From be24aeee563e7318c4dc5b371bdf5f6173b29240 Mon Sep 17 00:00:00 2001 From: Chris E Ferron Date: Mon, 12 Nov 2012 13:10:35 -0800 Subject: [PATCH] Imported Upstream version 1.0.0 --- .hgtags | 1 + README | 59 + js/jsd/Makefile.in | 103 + js/jsd/README | 6 + js/jsd/idl/Makefile.in | 52 + js/jsd/idl/jsdIDebuggerService.idl | 1303 + js/jsd/jsd.h | 1152 + js/jsd/jsd1640.def | 110 + js/jsd/jsd1640.rc | 99 + js/jsd/jsd3240.rc | 118 + js/jsd/jsd_atom.c | 178 + js/jsd/jsd_high.c | 439 + js/jsd/jsd_hook.c | 363 + js/jsd/jsd_java.c | 810 + js/jsd/jsd_lock.c | 256 + js/jsd/jsd_lock.h | 74 + js/jsd/jsd_obj.c | 286 + js/jsd/jsd_scpt.c | 963 + js/jsd/jsd_stak.c | 605 + js/jsd/jsd_step.c | 321 + js/jsd/jsd_text.c | 567 + js/jsd/jsd_val.c | 918 + js/jsd/jsd_xpc.cpp | 3510 + js/jsd/jsd_xpc.h | 398 + js/jsd/jsdebug.c | 1398 + js/jsd/jsdebug.h | 1577 + js/jsd/jsdstubs.c | 49 + js/jsd/mkshell.bat | 4 + js/jsd/resource.h | 52 + js/jsd/test/Makefile.in | 55 + js/jsd/test/bug507448.js | 25 + js/jsd/test/jsd-test.js | 119 + js/jsd/test/test-bug617870-callhooks.js | 52 + js/jsd/test/test_bug507448.html | 110 + js/jsd/test/test_bug617870-callhooks.html | 84 + js/src/Makefile.in | 995 + js/src/Makefile.ref | 468 + js/src/README.html | 54 + js/src/SpiderMonkey.rsp | 3 + js/src/Y.js | 19 + js/src/aclocal.m4 | 13 + js/src/analysis-tests/Makefile.in | 114 + js/src/analysis-tests/green-accessred.cpp | 11 + js/src/analysis-tests/green-callred.cpp | 12 + js/src/analysis-tests/green-callredptr.cpp | 8 + js/src/analysis-tests/green-tored-badpath.cpp | 14 + js/src/analysis-tests/green-tored.cpp | 12 + js/src/analysis-tests/green-toredptr.cpp | 12 + js/src/analysis-tests/misdeclared-red-funcptr.cpp | 5 + js/src/analysis-tests/misdeclared-red-funcptr2.cpp | 5 + js/src/analysis-tests/red-accessred.cpp | 11 + js/src/analysis-tests/red-callgreen.cpp | 8 + js/src/analysis-tests/red-callred.cpp | 8 + js/src/analysis-tests/red-togreenptr-arg.cpp | 11 + js/src/analysis-tests/red-togreenptr-field.cpp | 15 + .../red-togreenptr-initializer-array.cpp | 8 + .../red-togreenptr-initializer-cast.cpp | 7 + .../red-togreenptr-initializer-nested.cpp | 18 + .../red-togreenptr-initializer-struct.cpp | 12 + .../analysis-tests/red-togreenptr-initializer.cpp | 7 + js/src/analysis-tests/red-togreenptr-return.cpp | 9 + js/src/analysis-tests/red-togreenptr.cpp | 10 + js/src/assembler/TestMain.cpp | 929 + js/src/assembler/assembler/ARMAssembler.cpp | 447 + js/src/assembler/assembler/ARMAssembler.h | 1418 + js/src/assembler/assembler/ARMv7Assembler.h | 1926 + .../assembler/assembler/AbstractMacroAssembler.h | 611 + js/src/assembler/assembler/AssemblerBuffer.h | 228 + .../assembler/AssemblerBufferWithConstantPool.h | 344 + js/src/assembler/assembler/CodeLocation.h | 189 + js/src/assembler/assembler/LinkBuffer.h | 228 + js/src/assembler/assembler/MacroAssembler.h | 402 + js/src/assembler/assembler/MacroAssemblerARM.cpp | 108 + js/src/assembler/assembler/MacroAssemblerARM.h | 1276 + js/src/assembler/assembler/MacroAssemblerARMv7.h | 1223 + js/src/assembler/assembler/MacroAssemblerCodeRef.h | 203 + js/src/assembler/assembler/MacroAssemblerX86.h | 263 + .../assembler/MacroAssemblerX86Common.cpp | 51 + .../assembler/assembler/MacroAssemblerX86Common.h | 1464 + js/src/assembler/assembler/MacroAssemblerX86_64.h | 585 + js/src/assembler/assembler/RepatchBuffer.h | 163 + js/src/assembler/assembler/X86Assembler.h | 3004 + js/src/assembler/jit/ExecutableAllocator.cpp | 36 + js/src/assembler/jit/ExecutableAllocator.h | 466 + js/src/assembler/jit/ExecutableAllocatorOS2.cpp | 62 + js/src/assembler/jit/ExecutableAllocatorPosix.cpp | 94 + .../assembler/jit/ExecutableAllocatorSymbian.cpp | 73 + js/src/assembler/jit/ExecutableAllocatorWin.cpp | 60 + js/src/assembler/moco/MocoStubs.h | 74 + js/src/assembler/wtf/Assertions.cpp | 149 + js/src/assembler/wtf/Assertions.h | 271 + js/src/assembler/wtf/Platform.h | 996 + js/src/assembler/wtf/SegmentedVector.h | 264 + js/src/assembler/wtf/VMTags.h | 90 + js/src/bench.sh | 5 + js/src/build/autoconf/acoutput-fast.pl | 202 + js/src/build/autoconf/acwinpaths.m4 | 65 + js/src/build/autoconf/altoptions.m4 | 154 + js/src/build/autoconf/config.guess | 1537 + js/src/build/autoconf/config.sub | 1702 + js/src/build/autoconf/install-sh | 119 + js/src/build/autoconf/make-makefile | 324 + js/src/build/autoconf/match-dir.sh | 101 + js/src/build/autoconf/moznbytetype.m4 | 136 + js/src/build/autoconf/mozprog.m4 | 76 + js/src/build/autoconf/nspr.m4 | 102 + js/src/build/autoconf/pkg.m4 | 59 + js/src/build/cl.py | 96 + js/src/build/cygwin-wrapper | 75 + js/src/build/hcc | 111 + js/src/build/hcpp | 155 + js/src/build/msys-perl-wrapper | 16 + js/src/build/unix/mddepend.pl | 171 + js/src/build/unix/print-failed-commands.sh | 21 + js/src/build/unix/uniq.pl | 63 + js/src/build/win32/pgomerge.py | 40 + js/src/config.mk | 193 + js/src/config/Makefile.in | 109 + js/src/config/Moz/Milestone.pm | 232 + js/src/config/autoconf.mk.in | 361 + js/src/config/check-sync-dirs.py | 107 + js/src/config/check-sync-exceptions | 14 + js/src/config/config.mk | 853 + js/src/config/fastcwd.pl | 66 + js/src/config/find_vanilla_new_calls | 80 + js/src/config/gcc_hidden.h | 2 + js/src/config/make-system-wrappers.pl | 59 + js/src/config/milestone.pl | 112 + js/src/config/milestone.txt | 13 + js/src/config/mkdepend/Makefile.in | 83 + js/src/config/mkdepend/cppsetup.c | 233 + js/src/config/mkdepend/def.h | 184 + js/src/config/mkdepend/ifparser.c | 551 + js/src/config/mkdepend/ifparser.h | 83 + js/src/config/mkdepend/imakemdep.h | 733 + js/src/config/mkdepend/include.c | 337 + js/src/config/mkdepend/main.c | 860 + js/src/config/mkdepend/mkdepend.man | 382 + js/src/config/mkdepend/parse.c | 686 + js/src/config/mkdepend/pr.c | 124 + js/src/config/nfspwd.pl | 50 + js/src/config/nsinstall.c | 487 + js/src/config/nsinstall.exe.manifest | 22 + js/src/config/nsinstall.py | 155 + js/src/config/nsinstall_win.c | 711 + js/src/config/pathsub.c | 247 + js/src/config/pathsub.h | 74 + js/src/config/preprocessor.pl | 671 + js/src/config/rules.mk | 2348 + js/src/config/solaris_ia32.map | 1 + js/src/config/static-checking-config.mk | 24 + js/src/config/static-checking.js | 143 + js/src/config/string-format.js | 61 + js/src/config/system-headers | 1055 + js/src/config/version.mk | 85 + js/src/config/version_win.pl | 436 + js/src/configure | 16303 +++++ js/src/configure.in | 6157 ++ js/src/ctypes/CTypes.cpp | 6276 ++ js/src/ctypes/CTypes.h | 520 + js/src/ctypes/Library.cpp | 385 + js/src/ctypes/Library.h | 70 + js/src/ctypes/ctypes.msg | 47 + js/src/ctypes/libffi.patch | 1076 + js/src/ctypes/libffi/ChangeLog | 4259 ++ js/src/ctypes/libffi/ChangeLog.libffi | 613 + js/src/ctypes/libffi/ChangeLog.libgcj | 40 + js/src/ctypes/libffi/ChangeLog.v1 | 764 + js/src/ctypes/libffi/LICENSE | 21 + js/src/ctypes/libffi/Makefile.am | 198 + js/src/ctypes/libffi/Makefile.in | 1820 + js/src/ctypes/libffi/README | 327 + js/src/ctypes/libffi/acinclude.m4 | 92 + js/src/ctypes/libffi/aclocal.m4 | 8998 +++ js/src/ctypes/libffi/compile | 142 + js/src/ctypes/libffi/config.guess | 1498 + js/src/ctypes/libffi/config.sub | 1702 + js/src/ctypes/libffi/configure | 15041 +++++ js/src/ctypes/libffi/configure.ac | 459 + js/src/ctypes/libffi/configure.host | 11 + js/src/ctypes/libffi/depcomp | 584 + js/src/ctypes/libffi/doc/libffi.info | 593 + js/src/ctypes/libffi/doc/libffi.texi | 600 + js/src/ctypes/libffi/doc/stamp-vti | 4 + js/src/ctypes/libffi/doc/version.texi | 4 + js/src/ctypes/libffi/fficonfig.h.in | 193 + js/src/ctypes/libffi/include/Makefile.am | 9 + js/src/ctypes/libffi/include/Makefile.in | 471 + js/src/ctypes/libffi/include/ffi.h.in | 416 + js/src/ctypes/libffi/include/ffi_common.h | 122 + js/src/ctypes/libffi/install-sh | 323 + js/src/ctypes/libffi/libffi.pc.in | 10 + js/src/ctypes/libffi/libtool-version | 29 + js/src/ctypes/libffi/ltmain.sh | 8406 +++ js/src/ctypes/libffi/m4/libtool.m4 | 7360 +++ js/src/ctypes/libffi/m4/ltoptions.m4 | 368 + js/src/ctypes/libffi/m4/ltsugar.m4 | 123 + js/src/ctypes/libffi/m4/ltversion.m4 | 23 + js/src/ctypes/libffi/m4/lt~obsolete.m4 | 92 + js/src/ctypes/libffi/man/Makefile.am | 8 + js/src/ctypes/libffi/man/Makefile.in | 450 + js/src/ctypes/libffi/man/ffi.3 | 31 + js/src/ctypes/libffi/man/ffi_call.3 | 103 + js/src/ctypes/libffi/man/ffi_prep_cif.3 | 66 + js/src/ctypes/libffi/mdate-sh | 201 + js/src/ctypes/libffi/missing | 360 + js/src/ctypes/libffi/msvcc.sh | 197 + js/src/ctypes/libffi/src/alpha/ffi.c | 284 + js/src/ctypes/libffi/src/alpha/ffitarget.h | 48 + js/src/ctypes/libffi/src/alpha/osf.S | 366 + js/src/ctypes/libffi/src/arm/ffi.c | 500 + js/src/ctypes/libffi/src/arm/ffitarget.h | 63 + js/src/ctypes/libffi/src/arm/sysv.S | 462 + js/src/ctypes/libffi/src/avr32/ffi.c | 421 + js/src/ctypes/libffi/src/avr32/ffitarget.h | 50 + js/src/ctypes/libffi/src/avr32/sysv.S | 208 + js/src/ctypes/libffi/src/closures.c | 610 + js/src/ctypes/libffi/src/cris/ffi.c | 383 + js/src/ctypes/libffi/src/cris/ffitarget.h | 51 + js/src/ctypes/libffi/src/cris/sysv.S | 215 + js/src/ctypes/libffi/src/debug.c | 59 + js/src/ctypes/libffi/src/dlmalloc.c | 5158 ++ js/src/ctypes/libffi/src/frv/eabi.S | 128 + js/src/ctypes/libffi/src/frv/ffi.c | 292 + js/src/ctypes/libffi/src/frv/ffitarget.h | 57 + js/src/ctypes/libffi/src/ia64/ffi.c | 580 + js/src/ctypes/libffi/src/ia64/ffitarget.h | 50 + js/src/ctypes/libffi/src/ia64/ia64_flags.h | 40 + js/src/ctypes/libffi/src/ia64/unix.S | 560 + js/src/ctypes/libffi/src/java_raw_api.c | 356 + js/src/ctypes/libffi/src/m32r/ffi.c | 232 + js/src/ctypes/libffi/src/m32r/ffitarget.h | 48 + js/src/ctypes/libffi/src/m32r/sysv.S | 121 + js/src/ctypes/libffi/src/m68k/ffi.c | 278 + js/src/ctypes/libffi/src/m68k/ffitarget.h | 49 + js/src/ctypes/libffi/src/m68k/sysv.S | 234 + js/src/ctypes/libffi/src/mips/ffi.c | 1029 + js/src/ctypes/libffi/src/mips/ffitarget.h | 234 + js/src/ctypes/libffi/src/mips/n32.S | 591 + js/src/ctypes/libffi/src/mips/o32.S | 381 + js/src/ctypes/libffi/src/moxie/eabi.S | 128 + js/src/ctypes/libffi/src/moxie/ffi.c | 276 + js/src/ctypes/libffi/src/moxie/ffitarget.h | 52 + js/src/ctypes/libffi/src/pa/ffi.c | 716 + js/src/ctypes/libffi/src/pa/ffitarget.h | 78 + js/src/ctypes/libffi/src/pa/hpux32.S | 368 + js/src/ctypes/libffi/src/pa/linux.S | 357 + js/src/ctypes/libffi/src/powerpc/aix.S | 324 + js/src/ctypes/libffi/src/powerpc/aix_closure.S | 443 + js/src/ctypes/libffi/src/powerpc/asm.h | 125 + js/src/ctypes/libffi/src/powerpc/darwin.S | 245 + js/src/ctypes/libffi/src/powerpc/darwin_closure.S | 317 + js/src/ctypes/libffi/src/powerpc/ffi.c | 1442 + js/src/ctypes/libffi/src/powerpc/ffi_darwin.c | 928 + js/src/ctypes/libffi/src/powerpc/ffitarget.h | 132 + js/src/ctypes/libffi/src/powerpc/linux64.S | 187 + js/src/ctypes/libffi/src/powerpc/linux64_closure.S | 236 + js/src/ctypes/libffi/src/powerpc/ppc_closure.S | 327 + js/src/ctypes/libffi/src/powerpc/sysv.S | 219 + js/src/ctypes/libffi/src/prep_cif.c | 171 + js/src/ctypes/libffi/src/raw_api.c | 254 + js/src/ctypes/libffi/src/s390/ffi.c | 780 + js/src/ctypes/libffi/src/s390/ffitarget.h | 62 + js/src/ctypes/libffi/src/s390/sysv.S | 434 + js/src/ctypes/libffi/src/sh/ffi.c | 716 + js/src/ctypes/libffi/src/sh/ffitarget.h | 49 + js/src/ctypes/libffi/src/sh/sysv.S | 850 + js/src/ctypes/libffi/src/sh64/ffi.c | 468 + js/src/ctypes/libffi/src/sh64/ffitarget.h | 53 + js/src/ctypes/libffi/src/sh64/sysv.S | 539 + js/src/ctypes/libffi/src/sparc/ffi.c | 625 + js/src/ctypes/libffi/src/sparc/ffitarget.h | 68 + js/src/ctypes/libffi/src/sparc/v8.S | 313 + js/src/ctypes/libffi/src/sparc/v9.S | 307 + js/src/ctypes/libffi/src/types.c | 77 + js/src/ctypes/libffi/src/x86/darwin.S | 444 + js/src/ctypes/libffi/src/x86/darwin64.S | 416 + js/src/ctypes/libffi/src/x86/ffi.c | 644 + js/src/ctypes/libffi/src/x86/ffi64.c | 627 + js/src/ctypes/libffi/src/x86/ffitarget.h | 121 + js/src/ctypes/libffi/src/x86/freebsd.S | 458 + js/src/ctypes/libffi/src/x86/sysv.S | 467 + js/src/ctypes/libffi/src/x86/unix64.S | 426 + js/src/ctypes/libffi/src/x86/win32.S | 1065 + js/src/ctypes/libffi/src/x86/win64.S | 460 + js/src/ctypes/libffi/stamp-h.in | 1 + js/src/ctypes/libffi/testsuite/Makefile.am | 80 + js/src/ctypes/libffi/testsuite/Makefile.in | 484 + js/src/ctypes/libffi/testsuite/config/default.exp | 1 + js/src/ctypes/libffi/testsuite/lib/libffi-dg.exp | 350 + .../ctypes/libffi/testsuite/lib/target-libpath.exp | 263 + js/src/ctypes/libffi/testsuite/lib/wrapper.exp | 45 + .../ctypes/libffi/testsuite/libffi.call/call.exp | 36 + .../libffi/testsuite/libffi.call/closure_fn0.c | 89 + .../libffi/testsuite/libffi.call/closure_fn1.c | 81 + .../libffi/testsuite/libffi.call/closure_fn2.c | 81 + .../libffi/testsuite/libffi.call/closure_fn3.c | 82 + .../libffi/testsuite/libffi.call/closure_fn4.c | 89 + .../libffi/testsuite/libffi.call/closure_fn5.c | 92 + .../libffi/testsuite/libffi.call/closure_fn6.c | 90 + .../libffi/testsuite/libffi.call/closure_loc_fn0.c | 95 + .../libffi/testsuite/libffi.call/closure_stdcall.c | 64 + .../libffi/testsuite/libffi.call/cls_12byte.c | 94 + .../libffi/testsuite/libffi.call/cls_16byte.c | 95 + .../libffi/testsuite/libffi.call/cls_18byte.c | 96 + .../libffi/testsuite/libffi.call/cls_19byte.c | 102 + .../libffi/testsuite/libffi.call/cls_1_1byte.c | 89 + .../libffi/testsuite/libffi.call/cls_20byte.c | 91 + .../libffi/testsuite/libffi.call/cls_20byte1.c | 93 + .../libffi/testsuite/libffi.call/cls_24byte.c | 113 + .../libffi/testsuite/libffi.call/cls_2byte.c | 90 + .../libffi/testsuite/libffi.call/cls_3_1byte.c | 95 + .../libffi/testsuite/libffi.call/cls_3byte1.c | 90 + .../libffi/testsuite/libffi.call/cls_3byte2.c | 90 + .../libffi/testsuite/libffi.call/cls_4_1byte.c | 98 + .../libffi/testsuite/libffi.call/cls_4byte.c | 90 + .../libffi/testsuite/libffi.call/cls_5_1_byte.c | 109 + .../libffi/testsuite/libffi.call/cls_5byte.c | 98 + .../libffi/testsuite/libffi.call/cls_64byte.c | 124 + .../libffi/testsuite/libffi.call/cls_6_1_byte.c | 113 + .../libffi/testsuite/libffi.call/cls_6byte.c | 99 + .../libffi/testsuite/libffi.call/cls_7_1_byte.c | 117 + .../libffi/testsuite/libffi.call/cls_7byte.c | 97 + .../libffi/testsuite/libffi.call/cls_8byte.c | 88 + .../libffi/testsuite/libffi.call/cls_9byte1.c | 90 + .../libffi/testsuite/libffi.call/cls_9byte2.c | 91 + .../testsuite/libffi.call/cls_align_double.c | 93 + .../libffi/testsuite/libffi.call/cls_align_float.c | 91 + .../testsuite/libffi.call/cls_align_longdouble.c | 92 + .../libffi.call/cls_align_longdouble_split.c | 134 + .../libffi.call/cls_align_longdouble_split2.c | 117 + .../testsuite/libffi.call/cls_align_pointer.c | 95 + .../testsuite/libffi.call/cls_align_sint16.c | 91 + .../testsuite/libffi.call/cls_align_sint32.c | 91 + .../testsuite/libffi.call/cls_align_sint64.c | 92 + .../testsuite/libffi.call/cls_align_uint16.c | 91 + .../testsuite/libffi.call/cls_align_uint32.c | 91 + .../testsuite/libffi.call/cls_align_uint64.c | 93 + .../libffi/testsuite/libffi.call/cls_dbls_struct.c | 66 + .../libffi/testsuite/libffi.call/cls_double.c | 43 + .../libffi/testsuite/libffi.call/cls_double_va.c | 59 + .../libffi/testsuite/libffi.call/cls_float.c | 42 + .../libffi/testsuite/libffi.call/cls_longdouble.c | 105 + .../testsuite/libffi.call/cls_longdouble_va.c | 59 + .../libffi/testsuite/libffi.call/cls_multi_schar.c | 74 + .../testsuite/libffi.call/cls_multi_sshort.c | 74 + .../testsuite/libffi.call/cls_multi_sshortchar.c | 86 + .../libffi/testsuite/libffi.call/cls_multi_uchar.c | 91 + .../testsuite/libffi.call/cls_multi_ushort.c | 74 + .../testsuite/libffi.call/cls_multi_ushortchar.c | 86 + .../libffi/testsuite/libffi.call/cls_pointer.c | 74 + .../testsuite/libffi.call/cls_pointer_stack.c | 140 + .../libffi/testsuite/libffi.call/cls_schar.c | 44 + .../ctypes/libffi/testsuite/libffi.call/cls_sint.c | 42 + .../libffi/testsuite/libffi.call/cls_sshort.c | 42 + .../libffi/testsuite/libffi.call/cls_uchar.c | 42 + .../ctypes/libffi/testsuite/libffi.call/cls_uint.c | 43 + .../libffi/testsuite/libffi.call/cls_ulonglong.c | 47 + .../libffi/testsuite/libffi.call/cls_ushort.c | 43 + .../libffi/testsuite/libffi.call/err_bad_abi.c | 35 + .../libffi/testsuite/libffi.call/err_bad_typedef.c | 25 + .../ctypes/libffi/testsuite/libffi.call/ffitest.h | 129 + js/src/ctypes/libffi/testsuite/libffi.call/float.c | 59 + .../ctypes/libffi/testsuite/libffi.call/float1.c | 58 + .../ctypes/libffi/testsuite/libffi.call/float2.c | 58 + .../ctypes/libffi/testsuite/libffi.call/float3.c | 72 + .../ctypes/libffi/testsuite/libffi.call/float4.c | 62 + .../libffi/testsuite/libffi.call/huge_struct.c | 342 + js/src/ctypes/libffi/testsuite/libffi.call/many.c | 69 + .../libffi/testsuite/libffi.call/many_win32.c | 63 + .../ctypes/libffi/testsuite/libffi.call/negint.c | 53 + .../libffi/testsuite/libffi.call/nested_struct.c | 152 + .../libffi/testsuite/libffi.call/nested_struct1.c | 161 + .../libffi/testsuite/libffi.call/nested_struct10.c | 133 + .../libffi/testsuite/libffi.call/nested_struct2.c | 110 + .../libffi/testsuite/libffi.call/nested_struct3.c | 111 + .../libffi/testsuite/libffi.call/nested_struct4.c | 111 + .../libffi/testsuite/libffi.call/nested_struct5.c | 112 + .../libffi/testsuite/libffi.call/nested_struct6.c | 131 + .../libffi/testsuite/libffi.call/nested_struct7.c | 111 + .../libffi/testsuite/libffi.call/nested_struct8.c | 131 + .../libffi/testsuite/libffi.call/nested_struct9.c | 131 + .../ctypes/libffi/testsuite/libffi.call/problem1.c | 90 + .../libffi/testsuite/libffi.call/promotion.c | 59 + .../libffi/testsuite/libffi.call/pyobjc-tc.c | 114 + .../libffi/testsuite/libffi.call/return_dbl.c | 35 + .../libffi/testsuite/libffi.call/return_dbl1.c | 43 + .../libffi/testsuite/libffi.call/return_dbl2.c | 42 + .../libffi/testsuite/libffi.call/return_fl.c | 35 + .../libffi/testsuite/libffi.call/return_fl1.c | 36 + .../libffi/testsuite/libffi.call/return_fl2.c | 49 + .../libffi/testsuite/libffi.call/return_fl3.c | 42 + .../libffi/testsuite/libffi.call/return_ldl.c | 34 + .../libffi/testsuite/libffi.call/return_ll.c | 41 + .../libffi/testsuite/libffi.call/return_ll1.c | 43 + .../libffi/testsuite/libffi.call/return_sc.c | 36 + .../libffi/testsuite/libffi.call/return_sl.c | 38 + .../libffi/testsuite/libffi.call/return_uc.c | 38 + .../libffi/testsuite/libffi.call/return_ul.c | 38 + .../libffi/testsuite/libffi.call/stret_large.c | 145 + .../libffi/testsuite/libffi.call/stret_large2.c | 148 + .../libffi/testsuite/libffi.call/stret_medium.c | 124 + .../libffi/testsuite/libffi.call/stret_medium2.c | 125 + .../ctypes/libffi/testsuite/libffi.call/strlen.c | 44 + .../libffi/testsuite/libffi.call/strlen_win32.c | 44 + .../ctypes/libffi/testsuite/libffi.call/struct1.c | 65 + .../ctypes/libffi/testsuite/libffi.call/struct2.c | 67 + .../ctypes/libffi/testsuite/libffi.call/struct3.c | 59 + .../ctypes/libffi/testsuite/libffi.call/struct4.c | 63 + .../ctypes/libffi/testsuite/libffi.call/struct5.c | 65 + .../ctypes/libffi/testsuite/libffi.call/struct6.c | 64 + .../ctypes/libffi/testsuite/libffi.call/struct7.c | 74 + .../ctypes/libffi/testsuite/libffi.call/struct8.c | 80 + .../ctypes/libffi/testsuite/libffi.call/struct9.c | 67 + .../libffi/testsuite/libffi.call/testclosure.c | 70 + .../libffi/testsuite/libffi.special/ffitestcxx.h | 96 + .../libffi/testsuite/libffi.special/special.exp | 37 + .../libffi/testsuite/libffi.special/unwindtest.cc | 124 + .../libffi.special/unwindtest_ffi_call.cc | 53 + js/src/ctypes/libffi/texinfo.tex | 7210 ++ js/src/ctypes/typedefs.h | 150 + js/src/dtoa.c | 3255 + js/src/editline/Makefile.in | 55 + js/src/editline/Makefile.ref | 143 + js/src/editline/README | 83 + js/src/editline/editline.3 | 175 + js/src/editline/editline.c | 1374 + js/src/editline/editline.h | 135 + js/src/editline/sysunix.c | 182 + js/src/editline/unix.h | 82 + js/src/find-child.py | 69 + js/src/gnuplot/gcTimer.gnu | 24 + js/src/imacro_asm.py | 467 + js/src/imacros.jsasm | 718 + js/src/javascript-trace.d | 59 + js/src/jit-test/README | 74 + js/src/jit-test/jit_test.py | 463 + js/src/jit-test/lib/andTestHelper.js | 9 + js/src/jit-test/lib/array-compare.js | 24 + js/src/jit-test/lib/eqArrayHelper.js | 17 + js/src/jit-test/lib/mandelbrot-results.js | 3 + js/src/jit-test/lib/orTestHelper.js | 9 + js/src/jit-test/lib/prolog.js | 48 + js/src/jit-test/lib/range.js | 18 + js/src/jit-test/progressbar.py | 35 + .../jit-test/tests/arguments/args-createontrace.js | 18 + js/src/jit-test/tests/arguments/args-mochi-2.js | 23 + js/src/jit-test/tests/arguments/args-mochi-2a.js | 23 + js/src/jit-test/tests/arguments/args-mochi.js | 17 + .../tests/arguments/args-mutate-length-1.js | 16 + .../tests/arguments/args-mutate-length-2.js | 15 + js/src/jit-test/tests/arguments/args-range-2.js | 37 + .../jit-test/tests/arguments/args-range-const.js | 14 + js/src/jit-test/tests/arguments/args-range.js | 18 + .../tests/arguments/args-redefine-length-1.js | 7 + .../tests/arguments/args-redefine-length-2.js | 8 + js/src/jit-test/tests/arguments/args-sum.js | 16 + js/src/jit-test/tests/arguments/args-vargc.js | 18 + js/src/jit-test/tests/arguments/args1.js | 15 + js/src/jit-test/tests/arguments/args10.js | 16 + js/src/jit-test/tests/arguments/args11.js | 14 + js/src/jit-test/tests/arguments/args2.js | 20 + js/src/jit-test/tests/arguments/args2a.js | 17 + js/src/jit-test/tests/arguments/args2b.js | 17 + js/src/jit-test/tests/arguments/args2c.js | 19 + js/src/jit-test/tests/arguments/args2d.js | 17 + js/src/jit-test/tests/arguments/args3.js | 20 + js/src/jit-test/tests/arguments/args4.js | 21 + js/src/jit-test/tests/arguments/args5.js | 24 + js/src/jit-test/tests/arguments/args6.js | 22 + js/src/jit-test/tests/arguments/args6a.js | 23 + js/src/jit-test/tests/arguments/args7.js | 14 + js/src/jit-test/tests/arguments/args8.js | 14 + js/src/jit-test/tests/arguments/args9.js | 16 + js/src/jit-test/tests/arguments/argsub.js | 13 + js/src/jit-test/tests/arguments/argsx-1.js | 22 + js/src/jit-test/tests/arguments/argsx-2.js | 23 + js/src/jit-test/tests/arguments/argsx-3.js | 27 + js/src/jit-test/tests/arguments/argsx-3a.js | 27 + js/src/jit-test/tests/arguments/argsx-4.js | 23 + js/src/jit-test/tests/arguments/bug503772.js | 16 + js/src/jit-test/tests/arguments/bug508178.js | 18 + js/src/jit-test/tests/arguments/bug554670-1.js | 8 + js/src/jit-test/tests/arguments/bug554670-2.js | 8 + js/src/jit-test/tests/arguments/bug633020.js | 11 + js/src/jit-test/tests/arguments/nonstrict-args.js | 24 + .../nonstrict-assign-element-get-parameter.js | 13 + .../nonstrict-assign-parameter-get-element.js | 13 + .../jit-test/tests/arguments/nonstrict-assign.js | 17 + .../tests/arguments/nonstrict-later-assign.js | 18 + .../jit-test/tests/arguments/nonstrict-noargs.js | 21 + .../tests/arguments/strict-args-flushstack.js | 27 + .../arguments/strict-args-generator-flushstack.js | 27 + js/src/jit-test/tests/arguments/strict-args.js | 25 + .../tests/arguments/strict-assign-after.js | 28 + .../arguments/strict-assign-arguments-element.js | 21 + .../arguments/strict-assign-outer-param-psych.js | 27 + .../tests/arguments/strict-assign-outer-param.js | 27 + .../strict-assign-parameter-get-element.js | 14 + js/src/jit-test/tests/arguments/strict-assign.js | 26 + .../tests/arguments/strict-eval-mutation.js | 24 + js/src/jit-test/tests/arguments/strict-eval.js | 30 + .../tests/arguments/strict-maybe-assign-outer.js | 26 + .../tests/arguments/strict-maybe-nested-eval.js | 26 + .../strict-nested-assign-shadow-function-call.js | 33 + .../strict-nested-assign-shadow-function-name.js | 33 + .../strict-nested-assign-shadow-function.js | 32 + .../strict-nested-assign-shadowed-catch-call.js | 39 + .../strict-nested-assign-shadowed-catch.js | 39 + .../arguments/strict-nested-assign-shadowed-var.js | 29 + .../jit-test/tests/arguments/strict-nested-eval.js | 31 + .../tests/arguments/strict-nested-shadow-eval.js | 30 + .../arguments/strict-nested-shadow-maybe-eval.js | 30 + js/src/jit-test/tests/arguments/strict-noargs.js | 25 + js/src/jit-test/tests/arguments/testDelArg1.js | 13 + js/src/jit-test/tests/arguments/testDelArg2.js | 13 + js/src/jit-test/tests/basic/FPQuadCmp.js | 6 + .../tests/basic/argumentsPassedToBuiltin.js | 14 + js/src/jit-test/tests/basic/arith.js | 11 + .../jit-test/tests/basic/arityMismatchExtraArg.js | 13 + .../tests/basic/arityMismatchMissingArg.js | 8 + js/src/jit-test/tests/basic/bigLoadStoreDisp.js | 25 + .../tests/basic/bindname-in-strict-eval.js | 3 + js/src/jit-test/tests/basic/bitwiseAnd.js | 10 + js/src/jit-test/tests/basic/bitwiseGlobal.js | 8 + js/src/jit-test/tests/basic/bug464403.js | 7 + js/src/jit-test/tests/basic/bug465902.js | 13 + js/src/jit-test/tests/basic/bug489098.js | 18 + js/src/jit-test/tests/basic/bug504587-1.js | 13 + js/src/jit-test/tests/basic/bug507180.js | 69 + js/src/jit-test/tests/basic/bug509639.js | 3 + js/src/jit-test/tests/basic/bug509982.js | 15 + js/src/jit-test/tests/basic/bug510434.js | 2 + js/src/jit-test/tests/basic/bug510437-2.js | 13 + js/src/jit-test/tests/basic/bug510437.js | 12 + js/src/jit-test/tests/basic/bug510642.js | 14 + js/src/jit-test/tests/basic/bug510655.js | 15 + js/src/jit-test/tests/basic/bug511214.js | 18 + js/src/jit-test/tests/basic/bug511241.js | 15 + js/src/jit-test/tests/basic/bug513038.js | 16 + js/src/jit-test/tests/basic/bug513898-regexp.js | 51 + js/src/jit-test/tests/basic/bug516009.js | 20 + js/src/jit-test/tests/basic/bug517721.js | 8 + js/src/jit-test/tests/basic/bug519129.js | 1 + js/src/jit-test/tests/basic/bug520498.js | 9 + js/src/jit-test/tests/basic/bug522136.js | 10 + js/src/jit-test/tests/basic/bug522817.js | 17 + js/src/jit-test/tests/basic/bug524826-2.js | 11 + js/src/jit-test/tests/basic/bug524826.js | 10 + js/src/jit-test/tests/basic/bug525028.js | 16 + js/src/jit-test/tests/basic/bug527288.js | 7 + js/src/jit-test/tests/basic/bug528116.js | 8 + js/src/jit-test/tests/basic/bug528644.js | 16 + js/src/jit-test/tests/basic/bug529130.js | 19 + js/src/jit-test/tests/basic/bug532568-2.js | 20 + js/src/jit-test/tests/basic/bug532568.js | 19 + js/src/jit-test/tests/basic/bug532823.js | 23 + js/src/jit-test/tests/basic/bug535474.js | 27 + js/src/jit-test/tests/basic/bug535760.js | 13 + js/src/jit-test/tests/basic/bug535930.js | 19 + js/src/jit-test/tests/basic/bug536445.js | 10 + js/src/jit-test/tests/basic/bug536748.js | 8 + js/src/jit-test/tests/basic/bug539379.js | 9 + js/src/jit-test/tests/basic/bug539553-2.js | 7 + js/src/jit-test/tests/basic/bug539553-3.js | 11 + js/src/jit-test/tests/basic/bug539553.js | 11 + js/src/jit-test/tests/basic/bug541191-1.js | 23 + js/src/jit-test/tests/basic/bug541191-2.js | 23 + js/src/jit-test/tests/basic/bug541191-3.js | 23 + js/src/jit-test/tests/basic/bug541191-4.js | 27 + js/src/jit-test/tests/basic/bug541191-5.js | 24 + js/src/jit-test/tests/basic/bug547911-1.js | 7 + js/src/jit-test/tests/basic/bug547911-2.js | 7 + js/src/jit-test/tests/basic/bug551705.js | 39 + js/src/jit-test/tests/basic/bug552196.js | 12 + js/src/jit-test/tests/basic/bug557168-1.js | 11 + js/src/jit-test/tests/basic/bug557168-2.js | 11 + js/src/jit-test/tests/basic/bug557168-3.js | 10 + js/src/jit-test/tests/basic/bug557168.js | 4 + js/src/jit-test/tests/basic/bug557841.js | 1 + js/src/jit-test/tests/basic/bug558530.js | 14 + js/src/jit-test/tests/basic/bug558814.js | 10 + js/src/jit-test/tests/basic/bug559912.js | 12 + js/src/jit-test/tests/basic/bug560234.js | 10 + js/src/jit-test/tests/basic/bug560234b.js | 12 + js/src/jit-test/tests/basic/bug561279.js | 4 + js/src/jit-test/tests/basic/bug563125.js | 5 + js/src/jit-test/tests/basic/bug566637.js | 5 + js/src/jit-test/tests/basic/bug568276.js | 1 + js/src/jit-test/tests/basic/bug569651.js | 3 + js/src/jit-test/tests/basic/bug569843.js | 4 + js/src/jit-test/tests/basic/bug569849.js | 9 + js/src/jit-test/tests/basic/bug570385-1.js | 9 + js/src/jit-test/tests/basic/bug570385-2.js | 9 + js/src/jit-test/tests/basic/bug570385-3.js | 11 + js/src/jit-test/tests/basic/bug570663-1.js | 4 + js/src/jit-test/tests/basic/bug570663-2.js | 12 + js/src/jit-test/tests/basic/bug572229.js | 12 + js/src/jit-test/tests/basic/bug574280.js | 4 + js/src/jit-test/tests/basic/bug576823-regexp.js | 3 + js/src/jit-test/tests/basic/bug576837-regexp.js | 45 + js/src/jit-test/tests/basic/bug578041.js | 3 + js/src/jit-test/tests/basic/bug579740.js | 7 + js/src/jit-test/tests/basic/bug582161.js | 3 + js/src/jit-test/tests/basic/bug582479.js | 5 + js/src/jit-test/tests/basic/bug583615.js | 12 + js/src/jit-test/tests/basic/bug583757.js | 24 + js/src/jit-test/tests/basic/bug584499-1.js | 6 + js/src/jit-test/tests/basic/bug584499-2.js | 12 + js/src/jit-test/tests/basic/bug584565.js | 10 + js/src/jit-test/tests/basic/bug584603.js | 13 + js/src/jit-test/tests/basic/bug585542.js | 11 + js/src/jit-test/tests/basic/bug586499-regexp.js | 2 + js/src/jit-test/tests/basic/bug586917.js | 1834 + js/src/jit-test/tests/basic/bug587346-regexp-01.js | 1 + js/src/jit-test/tests/basic/bug587366.js | 3 + js/src/jit-test/tests/basic/bug589318.js | 10 + js/src/jit-test/tests/basic/bug590006.js | 11 + js/src/jit-test/tests/basic/bug592927.js | 27 + js/src/jit-test/tests/basic/bug593663-regexp.js | 109 + js/src/jit-test/tests/basic/bug594108.js | 8 + js/src/jit-test/tests/basic/bug594205.js | 16 + js/src/jit-test/tests/basic/bug595963-1.js | 19 + js/src/jit-test/tests/basic/bug595963-2.js | 19 + js/src/jit-test/tests/basic/bug596502-version.js | 23 + js/src/jit-test/tests/basic/bug599854.js | 4 + js/src/jit-test/tests/basic/bug601046.js | 8 + js/src/jit-test/tests/basic/bug601395.js | 2 + js/src/jit-test/tests/basic/bug601398.js | 7 + js/src/jit-test/tests/basic/bug601401.js | 5 + js/src/jit-test/tests/basic/bug601402.js | 2 + js/src/jit-test/tests/basic/bug601428.js | 2 + js/src/jit-test/tests/basic/bug602088.js | 6 + js/src/jit-test/tests/basic/bug605015.js | 9 + js/src/jit-test/tests/basic/bug605754-regexp.js | 2 + js/src/jit-test/tests/basic/bug606083.js | 32 + js/src/jit-test/tests/basic/bug606882-1.js | 3 + js/src/jit-test/tests/basic/bug606882-2.js | 16 + js/src/jit-test/tests/basic/bug608313.js | 11 + js/src/jit-test/tests/basic/bug608980.js | 11 + js/src/jit-test/tests/basic/bug609502-1.js | 9 + js/src/jit-test/tests/basic/bug609502-2.js | 5 + js/src/jit-test/tests/basic/bug609502-3.js | 11 + js/src/jit-test/tests/basic/bug610592.js | 29 + js/src/jit-test/tests/basic/bug613122.js | 4 + js/src/jit-test/tests/basic/bug613151.js | 18 + js/src/jit-test/tests/basic/bug613399.js | 3 + js/src/jit-test/tests/basic/bug614915.js | 2 + js/src/jit-test/tests/basic/bug616762.js | 26 + js/src/jit-test/tests/basic/bug617139.js | 9 + js/src/jit-test/tests/basic/bug617171.js | 4 + js/src/jit-test/tests/basic/bug618350.js | 24 + js/src/jit-test/tests/basic/bug618577.js | 5 + js/src/jit-test/tests/basic/bug619004.js | 4 + js/src/jit-test/tests/basic/bug620532.js | 15 + js/src/jit-test/tests/basic/bug620838.js | 22 + js/src/jit-test/tests/basic/bug621022-1.js | 14 + js/src/jit-test/tests/basic/bug621022-2.js | 13 + js/src/jit-test/tests/basic/bug623859.js | 16 + js/src/jit-test/tests/basic/bug623863.js | 5 + js/src/jit-test/tests/basic/bug624041-1.js | 8 + js/src/jit-test/tests/basic/bug624041-2.js | 11 + js/src/jit-test/tests/basic/bug625141-1.js | 13 + js/src/jit-test/tests/basic/bug625141-2.js | 13 + js/src/jit-test/tests/basic/bug625399.js | 7 + js/src/jit-test/tests/basic/bug627609.js | 2 + js/src/jit-test/tests/basic/bug627692-1.js | 19 + js/src/jit-test/tests/basic/bug627692-2.js | 28 + js/src/jit-test/tests/basic/bug630377.js | 7 + js/src/jit-test/tests/basic/bug630865-1.js | 6 + js/src/jit-test/tests/basic/bug630865-2.js | 6 + js/src/jit-test/tests/basic/bug630865-3.js | 12 + js/src/jit-test/tests/basic/bug630865-4.js | 10 + js/src/jit-test/tests/basic/bug630865-5.js | 13 + js/src/jit-test/tests/basic/bug630865-6.js | 11 + js/src/jit-test/tests/basic/bug631082.js | 13 + js/src/jit-test/tests/basic/bug631219.js | 10 + js/src/jit-test/tests/basic/bug631305.js | 9 + js/src/jit-test/tests/basic/bug631788.js | 1 + js/src/jit-test/tests/basic/bug632206.js | 6 + js/src/jit-test/tests/basic/bug632901.js | 9 + js/src/jit-test/tests/basic/bug632964-regexp.js | 17 + js/src/jit-test/tests/basic/bug633409-1.js | 13 + js/src/jit-test/tests/basic/bug633409-2.js | 13 + js/src/jit-test/tests/basic/bug633752.js | 11 + js/src/jit-test/tests/basic/bug633890.js | 9 + js/src/jit-test/tests/basic/bug634593.js | 4 + js/src/jit-test/tests/basic/bug635417.js | 2 + js/src/jit-test/tests/basic/call.js | 28 + js/src/jit-test/tests/basic/call2.js | 13 + js/src/jit-test/tests/basic/createMandelSet.js | 242 + js/src/jit-test/tests/basic/deep2.js | 11 + js/src/jit-test/tests/basic/deepForInLoop.js | 12 + .../jit-test/tests/basic/delete-array-elements.js | 12 + .../jit-test/tests/basic/delete-indexed-names.js | 12 + .../jit-test/tests/basic/delete-integer-nonid.js | 24 + js/src/jit-test/tests/basic/delete-named-names.js | 17 + js/src/jit-test/tests/basic/delete-non-config.js | 10 + js/src/jit-test/tests/basic/dependentStrings.js | 11 + js/src/jit-test/tests/basic/doMath.js | 60 + js/src/jit-test/tests/basic/equalInt.js | 29 + js/src/jit-test/tests/basic/fannkuch.js | 17 + js/src/jit-test/tests/basic/firstSlotConflict.js | 10 + js/src/jit-test/tests/basic/forVarInWith.js | 12 + js/src/jit-test/tests/basic/function-bind.js | 21 + js/src/jit-test/tests/basic/getelem.js | 30 + js/src/jit-test/tests/basic/getprop.js | 16 + js/src/jit-test/tests/basic/globalGet.js | 6 + js/src/jit-test/tests/basic/globalOptimize-1.js | 5 + js/src/jit-test/tests/basic/globalSet.js | 4 + js/src/jit-test/tests/basic/ifInsideLoop.js | 12 + js/src/jit-test/tests/basic/inArrayTest.js | 9 + js/src/jit-test/tests/basic/inObjectTest.js | 13 + .../tests/basic/innerLoopIntOuterDouble.js | 11 + .../jit-test/tests/basic/inner_double_outer_int.js | 10 + js/src/jit-test/tests/basic/jitstatsArchFlags.js | 14 + js/src/jit-test/tests/basic/joinTest.js | 15 + js/src/jit-test/tests/basic/matchInLoop.js | 8 + js/src/jit-test/tests/basic/math-jit-tests.js | 520 + js/src/jit-test/tests/basic/merge_type_maps.js | 9 + js/src/jit-test/tests/basic/missingArgTest.js | 12 + js/src/jit-test/tests/basic/missingArgTest2.js | 26 + js/src/jit-test/tests/basic/mod.js | 14 + js/src/jit-test/tests/basic/name-inactive-del.js | 28 + .../jit-test/tests/basic/name-inactive-eval-del.js | 10 + .../tests/basic/name-inactive-inferflags.js | 18 + js/src/jit-test/tests/basic/name-inactive.js | 20 + js/src/jit-test/tests/basic/name.js | 9 + js/src/jit-test/tests/basic/nestedExit2.js | 17 + js/src/jit-test/tests/basic/nestedExitLoop.js | 14 + .../jit-test/tests/basic/new-Function-prototype.js | 22 + js/src/jit-test/tests/basic/new-bound-function.js | 26 + js/src/jit-test/tests/basic/newArrayTest.js | 8 + js/src/jit-test/tests/basic/newTest.js | 14 + js/src/jit-test/tests/basic/nonEmptyStack1.js | 13 + js/src/jit-test/tests/basic/nonEmptyStack2.js | 10 + js/src/jit-test/tests/basic/orNaNTest1.js | 3 + js/src/jit-test/tests/basic/orNaNTest2.js | 3 + js/src/jit-test/tests/basic/outerline.js | 15 + js/src/jit-test/tests/basic/parseIntTests.js | 23 + js/src/jit-test/tests/basic/parsingNumbers.js | 23 + js/src/jit-test/tests/basic/perf-smoketest.js | 34 + js/src/jit-test/tests/basic/putargsNoReturn.js | 6 + js/src/jit-test/tests/basic/putargsReturn.js | 7 + js/src/jit-test/tests/basic/regexp-reset-input.js | 8 + .../tests/basic/regexp-sticky-undef-capture.js | 8 + js/src/jit-test/tests/basic/regexpLastIndex.js | 13 + js/src/jit-test/tests/basic/setArgumentsLength.js | 14 + js/src/jit-test/tests/basic/setArgumentsLength2.js | 12 + js/src/jit-test/tests/basic/setCall.js | 26 + js/src/jit-test/tests/basic/setCallEvalMiddle.js | 17 + js/src/jit-test/tests/basic/setCallEvalMiddle2.js | 18 + js/src/jit-test/tests/basic/setCallGlobal.js | 14 + js/src/jit-test/tests/basic/setelem.js | 12 + js/src/jit-test/tests/basic/setprop.js | 10 + js/src/jit-test/tests/basic/shapelessCalleeTest.js | 67 + .../jit-test/tests/basic/strict-eval-loop-error.js | 3 + js/src/jit-test/tests/basic/strictParseIntOctal.js | 16 + js/src/jit-test/tests/basic/stringConvert.js | 18 + .../tests/basic/stringSplitIntoArrayTest.js | 9 + js/src/jit-test/tests/basic/stringSplitTest.js | 9 + js/src/jit-test/tests/basic/strings.js | 21 + js/src/jit-test/tests/basic/test586387.js | 14 + .../tests/basic/testAbortedImacroDecompilation.js | 7 + .../tests/basic/testAccessCanonicalArgInGetElem.js | 12 + .../tests/basic/testAddAnyInconvertibleObject.js | 33 + .../tests/basic/testAddInconvertibleObjectAny.js | 39 + ...estAddInconvertibleObjectInconvertibleObject.js | 38 + js/src/jit-test/tests/basic/testAddNull.js | 13 + js/src/jit-test/tests/basic/testAddUndefined.js | 5 + js/src/jit-test/tests/basic/testApply.js | 7 + .../jit-test/tests/basic/testApplyAtJoinPoint.js | 12 + js/src/jit-test/tests/basic/testApplyCall.js | 42 + js/src/jit-test/tests/basic/testApplyUnbox.js | 11 + js/src/jit-test/tests/basic/testArrayComp1.js | 6 + js/src/jit-test/tests/basic/testArrayComp2.js | 7 + .../jit-test/tests/basic/testArrayDensityChange.js | 17 + js/src/jit-test/tests/basic/testArrayIn.js | 54 + .../tests/basic/testArrayInWithIndexedProto.js | 31 + js/src/jit-test/tests/basic/testArrayNaNIndex.js | 7 + js/src/jit-test/tests/basic/testArrayNamedProp.js | 5 + js/src/jit-test/tests/basic/testArrayPushPop.js | 11 + .../basic/testAssigningWatchedDeletedProperty.js | 7 + .../basic/testAssignmentThatIgnoresSetterRetval.js | 10 + js/src/jit-test/tests/basic/testAtomize.js | 10 + .../tests/basic/testBitOrAnyInconvertibleObject.js | 33 + .../tests/basic/testBitOrInconvertibleObjectAny.js | 33 + ...tBitOrInconvertibleObjectInconvertibleObject.js | 38 + js/src/jit-test/tests/basic/testBitwise.js | 12 + js/src/jit-test/tests/basic/testBoolToString.js | 3 + .../tests/basic/testBoxDoubleWithDoubleSizedInt.js | 10 + js/src/jit-test/tests/basic/testBranchCse.js | 7 + js/src/jit-test/tests/basic/testBranchingLoop.js | 11 + .../tests/basic/testBranchingUnstableLoop.js | 11 + .../basic/testBranchingUnstableLoopCounter.js | 11 + .../tests/basic/testBranchingUnstableObject.js | 13 + .../jit-test/tests/basic/testBrandedVsGeneric.js | 17 + js/src/jit-test/tests/basic/testBreak.js | 6 + js/src/jit-test/tests/basic/testBug458838.js | 19 + js/src/jit-test/tests/basic/testBug462388.js | 6 + js/src/jit-test/tests/basic/testBug462407.js | 6 + js/src/jit-test/tests/basic/testBug463490.js | 18 + js/src/jit-test/tests/basic/testBug465261.js | 7 + js/src/jit-test/tests/basic/testBug465272.js | 6 + js/src/jit-test/tests/basic/testBug465483.js | 7 + js/src/jit-test/tests/basic/testBug465688.js | 6 + js/src/jit-test/tests/basic/testBug466128.js | 9 + js/src/jit-test/tests/basic/testBug466262.js | 11 + js/src/jit-test/tests/basic/testBug474769.js | 10 + js/src/jit-test/tests/basic/testBug501690.js | 14 + js/src/jit-test/tests/basic/testBug502914.js | 19 + js/src/jit-test/tests/basic/testBug504520.js | 11 + js/src/jit-test/tests/basic/testBug504520Harder.js | 33 + js/src/jit-test/tests/basic/testBug507425.js | 14 + js/src/jit-test/tests/basic/testBug520503-1.js | 3 + js/src/jit-test/tests/basic/testBug520503-2.js | 18 + js/src/jit-test/tests/basic/testBug520503-3.js | 6 + js/src/jit-test/tests/basic/testBug529147.js | 22 + js/src/jit-test/tests/basic/testBug547791.js | 21 + js/src/jit-test/tests/basic/testBug550210.js | 16 + js/src/jit-test/tests/basic/testBug552248.js | 37 + js/src/jit-test/tests/basic/testBug554043.js | 6 + js/src/jit-test/tests/basic/testBug555484.js | 8 + js/src/jit-test/tests/basic/testBug558446.js | 11 + js/src/jit-test/tests/basic/testBug560098.js | 16 + js/src/jit-test/tests/basic/testBug566556.js | 9 + js/src/jit-test/tests/basic/testBug578044.js | 13 + js/src/jit-test/tests/basic/testBug579602.js | 21 + js/src/jit-test/tests/basic/testBug579646.js | 22 + js/src/jit-test/tests/basic/testBug579647.js | 13 + js/src/jit-test/tests/basic/testBug582766.js | 18 + js/src/jit-test/tests/basic/testBug584650.js | 9 + js/src/jit-test/tests/basic/testBug586866.js | 16 + js/src/jit-test/tests/basic/testBug593559.js | 10 + js/src/jit-test/tests/basic/testBug595916.js | 10 + js/src/jit-test/tests/basic/testBug597736.js | 32 + js/src/jit-test/tests/basic/testBug602413.js | 45 + js/src/jit-test/tests/basic/testBug603193.js | 12 + js/src/jit-test/tests/basic/testBug604210.js | 11 + js/src/jit-test/tests/basic/testBug606138.js | 3 + js/src/jit-test/tests/basic/testBug607659.js | 8 + js/src/jit-test/tests/basic/testBug614653.js | 10 + js/src/jit-test/tests/basic/testBug614752.js | 3 + js/src/jit-test/tests/basic/testBug616119.js | 6 + js/src/jit-test/tests/basic/testBug616454.js | 2 + js/src/jit-test/tests/basic/testBug621202.js | 16 + js/src/jit-test/tests/basic/testBug628564.js | 8 + js/src/jit-test/tests/basic/testBug629974.js | 7 + js/src/jit-test/tests/basic/testBug630064.js | 48 + js/src/jit-test/tests/basic/testBug634590.js | 12 + js/src/jit-test/tests/basic/testBug634590b.js | 19 + js/src/jit-test/tests/basic/testBug634590c.js | 20 + js/src/jit-test/tests/basic/testBug634590d.js | 19 + js/src/jit-test/tests/basic/testBug634590ma.js | 14 + js/src/jit-test/tests/basic/testCallApply.js | 168 + js/src/jit-test/tests/basic/testCallElem.js | 17 + js/src/jit-test/tests/basic/testCallNull.js | 9 + js/src/jit-test/tests/basic/testCallPick.js | 18 + js/src/jit-test/tests/basic/testCallProtoMethod.js | 14 + js/src/jit-test/tests/basic/testCaseAbort.js | 19 + .../tests/basic/testCaseTypeMismatchBadness.js | 22 + .../tests/basic/testChangingObjectWithLength.js | 37 + .../tests/basic/testChangingTypeDuringRecording.js | 6 + .../jit-test/tests/basic/testClosingRecursion.js | 13 + .../tests/basic/testClosureIncrSideExit.js | 17 + js/src/jit-test/tests/basic/testClosures.js | 18 + js/src/jit-test/tests/basic/testComparisons.js | 988 + .../tests/basic/testConcatNWithSideEffects.js | 13 + js/src/jit-test/tests/basic/testConstIf.js | 6 + js/src/jit-test/tests/basic/testConstSwitch.js | 13 + js/src/jit-test/tests/basic/testConstSwitch2.js | 6 + .../tests/basic/testConstantBooleanExpr.js | 6 + .../jit-test/tests/basic/testConstructorArgs-1.js | 11 + .../jit-test/tests/basic/testConstructorArgs-2.js | 12 + .../jit-test/tests/basic/testConstructorArgs-3.js | 11 + js/src/jit-test/tests/basic/testConstructorBail.js | 4 + js/src/jit-test/tests/basic/testContinue.js | 11 + .../jit-test/tests/basic/testContinueWithLabel.js | 16 + .../jit-test/tests/basic/testContinueWithLabel2.js | 7 + .../jit-test/tests/basic/testContinueWithLabel3.js | 6 + .../jit-test/tests/basic/testContinueWithLabel4.js | 25 + .../basic/testConvertibleObjectEqUndefined.js | 33 + js/src/jit-test/tests/basic/testCustomIterator.js | 26 + js/src/jit-test/tests/basic/testDateNow.js | 15 + js/src/jit-test/tests/basic/testDecElem1.js | 10 + js/src/jit-test/tests/basic/testDecElem2.js | 11 + .../jit-test/tests/basic/testDecayingInnerLoop.js | 9 + js/src/jit-test/tests/basic/testDeepBail1.js | 6 + .../tests/basic/testDeepBailFromHasInstance.js | 12 + .../jit-test/tests/basic/testDeepBailInMoreIter.js | 5 + .../tests/basic/testDeepBailWhileRecording.js | 20 + .../tests/basic/testDeepPropertyShadowing.js | 17 + .../basic/testDefinePropertyAcrossCompartment.js | 7 + js/src/jit-test/tests/basic/testDenseArrayProp.js | 12 + .../jit-test/tests/basic/testDenseToSlowArray.js | 185 + js/src/jit-test/tests/basic/testDestructuring.js | 9 + js/src/jit-test/tests/basic/testDifferingArgc.js | 18 + js/src/jit-test/tests/basic/testDivOverflow.js | 6 + js/src/jit-test/tests/basic/testDivision.js | 10 + js/src/jit-test/tests/basic/testDivisionFloat.js | 10 + .../tests/basic/testDivisionWithNegative1.js | 6 + .../jit-test/tests/basic/testDoubleComparison.js | 16 + js/src/jit-test/tests/basic/testDoubleToStr.js | 9 + .../tests/basic/testDoubleZeroInSwitch1.js | 7 + .../tests/basic/testDoubleZeroInSwitch2.js | 9 + js/src/jit-test/tests/basic/testElemDec1.js | 10 + js/src/jit-test/tests/basic/testElemDec2.js | 7 + js/src/jit-test/tests/basic/testElemInc1.js | 10 + js/src/jit-test/tests/basic/testElemInc2.js | 7 + .../tests/basic/testEliminatedGuardWithinAnchor.js | 12 + .../jit-test/tests/basic/testEqFalseEmptyString.js | 6 + .../basic/testErrorReportIn_getPrototypeOf.js | 9 + .../basic/testEvalCalledFromWatchOverSetter.js | 3 + .../tests/basic/testEvalInFunctionCallee.js | 4 + .../testExistingPropToJoinedMethodAttempt-2.js | 8 + .../testExistingPropToJoinedMethodAttempt-3.js | 15 + .../testExistingPropToJoinedMethodAttempt-4.js | 12 + .../basic/testExistingPropToJoinedMethodAttempt.js | 10 + .../tests/basic/testFewerGlobalsInInnerTree.js | 14 + js/src/jit-test/tests/basic/testFloatArrayIndex.js | 9 + js/src/jit-test/tests/basic/testForEach.js | 11 + .../tests/basic/testForInLoopChangeIteratorType.js | 11 + .../tests/basic/testFunctionIdentityChange.js | 21 + .../jit-test/tests/basic/testGCWhileRecording.js | 12 + .../jit-test/tests/basic/testGeneratorDeepBail.js | 11 + js/src/jit-test/tests/basic/testGetCallObj.js | 11 + js/src/jit-test/tests/basic/testGetThis.js | 7 + js/src/jit-test/tests/basic/testGlobalAsProto.js | 3 + .../jit-test/tests/basic/testGlobalMultitrees1.js | 11 + .../jit-test/tests/basic/testGlobalOptimize-2.js | 9 + .../jit-test/tests/basic/testGlobalOptimize-3.js | 9 + .../jit-test/tests/basic/testGlobalOptimize-4.js | 8 + .../jit-test/tests/basic/testGlobalOptimize-5.js | 10 + .../jit-test/tests/basic/testGlobalOptimize-6.js | 10 + .../jit-test/tests/basic/testGlobalProtoAccess.js | 5 + .../basic/testGlobalShapeChangeAfterDeepBail.js | 15 + js/src/jit-test/tests/basic/testGroupAssignment.js | 22 + js/src/jit-test/tests/basic/testGrowDenseArray.js | 7 + .../tests/basic/testGuardCalleeSneakAttack.js | 38 + .../tests/basic/testGuardCalleeSneakAttack2.js | 39 + .../jit-test/tests/basic/testHOTLOOPCorrectness.js | 14 + js/src/jit-test/tests/basic/testHOTLOOPSize.js | 4 + js/src/jit-test/tests/basic/testHeavy.js | 14 + js/src/jit-test/tests/basic/testHeavy2.js | 20 + .../jit-test/tests/basic/testHoleInDenseArray.js | 18 + js/src/jit-test/tests/basic/testHolePushing.js | 13 + .../testHolesAndIndexPropertiesOnThePrototype.js | 29 + js/src/jit-test/tests/basic/testINITELEM.js | 8 + js/src/jit-test/tests/basic/testIn.js | 19 + js/src/jit-test/tests/basic/testIncDec.js | 19 + js/src/jit-test/tests/basic/testIncDecReadOnly.js | 22 + js/src/jit-test/tests/basic/testIncElem1.js | 10 + js/src/jit-test/tests/basic/testIncElem2.js | 11 + js/src/jit-test/tests/basic/testIncElem3.js | 6 + js/src/jit-test/tests/basic/testInitDictionary.js | 51 + js/src/jit-test/tests/basic/testInitMethod.js | 9 + .../jit-test/tests/basic/testInitPropOverMethod.js | 9 + .../tests/basic/testInitPropWithIntName.js | 2 + .../jit-test/tests/basic/testInitProtoPrimitive.js | 2 + js/src/jit-test/tests/basic/testInitSharp.js | 18 + js/src/jit-test/tests/basic/testInitSingletons.js | 31 + js/src/jit-test/tests/basic/testInitSlowify.js | 41 + js/src/jit-test/tests/basic/testInitelemCond.js | 13 + .../tests/basic/testInitelemWithFloatIndex.js | 3 + .../jit-test/tests/basic/testInitelemWithSetter.js | 3 + .../jit-test/tests/basic/testInnerMissingArgs.js | 21 + .../jit-test/tests/basic/testInnerSwitchBreak.js | 24 + .../tests/basic/testInnerTreeMutatingUpvars.js | 17 + js/src/jit-test/tests/basic/testInt32ToId.js | 39 + js/src/jit-test/tests/basic/testIntFloor.js | 8 + js/src/jit-test/tests/basic/testIntOverflow.js | 15 + js/src/jit-test/tests/basic/testIntUnderflow.js | 15 + .../tests/basic/testInterpreterReentery8.js | 6 + .../jit-test/tests/basic/testInterpreterReentry.js | 6 + .../tests/basic/testInterpreterReentry2.js | 11 + .../tests/basic/testInterpreterReentry3.js | 7 + .../tests/basic/testInterpreterReentry4.js | 6 + .../tests/basic/testInterpreterReentry5.js | 9 + .../tests/basic/testInterpreterReentry6.js | 7 + .../tests/basic/testInterpreterReentry7.js | 11 + .../jit-test/tests/basic/testInvalidCharCodeAt.js | 12 + .../tests/basic/testInvertNullAfterNegateNull.js | 7 + .../tests/basic/testIteratorReification.js | 1 + js/src/jit-test/tests/basic/testLambdaCtor.js | 14 + js/src/jit-test/tests/basic/testLambdaInitedVar.js | 8 + js/src/jit-test/tests/basic/testLengthInString.js | 12 + .../tests/basic/testLengthOnNonNativeProto.js | 20 + .../tests/basic/testLetWithUnstableGlobal.js | 11 + js/src/jit-test/tests/basic/testLirBufOOM.js | 34 + js/src/jit-test/tests/basic/testLogicalNotNaN.js | 8 + js/src/jit-test/tests/basic/testLongNumToString.js | 7 + .../jit-test/tests/basic/testLoopWithUndefined1.js | 12 + .../jit-test/tests/basic/testLoopWithUndefined2.js | 20 + .../jit-test/tests/basic/testLoopingAccumulator.js | 21 + .../jit-test/tests/basic/testMatchAsCondition.js | 8 + .../jit-test/tests/basic/testMatchStringObject.js | 8 + js/src/jit-test/tests/basic/testMethodInc.js | 12 + js/src/jit-test/tests/basic/testMethodInit.js | 15 + js/src/jit-test/tests/basic/testMethodInitDeref.js | 9 + .../jit-test/tests/basic/testMethodInitSafety.js | 14 + .../jit-test/tests/basic/testMethodInitUneval.js | 9 + js/src/jit-test/tests/basic/testMethodOverride.js | 20 + js/src/jit-test/tests/basic/testMethodSet.js | 18 + .../jit-test/tests/basic/testMethodWriteBarrier.js | 4 + .../tests/basic/testMethodWriteBarrier2.js | 17 + .../tests/basic/testMethodWriteBarrier3.js | 27 + .../tests/basic/testMethodWriteBarrier4.js | 12 + js/src/jit-test/tests/basic/testMissingMethod.js | 9 + js/src/jit-test/tests/basic/testMissingMethod2.js | 10 + .../tests/basic/testModuloWithNegative1.js | 11 + .../tests/basic/testModuloWithNegative2.js | 7 + .../jit-test/tests/basic/testMoreArgcThanNargs.js | 14 + js/src/jit-test/tests/basic/testMoreClosures.js | 14 + js/src/jit-test/tests/basic/testMulOverflow.js | 6 + .../tests/basic/testMultipleArgumentsObjects.js | 12 + .../tests/basic/testMultiplePendingGlobalWrites.js | 11 + js/src/jit-test/tests/basic/testNEWINIT.js | 8 + js/src/jit-test/tests/basic/testNEWINIT_DOUBLE.js | 6 + .../jit-test/tests/basic/testNativeArgsRooting.js | 14 + js/src/jit-test/tests/basic/testNativeLog.js | 8 + js/src/jit-test/tests/basic/testNativeMax.js | 20 + js/src/jit-test/tests/basic/testNativeSetter.js | 14 + js/src/jit-test/tests/basic/testNegZero1.js | 9 + .../tests/basic/testNegativeArrayLength.js | 10 + .../tests/basic/testNegativeGETELEMIndex.js | 6 + js/src/jit-test/tests/basic/testNestedClosures.js | 23 + js/src/jit-test/tests/basic/testNestedDeepBail.js | 20 + .../tests/basic/testNestedEscapingLambdas.js | 31 + .../tests/basic/testNestedExitStackOuter.js | 29 + js/src/jit-test/tests/basic/testNestedForIn.js | 9 + js/src/jit-test/tests/basic/testNewArrayCount.js | 12 + js/src/jit-test/tests/basic/testNewArrayCount2.js | 8 + js/src/jit-test/tests/basic/testNewDate.js | 17 + js/src/jit-test/tests/basic/testNewObject.js | 8 + js/src/jit-test/tests/basic/testNewString.js | 27 + .../tests/basic/testNewWithNonNativeProto.js | 14 + js/src/jit-test/tests/basic/testNonStubGetter.js | 7 + js/src/jit-test/tests/basic/testNot.js | 8 + js/src/jit-test/tests/basic/testNullCallee.js | 16 + js/src/jit-test/tests/basic/testNullIncrement.js | 21 + js/src/jit-test/tests/basic/testNullRelCmp.js | 6 + js/src/jit-test/tests/basic/testNullToString.js | 18 + js/src/jit-test/tests/basic/testNumToString.js | 18 + js/src/jit-test/tests/basic/testNumberToString.js | 6 + .../basic/testObjectConstructorReturningObject.js | 12 + js/src/jit-test/tests/basic/testObjectLength.js | 15 + .../jit-test/tests/basic/testObjectOrderedCmp.js | 7 + .../jit-test/tests/basic/testObjectOrderedCmp2.js | 7 + js/src/jit-test/tests/basic/testObjectToNumber.js | 8 + js/src/jit-test/tests/basic/testObjectToString.js | 8 + .../jit-test/tests/basic/testObjectVsPrototype.js | 12 + .../tests/basic/testOwnPropertyWithInOperator.js | 12 + .../jit-test/tests/basic/testPartialFlatClosure.js | 16 + .../basic/testPrimitiveConstructorPrototype.js | 7 + .../jit-test/tests/basic/testPropagatedFunArgs.js | 34 + .../jit-test/tests/basic/testProxyConstructors.js | 16 + .../testProxyDefinePropertyWithMissingSetter.js | 23 + .../tests/basic/testPutOnEmptyArgsObject.js | 16 + .../jit-test/tests/basic/testRUNLOOPCorrectness.js | 15 + .../tests/basic/testReallyDeepNestedExit.js | 38 + js/src/jit-test/tests/basic/testRebranding.js | 10 + js/src/jit-test/tests/basic/testRebranding2.js | 21 + .../tests/basic/testReconstructImacroPCStack.js | 28 + js/src/jit-test/tests/basic/testRegExpLiteral.js | 17 + js/src/jit-test/tests/basic/testRegExpTest.js | 10 + js/src/jit-test/tests/basic/testRegexpGet.js | 8 + js/src/jit-test/tests/basic/testReplace2.js | 7 + js/src/jit-test/tests/basic/testReplaceMap.js | 27 + js/src/jit-test/tests/basic/testResumeOp.js | 8 + js/src/jit-test/tests/basic/testReverseArgTypes.js | 5 + .../basic/testScriptGetter_JSOP_CALLPROP-2.js | 13 + .../tests/basic/testScriptGetter_JSOP_CALLPROP.js | 11 + .../basic/testScriptGetter_JSOP_GETARGPROP.js | 9 + .../basic/testScriptGetter_JSOP_GETLOCALPROP.js | 10 + .../tests/basic/testScriptGetter_JSOP_GETPROP.js | 10 + .../basic/testScriptGetter_JSOP_GETTHISPROP.js | 11 + .../tests/basic/testSetGetterOnlyProperty.js | 5 + js/src/jit-test/tests/basic/testSetMethod.js | 13 + .../tests/basic/testSetPropNeitherMissNorHit.js | 5 + js/src/jit-test/tests/basic/testSetPropertyFail.js | 22 + .../basic/testSetProtoRegeneratesObjectShape.js | 24 + .../tests/basic/testSetelemWithFloatIndex.js | 4 + .../basic/testSettingWatchPointOnReadOnlyProp.js | 7 + js/src/jit-test/tests/basic/testShiftLeft.js | 38 + .../tests/basic/testShiftRightArithmetic.js | 44 + .../jit-test/tests/basic/testShiftRightLogical.js | 38 + .../tests/basic/testSideExitInConstructor.js | 39 + js/src/jit-test/tests/basic/testSlowArrayLength.js | 15 + js/src/jit-test/tests/basic/testSlowArrayPop.js | 12 + .../tests/basic/testSlowArrayPopMultiFrame.js | 24 + .../tests/basic/testSlowArrayPopNestedTrees.js | 36 + js/src/jit-test/tests/basic/testSlowNativeBail.js | 10 + js/src/jit-test/tests/basic/testSlowNativeCtor.js | 7 + .../tests/basic/testSlowNativeWithNullThis.js | 6 + .../tests/basic/testStackQuotaExhausted.js | 29 + js/src/jit-test/tests/basic/testStaticsInRegExp.js | 9 + js/src/jit-test/tests/basic/testStrict.js | 11 + js/src/jit-test/tests/basic/testString.js | 18 + .../basic/testStringConstructorWithExtraArg.js | 6 + js/src/jit-test/tests/basic/testStringIncrement.js | 27 + .../tests/basic/testStringLengthNoTinyId.js | 64 + .../jit-test/tests/basic/testStringObjectLength.js | 7 + .../tests/basic/testStringPropIncrement.js | 16 + js/src/jit-test/tests/basic/testStringResolve.js | 9 + js/src/jit-test/tests/basic/testStringToInt32.js | 6 + js/src/jit-test/tests/basic/testStringToNumber.js | 47 + js/src/jit-test/tests/basic/testStringify.js | 20 + js/src/jit-test/tests/basic/testSubstring.js | 7 + .../tests/basic/testSuppressDeletedProperty.js | 8 + js/src/jit-test/tests/basic/testSwitch.js | 25 + js/src/jit-test/tests/basic/testSwitchString.js | 28 + js/src/jit-test/tests/basic/testSwitchUndefined.js | 15 + js/src/jit-test/tests/basic/testTableSwitch1.js | 22 + js/src/jit-test/tests/basic/testTableSwitch2.js | 27 + js/src/jit-test/tests/basic/testThinForEach.js | 10 + js/src/jit-test/tests/basic/testThinLoopDemote.js | 20 + .../tests/basic/testThrowingObjectEqUndefined.js | 18 + js/src/jit-test/tests/basic/testToLocaleString.js | 2 + .../tests/basic/testToStringBeforeValueOf.js | 13 + js/src/jit-test/tests/basic/testToUpperToLower.js | 9 + js/src/jit-test/tests/basic/testTrueShiftTrue.js | 16 + .../jit-test/tests/basic/testTypeUnstableForIn.js | 10 + .../jit-test/tests/basic/testTypedArrayPunning.js | 42 + js/src/jit-test/tests/basic/testTypedArrays.js | 104 + js/src/jit-test/tests/basic/testTypeofHole.js | 8 + js/src/jit-test/tests/basic/testUnaryImacros.js | 26 + .../tests/basic/testUndefinedBooleanCmp.js | 24 + js/src/jit-test/tests/basic/testUndefinedCmp.js | 6 + .../jit-test/tests/basic/testUndefinedIncrement.js | 22 + .../tests/basic/testUndefinedPropertyAccess.js | 15 + .../tests/basic/testUndemotableBinaryOp.js | 6 + .../tests/basic/testUndemoteLateGlobalSlots.js | 11 + js/src/jit-test/tests/basic/testWeirdDateParse.js | 46 + .../jit-test/tests/basic/testWhileObjectOrNull.js | 18 + .../jit-test/tests/basic/testWhileWithContinue.js | 10 + .../jit-test/tests/basic/testWithAndShadowing.js | 14 + .../jit-test/tests/basic/testXMLPropertyNames.js | 11 + js/src/jit-test/tests/basic/test_JSOP_ARGCNT.js | 27 + js/src/jit-test/tests/basic/test_JSOP_ARGSUB.js | 27 + js/src/jit-test/tests/basic/testif.js | 11 + js/src/jit-test/tests/basic/testincops.js | 24 + js/src/jit-test/tests/basic/trees.js | 10 + js/src/jit-test/tests/basic/truthies.js | 29 + js/src/jit-test/tests/basic/typeofTest.js | 8 + js/src/jit-test/tests/basic/unboxint.js | 8 + js/src/jit-test/tests/basic/wrap-primitive-this.js | 39 + js/src/jit-test/tests/basic/xprop.js | 8 + js/src/jit-test/tests/closures/bug496922.js | 20 + js/src/jit-test/tests/closures/bug496987.js | 17 + js/src/jit-test/tests/closures/bug497015-1.js | 19 + js/src/jit-test/tests/closures/bug497015-2.js | 22 + js/src/jit-test/tests/closures/bug540131-2.js | 13 + js/src/jit-test/tests/closures/bug540131-3.js | 13 + js/src/jit-test/tests/closures/bug540131.js | 5 + js/src/jit-test/tests/closures/bug540133.js | 4 + js/src/jit-test/tests/closures/bug540136.js | 17 + js/src/jit-test/tests/closures/bug540242.js | 17 + js/src/jit-test/tests/closures/bug540243.js | 10 + js/src/jit-test/tests/closures/bug540348.js | 3 + js/src/jit-test/tests/closures/bug540528.js | 4 + js/src/jit-test/tests/closures/bug541239.js | 16 + js/src/jit-test/tests/closures/bug543565.js | 7 + js/src/jit-test/tests/closures/closure-pluseq.js | 31 + js/src/jit-test/tests/closures/closure-pluseq2.js | 30 + js/src/jit-test/tests/closures/closure-plusplus.js | 31 + js/src/jit-test/tests/closures/closure-tests.js | 6 + js/src/jit-test/tests/closures/flat-closure-1.js | 18 + js/src/jit-test/tests/closures/flat-closure-2.js | 15 + js/src/jit-test/tests/closures/flat-closure-3.js | 9 + js/src/jit-test/tests/closures/flat-closure-4.js | 15 + js/src/jit-test/tests/closures/flat-closure-5.js | 19 + js/src/jit-test/tests/closures/flat-closure-6.js | 17 + js/src/jit-test/tests/closures/flat-closure-7.js | 16 + js/src/jit-test/tests/closures/flat-closure-8.js | 19 + js/src/jit-test/tests/closures/incr-exit-2.js | 20 + js/src/jit-test/tests/closures/incr-exit-3.js | 28 + js/src/jit-test/tests/closures/incr-exit.js | 20 + .../jit-test/tests/closures/lambda-inner-heavy.js | 32 + .../tests/closures/lambda-light-returned.js | 25 + js/src/jit-test/tests/closures/lambda-light.js | 18 + js/src/jit-test/tests/closures/lambda.js | 27 + js/src/jit-test/tests/closures/lambdafc.js | 25 + js/src/jit-test/tests/closures/name-both-hvy.js | 28 + .../tests/closures/name-inactive-missing.js | 14 + js/src/jit-test/tests/closures/name.js | 25 + js/src/jit-test/tests/closures/name2.js | 23 + js/src/jit-test/tests/closures/name2a.js | 23 + js/src/jit-test/tests/closures/name2b.js | 23 + js/src/jit-test/tests/closures/name3.js | 24 + js/src/jit-test/tests/closures/name4.js | 22 + js/src/jit-test/tests/closures/namedLambda.js | 17 + js/src/jit-test/tests/closures/nameinc-loop-2.js | 26 + js/src/jit-test/tests/closures/nameinc-loop-3.js | 33 + .../tests/closures/nameinc-loop-missing-2.js | 19 + .../tests/closures/nameinc-loop-missing.js | 21 + js/src/jit-test/tests/closures/nameinc-loop.js | 24 + js/src/jit-test/tests/closures/nameinc.js | 21 + .../jit-test/tests/closures/set-outer-trace-1.js | 24 + .../jit-test/tests/closures/set-outer-trace-2.js | 23 + .../jit-test/tests/closures/set-outer-trace-3.js | 23 + .../jit-test/tests/closures/set-outer-trace-4.js | 23 + js/src/jit-test/tests/closures/set-outer-trace.js | 23 + js/src/jit-test/tests/closures/setname-1.js | 26 + .../jit-test/tests/closures/setname-closure-2.js | 27 + js/src/jit-test/tests/closures/setname-closure.js | 25 + .../jit-test/tests/closures/setname-inner-heavy.js | 18 + js/src/jit-test/tests/closures/setname-loop-2.js | 29 + js/src/jit-test/tests/closures/setname-loop.js | 26 + js/src/jit-test/tests/closures/setname-no-pop.js | 16 + js/src/jit-test/tests/closures/t001.js | 21 + js/src/jit-test/tests/closures/t002.js | 21 + js/src/jit-test/tests/closures/t003.js | 21 + js/src/jit-test/tests/closures/t004.js | 21 + js/src/jit-test/tests/closures/t005.js | 24 + js/src/jit-test/tests/closures/t006.js | 22 + js/src/jit-test/tests/closures/t007.js | 23 + js/src/jit-test/tests/closures/t008.js | 26 + js/src/jit-test/tests/closures/t009.js | 18 + js/src/jit-test/tests/closures/t010.js | 21 + js/src/jit-test/tests/closures/t011.js | 18 + js/src/jit-test/tests/closures/t012.js | 19 + js/src/jit-test/tests/closures/t013.js | 21 + js/src/jit-test/tests/closures/t014.js | 21 + js/src/jit-test/tests/closures/t015.js | 21 + js/src/jit-test/tests/closures/t016.js | 23 + js/src/jit-test/tests/closures/t017.js | 23 + js/src/jit-test/tests/closures/t018.js | 16 + js/src/jit-test/tests/closures/t019.js | 16 + js/src/jit-test/tests/closures/t020.js | 17 + js/src/jit-test/tests/closures/t021.js | 18 + js/src/jit-test/tests/closures/t022.js | 24 + js/src/jit-test/tests/closures/t023.js | 17 + js/src/jit-test/tests/closures/t024.js | 19 + js/src/jit-test/tests/closures/t025.js | 26 + js/src/jit-test/tests/closures/t026.js | 22 + js/src/jit-test/tests/closures/t027.js | 21 + js/src/jit-test/tests/closures/t028.js | 23 + js/src/jit-test/tests/closures/t029.js | 21 + js/src/jit-test/tests/closures/t030.js | 21 + js/src/jit-test/tests/closures/t031.js | 21 + js/src/jit-test/tests/closures/t032.js | 24 + js/src/jit-test/tests/closures/t033.js | 19 + js/src/jit-test/tests/closures/t034.js | 20 + js/src/jit-test/tests/closures/t035.js | 18 + js/src/jit-test/tests/closures/t036.js | 24 + js/src/jit-test/tests/closures/t037.js | 14 + .../jit-test/tests/closures/test-inner-imports.js | 22 + js/src/jit-test/tests/closures/upvar-nest.js | 24 + js/src/jit-test/tests/jaeger/bug549393-1.js | 43 + js/src/jit-test/tests/jaeger/bug549393-2.js | 10 + js/src/jit-test/tests/jaeger/bug549396.js | 1 + js/src/jit-test/tests/jaeger/bug549398.js | 10 + js/src/jit-test/tests/jaeger/bug549521.js | 12 + js/src/jit-test/tests/jaeger/bug549602.js | 31 + js/src/jit-test/tests/jaeger/bug549603.js | 3 + js/src/jit-test/tests/jaeger/bug550490.js | 14 + js/src/jit-test/tests/jaeger/bug550665.js | 8 + js/src/jit-test/tests/jaeger/bug551603.js | 8 + js/src/jit-test/tests/jaeger/bug552644.js | 6 + js/src/jit-test/tests/jaeger/bug553781-2.js | 13 + js/src/jit-test/tests/jaeger/bug553781.js | 11 + js/src/jit-test/tests/jaeger/bug553784.js | 18 + js/src/jit-test/tests/jaeger/bug554580-1.js | 7 + js/src/jit-test/tests/jaeger/bug554580-2.js | 9 + js/src/jit-test/tests/jaeger/bug554580-3.js | 11 + js/src/jit-test/tests/jaeger/bug554580-4.js | 18 + js/src/jit-test/tests/jaeger/bug554580-5.js | 20 + js/src/jit-test/tests/jaeger/bug554651.js | 15 + js/src/jit-test/tests/jaeger/bug554675-1.js | 8 + js/src/jit-test/tests/jaeger/bug554675-2.js | 11 + js/src/jit-test/tests/jaeger/bug554675-3.js | 11 + js/src/jit-test/tests/jaeger/bug555152.js | 9 + js/src/jit-test/tests/jaeger/bug555155.js | 12 + js/src/jit-test/tests/jaeger/bug555206.js | 4 + js/src/jit-test/tests/jaeger/bug555543.js | 8 + js/src/jit-test/tests/jaeger/bug555922.js | 11 + js/src/jit-test/tests/jaeger/bug556525.js | 5 + js/src/jit-test/tests/jaeger/bug557063.js | 7 + js/src/jit-test/tests/jaeger/bug557068.js | 5 + js/src/jit-test/tests/jaeger/bug557070.js | 6 + js/src/jit-test/tests/jaeger/bug557075.js | 8 + js/src/jit-test/tests/jaeger/bug560221.js | 13 + .../tests/jaeger/bug563000/eif-call-newvar.js | 14 + .../tests/jaeger/bug563000/eif-call-typechange.js | 14 + js/src/jit-test/tests/jaeger/bug563000/eif-call.js | 14 + .../tests/jaeger/bug563000/eif-getter-newvar.js | 10 + .../jaeger/bug563000/eif-getter-typechange.js | 11 + .../jit-test/tests/jaeger/bug563000/eif-getter.js | 11 + .../tests/jaeger/bug563000/eif-trap-newvar.js | 10 + .../tests/jaeger/bug563000/eif-trap-typechange.js | 13 + js/src/jit-test/tests/jaeger/bug563000/eif-trap.js | 11 + .../tests/jaeger/bug563000/simple-trap-1.js | 10 + .../tests/jaeger/bug563000/simple-trap-2.js | 11 + .../tests/jaeger/bug563000/simple-untrap.js | 12 + .../tests/jaeger/bug563000/test-debugger-1.js | 13 + .../tests/jaeger/bug563000/test-debugger-2.js | 10 + .../tests/jaeger/bug563000/test-throwhook-1.js | 19 + .../tests/jaeger/bug563000/test-throwhook-2.js | 14 + .../tests/jaeger/bug563000/trap-force-return-1.js | 8 + .../tests/jaeger/bug563000/trap-force-return-2.js | 8 + .../tests/jaeger/bug563000/trap-from-add-inline.js | 13 + .../tests/jaeger/bug563000/trap-from-add-ool.js | 15 + .../tests/jaeger/bug563000/trap-own-callsite.js | 16 + .../jaeger/bug563000/trap-parent-from-trap.js | 22 + .../jit-test/tests/jaeger/bug563000/trap-parent.js | 17 + .../tests/jaeger/bug563000/trap-self-as-parent.js | 19 + .../tests/jaeger/bug563000/trap-self-from-trap.js | 24 + .../jit-test/tests/jaeger/bug563000/trap-self.js | 12 + .../tests/jaeger/bug563000/untrap-cross-global.js | 5 + .../tests/jaeger/bug563000/untrap-own-trapsite.js | 16 + .../jit-test/tests/jaeger/bug563000/untrap-self.js | 14 + js/src/jit-test/tests/jaeger/bug565198.js | 6 + js/src/jit-test/tests/jaeger/bug565202.js | 7 + js/src/jit-test/tests/jaeger/bug566022.js | 8 + js/src/jit-test/tests/jaeger/bug573433.js | 7 + js/src/jit-test/tests/jaeger/bug576398.js | 10 + js/src/jit-test/tests/jaeger/bug577580.js | 7 + js/src/jit-test/tests/jaeger/bug577646.js | 5 + js/src/jit-test/tests/jaeger/bug577705.js | 65 + js/src/jit-test/tests/jaeger/bug577996.js | 6 + js/src/jit-test/tests/jaeger/bug580703.js | 9 + js/src/jit-test/tests/jaeger/bug580712.js | 1 + js/src/jit-test/tests/jaeger/bug580883.js | 6 + js/src/jit-test/tests/jaeger/bug580884-2.js | 23 + js/src/jit-test/tests/jaeger/bug580884-3.js | 10 + js/src/jit-test/tests/jaeger/bug580884.js | 8 + js/src/jit-test/tests/jaeger/bug580931-2.js | 4 + js/src/jit-test/tests/jaeger/bug581871.js | 10 + js/src/jit-test/tests/jaeger/bug581936.js | 12 + js/src/jit-test/tests/jaeger/bug582185.js | 3 + js/src/jit-test/tests/jaeger/bug582286.js | 3 + js/src/jit-test/tests/jaeger/bug582392.js | 8 + js/src/jit-test/tests/jaeger/bug582880.js | 9 + js/src/jit-test/tests/jaeger/bug582882.js | 11 + js/src/jit-test/tests/jaeger/bug582884.js | 7 + js/src/jit-test/tests/jaeger/bug582894.js | 6 + js/src/jit-test/tests/jaeger/bug582897.js | 6 + js/src/jit-test/tests/jaeger/bug582898.js | 6 + js/src/jit-test/tests/jaeger/bug582900.js | 3 + js/src/jit-test/tests/jaeger/bug583158.js | 9 + js/src/jit-test/tests/jaeger/bug583160.js | 10 + js/src/jit-test/tests/jaeger/bug583672.js | 30 + js/src/jit-test/tests/jaeger/bug583684.js | 8 + js/src/jit-test/tests/jaeger/bug583688.js | 10 + js/src/jit-test/tests/jaeger/bug583689.js | 7 + js/src/jit-test/tests/jaeger/bug584644-2.js | 7 + js/src/jit-test/tests/jaeger/bug584646.js | 7 + js/src/jit-test/tests/jaeger/bug584647.js | 2 + js/src/jit-test/tests/jaeger/bug585310.js | 19 + js/src/jit-test/tests/jaeger/bug585341.js | 6 + js/src/jit-test/tests/jaeger/bug585391.js | 11 + js/src/jit-test/tests/jaeger/bug585408-2.js | 6 + js/src/jit-test/tests/jaeger/bug585408-3.js | 7 + js/src/jit-test/tests/jaeger/bug585408.js | 7 + js/src/jit-test/tests/jaeger/bug585540.js | 13 + js/src/jit-test/tests/jaeger/bug587431.js | 29 + js/src/jit-test/tests/jaeger/bug588338.js | 14 + js/src/jit-test/tests/jaeger/bug588362-1.js | 8 + js/src/jit-test/tests/jaeger/bug588362-2.js | 10 + js/src/jit-test/tests/jaeger/bug588362-3.js | 10 + js/src/jit-test/tests/jaeger/bug588363-1.js | 5 + js/src/jit-test/tests/jaeger/bug588363-2.js | 7 + js/src/jit-test/tests/jaeger/bug589108.js | 10 + js/src/jit-test/tests/jaeger/bug589115.js | 6 + js/src/jit-test/tests/jaeger/bug589461.js | 7 + js/src/jit-test/tests/jaeger/bug590083.js | 11 + js/src/jit-test/tests/jaeger/bug591602.js | 40 + js/src/jit-test/tests/jaeger/bug591606.js | 5 + js/src/jit-test/tests/jaeger/bug592973-1.js | 12 + js/src/jit-test/tests/jaeger/bug592973-2.js | 7 + js/src/jit-test/tests/jaeger/bug592973-3.js | 8 + js/src/jit-test/tests/jaeger/bug593554.js | 8 + js/src/jit-test/tests/jaeger/bug595917.js | 4 + js/src/jit-test/tests/jaeger/bug595921.js | 9 + js/src/jit-test/tests/jaeger/bug597378.js | 12 + js/src/jit-test/tests/jaeger/bug597871.js | 8 + js/src/jit-test/tests/jaeger/bug598696.js | 6 + js/src/jit-test/tests/jaeger/bug599488.js | 9 + js/src/jit-test/tests/jaeger/bug600139.js | 11 + js/src/jit-test/tests/jaeger/bug600419.js | 5 + js/src/jit-test/tests/jaeger/bug600424.js | 14 + js/src/jit-test/tests/jaeger/bug601400.js | 8 + js/src/jit-test/tests/jaeger/bug601982.js | 33 + js/src/jit-test/tests/jaeger/bug604381.js | 14 + js/src/jit-test/tests/jaeger/bug604427.js | 6 + js/src/jit-test/tests/jaeger/bug606662-1.js | 5 + js/src/jit-test/tests/jaeger/bug606662-2.js | 5 + js/src/jit-test/tests/jaeger/bug606829.js | 8 + js/src/jit-test/tests/jaeger/bug610652.js | 5 + js/src/jit-test/tests/jaeger/bug615440.js | 5 + js/src/jit-test/tests/jaeger/bug616508.js | 9 + js/src/jit-test/tests/jaeger/bug618007.js | 31 + js/src/jit-test/tests/jaeger/bug620643.js | 1 + js/src/jit-test/tests/jaeger/bug623474.js | 10 + js/src/jit-test/tests/jaeger/bug624100.js | 2 + js/src/jit-test/tests/jaeger/bug624483.js | 5 + js/src/jit-test/tests/jaeger/bug625157.js | 16 + js/src/jit-test/tests/jaeger/bug625377.js | 13 + js/src/jit-test/tests/jaeger/bug625438.js | 10 + js/src/jit-test/tests/jaeger/bug625718-1.js | 12 + js/src/jit-test/tests/jaeger/bug625718-2.js | 14 + js/src/jit-test/tests/jaeger/bug625718-3.js | 52 + js/src/jit-test/tests/jaeger/bug625757.js | 4 + js/src/jit-test/tests/jaeger/bug627486.js | 23 + js/src/jit-test/tests/jaeger/bug630366.js | 7 + js/src/jit-test/tests/jaeger/compare-wrong-1.js | 4 + js/src/jit-test/tests/jaeger/crash-on-compare.js | 1 + .../tests/jaeger/deepBailAfterRunTracer.js | 25 + js/src/jit-test/tests/jaeger/floatTypedArrays.js | 64 + js/src/jit-test/tests/jaeger/fused-eq-ifeq.js | 6 + js/src/jit-test/tests/jaeger/getelem-sanity-1.js | 9 + js/src/jit-test/tests/jaeger/getelem-sanity-2.js | 22 + js/src/jit-test/tests/jaeger/getelem-sanity-3.js | 22 + js/src/jit-test/tests/jaeger/getelem-sanity-4.js | 51 + js/src/jit-test/tests/jaeger/getelem-sanity-5.js | 4 + js/src/jit-test/tests/jaeger/getelem-sanity-6.js | 4 + js/src/jit-test/tests/jaeger/getelem-sanity-7.js | 10 + .../jit-test/tests/jaeger/getelem-sanity-int-1.js | 7 + .../jit-test/tests/jaeger/getelem-sanity-int-2.js | 12 + .../jit-test/tests/jaeger/getelem-sanity-int-3.js | 19 + js/src/jit-test/tests/jaeger/globalOptimize-1.js | 5 + .../tests/jaeger/instanceOfWithKnownTypes.js | 13 + js/src/jit-test/tests/jaeger/invokeSessionGuard.js | 8 + js/src/jit-test/tests/jaeger/modConstDoubles.js | 8 + js/src/jit-test/tests/jaeger/modConstInt.js | 8 + js/src/jit-test/tests/jaeger/modConstZeroRhs.js | 8 + js/src/jit-test/tests/jaeger/modWithConstLhs.js | 2 + js/src/jit-test/tests/jaeger/mulNegZero.js | 31 + js/src/jit-test/tests/jaeger/negation.js | 2 + .../jit-test/tests/jaeger/normalIntTypedArrays.js | 49 + js/src/jit-test/tests/jaeger/optimize-globals-1.js | 9 + js/src/jit-test/tests/jaeger/optimize-globals-2.js | 20 + js/src/jit-test/tests/jaeger/optimize-globals-3.js | 9 + js/src/jit-test/tests/jaeger/regalloc-1.js | 15 + js/src/jit-test/tests/jaeger/regress-bug625701.js | 10 + js/src/jit-test/tests/jaeger/rsh-sanity-1.js | 17 + js/src/jit-test/tests/jaeger/scriptedICs-1.js | 39 + .../jit-test/tests/jaeger/smallIntTypedArrays.js | 112 + .../tests/jaeger/strictModeSetUndefinedVar.js | 8 + js/src/jit-test/tests/jaeger/subCommutativity.js | 4 + js/src/jit-test/tests/jaeger/tableSwitchConst.js | 18 + js/src/jit-test/tests/jaeger/tableSwitchDouble.js | 13 + js/src/jit-test/tests/jaeger/tableSwitchEmpty.js | 14 + js/src/jit-test/tests/jaeger/tableSwitchFloat.js | 18 + js/src/jit-test/tests/jaeger/tableSwitchNeg.js | 27 + .../jit-test/tests/jaeger/testAddStringObject.js | 17 + js/src/jit-test/tests/jaeger/testBug550743.js | 21 + .../jit-test/tests/jaeger/testCallElemAfterGC.js | 20 + js/src/jit-test/tests/jaeger/testDenseCallElem.js | 89 + js/src/jit-test/tests/jaeger/testForOps.js | 73 + js/src/jit-test/tests/jaeger/testPropCallElem.js | 93 + js/src/jit-test/tests/jaeger/testPropCallElem2.js | 20 + js/src/jit-test/tests/jaeger/testSetElem-Easy.js | 41 + .../jit-test/tests/jaeger/testSetElem-Indexed.js | 36 + .../jit-test/tests/jaeger/testSetElem-NewProto.js | 24 + .../tests/jaeger/testSetTypedFloatArray.js | 61 + .../jit-test/tests/jaeger/testSetTypedIntArray.js | 190 + .../jit-test/tests/jaeger/testShiftSameBacking.js | 12 + js/src/jit-test/tests/jaeger/unsignedShiftZero.js | 8 + js/src/jit-test/tests/jaeger/xor-sanity.js | 1 + js/src/jit-test/tests/pic/bug558099.js | 60 + js/src/jit-test/tests/pic/bug558616.js | 9 + js/src/jit-test/tests/pic/bug582899.js | 8 + js/src/jit-test/tests/pic/bug584642.js | 3 + js/src/jit-test/tests/pic/bug595706.js | 19 + js/src/jit-test/tests/pic/call_self.js | 15 + js/src/jit-test/tests/pic/densearray.js | 12 + js/src/jit-test/tests/pic/fuzz1.js | 4 + js/src/jit-test/tests/pic/fuzz2.js | 3 + js/src/jit-test/tests/pic/fuzz3.js | 3 + js/src/jit-test/tests/pic/grandproto.js | 28 + js/src/jit-test/tests/pic/length_array.js | 16 + js/src/jit-test/tests/pic/length_mix.js | 22 + js/src/jit-test/tests/pic/length_object.js | 16 + js/src/jit-test/tests/pic/length_string.js | 16 + js/src/jit-test/tests/pic/length_string_object.js | 36 + js/src/jit-test/tests/pic/proto1.js | 24 + js/src/jit-test/tests/pic/proto3.js | 32 + js/src/jit-test/tests/pic/proto_self.js | 39 + js/src/jit-test/tests/pic/self1.js | 18 + js/src/jit-test/tests/pic/self2.js | 18 + js/src/jit-test/tests/pic/self3.js | 19 + js/src/jit-test/tests/pic/self8.js | 32 + js/src/jit-test/tests/pic/set-assign.js | 10 + js/src/jit-test/tests/pic/set1.js | 11 + js/src/jit-test/tests/pic/set2.js | 14 + js/src/jit-test/tests/pic/shape_regen.js | 33 + js/src/jit-test/tests/pic/thisprop.js | 30 + js/src/jit-test/tests/pic/to-dictionary.js | 9 + js/src/jit-test/tests/sunspider/check-3d-cube.js | 345 + js/src/jit-test/tests/sunspider/check-3d-morph.js | 59 + .../jit-test/tests/sunspider/check-3d-raytrace.js | 443 + .../tests/sunspider/check-access-binary-trees.js | 52 + .../tests/sunspider/check-access-fannkuch.js | 66 + .../jit-test/tests/sunspider/check-access-nbody.js | 171 + .../tests/sunspider/check-access-nsieve.js | 40 + .../sunspider/check-bitops-3bit-bits-in-byte.js | 35 + .../tests/sunspider/check-bitops-bits-in-byte.js | 24 + .../tests/sunspider/check-bitops-bitwise-and.js | 29 + .../tests/sunspider/check-bitops-nsieve-bits.js | 40 + .../tests/sunspider/check-controlflow-recursive.js | 27 + .../jit-test/tests/sunspider/check-crypto-aes.js | 424 + .../jit-test/tests/sunspider/check-crypto-md5.js | 287 + .../jit-test/tests/sunspider/check-crypto-sha1.js | 225 + .../tests/sunspider/check-date-format-tofte.js | 302 + .../tests/sunspider/check-date-format-xparb.js | 422 + .../jit-test/tests/sunspider/check-math-cordic.js | 100 + .../tests/sunspider/check-math-partial-sums.js | 41 + .../tests/sunspider/check-math-spectral-norm.js | 53 + js/src/jit-test/tests/sunspider/check-mont.js | 119 + .../jit-test/tests/sunspider/check-regexp-dna.js | 1714 + .../jit-test/tests/sunspider/check-string-fasta.js | 90 + .../tests/sunspider/check-string-tagcloud.js | 270 + .../tests/sunspider/check-string-unpack-code.js | 73 + .../jit-test/tests/testCrossGlobalInvokeSession.js | 12 + js/src/jit-test/tests/v8-v5/check-crypto.js | 1713 + js/src/jit-test/tests/v8-v5/check-deltablue.js | 883 + js/src/jit-test/tests/v8-v5/check-earley-boyer.js | 4694 ++ js/src/jit-test/tests/v8-v5/check-raytrace.js | 935 + js/src/jit-test/tests/v8-v5/check-regexp.js | 1616 + js/src/jit-test/tests/v8-v5/check-richards.js | 536 + js/src/jit-test/tests/v8-v5/check-splay.js | 393 + js/src/jitstats.tbl | 97 + js/src/js-config.h.in | 91 + js/src/js-config.in | 111 + js/src/js.mdp | Bin 0 -> 17922 bytes js/src/js.msg | 351 + js/src/jsanalyze.cpp | 676 + js/src/jsanalyze.h | 213 + js/src/jsapi-tests/Makefile.in | 97 + js/src/jsapi-tests/README | 160 + js/src/jsapi-tests/selfTest.cpp | 24 + js/src/jsapi-tests/testBug604087.cpp | 84 + js/src/jsapi-tests/testClassGetter.cpp | 69 + js/src/jsapi-tests/testCloneScript.cpp | 50 + js/src/jsapi-tests/testConservativeGC.cpp | 80 + js/src/jsapi-tests/testContexts.cpp | 52 + js/src/jsapi-tests/testCustomIterator.cpp | 81 + js/src/jsapi-tests/testDebugger.cpp | 102 + js/src/jsapi-tests/testDeepFreeze.cpp | 54 + .../testDefineGetterSetterNonEnumerable.cpp | 59 + js/src/jsapi-tests/testDefineProperty.cpp | 20 + js/src/jsapi-tests/testExtendedEq.cpp | 59 + js/src/jsapi-tests/testFuncCallback.cpp | 138 + js/src/jsapi-tests/testGCChunkAlloc.cpp | 111 + js/src/jsapi-tests/testGetPropertyDefault.cpp | 66 + js/src/jsapi-tests/testIntString.cpp | 40 + js/src/jsapi-tests/testIsAboutToBeFinalized.cpp | 136 + js/src/jsapi-tests/testLookup.cpp | 76 + js/src/jsapi-tests/testNewObject.cpp | 100 + js/src/jsapi-tests/testOps.cpp | 60 + js/src/jsapi-tests/testPropCache.cpp | 35 + js/src/jsapi-tests/testSameValue.cpp | 24 + js/src/jsapi-tests/testScriptObject.cpp | 138 + js/src/jsapi-tests/testSetProperty.cpp | 87 + js/src/jsapi-tests/testThreadGC.cpp | 195 + js/src/jsapi-tests/testThreads.cpp | 174 + js/src/jsapi-tests/testTrap.cpp | 82 + js/src/jsapi-tests/testUTF8.cpp | 21 + js/src/jsapi-tests/testVersion.cpp | 264 + js/src/jsapi-tests/testXDR.cpp | 85 + js/src/jsapi-tests/tests.cpp | 87 + js/src/jsapi-tests/tests.h | 397 + js/src/jsapi.cpp | 6186 ++ js/src/jsapi.h | 3842 ++ js/src/jsarena.cpp | 450 + js/src/jsarena.h | 291 + js/src/jsarray.cpp | 3291 + js/src/jsarray.h | 342 + js/src/jsast.tbl | 119 + js/src/jsatom.cpp | 1026 + js/src/jsatom.h | 614 + js/src/jsatominlines.h | 145 + js/src/jsbit.h | 305 + js/src/jsbool.cpp | 194 + js/src/jsbool.h | 74 + js/src/jsbuiltins.cpp | 322 + js/src/jsbuiltins.h | 635 + js/src/jscell.h | 99 + js/src/jsclist.h | 139 + js/src/jsclone.cpp | 861 + js/src/jsclone.h | 191 + js/src/jscntxt.cpp | 2314 + js/src/jscntxt.h | 3348 + js/src/jscntxtinlines.h | 825 + js/src/jscompartment.cpp | 615 + js/src/jscompartment.h | 635 + js/src/jscompat.h | 55 + js/src/jsconfig.mk | 169 + js/src/jscpucfg.cpp | 182 + js/src/jscpucfg.h | 91 + js/src/jsdate.cpp | 2742 + js/src/jsdate.h | 125 + js/src/jsdbgapi.cpp | 2690 + js/src/jsdbgapi.h | 626 + js/src/jsdbgapiinlines.h | 68 + js/src/jsdhash.cpp | 903 + js/src/jsdhash.h | 607 + js/src/jsdtoa.cpp | 540 + js/src/jsdtoa.h | 148 + js/src/jsemit.cpp | 7744 +++ js/src/jsemit.h | 1071 + js/src/jsexn.cpp | 1298 + js/src/jsexn.h | 93 + js/src/jsfriendapi.cpp | 48 + js/src/jsfriendapi.h | 53 + js/src/jsfun.cpp | 3052 + js/src/jsfun.h | 613 + js/src/jsfuninlines.h | 52 + js/src/jsgc.cpp | 2951 + js/src/jsgc.h | 1114 + js/src/jsgcchunk.cpp | 419 + js/src/jsgcchunk.h | 97 + js/src/jsgcinlines.h | 683 + js/src/jsgcstats.cpp | 456 + js/src/jsgcstats.h | 180 + js/src/jshash.cpp | 477 + js/src/jshash.h | 153 + js/src/jshashtable.h | 1124 + js/src/jshotloop.h | 51 + js/src/jsify.pl | 483 + js/src/jsinterp.cpp | 6989 ++ js/src/jsinterp.h | 1122 + js/src/jsinterpinlines.h | 850 + js/src/jsinttypes.h | 144 + js/src/jsinvoke.cpp | 42 + js/src/jsiter.cpp | 1465 + js/src/jsiter.h | 248 + js/src/jskeyword.tbl | 115 + js/src/jskwgen.cpp | 460 + js/src/jslibmath.h | 88 + js/src/jslock.cpp | 736 + js/src/jslock.h | 239 + js/src/jslocko.asm | 60 + js/src/jslog2.cpp | 111 + js/src/jslong.h | 167 + js/src/jsmath.cpp | 885 + js/src/jsmath.h | 123 + js/src/jsnativestack.cpp | 230 + js/src/jsnativestack.h | 60 + js/src/jsnum.cpp | 1455 + js/src/jsnum.h | 708 + js/src/jsobj.cpp | 7040 ++ js/src/jsobj.h | 1952 + js/src/jsobjinlines.h | 1222 + js/src/json.cpp | 1270 + js/src/json.h | 137 + js/src/jsopcode.cpp | 5548 ++ js/src/jsopcode.h | 512 + js/src/jsopcode.tbl | 618 + js/src/jsopcodeinlines.h | 57 + js/src/jsoplengen.cpp | 121 + js/src/jsotypes.h | 198 + js/src/jsparse.cpp | 9864 +++ js/src/jsparse.h | 1254 + js/src/jsprf.cpp | 1262 + js/src/jsprf.h | 150 + js/src/jsprobes.cpp | 188 + js/src/jsprobes.h | 257 + js/src/jspropertycache.cpp | 509 + js/src/jspropertycache.h | 277 + js/src/jspropertycacheinlines.h | 155 + js/src/jspropertytree.cpp | 676 + js/src/jspropertytree.h | 141 + js/src/jsproto.tbl | 107 + js/src/jsproxy.cpp | 1454 + js/src/jsproxy.h | 225 + js/src/jsprvtd.h | 345 + js/src/jspubtd.h | 619 + js/src/jsreflect.cpp | 3326 + js/src/jsreflect.h | 139 + js/src/jsregexp.cpp | 934 + js/src/jsregexp.h | 401 + js/src/jsregexpinlines.h | 737 + js/src/jsreops.tbl | 145 + js/src/jsscan.cpp | 1826 + js/src/jsscan.h | 603 + js/src/jsscope.cpp | 1506 + js/src/jsscope.h | 924 + js/src/jsscopeinlines.h | 297 + js/src/jsscript.cpp | 2018 + js/src/jsscript.h | 750 + js/src/jsscriptinlines.h | 131 + js/src/jsshell.msg | 58 + js/src/jsstack.js | 375 + js/src/jsstaticcheck.h | 125 + js/src/jsstdint.h | 122 + js/src/jsstr.cpp | 5967 ++ js/src/jsstr.h | 1077 + js/src/jsstrinlines.h | 423 + js/src/jstl.h | 495 + js/src/jstracer.cpp | 17588 +++++ js/src/jstracer.h | 1895 + js/src/jstypedarray.cpp | 1754 + js/src/jstypedarray.h | 237 + js/src/jstypes.h | 507 + js/src/jsutil.cpp | 379 + js/src/jsutil.h | 469 + js/src/jsval.h | 831 + js/src/jsvalue.h | 1239 + js/src/jsvector.h | 759 + js/src/jsversion.h | 221 + js/src/jswin.h | 45 + js/src/jswince.asm | 82 + js/src/jswrapper.cpp | 701 + js/src/jswrapper.h | 193 + js/src/jsxdrapi.cpp | 797 + js/src/jsxdrapi.h | 219 + js/src/jsxml.cpp | 7753 +++ js/src/jsxml.h | 374 + js/src/lirasm/LInsClasses.tbl | 135 + js/src/lirasm/Makefile.in | 79 + js/src/lirasm/lirasm.cpp | 2466 + js/src/lirasm/testlirc.sh | 148 + js/src/lirasm/tests/32-bit/many_params.in | 31 + js/src/lirasm/tests/32-bit/many_params.out | 1 + js/src/lirasm/tests/64-bit/dasq.in | 8 + js/src/lirasm/tests/64-bit/dasq.out | 1 + js/src/lirasm/tests/64-bit/qasd.in | 7 + js/src/lirasm/tests/64-bit/qasd.out | 1 + js/src/lirasm/tests/64-bit/shq.in | 32 + js/src/lirasm/tests/64-bit/shq.out | 1 + js/src/lirasm/tests/add.in | 4 + js/src/lirasm/tests/add.out | 1 + js/src/lirasm/tests/addd.in | 31 + js/src/lirasm/tests/addd.out | 1 + js/src/lirasm/tests/addjovi.in | 14 + js/src/lirasm/tests/addjovi.out | 1 + js/src/lirasm/tests/addjovi_ovf.in | 14 + js/src/lirasm/tests/addjovi_ovf.out | 1 + js/src/lirasm/tests/addsub.in | 5 + js/src/lirasm/tests/addsub.out | 1 + js/src/lirasm/tests/bigendian/fuzz-527178.in | 5 + js/src/lirasm/tests/bigendian/fuzz-527178.out | 1 + js/src/lirasm/tests/bigendian/ldc2i.in | 26 + js/src/lirasm/tests/bigendian/ldc2i.out | 1 + js/src/lirasm/tests/bigendian/lds2i.in | 17 + js/src/lirasm/tests/bigendian/lds2i.out | 1 + js/src/lirasm/tests/bigendian/lduc2ui.in | 26 + js/src/lirasm/tests/bigendian/lduc2ui.out | 1 + js/src/lirasm/tests/bigendian/ldus2ui.in | 17 + js/src/lirasm/tests/bigendian/ldus2ui.out | 1 + js/src/lirasm/tests/bug596923.in | 17 + js/src/lirasm/tests/bug596923.out | 1 + js/src/lirasm/tests/call1.in | 12 + js/src/lirasm/tests/call1.out | 2 + js/src/lirasm/tests/call2.in | 5 + js/src/lirasm/tests/call2.out | 1 + js/src/lirasm/tests/calld1.in | 11 + js/src/lirasm/tests/calld1.out | 1 + js/src/lirasm/tests/callid1.in | 10 + js/src/lirasm/tests/callid1.out | 1 + js/src/lirasm/tests/callid2.in | 8 + js/src/lirasm/tests/callid2.out | 1 + js/src/lirasm/tests/callid3.in | 10 + js/src/lirasm/tests/callid3.out | 1 + js/src/lirasm/tests/callv.in | 5 + js/src/lirasm/tests/callv.out | 2 + js/src/lirasm/tests/cmov.in | 68 + js/src/lirasm/tests/cmov.out | 1 + js/src/lirasm/tests/cond_eqd.in | 54 + js/src/lirasm/tests/cond_eqd.out | 1 + js/src/lirasm/tests/cond_eqi.in | 53 + js/src/lirasm/tests/cond_eqi.out | 1 + js/src/lirasm/tests/cond_ged.in | 53 + js/src/lirasm/tests/cond_ged.out | 1 + js/src/lirasm/tests/cond_gei.in | 53 + js/src/lirasm/tests/cond_gei.out | 1 + js/src/lirasm/tests/cond_geui.in | 53 + js/src/lirasm/tests/cond_geui.out | 1 + js/src/lirasm/tests/cond_gtd.in | 53 + js/src/lirasm/tests/cond_gtd.out | 1 + js/src/lirasm/tests/cond_gti.in | 53 + js/src/lirasm/tests/cond_gti.out | 1 + js/src/lirasm/tests/cond_gtui.in | 53 + js/src/lirasm/tests/cond_gtui.out | 1 + js/src/lirasm/tests/cond_led.in | 53 + js/src/lirasm/tests/cond_led.out | 1 + js/src/lirasm/tests/cond_lei.in | 53 + js/src/lirasm/tests/cond_lei.out | 1 + js/src/lirasm/tests/cond_leui.in | 53 + js/src/lirasm/tests/cond_leui.out | 1 + js/src/lirasm/tests/cond_ltd.in | 53 + js/src/lirasm/tests/cond_ltd.out | 1 + js/src/lirasm/tests/cond_lti.in | 53 + js/src/lirasm/tests/cond_lti.out | 1 + js/src/lirasm/tests/cond_ltui.in | 53 + js/src/lirasm/tests/cond_ltui.out | 1 + js/src/lirasm/tests/divd.in | 31 + js/src/lirasm/tests/divd.out | 1 + js/src/lirasm/tests/float_double.in | 20 + js/src/lirasm/tests/float_double.out | 1 + js/src/lirasm/tests/floatingpoint.in | 4 + js/src/lirasm/tests/floatingpoint.out | 1 + js/src/lirasm/tests/fneg.in | 3 + js/src/lirasm/tests/fneg.out | 1 + js/src/lirasm/tests/fpu1-598151.in | 12 + js/src/lirasm/tests/fpu1-598151.out | 1 + js/src/lirasm/tests/fpu2-598151.in | 21 + js/src/lirasm/tests/fpu2-598151.out | 1 + js/src/lirasm/tests/fuzz-527178.in | 5 + js/src/lirasm/tests/fuzz-527178.out | 1 + js/src/lirasm/tests/hardfloat/d2i.in | 26 + js/src/lirasm/tests/hardfloat/d2i.out | 1 + js/src/lirasm/tests/hardfloat/f2i.in | 6 + js/src/lirasm/tests/hardfloat/f2i.out | 1 + js/src/lirasm/tests/hardfloat/i2d.in | 24 + js/src/lirasm/tests/hardfloat/i2d.out | 1 + js/src/lirasm/tests/hardfloat/ui2d.in | 5 + js/src/lirasm/tests/hardfloat/ui2d.out | 1 + js/src/lirasm/tests/ldc2i.in | 26 + js/src/lirasm/tests/ldc2i.out | 1 + js/src/lirasm/tests/lds2i.in | 17 + js/src/lirasm/tests/lds2i.out | 1 + js/src/lirasm/tests/lduc2ui.in | 26 + js/src/lirasm/tests/lduc2ui.out | 1 + js/src/lirasm/tests/ldus2ui.in | 17 + js/src/lirasm/tests/ldus2ui.out | 1 + js/src/lirasm/tests/littleendian/fuzz-527178.in | 5 + js/src/lirasm/tests/littleendian/fuzz-527178.out | 1 + js/src/lirasm/tests/littleendian/ldc2i.in | 26 + js/src/lirasm/tests/littleendian/ldc2i.out | 1 + js/src/lirasm/tests/littleendian/lds2i.in | 17 + js/src/lirasm/tests/littleendian/lds2i.out | 1 + js/src/lirasm/tests/littleendian/lduc2ui.in | 26 + js/src/lirasm/tests/littleendian/lduc2ui.out | 1 + js/src/lirasm/tests/littleendian/ldus2ui.in | 17 + js/src/lirasm/tests/littleendian/ldus2ui.out | 1 + js/src/lirasm/tests/loadstore.in | 9 + js/src/lirasm/tests/loadstore.out | 1 + js/src/lirasm/tests/mul_xxx.in | 6 + js/src/lirasm/tests/mul_xxx.out | 1 + js/src/lirasm/tests/mul_xxy.in | 7 + js/src/lirasm/tests/mul_xxy.out | 1 + js/src/lirasm/tests/mul_xyy.in | 10 + js/src/lirasm/tests/mul_xyy.out | 1 + js/src/lirasm/tests/mul_xyz.in | 13 + js/src/lirasm/tests/mul_xyz.out | 1 + js/src/lirasm/tests/muld.in | 31 + js/src/lirasm/tests/muld.out | 1 + js/src/lirasm/tests/muljovi.in | 15 + js/src/lirasm/tests/muljovi.out | 1 + js/src/lirasm/tests/muljovi_ovf.in | 14 + js/src/lirasm/tests/muljovi_ovf.out | 1 + js/src/lirasm/tests/muljovi_xxx.in | 11 + js/src/lirasm/tests/muljovi_xxx.out | 1 + js/src/lirasm/tests/muljovi_xxy.in | 12 + js/src/lirasm/tests/muljovi_xxy.out | 1 + js/src/lirasm/tests/muljovi_xyy.in | 15 + js/src/lirasm/tests/muljovi_xyy.out | 1 + js/src/lirasm/tests/muljovi_xyz.in | 18 + js/src/lirasm/tests/muljovi_xyz.out | 1 + js/src/lirasm/tests/mulov_xxx.in | 14 + js/src/lirasm/tests/mulov_xxx.out | 1 + js/src/lirasm/tests/mulov_xxy.in | 14 + js/src/lirasm/tests/mulov_xxy.out | 1 + js/src/lirasm/tests/mulov_xyy.in | 11 + js/src/lirasm/tests/mulov_xyy.out | 1 + js/src/lirasm/tests/mulov_xyz.in | 13 + js/src/lirasm/tests/mulov_xyz.out | 1 + js/src/lirasm/tests/multfrag1.in | 27 + js/src/lirasm/tests/multfrag1.out | 2 + js/src/lirasm/tests/multfrag2.in | 14 + js/src/lirasm/tests/multfrag2.out | 1 + js/src/lirasm/tests/multfrag3.in | 16 + js/src/lirasm/tests/multfrag3.out | 1 + js/src/lirasm/tests/negnot.in | 4 + js/src/lirasm/tests/negnot.out | 1 + js/src/lirasm/tests/random.out | 1 + js/src/lirasm/tests/shi.in | 32 + js/src/lirasm/tests/shi.out | 1 + js/src/lirasm/tests/softfloat/dhi2i.in | 4 + js/src/lirasm/tests/softfloat/dhi2i.out | 1 + js/src/lirasm/tests/softfloat/dlo2i.in | 4 + js/src/lirasm/tests/softfloat/dlo2i.out | 1 + js/src/lirasm/tests/softfloat/ii2d.in | 20 + js/src/lirasm/tests/softfloat/ii2d.out | 1 + js/src/lirasm/tests/std2f.in | 7 + js/src/lirasm/tests/std2f.out | 1 + js/src/lirasm/tests/subd.in | 31 + js/src/lirasm/tests/subd.out | 1 + js/src/lirasm/tests/subjovi.in | 15 + js/src/lirasm/tests/subjovi.out | 1 + js/src/lirasm/tests/subjovi_ovf.in | 14 + js/src/lirasm/tests/subjovi_ovf.out | 1 + js/src/lock_sparcv8plus.il | 84 + js/src/lock_sparcv9.il | 84 + js/src/methodjit/BaseAssembler.h | 777 + js/src/methodjit/BaseCompiler.h | 290 + js/src/methodjit/CodeGenIncludes.h | 66 + js/src/methodjit/Compiler.cpp | 5043 ++ js/src/methodjit/Compiler.h | 567 + js/src/methodjit/FastArithmetic.cpp | 1617 + js/src/methodjit/FastOps.cpp | 1856 + js/src/methodjit/FrameEntry.h | 263 + js/src/methodjit/FrameState-inl.h | 1164 + js/src/methodjit/FrameState.cpp | 1695 + js/src/methodjit/FrameState.h | 913 + js/src/methodjit/ICChecker.h | 87 + js/src/methodjit/ICLabels.h | 508 + js/src/methodjit/ICRepatcher.h | 164 + js/src/methodjit/ImmutableSync.cpp | 281 + js/src/methodjit/ImmutableSync.h | 130 + js/src/methodjit/InlineFrameAssembler.h | 157 + js/src/methodjit/InvokeHelpers.cpp | 1130 + js/src/methodjit/Logging.cpp | 143 + js/src/methodjit/Logging.h | 112 + js/src/methodjit/MachineRegs.h | 454 + js/src/methodjit/MethodJIT-inl.h | 105 + js/src/methodjit/MethodJIT.cpp | 1088 + js/src/methodjit/MethodJIT.h | 496 + js/src/methodjit/MonoIC.cpp | 1338 + js/src/methodjit/MonoIC.h | 281 + js/src/methodjit/NunboxAssembler.h | 463 + js/src/methodjit/PolyIC.cpp | 2749 + js/src/methodjit/PolyIC.h | 561 + js/src/methodjit/PunboxAssembler.h | 399 + js/src/methodjit/RematInfo.h | 287 + js/src/methodjit/Retcon.cpp | 225 + js/src/methodjit/Retcon.h | 111 + js/src/methodjit/StubCalls-inl.h | 105 + js/src/methodjit/StubCalls.cpp | 2708 + js/src/methodjit/StubCalls.h | 243 + js/src/methodjit/StubCompiler.cpp | 224 + js/src/methodjit/StubCompiler.h | 148 + js/src/methodjit/TrampolineCompiler.cpp | 157 + js/src/methodjit/TrampolineCompiler.h | 81 + js/src/methodjit/TrampolineMasmX64.asm | 175 + js/src/methodjit/TrampolineSUNWX64.s | 145 + js/src/methodjit/TrampolineSUNWX86.s | 135 + js/src/methodjit/TypedArrayIC.h | 546 + js/src/metrics/gc/README.txt | 8 + js/src/metrics/gc/gc-test.py | 177 + js/src/metrics/gc/tests/clock.js | 35 + js/src/metrics/gc/tests/dslots.js | 26 + js/src/metrics/gc/tests/loops.js | 55 + js/src/metrics/gc/tests/objGraph.js | 37 + js/src/metrics/jint/sunspider/3d-cube.js | 369 + js/src/metrics/jint/sunspider/3d-morph.js | 64 + js/src/metrics/jint/sunspider/3d-raytrace.js | 466 + .../metrics/jint/sunspider/access-binary-trees.js | 56 + js/src/metrics/jint/sunspider/access-fannkuch.js | 86 + js/src/metrics/jint/sunspider/access-nbody.js | 185 + js/src/metrics/jint/sunspider/access-nsieve.js | 48 + .../jint/sunspider/bitops-3bit-bits-in-byte.js | 37 + .../metrics/jint/sunspider/bitops-bits-in-byte.js | 28 + .../metrics/jint/sunspider/bitops-bitwise-and.js | 30 + .../metrics/jint/sunspider/bitops-nsieve-bits.js | 42 + .../jint/sunspider/controlflow-recursive.js | 27 + js/src/metrics/jint/sunspider/crypto-aes.js | 494 + js/src/metrics/jint/sunspider/crypto-md5.js | 302 + js/src/metrics/jint/sunspider/crypto-sha1.js | 242 + js/src/metrics/jint/sunspider/date-format-tofte.js | 305 + js/src/metrics/jint/sunspider/date-format-xparb.js | 427 + js/src/metrics/jint/sunspider/math-cordic.js | 99 + js/src/metrics/jint/sunspider/math-partial-sums.js | 37 + .../metrics/jint/sunspider/math-spectral-norm.js | 67 + js/src/metrics/jint/sunspider/regexp-dna.js | 1716 + js/src/metrics/jint/sunspider/string-base64.js | 143 + js/src/metrics/jint/sunspider/string-fasta.js | 95 + js/src/metrics/jint/sunspider/string-tagcloud.js | 277 + .../metrics/jint/sunspider/string-unpack-code.js | 152 + .../jint/sunspider/string-validate-input.js | 99 + js/src/metrics/jint/treesearch.py | 408 + js/src/metrics/jint/v8/base.js | 265 + js/src/metrics/jint/v8/crypto.js | 2135 + js/src/metrics/jint/v8/deltablue.js | 1196 + js/src/metrics/jint/v8/earley-boyer.js | 4682 ++ js/src/metrics/jint/v8/raytrace.js | 3418 + js/src/metrics/jint/v8/richards.js | 539 + js/src/metrics/jint/v8/run-earley-boyer.js | 44 + js/src/metrics/jint/v8/run-raytrace.js | 44 + js/src/metrics/jint/v8/run-richards.js | 44 + js/src/metrics/jint/v8/run.js | 49 + js/src/mozjs185.pc.in | 10 + js/src/nanojit-import-filemap | 13 + js/src/nanojit-import-rev | 1 + js/src/nanojit/Allocator.cpp | 103 + js/src/nanojit/Allocator.h | 140 + js/src/nanojit/Assembler.cpp | 2632 + js/src/nanojit/Assembler.h | 553 + js/src/nanojit/CodeAlloc.cpp | 570 + js/src/nanojit/CodeAlloc.h | 237 + js/src/nanojit/Containers.cpp | 95 + js/src/nanojit/Containers.h | 465 + js/src/nanojit/Fragmento.cpp | 80 + js/src/nanojit/Fragmento.h | 135 + js/src/nanojit/LIR.cpp | 3857 ++ js/src/nanojit/LIR.h | 2443 + js/src/nanojit/LIRopcode.tbl | 367 + js/src/nanojit/Native.h | 193 + js/src/nanojit/NativeARM.cpp | 2928 + js/src/nanojit/NativeARM.h | 1117 + js/src/nanojit/NativeCommon.h | 122 + js/src/nanojit/NativeMIPS.cpp | 2073 + js/src/nanojit/NativeMIPS.h | 715 + js/src/nanojit/NativePPC.cpp | 1459 + js/src/nanojit/NativePPC.h | 604 + js/src/nanojit/NativeSH4-auto-generated.h | 1726 + js/src/nanojit/NativeSH4.cpp | 1586 + js/src/nanojit/NativeSH4.h | 463 + js/src/nanojit/NativeSparc.cpp | 1646 + js/src/nanojit/NativeSparc.h | 456 + js/src/nanojit/NativeX64.cpp | 2214 + js/src/nanojit/NativeX64.h | 630 + js/src/nanojit/Nativei386.cpp | 2933 + js/src/nanojit/Nativei386.h | 472 + js/src/nanojit/RegAlloc.cpp | 57 + js/src/nanojit/RegAlloc.h | 211 + js/src/nanojit/VMPI.cpp | 153 + js/src/nanojit/VMPI.h | 139 + js/src/nanojit/avmplus.cpp | 184 + js/src/nanojit/avmplus.h | 347 + js/src/nanojit/manifest.mk | 88 + js/src/nanojit/nanojit.h | 382 + js/src/nanojit/njconfig.cpp | 117 + js/src/nanojit/njconfig.h | 107 + js/src/nanojit/njcpudetect.h | 115 + js/src/perf/jsperf.cpp | 295 + js/src/perf/jsperf.h | 163 + js/src/perf/pm_linux.cpp | 343 + js/src/perf/pm_stub.cpp | 96 + js/src/perfect.js | 39 + js/src/plify_jsdhash.sed | 39 + js/src/prmjtime.cpp | 872 + js/src/prmjtime.h | 227 + js/src/ref-config/AIX4.1.mk | 65 + js/src/ref-config/AIX4.2.mk | 64 + js/src/ref-config/AIX4.3.mk | 65 + js/src/ref-config/Darwin.mk | 85 + js/src/ref-config/Darwin1.3.mk | 81 + js/src/ref-config/Darwin1.4.mk | 41 + js/src/ref-config/Darwin5.2.mk | 81 + js/src/ref-config/Darwin5.3.mk | 81 + js/src/ref-config/Darwin64.mk | 72 + js/src/ref-config/HP-UXB.10.10.mk | 77 + js/src/ref-config/HP-UXB.10.20.mk | 77 + js/src/ref-config/HP-UXB.11.00.mk | 80 + js/src/ref-config/HP-UXB.11.31.mk | 65 + js/src/ref-config/IRIX.mk | 87 + js/src/ref-config/IRIX5.3.mk | 44 + js/src/ref-config/IRIX6.1.mk | 44 + js/src/ref-config/IRIX6.2.mk | 44 + js/src/ref-config/IRIX6.3.mk | 44 + js/src/ref-config/IRIX6.5.mk | 44 + js/src/ref-config/Linux_All.mk | 105 + js/src/ref-config/Mac_OS10.0.mk | 82 + js/src/ref-config/OSF1V4.0.mk | 72 + js/src/ref-config/OSF1V5.0.mk | 69 + js/src/ref-config/SunOS4.1.4.mk | 101 + js/src/ref-config/SunOS5.10.mk | 50 + js/src/ref-config/SunOS5.3.mk | 91 + js/src/ref-config/SunOS5.4.mk | 92 + js/src/ref-config/SunOS5.5.1.mk | 44 + js/src/ref-config/SunOS5.5.mk | 87 + js/src/ref-config/SunOS5.6.mk | 89 + js/src/ref-config/SunOS5.7.mk | 44 + js/src/ref-config/SunOS5.8.mk | 44 + js/src/ref-config/SunOS5.9.mk | 44 + js/src/ref-config/WINNT4.0.mk | 118 + js/src/ref-config/WINNT5.0.mk | 118 + js/src/ref-config/WINNT5.1.mk | 118 + js/src/ref-config/WINNT5.2.mk | 118 + js/src/ref-config/WINNT6.0.mk | 118 + js/src/ref-config/dgux.mk | 64 + js/src/resource.h | 15 + js/src/rules.mk | 206 + js/src/sharkctl.cpp | 238 + js/src/sharkctl.h | 53 + js/src/shell/Makefile.in | 81 + js/src/shell/js.cpp | 5815 ++ js/src/shell/jsworkers.cpp | 1280 + js/src/shell/jsworkers.h | 93 + js/src/t/3d-cube.js | 337 + js/src/t/3d-morph.js | 54 + js/src/t/3d-raytrace.js | 441 + js/src/t/access-binary-trees.js | 50 + js/src/t/access-fannkuch.js | 66 + js/src/t/access-nbody.js | 169 + js/src/t/access-nsieve.js | 38 + js/src/t/bitops-3bit-bits-in-byte.js | 32 + js/src/t/bitops-bits-in-byte.js | 21 + js/src/t/bitops-bitwise-and.js | 28 + js/src/t/bitops-nsieve-bits.js | 32 + js/src/t/controlflow-recursive.js | 25 + js/src/t/crypto-aes.js | 422 + js/src/t/crypto-md5.js | 286 + js/src/t/crypto-sha1.js | 224 + js/src/t/date-format-tofte.js | 299 + js/src/t/date-format-xparb.js | 417 + js/src/t/math-cordic.js | 95 + js/src/t/math-partial-sums.js | 33 + js/src/t/math-spectral-norm.js | 51 + js/src/t/regexp-dna.js | 1712 + js/src/t/string-base64.js | 135 + js/src/t/string-fasta.js | 85 + js/src/t/string-tagcloud.js | 265 + js/src/t/string-unpack-code.js | 68 + js/src/t/string-validate-input.js | 89 + js/src/tests/Makefile.in | 80 + js/src/tests/Patterns.pm | 257 + js/src/tests/SisyphusMakefile | 58 + js/src/tests/bisect.sh | 488 + js/src/tests/browser.js | 968 + js/src/tests/changes.sh | 122 + js/src/tests/compare_bench.py | 79 + js/src/tests/config.mk | 113 + js/src/tests/config.sh | 138 + js/src/tests/detect-universe.sh | 126 + js/src/tests/dikdik-n.tests | 3 + js/src/tests/e4x/Expressions/11.1.1.js | 84 + js/src/tests/e4x/Expressions/11.1.2.js | 85 + js/src/tests/e4x/Expressions/11.1.3.js | 55 + js/src/tests/e4x/Expressions/11.1.4-01.js | 60 + js/src/tests/e4x/Expressions/11.1.4-02.js | 57 + js/src/tests/e4x/Expressions/11.1.4-03.js | 59 + js/src/tests/e4x/Expressions/11.1.4-04.js | 55 + js/src/tests/e4x/Expressions/11.1.4-05.js | 56 + js/src/tests/e4x/Expressions/11.1.4-06.js | 60 + js/src/tests/e4x/Expressions/11.1.4-07.js | 77 + js/src/tests/e4x/Expressions/11.1.4-08.js | 157 + js/src/tests/e4x/Expressions/11.1.4.js | 139 + js/src/tests/e4x/Expressions/11.1.5.js | 61 + js/src/tests/e4x/Expressions/11.2.1.js | 173 + js/src/tests/e4x/Expressions/11.2.2.js | 105 + js/src/tests/e4x/Expressions/11.2.3.js | 60 + js/src/tests/e4x/Expressions/11.2.4.js | 116 + js/src/tests/e4x/Expressions/11.3.1.js | 271 + js/src/tests/e4x/Expressions/11.3.2.js | 51 + js/src/tests/e4x/Expressions/11.4.1.js | 138 + js/src/tests/e4x/Expressions/11.5.1.js | 100 + js/src/tests/e4x/Expressions/11.6.1.js | 428 + js/src/tests/e4x/Expressions/11.6.2.js | 325 + js/src/tests/e4x/Expressions/11.6.3.js | 118 + js/src/tests/e4x/Expressions/browser.js | 0 js/src/tests/e4x/Expressions/jstests.list | 30 + js/src/tests/e4x/Expressions/regress-301545.js | 54 + js/src/tests/e4x/Expressions/regress-302531.js | 32 + js/src/tests/e4x/Expressions/regress-340024.js | 60 + js/src/tests/e4x/Expressions/regress-366123.js | 66 + js/src/tests/e4x/Expressions/regress-496113.js | 64 + js/src/tests/e4x/Expressions/shell.js | 0 js/src/tests/e4x/GC/browser.js | 0 js/src/tests/e4x/GC/jstests.list | 11 + js/src/tests/e4x/GC/regress-280844-1.js | 58 + js/src/tests/e4x/GC/regress-280844-2.js | 70 + js/src/tests/e4x/GC/regress-292455.js | 78 + js/src/tests/e4x/GC/regress-313952-01.js | 67 + js/src/tests/e4x/GC/regress-313952-02.js | 76 + js/src/tests/e4x/GC/regress-324117.js | 97 + js/src/tests/e4x/GC/regress-324278.js | 85 + js/src/tests/e4x/GC/regress-339785.js | 91 + js/src/tests/e4x/GC/regress-357063-01.js | 72 + js/src/tests/e4x/GC/regress-357063-02.js | 68 + js/src/tests/e4x/GC/shell.js | 0 js/src/tests/e4x/Global/13.1.2.1.js | 558 + js/src/tests/e4x/Global/browser.js | 0 js/src/tests/e4x/Global/jstests.list | 2 + js/src/tests/e4x/Global/shell.js | 0 js/src/tests/e4x/Namespace/13.2.1.js | 67 + js/src/tests/e4x/Namespace/13.2.2.js | 85 + js/src/tests/e4x/Namespace/13.2.5.js | 66 + js/src/tests/e4x/Namespace/browser.js | 0 js/src/tests/e4x/Namespace/jstests.list | 9 + js/src/tests/e4x/Namespace/regress-283972.js | 64 + js/src/tests/e4x/Namespace/regress-292863.js | 61 + js/src/tests/e4x/Namespace/regress-350442.js | 73 + js/src/tests/e4x/Namespace/regress-444608-02.js | 54 + js/src/tests/e4x/Namespace/regress-444608.js | 54 + js/src/tests/e4x/Namespace/shell.js | 0 js/src/tests/e4x/QName/13.3.1.js | 74 + js/src/tests/e4x/QName/13.3.2.js | 86 + js/src/tests/e4x/QName/13.3.5.js | 66 + js/src/tests/e4x/QName/browser.js | 0 js/src/tests/e4x/QName/jstests.list | 9 + js/src/tests/e4x/QName/regress-373595-01.js | 52 + js/src/tests/e4x/QName/regress-373595-02.js | 54 + js/src/tests/e4x/QName/regress-373595-03.js | 54 + js/src/tests/e4x/QName/regress-444608.js | 55 + js/src/tests/e4x/QName/regress-619529.js | 17 + js/src/tests/e4x/QName/shell.js | 0 js/src/tests/e4x/Regress/browser.js | 0 js/src/tests/e4x/Regress/jstests.list | 96 + js/src/tests/e4x/Regress/regress-257679.js | 51 + js/src/tests/e4x/Regress/regress-263934.js | 65 + js/src/tests/e4x/Regress/regress-263935.js | 66 + js/src/tests/e4x/Regress/regress-263936.js | 64 + js/src/tests/e4x/Regress/regress-264369.js | 52 + js/src/tests/e4x/Regress/regress-271545.js | 73 + js/src/tests/e4x/Regress/regress-277650.js | 63 + js/src/tests/e4x/Regress/regress-277664.js | 63 + js/src/tests/e4x/Regress/regress-277683.js | 64 + js/src/tests/e4x/Regress/regress-277779.js | 59 + js/src/tests/e4x/Regress/regress-277935.js | 67 + js/src/tests/e4x/Regress/regress-278112.js | 54 + js/src/tests/e4x/Regress/regress-283349.js | 56 + js/src/tests/e4x/Regress/regress-290056.js | 60 + js/src/tests/e4x/Regress/regress-290499.js | 51 + js/src/tests/e4x/Regress/regress-301553.js | 59 + js/src/tests/e4x/Regress/regress-301573.js | 56 + js/src/tests/e4x/Regress/regress-301596.js | 59 + js/src/tests/e4x/Regress/regress-301692.js | 82 + js/src/tests/e4x/Regress/regress-308111.js | 956 + js/src/tests/e4x/Regress/regress-309897.js | 67 + js/src/tests/e4x/Regress/regress-311580.js | 60 + js/src/tests/e4x/Regress/regress-313799.js | 52 + js/src/tests/e4x/Regress/regress-318922.js | 107 + js/src/tests/e4x/Regress/regress-319872.js | 76 + js/src/tests/e4x/Regress/regress-321547.js | 90 + js/src/tests/e4x/Regress/regress-322499.js | 71 + js/src/tests/e4x/Regress/regress-323338-1.js | 74 + js/src/tests/e4x/Regress/regress-323338-2.js | 51 + js/src/tests/e4x/Regress/regress-325425.js | 59 + js/src/tests/e4x/Regress/regress-327564.js | 73 + js/src/tests/e4x/Regress/regress-327691-01.js | 58 + js/src/tests/e4x/Regress/regress-327691-02.js | 58 + js/src/tests/e4x/Regress/regress-327697.js | 79 + js/src/tests/e4x/Regress/regress-328249.js | 64 + js/src/tests/e4x/Regress/regress-329257.js | 70 + js/src/tests/e4x/Regress/regress-331558.js | 53 + js/src/tests/e4x/Regress/regress-331664.js | 52 + js/src/tests/e4x/Regress/regress-344455.js | 59 + js/src/tests/e4x/Regress/regress-347155.js | 68 + js/src/tests/e4x/Regress/regress-350206-1.js | 70 + js/src/tests/e4x/Regress/regress-350206.js | 56 + js/src/tests/e4x/Regress/regress-350238.js | 64 + js/src/tests/e4x/Regress/regress-350629.js | 128 + js/src/tests/e4x/Regress/regress-352097.js | 91 + js/src/tests/e4x/Regress/regress-352103.js | 75 + js/src/tests/e4x/Regress/regress-352223.js | 70 + js/src/tests/e4x/Regress/regress-354145-01.js | 66 + js/src/tests/e4x/Regress/regress-354145-02.js | 66 + js/src/tests/e4x/Regress/regress-354145-03.js | 67 + js/src/tests/e4x/Regress/regress-354145-04.js | 65 + js/src/tests/e4x/Regress/regress-354145-05.js | 65 + js/src/tests/e4x/Regress/regress-354145-07.js | 58 + js/src/tests/e4x/Regress/regress-354998.js | 93 + js/src/tests/e4x/Regress/regress-355474-02.js | 57 + js/src/tests/e4x/Regress/regress-355478.js | 61 + js/src/tests/e4x/Regress/regress-355569.js | 162 + js/src/tests/e4x/Regress/regress-356238-01.js | 56 + js/src/tests/e4x/Regress/regress-356238-02.js | 62 + js/src/tests/e4x/Regress/regress-356238-03.js | 63 + js/src/tests/e4x/Regress/regress-361451.js | 56 + js/src/tests/e4x/Regress/regress-364017.js | 57 + js/src/tests/e4x/Regress/regress-369032.js | 62 + js/src/tests/e4x/Regress/regress-369536.js | 47 + js/src/tests/e4x/Regress/regress-369740.js | 81 + js/src/tests/e4x/Regress/regress-370016.js | 51 + js/src/tests/e4x/Regress/regress-370048-01.js | 58 + js/src/tests/e4x/Regress/regress-370048-02.js | 56 + js/src/tests/e4x/Regress/regress-370372.js | 72 + js/src/tests/e4x/Regress/regress-371369.js | 62 + js/src/tests/e4x/Regress/regress-372563.js | 51 + js/src/tests/e4x/Regress/regress-372564.js | 51 + js/src/tests/e4x/Regress/regress-373082.js | 109 + js/src/tests/e4x/Regress/regress-374106.js | 51 + js/src/tests/e4x/Regress/regress-374112.js | 51 + js/src/tests/e4x/Regress/regress-374116.js | 51 + js/src/tests/e4x/Regress/regress-374160.js | 51 + js/src/tests/e4x/Regress/regress-375406.js | 52 + js/src/tests/e4x/Regress/regress-378492.js | 59 + js/src/tests/e4x/Regress/regress-380833.js | 54 + js/src/tests/e4x/Regress/regress-383255.js | 59 + js/src/tests/e4x/Regress/regress-394941.js | 67 + js/src/tests/e4x/Regress/regress-407323.js | 66 + js/src/tests/e4x/Regress/regress-426520.js | 63 + js/src/tests/e4x/Regress/regress-453915.js | 53 + js/src/tests/e4x/Regress/regress-458679-01.js | 63 + js/src/tests/e4x/Regress/regress-458679-02.js | 75 + js/src/tests/e4x/Regress/regress-460180.js | 52 + js/src/tests/e4x/Regress/regress-465063.js | 58 + js/src/tests/e4x/Regress/regress-470619.js | 59 + js/src/tests/e4x/Regress/regress-473709.js | 70 + js/src/tests/e4x/Regress/regress-474319.js | 66 + js/src/tests/e4x/Regress/regress-477053.js | 59 + js/src/tests/e4x/Regress/regress-561031.js | 1830 + js/src/tests/e4x/Regress/regress-587434.js | 12 + js/src/tests/e4x/Regress/shell.js | 0 js/src/tests/e4x/Statements/12.1.js | 133 + js/src/tests/e4x/Statements/12.2.js | 103 + js/src/tests/e4x/Statements/12.3-01.js | 75 + js/src/tests/e4x/Statements/browser.js | 0 js/src/tests/e4x/Statements/jstests.list | 4 + js/src/tests/e4x/Statements/shell.js | 0 js/src/tests/e4x/TypeConversion/10.1.1.js | 140 + js/src/tests/e4x/TypeConversion/10.1.2.js | 147 + js/src/tests/e4x/TypeConversion/10.2.1.js | 158 + js/src/tests/e4x/TypeConversion/10.3.1.js | 59 + js/src/tests/e4x/TypeConversion/10.3.js | 76 + js/src/tests/e4x/TypeConversion/10.4.1.js | 94 + js/src/tests/e4x/TypeConversion/10.4.js | 84 + js/src/tests/e4x/TypeConversion/10.5.1.js | 51 + js/src/tests/e4x/TypeConversion/10.5.js | 51 + js/src/tests/e4x/TypeConversion/10.6.1.js | 51 + js/src/tests/e4x/TypeConversion/10.6.js | 51 + js/src/tests/e4x/TypeConversion/browser.js | 0 js/src/tests/e4x/TypeConversion/jstests.list | 13 + js/src/tests/e4x/TypeConversion/regress-302097.js | 27 + js/src/tests/e4x/TypeConversion/shell.js | 0 js/src/tests/e4x/Types/9.1.1.1.js | 303 + js/src/tests/e4x/Types/9.1.1.10.js | 51 + js/src/tests/e4x/Types/9.1.1.11.js | 51 + js/src/tests/e4x/Types/9.1.1.12.js | 51 + js/src/tests/e4x/Types/9.1.1.13.js | 51 + js/src/tests/e4x/Types/9.1.1.2.js | 81 + js/src/tests/e4x/Types/9.1.1.3.js | 212 + js/src/tests/e4x/Types/9.1.1.4.js | 49 + js/src/tests/e4x/Types/9.1.1.5.js | 52 + js/src/tests/e4x/Types/9.1.1.6.js | 58 + js/src/tests/e4x/Types/9.1.1.7.js | 52 + js/src/tests/e4x/Types/9.1.1.8.js | 53 + js/src/tests/e4x/Types/9.1.1.9.js | 138 + js/src/tests/e4x/Types/9.2.1.1.js | 163 + js/src/tests/e4x/Types/9.2.1.10.js | 52 + js/src/tests/e4x/Types/9.2.1.2.js | 63 + js/src/tests/e4x/Types/9.2.1.3.js | 51 + js/src/tests/e4x/Types/9.2.1.4.js | 52 + js/src/tests/e4x/Types/9.2.1.5.js | 53 + js/src/tests/e4x/Types/9.2.1.6.js | 52 + js/src/tests/e4x/Types/9.2.1.7.js | 52 + js/src/tests/e4x/Types/9.2.1.8.js | 55 + js/src/tests/e4x/Types/9.2.1.9.js | 80 + js/src/tests/e4x/Types/browser.js | 0 js/src/tests/e4x/Types/jstests.list | 24 + js/src/tests/e4x/Types/shell.js | 0 js/src/tests/e4x/XML/13.4.1.js | 112 + js/src/tests/e4x/XML/13.4.2.js | 115 + js/src/tests/e4x/XML/13.4.3.10.js | 51 + js/src/tests/e4x/XML/13.4.3.js | 238 + js/src/tests/e4x/XML/13.4.4.1.js | 51 + js/src/tests/e4x/XML/13.4.4.10.js | 99 + js/src/tests/e4x/XML/13.4.4.11.js | 90 + js/src/tests/e4x/XML/13.4.4.12-1.js | 88 + js/src/tests/e4x/XML/13.4.4.12.js | 68 + js/src/tests/e4x/XML/13.4.4.13.js | 48 + js/src/tests/e4x/XML/13.4.4.14.js | 68 + js/src/tests/e4x/XML/13.4.4.15.js | 78 + js/src/tests/e4x/XML/13.4.4.16.js | 77 + js/src/tests/e4x/XML/13.4.4.17.js | 63 + js/src/tests/e4x/XML/13.4.4.18.js | 83 + js/src/tests/e4x/XML/13.4.4.19.js | 83 + js/src/tests/e4x/XML/13.4.4.2.js | 68 + js/src/tests/e4x/XML/13.4.4.20.js | 64 + js/src/tests/e4x/XML/13.4.4.21.js | 80 + js/src/tests/e4x/XML/13.4.4.22.js | 80 + js/src/tests/e4x/XML/13.4.4.23.js | 92 + js/src/tests/e4x/XML/13.4.4.24.js | 63 + js/src/tests/e4x/XML/13.4.4.25.js | 61 + js/src/tests/e4x/XML/13.4.4.26.js | 137 + js/src/tests/e4x/XML/13.4.4.27.js | 62 + js/src/tests/e4x/XML/13.4.4.28.js | 72 + js/src/tests/e4x/XML/13.4.4.29.js | 92 + js/src/tests/e4x/XML/13.4.4.3-01.js | 71 + js/src/tests/e4x/XML/13.4.4.3-02.js | 61 + js/src/tests/e4x/XML/13.4.4.3.js | 83 + js/src/tests/e4x/XML/13.4.4.30.js | 61 + js/src/tests/e4x/XML/13.4.4.31.js | 77 + js/src/tests/e4x/XML/13.4.4.32-01.js | 55 + js/src/tests/e4x/XML/13.4.4.32.js | 99 + js/src/tests/e4x/XML/13.4.4.33.js | 79 + js/src/tests/e4x/XML/13.4.4.34.js | 76 + js/src/tests/e4x/XML/13.4.4.35.js | 90 + js/src/tests/e4x/XML/13.4.4.36.js | 71 + js/src/tests/e4x/XML/13.4.4.37.js | 66 + js/src/tests/e4x/XML/13.4.4.38.js | 106 + js/src/tests/e4x/XML/13.4.4.39.js | 128 + js/src/tests/e4x/XML/13.4.4.4.js | 75 + js/src/tests/e4x/XML/13.4.4.40.js | 68 + js/src/tests/e4x/XML/13.4.4.5.js | 70 + js/src/tests/e4x/XML/13.4.4.6.js | 67 + js/src/tests/e4x/XML/13.4.4.7.js | 61 + js/src/tests/e4x/XML/13.4.4.8.js | 68 + js/src/tests/e4x/XML/13.4.4.9.js | 62 + js/src/tests/e4x/XML/browser.js | 0 js/src/tests/e4x/XML/jstests.list | 56 + js/src/tests/e4x/XML/regress-291930.js | 53 + js/src/tests/e4x/XML/regress-324422-1.js | 77 + js/src/tests/e4x/XML/regress-324422-2.js | 71 + js/src/tests/e4x/XML/regress-324688.js | 104 + js/src/tests/e4x/XML/regress-336921.js | 62 + js/src/tests/e4x/XML/regress-376773.js | 583 + js/src/tests/e4x/XML/regress-621464.js | 51 + js/src/tests/e4x/XML/shell.js | 0 js/src/tests/e4x/XMLList/13.5.1.js | 96 + js/src/tests/e4x/XMLList/13.5.2.js | 90 + js/src/tests/e4x/XMLList/13.5.4.10.js | 47 + js/src/tests/e4x/XMLList/13.5.4.11.js | 75 + js/src/tests/e4x/XMLList/13.5.4.12.js | 104 + js/src/tests/e4x/XMLList/13.5.4.13.js | 104 + js/src/tests/e4x/XMLList/13.5.4.14.js | 79 + js/src/tests/e4x/XMLList/13.5.4.15.js | 48 + js/src/tests/e4x/XMLList/13.5.4.16.js | 77 + js/src/tests/e4x/XMLList/13.5.4.17.js | 48 + js/src/tests/e4x/XMLList/13.5.4.18.js | 48 + js/src/tests/e4x/XMLList/13.5.4.19.js | 48 + js/src/tests/e4x/XMLList/13.5.4.2.js | 86 + js/src/tests/e4x/XMLList/13.5.4.20.js | 56 + js/src/tests/e4x/XMLList/13.5.4.21.js | 56 + js/src/tests/e4x/XMLList/13.5.4.22.js | 49 + js/src/tests/e4x/XMLList/13.5.4.3.js | 73 + js/src/tests/e4x/XMLList/13.5.4.4.js | 85 + js/src/tests/e4x/XMLList/13.5.4.5.js | 95 + js/src/tests/e4x/XMLList/13.5.4.6.js | 48 + js/src/tests/e4x/XMLList/13.5.4.7.js | 58 + js/src/tests/e4x/XMLList/13.5.4.8.js | 74 + js/src/tests/e4x/XMLList/13.5.4.9.js | 83 + js/src/tests/e4x/XMLList/browser.js | 0 js/src/tests/e4x/XMLList/jstests.list | 25 + js/src/tests/e4x/XMLList/regress-373072.js | 59 + js/src/tests/e4x/XMLList/shell.js | 0 js/src/tests/e4x/browser.js | 82 + js/src/tests/e4x/decompilation/browser.js | 0 .../e4x/decompilation/decompile-xml-escapes.js | 77 + js/src/tests/e4x/decompilation/jstests.list | 20 + js/src/tests/e4x/decompilation/regress-349814.js | 61 + js/src/tests/e4x/decompilation/regress-349815.js | 55 + js/src/tests/e4x/decompilation/regress-349822.js | 62 + js/src/tests/e4x/decompilation/regress-349956.js | 59 + js/src/tests/e4x/decompilation/regress-350226.js | 54 + js/src/tests/e4x/decompilation/regress-350531.js | 60 + js/src/tests/e4x/decompilation/regress-351706.js | 60 + js/src/tests/e4x/decompilation/regress-351988.js | 24 + js/src/tests/e4x/decompilation/regress-352013.js | 136 + js/src/tests/e4x/decompilation/regress-352459.js | 53 + js/src/tests/e4x/decompilation/regress-352649.js | 53 + js/src/tests/e4x/decompilation/regress-352789.js | 65 + js/src/tests/e4x/decompilation/regress-355101.js | 53 + .../tests/e4x/decompilation/regress-355474-01.js | 60 + js/src/tests/e4x/decompilation/regress-373678.js | 54 + js/src/tests/e4x/decompilation/regress-429249.js | 64 + js/src/tests/e4x/decompilation/regress-461233.js | 55 + js/src/tests/e4x/decompilation/regress-463360.js | 23 + js/src/tests/e4x/decompilation/shell.js | 0 js/src/tests/e4x/extensions/browser.js | 0 js/src/tests/e4x/extensions/extensibility.js | 42 + js/src/tests/e4x/extensions/jstests.list | 24 + js/src/tests/e4x/extensions/regress-305335.js | 61 + js/src/tests/e4x/extensions/regress-312196.js | 114 + js/src/tests/e4x/extensions/regress-313080.js | 58 + js/src/tests/e4x/extensions/regress-321547.js | 60 + js/src/tests/e4x/extensions/regress-327534.js | 60 + js/src/tests/e4x/extensions/regress-327897.js | 65 + js/src/tests/e4x/extensions/regress-335051.js | 64 + js/src/tests/e4x/extensions/regress-337226.js | 51 + js/src/tests/e4x/extensions/regress-352846-01.js | 82 + js/src/tests/e4x/extensions/regress-352846-02.js | 87 + js/src/tests/e4x/extensions/regress-352846-03.js | 92 + js/src/tests/e4x/extensions/regress-353165.js | 118 + js/src/tests/e4x/extensions/regress-354145-06.js | 66 + js/src/tests/e4x/extensions/regress-354151-01.js | 62 + js/src/tests/e4x/extensions/regress-354151-02.js | 68 + js/src/tests/e4x/extensions/regress-374025.js | 53 + js/src/tests/e4x/extensions/regress-374163.js | 61 + js/src/tests/e4x/extensions/regress-410192.js | 54 + js/src/tests/e4x/extensions/regress-450871-01.js | 66 + js/src/tests/e4x/extensions/regress-450871-02.js | 67 + js/src/tests/e4x/extensions/regress-462734-01.js | 66 + js/src/tests/e4x/extensions/regress-595207.js | 26 + js/src/tests/e4x/extensions/shell.js | 0 js/src/tests/e4x/jstests.list | 13 + js/src/tests/e4x/shell.js | 114 + js/src/tests/e4x/template.js | 19 + js/src/tests/ecma/Array/15.4-1.js | 132 + js/src/tests/ecma/Array/15.4-2.js | 113 + js/src/tests/ecma/Array/15.4.1.1.js | 110 + js/src/tests/ecma/Array/15.4.1.2.js | 161 + js/src/tests/ecma/Array/15.4.1.3.js | 83 + js/src/tests/ecma/Array/15.4.1.js | 131 + js/src/tests/ecma/Array/15.4.2.1-1.js | 111 + js/src/tests/ecma/Array/15.4.2.1-2.js | 100 + js/src/tests/ecma/Array/15.4.2.1-3.js | 136 + js/src/tests/ecma/Array/15.4.2.2-1.js | 182 + js/src/tests/ecma/Array/15.4.2.2-2.js | 117 + js/src/tests/ecma/Array/15.4.2.3.js | 100 + js/src/tests/ecma/Array/15.4.3.1-2.js | 80 + js/src/tests/ecma/Array/15.4.3.2.js | 61 + js/src/tests/ecma/Array/15.4.4.1.js | 62 + js/src/tests/ecma/Array/15.4.4.2.js | 109 + js/src/tests/ecma/Array/15.4.4.3-1.js | 162 + js/src/tests/ecma/Array/15.4.4.4-1.js | 293 + js/src/tests/ecma/Array/15.4.4.4-2.js | 168 + js/src/tests/ecma/Array/15.4.4.5-1.js | 224 + js/src/tests/ecma/Array/15.4.4.5-2.js | 226 + js/src/tests/ecma/Array/15.4.4.5-3.js | 181 + js/src/tests/ecma/Array/15.4.4.js | 73 + js/src/tests/ecma/Array/15.4.5.1-1.js | 169 + js/src/tests/ecma/Array/15.4.5.1-2.js | 151 + js/src/tests/ecma/Array/15.4.5.2-1.js | 85 + js/src/tests/ecma/Array/15.4.5.2-2.js | 126 + .../ecma/Array/array-length-set-on-nonarray.js | 26 + js/src/tests/ecma/Array/browser.js | 0 js/src/tests/ecma/Array/jstests.list | 29 + js/src/tests/ecma/Array/shell.js | 0 js/src/tests/ecma/Boolean/15.6.1.js | 95 + js/src/tests/ecma/Boolean/15.6.2.js | 160 + js/src/tests/ecma/Boolean/15.6.3.1-1.js | 71 + js/src/tests/ecma/Boolean/15.6.3.1-2.js | 70 + js/src/tests/ecma/Boolean/15.6.3.1-3.js | 70 + js/src/tests/ecma/Boolean/15.6.3.1-4.js | 74 + js/src/tests/ecma/Boolean/15.6.3.1.js | 68 + js/src/tests/ecma/Boolean/15.6.4-1.js | 71 + js/src/tests/ecma/Boolean/15.6.4.1.js | 61 + js/src/tests/ecma/Boolean/15.6.4.2-1.js | 96 + js/src/tests/ecma/Boolean/15.6.4.2-2.js | 72 + js/src/tests/ecma/Boolean/15.6.4.2-3.js | 64 + js/src/tests/ecma/Boolean/15.6.4.2-4-n.js | 68 + js/src/tests/ecma/Boolean/15.6.4.3-1.js | 87 + js/src/tests/ecma/Boolean/15.6.4.3-2.js | 66 + js/src/tests/ecma/Boolean/15.6.4.3-3.js | 65 + js/src/tests/ecma/Boolean/15.6.4.3-4-n.js | 68 + js/src/tests/ecma/Boolean/15.6.4.3.js | 82 + js/src/tests/ecma/Boolean/15.6.4.js | 79 + js/src/tests/ecma/Boolean/browser.js | 0 js/src/tests/ecma/Boolean/jstests.list | 20 + js/src/tests/ecma/Boolean/shell.js | 0 js/src/tests/ecma/Date/15.9.1.1-1.js | 94 + js/src/tests/ecma/Date/15.9.1.1-2.js | 89 + js/src/tests/ecma/Date/15.9.1.13-1.js | 77 + js/src/tests/ecma/Date/15.9.2.1.js | 173 + js/src/tests/ecma/Date/15.9.2.2-1.js | 85 + js/src/tests/ecma/Date/15.9.2.2-2.js | 88 + js/src/tests/ecma/Date/15.9.2.2-3.js | 85 + js/src/tests/ecma/Date/15.9.2.2-4.js | 81 + js/src/tests/ecma/Date/15.9.2.2-5.js | 85 + js/src/tests/ecma/Date/15.9.2.2-6.js | 84 + js/src/tests/ecma/Date/15.9.3.1-1.js | 238 + js/src/tests/ecma/Date/15.9.3.1-2.js | 151 + js/src/tests/ecma/Date/15.9.3.1-3.js | 140 + js/src/tests/ecma/Date/15.9.3.1-4.js | 150 + js/src/tests/ecma/Date/15.9.3.1-5.js | 139 + js/src/tests/ecma/Date/15.9.3.2-1.js | 149 + js/src/tests/ecma/Date/15.9.3.2-2.js | 140 + js/src/tests/ecma/Date/15.9.3.2-3.js | 144 + js/src/tests/ecma/Date/15.9.3.2-4.js | 141 + js/src/tests/ecma/Date/15.9.3.2-5.js | 138 + js/src/tests/ecma/Date/15.9.3.8-1.js | 154 + js/src/tests/ecma/Date/15.9.3.8-2.js | 152 + js/src/tests/ecma/Date/15.9.3.8-3.js | 159 + js/src/tests/ecma/Date/15.9.3.8-4.js | 160 + js/src/tests/ecma/Date/15.9.3.8-5.js | 160 + js/src/tests/ecma/Date/15.9.4.2-1.js | 80 + js/src/tests/ecma/Date/15.9.4.2.js | 190 + js/src/tests/ecma/Date/15.9.4.3.js | 184 + js/src/tests/ecma/Date/15.9.5.1.js | 62 + js/src/tests/ecma/Date/15.9.5.10-1.js | 84 + js/src/tests/ecma/Date/15.9.5.10-10.js | 88 + js/src/tests/ecma/Date/15.9.5.10-11.js | 88 + js/src/tests/ecma/Date/15.9.5.10-12.js | 88 + js/src/tests/ecma/Date/15.9.5.10-13.js | 88 + js/src/tests/ecma/Date/15.9.5.10-2.js | 84 + js/src/tests/ecma/Date/15.9.5.10-3.js | 84 + js/src/tests/ecma/Date/15.9.5.10-4.js | 84 + js/src/tests/ecma/Date/15.9.5.10-5.js | 84 + js/src/tests/ecma/Date/15.9.5.10-6.js | 84 + js/src/tests/ecma/Date/15.9.5.10-7.js | 84 + js/src/tests/ecma/Date/15.9.5.10-8.js | 88 + js/src/tests/ecma/Date/15.9.5.10-9.js | 88 + js/src/tests/ecma/Date/15.9.5.11-1.js | 75 + js/src/tests/ecma/Date/15.9.5.11-2.js | 75 + js/src/tests/ecma/Date/15.9.5.11-3.js | 75 + js/src/tests/ecma/Date/15.9.5.11-4.js | 75 + js/src/tests/ecma/Date/15.9.5.11-5.js | 75 + js/src/tests/ecma/Date/15.9.5.11-6.js | 75 + js/src/tests/ecma/Date/15.9.5.11-7.js | 75 + js/src/tests/ecma/Date/15.9.5.12-1.js | 76 + js/src/tests/ecma/Date/15.9.5.12-2.js | 76 + js/src/tests/ecma/Date/15.9.5.12-3.js | 76 + js/src/tests/ecma/Date/15.9.5.12-4.js | 76 + js/src/tests/ecma/Date/15.9.5.12-5.js | 76 + js/src/tests/ecma/Date/15.9.5.12-6.js | 76 + js/src/tests/ecma/Date/15.9.5.12-7.js | 76 + js/src/tests/ecma/Date/15.9.5.12-8.js | 70 + js/src/tests/ecma/Date/15.9.5.13-1.js | 78 + js/src/tests/ecma/Date/15.9.5.13-2.js | 75 + js/src/tests/ecma/Date/15.9.5.13-3.js | 76 + js/src/tests/ecma/Date/15.9.5.13-4.js | 76 + js/src/tests/ecma/Date/15.9.5.13-5.js | 76 + js/src/tests/ecma/Date/15.9.5.13-6.js | 76 + js/src/tests/ecma/Date/15.9.5.13-7.js | 75 + js/src/tests/ecma/Date/15.9.5.13-8.js | 70 + js/src/tests/ecma/Date/15.9.5.14.js | 86 + js/src/tests/ecma/Date/15.9.5.15.js | 87 + js/src/tests/ecma/Date/15.9.5.16.js | 86 + js/src/tests/ecma/Date/15.9.5.17.js | 87 + js/src/tests/ecma/Date/15.9.5.18.js | 87 + js/src/tests/ecma/Date/15.9.5.19.js | 87 + js/src/tests/ecma/Date/15.9.5.2-1.js | 150 + js/src/tests/ecma/Date/15.9.5.2-2-n.js | 83 + js/src/tests/ecma/Date/15.9.5.2.js | 150 + js/src/tests/ecma/Date/15.9.5.20.js | 87 + js/src/tests/ecma/Date/15.9.5.21-1.js | 69 + js/src/tests/ecma/Date/15.9.5.21-2.js | 69 + js/src/tests/ecma/Date/15.9.5.21-3.js | 69 + js/src/tests/ecma/Date/15.9.5.21-4.js | 69 + js/src/tests/ecma/Date/15.9.5.21-5.js | 69 + js/src/tests/ecma/Date/15.9.5.21-6.js | 69 + js/src/tests/ecma/Date/15.9.5.21-7.js | 69 + js/src/tests/ecma/Date/15.9.5.21-8.js | 70 + js/src/tests/ecma/Date/15.9.5.22-1.js | 88 + js/src/tests/ecma/Date/15.9.5.22-2.js | 73 + js/src/tests/ecma/Date/15.9.5.22-3.js | 73 + js/src/tests/ecma/Date/15.9.5.22-4.js | 73 + js/src/tests/ecma/Date/15.9.5.22-5.js | 73 + js/src/tests/ecma/Date/15.9.5.22-6.js | 73 + js/src/tests/ecma/Date/15.9.5.22-7.js | 73 + js/src/tests/ecma/Date/15.9.5.22-8.js | 71 + js/src/tests/ecma/Date/15.9.5.23-1.js | 138 + js/src/tests/ecma/Date/15.9.5.23-10.js | 138 + js/src/tests/ecma/Date/15.9.5.23-11.js | 139 + js/src/tests/ecma/Date/15.9.5.23-12.js | 136 + js/src/tests/ecma/Date/15.9.5.23-13.js | 136 + js/src/tests/ecma/Date/15.9.5.23-14.js | 136 + js/src/tests/ecma/Date/15.9.5.23-15.js | 136 + js/src/tests/ecma/Date/15.9.5.23-16.js | 136 + js/src/tests/ecma/Date/15.9.5.23-17.js | 136 + js/src/tests/ecma/Date/15.9.5.23-18.js | 136 + js/src/tests/ecma/Date/15.9.5.23-2.js | 108 + js/src/tests/ecma/Date/15.9.5.23-3-n.js | 78 + js/src/tests/ecma/Date/15.9.5.23-4.js | 111 + js/src/tests/ecma/Date/15.9.5.23-5.js | 112 + js/src/tests/ecma/Date/15.9.5.23-6.js | 111 + js/src/tests/ecma/Date/15.9.5.23-7.js | 112 + js/src/tests/ecma/Date/15.9.5.23-8.js | 102 + js/src/tests/ecma/Date/15.9.5.23-9.js | 102 + js/src/tests/ecma/Date/15.9.5.24-1.js | 133 + js/src/tests/ecma/Date/15.9.5.24-2.js | 133 + js/src/tests/ecma/Date/15.9.5.24-3.js | 133 + js/src/tests/ecma/Date/15.9.5.24-4.js | 133 + js/src/tests/ecma/Date/15.9.5.24-5.js | 133 + js/src/tests/ecma/Date/15.9.5.24-6.js | 133 + js/src/tests/ecma/Date/15.9.5.24-7.js | 133 + js/src/tests/ecma/Date/15.9.5.24-8.js | 132 + js/src/tests/ecma/Date/15.9.5.25-1.js | 173 + js/src/tests/ecma/Date/15.9.5.26-1.js | 182 + js/src/tests/ecma/Date/15.9.5.27-1.js | 182 + js/src/tests/ecma/Date/15.9.5.28-1.js | 195 + js/src/tests/ecma/Date/15.9.5.29-1.js | 190 + js/src/tests/ecma/Date/15.9.5.3-1-n.js | 79 + js/src/tests/ecma/Date/15.9.5.3-2.js | 103 + js/src/tests/ecma/Date/15.9.5.30-1.js | 191 + js/src/tests/ecma/Date/15.9.5.31-1.js | 221 + js/src/tests/ecma/Date/15.9.5.32-1.js | 140 + js/src/tests/ecma/Date/15.9.5.33-1.js | 144 + js/src/tests/ecma/Date/15.9.5.34-1.js | 181 + js/src/tests/ecma/Date/15.9.5.35-1.js | 138 + js/src/tests/ecma/Date/15.9.5.36-1.js | 164 + js/src/tests/ecma/Date/15.9.5.36-2.js | 163 + js/src/tests/ecma/Date/15.9.5.36-3.js | 162 + js/src/tests/ecma/Date/15.9.5.36-4.js | 162 + js/src/tests/ecma/Date/15.9.5.36-5.js | 162 + js/src/tests/ecma/Date/15.9.5.36-6.js | 162 + js/src/tests/ecma/Date/15.9.5.36-7.js | 162 + js/src/tests/ecma/Date/15.9.5.37-1.js | 172 + js/src/tests/ecma/Date/15.9.5.37-2.js | 160 + js/src/tests/ecma/Date/15.9.5.37-3.js | 163 + js/src/tests/ecma/Date/15.9.5.37-4.js | 162 + js/src/tests/ecma/Date/15.9.5.37-5.js | 158 + js/src/tests/ecma/Date/15.9.5.4-1.js | 92 + js/src/tests/ecma/Date/15.9.5.4-2-n.js | 75 + js/src/tests/ecma/Date/15.9.5.5.js | 111 + js/src/tests/ecma/Date/15.9.5.6.js | 103 + js/src/tests/ecma/Date/15.9.5.7.js | 104 + js/src/tests/ecma/Date/15.9.5.8.js | 112 + js/src/tests/ecma/Date/15.9.5.9.js | 112 + js/src/tests/ecma/Date/15.9.5.js | 82 + js/src/tests/ecma/Date/browser.js | 0 .../tests/ecma/Date/dst-offset-caching-1-of-8.js | 5 + .../tests/ecma/Date/dst-offset-caching-2-of-8.js | 5 + .../tests/ecma/Date/dst-offset-caching-3-of-8.js | 5 + .../tests/ecma/Date/dst-offset-caching-4-of-8.js | 5 + .../tests/ecma/Date/dst-offset-caching-5-of-8.js | 5 + .../tests/ecma/Date/dst-offset-caching-6-of-8.js | 5 + .../tests/ecma/Date/dst-offset-caching-7-of-8.js | 5 + .../tests/ecma/Date/dst-offset-caching-8-of-8.js | 5 + js/src/tests/ecma/Date/jstests.list | 159 + js/src/tests/ecma/Date/shell.js | 149 + js/src/tests/ecma/ExecutionContexts/10.1.3-1.js | 106 + js/src/tests/ecma/ExecutionContexts/10.1.3-2.js | 72 + js/src/tests/ecma/ExecutionContexts/10.1.3.js | 169 + js/src/tests/ecma/ExecutionContexts/10.1.4-1.js | 110 + js/src/tests/ecma/ExecutionContexts/10.1.4-10.js | 104 + js/src/tests/ecma/ExecutionContexts/10.1.4-2.js | 112 + js/src/tests/ecma/ExecutionContexts/10.1.4-3.js | 110 + js/src/tests/ecma/ExecutionContexts/10.1.4-4.js | 112 + js/src/tests/ecma/ExecutionContexts/10.1.4-5.js | 111 + js/src/tests/ecma/ExecutionContexts/10.1.4-6.js | 99 + js/src/tests/ecma/ExecutionContexts/10.1.4-7.js | 111 + js/src/tests/ecma/ExecutionContexts/10.1.4-8.js | 112 + js/src/tests/ecma/ExecutionContexts/10.1.5-1.js | 117 + js/src/tests/ecma/ExecutionContexts/10.1.5-2.js | 99 + js/src/tests/ecma/ExecutionContexts/10.1.5-3.js | 129 + js/src/tests/ecma/ExecutionContexts/10.1.5-4.js | 90 + js/src/tests/ecma/ExecutionContexts/10.1.8-2.js | 119 + js/src/tests/ecma/ExecutionContexts/10.1.8-3.js | 65 + js/src/tests/ecma/ExecutionContexts/10.2.1.js | 84 + js/src/tests/ecma/ExecutionContexts/10.2.2-1.js | 121 + js/src/tests/ecma/ExecutionContexts/10.2.2-2.js | 132 + js/src/tests/ecma/ExecutionContexts/10.2.3-1.js | 85 + js/src/tests/ecma/ExecutionContexts/10.2.3-2.js | 91 + js/src/tests/ecma/ExecutionContexts/browser.js | 0 js/src/tests/ecma/ExecutionContexts/jstests.list | 24 + js/src/tests/ecma/ExecutionContexts/shell.js | 0 js/src/tests/ecma/Expressions/11.1.1.js | 136 + js/src/tests/ecma/Expressions/11.10-1.js | 269 + js/src/tests/ecma/Expressions/11.10-2.js | 268 + js/src/tests/ecma/Expressions/11.10-3.js | 267 + js/src/tests/ecma/Expressions/11.12-1.js | 109 + js/src/tests/ecma/Expressions/11.12-2-n.js | 73 + js/src/tests/ecma/Expressions/11.12-3.js | 70 + js/src/tests/ecma/Expressions/11.12-4.js | 70 + js/src/tests/ecma/Expressions/11.13.1.js | 71 + js/src/tests/ecma/Expressions/11.13.2-1.js | 230 + js/src/tests/ecma/Expressions/11.13.2-2.js | 252 + js/src/tests/ecma/Expressions/11.13.2-3.js | 299 + js/src/tests/ecma/Expressions/11.13.2-4.js | 136 + js/src/tests/ecma/Expressions/11.13.2-5.js | 136 + js/src/tests/ecma/Expressions/11.13.js | 85 + js/src/tests/ecma/Expressions/11.14-1.js | 72 + js/src/tests/ecma/Expressions/11.2.1-1.js | 271 + js/src/tests/ecma/Expressions/11.2.1-2.js | 127 + js/src/tests/ecma/Expressions/11.2.1-3-n.js | 127 + js/src/tests/ecma/Expressions/11.2.1-4-n.js | 127 + js/src/tests/ecma/Expressions/11.2.1-5.js | 127 + js/src/tests/ecma/Expressions/11.2.2-1-n.js | 103 + js/src/tests/ecma/Expressions/11.2.2-1.js | 99 + js/src/tests/ecma/Expressions/11.2.2-10-n.js | 101 + js/src/tests/ecma/Expressions/11.2.2-11.js | 103 + js/src/tests/ecma/Expressions/11.2.2-2-n.js | 103 + js/src/tests/ecma/Expressions/11.2.2-3-n.js | 99 + js/src/tests/ecma/Expressions/11.2.2-4-n.js | 103 + js/src/tests/ecma/Expressions/11.2.2-5-n.js | 103 + js/src/tests/ecma/Expressions/11.2.2-6-n.js | 102 + js/src/tests/ecma/Expressions/11.2.2-7-n.js | 103 + js/src/tests/ecma/Expressions/11.2.2-8-n.js | 103 + js/src/tests/ecma/Expressions/11.2.2-9-n.js | 103 + js/src/tests/ecma/Expressions/11.2.3-1.js | 124 + js/src/tests/ecma/Expressions/11.2.3-2-n.js | 93 + js/src/tests/ecma/Expressions/11.2.3-3-n.js | 90 + js/src/tests/ecma/Expressions/11.2.3-4-n.js | 90 + js/src/tests/ecma/Expressions/11.2.3-5.js | 84 + js/src/tests/ecma/Expressions/11.3.1.js | 152 + js/src/tests/ecma/Expressions/11.3.2.js | 152 + js/src/tests/ecma/Expressions/11.4.1.js | 91 + js/src/tests/ecma/Expressions/11.4.2.js | 82 + js/src/tests/ecma/Expressions/11.4.3.js | 110 + js/src/tests/ecma/Expressions/11.4.4.js | 155 + js/src/tests/ecma/Expressions/11.4.5.js | 153 + js/src/tests/ecma/Expressions/11.4.6.js | 298 + js/src/tests/ecma/Expressions/11.4.7-01.js | 298 + js/src/tests/ecma/Expressions/11.4.7-02.js | 86 + js/src/tests/ecma/Expressions/11.4.8.js | 214 + js/src/tests/ecma/Expressions/11.4.9.js | 90 + js/src/tests/ecma/Expressions/11.5.1.js | 114 + js/src/tests/ecma/Expressions/11.5.2.js | 153 + js/src/tests/ecma/Expressions/11.5.3.js | 160 + js/src/tests/ecma/Expressions/11.6.1-1.js | 159 + js/src/tests/ecma/Expressions/11.6.1-2.js | 163 + js/src/tests/ecma/Expressions/11.6.1-3.js | 149 + js/src/tests/ecma/Expressions/11.6.2-1.js | 164 + js/src/tests/ecma/Expressions/11.6.3.js | 114 + js/src/tests/ecma/Expressions/11.7.1.js | 227 + js/src/tests/ecma/Expressions/11.7.2.js | 245 + js/src/tests/ecma/Expressions/11.7.3.js | 229 + js/src/tests/ecma/Expressions/11.8.1.js | 120 + js/src/tests/ecma/Expressions/11.8.2.js | 120 + js/src/tests/ecma/Expressions/11.8.3.js | 119 + js/src/tests/ecma/Expressions/11.8.4.js | 120 + js/src/tests/ecma/Expressions/11.9.1.js | 158 + js/src/tests/ecma/Expressions/11.9.2.js | 158 + js/src/tests/ecma/Expressions/11.9.3.js | 158 + js/src/tests/ecma/Expressions/browser.js | 0 js/src/tests/ecma/Expressions/jstests.list | 69 + js/src/tests/ecma/Expressions/shell.js | 0 js/src/tests/ecma/FunctionObjects/15.3.1.1-1.js | 135 + js/src/tests/ecma/FunctionObjects/15.3.1.1-2.js | 182 + js/src/tests/ecma/FunctionObjects/15.3.1.1-3.js | 98 + js/src/tests/ecma/FunctionObjects/15.3.2.1-1.js | 131 + js/src/tests/ecma/FunctionObjects/15.3.2.1-2.js | 106 + js/src/tests/ecma/FunctionObjects/15.3.2.1-3.js | 94 + js/src/tests/ecma/FunctionObjects/15.3.3.1-2.js | 69 + js/src/tests/ecma/FunctionObjects/15.3.3.1-3.js | 78 + js/src/tests/ecma/FunctionObjects/15.3.3.1-4.js | 69 + js/src/tests/ecma/FunctionObjects/15.3.3.2.js | 61 + js/src/tests/ecma/FunctionObjects/15.3.4-1.js | 93 + js/src/tests/ecma/FunctionObjects/15.3.4.1.js | 60 + js/src/tests/ecma/FunctionObjects/15.3.4.js | 80 + js/src/tests/ecma/FunctionObjects/15.3.5-1.js | 116 + js/src/tests/ecma/FunctionObjects/15.3.5-2.js | 89 + js/src/tests/ecma/FunctionObjects/15.3.5.1.js | 82 + js/src/tests/ecma/FunctionObjects/15.3.5.3.js | 71 + js/src/tests/ecma/FunctionObjects/browser.js | 0 js/src/tests/ecma/FunctionObjects/jstests.list | 18 + js/src/tests/ecma/FunctionObjects/shell.js | 0 js/src/tests/ecma/GlobalObject/15.1-1-n.js | 69 + js/src/tests/ecma/GlobalObject/15.1-2-n.js | 66 + js/src/tests/ecma/GlobalObject/15.1.1.1.js | 62 + js/src/tests/ecma/GlobalObject/15.1.1.2.js | 61 + js/src/tests/ecma/GlobalObject/15.1.2.1-2.js | 65 + js/src/tests/ecma/GlobalObject/15.1.2.2-1.js | 411 + js/src/tests/ecma/GlobalObject/15.1.2.2-2.js | 237 + js/src/tests/ecma/GlobalObject/15.1.2.3-1.js | 440 + js/src/tests/ecma/GlobalObject/15.1.2.3-2.js | 290 + js/src/tests/ecma/GlobalObject/15.1.2.4.js | 204 + js/src/tests/ecma/GlobalObject/15.1.2.5-1.js | 205 + js/src/tests/ecma/GlobalObject/15.1.2.5-2.js | 182 + js/src/tests/ecma/GlobalObject/15.1.2.5-3.js | 206 + js/src/tests/ecma/GlobalObject/15.1.2.6.js | 124 + js/src/tests/ecma/GlobalObject/15.1.2.7.js | 129 + js/src/tests/ecma/GlobalObject/browser.js | 0 js/src/tests/ecma/GlobalObject/jstests.list | 16 + js/src/tests/ecma/GlobalObject/shell.js | 0 js/src/tests/ecma/LexicalConventions/7.1-1.js | 81 + js/src/tests/ecma/LexicalConventions/7.1-2.js | 72 + js/src/tests/ecma/LexicalConventions/7.1-3.js | 88 + js/src/tests/ecma/LexicalConventions/7.2-1.js | 72 + js/src/tests/ecma/LexicalConventions/7.2-2-n.js | 73 + js/src/tests/ecma/LexicalConventions/7.2-3-n.js | 73 + js/src/tests/ecma/LexicalConventions/7.2-4-n.js | 72 + js/src/tests/ecma/LexicalConventions/7.2-5-n.js | 71 + js/src/tests/ecma/LexicalConventions/7.2-6.js | 67 + js/src/tests/ecma/LexicalConventions/7.3-1.js | 91 + js/src/tests/ecma/LexicalConventions/7.3-10.js | 64 + js/src/tests/ecma/LexicalConventions/7.3-11.js | 65 + js/src/tests/ecma/LexicalConventions/7.3-12.js | 63 + js/src/tests/ecma/LexicalConventions/7.3-13-n.js | 65 + js/src/tests/ecma/LexicalConventions/7.3-2.js | 64 + js/src/tests/ecma/LexicalConventions/7.3-3.js | 64 + js/src/tests/ecma/LexicalConventions/7.3-4.js | 64 + js/src/tests/ecma/LexicalConventions/7.3-5.js | 64 + js/src/tests/ecma/LexicalConventions/7.3-6.js | 64 + js/src/tests/ecma/LexicalConventions/7.3-7.js | 65 + js/src/tests/ecma/LexicalConventions/7.3-8.js | 64 + js/src/tests/ecma/LexicalConventions/7.3-9.js | 64 + js/src/tests/ecma/LexicalConventions/7.4.1-1-n.js | 70 + js/src/tests/ecma/LexicalConventions/7.4.1-2-n.js | 70 + js/src/tests/ecma/LexicalConventions/7.4.1-3-n.js | 68 + js/src/tests/ecma/LexicalConventions/7.4.2-1-n.js | 76 + js/src/tests/ecma/LexicalConventions/7.4.2-10-n.js | 76 + js/src/tests/ecma/LexicalConventions/7.4.2-11-n.js | 76 + js/src/tests/ecma/LexicalConventions/7.4.2-12-n.js | 76 + js/src/tests/ecma/LexicalConventions/7.4.2-13-n.js | 76 + js/src/tests/ecma/LexicalConventions/7.4.2-14-n.js | 76 + js/src/tests/ecma/LexicalConventions/7.4.2-15-n.js | 76 + js/src/tests/ecma/LexicalConventions/7.4.2-16-n.js | 76 + js/src/tests/ecma/LexicalConventions/7.4.2-2-n.js | 76 + js/src/tests/ecma/LexicalConventions/7.4.2-3-n.js | 76 + js/src/tests/ecma/LexicalConventions/7.4.2-4-n.js | 76 + js/src/tests/ecma/LexicalConventions/7.4.2-5-n.js | 76 + js/src/tests/ecma/LexicalConventions/7.4.2-6-n.js | 76 + js/src/tests/ecma/LexicalConventions/7.4.2-7-n.js | 74 + js/src/tests/ecma/LexicalConventions/7.4.2-8-n.js | 75 + js/src/tests/ecma/LexicalConventions/7.4.2-9-n.js | 76 + js/src/tests/ecma/LexicalConventions/7.4.3-1-n.js | 70 + js/src/tests/ecma/LexicalConventions/7.4.3-10-n.js | 70 + js/src/tests/ecma/LexicalConventions/7.4.3-11-n.js | 70 + js/src/tests/ecma/LexicalConventions/7.4.3-12-n.js | 70 + js/src/tests/ecma/LexicalConventions/7.4.3-13-n.js | 70 + js/src/tests/ecma/LexicalConventions/7.4.3-14-n.js | 102 + js/src/tests/ecma/LexicalConventions/7.4.3-15-n.js | 96 + js/src/tests/ecma/LexicalConventions/7.4.3-16-n.js | 87 + js/src/tests/ecma/LexicalConventions/7.4.3-2-n.js | 70 + js/src/tests/ecma/LexicalConventions/7.4.3-3-n.js | 70 + js/src/tests/ecma/LexicalConventions/7.4.3-4-n.js | 101 + js/src/tests/ecma/LexicalConventions/7.4.3-5-n.js | 70 + js/src/tests/ecma/LexicalConventions/7.4.3-6-n.js | 70 + js/src/tests/ecma/LexicalConventions/7.4.3-7-n.js | 102 + js/src/tests/ecma/LexicalConventions/7.4.3-8-n.js | 70 + js/src/tests/ecma/LexicalConventions/7.4.3-9-n.js | 103 + js/src/tests/ecma/LexicalConventions/7.5-1.js | 61 + js/src/tests/ecma/LexicalConventions/7.5-10-n.js | 63 + js/src/tests/ecma/LexicalConventions/7.5-2-n.js | 63 + js/src/tests/ecma/LexicalConventions/7.5-3-n.js | 63 + js/src/tests/ecma/LexicalConventions/7.5-4-n.js | 63 + js/src/tests/ecma/LexicalConventions/7.5-5-n.js | 63 + js/src/tests/ecma/LexicalConventions/7.5-6.js | 60 + js/src/tests/ecma/LexicalConventions/7.5-7.js | 60 + js/src/tests/ecma/LexicalConventions/7.5-8-n.js | 63 + js/src/tests/ecma/LexicalConventions/7.5-9-n.js | 63 + js/src/tests/ecma/LexicalConventions/7.6.js | 312 + js/src/tests/ecma/LexicalConventions/7.7.1.js | 63 + js/src/tests/ecma/LexicalConventions/7.7.2.js | 70 + js/src/tests/ecma/LexicalConventions/7.7.3-1.js | 197 + js/src/tests/ecma/LexicalConventions/7.7.3-2.js | 92 + js/src/tests/ecma/LexicalConventions/7.7.3.js | 330 + js/src/tests/ecma/LexicalConventions/7.7.4.js | 268 + js/src/tests/ecma/LexicalConventions/7.8.2-n.js | 62 + js/src/tests/ecma/LexicalConventions/browser.js | 0 js/src/tests/ecma/LexicalConventions/jstests.list | 76 + js/src/tests/ecma/LexicalConventions/shell.js | 0 js/src/tests/ecma/Math/15.8-2-n.js | 81 + js/src/tests/ecma/Math/15.8-3-n.js | 80 + js/src/tests/ecma/Math/15.8.1.1-1.js | 63 + js/src/tests/ecma/Math/15.8.1.1-2.js | 68 + js/src/tests/ecma/Math/15.8.1.2-1.js | 63 + js/src/tests/ecma/Math/15.8.1.2-2.js | 69 + js/src/tests/ecma/Math/15.8.1.3-1.js | 64 + js/src/tests/ecma/Math/15.8.1.3-2.js | 71 + js/src/tests/ecma/Math/15.8.1.4-1.js | 64 + js/src/tests/ecma/Math/15.8.1.4-2.js | 68 + js/src/tests/ecma/Math/15.8.1.5-1.js | 65 + js/src/tests/ecma/Math/15.8.1.5-2.js | 69 + js/src/tests/ecma/Math/15.8.1.6-1.js | 64 + js/src/tests/ecma/Math/15.8.1.6-2.js | 69 + js/src/tests/ecma/Math/15.8.1.7-1.js | 64 + js/src/tests/ecma/Math/15.8.1.7-2.js | 69 + js/src/tests/ecma/Math/15.8.1.8-1.js | 64 + js/src/tests/ecma/Math/15.8.1.8-2.js | 68 + js/src/tests/ecma/Math/15.8.1.8-3.js | 62 + js/src/tests/ecma/Math/15.8.1.js | 148 + js/src/tests/ecma/Math/15.8.2.1.js | 225 + js/src/tests/ecma/Math/15.8.2.10.js | 152 + js/src/tests/ecma/Math/15.8.2.11.js | 199 + js/src/tests/ecma/Math/15.8.2.12.js | 176 + js/src/tests/ecma/Math/15.8.2.13.js | 384 + js/src/tests/ecma/Math/15.8.2.14.js | 78 + js/src/tests/ecma/Math/15.8.2.15.js | 201 + js/src/tests/ecma/Math/15.8.2.16.js | 131 + js/src/tests/ecma/Math/15.8.2.17.js | 216 + js/src/tests/ecma/Math/15.8.2.18.js | 164 + js/src/tests/ecma/Math/15.8.2.2.js | 155 + js/src/tests/ecma/Math/15.8.2.3.js | 157 + js/src/tests/ecma/Math/15.8.2.4.js | 155 + js/src/tests/ecma/Math/15.8.2.5.js | 243 + js/src/tests/ecma/Math/15.8.2.6.js | 231 + js/src/tests/ecma/Math/15.8.2.7.js | 282 + js/src/tests/ecma/Math/15.8.2.8.js | 133 + js/src/tests/ecma/Math/15.8.2.9.js | 190 + js/src/tests/ecma/Math/browser.js | 0 js/src/tests/ecma/Math/jstests.list | 39 + js/src/tests/ecma/Math/shell.js | 0 js/src/tests/ecma/NativeObjects/browser.js | 0 js/src/tests/ecma/NativeObjects/jstests.list | 0 js/src/tests/ecma/NativeObjects/shell.js | 0 .../ecma/Number/0x-without-following-hexdigits.js | 30 + js/src/tests/ecma/Number/15.7.1.js | 87 + js/src/tests/ecma/Number/15.7.2.js | 167 + js/src/tests/ecma/Number/15.7.3.1-1.js | 70 + js/src/tests/ecma/Number/15.7.3.1-2.js | 70 + js/src/tests/ecma/Number/15.7.3.1-3.js | 66 + js/src/tests/ecma/Number/15.7.3.2-1.js | 64 + js/src/tests/ecma/Number/15.7.3.2-2.js | 69 + js/src/tests/ecma/Number/15.7.3.2-3.js | 66 + js/src/tests/ecma/Number/15.7.3.2-4.js | 63 + js/src/tests/ecma/Number/15.7.3.3-1.js | 67 + js/src/tests/ecma/Number/15.7.3.3-2.js | 72 + js/src/tests/ecma/Number/15.7.3.3-3.js | 63 + js/src/tests/ecma/Number/15.7.3.3-4.js | 65 + js/src/tests/ecma/Number/15.7.3.4-1.js | 65 + js/src/tests/ecma/Number/15.7.3.4-2.js | 70 + js/src/tests/ecma/Number/15.7.3.4-3.js | 64 + js/src/tests/ecma/Number/15.7.3.4-4.js | 65 + js/src/tests/ecma/Number/15.7.3.5-1.js | 63 + js/src/tests/ecma/Number/15.7.3.5-2.js | 69 + js/src/tests/ecma/Number/15.7.3.5-3.js | 64 + js/src/tests/ecma/Number/15.7.3.5-4.js | 65 + js/src/tests/ecma/Number/15.7.3.6-1.js | 64 + js/src/tests/ecma/Number/15.7.3.6-2.js | 68 + js/src/tests/ecma/Number/15.7.3.6-3.js | 64 + js/src/tests/ecma/Number/15.7.3.6-4.js | 65 + js/src/tests/ecma/Number/15.7.3.js | 68 + js/src/tests/ecma/Number/15.7.4-1.js | 59 + js/src/tests/ecma/Number/15.7.4.1.js | 61 + js/src/tests/ecma/Number/15.7.4.2-1.js | 110 + js/src/tests/ecma/Number/15.7.4.2-2-n.js | 75 + js/src/tests/ecma/Number/15.7.4.2-3-n.js | 72 + js/src/tests/ecma/Number/15.7.4.2-4.js | 69 + js/src/tests/ecma/Number/15.7.4.3-1.js | 96 + js/src/tests/ecma/Number/15.7.4.3-2.js | 64 + js/src/tests/ecma/Number/15.7.4.3-3-n.js | 71 + js/src/tests/ecma/Number/browser.js | 0 js/src/tests/ecma/Number/jstests.list | 37 + js/src/tests/ecma/Number/shell.js | 0 js/src/tests/ecma/ObjectObjects/15.2.1.1.js | 145 + js/src/tests/ecma/ObjectObjects/15.2.1.2.js | 80 + js/src/tests/ecma/ObjectObjects/15.2.2.1.js | 137 + js/src/tests/ecma/ObjectObjects/15.2.2.2.js | 73 + js/src/tests/ecma/ObjectObjects/15.2.3-1.js | 63 + js/src/tests/ecma/ObjectObjects/15.2.3.1-1.js | 68 + js/src/tests/ecma/ObjectObjects/15.2.3.1-2.js | 69 + js/src/tests/ecma/ObjectObjects/15.2.3.1-3.js | 69 + js/src/tests/ecma/ObjectObjects/15.2.3.1-4.js | 69 + js/src/tests/ecma/ObjectObjects/15.2.3.js | 66 + js/src/tests/ecma/ObjectObjects/15.2.4.1.js | 63 + js/src/tests/ecma/ObjectObjects/15.2.4.2.js | 129 + js/src/tests/ecma/ObjectObjects/15.2.4.3.js | 116 + js/src/tests/ecma/ObjectObjects/browser.js | 0 js/src/tests/ecma/ObjectObjects/jstests.list | 14 + js/src/tests/ecma/ObjectObjects/shell.js | 0 js/src/tests/ecma/README | 1 + js/src/tests/ecma/SourceText/6-1.js | 127 + js/src/tests/ecma/SourceText/6-2.js | 130 + js/src/tests/ecma/SourceText/browser.js | 0 js/src/tests/ecma/SourceText/jstests.list | 3 + js/src/tests/ecma/SourceText/shell.js | 0 js/src/tests/ecma/Statements/12.10-1.js | 150 + js/src/tests/ecma/Statements/12.10.js | 60 + js/src/tests/ecma/Statements/12.2-1.js | 73 + js/src/tests/ecma/Statements/12.5-1.js | 101 + js/src/tests/ecma/Statements/12.5-2.js | 98 + js/src/tests/ecma/Statements/12.6.1-1.js | 73 + js/src/tests/ecma/Statements/12.6.2-1.js | 74 + js/src/tests/ecma/Statements/12.6.2-2.js | 75 + js/src/tests/ecma/Statements/12.6.2-3.js | 71 + js/src/tests/ecma/Statements/12.6.2-4.js | 71 + js/src/tests/ecma/Statements/12.6.2-5.js | 72 + js/src/tests/ecma/Statements/12.6.2-6.js | 74 + js/src/tests/ecma/Statements/12.6.2-7.js | 72 + js/src/tests/ecma/Statements/12.6.2-8.js | 70 + js/src/tests/ecma/Statements/12.6.2-9-n.js | 75 + js/src/tests/ecma/Statements/12.6.3-1.js | 62 + js/src/tests/ecma/Statements/12.6.3-10.js | 114 + js/src/tests/ecma/Statements/12.6.3-11.js | 97 + js/src/tests/ecma/Statements/12.6.3-12.js | 102 + js/src/tests/ecma/Statements/12.6.3-19.js | 116 + js/src/tests/ecma/Statements/12.6.3-2.js | 62 + js/src/tests/ecma/Statements/12.6.3-3.js | 72 + js/src/tests/ecma/Statements/12.6.3-4.js | 201 + js/src/tests/ecma/Statements/12.6.3-5-n.js | 109 + js/src/tests/ecma/Statements/12.6.3-6-n.js | 108 + js/src/tests/ecma/Statements/12.6.3-7-n.js | 109 + js/src/tests/ecma/Statements/12.6.3-8-n.js | 109 + js/src/tests/ecma/Statements/12.6.3-9-n.js | 108 + js/src/tests/ecma/Statements/12.7-1-n.js | 63 + js/src/tests/ecma/Statements/12.8-1-n.js | 66 + js/src/tests/ecma/Statements/12.9-1-n.js | 62 + js/src/tests/ecma/Statements/browser.js | 0 js/src/tests/ecma/Statements/jstests.list | 32 + js/src/tests/ecma/Statements/shell.js | 0 js/src/tests/ecma/String/15.5.1.js | 133 + js/src/tests/ecma/String/15.5.2.js | 109 + js/src/tests/ecma/String/15.5.3.1-1.js | 70 + js/src/tests/ecma/String/15.5.3.1-2.js | 68 + js/src/tests/ecma/String/15.5.3.1-3.js | 65 + js/src/tests/ecma/String/15.5.3.1-4.js | 65 + js/src/tests/ecma/String/15.5.3.2-1.js | 189 + js/src/tests/ecma/String/15.5.3.2-2.js | 76 + js/src/tests/ecma/String/15.5.3.2-3.js | 120 + js/src/tests/ecma/String/15.5.3.js | 65 + js/src/tests/ecma/String/15.5.4.1.js | 62 + js/src/tests/ecma/String/15.5.4.10-1.js | 216 + js/src/tests/ecma/String/15.5.4.11-1.js | 517 + js/src/tests/ecma/String/15.5.4.11-2.js | 514 + js/src/tests/ecma/String/15.5.4.11-3.js | 513 + js/src/tests/ecma/String/15.5.4.11-4.js | 506 + js/src/tests/ecma/String/15.5.4.11-5.js | 519 + js/src/tests/ecma/String/15.5.4.11-6.js | 515 + js/src/tests/ecma/String/15.5.4.12-1.js | 519 + js/src/tests/ecma/String/15.5.4.12-2.js | 517 + js/src/tests/ecma/String/15.5.4.12-3.js | 558 + js/src/tests/ecma/String/15.5.4.12-4.js | 514 + js/src/tests/ecma/String/15.5.4.12-5.js | 514 + js/src/tests/ecma/String/15.5.4.2-1.js | 71 + js/src/tests/ecma/String/15.5.4.2-2-n.js | 72 + js/src/tests/ecma/String/15.5.4.2-3.js | 82 + js/src/tests/ecma/String/15.5.4.2.js | 86 + js/src/tests/ecma/String/15.5.4.3-1.js | 71 + js/src/tests/ecma/String/15.5.4.3-2.js | 89 + js/src/tests/ecma/String/15.5.4.3-3-n.js | 71 + js/src/tests/ecma/String/15.5.4.4-1.js | 91 + js/src/tests/ecma/String/15.5.4.4-2.js | 135 + js/src/tests/ecma/String/15.5.4.4-3.js | 111 + js/src/tests/ecma/String/15.5.4.4-4.js | 123 + js/src/tests/ecma/String/15.5.4.5-1.js | 86 + js/src/tests/ecma/String/15.5.4.5-2.js | 120 + js/src/tests/ecma/String/15.5.4.5-3.js | 130 + js/src/tests/ecma/String/15.5.4.5-4.js | 74 + js/src/tests/ecma/String/15.5.4.5-5.js | 105 + js/src/tests/ecma/String/15.5.4.6-1.js | 154 + js/src/tests/ecma/String/15.5.4.6-2.js | 253 + js/src/tests/ecma/String/15.5.4.7-1.js | 218 + js/src/tests/ecma/String/15.5.4.7-2.js | 216 + js/src/tests/ecma/String/15.5.4.8-1.js | 231 + js/src/tests/ecma/String/15.5.4.8-2.js | 246 + js/src/tests/ecma/String/15.5.4.8-3.js | 203 + js/src/tests/ecma/String/15.5.4.9-1.js | 201 + js/src/tests/ecma/String/15.5.4.js | 107 + js/src/tests/ecma/String/15.5.5.1.js | 87 + js/src/tests/ecma/String/browser.js | 0 js/src/tests/ecma/String/jstests.list | 50 + js/src/tests/ecma/String/shell.js | 0 js/src/tests/ecma/TypeConversion/9.2.js | 137 + js/src/tests/ecma/TypeConversion/9.3-1.js | 100 + js/src/tests/ecma/TypeConversion/9.3.1-1.js | 341 + js/src/tests/ecma/TypeConversion/9.3.1-2.js | 86 + js/src/tests/ecma/TypeConversion/9.3.1-3.js | 746 + js/src/tests/ecma/TypeConversion/9.3.js | 86 + js/src/tests/ecma/TypeConversion/9.4-1.js | 111 + js/src/tests/ecma/TypeConversion/9.4-2.js | 111 + js/src/tests/ecma/TypeConversion/9.5-2.js | 172 + js/src/tests/ecma/TypeConversion/9.6.js | 139 + js/src/tests/ecma/TypeConversion/9.7.js | 159 + js/src/tests/ecma/TypeConversion/9.8.1.js | 166 + js/src/tests/ecma/TypeConversion/9.9-1.js | 118 + js/src/tests/ecma/TypeConversion/browser.js | 0 js/src/tests/ecma/TypeConversion/jstests.list | 14 + js/src/tests/ecma/TypeConversion/shell.js | 0 js/src/tests/ecma/Types/8.1.js | 74 + js/src/tests/ecma/Types/8.4.js | 129 + js/src/tests/ecma/Types/8.6.2.1-1.js | 77 + js/src/tests/ecma/Types/browser.js | 0 js/src/tests/ecma/Types/jstests.list | 4 + js/src/tests/ecma/Types/shell.js | 0 js/src/tests/ecma/browser.js | 62 + js/src/tests/ecma/extensions/10.1.4-9.js | 109 + js/src/tests/ecma/extensions/10.1.6.js | 126 + js/src/tests/ecma/extensions/10.1.8-1.js | 134 + js/src/tests/ecma/extensions/11.6.1-1.js | 144 + js/src/tests/ecma/extensions/11.6.1-2.js | 135 + js/src/tests/ecma/extensions/11.6.1-3.js | 136 + js/src/tests/ecma/extensions/11.6.2-1.js | 123 + js/src/tests/ecma/extensions/15-1.js | 93 + js/src/tests/ecma/extensions/15-2.js | 76 + js/src/tests/ecma/extensions/15.1.2.1-1.js | 87 + js/src/tests/ecma/extensions/15.2.1.1.js | 81 + js/src/tests/ecma/extensions/15.2.3-1.js | 63 + js/src/tests/ecma/extensions/15.2.4.js | 65 + js/src/tests/ecma/extensions/15.3.1.1-1.js | 81 + js/src/tests/ecma/extensions/15.3.1.1-2.js | 81 + js/src/tests/ecma/extensions/15.3.2.1-1.js | 71 + js/src/tests/ecma/extensions/15.3.2.1-2.js | 71 + js/src/tests/ecma/extensions/15.3.3.1-1.js | 66 + js/src/tests/ecma/extensions/15.4.3.js | 62 + js/src/tests/ecma/extensions/15.5.3.js | 65 + js/src/tests/ecma/extensions/15.5.4.2.js | 58 + js/src/tests/ecma/extensions/15.5.4.4-4.js | 106 + js/src/tests/ecma/extensions/15.5.4.5-6.js | 93 + js/src/tests/ecma/extensions/15.5.4.7-3.js | 160 + js/src/tests/ecma/extensions/15.6.3.1-5.js | 57 + js/src/tests/ecma/extensions/15.6.3.js | 64 + js/src/tests/ecma/extensions/15.6.4-2.js | 65 + js/src/tests/ecma/extensions/15.7.3.js | 68 + js/src/tests/ecma/extensions/15.7.4.js | 89 + js/src/tests/ecma/extensions/15.8-1.js | 83 + js/src/tests/ecma/extensions/15.9.5.js | 75 + js/src/tests/ecma/extensions/8.6.2.1-1.js | 97 + js/src/tests/ecma/extensions/9.9-1.js | 101 + js/src/tests/ecma/extensions/browser.js | 0 js/src/tests/ecma/extensions/jstests.list | 35 + js/src/tests/ecma/extensions/shell.js | 0 js/src/tests/ecma/extensions/trapflatclosure.js | 25 + js/src/tests/ecma/jsref.js | 632 + js/src/tests/ecma/jstests.list | 18 + js/src/tests/ecma/shell.js | 580 + js/src/tests/ecma/template.js | 39 + js/src/tests/ecma_2/Exceptions/boolean-001.js | 79 + js/src/tests/ecma_2/Exceptions/boolean-002.js | 83 + js/src/tests/ecma_2/Exceptions/browser.js | 0 js/src/tests/ecma_2/Exceptions/date-001.js | 92 + js/src/tests/ecma_2/Exceptions/date-002.js | 86 + js/src/tests/ecma_2/Exceptions/date-003.js | 88 + js/src/tests/ecma_2/Exceptions/date-004.js | 82 + js/src/tests/ecma_2/Exceptions/exception-001.js | 77 + js/src/tests/ecma_2/Exceptions/exception-002.js | 77 + js/src/tests/ecma_2/Exceptions/exception-003.js | 81 + js/src/tests/ecma_2/Exceptions/exception-004.js | 77 + js/src/tests/ecma_2/Exceptions/exception-005.js | 77 + js/src/tests/ecma_2/Exceptions/exception-006.js | 88 + js/src/tests/ecma_2/Exceptions/exception-007.js | 89 + js/src/tests/ecma_2/Exceptions/exception-008.js | 76 + js/src/tests/ecma_2/Exceptions/exception-009.js | 85 + js/src/tests/ecma_2/Exceptions/exception-010-n.js | 60 + js/src/tests/ecma_2/Exceptions/exception-011-n.js | 61 + js/src/tests/ecma_2/Exceptions/expression-001.js | 82 + js/src/tests/ecma_2/Exceptions/expression-002.js | 92 + js/src/tests/ecma_2/Exceptions/expression-003.js | 87 + js/src/tests/ecma_2/Exceptions/expression-004.js | 81 + js/src/tests/ecma_2/Exceptions/expression-005.js | 73 + js/src/tests/ecma_2/Exceptions/expression-006.js | 78 + js/src/tests/ecma_2/Exceptions/expression-007.js | 76 + js/src/tests/ecma_2/Exceptions/expression-008.js | 73 + js/src/tests/ecma_2/Exceptions/expression-009.js | 74 + js/src/tests/ecma_2/Exceptions/expression-010.js | 75 + js/src/tests/ecma_2/Exceptions/expression-011.js | 75 + js/src/tests/ecma_2/Exceptions/expression-012.js | 76 + js/src/tests/ecma_2/Exceptions/expression-013.js | 76 + js/src/tests/ecma_2/Exceptions/expression-014.js | 78 + js/src/tests/ecma_2/Exceptions/expression-015.js | 72 + js/src/tests/ecma_2/Exceptions/expression-016.js | 72 + js/src/tests/ecma_2/Exceptions/expression-017.js | 72 + js/src/tests/ecma_2/Exceptions/expression-019.js | 76 + js/src/tests/ecma_2/Exceptions/function-001.js | 85 + js/src/tests/ecma_2/Exceptions/global-001.js | 77 + js/src/tests/ecma_2/Exceptions/global-002.js | 77 + js/src/tests/ecma_2/Exceptions/jstests.list | 103 + js/src/tests/ecma_2/Exceptions/lexical-001.js | 84 + js/src/tests/ecma_2/Exceptions/lexical-002.js | 84 + js/src/tests/ecma_2/Exceptions/lexical-003.js | 75 + js/src/tests/ecma_2/Exceptions/lexical-004.js | 84 + js/src/tests/ecma_2/Exceptions/lexical-005.js | 84 + js/src/tests/ecma_2/Exceptions/lexical-006.js | 90 + js/src/tests/ecma_2/Exceptions/lexical-007.js | 83 + js/src/tests/ecma_2/Exceptions/lexical-008.js | 85 + js/src/tests/ecma_2/Exceptions/lexical-009.js | 85 + js/src/tests/ecma_2/Exceptions/lexical-010.js | 83 + js/src/tests/ecma_2/Exceptions/lexical-011.js | 94 + js/src/tests/ecma_2/Exceptions/lexical-012.js | 85 + js/src/tests/ecma_2/Exceptions/lexical-013.js | 85 + js/src/tests/ecma_2/Exceptions/lexical-014.js | 94 + js/src/tests/ecma_2/Exceptions/lexical-015.js | 85 + js/src/tests/ecma_2/Exceptions/lexical-016.js | 94 + js/src/tests/ecma_2/Exceptions/lexical-017.js | 86 + js/src/tests/ecma_2/Exceptions/lexical-018.js | 85 + js/src/tests/ecma_2/Exceptions/lexical-019.js | 85 + js/src/tests/ecma_2/Exceptions/lexical-020.js | 85 + js/src/tests/ecma_2/Exceptions/lexical-021.js | 94 + js/src/tests/ecma_2/Exceptions/lexical-022.js | 85 + js/src/tests/ecma_2/Exceptions/lexical-023.js | 84 + js/src/tests/ecma_2/Exceptions/lexical-024.js | 91 + js/src/tests/ecma_2/Exceptions/lexical-025.js | 91 + js/src/tests/ecma_2/Exceptions/lexical-026.js | 91 + js/src/tests/ecma_2/Exceptions/lexical-027.js | 93 + js/src/tests/ecma_2/Exceptions/lexical-028.js | 91 + js/src/tests/ecma_2/Exceptions/lexical-029.js | 91 + js/src/tests/ecma_2/Exceptions/lexical-030.js | 91 + js/src/tests/ecma_2/Exceptions/lexical-031.js | 91 + js/src/tests/ecma_2/Exceptions/lexical-032.js | 91 + js/src/tests/ecma_2/Exceptions/lexical-033.js | 91 + js/src/tests/ecma_2/Exceptions/lexical-034.js | 90 + js/src/tests/ecma_2/Exceptions/lexical-035.js | 91 + js/src/tests/ecma_2/Exceptions/lexical-036.js | 91 + js/src/tests/ecma_2/Exceptions/lexical-037.js | 91 + js/src/tests/ecma_2/Exceptions/lexical-038.js | 91 + js/src/tests/ecma_2/Exceptions/lexical-039.js | 78 + js/src/tests/ecma_2/Exceptions/lexical-040.js | 78 + js/src/tests/ecma_2/Exceptions/lexical-041.js | 80 + js/src/tests/ecma_2/Exceptions/lexical-042.js | 81 + js/src/tests/ecma_2/Exceptions/lexical-047.js | 82 + js/src/tests/ecma_2/Exceptions/lexical-048.js | 76 + js/src/tests/ecma_2/Exceptions/lexical-049.js | 81 + js/src/tests/ecma_2/Exceptions/lexical-050.js | 77 + js/src/tests/ecma_2/Exceptions/lexical-051.js | 77 + js/src/tests/ecma_2/Exceptions/lexical-052.js | 79 + js/src/tests/ecma_2/Exceptions/lexical-053.js | 77 + js/src/tests/ecma_2/Exceptions/lexical-054.js | 78 + js/src/tests/ecma_2/Exceptions/number-001.js | 85 + js/src/tests/ecma_2/Exceptions/number-002.js | 80 + js/src/tests/ecma_2/Exceptions/number-003.js | 82 + js/src/tests/ecma_2/Exceptions/shell.js | 0 js/src/tests/ecma_2/Exceptions/statement-001.js | 79 + js/src/tests/ecma_2/Exceptions/statement-002.js | 101 + js/src/tests/ecma_2/Exceptions/statement-003.js | 112 + js/src/tests/ecma_2/Exceptions/statement-004.js | 84 + js/src/tests/ecma_2/Exceptions/statement-005.js | 83 + js/src/tests/ecma_2/Exceptions/statement-006.js | 83 + js/src/tests/ecma_2/Exceptions/statement-007.js | 74 + js/src/tests/ecma_2/Exceptions/statement-008.js | 74 + js/src/tests/ecma_2/Exceptions/statement-009.js | 73 + js/src/tests/ecma_2/Exceptions/string-001.js | 85 + js/src/tests/ecma_2/Exceptions/string-002.js | 84 + .../tests/ecma_2/Expressions/StrictEquality-001.js | 105 + js/src/tests/ecma_2/Expressions/browser.js | 0 js/src/tests/ecma_2/Expressions/jstests.list | 2 + js/src/tests/ecma_2/Expressions/shell.js | 0 js/src/tests/ecma_2/FunctionObjects/apply-001-n.js | 64 + js/src/tests/ecma_2/FunctionObjects/browser.js | 0 js/src/tests/ecma_2/FunctionObjects/call-1.js | 74 + js/src/tests/ecma_2/FunctionObjects/jstests.list | 3 + js/src/tests/ecma_2/FunctionObjects/shell.js | 0 js/src/tests/ecma_2/LexicalConventions/browser.js | 0 .../tests/ecma_2/LexicalConventions/jstests.list | 4 + .../ecma_2/LexicalConventions/keywords-001.js | 80 + .../LexicalConventions/regexp-literals-001.js | 76 + .../LexicalConventions/regexp-literals-002.js | 60 + js/src/tests/ecma_2/LexicalConventions/shell.js | 0 js/src/tests/ecma_2/README | 1 + js/src/tests/ecma_2/RegExp/browser.js | 0 js/src/tests/ecma_2/RegExp/constructor-001.js | 98 + js/src/tests/ecma_2/RegExp/exec-001.js | 72 + js/src/tests/ecma_2/RegExp/exec-002.js | 220 + js/src/tests/ecma_2/RegExp/function-001.js | 98 + js/src/tests/ecma_2/RegExp/hex-001.js | 101 + js/src/tests/ecma_2/RegExp/jstests.list | 15 + js/src/tests/ecma_2/RegExp/multiline-001.js | 100 + js/src/tests/ecma_2/RegExp/octal-001.js | 110 + js/src/tests/ecma_2/RegExp/octal-002.js | 125 + js/src/tests/ecma_2/RegExp/octal-003.js | 119 + js/src/tests/ecma_2/RegExp/properties-001.js | 123 + js/src/tests/ecma_2/RegExp/properties-002.js | 161 + js/src/tests/ecma_2/RegExp/regexp-enumerate-001.js | 120 + js/src/tests/ecma_2/RegExp/regress-001.js | 77 + js/src/tests/ecma_2/RegExp/shell.js | 0 js/src/tests/ecma_2/RegExp/unicode-001.js | 91 + js/src/tests/ecma_2/Statements/browser.js | 0 js/src/tests/ecma_2/Statements/dowhile-001.js | 76 + js/src/tests/ecma_2/Statements/dowhile-002.js | 103 + js/src/tests/ecma_2/Statements/dowhile-003.js | 95 + js/src/tests/ecma_2/Statements/dowhile-004.js | 99 + js/src/tests/ecma_2/Statements/dowhile-005.js | 105 + js/src/tests/ecma_2/Statements/dowhile-006.js | 121 + js/src/tests/ecma_2/Statements/dowhile-007.js | 129 + js/src/tests/ecma_2/Statements/forin-001.js | 329 + js/src/tests/ecma_2/Statements/forin-002.js | 108 + js/src/tests/ecma_2/Statements/if-001.js | 74 + js/src/tests/ecma_2/Statements/jstests.list | 31 + js/src/tests/ecma_2/Statements/label-001.js | 74 + js/src/tests/ecma_2/Statements/label-002.js | 88 + js/src/tests/ecma_2/Statements/shell.js | 0 js/src/tests/ecma_2/Statements/switch-001.js | 97 + js/src/tests/ecma_2/Statements/switch-002.js | 95 + js/src/tests/ecma_2/Statements/switch-003.js | 89 + js/src/tests/ecma_2/Statements/switch-004.js | 126 + js/src/tests/ecma_2/Statements/try-001.js | 115 + js/src/tests/ecma_2/Statements/try-003.js | 114 + js/src/tests/ecma_2/Statements/try-004.js | 86 + js/src/tests/ecma_2/Statements/try-005.js | 89 + js/src/tests/ecma_2/Statements/try-006.js | 119 + js/src/tests/ecma_2/Statements/try-007.js | 124 + js/src/tests/ecma_2/Statements/try-008.js | 91 + js/src/tests/ecma_2/Statements/try-009.js | 98 + js/src/tests/ecma_2/Statements/try-010.js | 105 + js/src/tests/ecma_2/Statements/try-012.js | 127 + js/src/tests/ecma_2/Statements/while-001.js | 74 + js/src/tests/ecma_2/Statements/while-002.js | 118 + js/src/tests/ecma_2/Statements/while-003.js | 119 + js/src/tests/ecma_2/Statements/while-004.js | 249 + js/src/tests/ecma_2/String/browser.js | 0 js/src/tests/ecma_2/String/jstests.list | 9 + js/src/tests/ecma_2/String/match-001.js | 138 + js/src/tests/ecma_2/String/match-002.js | 206 + js/src/tests/ecma_2/String/match-003.js | 164 + js/src/tests/ecma_2/String/match-004.js | 205 + js/src/tests/ecma_2/String/replace-001.js | 98 + js/src/tests/ecma_2/String/shell.js | 0 js/src/tests/ecma_2/String/split-001.js | 144 + js/src/tests/ecma_2/String/split-002.js | 302 + js/src/tests/ecma_2/String/split-003.js | 155 + js/src/tests/ecma_2/browser.js | 37 + js/src/tests/ecma_2/extensions/browser.js | 0 js/src/tests/ecma_2/extensions/constructor-001.js | 73 + js/src/tests/ecma_2/extensions/function-001.js | 73 + js/src/tests/ecma_2/extensions/instanceof-001.js | 143 + js/src/tests/ecma_2/extensions/instanceof-002.js | 159 + js/src/tests/ecma_2/extensions/instanceof-003-n.js | 120 + js/src/tests/ecma_2/extensions/instanceof-004-n.js | 120 + js/src/tests/ecma_2/extensions/instanceof-005-n.js | 121 + js/src/tests/ecma_2/extensions/instanceof-006.js | 118 + js/src/tests/ecma_2/extensions/jstests.list | 9 + js/src/tests/ecma_2/extensions/shell.js | 0 js/src/tests/ecma_2/instanceof/browser.js | 0 js/src/tests/ecma_2/instanceof/instanceof-001.js | 66 + js/src/tests/ecma_2/instanceof/instanceof-002.js | 83 + js/src/tests/ecma_2/instanceof/instanceof-003.js | 97 + js/src/tests/ecma_2/instanceof/jstests.list | 5 + js/src/tests/ecma_2/instanceof/regress-7635.js | 87 + js/src/tests/ecma_2/instanceof/shell.js | 0 js/src/tests/ecma_2/jsref.js | 591 + js/src/tests/ecma_2/jstests.list | 9 + js/src/tests/ecma_2/shell.js | 50 + js/src/tests/ecma_2/template.js | 26 + js/src/tests/ecma_3/Array/15.4.4.11-01.js | 60 + js/src/tests/ecma_3/Array/15.4.4.3-1.js | 87 + js/src/tests/ecma_3/Array/15.4.4.4-001.js | 152 + js/src/tests/ecma_3/Array/15.4.5.1-01.js | 92 + js/src/tests/ecma_3/Array/15.5.4.8-01.js | 75 + js/src/tests/ecma_3/Array/browser.js | 0 js/src/tests/ecma_3/Array/jstests.list | 18 + js/src/tests/ecma_3/Array/regress-101488.js | 171 + js/src/tests/ecma_3/Array/regress-130451.js | 218 + js/src/tests/ecma_3/Array/regress-322135-01.js | 72 + js/src/tests/ecma_3/Array/regress-322135-02.js | 64 + js/src/tests/ecma_3/Array/regress-322135-03.js | 72 + js/src/tests/ecma_3/Array/regress-322135-04.js | 70 + js/src/tests/ecma_3/Array/regress-387501.js | 82 + js/src/tests/ecma_3/Array/regress-390598.js | 72 + js/src/tests/ecma_3/Array/regress-421325.js | 66 + js/src/tests/ecma_3/Array/regress-430717.js | 64 + js/src/tests/ecma_3/Array/regress-488989.js | 67 + js/src/tests/ecma_3/Array/regress-619970.js | 8 + js/src/tests/ecma_3/Array/shell.js | 0 js/src/tests/ecma_3/Date/15.9.1.2-01.js | 61 + js/src/tests/ecma_3/Date/15.9.3.2-1.js | 60 + js/src/tests/ecma_3/Date/15.9.4.3.js | 232 + js/src/tests/ecma_3/Date/15.9.5.3.js | 151 + js/src/tests/ecma_3/Date/15.9.5.4.js | 184 + js/src/tests/ecma_3/Date/15.9.5.5-02.js | 87 + js/src/tests/ecma_3/Date/15.9.5.5.js | 143 + js/src/tests/ecma_3/Date/15.9.5.6.js | 152 + js/src/tests/ecma_3/Date/15.9.5.7.js | 141 + js/src/tests/ecma_3/Date/browser.js | 37 + js/src/tests/ecma_3/Date/jstests.list | 11 + js/src/tests/ecma_3/Date/regress-452786.js | 65 + js/src/tests/ecma_3/Date/shell.js | 563 + js/src/tests/ecma_3/Exceptions/15.11.1.1.js | 136 + js/src/tests/ecma_3/Exceptions/15.11.4.4-1.js | 173 + js/src/tests/ecma_3/Exceptions/15.11.5.js | 65 + js/src/tests/ecma_3/Exceptions/15.11.7.6-001.js | 129 + js/src/tests/ecma_3/Exceptions/15.11.7.6-002.js | 131 + js/src/tests/ecma_3/Exceptions/15.11.7.6-003.js | 131 + js/src/tests/ecma_3/Exceptions/binding-001.js | 127 + js/src/tests/ecma_3/Exceptions/browser.js | 0 js/src/tests/ecma_3/Exceptions/jstests.list | 12 + js/src/tests/ecma_3/Exceptions/regress-181654.js | 154 + js/src/tests/ecma_3/Exceptions/regress-181914.js | 193 + js/src/tests/ecma_3/Exceptions/regress-58946.js | 70 + js/src/tests/ecma_3/Exceptions/regress-95101.js | 117 + js/src/tests/ecma_3/Exceptions/shell.js | 0 js/src/tests/ecma_3/ExecutionContexts/10.1.3-1.js | 200 + js/src/tests/ecma_3/ExecutionContexts/10.1.3-2.js | 69 + js/src/tests/ecma_3/ExecutionContexts/10.1.3.js | 72 + js/src/tests/ecma_3/ExecutionContexts/10.1.4-1.js | 84 + js/src/tests/ecma_3/ExecutionContexts/10.6.1-01.js | 135 + js/src/tests/ecma_3/ExecutionContexts/browser.js | 0 js/src/tests/ecma_3/ExecutionContexts/jstests.list | 8 + .../ecma_3/ExecutionContexts/regress-23346.js | 70 + .../ecma_3/ExecutionContexts/regress-448595-01.js | 90 + js/src/tests/ecma_3/ExecutionContexts/shell.js | 0 js/src/tests/ecma_3/Expressions/11.10-01.js | 75 + js/src/tests/ecma_3/Expressions/11.10-02.js | 75 + js/src/tests/ecma_3/Expressions/11.10-03.js | 75 + js/src/tests/ecma_3/Expressions/11.6.1-1.js | 175 + js/src/tests/ecma_3/Expressions/11.7.1-01.js | 75 + js/src/tests/ecma_3/Expressions/11.7.2-01.js | 75 + js/src/tests/ecma_3/Expressions/11.7.3-01.js | 75 + js/src/tests/ecma_3/Expressions/11.9.6-1.js | 212 + js/src/tests/ecma_3/Expressions/browser.js | 0 js/src/tests/ecma_3/Expressions/jstests.list | 9 + js/src/tests/ecma_3/Expressions/shell.js | 0 js/src/tests/ecma_3/FunExpr/browser.js | 0 js/src/tests/ecma_3/FunExpr/fe-001-n.js | 57 + js/src/tests/ecma_3/FunExpr/fe-001.js | 56 + js/src/tests/ecma_3/FunExpr/fe-002.js | 60 + js/src/tests/ecma_3/FunExpr/jstests.list | 9 + js/src/tests/ecma_3/FunExpr/regress-518103.js | 27 + js/src/tests/ecma_3/FunExpr/regress-524826.js | 28 + js/src/tests/ecma_3/FunExpr/regress-528082.js | 20 + js/src/tests/ecma_3/FunExpr/regress-533254.js | 28 + js/src/tests/ecma_3/FunExpr/regress-545980.js | 41 + js/src/tests/ecma_3/FunExpr/shell.js | 0 js/src/tests/ecma_3/Function/15.3.4.3-1.js | 209 + js/src/tests/ecma_3/Function/15.3.4.4-1.js | 184 + js/src/tests/ecma_3/Function/arguments-001.js | 168 + js/src/tests/ecma_3/Function/arguments-002.js | 72 + js/src/tests/ecma_3/Function/browser.js | 0 js/src/tests/ecma_3/Function/call-001.js | 152 + js/src/tests/ecma_3/Function/jstests.list | 17 + js/src/tests/ecma_3/Function/regress-131964.js | 195 + js/src/tests/ecma_3/Function/regress-137181.js | 112 + js/src/tests/ecma_3/Function/regress-193555.js | 135 + js/src/tests/ecma_3/Function/regress-313570.js | 62 + js/src/tests/ecma_3/Function/regress-49286.js | 136 + js/src/tests/ecma_3/Function/regress-58274.js | 225 + js/src/tests/ecma_3/Function/regress-85880.js | 172 + js/src/tests/ecma_3/Function/regress-94506.js | 162 + js/src/tests/ecma_3/Function/regress-97921.js | 151 + js/src/tests/ecma_3/Function/scope-001.js | 264 + js/src/tests/ecma_3/Function/scope-002.js | 244 + js/src/tests/ecma_3/Function/shell.js | 0 js/src/tests/ecma_3/LexicalConventions/7.4-01.js | 72 + js/src/tests/ecma_3/LexicalConventions/7.8.3-01.js | 23 + js/src/tests/ecma_3/LexicalConventions/7.9.1.js | 156 + js/src/tests/ecma_3/LexicalConventions/browser.js | 0 .../tests/ecma_3/LexicalConventions/jstests.list | 4 + js/src/tests/ecma_3/LexicalConventions/shell.js | 0 js/src/tests/ecma_3/Number/15.7.4.2-01.js | 76 + js/src/tests/ecma_3/Number/15.7.4.3-01.js | 68 + js/src/tests/ecma_3/Number/15.7.4.3-02.js | 52 + js/src/tests/ecma_3/Number/15.7.4.5-1.js | 144 + js/src/tests/ecma_3/Number/15.7.4.5-2.js | 61 + js/src/tests/ecma_3/Number/15.7.4.6-1.js | 148 + js/src/tests/ecma_3/Number/15.7.4.7-1.js | 153 + js/src/tests/ecma_3/Number/15.7.4.7-2.js | 71 + js/src/tests/ecma_3/Number/browser.js | 0 js/src/tests/ecma_3/Number/jstests.list | 10 + js/src/tests/ecma_3/Number/regress-442242-01.js | 61 + js/src/tests/ecma_3/Number/shell.js | 0 js/src/tests/ecma_3/NumberFormatting/browser.js | 0 js/src/tests/ecma_3/NumberFormatting/jstests.list | 2 + js/src/tests/ecma_3/NumberFormatting/shell.js | 0 .../tests/ecma_3/NumberFormatting/tostring-001.js | 59 + js/src/tests/ecma_3/Object/8.6.1-01.js | 112 + js/src/tests/ecma_3/Object/8.6.2.6-001.js | 112 + js/src/tests/ecma_3/Object/8.6.2.6-002.js | 78 + js/src/tests/ecma_3/Object/browser.js | 7 + js/src/tests/ecma_3/Object/class-001.js | 155 + js/src/tests/ecma_3/Object/class-002.js | 145 + js/src/tests/ecma_3/Object/class-003.js | 138 + js/src/tests/ecma_3/Object/class-004.js | 138 + js/src/tests/ecma_3/Object/class-005.js | 123 + js/src/tests/ecma_3/Object/jstests.list | 14 + js/src/tests/ecma_3/Object/regress-361274.js | 65 + js/src/tests/ecma_3/Object/regress-385393-07.js | 66 + js/src/tests/ecma_3/Object/regress-459405.js | 40 + js/src/tests/ecma_3/Object/regress-72773.js | 96 + js/src/tests/ecma_3/Object/regress-79129-001.js | 79 + js/src/tests/ecma_3/Object/shell.js | 104 + js/src/tests/ecma_3/Operators/11.13.1-001.js | 151 + js/src/tests/ecma_3/Operators/11.13.1-002.js | 56 + js/src/tests/ecma_3/Operators/11.4.1-001.js | 119 + js/src/tests/ecma_3/Operators/11.4.1-002.js | 71 + js/src/tests/ecma_3/Operators/browser.js | 0 js/src/tests/ecma_3/Operators/jstests.list | 6 + js/src/tests/ecma_3/Operators/order-01.js | 107 + js/src/tests/ecma_3/Operators/shell.js | 0 js/src/tests/ecma_3/README | 1 + js/src/tests/ecma_3/RegExp/15.10.2-1.js | 180 + js/src/tests/ecma_3/RegExp/15.10.2.12.js | 62 + js/src/tests/ecma_3/RegExp/15.10.3.1-1.js | 135 + js/src/tests/ecma_3/RegExp/15.10.3.1-2.js | 143 + js/src/tests/ecma_3/RegExp/15.10.4.1-1.js | 126 + js/src/tests/ecma_3/RegExp/15.10.4.1-2.js | 132 + js/src/tests/ecma_3/RegExp/15.10.4.1-3.js | 138 + js/src/tests/ecma_3/RegExp/15.10.4.1-4.js | 145 + js/src/tests/ecma_3/RegExp/15.10.4.1-5-n.js | 138 + js/src/tests/ecma_3/RegExp/15.10.4.1-6.js | 94 + js/src/tests/ecma_3/RegExp/15.10.6.2-1.js | 139 + js/src/tests/ecma_3/RegExp/15.10.6.2-2.js | 366 + js/src/tests/ecma_3/RegExp/browser.js | 0 js/src/tests/ecma_3/RegExp/jstests.list | 69 + js/src/tests/ecma_3/RegExp/octal-001.js | 135 + js/src/tests/ecma_3/RegExp/octal-002.js | 217 + js/src/tests/ecma_3/RegExp/perlstress-001.js | 3229 + js/src/tests/ecma_3/RegExp/perlstress-002.js | 1841 + js/src/tests/ecma_3/RegExp/regress-100199.js | 306 + js/src/tests/ecma_3/RegExp/regress-105972.js | 156 + js/src/tests/ecma_3/RegExp/regress-119909.js | 91 + js/src/tests/ecma_3/RegExp/regress-122076.js | 109 + js/src/tests/ecma_3/RegExp/regress-123437.js | 111 + js/src/tests/ecma_3/RegExp/regress-165353.js | 121 + js/src/tests/ecma_3/RegExp/regress-169497.js | 104 + js/src/tests/ecma_3/RegExp/regress-169534.js | 94 + js/src/tests/ecma_3/RegExp/regress-187133.js | 141 + js/src/tests/ecma_3/RegExp/regress-188206.js | 218 + js/src/tests/ecma_3/RegExp/regress-191479.js | 197 + js/src/tests/ecma_3/RegExp/regress-202564.js | 100 + js/src/tests/ecma_3/RegExp/regress-209067.js | 1105 + js/src/tests/ecma_3/RegExp/regress-209919.js | 173 + js/src/tests/ecma_3/RegExp/regress-216591.js | 116 + js/src/tests/ecma_3/RegExp/regress-220367-001.js | 103 + js/src/tests/ecma_3/RegExp/regress-223273.js | 278 + js/src/tests/ecma_3/RegExp/regress-223535.js | 132 + js/src/tests/ecma_3/RegExp/regress-224676.js | 225 + js/src/tests/ecma_3/RegExp/regress-225289.js | 175 + js/src/tests/ecma_3/RegExp/regress-225343.js | 124 + js/src/tests/ecma_3/RegExp/regress-24712.js | 58 + js/src/tests/ecma_3/RegExp/regress-285219.js | 50 + js/src/tests/ecma_3/RegExp/regress-28686.js | 56 + js/src/tests/ecma_3/RegExp/regress-289669.js | 87 + js/src/tests/ecma_3/RegExp/regress-307456.js | 53 + js/src/tests/ecma_3/RegExp/regress-309840.js | 57 + js/src/tests/ecma_3/RegExp/regress-311414.js | 100 + js/src/tests/ecma_3/RegExp/regress-312351.js | 49 + js/src/tests/ecma_3/RegExp/regress-31316.js | 95 + js/src/tests/ecma_3/RegExp/regress-330684.js | 52 + js/src/tests/ecma_3/RegExp/regress-334158.js | 57 + js/src/tests/ecma_3/RegExp/regress-346090.js | 62 + js/src/tests/ecma_3/RegExp/regress-367888.js | 61 + js/src/tests/ecma_3/RegExp/regress-375642.js | 60 + js/src/tests/ecma_3/RegExp/regress-375651.js | 61 + js/src/tests/ecma_3/RegExp/regress-375711.js | 117 + js/src/tests/ecma_3/RegExp/regress-375715-01-n.js | 62 + js/src/tests/ecma_3/RegExp/regress-375715-02.js | 59 + js/src/tests/ecma_3/RegExp/regress-375715-03.js | 59 + js/src/tests/ecma_3/RegExp/regress-375715-04.js | 67 + js/src/tests/ecma_3/RegExp/regress-436700.js | 66 + js/src/tests/ecma_3/RegExp/regress-465862.js | 116 + js/src/tests/ecma_3/RegExp/regress-57572.js | 149 + js/src/tests/ecma_3/RegExp/regress-57631.js | 151 + js/src/tests/ecma_3/RegExp/regress-67773.js | 210 + js/src/tests/ecma_3/RegExp/regress-72964.js | 120 + js/src/tests/ecma_3/RegExp/regress-76683.js | 113 + js/src/tests/ecma_3/RegExp/regress-78156.js | 122 + js/src/tests/ecma_3/RegExp/regress-85721.js | 275 + js/src/tests/ecma_3/RegExp/regress-87231.js | 144 + js/src/tests/ecma_3/RegExp/regress-98306.js | 98 + js/src/tests/ecma_3/RegExp/shell.js | 265 + js/src/tests/ecma_3/Regress/browser.js | 0 js/src/tests/ecma_3/Regress/jstests.list | 8 + js/src/tests/ecma_3/Regress/regress-385393-04.js | 65 + js/src/tests/ecma_3/Regress/regress-419152.js | 89 + js/src/tests/ecma_3/Regress/regress-420087.js | 63 + js/src/tests/ecma_3/Regress/regress-420610.js | 49 + js/src/tests/ecma_3/Regress/regress-441477-01.js | 42 + js/src/tests/ecma_3/Regress/regress-469937.js | 59 + js/src/tests/ecma_3/Regress/regress-580544.js | 30 + js/src/tests/ecma_3/Regress/shell.js | 0 js/src/tests/ecma_3/Statements/12.10-01.js | 67 + js/src/tests/ecma_3/Statements/12.6.3.js | 79 + js/src/tests/ecma_3/Statements/browser.js | 0 js/src/tests/ecma_3/Statements/jstests.list | 18 + js/src/tests/ecma_3/Statements/regress-121744.js | 216 + js/src/tests/ecma_3/Statements/regress-131348.js | 183 + js/src/tests/ecma_3/Statements/regress-157509.js | 110 + js/src/tests/ecma_3/Statements/regress-194364.js | 151 + js/src/tests/ecma_3/Statements/regress-226517.js | 111 + js/src/tests/ecma_3/Statements/regress-302439.js | 1367 + js/src/tests/ecma_3/Statements/regress-324650.js | 5460 ++ js/src/tests/ecma_3/Statements/regress-444979.js | 76 + .../tests/ecma_3/Statements/regress-74474-001.js | 138 + .../tests/ecma_3/Statements/regress-74474-002.js | 9096 +++ .../tests/ecma_3/Statements/regress-74474-003.js | 9098 +++ .../tests/ecma_3/Statements/regress-83532-001.js | 70 + .../tests/ecma_3/Statements/regress-83532-002.js | 73 + js/src/tests/ecma_3/Statements/shell.js | 0 js/src/tests/ecma_3/Statements/switch-001.js | 142 + js/src/tests/ecma_3/Statements/switch-002.js | 19 + js/src/tests/ecma_3/String/15.5.4.11.js | 531 + js/src/tests/ecma_3/String/15.5.4.14.js | 49 + js/src/tests/ecma_3/String/browser.js | 0 js/src/tests/ecma_3/String/jstests.list | 9 + js/src/tests/ecma_3/String/regress-104375.js | 115 + js/src/tests/ecma_3/String/regress-189898.js | 156 + js/src/tests/ecma_3/String/regress-304376.js | 67 + js/src/tests/ecma_3/String/regress-313567.js | 55 + js/src/tests/ecma_3/String/regress-392378.js | 76 + js/src/tests/ecma_3/String/regress-83293.js | 215 + js/src/tests/ecma_3/String/shell.js | 0 js/src/tests/ecma_3/Unicode/browser.js | 0 js/src/tests/ecma_3/Unicode/jstests.list | 10 + js/src/tests/ecma_3/Unicode/regress-352044-01.js | 71 + js/src/tests/ecma_3/Unicode/regress-352044-02-n.js | 71 + js/src/tests/ecma_3/Unicode/shell.js | 0 js/src/tests/ecma_3/Unicode/uc-001-n.js | 61 + js/src/tests/ecma_3/Unicode/uc-001.js | 55 + js/src/tests/ecma_3/Unicode/uc-002-n.js | 54 + js/src/tests/ecma_3/Unicode/uc-002.js | 59 + js/src/tests/ecma_3/Unicode/uc-003.js | 70 + js/src/tests/ecma_3/Unicode/uc-004.js | 64 + js/src/tests/ecma_3/Unicode/uc-005.js | 275 + js/src/tests/ecma_3/browser.js | 36 + js/src/tests/ecma_3/extensions/10.1.3-2.js | 161 + js/src/tests/ecma_3/extensions/7.9.1.js | 82 + js/src/tests/ecma_3/extensions/browser.js | 0 js/src/tests/ecma_3/extensions/jstests.list | 15 + js/src/tests/ecma_3/extensions/regress-103087.js | 177 + .../tests/ecma_3/extensions/regress-188206-01.js | 107 + .../tests/ecma_3/extensions/regress-188206-02.js | 157 + .../tests/ecma_3/extensions/regress-220367-002.js | 111 + js/src/tests/ecma_3/extensions/regress-228087.js | 351 + js/src/tests/ecma_3/extensions/regress-274152.js | 82 + js/src/tests/ecma_3/extensions/regress-320854.js | 52 + js/src/tests/ecma_3/extensions/regress-327170.js | 57 + js/src/tests/ecma_3/extensions/regress-368516.js | 77 + .../tests/ecma_3/extensions/regress-385393-03.js | 62 + js/src/tests/ecma_3/extensions/regress-429248.js | 67 + js/src/tests/ecma_3/extensions/regress-430740.js | 71 + js/src/tests/ecma_3/extensions/shell.js | 265 + js/src/tests/ecma_3/jstests.list | 18 + js/src/tests/ecma_3/shell.js | 39 + js/src/tests/ecma_3/template.js | 28 + js/src/tests/ecma_3_1/Object/browser.js | 0 js/src/tests/ecma_3_1/Object/jstests.list | 2 + js/src/tests/ecma_3_1/Object/regress-444787.js | 154 + js/src/tests/ecma_3_1/Object/shell.js | 0 js/src/tests/ecma_3_1/README | 1 + js/src/tests/ecma_3_1/RegExp/browser.js | 0 js/src/tests/ecma_3_1/RegExp/jstests.list | 2 + js/src/tests/ecma_3_1/RegExp/regress-305064.js | 91 + js/src/tests/ecma_3_1/RegExp/shell.js | 0 js/src/tests/ecma_3_1/browser.js | 36 + js/src/tests/ecma_3_1/extensions/browser.js | 0 js/src/tests/ecma_3_1/extensions/jstests.list | 1 + js/src/tests/ecma_3_1/extensions/shell.js | 0 js/src/tests/ecma_3_1/jstests.list | 3 + js/src/tests/ecma_3_1/shell.js | 39 + js/src/tests/ecma_3_1/template.js | 28 + js/src/tests/ecma_5/Array/browser.js | 1 + js/src/tests/ecma_5/Array/jstests.list | 7 + js/src/tests/ecma_5/Array/length-01.js | 71 + js/src/tests/ecma_5/Array/regress-599159.js | 10 + js/src/tests/ecma_5/Array/shell.js | 0 js/src/tests/ecma_5/Array/sort-01.js | 23 + js/src/tests/ecma_5/Array/toLocaleString-01.js | 30 + js/src/tests/ecma_5/Array/toString-01.js | 52 + js/src/tests/ecma_5/Array/unshift-01.js | 41 + js/src/tests/ecma_5/Boolean/15.6.4.2.js | 17 + js/src/tests/ecma_5/Boolean/browser.js | 0 js/src/tests/ecma_5/Boolean/jstests.list | 2 + js/src/tests/ecma_5/Boolean/shell.js | 0 js/src/tests/ecma_5/Date/15.9.4.2.js | 157 + js/src/tests/ecma_5/Date/browser.js | 0 js/src/tests/ecma_5/Date/jstests.list | 3 + js/src/tests/ecma_5/Date/shell.js | 0 js/src/tests/ecma_5/Date/toJSON-01.js | 238 + js/src/tests/ecma_5/Expressions/11.1.5-01.js | 37 + js/src/tests/ecma_5/Expressions/browser.js | 0 js/src/tests/ecma_5/Expressions/jstests.list | 5 + .../ecma_5/Expressions/named-accessor-function.js | 49 + .../Expressions/nested-delete-name-in-evalcode.js | 163 + .../object-literal-accessor-arguments.js | 42 + js/src/tests/ecma_5/Expressions/shell.js | 7 + js/src/tests/ecma_5/Function/10.2.1.1.6.js | 35 + js/src/tests/ecma_5/Function/15.3.4.3-01.js | 245 + .../tests/ecma_5/Function/Function-arguments-gc.js | 39 + .../ecma_5/Function/arguments-caller-callee.js | 66 + .../Function/arguments-property-attributes.js | 102 + js/src/tests/ecma_5/Function/browser.js | 1 + .../tests/ecma_5/Function/builtin-no-prototype.js | 40 + js/src/tests/ecma_5/Function/function-bind.js | 282 + js/src/tests/ecma_5/Function/function-call.js | 134 + js/src/tests/ecma_5/Function/function-caller.js | 76 + js/src/tests/ecma_5/Function/jstests.list | 12 + .../ecma_5/Function/redefine-arguments-length.js | 65 + js/src/tests/ecma_5/Function/shell.js | 0 js/src/tests/ecma_5/Function/strict-arguments.js | 382 + .../adding-global-var-nonextensible-error.js | 35 + js/src/tests/ecma_5/Global/browser.js | 1 + js/src/tests/ecma_5/Global/direct-eval-but-not.js | 32 + js/src/tests/ecma_5/Global/eval-01.js | 38 + js/src/tests/ecma_5/Global/eval-02.js | 38 + .../eval-in-strict-eval-in-normal-function.js | 30 + .../ecma_5/Global/eval-inside-with-is-direct.js | 28 + .../Global/eval-native-callback-is-indirect.js | 32 + js/src/tests/ecma_5/Global/jstests.list | 11 + .../ecma_5/Global/parenthesized-eval-is-direct.js | 68 + js/src/tests/ecma_5/Global/parseFloat-01.js | 24 + js/src/tests/ecma_5/Global/parseInt-01.js | 170 + js/src/tests/ecma_5/Global/shell.js | 0 js/src/tests/ecma_5/JSON/browser.js | 1 + js/src/tests/ecma_5/JSON/cyclic-stringify.js | 100 + js/src/tests/ecma_5/JSON/jstests.list | 5 + js/src/tests/ecma_5/JSON/shell.js | 29 + js/src/tests/ecma_5/JSON/small-codepoints.js | 16 + js/src/tests/ecma_5/JSON/stringify-gap.js | 52 + js/src/tests/ecma_5/JSON/trailing-comma.js | 32 + js/src/tests/ecma_5/Number/15.7.4.2.js | 31 + js/src/tests/ecma_5/Number/browser.js | 0 js/src/tests/ecma_5/Number/jstests.list | 2 + js/src/tests/ecma_5/Number/shell.js | 0 js/src/tests/ecma_5/Object/15.2.3.12.js | 46 + js/src/tests/ecma_5/Object/15.2.3.14-01.js | 92 + js/src/tests/ecma_5/Object/15.2.3.3-01.js | 342 + js/src/tests/ecma_5/Object/15.2.3.4-01.js | 30 + js/src/tests/ecma_5/Object/15.2.3.4-02.js | 52 + js/src/tests/ecma_5/Object/15.2.3.4-03.js | 55 + js/src/tests/ecma_5/Object/15.2.3.4-04.js | 31 + js/src/tests/ecma_5/Object/15.2.3.5-01.js | 60 + .../ecma_5/Object/15.2.3.6-define-over-method.js | 24 + .../15.2.3.6-dictionary-redefinition-1-of-8.js | 5 + .../15.2.3.6-dictionary-redefinition-2-of-8.js | 5 + .../15.2.3.6-dictionary-redefinition-3-of-8.js | 5 + .../15.2.3.6-dictionary-redefinition-4-of-8.js | 5 + .../15.2.3.6-dictionary-redefinition-5-of-8.js | 5 + .../15.2.3.6-dictionary-redefinition-6-of-8.js | 5 + .../15.2.3.6-dictionary-redefinition-7-of-8.js | 5 + .../15.2.3.6-dictionary-redefinition-8-of-8.js | 5 + .../ecma_5/Object/15.2.3.6-function-length.js | 34 + .../Object/15.2.3.6-middle-redefinition-1-of-8.js | 5 + .../Object/15.2.3.6-middle-redefinition-2-of-8.js | 5 + .../Object/15.2.3.6-middle-redefinition-3-of-8.js | 5 + .../Object/15.2.3.6-middle-redefinition-4-of-8.js | 5 + .../Object/15.2.3.6-middle-redefinition-5-of-8.js | 5 + .../Object/15.2.3.6-middle-redefinition-6-of-8.js | 5 + .../Object/15.2.3.6-middle-redefinition-7-of-8.js | 5 + .../Object/15.2.3.6-middle-redefinition-8-of-8.js | 5 + .../tests/ecma_5/Object/15.2.3.6-miscellaneous.js | 74 + .../tests/ecma_5/Object/15.2.3.6-new-definition.js | 34 + .../ecma_5/Object/15.2.3.6-redefinition-1-of-4.js | 38 + .../ecma_5/Object/15.2.3.6-redefinition-2-of-4.js | 38 + .../ecma_5/Object/15.2.3.6-redefinition-3-of-4.js | 38 + .../ecma_5/Object/15.2.3.6-redefinition-4-of-4.js | 38 + js/src/tests/ecma_5/Object/15.2.3.7-01.js | 137 + js/src/tests/ecma_5/Object/15.2.3.9.js | 51 + .../ecma_5/Object/add-property-non-extensible.js | 118 + js/src/tests/ecma_5/Object/browser.js | 1 + js/src/tests/ecma_5/Object/defineProperty-setup.js | 1098 + js/src/tests/ecma_5/Object/extensibility-01.js | 103 + js/src/tests/ecma_5/Object/extensibility-02.js | 42 + .../ecma_5/Object/freeze-global-eval-const.js | 12 + js/src/tests/ecma_5/Object/isPrototypeOf.js | 86 + js/src/tests/ecma_5/Object/jstests.list | 46 + .../ecma_5/Object/mutation-prevention-methods.js | 124 + js/src/tests/ecma_5/Object/object-toString-01.js | 46 + .../ecma_5/Object/preventExtensions-idempotent.js | 30 + js/src/tests/ecma_5/Object/propertyIsEnumerable.js | 199 + js/src/tests/ecma_5/Object/shell.js | 0 .../Object/vacuous-accessor-unqualified-name.js | 26 + js/src/tests/ecma_5/README | 1 + js/src/tests/ecma_5/RegExp/15.10.5-01.js | 21 + js/src/tests/ecma_5/RegExp/15.10.7.5-01.js | 71 + js/src/tests/ecma_5/RegExp/7.8.5-01.js | 35 + js/src/tests/ecma_5/RegExp/browser.js | 1 + js/src/tests/ecma_5/RegExp/empty-lookahead.js | 8 + js/src/tests/ecma_5/RegExp/jstests.list | 6 + js/src/tests/ecma_5/RegExp/regress-617935.js | 38 + js/src/tests/ecma_5/RegExp/shell.js | 0 js/src/tests/ecma_5/String/15.5.4.11-01.js | 66 + js/src/tests/ecma_5/String/15.5.4.2.js | 14 + js/src/tests/ecma_5/String/15.5.4.7.js | 20 + js/src/tests/ecma_5/String/browser.js | 1 + js/src/tests/ecma_5/String/jstests.list | 4 + js/src/tests/ecma_5/String/shell.js | 0 js/src/tests/ecma_5/Types/8.12.5-01.js | 110 + js/src/tests/ecma_5/Types/browser.js | 1 + js/src/tests/ecma_5/Types/jstests.list | 2 + js/src/tests/ecma_5/Types/shell.js | 0 js/src/tests/ecma_5/browser.js | 36 + js/src/tests/ecma_5/eval/browser.js | 1 + ...xhaustive-fun-normalcaller-direct-normalcode.js | 208 + ...xhaustive-fun-normalcaller-direct-strictcode.js | 210 + ...austive-fun-normalcaller-indirect-normalcode.js | 208 + ...austive-fun-normalcaller-indirect-strictcode.js | 210 + ...xhaustive-fun-strictcaller-direct-normalcode.js | 212 + ...xhaustive-fun-strictcaller-direct-strictcode.js | 214 + ...austive-fun-strictcaller-indirect-normalcode.js | 212 + ...austive-fun-strictcaller-indirect-strictcode.js | 214 + ...ustive-global-normalcaller-direct-normalcode.js | 172 + ...ustive-global-normalcaller-direct-strictcode.js | 174 + ...tive-global-normalcaller-indirect-normalcode.js | 172 + ...tive-global-normalcaller-indirect-strictcode.js | 174 + ...ustive-global-strictcaller-direct-normalcode.js | 173 + ...ustive-global-strictcaller-direct-strictcode.js | 175 + ...tive-global-strictcaller-indirect-normalcode.js | 173 + ...tive-global-strictcaller-indirect-strictcode.js | 175 + js/src/tests/ecma_5/eval/jstests.list | 48 + js/src/tests/ecma_5/eval/shell.js | 0 .../eval/undeclared-name-in-nested-strict-eval.js | 26 + js/src/tests/ecma_5/extensions/15.4.4.11.js | 32 + js/src/tests/ecma_5/extensions/8.12.5-01.js | 97 + js/src/tests/ecma_5/extensions/Boolean-toSource.js | 17 + js/src/tests/ecma_5/extensions/Number-toSource.js | 17 + .../extensions/Object-keys-and-object-ids.js | 12 + js/src/tests/ecma_5/extensions/String-toSource.js | 14 + js/src/tests/ecma_5/extensions/browser.js | 1 + js/src/tests/ecma_5/extensions/bug352085.js | 17 + js/src/tests/ecma_5/extensions/bug472534.js | 30 + js/src/tests/ecma_5/extensions/bug496985.js | 12 + js/src/tests/ecma_5/extensions/bug566661.js | 6 + .../extensions/eval-native-callback-is-indirect.js | 43 + ...extension-methods-reject-null-undefined-this.js | 112 + .../ecma_5/extensions/function-definition-with.js | 52 + .../tests/ecma_5/extensions/iterator-in-catch.js | 20 + js/src/tests/ecma_5/extensions/jstests.list | 30 + .../extensions/nested-delete-name-in-evalcode.js | 98 + js/src/tests/ecma_5/extensions/proxy-strict.js | 12 + .../tests/ecma_5/extensions/regress-bug567606.js | 19 + .../tests/ecma_5/extensions/regress-bug607284.js | 16 + .../tests/ecma_5/extensions/regress-bug629723.js | 16 + js/src/tests/ecma_5/extensions/shell.js | 0 .../extensions/strict-function-statements.js | 100 + .../strict-option-redeclared-parameter.js | 30 + .../string-literal-getter-setter-decompilation.js | 34 + .../ecma_5/extensions/uneval-strict-functions.js | 61 + .../tests/ecma_5/extensions/watch-array-length.js | 41 + .../ecma_5/extensions/watch-inherited-property.js | 38 + .../ecma_5/extensions/watch-replaced-setter.js | 46 + .../extensions/watch-setter-become-setter.js | 44 + .../extensions/watch-value-prop-becoming-setter.js | 43 + .../watchpoint-deletes-JSPropertyOp-setter.js | 56 + js/src/tests/ecma_5/jstests.list | 16 + js/src/tests/ecma_5/misc/browser.js | 1 + .../builtin-methods-reject-null-undefined-this.js | 153 + js/src/tests/ecma_5/misc/enumerate-undefined.js | 24 + .../misc/explicit-undefined-optional-argument.js | 34 + .../tests/ecma_5/misc/function-definition-eval.js | 343 + .../ecma_5/misc/function-definition-evaluate.js | 343 + js/src/tests/ecma_5/misc/future-reserved-words.js | 505 + .../tests/ecma_5/misc/global-numeric-properties.js | 59 + js/src/tests/ecma_5/misc/jstests.list | 11 + .../misc/redeclare-var-non-writable-property.js | 24 + js/src/tests/ecma_5/misc/regress-bug632003.js | 63 + js/src/tests/ecma_5/misc/shell.js | 0 .../tests/ecma_5/misc/unwrapped-no-such-method.js | 13 + js/src/tests/ecma_5/shell.js | 154 + js/src/tests/ecma_5/strict/10.4.2.js | 55 + js/src/tests/ecma_5/strict/10.4.3.js | 58 + js/src/tests/ecma_5/strict/10.6.js | 55 + js/src/tests/ecma_5/strict/11.1.5.js | 171 + js/src/tests/ecma_5/strict/11.13.1.js | 29 + js/src/tests/ecma_5/strict/11.13.2.js | 29 + js/src/tests/ecma_5/strict/11.3.1.js | 29 + js/src/tests/ecma_5/strict/11.3.2.js | 29 + js/src/tests/ecma_5/strict/11.4.1.js | 41 + js/src/tests/ecma_5/strict/11.4.4.js | 29 + js/src/tests/ecma_5/strict/11.4.5.js | 29 + js/src/tests/ecma_5/strict/12.10.1.js | 30 + js/src/tests/ecma_5/strict/12.14.1.js | 37 + js/src/tests/ecma_5/strict/12.2.1.js | 25 + js/src/tests/ecma_5/strict/13.1.js | 345 + js/src/tests/ecma_5/strict/15.10.7.js | 43 + js/src/tests/ecma_5/strict/15.3.4.5.js | 26 + js/src/tests/ecma_5/strict/15.3.5.1.js | 19 + js/src/tests/ecma_5/strict/15.3.5.2.js | 16 + js/src/tests/ecma_5/strict/15.4.4.12.js | 50 + js/src/tests/ecma_5/strict/15.4.4.13.js | 50 + js/src/tests/ecma_5/strict/15.4.4.6.js | 28 + js/src/tests/ecma_5/strict/15.4.4.8.js | 50 + js/src/tests/ecma_5/strict/15.4.4.9.js | 50 + js/src/tests/ecma_5/strict/15.4.5.1.js | 30 + js/src/tests/ecma_5/strict/15.5.5.1.js | 26 + js/src/tests/ecma_5/strict/15.5.5.2.js | 15 + js/src/tests/ecma_5/strict/8.12.5.js | 82 + js/src/tests/ecma_5/strict/8.12.7.js | 32 + js/src/tests/ecma_5/strict/8.7.2.js | 56 + js/src/tests/ecma_5/strict/B.1.1.js | 31 + js/src/tests/ecma_5/strict/B.1.2.js | 38 + .../tests/ecma_5/strict/assign-to-callee-name.js | 42 + js/src/tests/ecma_5/strict/browser.js | 0 .../tests/ecma_5/strict/directive-prologue-01.js | 78 + .../ecma_5/strict/eval-variable-environment.js | 67 + js/src/tests/ecma_5/strict/function-name-arity.js | 26 + js/src/tests/ecma_5/strict/jstests.list | 44 + .../ecma_5/strict/primitive-this-no-writeback.js | 20 + js/src/tests/ecma_5/strict/regress-532041.js | 17 + js/src/tests/ecma_5/strict/regress-532254.js | 13 + js/src/tests/ecma_5/strict/regress-599159.js | 33 + js/src/tests/ecma_5/strict/shell.js | 0 .../ecma_5/strict/strict-this-is-not-truthy.js | 12 + .../this-for-function-expression-recursion.js | 44 + js/src/tests/ecma_5/strict/unbrand-this.js | 45 + js/src/tests/ecma_5/template.js | 28 + js/src/tests/get-universe.sh | 52 + js/src/tests/importList.html | 22 + js/src/tests/importList.js | 94 + js/src/tests/js-test-driver-begin.js | 1 + js/src/tests/js-test-driver-end.js | 3 + js/src/tests/js-test-driver-quirks.html | 23 + js/src/tests/js-test-driver-standards.html | 23 + js/src/tests/js1_1/README | 1 + js/src/tests/js1_1/browser.js | 37 + js/src/tests/js1_1/jsref.js | 167 + js/src/tests/js1_1/jstests.list | 1 + js/src/tests/js1_1/regress/browser.js | 0 js/src/tests/js1_1/regress/function-001.js | 78 + js/src/tests/js1_1/regress/jstests.list | 2 + js/src/tests/js1_1/regress/shell.js | 0 js/src/tests/js1_1/shell.js | 38 + js/src/tests/js1_2/Array/array_split_1.js | 85 + js/src/tests/js1_2/Array/browser.js | 0 js/src/tests/js1_2/Array/general1.js | 77 + js/src/tests/js1_2/Array/general2.js | 92 + js/src/tests/js1_2/Array/jstests.list | 9 + js/src/tests/js1_2/Array/shell.js | 0 js/src/tests/js1_2/Array/slice.js | 122 + js/src/tests/js1_2/Array/splice1.js | 152 + js/src/tests/js1_2/Array/splice2.js | 149 + js/src/tests/js1_2/Array/tostring_1.js | 125 + js/src/tests/js1_2/Array/tostring_2.js | 81 + js/src/tests/js1_2/Objects/browser.js | 0 js/src/tests/js1_2/Objects/jstests.list | 2 + js/src/tests/js1_2/Objects/shell.js | 0 js/src/tests/js1_2/Objects/toString-001.js | 119 + js/src/tests/js1_2/README | 1 + js/src/tests/js1_2/String/browser.js | 0 js/src/tests/js1_2/String/charCodeAt.js | 71 + js/src/tests/js1_2/String/concat.js | 82 + js/src/tests/js1_2/String/jstests.list | 5 + js/src/tests/js1_2/String/match.js | 62 + js/src/tests/js1_2/String/shell.js | 0 js/src/tests/js1_2/String/slice.js | 123 + js/src/tests/js1_2/browser.js | 37 + js/src/tests/js1_2/function/Function_object.js | 86 + js/src/tests/js1_2/function/Number.js | 84 + js/src/tests/js1_2/function/String.js | 72 + js/src/tests/js1_2/function/browser.js | 0 js/src/tests/js1_2/function/definition-1.js | 76 + js/src/tests/js1_2/function/function-001-n.js | 76 + js/src/tests/js1_2/function/jstests.list | 13 + js/src/tests/js1_2/function/length.js | 95 + js/src/tests/js1_2/function/nesting-1.js | 64 + js/src/tests/js1_2/function/nesting.js | 83 + js/src/tests/js1_2/function/regexparg-1.js | 104 + js/src/tests/js1_2/function/regexparg-2-n.js | 72 + js/src/tests/js1_2/function/shell.js | 0 js/src/tests/js1_2/function/tostring-1.js | 144 + js/src/tests/js1_2/function/tostring-2.js | 187 + js/src/tests/js1_2/jsref.js | 228 + js/src/tests/js1_2/jstests.list | 9 + js/src/tests/js1_2/operator/browser.js | 0 js/src/tests/js1_2/operator/equality.js | 71 + js/src/tests/js1_2/operator/jstests.list | 3 + js/src/tests/js1_2/operator/shell.js | 0 js/src/tests/js1_2/operator/strictEquality.js | 92 + js/src/tests/js1_2/regexp/RegExp_dollar_number.js | 110 + js/src/tests/js1_2/regexp/RegExp_input.js | 103 + js/src/tests/js1_2/regexp/RegExp_input_as_array.js | 103 + js/src/tests/js1_2/regexp/RegExp_lastIndex.js | 84 + js/src/tests/js1_2/regexp/RegExp_lastMatch.js | 87 + .../js1_2/regexp/RegExp_lastMatch_as_array.js | 87 + js/src/tests/js1_2/regexp/RegExp_lastParen.js | 101 + .../js1_2/regexp/RegExp_lastParen_as_array.js | 101 + js/src/tests/js1_2/regexp/RegExp_leftContext.js | 91 + .../js1_2/regexp/RegExp_leftContext_as_array.js | 91 + js/src/tests/js1_2/regexp/RegExp_multiline.js | 130 + .../js1_2/regexp/RegExp_multiline_as_array.js | 131 + js/src/tests/js1_2/regexp/RegExp_object.js | 89 + js/src/tests/js1_2/regexp/RegExp_rightContext.js | 91 + .../js1_2/regexp/RegExp_rightContext_as_array.js | 91 + js/src/tests/js1_2/regexp/alphanumeric.js | 130 + js/src/tests/js1_2/regexp/asterisk.js | 106 + js/src/tests/js1_2/regexp/backslash.js | 80 + js/src/tests/js1_2/regexp/backspace.js | 80 + js/src/tests/js1_2/regexp/beginLine.js | 82 + js/src/tests/js1_2/regexp/browser.js | 0 js/src/tests/js1_2/regexp/character_class.js | 109 + js/src/tests/js1_2/regexp/compile.js | 95 + js/src/tests/js1_2/regexp/control_characters.js | 73 + js/src/tests/js1_2/regexp/digit.js | 119 + js/src/tests/js1_2/regexp/dot.js | 97 + js/src/tests/js1_2/regexp/endLine.js | 82 + js/src/tests/js1_2/regexp/everything.js | 82 + js/src/tests/js1_2/regexp/exec.js | 78 + js/src/tests/js1_2/regexp/flags.js | 86 + js/src/tests/js1_2/regexp/global.js | 96 + js/src/tests/js1_2/regexp/hexadecimal.js | 108 + js/src/tests/js1_2/regexp/ignoreCase.js | 113 + js/src/tests/js1_2/regexp/interval.js | 116 + js/src/tests/js1_2/regexp/jstests.list | 51 + js/src/tests/js1_2/regexp/octal.js | 108 + js/src/tests/js1_2/regexp/parentheses.js | 108 + js/src/tests/js1_2/regexp/plus.js | 88 + js/src/tests/js1_2/regexp/question_mark.js | 100 + js/src/tests/js1_2/regexp/regress-6359.js | 85 + js/src/tests/js1_2/regexp/regress-9141.js | 104 + js/src/tests/js1_2/regexp/shell.js | 0 js/src/tests/js1_2/regexp/simple_form.js | 91 + js/src/tests/js1_2/regexp/source.js | 89 + js/src/tests/js1_2/regexp/special_characters.js | 159 + js/src/tests/js1_2/regexp/string_replace.js | 125 + js/src/tests/js1_2/regexp/string_search.js | 88 + js/src/tests/js1_2/regexp/string_split.js | 93 + js/src/tests/js1_2/regexp/test.js | 88 + js/src/tests/js1_2/regexp/toString.js | 80 + js/src/tests/js1_2/regexp/vertical_bar.js | 97 + js/src/tests/js1_2/regexp/whitespace.js | 124 + js/src/tests/js1_2/regexp/word_boundary.js | 120 + js/src/tests/js1_2/regress/browser.js | 0 js/src/tests/js1_2/regress/jstests.list | 3 + js/src/tests/js1_2/regress/regress-144834.js | 83 + js/src/tests/js1_2/regress/regress-7703.js | 101 + js/src/tests/js1_2/regress/shell.js | 0 js/src/tests/js1_2/shell.js | 39 + js/src/tests/js1_2/statements/break.js | 163 + js/src/tests/js1_2/statements/browser.js | 0 js/src/tests/js1_2/statements/continue.js | 176 + js/src/tests/js1_2/statements/do_while.js | 68 + js/src/tests/js1_2/statements/jstests.list | 6 + js/src/tests/js1_2/statements/shell.js | 0 js/src/tests/js1_2/statements/switch.js | 129 + js/src/tests/js1_2/statements/switch2.js | 191 + js/src/tests/js1_2/version120/boolean-001.js | 76 + js/src/tests/js1_2/version120/browser.js | 37 + js/src/tests/js1_2/version120/jstests.list | 3 + js/src/tests/js1_2/version120/regress-99663.js | 164 + js/src/tests/js1_2/version120/shell.js | 41 + js/src/tests/js1_3/Boolean/boolean-001.js | 76 + js/src/tests/js1_3/Boolean/browser.js | 0 js/src/tests/js1_3/Boolean/jstests.list | 2 + js/src/tests/js1_3/Boolean/shell.js | 0 js/src/tests/js1_3/README | 1 + js/src/tests/js1_3/Script/browser.js | 0 js/src/tests/js1_3/Script/delete-001.js | 82 + js/src/tests/js1_3/Script/function-001-n.js | 77 + js/src/tests/js1_3/Script/function-002.js | 78 + js/src/tests/js1_3/Script/in-001.js | 68 + js/src/tests/js1_3/Script/jstests.list | 7 + js/src/tests/js1_3/Script/new-001.js | 122 + js/src/tests/js1_3/Script/shell.js | 0 js/src/tests/js1_3/Script/switch-001.js | 83 + js/src/tests/js1_3/browser.js | 36 + js/src/tests/js1_3/extensions/browser.js | 0 js/src/tests/js1_3/extensions/jstests.list | 5 + js/src/tests/js1_3/extensions/proto_10.js | 155 + js/src/tests/js1_3/extensions/proto_2.js | 124 + js/src/tests/js1_3/extensions/proto_5.js | 148 + js/src/tests/js1_3/extensions/script-001.js | 173 + js/src/tests/js1_3/extensions/shell.js | 0 js/src/tests/js1_3/inherit/browser.js | 0 js/src/tests/js1_3/inherit/jstests.list | 11 + js/src/tests/js1_3/inherit/proto_1.js | 169 + js/src/tests/js1_3/inherit/proto_10.js | 123 + js/src/tests/js1_3/inherit/proto_11.js | 119 + js/src/tests/js1_3/inherit/proto_12.js | 145 + js/src/tests/js1_3/inherit/proto_3.js | 106 + js/src/tests/js1_3/inherit/proto_4.js | 158 + js/src/tests/js1_3/inherit/proto_6.js | 173 + js/src/tests/js1_3/inherit/proto_7.js | 128 + js/src/tests/js1_3/inherit/proto_8.js | 126 + js/src/tests/js1_3/inherit/proto_9.js | 104 + js/src/tests/js1_3/inherit/shell.js | 0 js/src/tests/js1_3/jsref.js | 195 + js/src/tests/js1_3/jstests.list | 6 + js/src/tests/js1_3/misc/browser.js | 0 js/src/tests/js1_3/misc/jstests.list | 0 js/src/tests/js1_3/misc/shell.js | 0 js/src/tests/js1_3/regress/browser.js | 0 js/src/tests/js1_3/regress/delete-001.js | 82 + js/src/tests/js1_3/regress/function-001-n.js | 77 + js/src/tests/js1_3/regress/function-002.js | 78 + js/src/tests/js1_3/regress/in-001.js | 69 + js/src/tests/js1_3/regress/jstests.list | 7 + js/src/tests/js1_3/regress/new-001.js | 122 + js/src/tests/js1_3/regress/shell.js | 0 js/src/tests/js1_3/regress/switch-001.js | 83 + js/src/tests/js1_3/shell.js | 39 + js/src/tests/js1_4/Eval/browser.js | 0 js/src/tests/js1_4/Eval/eval-001.js | 90 + js/src/tests/js1_4/Eval/eval-002.js | 96 + js/src/tests/js1_4/Eval/eval-003.js | 100 + js/src/tests/js1_4/Eval/jstests.list | 5 + js/src/tests/js1_4/Eval/regress-531682.js | 34 + js/src/tests/js1_4/Eval/shell.js | 0 js/src/tests/js1_4/Functions/browser.js | 0 js/src/tests/js1_4/Functions/function-001.js | 122 + js/src/tests/js1_4/Functions/jstests.list | 2 + js/src/tests/js1_4/Functions/shell.js | 0 js/src/tests/js1_4/README | 1 + js/src/tests/js1_4/Regress/browser.js | 0 js/src/tests/js1_4/Regress/date-001-n.js | 75 + js/src/tests/js1_4/Regress/function-001.js | 95 + js/src/tests/js1_4/Regress/function-002.js | 140 + js/src/tests/js1_4/Regress/function-003.js | 93 + js/src/tests/js1_4/Regress/function-004-n.js | 70 + js/src/tests/js1_4/Regress/jstests.list | 8 + js/src/tests/js1_4/Regress/regress-7224.js | 89 + js/src/tests/js1_4/Regress/shell.js | 0 js/src/tests/js1_4/Regress/toString-001-n.js | 70 + js/src/tests/js1_4/browser.js | 37 + js/src/tests/js1_4/jsref.js | 166 + js/src/tests/js1_4/jstests.list | 3 + js/src/tests/js1_4/shell.js | 38 + js/src/tests/js1_5/Array/11.1.4.js | 101 + js/src/tests/js1_5/Array/array-001.js | 121 + js/src/tests/js1_5/Array/browser.js | 0 js/src/tests/js1_5/Array/jstests.list | 36 + js/src/tests/js1_5/Array/regress-101964.js | 118 + js/src/tests/js1_5/Array/regress-107138.js | 210 + js/src/tests/js1_5/Array/regress-108440.js | 109 + js/src/tests/js1_5/Array/regress-154338.js | 123 + js/src/tests/js1_5/Array/regress-157652.js | 154 + js/src/tests/js1_5/Array/regress-178722.js | 163 + js/src/tests/js1_5/Array/regress-255555.js | 65 + js/src/tests/js1_5/Array/regress-299644.js | 60 + js/src/tests/js1_5/Array/regress-300858.js | 53 + js/src/tests/js1_5/Array/regress-310351.js | 86 + js/src/tests/js1_5/Array/regress-311515.js | 52 + js/src/tests/js1_5/Array/regress-313153.js | 50 + js/src/tests/js1_5/Array/regress-315509-01.js | 60 + js/src/tests/js1_5/Array/regress-330812.js | 64 + js/src/tests/js1_5/Array/regress-345961.js | 68 + js/src/tests/js1_5/Array/regress-348810.js | 60 + js/src/tests/js1_5/Array/regress-350256-01.js | 77 + js/src/tests/js1_5/Array/regress-350256-02.js | 77 + js/src/tests/js1_5/Array/regress-350256-03.js | 87 + js/src/tests/js1_5/Array/regress-360681-01.js | 65 + js/src/tests/js1_5/Array/regress-360681-02.js | 90 + js/src/tests/js1_5/Array/regress-364104.js | 106 + js/src/tests/js1_5/Array/regress-422286.js | 66 + js/src/tests/js1_5/Array/regress-424954.js | 30 + js/src/tests/js1_5/Array/regress-451483.js | 63 + js/src/tests/js1_5/Array/regress-451906.js | 63 + js/src/tests/js1_5/Array/regress-456845.js | 86 + js/src/tests/js1_5/Array/regress-465980-01.js | 67 + js/src/tests/js1_5/Array/regress-465980-02.js | 201 + js/src/tests/js1_5/Array/regress-474529.js | 89 + js/src/tests/js1_5/Array/regress-94257.js | 119 + js/src/tests/js1_5/Array/regress-99120-01.js | 83 + js/src/tests/js1_5/Array/regress-99120-02.js | 78 + js/src/tests/js1_5/Array/shell.js | 0 js/src/tests/js1_5/Date/browser.js | 0 js/src/tests/js1_5/Date/jstests.list | 8 + js/src/tests/js1_5/Date/regress-188211.js | 59 + js/src/tests/js1_5/Date/regress-301738-01.js | 129 + js/src/tests/js1_5/Date/regress-301738-02.js | 162 + js/src/tests/js1_5/Date/regress-309925-01.js | 47 + js/src/tests/js1_5/Date/regress-309925-02.js | 47 + js/src/tests/js1_5/Date/regress-346027.js | 62 + js/src/tests/js1_5/Date/regress-346363.js | 63 + js/src/tests/js1_5/Date/shell.js | 0 js/src/tests/js1_5/Error/browser.js | 0 js/src/tests/js1_5/Error/jstests.list | 4 + js/src/tests/js1_5/Error/regress-354246.js | 69 + js/src/tests/js1_5/Error/regress-412324.js | 49 + js/src/tests/js1_5/Error/regress-465377.js | 113 + js/src/tests/js1_5/Error/shell.js | 0 js/src/tests/js1_5/Exceptions/browser.js | 0 js/src/tests/js1_5/Exceptions/catchguard-002-n.js | 71 + js/src/tests/js1_5/Exceptions/catchguard-003-n.js | 75 + js/src/tests/js1_5/Exceptions/errstack-001.js | 278 + js/src/tests/js1_5/Exceptions/jstests.list | 16 + js/src/tests/js1_5/Exceptions/regress-121658.js | 157 + js/src/tests/js1_5/Exceptions/regress-123002.js | 126 + js/src/tests/js1_5/Exceptions/regress-232182.js | 154 + js/src/tests/js1_5/Exceptions/regress-257751.js | 126 + js/src/tests/js1_5/Exceptions/regress-273931.js | 107 + js/src/tests/js1_5/Exceptions/regress-315147.js | 68 + js/src/tests/js1_5/Exceptions/regress-332472.js | 57 + js/src/tests/js1_5/Exceptions/regress-333728.js | 115 + js/src/tests/js1_5/Exceptions/regress-342359.js | 76 + js/src/tests/js1_5/Exceptions/regress-347674.js | 95 + js/src/tests/js1_5/Exceptions/regress-350650-n.js | 62 + js/src/tests/js1_5/Exceptions/regress-350837.js | 78 + js/src/tests/js1_5/Exceptions/shell.js | 0 js/src/tests/js1_5/Expressions/browser.js | 0 js/src/tests/js1_5/Expressions/jstests.list | 6 + js/src/tests/js1_5/Expressions/regress-192288.js | 118 + js/src/tests/js1_5/Expressions/regress-394673.js | 81 + .../js1_5/Expressions/regress-96526-argsub.js | 124 + .../js1_5/Expressions/regress-96526-delelem.js | 124 + .../js1_5/Expressions/regress-96526-noargsub.js | 124 + js/src/tests/js1_5/Expressions/shell.js | 136 + js/src/tests/js1_5/Function/10.1.6-01.js | 61 + js/src/tests/js1_5/Function/10.1.6.js | 55 + js/src/tests/js1_5/Function/15.3.4.4.js | 73 + js/src/tests/js1_5/Function/browser.js | 0 js/src/tests/js1_5/Function/jstests.list | 15 + js/src/tests/js1_5/Function/regress-123371.js | 52 + js/src/tests/js1_5/Function/regress-178389.js | 61 + js/src/tests/js1_5/Function/regress-222029-001.js | 159 + js/src/tests/js1_5/Function/regress-222029-002.js | 168 + js/src/tests/js1_5/Function/regress-292215.js | 70 + js/src/tests/js1_5/Function/regress-338001.js | 73 + js/src/tests/js1_5/Function/regress-338121-01.js | 69 + js/src/tests/js1_5/Function/regress-338121-02.js | 73 + js/src/tests/js1_5/Function/regress-338121-03.js | 74 + js/src/tests/js1_5/Function/regress-344052.js | 62 + js/src/tests/js1_5/Function/regress-364023.js | 72 + js/src/tests/js1_5/Function/shell.js | 0 js/src/tests/js1_5/GC/browser.js | 0 js/src/tests/js1_5/GC/jstests.list | 26 + js/src/tests/js1_5/GC/regress-104584.js | 79 + js/src/tests/js1_5/GC/regress-203278-2.js | 112 + js/src/tests/js1_5/GC/regress-203278-3.js | 75 + js/src/tests/js1_5/GC/regress-278725.js | 64 + js/src/tests/js1_5/GC/regress-306788.js | 56 + js/src/tests/js1_5/GC/regress-311497.js | 93 + js/src/tests/js1_5/GC/regress-313276.js | 72 + js/src/tests/js1_5/GC/regress-313479.js | 69 + js/src/tests/js1_5/GC/regress-316885-01.js | 65 + js/src/tests/js1_5/GC/regress-316885-02.js | 74 + js/src/tests/js1_5/GC/regress-316885-03.js | 74 + js/src/tests/js1_5/GC/regress-319980-01.js | 159 + js/src/tests/js1_5/GC/regress-324278.js | 94 + js/src/tests/js1_5/GC/regress-331719.js | 51 + js/src/tests/js1_5/GC/regress-338653.js | 73 + js/src/tests/js1_5/GC/regress-341877-01.js | 72 + js/src/tests/js1_5/GC/regress-341877-02.js | 77 + js/src/tests/js1_5/GC/regress-346794.js | 76 + js/src/tests/js1_5/GC/regress-348532.js | 86 + js/src/tests/js1_5/GC/regress-352606.js | 60 + js/src/tests/js1_5/GC/regress-383269-01.js | 93 + js/src/tests/js1_5/GC/regress-383269-02.js | 97 + js/src/tests/js1_5/GC/regress-390078.js | 68 + js/src/tests/js1_5/GC/regress-418128.js | 72 + js/src/tests/js1_5/GC/regress-440558.js | 68 + js/src/tests/js1_5/GC/shell.js | 0 js/src/tests/js1_5/GetSet/browser.js | 0 js/src/tests/js1_5/GetSet/getset-002.js | 85 + js/src/tests/js1_5/GetSet/jstests.list | 4 + js/src/tests/js1_5/GetSet/regress-353264.js | 49 + js/src/tests/js1_5/GetSet/regress-375976.js | 63 + js/src/tests/js1_5/GetSet/shell.js | 0 js/src/tests/js1_5/LexicalConventions/browser.js | 0 js/src/tests/js1_5/LexicalConventions/jstests.list | 5 + .../tests/js1_5/LexicalConventions/lexical-001.js | 182 + .../js1_5/LexicalConventions/regress-177314.js | 109 + .../js1_5/LexicalConventions/regress-343675.js | 81 + .../js1_5/LexicalConventions/regress-469940.js | 70 + js/src/tests/js1_5/LexicalConventions/shell.js | 0 js/src/tests/js1_5/Object/browser.js | 0 js/src/tests/js1_5/Object/jstests.list | 11 + js/src/tests/js1_5/Object/regress-137000.js | 239 + js/src/tests/js1_5/Object/regress-192105.js | 182 + js/src/tests/js1_5/Object/regress-308806-01.js | 52 + js/src/tests/js1_5/Object/regress-338709.js | 106 + js/src/tests/js1_5/Object/regress-362872-01.js | 73 + js/src/tests/js1_5/Object/regress-362872-02.js | 24 + js/src/tests/js1_5/Object/regress-382503.js | 61 + js/src/tests/js1_5/Object/regress-382532.js | 69 + js/src/tests/js1_5/Object/regress-465476.js | 95 + js/src/tests/js1_5/Object/regress-90596-003.js | 311 + js/src/tests/js1_5/Object/shell.js | 0 js/src/tests/js1_5/README | 1 + js/src/tests/js1_5/Regress/browser.js | 0 js/src/tests/js1_5/Regress/jstests.list | 371 + js/src/tests/js1_5/Regress/regress-102725.js | 98 + js/src/tests/js1_5/Regress/regress-10278.js | 48 + js/src/tests/js1_5/Regress/regress-103602.js | 167 + js/src/tests/js1_5/Regress/regress-104077.js | 508 + js/src/tests/js1_5/Regress/regress-106244.js | 70 + js/src/tests/js1_5/Regress/regress-110286.js | 155 + js/src/tests/js1_5/Regress/regress-111557.js | 10964 ++++ js/src/tests/js1_5/Regress/regress-114491.js | 105 + js/src/tests/js1_5/Regress/regress-114493.js | 113 + js/src/tests/js1_5/Regress/regress-115436.js | 57 + js/src/tests/js1_5/Regress/regress-116228.js | 58 + js/src/tests/js1_5/Regress/regress-118849.js | 185 + js/src/tests/js1_5/Regress/regress-119719.js | 57 + js/src/tests/js1_5/Regress/regress-127243.js | 107 + js/src/tests/js1_5/Regress/regress-127557.js | 123 + js/src/tests/js1_5/Regress/regress-131510-001.js | 73 + js/src/tests/js1_5/Regress/regress-139316.js | 79 + js/src/tests/js1_5/Regress/regress-140852.js | 65 + js/src/tests/js1_5/Regress/regress-140974.js | 139 + js/src/tests/js1_5/Regress/regress-146596.js | 158 + js/src/tests/js1_5/Regress/regress-152646.js | 126 + js/src/tests/js1_5/Regress/regress-155081-2.js | 17553 +++++ js/src/tests/js1_5/Regress/regress-155081.js | 17560 +++++ js/src/tests/js1_5/Regress/regress-156354.js | 130 + js/src/tests/js1_5/Regress/regress-159334.js | 128 + js/src/tests/js1_5/Regress/regress-162392.js | 37 + js/src/tests/js1_5/Regress/regress-165201.js | 88 + js/src/tests/js1_5/Regress/regress-167328.js | 59 + js/src/tests/js1_5/Regress/regress-167658.js | 61 + js/src/tests/js1_5/Regress/regress-168347.js | 219 + js/src/tests/js1_5/Regress/regress-169559.js | 60 + js/src/tests/js1_5/Regress/regress-170193.js | 110 + js/src/tests/js1_5/Regress/regress-172699.js | 105 + js/src/tests/js1_5/Regress/regress-173067.js | 57 + js/src/tests/js1_5/Regress/regress-174709.js | 103 + js/src/tests/js1_5/Regress/regress-176125.js | 81 + js/src/tests/js1_5/Regress/regress-179524.js | 367 + js/src/tests/js1_5/Regress/regress-185165.js | 100 + js/src/tests/js1_5/Regress/regress-191633.js | 106 + js/src/tests/js1_5/Regress/regress-191668.js | 103 + js/src/tests/js1_5/Regress/regress-192414.js | 121 + js/src/tests/js1_5/Regress/regress-193418.js | 103 + js/src/tests/js1_5/Regress/regress-203278-1.js | 63 + js/src/tests/js1_5/Regress/regress-203402.js | 94 + js/src/tests/js1_5/Regress/regress-203841.js | 163 + js/src/tests/js1_5/Regress/regress-204210.js | 149 + js/src/tests/js1_5/Regress/regress-210682.js | 100 + js/src/tests/js1_5/Regress/regress-211590.js | 87 + js/src/tests/js1_5/Regress/regress-213482.js | 61 + js/src/tests/js1_5/Regress/regress-214761.js | 77 + js/src/tests/js1_5/Regress/regress-216320.js | 1039 + js/src/tests/js1_5/Regress/regress-224956.js | 286 + js/src/tests/js1_5/Regress/regress-229006.js | 65596 +++++++++++++++++++ js/src/tests/js1_5/Regress/regress-230216-1.js | 80 + js/src/tests/js1_5/Regress/regress-230216-2.js | 69 + js/src/tests/js1_5/Regress/regress-230216-3.js | 79 + js/src/tests/js1_5/Regress/regress-233483-2.js | 99 + js/src/tests/js1_5/Regress/regress-233483.js | 85 + js/src/tests/js1_5/Regress/regress-234389.js | 71 + js/src/tests/js1_5/Regress/regress-238881.js | 63 + js/src/tests/js1_5/Regress/regress-238945.js | 51 + js/src/tests/js1_5/Regress/regress-240577.js | 37 + js/src/tests/js1_5/Regress/regress-243174.js | 54 + js/src/tests/js1_5/Regress/regress-243389-n.js | 57 + js/src/tests/js1_5/Regress/regress-243869.js | 71 + js/src/tests/js1_5/Regress/regress-244470.js | 1112 + js/src/tests/js1_5/Regress/regress-244619.js | 65 + js/src/tests/js1_5/Regress/regress-245113.js | 80 + js/src/tests/js1_5/Regress/regress-245308.js | 60 + js/src/tests/js1_5/Regress/regress-246911.js | 63 + js/src/tests/js1_5/Regress/regress-246964.js | 195 + js/src/tests/js1_5/Regress/regress-247179.js | 52 + js/src/tests/js1_5/Regress/regress-248444.js | 76 + js/src/tests/js1_5/Regress/regress-249211.js | 62 + js/src/tests/js1_5/Regress/regress-252892.js | 162 + js/src/tests/js1_5/Regress/regress-253150.js | 122 + js/src/tests/js1_5/Regress/regress-254296.js | 59 + js/src/tests/js1_5/Regress/regress-254974.js | 71 + js/src/tests/js1_5/Regress/regress-256501.js | 71 + js/src/tests/js1_5/Regress/regress-256617.js | 68 + js/src/tests/js1_5/Regress/regress-256798.js | 69 + js/src/tests/js1_5/Regress/regress-259935.js | 74 + js/src/tests/js1_5/Regress/regress-260541.js | 54 + js/src/tests/js1_5/Regress/regress-261886.js | 62 + js/src/tests/js1_5/Regress/regress-261887.js | 69 + js/src/tests/js1_5/Regress/regress-271716-n.js | 59 + js/src/tests/js1_5/Regress/regress-274035.js | 62 + js/src/tests/js1_5/Regress/regress-274888.js | 72 + js/src/tests/js1_5/Regress/regress-275378.js | 80 + js/src/tests/js1_5/Regress/regress-276103.js | 59 + js/src/tests/js1_5/Regress/regress-278873.js | 60 + js/src/tests/js1_5/Regress/regress-280769-1.js | 57 + js/src/tests/js1_5/Regress/regress-280769-2.js | 73 + js/src/tests/js1_5/Regress/regress-280769-3.js | 78 + js/src/tests/js1_5/Regress/regress-280769-4.js | 80 + js/src/tests/js1_5/Regress/regress-280769-5.js | 63 + js/src/tests/js1_5/Regress/regress-280769.js | 72 + js/src/tests/js1_5/Regress/regress-281487.js | 68 + js/src/tests/js1_5/Regress/regress-281606.js | 79 + js/src/tests/js1_5/Regress/regress-281930.js | 53 + js/src/tests/js1_5/Regress/regress-283477.js | 60 + js/src/tests/js1_5/Regress/regress-286216.js | 62 + js/src/tests/js1_5/Regress/regress-288688.js | 80 + js/src/tests/js1_5/Regress/regress-289094.js | 60 + js/src/tests/js1_5/Regress/regress-290575.js | 89 + js/src/tests/js1_5/Regress/regress-290656.js | 64 + js/src/tests/js1_5/Regress/regress-294191.js | 62 + js/src/tests/js1_5/Regress/regress-294195-01.js | 57 + js/src/tests/js1_5/Regress/regress-294195-02.js | 49 + js/src/tests/js1_5/Regress/regress-294302.js | 56 + js/src/tests/js1_5/Regress/regress-295052.js | 58 + js/src/tests/js1_5/Regress/regress-295666.js | 55 + js/src/tests/js1_5/Regress/regress-299209.js | 55 + js/src/tests/js1_5/Regress/regress-299641.js | 57 + js/src/tests/js1_5/Regress/regress-303213.js | 87 + js/src/tests/js1_5/Regress/regress-306633.js | 67 + js/src/tests/js1_5/Regress/regress-306727.js | 72 + js/src/tests/js1_5/Regress/regress-306794.js | 25 + js/src/tests/js1_5/Regress/regress-308085.js | 601 + js/src/tests/js1_5/Regress/regress-308566.js | 59 + js/src/tests/js1_5/Regress/regress-309242.js | 76 + js/src/tests/js1_5/Regress/regress-310295.js | 53 + js/src/tests/js1_5/Regress/regress-310607.js | 61 + js/src/tests/js1_5/Regress/regress-310993.js | 54 + js/src/tests/js1_5/Regress/regress-311071.js | 50 + js/src/tests/js1_5/Regress/regress-311629.js | 54 + js/src/tests/js1_5/Regress/regress-312260.js | 59 + js/src/tests/js1_5/Regress/regress-31255.js | 112 + js/src/tests/js1_5/Regress/regress-312588.js | 62 + js/src/tests/js1_5/Regress/regress-313967-01.js | 111 + js/src/tests/js1_5/Regress/regress-313967-02.js | 86 + js/src/tests/js1_5/Regress/regress-314401.js | 103 + js/src/tests/js1_5/Regress/regress-315974.js | 82 + js/src/tests/js1_5/Regress/regress-315990.js | 72 + js/src/tests/js1_5/Regress/regress-317476.js | 63 + js/src/tests/js1_5/Regress/regress-317533.js | 86 + js/src/tests/js1_5/Regress/regress-317714-01.js | 51 + js/src/tests/js1_5/Regress/regress-317714-02.js | 52 + js/src/tests/js1_5/Regress/regress-319384.js | 60 + js/src/tests/js1_5/Regress/regress-319391.js | 72 + js/src/tests/js1_5/Regress/regress-320032.js | 59 + js/src/tests/js1_5/Regress/regress-320119.js | 147 + js/src/tests/js1_5/Regress/regress-321757.js | 142 + js/src/tests/js1_5/Regress/regress-321874.js | 240 + js/src/tests/js1_5/Regress/regress-321971.js | 55 + js/src/tests/js1_5/Regress/regress-322430.js | 69 + js/src/tests/js1_5/Regress/regress-323314-1.js | 72 + js/src/tests/js1_5/Regress/regress-325925.js | 19 + js/src/tests/js1_5/Regress/regress-326453.js | 21 + js/src/tests/js1_5/Regress/regress-326467.js | 50 + js/src/tests/js1_5/Regress/regress-328012.js | 61 + js/src/tests/js1_5/Regress/regress-328664.js | 63 + js/src/tests/js1_5/Regress/regress-328897.js | 78 + js/src/tests/js1_5/Regress/regress-329383.js | 115 + js/src/tests/js1_5/Regress/regress-329530.js | 72 + js/src/tests/js1_5/Regress/regress-330352.js | 66 + js/src/tests/js1_5/Regress/regress-330951.js | 49 + js/src/tests/js1_5/Regress/regress-334807-01.js | 56 + js/src/tests/js1_5/Regress/regress-334807-02.js | 60 + js/src/tests/js1_5/Regress/regress-334807-03.js | 56 + js/src/tests/js1_5/Regress/regress-334807-04.js | 60 + js/src/tests/js1_5/Regress/regress-334807-05.js | 65 + js/src/tests/js1_5/Regress/regress-334807-06.js | 69 + js/src/tests/js1_5/Regress/regress-336100.js | 54 + js/src/tests/js1_5/Regress/regress-338307.js | 61 + js/src/tests/js1_5/Regress/regress-340369.js | 57 + js/src/tests/js1_5/Regress/regress-341360.js | 87 + js/src/tests/js1_5/Regress/regress-343713.js | 53 + js/src/tests/js1_5/Regress/regress-343966.js | 64 + js/src/tests/js1_5/Regress/regress-344711-n.js | 66 + js/src/tests/js1_5/Regress/regress-344804.js | 64 + js/src/tests/js1_5/Regress/regress-344959.js | 68 + js/src/tests/js1_5/Regress/regress-346237.js | 60 + js/src/tests/js1_5/Regress/regress-346801.js | 108 + js/src/tests/js1_5/Regress/regress-347306-01.js | 84 + js/src/tests/js1_5/Regress/regress-349482-01.js | 61 + js/src/tests/js1_5/Regress/regress-349482-02.js | 61 + js/src/tests/js1_5/Regress/regress-349592.js | 60 + js/src/tests/js1_5/Regress/regress-349648.js | 97 + js/src/tests/js1_5/Regress/regress-350253.js | 66 + js/src/tests/js1_5/Regress/regress-350268.js | 106 + js/src/tests/js1_5/Regress/regress-350312.js | 113 + js/src/tests/js1_5/Regress/regress-350415.js | 66 + js/src/tests/js1_5/Regress/regress-350529.js | 65 + js/src/tests/js1_5/Regress/regress-350692.js | 69 + js/src/tests/js1_5/Regress/regress-351116.js | 61 + js/src/tests/js1_5/Regress/regress-351515.js | 68 + js/src/tests/js1_5/Regress/regress-352009.js | 59 + js/src/tests/js1_5/Regress/regress-352197.js | 101 + js/src/tests/js1_5/Regress/regress-352208.js | 76 + js/src/tests/js1_5/Regress/regress-352604.js | 61 + js/src/tests/js1_5/Regress/regress-354924.js | 63 + js/src/tests/js1_5/Regress/regress-355341.js | 61 + js/src/tests/js1_5/Regress/regress-355344.js | 81 + js/src/tests/js1_5/Regress/regress-355556.js | 67 + js/src/tests/js1_5/Regress/regress-355829-01.js | 60 + js/src/tests/js1_5/Regress/regress-355829-02.js | 73 + js/src/tests/js1_5/Regress/regress-355829-03.js | 61 + js/src/tests/js1_5/Regress/regress-356250.js | 76 + js/src/tests/js1_5/Regress/regress-356693.js | 68 + js/src/tests/js1_5/Regress/regress-360969-01.js | 73 + js/src/tests/js1_5/Regress/regress-360969-02.js | 63 + js/src/tests/js1_5/Regress/regress-360969-03.js | 73 + js/src/tests/js1_5/Regress/regress-360969-04.js | 63 + js/src/tests/js1_5/Regress/regress-360969-05.js | 75 + js/src/tests/js1_5/Regress/regress-360969-06.js | 64 + js/src/tests/js1_5/Regress/regress-361467.js | 64 + js/src/tests/js1_5/Regress/regress-361617.js | 67 + js/src/tests/js1_5/Regress/regress-362583.js | 76 + js/src/tests/js1_5/Regress/regress-3649-n.js | 65 + js/src/tests/js1_5/Regress/regress-366122.js | 78 + js/src/tests/js1_5/Regress/regress-366468.js | 67 + js/src/tests/js1_5/Regress/regress-366601.js | 70 + js/src/tests/js1_5/Regress/regress-367561-01.js | 69 + js/src/tests/js1_5/Regress/regress-367561-03.js | 68 + js/src/tests/js1_5/Regress/regress-372364.js | 79 + js/src/tests/js1_5/Regress/regress-379245.js | 71 + js/src/tests/js1_5/Regress/regress-383674.js | 90 + js/src/tests/js1_5/Regress/regress-383682.js | 36 + js/src/tests/js1_5/Regress/regress-385393-06.js | 60 + js/src/tests/js1_5/Regress/regress-387951-01.js | 60 + js/src/tests/js1_5/Regress/regress-387951-02.js | 60 + js/src/tests/js1_5/Regress/regress-387951-03.js | 60 + js/src/tests/js1_5/Regress/regress-39309.js | 109 + js/src/tests/js1_5/Regress/regress-396684.js | 80 + js/src/tests/js1_5/Regress/regress-398085-01.js | 777 + js/src/tests/js1_5/Regress/regress-398085-02.js | 760 + js/src/tests/js1_5/Regress/regress-398609.js | 71 + js/src/tests/js1_5/Regress/regress-404755.js | 82 + js/src/tests/js1_5/Regress/regress-406769.js | 187 + js/src/tests/js1_5/Regress/regress-407024.js | 52 + js/src/tests/js1_5/Regress/regress-407323.js | 74 + js/src/tests/js1_5/Regress/regress-407957.js | 62 + js/src/tests/js1_5/Regress/regress-410852.js | 40 + js/src/tests/js1_5/Regress/regress-416628.js | 141 + js/src/tests/js1_5/Regress/regress-416737-01.js | 60 + js/src/tests/js1_5/Regress/regress-416737-02.js | 65 + js/src/tests/js1_5/Regress/regress-417893.js | 68 + js/src/tests/js1_5/Regress/regress-418504.js | 85 + js/src/tests/js1_5/Regress/regress-418540.js | 93 + js/src/tests/js1_5/Regress/regress-419018.js | 79 + js/src/tests/js1_5/Regress/regress-419803.js | 60 + js/src/tests/js1_5/Regress/regress-420919.js | 69 + js/src/tests/js1_5/Regress/regress-422348.js | 69 + js/src/tests/js1_5/Regress/regress-424311.js | 60 + js/src/tests/js1_5/Regress/regress-425360.js | 73 + js/src/tests/js1_5/Regress/regress-426827.js | 66 + js/src/tests/js1_5/Regress/regress-428366.js | 21 + js/src/tests/js1_5/Regress/regress-438415-01.js | 59 + js/src/tests/js1_5/Regress/regress-438415-02.js | 63 + js/src/tests/js1_5/Regress/regress-440926.js | 66 + js/src/tests/js1_5/Regress/regress-449627.js | 116 + js/src/tests/js1_5/Regress/regress-449666.js | 67 + js/src/tests/js1_5/Regress/regress-450369.js | 344 + js/src/tests/js1_5/Regress/regress-450833.js | 81 + js/src/tests/js1_5/Regress/regress-451322.js | 70 + js/src/tests/js1_5/Regress/regress-451884.js | 67 + js/src/tests/js1_5/Regress/regress-451946.js | 66 + js/src/tests/js1_5/Regress/regress-452008.js | 185 + js/src/tests/js1_5/Regress/regress-452170.js | 63 + js/src/tests/js1_5/Regress/regress-452189.js | 23 + js/src/tests/js1_5/Regress/regress-452333.js | 63 + js/src/tests/js1_5/Regress/regress-452336.js | 63 + js/src/tests/js1_5/Regress/regress-452346.js | 60 + js/src/tests/js1_5/Regress/regress-452495.js | 53 + js/src/tests/js1_5/Regress/regress-452573-01.js | 63 + js/src/tests/js1_5/Regress/regress-452573-02.js | 63 + js/src/tests/js1_5/Regress/regress-452713.js | 63 + js/src/tests/js1_5/Regress/regress-452724-01.js | 63 + js/src/tests/js1_5/Regress/regress-452724-02.js | 63 + js/src/tests/js1_5/Regress/regress-452742-01.js | 83 + js/src/tests/js1_5/Regress/regress-452742-02.js | 88 + js/src/tests/js1_5/Regress/regress-452853.js | 63 + js/src/tests/js1_5/Regress/regress-452884-01.js | 63 + js/src/tests/js1_5/Regress/regress-452884-02.js | 63 + js/src/tests/js1_5/Regress/regress-453024.js | 77 + js/src/tests/js1_5/Regress/regress-453173.js | 65 + js/src/tests/js1_5/Regress/regress-453397.js | 80 + js/src/tests/js1_5/Regress/regress-453701.js | 63 + js/src/tests/js1_5/Regress/regress-453747.js | 71 + js/src/tests/js1_5/Regress/regress-454682.js | 67 + js/src/tests/js1_5/Regress/regress-454981.js | 68 + js/src/tests/js1_5/Regress/regress-455605.js | 64 + js/src/tests/js1_5/Regress/regress-455748.js | 64 + js/src/tests/js1_5/Regress/regress-455758-01.js | 64 + js/src/tests/js1_5/Regress/regress-455758-02.js | 64 + js/src/tests/js1_5/Regress/regress-455775.js | 66 + js/src/tests/js1_5/Regress/regress-456470.js | 72 + js/src/tests/js1_5/Regress/regress-456477-01.js | 64 + js/src/tests/js1_5/Regress/regress-456477-02.js | 64 + js/src/tests/js1_5/Regress/regress-456494.js | 82 + js/src/tests/js1_5/Regress/regress-456540-01.js | 64 + js/src/tests/js1_5/Regress/regress-456540-02.js | 64 + js/src/tests/js1_5/Regress/regress-457065-03.js | 66 + js/src/tests/js1_5/Regress/regress-457456.js | 64 + js/src/tests/js1_5/Regress/regress-457778.js | 64 + js/src/tests/js1_5/Regress/regress-458851.js | 64 + js/src/tests/js1_5/Regress/regress-459085.js | 36 + js/src/tests/js1_5/Regress/regress-459628.js | 68 + js/src/tests/js1_5/Regress/regress-459990.js | 65 + js/src/tests/js1_5/Regress/regress-460024.js | 73 + js/src/tests/js1_5/Regress/regress-460117.js | 79 + js/src/tests/js1_5/Regress/regress-460886-01.js | 60 + js/src/tests/js1_5/Regress/regress-460886-02.js | 60 + js/src/tests/js1_5/Regress/regress-461307.js | 65 + js/src/tests/js1_5/Regress/regress-461723.js | 64 + js/src/tests/js1_5/Regress/regress-462292.js | 66 + js/src/tests/js1_5/Regress/regress-462879.js | 66 + js/src/tests/js1_5/Regress/regress-462989.js | 65 + js/src/tests/js1_5/Regress/regress-463259.js | 61 + js/src/tests/js1_5/Regress/regress-463782.js | 100 + js/src/tests/js1_5/Regress/regress-464334.js | 68 + js/src/tests/js1_5/Regress/regress-464862.js | 155 + js/src/tests/js1_5/Regress/regress-465013.js | 73 + js/src/tests/js1_5/Regress/regress-465132.js | 77 + js/src/tests/js1_5/Regress/regress-465133.js | 67 + js/src/tests/js1_5/Regress/regress-465135.js | 67 + js/src/tests/js1_5/Regress/regress-465136.js | 67 + js/src/tests/js1_5/Regress/regress-465137.js | 67 + js/src/tests/js1_5/Regress/regress-465262.js | 66 + js/src/tests/js1_5/Regress/regress-465272.js | 66 + js/src/tests/js1_5/Regress/regress-465347.js | 84 + js/src/tests/js1_5/Regress/regress-465366.js | 73 + js/src/tests/js1_5/Regress/regress-466262.js | 68 + js/src/tests/js1_5/Regress/regress-466747.js | 93 + js/src/tests/js1_5/Regress/regress-469044.js | 103 + js/src/tests/js1_5/Regress/regress-470061.js | 77 + js/src/tests/js1_5/Regress/regress-470187-01.js | 60 + js/src/tests/js1_5/Regress/regress-470187-02.js | 60 + js/src/tests/js1_5/Regress/regress-470758-01.js | 30 + js/src/tests/js1_5/Regress/regress-470758-02.js | 32 + js/src/tests/js1_5/Regress/regress-472533.js | 60 + js/src/tests/js1_5/Regress/regress-475645-01.js | 81 + js/src/tests/js1_5/Regress/regress-475645-02.js | 88 + js/src/tests/js1_5/Regress/regress-476049.js | 75 + js/src/tests/js1_5/Regress/regress-476192.js | 73 + js/src/tests/js1_5/Regress/regress-477733.js | 76 + js/src/tests/js1_5/Regress/regress-477758.js | 84 + js/src/tests/js1_5/Regress/regress-478314.js | 64 + js/src/tests/js1_5/Regress/regress-479353.js | 60 + js/src/tests/js1_5/Regress/regress-480147.js | 67 + js/src/tests/js1_5/Regress/regress-480244.js | 85 + js/src/tests/js1_5/Regress/regress-481436.js | 73 + js/src/tests/js1_5/Regress/regress-482421.js | 60 + js/src/tests/js1_5/Regress/regress-482783.js | 66 + js/src/tests/js1_5/Regress/regress-483103.js | 67 + js/src/tests/js1_5/Regress/regress-501124.js | 77 + js/src/tests/js1_5/Regress/regress-503860.js | 24 + js/src/tests/js1_5/Regress/regress-504078.js | 83 + js/src/tests/js1_5/Regress/regress-506567.js | 77 + js/src/tests/js1_5/Regress/regress-511859.js | 197 + js/src/tests/js1_5/Regress/regress-57043.js | 112 + js/src/tests/js1_5/Regress/regress-58116.js | 30 + js/src/tests/js1_5/Regress/regress-68498-001.js | 77 + js/src/tests/js1_5/Regress/regress-68498-002.js | 100 + js/src/tests/js1_5/Regress/regress-68498-003.js | 104 + js/src/tests/js1_5/Regress/regress-68498-004.js | 132 + js/src/tests/js1_5/Regress/regress-69607.js | 75 + js/src/tests/js1_5/Regress/regress-71107.js | 79 + js/src/tests/js1_5/Regress/regress-76054.js | 159 + js/src/tests/js1_5/Regress/regress-80981.js | 3143 + js/src/tests/js1_5/Regress/regress-82306.js | 81 + js/src/tests/js1_5/Regress/regress-89443.js | 2152 + js/src/tests/js1_5/Regress/regress-89474.js | 84 + js/src/tests/js1_5/Regress/regress-90445.js | 328 + js/src/tests/js1_5/Regress/regress-96128-n.js | 84 + js/src/tests/js1_5/Regress/regress-96526-001.js | 536 + js/src/tests/js1_5/Regress/regress-96526-002.js | 62 + js/src/tests/js1_5/Regress/regress-96526-003.js | 4437 ++ js/src/tests/js1_5/Regress/regress-98901.js | 3924 ++ js/src/tests/js1_5/Regress/shell.js | 0 js/src/tests/js1_5/Scope/browser.js | 0 js/src/tests/js1_5/Scope/jstests.list | 18 + js/src/tests/js1_5/Scope/regress-154693.js | 100 + js/src/tests/js1_5/Scope/regress-181834.js | 182 + js/src/tests/js1_5/Scope/regress-184107.js | 126 + js/src/tests/js1_5/Scope/regress-185485.js | 162 + js/src/tests/js1_5/Scope/regress-191276.js | 127 + js/src/tests/js1_5/Scope/regress-192226.js | 124 + js/src/tests/js1_5/Scope/regress-202678-001.js | 135 + js/src/tests/js1_5/Scope/regress-202678-002.js | 136 + js/src/tests/js1_5/Scope/regress-208496-001.js | 173 + js/src/tests/js1_5/Scope/regress-208496-002.js | 165 + js/src/tests/js1_5/Scope/regress-220362.js | 115 + js/src/tests/js1_5/Scope/regress-446026-01.js | 83 + js/src/tests/js1_5/Scope/regress-446026-02.js | 59 + js/src/tests/js1_5/Scope/regress-77578-001.js | 183 + js/src/tests/js1_5/Scope/scope-002.js | 141 + js/src/tests/js1_5/Scope/scope-003.js | 142 + js/src/tests/js1_5/Scope/scope-004.js | 224 + js/src/tests/js1_5/Scope/shell.js | 0 js/src/tests/js1_5/String/browser.js | 0 js/src/tests/js1_5/String/jstests.list | 9 + js/src/tests/js1_5/String/regress-107771.js | 124 + js/src/tests/js1_5/String/regress-112626.js | 51 + js/src/tests/js1_5/String/regress-157334-01.js | 89 + js/src/tests/js1_5/String/regress-179068.js | 158 + js/src/tests/js1_5/String/regress-314890.js | 83 + js/src/tests/js1_5/String/regress-322772.js | 83 + js/src/tests/js1_5/String/regress-56940-01.js | 80 + js/src/tests/js1_5/String/regress-56940-02.js | 80 + js/src/tests/js1_5/String/shell.js | 0 js/src/tests/js1_5/browser.js | 37 + js/src/tests/js1_5/decompilation/browser.js | 0 js/src/tests/js1_5/decompilation/jstests.list | 63 + js/src/tests/js1_5/decompilation/regress-344120.js | 61 + js/src/tests/js1_5/decompilation/regress-346892.js | 61 + js/src/tests/js1_5/decompilation/regress-346902.js | 90 + js/src/tests/js1_5/decompilation/regress-346904.js | 155 + js/src/tests/js1_5/decompilation/regress-346915.js | 63 + js/src/tests/js1_5/decompilation/regress-349484.js | 68 + js/src/tests/js1_5/decompilation/regress-349489.js | 68 + js/src/tests/js1_5/decompilation/regress-349491.js | 78 + js/src/tests/js1_5/decompilation/regress-349596.js | 62 + js/src/tests/js1_5/decompilation/regress-349650.js | 64 + js/src/tests/js1_5/decompilation/regress-349663.js | 67 + js/src/tests/js1_5/decompilation/regress-350242.js | 68 + js/src/tests/js1_5/decompilation/regress-350263.js | 63 + js/src/tests/js1_5/decompilation/regress-350271.js | 63 + js/src/tests/js1_5/decompilation/regress-350666.js | 92 + js/src/tests/js1_5/decompilation/regress-350670.js | 68 + js/src/tests/js1_5/decompilation/regress-351104.js | 64 + js/src/tests/js1_5/decompilation/regress-351219.js | 66 + js/src/tests/js1_5/decompilation/regress-351336.js | 62 + js/src/tests/js1_5/decompilation/regress-351597.js | 63 + js/src/tests/js1_5/decompilation/regress-351625.js | 63 + js/src/tests/js1_5/decompilation/regress-351626.js | 63 + js/src/tests/js1_5/decompilation/regress-351693.js | 64 + js/src/tests/js1_5/decompilation/regress-351705.js | 64 + js/src/tests/js1_5/decompilation/regress-351793.js | 64 + js/src/tests/js1_5/decompilation/regress-352013.js | 92 + js/src/tests/js1_5/decompilation/regress-352022.js | 62 + js/src/tests/js1_5/decompilation/regress-352073.js | 68 + js/src/tests/js1_5/decompilation/regress-352202.js | 63 + js/src/tests/js1_5/decompilation/regress-352312.js | 68 + js/src/tests/js1_5/decompilation/regress-352360.js | 69 + js/src/tests/js1_5/decompilation/regress-352375.js | 61 + js/src/tests/js1_5/decompilation/regress-352453.js | 62 + js/src/tests/js1_5/decompilation/regress-352649.js | 62 + .../tests/js1_5/decompilation/regress-352873-01.js | 67 + .../tests/js1_5/decompilation/regress-352873-02.js | 67 + js/src/tests/js1_5/decompilation/regress-353000.js | 62 + js/src/tests/js1_5/decompilation/regress-353120.js | 62 + js/src/tests/js1_5/decompilation/regress-353146.js | 68 + js/src/tests/js1_5/decompilation/regress-354878.js | 61 + js/src/tests/js1_5/decompilation/regress-354910.js | 62 + js/src/tests/js1_5/decompilation/regress-356083.js | 65 + js/src/tests/js1_5/decompilation/regress-371692.js | 61 + js/src/tests/js1_5/decompilation/regress-373678.js | 61 + js/src/tests/js1_5/decompilation/regress-375639.js | 67 + js/src/tests/js1_5/decompilation/regress-375882.js | 75 + js/src/tests/js1_5/decompilation/regress-376564.js | 66 + js/src/tests/js1_5/decompilation/regress-383721.js | 65 + js/src/tests/js1_5/decompilation/regress-406555.js | 68 + .../tests/js1_5/decompilation/regress-437288-02.js | 63 + .../tests/js1_5/decompilation/regress-443071-01.js | 60 + .../tests/js1_5/decompilation/regress-456964-01.js | 73 + .../tests/js1_5/decompilation/regress-457093-01.js | 76 + js/src/tests/js1_5/decompilation/regress-457824.js | 65 + .../tests/js1_5/decompilation/regress-460116-01.js | 64 + .../tests/js1_5/decompilation/regress-460116-02.js | 64 + .../tests/js1_5/decompilation/regress-460116-03.js | 64 + js/src/tests/js1_5/decompilation/regress-460501.js | 70 + js/src/tests/js1_5/decompilation/regress-460870.js | 62 + js/src/tests/js1_5/decompilation/regress-461108.js | 63 + js/src/tests/js1_5/decompilation/regress-461110.js | 63 + js/src/tests/js1_5/decompilation/regress-461111.js | 63 + js/src/tests/js1_5/decompilation/shell.js | 1 + js/src/tests/js1_5/extensions/browser.js | 0 js/src/tests/js1_5/extensions/catchguard-001-n.js | 78 + js/src/tests/js1_5/extensions/catchguard-001.js | 82 + js/src/tests/js1_5/extensions/catchguard-002.js | 78 + js/src/tests/js1_5/extensions/catchguard-003.js | 93 + js/src/tests/js1_5/extensions/getset-001.js | 86 + js/src/tests/js1_5/extensions/getset-003.js | 222 + js/src/tests/js1_5/extensions/getset-004.js | 210 + js/src/tests/js1_5/extensions/getset-005.js | 219 + js/src/tests/js1_5/extensions/getset-006.js | 193 + js/src/tests/js1_5/extensions/jstests.list | 225 + js/src/tests/js1_5/extensions/no-such-method.js | 68 + js/src/tests/js1_5/extensions/regress-104077.js | 232 + js/src/tests/js1_5/extensions/regress-164697.js | 112 + js/src/tests/js1_5/extensions/regress-178722.js | 126 + js/src/tests/js1_5/extensions/regress-192465.js | 156 + js/src/tests/js1_5/extensions/regress-225831.js | 195 + js/src/tests/js1_5/extensions/regress-226078.js | 60 + js/src/tests/js1_5/extensions/regress-226507.js | 186 + js/src/tests/js1_5/extensions/regress-231518.js | 135 + js/src/tests/js1_5/extensions/regress-237461.js | 79 + js/src/tests/js1_5/extensions/regress-245148.js | 54 + js/src/tests/js1_5/extensions/regress-245795.js | 66 + js/src/tests/js1_5/extensions/regress-254375.js | 62 + js/src/tests/js1_5/extensions/regress-255245.js | 64 + js/src/tests/js1_5/extensions/regress-291213.js | 80 + js/src/tests/js1_5/extensions/regress-300079.js | 79 + js/src/tests/js1_5/extensions/regress-303277.js | 51 + js/src/tests/js1_5/extensions/regress-304897.js | 52 + js/src/tests/js1_5/extensions/regress-306738.js | 57 + js/src/tests/js1_5/extensions/regress-311161.js | 1470 + js/src/tests/js1_5/extensions/regress-311583.js | 53 + js/src/tests/js1_5/extensions/regress-311792-01.js | 58 + js/src/tests/js1_5/extensions/regress-311792-02.js | 72 + js/src/tests/js1_5/extensions/regress-313763.js | 78 + js/src/tests/js1_5/extensions/regress-313803.js | 56 + js/src/tests/js1_5/extensions/regress-313938.js | 86 + js/src/tests/js1_5/extensions/regress-314874.js | 72 + js/src/tests/js1_5/extensions/regress-315509-02.js | 74 + js/src/tests/js1_5/extensions/regress-319683.js | 63 + js/src/tests/js1_5/extensions/regress-322957.js | 59 + js/src/tests/js1_5/extensions/regress-327608.js | 80 + js/src/tests/js1_5/extensions/regress-328443.js | 64 + js/src/tests/js1_5/extensions/regress-328556.js | 51 + js/src/tests/js1_5/extensions/regress-330569.js | 130 + js/src/tests/js1_5/extensions/regress-333541.js | 122 + js/src/tests/js1_5/extensions/regress-335700.js | 126 + js/src/tests/js1_5/extensions/regress-336409-1.js | 81 + js/src/tests/js1_5/extensions/regress-336409-2.js | 80 + js/src/tests/js1_5/extensions/regress-336410-1.js | 81 + js/src/tests/js1_5/extensions/regress-336410-2.js | 80 + js/src/tests/js1_5/extensions/regress-338804-01.js | 101 + js/src/tests/js1_5/extensions/regress-338804-02.js | 102 + js/src/tests/js1_5/extensions/regress-338804-03.js | 61 + js/src/tests/js1_5/extensions/regress-339685.js | 59 + js/src/tests/js1_5/extensions/regress-341956-01.js | 100 + js/src/tests/js1_5/extensions/regress-341956-02.js | 87 + js/src/tests/js1_5/extensions/regress-341956-03.js | 104 + js/src/tests/js1_5/extensions/regress-342960.js | 86 + js/src/tests/js1_5/extensions/regress-345967.js | 99 + js/src/tests/js1_5/extensions/regress-346494-01.js | 122 + js/src/tests/js1_5/extensions/regress-346494.js | 140 + js/src/tests/js1_5/extensions/regress-347306-02.js | 83 + js/src/tests/js1_5/extensions/regress-348986.js | 160 + js/src/tests/js1_5/extensions/regress-350312-01.js | 82 + js/src/tests/js1_5/extensions/regress-350312-02.js | 144 + js/src/tests/js1_5/extensions/regress-350312-03.js | 148 + js/src/tests/js1_5/extensions/regress-350531.js | 187 + js/src/tests/js1_5/extensions/regress-351102-01.js | 71 + js/src/tests/js1_5/extensions/regress-351102-02.js | 77 + js/src/tests/js1_5/extensions/regress-351102-06.js | 66 + js/src/tests/js1_5/extensions/regress-351448.js | 97 + js/src/tests/js1_5/extensions/regress-351463-01.js | 286 + js/src/tests/js1_5/extensions/regress-351973.js | 83 + js/src/tests/js1_5/extensions/regress-352261.js | 80 + js/src/tests/js1_5/extensions/regress-352281.js | 66 + js/src/tests/js1_5/extensions/regress-352291.js | 73 + js/src/tests/js1_5/extensions/regress-352372.js | 97 + js/src/tests/js1_5/extensions/regress-352604.js | 65 + js/src/tests/js1_5/extensions/regress-353214.js | 61 + js/src/tests/js1_5/extensions/regress-354297.js | 62 + js/src/tests/js1_5/extensions/regress-354541-01.js | 67 + js/src/tests/js1_5/extensions/regress-354541-02.js | 76 + js/src/tests/js1_5/extensions/regress-354541-03.js | 88 + js/src/tests/js1_5/extensions/regress-354541-04.js | 93 + js/src/tests/js1_5/extensions/regress-355339.js | 64 + js/src/tests/js1_5/extensions/regress-355497.js | 93 + js/src/tests/js1_5/extensions/regress-355622.js | 66 + js/src/tests/js1_5/extensions/regress-355655.js | 77 + js/src/tests/js1_5/extensions/regress-355736.js | 71 + js/src/tests/js1_5/extensions/regress-355820.js | 63 + js/src/tests/js1_5/extensions/regress-355982.js | 75 + js/src/tests/js1_5/extensions/regress-356402.js | 55 + js/src/tests/js1_5/extensions/regress-358594-01.js | 64 + js/src/tests/js1_5/extensions/regress-358594-02.js | 53 + js/src/tests/js1_5/extensions/regress-358594-03.js | 63 + js/src/tests/js1_5/extensions/regress-358594-04.js | 53 + js/src/tests/js1_5/extensions/regress-358594-05.js | 64 + js/src/tests/js1_5/extensions/regress-358594-06.js | 53 + js/src/tests/js1_5/extensions/regress-359024.js | 68 + js/src/tests/js1_5/extensions/regress-361346.js | 54 + js/src/tests/js1_5/extensions/regress-361360.js | 64 + js/src/tests/js1_5/extensions/regress-361552.js | 59 + js/src/tests/js1_5/extensions/regress-361558.js | 51 + js/src/tests/js1_5/extensions/regress-361571.js | 70 + js/src/tests/js1_5/extensions/regress-361856.js | 67 + js/src/tests/js1_5/extensions/regress-361964.js | 85 + js/src/tests/js1_5/extensions/regress-363258.js | 79 + js/src/tests/js1_5/extensions/regress-363988.js | 81 + js/src/tests/js1_5/extensions/regress-365527.js | 98 + js/src/tests/js1_5/extensions/regress-365692.js | 72 + js/src/tests/js1_5/extensions/regress-365869.js | 114 + js/src/tests/js1_5/extensions/regress-366288.js | 50 + js/src/tests/js1_5/extensions/regress-366292.js | 51 + js/src/tests/js1_5/extensions/regress-366396.js | 49 + js/src/tests/js1_5/extensions/regress-367118-01.js | 73 + js/src/tests/js1_5/extensions/regress-367118-02.js | 73 + js/src/tests/js1_5/extensions/regress-367119-01.js | 73 + js/src/tests/js1_5/extensions/regress-367119-02.js | 73 + js/src/tests/js1_5/extensions/regress-367120-01.js | 73 + js/src/tests/js1_5/extensions/regress-367120-02.js | 73 + js/src/tests/js1_5/extensions/regress-367121.js | 96 + js/src/tests/js1_5/extensions/regress-367501-01.js | 67 + js/src/tests/js1_5/extensions/regress-367501-02.js | 69 + js/src/tests/js1_5/extensions/regress-367501-03.js | 70 + js/src/tests/js1_5/extensions/regress-367501-04.js | 70 + js/src/tests/js1_5/extensions/regress-367589.js | 80 + js/src/tests/js1_5/extensions/regress-367630.js | 76 + js/src/tests/js1_5/extensions/regress-367923.js | 82 + js/src/tests/js1_5/extensions/regress-368859.js | 69 + js/src/tests/js1_5/extensions/regress-369404.js | 80 + js/src/tests/js1_5/extensions/regress-369696-01.js | 63 + js/src/tests/js1_5/extensions/regress-369696-02.js | 88 + js/src/tests/js1_5/extensions/regress-369696-03.js | 79 + js/src/tests/js1_5/extensions/regress-371636.js | 87 + js/src/tests/js1_5/extensions/regress-372309.js | 79 + js/src/tests/js1_5/extensions/regress-374589.js | 66 + js/src/tests/js1_5/extensions/regress-375183.js | 94 + js/src/tests/js1_5/extensions/regress-375344.js | 66 + js/src/tests/js1_5/extensions/regress-375801.js | 68 + js/src/tests/js1_5/extensions/regress-376052.js | 103 + js/src/tests/js1_5/extensions/regress-379523.js | 70 + js/src/tests/js1_5/extensions/regress-380581.js | 61 + js/src/tests/js1_5/extensions/regress-380889.js | 72 + js/src/tests/js1_5/extensions/regress-381211.js | 61 + js/src/tests/js1_5/extensions/regress-381304.js | 101 + js/src/tests/js1_5/extensions/regress-384680.js | 66 + js/src/tests/js1_5/extensions/regress-385134.js | 66 + js/src/tests/js1_5/extensions/regress-385393-02.js | 66 + js/src/tests/js1_5/extensions/regress-385393-09.js | 50 + js/src/tests/js1_5/extensions/regress-390597.js | 74 + js/src/tests/js1_5/extensions/regress-390598.js | 66 + js/src/tests/js1_5/extensions/regress-394967.js | 74 + js/src/tests/js1_5/extensions/regress-396326.js | 80 + js/src/tests/js1_5/extensions/regress-406572.js | 76 + js/src/tests/js1_5/extensions/regress-407019.js | 69 + js/src/tests/js1_5/extensions/regress-407501.js | 73 + js/src/tests/js1_5/extensions/regress-407720.js | 83 + js/src/tests/js1_5/extensions/regress-412926.js | 89 + js/src/tests/js1_5/extensions/regress-414755.js | 85 + js/src/tests/js1_5/extensions/regress-416354.js | 79 + js/src/tests/js1_5/extensions/regress-416460.js | 62 + js/src/tests/js1_5/extensions/regress-416834.js | 52 + js/src/tests/js1_5/extensions/regress-418730.js | 64 + js/src/tests/js1_5/extensions/regress-420612.js | 60 + js/src/tests/js1_5/extensions/regress-420869-01.js | 72 + js/src/tests/js1_5/extensions/regress-421621.js | 53 + js/src/tests/js1_5/extensions/regress-422137.js | 67 + js/src/tests/js1_5/extensions/regress-422592.js | 102 + js/src/tests/js1_5/extensions/regress-424683-01.js | 68 + js/src/tests/js1_5/extensions/regress-426711.js | 66 + js/src/tests/js1_5/extensions/regress-427196-01.js | 72 + js/src/tests/js1_5/extensions/regress-427196-02.js | 69 + js/src/tests/js1_5/extensions/regress-427196-03.js | 63 + js/src/tests/js1_5/extensions/regress-429264.js | 65 + js/src/tests/js1_5/extensions/regress-429739.js | 70 + js/src/tests/js1_5/extensions/regress-431428.js | 70 + js/src/tests/js1_5/extensions/regress-432075.js | 56 + js/src/tests/js1_5/extensions/regress-434837-01.js | 122 + js/src/tests/js1_5/extensions/regress-435345-01.js | 131 + js/src/tests/js1_5/extensions/regress-435497-01.js | 67 + js/src/tests/js1_5/extensions/regress-435497-02.js | 67 + js/src/tests/js1_5/extensions/regress-435497-03.js | 67 + js/src/tests/js1_5/extensions/regress-436741.js | 67 + js/src/tests/js1_5/extensions/regress-437288-01.js | 60 + js/src/tests/js1_5/extensions/regress-44009.js | 85 + js/src/tests/js1_5/extensions/regress-443569.js | 73 + js/src/tests/js1_5/extensions/regress-446386.js | 79 + js/src/tests/js1_5/extensions/regress-452168.js | 71 + js/src/tests/js1_5/extensions/regress-452178.js | 64 + js/src/tests/js1_5/extensions/regress-452329.js | 59 + js/src/tests/js1_5/extensions/regress-452338.js | 63 + js/src/tests/js1_5/extensions/regress-452565.js | 53 + js/src/tests/js1_5/extensions/regress-453249.js | 55 + js/src/tests/js1_5/extensions/regress-454040.js | 58 + js/src/tests/js1_5/extensions/regress-454142.js | 61 + js/src/tests/js1_5/extensions/regress-454704.js | 87 + js/src/tests/js1_5/extensions/regress-455380.js | 62 + js/src/tests/js1_5/extensions/regress-455408.js | 63 + js/src/tests/js1_5/extensions/regress-455413.js | 58 + js/src/tests/js1_5/extensions/regress-459606.js | 61 + js/src/tests/js1_5/extensions/regress-462734-02.js | 63 + js/src/tests/js1_5/extensions/regress-462734-03.js | 62 + js/src/tests/js1_5/extensions/regress-462734-04.js | 65 + js/src/tests/js1_5/extensions/regress-465145.js | 58 + js/src/tests/js1_5/extensions/regress-465276.js | 68 + js/src/tests/js1_5/extensions/regress-469625.js | 66 + js/src/tests/js1_5/extensions/regress-469761.js | 65 + js/src/tests/js1_5/extensions/regress-472599.js | 66 + js/src/tests/js1_5/extensions/regress-472787.js | 62 + js/src/tests/js1_5/extensions/regress-476447.js | 65 + js/src/tests/js1_5/extensions/regress-479487.js | 78 + js/src/tests/js1_5/extensions/regress-479551.js | 76 + js/src/tests/js1_5/extensions/regress-480579.js | 38 + js/src/tests/js1_5/extensions/regress-481516.js | 41 + js/src/tests/js1_5/extensions/regress-488995.js | 78 + js/src/tests/js1_5/extensions/regress-50447-1.js | 217 + js/src/tests/js1_5/extensions/regress-50447.js | 168 + js/src/tests/js1_5/extensions/regress-543839.js | 38 + js/src/tests/js1_5/extensions/regress-90596-001.js | 298 + js/src/tests/js1_5/extensions/regress-90596-002.js | 298 + js/src/tests/js1_5/extensions/regress-96284-001.js | 181 + js/src/tests/js1_5/extensions/regress-96284-002.js | 181 + js/src/tests/js1_5/extensions/scope-001.js | 116 + js/src/tests/js1_5/extensions/shell.js | 0 js/src/tests/js1_5/extensions/toLocaleFormat-01.js | 270 + js/src/tests/js1_5/extensions/toLocaleFormat-02.js | 137 + js/src/tests/js1_5/jstests.list | 15 + js/src/tests/js1_5/shell.js | 40 + js/src/tests/js1_5/template.js | 28 + js/src/tests/js1_6/Array/browser.js | 0 js/src/tests/js1_6/Array/filter.js | 85 + js/src/tests/js1_6/Array/jstests.list | 14 + js/src/tests/js1_6/Array/regress-290592.js | 694 + js/src/tests/js1_6/Array/regress-304828.js | 271 + js/src/tests/js1_6/Array/regress-305002.js | 57 + js/src/tests/js1_6/Array/regress-310425-01.js | 59 + js/src/tests/js1_6/Array/regress-310425-02.js | 49 + js/src/tests/js1_6/Array/regress-320887.js | 26 + js/src/tests/js1_6/Array/regress-352742-01.js | 72 + js/src/tests/js1_6/Array/regress-352742-02.js | 64 + js/src/tests/js1_6/Array/regress-386030.js | 67 + js/src/tests/js1_6/Array/regress-415451.js | 56 + js/src/tests/js1_6/Array/regress-415540.js | 53 + js/src/tests/js1_6/Array/regress-566651.js | 20 + js/src/tests/js1_6/Array/shell.js | 0 js/src/tests/js1_6/README | 1 + js/src/tests/js1_6/Regress/browser.js | 0 js/src/tests/js1_6/Regress/jstests.list | 15 + js/src/tests/js1_6/Regress/regress-301574.js | 68 + js/src/tests/js1_6/Regress/regress-311157-01.js | 56 + js/src/tests/js1_6/Regress/regress-311157-02.js | 56 + js/src/tests/js1_6/Regress/regress-314887.js | 52 + js/src/tests/js1_6/Regress/regress-320172.js | 57 + js/src/tests/js1_6/Regress/regress-350417.js | 68 + js/src/tests/js1_6/Regress/regress-351795.js | 68 + js/src/tests/js1_6/Regress/regress-352271.js | 66 + js/src/tests/js1_6/Regress/regress-353078.js | 64 + js/src/tests/js1_6/Regress/regress-355002.js | 69 + js/src/tests/js1_6/Regress/regress-372565.js | 60 + js/src/tests/js1_6/Regress/regress-378492.js | 64 + js/src/tests/js1_6/Regress/regress-475469.js | 67 + js/src/tests/js1_6/Regress/regress-476655.js | 74 + js/src/tests/js1_6/Regress/shell.js | 0 js/src/tests/js1_6/String/browser.js | 0 js/src/tests/js1_6/String/jstests.list | 2 + js/src/tests/js1_6/String/regress-306591.js | 108 + js/src/tests/js1_6/String/shell.js | 0 js/src/tests/js1_6/browser.js | 36 + js/src/tests/js1_6/decompilation/browser.js | 0 js/src/tests/js1_6/decompilation/jstests.list | 4 + js/src/tests/js1_6/decompilation/regress-352084.js | 78 + .../tests/js1_6/decompilation/regress-352613-01.js | 74 + .../tests/js1_6/decompilation/regress-352613-02.js | 74 + js/src/tests/js1_6/decompilation/shell.js | 0 js/src/tests/js1_6/extensions/browser.js | 0 js/src/tests/js1_6/extensions/jstests.list | 17 + js/src/tests/js1_6/extensions/regress-312385-01.js | 162 + js/src/tests/js1_6/extensions/regress-352392.js | 70 + js/src/tests/js1_6/extensions/regress-385393-08.js | 57 + js/src/tests/js1_6/extensions/regress-414098.js | 71 + js/src/tests/js1_6/extensions/regress-455464-01.js | 53 + js/src/tests/js1_6/extensions/regress-455464-02.js | 63 + js/src/tests/js1_6/extensions/regress-455464-03.js | 65 + js/src/tests/js1_6/extensions/regress-455464-04.js | 62 + js/src/tests/js1_6/extensions/regress-456826.js | 159 + js/src/tests/js1_6/extensions/regress-457521.js | 56 + js/src/tests/js1_6/extensions/regress-465443.js | 73 + js/src/tests/js1_6/extensions/regress-470310.js | 65 + js/src/tests/js1_6/extensions/regress-472508.js | 58 + js/src/tests/js1_6/extensions/regress-475144.js | 57 + js/src/tests/js1_6/extensions/regress-479567.js | 67 + js/src/tests/js1_6/extensions/regress-565521.js | 40 + js/src/tests/js1_6/extensions/shell.js | 0 js/src/tests/js1_6/jstests.list | 5 + js/src/tests/js1_6/shell.js | 39 + js/src/tests/js1_6/template.js | 28 + js/src/tests/js1_7/GC/browser.js | 0 js/src/tests/js1_7/GC/jstests.list | 3 + js/src/tests/js1_7/GC/regress-341675.js | 67 + js/src/tests/js1_7/GC/regress-381374.js | 91 + js/src/tests/js1_7/GC/shell.js | 0 js/src/tests/js1_7/README | 1 + js/src/tests/js1_7/block/browser.js | 0 js/src/tests/js1_7/block/jstests.list | 37 + js/src/tests/js1_7/block/order-of-operation.js | 184 + js/src/tests/js1_7/block/regress-341939.js | 57 + js/src/tests/js1_7/block/regress-343765.js | 128 + js/src/tests/js1_7/block/regress-344139.js | 124 + js/src/tests/js1_7/block/regress-344262.js | 72 + js/src/tests/js1_7/block/regress-344370.js | 60 + js/src/tests/js1_7/block/regress-344601.js | 69 + js/src/tests/js1_7/block/regress-345542.js | 62 + js/src/tests/js1_7/block/regress-347559.js | 109 + js/src/tests/js1_7/block/regress-348685.js | 79 + js/src/tests/js1_7/block/regress-349283.js | 62 + js/src/tests/js1_7/block/regress-349298.js | 70 + js/src/tests/js1_7/block/regress-349507.js | 68 + js/src/tests/js1_7/block/regress-349653.js | 62 + js/src/tests/js1_7/block/regress-349962.js | 59 + js/src/tests/js1_7/block/regress-350279.js | 68 + js/src/tests/js1_7/block/regress-350730.js | 70 + js/src/tests/js1_7/block/regress-350793-01.js | 71 + js/src/tests/js1_7/block/regress-351497.js | 68 + js/src/tests/js1_7/block/regress-351606.js | 52 + js/src/tests/js1_7/block/regress-351794.js | 66 + js/src/tests/js1_7/block/regress-352092.js | 70 + js/src/tests/js1_7/block/regress-352185.js | 70 + js/src/tests/js1_7/block/regress-352212.js | 69 + js/src/tests/js1_7/block/regress-352267.js | 60 + js/src/tests/js1_7/block/regress-352422.js | 69 + js/src/tests/js1_7/block/regress-352609.js | 89 + js/src/tests/js1_7/block/regress-352616.js | 94 + js/src/tests/js1_7/block/regress-352624.js | 70 + js/src/tests/js1_7/block/regress-352786.js | 69 + js/src/tests/js1_7/block/regress-352907.js | 69 + js/src/tests/js1_7/block/regress-357754.js | 65 + js/src/tests/js1_7/block/regress-358508.js | 69 + js/src/tests/js1_7/block/regress-376410.js | 69 + js/src/tests/js1_7/block/regress-396900.js | 63 + js/src/tests/js1_7/block/regress-411279.js | 97 + js/src/tests/js1_7/block/shell.js | 0 js/src/tests/js1_7/browser.js | 36 + js/src/tests/js1_7/decompilation/browser.js | 0 js/src/tests/js1_7/decompilation/jstests.list | 49 + .../tests/js1_7/decompilation/regress-346642-01.js | 199 + js/src/tests/js1_7/decompilation/regress-349493.js | 63 + js/src/tests/js1_7/decompilation/regress-349499.js | 63 + js/src/tests/js1_7/decompilation/regress-349602.js | 68 + js/src/tests/js1_7/decompilation/regress-349605.js | 68 + js/src/tests/js1_7/decompilation/regress-349633.js | 68 + js/src/tests/js1_7/decompilation/regress-349634.js | 63 + js/src/tests/js1_7/decompilation/regress-350704.js | 64 + .../tests/js1_7/decompilation/regress-350793-02.js | 67 + js/src/tests/js1_7/decompilation/regress-350810.js | 61 + js/src/tests/js1_7/decompilation/regress-350991.js | 86 + .../tests/js1_7/decompilation/regress-351070-01.js | 101 + .../tests/js1_7/decompilation/regress-351070-03.js | 172 + js/src/tests/js1_7/decompilation/regress-351496.js | 67 + js/src/tests/js1_7/decompilation/regress-352008.js | 65 + js/src/tests/js1_7/decompilation/regress-352011.js | 74 + js/src/tests/js1_7/decompilation/regress-352015.js | 68 + js/src/tests/js1_7/decompilation/regress-352022.js | 68 + js/src/tests/js1_7/decompilation/regress-352025.js | 62 + js/src/tests/js1_7/decompilation/regress-352026.js | 78 + js/src/tests/js1_7/decompilation/regress-352068.js | 63 + js/src/tests/js1_7/decompilation/regress-352079.js | 78 + js/src/tests/js1_7/decompilation/regress-352198.js | 63 + js/src/tests/js1_7/decompilation/regress-352217.js | 76 + js/src/tests/js1_7/decompilation/regress-352266.js | 79 + js/src/tests/js1_7/decompilation/regress-352268.js | 76 + js/src/tests/js1_7/decompilation/regress-352269.js | 62 + js/src/tests/js1_7/decompilation/regress-352272.js | 62 + js/src/tests/js1_7/decompilation/regress-352283.js | 62 + js/src/tests/js1_7/decompilation/regress-352402.js | 61 + js/src/tests/js1_7/decompilation/regress-352415.js | 61 + js/src/tests/js1_7/decompilation/regress-352441.js | 63 + js/src/tests/js1_7/decompilation/regress-352732.js | 92 + js/src/tests/js1_7/decompilation/regress-355004.js | 61 + .../tests/js1_7/decompilation/regress-355049-01.js | 61 + .../tests/js1_7/decompilation/regress-355049-02.js | 61 + js/src/tests/js1_7/decompilation/regress-355105.js | 61 + js/src/tests/js1_7/decompilation/regress-355635.js | 61 + js/src/tests/js1_7/decompilation/regress-355786.js | 62 + js/src/tests/js1_7/decompilation/regress-356247.js | 102 + js/src/tests/js1_7/decompilation/regress-371802.js | 62 + js/src/tests/js1_7/decompilation/regress-374713.js | 62 + js/src/tests/js1_7/decompilation/regress-375794.js | 62 + js/src/tests/js1_7/decompilation/regress-379925.js | 62 + js/src/tests/js1_7/decompilation/regress-380506.js | 67 + js/src/tests/js1_7/decompilation/regress-410571.js | 141 + js/src/tests/js1_7/decompilation/regress-410649.js | 61 + js/src/tests/js1_7/decompilation/regress-429252.js | 70 + js/src/tests/js1_7/decompilation/shell.js | 0 js/src/tests/js1_7/expressions/browser.js | 0 .../tests/js1_7/expressions/destructuring-scope.js | 95 + js/src/tests/js1_7/expressions/jstests.list | 11 + js/src/tests/js1_7/expressions/regress-346203.js | 60 + .../tests/js1_7/expressions/regress-346645-01.js | 67 + .../tests/js1_7/expressions/regress-346645-02.js | 67 + .../tests/js1_7/expressions/regress-346645-03.js | 67 + js/src/tests/js1_7/expressions/regress-349624.js | 60 + js/src/tests/js1_7/expressions/regress-349818.js | 60 + js/src/tests/js1_7/expressions/regress-418051.js | 66 + js/src/tests/js1_7/expressions/regress-421806.js | 73 + js/src/tests/js1_7/expressions/regress-451340.js | 59 + js/src/tests/js1_7/expressions/shell.js | 0 js/src/tests/js1_7/extensions/basic-Iterator.js | 197 + js/src/tests/js1_7/extensions/basic-for-each.js | 122 + js/src/tests/js1_7/extensions/basic-for-in.js | 110 + js/src/tests/js1_7/extensions/browser.js | 0 .../tests/js1_7/extensions/destructuring-order.js | 184 + js/src/tests/js1_7/extensions/iterator-ctor.js | 135 + js/src/tests/js1_7/extensions/jstests.list | 70 + js/src/tests/js1_7/extensions/regress-346021.js | 77 + js/src/tests/js1_7/extensions/regress-346642-02.js | 67 + js/src/tests/js1_7/extensions/regress-346642-06.js | 108 + js/src/tests/js1_7/extensions/regress-346773.js | 84 + js/src/tests/js1_7/extensions/regress-349619.js | 60 + js/src/tests/js1_7/extensions/regress-350312.js | 112 + js/src/tests/js1_7/extensions/regress-351070-02.js | 101 + js/src/tests/js1_7/extensions/regress-351102-03.js | 76 + js/src/tests/js1_7/extensions/regress-351102-04.js | 66 + js/src/tests/js1_7/extensions/regress-351102-05.js | 66 + js/src/tests/js1_7/extensions/regress-351102-07.js | 75 + js/src/tests/js1_7/extensions/regress-352797-01.js | 67 + js/src/tests/js1_7/extensions/regress-352885-01.js | 61 + js/src/tests/js1_7/extensions/regress-352885-02.js | 98 + js/src/tests/js1_7/extensions/regress-353214-01.js | 78 + js/src/tests/js1_7/extensions/regress-353214-02.js | 62 + js/src/tests/js1_7/extensions/regress-353249.js | 66 + js/src/tests/js1_7/extensions/regress-353454.js | 69 + js/src/tests/js1_7/extensions/regress-354499-01.js | 78 + js/src/tests/js1_7/extensions/regress-354499-02.js | 81 + js/src/tests/js1_7/extensions/regress-354945-01.js | 66 + js/src/tests/js1_7/extensions/regress-354945-02.js | 70 + js/src/tests/js1_7/extensions/regress-355052-01.js | 69 + js/src/tests/js1_7/extensions/regress-355052-02.js | 69 + js/src/tests/js1_7/extensions/regress-355052-03.js | 75 + js/src/tests/js1_7/extensions/regress-355145.js | 65 + js/src/tests/js1_7/extensions/regress-355410.js | 72 + js/src/tests/js1_7/extensions/regress-355512.js | 70 + js/src/tests/js1_7/extensions/regress-355583.js | 71 + js/src/tests/js1_7/extensions/regress-363040-01.js | 97 + js/src/tests/js1_7/extensions/regress-363040-02.js | 96 + js/src/tests/js1_7/extensions/regress-366668-01.js | 63 + js/src/tests/js1_7/extensions/regress-366668-02.js | 63 + js/src/tests/js1_7/extensions/regress-367629.js | 70 + js/src/tests/js1_7/extensions/regress-368213.js | 49 + js/src/tests/js1_7/extensions/regress-368224.js | 60 + js/src/tests/js1_7/extensions/regress-372364.js | 68 + js/src/tests/js1_7/extensions/regress-379566.js | 77 + js/src/tests/js1_7/extensions/regress-380933.js | 80 + js/src/tests/js1_7/extensions/regress-381301.js | 64 + js/src/tests/js1_7/extensions/regress-381303.js | 67 + js/src/tests/js1_7/extensions/regress-387955-01.js | 72 + js/src/tests/js1_7/extensions/regress-387955-02.js | 74 + js/src/tests/js1_7/extensions/regress-392308.js | 79 + js/src/tests/js1_7/extensions/regress-396326.js | 69 + js/src/tests/js1_7/extensions/regress-429266.js | 72 + js/src/tests/js1_7/extensions/regress-453955.js | 63 + js/src/tests/js1_7/extensions/regress-455982-01.js | 58 + js/src/tests/js1_7/extensions/regress-455982-02.js | 58 + js/src/tests/js1_7/extensions/regress-458679.js | 84 + js/src/tests/js1_7/extensions/regress-469234.js | 64 + js/src/tests/js1_7/extensions/regress-469405-01.js | 59 + js/src/tests/js1_7/extensions/regress-469405-02.js | 57 + js/src/tests/js1_7/extensions/regress-470176.js | 70 + js/src/tests/js1_7/extensions/regress-470300-01.js | 64 + js/src/tests/js1_7/extensions/regress-470300-02.js | 64 + js/src/tests/js1_7/extensions/regress-473282.js | 53 + js/src/tests/js1_7/extensions/regress-474771-01.js | 66 + js/src/tests/js1_7/extensions/regress-474771-02.js | 54 + js/src/tests/js1_7/extensions/regress-476257.js | 92 + js/src/tests/js1_7/extensions/regress-477048.js | 66 + js/src/tests/js1_7/extensions/regress-589112.js | 6 + js/src/tests/js1_7/extensions/regress-590813.js | 23 + js/src/tests/js1_7/extensions/regress-591450.js | 12 + js/src/tests/js1_7/extensions/shell.js | 0 js/src/tests/js1_7/geniter/326466-01.js | 77 + js/src/tests/js1_7/geniter/browser.js | 0 .../js1_7/geniter/builtin-Iterator-function.js | 121 + js/src/tests/js1_7/geniter/evens.js | 57 + .../js1_7/geniter/fibonacci-matrix-generator.js | 96 + js/src/tests/js1_7/geniter/iterator-toString.js | 75 + js/src/tests/js1_7/geniter/jstests.list | 49 + .../tests/js1_7/geniter/message-value-passing.js | 120 + js/src/tests/js1_7/geniter/multiple-close.js | 97 + js/src/tests/js1_7/geniter/nested-yield.js | 90 + js/src/tests/js1_7/geniter/pi-generator.js | 91 + js/src/tests/js1_7/geniter/regress-345736.js | 79 + js/src/tests/js1_7/geniter/regress-345855.js | 125 + js/src/tests/js1_7/geniter/regress-345879-01.js | 65 + js/src/tests/js1_7/geniter/regress-345879-02.js | 66 + js/src/tests/js1_7/geniter/regress-347593.js | 87 + js/src/tests/js1_7/geniter/regress-347739.js | 80 + js/src/tests/js1_7/geniter/regress-349012-01.js | 83 + js/src/tests/js1_7/geniter/regress-349012-02.js | 93 + js/src/tests/js1_7/geniter/regress-349012-03.js | 74 + js/src/tests/js1_7/geniter/regress-349012-04.js | 74 + js/src/tests/js1_7/geniter/regress-349012-05.js | 76 + js/src/tests/js1_7/geniter/regress-349023-01.js | 74 + js/src/tests/js1_7/geniter/regress-349023-02.js | 61 + js/src/tests/js1_7/geniter/regress-349023-03.js | 61 + js/src/tests/js1_7/geniter/regress-349331.js | 126 + js/src/tests/js1_7/geniter/regress-349362.js | 61 + js/src/tests/js1_7/geniter/regress-349851.js | 68 + js/src/tests/js1_7/geniter/regress-350621.js | 95 + js/src/tests/js1_7/geniter/regress-350809.js | 68 + js/src/tests/js1_7/geniter/regress-351120.js | 68 + js/src/tests/js1_7/geniter/regress-351514.js | 68 + js/src/tests/js1_7/geniter/regress-352197.js | 68 + js/src/tests/js1_7/geniter/regress-352605.js | 67 + js/src/tests/js1_7/geniter/regress-352876.js | 74 + js/src/tests/js1_7/geniter/regress-355834.js | 62 + js/src/tests/js1_7/geniter/regress-359062.js | 73 + js/src/tests/js1_7/geniter/regress-366941.js | 83 + js/src/tests/js1_7/geniter/regress-382335.js | 68 + js/src/tests/js1_7/geniter/regress-387871.js | 74 + js/src/tests/js1_7/geniter/regress-390918.js | 79 + js/src/tests/js1_7/geniter/regress-392310.js | 81 + js/src/tests/js1_7/geniter/regress-466206.js | 70 + js/src/tests/js1_7/geniter/send-no-rhs.js | 89 + js/src/tests/js1_7/geniter/sequential-yields.js | 104 + js/src/tests/js1_7/geniter/shell.js | 0 js/src/tests/js1_7/geniter/simple-fib.js | 87 + js/src/tests/js1_7/geniter/throw-after-close.js | 122 + js/src/tests/js1_7/geniter/throw-forever.js | 117 + js/src/tests/js1_7/geniter/unreachable-yield.js | 89 + js/src/tests/js1_7/geniter/yield-undefined.js | 95 + js/src/tests/js1_7/iterable/browser.js | 0 js/src/tests/js1_7/iterable/jstests.list | 16 + js/src/tests/js1_7/iterable/regress-340526-01.js | 60 + js/src/tests/js1_7/iterable/regress-340526-02.js | 74 + js/src/tests/js1_7/iterable/regress-341496.js | 51 + js/src/tests/js1_7/iterable/regress-341499.js | 65 + js/src/tests/js1_7/iterable/regress-341510.js | 61 + js/src/tests/js1_7/iterable/regress-341815.js | 125 + js/src/tests/js1_7/iterable/regress-341821.js | 114 + js/src/tests/js1_7/iterable/regress-354750-01.js | 74 + js/src/tests/js1_7/iterable/regress-355025.js | 60 + js/src/tests/js1_7/iterable/regress-355075-01.js | 70 + js/src/tests/js1_7/iterable/regress-355075-02.js | 70 + js/src/tests/js1_7/iterable/regress-355090.js | 69 + js/src/tests/js1_7/iterable/regress-412467.js | 68 + js/src/tests/js1_7/iterable/regress-415922.js | 81 + js/src/tests/js1_7/iterable/regress-568056.js | 24 + js/src/tests/js1_7/iterable/shell.js | 0 js/src/tests/js1_7/jstests.list | 10 + js/src/tests/js1_7/lexical/browser.js | 0 js/src/tests/js1_7/lexical/jstests.list | 5 + js/src/tests/js1_7/lexical/regress-336376-01.js | 440 + js/src/tests/js1_7/lexical/regress-346642-03.js | 168 + js/src/tests/js1_7/lexical/regress-346642-04.js | 69 + js/src/tests/js1_7/lexical/regress-351515.js | 129 + js/src/tests/js1_7/lexical/shell.js | 0 js/src/tests/js1_7/regexp/browser.js | 0 js/src/tests/js1_7/regexp/jstests.list | 2 + js/src/tests/js1_7/regexp/shell.js | 0 js/src/tests/js1_7/regexp/yflag.js | 120 + js/src/tests/js1_7/regress/browser.js | 0 js/src/tests/js1_7/regress/jstests.list | 68 + js/src/tests/js1_7/regress/regress-350387.js | 69 + js/src/tests/js1_7/regress/regress-351503-01.js | 117 + js/src/tests/js1_7/regress/regress-351503-02.js | 122 + js/src/tests/js1_7/regress/regress-352640-01.js | 66 + js/src/tests/js1_7/regress/regress-352640-02.js | 66 + js/src/tests/js1_7/regress/regress-352640-03.js | 66 + js/src/tests/js1_7/regress/regress-352640-04.js | 66 + js/src/tests/js1_7/regress/regress-352797-02.js | 69 + js/src/tests/js1_7/regress/regress-352870-01.js | 69 + js/src/tests/js1_7/regress/regress-352870-02.js | 68 + js/src/tests/js1_7/regress/regress-352870-03.js | 70 + js/src/tests/js1_7/regress/regress-353079.js | 61 + js/src/tests/js1_7/regress/regress-355023.js | 63 + js/src/tests/js1_7/regress/regress-355832-01.js | 62 + js/src/tests/js1_7/regress/regress-355832-02.js | 62 + js/src/tests/js1_7/regress/regress-361566.js | 59 + js/src/tests/js1_7/regress/regress-363040-01.js | 127 + js/src/tests/js1_7/regress/regress-363040-02.js | 99 + js/src/tests/js1_7/regress/regress-369666-01.js | 91 + js/src/tests/js1_7/regress/regress-369666-02.js | 95 + js/src/tests/js1_7/regress/regress-372331.js | 87 + js/src/tests/js1_7/regress/regress-373827-01.js | 60 + js/src/tests/js1_7/regress/regress-373827-02.js | 66 + js/src/tests/js1_7/regress/regress-373828.js | 67 + js/src/tests/js1_7/regress/regress-375695.js | 59 + js/src/tests/js1_7/regress/regress-379442.js | 60 + js/src/tests/js1_7/regress/regress-379483.js | 60 + js/src/tests/js1_7/regress/regress-385133-01.js | 70 + js/src/tests/js1_7/regress/regress-385133-02.js | 68 + js/src/tests/js1_7/regress/regress-385393-05.js | 76 + js/src/tests/js1_7/regress/regress-387951.js | 60 + js/src/tests/js1_7/regress/regress-406477.js | 80 + js/src/tests/js1_7/regress/regress-407727-01.js | 49 + js/src/tests/js1_7/regress/regress-407727-02.js | 51 + js/src/tests/js1_7/regress/regress-407957.js | 62 + js/src/tests/js1_7/regress/regress-410649.js | 74 + js/src/tests/js1_7/regress/regress-414553.js | 54 + js/src/tests/js1_7/regress/regress-416601.js | 69 + js/src/tests/js1_7/regress/regress-416705.js | 72 + js/src/tests/js1_7/regress/regress-418641.js | 112 + js/src/tests/js1_7/regress/regress-419803.js | 63 + js/src/tests/js1_7/regress/regress-420399.js | 68 + js/src/tests/js1_7/regress/regress-428706.js | 60 + js/src/tests/js1_7/regress/regress-428708.js | 60 + js/src/tests/js1_7/regress/regress-452703.js | 53 + js/src/tests/js1_7/regress/regress-452960.js | 65 + js/src/tests/js1_7/regress/regress-453049.js | 63 + js/src/tests/js1_7/regress/regress-453051.js | 63 + js/src/tests/js1_7/regress/regress-453411.js | 64 + js/src/tests/js1_7/regress/regress-461235.js | 64 + js/src/tests/js1_7/regress/regress-461945.js | 64 + js/src/tests/js1_7/regress/regress-462071.js | 64 + js/src/tests/js1_7/regress/regress-462282.js | 64 + js/src/tests/js1_7/regress/regress-462388.js | 64 + js/src/tests/js1_7/regress/regress-462407.js | 53 + js/src/tests/js1_7/regress/regress-464403.js | 67 + js/src/tests/js1_7/regress/regress-465236.js | 62 + js/src/tests/js1_7/regress/regress-465424.js | 64 + js/src/tests/js1_7/regress/regress-465484.js | 62 + js/src/tests/js1_7/regress/regress-465686.js | 67 + js/src/tests/js1_7/regress/regress-469239-01.js | 70 + js/src/tests/js1_7/regress/regress-469239-02.js | 70 + js/src/tests/js1_7/regress/regress-470223.js | 72 + js/src/tests/js1_7/regress/regress-470388-01.js | 60 + js/src/tests/js1_7/regress/regress-470388-02.js | 65 + js/src/tests/js1_7/regress/regress-470388-03.js | 64 + js/src/tests/js1_7/regress/regress-474771.js | 78 + js/src/tests/js1_7/regress/shell.js | 0 js/src/tests/js1_7/shell.js | 46 + js/src/tests/js1_7/template.js | 28 + js/src/tests/js1_8/README | 1 + js/src/tests/js1_8/browser.js | 36 + js/src/tests/js1_8/decompilation/browser.js | 0 js/src/tests/js1_8/decompilation/jstests.list | 12 + js/src/tests/js1_8/decompilation/regress-260106.js | 63 + js/src/tests/js1_8/decompilation/regress-346749.js | 31 + js/src/tests/js1_8/decompilation/regress-381372.js | 62 + js/src/tests/js1_8/decompilation/regress-381504.js | 77 + .../tests/js1_8/decompilation/regress-381963-01.js | 62 + .../tests/js1_8/decompilation/regress-381963-02.js | 64 + js/src/tests/js1_8/decompilation/regress-382981.js | 66 + js/src/tests/js1_8/decompilation/regress-443074.js | 62 + js/src/tests/js1_8/decompilation/regress-460504.js | 62 + js/src/tests/js1_8/decompilation/regress-461233.js | 33 + .../tests/js1_8/decompilation/regress-469625-01.js | 35 + js/src/tests/js1_8/decompilation/shell.js | 0 js/src/tests/js1_8/extensions/browser.js | 0 js/src/tests/js1_8/extensions/dekker.js | 67 + js/src/tests/js1_8/extensions/expclo.js | 23 + js/src/tests/js1_8/extensions/expclo2.js | 23 + js/src/tests/js1_8/extensions/for-in.js | 54 + js/src/tests/js1_8/extensions/jstests.list | 46 + js/src/tests/js1_8/extensions/lamport.js | 125 + js/src/tests/js1_8/extensions/peterson.js | 88 + js/src/tests/js1_8/extensions/regress-353116.js | 111 + js/src/tests/js1_8/extensions/regress-378789.js | 66 + js/src/tests/js1_8/extensions/regress-385393-01.js | 66 + js/src/tests/js1_8/extensions/regress-385393-10.js | 66 + js/src/tests/js1_8/extensions/regress-385393-11.js | 67 + js/src/tests/js1_8/extensions/regress-385729.js | 87 + js/src/tests/js1_8/extensions/regress-394709.js | 92 + js/src/tests/js1_8/extensions/regress-415721.js | 43 + js/src/tests/js1_8/extensions/regress-417131.js | 107 + js/src/tests/js1_8/extensions/regress-417817.js | 86 + js/src/tests/js1_8/extensions/regress-419091.js | 83 + js/src/tests/js1_8/extensions/regress-422269.js | 88 + js/src/tests/js1_8/extensions/regress-445818.js | 72 + js/src/tests/js1_8/extensions/regress-446169-01.js | 81 + js/src/tests/js1_8/extensions/regress-446169-02.js | 79 + js/src/tests/js1_8/extensions/regress-452476.js | 61 + js/src/tests/js1_8/extensions/regress-452913.js | 50 + js/src/tests/js1_8/extensions/regress-454744.js | 70 + js/src/tests/js1_8/extensions/regress-455973.js | 61 + js/src/tests/js1_8/extensions/regress-465337.js | 64 + js/src/tests/js1_8/extensions/regress-465453.js | 76 + js/src/tests/js1_8/extensions/regress-469625.js | 44 + js/src/tests/js1_8/extensions/regress-471197.js | 78 + js/src/tests/js1_8/extensions/regress-472450-03.js | 66 + js/src/tests/js1_8/extensions/regress-472450-04.js | 68 + js/src/tests/js1_8/extensions/regress-473040.js | 59 + js/src/tests/js1_8/extensions/regress-475971.js | 89 + js/src/tests/js1_8/extensions/regress-476414-01.js | 98 + js/src/tests/js1_8/extensions/regress-476414-02.js | 99 + js/src/tests/js1_8/extensions/regress-476427.js | 68 + js/src/tests/js1_8/extensions/regress-476653.js | 68 + js/src/tests/js1_8/extensions/regress-476869.js | 78 + js/src/tests/js1_8/extensions/regress-476871-01.js | 54 + js/src/tests/js1_8/extensions/regress-476871-02.js | 67 + js/src/tests/js1_8/extensions/regress-479252.js | 72 + js/src/tests/js1_8/extensions/regress-479381.js | 50 + js/src/tests/js1_8/extensions/regress-481989.js | 53 + js/src/tests/js1_8/extensions/regress-482263.js | 60 + js/src/tests/js1_8/extensions/shell.js | 0 js/src/tests/js1_8/extensions/simple-tree.js | 51 + js/src/tests/js1_8/genexps/browser.js | 0 js/src/tests/js1_8/genexps/jstests.list | 10 + js/src/tests/js1_8/genexps/regress-347739.js | 83 + js/src/tests/js1_8/genexps/regress-349012-01.js | 86 + js/src/tests/js1_8/genexps/regress-349326.js | 180 + js/src/tests/js1_8/genexps/regress-349331.js | 125 + js/src/tests/js1_8/genexps/regress-380237-01.js | 233 + js/src/tests/js1_8/genexps/regress-380237-02.js | 62 + js/src/tests/js1_8/genexps/regress-380237-03.js | 189 + js/src/tests/js1_8/genexps/regress-380237-04.js | 328 + js/src/tests/js1_8/genexps/regress-384991.js | 91 + js/src/tests/js1_8/genexps/shell.js | 0 js/src/tests/js1_8/jstests.list | 4 + js/src/tests/js1_8/regress/browser.js | 0 js/src/tests/js1_8/regress/jstests.list | 86 + js/src/tests/js1_8/regress/regress-366941.js | 74 + js/src/tests/js1_8/regress/regress-384412.js | 230 + js/src/tests/js1_8/regress/regress-384758.js | 68 + js/src/tests/js1_8/regress/regress-404734.js | 63 + js/src/tests/js1_8/regress/regress-427798.js | 90 + js/src/tests/js1_8/regress/regress-433279-01.js | 60 + js/src/tests/js1_8/regress/regress-433279-02.js | 65 + js/src/tests/js1_8/regress/regress-433279-03.js | 65 + js/src/tests/js1_8/regress/regress-442333-01.js | 69 + js/src/tests/js1_8/regress/regress-452491.js | 63 + js/src/tests/js1_8/regress/regress-453492.js | 60 + js/src/tests/js1_8/regress/regress-455981-01.js | 68 + js/src/tests/js1_8/regress/regress-455981-02.js | 68 + js/src/tests/js1_8/regress/regress-457065-01.js | 66 + js/src/tests/js1_8/regress/regress-457065-02.js | 64 + js/src/tests/js1_8/regress/regress-458076.js | 64 + js/src/tests/js1_8/regress/regress-459185.js | 66 + js/src/tests/js1_8/regress/regress-459186.js | 66 + js/src/tests/js1_8/regress/regress-459389.js | 152 + js/src/tests/js1_8/regress/regress-461930.js | 65 + js/src/tests/js1_8/regress/regress-461932.js | 65 + js/src/tests/js1_8/regress/regress-463334-01.js | 65 + js/src/tests/js1_8/regress/regress-463334-02.js | 67 + js/src/tests/js1_8/regress/regress-463783.js | 67 + js/src/tests/js1_8/regress/regress-464092-01.js | 60 + js/src/tests/js1_8/regress/regress-464092-02.js | 67 + js/src/tests/js1_8/regress/regress-464096.js | 66 + js/src/tests/js1_8/regress/regress-464418.js | 79 + js/src/tests/js1_8/regress/regress-464978.js | 64 + js/src/tests/js1_8/regress/regress-465220.js | 77 + js/src/tests/js1_8/regress/regress-465234.js | 67 + js/src/tests/js1_8/regress/regress-465239.js | 67 + js/src/tests/js1_8/regress/regress-465241.js | 67 + js/src/tests/js1_8/regress/regress-465249.js | 64 + js/src/tests/js1_8/regress/regress-465261.js | 68 + js/src/tests/js1_8/regress/regress-465308.js | 65 + js/src/tests/js1_8/regress/regress-465454.js | 65 + js/src/tests/js1_8/regress/regress-465460-01.js | 66 + js/src/tests/js1_8/regress/regress-465460-02.js | 64 + js/src/tests/js1_8/regress/regress-465460-03.js | 64 + js/src/tests/js1_8/regress/regress-465460-04.js | 64 + js/src/tests/js1_8/regress/regress-465460-05.js | 64 + js/src/tests/js1_8/regress/regress-465460-06.js | 64 + js/src/tests/js1_8/regress/regress-465460-07.js | 73 + js/src/tests/js1_8/regress/regress-465460-08.js | 64 + js/src/tests/js1_8/regress/regress-465460-09.js | 64 + js/src/tests/js1_8/regress/regress-465460-10.js | 64 + js/src/tests/js1_8/regress/regress-465460-11.js | 64 + js/src/tests/js1_8/regress/regress-465460-12.js | 64 + js/src/tests/js1_8/regress/regress-465483.js | 64 + js/src/tests/js1_8/regress/regress-465567-01.js | 63 + js/src/tests/js1_8/regress/regress-465567-02.js | 59 + js/src/tests/js1_8/regress/regress-465688.js | 62 + js/src/tests/js1_8/regress/regress-466128.js | 65 + js/src/tests/js1_8/regress/regress-466787.js | 67 + js/src/tests/js1_8/regress/regress-467495-01.js | 60 + js/src/tests/js1_8/regress/regress-467495-02.js | 66 + js/src/tests/js1_8/regress/regress-467495-03.js | 79 + js/src/tests/js1_8/regress/regress-467495-04.js | 74 + js/src/tests/js1_8/regress/regress-467495-05.js | 63 + js/src/tests/js1_8/regress/regress-467495-06.js | 76 + js/src/tests/js1_8/regress/regress-468711.js | 64 + js/src/tests/js1_8/regress/regress-469547.js | 67 + js/src/tests/js1_8/regress/regress-469625-02.js | 35 + js/src/tests/js1_8/regress/regress-469625-03.js | 42 + js/src/tests/js1_8/regress/regress-471373.js | 77 + js/src/tests/js1_8/regress/regress-471660.js | 71 + js/src/tests/js1_8/regress/regress-472450-01.js | 65 + js/src/tests/js1_8/regress/regress-472450-02.js | 65 + js/src/tests/js1_8/regress/regress-472528-01.js | 73 + js/src/tests/js1_8/regress/regress-472528-02.js | 73 + js/src/tests/js1_8/regress/regress-472703.js | 72 + js/src/tests/js1_8/regress/regress-474769.js | 69 + js/src/tests/js1_8/regress/regress-474771.js | 72 + js/src/tests/js1_8/regress/regress-474935.js | 74 + js/src/tests/js1_8/regress/regress-476655.js | 73 + js/src/tests/js1_8/regress/regress-477234.js | 82 + js/src/tests/js1_8/regress/regress-477581.js | 37 + js/src/tests/js1_8/regress/regress-478205.js | 64 + js/src/tests/js1_8/regress/regress-479353.js | 55 + js/src/tests/js1_8/regress/regress-479740.js | 70 + js/src/tests/js1_8/regress/regress-481800.js | 64 + js/src/tests/js1_8/regress/regress-483749.js | 59 + js/src/tests/js1_8/regress/regress-499524.js | 50 + js/src/tests/js1_8/regress/regress-532491.js | 70 + js/src/tests/js1_8/regress/shell.js | 0 js/src/tests/js1_8/shell.js | 46 + js/src/tests/js1_8/template.js | 28 + js/src/tests/js1_8_1/JSON/browser.js | 0 js/src/tests/js1_8_1/JSON/jstests.list | 3 + js/src/tests/js1_8_1/JSON/regress-458959.js | 64 + js/src/tests/js1_8_1/JSON/regress-459293.js | 25 + js/src/tests/js1_8_1/JSON/shell.js | 0 js/src/tests/js1_8_1/README | 1 + js/src/tests/js1_8_1/String/browser.js | 0 js/src/tests/js1_8_1/String/jstests.list | 2 + js/src/tests/js1_8_1/String/regress-305064.js | 176 + js/src/tests/js1_8_1/String/shell.js | 0 js/src/tests/js1_8_1/browser.js | 36 + js/src/tests/js1_8_1/decompilation/browser.js | 0 js/src/tests/js1_8_1/decompilation/jstests.list | 21 + .../js1_8_1/decompilation/regress-346642-01.js | 194 + .../tests/js1_8_1/decompilation/regress-349605.js | 68 + .../tests/js1_8_1/decompilation/regress-349634.js | 63 + .../tests/js1_8_1/decompilation/regress-350991.js | 86 + .../js1_8_1/decompilation/regress-351070-01.js | 101 + .../tests/js1_8_1/decompilation/regress-351336.js | 62 + .../tests/js1_8_1/decompilation/regress-351626.js | 63 + .../tests/js1_8_1/decompilation/regress-352011.js | 74 + .../tests/js1_8_1/decompilation/regress-352022.js | 68 + .../tests/js1_8_1/decompilation/regress-352026.js | 78 + .../tests/js1_8_1/decompilation/regress-352609.js | 89 + .../tests/js1_8_1/decompilation/regress-353249.js | 66 + .../tests/js1_8_1/decompilation/regress-354878.js | 61 + .../tests/js1_8_1/decompilation/regress-371802.js | 62 + .../js1_8_1/decompilation/regress-373678-01.js | 61 + .../js1_8_1/decompilation/regress-380237-03.js | 189 + .../js1_8_1/decompilation/regress-380237-04.js | 332 + .../tests/js1_8_1/decompilation/regress-443074.js | 62 + .../js1_8_1/decompilation/regress-466905-03.js | 86 + .../tests/js1_8_1/decompilation/regress-530537.js | 40 + js/src/tests/js1_8_1/decompilation/shell.js | 0 js/src/tests/js1_8_1/extensions/browser.js | 0 js/src/tests/js1_8_1/extensions/jstests.list | 15 + .../js1_8_1/extensions/new-parenthesization.js | 21 + js/src/tests/js1_8_1/extensions/regress-352281.js | 66 + .../tests/js1_8_1/extensions/regress-353214-02.js | 62 + .../tests/js1_8_1/extensions/regress-437288-01.js | 68 + .../tests/js1_8_1/extensions/regress-452498-162.js | 58 + .../tests/js1_8_1/extensions/regress-452498-193.js | 65 + .../tests/js1_8_1/extensions/regress-452498-196.js | 75 + .../tests/js1_8_1/extensions/regress-452498-224.js | 62 + .../tests/js1_8_1/extensions/regress-466905-04.js | 81 + .../tests/js1_8_1/extensions/regress-466905-05.js | 76 + js/src/tests/js1_8_1/extensions/regress-477158.js | 65 + js/src/tests/js1_8_1/extensions/regress-477187.js | 72 + js/src/tests/js1_8_1/extensions/regress-520572.js | 41 + js/src/tests/js1_8_1/extensions/shell.js | 0 js/src/tests/js1_8_1/extensions/strict-warning.js | 31 + js/src/tests/js1_8_1/jit/browser.js | 0 js/src/tests/js1_8_1/jit/jstests.list | 24 + js/src/tests/js1_8_1/jit/math-jit-tests.js | 729 + js/src/tests/js1_8_1/jit/regress-451673.js | 115 + js/src/tests/js1_8_1/jit/regress-451974-01.js | 86 + js/src/tests/js1_8_1/jit/regress-451974-02.js | 97 + js/src/tests/js1_8_1/jit/regress-452498-01.js | 105 + js/src/tests/js1_8_1/jit/regress-458838.js | 97 + js/src/tests/js1_8_1/jit/regress-462459-01.js | 107 + js/src/tests/js1_8_1/jit/regress-462459-02.js | 106 + js/src/tests/js1_8_1/jit/regress-462459-03.js | 107 + js/src/tests/js1_8_1/jit/regress-462459-04.js | 107 + js/src/tests/js1_8_1/jit/regress-462459-05.js | 107 + js/src/tests/js1_8_1/jit/regress-462459-06.js | 107 + js/src/tests/js1_8_1/jit/regress-462459-07.js | 107 + js/src/tests/js1_8_1/jit/regress-462459-08.js | 107 + js/src/tests/js1_8_1/jit/regress-462459-09.js | 107 + js/src/tests/js1_8_1/jit/regress-462459-10.js | 107 + js/src/tests/js1_8_1/jit/regress-462459-11.js | 107 + js/src/tests/js1_8_1/jit/regress-462459-12.js | 107 + js/src/tests/js1_8_1/jit/regress-469927.js | 78 + js/src/tests/js1_8_1/jit/regress-470739.js | 80 + js/src/tests/js1_8_1/jit/regress-471635.js | 90 + js/src/tests/js1_8_1/jit/regress-489682.js | 65 + js/src/tests/js1_8_1/jit/shell.js | 4 + .../tests/js1_8_1/jit/testDeepBailFromNonNative.js | 59 + js/src/tests/js1_8_1/jstests.list | 7 + js/src/tests/js1_8_1/regress/browser.js | 0 js/src/tests/js1_8_1/regress/jstests.list | 87 + js/src/tests/js1_8_1/regress/regress-420399.js | 68 + js/src/tests/js1_8_1/regress/regress-452498-006.js | 77 + js/src/tests/js1_8_1/regress/regress-452498-027.js | 70 + js/src/tests/js1_8_1/regress/regress-452498-030.js | 63 + js/src/tests/js1_8_1/regress/regress-452498-038.js | 62 + js/src/tests/js1_8_1/regress/regress-452498-039.js | 67 + js/src/tests/js1_8_1/regress/regress-452498-040.js | 69 + js/src/tests/js1_8_1/regress/regress-452498-050.js | 76 + js/src/tests/js1_8_1/regress/regress-452498-051.js | 48 + .../tests/js1_8_1/regress/regress-452498-052-a.js | 41 + js/src/tests/js1_8_1/regress/regress-452498-052.js | 51 + js/src/tests/js1_8_1/regress/regress-452498-053.js | 80 + js/src/tests/js1_8_1/regress/regress-452498-054.js | 42 + js/src/tests/js1_8_1/regress/regress-452498-058.js | 63 + js/src/tests/js1_8_1/regress/regress-452498-062.js | 76 + js/src/tests/js1_8_1/regress/regress-452498-063.js | 67 + js/src/tests/js1_8_1/regress/regress-452498-068.js | 118 + js/src/tests/js1_8_1/regress/regress-452498-071.js | 63 + js/src/tests/js1_8_1/regress/regress-452498-072.js | 63 + js/src/tests/js1_8_1/regress/regress-452498-073.js | 70 + js/src/tests/js1_8_1/regress/regress-452498-074.js | 66 + js/src/tests/js1_8_1/regress/regress-452498-075.js | 64 + js/src/tests/js1_8_1/regress/regress-452498-076.js | 63 + js/src/tests/js1_8_1/regress/regress-452498-077.js | 66 + js/src/tests/js1_8_1/regress/regress-452498-079.js | 34 + js/src/tests/js1_8_1/regress/regress-452498-082.js | 184 + js/src/tests/js1_8_1/regress/regress-452498-091.js | 64 + js/src/tests/js1_8_1/regress/regress-452498-092.js | 72 + js/src/tests/js1_8_1/regress/regress-452498-098.js | 63 + .../tests/js1_8_1/regress/regress-452498-099-a.js | 71 + js/src/tests/js1_8_1/regress/regress-452498-099.js | 86 + js/src/tests/js1_8_1/regress/regress-452498-101.js | 63 + js/src/tests/js1_8_1/regress/regress-452498-102.js | 119 + js/src/tests/js1_8_1/regress/regress-452498-103.js | 63 + js/src/tests/js1_8_1/regress/regress-452498-104.js | 63 + js/src/tests/js1_8_1/regress/regress-452498-107.js | 66 + js/src/tests/js1_8_1/regress/regress-452498-108.js | 65 + js/src/tests/js1_8_1/regress/regress-452498-110.js | 81 + js/src/tests/js1_8_1/regress/regress-452498-111.js | 67 + js/src/tests/js1_8_1/regress/regress-452498-112.js | 71 + .../tests/js1_8_1/regress/regress-452498-114-a.js | 75 + js/src/tests/js1_8_1/regress/regress-452498-114.js | 82 + js/src/tests/js1_8_1/regress/regress-452498-116.js | 65 + js/src/tests/js1_8_1/regress/regress-452498-117.js | 166 + js/src/tests/js1_8_1/regress/regress-452498-118.js | 65 + js/src/tests/js1_8_1/regress/regress-452498-119.js | 92 + js/src/tests/js1_8_1/regress/regress-452498-121.js | 65 + js/src/tests/js1_8_1/regress/regress-452498-123.js | 91 + js/src/tests/js1_8_1/regress/regress-452498-129.js | 82 + js/src/tests/js1_8_1/regress/regress-452498-130.js | 89 + js/src/tests/js1_8_1/regress/regress-452498-131.js | 81 + .../tests/js1_8_1/regress/regress-452498-135-a.js | 67 + js/src/tests/js1_8_1/regress/regress-452498-135.js | 119 + js/src/tests/js1_8_1/regress/regress-452498-138.js | 76 + js/src/tests/js1_8_1/regress/regress-452498-139.js | 73 + js/src/tests/js1_8_1/regress/regress-452498-155.js | 66 + js/src/tests/js1_8_1/regress/regress-452498-160.js | 71 + .../tests/js1_8_1/regress/regress-452498-168-1.js | 65 + .../tests/js1_8_1/regress/regress-452498-168-2.js | 63 + js/src/tests/js1_8_1/regress/regress-452498-176.js | 63 + js/src/tests/js1_8_1/regress/regress-452498-178.js | 63 + js/src/tests/js1_8_1/regress/regress-452498-181.js | 63 + js/src/tests/js1_8_1/regress/regress-452498-184.js | 63 + js/src/tests/js1_8_1/regress/regress-452498-185.js | 69 + js/src/tests/js1_8_1/regress/regress-452498-187.js | 69 + js/src/tests/js1_8_1/regress/regress-452498-191.js | 79 + js/src/tests/js1_8_1/regress/regress-452498-192.js | 61 + js/src/tests/js1_8_1/regress/regress-466905-01.js | 62 + js/src/tests/js1_8_1/regress/regress-466905-02.js | 61 + js/src/tests/js1_8_1/regress/regress-479430-01.js | 75 + js/src/tests/js1_8_1/regress/regress-479430-02.js | 77 + js/src/tests/js1_8_1/regress/regress-479430-03.js | 80 + js/src/tests/js1_8_1/regress/regress-479430-04.js | 76 + js/src/tests/js1_8_1/regress/regress-479430-05.js | 75 + js/src/tests/js1_8_1/regress/regress-495773.js | 76 + js/src/tests/js1_8_1/regress/regress-495907.js | 68 + js/src/tests/js1_8_1/regress/regress-496922.js | 72 + js/src/tests/js1_8_1/regress/regress-507053.js | 80 + js/src/tests/js1_8_1/regress/regress-507295.js | 75 + js/src/tests/js1_8_1/regress/regress-507424.js | 67 + js/src/tests/js1_8_1/regress/regress-509354.js | 41 + js/src/tests/js1_8_1/regress/regress-515885.js | 6 + js/src/tests/js1_8_1/regress/regress-522123.js | 69 + js/src/tests/js1_8_1/regress/regress-524264.js | 7 + js/src/tests/js1_8_1/regress/regress-524743.js | 19 + js/src/tests/js1_8_1/regress/regress-530879.js | 9 + js/src/tests/js1_8_1/regress/shell.js | 0 js/src/tests/js1_8_1/shell.js | 47 + js/src/tests/js1_8_1/strict/12.2.1.js | 74 + js/src/tests/js1_8_1/strict/8.7.2.js | 16 + .../js1_8_1/strict/generator-eval-arguments.js | 37 + js/src/tests/js1_8_1/strict/jstests.list | 5 + .../js1_8_1/strict/let-block-eval-arguments.js | 34 + js/src/tests/js1_8_1/strict/shell.js | 88 + js/src/tests/js1_8_1/template.js | 28 + js/src/tests/js1_8_5/README | 4 + js/src/tests/js1_8_5/browser.js | 0 .../js1_8_5/extensions/array-length-protochange.js | 35 + js/src/tests/js1_8_5/extensions/browser.js | 6 + .../js1_8_5/extensions/censor-strict-caller.js | 34 + js/src/tests/js1_8_5/extensions/clone-errors.js | 58 + js/src/tests/js1_8_5/extensions/clone-forge.js | 31 + .../tests/js1_8_5/extensions/clone-leaf-object.js | 63 + js/src/tests/js1_8_5/extensions/clone-object.js | 233 + js/src/tests/js1_8_5/extensions/clone-regexp.js | 32 + js/src/tests/js1_8_5/extensions/clone-simple.js | 32 + .../tests/js1_8_5/extensions/clone-typed-array.js | 83 + .../js1_8_5/extensions/destructure-accessor.js | 75 + js/src/tests/js1_8_5/extensions/jstests.list | 36 + js/src/tests/js1_8_5/extensions/parseInt-octal.js | 30 + .../extensions/proxy-enumerateOwn-duplicates.js | 40 + .../tests/js1_8_5/extensions/proxy-proto-setter.js | 49 + js/src/tests/js1_8_5/extensions/recursion.js | 58 + js/src/tests/js1_8_5/extensions/reflect-parse.js | 1218 + .../tests/js1_8_5/extensions/regress-627984-1.js | 16 + .../tests/js1_8_5/extensions/regress-627984-2.js | 15 + .../tests/js1_8_5/extensions/regress-627984-3.js | 14 + .../tests/js1_8_5/extensions/regress-627984-4.js | 15 + .../tests/js1_8_5/extensions/regress-627984-5.js | 13 + .../tests/js1_8_5/extensions/regress-627984-6.js | 15 + .../tests/js1_8_5/extensions/regress-627984-7.js | 9 + js/src/tests/js1_8_5/extensions/regress-630377.js | 11 + js/src/tests/js1_8_5/extensions/regress-631723.js | 10 + .../tests/js1_8_5/extensions/scripted-proxies.js | 162 + .../extensions/set-property-non-extensible.js | 29 + js/src/tests/js1_8_5/extensions/shell.js | 172 + .../js1_8_5/extensions/typedarray-prototype.js | 46 + js/src/tests/js1_8_5/extensions/typedarray.js | 353 + .../tests/js1_8_5/extensions/worker-error-child.js | 9 + .../extensions/worker-error-propagation-child.js | 16 + .../js1_8_5/extensions/worker-error-propagation.js | 20 + js/src/tests/js1_8_5/extensions/worker-error.js | 21 + .../tests/js1_8_5/extensions/worker-fib-child.js | 27 + js/src/tests/js1_8_5/extensions/worker-fib.js | 18 + .../tests/js1_8_5/extensions/worker-init-child.js | 8 + js/src/tests/js1_8_5/extensions/worker-init.js | 19 + .../js1_8_5/extensions/worker-simple-child.js | 8 + js/src/tests/js1_8_5/extensions/worker-simple.js | 20 + .../js1_8_5/extensions/worker-terminate-child.js | 13 + .../js1_8_5/extensions/worker-terminate-iloop.js | 9 + .../tests/js1_8_5/extensions/worker-terminate.js | 37 + .../js1_8_5/extensions/worker-timeout-child.js | 9 + js/src/tests/js1_8_5/extensions/worker-timeout.js | 18 + js/src/tests/js1_8_5/jstests.list | 2 + js/src/tests/js1_8_5/regress/browser.js | 0 js/src/tests/js1_8_5/regress/jstests.list | 93 + js/src/tests/js1_8_5/regress/regress-500528.js | 22 + js/src/tests/js1_8_5/regress/regress-533876.js | 23 + js/src/tests/js1_8_5/regress/regress-541255-0.js | 14 + js/src/tests/js1_8_5/regress/regress-541255-1.js | 23 + js/src/tests/js1_8_5/regress/regress-541255-2.js | 11 + js/src/tests/js1_8_5/regress/regress-541255-3.js | 13 + js/src/tests/js1_8_5/regress/regress-541255-4.js | 11 + js/src/tests/js1_8_5/regress/regress-541455.js | 12 + js/src/tests/js1_8_5/regress/regress-546615.js | 13 + js/src/tests/js1_8_5/regress/regress-548276.js | 9 + js/src/tests/js1_8_5/regress/regress-551763-0.js | 27 + js/src/tests/js1_8_5/regress/regress-551763-1.js | 4 + js/src/tests/js1_8_5/regress/regress-551763-2.js | 3 + js/src/tests/js1_8_5/regress/regress-552432.js | 16 + js/src/tests/js1_8_5/regress/regress-553778.js | 16 + js/src/tests/js1_8_5/regress/regress-555246-0.js | 14 + js/src/tests/js1_8_5/regress/regress-555246-1.js | 18 + js/src/tests/js1_8_5/regress/regress-559402-1.js | 22 + js/src/tests/js1_8_5/regress/regress-559402-2.js | 8 + js/src/tests/js1_8_5/regress/regress-559438.js | 10 + js/src/tests/js1_8_5/regress/regress-560101.js | 4 + js/src/tests/js1_8_5/regress/regress-560998-1.js | 10 + js/src/tests/js1_8_5/regress/regress-560998-2.js | 10 + js/src/tests/js1_8_5/regress/regress-563210.js | 27 + js/src/tests/js1_8_5/regress/regress-563221.js | 8 + js/src/tests/js1_8_5/regress/regress-566549.js | 24 + js/src/tests/js1_8_5/regress/regress-566914.js | 21 + js/src/tests/js1_8_5/regress/regress-567152.js | 12 + js/src/tests/js1_8_5/regress/regress-569306.js | 10 + js/src/tests/js1_8_5/regress/regress-569464.js | 36 + js/src/tests/js1_8_5/regress/regress-571014.js | 22 + js/src/tests/js1_8_5/regress/regress-573875.js | 21 + js/src/tests/js1_8_5/regress/regress-576847.js | 19 + js/src/tests/js1_8_5/regress/regress-577648-1.js | 87 + js/src/tests/js1_8_5/regress/regress-577648-2.js | 12 + js/src/tests/js1_8_5/regress/regress-583429.js | 7 + js/src/tests/js1_8_5/regress/regress-584355.js | 7 + js/src/tests/js1_8_5/regress/regress-584578.js | 11 + js/src/tests/js1_8_5/regress/regress-584648.js | 15 + js/src/tests/js1_8_5/regress/regress-585257.js | 6 + js/src/tests/js1_8_5/regress/regress-586482-1.js | 25 + js/src/tests/js1_8_5/regress/regress-586482-2.js | 22 + js/src/tests/js1_8_5/regress/regress-586482-3.js | 27 + js/src/tests/js1_8_5/regress/regress-586482-4.js | 25 + js/src/tests/js1_8_5/regress/regress-586482-5.js | 18 + js/src/tests/js1_8_5/regress/regress-588339.js | 5 + js/src/tests/js1_8_5/regress/regress-591846.js | 61 + js/src/tests/js1_8_5/regress/regress-591897.js | 13 + js/src/tests/js1_8_5/regress/regress-592202-1.js | 7 + js/src/tests/js1_8_5/regress/regress-592202-2.js | 15 + js/src/tests/js1_8_5/regress/regress-592202-3.js | 28 + js/src/tests/js1_8_5/regress/regress-592202-4.js | 31 + js/src/tests/js1_8_5/regress/regress-592217.js | 11 + js/src/tests/js1_8_5/regress/regress-592556-c35.js | 20 + js/src/tests/js1_8_5/regress/regress-593256.js | 21 + js/src/tests/js1_8_5/regress/regress-595230-1.js | 19 + js/src/tests/js1_8_5/regress/regress-595230-2.js | 9 + js/src/tests/js1_8_5/regress/regress-595365-1.js | 31 + js/src/tests/js1_8_5/regress/regress-595365-2.js | 46 + js/src/tests/js1_8_5/regress/regress-596103.js | 13 + js/src/tests/js1_8_5/regress/regress-596805-1.js | 14 + js/src/tests/js1_8_5/regress/regress-596805-2.js | 27 + js/src/tests/js1_8_5/regress/regress-597870.js | 22 + js/src/tests/js1_8_5/regress/regress-597945-1.js | 22 + js/src/tests/js1_8_5/regress/regress-597945-2.js | 13 + js/src/tests/js1_8_5/regress/regress-598176.js | 27 + js/src/tests/js1_8_5/regress/regress-600067.js | 16 + js/src/tests/js1_8_5/regress/regress-600137.js | 22 + js/src/tests/js1_8_5/regress/regress-601399.js | 25 + js/src/tests/js1_8_5/regress/regress-602621.js | 15 + js/src/tests/js1_8_5/regress/regress-607799.js | 1 + js/src/tests/js1_8_5/regress/regress-607863.js | 13 + js/src/tests/js1_8_5/regress/regress-609617.js | 83 + js/src/tests/js1_8_5/regress/regress-610026.js | 65 + js/src/tests/js1_8_5/regress/regress-617405-1.js | 11 + js/src/tests/js1_8_5/regress/regress-617405-2.js | 17 + js/src/tests/js1_8_5/regress/regress-618572.js | 37 + js/src/tests/js1_8_5/regress/regress-618574.js | 20 + js/src/tests/js1_8_5/regress/regress-618576.js | 12 + js/src/tests/js1_8_5/regress/regress-618652.js | 10 + js/src/tests/js1_8_5/regress/regress-619003-1.js | 20 + js/src/tests/js1_8_5/regress/regress-619003-2.js | 9 + js/src/tests/js1_8_5/regress/regress-620376-1.js | 23 + js/src/tests/js1_8_5/regress/regress-620376-2.js | 19 + js/src/tests/js1_8_5/regress/regress-620750.js | 19 + js/src/tests/js1_8_5/regress/regress-621814.js | 13 + js/src/tests/js1_8_5/regress/regress-624199.js | 17 + js/src/tests/js1_8_5/regress/regress-624547.js | 16 + js/src/tests/js1_8_5/regress/regress-624968.js | 9 + js/src/tests/js1_8_5/regress/regress-626436.js | 7 + js/src/tests/js1_8_5/regress/regress-633741.js | 17 + js/src/tests/js1_8_5/regress/regress-634210-1.js | 11 + js/src/tests/js1_8_5/regress/regress-634210-2.js | 13 + js/src/tests/js1_8_5/regress/regress-634210-3.js | 13 + js/src/tests/js1_8_5/regress/regress-634210-4.js | 20 + js/src/tests/js1_8_5/regress/regress-635195.js | 8 + js/src/tests/js1_8_5/regress/regress-636364.js | 29 + .../tests/js1_8_5/regress/regress-yarr-regexp.js | 12 + js/src/tests/js1_8_5/regress/shell.js | 0 js/src/tests/js1_8_5/shell.js | 14 + js/src/tests/js1_8_5/template.js | 28 + js/src/tests/jsreftest.html | 19 + js/src/tests/jstests.list | 16 + js/src/tests/jstests.py | 365 + js/src/tests/known-failures.pl | 720 + js/src/tests/manifest.py | 166 + js/src/tests/menufoot.html | 8 + js/src/tests/menuhead.html | 58 + js/src/tests/menuhead.js | 730 + js/src/tests/mkhtml.pl | 84 + js/src/tests/mklistpage.pl | 443 + js/src/tests/most.tests | 892 + js/src/tests/narcissus-failures.txt | 1399 + js/src/tests/narcissus.README | 12 + js/src/tests/narcissus.list | 1 + js/src/tests/parsemark.py | 154 + js/src/tests/pattern-expander.pl | 181 + js/src/tests/pattern-extracter.pl | 227 + js/src/tests/performance-1.8.0.tests | 19 + js/src/tests/performance-1.8.1.tests | 19 + js/src/tests/performance-1.9.0.tests | 19 + js/src/tests/performance-1.9.1.tests | 19 + js/src/tests/performance-1.9.2.tests | 19 + js/src/tests/performance.tests | 18 + js/src/tests/post-process-logs.pl | 602 + js/src/tests/process-logs.sh | 203 + js/src/tests/progressbar.py | 35 + js/src/tests/remove-fixed-failures.sh | 82 + js/src/tests/runtests.sh | 262 + js/src/tests/shell.js | 911 + js/src/tests/slow-n-1.8.1-browser.tests | 62 + js/src/tests/slow-n-1.8.1.tests | 35 + js/src/tests/slow-n-1.9.0-browser.tests | 51 + js/src/tests/slow-n-1.9.0.tests | 21 + js/src/tests/slow-n-1.9.1-browser.tests | 49 + js/src/tests/slow-n-1.9.1.tests | 25 + js/src/tests/slow-n-1.9.2-browser.tests | 50 + js/src/tests/slow-n-1.9.2.tests | 24 + js/src/tests/slow-n.tests | 30 + js/src/tests/slow-narcissus.txt | 18 + js/src/tests/spidermonkey-gc.tests | 28 + js/src/tests/spidermonkey-n-1.8.0.tests | 95 + js/src/tests/spidermonkey-n-1.8.1.tests | 95 + js/src/tests/spidermonkey-n-1.9.0.tests | 99 + js/src/tests/spidermonkey-n-1.9.1.tests | 152 + js/src/tests/spidermonkey-n-1.9.2.tests | 152 + js/src/tests/spidermonkey-n-1.9.3.tests | 151 + js/src/tests/spidermonkey-n.tests | 90 + js/src/tests/src/jstests.jar | Bin 0 -> 324931 bytes js/src/tests/test.sh | 531 + js/src/tests/tests.py | 180 + js/src/tests/user.js | 38 + js/src/tests/userhookeach.js | 168 + js/src/tests/workers.py | 91 + js/src/time.sh | 13 + js/src/tracejit/Writer.cpp | 571 + js/src/tracejit/Writer.h | 1232 + js/src/tracevis/README | 50 + js/src/tracevis/acts.py | 65 + js/src/tracevis/binlog.py | 140 + js/src/tracevis/config.py | 5 + js/src/tracevis/tree.py | 282 + js/src/tracevis/vis.py | 235 + js/src/v8-dtoa/README | 34 + js/src/v8-dtoa/cached-powers.h | 119 + js/src/v8-dtoa/checks.cc | 57 + js/src/v8-dtoa/checks.h | 93 + js/src/v8-dtoa/conversions.cc | 131 + js/src/v8-dtoa/conversions.h | 41 + js/src/v8-dtoa/diy-fp.cc | 58 + js/src/v8-dtoa/diy-fp.h | 117 + js/src/v8-dtoa/double.h | 169 + js/src/v8-dtoa/dtoa.h | 81 + js/src/v8-dtoa/fast-dtoa.cc | 505 + js/src/v8-dtoa/fast-dtoa.h | 58 + js/src/v8-dtoa/globals.h | 69 + js/src/v8-dtoa/include-v8.h | 59 + js/src/v8-dtoa/platform.cc | 137 + js/src/v8-dtoa/platform.h | 103 + js/src/v8-dtoa/powers-ten.h | 2461 + js/src/v8-dtoa/utils.cc | 91 + js/src/v8-dtoa/utils.h | 165 + js/src/v8-dtoa/v8-dtoa.cc | 79 + js/src/v8-dtoa/v8.h | 51 + js/src/v8/base.js | 265 + js/src/v8/crypto.js | 1689 + js/src/v8/deltablue.js | 880 + js/src/v8/earley-boyer.js | 4682 ++ js/src/v8/raytrace.js | 3418 + js/src/v8/richards.js | 539 + js/src/v8/run-crypto.js | 44 + js/src/v8/run-deltablue.js | 44 + js/src/v8/run-earley-boyer.js | 44 + js/src/v8/run-raytrace.js | 44 + js/src/v8/run-richards.js | 44 + js/src/v8/run.js | 49 + js/src/vprof/manifest.mk | 39 + js/src/vprof/readme.txt | 130 + js/src/vprof/testVprofMT.c | 125 + js/src/vprof/vprof.cpp | 383 + js/src/vprof/vprof.h | 308 + js/src/yarr/Makefile | 5 + js/src/yarr/jswtfbridge.h | 61 + js/src/yarr/pcre/AUTHORS | 12 + js/src/yarr/pcre/COPYING | 35 + js/src/yarr/pcre/chartables.c | 96 + js/src/yarr/pcre/dftables | 273 + js/src/yarr/pcre/pcre.h | 68 + js/src/yarr/pcre/pcre.pri | 12 + js/src/yarr/pcre/pcre_compile.cpp | 2704 + js/src/yarr/pcre/pcre_exec.cpp | 2193 + js/src/yarr/pcre/pcre_internal.h | 434 + js/src/yarr/pcre/pcre_tables.cpp | 71 + js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp | 98 + js/src/yarr/pcre/pcre_xclass.cpp | 114 + js/src/yarr/pcre/ucpinternal.h | 126 + js/src/yarr/pcre/ucptable.cpp | 2968 + js/src/yarr/wtf/ASCIICType.h | 166 + js/src/yarr/yarr/RegExpJitTables.h | 2720 + js/src/yarr/yarr/RegexCommon.h | 50 + js/src/yarr/yarr/RegexCompiler.cpp | 664 + js/src/yarr/yarr/RegexCompiler.h | 38 + js/src/yarr/yarr/RegexJIT.cpp | 1567 + js/src/yarr/yarr/RegexJIT.h | 112 + js/src/yarr/yarr/RegexParser.h | 843 + js/src/yarr/yarr/RegexPattern.h | 438 + patches/bug-586016.patch | 22 + patches/bug-630209.patch | 2760 + patches/libname-changes.patch | 208 + 5987 files changed, 1032261 insertions(+) create mode 100644 .hgtags create mode 100644 README create mode 100644 js/jsd/Makefile.in create mode 100644 js/jsd/README create mode 100644 js/jsd/idl/Makefile.in create mode 100644 js/jsd/idl/jsdIDebuggerService.idl create mode 100644 js/jsd/jsd.h create mode 100644 js/jsd/jsd1640.def create mode 100644 js/jsd/jsd1640.rc create mode 100644 js/jsd/jsd3240.rc create mode 100644 js/jsd/jsd_atom.c create mode 100644 js/jsd/jsd_high.c create mode 100644 js/jsd/jsd_hook.c create mode 100644 js/jsd/jsd_java.c create mode 100644 js/jsd/jsd_lock.c create mode 100644 js/jsd/jsd_lock.h create mode 100644 js/jsd/jsd_obj.c create mode 100644 js/jsd/jsd_scpt.c create mode 100644 js/jsd/jsd_stak.c create mode 100644 js/jsd/jsd_step.c create mode 100644 js/jsd/jsd_text.c create mode 100644 js/jsd/jsd_val.c create mode 100644 js/jsd/jsd_xpc.cpp create mode 100644 js/jsd/jsd_xpc.h create mode 100644 js/jsd/jsdebug.c create mode 100644 js/jsd/jsdebug.h create mode 100644 js/jsd/jsdstubs.c create mode 100755 js/jsd/mkshell.bat create mode 100644 js/jsd/resource.h create mode 100644 js/jsd/test/Makefile.in create mode 100644 js/jsd/test/bug507448.js create mode 100644 js/jsd/test/jsd-test.js create mode 100644 js/jsd/test/test-bug617870-callhooks.js create mode 100644 js/jsd/test/test_bug507448.html create mode 100644 js/jsd/test/test_bug617870-callhooks.html create mode 100644 js/src/Makefile.in create mode 100644 js/src/Makefile.ref create mode 100644 js/src/README.html create mode 100644 js/src/SpiderMonkey.rsp create mode 100644 js/src/Y.js create mode 100644 js/src/aclocal.m4 create mode 100644 js/src/analysis-tests/Makefile.in create mode 100644 js/src/analysis-tests/green-accessred.cpp create mode 100644 js/src/analysis-tests/green-callred.cpp create mode 100644 js/src/analysis-tests/green-callredptr.cpp create mode 100644 js/src/analysis-tests/green-tored-badpath.cpp create mode 100644 js/src/analysis-tests/green-tored.cpp create mode 100644 js/src/analysis-tests/green-toredptr.cpp create mode 100644 js/src/analysis-tests/misdeclared-red-funcptr.cpp create mode 100644 js/src/analysis-tests/misdeclared-red-funcptr2.cpp create mode 100644 js/src/analysis-tests/red-accessred.cpp create mode 100644 js/src/analysis-tests/red-callgreen.cpp create mode 100644 js/src/analysis-tests/red-callred.cpp create mode 100644 js/src/analysis-tests/red-togreenptr-arg.cpp create mode 100644 js/src/analysis-tests/red-togreenptr-field.cpp create mode 100644 js/src/analysis-tests/red-togreenptr-initializer-array.cpp create mode 100644 js/src/analysis-tests/red-togreenptr-initializer-cast.cpp create mode 100644 js/src/analysis-tests/red-togreenptr-initializer-nested.cpp create mode 100644 js/src/analysis-tests/red-togreenptr-initializer-struct.cpp create mode 100644 js/src/analysis-tests/red-togreenptr-initializer.cpp create mode 100644 js/src/analysis-tests/red-togreenptr-return.cpp create mode 100644 js/src/analysis-tests/red-togreenptr.cpp create mode 100644 js/src/assembler/TestMain.cpp create mode 100644 js/src/assembler/assembler/ARMAssembler.cpp create mode 100644 js/src/assembler/assembler/ARMAssembler.h create mode 100644 js/src/assembler/assembler/ARMv7Assembler.h create mode 100644 js/src/assembler/assembler/AbstractMacroAssembler.h create mode 100644 js/src/assembler/assembler/AssemblerBuffer.h create mode 100644 js/src/assembler/assembler/AssemblerBufferWithConstantPool.h create mode 100644 js/src/assembler/assembler/CodeLocation.h create mode 100644 js/src/assembler/assembler/LinkBuffer.h create mode 100644 js/src/assembler/assembler/MacroAssembler.h create mode 100644 js/src/assembler/assembler/MacroAssemblerARM.cpp create mode 100644 js/src/assembler/assembler/MacroAssemblerARM.h create mode 100644 js/src/assembler/assembler/MacroAssemblerARMv7.h create mode 100644 js/src/assembler/assembler/MacroAssemblerCodeRef.h create mode 100644 js/src/assembler/assembler/MacroAssemblerX86.h create mode 100644 js/src/assembler/assembler/MacroAssemblerX86Common.cpp create mode 100644 js/src/assembler/assembler/MacroAssemblerX86Common.h create mode 100644 js/src/assembler/assembler/MacroAssemblerX86_64.h create mode 100644 js/src/assembler/assembler/RepatchBuffer.h create mode 100644 js/src/assembler/assembler/X86Assembler.h create mode 100644 js/src/assembler/jit/ExecutableAllocator.cpp create mode 100644 js/src/assembler/jit/ExecutableAllocator.h create mode 100644 js/src/assembler/jit/ExecutableAllocatorOS2.cpp create mode 100644 js/src/assembler/jit/ExecutableAllocatorPosix.cpp create mode 100644 js/src/assembler/jit/ExecutableAllocatorSymbian.cpp create mode 100644 js/src/assembler/jit/ExecutableAllocatorWin.cpp create mode 100644 js/src/assembler/moco/MocoStubs.h create mode 100644 js/src/assembler/wtf/Assertions.cpp create mode 100644 js/src/assembler/wtf/Assertions.h create mode 100644 js/src/assembler/wtf/Platform.h create mode 100644 js/src/assembler/wtf/SegmentedVector.h create mode 100644 js/src/assembler/wtf/VMTags.h create mode 100755 js/src/bench.sh create mode 100644 js/src/build/autoconf/acoutput-fast.pl create mode 100644 js/src/build/autoconf/acwinpaths.m4 create mode 100644 js/src/build/autoconf/altoptions.m4 create mode 100755 js/src/build/autoconf/config.guess create mode 100755 js/src/build/autoconf/config.sub create mode 100644 js/src/build/autoconf/install-sh create mode 100644 js/src/build/autoconf/make-makefile create mode 100644 js/src/build/autoconf/match-dir.sh create mode 100644 js/src/build/autoconf/moznbytetype.m4 create mode 100644 js/src/build/autoconf/mozprog.m4 create mode 100644 js/src/build/autoconf/nspr.m4 create mode 100644 js/src/build/autoconf/pkg.m4 create mode 100644 js/src/build/cl.py create mode 100644 js/src/build/cygwin-wrapper create mode 100644 js/src/build/hcc create mode 100644 js/src/build/hcpp create mode 100644 js/src/build/msys-perl-wrapper create mode 100644 js/src/build/unix/mddepend.pl create mode 100755 js/src/build/unix/print-failed-commands.sh create mode 100644 js/src/build/unix/uniq.pl create mode 100644 js/src/build/win32/pgomerge.py create mode 100644 js/src/config.mk create mode 100644 js/src/config/Makefile.in create mode 100644 js/src/config/Moz/Milestone.pm create mode 100644 js/src/config/autoconf.mk.in create mode 100644 js/src/config/check-sync-dirs.py create mode 100644 js/src/config/check-sync-exceptions create mode 100644 js/src/config/config.mk create mode 100644 js/src/config/fastcwd.pl create mode 100755 js/src/config/find_vanilla_new_calls create mode 100644 js/src/config/gcc_hidden.h create mode 100644 js/src/config/make-system-wrappers.pl create mode 100644 js/src/config/milestone.pl create mode 100644 js/src/config/milestone.txt create mode 100644 js/src/config/mkdepend/Makefile.in create mode 100644 js/src/config/mkdepend/cppsetup.c create mode 100644 js/src/config/mkdepend/def.h create mode 100644 js/src/config/mkdepend/ifparser.c create mode 100644 js/src/config/mkdepend/ifparser.h create mode 100644 js/src/config/mkdepend/imakemdep.h create mode 100644 js/src/config/mkdepend/include.c create mode 100644 js/src/config/mkdepend/main.c create mode 100644 js/src/config/mkdepend/mkdepend.man create mode 100644 js/src/config/mkdepend/parse.c create mode 100644 js/src/config/mkdepend/pr.c create mode 100644 js/src/config/nfspwd.pl create mode 100644 js/src/config/nsinstall.c create mode 100644 js/src/config/nsinstall.exe.manifest create mode 100644 js/src/config/nsinstall.py create mode 100644 js/src/config/nsinstall_win.c create mode 100644 js/src/config/pathsub.c create mode 100644 js/src/config/pathsub.h create mode 100644 js/src/config/preprocessor.pl create mode 100644 js/src/config/rules.mk create mode 100644 js/src/config/solaris_ia32.map create mode 100644 js/src/config/static-checking-config.mk create mode 100644 js/src/config/static-checking.js create mode 100644 js/src/config/string-format.js create mode 100644 js/src/config/system-headers create mode 100644 js/src/config/version.mk create mode 100755 js/src/config/version_win.pl create mode 100755 js/src/configure create mode 100644 js/src/configure.in create mode 100644 js/src/ctypes/CTypes.cpp create mode 100644 js/src/ctypes/CTypes.h create mode 100644 js/src/ctypes/Library.cpp create mode 100644 js/src/ctypes/Library.h create mode 100644 js/src/ctypes/ctypes.msg create mode 100644 js/src/ctypes/libffi.patch create mode 100644 js/src/ctypes/libffi/ChangeLog create mode 100644 js/src/ctypes/libffi/ChangeLog.libffi create mode 100644 js/src/ctypes/libffi/ChangeLog.libgcj create mode 100644 js/src/ctypes/libffi/ChangeLog.v1 create mode 100644 js/src/ctypes/libffi/LICENSE create mode 100644 js/src/ctypes/libffi/Makefile.am create mode 100644 js/src/ctypes/libffi/Makefile.in create mode 100644 js/src/ctypes/libffi/README create mode 100644 js/src/ctypes/libffi/acinclude.m4 create mode 100644 js/src/ctypes/libffi/aclocal.m4 create mode 100755 js/src/ctypes/libffi/compile create mode 100755 js/src/ctypes/libffi/config.guess create mode 100755 js/src/ctypes/libffi/config.sub create mode 100755 js/src/ctypes/libffi/configure create mode 100644 js/src/ctypes/libffi/configure.ac create mode 100644 js/src/ctypes/libffi/configure.host create mode 100755 js/src/ctypes/libffi/depcomp create mode 100644 js/src/ctypes/libffi/doc/libffi.info create mode 100644 js/src/ctypes/libffi/doc/libffi.texi create mode 100644 js/src/ctypes/libffi/doc/stamp-vti create mode 100644 js/src/ctypes/libffi/doc/version.texi create mode 100644 js/src/ctypes/libffi/fficonfig.h.in create mode 100644 js/src/ctypes/libffi/include/Makefile.am create mode 100644 js/src/ctypes/libffi/include/Makefile.in create mode 100644 js/src/ctypes/libffi/include/ffi.h.in create mode 100644 js/src/ctypes/libffi/include/ffi_common.h create mode 100755 js/src/ctypes/libffi/install-sh create mode 100644 js/src/ctypes/libffi/libffi.pc.in create mode 100644 js/src/ctypes/libffi/libtool-version create mode 100755 js/src/ctypes/libffi/ltmain.sh create mode 100644 js/src/ctypes/libffi/m4/libtool.m4 create mode 100644 js/src/ctypes/libffi/m4/ltoptions.m4 create mode 100644 js/src/ctypes/libffi/m4/ltsugar.m4 create mode 100644 js/src/ctypes/libffi/m4/ltversion.m4 create mode 100644 js/src/ctypes/libffi/m4/lt~obsolete.m4 create mode 100644 js/src/ctypes/libffi/man/Makefile.am create mode 100644 js/src/ctypes/libffi/man/Makefile.in create mode 100644 js/src/ctypes/libffi/man/ffi.3 create mode 100644 js/src/ctypes/libffi/man/ffi_call.3 create mode 100644 js/src/ctypes/libffi/man/ffi_prep_cif.3 create mode 100755 js/src/ctypes/libffi/mdate-sh create mode 100755 js/src/ctypes/libffi/missing create mode 100755 js/src/ctypes/libffi/msvcc.sh create mode 100644 js/src/ctypes/libffi/src/alpha/ffi.c create mode 100644 js/src/ctypes/libffi/src/alpha/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/alpha/osf.S create mode 100644 js/src/ctypes/libffi/src/arm/ffi.c create mode 100644 js/src/ctypes/libffi/src/arm/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/arm/sysv.S create mode 100644 js/src/ctypes/libffi/src/avr32/ffi.c create mode 100644 js/src/ctypes/libffi/src/avr32/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/avr32/sysv.S create mode 100644 js/src/ctypes/libffi/src/closures.c create mode 100644 js/src/ctypes/libffi/src/cris/ffi.c create mode 100644 js/src/ctypes/libffi/src/cris/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/cris/sysv.S create mode 100644 js/src/ctypes/libffi/src/debug.c create mode 100644 js/src/ctypes/libffi/src/dlmalloc.c create mode 100644 js/src/ctypes/libffi/src/frv/eabi.S create mode 100644 js/src/ctypes/libffi/src/frv/ffi.c create mode 100644 js/src/ctypes/libffi/src/frv/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/ia64/ffi.c create mode 100644 js/src/ctypes/libffi/src/ia64/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/ia64/ia64_flags.h create mode 100644 js/src/ctypes/libffi/src/ia64/unix.S create mode 100644 js/src/ctypes/libffi/src/java_raw_api.c create mode 100644 js/src/ctypes/libffi/src/m32r/ffi.c create mode 100644 js/src/ctypes/libffi/src/m32r/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/m32r/sysv.S create mode 100644 js/src/ctypes/libffi/src/m68k/ffi.c create mode 100644 js/src/ctypes/libffi/src/m68k/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/m68k/sysv.S create mode 100644 js/src/ctypes/libffi/src/mips/ffi.c create mode 100644 js/src/ctypes/libffi/src/mips/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/mips/n32.S create mode 100644 js/src/ctypes/libffi/src/mips/o32.S create mode 100644 js/src/ctypes/libffi/src/moxie/eabi.S create mode 100644 js/src/ctypes/libffi/src/moxie/ffi.c create mode 100644 js/src/ctypes/libffi/src/moxie/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/pa/ffi.c create mode 100644 js/src/ctypes/libffi/src/pa/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/pa/hpux32.S create mode 100644 js/src/ctypes/libffi/src/pa/linux.S create mode 100644 js/src/ctypes/libffi/src/powerpc/aix.S create mode 100644 js/src/ctypes/libffi/src/powerpc/aix_closure.S create mode 100644 js/src/ctypes/libffi/src/powerpc/asm.h create mode 100644 js/src/ctypes/libffi/src/powerpc/darwin.S create mode 100644 js/src/ctypes/libffi/src/powerpc/darwin_closure.S create mode 100644 js/src/ctypes/libffi/src/powerpc/ffi.c create mode 100644 js/src/ctypes/libffi/src/powerpc/ffi_darwin.c create mode 100644 js/src/ctypes/libffi/src/powerpc/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/powerpc/linux64.S create mode 100644 js/src/ctypes/libffi/src/powerpc/linux64_closure.S create mode 100644 js/src/ctypes/libffi/src/powerpc/ppc_closure.S create mode 100644 js/src/ctypes/libffi/src/powerpc/sysv.S create mode 100644 js/src/ctypes/libffi/src/prep_cif.c create mode 100644 js/src/ctypes/libffi/src/raw_api.c create mode 100644 js/src/ctypes/libffi/src/s390/ffi.c create mode 100644 js/src/ctypes/libffi/src/s390/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/s390/sysv.S create mode 100644 js/src/ctypes/libffi/src/sh/ffi.c create mode 100644 js/src/ctypes/libffi/src/sh/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/sh/sysv.S create mode 100644 js/src/ctypes/libffi/src/sh64/ffi.c create mode 100644 js/src/ctypes/libffi/src/sh64/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/sh64/sysv.S create mode 100644 js/src/ctypes/libffi/src/sparc/ffi.c create mode 100644 js/src/ctypes/libffi/src/sparc/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/sparc/v8.S create mode 100644 js/src/ctypes/libffi/src/sparc/v9.S create mode 100644 js/src/ctypes/libffi/src/types.c create mode 100644 js/src/ctypes/libffi/src/x86/darwin.S create mode 100644 js/src/ctypes/libffi/src/x86/darwin64.S create mode 100644 js/src/ctypes/libffi/src/x86/ffi.c create mode 100644 js/src/ctypes/libffi/src/x86/ffi64.c create mode 100644 js/src/ctypes/libffi/src/x86/ffitarget.h create mode 100644 js/src/ctypes/libffi/src/x86/freebsd.S create mode 100644 js/src/ctypes/libffi/src/x86/sysv.S create mode 100644 js/src/ctypes/libffi/src/x86/unix64.S create mode 100644 js/src/ctypes/libffi/src/x86/win32.S create mode 100644 js/src/ctypes/libffi/src/x86/win64.S create mode 100644 js/src/ctypes/libffi/stamp-h.in create mode 100644 js/src/ctypes/libffi/testsuite/Makefile.am create mode 100644 js/src/ctypes/libffi/testsuite/Makefile.in create mode 100644 js/src/ctypes/libffi/testsuite/config/default.exp create mode 100644 js/src/ctypes/libffi/testsuite/lib/libffi-dg.exp create mode 100644 js/src/ctypes/libffi/testsuite/lib/target-libpath.exp create mode 100644 js/src/ctypes/libffi/testsuite/lib/wrapper.exp create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/call.exp create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/closure_fn0.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/closure_fn1.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/closure_fn2.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/closure_fn3.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/closure_fn4.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/closure_fn5.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/closure_fn6.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/closure_loc_fn0.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/closure_stdcall.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_12byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_16byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_18byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_19byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_1_1byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_20byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_20byte1.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_24byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_2byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_3_1byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_3byte1.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_3byte2.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_4_1byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_4byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_5_1_byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_5byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_64byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_6_1_byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_6byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_7_1_byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_7byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_8byte.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_9byte1.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_9byte2.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_align_double.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_align_float.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_align_pointer.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint16.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint32.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint64.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint16.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint32.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint64.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_dbls_struct.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_double.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_double_va.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_float.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_schar.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_sshort.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_sshortchar.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_uchar.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_ushort.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_ushortchar.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_pointer.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_pointer_stack.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_schar.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_sint.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_sshort.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_uchar.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_uint.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_ulonglong.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/cls_ushort.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/err_bad_abi.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/err_bad_typedef.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/ffitest.h create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/float.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/float1.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/float2.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/float3.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/float4.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/huge_struct.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/many.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/many_win32.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/negint.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/nested_struct.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/nested_struct1.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/nested_struct10.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/nested_struct2.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/nested_struct3.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/nested_struct4.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/nested_struct5.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/nested_struct6.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/nested_struct7.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/nested_struct8.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/nested_struct9.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/problem1.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/promotion.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/pyobjc-tc.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/return_dbl.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/return_dbl1.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/return_dbl2.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/return_fl.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/return_fl1.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/return_fl2.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/return_fl3.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/return_ldl.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/return_ll.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/return_ll1.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/return_sc.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/return_sl.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/return_uc.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/return_ul.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/stret_large.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/stret_large2.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/stret_medium.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/stret_medium2.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/strlen.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/strlen_win32.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/struct1.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/struct2.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/struct3.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/struct4.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/struct5.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/struct6.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/struct7.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/struct8.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/struct9.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.call/testclosure.c create mode 100644 js/src/ctypes/libffi/testsuite/libffi.special/ffitestcxx.h create mode 100644 js/src/ctypes/libffi/testsuite/libffi.special/special.exp create mode 100644 js/src/ctypes/libffi/testsuite/libffi.special/unwindtest.cc create mode 100644 js/src/ctypes/libffi/testsuite/libffi.special/unwindtest_ffi_call.cc create mode 100644 js/src/ctypes/libffi/texinfo.tex create mode 100644 js/src/ctypes/typedefs.h create mode 100644 js/src/dtoa.c create mode 100644 js/src/editline/Makefile.in create mode 100644 js/src/editline/Makefile.ref create mode 100644 js/src/editline/README create mode 100644 js/src/editline/editline.3 create mode 100644 js/src/editline/editline.c create mode 100644 js/src/editline/editline.h create mode 100644 js/src/editline/sysunix.c create mode 100644 js/src/editline/unix.h create mode 100644 js/src/find-child.py create mode 100644 js/src/gnuplot/gcTimer.gnu create mode 100644 js/src/imacro_asm.py create mode 100644 js/src/imacros.jsasm create mode 100644 js/src/javascript-trace.d create mode 100644 js/src/jit-test/README create mode 100755 js/src/jit-test/jit_test.py create mode 100644 js/src/jit-test/lib/andTestHelper.js create mode 100644 js/src/jit-test/lib/array-compare.js create mode 100644 js/src/jit-test/lib/eqArrayHelper.js create mode 100644 js/src/jit-test/lib/mandelbrot-results.js create mode 100644 js/src/jit-test/lib/orTestHelper.js create mode 100644 js/src/jit-test/lib/prolog.js create mode 100644 js/src/jit-test/lib/range.js create mode 100644 js/src/jit-test/progressbar.py create mode 100644 js/src/jit-test/tests/arguments/args-createontrace.js create mode 100644 js/src/jit-test/tests/arguments/args-mochi-2.js create mode 100644 js/src/jit-test/tests/arguments/args-mochi-2a.js create mode 100644 js/src/jit-test/tests/arguments/args-mochi.js create mode 100644 js/src/jit-test/tests/arguments/args-mutate-length-1.js create mode 100644 js/src/jit-test/tests/arguments/args-mutate-length-2.js create mode 100644 js/src/jit-test/tests/arguments/args-range-2.js create mode 100644 js/src/jit-test/tests/arguments/args-range-const.js create mode 100644 js/src/jit-test/tests/arguments/args-range.js create mode 100644 js/src/jit-test/tests/arguments/args-redefine-length-1.js create mode 100644 js/src/jit-test/tests/arguments/args-redefine-length-2.js create mode 100644 js/src/jit-test/tests/arguments/args-sum.js create mode 100644 js/src/jit-test/tests/arguments/args-vargc.js create mode 100644 js/src/jit-test/tests/arguments/args1.js create mode 100644 js/src/jit-test/tests/arguments/args10.js create mode 100644 js/src/jit-test/tests/arguments/args11.js create mode 100644 js/src/jit-test/tests/arguments/args2.js create mode 100644 js/src/jit-test/tests/arguments/args2a.js create mode 100644 js/src/jit-test/tests/arguments/args2b.js create mode 100644 js/src/jit-test/tests/arguments/args2c.js create mode 100644 js/src/jit-test/tests/arguments/args2d.js create mode 100644 js/src/jit-test/tests/arguments/args3.js create mode 100644 js/src/jit-test/tests/arguments/args4.js create mode 100644 js/src/jit-test/tests/arguments/args5.js create mode 100644 js/src/jit-test/tests/arguments/args6.js create mode 100644 js/src/jit-test/tests/arguments/args6a.js create mode 100644 js/src/jit-test/tests/arguments/args7.js create mode 100644 js/src/jit-test/tests/arguments/args8.js create mode 100644 js/src/jit-test/tests/arguments/args9.js create mode 100644 js/src/jit-test/tests/arguments/argsub.js create mode 100644 js/src/jit-test/tests/arguments/argsx-1.js create mode 100644 js/src/jit-test/tests/arguments/argsx-2.js create mode 100644 js/src/jit-test/tests/arguments/argsx-3.js create mode 100644 js/src/jit-test/tests/arguments/argsx-3a.js create mode 100644 js/src/jit-test/tests/arguments/argsx-4.js create mode 100644 js/src/jit-test/tests/arguments/bug503772.js create mode 100644 js/src/jit-test/tests/arguments/bug508178.js create mode 100644 js/src/jit-test/tests/arguments/bug554670-1.js create mode 100644 js/src/jit-test/tests/arguments/bug554670-2.js create mode 100644 js/src/jit-test/tests/arguments/bug633020.js create mode 100644 js/src/jit-test/tests/arguments/nonstrict-args.js create mode 100644 js/src/jit-test/tests/arguments/nonstrict-assign-element-get-parameter.js create mode 100644 js/src/jit-test/tests/arguments/nonstrict-assign-parameter-get-element.js create mode 100644 js/src/jit-test/tests/arguments/nonstrict-assign.js create mode 100644 js/src/jit-test/tests/arguments/nonstrict-later-assign.js create mode 100644 js/src/jit-test/tests/arguments/nonstrict-noargs.js create mode 100644 js/src/jit-test/tests/arguments/strict-args-flushstack.js create mode 100644 js/src/jit-test/tests/arguments/strict-args-generator-flushstack.js create mode 100644 js/src/jit-test/tests/arguments/strict-args.js create mode 100644 js/src/jit-test/tests/arguments/strict-assign-after.js create mode 100644 js/src/jit-test/tests/arguments/strict-assign-arguments-element.js create mode 100644 js/src/jit-test/tests/arguments/strict-assign-outer-param-psych.js create mode 100644 js/src/jit-test/tests/arguments/strict-assign-outer-param.js create mode 100644 js/src/jit-test/tests/arguments/strict-assign-parameter-get-element.js create mode 100644 js/src/jit-test/tests/arguments/strict-assign.js create mode 100644 js/src/jit-test/tests/arguments/strict-eval-mutation.js create mode 100644 js/src/jit-test/tests/arguments/strict-eval.js create mode 100644 js/src/jit-test/tests/arguments/strict-maybe-assign-outer.js create mode 100644 js/src/jit-test/tests/arguments/strict-maybe-nested-eval.js create mode 100644 js/src/jit-test/tests/arguments/strict-nested-assign-shadow-function-call.js create mode 100644 js/src/jit-test/tests/arguments/strict-nested-assign-shadow-function-name.js create mode 100644 js/src/jit-test/tests/arguments/strict-nested-assign-shadow-function.js create mode 100644 js/src/jit-test/tests/arguments/strict-nested-assign-shadowed-catch-call.js create mode 100644 js/src/jit-test/tests/arguments/strict-nested-assign-shadowed-catch.js create mode 100644 js/src/jit-test/tests/arguments/strict-nested-assign-shadowed-var.js create mode 100644 js/src/jit-test/tests/arguments/strict-nested-eval.js create mode 100644 js/src/jit-test/tests/arguments/strict-nested-shadow-eval.js create mode 100644 js/src/jit-test/tests/arguments/strict-nested-shadow-maybe-eval.js create mode 100644 js/src/jit-test/tests/arguments/strict-noargs.js create mode 100644 js/src/jit-test/tests/arguments/testDelArg1.js create mode 100644 js/src/jit-test/tests/arguments/testDelArg2.js create mode 100644 js/src/jit-test/tests/basic/FPQuadCmp.js create mode 100644 js/src/jit-test/tests/basic/argumentsPassedToBuiltin.js create mode 100644 js/src/jit-test/tests/basic/arith.js create mode 100644 js/src/jit-test/tests/basic/arityMismatchExtraArg.js create mode 100644 js/src/jit-test/tests/basic/arityMismatchMissingArg.js create mode 100644 js/src/jit-test/tests/basic/bigLoadStoreDisp.js create mode 100644 js/src/jit-test/tests/basic/bindname-in-strict-eval.js create mode 100644 js/src/jit-test/tests/basic/bitwiseAnd.js create mode 100644 js/src/jit-test/tests/basic/bitwiseGlobal.js create mode 100644 js/src/jit-test/tests/basic/bug464403.js create mode 100644 js/src/jit-test/tests/basic/bug465902.js create mode 100644 js/src/jit-test/tests/basic/bug489098.js create mode 100644 js/src/jit-test/tests/basic/bug504587-1.js create mode 100644 js/src/jit-test/tests/basic/bug507180.js create mode 100644 js/src/jit-test/tests/basic/bug509639.js create mode 100644 js/src/jit-test/tests/basic/bug509982.js create mode 100644 js/src/jit-test/tests/basic/bug510434.js create mode 100644 js/src/jit-test/tests/basic/bug510437-2.js create mode 100644 js/src/jit-test/tests/basic/bug510437.js create mode 100644 js/src/jit-test/tests/basic/bug510642.js create mode 100644 js/src/jit-test/tests/basic/bug510655.js create mode 100644 js/src/jit-test/tests/basic/bug511214.js create mode 100644 js/src/jit-test/tests/basic/bug511241.js create mode 100644 js/src/jit-test/tests/basic/bug513038.js create mode 100644 js/src/jit-test/tests/basic/bug513898-regexp.js create mode 100644 js/src/jit-test/tests/basic/bug516009.js create mode 100644 js/src/jit-test/tests/basic/bug517721.js create mode 100644 js/src/jit-test/tests/basic/bug519129.js create mode 100644 js/src/jit-test/tests/basic/bug520498.js create mode 100644 js/src/jit-test/tests/basic/bug522136.js create mode 100644 js/src/jit-test/tests/basic/bug522817.js create mode 100644 js/src/jit-test/tests/basic/bug524826-2.js create mode 100644 js/src/jit-test/tests/basic/bug524826.js create mode 100644 js/src/jit-test/tests/basic/bug525028.js create mode 100644 js/src/jit-test/tests/basic/bug527288.js create mode 100644 js/src/jit-test/tests/basic/bug528116.js create mode 100644 js/src/jit-test/tests/basic/bug528644.js create mode 100644 js/src/jit-test/tests/basic/bug529130.js create mode 100644 js/src/jit-test/tests/basic/bug532568-2.js create mode 100644 js/src/jit-test/tests/basic/bug532568.js create mode 100644 js/src/jit-test/tests/basic/bug532823.js create mode 100644 js/src/jit-test/tests/basic/bug535474.js create mode 100644 js/src/jit-test/tests/basic/bug535760.js create mode 100644 js/src/jit-test/tests/basic/bug535930.js create mode 100644 js/src/jit-test/tests/basic/bug536445.js create mode 100644 js/src/jit-test/tests/basic/bug536748.js create mode 100644 js/src/jit-test/tests/basic/bug539379.js create mode 100644 js/src/jit-test/tests/basic/bug539553-2.js create mode 100644 js/src/jit-test/tests/basic/bug539553-3.js create mode 100644 js/src/jit-test/tests/basic/bug539553.js create mode 100644 js/src/jit-test/tests/basic/bug541191-1.js create mode 100644 js/src/jit-test/tests/basic/bug541191-2.js create mode 100644 js/src/jit-test/tests/basic/bug541191-3.js create mode 100644 js/src/jit-test/tests/basic/bug541191-4.js create mode 100644 js/src/jit-test/tests/basic/bug541191-5.js create mode 100644 js/src/jit-test/tests/basic/bug547911-1.js create mode 100644 js/src/jit-test/tests/basic/bug547911-2.js create mode 100644 js/src/jit-test/tests/basic/bug551705.js create mode 100644 js/src/jit-test/tests/basic/bug552196.js create mode 100644 js/src/jit-test/tests/basic/bug557168-1.js create mode 100644 js/src/jit-test/tests/basic/bug557168-2.js create mode 100644 js/src/jit-test/tests/basic/bug557168-3.js create mode 100644 js/src/jit-test/tests/basic/bug557168.js create mode 100644 js/src/jit-test/tests/basic/bug557841.js create mode 100644 js/src/jit-test/tests/basic/bug558530.js create mode 100644 js/src/jit-test/tests/basic/bug558814.js create mode 100644 js/src/jit-test/tests/basic/bug559912.js create mode 100644 js/src/jit-test/tests/basic/bug560234.js create mode 100644 js/src/jit-test/tests/basic/bug560234b.js create mode 100644 js/src/jit-test/tests/basic/bug561279.js create mode 100644 js/src/jit-test/tests/basic/bug563125.js create mode 100644 js/src/jit-test/tests/basic/bug566637.js create mode 100644 js/src/jit-test/tests/basic/bug568276.js create mode 100644 js/src/jit-test/tests/basic/bug569651.js create mode 100644 js/src/jit-test/tests/basic/bug569843.js create mode 100644 js/src/jit-test/tests/basic/bug569849.js create mode 100644 js/src/jit-test/tests/basic/bug570385-1.js create mode 100644 js/src/jit-test/tests/basic/bug570385-2.js create mode 100644 js/src/jit-test/tests/basic/bug570385-3.js create mode 100644 js/src/jit-test/tests/basic/bug570663-1.js create mode 100644 js/src/jit-test/tests/basic/bug570663-2.js create mode 100644 js/src/jit-test/tests/basic/bug572229.js create mode 100644 js/src/jit-test/tests/basic/bug574280.js create mode 100644 js/src/jit-test/tests/basic/bug576823-regexp.js create mode 100644 js/src/jit-test/tests/basic/bug576837-regexp.js create mode 100644 js/src/jit-test/tests/basic/bug578041.js create mode 100644 js/src/jit-test/tests/basic/bug579740.js create mode 100644 js/src/jit-test/tests/basic/bug582161.js create mode 100644 js/src/jit-test/tests/basic/bug582479.js create mode 100644 js/src/jit-test/tests/basic/bug583615.js create mode 100644 js/src/jit-test/tests/basic/bug583757.js create mode 100644 js/src/jit-test/tests/basic/bug584499-1.js create mode 100644 js/src/jit-test/tests/basic/bug584499-2.js create mode 100644 js/src/jit-test/tests/basic/bug584565.js create mode 100644 js/src/jit-test/tests/basic/bug584603.js create mode 100644 js/src/jit-test/tests/basic/bug585542.js create mode 100644 js/src/jit-test/tests/basic/bug586499-regexp.js create mode 100644 js/src/jit-test/tests/basic/bug586917.js create mode 100644 js/src/jit-test/tests/basic/bug587346-regexp-01.js create mode 100644 js/src/jit-test/tests/basic/bug587366.js create mode 100644 js/src/jit-test/tests/basic/bug589318.js create mode 100644 js/src/jit-test/tests/basic/bug590006.js create mode 100644 js/src/jit-test/tests/basic/bug592927.js create mode 100644 js/src/jit-test/tests/basic/bug593663-regexp.js create mode 100644 js/src/jit-test/tests/basic/bug594108.js create mode 100644 js/src/jit-test/tests/basic/bug594205.js create mode 100644 js/src/jit-test/tests/basic/bug595963-1.js create mode 100644 js/src/jit-test/tests/basic/bug595963-2.js create mode 100644 js/src/jit-test/tests/basic/bug596502-version.js create mode 100644 js/src/jit-test/tests/basic/bug599854.js create mode 100644 js/src/jit-test/tests/basic/bug601046.js create mode 100644 js/src/jit-test/tests/basic/bug601395.js create mode 100644 js/src/jit-test/tests/basic/bug601398.js create mode 100644 js/src/jit-test/tests/basic/bug601401.js create mode 100644 js/src/jit-test/tests/basic/bug601402.js create mode 100644 js/src/jit-test/tests/basic/bug601428.js create mode 100644 js/src/jit-test/tests/basic/bug602088.js create mode 100644 js/src/jit-test/tests/basic/bug605015.js create mode 100644 js/src/jit-test/tests/basic/bug605754-regexp.js create mode 100644 js/src/jit-test/tests/basic/bug606083.js create mode 100644 js/src/jit-test/tests/basic/bug606882-1.js create mode 100644 js/src/jit-test/tests/basic/bug606882-2.js create mode 100644 js/src/jit-test/tests/basic/bug608313.js create mode 100644 js/src/jit-test/tests/basic/bug608980.js create mode 100644 js/src/jit-test/tests/basic/bug609502-1.js create mode 100644 js/src/jit-test/tests/basic/bug609502-2.js create mode 100644 js/src/jit-test/tests/basic/bug609502-3.js create mode 100644 js/src/jit-test/tests/basic/bug610592.js create mode 100644 js/src/jit-test/tests/basic/bug613122.js create mode 100644 js/src/jit-test/tests/basic/bug613151.js create mode 100644 js/src/jit-test/tests/basic/bug613399.js create mode 100644 js/src/jit-test/tests/basic/bug614915.js create mode 100644 js/src/jit-test/tests/basic/bug616762.js create mode 100644 js/src/jit-test/tests/basic/bug617139.js create mode 100644 js/src/jit-test/tests/basic/bug617171.js create mode 100644 js/src/jit-test/tests/basic/bug618350.js create mode 100644 js/src/jit-test/tests/basic/bug618577.js create mode 100644 js/src/jit-test/tests/basic/bug619004.js create mode 100644 js/src/jit-test/tests/basic/bug620532.js create mode 100644 js/src/jit-test/tests/basic/bug620838.js create mode 100644 js/src/jit-test/tests/basic/bug621022-1.js create mode 100644 js/src/jit-test/tests/basic/bug621022-2.js create mode 100644 js/src/jit-test/tests/basic/bug623859.js create mode 100644 js/src/jit-test/tests/basic/bug623863.js create mode 100644 js/src/jit-test/tests/basic/bug624041-1.js create mode 100644 js/src/jit-test/tests/basic/bug624041-2.js create mode 100644 js/src/jit-test/tests/basic/bug625141-1.js create mode 100644 js/src/jit-test/tests/basic/bug625141-2.js create mode 100644 js/src/jit-test/tests/basic/bug625399.js create mode 100644 js/src/jit-test/tests/basic/bug627609.js create mode 100644 js/src/jit-test/tests/basic/bug627692-1.js create mode 100644 js/src/jit-test/tests/basic/bug627692-2.js create mode 100644 js/src/jit-test/tests/basic/bug630377.js create mode 100644 js/src/jit-test/tests/basic/bug630865-1.js create mode 100644 js/src/jit-test/tests/basic/bug630865-2.js create mode 100644 js/src/jit-test/tests/basic/bug630865-3.js create mode 100644 js/src/jit-test/tests/basic/bug630865-4.js create mode 100644 js/src/jit-test/tests/basic/bug630865-5.js create mode 100644 js/src/jit-test/tests/basic/bug630865-6.js create mode 100644 js/src/jit-test/tests/basic/bug631082.js create mode 100644 js/src/jit-test/tests/basic/bug631219.js create mode 100644 js/src/jit-test/tests/basic/bug631305.js create mode 100644 js/src/jit-test/tests/basic/bug631788.js create mode 100644 js/src/jit-test/tests/basic/bug632206.js create mode 100644 js/src/jit-test/tests/basic/bug632901.js create mode 100644 js/src/jit-test/tests/basic/bug632964-regexp.js create mode 100644 js/src/jit-test/tests/basic/bug633409-1.js create mode 100644 js/src/jit-test/tests/basic/bug633409-2.js create mode 100644 js/src/jit-test/tests/basic/bug633752.js create mode 100644 js/src/jit-test/tests/basic/bug633890.js create mode 100644 js/src/jit-test/tests/basic/bug634593.js create mode 100644 js/src/jit-test/tests/basic/bug635417.js create mode 100644 js/src/jit-test/tests/basic/call.js create mode 100644 js/src/jit-test/tests/basic/call2.js create mode 100644 js/src/jit-test/tests/basic/createMandelSet.js create mode 100644 js/src/jit-test/tests/basic/deep2.js create mode 100644 js/src/jit-test/tests/basic/deepForInLoop.js create mode 100644 js/src/jit-test/tests/basic/delete-array-elements.js create mode 100644 js/src/jit-test/tests/basic/delete-indexed-names.js create mode 100644 js/src/jit-test/tests/basic/delete-integer-nonid.js create mode 100644 js/src/jit-test/tests/basic/delete-named-names.js create mode 100644 js/src/jit-test/tests/basic/delete-non-config.js create mode 100644 js/src/jit-test/tests/basic/dependentStrings.js create mode 100644 js/src/jit-test/tests/basic/doMath.js create mode 100644 js/src/jit-test/tests/basic/equalInt.js create mode 100644 js/src/jit-test/tests/basic/fannkuch.js create mode 100644 js/src/jit-test/tests/basic/firstSlotConflict.js create mode 100644 js/src/jit-test/tests/basic/forVarInWith.js create mode 100644 js/src/jit-test/tests/basic/function-bind.js create mode 100644 js/src/jit-test/tests/basic/getelem.js create mode 100644 js/src/jit-test/tests/basic/getprop.js create mode 100644 js/src/jit-test/tests/basic/globalGet.js create mode 100644 js/src/jit-test/tests/basic/globalOptimize-1.js create mode 100644 js/src/jit-test/tests/basic/globalSet.js create mode 100644 js/src/jit-test/tests/basic/ifInsideLoop.js create mode 100644 js/src/jit-test/tests/basic/inArrayTest.js create mode 100644 js/src/jit-test/tests/basic/inObjectTest.js create mode 100644 js/src/jit-test/tests/basic/innerLoopIntOuterDouble.js create mode 100644 js/src/jit-test/tests/basic/inner_double_outer_int.js create mode 100644 js/src/jit-test/tests/basic/jitstatsArchFlags.js create mode 100644 js/src/jit-test/tests/basic/joinTest.js create mode 100644 js/src/jit-test/tests/basic/matchInLoop.js create mode 100644 js/src/jit-test/tests/basic/math-jit-tests.js create mode 100644 js/src/jit-test/tests/basic/merge_type_maps.js create mode 100644 js/src/jit-test/tests/basic/missingArgTest.js create mode 100644 js/src/jit-test/tests/basic/missingArgTest2.js create mode 100644 js/src/jit-test/tests/basic/mod.js create mode 100644 js/src/jit-test/tests/basic/name-inactive-del.js create mode 100644 js/src/jit-test/tests/basic/name-inactive-eval-del.js create mode 100644 js/src/jit-test/tests/basic/name-inactive-inferflags.js create mode 100644 js/src/jit-test/tests/basic/name-inactive.js create mode 100644 js/src/jit-test/tests/basic/name.js create mode 100644 js/src/jit-test/tests/basic/nestedExit2.js create mode 100644 js/src/jit-test/tests/basic/nestedExitLoop.js create mode 100644 js/src/jit-test/tests/basic/new-Function-prototype.js create mode 100644 js/src/jit-test/tests/basic/new-bound-function.js create mode 100644 js/src/jit-test/tests/basic/newArrayTest.js create mode 100644 js/src/jit-test/tests/basic/newTest.js create mode 100644 js/src/jit-test/tests/basic/nonEmptyStack1.js create mode 100644 js/src/jit-test/tests/basic/nonEmptyStack2.js create mode 100644 js/src/jit-test/tests/basic/orNaNTest1.js create mode 100644 js/src/jit-test/tests/basic/orNaNTest2.js create mode 100644 js/src/jit-test/tests/basic/outerline.js create mode 100644 js/src/jit-test/tests/basic/parseIntTests.js create mode 100644 js/src/jit-test/tests/basic/parsingNumbers.js create mode 100644 js/src/jit-test/tests/basic/perf-smoketest.js create mode 100644 js/src/jit-test/tests/basic/putargsNoReturn.js create mode 100644 js/src/jit-test/tests/basic/putargsReturn.js create mode 100644 js/src/jit-test/tests/basic/regexp-reset-input.js create mode 100644 js/src/jit-test/tests/basic/regexp-sticky-undef-capture.js create mode 100644 js/src/jit-test/tests/basic/regexpLastIndex.js create mode 100644 js/src/jit-test/tests/basic/setArgumentsLength.js create mode 100644 js/src/jit-test/tests/basic/setArgumentsLength2.js create mode 100644 js/src/jit-test/tests/basic/setCall.js create mode 100644 js/src/jit-test/tests/basic/setCallEvalMiddle.js create mode 100644 js/src/jit-test/tests/basic/setCallEvalMiddle2.js create mode 100644 js/src/jit-test/tests/basic/setCallGlobal.js create mode 100644 js/src/jit-test/tests/basic/setelem.js create mode 100644 js/src/jit-test/tests/basic/setprop.js create mode 100644 js/src/jit-test/tests/basic/shapelessCalleeTest.js create mode 100644 js/src/jit-test/tests/basic/strict-eval-loop-error.js create mode 100644 js/src/jit-test/tests/basic/strictParseIntOctal.js create mode 100644 js/src/jit-test/tests/basic/stringConvert.js create mode 100644 js/src/jit-test/tests/basic/stringSplitIntoArrayTest.js create mode 100644 js/src/jit-test/tests/basic/stringSplitTest.js create mode 100644 js/src/jit-test/tests/basic/strings.js create mode 100644 js/src/jit-test/tests/basic/test586387.js create mode 100644 js/src/jit-test/tests/basic/testAbortedImacroDecompilation.js create mode 100644 js/src/jit-test/tests/basic/testAccessCanonicalArgInGetElem.js create mode 100644 js/src/jit-test/tests/basic/testAddAnyInconvertibleObject.js create mode 100644 js/src/jit-test/tests/basic/testAddInconvertibleObjectAny.js create mode 100644 js/src/jit-test/tests/basic/testAddInconvertibleObjectInconvertibleObject.js create mode 100644 js/src/jit-test/tests/basic/testAddNull.js create mode 100644 js/src/jit-test/tests/basic/testAddUndefined.js create mode 100644 js/src/jit-test/tests/basic/testApply.js create mode 100644 js/src/jit-test/tests/basic/testApplyAtJoinPoint.js create mode 100644 js/src/jit-test/tests/basic/testApplyCall.js create mode 100644 js/src/jit-test/tests/basic/testApplyUnbox.js create mode 100644 js/src/jit-test/tests/basic/testArrayComp1.js create mode 100644 js/src/jit-test/tests/basic/testArrayComp2.js create mode 100644 js/src/jit-test/tests/basic/testArrayDensityChange.js create mode 100644 js/src/jit-test/tests/basic/testArrayIn.js create mode 100644 js/src/jit-test/tests/basic/testArrayInWithIndexedProto.js create mode 100644 js/src/jit-test/tests/basic/testArrayNaNIndex.js create mode 100644 js/src/jit-test/tests/basic/testArrayNamedProp.js create mode 100644 js/src/jit-test/tests/basic/testArrayPushPop.js create mode 100644 js/src/jit-test/tests/basic/testAssigningWatchedDeletedProperty.js create mode 100644 js/src/jit-test/tests/basic/testAssignmentThatIgnoresSetterRetval.js create mode 100644 js/src/jit-test/tests/basic/testAtomize.js create mode 100644 js/src/jit-test/tests/basic/testBitOrAnyInconvertibleObject.js create mode 100644 js/src/jit-test/tests/basic/testBitOrInconvertibleObjectAny.js create mode 100644 js/src/jit-test/tests/basic/testBitOrInconvertibleObjectInconvertibleObject.js create mode 100644 js/src/jit-test/tests/basic/testBitwise.js create mode 100644 js/src/jit-test/tests/basic/testBoolToString.js create mode 100644 js/src/jit-test/tests/basic/testBoxDoubleWithDoubleSizedInt.js create mode 100644 js/src/jit-test/tests/basic/testBranchCse.js create mode 100644 js/src/jit-test/tests/basic/testBranchingLoop.js create mode 100644 js/src/jit-test/tests/basic/testBranchingUnstableLoop.js create mode 100644 js/src/jit-test/tests/basic/testBranchingUnstableLoopCounter.js create mode 100644 js/src/jit-test/tests/basic/testBranchingUnstableObject.js create mode 100644 js/src/jit-test/tests/basic/testBrandedVsGeneric.js create mode 100644 js/src/jit-test/tests/basic/testBreak.js create mode 100644 js/src/jit-test/tests/basic/testBug458838.js create mode 100644 js/src/jit-test/tests/basic/testBug462388.js create mode 100644 js/src/jit-test/tests/basic/testBug462407.js create mode 100644 js/src/jit-test/tests/basic/testBug463490.js create mode 100644 js/src/jit-test/tests/basic/testBug465261.js create mode 100644 js/src/jit-test/tests/basic/testBug465272.js create mode 100644 js/src/jit-test/tests/basic/testBug465483.js create mode 100644 js/src/jit-test/tests/basic/testBug465688.js create mode 100644 js/src/jit-test/tests/basic/testBug466128.js create mode 100644 js/src/jit-test/tests/basic/testBug466262.js create mode 100644 js/src/jit-test/tests/basic/testBug474769.js create mode 100644 js/src/jit-test/tests/basic/testBug501690.js create mode 100644 js/src/jit-test/tests/basic/testBug502914.js create mode 100644 js/src/jit-test/tests/basic/testBug504520.js create mode 100644 js/src/jit-test/tests/basic/testBug504520Harder.js create mode 100644 js/src/jit-test/tests/basic/testBug507425.js create mode 100644 js/src/jit-test/tests/basic/testBug520503-1.js create mode 100644 js/src/jit-test/tests/basic/testBug520503-2.js create mode 100644 js/src/jit-test/tests/basic/testBug520503-3.js create mode 100644 js/src/jit-test/tests/basic/testBug529147.js create mode 100644 js/src/jit-test/tests/basic/testBug547791.js create mode 100644 js/src/jit-test/tests/basic/testBug550210.js create mode 100644 js/src/jit-test/tests/basic/testBug552248.js create mode 100644 js/src/jit-test/tests/basic/testBug554043.js create mode 100644 js/src/jit-test/tests/basic/testBug555484.js create mode 100644 js/src/jit-test/tests/basic/testBug558446.js create mode 100644 js/src/jit-test/tests/basic/testBug560098.js create mode 100644 js/src/jit-test/tests/basic/testBug566556.js create mode 100644 js/src/jit-test/tests/basic/testBug578044.js create mode 100644 js/src/jit-test/tests/basic/testBug579602.js create mode 100644 js/src/jit-test/tests/basic/testBug579646.js create mode 100644 js/src/jit-test/tests/basic/testBug579647.js create mode 100644 js/src/jit-test/tests/basic/testBug582766.js create mode 100644 js/src/jit-test/tests/basic/testBug584650.js create mode 100644 js/src/jit-test/tests/basic/testBug586866.js create mode 100644 js/src/jit-test/tests/basic/testBug593559.js create mode 100644 js/src/jit-test/tests/basic/testBug595916.js create mode 100644 js/src/jit-test/tests/basic/testBug597736.js create mode 100644 js/src/jit-test/tests/basic/testBug602413.js create mode 100644 js/src/jit-test/tests/basic/testBug603193.js create mode 100644 js/src/jit-test/tests/basic/testBug604210.js create mode 100644 js/src/jit-test/tests/basic/testBug606138.js create mode 100644 js/src/jit-test/tests/basic/testBug607659.js create mode 100644 js/src/jit-test/tests/basic/testBug614653.js create mode 100644 js/src/jit-test/tests/basic/testBug614752.js create mode 100644 js/src/jit-test/tests/basic/testBug616119.js create mode 100644 js/src/jit-test/tests/basic/testBug616454.js create mode 100644 js/src/jit-test/tests/basic/testBug621202.js create mode 100644 js/src/jit-test/tests/basic/testBug628564.js create mode 100644 js/src/jit-test/tests/basic/testBug629974.js create mode 100644 js/src/jit-test/tests/basic/testBug630064.js create mode 100644 js/src/jit-test/tests/basic/testBug634590.js create mode 100644 js/src/jit-test/tests/basic/testBug634590b.js create mode 100644 js/src/jit-test/tests/basic/testBug634590c.js create mode 100644 js/src/jit-test/tests/basic/testBug634590d.js create mode 100644 js/src/jit-test/tests/basic/testBug634590ma.js create mode 100644 js/src/jit-test/tests/basic/testCallApply.js create mode 100644 js/src/jit-test/tests/basic/testCallElem.js create mode 100644 js/src/jit-test/tests/basic/testCallNull.js create mode 100644 js/src/jit-test/tests/basic/testCallPick.js create mode 100644 js/src/jit-test/tests/basic/testCallProtoMethod.js create mode 100644 js/src/jit-test/tests/basic/testCaseAbort.js create mode 100644 js/src/jit-test/tests/basic/testCaseTypeMismatchBadness.js create mode 100644 js/src/jit-test/tests/basic/testChangingObjectWithLength.js create mode 100644 js/src/jit-test/tests/basic/testChangingTypeDuringRecording.js create mode 100644 js/src/jit-test/tests/basic/testClosingRecursion.js create mode 100644 js/src/jit-test/tests/basic/testClosureIncrSideExit.js create mode 100644 js/src/jit-test/tests/basic/testClosures.js create mode 100644 js/src/jit-test/tests/basic/testComparisons.js create mode 100644 js/src/jit-test/tests/basic/testConcatNWithSideEffects.js create mode 100644 js/src/jit-test/tests/basic/testConstIf.js create mode 100644 js/src/jit-test/tests/basic/testConstSwitch.js create mode 100644 js/src/jit-test/tests/basic/testConstSwitch2.js create mode 100644 js/src/jit-test/tests/basic/testConstantBooleanExpr.js create mode 100644 js/src/jit-test/tests/basic/testConstructorArgs-1.js create mode 100644 js/src/jit-test/tests/basic/testConstructorArgs-2.js create mode 100644 js/src/jit-test/tests/basic/testConstructorArgs-3.js create mode 100644 js/src/jit-test/tests/basic/testConstructorBail.js create mode 100644 js/src/jit-test/tests/basic/testContinue.js create mode 100644 js/src/jit-test/tests/basic/testContinueWithLabel.js create mode 100644 js/src/jit-test/tests/basic/testContinueWithLabel2.js create mode 100644 js/src/jit-test/tests/basic/testContinueWithLabel3.js create mode 100644 js/src/jit-test/tests/basic/testContinueWithLabel4.js create mode 100644 js/src/jit-test/tests/basic/testConvertibleObjectEqUndefined.js create mode 100644 js/src/jit-test/tests/basic/testCustomIterator.js create mode 100644 js/src/jit-test/tests/basic/testDateNow.js create mode 100644 js/src/jit-test/tests/basic/testDecElem1.js create mode 100644 js/src/jit-test/tests/basic/testDecElem2.js create mode 100644 js/src/jit-test/tests/basic/testDecayingInnerLoop.js create mode 100644 js/src/jit-test/tests/basic/testDeepBail1.js create mode 100644 js/src/jit-test/tests/basic/testDeepBailFromHasInstance.js create mode 100644 js/src/jit-test/tests/basic/testDeepBailInMoreIter.js create mode 100644 js/src/jit-test/tests/basic/testDeepBailWhileRecording.js create mode 100644 js/src/jit-test/tests/basic/testDeepPropertyShadowing.js create mode 100644 js/src/jit-test/tests/basic/testDefinePropertyAcrossCompartment.js create mode 100644 js/src/jit-test/tests/basic/testDenseArrayProp.js create mode 100644 js/src/jit-test/tests/basic/testDenseToSlowArray.js create mode 100644 js/src/jit-test/tests/basic/testDestructuring.js create mode 100644 js/src/jit-test/tests/basic/testDifferingArgc.js create mode 100644 js/src/jit-test/tests/basic/testDivOverflow.js create mode 100644 js/src/jit-test/tests/basic/testDivision.js create mode 100644 js/src/jit-test/tests/basic/testDivisionFloat.js create mode 100644 js/src/jit-test/tests/basic/testDivisionWithNegative1.js create mode 100644 js/src/jit-test/tests/basic/testDoubleComparison.js create mode 100644 js/src/jit-test/tests/basic/testDoubleToStr.js create mode 100644 js/src/jit-test/tests/basic/testDoubleZeroInSwitch1.js create mode 100644 js/src/jit-test/tests/basic/testDoubleZeroInSwitch2.js create mode 100644 js/src/jit-test/tests/basic/testElemDec1.js create mode 100644 js/src/jit-test/tests/basic/testElemDec2.js create mode 100644 js/src/jit-test/tests/basic/testElemInc1.js create mode 100644 js/src/jit-test/tests/basic/testElemInc2.js create mode 100644 js/src/jit-test/tests/basic/testEliminatedGuardWithinAnchor.js create mode 100644 js/src/jit-test/tests/basic/testEqFalseEmptyString.js create mode 100644 js/src/jit-test/tests/basic/testErrorReportIn_getPrototypeOf.js create mode 100644 js/src/jit-test/tests/basic/testEvalCalledFromWatchOverSetter.js create mode 100644 js/src/jit-test/tests/basic/testEvalInFunctionCallee.js create mode 100644 js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-2.js create mode 100644 js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-3.js create mode 100644 js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-4.js create mode 100644 js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt.js create mode 100644 js/src/jit-test/tests/basic/testFewerGlobalsInInnerTree.js create mode 100644 js/src/jit-test/tests/basic/testFloatArrayIndex.js create mode 100644 js/src/jit-test/tests/basic/testForEach.js create mode 100644 js/src/jit-test/tests/basic/testForInLoopChangeIteratorType.js create mode 100644 js/src/jit-test/tests/basic/testFunctionIdentityChange.js create mode 100644 js/src/jit-test/tests/basic/testGCWhileRecording.js create mode 100644 js/src/jit-test/tests/basic/testGeneratorDeepBail.js create mode 100644 js/src/jit-test/tests/basic/testGetCallObj.js create mode 100644 js/src/jit-test/tests/basic/testGetThis.js create mode 100644 js/src/jit-test/tests/basic/testGlobalAsProto.js create mode 100644 js/src/jit-test/tests/basic/testGlobalMultitrees1.js create mode 100644 js/src/jit-test/tests/basic/testGlobalOptimize-2.js create mode 100644 js/src/jit-test/tests/basic/testGlobalOptimize-3.js create mode 100644 js/src/jit-test/tests/basic/testGlobalOptimize-4.js create mode 100644 js/src/jit-test/tests/basic/testGlobalOptimize-5.js create mode 100644 js/src/jit-test/tests/basic/testGlobalOptimize-6.js create mode 100644 js/src/jit-test/tests/basic/testGlobalProtoAccess.js create mode 100644 js/src/jit-test/tests/basic/testGlobalShapeChangeAfterDeepBail.js create mode 100644 js/src/jit-test/tests/basic/testGroupAssignment.js create mode 100644 js/src/jit-test/tests/basic/testGrowDenseArray.js create mode 100644 js/src/jit-test/tests/basic/testGuardCalleeSneakAttack.js create mode 100644 js/src/jit-test/tests/basic/testGuardCalleeSneakAttack2.js create mode 100644 js/src/jit-test/tests/basic/testHOTLOOPCorrectness.js create mode 100644 js/src/jit-test/tests/basic/testHOTLOOPSize.js create mode 100644 js/src/jit-test/tests/basic/testHeavy.js create mode 100644 js/src/jit-test/tests/basic/testHeavy2.js create mode 100644 js/src/jit-test/tests/basic/testHoleInDenseArray.js create mode 100644 js/src/jit-test/tests/basic/testHolePushing.js create mode 100644 js/src/jit-test/tests/basic/testHolesAndIndexPropertiesOnThePrototype.js create mode 100644 js/src/jit-test/tests/basic/testINITELEM.js create mode 100644 js/src/jit-test/tests/basic/testIn.js create mode 100644 js/src/jit-test/tests/basic/testIncDec.js create mode 100644 js/src/jit-test/tests/basic/testIncDecReadOnly.js create mode 100644 js/src/jit-test/tests/basic/testIncElem1.js create mode 100644 js/src/jit-test/tests/basic/testIncElem2.js create mode 100644 js/src/jit-test/tests/basic/testIncElem3.js create mode 100644 js/src/jit-test/tests/basic/testInitDictionary.js create mode 100644 js/src/jit-test/tests/basic/testInitMethod.js create mode 100644 js/src/jit-test/tests/basic/testInitPropOverMethod.js create mode 100644 js/src/jit-test/tests/basic/testInitPropWithIntName.js create mode 100644 js/src/jit-test/tests/basic/testInitProtoPrimitive.js create mode 100644 js/src/jit-test/tests/basic/testInitSharp.js create mode 100644 js/src/jit-test/tests/basic/testInitSingletons.js create mode 100644 js/src/jit-test/tests/basic/testInitSlowify.js create mode 100644 js/src/jit-test/tests/basic/testInitelemCond.js create mode 100644 js/src/jit-test/tests/basic/testInitelemWithFloatIndex.js create mode 100644 js/src/jit-test/tests/basic/testInitelemWithSetter.js create mode 100644 js/src/jit-test/tests/basic/testInnerMissingArgs.js create mode 100644 js/src/jit-test/tests/basic/testInnerSwitchBreak.js create mode 100644 js/src/jit-test/tests/basic/testInnerTreeMutatingUpvars.js create mode 100644 js/src/jit-test/tests/basic/testInt32ToId.js create mode 100644 js/src/jit-test/tests/basic/testIntFloor.js create mode 100644 js/src/jit-test/tests/basic/testIntOverflow.js create mode 100644 js/src/jit-test/tests/basic/testIntUnderflow.js create mode 100644 js/src/jit-test/tests/basic/testInterpreterReentery8.js create mode 100644 js/src/jit-test/tests/basic/testInterpreterReentry.js create mode 100644 js/src/jit-test/tests/basic/testInterpreterReentry2.js create mode 100644 js/src/jit-test/tests/basic/testInterpreterReentry3.js create mode 100644 js/src/jit-test/tests/basic/testInterpreterReentry4.js create mode 100644 js/src/jit-test/tests/basic/testInterpreterReentry5.js create mode 100644 js/src/jit-test/tests/basic/testInterpreterReentry6.js create mode 100644 js/src/jit-test/tests/basic/testInterpreterReentry7.js create mode 100644 js/src/jit-test/tests/basic/testInvalidCharCodeAt.js create mode 100644 js/src/jit-test/tests/basic/testInvertNullAfterNegateNull.js create mode 100644 js/src/jit-test/tests/basic/testIteratorReification.js create mode 100644 js/src/jit-test/tests/basic/testLambdaCtor.js create mode 100644 js/src/jit-test/tests/basic/testLambdaInitedVar.js create mode 100644 js/src/jit-test/tests/basic/testLengthInString.js create mode 100644 js/src/jit-test/tests/basic/testLengthOnNonNativeProto.js create mode 100644 js/src/jit-test/tests/basic/testLetWithUnstableGlobal.js create mode 100644 js/src/jit-test/tests/basic/testLirBufOOM.js create mode 100644 js/src/jit-test/tests/basic/testLogicalNotNaN.js create mode 100644 js/src/jit-test/tests/basic/testLongNumToString.js create mode 100644 js/src/jit-test/tests/basic/testLoopWithUndefined1.js create mode 100644 js/src/jit-test/tests/basic/testLoopWithUndefined2.js create mode 100644 js/src/jit-test/tests/basic/testLoopingAccumulator.js create mode 100644 js/src/jit-test/tests/basic/testMatchAsCondition.js create mode 100644 js/src/jit-test/tests/basic/testMatchStringObject.js create mode 100644 js/src/jit-test/tests/basic/testMethodInc.js create mode 100644 js/src/jit-test/tests/basic/testMethodInit.js create mode 100644 js/src/jit-test/tests/basic/testMethodInitDeref.js create mode 100644 js/src/jit-test/tests/basic/testMethodInitSafety.js create mode 100644 js/src/jit-test/tests/basic/testMethodInitUneval.js create mode 100644 js/src/jit-test/tests/basic/testMethodOverride.js create mode 100644 js/src/jit-test/tests/basic/testMethodSet.js create mode 100644 js/src/jit-test/tests/basic/testMethodWriteBarrier.js create mode 100644 js/src/jit-test/tests/basic/testMethodWriteBarrier2.js create mode 100644 js/src/jit-test/tests/basic/testMethodWriteBarrier3.js create mode 100644 js/src/jit-test/tests/basic/testMethodWriteBarrier4.js create mode 100644 js/src/jit-test/tests/basic/testMissingMethod.js create mode 100644 js/src/jit-test/tests/basic/testMissingMethod2.js create mode 100644 js/src/jit-test/tests/basic/testModuloWithNegative1.js create mode 100644 js/src/jit-test/tests/basic/testModuloWithNegative2.js create mode 100644 js/src/jit-test/tests/basic/testMoreArgcThanNargs.js create mode 100644 js/src/jit-test/tests/basic/testMoreClosures.js create mode 100644 js/src/jit-test/tests/basic/testMulOverflow.js create mode 100644 js/src/jit-test/tests/basic/testMultipleArgumentsObjects.js create mode 100644 js/src/jit-test/tests/basic/testMultiplePendingGlobalWrites.js create mode 100644 js/src/jit-test/tests/basic/testNEWINIT.js create mode 100644 js/src/jit-test/tests/basic/testNEWINIT_DOUBLE.js create mode 100644 js/src/jit-test/tests/basic/testNativeArgsRooting.js create mode 100644 js/src/jit-test/tests/basic/testNativeLog.js create mode 100644 js/src/jit-test/tests/basic/testNativeMax.js create mode 100644 js/src/jit-test/tests/basic/testNativeSetter.js create mode 100644 js/src/jit-test/tests/basic/testNegZero1.js create mode 100644 js/src/jit-test/tests/basic/testNegativeArrayLength.js create mode 100644 js/src/jit-test/tests/basic/testNegativeGETELEMIndex.js create mode 100644 js/src/jit-test/tests/basic/testNestedClosures.js create mode 100644 js/src/jit-test/tests/basic/testNestedDeepBail.js create mode 100644 js/src/jit-test/tests/basic/testNestedEscapingLambdas.js create mode 100644 js/src/jit-test/tests/basic/testNestedExitStackOuter.js create mode 100644 js/src/jit-test/tests/basic/testNestedForIn.js create mode 100644 js/src/jit-test/tests/basic/testNewArrayCount.js create mode 100644 js/src/jit-test/tests/basic/testNewArrayCount2.js create mode 100644 js/src/jit-test/tests/basic/testNewDate.js create mode 100644 js/src/jit-test/tests/basic/testNewObject.js create mode 100644 js/src/jit-test/tests/basic/testNewString.js create mode 100644 js/src/jit-test/tests/basic/testNewWithNonNativeProto.js create mode 100644 js/src/jit-test/tests/basic/testNonStubGetter.js create mode 100644 js/src/jit-test/tests/basic/testNot.js create mode 100644 js/src/jit-test/tests/basic/testNullCallee.js create mode 100644 js/src/jit-test/tests/basic/testNullIncrement.js create mode 100644 js/src/jit-test/tests/basic/testNullRelCmp.js create mode 100644 js/src/jit-test/tests/basic/testNullToString.js create mode 100644 js/src/jit-test/tests/basic/testNumToString.js create mode 100644 js/src/jit-test/tests/basic/testNumberToString.js create mode 100644 js/src/jit-test/tests/basic/testObjectConstructorReturningObject.js create mode 100644 js/src/jit-test/tests/basic/testObjectLength.js create mode 100644 js/src/jit-test/tests/basic/testObjectOrderedCmp.js create mode 100644 js/src/jit-test/tests/basic/testObjectOrderedCmp2.js create mode 100644 js/src/jit-test/tests/basic/testObjectToNumber.js create mode 100644 js/src/jit-test/tests/basic/testObjectToString.js create mode 100644 js/src/jit-test/tests/basic/testObjectVsPrototype.js create mode 100644 js/src/jit-test/tests/basic/testOwnPropertyWithInOperator.js create mode 100644 js/src/jit-test/tests/basic/testPartialFlatClosure.js create mode 100644 js/src/jit-test/tests/basic/testPrimitiveConstructorPrototype.js create mode 100644 js/src/jit-test/tests/basic/testPropagatedFunArgs.js create mode 100644 js/src/jit-test/tests/basic/testProxyConstructors.js create mode 100644 js/src/jit-test/tests/basic/testProxyDefinePropertyWithMissingSetter.js create mode 100644 js/src/jit-test/tests/basic/testPutOnEmptyArgsObject.js create mode 100644 js/src/jit-test/tests/basic/testRUNLOOPCorrectness.js create mode 100644 js/src/jit-test/tests/basic/testReallyDeepNestedExit.js create mode 100644 js/src/jit-test/tests/basic/testRebranding.js create mode 100644 js/src/jit-test/tests/basic/testRebranding2.js create mode 100644 js/src/jit-test/tests/basic/testReconstructImacroPCStack.js create mode 100644 js/src/jit-test/tests/basic/testRegExpLiteral.js create mode 100644 js/src/jit-test/tests/basic/testRegExpTest.js create mode 100644 js/src/jit-test/tests/basic/testRegexpGet.js create mode 100644 js/src/jit-test/tests/basic/testReplace2.js create mode 100644 js/src/jit-test/tests/basic/testReplaceMap.js create mode 100644 js/src/jit-test/tests/basic/testResumeOp.js create mode 100644 js/src/jit-test/tests/basic/testReverseArgTypes.js create mode 100644 js/src/jit-test/tests/basic/testScriptGetter_JSOP_CALLPROP-2.js create mode 100644 js/src/jit-test/tests/basic/testScriptGetter_JSOP_CALLPROP.js create mode 100644 js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETARGPROP.js create mode 100644 js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETLOCALPROP.js create mode 100644 js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETPROP.js create mode 100644 js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETTHISPROP.js create mode 100644 js/src/jit-test/tests/basic/testSetGetterOnlyProperty.js create mode 100644 js/src/jit-test/tests/basic/testSetMethod.js create mode 100644 js/src/jit-test/tests/basic/testSetPropNeitherMissNorHit.js create mode 100644 js/src/jit-test/tests/basic/testSetPropertyFail.js create mode 100644 js/src/jit-test/tests/basic/testSetProtoRegeneratesObjectShape.js create mode 100644 js/src/jit-test/tests/basic/testSetelemWithFloatIndex.js create mode 100644 js/src/jit-test/tests/basic/testSettingWatchPointOnReadOnlyProp.js create mode 100644 js/src/jit-test/tests/basic/testShiftLeft.js create mode 100644 js/src/jit-test/tests/basic/testShiftRightArithmetic.js create mode 100644 js/src/jit-test/tests/basic/testShiftRightLogical.js create mode 100644 js/src/jit-test/tests/basic/testSideExitInConstructor.js create mode 100644 js/src/jit-test/tests/basic/testSlowArrayLength.js create mode 100644 js/src/jit-test/tests/basic/testSlowArrayPop.js create mode 100644 js/src/jit-test/tests/basic/testSlowArrayPopMultiFrame.js create mode 100644 js/src/jit-test/tests/basic/testSlowArrayPopNestedTrees.js create mode 100644 js/src/jit-test/tests/basic/testSlowNativeBail.js create mode 100644 js/src/jit-test/tests/basic/testSlowNativeCtor.js create mode 100644 js/src/jit-test/tests/basic/testSlowNativeWithNullThis.js create mode 100644 js/src/jit-test/tests/basic/testStackQuotaExhausted.js create mode 100644 js/src/jit-test/tests/basic/testStaticsInRegExp.js create mode 100644 js/src/jit-test/tests/basic/testStrict.js create mode 100644 js/src/jit-test/tests/basic/testString.js create mode 100644 js/src/jit-test/tests/basic/testStringConstructorWithExtraArg.js create mode 100644 js/src/jit-test/tests/basic/testStringIncrement.js create mode 100644 js/src/jit-test/tests/basic/testStringLengthNoTinyId.js create mode 100644 js/src/jit-test/tests/basic/testStringObjectLength.js create mode 100644 js/src/jit-test/tests/basic/testStringPropIncrement.js create mode 100644 js/src/jit-test/tests/basic/testStringResolve.js create mode 100644 js/src/jit-test/tests/basic/testStringToInt32.js create mode 100644 js/src/jit-test/tests/basic/testStringToNumber.js create mode 100644 js/src/jit-test/tests/basic/testStringify.js create mode 100644 js/src/jit-test/tests/basic/testSubstring.js create mode 100644 js/src/jit-test/tests/basic/testSuppressDeletedProperty.js create mode 100644 js/src/jit-test/tests/basic/testSwitch.js create mode 100644 js/src/jit-test/tests/basic/testSwitchString.js create mode 100644 js/src/jit-test/tests/basic/testSwitchUndefined.js create mode 100644 js/src/jit-test/tests/basic/testTableSwitch1.js create mode 100644 js/src/jit-test/tests/basic/testTableSwitch2.js create mode 100644 js/src/jit-test/tests/basic/testThinForEach.js create mode 100644 js/src/jit-test/tests/basic/testThinLoopDemote.js create mode 100644 js/src/jit-test/tests/basic/testThrowingObjectEqUndefined.js create mode 100644 js/src/jit-test/tests/basic/testToLocaleString.js create mode 100644 js/src/jit-test/tests/basic/testToStringBeforeValueOf.js create mode 100644 js/src/jit-test/tests/basic/testToUpperToLower.js create mode 100644 js/src/jit-test/tests/basic/testTrueShiftTrue.js create mode 100644 js/src/jit-test/tests/basic/testTypeUnstableForIn.js create mode 100644 js/src/jit-test/tests/basic/testTypedArrayPunning.js create mode 100644 js/src/jit-test/tests/basic/testTypedArrays.js create mode 100644 js/src/jit-test/tests/basic/testTypeofHole.js create mode 100644 js/src/jit-test/tests/basic/testUnaryImacros.js create mode 100644 js/src/jit-test/tests/basic/testUndefinedBooleanCmp.js create mode 100644 js/src/jit-test/tests/basic/testUndefinedCmp.js create mode 100644 js/src/jit-test/tests/basic/testUndefinedIncrement.js create mode 100644 js/src/jit-test/tests/basic/testUndefinedPropertyAccess.js create mode 100644 js/src/jit-test/tests/basic/testUndemotableBinaryOp.js create mode 100644 js/src/jit-test/tests/basic/testUndemoteLateGlobalSlots.js create mode 100644 js/src/jit-test/tests/basic/testWeirdDateParse.js create mode 100644 js/src/jit-test/tests/basic/testWhileObjectOrNull.js create mode 100644 js/src/jit-test/tests/basic/testWhileWithContinue.js create mode 100644 js/src/jit-test/tests/basic/testWithAndShadowing.js create mode 100644 js/src/jit-test/tests/basic/testXMLPropertyNames.js create mode 100644 js/src/jit-test/tests/basic/test_JSOP_ARGCNT.js create mode 100644 js/src/jit-test/tests/basic/test_JSOP_ARGSUB.js create mode 100644 js/src/jit-test/tests/basic/testif.js create mode 100644 js/src/jit-test/tests/basic/testincops.js create mode 100644 js/src/jit-test/tests/basic/trees.js create mode 100644 js/src/jit-test/tests/basic/truthies.js create mode 100644 js/src/jit-test/tests/basic/typeofTest.js create mode 100644 js/src/jit-test/tests/basic/unboxint.js create mode 100644 js/src/jit-test/tests/basic/wrap-primitive-this.js create mode 100644 js/src/jit-test/tests/basic/xprop.js create mode 100644 js/src/jit-test/tests/closures/bug496922.js create mode 100644 js/src/jit-test/tests/closures/bug496987.js create mode 100644 js/src/jit-test/tests/closures/bug497015-1.js create mode 100644 js/src/jit-test/tests/closures/bug497015-2.js create mode 100644 js/src/jit-test/tests/closures/bug540131-2.js create mode 100644 js/src/jit-test/tests/closures/bug540131-3.js create mode 100644 js/src/jit-test/tests/closures/bug540131.js create mode 100644 js/src/jit-test/tests/closures/bug540133.js create mode 100644 js/src/jit-test/tests/closures/bug540136.js create mode 100644 js/src/jit-test/tests/closures/bug540242.js create mode 100644 js/src/jit-test/tests/closures/bug540243.js create mode 100644 js/src/jit-test/tests/closures/bug540348.js create mode 100644 js/src/jit-test/tests/closures/bug540528.js create mode 100644 js/src/jit-test/tests/closures/bug541239.js create mode 100644 js/src/jit-test/tests/closures/bug543565.js create mode 100644 js/src/jit-test/tests/closures/closure-pluseq.js create mode 100644 js/src/jit-test/tests/closures/closure-pluseq2.js create mode 100644 js/src/jit-test/tests/closures/closure-plusplus.js create mode 100644 js/src/jit-test/tests/closures/closure-tests.js create mode 100644 js/src/jit-test/tests/closures/flat-closure-1.js create mode 100644 js/src/jit-test/tests/closures/flat-closure-2.js create mode 100644 js/src/jit-test/tests/closures/flat-closure-3.js create mode 100644 js/src/jit-test/tests/closures/flat-closure-4.js create mode 100644 js/src/jit-test/tests/closures/flat-closure-5.js create mode 100644 js/src/jit-test/tests/closures/flat-closure-6.js create mode 100644 js/src/jit-test/tests/closures/flat-closure-7.js create mode 100644 js/src/jit-test/tests/closures/flat-closure-8.js create mode 100644 js/src/jit-test/tests/closures/incr-exit-2.js create mode 100644 js/src/jit-test/tests/closures/incr-exit-3.js create mode 100644 js/src/jit-test/tests/closures/incr-exit.js create mode 100644 js/src/jit-test/tests/closures/lambda-inner-heavy.js create mode 100644 js/src/jit-test/tests/closures/lambda-light-returned.js create mode 100644 js/src/jit-test/tests/closures/lambda-light.js create mode 100644 js/src/jit-test/tests/closures/lambda.js create mode 100644 js/src/jit-test/tests/closures/lambdafc.js create mode 100644 js/src/jit-test/tests/closures/name-both-hvy.js create mode 100644 js/src/jit-test/tests/closures/name-inactive-missing.js create mode 100644 js/src/jit-test/tests/closures/name.js create mode 100644 js/src/jit-test/tests/closures/name2.js create mode 100644 js/src/jit-test/tests/closures/name2a.js create mode 100644 js/src/jit-test/tests/closures/name2b.js create mode 100644 js/src/jit-test/tests/closures/name3.js create mode 100644 js/src/jit-test/tests/closures/name4.js create mode 100644 js/src/jit-test/tests/closures/namedLambda.js create mode 100644 js/src/jit-test/tests/closures/nameinc-loop-2.js create mode 100644 js/src/jit-test/tests/closures/nameinc-loop-3.js create mode 100644 js/src/jit-test/tests/closures/nameinc-loop-missing-2.js create mode 100644 js/src/jit-test/tests/closures/nameinc-loop-missing.js create mode 100644 js/src/jit-test/tests/closures/nameinc-loop.js create mode 100644 js/src/jit-test/tests/closures/nameinc.js create mode 100644 js/src/jit-test/tests/closures/set-outer-trace-1.js create mode 100644 js/src/jit-test/tests/closures/set-outer-trace-2.js create mode 100644 js/src/jit-test/tests/closures/set-outer-trace-3.js create mode 100644 js/src/jit-test/tests/closures/set-outer-trace-4.js create mode 100644 js/src/jit-test/tests/closures/set-outer-trace.js create mode 100644 js/src/jit-test/tests/closures/setname-1.js create mode 100644 js/src/jit-test/tests/closures/setname-closure-2.js create mode 100644 js/src/jit-test/tests/closures/setname-closure.js create mode 100644 js/src/jit-test/tests/closures/setname-inner-heavy.js create mode 100644 js/src/jit-test/tests/closures/setname-loop-2.js create mode 100644 js/src/jit-test/tests/closures/setname-loop.js create mode 100644 js/src/jit-test/tests/closures/setname-no-pop.js create mode 100644 js/src/jit-test/tests/closures/t001.js create mode 100644 js/src/jit-test/tests/closures/t002.js create mode 100644 js/src/jit-test/tests/closures/t003.js create mode 100644 js/src/jit-test/tests/closures/t004.js create mode 100644 js/src/jit-test/tests/closures/t005.js create mode 100644 js/src/jit-test/tests/closures/t006.js create mode 100644 js/src/jit-test/tests/closures/t007.js create mode 100644 js/src/jit-test/tests/closures/t008.js create mode 100644 js/src/jit-test/tests/closures/t009.js create mode 100644 js/src/jit-test/tests/closures/t010.js create mode 100644 js/src/jit-test/tests/closures/t011.js create mode 100644 js/src/jit-test/tests/closures/t012.js create mode 100644 js/src/jit-test/tests/closures/t013.js create mode 100644 js/src/jit-test/tests/closures/t014.js create mode 100644 js/src/jit-test/tests/closures/t015.js create mode 100644 js/src/jit-test/tests/closures/t016.js create mode 100644 js/src/jit-test/tests/closures/t017.js create mode 100644 js/src/jit-test/tests/closures/t018.js create mode 100644 js/src/jit-test/tests/closures/t019.js create mode 100644 js/src/jit-test/tests/closures/t020.js create mode 100644 js/src/jit-test/tests/closures/t021.js create mode 100644 js/src/jit-test/tests/closures/t022.js create mode 100644 js/src/jit-test/tests/closures/t023.js create mode 100644 js/src/jit-test/tests/closures/t024.js create mode 100644 js/src/jit-test/tests/closures/t025.js create mode 100644 js/src/jit-test/tests/closures/t026.js create mode 100644 js/src/jit-test/tests/closures/t027.js create mode 100644 js/src/jit-test/tests/closures/t028.js create mode 100644 js/src/jit-test/tests/closures/t029.js create mode 100644 js/src/jit-test/tests/closures/t030.js create mode 100644 js/src/jit-test/tests/closures/t031.js create mode 100644 js/src/jit-test/tests/closures/t032.js create mode 100644 js/src/jit-test/tests/closures/t033.js create mode 100644 js/src/jit-test/tests/closures/t034.js create mode 100644 js/src/jit-test/tests/closures/t035.js create mode 100644 js/src/jit-test/tests/closures/t036.js create mode 100644 js/src/jit-test/tests/closures/t037.js create mode 100644 js/src/jit-test/tests/closures/test-inner-imports.js create mode 100644 js/src/jit-test/tests/closures/upvar-nest.js create mode 100644 js/src/jit-test/tests/jaeger/bug549393-1.js create mode 100644 js/src/jit-test/tests/jaeger/bug549393-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug549396.js create mode 100644 js/src/jit-test/tests/jaeger/bug549398.js create mode 100644 js/src/jit-test/tests/jaeger/bug549521.js create mode 100644 js/src/jit-test/tests/jaeger/bug549602.js create mode 100644 js/src/jit-test/tests/jaeger/bug549603.js create mode 100644 js/src/jit-test/tests/jaeger/bug550490.js create mode 100644 js/src/jit-test/tests/jaeger/bug550665.js create mode 100644 js/src/jit-test/tests/jaeger/bug551603.js create mode 100644 js/src/jit-test/tests/jaeger/bug552644.js create mode 100644 js/src/jit-test/tests/jaeger/bug553781-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug553781.js create mode 100644 js/src/jit-test/tests/jaeger/bug553784.js create mode 100644 js/src/jit-test/tests/jaeger/bug554580-1.js create mode 100644 js/src/jit-test/tests/jaeger/bug554580-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug554580-3.js create mode 100644 js/src/jit-test/tests/jaeger/bug554580-4.js create mode 100644 js/src/jit-test/tests/jaeger/bug554580-5.js create mode 100644 js/src/jit-test/tests/jaeger/bug554651.js create mode 100644 js/src/jit-test/tests/jaeger/bug554675-1.js create mode 100644 js/src/jit-test/tests/jaeger/bug554675-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug554675-3.js create mode 100644 js/src/jit-test/tests/jaeger/bug555152.js create mode 100644 js/src/jit-test/tests/jaeger/bug555155.js create mode 100644 js/src/jit-test/tests/jaeger/bug555206.js create mode 100644 js/src/jit-test/tests/jaeger/bug555543.js create mode 100644 js/src/jit-test/tests/jaeger/bug555922.js create mode 100644 js/src/jit-test/tests/jaeger/bug556525.js create mode 100644 js/src/jit-test/tests/jaeger/bug557063.js create mode 100644 js/src/jit-test/tests/jaeger/bug557068.js create mode 100644 js/src/jit-test/tests/jaeger/bug557070.js create mode 100644 js/src/jit-test/tests/jaeger/bug557075.js create mode 100644 js/src/jit-test/tests/jaeger/bug560221.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/eif-call-newvar.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/eif-call-typechange.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/eif-call.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/eif-getter-newvar.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/eif-getter-typechange.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/eif-getter.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/eif-trap-newvar.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/eif-trap-typechange.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/eif-trap.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/simple-trap-1.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/simple-trap-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/simple-untrap.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/test-debugger-1.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/test-debugger-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/test-throwhook-1.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/test-throwhook-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/trap-force-return-1.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/trap-force-return-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/trap-from-add-inline.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/trap-own-callsite.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/trap-parent-from-trap.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/trap-parent.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/trap-self-as-parent.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/trap-self-from-trap.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/trap-self.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/untrap-cross-global.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/untrap-own-trapsite.js create mode 100644 js/src/jit-test/tests/jaeger/bug563000/untrap-self.js create mode 100644 js/src/jit-test/tests/jaeger/bug565198.js create mode 100644 js/src/jit-test/tests/jaeger/bug565202.js create mode 100644 js/src/jit-test/tests/jaeger/bug566022.js create mode 100644 js/src/jit-test/tests/jaeger/bug573433.js create mode 100644 js/src/jit-test/tests/jaeger/bug576398.js create mode 100644 js/src/jit-test/tests/jaeger/bug577580.js create mode 100644 js/src/jit-test/tests/jaeger/bug577646.js create mode 100644 js/src/jit-test/tests/jaeger/bug577705.js create mode 100644 js/src/jit-test/tests/jaeger/bug577996.js create mode 100644 js/src/jit-test/tests/jaeger/bug580703.js create mode 100644 js/src/jit-test/tests/jaeger/bug580712.js create mode 100644 js/src/jit-test/tests/jaeger/bug580883.js create mode 100644 js/src/jit-test/tests/jaeger/bug580884-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug580884-3.js create mode 100644 js/src/jit-test/tests/jaeger/bug580884.js create mode 100644 js/src/jit-test/tests/jaeger/bug580931-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug581871.js create mode 100644 js/src/jit-test/tests/jaeger/bug581936.js create mode 100644 js/src/jit-test/tests/jaeger/bug582185.js create mode 100644 js/src/jit-test/tests/jaeger/bug582286.js create mode 100644 js/src/jit-test/tests/jaeger/bug582392.js create mode 100644 js/src/jit-test/tests/jaeger/bug582880.js create mode 100644 js/src/jit-test/tests/jaeger/bug582882.js create mode 100644 js/src/jit-test/tests/jaeger/bug582884.js create mode 100644 js/src/jit-test/tests/jaeger/bug582894.js create mode 100644 js/src/jit-test/tests/jaeger/bug582897.js create mode 100644 js/src/jit-test/tests/jaeger/bug582898.js create mode 100644 js/src/jit-test/tests/jaeger/bug582900.js create mode 100644 js/src/jit-test/tests/jaeger/bug583158.js create mode 100644 js/src/jit-test/tests/jaeger/bug583160.js create mode 100644 js/src/jit-test/tests/jaeger/bug583672.js create mode 100644 js/src/jit-test/tests/jaeger/bug583684.js create mode 100644 js/src/jit-test/tests/jaeger/bug583688.js create mode 100644 js/src/jit-test/tests/jaeger/bug583689.js create mode 100644 js/src/jit-test/tests/jaeger/bug584644-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug584646.js create mode 100644 js/src/jit-test/tests/jaeger/bug584647.js create mode 100644 js/src/jit-test/tests/jaeger/bug585310.js create mode 100644 js/src/jit-test/tests/jaeger/bug585341.js create mode 100644 js/src/jit-test/tests/jaeger/bug585391.js create mode 100644 js/src/jit-test/tests/jaeger/bug585408-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug585408-3.js create mode 100644 js/src/jit-test/tests/jaeger/bug585408.js create mode 100644 js/src/jit-test/tests/jaeger/bug585540.js create mode 100644 js/src/jit-test/tests/jaeger/bug587431.js create mode 100644 js/src/jit-test/tests/jaeger/bug588338.js create mode 100644 js/src/jit-test/tests/jaeger/bug588362-1.js create mode 100644 js/src/jit-test/tests/jaeger/bug588362-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug588362-3.js create mode 100644 js/src/jit-test/tests/jaeger/bug588363-1.js create mode 100644 js/src/jit-test/tests/jaeger/bug588363-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug589108.js create mode 100644 js/src/jit-test/tests/jaeger/bug589115.js create mode 100644 js/src/jit-test/tests/jaeger/bug589461.js create mode 100644 js/src/jit-test/tests/jaeger/bug590083.js create mode 100644 js/src/jit-test/tests/jaeger/bug591602.js create mode 100644 js/src/jit-test/tests/jaeger/bug591606.js create mode 100644 js/src/jit-test/tests/jaeger/bug592973-1.js create mode 100644 js/src/jit-test/tests/jaeger/bug592973-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug592973-3.js create mode 100644 js/src/jit-test/tests/jaeger/bug593554.js create mode 100644 js/src/jit-test/tests/jaeger/bug595917.js create mode 100644 js/src/jit-test/tests/jaeger/bug595921.js create mode 100644 js/src/jit-test/tests/jaeger/bug597378.js create mode 100644 js/src/jit-test/tests/jaeger/bug597871.js create mode 100644 js/src/jit-test/tests/jaeger/bug598696.js create mode 100644 js/src/jit-test/tests/jaeger/bug599488.js create mode 100644 js/src/jit-test/tests/jaeger/bug600139.js create mode 100644 js/src/jit-test/tests/jaeger/bug600419.js create mode 100644 js/src/jit-test/tests/jaeger/bug600424.js create mode 100644 js/src/jit-test/tests/jaeger/bug601400.js create mode 100644 js/src/jit-test/tests/jaeger/bug601982.js create mode 100644 js/src/jit-test/tests/jaeger/bug604381.js create mode 100644 js/src/jit-test/tests/jaeger/bug604427.js create mode 100644 js/src/jit-test/tests/jaeger/bug606662-1.js create mode 100644 js/src/jit-test/tests/jaeger/bug606662-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug606829.js create mode 100644 js/src/jit-test/tests/jaeger/bug610652.js create mode 100644 js/src/jit-test/tests/jaeger/bug615440.js create mode 100644 js/src/jit-test/tests/jaeger/bug616508.js create mode 100644 js/src/jit-test/tests/jaeger/bug618007.js create mode 100644 js/src/jit-test/tests/jaeger/bug620643.js create mode 100644 js/src/jit-test/tests/jaeger/bug623474.js create mode 100644 js/src/jit-test/tests/jaeger/bug624100.js create mode 100644 js/src/jit-test/tests/jaeger/bug624483.js create mode 100644 js/src/jit-test/tests/jaeger/bug625157.js create mode 100644 js/src/jit-test/tests/jaeger/bug625377.js create mode 100644 js/src/jit-test/tests/jaeger/bug625438.js create mode 100644 js/src/jit-test/tests/jaeger/bug625718-1.js create mode 100644 js/src/jit-test/tests/jaeger/bug625718-2.js create mode 100644 js/src/jit-test/tests/jaeger/bug625718-3.js create mode 100644 js/src/jit-test/tests/jaeger/bug625757.js create mode 100644 js/src/jit-test/tests/jaeger/bug627486.js create mode 100644 js/src/jit-test/tests/jaeger/bug630366.js create mode 100644 js/src/jit-test/tests/jaeger/compare-wrong-1.js create mode 100644 js/src/jit-test/tests/jaeger/crash-on-compare.js create mode 100644 js/src/jit-test/tests/jaeger/deepBailAfterRunTracer.js create mode 100644 js/src/jit-test/tests/jaeger/floatTypedArrays.js create mode 100644 js/src/jit-test/tests/jaeger/fused-eq-ifeq.js create mode 100644 js/src/jit-test/tests/jaeger/getelem-sanity-1.js create mode 100644 js/src/jit-test/tests/jaeger/getelem-sanity-2.js create mode 100644 js/src/jit-test/tests/jaeger/getelem-sanity-3.js create mode 100644 js/src/jit-test/tests/jaeger/getelem-sanity-4.js create mode 100644 js/src/jit-test/tests/jaeger/getelem-sanity-5.js create mode 100644 js/src/jit-test/tests/jaeger/getelem-sanity-6.js create mode 100644 js/src/jit-test/tests/jaeger/getelem-sanity-7.js create mode 100644 js/src/jit-test/tests/jaeger/getelem-sanity-int-1.js create mode 100644 js/src/jit-test/tests/jaeger/getelem-sanity-int-2.js create mode 100644 js/src/jit-test/tests/jaeger/getelem-sanity-int-3.js create mode 100644 js/src/jit-test/tests/jaeger/globalOptimize-1.js create mode 100644 js/src/jit-test/tests/jaeger/instanceOfWithKnownTypes.js create mode 100644 js/src/jit-test/tests/jaeger/invokeSessionGuard.js create mode 100644 js/src/jit-test/tests/jaeger/modConstDoubles.js create mode 100644 js/src/jit-test/tests/jaeger/modConstInt.js create mode 100644 js/src/jit-test/tests/jaeger/modConstZeroRhs.js create mode 100644 js/src/jit-test/tests/jaeger/modWithConstLhs.js create mode 100644 js/src/jit-test/tests/jaeger/mulNegZero.js create mode 100644 js/src/jit-test/tests/jaeger/negation.js create mode 100644 js/src/jit-test/tests/jaeger/normalIntTypedArrays.js create mode 100644 js/src/jit-test/tests/jaeger/optimize-globals-1.js create mode 100644 js/src/jit-test/tests/jaeger/optimize-globals-2.js create mode 100644 js/src/jit-test/tests/jaeger/optimize-globals-3.js create mode 100644 js/src/jit-test/tests/jaeger/regalloc-1.js create mode 100644 js/src/jit-test/tests/jaeger/regress-bug625701.js create mode 100644 js/src/jit-test/tests/jaeger/rsh-sanity-1.js create mode 100644 js/src/jit-test/tests/jaeger/scriptedICs-1.js create mode 100644 js/src/jit-test/tests/jaeger/smallIntTypedArrays.js create mode 100644 js/src/jit-test/tests/jaeger/strictModeSetUndefinedVar.js create mode 100644 js/src/jit-test/tests/jaeger/subCommutativity.js create mode 100644 js/src/jit-test/tests/jaeger/tableSwitchConst.js create mode 100644 js/src/jit-test/tests/jaeger/tableSwitchDouble.js create mode 100644 js/src/jit-test/tests/jaeger/tableSwitchEmpty.js create mode 100644 js/src/jit-test/tests/jaeger/tableSwitchFloat.js create mode 100644 js/src/jit-test/tests/jaeger/tableSwitchNeg.js create mode 100644 js/src/jit-test/tests/jaeger/testAddStringObject.js create mode 100644 js/src/jit-test/tests/jaeger/testBug550743.js create mode 100644 js/src/jit-test/tests/jaeger/testCallElemAfterGC.js create mode 100644 js/src/jit-test/tests/jaeger/testDenseCallElem.js create mode 100644 js/src/jit-test/tests/jaeger/testForOps.js create mode 100644 js/src/jit-test/tests/jaeger/testPropCallElem.js create mode 100644 js/src/jit-test/tests/jaeger/testPropCallElem2.js create mode 100644 js/src/jit-test/tests/jaeger/testSetElem-Easy.js create mode 100644 js/src/jit-test/tests/jaeger/testSetElem-Indexed.js create mode 100644 js/src/jit-test/tests/jaeger/testSetElem-NewProto.js create mode 100644 js/src/jit-test/tests/jaeger/testSetTypedFloatArray.js create mode 100644 js/src/jit-test/tests/jaeger/testSetTypedIntArray.js create mode 100644 js/src/jit-test/tests/jaeger/testShiftSameBacking.js create mode 100644 js/src/jit-test/tests/jaeger/unsignedShiftZero.js create mode 100644 js/src/jit-test/tests/jaeger/xor-sanity.js create mode 100644 js/src/jit-test/tests/pic/bug558099.js create mode 100644 js/src/jit-test/tests/pic/bug558616.js create mode 100644 js/src/jit-test/tests/pic/bug582899.js create mode 100644 js/src/jit-test/tests/pic/bug584642.js create mode 100644 js/src/jit-test/tests/pic/bug595706.js create mode 100644 js/src/jit-test/tests/pic/call_self.js create mode 100644 js/src/jit-test/tests/pic/densearray.js create mode 100644 js/src/jit-test/tests/pic/fuzz1.js create mode 100644 js/src/jit-test/tests/pic/fuzz2.js create mode 100644 js/src/jit-test/tests/pic/fuzz3.js create mode 100644 js/src/jit-test/tests/pic/grandproto.js create mode 100644 js/src/jit-test/tests/pic/length_array.js create mode 100644 js/src/jit-test/tests/pic/length_mix.js create mode 100644 js/src/jit-test/tests/pic/length_object.js create mode 100644 js/src/jit-test/tests/pic/length_string.js create mode 100644 js/src/jit-test/tests/pic/length_string_object.js create mode 100644 js/src/jit-test/tests/pic/proto1.js create mode 100644 js/src/jit-test/tests/pic/proto3.js create mode 100644 js/src/jit-test/tests/pic/proto_self.js create mode 100644 js/src/jit-test/tests/pic/self1.js create mode 100644 js/src/jit-test/tests/pic/self2.js create mode 100644 js/src/jit-test/tests/pic/self3.js create mode 100644 js/src/jit-test/tests/pic/self8.js create mode 100644 js/src/jit-test/tests/pic/set-assign.js create mode 100644 js/src/jit-test/tests/pic/set1.js create mode 100644 js/src/jit-test/tests/pic/set2.js create mode 100644 js/src/jit-test/tests/pic/shape_regen.js create mode 100644 js/src/jit-test/tests/pic/thisprop.js create mode 100644 js/src/jit-test/tests/pic/to-dictionary.js create mode 100644 js/src/jit-test/tests/sunspider/check-3d-cube.js create mode 100644 js/src/jit-test/tests/sunspider/check-3d-morph.js create mode 100644 js/src/jit-test/tests/sunspider/check-3d-raytrace.js create mode 100644 js/src/jit-test/tests/sunspider/check-access-binary-trees.js create mode 100644 js/src/jit-test/tests/sunspider/check-access-fannkuch.js create mode 100644 js/src/jit-test/tests/sunspider/check-access-nbody.js create mode 100644 js/src/jit-test/tests/sunspider/check-access-nsieve.js create mode 100644 js/src/jit-test/tests/sunspider/check-bitops-3bit-bits-in-byte.js create mode 100644 js/src/jit-test/tests/sunspider/check-bitops-bits-in-byte.js create mode 100644 js/src/jit-test/tests/sunspider/check-bitops-bitwise-and.js create mode 100644 js/src/jit-test/tests/sunspider/check-bitops-nsieve-bits.js create mode 100644 js/src/jit-test/tests/sunspider/check-controlflow-recursive.js create mode 100644 js/src/jit-test/tests/sunspider/check-crypto-aes.js create mode 100644 js/src/jit-test/tests/sunspider/check-crypto-md5.js create mode 100644 js/src/jit-test/tests/sunspider/check-crypto-sha1.js create mode 100644 js/src/jit-test/tests/sunspider/check-date-format-tofte.js create mode 100644 js/src/jit-test/tests/sunspider/check-date-format-xparb.js create mode 100644 js/src/jit-test/tests/sunspider/check-math-cordic.js create mode 100644 js/src/jit-test/tests/sunspider/check-math-partial-sums.js create mode 100644 js/src/jit-test/tests/sunspider/check-math-spectral-norm.js create mode 100644 js/src/jit-test/tests/sunspider/check-mont.js create mode 100644 js/src/jit-test/tests/sunspider/check-regexp-dna.js create mode 100644 js/src/jit-test/tests/sunspider/check-string-fasta.js create mode 100644 js/src/jit-test/tests/sunspider/check-string-tagcloud.js create mode 100644 js/src/jit-test/tests/sunspider/check-string-unpack-code.js create mode 100644 js/src/jit-test/tests/testCrossGlobalInvokeSession.js create mode 100644 js/src/jit-test/tests/v8-v5/check-crypto.js create mode 100644 js/src/jit-test/tests/v8-v5/check-deltablue.js create mode 100644 js/src/jit-test/tests/v8-v5/check-earley-boyer.js create mode 100644 js/src/jit-test/tests/v8-v5/check-raytrace.js create mode 100644 js/src/jit-test/tests/v8-v5/check-regexp.js create mode 100644 js/src/jit-test/tests/v8-v5/check-richards.js create mode 100644 js/src/jit-test/tests/v8-v5/check-splay.js create mode 100644 js/src/jitstats.tbl create mode 100644 js/src/js-config.h.in create mode 100644 js/src/js-config.in create mode 100644 js/src/js.mdp create mode 100644 js/src/js.msg create mode 100644 js/src/jsanalyze.cpp create mode 100644 js/src/jsanalyze.h create mode 100644 js/src/jsapi-tests/Makefile.in create mode 100644 js/src/jsapi-tests/README create mode 100644 js/src/jsapi-tests/selfTest.cpp create mode 100644 js/src/jsapi-tests/testBug604087.cpp create mode 100644 js/src/jsapi-tests/testClassGetter.cpp create mode 100644 js/src/jsapi-tests/testCloneScript.cpp create mode 100644 js/src/jsapi-tests/testConservativeGC.cpp create mode 100644 js/src/jsapi-tests/testContexts.cpp create mode 100644 js/src/jsapi-tests/testCustomIterator.cpp create mode 100644 js/src/jsapi-tests/testDebugger.cpp create mode 100644 js/src/jsapi-tests/testDeepFreeze.cpp create mode 100644 js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp create mode 100644 js/src/jsapi-tests/testDefineProperty.cpp create mode 100644 js/src/jsapi-tests/testExtendedEq.cpp create mode 100644 js/src/jsapi-tests/testFuncCallback.cpp create mode 100644 js/src/jsapi-tests/testGCChunkAlloc.cpp create mode 100644 js/src/jsapi-tests/testGetPropertyDefault.cpp create mode 100644 js/src/jsapi-tests/testIntString.cpp create mode 100644 js/src/jsapi-tests/testIsAboutToBeFinalized.cpp create mode 100644 js/src/jsapi-tests/testLookup.cpp create mode 100644 js/src/jsapi-tests/testNewObject.cpp create mode 100644 js/src/jsapi-tests/testOps.cpp create mode 100644 js/src/jsapi-tests/testPropCache.cpp create mode 100644 js/src/jsapi-tests/testSameValue.cpp create mode 100644 js/src/jsapi-tests/testScriptObject.cpp create mode 100644 js/src/jsapi-tests/testSetProperty.cpp create mode 100644 js/src/jsapi-tests/testThreadGC.cpp create mode 100644 js/src/jsapi-tests/testThreads.cpp create mode 100644 js/src/jsapi-tests/testTrap.cpp create mode 100644 js/src/jsapi-tests/testUTF8.cpp create mode 100644 js/src/jsapi-tests/testVersion.cpp create mode 100644 js/src/jsapi-tests/testXDR.cpp create mode 100644 js/src/jsapi-tests/tests.cpp create mode 100644 js/src/jsapi-tests/tests.h create mode 100644 js/src/jsapi.cpp create mode 100644 js/src/jsapi.h create mode 100644 js/src/jsarena.cpp create mode 100644 js/src/jsarena.h create mode 100644 js/src/jsarray.cpp create mode 100644 js/src/jsarray.h create mode 100644 js/src/jsast.tbl create mode 100644 js/src/jsatom.cpp create mode 100644 js/src/jsatom.h create mode 100644 js/src/jsatominlines.h create mode 100644 js/src/jsbit.h create mode 100644 js/src/jsbool.cpp create mode 100644 js/src/jsbool.h create mode 100644 js/src/jsbuiltins.cpp create mode 100644 js/src/jsbuiltins.h create mode 100644 js/src/jscell.h create mode 100644 js/src/jsclist.h create mode 100644 js/src/jsclone.cpp create mode 100644 js/src/jsclone.h create mode 100644 js/src/jscntxt.cpp create mode 100644 js/src/jscntxt.h create mode 100644 js/src/jscntxtinlines.h create mode 100644 js/src/jscompartment.cpp create mode 100644 js/src/jscompartment.h create mode 100644 js/src/jscompat.h create mode 100644 js/src/jsconfig.mk create mode 100644 js/src/jscpucfg.cpp create mode 100644 js/src/jscpucfg.h create mode 100644 js/src/jsdate.cpp create mode 100644 js/src/jsdate.h create mode 100644 js/src/jsdbgapi.cpp create mode 100644 js/src/jsdbgapi.h create mode 100644 js/src/jsdbgapiinlines.h create mode 100644 js/src/jsdhash.cpp create mode 100644 js/src/jsdhash.h create mode 100644 js/src/jsdtoa.cpp create mode 100644 js/src/jsdtoa.h create mode 100644 js/src/jsemit.cpp create mode 100644 js/src/jsemit.h create mode 100644 js/src/jsexn.cpp create mode 100644 js/src/jsexn.h create mode 100644 js/src/jsfriendapi.cpp create mode 100644 js/src/jsfriendapi.h create mode 100644 js/src/jsfun.cpp create mode 100644 js/src/jsfun.h create mode 100644 js/src/jsfuninlines.h create mode 100644 js/src/jsgc.cpp create mode 100644 js/src/jsgc.h create mode 100644 js/src/jsgcchunk.cpp create mode 100644 js/src/jsgcchunk.h create mode 100644 js/src/jsgcinlines.h create mode 100644 js/src/jsgcstats.cpp create mode 100644 js/src/jsgcstats.h create mode 100644 js/src/jshash.cpp create mode 100644 js/src/jshash.h create mode 100644 js/src/jshashtable.h create mode 100644 js/src/jshotloop.h create mode 100644 js/src/jsify.pl create mode 100644 js/src/jsinterp.cpp create mode 100644 js/src/jsinterp.h create mode 100644 js/src/jsinterpinlines.h create mode 100644 js/src/jsinttypes.h create mode 100644 js/src/jsinvoke.cpp create mode 100644 js/src/jsiter.cpp create mode 100644 js/src/jsiter.h create mode 100644 js/src/jskeyword.tbl create mode 100644 js/src/jskwgen.cpp create mode 100644 js/src/jslibmath.h create mode 100644 js/src/jslock.cpp create mode 100644 js/src/jslock.h create mode 100644 js/src/jslocko.asm create mode 100644 js/src/jslog2.cpp create mode 100644 js/src/jslong.h create mode 100644 js/src/jsmath.cpp create mode 100644 js/src/jsmath.h create mode 100644 js/src/jsnativestack.cpp create mode 100644 js/src/jsnativestack.h create mode 100644 js/src/jsnum.cpp create mode 100644 js/src/jsnum.h create mode 100644 js/src/jsobj.cpp create mode 100644 js/src/jsobj.h create mode 100644 js/src/jsobjinlines.h create mode 100644 js/src/json.cpp create mode 100644 js/src/json.h create mode 100644 js/src/jsopcode.cpp create mode 100644 js/src/jsopcode.h create mode 100644 js/src/jsopcode.tbl create mode 100644 js/src/jsopcodeinlines.h create mode 100644 js/src/jsoplengen.cpp create mode 100644 js/src/jsotypes.h create mode 100644 js/src/jsparse.cpp create mode 100644 js/src/jsparse.h create mode 100644 js/src/jsprf.cpp create mode 100644 js/src/jsprf.h create mode 100644 js/src/jsprobes.cpp create mode 100644 js/src/jsprobes.h create mode 100644 js/src/jspropertycache.cpp create mode 100644 js/src/jspropertycache.h create mode 100644 js/src/jspropertycacheinlines.h create mode 100644 js/src/jspropertytree.cpp create mode 100644 js/src/jspropertytree.h create mode 100644 js/src/jsproto.tbl create mode 100644 js/src/jsproxy.cpp create mode 100644 js/src/jsproxy.h create mode 100644 js/src/jsprvtd.h create mode 100644 js/src/jspubtd.h create mode 100644 js/src/jsreflect.cpp create mode 100644 js/src/jsreflect.h create mode 100644 js/src/jsregexp.cpp create mode 100644 js/src/jsregexp.h create mode 100644 js/src/jsregexpinlines.h create mode 100644 js/src/jsreops.tbl create mode 100644 js/src/jsscan.cpp create mode 100644 js/src/jsscan.h create mode 100644 js/src/jsscope.cpp create mode 100644 js/src/jsscope.h create mode 100644 js/src/jsscopeinlines.h create mode 100644 js/src/jsscript.cpp create mode 100644 js/src/jsscript.h create mode 100644 js/src/jsscriptinlines.h create mode 100644 js/src/jsshell.msg create mode 100644 js/src/jsstack.js create mode 100644 js/src/jsstaticcheck.h create mode 100644 js/src/jsstdint.h create mode 100644 js/src/jsstr.cpp create mode 100644 js/src/jsstr.h create mode 100644 js/src/jsstrinlines.h create mode 100644 js/src/jstl.h create mode 100644 js/src/jstracer.cpp create mode 100644 js/src/jstracer.h create mode 100644 js/src/jstypedarray.cpp create mode 100644 js/src/jstypedarray.h create mode 100644 js/src/jstypes.h create mode 100644 js/src/jsutil.cpp create mode 100644 js/src/jsutil.h create mode 100644 js/src/jsval.h create mode 100644 js/src/jsvalue.h create mode 100644 js/src/jsvector.h create mode 100644 js/src/jsversion.h create mode 100644 js/src/jswin.h create mode 100644 js/src/jswince.asm create mode 100644 js/src/jswrapper.cpp create mode 100644 js/src/jswrapper.h create mode 100644 js/src/jsxdrapi.cpp create mode 100644 js/src/jsxdrapi.h create mode 100644 js/src/jsxml.cpp create mode 100644 js/src/jsxml.h create mode 100644 js/src/lirasm/LInsClasses.tbl create mode 100644 js/src/lirasm/Makefile.in create mode 100644 js/src/lirasm/lirasm.cpp create mode 100755 js/src/lirasm/testlirc.sh create mode 100644 js/src/lirasm/tests/32-bit/many_params.in create mode 100644 js/src/lirasm/tests/32-bit/many_params.out create mode 100644 js/src/lirasm/tests/64-bit/dasq.in create mode 100644 js/src/lirasm/tests/64-bit/dasq.out create mode 100644 js/src/lirasm/tests/64-bit/qasd.in create mode 100644 js/src/lirasm/tests/64-bit/qasd.out create mode 100644 js/src/lirasm/tests/64-bit/shq.in create mode 100644 js/src/lirasm/tests/64-bit/shq.out create mode 100644 js/src/lirasm/tests/add.in create mode 100644 js/src/lirasm/tests/add.out create mode 100644 js/src/lirasm/tests/addd.in create mode 100644 js/src/lirasm/tests/addd.out create mode 100644 js/src/lirasm/tests/addjovi.in create mode 100644 js/src/lirasm/tests/addjovi.out create mode 100644 js/src/lirasm/tests/addjovi_ovf.in create mode 100644 js/src/lirasm/tests/addjovi_ovf.out create mode 100644 js/src/lirasm/tests/addsub.in create mode 100644 js/src/lirasm/tests/addsub.out create mode 100644 js/src/lirasm/tests/bigendian/fuzz-527178.in create mode 100644 js/src/lirasm/tests/bigendian/fuzz-527178.out create mode 100644 js/src/lirasm/tests/bigendian/ldc2i.in create mode 100644 js/src/lirasm/tests/bigendian/ldc2i.out create mode 100644 js/src/lirasm/tests/bigendian/lds2i.in create mode 100644 js/src/lirasm/tests/bigendian/lds2i.out create mode 100644 js/src/lirasm/tests/bigendian/lduc2ui.in create mode 100644 js/src/lirasm/tests/bigendian/lduc2ui.out create mode 100644 js/src/lirasm/tests/bigendian/ldus2ui.in create mode 100644 js/src/lirasm/tests/bigendian/ldus2ui.out create mode 100644 js/src/lirasm/tests/bug596923.in create mode 100644 js/src/lirasm/tests/bug596923.out create mode 100644 js/src/lirasm/tests/call1.in create mode 100644 js/src/lirasm/tests/call1.out create mode 100644 js/src/lirasm/tests/call2.in create mode 100644 js/src/lirasm/tests/call2.out create mode 100644 js/src/lirasm/tests/calld1.in create mode 100644 js/src/lirasm/tests/calld1.out create mode 100644 js/src/lirasm/tests/callid1.in create mode 100644 js/src/lirasm/tests/callid1.out create mode 100644 js/src/lirasm/tests/callid2.in create mode 100644 js/src/lirasm/tests/callid2.out create mode 100644 js/src/lirasm/tests/callid3.in create mode 100644 js/src/lirasm/tests/callid3.out create mode 100644 js/src/lirasm/tests/callv.in create mode 100644 js/src/lirasm/tests/callv.out create mode 100644 js/src/lirasm/tests/cmov.in create mode 100644 js/src/lirasm/tests/cmov.out create mode 100644 js/src/lirasm/tests/cond_eqd.in create mode 100644 js/src/lirasm/tests/cond_eqd.out create mode 100644 js/src/lirasm/tests/cond_eqi.in create mode 100644 js/src/lirasm/tests/cond_eqi.out create mode 100644 js/src/lirasm/tests/cond_ged.in create mode 100644 js/src/lirasm/tests/cond_ged.out create mode 100644 js/src/lirasm/tests/cond_gei.in create mode 100644 js/src/lirasm/tests/cond_gei.out create mode 100644 js/src/lirasm/tests/cond_geui.in create mode 100644 js/src/lirasm/tests/cond_geui.out create mode 100644 js/src/lirasm/tests/cond_gtd.in create mode 100644 js/src/lirasm/tests/cond_gtd.out create mode 100644 js/src/lirasm/tests/cond_gti.in create mode 100644 js/src/lirasm/tests/cond_gti.out create mode 100644 js/src/lirasm/tests/cond_gtui.in create mode 100644 js/src/lirasm/tests/cond_gtui.out create mode 100644 js/src/lirasm/tests/cond_led.in create mode 100644 js/src/lirasm/tests/cond_led.out create mode 100644 js/src/lirasm/tests/cond_lei.in create mode 100644 js/src/lirasm/tests/cond_lei.out create mode 100644 js/src/lirasm/tests/cond_leui.in create mode 100644 js/src/lirasm/tests/cond_leui.out create mode 100644 js/src/lirasm/tests/cond_ltd.in create mode 100644 js/src/lirasm/tests/cond_ltd.out create mode 100644 js/src/lirasm/tests/cond_lti.in create mode 100644 js/src/lirasm/tests/cond_lti.out create mode 100644 js/src/lirasm/tests/cond_ltui.in create mode 100644 js/src/lirasm/tests/cond_ltui.out create mode 100644 js/src/lirasm/tests/divd.in create mode 100644 js/src/lirasm/tests/divd.out create mode 100644 js/src/lirasm/tests/float_double.in create mode 100644 js/src/lirasm/tests/float_double.out create mode 100644 js/src/lirasm/tests/floatingpoint.in create mode 100644 js/src/lirasm/tests/floatingpoint.out create mode 100644 js/src/lirasm/tests/fneg.in create mode 100644 js/src/lirasm/tests/fneg.out create mode 100644 js/src/lirasm/tests/fpu1-598151.in create mode 100644 js/src/lirasm/tests/fpu1-598151.out create mode 100644 js/src/lirasm/tests/fpu2-598151.in create mode 100644 js/src/lirasm/tests/fpu2-598151.out create mode 100644 js/src/lirasm/tests/fuzz-527178.in create mode 100644 js/src/lirasm/tests/fuzz-527178.out create mode 100644 js/src/lirasm/tests/hardfloat/d2i.in create mode 100644 js/src/lirasm/tests/hardfloat/d2i.out create mode 100644 js/src/lirasm/tests/hardfloat/f2i.in create mode 100644 js/src/lirasm/tests/hardfloat/f2i.out create mode 100644 js/src/lirasm/tests/hardfloat/i2d.in create mode 100644 js/src/lirasm/tests/hardfloat/i2d.out create mode 100644 js/src/lirasm/tests/hardfloat/ui2d.in create mode 100644 js/src/lirasm/tests/hardfloat/ui2d.out create mode 100644 js/src/lirasm/tests/ldc2i.in create mode 100644 js/src/lirasm/tests/ldc2i.out create mode 100644 js/src/lirasm/tests/lds2i.in create mode 100644 js/src/lirasm/tests/lds2i.out create mode 100644 js/src/lirasm/tests/lduc2ui.in create mode 100644 js/src/lirasm/tests/lduc2ui.out create mode 100644 js/src/lirasm/tests/ldus2ui.in create mode 100644 js/src/lirasm/tests/ldus2ui.out create mode 100644 js/src/lirasm/tests/littleendian/fuzz-527178.in create mode 100644 js/src/lirasm/tests/littleendian/fuzz-527178.out create mode 100644 js/src/lirasm/tests/littleendian/ldc2i.in create mode 100644 js/src/lirasm/tests/littleendian/ldc2i.out create mode 100644 js/src/lirasm/tests/littleendian/lds2i.in create mode 100644 js/src/lirasm/tests/littleendian/lds2i.out create mode 100644 js/src/lirasm/tests/littleendian/lduc2ui.in create mode 100644 js/src/lirasm/tests/littleendian/lduc2ui.out create mode 100644 js/src/lirasm/tests/littleendian/ldus2ui.in create mode 100644 js/src/lirasm/tests/littleendian/ldus2ui.out create mode 100644 js/src/lirasm/tests/loadstore.in create mode 100644 js/src/lirasm/tests/loadstore.out create mode 100644 js/src/lirasm/tests/mul_xxx.in create mode 100644 js/src/lirasm/tests/mul_xxx.out create mode 100644 js/src/lirasm/tests/mul_xxy.in create mode 100644 js/src/lirasm/tests/mul_xxy.out create mode 100644 js/src/lirasm/tests/mul_xyy.in create mode 100644 js/src/lirasm/tests/mul_xyy.out create mode 100644 js/src/lirasm/tests/mul_xyz.in create mode 100644 js/src/lirasm/tests/mul_xyz.out create mode 100644 js/src/lirasm/tests/muld.in create mode 100644 js/src/lirasm/tests/muld.out create mode 100644 js/src/lirasm/tests/muljovi.in create mode 100644 js/src/lirasm/tests/muljovi.out create mode 100644 js/src/lirasm/tests/muljovi_ovf.in create mode 100644 js/src/lirasm/tests/muljovi_ovf.out create mode 100644 js/src/lirasm/tests/muljovi_xxx.in create mode 100644 js/src/lirasm/tests/muljovi_xxx.out create mode 100644 js/src/lirasm/tests/muljovi_xxy.in create mode 100644 js/src/lirasm/tests/muljovi_xxy.out create mode 100644 js/src/lirasm/tests/muljovi_xyy.in create mode 100644 js/src/lirasm/tests/muljovi_xyy.out create mode 100644 js/src/lirasm/tests/muljovi_xyz.in create mode 100644 js/src/lirasm/tests/muljovi_xyz.out create mode 100644 js/src/lirasm/tests/mulov_xxx.in create mode 100644 js/src/lirasm/tests/mulov_xxx.out create mode 100644 js/src/lirasm/tests/mulov_xxy.in create mode 100644 js/src/lirasm/tests/mulov_xxy.out create mode 100644 js/src/lirasm/tests/mulov_xyy.in create mode 100644 js/src/lirasm/tests/mulov_xyy.out create mode 100644 js/src/lirasm/tests/mulov_xyz.in create mode 100644 js/src/lirasm/tests/mulov_xyz.out create mode 100644 js/src/lirasm/tests/multfrag1.in create mode 100644 js/src/lirasm/tests/multfrag1.out create mode 100644 js/src/lirasm/tests/multfrag2.in create mode 100644 js/src/lirasm/tests/multfrag2.out create mode 100644 js/src/lirasm/tests/multfrag3.in create mode 100644 js/src/lirasm/tests/multfrag3.out create mode 100644 js/src/lirasm/tests/negnot.in create mode 100644 js/src/lirasm/tests/negnot.out create mode 100644 js/src/lirasm/tests/random.out create mode 100644 js/src/lirasm/tests/shi.in create mode 100644 js/src/lirasm/tests/shi.out create mode 100644 js/src/lirasm/tests/softfloat/dhi2i.in create mode 100644 js/src/lirasm/tests/softfloat/dhi2i.out create mode 100644 js/src/lirasm/tests/softfloat/dlo2i.in create mode 100644 js/src/lirasm/tests/softfloat/dlo2i.out create mode 100644 js/src/lirasm/tests/softfloat/ii2d.in create mode 100644 js/src/lirasm/tests/softfloat/ii2d.out create mode 100644 js/src/lirasm/tests/std2f.in create mode 100644 js/src/lirasm/tests/std2f.out create mode 100644 js/src/lirasm/tests/subd.in create mode 100644 js/src/lirasm/tests/subd.out create mode 100644 js/src/lirasm/tests/subjovi.in create mode 100644 js/src/lirasm/tests/subjovi.out create mode 100644 js/src/lirasm/tests/subjovi_ovf.in create mode 100644 js/src/lirasm/tests/subjovi_ovf.out create mode 100644 js/src/lock_sparcv8plus.il create mode 100644 js/src/lock_sparcv9.il create mode 100644 js/src/methodjit/BaseAssembler.h create mode 100644 js/src/methodjit/BaseCompiler.h create mode 100644 js/src/methodjit/CodeGenIncludes.h create mode 100644 js/src/methodjit/Compiler.cpp create mode 100644 js/src/methodjit/Compiler.h create mode 100644 js/src/methodjit/FastArithmetic.cpp create mode 100644 js/src/methodjit/FastOps.cpp create mode 100644 js/src/methodjit/FrameEntry.h create mode 100644 js/src/methodjit/FrameState-inl.h create mode 100644 js/src/methodjit/FrameState.cpp create mode 100644 js/src/methodjit/FrameState.h create mode 100644 js/src/methodjit/ICChecker.h create mode 100644 js/src/methodjit/ICLabels.h create mode 100644 js/src/methodjit/ICRepatcher.h create mode 100644 js/src/methodjit/ImmutableSync.cpp create mode 100644 js/src/methodjit/ImmutableSync.h create mode 100644 js/src/methodjit/InlineFrameAssembler.h create mode 100644 js/src/methodjit/InvokeHelpers.cpp create mode 100644 js/src/methodjit/Logging.cpp create mode 100644 js/src/methodjit/Logging.h create mode 100644 js/src/methodjit/MachineRegs.h create mode 100644 js/src/methodjit/MethodJIT-inl.h create mode 100644 js/src/methodjit/MethodJIT.cpp create mode 100644 js/src/methodjit/MethodJIT.h create mode 100644 js/src/methodjit/MonoIC.cpp create mode 100644 js/src/methodjit/MonoIC.h create mode 100644 js/src/methodjit/NunboxAssembler.h create mode 100644 js/src/methodjit/PolyIC.cpp create mode 100644 js/src/methodjit/PolyIC.h create mode 100644 js/src/methodjit/PunboxAssembler.h create mode 100644 js/src/methodjit/RematInfo.h create mode 100644 js/src/methodjit/Retcon.cpp create mode 100644 js/src/methodjit/Retcon.h create mode 100644 js/src/methodjit/StubCalls-inl.h create mode 100644 js/src/methodjit/StubCalls.cpp create mode 100644 js/src/methodjit/StubCalls.h create mode 100644 js/src/methodjit/StubCompiler.cpp create mode 100644 js/src/methodjit/StubCompiler.h create mode 100644 js/src/methodjit/TrampolineCompiler.cpp create mode 100644 js/src/methodjit/TrampolineCompiler.h create mode 100644 js/src/methodjit/TrampolineMasmX64.asm create mode 100644 js/src/methodjit/TrampolineSUNWX64.s create mode 100644 js/src/methodjit/TrampolineSUNWX86.s create mode 100644 js/src/methodjit/TypedArrayIC.h create mode 100644 js/src/metrics/gc/README.txt create mode 100644 js/src/metrics/gc/gc-test.py create mode 100644 js/src/metrics/gc/tests/clock.js create mode 100644 js/src/metrics/gc/tests/dslots.js create mode 100644 js/src/metrics/gc/tests/loops.js create mode 100644 js/src/metrics/gc/tests/objGraph.js create mode 100644 js/src/metrics/jint/sunspider/3d-cube.js create mode 100644 js/src/metrics/jint/sunspider/3d-morph.js create mode 100644 js/src/metrics/jint/sunspider/3d-raytrace.js create mode 100644 js/src/metrics/jint/sunspider/access-binary-trees.js create mode 100644 js/src/metrics/jint/sunspider/access-fannkuch.js create mode 100644 js/src/metrics/jint/sunspider/access-nbody.js create mode 100644 js/src/metrics/jint/sunspider/access-nsieve.js create mode 100644 js/src/metrics/jint/sunspider/bitops-3bit-bits-in-byte.js create mode 100644 js/src/metrics/jint/sunspider/bitops-bits-in-byte.js create mode 100644 js/src/metrics/jint/sunspider/bitops-bitwise-and.js create mode 100644 js/src/metrics/jint/sunspider/bitops-nsieve-bits.js create mode 100644 js/src/metrics/jint/sunspider/controlflow-recursive.js create mode 100644 js/src/metrics/jint/sunspider/crypto-aes.js create mode 100644 js/src/metrics/jint/sunspider/crypto-md5.js create mode 100644 js/src/metrics/jint/sunspider/crypto-sha1.js create mode 100644 js/src/metrics/jint/sunspider/date-format-tofte.js create mode 100644 js/src/metrics/jint/sunspider/date-format-xparb.js create mode 100644 js/src/metrics/jint/sunspider/math-cordic.js create mode 100644 js/src/metrics/jint/sunspider/math-partial-sums.js create mode 100644 js/src/metrics/jint/sunspider/math-spectral-norm.js create mode 100644 js/src/metrics/jint/sunspider/regexp-dna.js create mode 100644 js/src/metrics/jint/sunspider/string-base64.js create mode 100644 js/src/metrics/jint/sunspider/string-fasta.js create mode 100644 js/src/metrics/jint/sunspider/string-tagcloud.js create mode 100644 js/src/metrics/jint/sunspider/string-unpack-code.js create mode 100644 js/src/metrics/jint/sunspider/string-validate-input.js create mode 100644 js/src/metrics/jint/treesearch.py create mode 100644 js/src/metrics/jint/v8/base.js create mode 100644 js/src/metrics/jint/v8/crypto.js create mode 100644 js/src/metrics/jint/v8/deltablue.js create mode 100644 js/src/metrics/jint/v8/earley-boyer.js create mode 100644 js/src/metrics/jint/v8/raytrace.js create mode 100644 js/src/metrics/jint/v8/richards.js create mode 100644 js/src/metrics/jint/v8/run-earley-boyer.js create mode 100644 js/src/metrics/jint/v8/run-raytrace.js create mode 100644 js/src/metrics/jint/v8/run-richards.js create mode 100644 js/src/metrics/jint/v8/run.js create mode 100644 js/src/mozjs185.pc.in create mode 100644 js/src/nanojit-import-filemap create mode 100644 js/src/nanojit-import-rev create mode 100644 js/src/nanojit/Allocator.cpp create mode 100644 js/src/nanojit/Allocator.h create mode 100755 js/src/nanojit/Assembler.cpp create mode 100644 js/src/nanojit/Assembler.h create mode 100644 js/src/nanojit/CodeAlloc.cpp create mode 100644 js/src/nanojit/CodeAlloc.h create mode 100644 js/src/nanojit/Containers.cpp create mode 100644 js/src/nanojit/Containers.h create mode 100644 js/src/nanojit/Fragmento.cpp create mode 100644 js/src/nanojit/Fragmento.h create mode 100644 js/src/nanojit/LIR.cpp create mode 100644 js/src/nanojit/LIR.h create mode 100644 js/src/nanojit/LIRopcode.tbl create mode 100644 js/src/nanojit/Native.h create mode 100644 js/src/nanojit/NativeARM.cpp create mode 100644 js/src/nanojit/NativeARM.h create mode 100644 js/src/nanojit/NativeCommon.h create mode 100644 js/src/nanojit/NativeMIPS.cpp create mode 100644 js/src/nanojit/NativeMIPS.h create mode 100644 js/src/nanojit/NativePPC.cpp create mode 100644 js/src/nanojit/NativePPC.h create mode 100644 js/src/nanojit/NativeSH4-auto-generated.h create mode 100644 js/src/nanojit/NativeSH4.cpp create mode 100644 js/src/nanojit/NativeSH4.h create mode 100644 js/src/nanojit/NativeSparc.cpp create mode 100644 js/src/nanojit/NativeSparc.h create mode 100644 js/src/nanojit/NativeX64.cpp create mode 100644 js/src/nanojit/NativeX64.h create mode 100644 js/src/nanojit/Nativei386.cpp create mode 100644 js/src/nanojit/Nativei386.h create mode 100644 js/src/nanojit/RegAlloc.cpp create mode 100644 js/src/nanojit/RegAlloc.h create mode 100644 js/src/nanojit/VMPI.cpp create mode 100644 js/src/nanojit/VMPI.h create mode 100644 js/src/nanojit/avmplus.cpp create mode 100644 js/src/nanojit/avmplus.h create mode 100644 js/src/nanojit/manifest.mk create mode 100644 js/src/nanojit/nanojit.h create mode 100644 js/src/nanojit/njconfig.cpp create mode 100644 js/src/nanojit/njconfig.h create mode 100644 js/src/nanojit/njcpudetect.h create mode 100644 js/src/perf/jsperf.cpp create mode 100644 js/src/perf/jsperf.h create mode 100644 js/src/perf/pm_linux.cpp create mode 100644 js/src/perf/pm_stub.cpp create mode 100644 js/src/perfect.js create mode 100644 js/src/plify_jsdhash.sed create mode 100644 js/src/prmjtime.cpp create mode 100644 js/src/prmjtime.h create mode 100644 js/src/ref-config/AIX4.1.mk create mode 100644 js/src/ref-config/AIX4.2.mk create mode 100644 js/src/ref-config/AIX4.3.mk create mode 100644 js/src/ref-config/Darwin.mk create mode 100644 js/src/ref-config/Darwin1.3.mk create mode 100644 js/src/ref-config/Darwin1.4.mk create mode 100644 js/src/ref-config/Darwin5.2.mk create mode 100644 js/src/ref-config/Darwin5.3.mk create mode 100644 js/src/ref-config/Darwin64.mk create mode 100644 js/src/ref-config/HP-UXB.10.10.mk create mode 100644 js/src/ref-config/HP-UXB.10.20.mk create mode 100644 js/src/ref-config/HP-UXB.11.00.mk create mode 100644 js/src/ref-config/HP-UXB.11.31.mk create mode 100644 js/src/ref-config/IRIX.mk create mode 100644 js/src/ref-config/IRIX5.3.mk create mode 100644 js/src/ref-config/IRIX6.1.mk create mode 100644 js/src/ref-config/IRIX6.2.mk create mode 100644 js/src/ref-config/IRIX6.3.mk create mode 100644 js/src/ref-config/IRIX6.5.mk create mode 100644 js/src/ref-config/Linux_All.mk create mode 100644 js/src/ref-config/Mac_OS10.0.mk create mode 100644 js/src/ref-config/OSF1V4.0.mk create mode 100644 js/src/ref-config/OSF1V5.0.mk create mode 100644 js/src/ref-config/SunOS4.1.4.mk create mode 100644 js/src/ref-config/SunOS5.10.mk create mode 100644 js/src/ref-config/SunOS5.3.mk create mode 100644 js/src/ref-config/SunOS5.4.mk create mode 100644 js/src/ref-config/SunOS5.5.1.mk create mode 100644 js/src/ref-config/SunOS5.5.mk create mode 100644 js/src/ref-config/SunOS5.6.mk create mode 100644 js/src/ref-config/SunOS5.7.mk create mode 100644 js/src/ref-config/SunOS5.8.mk create mode 100644 js/src/ref-config/SunOS5.9.mk create mode 100644 js/src/ref-config/WINNT4.0.mk create mode 100644 js/src/ref-config/WINNT5.0.mk create mode 100644 js/src/ref-config/WINNT5.1.mk create mode 100644 js/src/ref-config/WINNT5.2.mk create mode 100644 js/src/ref-config/WINNT6.0.mk create mode 100644 js/src/ref-config/dgux.mk create mode 100644 js/src/resource.h create mode 100644 js/src/rules.mk create mode 100644 js/src/sharkctl.cpp create mode 100644 js/src/sharkctl.h create mode 100644 js/src/shell/Makefile.in create mode 100644 js/src/shell/js.cpp create mode 100644 js/src/shell/jsworkers.cpp create mode 100644 js/src/shell/jsworkers.h create mode 100644 js/src/t/3d-cube.js create mode 100644 js/src/t/3d-morph.js create mode 100644 js/src/t/3d-raytrace.js create mode 100644 js/src/t/access-binary-trees.js create mode 100644 js/src/t/access-fannkuch.js create mode 100644 js/src/t/access-nbody.js create mode 100644 js/src/t/access-nsieve.js create mode 100644 js/src/t/bitops-3bit-bits-in-byte.js create mode 100644 js/src/t/bitops-bits-in-byte.js create mode 100644 js/src/t/bitops-bitwise-and.js create mode 100644 js/src/t/bitops-nsieve-bits.js create mode 100644 js/src/t/controlflow-recursive.js create mode 100644 js/src/t/crypto-aes.js create mode 100644 js/src/t/crypto-md5.js create mode 100644 js/src/t/crypto-sha1.js create mode 100644 js/src/t/date-format-tofte.js create mode 100644 js/src/t/date-format-xparb.js create mode 100644 js/src/t/math-cordic.js create mode 100644 js/src/t/math-partial-sums.js create mode 100644 js/src/t/math-spectral-norm.js create mode 100644 js/src/t/regexp-dna.js create mode 100644 js/src/t/string-base64.js create mode 100644 js/src/t/string-fasta.js create mode 100644 js/src/t/string-tagcloud.js create mode 100644 js/src/t/string-unpack-code.js create mode 100644 js/src/t/string-validate-input.js create mode 100644 js/src/tests/Makefile.in create mode 100644 js/src/tests/Patterns.pm create mode 100644 js/src/tests/SisyphusMakefile create mode 100755 js/src/tests/bisect.sh create mode 100644 js/src/tests/browser.js create mode 100755 js/src/tests/changes.sh create mode 100644 js/src/tests/compare_bench.py create mode 100644 js/src/tests/config.mk create mode 100755 js/src/tests/config.sh create mode 100755 js/src/tests/detect-universe.sh create mode 100644 js/src/tests/dikdik-n.tests create mode 100644 js/src/tests/e4x/Expressions/11.1.1.js create mode 100644 js/src/tests/e4x/Expressions/11.1.2.js create mode 100644 js/src/tests/e4x/Expressions/11.1.3.js create mode 100644 js/src/tests/e4x/Expressions/11.1.4-01.js create mode 100644 js/src/tests/e4x/Expressions/11.1.4-02.js create mode 100644 js/src/tests/e4x/Expressions/11.1.4-03.js create mode 100644 js/src/tests/e4x/Expressions/11.1.4-04.js create mode 100644 js/src/tests/e4x/Expressions/11.1.4-05.js create mode 100644 js/src/tests/e4x/Expressions/11.1.4-06.js create mode 100644 js/src/tests/e4x/Expressions/11.1.4-07.js create mode 100644 js/src/tests/e4x/Expressions/11.1.4-08.js create mode 100644 js/src/tests/e4x/Expressions/11.1.4.js create mode 100644 js/src/tests/e4x/Expressions/11.1.5.js create mode 100644 js/src/tests/e4x/Expressions/11.2.1.js create mode 100644 js/src/tests/e4x/Expressions/11.2.2.js create mode 100644 js/src/tests/e4x/Expressions/11.2.3.js create mode 100644 js/src/tests/e4x/Expressions/11.2.4.js create mode 100644 js/src/tests/e4x/Expressions/11.3.1.js create mode 100644 js/src/tests/e4x/Expressions/11.3.2.js create mode 100644 js/src/tests/e4x/Expressions/11.4.1.js create mode 100644 js/src/tests/e4x/Expressions/11.5.1.js create mode 100644 js/src/tests/e4x/Expressions/11.6.1.js create mode 100644 js/src/tests/e4x/Expressions/11.6.2.js create mode 100644 js/src/tests/e4x/Expressions/11.6.3.js create mode 100644 js/src/tests/e4x/Expressions/browser.js create mode 100644 js/src/tests/e4x/Expressions/jstests.list create mode 100644 js/src/tests/e4x/Expressions/regress-301545.js create mode 100644 js/src/tests/e4x/Expressions/regress-302531.js create mode 100644 js/src/tests/e4x/Expressions/regress-340024.js create mode 100644 js/src/tests/e4x/Expressions/regress-366123.js create mode 100644 js/src/tests/e4x/Expressions/regress-496113.js create mode 100644 js/src/tests/e4x/Expressions/shell.js create mode 100644 js/src/tests/e4x/GC/browser.js create mode 100644 js/src/tests/e4x/GC/jstests.list create mode 100644 js/src/tests/e4x/GC/regress-280844-1.js create mode 100644 js/src/tests/e4x/GC/regress-280844-2.js create mode 100644 js/src/tests/e4x/GC/regress-292455.js create mode 100644 js/src/tests/e4x/GC/regress-313952-01.js create mode 100644 js/src/tests/e4x/GC/regress-313952-02.js create mode 100644 js/src/tests/e4x/GC/regress-324117.js create mode 100644 js/src/tests/e4x/GC/regress-324278.js create mode 100644 js/src/tests/e4x/GC/regress-339785.js create mode 100644 js/src/tests/e4x/GC/regress-357063-01.js create mode 100644 js/src/tests/e4x/GC/regress-357063-02.js create mode 100644 js/src/tests/e4x/GC/shell.js create mode 100644 js/src/tests/e4x/Global/13.1.2.1.js create mode 100644 js/src/tests/e4x/Global/browser.js create mode 100644 js/src/tests/e4x/Global/jstests.list create mode 100644 js/src/tests/e4x/Global/shell.js create mode 100644 js/src/tests/e4x/Namespace/13.2.1.js create mode 100644 js/src/tests/e4x/Namespace/13.2.2.js create mode 100644 js/src/tests/e4x/Namespace/13.2.5.js create mode 100644 js/src/tests/e4x/Namespace/browser.js create mode 100644 js/src/tests/e4x/Namespace/jstests.list create mode 100644 js/src/tests/e4x/Namespace/regress-283972.js create mode 100644 js/src/tests/e4x/Namespace/regress-292863.js create mode 100644 js/src/tests/e4x/Namespace/regress-350442.js create mode 100644 js/src/tests/e4x/Namespace/regress-444608-02.js create mode 100644 js/src/tests/e4x/Namespace/regress-444608.js create mode 100644 js/src/tests/e4x/Namespace/shell.js create mode 100644 js/src/tests/e4x/QName/13.3.1.js create mode 100644 js/src/tests/e4x/QName/13.3.2.js create mode 100644 js/src/tests/e4x/QName/13.3.5.js create mode 100644 js/src/tests/e4x/QName/browser.js create mode 100644 js/src/tests/e4x/QName/jstests.list create mode 100644 js/src/tests/e4x/QName/regress-373595-01.js create mode 100644 js/src/tests/e4x/QName/regress-373595-02.js create mode 100644 js/src/tests/e4x/QName/regress-373595-03.js create mode 100644 js/src/tests/e4x/QName/regress-444608.js create mode 100644 js/src/tests/e4x/QName/regress-619529.js create mode 100644 js/src/tests/e4x/QName/shell.js create mode 100644 js/src/tests/e4x/Regress/browser.js create mode 100644 js/src/tests/e4x/Regress/jstests.list create mode 100644 js/src/tests/e4x/Regress/regress-257679.js create mode 100644 js/src/tests/e4x/Regress/regress-263934.js create mode 100644 js/src/tests/e4x/Regress/regress-263935.js create mode 100644 js/src/tests/e4x/Regress/regress-263936.js create mode 100644 js/src/tests/e4x/Regress/regress-264369.js create mode 100644 js/src/tests/e4x/Regress/regress-271545.js create mode 100644 js/src/tests/e4x/Regress/regress-277650.js create mode 100644 js/src/tests/e4x/Regress/regress-277664.js create mode 100644 js/src/tests/e4x/Regress/regress-277683.js create mode 100644 js/src/tests/e4x/Regress/regress-277779.js create mode 100644 js/src/tests/e4x/Regress/regress-277935.js create mode 100644 js/src/tests/e4x/Regress/regress-278112.js create mode 100644 js/src/tests/e4x/Regress/regress-283349.js create mode 100644 js/src/tests/e4x/Regress/regress-290056.js create mode 100644 js/src/tests/e4x/Regress/regress-290499.js create mode 100644 js/src/tests/e4x/Regress/regress-301553.js create mode 100644 js/src/tests/e4x/Regress/regress-301573.js create mode 100644 js/src/tests/e4x/Regress/regress-301596.js create mode 100644 js/src/tests/e4x/Regress/regress-301692.js create mode 100644 js/src/tests/e4x/Regress/regress-308111.js create mode 100644 js/src/tests/e4x/Regress/regress-309897.js create mode 100644 js/src/tests/e4x/Regress/regress-311580.js create mode 100644 js/src/tests/e4x/Regress/regress-313799.js create mode 100644 js/src/tests/e4x/Regress/regress-318922.js create mode 100644 js/src/tests/e4x/Regress/regress-319872.js create mode 100644 js/src/tests/e4x/Regress/regress-321547.js create mode 100644 js/src/tests/e4x/Regress/regress-322499.js create mode 100644 js/src/tests/e4x/Regress/regress-323338-1.js create mode 100644 js/src/tests/e4x/Regress/regress-323338-2.js create mode 100644 js/src/tests/e4x/Regress/regress-325425.js create mode 100644 js/src/tests/e4x/Regress/regress-327564.js create mode 100644 js/src/tests/e4x/Regress/regress-327691-01.js create mode 100644 js/src/tests/e4x/Regress/regress-327691-02.js create mode 100644 js/src/tests/e4x/Regress/regress-327697.js create mode 100644 js/src/tests/e4x/Regress/regress-328249.js create mode 100644 js/src/tests/e4x/Regress/regress-329257.js create mode 100644 js/src/tests/e4x/Regress/regress-331558.js create mode 100644 js/src/tests/e4x/Regress/regress-331664.js create mode 100644 js/src/tests/e4x/Regress/regress-344455.js create mode 100644 js/src/tests/e4x/Regress/regress-347155.js create mode 100644 js/src/tests/e4x/Regress/regress-350206-1.js create mode 100644 js/src/tests/e4x/Regress/regress-350206.js create mode 100644 js/src/tests/e4x/Regress/regress-350238.js create mode 100644 js/src/tests/e4x/Regress/regress-350629.js create mode 100644 js/src/tests/e4x/Regress/regress-352097.js create mode 100644 js/src/tests/e4x/Regress/regress-352103.js create mode 100644 js/src/tests/e4x/Regress/regress-352223.js create mode 100644 js/src/tests/e4x/Regress/regress-354145-01.js create mode 100644 js/src/tests/e4x/Regress/regress-354145-02.js create mode 100644 js/src/tests/e4x/Regress/regress-354145-03.js create mode 100644 js/src/tests/e4x/Regress/regress-354145-04.js create mode 100644 js/src/tests/e4x/Regress/regress-354145-05.js create mode 100644 js/src/tests/e4x/Regress/regress-354145-07.js create mode 100644 js/src/tests/e4x/Regress/regress-354998.js create mode 100644 js/src/tests/e4x/Regress/regress-355474-02.js create mode 100644 js/src/tests/e4x/Regress/regress-355478.js create mode 100644 js/src/tests/e4x/Regress/regress-355569.js create mode 100644 js/src/tests/e4x/Regress/regress-356238-01.js create mode 100644 js/src/tests/e4x/Regress/regress-356238-02.js create mode 100644 js/src/tests/e4x/Regress/regress-356238-03.js create mode 100644 js/src/tests/e4x/Regress/regress-361451.js create mode 100644 js/src/tests/e4x/Regress/regress-364017.js create mode 100644 js/src/tests/e4x/Regress/regress-369032.js create mode 100644 js/src/tests/e4x/Regress/regress-369536.js create mode 100644 js/src/tests/e4x/Regress/regress-369740.js create mode 100644 js/src/tests/e4x/Regress/regress-370016.js create mode 100644 js/src/tests/e4x/Regress/regress-370048-01.js create mode 100644 js/src/tests/e4x/Regress/regress-370048-02.js create mode 100644 js/src/tests/e4x/Regress/regress-370372.js create mode 100644 js/src/tests/e4x/Regress/regress-371369.js create mode 100644 js/src/tests/e4x/Regress/regress-372563.js create mode 100644 js/src/tests/e4x/Regress/regress-372564.js create mode 100644 js/src/tests/e4x/Regress/regress-373082.js create mode 100644 js/src/tests/e4x/Regress/regress-374106.js create mode 100644 js/src/tests/e4x/Regress/regress-374112.js create mode 100644 js/src/tests/e4x/Regress/regress-374116.js create mode 100644 js/src/tests/e4x/Regress/regress-374160.js create mode 100644 js/src/tests/e4x/Regress/regress-375406.js create mode 100644 js/src/tests/e4x/Regress/regress-378492.js create mode 100644 js/src/tests/e4x/Regress/regress-380833.js create mode 100644 js/src/tests/e4x/Regress/regress-383255.js create mode 100644 js/src/tests/e4x/Regress/regress-394941.js create mode 100644 js/src/tests/e4x/Regress/regress-407323.js create mode 100755 js/src/tests/e4x/Regress/regress-426520.js create mode 100644 js/src/tests/e4x/Regress/regress-453915.js create mode 100644 js/src/tests/e4x/Regress/regress-458679-01.js create mode 100644 js/src/tests/e4x/Regress/regress-458679-02.js create mode 100644 js/src/tests/e4x/Regress/regress-460180.js create mode 100755 js/src/tests/e4x/Regress/regress-465063.js create mode 100755 js/src/tests/e4x/Regress/regress-470619.js create mode 100755 js/src/tests/e4x/Regress/regress-473709.js create mode 100755 js/src/tests/e4x/Regress/regress-474319.js create mode 100644 js/src/tests/e4x/Regress/regress-477053.js create mode 100644 js/src/tests/e4x/Regress/regress-561031.js create mode 100644 js/src/tests/e4x/Regress/regress-587434.js create mode 100644 js/src/tests/e4x/Regress/shell.js create mode 100644 js/src/tests/e4x/Statements/12.1.js create mode 100644 js/src/tests/e4x/Statements/12.2.js create mode 100644 js/src/tests/e4x/Statements/12.3-01.js create mode 100644 js/src/tests/e4x/Statements/browser.js create mode 100644 js/src/tests/e4x/Statements/jstests.list create mode 100644 js/src/tests/e4x/Statements/shell.js create mode 100644 js/src/tests/e4x/TypeConversion/10.1.1.js create mode 100644 js/src/tests/e4x/TypeConversion/10.1.2.js create mode 100644 js/src/tests/e4x/TypeConversion/10.2.1.js create mode 100644 js/src/tests/e4x/TypeConversion/10.3.1.js create mode 100644 js/src/tests/e4x/TypeConversion/10.3.js create mode 100644 js/src/tests/e4x/TypeConversion/10.4.1.js create mode 100644 js/src/tests/e4x/TypeConversion/10.4.js create mode 100644 js/src/tests/e4x/TypeConversion/10.5.1.js create mode 100644 js/src/tests/e4x/TypeConversion/10.5.js create mode 100644 js/src/tests/e4x/TypeConversion/10.6.1.js create mode 100644 js/src/tests/e4x/TypeConversion/10.6.js create mode 100644 js/src/tests/e4x/TypeConversion/browser.js create mode 100644 js/src/tests/e4x/TypeConversion/jstests.list create mode 100644 js/src/tests/e4x/TypeConversion/regress-302097.js create mode 100644 js/src/tests/e4x/TypeConversion/shell.js create mode 100644 js/src/tests/e4x/Types/9.1.1.1.js create mode 100644 js/src/tests/e4x/Types/9.1.1.10.js create mode 100644 js/src/tests/e4x/Types/9.1.1.11.js create mode 100644 js/src/tests/e4x/Types/9.1.1.12.js create mode 100644 js/src/tests/e4x/Types/9.1.1.13.js create mode 100644 js/src/tests/e4x/Types/9.1.1.2.js create mode 100644 js/src/tests/e4x/Types/9.1.1.3.js create mode 100644 js/src/tests/e4x/Types/9.1.1.4.js create mode 100644 js/src/tests/e4x/Types/9.1.1.5.js create mode 100644 js/src/tests/e4x/Types/9.1.1.6.js create mode 100644 js/src/tests/e4x/Types/9.1.1.7.js create mode 100644 js/src/tests/e4x/Types/9.1.1.8.js create mode 100644 js/src/tests/e4x/Types/9.1.1.9.js create mode 100644 js/src/tests/e4x/Types/9.2.1.1.js create mode 100644 js/src/tests/e4x/Types/9.2.1.10.js create mode 100644 js/src/tests/e4x/Types/9.2.1.2.js create mode 100644 js/src/tests/e4x/Types/9.2.1.3.js create mode 100644 js/src/tests/e4x/Types/9.2.1.4.js create mode 100644 js/src/tests/e4x/Types/9.2.1.5.js create mode 100644 js/src/tests/e4x/Types/9.2.1.6.js create mode 100644 js/src/tests/e4x/Types/9.2.1.7.js create mode 100644 js/src/tests/e4x/Types/9.2.1.8.js create mode 100644 js/src/tests/e4x/Types/9.2.1.9.js create mode 100644 js/src/tests/e4x/Types/browser.js create mode 100644 js/src/tests/e4x/Types/jstests.list create mode 100644 js/src/tests/e4x/Types/shell.js create mode 100644 js/src/tests/e4x/XML/13.4.1.js create mode 100644 js/src/tests/e4x/XML/13.4.2.js create mode 100644 js/src/tests/e4x/XML/13.4.3.10.js create mode 100644 js/src/tests/e4x/XML/13.4.3.js create mode 100644 js/src/tests/e4x/XML/13.4.4.1.js create mode 100644 js/src/tests/e4x/XML/13.4.4.10.js create mode 100644 js/src/tests/e4x/XML/13.4.4.11.js create mode 100644 js/src/tests/e4x/XML/13.4.4.12-1.js create mode 100644 js/src/tests/e4x/XML/13.4.4.12.js create mode 100644 js/src/tests/e4x/XML/13.4.4.13.js create mode 100644 js/src/tests/e4x/XML/13.4.4.14.js create mode 100644 js/src/tests/e4x/XML/13.4.4.15.js create mode 100644 js/src/tests/e4x/XML/13.4.4.16.js create mode 100644 js/src/tests/e4x/XML/13.4.4.17.js create mode 100644 js/src/tests/e4x/XML/13.4.4.18.js create mode 100644 js/src/tests/e4x/XML/13.4.4.19.js create mode 100644 js/src/tests/e4x/XML/13.4.4.2.js create mode 100644 js/src/tests/e4x/XML/13.4.4.20.js create mode 100644 js/src/tests/e4x/XML/13.4.4.21.js create mode 100644 js/src/tests/e4x/XML/13.4.4.22.js create mode 100644 js/src/tests/e4x/XML/13.4.4.23.js create mode 100644 js/src/tests/e4x/XML/13.4.4.24.js create mode 100644 js/src/tests/e4x/XML/13.4.4.25.js create mode 100644 js/src/tests/e4x/XML/13.4.4.26.js create mode 100644 js/src/tests/e4x/XML/13.4.4.27.js create mode 100644 js/src/tests/e4x/XML/13.4.4.28.js create mode 100644 js/src/tests/e4x/XML/13.4.4.29.js create mode 100644 js/src/tests/e4x/XML/13.4.4.3-01.js create mode 100644 js/src/tests/e4x/XML/13.4.4.3-02.js create mode 100644 js/src/tests/e4x/XML/13.4.4.3.js create mode 100644 js/src/tests/e4x/XML/13.4.4.30.js create mode 100644 js/src/tests/e4x/XML/13.4.4.31.js create mode 100644 js/src/tests/e4x/XML/13.4.4.32-01.js create mode 100644 js/src/tests/e4x/XML/13.4.4.32.js create mode 100644 js/src/tests/e4x/XML/13.4.4.33.js create mode 100644 js/src/tests/e4x/XML/13.4.4.34.js create mode 100644 js/src/tests/e4x/XML/13.4.4.35.js create mode 100644 js/src/tests/e4x/XML/13.4.4.36.js create mode 100644 js/src/tests/e4x/XML/13.4.4.37.js create mode 100644 js/src/tests/e4x/XML/13.4.4.38.js create mode 100644 js/src/tests/e4x/XML/13.4.4.39.js create mode 100644 js/src/tests/e4x/XML/13.4.4.4.js create mode 100644 js/src/tests/e4x/XML/13.4.4.40.js create mode 100644 js/src/tests/e4x/XML/13.4.4.5.js create mode 100644 js/src/tests/e4x/XML/13.4.4.6.js create mode 100644 js/src/tests/e4x/XML/13.4.4.7.js create mode 100644 js/src/tests/e4x/XML/13.4.4.8.js create mode 100644 js/src/tests/e4x/XML/13.4.4.9.js create mode 100644 js/src/tests/e4x/XML/browser.js create mode 100644 js/src/tests/e4x/XML/jstests.list create mode 100644 js/src/tests/e4x/XML/regress-291930.js create mode 100644 js/src/tests/e4x/XML/regress-324422-1.js create mode 100644 js/src/tests/e4x/XML/regress-324422-2.js create mode 100644 js/src/tests/e4x/XML/regress-324688.js create mode 100644 js/src/tests/e4x/XML/regress-336921.js create mode 100644 js/src/tests/e4x/XML/regress-376773.js create mode 100644 js/src/tests/e4x/XML/regress-621464.js create mode 100644 js/src/tests/e4x/XML/shell.js create mode 100644 js/src/tests/e4x/XMLList/13.5.1.js create mode 100644 js/src/tests/e4x/XMLList/13.5.2.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.10.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.11.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.12.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.13.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.14.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.15.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.16.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.17.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.18.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.19.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.2.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.20.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.21.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.22.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.3.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.4.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.5.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.6.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.7.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.8.js create mode 100644 js/src/tests/e4x/XMLList/13.5.4.9.js create mode 100644 js/src/tests/e4x/XMLList/browser.js create mode 100644 js/src/tests/e4x/XMLList/jstests.list create mode 100644 js/src/tests/e4x/XMLList/regress-373072.js create mode 100644 js/src/tests/e4x/XMLList/shell.js create mode 100644 js/src/tests/e4x/browser.js create mode 100644 js/src/tests/e4x/decompilation/browser.js create mode 100644 js/src/tests/e4x/decompilation/decompile-xml-escapes.js create mode 100644 js/src/tests/e4x/decompilation/jstests.list create mode 100644 js/src/tests/e4x/decompilation/regress-349814.js create mode 100644 js/src/tests/e4x/decompilation/regress-349815.js create mode 100644 js/src/tests/e4x/decompilation/regress-349822.js create mode 100644 js/src/tests/e4x/decompilation/regress-349956.js create mode 100644 js/src/tests/e4x/decompilation/regress-350226.js create mode 100644 js/src/tests/e4x/decompilation/regress-350531.js create mode 100644 js/src/tests/e4x/decompilation/regress-351706.js create mode 100644 js/src/tests/e4x/decompilation/regress-351988.js create mode 100644 js/src/tests/e4x/decompilation/regress-352013.js create mode 100644 js/src/tests/e4x/decompilation/regress-352459.js create mode 100644 js/src/tests/e4x/decompilation/regress-352649.js create mode 100644 js/src/tests/e4x/decompilation/regress-352789.js create mode 100644 js/src/tests/e4x/decompilation/regress-355101.js create mode 100644 js/src/tests/e4x/decompilation/regress-355474-01.js create mode 100644 js/src/tests/e4x/decompilation/regress-373678.js create mode 100644 js/src/tests/e4x/decompilation/regress-429249.js create mode 100644 js/src/tests/e4x/decompilation/regress-461233.js create mode 100644 js/src/tests/e4x/decompilation/regress-463360.js create mode 100644 js/src/tests/e4x/decompilation/shell.js create mode 100644 js/src/tests/e4x/extensions/browser.js create mode 100644 js/src/tests/e4x/extensions/extensibility.js create mode 100644 js/src/tests/e4x/extensions/jstests.list create mode 100644 js/src/tests/e4x/extensions/regress-305335.js create mode 100644 js/src/tests/e4x/extensions/regress-312196.js create mode 100644 js/src/tests/e4x/extensions/regress-313080.js create mode 100644 js/src/tests/e4x/extensions/regress-321547.js create mode 100644 js/src/tests/e4x/extensions/regress-327534.js create mode 100644 js/src/tests/e4x/extensions/regress-327897.js create mode 100644 js/src/tests/e4x/extensions/regress-335051.js create mode 100644 js/src/tests/e4x/extensions/regress-337226.js create mode 100644 js/src/tests/e4x/extensions/regress-352846-01.js create mode 100644 js/src/tests/e4x/extensions/regress-352846-02.js create mode 100644 js/src/tests/e4x/extensions/regress-352846-03.js create mode 100644 js/src/tests/e4x/extensions/regress-353165.js create mode 100644 js/src/tests/e4x/extensions/regress-354145-06.js create mode 100644 js/src/tests/e4x/extensions/regress-354151-01.js create mode 100644 js/src/tests/e4x/extensions/regress-354151-02.js create mode 100644 js/src/tests/e4x/extensions/regress-374025.js create mode 100644 js/src/tests/e4x/extensions/regress-374163.js create mode 100644 js/src/tests/e4x/extensions/regress-410192.js create mode 100644 js/src/tests/e4x/extensions/regress-450871-01.js create mode 100644 js/src/tests/e4x/extensions/regress-450871-02.js create mode 100644 js/src/tests/e4x/extensions/regress-462734-01.js create mode 100644 js/src/tests/e4x/extensions/regress-595207.js create mode 100644 js/src/tests/e4x/extensions/shell.js create mode 100644 js/src/tests/e4x/jstests.list create mode 100644 js/src/tests/e4x/shell.js create mode 100644 js/src/tests/e4x/template.js create mode 100644 js/src/tests/ecma/Array/15.4-1.js create mode 100644 js/src/tests/ecma/Array/15.4-2.js create mode 100644 js/src/tests/ecma/Array/15.4.1.1.js create mode 100644 js/src/tests/ecma/Array/15.4.1.2.js create mode 100644 js/src/tests/ecma/Array/15.4.1.3.js create mode 100644 js/src/tests/ecma/Array/15.4.1.js create mode 100644 js/src/tests/ecma/Array/15.4.2.1-1.js create mode 100644 js/src/tests/ecma/Array/15.4.2.1-2.js create mode 100644 js/src/tests/ecma/Array/15.4.2.1-3.js create mode 100644 js/src/tests/ecma/Array/15.4.2.2-1.js create mode 100644 js/src/tests/ecma/Array/15.4.2.2-2.js create mode 100644 js/src/tests/ecma/Array/15.4.2.3.js create mode 100644 js/src/tests/ecma/Array/15.4.3.1-2.js create mode 100644 js/src/tests/ecma/Array/15.4.3.2.js create mode 100644 js/src/tests/ecma/Array/15.4.4.1.js create mode 100644 js/src/tests/ecma/Array/15.4.4.2.js create mode 100644 js/src/tests/ecma/Array/15.4.4.3-1.js create mode 100644 js/src/tests/ecma/Array/15.4.4.4-1.js create mode 100644 js/src/tests/ecma/Array/15.4.4.4-2.js create mode 100644 js/src/tests/ecma/Array/15.4.4.5-1.js create mode 100644 js/src/tests/ecma/Array/15.4.4.5-2.js create mode 100644 js/src/tests/ecma/Array/15.4.4.5-3.js create mode 100644 js/src/tests/ecma/Array/15.4.4.js create mode 100644 js/src/tests/ecma/Array/15.4.5.1-1.js create mode 100644 js/src/tests/ecma/Array/15.4.5.1-2.js create mode 100644 js/src/tests/ecma/Array/15.4.5.2-1.js create mode 100644 js/src/tests/ecma/Array/15.4.5.2-2.js create mode 100644 js/src/tests/ecma/Array/array-length-set-on-nonarray.js create mode 100644 js/src/tests/ecma/Array/browser.js create mode 100644 js/src/tests/ecma/Array/jstests.list create mode 100644 js/src/tests/ecma/Array/shell.js create mode 100644 js/src/tests/ecma/Boolean/15.6.1.js create mode 100644 js/src/tests/ecma/Boolean/15.6.2.js create mode 100644 js/src/tests/ecma/Boolean/15.6.3.1-1.js create mode 100644 js/src/tests/ecma/Boolean/15.6.3.1-2.js create mode 100644 js/src/tests/ecma/Boolean/15.6.3.1-3.js create mode 100644 js/src/tests/ecma/Boolean/15.6.3.1-4.js create mode 100644 js/src/tests/ecma/Boolean/15.6.3.1.js create mode 100644 js/src/tests/ecma/Boolean/15.6.4-1.js create mode 100644 js/src/tests/ecma/Boolean/15.6.4.1.js create mode 100644 js/src/tests/ecma/Boolean/15.6.4.2-1.js create mode 100644 js/src/tests/ecma/Boolean/15.6.4.2-2.js create mode 100644 js/src/tests/ecma/Boolean/15.6.4.2-3.js create mode 100644 js/src/tests/ecma/Boolean/15.6.4.2-4-n.js create mode 100644 js/src/tests/ecma/Boolean/15.6.4.3-1.js create mode 100644 js/src/tests/ecma/Boolean/15.6.4.3-2.js create mode 100644 js/src/tests/ecma/Boolean/15.6.4.3-3.js create mode 100644 js/src/tests/ecma/Boolean/15.6.4.3-4-n.js create mode 100644 js/src/tests/ecma/Boolean/15.6.4.3.js create mode 100644 js/src/tests/ecma/Boolean/15.6.4.js create mode 100644 js/src/tests/ecma/Boolean/browser.js create mode 100644 js/src/tests/ecma/Boolean/jstests.list create mode 100644 js/src/tests/ecma/Boolean/shell.js create mode 100644 js/src/tests/ecma/Date/15.9.1.1-1.js create mode 100644 js/src/tests/ecma/Date/15.9.1.1-2.js create mode 100644 js/src/tests/ecma/Date/15.9.1.13-1.js create mode 100644 js/src/tests/ecma/Date/15.9.2.1.js create mode 100644 js/src/tests/ecma/Date/15.9.2.2-1.js create mode 100644 js/src/tests/ecma/Date/15.9.2.2-2.js create mode 100644 js/src/tests/ecma/Date/15.9.2.2-3.js create mode 100644 js/src/tests/ecma/Date/15.9.2.2-4.js create mode 100644 js/src/tests/ecma/Date/15.9.2.2-5.js create mode 100644 js/src/tests/ecma/Date/15.9.2.2-6.js create mode 100644 js/src/tests/ecma/Date/15.9.3.1-1.js create mode 100644 js/src/tests/ecma/Date/15.9.3.1-2.js create mode 100644 js/src/tests/ecma/Date/15.9.3.1-3.js create mode 100644 js/src/tests/ecma/Date/15.9.3.1-4.js create mode 100644 js/src/tests/ecma/Date/15.9.3.1-5.js create mode 100644 js/src/tests/ecma/Date/15.9.3.2-1.js create mode 100644 js/src/tests/ecma/Date/15.9.3.2-2.js create mode 100644 js/src/tests/ecma/Date/15.9.3.2-3.js create mode 100644 js/src/tests/ecma/Date/15.9.3.2-4.js create mode 100644 js/src/tests/ecma/Date/15.9.3.2-5.js create mode 100644 js/src/tests/ecma/Date/15.9.3.8-1.js create mode 100644 js/src/tests/ecma/Date/15.9.3.8-2.js create mode 100644 js/src/tests/ecma/Date/15.9.3.8-3.js create mode 100644 js/src/tests/ecma/Date/15.9.3.8-4.js create mode 100644 js/src/tests/ecma/Date/15.9.3.8-5.js create mode 100644 js/src/tests/ecma/Date/15.9.4.2-1.js create mode 100644 js/src/tests/ecma/Date/15.9.4.2.js create mode 100644 js/src/tests/ecma/Date/15.9.4.3.js create mode 100644 js/src/tests/ecma/Date/15.9.5.1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.10-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.10-10.js create mode 100644 js/src/tests/ecma/Date/15.9.5.10-11.js create mode 100644 js/src/tests/ecma/Date/15.9.5.10-12.js create mode 100644 js/src/tests/ecma/Date/15.9.5.10-13.js create mode 100644 js/src/tests/ecma/Date/15.9.5.10-2.js create mode 100644 js/src/tests/ecma/Date/15.9.5.10-3.js create mode 100644 js/src/tests/ecma/Date/15.9.5.10-4.js create mode 100644 js/src/tests/ecma/Date/15.9.5.10-5.js create mode 100644 js/src/tests/ecma/Date/15.9.5.10-6.js create mode 100644 js/src/tests/ecma/Date/15.9.5.10-7.js create mode 100644 js/src/tests/ecma/Date/15.9.5.10-8.js create mode 100644 js/src/tests/ecma/Date/15.9.5.10-9.js create mode 100644 js/src/tests/ecma/Date/15.9.5.11-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.11-2.js create mode 100644 js/src/tests/ecma/Date/15.9.5.11-3.js create mode 100644 js/src/tests/ecma/Date/15.9.5.11-4.js create mode 100644 js/src/tests/ecma/Date/15.9.5.11-5.js create mode 100644 js/src/tests/ecma/Date/15.9.5.11-6.js create mode 100644 js/src/tests/ecma/Date/15.9.5.11-7.js create mode 100644 js/src/tests/ecma/Date/15.9.5.12-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.12-2.js create mode 100644 js/src/tests/ecma/Date/15.9.5.12-3.js create mode 100644 js/src/tests/ecma/Date/15.9.5.12-4.js create mode 100644 js/src/tests/ecma/Date/15.9.5.12-5.js create mode 100644 js/src/tests/ecma/Date/15.9.5.12-6.js create mode 100644 js/src/tests/ecma/Date/15.9.5.12-7.js create mode 100644 js/src/tests/ecma/Date/15.9.5.12-8.js create mode 100644 js/src/tests/ecma/Date/15.9.5.13-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.13-2.js create mode 100644 js/src/tests/ecma/Date/15.9.5.13-3.js create mode 100644 js/src/tests/ecma/Date/15.9.5.13-4.js create mode 100644 js/src/tests/ecma/Date/15.9.5.13-5.js create mode 100644 js/src/tests/ecma/Date/15.9.5.13-6.js create mode 100644 js/src/tests/ecma/Date/15.9.5.13-7.js create mode 100644 js/src/tests/ecma/Date/15.9.5.13-8.js create mode 100644 js/src/tests/ecma/Date/15.9.5.14.js create mode 100644 js/src/tests/ecma/Date/15.9.5.15.js create mode 100644 js/src/tests/ecma/Date/15.9.5.16.js create mode 100644 js/src/tests/ecma/Date/15.9.5.17.js create mode 100644 js/src/tests/ecma/Date/15.9.5.18.js create mode 100644 js/src/tests/ecma/Date/15.9.5.19.js create mode 100644 js/src/tests/ecma/Date/15.9.5.2-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.2-2-n.js create mode 100644 js/src/tests/ecma/Date/15.9.5.2.js create mode 100644 js/src/tests/ecma/Date/15.9.5.20.js create mode 100644 js/src/tests/ecma/Date/15.9.5.21-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.21-2.js create mode 100644 js/src/tests/ecma/Date/15.9.5.21-3.js create mode 100644 js/src/tests/ecma/Date/15.9.5.21-4.js create mode 100644 js/src/tests/ecma/Date/15.9.5.21-5.js create mode 100644 js/src/tests/ecma/Date/15.9.5.21-6.js create mode 100644 js/src/tests/ecma/Date/15.9.5.21-7.js create mode 100644 js/src/tests/ecma/Date/15.9.5.21-8.js create mode 100644 js/src/tests/ecma/Date/15.9.5.22-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.22-2.js create mode 100644 js/src/tests/ecma/Date/15.9.5.22-3.js create mode 100644 js/src/tests/ecma/Date/15.9.5.22-4.js create mode 100644 js/src/tests/ecma/Date/15.9.5.22-5.js create mode 100644 js/src/tests/ecma/Date/15.9.5.22-6.js create mode 100644 js/src/tests/ecma/Date/15.9.5.22-7.js create mode 100644 js/src/tests/ecma/Date/15.9.5.22-8.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-10.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-11.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-12.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-13.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-14.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-15.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-16.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-17.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-18.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-2.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-3-n.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-4.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-5.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-6.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-7.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-8.js create mode 100644 js/src/tests/ecma/Date/15.9.5.23-9.js create mode 100644 js/src/tests/ecma/Date/15.9.5.24-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.24-2.js create mode 100644 js/src/tests/ecma/Date/15.9.5.24-3.js create mode 100644 js/src/tests/ecma/Date/15.9.5.24-4.js create mode 100644 js/src/tests/ecma/Date/15.9.5.24-5.js create mode 100644 js/src/tests/ecma/Date/15.9.5.24-6.js create mode 100644 js/src/tests/ecma/Date/15.9.5.24-7.js create mode 100644 js/src/tests/ecma/Date/15.9.5.24-8.js create mode 100644 js/src/tests/ecma/Date/15.9.5.25-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.26-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.27-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.28-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.29-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.3-1-n.js create mode 100644 js/src/tests/ecma/Date/15.9.5.3-2.js create mode 100644 js/src/tests/ecma/Date/15.9.5.30-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.31-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.32-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.33-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.34-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.35-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.36-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.36-2.js create mode 100644 js/src/tests/ecma/Date/15.9.5.36-3.js create mode 100644 js/src/tests/ecma/Date/15.9.5.36-4.js create mode 100644 js/src/tests/ecma/Date/15.9.5.36-5.js create mode 100644 js/src/tests/ecma/Date/15.9.5.36-6.js create mode 100644 js/src/tests/ecma/Date/15.9.5.36-7.js create mode 100644 js/src/tests/ecma/Date/15.9.5.37-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.37-2.js create mode 100644 js/src/tests/ecma/Date/15.9.5.37-3.js create mode 100644 js/src/tests/ecma/Date/15.9.5.37-4.js create mode 100644 js/src/tests/ecma/Date/15.9.5.37-5.js create mode 100644 js/src/tests/ecma/Date/15.9.5.4-1.js create mode 100644 js/src/tests/ecma/Date/15.9.5.4-2-n.js create mode 100644 js/src/tests/ecma/Date/15.9.5.5.js create mode 100644 js/src/tests/ecma/Date/15.9.5.6.js create mode 100644 js/src/tests/ecma/Date/15.9.5.7.js create mode 100644 js/src/tests/ecma/Date/15.9.5.8.js create mode 100644 js/src/tests/ecma/Date/15.9.5.9.js create mode 100644 js/src/tests/ecma/Date/15.9.5.js create mode 100644 js/src/tests/ecma/Date/browser.js create mode 100644 js/src/tests/ecma/Date/dst-offset-caching-1-of-8.js create mode 100644 js/src/tests/ecma/Date/dst-offset-caching-2-of-8.js create mode 100644 js/src/tests/ecma/Date/dst-offset-caching-3-of-8.js create mode 100644 js/src/tests/ecma/Date/dst-offset-caching-4-of-8.js create mode 100644 js/src/tests/ecma/Date/dst-offset-caching-5-of-8.js create mode 100644 js/src/tests/ecma/Date/dst-offset-caching-6-of-8.js create mode 100644 js/src/tests/ecma/Date/dst-offset-caching-7-of-8.js create mode 100644 js/src/tests/ecma/Date/dst-offset-caching-8-of-8.js create mode 100644 js/src/tests/ecma/Date/jstests.list create mode 100644 js/src/tests/ecma/Date/shell.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.3-1.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.3-2.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.3.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.4-1.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.4-10.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.4-2.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.4-3.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.4-4.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.4-5.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.4-6.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.4-7.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.4-8.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.5-1.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.5-2.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.5-3.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.5-4.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.8-2.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.1.8-3.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.2.1.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.2.2-1.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.2.2-2.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.2.3-1.js create mode 100644 js/src/tests/ecma/ExecutionContexts/10.2.3-2.js create mode 100644 js/src/tests/ecma/ExecutionContexts/browser.js create mode 100644 js/src/tests/ecma/ExecutionContexts/jstests.list create mode 100644 js/src/tests/ecma/ExecutionContexts/shell.js create mode 100644 js/src/tests/ecma/Expressions/11.1.1.js create mode 100644 js/src/tests/ecma/Expressions/11.10-1.js create mode 100644 js/src/tests/ecma/Expressions/11.10-2.js create mode 100644 js/src/tests/ecma/Expressions/11.10-3.js create mode 100644 js/src/tests/ecma/Expressions/11.12-1.js create mode 100644 js/src/tests/ecma/Expressions/11.12-2-n.js create mode 100644 js/src/tests/ecma/Expressions/11.12-3.js create mode 100644 js/src/tests/ecma/Expressions/11.12-4.js create mode 100644 js/src/tests/ecma/Expressions/11.13.1.js create mode 100644 js/src/tests/ecma/Expressions/11.13.2-1.js create mode 100644 js/src/tests/ecma/Expressions/11.13.2-2.js create mode 100644 js/src/tests/ecma/Expressions/11.13.2-3.js create mode 100644 js/src/tests/ecma/Expressions/11.13.2-4.js create mode 100644 js/src/tests/ecma/Expressions/11.13.2-5.js create mode 100644 js/src/tests/ecma/Expressions/11.13.js create mode 100644 js/src/tests/ecma/Expressions/11.14-1.js create mode 100644 js/src/tests/ecma/Expressions/11.2.1-1.js create mode 100644 js/src/tests/ecma/Expressions/11.2.1-2.js create mode 100644 js/src/tests/ecma/Expressions/11.2.1-3-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.1-4-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.1-5.js create mode 100644 js/src/tests/ecma/Expressions/11.2.2-1-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.2-1.js create mode 100644 js/src/tests/ecma/Expressions/11.2.2-10-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.2-11.js create mode 100644 js/src/tests/ecma/Expressions/11.2.2-2-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.2-3-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.2-4-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.2-5-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.2-6-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.2-7-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.2-8-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.2-9-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.3-1.js create mode 100644 js/src/tests/ecma/Expressions/11.2.3-2-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.3-3-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.3-4-n.js create mode 100644 js/src/tests/ecma/Expressions/11.2.3-5.js create mode 100644 js/src/tests/ecma/Expressions/11.3.1.js create mode 100644 js/src/tests/ecma/Expressions/11.3.2.js create mode 100644 js/src/tests/ecma/Expressions/11.4.1.js create mode 100644 js/src/tests/ecma/Expressions/11.4.2.js create mode 100644 js/src/tests/ecma/Expressions/11.4.3.js create mode 100644 js/src/tests/ecma/Expressions/11.4.4.js create mode 100644 js/src/tests/ecma/Expressions/11.4.5.js create mode 100644 js/src/tests/ecma/Expressions/11.4.6.js create mode 100644 js/src/tests/ecma/Expressions/11.4.7-01.js create mode 100644 js/src/tests/ecma/Expressions/11.4.7-02.js create mode 100644 js/src/tests/ecma/Expressions/11.4.8.js create mode 100644 js/src/tests/ecma/Expressions/11.4.9.js create mode 100644 js/src/tests/ecma/Expressions/11.5.1.js create mode 100644 js/src/tests/ecma/Expressions/11.5.2.js create mode 100644 js/src/tests/ecma/Expressions/11.5.3.js create mode 100644 js/src/tests/ecma/Expressions/11.6.1-1.js create mode 100644 js/src/tests/ecma/Expressions/11.6.1-2.js create mode 100644 js/src/tests/ecma/Expressions/11.6.1-3.js create mode 100644 js/src/tests/ecma/Expressions/11.6.2-1.js create mode 100644 js/src/tests/ecma/Expressions/11.6.3.js create mode 100644 js/src/tests/ecma/Expressions/11.7.1.js create mode 100644 js/src/tests/ecma/Expressions/11.7.2.js create mode 100644 js/src/tests/ecma/Expressions/11.7.3.js create mode 100644 js/src/tests/ecma/Expressions/11.8.1.js create mode 100644 js/src/tests/ecma/Expressions/11.8.2.js create mode 100644 js/src/tests/ecma/Expressions/11.8.3.js create mode 100644 js/src/tests/ecma/Expressions/11.8.4.js create mode 100644 js/src/tests/ecma/Expressions/11.9.1.js create mode 100644 js/src/tests/ecma/Expressions/11.9.2.js create mode 100644 js/src/tests/ecma/Expressions/11.9.3.js create mode 100644 js/src/tests/ecma/Expressions/browser.js create mode 100644 js/src/tests/ecma/Expressions/jstests.list create mode 100644 js/src/tests/ecma/Expressions/shell.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.1.1-1.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.1.1-2.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.1.1-3.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.2.1-1.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.2.1-2.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.2.1-3.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.3.1-2.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.3.1-3.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.3.1-4.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.3.2.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.4-1.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.4.1.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.4.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.5-1.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.5-2.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.5.1.js create mode 100644 js/src/tests/ecma/FunctionObjects/15.3.5.3.js create mode 100644 js/src/tests/ecma/FunctionObjects/browser.js create mode 100644 js/src/tests/ecma/FunctionObjects/jstests.list create mode 100644 js/src/tests/ecma/FunctionObjects/shell.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1-1-n.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1-2-n.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1.1.1.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1.1.2.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1.2.1-2.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1.2.2-1.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1.2.2-2.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1.2.3-1.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1.2.3-2.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1.2.4.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1.2.5-1.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1.2.5-2.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1.2.5-3.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1.2.6.js create mode 100644 js/src/tests/ecma/GlobalObject/15.1.2.7.js create mode 100644 js/src/tests/ecma/GlobalObject/browser.js create mode 100644 js/src/tests/ecma/GlobalObject/jstests.list create mode 100644 js/src/tests/ecma/GlobalObject/shell.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.1-1.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.1-2.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.1-3.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.2-1.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.2-2-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.2-3-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.2-4-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.2-5-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.2-6.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.3-1.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.3-10.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.3-11.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.3-12.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.3-13-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.3-2.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.3-3.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.3-4.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.3-5.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.3-6.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.3-7.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.3-8.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.3-9.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.1-1-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.1-2-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.1-3-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-1-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-10-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-11-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-12-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-13-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-14-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-15-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-16-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-2-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-3-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-4-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-5-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-6-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-7-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-8-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.2-9-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-1-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-10-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-11-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-12-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-13-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-14-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-15-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-16-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-2-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-3-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-4-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-5-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-6-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-7-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-8-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.4.3-9-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.5-1.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.5-10-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.5-2-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.5-3-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.5-4-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.5-5-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.5-6.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.5-7.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.5-8-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.5-9-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.6.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.7.1.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.7.2.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.7.3-1.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.7.3-2.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.7.3.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.7.4.js create mode 100644 js/src/tests/ecma/LexicalConventions/7.8.2-n.js create mode 100644 js/src/tests/ecma/LexicalConventions/browser.js create mode 100644 js/src/tests/ecma/LexicalConventions/jstests.list create mode 100644 js/src/tests/ecma/LexicalConventions/shell.js create mode 100644 js/src/tests/ecma/Math/15.8-2-n.js create mode 100644 js/src/tests/ecma/Math/15.8-3-n.js create mode 100644 js/src/tests/ecma/Math/15.8.1.1-1.js create mode 100644 js/src/tests/ecma/Math/15.8.1.1-2.js create mode 100644 js/src/tests/ecma/Math/15.8.1.2-1.js create mode 100644 js/src/tests/ecma/Math/15.8.1.2-2.js create mode 100644 js/src/tests/ecma/Math/15.8.1.3-1.js create mode 100644 js/src/tests/ecma/Math/15.8.1.3-2.js create mode 100644 js/src/tests/ecma/Math/15.8.1.4-1.js create mode 100644 js/src/tests/ecma/Math/15.8.1.4-2.js create mode 100644 js/src/tests/ecma/Math/15.8.1.5-1.js create mode 100644 js/src/tests/ecma/Math/15.8.1.5-2.js create mode 100644 js/src/tests/ecma/Math/15.8.1.6-1.js create mode 100644 js/src/tests/ecma/Math/15.8.1.6-2.js create mode 100644 js/src/tests/ecma/Math/15.8.1.7-1.js create mode 100644 js/src/tests/ecma/Math/15.8.1.7-2.js create mode 100644 js/src/tests/ecma/Math/15.8.1.8-1.js create mode 100644 js/src/tests/ecma/Math/15.8.1.8-2.js create mode 100644 js/src/tests/ecma/Math/15.8.1.8-3.js create mode 100644 js/src/tests/ecma/Math/15.8.1.js create mode 100644 js/src/tests/ecma/Math/15.8.2.1.js create mode 100644 js/src/tests/ecma/Math/15.8.2.10.js create mode 100644 js/src/tests/ecma/Math/15.8.2.11.js create mode 100644 js/src/tests/ecma/Math/15.8.2.12.js create mode 100644 js/src/tests/ecma/Math/15.8.2.13.js create mode 100644 js/src/tests/ecma/Math/15.8.2.14.js create mode 100644 js/src/tests/ecma/Math/15.8.2.15.js create mode 100644 js/src/tests/ecma/Math/15.8.2.16.js create mode 100644 js/src/tests/ecma/Math/15.8.2.17.js create mode 100644 js/src/tests/ecma/Math/15.8.2.18.js create mode 100644 js/src/tests/ecma/Math/15.8.2.2.js create mode 100644 js/src/tests/ecma/Math/15.8.2.3.js create mode 100644 js/src/tests/ecma/Math/15.8.2.4.js create mode 100644 js/src/tests/ecma/Math/15.8.2.5.js create mode 100644 js/src/tests/ecma/Math/15.8.2.6.js create mode 100644 js/src/tests/ecma/Math/15.8.2.7.js create mode 100644 js/src/tests/ecma/Math/15.8.2.8.js create mode 100644 js/src/tests/ecma/Math/15.8.2.9.js create mode 100644 js/src/tests/ecma/Math/browser.js create mode 100644 js/src/tests/ecma/Math/jstests.list create mode 100644 js/src/tests/ecma/Math/shell.js create mode 100644 js/src/tests/ecma/NativeObjects/browser.js create mode 100644 js/src/tests/ecma/NativeObjects/jstests.list create mode 100644 js/src/tests/ecma/NativeObjects/shell.js create mode 100644 js/src/tests/ecma/Number/0x-without-following-hexdigits.js create mode 100644 js/src/tests/ecma/Number/15.7.1.js create mode 100644 js/src/tests/ecma/Number/15.7.2.js create mode 100644 js/src/tests/ecma/Number/15.7.3.1-1.js create mode 100644 js/src/tests/ecma/Number/15.7.3.1-2.js create mode 100644 js/src/tests/ecma/Number/15.7.3.1-3.js create mode 100644 js/src/tests/ecma/Number/15.7.3.2-1.js create mode 100644 js/src/tests/ecma/Number/15.7.3.2-2.js create mode 100644 js/src/tests/ecma/Number/15.7.3.2-3.js create mode 100644 js/src/tests/ecma/Number/15.7.3.2-4.js create mode 100644 js/src/tests/ecma/Number/15.7.3.3-1.js create mode 100644 js/src/tests/ecma/Number/15.7.3.3-2.js create mode 100644 js/src/tests/ecma/Number/15.7.3.3-3.js create mode 100644 js/src/tests/ecma/Number/15.7.3.3-4.js create mode 100644 js/src/tests/ecma/Number/15.7.3.4-1.js create mode 100644 js/src/tests/ecma/Number/15.7.3.4-2.js create mode 100644 js/src/tests/ecma/Number/15.7.3.4-3.js create mode 100644 js/src/tests/ecma/Number/15.7.3.4-4.js create mode 100644 js/src/tests/ecma/Number/15.7.3.5-1.js create mode 100644 js/src/tests/ecma/Number/15.7.3.5-2.js create mode 100644 js/src/tests/ecma/Number/15.7.3.5-3.js create mode 100644 js/src/tests/ecma/Number/15.7.3.5-4.js create mode 100644 js/src/tests/ecma/Number/15.7.3.6-1.js create mode 100644 js/src/tests/ecma/Number/15.7.3.6-2.js create mode 100644 js/src/tests/ecma/Number/15.7.3.6-3.js create mode 100644 js/src/tests/ecma/Number/15.7.3.6-4.js create mode 100644 js/src/tests/ecma/Number/15.7.3.js create mode 100644 js/src/tests/ecma/Number/15.7.4-1.js create mode 100644 js/src/tests/ecma/Number/15.7.4.1.js create mode 100644 js/src/tests/ecma/Number/15.7.4.2-1.js create mode 100644 js/src/tests/ecma/Number/15.7.4.2-2-n.js create mode 100644 js/src/tests/ecma/Number/15.7.4.2-3-n.js create mode 100644 js/src/tests/ecma/Number/15.7.4.2-4.js create mode 100644 js/src/tests/ecma/Number/15.7.4.3-1.js create mode 100644 js/src/tests/ecma/Number/15.7.4.3-2.js create mode 100644 js/src/tests/ecma/Number/15.7.4.3-3-n.js create mode 100644 js/src/tests/ecma/Number/browser.js create mode 100644 js/src/tests/ecma/Number/jstests.list create mode 100644 js/src/tests/ecma/Number/shell.js create mode 100644 js/src/tests/ecma/ObjectObjects/15.2.1.1.js create mode 100644 js/src/tests/ecma/ObjectObjects/15.2.1.2.js create mode 100644 js/src/tests/ecma/ObjectObjects/15.2.2.1.js create mode 100644 js/src/tests/ecma/ObjectObjects/15.2.2.2.js create mode 100644 js/src/tests/ecma/ObjectObjects/15.2.3-1.js create mode 100644 js/src/tests/ecma/ObjectObjects/15.2.3.1-1.js create mode 100644 js/src/tests/ecma/ObjectObjects/15.2.3.1-2.js create mode 100644 js/src/tests/ecma/ObjectObjects/15.2.3.1-3.js create mode 100644 js/src/tests/ecma/ObjectObjects/15.2.3.1-4.js create mode 100644 js/src/tests/ecma/ObjectObjects/15.2.3.js create mode 100644 js/src/tests/ecma/ObjectObjects/15.2.4.1.js create mode 100644 js/src/tests/ecma/ObjectObjects/15.2.4.2.js create mode 100644 js/src/tests/ecma/ObjectObjects/15.2.4.3.js create mode 100644 js/src/tests/ecma/ObjectObjects/browser.js create mode 100644 js/src/tests/ecma/ObjectObjects/jstests.list create mode 100644 js/src/tests/ecma/ObjectObjects/shell.js create mode 100644 js/src/tests/ecma/README create mode 100644 js/src/tests/ecma/SourceText/6-1.js create mode 100644 js/src/tests/ecma/SourceText/6-2.js create mode 100644 js/src/tests/ecma/SourceText/browser.js create mode 100644 js/src/tests/ecma/SourceText/jstests.list create mode 100644 js/src/tests/ecma/SourceText/shell.js create mode 100644 js/src/tests/ecma/Statements/12.10-1.js create mode 100644 js/src/tests/ecma/Statements/12.10.js create mode 100644 js/src/tests/ecma/Statements/12.2-1.js create mode 100644 js/src/tests/ecma/Statements/12.5-1.js create mode 100644 js/src/tests/ecma/Statements/12.5-2.js create mode 100644 js/src/tests/ecma/Statements/12.6.1-1.js create mode 100644 js/src/tests/ecma/Statements/12.6.2-1.js create mode 100644 js/src/tests/ecma/Statements/12.6.2-2.js create mode 100644 js/src/tests/ecma/Statements/12.6.2-3.js create mode 100644 js/src/tests/ecma/Statements/12.6.2-4.js create mode 100644 js/src/tests/ecma/Statements/12.6.2-5.js create mode 100644 js/src/tests/ecma/Statements/12.6.2-6.js create mode 100644 js/src/tests/ecma/Statements/12.6.2-7.js create mode 100644 js/src/tests/ecma/Statements/12.6.2-8.js create mode 100644 js/src/tests/ecma/Statements/12.6.2-9-n.js create mode 100644 js/src/tests/ecma/Statements/12.6.3-1.js create mode 100644 js/src/tests/ecma/Statements/12.6.3-10.js create mode 100644 js/src/tests/ecma/Statements/12.6.3-11.js create mode 100644 js/src/tests/ecma/Statements/12.6.3-12.js create mode 100644 js/src/tests/ecma/Statements/12.6.3-19.js create mode 100644 js/src/tests/ecma/Statements/12.6.3-2.js create mode 100644 js/src/tests/ecma/Statements/12.6.3-3.js create mode 100644 js/src/tests/ecma/Statements/12.6.3-4.js create mode 100644 js/src/tests/ecma/Statements/12.6.3-5-n.js create mode 100644 js/src/tests/ecma/Statements/12.6.3-6-n.js create mode 100644 js/src/tests/ecma/Statements/12.6.3-7-n.js create mode 100644 js/src/tests/ecma/Statements/12.6.3-8-n.js create mode 100644 js/src/tests/ecma/Statements/12.6.3-9-n.js create mode 100644 js/src/tests/ecma/Statements/12.7-1-n.js create mode 100644 js/src/tests/ecma/Statements/12.8-1-n.js create mode 100644 js/src/tests/ecma/Statements/12.9-1-n.js create mode 100644 js/src/tests/ecma/Statements/browser.js create mode 100644 js/src/tests/ecma/Statements/jstests.list create mode 100644 js/src/tests/ecma/Statements/shell.js create mode 100644 js/src/tests/ecma/String/15.5.1.js create mode 100644 js/src/tests/ecma/String/15.5.2.js create mode 100644 js/src/tests/ecma/String/15.5.3.1-1.js create mode 100644 js/src/tests/ecma/String/15.5.3.1-2.js create mode 100644 js/src/tests/ecma/String/15.5.3.1-3.js create mode 100644 js/src/tests/ecma/String/15.5.3.1-4.js create mode 100644 js/src/tests/ecma/String/15.5.3.2-1.js create mode 100644 js/src/tests/ecma/String/15.5.3.2-2.js create mode 100644 js/src/tests/ecma/String/15.5.3.2-3.js create mode 100644 js/src/tests/ecma/String/15.5.3.js create mode 100644 js/src/tests/ecma/String/15.5.4.1.js create mode 100644 js/src/tests/ecma/String/15.5.4.10-1.js create mode 100644 js/src/tests/ecma/String/15.5.4.11-1.js create mode 100644 js/src/tests/ecma/String/15.5.4.11-2.js create mode 100644 js/src/tests/ecma/String/15.5.4.11-3.js create mode 100644 js/src/tests/ecma/String/15.5.4.11-4.js create mode 100644 js/src/tests/ecma/String/15.5.4.11-5.js create mode 100644 js/src/tests/ecma/String/15.5.4.11-6.js create mode 100644 js/src/tests/ecma/String/15.5.4.12-1.js create mode 100644 js/src/tests/ecma/String/15.5.4.12-2.js create mode 100644 js/src/tests/ecma/String/15.5.4.12-3.js create mode 100644 js/src/tests/ecma/String/15.5.4.12-4.js create mode 100644 js/src/tests/ecma/String/15.5.4.12-5.js create mode 100644 js/src/tests/ecma/String/15.5.4.2-1.js create mode 100644 js/src/tests/ecma/String/15.5.4.2-2-n.js create mode 100644 js/src/tests/ecma/String/15.5.4.2-3.js create mode 100644 js/src/tests/ecma/String/15.5.4.2.js create mode 100644 js/src/tests/ecma/String/15.5.4.3-1.js create mode 100644 js/src/tests/ecma/String/15.5.4.3-2.js create mode 100644 js/src/tests/ecma/String/15.5.4.3-3-n.js create mode 100644 js/src/tests/ecma/String/15.5.4.4-1.js create mode 100644 js/src/tests/ecma/String/15.5.4.4-2.js create mode 100644 js/src/tests/ecma/String/15.5.4.4-3.js create mode 100644 js/src/tests/ecma/String/15.5.4.4-4.js create mode 100644 js/src/tests/ecma/String/15.5.4.5-1.js create mode 100644 js/src/tests/ecma/String/15.5.4.5-2.js create mode 100644 js/src/tests/ecma/String/15.5.4.5-3.js create mode 100644 js/src/tests/ecma/String/15.5.4.5-4.js create mode 100644 js/src/tests/ecma/String/15.5.4.5-5.js create mode 100644 js/src/tests/ecma/String/15.5.4.6-1.js create mode 100644 js/src/tests/ecma/String/15.5.4.6-2.js create mode 100644 js/src/tests/ecma/String/15.5.4.7-1.js create mode 100644 js/src/tests/ecma/String/15.5.4.7-2.js create mode 100644 js/src/tests/ecma/String/15.5.4.8-1.js create mode 100644 js/src/tests/ecma/String/15.5.4.8-2.js create mode 100644 js/src/tests/ecma/String/15.5.4.8-3.js create mode 100644 js/src/tests/ecma/String/15.5.4.9-1.js create mode 100644 js/src/tests/ecma/String/15.5.4.js create mode 100644 js/src/tests/ecma/String/15.5.5.1.js create mode 100644 js/src/tests/ecma/String/browser.js create mode 100644 js/src/tests/ecma/String/jstests.list create mode 100644 js/src/tests/ecma/String/shell.js create mode 100644 js/src/tests/ecma/TypeConversion/9.2.js create mode 100644 js/src/tests/ecma/TypeConversion/9.3-1.js create mode 100644 js/src/tests/ecma/TypeConversion/9.3.1-1.js create mode 100644 js/src/tests/ecma/TypeConversion/9.3.1-2.js create mode 100644 js/src/tests/ecma/TypeConversion/9.3.1-3.js create mode 100644 js/src/tests/ecma/TypeConversion/9.3.js create mode 100644 js/src/tests/ecma/TypeConversion/9.4-1.js create mode 100644 js/src/tests/ecma/TypeConversion/9.4-2.js create mode 100644 js/src/tests/ecma/TypeConversion/9.5-2.js create mode 100644 js/src/tests/ecma/TypeConversion/9.6.js create mode 100644 js/src/tests/ecma/TypeConversion/9.7.js create mode 100644 js/src/tests/ecma/TypeConversion/9.8.1.js create mode 100644 js/src/tests/ecma/TypeConversion/9.9-1.js create mode 100644 js/src/tests/ecma/TypeConversion/browser.js create mode 100644 js/src/tests/ecma/TypeConversion/jstests.list create mode 100644 js/src/tests/ecma/TypeConversion/shell.js create mode 100644 js/src/tests/ecma/Types/8.1.js create mode 100644 js/src/tests/ecma/Types/8.4.js create mode 100644 js/src/tests/ecma/Types/8.6.2.1-1.js create mode 100644 js/src/tests/ecma/Types/browser.js create mode 100644 js/src/tests/ecma/Types/jstests.list create mode 100644 js/src/tests/ecma/Types/shell.js create mode 100644 js/src/tests/ecma/browser.js create mode 100644 js/src/tests/ecma/extensions/10.1.4-9.js create mode 100644 js/src/tests/ecma/extensions/10.1.6.js create mode 100644 js/src/tests/ecma/extensions/10.1.8-1.js create mode 100644 js/src/tests/ecma/extensions/11.6.1-1.js create mode 100644 js/src/tests/ecma/extensions/11.6.1-2.js create mode 100644 js/src/tests/ecma/extensions/11.6.1-3.js create mode 100644 js/src/tests/ecma/extensions/11.6.2-1.js create mode 100644 js/src/tests/ecma/extensions/15-1.js create mode 100644 js/src/tests/ecma/extensions/15-2.js create mode 100644 js/src/tests/ecma/extensions/15.1.2.1-1.js create mode 100644 js/src/tests/ecma/extensions/15.2.1.1.js create mode 100644 js/src/tests/ecma/extensions/15.2.3-1.js create mode 100644 js/src/tests/ecma/extensions/15.2.4.js create mode 100644 js/src/tests/ecma/extensions/15.3.1.1-1.js create mode 100644 js/src/tests/ecma/extensions/15.3.1.1-2.js create mode 100644 js/src/tests/ecma/extensions/15.3.2.1-1.js create mode 100644 js/src/tests/ecma/extensions/15.3.2.1-2.js create mode 100644 js/src/tests/ecma/extensions/15.3.3.1-1.js create mode 100644 js/src/tests/ecma/extensions/15.4.3.js create mode 100644 js/src/tests/ecma/extensions/15.5.3.js create mode 100644 js/src/tests/ecma/extensions/15.5.4.2.js create mode 100644 js/src/tests/ecma/extensions/15.5.4.4-4.js create mode 100644 js/src/tests/ecma/extensions/15.5.4.5-6.js create mode 100644 js/src/tests/ecma/extensions/15.5.4.7-3.js create mode 100644 js/src/tests/ecma/extensions/15.6.3.1-5.js create mode 100644 js/src/tests/ecma/extensions/15.6.3.js create mode 100644 js/src/tests/ecma/extensions/15.6.4-2.js create mode 100644 js/src/tests/ecma/extensions/15.7.3.js create mode 100644 js/src/tests/ecma/extensions/15.7.4.js create mode 100644 js/src/tests/ecma/extensions/15.8-1.js create mode 100644 js/src/tests/ecma/extensions/15.9.5.js create mode 100644 js/src/tests/ecma/extensions/8.6.2.1-1.js create mode 100644 js/src/tests/ecma/extensions/9.9-1.js create mode 100644 js/src/tests/ecma/extensions/browser.js create mode 100644 js/src/tests/ecma/extensions/jstests.list create mode 100644 js/src/tests/ecma/extensions/shell.js create mode 100644 js/src/tests/ecma/extensions/trapflatclosure.js create mode 100644 js/src/tests/ecma/jsref.js create mode 100644 js/src/tests/ecma/jstests.list create mode 100644 js/src/tests/ecma/shell.js create mode 100644 js/src/tests/ecma/template.js create mode 100644 js/src/tests/ecma_2/Exceptions/boolean-001.js create mode 100644 js/src/tests/ecma_2/Exceptions/boolean-002.js create mode 100644 js/src/tests/ecma_2/Exceptions/browser.js create mode 100644 js/src/tests/ecma_2/Exceptions/date-001.js create mode 100644 js/src/tests/ecma_2/Exceptions/date-002.js create mode 100644 js/src/tests/ecma_2/Exceptions/date-003.js create mode 100644 js/src/tests/ecma_2/Exceptions/date-004.js create mode 100644 js/src/tests/ecma_2/Exceptions/exception-001.js create mode 100644 js/src/tests/ecma_2/Exceptions/exception-002.js create mode 100644 js/src/tests/ecma_2/Exceptions/exception-003.js create mode 100644 js/src/tests/ecma_2/Exceptions/exception-004.js create mode 100644 js/src/tests/ecma_2/Exceptions/exception-005.js create mode 100644 js/src/tests/ecma_2/Exceptions/exception-006.js create mode 100644 js/src/tests/ecma_2/Exceptions/exception-007.js create mode 100644 js/src/tests/ecma_2/Exceptions/exception-008.js create mode 100644 js/src/tests/ecma_2/Exceptions/exception-009.js create mode 100644 js/src/tests/ecma_2/Exceptions/exception-010-n.js create mode 100644 js/src/tests/ecma_2/Exceptions/exception-011-n.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-001.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-002.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-003.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-004.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-005.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-006.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-007.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-008.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-009.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-010.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-011.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-012.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-013.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-014.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-015.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-016.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-017.js create mode 100644 js/src/tests/ecma_2/Exceptions/expression-019.js create mode 100644 js/src/tests/ecma_2/Exceptions/function-001.js create mode 100644 js/src/tests/ecma_2/Exceptions/global-001.js create mode 100644 js/src/tests/ecma_2/Exceptions/global-002.js create mode 100644 js/src/tests/ecma_2/Exceptions/jstests.list create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-001.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-002.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-003.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-004.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-005.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-006.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-007.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-008.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-009.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-010.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-011.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-012.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-013.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-014.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-015.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-016.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-017.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-018.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-019.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-020.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-021.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-022.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-023.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-024.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-025.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-026.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-027.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-028.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-029.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-030.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-031.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-032.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-033.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-034.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-035.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-036.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-037.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-038.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-039.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-040.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-041.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-042.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-047.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-048.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-049.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-050.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-051.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-052.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-053.js create mode 100644 js/src/tests/ecma_2/Exceptions/lexical-054.js create mode 100644 js/src/tests/ecma_2/Exceptions/number-001.js create mode 100644 js/src/tests/ecma_2/Exceptions/number-002.js create mode 100644 js/src/tests/ecma_2/Exceptions/number-003.js create mode 100644 js/src/tests/ecma_2/Exceptions/shell.js create mode 100644 js/src/tests/ecma_2/Exceptions/statement-001.js create mode 100644 js/src/tests/ecma_2/Exceptions/statement-002.js create mode 100644 js/src/tests/ecma_2/Exceptions/statement-003.js create mode 100644 js/src/tests/ecma_2/Exceptions/statement-004.js create mode 100644 js/src/tests/ecma_2/Exceptions/statement-005.js create mode 100644 js/src/tests/ecma_2/Exceptions/statement-006.js create mode 100644 js/src/tests/ecma_2/Exceptions/statement-007.js create mode 100644 js/src/tests/ecma_2/Exceptions/statement-008.js create mode 100644 js/src/tests/ecma_2/Exceptions/statement-009.js create mode 100644 js/src/tests/ecma_2/Exceptions/string-001.js create mode 100644 js/src/tests/ecma_2/Exceptions/string-002.js create mode 100644 js/src/tests/ecma_2/Expressions/StrictEquality-001.js create mode 100644 js/src/tests/ecma_2/Expressions/browser.js create mode 100644 js/src/tests/ecma_2/Expressions/jstests.list create mode 100644 js/src/tests/ecma_2/Expressions/shell.js create mode 100644 js/src/tests/ecma_2/FunctionObjects/apply-001-n.js create mode 100644 js/src/tests/ecma_2/FunctionObjects/browser.js create mode 100644 js/src/tests/ecma_2/FunctionObjects/call-1.js create mode 100644 js/src/tests/ecma_2/FunctionObjects/jstests.list create mode 100644 js/src/tests/ecma_2/FunctionObjects/shell.js create mode 100644 js/src/tests/ecma_2/LexicalConventions/browser.js create mode 100644 js/src/tests/ecma_2/LexicalConventions/jstests.list create mode 100644 js/src/tests/ecma_2/LexicalConventions/keywords-001.js create mode 100644 js/src/tests/ecma_2/LexicalConventions/regexp-literals-001.js create mode 100644 js/src/tests/ecma_2/LexicalConventions/regexp-literals-002.js create mode 100644 js/src/tests/ecma_2/LexicalConventions/shell.js create mode 100644 js/src/tests/ecma_2/README create mode 100644 js/src/tests/ecma_2/RegExp/browser.js create mode 100644 js/src/tests/ecma_2/RegExp/constructor-001.js create mode 100644 js/src/tests/ecma_2/RegExp/exec-001.js create mode 100644 js/src/tests/ecma_2/RegExp/exec-002.js create mode 100644 js/src/tests/ecma_2/RegExp/function-001.js create mode 100644 js/src/tests/ecma_2/RegExp/hex-001.js create mode 100644 js/src/tests/ecma_2/RegExp/jstests.list create mode 100644 js/src/tests/ecma_2/RegExp/multiline-001.js create mode 100644 js/src/tests/ecma_2/RegExp/octal-001.js create mode 100644 js/src/tests/ecma_2/RegExp/octal-002.js create mode 100644 js/src/tests/ecma_2/RegExp/octal-003.js create mode 100644 js/src/tests/ecma_2/RegExp/properties-001.js create mode 100644 js/src/tests/ecma_2/RegExp/properties-002.js create mode 100644 js/src/tests/ecma_2/RegExp/regexp-enumerate-001.js create mode 100644 js/src/tests/ecma_2/RegExp/regress-001.js create mode 100644 js/src/tests/ecma_2/RegExp/shell.js create mode 100644 js/src/tests/ecma_2/RegExp/unicode-001.js create mode 100644 js/src/tests/ecma_2/Statements/browser.js create mode 100644 js/src/tests/ecma_2/Statements/dowhile-001.js create mode 100644 js/src/tests/ecma_2/Statements/dowhile-002.js create mode 100644 js/src/tests/ecma_2/Statements/dowhile-003.js create mode 100644 js/src/tests/ecma_2/Statements/dowhile-004.js create mode 100644 js/src/tests/ecma_2/Statements/dowhile-005.js create mode 100644 js/src/tests/ecma_2/Statements/dowhile-006.js create mode 100644 js/src/tests/ecma_2/Statements/dowhile-007.js create mode 100644 js/src/tests/ecma_2/Statements/forin-001.js create mode 100644 js/src/tests/ecma_2/Statements/forin-002.js create mode 100644 js/src/tests/ecma_2/Statements/if-001.js create mode 100644 js/src/tests/ecma_2/Statements/jstests.list create mode 100644 js/src/tests/ecma_2/Statements/label-001.js create mode 100644 js/src/tests/ecma_2/Statements/label-002.js create mode 100644 js/src/tests/ecma_2/Statements/shell.js create mode 100644 js/src/tests/ecma_2/Statements/switch-001.js create mode 100644 js/src/tests/ecma_2/Statements/switch-002.js create mode 100644 js/src/tests/ecma_2/Statements/switch-003.js create mode 100644 js/src/tests/ecma_2/Statements/switch-004.js create mode 100644 js/src/tests/ecma_2/Statements/try-001.js create mode 100644 js/src/tests/ecma_2/Statements/try-003.js create mode 100644 js/src/tests/ecma_2/Statements/try-004.js create mode 100644 js/src/tests/ecma_2/Statements/try-005.js create mode 100644 js/src/tests/ecma_2/Statements/try-006.js create mode 100644 js/src/tests/ecma_2/Statements/try-007.js create mode 100644 js/src/tests/ecma_2/Statements/try-008.js create mode 100644 js/src/tests/ecma_2/Statements/try-009.js create mode 100644 js/src/tests/ecma_2/Statements/try-010.js create mode 100644 js/src/tests/ecma_2/Statements/try-012.js create mode 100644 js/src/tests/ecma_2/Statements/while-001.js create mode 100644 js/src/tests/ecma_2/Statements/while-002.js create mode 100644 js/src/tests/ecma_2/Statements/while-003.js create mode 100644 js/src/tests/ecma_2/Statements/while-004.js create mode 100644 js/src/tests/ecma_2/String/browser.js create mode 100644 js/src/tests/ecma_2/String/jstests.list create mode 100644 js/src/tests/ecma_2/String/match-001.js create mode 100644 js/src/tests/ecma_2/String/match-002.js create mode 100644 js/src/tests/ecma_2/String/match-003.js create mode 100644 js/src/tests/ecma_2/String/match-004.js create mode 100644 js/src/tests/ecma_2/String/replace-001.js create mode 100644 js/src/tests/ecma_2/String/shell.js create mode 100644 js/src/tests/ecma_2/String/split-001.js create mode 100644 js/src/tests/ecma_2/String/split-002.js create mode 100644 js/src/tests/ecma_2/String/split-003.js create mode 100644 js/src/tests/ecma_2/browser.js create mode 100644 js/src/tests/ecma_2/extensions/browser.js create mode 100644 js/src/tests/ecma_2/extensions/constructor-001.js create mode 100644 js/src/tests/ecma_2/extensions/function-001.js create mode 100644 js/src/tests/ecma_2/extensions/instanceof-001.js create mode 100644 js/src/tests/ecma_2/extensions/instanceof-002.js create mode 100644 js/src/tests/ecma_2/extensions/instanceof-003-n.js create mode 100644 js/src/tests/ecma_2/extensions/instanceof-004-n.js create mode 100644 js/src/tests/ecma_2/extensions/instanceof-005-n.js create mode 100644 js/src/tests/ecma_2/extensions/instanceof-006.js create mode 100644 js/src/tests/ecma_2/extensions/jstests.list create mode 100644 js/src/tests/ecma_2/extensions/shell.js create mode 100644 js/src/tests/ecma_2/instanceof/browser.js create mode 100644 js/src/tests/ecma_2/instanceof/instanceof-001.js create mode 100644 js/src/tests/ecma_2/instanceof/instanceof-002.js create mode 100644 js/src/tests/ecma_2/instanceof/instanceof-003.js create mode 100644 js/src/tests/ecma_2/instanceof/jstests.list create mode 100644 js/src/tests/ecma_2/instanceof/regress-7635.js create mode 100644 js/src/tests/ecma_2/instanceof/shell.js create mode 100644 js/src/tests/ecma_2/jsref.js create mode 100644 js/src/tests/ecma_2/jstests.list create mode 100644 js/src/tests/ecma_2/shell.js create mode 100644 js/src/tests/ecma_2/template.js create mode 100644 js/src/tests/ecma_3/Array/15.4.4.11-01.js create mode 100644 js/src/tests/ecma_3/Array/15.4.4.3-1.js create mode 100644 js/src/tests/ecma_3/Array/15.4.4.4-001.js create mode 100644 js/src/tests/ecma_3/Array/15.4.5.1-01.js create mode 100644 js/src/tests/ecma_3/Array/15.5.4.8-01.js create mode 100644 js/src/tests/ecma_3/Array/browser.js create mode 100644 js/src/tests/ecma_3/Array/jstests.list create mode 100644 js/src/tests/ecma_3/Array/regress-101488.js create mode 100644 js/src/tests/ecma_3/Array/regress-130451.js create mode 100644 js/src/tests/ecma_3/Array/regress-322135-01.js create mode 100644 js/src/tests/ecma_3/Array/regress-322135-02.js create mode 100644 js/src/tests/ecma_3/Array/regress-322135-03.js create mode 100644 js/src/tests/ecma_3/Array/regress-322135-04.js create mode 100644 js/src/tests/ecma_3/Array/regress-387501.js create mode 100755 js/src/tests/ecma_3/Array/regress-390598.js create mode 100644 js/src/tests/ecma_3/Array/regress-421325.js create mode 100644 js/src/tests/ecma_3/Array/regress-430717.js create mode 100755 js/src/tests/ecma_3/Array/regress-488989.js create mode 100644 js/src/tests/ecma_3/Array/regress-619970.js create mode 100644 js/src/tests/ecma_3/Array/shell.js create mode 100644 js/src/tests/ecma_3/Date/15.9.1.2-01.js create mode 100644 js/src/tests/ecma_3/Date/15.9.3.2-1.js create mode 100644 js/src/tests/ecma_3/Date/15.9.4.3.js create mode 100644 js/src/tests/ecma_3/Date/15.9.5.3.js create mode 100644 js/src/tests/ecma_3/Date/15.9.5.4.js create mode 100644 js/src/tests/ecma_3/Date/15.9.5.5-02.js create mode 100644 js/src/tests/ecma_3/Date/15.9.5.5.js create mode 100644 js/src/tests/ecma_3/Date/15.9.5.6.js create mode 100644 js/src/tests/ecma_3/Date/15.9.5.7.js create mode 100644 js/src/tests/ecma_3/Date/browser.js create mode 100644 js/src/tests/ecma_3/Date/jstests.list create mode 100644 js/src/tests/ecma_3/Date/regress-452786.js create mode 100644 js/src/tests/ecma_3/Date/shell.js create mode 100644 js/src/tests/ecma_3/Exceptions/15.11.1.1.js create mode 100644 js/src/tests/ecma_3/Exceptions/15.11.4.4-1.js create mode 100644 js/src/tests/ecma_3/Exceptions/15.11.5.js create mode 100644 js/src/tests/ecma_3/Exceptions/15.11.7.6-001.js create mode 100644 js/src/tests/ecma_3/Exceptions/15.11.7.6-002.js create mode 100644 js/src/tests/ecma_3/Exceptions/15.11.7.6-003.js create mode 100644 js/src/tests/ecma_3/Exceptions/binding-001.js create mode 100644 js/src/tests/ecma_3/Exceptions/browser.js create mode 100644 js/src/tests/ecma_3/Exceptions/jstests.list create mode 100644 js/src/tests/ecma_3/Exceptions/regress-181654.js create mode 100644 js/src/tests/ecma_3/Exceptions/regress-181914.js create mode 100644 js/src/tests/ecma_3/Exceptions/regress-58946.js create mode 100644 js/src/tests/ecma_3/Exceptions/regress-95101.js create mode 100644 js/src/tests/ecma_3/Exceptions/shell.js create mode 100644 js/src/tests/ecma_3/ExecutionContexts/10.1.3-1.js create mode 100644 js/src/tests/ecma_3/ExecutionContexts/10.1.3-2.js create mode 100644 js/src/tests/ecma_3/ExecutionContexts/10.1.3.js create mode 100644 js/src/tests/ecma_3/ExecutionContexts/10.1.4-1.js create mode 100644 js/src/tests/ecma_3/ExecutionContexts/10.6.1-01.js create mode 100644 js/src/tests/ecma_3/ExecutionContexts/browser.js create mode 100644 js/src/tests/ecma_3/ExecutionContexts/jstests.list create mode 100644 js/src/tests/ecma_3/ExecutionContexts/regress-23346.js create mode 100644 js/src/tests/ecma_3/ExecutionContexts/regress-448595-01.js create mode 100644 js/src/tests/ecma_3/ExecutionContexts/shell.js create mode 100644 js/src/tests/ecma_3/Expressions/11.10-01.js create mode 100644 js/src/tests/ecma_3/Expressions/11.10-02.js create mode 100644 js/src/tests/ecma_3/Expressions/11.10-03.js create mode 100644 js/src/tests/ecma_3/Expressions/11.6.1-1.js create mode 100644 js/src/tests/ecma_3/Expressions/11.7.1-01.js create mode 100644 js/src/tests/ecma_3/Expressions/11.7.2-01.js create mode 100644 js/src/tests/ecma_3/Expressions/11.7.3-01.js create mode 100644 js/src/tests/ecma_3/Expressions/11.9.6-1.js create mode 100644 js/src/tests/ecma_3/Expressions/browser.js create mode 100644 js/src/tests/ecma_3/Expressions/jstests.list create mode 100644 js/src/tests/ecma_3/Expressions/shell.js create mode 100644 js/src/tests/ecma_3/FunExpr/browser.js create mode 100644 js/src/tests/ecma_3/FunExpr/fe-001-n.js create mode 100644 js/src/tests/ecma_3/FunExpr/fe-001.js create mode 100644 js/src/tests/ecma_3/FunExpr/fe-002.js create mode 100644 js/src/tests/ecma_3/FunExpr/jstests.list create mode 100644 js/src/tests/ecma_3/FunExpr/regress-518103.js create mode 100644 js/src/tests/ecma_3/FunExpr/regress-524826.js create mode 100644 js/src/tests/ecma_3/FunExpr/regress-528082.js create mode 100644 js/src/tests/ecma_3/FunExpr/regress-533254.js create mode 100644 js/src/tests/ecma_3/FunExpr/regress-545980.js create mode 100644 js/src/tests/ecma_3/FunExpr/shell.js create mode 100644 js/src/tests/ecma_3/Function/15.3.4.3-1.js create mode 100644 js/src/tests/ecma_3/Function/15.3.4.4-1.js create mode 100644 js/src/tests/ecma_3/Function/arguments-001.js create mode 100644 js/src/tests/ecma_3/Function/arguments-002.js create mode 100644 js/src/tests/ecma_3/Function/browser.js create mode 100644 js/src/tests/ecma_3/Function/call-001.js create mode 100644 js/src/tests/ecma_3/Function/jstests.list create mode 100644 js/src/tests/ecma_3/Function/regress-131964.js create mode 100644 js/src/tests/ecma_3/Function/regress-137181.js create mode 100644 js/src/tests/ecma_3/Function/regress-193555.js create mode 100644 js/src/tests/ecma_3/Function/regress-313570.js create mode 100644 js/src/tests/ecma_3/Function/regress-49286.js create mode 100644 js/src/tests/ecma_3/Function/regress-58274.js create mode 100644 js/src/tests/ecma_3/Function/regress-85880.js create mode 100644 js/src/tests/ecma_3/Function/regress-94506.js create mode 100644 js/src/tests/ecma_3/Function/regress-97921.js create mode 100644 js/src/tests/ecma_3/Function/scope-001.js create mode 100644 js/src/tests/ecma_3/Function/scope-002.js create mode 100644 js/src/tests/ecma_3/Function/shell.js create mode 100644 js/src/tests/ecma_3/LexicalConventions/7.4-01.js create mode 100644 js/src/tests/ecma_3/LexicalConventions/7.8.3-01.js create mode 100644 js/src/tests/ecma_3/LexicalConventions/7.9.1.js create mode 100644 js/src/tests/ecma_3/LexicalConventions/browser.js create mode 100644 js/src/tests/ecma_3/LexicalConventions/jstests.list create mode 100644 js/src/tests/ecma_3/LexicalConventions/shell.js create mode 100644 js/src/tests/ecma_3/Number/15.7.4.2-01.js create mode 100644 js/src/tests/ecma_3/Number/15.7.4.3-01.js create mode 100644 js/src/tests/ecma_3/Number/15.7.4.3-02.js create mode 100644 js/src/tests/ecma_3/Number/15.7.4.5-1.js create mode 100644 js/src/tests/ecma_3/Number/15.7.4.5-2.js create mode 100644 js/src/tests/ecma_3/Number/15.7.4.6-1.js create mode 100644 js/src/tests/ecma_3/Number/15.7.4.7-1.js create mode 100644 js/src/tests/ecma_3/Number/15.7.4.7-2.js create mode 100644 js/src/tests/ecma_3/Number/browser.js create mode 100644 js/src/tests/ecma_3/Number/jstests.list create mode 100644 js/src/tests/ecma_3/Number/regress-442242-01.js create mode 100644 js/src/tests/ecma_3/Number/shell.js create mode 100644 js/src/tests/ecma_3/NumberFormatting/browser.js create mode 100644 js/src/tests/ecma_3/NumberFormatting/jstests.list create mode 100644 js/src/tests/ecma_3/NumberFormatting/shell.js create mode 100644 js/src/tests/ecma_3/NumberFormatting/tostring-001.js create mode 100644 js/src/tests/ecma_3/Object/8.6.1-01.js create mode 100644 js/src/tests/ecma_3/Object/8.6.2.6-001.js create mode 100644 js/src/tests/ecma_3/Object/8.6.2.6-002.js create mode 100644 js/src/tests/ecma_3/Object/browser.js create mode 100644 js/src/tests/ecma_3/Object/class-001.js create mode 100644 js/src/tests/ecma_3/Object/class-002.js create mode 100644 js/src/tests/ecma_3/Object/class-003.js create mode 100644 js/src/tests/ecma_3/Object/class-004.js create mode 100644 js/src/tests/ecma_3/Object/class-005.js create mode 100644 js/src/tests/ecma_3/Object/jstests.list create mode 100644 js/src/tests/ecma_3/Object/regress-361274.js create mode 100644 js/src/tests/ecma_3/Object/regress-385393-07.js create mode 100644 js/src/tests/ecma_3/Object/regress-459405.js create mode 100644 js/src/tests/ecma_3/Object/regress-72773.js create mode 100644 js/src/tests/ecma_3/Object/regress-79129-001.js create mode 100644 js/src/tests/ecma_3/Object/shell.js create mode 100644 js/src/tests/ecma_3/Operators/11.13.1-001.js create mode 100644 js/src/tests/ecma_3/Operators/11.13.1-002.js create mode 100644 js/src/tests/ecma_3/Operators/11.4.1-001.js create mode 100644 js/src/tests/ecma_3/Operators/11.4.1-002.js create mode 100644 js/src/tests/ecma_3/Operators/browser.js create mode 100644 js/src/tests/ecma_3/Operators/jstests.list create mode 100644 js/src/tests/ecma_3/Operators/order-01.js create mode 100644 js/src/tests/ecma_3/Operators/shell.js create mode 100644 js/src/tests/ecma_3/README create mode 100644 js/src/tests/ecma_3/RegExp/15.10.2-1.js create mode 100644 js/src/tests/ecma_3/RegExp/15.10.2.12.js create mode 100644 js/src/tests/ecma_3/RegExp/15.10.3.1-1.js create mode 100644 js/src/tests/ecma_3/RegExp/15.10.3.1-2.js create mode 100644 js/src/tests/ecma_3/RegExp/15.10.4.1-1.js create mode 100644 js/src/tests/ecma_3/RegExp/15.10.4.1-2.js create mode 100644 js/src/tests/ecma_3/RegExp/15.10.4.1-3.js create mode 100644 js/src/tests/ecma_3/RegExp/15.10.4.1-4.js create mode 100644 js/src/tests/ecma_3/RegExp/15.10.4.1-5-n.js create mode 100644 js/src/tests/ecma_3/RegExp/15.10.4.1-6.js create mode 100644 js/src/tests/ecma_3/RegExp/15.10.6.2-1.js create mode 100644 js/src/tests/ecma_3/RegExp/15.10.6.2-2.js create mode 100644 js/src/tests/ecma_3/RegExp/browser.js create mode 100644 js/src/tests/ecma_3/RegExp/jstests.list create mode 100644 js/src/tests/ecma_3/RegExp/octal-001.js create mode 100644 js/src/tests/ecma_3/RegExp/octal-002.js create mode 100644 js/src/tests/ecma_3/RegExp/perlstress-001.js create mode 100644 js/src/tests/ecma_3/RegExp/perlstress-002.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-100199.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-105972.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-119909.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-122076.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-123437.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-165353.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-169497.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-169534.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-187133.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-188206.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-191479.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-202564.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-209067.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-209919.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-216591.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-220367-001.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-223273.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-223535.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-224676.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-225289.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-225343.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-24712.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-285219.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-28686.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-289669.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-307456.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-309840.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-311414.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-312351.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-31316.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-330684.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-334158.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-346090.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-367888.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-375642.js create mode 100755 js/src/tests/ecma_3/RegExp/regress-375651.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-375711.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-375715-01-n.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-375715-02.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-375715-03.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-375715-04.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-436700.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-465862.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-57572.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-57631.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-67773.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-72964.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-76683.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-78156.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-85721.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-87231.js create mode 100644 js/src/tests/ecma_3/RegExp/regress-98306.js create mode 100644 js/src/tests/ecma_3/RegExp/shell.js create mode 100644 js/src/tests/ecma_3/Regress/browser.js create mode 100644 js/src/tests/ecma_3/Regress/jstests.list create mode 100644 js/src/tests/ecma_3/Regress/regress-385393-04.js create mode 100644 js/src/tests/ecma_3/Regress/regress-419152.js create mode 100644 js/src/tests/ecma_3/Regress/regress-420087.js create mode 100644 js/src/tests/ecma_3/Regress/regress-420610.js create mode 100644 js/src/tests/ecma_3/Regress/regress-441477-01.js create mode 100755 js/src/tests/ecma_3/Regress/regress-469937.js create mode 100644 js/src/tests/ecma_3/Regress/regress-580544.js create mode 100644 js/src/tests/ecma_3/Regress/shell.js create mode 100644 js/src/tests/ecma_3/Statements/12.10-01.js create mode 100644 js/src/tests/ecma_3/Statements/12.6.3.js create mode 100644 js/src/tests/ecma_3/Statements/browser.js create mode 100644 js/src/tests/ecma_3/Statements/jstests.list create mode 100644 js/src/tests/ecma_3/Statements/regress-121744.js create mode 100644 js/src/tests/ecma_3/Statements/regress-131348.js create mode 100644 js/src/tests/ecma_3/Statements/regress-157509.js create mode 100644 js/src/tests/ecma_3/Statements/regress-194364.js create mode 100644 js/src/tests/ecma_3/Statements/regress-226517.js create mode 100644 js/src/tests/ecma_3/Statements/regress-302439.js create mode 100644 js/src/tests/ecma_3/Statements/regress-324650.js create mode 100644 js/src/tests/ecma_3/Statements/regress-444979.js create mode 100644 js/src/tests/ecma_3/Statements/regress-74474-001.js create mode 100644 js/src/tests/ecma_3/Statements/regress-74474-002.js create mode 100644 js/src/tests/ecma_3/Statements/regress-74474-003.js create mode 100644 js/src/tests/ecma_3/Statements/regress-83532-001.js create mode 100644 js/src/tests/ecma_3/Statements/regress-83532-002.js create mode 100644 js/src/tests/ecma_3/Statements/shell.js create mode 100644 js/src/tests/ecma_3/Statements/switch-001.js create mode 100644 js/src/tests/ecma_3/Statements/switch-002.js create mode 100644 js/src/tests/ecma_3/String/15.5.4.11.js create mode 100644 js/src/tests/ecma_3/String/15.5.4.14.js create mode 100644 js/src/tests/ecma_3/String/browser.js create mode 100644 js/src/tests/ecma_3/String/jstests.list create mode 100644 js/src/tests/ecma_3/String/regress-104375.js create mode 100644 js/src/tests/ecma_3/String/regress-189898.js create mode 100644 js/src/tests/ecma_3/String/regress-304376.js create mode 100644 js/src/tests/ecma_3/String/regress-313567.js create mode 100644 js/src/tests/ecma_3/String/regress-392378.js create mode 100644 js/src/tests/ecma_3/String/regress-83293.js create mode 100644 js/src/tests/ecma_3/String/shell.js create mode 100644 js/src/tests/ecma_3/Unicode/browser.js create mode 100644 js/src/tests/ecma_3/Unicode/jstests.list create mode 100644 js/src/tests/ecma_3/Unicode/regress-352044-01.js create mode 100644 js/src/tests/ecma_3/Unicode/regress-352044-02-n.js create mode 100644 js/src/tests/ecma_3/Unicode/shell.js create mode 100644 js/src/tests/ecma_3/Unicode/uc-001-n.js create mode 100644 js/src/tests/ecma_3/Unicode/uc-001.js create mode 100644 js/src/tests/ecma_3/Unicode/uc-002-n.js create mode 100644 js/src/tests/ecma_3/Unicode/uc-002.js create mode 100644 js/src/tests/ecma_3/Unicode/uc-003.js create mode 100644 js/src/tests/ecma_3/Unicode/uc-004.js create mode 100644 js/src/tests/ecma_3/Unicode/uc-005.js create mode 100644 js/src/tests/ecma_3/browser.js create mode 100644 js/src/tests/ecma_3/extensions/10.1.3-2.js create mode 100644 js/src/tests/ecma_3/extensions/7.9.1.js create mode 100644 js/src/tests/ecma_3/extensions/browser.js create mode 100644 js/src/tests/ecma_3/extensions/jstests.list create mode 100644 js/src/tests/ecma_3/extensions/regress-103087.js create mode 100644 js/src/tests/ecma_3/extensions/regress-188206-01.js create mode 100644 js/src/tests/ecma_3/extensions/regress-188206-02.js create mode 100644 js/src/tests/ecma_3/extensions/regress-220367-002.js create mode 100644 js/src/tests/ecma_3/extensions/regress-228087.js create mode 100644 js/src/tests/ecma_3/extensions/regress-274152.js create mode 100644 js/src/tests/ecma_3/extensions/regress-320854.js create mode 100644 js/src/tests/ecma_3/extensions/regress-327170.js create mode 100644 js/src/tests/ecma_3/extensions/regress-368516.js create mode 100644 js/src/tests/ecma_3/extensions/regress-385393-03.js create mode 100644 js/src/tests/ecma_3/extensions/regress-429248.js create mode 100644 js/src/tests/ecma_3/extensions/regress-430740.js create mode 100644 js/src/tests/ecma_3/extensions/shell.js create mode 100644 js/src/tests/ecma_3/jstests.list create mode 100644 js/src/tests/ecma_3/shell.js create mode 100644 js/src/tests/ecma_3/template.js create mode 100644 js/src/tests/ecma_3_1/Object/browser.js create mode 100644 js/src/tests/ecma_3_1/Object/jstests.list create mode 100644 js/src/tests/ecma_3_1/Object/regress-444787.js create mode 100644 js/src/tests/ecma_3_1/Object/shell.js create mode 100644 js/src/tests/ecma_3_1/README create mode 100644 js/src/tests/ecma_3_1/RegExp/browser.js create mode 100644 js/src/tests/ecma_3_1/RegExp/jstests.list create mode 100644 js/src/tests/ecma_3_1/RegExp/regress-305064.js create mode 100644 js/src/tests/ecma_3_1/RegExp/shell.js create mode 100644 js/src/tests/ecma_3_1/browser.js create mode 100644 js/src/tests/ecma_3_1/extensions/browser.js create mode 100644 js/src/tests/ecma_3_1/extensions/jstests.list create mode 100644 js/src/tests/ecma_3_1/extensions/shell.js create mode 100644 js/src/tests/ecma_3_1/jstests.list create mode 100644 js/src/tests/ecma_3_1/shell.js create mode 100644 js/src/tests/ecma_3_1/template.js create mode 100644 js/src/tests/ecma_5/Array/browser.js create mode 100644 js/src/tests/ecma_5/Array/jstests.list create mode 100644 js/src/tests/ecma_5/Array/length-01.js create mode 100644 js/src/tests/ecma_5/Array/regress-599159.js create mode 100644 js/src/tests/ecma_5/Array/shell.js create mode 100644 js/src/tests/ecma_5/Array/sort-01.js create mode 100644 js/src/tests/ecma_5/Array/toLocaleString-01.js create mode 100644 js/src/tests/ecma_5/Array/toString-01.js create mode 100644 js/src/tests/ecma_5/Array/unshift-01.js create mode 100644 js/src/tests/ecma_5/Boolean/15.6.4.2.js create mode 100644 js/src/tests/ecma_5/Boolean/browser.js create mode 100644 js/src/tests/ecma_5/Boolean/jstests.list create mode 100644 js/src/tests/ecma_5/Boolean/shell.js create mode 100644 js/src/tests/ecma_5/Date/15.9.4.2.js create mode 100644 js/src/tests/ecma_5/Date/browser.js create mode 100644 js/src/tests/ecma_5/Date/jstests.list create mode 100644 js/src/tests/ecma_5/Date/shell.js create mode 100644 js/src/tests/ecma_5/Date/toJSON-01.js create mode 100644 js/src/tests/ecma_5/Expressions/11.1.5-01.js create mode 100644 js/src/tests/ecma_5/Expressions/browser.js create mode 100644 js/src/tests/ecma_5/Expressions/jstests.list create mode 100644 js/src/tests/ecma_5/Expressions/named-accessor-function.js create mode 100644 js/src/tests/ecma_5/Expressions/nested-delete-name-in-evalcode.js create mode 100644 js/src/tests/ecma_5/Expressions/object-literal-accessor-arguments.js create mode 100644 js/src/tests/ecma_5/Expressions/shell.js create mode 100644 js/src/tests/ecma_5/Function/10.2.1.1.6.js create mode 100644 js/src/tests/ecma_5/Function/15.3.4.3-01.js create mode 100644 js/src/tests/ecma_5/Function/Function-arguments-gc.js create mode 100644 js/src/tests/ecma_5/Function/arguments-caller-callee.js create mode 100644 js/src/tests/ecma_5/Function/arguments-property-attributes.js create mode 100644 js/src/tests/ecma_5/Function/browser.js create mode 100644 js/src/tests/ecma_5/Function/builtin-no-prototype.js create mode 100644 js/src/tests/ecma_5/Function/function-bind.js create mode 100644 js/src/tests/ecma_5/Function/function-call.js create mode 100644 js/src/tests/ecma_5/Function/function-caller.js create mode 100644 js/src/tests/ecma_5/Function/jstests.list create mode 100644 js/src/tests/ecma_5/Function/redefine-arguments-length.js create mode 100644 js/src/tests/ecma_5/Function/shell.js create mode 100644 js/src/tests/ecma_5/Function/strict-arguments.js create mode 100644 js/src/tests/ecma_5/Global/adding-global-var-nonextensible-error.js create mode 100644 js/src/tests/ecma_5/Global/browser.js create mode 100644 js/src/tests/ecma_5/Global/direct-eval-but-not.js create mode 100644 js/src/tests/ecma_5/Global/eval-01.js create mode 100644 js/src/tests/ecma_5/Global/eval-02.js create mode 100644 js/src/tests/ecma_5/Global/eval-in-strict-eval-in-normal-function.js create mode 100644 js/src/tests/ecma_5/Global/eval-inside-with-is-direct.js create mode 100644 js/src/tests/ecma_5/Global/eval-native-callback-is-indirect.js create mode 100644 js/src/tests/ecma_5/Global/jstests.list create mode 100644 js/src/tests/ecma_5/Global/parenthesized-eval-is-direct.js create mode 100644 js/src/tests/ecma_5/Global/parseFloat-01.js create mode 100644 js/src/tests/ecma_5/Global/parseInt-01.js create mode 100644 js/src/tests/ecma_5/Global/shell.js create mode 100644 js/src/tests/ecma_5/JSON/browser.js create mode 100644 js/src/tests/ecma_5/JSON/cyclic-stringify.js create mode 100644 js/src/tests/ecma_5/JSON/jstests.list create mode 100644 js/src/tests/ecma_5/JSON/shell.js create mode 100644 js/src/tests/ecma_5/JSON/small-codepoints.js create mode 100644 js/src/tests/ecma_5/JSON/stringify-gap.js create mode 100644 js/src/tests/ecma_5/JSON/trailing-comma.js create mode 100644 js/src/tests/ecma_5/Number/15.7.4.2.js create mode 100644 js/src/tests/ecma_5/Number/browser.js create mode 100644 js/src/tests/ecma_5/Number/jstests.list create mode 100644 js/src/tests/ecma_5/Number/shell.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.12.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.14-01.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.3-01.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.4-01.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.4-02.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.4-03.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.4-04.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.5-01.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-define-over-method.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-1-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-2-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-3-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-4-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-5-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-6-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-7-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-dictionary-redefinition-8-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-function-length.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-1-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-2-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-3-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-4-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-5-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-6-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-7-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-middle-redefinition-8-of-8.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-miscellaneous.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-new-definition.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-redefinition-1-of-4.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-redefinition-2-of-4.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-redefinition-3-of-4.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.6-redefinition-4-of-4.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.7-01.js create mode 100644 js/src/tests/ecma_5/Object/15.2.3.9.js create mode 100644 js/src/tests/ecma_5/Object/add-property-non-extensible.js create mode 100644 js/src/tests/ecma_5/Object/browser.js create mode 100644 js/src/tests/ecma_5/Object/defineProperty-setup.js create mode 100644 js/src/tests/ecma_5/Object/extensibility-01.js create mode 100644 js/src/tests/ecma_5/Object/extensibility-02.js create mode 100644 js/src/tests/ecma_5/Object/freeze-global-eval-const.js create mode 100644 js/src/tests/ecma_5/Object/isPrototypeOf.js create mode 100644 js/src/tests/ecma_5/Object/jstests.list create mode 100644 js/src/tests/ecma_5/Object/mutation-prevention-methods.js create mode 100644 js/src/tests/ecma_5/Object/object-toString-01.js create mode 100644 js/src/tests/ecma_5/Object/preventExtensions-idempotent.js create mode 100644 js/src/tests/ecma_5/Object/propertyIsEnumerable.js create mode 100644 js/src/tests/ecma_5/Object/shell.js create mode 100644 js/src/tests/ecma_5/Object/vacuous-accessor-unqualified-name.js create mode 100644 js/src/tests/ecma_5/README create mode 100644 js/src/tests/ecma_5/RegExp/15.10.5-01.js create mode 100644 js/src/tests/ecma_5/RegExp/15.10.7.5-01.js create mode 100644 js/src/tests/ecma_5/RegExp/7.8.5-01.js create mode 100644 js/src/tests/ecma_5/RegExp/browser.js create mode 100644 js/src/tests/ecma_5/RegExp/empty-lookahead.js create mode 100644 js/src/tests/ecma_5/RegExp/jstests.list create mode 100644 js/src/tests/ecma_5/RegExp/regress-617935.js create mode 100644 js/src/tests/ecma_5/RegExp/shell.js create mode 100644 js/src/tests/ecma_5/String/15.5.4.11-01.js create mode 100644 js/src/tests/ecma_5/String/15.5.4.2.js create mode 100644 js/src/tests/ecma_5/String/15.5.4.7.js create mode 100644 js/src/tests/ecma_5/String/browser.js create mode 100644 js/src/tests/ecma_5/String/jstests.list create mode 100644 js/src/tests/ecma_5/String/shell.js create mode 100644 js/src/tests/ecma_5/Types/8.12.5-01.js create mode 100644 js/src/tests/ecma_5/Types/browser.js create mode 100644 js/src/tests/ecma_5/Types/jstests.list create mode 100644 js/src/tests/ecma_5/Types/shell.js create mode 100644 js/src/tests/ecma_5/browser.js create mode 100644 js/src/tests/ecma_5/eval/browser.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-fun-normalcaller-direct-normalcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-fun-normalcaller-direct-strictcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-fun-normalcaller-indirect-normalcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-fun-normalcaller-indirect-strictcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-fun-strictcaller-direct-normalcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-fun-strictcaller-direct-strictcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-fun-strictcaller-indirect-normalcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-fun-strictcaller-indirect-strictcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-global-normalcaller-direct-normalcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-global-normalcaller-direct-strictcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-global-normalcaller-indirect-normalcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-global-normalcaller-indirect-strictcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-global-strictcaller-direct-normalcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-global-strictcaller-direct-strictcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-global-strictcaller-indirect-normalcode.js create mode 100644 js/src/tests/ecma_5/eval/exhaustive-global-strictcaller-indirect-strictcode.js create mode 100644 js/src/tests/ecma_5/eval/jstests.list create mode 100644 js/src/tests/ecma_5/eval/shell.js create mode 100644 js/src/tests/ecma_5/eval/undeclared-name-in-nested-strict-eval.js create mode 100644 js/src/tests/ecma_5/extensions/15.4.4.11.js create mode 100644 js/src/tests/ecma_5/extensions/8.12.5-01.js create mode 100644 js/src/tests/ecma_5/extensions/Boolean-toSource.js create mode 100644 js/src/tests/ecma_5/extensions/Number-toSource.js create mode 100644 js/src/tests/ecma_5/extensions/Object-keys-and-object-ids.js create mode 100644 js/src/tests/ecma_5/extensions/String-toSource.js create mode 100644 js/src/tests/ecma_5/extensions/browser.js create mode 100644 js/src/tests/ecma_5/extensions/bug352085.js create mode 100644 js/src/tests/ecma_5/extensions/bug472534.js create mode 100644 js/src/tests/ecma_5/extensions/bug496985.js create mode 100644 js/src/tests/ecma_5/extensions/bug566661.js create mode 100644 js/src/tests/ecma_5/extensions/eval-native-callback-is-indirect.js create mode 100644 js/src/tests/ecma_5/extensions/extension-methods-reject-null-undefined-this.js create mode 100644 js/src/tests/ecma_5/extensions/function-definition-with.js create mode 100644 js/src/tests/ecma_5/extensions/iterator-in-catch.js create mode 100644 js/src/tests/ecma_5/extensions/jstests.list create mode 100644 js/src/tests/ecma_5/extensions/nested-delete-name-in-evalcode.js create mode 100644 js/src/tests/ecma_5/extensions/proxy-strict.js create mode 100644 js/src/tests/ecma_5/extensions/regress-bug567606.js create mode 100644 js/src/tests/ecma_5/extensions/regress-bug607284.js create mode 100644 js/src/tests/ecma_5/extensions/regress-bug629723.js create mode 100644 js/src/tests/ecma_5/extensions/shell.js create mode 100644 js/src/tests/ecma_5/extensions/strict-function-statements.js create mode 100644 js/src/tests/ecma_5/extensions/strict-option-redeclared-parameter.js create mode 100644 js/src/tests/ecma_5/extensions/string-literal-getter-setter-decompilation.js create mode 100644 js/src/tests/ecma_5/extensions/uneval-strict-functions.js create mode 100644 js/src/tests/ecma_5/extensions/watch-array-length.js create mode 100644 js/src/tests/ecma_5/extensions/watch-inherited-property.js create mode 100644 js/src/tests/ecma_5/extensions/watch-replaced-setter.js create mode 100644 js/src/tests/ecma_5/extensions/watch-setter-become-setter.js create mode 100644 js/src/tests/ecma_5/extensions/watch-value-prop-becoming-setter.js create mode 100644 js/src/tests/ecma_5/extensions/watchpoint-deletes-JSPropertyOp-setter.js create mode 100644 js/src/tests/ecma_5/jstests.list create mode 100644 js/src/tests/ecma_5/misc/browser.js create mode 100644 js/src/tests/ecma_5/misc/builtin-methods-reject-null-undefined-this.js create mode 100644 js/src/tests/ecma_5/misc/enumerate-undefined.js create mode 100644 js/src/tests/ecma_5/misc/explicit-undefined-optional-argument.js create mode 100644 js/src/tests/ecma_5/misc/function-definition-eval.js create mode 100644 js/src/tests/ecma_5/misc/function-definition-evaluate.js create mode 100644 js/src/tests/ecma_5/misc/future-reserved-words.js create mode 100644 js/src/tests/ecma_5/misc/global-numeric-properties.js create mode 100644 js/src/tests/ecma_5/misc/jstests.list create mode 100644 js/src/tests/ecma_5/misc/redeclare-var-non-writable-property.js create mode 100644 js/src/tests/ecma_5/misc/regress-bug632003.js create mode 100644 js/src/tests/ecma_5/misc/shell.js create mode 100644 js/src/tests/ecma_5/misc/unwrapped-no-such-method.js create mode 100644 js/src/tests/ecma_5/shell.js create mode 100644 js/src/tests/ecma_5/strict/10.4.2.js create mode 100644 js/src/tests/ecma_5/strict/10.4.3.js create mode 100644 js/src/tests/ecma_5/strict/10.6.js create mode 100644 js/src/tests/ecma_5/strict/11.1.5.js create mode 100644 js/src/tests/ecma_5/strict/11.13.1.js create mode 100644 js/src/tests/ecma_5/strict/11.13.2.js create mode 100644 js/src/tests/ecma_5/strict/11.3.1.js create mode 100644 js/src/tests/ecma_5/strict/11.3.2.js create mode 100644 js/src/tests/ecma_5/strict/11.4.1.js create mode 100644 js/src/tests/ecma_5/strict/11.4.4.js create mode 100644 js/src/tests/ecma_5/strict/11.4.5.js create mode 100644 js/src/tests/ecma_5/strict/12.10.1.js create mode 100644 js/src/tests/ecma_5/strict/12.14.1.js create mode 100644 js/src/tests/ecma_5/strict/12.2.1.js create mode 100644 js/src/tests/ecma_5/strict/13.1.js create mode 100644 js/src/tests/ecma_5/strict/15.10.7.js create mode 100644 js/src/tests/ecma_5/strict/15.3.4.5.js create mode 100644 js/src/tests/ecma_5/strict/15.3.5.1.js create mode 100644 js/src/tests/ecma_5/strict/15.3.5.2.js create mode 100644 js/src/tests/ecma_5/strict/15.4.4.12.js create mode 100644 js/src/tests/ecma_5/strict/15.4.4.13.js create mode 100644 js/src/tests/ecma_5/strict/15.4.4.6.js create mode 100644 js/src/tests/ecma_5/strict/15.4.4.8.js create mode 100644 js/src/tests/ecma_5/strict/15.4.4.9.js create mode 100644 js/src/tests/ecma_5/strict/15.4.5.1.js create mode 100644 js/src/tests/ecma_5/strict/15.5.5.1.js create mode 100644 js/src/tests/ecma_5/strict/15.5.5.2.js create mode 100644 js/src/tests/ecma_5/strict/8.12.5.js create mode 100644 js/src/tests/ecma_5/strict/8.12.7.js create mode 100644 js/src/tests/ecma_5/strict/8.7.2.js create mode 100644 js/src/tests/ecma_5/strict/B.1.1.js create mode 100644 js/src/tests/ecma_5/strict/B.1.2.js create mode 100644 js/src/tests/ecma_5/strict/assign-to-callee-name.js create mode 100644 js/src/tests/ecma_5/strict/browser.js create mode 100644 js/src/tests/ecma_5/strict/directive-prologue-01.js create mode 100644 js/src/tests/ecma_5/strict/eval-variable-environment.js create mode 100644 js/src/tests/ecma_5/strict/function-name-arity.js create mode 100644 js/src/tests/ecma_5/strict/jstests.list create mode 100644 js/src/tests/ecma_5/strict/primitive-this-no-writeback.js create mode 100644 js/src/tests/ecma_5/strict/regress-532041.js create mode 100644 js/src/tests/ecma_5/strict/regress-532254.js create mode 100644 js/src/tests/ecma_5/strict/regress-599159.js create mode 100644 js/src/tests/ecma_5/strict/shell.js create mode 100644 js/src/tests/ecma_5/strict/strict-this-is-not-truthy.js create mode 100644 js/src/tests/ecma_5/strict/this-for-function-expression-recursion.js create mode 100644 js/src/tests/ecma_5/strict/unbrand-this.js create mode 100644 js/src/tests/ecma_5/template.js create mode 100755 js/src/tests/get-universe.sh create mode 100644 js/src/tests/importList.html create mode 100644 js/src/tests/importList.js create mode 100644 js/src/tests/js-test-driver-begin.js create mode 100644 js/src/tests/js-test-driver-end.js create mode 100644 js/src/tests/js-test-driver-quirks.html create mode 100644 js/src/tests/js-test-driver-standards.html create mode 100644 js/src/tests/js1_1/README create mode 100644 js/src/tests/js1_1/browser.js create mode 100644 js/src/tests/js1_1/jsref.js create mode 100644 js/src/tests/js1_1/jstests.list create mode 100644 js/src/tests/js1_1/regress/browser.js create mode 100644 js/src/tests/js1_1/regress/function-001.js create mode 100644 js/src/tests/js1_1/regress/jstests.list create mode 100644 js/src/tests/js1_1/regress/shell.js create mode 100644 js/src/tests/js1_1/shell.js create mode 100644 js/src/tests/js1_2/Array/array_split_1.js create mode 100644 js/src/tests/js1_2/Array/browser.js create mode 100644 js/src/tests/js1_2/Array/general1.js create mode 100644 js/src/tests/js1_2/Array/general2.js create mode 100644 js/src/tests/js1_2/Array/jstests.list create mode 100644 js/src/tests/js1_2/Array/shell.js create mode 100644 js/src/tests/js1_2/Array/slice.js create mode 100644 js/src/tests/js1_2/Array/splice1.js create mode 100644 js/src/tests/js1_2/Array/splice2.js create mode 100644 js/src/tests/js1_2/Array/tostring_1.js create mode 100644 js/src/tests/js1_2/Array/tostring_2.js create mode 100644 js/src/tests/js1_2/Objects/browser.js create mode 100644 js/src/tests/js1_2/Objects/jstests.list create mode 100644 js/src/tests/js1_2/Objects/shell.js create mode 100644 js/src/tests/js1_2/Objects/toString-001.js create mode 100644 js/src/tests/js1_2/README create mode 100644 js/src/tests/js1_2/String/browser.js create mode 100644 js/src/tests/js1_2/String/charCodeAt.js create mode 100644 js/src/tests/js1_2/String/concat.js create mode 100644 js/src/tests/js1_2/String/jstests.list create mode 100644 js/src/tests/js1_2/String/match.js create mode 100644 js/src/tests/js1_2/String/shell.js create mode 100644 js/src/tests/js1_2/String/slice.js create mode 100644 js/src/tests/js1_2/browser.js create mode 100644 js/src/tests/js1_2/function/Function_object.js create mode 100644 js/src/tests/js1_2/function/Number.js create mode 100644 js/src/tests/js1_2/function/String.js create mode 100644 js/src/tests/js1_2/function/browser.js create mode 100644 js/src/tests/js1_2/function/definition-1.js create mode 100644 js/src/tests/js1_2/function/function-001-n.js create mode 100644 js/src/tests/js1_2/function/jstests.list create mode 100644 js/src/tests/js1_2/function/length.js create mode 100644 js/src/tests/js1_2/function/nesting-1.js create mode 100644 js/src/tests/js1_2/function/nesting.js create mode 100644 js/src/tests/js1_2/function/regexparg-1.js create mode 100644 js/src/tests/js1_2/function/regexparg-2-n.js create mode 100644 js/src/tests/js1_2/function/shell.js create mode 100644 js/src/tests/js1_2/function/tostring-1.js create mode 100644 js/src/tests/js1_2/function/tostring-2.js create mode 100644 js/src/tests/js1_2/jsref.js create mode 100644 js/src/tests/js1_2/jstests.list create mode 100644 js/src/tests/js1_2/operator/browser.js create mode 100644 js/src/tests/js1_2/operator/equality.js create mode 100644 js/src/tests/js1_2/operator/jstests.list create mode 100644 js/src/tests/js1_2/operator/shell.js create mode 100644 js/src/tests/js1_2/operator/strictEquality.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_dollar_number.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_input.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_input_as_array.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_lastIndex.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_lastMatch.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_lastMatch_as_array.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_lastParen.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_lastParen_as_array.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_leftContext.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_leftContext_as_array.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_multiline.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_multiline_as_array.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_object.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_rightContext.js create mode 100644 js/src/tests/js1_2/regexp/RegExp_rightContext_as_array.js create mode 100644 js/src/tests/js1_2/regexp/alphanumeric.js create mode 100644 js/src/tests/js1_2/regexp/asterisk.js create mode 100644 js/src/tests/js1_2/regexp/backslash.js create mode 100644 js/src/tests/js1_2/regexp/backspace.js create mode 100644 js/src/tests/js1_2/regexp/beginLine.js create mode 100644 js/src/tests/js1_2/regexp/browser.js create mode 100644 js/src/tests/js1_2/regexp/character_class.js create mode 100644 js/src/tests/js1_2/regexp/compile.js create mode 100644 js/src/tests/js1_2/regexp/control_characters.js create mode 100644 js/src/tests/js1_2/regexp/digit.js create mode 100644 js/src/tests/js1_2/regexp/dot.js create mode 100644 js/src/tests/js1_2/regexp/endLine.js create mode 100644 js/src/tests/js1_2/regexp/everything.js create mode 100644 js/src/tests/js1_2/regexp/exec.js create mode 100644 js/src/tests/js1_2/regexp/flags.js create mode 100644 js/src/tests/js1_2/regexp/global.js create mode 100644 js/src/tests/js1_2/regexp/hexadecimal.js create mode 100644 js/src/tests/js1_2/regexp/ignoreCase.js create mode 100644 js/src/tests/js1_2/regexp/interval.js create mode 100644 js/src/tests/js1_2/regexp/jstests.list create mode 100644 js/src/tests/js1_2/regexp/octal.js create mode 100644 js/src/tests/js1_2/regexp/parentheses.js create mode 100644 js/src/tests/js1_2/regexp/plus.js create mode 100644 js/src/tests/js1_2/regexp/question_mark.js create mode 100644 js/src/tests/js1_2/regexp/regress-6359.js create mode 100644 js/src/tests/js1_2/regexp/regress-9141.js create mode 100644 js/src/tests/js1_2/regexp/shell.js create mode 100644 js/src/tests/js1_2/regexp/simple_form.js create mode 100644 js/src/tests/js1_2/regexp/source.js create mode 100644 js/src/tests/js1_2/regexp/special_characters.js create mode 100644 js/src/tests/js1_2/regexp/string_replace.js create mode 100644 js/src/tests/js1_2/regexp/string_search.js create mode 100644 js/src/tests/js1_2/regexp/string_split.js create mode 100644 js/src/tests/js1_2/regexp/test.js create mode 100644 js/src/tests/js1_2/regexp/toString.js create mode 100644 js/src/tests/js1_2/regexp/vertical_bar.js create mode 100644 js/src/tests/js1_2/regexp/whitespace.js create mode 100644 js/src/tests/js1_2/regexp/word_boundary.js create mode 100644 js/src/tests/js1_2/regress/browser.js create mode 100644 js/src/tests/js1_2/regress/jstests.list create mode 100644 js/src/tests/js1_2/regress/regress-144834.js create mode 100644 js/src/tests/js1_2/regress/regress-7703.js create mode 100644 js/src/tests/js1_2/regress/shell.js create mode 100644 js/src/tests/js1_2/shell.js create mode 100644 js/src/tests/js1_2/statements/break.js create mode 100644 js/src/tests/js1_2/statements/browser.js create mode 100644 js/src/tests/js1_2/statements/continue.js create mode 100644 js/src/tests/js1_2/statements/do_while.js create mode 100644 js/src/tests/js1_2/statements/jstests.list create mode 100644 js/src/tests/js1_2/statements/shell.js create mode 100644 js/src/tests/js1_2/statements/switch.js create mode 100644 js/src/tests/js1_2/statements/switch2.js create mode 100644 js/src/tests/js1_2/version120/boolean-001.js create mode 100644 js/src/tests/js1_2/version120/browser.js create mode 100644 js/src/tests/js1_2/version120/jstests.list create mode 100644 js/src/tests/js1_2/version120/regress-99663.js create mode 100644 js/src/tests/js1_2/version120/shell.js create mode 100644 js/src/tests/js1_3/Boolean/boolean-001.js create mode 100644 js/src/tests/js1_3/Boolean/browser.js create mode 100644 js/src/tests/js1_3/Boolean/jstests.list create mode 100644 js/src/tests/js1_3/Boolean/shell.js create mode 100644 js/src/tests/js1_3/README create mode 100644 js/src/tests/js1_3/Script/browser.js create mode 100644 js/src/tests/js1_3/Script/delete-001.js create mode 100644 js/src/tests/js1_3/Script/function-001-n.js create mode 100644 js/src/tests/js1_3/Script/function-002.js create mode 100644 js/src/tests/js1_3/Script/in-001.js create mode 100644 js/src/tests/js1_3/Script/jstests.list create mode 100644 js/src/tests/js1_3/Script/new-001.js create mode 100644 js/src/tests/js1_3/Script/shell.js create mode 100644 js/src/tests/js1_3/Script/switch-001.js create mode 100644 js/src/tests/js1_3/browser.js create mode 100644 js/src/tests/js1_3/extensions/browser.js create mode 100644 js/src/tests/js1_3/extensions/jstests.list create mode 100644 js/src/tests/js1_3/extensions/proto_10.js create mode 100644 js/src/tests/js1_3/extensions/proto_2.js create mode 100644 js/src/tests/js1_3/extensions/proto_5.js create mode 100644 js/src/tests/js1_3/extensions/script-001.js create mode 100644 js/src/tests/js1_3/extensions/shell.js create mode 100644 js/src/tests/js1_3/inherit/browser.js create mode 100644 js/src/tests/js1_3/inherit/jstests.list create mode 100644 js/src/tests/js1_3/inherit/proto_1.js create mode 100644 js/src/tests/js1_3/inherit/proto_10.js create mode 100644 js/src/tests/js1_3/inherit/proto_11.js create mode 100644 js/src/tests/js1_3/inherit/proto_12.js create mode 100644 js/src/tests/js1_3/inherit/proto_3.js create mode 100644 js/src/tests/js1_3/inherit/proto_4.js create mode 100644 js/src/tests/js1_3/inherit/proto_6.js create mode 100644 js/src/tests/js1_3/inherit/proto_7.js create mode 100644 js/src/tests/js1_3/inherit/proto_8.js create mode 100644 js/src/tests/js1_3/inherit/proto_9.js create mode 100644 js/src/tests/js1_3/inherit/shell.js create mode 100644 js/src/tests/js1_3/jsref.js create mode 100644 js/src/tests/js1_3/jstests.list create mode 100644 js/src/tests/js1_3/misc/browser.js create mode 100644 js/src/tests/js1_3/misc/jstests.list create mode 100644 js/src/tests/js1_3/misc/shell.js create mode 100644 js/src/tests/js1_3/regress/browser.js create mode 100644 js/src/tests/js1_3/regress/delete-001.js create mode 100644 js/src/tests/js1_3/regress/function-001-n.js create mode 100644 js/src/tests/js1_3/regress/function-002.js create mode 100644 js/src/tests/js1_3/regress/in-001.js create mode 100644 js/src/tests/js1_3/regress/jstests.list create mode 100644 js/src/tests/js1_3/regress/new-001.js create mode 100644 js/src/tests/js1_3/regress/shell.js create mode 100644 js/src/tests/js1_3/regress/switch-001.js create mode 100644 js/src/tests/js1_3/shell.js create mode 100644 js/src/tests/js1_4/Eval/browser.js create mode 100644 js/src/tests/js1_4/Eval/eval-001.js create mode 100644 js/src/tests/js1_4/Eval/eval-002.js create mode 100644 js/src/tests/js1_4/Eval/eval-003.js create mode 100644 js/src/tests/js1_4/Eval/jstests.list create mode 100644 js/src/tests/js1_4/Eval/regress-531682.js create mode 100644 js/src/tests/js1_4/Eval/shell.js create mode 100644 js/src/tests/js1_4/Functions/browser.js create mode 100644 js/src/tests/js1_4/Functions/function-001.js create mode 100644 js/src/tests/js1_4/Functions/jstests.list create mode 100644 js/src/tests/js1_4/Functions/shell.js create mode 100644 js/src/tests/js1_4/README create mode 100644 js/src/tests/js1_4/Regress/browser.js create mode 100644 js/src/tests/js1_4/Regress/date-001-n.js create mode 100644 js/src/tests/js1_4/Regress/function-001.js create mode 100644 js/src/tests/js1_4/Regress/function-002.js create mode 100644 js/src/tests/js1_4/Regress/function-003.js create mode 100644 js/src/tests/js1_4/Regress/function-004-n.js create mode 100644 js/src/tests/js1_4/Regress/jstests.list create mode 100644 js/src/tests/js1_4/Regress/regress-7224.js create mode 100644 js/src/tests/js1_4/Regress/shell.js create mode 100644 js/src/tests/js1_4/Regress/toString-001-n.js create mode 100644 js/src/tests/js1_4/browser.js create mode 100644 js/src/tests/js1_4/jsref.js create mode 100644 js/src/tests/js1_4/jstests.list create mode 100644 js/src/tests/js1_4/shell.js create mode 100644 js/src/tests/js1_5/Array/11.1.4.js create mode 100644 js/src/tests/js1_5/Array/array-001.js create mode 100644 js/src/tests/js1_5/Array/browser.js create mode 100644 js/src/tests/js1_5/Array/jstests.list create mode 100644 js/src/tests/js1_5/Array/regress-101964.js create mode 100644 js/src/tests/js1_5/Array/regress-107138.js create mode 100644 js/src/tests/js1_5/Array/regress-108440.js create mode 100644 js/src/tests/js1_5/Array/regress-154338.js create mode 100644 js/src/tests/js1_5/Array/regress-157652.js create mode 100644 js/src/tests/js1_5/Array/regress-178722.js create mode 100644 js/src/tests/js1_5/Array/regress-255555.js create mode 100644 js/src/tests/js1_5/Array/regress-299644.js create mode 100644 js/src/tests/js1_5/Array/regress-300858.js create mode 100644 js/src/tests/js1_5/Array/regress-310351.js create mode 100644 js/src/tests/js1_5/Array/regress-311515.js create mode 100644 js/src/tests/js1_5/Array/regress-313153.js create mode 100644 js/src/tests/js1_5/Array/regress-315509-01.js create mode 100644 js/src/tests/js1_5/Array/regress-330812.js create mode 100644 js/src/tests/js1_5/Array/regress-345961.js create mode 100644 js/src/tests/js1_5/Array/regress-348810.js create mode 100644 js/src/tests/js1_5/Array/regress-350256-01.js create mode 100644 js/src/tests/js1_5/Array/regress-350256-02.js create mode 100644 js/src/tests/js1_5/Array/regress-350256-03.js create mode 100644 js/src/tests/js1_5/Array/regress-360681-01.js create mode 100644 js/src/tests/js1_5/Array/regress-360681-02.js create mode 100644 js/src/tests/js1_5/Array/regress-364104.js create mode 100644 js/src/tests/js1_5/Array/regress-422286.js create mode 100644 js/src/tests/js1_5/Array/regress-424954.js create mode 100644 js/src/tests/js1_5/Array/regress-451483.js create mode 100644 js/src/tests/js1_5/Array/regress-451906.js create mode 100644 js/src/tests/js1_5/Array/regress-456845.js create mode 100755 js/src/tests/js1_5/Array/regress-465980-01.js create mode 100755 js/src/tests/js1_5/Array/regress-465980-02.js create mode 100755 js/src/tests/js1_5/Array/regress-474529.js create mode 100644 js/src/tests/js1_5/Array/regress-94257.js create mode 100644 js/src/tests/js1_5/Array/regress-99120-01.js create mode 100644 js/src/tests/js1_5/Array/regress-99120-02.js create mode 100644 js/src/tests/js1_5/Array/shell.js create mode 100644 js/src/tests/js1_5/Date/browser.js create mode 100644 js/src/tests/js1_5/Date/jstests.list create mode 100644 js/src/tests/js1_5/Date/regress-188211.js create mode 100644 js/src/tests/js1_5/Date/regress-301738-01.js create mode 100644 js/src/tests/js1_5/Date/regress-301738-02.js create mode 100644 js/src/tests/js1_5/Date/regress-309925-01.js create mode 100644 js/src/tests/js1_5/Date/regress-309925-02.js create mode 100644 js/src/tests/js1_5/Date/regress-346027.js create mode 100644 js/src/tests/js1_5/Date/regress-346363.js create mode 100644 js/src/tests/js1_5/Date/shell.js create mode 100644 js/src/tests/js1_5/Error/browser.js create mode 100644 js/src/tests/js1_5/Error/jstests.list create mode 100644 js/src/tests/js1_5/Error/regress-354246.js create mode 100644 js/src/tests/js1_5/Error/regress-412324.js create mode 100644 js/src/tests/js1_5/Error/regress-465377.js create mode 100644 js/src/tests/js1_5/Error/shell.js create mode 100644 js/src/tests/js1_5/Exceptions/browser.js create mode 100644 js/src/tests/js1_5/Exceptions/catchguard-002-n.js create mode 100644 js/src/tests/js1_5/Exceptions/catchguard-003-n.js create mode 100644 js/src/tests/js1_5/Exceptions/errstack-001.js create mode 100644 js/src/tests/js1_5/Exceptions/jstests.list create mode 100644 js/src/tests/js1_5/Exceptions/regress-121658.js create mode 100644 js/src/tests/js1_5/Exceptions/regress-123002.js create mode 100644 js/src/tests/js1_5/Exceptions/regress-232182.js create mode 100644 js/src/tests/js1_5/Exceptions/regress-257751.js create mode 100644 js/src/tests/js1_5/Exceptions/regress-273931.js create mode 100644 js/src/tests/js1_5/Exceptions/regress-315147.js create mode 100644 js/src/tests/js1_5/Exceptions/regress-332472.js create mode 100644 js/src/tests/js1_5/Exceptions/regress-333728.js create mode 100644 js/src/tests/js1_5/Exceptions/regress-342359.js create mode 100644 js/src/tests/js1_5/Exceptions/regress-347674.js create mode 100644 js/src/tests/js1_5/Exceptions/regress-350650-n.js create mode 100644 js/src/tests/js1_5/Exceptions/regress-350837.js create mode 100644 js/src/tests/js1_5/Exceptions/shell.js create mode 100644 js/src/tests/js1_5/Expressions/browser.js create mode 100644 js/src/tests/js1_5/Expressions/jstests.list create mode 100644 js/src/tests/js1_5/Expressions/regress-192288.js create mode 100644 js/src/tests/js1_5/Expressions/regress-394673.js create mode 100644 js/src/tests/js1_5/Expressions/regress-96526-argsub.js create mode 100644 js/src/tests/js1_5/Expressions/regress-96526-delelem.js create mode 100644 js/src/tests/js1_5/Expressions/regress-96526-noargsub.js create mode 100644 js/src/tests/js1_5/Expressions/shell.js create mode 100644 js/src/tests/js1_5/Function/10.1.6-01.js create mode 100644 js/src/tests/js1_5/Function/10.1.6.js create mode 100644 js/src/tests/js1_5/Function/15.3.4.4.js create mode 100644 js/src/tests/js1_5/Function/browser.js create mode 100644 js/src/tests/js1_5/Function/jstests.list create mode 100644 js/src/tests/js1_5/Function/regress-123371.js create mode 100644 js/src/tests/js1_5/Function/regress-178389.js create mode 100644 js/src/tests/js1_5/Function/regress-222029-001.js create mode 100644 js/src/tests/js1_5/Function/regress-222029-002.js create mode 100644 js/src/tests/js1_5/Function/regress-292215.js create mode 100644 js/src/tests/js1_5/Function/regress-338001.js create mode 100644 js/src/tests/js1_5/Function/regress-338121-01.js create mode 100644 js/src/tests/js1_5/Function/regress-338121-02.js create mode 100644 js/src/tests/js1_5/Function/regress-338121-03.js create mode 100644 js/src/tests/js1_5/Function/regress-344052.js create mode 100644 js/src/tests/js1_5/Function/regress-364023.js create mode 100644 js/src/tests/js1_5/Function/shell.js create mode 100644 js/src/tests/js1_5/GC/browser.js create mode 100644 js/src/tests/js1_5/GC/jstests.list create mode 100644 js/src/tests/js1_5/GC/regress-104584.js create mode 100644 js/src/tests/js1_5/GC/regress-203278-2.js create mode 100644 js/src/tests/js1_5/GC/regress-203278-3.js create mode 100644 js/src/tests/js1_5/GC/regress-278725.js create mode 100644 js/src/tests/js1_5/GC/regress-306788.js create mode 100644 js/src/tests/js1_5/GC/regress-311497.js create mode 100644 js/src/tests/js1_5/GC/regress-313276.js create mode 100644 js/src/tests/js1_5/GC/regress-313479.js create mode 100644 js/src/tests/js1_5/GC/regress-316885-01.js create mode 100644 js/src/tests/js1_5/GC/regress-316885-02.js create mode 100644 js/src/tests/js1_5/GC/regress-316885-03.js create mode 100644 js/src/tests/js1_5/GC/regress-319980-01.js create mode 100644 js/src/tests/js1_5/GC/regress-324278.js create mode 100644 js/src/tests/js1_5/GC/regress-331719.js create mode 100644 js/src/tests/js1_5/GC/regress-338653.js create mode 100644 js/src/tests/js1_5/GC/regress-341877-01.js create mode 100644 js/src/tests/js1_5/GC/regress-341877-02.js create mode 100644 js/src/tests/js1_5/GC/regress-346794.js create mode 100644 js/src/tests/js1_5/GC/regress-348532.js create mode 100644 js/src/tests/js1_5/GC/regress-352606.js create mode 100644 js/src/tests/js1_5/GC/regress-383269-01.js create mode 100644 js/src/tests/js1_5/GC/regress-383269-02.js create mode 100644 js/src/tests/js1_5/GC/regress-390078.js create mode 100644 js/src/tests/js1_5/GC/regress-418128.js create mode 100644 js/src/tests/js1_5/GC/regress-440558.js create mode 100644 js/src/tests/js1_5/GC/shell.js create mode 100644 js/src/tests/js1_5/GetSet/browser.js create mode 100644 js/src/tests/js1_5/GetSet/getset-002.js create mode 100644 js/src/tests/js1_5/GetSet/jstests.list create mode 100644 js/src/tests/js1_5/GetSet/regress-353264.js create mode 100644 js/src/tests/js1_5/GetSet/regress-375976.js create mode 100644 js/src/tests/js1_5/GetSet/shell.js create mode 100644 js/src/tests/js1_5/LexicalConventions/browser.js create mode 100644 js/src/tests/js1_5/LexicalConventions/jstests.list create mode 100644 js/src/tests/js1_5/LexicalConventions/lexical-001.js create mode 100644 js/src/tests/js1_5/LexicalConventions/regress-177314.js create mode 100644 js/src/tests/js1_5/LexicalConventions/regress-343675.js create mode 100644 js/src/tests/js1_5/LexicalConventions/regress-469940.js create mode 100644 js/src/tests/js1_5/LexicalConventions/shell.js create mode 100644 js/src/tests/js1_5/Object/browser.js create mode 100644 js/src/tests/js1_5/Object/jstests.list create mode 100644 js/src/tests/js1_5/Object/regress-137000.js create mode 100644 js/src/tests/js1_5/Object/regress-192105.js create mode 100644 js/src/tests/js1_5/Object/regress-308806-01.js create mode 100644 js/src/tests/js1_5/Object/regress-338709.js create mode 100644 js/src/tests/js1_5/Object/regress-362872-01.js create mode 100644 js/src/tests/js1_5/Object/regress-362872-02.js create mode 100644 js/src/tests/js1_5/Object/regress-382503.js create mode 100644 js/src/tests/js1_5/Object/regress-382532.js create mode 100644 js/src/tests/js1_5/Object/regress-465476.js create mode 100644 js/src/tests/js1_5/Object/regress-90596-003.js create mode 100644 js/src/tests/js1_5/Object/shell.js create mode 100644 js/src/tests/js1_5/README create mode 100644 js/src/tests/js1_5/Regress/browser.js create mode 100644 js/src/tests/js1_5/Regress/jstests.list create mode 100644 js/src/tests/js1_5/Regress/regress-102725.js create mode 100644 js/src/tests/js1_5/Regress/regress-10278.js create mode 100644 js/src/tests/js1_5/Regress/regress-103602.js create mode 100644 js/src/tests/js1_5/Regress/regress-104077.js create mode 100644 js/src/tests/js1_5/Regress/regress-106244.js create mode 100644 js/src/tests/js1_5/Regress/regress-110286.js create mode 100644 js/src/tests/js1_5/Regress/regress-111557.js create mode 100644 js/src/tests/js1_5/Regress/regress-114491.js create mode 100644 js/src/tests/js1_5/Regress/regress-114493.js create mode 100644 js/src/tests/js1_5/Regress/regress-115436.js create mode 100644 js/src/tests/js1_5/Regress/regress-116228.js create mode 100644 js/src/tests/js1_5/Regress/regress-118849.js create mode 100644 js/src/tests/js1_5/Regress/regress-119719.js create mode 100644 js/src/tests/js1_5/Regress/regress-127243.js create mode 100644 js/src/tests/js1_5/Regress/regress-127557.js create mode 100644 js/src/tests/js1_5/Regress/regress-131510-001.js create mode 100644 js/src/tests/js1_5/Regress/regress-139316.js create mode 100644 js/src/tests/js1_5/Regress/regress-140852.js create mode 100644 js/src/tests/js1_5/Regress/regress-140974.js create mode 100644 js/src/tests/js1_5/Regress/regress-146596.js create mode 100644 js/src/tests/js1_5/Regress/regress-152646.js create mode 100644 js/src/tests/js1_5/Regress/regress-155081-2.js create mode 100644 js/src/tests/js1_5/Regress/regress-155081.js create mode 100644 js/src/tests/js1_5/Regress/regress-156354.js create mode 100644 js/src/tests/js1_5/Regress/regress-159334.js create mode 100644 js/src/tests/js1_5/Regress/regress-162392.js create mode 100644 js/src/tests/js1_5/Regress/regress-165201.js create mode 100644 js/src/tests/js1_5/Regress/regress-167328.js create mode 100644 js/src/tests/js1_5/Regress/regress-167658.js create mode 100644 js/src/tests/js1_5/Regress/regress-168347.js create mode 100644 js/src/tests/js1_5/Regress/regress-169559.js create mode 100644 js/src/tests/js1_5/Regress/regress-170193.js create mode 100644 js/src/tests/js1_5/Regress/regress-172699.js create mode 100644 js/src/tests/js1_5/Regress/regress-173067.js create mode 100644 js/src/tests/js1_5/Regress/regress-174709.js create mode 100644 js/src/tests/js1_5/Regress/regress-176125.js create mode 100644 js/src/tests/js1_5/Regress/regress-179524.js create mode 100644 js/src/tests/js1_5/Regress/regress-185165.js create mode 100644 js/src/tests/js1_5/Regress/regress-191633.js create mode 100644 js/src/tests/js1_5/Regress/regress-191668.js create mode 100644 js/src/tests/js1_5/Regress/regress-192414.js create mode 100644 js/src/tests/js1_5/Regress/regress-193418.js create mode 100644 js/src/tests/js1_5/Regress/regress-203278-1.js create mode 100644 js/src/tests/js1_5/Regress/regress-203402.js create mode 100644 js/src/tests/js1_5/Regress/regress-203841.js create mode 100644 js/src/tests/js1_5/Regress/regress-204210.js create mode 100644 js/src/tests/js1_5/Regress/regress-210682.js create mode 100644 js/src/tests/js1_5/Regress/regress-211590.js create mode 100644 js/src/tests/js1_5/Regress/regress-213482.js create mode 100644 js/src/tests/js1_5/Regress/regress-214761.js create mode 100644 js/src/tests/js1_5/Regress/regress-216320.js create mode 100644 js/src/tests/js1_5/Regress/regress-224956.js create mode 100644 js/src/tests/js1_5/Regress/regress-229006.js create mode 100644 js/src/tests/js1_5/Regress/regress-230216-1.js create mode 100644 js/src/tests/js1_5/Regress/regress-230216-2.js create mode 100644 js/src/tests/js1_5/Regress/regress-230216-3.js create mode 100644 js/src/tests/js1_5/Regress/regress-233483-2.js create mode 100644 js/src/tests/js1_5/Regress/regress-233483.js create mode 100644 js/src/tests/js1_5/Regress/regress-234389.js create mode 100644 js/src/tests/js1_5/Regress/regress-238881.js create mode 100644 js/src/tests/js1_5/Regress/regress-238945.js create mode 100644 js/src/tests/js1_5/Regress/regress-240577.js create mode 100644 js/src/tests/js1_5/Regress/regress-243174.js create mode 100644 js/src/tests/js1_5/Regress/regress-243389-n.js create mode 100644 js/src/tests/js1_5/Regress/regress-243869.js create mode 100644 js/src/tests/js1_5/Regress/regress-244470.js create mode 100644 js/src/tests/js1_5/Regress/regress-244619.js create mode 100644 js/src/tests/js1_5/Regress/regress-245113.js create mode 100644 js/src/tests/js1_5/Regress/regress-245308.js create mode 100644 js/src/tests/js1_5/Regress/regress-246911.js create mode 100644 js/src/tests/js1_5/Regress/regress-246964.js create mode 100644 js/src/tests/js1_5/Regress/regress-247179.js create mode 100644 js/src/tests/js1_5/Regress/regress-248444.js create mode 100644 js/src/tests/js1_5/Regress/regress-249211.js create mode 100644 js/src/tests/js1_5/Regress/regress-252892.js create mode 100644 js/src/tests/js1_5/Regress/regress-253150.js create mode 100644 js/src/tests/js1_5/Regress/regress-254296.js create mode 100644 js/src/tests/js1_5/Regress/regress-254974.js create mode 100644 js/src/tests/js1_5/Regress/regress-256501.js create mode 100644 js/src/tests/js1_5/Regress/regress-256617.js create mode 100644 js/src/tests/js1_5/Regress/regress-256798.js create mode 100644 js/src/tests/js1_5/Regress/regress-259935.js create mode 100644 js/src/tests/js1_5/Regress/regress-260541.js create mode 100644 js/src/tests/js1_5/Regress/regress-261886.js create mode 100644 js/src/tests/js1_5/Regress/regress-261887.js create mode 100644 js/src/tests/js1_5/Regress/regress-271716-n.js create mode 100644 js/src/tests/js1_5/Regress/regress-274035.js create mode 100644 js/src/tests/js1_5/Regress/regress-274888.js create mode 100644 js/src/tests/js1_5/Regress/regress-275378.js create mode 100644 js/src/tests/js1_5/Regress/regress-276103.js create mode 100644 js/src/tests/js1_5/Regress/regress-278873.js create mode 100644 js/src/tests/js1_5/Regress/regress-280769-1.js create mode 100644 js/src/tests/js1_5/Regress/regress-280769-2.js create mode 100644 js/src/tests/js1_5/Regress/regress-280769-3.js create mode 100644 js/src/tests/js1_5/Regress/regress-280769-4.js create mode 100644 js/src/tests/js1_5/Regress/regress-280769-5.js create mode 100644 js/src/tests/js1_5/Regress/regress-280769.js create mode 100644 js/src/tests/js1_5/Regress/regress-281487.js create mode 100644 js/src/tests/js1_5/Regress/regress-281606.js create mode 100644 js/src/tests/js1_5/Regress/regress-281930.js create mode 100644 js/src/tests/js1_5/Regress/regress-283477.js create mode 100644 js/src/tests/js1_5/Regress/regress-286216.js create mode 100644 js/src/tests/js1_5/Regress/regress-288688.js create mode 100644 js/src/tests/js1_5/Regress/regress-289094.js create mode 100644 js/src/tests/js1_5/Regress/regress-290575.js create mode 100644 js/src/tests/js1_5/Regress/regress-290656.js create mode 100644 js/src/tests/js1_5/Regress/regress-294191.js create mode 100644 js/src/tests/js1_5/Regress/regress-294195-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-294195-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-294302.js create mode 100644 js/src/tests/js1_5/Regress/regress-295052.js create mode 100644 js/src/tests/js1_5/Regress/regress-295666.js create mode 100644 js/src/tests/js1_5/Regress/regress-299209.js create mode 100644 js/src/tests/js1_5/Regress/regress-299641.js create mode 100644 js/src/tests/js1_5/Regress/regress-303213.js create mode 100644 js/src/tests/js1_5/Regress/regress-306633.js create mode 100644 js/src/tests/js1_5/Regress/regress-306727.js create mode 100644 js/src/tests/js1_5/Regress/regress-306794.js create mode 100644 js/src/tests/js1_5/Regress/regress-308085.js create mode 100644 js/src/tests/js1_5/Regress/regress-308566.js create mode 100644 js/src/tests/js1_5/Regress/regress-309242.js create mode 100644 js/src/tests/js1_5/Regress/regress-310295.js create mode 100644 js/src/tests/js1_5/Regress/regress-310607.js create mode 100644 js/src/tests/js1_5/Regress/regress-310993.js create mode 100644 js/src/tests/js1_5/Regress/regress-311071.js create mode 100644 js/src/tests/js1_5/Regress/regress-311629.js create mode 100644 js/src/tests/js1_5/Regress/regress-312260.js create mode 100644 js/src/tests/js1_5/Regress/regress-31255.js create mode 100644 js/src/tests/js1_5/Regress/regress-312588.js create mode 100644 js/src/tests/js1_5/Regress/regress-313967-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-313967-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-314401.js create mode 100644 js/src/tests/js1_5/Regress/regress-315974.js create mode 100644 js/src/tests/js1_5/Regress/regress-315990.js create mode 100644 js/src/tests/js1_5/Regress/regress-317476.js create mode 100644 js/src/tests/js1_5/Regress/regress-317533.js create mode 100644 js/src/tests/js1_5/Regress/regress-317714-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-317714-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-319384.js create mode 100644 js/src/tests/js1_5/Regress/regress-319391.js create mode 100644 js/src/tests/js1_5/Regress/regress-320032.js create mode 100644 js/src/tests/js1_5/Regress/regress-320119.js create mode 100644 js/src/tests/js1_5/Regress/regress-321757.js create mode 100644 js/src/tests/js1_5/Regress/regress-321874.js create mode 100644 js/src/tests/js1_5/Regress/regress-321971.js create mode 100644 js/src/tests/js1_5/Regress/regress-322430.js create mode 100644 js/src/tests/js1_5/Regress/regress-323314-1.js create mode 100644 js/src/tests/js1_5/Regress/regress-325925.js create mode 100644 js/src/tests/js1_5/Regress/regress-326453.js create mode 100644 js/src/tests/js1_5/Regress/regress-326467.js create mode 100644 js/src/tests/js1_5/Regress/regress-328012.js create mode 100644 js/src/tests/js1_5/Regress/regress-328664.js create mode 100644 js/src/tests/js1_5/Regress/regress-328897.js create mode 100644 js/src/tests/js1_5/Regress/regress-329383.js create mode 100644 js/src/tests/js1_5/Regress/regress-329530.js create mode 100644 js/src/tests/js1_5/Regress/regress-330352.js create mode 100644 js/src/tests/js1_5/Regress/regress-330951.js create mode 100644 js/src/tests/js1_5/Regress/regress-334807-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-334807-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-334807-03.js create mode 100644 js/src/tests/js1_5/Regress/regress-334807-04.js create mode 100644 js/src/tests/js1_5/Regress/regress-334807-05.js create mode 100644 js/src/tests/js1_5/Regress/regress-334807-06.js create mode 100644 js/src/tests/js1_5/Regress/regress-336100.js create mode 100644 js/src/tests/js1_5/Regress/regress-338307.js create mode 100644 js/src/tests/js1_5/Regress/regress-340369.js create mode 100644 js/src/tests/js1_5/Regress/regress-341360.js create mode 100644 js/src/tests/js1_5/Regress/regress-343713.js create mode 100644 js/src/tests/js1_5/Regress/regress-343966.js create mode 100644 js/src/tests/js1_5/Regress/regress-344711-n.js create mode 100644 js/src/tests/js1_5/Regress/regress-344804.js create mode 100644 js/src/tests/js1_5/Regress/regress-344959.js create mode 100644 js/src/tests/js1_5/Regress/regress-346237.js create mode 100644 js/src/tests/js1_5/Regress/regress-346801.js create mode 100644 js/src/tests/js1_5/Regress/regress-347306-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-349482-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-349482-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-349592.js create mode 100644 js/src/tests/js1_5/Regress/regress-349648.js create mode 100644 js/src/tests/js1_5/Regress/regress-350253.js create mode 100644 js/src/tests/js1_5/Regress/regress-350268.js create mode 100644 js/src/tests/js1_5/Regress/regress-350312.js create mode 100644 js/src/tests/js1_5/Regress/regress-350415.js create mode 100644 js/src/tests/js1_5/Regress/regress-350529.js create mode 100644 js/src/tests/js1_5/Regress/regress-350692.js create mode 100644 js/src/tests/js1_5/Regress/regress-351116.js create mode 100644 js/src/tests/js1_5/Regress/regress-351515.js create mode 100644 js/src/tests/js1_5/Regress/regress-352009.js create mode 100644 js/src/tests/js1_5/Regress/regress-352197.js create mode 100644 js/src/tests/js1_5/Regress/regress-352208.js create mode 100644 js/src/tests/js1_5/Regress/regress-352604.js create mode 100644 js/src/tests/js1_5/Regress/regress-354924.js create mode 100644 js/src/tests/js1_5/Regress/regress-355341.js create mode 100644 js/src/tests/js1_5/Regress/regress-355344.js create mode 100644 js/src/tests/js1_5/Regress/regress-355556.js create mode 100755 js/src/tests/js1_5/Regress/regress-355829-01.js create mode 100755 js/src/tests/js1_5/Regress/regress-355829-02.js create mode 100755 js/src/tests/js1_5/Regress/regress-355829-03.js create mode 100644 js/src/tests/js1_5/Regress/regress-356250.js create mode 100644 js/src/tests/js1_5/Regress/regress-356693.js create mode 100644 js/src/tests/js1_5/Regress/regress-360969-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-360969-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-360969-03.js create mode 100644 js/src/tests/js1_5/Regress/regress-360969-04.js create mode 100644 js/src/tests/js1_5/Regress/regress-360969-05.js create mode 100644 js/src/tests/js1_5/Regress/regress-360969-06.js create mode 100644 js/src/tests/js1_5/Regress/regress-361467.js create mode 100644 js/src/tests/js1_5/Regress/regress-361617.js create mode 100644 js/src/tests/js1_5/Regress/regress-362583.js create mode 100644 js/src/tests/js1_5/Regress/regress-3649-n.js create mode 100644 js/src/tests/js1_5/Regress/regress-366122.js create mode 100644 js/src/tests/js1_5/Regress/regress-366468.js create mode 100644 js/src/tests/js1_5/Regress/regress-366601.js create mode 100644 js/src/tests/js1_5/Regress/regress-367561-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-367561-03.js create mode 100644 js/src/tests/js1_5/Regress/regress-372364.js create mode 100644 js/src/tests/js1_5/Regress/regress-379245.js create mode 100644 js/src/tests/js1_5/Regress/regress-383674.js create mode 100644 js/src/tests/js1_5/Regress/regress-383682.js create mode 100644 js/src/tests/js1_5/Regress/regress-385393-06.js create mode 100644 js/src/tests/js1_5/Regress/regress-387951-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-387951-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-387951-03.js create mode 100644 js/src/tests/js1_5/Regress/regress-39309.js create mode 100644 js/src/tests/js1_5/Regress/regress-396684.js create mode 100644 js/src/tests/js1_5/Regress/regress-398085-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-398085-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-398609.js create mode 100644 js/src/tests/js1_5/Regress/regress-404755.js create mode 100644 js/src/tests/js1_5/Regress/regress-406769.js create mode 100644 js/src/tests/js1_5/Regress/regress-407024.js create mode 100644 js/src/tests/js1_5/Regress/regress-407323.js create mode 100644 js/src/tests/js1_5/Regress/regress-407957.js create mode 100644 js/src/tests/js1_5/Regress/regress-410852.js create mode 100644 js/src/tests/js1_5/Regress/regress-416628.js create mode 100644 js/src/tests/js1_5/Regress/regress-416737-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-416737-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-417893.js create mode 100644 js/src/tests/js1_5/Regress/regress-418504.js create mode 100644 js/src/tests/js1_5/Regress/regress-418540.js create mode 100644 js/src/tests/js1_5/Regress/regress-419018.js create mode 100644 js/src/tests/js1_5/Regress/regress-419803.js create mode 100644 js/src/tests/js1_5/Regress/regress-420919.js create mode 100644 js/src/tests/js1_5/Regress/regress-422348.js create mode 100644 js/src/tests/js1_5/Regress/regress-424311.js create mode 100644 js/src/tests/js1_5/Regress/regress-425360.js create mode 100644 js/src/tests/js1_5/Regress/regress-426827.js create mode 100644 js/src/tests/js1_5/Regress/regress-428366.js create mode 100644 js/src/tests/js1_5/Regress/regress-438415-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-438415-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-440926.js create mode 100644 js/src/tests/js1_5/Regress/regress-449627.js create mode 100644 js/src/tests/js1_5/Regress/regress-449666.js create mode 100644 js/src/tests/js1_5/Regress/regress-450369.js create mode 100644 js/src/tests/js1_5/Regress/regress-450833.js create mode 100755 js/src/tests/js1_5/Regress/regress-451322.js create mode 100644 js/src/tests/js1_5/Regress/regress-451884.js create mode 100644 js/src/tests/js1_5/Regress/regress-451946.js create mode 100644 js/src/tests/js1_5/Regress/regress-452008.js create mode 100644 js/src/tests/js1_5/Regress/regress-452170.js create mode 100644 js/src/tests/js1_5/Regress/regress-452189.js create mode 100644 js/src/tests/js1_5/Regress/regress-452333.js create mode 100644 js/src/tests/js1_5/Regress/regress-452336.js create mode 100644 js/src/tests/js1_5/Regress/regress-452346.js create mode 100644 js/src/tests/js1_5/Regress/regress-452495.js create mode 100644 js/src/tests/js1_5/Regress/regress-452573-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-452573-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-452713.js create mode 100644 js/src/tests/js1_5/Regress/regress-452724-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-452724-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-452742-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-452742-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-452853.js create mode 100644 js/src/tests/js1_5/Regress/regress-452884-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-452884-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-453024.js create mode 100644 js/src/tests/js1_5/Regress/regress-453173.js create mode 100644 js/src/tests/js1_5/Regress/regress-453397.js create mode 100644 js/src/tests/js1_5/Regress/regress-453701.js create mode 100644 js/src/tests/js1_5/Regress/regress-453747.js create mode 100644 js/src/tests/js1_5/Regress/regress-454682.js create mode 100644 js/src/tests/js1_5/Regress/regress-454981.js create mode 100644 js/src/tests/js1_5/Regress/regress-455605.js create mode 100644 js/src/tests/js1_5/Regress/regress-455748.js create mode 100644 js/src/tests/js1_5/Regress/regress-455758-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-455758-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-455775.js create mode 100644 js/src/tests/js1_5/Regress/regress-456470.js create mode 100644 js/src/tests/js1_5/Regress/regress-456477-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-456477-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-456494.js create mode 100644 js/src/tests/js1_5/Regress/regress-456540-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-456540-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-457065-03.js create mode 100644 js/src/tests/js1_5/Regress/regress-457456.js create mode 100644 js/src/tests/js1_5/Regress/regress-457778.js create mode 100644 js/src/tests/js1_5/Regress/regress-458851.js create mode 100644 js/src/tests/js1_5/Regress/regress-459085.js create mode 100644 js/src/tests/js1_5/Regress/regress-459628.js create mode 100644 js/src/tests/js1_5/Regress/regress-459990.js create mode 100644 js/src/tests/js1_5/Regress/regress-460024.js create mode 100644 js/src/tests/js1_5/Regress/regress-460117.js create mode 100755 js/src/tests/js1_5/Regress/regress-460886-01.js create mode 100755 js/src/tests/js1_5/Regress/regress-460886-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-461307.js create mode 100644 js/src/tests/js1_5/Regress/regress-461723.js create mode 100644 js/src/tests/js1_5/Regress/regress-462292.js create mode 100644 js/src/tests/js1_5/Regress/regress-462879.js create mode 100644 js/src/tests/js1_5/Regress/regress-462989.js create mode 100644 js/src/tests/js1_5/Regress/regress-463259.js create mode 100644 js/src/tests/js1_5/Regress/regress-463782.js create mode 100644 js/src/tests/js1_5/Regress/regress-464334.js create mode 100644 js/src/tests/js1_5/Regress/regress-464862.js create mode 100644 js/src/tests/js1_5/Regress/regress-465013.js create mode 100644 js/src/tests/js1_5/Regress/regress-465132.js create mode 100644 js/src/tests/js1_5/Regress/regress-465133.js create mode 100644 js/src/tests/js1_5/Regress/regress-465135.js create mode 100644 js/src/tests/js1_5/Regress/regress-465136.js create mode 100644 js/src/tests/js1_5/Regress/regress-465137.js create mode 100644 js/src/tests/js1_5/Regress/regress-465262.js create mode 100644 js/src/tests/js1_5/Regress/regress-465272.js create mode 100644 js/src/tests/js1_5/Regress/regress-465347.js create mode 100644 js/src/tests/js1_5/Regress/regress-465366.js create mode 100644 js/src/tests/js1_5/Regress/regress-466262.js create mode 100644 js/src/tests/js1_5/Regress/regress-466747.js create mode 100644 js/src/tests/js1_5/Regress/regress-469044.js create mode 100644 js/src/tests/js1_5/Regress/regress-470061.js create mode 100644 js/src/tests/js1_5/Regress/regress-470187-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-470187-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-470758-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-470758-02.js create mode 100755 js/src/tests/js1_5/Regress/regress-472533.js create mode 100644 js/src/tests/js1_5/Regress/regress-475645-01.js create mode 100644 js/src/tests/js1_5/Regress/regress-475645-02.js create mode 100644 js/src/tests/js1_5/Regress/regress-476049.js create mode 100644 js/src/tests/js1_5/Regress/regress-476192.js create mode 100644 js/src/tests/js1_5/Regress/regress-477733.js create mode 100644 js/src/tests/js1_5/Regress/regress-477758.js create mode 100644 js/src/tests/js1_5/Regress/regress-478314.js create mode 100644 js/src/tests/js1_5/Regress/regress-479353.js create mode 100644 js/src/tests/js1_5/Regress/regress-480147.js create mode 100644 js/src/tests/js1_5/Regress/regress-480244.js create mode 100755 js/src/tests/js1_5/Regress/regress-481436.js create mode 100644 js/src/tests/js1_5/Regress/regress-482421.js create mode 100755 js/src/tests/js1_5/Regress/regress-482783.js create mode 100644 js/src/tests/js1_5/Regress/regress-483103.js create mode 100755 js/src/tests/js1_5/Regress/regress-501124.js create mode 100644 js/src/tests/js1_5/Regress/regress-503860.js create mode 100644 js/src/tests/js1_5/Regress/regress-504078.js create mode 100644 js/src/tests/js1_5/Regress/regress-506567.js create mode 100644 js/src/tests/js1_5/Regress/regress-511859.js create mode 100644 js/src/tests/js1_5/Regress/regress-57043.js create mode 100644 js/src/tests/js1_5/Regress/regress-58116.js create mode 100644 js/src/tests/js1_5/Regress/regress-68498-001.js create mode 100644 js/src/tests/js1_5/Regress/regress-68498-002.js create mode 100644 js/src/tests/js1_5/Regress/regress-68498-003.js create mode 100644 js/src/tests/js1_5/Regress/regress-68498-004.js create mode 100644 js/src/tests/js1_5/Regress/regress-69607.js create mode 100644 js/src/tests/js1_5/Regress/regress-71107.js create mode 100644 js/src/tests/js1_5/Regress/regress-76054.js create mode 100644 js/src/tests/js1_5/Regress/regress-80981.js create mode 100644 js/src/tests/js1_5/Regress/regress-82306.js create mode 100644 js/src/tests/js1_5/Regress/regress-89443.js create mode 100644 js/src/tests/js1_5/Regress/regress-89474.js create mode 100644 js/src/tests/js1_5/Regress/regress-90445.js create mode 100644 js/src/tests/js1_5/Regress/regress-96128-n.js create mode 100644 js/src/tests/js1_5/Regress/regress-96526-001.js create mode 100644 js/src/tests/js1_5/Regress/regress-96526-002.js create mode 100644 js/src/tests/js1_5/Regress/regress-96526-003.js create mode 100644 js/src/tests/js1_5/Regress/regress-98901.js create mode 100644 js/src/tests/js1_5/Regress/shell.js create mode 100644 js/src/tests/js1_5/Scope/browser.js create mode 100644 js/src/tests/js1_5/Scope/jstests.list create mode 100644 js/src/tests/js1_5/Scope/regress-154693.js create mode 100644 js/src/tests/js1_5/Scope/regress-181834.js create mode 100644 js/src/tests/js1_5/Scope/regress-184107.js create mode 100644 js/src/tests/js1_5/Scope/regress-185485.js create mode 100644 js/src/tests/js1_5/Scope/regress-191276.js create mode 100644 js/src/tests/js1_5/Scope/regress-192226.js create mode 100644 js/src/tests/js1_5/Scope/regress-202678-001.js create mode 100644 js/src/tests/js1_5/Scope/regress-202678-002.js create mode 100644 js/src/tests/js1_5/Scope/regress-208496-001.js create mode 100644 js/src/tests/js1_5/Scope/regress-208496-002.js create mode 100644 js/src/tests/js1_5/Scope/regress-220362.js create mode 100644 js/src/tests/js1_5/Scope/regress-446026-01.js create mode 100644 js/src/tests/js1_5/Scope/regress-446026-02.js create mode 100644 js/src/tests/js1_5/Scope/regress-77578-001.js create mode 100644 js/src/tests/js1_5/Scope/scope-002.js create mode 100644 js/src/tests/js1_5/Scope/scope-003.js create mode 100644 js/src/tests/js1_5/Scope/scope-004.js create mode 100644 js/src/tests/js1_5/Scope/shell.js create mode 100644 js/src/tests/js1_5/String/browser.js create mode 100644 js/src/tests/js1_5/String/jstests.list create mode 100644 js/src/tests/js1_5/String/regress-107771.js create mode 100644 js/src/tests/js1_5/String/regress-112626.js create mode 100644 js/src/tests/js1_5/String/regress-157334-01.js create mode 100644 js/src/tests/js1_5/String/regress-179068.js create mode 100644 js/src/tests/js1_5/String/regress-314890.js create mode 100644 js/src/tests/js1_5/String/regress-322772.js create mode 100644 js/src/tests/js1_5/String/regress-56940-01.js create mode 100644 js/src/tests/js1_5/String/regress-56940-02.js create mode 100644 js/src/tests/js1_5/String/shell.js create mode 100644 js/src/tests/js1_5/browser.js create mode 100644 js/src/tests/js1_5/decompilation/browser.js create mode 100644 js/src/tests/js1_5/decompilation/jstests.list create mode 100644 js/src/tests/js1_5/decompilation/regress-344120.js create mode 100644 js/src/tests/js1_5/decompilation/regress-346892.js create mode 100644 js/src/tests/js1_5/decompilation/regress-346902.js create mode 100644 js/src/tests/js1_5/decompilation/regress-346904.js create mode 100644 js/src/tests/js1_5/decompilation/regress-346915.js create mode 100644 js/src/tests/js1_5/decompilation/regress-349484.js create mode 100644 js/src/tests/js1_5/decompilation/regress-349489.js create mode 100644 js/src/tests/js1_5/decompilation/regress-349491.js create mode 100644 js/src/tests/js1_5/decompilation/regress-349596.js create mode 100644 js/src/tests/js1_5/decompilation/regress-349650.js create mode 100644 js/src/tests/js1_5/decompilation/regress-349663.js create mode 100644 js/src/tests/js1_5/decompilation/regress-350242.js create mode 100644 js/src/tests/js1_5/decompilation/regress-350263.js create mode 100644 js/src/tests/js1_5/decompilation/regress-350271.js create mode 100644 js/src/tests/js1_5/decompilation/regress-350666.js create mode 100644 js/src/tests/js1_5/decompilation/regress-350670.js create mode 100644 js/src/tests/js1_5/decompilation/regress-351104.js create mode 100644 js/src/tests/js1_5/decompilation/regress-351219.js create mode 100644 js/src/tests/js1_5/decompilation/regress-351336.js create mode 100644 js/src/tests/js1_5/decompilation/regress-351597.js create mode 100644 js/src/tests/js1_5/decompilation/regress-351625.js create mode 100644 js/src/tests/js1_5/decompilation/regress-351626.js create mode 100644 js/src/tests/js1_5/decompilation/regress-351693.js create mode 100644 js/src/tests/js1_5/decompilation/regress-351705.js create mode 100644 js/src/tests/js1_5/decompilation/regress-351793.js create mode 100644 js/src/tests/js1_5/decompilation/regress-352013.js create mode 100644 js/src/tests/js1_5/decompilation/regress-352022.js create mode 100644 js/src/tests/js1_5/decompilation/regress-352073.js create mode 100644 js/src/tests/js1_5/decompilation/regress-352202.js create mode 100644 js/src/tests/js1_5/decompilation/regress-352312.js create mode 100644 js/src/tests/js1_5/decompilation/regress-352360.js create mode 100644 js/src/tests/js1_5/decompilation/regress-352375.js create mode 100644 js/src/tests/js1_5/decompilation/regress-352453.js create mode 100644 js/src/tests/js1_5/decompilation/regress-352649.js create mode 100644 js/src/tests/js1_5/decompilation/regress-352873-01.js create mode 100644 js/src/tests/js1_5/decompilation/regress-352873-02.js create mode 100644 js/src/tests/js1_5/decompilation/regress-353000.js create mode 100644 js/src/tests/js1_5/decompilation/regress-353120.js create mode 100644 js/src/tests/js1_5/decompilation/regress-353146.js create mode 100644 js/src/tests/js1_5/decompilation/regress-354878.js create mode 100644 js/src/tests/js1_5/decompilation/regress-354910.js create mode 100644 js/src/tests/js1_5/decompilation/regress-356083.js create mode 100644 js/src/tests/js1_5/decompilation/regress-371692.js create mode 100644 js/src/tests/js1_5/decompilation/regress-373678.js create mode 100644 js/src/tests/js1_5/decompilation/regress-375639.js create mode 100644 js/src/tests/js1_5/decompilation/regress-375882.js create mode 100644 js/src/tests/js1_5/decompilation/regress-376564.js create mode 100644 js/src/tests/js1_5/decompilation/regress-383721.js create mode 100644 js/src/tests/js1_5/decompilation/regress-406555.js create mode 100644 js/src/tests/js1_5/decompilation/regress-437288-02.js create mode 100644 js/src/tests/js1_5/decompilation/regress-443071-01.js create mode 100644 js/src/tests/js1_5/decompilation/regress-456964-01.js create mode 100644 js/src/tests/js1_5/decompilation/regress-457093-01.js create mode 100644 js/src/tests/js1_5/decompilation/regress-457824.js create mode 100644 js/src/tests/js1_5/decompilation/regress-460116-01.js create mode 100644 js/src/tests/js1_5/decompilation/regress-460116-02.js create mode 100644 js/src/tests/js1_5/decompilation/regress-460116-03.js create mode 100644 js/src/tests/js1_5/decompilation/regress-460501.js create mode 100644 js/src/tests/js1_5/decompilation/regress-460870.js create mode 100644 js/src/tests/js1_5/decompilation/regress-461108.js create mode 100644 js/src/tests/js1_5/decompilation/regress-461110.js create mode 100644 js/src/tests/js1_5/decompilation/regress-461111.js create mode 100644 js/src/tests/js1_5/decompilation/shell.js create mode 100644 js/src/tests/js1_5/extensions/browser.js create mode 100644 js/src/tests/js1_5/extensions/catchguard-001-n.js create mode 100644 js/src/tests/js1_5/extensions/catchguard-001.js create mode 100644 js/src/tests/js1_5/extensions/catchguard-002.js create mode 100644 js/src/tests/js1_5/extensions/catchguard-003.js create mode 100644 js/src/tests/js1_5/extensions/getset-001.js create mode 100644 js/src/tests/js1_5/extensions/getset-003.js create mode 100644 js/src/tests/js1_5/extensions/getset-004.js create mode 100644 js/src/tests/js1_5/extensions/getset-005.js create mode 100644 js/src/tests/js1_5/extensions/getset-006.js create mode 100644 js/src/tests/js1_5/extensions/jstests.list create mode 100644 js/src/tests/js1_5/extensions/no-such-method.js create mode 100644 js/src/tests/js1_5/extensions/regress-104077.js create mode 100644 js/src/tests/js1_5/extensions/regress-164697.js create mode 100644 js/src/tests/js1_5/extensions/regress-178722.js create mode 100644 js/src/tests/js1_5/extensions/regress-192465.js create mode 100644 js/src/tests/js1_5/extensions/regress-225831.js create mode 100644 js/src/tests/js1_5/extensions/regress-226078.js create mode 100644 js/src/tests/js1_5/extensions/regress-226507.js create mode 100644 js/src/tests/js1_5/extensions/regress-231518.js create mode 100644 js/src/tests/js1_5/extensions/regress-237461.js create mode 100644 js/src/tests/js1_5/extensions/regress-245148.js create mode 100644 js/src/tests/js1_5/extensions/regress-245795.js create mode 100644 js/src/tests/js1_5/extensions/regress-254375.js create mode 100644 js/src/tests/js1_5/extensions/regress-255245.js create mode 100644 js/src/tests/js1_5/extensions/regress-291213.js create mode 100644 js/src/tests/js1_5/extensions/regress-300079.js create mode 100644 js/src/tests/js1_5/extensions/regress-303277.js create mode 100644 js/src/tests/js1_5/extensions/regress-304897.js create mode 100644 js/src/tests/js1_5/extensions/regress-306738.js create mode 100644 js/src/tests/js1_5/extensions/regress-311161.js create mode 100644 js/src/tests/js1_5/extensions/regress-311583.js create mode 100644 js/src/tests/js1_5/extensions/regress-311792-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-311792-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-313763.js create mode 100644 js/src/tests/js1_5/extensions/regress-313803.js create mode 100644 js/src/tests/js1_5/extensions/regress-313938.js create mode 100644 js/src/tests/js1_5/extensions/regress-314874.js create mode 100644 js/src/tests/js1_5/extensions/regress-315509-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-319683.js create mode 100644 js/src/tests/js1_5/extensions/regress-322957.js create mode 100644 js/src/tests/js1_5/extensions/regress-327608.js create mode 100644 js/src/tests/js1_5/extensions/regress-328443.js create mode 100644 js/src/tests/js1_5/extensions/regress-328556.js create mode 100644 js/src/tests/js1_5/extensions/regress-330569.js create mode 100644 js/src/tests/js1_5/extensions/regress-333541.js create mode 100644 js/src/tests/js1_5/extensions/regress-335700.js create mode 100644 js/src/tests/js1_5/extensions/regress-336409-1.js create mode 100644 js/src/tests/js1_5/extensions/regress-336409-2.js create mode 100644 js/src/tests/js1_5/extensions/regress-336410-1.js create mode 100644 js/src/tests/js1_5/extensions/regress-336410-2.js create mode 100644 js/src/tests/js1_5/extensions/regress-338804-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-338804-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-338804-03.js create mode 100644 js/src/tests/js1_5/extensions/regress-339685.js create mode 100644 js/src/tests/js1_5/extensions/regress-341956-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-341956-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-341956-03.js create mode 100644 js/src/tests/js1_5/extensions/regress-342960.js create mode 100644 js/src/tests/js1_5/extensions/regress-345967.js create mode 100644 js/src/tests/js1_5/extensions/regress-346494-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-346494.js create mode 100644 js/src/tests/js1_5/extensions/regress-347306-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-348986.js create mode 100644 js/src/tests/js1_5/extensions/regress-350312-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-350312-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-350312-03.js create mode 100644 js/src/tests/js1_5/extensions/regress-350531.js create mode 100644 js/src/tests/js1_5/extensions/regress-351102-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-351102-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-351102-06.js create mode 100644 js/src/tests/js1_5/extensions/regress-351448.js create mode 100644 js/src/tests/js1_5/extensions/regress-351463-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-351973.js create mode 100644 js/src/tests/js1_5/extensions/regress-352261.js create mode 100644 js/src/tests/js1_5/extensions/regress-352281.js create mode 100644 js/src/tests/js1_5/extensions/regress-352291.js create mode 100644 js/src/tests/js1_5/extensions/regress-352372.js create mode 100644 js/src/tests/js1_5/extensions/regress-352604.js create mode 100644 js/src/tests/js1_5/extensions/regress-353214.js create mode 100644 js/src/tests/js1_5/extensions/regress-354297.js create mode 100644 js/src/tests/js1_5/extensions/regress-354541-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-354541-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-354541-03.js create mode 100644 js/src/tests/js1_5/extensions/regress-354541-04.js create mode 100644 js/src/tests/js1_5/extensions/regress-355339.js create mode 100644 js/src/tests/js1_5/extensions/regress-355497.js create mode 100644 js/src/tests/js1_5/extensions/regress-355622.js create mode 100644 js/src/tests/js1_5/extensions/regress-355655.js create mode 100644 js/src/tests/js1_5/extensions/regress-355736.js create mode 100644 js/src/tests/js1_5/extensions/regress-355820.js create mode 100644 js/src/tests/js1_5/extensions/regress-355982.js create mode 100644 js/src/tests/js1_5/extensions/regress-356402.js create mode 100644 js/src/tests/js1_5/extensions/regress-358594-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-358594-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-358594-03.js create mode 100644 js/src/tests/js1_5/extensions/regress-358594-04.js create mode 100644 js/src/tests/js1_5/extensions/regress-358594-05.js create mode 100644 js/src/tests/js1_5/extensions/regress-358594-06.js create mode 100644 js/src/tests/js1_5/extensions/regress-359024.js create mode 100644 js/src/tests/js1_5/extensions/regress-361346.js create mode 100644 js/src/tests/js1_5/extensions/regress-361360.js create mode 100644 js/src/tests/js1_5/extensions/regress-361552.js create mode 100644 js/src/tests/js1_5/extensions/regress-361558.js create mode 100644 js/src/tests/js1_5/extensions/regress-361571.js create mode 100644 js/src/tests/js1_5/extensions/regress-361856.js create mode 100644 js/src/tests/js1_5/extensions/regress-361964.js create mode 100644 js/src/tests/js1_5/extensions/regress-363258.js create mode 100644 js/src/tests/js1_5/extensions/regress-363988.js create mode 100644 js/src/tests/js1_5/extensions/regress-365527.js create mode 100644 js/src/tests/js1_5/extensions/regress-365692.js create mode 100644 js/src/tests/js1_5/extensions/regress-365869.js create mode 100644 js/src/tests/js1_5/extensions/regress-366288.js create mode 100644 js/src/tests/js1_5/extensions/regress-366292.js create mode 100644 js/src/tests/js1_5/extensions/regress-366396.js create mode 100644 js/src/tests/js1_5/extensions/regress-367118-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-367118-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-367119-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-367119-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-367120-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-367120-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-367121.js create mode 100644 js/src/tests/js1_5/extensions/regress-367501-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-367501-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-367501-03.js create mode 100644 js/src/tests/js1_5/extensions/regress-367501-04.js create mode 100644 js/src/tests/js1_5/extensions/regress-367589.js create mode 100644 js/src/tests/js1_5/extensions/regress-367630.js create mode 100644 js/src/tests/js1_5/extensions/regress-367923.js create mode 100644 js/src/tests/js1_5/extensions/regress-368859.js create mode 100644 js/src/tests/js1_5/extensions/regress-369404.js create mode 100755 js/src/tests/js1_5/extensions/regress-369696-01.js create mode 100755 js/src/tests/js1_5/extensions/regress-369696-02.js create mode 100755 js/src/tests/js1_5/extensions/regress-369696-03.js create mode 100644 js/src/tests/js1_5/extensions/regress-371636.js create mode 100644 js/src/tests/js1_5/extensions/regress-372309.js create mode 100644 js/src/tests/js1_5/extensions/regress-374589.js create mode 100644 js/src/tests/js1_5/extensions/regress-375183.js create mode 100644 js/src/tests/js1_5/extensions/regress-375344.js create mode 100644 js/src/tests/js1_5/extensions/regress-375801.js create mode 100644 js/src/tests/js1_5/extensions/regress-376052.js create mode 100644 js/src/tests/js1_5/extensions/regress-379523.js create mode 100644 js/src/tests/js1_5/extensions/regress-380581.js create mode 100644 js/src/tests/js1_5/extensions/regress-380889.js create mode 100644 js/src/tests/js1_5/extensions/regress-381211.js create mode 100644 js/src/tests/js1_5/extensions/regress-381304.js create mode 100644 js/src/tests/js1_5/extensions/regress-384680.js create mode 100644 js/src/tests/js1_5/extensions/regress-385134.js create mode 100644 js/src/tests/js1_5/extensions/regress-385393-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-385393-09.js create mode 100644 js/src/tests/js1_5/extensions/regress-390597.js create mode 100755 js/src/tests/js1_5/extensions/regress-390598.js create mode 100644 js/src/tests/js1_5/extensions/regress-394967.js create mode 100644 js/src/tests/js1_5/extensions/regress-396326.js create mode 100644 js/src/tests/js1_5/extensions/regress-406572.js create mode 100644 js/src/tests/js1_5/extensions/regress-407019.js create mode 100644 js/src/tests/js1_5/extensions/regress-407501.js create mode 100644 js/src/tests/js1_5/extensions/regress-407720.js create mode 100644 js/src/tests/js1_5/extensions/regress-412926.js create mode 100644 js/src/tests/js1_5/extensions/regress-414755.js create mode 100644 js/src/tests/js1_5/extensions/regress-416354.js create mode 100644 js/src/tests/js1_5/extensions/regress-416460.js create mode 100644 js/src/tests/js1_5/extensions/regress-416834.js create mode 100644 js/src/tests/js1_5/extensions/regress-418730.js create mode 100644 js/src/tests/js1_5/extensions/regress-420612.js create mode 100644 js/src/tests/js1_5/extensions/regress-420869-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-421621.js create mode 100644 js/src/tests/js1_5/extensions/regress-422137.js create mode 100644 js/src/tests/js1_5/extensions/regress-422592.js create mode 100644 js/src/tests/js1_5/extensions/regress-424683-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-426711.js create mode 100755 js/src/tests/js1_5/extensions/regress-427196-01.js create mode 100755 js/src/tests/js1_5/extensions/regress-427196-02.js create mode 100755 js/src/tests/js1_5/extensions/regress-427196-03.js create mode 100644 js/src/tests/js1_5/extensions/regress-429264.js create mode 100755 js/src/tests/js1_5/extensions/regress-429739.js create mode 100644 js/src/tests/js1_5/extensions/regress-431428.js create mode 100644 js/src/tests/js1_5/extensions/regress-432075.js create mode 100644 js/src/tests/js1_5/extensions/regress-434837-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-435345-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-435497-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-435497-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-435497-03.js create mode 100644 js/src/tests/js1_5/extensions/regress-436741.js create mode 100644 js/src/tests/js1_5/extensions/regress-437288-01.js create mode 100644 js/src/tests/js1_5/extensions/regress-44009.js create mode 100644 js/src/tests/js1_5/extensions/regress-443569.js create mode 100644 js/src/tests/js1_5/extensions/regress-446386.js create mode 100644 js/src/tests/js1_5/extensions/regress-452168.js create mode 100644 js/src/tests/js1_5/extensions/regress-452178.js create mode 100644 js/src/tests/js1_5/extensions/regress-452329.js create mode 100644 js/src/tests/js1_5/extensions/regress-452338.js create mode 100644 js/src/tests/js1_5/extensions/regress-452565.js create mode 100644 js/src/tests/js1_5/extensions/regress-453249.js create mode 100644 js/src/tests/js1_5/extensions/regress-454040.js create mode 100644 js/src/tests/js1_5/extensions/regress-454142.js create mode 100755 js/src/tests/js1_5/extensions/regress-454704.js create mode 100644 js/src/tests/js1_5/extensions/regress-455380.js create mode 100644 js/src/tests/js1_5/extensions/regress-455408.js create mode 100644 js/src/tests/js1_5/extensions/regress-455413.js create mode 100644 js/src/tests/js1_5/extensions/regress-459606.js create mode 100644 js/src/tests/js1_5/extensions/regress-462734-02.js create mode 100644 js/src/tests/js1_5/extensions/regress-462734-03.js create mode 100644 js/src/tests/js1_5/extensions/regress-462734-04.js create mode 100755 js/src/tests/js1_5/extensions/regress-465145.js create mode 100644 js/src/tests/js1_5/extensions/regress-465276.js create mode 100644 js/src/tests/js1_5/extensions/regress-469625.js create mode 100644 js/src/tests/js1_5/extensions/regress-469761.js create mode 100644 js/src/tests/js1_5/extensions/regress-472599.js create mode 100755 js/src/tests/js1_5/extensions/regress-472787.js create mode 100644 js/src/tests/js1_5/extensions/regress-476447.js create mode 100644 js/src/tests/js1_5/extensions/regress-479487.js create mode 100644 js/src/tests/js1_5/extensions/regress-479551.js create mode 100644 js/src/tests/js1_5/extensions/regress-480579.js create mode 100644 js/src/tests/js1_5/extensions/regress-481516.js create mode 100755 js/src/tests/js1_5/extensions/regress-488995.js create mode 100644 js/src/tests/js1_5/extensions/regress-50447-1.js create mode 100644 js/src/tests/js1_5/extensions/regress-50447.js create mode 100644 js/src/tests/js1_5/extensions/regress-543839.js create mode 100644 js/src/tests/js1_5/extensions/regress-90596-001.js create mode 100644 js/src/tests/js1_5/extensions/regress-90596-002.js create mode 100644 js/src/tests/js1_5/extensions/regress-96284-001.js create mode 100644 js/src/tests/js1_5/extensions/regress-96284-002.js create mode 100644 js/src/tests/js1_5/extensions/scope-001.js create mode 100644 js/src/tests/js1_5/extensions/shell.js create mode 100644 js/src/tests/js1_5/extensions/toLocaleFormat-01.js create mode 100644 js/src/tests/js1_5/extensions/toLocaleFormat-02.js create mode 100644 js/src/tests/js1_5/jstests.list create mode 100644 js/src/tests/js1_5/shell.js create mode 100644 js/src/tests/js1_5/template.js create mode 100644 js/src/tests/js1_6/Array/browser.js create mode 100644 js/src/tests/js1_6/Array/filter.js create mode 100644 js/src/tests/js1_6/Array/jstests.list create mode 100644 js/src/tests/js1_6/Array/regress-290592.js create mode 100644 js/src/tests/js1_6/Array/regress-304828.js create mode 100644 js/src/tests/js1_6/Array/regress-305002.js create mode 100644 js/src/tests/js1_6/Array/regress-310425-01.js create mode 100644 js/src/tests/js1_6/Array/regress-310425-02.js create mode 100644 js/src/tests/js1_6/Array/regress-320887.js create mode 100644 js/src/tests/js1_6/Array/regress-352742-01.js create mode 100644 js/src/tests/js1_6/Array/regress-352742-02.js create mode 100644 js/src/tests/js1_6/Array/regress-386030.js create mode 100644 js/src/tests/js1_6/Array/regress-415451.js create mode 100644 js/src/tests/js1_6/Array/regress-415540.js create mode 100644 js/src/tests/js1_6/Array/regress-566651.js create mode 100644 js/src/tests/js1_6/Array/shell.js create mode 100644 js/src/tests/js1_6/README create mode 100644 js/src/tests/js1_6/Regress/browser.js create mode 100644 js/src/tests/js1_6/Regress/jstests.list create mode 100644 js/src/tests/js1_6/Regress/regress-301574.js create mode 100644 js/src/tests/js1_6/Regress/regress-311157-01.js create mode 100644 js/src/tests/js1_6/Regress/regress-311157-02.js create mode 100644 js/src/tests/js1_6/Regress/regress-314887.js create mode 100644 js/src/tests/js1_6/Regress/regress-320172.js create mode 100644 js/src/tests/js1_6/Regress/regress-350417.js create mode 100644 js/src/tests/js1_6/Regress/regress-351795.js create mode 100644 js/src/tests/js1_6/Regress/regress-352271.js create mode 100644 js/src/tests/js1_6/Regress/regress-353078.js create mode 100644 js/src/tests/js1_6/Regress/regress-355002.js create mode 100644 js/src/tests/js1_6/Regress/regress-372565.js create mode 100644 js/src/tests/js1_6/Regress/regress-378492.js create mode 100644 js/src/tests/js1_6/Regress/regress-475469.js create mode 100644 js/src/tests/js1_6/Regress/regress-476655.js create mode 100644 js/src/tests/js1_6/Regress/shell.js create mode 100644 js/src/tests/js1_6/String/browser.js create mode 100644 js/src/tests/js1_6/String/jstests.list create mode 100644 js/src/tests/js1_6/String/regress-306591.js create mode 100644 js/src/tests/js1_6/String/shell.js create mode 100644 js/src/tests/js1_6/browser.js create mode 100644 js/src/tests/js1_6/decompilation/browser.js create mode 100644 js/src/tests/js1_6/decompilation/jstests.list create mode 100644 js/src/tests/js1_6/decompilation/regress-352084.js create mode 100644 js/src/tests/js1_6/decompilation/regress-352613-01.js create mode 100644 js/src/tests/js1_6/decompilation/regress-352613-02.js create mode 100644 js/src/tests/js1_6/decompilation/shell.js create mode 100644 js/src/tests/js1_6/extensions/browser.js create mode 100644 js/src/tests/js1_6/extensions/jstests.list create mode 100644 js/src/tests/js1_6/extensions/regress-312385-01.js create mode 100644 js/src/tests/js1_6/extensions/regress-352392.js create mode 100644 js/src/tests/js1_6/extensions/regress-385393-08.js create mode 100644 js/src/tests/js1_6/extensions/regress-414098.js create mode 100644 js/src/tests/js1_6/extensions/regress-455464-01.js create mode 100644 js/src/tests/js1_6/extensions/regress-455464-02.js create mode 100644 js/src/tests/js1_6/extensions/regress-455464-03.js create mode 100644 js/src/tests/js1_6/extensions/regress-455464-04.js create mode 100644 js/src/tests/js1_6/extensions/regress-456826.js create mode 100755 js/src/tests/js1_6/extensions/regress-457521.js create mode 100644 js/src/tests/js1_6/extensions/regress-465443.js create mode 100644 js/src/tests/js1_6/extensions/regress-470310.js create mode 100644 js/src/tests/js1_6/extensions/regress-472508.js create mode 100644 js/src/tests/js1_6/extensions/regress-475144.js create mode 100755 js/src/tests/js1_6/extensions/regress-479567.js create mode 100644 js/src/tests/js1_6/extensions/regress-565521.js create mode 100644 js/src/tests/js1_6/extensions/shell.js create mode 100644 js/src/tests/js1_6/jstests.list create mode 100644 js/src/tests/js1_6/shell.js create mode 100644 js/src/tests/js1_6/template.js create mode 100644 js/src/tests/js1_7/GC/browser.js create mode 100644 js/src/tests/js1_7/GC/jstests.list create mode 100644 js/src/tests/js1_7/GC/regress-341675.js create mode 100644 js/src/tests/js1_7/GC/regress-381374.js create mode 100644 js/src/tests/js1_7/GC/shell.js create mode 100644 js/src/tests/js1_7/README create mode 100644 js/src/tests/js1_7/block/browser.js create mode 100644 js/src/tests/js1_7/block/jstests.list create mode 100644 js/src/tests/js1_7/block/order-of-operation.js create mode 100644 js/src/tests/js1_7/block/regress-341939.js create mode 100644 js/src/tests/js1_7/block/regress-343765.js create mode 100644 js/src/tests/js1_7/block/regress-344139.js create mode 100644 js/src/tests/js1_7/block/regress-344262.js create mode 100644 js/src/tests/js1_7/block/regress-344370.js create mode 100644 js/src/tests/js1_7/block/regress-344601.js create mode 100644 js/src/tests/js1_7/block/regress-345542.js create mode 100644 js/src/tests/js1_7/block/regress-347559.js create mode 100644 js/src/tests/js1_7/block/regress-348685.js create mode 100644 js/src/tests/js1_7/block/regress-349283.js create mode 100644 js/src/tests/js1_7/block/regress-349298.js create mode 100644 js/src/tests/js1_7/block/regress-349507.js create mode 100644 js/src/tests/js1_7/block/regress-349653.js create mode 100644 js/src/tests/js1_7/block/regress-349962.js create mode 100644 js/src/tests/js1_7/block/regress-350279.js create mode 100644 js/src/tests/js1_7/block/regress-350730.js create mode 100644 js/src/tests/js1_7/block/regress-350793-01.js create mode 100644 js/src/tests/js1_7/block/regress-351497.js create mode 100644 js/src/tests/js1_7/block/regress-351606.js create mode 100644 js/src/tests/js1_7/block/regress-351794.js create mode 100644 js/src/tests/js1_7/block/regress-352092.js create mode 100644 js/src/tests/js1_7/block/regress-352185.js create mode 100644 js/src/tests/js1_7/block/regress-352212.js create mode 100644 js/src/tests/js1_7/block/regress-352267.js create mode 100644 js/src/tests/js1_7/block/regress-352422.js create mode 100644 js/src/tests/js1_7/block/regress-352609.js create mode 100644 js/src/tests/js1_7/block/regress-352616.js create mode 100644 js/src/tests/js1_7/block/regress-352624.js create mode 100644 js/src/tests/js1_7/block/regress-352786.js create mode 100644 js/src/tests/js1_7/block/regress-352907.js create mode 100644 js/src/tests/js1_7/block/regress-357754.js create mode 100644 js/src/tests/js1_7/block/regress-358508.js create mode 100644 js/src/tests/js1_7/block/regress-376410.js create mode 100644 js/src/tests/js1_7/block/regress-396900.js create mode 100644 js/src/tests/js1_7/block/regress-411279.js create mode 100644 js/src/tests/js1_7/block/shell.js create mode 100644 js/src/tests/js1_7/browser.js create mode 100644 js/src/tests/js1_7/decompilation/browser.js create mode 100644 js/src/tests/js1_7/decompilation/jstests.list create mode 100644 js/src/tests/js1_7/decompilation/regress-346642-01.js create mode 100644 js/src/tests/js1_7/decompilation/regress-349493.js create mode 100644 js/src/tests/js1_7/decompilation/regress-349499.js create mode 100644 js/src/tests/js1_7/decompilation/regress-349602.js create mode 100644 js/src/tests/js1_7/decompilation/regress-349605.js create mode 100644 js/src/tests/js1_7/decompilation/regress-349633.js create mode 100644 js/src/tests/js1_7/decompilation/regress-349634.js create mode 100644 js/src/tests/js1_7/decompilation/regress-350704.js create mode 100644 js/src/tests/js1_7/decompilation/regress-350793-02.js create mode 100644 js/src/tests/js1_7/decompilation/regress-350810.js create mode 100644 js/src/tests/js1_7/decompilation/regress-350991.js create mode 100644 js/src/tests/js1_7/decompilation/regress-351070-01.js create mode 100644 js/src/tests/js1_7/decompilation/regress-351070-03.js create mode 100644 js/src/tests/js1_7/decompilation/regress-351496.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352008.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352011.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352015.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352022.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352025.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352026.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352068.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352079.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352198.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352217.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352266.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352268.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352269.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352272.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352283.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352402.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352415.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352441.js create mode 100644 js/src/tests/js1_7/decompilation/regress-352732.js create mode 100644 js/src/tests/js1_7/decompilation/regress-355004.js create mode 100644 js/src/tests/js1_7/decompilation/regress-355049-01.js create mode 100644 js/src/tests/js1_7/decompilation/regress-355049-02.js create mode 100644 js/src/tests/js1_7/decompilation/regress-355105.js create mode 100644 js/src/tests/js1_7/decompilation/regress-355635.js create mode 100644 js/src/tests/js1_7/decompilation/regress-355786.js create mode 100644 js/src/tests/js1_7/decompilation/regress-356247.js create mode 100644 js/src/tests/js1_7/decompilation/regress-371802.js create mode 100644 js/src/tests/js1_7/decompilation/regress-374713.js create mode 100644 js/src/tests/js1_7/decompilation/regress-375794.js create mode 100644 js/src/tests/js1_7/decompilation/regress-379925.js create mode 100644 js/src/tests/js1_7/decompilation/regress-380506.js create mode 100644 js/src/tests/js1_7/decompilation/regress-410571.js create mode 100644 js/src/tests/js1_7/decompilation/regress-410649.js create mode 100644 js/src/tests/js1_7/decompilation/regress-429252.js create mode 100644 js/src/tests/js1_7/decompilation/shell.js create mode 100644 js/src/tests/js1_7/expressions/browser.js create mode 100644 js/src/tests/js1_7/expressions/destructuring-scope.js create mode 100644 js/src/tests/js1_7/expressions/jstests.list create mode 100644 js/src/tests/js1_7/expressions/regress-346203.js create mode 100644 js/src/tests/js1_7/expressions/regress-346645-01.js create mode 100644 js/src/tests/js1_7/expressions/regress-346645-02.js create mode 100644 js/src/tests/js1_7/expressions/regress-346645-03.js create mode 100644 js/src/tests/js1_7/expressions/regress-349624.js create mode 100644 js/src/tests/js1_7/expressions/regress-349818.js create mode 100644 js/src/tests/js1_7/expressions/regress-418051.js create mode 100644 js/src/tests/js1_7/expressions/regress-421806.js create mode 100644 js/src/tests/js1_7/expressions/regress-451340.js create mode 100644 js/src/tests/js1_7/expressions/shell.js create mode 100644 js/src/tests/js1_7/extensions/basic-Iterator.js create mode 100644 js/src/tests/js1_7/extensions/basic-for-each.js create mode 100644 js/src/tests/js1_7/extensions/basic-for-in.js create mode 100644 js/src/tests/js1_7/extensions/browser.js create mode 100644 js/src/tests/js1_7/extensions/destructuring-order.js create mode 100644 js/src/tests/js1_7/extensions/iterator-ctor.js create mode 100644 js/src/tests/js1_7/extensions/jstests.list create mode 100644 js/src/tests/js1_7/extensions/regress-346021.js create mode 100644 js/src/tests/js1_7/extensions/regress-346642-02.js create mode 100644 js/src/tests/js1_7/extensions/regress-346642-06.js create mode 100644 js/src/tests/js1_7/extensions/regress-346773.js create mode 100644 js/src/tests/js1_7/extensions/regress-349619.js create mode 100644 js/src/tests/js1_7/extensions/regress-350312.js create mode 100644 js/src/tests/js1_7/extensions/regress-351070-02.js create mode 100644 js/src/tests/js1_7/extensions/regress-351102-03.js create mode 100644 js/src/tests/js1_7/extensions/regress-351102-04.js create mode 100644 js/src/tests/js1_7/extensions/regress-351102-05.js create mode 100644 js/src/tests/js1_7/extensions/regress-351102-07.js create mode 100644 js/src/tests/js1_7/extensions/regress-352797-01.js create mode 100644 js/src/tests/js1_7/extensions/regress-352885-01.js create mode 100644 js/src/tests/js1_7/extensions/regress-352885-02.js create mode 100644 js/src/tests/js1_7/extensions/regress-353214-01.js create mode 100644 js/src/tests/js1_7/extensions/regress-353214-02.js create mode 100644 js/src/tests/js1_7/extensions/regress-353249.js create mode 100644 js/src/tests/js1_7/extensions/regress-353454.js create mode 100644 js/src/tests/js1_7/extensions/regress-354499-01.js create mode 100644 js/src/tests/js1_7/extensions/regress-354499-02.js create mode 100644 js/src/tests/js1_7/extensions/regress-354945-01.js create mode 100644 js/src/tests/js1_7/extensions/regress-354945-02.js create mode 100644 js/src/tests/js1_7/extensions/regress-355052-01.js create mode 100644 js/src/tests/js1_7/extensions/regress-355052-02.js create mode 100644 js/src/tests/js1_7/extensions/regress-355052-03.js create mode 100644 js/src/tests/js1_7/extensions/regress-355145.js create mode 100644 js/src/tests/js1_7/extensions/regress-355410.js create mode 100644 js/src/tests/js1_7/extensions/regress-355512.js create mode 100644 js/src/tests/js1_7/extensions/regress-355583.js create mode 100644 js/src/tests/js1_7/extensions/regress-363040-01.js create mode 100644 js/src/tests/js1_7/extensions/regress-363040-02.js create mode 100644 js/src/tests/js1_7/extensions/regress-366668-01.js create mode 100644 js/src/tests/js1_7/extensions/regress-366668-02.js create mode 100644 js/src/tests/js1_7/extensions/regress-367629.js create mode 100644 js/src/tests/js1_7/extensions/regress-368213.js create mode 100644 js/src/tests/js1_7/extensions/regress-368224.js create mode 100644 js/src/tests/js1_7/extensions/regress-372364.js create mode 100644 js/src/tests/js1_7/extensions/regress-379566.js create mode 100644 js/src/tests/js1_7/extensions/regress-380933.js create mode 100644 js/src/tests/js1_7/extensions/regress-381301.js create mode 100644 js/src/tests/js1_7/extensions/regress-381303.js create mode 100644 js/src/tests/js1_7/extensions/regress-387955-01.js create mode 100644 js/src/tests/js1_7/extensions/regress-387955-02.js create mode 100644 js/src/tests/js1_7/extensions/regress-392308.js create mode 100644 js/src/tests/js1_7/extensions/regress-396326.js create mode 100644 js/src/tests/js1_7/extensions/regress-429266.js create mode 100644 js/src/tests/js1_7/extensions/regress-453955.js create mode 100644 js/src/tests/js1_7/extensions/regress-455982-01.js create mode 100644 js/src/tests/js1_7/extensions/regress-455982-02.js create mode 100644 js/src/tests/js1_7/extensions/regress-458679.js create mode 100644 js/src/tests/js1_7/extensions/regress-469234.js create mode 100755 js/src/tests/js1_7/extensions/regress-469405-01.js create mode 100755 js/src/tests/js1_7/extensions/regress-469405-02.js create mode 100644 js/src/tests/js1_7/extensions/regress-470176.js create mode 100644 js/src/tests/js1_7/extensions/regress-470300-01.js create mode 100644 js/src/tests/js1_7/extensions/regress-470300-02.js create mode 100755 js/src/tests/js1_7/extensions/regress-473282.js create mode 100644 js/src/tests/js1_7/extensions/regress-474771-01.js create mode 100644 js/src/tests/js1_7/extensions/regress-474771-02.js create mode 100644 js/src/tests/js1_7/extensions/regress-476257.js create mode 100644 js/src/tests/js1_7/extensions/regress-477048.js create mode 100644 js/src/tests/js1_7/extensions/regress-589112.js create mode 100644 js/src/tests/js1_7/extensions/regress-590813.js create mode 100644 js/src/tests/js1_7/extensions/regress-591450.js create mode 100644 js/src/tests/js1_7/extensions/shell.js create mode 100644 js/src/tests/js1_7/geniter/326466-01.js create mode 100644 js/src/tests/js1_7/geniter/browser.js create mode 100644 js/src/tests/js1_7/geniter/builtin-Iterator-function.js create mode 100644 js/src/tests/js1_7/geniter/evens.js create mode 100644 js/src/tests/js1_7/geniter/fibonacci-matrix-generator.js create mode 100644 js/src/tests/js1_7/geniter/iterator-toString.js create mode 100644 js/src/tests/js1_7/geniter/jstests.list create mode 100644 js/src/tests/js1_7/geniter/message-value-passing.js create mode 100644 js/src/tests/js1_7/geniter/multiple-close.js create mode 100644 js/src/tests/js1_7/geniter/nested-yield.js create mode 100644 js/src/tests/js1_7/geniter/pi-generator.js create mode 100644 js/src/tests/js1_7/geniter/regress-345736.js create mode 100644 js/src/tests/js1_7/geniter/regress-345855.js create mode 100644 js/src/tests/js1_7/geniter/regress-345879-01.js create mode 100644 js/src/tests/js1_7/geniter/regress-345879-02.js create mode 100644 js/src/tests/js1_7/geniter/regress-347593.js create mode 100644 js/src/tests/js1_7/geniter/regress-347739.js create mode 100644 js/src/tests/js1_7/geniter/regress-349012-01.js create mode 100644 js/src/tests/js1_7/geniter/regress-349012-02.js create mode 100644 js/src/tests/js1_7/geniter/regress-349012-03.js create mode 100644 js/src/tests/js1_7/geniter/regress-349012-04.js create mode 100644 js/src/tests/js1_7/geniter/regress-349012-05.js create mode 100644 js/src/tests/js1_7/geniter/regress-349023-01.js create mode 100644 js/src/tests/js1_7/geniter/regress-349023-02.js create mode 100644 js/src/tests/js1_7/geniter/regress-349023-03.js create mode 100644 js/src/tests/js1_7/geniter/regress-349331.js create mode 100644 js/src/tests/js1_7/geniter/regress-349362.js create mode 100644 js/src/tests/js1_7/geniter/regress-349851.js create mode 100644 js/src/tests/js1_7/geniter/regress-350621.js create mode 100644 js/src/tests/js1_7/geniter/regress-350809.js create mode 100644 js/src/tests/js1_7/geniter/regress-351120.js create mode 100644 js/src/tests/js1_7/geniter/regress-351514.js create mode 100644 js/src/tests/js1_7/geniter/regress-352197.js create mode 100644 js/src/tests/js1_7/geniter/regress-352605.js create mode 100644 js/src/tests/js1_7/geniter/regress-352876.js create mode 100644 js/src/tests/js1_7/geniter/regress-355834.js create mode 100644 js/src/tests/js1_7/geniter/regress-359062.js create mode 100644 js/src/tests/js1_7/geniter/regress-366941.js create mode 100644 js/src/tests/js1_7/geniter/regress-382335.js create mode 100644 js/src/tests/js1_7/geniter/regress-387871.js create mode 100644 js/src/tests/js1_7/geniter/regress-390918.js create mode 100644 js/src/tests/js1_7/geniter/regress-392310.js create mode 100755 js/src/tests/js1_7/geniter/regress-466206.js create mode 100644 js/src/tests/js1_7/geniter/send-no-rhs.js create mode 100644 js/src/tests/js1_7/geniter/sequential-yields.js create mode 100644 js/src/tests/js1_7/geniter/shell.js create mode 100644 js/src/tests/js1_7/geniter/simple-fib.js create mode 100644 js/src/tests/js1_7/geniter/throw-after-close.js create mode 100644 js/src/tests/js1_7/geniter/throw-forever.js create mode 100644 js/src/tests/js1_7/geniter/unreachable-yield.js create mode 100644 js/src/tests/js1_7/geniter/yield-undefined.js create mode 100644 js/src/tests/js1_7/iterable/browser.js create mode 100644 js/src/tests/js1_7/iterable/jstests.list create mode 100644 js/src/tests/js1_7/iterable/regress-340526-01.js create mode 100644 js/src/tests/js1_7/iterable/regress-340526-02.js create mode 100644 js/src/tests/js1_7/iterable/regress-341496.js create mode 100644 js/src/tests/js1_7/iterable/regress-341499.js create mode 100644 js/src/tests/js1_7/iterable/regress-341510.js create mode 100644 js/src/tests/js1_7/iterable/regress-341815.js create mode 100644 js/src/tests/js1_7/iterable/regress-341821.js create mode 100644 js/src/tests/js1_7/iterable/regress-354750-01.js create mode 100644 js/src/tests/js1_7/iterable/regress-355025.js create mode 100644 js/src/tests/js1_7/iterable/regress-355075-01.js create mode 100644 js/src/tests/js1_7/iterable/regress-355075-02.js create mode 100644 js/src/tests/js1_7/iterable/regress-355090.js create mode 100644 js/src/tests/js1_7/iterable/regress-412467.js create mode 100644 js/src/tests/js1_7/iterable/regress-415922.js create mode 100644 js/src/tests/js1_7/iterable/regress-568056.js create mode 100644 js/src/tests/js1_7/iterable/shell.js create mode 100644 js/src/tests/js1_7/jstests.list create mode 100644 js/src/tests/js1_7/lexical/browser.js create mode 100644 js/src/tests/js1_7/lexical/jstests.list create mode 100644 js/src/tests/js1_7/lexical/regress-336376-01.js create mode 100644 js/src/tests/js1_7/lexical/regress-346642-03.js create mode 100644 js/src/tests/js1_7/lexical/regress-346642-04.js create mode 100644 js/src/tests/js1_7/lexical/regress-351515.js create mode 100644 js/src/tests/js1_7/lexical/shell.js create mode 100644 js/src/tests/js1_7/regexp/browser.js create mode 100644 js/src/tests/js1_7/regexp/jstests.list create mode 100644 js/src/tests/js1_7/regexp/shell.js create mode 100644 js/src/tests/js1_7/regexp/yflag.js create mode 100644 js/src/tests/js1_7/regress/browser.js create mode 100644 js/src/tests/js1_7/regress/jstests.list create mode 100644 js/src/tests/js1_7/regress/regress-350387.js create mode 100644 js/src/tests/js1_7/regress/regress-351503-01.js create mode 100644 js/src/tests/js1_7/regress/regress-351503-02.js create mode 100644 js/src/tests/js1_7/regress/regress-352640-01.js create mode 100644 js/src/tests/js1_7/regress/regress-352640-02.js create mode 100644 js/src/tests/js1_7/regress/regress-352640-03.js create mode 100644 js/src/tests/js1_7/regress/regress-352640-04.js create mode 100644 js/src/tests/js1_7/regress/regress-352797-02.js create mode 100644 js/src/tests/js1_7/regress/regress-352870-01.js create mode 100644 js/src/tests/js1_7/regress/regress-352870-02.js create mode 100644 js/src/tests/js1_7/regress/regress-352870-03.js create mode 100644 js/src/tests/js1_7/regress/regress-353079.js create mode 100644 js/src/tests/js1_7/regress/regress-355023.js create mode 100644 js/src/tests/js1_7/regress/regress-355832-01.js create mode 100644 js/src/tests/js1_7/regress/regress-355832-02.js create mode 100644 js/src/tests/js1_7/regress/regress-361566.js create mode 100644 js/src/tests/js1_7/regress/regress-363040-01.js create mode 100644 js/src/tests/js1_7/regress/regress-363040-02.js create mode 100644 js/src/tests/js1_7/regress/regress-369666-01.js create mode 100644 js/src/tests/js1_7/regress/regress-369666-02.js create mode 100644 js/src/tests/js1_7/regress/regress-372331.js create mode 100644 js/src/tests/js1_7/regress/regress-373827-01.js create mode 100644 js/src/tests/js1_7/regress/regress-373827-02.js create mode 100644 js/src/tests/js1_7/regress/regress-373828.js create mode 100644 js/src/tests/js1_7/regress/regress-375695.js create mode 100644 js/src/tests/js1_7/regress/regress-379442.js create mode 100644 js/src/tests/js1_7/regress/regress-379483.js create mode 100644 js/src/tests/js1_7/regress/regress-385133-01.js create mode 100644 js/src/tests/js1_7/regress/regress-385133-02.js create mode 100644 js/src/tests/js1_7/regress/regress-385393-05.js create mode 100644 js/src/tests/js1_7/regress/regress-387951.js create mode 100644 js/src/tests/js1_7/regress/regress-406477.js create mode 100644 js/src/tests/js1_7/regress/regress-407727-01.js create mode 100644 js/src/tests/js1_7/regress/regress-407727-02.js create mode 100644 js/src/tests/js1_7/regress/regress-407957.js create mode 100644 js/src/tests/js1_7/regress/regress-410649.js create mode 100644 js/src/tests/js1_7/regress/regress-414553.js create mode 100644 js/src/tests/js1_7/regress/regress-416601.js create mode 100644 js/src/tests/js1_7/regress/regress-416705.js create mode 100644 js/src/tests/js1_7/regress/regress-418641.js create mode 100644 js/src/tests/js1_7/regress/regress-419803.js create mode 100644 js/src/tests/js1_7/regress/regress-420399.js create mode 100644 js/src/tests/js1_7/regress/regress-428706.js create mode 100644 js/src/tests/js1_7/regress/regress-428708.js create mode 100644 js/src/tests/js1_7/regress/regress-452703.js create mode 100644 js/src/tests/js1_7/regress/regress-452960.js create mode 100644 js/src/tests/js1_7/regress/regress-453049.js create mode 100644 js/src/tests/js1_7/regress/regress-453051.js create mode 100644 js/src/tests/js1_7/regress/regress-453411.js create mode 100644 js/src/tests/js1_7/regress/regress-461235.js create mode 100644 js/src/tests/js1_7/regress/regress-461945.js create mode 100644 js/src/tests/js1_7/regress/regress-462071.js create mode 100644 js/src/tests/js1_7/regress/regress-462282.js create mode 100644 js/src/tests/js1_7/regress/regress-462388.js create mode 100644 js/src/tests/js1_7/regress/regress-462407.js create mode 100644 js/src/tests/js1_7/regress/regress-464403.js create mode 100644 js/src/tests/js1_7/regress/regress-465236.js create mode 100644 js/src/tests/js1_7/regress/regress-465424.js create mode 100644 js/src/tests/js1_7/regress/regress-465484.js create mode 100755 js/src/tests/js1_7/regress/regress-465686.js create mode 100644 js/src/tests/js1_7/regress/regress-469239-01.js create mode 100644 js/src/tests/js1_7/regress/regress-469239-02.js create mode 100644 js/src/tests/js1_7/regress/regress-470223.js create mode 100644 js/src/tests/js1_7/regress/regress-470388-01.js create mode 100644 js/src/tests/js1_7/regress/regress-470388-02.js create mode 100644 js/src/tests/js1_7/regress/regress-470388-03.js create mode 100644 js/src/tests/js1_7/regress/regress-474771.js create mode 100644 js/src/tests/js1_7/regress/shell.js create mode 100644 js/src/tests/js1_7/shell.js create mode 100644 js/src/tests/js1_7/template.js create mode 100644 js/src/tests/js1_8/README create mode 100644 js/src/tests/js1_8/browser.js create mode 100644 js/src/tests/js1_8/decompilation/browser.js create mode 100644 js/src/tests/js1_8/decompilation/jstests.list create mode 100644 js/src/tests/js1_8/decompilation/regress-260106.js create mode 100644 js/src/tests/js1_8/decompilation/regress-346749.js create mode 100644 js/src/tests/js1_8/decompilation/regress-381372.js create mode 100644 js/src/tests/js1_8/decompilation/regress-381504.js create mode 100644 js/src/tests/js1_8/decompilation/regress-381963-01.js create mode 100644 js/src/tests/js1_8/decompilation/regress-381963-02.js create mode 100644 js/src/tests/js1_8/decompilation/regress-382981.js create mode 100644 js/src/tests/js1_8/decompilation/regress-443074.js create mode 100644 js/src/tests/js1_8/decompilation/regress-460504.js create mode 100644 js/src/tests/js1_8/decompilation/regress-461233.js create mode 100644 js/src/tests/js1_8/decompilation/regress-469625-01.js create mode 100644 js/src/tests/js1_8/decompilation/shell.js create mode 100644 js/src/tests/js1_8/extensions/browser.js create mode 100644 js/src/tests/js1_8/extensions/dekker.js create mode 100644 js/src/tests/js1_8/extensions/expclo.js create mode 100644 js/src/tests/js1_8/extensions/expclo2.js create mode 100644 js/src/tests/js1_8/extensions/for-in.js create mode 100644 js/src/tests/js1_8/extensions/jstests.list create mode 100644 js/src/tests/js1_8/extensions/lamport.js create mode 100644 js/src/tests/js1_8/extensions/peterson.js create mode 100644 js/src/tests/js1_8/extensions/regress-353116.js create mode 100644 js/src/tests/js1_8/extensions/regress-378789.js create mode 100644 js/src/tests/js1_8/extensions/regress-385393-01.js create mode 100644 js/src/tests/js1_8/extensions/regress-385393-10.js create mode 100644 js/src/tests/js1_8/extensions/regress-385393-11.js create mode 100644 js/src/tests/js1_8/extensions/regress-385729.js create mode 100644 js/src/tests/js1_8/extensions/regress-394709.js create mode 100644 js/src/tests/js1_8/extensions/regress-415721.js create mode 100644 js/src/tests/js1_8/extensions/regress-417131.js create mode 100644 js/src/tests/js1_8/extensions/regress-417817.js create mode 100644 js/src/tests/js1_8/extensions/regress-419091.js create mode 100644 js/src/tests/js1_8/extensions/regress-422269.js create mode 100644 js/src/tests/js1_8/extensions/regress-445818.js create mode 100644 js/src/tests/js1_8/extensions/regress-446169-01.js create mode 100644 js/src/tests/js1_8/extensions/regress-446169-02.js create mode 100644 js/src/tests/js1_8/extensions/regress-452476.js create mode 100755 js/src/tests/js1_8/extensions/regress-452913.js create mode 100644 js/src/tests/js1_8/extensions/regress-454744.js create mode 100644 js/src/tests/js1_8/extensions/regress-455973.js create mode 100644 js/src/tests/js1_8/extensions/regress-465337.js create mode 100644 js/src/tests/js1_8/extensions/regress-465453.js create mode 100644 js/src/tests/js1_8/extensions/regress-469625.js create mode 100644 js/src/tests/js1_8/extensions/regress-471197.js create mode 100644 js/src/tests/js1_8/extensions/regress-472450-03.js create mode 100644 js/src/tests/js1_8/extensions/regress-472450-04.js create mode 100755 js/src/tests/js1_8/extensions/regress-473040.js create mode 100755 js/src/tests/js1_8/extensions/regress-475971.js create mode 100644 js/src/tests/js1_8/extensions/regress-476414-01.js create mode 100644 js/src/tests/js1_8/extensions/regress-476414-02.js create mode 100644 js/src/tests/js1_8/extensions/regress-476427.js create mode 100755 js/src/tests/js1_8/extensions/regress-476653.js create mode 100644 js/src/tests/js1_8/extensions/regress-476869.js create mode 100755 js/src/tests/js1_8/extensions/regress-476871-01.js create mode 100755 js/src/tests/js1_8/extensions/regress-476871-02.js create mode 100644 js/src/tests/js1_8/extensions/regress-479252.js create mode 100644 js/src/tests/js1_8/extensions/regress-479381.js create mode 100644 js/src/tests/js1_8/extensions/regress-481989.js create mode 100644 js/src/tests/js1_8/extensions/regress-482263.js create mode 100644 js/src/tests/js1_8/extensions/shell.js create mode 100644 js/src/tests/js1_8/extensions/simple-tree.js create mode 100644 js/src/tests/js1_8/genexps/browser.js create mode 100644 js/src/tests/js1_8/genexps/jstests.list create mode 100644 js/src/tests/js1_8/genexps/regress-347739.js create mode 100644 js/src/tests/js1_8/genexps/regress-349012-01.js create mode 100644 js/src/tests/js1_8/genexps/regress-349326.js create mode 100644 js/src/tests/js1_8/genexps/regress-349331.js create mode 100644 js/src/tests/js1_8/genexps/regress-380237-01.js create mode 100644 js/src/tests/js1_8/genexps/regress-380237-02.js create mode 100644 js/src/tests/js1_8/genexps/regress-380237-03.js create mode 100644 js/src/tests/js1_8/genexps/regress-380237-04.js create mode 100644 js/src/tests/js1_8/genexps/regress-384991.js create mode 100644 js/src/tests/js1_8/genexps/shell.js create mode 100644 js/src/tests/js1_8/jstests.list create mode 100644 js/src/tests/js1_8/regress/browser.js create mode 100644 js/src/tests/js1_8/regress/jstests.list create mode 100644 js/src/tests/js1_8/regress/regress-366941.js create mode 100644 js/src/tests/js1_8/regress/regress-384412.js create mode 100644 js/src/tests/js1_8/regress/regress-384758.js create mode 100644 js/src/tests/js1_8/regress/regress-404734.js create mode 100644 js/src/tests/js1_8/regress/regress-427798.js create mode 100644 js/src/tests/js1_8/regress/regress-433279-01.js create mode 100644 js/src/tests/js1_8/regress/regress-433279-02.js create mode 100644 js/src/tests/js1_8/regress/regress-433279-03.js create mode 100644 js/src/tests/js1_8/regress/regress-442333-01.js create mode 100644 js/src/tests/js1_8/regress/regress-452491.js create mode 100644 js/src/tests/js1_8/regress/regress-453492.js create mode 100644 js/src/tests/js1_8/regress/regress-455981-01.js create mode 100644 js/src/tests/js1_8/regress/regress-455981-02.js create mode 100644 js/src/tests/js1_8/regress/regress-457065-01.js create mode 100644 js/src/tests/js1_8/regress/regress-457065-02.js create mode 100644 js/src/tests/js1_8/regress/regress-458076.js create mode 100644 js/src/tests/js1_8/regress/regress-459185.js create mode 100644 js/src/tests/js1_8/regress/regress-459186.js create mode 100644 js/src/tests/js1_8/regress/regress-459389.js create mode 100644 js/src/tests/js1_8/regress/regress-461930.js create mode 100644 js/src/tests/js1_8/regress/regress-461932.js create mode 100644 js/src/tests/js1_8/regress/regress-463334-01.js create mode 100644 js/src/tests/js1_8/regress/regress-463334-02.js create mode 100644 js/src/tests/js1_8/regress/regress-463783.js create mode 100644 js/src/tests/js1_8/regress/regress-464092-01.js create mode 100644 js/src/tests/js1_8/regress/regress-464092-02.js create mode 100644 js/src/tests/js1_8/regress/regress-464096.js create mode 100644 js/src/tests/js1_8/regress/regress-464418.js create mode 100644 js/src/tests/js1_8/regress/regress-464978.js create mode 100644 js/src/tests/js1_8/regress/regress-465220.js create mode 100644 js/src/tests/js1_8/regress/regress-465234.js create mode 100644 js/src/tests/js1_8/regress/regress-465239.js create mode 100644 js/src/tests/js1_8/regress/regress-465241.js create mode 100644 js/src/tests/js1_8/regress/regress-465249.js create mode 100644 js/src/tests/js1_8/regress/regress-465261.js create mode 100644 js/src/tests/js1_8/regress/regress-465308.js create mode 100644 js/src/tests/js1_8/regress/regress-465454.js create mode 100644 js/src/tests/js1_8/regress/regress-465460-01.js create mode 100644 js/src/tests/js1_8/regress/regress-465460-02.js create mode 100644 js/src/tests/js1_8/regress/regress-465460-03.js create mode 100644 js/src/tests/js1_8/regress/regress-465460-04.js create mode 100644 js/src/tests/js1_8/regress/regress-465460-05.js create mode 100644 js/src/tests/js1_8/regress/regress-465460-06.js create mode 100644 js/src/tests/js1_8/regress/regress-465460-07.js create mode 100644 js/src/tests/js1_8/regress/regress-465460-08.js create mode 100644 js/src/tests/js1_8/regress/regress-465460-09.js create mode 100644 js/src/tests/js1_8/regress/regress-465460-10.js create mode 100644 js/src/tests/js1_8/regress/regress-465460-11.js create mode 100644 js/src/tests/js1_8/regress/regress-465460-12.js create mode 100644 js/src/tests/js1_8/regress/regress-465483.js create mode 100644 js/src/tests/js1_8/regress/regress-465567-01.js create mode 100644 js/src/tests/js1_8/regress/regress-465567-02.js create mode 100644 js/src/tests/js1_8/regress/regress-465688.js create mode 100644 js/src/tests/js1_8/regress/regress-466128.js create mode 100644 js/src/tests/js1_8/regress/regress-466787.js create mode 100644 js/src/tests/js1_8/regress/regress-467495-01.js create mode 100644 js/src/tests/js1_8/regress/regress-467495-02.js create mode 100644 js/src/tests/js1_8/regress/regress-467495-03.js create mode 100644 js/src/tests/js1_8/regress/regress-467495-04.js create mode 100644 js/src/tests/js1_8/regress/regress-467495-05.js create mode 100644 js/src/tests/js1_8/regress/regress-467495-06.js create mode 100644 js/src/tests/js1_8/regress/regress-468711.js create mode 100755 js/src/tests/js1_8/regress/regress-469547.js create mode 100644 js/src/tests/js1_8/regress/regress-469625-02.js create mode 100644 js/src/tests/js1_8/regress/regress-469625-03.js create mode 100644 js/src/tests/js1_8/regress/regress-471373.js create mode 100644 js/src/tests/js1_8/regress/regress-471660.js create mode 100644 js/src/tests/js1_8/regress/regress-472450-01.js create mode 100644 js/src/tests/js1_8/regress/regress-472450-02.js create mode 100644 js/src/tests/js1_8/regress/regress-472528-01.js create mode 100644 js/src/tests/js1_8/regress/regress-472528-02.js create mode 100644 js/src/tests/js1_8/regress/regress-472703.js create mode 100644 js/src/tests/js1_8/regress/regress-474769.js create mode 100644 js/src/tests/js1_8/regress/regress-474771.js create mode 100644 js/src/tests/js1_8/regress/regress-474935.js create mode 100644 js/src/tests/js1_8/regress/regress-476655.js create mode 100644 js/src/tests/js1_8/regress/regress-477234.js create mode 100644 js/src/tests/js1_8/regress/regress-477581.js create mode 100644 js/src/tests/js1_8/regress/regress-478205.js create mode 100755 js/src/tests/js1_8/regress/regress-479353.js create mode 100644 js/src/tests/js1_8/regress/regress-479740.js create mode 100644 js/src/tests/js1_8/regress/regress-481800.js create mode 100644 js/src/tests/js1_8/regress/regress-483749.js create mode 100644 js/src/tests/js1_8/regress/regress-499524.js create mode 100644 js/src/tests/js1_8/regress/regress-532491.js create mode 100644 js/src/tests/js1_8/regress/shell.js create mode 100644 js/src/tests/js1_8/shell.js create mode 100644 js/src/tests/js1_8/template.js create mode 100644 js/src/tests/js1_8_1/JSON/browser.js create mode 100644 js/src/tests/js1_8_1/JSON/jstests.list create mode 100644 js/src/tests/js1_8_1/JSON/regress-458959.js create mode 100644 js/src/tests/js1_8_1/JSON/regress-459293.js create mode 100644 js/src/tests/js1_8_1/JSON/shell.js create mode 100644 js/src/tests/js1_8_1/README create mode 100644 js/src/tests/js1_8_1/String/browser.js create mode 100644 js/src/tests/js1_8_1/String/jstests.list create mode 100644 js/src/tests/js1_8_1/String/regress-305064.js create mode 100644 js/src/tests/js1_8_1/String/shell.js create mode 100644 js/src/tests/js1_8_1/browser.js create mode 100644 js/src/tests/js1_8_1/decompilation/browser.js create mode 100644 js/src/tests/js1_8_1/decompilation/jstests.list create mode 100644 js/src/tests/js1_8_1/decompilation/regress-346642-01.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-349605.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-349634.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-350991.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-351070-01.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-351336.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-351626.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-352011.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-352022.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-352026.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-352609.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-353249.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-354878.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-371802.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-373678-01.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-380237-03.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-380237-04.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-443074.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-466905-03.js create mode 100644 js/src/tests/js1_8_1/decompilation/regress-530537.js create mode 100644 js/src/tests/js1_8_1/decompilation/shell.js create mode 100644 js/src/tests/js1_8_1/extensions/browser.js create mode 100644 js/src/tests/js1_8_1/extensions/jstests.list create mode 100644 js/src/tests/js1_8_1/extensions/new-parenthesization.js create mode 100644 js/src/tests/js1_8_1/extensions/regress-352281.js create mode 100644 js/src/tests/js1_8_1/extensions/regress-353214-02.js create mode 100644 js/src/tests/js1_8_1/extensions/regress-437288-01.js create mode 100644 js/src/tests/js1_8_1/extensions/regress-452498-162.js create mode 100644 js/src/tests/js1_8_1/extensions/regress-452498-193.js create mode 100644 js/src/tests/js1_8_1/extensions/regress-452498-196.js create mode 100644 js/src/tests/js1_8_1/extensions/regress-452498-224.js create mode 100644 js/src/tests/js1_8_1/extensions/regress-466905-04.js create mode 100644 js/src/tests/js1_8_1/extensions/regress-466905-05.js create mode 100644 js/src/tests/js1_8_1/extensions/regress-477158.js create mode 100644 js/src/tests/js1_8_1/extensions/regress-477187.js create mode 100644 js/src/tests/js1_8_1/extensions/regress-520572.js create mode 100644 js/src/tests/js1_8_1/extensions/shell.js create mode 100644 js/src/tests/js1_8_1/extensions/strict-warning.js create mode 100644 js/src/tests/js1_8_1/jit/browser.js create mode 100644 js/src/tests/js1_8_1/jit/jstests.list create mode 100644 js/src/tests/js1_8_1/jit/math-jit-tests.js create mode 100644 js/src/tests/js1_8_1/jit/regress-451673.js create mode 100644 js/src/tests/js1_8_1/jit/regress-451974-01.js create mode 100644 js/src/tests/js1_8_1/jit/regress-451974-02.js create mode 100644 js/src/tests/js1_8_1/jit/regress-452498-01.js create mode 100644 js/src/tests/js1_8_1/jit/regress-458838.js create mode 100644 js/src/tests/js1_8_1/jit/regress-462459-01.js create mode 100644 js/src/tests/js1_8_1/jit/regress-462459-02.js create mode 100644 js/src/tests/js1_8_1/jit/regress-462459-03.js create mode 100644 js/src/tests/js1_8_1/jit/regress-462459-04.js create mode 100644 js/src/tests/js1_8_1/jit/regress-462459-05.js create mode 100644 js/src/tests/js1_8_1/jit/regress-462459-06.js create mode 100644 js/src/tests/js1_8_1/jit/regress-462459-07.js create mode 100644 js/src/tests/js1_8_1/jit/regress-462459-08.js create mode 100644 js/src/tests/js1_8_1/jit/regress-462459-09.js create mode 100644 js/src/tests/js1_8_1/jit/regress-462459-10.js create mode 100644 js/src/tests/js1_8_1/jit/regress-462459-11.js create mode 100644 js/src/tests/js1_8_1/jit/regress-462459-12.js create mode 100644 js/src/tests/js1_8_1/jit/regress-469927.js create mode 100644 js/src/tests/js1_8_1/jit/regress-470739.js create mode 100644 js/src/tests/js1_8_1/jit/regress-471635.js create mode 100644 js/src/tests/js1_8_1/jit/regress-489682.js create mode 100644 js/src/tests/js1_8_1/jit/shell.js create mode 100644 js/src/tests/js1_8_1/jit/testDeepBailFromNonNative.js create mode 100644 js/src/tests/js1_8_1/jstests.list create mode 100644 js/src/tests/js1_8_1/regress/browser.js create mode 100644 js/src/tests/js1_8_1/regress/jstests.list create mode 100644 js/src/tests/js1_8_1/regress/regress-420399.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-006.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-027.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-030.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-038.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-039.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-040.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-050.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-051.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-052-a.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-052.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-053.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-054.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-058.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-062.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-063.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-068.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-071.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-072.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-073.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-074.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-075.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-076.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-077.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-079.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-082.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-091.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-092.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-098.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-099-a.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-099.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-101.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-102.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-103.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-104.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-107.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-108.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-110.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-111.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-112.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-114-a.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-114.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-116.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-117.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-118.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-119.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-121.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-123.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-129.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-130.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-131.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-135-a.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-135.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-138.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-139.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-155.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-160.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-168-1.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-168-2.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-176.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-178.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-181.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-184.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-185.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-187.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-191.js create mode 100644 js/src/tests/js1_8_1/regress/regress-452498-192.js create mode 100644 js/src/tests/js1_8_1/regress/regress-466905-01.js create mode 100644 js/src/tests/js1_8_1/regress/regress-466905-02.js create mode 100644 js/src/tests/js1_8_1/regress/regress-479430-01.js create mode 100644 js/src/tests/js1_8_1/regress/regress-479430-02.js create mode 100644 js/src/tests/js1_8_1/regress/regress-479430-03.js create mode 100644 js/src/tests/js1_8_1/regress/regress-479430-04.js create mode 100644 js/src/tests/js1_8_1/regress/regress-479430-05.js create mode 100644 js/src/tests/js1_8_1/regress/regress-495773.js create mode 100644 js/src/tests/js1_8_1/regress/regress-495907.js create mode 100644 js/src/tests/js1_8_1/regress/regress-496922.js create mode 100644 js/src/tests/js1_8_1/regress/regress-507053.js create mode 100644 js/src/tests/js1_8_1/regress/regress-507295.js create mode 100644 js/src/tests/js1_8_1/regress/regress-507424.js create mode 100644 js/src/tests/js1_8_1/regress/regress-509354.js create mode 100644 js/src/tests/js1_8_1/regress/regress-515885.js create mode 100644 js/src/tests/js1_8_1/regress/regress-522123.js create mode 100644 js/src/tests/js1_8_1/regress/regress-524264.js create mode 100644 js/src/tests/js1_8_1/regress/regress-524743.js create mode 100644 js/src/tests/js1_8_1/regress/regress-530879.js create mode 100644 js/src/tests/js1_8_1/regress/shell.js create mode 100644 js/src/tests/js1_8_1/shell.js create mode 100644 js/src/tests/js1_8_1/strict/12.2.1.js create mode 100644 js/src/tests/js1_8_1/strict/8.7.2.js create mode 100644 js/src/tests/js1_8_1/strict/generator-eval-arguments.js create mode 100644 js/src/tests/js1_8_1/strict/jstests.list create mode 100644 js/src/tests/js1_8_1/strict/let-block-eval-arguments.js create mode 100644 js/src/tests/js1_8_1/strict/shell.js create mode 100644 js/src/tests/js1_8_1/template.js create mode 100644 js/src/tests/js1_8_5/README create mode 100644 js/src/tests/js1_8_5/browser.js create mode 100644 js/src/tests/js1_8_5/extensions/array-length-protochange.js create mode 100644 js/src/tests/js1_8_5/extensions/browser.js create mode 100644 js/src/tests/js1_8_5/extensions/censor-strict-caller.js create mode 100644 js/src/tests/js1_8_5/extensions/clone-errors.js create mode 100644 js/src/tests/js1_8_5/extensions/clone-forge.js create mode 100644 js/src/tests/js1_8_5/extensions/clone-leaf-object.js create mode 100644 js/src/tests/js1_8_5/extensions/clone-object.js create mode 100644 js/src/tests/js1_8_5/extensions/clone-regexp.js create mode 100644 js/src/tests/js1_8_5/extensions/clone-simple.js create mode 100644 js/src/tests/js1_8_5/extensions/clone-typed-array.js create mode 100644 js/src/tests/js1_8_5/extensions/destructure-accessor.js create mode 100644 js/src/tests/js1_8_5/extensions/jstests.list create mode 100644 js/src/tests/js1_8_5/extensions/parseInt-octal.js create mode 100644 js/src/tests/js1_8_5/extensions/proxy-enumerateOwn-duplicates.js create mode 100644 js/src/tests/js1_8_5/extensions/proxy-proto-setter.js create mode 100644 js/src/tests/js1_8_5/extensions/recursion.js create mode 100644 js/src/tests/js1_8_5/extensions/reflect-parse.js create mode 100644 js/src/tests/js1_8_5/extensions/regress-627984-1.js create mode 100644 js/src/tests/js1_8_5/extensions/regress-627984-2.js create mode 100644 js/src/tests/js1_8_5/extensions/regress-627984-3.js create mode 100644 js/src/tests/js1_8_5/extensions/regress-627984-4.js create mode 100644 js/src/tests/js1_8_5/extensions/regress-627984-5.js create mode 100644 js/src/tests/js1_8_5/extensions/regress-627984-6.js create mode 100644 js/src/tests/js1_8_5/extensions/regress-627984-7.js create mode 100644 js/src/tests/js1_8_5/extensions/regress-630377.js create mode 100644 js/src/tests/js1_8_5/extensions/regress-631723.js create mode 100644 js/src/tests/js1_8_5/extensions/scripted-proxies.js create mode 100644 js/src/tests/js1_8_5/extensions/set-property-non-extensible.js create mode 100644 js/src/tests/js1_8_5/extensions/shell.js create mode 100644 js/src/tests/js1_8_5/extensions/typedarray-prototype.js create mode 100644 js/src/tests/js1_8_5/extensions/typedarray.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-error-child.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-error-propagation-child.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-error-propagation.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-error.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-fib-child.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-fib.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-init-child.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-init.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-simple-child.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-simple.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-terminate-child.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-terminate-iloop.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-terminate.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-timeout-child.js create mode 100644 js/src/tests/js1_8_5/extensions/worker-timeout.js create mode 100644 js/src/tests/js1_8_5/jstests.list create mode 100644 js/src/tests/js1_8_5/regress/browser.js create mode 100644 js/src/tests/js1_8_5/regress/jstests.list create mode 100644 js/src/tests/js1_8_5/regress/regress-500528.js create mode 100644 js/src/tests/js1_8_5/regress/regress-533876.js create mode 100644 js/src/tests/js1_8_5/regress/regress-541255-0.js create mode 100644 js/src/tests/js1_8_5/regress/regress-541255-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-541255-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-541255-3.js create mode 100644 js/src/tests/js1_8_5/regress/regress-541255-4.js create mode 100644 js/src/tests/js1_8_5/regress/regress-541455.js create mode 100644 js/src/tests/js1_8_5/regress/regress-546615.js create mode 100644 js/src/tests/js1_8_5/regress/regress-548276.js create mode 100644 js/src/tests/js1_8_5/regress/regress-551763-0.js create mode 100644 js/src/tests/js1_8_5/regress/regress-551763-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-551763-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-552432.js create mode 100644 js/src/tests/js1_8_5/regress/regress-553778.js create mode 100644 js/src/tests/js1_8_5/regress/regress-555246-0.js create mode 100644 js/src/tests/js1_8_5/regress/regress-555246-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-559402-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-559402-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-559438.js create mode 100644 js/src/tests/js1_8_5/regress/regress-560101.js create mode 100644 js/src/tests/js1_8_5/regress/regress-560998-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-560998-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-563210.js create mode 100644 js/src/tests/js1_8_5/regress/regress-563221.js create mode 100644 js/src/tests/js1_8_5/regress/regress-566549.js create mode 100644 js/src/tests/js1_8_5/regress/regress-566914.js create mode 100644 js/src/tests/js1_8_5/regress/regress-567152.js create mode 100644 js/src/tests/js1_8_5/regress/regress-569306.js create mode 100644 js/src/tests/js1_8_5/regress/regress-569464.js create mode 100644 js/src/tests/js1_8_5/regress/regress-571014.js create mode 100644 js/src/tests/js1_8_5/regress/regress-573875.js create mode 100644 js/src/tests/js1_8_5/regress/regress-576847.js create mode 100644 js/src/tests/js1_8_5/regress/regress-577648-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-577648-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-583429.js create mode 100644 js/src/tests/js1_8_5/regress/regress-584355.js create mode 100644 js/src/tests/js1_8_5/regress/regress-584578.js create mode 100644 js/src/tests/js1_8_5/regress/regress-584648.js create mode 100644 js/src/tests/js1_8_5/regress/regress-585257.js create mode 100644 js/src/tests/js1_8_5/regress/regress-586482-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-586482-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-586482-3.js create mode 100644 js/src/tests/js1_8_5/regress/regress-586482-4.js create mode 100644 js/src/tests/js1_8_5/regress/regress-586482-5.js create mode 100644 js/src/tests/js1_8_5/regress/regress-588339.js create mode 100644 js/src/tests/js1_8_5/regress/regress-591846.js create mode 100644 js/src/tests/js1_8_5/regress/regress-591897.js create mode 100644 js/src/tests/js1_8_5/regress/regress-592202-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-592202-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-592202-3.js create mode 100644 js/src/tests/js1_8_5/regress/regress-592202-4.js create mode 100644 js/src/tests/js1_8_5/regress/regress-592217.js create mode 100644 js/src/tests/js1_8_5/regress/regress-592556-c35.js create mode 100644 js/src/tests/js1_8_5/regress/regress-593256.js create mode 100644 js/src/tests/js1_8_5/regress/regress-595230-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-595230-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-595365-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-595365-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-596103.js create mode 100644 js/src/tests/js1_8_5/regress/regress-596805-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-596805-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-597870.js create mode 100644 js/src/tests/js1_8_5/regress/regress-597945-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-597945-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-598176.js create mode 100644 js/src/tests/js1_8_5/regress/regress-600067.js create mode 100644 js/src/tests/js1_8_5/regress/regress-600137.js create mode 100644 js/src/tests/js1_8_5/regress/regress-601399.js create mode 100644 js/src/tests/js1_8_5/regress/regress-602621.js create mode 100644 js/src/tests/js1_8_5/regress/regress-607799.js create mode 100644 js/src/tests/js1_8_5/regress/regress-607863.js create mode 100644 js/src/tests/js1_8_5/regress/regress-609617.js create mode 100644 js/src/tests/js1_8_5/regress/regress-610026.js create mode 100644 js/src/tests/js1_8_5/regress/regress-617405-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-617405-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-618572.js create mode 100644 js/src/tests/js1_8_5/regress/regress-618574.js create mode 100644 js/src/tests/js1_8_5/regress/regress-618576.js create mode 100644 js/src/tests/js1_8_5/regress/regress-618652.js create mode 100644 js/src/tests/js1_8_5/regress/regress-619003-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-619003-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-620376-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-620376-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-620750.js create mode 100644 js/src/tests/js1_8_5/regress/regress-621814.js create mode 100644 js/src/tests/js1_8_5/regress/regress-624199.js create mode 100644 js/src/tests/js1_8_5/regress/regress-624547.js create mode 100644 js/src/tests/js1_8_5/regress/regress-624968.js create mode 100644 js/src/tests/js1_8_5/regress/regress-626436.js create mode 100644 js/src/tests/js1_8_5/regress/regress-633741.js create mode 100644 js/src/tests/js1_8_5/regress/regress-634210-1.js create mode 100644 js/src/tests/js1_8_5/regress/regress-634210-2.js create mode 100644 js/src/tests/js1_8_5/regress/regress-634210-3.js create mode 100644 js/src/tests/js1_8_5/regress/regress-634210-4.js create mode 100644 js/src/tests/js1_8_5/regress/regress-635195.js create mode 100644 js/src/tests/js1_8_5/regress/regress-636364.js create mode 100644 js/src/tests/js1_8_5/regress/regress-yarr-regexp.js create mode 100644 js/src/tests/js1_8_5/regress/shell.js create mode 100644 js/src/tests/js1_8_5/shell.js create mode 100644 js/src/tests/js1_8_5/template.js create mode 100644 js/src/tests/jsreftest.html create mode 100644 js/src/tests/jstests.list create mode 100755 js/src/tests/jstests.py create mode 100755 js/src/tests/known-failures.pl create mode 100644 js/src/tests/manifest.py create mode 100644 js/src/tests/menufoot.html create mode 100644 js/src/tests/menuhead.html create mode 100644 js/src/tests/menuhead.js create mode 100644 js/src/tests/mkhtml.pl create mode 100644 js/src/tests/mklistpage.pl create mode 100644 js/src/tests/most.tests create mode 100644 js/src/tests/narcissus-failures.txt create mode 100644 js/src/tests/narcissus.README create mode 100644 js/src/tests/narcissus.list create mode 100644 js/src/tests/parsemark.py create mode 100755 js/src/tests/pattern-expander.pl create mode 100755 js/src/tests/pattern-extracter.pl create mode 100644 js/src/tests/performance-1.8.0.tests create mode 100644 js/src/tests/performance-1.8.1.tests create mode 100644 js/src/tests/performance-1.9.0.tests create mode 100644 js/src/tests/performance-1.9.1.tests create mode 100644 js/src/tests/performance-1.9.2.tests create mode 100644 js/src/tests/performance.tests create mode 100755 js/src/tests/post-process-logs.pl create mode 100755 js/src/tests/process-logs.sh create mode 100644 js/src/tests/progressbar.py create mode 100755 js/src/tests/remove-fixed-failures.sh create mode 100755 js/src/tests/runtests.sh create mode 100644 js/src/tests/shell.js create mode 100644 js/src/tests/slow-n-1.8.1-browser.tests create mode 100644 js/src/tests/slow-n-1.8.1.tests create mode 100644 js/src/tests/slow-n-1.9.0-browser.tests create mode 100644 js/src/tests/slow-n-1.9.0.tests create mode 100644 js/src/tests/slow-n-1.9.1-browser.tests create mode 100644 js/src/tests/slow-n-1.9.1.tests create mode 100644 js/src/tests/slow-n-1.9.2-browser.tests create mode 100644 js/src/tests/slow-n-1.9.2.tests create mode 100644 js/src/tests/slow-n.tests create mode 100644 js/src/tests/slow-narcissus.txt create mode 100644 js/src/tests/spidermonkey-gc.tests create mode 100755 js/src/tests/spidermonkey-n-1.8.0.tests create mode 100755 js/src/tests/spidermonkey-n-1.8.1.tests create mode 100755 js/src/tests/spidermonkey-n-1.9.0.tests create mode 100755 js/src/tests/spidermonkey-n-1.9.1.tests create mode 100644 js/src/tests/spidermonkey-n-1.9.2.tests create mode 100644 js/src/tests/spidermonkey-n-1.9.3.tests create mode 100755 js/src/tests/spidermonkey-n.tests create mode 100644 js/src/tests/src/jstests.jar create mode 100755 js/src/tests/test.sh create mode 100644 js/src/tests/tests.py create mode 100755 js/src/tests/user.js create mode 100644 js/src/tests/userhookeach.js create mode 100644 js/src/tests/workers.py create mode 100755 js/src/time.sh create mode 100644 js/src/tracejit/Writer.cpp create mode 100644 js/src/tracejit/Writer.h create mode 100644 js/src/tracevis/README create mode 100644 js/src/tracevis/acts.py create mode 100644 js/src/tracevis/binlog.py create mode 100644 js/src/tracevis/config.py create mode 100644 js/src/tracevis/tree.py create mode 100644 js/src/tracevis/vis.py create mode 100644 js/src/v8-dtoa/README create mode 100644 js/src/v8-dtoa/cached-powers.h create mode 100644 js/src/v8-dtoa/checks.cc create mode 100644 js/src/v8-dtoa/checks.h create mode 100644 js/src/v8-dtoa/conversions.cc create mode 100644 js/src/v8-dtoa/conversions.h create mode 100644 js/src/v8-dtoa/diy-fp.cc create mode 100644 js/src/v8-dtoa/diy-fp.h create mode 100644 js/src/v8-dtoa/double.h create mode 100644 js/src/v8-dtoa/dtoa.h create mode 100644 js/src/v8-dtoa/fast-dtoa.cc create mode 100644 js/src/v8-dtoa/fast-dtoa.h create mode 100644 js/src/v8-dtoa/globals.h create mode 100644 js/src/v8-dtoa/include-v8.h create mode 100644 js/src/v8-dtoa/platform.cc create mode 100644 js/src/v8-dtoa/platform.h create mode 100644 js/src/v8-dtoa/powers-ten.h create mode 100644 js/src/v8-dtoa/utils.cc create mode 100644 js/src/v8-dtoa/utils.h create mode 100644 js/src/v8-dtoa/v8-dtoa.cc create mode 100644 js/src/v8-dtoa/v8.h create mode 100644 js/src/v8/base.js create mode 100644 js/src/v8/crypto.js create mode 100644 js/src/v8/deltablue.js create mode 100644 js/src/v8/earley-boyer.js create mode 100644 js/src/v8/raytrace.js create mode 100644 js/src/v8/richards.js create mode 100644 js/src/v8/run-crypto.js create mode 100644 js/src/v8/run-deltablue.js create mode 100644 js/src/v8/run-earley-boyer.js create mode 100644 js/src/v8/run-raytrace.js create mode 100644 js/src/v8/run-richards.js create mode 100644 js/src/v8/run.js create mode 100644 js/src/vprof/manifest.mk create mode 100644 js/src/vprof/readme.txt create mode 100644 js/src/vprof/testVprofMT.c create mode 100644 js/src/vprof/vprof.cpp create mode 100644 js/src/vprof/vprof.h create mode 100644 js/src/yarr/Makefile create mode 100644 js/src/yarr/jswtfbridge.h create mode 100644 js/src/yarr/pcre/AUTHORS create mode 100644 js/src/yarr/pcre/COPYING create mode 100644 js/src/yarr/pcre/chartables.c create mode 100644 js/src/yarr/pcre/dftables create mode 100644 js/src/yarr/pcre/pcre.h create mode 100644 js/src/yarr/pcre/pcre.pri create mode 100644 js/src/yarr/pcre/pcre_compile.cpp create mode 100644 js/src/yarr/pcre/pcre_exec.cpp create mode 100644 js/src/yarr/pcre/pcre_internal.h create mode 100644 js/src/yarr/pcre/pcre_tables.cpp create mode 100644 js/src/yarr/pcre/pcre_ucp_searchfuncs.cpp create mode 100644 js/src/yarr/pcre/pcre_xclass.cpp create mode 100644 js/src/yarr/pcre/ucpinternal.h create mode 100644 js/src/yarr/pcre/ucptable.cpp create mode 100644 js/src/yarr/wtf/ASCIICType.h create mode 100644 js/src/yarr/yarr/RegExpJitTables.h create mode 100644 js/src/yarr/yarr/RegexCommon.h create mode 100644 js/src/yarr/yarr/RegexCompiler.cpp create mode 100644 js/src/yarr/yarr/RegexCompiler.h create mode 100644 js/src/yarr/yarr/RegexJIT.cpp create mode 100644 js/src/yarr/yarr/RegexJIT.h create mode 100644 js/src/yarr/yarr/RegexParser.h create mode 100644 js/src/yarr/yarr/RegexPattern.h create mode 100644 patches/bug-586016.patch create mode 100644 patches/bug-630209.patch create mode 100644 patches/libname-changes.patch diff --git a/.hgtags b/.hgtags new file mode 100644 index 0000000..e8fa99d --- /dev/null +++ b/.hgtags @@ -0,0 +1 @@ +721f9b43513e24e14c669113fd34b730457a4509 js185-1.0.0 diff --git a/README b/README new file mode 100644 index 0000000..ba8f340 --- /dev/null +++ b/README @@ -0,0 +1,59 @@ +1. The latest release notes for SpiderMonkey can be found at: + + https://developer.mozilla.org/En/SpiderMonkey/1.8.5 + + +2. js/jsd contains code for debugging support for the JavaScript engine in js/src. + + +Packaging Notes +--------------- +This release is based on revision 5f8f494a4c29 of https://hg.mozilla.org/releases/mozilla-2.0, with +a few trivial changes applied to improve the manageability of the standalone-release. In addition +to running autoconf 2.13 before bundling the release, the changes in the patches directory were +applied. + +This standalone release introduces a new, experimental, naming convention for the SpiderMonkey +shared library. This naming convention will not be rolled back into the mainline Mozilla source +tree, however the relevant patches are included with this distribution. + +Note: Please copy wes@page.ca on bugs related to packaging this standalone release. + +Linux and non-Mac OS X Unices +----------------------------- +Previous releases and the master source repositories build a shared library named libmozjs.so. In +an effort to make version identification easier for embedders and OS distribution maintainers, this +standalone release builds libmozjs185.so.1.0.0 (.dylib.1.0.0 on Mac OS X). + +libmozjs185 indicates that this is the SpiderMonkey library which implements JavaScript 1.8.5. The +1.0.0 suffix is of the form major.minor.micro revision. While it is unlikely that more than one +official source release for a given version of JavaScript will be published, it has happened in the +past (e.g JS 1.4-1), and we want to provide clear direction in case there is a compelling need: + +* a change in major revision number indicates a change which is ABI and API incompatible with the + previous release, + +* a change in minor revision number indicates a change which is ABI incompatible, but API + compatible with the previous release, + +* a change in micro revision number indicates a change which is both ABI and API compatible with + the previous release. + +A symbolic link will be provided linking libmoz185.js.so to this library, along with +libmoz185.js.so.1.0 when building the install target. + +Most embeddings building on Unix or Linux should link against libmozjs185.so.1.0. + +The static library has been renamed, from libjs_static.a to libmozjs185-1.0.a. + +Mac OS X +-------- +The versioning rules and symbolic links are the same as for the other flavours of Unix, but the +library name is now libmozjs185.1.0.0.dylib. + +Most embeddings building on Mac OS X should link against libmozjs185.1.0.dylib. + +Microsoft Windows +----------------- +The versioning rules are the same as for Unix, but the the library name is now +libmozjs185-1.0.dll. Symbolic links will not be created. diff --git a/js/jsd/Makefile.in b/js/jsd/Makefile.in new file mode 100644 index 0000000..fb2500a --- /dev/null +++ b/js/jsd/Makefile.in @@ -0,0 +1,103 @@ +#!gmake +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +VPATH = @srcdir@ +srcdir = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = jsdebug +LIBRARY_NAME = jsd +FORCE_SHARED_LIB= 1 +ifeq ($(OS_ARCH)$(MOZ_ENABLE_LIBXUL),WINNT) +LIBRARY_NAME = jsd32$(VERSION_NUMBER) +endif + +# REQUIRES = java js + + +EXTRA_DSO_LDOPTS += \ + $(MOZ_COMPONENT_LIBS) \ + $(MOZ_JS_LIBS) \ + $(NULL) +EXPORTS = jsdebug.h + +ifdef JS_THREADSAFE +DEFINES += -DJS_THREADSAFE +endif + +CSRCS = \ + jsdebug.c \ + jsd_atom.c \ + jsd_high.c \ + jsd_hook.c \ + jsd_lock.c \ + jsd_obj.c \ + jsd_scpt.c \ + jsd_stak.c \ + jsd_step.c \ + jsd_text.c \ + jsd_val.c \ + $(NULL) + +ifdef JSD_STANDALONE +DIRS += jsdb +else +DIRS += idl +CPPSRCS = jsd_xpc.cpp +IS_COMPONENT = 1 +LIBXUL_LIBRARY = 1 + +ifdef MOZ_ENABLE_LIBXUL +FORCE_SHARED_LIB= +MODULE_NAME = JavaScript_Debugger +EXPORT_LIBRARY = 1 +endif +endif + +ifdef ENABLE_TESTS +TOOL_DIRS += test +endif + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_JSD_API diff --git a/js/jsd/README b/js/jsd/README new file mode 100644 index 0000000..25295a8 --- /dev/null +++ b/js/jsd/README @@ -0,0 +1,6 @@ +js/jsd contains code for debugging support for the C-based JavaScript engine +in js/src. jsd_xpc.cpp provides an XPCOM binding for the library. + +js/jsd/jsdb is a console debugger using only native code (see README in that +directory.) This debugger is no longer being actively developed, though it +should work. diff --git a/js/jsd/idl/Makefile.in b/js/jsd/idl/Makefile.in new file mode 100644 index 0000000..03f8275 --- /dev/null +++ b/js/jsd/idl/Makefile.in @@ -0,0 +1,52 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = jsdebug +XPIDL_MODULE = jsdservice + +XPIDLSRCS = \ + jsdIDebuggerService.idl \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/js/jsd/idl/jsdIDebuggerService.idl b/js/jsd/idl/jsdIDebuggerService.idl new file mode 100644 index 0000000..2a0c187 --- /dev/null +++ b/js/jsd/idl/jsdIDebuggerService.idl @@ -0,0 +1,1303 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert Ginda, + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +%{ C++ +#include "jsdebug.h" +#include "nsAString.h" +%} + +[ptr] native JSDContext(JSDContext); +[ptr] native JSDObject(JSDObject); +[ptr] native JSDProperty(JSDProperty); +[ptr] native JSDScript(JSDScript); +[ptr] native JSDStackFrameInfo(JSDStackFrameInfo); +[ptr] native JSDThreadState(JSDThreadState); +[ptr] native JSDValue(JSDValue); +[ptr] native JSRuntime(JSRuntime); +[ptr] native JSContext(JSContext); +[ptr] native JSCompartment(JSCompartment); + +/* interfaces we declare in this file */ +interface jsdIDebuggerService; +interface jsdIFilter; +interface jsdINestCallback; +interface jsdIFilterEnumerator; +interface jsdIContextEnumerator; +interface jsdIScriptEnumerator; +interface jsdIScriptHook; +interface jsdIErrorHook; +interface jsdIExecutionHook; +interface jsdICallHook; +interface jsdIEphemeral; +interface jsdIContext; +interface jsdIStackFrame; +interface jsdIScript; +interface jsdIValue; +interface jsdIObject; +interface jsdIProperty; +interface jsdIActivationCallback; + +/** + * Debugger service. It's not a good idea to have more than one active client of + * the debugger service. + */ +[scriptable, uuid(aa232c7f-855f-4488-a92c-6f89adc668cc)] +interface jsdIDebuggerService : nsISupports +{ + /** Internal use only. */ + [noscript] readonly attribute JSDContext JSDContext; + + /** + * Called when an error or warning occurs. + */ + attribute jsdIErrorHook errorHook; + /** + * Called when a jsdIScript is created or destroyed. + */ + attribute jsdIScriptHook scriptHook; + /** + * Called when the engine encounters a breakpoint. + */ + attribute jsdIExecutionHook breakpointHook; + /** + * Called when the engine encounters the debugger keyword. + */ + attribute jsdIExecutionHook debuggerHook; + /** + * Called when the errorHook returns false. + */ + attribute jsdIExecutionHook debugHook; + /** + * Called before the next PC is executed. + */ + attribute jsdIExecutionHook interruptHook; + /** + * Called when an exception is thrown (even if it will be caught.) + */ + attribute jsdIExecutionHook throwHook; + /** + * Called before and after a toplevel script is evaluated. + */ + attribute jsdICallHook topLevelHook; + /** + * Called before and after a function is called. + */ + attribute jsdICallHook functionHook; + + + /** + * VERSION_* values must be kept in sync with the JSVersion enumeration in + * jspubtd.h. + */ + + /** + * Possible values for jsdIScript::version and jsdIContext::version. + */ + const long VERSION_1_0 = 100; + const long VERSION_1_1 = 110; + const long VERSION_1_2 = 120; + const long VERSION_1_3 = 130; + const long VERSION_1_4 = 140; + const long VERSION_1_5 = 150; + const long VERSION_DEFAULT = 0; + const long VERSION_UNKNOWN = -1; + + /** + * These flags need to be kept in sync with the context flags defined in + * jsdebug.h + */ + + /** + * Link native frames in call stacks. + */ + const unsigned long ENABLE_NATIVE_FRAMES = 0x01; + /** + * Normally, if a script has a 0 in JSD_SCRIPT_PROFILE_BIT it is included in + * profile data, otherwise it is not profiled. Setting the + * PROFILE_WHEN_SET flag reverses this convention. + */ + const unsigned long PROFILE_WHEN_SET = 0x02; + /** + * Normally, when the script in the top frame of a thread state has a 1 in + * JSD_SCRIPT_DEBUG_BIT, the execution hook is ignored. Setting the + * DEBUG_WHEN_SET flag reverses this convention. + */ + const unsigned long DEBUG_WHEN_SET = 0x04; + /** + * When this flag is set the internal call hook will collect profile data. + */ + const unsigned long COLLECT_PROFILE_DATA = 0x08; + /** + * When this flag is set, stack frames that are disabled for debugging + * will not appear in the call stack chain. + */ + const unsigned long HIDE_DISABLED_FRAMES = 0x10; + /** + * When this flag is set, the debugger will only check the + * JSD_SCRIPT_DEBUG_BIT on the top (most recent) stack frame. This + * makes it possible to stop in an enabled frame which was called from + * a stack that contains a disabled frame. + * + * When this flag is *not* set, any stack that contains a disabled frame + * will not be debugged (the execution hook will not be invoked.) + * + * This only applies when the reason for calling the hook would have + * been TYPE_INTERRUPTED or TYPE_THROW. TYPE_BREAKPOINT, + * TYPE_DEBUG_REQUESTED, and TYPE_DEBUGGER_KEYWORD always stop, regardless + * of this setting, as long as the top frame is not disabled. + * + * If HIDE_DISABLED_FRAMES is set, this is effectively set as well. + */ + const unsigned long MASK_TOP_FRAME_ONLY = 0x20; + /** + * This flag has been retired, do not re-use. It previously provided a hook + * for object allocation. + */ + const unsigned long DISABLE_OBJECT_TRACE_RETIRED = 0x40; + + /** + * Debugger service flags. + */ + attribute unsigned long flags; + + /** + * Major version number of implementation. + */ + readonly attribute unsigned long implementationMajor; + /** + * Minor version number of implementation. + */ + readonly attribute unsigned long implementationMinor; + /** + * Free form AUTF8String identifier for implementation. + */ + readonly attribute AUTF8String implementationString; + + /** + * |true| if the debugger service has been turned on. This does not + * necessarily mean another app is actively using the service, as the + * autostart pref may have turned the service on. + */ + readonly attribute boolean isOn; + + + /** + * Synchronous activation of the debugger is no longer supported, + * and will throw an exception. + */ + void on (); + + /** + * Turn on the debugger. This function should only be called from JavaScript + * code. The debugger will be enabled on the runtime the call is made on, + * as determined by nsIXPCNativeCallContext. + * + * The debugger will be activated asynchronously, because there can be no JS + * on the stack when code is to be re-compiled for debug mode. + */ + void asyncOn (in jsdIActivationCallback callback); + + /** + * Called by nsIXPConnect after it's had a chance to recompile for + * debug mode. + */ + [noscript] void activateDebugger(in JSRuntime rt); + + /** + * Called by nsIXPConnect to deactivate debugger on setup failure. + */ + [noscript] void deactivateDebugger(); + + /** + * Recompile all active scripts in the runtime for debugMode. + */ + [noscript] void recompileForDebugMode(in JSContext cx, in JSCompartment comp, in PRBool mode); + + /** + * Turn the debugger off. This will invalidate all of your jsdIEphemeral + * derived objects, and clear all of your breakpoints. In theory you + * should be able to turn the debugger back on at some later time without + * any problems. + */ + void off (); + + /** + * Peek at the current pause depth of the debugger. + * + * @return depth Number of pause() calls still waiting to be unPause()d. + */ + readonly attribute unsigned long pauseDepth; + /** + * Temporarily disable the debugger. Hooks will not be called while the + * debugger is paused. Multiple calls to pause will increase the "pause + * depth", and equal number of unPause calles must be made to resume + * normal debugging. + * + * @return depth Number of times pause has been called since the debugger + * has been unpaused. + */ + unsigned long pause(); + /** + * Undo a pause. + * + * @return depth The number of remaining pending pause calls. + */ + unsigned long unPause(); + + /** + * Force the engine to perform garbage collection. + */ + void GC(); + + /** + * Clear profile data for all scripts. + */ + void clearProfileData(); + + /** + * Adds an execution hook filter. These filters are consulted each time one + * of the jsdIExecutionHooks is about to be called. Filters are matched in + * a first in, first compared fashion. The first filter to match determines + * whether or not the hook is called. Use swapFilter to reorder existing + * filters, and removeFilter to remove them. + * + * If |filter| is already present this method throws NS_ERROR_INVALID_ARG. + * + * @param filter Object representing the filter to add. + * @param after Insert |filter| after this one. Pass null to insert at + * the beginning. + */ + void insertFilter (in jsdIFilter filter, in jsdIFilter after); + /** + * Same as insertFilter, except always add to the end of the list. + */ + void appendFilter (in jsdIFilter filter); + /** + * Remove a filter. + * + * If |filter| is not present this method throws NS_ERROR_INVALID_ARG. + * + * @param filter Object representing the filter to remove. Must be the exact + * object passed to addFilter, not just a new object with the same + * properties. + */ + void removeFilter (in jsdIFilter filter); + /** + * Swap position of two filters. + * + * If |filter_a| is not present, this method throws NS_ERROR_INVALID_ARG. + * If |filter_b| is not present, filter_a is replaced by filter_b. + * If |filter_a| == |filter_b|, then filter is refreshed. + */ + void swapFilters (in jsdIFilter filter_a, in jsdIFilter filter_b); + /** + * Enumerate registered filters. This routine refreshes each filter before + * passing them on to the enumeration function. Calling this with a null + * |enumerator| is equivalent to jsdIService::refreshFilters. + * + * @param enumerator jsdIFilterEnumerator instance to be called back for the + * enumeration. + */ + void enumerateFilters (in jsdIFilterEnumerator enumerator); + /** + * Force the debugger to resync its internal filter cache with the + * actual values in the jsdIFilter objects. To refresh a single filter + * use jsdIService::swapFilters. This method is equivalent to + * jsdIService::enumerateFilters with a null enumerator. + */ + void refreshFilters (); + /** + * Clear the list of filters. + */ + void clearFilters(); + + /** + * Enumerate all known contexts. + */ + void enumerateContexts (in jsdIContextEnumerator enumerator); + + /** + * Enumerate all scripts the debugger knows about. Any scripts created + * before you turned the debugger on, or after turning the debugger off + * will not be available unless the autostart perf is set. + * + * @param enumerator jsdIScriptEnumerator instance to be called back for + * the enumeration. + */ + void enumerateScripts (in jsdIScriptEnumerator enumerator); + /** + * Clear all breakpoints in all scripts. + */ + void clearAllBreakpoints (); + + /** + * When called from JavaScript, this method returns the jsdIValue wrapper + * for the given value. If a wrapper does not exist one will be created. + * When called from another language this method returns an xpconnect + * defined error code. + */ + jsdIValue wrapValue (/*in jsvalue value*/); + + /** + * The same as above but to be called from C++. + */ + [noscript] jsdIValue wrapJSValue (in jsval value); + + /* XXX these two routines are candidates for refactoring. The only problem + * is that it is not clear where and how they should land. + */ + + /** + * Push a new network queue, and enter a new UI event loop. + * @param callback jsdINestCallback instance to be called back after the + * network queue has been pushed, but before the + * UI loop starts. + * @return depth returns the current number of times the event loop has been + * nested. your code can use it for sanity checks. + */ + unsigned long enterNestedEventLoop (in jsdINestCallback callback); + /** + * Exit the current nested event loop after the current iteration completes, + * and pop the network event queue. + * + * @return depth returns the current number of times the event loop has been + * nested. your code can use it for sanity checks. + */ + unsigned long exitNestedEventLoop (); + + /** + * Output dump of JS heap. + * + * @param fileName Filename to dump the heap into. + */ + void dumpHeap (in AUTF8String fileName); +}; + +/* callback interfaces */ + +/** + * Object representing a pattern of global object and/or url the debugger should + * ignore. The debugger service itself will not modify properties of these + * objects. + */ +[scriptable, uuid(0c9189d9-4287-47a4-bca6-6ed65aaf737f)] +interface jsdIFilter : nsISupports +{ + /** + * These two bytes of the flags attribute are reserved for interpretation + * by the jsdService implementation. You can do what you like with the + * remaining flags. + */ + const unsigned long FLAG_RESERVED_MASK = 0xFF; + /** + * Filters without this flag set are ignored. + */ + const unsigned long FLAG_ENABLED = 0x01; + /** + * Filters with this flag set are "pass" filters, they allow matching hooks + * to continue. Filters without this flag block matching hooks. + */ + const unsigned long FLAG_PASS = 0x02; + + /** + * FLAG_* values from above, OR'd together. + */ + attribute unsigned long flags; + + /** + * An nsISupports version of the global object to be filtered. A null glob + * matches all hooks. This attribute must be QI'able to the + * (non-scriptable) nsIScriptGlobalObject interface. + * + * The jsdIService caches this value internally, so if it changes you must + * swap the filter with itself using jsdIService::swapFilters. + */ + attribute nsISupports globalObject; + + /** + * String representing the url pattern to be filtered. Supports limited + * glob matching, at the beginning and end of the pattern only. For example, + * "chrome://venkman*" filters all urls that start with chrome/venkman, + * "*.cgi" filters all cgi's, and "http://myserver/utils.js" filters only + * the utils.js file on "myserver". A null urlPattern matches all urls. + * + * The jsdIService caches this value internally, to if it changes you must + * swap the filter with itself using jsdIService::swapFilters. + */ + attribute AUTF8String urlPattern; + + /** + * Line number for the start of this filter. Line numbers are one based. + * Assigning a 0 to this attribute will tell the debugger to ignore the + * entire file. + */ + attribute unsigned long startLine; + + /** + * Line number for the end of this filter. Line numbers are one based. + * Assigning a 0 to this attribute will tell the debugger to ignore from + * |startLine| to the end of the file. + */ + attribute unsigned long endLine; +}; + +/** + * Notify client code that debugMode has been activated. + */ +[scriptable, function, uuid(6da7f5fb-3a84-4abe-9e23-8b2045960732)] +interface jsdIActivationCallback : nsISupports +{ + void onDebuggerActivated (); +}; + +/** + * Pass an instance of one of these to jsdIDebuggerService::enterNestedEventLoop. + */ +[scriptable, function, uuid(88bea60f-9b5d-4b39-b08b-1c3a278782c6)] +interface jsdINestCallback : nsISupports +{ + /** + * This method will be called after pre-nesting work has completed, such + * as pushing the js context and network event queue, but before the new + * event loop starts. + */ + void onNest (); +}; + +/** + * Pass an instance of one of these to jsdIDebuggerService::enumerateFilters. + */ +[scriptable, function, uuid(e391ba85-9379-4762-b387-558e38db730f)] +interface jsdIFilterEnumerator : nsISupports +{ + /** + * The enumerateFilter method will be called once for every filter the + * debugger knows about. + */ + void enumerateFilter (in jsdIFilter filter); +}; + +/** + * Pass an instance of one of these to jsdIDebuggerService::enumerateScripts. + */ +[scriptable, function, uuid(4eef60c2-9bbc-48fa-b196-646a832c6c81)] +interface jsdIScriptEnumerator : nsISupports +{ + /** + * The enumerateScript method will be called once for every script the + * debugger knows about. + */ + void enumerateScript (in jsdIScript script); +}; + +/** + * Pass an instance of one of these to jsdIDebuggerService::enumerateContexts. + */ +[scriptable, function, uuid(57d18286-550c-4ca9-ac33-56f12ebba91e)] +interface jsdIContextEnumerator : nsISupports +{ + /** + * The enumerateContext method will be called once for every context + * currently in use. + */ + void enumerateContext (in jsdIContext executionContext); +}; + +/** + * Set jsdIDebuggerService::scriptHook to an instance of one of these. + */ +[scriptable, uuid(bb722893-0f63-45c5-b547-7a0947c7b6b6)] +interface jsdIScriptHook : nsISupports +{ + /** + * Called when scripts are created. + */ + void onScriptCreated (in jsdIScript script); + /** + * Called when the JavaScript engine destroys a script. The jsdIScript + * object passed in will already be invalidated. + */ + void onScriptDestroyed (in jsdIScript script); +}; + +/** + * Hook instances of this interface up to the + * jsdIDebuggerService::functionHook and toplevelHook properties. + */ +[scriptable, function, uuid(3eff1314-7ae3-4cf8-833b-c33c24a55633)] +interface jsdICallHook : nsISupports +{ + /** + * TYPE_* values must be kept in sync with the JSD_HOOK_* #defines + * in jsdebug.h. + */ + + /** + * Toplevel script is starting. + */ + const unsigned long TYPE_TOPLEVEL_START = 0; + /** + * Toplevel script has completed. + */ + const unsigned long TYPE_TOPLEVEL_END = 1; + /** + * Function is being called. + */ + const unsigned long TYPE_FUNCTION_CALL = 2; + /** + * Function is returning. + */ + const unsigned long TYPE_FUNCTION_RETURN = 3; + + /** + * Called before the JavaScript engine executes a top level script or calls + * a function. + */ + void onCall (in jsdIStackFrame frame, in unsigned long type); +}; + +[scriptable, function, uuid(e6b45eee-d974-4d85-9d9e-f5a67218deb4)] +interface jsdIErrorHook : nsISupports +{ + /** + * REPORT_* values must be kept in sync with JSREPORT_* #defines in + * jsapi.h + */ + + /** + * Report is an error. + */ + const unsigned long REPORT_ERROR = 0x00; + /** + * Report is only a warning. + */ + const unsigned long REPORT_WARNING = 0x01; + /** + * Report represents an uncaught exception. + */ + const unsigned long REPORT_EXCEPTION = 0x02; + /** + * Report is due to strict mode. + */ + const unsigned long REPORT_STRICT = 0x04; + + /** + * Called when the JavaScript engine encounters an error. Return |true| + * to pass the error along, |false| to invoke the debugHook. + */ + boolean onError (in AUTF8String message, in AUTF8String fileName, + in unsigned long line, in unsigned long pos, + in unsigned long flags, in unsigned long errnum, + in jsdIValue exc); +}; + +/** + * Hook instances of this interface up to the + * jsdIDebuggerService::breakpointHook, debuggerHook, errorHook, interruptHook, + * and throwHook properties. + */ +[scriptable, function, uuid(3a722496-9d78-4f0a-a797-293d9e8cb8d2)] +interface jsdIExecutionHook : nsISupports +{ + /** + * TYPE_* values must be kept in sync with JSD_HOOK_* #defines in jsdebug.h. + */ + + /** + * Execution stopped because we're in single step mode. + */ + const unsigned long TYPE_INTERRUPTED = 0; + /** + * Execution stopped by a trap instruction (i.e. breakoint.) + */ + const unsigned long TYPE_BREAKPOINT = 1; + /** + * Error handler returned an "invoke debugger" value. + */ + const unsigned long TYPE_DEBUG_REQUESTED = 2; + /** + * Debugger keyword encountered. + */ + const unsigned long TYPE_DEBUGGER_KEYWORD = 3; + /** + * Exception was thrown. + */ + const unsigned long TYPE_THROW = 4; + + /** + * RETURN_* values must be kept in sync with JSD_HOOK_RETURN_* #defines in + * jsdebug.h. + */ + + /** + * Indicates unrecoverable error processing the hook. This will cause + * the script being executed to be aborted without raising a JavaScript + * exception. + */ + const unsigned long RETURN_HOOK_ERROR = 0; + /** + * Continue processing normally. This is the "do nothing special" return + * value for all hook types *except* TYPE_THROW. Returning RETURN_CONTINUE + * from TYPE_THROW cause the exception to be ignored. Return + * RETURN_CONTINUE_THROW to continue exception processing from TYPE_THROW + * hooks. + */ + const unsigned long RETURN_CONTINUE = 1; + /** + * Same effect as RETURN_HOOK_ERROR. + */ + const unsigned long RETURN_ABORT = 2; + /** + * Return the value of the |val| parameter. + */ + const unsigned long RETURN_RET_WITH_VAL = 3; + /** + * Throw the value of the |val| parameter. + */ + const unsigned long RETURN_THROW_WITH_VAL = 4; + /** + * Continue the current throw. + */ + const unsigned long RETURN_CONTINUE_THROW = 5; + + /** + * @param frame A jsdIStackFrame object representing the bottom stack frame. + * @param type One of the jsdIExecutionHook::TYPE_ constants. + * @param val in - Current exception (if any) when this method is called. + * out - If you return RETURN_THROW_WITH_VAL, value to be + * thrown. + * If you return RETURN_RET_WITH_VAL, value to return. + * All other return values, not significant. + * @retval One of the jsdIExecutionHook::RETURN_* constants. + */ + unsigned long onExecute (in jsdIStackFrame frame, + in unsigned long type, inout jsdIValue val); +}; + +/** + * Objects which inherit this interface may go away, with (jsdIScript) or + * without (all others) notification. These objects are generally wrappers + * around JSD structures that go away when you call jsdService::Off(). + */ +[scriptable, uuid(46f1e23e-1dd2-11b2-9ceb-8285f2e95e69)] +interface jsdIEphemeral : nsISupports +{ + /** + * |true| if this object is still valid. If not, many or all of the methods + * and/or properties of the inheritor may no longer be callable. + */ + readonly attribute boolean isValid; + /** + * Mark this instance as invalid. + */ + [noscript] void invalidate(); +}; + +/* handle objects */ + +/** + * Context object. Only context's which are also nsISupports objects can be + * reflected by this interface. + */ +[scriptable, uuid(3e5c934d-6863-4d81-96f5-76a3b962fc2b)] +interface jsdIContext : jsdIEphemeral +{ + /* Internal use only. */ + [noscript] readonly attribute JSContext JSContext; + + /** + * OPT_* values must be kept in sync with JSOPTION_* #defines in jsapi.h. + */ + + /** + * Strict mode is on. + */ + const long OPT_STRICT = 0x01; + /** + * Warnings reported as errors. + */ + const long OPT_WERR = 0x02; + /** + * Makes eval() use the last object on its 'obj' param's scope chain as the + * ECMA 'variables object'. + */ + const long OPT_VAROBJFIX = 0x04; + /** + * Private data for this object is an nsISupports object. Attempting to + * alter this bit will result in an NS_ERROR_ILLEGAL_VALUE. + */ + const long OPT_ISUPPORTS = 0x08; + /** + * OPT_* values above, OR'd together. + */ + attribute unsigned long options; + + /** + * Last version set on this context. + * Scripts typically select this with the "language" attribute. + * See the VERSION_* consts on jsdIDebuggerService. + */ + attribute long version; + + /** + * Unique tag among all valid jsdIContext objects, useful as a hash key. + */ + readonly attribute unsigned long tag; + + /** + * Private data for this context, if it is an nsISupports, |null| otherwise. + */ + readonly attribute nsISupports privateData; + + /** + * Retrieve the underlying context wrapped by this jsdIContext. + */ + readonly attribute nsISupports wrappedContext; + + /** + * Top of the scope chain for this context. + */ + readonly attribute jsdIValue globalObject; + + /** + * |true| if this context should be allowed to run scripts, |false| + * otherwise. This attribute is only valid for contexts which implement + * nsIScriptContext. Setting or getting this attribute on any other + * context will throw a NS_ERROR_NO_INTERFACE exception. + */ + attribute boolean scriptsEnabled; +}; + +/** + * Stack frame objects. These are only valid inside the jsdIExecutionHook which + * gave it to you. After you return from that handler the bottom frame, and any + * frame you found attached through it, are invalidated via the jsdIEphemeral + * interface. Once a jsdIStackFrame has been invalidated all method and + * property accesses will throw a NS_ERROR_NOT_AVAILABLE exception. + */ +[scriptable, uuid(0633ca73-105e-4e8e-bcc5-13405d61754a)] +interface jsdIStackFrame : jsdIEphemeral +{ + /** Internal use only. */ + [noscript] readonly attribute JSDContext JSDContext; + /** Internal use only. */ + [noscript] readonly attribute JSDThreadState JSDThreadState; + /** Internal use only. */ + [noscript] readonly attribute JSDStackFrameInfo JSDStackFrameInfo; + + /** + * True if stack frame represents a frame created as a result of a debugger + * evaluation. + */ + readonly attribute boolean isDebugger; + /** + * True if stack frame is constructing a new object. + */ + readonly attribute boolean isConstructing; + + /** + * Link to the caller's stack frame. + */ + readonly attribute jsdIStackFrame callingFrame; + /** + * Executon context. + */ + readonly attribute jsdIContext executionContext; + /** + * Function name executing in this stack frame. + */ + readonly attribute AUTF8String functionName; + /** + * Script running in this stack frame, null for native frames. + */ + readonly attribute jsdIScript script; + /** + * Current program counter in this stack frame. + */ + readonly attribute unsigned long pc; + /** + * Current line number (using the script's pc to line map.) + */ + readonly attribute unsigned long line; + /** + * Function object running in this stack frame. + */ + readonly attribute jsdIValue callee; + /** + * Top object in the scope chain. + */ + readonly attribute jsdIValue scope; + /** + * |this| object for this stack frame. + */ + readonly attribute jsdIValue thisValue; + /** + * Evaluate arbitrary JavaScript in this stack frame. + * @param bytes Script to be evaluated. + * @param fileName Filename to compile this script under. This is the + * filename you'll see in error messages, etc. + * @param line Starting line number for this script. One based. + * @retval Result of evaluating the script. + */ + boolean eval (in AString bytes, in AUTF8String fileName, + in unsigned long line, out jsdIValue result); + +}; + +/** + * Script object. In JavaScript engine terms, there's a single script for each + * function, and one for the top level script. + */ +[scriptable, uuid(e7935220-7def-4c8e-832f-fbc948a97490)] +interface jsdIScript : jsdIEphemeral +{ + /** Internal use only. */ + [noscript] readonly attribute JSDContext JSDContext; + /** Internal use only. */ + [noscript] readonly attribute JSDScript JSDScript; + + /** + * Last version set on this context. + * Scripts typically select this with the "language" attribute. + * See the VERSION_* consts on jsdIDebuggerService. + */ + readonly attribute long version; + + /** + * Tag value guaranteed unique among jsdIScript objects. Useful as a + * hash key in script. + */ + readonly attribute unsigned long tag; + + /** + * FLAG_* values need to be kept in sync with JSD_SCRIPT_* #defines in + * jsdebug.h. + */ + + /** + * Determines whether or not to collect profile information for this + * script. The context flag FLAG_PROFILE_WHEN_SET decides the logic. + */ + const unsigned long FLAG_PROFILE = 0x01; + /** + * Determines whether or not to ignore breakpoints, etc. in this script. + * The context flag JSD_DEBUG_WHEN_SET decides the logic. + */ + const unsigned long FLAG_DEBUG = 0x02; + + /** + * FLAG_* attributes from above, OR'd together. + */ + attribute unsigned long flags; + + /** + * Filename given for this script when it was compiled. + * This data is copied from the underlying structure when the jsdIScript + * instance is created and is therefore available even after the script is + * invalidated. + */ + readonly attribute AUTF8String fileName; + /** + * Function name for this script. "anonymous" for unnamed functions (or + * a function actually named anonymous), empty for top level scripts. + * This data is copied from the underlying structure when the jsdIScript + * instance is created and is therefore available even after the script is + * invalidated. + */ + readonly attribute AUTF8String functionName; + /** + * The names of the arguments for this function; empty if this is + * not a function. + */ + void getParameterNames([optional] out unsigned long count, + [array, size_is(count), retval] out wstring paramNames); + /** + * Fetch the function object as a jsdIValue. + */ + readonly attribute jsdIValue functionObject; + /** + * Source code for this script, without function declaration. + */ + readonly attribute AString functionSource; + /** + * Line number in source file containing the first line of this script. + * This data is copied from the underlying structure when the jsdIScript + * instance is created and is therefore available even after the script is + * invalidated. + */ + readonly attribute unsigned long baseLineNumber; + /** + * Total number of lines in this script. + * This data is copied from the underlying structure when the jsdIScript + * instance is created and is therefore available even after the script is + * invalidated. + */ + readonly attribute unsigned long lineExtent; + + /** + * Number of times this script has been called. + */ + readonly attribute unsigned long callCount; + /** + * Number of times this script called itself, directly or indirectly. + */ + readonly attribute unsigned long maxRecurseDepth; + /** + * Shortest execution time recorded, in milliseconds. + */ + readonly attribute double minExecutionTime; + /** + * Longest execution time recorded, in milliseconds. + */ + readonly attribute double maxExecutionTime; + /** + * Total time spent in this function, in milliseconds. + */ + readonly attribute double totalExecutionTime; + /** + * Shortest execution time recorded, in milliseconds, excluding time spent + * in other called code. + */ + readonly attribute double minOwnExecutionTime; + /** + * Longest execution time recorded, in milliseconds, excluding time spent + * in other called code. + */ + readonly attribute double maxOwnExecutionTime; + /** + * Total time spent in this function, in milliseconds, excluding time spent + * in other called code. + */ + readonly attribute double totalOwnExecutionTime; + + /** + * Clear profile data for this script. + */ + void clearProfileData(); + + const unsigned long PCMAP_SOURCETEXT = 1; /* map to actual source text */ + const unsigned long PCMAP_PRETTYPRINT = 2; /* map to pretty printed source */ + + /** + * Get the closest line number to a given PC. + * The |pcmap| argument specifies which pc to source line map to use. + */ + unsigned long pcToLine (in unsigned long pc, in unsigned long pcmap); + /** + * Get the first PC associated with a line. + * The |pcmap| argument specifies which pc to source line map to use. + */ + unsigned long lineToPc (in unsigned long line, in unsigned long pcmap); + /** + * Determine is a particular line is executable, like checking that + * lineToPc == pcToLine, except in one call. + * The |pcmap| argument specifies which pc to source line map to use. + */ + boolean isLineExecutable (in unsigned long line, in unsigned long pcmap); + /** + * Set a breakpoint at a PC in this script. + */ + void setBreakpoint (in unsigned long pc); + /** + * Clear a breakpoint at a PC in this script. + */ + void clearBreakpoint (in unsigned long pc); + /** + * Clear all breakpoints set in this script. + */ + void clearAllBreakpoints (); + /** + * Call interrupt hook at least once per source line + */ + void enableSingleStepInterrupts (in PRBool mode); +}; + +/** + * Value objects. Represents typeless JavaScript values (jsval in SpiderMonkey + * terminology.) These are valid until the debugger is turned off. Holding a + * jsdIValue adds a root for the underlying JavaScript value, so don't keep it + * if you don't need to. + */ +[scriptable, uuid(fd1311f7-096c-44a3-847b-9d478c8176c3)] +interface jsdIValue : jsdIEphemeral +{ + /** Internal use only. */ + [noscript] readonly attribute JSDContext JSDContext; + /** Internal use only. */ + [noscript] readonly attribute JSDValue JSDValue; + + /** + * |false| unless the value is a function declared in script. + */ + readonly attribute boolean isNative; + /** + * |true| if the value represents a number, either double or integer. + * |false| for all other values, including numbers assigned as strings + * (eg. x = "1";) + */ + readonly attribute boolean isNumber; + /** + * |true| if the value represents a JavaScript primitive number or AUTF8String + */ + readonly attribute boolean isPrimitive; + + /** Value is either |true| or |false|. */ + const unsigned long TYPE_BOOLEAN = 0; + /** Value is a primitive number that is too large to fit in an integer. */ + const unsigned long TYPE_DOUBLE = 1; + /** Value is a primitive number that fits into an integer. */ + const unsigned long TYPE_INT = 2; + /** Value is a function. */ + const unsigned long TYPE_FUNCTION = 3; + /** Value is |null|. */ + const unsigned long TYPE_NULL = 4; + /** Value is an object. */ + const unsigned long TYPE_OBJECT = 5; + /** Value is a primitive AUTF8String. */ + const unsigned long TYPE_STRING = 6; + /** Value is void. */ + const unsigned long TYPE_VOID = 7; + + /** + * One of the TYPE_* values above. + */ + readonly attribute unsigned long jsType; + /** + * Prototype value if this value represents an object, null if the value is + * not an object or the object has no prototype. + */ + readonly attribute jsdIValue jsPrototype; + /** + * Parent value if this value represents an object, null if the value is not + * an object or the object has no parent. + */ + readonly attribute jsdIValue jsParent; + /** + * Class name if this value represents an object. Empty AUTF8String if the value + * is not an object. + */ + readonly attribute AUTF8String jsClassName; + /** + * Constructor name if this value represents an object. Empty AUTF8String if the + * value is not an object. + */ + readonly attribute jsdIValue jsConstructor; + /** + * Function name if this value represents a function. Empty AUTF8String if the + * value is not a function. + */ + readonly attribute AUTF8String jsFunctionName; + + /** + * Value if interpreted as a boolean. Converts if necessary. + */ + readonly attribute boolean booleanValue; + /** + * Value if interpreted as a double. Converts if necessary. + */ + readonly attribute double doubleValue; + /** + * Value if interpreted as an integer. Converts if necessary. + */ + readonly attribute long intValue; + /** + * Value if interpreted as an object. + */ + readonly attribute jsdIObject objectValue; + /** + * Value if interpreted as a AUTF8String. Converts if necessary. + */ + readonly attribute AUTF8String stringValue; + + /** + * Number of properties. 0 if the value is not an object, or the value is + * an object but has no properties. + */ + readonly attribute long propertyCount; + + /** + * Retrieves all properties if this value represents an object. If this + * value is not an object a 0 element array is returned. + * @param propArray Array of jsdIProperty values for this value. + * @param length Size of array. + */ + void getProperties ([array, size_is(length)] out jsdIProperty propArray, + out unsigned long length); + /** + * Retrieves a single property from the value. Only valid if the value + * represents an object. + * @param name Name of the property to retrieve. + * @retval jsdIProperty for the requested property name or null if no + * property exists for the requested name. + */ + jsdIProperty getProperty (in AUTF8String name); + + /** + * jsdIValues are wrappers around JavaScript engine structures. Much of the + * data is copied instead of shared. The refresh method is used to resync + * the jsdIValue with the underlying structure. + */ + void refresh(); + + /** + * When called from JavaScript, this method returns the JavaScript value + * wrapped by this jsdIValue. The calling script is free to use the result + * as it would any other JavaScript value. + * When called from another language this method returns an xpconnect + * defined error code. + */ + void getWrappedValue(); + + /** + * If this is a function value, return its associated jsdIScript. + * Otherwise, return null. + */ + readonly attribute jsdIScript script; +}; + +/** + * Properties specific to values which are also objects. + * XXX We don't add roots for these yet, so make sure you hold on to the + * jsdIValue from whence your jsdIObject instance came for at least as long as + * you hold the jsdIObject. + * XXX Maybe the jsClassName, jsConstructorName, and property related attribute/ + * functions from jsdIValue should move to this interface. We could inherit from + * jsdIValue or use interface flattening or something. + */ +[scriptable, uuid(87d86308-7a27-4255-b23c-ce2394f02473)] +interface jsdIObject : nsISupports +{ + /** Internal use only. */ + [noscript] readonly attribute JSDContext JSDContext; + /** Internal use only. */ + [noscript] readonly attribute JSDObject JSDObject; + + /** + * The URL (filename) that contains the script which caused this object + * to be created. + */ + readonly attribute AUTF8String creatorURL; + /** + * Line number in the creatorURL where this object was created. + */ + readonly attribute unsigned long creatorLine; + /** + * The URL (filename) that contains the script which defined the constructor + * used to create this object. + */ + readonly attribute AUTF8String constructorURL; + /** + * Line number in the creatorURL where this object was created. + */ + readonly attribute unsigned long constructorLine; + /** + * jsdIValue for this object. + */ + readonly attribute jsdIValue value; +}; + +/** + * Representation of a property of an object. When an instance is invalid, all + * method and property access will result in a NS_UNAVAILABLE error. + */ +[scriptable, uuid(09332485-1419-42bc-ba1f-070815ed4b82)] +interface jsdIProperty : jsdIEphemeral +{ + /** Internal use only. */ + [noscript] readonly attribute JSDContext JSDContext; + /** Internal use only. */ + [noscript] readonly attribute JSDProperty JSDProperty; + + /** + * FLAG_* values must be kept in sync with JSDPD_* #defines in jsdebug.h. + */ + + /** visible to for/in loop */ + const unsigned long FLAG_ENUMERATE = 0x01; + /** assignment is error */ + const unsigned long FLAG_READONLY = 0x02; + /** property cannot be deleted */ + const unsigned long FLAG_PERMANENT = 0x04; + /** property has an alias id */ + const unsigned long FLAG_ALIAS = 0x08; + /** argument to function */ + const unsigned long FLAG_ARGUMENT = 0x10; + /** local variable in function */ + const unsigned long FLAG_VARIABLE = 0x20; + /** exception occurred looking up property, value is exception */ + const unsigned long FLAG_EXCEPTION = 0x40; + /** native getter returned JS_FALSE without throwing an exception */ + const unsigned long FLAG_ERROR = 0x80; + /** found via explicit lookup (property defined elsewhere.) */ + const unsigned long FLAG_HINTED = 0x800; + + /** FLAG_* values OR'd together, representing the flags for this property. */ + readonly attribute unsigned long flags; + /** jsdIValue representing the alias for this property. */ + readonly attribute jsdIValue alias; + /** name for this property. */ + readonly attribute jsdIValue name; + /** value of this property. */ + readonly attribute jsdIValue value; + /** slot number if this property is a local variable or parameter. */ + readonly attribute unsigned long varArgSlot; + +}; + +/* +[scriptable, uuid(a47adad2-1dd1-11b2-b9e9-8e67a47beca5)] +interface jsdISourceText : nsISupports +{}; + +[scriptable, uuid(b6d1c006-1dd1-11b2-b9d8-b4d1ccfb74d8)] +interface jsdIThreadState : nsISupports +{ + [noscript] readonly attribute JSDContext JSDContext; + [noscript] readonly attribute JSDThreadState JSDThreadState; + + readonly attribute unsigned long frameCount; + readonly attribute jsdIStackFrame topFrame; + + attribute jsdIValue pendingException; +}; + +*/ + diff --git a/js/jsd/jsd.h b/js/jsd/jsd.h new file mode 100644 index 0000000..2c6ada6 --- /dev/null +++ b/js/jsd/jsd.h @@ -0,0 +1,1152 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Header for JavaScript Debugging support - Internal ONLY declarations + */ + +#ifndef jsd_h___ +#define jsd_h___ + +/* +* NOTE: This is a *private* header file and should only be included by +* the sources in js/jsd. Defining EXPORT_JSD_API in an outside module +* using jsd would be bad. +*/ +#define EXPORT_JSD_API 1 /* if used, must be set before include of jsdebug.h */ + +/* +* These can be controled by the makefile, but this allows a place to set +* the values always used in the mozilla client, but perhaps done differently +* in other embeddings. +*/ +#ifdef MOZILLA_CLIENT +#define JSD_THREADSAFE 1 +/* define JSD_HAS_DANGEROUS_THREAD 1 */ +#define JSD_USE_NSPR_LOCKS 1 +#endif /* MOZILLA_CLIENT */ + + +/* Get jstypes.h included first. After that we can use PR macros for doing +* this extern "C" stuff! +*/ +#ifdef __cplusplus +extern "C" +{ +#endif +#include "jstypes.h" +#ifdef __cplusplus +} +#endif + +JS_BEGIN_EXTERN_C +#include "jsprf.h" +#include "jsutil.h" /* Added by JSIFY */ +#include "jshash.h" /* Added by JSIFY */ +#include "jsclist.h" +#include "jsdebug.h" +#include "jsapi.h" +#include "jsdbgapi.h" +#include "jsd_lock.h" + +#include +#include +#include + +#ifdef LIVEWIRE +#include +#include +#include +#include +#endif /* LIVEWIRE */ +JS_END_EXTERN_C + +JS_BEGIN_EXTERN_C + +#define JSD_MAJOR_VERSION 1 +#define JSD_MINOR_VERSION 1 + +/***************************************************************************/ +/* handy macros */ +#undef CHECK_BIT_FLAG +#define CHECK_BIT_FLAG(f,b) ((f)&(b)) +#undef SET_BIT_FLAG +#define SET_BIT_FLAG(f,b) ((f)|=(b)) +#undef CLEAR_BIT_FLAG +#define CLEAR_BIT_FLAG(f,b) ((f)&=(~(b))) + +#define JSD_IS_DEBUG_ENABLED(jsdc,jsdscript) \ + (!(((jsdc->flags & JSD_DEBUG_WHEN_SET) ? 1 : 0) ^ \ + ((jsdscript->flags & JSD_SCRIPT_DEBUG_BIT) ? 1 : 0))) +#define JSD_IS_PROFILE_ENABLED(jsdc,jsdscript) \ + ((jsdc->flags & JSD_COLLECT_PROFILE_DATA) && \ + (!(((jsdc->flags & JSD_PROFILE_WHEN_SET) ? 1 : 0) ^ \ + ((jsdscript->flags & JSD_SCRIPT_PROFILE_BIT) ? 1 : 0)))) + + +/***************************************************************************/ +/* These are not exposed in jsdebug.h - typedef here for consistency */ + +typedef struct JSDExecHook JSDExecHook; +typedef struct JSDAtom JSDAtom; +typedef struct JSDProfileData JSDProfileData; +/***************************************************************************/ +/* Our structures */ + +/* +* XXX What I'm calling a JSDContext is really more of a JSDTaskState. +*/ + +struct JSDContext +{ + JSCList links; /* we are part of a JSCList */ + JSBool inited; + void* data; + uint32 flags; + JSD_ScriptHookProc scriptHook; + void* scriptHookData; + JSD_ExecutionHookProc interruptHook; + void* interruptHookData; + JSRuntime* jsrt; + JSD_ErrorReporter errorReporter; + void* errorReporterData; + JSCList threadsStates; + JSD_ExecutionHookProc debugBreakHook; + void* debugBreakHookData; + JSD_ExecutionHookProc debuggerHook; + void* debuggerHookData; + JSD_ExecutionHookProc throwHook; + void* throwHookData; + JSD_CallHookProc functionHook; + void* functionHookData; + JSD_CallHookProc toplevelHook; + void* toplevelHookData; + JSContext* dumbContext; + JSObject* glob; + JSD_UserCallbacks userCallbacks; + void* user; + JSCList scripts; + JSHashTable* scriptsTable; + JSCList sources; + JSCList removedSources; + uintN sourceAlterCount; + JSHashTable* atoms; + JSCList objectsList; + JSHashTable* objectsTable; + JSDProfileData* callingFunctionPData; + int64 lastReturnTime; +#ifdef JSD_THREADSAFE + void* scriptsLock; + void* sourceTextLock; + void* objectsLock; + void* atomsLock; + void* threadStatesLock; +#endif /* JSD_THREADSAFE */ +#ifdef JSD_HAS_DANGEROUS_THREAD + void* dangerousThread; +#endif /* JSD_HAS_DANGEROUS_THREAD */ + +}; + +struct JSDScript +{ + JSCList links; /* we are part of a JSCList */ + JSDContext* jsdc; /* JSDContext for this jsdscript */ + JSScript* script; /* script we are wrapping */ + JSFunction* function; /* back pointer to owning function (can be NULL) */ + uintN lineBase; /* we cache this */ + uintN lineExtent; /* we cache this */ + JSCList hooks; /* JSCList of JSDExecHooks for this script */ + char* url; + uint32 flags; + void* data; + + JSDProfileData *profileData; + +#ifdef LIVEWIRE + LWDBGApp* app; + LWDBGScript* lwscript; +#endif +}; + +struct JSDProfileData +{ + JSDProfileData* caller; + int64 lastCallStart; + int64 runningTime; + uintN callCount; + uintN recurseDepth; + uintN maxRecurseDepth; + jsdouble minExecutionTime; + jsdouble maxExecutionTime; + jsdouble totalExecutionTime; + jsdouble minOwnExecutionTime; + jsdouble maxOwnExecutionTime; + jsdouble totalOwnExecutionTime; +}; + +struct JSDSourceText +{ + JSCList links; /* we are part of a JSCList */ + char* url; + char* text; + uintN textLength; + uintN textSpace; + JSBool dirty; + JSDSourceStatus status; + uintN alterCount; + JSBool doingEval; +}; + +struct JSDExecHook +{ + JSCList links; /* we are part of a JSCList */ + JSDScript* jsdscript; + jsuword pc; + JSD_ExecutionHookProc hook; + void* callerdata; +}; + +#define TS_HAS_DISABLED_FRAME 0x01 + +struct JSDThreadState +{ + JSCList links; /* we are part of a JSCList */ + JSContext* context; + void* thread; + JSCList stack; + uintN stackDepth; + uintN flags; +}; + +struct JSDStackFrameInfo +{ + JSCList links; /* we are part of a JSCList */ + JSDThreadState* jsdthreadstate; + JSDScript* jsdscript; + jsuword pc; + JSStackFrame* fp; +}; + +#define GOT_PROTO ((short) (1 << 0)) +#define GOT_PROPS ((short) (1 << 1)) +#define GOT_PARENT ((short) (1 << 2)) +#define GOT_CTOR ((short) (1 << 3)) + +struct JSDValue +{ + jsval val; + intN nref; + JSCList props; + JSString* string; + JSString* funName; + const char* className; + JSDValue* proto; + JSDValue* parent; + JSDValue* ctor; + uintN flags; +}; + +struct JSDProperty +{ + JSCList links; /* we are part of a JSCList */ + intN nref; + JSDValue* val; + JSDValue* name; + JSDValue* alias; + uintN slot; + uintN flags; +}; + +struct JSDAtom +{ + char* str; /* must be first element in struct for compare */ + intN refcount; +}; + +struct JSDObject +{ + JSCList links; /* we are part of a JSCList */ + JSObject* obj; + JSDAtom* newURL; + uintN newLineno; + JSDAtom* ctorURL; + uintN ctorLineno; + JSDAtom* ctorName; +}; + +/***************************************************************************/ +/* Code validation support */ + +#ifdef DEBUG +extern void JSD_ASSERT_VALID_CONTEXT(JSDContext* jsdc); +extern void JSD_ASSERT_VALID_SCRIPT(JSDScript* jsdscript); +extern void JSD_ASSERT_VALID_SOURCE_TEXT(JSDSourceText* jsdsrc); +extern void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState* jsdthreadstate); +extern void JSD_ASSERT_VALID_STACK_FRAME(JSDStackFrameInfo* jsdframe); +extern void JSD_ASSERT_VALID_EXEC_HOOK(JSDExecHook* jsdhook); +extern void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval); +extern void JSD_ASSERT_VALID_PROPERTY(JSDProperty* jsdprop); +extern void JSD_ASSERT_VALID_OBJECT(JSDObject* jsdobj); +#else +#define JSD_ASSERT_VALID_CONTEXT(x) ((void)0) +#define JSD_ASSERT_VALID_SCRIPT(x) ((void)0) +#define JSD_ASSERT_VALID_SOURCE_TEXT(x) ((void)0) +#define JSD_ASSERT_VALID_THREAD_STATE(x)((void)0) +#define JSD_ASSERT_VALID_STACK_FRAME(x) ((void)0) +#define JSD_ASSERT_VALID_EXEC_HOOK(x) ((void)0) +#define JSD_ASSERT_VALID_VALUE(x) ((void)0) +#define JSD_ASSERT_VALID_PROPERTY(x) ((void)0) +#define JSD_ASSERT_VALID_OBJECT(x) ((void)0) +#endif + +/***************************************************************************/ +/* higher level functions */ + +extern JSDContext* +jsd_DebuggerOnForUser(JSRuntime* jsrt, + JSD_UserCallbacks* callbacks, + void* user, + JSObject* scopeobj); + +extern JSDContext* +jsd_DebuggerOn(void); + +extern void +jsd_DebuggerOff(JSDContext* jsdc); + +extern void +jsd_DebuggerPause(JSDContext* jsdc, JSBool forceAllHooksOff); + +extern void +jsd_DebuggerUnpause(JSDContext* jsdc); + +extern void +jsd_SetUserCallbacks(JSRuntime* jsrt, JSD_UserCallbacks* callbacks, void* user); + +extern JSDContext* +jsd_JSDContextForJSContext(JSContext* context); + +extern void* +jsd_SetContextPrivate(JSDContext* jsdc, void *data); + +extern void* +jsd_GetContextPrivate(JSDContext* jsdc); + +extern void +jsd_ClearAllProfileData(JSDContext* jsdc); + +extern JSBool +jsd_SetErrorReporter(JSDContext* jsdc, + JSD_ErrorReporter reporter, + void* callerdata); + +extern JSBool +jsd_GetErrorReporter(JSDContext* jsdc, + JSD_ErrorReporter* reporter, + void** callerdata); + +static JSBool +jsd_DebugErrorHook(JSContext *cx, const char *message, + JSErrorReport *report, void *closure); + +/***************************************************************************/ +/* Script functions */ + +extern JSBool +jsd_InitScriptManager(JSDContext *jsdc); + +extern void +jsd_DestroyScriptManager(JSDContext* jsdc); + +extern JSDScript* +jsd_FindJSDScript(JSDContext* jsdc, + JSScript *script); + +extern JSDScript* +jsd_FindOrCreateJSDScript(JSDContext *jsdc, + JSContext *cx, + JSScript *script, + JSStackFrame *fp); + +extern JSDProfileData* +jsd_GetScriptProfileData(JSDContext* jsdc, JSDScript *script); + +extern uint32 +jsd_GetScriptFlags(JSDContext *jsdc, JSDScript *script); + +extern void +jsd_SetScriptFlags(JSDContext *jsdc, JSDScript *script, uint32 flags); + +extern uintN +jsd_GetScriptCallCount(JSDContext* jsdc, JSDScript *script); + +extern uintN +jsd_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script); + +extern jsdouble +jsd_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script); + +extern jsdouble +jsd_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script); + +extern jsdouble +jsd_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script); + +extern jsdouble +jsd_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script); + +extern jsdouble +jsd_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script); + +extern jsdouble +jsd_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script); + +extern void +jsd_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script); + +extern JSScript * +jsd_GetJSScript (JSDContext *jsdc, JSDScript *script); + +extern JSFunction * +jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script); + +extern JSDScript* +jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp); + +extern void * +jsd_SetScriptPrivate (JSDScript *jsdscript, void *data); + +extern void * +jsd_GetScriptPrivate (JSDScript *jsdscript); + +extern JSBool +jsd_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript); + +extern const char* +jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript); + +extern JSString* +jsd_GetScriptFunctionId(JSDContext* jsdc, JSDScript *jsdscript); + +extern uintN +jsd_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript); + +extern uintN +jsd_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript); + +extern JSBool +jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata); + +extern JSBool +jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata); + +extern jsuword +jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line); + +extern uintN +jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc); + +extern void +jsd_NewScriptHookProc( + JSContext *cx, + const char *filename, /* URL this script loads from */ + uintN lineno, /* line where this script starts */ + JSScript *script, + JSFunction *fun, + void* callerdata); + +extern void +jsd_DestroyScriptHookProc( + JSContext *cx, + JSScript *script, + void* callerdata); + +/* Script execution hook functions */ + +extern JSBool +jsd_SetExecutionHook(JSDContext* jsdc, + JSDScript* jsdscript, + jsuword pc, + JSD_ExecutionHookProc hook, + void* callerdata); + +extern JSBool +jsd_ClearExecutionHook(JSDContext* jsdc, + JSDScript* jsdscript, + jsuword pc); + +extern JSBool +jsd_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript); + +extern JSBool +jsd_ClearAllExecutionHooks(JSDContext* jsdc); + +extern void +jsd_ScriptCreated(JSDContext* jsdc, + JSContext *cx, + const char *filename, /* URL this script loads from */ + uintN lineno, /* line where this script starts */ + JSScript *script, + JSFunction *fun); + +extern void +jsd_ScriptDestroyed(JSDContext* jsdc, + JSContext *cx, + JSScript *script); + +/***************************************************************************/ +/* Source Text functions */ + +extern JSDSourceText* +jsd_IterateSources(JSDContext* jsdc, JSDSourceText **iterp); + +extern JSDSourceText* +jsd_FindSourceForURL(JSDContext* jsdc, const char* url); + +extern const char* +jsd_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc); + +extern JSBool +jsd_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc, + const char** ppBuf, intN* pLen); + +extern void +jsd_ClearSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc); + +extern JSDSourceStatus +jsd_GetSourceStatus(JSDContext* jsdc, JSDSourceText* jsdsrc); + +extern JSBool +jsd_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc); + +extern void +jsd_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, JSBool dirty); + +extern uintN +jsd_GetSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc); + +extern uintN +jsd_IncrementSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc); + +extern JSDSourceText* +jsd_NewSourceText(JSDContext* jsdc, const char* url); + +extern JSDSourceText* +jsd_AppendSourceText(JSDContext* jsdc, + JSDSourceText* jsdsrc, + const char* text, /* *not* zero terminated */ + size_t length, + JSDSourceStatus status); + +extern JSDSourceText* +jsd_AppendUCSourceText(JSDContext* jsdc, + JSDSourceText* jsdsrc, + const jschar* text, /* *not* zero terminated */ + size_t length, + JSDSourceStatus status); + +/* convienence function for adding complete source of url in one call */ +extern JSBool +jsd_AddFullSourceText(JSDContext* jsdc, + const char* text, /* *not* zero terminated */ + size_t length, + const char* url); + +extern void +jsd_DestroyAllSources(JSDContext* jsdc); + +extern const char* +jsd_BuildNormalizedURL(const char* url_string); + +extern void +jsd_StartingEvalUsingFilename(JSDContext* jsdc, const char* url); + +extern void +jsd_FinishedEvalUsingFilename(JSDContext* jsdc, const char* url); + +/***************************************************************************/ +/* Interrupt Hook functions */ + +extern JSBool +jsd_SetInterruptHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata); + +extern JSBool +jsd_ClearInterruptHook(JSDContext* jsdc); + +extern JSBool +jsd_EnableSingleStepInterrupts(JSDContext* jsdc, + JSDScript* jsdscript, + JSBool enable); + +extern JSBool +jsd_SetDebugBreakHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata); + +extern JSBool +jsd_ClearDebugBreakHook(JSDContext* jsdc); + +extern JSBool +jsd_SetDebuggerHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata); + +extern JSBool +jsd_ClearDebuggerHook(JSDContext* jsdc); + +extern JSTrapStatus +jsd_CallExecutionHook(JSDContext* jsdc, + JSContext* cx, + uintN type, + JSD_ExecutionHookProc hook, + void* hookData, + jsval* rval); + +extern JSBool +jsd_CallCallHook (JSDContext* jsdc, + JSContext* cx, + uintN type, + JSD_CallHookProc hook, + void* hookData); + +extern JSBool +jsd_SetThrowHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata); +extern JSBool +jsd_ClearThrowHook(JSDContext* jsdc); + +extern JSTrapStatus +jsd_DebuggerHandler(JSContext *cx, JSScript *script, jsbytecode *pc, + jsval *rval, void *closure); + +extern JSTrapStatus +jsd_ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, + jsval *rval, void *closure); + +extern JSBool +jsd_SetFunctionHook(JSDContext* jsdc, + JSD_CallHookProc hook, + void* callerdata); + +extern JSBool +jsd_ClearFunctionHook(JSDContext* jsdc); + +extern JSBool +jsd_SetTopLevelHook(JSDContext* jsdc, + JSD_CallHookProc hook, + void* callerdata); + +extern JSBool +jsd_ClearTopLevelHook(JSDContext* jsdc); + +/***************************************************************************/ +/* Stack Frame functions */ + +extern uintN +jsd_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate); + +extern JSDStackFrameInfo* +jsd_GetStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate); + +extern JSContext* +jsd_GetJSContext(JSDContext* jsdc, JSDThreadState* jsdthreadstate); + +extern JSDStackFrameInfo* +jsd_GetCallingStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +extern JSDScript* +jsd_GetScriptForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +extern jsuword +jsd_GetPCForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +extern JSDValue* +jsd_GetCallObjectForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +extern JSDValue* +jsd_GetScopeChainForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +extern JSBool +jsd_IsStackFrameDebugger(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +extern JSBool +jsd_IsStackFrameConstructing(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +extern JSDValue* +jsd_GetThisForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +extern JSString* +jsd_GetIdForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +extern JSDThreadState* +jsd_NewThreadState(JSDContext* jsdc, JSContext *cx); + +extern void +jsd_DestroyThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate); + +extern JSBool +jsd_EvaluateUCScriptInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + const jschar *bytes, uintN length, + const char *filename, uintN lineno, + JSBool eatExceptions, jsval *rval); + +extern JSBool +jsd_EvaluateScriptInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + const char *bytes, uintN length, + const char *filename, uintN lineno, + JSBool eatExceptions, jsval *rval); + +extern JSString* +jsd_ValToStringInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + jsval val); + +extern JSBool +jsd_IsValidThreadState(JSDContext* jsdc, + JSDThreadState* jsdthreadstate); + +extern JSBool +jsd_IsValidFrameInThreadState(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +extern JSDValue* +jsd_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate); + +extern JSBool +jsd_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate, + JSDValue* jsdval); + +/***************************************************************************/ +/* Locking support */ + +/* protos are in js_lock.h for: + * jsd_CreateLock + * jsd_Lock + * jsd_Unlock + * jsd_IsLocked + * jsd_CurrentThread + */ + +#ifdef JSD_THREADSAFE + +/* the system-wide lock */ +extern void* _jsd_global_lock; +#define JSD_LOCK() \ + JS_BEGIN_MACRO \ + if(!_jsd_global_lock) \ + _jsd_global_lock = jsd_CreateLock(); \ + JS_ASSERT(_jsd_global_lock); \ + jsd_Lock(_jsd_global_lock); \ + JS_END_MACRO + +#define JSD_UNLOCK() \ + JS_BEGIN_MACRO \ + JS_ASSERT(_jsd_global_lock); \ + jsd_Unlock(_jsd_global_lock); \ + JS_END_MACRO + +/* locks for the subsystems of a given context */ +#define JSD_INIT_LOCKS(jsdc) \ + ( (NULL != (jsdc->scriptsLock = jsd_CreateLock())) && \ + (NULL != (jsdc->sourceTextLock = jsd_CreateLock())) && \ + (NULL != (jsdc->atomsLock = jsd_CreateLock())) && \ + (NULL != (jsdc->objectsLock = jsd_CreateLock())) && \ + (NULL != (jsdc->threadStatesLock = jsd_CreateLock())) ) + +#define JSD_LOCK_SCRIPTS(jsdc) jsd_Lock(jsdc->scriptsLock) +#define JSD_UNLOCK_SCRIPTS(jsdc) jsd_Unlock(jsdc->scriptsLock) + +#define JSD_LOCK_SOURCE_TEXT(jsdc) jsd_Lock(jsdc->sourceTextLock) +#define JSD_UNLOCK_SOURCE_TEXT(jsdc) jsd_Unlock(jsdc->sourceTextLock) + +#define JSD_LOCK_ATOMS(jsdc) jsd_Lock(jsdc->atomsLock) +#define JSD_UNLOCK_ATOMS(jsdc) jsd_Unlock(jsdc->atomsLock) + +#define JSD_LOCK_OBJECTS(jsdc) jsd_Lock(jsdc->objectsLock) +#define JSD_UNLOCK_OBJECTS(jsdc) jsd_Unlock(jsdc->objectsLock) + +#define JSD_LOCK_THREADSTATES(jsdc) jsd_Lock(jsdc->threadStatesLock) +#define JSD_UNLOCK_THREADSTATES(jsdc) jsd_Unlock(jsdc->threadStatesLock) + +#else /* !JSD_THREADSAFE */ + +#define JSD_LOCK() ((void)0) +#define JSD_UNLOCK() ((void)0) + +#define JSD_INIT_LOCKS(jsdc) 1 + +#define JSD_LOCK_SCRIPTS(jsdc) ((void)0) +#define JSD_UNLOCK_SCRIPTS(jsdc) ((void)0) + +#define JSD_LOCK_SOURCE_TEXT(jsdc) ((void)0) +#define JSD_UNLOCK_SOURCE_TEXT(jsdc) ((void)0) + +#define JSD_LOCK_ATOMS(jsdc) ((void)0) +#define JSD_UNLOCK_ATOMS(jsdc) ((void)0) + +#define JSD_LOCK_OBJECTS(jsdc) ((void)0) +#define JSD_UNLOCK_OBJECTS(jsdc) ((void)0) + +#define JSD_LOCK_THREADSTATES(jsdc) ((void)0) +#define JSD_UNLOCK_THREADSTATES(jsdc) ((void)0) + +#endif /* JSD_THREADSAFE */ + +/* NOTE: These are intended for ASSERTs. Thus we supply checks for both + * LOCKED and UNLOCKED (rather that just LOCKED and !LOCKED) so that in + * the DEBUG non-Threadsafe case we can have an ASSERT that always succeeds + * without having to special case things in the code. + */ +#if defined(JSD_THREADSAFE) && defined(DEBUG) +#define JSD_SCRIPTS_LOCKED(jsdc) (jsd_IsLocked(jsdc->scriptsLock)) +#define JSD_SOURCE_TEXT_LOCKED(jsdc) (jsd_IsLocked(jsdc->sourceTextLock)) +#define JSD_ATOMS_LOCKED(jsdc) (jsd_IsLocked(jsdc->atomsLock)) +#define JSD_OBJECTS_LOCKED(jsdc) (jsd_IsLocked(jsdc->objectsLock)) +#define JSD_THREADSTATES_LOCKED(jsdc) (jsd_IsLocked(jsdc->threadStatesLock)) +#define JSD_SCRIPTS_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->scriptsLock)) +#define JSD_SOURCE_TEXT_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->sourceTextLock)) +#define JSD_ATOMS_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->atomsLock)) +#define JSD_OBJECTS_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->objectsLock)) +#define JSD_THREADSTATES_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->threadStatesLock)) +#else +#define JSD_SCRIPTS_LOCKED(jsdc) 1 +#define JSD_SOURCE_TEXT_LOCKED(jsdc) 1 +#define JSD_ATOMS_LOCKED(jsdc) 1 +#define JSD_OBJECTS_LOCKED(jsdc) 1 +#define JSD_THREADSTATES_LOCKED(jsdc) 1 +#define JSD_SCRIPTS_UNLOCKED(jsdc) 1 +#define JSD_SOURCE_TEXT_UNLOCKED(jsdc) 1 +#define JSD_ATOMS_UNLOCKED(jsdc) 1 +#define JSD_OBJECTS_UNLOCKED(jsdc) 1 +#define JSD_THREADSTATES_UNLOCKED(jsdc) 1 +#endif /* defined(JSD_THREADSAFE) && defined(DEBUG) */ + +/***************************************************************************/ +/* Threading support */ + +#ifdef JSD_THREADSAFE + +#define JSD_CURRENT_THREAD() jsd_CurrentThread() + +#else /* !JSD_THREADSAFE */ + +#define JSD_CURRENT_THREAD() ((void*)0) + +#endif /* JSD_THREADSAFE */ + +/***************************************************************************/ +/* Dangerous thread support */ + +#ifdef JSD_HAS_DANGEROUS_THREAD + +#define JSD_IS_DANGEROUS_THREAD(jsdc) \ + (JSD_CURRENT_THREAD() == jsdc->dangerousThread) + +#else /* !JSD_HAS_DANGEROUS_THREAD */ + +#define JSD_IS_DANGEROUS_THREAD(jsdc) 0 + +#endif /* JSD_HAS_DANGEROUS_THREAD */ + +/***************************************************************************/ +/* Value and Property Functions */ + +extern JSDValue* +jsd_NewValue(JSDContext* jsdc, jsval val); + +extern void +jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval); + +extern jsval +jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval); + +extern void +jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval); + +/**************************************************/ + +extern JSBool +jsd_IsValueObject(JSDContext* jsdc, JSDValue* jsdval); + +extern JSBool +jsd_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval); + +extern JSBool +jsd_IsValueInt(JSDContext* jsdc, JSDValue* jsdval); + +extern JSBool +jsd_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval); + +extern JSBool +jsd_IsValueString(JSDContext* jsdc, JSDValue* jsdval); + +extern JSBool +jsd_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval); + +extern JSBool +jsd_IsValueNull(JSDContext* jsdc, JSDValue* jsdval); + +extern JSBool +jsd_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval); + +extern JSBool +jsd_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval); + +extern JSBool +jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval); + +extern JSBool +jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval); + +/**************************************************/ + +extern JSBool +jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval); + +extern int32 +jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval); + +extern jsdouble +jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval); + +extern JSString* +jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval); + +extern JSString* +jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval); + +extern JSFunction* +jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval); + +/**************************************************/ + +extern uintN +jsd_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval); + +extern JSDProperty* +jsd_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp); + +extern JSDProperty* +jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name); + +extern JSDValue* +jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval); + +extern JSDValue* +jsd_GetValueParent(JSDContext* jsdc, JSDValue* jsdval); + +extern JSDValue* +jsd_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval); + +extern const char* +jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval); + +extern JSDScript* +jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval); + +/**************************************************/ + +extern void +jsd_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop); + +extern JSDValue* +jsd_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop); + +extern JSDValue* +jsd_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop); + +extern JSDValue* +jsd_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop); + +extern uintN +jsd_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop); + +extern uintN +jsd_GetPropertyVarArgSlot(JSDContext* jsdc, JSDProperty* jsdprop); + +/**************************************************/ +/* Stepping Functions */ + +extern void * +jsd_FunctionCallHook(JSContext *cx, JSStackFrame *fp, JSBool before, + JSBool *ok, void *closure); + +extern void * +jsd_TopLevelCallHook(JSContext *cx, JSStackFrame *fp, JSBool before, + JSBool *ok, void *closure); + +/**************************************************/ +/* Object Functions */ + +extern JSBool +jsd_InitObjectManager(JSDContext* jsdc); + +extern void +jsd_DestroyObjectManager(JSDContext* jsdc); + +extern void +jsd_DestroyObjects(JSDContext* jsdc); + +extern void +jsd_Constructing(JSDContext* jsdc, JSContext *cx, JSObject *obj, + JSStackFrame *fp); + +extern JSDObject* +jsd_IterateObjects(JSDContext* jsdc, JSDObject** iterp); + +extern JSObject* +jsd_GetWrappedObject(JSDContext* jsdc, JSDObject* jsdobj); + +extern const char* +jsd_GetObjectNewURL(JSDContext* jsdc, JSDObject* jsdobj); + +extern uintN +jsd_GetObjectNewLineNumber(JSDContext* jsdc, JSDObject* jsdobj); + +extern const char* +jsd_GetObjectConstructorURL(JSDContext* jsdc, JSDObject* jsdobj); + +extern uintN +jsd_GetObjectConstructorLineNumber(JSDContext* jsdc, JSDObject* jsdobj); + +extern const char* +jsd_GetObjectConstructorName(JSDContext* jsdc, JSDObject* jsdobj); + +extern JSDObject* +jsd_GetJSDObjectForJSObject(JSDContext* jsdc, JSObject* jsobj); + +extern JSDObject* +jsd_GetObjectForValue(JSDContext* jsdc, JSDValue* jsdval); + +/* +* returns new refcounted JSDValue +*/ +extern JSDValue* +jsd_GetValueForObject(JSDContext* jsdc, JSDObject* jsdobj); + +/**************************************************/ +/* Atom Functions */ + +extern JSBool +jsd_CreateAtomTable(JSDContext* jsdc); + +extern void +jsd_DestroyAtomTable(JSDContext* jsdc); + +extern JSDAtom* +jsd_AddAtom(JSDContext* jsdc, const char* str); + +extern JSDAtom* +jsd_CloneAtom(JSDContext* jsdc, JSDAtom* atom); + +extern void +jsd_DropAtom(JSDContext* jsdc, JSDAtom* atom); + +#define JSD_ATOM_TO_STRING(a) ((const char*)((a)->str)) + +/***************************************************************************/ +/* Livewire specific API */ +#ifdef LIVEWIRE + +extern LWDBGScript* +jsdlw_GetLWScript(JSDContext* jsdc, JSDScript* jsdscript); + +extern char* +jsdlw_BuildAppRelativeFilename(LWDBGApp* app, const char* filename); + +extern JSDSourceText* +jsdlw_PreLoadSource(JSDContext* jsdc, LWDBGApp* app, + const char* filename, JSBool clear); + +extern JSDSourceText* +jsdlw_ForceLoadSource(JSDContext* jsdc, JSDSourceText* jsdsrc); + +extern JSBool +jsdlw_UserCodeAtPC(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc); + +extern JSBool +jsdlw_RawToProcessedLineNumber(JSDContext* jsdc, JSDScript* jsdscript, + uintN lineIn, uintN* lineOut); + +extern JSBool +jsdlw_ProcessedToRawLineNumber(JSDContext* jsdc, JSDScript* jsdscript, + uintN lineIn, uintN* lineOut); + + +#if 0 +/* our hook proc for LiveWire app start/stop */ +extern void +jsdlw_AppHookProc(LWDBGApp* app, + JSBool created, + void *callerdata); +#endif + + +#endif +/***************************************************************************/ + +JS_END_EXTERN_C + +#endif /* jsd_h___ */ diff --git a/js/jsd/jsd1640.def b/js/jsd/jsd1640.def new file mode 100644 index 0000000..38e1f2c --- /dev/null +++ b/js/jsd/jsd1640.def @@ -0,0 +1,110 @@ +; -*- Mode: Fundamental; tab-width: 4; indent-tabs-mode: nil -*- +; +; ***** BEGIN LICENSE BLOCK ***** +; Version: MPL 1.1/GPL 2.0/LGPL 2.1 +; +; The contents of this file are subject to the Mozilla Public License Version +; 1.1 (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.mozilla.org/MPL/ +; +; Software distributed under the License is distributed on an "AS IS" basis, +; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +; for the specific language governing rights and limitations under the +; License. +; +; The Original Code is mozilla.org code. +; +; The Initial Developer of the Original Code is +; Netscape Communications Corporation. +; Portions created by the Initial Developer are Copyright (C) 1998 +; the Initial Developer. All Rights Reserved. +; +; Contributor(s): +; +; Alternatively, the contents of this file may be used under the terms of +; either the GNU General Public License Version 2 or later (the "GPL"), or +; the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +; in which case the provisions of the GPL or the LGPL are applicable instead +; of those above. If you wish to allow use of your version of this file only +; under the terms of either the GPL or the LGPL, and not to allow others to +; use your version of this file under the terms of the MPL, indicate your +; decision by deleting the provisions above and replace them with the notice +; and other provisions required by the GPL or the LGPL. If you do not delete +; the provisions above, a recipient may use your version of this file under +; the terms of any one of the MPL, the GPL or the LGPL. +; +; ***** END LICENSE BLOCK ***** + + +LIBRARY JSD1640.DLL +EXETYPE WINDOWS +PROTMODE + +DESCRIPTION 'Netscape 16-bit JavaScript Debugger Library' + +CODE LOADONCALL MOVEABLE DISCARDABLE +DATA PRELOAD MOVEABLE SINGLE + +HEAPSIZE 8192 + +EXPORTS + WEP @1 RESIDENTNAME NONAME + _JSD_AppendSourceText + _JSD_ClearAllExecutionHooks + _JSD_ClearAllExecutionHooksForScript + _JSD_ClearDebugBreakHook + _JSD_ClearExecutionHook + _JSD_ClearInterruptHook + _JSD_ClearSourceText + _JSD_DebuggerOff + _JSD_DebuggerOn + _JSD_EvaluateScriptInStackFrame + _JSD_FindSourceForURL + _JSD_GetCallingStackFrame + _JSD_GetClosestLine + _JSD_GetClosestPC + _JSD_GetCountOfStackFrames + _JSD_GetDefaultJSContext + _JSD_GetMajorVersion + _JSD_GetMinorVersion + _JSD_GetPCForStackFrame + _JSD_GetScriptBaseLineNumber + _JSD_GetScriptFilename + _JSD_GetScriptForStackFrame + _JSD_GetScriptFunctionId + _JSD_GetScriptHook + _JSD_GetScriptLineExtent + _JSD_GetSourceAlterCount + _JSD_GetSourceStatus + _JSD_GetSourceText + _JSD_GetSourceURL + _JSD_GetStackFrame + _JSD_IncrementSourceAlterCount + _JSD_IsSourceDirty + _JSD_IterateScripts + _JSD_IterateSources + _JSD_LockScriptSubsystem + _JSD_LockSourceTextSubsystem + _JSD_NewSourceText + _JSD_SetDebugBreakHook + _JSD_SetErrorReporter + _JSD_SetExecutionHook + _JSD_SetInterruptHook + _JSD_SetScriptHook + _JSD_SetSourceDirty + _JSD_SetUserCallbacks + _JSD_UnlockScriptSubsystem + _JSD_UnlockSourceTextSubsystem + _Java_netscape_jsdebug_DebugController__0005fsetController_stub + _Java_netscape_jsdebug_DebugController_executeScriptInStackFrame_stub + _Java_netscape_jsdebug_DebugController_sendInterrupt_stub + _Java_netscape_jsdebug_DebugController_setInstructionHook0_stub + _Java_netscape_jsdebug_JSPC_getSourceLocation_stub + _Java_netscape_jsdebug_JSSourceTextProvider_loadSourceTextItem_stub + _Java_netscape_jsdebug_JSSourceTextProvider_refreshSourceTextVector_stub + _Java_netscape_jsdebug_JSStackFrameInfo_getCaller0_stub + _Java_netscape_jsdebug_JSStackFrameInfo_getPC_stub + _Java_netscape_jsdebug_JSThreadState_countStackFrames_stub + _Java_netscape_jsdebug_JSThreadState_getCurrentFrame_stub + _Java_netscape_jsdebug_Script_getClosestPC_stub diff --git a/js/jsd/jsd1640.rc b/js/jsd/jsd1640.rc new file mode 100644 index 0000000..010aaf2 --- /dev/null +++ b/js/jsd/jsd1640.rc @@ -0,0 +1,99 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + + +///////////////////////////////////////////////////////////////////////////// + +// Version stamp for this .DLL + +#include + +#include + + + +VS_VERSION_INFO VERSIONINFO + + FILEVERSION 4 // major, minor, release (alpha 1), build # + + PRODUCTVERSION 4 + + FILEFLAGSMASK 0 + + FILEFLAGS 0 // final version + + FILEOS VOS_DOS_WINDOWS16 + + FILETYPE VFT_DLL + + FILESUBTYPE 0 // not used + +BEGIN + + BLOCK "StringFileInfo" + + BEGIN + + BLOCK "040904E4" // Lang=US English, CharSet=Windows Multilingual + + BEGIN + + VALUE "CompanyName", "Netscape Communications Corporation\0" + + VALUE "FileDescription", "Netscape 16-bit JavaScript Debugger Module\0" + + VALUE "FileVersion", "4.0\0" + + VALUE "InternalName", "JSD1640\0" + + VALUE "LegalCopyright", "Copyright Netscape Communications. 1994-96\0" + + VALUE "LegalTrademarks", "Netscape, Mozilla\0" + + VALUE "OriginalFilename","JSD1640.DLL\0" + + VALUE "ProductName", "NETSCAPE\0" + + VALUE "ProductVersion", "4.0\0" + + END + + END + +END + diff --git a/js/jsd/jsd3240.rc b/js/jsd/jsd3240.rc new file mode 100644 index 0000000..a8a464a --- /dev/null +++ b/js/jsd/jsd3240.rc @@ -0,0 +1,118 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + + +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winver.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 4,0,0,0 + PRODUCTVERSION 4,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x10004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "Netscape Communications Corporation\0" + VALUE "FileDescription", "Netscape 32-bit JavaScript Debugger Module\0" + VALUE "FileVersion", "4.0\0" + VALUE "InternalName", "JSD3240\0" + VALUE "LegalCopyright", "Copyright Netscape Communications. 1994-96\0" + VALUE "LegalTrademarks", "Netscape, Mozilla\0" + VALUE "OriginalFilename", "jsd3240.dll\0" + VALUE "ProductName", "NETSCAPE\0" + VALUE "ProductVersion", "4.0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winver.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/js/jsd/jsd_atom.c b/js/jsd/jsd_atom.c new file mode 100644 index 0000000..66f09ff --- /dev/null +++ b/js/jsd/jsd_atom.c @@ -0,0 +1,178 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript Debugging support - Atom support + */ + +#include "jsd.h" + +/* #define TEST_ATOMS 1 */ + +#ifdef TEST_ATOMS +static void +_testAtoms(JSDContext*jsdc) +{ + JSDAtom* atom0 = jsd_AddAtom(jsdc, "foo"); + JSDAtom* atom1 = jsd_AddAtom(jsdc, "foo"); + JSDAtom* atom2 = jsd_AddAtom(jsdc, "bar"); + JSDAtom* atom3 = jsd_CloneAtom(jsdc, atom1); + JSDAtom* atom4 = jsd_CloneAtom(jsdc, atom2); + + const char* c0 = JSD_ATOM_TO_STRING(atom0); + const char* c1 = JSD_ATOM_TO_STRING(atom1); + const char* c2 = JSD_ATOM_TO_STRING(atom2); + const char* c3 = JSD_ATOM_TO_STRING(atom3); + const char* c4 = JSD_ATOM_TO_STRING(atom4); + + jsd_DropAtom(jsdc, atom0); + jsd_DropAtom(jsdc, atom1); + jsd_DropAtom(jsdc, atom2); + jsd_DropAtom(jsdc, atom3); + jsd_DropAtom(jsdc, atom4); +} +#endif + +static intN +_atom_smasher(JSHashEntry *he, intN i, void *arg) +{ + JS_ASSERT(he); + JS_ASSERT(he->value); + JS_ASSERT(((JSDAtom*)(he->value))->str); + + free(((JSDAtom*)(he->value))->str); + free(he->value); + he->value = NULL; + he->key = NULL; + return HT_ENUMERATE_NEXT; +} + +static intN +_compareAtomKeys(const void *v1, const void *v2) +{ + return 0 == strcmp((const char*)v1, (const char*)v2); +} + +static intN +_compareAtoms(const void *v1, const void *v2) +{ + return 0 == strcmp(((JSDAtom*)v1)->str, ((JSDAtom*)v2)->str); +} + + +JSBool +jsd_CreateAtomTable(JSDContext* jsdc) +{ + jsdc->atoms = JS_NewHashTable(256, JS_HashString, + _compareAtomKeys, _compareAtoms, + NULL, NULL); +#ifdef TEST_ATOMS + _testAtoms(jsdc); +#endif + return !!jsdc->atoms; +} + +void +jsd_DestroyAtomTable(JSDContext* jsdc) +{ + if( jsdc->atoms ) + { + JS_HashTableEnumerateEntries(jsdc->atoms, _atom_smasher, NULL); + JS_HashTableDestroy(jsdc->atoms); + jsdc->atoms = NULL; + } +} + +JSDAtom* +jsd_AddAtom(JSDContext* jsdc, const char* str) +{ + JSDAtom* atom; + + if(!str) + { + JS_ASSERT(0); + return NULL; + } + + JSD_LOCK_ATOMS(jsdc); + + atom = (JSDAtom*) JS_HashTableLookup(jsdc->atoms, str); + + if( atom ) + atom->refcount++; + else + { + atom = (JSDAtom*) malloc(sizeof(JSDAtom)); + if( atom ) + { + atom->str = strdup(str); + atom->refcount = 1; + if(!JS_HashTableAdd(jsdc->atoms, atom->str, atom)) + { + free(atom->str); + free(atom); + atom = NULL; + } + } + } + + JSD_UNLOCK_ATOMS(jsdc); + return atom; +} + +JSDAtom* +jsd_CloneAtom(JSDContext* jsdc, JSDAtom* atom) +{ + JSD_LOCK_ATOMS(jsdc); + atom->refcount++; + JSD_UNLOCK_ATOMS(jsdc); + return atom; +} + +void +jsd_DropAtom(JSDContext* jsdc, JSDAtom* atom) +{ + JSD_LOCK_ATOMS(jsdc); + if(! --atom->refcount) + { + JS_HashTableRemove(jsdc->atoms, atom->str); + free(atom->str); + free(atom); + } + JSD_UNLOCK_ATOMS(jsdc); +} + diff --git a/js/jsd/jsd_high.c b/js/jsd/jsd_high.c new file mode 100644 index 0000000..fab896b --- /dev/null +++ b/js/jsd/jsd_high.c @@ -0,0 +1,439 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript Debugging support - 'High Level' functions + */ + +#include "jsd.h" + +/***************************************************************************/ + +/* XXX not 'static' because of old Mac CodeWarrior bug */ +JSCList _jsd_context_list = JS_INIT_STATIC_CLIST(&_jsd_context_list); + +/* these are used to connect JSD_SetUserCallbacks() with JSD_DebuggerOn() */ +static JSD_UserCallbacks _callbacks; +static void* _user = NULL; +static JSRuntime* _jsrt = NULL; + +#ifdef JSD_HAS_DANGEROUS_THREAD +static void* _dangerousThread = NULL; +#endif + +#ifdef JSD_THREADSAFE +void* _jsd_global_lock = NULL; +#endif + +#ifdef DEBUG +void JSD_ASSERT_VALID_CONTEXT(JSDContext* jsdc) +{ + JS_ASSERT(jsdc->inited); + JS_ASSERT(jsdc->jsrt); + JS_ASSERT(jsdc->dumbContext); + JS_ASSERT(jsdc->glob); +} +#endif + +static JSClass global_class = { + "JSDGlobal", JSCLASS_GLOBAL_FLAGS, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSBool +_validateUserCallbacks(JSD_UserCallbacks* callbacks) +{ + return !callbacks || + (callbacks->size && callbacks->size <= sizeof(JSD_UserCallbacks)); +} + +static JSDContext* +_newJSDContext(JSRuntime* jsrt, + JSD_UserCallbacks* callbacks, + void* user, + JSObject* scopeobj) +{ + JSDContext* jsdc = NULL; + JSCrossCompartmentCall *call = NULL; + + if( ! jsrt ) + return NULL; + + if( ! _validateUserCallbacks(callbacks) ) + return NULL; + + jsdc = (JSDContext*) calloc(1, sizeof(JSDContext)); + if( ! jsdc ) + goto label_newJSDContext_failure; + + if( ! JSD_INIT_LOCKS(jsdc) ) + goto label_newJSDContext_failure; + + JS_INIT_CLIST(&jsdc->links); + + jsdc->jsrt = jsrt; + + if( callbacks ) + memcpy(&jsdc->userCallbacks, callbacks, callbacks->size); + + jsdc->user = user; + +#ifdef JSD_HAS_DANGEROUS_THREAD + jsdc->dangerousThread = _dangerousThread; +#endif + + JS_INIT_CLIST(&jsdc->threadsStates); + JS_INIT_CLIST(&jsdc->sources); + JS_INIT_CLIST(&jsdc->removedSources); + + jsdc->sourceAlterCount = 1; + + if( ! jsd_CreateAtomTable(jsdc) ) + goto label_newJSDContext_failure; + + if( ! jsd_InitObjectManager(jsdc) ) + goto label_newJSDContext_failure; + + if( ! jsd_InitScriptManager(jsdc) ) + goto label_newJSDContext_failure; + + jsdc->dumbContext = JS_NewContext(jsdc->jsrt, 256); + if( ! jsdc->dumbContext ) + goto label_newJSDContext_failure; + + JS_BeginRequest(jsdc->dumbContext); + + jsdc->glob = JS_NewCompartmentAndGlobalObject(jsdc->dumbContext, &global_class, NULL); + + if( ! jsdc->glob ) + goto label_newJSDContext_failure; + + call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob); + if( ! call ) + goto label_newJSDContext_failure; + + if( ! JS_InitStandardClasses(jsdc->dumbContext, jsdc->glob) ) + goto label_newJSDContext_failure; + + if( call ) + JS_LeaveCrossCompartmentCall(call); + + JS_EndRequest(jsdc->dumbContext); + + jsdc->data = NULL; + jsdc->inited = JS_TRUE; + + JSD_LOCK(); + JS_INSERT_LINK(&jsdc->links, &_jsd_context_list); + JSD_UNLOCK(); + + return jsdc; + +label_newJSDContext_failure: + if( jsdc ) { + jsd_DestroyObjectManager(jsdc); + jsd_DestroyAtomTable(jsdc); + JS_EndRequest(jsdc->dumbContext); + free(jsdc); + } + return NULL; +} + +static void +_destroyJSDContext(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + + JSD_LOCK(); + JS_REMOVE_LINK(&jsdc->links); + JSD_UNLOCK(); + + jsd_DestroyObjectManager(jsdc); + jsd_DestroyAtomTable(jsdc); + + jsdc->inited = JS_FALSE; + + /* + * We should free jsdc here, but we let it leak in case there are any + * asynchronous hooks calling into the system using it as a handle + * + * XXX we also leak the locks + */ + JS_DestroyContext(jsdc->dumbContext); + jsdc->dumbContext = NULL; +} + +/***************************************************************************/ + +JSDContext* +jsd_DebuggerOnForUser(JSRuntime* jsrt, + JSD_UserCallbacks* callbacks, + void* user, + JSObject* scopeobj) +{ + JSDContext* jsdc; + JSContext* iter = NULL; + + jsdc = _newJSDContext(jsrt, callbacks, user, scopeobj); + if( ! jsdc ) + return NULL; + + /* + * Set hooks here. The new/destroy script hooks are on even when + * the debugger is paused. The destroy hook so we'll clean up + * internal data structures when scripts are destroyed, and the + * newscript hook for backwards compatibility for now. We'd like + * to stop doing that. + */ + JS_SetNewScriptHookProc(jsdc->jsrt, jsd_NewScriptHookProc, jsdc); + JS_SetDestroyScriptHookProc(jsdc->jsrt, jsd_DestroyScriptHookProc, jsdc); + jsd_DebuggerUnpause(jsdc); +#ifdef LIVEWIRE + LWDBG_SetNewScriptHookProc(jsd_NewScriptHookProc, jsdc); +#endif + if( jsdc->userCallbacks.setContext ) + jsdc->userCallbacks.setContext(jsdc, jsdc->user); + return jsdc; +} + +JSDContext* +jsd_DebuggerOn(void) +{ + JS_ASSERT(_jsrt); + JS_ASSERT(_validateUserCallbacks(&_callbacks)); + return jsd_DebuggerOnForUser(_jsrt, &_callbacks, _user, NULL); +} + +void +jsd_DebuggerOff(JSDContext* jsdc) +{ + jsd_DebuggerPause(jsdc, JS_TRUE); + /* clear hooks here */ + JS_SetNewScriptHookProc(jsdc->jsrt, NULL, NULL); + JS_SetDestroyScriptHookProc(jsdc->jsrt, NULL, NULL); +#ifdef LIVEWIRE + LWDBG_SetNewScriptHookProc(NULL,NULL); +#endif + + /* clean up */ + JSD_LockScriptSubsystem(jsdc); + jsd_DestroyScriptManager(jsdc); + JSD_UnlockScriptSubsystem(jsdc); + jsd_DestroyAllSources(jsdc); + + _destroyJSDContext(jsdc); + + if( jsdc->userCallbacks.setContext ) + jsdc->userCallbacks.setContext(NULL, jsdc->user); +} + +void +jsd_DebuggerPause(JSDContext* jsdc, JSBool forceAllHooksOff) +{ + JS_SetDebuggerHandler(jsdc->jsrt, NULL, NULL); + if (forceAllHooksOff || !(jsdc->flags & JSD_COLLECT_PROFILE_DATA)) { + JS_SetExecuteHook(jsdc->jsrt, NULL, NULL); + JS_SetCallHook(jsdc->jsrt, NULL, NULL); + } + JS_SetThrowHook(jsdc->jsrt, NULL, NULL); + JS_SetDebugErrorHook(jsdc->jsrt, NULL, NULL); +} + +void +jsd_DebuggerUnpause(JSDContext* jsdc) +{ + JS_SetDebuggerHandler(jsdc->jsrt, jsd_DebuggerHandler, jsdc); + JS_SetExecuteHook(jsdc->jsrt, jsd_TopLevelCallHook, jsdc); + JS_SetCallHook(jsdc->jsrt, jsd_FunctionCallHook, jsdc); + JS_SetThrowHook(jsdc->jsrt, jsd_ThrowHandler, jsdc); + JS_SetDebugErrorHook(jsdc->jsrt, jsd_DebugErrorHook, jsdc); +} + +void +jsd_SetUserCallbacks(JSRuntime* jsrt, JSD_UserCallbacks* callbacks, void* user) +{ + _jsrt = jsrt; + _user = user; + +#ifdef JSD_HAS_DANGEROUS_THREAD + _dangerousThread = JSD_CURRENT_THREAD(); +#endif + + if( callbacks ) + memcpy(&_callbacks, callbacks, sizeof(JSD_UserCallbacks)); + else + memset(&_callbacks, 0 , sizeof(JSD_UserCallbacks)); +} + +void* +jsd_SetContextPrivate(JSDContext* jsdc, void *data) +{ + void *rval = jsdc->data; + jsdc->data = data; + return data; +} + +void* +jsd_GetContextPrivate(JSDContext* jsdc) +{ + return jsdc->data; +} + +void +jsd_ClearAllProfileData(JSDContext* jsdc) +{ + JSDScript *current; + + JSD_LOCK_SCRIPTS(jsdc); + current = (JSDScript *)jsdc->scripts.next; + while (current != (JSDScript *)&jsdc->scripts) + { + jsd_ClearScriptProfileData(jsdc, current); + current = (JSDScript *)current->links.next; + } + + JSD_UNLOCK_SCRIPTS(jsdc); +} + +JSDContext* +jsd_JSDContextForJSContext(JSContext* context) +{ + JSDContext* iter; + JSDContext* jsdc = NULL; + JSRuntime* runtime = JS_GetRuntime(context); + + JSD_LOCK(); + for( iter = (JSDContext*)_jsd_context_list.next; + iter != (JSDContext*)&_jsd_context_list; + iter = (JSDContext*)iter->links.next ) + { + if( runtime == iter->jsrt ) + { + jsdc = iter; + break; + } + } + JSD_UNLOCK(); + return jsdc; +} + +static JSBool +jsd_DebugErrorHook(JSContext *cx, const char *message, + JSErrorReport *report, void *closure) +{ + JSDContext* jsdc = (JSDContext*) closure; + JSD_ErrorReporter errorReporter; + void* errorReporterData; + + if( ! jsdc ) + { + JS_ASSERT(0); + return JS_TRUE; + } + if( JSD_IS_DANGEROUS_THREAD(jsdc) ) + return JS_TRUE; + + /* local in case hook gets cleared on another thread */ + JSD_LOCK(); + errorReporter = jsdc->errorReporter; + errorReporterData = jsdc->errorReporterData; + JSD_UNLOCK(); + + if(!errorReporter) + return JS_TRUE; + + switch(errorReporter(jsdc, cx, message, report, errorReporterData)) + { + case JSD_ERROR_REPORTER_PASS_ALONG: + return JS_TRUE; + case JSD_ERROR_REPORTER_RETURN: + return JS_FALSE; + case JSD_ERROR_REPORTER_DEBUG: + { + jsval rval; + JSD_ExecutionHookProc hook; + void* hookData; + + /* local in case hook gets cleared on another thread */ + JSD_LOCK(); + hook = jsdc->debugBreakHook; + hookData = jsdc->debugBreakHookData; + JSD_UNLOCK(); + + jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_DEBUG_REQUESTED, + hook, hookData, &rval); + /* XXX Should make this dependent on ExecutionHook retval */ + return JS_TRUE; + } + case JSD_ERROR_REPORTER_CLEAR_RETURN: + if(report && JSREPORT_IS_EXCEPTION(report->flags)) + JS_ClearPendingException(cx); + return JS_FALSE; + default: + JS_ASSERT(0); + break; + } + return JS_TRUE; +} + +JSBool +jsd_SetErrorReporter(JSDContext* jsdc, + JSD_ErrorReporter reporter, + void* callerdata) +{ + JSD_LOCK(); + jsdc->errorReporter = reporter; + jsdc->errorReporterData = callerdata; + JSD_UNLOCK(); + return JS_TRUE; +} + +JSBool +jsd_GetErrorReporter(JSDContext* jsdc, + JSD_ErrorReporter* reporter, + void** callerdata) +{ + JSD_LOCK(); + if( reporter ) + *reporter = jsdc->errorReporter; + if( callerdata ) + *callerdata = jsdc->errorReporterData; + JSD_UNLOCK(); + return JS_TRUE; +} diff --git a/js/jsd/jsd_hook.c b/js/jsd/jsd_hook.c new file mode 100644 index 0000000..45c6be8 --- /dev/null +++ b/js/jsd/jsd_hook.c @@ -0,0 +1,363 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript Debugging support - Hook support + */ + +#include "jsd.h" + +JSTrapStatus +jsd_InterruptHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, + void *closure) +{ + JSDScript* jsdscript; + JSDContext* jsdc = (JSDContext*) closure; + JSD_ExecutionHookProc hook; + void* hookData; + + if( ! jsdc || ! jsdc->inited ) + return JSTRAP_CONTINUE; + + if( JSD_IS_DANGEROUS_THREAD(jsdc) ) + return JSTRAP_CONTINUE; + + /* local in case jsdc->interruptHook gets cleared on another thread */ + JSD_LOCK(); + hook = jsdc->interruptHook; + hookData = jsdc->interruptHookData; + JSD_UNLOCK(); + + if (!hook) + return JSTRAP_CONTINUE; + + JSD_LOCK_SCRIPTS(jsdc); + jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, NULL); + JSD_UNLOCK_SCRIPTS(jsdc); + if( ! jsdscript ) + return JSTRAP_CONTINUE; + +#ifdef LIVEWIRE + if( ! jsdlw_UserCodeAtPC(jsdc, jsdscript, (jsuword)pc) ) + return JSTRAP_CONTINUE; +#endif + + return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_INTERRUPTED, + hook, hookData, rval); +} + +JSTrapStatus +jsd_DebuggerHandler(JSContext *cx, JSScript *script, jsbytecode *pc, + jsval *rval, void *closure) +{ + JSDScript* jsdscript; + JSDContext* jsdc = (JSDContext*) closure; + JSD_ExecutionHookProc hook; + void* hookData; + + if( ! jsdc || ! jsdc->inited ) + return JSTRAP_CONTINUE; + + if( JSD_IS_DANGEROUS_THREAD(jsdc) ) + return JSTRAP_CONTINUE; + + /* local in case jsdc->debuggerHook gets cleared on another thread */ + JSD_LOCK(); + hook = jsdc->debuggerHook; + hookData = jsdc->debuggerHookData; + JSD_UNLOCK(); + if(!hook) + return JSTRAP_CONTINUE; + + JSD_LOCK_SCRIPTS(jsdc); + jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, NULL); + JSD_UNLOCK_SCRIPTS(jsdc); + if( ! jsdscript ) + return JSTRAP_CONTINUE; + + return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_DEBUGGER_KEYWORD, + hook, hookData, rval); +} + + +JSTrapStatus +jsd_ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, + jsval *rval, void *closure) +{ + JSDScript* jsdscript; + JSDContext* jsdc = (JSDContext*) closure; + JSD_ExecutionHookProc hook; + void* hookData; + + if( ! jsdc || ! jsdc->inited ) + return JSD_HOOK_RETURN_CONTINUE_THROW; + + if( JSD_IS_DANGEROUS_THREAD(jsdc) ) + return JSD_HOOK_RETURN_CONTINUE_THROW; + + /* local in case jsdc->throwHook gets cleared on another thread */ + JSD_LOCK(); + hook = jsdc->throwHook; + hookData = jsdc->throwHookData; + JSD_UNLOCK(); + if (!hook) + return JSD_HOOK_RETURN_CONTINUE_THROW; + + JSD_LOCK_SCRIPTS(jsdc); + jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, NULL); + JSD_UNLOCK_SCRIPTS(jsdc); + if( ! jsdscript ) + return JSD_HOOK_RETURN_CONTINUE_THROW; + + JS_GetPendingException(cx, rval); + + return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_THROW, + hook, hookData, rval); +} + +JSTrapStatus +jsd_CallExecutionHook(JSDContext* jsdc, + JSContext *cx, + uintN type, + JSD_ExecutionHookProc hook, + void* hookData, + jsval* rval) +{ + uintN hookanswer = JSD_HOOK_THROW == type ? + JSD_HOOK_RETURN_CONTINUE_THROW : + JSD_HOOK_RETURN_CONTINUE; + JSDThreadState* jsdthreadstate; + + if(hook && NULL != (jsdthreadstate = jsd_NewThreadState(jsdc,cx))) + { + if ((type != JSD_HOOK_THROW && type != JSD_HOOK_INTERRUPTED) || + jsdc->flags & JSD_MASK_TOP_FRAME_ONLY || + !(jsdthreadstate->flags & TS_HAS_DISABLED_FRAME)) + { + /* + * if it's not a throw and it's not an interrupt, + * or we're only masking the top frame, + * or there are no disabled frames in this stack, + * then call out. + */ + hookanswer = hook(jsdc, jsdthreadstate, type, hookData, rval); + jsd_DestroyThreadState(jsdc, jsdthreadstate); + } + } + + switch(hookanswer) + { + case JSD_HOOK_RETURN_ABORT: + case JSD_HOOK_RETURN_HOOK_ERROR: + return JSTRAP_ERROR; + case JSD_HOOK_RETURN_RET_WITH_VAL: + return JSTRAP_RETURN; + case JSD_HOOK_RETURN_THROW_WITH_VAL: + return JSTRAP_THROW; + case JSD_HOOK_RETURN_CONTINUE: + break; + case JSD_HOOK_RETURN_CONTINUE_THROW: + /* only makes sense for jsd_ThrowHandler (which init'd rval) */ + JS_ASSERT(JSD_HOOK_THROW == type); + return JSTRAP_THROW; + default: + JS_ASSERT(0); + break; + } + return JSTRAP_CONTINUE; +} + +JSBool +jsd_CallCallHook (JSDContext* jsdc, + JSContext *cx, + uintN type, + JSD_CallHookProc hook, + void* hookData) +{ + JSBool hookanswer; + JSDThreadState* jsdthreadstate; + + hookanswer = JS_FALSE; + if(hook && NULL != (jsdthreadstate = jsd_NewThreadState(jsdc, cx))) + { + hookanswer = hook(jsdc, jsdthreadstate, type, hookData); + jsd_DestroyThreadState(jsdc, jsdthreadstate); + } + + return hookanswer; +} + +JSBool +jsd_SetInterruptHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata) +{ + JSD_LOCK(); + jsdc->interruptHookData = callerdata; + jsdc->interruptHook = hook; + JS_SetInterrupt(jsdc->jsrt, jsd_InterruptHandler, (void*) jsdc); + JSD_UNLOCK(); + + return JS_TRUE; +} + +JSBool +jsd_ClearInterruptHook(JSDContext* jsdc) +{ + JSD_LOCK(); + JS_ClearInterrupt(jsdc->jsrt, NULL, NULL ); + jsdc->interruptHook = NULL; + JSD_UNLOCK(); + + return JS_TRUE; +} + +JSBool +jsd_SetDebugBreakHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata) +{ + JSD_LOCK(); + jsdc->debugBreakHookData = callerdata; + jsdc->debugBreakHook = hook; + JSD_UNLOCK(); + + return JS_TRUE; +} + +JSBool +jsd_ClearDebugBreakHook(JSDContext* jsdc) +{ + JSD_LOCK(); + jsdc->debugBreakHook = NULL; + JSD_UNLOCK(); + + return JS_TRUE; +} + +JSBool +jsd_SetDebuggerHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata) +{ + JSD_LOCK(); + jsdc->debuggerHookData = callerdata; + jsdc->debuggerHook = hook; + JSD_UNLOCK(); + + return JS_TRUE; +} + +JSBool +jsd_ClearDebuggerHook(JSDContext* jsdc) +{ + JSD_LOCK(); + jsdc->debuggerHook = NULL; + JSD_UNLOCK(); + + return JS_TRUE; +} + +JSBool +jsd_SetThrowHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata) +{ + JSD_LOCK(); + jsdc->throwHookData = callerdata; + jsdc->throwHook = hook; + JSD_UNLOCK(); + + return JS_TRUE; +} + +JSBool +jsd_ClearThrowHook(JSDContext* jsdc) +{ + JSD_LOCK(); + jsdc->throwHook = NULL; + JSD_UNLOCK(); + + return JS_TRUE; +} + +JSBool +jsd_SetFunctionHook(JSDContext* jsdc, + JSD_CallHookProc hook, + void* callerdata) +{ + JSD_LOCK(); + jsdc->functionHookData = callerdata; + jsdc->functionHook = hook; + JSD_UNLOCK(); + + return JS_TRUE; +} + +JSBool +jsd_ClearFunctionHook(JSDContext* jsdc) +{ + JSD_LOCK(); + jsdc->functionHook = NULL; + JSD_UNLOCK(); + + return JS_TRUE; +} + +JSBool +jsd_SetTopLevelHook(JSDContext* jsdc, + JSD_CallHookProc hook, + void* callerdata) +{ + JSD_LOCK(); + jsdc->toplevelHookData = callerdata; + jsdc->toplevelHook = hook; + JSD_UNLOCK(); + + return JS_TRUE; +} + +JSBool +jsd_ClearTopLevelHook(JSDContext* jsdc) +{ + JSD_LOCK(); + jsdc->toplevelHook = NULL; + JSD_UNLOCK(); + + return JS_TRUE; +} + diff --git a/js/jsd/jsd_java.c b/js/jsd/jsd_java.c new file mode 100644 index 0000000..aacff10 --- /dev/null +++ b/js/jsd/jsd_java.c @@ -0,0 +1,810 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* this is all going away... replaced by code in js/jsd/java */ + +#if 0 + +#include "native.h" +#include "jsdebug.h" + +#include "_gen/netscape_jsdebug_DebugController.h" +#include "_gen/netscape_jsdebug_Script.h" +#include "_gen/netscape_jsdebug_JSThreadState.h" +#include "_gen/netscape_jsdebug_JSStackFrameInfo.h" +#include "_gen/netscape_jsdebug_JSPC.h" +#include "_gen/netscape_jsdebug_JSSourceTextProvider.h" +#include "_gen/netscape_jsdebug_JSErrorReporter.h" + +static JSDContext* context = 0; +static struct Hnetscape_jsdebug_DebugController* controller = 0; + +/***************************************************************************/ +/* helpers */ + +static JHandle* +_constructInteger(ExecEnv *ee, long i) +{ + return (JHandle*) + execute_java_constructor(ee, "java/lang/Integer", 0, "(I)", i); +} + +static JHandle* +_putHash(ExecEnv *ee, JHandle* tbl, JHandle* key, JHandle* ob) +{ + return (JHandle*) + execute_java_dynamic_method( + ee, tbl, "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + key, ob ); +} + +static JHandle* +_getHash(ExecEnv *ee, JHandle* tbl, JHandle* key) +{ + return (JHandle*) + execute_java_dynamic_method( + ee, tbl, "get", + "(Ljava/lang/Object;)Ljava/lang/Object;", + key ); +} + +static JHandle* +_removeHash(ExecEnv *ee, JHandle* tbl, JHandle* key) +{ + return (JHandle*) + execute_java_dynamic_method( + ee, tbl, "remove", + "(Ljava/lang/Object;)Ljava/lang/Object;", + key ); +} + +struct Hnetscape_jsdebug_JSStackFrameInfo* +_constructJSStackFrameInfo( ExecEnv* ee, JSDStackFrameInfo* jsdframe, + struct Hnetscape_jsdebug_JSThreadState* threadState ) +{ + struct Hnetscape_jsdebug_JSStackFrameInfo* frame; + + frame = (struct Hnetscape_jsdebug_JSStackFrameInfo*) + execute_java_constructor( ee, "netscape/jsdebug/JSStackFrameInfo", 0, + "(Lnetscape/jsdebug/JSThreadState;)", + threadState ); + if( ! frame ) + return NULL; + + /* XXX fill in additional fields */ + unhand(frame)->_nativePtr = (long) jsdframe; + + return frame; +} + +struct Hnetscape_jsdebug_JSPC* +_constructJSPC( ExecEnv* ee, struct Hnetscape_jsdebug_Script* script, long pc ) +{ + struct Hnetscape_jsdebug_JSPC * pcOb; + + pcOb = (struct Hnetscape_jsdebug_JSPC *) + execute_java_constructor( ee, "netscape/jsdebug/JSPC", 0, + "(Lnetscape/jsdebug/Script;I)", + script, pc ); + if( ! pcOb ) + return NULL; + + /* XXX fill in additional fields */ + + return pcOb; +} + +static Hnetscape_jsdebug_Script* +_scriptObFromJSDScriptPtr( ExecEnv* ee, JSDScript* jsdscript ) +{ + JHandle* tbl = (JHandle*) unhand(controller)->scriptTable; + JHandle* key = _constructInteger(ee,(long)jsdscript); + return (Hnetscape_jsdebug_Script*) _getHash( ee, tbl, key ); +} + +/***************************************************************************/ + +void +_scriptHook( JSDContext* jsdc, + JSDScript* jsdscript, + JSBool creating, + void* callerdata ) +{ + Hnetscape_jsdebug_Script* script; + ExecEnv* ee = EE(); + + if( ! context || ! controller || ! ee ) + return; + + if( creating ) + { + char* url = (char*)JSD_GetScriptFilename (jsdc, jsdscript); + JSString* function = JSD_GetScriptFunctionId (jsdc, jsdscript); + int base = JSD_GetScriptBaseLineNumber (jsdc, jsdscript); + int extent = JSD_GetScriptLineExtent (jsdc, jsdscript); + + if( ! url ) + { + return; + /* url = ""; */ + } + + /* create Java Object for Script */ + script = (Hnetscape_jsdebug_Script*) + execute_java_constructor(ee, "netscape/jsdebug/Script", 0, "()"); + + if( ! script ) + return; + + /* set the members */ + unhand(script)->_url = makeJavaString(url,strlen(url)); + unhand(script)->_function = function ? makeJavaString(function,strlen(function)) : 0; + unhand(script)->_baseLineNumber = base; + unhand(script)->_lineExtent = extent; + unhand(script)->_nativePtr = (long)jsdscript; + + /* add it to the hash table */ + _putHash( ee, (JHandle*) unhand(controller)->scriptTable, + _constructInteger(ee, (long)jsdscript), (JHandle*)script ); + + /* call the hook */ + if( unhand(controller)->scriptHook ) + { + execute_java_dynamic_method( ee,(JHandle*)unhand(controller)->scriptHook, + "justLoadedScript", + "(Lnetscape/jsdebug/Script;)V", + script ); + } + } + else + { + JHandle* tbl = (JHandle*) unhand(controller)->scriptTable; + JHandle* key = _constructInteger(ee,(long)jsdscript); + + /* find Java Object for Script */ + script = (Hnetscape_jsdebug_Script*) _getHash( ee, tbl, key ); + + if( ! script ) + return; + + /* remove it from the hash table */ + _removeHash( ee, tbl, key ); + + /* call the hook */ + if( unhand(controller)->scriptHook ) + { + execute_java_dynamic_method( ee,(JHandle*)unhand(controller)->scriptHook, + "aboutToUnloadScript", + "(Lnetscape/jsdebug/Script;)V", + script ); + } + /* set the Script as invalid */ + execute_java_dynamic_method( ee,(JHandle*)script, + "_setInvalid", + "()V" ); + } +} + +/***************************************************************************/ +PRUintn +_executionHook( JSDContext* jsdc, + JSDThreadState* jsdstate, + PRUintn type, + void* callerdata ) +{ + Hnetscape_jsdebug_JSThreadState* threadState; + Hnetscape_jsdebug_Script* script; + JHandle* pcOb; + JSDStackFrameInfo* jsdframe; + JSDScript* jsdscript; + int pc; + JHandle* tblScript; + JHandle* keyScript; + ExecEnv* ee = EE(); + + if( ! context || ! controller || ! ee ) + return JSD_HOOK_RETURN_HOOK_ERROR; + + /* get the JSDStackFrameInfo */ + jsdframe = JSD_GetStackFrame(jsdc, jsdstate); + if( ! jsdframe ) + return JSD_HOOK_RETURN_HOOK_ERROR; + + /* get the JSDScript */ + jsdscript = JSD_GetScriptForStackFrame(jsdc, jsdstate, jsdframe); + if( ! jsdscript ) + return JSD_HOOK_RETURN_HOOK_ERROR; + + /* find Java Object for Script */ + tblScript = (JHandle*) unhand(controller)->scriptTable; + keyScript = _constructInteger(ee, (long)jsdscript); + script = (Hnetscape_jsdebug_Script*) _getHash( ee, tblScript, keyScript ); + if( ! script ) + return JSD_HOOK_RETURN_HOOK_ERROR; + + /* generate a JSPC */ + pc = JSD_GetPCForStackFrame(jsdc, jsdstate, jsdframe); + + pcOb = (JHandle*) + _constructJSPC(ee, script, pc); + if( ! pcOb ) + return JSD_HOOK_RETURN_HOOK_ERROR; + + /* build a JSThreadState */ + threadState = (struct Hnetscape_jsdebug_JSThreadState*) + execute_java_constructor( ee, "netscape/jsdebug/JSThreadState",0,"()"); + if( ! threadState ) + return JSD_HOOK_RETURN_HOOK_ERROR; + + /* populate the ThreadState */ + /* XXX FILL IN THE REST... */ + unhand(threadState)->valid = 1; /* correct value for true? */ + unhand(threadState)->currentFramePtr = (long) jsdframe; + unhand(threadState)->nativeThreadState = (long) jsdstate; + unhand(threadState)->continueState = netscape_jsdebug_JSThreadState_DEBUG_STATE_RUN; + + /* XXX FILL IN THE REST... */ + + + /* find and call the appropriate Hook */ + if( JSD_HOOK_INTERRUPTED == type ) + { + JHandle* hook; + + /* clear the JSD level hook (must reset on next sendInterrupt0()*/ + JSD_ClearInterruptHook(context); + + hook = (JHandle*) unhand(controller)->interruptHook; + if( ! hook ) + return JSD_HOOK_RETURN_HOOK_ERROR; + + /* call the hook */ + execute_java_dynamic_method( + ee, hook, "aboutToExecute", + "(Lnetscape/jsdebug/ThreadStateBase;Lnetscape/jsdebug/PC;)V", + threadState, pcOb ); + } + else if( JSD_HOOK_DEBUG_REQUESTED == type ) + { + JHandle* hook; + + hook = (JHandle*) unhand(controller)->debugBreakHook; + if( ! hook ) + return JSD_HOOK_RETURN_HOOK_ERROR; + + /* call the hook */ + execute_java_dynamic_method( + ee, hook, "aboutToExecute", + "(Lnetscape/jsdebug/ThreadStateBase;Lnetscape/jsdebug/PC;)V", + threadState, pcOb ); + } + else if( JSD_HOOK_BREAKPOINT == type ) + { + JHandle* hook; + + hook = (JHandle*) + execute_java_dynamic_method( + ee,(JHandle*)controller, + "getInstructionHook0", + "(Lnetscape/jsdebug/PC;)Lnetscape/jsdebug/InstructionHook;", + pcOb ); + if( ! hook ) + return JSD_HOOK_RETURN_HOOK_ERROR; + + /* call the hook */ + execute_java_dynamic_method( + ee, hook, "aboutToExecute", + "(Lnetscape/jsdebug/ThreadStateBase;)V", + threadState ); + } + + if( netscape_jsdebug_JSThreadState_DEBUG_STATE_THROW == + unhand(threadState)->continueState ) + return JSD_HOOK_RETURN_ABORT; + + return JSD_HOOK_RETURN_CONTINUE; +} + +PRUintn +_errorReporter( JSDContext* jsdc, + JSContext* cx, + const char* message, + JSErrorReport* report, + void* callerdata ) +{ + JHandle* reporter; + JHandle* msg = NULL; + JHandle* filename = NULL; + int lineno = 0; + JHandle* linebuf = NULL; + int tokenOffset = 0; + ExecEnv* ee = EE(); + + if( ! context || ! controller || ! ee ) + return JSD_ERROR_REPORTER_PASS_ALONG; + + reporter = (JHandle*) unhand(controller)->errorReporter; + if( ! reporter ) + return JSD_ERROR_REPORTER_PASS_ALONG; + + if( message ) + msg = (JHandle*) makeJavaString((char*)message, strlen(message)); + if( report && report->filename ) + filename = (JHandle*) makeJavaString((char*)report->filename, strlen(report->filename)); + if( report && report->linebuf ) + linebuf = (JHandle*) makeJavaString((char*)report->linebuf, strlen(report->linebuf)); + if( report ) + lineno = report->lineno; + if( report && report->linebuf && report->tokenptr ) + tokenOffset = report->tokenptr - report->linebuf; + + return (int) + execute_java_dynamic_method( + ee, reporter, "reportError", + "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;I)I", + msg, + filename, + lineno, + linebuf, + tokenOffset ); +} + +/***************************************************************************/ +/* from "_gen\netscape_jsdebug_DebugController.h" */ + + +/* XXX HACK */ +JSDContext* _simContext = 0; + +void netscape_jsdebug_DebugController__setController(struct Hnetscape_jsdebug_DebugController * self,/*boolean*/ long on) +{ + if(on) + { + context = JSD_DebuggerOn(); + if( ! context ) + return; + + _simContext = context; /* XXX HACK */ + + unhand(self)->_nativeContext = (long) context; + controller = self; + JSD_SetScriptHook(context, _scriptHook, (void*)1 ); + JSD_SetErrorReporter(context, _errorReporter, (void*)1 ); + JSD_SetDebugBreakHook(context, _executionHook, (void*)1 ); + } + else + { + /* XXX stop somehow... */ + /* kill context */ + JSD_SetDebugBreakHook(context, NULL, NULL ); + JSD_SetErrorReporter(context, NULL, NULL); + JSD_SetScriptHook(context, NULL, NULL); + context = 0; + controller = 0; + } +} + +void netscape_jsdebug_DebugController_setInstructionHook0(struct Hnetscape_jsdebug_DebugController * self,struct Hnetscape_jsdebug_PC * pcOb) +{ + Hnetscape_jsdebug_Script* script; + JSDScript* jsdscript; + PRUintn pc; + ExecEnv* ee = EE(); + + if( ! context || ! controller || ! ee ) + return; + + script = (Hnetscape_jsdebug_Script*) + execute_java_dynamic_method(ee, (JHandle*)pcOb, "getScript","()Lnetscape/jsdebug/Script;"); + + if( ! script ) + return; + + jsdscript = (JSDScript*) unhand(script)->_nativePtr; + if( ! jsdscript ) + return; + + pc = (PRUintn) + execute_java_dynamic_method(ee, (JHandle*)pcOb, "getPC","()I"); + + JSD_SetExecutionHook(context, jsdscript, pc, _executionHook, 0); +} + +void netscape_jsdebug_DebugController_sendInterrupt0(struct Hnetscape_jsdebug_DebugController * self) +{ + if( ! context || ! controller ) + return; + JSD_SetInterruptHook(context, _executionHook, 0); +} + +struct Hjava_lang_String *netscape_jsdebug_DebugController_executeScriptInStackFrame0(struct Hnetscape_jsdebug_DebugController *self,struct Hnetscape_jsdebug_JSStackFrameInfo *frame,struct Hjava_lang_String *src,struct Hjava_lang_String *filename,long lineno) +{ + struct Hnetscape_jsdebug_JSThreadState* threadStateOb; + JSDThreadState* jsdthreadstate; + JSDStackFrameInfo* jsdframe; + char* filenameC; + char* srcC; + JSString* jsstr; + jsval rval; + JSBool success; + int srclen; + + threadStateOb = (struct Hnetscape_jsdebug_JSThreadState*)unhand(frame)->threadState; + jsdthreadstate = (JSDThreadState*) unhand(threadStateOb)->nativeThreadState; + + jsdframe = (JSDStackFrameInfo*) unhand(frame)->_nativePtr; + + if( ! context || ! controller || ! jsdframe ) + return NULL; + + filenameC = allocCString(filename); + if( ! filenameC ) + return NULL; + srcC = allocCString(src); + if( ! srcC ) + { + free(filenameC); + return NULL; + } + + srclen = strlen(srcC); + + success = JSD_EvaluateScriptInStackFrame(context, jsdthreadstate, jsdframe, + srcC, srclen, + filenameC, lineno, &rval); + + /* XXX crashing on Windows under Symantec (though I can't see why!)*/ + + free(filenameC); + free(srcC); + + + if( ! success ) + return NULL; + + if( JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval) ) + return NULL; + + jsstr = JSD_ValToStringInStackFrame(context,jsdthreadstate,jsdframe,rval); + if( ! jsstr ) + return NULL; + + /* XXXbe should use JS_GetStringChars and preserve Unicode. */ + return makeJavaString((char*)JS_GetStringBytes(jsstr), JS_GetStringLength(jsstr)); +} + +long netscape_jsdebug_DebugController_getNativeMajorVersion(struct Hnetscape_jsdebug_DebugController* self) +{ + return (long) JSD_GetMajorVersion(); +} + +long netscape_jsdebug_DebugController_getNativeMinorVersion(struct Hnetscape_jsdebug_DebugController* self) +{ + return (long) JSD_GetMinorVersion(); +} + +/***************************************************************************/ +/* from "_gen\netscape_jsdebug_Script.h" */ + +struct Hnetscape_jsdebug_JSPC *netscape_jsdebug_Script_getClosestPC(struct Hnetscape_jsdebug_Script * self,long line) +{ + PRUintn pc; + JSDScript* jsdscript; + + if( ! context || ! controller ) + return 0; + + jsdscript = (JSDScript*) unhand(self)->_nativePtr; + if( ! jsdscript ) + return 0; + + pc = JSD_GetClosestPC(context, jsdscript, line); + + if( -1 == pc ) + return 0; + return _constructJSPC( 0, self, pc); +} + +/***************************************************************************/ +/* from "_gen\netscape_jsdebug_JSThreadState.h" */ + +long netscape_jsdebug_JSThreadState_countStackFrames(struct Hnetscape_jsdebug_JSThreadState * self) +{ + JSDThreadState* jsdstate; + + if( ! context || ! controller ) + return 0; + + jsdstate = (JSDThreadState*) unhand(self)->nativeThreadState; + + if( ! jsdstate ) + return 0; + + return (long) JSD_GetCountOfStackFrames(context, jsdstate); +} + +struct Hnetscape_jsdebug_StackFrameInfo *netscape_jsdebug_JSThreadState_getCurrentFrame(struct Hnetscape_jsdebug_JSThreadState * self) +{ + JSDThreadState* jsdstate; + JSDStackFrameInfo* jsdframe; + + if( ! context || ! controller ) + return NULL; + + jsdstate = (JSDThreadState*) unhand(self)->nativeThreadState; + + if( ! jsdstate ) + return NULL; + + jsdframe = JSD_GetStackFrame(context, jsdstate); + if( ! jsdframe ) + return NULL; + + return (struct Hnetscape_jsdebug_StackFrameInfo*) + _constructJSStackFrameInfo( 0, jsdframe, self ); +} + + +/***************************************************************************/ +/* from "_gen\netscape_jsdebug_JSStackFrameInfo.h" */ + +struct Hnetscape_jsdebug_StackFrameInfo *netscape_jsdebug_JSStackFrameInfo_getCaller0(struct Hnetscape_jsdebug_JSStackFrameInfo * self) +{ + JSDStackFrameInfo* jsdframeCur; + JSDStackFrameInfo* jsdframeCaller; + struct Hnetscape_jsdebug_JSThreadState* threadState; + JSDThreadState* jsdthreadstate; + + if( ! context || ! controller ) + return NULL; + + jsdframeCur = (JSDStackFrameInfo*) unhand(self)->_nativePtr; + if( ! jsdframeCur ) + return NULL; + + threadState = (struct Hnetscape_jsdebug_JSThreadState*) unhand(self)->threadState; + if( ! threadState ) + return NULL; + + jsdthreadstate = (JSDThreadState*) unhand(threadState)->nativeThreadState; + if( ! jsdthreadstate ) + return NULL; + + jsdframeCaller = JSD_GetCallingStackFrame(context, jsdthreadstate, jsdframeCur); + if( ! jsdframeCaller ) + return NULL; + + return (struct Hnetscape_jsdebug_StackFrameInfo*) + _constructJSStackFrameInfo( 0, jsdframeCaller, threadState ); +} +struct Hnetscape_jsdebug_PC *netscape_jsdebug_JSStackFrameInfo_getPC(struct Hnetscape_jsdebug_JSStackFrameInfo * self) +{ + JSDScript* jsdscript; + JSDStackFrameInfo* jsdframe; + struct Hnetscape_jsdebug_Script* script; + struct Hnetscape_jsdebug_JSThreadState* threadState; + JSDThreadState* jsdthreadstate; + int pc; + ExecEnv* ee = EE(); + + if( ! context || ! controller || ! ee ) + return NULL; + + jsdframe = (JSDStackFrameInfo*) unhand(self)->_nativePtr; + if( ! jsdframe ) + return NULL; + + threadState = (struct Hnetscape_jsdebug_JSThreadState*) unhand(self)->threadState; + if( ! threadState ) + return NULL; + + jsdthreadstate = (JSDThreadState*) unhand(threadState)->nativeThreadState; + if( ! jsdthreadstate ) + return NULL; + + jsdscript = JSD_GetScriptForStackFrame(context, jsdthreadstate, jsdframe ); + if( ! jsdscript ) + return NULL; + + script = _scriptObFromJSDScriptPtr(ee, jsdscript); + if( ! script ) + return NULL; + + pc = JSD_GetPCForStackFrame(context, jsdthreadstate, jsdframe); + if( ! pc ) + return NULL; + + return (struct Hnetscape_jsdebug_PC*) _constructJSPC(ee, script, pc); +} + +/***************************************************************************/ +/* from "_gen\netscape_jsdebug_JSPC.h" */ + +struct Hnetscape_jsdebug_SourceLocation *netscape_jsdebug_JSPC_getSourceLocation(struct Hnetscape_jsdebug_JSPC * self) +{ + JSDScript* jsdscript; + struct Hnetscape_jsdebug_Script* script; + struct Hnetscape_jsdebug_JSPC* newPCOb; + int line; + int newpc; + int pc; + ExecEnv* ee = EE(); + + if( ! context || ! controller || ! ee ) + return NULL; + + script = unhand(self)->script; + + if( ! script ) + return NULL; + + jsdscript = (JSDScript*) unhand(script)->_nativePtr; + if( ! jsdscript ) + return NULL; + pc = unhand(self)->pc; + + line = JSD_GetClosestLine(context, jsdscript, pc); + newpc = JSD_GetClosestPC(context, jsdscript, line); + + newPCOb = _constructJSPC(ee, script, newpc ); + if( ! newPCOb ) + return NULL; + + return (struct Hnetscape_jsdebug_SourceLocation *) + execute_java_constructor( ee, "netscape/jsdebug/JSSourceLocation", 0, + "(Lnetscape/jsdebug/JSPC;I)", + newPCOb, line ); +} + +/***************************************************************************/ +/* from "_gen\netscape_jsdebug_JSSourceTextProvider.h" */ + +struct Hnetscape_jsdebug_SourceTextItem *netscape_jsdebug_JSSourceTextProvider_loadSourceTextItem0(struct Hnetscape_jsdebug_JSSourceTextProvider * self,struct Hjava_lang_String * url) +{ + /* this should attempt to load the source for the indicated URL */ + return NULL; +} + +void netscape_jsdebug_JSSourceTextProvider_refreshSourceTextVector(struct Hnetscape_jsdebug_JSSourceTextProvider * self) +{ + + JHandle* vec; + JHandle* itemOb; + JSDSourceText* iterp = 0; + JSDSourceText* item; + const char* url; + struct Hjava_lang_String* urlOb; + ExecEnv* ee = EE(); + + if( ! context || ! controller || ! ee ) + return; + + /* create new vector */ + vec = (JHandle*) execute_java_constructor(ee, "netscape/util/Vector", 0, "()"); + if( ! vec ) + return; + + /* lock the native subsystem */ + JSD_LockSourceTextSubsystem(context); + + /* iterate through the native items */ + while( 0 != (item = JSD_IterateSources(context, &iterp)) ) + { + int urlStrLen; + int status = JSD_GetSourceStatus(context,item); + + /* try to find Java object */ + url = JSD_GetSourceURL(context, item); + if( ! url || 0 == (urlStrLen = strlen(url)) ) /* ignoring those with no url */ + continue; + + urlOb = makeJavaString((char*)url,urlStrLen); + if( ! urlOb ) + continue; + + itemOb = (JHandle*) + execute_java_dynamic_method( ee, (JHandle*)self, "findSourceTextItem0", + "(Ljava/lang/String;)Lnetscape/jsdebug/SourceTextItem;", + urlOb ); + + if( ! itemOb ) + { + /* if not found then generate new item */ + struct Hjava_lang_String* textOb; + const char* str; + int length; + + if( ! JSD_GetSourceText(context, item, &str, &length ) ) + { + str = ""; + length = 0; + } + textOb = makeJavaString((char*)str, length); + + itemOb = (JHandle*) + execute_java_constructor(ee, "netscape/jsdebug/SourceTextItem",0, + "(Ljava/lang/String;Ljava/lang/String;I)", + urlOb, textOb, status ); + } + else if( JSD_IsSourceDirty(context, item) && + JSD_SOURCE_CLEARED != status ) + { + /* if found and dirty then update */ + struct Hjava_lang_String* textOb; + const char* str; + int length; + + if( ! JSD_GetSourceText(context, item, &str, &length ) ) + { + str = ""; + length = 0; + } + textOb = makeJavaString((char*)str, length); + execute_java_dynamic_method(ee, itemOb, "setText", + "(Ljava/lang/String;)V", textOb); + execute_java_dynamic_method(ee, itemOb, "setStatus", + "(I)V", status ); + execute_java_dynamic_method(ee, itemOb, "setDirty", "(Z)V", 1 ); + } + + /* we have our copy; clear the native cached text */ + if( JSD_SOURCE_INITED != status && + JSD_SOURCE_PARTIAL != status && + JSD_SOURCE_CLEARED != status ) + { + JSD_ClearSourceText(context, item); + } + + /* set the item clean */ + JSD_SetSourceDirty(context, item, FALSE ); + + /* add the item to the vector */ + if( itemOb ) + execute_java_dynamic_method(ee, vec, "addElement", + "(Ljava/lang/Object;)V", itemOb ); + } + /* unlock the native subsystem */ + JSD_UnlockSourceTextSubsystem(context); + + /* set main vector to our new vector */ + + unhand(self)->_sourceTextVector = (struct Hnetscape_util_Vector*) vec; +} + + +#endif diff --git a/js/jsd/jsd_lock.c b/js/jsd/jsd_lock.c new file mode 100644 index 0000000..ff5e695 --- /dev/null +++ b/js/jsd/jsd_lock.c @@ -0,0 +1,256 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript Debugging support - Locking and threading support + */ + +/* +* ifdef JSD_USE_NSPR_LOCKS then you musat build and run against NSPR2. +* Otherwise, there are stubs that can be filled in with your own locking +* code. Also, note that these stubs include a jsd_CurrentThread() +* implementation that only works on Win32 - this is needed for the inprocess +* Java-based debugger. +*/ + +#include "jsd.h" + +#ifdef JSD_THREADSAFE + +#ifdef JSD_USE_NSPR_LOCKS + +#include "prlock.h" +#include "prthread.h" + +#ifdef JSD_ATTACH_THREAD_HACK +#include "pprthred.h" /* need this as long as JS_AttachThread is needed */ +#endif + +struct JSDStaticLock +{ + void* owner; + PRLock* lock; + int count; +#ifdef DEBUG + uint16 sig; +#endif +}; + +/* + * This exists to wrap non-NSPR theads (e.g. Java threads) in NSPR wrappers. + * XXX We ignore the memory leak issue. + * It is claimed that future versions of NSPR will automatically wrap on + * the call to PR_GetCurrentThread. + * + * XXX We ignore the memory leak issue - i.e. we never call PR_DetachThread. + * + */ +#undef _CURRENT_THREAD +#ifdef JSD_ATTACH_THREAD_HACK +#define _CURRENT_THREAD(out) \ +JS_BEGIN_MACRO \ + out = (void*) PR_GetCurrentThread(); \ + if(!out) \ + out = (void*) JS_AttachThread(PR_USER_THREAD,PR_PRIORITY_NORMAL,NULL);\ + JS_ASSERT(out); \ +JS_END_MACRO +#else +#define _CURRENT_THREAD(out) \ +JS_BEGIN_MACRO \ + out = (void*) PR_GetCurrentThread(); \ + JS_ASSERT(out); \ +JS_END_MACRO +#endif + +#ifdef DEBUG +#define JSD_LOCK_SIG 0x10CC10CC +void ASSERT_VALID_LOCK(JSDStaticLock* lock) +{ + JS_ASSERT(lock); + JS_ASSERT(lock->lock); + JS_ASSERT(lock->count >= 0); + JS_ASSERT(lock->sig == (uint16) JSD_LOCK_SIG); +} +#else +#define ASSERT_VALID_LOCK(x) ((void)0) +#endif + +void* +jsd_CreateLock() +{ + JSDStaticLock* lock; + + if( ! (lock = calloc(1, sizeof(JSDStaticLock))) || + ! (lock->lock = PR_NewLock()) ) + { + if(lock) + { + free(lock); + lock = NULL; + } + } +#ifdef DEBUG + if(lock) lock->sig = (uint16) JSD_LOCK_SIG; +#endif + return lock; +} + +void +jsd_Lock(JSDStaticLock* lock) +{ + void* me; + ASSERT_VALID_LOCK(lock); + _CURRENT_THREAD(me); + + if(lock->owner == me) + { + lock->count++; + JS_ASSERT(lock->count > 1); + } + else + { + PR_Lock(lock->lock); /* this can block... */ + JS_ASSERT(lock->owner == 0); + JS_ASSERT(lock->count == 0); + lock->count = 1; + lock->owner = me; + } +} + +void +jsd_Unlock(JSDStaticLock* lock) +{ + void* me; + ASSERT_VALID_LOCK(lock); + _CURRENT_THREAD(me); + + /* it's an error to unlock a lock you don't own */ + JS_ASSERT(lock->owner == me); + if(lock->owner != me) + return; + + if(--lock->count == 0) + { + lock->owner = NULL; + PR_Unlock(lock->lock); + } +} + +#ifdef DEBUG +JSBool +jsd_IsLocked(JSDStaticLock* lock) +{ + void* me; + ASSERT_VALID_LOCK(lock); + _CURRENT_THREAD(me); + if (lock->owner != me) + return JS_FALSE; + JS_ASSERT(lock->count > 0); + return JS_TRUE; +} +#endif /* DEBUG */ + +void* +jsd_CurrentThread() +{ + void* me; + _CURRENT_THREAD(me); + return me; +} + + +#else /* ! JSD_USE_NSPR_LOCKS */ + +#ifdef WIN32 +#pragma message("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") +#pragma message("!! you are compiling the stubbed version of jsd_lock.c !!") +#pragma message("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") +#endif + +/* + * NOTE: 'Real' versions of these locks must be reentrant in the sense that + * they support nested calls to lock and unlock. + */ + +void* +jsd_CreateLock() +{ + return (void*)1; +} + +void +jsd_Lock(void* lock) +{ +} + +void +jsd_Unlock(void* lock) +{ +} + +#ifdef DEBUG +JSBool +jsd_IsLocked(void* lock) +{ + return JS_TRUE; +} +#endif /* DEBUG */ + +/* + * This Windows only thread id code is here to allow the Java-based + * JSDebugger to work with the single threaded js.c shell (even without + * real locking and threading support). + */ + +#ifdef WIN32 +/* bogus (but good enough) declaration*/ +extern void* __stdcall GetCurrentThreadId(void); +#endif + +void* +jsd_CurrentThread() +{ +#ifdef WIN32 + return GetCurrentThreadId(); +#else + return (void*)1; +#endif +} + +#endif /* JSD_USE_NSPR_LOCKS */ + +#endif /* JSD_THREADSAFE */ diff --git a/js/jsd/jsd_lock.h b/js/jsd/jsd_lock.h new file mode 100644 index 0000000..0a6e0a9 --- /dev/null +++ b/js/jsd/jsd_lock.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Header for JavaScript Debugging support - Locking and threading functions + */ + +#ifndef jsd_lock_h___ +#define jsd_lock_h___ + +/* + * If you want to support threading and locking, define JSD_THREADSAFE and + * implement the functions below. + */ + +/* + * NOTE: These locks must be reentrant in the sense that they support + * nested calls to lock and unlock. + */ + +typedef struct JSDStaticLock JSDStaticLock; + +extern void* +jsd_CreateLock(); + +extern void +jsd_Lock(JSDStaticLock* lock); + +extern void +jsd_Unlock(JSDStaticLock* lock); + +#ifdef DEBUG +extern JSBool +jsd_IsLocked(JSDStaticLock* lock); +#endif /* DEBUG */ + +extern void* +jsd_CurrentThread(); + +#endif /* jsd_lock_h___ */ diff --git a/js/jsd/jsd_obj.c b/js/jsd/jsd_obj.c new file mode 100644 index 0000000..00a5d8c --- /dev/null +++ b/js/jsd/jsd_obj.c @@ -0,0 +1,286 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript Debugging support - Object support + */ + +#include "jsd.h" + +/* +* #define JSD_TRACE 1 +*/ + +#ifdef JSD_TRACE +#define TRACEOBJ(jsdc, jsdobj, which) _traceObj(jsdc, jsdobj, which) + +static char * +_describeObj(JSDContext* jsdc, JSDObject *jsdobj) +{ + return + JS_smprintf("%0x new'd in %s at line %d using ctor %s in %s at line %d", + (int)jsdobj, + JSD_GetObjectNewURL(jsdc, jsdobj), + JSD_GetObjectNewLineNumber(jsdc, jsdobj), + JSD_GetObjectConstructorName(jsdc, jsdobj), + JSD_GetObjectConstructorURL(jsdc, jsdobj), + JSD_GetObjectConstructorLineNumber(jsdc, jsdobj)); +} + +static void +_traceObj(JSDContext* jsdc, JSDObject* jsdobj, int which) +{ + char* description; + + if( !jsdobj ) + return; + + description = _describeObj(jsdc, jsdobj); + + printf("%s : %s\n", + which == 0 ? "new " : + which == 1 ? "final" : + "ctor ", + description); + if(description) + free(description); +} +#else +#define TRACEOBJ(jsdc, jsdobj, which) ((void)0) +#endif /* JSD_TRACE */ + +#ifdef DEBUG +void JSD_ASSERT_VALID_OBJECT(JSDObject* jsdobj) +{ + JS_ASSERT(jsdobj); + JS_ASSERT(!JS_CLIST_IS_EMPTY(&jsdobj->links)); + JS_ASSERT(jsdobj->obj); +} +#endif + + +static void +_destroyJSDObject(JSDContext* jsdc, JSDObject* jsdobj) +{ + JS_ASSERT(JSD_OBJECTS_LOCKED(jsdc)); + + JS_REMOVE_LINK(&jsdobj->links); + JS_HashTableRemove(jsdc->objectsTable, jsdobj->obj); + + if(jsdobj->newURL) + jsd_DropAtom(jsdc, jsdobj->newURL); + if(jsdobj->ctorURL) + jsd_DropAtom(jsdc, jsdobj->ctorURL); + if(jsdobj->ctorName) + jsd_DropAtom(jsdc, jsdobj->ctorName); + free(jsdobj); +} + +static JSDObject* +_createJSDObject(JSDContext* jsdc, JSContext *cx, JSObject *obj) +{ + JSDObject* jsdobj; + JSStackFrame* fp; + JSStackFrame* iter = NULL; + const char* newURL; + jsbytecode* pc; + + JS_ASSERT(JSD_OBJECTS_LOCKED(jsdc)); + + jsdobj = (JSDObject*) calloc(1, sizeof(JSDObject)); + if (jsdobj) + { + JS_INIT_CLIST(&jsdobj->links); + JS_APPEND_LINK(&jsdobj->links, &jsdc->objectsList); + jsdobj->obj = obj; + JS_HashTableAdd(jsdc->objectsTable, obj, jsdobj); + } + return jsdobj; +} + +void +jsd_Constructing(JSDContext* jsdc, JSContext *cx, JSObject *obj, + JSStackFrame *fp) +{ + JSDObject* jsdobj; + JSScript* script; + JSDScript* jsdscript; + const char* ctorURL; + const char* ctorName; + + JSD_LOCK_OBJECTS(jsdc); + jsdobj = jsd_GetJSDObjectForJSObject(jsdc, obj); + if( jsdobj && !jsdobj->ctorURL && JS_IsScriptFrame(cx, fp) ) + { + script = JS_GetFrameScript(cx, fp); + if( script ) + { + ctorURL = JS_GetScriptFilename(cx, script); + if( ctorURL ) + jsdobj->ctorURL = jsd_AddAtom(jsdc, ctorURL); + + JSD_LOCK_SCRIPTS(jsdc); + jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, fp); + JSD_UNLOCK_SCRIPTS(jsdc); + if( jsdscript ) + { + ctorName = jsd_GetScriptFunctionId(jsdc, jsdscript); + if( ctorName ) + jsdobj->ctorName = jsd_AddAtom(jsdc, ctorName); + } + jsdobj->ctorLineno = JS_GetScriptBaseLineNumber(cx, script); + } + } + TRACEOBJ(jsdc, jsdobj, 3); + JSD_UNLOCK_OBJECTS(jsdc); +} + +static JSHashNumber +_hash_root(const void *key) +{ + return ((JSHashNumber)(ptrdiff_t) key) >> 2; /* help lame MSVC1.5 on Win16 */ +} + +JSBool +jsd_InitObjectManager(JSDContext* jsdc) +{ + JS_INIT_CLIST(&jsdc->objectsList); + jsdc->objectsTable = JS_NewHashTable(256, _hash_root, + JS_CompareValues, JS_CompareValues, + NULL, NULL); + return !!jsdc->objectsTable; +} + +void +jsd_DestroyObjectManager(JSDContext* jsdc) +{ + jsd_DestroyObjects(jsdc); + JSD_LOCK_OBJECTS(jsdc); + JS_HashTableDestroy(jsdc->objectsTable); + JSD_UNLOCK_OBJECTS(jsdc); +} + +void +jsd_DestroyObjects(JSDContext* jsdc) +{ + JSD_LOCK_OBJECTS(jsdc); + while( !JS_CLIST_IS_EMPTY(&jsdc->objectsList) ) + _destroyJSDObject(jsdc, (JSDObject*)JS_NEXT_LINK(&jsdc->objectsList)); + JSD_UNLOCK_OBJECTS(jsdc); +} + +JSDObject* +jsd_IterateObjects(JSDContext* jsdc, JSDObject** iterp) +{ + JSDObject *jsdobj = *iterp; + + JS_ASSERT(JSD_OBJECTS_LOCKED(jsdc)); + + if( !jsdobj ) + jsdobj = (JSDObject *)jsdc->objectsList.next; + if( jsdobj == (JSDObject *)&jsdc->objectsList ) + return NULL; + *iterp = (JSDObject*) jsdobj->links.next; + return jsdobj; +} + +JSObject* +jsd_GetWrappedObject(JSDContext* jsdc, JSDObject* jsdobj) +{ + return jsdobj->obj; +} + +const char* +jsd_GetObjectNewURL(JSDContext* jsdc, JSDObject* jsdobj) +{ + if( jsdobj->newURL ) + return JSD_ATOM_TO_STRING(jsdobj->newURL); + return NULL; +} + +uintN +jsd_GetObjectNewLineNumber(JSDContext* jsdc, JSDObject* jsdobj) +{ + return jsdobj->newLineno; +} + +const char* +jsd_GetObjectConstructorURL(JSDContext* jsdc, JSDObject* jsdobj) +{ + if( jsdobj->ctorURL ) + return JSD_ATOM_TO_STRING(jsdobj->ctorURL); + return NULL; +} + +uintN +jsd_GetObjectConstructorLineNumber(JSDContext* jsdc, JSDObject* jsdobj) +{ + return jsdobj->ctorLineno; +} + +const char* +jsd_GetObjectConstructorName(JSDContext* jsdc, JSDObject* jsdobj) +{ + if( jsdobj->ctorName ) + return JSD_ATOM_TO_STRING(jsdobj->ctorName); + return NULL; +} + +JSDObject* +jsd_GetJSDObjectForJSObject(JSDContext* jsdc, JSObject* jsobj) +{ + JSDObject* jsdobj; + + JSD_LOCK_OBJECTS(jsdc); + jsdobj = (JSDObject*) JS_HashTableLookup(jsdc->objectsTable, jsobj); + JSD_UNLOCK_OBJECTS(jsdc); + return jsdobj; +} + +JSDObject* +jsd_GetObjectForValue(JSDContext* jsdc, JSDValue* jsdval) +{ + return jsd_GetJSDObjectForJSObject(jsdc, JSVAL_TO_OBJECT(jsdval->val)); +} + +JSDValue* +jsd_GetValueForObject(JSDContext* jsdc, JSDObject* jsdobj) +{ + return jsd_NewValue(jsdc, OBJECT_TO_JSVAL(jsdobj->obj)); +} + + diff --git a/js/jsd/jsd_scpt.c b/js/jsd/jsd_scpt.c new file mode 100644 index 0000000..237db06 --- /dev/null +++ b/js/jsd/jsd_scpt.c @@ -0,0 +1,963 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript Debugging support - Script support + */ + +#include "jsd.h" +#include "jsfriendapi.h" + +/* Comment this out to disable (NT specific) dumping as we go */ +/* +** #ifdef DEBUG +** #define JSD_DUMP 1 +** #endif +*/ + +#define NOT_SET_YET -1 + +/***************************************************************************/ + +#ifdef DEBUG +void JSD_ASSERT_VALID_SCRIPT(JSDScript* jsdscript) +{ + JS_ASSERT(jsdscript); + JS_ASSERT(jsdscript->script); +} +void JSD_ASSERT_VALID_EXEC_HOOK(JSDExecHook* jsdhook) +{ + JS_ASSERT(jsdhook); + JS_ASSERT(jsdhook->hook); +} +#endif + +#ifdef LIVEWIRE +static JSBool +HasFileExtention(const char* name, const char* ext) +{ + int i; + int len = strlen(ext); + const char* p = strrchr(name,'.'); + if( !p ) + return JS_FALSE; + p++; + for(i = 0; i < len; i++ ) + { + JS_ASSERT(islower(ext[i])); + if( 0 == p[i] || tolower(p[i]) != ext[i] ) + return JS_FALSE; + } + if( 0 != p[i] ) + return JS_FALSE; + return JS_TRUE; +} +#endif /* LIVEWIRE */ + +static JSDScript* +_newJSDScript(JSDContext* jsdc, + JSContext *cx, + JSScript *script, + JSFunction* function) +{ + JSDScript* jsdscript; + uintN lineno; + const char* raw_filename; + + JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc)); + + /* these are inlined javascript: urls and we can't handle them now */ + lineno = (uintN) JS_GetScriptBaseLineNumber(cx, script); + if( lineno == 0 ) + return NULL; + + jsdscript = (JSDScript*) calloc(1, sizeof(JSDScript)); + if( ! jsdscript ) + return NULL; + + raw_filename = JS_GetScriptFilename(cx,script); + + JS_HashTableAdd(jsdc->scriptsTable, (void *)script, (void *)jsdscript); + JS_APPEND_LINK(&jsdscript->links, &jsdc->scripts); + jsdscript->jsdc = jsdc; + jsdscript->script = script; + jsdscript->function = function; + jsdscript->lineBase = lineno; + jsdscript->lineExtent = (uintN)NOT_SET_YET; + jsdscript->data = NULL; +#ifndef LIVEWIRE + jsdscript->url = (char*) jsd_BuildNormalizedURL(raw_filename); +#else + jsdscript->app = LWDBG_GetCurrentApp(); + if( jsdscript->app && raw_filename ) + { + jsdscript->url = jsdlw_BuildAppRelativeFilename(jsdscript->app, raw_filename); + if( function ) + { + JSString* funid = JS_GetFunctionId(function); + char* funbytes; + const char* funnanme; + if( fuinid ) + { + funbytes = JS_EncodeString(cx, funid); + funname = funbytes ? funbytes : ""; + } + else + { + funbytes = NULL; + funname = "anonymous"; + } + jsdscript->lwscript = + LWDBG_GetScriptOfFunction(jsdscript->app,funname); + JS_Free(cx, funbytes); + + /* also, make sure this file is added to filelist if is .js file */ + if( HasFileExtention(raw_filename,"js") || + HasFileExtention(raw_filename,"sjs") ) + { + jsdlw_PreLoadSource(jsdc, jsdscript->app, raw_filename, JS_FALSE); + } + } + else + { + jsdscript->lwscript = LWDBG_GetCurrentTopLevelScript(); + } + } +#endif + + JS_INIT_CLIST(&jsdscript->hooks); + + return jsdscript; +} + +static void +_destroyJSDScript(JSDContext* jsdc, + JSDScript* jsdscript) +{ + JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc)); + + /* destroy all hooks */ + jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript); + + JS_REMOVE_LINK(&jsdscript->links); + if(jsdscript->url) + free(jsdscript->url); + + if (jsdscript->profileData) + free(jsdscript->profileData); + + free(jsdscript); +} + +/***************************************************************************/ + +#ifdef JSD_DUMP +#ifndef XP_WIN +void +OutputDebugString (char *buf) +{ + fprintf (stderr, "%s", buf); +} +#endif + +static void +_dumpJSDScript(JSDContext* jsdc, JSDScript* jsdscript, const char* leadingtext) +{ + const char* name; + JSString* fun; + uintN base; + uintN extent; + char Buf[256]; + size_t n; + + name = jsd_GetScriptFilename(jsdc, jsdscript); + fun = jsd_GetScriptFunctionId(jsdc, jsdscript); + base = jsd_GetScriptBaseLineNumber(jsdc, jsdscript); + extent = jsd_GetScriptLineExtent(jsdc, jsdscript); + n = size_t(snprintf(Buf, sizeof(Buf), "%sscript=%08X, %s, ", + leadingtext, (unsigned) jsdscript->script, + name ? name : "no URL")); + if (n + 1 < sizeof(Buf)) { + if (fun) { + n += size_t(snprintf(Buf + n, sizeof(Buf) - n, "%s", "no fun")); + } else { + n += JS_PutEscapedFlatString(Buf + n, sizeof(Buf) - n, + JS_ASSERT_STRING_IS_FLAT(fun), 0); + Buf[sizeof(Buf) - 1] = '\0'; + } + if (n + 1 < sizeof(Buf)) + snprintf(Buf + n, sizeof(Buf) - n, ", %d-%d\n", base, base + extent - 1); + } + OutputDebugString( Buf ); +} + +static void +_dumpJSDScriptList( JSDContext* jsdc ) +{ + JSDScript* iterp = NULL; + JSDScript* jsdscript = NULL; + + OutputDebugString( "*** JSDScriptDump\n" ); + while( NULL != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) ) + _dumpJSDScript( jsdc, jsdscript, " script: " ); +} +#endif /* JSD_DUMP */ + +/***************************************************************************/ +static JSHashNumber +jsd_hash_script(const void *key) +{ + return ((JSHashNumber)(ptrdiff_t) key) >> 2; /* help lame MSVC1.5 on Win16 */ +} + +static void * +jsd_alloc_script_table(void *priv, size_t size) +{ + return malloc(size); +} + +static void +jsd_free_script_table(void *priv, void *item, size_t size) +{ + free(item); +} + +static JSHashEntry * +jsd_alloc_script_entry(void *priv, const void *item) +{ + return (JSHashEntry*) malloc(sizeof(JSHashEntry)); +} + +static void +jsd_free_script_entry(void *priv, JSHashEntry *he, uintN flag) +{ + if (flag == HT_FREE_ENTRY) + { + _destroyJSDScript((JSDContext*) priv, (JSDScript*) he->value); + free(he); + } +} + +static JSHashAllocOps script_alloc_ops = { + jsd_alloc_script_table, jsd_free_script_table, + jsd_alloc_script_entry, jsd_free_script_entry +}; + +#ifndef JSD_SCRIPT_HASH_SIZE +#define JSD_SCRIPT_HASH_SIZE 1024 +#endif + +JSBool +jsd_InitScriptManager(JSDContext* jsdc) +{ + JS_INIT_CLIST(&jsdc->scripts); + jsdc->scriptsTable = JS_NewHashTable(JSD_SCRIPT_HASH_SIZE, jsd_hash_script, + JS_CompareValues, JS_CompareValues, + &script_alloc_ops, (void*) jsdc); + return !!jsdc->scriptsTable; +} + +void +jsd_DestroyScriptManager(JSDContext* jsdc) +{ + JSD_LOCK_SCRIPTS(jsdc); + if (jsdc->scriptsTable) + JS_HashTableDestroy(jsdc->scriptsTable); + JSD_UNLOCK_SCRIPTS(jsdc); +} + +JSDScript* +jsd_FindJSDScript( JSDContext* jsdc, + JSScript *script ) +{ + JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc)); + return (JSDScript*) JS_HashTableLookup(jsdc->scriptsTable, (void *)script); +} + +JSDScript * +jsd_FindOrCreateJSDScript(JSDContext *jsdc, + JSContext *cx, + JSScript *script, + JSStackFrame *fp) +{ + JSDScript *jsdscript; + JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc)); + + jsdscript = jsd_FindJSDScript(jsdc, script); + if (jsdscript) + return jsdscript; + + /* Fallback for unknown scripts: create a new script. */ + if (!fp) + JS_FrameIterator(cx, &fp); + if (fp) + jsdscript = _newJSDScript(jsdc, cx, script, JS_GetFrameFunction(cx, fp)); + + return jsdscript; +} + +JSDProfileData* +jsd_GetScriptProfileData(JSDContext* jsdc, JSDScript *script) +{ + if (!script->profileData) + script->profileData = (JSDProfileData*)calloc(1, sizeof(JSDProfileData)); + + return script->profileData; +} + +uint32 +jsd_GetScriptFlags(JSDContext *jsdc, JSDScript *script) +{ + return script->flags; +} + +void +jsd_SetScriptFlags(JSDContext *jsdc, JSDScript *script, uint32 flags) +{ + script->flags = flags; +} + +uintN +jsd_GetScriptCallCount(JSDContext* jsdc, JSDScript *script) +{ + if (script->profileData) + return script->profileData->callCount; + + return 0; +} + +uintN +jsd_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script) +{ + if (script->profileData) + return script->profileData->maxRecurseDepth; + + return 0; +} + +jsdouble +jsd_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script) +{ + if (script->profileData) + return script->profileData->minExecutionTime; + + return 0.0; +} + +jsdouble +jsd_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script) +{ + if (script->profileData) + return script->profileData->maxExecutionTime; + + return 0.0; +} + +jsdouble +jsd_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script) +{ + if (script->profileData) + return script->profileData->totalExecutionTime; + + return 0.0; +} + +jsdouble +jsd_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script) +{ + if (script->profileData) + return script->profileData->minOwnExecutionTime; + + return 0.0; +} + +jsdouble +jsd_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script) +{ + if (script->profileData) + return script->profileData->maxOwnExecutionTime; + + return 0.0; +} + +jsdouble +jsd_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script) +{ + if (script->profileData) + return script->profileData->totalOwnExecutionTime; + + return 0.0; +} + +void +jsd_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script) +{ + if (script->profileData) + { + free(script->profileData); + script->profileData = NULL; + } +} + +JSScript * +jsd_GetJSScript (JSDContext *jsdc, JSDScript *script) +{ + return script->script; +} + +JSFunction * +jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script) +{ + return script->function; +} + +JSDScript* +jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp) +{ + JSDScript *jsdscript = *iterp; + + JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc)); + + if( !jsdscript ) + jsdscript = (JSDScript *)jsdc->scripts.next; + if( jsdscript == (JSDScript *)&jsdc->scripts ) + return NULL; + *iterp = (JSDScript*) jsdscript->links.next; + return jsdscript; +} + +void * +jsd_SetScriptPrivate(JSDScript *jsdscript, void *data) +{ + void *rval = jsdscript->data; + jsdscript->data = data; + return rval; +} + +void * +jsd_GetScriptPrivate(JSDScript *jsdscript) +{ + return jsdscript->data; +} + +JSBool +jsd_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript) +{ + JSDScript *current; + + JS_ASSERT(JSD_SCRIPTS_LOCKED(jsdc)); + + for( current = (JSDScript *)jsdc->scripts.next; + current != (JSDScript *)&jsdc->scripts; + current = (JSDScript *)current->links.next ) + { + if(jsdscript == current) + return JS_TRUE; + } + return JS_FALSE; +} + +const char* +jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript) +{ + return jsdscript->url; +} + +JSString* +jsd_GetScriptFunctionId(JSDContext* jsdc, JSDScript *jsdscript) +{ + JSString* str; + + if( ! jsdscript->function ) + return NULL; + str = JS_GetFunctionId(jsdscript->function); + + /* For compatibility we return "anonymous", not an empty string here. */ + return str ? str : JS_GetAnonymousString(jsdc->jsrt); +} + +uintN +jsd_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript) +{ + return jsdscript->lineBase; +} + +uintN +jsd_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript) +{ + if( NOT_SET_YET == (int)jsdscript->lineExtent ) + jsdscript->lineExtent = JS_GetScriptLineExtent(jsdc->dumbContext, jsdscript->script); + return jsdscript->lineExtent; +} + +jsuword +jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line) +{ + jsuword pc; + JSCrossCompartmentCall *call; + +#ifdef LIVEWIRE + if( jsdscript && jsdscript->lwscript ) + { + uintN newline; + jsdlw_RawToProcessedLineNumber(jsdc, jsdscript, line, &newline); + if( line != newline ) + line = newline; + } +#endif + + call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script); + if(!call) + return 0; + pc = (jsuword) JS_LineNumberToPC(jsdc->dumbContext, jsdscript->script, line ); + JS_LeaveCrossCompartmentCall(call); + return pc; +} + +uintN +jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc) +{ + JSCrossCompartmentCall *call; + uintN first = jsdscript->lineBase; + uintN last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1; + uintN line = 0; + + call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script); + if(!call) + return 0; + if (pc) + line = JS_PCToLineNumber(jsdc->dumbContext, jsdscript->script, (jsbytecode*)pc); + JS_LeaveCrossCompartmentCall(call); + + if( line < first ) + return first; + if( line > last ) + return last; + +#ifdef LIVEWIRE + if( jsdscript && jsdscript->lwscript ) + { + uintN newline; + jsdlw_ProcessedToRawLineNumber(jsdc, jsdscript, line, &newline); + line = newline; + } +#endif + + return line; +} + +JSBool +jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata) +{ + JSD_LOCK(); + jsdc->scriptHook = hook; + jsdc->scriptHookData = callerdata; + JSD_UNLOCK(); + return JS_TRUE; +} + +JSBool +jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata) +{ + JSD_LOCK(); + if( hook ) + *hook = jsdc->scriptHook; + if( callerdata ) + *callerdata = jsdc->scriptHookData; + JSD_UNLOCK(); + return JS_TRUE; +} + +JSBool +jsd_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, JSBool enable) +{ + JSCrossCompartmentCall *call; + JSBool rv; + call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script); + if(!call) + return JS_FALSE; + JSD_LOCK(); + rv = JS_SetSingleStepMode(jsdc->dumbContext, jsdscript->script, enable); + JSD_UNLOCK(); + JS_LeaveCrossCompartmentCall(call); + return rv; +} + + +/***************************************************************************/ + +void +jsd_NewScriptHookProc( + JSContext *cx, + const char *filename, /* URL this script loads from */ + uintN lineno, /* line where this script starts */ + JSScript *script, + JSFunction *fun, + void* callerdata ) +{ + JSDScript* jsdscript = NULL; + JSDContext* jsdc = (JSDContext*) callerdata; + JSD_ScriptHookProc hook; + void* hookData; + + JSD_ASSERT_VALID_CONTEXT(jsdc); + + if( JSD_IS_DANGEROUS_THREAD(jsdc) ) + return; + + JSD_LOCK_SCRIPTS(jsdc); + jsdscript = _newJSDScript(jsdc, cx, script, fun); + JSD_UNLOCK_SCRIPTS(jsdc); + if( ! jsdscript ) + return; + +#ifdef JSD_DUMP + JSD_LOCK_SCRIPTS(jsdc); + _dumpJSDScript(jsdc, jsdscript, "***NEW Script: "); + _dumpJSDScriptList( jsdc ); + JSD_UNLOCK_SCRIPTS(jsdc); +#endif /* JSD_DUMP */ + + /* local in case jsdc->scriptHook gets cleared on another thread */ + JSD_LOCK(); + hook = jsdc->scriptHook; + hookData = jsdc->scriptHookData; + JSD_UNLOCK(); + + if( hook ) + hook(jsdc, jsdscript, JS_TRUE, hookData); +} + +void +jsd_DestroyScriptHookProc( + JSContext *cx, + JSScript *script, + void* callerdata ) +{ + JSDScript* jsdscript = NULL; + JSDContext* jsdc = (JSDContext*) callerdata; + JSD_ScriptHookProc hook; + void* hookData; + + JSD_ASSERT_VALID_CONTEXT(jsdc); + + if( JSD_IS_DANGEROUS_THREAD(jsdc) ) + return; + + JSD_LOCK_SCRIPTS(jsdc); + jsdscript = jsd_FindJSDScript(jsdc, script); + JSD_UNLOCK_SCRIPTS(jsdc); + + if( ! jsdscript ) + return; + +#ifdef JSD_DUMP + JSD_LOCK_SCRIPTS(jsdc); + _dumpJSDScript(jsdc, jsdscript, "***DESTROY Script: "); + JSD_UNLOCK_SCRIPTS(jsdc); +#endif /* JSD_DUMP */ + + /* local in case hook gets cleared on another thread */ + JSD_LOCK(); + hook = jsdc->scriptHook; + hookData = jsdc->scriptHookData; + JSD_UNLOCK(); + + if( hook ) + hook(jsdc, jsdscript, JS_FALSE, hookData); + + JSD_LOCK_SCRIPTS(jsdc); + JS_HashTableRemove(jsdc->scriptsTable, (void *)script); + JSD_UNLOCK_SCRIPTS(jsdc); + +#ifdef JSD_DUMP + JSD_LOCK_SCRIPTS(jsdc); + _dumpJSDScriptList(jsdc); + JSD_UNLOCK_SCRIPTS(jsdc); +#endif /* JSD_DUMP */ +} + + +/***************************************************************************/ + +static JSDExecHook* +_findHook(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc) +{ + JSDExecHook* jsdhook; + JSCList* list = &jsdscript->hooks; + + for( jsdhook = (JSDExecHook*)list->next; + jsdhook != (JSDExecHook*)list; + jsdhook = (JSDExecHook*)jsdhook->links.next ) + { + if (jsdhook->pc == pc) + return jsdhook; + } + return NULL; +} + +static JSBool +_isActiveHook(JSDContext* jsdc, JSScript *script, JSDExecHook* jsdhook) +{ + JSDExecHook* current; + JSCList* list; + JSDScript* jsdscript; + + JSD_LOCK_SCRIPTS(jsdc); + jsdscript = jsd_FindJSDScript(jsdc, script); + if( ! jsdscript) + { + JSD_UNLOCK_SCRIPTS(jsdc); + return JS_FALSE; + } + + list = &jsdscript->hooks; + + for( current = (JSDExecHook*)list->next; + current != (JSDExecHook*)list; + current = (JSDExecHook*)current->links.next ) + { + if(current == jsdhook) + { + JSD_UNLOCK_SCRIPTS(jsdc); + return JS_TRUE; + } + } + JSD_UNLOCK_SCRIPTS(jsdc); + return JS_FALSE; +} + + +JSTrapStatus +jsd_TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, + jsval closure) +{ + JSDExecHook* jsdhook = (JSDExecHook*) JSVAL_TO_PRIVATE(closure); + JSD_ExecutionHookProc hook; + void* hookData; + JSDContext* jsdc; + JSDScript* jsdscript; + + JSD_LOCK(); + + if( NULL == (jsdc = jsd_JSDContextForJSContext(cx)) || + ! _isActiveHook(jsdc, script, jsdhook) ) + { + JSD_UNLOCK(); + return JSTRAP_CONTINUE; + } + + JSD_ASSERT_VALID_EXEC_HOOK(jsdhook); + JS_ASSERT(!jsdhook->pc || jsdhook->pc == (jsuword)pc); + JS_ASSERT(jsdhook->jsdscript->script == script); + JS_ASSERT(jsdhook->jsdscript->jsdc == jsdc); + + hook = jsdhook->hook; + hookData = jsdhook->callerdata; + jsdscript = jsdhook->jsdscript; + + /* do not use jsdhook-> after this point */ + JSD_UNLOCK(); + + if( ! jsdc || ! jsdc->inited ) + return JSTRAP_CONTINUE; + + if( JSD_IS_DANGEROUS_THREAD(jsdc) ) + return JSTRAP_CONTINUE; + +#ifdef LIVEWIRE + if( ! jsdlw_UserCodeAtPC(jsdc, jsdscript, (jsuword)pc) ) + return JSTRAP_CONTINUE; +#endif + + return jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_BREAKPOINT, + hook, hookData, rval); +} + + + +JSBool +jsd_SetExecutionHook(JSDContext* jsdc, + JSDScript* jsdscript, + jsuword pc, + JSD_ExecutionHookProc hook, + void* callerdata) +{ + JSDExecHook* jsdhook; + JSBool rv; + JSCrossCompartmentCall *call; + + JSD_LOCK(); + if( ! hook ) + { + jsd_ClearExecutionHook(jsdc, jsdscript, pc); + JSD_UNLOCK(); + return JS_TRUE; + } + + jsdhook = _findHook(jsdc, jsdscript, pc); + if( jsdhook ) + { + jsdhook->hook = hook; + jsdhook->callerdata = callerdata; + JSD_UNLOCK(); + return JS_TRUE; + } + /* else... */ + + jsdhook = (JSDExecHook*)calloc(1, sizeof(JSDExecHook)); + if( ! jsdhook ) { + JSD_UNLOCK(); + return JS_FALSE; + } + jsdhook->jsdscript = jsdscript; + jsdhook->pc = pc; + jsdhook->hook = hook; + jsdhook->callerdata = callerdata; + + call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script); + if(!call) { + free(jsdhook); + JSD_UNLOCK(); + return JS_FALSE; + } + + rv = JS_SetTrap(jsdc->dumbContext, jsdscript->script, + (jsbytecode*)pc, jsd_TrapHandler, + PRIVATE_TO_JSVAL(jsdhook)); + + JS_LeaveCrossCompartmentCall(call); + + if ( ! rv ) { + free(jsdhook); + JSD_UNLOCK(); + return JS_FALSE; + } + + JS_APPEND_LINK(&jsdhook->links, &jsdscript->hooks); + JSD_UNLOCK(); + + return JS_TRUE; +} + +JSBool +jsd_ClearExecutionHook(JSDContext* jsdc, + JSDScript* jsdscript, + jsuword pc) +{ + JSCrossCompartmentCall *call; + JSDExecHook* jsdhook; + + JSD_LOCK(); + + jsdhook = _findHook(jsdc, jsdscript, pc); + if( ! jsdhook ) + { + JSD_UNLOCK(); + return JS_FALSE; + } + + call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script); + if(!call) { + JSD_UNLOCK(); + return JS_FALSE; + } + + JS_ClearTrap(jsdc->dumbContext, jsdscript->script, + (jsbytecode*)pc, NULL, NULL ); + + JS_LeaveCrossCompartmentCall(call); + + JS_REMOVE_LINK(&jsdhook->links); + free(jsdhook); + + JSD_UNLOCK(); + return JS_TRUE; +} + +JSBool +jsd_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript) +{ + JSDExecHook* jsdhook; + JSCList* list = &jsdscript->hooks; + + JSD_LOCK(); + + while( (JSDExecHook*)list != (jsdhook = (JSDExecHook*)list->next) ) + { + JS_REMOVE_LINK(&jsdhook->links); + free(jsdhook); + } + + /* No cross-compartment call here because we may be in the middle of GC */ + JS_ClearScriptTraps(jsdc->dumbContext, jsdscript->script); + JSD_UNLOCK(); + + return JS_TRUE; +} + +JSBool +jsd_ClearAllExecutionHooks(JSDContext* jsdc) +{ + JSDScript* jsdscript; + JSDScript* iterp = NULL; + + JSD_LOCK(); + while( NULL != (jsdscript = jsd_IterateScripts(jsdc, &iterp)) ) + jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript); + JSD_UNLOCK(); + return JS_TRUE; +} + +void +jsd_ScriptCreated(JSDContext* jsdc, + JSContext *cx, + const char *filename, /* URL this script loads from */ + uintN lineno, /* line where this script starts */ + JSScript *script, + JSFunction *fun) +{ + jsd_NewScriptHookProc(cx, filename, lineno, script, fun, jsdc); +} + +void +jsd_ScriptDestroyed(JSDContext* jsdc, + JSContext *cx, + JSScript *script) +{ + jsd_DestroyScriptHookProc(cx, script, jsdc); +} diff --git a/js/jsd/jsd_stak.c b/js/jsd/jsd_stak.c new file mode 100644 index 0000000..6884adc --- /dev/null +++ b/js/jsd/jsd_stak.c @@ -0,0 +1,605 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript Debugging support - Call stack support + */ + +#include "jsd.h" +#include "jsfriendapi.h" + +#ifdef DEBUG +void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState* jsdthreadstate) +{ + JS_ASSERT(jsdthreadstate); + JS_ASSERT(jsdthreadstate->stackDepth > 0); +} + +void JSD_ASSERT_VALID_STACK_FRAME(JSDStackFrameInfo* jsdframe) +{ + JS_ASSERT(jsdframe); + JS_ASSERT(jsdframe->jsdthreadstate); +} +#endif + +static JSDStackFrameInfo* +_addNewFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSScript* script, + jsuword pc, + JSStackFrame* fp) +{ + JSDStackFrameInfo* jsdframe; + JSDScript* jsdscript = NULL; + + if (JS_IsScriptFrame(jsdthreadstate->context, fp)) + { + JSD_LOCK_SCRIPTS(jsdc); + jsdscript = jsd_FindJSDScript(jsdc, script); + JSD_UNLOCK_SCRIPTS(jsdc); + if (!jsdscript || (jsdc->flags & JSD_HIDE_DISABLED_FRAMES && + !JSD_IS_DEBUG_ENABLED(jsdc, jsdscript))) + { + return NULL; + } + + if (!JSD_IS_DEBUG_ENABLED(jsdc, jsdscript)) + jsdthreadstate->flags |= TS_HAS_DISABLED_FRAME; + } + + jsdframe = (JSDStackFrameInfo*) calloc(1, sizeof(JSDStackFrameInfo)); + if( ! jsdframe ) + return NULL; + + jsdframe->jsdthreadstate = jsdthreadstate; + jsdframe->jsdscript = jsdscript; + jsdframe->pc = pc; + jsdframe->fp = fp; + + JS_APPEND_LINK(&jsdframe->links, &jsdthreadstate->stack); + jsdthreadstate->stackDepth++; + + return jsdframe; +} + +static void +_destroyFrame(JSDStackFrameInfo* jsdframe) +{ + /* kill any alloc'd objects in frame here... */ + + if( jsdframe ) + free(jsdframe); +} + +JSDThreadState* +jsd_NewThreadState(JSDContext* jsdc, JSContext *cx ) +{ + JSDThreadState* jsdthreadstate; + JSStackFrame * iter = NULL; + JSStackFrame * fp; + + jsdthreadstate = (JSDThreadState*)calloc(1, sizeof(JSDThreadState)); + if( ! jsdthreadstate ) + return NULL; + + jsdthreadstate->context = cx; + jsdthreadstate->thread = JSD_CURRENT_THREAD(); + JS_INIT_CLIST(&jsdthreadstate->stack); + jsdthreadstate->stackDepth = 0; + + JS_BeginRequest(jsdthreadstate->context); + while( NULL != (fp = JS_FrameIterator(cx, &iter)) ) + { + JSScript* script = JS_GetFrameScript(cx, fp); + jsuword pc = (jsuword) JS_GetFramePC(cx, fp); + jsval dummyThis; + + /* + * don't construct a JSDStackFrame for dummy frames (those without a + * |this| object, or native frames, if JSD_INCLUDE_NATIVE_FRAMES + * isn't set. + */ + if (JS_GetFrameThis(cx, fp, &dummyThis) && + ((jsdc->flags & JSD_INCLUDE_NATIVE_FRAMES) || + JS_IsScriptFrame(cx, fp))) + { + JSDStackFrameInfo *frame; + + frame = _addNewFrame( jsdc, jsdthreadstate, script, pc, fp ); + + if ((jsdthreadstate->stackDepth == 0 && !frame) || + (jsdthreadstate->stackDepth == 1 && frame && + frame->jsdscript && !JSD_IS_DEBUG_ENABLED(jsdc, frame->jsdscript))) + { + /* + * if we failed to create the first frame, or the top frame + * is not enabled for debugging, fail the entire thread state. + */ + JS_INIT_CLIST(&jsdthreadstate->links); + JS_EndRequest(jsdthreadstate->context); + jsd_DestroyThreadState(jsdc, jsdthreadstate); + return NULL; + } + } + } + JS_EndRequest(jsdthreadstate->context); + + if (jsdthreadstate->stackDepth == 0) + { + free(jsdthreadstate); + return NULL; + } + + JSD_LOCK_THREADSTATES(jsdc); + JS_APPEND_LINK(&jsdthreadstate->links, &jsdc->threadsStates); + JSD_UNLOCK_THREADSTATES(jsdc); + + return jsdthreadstate; +} + +void +jsd_DestroyThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate) +{ + JSDStackFrameInfo* jsdframe; + JSCList* list; + + JS_ASSERT(jsdthreadstate); + JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread); + + JSD_LOCK_THREADSTATES(jsdc); + JS_REMOVE_LINK(&jsdthreadstate->links); + JSD_UNLOCK_THREADSTATES(jsdc); + + list = &jsdthreadstate->stack; + while( (JSDStackFrameInfo*)list != (jsdframe = (JSDStackFrameInfo*)list->next) ) + { + JS_REMOVE_LINK(&jsdframe->links); + _destroyFrame(jsdframe); + } + free(jsdthreadstate); +} + +uintN +jsd_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate) +{ + uintN count = 0; + + JSD_LOCK_THREADSTATES(jsdc); + + if( jsd_IsValidThreadState(jsdc, jsdthreadstate) ) + count = jsdthreadstate->stackDepth; + + JSD_UNLOCK_THREADSTATES(jsdc); + + return count; +} + +JSDStackFrameInfo* +jsd_GetStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate) +{ + JSDStackFrameInfo* jsdframe = NULL; + + JSD_LOCK_THREADSTATES(jsdc); + + if( jsd_IsValidThreadState(jsdc, jsdthreadstate) ) + jsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdthreadstate->stack); + JSD_UNLOCK_THREADSTATES(jsdc); + + return jsdframe; +} + +JSContext * +jsd_GetJSContext (JSDContext* jsdc, JSDThreadState* jsdthreadstate) +{ + JSContext* cx = NULL; + + JSD_LOCK_THREADSTATES(jsdc); + if( jsd_IsValidThreadState(jsdc, jsdthreadstate) ) + cx = jsdthreadstate->context; + JSD_UNLOCK_THREADSTATES(jsdc); + + return cx; +} + +JSDStackFrameInfo* +jsd_GetCallingStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSDStackFrameInfo* nextjsdframe = NULL; + + JSD_LOCK_THREADSTATES(jsdc); + + if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) + if( JS_LIST_HEAD(&jsdframe->links) != &jsdframe->jsdthreadstate->stack ) + nextjsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdframe->links); + + JSD_UNLOCK_THREADSTATES(jsdc); + + return nextjsdframe; +} + +JSDScript* +jsd_GetScriptForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSDScript* jsdscript = NULL; + + JSD_LOCK_THREADSTATES(jsdc); + + if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) + jsdscript = jsdframe->jsdscript; + + JSD_UNLOCK_THREADSTATES(jsdc); + + return jsdscript; +} + +jsuword +jsd_GetPCForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + jsuword pc = 0; + + JSD_LOCK_THREADSTATES(jsdc); + + if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) + pc = jsdframe->pc; + + JSD_UNLOCK_THREADSTATES(jsdc); + + return pc; +} + +JSDValue* +jsd_GetCallObjectForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSObject* obj; + JSDValue* jsdval = NULL; + + JSD_LOCK_THREADSTATES(jsdc); + + if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) + { + obj = JS_GetFrameCallObject(jsdthreadstate->context, jsdframe->fp); + if(obj) + jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj)); + } + + JSD_UNLOCK_THREADSTATES(jsdc); + + return jsdval; +} + +JSDValue* +jsd_GetScopeChainForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSObject* obj; + JSDValue* jsdval = NULL; + + JSD_LOCK_THREADSTATES(jsdc); + + if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) + { + JS_BeginRequest(jsdthreadstate->context); + obj = JS_GetFrameScopeChain(jsdthreadstate->context, jsdframe->fp); + JS_EndRequest(jsdthreadstate->context); + if(obj) + jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj)); + } + + JSD_UNLOCK_THREADSTATES(jsdc); + + return jsdval; +} + +JSDValue* +jsd_GetThisForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSObject* obj; + JSDValue* jsdval = NULL; + JSD_LOCK_THREADSTATES(jsdc); + + if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) + { + JSBool ok; + jsval thisval; + JS_BeginRequest(jsdthreadstate->context); + ok = JS_GetFrameThis(jsdthreadstate->context, jsdframe->fp, &thisval); + JS_EndRequest(jsdthreadstate->context); + if(ok) + jsdval = JSD_NewValue(jsdc, thisval); + } + + JSD_UNLOCK_THREADSTATES(jsdc); + return jsdval; +} + +JSString* +jsd_GetIdForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSString *rv = NULL; + + JSD_LOCK_THREADSTATES(jsdc); + + if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) + { + JSFunction *fun = JS_GetFrameFunction (jsdthreadstate->context, + jsdframe->fp); + if( fun ) + { + rv = JS_GetFunctionId (fun); + + /* + * For compatibility we return "anonymous", not an empty string + * here. + */ + if( !rv ) + rv = JS_GetAnonymousString(jsdc->jsrt); + } + } + + JSD_UNLOCK_THREADSTATES(jsdc); + return rv; +} + +JSBool +jsd_IsStackFrameDebugger(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSBool rv = JS_TRUE; + JSD_LOCK_THREADSTATES(jsdc); + + if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) + { + rv = JS_IsDebuggerFrame(jsdthreadstate->context, jsdframe->fp); + } + + JSD_UNLOCK_THREADSTATES(jsdc); + return rv; +} + +JSBool +jsd_IsStackFrameConstructing(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSBool rv = JS_TRUE; + JSD_LOCK_THREADSTATES(jsdc); + + if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) ) + { + rv = JS_IsConstructorFrame(jsdthreadstate->context, jsdframe->fp); + } + + JSD_UNLOCK_THREADSTATES(jsdc); + return rv; +} + +JSBool +jsd_EvaluateUCScriptInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + const jschar *bytes, uintN length, + const char *filename, uintN lineno, + JSBool eatExceptions, jsval *rval) +{ + JSBool retval; + JSBool valid; + JSExceptionState* exceptionState = NULL; + JSContext* cx; + + JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread); + + JSD_LOCK_THREADSTATES(jsdc); + valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe); + JSD_UNLOCK_THREADSTATES(jsdc); + + if( ! valid ) + return JS_FALSE; + + cx = jsdthreadstate->context; + JS_ASSERT(cx); + + if (eatExceptions) + exceptionState = JS_SaveExceptionState(cx); + JS_ClearPendingException(cx); + jsd_StartingEvalUsingFilename(jsdc, filename); + retval = JS_EvaluateUCInStackFrame(cx, jsdframe->fp, bytes, length, + filename, lineno, rval); + jsd_FinishedEvalUsingFilename(jsdc, filename); + if (eatExceptions) + JS_RestoreExceptionState(cx, exceptionState); + + return retval; +} + +JSBool +jsd_EvaluateScriptInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + const char *bytes, uintN length, + const char *filename, uintN lineno, + JSBool eatExceptions, jsval *rval) +{ + JSBool retval; + JSBool valid; + JSExceptionState* exceptionState = NULL; + JSContext *cx; + + JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread); + + JSD_LOCK_THREADSTATES(jsdc); + valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe); + JSD_UNLOCK_THREADSTATES(jsdc); + + if (!valid) + return JS_FALSE; + + cx = jsdthreadstate->context; + JS_ASSERT(cx); + + if (eatExceptions) + exceptionState = JS_SaveExceptionState(cx); + JS_ClearPendingException(cx); + jsd_StartingEvalUsingFilename(jsdc, filename); + retval = JS_EvaluateInStackFrame(cx, jsdframe->fp, bytes, length, + filename, lineno, rval); + jsd_FinishedEvalUsingFilename(jsdc, filename); + if (eatExceptions) + JS_RestoreExceptionState(cx, exceptionState); + + return retval; +} + +JSString* +jsd_ValToStringInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + jsval val) +{ + JSBool valid; + JSString* retval; + JSExceptionState* exceptionState; + JSContext* cx; + + JSD_LOCK_THREADSTATES(jsdc); + valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe); + JSD_UNLOCK_THREADSTATES(jsdc); + + if( ! valid ) + return NULL; + + cx = jsdthreadstate->context; + JS_ASSERT(cx); + + exceptionState = JS_SaveExceptionState(cx); + retval = JS_ValueToString(cx, val); + JS_RestoreExceptionState(cx, exceptionState); + + return retval; +} + +JSBool +jsd_IsValidThreadState(JSDContext* jsdc, + JSDThreadState* jsdthreadstate) +{ + JSDThreadState *cur; + + JS_ASSERT( JSD_THREADSTATES_LOCKED(jsdc) ); + + for( cur = (JSDThreadState*)jsdc->threadsStates.next; + cur != (JSDThreadState*)&jsdc->threadsStates; + cur = (JSDThreadState*)cur->links.next ) + { + if( cur == jsdthreadstate ) + return JS_TRUE; + } + return JS_FALSE; +} + +JSBool +jsd_IsValidFrameInThreadState(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JS_ASSERT(JSD_THREADSTATES_LOCKED(jsdc)); + + if( ! jsd_IsValidThreadState(jsdc, jsdthreadstate) ) + return JS_FALSE; + if( jsdframe->jsdthreadstate != jsdthreadstate ) + return JS_FALSE; + + JSD_ASSERT_VALID_THREAD_STATE(jsdthreadstate); + JSD_ASSERT_VALID_STACK_FRAME(jsdframe); + + return JS_TRUE; +} + +static JSContext* +_getContextForThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate) +{ + JSBool valid; + JSD_LOCK_THREADSTATES(jsdc); + valid = jsd_IsValidThreadState(jsdc, jsdthreadstate); + JSD_UNLOCK_THREADSTATES(jsdc); + if( valid ) + return jsdthreadstate->context; + return NULL; +} + +JSDValue* +jsd_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate) +{ + JSContext* cx; + jsval val; + + if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate))) + return NULL; + + if(JS_GetPendingException(cx, &val)) + return jsd_NewValue(jsdc, val); + return NULL; +} + +JSBool +jsd_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate, + JSDValue* jsdval) +{ + JSContext* cx; + + if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate))) + return JS_FALSE; + + if(jsdval) + JS_SetPendingException(cx, JSD_GetValueWrappedJSVal(jsdc, jsdval)); + else + JS_ClearPendingException(cx); + return JS_TRUE; +} + diff --git a/js/jsd/jsd_step.c b/js/jsd/jsd_step.c new file mode 100644 index 0000000..524a36a --- /dev/null +++ b/js/jsd/jsd_step.c @@ -0,0 +1,321 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript Debugging support - Stepping support + */ + +#include "jsd.h" + +/* +* #define JSD_TRACE 1 +*/ + +#ifdef JSD_TRACE + +static char* +_indentSpaces(int i) +{ +#define MAX_INDENT 63 + static char* p = NULL; + if(!p) + { + p = calloc(1, MAX_INDENT+1); + if(!p) return ""; + memset(p, ' ', MAX_INDENT); + } + if(i > MAX_INDENT) return p; + return p + MAX_INDENT-i; +} + +static void +_interpreterTrace(JSDContext* jsdc, JSContext *cx, JSStackFrame *fp, + JSBool before) +{ + JSDScript* jsdscript = NULL; + JSScript * script; + static indent = 0; + JSString* funName = NULL; + + script = JS_GetFrameScript(cx, fp); + if(script) + { + JSD_LOCK_SCRIPTS(jsdc); + jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, script, fp); + JSD_UNLOCK_SCRIPTS(jsdc); + if(jsdscript) + funName = JSD_GetScriptFunctionId(jsdc, jsdscript); + } + + if(before) + printf("%sentering ", _indentSpaces(indent++)); + else + printf("%sleaving ", _indentSpaces(--indent)); + + if (!funName) + printf("TOP_LEVEL"); + else + JS_FileEscapedString(stdout, funName, 0); + + if(before) + { + jsval thisVal; + + printf("%s this: ", JS_IsConstructorFrame(cx, fp) ? "constructing":""); + + if (JS_GetFrameThis(cx, fp, &thisVal)) + printf("0x%0llx", (JSUword) thisVal); + else + puts(""); + } + printf("\n"); + JS_ASSERT(indent >= 0); +} +#endif + +JSBool +_callHook(JSDContext *jsdc, JSContext *cx, JSStackFrame *fp, JSBool before, + uintN type, JSD_CallHookProc hook, void *hookData) +{ + JSDScript* jsdscript; + JSScript* jsscript; + JSBool hookresult = JS_TRUE; + + if (!jsdc || !jsdc->inited) + return JS_FALSE; + + if (!hook && !(jsdc->flags & JSD_COLLECT_PROFILE_DATA)) + { + /* no hook to call, no profile data needs to be collected, + * so there is nothing to do here. + */ + return hookresult; + } + + if (before && JS_IsConstructorFrame(cx, fp)) { + jsval newObj; + if (!JS_GetFrameThis(cx, fp, &newObj)) + return JS_FALSE; + jsd_Constructing(jsdc, cx, JSVAL_TO_OBJECT(newObj), fp); + } + + jsscript = JS_GetFrameScript(cx, fp); + if (jsscript) + { + JSD_LOCK_SCRIPTS(jsdc); + jsdscript = jsd_FindOrCreateJSDScript(jsdc, cx, jsscript, fp); + JSD_UNLOCK_SCRIPTS(jsdc); + + if (jsdscript) + { + if (JSD_IS_PROFILE_ENABLED(jsdc, jsdscript)) + { + JSDProfileData *pdata; + pdata = jsd_GetScriptProfileData (jsdc, jsdscript); + if (pdata) + { + if (before) + { + if (JSLL_IS_ZERO(pdata->lastCallStart)) + { + int64 now; + JSDProfileData *callerpdata; + + /* Get the time just the once, for consistency. */ + now = JS_Now(); + /* This contains a pointer to the profile data for + * the caller of this function. */ + callerpdata = jsdc->callingFunctionPData; + if (callerpdata) + { + int64 ll_delta; + pdata->caller = callerpdata; + /* We need to 'stop' the timer for the caller. + * Use time since last return if appropriate. */ + if (JSLL_IS_ZERO(jsdc->lastReturnTime)) + { + JSLL_SUB(ll_delta, now, callerpdata->lastCallStart); + } else { + JSLL_SUB(ll_delta, now, jsdc->lastReturnTime); + } + JSLL_ADD(callerpdata->runningTime, callerpdata->runningTime, ll_delta); + } + /* We're the new current function, and no return + * has happened yet. */ + jsdc->callingFunctionPData = pdata; + jsdc->lastReturnTime = 0; + /* This function has no running time (just been + * called!), and we'll need the call start time. */ + pdata->runningTime = 0; + pdata->lastCallStart = now; + } else { + if (++pdata->recurseDepth > pdata->maxRecurseDepth) + pdata->maxRecurseDepth = pdata->recurseDepth; + } + /* make sure we're called for the return too. */ + hookresult = JS_TRUE; + } else if (!pdata->recurseDepth && + !JSLL_IS_ZERO(pdata->lastCallStart)) { + int64 now, ll_delta; + jsdouble delta; + now = JS_Now(); + JSLL_SUB(ll_delta, now, pdata->lastCallStart); + JSLL_L2D(delta, ll_delta); + delta /= 1000.0; + pdata->totalExecutionTime += delta; + /* minExecutionTime starts as 0, so we need to overwrite + * it on the first call always. */ + if ((0 == pdata->callCount) || + delta < pdata->minExecutionTime) + { + pdata->minExecutionTime = delta; + } + if (delta > pdata->maxExecutionTime) + pdata->maxExecutionTime = delta; + + /* If we last returned from a function (as opposed to + * having last entered this function), we need to inc. + * the running total by the time delta since the last + * return, and use the running total instead of the + * delta calculated above. */ + if (!JSLL_IS_ZERO(jsdc->lastReturnTime)) + { + /* Add last chunk to running time, and use total + * running time as 'delta'. */ + JSLL_SUB(ll_delta, now, jsdc->lastReturnTime); + JSLL_ADD(pdata->runningTime, pdata->runningTime, ll_delta); + JSLL_L2D(delta, pdata->runningTime); + delta /= 1000.0; + } + + pdata->totalOwnExecutionTime += delta; + /* See minExecutionTime comment above. */ + if ((0 == pdata->callCount) || + delta < pdata->minOwnExecutionTime) + { + pdata->minOwnExecutionTime = delta; + } + if (delta > pdata->maxOwnExecutionTime) + pdata->maxOwnExecutionTime = delta; + + /* Current function is now our caller. */ + jsdc->callingFunctionPData = pdata->caller; + /* No hanging pointers, please. */ + pdata->caller = NULL; + /* Mark the time we returned, and indicate this + * function is no longer running. */ + jsdc->lastReturnTime = now; + pdata->lastCallStart = 0; + ++pdata->callCount; + } else if (pdata->recurseDepth) { + --pdata->recurseDepth; + ++pdata->callCount; + } + } + if (hook) + jsd_CallCallHook (jsdc, cx, type, hook, hookData); + } else { + if (hook) + hookresult = + jsd_CallCallHook (jsdc, cx, type, hook, hookData); + else + hookresult = JS_TRUE; + } + } + } + +#ifdef JSD_TRACE + _interpreterTrace(jsdc, cx, fp, before); + return JS_TRUE; +#else + return hookresult; +#endif + +} + +void * +jsd_FunctionCallHook(JSContext *cx, JSStackFrame *fp, JSBool before, + JSBool *ok, void *closure) +{ + JSDContext* jsdc; + JSD_CallHookProc hook; + void* hookData; + + jsdc = (JSDContext*) closure; + + /* local in case jsdc->functionHook gets cleared on another thread */ + JSD_LOCK(); + hook = jsdc->functionHook; + hookData = jsdc->functionHookData; + JSD_UNLOCK(); + + if (_callHook (jsdc, cx, fp, before, + (before) ? JSD_HOOK_FUNCTION_CALL : JSD_HOOK_FUNCTION_RETURN, + hook, hookData)) + { + return closure; + } + + return NULL; +} + +void * +jsd_TopLevelCallHook(JSContext *cx, JSStackFrame *fp, JSBool before, + JSBool *ok, void *closure) +{ + JSDContext* jsdc; + JSD_CallHookProc hook; + void* hookData; + + jsdc = (JSDContext*) closure; + + /* local in case jsdc->toplevelHook gets cleared on another thread */ + JSD_LOCK(); + hook = jsdc->toplevelHook; + hookData = jsdc->toplevelHookData; + JSD_UNLOCK(); + + if (_callHook (jsdc, cx, fp, before, + (before) ? JSD_HOOK_TOPLEVEL_START : JSD_HOOK_TOPLEVEL_END, + hook, hookData)) + { + return closure; + } + + return NULL; + +} diff --git a/js/jsd/jsd_text.c b/js/jsd/jsd_text.c new file mode 100644 index 0000000..16def17 --- /dev/null +++ b/js/jsd/jsd_text.c @@ -0,0 +1,567 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript Debugging support - Source Text functions + */ + +#include +#include "jsd.h" + +#ifdef DEBUG +void JSD_ASSERT_VALID_SOURCE_TEXT(JSDSourceText* jsdsrc) +{ + JS_ASSERT(jsdsrc); + JS_ASSERT(jsdsrc->url); +} +#endif + +/***************************************************************************/ +/* XXX add notification */ + +static void +_clearText(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + if( jsdsrc->text ) + free(jsdsrc->text); + jsdsrc->text = NULL; + jsdsrc->textLength = 0; + jsdsrc->textSpace = 0; + jsdsrc->status = JSD_SOURCE_CLEARED; + jsdsrc->dirty = JS_TRUE; + jsdsrc->alterCount = jsdc->sourceAlterCount++ ; + jsdsrc->doingEval = JS_FALSE; +} + +static JSBool +_appendText(JSDContext* jsdc, JSDSourceText* jsdsrc, + const char* text, size_t length) +{ +#define MEMBUF_GROW 1000 + + uintN neededSize = jsdsrc->textLength + length; + + if( neededSize > jsdsrc->textSpace ) + { + char* newBuf; + uintN iNewSize; + + /* if this is the first alloc, the req might be all that's needed*/ + if( ! jsdsrc->textSpace ) + iNewSize = length; + else + iNewSize = (neededSize * 5 / 4) + MEMBUF_GROW; + + newBuf = (char*) realloc(jsdsrc->text, iNewSize); + if( ! newBuf ) + { + /* try again with the minimal size really asked for */ + iNewSize = neededSize; + newBuf = (char*) realloc(jsdsrc->text, iNewSize); + if( ! newBuf ) + { + /* out of memory */ + _clearText( jsdc, jsdsrc ); + jsdsrc->status = JSD_SOURCE_FAILED; + return JS_FALSE; + } + } + + jsdsrc->text = newBuf; + jsdsrc->textSpace = iNewSize; + } + + memcpy(jsdsrc->text + jsdsrc->textLength, text, length); + jsdsrc->textLength += length; + return JS_TRUE; +} + +static JSDSourceText* +_newSource(JSDContext* jsdc, const char* url) +{ + JSDSourceText* jsdsrc = (JSDSourceText*)calloc(1,sizeof(JSDSourceText)); + if( ! jsdsrc ) + return NULL; + + jsdsrc->url = (char*) url; /* already a copy */ + jsdsrc->status = JSD_SOURCE_INITED; + jsdsrc->dirty = JS_TRUE; + jsdsrc->alterCount = jsdc->sourceAlterCount++ ; + + return jsdsrc; +} + +static void +_destroySource(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + JS_ASSERT(NULL == jsdsrc->text); /* must _clearText() first */ + free(jsdsrc->url); + free(jsdsrc); +} + +static void +_removeSource(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + JS_REMOVE_LINK(&jsdsrc->links); + _clearText(jsdc, jsdsrc); + _destroySource(jsdc, jsdsrc); +} + +static JSDSourceText* +_addSource(JSDContext* jsdc, const char* url) +{ + JSDSourceText* jsdsrc = _newSource(jsdc, url); + if( ! jsdsrc ) + return NULL; + JS_INSERT_LINK(&jsdsrc->links, &jsdc->sources); + return jsdsrc; +} + +static void +_moveSourceToFront(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + JS_REMOVE_LINK(&jsdsrc->links); + JS_INSERT_LINK(&jsdsrc->links, &jsdc->sources); +} + +static void +_moveSourceToRemovedList(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + _clearText(jsdc, jsdsrc); + JS_REMOVE_LINK(&jsdsrc->links); + JS_INSERT_LINK(&jsdsrc->links, &jsdc->removedSources); +} + +static void +_removeSourceFromRemovedList( JSDContext* jsdc, JSDSourceText* jsdsrc ) +{ + JS_REMOVE_LINK(&jsdsrc->links); + _destroySource( jsdc, jsdsrc ); +} + +static JSBool +_isSourceInSourceList(JSDContext* jsdc, JSDSourceText* jsdsrcToFind) +{ + JSDSourceText *jsdsrc; + + for( jsdsrc = (JSDSourceText*)jsdc->sources.next; + jsdsrc != (JSDSourceText*)&jsdc->sources; + jsdsrc = (JSDSourceText*)jsdsrc->links.next ) + { + if( jsdsrc == jsdsrcToFind ) + return JS_TRUE; + } + return JS_FALSE; +} + +/* compare strings in a case insensitive manner with a length limit +*/ + +static int +strncasecomp (const char* one, const char * two, int n) +{ + const char *pA; + const char *pB; + + for(pA=one, pB=two;; pA++, pB++) + { + int tmp; + if (pA == one+n) + return 0; + if (!(*pA && *pB)) + return *pA - *pB; + tmp = tolower(*pA) - tolower(*pB); + if (tmp) + return tmp; + } +} + +static char file_url_prefix[] = "file:"; +#define FILE_URL_PREFIX_LEN (sizeof file_url_prefix - 1) + +const char* +jsd_BuildNormalizedURL( const char* url_string ) +{ + char *new_url_string; + + if( ! url_string ) + return NULL; + + if (!strncasecomp(url_string, file_url_prefix, FILE_URL_PREFIX_LEN) && + url_string[FILE_URL_PREFIX_LEN + 0] == '/' && + url_string[FILE_URL_PREFIX_LEN + 1] == '/') { + new_url_string = JS_smprintf("%s%s", + file_url_prefix, + url_string + FILE_URL_PREFIX_LEN + 2); + } else { + new_url_string = strdup(url_string); + } + return new_url_string; +} + +/***************************************************************************/ + +void +jsd_DestroyAllSources( JSDContext* jsdc ) +{ + JSDSourceText *jsdsrc; + JSDSourceText *next; + + for( jsdsrc = (JSDSourceText*)jsdc->sources.next; + jsdsrc != (JSDSourceText*)&jsdc->sources; + jsdsrc = next ) + { + next = (JSDSourceText*)jsdsrc->links.next; + _removeSource( jsdc, jsdsrc ); + } + + for( jsdsrc = (JSDSourceText*)jsdc->removedSources.next; + jsdsrc != (JSDSourceText*)&jsdc->removedSources; + jsdsrc = next ) + { + next = (JSDSourceText*)jsdsrc->links.next; + _removeSourceFromRemovedList( jsdc, jsdsrc ); + } + +} + +JSDSourceText* +jsd_IterateSources(JSDContext* jsdc, JSDSourceText **iterp) +{ + JSDSourceText *jsdsrc = *iterp; + + if( !jsdsrc ) + jsdsrc = (JSDSourceText *)jsdc->sources.next; + if( jsdsrc == (JSDSourceText *)&jsdc->sources ) + return NULL; + *iterp = (JSDSourceText *)jsdsrc->links.next; + return jsdsrc; +} + +JSDSourceText* +jsd_FindSourceForURL(JSDContext* jsdc, const char* url) +{ + JSDSourceText *jsdsrc; + + for( jsdsrc = (JSDSourceText *)jsdc->sources.next; + jsdsrc != (JSDSourceText *)&jsdc->sources; + jsdsrc = (JSDSourceText *)jsdsrc->links.next ) + { + if( 0 == strcmp(jsdsrc->url, url) ) + return jsdsrc; + } + return NULL; +} + +const char* +jsd_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + return jsdsrc->url; +} + +JSBool +jsd_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc, + const char** ppBuf, intN* pLen ) +{ + *ppBuf = jsdsrc->text; + *pLen = jsdsrc->textLength; + return JS_TRUE; +} + +void +jsd_ClearSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + if( JSD_SOURCE_INITED != jsdsrc->status && + JSD_SOURCE_PARTIAL != jsdsrc->status ) + { + _clearText(jsdc, jsdsrc); + } +} + +JSDSourceStatus +jsd_GetSourceStatus(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + return jsdsrc->status; +} + +JSBool +jsd_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + return jsdsrc->dirty; +} + +void +jsd_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, JSBool dirty) +{ + jsdsrc->dirty = dirty; +} + +uintN +jsd_GetSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + return jsdsrc->alterCount; +} + +uintN +jsd_IncrementSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + return jsdsrc->alterCount = jsdc->sourceAlterCount++; +} + +/***************************************************************************/ + +#if defined(DEBUG) && 0 +void DEBUG_ITERATE_SOURCES( JSDContext* jsdc ) +{ + JSDSourceText* iterp = NULL; + JSDSourceText* jsdsrc = NULL; + int dummy; + + while( NULL != (jsdsrc = jsd_IterateSources(jsdc, &iterp)) ) + { + const char* url; + const char* text; + int len; + JSBool dirty; + JSDStreamStatus status; + JSBool gotSrc; + + url = JSD_GetSourceURL(jsdc, jsdsrc); + dirty = JSD_IsSourceDirty(jsdc, jsdsrc); + status = JSD_GetSourceStatus(jsdc, jsdsrc); + gotSrc = JSD_GetSourceText(jsdc, jsdsrc, &text, &len ); + + dummy = 0; /* gives us a line to set breakpoint... */ + } +} +#else +#define DEBUG_ITERATE_SOURCES(x) ((void)x) +#endif + +/***************************************************************************/ + +JSDSourceText* +jsd_NewSourceText(JSDContext* jsdc, const char* url) +{ + JSDSourceText* jsdsrc; + const char* new_url_string; + + JSD_LOCK_SOURCE_TEXT(jsdc); + +#ifdef LIVEWIRE + new_url_string = url; /* we take ownership of alloc'd string */ +#else + new_url_string = jsd_BuildNormalizedURL(url); +#endif + if( ! new_url_string ) + return NULL; + + jsdsrc = jsd_FindSourceForURL(jsdc, new_url_string); + + if( jsdsrc ) + { + if( jsdsrc->doingEval ) + { +#ifdef LIVEWIRE + free((char*)new_url_string); +#endif + JSD_UNLOCK_SOURCE_TEXT(jsdc); + return NULL; + } + else + _moveSourceToRemovedList(jsdc, jsdsrc); + } + + jsdsrc = _addSource( jsdc, new_url_string ); + + JSD_UNLOCK_SOURCE_TEXT(jsdc); + + return jsdsrc; +} + +JSDSourceText* +jsd_AppendSourceText(JSDContext* jsdc, + JSDSourceText* jsdsrc, + const char* text, /* *not* zero terminated */ + size_t length, + JSDSourceStatus status) +{ + JSD_LOCK_SOURCE_TEXT(jsdc); + + if( jsdsrc->doingEval ) + { + JSD_UNLOCK_SOURCE_TEXT(jsdc); + return NULL; + } + + if( ! _isSourceInSourceList( jsdc, jsdsrc ) ) + { + _removeSourceFromRemovedList( jsdc, jsdsrc ); + JSD_UNLOCK_SOURCE_TEXT(jsdc); + return NULL; + } + + if( text && length && ! _appendText( jsdc, jsdsrc, text, length ) ) + { + jsdsrc->dirty = JS_TRUE; + jsdsrc->alterCount = jsdc->sourceAlterCount++ ; + jsdsrc->status = JSD_SOURCE_FAILED; + _moveSourceToRemovedList(jsdc, jsdsrc); + JSD_UNLOCK_SOURCE_TEXT(jsdc); + return NULL; + } + + jsdsrc->dirty = JS_TRUE; + jsdsrc->alterCount = jsdc->sourceAlterCount++ ; + jsdsrc->status = status; + DEBUG_ITERATE_SOURCES(jsdc); + JSD_UNLOCK_SOURCE_TEXT(jsdc); + return jsdsrc; +} + +JSDSourceText* +jsd_AppendUCSourceText(JSDContext* jsdc, + JSDSourceText* jsdsrc, + const jschar* text, /* *not* zero terminated */ + size_t length, + JSDSourceStatus status) +{ +#define UNICODE_TRUNCATE_BUF_SIZE 1024 + static char* buf = NULL; + int remaining = length; + + if(!text || !length) + return jsd_AppendSourceText(jsdc, jsdsrc, NULL, 0, status); + + JSD_LOCK_SOURCE_TEXT(jsdc); + if(!buf) + { + buf = malloc(UNICODE_TRUNCATE_BUF_SIZE); + if(!buf) + { + JSD_UNLOCK_SOURCE_TEXT(jsdc); + return NULL; + } + } + while(remaining && jsdsrc) { + int bytes = JS_MIN(remaining, UNICODE_TRUNCATE_BUF_SIZE); + int i; + for(i = 0; i < bytes; i++) + buf[i] = (const char) *(text++); + jsdsrc = jsd_AppendSourceText(jsdc,jsdsrc, + buf, bytes, + JSD_SOURCE_PARTIAL); + remaining -= bytes; + } + if(jsdsrc && status != JSD_SOURCE_PARTIAL) + jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc, NULL, 0, status); + + JSD_UNLOCK_SOURCE_TEXT(jsdc); + return jsdsrc; +} + +/* convienence function for adding complete source of url in one call */ +JSBool +jsd_AddFullSourceText(JSDContext* jsdc, + const char* text, /* *not* zero terminated */ + size_t length, + const char* url) +{ + JSDSourceText* jsdsrc; + + JSD_LOCK_SOURCE_TEXT(jsdc); + + jsdsrc = jsd_NewSourceText(jsdc, url); + if( jsdsrc ) + jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc, + text, length, JSD_SOURCE_PARTIAL ); + if( jsdsrc ) + jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc, + NULL, 0, JSD_SOURCE_COMPLETED ); + + JSD_UNLOCK_SOURCE_TEXT(jsdc); + + return jsdsrc ? JS_TRUE : JS_FALSE; +} + +/***************************************************************************/ + +void +jsd_StartingEvalUsingFilename(JSDContext* jsdc, const char* url) +{ + JSDSourceText* jsdsrc; + + /* NOTE: We leave it locked! */ + JSD_LOCK_SOURCE_TEXT(jsdc); + + jsdsrc = jsd_FindSourceForURL(jsdc, url); + if(jsdsrc) + { +#if 0 +#ifndef JSD_LOWLEVEL_SOURCE + JS_ASSERT(! jsdsrc->doingEval); +#endif +#endif + jsdsrc->doingEval = JS_TRUE; + } +} + +void +jsd_FinishedEvalUsingFilename(JSDContext* jsdc, const char* url) +{ + JSDSourceText* jsdsrc; + + /* NOTE: We ASSUME it is locked! */ + + jsdsrc = jsd_FindSourceForURL(jsdc, url); + if(jsdsrc) + { +#if 0 +#ifndef JSD_LOWLEVEL_SOURCE + /* + * when using this low level source addition, this jsdsrc might + * not have existed before the eval, but does exist now (without + * this flag set!) + */ + JS_ASSERT(jsdsrc->doingEval); +#endif +#endif + jsdsrc->doingEval = JS_FALSE; + } + + JSD_UNLOCK_SOURCE_TEXT(jsdc); +} diff --git a/js/jsd/jsd_val.c b/js/jsd/jsd_val.c new file mode 100644 index 0000000..51ddafc --- /dev/null +++ b/js/jsd/jsd_val.c @@ -0,0 +1,918 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript Debugging support - Value and Property support + */ + +#include "jsd.h" +#include "jsapi.h" +#include "jsfriendapi.h" + +#ifdef DEBUG +void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval) +{ + JS_ASSERT(jsdval); + JS_ASSERT(jsdval->nref > 0); + if(!JS_CLIST_IS_EMPTY(&jsdval->props)) + { + JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)); + JS_ASSERT(JSVAL_IS_OBJECT(jsdval->val)); + } + + if(jsdval->proto) + { + JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO)); + JS_ASSERT(jsdval->proto->nref > 0); + } + if(jsdval->parent) + { + JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT)); + JS_ASSERT(jsdval->parent->nref > 0); + } + if(jsdval->ctor) + { + JS_ASSERT(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR)); + JS_ASSERT(jsdval->ctor->nref > 0); + } +} + +void JSD_ASSERT_VALID_PROPERTY(JSDProperty* jsdprop) +{ + JS_ASSERT(jsdprop); + JS_ASSERT(jsdprop->name); + JS_ASSERT(jsdprop->name->nref > 0); + JS_ASSERT(jsdprop->val); + JS_ASSERT(jsdprop->val->nref > 0); + if(jsdprop->alias) + JS_ASSERT(jsdprop->alias->nref > 0); +} +#endif + + +JSBool +jsd_IsValueObject(JSDContext* jsdc, JSDValue* jsdval) +{ + return JSVAL_IS_OBJECT(jsdval->val); +} + +JSBool +jsd_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval) +{ + return JSVAL_IS_NUMBER(jsdval->val); +} + +JSBool +jsd_IsValueInt(JSDContext* jsdc, JSDValue* jsdval) +{ + return JSVAL_IS_INT(jsdval->val); +} + +JSBool +jsd_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval) +{ + return JSVAL_IS_DOUBLE(jsdval->val); +} + +JSBool +jsd_IsValueString(JSDContext* jsdc, JSDValue* jsdval) +{ + return JSVAL_IS_STRING(jsdval->val); +} + +JSBool +jsd_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval) +{ + return JSVAL_IS_BOOLEAN(jsdval->val); +} + +JSBool +jsd_IsValueNull(JSDContext* jsdc, JSDValue* jsdval) +{ + return JSVAL_IS_NULL(jsdval->val); +} + +JSBool +jsd_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval) +{ + return JSVAL_IS_VOID(jsdval->val); +} + +JSBool +jsd_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval) +{ + return JSVAL_IS_PRIMITIVE(jsdval->val); +} + +JSBool +jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval) +{ + return !JSVAL_IS_PRIMITIVE(jsdval->val) && + JS_ObjectIsCallable(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val)); +} + +JSBool +jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval) +{ + JSContext* cx = jsdc->dumbContext; + JSFunction* fun; + JSExceptionState* exceptionState; + JSCrossCompartmentCall *call = NULL; + + if(jsd_IsValueFunction(jsdc, jsdval)) + { + JSBool ok = JS_FALSE; + JS_BeginRequest(cx); + call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val)); + if(!call) { + JS_EndRequest(cx); + + return JS_FALSE; + } + + exceptionState = JS_SaveExceptionState(cx); + fun = JSD_GetValueFunction(jsdc, jsdval); + JS_RestoreExceptionState(cx, exceptionState); + if(fun) + ok = JS_GetFunctionScript(cx, fun) ? JS_FALSE : JS_TRUE; + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(cx); + JS_ASSERT(fun); + return ok; + } + return !JSVAL_IS_PRIMITIVE(jsdval->val); +} + +/***************************************************************************/ + +JSBool +jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval) +{ + jsval val = jsdval->val; + if(!JSVAL_IS_BOOLEAN(val)) + return JS_FALSE; + return JSVAL_TO_BOOLEAN(val); +} + +int32 +jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval) +{ + jsval val = jsdval->val; + if(!JSVAL_IS_INT(val)) + return 0; + return JSVAL_TO_INT(val); +} + +jsdouble +jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval) +{ + if(!JSVAL_IS_DOUBLE(jsdval->val)) + return 0; + return JSVAL_TO_DOUBLE(jsdval->val); +} + +JSString* +jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval) +{ + JSContext* cx = jsdc->dumbContext; + JSExceptionState* exceptionState; + JSCrossCompartmentCall *call = NULL; + jsval stringval; + JSString *string; + JSBool needWrap; + JSObject *scopeObj; + + if(jsdval->string) + return jsdval->string; + + /* Reuse the string without copying or re-rooting it */ + if(JSVAL_IS_STRING(jsdval->val)) { + jsdval->string = JSVAL_TO_STRING(jsdval->val); + return jsdval->string; + } + + JS_BeginRequest(cx); + + /* Objects call JS_ValueToString in their own compartment. */ + scopeObj = JSVAL_IS_OBJECT(jsdval->val) ? JSVAL_TO_OBJECT(jsdval->val) : jsdc->glob; + call = JS_EnterCrossCompartmentCall(cx, scopeObj); + if(!call) { + JS_EndRequest(cx); + return NULL; + } + exceptionState = JS_SaveExceptionState(cx); + + string = JS_ValueToString(cx, jsdval->val); + + JS_RestoreExceptionState(cx, exceptionState); + JS_LeaveCrossCompartmentCall(call); + + if(string) { + stringval = STRING_TO_JSVAL(string); + call = JS_EnterCrossCompartmentCall(cx, jsdc->glob); + } + if(!string || !call || !JS_WrapValue(cx, &stringval)) { + if(call) + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(cx); + return NULL; + } + + jsdval->string = JSVAL_TO_STRING(stringval); + if(!JS_AddNamedStringRoot(cx, &jsdval->string, "ValueString")) + jsdval->string = NULL; + + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(cx); + + return jsdval->string; +} + +JSString* +jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval) +{ + JSContext* cx = jsdc->dumbContext; + JSFunction* fun; + JSExceptionState* exceptionState; + JSCrossCompartmentCall *call = NULL; + + if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval)) + { + JS_BeginRequest(cx); + + call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val)); + if(!call) { + JS_EndRequest(cx); + + return NULL; + } + + exceptionState = JS_SaveExceptionState(cx); + fun = JSD_GetValueFunction(jsdc, jsdval); + JS_RestoreExceptionState(cx, exceptionState); + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(cx); + if(!fun) + return NULL; + jsdval->funName = JS_GetFunctionId(fun); + + /* For compatibility we return "anonymous", not an empty string here. */ + if (!jsdval->funName) + jsdval->funName = JS_GetAnonymousString(jsdc->jsrt); + } + return jsdval->funName; +} + +/***************************************************************************/ + +/* + * Create a new JSD value referring to a jsval. Copy string values into the + * JSD compartment. Leave all other GCTHINGs in their native compartments + * and access them through cross-compartment calls. + */ +JSDValue* +jsd_NewValue(JSDContext* jsdc, jsval val) +{ + JSDValue* jsdval; + JSCrossCompartmentCall *call = NULL; + + if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue)))) + return NULL; + + if(JSVAL_IS_GCTHING(val)) + { + JSBool ok; + JS_BeginRequest(jsdc->dumbContext); + + call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob); + if(!call) { + JS_EndRequest(jsdc->dumbContext); + free(jsdval); + return NULL; + } + + ok = JS_AddNamedValueRoot(jsdc->dumbContext, &jsdval->val, "JSDValue"); + if(ok && JSVAL_IS_STRING(val)) { + if(!JS_WrapValue(jsdc->dumbContext, &val)) { + ok = JS_FALSE; + } + } + + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(jsdc->dumbContext); + if(!ok) + { + free(jsdval); + return NULL; + } + } + jsdval->val = val; + jsdval->nref = 1; + JS_INIT_CLIST(&jsdval->props); + + return jsdval; +} + +void +jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval) +{ + JSCrossCompartmentCall *call = NULL; + + JS_ASSERT(jsdval->nref > 0); + if(0 == --jsdval->nref) + { + jsd_RefreshValue(jsdc, jsdval); + if(JSVAL_IS_GCTHING(jsdval->val)) + { + JS_BeginRequest(jsdc->dumbContext); + call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob); + if(!call) { + JS_EndRequest(jsdc->dumbContext); + + return; + } + + JS_RemoveValueRoot(jsdc->dumbContext, &jsdval->val); + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(jsdc->dumbContext); + } + free(jsdval); + } +} + +jsval +jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval) +{ + JSObject* obj; + JSContext* cx; + jsval val = jsdval->val; + if (!JSVAL_IS_PRIMITIVE(val)) { + cx = JSD_GetDefaultJSContext(jsdc); + obj = js_ObjectToOuterObject(cx, JSVAL_TO_OBJECT(val)); + if (!obj) + { + JS_ClearPendingException(cx); + val = JSVAL_NULL; + } + else + val = OBJECT_TO_JSVAL(obj); + } + + return val; +} + +static JSDProperty* _newProperty(JSDContext* jsdc, JSPropertyDesc* pd, + uintN additionalFlags) +{ + JSDProperty* jsdprop; + + if(!(jsdprop = (JSDProperty*) calloc(1, sizeof(JSDProperty)))) + return NULL; + + JS_INIT_CLIST(&jsdprop->links); + jsdprop->nref = 1; + jsdprop->flags = pd->flags | additionalFlags; + jsdprop->slot = pd->slot; + + if(!(jsdprop->name = jsd_NewValue(jsdc, pd->id))) + goto new_prop_fail; + + if(!(jsdprop->val = jsd_NewValue(jsdc, pd->value))) + goto new_prop_fail; + + if((jsdprop->flags & JSDPD_ALIAS) && + !(jsdprop->alias = jsd_NewValue(jsdc, pd->alias))) + goto new_prop_fail; + + return jsdprop; +new_prop_fail: + jsd_DropProperty(jsdc, jsdprop); + return NULL; +} + +static void _freeProps(JSDContext* jsdc, JSDValue* jsdval) +{ + JSDProperty* jsdprop; + + while(jsdprop = (JSDProperty*)jsdval->props.next, + jsdprop != (JSDProperty*)&jsdval->props) + { + JS_REMOVE_AND_INIT_LINK(&jsdprop->links); + jsd_DropProperty(jsdc, jsdprop); + } + JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props)); + CLEAR_BIT_FLAG(jsdval->flags, GOT_PROPS); +} + +static JSBool _buildProps(JSDContext* jsdc, JSDValue* jsdval) +{ + JSContext* cx = jsdc->dumbContext; + JSObject *obj; + JSPropertyDescArray pda; + uintN i; + JSCrossCompartmentCall *call = NULL; + + JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props)); + JS_ASSERT(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS))); + JS_ASSERT(JSVAL_IS_OBJECT(jsdval->val)); + + if(JSVAL_IS_PRIMITIVE(jsdval->val)) + return JS_FALSE; + + obj = JSVAL_TO_OBJECT(jsdval->val); + + JS_BeginRequest(cx); + call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj); + if(!call) + { + JS_EndRequest(jsdc->dumbContext); + return JS_FALSE; + } + + if(!JS_GetPropertyDescArray(cx, obj, &pda)) + { + JS_EndRequest(cx); + JS_LeaveCrossCompartmentCall(call); + return JS_FALSE; + } + + for(i = 0; i < pda.length; i++) + { + JSDProperty* prop = _newProperty(jsdc, &pda.array[i], 0); + if(!prop) + { + _freeProps(jsdc, jsdval); + break; + } + JS_APPEND_LINK(&prop->links, &jsdval->props); + } + JS_PutPropertyDescArray(cx, &pda); + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(cx); + SET_BIT_FLAG(jsdval->flags, GOT_PROPS); + return !JS_CLIST_IS_EMPTY(&jsdval->props); +} + +#undef DROP_CLEAR_VALUE +#define DROP_CLEAR_VALUE(jsdc, x) if(x){jsd_DropValue(jsdc,x); x = NULL;} + +void +jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval) +{ + JSContext* cx = jsdc->dumbContext; + JSCrossCompartmentCall *call = NULL; + + if(jsdval->string) + { + /* if the jsval is a string, then we didn't need to root the string */ + if(!JSVAL_IS_STRING(jsdval->val)) + { + JS_BeginRequest(cx); + call = JS_EnterCrossCompartmentCall(cx, jsdc->glob); + if(!call) { + JS_EndRequest(cx); + + return; + } + + JS_RemoveStringRoot(cx, &jsdval->string); + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(cx); + } + jsdval->string = NULL; + } + + jsdval->funName = NULL; + jsdval->className = NULL; + DROP_CLEAR_VALUE(jsdc, jsdval->proto); + DROP_CLEAR_VALUE(jsdc, jsdval->parent); + DROP_CLEAR_VALUE(jsdc, jsdval->ctor); + _freeProps(jsdc, jsdval); + jsdval->flags = 0; +} + +/***************************************************************************/ + +uintN +jsd_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval) +{ + JSDProperty* jsdprop; + uintN count = 0; + + if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS))) + if(!_buildProps(jsdc, jsdval)) + return 0; + + for(jsdprop = (JSDProperty*)jsdval->props.next; + jsdprop != (JSDProperty*)&jsdval->props; + jsdprop = (JSDProperty*)jsdprop->links.next) + { + count++; + } + return count; +} + +JSDProperty* +jsd_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp) +{ + JSDProperty* jsdprop = *iterp; + if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS))) + { + JS_ASSERT(!jsdprop); + if(!_buildProps(jsdc, jsdval)) + return NULL; + } + + if(!jsdprop) + jsdprop = (JSDProperty*)jsdval->props.next; + if(jsdprop == (JSDProperty*)&jsdval->props) + return NULL; + *iterp = (JSDProperty*)jsdprop->links.next; + + JS_ASSERT(jsdprop); + jsdprop->nref++; + return jsdprop; +} + +JSDProperty* +jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name) +{ + JSContext* cx = jsdc->dumbContext; + JSDProperty* jsdprop; + JSDProperty* iter = NULL; + JSObject* obj; + uintN attrs = 0; + JSBool found; + JSPropertyDesc pd; + const jschar * nameChars; + size_t nameLen; + jsval val, nameval; + jsid nameid; + JSCrossCompartmentCall *call = NULL; + + if(!jsd_IsValueObject(jsdc, jsdval)) + return NULL; + + /* If we already have the prop, then return it */ + while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter))) + { + JSString* propName = jsd_GetValueString(jsdc, jsdprop->name); + if(propName) { + intN result; + if (JS_CompareStrings(cx, propName, name, &result) && !result) + return jsdprop; + } + JSD_DropProperty(jsdc, jsdprop); + } + /* Not found in property list, look it up explicitly */ + + if(!(obj = JSVAL_TO_OBJECT(jsdval->val))) + return NULL; + + if (!(nameChars = JS_GetStringCharsZAndLength(cx, name, &nameLen))) + return NULL; + + JS_BeginRequest(cx); + call = JS_EnterCrossCompartmentCall(cx, obj); + if(!call) { + JS_EndRequest(cx); + + return NULL; + } + + JS_GetUCPropertyAttributes(cx, obj, nameChars, nameLen, &attrs, &found); + if (!found) + { + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(cx); + return NULL; + } + + JS_ClearPendingException(cx); + + if(!JS_GetUCProperty(cx, obj, nameChars, nameLen, &val)) + { + if (JS_IsExceptionPending(cx)) + { + if (!JS_GetPendingException(cx, &pd.value)) + { + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(cx); + return NULL; + } + pd.flags = JSPD_EXCEPTION; + } + else + { + pd.flags = JSPD_ERROR; + pd.value = JSVAL_VOID; + } + } + else + { + pd.value = val; + } + + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(cx); + + nameval = STRING_TO_JSVAL(name); + if (!JS_ValueToId(cx, nameval, &nameid) || + !JS_IdToValue(cx, nameid, &pd.id)) { + return NULL; + } + + pd.slot = pd.spare = 0; + pd.alias = JSVAL_NULL; + pd.flags |= (attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0 + | (attrs & JSPROP_READONLY) ? JSPD_READONLY : 0 + | (attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0; + + return _newProperty(jsdc, &pd, JSDPD_HINTED); +} + +/* + * Retrieve a JSFunction* from a JSDValue*. This differs from + * JS_ValueToFunction by fully unwrapping the object first. + */ +JSFunction* +jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval) +{ + JSObject *obj; + JSFunction *fun; + JSCrossCompartmentCall *call = NULL; + if (!JSVAL_IS_OBJECT(jsdval->val)) + return NULL; + if(!(obj = JSVAL_TO_OBJECT(jsdval->val))) + return NULL; + obj = JS_UnwrapObject(jsdc->dumbContext, obj); + + call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj); + if (!call) + return NULL; + fun = JS_ValueToFunction(jsdc->dumbContext, OBJECT_TO_JSVAL(obj)); + JS_LeaveCrossCompartmentCall(call); + + return fun; +} + +JSDValue* +jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval) +{ + JSCrossCompartmentCall *call = NULL; + + if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO))) + { + JSObject* obj; + JSObject* proto; + JS_ASSERT(!jsdval->proto); + SET_BIT_FLAG(jsdval->flags, GOT_PROTO); + if(!JSVAL_IS_OBJECT(jsdval->val)) + return NULL; + if(!(obj = JSVAL_TO_OBJECT(jsdval->val))) + return NULL; + JS_BeginRequest(jsdc->dumbContext); + call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj); + if(!call) { + JS_EndRequest(jsdc->dumbContext); + + return NULL; + } + proto = JS_GetPrototype(jsdc->dumbContext, obj); + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(jsdc->dumbContext); + if(!proto) + return NULL; + jsdval->proto = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(proto)); + } + if(jsdval->proto) + jsdval->proto->nref++; + return jsdval->proto; +} + +JSDValue* +jsd_GetValueParent(JSDContext* jsdc, JSDValue* jsdval) +{ + JSCrossCompartmentCall *call = NULL; + + if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT))) + { + JSObject* obj; + JSObject* parent; + JS_ASSERT(!jsdval->parent); + SET_BIT_FLAG(jsdval->flags, GOT_PARENT); + if(!JSVAL_IS_OBJECT(jsdval->val)) + return NULL; + if(!(obj = JSVAL_TO_OBJECT(jsdval->val))) + return NULL; + JS_BeginRequest(jsdc->dumbContext); + call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj); + if(!call) { + JS_EndRequest(jsdc->dumbContext); + + return NULL; + } + parent = JS_GetParent(jsdc->dumbContext,obj); + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(jsdc->dumbContext); + if(!parent) + return NULL; + jsdval->parent = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(parent)); + } + if(jsdval->parent) + jsdval->parent->nref++; + return jsdval->parent; +} + +JSDValue* +jsd_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval) +{ + JSCrossCompartmentCall *call = NULL; + + if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR))) + { + JSObject* obj; + JSObject* proto; + JSObject* ctor; + JS_ASSERT(!jsdval->ctor); + SET_BIT_FLAG(jsdval->flags, GOT_CTOR); + if(!JSVAL_IS_OBJECT(jsdval->val)) + return NULL; + if(!(obj = JSVAL_TO_OBJECT(jsdval->val))) + return NULL; + JS_BeginRequest(jsdc->dumbContext); + call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj); + if(!call) { + JS_EndRequest(jsdc->dumbContext); + + return NULL; + } + proto = JS_GetPrototype(jsdc->dumbContext,obj); + if(!proto) + { + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(jsdc->dumbContext); + return NULL; + } + ctor = JS_GetConstructor(jsdc->dumbContext,proto); + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(jsdc->dumbContext); + if(!ctor) + return NULL; + jsdval->ctor = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(ctor)); + } + if(jsdval->ctor) + jsdval->ctor->nref++; + return jsdval->ctor; +} + +const char* +jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval) +{ + jsval val = jsdval->val; + JSCrossCompartmentCall *call = NULL; + + if(!jsdval->className && JSVAL_IS_OBJECT(val)) + { + JSObject* obj; + if(!(obj = JSVAL_TO_OBJECT(val))) + return NULL; + JS_BeginRequest(jsdc->dumbContext); + call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj); + if(!call) { + JS_EndRequest(jsdc->dumbContext); + + return NULL; + } + if(JS_GET_CLASS(jsdc->dumbContext, obj)) + jsdval->className = JS_GET_CLASS(jsdc->dumbContext, obj)->name; + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(jsdc->dumbContext); + } + return jsdval->className; +} + +JSDScript* +jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval) +{ + JSContext* cx = jsdc->dumbContext; + jsval val = jsdval->val; + JSFunction* fun = NULL; + JSExceptionState* exceptionState; + JSScript* script = NULL; + JSDScript* jsdscript; + JSCrossCompartmentCall *call = NULL; + + if (!jsd_IsValueFunction(jsdc, jsdval)) + return NULL; + + JS_BeginRequest(cx); + call = JS_EnterCrossCompartmentCall(cx, JSVAL_TO_OBJECT(val)); + if (!call) { + JS_EndRequest(cx); + + return NULL; + } + + exceptionState = JS_SaveExceptionState(cx); + fun = JSD_GetValueFunction(jsdc, jsdval); + JS_RestoreExceptionState(cx, exceptionState); + if (fun) + script = JS_GetFunctionScript(cx, fun); + JS_LeaveCrossCompartmentCall(call); + JS_EndRequest(cx); + + if (!script) + return NULL; + + JSD_LOCK_SCRIPTS(jsdc); + jsdscript = jsd_FindJSDScript(jsdc, script); + JSD_UNLOCK_SCRIPTS(jsdc); + return jsdscript; +} + + +/***************************************************************************/ +/***************************************************************************/ + +JSDValue* +jsd_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop) +{ + jsdprop->name->nref++; + return jsdprop->name; +} + +JSDValue* +jsd_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop) +{ + jsdprop->val->nref++; + return jsdprop->val; +} + +JSDValue* +jsd_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop) +{ + if(jsdprop->alias) + jsdprop->alias->nref++; + return jsdprop->alias; +} + +uintN +jsd_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop) +{ + return jsdprop->flags; +} + +uintN +jsd_GetPropertyVarArgSlot(JSDContext* jsdc, JSDProperty* jsdprop) +{ + return jsdprop->slot; +} + +void +jsd_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop) +{ + JS_ASSERT(jsdprop->nref > 0); + if(0 == --jsdprop->nref) + { + JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdprop->links)); + DROP_CLEAR_VALUE(jsdc, jsdprop->val); + DROP_CLEAR_VALUE(jsdc, jsdprop->name); + DROP_CLEAR_VALUE(jsdc, jsdprop->alias); + free(jsdprop); + } +} diff --git a/js/jsd/jsd_xpc.cpp b/js/jsd/jsd_xpc.cpp new file mode 100644 index 0000000..bdf4cae --- /dev/null +++ b/js/jsd/jsd_xpc.cpp @@ -0,0 +1,3510 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert Ginda, + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsdbgapi.h" +#include "jslock.h" +#include "jsd_xpc.h" + +#include "nsIXPConnect.h" +#include "mozilla/ModuleUtils.h" +#include "nsIServiceManager.h" +#include "nsIScriptGlobalObject.h" +#include "nsIObserver.h" +#include "nsIObserverService.h" +#include "nsICategoryManager.h" +#include "nsIJSRuntimeService.h" +#include "nsIThreadInternal.h" +#include "nsThreadUtils.h" +#include "nsMemory.h" +#include "jsdebug.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" + +/* XXX DOM dependency */ +#include "nsIScriptContext.h" +#include "nsIJSContextStack.h" + +/* XXX private JS headers. */ +#include "jscompartment.h" + +/* + * defining CAUTIOUS_SCRIPTHOOK makes jsds disable GC while calling out to the + * script hook. This was a hack to avoid some js engine problems that should + * be fixed now (see Mozilla bug 77636). + */ +#undef CAUTIOUS_SCRIPTHOOK + +#ifdef DEBUG_verbose +# define DEBUG_COUNT(name, count) \ + { if ((count % 10) == 0) printf (name ": %i\n", count); } +# define DEBUG_CREATE(name, count) {count++; DEBUG_COUNT ("+++++ "name,count)} +# define DEBUG_DESTROY(name, count) {count--; DEBUG_COUNT ("----- "name,count)} +#else +# define DEBUG_CREATE(name, count) +# define DEBUG_DESTROY(name, count) +#endif + +#define ASSERT_VALID_CONTEXT { if (!mCx) return NS_ERROR_NOT_AVAILABLE; } +#define ASSERT_VALID_EPHEMERAL { if (!mValid) return NS_ERROR_NOT_AVAILABLE; } + +#define JSDSERVICE_CID \ +{ /* f1299dc2-1dd1-11b2-a347-ee6b7660e048 */ \ + 0xf1299dc2, \ + 0x1dd1, \ + 0x11b2, \ + {0xa3, 0x47, 0xee, 0x6b, 0x76, 0x60, 0xe0, 0x48} \ +} + +#define JSDASO_CID \ +{ /* 2fd6b7f6-eb8c-4f32-ad26-113f2c02d0fe */ \ + 0x2fd6b7f6, \ + 0xeb8c, \ + 0x4f32, \ + {0xad, 0x26, 0x11, 0x3f, 0x2c, 0x02, 0xd0, 0xfe} \ +} + +#define JSDS_MAJOR_VERSION 1 +#define JSDS_MINOR_VERSION 2 + +#define NS_CATMAN_CTRID "@mozilla.org/categorymanager;1" +#define NS_JSRT_CTRID "@mozilla.org/js/xpc/RuntimeService;1" + +#define AUTOREG_CATEGORY "xpcom-autoregistration" +#define APPSTART_CATEGORY "app-startup" +#define JSD_AUTOREG_ENTRY "JSDebugger Startup Observer" +#define JSD_STARTUP_ENTRY "JSDebugger Startup Observer" + +static JSBool +jsds_GCCallbackProc (JSContext *cx, JSGCStatus status); + +/******************************************************************************* + * global vars + ******************************************************************************/ + +const char implementationString[] = "Mozilla JavaScript Debugger Service"; + +const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1"; +const char jsdARObserverCtrID[] = "@mozilla.org/js/jsd/app-start-observer;2"; +const char jsdASObserverCtrID[] = "service,@mozilla.org/js/jsd/app-start-observer;2"; + +#ifdef DEBUG_verbose +PRUint32 gScriptCount = 0; +PRUint32 gValueCount = 0; +PRUint32 gPropertyCount = 0; +PRUint32 gContextCount = 0; +PRUint32 gFrameCount = 0; +#endif + +static jsdService *gJsds = 0; +static JSGCCallback gLastGCProc = jsds_GCCallbackProc; +static JSGCStatus gGCStatus = JSGC_END; + +static struct DeadScript { + PRCList links; + JSDContext *jsdc; + jsdIScript *script; +} *gDeadScripts = nsnull; + +enum PatternType { + ptIgnore = 0U, + ptStartsWith = 1U, + ptEndsWith = 2U, + ptContains = 3U, + ptEquals = 4U +}; + +static struct FilterRecord { + PRCList links; + jsdIFilter *filterObject; + void *glob; + nsCString urlPattern; + PatternType patternType; + PRUint32 startLine; + PRUint32 endLine; +} *gFilters = nsnull; + +static struct LiveEphemeral *gLiveValues = nsnull; +static struct LiveEphemeral *gLiveProperties = nsnull; +static struct LiveEphemeral *gLiveContexts = nsnull; +static struct LiveEphemeral *gLiveStackFrames = nsnull; + +/******************************************************************************* + * utility functions for ephemeral lists + *******************************************************************************/ +already_AddRefed +jsds_FindEphemeral (LiveEphemeral **listHead, void *key) +{ + if (!*listHead) + return nsnull; + + LiveEphemeral *lv_record = + reinterpret_cast + (PR_NEXT_LINK(&(*listHead)->links)); + do + { + if (lv_record->key == key) + { + NS_IF_ADDREF(lv_record->value); + return lv_record->value; + } + lv_record = reinterpret_cast + (PR_NEXT_LINK(&lv_record->links)); + } + while (lv_record != *listHead); + + return nsnull; +} + +void +jsds_InvalidateAllEphemerals (LiveEphemeral **listHead) +{ + LiveEphemeral *lv_record = + reinterpret_cast + (PR_NEXT_LINK(&(*listHead)->links)); + do + { + LiveEphemeral *next = + reinterpret_cast + (PR_NEXT_LINK(&lv_record->links)); + lv_record->value->Invalidate(); + lv_record = next; + } + while (*listHead); +} + +void +jsds_InsertEphemeral (LiveEphemeral **listHead, LiveEphemeral *item) +{ + if (*listHead) { + /* if the list exists, add to it */ + PR_APPEND_LINK(&item->links, &(*listHead)->links); + } else { + /* otherwise create the list */ + PR_INIT_CLIST(&item->links); + *listHead = item; + } +} + +void +jsds_RemoveEphemeral (LiveEphemeral **listHead, LiveEphemeral *item) +{ + LiveEphemeral *next = reinterpret_cast + (PR_NEXT_LINK(&item->links)); + + if (next == item) + { + /* if the current item is also the next item, we're the only element, + * null out the list head */ + NS_ASSERTION (*listHead == item, + "How could we not be the head of a one item list?"); + *listHead = nsnull; + } + else if (item == *listHead) + { + /* otherwise, if we're currently the list head, change it */ + *listHead = next; + } + + PR_REMOVE_AND_INIT_LINK(&item->links); +} + +/******************************************************************************* + * utility functions for filters + *******************************************************************************/ +void +jsds_FreeFilter (FilterRecord *rec) +{ + NS_IF_RELEASE (rec->filterObject); + PR_Free (rec); +} + +/* copies appropriate |filter| attributes into |rec|. + * False return indicates failure, the contents of |rec| will not be changed. + */ +PRBool +jsds_SyncFilter (FilterRecord *rec, jsdIFilter *filter) +{ + NS_ASSERTION (rec, "jsds_SyncFilter without rec"); + NS_ASSERTION (filter, "jsds_SyncFilter without filter"); + + JSObject *glob_proper = nsnull; + nsCOMPtr glob; + nsresult rv = filter->GetGlobalObject(getter_AddRefs(glob)); + if (NS_FAILED(rv)) + return PR_FALSE; + if (glob) { + nsCOMPtr nsiglob = do_QueryInterface(glob); + if (nsiglob) + glob_proper = nsiglob->GetGlobalJSObject(); + } + + PRUint32 startLine; + rv = filter->GetStartLine(&startLine); + if (NS_FAILED(rv)) + return PR_FALSE; + + PRUint32 endLine; + rv = filter->GetStartLine(&endLine); + if (NS_FAILED(rv)) + return PR_FALSE; + + nsCAutoString urlPattern; + rv = filter->GetUrlPattern (urlPattern); + if (NS_FAILED(rv)) + return PR_FALSE; + + PRUint32 len = urlPattern.Length(); + if (len) { + if (urlPattern[0] == '*') { + /* pattern starts with a *, shift all chars once to the left, + * including the trailing null. */ + urlPattern = Substring(urlPattern, 1, len); + + if (urlPattern[len - 2] == '*') { + /* pattern is in the format "*foo*", overwrite the final * with + * a null. */ + urlPattern.Truncate(len - 2); + rec->patternType = ptContains; + } else { + /* pattern is in the format "*foo", just make a note of the + * new length. */ + rec->patternType = ptEndsWith; + } + } else if (urlPattern[len - 1] == '*') { + /* pattern is in the format "foo*", overwrite the final * with a + * null. */ + urlPattern.Truncate(len - 1); + rec->patternType = ptStartsWith; + } else { + /* pattern is in the format "foo". */ + rec->patternType = ptEquals; + } + } else { + rec->patternType = ptIgnore; + } + + /* we got everything we need without failing, now copy it into rec. */ + + if (rec->filterObject != filter) { + NS_IF_RELEASE(rec->filterObject); + NS_ADDREF(filter); + rec->filterObject = filter; + } + + rec->glob = glob_proper; + + rec->startLine = startLine; + rec->endLine = endLine; + + rec->urlPattern = urlPattern; + + return PR_TRUE; + +} + +FilterRecord * +jsds_FindFilter (jsdIFilter *filter) +{ + if (!gFilters) + return nsnull; + + FilterRecord *current = gFilters; + + do { + if (current->filterObject == filter) + return current; + current = reinterpret_cast + (PR_NEXT_LINK(¤t->links)); + } while (current != gFilters); + + return nsnull; +} + +/* returns true if the hook should be executed. */ +PRBool +jsds_FilterHook (JSDContext *jsdc, JSDThreadState *state) +{ + JSContext *cx = JSD_GetJSContext (jsdc, state); + void *glob = static_cast(JS_GetGlobalObject (cx)); + + if (!glob) { + NS_WARNING("No global in threadstate"); + return PR_FALSE; + } + + JSDStackFrameInfo *frame = JSD_GetStackFrame (jsdc, state); + + if (!frame) { + NS_WARNING("No frame in threadstate"); + return PR_FALSE; + } + + JSDScript *script = JSD_GetScriptForStackFrame (jsdc, state, frame); + if (!script) + return PR_TRUE; + + jsuword pc = JSD_GetPCForStackFrame (jsdc, state, frame); + + nsDependentCString url(JSD_GetScriptFilename (jsdc, script)); + if (url.IsEmpty()) { + NS_WARNING ("Script with no filename"); + return PR_FALSE; + } + + if (!gFilters) + return PR_TRUE; + + PRUint32 currentLine = JSD_GetClosestLine (jsdc, script, pc); + PRUint32 len = 0; + FilterRecord *currentFilter = gFilters; + do { + PRUint32 flags = 0; + nsresult rv = currentFilter->filterObject->GetFlags(&flags); + NS_ASSERTION(NS_SUCCEEDED(rv), "Error getting flags for filter"); + if (flags & jsdIFilter::FLAG_ENABLED) { + /* if there is no glob, or the globs match */ + if ((!currentFilter->glob || currentFilter->glob == glob) && + /* and there is no start line, or the start line is before + * or equal to the current */ + (!currentFilter->startLine || + currentFilter->startLine <= currentLine) && + /* and there is no end line, or the end line is after + * or equal to the current */ + (!currentFilter->endLine || + currentFilter->endLine >= currentLine)) { + /* then we're going to have to compare the url. */ + if (currentFilter->patternType == ptIgnore) + return !!(flags & jsdIFilter::FLAG_PASS); + + if (!len) + len = url.Length(); + nsCString urlPattern = currentFilter->urlPattern; + PRUint32 patternLength = urlPattern.Length(); + if (len >= patternLength) { + switch (currentFilter->patternType) { + case ptEquals: + if (urlPattern.Equals(url)) + return !!(flags & jsdIFilter::FLAG_PASS); + break; + case ptStartsWith: + if (urlPattern.Equals(Substring(url, 0, patternLength))) + return !!(flags & jsdIFilter::FLAG_PASS); + break; + case ptEndsWith: + if (urlPattern.Equals(Substring(url, len - patternLength))) + return !!(flags & jsdIFilter::FLAG_PASS); + break; + case ptContains: + { + nsACString::const_iterator start, end; + url.BeginReading(start); + url.EndReading(end); + if (FindInReadable(currentFilter->urlPattern, start, end)) + return !!(flags & jsdIFilter::FLAG_PASS); + } + break; + default: + NS_ERROR("Invalid pattern type"); + } + } + } + } + currentFilter = reinterpret_cast + (PR_NEXT_LINK(¤tFilter->links)); + } while (currentFilter != gFilters); + + return PR_TRUE; + +} + +/******************************************************************************* + * c callbacks + *******************************************************************************/ + +static void +jsds_NotifyPendingDeadScripts (JSContext *cx) +{ +#ifdef CAUTIOUS_SCRIPTHOOK + JSRuntime *rt = JS_GetRuntime(cx); +#endif + jsdService *jsds = gJsds; + + nsCOMPtr hook; + if (jsds) { + NS_ADDREF(jsds); + jsds->GetScriptHook (getter_AddRefs(hook)); + jsds->Pause(nsnull); + } + + DeadScript *deadScripts = gDeadScripts; + gDeadScripts = nsnull; + while (deadScripts) { + DeadScript *ds = deadScripts; + /* get next deleted script */ + deadScripts = reinterpret_cast + (PR_NEXT_LINK(&ds->links)); + if (deadScripts == ds) + deadScripts = nsnull; + + if (hook) + { + /* tell the user this script has been destroyed */ +#ifdef CAUTIOUS_SCRIPTHOOK + JS_UNKEEP_ATOMS(rt); +#endif + hook->OnScriptDestroyed (ds->script); +#ifdef CAUTIOUS_SCRIPTHOOK + JS_KEEP_ATOMS(rt); +#endif + } + + /* take it out of the circular list */ + PR_REMOVE_LINK(&ds->links); + + /* addref came from the FromPtr call in jsds_ScriptHookProc */ + NS_RELEASE(ds->script); + /* free the struct! */ + PR_Free(ds); + } + + if (jsds) { + jsds->UnPause(nsnull); + NS_RELEASE(jsds); + } +} + +static JSBool +jsds_GCCallbackProc (JSContext *cx, JSGCStatus status) +{ +#ifdef DEBUG_verbose + printf ("new gc status is %i\n", status); +#endif + if (status == JSGC_END) { + /* just to guard against reentering. */ + gGCStatus = JSGC_BEGIN; + while (gDeadScripts) + jsds_NotifyPendingDeadScripts (cx); + } + + gGCStatus = status; + if (gLastGCProc && !gLastGCProc (cx, status)) { + /* + * If gLastGCProc returns false, then the GC will abort without making + * another callback with status=JSGC_END, so set the status to JSGC_END + * here. + */ + gGCStatus = JSGC_END; + return JS_FALSE; + } + + return JS_TRUE; +} + +static uintN +jsds_ErrorHookProc (JSDContext *jsdc, JSContext *cx, const char *message, + JSErrorReport *report, void *callerdata) +{ + static PRBool running = PR_FALSE; + + nsCOMPtr hook; + gJsds->GetErrorHook(getter_AddRefs(hook)); + if (!hook) + return JSD_ERROR_REPORTER_PASS_ALONG; + + if (running) + return JSD_ERROR_REPORTER_PASS_ALONG; + + running = PR_TRUE; + + nsCOMPtr val; + if (JS_IsExceptionPending(cx)) { + jsval jv; + JS_GetPendingException(cx, &jv); + JSDValue *jsdv = JSD_NewValue (jsdc, jv); + val = getter_AddRefs(jsdValue::FromPtr(jsdc, jsdv)); + } + + nsCAutoString fileName; + PRUint32 line; + PRUint32 pos; + PRUint32 flags; + PRUint32 errnum; + PRBool rval; + if (report) { + fileName.Assign(report->filename); + line = report->lineno; + pos = report->tokenptr - report->linebuf; + flags = report->flags; + errnum = report->errorNumber; + } + else + { + line = 0; + pos = 0; + flags = 0; + errnum = 0; + } + + gJsds->Pause(nsnull); + hook->OnError (nsDependentCString(message), fileName, line, pos, flags, errnum, val, &rval); + gJsds->UnPause(nsnull); + + running = PR_FALSE; + if (!rval) + return JSD_ERROR_REPORTER_DEBUG; + + return JSD_ERROR_REPORTER_PASS_ALONG; +} + +static JSBool +jsds_CallHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate, + uintN type, void* callerdata) +{ + nsCOMPtr hook; + + switch (type) + { + case JSD_HOOK_TOPLEVEL_START: + case JSD_HOOK_TOPLEVEL_END: + gJsds->GetTopLevelHook(getter_AddRefs(hook)); + break; + + case JSD_HOOK_FUNCTION_CALL: + case JSD_HOOK_FUNCTION_RETURN: + gJsds->GetFunctionHook(getter_AddRefs(hook)); + break; + + default: + NS_ASSERTION (0, "Unknown hook type."); + } + + if (!hook) + return JS_TRUE; + + if (!jsds_FilterHook (jsdc, jsdthreadstate)) + return JS_FALSE; + + JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate); + nsCOMPtr frame = + getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate, + native_frame)); + gJsds->Pause(nsnull); + hook->OnCall(frame, type); + gJsds->UnPause(nsnull); + jsdStackFrame::InvalidateAll(); + + return JS_TRUE; +} + +static PRUint32 +jsds_ExecutionHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate, + uintN type, void* callerdata, jsval* rval) +{ + nsCOMPtr hook(0); + PRUint32 hook_rv = JSD_HOOK_RETURN_CONTINUE; + nsCOMPtr js_rv; + + switch (type) + { + case JSD_HOOK_INTERRUPTED: + gJsds->GetInterruptHook(getter_AddRefs(hook)); + break; + case JSD_HOOK_DEBUG_REQUESTED: + gJsds->GetDebugHook(getter_AddRefs(hook)); + break; + case JSD_HOOK_DEBUGGER_KEYWORD: + gJsds->GetDebuggerHook(getter_AddRefs(hook)); + break; + case JSD_HOOK_BREAKPOINT: + { + /* we can't pause breakpoints the way we pause the other + * execution hooks (at least, not easily.) Instead we bail + * here if the service is paused. */ + PRUint32 level; + gJsds->GetPauseDepth(&level); + if (!level) + gJsds->GetBreakpointHook(getter_AddRefs(hook)); + } + break; + case JSD_HOOK_THROW: + { + hook_rv = JSD_HOOK_RETURN_CONTINUE_THROW; + gJsds->GetThrowHook(getter_AddRefs(hook)); + if (hook) { + JSDValue *jsdv = JSD_GetException (jsdc, jsdthreadstate); + js_rv = getter_AddRefs(jsdValue::FromPtr (jsdc, jsdv)); + } + break; + } + default: + NS_ASSERTION (0, "Unknown hook type."); + } + + if (!hook) + return hook_rv; + + if (!jsds_FilterHook (jsdc, jsdthreadstate)) + return JSD_HOOK_RETURN_CONTINUE; + + JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate); + nsCOMPtr frame = + getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate, + native_frame)); + gJsds->Pause(nsnull); + jsdIValue *inout_rv = js_rv; + NS_IF_ADDREF(inout_rv); + hook->OnExecute (frame, type, &inout_rv, &hook_rv); + js_rv = inout_rv; + NS_IF_RELEASE(inout_rv); + gJsds->UnPause(nsnull); + jsdStackFrame::InvalidateAll(); + + if (hook_rv == JSD_HOOK_RETURN_RET_WITH_VAL || + hook_rv == JSD_HOOK_RETURN_THROW_WITH_VAL) { + *rval = JSVAL_VOID; + if (js_rv) { + JSDValue *jsdv; + if (NS_SUCCEEDED(js_rv->GetJSDValue (&jsdv))) + *rval = JSD_GetValueWrappedJSVal(jsdc, jsdv); + } + } + + return hook_rv; +} + +static void +jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, JSBool creating, + void* callerdata) +{ +#ifdef CAUTIOUS_SCRIPTHOOK + JSContext *cx = JSD_GetDefaultJSContext(jsdc); + JSRuntime *rt = JS_GetRuntime(cx); +#endif + + if (creating) { + nsCOMPtr hook; + gJsds->GetScriptHook(getter_AddRefs(hook)); + + /* a script is being created */ + if (!hook) { + /* nobody cares, just exit */ + return; + } + + nsCOMPtr script = + getter_AddRefs(jsdScript::FromPtr(jsdc, jsdscript)); +#ifdef CAUTIOUS_SCRIPTHOOK + JS_UNKEEP_ATOMS(rt); +#endif + gJsds->Pause(nsnull); + hook->OnScriptCreated (script); + gJsds->UnPause(nsnull); +#ifdef CAUTIOUS_SCRIPTHOOK + JS_KEEP_ATOMS(rt); +#endif + } else { + /* a script is being destroyed. even if there is no registered hook + * we'll still need to invalidate the jsdIScript record, in order + * to remove the reference held in the JSDScript private data. */ + nsCOMPtr jsdis = + static_cast(JSD_GetScriptPrivate(jsdscript)); + if (!jsdis) + return; + + jsdis->Invalidate(); + + if (gGCStatus == JSGC_END) { + nsCOMPtr hook; + gJsds->GetScriptHook(getter_AddRefs(hook)); + if (!hook) + return; + + /* if GC *isn't* running, we can tell the user about the script + * delete now. */ +#ifdef CAUTIOUS_SCRIPTHOOK + JS_UNKEEP_ATOMS(rt); +#endif + + gJsds->Pause(nsnull); + hook->OnScriptDestroyed (jsdis); + gJsds->UnPause(nsnull); +#ifdef CAUTIOUS_SCRIPTHOOK + JS_KEEP_ATOMS(rt); +#endif + } else { + /* if a GC *is* running, we've got to wait until it's done before + * we can execute any JS, so we queue the notification in a PRCList + * until GC tells us it's done. See jsds_GCCallbackProc(). */ + DeadScript *ds = PR_NEW(DeadScript); + if (!ds) + return; /* NS_ERROR_OUT_OF_MEMORY */ + + ds->jsdc = jsdc; + ds->script = jsdis; + NS_ADDREF(ds->script); + if (gDeadScripts) + /* if the queue exists, add to it */ + PR_APPEND_LINK(&ds->links, &gDeadScripts->links); + else { + /* otherwise create the queue */ + PR_INIT_CLIST(&ds->links); + gDeadScripts = ds; + } + } + } +} + +/******************************************************************************* + * reflected jsd data structures + *******************************************************************************/ + +/* Contexts */ +/* +NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral); + +NS_IMETHODIMP +jsdContext::GetJSDContext(JSDContext **_rval) +{ + *_rval = mCx; + return NS_OK; +} +*/ + +/* Objects */ +NS_IMPL_THREADSAFE_ISUPPORTS1(jsdObject, jsdIObject) + +NS_IMETHODIMP +jsdObject::GetJSDContext(JSDContext **_rval) +{ + *_rval = mCx; + return NS_OK; +} + +NS_IMETHODIMP +jsdObject::GetJSDObject(JSDObject **_rval) +{ + *_rval = mObject; + return NS_OK; +} + +NS_IMETHODIMP +jsdObject::GetCreatorURL(nsACString &_rval) +{ + _rval.Assign(JSD_GetObjectNewURL(mCx, mObject)); + return NS_OK; +} + +NS_IMETHODIMP +jsdObject::GetCreatorLine(PRUint32 *_rval) +{ + *_rval = JSD_GetObjectNewLineNumber(mCx, mObject); + return NS_OK; +} + +NS_IMETHODIMP +jsdObject::GetConstructorURL(nsACString &_rval) +{ + _rval.Assign(JSD_GetObjectConstructorURL(mCx, mObject)); + return NS_OK; +} + +NS_IMETHODIMP +jsdObject::GetConstructorLine(PRUint32 *_rval) +{ + *_rval = JSD_GetObjectConstructorLineNumber(mCx, mObject); + return NS_OK; +} + +NS_IMETHODIMP +jsdObject::GetValue(jsdIValue **_rval) +{ + JSDValue *jsdv = JSD_GetValueForObject (mCx, mObject); + + *_rval = jsdValue::FromPtr (mCx, jsdv); + return NS_OK; +} + +/* Properties */ +NS_IMPL_THREADSAFE_ISUPPORTS2(jsdProperty, jsdIProperty, jsdIEphemeral) + +jsdProperty::jsdProperty (JSDContext *aCx, JSDProperty *aProperty) : + mCx(aCx), mProperty(aProperty) +{ + DEBUG_CREATE ("jsdProperty", gPropertyCount); + mValid = (aCx && aProperty); + mLiveListEntry.value = this; + jsds_InsertEphemeral (&gLiveProperties, &mLiveListEntry); +} + +jsdProperty::~jsdProperty () +{ + DEBUG_DESTROY ("jsdProperty", gPropertyCount); + if (mValid) + Invalidate(); +} + +NS_IMETHODIMP +jsdProperty::Invalidate() +{ + ASSERT_VALID_EPHEMERAL; + mValid = PR_FALSE; + jsds_RemoveEphemeral (&gLiveProperties, &mLiveListEntry); + JSD_DropProperty (mCx, mProperty); + return NS_OK; +} + +void +jsdProperty::InvalidateAll() +{ + if (gLiveProperties) + jsds_InvalidateAllEphemerals (&gLiveProperties); +} + +NS_IMETHODIMP +jsdProperty::GetJSDContext(JSDContext **_rval) +{ + *_rval = mCx; + return NS_OK; +} + +NS_IMETHODIMP +jsdProperty::GetJSDProperty(JSDProperty **_rval) +{ + *_rval = mProperty; + return NS_OK; +} + +NS_IMETHODIMP +jsdProperty::GetIsValid(PRBool *_rval) +{ + *_rval = mValid; + return NS_OK; +} + +NS_IMETHODIMP +jsdProperty::GetAlias(jsdIValue **_rval) +{ + JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty); + + *_rval = jsdValue::FromPtr (mCx, jsdv); + return NS_OK; +} + +NS_IMETHODIMP +jsdProperty::GetFlags(PRUint32 *_rval) +{ + *_rval = JSD_GetPropertyFlags (mCx, mProperty); + return NS_OK; +} + +NS_IMETHODIMP +jsdProperty::GetName(jsdIValue **_rval) +{ + JSDValue *jsdv = JSD_GetPropertyName (mCx, mProperty); + + *_rval = jsdValue::FromPtr (mCx, jsdv); + return NS_OK; +} + +NS_IMETHODIMP +jsdProperty::GetValue(jsdIValue **_rval) +{ + JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty); + + *_rval = jsdValue::FromPtr (mCx, jsdv); + return NS_OK; +} + +NS_IMETHODIMP +jsdProperty::GetVarArgSlot(PRUint32 *_rval) +{ + *_rval = JSD_GetPropertyVarArgSlot (mCx, mProperty); + return NS_OK; +} + +/* Scripts */ +NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript, jsdIScript, jsdIEphemeral) + +static NS_IMETHODIMP +AssignToJSString(nsACString *x, JSString *str) +{ + if (!str) { + x->SetLength(0); + return NS_OK; + } + size_t length = JS_GetStringEncodingLength(NULL, str); + if (length == size_t(-1)) + return NS_ERROR_FAILURE; + x->SetLength(PRUint32(length)); + if (x->Length() != PRUint32(length)) + return NS_ERROR_OUT_OF_MEMORY; + JS_EncodeStringToBuffer(str, x->BeginWriting(), length); + return NS_OK; +} + +jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(PR_FALSE), + mTag(0), + mCx(aCx), + mScript(aScript), + mFileName(0), + mFunctionName(0), + mBaseLineNumber(0), + mLineExtent(0), + mPPLineMap(0), + mFirstPC(0) +{ + DEBUG_CREATE ("jsdScript", gScriptCount); + + if (mScript) { + /* copy the script's information now, so we have it later, when it + * gets destroyed. */ + JSD_LockScriptSubsystem(mCx); + mFileName = new nsCString(JSD_GetScriptFilename(mCx, mScript)); + mFunctionName = new nsCString(); + if (mFunctionName) { + JSString *str = JSD_GetScriptFunctionId(mCx, mScript); + if (str) + AssignToJSString(mFunctionName, str); + } + mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript); + mLineExtent = JSD_GetScriptLineExtent(mCx, mScript); + mFirstPC = JSD_GetClosestPC(mCx, mScript, 0); + JSD_UnlockScriptSubsystem(mCx); + + mValid = PR_TRUE; + } +} + +jsdScript::~jsdScript () +{ + DEBUG_DESTROY ("jsdScript", gScriptCount); + if (mFileName) + delete mFileName; + if (mFunctionName) + delete mFunctionName; + + if (mPPLineMap) + PR_Free(mPPLineMap); + + /* Invalidate() needs to be called to release an owning reference to + * ourselves, so if we got here without being invalidated, something + * has gone wrong with our ref count. */ + NS_ASSERTION (!mValid, "Script destroyed without being invalidated."); +} + +/* + * This method populates a line <-> pc map for a pretty printed version of this + * script. It does this by decompiling, and then recompiling the script. The + * resulting script is scanned for the line map, and then left as GC fodder. + */ +PCMapEntry * +jsdScript::CreatePPLineMap() +{ + JSContext *cx = JSD_GetDefaultJSContext (mCx); + JSAutoRequest ar(cx); + JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL); + JSFunction *fun = JSD_GetJSFunction (mCx, mScript); + JSScript *script; /* In JSD compartment */ + PRUint32 baseLine; + JSObject *scriptObj = NULL; + JSString *jsstr; + size_t length; + const jschar *chars; + + if (fun) { + uintN nargs; + + { + JSAutoEnterCompartment ac; + if (!ac.enter(cx, JS_GetFunctionObject(fun))) + return nsnull; + + nargs = JS_GetFunctionArgumentCount(cx, fun); + if (nargs > 12) + return nsnull; + jsstr = JS_DecompileFunctionBody (cx, fun, 4); + if (!jsstr) + return nsnull; + + if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length))) + return nsnull; + } + + JS::Anchor kungFuDeathGrip(jsstr); + const char *argnames[] = {"arg1", "arg2", "arg3", "arg4", + "arg5", "arg6", "arg7", "arg8", + "arg9", "arg10", "arg11", "arg12" }; + fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, chars, + length, "x-jsd:ppbuffer?type=function", 3); + if (!fun || !(script = JS_GetFunctionScript(cx, fun))) + return nsnull; + baseLine = 3; + } else { + script = JSD_GetJSScript(mCx, mScript); + JSString *jsstr; + + { + JS::AutoEnterScriptCompartment ac; + if (!ac.enter(cx, script)) + return nsnull; + + jsstr = JS_DecompileScript (cx, script, "ppscript", 4); + if (!jsstr) + return nsnull; + + if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length))) + return nsnull; + } + + JS::Anchor kungFuDeathGrip(jsstr); + scriptObj = JS_CompileUCScript (cx, obj, chars, length, "x-jsd:ppbuffer?type=script", 1); + if (!scriptObj) + return nsnull; + script = JS_GetScriptFromObject(scriptObj); + baseLine = 1; + } + + /* Make sure that a non-function script is rooted via scriptObj until the + * end of script usage. */ + JS::Anchor scriptAnchor(scriptObj); + + PRUint32 scriptExtent = JS_GetScriptLineExtent (cx, script); + jsbytecode* firstPC = JS_LineNumberToPC (cx, script, 0); + /* allocate worst case size of map (number of lines in script + 1 + * for our 0 record), we'll shrink it with a realloc later. */ + PCMapEntry *lineMap = + static_cast + (PR_Malloc((scriptExtent + 1) * sizeof (PCMapEntry))); + PRUint32 lineMapSize = 0; + + if (lineMap) { + for (PRUint32 line = baseLine; line < scriptExtent + baseLine; ++line) { + jsbytecode* pc = JS_LineNumberToPC (cx, script, line); + if (line == JS_PCToLineNumber (cx, script, pc)) { + lineMap[lineMapSize].line = line; + lineMap[lineMapSize].pc = pc - firstPC; + ++lineMapSize; + } + } + if (scriptExtent != lineMapSize) { + lineMap = + static_cast + (PR_Realloc(mPPLineMap = lineMap, + lineMapSize * sizeof(PCMapEntry))); + if (!lineMap) { + PR_Free(mPPLineMap); + lineMapSize = 0; + } + } + } + + mPCMapSize = lineMapSize; + return mPPLineMap = lineMap; +} + +PRUint32 +jsdScript::PPPcToLine (PRUint32 aPC) +{ + if (!mPPLineMap && !CreatePPLineMap()) + return 0; + PRUint32 i; + for (i = 1; i < mPCMapSize; ++i) { + if (mPPLineMap[i].pc > aPC) + return mPPLineMap[i - 1].line; + } + + return mPPLineMap[mPCMapSize - 1].line; +} + +PRUint32 +jsdScript::PPLineToPc (PRUint32 aLine) +{ + if (!mPPLineMap && !CreatePPLineMap()) + return 0; + PRUint32 i; + for (i = 1; i < mPCMapSize; ++i) { + if (mPPLineMap[i].line > aLine) + return mPPLineMap[i - 1].pc; + } + + return mPPLineMap[mPCMapSize - 1].pc; +} + +NS_IMETHODIMP +jsdScript::GetJSDContext(JSDContext **_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = mCx; + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetJSDScript(JSDScript **_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = mScript; + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetVersion (PRInt32 *_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSContext *cx = JSD_GetDefaultJSContext (mCx); + JSScript *script = JSD_GetJSScript(mCx, mScript); + JS::AutoEnterScriptCompartment ac; + if (!ac.enter(cx, script)) + return NS_ERROR_FAILURE; + *_rval = static_cast(JS_GetScriptVersion(cx, script)); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetTag(PRUint32 *_rval) +{ + if (!mTag) + mTag = ++jsdScript::LastTag; + + *_rval = mTag; + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::Invalidate() +{ + ASSERT_VALID_EPHEMERAL; + mValid = PR_FALSE; + + /* release the addref we do in FromPtr */ + jsdIScript *script = static_cast + (JSD_GetScriptPrivate(mScript)); + NS_ASSERTION (script == this, "That's not my script!"); + NS_RELEASE(script); + JSD_SetScriptPrivate(mScript, NULL); + return NS_OK; +} + +void +jsdScript::InvalidateAll () +{ + JSDContext *cx; + if (NS_FAILED(gJsds->GetJSDContext (&cx))) + return; + + JSDScript *script; + JSDScript *iter = NULL; + + JSD_LockScriptSubsystem(cx); + while((script = JSD_IterateScripts(cx, &iter)) != NULL) { + nsCOMPtr jsdis = + static_cast(JSD_GetScriptPrivate(script)); + if (jsdis) + jsdis->Invalidate(); + } + JSD_UnlockScriptSubsystem(cx); +} + +NS_IMETHODIMP +jsdScript::GetIsValid(PRBool *_rval) +{ + *_rval = mValid; + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::SetFlags(PRUint32 flags) +{ + ASSERT_VALID_EPHEMERAL; + JSD_SetScriptFlags(mCx, mScript, flags); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetFlags(PRUint32 *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_GetScriptFlags(mCx, mScript); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetFileName(nsACString &_rval) +{ + _rval.Assign(*mFileName); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetFunctionName(nsACString &_rval) +{ + _rval.Assign(*mFunctionName); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetParameterNames(PRUint32* count, PRUnichar*** paramNames) +{ + ASSERT_VALID_EPHEMERAL; + JSContext *cx = JSD_GetDefaultJSContext (mCx); + if (!cx) { + NS_WARNING("No default context !?"); + return NS_ERROR_FAILURE; + } + JSFunction *fun = JSD_GetJSFunction (mCx, mScript); + if (!fun) { + *count = 0; + *paramNames = nsnull; + return NS_OK; + } + + JSAutoRequest ar(cx); + JSAutoEnterCompartment ac; + if (!ac.enter(cx, JS_GetFunctionObject(fun))) + return NS_ERROR_FAILURE; + + uintN nargs; + if (!JS_FunctionHasLocalNames(cx, fun) || + (nargs = JS_GetFunctionArgumentCount(cx, fun)) == 0) { + *count = 0; + *paramNames = nsnull; + return NS_OK; + } + + PRUnichar **ret = + static_cast(NS_Alloc(nargs * sizeof(PRUnichar*))); + if (!ret) + return NS_ERROR_OUT_OF_MEMORY; + + void *mark; + jsuword *names = JS_GetFunctionLocalNameArray(cx, fun, &mark); + if (!names) { + NS_Free(ret); + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = NS_OK; + for (uintN i = 0; i < nargs; ++i) { + JSAtom *atom = JS_LocalNameToAtom(names[i]); + if (!atom) { + ret[i] = 0; + } else { + JSString *str = JS_AtomKey(atom); + ret[i] = NS_strndup(JS_GetInternedStringChars(str), JS_GetStringLength(str)); + if (!ret[i]) { + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret); + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + } + JS_ReleaseFunctionLocalNameArray(cx, mark); + if (NS_FAILED(rv)) + return rv; + *count = nargs; + *paramNames = ret; + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetFunctionObject(jsdIValue **_rval) +{ + JSFunction *fun = JSD_GetJSFunction(mCx, mScript); + if (!fun) + return NS_ERROR_NOT_AVAILABLE; + + JSObject *obj = JS_GetFunctionObject(fun); + if (!obj) + return NS_ERROR_FAILURE; + + JSDContext *cx; + if (NS_FAILED(gJsds->GetJSDContext (&cx))) + return NS_ERROR_NOT_INITIALIZED; + + JSDValue *jsdv = JSD_NewValue(cx, OBJECT_TO_JSVAL(obj)); + if (!jsdv) + return NS_ERROR_OUT_OF_MEMORY; + + *_rval = jsdValue::FromPtr(cx, jsdv); + if (!*_rval) { + JSD_DropValue(cx, jsdv); + return NS_ERROR_OUT_OF_MEMORY; + } + + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetFunctionSource(nsAString & aFunctionSource) +{ + ASSERT_VALID_EPHEMERAL; + JSContext *cx = JSD_GetDefaultJSContext (mCx); + if (!cx) { + NS_WARNING("No default context !?"); + return NS_ERROR_FAILURE; + } + JSFunction *fun = JSD_GetJSFunction (mCx, mScript); + + JSAutoRequest ar(cx); + + JSString *jsstr; + JSAutoEnterCompartment ac; + JS::AutoEnterScriptCompartment asc; + if (fun) { + if (!ac.enter(cx, JS_GetFunctionObject(fun))) + return NS_ERROR_FAILURE; + jsstr = JS_DecompileFunction (cx, fun, 4); + } else { + JSScript *script = JSD_GetJSScript (mCx, mScript); + if (!asc.enter(cx, script)) + return NS_ERROR_FAILURE; + jsstr = JS_DecompileScript (cx, script, "ppscript", 4); + } + if (!jsstr) + return NS_ERROR_FAILURE; + + size_t length; + const jschar *chars = JS_GetStringCharsZAndLength(cx, jsstr, &length); + if (!chars) + return NS_ERROR_FAILURE; + + aFunctionSource = nsDependentString(chars, length); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetBaseLineNumber(PRUint32 *_rval) +{ + *_rval = mBaseLineNumber; + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetLineExtent(PRUint32 *_rval) +{ + *_rval = mLineExtent; + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetCallCount(PRUint32 *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_GetScriptCallCount (mCx, mScript); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetMaxRecurseDepth(PRUint32 *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_GetScriptMaxRecurseDepth (mCx, mScript); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetMinExecutionTime(double *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_GetScriptMinExecutionTime (mCx, mScript); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetMaxExecutionTime(double *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_GetScriptMaxExecutionTime (mCx, mScript); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetTotalExecutionTime(double *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_GetScriptTotalExecutionTime (mCx, mScript); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetMinOwnExecutionTime(double *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_GetScriptMinOwnExecutionTime (mCx, mScript); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetMaxOwnExecutionTime(double *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_GetScriptMaxOwnExecutionTime (mCx, mScript); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::GetTotalOwnExecutionTime(double *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_GetScriptTotalOwnExecutionTime (mCx, mScript); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::ClearProfileData() +{ + ASSERT_VALID_EPHEMERAL; + JSD_ClearScriptProfileData(mCx, mScript); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::PcToLine(PRUint32 aPC, PRUint32 aPcmap, PRUint32 *_rval) +{ + ASSERT_VALID_EPHEMERAL; + if (aPcmap == PCMAP_SOURCETEXT) { + *_rval = JSD_GetClosestLine (mCx, mScript, mFirstPC + aPC); + } else if (aPcmap == PCMAP_PRETTYPRINT) { + *_rval = PPPcToLine(aPC); + } else { + return NS_ERROR_INVALID_ARG; + } + + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::LineToPc(PRUint32 aLine, PRUint32 aPcmap, PRUint32 *_rval) +{ + ASSERT_VALID_EPHEMERAL; + if (aPcmap == PCMAP_SOURCETEXT) { + jsuword pc = JSD_GetClosestPC (mCx, mScript, aLine); + *_rval = pc - mFirstPC; + } else if (aPcmap == PCMAP_PRETTYPRINT) { + *_rval = PPLineToPc(aLine); + } else { + return NS_ERROR_INVALID_ARG; + } + + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::EnableSingleStepInterrupts(PRBool enable) +{ + ASSERT_VALID_EPHEMERAL; + + /* Must have set interrupt hook before enabling */ + if (enable && !jsdService::GetService()->CheckInterruptHook()) + return NS_ERROR_NOT_INITIALIZED; + + return (JSD_EnableSingleStepInterrupts(mCx, mScript, enable) ? NS_OK : NS_ERROR_FAILURE); +} + +NS_IMETHODIMP +jsdScript::IsLineExecutable(PRUint32 aLine, PRUint32 aPcmap, PRBool *_rval) +{ + ASSERT_VALID_EPHEMERAL; + if (aPcmap == PCMAP_SOURCETEXT) { + jsuword pc = JSD_GetClosestPC (mCx, mScript, aLine); + *_rval = (aLine == JSD_GetClosestLine (mCx, mScript, pc)); + } else if (aPcmap == PCMAP_PRETTYPRINT) { + if (!mPPLineMap && !CreatePPLineMap()) + return NS_ERROR_OUT_OF_MEMORY; + *_rval = PR_FALSE; + for (PRUint32 i = 0; i < mPCMapSize; ++i) { + if (mPPLineMap[i].line >= aLine) { + *_rval = (mPPLineMap[i].line == aLine); + break; + } + } + } else { + return NS_ERROR_INVALID_ARG; + } + + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::SetBreakpoint(PRUint32 aPC) +{ + ASSERT_VALID_EPHEMERAL; + jsuword pc = mFirstPC + aPC; + JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc, NULL); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::ClearBreakpoint(PRUint32 aPC) +{ + ASSERT_VALID_EPHEMERAL; + jsuword pc = mFirstPC + aPC; + JSD_ClearExecutionHook (mCx, mScript, pc); + return NS_OK; +} + +NS_IMETHODIMP +jsdScript::ClearAllBreakpoints() +{ + ASSERT_VALID_EPHEMERAL; + JSD_LockScriptSubsystem(mCx); + JSD_ClearAllExecutionHooksForScript (mCx, mScript); + JSD_UnlockScriptSubsystem(mCx); + return NS_OK; +} + +/* Contexts */ +NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral) + +jsdIContext * +jsdContext::FromPtr (JSDContext *aJSDCx, JSContext *aJSCx) +{ + if (!aJSDCx || !aJSCx) + return nsnull; + + nsCOMPtr jsdicx; + nsCOMPtr eph = + jsds_FindEphemeral (&gLiveContexts, static_cast(aJSCx)); + if (eph) + { + jsdicx = do_QueryInterface(eph); + } + else + { + nsCOMPtr iscx; + if (JS_GetOptions(aJSCx) & JSOPTION_PRIVATE_IS_NSISUPPORTS) + iscx = static_cast(JS_GetContextPrivate(aJSCx)); + jsdicx = new jsdContext (aJSDCx, aJSCx, iscx); + } + + jsdIContext *ctx = nsnull; + jsdicx.swap(ctx); + return ctx; +} + +jsdContext::jsdContext (JSDContext *aJSDCx, JSContext *aJSCx, + nsISupports *aISCx) : mValid(PR_TRUE), mTag(0), + mJSDCx(aJSDCx), + mJSCx(aJSCx), mISCx(aISCx) +{ + DEBUG_CREATE ("jsdContext", gContextCount); + mLiveListEntry.value = this; + mLiveListEntry.key = static_cast(aJSCx); + jsds_InsertEphemeral (&gLiveContexts, &mLiveListEntry); +} + +jsdContext::~jsdContext() +{ + DEBUG_DESTROY ("jsdContext", gContextCount); + if (mValid) + { + /* call Invalidate() to take ourselves out of the live list */ + Invalidate(); + } +} + +NS_IMETHODIMP +jsdContext::GetIsValid(PRBool *_rval) +{ + *_rval = mValid; + return NS_OK; +} + +NS_IMETHODIMP +jsdContext::Invalidate() +{ + ASSERT_VALID_EPHEMERAL; + mValid = PR_FALSE; + jsds_RemoveEphemeral (&gLiveContexts, &mLiveListEntry); + return NS_OK; +} + +void +jsdContext::InvalidateAll() +{ + if (gLiveContexts) + jsds_InvalidateAllEphemerals (&gLiveContexts); +} + +NS_IMETHODIMP +jsdContext::GetJSContext(JSContext **_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = mJSCx; + return NS_OK; +} + +NS_IMETHODIMP +jsdContext::GetOptions(PRUint32 *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JS_GetOptions(mJSCx); + return NS_OK; +} + +NS_IMETHODIMP +jsdContext::SetOptions(PRUint32 options) +{ + ASSERT_VALID_EPHEMERAL; + PRUint32 lastOptions = JS_GetOptions(mJSCx); + + /* don't let users change this option, they'd just be shooting themselves + * in the foot. */ + if ((options ^ lastOptions) & JSOPTION_PRIVATE_IS_NSISUPPORTS) + return NS_ERROR_ILLEGAL_VALUE; + + JS_SetOptions(mJSCx, options); + return NS_OK; +} + +NS_IMETHODIMP +jsdContext::GetPrivateData(nsISupports **_rval) +{ + ASSERT_VALID_EPHEMERAL; + PRUint32 options = JS_GetOptions(mJSCx); + if (options & JSOPTION_PRIVATE_IS_NSISUPPORTS) + { + *_rval = static_cast(JS_GetContextPrivate(mJSCx)); + NS_IF_ADDREF(*_rval); + } + else + { + *_rval = nsnull; + } + + return NS_OK; +} + +NS_IMETHODIMP +jsdContext::GetWrappedContext(nsISupports **_rval) +{ + ASSERT_VALID_EPHEMERAL; + NS_IF_ADDREF(*_rval = mISCx); + return NS_OK; +} + +NS_IMETHODIMP +jsdContext::GetTag(PRUint32 *_rval) +{ + ASSERT_VALID_EPHEMERAL; + if (!mTag) + mTag = ++jsdContext::LastTag; + + *_rval = mTag; + return NS_OK; +} + +NS_IMETHODIMP +jsdContext::GetVersion (PRInt32 *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = static_cast(JS_GetVersion(mJSCx)); + return NS_OK; +} + +NS_IMETHODIMP +jsdContext::SetVersion (PRInt32 id) +{ + ASSERT_VALID_EPHEMERAL; + JSVersion ver = static_cast(id); + JS_SetVersion(mJSCx, ver); + return NS_OK; +} + +NS_IMETHODIMP +jsdContext::GetGlobalObject (jsdIValue **_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSObject *glob = JS_GetGlobalObject(mJSCx); + JSDValue *jsdv = JSD_NewValue (mJSDCx, OBJECT_TO_JSVAL(glob)); + if (!jsdv) + return NS_ERROR_FAILURE; + *_rval = jsdValue::FromPtr (mJSDCx, jsdv); + if (!*_rval) + return NS_ERROR_FAILURE; + return NS_OK; +} + +NS_IMETHODIMP +jsdContext::GetScriptsEnabled (PRBool *_rval) +{ + ASSERT_VALID_EPHEMERAL; + if (!mISCx) { + *_rval = PR_TRUE; + return NS_OK; + } + + nsCOMPtr context = do_QueryInterface(mISCx); + if (!context) + return NS_ERROR_NO_INTERFACE; + + *_rval = context->GetScriptsEnabled(); + + return NS_OK; +} + +NS_IMETHODIMP +jsdContext::SetScriptsEnabled (PRBool _rval) +{ + ASSERT_VALID_EPHEMERAL; + if (!mISCx) { + if (_rval) + return NS_OK; + return NS_ERROR_NO_INTERFACE; + } + + nsCOMPtr context = do_QueryInterface(mISCx); + if (!context) + return NS_ERROR_NO_INTERFACE; + + context->SetScriptsEnabled(_rval, PR_TRUE); + + return NS_OK; +} + +/* Stack Frames */ +NS_IMPL_THREADSAFE_ISUPPORTS2(jsdStackFrame, jsdIStackFrame, jsdIEphemeral) + +jsdStackFrame::jsdStackFrame (JSDContext *aCx, JSDThreadState *aThreadState, + JSDStackFrameInfo *aStackFrameInfo) : + mCx(aCx), mThreadState(aThreadState), mStackFrameInfo(aStackFrameInfo) +{ + DEBUG_CREATE ("jsdStackFrame", gFrameCount); + mValid = (aCx && aThreadState && aStackFrameInfo); + if (mValid) { + mLiveListEntry.key = aStackFrameInfo; + mLiveListEntry.value = this; + jsds_InsertEphemeral (&gLiveStackFrames, &mLiveListEntry); + } +} + +jsdStackFrame::~jsdStackFrame() +{ + DEBUG_DESTROY ("jsdStackFrame", gFrameCount); + if (mValid) + { + /* call Invalidate() to take ourselves out of the live list */ + Invalidate(); + } +} + +jsdIStackFrame * +jsdStackFrame::FromPtr (JSDContext *aCx, JSDThreadState *aThreadState, + JSDStackFrameInfo *aStackFrameInfo) +{ + if (!aStackFrameInfo) + return nsnull; + + jsdIStackFrame *rv; + nsCOMPtr frame; + + nsCOMPtr eph = + jsds_FindEphemeral (&gLiveStackFrames, + reinterpret_cast(aStackFrameInfo)); + + if (eph) + { + frame = do_QueryInterface(eph); + rv = frame; + } + else + { + rv = new jsdStackFrame (aCx, aThreadState, aStackFrameInfo); + } + + NS_IF_ADDREF(rv); + return rv; +} + +NS_IMETHODIMP +jsdStackFrame::Invalidate() +{ + ASSERT_VALID_EPHEMERAL; + mValid = PR_FALSE; + jsds_RemoveEphemeral (&gLiveStackFrames, &mLiveListEntry); + return NS_OK; +} + +void +jsdStackFrame::InvalidateAll() +{ + if (gLiveStackFrames) + jsds_InvalidateAllEphemerals (&gLiveStackFrames); +} + +NS_IMETHODIMP +jsdStackFrame::GetJSDContext(JSDContext **_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = mCx; + return NS_OK; +} + +NS_IMETHODIMP +jsdStackFrame::GetJSDThreadState(JSDThreadState **_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = mThreadState; + return NS_OK; +} + +NS_IMETHODIMP +jsdStackFrame::GetJSDStackFrameInfo(JSDStackFrameInfo **_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = mStackFrameInfo; + return NS_OK; +} + +NS_IMETHODIMP +jsdStackFrame::GetIsValid(PRBool *_rval) +{ + *_rval = mValid; + return NS_OK; +} + +NS_IMETHODIMP +jsdStackFrame::GetCallingFrame(jsdIStackFrame **_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSDStackFrameInfo *sfi = JSD_GetCallingStackFrame (mCx, mThreadState, + mStackFrameInfo); + *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi); + return NS_OK; +} + +NS_IMETHODIMP +jsdStackFrame::GetExecutionContext(jsdIContext **_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSContext *cx = JSD_GetJSContext (mCx, mThreadState); + *_rval = jsdContext::FromPtr (mCx, cx); + return NS_OK; +} + +NS_IMETHODIMP +jsdStackFrame::GetFunctionName(nsACString &_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSString *str = JSD_GetIdForStackFrame(mCx, mThreadState, mStackFrameInfo); + if (str) + return AssignToJSString(&_rval, str); + + _rval.Assign("anonymous"); + return NS_OK; +} + +NS_IMETHODIMP +jsdStackFrame::GetIsDebugger(PRBool *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_IsStackFrameDebugger (mCx, mThreadState, mStackFrameInfo); + return NS_OK; +} + +NS_IMETHODIMP +jsdStackFrame::GetIsConstructing(PRBool *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_IsStackFrameConstructing (mCx, mThreadState, mStackFrameInfo); + return NS_OK; +} + +NS_IMETHODIMP +jsdStackFrame::GetScript(jsdIScript **_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState, + mStackFrameInfo); + *_rval = jsdScript::FromPtr (mCx, script); + return NS_OK; +} + +NS_IMETHODIMP +jsdStackFrame::GetPc(PRUint32 *_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState, + mStackFrameInfo); + if (!script) + return NS_ERROR_FAILURE; + jsuword pcbase = JSD_GetClosestPC(mCx, script, 0); + + jsuword pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo); + if (pc) + *_rval = pc - pcbase; + else + *_rval = pcbase; + return NS_OK; +} + +NS_IMETHODIMP +jsdStackFrame::GetLine(PRUint32 *_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState, + mStackFrameInfo); + if (script) { + jsuword pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo); + *_rval = JSD_GetClosestLine (mCx, script, pc); + } else { + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +jsdStackFrame::GetCallee(jsdIValue **_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSDValue *jsdv = JSD_GetCallObjectForStackFrame (mCx, mThreadState, + mStackFrameInfo); + + *_rval = jsdValue::FromPtr (mCx, jsdv); + return NS_OK; +} + +NS_IMETHODIMP +jsdStackFrame::GetScope(jsdIValue **_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSDValue *jsdv = JSD_GetScopeChainForStackFrame (mCx, mThreadState, + mStackFrameInfo); + + *_rval = jsdValue::FromPtr (mCx, jsdv); + return NS_OK; +} + +NS_IMETHODIMP +jsdStackFrame::GetThisValue(jsdIValue **_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSDValue *jsdv = JSD_GetThisForStackFrame (mCx, mThreadState, + mStackFrameInfo); + + *_rval = jsdValue::FromPtr (mCx, jsdv); + return NS_OK; +} + + +NS_IMETHODIMP +jsdStackFrame::Eval (const nsAString &bytes, const nsACString &fileName, + PRUint32 line, jsdIValue **result, PRBool *_rval) +{ + ASSERT_VALID_EPHEMERAL; + + if (bytes.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + // get pointer to buffer contained in |bytes| + nsAString::const_iterator h; + bytes.BeginReading(h); + const jschar *char_bytes = reinterpret_cast(h.get()); + + JSExceptionState *estate = 0; + jsval jv; + + JSContext *cx = JSD_GetJSContext (mCx, mThreadState); + + JSAutoRequest ar(cx); + + estate = JS_SaveExceptionState (cx); + JS_ClearPendingException (cx); + + nsresult rv; + nsCOMPtr stack = do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv); + if (NS_SUCCEEDED(rv)) + rv = stack->Push(cx); + if (NS_FAILED(rv)) { + JS_RestoreExceptionState (cx, estate); + return rv; + } + + *_rval = JSD_AttemptUCScriptInStackFrame (mCx, mThreadState, + mStackFrameInfo, + char_bytes, bytes.Length(), + PromiseFlatCString(fileName).get(), + line, &jv); + if (!*_rval) { + if (JS_IsExceptionPending(cx)) + JS_GetPendingException (cx, &jv); + else + jv = JSVAL_NULL; + } + + JS_RestoreExceptionState (cx, estate); + +#ifdef DEBUG + JSContext* poppedCX; + rv = stack->Pop(&poppedCX); + NS_ASSERTION(NS_SUCCEEDED(rv) && poppedCX == cx, "bad pop"); +#else + (void) stack->Pop(nsnull); +#endif + + JSDValue *jsdv = JSD_NewValue (mCx, jv); + if (!jsdv) + return NS_ERROR_FAILURE; + *result = jsdValue::FromPtr (mCx, jsdv); + if (!*result) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +/* Values */ +NS_IMPL_THREADSAFE_ISUPPORTS2(jsdValue, jsdIValue, jsdIEphemeral) +jsdIValue * +jsdValue::FromPtr (JSDContext *aCx, JSDValue *aValue) +{ + /* value will be dropped by te jsdValue destructor. */ + + if (!aValue) + return nsnull; + + jsdIValue *rv = new jsdValue (aCx, aValue); + NS_IF_ADDREF(rv); + return rv; +} + +jsdValue::jsdValue (JSDContext *aCx, JSDValue *aValue) : mValid(PR_TRUE), + mCx(aCx), + mValue(aValue) +{ + DEBUG_CREATE ("jsdValue", gValueCount); + mLiveListEntry.value = this; + jsds_InsertEphemeral (&gLiveValues, &mLiveListEntry); +} + +jsdValue::~jsdValue() +{ + DEBUG_DESTROY ("jsdValue", gValueCount); + if (mValid) + /* call Invalidate() to take ourselves out of the live list */ + Invalidate(); +} + +NS_IMETHODIMP +jsdValue::GetIsValid(PRBool *_rval) +{ + *_rval = mValid; + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::Invalidate() +{ + ASSERT_VALID_EPHEMERAL; + mValid = PR_FALSE; + jsds_RemoveEphemeral (&gLiveValues, &mLiveListEntry); + JSD_DropValue (mCx, mValue); + return NS_OK; +} + +void +jsdValue::InvalidateAll() +{ + if (gLiveValues) + jsds_InvalidateAllEphemerals (&gLiveValues); +} + +NS_IMETHODIMP +jsdValue::GetJSDContext(JSDContext **_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = mCx; + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetJSDValue (JSDValue **_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = mValue; + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetIsNative (PRBool *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_IsValueNative (mCx, mValue); + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetIsNumber (PRBool *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_IsValueNumber (mCx, mValue); + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetIsPrimitive (PRBool *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_IsValuePrimitive (mCx, mValue); + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetJsType (PRUint32 *_rval) +{ + ASSERT_VALID_EPHEMERAL; + jsval val; + + val = JSD_GetValueWrappedJSVal (mCx, mValue); + + if (JSVAL_IS_NULL(val)) + *_rval = TYPE_NULL; + else if (JSVAL_IS_BOOLEAN(val)) + *_rval = TYPE_BOOLEAN; + else if (JSVAL_IS_DOUBLE(val)) + *_rval = TYPE_DOUBLE; + else if (JSVAL_IS_INT(val)) + *_rval = TYPE_INT; + else if (JSVAL_IS_STRING(val)) + *_rval = TYPE_STRING; + else if (JSVAL_IS_VOID(val)) + *_rval = TYPE_VOID; + else if (JSD_IsValueFunction (mCx, mValue)) + *_rval = TYPE_FUNCTION; + else if (JSVAL_IS_OBJECT(val)) + *_rval = TYPE_OBJECT; + else + NS_ASSERTION (0, "Value has no discernible type."); + + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetJsPrototype (jsdIValue **_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSDValue *jsdv = JSD_GetValuePrototype (mCx, mValue); + *_rval = jsdValue::FromPtr (mCx, jsdv); + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetJsParent (jsdIValue **_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSDValue *jsdv = JSD_GetValueParent (mCx, mValue); + *_rval = jsdValue::FromPtr (mCx, jsdv); + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetJsClassName(nsACString &_rval) +{ + ASSERT_VALID_EPHEMERAL; + _rval.Assign(JSD_GetValueClassName(mCx, mValue)); + + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetJsConstructor (jsdIValue **_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSDValue *jsdv = JSD_GetValueConstructor (mCx, mValue); + *_rval = jsdValue::FromPtr (mCx, jsdv); + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetJsFunctionName(nsACString &_rval) +{ + ASSERT_VALID_EPHEMERAL; + return AssignToJSString(&_rval, JSD_GetValueFunctionId(mCx, mValue)); +} + +NS_IMETHODIMP +jsdValue::GetBooleanValue(PRBool *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_GetValueBoolean (mCx, mValue); + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetDoubleValue(double *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_GetValueDouble (mCx, mValue); + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetIntValue(PRInt32 *_rval) +{ + ASSERT_VALID_EPHEMERAL; + *_rval = JSD_GetValueInt (mCx, mValue); + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetObjectValue(jsdIObject **_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSDObject *obj; + obj = JSD_GetObjectForValue (mCx, mValue); + *_rval = jsdObject::FromPtr (mCx, obj); + if (!*_rval) + return NS_ERROR_FAILURE; + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetStringValue(nsACString &_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSContext *cx = JSD_GetDefaultJSContext (mCx); + if (!cx) { + NS_WARNING("No default context !?"); + return NS_ERROR_FAILURE; + } + JSString *jstr_val = JSD_GetValueString(mCx, mValue); + if (jstr_val) { + size_t length; + const jschar *chars = JS_GetStringCharsZAndLength(cx, jstr_val, &length); + if (!chars) + return NS_ERROR_FAILURE; + nsDependentString depStr(chars, length); + CopyUTF16toUTF8(depStr, _rval); + } else { + _rval.Truncate(); + } + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetPropertyCount (PRInt32 *_rval) +{ + ASSERT_VALID_EPHEMERAL; + if (JSD_IsValueObject(mCx, mValue)) + *_rval = JSD_GetCountOfProperties (mCx, mValue); + else + *_rval = -1; + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetProperties (jsdIProperty ***propArray, PRUint32 *length) +{ + ASSERT_VALID_EPHEMERAL; + *propArray = nsnull; + if (length) + *length = 0; + + PRUint32 prop_count = JSD_IsValueObject(mCx, mValue) + ? JSD_GetCountOfProperties (mCx, mValue) + : 0; + NS_ENSURE_TRUE(prop_count, NS_OK); + + jsdIProperty **pa_temp = + static_cast + (nsMemory::Alloc(sizeof (jsdIProperty *) * + prop_count)); + NS_ENSURE_TRUE(pa_temp, NS_ERROR_OUT_OF_MEMORY); + + PRUint32 i = 0; + JSDProperty *iter = NULL; + JSDProperty *prop; + while ((prop = JSD_IterateProperties (mCx, mValue, &iter))) { + pa_temp[i] = jsdProperty::FromPtr (mCx, prop); + ++i; + } + + NS_ASSERTION (prop_count == i, "property count mismatch"); + + /* if caller doesn't care about length, don't bother telling them */ + *propArray = pa_temp; + if (length) + *length = prop_count; + + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetProperty (const nsACString &name, jsdIProperty **_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSContext *cx = JSD_GetDefaultJSContext (mCx); + + JSAutoRequest ar(cx); + + /* not rooting this */ + JSString *jstr_name = JS_NewStringCopyZ(cx, PromiseFlatCString(name).get()); + if (!jstr_name) + return NS_ERROR_OUT_OF_MEMORY; + + JSDProperty *prop = JSD_GetValueProperty (mCx, mValue, jstr_name); + + *_rval = jsdProperty::FromPtr (mCx, prop); + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::Refresh() +{ + ASSERT_VALID_EPHEMERAL; + JSD_RefreshValue (mCx, mValue); + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetWrappedValue() +{ + ASSERT_VALID_EPHEMERAL; + nsresult rv; + nsCOMPtr xpc = do_GetService(nsIXPConnect::GetCID(), &rv); + if (NS_FAILED(rv)) + return rv; + + nsAXPCNativeCallContext *cc = nsnull; + rv = xpc->GetCurrentNativeCallContext(&cc); + if (NS_FAILED(rv)) + return rv; + + jsval *result; + rv = cc->GetRetValPtr(&result); + if (NS_FAILED(rv)) + return rv; + + if (result) + { + JSContext *cx; + rv = cc->GetJSContext(&cx); + if (NS_FAILED(rv)) + return rv; + *result = JSD_GetValueWrappedJSVal (mCx, mValue); + if (!JS_WrapValue(cx, result)) + return NS_ERROR_FAILURE; + cc->SetReturnValueWasSet(PR_TRUE); + } + + return NS_OK; +} + +NS_IMETHODIMP +jsdValue::GetScript(jsdIScript **_rval) +{ + ASSERT_VALID_EPHEMERAL; + JSDScript *script = JSD_GetScriptForValue(mCx, mValue); + *_rval = jsdScript::FromPtr(mCx, script); + return NS_OK; +} + +/****************************************************************************** + * debugger service implementation + ******************************************************************************/ +NS_IMPL_THREADSAFE_ISUPPORTS1(jsdService, jsdIDebuggerService) + +NS_IMETHODIMP +jsdService::GetJSDContext(JSDContext **_rval) +{ + *_rval = mCx; + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetFlags (PRUint32 *_rval) +{ + ASSERT_VALID_CONTEXT; + *_rval = JSD_GetContextFlags (mCx); + return NS_OK; +} + +NS_IMETHODIMP +jsdService::SetFlags (PRUint32 flags) +{ + ASSERT_VALID_CONTEXT; + JSD_SetContextFlags (mCx, flags); + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetImplementationString(nsACString &aImplementationString) +{ + aImplementationString.AssignLiteral(implementationString); + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetImplementationMajor(PRUint32 *_rval) +{ + *_rval = JSDS_MAJOR_VERSION; + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetImplementationMinor(PRUint32 *_rval) +{ + *_rval = JSDS_MINOR_VERSION; + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetIsOn (PRBool *_rval) +{ + *_rval = mOn; + return NS_OK; +} + +NS_IMETHODIMP +jsdService::On (void) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +jsdService::AsyncOn (jsdIActivationCallback *activationCallback) +{ + nsresult rv; + + /* get JS things from the CallContext */ + nsCOMPtr xpc = do_GetService(nsIXPConnect::GetCID(), &rv); + if (NS_FAILED(rv)) return rv; + + nsAXPCNativeCallContext *cc = nsnull; + rv = xpc->GetCurrentNativeCallContext(&cc); + if (NS_FAILED(rv)) return rv; + + JSContext *cx; + rv = cc->GetJSContext (&cx); + if (NS_FAILED(rv)) return rv; + + mActivationCallback = activationCallback; + + return xpc->SetDebugModeWhenPossible(PR_TRUE); +} + +NS_IMETHODIMP +jsdService::RecompileForDebugMode (JSContext *cx, JSCompartment *comp, JSBool mode) { + NS_ASSERTION(NS_IsMainThread(), "wrong thread"); + /* XPConnect now does this work itself, so this IDL entry point is no longer used. */ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +jsdService::DeactivateDebugger () +{ + if (!mCx) + return NS_OK; + + jsdContext::InvalidateAll(); + jsdScript::InvalidateAll(); + jsdValue::InvalidateAll(); + jsdProperty::InvalidateAll(); + jsdStackFrame::InvalidateAll(); + ClearAllBreakpoints(); + + JSD_SetErrorReporter (mCx, NULL, NULL); + JSD_SetScriptHook (mCx, NULL, NULL); + JSD_ClearThrowHook (mCx); + JSD_ClearInterruptHook (mCx); + JSD_ClearDebuggerHook (mCx); + JSD_ClearDebugBreakHook (mCx); + JSD_ClearTopLevelHook (mCx); + JSD_ClearFunctionHook (mCx); + + JSD_DebuggerOff (mCx); + + mCx = nsnull; + mRuntime = nsnull; + mOn = PR_FALSE; + + return NS_OK; +} + + +NS_IMETHODIMP +jsdService::ActivateDebugger (JSRuntime *rt) +{ + if (mOn) + return (rt == mRuntime) ? NS_OK : NS_ERROR_ALREADY_INITIALIZED; + + mRuntime = rt; + + if (gLastGCProc == jsds_GCCallbackProc) + /* condition indicates that the callback proc has not been set yet */ + gLastGCProc = JS_SetGCCallbackRT (rt, jsds_GCCallbackProc); + + mCx = JSD_DebuggerOnForUser (rt, NULL, NULL); + if (!mCx) + return NS_ERROR_FAILURE; + + JSContext *cx = JSD_GetDefaultJSContext (mCx); + JSObject *glob = JS_GetGlobalObject (cx); + + /* init xpconnect on the debugger's context in case xpconnect tries to + * use it for stuff. */ + nsresult rv; + nsCOMPtr xpc = do_GetService(nsIXPConnect::GetCID(), &rv); + if (NS_FAILED(rv)) + return rv; + + xpc->InitClasses (cx, glob); + + /* Start watching for script creation/destruction and manage jsdScript + * objects accordingly + */ + JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL); + + /* If any of these mFooHook objects are installed, do the required JSD + * hookup now. See also, jsdService::SetFooHook(). + */ + if (mErrorHook) + JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL); + if (mThrowHook) + JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL); + /* can't ignore script callbacks, as we need to |Release| the wrapper + * stored in private data when a script is deleted. */ + if (mInterruptHook) + JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL); + if (mDebuggerHook) + JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL); + if (mDebugHook) + JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL); + if (mTopLevelHook) + JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL); + else + JSD_ClearTopLevelHook (mCx); + if (mFunctionHook) + JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL); + else + JSD_ClearFunctionHook (mCx); + mOn = PR_TRUE; + +#ifdef DEBUG + printf ("+++ JavaScript debugging hooks installed.\n"); +#endif + + if (mActivationCallback) + return mActivationCallback->OnDebuggerActivated(); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::Off (void) +{ + if (!mOn) + return NS_OK; + + if (!mCx || !mRuntime) + return NS_ERROR_NOT_INITIALIZED; + + if (gDeadScripts) { + if (gGCStatus != JSGC_END) + return NS_ERROR_NOT_AVAILABLE; + + JSContext *cx = JSD_GetDefaultJSContext(mCx); + while (gDeadScripts) + jsds_NotifyPendingDeadScripts (cx); + } + + /* + if (gLastGCProc != jsds_GCCallbackProc) + JS_SetGCCallbackRT (mRuntime, gLastGCProc); + */ + + DeactivateDebugger(); + +#ifdef DEBUG + printf ("+++ JavaScript debugging hooks removed.\n"); +#endif + + nsresult rv; + nsCOMPtr xpc = do_GetService(nsIXPConnect::GetCID(), &rv); + if (NS_FAILED(rv)) + return rv; + + xpc->SetDebugModeWhenPossible(PR_FALSE); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetPauseDepth(PRUint32 *_rval) +{ + NS_ENSURE_ARG_POINTER(_rval); + *_rval = mPauseLevel; + return NS_OK; +} + +NS_IMETHODIMP +jsdService::Pause(PRUint32 *_rval) +{ + if (!mCx) + return NS_ERROR_NOT_INITIALIZED; + + if (++mPauseLevel == 1) { + JSD_SetErrorReporter (mCx, NULL, NULL); + JSD_ClearThrowHook (mCx); + JSD_ClearInterruptHook (mCx); + JSD_ClearDebuggerHook (mCx); + JSD_ClearDebugBreakHook (mCx); + JSD_ClearTopLevelHook (mCx); + JSD_ClearFunctionHook (mCx); + JSD_DebuggerPause (mCx); + } + + if (_rval) + *_rval = mPauseLevel; + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::UnPause(PRUint32 *_rval) +{ + if (!mCx) + return NS_ERROR_NOT_INITIALIZED; + + if (mPauseLevel == 0) + return NS_ERROR_NOT_AVAILABLE; + + /* check mOn before we muck with this stuff, it's possible the debugger + * was turned off while we were paused. + */ + if (--mPauseLevel == 0 && mOn) { + JSD_DebuggerUnpause (mCx); + if (mErrorHook) + JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL); + if (mThrowHook) + JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL); + if (mInterruptHook) + JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL); + if (mDebuggerHook) + JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL); + if (mDebugHook) + JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL); + if (mTopLevelHook) + JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL); + else + JSD_ClearTopLevelHook (mCx); + if (mFunctionHook) + JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL); + else + JSD_ClearFunctionHook (mCx); + } + + if (_rval) + *_rval = mPauseLevel; + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::EnumerateContexts (jsdIContextEnumerator *enumerator) +{ + ASSERT_VALID_CONTEXT; + + if (!enumerator) + return NS_OK; + + JSContext *iter = NULL; + JSContext *cx; + + while ((cx = JS_ContextIterator (mRuntime, &iter))) + { + nsCOMPtr jsdicx = + getter_AddRefs(jsdContext::FromPtr(mCx, cx)); + if (jsdicx) + { + if (NS_FAILED(enumerator->EnumerateContext(jsdicx))) + break; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::EnumerateScripts (jsdIScriptEnumerator *enumerator) +{ + ASSERT_VALID_CONTEXT; + + JSDScript *script; + JSDScript *iter = NULL; + nsresult rv = NS_OK; + + JSD_LockScriptSubsystem(mCx); + while((script = JSD_IterateScripts(mCx, &iter))) { + nsCOMPtr jsdis = + getter_AddRefs(jsdScript::FromPtr(mCx, script)); + rv = enumerator->EnumerateScript (jsdis); + if (NS_FAILED(rv)) + break; + } + JSD_UnlockScriptSubsystem(mCx); + + return rv; +} + +NS_IMETHODIMP +jsdService::GC (void) +{ + ASSERT_VALID_CONTEXT; + JSContext *cx = JSD_GetDefaultJSContext (mCx); + JS_GC(cx); + return NS_OK; +} + +NS_IMETHODIMP +jsdService::DumpHeap(const nsACString &fileName) +{ + ASSERT_VALID_CONTEXT; +#ifndef DEBUG + return NS_ERROR_NOT_IMPLEMENTED; +#else + nsresult rv = NS_OK; + FILE *file = !fileName.IsEmpty() ? fopen(PromiseFlatCString(fileName).get(), "w") : stdout; + if (!file) { + rv = NS_ERROR_FAILURE; + } else { + JSContext *cx = JSD_GetDefaultJSContext (mCx); + if (!JS_DumpHeap(cx, file, NULL, 0, NULL, (size_t)-1, NULL)) + rv = NS_ERROR_FAILURE; + if (file != stdout) + fclose(file); + } + return rv; +#endif +} + +NS_IMETHODIMP +jsdService::ClearProfileData () +{ + ASSERT_VALID_CONTEXT; + JSD_ClearAllProfileData (mCx); + return NS_OK; +} + +NS_IMETHODIMP +jsdService::InsertFilter (jsdIFilter *filter, jsdIFilter *after) +{ + NS_ENSURE_ARG_POINTER (filter); + if (jsds_FindFilter (filter)) + return NS_ERROR_INVALID_ARG; + + FilterRecord *rec = PR_NEWZAP (FilterRecord); + if (!rec) + return NS_ERROR_OUT_OF_MEMORY; + + if (!jsds_SyncFilter (rec, filter)) { + PR_Free (rec); + return NS_ERROR_FAILURE; + } + + if (gFilters) { + if (!after) { + /* insert at head of list */ + PR_INSERT_LINK(&rec->links, &gFilters->links); + gFilters = rec; + } else { + /* insert somewhere in the list */ + FilterRecord *afterRecord = jsds_FindFilter (after); + if (!afterRecord) { + jsds_FreeFilter(rec); + return NS_ERROR_INVALID_ARG; + } + PR_INSERT_AFTER(&rec->links, &afterRecord->links); + } + } else { + if (after) { + /* user asked to insert into the middle of an empty list, bail. */ + jsds_FreeFilter(rec); + return NS_ERROR_NOT_INITIALIZED; + } + PR_INIT_CLIST(&rec->links); + gFilters = rec; + } + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::AppendFilter (jsdIFilter *filter) +{ + NS_ENSURE_ARG_POINTER (filter); + if (jsds_FindFilter (filter)) + return NS_ERROR_INVALID_ARG; + FilterRecord *rec = PR_NEWZAP (FilterRecord); + + if (!jsds_SyncFilter (rec, filter)) { + PR_Free (rec); + return NS_ERROR_FAILURE; + } + + if (gFilters) { + PR_INSERT_BEFORE(&rec->links, &gFilters->links); + } else { + PR_INIT_CLIST(&rec->links); + gFilters = rec; + } + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::RemoveFilter (jsdIFilter *filter) +{ + NS_ENSURE_ARG_POINTER(filter); + FilterRecord *rec = jsds_FindFilter (filter); + if (!rec) + return NS_ERROR_INVALID_ARG; + + if (gFilters == rec) { + gFilters = reinterpret_cast + (PR_NEXT_LINK(&rec->links)); + /* If we're the only filter left, null out the list head. */ + if (gFilters == rec) + gFilters = nsnull; + } + + + PR_REMOVE_LINK(&rec->links); + jsds_FreeFilter (rec); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::SwapFilters (jsdIFilter *filter_a, jsdIFilter *filter_b) +{ + NS_ENSURE_ARG_POINTER(filter_a); + NS_ENSURE_ARG_POINTER(filter_b); + + FilterRecord *rec_a = jsds_FindFilter (filter_a); + if (!rec_a) + return NS_ERROR_INVALID_ARG; + + if (filter_a == filter_b) { + /* just a refresh */ + if (!jsds_SyncFilter (rec_a, filter_a)) + return NS_ERROR_FAILURE; + return NS_OK; + } + + FilterRecord *rec_b = jsds_FindFilter (filter_b); + if (!rec_b) { + /* filter_b is not in the list, replace filter_a with filter_b. */ + if (!jsds_SyncFilter (rec_a, filter_b)) + return NS_ERROR_FAILURE; + } else { + /* both filters are in the list, swap. */ + if (!jsds_SyncFilter (rec_a, filter_b)) + return NS_ERROR_FAILURE; + if (!jsds_SyncFilter (rec_b, filter_a)) + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::EnumerateFilters (jsdIFilterEnumerator *enumerator) +{ + if (!gFilters) + return NS_OK; + + FilterRecord *current = gFilters; + do { + jsds_SyncFilter (current, current->filterObject); + /* SyncFilter failure would be bad, but what would we do about it? */ + if (enumerator) { + nsresult rv = enumerator->EnumerateFilter (current->filterObject); + if (NS_FAILED(rv)) + return rv; + } + current = reinterpret_cast + (PR_NEXT_LINK (¤t->links)); + } while (current != gFilters); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::RefreshFilters () +{ + return EnumerateFilters(nsnull); +} + +NS_IMETHODIMP +jsdService::ClearFilters () +{ + if (!gFilters) + return NS_OK; + + FilterRecord *current = reinterpret_cast + (PR_NEXT_LINK (&gFilters->links)); + do { + FilterRecord *next = reinterpret_cast + (PR_NEXT_LINK (¤t->links)); + PR_REMOVE_AND_INIT_LINK(¤t->links); + jsds_FreeFilter(current); + current = next; + } while (current != gFilters); + + jsds_FreeFilter(current); + gFilters = nsnull; + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::ClearAllBreakpoints (void) +{ + ASSERT_VALID_CONTEXT; + + JSD_LockScriptSubsystem(mCx); + JSD_ClearAllExecutionHooks (mCx); + JSD_UnlockScriptSubsystem(mCx); + return NS_OK; +} + +NS_IMETHODIMP +jsdService::WrapValue(jsdIValue **_rval) +{ + ASSERT_VALID_CONTEXT; + + nsresult rv; + nsCOMPtr xpc = do_GetService (nsIXPConnect::GetCID(), &rv); + if (NS_FAILED(rv)) + return rv; + + nsAXPCNativeCallContext *cc = nsnull; + rv = xpc->GetCurrentNativeCallContext (&cc); + if (NS_FAILED(rv)) + return rv; + + PRUint32 argc; + rv = cc->GetArgc (&argc); + if (NS_FAILED(rv)) + return rv; + if (argc < 1) + return NS_ERROR_INVALID_ARG; + + jsval *argv; + rv = cc->GetArgvPtr (&argv); + if (NS_FAILED(rv)) + return rv; + + return WrapJSValue(argv[0], _rval); +} + +NS_IMETHODIMP +jsdService::WrapJSValue(const jsval &value, jsdIValue** _rval) +{ + JSDValue *jsdv = JSD_NewValue(mCx, value); + if (!jsdv) + return NS_ERROR_FAILURE; + + *_rval = jsdValue::FromPtr (mCx, jsdv); + return NS_OK; +} + + +NS_IMETHODIMP +jsdService::EnterNestedEventLoop (jsdINestCallback *callback, PRUint32 *_rval) +{ + // Nesting event queues is a thing of the past. Now, we just spin the + // current event loop. + + nsresult rv; + nsCOMPtr + stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv)); + if (NS_FAILED(rv)) + return rv; + PRUint32 nestLevel = ++mNestedLoopLevel; + + nsCOMPtr thread = do_GetCurrentThread(); + + if (NS_SUCCEEDED(stack->Push(nsnull))) { + if (callback) { + Pause(nsnull); + rv = callback->OnNest(); + UnPause(nsnull); + } + + while (NS_SUCCEEDED(rv) && mNestedLoopLevel >= nestLevel) { + if (!NS_ProcessNextEvent(thread)) + rv = NS_ERROR_UNEXPECTED; + } + + JSContext* cx; + stack->Pop(&cx); + NS_ASSERTION(cx == nsnull, "JSContextStack mismatch"); + } + else + rv = NS_ERROR_FAILURE; + + NS_ASSERTION (mNestedLoopLevel <= nestLevel, + "nested event didn't unwind properly"); + if (mNestedLoopLevel == nestLevel) + --mNestedLoopLevel; + + *_rval = mNestedLoopLevel; + return rv; +} + +NS_IMETHODIMP +jsdService::ExitNestedEventLoop (PRUint32 *_rval) +{ + if (mNestedLoopLevel > 0) + --mNestedLoopLevel; + else + return NS_ERROR_FAILURE; + + *_rval = mNestedLoopLevel; + return NS_OK; +} + +/* hook attribute get/set functions */ + +NS_IMETHODIMP +jsdService::SetErrorHook (jsdIErrorHook *aHook) +{ + mErrorHook = aHook; + + /* if the debugger isn't initialized, that's all we can do for now. The + * ActivateDebugger() method will do the rest when the coast is clear. + */ + if (!mCx || mPauseLevel) + return NS_OK; + + if (aHook) + JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL); + else + JSD_SetErrorReporter (mCx, NULL, NULL); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetErrorHook (jsdIErrorHook **aHook) +{ + *aHook = mErrorHook; + NS_IF_ADDREF(*aHook); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::SetBreakpointHook (jsdIExecutionHook *aHook) +{ + mBreakpointHook = aHook; + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetBreakpointHook (jsdIExecutionHook **aHook) +{ + *aHook = mBreakpointHook; + NS_IF_ADDREF(*aHook); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::SetDebugHook (jsdIExecutionHook *aHook) +{ + mDebugHook = aHook; + + /* if the debugger isn't initialized, that's all we can do for now. The + * ActivateDebugger() method will do the rest when the coast is clear. + */ + if (!mCx || mPauseLevel) + return NS_OK; + + if (aHook) + JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL); + else + JSD_ClearDebugBreakHook (mCx); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetDebugHook (jsdIExecutionHook **aHook) +{ + *aHook = mDebugHook; + NS_IF_ADDREF(*aHook); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::SetDebuggerHook (jsdIExecutionHook *aHook) +{ + mDebuggerHook = aHook; + + /* if the debugger isn't initialized, that's all we can do for now. The + * ActivateDebugger() method will do the rest when the coast is clear. + */ + if (!mCx || mPauseLevel) + return NS_OK; + + if (aHook) + JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL); + else + JSD_ClearDebuggerHook (mCx); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetDebuggerHook (jsdIExecutionHook **aHook) +{ + *aHook = mDebuggerHook; + NS_IF_ADDREF(*aHook); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::SetInterruptHook (jsdIExecutionHook *aHook) +{ + mInterruptHook = aHook; + + /* if the debugger isn't initialized, that's all we can do for now. The + * ActivateDebugger() method will do the rest when the coast is clear. + */ + if (!mCx || mPauseLevel) + return NS_OK; + + if (aHook) + JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL); + else + JSD_ClearInterruptHook (mCx); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetInterruptHook (jsdIExecutionHook **aHook) +{ + *aHook = mInterruptHook; + NS_IF_ADDREF(*aHook); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::SetScriptHook (jsdIScriptHook *aHook) +{ + mScriptHook = aHook; + + /* if the debugger isn't initialized, that's all we can do for now. The + * ActivateDebugger() method will do the rest when the coast is clear. + */ + if (!mCx || mPauseLevel) + return NS_OK; + + if (aHook) + JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL); + /* we can't unset it if !aHook, because we still need to see script + * deletes in order to Release the jsdIScripts held in JSDScript + * private data. */ + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetScriptHook (jsdIScriptHook **aHook) +{ + *aHook = mScriptHook; + NS_IF_ADDREF(*aHook); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::SetThrowHook (jsdIExecutionHook *aHook) +{ + mThrowHook = aHook; + + /* if the debugger isn't initialized, that's all we can do for now. The + * ActivateDebugger() method will do the rest when the coast is clear. + */ + if (!mCx || mPauseLevel) + return NS_OK; + + if (aHook) + JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL); + else + JSD_ClearThrowHook (mCx); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetThrowHook (jsdIExecutionHook **aHook) +{ + *aHook = mThrowHook; + NS_IF_ADDREF(*aHook); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::SetTopLevelHook (jsdICallHook *aHook) +{ + mTopLevelHook = aHook; + + /* if the debugger isn't initialized, that's all we can do for now. The + * ActivateDebugger() method will do the rest when the coast is clear. + */ + if (!mCx || mPauseLevel) + return NS_OK; + + if (aHook) + JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL); + else + JSD_ClearTopLevelHook (mCx); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetTopLevelHook (jsdICallHook **aHook) +{ + *aHook = mTopLevelHook; + NS_IF_ADDREF(*aHook); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::SetFunctionHook (jsdICallHook *aHook) +{ + mFunctionHook = aHook; + + /* if the debugger isn't initialized, that's all we can do for now. The + * ActivateDebugger() method will do the rest when the coast is clear. + */ + if (!mCx || mPauseLevel) + return NS_OK; + + if (aHook) + JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL); + else + JSD_ClearFunctionHook (mCx); + + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetFunctionHook (jsdICallHook **aHook) +{ + *aHook = mFunctionHook; + NS_IF_ADDREF(*aHook); + + return NS_OK; +} + +/* virtual */ +jsdService::~jsdService() +{ + ClearFilters(); + mErrorHook = nsnull; + mBreakpointHook = nsnull; + mDebugHook = nsnull; + mDebuggerHook = nsnull; + mInterruptHook = nsnull; + mScriptHook = nsnull; + mThrowHook = nsnull; + mTopLevelHook = nsnull; + mFunctionHook = nsnull; + gGCStatus = JSGC_END; + Off(); + gJsds = nsnull; +} + +jsdService * +jsdService::GetService () +{ + if (!gJsds) + gJsds = new jsdService(); + + NS_IF_ADDREF(gJsds); + return gJsds; +} + +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(jsdService, jsdService::GetService) + +/* app-start observer. turns on the debugger at app-start. this is inserted + * and/or removed from the app-start category by the jsdService::initAtStartup + * property. + */ +class jsdASObserver : public nsIObserver +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + jsdASObserver () {} +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(jsdASObserver, nsIObserver) + +NS_IMETHODIMP +jsdASObserver::Observe (nsISupports *aSubject, const char *aTopic, + const PRUnichar *aData) +{ + nsresult rv; + + // Hmm. Why is the app-startup observer called multiple times? + //NS_ASSERTION(!gJsds, "app startup observer called twice"); + nsCOMPtr jsds = do_GetService(jsdServiceCtrID, &rv); + if (NS_FAILED(rv)) + return rv; + + PRBool on; + rv = jsds->GetIsOn(&on); + if (NS_FAILED(rv) || on) + return rv; + + nsCOMPtr rts = do_GetService(NS_JSRT_CTRID, &rv); + if (NS_FAILED(rv)) + return rv; + + JSRuntime *rt; + rts->GetRuntime (&rt); + if (NS_FAILED(rv)) + return rv; + + rv = jsds->ActivateDebugger(rt); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver) +NS_DEFINE_NAMED_CID(JSDSERVICE_CID); +NS_DEFINE_NAMED_CID(JSDASO_CID); + +static const mozilla::Module::CIDEntry kJSDCIDs[] = { + { &kJSDSERVICE_CID, false, NULL, jsdServiceConstructor }, + { &kJSDASO_CID, false, NULL, jsdASObserverConstructor }, + { NULL } +}; + +static const mozilla::Module::ContractIDEntry kJSDContracts[] = { + { jsdServiceCtrID, &kJSDSERVICE_CID }, + { jsdARObserverCtrID, &kJSDASO_CID }, + { NULL } +}; + +static const mozilla::Module kJSDModule = { + mozilla::Module::kVersion, + kJSDCIDs, + kJSDContracts +}; + +NSMODULE_DEFN(JavaScript_Debugger) = &kJSDModule; + +/******************************************************************************** + ******************************************************************************** + * graveyard + */ + +#if 0 +/* Thread States */ +NS_IMPL_THREADSAFE_ISUPPORTS1(jsdThreadState, jsdIThreadState); + +NS_IMETHODIMP +jsdThreadState::GetJSDContext(JSDContext **_rval) +{ + *_rval = mCx; + return NS_OK; +} + +NS_IMETHODIMP +jsdThreadState::GetJSDThreadState(JSDThreadState **_rval) +{ + *_rval = mThreadState; + return NS_OK; +} + +NS_IMETHODIMP +jsdThreadState::GetFrameCount (PRUint32 *_rval) +{ + *_rval = JSD_GetCountOfStackFrames (mCx, mThreadState); + return NS_OK; +} + +NS_IMETHODIMP +jsdThreadState::GetTopFrame (jsdIStackFrame **_rval) +{ + JSDStackFrameInfo *sfi = JSD_GetStackFrame (mCx, mThreadState); + + *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi); + return NS_OK; +} + +NS_IMETHODIMP +jsdThreadState::GetPendingException(jsdIValue **_rval) +{ + JSDValue *jsdv = JSD_GetException (mCx, mThreadState); + + *_rval = jsdValue::FromPtr (mCx, jsdv); + return NS_OK; +} + +NS_IMETHODIMP +jsdThreadState::SetPendingException(jsdIValue *aException) +{ + JSDValue *jsdv; + + nsresult rv = aException->GetJSDValue (&jsdv); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + if (!JSD_SetException (mCx, mThreadState, jsdv)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +#endif diff --git a/js/jsd/jsd_xpc.h b/js/jsd/jsd_xpc.h new file mode 100644 index 0000000..ed759f4 --- /dev/null +++ b/js/jsd/jsd_xpc.h @@ -0,0 +1,398 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert Ginda, + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef JSDSERVICE_H___ +#define JSDSERVICE_H___ + +#include "jsdIDebuggerService.h" +#include "jsdebug.h" +#include "nsString.h" +#include "nsCOMPtr.h" +#include "nspr.h" + +// #if defined(DEBUG_rginda_l) +// # define DEBUG_verbose +// #endif + +struct LiveEphemeral { + /* link in a chain of live values list */ + PRCList links; + jsdIEphemeral *value; + void *key; +}; + +struct PCMapEntry { + PRUint32 pc, line; +}; + +/******************************************************************************* + * reflected jsd data structures + *******************************************************************************/ + +class jsdObject : public jsdIObject +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_JSDIOBJECT + + /* you'll normally use use FromPtr() instead of directly constructing one */ + jsdObject (JSDContext *aCx, JSDObject *aObject) : + mCx(aCx), mObject(aObject) + { + } + + static jsdIObject *FromPtr (JSDContext *aCx, + JSDObject *aObject) + { + if (!aObject) + return nsnull; + + jsdIObject *rv = new jsdObject (aCx, aObject); + NS_IF_ADDREF(rv); + return rv; + } + + private: + jsdObject(); /* no implementation */ + jsdObject(const jsdObject&); /* no implementation */ + + JSDContext *mCx; + JSDObject *mObject; +}; + + +class jsdProperty : public jsdIProperty +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_JSDIPROPERTY + NS_DECL_JSDIEPHEMERAL + + jsdProperty (JSDContext *aCx, JSDProperty *aProperty); + virtual ~jsdProperty (); + + static jsdIProperty *FromPtr (JSDContext *aCx, + JSDProperty *aProperty) + { + if (!aProperty) + return nsnull; + + jsdIProperty *rv = new jsdProperty (aCx, aProperty); + NS_IF_ADDREF(rv); + return rv; + } + + static void InvalidateAll(); + + private: + jsdProperty(); /* no implementation */ + jsdProperty(const jsdProperty&); /* no implementation */ + + PRBool mValid; + LiveEphemeral mLiveListEntry; + JSDContext *mCx; + JSDProperty *mProperty; +}; + +class jsdScript : public jsdIScript +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_JSDISCRIPT + NS_DECL_JSDIEPHEMERAL + + /* you'll normally use use FromPtr() instead of directly constructing one */ + jsdScript (JSDContext *aCx, JSDScript *aScript); + virtual ~jsdScript(); + + static jsdIScript *FromPtr (JSDContext *aCx, JSDScript *aScript) + { + if (!aScript) + return nsnull; + + void *data = JSD_GetScriptPrivate (aScript); + jsdIScript *rv; + + if (data) { + rv = static_cast(data); + } else { + rv = new jsdScript (aCx, aScript); + NS_IF_ADDREF(rv); /* addref for the SetScriptPrivate, released in + * Invalidate() */ + JSD_SetScriptPrivate (aScript, static_cast(rv)); + } + + NS_IF_ADDREF(rv); /* addref for return value */ + return rv; + } + + static void InvalidateAll(); + + private: + static PRUint32 LastTag; + + jsdScript(); /* no implementation */ + jsdScript (const jsdScript&); /* no implementation */ + PCMapEntry* CreatePPLineMap(); + PRUint32 PPPcToLine(PRUint32 aPC); + PRUint32 PPLineToPc(PRUint32 aLine); + + PRBool mValid; + PRUint32 mTag; + JSDContext *mCx; + JSDScript *mScript; + nsCString *mFileName; + nsCString *mFunctionName; + PRUint32 mBaseLineNumber, mLineExtent; + PCMapEntry *mPPLineMap; + PRUint32 mPCMapSize; + jsuword mFirstPC; +}; + +PRUint32 jsdScript::LastTag = 0; + +class jsdContext : public jsdIContext +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_JSDICONTEXT + NS_DECL_JSDIEPHEMERAL + + jsdContext (JSDContext *aJSDCx, JSContext *aJSCx, nsISupports *aISCx); + virtual ~jsdContext(); + + static void InvalidateAll(); + static jsdIContext *FromPtr (JSDContext *aJSDCx, JSContext *aJSCx); + private: + static PRUint32 LastTag; + + jsdContext (); /* no implementation */ + jsdContext (const jsdContext&); /* no implementation */ + + PRBool mValid; + LiveEphemeral mLiveListEntry; + PRUint32 mTag; + JSDContext *mJSDCx; + JSContext *mJSCx; + nsCOMPtr mISCx; +}; + +PRUint32 jsdContext::LastTag = 0; + +class jsdStackFrame : public jsdIStackFrame +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_JSDISTACKFRAME + NS_DECL_JSDIEPHEMERAL + + /* you'll normally use use FromPtr() instead of directly constructing one */ + jsdStackFrame (JSDContext *aCx, JSDThreadState *aThreadState, + JSDStackFrameInfo *aStackFrameInfo); + virtual ~jsdStackFrame(); + + static void InvalidateAll(); + static jsdIStackFrame* FromPtr (JSDContext *aCx, + JSDThreadState *aThreadState, + JSDStackFrameInfo *aStackFrameInfo); + + private: + jsdStackFrame(); /* no implementation */ + jsdStackFrame(const jsdStackFrame&); /* no implementation */ + + PRBool mValid; + LiveEphemeral mLiveListEntry; + JSDContext *mCx; + JSDThreadState *mThreadState; + JSDStackFrameInfo *mStackFrameInfo; +}; + +class jsdValue : public jsdIValue +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_JSDIVALUE + NS_DECL_JSDIEPHEMERAL + + /* you'll normally use use FromPtr() instead of directly constructing one */ + jsdValue (JSDContext *aCx, JSDValue *aValue); + virtual ~jsdValue(); + + static jsdIValue *FromPtr (JSDContext *aCx, JSDValue *aValue); + static void InvalidateAll(); + + private: + jsdValue(); /* no implementation */ + jsdValue (const jsdScript&); /* no implementation */ + + PRBool mValid; + LiveEphemeral mLiveListEntry; + JSDContext *mCx; + JSDValue *mValue; +}; + +/****************************************************************************** + * debugger service + ******************************************************************************/ + +class jsdService : public jsdIDebuggerService +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_JSDIDEBUGGERSERVICE + + jsdService() : mOn(PR_FALSE), mPauseLevel(0), + mNestedLoopLevel(0), mCx(0), mRuntime(0), mErrorHook(0), + mBreakpointHook(0), mDebugHook(0), mDebuggerHook(0), + mInterruptHook(0), mScriptHook(0), mThrowHook(0), + mTopLevelHook(0), mFunctionHook(0) + { + } + + virtual ~jsdService(); + + static jsdService *GetService (); + + PRBool CheckInterruptHook() { return !!mInterruptHook; } + + private: + PRBool mOn; + PRUint32 mPauseLevel; + PRUint32 mNestedLoopLevel; + JSDContext *mCx; + JSRuntime *mRuntime; + + nsCOMPtr mErrorHook; + nsCOMPtr mBreakpointHook; + nsCOMPtr mDebugHook; + nsCOMPtr mDebuggerHook; + nsCOMPtr mInterruptHook; + nsCOMPtr mScriptHook; + nsCOMPtr mThrowHook; + nsCOMPtr mTopLevelHook; + nsCOMPtr mFunctionHook; + nsCOMPtr mActivationCallback; +}; + +#endif /* JSDSERVICE_H___ */ + + +/* graveyard */ + +#if 0 + +class jsdContext : public jsdIContext +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_JSDICONTEXT + + /* you'll normally use use FromPtr() instead of directly constructing one */ + jsdContext (JSDContext *aCx) : mCx(aCx) + { + printf ("++++++ jsdContext\n"); + } + + static jsdIContext *FromPtr (JSDContext *aCx) + { + if (!aCx) + return nsnull; + + void *data = JSD_GetContextPrivate (aCx); + jsdIContext *rv; + + if (data) { + rv = static_cast(data); + } else { + rv = new jsdContext (aCx); + NS_IF_ADDREF(rv); // addref for the SetContextPrivate + JSD_SetContextPrivate (aCx, static_cast(rv)); + } + + NS_IF_ADDREF(rv); // addref for the return value + return rv; + } + + virtual ~jsdContext() { printf ("------ ~jsdContext\n"); } + private: + jsdContext(); /* no implementation */ + jsdContext(const jsdContext&); /* no implementation */ + + JSDContext *mCx; +}; + +class jsdThreadState : public jsdIThreadState +{ + public: + NS_DECL_ISUPPORTS + NS_DECL_JSDITHREADSTATE + + /* you'll normally use use FromPtr() instead of directly constructing one */ + jsdThreadState (JSDContext *aCx, JSDThreadState *aThreadState) : + mCx(aCx), mThreadState(aThreadState) + { + } + + /* XXX These things are only valid for a short period of time, they reflect + * state in the js engine that will go away after stepping past wherever + * we were stopped at when this was created. We could keep a list of every + * instance of this we've created, and "invalidate" them before we let the + * engine continue. The next time we need a threadstate, we can search the + * list to find an invalidated one, and just reuse it. + */ + static jsdIThreadState *FromPtr (JSDContext *aCx, + JSDThreadState *aThreadState) + { + if (!aThreadState) + return nsnull; + + jsdIThreadState *rv = new jsdThreadState (aCx, aThreadState); + NS_IF_ADDREF(rv); + return rv; + } + + private: + jsdThreadState(); /* no implementation */ + jsdThreadState(const jsdThreadState&); /* no implementation */ + + JSDContext *mCx; + JSDThreadState *mThreadState; +}; + +#endif diff --git a/js/jsd/jsdebug.c b/js/jsd/jsdebug.c new file mode 100644 index 0000000..6ae9c58 --- /dev/null +++ b/js/jsd/jsdebug.c @@ -0,0 +1,1398 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript Debugging support - All public functions + */ + +#include "jsd.h" + +/***************************************************************************/ +/* High Level calls */ + +JSD_PUBLIC_API(JSDContext*) +JSD_DebuggerOnForUser(JSRuntime* jsrt, + JSD_UserCallbacks* callbacks, + void* user) +{ + return jsd_DebuggerOnForUser(jsrt, callbacks, user, NULL); +} + +JSD_PUBLIC_API(JSDContext*) +JSD_DebuggerOn(void) +{ + return jsd_DebuggerOn(); +} + +JSD_PUBLIC_API(void) +JSD_DebuggerOff(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + jsd_DebuggerOff(jsdc); +} + +JSD_PUBLIC_API(void) +JSD_DebuggerPause(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + jsd_DebuggerPause(jsdc, JS_FALSE); +} + +JSD_PUBLIC_API(void) +JSD_DebuggerUnpause(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + jsd_DebuggerUnpause(jsdc); +} + +JSD_PUBLIC_API(uintN) +JSD_GetMajorVersion(void) +{ + return JSD_MAJOR_VERSION; +} + +JSD_PUBLIC_API(uintN) +JSD_GetMinorVersion(void) +{ + return JSD_MINOR_VERSION; +} + +JSD_PUBLIC_API(JSContext*) +JSD_GetDefaultJSContext(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsdc->dumbContext; +} + +JSD_PUBLIC_API(void) +JSD_SetUserCallbacks(JSRuntime* jsrt, JSD_UserCallbacks* callbacks, void* user) +{ + jsd_SetUserCallbacks(jsrt, callbacks, user); +} + +JSD_PUBLIC_API(void) +JSD_JSContextInUse(JSDContext* jsdc, JSContext* context) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + /* we no longer need this information - may need it again in the future */ +} + +JSD_PUBLIC_API(void *) +JSD_SetContextPrivate(JSDContext *jsdc, void *data) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_SetContextPrivate (jsdc, data); +} + +JSD_PUBLIC_API(void *) +JSD_GetContextPrivate(JSDContext *jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetContextPrivate (jsdc); +} + +JSD_PUBLIC_API(void) +JSD_ClearAllProfileData(JSDContext *jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + jsd_ClearAllProfileData(jsdc); +} + +JSD_PUBLIC_API(void) +JSD_SetContextFlags(JSDContext *jsdc, uint32 flags) +{ + uint32 oldFlags = jsdc->flags; + JSD_ASSERT_VALID_CONTEXT(jsdc); + jsdc->flags = flags; + if (flags & JSD_COLLECT_PROFILE_DATA) { + /* Need to reenable our call hooks now */ + JS_SetExecuteHook(jsdc->jsrt, jsd_TopLevelCallHook, jsdc); + JS_SetCallHook(jsdc->jsrt, jsd_FunctionCallHook, jsdc); + } +} + +JSD_PUBLIC_API(uint32) +JSD_GetContextFlags(JSDContext *jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsdc->flags; +} + +JSD_PUBLIC_API(JSDContext*) +JSD_JSDContextForJSContext(JSContext* context) +{ + return jsd_JSDContextForJSContext(context); +} + +/***************************************************************************/ +/* Script functions */ + +JSD_PUBLIC_API(void) +JSD_LockScriptSubsystem(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_LOCK_SCRIPTS(jsdc); +} + +JSD_PUBLIC_API(void) +JSD_UnlockScriptSubsystem(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_UNLOCK_SCRIPTS(jsdc); +} + +JSD_PUBLIC_API(JSDScript*) +JSD_IterateScripts(JSDContext* jsdc, JSDScript **iterp) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_IterateScripts(jsdc, iterp); +} + +JSD_PUBLIC_API(uint32) +JSD_GetScriptFlags(JSDContext *jsdc, JSDScript *script) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetScriptFlags(jsdc, script); +} + +JSD_PUBLIC_API(void) +JSD_SetScriptFlags(JSDContext *jsdc, JSDScript *script, uint32 flags) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + jsd_SetScriptFlags(jsdc, script, flags); +} + +JSD_PUBLIC_API(uintN) +JSD_GetScriptCallCount(JSDContext* jsdc, JSDScript *script) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetScriptCallCount(jsdc, script); +} + +JSD_PUBLIC_API(uintN) +JSD_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetScriptMaxRecurseDepth(jsdc, script); +} + + +JSD_PUBLIC_API(jsdouble) +JSD_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetScriptMinExecutionTime(jsdc, script); +} + +JSD_PUBLIC_API(jsdouble) +JSD_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetScriptMaxExecutionTime(jsdc, script); +} + +JSD_PUBLIC_API(jsdouble) +JSD_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetScriptTotalExecutionTime(jsdc, script); +} + +JSD_PUBLIC_API(jsdouble) +JSD_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetScriptMinOwnExecutionTime(jsdc, script); +} + +JSD_PUBLIC_API(jsdouble) +JSD_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetScriptMaxOwnExecutionTime(jsdc, script); +} + +JSD_PUBLIC_API(jsdouble) +JSD_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetScriptTotalOwnExecutionTime(jsdc, script); +} + +JSD_PUBLIC_API(void) +JSD_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + jsd_ClearScriptProfileData(jsdc, script); +} + +JSD_PUBLIC_API(JSScript*) +JSD_GetJSScript(JSDContext* jsdc, JSDScript *script) +{ + return jsd_GetJSScript(jsdc, script); +} + +JSD_PUBLIC_API(JSFunction*) +JSD_GetJSFunction(JSDContext* jsdc, JSDScript *script) +{ + return jsd_GetJSFunction (jsdc, script); +} + +JSD_PUBLIC_API(void *) +JSD_SetScriptPrivate(JSDScript *jsdscript, void *data) +{ + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsd_SetScriptPrivate (jsdscript, data); +} + +JSD_PUBLIC_API(void *) +JSD_GetScriptPrivate(JSDScript *jsdscript) +{ + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsd_GetScriptPrivate (jsdscript); +} + + +JSD_PUBLIC_API(JSBool) +JSD_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_IsActiveScript(jsdc, jsdscript); +} + +JSD_PUBLIC_API(const char*) +JSD_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsd_GetScriptFilename(jsdc, jsdscript); +} + +JSD_PUBLIC_API(JSString *) +JSD_GetScriptFunctionId(JSDContext* jsdc, JSDScript *jsdscript) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsd_GetScriptFunctionId(jsdc, jsdscript); +} + +JSD_PUBLIC_API(uintN) +JSD_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsd_GetScriptBaseLineNumber(jsdc, jsdscript); +} + +JSD_PUBLIC_API(uintN) +JSD_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsd_GetScriptLineExtent(jsdc, jsdscript); +} + +JSD_PUBLIC_API(JSBool) +JSD_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_SetScriptHook(jsdc, hook, callerdata); +} + +JSD_PUBLIC_API(JSBool) +JSD_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetScriptHook(jsdc, hook, callerdata); +} + +JSD_PUBLIC_API(jsuword) +JSD_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsd_GetClosestPC(jsdc, jsdscript, line); +} + +JSD_PUBLIC_API(uintN) +JSD_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsd_GetClosestLine(jsdc, jsdscript, pc); +} + +JSD_PUBLIC_API(void) +JSD_ScriptCreated(JSDContext* jsdc, + JSContext *cx, + const char *filename, /* URL this script loads from */ + uintN lineno, /* line where this script starts */ + JSScript *script, + JSFunction *fun) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + jsd_ScriptCreated(jsdc, cx, filename, lineno, script, fun); +} + +JSD_PUBLIC_API(void) +JSD_ScriptDestroyed(JSDContext* jsdc, + JSContext *cx, + JSScript *script) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + jsd_ScriptDestroyed(jsdc, cx, script); +} + +/***************************************************************************/ +/* Source Text functions */ + +JSD_PUBLIC_API(void) +JSD_LockSourceTextSubsystem(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_LOCK_SOURCE_TEXT(jsdc); +} + +JSD_PUBLIC_API(void) +JSD_UnlockSourceTextSubsystem(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_UNLOCK_SOURCE_TEXT(jsdc); +} + +JSD_PUBLIC_API(JSDSourceText*) +JSD_IterateSources(JSDContext* jsdc, JSDSourceText **iterp) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_IterateSources(jsdc, iterp); +} + +JSD_PUBLIC_API(JSDSourceText*) +JSD_FindSourceForURL(JSDContext* jsdc, const char* url) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JS_ASSERT(url); + return jsd_FindSourceForURL(jsdc, url); +} + +JSD_PUBLIC_API(const char*) +JSD_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc); + return jsd_GetSourceURL(jsdc,jsdsrc); +} + +JSD_PUBLIC_API(JSBool) +JSD_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc, + const char** ppBuf, intN* pLen) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc); + JS_ASSERT(ppBuf); + JS_ASSERT(pLen); + return jsd_GetSourceText(jsdc, jsdsrc, ppBuf, pLen); +} + +JSD_PUBLIC_API(void) +JSD_ClearSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc); + jsd_ClearSourceText(jsdc, jsdsrc); +} + + +JSD_PUBLIC_API(JSDSourceStatus) +JSD_GetSourceStatus(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc); + return jsd_GetSourceStatus(jsdc, jsdsrc); +} + +JSD_PUBLIC_API(JSBool) +JSD_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc); + return jsd_IsSourceDirty(jsdc, jsdsrc); +} + +JSD_PUBLIC_API(void) +JSD_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, JSBool dirty) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc); + jsd_SetSourceDirty(jsdc, jsdsrc, dirty); +} + +JSD_PUBLIC_API(uintN) +JSD_GetSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc); + return jsd_GetSourceAlterCount(jsdc, jsdsrc); +} + +JSD_PUBLIC_API(uintN) +JSD_IncrementSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc); + return jsd_IncrementSourceAlterCount(jsdc, jsdsrc); +} + +JSD_PUBLIC_API(void) +JSD_DestroyAllSources( JSDContext* jsdc ) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + jsd_DestroyAllSources(jsdc); +} + +JSD_PUBLIC_API(JSDSourceText*) +JSD_NewSourceText(JSDContext* jsdc, const char* url) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JS_ASSERT(url); + return jsd_NewSourceText(jsdc, url); +} + +JSD_PUBLIC_API(JSDSourceText*) +JSD_AppendSourceText(JSDContext* jsdc, + JSDSourceText* jsdsrc, + const char* text, /* *not* zero terminated */ + size_t length, + JSDSourceStatus status) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc); + return jsd_AppendSourceText(jsdc, jsdsrc, text, length, status); +} + +extern JSD_PUBLIC_API(JSDSourceText*) +JSD_AppendUCSourceText(JSDContext* jsdc, + JSDSourceText* jsdsrc, + const jschar* text, /* *not* zero terminated */ + size_t length, + JSDSourceStatus status) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc); + return jsd_AppendUCSourceText(jsdc, jsdsrc, text, length, status); +} + +JSD_PUBLIC_API(JSBool) +JSD_AddFullSourceText(JSDContext* jsdc, + const char* text, /* *not* zero terminated */ + size_t length, + const char* url) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JS_ASSERT(url); + return jsd_AddFullSourceText(jsdc, text, length, url); +} + +/***************************************************************************/ +/* Execution/Interrupt Hook functions */ + +JSD_PUBLIC_API(JSBool) +JSD_SetExecutionHook(JSDContext* jsdc, + JSDScript* jsdscript, + jsuword pc, + JSD_ExecutionHookProc hook, + void* callerdata) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsd_SetExecutionHook(jsdc, jsdscript, pc, hook, callerdata); +} + +JSD_PUBLIC_API(JSBool) +JSD_ClearExecutionHook(JSDContext* jsdc, + JSDScript* jsdscript, + jsuword pc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsd_ClearExecutionHook(jsdc, jsdscript, pc); +} + +JSD_PUBLIC_API(JSBool) +JSD_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsd_ClearAllExecutionHooksForScript(jsdc, jsdscript); +} + +JSD_PUBLIC_API(JSBool) +JSD_ClearAllExecutionHooks(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_ClearAllExecutionHooks(jsdc); +} + +JSD_PUBLIC_API(JSBool) +JSD_SetInterruptHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_SetInterruptHook(jsdc, hook, callerdata); +} + +JSD_PUBLIC_API(JSBool) +JSD_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, JSBool enable) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsd_EnableSingleStepInterrupts(jsdc, jsdscript, enable); +} + +JSD_PUBLIC_API(JSBool) +JSD_ClearInterruptHook(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_ClearInterruptHook(jsdc); +} + +JSD_PUBLIC_API(JSBool) +JSD_SetDebugBreakHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_SetDebugBreakHook(jsdc, hook, callerdata); +} + +JSD_PUBLIC_API(JSBool) +JSD_ClearDebugBreakHook(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_ClearDebugBreakHook(jsdc); +} + +JSD_PUBLIC_API(JSBool) +JSD_SetDebuggerHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_SetDebuggerHook(jsdc, hook, callerdata); +} + +JSD_PUBLIC_API(JSBool) +JSD_ClearDebuggerHook(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_ClearDebuggerHook(jsdc); +} + +JSD_PUBLIC_API(JSBool) +JSD_SetThrowHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_SetThrowHook(jsdc, hook, callerdata); +} + +JSD_PUBLIC_API(JSBool) +JSD_ClearThrowHook(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_ClearThrowHook(jsdc); +} + +JSD_PUBLIC_API(JSBool) +JSD_SetTopLevelHook(JSDContext* jsdc, + JSD_CallHookProc hook, + void* callerdata) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_SetTopLevelHook(jsdc, hook, callerdata); +} + +JSD_PUBLIC_API(JSBool) +JSD_ClearTopLevelHook(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_ClearTopLevelHook(jsdc); +} + +JSD_PUBLIC_API(JSBool) +JSD_SetFunctionHook(JSDContext* jsdc, + JSD_CallHookProc hook, + void* callerdata) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_SetFunctionHook(jsdc, hook, callerdata); +} + +JSD_PUBLIC_API(JSBool) +JSD_ClearFunctionHook(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_ClearFunctionHook(jsdc); +} + +/***************************************************************************/ +/* Stack Frame functions */ + +JSD_PUBLIC_API(uintN) +JSD_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetCountOfStackFrames(jsdc, jsdthreadstate); +} + +JSD_PUBLIC_API(JSDStackFrameInfo*) +JSD_GetStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetStackFrame(jsdc, jsdthreadstate); +} + +JSD_PUBLIC_API(JSContext*) +JSD_GetJSContext(JSDContext* jsdc, JSDThreadState* jsdthreadstate) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetJSContext(jsdc, jsdthreadstate); +} + +JSD_PUBLIC_API(JSDStackFrameInfo*) +JSD_GetCallingStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetCallingStackFrame(jsdc, jsdthreadstate, jsdframe); +} + +JSD_PUBLIC_API(JSDScript*) +JSD_GetScriptForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetScriptForStackFrame(jsdc, jsdthreadstate, jsdframe); +} + +JSD_PUBLIC_API(jsuword) +JSD_GetPCForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetPCForStackFrame(jsdc, jsdthreadstate, jsdframe); +} + +JSD_PUBLIC_API(JSDValue*) +JSD_GetCallObjectForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetCallObjectForStackFrame(jsdc, jsdthreadstate, jsdframe); +} + +JSD_PUBLIC_API(JSDValue*) +JSD_GetScopeChainForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetScopeChainForStackFrame(jsdc, jsdthreadstate, jsdframe); +} + +JSD_PUBLIC_API(JSDValue*) +JSD_GetThisForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetThisForStackFrame(jsdc, jsdthreadstate, jsdframe); +} + +JSD_PUBLIC_API(JSString *) +JSD_GetIdForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetIdForStackFrame(jsdc, jsdthreadstate, jsdframe); +} + +JSD_PUBLIC_API(JSBool) +JSD_IsStackFrameDebugger(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_IsStackFrameDebugger(jsdc, jsdthreadstate, jsdframe); +} + +JSD_PUBLIC_API(JSBool) +JSD_IsStackFrameConstructing(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_IsStackFrameConstructing(jsdc, jsdthreadstate, jsdframe); +} + +JSD_PUBLIC_API(JSBool) +JSD_EvaluateUCScriptInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + const jschar *bytes, uintN length, + const char *filename, uintN lineno, jsval *rval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JS_ASSERT(bytes); + JS_ASSERT(length); + JS_ASSERT(filename); + JS_ASSERT(rval); + + return jsd_EvaluateUCScriptInStackFrame(jsdc, jsdthreadstate,jsdframe, + bytes, length, filename, lineno, + JS_TRUE, rval); +} + +JSD_PUBLIC_API(JSBool) +JSD_AttemptUCScriptInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + const jschar *bytes, uintN length, + const char *filename, uintN lineno, + jsval *rval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JS_ASSERT(bytes); + JS_ASSERT(length); + JS_ASSERT(filename); + JS_ASSERT(rval); + + return jsd_EvaluateUCScriptInStackFrame(jsdc, jsdthreadstate,jsdframe, + bytes, length, filename, lineno, + JS_FALSE, rval); +} + +JSD_PUBLIC_API(JSBool) +JSD_EvaluateScriptInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + const char *bytes, uintN length, + const char *filename, uintN lineno, jsval *rval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JS_ASSERT(bytes); + JS_ASSERT(length); + JS_ASSERT(filename); + JS_ASSERT(rval); + + return jsd_EvaluateScriptInStackFrame(jsdc, jsdthreadstate,jsdframe, + bytes, length, + filename, lineno, JS_TRUE, rval); +} + +JSD_PUBLIC_API(JSBool) +JSD_AttemptScriptInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + const char *bytes, uintN length, + const char *filename, uintN lineno, jsval *rval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JS_ASSERT(bytes); + JS_ASSERT(length); + JS_ASSERT(filename); + JS_ASSERT(rval); + + return jsd_EvaluateScriptInStackFrame(jsdc, jsdthreadstate,jsdframe, + bytes, length, + filename, lineno, JS_FALSE, rval); +} + +JSD_PUBLIC_API(JSString*) +JSD_ValToStringInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + jsval val) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_ValToStringInStackFrame(jsdc, jsdthreadstate, jsdframe, val); +} + +JSD_PUBLIC_API(JSDValue*) +JSD_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetException(jsdc, jsdthreadstate); +} + +extern JSD_PUBLIC_API(JSBool) +JSD_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate, + JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_SetException(jsdc, jsdthreadstate, jsdval); +} + +/***************************************************************************/ + +JSD_PUBLIC_API(JSBool) +JSD_SetErrorReporter(JSDContext* jsdc, + JSD_ErrorReporter reporter, + void* callerdata) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_SetErrorReporter(jsdc, reporter, callerdata); +} + +JSD_PUBLIC_API(JSBool) +JSD_GetErrorReporter(JSDContext* jsdc, + JSD_ErrorReporter* reporter, + void** callerdata) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetErrorReporter(jsdc, reporter, callerdata); +} + +/***************************************************************************/ + +JSD_PUBLIC_API(JSBool) +JSD_IsLockingAndThreadIdSupported() +{ +#ifdef JSD_THREADSAFE + return JS_TRUE; +#else + return JS_FALSE; +#endif +} + +JSD_PUBLIC_API(void*) +JSD_CreateLock() +{ +#ifdef JSD_THREADSAFE + return jsd_CreateLock(); +#else + return (void*)1; +#endif +} + +JSD_PUBLIC_API(void) +JSD_Lock(void* lock) +{ +#ifdef JSD_THREADSAFE + jsd_Lock(lock); +#endif +} + +JSD_PUBLIC_API(void) +JSD_Unlock(void* lock) +{ +#ifdef JSD_THREADSAFE + jsd_Unlock(lock); +#endif +} + +JSD_PUBLIC_API(JSBool) +JSD_IsLocked(void* lock) +{ +#if defined(JSD_THREADSAFE) && defined(DEBUG) + return jsd_IsLocked(lock); +#else + return JS_TRUE; +#endif +} + +JSD_PUBLIC_API(JSBool) +JSD_IsUnlocked(void* lock) +{ +#if defined(JSD_THREADSAFE) && defined(DEBUG) + return ! jsd_IsLocked(lock); +#else + return JS_TRUE; +#endif +} + +JSD_PUBLIC_API(void*) +JSD_CurrentThread() +{ + return JSD_CURRENT_THREAD(); +} + +/***************************************************************************/ +/* Value and Property Functions */ + +JSD_PUBLIC_API(JSDValue*) +JSD_NewValue(JSDContext* jsdc, jsval val) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_NewValue(jsdc, val); +} + +JSD_PUBLIC_API(void) +JSD_DropValue(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + jsd_DropValue(jsdc, jsdval); +} + +JSD_PUBLIC_API(jsval) +JSD_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_GetValueWrappedJSVal(jsdc, jsdval); +} + +JSD_PUBLIC_API(void) +JSD_RefreshValue(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + jsd_RefreshValue(jsdc, jsdval); +} + +/**************************************************/ + +JSD_PUBLIC_API(JSBool) +JSD_IsValueObject(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_IsValueObject(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSBool) +JSD_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_IsValueNumber(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSBool) +JSD_IsValueInt(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_IsValueInt(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSBool) +JSD_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_IsValueDouble(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSBool) +JSD_IsValueString(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_IsValueString(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSBool) +JSD_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_IsValueBoolean(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSBool) +JSD_IsValueNull(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_IsValueNull(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSBool) +JSD_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_IsValueVoid(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSBool) +JSD_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_IsValuePrimitive(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSBool) +JSD_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_IsValueFunction(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSBool) +JSD_IsValueNative(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_IsValueNative(jsdc, jsdval); +} + +/**************************************************/ + +JSD_PUBLIC_API(JSBool) +JSD_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_GetValueBoolean(jsdc, jsdval); +} + +JSD_PUBLIC_API(int32) +JSD_GetValueInt(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_GetValueInt(jsdc, jsdval); +} + +JSD_PUBLIC_API(jsdouble) +JSD_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_GetValueDouble(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSString*) +JSD_GetValueString(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_GetValueString(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSString *) +JSD_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_GetValueFunctionId(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSFunction*) +JSD_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_GetValueFunction(jsdc, jsdval); +} + +/**************************************************/ + +JSD_PUBLIC_API(uintN) +JSD_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_GetCountOfProperties(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSDProperty*) +JSD_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + JS_ASSERT(iterp); + return jsd_IterateProperties(jsdc, jsdval, iterp); +} + +JSD_PUBLIC_API(JSDProperty*) +JSD_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + JS_ASSERT(name); + return jsd_GetValueProperty(jsdc, jsdval, name); +} + +JSD_PUBLIC_API(JSDValue*) +JSD_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_GetValuePrototype(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSDValue*) +JSD_GetValueParent(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_GetValueParent(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSDValue*) +JSD_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_GetValueConstructor(jsdc, jsdval); +} + +JSD_PUBLIC_API(const char*) +JSD_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_GetValueClassName(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSDScript*) +JSD_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_GetScriptForValue(jsdc, jsdval); +} +/**************************************************/ + +JSD_PUBLIC_API(void) +JSD_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_PROPERTY(jsdprop); + jsd_DropProperty(jsdc, jsdprop); +} + + +JSD_PUBLIC_API(JSDValue*) +JSD_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_PROPERTY(jsdprop); + return jsd_GetPropertyName(jsdc, jsdprop); +} + +JSD_PUBLIC_API(JSDValue*) +JSD_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_PROPERTY(jsdprop); + return jsd_GetPropertyValue(jsdc, jsdprop); +} + +JSD_PUBLIC_API(JSDValue*) +JSD_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_PROPERTY(jsdprop); + return jsd_GetPropertyAlias(jsdc, jsdprop); +} + +JSD_PUBLIC_API(uintN) +JSD_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_PROPERTY(jsdprop); + return jsd_GetPropertyFlags(jsdc, jsdprop); +} + +JSD_PUBLIC_API(uintN) +JSD_GetPropertyVarArgSlot(JSDContext* jsdc, JSDProperty* jsdprop) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_PROPERTY(jsdprop); + return jsd_GetPropertyVarArgSlot(jsdc, jsdprop); +} + +/**************************************************/ +/* Object Functions */ + +JSD_PUBLIC_API(void) +JSD_LockObjectSubsystem(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_LOCK_OBJECTS(jsdc); +} + +JSD_PUBLIC_API(void) +JSD_UnlockObjectSubsystem(JSDContext* jsdc) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_UNLOCK_OBJECTS(jsdc); +} + +JSD_PUBLIC_API(JSDObject*) +JSD_IterateObjects(JSDContext* jsdc, JSDObject** iterp) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + return jsd_IterateObjects(jsdc, iterp); +} + +JSD_PUBLIC_API(JSObject*) +JSD_GetWrappedObject(JSDContext* jsdc, JSDObject* jsdobj) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_OBJECT(jsdobj); + return jsd_GetWrappedObject(jsdc, jsdobj); + +} + +JSD_PUBLIC_API(const char*) +JSD_GetObjectNewURL(JSDContext* jsdc, JSDObject* jsdobj) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_OBJECT(jsdobj); + return jsd_GetObjectNewURL(jsdc, jsdobj); +} + +JSD_PUBLIC_API(uintN) +JSD_GetObjectNewLineNumber(JSDContext* jsdc, JSDObject* jsdobj) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_OBJECT(jsdobj); + return jsd_GetObjectNewLineNumber(jsdc, jsdobj); +} + +JSD_PUBLIC_API(const char*) +JSD_GetObjectConstructorURL(JSDContext* jsdc, JSDObject* jsdobj) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_OBJECT(jsdobj); + return jsd_GetObjectConstructorURL(jsdc, jsdobj); +} + +JSD_PUBLIC_API(uintN) +JSD_GetObjectConstructorLineNumber(JSDContext* jsdc, JSDObject* jsdobj) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_OBJECT(jsdobj); + return jsd_GetObjectConstructorLineNumber(jsdc, jsdobj); +} + +JSD_PUBLIC_API(const char*) +JSD_GetObjectConstructorName(JSDContext* jsdc, JSDObject* jsdobj) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_OBJECT(jsdobj); + return jsd_GetObjectConstructorName(jsdc, jsdobj); +} + +JSD_PUBLIC_API(JSDObject*) +JSD_GetJSDObjectForJSObject(JSDContext* jsdc, JSObject* jsobj) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JS_ASSERT(jsobj); + return jsd_GetJSDObjectForJSObject(jsdc, jsobj); +} + +JSD_PUBLIC_API(JSDObject*) +JSD_GetObjectForValue(JSDContext* jsdc, JSDValue* jsdval) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_VALUE(jsdval); + return jsd_GetObjectForValue(jsdc, jsdval); +} + +JSD_PUBLIC_API(JSDValue*) +JSD_GetValueForObject(JSDContext* jsdc, JSDObject* jsdobj) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_OBJECT(jsdobj); + return jsd_GetValueForObject(jsdc, jsdobj); +} + +/***************************************************************************/ +/* Livewire specific API */ +#ifdef LIVEWIRE + +JSD_PUBLIC_API(LWDBGScript*) +JSDLW_GetLWScript(JSDContext* jsdc, JSDScript* jsdscript) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsdlw_GetLWScript(jsdc, jsdscript); +} + +JSD_PUBLIC_API(JSDSourceText*) +JSDLW_PreLoadSource( JSDContext* jsdc, LWDBGApp* app, + const char* filename, JSBool clear ) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JS_ASSERT(app); + JS_ASSERT(filename); + return jsdlw_PreLoadSource(jsdc, app, filename, clear); +} + +JSD_PUBLIC_API(JSDSourceText*) +JSDLW_ForceLoadSource( JSDContext* jsdc, JSDSourceText* jsdsrc ) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SOURCE_TEXT(jsdsrc); + return jsdlw_ForceLoadSource(jsdc, jsdsrc); +} + +JSD_PUBLIC_API(JSBool) +JSDLW_RawToProcessedLineNumber(JSDContext* jsdc, JSDScript* jsdscript, + uintN lineIn, uintN* lineOut) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsdlw_RawToProcessedLineNumber(jsdc, jsdscript, lineIn, lineOut); +} + +JSD_PUBLIC_API(JSBool) +JSDLW_ProcessedToRawLineNumber(JSDContext* jsdc, JSDScript* jsdscript, + uintN lineIn, uintN* lineOut) +{ + JSD_ASSERT_VALID_CONTEXT(jsdc); + JSD_ASSERT_VALID_SCRIPT(jsdscript); + return jsdlw_ProcessedToRawLineNumber(jsdc, jsdscript, lineIn, lineOut); +} + +#endif +/***************************************************************************/ diff --git a/js/jsd/jsdebug.h b/js/jsd/jsdebug.h new file mode 100644 index 0000000..5e597c9 --- /dev/null +++ b/js/jsd/jsdebug.h @@ -0,0 +1,1577 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Header for JavaScript Debugging support - All public functions + */ + +#ifndef jsdebug_h___ +#define jsdebug_h___ + +/* Get jstypes.h included first. After that we can use PR macros for doing +* this extern "C" stuff! +*/ +#ifdef __cplusplus +extern "C" +{ +#endif +#include "jstypes.h" +#ifdef __cplusplus +} +#endif + +#include "jsapi.h" +#include "jsdbgapi.h" +#ifdef LIVEWIRE +#include "lwdbgapi.h" +#endif + +JS_BEGIN_EXTERN_C + +/* + * The linkage of JSD API functions differs depending on whether the file is + * used within the JSD library or not. Any source file within the JSD + * libraray should define EXPORT_JSD_API whereas any client of the library + * should not. + */ +#ifdef EXPORT_JSD_API +#define JSD_PUBLIC_API(t) JS_EXPORT_API(t) +#define JSD_PUBLIC_DATA(t) JS_EXPORT_DATA(t) +#else +#define JSD_PUBLIC_API(t) JS_IMPORT_API(t) +#define JSD_PUBLIC_DATA(t) JS_IMPORT_DATA(t) +#endif + +#define JSD_FRIEND_API(t) JSD_PUBLIC_API(t) +#define JSD_FRIEND_DATA(t) JSD_PUBLIC_DATA(t) + +/***************************************************************************/ +/* Opaque typedefs for handles */ + +typedef struct JSDContext JSDContext; +typedef struct JSDScript JSDScript; +typedef struct JSDSourceText JSDSourceText; +typedef struct JSDThreadState JSDThreadState; +typedef struct JSDStackFrameInfo JSDStackFrameInfo; +typedef struct JSDValue JSDValue; +typedef struct JSDProperty JSDProperty; +typedef struct JSDObject JSDObject; + +/***************************************************************************/ +/* High Level calls */ + +/* +* callback stuff for calls in EXE to be accessed by this code +* when it lives in an explicitly loaded DLL +*/ + +/* +* This callback allows JSD to inform the embedding when JSD has been +* turned on or off. This is especially useful in the Java-based debugging +* system used in mozilla because the debugger applet controls starting +* up the JSD system. +*/ +typedef void +(* JSD_SetContextProc)(JSDContext* jsdc, void* user); + +/* This struct could have more fields in future versions */ +typedef struct +{ + uintN size; /* size of this struct (init before use)*/ + JSD_SetContextProc setContext; +} JSD_UserCallbacks; + +/* +* Used by an embedding to tell JSD what JSRuntime to use and to set +* callbacks without starting up JSD. This assumes only one JSRuntime +* will be used. This exists to support the mozilla Java-based debugger +* system. +*/ +extern JSD_PUBLIC_API(void) +JSD_SetUserCallbacks(JSRuntime* jsrt, + JSD_UserCallbacks* callbacks, + void* user); + +/* +* Startup JSD. +* This version of the init function requires that JSD_SetUserCallbacks() +* has been previously called (with a non-NULL callback struct pointer) +*/ +extern JSD_PUBLIC_API(JSDContext*) +JSD_DebuggerOn(void); + +/* +* Startup JSD on a particular JSRuntime with (optional) callbacks +*/ +extern JSD_PUBLIC_API(JSDContext*) +JSD_DebuggerOnForUser(JSRuntime* jsrt, + JSD_UserCallbacks* callbacks, + void* user); + +/* + * Startup JSD in an application that uses compartments. Debugger + * objects will be allocated in the same compartment as scopeobj. + */ +extern JSD_PUBLIC_API(JSDContext*) +JSD_DebuggerOnForUserWithCompartment(JSRuntime* jsrt, + JSD_UserCallbacks* callbacks, + void* user, + JSObject* scopeobj); + +/* +* Shutdown JSD for this JSDContext +*/ +extern JSD_PUBLIC_API(void) +JSD_DebuggerOff(JSDContext* jsdc); + +/* + * Pause JSD for this JSDContext + */ +extern JSD_PUBLIC_API(void) +JSD_DebuggerPause(JSDContext* jsdc); + +/* + * Unpause JSD for this JSDContext + */ +extern JSD_PUBLIC_API(void) +JSD_DebuggerUnpause(JSDContext* jsdc); + +/* +* Get the Major Version (initial JSD release used major version = 1) +*/ +extern JSD_PUBLIC_API(uintN) +JSD_GetMajorVersion(void); + +/* +* Get the Minor Version (initial JSD release used minor version = 0) +*/ +extern JSD_PUBLIC_API(uintN) +JSD_GetMinorVersion(void); + +/* +* Returns a 'dumb' JSContext that can be used for utility purposes as needed +*/ +extern JSD_PUBLIC_API(JSContext*) +JSD_GetDefaultJSContext(JSDContext* jsdc); + +/* +* Set the private data for this context, returns previous value +*/ +extern JSD_PUBLIC_API(void *) +JSD_SetContextPrivate(JSDContext *jsdc, void *data); + +/* +* Get the private data for this context +*/ +extern JSD_PUBLIC_API(void *) +JSD_GetContextPrivate(JSDContext *jsdc); + +/* +* Clear profile data for all scripts +*/ +extern JSD_PUBLIC_API(void) +JSD_ClearAllProfileData(JSDContext* jsdc); + +/* +* Context flags. +*/ + +/* Include native frames in JSDThreadStates. */ +#define JSD_INCLUDE_NATIVE_FRAMES 0x01 +/* +* Normally, if a script has a 0 in JSD_SCRIPT_PROFILE_BIT it is included in +* profile data, otherwise it is not profiled. Setting the JSD_PROFILE_WHEN_SET +* flag reverses this convention. +*/ +#define JSD_PROFILE_WHEN_SET 0x02 +/* +* Normally, when the script in the top frame of a thread state has a 1 in +* JSD_SCRIPT_DEBUG_BIT, the execution hook is ignored. Setting the +* JSD_DEBUG_WHEN_SET flag reverses this convention. +*/ +#define JSD_DEBUG_WHEN_SET 0x04 +/* +* When this flag is set the internal call hook will collect profile data. +*/ +#define JSD_COLLECT_PROFILE_DATA 0x08 +/* +* When this flag is set, stack frames that are disabled for debugging +* will not appear in the call stack chain. +*/ +#define JSD_HIDE_DISABLED_FRAMES 0x10 +/* +* When this flag is set, the debugger will only check the +* JSD_SCRIPT_DEBUG_BIT on the top (most recent) stack frame. This +* makes it possible to stop in an enabled frame which was called from +* a stack that contains a disabled frame. +* +* When this flag is *not* set, any stack that contains a disabled frame +* will not be debugged (the execution hook will not be invoked.) +* +* This only applies when the reason for calling the hook would have +* been JSD_HOOK_INTERRUPTED or JSD_HOOK_THROW. JSD_HOOK_BREAKPOINT, +* JSD_HOOK_DEBUG_REQUESTED, and JSD_HOOK_DEBUGGER_KEYWORD always stop, +* regardless of this setting, as long as the top frame is not disabled. +* +* If JSD_HIDE_DISABLED_FRAMES is set, this is effectively set as well. +*/ +#define JSD_MASK_TOP_FRAME_ONLY 0x20 + +/* +* 0x40 was formerly used to hook into object creation. +*/ +#define JSD_DISABLE_OBJECT_TRACE_RETIRED 0x40 + + +extern JSD_PUBLIC_API(void) +JSD_SetContextFlags (JSDContext* jsdc, uint32 flags); + +extern JSD_PUBLIC_API(uint32) +JSD_GetContextFlags (JSDContext* jsdc); + +/* +* Notify JSD that this JSContext is 'in use'. This allows JSD to hook the +* ErrorReporter. For the most part this is done automatically whenever +* events like script loading happen. But, it is a good idea to call this +* from the embedding when new contexts come into use. +*/ +extern JSD_PUBLIC_API(void) +JSD_JSContextInUse(JSDContext* jsdc, JSContext* context); + +/* +* Find the JSDContext (if any) associated with the JSRuntime of a +* given JSContext. +*/ +extern JSD_PUBLIC_API(JSDContext*) +JSD_JSDContextForJSContext(JSContext* context); + +/***************************************************************************/ +/* Script functions */ + +/* +* Lock the entire script subsystem. This grabs a highlevel lock that +* protects the JSD internal information about scripts. It is important +* to wrap script related calls in this lock in multithreaded situations +* -- i.e. where the debugger is running on a different thread than the +* interpreter -- or when multiple debugger threads may be accessing this +* subsystem. It is safe (and best) to use this locking even if the +* environment might not be multi-threaded. Safely nestable. +*/ +extern JSD_PUBLIC_API(void) +JSD_LockScriptSubsystem(JSDContext* jsdc); + +/* +* Unlock the entire script subsystem -- see JSD_LockScriptSubsystem +*/ +extern JSD_PUBLIC_API(void) +JSD_UnlockScriptSubsystem(JSDContext* jsdc); + +/* +* Iterate through all the active scripts for this JSDContext. +* NOTE: must initialize iterp to NULL to start iteration. +* NOTE: must lock and unlock the subsystem +* example: +* +* JSDScript jsdscript; +* JSDScript iter = NULL; +* +* JSD_LockScriptSubsystem(jsdc); +* while((jsdscript = JSD_IterateScripts(jsdc, &iter)) != NULL) { +* *** use jsdscript here *** +* } +* JSD_UnlockScriptSubsystem(jsdc); +*/ +extern JSD_PUBLIC_API(JSDScript*) +JSD_IterateScripts(JSDContext* jsdc, JSDScript **iterp); + +/* +* Get the number of times this script has been called. +*/ +extern JSD_PUBLIC_API(uintN) +JSD_GetScriptCallCount(JSDContext* jsdc, JSDScript *script); + +/* +* Get the max number of times this script called itself, directly or indirectly. +*/ +extern JSD_PUBLIC_API(uintN) +JSD_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script); + +/* +* Get the shortest execution time recorded. +*/ +extern JSD_PUBLIC_API(jsdouble) +JSD_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script); + +/* +* Get the longest execution time recorded. +*/ +extern JSD_PUBLIC_API(jsdouble) +JSD_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script); + +/* +* Get the total amount of time spent in this script. +*/ +extern JSD_PUBLIC_API(jsdouble) +JSD_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script); + +/* +* Get the shortest execution time recorded, excluding time spent in called +* functions. +*/ +extern JSD_PUBLIC_API(jsdouble) +JSD_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script); + +/* +* Get the longest execution time recorded, excluding time spent in called +* functions. +*/ +extern JSD_PUBLIC_API(jsdouble) +JSD_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script); + +/* +* Get the total amount of time spent in this script, excluding time spent +* in called functions. +*/ +extern JSD_PUBLIC_API(jsdouble) +JSD_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script); + +/* +* Clear profile data for this script. +*/ +extern JSD_PUBLIC_API(void) +JSD_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script); + +/* +* Get the JSScript for a JSDScript +*/ +extern JSD_PUBLIC_API(JSScript*) +JSD_GetJSScript(JSDContext* jsdc, JSDScript *script); + +/* +* Get the JSFunction for a JSDScript +*/ +extern JSD_PUBLIC_API(JSFunction*) +JSD_GetJSFunction(JSDContext* jsdc, JSDScript *script); + +/* +* Determines whether or not to collect profile information for this +* script. The context flag JSD_PROFILE_WHEN_SET decides the logic. +*/ +#define JSD_SCRIPT_PROFILE_BIT 0x01 +/* +* Determines whether or not to ignore breakpoints, etc. in this script. +* The context flag JSD_DEBUG_WHEN_SET decides the logic. +*/ +#define JSD_SCRIPT_DEBUG_BIT 0x02 + +extern JSD_PUBLIC_API(uint32) +JSD_GetScriptFlags(JSDContext *jsdc, JSDScript* jsdscript); + +extern JSD_PUBLIC_API(void) +JSD_SetScriptFlags(JSDContext *jsdc, JSDScript* jsdscript, uint32 flags); + +/* +* Set the private data for this script, returns previous value +*/ +extern JSD_PUBLIC_API(void *) +JSD_SetScriptPrivate(JSDScript* jsdscript, void *data); + +/* +* Get the private data for this script +*/ +extern JSD_PUBLIC_API(void *) +JSD_GetScriptPrivate(JSDScript* jsdscript); + +/* +* Determine if this script is still loaded in the interpreter +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript); + +/* +* Get the filename associated with this script +*/ +extern JSD_PUBLIC_API(const char*) +JSD_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript); + +/* +* Get the function name associated with this script (NULL if not a function). +* If the function does not have a name the result is the string "anonymous". +* *** new for gecko 2.0 **** +*/ +extern JSD_PUBLIC_API(JSString *) +JSD_GetScriptFunctionId(JSDContext* jsdc, JSDScript *jsdscript); + +/* +* Get the base linenumber of the sourcefile from which this script was loaded. +* This is one-based -- i.e. the first line of a file is line '1'. This may +* return 0 if this infomation is unknown. +*/ +extern JSD_PUBLIC_API(uintN) +JSD_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript); + +/* +* Get the count of source lines associated with this script (1 or greater) +*/ +extern JSD_PUBLIC_API(uintN) +JSD_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript); + +/* +* Declaration of callback for notification of script creation and destruction. +* 'creating' is JS_TRUE if creating new script, JS_FALSE if destroying existing +* script (callback called just before actual destruction). +* 'callerdata' is what was passed to JSD_SetScriptHook to set the hook. +*/ +typedef void +(* JSD_ScriptHookProc)(JSDContext* jsdc, + JSDScript* jsdscript, + JSBool creating, + void* callerdata); + +/* +* Set a hook to be called when scripts are created or destroyed (loaded or +* unloaded). +* 'callerdata' can be whatever you want it to be. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata); + +/* +* Get the current script hook. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata); + +/* +* Get a 'Program Counter' value for a given line. This represents the location +* of the first bit of executable code for this line of source. This 'pc' should +* be considered an opaque handle. +* 0 is returned for invalid scripts, or lines that lie outside the script. +* If no code is on the given line, then the returned pc represents the first +* code within the script (if any) after the given line. +* This function can be used to set breakpoints -- see JSD_SetExecutionHook +*/ +extern JSD_PUBLIC_API(jsuword) +JSD_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line); + +/* +* Get the source line number for a given 'Program Counter' location. +* Returns 0 if no source line information is appropriate (or available) for +* the given pc. +*/ +extern JSD_PUBLIC_API(uintN) +JSD_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc); + +/* these are only used in cases where scripts are created outside of JS*/ + +/* +* Direct call to notify JSD that a script has been created. +* Embeddings that use the normal jsapi script functions need not call this. +* Any embedding that follows the (discouraged!) practice of contructing script +* structures manually should call this function to inform JSD. (older ssjs +* systems do this). +*/ +extern JSD_PUBLIC_API(void) +JSD_ScriptCreated(JSDContext* jsdc, + JSContext *cx, + const char *filename, /* URL this script loads from */ + uintN lineno, /* line where this script starts */ + JSScript *script, + JSFunction *fun); + +/* +* see JSD_ScriptCreated +*/ +extern JSD_PUBLIC_API(void) +JSD_ScriptDestroyed(JSDContext* jsdc, + JSContext *cx, + JSScript *script); + +/***************************************************************************/ +/* Source Text functions */ + +/* +* In some embeddings (e.g. mozilla) JavaScript source code from a 'file' may be +* execute before the entire 'file' has even been loaded. This system supports +* access to such incrmentally loaded source. It also allows for the possibility +* that source loading may fail or be aborted (though the source that did load +* may still be usable). Remember that this source is the entire 'file' +* contents and that the JavaScript code may only be part of that source. +* +* For any given URL there can only be one source text item (the most recently +* loaded). +*/ + +/* these coorespond to netscape.jsdebug.SourceTextItem.java values - +* change in both places if anywhere +*/ + +typedef enum +{ + JSD_SOURCE_INITED = 0, /* initialized, but contains no source yet */ + JSD_SOURCE_PARTIAL = 1, /* some source loaded, more expected */ + JSD_SOURCE_COMPLETED = 2, /* all source finished loading */ + JSD_SOURCE_ABORTED = 3, /* user aborted loading, some may be loaded */ + JSD_SOURCE_FAILED = 4, /* loading failed, some may be loaded */ + JSD_SOURCE_CLEARED = 5 /* text has been cleared by debugger */ +} JSDSourceStatus; + +/* +* Lock the entire source text subsystem. This grabs a highlevel lock that +* protects the JSD internal information about sources. It is important to +* wrap source text related calls in this lock in multithreaded situations +* -- i.e. where the debugger is running on a different thread than the +* interpreter (or the loader of sources) -- or when multiple debugger +* threads may be accessing this subsystem. It is safe (and best) to use +* this locking even if the environment might not be multi-threaded. +* Safely Nestable. +*/ +extern JSD_PUBLIC_API(void) +JSD_LockSourceTextSubsystem(JSDContext* jsdc); + +/* +* Unlock the entire source text subsystem. see JSD_LockSourceTextSubsystem. +*/ +extern JSD_PUBLIC_API(void) +JSD_UnlockSourceTextSubsystem(JSDContext* jsdc); + +/* +* Iterate the source test items. Use the same pattern of calls shown in +* the example for JSD_IterateScripts - NOTE that the SourceTextSubsystem. +* must be locked before and unlocked after iterating. +*/ +extern JSD_PUBLIC_API(JSDSourceText*) +JSD_IterateSources(JSDContext* jsdc, JSDSourceText **iterp); + +/* +* Find the source text item for the given URL (or filename - or whatever +* string the given embedding uses to describe source locations). +* Returns NULL is not found. +*/ +extern JSD_PUBLIC_API(JSDSourceText*) +JSD_FindSourceForURL(JSDContext* jsdc, const char* url); + +/* +* Get the URL string associated with the given source text item +*/ +extern JSD_PUBLIC_API(const char*) +JSD_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc); + +/* +* Get the actual source text. This gives access to the actual storage of +* the source - it sHould *not* be written to. +* The buffer is NOT zero terminated (nor is it guaranteed to have space to +* hold a zero terminating char). +* XXX this is 8-bit character data. Unicode source is not yet supported. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc, + const char** ppBuf, intN* pLen); + +/* +* Clear the text -- delete the text and set the status to JSD_SOURCE_CLEARED. +* This is useful if source is done loading and the debugger wishes to store +* the text data itself (e.g. in a Java String). This allows avoidance of +* storing the same text in multiple places. +*/ +extern JSD_PUBLIC_API(void) +JSD_ClearSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc); + +/* +* Return the status of the source text item. see JSDSourceStatus enum. +*/ +extern JSD_PUBLIC_API(JSDSourceStatus) +JSD_GetSourceStatus(JSDContext* jsdc, JSDSourceText* jsdsrc); + +/* +* Has the source been altered since the last call to JSD_SetSourceDirty? +* Use of JSD_IsSourceDirty and JSD_SetSourceDirty is still supported, but +* discouraged in favor of the JSD_GetSourceAlterCount system. This dirty +* scheme ASSUMES that there is only one consumer of the data. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc); + +/* +* Clear the dirty flag +*/ +extern JSD_PUBLIC_API(void) +JSD_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, JSBool dirty); + +/* +* Each time a source text item is altered this value is incremented. Any +* consumer can store this value when they retieve other data about the +* source text item and then check later to see if the current value is +* different from their stored value. Thus they can know if they have stale +* data or not. NOTE: this value is not gauranteed to start at any given number. +*/ +extern JSD_PUBLIC_API(uintN) +JSD_GetSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc); + +/* +* Force an increment in the alter count for a source text item. This is +* normally automatic when the item changes, but a give consumer may want to +* force this to amke an item appear to have changed even if it has not. +*/ +extern JSD_PUBLIC_API(uintN) +JSD_IncrementSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc); + +/* +* Destroy *all* the source text items +* (new for server-side USE WITH CARE) +*/ +extern JSD_PUBLIC_API(void) +JSD_DestroyAllSources( JSDContext* jsdc ); + +/* functions for adding source items */ + +/* +* Add a new item for a given URL. If an iten already exists for the given URL +* then the old item is removed. +* 'url' may not be NULL. +*/ +extern JSD_PUBLIC_API(JSDSourceText*) +JSD_NewSourceText(JSDContext* jsdc, const char* url); + +/* +* Append text (or change status -- e.g. set completed) for a source text +* item. Text need not be zero terminated. Callers should consider the returned +* JSDSourceText to be the 'current' item for future use. This may return NULL +* if called after this item has been replaced by a call to JSD_NewSourceText. +*/ +extern JSD_PUBLIC_API(JSDSourceText*) +JSD_AppendSourceText(JSDContext* jsdc, + JSDSourceText* jsdsrc, + const char* text, /* *not* zero terminated */ + size_t length, + JSDSourceStatus status); + +/* +* Unicode varient of JSD_AppendSourceText. +* +* NOTE: At this point text is stored in 8bit ASCII so this function just +* extracts the bottom 8bits from each jschar. At some future point we may +* switch to storing and exposing 16bit Unicode. +*/ +extern JSD_PUBLIC_API(JSDSourceText*) +JSD_AppendUCSourceText(JSDContext* jsdc, + JSDSourceText* jsdsrc, + const jschar* text, /* *not* zero terminated */ + size_t length, + JSDSourceStatus status); +/* + * Convienence function for adding complete source of url in one call. + * same as: + * JSDSourceText* jsdsrc; + * JSD_LOCK_SOURCE_TEXT(jsdc); + * jsdsrc = jsd_NewSourceText(jsdc, url); + * if(jsdsrc) + * jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc, + * text, length, JSD_SOURCE_PARTIAL); + * if(jsdsrc) + * jsdsrc = jsd_AppendSourceText(jsdc, jsdsrc, + * NULL, 0, JSD_SOURCE_COMPLETED); + * JSD_UNLOCK_SOURCE_TEXT(jsdc); + * return jsdsrc ? JS_TRUE : JS_FALSE; + */ +extern JSD_PUBLIC_API(JSBool) +JSD_AddFullSourceText(JSDContext* jsdc, + const char* text, /* *not* zero terminated */ + size_t length, + const char* url); + +/***************************************************************************/ +/* Execution/Interrupt Hook functions */ + +/* possible 'type' params for JSD_ExecutionHookProc */ +#define JSD_HOOK_INTERRUPTED 0 +#define JSD_HOOK_BREAKPOINT 1 +#define JSD_HOOK_DEBUG_REQUESTED 2 +#define JSD_HOOK_DEBUGGER_KEYWORD 3 +#define JSD_HOOK_THROW 4 + +/* legal return values for JSD_ExecutionHookProc */ +#define JSD_HOOK_RETURN_HOOK_ERROR 0 +#define JSD_HOOK_RETURN_CONTINUE 1 +#define JSD_HOOK_RETURN_ABORT 2 +#define JSD_HOOK_RETURN_RET_WITH_VAL 3 +#define JSD_HOOK_RETURN_THROW_WITH_VAL 4 +#define JSD_HOOK_RETURN_CONTINUE_THROW 5 + +/* +* Implement a callback of this form in order to hook execution. +*/ +typedef uintN +(* JSD_ExecutionHookProc)(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + uintN type, + void* callerdata, + jsval* rval); + +/* possible 'type' params for JSD_CallHookProc */ +#define JSD_HOOK_TOPLEVEL_START 0 /* about to evaluate top level script */ +#define JSD_HOOK_TOPLEVEL_END 1 /* done evaluting top level script */ +#define JSD_HOOK_FUNCTION_CALL 2 /* about to call a function */ +#define JSD_HOOK_FUNCTION_RETURN 3 /* done calling function */ + +/* +* Implement a callback of this form in order to hook function call/returns. +* Return JS_TRUE from a TOPLEVEL_START or FUNCTION_CALL type call hook if you +* want to hear about the TOPLEVEL_END or FUNCTION_RETURN too. Return value is +* ignored to TOPLEVEL_END and FUNCTION_RETURN type hooks. +*/ +typedef JSBool +(* JSD_CallHookProc)(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + uintN type, + void* callerdata); + +/* +* Set Hook to be called whenever the given pc is about to be executed -- +* i.e. for 'trap' or 'breakpoint' +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_SetExecutionHook(JSDContext* jsdc, + JSDScript* jsdscript, + jsuword pc, + JSD_ExecutionHookProc hook, + void* callerdata); + +/* +* Clear the hook for this pc +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_ClearExecutionHook(JSDContext* jsdc, + JSDScript* jsdscript, + jsuword pc); + +/* +* Clear all the pc specific hooks for this script +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript); + +/* +* Clear all the pc specific hooks for the entire JSRuntime associated with +* this JSDContext +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_ClearAllExecutionHooks(JSDContext* jsdc); + +/* +* Set a hook to be called before the next instruction is executed. Depending +* on the threading situation and whether or not an JS code is currently +* executing the hook might be called before this call returns, or at some +* future time. The hook will continue to be called as each instruction +* executes until cleared. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_SetInterruptHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata); + +/* +* Call the interrupt hook at least once per source line +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript *jsdscript, JSBool enable); + +/* +* Clear the current interrupt hook. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_ClearInterruptHook(JSDContext* jsdc); + +/* +* Set the hook that should be called whenever a JSD_ErrorReporter hook +* returns JSD_ERROR_REPORTER_DEBUG. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_SetDebugBreakHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata); + +/* +* Clear the debug break hook +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_ClearDebugBreakHook(JSDContext* jsdc); + +/* +* Set the hook that should be called when the 'debugger' keyword is +* encountered by the JavaScript interpreter during execution. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_SetDebuggerHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata); + +/* +* Clear the 'debugger' keyword hook +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_ClearDebuggerHook(JSDContext* jsdc); + +/* +* Set the hook that should be called when a JS exception is thrown. +* NOTE: the 'do default' return value is: JSD_HOOK_RETURN_CONTINUE_THROW +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_SetThrowHook(JSDContext* jsdc, + JSD_ExecutionHookProc hook, + void* callerdata); +/* +* Clear the throw hook +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_ClearThrowHook(JSDContext* jsdc); + +/* +* Set the hook that should be called when a toplevel script begins or completes. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_SetTopLevelHook(JSDContext* jsdc, + JSD_CallHookProc hook, + void* callerdata); +/* +* Clear the toplevel call hook +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_ClearTopLevelHook(JSDContext* jsdc); + +/* +* Set the hook that should be called when a function call or return happens. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_SetFunctionHook(JSDContext* jsdc, + JSD_CallHookProc hook, + void* callerdata); +/* +* Clear the function call hook +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_ClearFunctionHook(JSDContext* jsdc); + +/***************************************************************************/ +/* Stack Frame functions */ + +/* +* Get the count of call stack frames for the given JSDThreadState +*/ +extern JSD_PUBLIC_API(uintN) +JSD_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate); + +/* +* Get the 'current' call stack frame for the given JSDThreadState +*/ +extern JSD_PUBLIC_API(JSDStackFrameInfo*) +JSD_GetStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate); + +/* +* Get the JSContext for the given JSDThreadState +*/ +extern JSD_PUBLIC_API(JSContext*) +JSD_GetJSContext(JSDContext* jsdc, JSDThreadState* jsdthreadstate); + +/* +* Get the calling call stack frame for the given frame +*/ +extern JSD_PUBLIC_API(JSDStackFrameInfo*) +JSD_GetCallingStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +/* +* Get the script for the given call stack frame +*/ +extern JSD_PUBLIC_API(JSDScript*) +JSD_GetScriptForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +/* +* Get the 'Program Counter' for the given call stack frame +*/ +extern JSD_PUBLIC_API(jsuword) +JSD_GetPCForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +/* +* Get the JavaScript Call Object for the given call stack frame. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDValue*) +JSD_GetCallObjectForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +/* +* Get the head of the scope chain for the given call stack frame. +* the chain can be traversed using JSD_GetValueParent. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDValue*) +JSD_GetScopeChainForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +/* +* Get the 'this' Object for the given call stack frame. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDValue*) +JSD_GetThisForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +/* +* Get the name of the function executing in this stack frame. Especially useful +* for native frames (without script objects.) +* *** new for gecko 2.0 **** +*/ +extern JSD_PUBLIC_API(JSString *) +JSD_GetIdForStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +/* +* True if stack frame represents a frame created as a result of a debugger +* evaluation. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsStackFrameDebugger(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +/* +* True if stack frame is constructing a new object. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsStackFrameConstructing(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe); + +/* +* Evaluate the given unicode source code in the context of the given stack frame. +* returns JS_TRUE and puts result in rval on success, JS_FALSE on failure. +* NOTE: The ErrorReporter hook might be called if this fails. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_EvaluateUCScriptInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + const jschar *bytes, uintN length, + const char *filename, uintN lineno, + jsval *rval); + +/* +* Same as above, but does not eat exceptions. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_AttemptUCScriptInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + const jschar *bytes, uintN length, + const char *filename, uintN lineno, + jsval *rval); + +/* single byte character version of JSD_EvaluateUCScriptInStackFrame */ +extern JSD_PUBLIC_API(JSBool) +JSD_EvaluateScriptInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + const char *bytes, uintN length, + const char *filename, uintN lineno, jsval *rval); + +/* +* Same as above, but does not eat exceptions. +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_AttemptScriptInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + const char *bytes, uintN length, + const char *filename, uintN lineno, jsval *rval); + +/* +* Convert the given jsval to a string +* NOTE: The ErrorReporter hook might be called if this fails. +*/ +extern JSD_PUBLIC_API(JSString*) +JSD_ValToStringInStackFrame(JSDContext* jsdc, + JSDThreadState* jsdthreadstate, + JSDStackFrameInfo* jsdframe, + jsval val); + +/* +* Get the JSDValue currently being thrown as an exception (may be NULL). +* NOTE: must eventually release by calling JSD_DropValue (if not NULL) +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDValue*) +JSD_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate); + +/* +* Set the JSDValue currently being thrown as an exception. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate, + JSDValue* jsdval); + +/***************************************************************************/ +/* Error Reporter functions */ + +/* +* XXX The ErrorReporter Hook scheme is going to change soon to more +* Fully support exceptions. +*/ + +/* legal return values for JSD_ErrorReporter */ +#define JSD_ERROR_REPORTER_PASS_ALONG 0 /* pass along to regular reporter */ +#define JSD_ERROR_REPORTER_RETURN 1 /* don't pass to error reporter */ +#define JSD_ERROR_REPORTER_DEBUG 2 /* force call to DebugBreakHook */ +#define JSD_ERROR_REPORTER_CLEAR_RETURN 3 /* clear exception and don't pass */ + +/* +* Implement a callback of this form in order to hook the ErrorReporter +*/ +typedef uintN +(* JSD_ErrorReporter)(JSDContext* jsdc, + JSContext* cx, + const char* message, + JSErrorReport* report, + void* callerdata); + +/* Set ErrorReporter hook */ +extern JSD_PUBLIC_API(JSBool) +JSD_SetErrorReporter(JSDContext* jsdc, + JSD_ErrorReporter reporter, + void* callerdata); + +/* Get Current ErrorReporter hook */ +extern JSD_PUBLIC_API(JSBool) +JSD_GetErrorReporter(JSDContext* jsdc, + JSD_ErrorReporter* reporter, + void** callerdata); + +/***************************************************************************/ +/* Generic locks that callers can use for their own purposes */ + +/* +* Is Locking and GetThread supported in this build? +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsLockingAndThreadIdSupported(); + +/* +* Create a reentrant/nestable lock +*/ +extern JSD_PUBLIC_API(void*) +JSD_CreateLock(); + +/* +* Aquire lock for this thread (or block until available). Increments a +* counter if this thread already owns the lock. +*/ +extern JSD_PUBLIC_API(void) +JSD_Lock(void* lock); + +/* +* Release lock for this thread (or decrement the counter if JSD_Lock +* was previous called more than once). +*/ +extern JSD_PUBLIC_API(void) +JSD_Unlock(void* lock); + +/* +* For debugging only if not (JS_THREADSAFE AND DEBUG) then returns JS_TRUE +* So JSD_IsLocked(lock) may not equal !JSD_IsUnlocked(lock) +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsLocked(void* lock); + +/* +* See above... +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsUnlocked(void* lock); + +/* +* return an ID uniquely identifying this thread. +*/ +extern JSD_PUBLIC_API(void*) +JSD_CurrentThread(); + +/***************************************************************************/ +/* Value and Property Functions --- All NEW for 1.1 --- */ + +/* +* NOTE: JSDValue and JSDProperty objects are reference counted. This allows +* for rooting these objects AND any underlying garbage collected jsvals. +* ALL JSDValue and JSDProperty objects returned by the functions below +* MUST eventually be released using the appropriate JSD_Dropxxx function. +*/ + +/* +* Create a new JSDValue to wrap the given jsval +* NOTE: must eventually release by calling JSD_DropValue (if not NULL) +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDValue*) +JSD_NewValue(JSDContext* jsdc, jsval val); + +/* +* Release the JSDValue. After this call the object MUST not be referenced again! +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(void) +JSD_DropValue(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Get the jsval wrapped by this JSDValue +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(jsval) +JSD_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Clear all property and association information about the given JSDValue. +* Such information will be lazily regenerated when later accessed. This +* function must be called to make changes to the properties of an object +* visible to the accessor functions below (if the properties et.al. have +* changed since a previous call to those accessors). +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(void) +JSD_RefreshValue(JSDContext* jsdc, JSDValue* jsdval); + +/**************************************************/ + +/* +* Does the JSDValue wrap a JSObject? +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsValueObject(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Does the JSDValue wrap a number (int or double)? +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Does the JSDValue wrap an int? +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsValueInt(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Does the JSDValue wrap a double? +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Does the JSDValue wrap a JSString? +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsValueString(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Does the JSDValue wrap a JSBool? +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Does the JSDValue wrap a JSVAL_NULL? +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsValueNull(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Does the JSDValue wrap a JSVAL_VOID? +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Does the JSDValue wrap a primative (not a JSObject)? +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Does the JSDValue wrap a function? +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Does the JSDValue wrap a native function? +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_IsValueNative(JSDContext* jsdc, JSDValue* jsdval); + +/**************************************************/ + +/* +* Return JSBool value (does NOT do conversion). +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSBool) +JSD_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Return int32 value (does NOT do conversion). +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(int32) +JSD_GetValueInt(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Return double value (does NOT do conversion). +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(jsdouble) +JSD_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Return JSString value (DOES do conversion if necessary). +* NOTE that the JSString returned is not protected from garbage +* collection. It should be immediately read or wrapped using +* JSD_NewValue(jsdc,STRING_TO_JSVAL(str)) if necessary. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSString*) +JSD_GetValueString(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Return name of function IFF JSDValue represents a function. +* *** new for gecko 2.0 **** +*/ +extern JSD_PUBLIC_API(JSString *) +JSD_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Return function object IFF JSDValue represents a function or an object +* wrapping a function. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSFunction*) +JSD_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval); + +/**************************************************/ + +/* +* Return the number of properties for the JSDValue. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(uintN) +JSD_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Iterate through the properties of the JSDValue. +* Use form similar to that shown for JSD_IterateScripts (no locking required). +* NOTE: each JSDProperty returned must eventually be released by calling +* JSD_DropProperty. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDProperty*) +JSD_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp); + +/* +* Get the JSDProperty for the property of this JSDVal with this name. +* NOTE: must eventually release by calling JSD_DropProperty (if not NULL) +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDProperty*) +JSD_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name); + +/* +* Get the prototype object for this JSDValue. +* NOTE: must eventually release by calling JSD_DropValue (if not NULL) +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDValue*) +JSD_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Get the parent object for this JSDValue. +* NOTE: must eventually release by calling JSD_DropValue (if not NULL) +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDValue*) +JSD_GetValueParent(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Get the ctor object for this JSDValue (or likely its prototype's ctor). +* NOTE: must eventually release by calling JSD_DropValue (if not NULL) +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDValue*) +JSD_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Get the name of the class for this object. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(const char*) +JSD_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Get the script for the given value if the given value represents a +* scripted function. Otherwise, return null. +*/ +extern JSD_PUBLIC_API(JSDScript*) +JSD_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval); + +/**************************************************/ + +/* possible or'd together bitflags returned by JSD_GetPropertyFlags + * + * XXX these must stay the same as the JSPD_ flags in jsdbgapi.h + */ +#define JSDPD_ENUMERATE JSPD_ENUMERATE /* visible to for/in loop */ +#define JSDPD_READONLY JSPD_READONLY /* assignment is error */ +#define JSDPD_PERMANENT JSPD_PERMANENT /* property cannot be deleted */ +#define JSDPD_ALIAS JSPD_ALIAS /* property has an alias id */ +#define JSDPD_ARGUMENT JSPD_ARGUMENT /* argument to function */ +#define JSDPD_VARIABLE JSPD_VARIABLE /* local variable in function */ +#define JSDPD_EXCEPTION JSPD_EXCEPTION /* exception occurred looking up */ + /* proprety, value is exception */ +#define JSDPD_ERROR JSPD_ERROR /* native getter returned JS_FALSE */ + /* without throwing an exception */ +/* this is not one of the JSPD_ flags in jsdbgapi.h - careful not to overlap*/ +#define JSDPD_HINTED 0x800 /* found via explicit lookup */ + +/* +* Release this JSDProperty +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(void) +JSD_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop); + +/* +* Get the JSDValue represeting the name of this property (int or string) +* NOTE: must eventually release by calling JSD_DropValue +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDValue*) +JSD_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop); + +/* +* Get the JSDValue represeting the current value of this property +* NOTE: must eventually release by calling JSD_DropValue (if not NULL) +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDValue*) +JSD_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop); + +/* +* Get the JSDValue represeting the alias of this property (if JSDPD_ALIAS set) +* NOTE: must eventually release by calling JSD_DropValue (if not NULL) +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDValue*) +JSD_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop); + +/* +* Get the flags for this property +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(uintN) +JSD_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop); + +/* +* Get Variable or Argument slot number (if JSDPD_ARGUMENT or JSDPD_VARIABLE set) +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(uintN) +JSD_GetPropertyVarArgSlot(JSDContext* jsdc, JSDProperty* jsdprop); + +/***************************************************************************/ +/* Object Functions --- All NEW for 1.1 --- */ + +/* +* JSDObjects exist to allow a means of iterating through all JSObjects in the +* engine. They are created and destroyed as the wrapped JSObjects are created +* and destroyed in the engine. JSDObjects additionally track the location in +* the JavaScript source where their wrapped JSObjects were created and the name +* and location of the (non-native) constructor used. +* +* NOTE: JSDObjects are NOT reference counted. The have only weak links to +* jsObjects - thus they do not inhibit garbage collection of JSObjects. If +* you need a JSDObject to safely persist then wrap it in a JSDValue (using +* jsd_GetValueForObject). +*/ + +/* +* Lock the entire Object subsystem -- see JSD_UnlockObjectSubsystem +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(void) +JSD_LockObjectSubsystem(JSDContext* jsdc); + +/* +* Unlock the entire Object subsystem -- see JSD_LockObjectSubsystem +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(void) +JSD_UnlockObjectSubsystem(JSDContext* jsdc); + +/* +* Iterate through the known objects +* Use form similar to that shown for JSD_IterateScripts. +* NOTE: the ObjectSubsystem must be locked before and unlocked after iterating. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDObject*) +JSD_IterateObjects(JSDContext* jsdc, JSDObject** iterp); + +/* +* Get the JSObject represented by this JSDObject +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSObject*) +JSD_GetWrappedObject(JSDContext* jsdc, JSDObject* jsdobj); + +/* +* Get the URL of the line of source that caused this object to be created. +* May be NULL. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(const char*) +JSD_GetObjectNewURL(JSDContext* jsdc, JSDObject* jsdobj); + +/* +* Get the line number of the line of source that caused this object to be +* created. May be 0 indicating that the line number is unknown. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(uintN) +JSD_GetObjectNewLineNumber(JSDContext* jsdc, JSDObject* jsdobj); + +/* +* Get the URL of the line of source of the constructor for this object. +* May be NULL. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(const char*) +JSD_GetObjectConstructorURL(JSDContext* jsdc, JSDObject* jsdobj); + +/* +* Get the line number of the line of source of the constructor for this object. +* created. May be 0 indicating that the line number is unknown. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(uintN) +JSD_GetObjectConstructorLineNumber(JSDContext* jsdc, JSDObject* jsdobj); + +/* +* Get the name of the constructor for this object. +* May be NULL. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(const char*) +JSD_GetObjectConstructorName(JSDContext* jsdc, JSDObject* jsdobj); + +/* +* Get JSDObject representing this JSObject. +* May return NULL. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDObject*) +JSD_GetJSDObjectForJSObject(JSDContext* jsdc, JSObject* jsobj); + +/* +* Get JSDObject representing this JSDValue. +* May return NULL. +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDObject*) +JSD_GetObjectForValue(JSDContext* jsdc, JSDValue* jsdval); + +/* +* Create a JSDValue to wrap (and root) this JSDObject. +* NOTE: must eventually release by calling JSD_DropValue (if not NULL) +* *** new for version 1.1 **** +*/ +extern JSD_PUBLIC_API(JSDValue*) +JSD_GetValueForObject(JSDContext* jsdc, JSDObject* jsdobj); + +/***************************************************************************/ +/* Livewire specific API */ +#ifdef LIVEWIRE + +extern JSD_PUBLIC_API(LWDBGScript*) +JSDLW_GetLWScript(JSDContext* jsdc, JSDScript* jsdscript); + +extern JSD_PUBLIC_API(JSDSourceText*) +JSDLW_PreLoadSource(JSDContext* jsdc, LWDBGApp* app, + const char* filename, JSBool clear); + +extern JSD_PUBLIC_API(JSDSourceText*) +JSDLW_ForceLoadSource(JSDContext* jsdc, JSDSourceText* jsdsrc); + +extern JSD_PUBLIC_API(JSBool) +JSDLW_RawToProcessedLineNumber(JSDContext* jsdc, JSDScript* jsdscript, + uintN lineIn, uintN* lineOut); + +extern JSD_PUBLIC_API(JSBool) +JSDLW_ProcessedToRawLineNumber(JSDContext* jsdc, JSDScript* jsdscript, + uintN lineIn, uintN* lineOut); + +#endif +/***************************************************************************/ + +JS_END_EXTERN_C + +#endif /* jsdebug_h___ */ diff --git a/js/jsd/jsdstubs.c b/js/jsd/jsdstubs.c new file mode 100644 index 0000000..6741d45 --- /dev/null +++ b/js/jsd/jsdstubs.c @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* this is all going away... replaced by code in js/jsd/java */ + +#if 0 + +#include "_stubs/netscape_jsdebug_Script.c" +#include "_stubs/netscape_jsdebug_DebugController.c" +#include "_stubs/netscape_jsdebug_JSThreadState.c" +#include "_stubs/netscape_jsdebug_JSStackFrameInfo.c" +#include "_stubs/netscape_jsdebug_JSPC.c" +#include "_stubs/netscape_jsdebug_JSSourceTextProvider.c" + +#endif diff --git a/js/jsd/mkshell.bat b/js/jsd/mkshell.bat new file mode 100755 index 0000000..48a073f --- /dev/null +++ b/js/jsd/mkshell.bat @@ -0,0 +1,4 @@ +@echo off +REM nmake -f jsdshell.mak JSDEBUGGER_JAVA_UI=1 %1 %2 %3 %4 %5 +@echo on +nmake -f jsdshell.mak JSDEBUGGER_JAVA_UI=1 %1 %2 %3 %4 %5 diff --git a/js/jsd/resource.h b/js/jsd/resource.h new file mode 100644 index 0000000..4d2a9c2 --- /dev/null +++ b/js/jsd/resource.h @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by jsd3240.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/js/jsd/test/Makefile.in b/js/jsd/test/Makefile.in new file mode 100644 index 0000000..1142a0c --- /dev/null +++ b/js/jsd/test/Makefile.in @@ -0,0 +1,55 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +relativesrcdir = js/jsd/test + +include $(DEPTH)/config/autoconf.mk + +MODULE = jsdebug + +include $(topsrcdir)/config/rules.mk + +_TEST_FILES = test_bug507448.html bug507448.js \ + test_bug617870-callhooks.html test-bug617870-callhooks.js jsd-test.js \ + $(NULL) + +libs:: $(_TEST_FILES) + $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir) diff --git a/js/jsd/test/bug507448.js b/js/jsd/test/bug507448.js new file mode 100644 index 0000000..9ef2241 --- /dev/null +++ b/js/jsd/test/bug507448.js @@ -0,0 +1,25 @@ +netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + +function f() {} +function g(a,b) {} +function h(me, too, here) { var x = 1; } +function annoying(a, b, a, b, b, a) {} +function manyLocals(a, b, c, d, e, f, g, h, i, j, k, l, m) { + var n, o, p, q, r, s, t, u, v, w, x, y, z; +} + +assertArraysEqual(jsd.wrapValue(f).script.getParameterNames(), []); +assertArraysEqual(jsd.wrapValue(g).script.getParameterNames(), ["a", "b"]); +assertArraysEqual(jsd.wrapValue(h).script.getParameterNames(), ["me", "too", "here"]); +assertArraysEqual(jsd.wrapValue(annoying).script.getParameterNames(), + ["a", "b", "a", "b", "b", "a"]); +assertArraysEqual(jsd.wrapValue(manyLocals).script.getParameterNames(), + "abcdefghijklm".split("")); + +if (!jsdOnAtStart) { + // turn JSD off if it wasn't on when this test started + jsd.off(); + ok(!jsd.isOn, "JSD shouldn't be running at the end of this test."); +} + +SimpleTest.finish(); \ No newline at end of file diff --git a/js/jsd/test/jsd-test.js b/js/jsd/test/jsd-test.js new file mode 100644 index 0000000..cb6480c --- /dev/null +++ b/js/jsd/test/jsd-test.js @@ -0,0 +1,119 @@ +netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); +const Cc = Components.classes; +const Ci = Components.interfaces; +const RETURN_CONTINUE = Ci.jsdIExecutionHook.RETURN_CONTINUE; +const DebuggerService = Cc["@mozilla.org/js/jsd/debugger-service;1"]; + +var jsd = Components.classes['@mozilla.org/js/jsd/debugger-service;1'] + .getService(Ci.jsdIDebuggerService); +var jsdOnAtStart = false; + +function setupJSD(test) { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + jsdOnAtStart = jsd.isOn; + if (jsdOnAtStart) { + runTest(); + } else { + jsd.asyncOn({ onDebuggerActivated: function() { runTest(); } }); + } +} + +// Ugly workaround: when you turn the debugger on, it will only see scripts +// compiled after that point. And it may be turned on asynchronously. So +// we put the debugged code into a separate script that gets loaded after +// the debugger is on. +function loadScript(url, element) { + var script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = url; + script.defer = false; + element.appendChild(script); +} + +function findScriptByFunction(name) { + var script; + jsd.enumerateScripts({ enumerateScript: + function(script_) { + if (script_.functionName === name) { + script = script_; + } + } + }); + + if (typeof(script) === "undefined") { + throw("Cannot find function named '" + name + "'"); + } + + return script; +} + +// Pass in a JSD script +function breakOnAllLines(script) { + // Map each line to a PC, and collect that set of PCs (removing + // duplicates.) + var pcs = {}; + for (i = 0; i < script.lineExtent; i++) { + var jsdLine = script.baseLineNumber + i; + var pc = script.lineToPc(jsdLine, Ci.jsdIScript.PCMAP_SOURCETEXT); + pcs[pc] = 1; + } + + // Set a breakpoint on each of those PCs. + for (pc in pcs) { + try { + script.setBreakpoint(pc); + } catch(e) { + alert("Error setting breakpoint: " + e); + } + } +} + +// Set a breakpoint on a script, where lineno is relative to the beginning +// of the script (NOT the absolute line number within the file). +function breakOnLine(script, lineno) { + breakOnAbsoluteLine(script, script.baseLineNumber + lineno); +} + +function breakOnAbsoluteLine(script, lineno) { + var pc = script.lineToPc(lineno, Ci.jsdIScript.PCMAP_SOURCETEXT); + script.setBreakpoint(pc); +} + +function loadPage(page) { + var url; + if (page.match(/^\w+:/)) { + // Full URI, so just use it + url = page; + } else { + // Treat as relative to previous page + url = document.location.href.replace(/\/[^\/]*$/, "/" + page); + } + + dump("Switching to URL " + url + "\n"); + + gURLBar.value = url; + gURLBar.handleCommand(); +} + +function breakpointObserver(lines, interesting, callback) { + jsd.breakpointHook = { onExecute: function(frame, type, rv) { + breakpoints_hit.push(frame.line); + if (frame.line in interesting) { + return callback(frame, type, breakpoints_hit); + } else { + return RETURN_CONTINUE; + } + } }; +} + +function dumpStack(frame, msg) { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + dump(msg + ":\n"); + while(frame) { + var callee = frame.callee; + if (callee !== null) + callee = callee.jsClassName; + dump(" " + frame.script.fileName + ":" + frame.line + " func=" + frame.script.functionName + " ffunc=" + frame.functionName + " callee=" + callee + " pc=" + frame.pc + "\n"); + frame = frame.callingFrame; + } +} diff --git a/js/jsd/test/test-bug617870-callhooks.js b/js/jsd/test/test-bug617870-callhooks.js new file mode 100644 index 0000000..bfe97a3 --- /dev/null +++ b/js/jsd/test/test-bug617870-callhooks.js @@ -0,0 +1,52 @@ +g = { 'global noneval': 1 }; +netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + +eval("g['global eval'] = 1"); + +// Function to step through and set breakpoints on +function f1() { + g['function noneval'] = 1; + eval("g['function eval'] = 1"); + + x = 1; + for (y = 0; y < 10; y++) { + x++; + } + for (y = 0; y < 3; y++) { + x++; + } + z = 3; +} + +var f2 = new Function("g['function noneval'] = 2; eval(\"g['function eval'] = 2\")"); + +function testJSD(jsd) { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + ok(jsd.isOn, "JSD needs to be running for this test."); + + var numBreakpoints = 0; + + f1(); + f2(); + jsd.topLevelHook = null; + jsd.functionHook = null; + dump("numGlobalNonevals="+numGlobalNonevals+"\n"); + dump("numFunctionNonevals="+numFunctionNonevals+"\n"); + dump("numGlobalEvals="+numGlobalEvals+"\n"); + dump("numFunctionEvals="+numFunctionEvals+"\n"); + + ok(numFunctionNonevals == 3, "(fn) Should have hit f1(), testJSD(), and f2(); hit " + hits.fn); + ok(numGlobalNonevals == 1, "(gn) Overall script, hit " + hits.gn); + ok(numGlobalEvals == 1, "(ge) Eval in global area, hit " + hits.ge); + ok(numFunctionEvals == 2, "(fe) Evals within f1() and f2(), hit " + hits.fe); + + if (!jsdOnAtStart) { + // turn JSD off if it wasn't on when this test started + jsd.off(); + ok(!jsd.isOn, "JSD shouldn't be running at the end of this test."); + } + + SimpleTest.finish(); +} + +testJSD(jsd); diff --git a/js/jsd/test/test_bug507448.html b/js/jsd/test/test_bug507448.html new file mode 100644 index 0000000..54f87cc --- /dev/null +++ b/js/jsd/test/test_bug507448.html @@ -0,0 +1,110 @@ + + + + + Test for Bug 507448 + + + + + +Mozilla Bug 507448 +

+ +
+
+
+
+
+ + diff --git a/js/jsd/test/test_bug617870-callhooks.html b/js/jsd/test/test_bug617870-callhooks.html new file mode 100644 index 0000000..f0c4ee0 --- /dev/null +++ b/js/jsd/test/test_bug617870-callhooks.html @@ -0,0 +1,84 @@ + + + + + JSD Test for Bug AUTOFILLED + + + + + + + + + +

+ + + +
+
+ + + diff --git a/js/src/Makefile.in b/js/src/Makefile.in new file mode 100644 index 0000000..a85e055 --- /dev/null +++ b/js/src/Makefile.in @@ -0,0 +1,995 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = . +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ + +run_for_side_effects := $(shell echo "MAKE: $(MAKE)") +include $(DEPTH)/config/autoconf.mk + +DIRS = config + +ifdef DEHYDRA_PATH +DIRS += analysis-tests +endif + +ifdef JS_NATIVE_EDITLINE +DIRS += editline +endif + +# editline needs to get built before the shell +ifndef JS_DISABLE_SHELL +DIRS += shell +endif + +# FIXME: bug 515383 covers getting these working on wince +# bug 530688 covers Android +ifneq (,$(filter-out WINCE ANDROID,$(OS_ARCH))) +ifdef ENABLE_TESTS +DIRS += jsapi-tests +endif +endif + +ifdef ENABLE_TESTS +DIRS += tests +endif + +SRCREL_VERSION = 1.0.0 +SRCREL_ABI_VERSION := $(word 1,$(subst ., ,$(SRCREL_VERSION))).$(word 2,$(subst ., ,$(SRCREL_VERSION))) + +MODULE = js +ifeq (,$(HOST_BIN_SUFFIX)) +LIBRARY_NAME = mozjs185 +else +LIBRARY_NAME = mozjs185-$(SRCREL_ABI_VERSION) +endif +STATIC_LIBRARY_NAME = js_static +GRE_MODULE = 1 + +LIBS = $(NSPR_LIBS) + +ifdef GNU_CXX +ifdef INTEL_CXX +# icc gets special optimize flags +ifdef MOZ_PROFILE_GENERATE +MODULE_OPTIMIZE_FLAGS = -O0 +else +MODULE_OPTIMIZE_FLAGS = -O2 -ip +endif +else # not INTEL_CXX + +MODULE_OPTIMIZE_FLAGS = -O3 -fstrict-aliasing + +# We normally want -fomit-frame-pointer, but we want an explicit +# -fno-omit-frame-pointer if we're using a sampling profiler. +ifndef MOZ_PROFILING +MODULE_OPTIMIZE_FLAGS += -fomit-frame-pointer +else +MODULE_OPTIMIZE_FLAGS += -fno-omit-frame-pointer +endif + +endif +else # not GNU_CXX +ifeq ($(OS_ARCH),SunOS) +MODULE_OPTIMIZE_FLAGS = -xO4 +endif +ifeq ($(OS_ARCH),WINNT) +MODULE_OPTIMIZE_FLAGS = -O2 +endif +endif + + +# JavaScript must be built shared, even for static builds, as it is used by +# other modules which are always built shared. Failure to do so results in +# the js code getting copied into xpinstall and jsd as well as mozilla-bin, +# and then the static data cells used for locking no longer work. +# +# In fact, we now build both a static and a shared library, as the +# JS shell would like to link to the static library. + +ifdef JS_SHARED_LIBRARY +FORCE_SHARED_LIB = 1 +endif +FORCE_STATIC_LIB = 1 +DIST_INSTALL = 1 + +VPATH = $(srcdir) + +CPPSRCS = \ + jsanalyze.cpp \ + jsapi.cpp \ + jsarena.cpp \ + jsarray.cpp \ + jsatom.cpp \ + jsbool.cpp \ + jsclone.cpp \ + jscntxt.cpp \ + jscompartment.cpp \ + jsdate.cpp \ + jsdbgapi.cpp \ + jsdhash.cpp \ + jsdtoa.cpp \ + jsemit.cpp \ + jsexn.cpp \ + jsfriendapi.cpp \ + jsfun.cpp \ + jsgc.cpp \ + jsgcchunk.cpp \ + jsgcstats.cpp \ + jshash.cpp \ + jsinterp.cpp \ + jsinvoke.cpp \ + jsiter.cpp \ + jslock.cpp \ + jslog2.cpp \ + jsmath.cpp \ + jsnativestack.cpp \ + jsnum.cpp \ + jsobj.cpp \ + json.cpp \ + jsopcode.cpp \ + jsparse.cpp \ + jsproxy.cpp \ + jsprf.cpp \ + jsprobes.cpp \ + jspropertycache.cpp \ + jspropertytree.cpp \ + jsreflect.cpp \ + jsregexp.cpp \ + jsscan.cpp \ + jsscope.cpp \ + jsscript.cpp \ + jsstr.cpp \ + jstypedarray.cpp \ + jsutil.cpp \ + jswrapper.cpp \ + jsxdrapi.cpp \ + jsxml.cpp \ + prmjtime.cpp \ + sharkctl.cpp \ + $(NULL) + +INSTALLED_HEADERS = \ + js-config.h \ + jsautocfg.h \ + $(CURDIR)/jsautokw.h \ + js.msg \ + jsanalyze.h \ + jsapi.h \ + jsarray.h \ + jsarena.h \ + jsatom.h \ + jsbit.h \ + jsbool.h \ + jsclist.h \ + jsclone.h \ + jscntxt.h \ + jscompat.h \ + jsdate.h \ + jsdbgapi.h \ + jsdhash.h \ + jsdtoa.h \ + jsemit.h \ + jsfun.h \ + jsfriendapi.h \ + jsgc.h \ + jscell.h \ + jsgcchunk.h \ + jsgcstats.h \ + jscompartment.h \ + jshash.h \ + jsinterp.h \ + jsinttypes.h \ + jsiter.h \ + jslock.h \ + jslong.h \ + jsmath.h \ + jsobj.h \ + jsobjinlines.h \ + json.h \ + jsopcode.tbl \ + jsopcode.h \ + jsopcodeinlines.h \ + jsotypes.h \ + jsparse.h \ + jsproxy.h \ + jsprf.h \ + jsprobes.h \ + jspropertycache.h \ + jspropertycacheinlines.h \ + jspropertytree.h \ + jsproto.tbl \ + jsprvtd.h \ + jspubtd.h \ + jsreflect.h \ + jsregexp.h \ + jsscan.h \ + jsscope.h \ + jsscript.h \ + jsscriptinlines.h \ + jsstaticcheck.h \ + jsstdint.h \ + jsstr.h \ + jstracer.h \ + jshotloop.h \ + jstypedarray.h \ + jstypes.h \ + jsutil.h \ + jsvector.h \ + jstl.h \ + jshashtable.h \ + jsversion.h \ + jswrapper.h \ + jsxdrapi.h \ + jsxml.h \ + jsval.h \ + jsvalue.h \ + prmjtime.h \ + $(NULL) + +ifdef ENABLE_TRACEJIT +VPATH += \ + $(srcdir)/tracejit \ + $(srcdir)/nanojit \ + +INSTALLED_HEADERS += \ + jsbuiltins.h \ + Assembler.h \ + Allocator.h \ + CodeAlloc.h \ + Containers.h \ + LIR.h \ + LIRopcode.tbl \ + avmplus.h \ + Fragmento.h \ + Native.h \ + NativeCommon.h \ + Native$(NANOJIT_ARCH).h \ + njconfig.h \ + njcpudetect.h \ + RegAlloc.h \ + nanojit.h \ + VMPI.h \ + Writer.h \ + $(NULL) + +CPPSRCS += \ + jstracer.cpp \ + Assembler.cpp \ + Allocator.cpp \ + CodeAlloc.cpp \ + Containers.cpp \ + Fragmento.cpp \ + LIR.cpp \ + njconfig.cpp \ + RegAlloc.cpp \ + avmplus.cpp \ + Native$(NANOJIT_ARCH).cpp \ + jsbuiltins.cpp \ + VMPI.cpp \ + Writer.cpp \ + $(NULL) + +ifdef WINCE +# don't need -c +AS_DASH_C_FLAG = +ASFLAGS += -arch 6 +ASFILES += jswince.asm +endif + +endif # ENABLE_TRACEJIT +ifdef ENABLE_METHODJIT + +############################################### +# BEGIN include sources for the method JIT +# +VPATH += $(srcdir)/methodjit + +CPPSRCS += MethodJIT.cpp \ + StubCalls.cpp \ + Compiler.cpp \ + FrameState.cpp \ + FastArithmetic.cpp \ + FastOps.cpp \ + StubCompiler.cpp \ + MonoIC.cpp \ + PolyIC.cpp \ + ImmutableSync.cpp \ + InvokeHelpers.cpp \ + Retcon.cpp \ + TrampolineCompiler.cpp \ + $(NULL) +# PICStubCompiler.cpp \ + +ifeq (86, $(findstring 86,$(TARGET_CPU))) +ifeq (x86_64, $(TARGET_CPU)) +ifdef _MSC_VER +ASFILES += TrampolineMasmX64.asm +endif +ifdef SOLARIS_SUNPRO_CXX +ASFILES += TrampolineSUNWX64.s +endif +#CPPSRCS += only_on_x86_64.cpp +else +#CPPSRCS += only_on_x86.cpp +ifdef SOLARIS_SUNPRO_CXX +ASFILES += TrampolineSUNWX86.s +endif +endif +endif +ifeq (arm, $(TARGET_CPU)) +#CPPSRCS += only_on_arm.cpp +endif +# +# END enclude sources for the method JIT +############################################# + +endif + +############################################### +# BEGIN include sources for V8 dtoa +# +VPATH += $(srcdir)/v8-dtoa \ + $(NONE) + +CPPSRCS += checks.cc \ + conversions.cc \ + diy-fp.cc \ + v8-dtoa.cc \ + fast-dtoa.cc \ + platform.cc \ + utils.cc \ + $(NONE) + +# +# END enclude sources for V8 dtoa +############################################# + +ifeq (,$(filter-out powerpc sparc,$(TARGET_CPU))) + +VPATH += $(srcdir)/assembler \ + $(srcdir)/assembler/wtf \ + $(srcdir)/yarr/pcre \ + $(NULL) + +CPPSRCS += pcre_compile.cpp \ + pcre_exec.cpp \ + pcre_tables.cpp \ + pcre_xclass.cpp \ + pcre_ucp_searchfuncs.cpp \ + $(NULL) +else + +############################################### +# BEGIN include sources for the Nitro assembler +# +VPATH += $(srcdir)/assembler \ + $(srcdir)/assembler/wtf \ + $(srcdir)/assembler/jit \ + $(srcdir)/assembler/assembler \ + $(srcdir)/methodjit \ + $(srcdir)/yarr \ + $(srcdir)/yarr/yarr \ + $(srcdir)/yarr/pcre \ + $(srcdir)/yarr/wtf \ + $(NONE) + +CPPSRCS += Assertions.cpp \ + ExecutableAllocatorPosix.cpp \ + ExecutableAllocatorWin.cpp \ + ExecutableAllocatorOS2.cpp \ + ExecutableAllocator.cpp \ + ARMAssembler.cpp \ + Logging.cpp \ + MacroAssemblerARM.cpp \ + MacroAssemblerX86Common.cpp \ + RegexCompiler.cpp \ + RegexJIT.cpp \ + pcre_compile.cpp \ + pcre_exec.cpp \ + pcre_tables.cpp \ + pcre_xclass.cpp \ + pcre_ucp_searchfuncs.cpp \ + $(NONE) + +ifeq (86, $(findstring 86,$(TARGET_CPU))) +ifeq (x86_64, $(TARGET_CPU)) +#CPPSRCS += only_on_x86_64.cpp +else +#CPPSRCS += only_on_x86.cpp +endif +endif +ifeq (arm, $(TARGET_CPU)) +#CPPSRCS += only_on_arm.cpp +endif +# +# END enclude sources for the Nitro assembler +############################################# + +endif + +ifdef JS_HAS_CTYPES +VPATH += $(srcdir)/ctypes + +CPPSRCS += \ + CTypes.cpp \ + Library.cpp \ + $(NULL) + +LOCAL_INCLUDES = \ + -Ictypes/libffi/include \ + -I. \ + $(NULL) + +ifeq ($(OS_ARCH),OS2) +SHARED_LIBRARY_LIBS += \ + ctypes/libffi/.libs/ffi.a \ + $(NULL) +else +SHARED_LIBRARY_LIBS += \ + ctypes/libffi/.libs/libffi.$(LIB_SUFFIX) \ + $(NULL) +endif + +endif # JS_HAS_CTYPES + +ifdef HAVE_DTRACE +INSTALLED_HEADERS += \ + $(CURDIR)/javascript-trace.h \ + $(NULL) +endif + +# PerfMeasurement is available regardless of low-level support for it; +# it just doesn't necessarily do anything useful. There is one +# implementation source file per supported operating system, plus a stub +# for unsupported OSes, plus the Javascript wrapper. +VPATH += $(srcdir)/perf +INSTALLED_HEADERS += jsperf.h +CPPSRCS += jsperf.cpp +ifdef HAVE_LINUX_PERF_EVENT_H +CPPSRCS += pm_linux.cpp +else +CPPSRCS += pm_stub.cpp +endif + +ifeq (,$(filter-out WINNT WINCE,$(OS_ARCH))) +INSTALLED_HEADERS += jscpucfg.h +endif + +EXPORTS = $(INSTALLED_HEADERS) + +DASH_R = -r + +ifneq (,$(filter OS2 WINCE WINNT,$(OS_ARCH))) +SDK_LIBRARY = $(IMPORT_LIBRARY) +else +SDK_LIBRARY = $(SHARED_LIBRARY) +endif + +include $(topsrcdir)/config/config.mk + +EXTRA_DSO_LDOPTS += $(NSPR_LIBS) + +ifndef BUILD_OPT +MOCHAFILE = 1 +endif + +# Define keyword generator before rules.mk, see bug 323979 comment 50 + +HOST_SIMPLE_PROGRAMS += host_jskwgen$(HOST_BIN_SUFFIX) +GARBAGE += jsautokw.h host_jskwgen$(HOST_BIN_SUFFIX) + +HOST_SIMPLE_PROGRAMS += host_jsoplengen$(HOST_BIN_SUFFIX) +GARBAGE += jsautooplen.h host_jsoplengen$(HOST_BIN_SUFFIX) + +USE_HOST_CXX = 1 + +ifdef HAVE_DTRACE +ifneq ($(OS_ARCH),Darwin) +DTRACE_PROBE_OBJ = $(LIBRARY_NAME)-dtrace.$(OBJ_SUFFIX) +endif +MOZILLA_DTRACE_SRC = $(srcdir)/javascript-trace.d +endif + +default:: + +ifneq (,$(CROSS_COMPILE)$(filter-out WINNT OS2,$(OS_ARCH))) +ifneq (,$(filter-out SYMBIAN WINCE,$(OS_ARCH))) +# nsinstall doesn't get built until we enter config/ in the exports phase, +# so we'll have to manually ensure it gets built here if we want to use +# $(EXPORTS) +export:: config/nsinstall$(HOST_BIN_SUFFIX) +$(PUBLIC) $(SDK_PUBLIC): config/nsinstall$(HOST_BIN_SUFFIX) + +config/nsinstall$(HOST_BIN_SUFFIX): $(srcdir)/config/nsinstall.c $(srcdir)/config/pathsub.c + $(MAKE) -C config/ nsinstall$(HOST_BIN_SUFFIX) +endif +endif + +include $(topsrcdir)/config/rules.mk + +ifdef JS_HAS_CTYPES +# Build libffi proper as part of the 'exports' target, so things get built +# in the right order. +export:: + $(call SUBMAKE,,ctypes/libffi) + +distclean clean:: + $(call SUBMAKE,$@,ctypes/libffi) +endif + +ifdef MOZ_SYNC_BUILD_FILES +# Because the SpiderMonkey can be distributed and built independently +# of the Mozilla source tree, it contains its own copies of many of +# the files used by the top-level Mozilla build process, from the +# 'config' and 'build' subtrees. +# +# To make it simpler to keep the copies in sync, we follow the policy +# that the SpiderMonkey copies must always be exact copies of those in +# the containing Mozilla tree. If you've made a change in one, it +# belongs in the other as well. If the change isn't right for both +# places, then that's something to bring up with the other developers. +# +# Some files are reasonable to diverge; for example, +# js/config/autoconf.mk.in doesn't need most of the stuff in +# config/autoconf.mk.in. +check-sync-dirs = $(PYTHON) $(srcdir)/config/check-sync-dirs.py +check:: + $(check-sync-dirs) $(srcdir)/config $(MOZ_SYNC_BUILD_FILES)/config + $(check-sync-dirs) $(srcdir)/build $(MOZ_SYNC_BUILD_FILES)/build + +check-valgrind:: + $(check-sync-dirs) $(srcdir)/config $(MOZ_SYNC_BUILD_FILES)/config + $(check-sync-dirs) $(srcdir)/build $(MOZ_SYNC_BUILD_FILES)/build +endif + +# The "find any vanilla new/new[] calls" script is tailored to Linux, so +# only run it there. That should be enough to catch any such calls that +# creep in. +ifeq ($(OS_ARCH),Linux) +check:: + $(srcdir)/config/find_vanilla_new_calls $(LIBRARY) +endif + +ifdef ENABLE_TRACEJIT +ifndef WINCE +JITFLAGS = ,m,j,mj,mjp,am,amj,amjp,amd +check:: + $(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \ + --no-slow --no-progress --tinderbox --jitflags=$(JITFLAGS) $(DIST)/bin/js$(BIN_SUFFIX) + +check-valgrind:: + $(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \ + --valgrind --no-slow --no-progress --tinderbox --jitflags=$(JITFLAGS) $(DIST)/bin/js$(BIN_SUFFIX) +endif +endif + +DIST_GARBAGE = config.cache config.log config.status \ + config/autoconf.mk \ + unallmakefiles js-config js-config.h js-confdefs.h + +distclean:: + cat unallmakefiles | $(XARGS) rm -f + rm -f $(DIST_GARBAGE) + +# our build system doesn't handle subdir srcs very gracefully today +export:: + mkdir -p nanojit + +DEFINES += -DEXPORT_JS_API + +# Some platforms that have stdint.h include it in system headers. So +# to reliably get limit macros defined, we'd always have to define the +# one below before including any header, but that's obscure and +# fragile, so we do it here. +DEFINES += -D__STDC_LIMIT_MACROS + +INCLUDES += -I$(srcdir) + +GARBAGE += jscpucfg.o jsautocfg.h jsautocfg.tmp jscpucfg + +ifneq (,$(CROSS_COMPILE)$(filter-out WINNT,$(OS_ARCH))) +TARGETS += jscpucfg$(HOST_BIN_SUFFIX) +endif + +ifdef JS_THREADSAFE +DEFINES += -DJS_THREADSAFE +endif + +ifdef JS_HAS_CTYPES +DEFINES += -DJS_HAS_CTYPES +DEFINES += -DDLL_PREFIX=\"$(DLL_PREFIX)\" -DDLL_SUFFIX=\"$(DLL_SUFFIX)\" +endif + +ifdef JS_NO_THIN_LOCKS +DEFINES += -DJS_USE_ONLY_NSPR_LOCKS +endif + +ifdef JS_VERSION +DEFINES += -DJS_VERSION=$(JS_VERSION) +endif + +ifneq ($(findstring -L,$(NSPR_LIBS)),) +NSPR_STATIC_PATH = $(subst -L,,$(findstring -L,$(NSPR_LIBS))) +else +NSPR_STATIC_PATH = $(DIST)/lib +endif + +ifdef MOZ_VTUNE +CXXFLAGS += -IC:/Program\ Files/Intel/VTune/Analyzer/Include +EXTRA_DSO_LDOPTS += C:/Program\ Files/Intel/VTune/Analyzer/Lib/VtuneApi.lib +LIBS += C:/Program\ Files/Intel/VTune/Analyzer/Lib/VtuneApi.lib +endif + +# BeOS and HP-UX do not require the extra linking of "-lm" +ifeq (,$(filter BeOS HP-UX WINNT WINCE OpenVMS OS2,$(OS_ARCH))) +EXTRA_LIBS += -lm +endif + +# Prevent floating point errors caused by VC++ optimizations +ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_) +ifeq (,$(filter-out 1200 1300 1310,$(_MSC_VER))) +CFLAGS += -Op +else +CFLAGS += -fp:precise +endif +endif # WINNT + +ifeq ($(OS_ARCH),FreeBSD) +EXTRA_LIBS += -pthread +endif +ifeq ($(OS_ARCH),IRIX) +ifdef USE_N32 +DASH_R += -n32 +endif +endif +ifeq ($(OS_ARCH),Linux) +EXTRA_LIBS += -ldl +endif +ifeq ($(OS_ARCH),OSF1) +EXTRA_LIBS += -lc_r +endif +ifeq ($(OS_ARCH),SunOS) +ifeq ($(TARGET_CPU),sparc) + +ifdef GNU_CC +CFLAGS += -mcpu=v9 +CXXFLAGS += -mcpu=v9 +endif # GNU_CC + +endif +ifeq ($(OS_RELEASE),4.1) +EXTRA_LIBS += -ldl -lnsl +else +EXTRA_LIBS += -lposix4 -ldl -lnsl -lsocket +endif +endif + +ifdef MOZ_MEMORY +ifeq ($(OS_ARCH),Darwin) +LDFLAGS += -ljemalloc +endif +endif + +ifdef SOLARIS_SUNPRO_CXX +ifeq ($(TARGET_CPU),sparc) +# Sun Studio SPARC doesn't work well with gcc inline asm, use lock_SunOS_sparc*.il +jslock.o: jslock.cpp Makefile.in lock_sparcv8plus.il lock_sparcv9.il + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CXX) +ifeq (sparcv9,$(findstring sparcv9,$(OS_TEST))) + $(CXX) -o $@ -c $(COMPILE_CFLAGS) $(srcdir)/lock_sparcv9.il $< +else + $(CXX) -o $@ -c $(COMPILE_CFLAGS) $(srcdir)/lock_sparcv8plus.il $< +endif # sparcv9 +endif # sparc +endif # SOLARIS_SUNPRO_CXX + +ifeq ($(OS_ARCH),IRIX) +ifndef GNU_CC +_COMPILE_CFLAGS = $(patsubst -O%,-O1,$(COMPILE_CFLAGS)) +jsapi.o jsxdrapi.o jsarena.o jsarray.o jsatom.o jsemit.o jsfun.o jsinterp.o jsreflect.o jsregexp.o jsparse.o jsopcode.o jsscript.o: %.o: %.cpp Makefile.in + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CXX) + $(CXX) -o $@ -c $(_COMPILE_CFLAGS) $< +endif +endif + +# An AIX Optimization bug causes PR_dtoa() & JS_dtoa to produce wrong result. +# This suppresses optimization for this single compilation unit. +ifeq ($(OS_ARCH),AIX) +jsatom.o: jsatom.cpp Makefile.in + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CXX) + $(CXX) -o $@ -c $(filter-out $(MOZ_OPTIMIZE_FLAGS), $(COMPILE_CFLAGS)) $< +jsdtoa.o: jsdtoa.cpp Makefile.in + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CXX) + $(CXX) -o $@ -c $(filter-out $(MOZ_OPTIMIZE_FLAGS), $(COMPILE_CFLAGS)) $< +endif + +export:: jsautocfg.h + +ifeq (,$(CROSS_COMPILE)$(GNU_CC)$(filter-out WINNT,$(OS_ARCH))) +jsautocfg.h: + touch $@ +else +ifeq ($(OS_ARCH),WINCE) +jsautocfg.h: + touch $@ +else +jsautocfg.h: jscpucfg$(HOST_BIN_SUFFIX) + @rm -f $@ jsautocfg.tmp + ./jscpucfg > jsautocfg.tmp + mv jsautocfg.tmp $@ +endif +endif + +# jscpucfg is a strange target +# Needs to be built with the host compiler but needs to include +# the mdcpucfg for the target so it needs the appropriate target defines +ifdef HOST_NSPR_MDCPUCFG +HOST_CXX := $(HOST_CXX) -DMDCPUCFG=$(TARGET_NSPR_MDCPUCFG) +HOST_CXXFLAGS := $(patsubst -DXP_%,,$(HOST_CXXFLAGS)) +endif + +ifdef CROSS_COMPILE +# jscpucfg needs to know when it's supposed to produce a config for the target +JSCPUCFG_DEFINES = $(ACDEFINES) +endif + +ifeq ($(OS_ARCH),QNX) +ifneq ($(OS_TARGET),NTO) +# QNX's compiler apparently can't build a binary directly from a source file. +jscpucfg.o: jscpucfg.cpp Makefile.in + $(HOST_CXX) $(HOST_CXXFLAGS) -c $(JSCPUCFG_DEFINES) $(DEFINES) $(NSPR_CFLAGS) -o $@ $< + +jscpucfg: jscpucfg.o + $(HOST_CXX) $(HOST_CXXFLAGS) $(JSCPUCFG_DEFINES) $(DEFINES) -o $@ $< +endif +else +ifeq ($(OS_ARCH),WINCE) +jscpucfg$(HOST_BIN_SUFFIX): + echo no need to build jscpucfg $< +else +jscpucfg$(HOST_BIN_SUFFIX): jscpucfg.cpp Makefile.in + $(HOST_CXX) $(HOST_CXXFLAGS) $(JSCPUCFG_DEFINES) $(DEFINES) $(NSPR_CFLAGS) $(HOST_OUTOPTION)$@ $< +endif +endif + +# Compute the linker flags that programs linking against SpiderMonkey should +# pass to get SpiderMonkey and its dependencies, beyond just the -L and -l +# for the SpiderMonkey library itself. +# - EXTRA_DSO_LDOPTS includes the NSPR -L and -l flags. +# - OS_LIBS includes libraries selected by the configure script. +# - EXTRA_LIBS includes libraries selected by this Makefile. +JS_CONFIG_LIBS=$(EXTRA_DSO_LDOPTS) $(OS_LIBS) $(EXTRA_LIBS) +JS_CONFIG_MOZ_JS_LIBS=-L$(libdir) -l$(LIBRARY_NAME) + +# The configure script invokes this rule explicitly at configure time! +# It's important that js-config be ready by the time we're done +# configuring, because we may be running other configure scripts that +# would like to run js-config themselves, before js is built. +# +# This file and rules.mk go through a certain amount of work to decide +# which libraries to build, what to name them, and what flags to pass +# when linking them (and thus what flags its own clients must pass). +# All this information needs to go into the js-config script. To +# avoid trying to re-compute all that in the configure script, we just +# have the configure script generate this Makefile, and then invoke +# this rule. +at=@ +js-config: js-config.in Makefile $(DEPTH)/config/autoconf.mk $(topsrcdir)/config/config.mk $(topsrcdir)/config/rules.mk + rm -f js-config.tmp + sed < $< > js-config.tmp \ + -e 's|$(at)prefix$(at)|$(prefix)|' \ + -e 's|$(at)exec_prefix$(at)|$(exec_prefix)|' \ + -e 's|$(at)includedir$(at)|$(includedir)|' \ + -e 's|$(at)libdir$(at)|$(libdir)|' \ + -e 's|$(at)MOZILLA_VERSION$(at)|$(MOZILLA_VERSION)|' \ + -e 's|$(at)LIBRARY_NAME$(at)|$(LIBRARY_NAME)|' \ + -e 's|$(at)NSPR_CFLAGS$(at)|$(NSPR_CFLAGS)|' \ + -e 's|$(at)JS_CONFIG_LIBS$(at)|$(JS_CONFIG_LIBS)|' \ + -e 's|$(at)MOZ_JS_LIBS$(at)|$(JS_CONFIG_MOZ_JS_LIBS)|' \ + && mv js-config.tmp $@ && chmod +x $@ + +SCRIPTS = js-config +SDK_BINARY = js-config + +pkg_config_files = \ + mozjs185.pc \ + $(NULL) + +GARBAGE += $(pkg_config_files) + +%.pc: $(srcdir)/%.pc.in Makefile + cat $< | sed \ + -e "s|%prefix%|$(prefix)|" \ + -e "s|%includedir%|$(includedir)|" \ + -e "s|%libdir%|$(libdir)|" \ + -e 's|%MOZILLA_VERSION%|$(MOZILLA_VERSION)|' \ + > $@ && chmod 644 $@ + +install:: $(pkg_config_files) + @echo pkg_config_file: $(pkg_config_files) + $(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(libdir)/pkgconfig + +install:: $(INSTALLED_HEADERS) + $(SYSINSTALL) $^ $(DESTDIR)$(includedir)/$(MODULE) + +install:: $(SCRIPTS) + $(SYSINSTALL) $^ $(DESTDIR)$(bindir) + +ifeq (,$(HOST_BIN_SUFFIX)) +ifeq (.dylib,$(DLL_SUFFIX)) +# Mac OS X +SHLIB_ANY_VER := $(DESTDIR)$(libdir)/$(SHARED_LIBRARY) +SHLIB_ABI_VER := $(DESTDIR)$(libdir)/$(SHARED_LIBRARY:$(DLL_SUFFIX)=.$(SRCREL_ABI_VERSION)$(DLL_SUFFIX)) +SHLIB_EXACT_VER := $(DESTDIR)$(libdir)/$(SHARED_LIBRARY:$(DLL_SUFFIX)=.$(SRCREL_VERSION)$(DLL_SUFFIX)) +$(SHARED_LIBRARY): EXTRA_DSO_LDOPTS += -install_name $(SHLIB_ABI_VER) +$(SHARED_LIBRARY): EXTRA_DSO_LDOPTS += -current_version $(SRCREL_VERSION) +$(SHARED_LIBRARY): EXTRA_DSO_LDOPTS += -compatibility_version $(SRCREL_ABI_VERSION) +else +# Generic Unix / Linux +SHLIB_ANY_VER := $(DESTDIR)$(libdir)/$(SHARED_LIBRARY) +SHLIB_ABI_VER := $(DESTDIR)$(libdir)/$(SHARED_LIBRARY).$(SRCREL_ABI_VERSION) +SHLIB_EXACT_VER := $(DESTDIR)$(libdir)/$(SHARED_LIBRARY).$(SRCREL_VERSION) +$(SHARED_LIBRARY): EXTRA_DSO_LDOPTS += -Wl,-soname,$(notdir $(SHLIB_ABI_VER)) +endif +endif + +install:: $(LIBRARY) $(SHARED_LIBRARY) $(IMPORT_LIBRARY) +ifneq (,$(LIBRARY)) + $(SYSINSTALL) $(LIBRARY) $(DESTDIR)$(libdir) + mv -f $(DESTDIR)$(libdir)/$(LIBRARY) $(subst $(STATIC_LIBRARY_NAME),mozjs185-$(SRCREL_ABI_VERSION),$(DESTDIR)$(libdir)/$(LIBRARY)) +endif +ifneq (,$(SHARED_LIBRARY)) +ifeq (,$(HOST_BIN_SUFFIX)) + @[ ! -h $(SHLIB_ANY_VER) ] || rm -f $(SHLIB_ANY_VER) +endif + $(SYSINSTALL) $(SHARED_LIBRARY) $(DESTDIR)$(libdir) +ifeq (,$(HOST_BIN_SUFFIX)) + mv -f $(SHLIB_ANY_VER) $(SHLIB_EXACT_VER) + @[ ! -h $(SHLIB_ABI_VER) ] || rm -f $(SHLIB_ABI_VER) + ln -s $(SHLIB_EXACT_VER) $(SHLIB_ABI_VER) + ln -s $(SHLIB_ABI_VER) $(SHLIB_ANY_VER) +endif +endif +ifneq (,$(IMPORT_LIBRARY)) + $(SYSINSTALL) $(IMPORT_LIBRARY) $(DESTDIR)$(libdir) +endif + +# Extra dependancies and rules for auto-generated headers +host_jskwgen.$(OBJ_SUFFIX): jsversion.h jskeyword.tbl + +# Use CURDIR to avoid finding a jsautokw.h in the source tree (from a +# previous build?) via VPATH when we're building in a separate tree. +$(CURDIR)/jsautokw.h: host_jskwgen$(HOST_BIN_SUFFIX) + ./host_jskwgen$(HOST_BIN_SUFFIX) $@ + +host_jsoplengen.$(OBJ_SUFFIX): jsopcode.tbl + +# Use CURDIR to avoid finding a jsautooplen.h in the source tree (from +# a previous build?) via VPATH when we're building in a separate tree. +$(CURDIR)/jsautooplen.h: host_jsoplengen$(HOST_BIN_SUFFIX) + ./host_jsoplengen$(HOST_BIN_SUFFIX) $@ + +# Force auto-header generation before compiling any source that may use them +$(patsubst %.cc,%.$(OBJ_SUFFIX),$(CPPSRCS:%.cpp=%.$(OBJ_SUFFIX))): $(CURDIR)/jsautokw.h $(CURDIR)/jsautooplen.h + +ifdef HAVE_DTRACE +$(CURDIR)/javascript-trace.h: $(srcdir)/javascript-trace.d + dtrace -h -s $(srcdir)/javascript-trace.d -o javascript-trace.h.in + sed -e 's/if _DTRACE_VERSION/ifdef INCLUDE_MOZILLA_DTRACE/' \ + -e '/const/!s/char \*/const char */g' \ + javascript-trace.h.in > javascript-trace.h + +# We can't automatically generate dependencies on auto-generated headers; +# we have to list them explicitly. +$(addsuffix .$(OBJ_SUFFIX),jsprobes jsinterp jsobj): $(CURDIR)/javascript-trace.h +endif + +ifdef ENABLE_TRACEJIT +# Imacro compilation. +$(CURDIR)/imacros.c.out: $(srcdir)/imacro_asm.py $(srcdir)/imacros.jsasm jsopcode.tbl + $(PYTHON) $< $(srcdir)/imacros.jsasm $(CURDIR)/imacros.c.out +$(addsuffix .$(OBJ_SUFFIX),jstracer): $(CURDIR)/imacros.c.out + +# Code for importing the nanojit subtree from its repository. +NANOJIT_CENTRAL_REV=$(shell cat $(srcdir)/nanojit-import-rev) +NANOJIT_CENTRAL_REPO=http://hg.mozilla.org/projects/nanojit-central +NANOJIT_CENTRAL_LOCAL=$(CURDIR)/nanojit-central +CUR_REPO=$(srcdir)/../.. + +update-nanojit: + rm -Rf $(NANOJIT_CENTRAL_LOCAL) import-splicemap import-revmap + hg clone $(NANOJIT_CENTRAL_REPO) $(NANOJIT_CENTRAL_LOCAL) + python $(srcdir)/find-child.py \ + --src=$(NANOJIT_CENTRAL_LOCAL) \ + --dst=$(CUR_REPO) \ + --start=$(NANOJIT_CENTRAL_REV) \ + --filemap=$(srcdir)/nanojit-import-filemap \ + >import-splicemap + hg convert --config convert.hg.saverev=True \ + --config convert.hg.startrev=`cut -d ' ' -f 1 import-splicemap` \ + --filemap=$(srcdir)/nanojit-import-filemap \ + --splicemap=import-splicemap \ + $(NANOJIT_CENTRAL_LOCAL) \ + $(CUR_REPO) \ + import-revmap + (cd $(srcdir) && hg up) + (cd $(NANOJIT_CENTRAL_LOCAL) && hg log -r tip --template "{node}\n") >$(srcdir)/nanojit-import-rev + (cd $(srcdir) && hg commit --message="Update nanojit-import-rev stamp." nanojit-import-rev) + +.PHONY: update-nanojit +endif + +############################################### +# BEGIN kludges for the Nitro assembler +# + +# Needed to "configure" it correctly. Unfortunately these +# flags wind up being applied to all code in js/src, not just +# the code in js/src/assembler. +CXXFLAGS += -DUSE_SYSTEM_MALLOC=1 -DENABLE_ASSEMBLER=1 -DENABLE_JIT=1 + +INCLUDES += -I$(srcdir)/assembler -I$(srcdir)/yarr + +ifdef ENABLE_METHODJIT +# Build a standalone test program that exercises the assembler +# sources a bit. +TESTMAIN_OBJS = \ + Assertions.$(OBJ_SUFFIX) \ + ExecutableAllocatorPosix.$(OBJ_SUFFIX) \ + ExecutableAllocatorWin.$(OBJ_SUFFIX) \ + ExecutableAllocator.$(OBJ_SUFFIX) \ + ARMAssembler.$(OBJ_SUFFIX) \ + MacroAssemblerARM.$(OBJ_SUFFIX) \ + TestMain.$(OBJ_SUFFIX) \ + jsutil.$(OBJ_SUFFIX) \ + jslog2.$(OBJ_SUFFIX) +TestMain$(HOST_BIN_SUFFIX): $(TESTMAIN_OBJS) + $(CXX) -o TestMain$(HOST_BIN_SUFFIX) $(TESTMAIN_OBJS) +endif + +# +# END kludges for the Nitro assembler +############################################### + diff --git a/js/src/Makefile.ref b/js/src/Makefile.ref new file mode 100644 index 0000000..2ff69ce --- /dev/null +++ b/js/src/Makefile.ref @@ -0,0 +1,468 @@ +# -*- Mode: makefile -*- +# vim: ft=make +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Michael Ang +# Kevin Buhr +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# JSRef GNUmake makefile. +# +# Note: dependency rules are missing for some files (some +# .h, all .msg, etc.) Re-make clean if in doubt. +# + + +DEPTH = . + +include config.mk + +#NS_USE_NATIVE = 1 + +ifndef NANOJIT_ARCH +$(warning NANOJIT_ARCH not defined in config/$(OS_CONFIG).mk, JIT disabled) +else +ifdef DISABLE_JIT +$(warning disabling JIT per build specification) +else +ENABLE_JIT=1 +endif +endif + +ifdef ENABLE_JIT +DEFINES += -DJS_TRACER +DEFINES += -DFEATURE_NANOJIT +INCLUDES += -Inanojit +endif + +#ifndef BUILD_OPT +#DEFINES += -Ivprof +#endif + +# Look in OBJDIR to find jsautocfg.h, jsautokw.h, and js-config.h +INCLUDES += -I. -I$(OBJDIR) + +ifdef JS_THREADSAFE +DEFINES += -DJS_THREADSAFE +INCLUDES += -I$(DIST)/include/nspr +ifdef USE_MSVC +OTHER_LIBS += $(DIST)/lib/libnspr$(NSPR_LIBSUFFIX).lib +else +OTHER_LIBS += -L$(DIST)/lib -lnspr$(NSPR_LIBSUFFIX) +endif +endif + +ifdef JS_HAS_CTYPES +DEFINES += -DJS_HAS_CTYPES +INCLUDES += -I$(DIST)/include/nspr +ifdef USE_MSVC +OTHER_LIBS += $(DIST)/lib/libnspr$(NSPR_LIBSUFFIX).lib +else +OTHER_LIBS += -L$(DIST)/lib -lnspr$(NSPR_LIBSUFFIX) +endif +endif + +ifdef JS_NO_THIN_LOCKS +DEFINES += -DJS_USE_ONLY_NSPR_LOCKS +endif + +ifdef JS_GC_ZEAL +DEFINES += -DJS_GC_ZEAL +endif + +# +# XCFLAGS may be set in the environment or on the gmake command line +# +#CFLAGS += -DDEBUG -DDEBUG_brendan -DJS_ARENAMETER -DJS_HASHMETER -DJS_DUMP_PROPTREE_STATS -DJS_DUMP_SCOPE_METERS -DJS_SCOPE_DEPTH_METER -DJS_BASIC_STATS +CFLAGS += $(OS_CFLAGS) $(DEFINES) $(INCLUDES) $(XCFLAGS) + +LDFLAGS = $(XLDFLAGS) +LDFLAGS += $(OS_LDFLAGS) + +ifdef MOZ_SHARK +DEFINES += -DMOZ_SHARK +CFLAGS += -F/System/Library/PrivateFrameworks +LDFLAGS += -F/System/Library/PrivateFrameworks -framework CHUD +endif +ifdef MOZ_CALLGRIND +DEFINES += -DMOZ_CALLGRIND +endif +ifdef MOZ_VTUNE +DEFINES += -DMOZ_VTUNE +CXXFLAGS += -IC:/Program\ Files/Intel/VTune/Analyzer/Include +OTHER_LIBS += C:/Program\ Files/Intel/VTune/Analyzer/Lib/VtuneApi.lib +endif + +ifndef NO_LIBM +LDFLAGS += -lm +endif + +# Prevent floating point errors caused by VC++ optimizations +ifeq ($(OS_ARCH),WINNT) +_MSC_VER = $(shell $(CXX) 2>&1 | sed -n 's/.*Compiler Version \([0-9]*\)\.\([0-9]*\).*/\1\2/p') +ifeq (,$(filter-out 1200 1300 1310,$(_MSC_VER))) +CFLAGS += -Op +else +CFLAGS += -fp:precise +endif +endif # WINNT + +# +# Server-related changes : +# +ifdef NES40 +DEFINES += -DNES40 +endif + +# +# Line editing support. +# Define JS_READLINE or JS_EDITLINE to enable line editing in the +# js command-line interpreter. +# +ifdef JS_READLINE +# For those platforms with the readline library installed. +DEFINES += -DEDITLINE +PROG_LIBS += -lreadline -ltermcap +else +ifdef JS_EDITLINE +# Use the editline library, built locally. +PREDIRS += editline +DEFINES += -DEDITLINE +PROG_LIBS += $(OBJDIR)/editline/libedit.a +endif +endif + +# For purify +PURE_CFLAGS = -DXP_UNIX $(OPTIMIZER) $(PURE_OS_CFLAGS) $(DEFINES) \ + $(INCLUDES) $(XCFLAGS) + +# +# JS file lists +# +JS_HFILES = \ + jsarray.h \ + jsatom.h \ + jsbool.h \ + jscntxt.h \ + jsdate.h \ + jsemit.h \ + jsexn.h \ + jsfun.h \ + jsgc.h \ + jsinterp.h \ + jsiter.h \ + jslibmath.h \ + jslock.h \ + jsmath.h \ + jsnum.h \ + jsobj.h \ + json.h \ + jsopcode.h \ + jsparse.h \ + jsarena.h \ + jsclist.h \ + jsdhash.h \ + jsdtoa.h \ + jshash.h \ + jslong.h \ + jstypes.h \ + jsprvtd.h \ + jspubtd.h \ + jsregexp.h \ + jsscan.h \ + jsscope.h \ + jsscript.h \ + jsstr.h \ + jsversion.h \ + jsxdrapi.h \ + jsxml.h \ + $(NULL) + +ifdef ENABLE_JIT +JS_HFILES += \ + jstracer.h \ + nanojit/Assembler.h \ + nanojit/LIR.h \ + nanojit/Native$(NANOJIT_ARCH).h \ + nanojit/avmplus.h \ + nanojit/vm_fops.h \ + nanojit/Fragmento.h \ + nanojit/Native.h \ + nanojit/RegAlloc.h \ + nanojit/nanojit.h \ + $(NULL) +endif + +ifndef BUILD_OPT +#JS_HFILES += \ +# vprof/vprof.h \ +# $(NULL) +endif + +API_HFILES = \ + jsapi.h \ + jsdbgapi.h \ + $(NULL) + +OTHER_HFILES = \ + jsbit.h \ + jscompat.h \ + jscpucfg.h \ + jsotypes.h \ + prmjtime.h \ + resource.h \ + jsopcode.tbl \ + jsproto.tbl \ + js.msg \ + jsshell.msg \ + jskeyword.tbl \ + $(NULL) + +ifndef PREBUILT_CPUCFG +OTHER_HFILES += $(OBJDIR)/jsautocfg.h +endif +OTHER_HFILES += $(OBJDIR)/jsautokw.h $(OBJDIR)/js-config.h + +HFILES = $(JS_HFILES) $(API_HFILES) $(OTHER_HFILES) + +JS_CPPFILES = \ + jsapi.cpp \ + jsarena.cpp \ + jsarray.cpp \ + jsatom.cpp \ + jsbool.cpp \ + jscntxt.cpp \ + jsdate.cpp \ + jsdbgapi.cpp \ + jsdhash.cpp \ + jsdtoa.cpp \ + jsemit.cpp \ + jsexn.cpp \ + jsfun.cpp \ + jsgc.cpp \ + jshash.cpp \ + jsinterp.cpp \ + jsinvoke.cpp \ + jsiter.cpp \ + jslock.cpp \ + jslog2.cpp \ + jslong.cpp \ + jsmath.cpp \ + jsnum.cpp \ + jsobj.cpp \ + json.cpp \ + jsopcode.cpp \ + jsparse.cpp \ + jsprf.cpp \ + jsregexp.cpp \ + jsscan.cpp \ + jsscope.cpp \ + jsscript.cpp \ + jsstr.cpp \ + jsutil.cpp \ + jsxdrapi.cpp \ + jsxml.cpp \ + prmjtime.cpp \ + $(NULL) + +ifdef ENABLE_JIT +JS_CPPFILES += \ + jsbuiltins.cpp \ + jstracer.cpp \ + nanojit/Assembler.cpp \ + nanojit/Fragmento.cpp \ + nanojit/LIR.cpp \ + nanojit/Native$(NANOJIT_ARCH).cpp \ + nanojit/RegAlloc.cpp \ + nanojit/avmplus.cpp \ + $(NULL) + +endif + +ifndef BUILD_OPT +#JS_CPPFILES += \ +# vprof/vprof.cpp \ +# $(NULL) +endif + +LIB_CPPFILES = $(JS_CPPFILES) +LIB_ASFILES := $(wildcard *_$(OS_ARCH).s) +PROG_CPPFILES = js.cpp + +ifdef USE_MSVC +LIBRARY = $(OBJDIR)/js32.lib +SHARED_LIBRARY = $(OBJDIR)/js32.dll +PROGRAM = $(OBJDIR)/js.exe +else +LIBRARY = $(OBJDIR)/libjs.a +SHARED_LIBRARY = $(OBJDIR)/libjs.$(SO_SUFFIX) +PROGRAM = $(OBJDIR)/js +endif + +include rules.mk + +MOZ_DEPTH = ../.. +include jsconfig.mk + +nsinstall-target: + cd ../../config; $(MAKE) OBJDIR=$(OBJDIR) OBJDIR_NAME=$(OBJDIR) + +# +# Automatic header generation +# + +AUTO_HEADERS = \ + $(OBJDIR)/jsautokw.h \ + $(OBJDIR)/jsautooplen.h \ + $(NULL) + +$(OBJDIR)/jsautokw.h: jskeyword.tbl + +$(OBJDIR)/jsautooplen.h: jsopcode.tbl + +GARBAGE += $(AUTO_HEADERS) +GARBAGE += $(AUTO_HEADERS:$(OBJDIR)/jsauto%.h=$(OBJDIR)/js%gen$(HOST_BIN_SUFFIX)) + +ifdef USE_MSVC + +GARBAGE += $(AUTO_HEADERS:$(OBJDIR)/jsauto%.h=$(OBJDIR)/js%gen.obj) + +$(AUTO_HEADERS): $(OBJDIR)/jsauto%.h: js%gen.cpp + @$(MAKE_OBJDIR) + $(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $(OPTIMIZER) $< + link.exe -out:"$(OBJDIR)/js$*gen$(HOST_BIN_SUFFIX)" $(EXE_LINK_FLAGS) $(OBJDIR)/js$*gen.obj + $(OBJDIR)/js$*gen$(HOST_BIN_SUFFIX) $@ +else + +GARBAGE += $(AUTO_HEADERS:$(OBJDIR)/jsauto%.h=$(OBJDIR)/js%gen.d) +$(AUTO_HEADERS): $(OBJDIR)/jsauto%.h: js%gen.cpp + @$(MAKE_OBJDIR) + $(CXX) -o $(OBJDIR)/js$*gen$(HOST_BIN_SUFFIX) $(CFLAGS) $(OPTIMIZER) $(LDFLAGS) $< + $(OBJDIR)/js$*gen$(HOST_BIN_SUFFIX) $@ + +endif + +# force creation of autoheaders before compiling any source that may use them +$(LIB_OBJS) : $(AUTO_HEADERS) + +# +# An installed header file describing configuration options that affect +# the API. +# + +# Avoid rebuilding unless js-config.h's contents actually change. The +# timestamp on js-config.h.stamp corresponds to the last time we +# checked that js-config.h was up to date. If the stamp changes but +# js-config.h does not, then make concludes that targets depending on +# js-config.h don't need to be rebuilt. The dummy '@true' rule here +# keeps make from concluding that js-config.h never changes. +$(OBJDIR)/js-config.h: $(OBJDIR)/js-config.h.stamp + @true + +js-config-switch=$(if $(value $($1)),-e 's/\#undef $1/\#define $1/') +$(OBJDIR)/js-config.h.stamp: js-config.h.in Makefile.ref + sed < $< > $(@:.stamp=.tmp) \ + $(call js-config-switch,JS_THREADSAFE) \ + $(call js-config-switch,JS_HAS_CTYPES) \ + $(call js-config-switch,JS_GC_ZEAL) \ + -e :dummy + if ! [ -f $(@:.stamp=) ] || ! cmp $(@:.stamp=.tmp) $(@:.stamp=); then \ + mv $(@:.stamp=.tmp) $(@:.stamp=); \ + fi + touch $@ + +GARBAGE += $(OBJDIR)/js-config.h $(OBJDIR)/js-config.h.stamp + +# Force creation of js-config.h before compiling any source that may use it. +$(LIB_OBJS) : $(OBJDIR)/js-config.h + +# +# JS shell executable +# + +ifdef USE_MSVC +$(PROGRAM): $(PROG_OBJS) $(LIBRARY) + link.exe -out:"$@" $(EXE_LINK_FLAGS) $^ +else +$(PROGRAM): $(PROG_OBJS) $(LIBRARY) + $(CXX) -o $@ $(CFLAGS) $(PROG_OBJS) $(LIBRARY) $(LDFLAGS) $(OTHER_LIBS) \ + $(PROG_LIBS) +endif + +$(PROGRAM).pure: $(PROG_OBJS) $(LIBRARY) + purify $(PUREFLAGS) \ + $(CXX) -o $@ $(PURE_OS_CFLAGS) $(PROG_OBJS) $(LIBRARY) $(LDFLAGS) \ + $(OTHER_LIBS) $(PROG_LIBS) + +ifndef PREBUILT_CPUCFG +$(filter-out jscpucfg.h $(OBJDIR)/jsautocfg.h, $(HFILES)) $(CPPFILES): $(OBJDIR)/jsautocfg.h + +$(OBJDIR)/jsautocfg.h: $(OBJDIR)/jscpucfg + rm -f $@ + $(OBJDIR)/jscpucfg > $@ + +$(OBJDIR)/jscpucfg: $(OBJDIR)/jscpucfg.o + $(CXX) $(OS_LDFLAGS) -o $@ $(OBJDIR)/jscpucfg.o + +GARBAGE += $(OBJDIR)/jsautocfg.h $(OBJDIR)/jscpucfg \ + $(OBJDIR)/jscpucfg.o $(OBJDIR)/jscpucfg.d +endif + +# Automatic make dependencies files +DEPENDENCIES = $(CPPFILES:%.cpp=$(OBJDIR)/%.d) + +# +# Hardwire dependencies for some files +# +ifdef USE_MSVC +OBJ=obj +else +OBJ=o +endif + +$(OBJDIR)/jsinvoke.$(OBJ): jsinterp.h jsinterp.cpp +$(OBJDIR)/jsinvoke.obj : jsinterp.h jsinterp.cpp + +-include $(DEPENDENCIES) + +TARNAME = jsref.tar +TARFILES = files `cat files` + +SUFFIXES: .i +%.i: %.cpp + $(CXX) -C -E $(CFLAGS) $< > $*.i diff --git a/js/src/README.html b/js/src/README.html new file mode 100644 index 0000000..6eb1567 --- /dev/null +++ b/js/src/README.html @@ -0,0 +1,54 @@ + + + + + + + SpiderMonkey README + + + +

SpiderMonkey README

+ +

See the +SpiderMonkey +pages on the Mozilla Developer Center. + + + diff --git a/js/src/SpiderMonkey.rsp b/js/src/SpiderMonkey.rsp new file mode 100644 index 0000000..eb93040 --- /dev/null +++ b/js/src/SpiderMonkey.rsp @@ -0,0 +1,3 @@ +mozilla/js/src/* +mozilla/js/src/config/* +mozilla/js/src/macbuild/* diff --git a/js/src/Y.js b/js/src/Y.js new file mode 100644 index 0000000..e92a65a --- /dev/null +++ b/js/src/Y.js @@ -0,0 +1,19 @@ +// The Y combinator, applied to the factorial function + +function factorial(proc) { + return function (n) { + return (n <= 1) ? 1 : n * proc(n-1); + } +} + +function Y(outer) { + function inner(proc) { + function apply(arg) { + return proc(proc)(arg); + } + return outer(apply); + } + return inner(inner); +} + +print("5! is " + Y(factorial)(5)); diff --git a/js/src/aclocal.m4 b/js/src/aclocal.m4 new file mode 100644 index 0000000..3745619 --- /dev/null +++ b/js/src/aclocal.m4 @@ -0,0 +1,13 @@ +dnl +dnl Local autoconf macros used with mozilla +dnl The contents of this file are under the Public Domain. +dnl + +builtin(include, build/autoconf/pkg.m4)dnl +builtin(include, build/autoconf/nspr.m4)dnl +builtin(include, build/autoconf/altoptions.m4)dnl +builtin(include, build/autoconf/moznbytetype.m4)dnl +builtin(include, build/autoconf/mozprog.m4)dnl +builtin(include, build/autoconf/acwinpaths.m4)dnl + +MOZ_PROG_CHECKMSYS() diff --git a/js/src/analysis-tests/Makefile.in b/js/src/analysis-tests/Makefile.in new file mode 100644 index 0000000..e70b0c3 --- /dev/null +++ b/js/src/analysis-tests/Makefile.in @@ -0,0 +1,114 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla 2. +# +# The Initial Developer of the Original Code is +# the Mozilla Foundation . +# +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Benjamin Smedberg (Author) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +# we will do compilations that create dependency files. +NEED_MDDEPDIR = 1 + +include $(DEPTH)/config/autoconf.mk + +REDGREEN_WARNING_TESTCASES = \ + green-callred.cpp \ + green-accessred.cpp \ + green-tored-badpath.cpp \ + misdeclared-red-funcptr.cpp \ + misdeclared-red-funcptr2.cpp \ + red-togreenptr.cpp \ + red-togreenptr-return.cpp \ + red-togreenptr-arg.cpp \ + red-togreenptr-field.cpp \ + red-togreenptr-initializer.cpp \ + red-togreenptr-initializer-struct.cpp \ + red-togreenptr-initializer-array.cpp \ + red-togreenptr-initializer-nested.cpp \ + red-togreenptr-initializer-cast.cpp \ + green-callredptr.cpp \ + $(NULL) + +REDGREEN_SUCCESS_TESTCASES = \ + red-callred.cpp \ + red-callgreen.cpp \ + red-accessred.cpp \ + green-tored.cpp \ + green-toredptr.cpp \ + $(NULL) + +STATIC_WARNING_TESTCASES = \ + $(REDGREEN_WARNING_TESTCASES) \ + $(NULL) + +STATIC_PASS_TESTCASES = \ + $(REDGREEN_SUCCESS_TESTCASES) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +LOCAL_INCLUDES += -I$(srcdir)/.. -I.. + +check:: \ + $(STATIC_WARNING_TESTCASES:.cpp=.s-warn) \ + $(STATIC_PASS_TESTCASES:.cpp=.s-pass) \ + $(NULL) + +# We want to compile each file and invert the result to ensure that +# compilation failed. +%.s-warn: %.cpp $(GLOBAL_DEPS) $(DEHYDRA_SCRIPTS) + @printf "Compiling $($(*F).errlog 2>&1; then \ + printf "fail:\nerror: compilation of $($(*F).werrlog 2>&1; then \ + printf "ok.\n"; \ + else \ + printf "fail:\nerror: compilation of $($(*F).errlog 2>&1; then \ + printf "ok.\n"; \ + else \ + printf "fail:\nerror: compilation of $(redmember; +} diff --git a/js/src/analysis-tests/green-callred.cpp b/js/src/analysis-tests/green-callred.cpp new file mode 100644 index 0000000..d984403 --- /dev/null +++ b/js/src/analysis-tests/green-callred.cpp @@ -0,0 +1,12 @@ +#include "jstypes.h" + +#ifndef NS_STATIC_CHECKING +#error Running this without NS_STATIC_CHECKING is silly +#endif + +JS_REQUIRES_STACK void RedFunc(); + +void GreenFunc() +{ + RedFunc(); +} diff --git a/js/src/analysis-tests/green-callredptr.cpp b/js/src/analysis-tests/green-callredptr.cpp new file mode 100644 index 0000000..464e7f7 --- /dev/null +++ b/js/src/analysis-tests/green-callredptr.cpp @@ -0,0 +1,8 @@ +#include "jstypes.h" + +typedef void (JS_REQUIRES_STACK *RedFuncPtr)(); + +void GreenFunc(RedFuncPtr f) +{ + f(); +} diff --git a/js/src/analysis-tests/green-tored-badpath.cpp b/js/src/analysis-tests/green-tored-badpath.cpp new file mode 100644 index 0000000..32d5a0e --- /dev/null +++ b/js/src/analysis-tests/green-tored-badpath.cpp @@ -0,0 +1,14 @@ +#include "jstypes.h" + +JS_REQUIRES_STACK void RedFunc(); + +JS_FORCES_STACK void TurnRedFunc(); + +void GreenPartlyRedFunc(int i) +{ + if (i) { + TurnRedFunc(); + } + + RedFunc(); +} diff --git a/js/src/analysis-tests/green-tored.cpp b/js/src/analysis-tests/green-tored.cpp new file mode 100644 index 0000000..78676c8 --- /dev/null +++ b/js/src/analysis-tests/green-tored.cpp @@ -0,0 +1,12 @@ +#include "jstypes.h" + +JS_REQUIRES_STACK void RedFunc(); + +JS_FORCES_STACK void TurnRedFunc(); + +void GreenToRedFunc() +{ + TurnRedFunc(); + + RedFunc(); +} diff --git a/js/src/analysis-tests/green-toredptr.cpp b/js/src/analysis-tests/green-toredptr.cpp new file mode 100644 index 0000000..78df373 --- /dev/null +++ b/js/src/analysis-tests/green-toredptr.cpp @@ -0,0 +1,12 @@ +#include "jstypes.h" + +void GreenFunc(); + +typedef void (JS_REQUIRES_STACK *RedFuncPtr)(); + +RedFuncPtr Test() +{ + // assigning a green function to a red function pointer is ok + RedFuncPtr p = GreenFunc; + return p; +} diff --git a/js/src/analysis-tests/misdeclared-red-funcptr.cpp b/js/src/analysis-tests/misdeclared-red-funcptr.cpp new file mode 100644 index 0000000..9805347 --- /dev/null +++ b/js/src/analysis-tests/misdeclared-red-funcptr.cpp @@ -0,0 +1,5 @@ +#include "jstypes.h" + + +// JS_REQUIRES_STACK should come before the * +typedef void (* JS_REQUIRES_STACK RedFuncPtr)(); diff --git a/js/src/analysis-tests/misdeclared-red-funcptr2.cpp b/js/src/analysis-tests/misdeclared-red-funcptr2.cpp new file mode 100644 index 0000000..3ecc25e --- /dev/null +++ b/js/src/analysis-tests/misdeclared-red-funcptr2.cpp @@ -0,0 +1,5 @@ +#include "jstypes.h" + + +// JS_REQUIRES_STACK should come before the * +typedef void (* RedFuncPtr)() JS_REQUIRES_STACK; diff --git a/js/src/analysis-tests/red-accessred.cpp b/js/src/analysis-tests/red-accessred.cpp new file mode 100644 index 0000000..cf69fbf --- /dev/null +++ b/js/src/analysis-tests/red-accessred.cpp @@ -0,0 +1,11 @@ +#include "jstypes.h" + +struct Foo +{ + JS_REQUIRES_STACK void *redmember; +}; + +JS_REQUIRES_STACK void * RedFunc(Foo *f) +{ + return f->redmember; +} diff --git a/js/src/analysis-tests/red-callgreen.cpp b/js/src/analysis-tests/red-callgreen.cpp new file mode 100644 index 0000000..96270e8 --- /dev/null +++ b/js/src/analysis-tests/red-callgreen.cpp @@ -0,0 +1,8 @@ +#include "jstypes.h" + +void GreenFunc(); + +void JS_REQUIRES_STACK RedFunc() +{ + GreenFunc(); +} diff --git a/js/src/analysis-tests/red-callred.cpp b/js/src/analysis-tests/red-callred.cpp new file mode 100644 index 0000000..013bb12 --- /dev/null +++ b/js/src/analysis-tests/red-callred.cpp @@ -0,0 +1,8 @@ +#include "jstypes.h" + +JS_REQUIRES_STACK void RedFunc1(); + +JS_REQUIRES_STACK void RedFunc2() +{ + RedFunc1(); +} diff --git a/js/src/analysis-tests/red-togreenptr-arg.cpp b/js/src/analysis-tests/red-togreenptr-arg.cpp new file mode 100644 index 0000000..b3bb17d --- /dev/null +++ b/js/src/analysis-tests/red-togreenptr-arg.cpp @@ -0,0 +1,11 @@ +#include "jstypes.h" + +typedef void (*GreenFuncPtr)(); +typedef void (JS_REQUIRES_STACK *RedFuncPtr)(); + +void TakesAsArgument(GreenFuncPtr g); + +void Test(RedFuncPtr p) +{ + TakesAsArgument(p); +} diff --git a/js/src/analysis-tests/red-togreenptr-field.cpp b/js/src/analysis-tests/red-togreenptr-field.cpp new file mode 100644 index 0000000..f5c856b --- /dev/null +++ b/js/src/analysis-tests/red-togreenptr-field.cpp @@ -0,0 +1,15 @@ +#include "jstypes.h" + +typedef void (*GreenFuncPtr)(); +typedef void (JS_REQUIRES_STACK *RedFuncPtr)(); + +struct Foo +{ + int i; + GreenFuncPtr p; +}; + +void Test(Foo *foo, RedFuncPtr p) +{ + foo->p = p; +} diff --git a/js/src/analysis-tests/red-togreenptr-initializer-array.cpp b/js/src/analysis-tests/red-togreenptr-initializer-array.cpp new file mode 100644 index 0000000..8e3ec18 --- /dev/null +++ b/js/src/analysis-tests/red-togreenptr-initializer-array.cpp @@ -0,0 +1,8 @@ +#include "jstypes.h" + +void GreenFunc(); +JS_REQUIRES_STACK void RedFunc(); + +typedef void (*GreenFuncPtr)(); + +GreenFuncPtr fpa[2] = {GreenFunc, RedFunc}; diff --git a/js/src/analysis-tests/red-togreenptr-initializer-cast.cpp b/js/src/analysis-tests/red-togreenptr-initializer-cast.cpp new file mode 100644 index 0000000..8029605 --- /dev/null +++ b/js/src/analysis-tests/red-togreenptr-initializer-cast.cpp @@ -0,0 +1,7 @@ +#include "jstypes.h" + +JS_REQUIRES_STACK void RedFunc(); + +typedef void (*GreenFuncPtr)(int); + +GreenFuncPtr gfpa = (GreenFuncPtr) RedFunc; diff --git a/js/src/analysis-tests/red-togreenptr-initializer-nested.cpp b/js/src/analysis-tests/red-togreenptr-initializer-nested.cpp new file mode 100644 index 0000000..d4e4815 --- /dev/null +++ b/js/src/analysis-tests/red-togreenptr-initializer-nested.cpp @@ -0,0 +1,18 @@ +#include "jstypes.h" + +void GreenFunc(); +JS_REQUIRES_STACK void RedFunc(); + +typedef void (*GreenFuncPtr)(); + +struct S +{ + int i; + GreenFuncPtr p; +}; + +S sa[] = { + { 2, GreenFunc }, + { 1, RedFunc }, +}; + diff --git a/js/src/analysis-tests/red-togreenptr-initializer-struct.cpp b/js/src/analysis-tests/red-togreenptr-initializer-struct.cpp new file mode 100644 index 0000000..c2d9a9e --- /dev/null +++ b/js/src/analysis-tests/red-togreenptr-initializer-struct.cpp @@ -0,0 +1,12 @@ +#include "jstypes.h" + +JS_REQUIRES_STACK void RedFunc(); + +typedef void (*GreenFuncPtr)(); + +struct GreenStruct +{ + GreenFuncPtr func; +}; + +GreenStruct gs = { RedFunc }; diff --git a/js/src/analysis-tests/red-togreenptr-initializer.cpp b/js/src/analysis-tests/red-togreenptr-initializer.cpp new file mode 100644 index 0000000..063bb14 --- /dev/null +++ b/js/src/analysis-tests/red-togreenptr-initializer.cpp @@ -0,0 +1,7 @@ +#include "jstypes.h" + +JS_REQUIRES_STACK void RedFunc(); + +typedef void (*GreenFuncPtr)(); + +GreenFuncPtr funcp = RedFunc; diff --git a/js/src/analysis-tests/red-togreenptr-return.cpp b/js/src/analysis-tests/red-togreenptr-return.cpp new file mode 100644 index 0000000..ff91afd --- /dev/null +++ b/js/src/analysis-tests/red-togreenptr-return.cpp @@ -0,0 +1,9 @@ +#include "jstypes.h" + +typedef void (*GreenFuncPtr)(); +typedef void (JS_REQUIRES_STACK *RedFuncPtr)(); + +GreenFuncPtr Test(RedFuncPtr p) +{ + return p; +} diff --git a/js/src/analysis-tests/red-togreenptr.cpp b/js/src/analysis-tests/red-togreenptr.cpp new file mode 100644 index 0000000..65dfd4d --- /dev/null +++ b/js/src/analysis-tests/red-togreenptr.cpp @@ -0,0 +1,10 @@ +#include "jstypes.h" + +JS_REQUIRES_STACK void RedFunc(); + +typedef void (*GreenFuncPtr)(); + +GreenFuncPtr Test() +{ + return RedFunc; +} diff --git a/js/src/assembler/TestMain.cpp b/js/src/assembler/TestMain.cpp new file mode 100644 index 0000000..40f3085 --- /dev/null +++ b/js/src/assembler/TestMain.cpp @@ -0,0 +1,929 @@ + +// A short test program with which to experiment with the assembler. + +//satisfies CPU(X86_64) +//#define WTF_CPU_X86_64 + +// satisfies ENABLE(ASSEMBLER) +#define ENABLE_ASSEMBLER 1 + +// satisfies ENABLE(JIT) +#define ENABLE_JIT 1 + +#define USE_SYSTEM_MALLOC 1 +// leads to FORCE_SYSTEM_MALLOC in wtf/FastMalloc.cpp + +#include +#include +#include +#include + +#include + +#include + +///////////////////////////////////////////////////////////////// +// Temporary scaffolding for selecting the arch +#undef ARCH_x86 +#undef ARCH_amd64 +#undef ARCH_arm + +#if defined(__APPLE__) && defined(__i386__) +# define ARCH_x86 1 +#elif defined(__APPLE__) && defined(__x86_64__) +# define ARCH_amd64 1 +#elif defined(__linux__) && defined(__i386__) +# define ARCH_x86 1 +#elif defined(__linux__) && defined(__x86_64__) +# define ARCH_amd64 1 +#elif defined(__linux__) && defined(__arm__) +# define ARCH_arm 1 +#elif defined(_MSC_VER) && defined(_M_IX86) +# define ARCH_x86 1 +#endif +///////////////////////////////////////////////////////////////// + +// just somewhere convenient to put a breakpoint, before +// running gdb +#if WTF_COMPILER_GCC +__attribute__((noinline)) +#endif +void pre_run ( void ) { } + +///////////////////////////////////////////////////////////////// +//// test1 (simple straight line code) +#if WTF_COMPILER_GCC + +void test1 ( void ) +{ + printf("\n------------ Test 1 (straight line code) ------------\n\n" ); + + // Create new assembler + JSC::MacroAssembler* am = new JSC::MacroAssembler(); + +#if defined(ARCH_amd64) + JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15; + // dump some instructions into it + // xor %r15,%r15 + // add $0x7b,%r15 + // add $0x141,%r15 + // retq + am->xorPtr(areg,areg); + am->addPtr(JSC::MacroAssembler::Imm32(123), areg); + am->addPtr(JSC::MacroAssembler::Imm32(321), areg); + am->ret(); +#endif + +#if defined(ARCH_x86) + JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi; + // dump some instructions into it + // xor %edi,%edi + // add $0x7b,%edi + // add $0x141,%edi + // ret + am->xorPtr(areg,areg); + am->addPtr(JSC::MacroAssembler::Imm32(123), areg); + am->addPtr(JSC::MacroAssembler::Imm32(321), areg); + am->ret(); +#endif + +#if defined(ARCH_arm) + JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8; + // eors r8, r8, r8 + // adds r8, r8, #123 ; 0x7b + // mov r3, #256 ; 0x100 + // orr r3, r3, #65 ; 0x41 + // adds r8, r8, r3 + // mov pc, lr + am->xorPtr(areg,areg); + am->addPtr(JSC::MacroAssembler::Imm32(123), areg); + am->addPtr(JSC::MacroAssembler::Imm32(321), areg); + am->ret(); +#endif + + // prepare a link buffer, into which we can copy the completed insns + JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); + + // intermediate step .. get the pool suited for the size of code in 'am' + //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); + JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); + + // constructor for LinkBuffer asks ep to allocate r-x memory, + // then copies it there. + JSC::LinkBuffer patchBuffer(am, ep); + + // finalize + JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); + + // cr now holds a pointer to the final runnable code. + void* entry = cr.m_code.executableAddress(); + + printf("disas %p %p\n", + entry, (char*)entry + cr.m_size); + pre_run(); + + unsigned long result = 0x55555555; + +#if defined(ARCH_amd64) + // call the generated piece of code. It puts its result in r15. + __asm__ __volatile__( + "callq *%1" "\n\t" + "movq %%r15, %0" "\n" + :/*out*/ "=r"(result) + :/*in*/ "r"(entry) + :/*trash*/ "r15","cc" + ); +#endif +#if defined(ARCH_x86) + // call the generated piece of code. It puts its result in edi. + __asm__ __volatile__( + "calll *%1" "\n\t" + "movl %%edi, %0" "\n" + :/*out*/ "=r"(result) + :/*in*/ "r"(entry) + :/*trash*/ "edi","cc" + ); +#endif +#if defined(ARCH_arm) + // call the generated piece of code. It puts its result in r8. + __asm__ __volatile__( + "blx %1" "\n\t" + "mov %0, %%r8" "\n" + :/*out*/ "=r"(result) + :/*in*/ "r"(entry) + :/*trash*/ "r8","cc" + ); +#endif + + printf("\n"); + printf("value computed is %lu (expected 444)\n", result); + printf("\n"); + + delete eal; + delete am; +} + +#endif /* WTF_COMPILER_GCC */ + +///////////////////////////////////////////////////////////////// +//// test2 (a simple counting-down loop) +#if WTF_COMPILER_GCC + +void test2 ( void ) +{ + printf("\n------------ Test 2 (mini loop) ------------\n\n" ); + + // Create new assembler + JSC::MacroAssembler* am = new JSC::MacroAssembler(); + +#if defined(ARCH_amd64) + JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15; + // xor %r15,%r15 + // add $0x7b,%r15 + // add $0x141,%r15 + // sub $0x1,%r15 + // mov $0x0,%r11 + // cmp %r11,%r15 + // jne 0x7ff6d3e6a00e + // retq + // so r15 always winds up being zero + am->xorPtr(areg,areg); + am->addPtr(JSC::MacroAssembler::Imm32(123), areg); + am->addPtr(JSC::MacroAssembler::Imm32(321), areg); + + JSC::MacroAssembler::Label loopHeadLabel(am); + am->subPtr(JSC::MacroAssembler::Imm32(1), areg); + + JSC::MacroAssembler::Jump j + = am->branchPtr(JSC::MacroAssembler::NotEqual, + areg, JSC::MacroAssembler::ImmPtr(0)); + j.linkTo(loopHeadLabel, am); + + am->ret(); +#endif + +#if defined(ARCH_x86) + JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi; + // xor %edi,%edi + // add $0x7b,%edi + // add $0x141,%edi + // sub $0x1,%edi + // test %edi,%edi + // jne 0xf7f9700b + // ret + // so edi always winds up being zero + am->xorPtr(areg,areg); + am->addPtr(JSC::MacroAssembler::Imm32(123), areg); + am->addPtr(JSC::MacroAssembler::Imm32(321), areg); + + JSC::MacroAssembler::Label loopHeadLabel(am); + am->subPtr(JSC::MacroAssembler::Imm32(1), areg); + + JSC::MacroAssembler::Jump j + = am->branchPtr(JSC::MacroAssembler::NotEqual, + areg, JSC::MacroAssembler::ImmPtr(0)); + j.linkTo(loopHeadLabel, am); + + am->ret(); +#endif + +#if defined(ARCH_arm) + JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8; + // eors r8, r8, r8 + // adds r8, r8, #123 ; 0x7b + // mov r3, #256 ; 0x100 + // orr r3, r3, #65 ; 0x41 + // adds r8, r8, r3 + // subs r8, r8, #1 ; 0x1 + // ldr r3, [pc, #8] ; 0x40026028 + // cmp r8, r3 + // bne 0x40026014 + // mov pc, lr + // andeq r0, r0, r0 // DATA (0) + // andeq r0, r0, r4, lsl r0 // DATA (?? what's this for?) + // so r8 always winds up being zero + am->xorPtr(areg,areg); + am->addPtr(JSC::MacroAssembler::Imm32(123), areg); + am->addPtr(JSC::MacroAssembler::Imm32(321), areg); + + JSC::MacroAssembler::Label loopHeadLabel(am); + am->subPtr(JSC::MacroAssembler::Imm32(1), areg); + + JSC::MacroAssembler::Jump j + = am->branchPtr(JSC::MacroAssembler::NotEqual, + areg, JSC::MacroAssembler::ImmPtr(0)); + j.linkTo(loopHeadLabel, am); + + am->ret(); +#endif + + // prepare a link buffer, into which we can copy the completed insns + JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); + + // intermediate step .. get the pool suited for the size of code in 'am' + //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); + JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); + + // constructor for LinkBuffer asks ep to allocate r-x memory, + // then copies it there. + JSC::LinkBuffer patchBuffer(am, ep); + + // finalize + JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); + + // cr now holds a pointer to the final runnable code. + void* entry = cr.m_code.executableAddress(); + + printf("disas %p %p\n", + entry, (char*)entry + cr.m_size); + pre_run(); + + unsigned long result = 0x55555555; + +#if defined(ARCH_amd64) + // call the generated piece of code. It puts its result in r15. + __asm__ __volatile__( + "callq *%1" "\n\t" + "movq %%r15, %0" "\n" + :/*out*/ "=r"(result) + :/*in*/ "r"(entry) + :/*trash*/ "r15","cc" + ); +#endif +#if defined(ARCH_x86) + // call the generated piece of code. It puts its result in edi. + __asm__ __volatile__( + "calll *%1" "\n\t" + "movl %%edi, %0" "\n" + :/*out*/ "=r"(result) + :/*in*/ "r"(entry) + :/*trash*/ "edi","cc" + ); +#endif +#if defined(ARCH_arm) + // call the generated piece of code. It puts its result in r8. + __asm__ __volatile__( + "blx %1" "\n\t" + "mov %0, %%r8" "\n" + :/*out*/ "=r"(result) + :/*in*/ "r"(entry) + :/*trash*/ "r8","cc" + ); +#endif + + printf("\n"); + printf("value computed is %lu (expected 0)\n", result); + printf("\n"); + + delete eal; + delete am; +} + +#endif /* WTF_COMPILER_GCC */ + +///////////////////////////////////////////////////////////////// +//// test3 (if-then-else) +#if WTF_COMPILER_GCC + +void test3 ( void ) +{ + printf("\n------------ Test 3 (if-then-else) ------------\n\n" ); + + // Create new assembler + JSC::MacroAssembler* am = new JSC::MacroAssembler(); + +#if defined(ARCH_amd64) + JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15; + // mov $0x64,%r15d + // mov $0x0,%r11 + // cmp %r11,%r15 + // jne 0x7ff6d3e6a024 + // mov $0x40,%r15d + // jmpq 0x7ff6d3e6a02a + // mov $0x4,%r15d + // retq + // so r15 ends up being 4 + + // put a value in reg + am->move(JSC::MacroAssembler::Imm32(100), areg); + + // test, and conditionally jump to 'else' branch + JSC::MacroAssembler::Jump jToElse + = am->branchPtr(JSC::MacroAssembler::NotEqual, + areg, JSC::MacroAssembler::ImmPtr(0)); + + // 'then' branch + am->move(JSC::MacroAssembler::Imm32(64), areg); + JSC::MacroAssembler::Jump jToAfter + = am->jump(); + + // 'else' branch + JSC::MacroAssembler::Label elseLbl(am); + am->move(JSC::MacroAssembler::Imm32(4), areg); + + // after + JSC::MacroAssembler::Label afterLbl(am); + + am->ret(); +#endif + +#if defined(ARCH_x86) + JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi; + // mov $0x64,%edi + // test %edi,%edi + // jne 0xf7f22017 + // mov $0x40,%edi + // jmp 0xf7f2201c + // mov $0x4,%edi + // ret + // so edi ends up being 4 + + // put a value in reg + am->move(JSC::MacroAssembler::Imm32(100), areg); + + // test, and conditionally jump to 'else' branch + JSC::MacroAssembler::Jump jToElse + = am->branchPtr(JSC::MacroAssembler::NotEqual, + areg, JSC::MacroAssembler::ImmPtr(0)); + + // 'then' branch + am->move(JSC::MacroAssembler::Imm32(64), areg); + JSC::MacroAssembler::Jump jToAfter + = am->jump(); + + // 'else' branch + JSC::MacroAssembler::Label elseLbl(am); + am->move(JSC::MacroAssembler::Imm32(4), areg); + + // after + JSC::MacroAssembler::Label afterLbl(am); + + am->ret(); +#endif + +#if defined(ARCH_arm) + JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8; + // mov r8, #100 ; 0x64 + // ldr r3, [pc, #20] ; 0x40026020 + // cmp r8, r3 + // bne 0x40026018 + // mov r8, #64 ; 0x40 + // b 0x4002601c + // mov r8, #4 ; 0x4 + // mov pc, lr + // andeq r0, r0, r0 // DATA + // andeq r0, r0, r8, lsl r0 // DATA + // andeq r0, r0, r12, lsl r0 // DATA + // ldr r3, [r3, -r3] // DATA + // so r8 ends up being 4 + + // put a value in reg + am->move(JSC::MacroAssembler::Imm32(100), areg); + + // test, and conditionally jump to 'else' branch + JSC::MacroAssembler::Jump jToElse + = am->branchPtr(JSC::MacroAssembler::NotEqual, + areg, JSC::MacroAssembler::ImmPtr(0)); + + // 'then' branch + am->move(JSC::MacroAssembler::Imm32(64), areg); + JSC::MacroAssembler::Jump jToAfter + = am->jump(); + + // 'else' branch + JSC::MacroAssembler::Label elseLbl(am); + am->move(JSC::MacroAssembler::Imm32(4), areg); + + // after + JSC::MacroAssembler::Label afterLbl(am); + + am->ret(); +#endif + + // set branch targets appropriately + jToElse.linkTo(elseLbl, am); + jToAfter.linkTo(afterLbl, am); + + // prepare a link buffer, into which we can copy the completed insns + JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); + + // intermediate step .. get the pool suited for the size of code in 'am' + //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); + JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); + + // constructor for LinkBuffer asks ep to allocate r-x memory, + // then copies it there. + JSC::LinkBuffer patchBuffer(am, ep); + + // finalize + JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); + + // cr now holds a pointer to the final runnable code. + void* entry = cr.m_code.executableAddress(); + + printf("disas %p %p\n", + entry, (char*)entry + cr.m_size); + pre_run(); + + unsigned long result = 0x55555555; + +#if defined(ARCH_amd64) + // call the generated piece of code. It puts its result in r15. + __asm__ __volatile__( + "callq *%1" "\n\t" + "movq %%r15, %0" "\n" + :/*out*/ "=r"(result) + :/*in*/ "r"(entry) + :/*trash*/ "r15","cc" + ); +#endif +#if defined(ARCH_x86) + // call the generated piece of code. It puts its result in edi. + __asm__ __volatile__( + "calll *%1" "\n\t" + "movl %%edi, %0" "\n" + :/*out*/ "=r"(result) + :/*in*/ "r"(entry) + :/*trash*/ "edi","cc" + ); +#endif +#if defined(ARCH_arm) + // call the generated piece of code. It puts its result in r8. + __asm__ __volatile__( + "blx %1" "\n\t" + "mov %0, %%r8" "\n" + :/*out*/ "=r"(result) + :/*in*/ "r"(entry) + :/*trash*/ "r8","cc" + ); +#endif + + printf("\n"); + printf("value computed is %lu (expected 4)\n", result); + printf("\n"); + + delete eal; + delete am; +} + +#endif /* WTF_COMPILER_GCC */ + +///////////////////////////////////////////////////////////////// +//// test4 (callable function) + +void test4 ( void ) +{ + printf("\n------------ Test 4 (callable fn) ------------\n\n" ); + + // Create new assembler + JSC::MacroAssembler* am = new JSC::MacroAssembler(); + +#if defined(ARCH_amd64) + // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function + // push %rbp + // mov %rsp,%rbp + // push %rbx + // push %r12 + // push %r13 + // push %r14 + // push %r15 + // xor %rax,%rax + // add $0x7b,%rax + // add $0x141,%rax + // pop %r15 + // pop %r14 + // pop %r13 + // pop %r12 + // pop %rbx + // mov %rbp,%rsp + // pop %rbp + // retq + // callable as a normal function, returns 444 + + JSC::X86Registers::RegisterID rreg = JSC::X86Registers::eax; + am->push(JSC::X86Registers::ebp); + am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); + am->push(JSC::X86Registers::ebx); + am->push(JSC::X86Registers::r12); + am->push(JSC::X86Registers::r13); + am->push(JSC::X86Registers::r14); + am->push(JSC::X86Registers::r15); + + am->xorPtr(rreg,rreg); + am->addPtr(JSC::MacroAssembler::Imm32(123), rreg); + am->addPtr(JSC::MacroAssembler::Imm32(321), rreg); + + am->pop(JSC::X86Registers::r15); + am->pop(JSC::X86Registers::r14); + am->pop(JSC::X86Registers::r13); + am->pop(JSC::X86Registers::r12); + am->pop(JSC::X86Registers::ebx); + am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); + am->pop(JSC::X86Registers::ebp); + am->ret(); +#endif + +#if defined(ARCH_x86) + // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function + // push %ebp + // mov %esp,%ebp + // push %ebx + // push %esi + // push %edi + // xor %eax,%eax + // add $0x7b,%eax + // add $0x141,%eax + // pop %edi + // pop %esi + // pop %ebx + // mov %ebp,%esp + // pop %ebp + // ret + // callable as a normal function, returns 444 + + JSC::X86Registers::RegisterID rreg = JSC::X86Registers::eax; + + am->push(JSC::X86Registers::ebp); + am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); + am->push(JSC::X86Registers::ebx); + am->push(JSC::X86Registers::esi); + am->push(JSC::X86Registers::edi); + + am->xorPtr(rreg,rreg); + am->addPtr(JSC::MacroAssembler::Imm32(123), rreg); + am->addPtr(JSC::MacroAssembler::Imm32(321), rreg); + + am->pop(JSC::X86Registers::edi); + am->pop(JSC::X86Registers::esi); + am->pop(JSC::X86Registers::ebx); + am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); + am->pop(JSC::X86Registers::ebp); + am->ret(); +#endif + +#if defined(ARCH_arm) + // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function + // push {r4} ; (str r4, [sp, #-4]!) + // push {r5} ; (str r5, [sp, #-4]!) + // push {r6} ; (str r6, [sp, #-4]!) + // push {r7} ; (str r7, [sp, #-4]!) + // push {r8} ; (str r8, [sp, #-4]!) + // push {r9} ; (str r9, [sp, #-4]!) + // push {r10} ; (str r10, [sp, #-4]!) + // push {r11} ; (str r11, [sp, #-4]!) + // eors r0, r0, r0 + // adds r0, r0, #123 ; 0x7b + // mov r3, #256 ; 0x100 + // orr r3, r3, #65 ; 0x41 + // adds r0, r0, r3 + // pop {r11} ; (ldr r11, [sp], #4) + // pop {r10} ; (ldr r10, [sp], #4) + // pop {r9} ; (ldr r9, [sp], #4) + // pop {r8} ; (ldr r8, [sp], #4) + // pop {r7} ; (ldr r7, [sp], #4) + // pop {r6} ; (ldr r6, [sp], #4) + // pop {r5} ; (ldr r5, [sp], #4) + // pop {r4} ; (ldr r4, [sp], #4) + // mov pc, lr + // callable as a normal function, returns 444 + + JSC::ARMRegisters::RegisterID rreg = JSC::ARMRegisters::r0; + + am->push(JSC::ARMRegisters::r4); + am->push(JSC::ARMRegisters::r5); + am->push(JSC::ARMRegisters::r6); + am->push(JSC::ARMRegisters::r7); + am->push(JSC::ARMRegisters::r8); + am->push(JSC::ARMRegisters::r9); + am->push(JSC::ARMRegisters::r10); + am->push(JSC::ARMRegisters::r11); + + am->xorPtr(rreg,rreg); + am->addPtr(JSC::MacroAssembler::Imm32(123), rreg); + am->addPtr(JSC::MacroAssembler::Imm32(321), rreg); + + am->pop(JSC::ARMRegisters::r11); + am->pop(JSC::ARMRegisters::r10); + am->pop(JSC::ARMRegisters::r9); + am->pop(JSC::ARMRegisters::r8); + am->pop(JSC::ARMRegisters::r7); + am->pop(JSC::ARMRegisters::r6); + am->pop(JSC::ARMRegisters::r5); + am->pop(JSC::ARMRegisters::r4); + + am->ret(); +#endif + + // prepare a link buffer, into which we can copy the completed insns + JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); + + // intermediate step .. get the pool suited for the size of code in 'am' + //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); + JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); + + // constructor for LinkBuffer asks ep to allocate r-x memory, + // then copies it there. + JSC::LinkBuffer patchBuffer(am, ep); + + // now fix up any branches/calls + //JSC::FunctionPtr target = JSC::FunctionPtr::FunctionPtr( &cube ); + + // finalize + JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); + + // cr now holds a pointer to the final runnable code. + void* entry = cr.m_code.executableAddress(); + + printf("disas %p %p\n", + entry, (char*)entry + cr.m_size); + pre_run(); + + // call the function + unsigned long (*fn)(void) = (unsigned long (*)())entry; + unsigned long result = fn(); + + printf("\n"); + printf("value computed is %lu (expected 444)\n", result); + printf("\n"); + + delete eal; + delete am; +} + + +///////////////////////////////////////////////////////////////// +//// test5 (call in, out, repatch) + +// a function which we will call from the JIT generated code +unsigned long cube ( unsigned long x ) { return x * x * x; } +unsigned long square ( unsigned long x ) { return x * x; } + +void test5 ( void ) +{ + printf("\n--------- Test 5 (call in, out, repatch) ---------\n\n" ); + + // Create new assembler + JSC::MacroAssembler* am = new JSC::MacroAssembler(); + JSC::MacroAssembler::Call cl; + ptrdiff_t offset_of_call_insn; + +#if defined(ARCH_amd64) + // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function + // and then call a non-JIT-generated helper from within + // this code + // push %rbp + // mov %rsp,%rbp + // push %rbx + // push %r12 + // push %r13 + // push %r14 + // push %r15 + // mov $0x9,%edi + // mov $0x40187e,%r11 + // callq *%r11 + // pop %r15 + // pop %r14 + // pop %r13 + // pop %r12 + // pop %rbx + // mov %rbp,%rsp + // pop %rbp + // retq + JSC::MacroAssembler::Label startOfFnLbl(am); + am->push(JSC::X86Registers::ebp); + am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); + am->push(JSC::X86Registers::ebx); + am->push(JSC::X86Registers::r12); + am->push(JSC::X86Registers::r13); + am->push(JSC::X86Registers::r14); + am->push(JSC::X86Registers::r15); + + // let's compute cube(9). Move $9 to the first arg reg. + am->move(JSC::MacroAssembler::Imm32(9), JSC::X86Registers::edi); + cl = am->JSC::MacroAssembler::call(); + + // result is now in %rax. Leave it ther and just return. + + am->pop(JSC::X86Registers::r15); + am->pop(JSC::X86Registers::r14); + am->pop(JSC::X86Registers::r13); + am->pop(JSC::X86Registers::r12); + am->pop(JSC::X86Registers::ebx); + am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); + am->pop(JSC::X86Registers::ebp); + am->ret(); + + offset_of_call_insn + = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl); + if (0) printf("XXXXXXXX offset = %lu\n", offset_of_call_insn); +#endif + +#if defined(ARCH_x86) + // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function + // and then call a non-JIT-generated helper from within + // this code + // push %ebp + // mov %esp,%ebp + // push %ebx + // push %esi + // push %edi + // push $0x9 + // call 0x80490e9 <_Z4cubem> + // add $0x4,%esp + // pop %edi + // pop %esi + // pop %ebx + // mov %ebp,%esp + // pop %ebp + // ret + JSC::MacroAssembler::Label startOfFnLbl(am); + am->push(JSC::X86Registers::ebp); + am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); + am->push(JSC::X86Registers::ebx); + am->push(JSC::X86Registers::esi); + am->push(JSC::X86Registers::edi); + + // let's compute cube(9). Push $9 on the stack. + am->push(JSC::MacroAssembler::Imm32(9)); + cl = am->JSC::MacroAssembler::call(); + am->addPtr(JSC::MacroAssembler::Imm32(4), JSC::X86Registers::esp); + // result is now in %eax. Leave it there and just return. + + am->pop(JSC::X86Registers::edi); + am->pop(JSC::X86Registers::esi); + am->pop(JSC::X86Registers::ebx); + am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); + am->pop(JSC::X86Registers::ebp); + am->ret(); + + offset_of_call_insn + = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl); + if (0) printf("XXXXXXXX offset = %lu\n", + (unsigned long)offset_of_call_insn); +#endif + +#if defined(ARCH_arm) + // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function + // push {r4} ; (str r4, [sp, #-4]!) + // push {r5} ; (str r5, [sp, #-4]!) + // push {r6} ; (str r6, [sp, #-4]!) + // push {r7} ; (str r7, [sp, #-4]!) + // push {r8} ; (str r8, [sp, #-4]!) + // push {r9} ; (str r9, [sp, #-4]!) + // push {r10} ; (str r10, [sp, #-4]!) + // push {r11} ; (str r11, [sp, #-4]!) + // eors r0, r0, r0 + // adds r0, r0, #123 ; 0x7b + // mov r3, #256 ; 0x100 + // orr r3, r3, #65 ; 0x41 + // adds r0, r0, r3 + // pop {r11} ; (ldr r11, [sp], #4) + // pop {r10} ; (ldr r10, [sp], #4) + // pop {r9} ; (ldr r9, [sp], #4) + // pop {r8} ; (ldr r8, [sp], #4) + // pop {r7} ; (ldr r7, [sp], #4) + // pop {r6} ; (ldr r6, [sp], #4) + // pop {r5} ; (ldr r5, [sp], #4) + // pop {r4} ; (ldr r4, [sp], #4) + // mov pc, lr + // callable as a normal function, returns 444 + JSC::MacroAssembler::Label startOfFnLbl(am); + am->push(JSC::ARMRegisters::r4); + am->push(JSC::ARMRegisters::r5); + am->push(JSC::ARMRegisters::r6); + am->push(JSC::ARMRegisters::r7); + am->push(JSC::ARMRegisters::r8); + am->push(JSC::ARMRegisters::r9); + am->push(JSC::ARMRegisters::r10); + am->push(JSC::ARMRegisters::r11); + am->push(JSC::ARMRegisters::lr); + + // let's compute cube(9). Get $9 into r0. + am->move(JSC::MacroAssembler::Imm32(9), JSC::ARMRegisters::r0); + cl = am->JSC::MacroAssembler::call(); + // result is now in r0. Leave it there and just return. + + am->pop(JSC::ARMRegisters::lr); + am->pop(JSC::ARMRegisters::r11); + am->pop(JSC::ARMRegisters::r10); + am->pop(JSC::ARMRegisters::r9); + am->pop(JSC::ARMRegisters::r8); + am->pop(JSC::ARMRegisters::r7); + am->pop(JSC::ARMRegisters::r6); + am->pop(JSC::ARMRegisters::r5); + am->pop(JSC::ARMRegisters::r4); + am->ret(); + + offset_of_call_insn + = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl); + if (0) printf("XXXXXXXX offset = %lu\n", + (unsigned long)offset_of_call_insn); +#endif + + // prepare a link buffer, into which we can copy the completed insns + JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); + + // intermediate step .. get the pool suited for the size of code in 'am' + //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); + JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); + + // constructor for LinkBuffer asks ep to allocate r-x memory, + // then copies it there. + JSC::LinkBuffer patchBuffer(am, ep); + + // now fix up any branches/calls + JSC::FunctionPtr target = JSC::FunctionPtr::FunctionPtr( &cube ); + patchBuffer.link(cl, target); + + JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); + + // cr now holds a pointer to the final runnable code. + void* entry = cr.m_code.executableAddress(); + + printf("disas %p %p\n", + entry, (char*)entry + cr.m_size); + + + pre_run(); + + printf("\n"); + + unsigned long (*fn)() = (unsigned long(*)())entry; + unsigned long result = fn(); + + printf("value computed is %lu (expected 729)\n", result); + printf("\n"); + + // now repatch the call in the JITted code to go elsewhere + JSC::JITCode jc = JSC::JITCode::JITCode(entry, cr.m_size); + JSC::CodeBlock cb = JSC::CodeBlock::CodeBlock(jc); + + // the address of the call insn, that we want to prod + JSC::MacroAssemblerCodePtr cp + = JSC::MacroAssemblerCodePtr( ((char*)entry) + offset_of_call_insn ); + + JSC::RepatchBuffer repatchBuffer(&cb); + repatchBuffer.relink( JSC::CodeLocationCall(cp), + JSC::FunctionPtr::FunctionPtr( &square )); + + result = fn(); + printf("value computed is %lu (expected 81)\n", result); + printf("\n\n"); + + delete eal; + delete am; +} + +///////////////////////////////////////////////////////////////// + +int main ( void ) +{ +#if WTF_COMPILER_GCC + test1(); + test2(); + test3(); +#endif + test4(); + test5(); + return 0; +} diff --git a/js/src/assembler/assembler/ARMAssembler.cpp b/js/src/assembler/assembler/ARMAssembler.cpp new file mode 100644 index 0000000..ba7cec2 --- /dev/null +++ b/js/src/assembler/assembler/ARMAssembler.cpp @@ -0,0 +1,447 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2009 University of Szeged + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#include "assembler/wtf/Platform.h" + +#if ENABLE_ASSEMBLER && WTF_CPU_ARM_TRADITIONAL + +#include "ARMAssembler.h" + +namespace JSC { + +// Patching helpers + +void ARMAssembler::patchConstantPoolLoad(void* loadAddr, void* constPoolAddr) +{ + ARMWord *ldr = reinterpret_cast(loadAddr); + ARMWord diff = reinterpret_cast(constPoolAddr) - ldr; + ARMWord index = (*ldr & 0xfff) >> 1; + + ASSERT(diff >= 1); + if (diff >= 2 || index > 0) { + diff = (diff + index - 2) * sizeof(ARMWord); + ASSERT(diff <= 0xfff); + *ldr = (*ldr & ~0xfff) | diff; + } else + *ldr = (*ldr & ~(0xfff | ARMAssembler::DT_UP)) | sizeof(ARMWord); +} + +// Handle immediates + +ARMWord ARMAssembler::getOp2(ARMWord imm) +{ + int rol; + + if (imm <= 0xff) + return OP2_IMM | imm; + + if ((imm & 0xff000000) == 0) { + imm <<= 8; + rol = 8; + } + else { + imm = (imm << 24) | (imm >> 8); + rol = 0; + } + + if ((imm & 0xff000000) == 0) { + imm <<= 8; + rol += 4; + } + + if ((imm & 0xf0000000) == 0) { + imm <<= 4; + rol += 2; + } + + if ((imm & 0xc0000000) == 0) { + imm <<= 2; + rol += 1; + } + + if ((imm & 0x00ffffff) == 0) + return OP2_IMM | (imm >> 24) | (rol << 8); + + return INVALID_IMM; +} + +int ARMAssembler::genInt(int reg, ARMWord imm, bool positive) +{ + // Step1: Search a non-immediate part + ARMWord mask; + ARMWord imm1; + ARMWord imm2; + int rol; + + mask = 0xff000000; + rol = 8; + while(1) { + if ((imm & mask) == 0) { + imm = (imm << rol) | (imm >> (32 - rol)); + rol = 4 + (rol >> 1); + break; + } + rol += 2; + mask >>= 2; + if (mask & 0x3) { + // rol 8 + imm = (imm << 8) | (imm >> 24); + mask = 0xff00; + rol = 24; + while (1) { + if ((imm & mask) == 0) { + imm = (imm << rol) | (imm >> (32 - rol)); + rol = (rol >> 1) - 8; + break; + } + rol += 2; + mask >>= 2; + if (mask & 0x3) + return 0; + } + break; + } + } + + ASSERT((imm & 0xff) == 0); + + if ((imm & 0xff000000) == 0) { + imm1 = OP2_IMM | ((imm >> 16) & 0xff) | (((rol + 4) & 0xf) << 8); + imm2 = OP2_IMM | ((imm >> 8) & 0xff) | (((rol + 8) & 0xf) << 8); + } else if (imm & 0xc0000000) { + imm1 = OP2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8); + imm <<= 8; + rol += 4; + + if ((imm & 0xff000000) == 0) { + imm <<= 8; + rol += 4; + } + + if ((imm & 0xf0000000) == 0) { + imm <<= 4; + rol += 2; + } + + if ((imm & 0xc0000000) == 0) { + imm <<= 2; + rol += 1; + } + + if ((imm & 0x00ffffff) == 0) + imm2 = OP2_IMM | (imm >> 24) | ((rol & 0xf) << 8); + else + return 0; + } else { + if ((imm & 0xf0000000) == 0) { + imm <<= 4; + rol += 2; + } + + if ((imm & 0xc0000000) == 0) { + imm <<= 2; + rol += 1; + } + + imm1 = OP2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8); + imm <<= 8; + rol += 4; + + if ((imm & 0xf0000000) == 0) { + imm <<= 4; + rol += 2; + } + + if ((imm & 0xc0000000) == 0) { + imm <<= 2; + rol += 1; + } + + if ((imm & 0x00ffffff) == 0) + imm2 = OP2_IMM | (imm >> 24) | ((rol & 0xf) << 8); + else + return 0; + } + + if (positive) { + mov_r(reg, imm1); + orr_r(reg, reg, imm2); + } else { + mvn_r(reg, imm1); + bic_r(reg, reg, imm2); + } + + return 1; +} + +#ifdef __GNUC__ +// If the result of this function isn't used, the caller should probably be +// using movImm. +__attribute__((warn_unused_result)) +#endif +ARMWord ARMAssembler::getImm(ARMWord imm, int tmpReg, bool invert) +{ + ARMWord tmp; + + // Do it by 1 instruction + tmp = getOp2(imm); + if (tmp != INVALID_IMM) + return tmp; + + tmp = getOp2(~imm); + if (tmp != INVALID_IMM) { + if (invert) + return tmp | OP2_INV_IMM; + mvn_r(tmpReg, tmp); + return tmpReg; + } + + return encodeComplexImm(imm, tmpReg); +} + +void ARMAssembler::moveImm(ARMWord imm, int dest) +{ + ARMWord tmp; + + // Do it by 1 instruction + tmp = getOp2(imm); + if (tmp != INVALID_IMM) { + mov_r(dest, tmp); + return; + } + + tmp = getOp2(~imm); + if (tmp != INVALID_IMM) { + mvn_r(dest, tmp); + return; + } + + encodeComplexImm(imm, dest); +} + +ARMWord ARMAssembler::encodeComplexImm(ARMWord imm, int dest) +{ +#if WTF_ARM_ARCH_VERSION >= 7 + ARMWord tmp = getImm16Op2(imm); + if (tmp != INVALID_IMM) { + movw_r(dest, tmp); + return dest; + } + movw_r(dest, getImm16Op2(imm & 0xffff)); + movt_r(dest, getImm16Op2(imm >> 16)); + return dest; +#else + // Do it by 2 instruction + if (genInt(dest, imm, true)) + return dest; + if (genInt(dest, ~imm, false)) + return dest; + + ldr_imm(dest, imm); + return dest; +#endif +} + +// Memory load/store helpers + +void ARMAssembler::dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset) +{ + if (offset >= 0) { + if (offset <= 0xfff) + dtr_u(isLoad, srcDst, base, offset); + else if (offset <= 0xfffff) { + add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8)); + dtr_u(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff)); + } else { + moveImm(offset, ARMRegisters::S0); + dtr_ur(isLoad, srcDst, base, ARMRegisters::S0); + } + } else { + offset = -offset; + if (offset <= 0xfff) + dtr_d(isLoad, srcDst, base, offset); + else if (offset <= 0xfffff) { + sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8)); + dtr_d(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff)); + } else { + moveImm(offset, ARMRegisters::S0); + dtr_dr(isLoad, srcDst, base, ARMRegisters::S0); + } + } +} + +void ARMAssembler::dataTransfer8(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset) +{ + if (offset >= 0) { + if (offset <= 0xfff) + dtrb_u(isLoad, srcDst, base, offset); + else if (offset <= 0xfffff) { + add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8)); + dtrb_u(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff)); + } else { + moveImm(offset, ARMRegisters::S0); + dtrb_ur(isLoad, srcDst, base, ARMRegisters::S0); + } + } else { + offset = -offset; + if (offset <= 0xfff) + dtrb_d(isLoad, srcDst, base, offset); + else if (offset <= 0xfffff) { + sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8)); + dtrb_d(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff)); + } else { + moveImm(offset, ARMRegisters::S0); + dtrb_dr(isLoad, srcDst, base, ARMRegisters::S0); + } + } +} + +void ARMAssembler::baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset) +{ + ARMWord op2; + + ASSERT(scale >= 0 && scale <= 3); + op2 = lsl(index, scale); + + if (offset >= 0 && offset <= 0xfff) { + add_r(ARMRegisters::S0, base, op2); + dtr_u(isLoad, srcDst, ARMRegisters::S0, offset); + return; + } + if (offset <= 0 && offset >= -0xfff) { + add_r(ARMRegisters::S0, base, op2); + dtr_d(isLoad, srcDst, ARMRegisters::S0, -offset); + return; + } + + ldr_un_imm(ARMRegisters::S0, offset); + add_r(ARMRegisters::S0, ARMRegisters::S0, op2); + dtr_ur(isLoad, srcDst, base, ARMRegisters::S0); +} + +void ARMAssembler::doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset) +{ + if (offset & 0x3) { + if (offset <= 0x3ff && offset >= 0) { + fdtr_u(isLoad, srcDst, base, offset >> 2); + return; + } + if (offset <= 0x3ffff && offset >= 0) { + add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | (11 << 8)); + fdtr_u(isLoad, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff); + return; + } + offset = -offset; + + if (offset <= 0x3ff && offset >= 0) { + fdtr_d(isLoad, srcDst, base, offset >> 2); + return; + } + if (offset <= 0x3ffff && offset >= 0) { + sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | (11 << 8)); + fdtr_d(isLoad, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff); + return; + } + offset = -offset; + } + + // TODO: This is broken in the case that offset is unaligned. VFP can never + // perform unaligned accesses, even from an unaligned register base. (NEON + // can, but VFP isn't NEON. It is not advisable to interleave a NEON load + // with VFP code, so the best solution here is probably to perform an + // unaligned integer load, then move the result into VFP using VMOV.) + ASSERT((offset & 0x3) == 0); + + ldr_un_imm(ARMRegisters::S0, offset); + add_r(ARMRegisters::S0, ARMRegisters::S0, base); + fdtr_u(isLoad, srcDst, ARMRegisters::S0, 0); +} + +// Fix up the offsets and literal-pool loads in buffer. The buffer should +// already contain the code from m_buffer. +inline void ARMAssembler::fixUpOffsets(void * buffer) +{ + char * data = reinterpret_cast(buffer); + for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) { + // The last bit is set if the constant must be placed on constant pool. + int pos = (*iter) & (~0x1); + ARMWord* ldrAddr = reinterpret_cast(data + pos); + ARMWord* addr = getLdrImmAddress(ldrAddr); + if (*addr != InvalidBranchTarget) { +// The following is disabled for JM because we patch some branches after +// calling fixUpOffset, and the branch patcher doesn't know how to handle 'B' +// instructions. +#if 0 + if (!(*iter & 1)) { + int diff = reinterpret_cast(data + *addr) - (ldrAddr + DefaultPrefetching); + + if ((diff <= BOFFSET_MAX && diff >= BOFFSET_MIN)) { + *ldrAddr = B | getConditionalField(*ldrAddr) | (diff & BRANCH_MASK); + continue; + } + } +#endif + *addr = reinterpret_cast(data + *addr); + } + } +} + +void* ARMAssembler::executableCopy(ExecutablePool* allocator) +{ + // 64-bit alignment is required for next constant pool and JIT code as well + m_buffer.flushWithoutBarrier(true); + if (m_buffer.uncheckedSize() & 0x7) + bkpt(0); + + void * data = m_buffer.executableCopy(allocator); + if (data) + fixUpOffsets(data); + return data; +} + +// This just dumps the code into the specified buffer, fixing up absolute +// offsets and literal pool loads as it goes. The buffer is assumed to be large +// enough to hold the code, and any pre-existing literal pool is assumed to +// have been flushed. +void* ARMAssembler::executableCopy(void * buffer) +{ + if (m_buffer.oom()) + return NULL; + + ASSERT(m_buffer.sizeOfConstantPool() == 0); + + memcpy(buffer, m_buffer.data(), m_buffer.size()); + fixUpOffsets(buffer); + return buffer; +} + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) diff --git a/js/src/assembler/assembler/ARMAssembler.h b/js/src/assembler/assembler/ARMAssembler.h new file mode 100644 index 0000000..b0b590d --- /dev/null +++ b/js/src/assembler/assembler/ARMAssembler.h @@ -0,0 +1,1418 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2009, 2010 University of Szeged + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef ARMAssembler_h +#define ARMAssembler_h + +#include "assembler/wtf/Platform.h" + +// Some debug code uses s(n)printf for instruction logging. +#include + +#if ENABLE_ASSEMBLER && WTF_CPU_ARM_TRADITIONAL + +#include "AssemblerBufferWithConstantPool.h" +#include "assembler/wtf/Assertions.h" + +#include "methodjit/Logging.h" +#define IPFX " %s" +#define ISPFX " " +#ifdef JS_METHODJIT_SPEW +# define MAYBE_PAD (isOOLPath ? "> " : "") +# define FIXME_INSN_PRINTING \ + do { \ + js::JaegerSpew(js::JSpew_Insns, \ + IPFX "FIXME insn printing %s:%d\n", \ + MAYBE_PAD, \ + __FILE__, __LINE__); \ + } while (0) +#else +# define MAYBE_PAD "" +# define FIXME_INSN_PRINTING ((void) 0) +#endif + +// TODO: We don't print the condition code in our JaegerSpew lines. Doing this +// is awkward whilst maintaining a consistent field width. + +namespace JSC { + + typedef uint32_t ARMWord; + + namespace ARMRegisters { + typedef enum { + r0 = 0, + r1, + r2, + r3, + S0 = r3, + r4, + r5, + r6, + r7, + r8, + S1 = r8, + r9, + r10, + r11, + r12, + ip = r12, + r13, + sp = r13, + r14, + lr = r14, + r15, + pc = r15 + } RegisterID; + + typedef enum { + d0, + d1, + d2, + d3, + SD0 = d3, + d4, + d5, + d6, + d7, + d8, + d9, + d10, + d11, + d12, + d13, + d14, + d15, + d16, + d17, + d18, + d19, + d20, + d21, + d22, + d23, + d24, + d25, + d26, + d27, + d28, + d29, + d30, + d31 + } FPRegisterID; + + } // namespace ARMRegisters + + class ARMAssembler { + public: + +#ifdef JS_METHODJIT_SPEW + bool isOOLPath; + // Assign a default value to keep Valgrind quiet. + ARMAssembler() : isOOLPath(false) { } +#else + ARMAssembler() { } +#endif + + typedef ARMRegisters::RegisterID RegisterID; + typedef ARMRegisters::FPRegisterID FPRegisterID; + typedef AssemblerBufferWithConstantPool<2048, 4, 4, ARMAssembler> ARMBuffer; + typedef SegmentedVector Jumps; + + unsigned char *buffer() const { return m_buffer.buffer(); } + bool oom() const { return m_buffer.oom(); } + + // ARM conditional constants + typedef enum { + EQ = 0x00000000, // Zero + NE = 0x10000000, // Non-zero + CS = 0x20000000, + CC = 0x30000000, + MI = 0x40000000, + PL = 0x50000000, + VS = 0x60000000, + VC = 0x70000000, + HI = 0x80000000, + LS = 0x90000000, + GE = 0xa0000000, + LT = 0xb0000000, + GT = 0xc0000000, + LE = 0xd0000000, + AL = 0xe0000000 + } Condition; + + // ARM instruction constants + enum { + AND = (0x0 << 21), + EOR = (0x1 << 21), + SUB = (0x2 << 21), + RSB = (0x3 << 21), + ADD = (0x4 << 21), + ADC = (0x5 << 21), + SBC = (0x6 << 21), + RSC = (0x7 << 21), + TST = (0x8 << 21), + TEQ = (0x9 << 21), + CMP = (0xa << 21), + CMN = (0xb << 21), + ORR = (0xc << 21), + MOV = (0xd << 21), + BIC = (0xe << 21), + MVN = (0xf << 21), + MUL = 0x00000090, + MULL = 0x00c00090, + FCPYD = 0x0eb00b40, + FADDD = 0x0e300b00, + FNEGD = 0x0eb10b40, + FDIVD = 0x0e800b00, + FSUBD = 0x0e300b40, + FMULD = 0x0e200b00, + FCMPD = 0x0eb40b40, + FSQRTD = 0x0eb10bc0, + DTR = 0x05000000, + LDRH = 0x00100090, + STRH = 0x00000090, + STMDB = 0x09200000, + LDMIA = 0x08b00000, + FDTR = 0x0d000b00, + B = 0x0a000000, + BL = 0x0b000000 +#if WTF_ARM_ARCH_VERSION >= 5 || defined(__ARM_ARCH_4T__) + ,BX = 0x012fff10 +#endif + ,FMSR = 0x0e000a10, + FMRS = 0x0e100a10, + FSITOD = 0x0eb80bc0, + FTOSID = 0x0ebd0b40, + FTOSIZD = 0x0ebd0bc0, + FMSTAT = 0x0ef1fa10 +#if WTF_ARM_ARCH_VERSION >= 5 + ,CLZ = 0x016f0f10, + BKPT = 0xe1200070, + BLX = 0x012fff30 +#endif +#if WTF_ARM_ARCH_VERSION >= 7 + ,MOVW = 0x03000000, + MOVT = 0x03400000 +#endif + }; + + enum { + OP2_IMM = (1 << 25), + OP2_IMMh = (1 << 22), + OP2_INV_IMM = (1 << 26), + SET_CC = (1 << 20), + OP2_OFSREG = (1 << 25), + DT_UP = (1 << 23), + DT_BYTE = (1 << 22), + DT_WB = (1 << 21), + // This flag is inlcuded in LDR and STR + DT_PRE = (1 << 24), + HDT_UH = (1 << 5), + DT_LOAD = (1 << 20) + }; + + // Masks of ARM instructions + enum { + BRANCH_MASK = 0x00ffffff, + NONARM = 0xf0000000, + SDT_MASK = 0x0c000000, + SDT_OFFSET_MASK = 0xfff + }; + + enum { + BOFFSET_MIN = -0x00800000, + BOFFSET_MAX = 0x007fffff, + SDT = 0x04000000 + }; + + enum { + padForAlign8 = (int)0x00, + padForAlign16 = (int)0x0000, + padForAlign32 = (int)0xe12fff7f // 'bkpt 0xffff' + }; + + typedef enum { + LSL = 0, + LSR = 1, + ASR = 2, + ROR = 3 + } Shift; + + static const ARMWord INVALID_IMM = 0xf0000000; + static const ARMWord InvalidBranchTarget = 0xffffffff; + static const int DefaultPrefetching = 2; + + class JmpSrc { + friend class ARMAssembler; + public: + JmpSrc() + : m_offset(-1) + { + } + + private: + JmpSrc(int offset) + : m_offset(offset) + { + } + + int m_offset; + }; + + class JmpDst { + friend class ARMAssembler; + public: + JmpDst() + : m_offset(-1) + , m_used(false) + { + } + + bool isUsed() const { return m_used; } + void used() { m_used = true; } + bool isValid() const { return m_offset != -1; } + private: + JmpDst(int offset) + : m_offset(offset) + , m_used(false) + { + ASSERT(m_offset == offset); + } + + int m_offset : 31; + bool m_used : 1; + }; + + // Instruction formating + + void emitInst(ARMWord op, int rd, int rn, ARMWord op2) + { + ASSERT ( ((op2 & ~OP2_IMM) <= 0xfff) || (((op2 & ~OP2_IMMh) <= 0xfff)) ); + m_buffer.putInt(op | RN(rn) | RD(rd) | op2); + } + + void and_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("and", cc, rd, rn, op2); + emitInst(static_cast(cc) | AND, rd, rn, op2); + } + + void ands_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("ands", cc, rd, rn, op2); + emitInst(static_cast(cc) | AND | SET_CC, rd, rn, op2); + } + + void eor_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("eor", cc, rd, rn, op2); + emitInst(static_cast(cc) | EOR, rd, rn, op2); + } + + void eors_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("eors", cc, rd, rn, op2); + emitInst(static_cast(cc) | EOR | SET_CC, rd, rn, op2); + } + + void sub_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("sub", cc, rd, rn, op2); + emitInst(static_cast(cc) | SUB, rd, rn, op2); + } + + void subs_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("subs", cc, rd, rn, op2); + emitInst(static_cast(cc) | SUB | SET_CC, rd, rn, op2); + } + + void rsb_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("rsb", cc, rd, rn, op2); + emitInst(static_cast(cc) | RSB, rd, rn, op2); + } + + void rsbs_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("rsbs", cc, rd, rn, op2); + emitInst(static_cast(cc) | RSB | SET_CC, rd, rn, op2); + } + + void add_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("add", cc, rd, rn, op2); + emitInst(static_cast(cc) | ADD, rd, rn, op2); + } + + void adds_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("adds", cc, rd, rn, op2); + emitInst(static_cast(cc) | ADD | SET_CC, rd, rn, op2); + } + + void adc_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("adc", cc, rd, rn, op2); + emitInst(static_cast(cc) | ADC, rd, rn, op2); + } + + void adcs_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("adcs", cc, rd, rn, op2); + emitInst(static_cast(cc) | ADC | SET_CC, rd, rn, op2); + } + + void sbc_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("sbc", cc, rd, rn, op2); + emitInst(static_cast(cc) | SBC, rd, rn, op2); + } + + void sbcs_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("sbcs", cc, rd, rn, op2); + emitInst(static_cast(cc) | SBC | SET_CC, rd, rn, op2); + } + + void rsc_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("rsc", cc, rd, rn, op2); + emitInst(static_cast(cc) | RSC, rd, rn, op2); + } + + void rscs_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("rscs", cc, rd, rn, op2); + emitInst(static_cast(cc) | RSC | SET_CC, rd, rn, op2); + } + + void tst_r(int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("tst", cc, rn, op2); + emitInst(static_cast(cc) | TST | SET_CC, 0, rn, op2); + } + + void teq_r(int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("teq", cc, rn, op2); + emitInst(static_cast(cc) | TEQ | SET_CC, 0, rn, op2); + } + + void cmp_r(int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("cmp", cc, rn, op2); + emitInst(static_cast(cc) | CMP | SET_CC, 0, rn, op2); + } + + void cmn_r(int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("cmn", cc, rn, op2); + emitInst(static_cast(cc) | CMN | SET_CC, 0, rn, op2); + } + + void orr_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("orr", cc, rd, rn, op2); + emitInst(static_cast(cc) | ORR, rd, rn, op2); + } + + void orrs_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("orrs", cc, rd, rn, op2); + emitInst(static_cast(cc) | ORR | SET_CC, rd, rn, op2); + } + + void mov_r(int rd, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("mov", cc, rd, op2); + emitInst(static_cast(cc) | MOV, rd, ARMRegisters::r0, op2); + } + +#if WTF_ARM_ARCH_VERSION >= 7 + void movw_r(int rd, ARMWord op2, Condition cc = AL) + { + ASSERT((op2 | 0xf0fff) == 0xf0fff); + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, 0x%04x\n", MAYBE_PAD, "movw", nameGpReg(rd), (op2 & 0xfff) | ((op2 >> 4) & 0xf000)); + m_buffer.putInt(static_cast(cc) | MOVW | RD(rd) | op2); + } + + void movt_r(int rd, ARMWord op2, Condition cc = AL) + { + ASSERT((op2 | 0xf0fff) == 0xf0fff); + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, 0x%04x\n", MAYBE_PAD, "movt", nameGpReg(rd), (op2 & 0xfff) | ((op2 >> 4) & 0xf000)); + m_buffer.putInt(static_cast(cc) | MOVT | RD(rd) | op2); + } +#endif + + void movs_r(int rd, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("movs", cc, rd, op2); + emitInst(static_cast(cc) | MOV | SET_CC, rd, ARMRegisters::r0, op2); + } + + void bic_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("bic", cc, rd, rn, op2); + emitInst(static_cast(cc) | BIC, rd, rn, op2); + } + + void bics_r(int rd, int rn, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("bics", cc, rd, rn, op2); + emitInst(static_cast(cc) | BIC | SET_CC, rd, rn, op2); + } + + void mvn_r(int rd, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("mvn", cc, rd, op2); + emitInst(static_cast(cc) | MVN, rd, ARMRegisters::r0, op2); + } + + void mvns_r(int rd, ARMWord op2, Condition cc = AL) + { + spewInsWithOp2("mvns", cc, rd, op2); + emitInst(static_cast(cc) | MVN | SET_CC, rd, ARMRegisters::r0, op2); + } + + void mul_r(int rd, int rn, int rm, Condition cc = AL) + { + spewInsWithOp2("mul", cc, rd, rn, static_cast(rm)); + m_buffer.putInt(static_cast(cc) | MUL | RN(rd) | RS(rn) | RM(rm)); + } + + void muls_r(int rd, int rn, int rm, Condition cc = AL) + { + spewInsWithOp2("muls", cc, rd, rn, static_cast(rm)); + m_buffer.putInt(static_cast(cc) | MUL | SET_CC | RN(rd) | RS(rn) | RM(rm)); + } + + void mull_r(int rdhi, int rdlo, int rn, int rm, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, %s, %s, %s\n", MAYBE_PAD, "mull", nameGpReg(rdlo), nameGpReg(rdhi), nameGpReg(rn), nameGpReg(rm)); + m_buffer.putInt(static_cast(cc) | MULL | RN(rdhi) | RD(rdlo) | RS(rn) | RM(rm)); + } + + void fcpyd_r(int dd, int dm, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, %s, %s\n", MAYBE_PAD, "vmov.f64", nameFpRegD(dd), nameFpRegD(dm)); + // TODO: emitInst doesn't work for VFP instructions, though it + // seems to work for current usage. + emitInst(static_cast(cc) | FCPYD, dd, dd, dm); + } + + void faddd_r(int dd, int dn, int dm, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, %s, %s\n", MAYBE_PAD, "vadd.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm)); + // TODO: emitInst doesn't work for VFP instructions, though it + // seems to work for current usage. + emitInst(static_cast(cc) | FADDD, dd, dn, dm); + } + + void fnegd_r(int dd, int dm, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, %s, %s, %s\n", MAYBE_PAD, "fnegd", nameFpRegD(dd), nameFpRegD(dm)); + m_buffer.putInt(static_cast(cc) | FNEGD | DD(dd) | DM(dm)); + } + + void fdivd_r(int dd, int dn, int dm, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, %s, %s\n", MAYBE_PAD, "vdiv.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm)); + // TODO: emitInst doesn't work for VFP instructions, though it + // seems to work for current usage. + emitInst(static_cast(cc) | FDIVD, dd, dn, dm); + } + + void fsubd_r(int dd, int dn, int dm, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, %s, %s\n", MAYBE_PAD, "vsub.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm)); + // TODO: emitInst doesn't work for VFP instructions, though it + // seems to work for current usage. + emitInst(static_cast(cc) | FSUBD, dd, dn, dm); + } + + void fmuld_r(int dd, int dn, int dm, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, %s, %s\n", MAYBE_PAD, "vmul.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm)); + // TODO: emitInst doesn't work for VFP instructions, though it + // seems to work for current usage. + emitInst(static_cast(cc) | FMULD, dd, dn, dm); + } + + void fcmpd_r(int dd, int dm, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, %s\n", MAYBE_PAD, "vcmp.f64", nameFpRegD(dd), nameFpRegD(dm)); + // TODO: emitInst doesn't work for VFP instructions, though it + // seems to work for current usage. + emitInst(static_cast(cc) | FCMPD, dd, 0, dm); + } + + void fsqrtd_r(int dd, int dm, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, %s\n", MAYBE_PAD, "vsqrt.f64", nameFpRegD(dd), nameFpRegD(dm)); + // TODO: emitInst doesn't work for VFP instructions, though it + // seems to work for current usage. + emitInst(static_cast(cc) | FSQRTD, dd, 0, dm); + } + + void ldr_imm(int rd, ARMWord imm, Condition cc = AL) + { + char mnemonic[16]; + snprintf(mnemonic, 16, "ldr%s", nameCC(cc)); + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, =0x%x @ (%d) (reusable pool entry)\n", MAYBE_PAD, mnemonic, nameGpReg(rd), imm, static_cast(imm)); + m_buffer.putIntWithConstantInt(static_cast(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm, true); + } + + void ldr_un_imm(int rd, ARMWord imm, Condition cc = AL) + { + char mnemonic[16]; + snprintf(mnemonic, 16, "ldr%s", nameCC(cc)); + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, =0x%x @ (%d)\n", MAYBE_PAD, mnemonic, nameGpReg(rd), imm, static_cast(imm)); + m_buffer.putIntWithConstantInt(static_cast(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm); + } + + // Data transfers like this: + // LDR rd, [rb, +offset] + // STR rd, [rb, +offset] + void dtr_u(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL) + { + char const * mnemonic = (isLoad) ? ("ldr") : ("str"); + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), offset); + emitInst(static_cast(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP, rd, rb, offset); + } + + // Data transfers like this: + // LDR rd, [rb, +rm] + // STR rd, [rb, +rm] + void dtr_ur(bool isLoad, int rd, int rb, int rm, Condition cc = AL) + { + char const * mnemonic = (isLoad) ? ("ldr") : ("str"); + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, [%s, +%s]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), nameGpReg(rm)); + emitInst(static_cast(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP | OP2_OFSREG, rd, rb, rm); + } + + // Data transfers like this: + // LDR rd, [rb, -offset] + // STR rd, [rb, -offset] + void dtr_d(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL) + { + char const * mnemonic = (isLoad) ? ("ldr") : ("str"); + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, [%s, #-%u]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), offset); + emitInst(static_cast(cc) | DTR | (isLoad ? DT_LOAD : 0), rd, rb, offset); + } + + // Data transfers like this: + // LDR rd, [rb, -rm] + // STR rd, [rb, -rm] + void dtr_dr(bool isLoad, int rd, int rb, int rm, Condition cc = AL) + { + char const * mnemonic = (isLoad) ? ("ldr") : ("str"); + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, [%s, -%s]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), nameGpReg(rm)); + emitInst(static_cast(cc) | DTR | (isLoad ? DT_LOAD : 0) | OP2_OFSREG, rd, rb, rm); + } + + // Data transfers like this: + // LDRB rd, [rb, +offset] + // STRB rd, [rb, +offset] + void dtrb_u(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL) + { + char const * mnemonic = (isLoad) ? ("ldrb") : ("strb"); + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), offset); + emitInst(static_cast(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0) | DT_UP, rd, rb, offset); + } + + // Data transfers like this: + // LDRB rd, [rb, +rm] + // STRB rd, [rb, +rm] + void dtrb_ur(bool isLoad, int rd, int rb, int rm, Condition cc = AL) + { + char const * mnemonic = (isLoad) ? ("ldrb") : ("strb"); + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, [%s, +%s]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), nameGpReg(rm)); + emitInst(static_cast(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0) | DT_UP | OP2_OFSREG, rd, rb, rm); + } + + // Data transfers like this: + // LDRB rd, [rb, -offset] + // STRB rd, [rb, -offset] + void dtrb_d(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL) + { + char const * mnemonic = (isLoad) ? ("ldrb") : ("strb"); + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, [%s, #-%u]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), offset); + emitInst(static_cast(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0), rd, rb, offset); + } + + // Data transfers like this: + // LDRB rd, [rb, -rm] + // STRB rd, [rb, -rm] + void dtrb_dr(bool isLoad, int rd, int rb, int rm, Condition cc = AL) + { + char const * mnemonic = (isLoad) ? ("ldrb") : ("strb"); + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, [%s, -%s]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), nameGpReg(rm)); + emitInst(static_cast(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0) | OP2_OFSREG, rd, rb, rm); + } + + void ldrh_r(int rd, int rb, int rm, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, [%s, +%s]\n", MAYBE_PAD, "ldrh", nameGpReg(rd), nameGpReg(rb), nameGpReg(rm)); + emitInst(static_cast(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rb, rm); + } + + void ldrh_d(int rd, int rb, ARMWord offset, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, [%s, #-%u]\n", MAYBE_PAD, "ldrh", nameGpReg(rd), nameGpReg(rb), offset); + emitInst(static_cast(cc) | LDRH | HDT_UH | DT_PRE, rd, rb, offset); + } + + void ldrh_u(int rd, int rb, ARMWord offset, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, "ldrh", nameGpReg(rd), nameGpReg(rb), offset); + emitInst(static_cast(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rb, offset); + } + + void strh_r(int rb, int rm, int rd, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, [%s, +%s]\n", MAYBE_PAD, "strh", nameGpReg(rd), nameGpReg(rb), nameGpReg(rm)); + emitInst(static_cast(cc) | STRH | HDT_UH | DT_UP | DT_PRE, rd, rb, rm); + } + + void fdtr_u(bool isLoad, int dd, int rn, ARMWord offset, Condition cc = AL) + { + char const * ins = isLoad ? "vldr.f64" : "vstr.f64"; + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, ins, nameFpRegD(dd), nameGpReg(rn), offset); + ASSERT(offset <= 0xff); + emitInst(static_cast(cc) | FDTR | DT_UP | (isLoad ? DT_LOAD : 0), dd, rn, offset); + } + + void fdtr_d(bool isLoad, int dd, int rn, ARMWord offset, Condition cc = AL) + { + char const * ins = isLoad ? "vldr.f64" : "vstr.f64"; + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, [%s, #-%u]\n", MAYBE_PAD, ins, nameFpRegD(dd), nameGpReg(rn), offset); + ASSERT(offset <= 0xff); + emitInst(static_cast(cc) | FDTR | (isLoad ? DT_LOAD : 0), dd, rn, offset); + } + + void push_r(int reg, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s {%s}\n", MAYBE_PAD, "push", nameGpReg(reg)); + ASSERT(ARMWord(reg) <= 0xf); + m_buffer.putInt(cc | DTR | DT_WB | RN(ARMRegisters::sp) | RD(reg) | 0x4); + } + + void pop_r(int reg, Condition cc = AL) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s {%s}\n", MAYBE_PAD, "pop", nameGpReg(reg)); + ASSERT(ARMWord(reg) <= 0xf); + m_buffer.putInt(cc | (DTR ^ DT_PRE) | DT_LOAD | DT_UP | RN(ARMRegisters::sp) | RD(reg) | 0x4); + } + + inline void poke_r(int reg, Condition cc = AL) + { + dtr_d(false, ARMRegisters::sp, 0, reg, cc); + } + + inline void peek_r(int reg, Condition cc = AL) + { + dtr_u(true, reg, ARMRegisters::sp, 0, cc); + } + + void fmsr_r(int dd, int rn, Condition cc = AL) + { + // TODO: emitInst doesn't work for VFP instructions, though it + // seems to work for current usage. + emitInst(static_cast(cc) | FMSR, rn, dd, 0); + } + + void fmrs_r(int rd, int dn, Condition cc = AL) + { + // TODO: emitInst doesn't work for VFP instructions, though it + // seems to work for current usage. + emitInst(static_cast(cc) | FMRS, rd, dn, 0); + } + + void fsitod_r(int dd, int dm, Condition cc = AL) + { + // TODO: emitInst doesn't work for VFP instructions, though it + // seems to work for current usage. + emitInst(static_cast(cc) | FSITOD, dd, 0, dm); + } + + void ftosid_r(int fd, int dm, Condition cc = AL) + { + // TODO: emitInst doesn't work for VFP instructions, though it + // seems to work for current usage. + emitInst(static_cast(cc) | FTOSID, fd, 0, dm); + } + + void ftosizd_r(int fd, int dm, Condition cc = AL) + { + // TODO: emitInst doesn't work for VFP instructions, though it + // seems to work for current usage. + emitInst(static_cast(cc) | FTOSIZD, fd, 0, dm); + } + + void fmstat(Condition cc = AL) + { + // TODO: emitInst doesn't work for VFP instructions, though it + // seems to work for current usage. + m_buffer.putInt(static_cast(cc) | FMSTAT); + } + +#if WTF_ARM_ARCH_VERSION >= 5 + void clz_r(int rd, int rm, Condition cc = AL) + { + spewInsWithOp2("clz", cc, rd, static_cast(rm)); + m_buffer.putInt(static_cast(cc) | CLZ | RD(rd) | RM(rm)); + } +#endif + + void bkpt(ARMWord value) + { +#if WTF_ARM_ARCH_VERSION >= 5 + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s #0x%04x\n", MAYBE_PAD, "bkpt", value); + m_buffer.putInt(BKPT | ((value & 0xfff0) << 4) | (value & 0xf)); +#else + // Cannot access to Zero memory address + dtr_dr(true, ARMRegisters::S0, ARMRegisters::S0, ARMRegisters::S0); +#endif + } + + void bx(int rm, Condition cc = AL) + { +#if WTF_ARM_ARCH_VERSION >= 5 || defined(__ARM_ARCH_4T__) + js::JaegerSpew( + js::JSpew_Insns, + IPFX "bx%-13s %s\n", MAYBE_PAD, nameCC(cc), nameGpReg(rm)); + emitInst(static_cast(cc) | BX, 0, 0, RM(rm)); +#else + mov_r(ARMRegisters::pc, RM(rm), cc); +#endif + } + + JmpSrc blx(int rm, Condition cc = AL) + { +#if WTF_ARM_ARCH_AT_LEAST(5) + int s = m_buffer.uncheckedSize(); + js::JaegerSpew( + js::JSpew_Insns, + IPFX "blx%-12s %s\n", MAYBE_PAD, nameCC(cc), nameGpReg(rm)); + emitInst(static_cast(cc) | BLX, 0, 0, RM(rm)); +#else + ASSERT(rm != 14); + ensureSpace(2 * sizeof(ARMWord), 0); + mov_r(ARMRegisters::lr, ARMRegisters::pc, cc); + int s = m_buffer.uncheckedSize(); + bx(rm, cc); +#endif + return JmpSrc(s); + } + + static ARMWord lsl(int reg, ARMWord value) + { + ASSERT(reg <= ARMRegisters::pc); + ASSERT(value <= 0x1f); + return reg | (value << 7) | (LSL << 5); + } + + static ARMWord lsr(int reg, ARMWord value) + { + ASSERT(reg <= ARMRegisters::pc); + ASSERT(value <= 0x1f); + return reg | (value << 7) | (LSR << 5); + } + + static ARMWord asr(int reg, ARMWord value) + { + ASSERT(reg <= ARMRegisters::pc); + ASSERT(value <= 0x1f); + return reg | (value << 7) | (ASR << 5); + } + + static ARMWord lsl_r(int reg, int shiftReg) + { + ASSERT(reg <= ARMRegisters::pc); + ASSERT(shiftReg <= ARMRegisters::pc); + return reg | (shiftReg << 8) | (LSL << 5) | 0x10; + } + + static ARMWord lsr_r(int reg, int shiftReg) + { + ASSERT(reg <= ARMRegisters::pc); + ASSERT(shiftReg <= ARMRegisters::pc); + return reg | (shiftReg << 8) | (LSR << 5) | 0x10; + } + + static ARMWord asr_r(int reg, int shiftReg) + { + ASSERT(reg <= ARMRegisters::pc); + ASSERT(shiftReg <= ARMRegisters::pc); + return reg | (shiftReg << 8) | (ASR << 5) | 0x10; + } + + // General helpers + + void forceFlushConstantPool() + { + m_buffer.flushWithoutBarrier(true); + } + + int size() + { + return m_buffer.size(); + } + + void ensureSpace(int insnSpace, int constSpace) + { + m_buffer.ensureSpace(insnSpace, constSpace); + } + + void ensureSpace(int space) + { + m_buffer.ensureSpace(space); + } + + int sizeOfConstantPool() + { + return m_buffer.sizeOfConstantPool(); + } + +#ifdef DEBUG + void allowPoolFlush(bool allowFlush) + { + m_buffer.allowPoolFlush(allowFlush); + } +#endif + + JmpDst label() + { + JmpDst label(m_buffer.size()); + js::JaegerSpew(js::JSpew_Insns, IPFX "#label ((%d))\n", MAYBE_PAD, label.m_offset); + return label; + } + + JmpDst align(int alignment) + { + while (!m_buffer.isAligned(alignment)) + mov_r(ARMRegisters::r0, ARMRegisters::r0); + + return label(); + } + + JmpSrc loadBranchTarget(int rd, Condition cc = AL, int useConstantPool = 0) + { + // The 'useConstantPool' flag really just indicates where we have + // to use the constant pool, for repatching. We might still use it, + // so ensure there's space for a pool constant irrespective of + // 'useConstantPool'. + ensureSpace(sizeof(ARMWord), sizeof(ARMWord)); + int s = m_buffer.uncheckedSize(); + ldr_un_imm(rd, InvalidBranchTarget, cc); + m_jumps.append(s | (useConstantPool & 0x1)); + return JmpSrc(s); + } + + JmpSrc jmp(Condition cc = AL, int useConstantPool = 0) + { + return loadBranchTarget(ARMRegisters::pc, cc, useConstantPool); + } + + void* executableCopy(ExecutablePool* allocator); + void* executableCopy(void* buffer); + void fixUpOffsets(void* buffer); + + // Patching helpers + + static ARMWord* getLdrImmAddress(ARMWord* insn) + { +#if WTF_ARM_ARCH_AT_LEAST(5) + // Check for call + if ((*insn & 0x0f7f0000) != 0x051f0000) { + // Must be BLX + ASSERT((*insn & 0x012fff30) == 0x012fff30); + insn--; + } +#endif + // Must be an ldr ..., [pc +/- imm] + ASSERT((*insn & 0x0f7f0000) == 0x051f0000); + + ARMWord addr = reinterpret_cast(insn) + DefaultPrefetching * sizeof(ARMWord); + if (*insn & DT_UP) + return reinterpret_cast(addr + (*insn & SDT_OFFSET_MASK)); + return reinterpret_cast(addr - (*insn & SDT_OFFSET_MASK)); + } + + static ARMWord* getLdrImmAddressOnPool(ARMWord* insn, uint32_t* constPool) + { + // Must be an ldr ..., [pc +/- imm] + ASSERT((*insn & 0x0f7f0000) == 0x051f0000); + + if (*insn & 0x1) + return reinterpret_cast(constPool + ((*insn & SDT_OFFSET_MASK) >> 1)); + return getLdrImmAddress(insn); + } + + static void patchPointerInternal(intptr_t from, void* to) + { + ARMWord* insn = reinterpret_cast(from); + ARMWord* addr = getLdrImmAddress(insn); + *addr = reinterpret_cast(to); + } + + static ARMWord patchConstantPoolLoad(ARMWord load, ARMWord value) + { + value = (value << 1) + 1; + ASSERT(!(value & ~0xfff)); + return (load & ~0xfff) | value; + } + + static void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr); + + // Patch pointers + + static void linkPointer(void* code, JmpDst from, void* to) + { + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##linkPointer ((%p + %#x)) points to ((%p))\n", + code, from.m_offset, to); + + patchPointerInternal(reinterpret_cast(code) + from.m_offset, to); + } + + static void repatchInt32(void* from, int32_t to) + { + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##repatchInt32 ((%p)) holds ((%p))\n", + from, to); + + patchPointerInternal(reinterpret_cast(from), reinterpret_cast(to)); + } + + static void repatchPointer(void* from, void* to) + { + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##repatchPointer ((%p)) points to ((%p))\n", + from, to); + + patchPointerInternal(reinterpret_cast(from), to); + } + + static void repatchLoadPtrToLEA(void* from) + { + // On arm, this is a patch from LDR to ADD. It is restricted conversion, + // from special case to special case, altough enough for its purpose + ARMWord* insn = reinterpret_cast(from); + ASSERT((*insn & 0x0ff00f00) == 0x05900000); + + *insn = (*insn & 0xf00ff0ff) | 0x02800000; + ExecutableAllocator::cacheFlush(insn, sizeof(ARMWord)); + } + + static void repatchLEAToLoadPtr(void* from) + { + // Like repatchLoadPtrToLEA, this is specialized for our purpose. + ARMWord* insn = reinterpret_cast(from); + if ((*insn & 0x0ff00f00) == 0x05900000) + return; // Valid ldr instruction + ASSERT((*insn & 0x0ff00000) == 0x02800000); // Valid add instruction + ASSERT((*insn & 0x00000f00) == 0x00000000); // Simple-to-handle immediates (no rotate) + + *insn = (*insn & 0xf00ff0ff) | 0x05900000; + ExecutableAllocator::cacheFlush(insn, sizeof(ARMWord)); + } + + // Linkers + + void linkJump(JmpSrc from, JmpDst to) + { + ARMWord code = reinterpret_cast(m_buffer.data()); + ARMWord* insn = reinterpret_cast(code + from.m_offset); + ARMWord* addr = getLdrImmAddressOnPool(insn, m_buffer.poolAddress()); + + js::JaegerSpew(js::JSpew_Insns, + IPFX "##linkJump ((%#x)) jumps to ((%#x))\n", MAYBE_PAD, + from.m_offset, to.m_offset); + + *addr = to.m_offset; + } + + static void linkJump(void* code, JmpSrc from, void* to) + { + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##linkJump ((%p + %#x)) jumps to ((%p))\n", + code, from.m_offset, to); + + patchPointerInternal(reinterpret_cast(code) + from.m_offset, to); + } + + static void relinkJump(void* from, void* to) + { + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##relinkJump ((%p)) jumps to ((%p))\n", + from, to); + + patchPointerInternal(reinterpret_cast(from), to); + } + + static bool canRelinkJump(void* from, void* to) + { + return true; + } + + static void linkCall(void* code, JmpSrc from, void* to) + { + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##linkCall ((%p + %#x)) jumps to ((%p))\n", + code, from.m_offset, to); + + patchPointerInternal(reinterpret_cast(code) + from.m_offset, to); + } + + static void relinkCall(void* from, void* to) + { + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##relinkCall ((%p)) jumps to ((%p))\n", + from, to); + + patchPointerInternal(reinterpret_cast(from), to); + } + + // Address operations + + static void* getRelocatedAddress(void* code, JmpSrc jump) + { + return reinterpret_cast(reinterpret_cast(code) + jump.m_offset / sizeof(ARMWord)); + } + + static void* getRelocatedAddress(void* code, JmpDst label) + { + return reinterpret_cast(reinterpret_cast(code) + label.m_offset / sizeof(ARMWord)); + } + + // Address differences + + static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to) + { + return to.m_offset - from.m_offset; + } + + static int getDifferenceBetweenLabels(JmpDst from, JmpDst to) + { + return to.m_offset - from.m_offset; + } + + static unsigned getCallReturnOffset(JmpSrc call) + { + return call.m_offset + sizeof(ARMWord); + } + + // Handle immediates + + static ARMWord getOp2Byte(ARMWord imm) + { + ASSERT(imm <= 0xff); + return OP2_IMMh | (imm & 0x0f) | ((imm & 0xf0) << 4) ; + } + + static ARMWord getOp2(ARMWord imm); + +#if WTF_ARM_ARCH_VERSION >= 7 + static ARMWord getImm16Op2(ARMWord imm) + { + if (imm <= 0xffff) + return (imm & 0xf000) << 4 | (imm & 0xfff); + return INVALID_IMM; + } +#endif + ARMWord getImm(ARMWord imm, int tmpReg, bool invert = false); + void moveImm(ARMWord imm, int dest); + ARMWord encodeComplexImm(ARMWord imm, int dest); + + ARMWord getOffsetForHalfwordDataTransfer(ARMWord imm, int tmpReg) + { + // Encode immediate data in the instruction if it is possible + if (imm <= 0xff) + return getOp2Byte(imm); + // Otherwise, store the data in a temporary register + return encodeComplexImm(imm, tmpReg); + } + + // Memory load/store helpers + + void dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset); + void dataTransfer8(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset); + void baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset); + void doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset); + + // Constant pool hnadlers + + static ARMWord placeConstantPoolBarrier(int offset) + { + offset = (offset - sizeof(ARMWord)) >> 2; + ASSERT((offset <= BOFFSET_MAX && offset >= BOFFSET_MIN)); + return AL | B | (offset & BRANCH_MASK); + } + + private: + static char const * nameGpReg(int reg) + { + ASSERT(reg <= 16); + ASSERT(reg >= 0); + static char const * names[] = { + "r0", "r1", "r2", "r3", + "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", + "ip", "sp", "lr", "pc" + }; + return names[reg]; + } + + static char const * nameFpRegD(int reg) + { + ASSERT(reg <= 31); + ASSERT(reg >= 0); + static char const * names[] = { + "d0", "d1", "d2", "d3", + "d4", "d5", "d6", "d7", + "d8", "d9", "d10", "d11", + "d12", "d13", "d14", "d15", + "d16", "d17", "d18", "d19", + "d20", "d21", "d22", "d23", + "d24", "d25", "d26", "d27", + "d28", "d29", "d30", "d31" + }; + return names[reg]; + } + + static char const * nameCC(Condition cc) + { + ASSERT(cc <= AL); + ASSERT(cc >= 0); + ASSERT((cc & 0x0fffffff) == 0); + + uint32_t ccIndex = cc >> 28; + static char const * names[] = { + "eq", "ne", + "cs", "cc", + "mi", "pl", + "vs", "vc", + "hi", "ls", + "ge", "lt", + "gt", "le", + " " // AL is the default, so don't show it. + }; + return names[ccIndex]; + } + + // Decodes operand 2 immediate values (for debug output and assertions). + inline uint32_t decOp2Imm(uint32_t op2) + { + ASSERT((op2 & ~0xfff) == 0); + + uint32_t imm8 = op2 & 0xff; + uint32_t rot = ((op2 >> 7) & 0x1e); + + // 'rot' is a right-rotate count. + + uint32_t imm = (imm8 >> rot); + if (rot > 0) { + imm |= (imm8 << (32-rot)); + } + + return imm; + } + + // Format the operand 2 argument for debug spew. The operand can be + // either an immediate or a register specifier. + void fmtOp2(char * out, ARMWord op2) + { + static char const * const shifts[4] = {"LSL", "LSR", "ASR", "ROR"}; + + if ((op2 & OP2_IMM) || (op2 & OP2_IMMh)) { + // Immediate values. + + uint32_t imm = decOp2Imm(op2 & ~(OP2_IMM | OP2_IMMh)); + sprintf(out, "#0x%x @ (%d)", imm, static_cast(imm)); + } else { + // Register values. + + char const * rm = nameGpReg(op2 & 0xf); + Shift type = static_cast((op2 >> 5) & 0x3); + + // Bit 4 specifies barrel-shifter parameters in operand 2. + if (op2 & (1<<4)) { + // Register-shifted register. + // Example: "r0, LSL r6" + char const * rs = nameGpReg((op2 >> 8) & 0xf); + sprintf(out, "%s, %s %s", rm, shifts[type], rs); + } else { + // Immediate-shifted register. + // Example: "r0, ASR #31" + uint32_t imm = (op2 >> 7) & 0x1f; + + // Deal with special encodings. + if ((type == LSL) && (imm == 0)) { + // "LSL #0" doesn't shift at all (and is the default). + sprintf(out, "%s", rm); + return; + } + + if ((type == ROR) && (imm == 0)) { + // "ROR #0" is a special case ("RRX"). + sprintf(out, "%s, RRX", rm); + return; + } + + if (((type == LSR) || (type == ASR)) && (imm == 0)) { + // Both LSR and ASR have a range of 1-32, with 32 + // encoded as 0. + imm = 32; + } + + // Print the result. + + sprintf(out, "%s, %s #%u", rm, shifts[type], imm); + } + } + } + + void spewInsWithOp2(char const * ins, Condition cc, int rd, int rn, ARMWord op2) + { + char mnemonic[16]; + snprintf(mnemonic, 16, "%s%s", ins, nameCC(cc)); + + char op2_fmt[48]; + fmtOp2(op2_fmt, op2); + + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, %s, %s\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rn), op2_fmt); + } + + void spewInsWithOp2(char const * ins, Condition cc, int r, ARMWord op2) + { + char mnemonic[16]; + snprintf(mnemonic, 16, "%s%s", ins, nameCC(cc)); + + char op2_fmt[48]; + fmtOp2(op2_fmt, op2); + + js::JaegerSpew(js::JSpew_Insns, + IPFX "%-15s %s, %s\n", MAYBE_PAD, mnemonic, nameGpReg(r), op2_fmt); + } + + ARMWord RM(int reg) + { + ASSERT(reg <= ARMRegisters::pc); + return reg; + } + + ARMWord RS(int reg) + { + ASSERT(reg <= ARMRegisters::pc); + return reg << 8; + } + + ARMWord RD(int reg) + { + ASSERT(reg <= ARMRegisters::pc); + return reg << 12; + } + + ARMWord RN(int reg) + { + ASSERT(reg <= ARMRegisters::pc); + return reg << 16; + } + + ARMWord DD(int reg) + { + ASSERT(reg <= ARMRegisters::d31); + // Endoded as bits [22,15:12]. + return ((reg << 12) | (reg << 18)) & 0x0040f000; + } + + ARMWord DN(int reg) + { + ASSERT(reg <= ARMRegisters::d31); + // Endoded as bits [7,19:16]. + return ((reg << 16) | (reg << 3)) & 0x000f0080; + } + + ARMWord DM(int reg) + { + ASSERT(reg <= ARMRegisters::d31); + // Encoded as bits [5,3:0]. + return ((reg << 1) & 0x20) | (reg & 0xf); + } + + static ARMWord getConditionalField(ARMWord i) + { + return i & 0xf0000000; + } + + int genInt(int reg, ARMWord imm, bool positive); + + ARMBuffer m_buffer; + Jumps m_jumps; + }; + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) + +#endif // ARMAssembler_h diff --git a/js/src/assembler/assembler/ARMv7Assembler.h b/js/src/assembler/assembler/ARMv7Assembler.h new file mode 100644 index 0000000..60e201c --- /dev/null +++ b/js/src/assembler/assembler/ARMv7Assembler.h @@ -0,0 +1,1926 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2010 University of Szeged + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef ARMAssembler_h +#define ARMAssembler_h + +#include "assembler/wtf/Platform.h" + +#if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2) + +#include "AssemblerBuffer.h" +#include "assembler/wtf/Assertions.h" +#include "assembler/wtf/Vector.h" +#include + +namespace JSC { + +namespace ARMRegisters { + typedef enum { + r0, + r1, + r2, + r3, + r4, + r5, + r6, + r7, wr = r7, // thumb work register + r8, + r9, sb = r9, // static base + r10, sl = r10, // stack limit + r11, fp = r11, // frame pointer + r12, ip = r12, + r13, sp = r13, + r14, lr = r14, + r15, pc = r15, + } RegisterID; + + // s0 == d0 == q0 + // s4 == d2 == q1 + // etc + typedef enum { + s0 = 0, + s1 = 1, + s2 = 2, + s3 = 3, + s4 = 4, + s5 = 5, + s6 = 6, + s7 = 7, + s8 = 8, + s9 = 9, + s10 = 10, + s11 = 11, + s12 = 12, + s13 = 13, + s14 = 14, + s15 = 15, + s16 = 16, + s17 = 17, + s18 = 18, + s19 = 19, + s20 = 20, + s21 = 21, + s22 = 22, + s23 = 23, + s24 = 24, + s25 = 25, + s26 = 26, + s27 = 27, + s28 = 28, + s29 = 29, + s30 = 30, + s31 = 31, + d0 = 0 << 1, + d1 = 1 << 1, + d2 = 2 << 1, + d3 = 3 << 1, + d4 = 4 << 1, + d5 = 5 << 1, + d6 = 6 << 1, + d7 = 7 << 1, + d8 = 8 << 1, + d9 = 9 << 1, + d10 = 10 << 1, + d11 = 11 << 1, + d12 = 12 << 1, + d13 = 13 << 1, + d14 = 14 << 1, + d15 = 15 << 1, + d16 = 16 << 1, + d17 = 17 << 1, + d18 = 18 << 1, + d19 = 19 << 1, + d20 = 20 << 1, + d21 = 21 << 1, + d22 = 22 << 1, + d23 = 23 << 1, + d24 = 24 << 1, + d25 = 25 << 1, + d26 = 26 << 1, + d27 = 27 << 1, + d28 = 28 << 1, + d29 = 29 << 1, + d30 = 30 << 1, + d31 = 31 << 1, + q0 = 0 << 2, + q1 = 1 << 2, + q2 = 2 << 2, + q3 = 3 << 2, + q4 = 4 << 2, + q5 = 5 << 2, + q6 = 6 << 2, + q7 = 7 << 2, + q8 = 8 << 2, + q9 = 9 << 2, + q10 = 10 << 2, + q11 = 11 << 2, + q12 = 12 << 2, + q13 = 13 << 2, + q14 = 14 << 2, + q15 = 15 << 2, + q16 = 16 << 2, + q17 = 17 << 2, + q18 = 18 << 2, + q19 = 19 << 2, + q20 = 20 << 2, + q21 = 21 << 2, + q22 = 22 << 2, + q23 = 23 << 2, + q24 = 24 << 2, + q25 = 25 << 2, + q26 = 26 << 2, + q27 = 27 << 2, + q28 = 28 << 2, + q29 = 29 << 2, + q30 = 30 << 2, + q31 = 31 << 2, + } FPRegisterID; +} + +class ARMv7Assembler; +class ARMThumbImmediate { + friend class ARMv7Assembler; + + typedef uint8_t ThumbImmediateType; + static const ThumbImmediateType TypeInvalid = 0; + static const ThumbImmediateType TypeEncoded = 1; + static const ThumbImmediateType TypeUInt16 = 2; + + typedef union { + int16_t asInt; + struct { + unsigned imm8 : 8; + unsigned imm3 : 3; + unsigned i : 1; + unsigned imm4 : 4; + }; + // If this is an encoded immediate, then it may describe a shift, or a pattern. + struct { + unsigned shiftValue7 : 7; + unsigned shiftAmount : 5; + }; + struct { + unsigned immediate : 8; + unsigned pattern : 4; + }; + } ThumbImmediateValue; + + // byte0 contains least significant bit; not using an array to make client code endian agnostic. + typedef union { + int32_t asInt; + struct { + uint8_t byte0; + uint8_t byte1; + uint8_t byte2; + uint8_t byte3; + }; + } PatternBytes; + + ALWAYS_INLINE static void countLeadingZerosPartial(uint32_t& value, int32_t& zeros, const int N) + { + if (value & ~((1 << N) - 1)) /* check for any of the top N bits (of 2N bits) are set */ + value >>= N; /* if any were set, lose the bottom N */ + else /* if none of the top N bits are set, */ + zeros += N; /* then we have identified N leading zeros */ + } + + static int32_t countLeadingZeros(uint32_t value) + { + if (!value) + return 32; + + int32_t zeros = 0; + countLeadingZerosPartial(value, zeros, 16); + countLeadingZerosPartial(value, zeros, 8); + countLeadingZerosPartial(value, zeros, 4); + countLeadingZerosPartial(value, zeros, 2); + countLeadingZerosPartial(value, zeros, 1); + return zeros; + } + + ARMThumbImmediate() + : m_type(TypeInvalid) + { + m_value.asInt = 0; + } + + ARMThumbImmediate(ThumbImmediateType type, ThumbImmediateValue value) + : m_type(type) + , m_value(value) + { + } + + ARMThumbImmediate(ThumbImmediateType type, uint16_t value) + : m_type(TypeUInt16) + { + // Make sure this constructor is only reached with type TypeUInt16; + // this extra parameter makes the code a little clearer by making it + // explicit at call sites which type is being constructed + ASSERT_UNUSED(type, type == TypeUInt16); + + m_value.asInt = value; + } + +public: + static ARMThumbImmediate makeEncodedImm(uint32_t value) + { + ThumbImmediateValue encoding; + encoding.asInt = 0; + + // okay, these are easy. + if (value < 256) { + encoding.immediate = value; + encoding.pattern = 0; + return ARMThumbImmediate(TypeEncoded, encoding); + } + + int32_t leadingZeros = countLeadingZeros(value); + // if there were 24 or more leading zeros, then we'd have hit the (value < 256) case. + ASSERT(leadingZeros < 24); + + // Given a number with bit fields Z:B:C, where count(Z)+count(B)+count(C) == 32, + // Z are the bits known zero, B is the 8-bit immediate, C are the bits to check for + // zero. count(B) == 8, so the count of bits to be checked is 24 - count(Z). + int32_t rightShiftAmount = 24 - leadingZeros; + if (value == ((value >> rightShiftAmount) << rightShiftAmount)) { + // Shift the value down to the low byte position. The assign to + // shiftValue7 drops the implicit top bit. + encoding.shiftValue7 = value >> rightShiftAmount; + // The endoded shift amount is the magnitude of a right rotate. + encoding.shiftAmount = 8 + leadingZeros; + return ARMThumbImmediate(TypeEncoded, encoding); + } + + PatternBytes bytes; + bytes.asInt = value; + + if ((bytes.byte0 == bytes.byte1) && (bytes.byte0 == bytes.byte2) && (bytes.byte0 == bytes.byte3)) { + encoding.immediate = bytes.byte0; + encoding.pattern = 3; + return ARMThumbImmediate(TypeEncoded, encoding); + } + + if ((bytes.byte0 == bytes.byte2) && !(bytes.byte1 | bytes.byte3)) { + encoding.immediate = bytes.byte0; + encoding.pattern = 1; + return ARMThumbImmediate(TypeEncoded, encoding); + } + + if ((bytes.byte1 == bytes.byte3) && !(bytes.byte0 | bytes.byte2)) { + encoding.immediate = bytes.byte0; + encoding.pattern = 2; + return ARMThumbImmediate(TypeEncoded, encoding); + } + + return ARMThumbImmediate(); + } + + static ARMThumbImmediate makeUInt12(int32_t value) + { + return (!(value & 0xfffff000)) + ? ARMThumbImmediate(TypeUInt16, (uint16_t)value) + : ARMThumbImmediate(); + } + + static ARMThumbImmediate makeUInt12OrEncodedImm(int32_t value) + { + // If this is not a 12-bit unsigned it, try making an encoded immediate. + return (!(value & 0xfffff000)) + ? ARMThumbImmediate(TypeUInt16, (uint16_t)value) + : makeEncodedImm(value); + } + + // The 'make' methods, above, return a !isValid() value if the argument + // cannot be represented as the requested type. This methods is called + // 'get' since the argument can always be represented. + static ARMThumbImmediate makeUInt16(uint16_t value) + { + return ARMThumbImmediate(TypeUInt16, value); + } + + bool isValid() + { + return m_type != TypeInvalid; + } + + // These methods rely on the format of encoded byte values. + bool isUInt3() { return !(m_value.asInt & 0xfff8); } + bool isUInt4() { return !(m_value.asInt & 0xfff0); } + bool isUInt5() { return !(m_value.asInt & 0xffe0); } + bool isUInt6() { return !(m_value.asInt & 0xffc0); } + bool isUInt7() { return !(m_value.asInt & 0xff80); } + bool isUInt8() { return !(m_value.asInt & 0xff00); } + bool isUInt9() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfe00); } + bool isUInt10() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfc00); } + bool isUInt12() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xf000); } + bool isUInt16() { return m_type == TypeUInt16; } + uint8_t getUInt3() { ASSERT(isUInt3()); return m_value.asInt; } + uint8_t getUInt4() { ASSERT(isUInt4()); return m_value.asInt; } + uint8_t getUInt5() { ASSERT(isUInt5()); return m_value.asInt; } + uint8_t getUInt6() { ASSERT(isUInt6()); return m_value.asInt; } + uint8_t getUInt7() { ASSERT(isUInt7()); return m_value.asInt; } + uint8_t getUInt8() { ASSERT(isUInt8()); return m_value.asInt; } + uint8_t getUInt9() { ASSERT(isUInt9()); return m_value.asInt; } + uint8_t getUInt10() { ASSERT(isUInt10()); return m_value.asInt; } + uint16_t getUInt12() { ASSERT(isUInt12()); return m_value.asInt; } + uint16_t getUInt16() { ASSERT(isUInt16()); return m_value.asInt; } + + bool isEncodedImm() { return m_type == TypeEncoded; } + +private: + ThumbImmediateType m_type; + ThumbImmediateValue m_value; +}; + + +typedef enum { + SRType_LSL, + SRType_LSR, + SRType_ASR, + SRType_ROR, + + SRType_RRX = SRType_ROR +} ARMShiftType; + +class ARMv7Assembler; +class ShiftTypeAndAmount { + friend class ARMv7Assembler; + +public: + ShiftTypeAndAmount() + { + m_u.type = (ARMShiftType)0; + m_u.amount = 0; + } + + ShiftTypeAndAmount(ARMShiftType type, unsigned amount) + { + m_u.type = type; + m_u.amount = amount & 31; + } + + unsigned lo4() { return m_u.lo4; } + unsigned hi4() { return m_u.hi4; } + +private: + union { + struct { + unsigned lo4 : 4; + unsigned hi4 : 4; + }; + struct { + unsigned type : 2; + unsigned amount : 5; + }; + } m_u; +}; + + +/* +Some features of the Thumb instruction set are deprecated in ARMv7. Deprecated features affecting +instructions supported by ARMv7-M are as follows: +• use of the PC as or in a 16-bit ADD (SP plus register) instruction +• use of the SP as in a 16-bit ADD (SP plus register) instruction +• use of the SP as in a 16-bit CMP (register) instruction +• use of MOV (register) instructions in which is the SP or PC and is also the SP or PC. +• use of as the lowest-numbered register in the register list of a 16-bit STM instruction with base +register writeback +*/ + +class ARMv7Assembler { +public: + ~ARMv7Assembler() + { + ASSERT(m_jumpsToLink.isEmpty()); + } + + typedef ARMRegisters::RegisterID RegisterID; + typedef ARMRegisters::FPRegisterID FPRegisterID; + + // (HS, LO, HI, LS) -> (AE, B, A, BE) + // (VS, VC) -> (O, NO) + typedef enum { + ConditionEQ, + ConditionNE, + ConditionHS, + ConditionLO, + ConditionMI, + ConditionPL, + ConditionVS, + ConditionVC, + ConditionHI, + ConditionLS, + ConditionGE, + ConditionLT, + ConditionGT, + ConditionLE, + ConditionAL, + + ConditionCS = ConditionHS, + ConditionCC = ConditionLO, + } Condition; + + class JmpSrc { + friend class ARMv7Assembler; + friend class ARMInstructionFormatter; + public: + JmpSrc() + : m_offset(-1) + { + } + + private: + JmpSrc(int offset) + : m_offset(offset) + { + } + + int m_offset; + }; + + class JmpDst { + friend class ARMv7Assembler; + friend class ARMInstructionFormatter; + public: + JmpDst() + : m_offset(-1) + , m_used(false) + { + } + + bool isUsed() const { return m_used; } + void used() { m_used = true; } + private: + JmpDst(int offset) + : m_offset(offset) + , m_used(false) + { + ASSERT(m_offset == offset); + } + + int m_offset : 31; + int m_used : 1; + }; + +private: + + struct LinkRecord { + LinkRecord(intptr_t from, intptr_t to) + : from(from) + , to(to) + { + } + + intptr_t from; + intptr_t to; + }; + + // ARMv7, Appx-A.6.3 + bool BadReg(RegisterID reg) + { + return (reg == ARMRegisters::sp) || (reg == ARMRegisters::pc); + } + + bool isSingleRegister(FPRegisterID reg) + { + // Check that the high bit isn't set (q16+), and that the low bit isn't (s1, s3, etc). + return !(reg & ~31); + } + + bool isDoubleRegister(FPRegisterID reg) + { + // Check that the high bit isn't set (q16+), and that the low bit isn't (s1, s3, etc). + return !(reg & ~(31 << 1)); + } + + bool isQuadRegister(FPRegisterID reg) + { + return !(reg & ~(31 << 2)); + } + + uint32_t singleRegisterNum(FPRegisterID reg) + { + ASSERT(isSingleRegister(reg)); + return reg; + } + + uint32_t doubleRegisterNum(FPRegisterID reg) + { + ASSERT(isDoubleRegister(reg)); + return reg >> 1; + } + + uint32_t quadRegisterNum(FPRegisterID reg) + { + ASSERT(isQuadRegister(reg)); + return reg >> 2; + } + + uint32_t singleRegisterMask(FPRegisterID rd, int highBitsShift, int lowBitShift) + { + uint32_t rdNum = singleRegisterNum(rd); + uint32_t rdMask = (rdNum >> 1) << highBitsShift; + if (rdNum & 1) + rdMask |= 1 << lowBitShift; + return rdMask; + } + + uint32_t doubleRegisterMask(FPRegisterID rd, int highBitShift, int lowBitsShift) + { + uint32_t rdNum = doubleRegisterNum(rd); + uint32_t rdMask = (rdNum & 0xf) << lowBitsShift; + if (rdNum & 16) + rdMask |= 1 << highBitShift; + return rdMask; + } + + typedef enum { + OP_ADD_reg_T1 = 0x1800, + OP_ADD_S_reg_T1 = 0x1800, + OP_SUB_reg_T1 = 0x1A00, + OP_SUB_S_reg_T1 = 0x1A00, + OP_ADD_imm_T1 = 0x1C00, + OP_ADD_S_imm_T1 = 0x1C00, + OP_SUB_imm_T1 = 0x1E00, + OP_SUB_S_imm_T1 = 0x1E00, + OP_MOV_imm_T1 = 0x2000, + OP_CMP_imm_T1 = 0x2800, + OP_ADD_imm_T2 = 0x3000, + OP_ADD_S_imm_T2 = 0x3000, + OP_SUB_imm_T2 = 0x3800, + OP_SUB_S_imm_T2 = 0x3800, + OP_AND_reg_T1 = 0x4000, + OP_EOR_reg_T1 = 0x4040, + OP_TST_reg_T1 = 0x4200, + OP_CMP_reg_T1 = 0x4280, + OP_ORR_reg_T1 = 0x4300, + OP_MVN_reg_T1 = 0x43C0, + OP_ADD_reg_T2 = 0x4400, + OP_MOV_reg_T1 = 0x4600, + OP_BLX = 0x4700, + OP_BX = 0x4700, + OP_STR_reg_T1 = 0x5000, + OP_LDR_reg_T1 = 0x5800, + OP_LDRH_reg_T1 = 0x5A00, + OP_LDRB_reg_T1 = 0x5C00, + OP_STR_imm_T1 = 0x6000, + OP_LDR_imm_T1 = 0x6800, + OP_LDRB_imm_T1 = 0x7800, + OP_LDRH_imm_T1 = 0x8800, + OP_STR_imm_T2 = 0x9000, + OP_LDR_imm_T2 = 0x9800, + OP_ADD_SP_imm_T1 = 0xA800, + OP_ADD_SP_imm_T2 = 0xB000, + OP_SUB_SP_imm_T1 = 0xB080, + OP_BKPT = 0xBE00, + OP_IT = 0xBF00, + OP_NOP_T1 = 0xBF00, + } OpcodeID; + + typedef enum { + OP_AND_reg_T2 = 0xEA00, + OP_TST_reg_T2 = 0xEA10, + OP_ORR_reg_T2 = 0xEA40, + OP_ASR_imm_T1 = 0xEA4F, + OP_LSL_imm_T1 = 0xEA4F, + OP_LSR_imm_T1 = 0xEA4F, + OP_ROR_imm_T1 = 0xEA4F, + OP_MVN_reg_T2 = 0xEA6F, + OP_EOR_reg_T2 = 0xEA80, + OP_ADD_reg_T3 = 0xEB00, + OP_ADD_S_reg_T3 = 0xEB10, + OP_SUB_reg_T2 = 0xEBA0, + OP_SUB_S_reg_T2 = 0xEBB0, + OP_CMP_reg_T2 = 0xEBB0, + OP_B_T4a = 0xF000, + OP_AND_imm_T1 = 0xF000, + OP_TST_imm = 0xF010, + OP_ORR_imm_T1 = 0xF040, + OP_MOV_imm_T2 = 0xF040, + OP_MVN_imm = 0xF060, + OP_EOR_imm_T1 = 0xF080, + OP_ADD_imm_T3 = 0xF100, + OP_ADD_S_imm_T3 = 0xF110, + OP_CMN_imm = 0xF110, + OP_SUB_imm_T3 = 0xF1A0, + OP_SUB_S_imm_T3 = 0xF1B0, + OP_CMP_imm_T2 = 0xF1B0, + OP_ADD_imm_T4 = 0xF200, + OP_MOV_imm_T3 = 0xF240, + OP_SUB_imm_T4 = 0xF2A0, + OP_MOVT = 0xF2C0, + OP_NOP_T2a = 0xF3AF, + OP_LDRB_imm_T3 = 0xF810, + OP_LDRB_reg_T2 = 0xF810, + OP_LDRH_reg_T2 = 0xF830, + OP_LDRH_imm_T3 = 0xF830, + OP_STR_imm_T4 = 0xF840, + OP_STR_reg_T2 = 0xF840, + OP_LDR_imm_T4 = 0xF850, + OP_LDR_reg_T2 = 0xF850, + OP_LDRB_imm_T2 = 0xF890, + OP_LDRH_imm_T2 = 0xF8B0, + OP_STR_imm_T3 = 0xF8C0, + OP_LDR_imm_T3 = 0xF8D0, + OP_LSL_reg_T2 = 0xFA00, + OP_LSR_reg_T2 = 0xFA20, + OP_ASR_reg_T2 = 0xFA40, + OP_ROR_reg_T2 = 0xFA60, + OP_SMULL_T1 = 0xFB80, + } OpcodeID1; + + typedef enum { + OP_B_T4b = 0x9000, + OP_NOP_T2b = 0x8000, + } OpcodeID2; + + struct FourFours { + FourFours(unsigned f3, unsigned f2, unsigned f1, unsigned f0) + { + m_u.f0 = f0; + m_u.f1 = f1; + m_u.f2 = f2; + m_u.f3 = f3; + } + + union { + unsigned value; + struct { + unsigned f0 : 4; + unsigned f1 : 4; + unsigned f2 : 4; + unsigned f3 : 4; + }; + } m_u; + }; + + class ARMInstructionFormatter; + + // false means else! + bool ifThenElseConditionBit(Condition condition, bool isIf) + { + return isIf ? (condition & 1) : !(condition & 1); + } + uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if, bool inst4if) + { + int mask = (ifThenElseConditionBit(condition, inst2if) << 3) + | (ifThenElseConditionBit(condition, inst3if) << 2) + | (ifThenElseConditionBit(condition, inst4if) << 1) + | 1; + ASSERT((condition != ConditionAL) || (mask & (mask - 1))); + return (condition << 4) | mask; + } + uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if) + { + int mask = (ifThenElseConditionBit(condition, inst2if) << 3) + | (ifThenElseConditionBit(condition, inst3if) << 2) + | 2; + ASSERT((condition != ConditionAL) || (mask & (mask - 1))); + return (condition << 4) | mask; + } + uint8_t ifThenElse(Condition condition, bool inst2if) + { + int mask = (ifThenElseConditionBit(condition, inst2if) << 3) + | 4; + ASSERT((condition != ConditionAL) || (mask & (mask - 1))); + return (condition << 4) | mask; + } + + uint8_t ifThenElse(Condition condition) + { + int mask = 8; + ASSERT((condition != ConditionAL) || (mask & (mask - 1))); + return (condition << 4) | mask; + } + +public: + + void add(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) + { + // Rd can only be SP if Rn is also SP. + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(imm.isValid()); + + if (rn == ARMRegisters::sp) { + if (!(rd & 8) && imm.isUInt10()) { + m_formatter.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1, rd, imm.getUInt10() >> 2); + return; + } else if ((rd == ARMRegisters::sp) && imm.isUInt9()) { + m_formatter.oneWordOp9Imm7(OP_ADD_SP_imm_T2, imm.getUInt9() >> 2); + return; + } + } else if (!((rd | rn) & 8)) { + if (imm.isUInt3()) { + m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); + return; + } else if ((rd == rn) && imm.isUInt8()) { + m_formatter.oneWordOp5Reg3Imm8(OP_ADD_imm_T2, rd, imm.getUInt8()); + return; + } + } + + if (imm.isEncodedImm()) + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T3, rn, rd, imm); + else { + ASSERT(imm.isUInt12()); + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T4, rn, rd, imm); + } + } + + void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) + { + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(!BadReg(rm)); + m_formatter.twoWordOp12Reg4FourFours(OP_ADD_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); + } + + // NOTE: In an IT block, add doesn't modify the flags register. + void add(RegisterID rd, RegisterID rn, RegisterID rm) + { + if (rd == rn) + m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rm, rd); + else if (rd == rm) + m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rn, rd); + else if (!((rd | rn | rm) & 8)) + m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd); + else + add(rd, rn, rm, ShiftTypeAndAmount()); + } + + // Not allowed in an IT (if then) block. + void add_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) + { + // Rd can only be SP if Rn is also SP. + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(imm.isEncodedImm()); + + if (!((rd | rn) & 8)) { + if (imm.isUInt3()) { + m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); + return; + } else if ((rd == rn) && imm.isUInt8()) { + m_formatter.oneWordOp5Reg3Imm8(OP_ADD_S_imm_T2, rd, imm.getUInt8()); + return; + } + } + + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_S_imm_T3, rn, rd, imm); + } + + // Not allowed in an IT (if then) block? + void add_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) + { + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(!BadReg(rm)); + m_formatter.twoWordOp12Reg4FourFours(OP_ADD_S_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); + } + + // Not allowed in an IT (if then) block. + void add_S(RegisterID rd, RegisterID rn, RegisterID rm) + { + if (!((rd | rn | rm) & 8)) + m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_S_reg_T1, rm, rn, rd); + else + add_S(rd, rn, rm, ShiftTypeAndAmount()); + } + + void ARM_and(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rn)); + ASSERT(imm.isEncodedImm()); + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_AND_imm_T1, rn, rd, imm); + } + + void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rn)); + ASSERT(!BadReg(rm)); + m_formatter.twoWordOp12Reg4FourFours(OP_AND_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); + } + + void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm) + { + if ((rd == rn) && !((rd | rm) & 8)) + m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rm, rd); + else if ((rd == rm) && !((rd | rn) & 8)) + m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rn, rd); + else + ARM_and(rd, rn, rm, ShiftTypeAndAmount()); + } + + void asr(RegisterID rd, RegisterID rm, int32_t shiftAmount) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rm)); + ShiftTypeAndAmount shift(SRType_ASR, shiftAmount); + m_formatter.twoWordOp16FourFours(OP_ASR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); + } + + void asr(RegisterID rd, RegisterID rn, RegisterID rm) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rn)); + ASSERT(!BadReg(rm)); + m_formatter.twoWordOp12Reg4FourFours(OP_ASR_reg_T2, rn, FourFours(0xf, rd, 0, rm)); + } + + // Only allowed in IT (if then) block if last instruction. + JmpSrc b() + { + m_formatter.twoWordOp16Op16(OP_B_T4a, OP_B_T4b); + return JmpSrc(m_formatter.size()); + } + + // Only allowed in IT (if then) block if last instruction. + JmpSrc blx(RegisterID rm) + { + ASSERT(rm != ARMRegisters::pc); + m_formatter.oneWordOp8RegReg143(OP_BLX, rm, (RegisterID)8); + return JmpSrc(m_formatter.size()); + } + + // Only allowed in IT (if then) block if last instruction. + JmpSrc bx(RegisterID rm) + { + m_formatter.oneWordOp8RegReg143(OP_BX, rm, (RegisterID)0); + return JmpSrc(m_formatter.size()); + } + + void bkpt(uint8_t imm=0) + { + m_formatter.oneWordOp8Imm8(OP_BKPT, imm); + } + + void cmn(RegisterID rn, ARMThumbImmediate imm) + { + ASSERT(rn != ARMRegisters::pc); + ASSERT(imm.isEncodedImm()); + + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm, rn, (RegisterID)0xf, imm); + } + + void cmp(RegisterID rn, ARMThumbImmediate imm) + { + ASSERT(rn != ARMRegisters::pc); + ASSERT(imm.isEncodedImm()); + + if (!(rn & 8) && imm.isUInt8()) + m_formatter.oneWordOp5Reg3Imm8(OP_CMP_imm_T1, rn, imm.getUInt8()); + else + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMP_imm_T2, rn, (RegisterID)0xf, imm); + } + + void cmp(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) + { + ASSERT(rn != ARMRegisters::pc); + ASSERT(!BadReg(rm)); + m_formatter.twoWordOp12Reg4FourFours(OP_CMP_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm)); + } + + void cmp(RegisterID rn, RegisterID rm) + { + if ((rn | rm) & 8) + cmp(rn, rm, ShiftTypeAndAmount()); + else + m_formatter.oneWordOp10Reg3Reg3(OP_CMP_reg_T1, rm, rn); + } + + // xor is not spelled with an 'e'. :-( + void eor(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rn)); + ASSERT(imm.isEncodedImm()); + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_EOR_imm_T1, rn, rd, imm); + } + + // xor is not spelled with an 'e'. :-( + void eor(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rn)); + ASSERT(!BadReg(rm)); + m_formatter.twoWordOp12Reg4FourFours(OP_EOR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); + } + + // xor is not spelled with an 'e'. :-( + void eor(RegisterID rd, RegisterID rn, RegisterID rm) + { + if ((rd == rn) && !((rd | rm) & 8)) + m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rm, rd); + else if ((rd == rm) && !((rd | rn) & 8)) + m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rn, rd); + else + eor(rd, rn, rm, ShiftTypeAndAmount()); + } + + void it(Condition cond) + { + m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond)); + } + + void it(Condition cond, bool inst2if) + { + m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if)); + } + + void it(Condition cond, bool inst2if, bool inst3if) + { + m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if)); + } + + void it(Condition cond, bool inst2if, bool inst3if, bool inst4if) + { + m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if, inst4if)); + } + + // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. + void ldr(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) + { + ASSERT(rn != ARMRegisters::pc); // LDR (literal) + ASSERT(imm.isUInt12()); + + if (!((rt | rn) & 8) && imm.isUInt7()) + m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt); + else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10()) + m_formatter.oneWordOp5Reg3Imm8(OP_LDR_imm_T2, rt, imm.getUInt10() >> 2); + else + m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, imm.getUInt12()); + } + + // If index is set, this is a regular offset or a pre-indexed load; + // if index is not set then is is a post-index load. + // + // If wback is set rn is updated - this is a pre or post index load, + // if wback is not set this is a regular offset memory access. + // + // (-255 <= offset <= 255) + // _reg = REG[rn] + // _tmp = _reg + offset + // MEM[index ? _tmp : _reg] = REG[rt] + // if (wback) REG[rn] = _tmp + void ldr(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) + { + ASSERT(rt != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(index || wback); + ASSERT(!wback | (rt != rn)); + + bool add = true; + if (offset < 0) { + add = false; + offset = -offset; + } + ASSERT((offset & ~0xff) == 0); + + offset |= (wback << 8); + offset |= (add << 9); + offset |= (index << 10); + offset |= (1 << 11); + + m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T4, rn, rt, offset); + } + + // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. + void ldr(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0) + { + ASSERT(rn != ARMRegisters::pc); // LDR (literal) + ASSERT(!BadReg(rm)); + ASSERT(shift <= 3); + + if (!shift && !((rt | rn | rm) & 8)) + m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDR_reg_T1, rm, rn, rt); + else + m_formatter.twoWordOp12Reg4FourFours(OP_LDR_reg_T2, rn, FourFours(rt, 0, shift, rm)); + } + + // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. + void ldrh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) + { + ASSERT(rn != ARMRegisters::pc); // LDR (literal) + ASSERT(imm.isUInt12()); + + if (!((rt | rn) & 8) && imm.isUInt6()) + m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1, imm.getUInt6() >> 2, rn, rt); + else + m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2, rn, rt, imm.getUInt12()); + } + + // If index is set, this is a regular offset or a pre-indexed load; + // if index is not set then is is a post-index load. + // + // If wback is set rn is updated - this is a pre or post index load, + // if wback is not set this is a regular offset memory access. + // + // (-255 <= offset <= 255) + // _reg = REG[rn] + // _tmp = _reg + offset + // MEM[index ? _tmp : _reg] = REG[rt] + // if (wback) REG[rn] = _tmp + void ldrh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) + { + ASSERT(rt != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(index || wback); + ASSERT(!wback | (rt != rn)); + + bool add = true; + if (offset < 0) { + add = false; + offset = -offset; + } + ASSERT((offset & ~0xff) == 0); + + offset |= (wback << 8); + offset |= (add << 9); + offset |= (index << 10); + offset |= (1 << 11); + + m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T3, rn, rt, offset); + } + + void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0) + { + ASSERT(!BadReg(rt)); // Memory hint + ASSERT(rn != ARMRegisters::pc); // LDRH (literal) + ASSERT(!BadReg(rm)); + ASSERT(shift <= 3); + + if (!shift && !((rt | rn | rm) & 8)) + m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRH_reg_T1, rm, rn, rt); + else + m_formatter.twoWordOp12Reg4FourFours(OP_LDRH_reg_T2, rn, FourFours(rt, 0, shift, rm)); + } + + void ldrb(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) + { + ASSERT(rn != ARMRegisters::pc); // LDR (literal) + ASSERT(imm.isUInt12()); + + if (!((rt | rn) & 8) && imm.isUInt5()) + m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRB_imm_T1, imm.getUInt5(), rn, rt); + else + m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T2, rn, rt, imm.getUInt12()); + } + + void ldrb(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) + { + ASSERT(rt != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(index || wback); + ASSERT(!wback | (rt != rn)); + + bool add = true; + if (offset < 0) { + add = false; + offset = -offset; + } + + ASSERT(!(offset & ~0xff)); + + offset |= (wback << 8); + offset |= (add << 9); + offset |= (index << 10); + offset |= (1 << 11); + + m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T3, rn, rt, offset); + } + + void ldrb(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0) + { + ASSERT(rn != ARMRegisters::pc); // LDR (literal) + ASSERT(!BadReg(rm)); + ASSERT(shift <= 3); + + if (!shift && !((rt | rn | rm) & 8)) + m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRB_reg_T1, rm, rn, rt); + else + m_formatter.twoWordOp12Reg4FourFours(OP_LDRB_reg_T2, rn, FourFours(rt, 0, shift, rm)); + } + + void lsl(RegisterID rd, RegisterID rm, int32_t shiftAmount) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rm)); + ShiftTypeAndAmount shift(SRType_LSL, shiftAmount); + m_formatter.twoWordOp16FourFours(OP_LSL_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); + } + + void lsl(RegisterID rd, RegisterID rn, RegisterID rm) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rn)); + ASSERT(!BadReg(rm)); + m_formatter.twoWordOp12Reg4FourFours(OP_LSL_reg_T2, rn, FourFours(0xf, rd, 0, rm)); + } + + void lsr(RegisterID rd, RegisterID rm, int32_t shiftAmount) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rm)); + ShiftTypeAndAmount shift(SRType_LSR, shiftAmount); + m_formatter.twoWordOp16FourFours(OP_LSR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); + } + + void lsr(RegisterID rd, RegisterID rn, RegisterID rm) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rn)); + ASSERT(!BadReg(rm)); + m_formatter.twoWordOp12Reg4FourFours(OP_LSR_reg_T2, rn, FourFours(0xf, rd, 0, rm)); + } + + void movT3(RegisterID rd, ARMThumbImmediate imm) + { + ASSERT(imm.isValid()); + ASSERT(!imm.isEncodedImm()); + ASSERT(!BadReg(rd)); + + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3, imm.m_value.imm4, rd, imm); + } + + void mov(RegisterID rd, ARMThumbImmediate imm) + { + ASSERT(imm.isValid()); + ASSERT(!BadReg(rd)); + + if ((rd < 8) && imm.isUInt8()) + m_formatter.oneWordOp5Reg3Imm8(OP_MOV_imm_T1, rd, imm.getUInt8()); + else if (imm.isEncodedImm()) + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T2, 0xf, rd, imm); + else + movT3(rd, imm); + } + + void mov(RegisterID rd, RegisterID rm) + { + m_formatter.oneWordOp8RegReg143(OP_MOV_reg_T1, rm, rd); + } + + void movt(RegisterID rd, ARMThumbImmediate imm) + { + ASSERT(imm.isUInt16()); + ASSERT(!BadReg(rd)); + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOVT, imm.m_value.imm4, rd, imm); + } + + void mvn(RegisterID rd, ARMThumbImmediate imm) + { + ASSERT(imm.isEncodedImm()); + ASSERT(!BadReg(rd)); + + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MVN_imm, 0xf, rd, imm); + } + + void mvn(RegisterID rd, RegisterID rm, ShiftTypeAndAmount shift) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rm)); + m_formatter.twoWordOp16FourFours(OP_MVN_reg_T2, FourFours(shift.hi4(), rd, shift.lo4(), rm)); + } + + void mvn(RegisterID rd, RegisterID rm) + { + if (!((rd | rm) & 8)) + m_formatter.oneWordOp10Reg3Reg3(OP_MVN_reg_T1, rm, rd); + else + mvn(rd, rm, ShiftTypeAndAmount()); + } + + void orr(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rn)); + ASSERT(imm.isEncodedImm()); + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ORR_imm_T1, rn, rd, imm); + } + + void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rn)); + ASSERT(!BadReg(rm)); + m_formatter.twoWordOp12Reg4FourFours(OP_ORR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); + } + + void orr(RegisterID rd, RegisterID rn, RegisterID rm) + { + if ((rd == rn) && !((rd | rm) & 8)) + m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rm, rd); + else if ((rd == rm) && !((rd | rn) & 8)) + m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rn, rd); + else + orr(rd, rn, rm, ShiftTypeAndAmount()); + } + + void ror(RegisterID rd, RegisterID rm, int32_t shiftAmount) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rm)); + ShiftTypeAndAmount shift(SRType_ROR, shiftAmount); + m_formatter.twoWordOp16FourFours(OP_ROR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); + } + + void ror(RegisterID rd, RegisterID rn, RegisterID rm) + { + ASSERT(!BadReg(rd)); + ASSERT(!BadReg(rn)); + ASSERT(!BadReg(rm)); + m_formatter.twoWordOp12Reg4FourFours(OP_ROR_reg_T2, rn, FourFours(0xf, rd, 0, rm)); + } + + void smull(RegisterID rdLo, RegisterID rdHi, RegisterID rn, RegisterID rm) + { + ASSERT(!BadReg(rdLo)); + ASSERT(!BadReg(rdHi)); + ASSERT(!BadReg(rn)); + ASSERT(!BadReg(rm)); + ASSERT(rdLo != rdHi); + m_formatter.twoWordOp12Reg4FourFours(OP_SMULL_T1, rn, FourFours(rdLo, rdHi, 0, rm)); + } + + // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. + void str(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) + { + ASSERT(rt != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(imm.isUInt12()); + + if (!((rt | rn) & 8) && imm.isUInt7()) + m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STR_imm_T1, imm.getUInt7() >> 2, rn, rt); + else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10()) + m_formatter.oneWordOp5Reg3Imm8(OP_STR_imm_T2, rt, imm.getUInt10() >> 2); + else + m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3, rn, rt, imm.getUInt12()); + } + + // If index is set, this is a regular offset or a pre-indexed store; + // if index is not set then is is a post-index store. + // + // If wback is set rn is updated - this is a pre or post index store, + // if wback is not set this is a regular offset memory access. + // + // (-255 <= offset <= 255) + // _reg = REG[rn] + // _tmp = _reg + offset + // MEM[index ? _tmp : _reg] = REG[rt] + // if (wback) REG[rn] = _tmp + void str(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) + { + ASSERT(rt != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(index || wback); + ASSERT(!wback | (rt != rn)); + + bool add = true; + if (offset < 0) { + add = false; + offset = -offset; + } + ASSERT((offset & ~0xff) == 0); + + offset |= (wback << 8); + offset |= (add << 9); + offset |= (index << 10); + offset |= (1 << 11); + + m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T4, rn, rt, offset); + } + + // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. + void str(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0) + { + ASSERT(rn != ARMRegisters::pc); + ASSERT(!BadReg(rm)); + ASSERT(shift <= 3); + + if (!shift && !((rt | rn | rm) & 8)) + m_formatter.oneWordOp7Reg3Reg3Reg3(OP_STR_reg_T1, rm, rn, rt); + else + m_formatter.twoWordOp12Reg4FourFours(OP_STR_reg_T2, rn, FourFours(rt, 0, shift, rm)); + } + + void sub(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) + { + // Rd can only be SP if Rn is also SP. + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(imm.isValid()); + + if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) { + m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2); + return; + } else if (!((rd | rn) & 8)) { + if (imm.isUInt3()) { + m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); + return; + } else if ((rd == rn) && imm.isUInt8()) { + m_formatter.oneWordOp5Reg3Imm8(OP_SUB_imm_T2, rd, imm.getUInt8()); + return; + } + } + + if (imm.isEncodedImm()) + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T3, rn, rd, imm); + else { + ASSERT(imm.isUInt12()); + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T4, rn, rd, imm); + } + } + + void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) + { + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(!BadReg(rm)); + m_formatter.twoWordOp12Reg4FourFours(OP_SUB_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); + } + + // NOTE: In an IT block, add doesn't modify the flags register. + void sub(RegisterID rd, RegisterID rn, RegisterID rm) + { + if (!((rd | rn | rm) & 8)) + m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd); + else + sub(rd, rn, rm, ShiftTypeAndAmount()); + } + + // Not allowed in an IT (if then) block. + void sub_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) + { + // Rd can only be SP if Rn is also SP. + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(imm.isValid()); + + if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) { + m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2); + return; + } else if (!((rd | rn) & 8)) { + if (imm.isUInt3()) { + m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); + return; + } else if ((rd == rn) && imm.isUInt8()) { + m_formatter.oneWordOp5Reg3Imm8(OP_SUB_S_imm_T2, rd, imm.getUInt8()); + return; + } + } + + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_S_imm_T3, rn, rd, imm); + } + + // Not allowed in an IT (if then) block? + void sub_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) + { + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(!BadReg(rm)); + m_formatter.twoWordOp12Reg4FourFours(OP_SUB_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); + } + + // Not allowed in an IT (if then) block. + void sub_S(RegisterID rd, RegisterID rn, RegisterID rm) + { + if (!((rd | rn | rm) & 8)) + m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_S_reg_T1, rm, rn, rd); + else + sub_S(rd, rn, rm, ShiftTypeAndAmount()); + } + + void tst(RegisterID rn, ARMThumbImmediate imm) + { + ASSERT(!BadReg(rn)); + ASSERT(imm.isEncodedImm()); + + m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_TST_imm, rn, (RegisterID)0xf, imm); + } + + void tst(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) + { + ASSERT(!BadReg(rn)); + ASSERT(!BadReg(rm)); + m_formatter.twoWordOp12Reg4FourFours(OP_TST_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm)); + } + + void tst(RegisterID rn, RegisterID rm) + { + if ((rn | rm) & 8) + tst(rn, rm, ShiftTypeAndAmount()); + else + m_formatter.oneWordOp10Reg3Reg3(OP_TST_reg_T1, rm, rn); + } + + void vadd_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm) + { + m_formatter.vfpOp(0x0b00ee30 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16)); + } + + void vcmp_F64(FPRegisterID rd, FPRegisterID rm) + { + m_formatter.vfpOp(0x0bc0eeb4 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rm, 21, 16)); + } + + void vcvt_F64_S32(FPRegisterID fd, FPRegisterID sm) + { + m_formatter.vfpOp(0x0bc0eeb8 | doubleRegisterMask(fd, 6, 28) | singleRegisterMask(sm, 16, 21)); + } + + void vcvt_S32_F64(FPRegisterID sd, FPRegisterID fm) + { + m_formatter.vfpOp(0x0bc0eebd | singleRegisterMask(sd, 28, 6) | doubleRegisterMask(fm, 21, 16)); + } + + void vldr(FPRegisterID rd, RegisterID rn, int32_t imm) + { + vmem(rd, rn, imm, true); + } + + void vmov(RegisterID rd, FPRegisterID sn) + { + m_formatter.vfpOp(0x0a10ee10 | (rd << 28) | singleRegisterMask(sn, 0, 23)); + } + + void vmov(FPRegisterID sn, RegisterID rd) + { + m_formatter.vfpOp(0x0a10ee00 | (rd << 28) | singleRegisterMask(sn, 0, 23)); + } + + // move FPSCR flags to APSR. + void vmrs_APSR_nzcv_FPSCR() + { + m_formatter.vfpOp(0xfa10eef1); + } + + void vmul_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm) + { + m_formatter.vfpOp(0x0b00ee20 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16)); + } + + void vstr(FPRegisterID rd, RegisterID rn, int32_t imm) + { + vmem(rd, rn, imm, false); + } + + void vsub_F64(FPRegisterID rd, FPRegisterID rn, FPRegisterID rm) + { + m_formatter.vfpOp(0x0b40ee30 | doubleRegisterMask(rd, 6, 28) | doubleRegisterMask(rn, 23, 0) | doubleRegisterMask(rm, 21, 16)); + } + + + JmpDst label() + { + return JmpDst(m_formatter.size()); + } + + JmpDst align(int alignment) + { + while (!m_formatter.isAligned(alignment)) + bkpt(); + + return label(); + } + + static void* getRelocatedAddress(void* code, JmpSrc jump) + { + ASSERT(jump.m_offset != -1); + + return reinterpret_cast(reinterpret_cast(code) + jump.m_offset); + } + + static void* getRelocatedAddress(void* code, JmpDst destination) + { + ASSERT(destination.m_offset != -1); + + return reinterpret_cast(reinterpret_cast(code) + destination.m_offset); + } + + static int getDifferenceBetweenLabels(JmpDst src, JmpDst dst) + { + return dst.m_offset - src.m_offset; + } + + static int getDifferenceBetweenLabels(JmpDst src, JmpSrc dst) + { + return dst.m_offset - src.m_offset; + } + + static int getDifferenceBetweenLabels(JmpSrc src, JmpDst dst) + { + return dst.m_offset - src.m_offset; + } + + // Assembler admin methods: + + size_t size() const + { + return m_formatter.size(); + } + + void* executableCopy(ExecutablePool* allocator) + { + void* copy = m_formatter.executableCopy(allocator); + + unsigned jumpCount = m_jumpsToLink.size(); + for (unsigned i = 0; i < jumpCount; ++i) { + uint16_t* location = reinterpret_cast(reinterpret_cast(copy) + m_jumpsToLink[i].from); + uint16_t* target = reinterpret_cast(reinterpret_cast(copy) + m_jumpsToLink[i].to); + linkJumpAbsolute(location, target); + } + m_jumpsToLink.clear(); + + ASSERT(copy); + return copy; + } + + static unsigned getCallReturnOffset(JmpSrc call) + { + ASSERT(call.m_offset >= 0); + return call.m_offset; + } + + // Linking & patching: + // + // 'link' and 'patch' methods are for use on unprotected code - such as the code + // within the AssemblerBuffer, and code being patched by the patch buffer. Once + // code has been finalized it is (platform support permitting) within a non- + // writable region of memory; to modify the code in an execute-only execuable + // pool the 'repatch' and 'relink' methods should be used. + + void linkJump(JmpSrc from, JmpDst to) + { + ASSERT(to.m_offset != -1); + ASSERT(from.m_offset != -1); + m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset)); + } + + static void linkJump(void* code, JmpSrc from, void* to) + { + ASSERT(from.m_offset != -1); + + uint16_t* location = reinterpret_cast(reinterpret_cast(code) + from.m_offset); + linkJumpAbsolute(location, to); + } + + // bah, this mathod should really be static, since it is used by the LinkBuffer. + // return a bool saying whether the link was successful? + static void linkCall(void* code, JmpSrc from, void* to) + { + ASSERT(!(reinterpret_cast(code) & 1)); + ASSERT(from.m_offset != -1); + ASSERT(reinterpret_cast(to) & 1); + + setPointer(reinterpret_cast(reinterpret_cast(code) + from.m_offset) - 1, to); + } + + static void linkPointer(void* code, JmpDst where, void* value) + { + setPointer(reinterpret_cast(code) + where.m_offset, value); + } + + static void relinkJump(void* from, void* to) + { + ASSERT(!(reinterpret_cast(from) & 1)); + ASSERT(!(reinterpret_cast(to) & 1)); + + linkJumpAbsolute(reinterpret_cast(from), to); + + ExecutableAllocator::cacheFlush(reinterpret_cast(from) - 5, 5 * sizeof(uint16_t)); + } + + static bool canRelinkJump(void* from, void* to) + { + return true; + } + + static void relinkCall(void* from, void* to) + { + ASSERT(!(reinterpret_cast(from) & 1)); + ASSERT(reinterpret_cast(to) & 1); + + setPointer(reinterpret_cast(from) - 1, to); + + ExecutableAllocator::cacheFlush(reinterpret_cast(from) - 5, 4 * sizeof(uint16_t)); + } + + static void repatchInt32(void* where, int32_t value) + { + ASSERT(!(reinterpret_cast(where) & 1)); + + setInt32(where, value); + + ExecutableAllocator::cacheFlush(reinterpret_cast(where) - 4, 4 * sizeof(uint16_t)); + } + + static void repatchPointer(void* where, void* value) + { + ASSERT(!(reinterpret_cast(where) & 1)); + + setPointer(where, value); + + ExecutableAllocator::cacheFlush(reinterpret_cast(where) - 4, 4 * sizeof(uint16_t)); + } + + static void repatchLoadPtrToLEA(void* where) + { + ASSERT(!(reinterpret_cast(where) & 1)); + + uint16_t* loadOp = reinterpret_cast(where) + 4; + ASSERT((*loadOp & 0xfff0) == OP_LDR_reg_T2); + + *loadOp = OP_ADD_reg_T3 | (*loadOp & 0xf); + ExecutableAllocator::cacheFlush(loadOp, sizeof(uint16_t)); + } + + static void repatchLEAToLoadPtr(void* where) + { + ASSERT(!(reinterpret_cast(where) & 1)); + + uint16_t* loadOp = reinterpret_cast(where) + 4; + if ((*loadOp & 0xfff0) == OP_LDR_reg_T2) + return; + + ASSERT((*loadOp & 0xfff0) == OP_ADD_reg_T3); + + *loadOp = OP_LDR_reg_T2 | (*loadOp & 0xf); + ExecutableAllocator::cacheFlush(loadOp, sizeof(uint16_t)); + } + +private: + + // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. + // (i.e. +/-(0..255) 32-bit words) + void vmem(FPRegisterID rd, RegisterID rn, int32_t imm, bool isLoad) + { + bool up; + uint32_t offset; + if (imm < 0) { + offset = -imm; + up = false; + } else { + offset = imm; + up = true; + } + + // offset is effectively leftshifted by 2 already (the bottom two bits are zero, and not + // reperesented in the instruction. Left shift by 14, to mov it into position 0x00AA0000. + ASSERT((offset & ~(0xff << 2)) == 0); + offset <<= 14; + + m_formatter.vfpOp(0x0b00ed00 | offset | (up << 7) | (isLoad << 4) | doubleRegisterMask(rd, 6, 28) | rn); + } + + static void setInt32(void* code, uint32_t value) + { + uint16_t* location = reinterpret_cast(code); + ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2)); + + ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast(value)); + ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast(value >> 16)); + location[-4] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16); + location[-3] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-3] >> 8) & 0xf, lo16); + location[-2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16); + location[-1] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-1] >> 8) & 0xf, hi16); + + ExecutableAllocator::cacheFlush(location - 4, 4 * sizeof(uint16_t)); + } + + static void setPointer(void* code, void* value) + { + setInt32(code, reinterpret_cast(value)); + } + + static bool isB(void* address) + { + uint16_t* instruction = static_cast(address); + return ((instruction[0] & 0xf800) == OP_B_T4a) && ((instruction[1] & 0xd000) == OP_B_T4b); + } + + static bool isBX(void* address) + { + uint16_t* instruction = static_cast(address); + return (instruction[0] & 0xff87) == OP_BX; + } + + static bool isMOV_imm_T3(void* address) + { + uint16_t* instruction = static_cast(address); + return ((instruction[0] & 0xFBF0) == OP_MOV_imm_T3) && ((instruction[1] & 0x8000) == 0); + } + + static bool isMOVT(void* address) + { + uint16_t* instruction = static_cast(address); + return ((instruction[0] & 0xFBF0) == OP_MOVT) && ((instruction[1] & 0x8000) == 0); + } + + static bool isNOP_T1(void* address) + { + uint16_t* instruction = static_cast(address); + return instruction[0] == OP_NOP_T1; + } + + static bool isNOP_T2(void* address) + { + uint16_t* instruction = static_cast(address); + return (instruction[0] == OP_NOP_T2a) && (instruction[1] == OP_NOP_T2b); + } + + static void linkJumpAbsolute(uint16_t* instruction, void* target) + { + // FIMXE: this should be up in the MacroAssembler layer. :-( + const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip; + + ASSERT(!(reinterpret_cast(instruction) & 1)); + ASSERT(!(reinterpret_cast(target) & 1)); + + ASSERT( (isMOV_imm_T3(instruction - 5) && isMOVT(instruction - 3) && isBX(instruction - 1)) + || (isNOP_T1(instruction - 5) && isNOP_T2(instruction - 4) && isB(instruction - 2)) ); + + intptr_t relative = reinterpret_cast(target) - (reinterpret_cast(instruction)); + + // From Cortex-A8 errata: + // If the 32-bit Thumb-2 branch instruction spans two 4KiB regions and + // the target of the branch falls within the first region it is + // possible for the processor to incorrectly determine the branch + // instruction, and it is also possible in some cases for the processor + // to enter a deadlock state. + // The instruction is spanning two pages if it ends at an address ending 0x002 + bool spansTwo4K = ((reinterpret_cast(instruction) & 0xfff) == 0x002); + // The target is in the first page if the jump branch back by [3..0x1002] bytes + bool targetInFirstPage = (relative >= -0x1002) && (relative < -2); + bool wouldTriggerA8Errata = spansTwo4K && targetInFirstPage; + + if (((relative << 7) >> 7) == relative && !wouldTriggerA8Errata) { + // ARM encoding for the top two bits below the sign bit is 'peculiar'. + if (relative >= 0) + relative ^= 0xC00000; + + // All branch offsets should be an even distance. + ASSERT(!(relative & 1)); + // There may be a better way to fix this, but right now put the NOPs first, since in the + // case of an conditional branch this will be coming after an ITTT predicating *three* + // instructions! Looking backwards to modify the ITTT to an IT is not easy, due to + // variable wdith encoding - the previous instruction might *look* like an ITTT but + // actually be the second half of a 2-word op. + instruction[-5] = OP_NOP_T1; + instruction[-4] = OP_NOP_T2a; + instruction[-3] = OP_NOP_T2b; + instruction[-2] = OP_B_T4a | ((relative & 0x1000000) >> 14) | ((relative & 0x3ff000) >> 12); + instruction[-1] = OP_B_T4b | ((relative & 0x800000) >> 10) | ((relative & 0x400000) >> 11) | ((relative & 0xffe) >> 1); + } else { + ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast(reinterpret_cast(target) + 1)); + ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast(reinterpret_cast(target) >> 16)); + instruction[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16); + instruction[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, lo16); + instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16); + instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16); + instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3); + } + } + + static uint16_t twoWordOp5i6Imm4Reg4EncodedImmFirst(uint16_t op, ARMThumbImmediate imm) + { + return op | (imm.m_value.i << 10) | imm.m_value.imm4; + } + static uint16_t twoWordOp5i6Imm4Reg4EncodedImmSecond(uint16_t rd, ARMThumbImmediate imm) + { + return (imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8; + } + + class ARMInstructionFormatter { + public: + void oneWordOp5Reg3Imm8(OpcodeID op, RegisterID rd, uint8_t imm) + { + m_buffer.putShort(op | (rd << 8) | imm); + } + + void oneWordOp5Imm5Reg3Reg3(OpcodeID op, uint8_t imm, RegisterID reg1, RegisterID reg2) + { + m_buffer.putShort(op | (imm << 6) | (reg1 << 3) | reg2); + } + + void oneWordOp7Reg3Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2, RegisterID reg3) + { + m_buffer.putShort(op | (reg1 << 6) | (reg2 << 3) | reg3); + } + + void oneWordOp8Imm8(OpcodeID op, uint8_t imm) + { + m_buffer.putShort(op | imm); + } + + void oneWordOp8RegReg143(OpcodeID op, RegisterID reg1, RegisterID reg2) + { + m_buffer.putShort(op | ((reg2 & 8) << 4) | (reg1 << 3) | (reg2 & 7)); + } + void oneWordOp9Imm7(OpcodeID op, uint8_t imm) + { + m_buffer.putShort(op | imm); + } + + void oneWordOp10Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2) + { + m_buffer.putShort(op | (reg1 << 3) | reg2); + } + + void twoWordOp12Reg4FourFours(OpcodeID1 op, RegisterID reg, FourFours ff) + { + m_buffer.putShort(op | reg); + m_buffer.putShort(ff.m_u.value); + } + + void twoWordOp16FourFours(OpcodeID1 op, FourFours ff) + { + m_buffer.putShort(op); + m_buffer.putShort(ff.m_u.value); + } + + void twoWordOp16Op16(OpcodeID1 op1, OpcodeID2 op2) + { + m_buffer.putShort(op1); + m_buffer.putShort(op2); + } + + void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op, int imm4, RegisterID rd, ARMThumbImmediate imm) + { + ARMThumbImmediate newImm = imm; + newImm.m_value.imm4 = imm4; + + m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst(op, newImm)); + m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, newImm)); + } + + void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm) + { + m_buffer.putShort(op | reg1); + m_buffer.putShort((reg2 << 12) | imm); + } + + void vfpOp(int32_t op) + { + m_buffer.putInt(op); + } + + + // Administrative methods: + + size_t size() const { return m_buffer.size(); } + bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); } + void* data() const { return m_buffer.data(); } + void* executableCopy(ExecutablePool* allocator) { return m_buffer.executableCopy(allocator); } + bool oom() const { return m_buffer.oom(); } + + private: + AssemblerBuffer m_buffer; + } m_formatter; + + Vector m_jumpsToLink; +}; + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2) + +#endif // ARMAssembler_h diff --git a/js/src/assembler/assembler/AbstractMacroAssembler.h b/js/src/assembler/assembler/AbstractMacroAssembler.h new file mode 100644 index 0000000..77958d9 --- /dev/null +++ b/js/src/assembler/assembler/AbstractMacroAssembler.h @@ -0,0 +1,611 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef AbstractMacroAssembler_h +#define AbstractMacroAssembler_h + +#include "assembler/wtf/Platform.h" +#include "assembler/assembler/MacroAssemblerCodeRef.h" +#include "assembler/assembler/CodeLocation.h" +#include "jsstdint.h" + +#if ENABLE_ASSEMBLER + +namespace JSC { + +class LinkBuffer; +class RepatchBuffer; + +template +class AbstractMacroAssembler { +public: + typedef AssemblerType AssemblerType_T; + + typedef MacroAssemblerCodePtr CodePtr; + typedef MacroAssemblerCodeRef CodeRef; + + class Jump; + + typedef typename AssemblerType::RegisterID RegisterID; + typedef typename AssemblerType::FPRegisterID FPRegisterID; + typedef typename AssemblerType::JmpSrc JmpSrc; + typedef typename AssemblerType::JmpDst JmpDst; + +#ifdef DEBUG + void setSpewPath(bool isOOLPath) + { + m_assembler.isOOLPath = isOOLPath; + } +#endif + + // Section 1: MacroAssembler operand types + // + // The following types are used as operands to MacroAssembler operations, + // describing immediate and memory operands to the instructions to be planted. + + + enum Scale { + TimesOne, + TimesTwo, + TimesFour, + TimesEight + }; + + // Address: + // + // Describes a simple base-offset address. + struct Address { + explicit Address() {} + + explicit Address(RegisterID base, int32_t offset = 0) + : base(base) + , offset(offset) + { + } + + RegisterID base; + int32_t offset; + }; + + struct ExtendedAddress { + explicit ExtendedAddress(RegisterID base, intptr_t offset = 0) + : base(base) + , offset(offset) + { + } + + RegisterID base; + intptr_t offset; + }; + + // ImplicitAddress: + // + // This class is used for explicit 'load' and 'store' operations + // (as opposed to situations in which a memory operand is provided + // to a generic operation, such as an integer arithmetic instruction). + // + // In the case of a load (or store) operation we want to permit + // addresses to be implicitly constructed, e.g. the two calls: + // + // load32(Address(addrReg), destReg); + // load32(addrReg, destReg); + // + // Are equivalent, and the explicit wrapping of the Address in the former + // is unnecessary. + struct ImplicitAddress { + ImplicitAddress(RegisterID base) + : base(base) + , offset(0) + { + } + + ImplicitAddress(Address address) + : base(address.base) + , offset(address.offset) + { + } + + RegisterID base; + int32_t offset; + }; + + // BaseIndex: + // + // Describes a complex addressing mode. + struct BaseIndex { + BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0) + : base(base) + , index(index) + , scale(scale) + , offset(offset) + { + } + + RegisterID base; + RegisterID index; + Scale scale; + int32_t offset; + }; + + // AbsoluteAddress: + // + // Describes an memory operand given by a pointer. For regular load & store + // operations an unwrapped void* will be used, rather than using this. + struct AbsoluteAddress { + explicit AbsoluteAddress(void* ptr) + : m_ptr(ptr) + { + } + + void* m_ptr; + }; + + // ImmPtr: + // + // A pointer sized immediate operand to an instruction - this is wrapped + // in a class requiring explicit construction in order to differentiate + // from pointers used as absolute addresses to memory operations + struct ImmPtr { + explicit ImmPtr(const void* value) + : m_value(value) + { + } + + intptr_t asIntptr() + { + return reinterpret_cast(m_value); + } + + const void* m_value; + }; + + // Imm32: + // + // A 32bit immediate operand to an instruction - this is wrapped in a + // class requiring explicit construction in order to prevent RegisterIDs + // (which are implemented as an enum) from accidentally being passed as + // immediate values. + struct Imm32 { + explicit Imm32(int32_t value) + : m_value(value) +#if WTF_CPU_ARM || WTF_CPU_MIPS + , m_isPointer(false) +#endif + { + } + +#if !WTF_CPU_X86_64 + explicit Imm32(ImmPtr ptr) + : m_value(ptr.asIntptr()) +#if WTF_CPU_ARM || WTF_CPU_MIPS + , m_isPointer(true) +#endif + { + } +#endif + + int32_t m_value; +#if WTF_CPU_ARM || WTF_CPU_MIPS + // We rely on being able to regenerate code to recover exception handling + // information. Since ARMv7 supports 16-bit immediates there is a danger + // that if pointer values change the layout of the generated code will change. + // To avoid this problem, always generate pointers (and thus Imm32s constructed + // from ImmPtrs) with a code sequence that is able to represent any pointer + // value - don't use a more compact form in these cases. + // Same for MIPS. + bool m_isPointer; +#endif + }; + + struct ImmDouble { + union { + struct { +#if WTF_CPU_BIG_ENDIAN || WTF_CPU_MIDDLE_ENDIAN + uint32 msb, lsb; +#else + uint32 lsb, msb; +#endif + } s; + uint64_t u64; + double d; + } u; + + explicit ImmDouble(double d) { + u.d = d; + } + }; + + + // Section 2: MacroAssembler code buffer handles + // + // The following types are used to reference items in the code buffer + // during JIT code generation. For example, the type Jump is used to + // track the location of a jump instruction so that it may later be + // linked to a label marking its destination. + + + // Label: + // + // A Label records a point in the generated instruction stream, typically such that + // it may be used as a destination for a jump. + class Label { + template + friend class AbstractMacroAssembler; + friend class Jump; + friend class MacroAssemblerCodeRef; + friend class LinkBuffer; + + public: + Label() + { + } + + Label(AbstractMacroAssembler* masm) + : m_label(masm->m_assembler.label()) + { + } + + bool isUsed() const { return m_label.isUsed(); } + void used() { m_label.used(); } + bool isValid() const { return m_label.isValid(); } + private: + JmpDst m_label; + }; + + // DataLabelPtr: + // + // A DataLabelPtr is used to refer to a location in the code containing a pointer to be + // patched after the code has been generated. + class DataLabelPtr { + template + friend class AbstractMacroAssembler; + friend class LinkBuffer; + public: + DataLabelPtr() + { + } + + DataLabelPtr(AbstractMacroAssembler* masm) + : m_label(masm->m_assembler.label()) + { + } + + private: + JmpDst m_label; + }; + + // DataLabel32: + // + // A DataLabel32 is used to refer to a location in the code containing a + // 32-bit constant to be patched after the code has been generated. + class DataLabel32 { + template + friend class AbstractMacroAssembler; + friend class LinkBuffer; + public: + DataLabel32() + { + } + + DataLabel32(AbstractMacroAssembler* masm) + : m_label(masm->m_assembler.label()) + { + } + + private: + JmpDst m_label; + }; + + // Call: + // + // A Call object is a reference to a call instruction that has been planted + // into the code buffer - it is typically used to link the call, setting the + // relative offset such that when executed it will call to the desired + // destination. + class Call { + template + friend class AbstractMacroAssembler; + + public: + enum Flags { + None = 0x0, + Linkable = 0x1, + Near = 0x2, + LinkableNear = 0x3 + }; + + Call() + : m_flags(None) + { + } + + Call(JmpSrc jmp, Flags flags) + : m_jmp(jmp) + , m_flags(flags) + { + } + + bool isFlagSet(Flags flag) + { + return !!(m_flags & flag); + } + + static Call fromTailJump(Jump jump) + { + return Call(jump.m_jmp, Linkable); + } + + JmpSrc m_jmp; + private: + Flags m_flags; + }; + + // Jump: + // + // A jump object is a reference to a jump instruction that has been planted + // into the code buffer - it is typically used to link the jump, setting the + // relative offset such that when executed it will jump to the desired + // destination. + class Jump { + template + friend class AbstractMacroAssembler; + friend class Call; + friend class LinkBuffer; + public: + Jump() + { + } + + Jump(JmpSrc jmp) + : m_jmp(jmp) + { + } + + void link(AbstractMacroAssembler* masm) + { + masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label()); + } + + void linkTo(Label label, AbstractMacroAssembler* masm) + { + masm->m_assembler.linkJump(m_jmp, label.m_label); + } + + private: + JmpSrc m_jmp; + }; + + // JumpList: + // + // A JumpList is a set of Jump objects. + // All jumps in the set will be linked to the same destination. + class JumpList { + friend class LinkBuffer; + + public: + typedef js::Vector JumpVector; + + void link(AbstractMacroAssembler* masm) + { + size_t size = m_jumps.length(); + for (size_t i = 0; i < size; ++i) + m_jumps[i].link(masm); + m_jumps.clear(); + } + + void linkTo(Label label, AbstractMacroAssembler* masm) + { + size_t size = m_jumps.length(); + for (size_t i = 0; i < size; ++i) + m_jumps[i].linkTo(label, masm); + m_jumps.clear(); + } + + void append(Jump jump) + { + m_jumps.append(jump); + } + + void append(JumpList& other) + { + m_jumps.append(other.m_jumps.begin(), other.m_jumps.length()); + } + + bool empty() + { + return !m_jumps.length(); + } + + const JumpVector& jumps() { return m_jumps; } + + private: + JumpVector m_jumps; + }; + + + // Section 3: Misc admin methods + + static CodePtr trampolineAt(CodeRef ref, Label label) + { + return CodePtr(AssemblerType::getRelocatedAddress(ref.m_code.dataLocation(), label.m_label)); + } + + size_t size() + { + return m_assembler.size(); + } + + unsigned char *buffer() + { + return m_assembler.buffer(); + } + + bool oom() + { + return m_assembler.oom(); + } + + void* executableCopy(void* buffer) + { + return m_assembler.executableCopy(buffer); + } + + Label label() + { + return Label(this); + } + + DataLabel32 dataLabel32() + { + return DataLabel32(this); + } + + Label align() + { + m_assembler.align(16); + return Label(this); + } + + ptrdiff_t differenceBetween(Label from, Jump to) + { + return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); + } + + ptrdiff_t differenceBetween(Label from, Call to) + { + return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); + } + + ptrdiff_t differenceBetween(Label from, Label to) + { + return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); + } + + ptrdiff_t differenceBetween(Label from, DataLabelPtr to) + { + return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); + } + + ptrdiff_t differenceBetween(Label from, DataLabel32 to) + { + return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); + } + + ptrdiff_t differenceBetween(DataLabel32 from, Label to) + { + return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); + } + + ptrdiff_t differenceBetween(DataLabelPtr from, Jump to) + { + return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); + } + + ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to) + { + return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); + } + + ptrdiff_t differenceBetween(DataLabelPtr from, Call to) + { + return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); + } + +protected: + AssemblerType m_assembler; + + friend class LinkBuffer; + friend class RepatchBuffer; + + static void linkJump(void* code, Jump jump, CodeLocationLabel target) + { + AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation()); + } + + static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value) + { + AssemblerType::linkPointer(code, label, value); + } + + static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label) + { + return AssemblerType::getRelocatedAddress(code, label); + } + + static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label) + { + return AssemblerType::getRelocatedAddress(code, label); + } + + static unsigned getLinkerCallReturnOffset(Call call) + { + return AssemblerType::getCallReturnOffset(call.m_jmp); + } + + static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination) + { + AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation()); + } + + static bool canRepatchJump(CodeLocationJump jump, CodeLocationLabel destination) + { + return AssemblerType::canRelinkJump(jump.dataLocation(), destination.dataLocation()); + } + + static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination) + { + AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress()); + } + + static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value) + { + AssemblerType::repatchInt32(dataLabel32.dataLocation(), value); + } + + static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value) + { + AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value); + } + + static void repatchLoadPtrToLEA(CodeLocationInstruction instruction) + { + AssemblerType::repatchLoadPtrToLEA(instruction.dataLocation()); + } + + static void repatchLEAToLoadPtr(CodeLocationInstruction instruction) + { + AssemblerType::repatchLEAToLoadPtr(instruction.dataLocation()); + } +}; + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) + +#endif // AbstractMacroAssembler_h diff --git a/js/src/assembler/assembler/AssemblerBuffer.h b/js/src/assembler/assembler/AssemblerBuffer.h new file mode 100644 index 0000000..3698c67 --- /dev/null +++ b/js/src/assembler/assembler/AssemblerBuffer.h @@ -0,0 +1,228 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef AssemblerBuffer_h +#define AssemblerBuffer_h + +#include "assembler/wtf/Platform.h" + +#if ENABLE_ASSEMBLER + +#include +#include "assembler/jit/ExecutableAllocator.h" +#include "assembler/wtf/Assertions.h" +#include "jsstdint.h" + +namespace JSC { + + class AssemblerBuffer { + static const int inlineCapacity = 256; + public: + AssemblerBuffer() + : m_buffer(m_inlineBuffer) + , m_capacity(inlineCapacity) + , m_size(0) + , m_oom(false) + { + } + + ~AssemblerBuffer() + { + if (m_buffer != m_inlineBuffer) + free(m_buffer); + } + + void ensureSpace(int space) + { + if (m_size > m_capacity - space) + grow(); + } + + bool isAligned(int alignment) const + { + return !(m_size & (alignment - 1)); + } + + void putByteUnchecked(int value) + { + ASSERT(!(m_size > m_capacity - 4)); + m_buffer[m_size] = char(value); + m_size++; + } + + void putByte(int value) + { + if (m_size > m_capacity - 4) + grow(); + putByteUnchecked(value); + } + + void putShortUnchecked(int value) + { + ASSERT(!(m_size > m_capacity - 4)); + *reinterpret_cast(&m_buffer[m_size]) = short(value); + m_size += 2; + } + + void putShort(int value) + { + if (m_size > m_capacity - 4) + grow(); + putShortUnchecked(value); + } + + void putIntUnchecked(int value) + { + ASSERT(!(m_size > m_capacity - 4)); + *reinterpret_cast(&m_buffer[m_size]) = value; + m_size += 4; + } + + void putInt64Unchecked(int64_t value) + { + ASSERT(!(m_size > m_capacity - 8)); + *reinterpret_cast(&m_buffer[m_size]) = value; + m_size += 8; + } + + void putInt(int value) + { + if (m_size > m_capacity - 4) + grow(); + putIntUnchecked(value); + } + + void* data() const + { + return m_buffer; + } + + int size() const + { + return m_size; + } + + bool oom() const + { + return m_oom; + } + + /* + * The user must check for a NULL return value, which means + * no code was generated, or there was an OOM. + */ + void* executableCopy(ExecutablePool* allocator) + { + if (m_oom) + return 0; + + if (!m_size) + return 0; + + void* result = allocator->alloc(m_size); + + if (!result) + return 0; + + ExecutableAllocator::makeWritable(result, m_size); + + return memcpy(result, m_buffer, m_size); + } + + unsigned char *buffer() const { + ASSERT(!m_oom); + return reinterpret_cast(m_buffer); + } + + protected: + void append(const char* data, int size) + { + if (m_size > m_capacity - size) + grow(size); + + // If we OOM and size > inlineCapacity, this would crash. + if (m_oom) + return; + memcpy(m_buffer + m_size, data, size); + m_size += size; + } + + /* + * OOM handling: This class can OOM in the grow() method trying to + * allocate a new buffer. In response to an OOM, we need to avoid + * crashing and report the error. We also want to make it so that + * users of this class need to check for OOM only at certain points + * and not after every operation. + * + * Our strategy for handling an OOM is to set m_oom, and then set + * m_size to 0, preserving the current buffer. This way, the user + * can continue assembling into the buffer, deferring OOM checking + * until the user wants to read code out of the buffer. + * + * See also the |executableCopy| and |buffer| methods. + */ + + void grow(int extraCapacity = 0) + { + int newCapacity = m_capacity + m_capacity / 2 + extraCapacity; + char* newBuffer; + + if (m_buffer == m_inlineBuffer) { + newBuffer = static_cast(malloc(newCapacity)); + if (!newBuffer) { + m_size = 0; + m_oom = true; + return; + } + memcpy(newBuffer, m_buffer, m_size); + } else { + newBuffer = static_cast(realloc(m_buffer, newCapacity)); + if (!newBuffer) { + m_size = 0; + m_oom = true; + return; + } + } + + m_buffer = newBuffer; + m_capacity = newCapacity; + } + + char m_inlineBuffer[inlineCapacity]; + char* m_buffer; + int m_capacity; + int m_size; + bool m_oom; + }; + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) + +#endif // AssemblerBuffer_h diff --git a/js/src/assembler/assembler/AssemblerBufferWithConstantPool.h b/js/src/assembler/assembler/AssemblerBufferWithConstantPool.h new file mode 100644 index 0000000..566454c --- /dev/null +++ b/js/src/assembler/assembler/AssemblerBufferWithConstantPool.h @@ -0,0 +1,344 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2009 University of Szeged + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef AssemblerBufferWithConstantPool_h +#define AssemblerBufferWithConstantPool_h + +#include "assembler/wtf/Platform.h" + +#if ENABLE_ASSEMBLER + +#include "AssemblerBuffer.h" +#include "assembler/wtf/SegmentedVector.h" +#include "assembler/wtf/Assertions.h" + +#include "methodjit/Logging.h" + +#define ASSEMBLER_HAS_CONSTANT_POOL 1 + +namespace JSC { + +/* + On a constant pool 4 or 8 bytes data can be stored. The values can be + constants or addresses. The addresses should be 32 or 64 bits. The constants + should be double-precisions float or integer numbers which are hard to be + encoded as few machine instructions. + + TODO: The pool is desinged to handle both 32 and 64 bits values, but + currently only the 4 bytes constants are implemented and tested. + + The AssemblerBuffer can contain multiple constant pools. Each pool is inserted + into the instruction stream - protected by a jump instruction from the + execution flow. + + The flush mechanism is called when no space remain to insert the next instruction + into the pool. Three values are used to determine when the constant pool itself + have to be inserted into the instruction stream (Assembler Buffer): + + - maxPoolSize: size of the constant pool in bytes, this value cannot be + larger than the maximum offset of a PC relative memory load + + - barrierSize: size of jump instruction in bytes which protects the + constant pool from execution + + - maxInstructionSize: maximum length of a machine instruction in bytes + + There are some callbacks which solve the target architecture specific + address handling: + + - TYPE patchConstantPoolLoad(TYPE load, int value): + patch the 'load' instruction with the index of the constant in the + constant pool and return the patched instruction. + + - void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr): + patch the a PC relative load instruction at 'loadAddr' address with the + final relative offset. The offset can be computed with help of + 'constPoolAddr' (the address of the constant pool) and index of the + constant (which is stored previously in the load instruction itself). + + - TYPE placeConstantPoolBarrier(int size): + return with a constant pool barrier instruction which jumps over the + constant pool. + + The 'put*WithConstant*' functions should be used to place a data into the + constant pool. +*/ + +template +class AssemblerBufferWithConstantPool: public AssemblerBuffer { + typedef SegmentedVector LoadOffsets; +public: + enum { + UniqueConst, + ReusableConst, + UnusedEntry + }; + + AssemblerBufferWithConstantPool() + : AssemblerBuffer() + , m_numConsts(0) + , m_maxDistance(maxPoolSize) + , m_lastConstDelta(0) +#ifdef DEBUG + , m_allowFlush(true) +#endif + { + m_pool = static_cast(malloc(maxPoolSize)); + m_mask = static_cast(malloc(maxPoolSize / sizeof(uint32_t))); + } + + ~AssemblerBufferWithConstantPool() + { + free(m_mask); + free(m_pool); + } + + void ensureSpace(int space) + { + flushIfNoSpaceFor(space); + AssemblerBuffer::ensureSpace(space); + } + + void ensureSpace(int insnSpace, int constSpace) + { + flushIfNoSpaceFor(insnSpace, constSpace); + AssemblerBuffer::ensureSpace(insnSpace); + } + + bool isAligned(int alignment) + { + flushIfNoSpaceFor(alignment); + return AssemblerBuffer::isAligned(alignment); + } + + void putByteUnchecked(int value) + { + AssemblerBuffer::putByteUnchecked(value); + correctDeltas(1); + } + + void putByte(int value) + { + flushIfNoSpaceFor(1); + AssemblerBuffer::putByte(value); + correctDeltas(1); + } + + void putShortUnchecked(int value) + { + AssemblerBuffer::putShortUnchecked(value); + correctDeltas(2); + } + + void putShort(int value) + { + flushIfNoSpaceFor(2); + AssemblerBuffer::putShort(value); + correctDeltas(2); + } + + void putIntUnchecked(int value) + { + AssemblerBuffer::putIntUnchecked(value); + correctDeltas(4); + } + + void putInt(int value) + { + flushIfNoSpaceFor(4); + AssemblerBuffer::putInt(value); + correctDeltas(4); + } + + void putInt64Unchecked(int64_t value) + { + AssemblerBuffer::putInt64Unchecked(value); + correctDeltas(8); + } + + int size() + { + flushIfNoSpaceFor(maxInstructionSize, sizeof(uint64_t)); + return AssemblerBuffer::size(); + } + + int uncheckedSize() + { + return AssemblerBuffer::size(); + } + + void* executableCopy(ExecutablePool* allocator) + { + flushConstantPool(false); + return AssemblerBuffer::executableCopy(allocator); + } + + void putIntWithConstantInt(uint32_t insn, uint32_t constant, bool isReusable = false) + { + flushIfNoSpaceFor(4, 4); + + m_loadOffsets.append(AssemblerBuffer::size()); + if (isReusable) + for (int i = 0; i < m_numConsts; ++i) { + if (m_mask[i] == ReusableConst && m_pool[i] == constant) { + AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, i)); + correctDeltas(4); + return; + } + } + + m_pool[m_numConsts] = constant; + m_mask[m_numConsts] = static_cast(isReusable ? ReusableConst : UniqueConst); + + AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, m_numConsts)); + ++m_numConsts; + + correctDeltas(4, 4); + } + + // This flushing mechanism can be called after any unconditional jumps. + void flushWithoutBarrier(bool isForced = false) + { + // Flush if constant pool is more than 60% full to avoid overuse of this function. + if (isForced || (5 * m_numConsts * sizeof(uint32_t)) > (3 * maxPoolSize)) + flushConstantPool(false); + } + + uint32_t* poolAddress() + { + return m_pool; + } + + int sizeOfConstantPool() + { + return m_numConsts; + } + +#ifdef DEBUG + // Guard constant pool flushes to ensure that they don't occur during + // regions where offsets into the code have to be maintained (such as PICs). + void allowPoolFlush(bool allowFlush) + { + m_allowFlush = allowFlush; + } +#endif + +private: + void correctDeltas(int insnSize) + { + m_maxDistance -= insnSize; + m_lastConstDelta -= insnSize; + if (m_lastConstDelta < 0) + m_lastConstDelta = 0; + } + + void correctDeltas(int insnSize, int constSize) + { + correctDeltas(insnSize); + + m_maxDistance -= m_lastConstDelta; + m_lastConstDelta = constSize; + } + + void flushConstantPool(bool useBarrier = true) + { + js::JaegerSpew(js::JSpew_Insns, " -- FLUSHING CONSTANT POOL WITH %d CONSTANTS --\n", + m_numConsts); + ASSERT(m_allowFlush); + if (m_numConsts == 0) + return; + int alignPool = (AssemblerBuffer::size() + (useBarrier ? barrierSize : 0)) & (sizeof(uint64_t) - 1); + + if (alignPool) + alignPool = sizeof(uint64_t) - alignPool; + + // Callback to protect the constant pool from execution + if (useBarrier) + AssemblerBuffer::putInt(AssemblerType::placeConstantPoolBarrier(m_numConsts * sizeof(uint32_t) + alignPool)); + + if (alignPool) { + if (alignPool & 1) + AssemblerBuffer::putByte(AssemblerType::padForAlign8); + if (alignPool & 2) + AssemblerBuffer::putShort(AssemblerType::padForAlign16); + if (alignPool & 4) + AssemblerBuffer::putInt(AssemblerType::padForAlign32); + } + + int constPoolOffset = AssemblerBuffer::size(); + append(reinterpret_cast(m_pool), m_numConsts * sizeof(uint32_t)); + + // Patch each PC relative load + for (LoadOffsets::Iterator iter = m_loadOffsets.begin(); iter != m_loadOffsets.end(); ++iter) { + void* loadAddr = reinterpret_cast(m_buffer + *iter); + AssemblerType::patchConstantPoolLoad(loadAddr, reinterpret_cast(m_buffer + constPoolOffset)); + } + + m_loadOffsets.clear(); + m_numConsts = 0; + m_maxDistance = maxPoolSize; + } + + void flushIfNoSpaceFor(int nextInsnSize) + { + if (m_numConsts == 0) + return; + int lastConstDelta = m_lastConstDelta > nextInsnSize ? m_lastConstDelta - nextInsnSize : 0; + if ((m_maxDistance < nextInsnSize + lastConstDelta + barrierSize + (int)sizeof(uint32_t))) + flushConstantPool(); + } + + void flushIfNoSpaceFor(int nextInsnSize, int nextConstSize) + { + if (m_numConsts == 0) + return; + if ((m_maxDistance < nextInsnSize + m_lastConstDelta + nextConstSize + barrierSize + (int)sizeof(uint32_t)) || + (m_numConsts * sizeof(uint32_t) + nextConstSize >= maxPoolSize)) + flushConstantPool(); + } + + uint32_t* m_pool; + char* m_mask; + LoadOffsets m_loadOffsets; + + int m_numConsts; + int m_maxDistance; + int m_lastConstDelta; + +#ifdef DEBUG + bool m_allowFlush; +#endif +}; + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) + +#endif // AssemblerBufferWithConstantPool_h diff --git a/js/src/assembler/assembler/CodeLocation.h b/js/src/assembler/assembler/CodeLocation.h new file mode 100644 index 0000000..4901576 --- /dev/null +++ b/js/src/assembler/assembler/CodeLocation.h @@ -0,0 +1,189 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef CodeLocation_h +#define CodeLocation_h + +#include "assembler/wtf/Platform.h" +#include "assembler/assembler/MacroAssemblerCodeRef.h" + +#if ENABLE_ASSEMBLER + +namespace JSC { + +class CodeLocationInstruction; +class CodeLocationLabel; +class CodeLocationJump; +class CodeLocationCall; +class CodeLocationNearCall; +class CodeLocationDataLabel32; +class CodeLocationDataLabelPtr; + +// The CodeLocation* types are all pretty much do-nothing wrappers around +// CodePtr (or MacroAssemblerCodePtr, to give it its full name). These +// classes only exist to provide type-safety when linking and patching code. +// +// The one new piece of functionallity introduced by these classes is the +// ability to create (or put another way, to re-discover) another CodeLocation +// at an offset from one you already know. When patching code to optimize it +// we often want to patch a number of instructions that are short, fixed +// offsets apart. To reduce memory overhead we will only retain a pointer to +// one of the instructions, and we will use the *AtOffset methods provided by +// CodeLocationCommon to find the other points in the code to modify. +class CodeLocationCommon : public MacroAssemblerCodePtr { +public: + CodeLocationInstruction instructionAtOffset(int offset); + CodeLocationLabel labelAtOffset(int offset); + CodeLocationJump jumpAtOffset(int offset); + CodeLocationCall callAtOffset(int offset); + CodeLocationNearCall nearCallAtOffset(int offset); + CodeLocationDataLabelPtr dataLabelPtrAtOffset(int offset); + CodeLocationDataLabel32 dataLabel32AtOffset(int offset); + +protected: + CodeLocationCommon() + { + } + + CodeLocationCommon(MacroAssemblerCodePtr location) + : MacroAssemblerCodePtr(location) + { + } +}; + +class CodeLocationInstruction : public CodeLocationCommon { +public: + CodeLocationInstruction() {} + explicit CodeLocationInstruction(MacroAssemblerCodePtr location) + : CodeLocationCommon(location) {} + explicit CodeLocationInstruction(void* location) + : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} +}; + +class CodeLocationLabel : public CodeLocationCommon { +public: + CodeLocationLabel() {} + explicit CodeLocationLabel(MacroAssemblerCodePtr location) + : CodeLocationCommon(location) {} + explicit CodeLocationLabel(void* location) + : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} +}; + +class CodeLocationJump : public CodeLocationCommon { +public: + CodeLocationJump() {} + explicit CodeLocationJump(MacroAssemblerCodePtr location) + : CodeLocationCommon(location) {} + explicit CodeLocationJump(void* location) + : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} +}; + +class CodeLocationCall : public CodeLocationCommon { +public: + CodeLocationCall() {} + explicit CodeLocationCall(MacroAssemblerCodePtr location) + : CodeLocationCommon(location) {} + explicit CodeLocationCall(void* location) + : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} +}; + +class CodeLocationNearCall : public CodeLocationCommon { +public: + CodeLocationNearCall() {} + explicit CodeLocationNearCall(MacroAssemblerCodePtr location) + : CodeLocationCommon(location) {} + explicit CodeLocationNearCall(void* location) + : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} +}; + +class CodeLocationDataLabel32 : public CodeLocationCommon { +public: + CodeLocationDataLabel32() {} + explicit CodeLocationDataLabel32(MacroAssemblerCodePtr location) + : CodeLocationCommon(location) {} + explicit CodeLocationDataLabel32(void* location) + : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} +}; + +class CodeLocationDataLabelPtr : public CodeLocationCommon { +public: + CodeLocationDataLabelPtr() {} + explicit CodeLocationDataLabelPtr(MacroAssemblerCodePtr location) + : CodeLocationCommon(location) {} + explicit CodeLocationDataLabelPtr(void* location) + : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} +}; + +inline CodeLocationInstruction CodeLocationCommon::instructionAtOffset(int offset) +{ + ASSERT_VALID_CODE_OFFSET(offset); + return CodeLocationInstruction(reinterpret_cast(dataLocation()) + offset); +} + +inline CodeLocationLabel CodeLocationCommon::labelAtOffset(int offset) +{ + ASSERT_VALID_CODE_OFFSET(offset); + return CodeLocationLabel(reinterpret_cast(dataLocation()) + offset); +} + +inline CodeLocationJump CodeLocationCommon::jumpAtOffset(int offset) +{ + ASSERT_VALID_CODE_OFFSET(offset); + return CodeLocationJump(reinterpret_cast(dataLocation()) + offset); +} + +inline CodeLocationCall CodeLocationCommon::callAtOffset(int offset) +{ + ASSERT_VALID_CODE_OFFSET(offset); + return CodeLocationCall(reinterpret_cast(dataLocation()) + offset); +} + +inline CodeLocationNearCall CodeLocationCommon::nearCallAtOffset(int offset) +{ + ASSERT_VALID_CODE_OFFSET(offset); + return CodeLocationNearCall(reinterpret_cast(dataLocation()) + offset); +} + +inline CodeLocationDataLabelPtr CodeLocationCommon::dataLabelPtrAtOffset(int offset) +{ + ASSERT_VALID_CODE_OFFSET(offset); + return CodeLocationDataLabelPtr(reinterpret_cast(dataLocation()) + offset); +} + +inline CodeLocationDataLabel32 CodeLocationCommon::dataLabel32AtOffset(int offset) +{ + ASSERT_VALID_CODE_OFFSET(offset); + return CodeLocationDataLabel32(reinterpret_cast(dataLocation()) + offset); +} + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) + +#endif // CodeLocation_h diff --git a/js/src/assembler/assembler/LinkBuffer.h b/js/src/assembler/assembler/LinkBuffer.h new file mode 100644 index 0000000..5bd5d6e --- /dev/null +++ b/js/src/assembler/assembler/LinkBuffer.h @@ -0,0 +1,228 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef LinkBuffer_h +#define LinkBuffer_h + +#include "assembler/wtf/Platform.h" + +#if ENABLE_ASSEMBLER + +#include + +namespace JSC { + +// LinkBuffer: +// +// This class assists in linking code generated by the macro assembler, once code generation +// has been completed, and the code has been copied to is final location in memory. At this +// time pointers to labels within the code may be resolved, and relative offsets to external +// addresses may be fixed. +// +// Specifically: +// * Jump objects may be linked to external targets, +// * The address of Jump objects may taken, such that it can later be relinked. +// * The return address of a Call may be acquired. +// * The address of a Label pointing into the code may be resolved. +// * The value referenced by a DataLabel may be set. +// +class LinkBuffer { + typedef MacroAssemblerCodeRef CodeRef; + typedef MacroAssembler::Label Label; + typedef MacroAssembler::Jump Jump; + typedef MacroAssembler::JumpList JumpList; + typedef MacroAssembler::Call Call; + typedef MacroAssembler::DataLabel32 DataLabel32; + typedef MacroAssembler::DataLabelPtr DataLabelPtr; + +public: + // Note: Initialization sequence is significant, since executablePool is a PassRefPtr. + // First, executablePool is copied into m_executablePool, then the initialization of + // m_code uses m_executablePool, *not* executablePool, since this is no longer valid. + LinkBuffer(MacroAssembler* masm, ExecutablePool* executablePool) + : m_executablePool(executablePool) + , m_code(executableCopy(*masm, executablePool)) + , m_size(masm->m_assembler.size()) +#ifndef NDEBUG + , m_completed(false) +#endif + { + } + + LinkBuffer() + : m_executablePool(NULL) + , m_code(NULL) + , m_size(0) +#ifndef NDEBUG + , m_completed(false) +#endif + { + } + + LinkBuffer(uint8* ncode, size_t size) + : m_executablePool(NULL) + , m_code(ncode) + , m_size(size) +#ifndef NDEBUG + , m_completed(false) +#endif + { + } + + ~LinkBuffer() + { + ASSERT(!m_executablePool || m_completed); + } + + // These methods are used to link or set values at code generation time. + + void link(Call call, FunctionPtr function) + { + ASSERT(call.isFlagSet(Call::Linkable)); + MacroAssembler::linkCall(code(), call, function); + } + + void link(Jump jump, CodeLocationLabel label) + { + MacroAssembler::linkJump(code(), jump, label); + } + + void link(JumpList list, CodeLocationLabel label) + { + for (unsigned i = 0; i < list.m_jumps.length(); ++i) + MacroAssembler::linkJump(code(), list.m_jumps[i], label); + } + + void patch(DataLabelPtr label, void* value) + { + MacroAssembler::linkPointer(code(), label.m_label, value); + } + + void patch(DataLabelPtr label, CodeLocationLabel value) + { + MacroAssembler::linkPointer(code(), label.m_label, value.executableAddress()); + } + + // These methods are used to obtain handles to allow the code to be relinked / repatched later. + + CodeLocationCall locationOf(Call call) + { + ASSERT(call.isFlagSet(Call::Linkable)); + ASSERT(!call.isFlagSet(Call::Near)); + return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp)); + } + + CodeLocationJump locationOf(Jump j) + { + return CodeLocationJump(MacroAssembler::getLinkerAddress(code(), j.m_jmp)); + } + + CodeLocationNearCall locationOfNearCall(Call call) + { + ASSERT(call.isFlagSet(Call::Linkable)); + ASSERT(call.isFlagSet(Call::Near)); + return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp)); + } + + CodeLocationLabel locationOf(Label label) + { + return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), label.m_label)); + } + + CodeLocationDataLabelPtr locationOf(DataLabelPtr label) + { + return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), label.m_label)); + } + + CodeLocationDataLabel32 locationOf(DataLabel32 label) + { + return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), label.m_label)); + } + + // This method obtains the return address of the call, given as an offset from + // the start of the code. + unsigned returnAddressOffset(Call call) + { + return MacroAssembler::getLinkerCallReturnOffset(call); + } + + // Upon completion of all patching either 'finalizeCode()' or 'finalizeCodeAddendum()' should be called + // once to complete generation of the code. 'finalizeCode()' is suited to situations + // where the executable pool must also be retained, the lighter-weight 'finalizeCodeAddendum()' is + // suited to adding to an existing allocation. + CodeRef finalizeCode() + { + performFinalization(); + + return CodeRef(m_code, m_executablePool, m_size); + } + CodeLocationLabel finalizeCodeAddendum() + { + performFinalization(); + + return CodeLocationLabel(code()); + } + +protected: + // Keep this private! - the underlying code should only be obtained externally via + // finalizeCode() or finalizeCodeAddendum(). + void* code() + { + return m_code; + } + + void *executableCopy(MacroAssembler &masm, ExecutablePool *pool) + { + return masm.m_assembler.executableCopy(pool); + } + + void performFinalization() + { +#ifndef NDEBUG + ASSERT(!m_completed); + m_completed = true; +#endif + + ExecutableAllocator::makeExecutable(code(), m_size); + ExecutableAllocator::cacheFlush(code(), m_size); + } + + ExecutablePool* m_executablePool; + void* m_code; + size_t m_size; +#ifndef NDEBUG + bool m_completed; +#endif +}; + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) + +#endif // LinkBuffer_h diff --git a/js/src/assembler/assembler/MacroAssembler.h b/js/src/assembler/assembler/MacroAssembler.h new file mode 100644 index 0000000..5f24981 --- /dev/null +++ b/js/src/assembler/assembler/MacroAssembler.h @@ -0,0 +1,402 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MacroAssembler_h +#define MacroAssembler_h + +#include "assembler/wtf/Platform.h" + +#if ENABLE_ASSEMBLER + +#if WTF_CPU_ARM_THUMB2 +#include "MacroAssemblerARMv7.h" +namespace JSC { typedef MacroAssemblerARMv7 MacroAssemblerBase; } + +#elif WTF_CPU_ARM_TRADITIONAL +#include "MacroAssemblerARM.h" +namespace JSC { typedef MacroAssemblerARM MacroAssemblerBase; } + +#elif WTF_CPU_MIPS +#include "MacroAssemblerMIPS.h" +namespace JSC { typedef MacroAssemblerMIPS MacroAssemblerBase; } + +#elif WTF_CPU_X86 +#include "MacroAssemblerX86.h" +namespace JSC { typedef MacroAssemblerX86 MacroAssemblerBase; } + +#elif WTF_CPU_X86_64 +#include "MacroAssemblerX86_64.h" +namespace JSC { typedef MacroAssemblerX86_64 MacroAssemblerBase; } + +#else +#error "The MacroAssembler is not supported on this platform." +#endif + + +namespace JSC { + +class MacroAssembler : public MacroAssemblerBase { +public: + + using MacroAssemblerBase::pop; + using MacroAssemblerBase::jump; + using MacroAssemblerBase::branch32; + using MacroAssemblerBase::branch16; +#if WTF_CPU_X86_64 + using MacroAssemblerBase::branchPtr; + using MacroAssemblerBase::branchTestPtr; +#endif + + + // Platform agnostic onvenience functions, + // described in terms of other macro assembly methods. + void pop() + { + addPtr(Imm32(sizeof(void*)), stackPointerRegister); + } + + void peek(RegisterID dest, int index = 0) + { + loadPtr(Address(stackPointerRegister, (index * sizeof(void*))), dest); + } + + void poke(RegisterID src, int index = 0) + { + storePtr(src, Address(stackPointerRegister, (index * sizeof(void*)))); + } + + void poke(Imm32 value, int index = 0) + { + store32(value, Address(stackPointerRegister, (index * sizeof(void*)))); + } + + void poke(ImmPtr imm, int index = 0) + { + storePtr(imm, Address(stackPointerRegister, (index * sizeof(void*)))); + } + + + // Backwards banches, these are currently all implemented using existing forwards branch mechanisms. + void branchPtr(Condition cond, RegisterID op1, ImmPtr imm, Label target) + { + branchPtr(cond, op1, imm).linkTo(target, this); + } + + void branch32(Condition cond, RegisterID op1, RegisterID op2, Label target) + { + branch32(cond, op1, op2).linkTo(target, this); + } + + void branch32(Condition cond, RegisterID op1, Imm32 imm, Label target) + { + branch32(cond, op1, imm).linkTo(target, this); + } + + void branch32(Condition cond, RegisterID left, Address right, Label target) + { + branch32(cond, left, right).linkTo(target, this); + } + + void branch16(Condition cond, BaseIndex left, RegisterID right, Label target) + { + branch16(cond, left, right).linkTo(target, this); + } + + void branchTestPtr(Condition cond, RegisterID reg, Label target) + { + branchTestPtr(cond, reg).linkTo(target, this); + } + + void jump(Label target) + { + jump().linkTo(target, this); + } + + + // Ptr methods + // On 32-bit platforms (i.e. x86), these methods directly map onto their 32-bit equivalents. + // FIXME: should this use a test for 32-bitness instead of this specific exception? +#if !WTF_CPU_X86_64 + void addPtr(RegisterID src, RegisterID dest) + { + add32(src, dest); + } + + void addPtr(Imm32 imm32, Address address) + { + add32(imm32, address); + } + + void addPtr(Imm32 imm, RegisterID srcDest) + { + add32(imm, srcDest); + } + + void addPtr(ImmPtr imm, RegisterID dest) + { + add32(Imm32(imm), dest); + } + + void addPtr(Imm32 imm, RegisterID src, RegisterID dest) + { + add32(imm, src, dest); + } + + void andPtr(RegisterID src, RegisterID dest) + { + and32(src, dest); + } + + void andPtr(Address address, RegisterID srcDest) + { + and32(address, srcDest); + } + + void andPtr(Imm32 imm, RegisterID srcDest) + { + and32(imm, srcDest); + } + + void andPtr(ImmPtr ptr, RegisterID srcDest) + { + and32(Imm32(ptr), srcDest); + } + + void notPtr(RegisterID srcDest) + { + not32(srcDest); + } + + void orPtr(RegisterID src, RegisterID dest) + { + or32(src, dest); + } + + void orPtr(ImmPtr imm, RegisterID dest) + { + or32(Imm32(imm), dest); + } + + void orPtr(Imm32 imm, RegisterID dest) + { + or32(imm, dest); + } + + void orPtr(Address address, RegisterID srcDest) + { + or32(address, srcDest); + } + + void subPtr(RegisterID src, RegisterID dest) + { + sub32(src, dest); + } + + void subPtr(Imm32 imm, RegisterID dest) + { + sub32(imm, dest); + } + + void subPtr(ImmPtr imm, RegisterID dest) + { + sub32(Imm32(imm), dest); + } + + void subPtr(ImmPtr imm, Address address) + { + sub32(Imm32(imm), address); + } + + void xorPtr(RegisterID src, RegisterID dest) + { + xor32(src, dest); + } + + void xorPtr(Imm32 imm, RegisterID srcDest) + { + xor32(imm, srcDest); + } + + + void loadPtr(ImplicitAddress address, RegisterID dest) + { + load32(address, dest); + } + + void loadPtr(BaseIndex address, RegisterID dest) + { + load32(address, dest); + } + + void loadPtr(void* address, RegisterID dest) + { + load32(address, dest); + } + + DataLabel32 loadPtrWithAddressOffsetPatch(Address address, RegisterID dest) + { + return load32WithAddressOffsetPatch(address, dest); + } + + void setPtr(Condition cond, RegisterID left, Imm32 right, RegisterID dest) + { + set32(cond, left, right, dest); + } + + void storePtr(RegisterID src, ImplicitAddress address) + { + store32(src, address); + } + + void storePtr(RegisterID src, BaseIndex address) + { + store32(src, address); + } + + void storePtr(RegisterID src, void* address) + { + store32(src, address); + } + + void storePtr(ImmPtr imm, ImplicitAddress address) + { + store32(Imm32(imm), address); + } + + void storePtr(ImmPtr imm, BaseIndex address) + { + store32(Imm32(imm), address); + } + + void storePtr(ImmPtr imm, void* address) + { + store32(Imm32(imm), address); + } + + DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address) + { + return store32WithAddressOffsetPatch(src, address); + } + + + Jump branchPtr(Condition cond, RegisterID left, RegisterID right) + { + return branch32(cond, left, right); + } + + Jump branchPtr(Condition cond, RegisterID left, ImmPtr right) + { + return branch32(cond, left, Imm32(right)); + } + + Jump branchPtr(Condition cond, RegisterID left, Imm32 right) + { + return branch32(cond, left, right); + } + + Jump branchPtr(Condition cond, RegisterID left, Address right) + { + return branch32(cond, left, right); + } + + Jump branchPtr(Condition cond, Address left, RegisterID right) + { + return branch32(cond, left, right); + } + + Jump branchPtr(Condition cond, AbsoluteAddress left, RegisterID right) + { + return branch32(cond, left, right); + } + + Jump branchPtr(Condition cond, Address left, ImmPtr right) + { + return branch32(cond, left, Imm32(right)); + } + + Jump branchPtr(Condition cond, AbsoluteAddress left, ImmPtr right) + { + return branch32(cond, left, Imm32(right)); + } + + Jump branchTestPtr(Condition cond, RegisterID reg, RegisterID mask) + { + return branchTest32(cond, reg, mask); + } + + Jump branchTestPtr(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) + { + return branchTest32(cond, reg, mask); + } + + Jump branchTestPtr(Condition cond, Address address, Imm32 mask = Imm32(-1)) + { + return branchTest32(cond, address, mask); + } + + Jump branchTestPtr(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) + { + return branchTest32(cond, address, mask); + } + + + Jump branchAddPtr(Condition cond, RegisterID src, RegisterID dest) + { + return branchAdd32(cond, src, dest); + } + + Jump branchSubPtr(Condition cond, Imm32 imm, RegisterID dest) + { + return branchSub32(cond, imm, dest); + } + + using MacroAssemblerBase::branchTest8; + Jump branchTest8(Condition cond, ExtendedAddress address, Imm32 mask = Imm32(-1)) + { + return MacroAssemblerBase::branchTest8(cond, Address(address.base, address.offset), mask); + } + + void rshiftPtr(Imm32 imm, RegisterID dest) + { + rshift32(imm, dest); + } + + void lshiftPtr(Imm32 imm, RegisterID dest) + { + lshift32(imm, dest); + } +#endif + +}; + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) + +#endif // MacroAssembler_h diff --git a/js/src/assembler/assembler/MacroAssemblerARM.cpp b/js/src/assembler/assembler/MacroAssemblerARM.cpp new file mode 100644 index 0000000..14b4166 --- /dev/null +++ b/js/src/assembler/assembler/MacroAssemblerARM.cpp @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2009 University of Szeged + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#include "assembler/wtf/Platform.h" + +#if ENABLE_ASSEMBLER && WTF_CPU_ARM_TRADITIONAL + +#include "MacroAssemblerARM.h" + +#if WTF_PLATFORM_LINUX || WTF_PLATFORM_ANDROID +#include +#include +#include +#include +#include + +// lame check for kernel version +// see bug 586550 +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) +#include +#else +#include +#endif + +#endif + +namespace JSC { + +static bool isVFPPresent() +{ +#if WTF_PLATFORM_LINUX + int fd = open("/proc/self/auxv", O_RDONLY); + if (fd > 0) { + Elf32_auxv_t aux; + while (read(fd, &aux, sizeof(Elf32_auxv_t))) { + if (aux.a_type == AT_HWCAP) { + close(fd); + return aux.a_un.a_val & HWCAP_VFP; + } + } + close(fd); + } +#endif + + return false; +} + +const bool MacroAssemblerARM::s_isVFPPresent = isVFPPresent(); + +#if WTF_CPU_ARMV5_OR_LOWER +/* On ARMv5 and below, natural alignment is required. */ +void MacroAssemblerARM::load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) +{ + ARMWord op2; + + ASSERT(address.scale >= 0 && address.scale <= 3); + op2 = m_assembler.lsl(address.index, static_cast(address.scale)); + + if (address.offset >= 0 && address.offset + 0x2 <= 0xff) { + m_assembler.add_r(ARMRegisters::S0, address.base, op2); + m_assembler.ldrh_u(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset)); + m_assembler.ldrh_u(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset + 0x2)); + } else if (address.offset < 0 && address.offset >= -0xff) { + m_assembler.add_r(ARMRegisters::S0, address.base, op2); + m_assembler.ldrh_d(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset)); + m_assembler.ldrh_d(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset - 0x2)); + } else { + m_assembler.ldr_un_imm(ARMRegisters::S0, address.offset); + m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, op2); + m_assembler.ldrh_r(dest, address.base, ARMRegisters::S0); + m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::OP2_IMM | 0x2); + m_assembler.ldrh_r(ARMRegisters::S0, address.base, ARMRegisters::S0); + } + m_assembler.orr_r(dest, dest, m_assembler.lsl(ARMRegisters::S0, 16)); +} +#endif + +} + +#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) diff --git a/js/src/assembler/assembler/MacroAssemblerARM.h b/js/src/assembler/assembler/MacroAssemblerARM.h new file mode 100644 index 0000000..7413411 --- /dev/null +++ b/js/src/assembler/assembler/MacroAssemblerARM.h @@ -0,0 +1,1276 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2008 Apple Inc. + * Copyright (C) 2009, 2010 University of Szeged + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MacroAssemblerARM_h +#define MacroAssemblerARM_h + +#include "assembler/wtf/Platform.h" + +#if ENABLE_ASSEMBLER && WTF_CPU_ARM_TRADITIONAL + +#include "ARMAssembler.h" +#include "AbstractMacroAssembler.h" + +namespace JSC { + +class MacroAssemblerARM : public AbstractMacroAssembler { + static const int DoubleConditionMask = 0x0f; + static const int DoubleConditionBitSpecial = 0x10; + COMPILE_ASSERT(!(DoubleConditionBitSpecial & DoubleConditionMask), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes); +public: + enum Condition { + Equal = ARMAssembler::EQ, + NotEqual = ARMAssembler::NE, + Above = ARMAssembler::HI, + AboveOrEqual = ARMAssembler::CS, + Below = ARMAssembler::CC, + BelowOrEqual = ARMAssembler::LS, + GreaterThan = ARMAssembler::GT, + GreaterThanOrEqual = ARMAssembler::GE, + LessThan = ARMAssembler::LT, + LessThanOrEqual = ARMAssembler::LE, + Overflow = ARMAssembler::VS, + Signed = ARMAssembler::MI, + Zero = ARMAssembler::EQ, + NonZero = ARMAssembler::NE + }; + + enum DoubleCondition { + // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. + DoubleEqual = ARMAssembler::EQ, + DoubleNotEqual = ARMAssembler::NE | DoubleConditionBitSpecial, + DoubleGreaterThan = ARMAssembler::GT, + DoubleGreaterThanOrEqual = ARMAssembler::GE, + DoubleLessThan = ARMAssembler::CC, + DoubleLessThanOrEqual = ARMAssembler::LS, + // If either operand is NaN, these conditions always evaluate to true. + DoubleEqualOrUnordered = ARMAssembler::EQ | DoubleConditionBitSpecial, + DoubleNotEqualOrUnordered = ARMAssembler::NE, + DoubleGreaterThanOrUnordered = ARMAssembler::HI, + DoubleGreaterThanOrEqualOrUnordered = ARMAssembler::CS, + DoubleLessThanOrUnordered = ARMAssembler::LT, + DoubleLessThanOrEqualOrUnordered = ARMAssembler::LE + }; + + static const RegisterID stackPointerRegister = ARMRegisters::sp; + static const RegisterID linkRegister = ARMRegisters::lr; + + static const Scale ScalePtr = TimesFour; + static const unsigned int TotalRegisters = 16; + + void add32(RegisterID src, RegisterID dest) + { + m_assembler.adds_r(dest, dest, src); + } + + void add32(Imm32 imm, Address address) + { + load32(address, ARMRegisters::S1); + add32(imm, ARMRegisters::S1); + store32(ARMRegisters::S1, address); + } + + void add32(Imm32 imm, RegisterID dest) + { + m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + } + + void add32(Address src, RegisterID dest) + { + load32(src, ARMRegisters::S1); + add32(ARMRegisters::S1, dest); + } + + void and32(Address src, RegisterID dest) + { + load32(src, ARMRegisters::S1); + and32(ARMRegisters::S1, dest); + } + + void and32(RegisterID src, RegisterID dest) + { + m_assembler.ands_r(dest, dest, src); + } + + void and32(Imm32 imm, RegisterID dest) + { + ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true); + if (w & ARMAssembler::OP2_INV_IMM) + m_assembler.bics_r(dest, dest, w & ~ARMAssembler::OP2_INV_IMM); + else + m_assembler.ands_r(dest, dest, w); + } + + void lshift32(RegisterID shift_amount, RegisterID dest) + { + ARMWord w = ARMAssembler::getOp2(0x1f); + ASSERT(w != ARMAssembler::INVALID_IMM); + m_assembler.and_r(ARMRegisters::S0, shift_amount, w); + + m_assembler.movs_r(dest, m_assembler.lsl_r(dest, ARMRegisters::S0)); + } + + void lshift32(Imm32 imm, RegisterID dest) + { + m_assembler.movs_r(dest, m_assembler.lsl(dest, imm.m_value & 0x1f)); + } + + void mul32(RegisterID src, RegisterID dest) + { + if (src == dest) { + move(src, ARMRegisters::S0); + src = ARMRegisters::S0; + } + m_assembler.muls_r(dest, dest, src); + } + + void mul32(Imm32 imm, RegisterID src, RegisterID dest) + { + move(imm, ARMRegisters::S0); + m_assembler.muls_r(dest, src, ARMRegisters::S0); + } + + void neg32(RegisterID srcDest) + { + m_assembler.rsbs_r(srcDest, srcDest, ARMAssembler::getOp2(0)); + } + + void not32(RegisterID dest) + { + m_assembler.mvns_r(dest, dest); + } + + void or32(RegisterID src, RegisterID dest) + { + m_assembler.orrs_r(dest, dest, src); + } + + void or32(Imm32 imm, RegisterID dest) + { + m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + } + + void rshift32(RegisterID shift_amount, RegisterID dest) + { + ARMWord w = ARMAssembler::getOp2(0x1f); + ASSERT(w != ARMAssembler::INVALID_IMM); + m_assembler.and_r(ARMRegisters::S0, shift_amount, w); + + m_assembler.movs_r(dest, m_assembler.asr_r(dest, ARMRegisters::S0)); + } + + void rshift32(Imm32 imm, RegisterID dest) + { + m_assembler.movs_r(dest, m_assembler.asr(dest, imm.m_value & 0x1f)); + } + + void urshift32(RegisterID shift_amount, RegisterID dest) + { + ARMWord w = ARMAssembler::getOp2(0x1f); + ASSERT(w != ARMAssembler::INVALID_IMM); + m_assembler.and_r(ARMRegisters::S0, shift_amount, w); + + m_assembler.movs_r(dest, m_assembler.lsr_r(dest, ARMRegisters::S0)); + } + + void urshift32(Imm32 imm, RegisterID dest) + { + m_assembler.movs_r(dest, m_assembler.lsr(dest, imm.m_value & 0x1f)); + } + + void sub32(RegisterID src, RegisterID dest) + { + m_assembler.subs_r(dest, dest, src); + } + + void sub32(Imm32 imm, RegisterID dest) + { + m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + } + + void sub32(Imm32 imm, Address address) + { + load32(address, ARMRegisters::S1); + sub32(imm, ARMRegisters::S1); + store32(ARMRegisters::S1, address); + } + + void sub32(Address src, RegisterID dest) + { + load32(src, ARMRegisters::S1); + sub32(ARMRegisters::S1, dest); + } + + void or32(Address address, RegisterID dest) + { + load32(address, ARMRegisters::S1); + or32(ARMRegisters::S1, dest); + } + + void xor32(RegisterID src, RegisterID dest) + { + m_assembler.eors_r(dest, dest, src); + } + + void xor32(Imm32 imm, RegisterID dest) + { + m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + } + + void xor32(Address src, RegisterID dest) + { + load32(src, ARMRegisters::S1); + m_assembler.eors_r(dest, dest, ARMRegisters::S1); + } + + void load8(ImplicitAddress address, RegisterID dest) + { + m_assembler.dataTransfer8(true, dest, address.base, address.offset); + } + + void load32(ImplicitAddress address, RegisterID dest) + { + m_assembler.dataTransfer32(true, dest, address.base, address.offset); + } + + void load32(BaseIndex address, RegisterID dest) + { + m_assembler.baseIndexTransfer32(true, dest, address.base, address.index, static_cast(address.scale), address.offset); + } + +#if WTF_CPU_ARMV5_OR_LOWER + void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest); +#else + void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) + { + load32(address, dest); + } +#endif + + DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) + { + ASSERT(address.base != ARMRegisters::S0); + DataLabel32 dataLabel(this); + m_assembler.ldr_un_imm(ARMRegisters::S0, 0); + m_assembler.dtr_ur(true, dest, address.base, ARMRegisters::S0); + return dataLabel; + } + + DataLabel32 load64WithAddressOffsetPatch(Address address, RegisterID hi, RegisterID lo) + { + ASSERT(address.base != ARMRegisters::S0); + ASSERT(lo != ARMRegisters::S0); + DataLabel32 dataLabel(this); + m_assembler.ldr_un_imm(ARMRegisters::S0, 0); + m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base); + m_assembler.dtr_u(true, lo, ARMRegisters::S0, 0); + m_assembler.dtr_u(true, hi, ARMRegisters::S0, 4); + return dataLabel; + } + + Label loadPtrWithPatchToLEA(Address address, RegisterID dest) + { + Label label(this); + load32(address, dest); + return label; + } + + void load16(BaseIndex address, RegisterID dest) + { + m_assembler.add_r(ARMRegisters::S1, address.base, m_assembler.lsl(address.index, address.scale)); + load16(Address(ARMRegisters::S1, address.offset), dest); + } + + void load16(ImplicitAddress address, RegisterID dest) + { + if (address.offset >= 0) + m_assembler.ldrh_u(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(address.offset, ARMRegisters::S0)); + else + m_assembler.ldrh_d(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(-address.offset, ARMRegisters::S0)); + } + + DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) + { + ASSERT(address.base != ARMRegisters::S0); + DataLabel32 dataLabel(this); + m_assembler.ldr_un_imm(ARMRegisters::S0, 0); + m_assembler.dtr_ur(false, src, address.base, ARMRegisters::S0); + return dataLabel; + } + + DataLabel32 store64WithAddressOffsetPatch(RegisterID hi, RegisterID lo, Address address) + { + ASSERT(hi != ARMRegisters::S0); + ASSERT(lo != ARMRegisters::S0); + ASSERT(address.base != ARMRegisters::S0); + DataLabel32 dataLabel(this); + m_assembler.ldr_un_imm(ARMRegisters::S0, address.offset); + m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base); + m_assembler.dtr_u(false, lo, ARMRegisters::S0, 0); + m_assembler.dtr_u(false, hi, ARMRegisters::S0, 4); + return dataLabel; + } + + DataLabel32 store64WithAddressOffsetPatch(Imm32 hi, RegisterID lo, Address address) + { + ASSERT(lo != ARMRegisters::S0); + ASSERT(lo != ARMRegisters::S1); + ASSERT(lo != address.base); + ASSERT(address.base != ARMRegisters::S0); + ASSERT(address.base != ARMRegisters::S1); + DataLabel32 dataLabel(this); + m_assembler.ldr_un_imm(ARMRegisters::S0, address.offset); + m_assembler.moveImm(hi.m_value, ARMRegisters::S1); + m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base); + m_assembler.dtr_u(false, lo, ARMRegisters::S0, 0); + m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 4); + return dataLabel; + } + + DataLabel32 store64WithAddressOffsetPatch(Imm32 hi, Imm32 lo, Address address) + { + ASSERT(address.base != ARMRegisters::S0); + ASSERT(address.base != ARMRegisters::S1); + DataLabel32 dataLabel(this); + m_assembler.ldr_un_imm(ARMRegisters::S0, address.offset); + m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, address.base); + m_assembler.moveImm(lo.m_value, ARMRegisters::S1); + m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); + /* TODO: improve this by getting another scratch register. */ + m_assembler.moveImm(hi.m_value, ARMRegisters::S1); + m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 4); + return dataLabel; + } + + void store32(RegisterID src, ImplicitAddress address) + { + m_assembler.dataTransfer32(false, src, address.base, address.offset); + } + + void store32(RegisterID src, BaseIndex address) + { + m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast(address.scale), address.offset); + } + + void store32(Imm32 imm, BaseIndex address) + { + if (imm.m_isPointer) + m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); + else + move(imm, ARMRegisters::S1); + store32(ARMRegisters::S1, address); + } + + void store32(Imm32 imm, ImplicitAddress address) + { + if (imm.m_isPointer) + m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); + else + move(imm, ARMRegisters::S1); + store32(ARMRegisters::S1, address); + } + + void store32(RegisterID src, void* address) + { + m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address)); + m_assembler.dtr_u(false, src, ARMRegisters::S0, 0); + } + + void store32(Imm32 imm, void* address) + { + m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address)); + if (imm.m_isPointer) + m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); + else + m_assembler.moveImm(imm.m_value, ARMRegisters::S1); + m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); + } + + void pop(RegisterID dest) + { + m_assembler.pop_r(dest); + } + + void push(RegisterID src) + { + m_assembler.push_r(src); + } + + void push(Address address) + { + load32(address, ARMRegisters::S1); + push(ARMRegisters::S1); + } + + void push(Imm32 imm) + { + move(imm, ARMRegisters::S0); + push(ARMRegisters::S0); + } + + void move(Imm32 imm, RegisterID dest) + { + if (imm.m_isPointer) + m_assembler.ldr_un_imm(dest, imm.m_value); + else + m_assembler.moveImm(imm.m_value, dest); + } + + void move(RegisterID src, RegisterID dest) + { + m_assembler.mov_r(dest, src); + } + + void move(ImmPtr imm, RegisterID dest) + { + move(Imm32(imm), dest); + } + + void swap(RegisterID reg1, RegisterID reg2) + { + m_assembler.mov_r(ARMRegisters::S0, reg1); + m_assembler.mov_r(reg1, reg2); + m_assembler.mov_r(reg2, ARMRegisters::S0); + } + + void signExtend32ToPtr(RegisterID src, RegisterID dest) + { + if (src != dest) + move(src, dest); + } + + void zeroExtend32ToPtr(RegisterID src, RegisterID dest) + { + if (src != dest) + move(src, dest); + } + + Jump branch8(Condition cond, Address left, Imm32 right) + { + load8(left, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); + } + + Jump branch32(Condition cond, RegisterID left, RegisterID right, int useConstantPool = 0) + { + m_assembler.cmp_r(left, right); + return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); + } + + Jump branch32(Condition cond, RegisterID left, Imm32 right, int useConstantPool = 0) + { + ASSERT(left != ARMRegisters::S0); + if (right.m_isPointer) { + m_assembler.ldr_un_imm(ARMRegisters::S0, right.m_value); + m_assembler.cmp_r(left, ARMRegisters::S0); + } else + m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); + return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); + } + + // Like branch32, but emit a consistently-structured sequence such that the + // number of instructions emitted is constant, regardless of the argument + // values. For ARM, this is identical to branch32WithPatch, except that it + // does not generate a DataLabel32. + Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right) + { + m_assembler.ldr_un_imm(ARMRegisters::S1, right.m_value); + return branch32(cond, left, ARMRegisters::S1, true); + } + + // As branch32_force32, but allow the value ('right') to be patched. + Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel) + { + ASSERT(left != ARMRegisters::S1); + dataLabel = moveWithPatch(right, ARMRegisters::S1); + return branch32(cond, left, ARMRegisters::S1, true); + } + + Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel) + { + ASSERT(left.base != ARMRegisters::S1); + load32(left, ARMRegisters::S1); + dataLabel = moveWithPatch(right, ARMRegisters::S0); + return branch32(cond, ARMRegisters::S1, ARMRegisters::S0, true); + } + + Jump branch32(Condition cond, RegisterID left, Address right) + { + load32(right, ARMRegisters::S1); + return branch32(cond, left, ARMRegisters::S1); + } + + Jump branch32(Condition cond, Address left, RegisterID right) + { + load32(left, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); + } + + Jump branch32(Condition cond, Address left, Imm32 right) + { + load32(left, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); + } + + Jump branch32(Condition cond, BaseIndex left, Imm32 right) + { + load32(left, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); + } + + Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) + { + load32WithUnalignedHalfWords(left, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); + } + + Jump branch16(Condition cond, BaseIndex left, RegisterID right) + { + (void)(cond); + (void)(left); + (void)(right); + ASSERT_NOT_REACHED(); + return jump(); + } + + Jump branch16(Condition cond, BaseIndex left, Imm32 right) + { + load16(left, ARMRegisters::S0); + move(right, ARMRegisters::S1); + m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S1); + return m_assembler.jmp(ARMCondition(cond)); + } + + Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) + { + load8(address, ARMRegisters::S1); + return branchTest32(cond, ARMRegisters::S1, mask); + } + + Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) + { + ASSERT((cond == Zero) || (cond == NonZero)); + m_assembler.tst_r(reg, mask); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + ARMWord w = m_assembler.getImm(mask.m_value, ARMRegisters::S0, true); + if (w & ARMAssembler::OP2_INV_IMM) + m_assembler.bics_r(ARMRegisters::S0, reg, w & ~ARMAssembler::OP2_INV_IMM); + else + m_assembler.tst_r(reg, w); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) + { + load32(address, ARMRegisters::S1); + return branchTest32(cond, ARMRegisters::S1, mask); + } + + Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) + { + load32(address, ARMRegisters::S1); + return branchTest32(cond, ARMRegisters::S1, mask); + } + + Jump jump() + { + return Jump(m_assembler.jmp()); + } + + void jump(RegisterID target) + { + m_assembler.bx(target); + } + + void jump(Address address) + { + load32(address, ARMRegisters::pc); + } + + Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + add32(src, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + add32(imm, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + Jump branchAdd32(Condition cond, Address src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + add32(src, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + void mull32(RegisterID src1, RegisterID src2, RegisterID dest) + { + if (src1 == dest) { + move(src1, ARMRegisters::S0); + src1 = ARMRegisters::S0; + } + m_assembler.mull_r(ARMRegisters::S1, dest, src2, src1); + m_assembler.cmp_r(ARMRegisters::S1, m_assembler.asr(dest, 31)); + } + + Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + if (cond == Overflow) { + mull32(src, dest, dest); + cond = NonZero; + } + else + mul32(src, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + if (cond == Overflow) { + move(imm, ARMRegisters::S0); + mull32(ARMRegisters::S0, src, dest); + cond = NonZero; + } + else + mul32(imm, src, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + sub32(src, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + sub32(imm, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + Jump branchSub32(Condition cond, Address src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + sub32(src, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + Jump branchSub32(Condition cond, Imm32 imm, Address dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + sub32(imm, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + Jump branchNeg32(Condition cond, RegisterID srcDest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + neg32(srcDest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) + { + ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); + or32(src, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + // Encode a NOP using "MOV rX, rX", where 'X' is defined by 'tag', and is + // in the range r0-r14. + void nop(int tag) + { + ASSERT((tag >= 0) && (tag <= 14)); + m_assembler.mov_r(tag, tag); + } + + void breakpoint() + { + m_assembler.bkpt(0); + } + + Call nearCall() + { +#if WTF_ARM_ARCH_VERSION >= 5 + Call call(m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true), Call::LinkableNear); + m_assembler.blx(ARMRegisters::S1); + return call; +#else + prepareCall(); + return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::LinkableNear); +#endif + } + + Call call(RegisterID target) + { + m_assembler.blx(target); + JmpSrc jmpSrc; + return Call(jmpSrc, Call::None); + } + + void call(Address address) + { + call32(address.base, address.offset); + } + + void ret() + { + m_assembler.bx(linkRegister); + } + + void set32(Condition cond, Address left, RegisterID right, RegisterID dest) + { + load32(left, ARMRegisters::S1); + set32(cond, ARMRegisters::S1, right, dest); + } + + void set32(Condition cond, RegisterID left, Address right, RegisterID dest) + { + load32(right, ARMRegisters::S1); + set32(cond, left, ARMRegisters::S1, dest); + } + + void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) + { + m_assembler.cmp_r(left, right); + m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); + m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); + } + + void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) + { + m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); + m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); + m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); + } + + void set32(Condition cond, Address left, Imm32 right, RegisterID dest) + { + load32(left, ARMRegisters::S1); + set32(cond, ARMRegisters::S1, right, dest); + } + + void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest) + { + // ARM doesn't have byte registers + set32(cond, left, right, dest); + } + + void set8(Condition cond, Address left, RegisterID right, RegisterID dest) + { + // ARM doesn't have byte registers + load32(left, ARMRegisters::S1); + set32(cond, ARMRegisters::S1, right, dest); + } + + void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest) + { + // ARM doesn't have byte registers + set32(cond, left, right, dest); + } + + void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest) + { + load32(address, ARMRegisters::S1); + if (mask.m_value == -1) + m_assembler.cmp_r(0, ARMRegisters::S1); + else + m_assembler.tst_r(ARMRegisters::S1, m_assembler.getImm(mask.m_value, ARMRegisters::S0)); + m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); + m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); + } + + void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest) + { + // ARM doesn't have byte registers + setTest32(cond, address, mask, dest); + } + + void add32(Imm32 imm, RegisterID src, RegisterID dest) + { + m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + } + + void lea(Address address, RegisterID dest) + { + m_assembler.add_r(dest, address.base, m_assembler.getImm(address.offset, ARMRegisters::S0)); + } + + void lea(BaseIndex address, RegisterID dest) + { + /* This could be better? */ + move(address.index, ARMRegisters::S1); + if (address.scale != 0) + lshift32(Imm32(address.scale), ARMRegisters::S1); + if (address.offset) + add32(Imm32(address.offset), ARMRegisters::S1); + add32(address.base, ARMRegisters::S1); + move(ARMRegisters::S1, dest); + } + + void add32(Imm32 imm, AbsoluteAddress address) + { + m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr)); + m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); + add32(imm, ARMRegisters::S1); + m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address.m_ptr)); + m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); + } + + void sub32(Imm32 imm, AbsoluteAddress address) + { + m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr)); + m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); + sub32(imm, ARMRegisters::S1); + m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address.m_ptr)); + m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); + } + + void load32(void* address, RegisterID dest) + { + m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address)); + m_assembler.dtr_u(true, dest, ARMRegisters::S0, 0); + } + + Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) + { + load32(left.m_ptr, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); + } + + Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) + { + load32(left.m_ptr, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); + } + + Call call() + { +#if WTF_ARM_ARCH_VERSION >= 5 + Call call(m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true), Call::Linkable); + m_assembler.blx(ARMRegisters::S1); + return call; +#else + prepareCall(); + return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::Linkable); +#endif + } + + Call tailRecursiveCall() + { + return Call::fromTailJump(jump()); + } + + Call makeTailRecursiveCall(Jump oldJump) + { + return Call::fromTailJump(oldJump); + } + + DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest) + { + DataLabelPtr dataLabel(this); + m_assembler.ldr_un_imm(dest, reinterpret_cast(initialValue.m_value)); + return dataLabel; + } + + DataLabel32 moveWithPatch(Imm32 initialValue, RegisterID dest) + { + DataLabel32 dataLabel(this); + m_assembler.ldr_un_imm(dest, initialValue.m_value); + return dataLabel; + } + + Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) + { + dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1); + Jump jump = branch32(cond, left, ARMRegisters::S1, true); + return jump; + } + + Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) + { + load32(left, ARMRegisters::S1); + dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0); + Jump jump = branch32(cond, ARMRegisters::S0, ARMRegisters::S1, true); + return jump; + } + + DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) + { + DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1); + store32(ARMRegisters::S1, address); + return dataLabel; + } + + DataLabelPtr storePtrWithPatch(ImplicitAddress address) + { + return storePtrWithPatch(ImmPtr(0), address); + } + + // Floating point operators + bool supportsFloatingPoint() const + { + return s_isVFPPresent; + } + + bool supportsFloatingPointTruncate() const + { + return true; + } + + bool supportsFloatingPointSqrt() const + { + return s_isVFPPresent; + } + + void moveDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.fcpyd_r(dest, src); + } + + void loadDouble(ImplicitAddress address, FPRegisterID dest) + { + m_assembler.doubleTransfer(true, dest, address.base, address.offset); + } + + DataLabelPtr loadDouble(const void* address, FPRegisterID dest) + { + DataLabelPtr label = moveWithPatch(ImmPtr(address), ARMRegisters::S0); + m_assembler.fdtr_u(true, dest, ARMRegisters::S0, 0); + return label; + } + + void storeDouble(FPRegisterID src, ImplicitAddress address) + { + m_assembler.doubleTransfer(false, src, address.base, address.offset); + } + + void addDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.faddd_r(dest, dest, src); + } + + void addDouble(Address src, FPRegisterID dest) + { + loadDouble(src, ARMRegisters::SD0); + addDouble(ARMRegisters::SD0, dest); + } + + void divDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.fdivd_r(dest, dest, src); + } + + void divDouble(Address src, FPRegisterID dest) + { + ASSERT_NOT_REACHED(); // Untested + loadDouble(src, ARMRegisters::SD0); + divDouble(ARMRegisters::SD0, dest); + } + + void subDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.fsubd_r(dest, dest, src); + } + + void subDouble(Address src, FPRegisterID dest) + { + loadDouble(src, ARMRegisters::SD0); + subDouble(ARMRegisters::SD0, dest); + } + + void mulDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.fmuld_r(dest, dest, src); + } + + void mulDouble(Address src, FPRegisterID dest) + { + loadDouble(src, ARMRegisters::SD0); + mulDouble(ARMRegisters::SD0, dest); + } + + void negDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.fnegd_r(dest, src); + } + + void sqrtDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.fsqrtd_r(dest, src); + } + + void convertInt32ToDouble(RegisterID src, FPRegisterID dest) + { + m_assembler.fmsr_r(dest, src); + m_assembler.fsitod_r(dest, dest); + } + + void convertInt32ToDouble(Address src, FPRegisterID dest) + { + // flds does not worth the effort here + load32(src, ARMRegisters::S1); + convertInt32ToDouble(ARMRegisters::S1, dest); + } + + void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) + { + ASSERT_NOT_REACHED(); // Untested + // flds does not worth the effort here + m_assembler.ldr_un_imm(ARMRegisters::S1, (ARMWord)src.m_ptr); + m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); + convertInt32ToDouble(ARMRegisters::S1, dest); + } + + Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) + { + m_assembler.fcmpd_r(left, right); + m_assembler.fmstat(); + if (cond & DoubleConditionBitSpecial) + m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS); + return Jump(m_assembler.jmp(static_cast(cond & ~DoubleConditionMask))); + } + + // Truncates 'src' to an integer, and places the resulting 'dest'. + // If the result is not representable as a 32 bit value, branch. + // May also branch for some values that are representable in 32 bits + Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest) + { + m_assembler.ftosizd_r(ARMRegisters::SD0, src); + // If FTOSIZD (VCVT.S32.F64) can't fit the result into a 32-bit + // integer, it saturates at INT_MAX or INT_MIN. Testing this is + // probably quicker than testing FPSCR for exception. + m_assembler.fmrs_r(dest, ARMRegisters::SD0); + m_assembler.cmn_r(dest, ARMAssembler::getOp2(-0x7fffffff)); + m_assembler.cmp_r(dest, ARMAssembler::getOp2(0x80000000), ARMCondition(NonZero)); + return Jump(m_assembler.jmp(ARMCondition(Zero))); + } + + // Convert 'src' to an integer, and places the resulting 'dest'. + // If the result is not representable as a 32 bit value, branch. + // May also branch for some values that are representable in 32 bits + // (specifically, in this case, 0). + void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) + { + m_assembler.ftosid_r(ARMRegisters::SD0, src); + m_assembler.fmrs_r(dest, ARMRegisters::SD0); + + // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. + m_assembler.fsitod_r(ARMRegisters::SD0, ARMRegisters::SD0); + failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, ARMRegisters::SD0)); + + // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0 + failureCases.append(branchTest32(Zero, dest)); + } + + void zeroDouble(FPRegisterID srcDest) + { + m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2(0)); + convertInt32ToDouble(ARMRegisters::S0, srcDest); + } + + void ensureSpace(int space) + { + m_assembler.ensureSpace(space); + } + + void forceFlushConstantPool() + { + m_assembler.forceFlushConstantPool(); + } + +#ifdef DEBUG + void allowPoolFlush(bool allowFlush) + { + m_assembler.allowPoolFlush(allowFlush); + } +#endif + +protected: + ARMAssembler::Condition ARMCondition(Condition cond) + { + return static_cast(cond); + } + + void ensureSpace(int insnSpace, int constSpace) + { + m_assembler.ensureSpace(insnSpace, constSpace); + } + + int sizeOfConstantPool() + { + return m_assembler.sizeOfConstantPool(); + } + +#if WTF_ARM_ARCH_VERSION < 5 + void prepareCall() + { +#if WTF_ARM_ARCH_VERSION < 5 + ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); + + m_assembler.mov_r(linkRegister, ARMRegisters::pc); +#endif + } +#endif + +#if WTF_ARM_ARCH_VERSION < 5 + void call32(RegisterID base, int32_t offset) + { +#if WTF_ARM_ARCH_VERSION >= 5 + int targetReg = ARMRegisters::S1; +#else + int targetReg = ARMRegisters::pc; +#endif + int tmpReg = ARMRegisters::S1; + + if (base == ARMRegisters::sp) + offset += 4; + + if (offset >= 0) { + if (offset <= 0xfff) { + prepareCall(); + m_assembler.dtr_u(true, targetReg, base, offset); + } else if (offset <= 0xfffff) { + m_assembler.add_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); + prepareCall(); + m_assembler.dtr_u(true, targetReg, tmpReg, offset & 0xfff); + } else { + ARMWord reg = m_assembler.getImm(offset, tmpReg); + prepareCall(); + m_assembler.dtr_ur(true, targetReg, base, reg); + } + } else { + offset = -offset; + if (offset <= 0xfff) { + prepareCall(); + m_assembler.dtr_d(true, targetReg, base, offset); + } else if (offset <= 0xfffff) { + m_assembler.sub_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); + prepareCall(); + m_assembler.dtr_d(true, targetReg, tmpReg, offset & 0xfff); + } else { + ARMWord reg = m_assembler.getImm(offset, tmpReg); + prepareCall(); + m_assembler.dtr_dr(true, targetReg, base, reg); + } + } +#if WTF_ARM_ARCH_VERSION >= 5 + m_assembler.blx(targetReg); +#endif + } +#else + void call32(RegisterID base, int32_t offset) + { + // TODO: Why is SP special? + if (base == ARMRegisters::sp) + offset += 4; + + // Branch to the address stored in base+offset, using one of the + // following sequences: + // ---- + // LDR ip, [base, ±offset] + // BLX ip + // ---- + // ADD/SUB ip, base, #(offset & 0xff000) + // LDR ip, [ip, #(offset & 0xfff)] + // BLX ip + // ---- + // LDR ip, =offset + // LDR ip, [base, ±ip] + // BLX ip + + if (offset >= 0) { + if (offset <= 0xfff) { + m_assembler.dtr_u(true, ARMRegisters::S0, base, offset); + } else if (offset <= 0xfffff) { + m_assembler.add_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); + m_assembler.dtr_u(true, ARMRegisters::S0, ARMRegisters::S0, offset & 0xfff); + } else { + m_assembler.moveImm(offset, ARMRegisters::S0); + m_assembler.dtr_ur(true, ARMRegisters::S0, base, ARMRegisters::S0); + } + } else { + offset = -offset; + if (offset <= 0xfff) { + m_assembler.dtr_d(true, ARMRegisters::S0, base, offset); + } else if (offset <= 0xfffff) { + m_assembler.sub_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); + m_assembler.dtr_d(true, ARMRegisters::S0, ARMRegisters::S0, offset & 0xfff); + } else { + m_assembler.moveImm(offset, ARMRegisters::S0); + m_assembler.dtr_dr(true, ARMRegisters::S0, base, ARMRegisters::S0); + } + } + m_assembler.blx(ARMRegisters::S0); + } +#endif + +private: + friend class LinkBuffer; + friend class RepatchBuffer; + + static void linkCall(void* code, Call call, FunctionPtr function) + { + ARMAssembler::linkCall(code, call.m_jmp, function.value()); + } + + static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) + { + ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); + } + + static void repatchCall(CodeLocationCall call, FunctionPtr destination) + { + ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); + } + + static const bool s_isVFPPresent; +}; + +} + +#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) + +#endif // MacroAssemblerARM_h diff --git a/js/src/assembler/assembler/MacroAssemblerARMv7.h b/js/src/assembler/assembler/MacroAssemblerARMv7.h new file mode 100644 index 0000000..5492f82 --- /dev/null +++ b/js/src/assembler/assembler/MacroAssemblerARMv7.h @@ -0,0 +1,1223 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2010 University of Szeged + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MacroAssemblerARMv7_h +#define MacroAssemblerARMv7_h + +#include "assembler/wtf/Platform.h" + +#if ENABLE(ASSEMBLER) + +#include "ARMv7Assembler.h" +#include "AbstractMacroAssembler.h" + +namespace JSC { + +class MacroAssemblerARMv7 : public AbstractMacroAssembler { + // FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7? + // - dTR is likely used more than aTR, and we'll get better instruction + // encoding if it's in the low 8 registers. + static const ARMRegisters::RegisterID dataTempRegister = ARMRegisters::ip; + static const RegisterID addressTempRegister = ARMRegisters::r3; + static const FPRegisterID fpTempRegister = ARMRegisters::d7; + static const unsigned int TotalRegisters = 16; + + struct ArmAddress { + enum AddressType { + HasOffset, + HasIndex, + } type; + RegisterID base; + union { + int32_t offset; + struct { + RegisterID index; + Scale scale; + }; + } u; + + explicit ArmAddress(RegisterID base, int32_t offset = 0) + : type(HasOffset) + , base(base) + { + u.offset = offset; + } + + explicit ArmAddress(RegisterID base, RegisterID index, Scale scale = TimesOne) + : type(HasIndex) + , base(base) + { + u.index = index; + u.scale = scale; + } + }; + +public: + + static const Scale ScalePtr = TimesFour; + + enum Condition { + Equal = ARMv7Assembler::ConditionEQ, + NotEqual = ARMv7Assembler::ConditionNE, + Above = ARMv7Assembler::ConditionHI, + AboveOrEqual = ARMv7Assembler::ConditionHS, + Below = ARMv7Assembler::ConditionLO, + BelowOrEqual = ARMv7Assembler::ConditionLS, + GreaterThan = ARMv7Assembler::ConditionGT, + GreaterThanOrEqual = ARMv7Assembler::ConditionGE, + LessThan = ARMv7Assembler::ConditionLT, + LessThanOrEqual = ARMv7Assembler::ConditionLE, + Overflow = ARMv7Assembler::ConditionVS, + Signed = ARMv7Assembler::ConditionMI, + Zero = ARMv7Assembler::ConditionEQ, + NonZero = ARMv7Assembler::ConditionNE + }; + enum DoubleCondition { + // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. + DoubleEqual = ARMv7Assembler::ConditionEQ, + DoubleNotEqual = ARMv7Assembler::ConditionVC, // Not the right flag! check for this & handle differently. + DoubleGreaterThan = ARMv7Assembler::ConditionGT, + DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE, + DoubleLessThan = ARMv7Assembler::ConditionLO, + DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS, + // If either operand is NaN, these conditions always evaluate to true. + DoubleEqualOrUnordered = ARMv7Assembler::ConditionVS, // Not the right flag! check for this & handle differently. + DoubleNotEqualOrUnordered = ARMv7Assembler::ConditionNE, + DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI, + DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS, + DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT, + DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE, + }; + + static const RegisterID stackPointerRegister = ARMRegisters::sp; + static const RegisterID linkRegister = ARMRegisters::lr; + + // Integer arithmetic operations: + // + // Operations are typically two operand - operation(source, srcDst) + // For many operations the source may be an Imm32, the srcDst operand + // may often be a memory location (explictly described using an Address + // object). + + void add32(RegisterID src, RegisterID dest) + { + m_assembler.add(dest, dest, src); + } + + void add32(Imm32 imm, RegisterID dest) + { + add32(imm, dest, dest); + } + + void add32(Imm32 imm, RegisterID src, RegisterID dest) + { + ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); + if (armImm.isValid()) + m_assembler.add(dest, src, armImm); + else { + move(imm, dataTempRegister); + m_assembler.add(dest, src, dataTempRegister); + } + } + + void add32(Imm32 imm, Address address) + { + load32(address, dataTempRegister); + + ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); + if (armImm.isValid()) + m_assembler.add(dataTempRegister, dataTempRegister, armImm); + else { + // Hrrrm, since dataTempRegister holds the data loaded, + // use addressTempRegister to hold the immediate. + move(imm, addressTempRegister); + m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister); + } + + store32(dataTempRegister, address); + } + + void add32(Address src, RegisterID dest) + { + load32(src, dataTempRegister); + add32(dataTempRegister, dest); + } + + void add32(Imm32 imm, AbsoluteAddress address) + { + load32(address.m_ptr, dataTempRegister); + + ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); + if (armImm.isValid()) + m_assembler.add(dataTempRegister, dataTempRegister, armImm); + else { + // Hrrrm, since dataTempRegister holds the data loaded, + // use addressTempRegister to hold the immediate. + move(imm, addressTempRegister); + m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister); + } + + store32(dataTempRegister, address.m_ptr); + } + + void and32(RegisterID src, RegisterID dest) + { + m_assembler.ARM_and(dest, dest, src); + } + + void and32(Imm32 imm, RegisterID dest) + { + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); + if (armImm.isValid()) + m_assembler.ARM_and(dest, dest, armImm); + else { + move(imm, dataTempRegister); + m_assembler.ARM_and(dest, dest, dataTempRegister); + } + } + + void lshift32(RegisterID shift_amount, RegisterID dest) + { + // Clamp the shift to the range 0..31 + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); + ASSERT(armImm.isValid()); + m_assembler.ARM_and(dataTempRegister, shift_amount, armImm); + + m_assembler.lsl(dest, dest, dataTempRegister); + } + + void lshift32(Imm32 imm, RegisterID dest) + { + m_assembler.lsl(dest, dest, imm.m_value & 0x1f); + } + + void mul32(RegisterID src, RegisterID dest) + { + m_assembler.smull(dest, dataTempRegister, dest, src); + } + + void mul32(Imm32 imm, RegisterID src, RegisterID dest) + { + move(imm, dataTempRegister); + m_assembler.smull(dest, dataTempRegister, src, dataTempRegister); + } + + void not32(RegisterID srcDest) + { + m_assembler.mvn(srcDest, srcDest); + } + + void or32(RegisterID src, RegisterID dest) + { + m_assembler.orr(dest, dest, src); + } + + void or32(Imm32 imm, RegisterID dest) + { + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); + if (armImm.isValid()) + m_assembler.orr(dest, dest, armImm); + else { + move(imm, dataTempRegister); + m_assembler.orr(dest, dest, dataTempRegister); + } + } + + void rshift32(RegisterID shift_amount, RegisterID dest) + { + // Clamp the shift to the range 0..31 + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); + ASSERT(armImm.isValid()); + m_assembler.ARM_and(dataTempRegister, shift_amount, armImm); + + m_assembler.asr(dest, dest, dataTempRegister); + } + + void rshift32(Imm32 imm, RegisterID dest) + { + m_assembler.asr(dest, dest, imm.m_value & 0x1f); + } + + void urshift32(RegisterID shift_amount, RegisterID dest) + { + // Clamp the shift to the range 0..31 + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); + ASSERT(armImm.isValid()); + m_assembler.ARM_and(dataTempRegister, shift_amount, armImm); + + m_assembler.lsr(dest, dest, dataTempRegister); + } + + void urshift32(Imm32 imm, RegisterID dest) + { + m_assembler.lsr(dest, dest, imm.m_value & 0x1f); + } + + void sub32(RegisterID src, RegisterID dest) + { + m_assembler.sub(dest, dest, src); + } + + void sub32(Imm32 imm, RegisterID dest) + { + ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); + if (armImm.isValid()) + m_assembler.sub(dest, dest, armImm); + else { + move(imm, dataTempRegister); + m_assembler.sub(dest, dest, dataTempRegister); + } + } + + void sub32(Imm32 imm, Address address) + { + load32(address, dataTempRegister); + + ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); + if (armImm.isValid()) + m_assembler.sub(dataTempRegister, dataTempRegister, armImm); + else { + // Hrrrm, since dataTempRegister holds the data loaded, + // use addressTempRegister to hold the immediate. + move(imm, addressTempRegister); + m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister); + } + + store32(dataTempRegister, address); + } + + void sub32(Address src, RegisterID dest) + { + load32(src, dataTempRegister); + sub32(dataTempRegister, dest); + } + + void sub32(Imm32 imm, AbsoluteAddress address) + { + load32(address.m_ptr, dataTempRegister); + + ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); + if (armImm.isValid()) + m_assembler.sub(dataTempRegister, dataTempRegister, armImm); + else { + // Hrrrm, since dataTempRegister holds the data loaded, + // use addressTempRegister to hold the immediate. + move(imm, addressTempRegister); + m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister); + } + + store32(dataTempRegister, address.m_ptr); + } + + void xor32(RegisterID src, RegisterID dest) + { + m_assembler.eor(dest, dest, src); + } + + void xor32(Imm32 imm, RegisterID dest) + { + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); + if (armImm.isValid()) + m_assembler.eor(dest, dest, armImm); + else { + move(imm, dataTempRegister); + m_assembler.eor(dest, dest, dataTempRegister); + } + } + + + // Memory access operations: + // + // Loads are of the form load(address, destination) and stores of the form + // store(source, address). The source for a store may be an Imm32. Address + // operand objects to loads and store will be implicitly constructed if a + // register is passed. + +private: + void load32(ArmAddress address, RegisterID dest) + { + if (address.type == ArmAddress::HasIndex) + m_assembler.ldr(dest, address.base, address.u.index, address.u.scale); + else if (address.u.offset >= 0) { + ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); + ASSERT(armImm.isValid()); + m_assembler.ldr(dest, address.base, armImm); + } else { + ASSERT(address.u.offset >= -255); + m_assembler.ldr(dest, address.base, address.u.offset, true, false); + } + } + + void load16(ArmAddress address, RegisterID dest) + { + if (address.type == ArmAddress::HasIndex) + m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale); + else if (address.u.offset >= 0) { + ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); + ASSERT(armImm.isValid()); + m_assembler.ldrh(dest, address.base, armImm); + } else { + ASSERT(address.u.offset >= -255); + m_assembler.ldrh(dest, address.base, address.u.offset, true, false); + } + } + + void load8(ArmAddress address, RegisterID dest) + { + if (address.type == ArmAddress::HasIndex) + m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale); + else if (address.u.offset >= 0) { + ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); + ASSERT(armImm.isValid()); + m_assembler.ldrb(dest, address.base, armImm); + } else { + ASSERT(address.u.offset >= -255); + m_assembler.ldrb(dest, address.base, address.u.offset, true, false); + } + } + + void store32(RegisterID src, ArmAddress address) + { + if (address.type == ArmAddress::HasIndex) + m_assembler.str(src, address.base, address.u.index, address.u.scale); + else if (address.u.offset >= 0) { + ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); + ASSERT(armImm.isValid()); + m_assembler.str(src, address.base, armImm); + } else { + ASSERT(address.u.offset >= -255); + m_assembler.str(src, address.base, address.u.offset, true, false); + } + } + +public: + void load32(ImplicitAddress address, RegisterID dest) + { + load32(setupArmAddress(address), dest); + } + + void load32(BaseIndex address, RegisterID dest) + { + load32(setupArmAddress(address), dest); + } + + void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) + { + load32(setupArmAddress(address), dest); + } + + void load32(void* address, RegisterID dest) + { + move(ImmPtr(address), addressTempRegister); + m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); + } + + void load8(ImplicitAddress address, RegisterID dest) + { + load8(setupArmAddress(address), dest); + } + + DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) + { + DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister); + load32(ArmAddress(address.base, dataTempRegister), dest); + return label; + } + + Label loadPtrWithPatchToLEA(Address address, RegisterID dest) + { + Label label(this); + moveFixedWidthEncoding(Imm32(address.offset), dataTempRegister); + load32(ArmAddress(address.base, dataTempRegister), dest); + return label; + } + + void load16(BaseIndex address, RegisterID dest) + { + m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale); + } + + void load16(ImplicitAddress address, RegisterID dest) + { + m_assembler.ldrh(dest, address.base, address.offset); + } + + DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) + { + DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister); + store32(src, ArmAddress(address.base, dataTempRegister)); + return label; + } + + void store32(RegisterID src, ImplicitAddress address) + { + store32(src, setupArmAddress(address)); + } + + void store32(RegisterID src, BaseIndex address) + { + store32(src, setupArmAddress(address)); + } + + void store32(Imm32 imm, ImplicitAddress address) + { + move(imm, dataTempRegister); + store32(dataTempRegister, setupArmAddress(address)); + } + + void store32(RegisterID src, void* address) + { + move(ImmPtr(address), addressTempRegister); + m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); + } + + void store32(Imm32 imm, void* address) + { + move(imm, dataTempRegister); + store32(dataTempRegister, address); + } + + + // Floating-point operations: + + bool supportsFloatingPoint() const { return true; } + // On x86(_64) the MacroAssembler provides an interface to truncate a double to an integer. + // If a value is not representable as an integer, and possibly for some values that are, + // (on x86 INT_MIN, since this is indistinguishable from results for out-of-range/NaN input) + // a branch will be taken. It is not clear whether this interface will be well suited to + // other platforms. On ARMv7 the hardware truncation operation produces multiple possible + // failure values (saturates to INT_MIN & INT_MAX, NaN reulsts in a value of 0). This is a + // temporary solution while we work out what this interface should be. Either we need to + // decide to make this interface work on all platforms, rework the interface to make it more + // generic, or decide that the MacroAssembler cannot practically be used to abstracted these + // operations, and make clients go directly to the m_assembler to plant truncation instructions. + // In short, FIXME:. + bool supportsFloatingPointTruncate() const { return false; } + + bool supportsFloatingPointSqrt() const + { + return false; + } + + void loadDouble(ImplicitAddress address, FPRegisterID dest) + { + RegisterID base = address.base; + int32_t offset = address.offset; + + // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. + if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) { + add32(Imm32(offset), base, addressTempRegister); + base = addressTempRegister; + offset = 0; + } + + m_assembler.vldr(dest, base, offset); + } + + void storeDouble(FPRegisterID src, ImplicitAddress address) + { + RegisterID base = address.base; + int32_t offset = address.offset; + + // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. + if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) { + add32(Imm32(offset), base, addressTempRegister); + base = addressTempRegister; + offset = 0; + } + + m_assembler.vstr(src, base, offset); + } + + void addDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.vadd_F64(dest, dest, src); + } + + void addDouble(Address src, FPRegisterID dest) + { + loadDouble(src, fpTempRegister); + addDouble(fpTempRegister, dest); + } + + void subDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.vsub_F64(dest, dest, src); + } + + void subDouble(Address src, FPRegisterID dest) + { + loadDouble(src, fpTempRegister); + subDouble(fpTempRegister, dest); + } + + void mulDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.vmul_F64(dest, dest, src); + } + + void mulDouble(Address src, FPRegisterID dest) + { + loadDouble(src, fpTempRegister); + mulDouble(fpTempRegister, dest); + } + + void sqrtDouble(FPRegisterID, FPRegisterID) + { + ASSERT_NOT_REACHED(); + } + + void convertInt32ToDouble(RegisterID src, FPRegisterID dest) + { + m_assembler.vmov(fpTempRegister, src); + m_assembler.vcvt_F64_S32(dest, fpTempRegister); + } + + Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) + { + m_assembler.vcmp_F64(left, right); + m_assembler.vmrs_APSR_nzcv_FPSCR(); + + if (cond == DoubleNotEqual) { + // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump. + Jump unordered = makeBranch(ARMv7Assembler::ConditionVS); + Jump result = makeBranch(ARMv7Assembler::ConditionNE); + unordered.link(this); + return result; + } + if (cond == DoubleEqualOrUnordered) { + Jump unordered = makeBranch(ARMv7Assembler::ConditionVS); + Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE); + unordered.link(this); + // We get here if either unordered, or equal. + Jump result = makeJump(); + notEqual.link(this); + return result; + } + return makeBranch(cond); + } + + Jump branchTruncateDoubleToInt32(FPRegisterID, RegisterID) + { + ASSERT_NOT_REACHED(); + return jump(); + } + + + // Stack manipulation operations: + // + // The ABI is assumed to provide a stack abstraction to memory, + // containing machine word sized units of data. Push and pop + // operations add and remove a single register sized unit of data + // to or from the stack. Peek and poke operations read or write + // values on the stack, without moving the current stack position. + + void pop(RegisterID dest) + { + // store postindexed with writeback + m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true); + } + + void push(RegisterID src) + { + // store preindexed with writeback + m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true); + } + + void push(Address address) + { + load32(address, dataTempRegister); + push(dataTempRegister); + } + + void push(Imm32 imm) + { + move(imm, dataTempRegister); + push(dataTempRegister); + } + + // Register move operations: + // + // Move values in registers. + + void move(Imm32 imm, RegisterID dest) + { + uint32_t value = imm.m_value; + + if (imm.m_isPointer) + moveFixedWidthEncoding(imm, dest); + else { + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value); + + if (armImm.isValid()) + m_assembler.mov(dest, armImm); + else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid()) + m_assembler.mvn(dest, armImm); + else { + m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value)); + if (value & 0xffff0000) + m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16)); + } + } + } + + void move(RegisterID src, RegisterID dest) + { + m_assembler.mov(dest, src); + } + + void move(ImmPtr imm, RegisterID dest) + { + move(Imm32(imm), dest); + } + + void swap(RegisterID reg1, RegisterID reg2) + { + move(reg1, dataTempRegister); + move(reg2, reg1); + move(dataTempRegister, reg2); + } + + void signExtend32ToPtr(RegisterID src, RegisterID dest) + { + if (src != dest) + move(src, dest); + } + + void zeroExtend32ToPtr(RegisterID src, RegisterID dest) + { + if (src != dest) + move(src, dest); + } + + + // Forwards / external control flow operations: + // + // This set of jump and conditional branch operations return a Jump + // object which may linked at a later point, allow forwards jump, + // or jumps that will require external linkage (after the code has been + // relocated). + // + // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge + // respecitvely, for unsigned comparisons the names b, a, be, and ae are + // used (representing the names 'below' and 'above'). + // + // Operands to the comparision are provided in the expected order, e.g. + // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when + // treated as a signed 32bit value, is less than or equal to 5. + // + // jz and jnz test whether the first operand is equal to zero, and take + // an optional second operand of a mask under which to perform the test. +private: + + // Should we be using TEQ for equal/not-equal? + void compare32(RegisterID left, Imm32 right) + { + int32_t imm = right.m_value; + if (!imm) + m_assembler.tst(left, left); + else { + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm); + if (armImm.isValid()) + m_assembler.cmp(left, armImm); + if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid()) + m_assembler.cmn(left, armImm); + else { + move(Imm32(imm), dataTempRegister); + m_assembler.cmp(left, dataTempRegister); + } + } + } + + void test32(RegisterID reg, Imm32 mask) + { + int32_t imm = mask.m_value; + + if (imm == -1) + m_assembler.tst(reg, reg); + else { + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm); + if (armImm.isValid()) + m_assembler.tst(reg, armImm); + else { + move(mask, dataTempRegister); + m_assembler.tst(reg, dataTempRegister); + } + } + } + +public: + Jump branch32(Condition cond, RegisterID left, RegisterID right) + { + m_assembler.cmp(left, right); + return Jump(makeBranch(cond)); + } + + Jump branch32(Condition cond, RegisterID left, Imm32 right) + { + compare32(left, right); + return Jump(makeBranch(cond)); + } + + Jump branch32(Condition cond, RegisterID left, Address right) + { + load32(right, dataTempRegister); + return branch32(cond, left, dataTempRegister); + } + + Jump branch32(Condition cond, Address left, RegisterID right) + { + load32(left, dataTempRegister); + return branch32(cond, dataTempRegister, right); + } + + Jump branch32(Condition cond, Address left, Imm32 right) + { + // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ + load32(left, addressTempRegister); + return branch32(cond, addressTempRegister, right); + } + + Jump branch32(Condition cond, BaseIndex left, Imm32 right) + { + // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ + load32(left, addressTempRegister); + return branch32(cond, addressTempRegister, right); + } + + Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) + { + // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ + load32WithUnalignedHalfWords(left, addressTempRegister); + return branch32(cond, addressTempRegister, right); + } + + Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) + { + load32(left.m_ptr, dataTempRegister); + return branch32(cond, dataTempRegister, right); + } + + Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) + { + // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ + load32(left.m_ptr, addressTempRegister); + return branch32(cond, addressTempRegister, right); + } + + Jump branch16(Condition cond, BaseIndex left, RegisterID right) + { + load16(left, dataTempRegister); + m_assembler.lsl(addressTempRegister, right, 16); + m_assembler.lsl(dataTempRegister, dataTempRegister, 16); + return branch32(cond, dataTempRegister, addressTempRegister); + } + + Jump branch16(Condition cond, BaseIndex left, Imm32 right) + { + // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ + load16(left, addressTempRegister); + m_assembler.lsl(addressTempRegister, addressTempRegister, 16); + return branch32(cond, addressTempRegister, Imm32(right.m_value << 16)); + } + + Jump branch8(Condition cond, RegisterID left, Imm32 right) + { + compare32(left, right); + return Jump(makeBranch(cond)); + } + + Jump branch8(Condition cond, Address left, Imm32 right) + { + // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/ + load8(left, addressTempRegister); + return branch8(cond, addressTempRegister, right); + } + + Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) + { + ASSERT((cond == Zero) || (cond == NonZero)); + m_assembler.tst(reg, mask); + return Jump(makeBranch(cond)); + } + + Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + test32(reg, mask); + return Jump(makeBranch(cond)); + } + + Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/ + load32(address, addressTempRegister); + return branchTest32(cond, addressTempRegister, mask); + } + + Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/ + load32(address, addressTempRegister); + return branchTest32(cond, addressTempRegister, mask); + } + + Jump branchTest8(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + test32(reg, mask); + return Jump(makeBranch(cond)); + } + + Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/ + load8(address, addressTempRegister); + return branchTest8(cond, addressTempRegister, mask); + } + + Jump jump() + { + return Jump(makeJump()); + } + + void jump(RegisterID target) + { + m_assembler.bx(target); + } + + // Address is a memory location containing the address to jump to + void jump(Address address) + { + load32(address, dataTempRegister); + m_assembler.bx(dataTempRegister); + } + + + // Arithmetic control flow operations: + // + // This set of conditional branch operations branch based + // on the result of an arithmetic operation. The operation + // is performed as normal, storing the result. + // + // * jz operations branch if the result is zero. + // * jo operations branch if the (signed) arithmetic + // operation caused an overflow to occur. + + Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + m_assembler.add_S(dest, dest, src); + return Jump(makeBranch(cond)); + } + + Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); + if (armImm.isValid()) + m_assembler.add_S(dest, dest, armImm); + else { + move(imm, dataTempRegister); + m_assembler.add_S(dest, dest, dataTempRegister); + } + return Jump(makeBranch(cond)); + } + + Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) + { + ASSERT(cond == Overflow); + m_assembler.smull(dest, dataTempRegister, dest, src); + m_assembler.asr(addressTempRegister, dest, 31); + return branch32(NotEqual, addressTempRegister, dataTempRegister); + } + + Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) + { + ASSERT(cond == Overflow); + move(imm, dataTempRegister); + m_assembler.smull(dest, dataTempRegister, src, dataTempRegister); + m_assembler.asr(addressTempRegister, dest, 31); + return branch32(NotEqual, addressTempRegister, dataTempRegister); + } + + Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + m_assembler.sub_S(dest, dest, src); + return Jump(makeBranch(cond)); + } + + Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); + if (armImm.isValid()) + m_assembler.sub_S(dest, dest, armImm); + else { + move(imm, dataTempRegister); + m_assembler.sub_S(dest, dest, dataTempRegister); + } + return Jump(makeBranch(cond)); + } + + + // Miscellaneous operations: + + void breakpoint() + { + m_assembler.bkpt(); + } + + Call nearCall() + { + moveFixedWidthEncoding(Imm32(0), dataTempRegister); + return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear); + } + + Call call() + { + moveFixedWidthEncoding(Imm32(0), dataTempRegister); + return Call(m_assembler.blx(dataTempRegister), Call::Linkable); + } + + Call call(RegisterID target) + { + return Call(m_assembler.blx(target), Call::None); + } + + Call call(Address address) + { + load32(address, dataTempRegister); + return Call(m_assembler.blx(dataTempRegister), Call::None); + } + + void ret() + { + m_assembler.bx(linkRegister); + } + + void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) + { + m_assembler.cmp(left, right); + m_assembler.it(armV7Condition(cond), false); + m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); + m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); + } + + void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) + { + compare32(left, right); + m_assembler.it(armV7Condition(cond), false); + m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); + m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); + } + + // FIXME: + // The mask should be optional... paerhaps the argument order should be + // dest-src, operations always have a dest? ... possibly not true, considering + // asm ops like test, or pseudo ops like pop(). + void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest) + { + load32(address, dataTempRegister); + test32(dataTempRegister, mask); + m_assembler.it(armV7Condition(cond), false); + m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); + m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); + } + + void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest) + { + load8(address, dataTempRegister); + test32(dataTempRegister, mask); + m_assembler.it(armV7Condition(cond), false); + m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); + m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); + } + + DataLabel32 moveWithPatch(Imm32 imm, RegisterID dst) + { + moveFixedWidthEncoding(imm, dst); + return DataLabel32(this); + } + + DataLabelPtr moveWithPatch(ImmPtr imm, RegisterID dst) + { + moveFixedWidthEncoding(Imm32(imm), dst); + return DataLabelPtr(this); + } + + Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) + { + dataLabel = moveWithPatch(initialRightValue, dataTempRegister); + return branch32(cond, left, dataTempRegister); + } + + Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) + { + load32(left, addressTempRegister); + dataLabel = moveWithPatch(initialRightValue, dataTempRegister); + return branch32(cond, addressTempRegister, dataTempRegister); + } + + DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) + { + DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister); + store32(dataTempRegister, address); + return label; + } + DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(ImmPtr(0), address); } + + + Call tailRecursiveCall() + { + // Like a normal call, but don't link. + moveFixedWidthEncoding(Imm32(0), dataTempRegister); + return Call(m_assembler.bx(dataTempRegister), Call::Linkable); + } + + Call makeTailRecursiveCall(Jump oldJump) + { + oldJump.link(this); + return tailRecursiveCall(); + } + + +protected: + ARMv7Assembler::JmpSrc makeJump() + { + moveFixedWidthEncoding(Imm32(0), dataTempRegister); + return m_assembler.bx(dataTempRegister); + } + + ARMv7Assembler::JmpSrc makeBranch(ARMv7Assembler::Condition cond) + { + m_assembler.it(cond, true, true); + moveFixedWidthEncoding(Imm32(0), dataTempRegister); + return m_assembler.bx(dataTempRegister); + } + ARMv7Assembler::JmpSrc makeBranch(Condition cond) { return makeBranch(armV7Condition(cond)); } + ARMv7Assembler::JmpSrc makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); } + + ArmAddress setupArmAddress(BaseIndex address) + { + if (address.offset) { + ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset); + if (imm.isValid()) + m_assembler.add(addressTempRegister, address.base, imm); + else { + move(Imm32(address.offset), addressTempRegister); + m_assembler.add(addressTempRegister, addressTempRegister, address.base); + } + + return ArmAddress(addressTempRegister, address.index, address.scale); + } else + return ArmAddress(address.base, address.index, address.scale); + } + + ArmAddress setupArmAddress(Address address) + { + if ((address.offset >= -0xff) && (address.offset <= 0xfff)) + return ArmAddress(address.base, address.offset); + + move(Imm32(address.offset), addressTempRegister); + return ArmAddress(address.base, addressTempRegister); + } + + ArmAddress setupArmAddress(ImplicitAddress address) + { + if ((address.offset >= -0xff) && (address.offset <= 0xfff)) + return ArmAddress(address.base, address.offset); + + move(Imm32(address.offset), addressTempRegister); + return ArmAddress(address.base, addressTempRegister); + } + + RegisterID makeBaseIndexBase(BaseIndex address) + { + if (!address.offset) + return address.base; + + ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset); + if (imm.isValid()) + m_assembler.add(addressTempRegister, address.base, imm); + else { + move(Imm32(address.offset), addressTempRegister); + m_assembler.add(addressTempRegister, addressTempRegister, address.base); + } + + return addressTempRegister; + } + + void moveFixedWidthEncoding(Imm32 imm, RegisterID dst) + { + uint32_t value = imm.m_value; + m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff)); + m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16)); + } + + ARMv7Assembler::Condition armV7Condition(Condition cond) + { + return static_cast(cond); + } + + ARMv7Assembler::Condition armV7Condition(DoubleCondition cond) + { + return static_cast(cond); + } + +private: + friend class LinkBuffer; + friend class RepatchBuffer; + + static void linkCall(void* code, Call call, FunctionPtr function) + { + ARMv7Assembler::linkCall(code, call.m_jmp, function.value()); + } + + static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) + { + ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); + } + + static void repatchCall(CodeLocationCall call, FunctionPtr destination) + { + ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); + } +}; + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) + +#endif // MacroAssemblerARMv7_h diff --git a/js/src/assembler/assembler/MacroAssemblerCodeRef.h b/js/src/assembler/assembler/MacroAssemblerCodeRef.h new file mode 100644 index 0000000..841fa96 --- /dev/null +++ b/js/src/assembler/assembler/MacroAssemblerCodeRef.h @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MacroAssemblerCodeRef_h +#define MacroAssemblerCodeRef_h + +#include "assembler/wtf/Platform.h" +#include "assembler/jit/ExecutableAllocator.h" + +#if ENABLE_ASSEMBLER + +// ASSERT_VALID_CODE_POINTER checks that ptr is a non-null pointer, and that it is a valid +// instruction address on the platform (for example, check any alignment requirements). +#if WTF_CPU_ARM_THUMB2 +// ARM/thumb instructions must be 16-bit aligned, but all code pointers to be loaded +// into the processor are decorated with the bottom bit set, indicating that this is +// thumb code (as oposed to 32-bit traditional ARM). The first test checks for both +// decorated and undectorated null, and the second test ensures that the pointer is +// decorated. +#define ASSERT_VALID_CODE_POINTER(ptr) \ + ASSERT(reinterpret_cast(ptr) & ~1); \ + ASSERT(reinterpret_cast(ptr) & 1) +#define ASSERT_VALID_CODE_OFFSET(offset) \ + ASSERT(!(offset & 1)) // Must be multiple of 2. +#else +#define ASSERT_VALID_CODE_POINTER(ptr) \ + ASSERT(ptr) +#define ASSERT_VALID_CODE_OFFSET(offset) // Anything goes! +#endif + +namespace JSC { + +// FunctionPtr: +// +// FunctionPtr should be used to wrap pointers to C/C++ functions in JSC +// (particularly, the stub functions). +class FunctionPtr { +public: + FunctionPtr() + : m_value(0) + { + } + + template + explicit FunctionPtr(FunctionType* value) +#if WTF_COMPILER_RVCT + // RVTC compiler needs C-style cast as it fails with the following error + // Error: #694: reinterpret_cast cannot cast away const or other type qualifiers + : m_value((void*)(value)) +#else + : m_value(reinterpret_cast(value)) +#endif + { + ASSERT_VALID_CODE_POINTER(m_value); + } + + void* value() const { return m_value; } + void* executableAddress() const { return m_value; } + + +private: + void* m_value; +}; + +// ReturnAddressPtr: +// +// ReturnAddressPtr should be used to wrap return addresses generated by processor +// 'call' instructions exectued in JIT code. We use return addresses to look up +// exception and optimization information, and to repatch the call instruction +// that is the source of the return address. +class ReturnAddressPtr { +public: + ReturnAddressPtr() + : m_value(0) + { + } + + explicit ReturnAddressPtr(void* value) + : m_value(value) + { + ASSERT_VALID_CODE_POINTER(m_value); + } + + explicit ReturnAddressPtr(FunctionPtr function) + : m_value(function.value()) + { + ASSERT_VALID_CODE_POINTER(m_value); + } + + void* value() const { return m_value; } + +private: + void* m_value; +}; + +// MacroAssemblerCodePtr: +// +// MacroAssemblerCodePtr should be used to wrap pointers to JIT generated code. +class MacroAssemblerCodePtr { +public: + MacroAssemblerCodePtr() + : m_value(0) + { + } + + explicit MacroAssemblerCodePtr(void* value) +#if WTF_CPU_ARM_THUMB2 + // Decorate the pointer as a thumb code pointer. + : m_value(reinterpret_cast(value) + 1) +#else + : m_value(value) +#endif + { + ASSERT_VALID_CODE_POINTER(m_value); + } + + explicit MacroAssemblerCodePtr(ReturnAddressPtr ra) + : m_value(ra.value()) + { + ASSERT_VALID_CODE_POINTER(m_value); + } + + void* executableAddress() const { + return m_value; + } +#if WTF_CPU_ARM_THUMB2 + // To use this pointer as a data address remove the decoration. + void* dataLocation() const { ASSERT_VALID_CODE_POINTER(m_value); return reinterpret_cast(m_value) - 1; } +#else + void* dataLocation() const { ASSERT_VALID_CODE_POINTER(m_value); return m_value; } +#endif + + bool operator!() + { + return !m_value; + } + + ptrdiff_t operator -(const MacroAssemblerCodePtr &other) const + { + JS_ASSERT(m_value); + return reinterpret_cast(m_value) - + reinterpret_cast(other.m_value); + } + +private: + void* m_value; +}; + +// MacroAssemblerCodeRef: +// +// A reference to a section of JIT generated code. A CodeRef consists of a +// pointer to the code, and a ref pointer to the pool from within which it +// was allocated. +class MacroAssemblerCodeRef { +public: + MacroAssemblerCodeRef() + : m_size(0) + { + } + + MacroAssemblerCodeRef(void* code, ExecutablePool* executablePool, size_t size) + : m_code(code) + , m_executablePool(executablePool) + , m_size(size) + { + } + + MacroAssemblerCodePtr m_code; + ExecutablePool* m_executablePool; + size_t m_size; +}; + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) + +#endif // MacroAssemblerCodeRef_h diff --git a/js/src/assembler/assembler/MacroAssemblerX86.h b/js/src/assembler/assembler/MacroAssemblerX86.h new file mode 100644 index 0000000..ee61b89 --- /dev/null +++ b/js/src/assembler/assembler/MacroAssemblerX86.h @@ -0,0 +1,263 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MacroAssemblerX86_h +#define MacroAssemblerX86_h + +#include "assembler/wtf/Platform.h" + +#if ENABLE_ASSEMBLER && WTF_CPU_X86 + +#include "MacroAssemblerX86Common.h" + +namespace JSC { + +class MacroAssemblerX86 : public MacroAssemblerX86Common { +public: + MacroAssemblerX86() + : m_isSSE2Present(isSSE2Present()) + { + } + + static const Scale ScalePtr = TimesFour; + static const unsigned int TotalRegisters = 8; + + using MacroAssemblerX86Common::add32; + using MacroAssemblerX86Common::and32; + using MacroAssemblerX86Common::sub32; + using MacroAssemblerX86Common::or32; + using MacroAssemblerX86Common::load32; + using MacroAssemblerX86Common::store32; + using MacroAssemblerX86Common::branch32; + using MacroAssemblerX86Common::call; + using MacroAssemblerX86Common::loadDouble; + using MacroAssemblerX86Common::storeDouble; + using MacroAssemblerX86Common::convertInt32ToDouble; + + void add32(Imm32 imm, RegisterID src, RegisterID dest) + { + m_assembler.leal_mr(imm.m_value, src, dest); + } + + void lea(Address address, RegisterID dest) + { + m_assembler.leal_mr(address.offset, address.base, dest); + } + + void lea(BaseIndex address, RegisterID dest) + { + m_assembler.leal_mr(address.offset, address.base, address.index, address.scale, dest); + } + + void add32(Imm32 imm, AbsoluteAddress address) + { + m_assembler.addl_im(imm.m_value, address.m_ptr); + } + + void addWithCarry32(Imm32 imm, AbsoluteAddress address) + { + m_assembler.adcl_im(imm.m_value, address.m_ptr); + } + + void and32(Imm32 imm, AbsoluteAddress address) + { + m_assembler.andl_im(imm.m_value, address.m_ptr); + } + + void or32(Imm32 imm, AbsoluteAddress address) + { + m_assembler.orl_im(imm.m_value, address.m_ptr); + } + + void sub32(Imm32 imm, AbsoluteAddress address) + { + m_assembler.subl_im(imm.m_value, address.m_ptr); + } + + void load32(void* address, RegisterID dest) + { + m_assembler.movl_mr(address, dest); + } + + void storeDouble(ImmDouble imm, Address address) + { + store32(Imm32(imm.u.s.lsb), address); + store32(Imm32(imm.u.s.msb), Address(address.base, address.offset + 4)); + } + + void storeDouble(ImmDouble imm, BaseIndex address) + { + store32(Imm32(imm.u.s.lsb), address); + store32(Imm32(imm.u.s.msb), + BaseIndex(address.base, address.index, address.scale, address.offset + 4)); + } + + DataLabelPtr loadDouble(const void* address, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.movsd_mr(address, dest); + return DataLabelPtr(this); + } + + void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) + { + m_assembler.cvtsi2sd_mr(src.m_ptr, dest); + } + + void convertUInt32ToDouble(RegisterID srcDest, FPRegisterID dest) + { + // Trick is from nanojit/Nativei386.cpp, asm_ui2d. + static const double NegativeOne = 2147483648.0; + + // src is [0, 2^32-1] + sub32(Imm32(0x80000000), srcDest); + + // Now src is [-2^31, 2^31-1] - int range, but not the same value. + zeroDouble(dest); + convertInt32ToDouble(srcDest, dest); + + // dest is now a double with the int range. + // correct the double value by adding (0x80000000). + move(ImmPtr(&NegativeOne), srcDest); + addDouble(Address(srcDest), dest); + } + + void store32(Imm32 imm, void* address) + { + m_assembler.movl_i32m(imm.m_value, address); + } + + void store32(RegisterID src, void* address) + { + m_assembler.movl_rm(src, address); + } + + Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) + { + m_assembler.cmpl_rm(right, left.m_ptr); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) + { + m_assembler.cmpl_im(right.m_value, left.m_ptr); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Call call() + { + return Call(m_assembler.call(), Call::Linkable); + } + + Call tailRecursiveCall() + { + return Call::fromTailJump(jump()); + } + + Call makeTailRecursiveCall(Jump oldJump) + { + return Call::fromTailJump(oldJump); + } + + + DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest) + { + m_assembler.movl_i32r(initialValue.asIntptr(), dest); + return DataLabelPtr(this); + } + + Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) + { + m_assembler.cmpl_ir_force32(initialRightValue.asIntptr(), left); + dataLabel = DataLabelPtr(this); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) + { + m_assembler.cmpl_im_force32(initialRightValue.asIntptr(), left.offset, left.base); + dataLabel = DataLabelPtr(this); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) + { + m_assembler.movl_i32m(initialValue.asIntptr(), address.offset, address.base); + return DataLabelPtr(this); + } + + Label loadPtrWithPatchToLEA(Address address, RegisterID dest) + { + Label label(this); + load32(address, dest); + return label; + } + + void pushAllRegs() + { + m_assembler.pusha(); + } + + void popAllRegs() + { + m_assembler.popa(); + } + + bool supportsFloatingPoint() const { return m_isSSE2Present; } + // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate() + bool supportsFloatingPointTruncate() const { return m_isSSE2Present; } + bool supportsFloatingPointSqrt() const { return m_isSSE2Present; } + +private: + const bool m_isSSE2Present; + + friend class LinkBuffer; + friend class RepatchBuffer; + + static void linkCall(void* code, Call call, FunctionPtr function) + { + X86Assembler::linkCall(code, call.m_jmp, function.value()); + } + + static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) + { + X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); + } + + static void repatchCall(CodeLocationCall call, FunctionPtr destination) + { + X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); + } +}; + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) + +#endif // MacroAssemblerX86_h diff --git a/js/src/assembler/assembler/MacroAssemblerX86Common.cpp b/js/src/assembler/assembler/MacroAssemblerX86Common.cpp new file mode 100644 index 0000000..1477815 --- /dev/null +++ b/js/src/assembler/assembler/MacroAssemblerX86Common.cpp @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation + * + * Contributor(s): + * Alex Miller + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "assembler/wtf/Platform.h" + +/* SSE checks only make sense on Intel platforms. */ +#if WTF_CPU_X86 || WTF_CPU_X86_64 + +#include "MacroAssemblerX86Common.h" + +using namespace JSC; +MacroAssemblerX86Common::SSECheckState MacroAssemblerX86Common::s_sseCheckState = NotCheckedSSE; + +#endif /* WTF_CPU_X86 || WTF_CPU_X86_64 */ + diff --git a/js/src/assembler/assembler/MacroAssemblerX86Common.h b/js/src/assembler/assembler/MacroAssemblerX86Common.h new file mode 100644 index 0000000..d70ba3a --- /dev/null +++ b/js/src/assembler/assembler/MacroAssemblerX86Common.h @@ -0,0 +1,1464 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MacroAssemblerX86Common_h +#define MacroAssemblerX86Common_h + +#include "assembler/wtf/Platform.h" + +#if ENABLE_ASSEMBLER + +#include "X86Assembler.h" +#include "AbstractMacroAssembler.h" + +#if WTF_COMPILER_MSVC +#if WTF_CPU_X86_64 +/* for __cpuid */ +#include +#endif +#endif + +namespace JSC { + +class MacroAssemblerX86Common : public AbstractMacroAssembler { + static const int DoubleConditionBitInvert = 0x10; + static const int DoubleConditionBitSpecial = 0x20; + static const int DoubleConditionBits = DoubleConditionBitInvert | DoubleConditionBitSpecial; + +protected: +#if WTF_CPU_X86_64 + static const X86Registers::RegisterID scratchRegister = X86Registers::r11; +#endif + +public: + + enum Condition { + Equal = X86Assembler::ConditionE, + NotEqual = X86Assembler::ConditionNE, + Above = X86Assembler::ConditionA, + AboveOrEqual = X86Assembler::ConditionAE, + Below = X86Assembler::ConditionB, + BelowOrEqual = X86Assembler::ConditionBE, + GreaterThan = X86Assembler::ConditionG, + GreaterThanOrEqual = X86Assembler::ConditionGE, + LessThan = X86Assembler::ConditionL, + LessThanOrEqual = X86Assembler::ConditionLE, + Overflow = X86Assembler::ConditionO, + Signed = X86Assembler::ConditionS, + Zero = X86Assembler::ConditionE, + NonZero = X86Assembler::ConditionNE + }; + + enum DoubleCondition { + // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. + DoubleEqual = X86Assembler::ConditionE | DoubleConditionBitSpecial, + DoubleNotEqual = X86Assembler::ConditionNE, + DoubleGreaterThan = X86Assembler::ConditionA, + DoubleGreaterThanOrEqual = X86Assembler::ConditionAE, + DoubleLessThan = X86Assembler::ConditionA | DoubleConditionBitInvert, + DoubleLessThanOrEqual = X86Assembler::ConditionAE | DoubleConditionBitInvert, + // If either operand is NaN, these conditions always evaluate to true. + DoubleEqualOrUnordered = X86Assembler::ConditionE, + DoubleNotEqualOrUnordered = X86Assembler::ConditionNE | DoubleConditionBitSpecial, + DoubleGreaterThanOrUnordered = X86Assembler::ConditionB | DoubleConditionBitInvert, + DoubleGreaterThanOrEqualOrUnordered = X86Assembler::ConditionBE | DoubleConditionBitInvert, + DoubleLessThanOrUnordered = X86Assembler::ConditionB, + DoubleLessThanOrEqualOrUnordered = X86Assembler::ConditionBE + }; + COMPILE_ASSERT( + !((X86Assembler::ConditionE | X86Assembler::ConditionNE | X86Assembler::ConditionA | X86Assembler::ConditionAE | X86Assembler::ConditionB | X86Assembler::ConditionBE) & DoubleConditionBits), + DoubleConditionBits_should_not_interfere_with_X86Assembler_Condition_codes); + + static const RegisterID stackPointerRegister = X86Registers::esp; + + static inline bool CanUse8Bit(RegisterID reg) { + return !!((1 << reg) & ~((1 << X86Registers::esp) | + (1 << X86Registers::edi) | + (1 << X86Registers::esi) | + (1 << X86Registers::ebp))); + } + + // Integer arithmetic operations: + // + // Operations are typically two operand - operation(source, srcDst) + // For many operations the source may be an Imm32, the srcDst operand + // may often be a memory location (explictly described using an Address + // object). + + void add32(RegisterID src, RegisterID dest) + { + m_assembler.addl_rr(src, dest); + } + + void add32(Imm32 imm, Address address) + { + m_assembler.addl_im(imm.m_value, address.offset, address.base); + } + + void add32(Imm32 imm, RegisterID dest) + { + m_assembler.addl_ir(imm.m_value, dest); + } + + void add32(Address src, RegisterID dest) + { + m_assembler.addl_mr(src.offset, src.base, dest); + } + + void add32(RegisterID src, Address dest) + { + m_assembler.addl_rm(src, dest.offset, dest.base); + } + + void and32(RegisterID src, RegisterID dest) + { + m_assembler.andl_rr(src, dest); + } + + void and32(Imm32 imm, RegisterID dest) + { + m_assembler.andl_ir(imm.m_value, dest); + } + + void and32(RegisterID src, Address dest) + { + m_assembler.andl_rm(src, dest.offset, dest.base); + } + + void and32(Address src, RegisterID dest) + { + m_assembler.andl_mr(src.offset, src.base, dest); + } + + void and32(Imm32 imm, Address address) + { + m_assembler.andl_im(imm.m_value, address.offset, address.base); + } + + void lshift32(Imm32 imm, RegisterID dest) + { + m_assembler.shll_i8r(imm.m_value, dest); + } + + void lshift32(RegisterID shift_amount, RegisterID dest) + { + // On x86 we can only shift by ecx; if asked to shift by another register we'll + // need rejig the shift amount into ecx first, and restore the registers afterwards. + if (shift_amount != X86Registers::ecx) { + swap(shift_amount, X86Registers::ecx); + + // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx" + if (dest == shift_amount) + m_assembler.shll_CLr(X86Registers::ecx); + // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx" + else if (dest == X86Registers::ecx) + m_assembler.shll_CLr(shift_amount); + // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx" + else + m_assembler.shll_CLr(dest); + + swap(shift_amount, X86Registers::ecx); + } else + m_assembler.shll_CLr(dest); + } + + void mul32(RegisterID src, RegisterID dest) + { + m_assembler.imull_rr(src, dest); + } + + void mul32(Address src, RegisterID dest) + { + m_assembler.imull_mr(src.offset, src.base, dest); + } + + void mul32(Imm32 imm, RegisterID src, RegisterID dest) + { + m_assembler.imull_i32r(src, imm.m_value, dest); + } + + void neg32(RegisterID srcDest) + { + m_assembler.negl_r(srcDest); + } + + void neg32(Address srcDest) + { + m_assembler.negl_m(srcDest.offset, srcDest.base); + } + + void not32(RegisterID srcDest) + { + m_assembler.notl_r(srcDest); + } + + void not32(Address srcDest) + { + m_assembler.notl_m(srcDest.offset, srcDest.base); + } + + void or32(RegisterID src, RegisterID dest) + { + m_assembler.orl_rr(src, dest); + } + + void or32(Imm32 imm, RegisterID dest) + { + m_assembler.orl_ir(imm.m_value, dest); + } + + void or32(RegisterID src, Address dest) + { + m_assembler.orl_rm(src, dest.offset, dest.base); + } + + void or32(Address src, RegisterID dest) + { + m_assembler.orl_mr(src.offset, src.base, dest); + } + + void or32(Imm32 imm, Address address) + { + m_assembler.orl_im(imm.m_value, address.offset, address.base); + } + + void rshift32(RegisterID shift_amount, RegisterID dest) + { + // On x86 we can only shift by ecx; if asked to shift by another register we'll + // need rejig the shift amount into ecx first, and restore the registers afterwards. + if (shift_amount != X86Registers::ecx) { + swap(shift_amount, X86Registers::ecx); + + // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx" + if (dest == shift_amount) + m_assembler.sarl_CLr(X86Registers::ecx); + // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx" + else if (dest == X86Registers::ecx) + m_assembler.sarl_CLr(shift_amount); + // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx" + else + m_assembler.sarl_CLr(dest); + + swap(shift_amount, X86Registers::ecx); + } else + m_assembler.sarl_CLr(dest); + } + + void rshift32(Imm32 imm, RegisterID dest) + { + m_assembler.sarl_i8r(imm.m_value, dest); + } + + void urshift32(RegisterID shift_amount, RegisterID dest) + { + // On x86 we can only shift by ecx; if asked to shift by another register we'll + // need rejig the shift amount into ecx first, and restore the registers afterwards. + if (shift_amount != X86Registers::ecx) { + swap(shift_amount, X86Registers::ecx); + + // E.g. transform "shrl %eax, %eax" -> "xchgl %eax, %ecx; shrl %ecx, %ecx; xchgl %eax, %ecx" + if (dest == shift_amount) + m_assembler.shrl_CLr(X86Registers::ecx); + // E.g. transform "shrl %eax, %ecx" -> "xchgl %eax, %ecx; shrl %ecx, %eax; xchgl %eax, %ecx" + else if (dest == X86Registers::ecx) + m_assembler.shrl_CLr(shift_amount); + // E.g. transform "shrl %eax, %ebx" -> "xchgl %eax, %ecx; shrl %ecx, %ebx; xchgl %eax, %ecx" + else + m_assembler.shrl_CLr(dest); + + swap(shift_amount, X86Registers::ecx); + } else + m_assembler.shrl_CLr(dest); + } + + void urshift32(Imm32 imm, RegisterID dest) + { + m_assembler.shrl_i8r(imm.m_value, dest); + } + + void sub32(RegisterID src, RegisterID dest) + { + m_assembler.subl_rr(src, dest); + } + + void sub32(Imm32 imm, RegisterID dest) + { + m_assembler.subl_ir(imm.m_value, dest); + } + + void sub32(Imm32 imm, Address address) + { + m_assembler.subl_im(imm.m_value, address.offset, address.base); + } + + void sub32(Address src, RegisterID dest) + { + m_assembler.subl_mr(src.offset, src.base, dest); + } + + void sub32(RegisterID src, Address dest) + { + m_assembler.subl_rm(src, dest.offset, dest.base); + } + + + void xor32(RegisterID src, RegisterID dest) + { + m_assembler.xorl_rr(src, dest); + } + + void xor32(Imm32 imm, Address dest) + { + m_assembler.xorl_im(imm.m_value, dest.offset, dest.base); + } + + void xor32(Imm32 imm, RegisterID dest) + { + m_assembler.xorl_ir(imm.m_value, dest); + } + + void xor32(RegisterID src, Address dest) + { + m_assembler.xorl_rm(src, dest.offset, dest.base); + } + + void xor32(Address src, RegisterID dest) + { + m_assembler.xorl_mr(src.offset, src.base, dest); + } + + void sqrtDouble(FPRegisterID src, FPRegisterID dst) + { + m_assembler.sqrtsd_rr(src, dst); + } + + // Memory access operations: + // + // Loads are of the form load(address, destination) and stores of the form + // store(source, address). The source for a store may be an Imm32. Address + // operand objects to loads and store will be implicitly constructed if a + // register is passed. + + void load32(ImplicitAddress address, RegisterID dest) + { + m_assembler.movl_mr(address.offset, address.base, dest); + } + + void load32(BaseIndex address, RegisterID dest) + { + m_assembler.movl_mr(address.offset, address.base, address.index, address.scale, dest); + } + + void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) + { + load32(address, dest); + } + + DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) + { + m_assembler.movl_mr_disp32(address.offset, address.base, dest); + return DataLabel32(this); + } + + void store8(RegisterID src, Address address) + { + m_assembler.movb_rm(src, address.offset, address.base); + } + + void store8(RegisterID src, BaseIndex address) + { + m_assembler.movb_rm(src, address.offset, address.base, address.index, address.scale); + } + + void store16(RegisterID src, Address address) + { + m_assembler.movw_rm(src, address.offset, address.base); + } + + void store16(RegisterID src, BaseIndex address) + { + m_assembler.movw_rm(src, address.offset, address.base, address.index, address.scale); + } + + void load8ZeroExtend(BaseIndex address, RegisterID dest) + { + m_assembler.movzbl_mr(address.offset, address.base, address.index, address.scale, dest); + } + + void load8ZeroExtend(Address address, RegisterID dest) + { + m_assembler.movzbl_mr(address.offset, address.base, dest); + } + + void load8SignExtend(BaseIndex address, RegisterID dest) + { + m_assembler.movxbl_mr(address.offset, address.base, address.index, address.scale, dest); + } + + void load8SignExtend(Address address, RegisterID dest) + { + m_assembler.movxbl_mr(address.offset, address.base, dest); + } + + void load16SignExtend(BaseIndex address, RegisterID dest) + { + m_assembler.movxwl_mr(address.offset, address.base, address.index, address.scale, dest); + } + + void load16SignExtend(Address address, RegisterID dest) + { + m_assembler.movxwl_mr(address.offset, address.base, dest); + } + + void load16(BaseIndex address, RegisterID dest) + { + m_assembler.movzwl_mr(address.offset, address.base, address.index, address.scale, dest); + } + + void load16(Address address, RegisterID dest) + { + m_assembler.movzwl_mr(address.offset, address.base, dest); + } + + DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) + { + m_assembler.movl_rm_disp32(src, address.offset, address.base); + return DataLabel32(this); + } + + void store32(RegisterID src, ImplicitAddress address) + { + m_assembler.movl_rm(src, address.offset, address.base); + } + + void store32(RegisterID src, BaseIndex address) + { + m_assembler.movl_rm(src, address.offset, address.base, address.index, address.scale); + } + + void store32(Imm32 imm, BaseIndex address) + { + m_assembler.movl_i32m(imm.m_value, address.offset, address.base, address.index, address.scale); + } + + void store16(Imm32 imm, BaseIndex address) + { + m_assembler.movw_i16m(imm.m_value, address.offset, address.base, address.index, address.scale); + } + + void store8(Imm32 imm, BaseIndex address) + { + m_assembler.movb_i8m(imm.m_value, address.offset, address.base, address.index, address.scale); + } + + void store32(Imm32 imm, ImplicitAddress address) + { + m_assembler.movl_i32m(imm.m_value, address.offset, address.base); + } + + void store16(Imm32 imm, ImplicitAddress address) + { + m_assembler.movw_i16m(imm.m_value, address.offset, address.base); + } + + void store8(Imm32 imm, ImplicitAddress address) + { + m_assembler.movb_i8m(imm.m_value, address.offset, address.base); + } + + + // Floating-point operation: + // + // Presently only supports SSE, not x87 floating point. + + void moveDouble(FPRegisterID src, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.movsd_rr(src, dest); + } + + void loadFloat(ImplicitAddress address, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.movss_mr(address.offset, address.base, dest); + m_assembler.cvtss2sd_rr(dest, dest); + } + + void loadFloat(BaseIndex address, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.movss_mr(address.offset, address.base, address.index, address.scale, dest); + m_assembler.cvtss2sd_rr(dest, dest); + } + + void convertDoubleToFloat(FPRegisterID src, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.cvtsd2ss_rr(src, dest); + } + + void loadDouble(ImplicitAddress address, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.movsd_mr(address.offset, address.base, dest); + } + + void loadDouble(BaseIndex address, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.movsd_mr(address.offset, address.base, address.index, address.scale, dest); + } + + void storeFloat(ImmDouble imm, Address address) + { + union { + float f; + uint32 u32; + } u; + u.f = imm.u.d; + store32(Imm32(u.u32), address); + } + + void storeFloat(ImmDouble imm, BaseIndex address) + { + union { + float f; + uint32 u32; + } u; + u.f = imm.u.d; + store32(Imm32(u.u32), address); + } + + void storeDouble(FPRegisterID src, ImplicitAddress address) + { + ASSERT(isSSE2Present()); + m_assembler.movsd_rm(src, address.offset, address.base); + } + + void storeFloat(FPRegisterID src, ImplicitAddress address) + { + ASSERT(isSSE2Present()); + m_assembler.movss_rm(src, address.offset, address.base); + } + + void storeDouble(FPRegisterID src, BaseIndex address) + { + ASSERT(isSSE2Present()); + m_assembler.movsd_rm(src, address.offset, address.base, address.index, address.scale); + } + + void storeFloat(FPRegisterID src, BaseIndex address) + { + ASSERT(isSSE2Present()); + m_assembler.movss_rm(src, address.offset, address.base, address.index, address.scale); + } + + void addDouble(FPRegisterID src, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.addsd_rr(src, dest); + } + + void addDouble(Address src, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.addsd_mr(src.offset, src.base, dest); + } + + void divDouble(FPRegisterID src, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.divsd_rr(src, dest); + } + + void divDouble(Address src, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.divsd_mr(src.offset, src.base, dest); + } + + void subDouble(FPRegisterID src, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.subsd_rr(src, dest); + } + + void subDouble(Address src, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.subsd_mr(src.offset, src.base, dest); + } + + void mulDouble(FPRegisterID src, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.mulsd_rr(src, dest); + } + + void mulDouble(Address src, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.mulsd_mr(src.offset, src.base, dest); + } + + void xorDouble(FPRegisterID src, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.xorpd_rr(src, dest); + } + + void convertInt32ToDouble(RegisterID src, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.cvtsi2sd_rr(src, dest); + } + + void convertInt32ToDouble(Address src, FPRegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.cvtsi2sd_mr(src.offset, src.base, dest); + } + + Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) + { + ASSERT(isSSE2Present()); + + if (cond & DoubleConditionBitInvert) + m_assembler.ucomisd_rr(left, right); + else + m_assembler.ucomisd_rr(right, left); + + if (cond == DoubleEqual) { + Jump isUnordered(m_assembler.jp()); + Jump result = Jump(m_assembler.je()); + isUnordered.link(this); + return result; + } else if (cond == DoubleNotEqualOrUnordered) { + Jump isUnordered(m_assembler.jp()); + Jump isEqual(m_assembler.je()); + isUnordered.link(this); + Jump result = jump(); + isEqual.link(this); + return result; + } + + ASSERT(!(cond & DoubleConditionBitSpecial)); + return Jump(m_assembler.jCC(static_cast(cond & ~DoubleConditionBits))); + } + + // Truncates 'src' to an integer, and places the resulting 'dest'. + // If the result is not representable as a 32 bit value, branch. + // May also branch for some values that are representable in 32 bits + // (specifically, in this case, INT_MIN). + Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest) + { + ASSERT(isSSE2Present()); + m_assembler.cvttsd2si_rr(src, dest); + return branch32(Equal, dest, Imm32(0x80000000)); + } + + // Convert 'src' to an integer, and places the resulting 'dest'. + // If the result is not representable as a 32 bit value, branch. + // May also branch for some values that are representable in 32 bits + // (specifically, in this case, 0). + void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) + { + ASSERT(isSSE2Present()); + m_assembler.cvttsd2si_rr(src, dest); + + // If the result is zero, it might have been -0.0, and the double comparison won't catch this! + failureCases.append(branchTest32(Zero, dest)); + + // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. + convertInt32ToDouble(dest, fpTemp); + m_assembler.ucomisd_rr(fpTemp, src); + failureCases.append(m_assembler.jp()); + failureCases.append(m_assembler.jne()); + } + + void zeroDouble(FPRegisterID srcDest) + { + ASSERT(isSSE2Present()); + m_assembler.xorpd_rr(srcDest, srcDest); + } + + + // Stack manipulation operations: + // + // The ABI is assumed to provide a stack abstraction to memory, + // containing machine word sized units of data. Push and pop + // operations add and remove a single register sized unit of data + // to or from the stack. Peek and poke operations read or write + // values on the stack, without moving the current stack position. + + void pop(RegisterID dest) + { + m_assembler.pop_r(dest); + } + + void push(RegisterID src) + { + m_assembler.push_r(src); + } + + void push(Address address) + { + m_assembler.push_m(address.offset, address.base); + } + + void push(Imm32 imm) + { + m_assembler.push_i32(imm.m_value); + } + + + // Register move operations: + // + // Move values in registers. + + void move(Imm32 imm, RegisterID dest) + { + // Note: on 64-bit the Imm32 value is zero extended into the register, it + // may be useful to have a separate version that sign extends the value? + if (!imm.m_value) + m_assembler.xorl_rr(dest, dest); + else + m_assembler.movl_i32r(imm.m_value, dest); + } + +#if WTF_CPU_X86_64 + void move(RegisterID src, RegisterID dest) + { + // Note: on 64-bit this is is a full register move; perhaps it would be + // useful to have separate move32 & movePtr, with move32 zero extending? + if (src != dest) + m_assembler.movq_rr(src, dest); + } + + void move(ImmPtr imm, RegisterID dest) + { + m_assembler.movq_i64r(imm.asIntptr(), dest); + } + + void swap(RegisterID reg1, RegisterID reg2) + { + // XCHG is extremely slow. Don't use XCHG. + if (reg1 != reg2) { + m_assembler.movq_rr(reg1, scratchRegister); + m_assembler.movq_rr(reg2, reg1); + m_assembler.movq_rr(scratchRegister, reg2); + } + } + + void signExtend32ToPtr(RegisterID src, RegisterID dest) + { + m_assembler.movsxd_rr(src, dest); + } + + void zeroExtend32ToPtr(RegisterID src, RegisterID dest) + { + m_assembler.movl_rr(src, dest); + } +#else + void move(RegisterID src, RegisterID dest) + { + if (src != dest) + m_assembler.movl_rr(src, dest); + } + + void move(ImmPtr imm, RegisterID dest) + { + m_assembler.movl_i32r(imm.asIntptr(), dest); + } + + void swap(RegisterID reg1, RegisterID reg2) + { + if (reg1 != reg2) + m_assembler.xchgl_rr(reg1, reg2); + } + + void signExtend32ToPtr(RegisterID src, RegisterID dest) + { + move(src, dest); + } + + void zeroExtend32ToPtr(RegisterID src, RegisterID dest) + { + move(src, dest); + } +#endif + + + // Forwards / external control flow operations: + // + // This set of jump and conditional branch operations return a Jump + // object which may linked at a later point, allow forwards jump, + // or jumps that will require external linkage (after the code has been + // relocated). + // + // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge + // respecitvely, for unsigned comparisons the names b, a, be, and ae are + // used (representing the names 'below' and 'above'). + // + // Operands to the comparision are provided in the expected order, e.g. + // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when + // treated as a signed 32bit value, is less than or equal to 5. + // + // jz and jnz test whether the first operand is equal to zero, and take + // an optional second operand of a mask under which to perform the test. + +public: + Jump branch8(Condition cond, Address left, Imm32 right) + { + m_assembler.cmpb_im(right.m_value, left.offset, left.base); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branch32(Condition cond, RegisterID left, RegisterID right) + { + m_assembler.cmpl_rr(right, left); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branch32(Condition cond, RegisterID left, Imm32 right) + { + if (((cond == Equal) || (cond == NotEqual)) && !right.m_value) + m_assembler.testl_rr(left, left); + else + m_assembler.cmpl_ir(right.m_value, left); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + // Branch based on a 32-bit comparison, forcing the size of the + // immediate operand to 32 bits in the native code stream to ensure that + // the length of code emitted by this instruction is consistent. + Jump branch32FixedLength(Condition cond, RegisterID left, Imm32 right) + { + m_assembler.cmpl_ir_force32(right.m_value, left); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + // Branch and record a label after the comparison. + Jump branch32WithPatch(Condition cond, RegisterID left, Imm32 right, DataLabel32 &dataLabel) + { + // Always use cmpl, since the value is to be patched. + m_assembler.cmpl_ir_force32(right.m_value, left); + dataLabel = DataLabel32(this); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branch32WithPatch(Condition cond, Address left, Imm32 right, DataLabel32 &dataLabel) + { + m_assembler.cmpl_im_force32(right.m_value, left.offset, left.base); + dataLabel = DataLabel32(this); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branch32(Condition cond, RegisterID left, Address right) + { + m_assembler.cmpl_mr(right.offset, right.base, left); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branch32(Condition cond, Address left, RegisterID right) + { + m_assembler.cmpl_rm(right, left.offset, left.base); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branch32(Condition cond, Address left, Imm32 right) + { + m_assembler.cmpl_im(right.m_value, left.offset, left.base); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branch32(Condition cond, BaseIndex left, Imm32 right) + { + m_assembler.cmpl_im(right.m_value, left.offset, left.base, left.index, left.scale); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) + { + return branch32(cond, left, right); + } + + Jump branch16(Condition cond, BaseIndex left, RegisterID right) + { + m_assembler.cmpw_rm(right, left.offset, left.base, left.index, left.scale); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branch16(Condition cond, BaseIndex left, Imm32 right) + { + ASSERT(!(right.m_value & 0xFFFF0000)); + + m_assembler.cmpw_im(right.m_value, left.offset, left.base, left.index, left.scale); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) + { + ASSERT((cond == Zero) || (cond == NonZero)); + m_assembler.testl_rr(reg, mask); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + // if we are only interested in the low seven bits, this can be tested with a testb + if (mask.m_value == -1) + m_assembler.testl_rr(reg, reg); + else if (CanUse8Bit(reg) && (mask.m_value & ~0x7f) == 0) + m_assembler.testb_i8r(mask.m_value, reg); + else + m_assembler.testl_i32r(mask.m_value, reg); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + if (mask.m_value == -1) + m_assembler.cmpl_im(0, address.offset, address.base); + else + m_assembler.testl_i32m(mask.m_value, address.offset, address.base); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + if (mask.m_value == -1) + m_assembler.cmpl_im(0, address.offset, address.base, address.index, address.scale); + else + m_assembler.testl_i32m(mask.m_value, address.offset, address.base, address.index, address.scale); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + if (mask.m_value == -1) + m_assembler.cmpb_im(0, address.offset, address.base); + else + m_assembler.testb_im(mask.m_value, address.offset, address.base); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchTest8(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + if (mask.m_value == -1) + m_assembler.cmpb_im(0, address.offset, address.base, address.index, address.scale); + else + m_assembler.testb_im(mask.m_value, address.offset, address.base, address.index, address.scale); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump jump() + { + return Jump(m_assembler.jmp()); + } + + void jump(RegisterID target) + { + m_assembler.jmp_r(target); + } + + // Address is a memory location containing the address to jump to + void jump(Address address) + { + m_assembler.jmp_m(address.offset, address.base); + } + + void jump(BaseIndex address) + { + m_assembler.jmp_m(address.offset, address.base, address.index, address.scale); + } + + // Arithmetic control flow operations: + // + // This set of conditional branch operations branch based + // on the result of an arithmetic operation. The operation + // is performed as normal, storing the result. + // + // * jz operations branch if the result is zero. + // * jo operations branch if the (signed) arithmetic + // operation caused an overflow to occur. + + Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + add32(src, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + add32(imm, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchAdd32(Condition cond, Imm32 src, Address dest) + { + ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); + add32(src, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchAdd32(Condition cond, RegisterID src, Address dest) + { + ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); + add32(src, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchAdd32(Condition cond, Address src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); + add32(src, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) + { + ASSERT(cond == Overflow); + mul32(src, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchMul32(Condition cond, Address src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); + mul32(src, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) + { + ASSERT(cond == Overflow); + mul32(imm, src, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + sub32(src, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + sub32(imm, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchSub32(Condition cond, Imm32 imm, Address dest) + { + ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); + sub32(imm, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchSub32(Condition cond, RegisterID src, Address dest) + { + ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); + sub32(src, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchSub32(Condition cond, Address src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); + sub32(src, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchNeg32(Condition cond, RegisterID srcDest) + { + ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); + neg32(srcDest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) + { + ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); + or32(src, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + + // Miscellaneous operations: + + void breakpoint() + { + m_assembler.int3(); + } + + Call nearCall() + { + return Call(m_assembler.call(), Call::LinkableNear); + } + + Call call(RegisterID target) + { + return Call(m_assembler.call(target), Call::None); + } + + void call(Address address) + { + m_assembler.call_m(address.offset, address.base); + } + + void ret() + { + m_assembler.ret(); + } + + void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest) + { + m_assembler.cmpl_rr(right, left); + m_assembler.setCC_r(x86Condition(cond), dest); + } + + void set8(Condition cond, Address left, RegisterID right, RegisterID dest) + { + m_assembler.cmpl_mr(left.offset, left.base, right); + m_assembler.setCC_r(x86Condition(cond), dest); + } + + void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest) + { + if (((cond == Equal) || (cond == NotEqual)) && !right.m_value) + m_assembler.testl_rr(left, left); + else + m_assembler.cmpl_ir(right.m_value, left); + m_assembler.setCC_r(x86Condition(cond), dest); + } + + void set32(Condition cond, Address left, RegisterID right, RegisterID dest) + { + m_assembler.cmpl_rm(right, left.offset, left.base); + m_assembler.setCC_r(x86Condition(cond), dest); + m_assembler.movzbl_rr(dest, dest); + } + + void set32(Condition cond, RegisterID left, Address right, RegisterID dest) + { + m_assembler.cmpl_mr(right.offset, right.base, left); + m_assembler.setCC_r(x86Condition(cond), dest); + m_assembler.movzbl_rr(dest, dest); + } + + void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) + { + m_assembler.cmpl_rr(right, left); + m_assembler.setCC_r(x86Condition(cond), dest); + m_assembler.movzbl_rr(dest, dest); + } + + void set32(Condition cond, Address left, Imm32 right, RegisterID dest) + { + m_assembler.cmpl_im(right.m_value, left.offset, left.base); + m_assembler.setCC_r(x86Condition(cond), dest); + m_assembler.movzbl_rr(dest, dest); + } + + void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) + { + if (((cond == Equal) || (cond == NotEqual)) && !right.m_value) + m_assembler.testl_rr(left, left); + else + m_assembler.cmpl_ir(right.m_value, left); + m_assembler.setCC_r(x86Condition(cond), dest); + m_assembler.movzbl_rr(dest, dest); + } + + // FIXME: + // The mask should be optional... paerhaps the argument order should be + // dest-src, operations always have a dest? ... possibly not true, considering + // asm ops like test, or pseudo ops like pop(). + + void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest) + { + if (mask.m_value == -1) + m_assembler.cmpb_im(0, address.offset, address.base); + else + m_assembler.testb_im(mask.m_value, address.offset, address.base); + m_assembler.setCC_r(x86Condition(cond), dest); + m_assembler.movzbl_rr(dest, dest); + } + + void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest) + { + if (mask.m_value == -1) + m_assembler.cmpl_im(0, address.offset, address.base); + else + m_assembler.testl_i32m(mask.m_value, address.offset, address.base); + m_assembler.setCC_r(x86Condition(cond), dest); + m_assembler.movzbl_rr(dest, dest); + } + + // As the SSE's were introduced in order, the presence of a later SSE implies + // the presence of an earlier SSE. For example, SSE4_2 support implies SSE2 support. + enum SSECheckState { + NotCheckedSSE = 0, + NoSSE = 1, + HasSSE = 2, + HasSSE2 = 3, + HasSSE3 = 4, + HasSSSE3 = 5, + HasSSE4_1 = 6, + HasSSE4_2 = 7 + }; + + static SSECheckState getSSEState() + { + if (s_sseCheckState == NotCheckedSSE) { + MacroAssemblerX86Common::setSSECheckState(); + } + // Only check once. + ASSERT(s_sseCheckState != NotCheckedSSE); + + return s_sseCheckState; + } + +protected: + X86Assembler::Condition x86Condition(Condition cond) + { + return static_cast(cond); + } + +private: + friend class MacroAssemblerX86; + + static SSECheckState s_sseCheckState; + + static void setSSECheckState() + { + // Default the flags value to zero; if the compiler is + // not MSVC or GCC we will read this as SSE2 not present. + volatile int flags_edx = 0; + volatile int flags_ecx = 0; +#if WTF_COMPILER_MSVC +#if WTF_CPU_X86_64 + int cpuinfo[4]; + + __cpuid(cpuinfo, 1); + flags_ecx = cpuinfo[2]; + flags_edx = cpuinfo[3]; +#else + _asm { + mov eax, 1 // cpuid function 1 gives us the standard feature set + cpuid; + mov flags_ecx, ecx; + mov flags_edx, edx; + } +#endif +#elif WTF_COMPILER_GCC +#if WTF_CPU_X86_64 + asm ( + "movl $0x1, %%eax;" + "pushq %%rbx;" + "cpuid;" + "popq %%rbx;" + "movl %%ecx, %0;" + "movl %%edx, %1;" + : "=g" (flags_ecx), "=g" (flags_edx) + : + : "%eax", "%ecx", "%edx" + ); +#else + asm ( + "movl $0x1, %%eax;" + "pushl %%ebx;" + "cpuid;" + "popl %%ebx;" + "movl %%ecx, %0;" + "movl %%edx, %1;" + : "=g" (flags_ecx), "=g" (flags_edx) + : + : "%eax", "%ecx", "%edx" + ); +#endif +#elif WTF_COMPILER_SUNPRO +#if WTF_CPU_X86_64 + asm ( + "movl $0x1, %%eax;" + "pushq %%rbx;" + "cpuid;" + "popq %%rbx;" + "movl %%ecx, (%rsi);" + "movl %%edx, (%rdi);" + : + : "S" (&flags_ecx), "D" (&flags_edx) + : "%eax", "%ecx", "%edx" + ); +#else + asm ( + "movl $0x1, %eax;" + "pushl %ebx;" + "cpuid;" + "popl %ebx;" + "movl %ecx, (%esi);" + "movl %edx, (%edi);" + : + : "S" (&flags_ecx), "D" (&flags_edx) + : "%eax", "%ecx", "%edx" + ); +#endif +#endif + static const int SSEFeatureBit = 1 << 25; + static const int SSE2FeatureBit = 1 << 26; + static const int SSE3FeatureBit = 1 << 0; + static const int SSSE3FeatureBit = 1 << 9; + static const int SSE41FeatureBit = 1 << 19; + static const int SSE42FeatureBit = 1 << 20; + if (flags_ecx & SSE42FeatureBit) + s_sseCheckState = HasSSE4_2; + else if (flags_ecx & SSE41FeatureBit) + s_sseCheckState = HasSSE4_1; + else if (flags_ecx & SSSE3FeatureBit) + s_sseCheckState = HasSSSE3; + else if (flags_ecx & SSE3FeatureBit) + s_sseCheckState = HasSSE3; + else if (flags_edx & SSE2FeatureBit) + s_sseCheckState = HasSSE2; + else if (flags_edx & SSEFeatureBit) + s_sseCheckState = HasSSE; + else + s_sseCheckState = NoSSE; + } + +#if WTF_CPU_X86 +#if WTF_PLATFORM_MAC + + // All X86 Macs are guaranteed to support at least SSE2 + static bool isSSEPresent() + { + return true; + } + + static bool isSSE2Present() + { + return true; + } + +#else // PLATFORM(MAC) + + static bool isSSEPresent() + { + if (s_sseCheckState == NotCheckedSSE) { + setSSECheckState(); + } + // Only check once. + ASSERT(s_sseCheckState != NotCheckedSSE); + + return s_sseCheckState >= HasSSE; + } + + static bool isSSE2Present() + { + if (s_sseCheckState == NotCheckedSSE) { + setSSECheckState(); + } + // Only check once. + ASSERT(s_sseCheckState != NotCheckedSSE); + + return s_sseCheckState >= HasSSE2; + } + + +#endif // PLATFORM(MAC) +#elif !defined(NDEBUG) // CPU(X86) + + // On x86-64 we should never be checking for SSE2 in a non-debug build, + // but non debug add this method to keep the asserts above happy. + static bool isSSE2Present() + { + return true; + } + +#endif + static bool isSSE3Present() + { + if (s_sseCheckState == NotCheckedSSE) { + setSSECheckState(); + } + // Only check once. + ASSERT(s_sseCheckState != NotCheckedSSE); + + return s_sseCheckState >= HasSSE3; + } + + static bool isSSSE3Present() + { + if (s_sseCheckState == NotCheckedSSE) { + setSSECheckState(); + } + // Only check once. + ASSERT(s_sseCheckState != NotCheckedSSE); + + return s_sseCheckState >= HasSSSE3; + } + + static bool isSSE41Present() + { + if (s_sseCheckState == NotCheckedSSE) { + setSSECheckState(); + } + // Only check once. + ASSERT(s_sseCheckState != NotCheckedSSE); + + return s_sseCheckState >= HasSSE4_1; + } + + static bool isSSE42Present() + { + if (s_sseCheckState == NotCheckedSSE) { + setSSECheckState(); + } + // Only check once. + ASSERT(s_sseCheckState != NotCheckedSSE); + + return s_sseCheckState >= HasSSE4_2; + } +}; + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) + +#endif // MacroAssemblerX86Common_h diff --git a/js/src/assembler/assembler/MacroAssemblerX86_64.h b/js/src/assembler/assembler/MacroAssemblerX86_64.h new file mode 100644 index 0000000..7dadc6b --- /dev/null +++ b/js/src/assembler/assembler/MacroAssemblerX86_64.h @@ -0,0 +1,585 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MacroAssemblerX86_64_h +#define MacroAssemblerX86_64_h + +#include "assembler/wtf/Platform.h" + +#if ENABLE_ASSEMBLER && WTF_CPU_X86_64 + +#include "MacroAssemblerX86Common.h" + +#define REPTACH_OFFSET_CALL_R11 3 + +namespace JSC { + +class MacroAssemblerX86_64 : public MacroAssemblerX86Common { +protected: + static const intptr_t MinInt32 = 0xFFFFFFFF80000000; + static const intptr_t MaxInt32 = 0x000000007FFFFFFF; + +public: + static const Scale ScalePtr = TimesEight; + static const unsigned int TotalRegisters = 16; + + using MacroAssemblerX86Common::add32; + using MacroAssemblerX86Common::and32; + using MacroAssemblerX86Common::or32; + using MacroAssemblerX86Common::sub32; + using MacroAssemblerX86Common::load32; + using MacroAssemblerX86Common::store32; + using MacroAssemblerX86Common::call; + using MacroAssemblerX86Common::loadDouble; + using MacroAssemblerX86Common::storeDouble; + using MacroAssemblerX86Common::convertInt32ToDouble; + + void add32(Imm32 imm, AbsoluteAddress address) + { + move(ImmPtr(address.m_ptr), scratchRegister); + add32(imm, Address(scratchRegister)); + } + + void and32(Imm32 imm, AbsoluteAddress address) + { + move(ImmPtr(address.m_ptr), scratchRegister); + and32(imm, Address(scratchRegister)); + } + + void or32(Imm32 imm, AbsoluteAddress address) + { + move(ImmPtr(address.m_ptr), scratchRegister); + or32(imm, Address(scratchRegister)); + } + + void sub32(Imm32 imm, AbsoluteAddress address) + { + move(ImmPtr(address.m_ptr), scratchRegister); + sub32(imm, Address(scratchRegister)); + } + + void load32(void* address, RegisterID dest) + { + if (dest == X86Registers::eax) + m_assembler.movl_mEAX(address); + else { + move(ImmPtr(address), scratchRegister); + load32(ImplicitAddress(scratchRegister), dest); + } + } + + DataLabelPtr loadDouble(const void* address, FPRegisterID dest) + { + DataLabelPtr label = moveWithPatch(ImmPtr(address), scratchRegister); + loadDouble(scratchRegister, dest); + return label; + } + + void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) + { + move(Imm32(*static_cast(src.m_ptr)), scratchRegister); + m_assembler.cvtsi2sd_rr(scratchRegister, dest); + } + + void convertUInt32ToDouble(RegisterID srcDest, FPRegisterID dest) + { + zeroExtend32ToPtr(srcDest, srcDest); + zeroDouble(dest); // break dependency chains + m_assembler.cvtsq2sd_rr(srcDest, dest); + } + + void store32(Imm32 imm, void* address) + { + move(X86Registers::eax, scratchRegister); + move(imm, X86Registers::eax); + m_assembler.movl_EAXm(address); + move(scratchRegister, X86Registers::eax); + } + + Call call() + { + DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister); + Call result = Call(m_assembler.call(scratchRegister), Call::Linkable); + ASSERT(differenceBetween(label, result) == REPTACH_OFFSET_CALL_R11); + return result; + } + + Call tailRecursiveCall() + { + DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister); + Jump newJump = Jump(m_assembler.jmp_r(scratchRegister)); + ASSERT(differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11); + return Call::fromTailJump(newJump); + } + + Call makeTailRecursiveCall(Jump oldJump) + { + oldJump.link(this); + DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister); + Jump newJump = Jump(m_assembler.jmp_r(scratchRegister)); + ASSERT(differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11); + return Call::fromTailJump(newJump); + } + + + void addPtr(RegisterID src, RegisterID dest) + { + m_assembler.addq_rr(src, dest); + } + + void lea(BaseIndex address, RegisterID dest) + { + m_assembler.leaq_mr(address.offset, address.base, address.index, address.scale, dest); + } + + void lea(Address address, RegisterID dest) + { + m_assembler.leaq_mr(address.offset, address.base, dest); + } + + void addPtr(Imm32 imm, RegisterID srcDest) + { + m_assembler.addq_ir(imm.m_value, srcDest); + } + + void addPtr(ImmPtr imm, RegisterID dest) + { + move(imm, scratchRegister); + m_assembler.addq_rr(scratchRegister, dest); + } + + void addPtr(Imm32 imm, RegisterID src, RegisterID dest) + { + m_assembler.leaq_mr(imm.m_value, src, dest); + } + + void addPtr(Imm32 imm, Address address) + { + m_assembler.addq_im(imm.m_value, address.offset, address.base); + } + + void addPtr(Imm32 imm, AbsoluteAddress address) + { + move(ImmPtr(address.m_ptr), scratchRegister); + addPtr(imm, Address(scratchRegister)); + } + + void andPtr(RegisterID src, RegisterID dest) + { + m_assembler.andq_rr(src, dest); + } + + void andPtr(Address src, RegisterID dest) + { + m_assembler.andq_mr(src.offset, src.base, dest); + } + + void andPtr(Imm32 imm, RegisterID srcDest) + { + m_assembler.andq_ir(imm.m_value, srcDest); + } + + void andPtr(ImmPtr imm, RegisterID srcDest) + { + intptr_t value = intptr_t(imm.m_value); + + // 32-bit immediates in 64-bit ALU ops are sign-extended. + if (value >= MinInt32 && value <= MaxInt32) { + andPtr(Imm32(int(value)), srcDest); + } else { + move(imm, scratchRegister); + m_assembler.andq_rr(scratchRegister, srcDest); + } + } + + void notPtr(RegisterID srcDest) + { + m_assembler.notq_r(srcDest); + } + + void orPtr(Address src, RegisterID dest) + { + m_assembler.orq_mr(src.offset, src.base, dest); + } + + void orPtr(RegisterID src, RegisterID dest) + { + m_assembler.orq_rr(src, dest); + } + + void orPtr(ImmPtr imm, RegisterID dest) + { + move(imm, scratchRegister); + m_assembler.orq_rr(scratchRegister, dest); + } + + void orPtr(Imm32 imm, RegisterID dest) + { + m_assembler.orq_ir(imm.m_value, dest); + } + + void subPtr(RegisterID src, RegisterID dest) + { + m_assembler.subq_rr(src, dest); + } + + void subPtr(Imm32 imm, RegisterID dest) + { + m_assembler.subq_ir(imm.m_value, dest); + } + + void subPtr(ImmPtr imm, RegisterID dest) + { + move(imm, scratchRegister); + m_assembler.subq_rr(scratchRegister, dest); + } + + void xorPtr(RegisterID src, RegisterID dest) + { + m_assembler.xorq_rr(src, dest); + } + + void xorPtr(Imm32 imm, RegisterID srcDest) + { + m_assembler.xorq_ir(imm.m_value, srcDest); + } + + void rshiftPtr(Imm32 imm, RegisterID srcDest) + { + m_assembler.sarq_i8r(imm.m_value, srcDest); + } + + void lshiftPtr(Imm32 imm, RegisterID srcDest) + { + m_assembler.shlq_i8r(imm.m_value, srcDest); + } + + void loadPtr(ImplicitAddress address, RegisterID dest) + { + m_assembler.movq_mr(address.offset, address.base, dest); + } + + void loadPtr(BaseIndex address, RegisterID dest) + { + m_assembler.movq_mr(address.offset, address.base, address.index, address.scale, dest); + } + + void loadPtr(void* address, RegisterID dest) + { + if (dest == X86Registers::eax) + m_assembler.movq_mEAX(address); + else { + move(ImmPtr(address), scratchRegister); + loadPtr(ImplicitAddress(scratchRegister), dest); + } + } + + DataLabel32 loadPtrWithAddressOffsetPatch(Address address, RegisterID dest) + { + m_assembler.movq_mr_disp32(address.offset, address.base, dest); + return DataLabel32(this); + } + + void storePtr(RegisterID src, ImplicitAddress address) + { + m_assembler.movq_rm(src, address.offset, address.base); + } + + void storePtr(ImmPtr imm, BaseIndex address) + { + intptr_t value = intptr_t(imm.m_value); + + // 32-bit immediates in 64-bit stores will be zero-extended, so check + // if the value can fit in such a store. + if (value >= 0 && value < intptr_t(0x7FFFFFFF)) { + m_assembler.movq_i32m(int32_t(value), address.offset, address.base, address.index, + address.scale); + } else { + move(imm, scratchRegister); + storePtr(scratchRegister, address); + } + } + + void storePtr(RegisterID src, BaseIndex address) + { + m_assembler.movq_rm(src, address.offset, address.base, address.index, address.scale); + } + + void storePtr(RegisterID src, void* address) + { + if (src == X86Registers::eax) + m_assembler.movq_EAXm(address); + else { + move(ImmPtr(address), scratchRegister); + storePtr(src, ImplicitAddress(scratchRegister)); + } + } + + void storePtr(ImmPtr imm, ImplicitAddress address) + { + intptr_t value = intptr_t(imm.m_value); + + // 32-bit immediates in 64-bit stores will be zero-extended, so check + // if the value can fit in such a store. + if (value >= 0 && value < intptr_t(0x7FFFFFFF)) { + m_assembler.movq_i32m(int32_t(value), address.offset, address.base); + } else { + move(imm, scratchRegister); + storePtr(scratchRegister, address); + } + } + + DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address) + { + m_assembler.movq_rm_disp32(src, address.offset, address.base); + return DataLabel32(this); + } + + void movePtrToDouble(RegisterID src, FPRegisterID dest) + { + m_assembler.movq_rr(src, dest); + } + + void moveDoubleToPtr(FPRegisterID src, RegisterID dest) + { + m_assembler.movq_rr(src, dest); + } + + void setPtr(Condition cond, RegisterID left, Imm32 right, RegisterID dest) + { + if (((cond == Equal) || (cond == NotEqual)) && !right.m_value) + m_assembler.testq_rr(left, left); + else + m_assembler.cmpq_ir(right.m_value, left); + m_assembler.setCC_r(x86Condition(cond), dest); + m_assembler.movzbl_rr(dest, dest); + } + + void setPtr(Condition cond, RegisterID left, RegisterID right, RegisterID dest) + { + m_assembler.cmpq_rr(right, left); + m_assembler.setCC_r(x86Condition(cond), dest); + m_assembler.movzbl_rr(dest, dest); + } + + void setPtr(Condition cond, RegisterID left, ImmPtr right, RegisterID dest) + { + move(right, scratchRegister); + setPtr(cond, left, scratchRegister, dest); + } + + Jump branchPtr(Condition cond, RegisterID left, RegisterID right) + { + m_assembler.cmpq_rr(right, left); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchPtr(Condition cond, RegisterID left, Imm32 right) + { + m_assembler.cmpq_ir(right.m_value, left); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchPtr(Condition cond, RegisterID left, ImmPtr right) + { + move(right, scratchRegister); + return branchPtr(cond, left, scratchRegister); + } + + Jump branchPtr(Condition cond, RegisterID left, Address right) + { + m_assembler.cmpq_mr(right.offset, right.base, left); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchPtr(Condition cond, AbsoluteAddress left, RegisterID right) + { + move(ImmPtr(left.m_ptr), scratchRegister); + return branchPtr(cond, Address(scratchRegister), right); + } + + Jump branchPtr(Condition cond, Address left, RegisterID right) + { + m_assembler.cmpq_rm(right, left.offset, left.base); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchPtr(Condition cond, Address left, ImmPtr right) + { + move(right, scratchRegister); + return branchPtr(cond, left, scratchRegister); + } + + Jump branchTestPtr(Condition cond, RegisterID reg, RegisterID mask) + { + m_assembler.testq_rr(reg, mask); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchTestPtr(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) + { + // if we are only interested in the low seven bits, this can be tested with a testb + if (mask.m_value == -1) + m_assembler.testq_rr(reg, reg); + else if ((mask.m_value & ~0x7f) == 0) + m_assembler.testb_i8r(mask.m_value, reg); + else + m_assembler.testq_i32r(mask.m_value, reg); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchTestPtr(Condition cond, Address address, Imm32 mask = Imm32(-1)) + { + if (mask.m_value == -1) + m_assembler.cmpq_im(0, address.offset, address.base); + else + m_assembler.testq_i32m(mask.m_value, address.offset, address.base); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchTestPtr(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) + { + if (mask.m_value == -1) + m_assembler.cmpq_im(0, address.offset, address.base, address.index, address.scale); + else + m_assembler.testq_i32m(mask.m_value, address.offset, address.base, address.index, address.scale); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + + Jump branchAddPtr(Condition cond, RegisterID src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); + addPtr(src, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + Jump branchSubPtr(Condition cond, Imm32 imm, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); + subPtr(imm, dest); + return Jump(m_assembler.jCC(x86Condition(cond))); + } + + DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest) + { + m_assembler.movq_i64r(initialValue.asIntptr(), dest); + return DataLabelPtr(this); + } + + Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) + { + dataLabel = moveWithPatch(initialRightValue, scratchRegister); + return branchPtr(cond, left, scratchRegister); + } + + Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) + { + dataLabel = moveWithPatch(initialRightValue, scratchRegister); + return branchPtr(cond, left, scratchRegister); + } + + DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) + { + DataLabelPtr label = moveWithPatch(initialValue, scratchRegister); + storePtr(scratchRegister, address); + return label; + } + + using MacroAssemblerX86Common::branchTest8; + Jump branchTest8(Condition cond, ExtendedAddress address, Imm32 mask = Imm32(-1)) + { + ImmPtr addr(reinterpret_cast(address.offset)); + MacroAssemblerX86Common::move(addr, scratchRegister); + return MacroAssemblerX86Common::branchTest8(cond, BaseIndex(scratchRegister, address.base, TimesOne), mask); + } + + Label loadPtrWithPatchToLEA(Address address, RegisterID dest) + { + Label label(this); + loadPtr(address, dest); + return label; + } + + void pushAllRegs() + { + for (int i = X86Registers::eax; i <= X86Registers::r15; i++) + m_assembler.push_r((RegisterID)i); + } + + void popAllRegs() + { + for (int i = X86Registers::r15; i >= X86Registers::eax; i--) + m_assembler.pop_r((RegisterID)i); + } + + void storeDouble(ImmDouble imm, Address address) + { + storePtr(ImmPtr(reinterpret_cast(imm.u.u64)), address); + } + + void storeDouble(ImmDouble imm, BaseIndex address) + { + storePtr(ImmPtr(reinterpret_cast(imm.u.u64)), address); + } + + bool supportsFloatingPoint() const { return true; } + // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate() + bool supportsFloatingPointTruncate() const { return true; } + bool supportsFloatingPointSqrt() const { return true; } + +private: + friend class LinkBuffer; + friend class RepatchBuffer; + + static void linkCall(void* code, Call call, FunctionPtr function) + { + if (!call.isFlagSet(Call::Near)) + X86Assembler::linkPointer(code, X86Assembler::labelFor(call.m_jmp, -REPTACH_OFFSET_CALL_R11), function.value()); + else + X86Assembler::linkCall(code, call.m_jmp, function.value()); + } + + static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) + { + X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress()); + } + + static void repatchCall(CodeLocationCall call, FunctionPtr destination) + { + X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress()); + } + +}; + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) + +#endif // MacroAssemblerX86_64_h diff --git a/js/src/assembler/assembler/RepatchBuffer.h b/js/src/assembler/assembler/RepatchBuffer.h new file mode 100644 index 0000000..8d28da7 --- /dev/null +++ b/js/src/assembler/assembler/RepatchBuffer.h @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef RepatchBuffer_h +#define RepatchBuffer_h + +#include "assembler/wtf/Platform.h" + +#if ENABLE_ASSEMBLER + +#include +#include //MOCO + +namespace JSC { + +// RepatchBuffer: +// +// This class is used to modify code after code generation has been completed, +// and after the code has potentially already been executed. This mechanism is +// used to apply optimizations to the code. +// +class RepatchBuffer { + typedef MacroAssemblerCodePtr CodePtr; + +public: + RepatchBuffer(const MacroAssemblerCodeRef &ref) + { + m_start = ref.m_code.executableAddress(); + m_size = ref.m_size; + mprot = true; + + if (mprot) + ExecutableAllocator::makeWritable(m_start, m_size); + } + + RepatchBuffer(const JITCode &code) + { + m_start = code.start(); + m_size = code.size(); + mprot = true; + + if (mprot) + ExecutableAllocator::makeWritable(m_start, m_size); + } + + ~RepatchBuffer() + { + if (mprot) + ExecutableAllocator::makeExecutable(m_start, m_size); + } + + void relink(CodeLocationJump jump, CodeLocationLabel destination) + { + MacroAssembler::repatchJump(jump, destination); + } + + bool canRelink(CodeLocationJump jump, CodeLocationLabel destination) + { + return MacroAssembler::canRepatchJump(jump, destination); + } + + void relink(CodeLocationCall call, CodeLocationLabel destination) + { + MacroAssembler::repatchCall(call, destination); + } + + void relink(CodeLocationCall call, FunctionPtr destination) + { + MacroAssembler::repatchCall(call, destination); + } + + void relink(CodeLocationNearCall nearCall, CodePtr destination) + { + MacroAssembler::repatchNearCall(nearCall, CodeLocationLabel(destination)); + } + + void relink(CodeLocationNearCall nearCall, CodeLocationLabel destination) + { + MacroAssembler::repatchNearCall(nearCall, destination); + } + + void repatch(CodeLocationDataLabel32 dataLabel32, int32_t value) + { + MacroAssembler::repatchInt32(dataLabel32, value); + } + + void repatch(CodeLocationDataLabelPtr dataLabelPtr, void* value) + { + MacroAssembler::repatchPointer(dataLabelPtr, value); + } + + void repatchLoadPtrToLEA(CodeLocationInstruction instruction) + { + MacroAssembler::repatchLoadPtrToLEA(instruction); + } + + void repatchLEAToLoadPtr(CodeLocationInstruction instruction) + { + MacroAssembler::repatchLEAToLoadPtr(instruction); + } + + void relinkCallerToTrampoline(ReturnAddressPtr returnAddress, CodeLocationLabel label) + { + relink(CodeLocationCall(CodePtr(returnAddress)), label); + } + + void relinkCallerToTrampoline(ReturnAddressPtr returnAddress, CodePtr newCalleeFunction) + { + relinkCallerToTrampoline(returnAddress, CodeLocationLabel(newCalleeFunction)); + } + + void relinkCallerToFunction(ReturnAddressPtr returnAddress, FunctionPtr function) + { + relink(CodeLocationCall(CodePtr(returnAddress)), function); + } + + void relinkNearCallerToTrampoline(ReturnAddressPtr returnAddress, CodeLocationLabel label) + { + relink(CodeLocationNearCall(CodePtr(returnAddress)), label); + } + + void relinkNearCallerToTrampoline(ReturnAddressPtr returnAddress, CodePtr newCalleeFunction) + { + relinkNearCallerToTrampoline(returnAddress, CodeLocationLabel(newCalleeFunction)); + } + +protected: + void* m_start; + size_t m_size; + bool mprot; +}; + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) + +#endif // RepatchBuffer_h diff --git a/js/src/assembler/assembler/X86Assembler.h b/js/src/assembler/assembler/X86Assembler.h new file mode 100644 index 0000000..85dc968 --- /dev/null +++ b/js/src/assembler/assembler/X86Assembler.h @@ -0,0 +1,3004 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef X86Assembler_h +#define X86Assembler_h + +#include "assembler/wtf/Platform.h" + +#if ENABLE_ASSEMBLER && (WTF_CPU_X86 || WTF_CPU_X86_64) + +#include "AssemblerBuffer.h" +#include "jsstdint.h" +#include "assembler/wtf/Assertions.h" +#include "jsvector.h" + +#include "methodjit/Logging.h" +#define IPFX " %s" +#define ISPFX " " +#ifdef JS_METHODJIT_SPEW +# define MAYBE_PAD (isOOLPath ? "> " : "") +# define PRETTY_PRINT_OFFSET(os) (((os)<0)?"-":""), (((os)<0)?-(os):(os)) +# define FIXME_INSN_PRINTING \ + do { \ + js::JaegerSpew(js::JSpew_Insns, \ + ISPFX "FIXME insn printing %s:%d\n", \ + __FILE__, __LINE__); \ + } while (0) +#else +# define MAYBE_PAD "" +# define FIXME_INSN_PRINTING ((void) 0) +# define PRETTY_PRINT_OFFSET(os) "", 0 +#endif + + +namespace JSC { + +inline bool CAN_SIGN_EXTEND_8_32(int32_t value) { return value == (int32_t)(signed char)value; } + +namespace X86Registers { + typedef enum { + eax, + ecx, + edx, + ebx, + esp, + ebp, + esi, + edi + +#if WTF_CPU_X86_64 + ,r8, + r9, + r10, + r11, + r12, + r13, + r14, + r15 +#endif + } RegisterID; + + typedef enum { + xmm0, + xmm1, + xmm2, + xmm3, + xmm4, + xmm5, + xmm6, + xmm7 + } XMMRegisterID; + + static const char* nameFPReg(XMMRegisterID fpreg) + { + static const char* xmmnames[8] + = { "%xmm0", "%xmm1", "%xmm2", "%xmm3", + "%xmm4", "%xmm5", "%xmm6", "%xmm7" }; + int off = (XMMRegisterID)fpreg - (XMMRegisterID)xmm0; + return (off < 0 || off > 7) ? "%xmm?" : xmmnames[off]; + } + + static const char* nameIReg(int szB, RegisterID reg) + { + static const char* r64names[16] + = { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" }; + static const char* r32names[16] + = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", + "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" }; + static const char* r16names[16] + = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", + "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" }; + static const char* r8names[16] + = { "%al", "%cl", "%dl", "%bl", "%ah/spl", "%ch/bpl", "%dh/sil", "%bh/dil", + "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" }; + int off = (RegisterID)reg - (RegisterID)eax; + const char** tab = r64names; + switch (szB) { + case 1: tab = r8names; break; + case 2: tab = r16names; break; + case 4: tab = r32names; break; + } + return (off < 0 || off > 15) ? "%r???" : tab[off]; + } + + static const char* nameIReg(RegisterID reg) + { +# if WTF_CPU_X86_64 + return nameIReg(8, reg); +# else + return nameIReg(4, reg); +# endif + } + +} /* namespace X86Registers */ + + +class X86Assembler { +public: + typedef X86Registers::RegisterID RegisterID; + typedef X86Registers::XMMRegisterID XMMRegisterID; + typedef XMMRegisterID FPRegisterID; + + typedef enum { + ConditionO, + ConditionNO, + ConditionB, + ConditionAE, + ConditionE, + ConditionNE, + ConditionBE, + ConditionA, + ConditionS, + ConditionNS, + ConditionP, + ConditionNP, + ConditionL, + ConditionGE, + ConditionLE, + ConditionG, + + ConditionC = ConditionB, + ConditionNC = ConditionAE + } Condition; + + static const char* nameCC(Condition cc) + { + static const char* names[16] + = { "o ", "no", "b ", "ae", "e ", "ne", "be", "a ", + "s ", "ns", "p ", "np", "l ", "ge", "le", "g " }; + int ix = (int)cc; + return (ix < 0 || ix > 15) ? "??" : names[ix]; + } + +private: + typedef enum { + OP_ADD_EvGv = 0x01, + OP_ADD_GvEv = 0x03, + OP_OR_EvGv = 0x09, + OP_OR_GvEv = 0x0B, + OP_2BYTE_ESCAPE = 0x0F, + OP_3BYTE_ESCAPE = 0x3A, + OP_AND_EvGv = 0x21, + OP_AND_GvEv = 0x23, + OP_SUB_EvGv = 0x29, + OP_SUB_GvEv = 0x2B, + PRE_PREDICT_BRANCH_NOT_TAKEN = 0x2E, + OP_XOR_EvGv = 0x31, + OP_XOR_GvEv = 0x33, + OP_CMP_EvGv = 0x39, + OP_CMP_GvEv = 0x3B, +#if WTF_CPU_X86_64 + PRE_REX = 0x40, +#endif + OP_PUSH_EAX = 0x50, + OP_POP_EAX = 0x58, +#if WTF_CPU_X86 + OP_PUSHA = 0x60, + OP_POPA = 0x61, +#endif +#if WTF_CPU_X86_64 + OP_MOVSXD_GvEv = 0x63, +#endif + PRE_OPERAND_SIZE = 0x66, + PRE_SSE_66 = 0x66, + OP_PUSH_Iz = 0x68, + OP_IMUL_GvEvIz = 0x69, + OP_GROUP1_EbIb = 0x80, + OP_GROUP1_EvIz = 0x81, + OP_GROUP1_EvIb = 0x83, + OP_TEST_EvGv = 0x85, + OP_XCHG_EvGv = 0x87, + OP_MOV_EbGv = 0x88, + OP_MOV_EvGv = 0x89, + OP_MOV_GvEv = 0x8B, + OP_LEA = 0x8D, + OP_GROUP1A_Ev = 0x8F, + OP_CDQ = 0x99, + OP_MOV_EAXOv = 0xA1, + OP_MOV_OvEAX = 0xA3, + OP_MOV_EAXIv = 0xB8, + OP_GROUP2_EvIb = 0xC1, + OP_RET = 0xC3, + OP_GROUP11_EvIb = 0xC6, + OP_GROUP11_EvIz = 0xC7, + OP_INT3 = 0xCC, + OP_GROUP2_Ev1 = 0xD1, + OP_GROUP2_EvCL = 0xD3, + OP_CALL_rel32 = 0xE8, + OP_JMP_rel32 = 0xE9, + PRE_SSE_F2 = 0xF2, + PRE_SSE_F3 = 0xF3, + OP_HLT = 0xF4, + OP_GROUP3_EbIb = 0xF6, + OP_GROUP3_Ev = 0xF7, + OP_GROUP3_EvIz = 0xF7, // OP_GROUP3_Ev has an immediate, when instruction is a test. + OP_GROUP5_Ev = 0xFF + } OneByteOpcodeID; + + typedef enum { + OP2_MOVSD_VsdWsd = 0x10, + OP2_MOVSD_WsdVsd = 0x11, + OP2_UNPCKLPS_VsdWsd = 0x14, + OP2_CVTSI2SD_VsdEd = 0x2A, + OP2_CVTTSD2SI_GdWsd = 0x2C, + OP2_UCOMISD_VsdWsd = 0x2E, + OP2_ADDSD_VsdWsd = 0x58, + OP2_MULSD_VsdWsd = 0x59, + OP2_CVTSS2SD_VsdEd = 0x5A, + OP2_CVTSD2SS_VsdEd = 0x5A, + OP2_SUBSD_VsdWsd = 0x5C, + OP2_DIVSD_VsdWsd = 0x5E, + OP2_SQRTSD_VsdWsd = 0x51, + OP2_XORPD_VpdWpd = 0x57, + OP2_MOVD_VdEd = 0x6E, + OP2_PSRLDQ_Vd = 0x73, + OP2_MOVD_EdVd = 0x7E, + OP2_JCC_rel32 = 0x80, + OP_SETCC = 0x90, + OP2_IMUL_GvEv = 0xAF, + OP2_MOVSX_GvEb = 0xBE, + OP2_MOVSX_GvEw = 0xBF, + OP2_MOVZX_GvEb = 0xB6, + OP2_MOVZX_GvEw = 0xB7, + OP2_PEXTRW_GdUdIb = 0xC5 + } TwoByteOpcodeID; + + typedef enum { + OP3_PINSRD_VsdWsd = 0x22 + } ThreeByteOpcodeID; + + TwoByteOpcodeID jccRel32(Condition cond) + { + return (TwoByteOpcodeID)(OP2_JCC_rel32 + cond); + } + + TwoByteOpcodeID setccOpcode(Condition cond) + { + return (TwoByteOpcodeID)(OP_SETCC + cond); + } + + typedef enum { + GROUP1_OP_ADD = 0, + GROUP1_OP_OR = 1, + GROUP1_OP_ADC = 2, + GROUP1_OP_AND = 4, + GROUP1_OP_SUB = 5, + GROUP1_OP_XOR = 6, + GROUP1_OP_CMP = 7, + + GROUP1A_OP_POP = 0, + + GROUP2_OP_SHL = 4, + GROUP2_OP_SHR = 5, + GROUP2_OP_SAR = 7, + + GROUP3_OP_TEST = 0, + GROUP3_OP_NOT = 2, + GROUP3_OP_NEG = 3, + GROUP3_OP_IDIV = 7, + + GROUP5_OP_CALLN = 2, + GROUP5_OP_JMPN = 4, + GROUP5_OP_PUSH = 6, + + GROUP11_MOV = 0 + } GroupOpcodeID; + + class X86InstructionFormatter; +public: + +#ifdef JS_METHODJIT_SPEW + bool isOOLPath; +#endif + + class JmpSrc { + friend class X86Assembler; + friend class X86InstructionFormatter; + public: + JmpSrc() + : m_offset(-1) + { + } + + private: + JmpSrc(int offset) + : m_offset(offset) + { + } + + int m_offset; + }; + + class JmpDst { + friend class X86Assembler; + friend class X86InstructionFormatter; + public: + JmpDst() + : m_offset(-1) + , m_used(false) + { + } + + bool isUsed() const { return m_used; } + void used() { m_used = true; } + bool isValid() const { return m_offset != -1; } + private: + JmpDst(int offset) + : m_offset(offset) + , m_used(false) + { + ASSERT(m_offset == offset); + } + + signed int m_offset : 31; + bool m_used : 1; + }; + + X86Assembler() +#ifdef JS_METHODJIT_SPEW + : isOOLPath(false) +#endif + { + } + + size_t size() const { return m_formatter.size(); } + unsigned char *buffer() const { return m_formatter.buffer(); } + bool oom() const { return m_formatter.oom(); } + + // Stack operations: + + void push_r(RegisterID reg) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "push %s\n", MAYBE_PAD, nameIReg(reg)); + m_formatter.oneByteOp(OP_PUSH_EAX, reg); + } + + void pop_r(RegisterID reg) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "pop %s\n", MAYBE_PAD, nameIReg(reg)); + m_formatter.oneByteOp(OP_POP_EAX, reg); + } + + void push_i32(int imm) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "pushl %s$0x%x\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(imm)); + m_formatter.oneByteOp(OP_PUSH_Iz); + m_formatter.immediate32(imm); + } + + void push_m(int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "push %s0x%x(%s)\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_PUSH, base, offset); + } + + void pop_m(int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_GROUP1A_Ev, GROUP1A_OP_POP, base, offset); + } + + // Arithmetic operations: + +#if !WTF_CPU_X86_64 + void adcl_im(int imm, void* addr) + { + FIXME_INSN_PRINTING; + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADC, addr); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_ADC, addr); + m_formatter.immediate32(imm); + } + } +#endif + + void addl_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "addl %s, %s\n", MAYBE_PAD, + nameIReg(4,src), nameIReg(4,dst)); + m_formatter.oneByteOp(OP_ADD_EvGv, src, dst); + } + + void addl_mr(int offset, RegisterID base, RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_ADD_GvEv, dst, base, offset); + } + + void addl_rm(RegisterID src, int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_ADD_EvGv, src, base, offset); + } + + void addl_ir(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "addl $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(4,dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADD, dst); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_ADD, dst); + m_formatter.immediate32(imm); + } + } + + void addl_im(int imm, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "addl %d, %s0x%x(%s)\n", MAYBE_PAD, + imm, PRETTY_PRINT_OFFSET(offset), nameIReg(8,base)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADD, base, offset); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_ADD, base, offset); + m_formatter.immediate32(imm); + } + } + +#if WTF_CPU_X86_64 + void addq_rr(RegisterID src, RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp64(OP_ADD_EvGv, src, dst); + } + + void addq_ir(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "addq $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(8,dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_ADD, dst); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_ADD, dst); + m_formatter.immediate32(imm); + } + } + + void addq_im(int imm, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "addq $0x%x, %s0x%x(%s)\n", MAYBE_PAD, + imm, PRETTY_PRINT_OFFSET(offset), nameIReg(8,base)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_ADD, base, offset); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_ADD, base, offset); + m_formatter.immediate32(imm); + } + } +#else + void addl_im(int imm, void* addr) + { + FIXME_INSN_PRINTING; + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADD, addr); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_ADD, addr); + m_formatter.immediate32(imm); + } + } +#endif + + void andl_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "andl %s, %s\n", MAYBE_PAD, + nameIReg(4,src), nameIReg(4,dst)); + m_formatter.oneByteOp(OP_AND_EvGv, src, dst); + } + + void andl_mr(int offset, RegisterID base, RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_AND_GvEv, dst, base, offset); + } + + void andl_rm(RegisterID src, int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_AND_EvGv, src, base, offset); + } + + void andl_ir(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "andl $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(4,dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_AND, dst); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_AND, dst); + m_formatter.immediate32(imm); + } + } + + void andl_im(int imm, int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_AND, base, offset); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_AND, base, offset); + m_formatter.immediate32(imm); + } + } + +#if WTF_CPU_X86_64 + void andq_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "andq %s, %s\n", MAYBE_PAD, + nameIReg(8,src), nameIReg(8,dst)); + m_formatter.oneByteOp64(OP_AND_EvGv, src, dst); + } + + void andq_mr(int offset, RegisterID base, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "andq %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(8,base), nameIReg(8,dst)); + m_formatter.oneByteOp64(OP_AND_GvEv, dst, base, offset); + } + + void orq_mr(int offset, RegisterID base, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "orq %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(8,base), nameIReg(8,dst)); + m_formatter.oneByteOp64(OP_OR_GvEv, dst, base, offset); + } + + void andq_ir(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "andq $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(8,dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_AND, dst); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_AND, dst); + m_formatter.immediate32(imm); + } + } +#else + void andl_im(int imm, void* addr) + { + FIXME_INSN_PRINTING; + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_AND, addr); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_AND, addr); + m_formatter.immediate32(imm); + } + } +#endif + + void negl_r(RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "negl %s\n", MAYBE_PAD, nameIReg(4,dst)); + m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_NEG, dst); + } + + void negl_m(int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_NEG, base, offset); + } + + void notl_r(RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "notl %s\n", MAYBE_PAD, nameIReg(4,dst)); + m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_NOT, dst); + } + + void notl_m(int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_NOT, base, offset); + } + + void orl_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "orl %s, %s\n", MAYBE_PAD, + nameIReg(4,src), nameIReg(4,dst)); + m_formatter.oneByteOp(OP_OR_EvGv, src, dst); + } + + void orl_mr(int offset, RegisterID base, RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_OR_GvEv, dst, base, offset); + } + + void orl_rm(RegisterID src, int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_OR_EvGv, src, base, offset); + } + + void orl_ir(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "orl $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(4,dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_OR, dst); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_OR, dst); + m_formatter.immediate32(imm); + } + } + + void orl_im(int imm, int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_OR, base, offset); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_OR, base, offset); + m_formatter.immediate32(imm); + } + } + +#if WTF_CPU_X86_64 + void orq_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "orq %s, %s\n", MAYBE_PAD, + nameIReg(8,src), nameIReg(8,dst)); + m_formatter.oneByteOp64(OP_OR_EvGv, src, dst); + } + + void orq_ir(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "orq $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(8,dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_OR, dst); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_OR, dst); + m_formatter.immediate32(imm); + } + } + + void notq_r(RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "notq %s\n", MAYBE_PAD, nameIReg(8,dst)); + m_formatter.oneByteOp64(OP_GROUP3_Ev, GROUP3_OP_NOT, dst); + } +#else + void orl_im(int imm, void* addr) + { + FIXME_INSN_PRINTING; + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_OR, addr); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_OR, addr); + m_formatter.immediate32(imm); + } + } +#endif + + void subl_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "subl %s, %s\n", MAYBE_PAD, + nameIReg(4,src), nameIReg(4,dst)); + m_formatter.oneByteOp(OP_SUB_EvGv, src, dst); + } + + void subl_mr(int offset, RegisterID base, RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_SUB_GvEv, dst, base, offset); + } + + void subl_rm(RegisterID src, int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_SUB_EvGv, src, base, offset); + } + + void subl_ir(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "subl $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(4, dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_SUB, dst); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_SUB, dst); + m_formatter.immediate32(imm); + } + } + + void subl_im(int imm, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "subl $0x%x, %s0x%x(%s)\n", MAYBE_PAD, + imm, PRETTY_PRINT_OFFSET(offset), nameIReg(4, base)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_SUB, base, offset); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_SUB, base, offset); + m_formatter.immediate32(imm); + } + } + +#if WTF_CPU_X86_64 + void subq_rr(RegisterID src, RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp64(OP_SUB_EvGv, src, dst); + } + + void subq_ir(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "subq $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(8,dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_SUB, dst); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_SUB, dst); + m_formatter.immediate32(imm); + } + } +#else + void subl_im(int imm, void* addr) + { + FIXME_INSN_PRINTING; + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_SUB, addr); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_SUB, addr); + m_formatter.immediate32(imm); + } + } +#endif + + void xorl_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "xorl %s, %s\n", MAYBE_PAD, + nameIReg(4,src), nameIReg(4,dst)); + m_formatter.oneByteOp(OP_XOR_EvGv, src, dst); + } + + void xorl_mr(int offset, RegisterID base, RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_XOR_GvEv, dst, base, offset); + } + + void xorl_rm(RegisterID src, int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_XOR_EvGv, src, base, offset); + } + + void xorl_im(int imm, int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_XOR, base, offset); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_XOR, base, offset); + m_formatter.immediate32(imm); + } + } + + void xorl_ir(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "xorl %d, %s\n", MAYBE_PAD, + imm, nameIReg(4,dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_XOR, dst); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_XOR, dst); + m_formatter.immediate32(imm); + } + } + +#if WTF_CPU_X86_64 + void xorq_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "xorq %s, %s\n", MAYBE_PAD, + nameIReg(8,src), nameIReg(8, dst)); + m_formatter.oneByteOp64(OP_XOR_EvGv, src, dst); + } + + void xorq_ir(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "xorq %d, %s\n", MAYBE_PAD, + imm, nameIReg(8,dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_XOR, dst); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_XOR, dst); + m_formatter.immediate32(imm); + } + } +#endif + + void sarl_i8r(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "sarl $%d, %s\n", MAYBE_PAD, imm, nameIReg(4, dst)); + if (imm == 1) + m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst); + else { + m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst); + m_formatter.immediate8(imm); + } + } + + void sarl_CLr(RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "sarl %%cl, %s\n", MAYBE_PAD, nameIReg(4, dst)); + m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst); + } + + void shrl_i8r(int imm, RegisterID dst) + { + if (imm == 1) + m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SHR, dst); + else { + m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SHR, dst); + m_formatter.immediate8(imm); + } + } + + void shrl_CLr(RegisterID dst) + { + m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SHR, dst); + } + + void shll_i8r(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "shll $%d, %s\n", MAYBE_PAD, imm, nameIReg(4, dst)); + if (imm == 1) + m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SHL, dst); + else { + m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SHL, dst); + m_formatter.immediate8(imm); + } + } + + void shll_CLr(RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "shll %%cl, %s\n", MAYBE_PAD, nameIReg(4, dst)); + m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SHL, dst); + } + +#if WTF_CPU_X86_64 + void sarq_CLr(RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst); + } + + void sarq_i8r(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "sarq $%d, %s\n", MAYBE_PAD, imm, nameIReg(8, dst)); + if (imm == 1) + m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst); + else { + m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst); + m_formatter.immediate8(imm); + } + } + + void shlq_i8r(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "shlq $%d, %s\n", MAYBE_PAD, imm, nameIReg(8, dst)); + if (imm == 1) + m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SHL, dst); + else { + m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SHL, dst); + m_formatter.immediate8(imm); + } + } +#endif + + void imull_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "imull %s, %s\n", MAYBE_PAD, nameIReg(4,src), nameIReg(4, dst)); + m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, src); + } + + void imull_mr(int offset, RegisterID base, RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, base, offset); + } + + void imull_i32r(RegisterID src, int32_t value, RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_IMUL_GvEvIz, dst, src); + m_formatter.immediate32(value); + } + + void idivl_r(RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "idivl %s\n", MAYBE_PAD, + nameIReg(4, dst)); + m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_IDIV, dst); + } + + // Comparisons: + + void cmpl_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cmpl %s, %s\n", MAYBE_PAD, + nameIReg(4, src), nameIReg(4, dst)); + m_formatter.oneByteOp(OP_CMP_EvGv, src, dst); + } + + void cmpl_rm(RegisterID src, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cmpl %s, %s0x%x(%s)\n", MAYBE_PAD, + nameIReg(4, src), PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.oneByteOp(OP_CMP_EvGv, src, base, offset); + } + + void cmpl_mr(int offset, RegisterID base, RegisterID src) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cmpl %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(4, base), nameIReg(src)); + m_formatter.oneByteOp(OP_CMP_GvEv, src, base, offset); + } + + void cmpl_ir(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cmpl $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(4, dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, dst); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, dst); + m_formatter.immediate32(imm); + } + } + + void cmpl_ir_force32(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cmpl $0x%x, %s\n", MAYBE_PAD, imm, nameIReg(4, dst)); + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, dst); + m_formatter.immediate32(imm); + } + + void cmpl_im(int imm, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cmpl $0x%x, %s0x%x(%s)\n", MAYBE_PAD, + imm, PRETTY_PRINT_OFFSET(offset), nameIReg(4,base)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, offset); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, offset); + m_formatter.immediate32(imm); + } + } + + void cmpb_im(int imm, int offset, RegisterID base) + { + m_formatter.oneByteOp(OP_GROUP1_EbIb, GROUP1_OP_CMP, base, offset); + m_formatter.immediate8(imm); + } + + void cmpb_im(int imm, int offset, RegisterID base, RegisterID index, int scale) + { + m_formatter.oneByteOp(OP_GROUP1_EbIb, GROUP1_OP_CMP, base, index, scale, offset); + m_formatter.immediate8(imm); + } + + void cmpl_im(int imm, int offset, RegisterID base, RegisterID index, int scale) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cmpl %d, %d(%s,%s,%d)\n", MAYBE_PAD, + imm, offset, nameIReg(4,base), nameIReg(4,index), scale); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, index, scale, offset); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, index, scale, offset); + m_formatter.immediate32(imm); + } + } + + void cmpl_im_force32(int imm, int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, offset); + m_formatter.immediate32(imm); + } + +#if WTF_CPU_X86_64 + void cmpq_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cmpq %s, %s\n", MAYBE_PAD, + nameIReg(8, src), nameIReg(8, dst)); + m_formatter.oneByteOp64(OP_CMP_EvGv, src, dst); + } + + void cmpq_rm(RegisterID src, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cmpq %s, %d(%s)\n", MAYBE_PAD, + nameIReg(8, src), offset, nameIReg(8, base)); + m_formatter.oneByteOp64(OP_CMP_EvGv, src, base, offset); + } + + void cmpq_mr(int offset, RegisterID base, RegisterID src) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cmpq %d(%s), %s\n", MAYBE_PAD, + offset, nameIReg(8, base), nameIReg(8, src)); + m_formatter.oneByteOp64(OP_CMP_GvEv, src, base, offset); + } + + void cmpq_ir(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cmpq %d, %s\n", MAYBE_PAD, + imm, nameIReg(8, dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_CMP, dst); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_CMP, dst); + m_formatter.immediate32(imm); + } + } + + void cmpq_im(int imm, int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, offset); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, offset); + m_formatter.immediate32(imm); + } + } + + void cmpq_im(int imm, int offset, RegisterID base, RegisterID index, int scale) + { + FIXME_INSN_PRINTING; + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, index, scale, offset); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, index, scale, offset); + m_formatter.immediate32(imm); + } + } +#else + void cmpl_rm(RegisterID reg, void* addr) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_CMP_EvGv, reg, addr); + } + + void cmpl_im(int imm, void* addr) + { + FIXME_INSN_PRINTING; + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, addr); + m_formatter.immediate8(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, addr); + m_formatter.immediate32(imm); + } + } +#endif + + void cmpw_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale) + { + FIXME_INSN_PRINTING; + m_formatter.prefix(PRE_OPERAND_SIZE); + m_formatter.oneByteOp(OP_CMP_EvGv, src, base, index, scale, offset); + } + + void cmpw_im(int imm, int offset, RegisterID base, RegisterID index, int scale) + { + FIXME_INSN_PRINTING; + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.prefix(PRE_OPERAND_SIZE); + m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, index, scale, offset); + m_formatter.immediate8(imm); + } else { + m_formatter.prefix(PRE_OPERAND_SIZE); + m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, index, scale, offset); + m_formatter.immediate16(imm); + } + } + + void testl_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "testl %s, %s\n", MAYBE_PAD, + nameIReg(4,src), nameIReg(4,dst)); + m_formatter.oneByteOp(OP_TEST_EvGv, src, dst); + } + + void testl_i32r(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "testl $0x%x, %s\n", MAYBE_PAD, + imm, nameIReg(dst)); + m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, dst); + m_formatter.immediate32(imm); + } + + void testl_i32m(int imm, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "testl $0x%x, %s0x%x(%s)\n", MAYBE_PAD, + imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, offset); + m_formatter.immediate32(imm); + } + + void testb_im(int imm, int offset, RegisterID base) + { + m_formatter.oneByteOp(OP_GROUP3_EbIb, GROUP3_OP_TEST, base, offset); + m_formatter.immediate8(imm); + } + + void testb_im(int imm, int offset, RegisterID base, RegisterID index, int scale) + { + m_formatter.oneByteOp(OP_GROUP3_EbIb, GROUP3_OP_TEST, base, index, scale, offset); + m_formatter.immediate8(imm); + } + + void testl_i32m(int imm, int offset, RegisterID base, RegisterID index, int scale) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, index, scale, offset); + m_formatter.immediate32(imm); + } + +#if WTF_CPU_X86_64 + void testq_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "testq %s, %s\n", MAYBE_PAD, + nameIReg(8,src), nameIReg(8,dst)); + m_formatter.oneByteOp64(OP_TEST_EvGv, src, dst); + } + + void testq_i32r(int imm, RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp64(OP_GROUP3_EvIz, GROUP3_OP_TEST, dst); + m_formatter.immediate32(imm); + } + + void testq_i32m(int imm, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "testq $0x%x, %s0x%x(%s)\n", MAYBE_PAD, + imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.oneByteOp64(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, offset); + m_formatter.immediate32(imm); + } + + void testq_i32m(int imm, int offset, RegisterID base, RegisterID index, int scale) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp64(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, index, scale, offset); + m_formatter.immediate32(imm); + } +#endif + + void testw_rr(RegisterID src, RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.prefix(PRE_OPERAND_SIZE); + m_formatter.oneByteOp(OP_TEST_EvGv, src, dst); + } + + void testb_i8r(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "testb $0x%x, %s\n", MAYBE_PAD, + imm, nameIReg(1,dst)); + m_formatter.oneByteOp8(OP_GROUP3_EbIb, GROUP3_OP_TEST, dst); + m_formatter.immediate8(imm); + } + + void setCC_r(Condition cond, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "set%s %s\n", MAYBE_PAD, + nameCC(cond), nameIReg(1,dst)); + m_formatter.twoByteOp8(setccOpcode(cond), (GroupOpcodeID)0, dst); + } + + void sete_r(RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.twoByteOp8(setccOpcode(ConditionE), (GroupOpcodeID)0, dst); + } + + void setz_r(RegisterID dst) + { + FIXME_INSN_PRINTING; + sete_r(dst); + } + + void setne_r(RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.twoByteOp8(setccOpcode(ConditionNE), (GroupOpcodeID)0, dst); + } + + void setnz_r(RegisterID dst) + { + FIXME_INSN_PRINTING; + setne_r(dst); + } + + // Various move ops: + + void cdq() + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cdq \n", MAYBE_PAD); + m_formatter.oneByteOp(OP_CDQ); + } + + void xchgl_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "xchgl %s, %s\n", MAYBE_PAD, + nameIReg(4,src), nameIReg(4,dst)); + m_formatter.oneByteOp(OP_XCHG_EvGv, src, dst); + } + +#if WTF_CPU_X86_64 + void xchgq_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "xchgq %s, %s\n", MAYBE_PAD, + nameIReg(8,src), nameIReg(8,dst)); + m_formatter.oneByteOp64(OP_XCHG_EvGv, src, dst); + } +#endif + + void movl_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movl %s, %s\n", MAYBE_PAD, + nameIReg(4,src), nameIReg(4,dst)); + m_formatter.oneByteOp(OP_MOV_EvGv, src, dst); + } + + void movw_rm(RegisterID src, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movw %s, %s0x%x(%s)\n", MAYBE_PAD, + nameIReg(2,src), PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.prefix(PRE_OPERAND_SIZE); + m_formatter.oneByteOp(OP_MOV_EvGv, src, base, offset); + } + + void movl_rm(RegisterID src, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movl %s, %s0x%x(%s)\n", MAYBE_PAD, + nameIReg(4,src), PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.oneByteOp(OP_MOV_EvGv, src, base, offset); + } + + void movl_rm_disp32(RegisterID src, int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp_disp32(OP_MOV_EvGv, src, base, offset); + } + + void movw_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movw %s, %d(%s,%s,%d)\n", MAYBE_PAD, + nameIReg(2, src), offset, nameIReg(base), nameIReg(index), scale); + m_formatter.prefix(PRE_OPERAND_SIZE); + m_formatter.oneByteOp(OP_MOV_EvGv, src, base, index, scale, offset); + } + + void movl_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movl %s, %d(%s,%s,%d)\n", MAYBE_PAD, + nameIReg(4, src), offset, nameIReg(base), nameIReg(index), scale); + m_formatter.oneByteOp(OP_MOV_EvGv, src, base, index, scale, offset); + } + + void movl_mEAX(void* addr) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_MOV_EAXOv); +#if WTF_CPU_X86_64 + m_formatter.immediate64(reinterpret_cast(addr)); +#else + m_formatter.immediate32(reinterpret_cast(addr)); +#endif + } + + void movl_mr(int offset, RegisterID base, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movl %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(4, dst)); + m_formatter.oneByteOp(OP_MOV_GvEv, dst, base, offset); + } + + void movl_mr_disp32(int offset, RegisterID base, RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp_disp32(OP_MOV_GvEv, dst, base, offset); + } + + void movl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movl %d(%s,%s,%d), %s\n", MAYBE_PAD, + offset, nameIReg(base), nameIReg(index), scale, nameIReg(4, dst)); + m_formatter.oneByteOp(OP_MOV_GvEv, dst, base, index, scale, offset); + } + + void movl_i32r(int imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movl $0x%x, %s\n", MAYBE_PAD, + imm, nameIReg(dst)); + m_formatter.oneByteOp(OP_MOV_EAXIv, dst); + m_formatter.immediate32(imm); + } + + void movb_i8m(int imm, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movb $0x%x, %s0x%x(%s)\n", MAYBE_PAD, + imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.oneByteOp(OP_GROUP11_EvIb, GROUP11_MOV, base, offset); + m_formatter.immediate8(imm); + } + + void movb_i8m(int imm, int offset, RegisterID base, RegisterID index, int scale) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movb $0x%x, %d(%s,%s,%d)\n", MAYBE_PAD, + imm, offset, nameIReg(base), nameIReg(index), scale); + m_formatter.oneByteOp(OP_GROUP11_EvIb, GROUP11_MOV, base, index, scale, offset); + m_formatter.immediate8(imm); + } + + void movw_i16m(int imm, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movw $0x%x, %s0x%x(%s)\n", MAYBE_PAD, + imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.prefix(PRE_OPERAND_SIZE); + m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, base, offset); + m_formatter.immediate16(imm); + } + + void movl_i32m(int imm, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movl $0x%x, %s0x%x(%s)\n", MAYBE_PAD, + imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, base, offset); + m_formatter.immediate32(imm); + } + + void movw_i16m(int imm, int offset, RegisterID base, RegisterID index, int scale) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movw $0x%x, %d(%s,%s,%d)\n", MAYBE_PAD, + imm, offset, nameIReg(base), nameIReg(index), scale); + m_formatter.prefix(PRE_OPERAND_SIZE); + m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, base, index, scale, offset); + m_formatter.immediate16(imm); + } + + void movl_i32m(int imm, int offset, RegisterID base, RegisterID index, int scale) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movl $0x%x, %d(%s,%s,%d)\n", MAYBE_PAD, + imm, offset, nameIReg(base), nameIReg(index), scale); + m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, base, index, scale, offset); + m_formatter.immediate32(imm); + } + + void movl_EAXm(void* addr) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_MOV_OvEAX); +#if WTF_CPU_X86_64 + m_formatter.immediate64(reinterpret_cast(addr)); +#else + m_formatter.immediate32(reinterpret_cast(addr)); +#endif + } + +#if WTF_CPU_X86_64 + void movq_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movq %s, %s\n", MAYBE_PAD, + nameIReg(8,src), nameIReg(8,dst)); + m_formatter.oneByteOp64(OP_MOV_EvGv, src, dst); + } + + void movq_rm(RegisterID src, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movq %s, %s0x%x(%s)\n", MAYBE_PAD, + nameIReg(8,src), PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.oneByteOp64(OP_MOV_EvGv, src, base, offset); + } + + void movq_rm_disp32(RegisterID src, int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp64_disp32(OP_MOV_EvGv, src, base, offset); + } + + void movq_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movq %s, %s0x%x(%s)\n", MAYBE_PAD, + nameIReg(8,src), PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.oneByteOp64(OP_MOV_EvGv, src, base, index, scale, offset); + } + + void movq_mEAX(void* addr) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp64(OP_MOV_EAXOv); + m_formatter.immediate64(reinterpret_cast(addr)); + } + + void movq_EAXm(void* addr) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp64(OP_MOV_OvEAX); + m_formatter.immediate64(reinterpret_cast(addr)); + } + + void movq_mr(int offset, RegisterID base, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movq %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(8,dst)); + m_formatter.oneByteOp64(OP_MOV_GvEv, dst, base, offset); + } + + void movq_mr_disp32(int offset, RegisterID base, RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp64_disp32(OP_MOV_GvEv, dst, base, offset); + } + + void movq_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movq %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(8,dst)); + m_formatter.oneByteOp64(OP_MOV_GvEv, dst, base, index, scale, offset); + } + + void leaq_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "leaq %d(%s,%s,%d), %s\n", MAYBE_PAD, + offset, nameIReg(base), nameIReg(index), scale, nameIReg(8,dst)), + m_formatter.oneByteOp64(OP_LEA, dst, base, index, scale, offset); + } + + void movq_i32m(int imm, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movq $%d, %s0x%x(%s)\n", MAYBE_PAD, + imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.oneByteOp64(OP_GROUP11_EvIz, GROUP11_MOV, base, offset); + m_formatter.immediate32(imm); + } + + void movq_i32m(int imm, int offset, RegisterID base, RegisterID index, int scale) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movq $%d, %s0x%x(%s)\n", MAYBE_PAD, + imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.oneByteOp64(OP_GROUP11_EvIz, GROUP11_MOV, base, index, scale, offset); + m_formatter.immediate32(imm); + } + + void movq_i64r(int64_t imm, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movabsq $0x%llx, %s\n", MAYBE_PAD, + (unsigned long long int)imm, nameIReg(8,dst)); + m_formatter.oneByteOp64(OP_MOV_EAXIv, dst); + m_formatter.immediate64(imm); + } + + void movsxd_rr(RegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movsxd %s, %s\n", MAYBE_PAD, + nameIReg(4, src), nameIReg(8, dst)); + m_formatter.oneByteOp64(OP_MOVSXD_GvEv, dst, src); + } + + +#else + void movl_rm(RegisterID src, void* addr) + { + FIXME_INSN_PRINTING; + if (src == X86Registers::eax) + movl_EAXm(addr); + else + m_formatter.oneByteOp(OP_MOV_EvGv, src, addr); + } + + void movl_mr(void* addr, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movl 0(%p), %s\n", MAYBE_PAD, + addr, nameIReg(4, dst)); + if (dst == X86Registers::eax) + movl_mEAX(addr); + else + m_formatter.oneByteOp(OP_MOV_GvEv, dst, addr); + } + + void movl_i32m(int imm, void* addr) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, addr); + m_formatter.immediate32(imm); + } +#endif + + void movb_rm(RegisterID src, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movb %s, %s0x%x(%s)\n", MAYBE_PAD, + nameIReg(1, src), PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.oneByteOp8(OP_MOV_EbGv, src, base, offset); + } + + void movb_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movb %s, %d(%s,%s,%d)\n", MAYBE_PAD, + nameIReg(1, src), offset, nameIReg(base), nameIReg(index), scale); + m_formatter.oneByteOp8(OP_MOV_EbGv, src, base, index, scale, offset); + } + + void movzbl_mr(int offset, RegisterID base, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movzbl %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(4, dst)); + m_formatter.twoByteOp(OP2_MOVZX_GvEb, dst, base, offset); + } + + void movzbl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movzbl %d(%s,%s,%d), %s\n", MAYBE_PAD, + offset, nameIReg(base), nameIReg(index), scale, nameIReg(dst)); + m_formatter.twoByteOp(OP2_MOVZX_GvEb, dst, base, index, scale, offset); + } + + void movxbl_mr(int offset, RegisterID base, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movxbl %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(4, dst)); + m_formatter.twoByteOp(OP2_MOVSX_GvEb, dst, base, offset); + } + + void movxbl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movxbl %d(%s,%s,%d), %s\n", MAYBE_PAD, + offset, nameIReg(base), nameIReg(index), scale, nameIReg(dst)); + m_formatter.twoByteOp(OP2_MOVSX_GvEb, dst, base, index, scale, offset); + } + + void movzwl_mr(int offset, RegisterID base, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movzwl %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(4, dst)); + m_formatter.twoByteOp(OP2_MOVZX_GvEw, dst, base, offset); + } + + void movzwl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movzwl %d(%s,%s,%d), %s\n", MAYBE_PAD, + offset, nameIReg(base), nameIReg(index), scale, nameIReg(dst)); + m_formatter.twoByteOp(OP2_MOVZX_GvEw, dst, base, index, scale, offset); + } + + void movxwl_mr(int offset, RegisterID base, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movxwl %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(4, dst)); + m_formatter.twoByteOp(OP2_MOVSX_GvEw, dst, base, offset); + } + + void movxwl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movxwl %d(%s,%s,%d), %s\n", MAYBE_PAD, + offset, nameIReg(base), nameIReg(index), scale, nameIReg(dst)); + m_formatter.twoByteOp(OP2_MOVSX_GvEw, dst, base, index, scale, offset); + } + + void movzbl_rr(RegisterID src, RegisterID dst) + { + // In 64-bit, this may cause an unnecessary REX to be planted (if the dst register + // is in the range ESP-EDI, and the src would not have required a REX). Unneeded + // REX prefixes are defined to be silently ignored by the processor. + js::JaegerSpew(js::JSpew_Insns, + IPFX "movzbl %s, %s\n", MAYBE_PAD, + nameIReg(4,src), nameIReg(4,dst)); + m_formatter.twoByteOp8(OP2_MOVZX_GvEb, dst, src); + } + + void leal_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "leal %d(%s,%s,%d), %s\n", MAYBE_PAD, + offset, nameIReg(base), nameIReg(index), scale, nameIReg(dst)); + m_formatter.oneByteOp(OP_LEA, dst, base, index, scale, offset); + } + + void leal_mr(int offset, RegisterID base, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "leal %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(4,dst)); + m_formatter.oneByteOp(OP_LEA, dst, base, offset); + } +#if WTF_CPU_X86_64 + void leaq_mr(int offset, RegisterID base, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "leaq %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(8,dst)); + m_formatter.oneByteOp64(OP_LEA, dst, base, offset); + } +#endif + + // Flow control: + + JmpSrc call() + { + m_formatter.oneByteOp(OP_CALL_rel32); + JmpSrc r = m_formatter.immediateRel32(); + js::JaegerSpew(js::JSpew_Insns, + IPFX "call ((%d))\n", MAYBE_PAD, r.m_offset); + return r; + } + + JmpSrc call(RegisterID dst) + { + m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_CALLN, dst); + JmpSrc r = JmpSrc(m_formatter.size()); + js::JaegerSpew(js::JSpew_Insns, + IPFX "call *%s\n", MAYBE_PAD, nameIReg(dst)); + return r; + } + + void call_m(int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_CALLN, base, offset); + } + + JmpSrc jmp() + { + m_formatter.oneByteOp(OP_JMP_rel32); + JmpSrc r = m_formatter.immediateRel32(); + js::JaegerSpew(js::JSpew_Insns, + IPFX "jmp ((%d))\n", MAYBE_PAD, r.m_offset); + return r; + } + + // Return a JmpSrc so we have a label to the jump, so we can use this + // To make a tail recursive call on x86-64. The MacroAssembler + // really shouldn't wrap this as a Jump, since it can't be linked. :-/ + JmpSrc jmp_r(RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "jmp ((%s))\n", MAYBE_PAD, + nameIReg(dst)); + m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_JMPN, dst); + return JmpSrc(m_formatter.size()); + } + + void jmp_m(int offset, RegisterID base) + { + FIXME_INSN_PRINTING; + m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_JMPN, base, offset); + } + + void jmp_m(int offset, RegisterID base, RegisterID index, int scale) { + js::JaegerSpew(js::JSpew_Insns, + IPFX "jmp ((%d(%s,%s,%d)))\n", MAYBE_PAD, + offset, nameIReg(base), nameIReg(index), scale); + m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_JMPN, base, index, scale, offset); + } + + JmpSrc jne() + { + return jCC(ConditionNE); + } + + JmpSrc jnz() + { + // printing done by jne() + return jne(); + } + + JmpSrc je() + { + FIXME_INSN_PRINTING; + m_formatter.twoByteOp(jccRel32(ConditionE)); + return m_formatter.immediateRel32(); + } + + JmpSrc jz() + { + // printing done by je() + return je(); + } + + JmpSrc jl() + { + FIXME_INSN_PRINTING; + m_formatter.twoByteOp(jccRel32(ConditionL)); + return m_formatter.immediateRel32(); + } + + JmpSrc jb() + { + FIXME_INSN_PRINTING; + m_formatter.twoByteOp(jccRel32(ConditionB)); + return m_formatter.immediateRel32(); + } + + JmpSrc jle() + { + FIXME_INSN_PRINTING; + m_formatter.twoByteOp(jccRel32(ConditionLE)); + return m_formatter.immediateRel32(); + } + + JmpSrc jbe() + { + FIXME_INSN_PRINTING; + m_formatter.twoByteOp(jccRel32(ConditionBE)); + return m_formatter.immediateRel32(); + } + + JmpSrc jge() + { + FIXME_INSN_PRINTING; + m_formatter.twoByteOp(jccRel32(ConditionGE)); + return m_formatter.immediateRel32(); + } + + JmpSrc jg() + { + FIXME_INSN_PRINTING; + m_formatter.twoByteOp(jccRel32(ConditionG)); + return m_formatter.immediateRel32(); + } + + JmpSrc ja() + { + FIXME_INSN_PRINTING; + m_formatter.twoByteOp(jccRel32(ConditionA)); + return m_formatter.immediateRel32(); + } + + JmpSrc jae() + { + FIXME_INSN_PRINTING; + m_formatter.twoByteOp(jccRel32(ConditionAE)); + return m_formatter.immediateRel32(); + } + + JmpSrc jo() + { + FIXME_INSN_PRINTING; + m_formatter.twoByteOp(jccRel32(ConditionO)); + return m_formatter.immediateRel32(); + } + + JmpSrc jp() + { + return jCC(ConditionP); + } + + JmpSrc js() + { + FIXME_INSN_PRINTING; + m_formatter.twoByteOp(jccRel32(ConditionS)); + return m_formatter.immediateRel32(); + } + + JmpSrc jCC(Condition cond) + { + m_formatter.twoByteOp(jccRel32(cond)); + JmpSrc r = m_formatter.immediateRel32(); + js::JaegerSpew(js::JSpew_Insns, + IPFX "j%s ((%d))\n", MAYBE_PAD, + nameCC(cond), r.m_offset); + return r; + } + + // SSE operations: + + void addsd_rr(XMMRegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "addsd %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, (RegisterID)dst, (RegisterID)src); + } + + void addsd_mr(int offset, RegisterID base, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "addsd %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, (RegisterID)dst, base, offset); + } + + void cvtss2sd_rr(XMMRegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cvtps2pd %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F3); + m_formatter.twoByteOp(OP2_CVTSS2SD_VsdEd, (RegisterID)dst, (RegisterID)src); + } + + void cvtsd2ss_rr(XMMRegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cvtps2pd %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_CVTSD2SS_VsdEd, (RegisterID)dst, (RegisterID)src); + } + + void cvtsi2sd_rr(RegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cvtsi2sd %s, %s\n", MAYBE_PAD, + nameIReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, src); + } + +#if WTF_CPU_X86_64 + void cvtsq2sd_rr(RegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cvtsq2sd %s, %s\n", MAYBE_PAD, + nameIReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp64(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, src); + } +#endif + + void cvtsi2sd_mr(int offset, RegisterID base, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cvtsi2sd %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, base, offset); + } + +#if !WTF_CPU_X86_64 + void cvtsi2sd_mr(void* address, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cvtsi2sd %p, %s\n", MAYBE_PAD, + address, nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, address); + } +#endif + + void cvttsd2si_rr(XMMRegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "cvttsd2si %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameIReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_CVTTSD2SI_GdWsd, dst, (RegisterID)src); + } + + void unpcklps_rr(XMMRegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "unpcklps %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameFPReg(dst)); + m_formatter.twoByteOp(OP2_UNPCKLPS_VsdWsd, (RegisterID)dst, (RegisterID)src); + } + + void movd_rr(RegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movd %s, %s\n", MAYBE_PAD, + nameIReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteOp(OP2_MOVD_VdEd, (RegisterID)dst, src); + } + + void psrldq_rr(XMMRegisterID dest, int shift) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "pslldq %s, %d\n", MAYBE_PAD, + nameFPReg(dest), shift); + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteOp(OP2_PSRLDQ_Vd, (RegisterID)3, (RegisterID)dest); + m_formatter.immediate8(shift); + } + + void movd_rr(XMMRegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movd %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameIReg(dst)); + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteOp(OP2_MOVD_EdVd, (RegisterID)src, dst); + } + +#if WTF_CPU_X86_64 + void movq_rr(XMMRegisterID src, RegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movq %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameIReg(dst)); + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteOp64(OP2_MOVD_EdVd, (RegisterID)src, dst); + } + + void movq_rr(RegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movq %s, %s\n", MAYBE_PAD, + nameIReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteOp64(OP2_MOVD_VdEd, (RegisterID)dst, src); + } +#endif + + void movsd_rm(XMMRegisterID src, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movsd %s, %s0x%x(%s)\n", MAYBE_PAD, + nameFPReg(src), PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, base, offset); + } + + void movss_rm(XMMRegisterID src, int offset, RegisterID base) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movss %s, %s0x%x(%s)\n", MAYBE_PAD, + nameFPReg(src), PRETTY_PRINT_OFFSET(offset), nameIReg(base)); + m_formatter.prefix(PRE_SSE_F3); + m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, base, offset); + } + + void movss_mr(int offset, RegisterID base, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movss %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F3); + m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, base, offset); + } + + void movsd_rm(XMMRegisterID src, int offset, RegisterID base, RegisterID index, int scale) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movsd %s, %d(%s,%s,%d)\n", MAYBE_PAD, + nameFPReg(src), offset, nameIReg(base), nameIReg(index), scale); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, base, index, scale, offset); + } + + void movss_rm(XMMRegisterID src, int offset, RegisterID base, RegisterID index, int scale) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movss %s, %d(%s,%s,%d)\n", MAYBE_PAD, + nameFPReg(src), offset, nameIReg(base), nameIReg(index), scale); + m_formatter.prefix(PRE_SSE_F3); + m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, base, index, scale, offset); + } + + void movss_mr(int offset, RegisterID base, RegisterID index, int scale, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movss %d(%s,%s,%d), %s\n", MAYBE_PAD, + offset, nameIReg(base), nameIReg(index), scale, nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F3); + m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, base, index, scale, offset); + } + + void movsd_mr(int offset, RegisterID base, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movsd %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, base, offset); + } + + void movsd_mr(int offset, RegisterID base, RegisterID index, int scale, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movsd %d(%s,%s,%d), %s\n", MAYBE_PAD, + offset, nameIReg(base), nameIReg(index), scale, nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, base, index, scale, offset); + } + + void movsd_rr(XMMRegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movsd %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, (RegisterID)src); + } + +#if !WTF_CPU_X86_64 + void movsd_mr(const void* address, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "movsd %p, %s\n", MAYBE_PAD, + address, nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, address); + } +#endif + + void mulsd_rr(XMMRegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "mulsd %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_MULSD_VsdWsd, (RegisterID)dst, (RegisterID)src); + } + + void mulsd_mr(int offset, RegisterID base, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "mulsd %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_MULSD_VsdWsd, (RegisterID)dst, base, offset); + } + + void pextrw_irr(int whichWord, XMMRegisterID src, RegisterID dst) + { + FIXME_INSN_PRINTING; + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteOp(OP2_PEXTRW_GdUdIb, (RegisterID)dst, (RegisterID)src); + m_formatter.immediate8(whichWord); + } + + void subsd_rr(XMMRegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "subsd %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_SUBSD_VsdWsd, (RegisterID)dst, (RegisterID)src); + } + + void subsd_mr(int offset, RegisterID base, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "subsd %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_SUBSD_VsdWsd, (RegisterID)dst, base, offset); + } + + void ucomisd_rr(XMMRegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "ucomisd %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteOp(OP2_UCOMISD_VsdWsd, (RegisterID)dst, (RegisterID)src); + } + + void ucomisd_mr(int offset, RegisterID base, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "ucomisd %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteOp(OP2_UCOMISD_VsdWsd, (RegisterID)dst, base, offset); + } + + void divsd_rr(XMMRegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "divsd %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_DIVSD_VsdWsd, (RegisterID)dst, (RegisterID)src); + } + + void divsd_mr(int offset, RegisterID base, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "divsd %s0x%x(%s), %s\n", MAYBE_PAD, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_DIVSD_VsdWsd, (RegisterID)dst, base, offset); + } + + void xorpd_rr(XMMRegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "xorpd %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteOp(OP2_XORPD_VpdWpd, (RegisterID)dst, (RegisterID)src); + } + + void sqrtsd_rr(XMMRegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "sqrtsd %s, %s\n", MAYBE_PAD, + nameFPReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_F2); + m_formatter.twoByteOp(OP2_SQRTSD_VsdWsd, (RegisterID)dst, (RegisterID)src); + } + + void pinsrd_rr(RegisterID src, XMMRegisterID dst) + { + js::JaegerSpew(js::JSpew_Insns, + IPFX "pinsrd $1, %s, %s\n", MAYBE_PAD, + nameIReg(src), nameFPReg(dst)); + m_formatter.prefix(PRE_SSE_66); + m_formatter.threeByteOp(OP3_PINSRD_VsdWsd, (RegisterID)dst, (RegisterID)src); + m_formatter.immediate8(0x01); // the $1 + } + + // Misc instructions: + + void int3() + { + js::JaegerSpew(js::JSpew_Insns, IPFX "int3\n", MAYBE_PAD); + m_formatter.oneByteOp(OP_INT3); + } + + void ret() + { + js::JaegerSpew(js::JSpew_Insns, IPFX "ret\n", MAYBE_PAD); + m_formatter.oneByteOp(OP_RET); + } + + void predictNotTaken() + { + FIXME_INSN_PRINTING; + m_formatter.prefix(PRE_PREDICT_BRANCH_NOT_TAKEN); + } + +#if WTF_CPU_X86 + void pusha() + { + js::JaegerSpew(js::JSpew_Insns, IPFX "pusha\n", MAYBE_PAD); + m_formatter.oneByteOp(OP_PUSHA); + } + + void popa() + { + js::JaegerSpew(js::JSpew_Insns, IPFX "popa\n", MAYBE_PAD); + m_formatter.oneByteOp(OP_POPA); + } +#endif + + // Assembler admin methods: + + JmpDst label() + { + JmpDst r = JmpDst(m_formatter.size()); + js::JaegerSpew(js::JSpew_Insns, + IPFX "#label ((%d))\n", MAYBE_PAD, r.m_offset); + return r; + } + + static JmpDst labelFor(JmpSrc jump, intptr_t offset = 0) + { + FIXME_INSN_PRINTING; + return JmpDst(jump.m_offset + offset); + } + + JmpDst align(int alignment) + { + FIXME_INSN_PRINTING; + while (!m_formatter.isAligned(alignment)) + m_formatter.oneByteOp(OP_HLT); + + return label(); + } + + // Linking & patching: + // + // 'link' and 'patch' methods are for use on unprotected code - such as the code + // within the AssemblerBuffer, and code being patched by the patch buffer. Once + // code has been finalized it is (platform support permitting) within a non- + // writable region of memory; to modify the code in an execute-only execuable + // pool the 'repatch' and 'relink' methods should be used. + + void linkJump(JmpSrc from, JmpDst to) + { + ASSERT(from.m_offset != -1); + ASSERT(to.m_offset != -1); + + js::JaegerSpew(js::JSpew_Insns, + IPFX "##link ((%d)) jumps to ((%d))\n", MAYBE_PAD, + from.m_offset, to.m_offset); + char* code = reinterpret_cast(m_formatter.data()); + setRel32(code + from.m_offset, code + to.m_offset); + } + + static void linkJump(void* code, JmpSrc from, void* to) + { + ASSERT(from.m_offset != -1); + + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##link ((%d)) jumps to ((%p))\n", + from.m_offset, to); + setRel32(reinterpret_cast(code) + from.m_offset, to); + } + + static void linkCall(void* code, JmpSrc from, void* to) + { + ASSERT(from.m_offset != -1); + + FIXME_INSN_PRINTING; + setRel32(reinterpret_cast(code) + from.m_offset, to); + } + + static void linkPointer(void* code, JmpDst where, void* value) + { + ASSERT(where.m_offset != -1); + + FIXME_INSN_PRINTING; + setPointer(reinterpret_cast(code) + where.m_offset, value); + } + + static void relinkJump(void* from, void* to) + { + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##relinkJump ((from=%p)) ((to=%p))\n", + from, to); + setRel32(from, to); + } + + static bool canRelinkJump(void* from, void* to) + { + intptr_t offset = reinterpret_cast(to) - reinterpret_cast(from); + return (offset == static_cast(offset)); + } + + static void relinkCall(void* from, void* to) + { + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##relinkCall ((from=%p)) ((to=%p))\n", + from, to); + setRel32(from, to); + } + + static void repatchInt32(void* where, int32_t value) + { + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##relinkInt32 ((where=%p)) ((value=%d))\n", + where, value); + setInt32(where, value); + } + + static void repatchPointer(void* where, void* value) + { + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##repatchPtr ((where=%p)) ((value=%p))\n", + where, value); + setPointer(where, value); + } + + static void repatchLoadPtrToLEA(void* where) + { + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##repatchLoadPtrToLEA ((where=%p))\n", + where); + +#if WTF_CPU_X86_64 + // On x86-64 pointer memory accesses require a 64-bit operand, and as such a REX prefix. + // Skip over the prefix byte. + where = reinterpret_cast(where) + 1; +#endif + *reinterpret_cast(where) = static_cast(OP_LEA); + } + + static void repatchLEAToLoadPtr(void* where) + { + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##repatchLEAToLoadPtr ((where=%p))\n", + where); +#if WTF_CPU_X86_64 + // On x86-64 pointer memory accesses require a 64-bit operand, and as such a REX prefix. + // Skip over the prefix byte. + where = reinterpret_cast(where) + 1; +#endif + *reinterpret_cast(where) = static_cast(OP_MOV_GvEv); + } + + static unsigned getCallReturnOffset(JmpSrc call) + { + ASSERT(call.m_offset >= 0); + return call.m_offset; + } + + static void* getRelocatedAddress(void* code, JmpSrc jump) + { + ASSERT(jump.m_offset != -1); + + return reinterpret_cast(reinterpret_cast(code) + jump.m_offset); + } + + static void* getRelocatedAddress(void* code, JmpDst destination) + { + ASSERT(destination.m_offset != -1); + + return reinterpret_cast(reinterpret_cast(code) + destination.m_offset); + } + + static int getDifferenceBetweenLabels(JmpDst src, JmpDst dst) + { + return dst.m_offset - src.m_offset; + } + + static int getDifferenceBetweenLabels(JmpDst src, JmpSrc dst) + { + return dst.m_offset - src.m_offset; + } + + static int getDifferenceBetweenLabels(JmpSrc src, JmpDst dst) + { + return dst.m_offset - src.m_offset; + } + + void* executableCopy(ExecutablePool* allocator) + { + void* copy = m_formatter.executableCopy(allocator); + return copy; + } + + void* executableCopy(void* buffer) + { + if (m_formatter.oom()) + return NULL; + return memcpy(buffer, m_formatter.buffer(), size()); + } + +private: + + static void setPointer(void* where, void* value) + { + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##setPtr ((where=%p)) ((value=%p))\n", where, value); + reinterpret_cast(where)[-1] = value; + } + + static void setInt32(void* where, int32_t value) + { + reinterpret_cast(where)[-1] = value; + } + + static void setRel32(void* from, void* to) + { + intptr_t offset = reinterpret_cast(to) - reinterpret_cast(from); + ASSERT(offset == static_cast(offset)); +#define JS_CRASH(x) *(int *)x = 0 + if (offset != static_cast(offset)) + JS_CRASH(0xC0DE); +#undef JS_CRASH + + js::JaegerSpew(js::JSpew_Insns, + ISPFX "##setRel32 ((from=%p)) ((to=%p))\n", from, to); + setInt32(from, offset); + } + + class X86InstructionFormatter { + + static const int maxInstructionSize = 16; + + public: + + // Legacy prefix bytes: + // + // These are emmitted prior to the instruction. + + void prefix(OneByteOpcodeID pre) + { + m_buffer.putByte(pre); + } + + // Word-sized operands / no operand instruction formatters. + // + // In addition to the opcode, the following operand permutations are supported: + // * None - instruction takes no operands. + // * One register - the low three bits of the RegisterID are added into the opcode. + // * Two registers - encode a register form ModRm (for all ModRm formats, the reg field is passed first, and a GroupOpcodeID may be passed in its place). + // * Three argument ModRM - a register, and a register and an offset describing a memory operand. + // * Five argument ModRM - a register, and a base register, an index, scale, and offset describing a memory operand. + // + // For 32-bit x86 targets, the address operand may also be provided as a void*. + // On 64-bit targets REX prefixes will be planted as necessary, where high numbered registers are used. + // + // The twoByteOp methods plant two-byte Intel instructions sequences (first opcode byte 0x0F). + + void oneByteOp(OneByteOpcodeID opcode) + { + m_buffer.ensureSpace(maxInstructionSize); + m_buffer.putByteUnchecked(opcode); + } + + void oneByteOp(OneByteOpcodeID opcode, RegisterID reg) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexIfNeeded(0, 0, reg); + m_buffer.putByteUnchecked(opcode + (reg & 7)); + } + + void oneByteOp(OneByteOpcodeID opcode, int reg, RegisterID rm) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexIfNeeded(reg, 0, rm); + m_buffer.putByteUnchecked(opcode); + registerModRM(reg, rm); + } + + void oneByteOp(OneByteOpcodeID opcode, int reg, RegisterID base, int offset) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexIfNeeded(reg, 0, base); + m_buffer.putByteUnchecked(opcode); + memoryModRM(reg, base, offset); + } + + void oneByteOp_disp32(OneByteOpcodeID opcode, int reg, RegisterID base, int offset) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexIfNeeded(reg, 0, base); + m_buffer.putByteUnchecked(opcode); + memoryModRM_disp32(reg, base, offset); + } + + void oneByteOp(OneByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexIfNeeded(reg, index, base); + m_buffer.putByteUnchecked(opcode); + memoryModRM(reg, base, index, scale, offset); + } + +#if !WTF_CPU_X86_64 + void oneByteOp(OneByteOpcodeID opcode, int reg, void* address) + { + m_buffer.ensureSpace(maxInstructionSize); + m_buffer.putByteUnchecked(opcode); + memoryModRM(reg, address); + } +#endif + + void twoByteOp(TwoByteOpcodeID opcode) + { + m_buffer.ensureSpace(maxInstructionSize); + m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); + m_buffer.putByteUnchecked(opcode); + } + + void twoByteOp(TwoByteOpcodeID opcode, int reg, RegisterID rm) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexIfNeeded(reg, 0, rm); + m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); + m_buffer.putByteUnchecked(opcode); + registerModRM(reg, rm); + } + + void twoByteOp(TwoByteOpcodeID opcode, int reg, RegisterID base, int offset) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexIfNeeded(reg, 0, base); + m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); + m_buffer.putByteUnchecked(opcode); + memoryModRM(reg, base, offset); + } + + void twoByteOp(TwoByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexIfNeeded(reg, index, base); + m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); + m_buffer.putByteUnchecked(opcode); + memoryModRM(reg, base, index, scale, offset); + } + +#if !WTF_CPU_X86_64 + void twoByteOp(TwoByteOpcodeID opcode, int reg, const void* address) + { + m_buffer.ensureSpace(maxInstructionSize); + m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); + m_buffer.putByteUnchecked(opcode); + memoryModRM(reg, address); + } +#endif + + void threeByteOp(ThreeByteOpcodeID opcode, int reg, RegisterID rm) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexIfNeeded(reg, 0, rm); + m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); + m_buffer.putByteUnchecked(OP_3BYTE_ESCAPE); + m_buffer.putByteUnchecked(opcode); + registerModRM(reg, rm); + } + +#if WTF_CPU_X86_64 + // Quad-word-sized operands: + // + // Used to format 64-bit operantions, planting a REX.w prefix. + // When planting d64 or f64 instructions, not requiring a REX.w prefix, + // the normal (non-'64'-postfixed) formatters should be used. + + void oneByteOp64(OneByteOpcodeID opcode) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexW(0, 0, 0); + m_buffer.putByteUnchecked(opcode); + } + + void oneByteOp64(OneByteOpcodeID opcode, RegisterID reg) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexW(0, 0, reg); + m_buffer.putByteUnchecked(opcode + (reg & 7)); + } + + void oneByteOp64(OneByteOpcodeID opcode, int reg, RegisterID rm) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexW(reg, 0, rm); + m_buffer.putByteUnchecked(opcode); + registerModRM(reg, rm); + } + + void oneByteOp64(OneByteOpcodeID opcode, int reg, RegisterID base, int offset) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexW(reg, 0, base); + m_buffer.putByteUnchecked(opcode); + memoryModRM(reg, base, offset); + } + + void oneByteOp64_disp32(OneByteOpcodeID opcode, int reg, RegisterID base, int offset) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexW(reg, 0, base); + m_buffer.putByteUnchecked(opcode); + memoryModRM_disp32(reg, base, offset); + } + + void oneByteOp64(OneByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexW(reg, index, base); + m_buffer.putByteUnchecked(opcode); + memoryModRM(reg, base, index, scale, offset); + } + + void twoByteOp64(TwoByteOpcodeID opcode, int reg, RegisterID rm) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexW(reg, 0, rm); + m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); + m_buffer.putByteUnchecked(opcode); + registerModRM(reg, rm); + } +#endif + + // Byte-operands: + // + // These methods format byte operations. Byte operations differ from the normal + // formatters in the circumstances under which they will decide to emit REX prefixes. + // These should be used where any register operand signifies a byte register. + // + // The disctinction is due to the handling of register numbers in the range 4..7 on + // x86-64. These register numbers may either represent the second byte of the first + // four registers (ah..bh) or the first byte of the second four registers (spl..dil). + // + // Since ah..bh cannot be used in all permutations of operands (specifically cannot + // be accessed where a REX prefix is present), these are likely best treated as + // deprecated. In order to ensure the correct registers spl..dil are selected a + // REX prefix will be emitted for any byte register operand in the range 4..15. + // + // These formatters may be used in instructions where a mix of operand sizes, in which + // case an unnecessary REX will be emitted, for example: + // movzbl %al, %edi + // In this case a REX will be planted since edi is 7 (and were this a byte operand + // a REX would be required to specify dil instead of bh). Unneeded REX prefixes will + // be silently ignored by the processor. + // + // Address operands should still be checked using regRequiresRex(), while byteRegRequiresRex() + // is provided to check byte register operands. + + void oneByteOp8(OneByteOpcodeID opcode, GroupOpcodeID groupOp, RegisterID rm) + { +#if !WTF_CPU_X86_64 + ASSERT(!byteRegRequiresRex(rm)); +#endif + m_buffer.ensureSpace(maxInstructionSize); + emitRexIf(byteRegRequiresRex(rm), 0, 0, rm); + m_buffer.putByteUnchecked(opcode); + registerModRM(groupOp, rm); + } + + void oneByteOp8(OneByteOpcodeID opcode, int reg, RegisterID base, int offset) + { +#if !WTF_CPU_X86_64 + ASSERT(!byteRegRequiresRex(reg)); +#endif + m_buffer.ensureSpace(maxInstructionSize); + emitRexIf(byteRegRequiresRex(reg), reg, 0, base); + m_buffer.putByteUnchecked(opcode); + memoryModRM(reg, base, offset); + } + + void oneByteOp8(OneByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset) + { +#if !WTF_CPU_X86_64 + ASSERT(!byteRegRequiresRex(reg)); +#endif + m_buffer.ensureSpace(maxInstructionSize); + emitRexIf(byteRegRequiresRex(reg), reg, index, base); + m_buffer.putByteUnchecked(opcode); + memoryModRM(reg, base, index, scale, offset); + } + + void twoByteOp8(TwoByteOpcodeID opcode, RegisterID reg, RegisterID rm) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexIf(byteRegRequiresRex(reg)|byteRegRequiresRex(rm), reg, 0, rm); + m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); + m_buffer.putByteUnchecked(opcode); + registerModRM(reg, rm); + } + + void twoByteOp8(TwoByteOpcodeID opcode, GroupOpcodeID groupOp, RegisterID rm) + { + m_buffer.ensureSpace(maxInstructionSize); + emitRexIf(byteRegRequiresRex(rm), 0, 0, rm); + m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); + m_buffer.putByteUnchecked(opcode); + registerModRM(groupOp, rm); + } + + // Immediates: + // + // An immedaite should be appended where appropriate after an op has been emitted. + // The writes are unchecked since the opcode formatters above will have ensured space. + + void immediate8(int imm) + { + m_buffer.putByteUnchecked(imm); + } + + void immediate16(int imm) + { + m_buffer.putShortUnchecked(imm); + } + + void immediate32(int imm) + { + m_buffer.putIntUnchecked(imm); + } + + void immediate64(int64_t imm) + { + m_buffer.putInt64Unchecked(imm); + } + + JmpSrc immediateRel32() + { + m_buffer.putIntUnchecked(0); + return JmpSrc(m_buffer.size()); + } + + // Administrative methods: + + size_t size() const { return m_buffer.size(); } + unsigned char *buffer() const { return m_buffer.buffer(); } + bool oom() const { return m_buffer.oom(); } + bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); } + void* data() const { return m_buffer.data(); } + void* executableCopy(ExecutablePool* allocator) { return m_buffer.executableCopy(allocator); } + + private: + + // Internals; ModRm and REX formatters. + + // Byte operand register spl & above require a REX prefix (to prevent the 'H' registers be accessed). + inline bool byteRegRequiresRex(int reg) + { + return (reg >= X86Registers::esp); + } + + static const RegisterID noBase = X86Registers::ebp; + static const RegisterID hasSib = X86Registers::esp; + static const RegisterID noIndex = X86Registers::esp; +#if WTF_CPU_X86_64 + static const RegisterID noBase2 = X86Registers::r13; + static const RegisterID hasSib2 = X86Registers::r12; + + // Registers r8 & above require a REX prefixe. + inline bool regRequiresRex(int reg) + { + return (reg >= X86Registers::r8); + } + + // Format a REX prefix byte. + inline void emitRex(bool w, int r, int x, int b) + { + m_buffer.putByteUnchecked(PRE_REX | ((int)w << 3) | ((r>>3)<<2) | ((x>>3)<<1) | (b>>3)); + } + + // Used to plant a REX byte with REX.w set (for 64-bit operations). + inline void emitRexW(int r, int x, int b) + { + emitRex(true, r, x, b); + } + + // Used for operations with byte operands - use byteRegRequiresRex() to check register operands, + // regRequiresRex() to check other registers (i.e. address base & index). + // + // NB: WebKit's use of emitRexIf() is limited such that the reqRequiresRex() checks are + // not needed. SpiderMonkey extends oneByteOp8 functionality such that r, x, and b can + // all be used. + inline void emitRexIf(bool condition, int r, int x, int b) + { + if (condition || regRequiresRex(r) || regRequiresRex(x) || regRequiresRex(b)) + emitRex(false, r, x, b); + } + + // Used for word sized operations, will plant a REX prefix if necessary (if any register is r8 or above). + inline void emitRexIfNeeded(int r, int x, int b) + { + emitRexIf(regRequiresRex(r) || regRequiresRex(x) || regRequiresRex(b), r, x, b); + } +#else + // No REX prefix bytes on 32-bit x86. + inline bool regRequiresRex(int) { return false; } + inline void emitRexIf(bool, int, int, int) {} + inline void emitRexIfNeeded(int, int, int) {} +#endif + + enum ModRmMode { + ModRmMemoryNoDisp, + ModRmMemoryDisp8, + ModRmMemoryDisp32, + ModRmRegister + }; + + void putModRm(ModRmMode mode, int reg, RegisterID rm) + { + m_buffer.putByteUnchecked((mode << 6) | ((reg & 7) << 3) | (rm & 7)); + } + + void putModRmSib(ModRmMode mode, int reg, RegisterID base, RegisterID index, int scale) + { + ASSERT(mode != ModRmRegister); + + putModRm(mode, reg, hasSib); + m_buffer.putByteUnchecked((scale << 6) | ((index & 7) << 3) | (base & 7)); + } + + void registerModRM(int reg, RegisterID rm) + { + putModRm(ModRmRegister, reg, rm); + } + + void memoryModRM(int reg, RegisterID base, int offset) + { + // A base of esp or r12 would be interpreted as a sib, so force a sib with no index & put the base in there. +#if WTF_CPU_X86_64 + if ((base == hasSib) || (base == hasSib2)) { +#else + if (base == hasSib) { +#endif + if (!offset) // No need to check if the base is noBase, since we know it is hasSib! + putModRmSib(ModRmMemoryNoDisp, reg, base, noIndex, 0); + else if (CAN_SIGN_EXTEND_8_32(offset)) { + putModRmSib(ModRmMemoryDisp8, reg, base, noIndex, 0); + m_buffer.putByteUnchecked(offset); + } else { + putModRmSib(ModRmMemoryDisp32, reg, base, noIndex, 0); + m_buffer.putIntUnchecked(offset); + } + } else { +#if WTF_CPU_X86_64 + if (!offset && (base != noBase) && (base != noBase2)) +#else + if (!offset && (base != noBase)) +#endif + putModRm(ModRmMemoryNoDisp, reg, base); + else if (CAN_SIGN_EXTEND_8_32(offset)) { + putModRm(ModRmMemoryDisp8, reg, base); + m_buffer.putByteUnchecked(offset); + } else { + putModRm(ModRmMemoryDisp32, reg, base); + m_buffer.putIntUnchecked(offset); + } + } + } + + void memoryModRM_disp32(int reg, RegisterID base, int offset) + { + // A base of esp or r12 would be interpreted as a sib, so force a sib with no index & put the base in there. +#if WTF_CPU_X86_64 + if ((base == hasSib) || (base == hasSib2)) { +#else + if (base == hasSib) { +#endif + putModRmSib(ModRmMemoryDisp32, reg, base, noIndex, 0); + m_buffer.putIntUnchecked(offset); + } else { + putModRm(ModRmMemoryDisp32, reg, base); + m_buffer.putIntUnchecked(offset); + } + } + + void memoryModRM(int reg, RegisterID base, RegisterID index, int scale, int offset) + { + ASSERT(index != noIndex); + +#if WTF_CPU_X86_64 + if (!offset && (base != noBase) && (base != noBase2)) +#else + if (!offset && (base != noBase)) +#endif + putModRmSib(ModRmMemoryNoDisp, reg, base, index, scale); + else if (CAN_SIGN_EXTEND_8_32(offset)) { + putModRmSib(ModRmMemoryDisp8, reg, base, index, scale); + m_buffer.putByteUnchecked(offset); + } else { + putModRmSib(ModRmMemoryDisp32, reg, base, index, scale); + m_buffer.putIntUnchecked(offset); + } + } + +#if !WTF_CPU_X86_64 + void memoryModRM(int reg, const void* address) + { + // noBase + ModRmMemoryNoDisp means noBase + ModRmMemoryDisp32! + putModRm(ModRmMemoryNoDisp, reg, noBase); + m_buffer.putIntUnchecked(reinterpret_cast(address)); + } +#endif + + AssemblerBuffer m_buffer; + } m_formatter; +}; + +} // namespace JSC + +#endif // ENABLE(ASSEMBLER) && CPU(X86) + +#endif // X86Assembler_h diff --git a/js/src/assembler/jit/ExecutableAllocator.cpp b/js/src/assembler/jit/ExecutableAllocator.cpp new file mode 100644 index 0000000..a00c497 --- /dev/null +++ b/js/src/assembler/jit/ExecutableAllocator.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ExecutableAllocator.h" + +#if ENABLE_ASSEMBLER + +namespace JSC { + +size_t ExecutableAllocator::pageSize = 0; + +} + +#endif // HAVE(ASSEMBLER) diff --git a/js/src/assembler/jit/ExecutableAllocator.h b/js/src/assembler/jit/ExecutableAllocator.h new file mode 100644 index 0000000..511aebf --- /dev/null +++ b/js/src/assembler/jit/ExecutableAllocator.h @@ -0,0 +1,466 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ExecutableAllocator_h +#define ExecutableAllocator_h + +#include // for ptrdiff_t +#include +#include "assembler/wtf/Assertions.h" + +#include "jsapi.h" +#include "jsprvtd.h" +#include "jsvector.h" +#include "jslock.h" + +#if WTF_PLATFORM_IPHONE +#include +#include +#endif + +#if WTF_PLATFORM_SYMBIAN +#include +#endif + +#if WTF_CPU_MIPS && WTF_PLATFORM_LINUX +#include +#endif + +#if WTF_PLATFORM_WINCE +// From pkfuncs.h (private header file from the Platform Builder) +#define CACHE_SYNC_ALL 0x07F +extern "C" __declspec(dllimport) void CacheRangeFlush(LPVOID pAddr, DWORD dwLength, DWORD dwFlags); +#endif + +#define JIT_ALLOCATOR_PAGE_SIZE (ExecutableAllocator::pageSize) +/* + * On Windows, VirtualAlloc effectively allocates in 64K chunks. (Technically, + * it allocates in page chunks, but the starting address is always a multiple + * of 64K, so each allocation uses up 64K of address space.) So a size less + * than that would be pointless. But it turns out that 64KB is a reasonable + * size for all platforms. + */ +#define JIT_ALLOCATOR_LARGE_ALLOC_SIZE (ExecutableAllocator::pageSize * 16) + +#if ENABLE_ASSEMBLER_WX_EXCLUSIVE +#define PROTECTION_FLAGS_RW (PROT_READ | PROT_WRITE) +#define PROTECTION_FLAGS_RX (PROT_READ | PROT_EXEC) +#define INITIAL_PROTECTION_FLAGS PROTECTION_FLAGS_RX +#else +#define INITIAL_PROTECTION_FLAGS (PROT_READ | PROT_WRITE | PROT_EXEC) +#endif + +namespace JSC { + +// Something included via windows.h defines a macro with this name, +// which causes the function below to fail to compile. +#ifdef _MSC_VER +# undef max +#endif + +const size_t OVERSIZE_ALLOCATION = size_t(-1); + +inline size_t roundUpAllocationSize(size_t request, size_t granularity) +{ + if ((std::numeric_limits::max() - granularity) <= request) + return OVERSIZE_ALLOCATION; + + // Round up to next page boundary + size_t size = request + (granularity - 1); + size = size & ~(granularity - 1); + JS_ASSERT(size >= request); + return size; +} + +} + +#if ENABLE_ASSEMBLER + +//#define DEBUG_STRESS_JSC_ALLOCATOR + +namespace JSC { + + // These are reference-counted. A new one (from the constructor or create) + // starts with a count of 1. + class ExecutablePool { +private: + struct Allocation { + char* pages; + size_t size; +#if WTF_PLATFORM_SYMBIAN + RChunk* chunk; +#endif + }; + typedef js::Vector AllocationList; + + // Reference count for automatic reclamation. + unsigned m_refCount; + +public: + // It should be impossible for us to roll over, because only small + // pools have multiple holders, and they have one holder per chunk + // of generated code, and they only hold 16KB or so of code. + void addRef() + { + JS_ASSERT(m_refCount); + ++m_refCount; + } + + void release() + { + JS_ASSERT(m_refCount != 0); + if (--m_refCount == 0) + js_delete(this); + } + + static ExecutablePool* create(size_t n) + { + /* We can't (easily) use js_new() here because the constructor is private. */ + void *memory = js_malloc(sizeof(ExecutablePool)); + ExecutablePool *pool = memory ? new(memory) ExecutablePool(n) : NULL; + if (!pool || !pool->m_freePtr) { + js_delete(pool); + return NULL; + } + return pool; + } + + void* alloc(size_t n) + { + JS_ASSERT(m_freePtr <= m_end); + + // Round 'n' up to a multiple of word size; if all allocations are of + // word sized quantities, then all subsequent allocations will be aligned. + n = roundUpAllocationSize(n, sizeof(void*)); + if (n == OVERSIZE_ALLOCATION) + return NULL; + + if (static_cast(n) < (m_end - m_freePtr)) { + void* result = m_freePtr; + m_freePtr += n; + return result; + } + + // Insufficient space to allocate in the existing pool + // so we need allocate into a new pool + return poolAllocate(n); + } + + ~ExecutablePool() + { + Allocation* end = m_pools.end(); + for (Allocation* ptr = m_pools.begin(); ptr != end; ++ptr) + ExecutablePool::systemRelease(*ptr); + } + + size_t available() const { return (m_pools.length() > 1) ? 0 : m_end - m_freePtr; } + + // Flag for downstream use, whether to try to release references to this pool. + bool m_destroy; + + // GC number in which the m_destroy flag was most recently set. Used downstream to + // remember whether m_destroy was computed for the currently active GC. + size_t m_gcNumber; + +private: + // On OOM, this will return an Allocation where pages is NULL. + static Allocation systemAlloc(size_t n); + static void systemRelease(const Allocation& alloc); + + ExecutablePool(size_t n); + + void* poolAllocate(size_t n); + + char* m_freePtr; + char* m_end; + AllocationList m_pools; +}; + +class ExecutableAllocator { + enum ProtectionSeting { Writable, Executable }; + + // Initialization can fail so we use a create method instead. + ExecutableAllocator() {} +public: + static size_t pageSize; + + // Returns NULL on OOM. + static ExecutableAllocator *create() + { + /* We can't (easily) use js_new() here because the constructor is private. */ + void *memory = js_malloc(sizeof(ExecutableAllocator)); + ExecutableAllocator *allocator = memory ? new(memory) ExecutableAllocator() : NULL; + if (!allocator) + return allocator; + + if (!pageSize) + intializePageSize(); + ExecutablePool *pool = ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE); + if (!pool) { + js_delete(allocator); + return NULL; + } + JS_ASSERT(allocator->m_smallAllocationPools.empty()); + allocator->m_smallAllocationPools.append(pool); + return allocator; + } + + ~ExecutableAllocator() + { + for (size_t i = 0; i < m_smallAllocationPools.length(); i++) + js_delete(m_smallAllocationPools[i]); + } + + // poolForSize returns reference-counted objects. The caller owns a reference + // to the object; i.e., poolForSize increments the count before returning the + // object. + + ExecutablePool* poolForSize(size_t n) + { +#ifndef DEBUG_STRESS_JSC_ALLOCATOR + // Try to fit in an existing small allocator. Use the pool with the + // least available space that is big enough (best-fit). This is the + // best strategy because (a) it maximizes the chance of the next + // allocation fitting in a small pool, and (b) it minimizes the + // potential waste when a small pool is next abandoned. + ExecutablePool *minPool = NULL; + for (size_t i = 0; i < m_smallAllocationPools.length(); i++) { + ExecutablePool *pool = m_smallAllocationPools[i]; + if (n <= pool->available() && (!minPool || pool->available() < minPool->available())) + minPool = pool; + } + if (minPool) { + minPool->addRef(); + return minPool; + } +#endif + + // If the request is large, we just provide a unshared allocator + if (n > JIT_ALLOCATOR_LARGE_ALLOC_SIZE) + return ExecutablePool::create(n); + + // Create a new allocator + ExecutablePool* pool = ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE); + if (!pool) + return NULL; + // At this point, local |pool| is the owner. + + if (m_smallAllocationPools.length() < maxSmallPools) { + // We haven't hit the maximum number of live pools; add the new pool. + m_smallAllocationPools.append(pool); + pool->addRef(); + } else { + // Find the pool with the least space. + int iMin = 0; + for (size_t i = 1; i < m_smallAllocationPools.length(); i++) + if (m_smallAllocationPools[i]->available() < + m_smallAllocationPools[iMin]->available()) + { + iMin = i; + } + + // If the new allocator will result in more free space than the small + // pool with the least space, then we will use it instead + ExecutablePool *minPool = m_smallAllocationPools[iMin]; + if ((pool->available() - n) > minPool->available()) { + minPool->release(); + m_smallAllocationPools[iMin] = pool; + pool->addRef(); + } + } + + // Pass ownership to the caller. + return pool; + } + +#if ENABLE_ASSEMBLER_WX_EXCLUSIVE + static void makeWritable(void* start, size_t size) + { + reprotectRegion(start, size, Writable); + } + + static void makeExecutable(void* start, size_t size) + { + reprotectRegion(start, size, Executable); + } +#else + static void makeWritable(void*, size_t) {} + static void makeExecutable(void*, size_t) {} +#endif + + +#if WTF_CPU_X86 || WTF_CPU_X86_64 + static void cacheFlush(void*, size_t) + { + } +#elif WTF_CPU_MIPS + static void cacheFlush(void* code, size_t size) + { +#if WTF_COMPILER_GCC && (GCC_VERSION >= 40300) +#if WTF_MIPS_ISA_REV(2) && (GCC_VERSION < 40403) + int lineSize; + asm("rdhwr %0, $1" : "=r" (lineSize)); + // + // Modify "start" and "end" to avoid GCC 4.3.0-4.4.2 bug in + // mips_expand_synci_loop that may execute synci one more time. + // "start" points to the fisrt byte of the cache line. + // "end" points to the last byte of the line before the last cache line. + // Because size is always a multiple of 4, this is safe to set + // "end" to the last byte. + // + intptr_t start = reinterpret_cast(code) & (-lineSize); + intptr_t end = ((reinterpret_cast(code) + size - 1) & (-lineSize)) - 1; + __builtin___clear_cache(reinterpret_cast(start), reinterpret_cast(end)); +#else + intptr_t end = reinterpret_cast(code) + size; + __builtin___clear_cache(reinterpret_cast(code), reinterpret_cast(end)); +#endif +#else + _flush_cache(reinterpret_cast(code), size, BCACHE); +#endif + } +#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE + static void cacheFlush(void* code, size_t size) + { + sys_dcache_flush(code, size); + sys_icache_invalidate(code, size); + } +#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_LINUX + static void cacheFlush(void* code, size_t size) + { + asm volatile ( + "push {r7}\n" + "mov r0, %0\n" + "mov r1, %1\n" + "movw r7, #0x2\n" + "movt r7, #0xf\n" + "movs r2, #0x0\n" + "svc 0x0\n" + "pop {r7}\n" + : + : "r" (code), "r" (reinterpret_cast(code) + size) + : "r0", "r1", "r2"); + } +#elif WTF_PLATFORM_SYMBIAN + static void cacheFlush(void* code, size_t size) + { + User::IMB_Range(code, static_cast(code) + size); + } +#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT + static __asm void cacheFlush(void* code, size_t size); +#elif WTF_CPU_ARM_TRADITIONAL && (WTF_PLATFORM_LINUX || WTF_PLATFORM_ANDROID) && WTF_COMPILER_GCC + static void cacheFlush(void* code, size_t size) + { + asm volatile ( + "push {r7}\n" + "mov r0, %0\n" + "mov r1, %1\n" + "mov r7, #0xf0000\n" + "add r7, r7, #0x2\n" + "mov r2, #0x0\n" + "svc 0x0\n" + "pop {r7}\n" + : + : "r" (code), "r" (reinterpret_cast(code) + size) + : "r0", "r1", "r2"); + } +#elif WTF_PLATFORM_WINCE + static void cacheFlush(void* code, size_t size) + { + CacheRangeFlush(code, size, CACHE_SYNC_ALL); + } +#else + #error "The cacheFlush support is missing on this platform." +#endif + +private: + +#if ENABLE_ASSEMBLER_WX_EXCLUSIVE + static void reprotectRegion(void*, size_t, ProtectionSeting); +#endif + + static const size_t maxSmallPools = 4; + typedef js::Vector SmallExecPoolVector; + SmallExecPoolVector m_smallAllocationPools; + static void intializePageSize(); +}; + +// This constructor can fail due to OOM. If it does, m_freePtr will be +// set to NULL. +inline ExecutablePool::ExecutablePool(size_t n) : m_refCount(1), m_destroy(false), m_gcNumber(0) +{ + size_t allocSize = roundUpAllocationSize(n, JIT_ALLOCATOR_PAGE_SIZE); + if (allocSize == OVERSIZE_ALLOCATION) { + m_freePtr = NULL; + return; + } +#ifdef DEBUG_STRESS_JSC_ALLOCATOR + Allocation mem = systemAlloc(size_t(4294967291)); +#else + Allocation mem = systemAlloc(allocSize); +#endif + if (!mem.pages) { + m_freePtr = NULL; + return; + } + if (!m_pools.append(mem)) { + systemRelease(mem); + m_freePtr = NULL; + return; + } + m_freePtr = mem.pages; + m_end = m_freePtr + allocSize; +} + +inline void* ExecutablePool::poolAllocate(size_t n) +{ + size_t allocSize = roundUpAllocationSize(n, JIT_ALLOCATOR_PAGE_SIZE); + if (allocSize == OVERSIZE_ALLOCATION) + return NULL; + +#ifdef DEBUG_STRESS_JSC_ALLOCATOR + Allocation result = systemAlloc(size_t(4294967291)); +#else + Allocation result = systemAlloc(allocSize); +#endif + if (!result.pages) + return NULL; + + JS_ASSERT(m_end >= m_freePtr); + if ((allocSize - n) > static_cast(m_end - m_freePtr)) { + // Replace allocation pool + m_freePtr = result.pages + n; + m_end = result.pages + allocSize; + } + + m_pools.append(result); + return result.pages; +} + +} + +#endif // ENABLE(ASSEMBLER) + +#endif // !defined(ExecutableAllocator) diff --git a/js/src/assembler/jit/ExecutableAllocatorOS2.cpp b/js/src/assembler/jit/ExecutableAllocatorOS2.cpp new file mode 100644 index 0000000..217bbc5 --- /dev/null +++ b/js/src/assembler/jit/ExecutableAllocatorOS2.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "ExecutableAllocator.h" + +#if ENABLE_ASSEMBLER && WTF_PLATFORM_OS2 + +#define INCL_DOS +#include + +namespace JSC { + +void ExecutableAllocator::intializePageSize() +{ + ExecutableAllocator::pageSize = 4096u; +} + +ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t n) +{ + void* allocation = NULL; + if (DosAllocMem(&allocation, n, OBJ_ANY|PAG_COMMIT|PAG_READ|PAG_WRITE) && + DosAllocMem(&allocation, n, PAG_COMMIT|PAG_READ|PAG_WRITE)) + CRASH(); + ExecutablePool::Allocation alloc = {reinterpret_cast(allocation), n}; + return alloc; +} + +void ExecutablePool::systemRelease(const ExecutablePool::Allocation& alloc) +{ + DosFreeMem(alloc.pages); +} + +#if ENABLE_ASSEMBLER_WX_EXCLUSIVE +#error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform." +#endif + +} + +#endif // HAVE(ASSEMBLER) diff --git a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp new file mode 100644 index 0000000..43370d2 --- /dev/null +++ b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ExecutableAllocator.h" + +#if ENABLE_ASSEMBLER && WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN + +#include +#include +#include + +namespace JSC { + +void ExecutableAllocator::intializePageSize() +{ + ExecutableAllocator::pageSize = getpagesize(); +} + +ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t n) +{ + void* allocation = mmap(NULL, n, INITIAL_PROTECTION_FLAGS, MAP_PRIVATE | MAP_ANON, VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY, 0); + if (allocation == MAP_FAILED) + allocation = NULL; + ExecutablePool::Allocation alloc = { reinterpret_cast(allocation), n }; + return alloc; +} + +void ExecutablePool::systemRelease(const ExecutablePool::Allocation& alloc) +{ + int result = munmap(alloc.pages, alloc.size); + ASSERT_UNUSED(result, !result); +} + +#if WTF_ENABLE_ASSEMBLER_WX_EXCLUSIVE +void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSeting setting) +{ + if (!pageSize) + intializePageSize(); + + // Calculate the start of the page containing this region, + // and account for this extra memory within size. + intptr_t startPtr = reinterpret_cast(start); + intptr_t pageStartPtr = startPtr & ~(pageSize - 1); + void* pageStart = reinterpret_cast(pageStartPtr); + size += (startPtr - pageStartPtr); + + // Round size up + size += (pageSize - 1); + size &= ~(pageSize - 1); + + mprotect(pageStart, size, (setting == Writable) ? PROTECTION_FLAGS_RW : PROTECTION_FLAGS_RX); +} +#endif + +#if WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX && WTF_COMPILER_RVCT +__asm void ExecutableAllocator::cacheFlush(void* code, size_t size) +{ + ARM + push {r7} + add r1, r1, r0 + mov r7, #0xf0000 + add r7, r7, #0x2 + mov r2, #0x0 + svc #0x0 + pop {r7} + bx lr +} +#endif + +} + +#endif // HAVE(ASSEMBLER) diff --git a/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp b/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp new file mode 100644 index 0000000..305adb2 --- /dev/null +++ b/js/src/assembler/jit/ExecutableAllocatorSymbian.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 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 + * + */ + +#include "config.h" + +#include "ExecutableAllocator.h" + +#if ENABLE_ASSEMBLER && WTF_PLATFORM_SYMBIAN + +#include +#include + +// Set the page size to 256 Kb to compensate for moving memory model limitation +const size_t MOVING_MEM_PAGE_SIZE = 256 * 1024; + +namespace JSC { + +void ExecutableAllocator::intializePageSize() +{ +#if WTF_CPU_ARMV5_OR_LOWER + // The moving memory model (as used in ARMv5 and earlier platforms) + // on Symbian OS limits the number of chunks for each process to 16. + // To mitigate this limitation increase the pagesize to + // allocate less of larger chunks. + ExecutableAllocator::pageSize = MOVING_MEM_PAGE_SIZE; +#else + TInt page_size; + UserHal::PageSizeInBytes(page_size); + ExecutableAllocator::pageSize = page_size; +#endif +} + +ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t n) +{ + RChunk* codeChunk = new RChunk(); + + TInt errorCode = codeChunk->CreateLocalCode(n, n); + + char* allocation = reinterpret_cast(codeChunk->Base()); + ExecutablePool::Allocation alloc = { allocation, n, codeChunk }; + return alloc; +} + +void ExecutablePool::systemRelease(const ExecutablePool::Allocation& alloc) +{ + alloc.chunk->Close(); + delete alloc.chunk; +} + +#if ENABLE_ASSEMBLER_WX_EXCLUSIVE +#error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform." +#endif + +} + +#endif // HAVE(ASSEMBLER) diff --git a/js/src/assembler/jit/ExecutableAllocatorWin.cpp b/js/src/assembler/jit/ExecutableAllocatorWin.cpp new file mode 100644 index 0000000..e59564a --- /dev/null +++ b/js/src/assembler/jit/ExecutableAllocatorWin.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "ExecutableAllocator.h" + +#if ENABLE_ASSEMBLER && WTF_PLATFORM_WIN_OS + +#include "jswin.h" + +namespace JSC { + +void ExecutableAllocator::intializePageSize() +{ + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + ExecutableAllocator::pageSize = system_info.dwPageSize; +} + +ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t n) +{ + void *allocation = VirtualAlloc(0, n, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + ExecutablePool::Allocation alloc = {reinterpret_cast(allocation), n}; + return alloc; +} + +void ExecutablePool::systemRelease(const ExecutablePool::Allocation& alloc) +{ + VirtualFree(alloc.pages, 0, MEM_RELEASE); +} + +#if ENABLE_ASSEMBLER_WX_EXCLUSIVE +#error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform." +#endif + +} + +#endif // HAVE(ASSEMBLER) diff --git a/js/src/assembler/moco/MocoStubs.h b/js/src/assembler/moco/MocoStubs.h new file mode 100644 index 0000000..584595b --- /dev/null +++ b/js/src/assembler/moco/MocoStubs.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=79 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Julian Seward + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _include_assembler_moco_stubs_h_ +#define _include_assembler_moco_stubs_h_ + +namespace JSC { + +class JITCode { +public: + JITCode(void* start, size_t size) + : m_start(start), m_size(size) + { } + JITCode() { } + void* start() const { return m_start; } + size_t size() const { return m_size; } +private: + void* m_start; + size_t m_size; +}; + +class CodeBlock { +public: + CodeBlock(JITCode& jc) + : m_jitcode(jc) + { + } + JITCode& getJITCode() { return m_jitcode; } +private: + JITCode& m_jitcode; +}; + +} // namespace JSC + +#endif /* _include_assembler_moco_stubs_h_ */ + diff --git a/js/src/assembler/wtf/Assertions.cpp b/js/src/assembler/wtf/Assertions.cpp new file mode 100644 index 0000000..7dcba64 --- /dev/null +++ b/js/src/assembler/wtf/Assertions.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Assertions.h" + +#include +#include +#include + +#if WTF_COMPILER_MSVC && !WTF_PLATFORM_WINCE +#ifndef WINVER +#define WINVER 0x0500 +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif +#include "jswin.h" +#include +#endif + +#if WTF_PLATFORM_WINCE +#include +#endif + +extern "C" { + +WTF_ATTRIBUTE_PRINTF(1, 0) +static void vprintf_stderr_common(const char* format, va_list args) +{ + vfprintf(stderr, format, args); +} + +WTF_ATTRIBUTE_PRINTF(1, 2) +static void printf_stderr_common(const char* format, ...) +{ + va_list args; + va_start(args, format); + vprintf_stderr_common(format, args); + va_end(args); +} + +static void printCallSite(const char* file, int line, const char* function) +{ +#if WTF_COMPILER_MSVC && !WTF_PLATFORM_WINCE && defined _DEBUG + _CrtDbgReport(_CRT_WARN, file, line, NULL, "%s\n", function); +#else + printf_stderr_common("(%s:%d %s)\n", file, line, function); +#endif +} + +void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion) +{ + if (assertion) + printf_stderr_common("ASSERTION FAILED: %s\n", assertion); + else + printf_stderr_common("SHOULD NEVER BE REACHED\n"); + printCallSite(file, line, function); +} + +void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...) +{ + printf_stderr_common("ASSERTION FAILED: "); + va_list args; + va_start(args, format); + vprintf_stderr_common(format, args); + va_end(args); + printf_stderr_common("\n%s\n", assertion); + printCallSite(file, line, function); +} + +void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion) +{ + printf_stderr_common("ARGUMENT BAD: %s, %s\n", argName, assertion); + printCallSite(file, line, function); +} + +void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...) +{ + printf_stderr_common("FATAL ERROR: "); + va_list args; + va_start(args, format); + vprintf_stderr_common(format, args); + va_end(args); + printf_stderr_common("\n"); + printCallSite(file, line, function); +} + +void WTFReportError(const char* file, int line, const char* function, const char* format, ...) +{ + printf_stderr_common("ERROR: "); + va_list args; + va_start(args, format); + vprintf_stderr_common(format, args); + va_end(args); + printf_stderr_common("\n"); + printCallSite(file, line, function); +} + +void WTFLog(WTFLogChannel* channel, const char* format, ...) +{ + if (channel->state != WTFLogChannelOn) + return; + + va_list args; + va_start(args, format); + vprintf_stderr_common(format, args); + va_end(args); + if (format[strlen(format) - 1] != '\n') + printf_stderr_common("\n"); +} + +void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...) +{ + if (channel->state != WTFLogChannelOn) + return; + + va_list args; + va_start(args, format); + vprintf_stderr_common(format, args); + va_end(args); + if (format[strlen(format) - 1] != '\n') + printf_stderr_common("\n"); + printCallSite(file, line, function); +} + +} // extern "C" diff --git a/js/src/assembler/wtf/Assertions.h b/js/src/assembler/wtf/Assertions.h new file mode 100644 index 0000000..535600c --- /dev/null +++ b/js/src/assembler/wtf/Assertions.h @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WTF_Assertions_h +#define WTF_Assertions_h + +/* + no namespaces because this file has to be includable from C and Objective-C + + Note, this file uses many GCC extensions, but it should be compatible with + C, Objective C, C++, and Objective C++. + + For non-debug builds, everything is disabled by default. + Defining any of the symbols explicitly prevents this from having any effect. + + MSVC7 note: variadic macro support was added in MSVC8, so for now we disable + those macros in MSVC7. For more info, see the MSDN document on variadic + macros here: + + http://msdn2.microsoft.com/en-us/library/ms177415(VS.80).aspx +*/ + +#include "Platform.h" + +#if WTF_COMPILER_MSVC +#include +#else +#include +#endif + +#if WTF_PLATFORM_SYMBIAN +#include +#include +#endif + +#ifdef NDEBUG +#define ASSERTIONS_DISABLED_DEFAULT 1 +#else +#define ASSERTIONS_DISABLED_DEFAULT 0 +#endif + +#ifndef ASSERT_DISABLED +#define ASSERT_DISABLED ASSERTIONS_DISABLED_DEFAULT +#endif + +#ifndef ASSERT_ARG_DISABLED +#define ASSERT_ARG_DISABLED ASSERTIONS_DISABLED_DEFAULT +#endif + +#ifndef FATAL_DISABLED +#define FATAL_DISABLED ASSERTIONS_DISABLED_DEFAULT +#endif + +#ifndef ERROR_DISABLED +#define ERROR_DISABLED ASSERTIONS_DISABLED_DEFAULT +#endif + +#ifndef LOG_DISABLED +#define LOG_DISABLED ASSERTIONS_DISABLED_DEFAULT +#endif + +#if WTF_COMPILER_GCC +#define WTF_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#else +#define WTF_PRETTY_FUNCTION __FUNCTION__ +#endif + +/* WTF logging functions can process %@ in the format string to log a NSObject* but the printf format attribute + emits a warning when %@ is used in the format string. Until is resolved we can't include + the attribute when being used from Objective-C code in case it decides to use %@. */ +#if WTF_COMPILER_GCC && !defined(__OBJC__) +#define WTF_ATTRIBUTE_PRINTF(formatStringArgument, extraArguments) __attribute__((__format__(printf, formatStringArgument, extraArguments))) +#else +#define WTF_ATTRIBUTE_PRINTF(formatStringArgument, extraArguments) +#endif + +/* These helper functions are always declared, but not necessarily always defined if the corresponding function is disabled. */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { WTFLogChannelOff, WTFLogChannelOn } WTFLogChannelState; + +typedef struct { + unsigned mask; + const char *defaultName; + WTFLogChannelState state; +} WTFLogChannel; + +void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion); +void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...) WTF_ATTRIBUTE_PRINTF(5, 6); +void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion); +void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...) WTF_ATTRIBUTE_PRINTF(4, 5); +void WTFReportError(const char* file, int line, const char* function, const char* format, ...) WTF_ATTRIBUTE_PRINTF(4, 5); +void WTFLog(WTFLogChannel* channel, const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3); +void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...) WTF_ATTRIBUTE_PRINTF(5, 6); + +#ifdef __cplusplus +} +#endif + +/* CRASH -- gets us into the debugger or the crash reporter -- signals are ignored by the crash reporter so we must do better */ + +#ifndef CRASH +#if WTF_PLATFORM_SYMBIAN +#define CRASH() do { \ + __DEBUGGER(); \ + User::Panic(_L("Webkit CRASH"),0); \ + } while(false) +#else +#define CRASH() do { \ + *(int *)(uintptr_t)0xbbadbeef = 0; \ + ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \ +} while(false) +#endif +#endif + +/* ASSERT, ASSERT_WITH_MESSAGE, ASSERT_NOT_REACHED */ + +#if WTF_PLATFORM_WINCE && !WTF_PLATFORM_TORCHMOBILE +/* FIXME: We include this here only to avoid a conflict with the ASSERT macro. */ +#include "jswin.h" +#undef min +#undef max +#undef ERROR +#endif + +#if WTF_PLATFORM_WIN_OS || WTF_PLATFORM_SYMBIAN +/* FIXME: Change to use something other than ASSERT to avoid this conflict with the underlying platform */ +#undef ASSERT +#endif + +#if ASSERT_DISABLED + +#define ASSERT(assertion) ((void)0) +#if WTF_COMPILER_MSVC7 +#define ASSERT_WITH_MESSAGE(assertion) ((void)0) +#elif WTF_COMPILER_WINSCW +#define ASSERT_WITH_MESSAGE(assertion, arg...) ((void)0) +#else +#define ASSERT_WITH_MESSAGE(assertion, ...) ((void)0) +#endif /* COMPILER(MSVC7) */ +#define ASSERT_NOT_REACHED() ((void)0) +#define ASSERT_UNUSED(variable, assertion) ((void)variable) + +#else + +#define ASSERT(assertion) do \ + if (!(assertion)) { \ + WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \ + CRASH(); \ + } \ +while (0) +#if WTF_COMPILER_MSVC7 +#define ASSERT_WITH_MESSAGE(assertion) ((void)0) +#elif WTF_COMPILER_WINSCW +#define ASSERT_WITH_MESSAGE(assertion, arg...) ((void)0) +#else +#define ASSERT_WITH_MESSAGE(assertion, ...) do \ + if (!(assertion)) { \ + WTFReportAssertionFailureWithMessage(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion, __VA_ARGS__); \ + CRASH(); \ + } \ +while (0) +#endif /* COMPILER(MSVC7) */ +#define ASSERT_NOT_REACHED() do { \ + WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, 0); \ + CRASH(); \ +} while (0) + +#define ASSERT_UNUSED(variable, assertion) ASSERT(assertion) + +#endif + +/* ASSERT_ARG */ + +#if ASSERT_ARG_DISABLED + +#define ASSERT_ARG(argName, assertion) ((void)0) + +#else + +#define ASSERT_ARG(argName, assertion) do \ + if (!(assertion)) { \ + WTFReportArgumentAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #argName, #assertion); \ + CRASH(); \ + } \ +while (0) + +#endif + +/* COMPILE_ASSERT */ +#ifndef COMPILE_ASSERT +#define COMPILE_ASSERT(exp, name) typedef int dummy##name [(exp) ? 1 : -1] +#endif + +/* FATAL */ + +#if FATAL_DISABLED && !WTF_COMPILER_MSVC7 && !WTF_COMPILER_WINSCW +#define FATAL(...) ((void)0) +#elif WTF_COMPILER_MSVC7 +#define FATAL() ((void)0) +#else +#define FATAL(...) do { \ + WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, __VA_ARGS__); \ + CRASH(); \ +} while (0) +#endif + +/* LOG_ERROR */ + +#if ERROR_DISABLED && !WTF_COMPILER_MSVC7 && !WTF_COMPILER_WINSCW +#define LOG_ERROR(...) ((void)0) +#elif WTF_COMPILER_MSVC7 +#define LOG_ERROR() ((void)0) +#elif WTF_COMPILER_WINSCW +#define LOG_ERROR(arg...) ((void)0) +#else +#define LOG_ERROR(...) WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, __VA_ARGS__) +#endif + +/* LOG */ + +#if LOG_DISABLED && !WTF_COMPILER_MSVC7 && !WTF_COMPILER_WINSCW +#define LOG(channel, ...) ((void)0) +#elif WTF_COMPILER_MSVC7 +#define LOG() ((void)0) +#elif WTF_COMPILER_WINSCW +#define LOG(arg...) ((void)0) +#else +#define LOG(channel, ...) WTFLog(&JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, channel), __VA_ARGS__) +#define JOIN_LOG_CHANNEL_WITH_PREFIX(prefix, channel) JOIN_LOG_CHANNEL_WITH_PREFIX_LEVEL_2(prefix, channel) +#define JOIN_LOG_CHANNEL_WITH_PREFIX_LEVEL_2(prefix, channel) prefix ## channel +#endif + +/* LOG_VERBOSE */ + +#if LOG_DISABLED && !WTF_COMPILER_MSVC7 && !WTF_COMPILER_WINSCW +#define LOG_VERBOSE(channel, ...) ((void)0) +#elif WTF_COMPILER_MSVC7 +#define LOG_VERBOSE(channel) ((void)0) +#elif WTF_COMPILER_WINSCW +#define LOG_VERBOSE(channel, arg...) ((void)0) +#else +#define LOG_VERBOSE(channel, ...) WTFLogVerbose(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, &JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, channel), __VA_ARGS__) +#endif + +#endif /* WTF_Assertions_h */ diff --git a/js/src/assembler/wtf/Platform.h b/js/src/assembler/wtf/Platform.h new file mode 100644 index 0000000..3dfad2a --- /dev/null +++ b/js/src/assembler/wtf/Platform.h @@ -0,0 +1,996 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WTF_Platform_h +#define WTF_Platform_h + +/* Either XX(YY) --> WTF_XX_YY or XX(YY) --> XX_YY, depending on XX + + PLATFORM(YY) --> WTF_PLATFORM_YY + COMPILER(YY) --> WTF_COMPILER_YY + CPU(YY) --> WTF_CPU_YY + OS(YY) --> WTF_OS_YY + USE(YY) --> WTF_USE_YY + + HAVE(YY) --> HAVE_YY + ENABLE(YY) --> ENABLE_YY +*/ + +/* ==== PLATFORM handles OS, operating environment, graphics API, and + CPU. This macro will be phased out in favor of platform adaptation + macros, policy decision macros, and top-level port definitions. ==== */ +//#define PLATFORM(WTF_FEATURE) (defined(WTF_PLATFORM_##WTF_FEATURE) && WTF_PLATFORM_##WTF_FEATURE) + + +/* ==== Platform adaptation macros: these describe properties of the target environment. ==== */ + +/* COMPILER() - the compiler being used to build the project */ +//#define COMPILER(WTF_FEATURE) (defined(WTF_COMPILER_##WTF_FEATURE) && WTF_COMPILER_##WTF_FEATURE) +/* CPU() - the target CPU architecture */ +//#define CPU(WTF_FEATURE) (defined(WTF_CPU_##WTF_FEATURE) && WTF_CPU_##WTF_FEATURE) +/* HAVE() - specific system features (headers, functions or similar) that are present or not */ +//#define HAVE(WTF_FEATURE) (defined(HAVE_##WTF_FEATURE) && HAVE_##WTF_FEATURE) +/* OS() - underlying operating system; only to be used for mandated low-level services like + virtual memory, not to choose a GUI toolkit */ +//#define OS(WTF_FEATURE) (defined(WTF_OS_##WTF_FEATURE) && WTF_OS_##WTF_FEATURE) + + +/* ==== Policy decision macros: these define policy choices for a particular port. ==== */ + +/* USE() - use a particular third-party library or optional OS service */ +//#define USE(WTF_FEATURE) (defined(WTF_USE_##WTF_FEATURE) && WTF_USE_##WTF_FEATURE) +/* ENABLE() - turn on a specific feature of WebKit */ +//#define ENABLE(WTF_FEATURE) (defined(ENABLE_##WTF_FEATURE) && ENABLE_##WTF_FEATURE) + + + +/* ==== COMPILER() - the compiler being used to build the project ==== */ + +/* COMPILER(MSVC) Microsoft Visual C++ */ +/* COMPILER(MSVC7) Microsoft Visual C++ v7 or lower*/ +#if defined(_MSC_VER) +#define WTF_COMPILER_MSVC 1 +#if _MSC_VER < 1400 +#define WTF_COMPILER_MSVC7 1 +#endif +#endif + +/* COMPILER(RVCT) - ARM RealView Compilation Tools */ +#if defined(__CC_ARM) || defined(__ARMCC__) +#define WTF_COMPILER_RVCT 1 +#endif + +/* COMPILER(GCC) - GNU Compiler Collection */ +/* --gnu option of the RVCT compiler also defines __GNUC__ */ +#if defined(__GNUC__) && !WTF_COMPILER_RVCT +#define WTF_COMPILER_GCC 1 +#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +/* COMPILER(MINGW) - MinGW GCC */ +#if defined(MINGW) || defined(__MINGW32__) +#define WTF_COMPILER_MINGW 1 +#endif + +/* COMPILER(WINSCW) - CodeWarrior for Symbian emulator */ +#if defined(__WINSCW__) +#define WTF_COMPILER_WINSCW 1 +#endif + +/* COMPILER(SUNPRO) - Sun Studio for Solaris */ +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#define WTF_COMPILER_SUNPRO 1 +#endif + + +/* ==== CPU() - the target CPU architecture ==== */ + +/* This also defines CPU(BIG_ENDIAN) or CPU(MIDDLE_ENDIAN) or neither, as appropriate. */ + + +/* CPU(ALPHA) - DEC Alpha */ +#if defined(__alpha__) +#define WTF_CPU_ALPHA 1 +#endif + +/* CPU(IA64) - Itanium / IA-64 */ +#if defined(__ia64__) +#define WTF_CPU_IA64 1 +#endif + +/* CPU(PPC) - PowerPC 32-bit */ +#if defined(__ppc__) \ + || defined(__PPC__) \ + || defined(__powerpc__) \ + || defined(__powerpc) \ + || defined(__POWERPC__) \ + || defined(_M_PPC) \ + || defined(__PPC) +#define WTF_CPU_PPC 1 +#define WTF_CPU_BIG_ENDIAN 1 +#endif + +/* CPU(PPC64) - PowerPC 64-bit */ +#if defined(__ppc64__) \ + || defined(__PPC64__) +#define WTF_CPU_PPC64 1 +#define WTF_CPU_BIG_ENDIAN 1 +#endif + +/* CPU(SH4) - SuperH SH-4 */ +#if defined(__SH4__) +#define WTF_CPU_SH4 1 +#endif + +/* CPU(SPARC32) - SPARC 32-bit */ +#if defined(__sparc) && !defined(__arch64__) || defined(__sparcv8) +#define WTF_CPU_SPARC32 1 +#define WTF_CPU_BIG_ENDIAN 1 +#endif + +/* CPU(SPARC64) - SPARC 64-bit */ +#if defined(__sparc__) && defined(__arch64__) || defined (__sparcv9) +#define WTF_CPU_SPARC64 1 +#define WTF_CPU_BIG_ENDIAN 1 +#endif + +/* CPU(SPARC) - any SPARC, true for CPU(SPARC32) and CPU(SPARC64) */ +#if WTF_CPU_SPARC32 || WTF_CPU_SPARC64 +#define WTF_CPU_SPARC +#endif + +/* CPU(X86) - i386 / x86 32-bit */ +#if defined(__i386__) \ + || defined(i386) \ + || defined(_M_IX86) \ + || defined(_X86_) \ + || defined(__THW_INTEL) +#define WTF_CPU_X86 1 +#endif + +/* CPU(X86_64) - AMD64 / Intel64 / x86_64 64-bit */ +#if defined(__x86_64__) \ + || defined(_M_X64) +#define WTF_CPU_X86_64 1 +#endif + +/* CPU(ARM) - ARM, any version*/ +#if defined(arm) \ + || defined(__arm__) +#define WTF_CPU_ARM 1 + +#if defined(__ARMEB__) +#define WTF_CPU_BIG_ENDIAN 1 + +#elif !defined(__ARM_EABI__) \ + && !defined(__EABI__) \ + && !defined(__VFP_FP__) \ + && !defined(ANDROID) +#define WTF_CPU_MIDDLE_ENDIAN 1 + +#endif + +#define WTF_ARM_ARCH_AT_LEAST(N) (WTF_CPU_ARM && WTF_ARM_ARCH_VERSION >= N) + +/* Set WTF_ARM_ARCH_VERSION */ +#if defined(__ARM_ARCH_4__) \ + || defined(__ARM_ARCH_4T__) \ + || defined(__MARM_ARMV4__) \ + || defined(_ARMV4I_) +#define WTF_ARM_ARCH_VERSION 4 + +#elif defined(__ARM_ARCH_5__) \ + || defined(__ARM_ARCH_5T__) \ + || defined(__ARM_ARCH_5E__) \ + || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) \ + || defined(__MARM_ARMV5__) +#define WTF_ARM_ARCH_VERSION 5 + +#elif defined(__ARM_ARCH_6__) \ + || defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6K__) \ + || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6ZK__) \ + || defined(__ARM_ARCH_6T2__) \ + || defined(__ARMV6__) +#define WTF_ARM_ARCH_VERSION 6 + +#elif defined(__ARM_ARCH_7A__) \ + || defined(__ARM_ARCH_7R__) +#define WTF_ARM_ARCH_VERSION 7 + +/* RVCT sets _TARGET_ARCH_ARM */ +#elif defined(__TARGET_ARCH_ARM) +#define WTF_ARM_ARCH_VERSION __TARGET_ARCH_ARM + +#else +#define WTF_ARM_ARCH_VERSION 0 + +#endif + +/* Set WTF_THUMB_ARCH_VERSION */ +#if defined(__ARM_ARCH_4T__) +#define WTF_THUMB_ARCH_VERSION 1 + +#elif defined(__ARM_ARCH_5T__) \ + || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) +#define WTF_THUMB_ARCH_VERSION 2 + +#elif defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6K__) \ + || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6ZK__) \ + || defined(__ARM_ARCH_6M__) +#define WTF_THUMB_ARCH_VERSION 3 + +#elif defined(__ARM_ARCH_6T2__) \ + || defined(__ARM_ARCH_7__) \ + || defined(__ARM_ARCH_7A__) \ + || defined(__ARM_ARCH_7R__) \ + || defined(__ARM_ARCH_7M__) +#define WTF_THUMB_ARCH_VERSION 4 + +/* RVCT sets __TARGET_ARCH_THUMB */ +#elif defined(__TARGET_ARCH_THUMB) +#define WTF_THUMB_ARCH_VERSION __TARGET_ARCH_THUMB + +#else +#define WTF_THUMB_ARCH_VERSION 0 +#endif + + +/* CPU(ARMV5_OR_LOWER) - ARM instruction set v5 or earlier */ +/* On ARMv5 and below the natural alignment is required. + And there are some other differences for v5 or earlier. */ +#if !defined(ARMV5_OR_LOWER) /* && !CPU_ARM_ARCH_AT_LEAST(6) */ +#define WTF_CPU_ARMV5_OR_LOWER 1 +#endif + + +/* CPU(ARM_TRADITIONAL) - Thumb2 is not available, only traditional ARM (v4 or greater) */ +/* CPU(ARM_THUMB2) - Thumb2 instruction set is available */ +/* Only one of these will be defined. */ +#if !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2) +# if defined(thumb2) || defined(__thumb2__) \ + || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4) +# define WTF_CPU_ARM_TRADITIONAL 1 +# define WTF_CPU_ARM_THUMB2 0 +# elif WTF_ARM_ARCH_AT_LEAST(4) +# define WTF_CPU_ARM_TRADITIONAL 1 +# define WTF_CPU_ARM_THUMB2 0 +# else +# error "Not supported ARM architecture" +# endif +#elif WTF_CPU_ARM_TRADITIONAL && WTF_CPU_ARM_THUMB2 /* Sanity Check */ +# error "Cannot use both of WTF_CPU_ARM_TRADITIONAL and WTF_CPU_ARM_THUMB2 platforms" +#endif // !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2) + +#endif /* ARM */ + + + +/* Operating systems - low-level dependencies */ + +/* PLATFORM(DARWIN) */ +/* Operating system level dependencies for Mac OS X / Darwin that should */ +/* be used regardless of operating environment */ +#ifdef __APPLE__ +#define WTF_PLATFORM_DARWIN 1 +#include +#if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 +#define BUILDING_ON_TIGER 1 +#elif !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 +#define BUILDING_ON_LEOPARD 1 +#elif !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 +#define BUILDING_ON_SNOW_LEOPARD 1 +#endif +#if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 +#define TARGETING_TIGER 1 +#elif !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 +#define TARGETING_LEOPARD 1 +#elif !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7 +#define TARGETING_SNOW_LEOPARD 1 +#endif +#include +#endif + +/* PLATFORM(WIN_OS) */ +/* Operating system level dependencies for Windows that should be used */ +/* regardless of operating environment */ +#if defined(WIN32) || defined(_WIN32) +#define WTF_PLATFORM_WIN_OS 1 +#endif + +/* PLATFORM(WINCE) */ +/* Operating system level dependencies for Windows CE that should be used */ +/* regardless of operating environment */ +/* Note that for this platform PLATFORM(WIN_OS) is also defined. */ +#if defined(_WIN32_WCE) +#define WTF_PLATFORM_WINCE 1 +#endif + +/* PLATFORM(LINUX) */ +/* Operating system level dependencies for Linux-like systems that */ +/* should be used regardless of operating environment */ +#ifdef __linux__ +#define WTF_PLATFORM_LINUX 1 +#endif + +/* PLATFORM(FREEBSD) */ +/* Operating system level dependencies for FreeBSD-like systems that */ +/* should be used regardless of operating environment */ +#ifdef __FreeBSD__ +#define WTF_PLATFORM_FREEBSD 1 +#endif + +/* PLATFORM(OPENBSD) */ +/* Operating system level dependencies for OpenBSD systems that */ +/* should be used regardless of operating environment */ +#ifdef __OpenBSD__ +#define WTF_PLATFORM_OPENBSD 1 +#endif + +/* PLATFORM(SOLARIS) */ +/* Operating system level dependencies for Solaris that should be used */ +/* regardless of operating environment */ +#if defined(sun) || defined(__sun) +#define WTF_PLATFORM_SOLARIS 1 +#endif + +/* PLATFORM(OS2) */ +/* Operating system level dependencies for OS/2 that should be used */ +/* regardless of operating environment */ +#if defined(OS2) || defined(__OS2__) +#define WTF_PLATFORM_OS2 1 +#endif + +#if defined (__SYMBIAN32__) +/* we are cross-compiling, it is not really windows */ +#undef WTF_PLATFORM_WIN_OS +#undef WTF_PLATFORM_WIN +#define WTF_PLATFORM_SYMBIAN 1 +#endif + + +/* PLATFORM(NETBSD) */ +/* Operating system level dependencies for NetBSD that should be used */ +/* regardless of operating environment */ +#if defined(__NetBSD__) +#define WTF_PLATFORM_NETBSD 1 +#endif + +/* PLATFORM(QNX) */ +/* Operating system level dependencies for QNX that should be used */ +/* regardless of operating environment */ +#if defined(__QNXNTO__) +#define WTF_PLATFORM_QNX 1 +#endif + +/* PLATFORM(UNIX) */ +/* Operating system level dependencies for Unix-like systems that */ +/* should be used regardless of operating environment */ +#if WTF_PLATFORM_DARWIN \ + || WTF_PLATFORM_FREEBSD \ + || WTF_PLATFORM_SYMBIAN \ + || WTF_PLATFORM_NETBSD \ + || defined(unix) \ + || defined(__unix) \ + || defined(__unix__) \ + || defined(_AIX) \ + || defined(__HAIKU__) \ + || defined(__QNXNTO__) \ + || defined(ANDROID) +#define WTF_PLATFORM_UNIX 1 +#endif + +/* Operating environments */ + +/* PLATFORM(CHROMIUM) */ +/* PLATFORM(QT) */ +/* PLATFORM(WX) */ +/* PLATFORM(GTK) */ +/* PLATFORM(HAIKU) */ +/* PLATFORM(MAC) */ +/* PLATFORM(WIN) */ +#if defined(BUILDING_CHROMIUM__) +#define WTF_PLATFORM_CHROMIUM 1 +#elif defined(BUILDING_QT__) +#define WTF_PLATFORM_QT 1 +#elif defined(BUILDING_WX__) +#define WTF_PLATFORM_WX 1 +#elif defined(BUILDING_GTK__) +#define WTF_PLATFORM_GTK 1 +#elif defined(BUILDING_HAIKU__) +#define WTF_PLATFORM_HAIKU 1 +#elif WTF_PLATFORM_DARWIN +#define WTF_PLATFORM_MAC 1 +#elif WTF_PLATFORM_WIN_OS +#define WTF_PLATFORM_WIN 1 +#endif + +/* PLATFORM(IPHONE) */ +#if (defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) +#define WTF_PLATFORM_IPHONE 1 +#endif + +/* PLATFORM(IPHONE_SIMULATOR) */ +#if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR +#define WTF_PLATFORM_IPHONE 1 +#define WTF_PLATFORM_IPHONE_SIMULATOR 1 +#else +#define WTF_PLATFORM_IPHONE_SIMULATOR 0 +#endif + +#if !defined(WTF_PLATFORM_IPHONE) +#define WTF_PLATFORM_IPHONE 0 +#endif + +/* PLATFORM(ANDROID) */ +#if defined(ANDROID) +#define WTF_PLATFORM_ANDROID 1 +#endif + +/* Graphics engines */ + +/* PLATFORM(CG) and PLATFORM(CI) */ +#if WTF_PLATFORM_MAC || WTF_PLATFORM_IPHONE +#define WTF_PLATFORM_CG 1 +#endif +#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE +#define WTF_PLATFORM_CI 1 +#endif + +/* PLATFORM(SKIA) for Win/Linux, CG/CI for Mac */ +#if WTF_PLATFORM_CHROMIUM +#if WTF_PLATFORM_DARWIN +#define WTF_PLATFORM_CG 1 +#define WTF_PLATFORM_CI 1 +#define WTF_USE_ATSUI 1 +#define WTF_USE_CORE_TEXT 1 +#else +#define WTF_PLATFORM_SKIA 1 +#endif +#endif + +#if WTF_PLATFORM_GTK +#define WTF_PLATFORM_CAIRO 1 +#endif + + +/* PLATFORM(WINCE) && PLATFORM(QT) + We can not determine the endianess at compile time. For + Qt for Windows CE the endianess is specified in the + device specific makespec +*/ +#if WTF_PLATFORM_WINCE && WTF_PLATFORM_QT +# include +# undef WTF_PLATFORM_BIG_ENDIAN +# undef WTF_PLATFORM_MIDDLE_ENDIAN +# if Q_BYTE_ORDER == Q_BIG_EDIAN +# define WTF_PLATFORM_BIG_ENDIAN 1 +# endif + +# include +#endif + +#if (WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_OS2 || (WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN && !ENABLE_SINGLE_THREADED)) && !defined(ENABLE_JSC_MULTIPLE_THREADS) +#define ENABLE_JSC_MULTIPLE_THREADS 1 +#endif + +/* On Windows, use QueryPerformanceCounter by default */ +#if WTF_PLATFORM_WIN_OS +#define WTF_USE_QUERY_PERFORMANCE_COUNTER 1 +#endif + +#if WTF_PLATFORM_WINCE && !WTF_PLATFORM_QT +#undef ENABLE_JSC_MULTIPLE_THREADS +#define ENABLE_JSC_MULTIPLE_THREADS 0 +#define USE_SYSTEM_MALLOC 0 +#define ENABLE_ICONDATABASE 0 +#define ENABLE_JAVASCRIPT_DEBUGGER 0 +#define ENABLE_FTPDIR 0 +#define ENABLE_PAN_SCROLLING 0 +#define ENABLE_WML 1 +#define HAVE_ACCESSIBILITY 0 + +#define NOMINMAX // Windows min and max conflict with standard macros +#define NOSHLWAPI // shlwapi.h not available on WinCe + +// MSDN documentation says these functions are provided with uspce.lib. But we cannot find this file. +#define __usp10__ // disable "usp10.h" + +#define _INC_ASSERT // disable "assert.h" +#define assert(x) + +// _countof is only included in CE6; for CE5 we need to define it ourself +#ifndef _countof +#define _countof(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#endif /* PLATFORM(WINCE) && !PLATFORM(QT) */ + +#if WTF_PLATFORM_QT +#define WTF_USE_QT4_UNICODE 1 +#elif WTF_PLATFORM_WINCE +#define WTF_USE_WINCE_UNICODE 1 +#elif WTF_PLATFORM_GTK +/* The GTK+ Unicode backend is configurable */ +#else +#define WTF_USE_ICU_UNICODE 1 +#endif + +#if WTF_PLATFORM_MAC && !WTF_PLATFORM_IPHONE +#define WTF_PLATFORM_CF 1 +#define WTF_USE_PTHREADS 1 +#define HAVE_PTHREAD_RWLOCK 1 +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_TIGER) && WTF_CPU_X86_64 +#define WTF_USE_PLUGIN_HOST_PROCESS 1 +#endif +#if !defined(ENABLE_MAC_JAVA_BRIDGE) +#define ENABLE_MAC_JAVA_BRIDGE 1 +#endif +#if !defined(ENABLE_DASHBOARD_SUPPORT) +#define ENABLE_DASHBOARD_SUPPORT 1 +#endif +#define HAVE_READLINE 1 +#define HAVE_RUNLOOP_TIMER 1 +#endif /* PLATFORM(MAC) && !PLATFORM(IPHONE) */ + +#if WTF_PLATFORM_CHROMIUM && WTF_PLATFORM_DARWIN +#define WTF_PLATFORM_CF 1 +#define WTF_USE_PTHREADS 1 +#define HAVE_PTHREAD_RWLOCK 1 +#endif + +#if WTF_PLATFORM_QT && WTF_PLATFORM_DARWIN +#define WTF_PLATFORM_CF 1 +#endif + +#if WTF_PLATFORM_IPHONE +#define ENABLE_CONTEXT_MENUS 0 +#define ENABLE_DRAG_SUPPORT 0 +#define ENABLE_FTPDIR 1 +#define ENABLE_GEOLOCATION 1 +#define ENABLE_ICONDATABASE 0 +#define ENABLE_INSPECTOR 0 +#define ENABLE_MAC_JAVA_BRIDGE 0 +#define ENABLE_NETSCAPE_PLUGIN_API 0 +#define ENABLE_ORIENTATION_EVENTS 1 +#define ENABLE_REPAINT_THROTTLING 1 +#define HAVE_READLINE 1 +#define WTF_PLATFORM_CF 1 +#define WTF_USE_PTHREADS 1 +#define HAVE_PTHREAD_RWLOCK 1 +#endif + +#if WTF_PLATFORM_ANDROID +#define WTF_USE_PTHREADS 1 +#define WTF_PLATFORM_SGL 1 +#define USE_SYSTEM_MALLOC 1 +#define ENABLE_MAC_JAVA_BRIDGE 1 +#define LOG_DISABLED 1 +// Prevents Webkit from drawing the caret in textfields and textareas +// This prevents unnecessary invals. +#define ENABLE_TEXT_CARET 1 +#define ENABLE_JAVASCRIPT_DEBUGGER 0 +#endif + +#if WTF_PLATFORM_WIN +#define WTF_USE_WININET 1 +#endif + +#if WTF_PLATFORM_WX +#define ENABLE_ASSEMBLER 1 +#if WTF_PLATFORM_DARWIN +#define WTF_PLATFORM_CF 1 +#endif +#endif + +#if WTF_PLATFORM_GTK +#if HAVE_PTHREAD_H +#define WTF_USE_PTHREADS 1 +#define HAVE_PTHREAD_RWLOCK 1 +#endif +#endif + +#if WTF_PLATFORM_HAIKU +#define HAVE_POSIX_MEMALIGN 1 +#define WTF_USE_CURL 1 +#define WTF_USE_PTHREADS 1 +#define HAVE_PTHREAD_RWLOCK 1 +#define USE_SYSTEM_MALLOC 1 +#define ENABLE_NETSCAPE_PLUGIN_API 0 +#endif + +#if !defined(HAVE_ACCESSIBILITY) +#if WTF_PLATFORM_IPHONE || WTF_PLATFORM_MAC || WTF_PLATFORM_WIN || WTF_PLATFORM_GTK || WTF_PLATFORM_CHROMIUM +#define HAVE_ACCESSIBILITY 1 +#endif +#endif /* !defined(HAVE_ACCESSIBILITY) */ + +#if WTF_PLATFORM_UNIX && !WTF_PLATFORM_SYMBIAN +#define HAVE_SIGNAL_H 1 +#endif + +#if !WTF_PLATFORM_WIN_OS && !WTF_PLATFORM_SOLARIS && !WTF_PLATFORM_QNX \ + && !WTF_PLATFORM_SYMBIAN && !WTF_PLATFORM_HAIKU && !WTF_COMPILER_RVCT \ + && !WTF_PLATFORM_ANDROID && !WTF_PLATFORM_OS2 +#define HAVE_TM_GMTOFF 1 +#define HAVE_TM_ZONE 1 +#define HAVE_TIMEGM 1 +#endif + +#if WTF_PLATFORM_DARWIN + +#define HAVE_ERRNO_H 1 +#define HAVE_LANGINFO_H 1 +#define HAVE_MMAP 1 +#define HAVE_MERGESORT 1 +#define HAVE_SBRK 1 +#define HAVE_STRINGS_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TIMEB_H 1 + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !WTF_PLATFORM_IPHONE && !WTF_PLATFORM_QT +#define HAVE_MADV_FREE_REUSE 1 +#define HAVE_MADV_FREE 1 +#define HAVE_PTHREAD_SETNAME_NP 1 +#endif + +#if WTF_PLATFORM_IPHONE +#define HAVE_MADV_FREE 1 +#endif + +#elif WTF_PLATFORM_WIN_OS + +#if WTF_PLATFORM_WINCE +#define HAVE_ERRNO_H 0 +#else +#define HAVE_SYS_TIMEB_H 1 +#endif +#define HAVE_VIRTUALALLOC 1 + +#elif WTF_PLATFORM_SYMBIAN + +#define HAVE_ERRNO_H 1 +#define HAVE_MMAP 0 +#define HAVE_SBRK 1 + +#define HAVE_SYS_TIME_H 1 +#define HAVE_STRINGS_H 1 + +#if !WTF_COMPILER_RVCT +#define HAVE_SYS_PARAM_H 1 +#endif + +#elif WTF_PLATFORM_QNX + +#define HAVE_ERRNO_H 1 +#define HAVE_MMAP 1 +#define HAVE_SBRK 1 +#define HAVE_STRINGS_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_TIME_H 1 + +#elif WTF_PLATFORM_ANDROID + +#define HAVE_ERRNO_H 1 +#define HAVE_LANGINFO_H 0 +#define HAVE_MMAP 1 +#define HAVE_SBRK 1 +#define HAVE_STRINGS_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_TIME_H 1 + +#elif WTF_PLATFORM_OS2 + +#define HAVE_MMAP 1 +#define ENABLE_ASSEMBLER 1 +#define HAVE_ERRNO_H 1 +#define HAVE_STRINGS_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TIMEB_H 1 + +#else + +/* FIXME: is this actually used or do other platforms generate their own config.h? */ + +#define HAVE_ERRNO_H 1 +/* As long as Haiku doesn't have a complete support of locale this will be disabled. */ +#if !WTF_PLATFORM_HAIKU +#define HAVE_LANGINFO_H 1 +#endif +#define HAVE_MMAP 1 +#define HAVE_SBRK 1 +#define HAVE_STRINGS_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_TIME_H 1 + +#endif + +/* ENABLE macro defaults */ + +/* fastMalloc match validation allows for runtime verification that + new is matched by delete, fastMalloc is matched by fastFree, etc. */ +#if !defined(ENABLE_FAST_MALLOC_MATCH_VALIDATION) +#define ENABLE_FAST_MALLOC_MATCH_VALIDATION 0 +#endif + +#if !defined(ENABLE_ICONDATABASE) +#define ENABLE_ICONDATABASE 1 +#endif + +#if !defined(ENABLE_DATABASE) +#define ENABLE_DATABASE 1 +#endif + +#if !defined(ENABLE_JAVASCRIPT_DEBUGGER) +#define ENABLE_JAVASCRIPT_DEBUGGER 1 +#endif + +#if !defined(ENABLE_FTPDIR) +#define ENABLE_FTPDIR 1 +#endif + +#if !defined(ENABLE_CONTEXT_MENUS) +#define ENABLE_CONTEXT_MENUS 1 +#endif + +#if !defined(ENABLE_DRAG_SUPPORT) +#define ENABLE_DRAG_SUPPORT 1 +#endif + +#if !defined(ENABLE_DASHBOARD_SUPPORT) +#define ENABLE_DASHBOARD_SUPPORT 0 +#endif + +#if !defined(ENABLE_INSPECTOR) +#define ENABLE_INSPECTOR 1 +#endif + +#if !defined(ENABLE_MAC_JAVA_BRIDGE) +#define ENABLE_MAC_JAVA_BRIDGE 0 +#endif + +#if !defined(ENABLE_NETSCAPE_PLUGIN_API) +#define ENABLE_NETSCAPE_PLUGIN_API 1 +#endif + +#if !defined(WTF_USE_PLUGIN_HOST_PROCESS) +#define WTF_USE_PLUGIN_HOST_PROCESS 0 +#endif + +#if !defined(ENABLE_ORIENTATION_EVENTS) +#define ENABLE_ORIENTATION_EVENTS 0 +#endif + +#if !defined(ENABLE_OPCODE_STATS) +#define ENABLE_OPCODE_STATS 0 +#endif + +#define ENABLE_SAMPLING_COUNTERS 0 +#define ENABLE_SAMPLING_FLAGS 0 +#define ENABLE_OPCODE_SAMPLING 0 +#define ENABLE_CODEBLOCK_SAMPLING 0 +#if ENABLE_CODEBLOCK_SAMPLING && !ENABLE_OPCODE_SAMPLING +#error "CODEBLOCK_SAMPLING requires OPCODE_SAMPLING" +#endif +#if ENABLE_OPCODE_SAMPLING || ENABLE_SAMPLING_FLAGS +#define ENABLE_SAMPLING_THREAD 1 +#endif + +#if !defined(ENABLE_GEOLOCATION) +#define ENABLE_GEOLOCATION 0 +#endif + +#if !defined(ENABLE_NOTIFICATIONS) +#define ENABLE_NOTIFICATIONS 0 +#endif + +#if !defined(ENABLE_TEXT_CARET) +#define ENABLE_TEXT_CARET 1 +#endif + +#if !defined(ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL) +#define ENABLE_ON_FIRST_TEXTAREA_FOCUS_SELECT_ALL 0 +#endif + +#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) +#if (WTF_CPU_X86_64 && (WTF_PLATFORM_UNIX || WTF_PLATFORM_WIN_OS)) || WTF_CPU_IA64 || WTF_CPU_ALPHA +#define WTF_USE_JSVALUE64 1 +#elif WTF_CPU_ARM || WTF_CPU_PPC64 +#define WTF_USE_JSVALUE32 1 +#elif WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW +/* Using JSVALUE32_64 causes padding/alignement issues for JITStubArg +on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ +#define WTF_USE_JSVALUE32 1 +#else +#define WTF_USE_JSVALUE32_64 1 +#endif +#endif /* !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) */ + +#if !defined(ENABLE_REPAINT_THROTTLING) +#define ENABLE_REPAINT_THROTTLING 0 +#endif + +#if !defined(ENABLE_JIT) + +/* The JIT is tested & working on x86_64 Mac */ +#if WTF_CPU_X86_64 && WTF_PLATFORM_MAC + #define ENABLE_JIT 1 +/* The JIT is tested & working on x86 Mac */ +#elif WTF_CPU_X86 && WTF_PLATFORM_MAC + #define ENABLE_JIT 1 + #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 +#elif WTF_CPU_ARM_THUMB2 && WTF_PLATFORM_IPHONE + #define ENABLE_JIT 1 +/* The JIT is tested & working on x86 OS/2 */ +#elif WTF_CPU_X86 && WTF_PLATFORM_OS2 + #define ENABLE_JIT 1 +/* The JIT is tested & working on x86 Windows */ +#elif WTF_CPU_X86 && WTF_PLATFORM_WIN + #define ENABLE_JIT 1 +#endif + +#if WTF_PLATFORM_QT +#if WTF_CPU_X86_64 && WTF_PLATFORM_DARWIN + #define ENABLE_JIT 1 +#elif WTF_CPU_X86 && WTF_PLATFORM_DARWIN + #define ENABLE_JIT 1 + #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 +#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MINGW && GCC_VERSION >= 40100 + #define ENABLE_JIT 1 + #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 +#elif WTF_CPU_X86 && WTF_PLATFORM_WIN_OS && WTF_COMPILER_MSVC + #define ENABLE_JIT 1 + #define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1 +#elif WTF_CPU_X86 && WTF_PLATFORM_LINUX && GCC_VERSION >= 40100 + #define ENABLE_JIT 1 + #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 +#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_LINUX + #define ENABLE_JIT 1 +#endif +#endif /* PLATFORM(QT) */ + +#endif /* !defined(ENABLE_JIT) */ + +#if ENABLE_JIT +#ifndef ENABLE_JIT_OPTIMIZE_CALL +#define ENABLE_JIT_OPTIMIZE_CALL 1 +#endif +#ifndef ENABLE_JIT_OPTIMIZE_NATIVE_CALL +#define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 1 +#endif +#ifndef ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS +#define ENABLE_JIT_OPTIMIZE_PROPERTY_ACCESS 1 +#endif +#ifndef ENABLE_JIT_OPTIMIZE_METHOD_CALLS +#define ENABLE_JIT_OPTIMIZE_METHOD_CALLS 1 +#endif +#endif + +#if WTF_CPU_X86 && WTF_COMPILER_MSVC +#define JSC_HOST_CALL __fastcall +#elif WTF_CPU_X86 && WTF_COMPILER_GCC +#define JSC_HOST_CALL __attribute__ ((fastcall)) +#else +#define JSC_HOST_CALL +#endif + +#if WTF_COMPILER_GCC && !ENABLE_JIT +#define HAVE_COMPUTED_GOTO 1 +#endif + +#if ENABLE_JIT && defined(COVERAGE) + #define WTF_USE_INTERPRETER 0 +#else + #define WTF_USE_INTERPRETER 1 +#endif + +/* Yet Another Regex Runtime. */ +#if !defined(ENABLE_YARR_JIT) + +/* YARR supports x86 & x86-64, and has been tested on Mac and Windows. */ +#if (WTF_CPU_X86 \ + || WTF_CPU_X86_64 \ + || WTF_CPU_ARM_TRADITIONAL \ + || WTF_CPU_ARM_THUMB2 \ + || WTF_CPU_X86) +#define ENABLE_YARR_JIT 1 +#else +#define ENABLE_YARR_JIT 0 +#endif + +#endif /* !defined(ENABLE_YARR_JIT) */ + +#if (ENABLE_JIT || ENABLE_YARR_JIT) +#define ENABLE_ASSEMBLER 1 +#endif +/* Setting this flag prevents the assembler from using RWX memory; this may improve + security but currectly comes at a significant performance cost. */ +#if WTF_PLATFORM_IPHONE +#define ENABLE_ASSEMBLER_WX_EXCLUSIVE 1 +#else +#define ENABLE_ASSEMBLER_WX_EXCLUSIVE 0 +#endif + +#if !defined(ENABLE_PAN_SCROLLING) && WTF_PLATFORM_WIN_OS +#define ENABLE_PAN_SCROLLING 1 +#endif + +/* Use the QXmlStreamReader implementation for XMLTokenizer */ +/* Use the QXmlQuery implementation for XSLTProcessor */ +#if WTF_PLATFORM_QT +#define WTF_USE_QXMLSTREAM 1 +#define WTF_USE_QXMLQUERY 1 +#endif + +#if !WTF_PLATFORM_QT +#define WTF_USE_FONT_FAST_PATH 1 +#endif + +/* Accelerated compositing */ +#if WTF_PLATFORM_MAC +#if !defined(BUILDING_ON_TIGER) +#define WTF_USE_ACCELERATED_COMPOSITING 1 +#endif +#endif + +#if WTF_PLATFORM_IPHONE +#define WTF_USE_ACCELERATED_COMPOSITING 1 +#endif + +/* FIXME: Defining ENABLE_3D_RENDERING here isn't really right, but it's always used with + with WTF_USE_ACCELERATED_COMPOSITING, and it allows the feature to be turned on and + off in one place. */ +//#if WTF_PLATFORM_WIN +//#include "QuartzCorePresent.h" +//#if QUARTZCORE_PRESENT +//#define WTF_USE_ACCELERATED_COMPOSITING 1 +//#define ENABLE_3D_RENDERING 1 +//#endif +//#endif + +#if WTF_COMPILER_GCC +#define WARN_UNUSED_RETURN __attribute__ ((warn_unused_result)) +#else +#define WARN_UNUSED_RETURN +#endif + +#if !ENABLE_NETSCAPE_PLUGIN_API || (ENABLE_NETSCAPE_PLUGIN_API && ((WTF_PLATFORM_UNIX && (WTF_PLATFORM_QT || WTF_PLATFORM_WX)) || WTF_PLATFORM_GTK)) +#define ENABLE_PLUGIN_PACKAGE_SIMPLE_HASH 1 +#endif + +/* Set up a define for a common error that is intended to cause a build error -- thus the space after Error. */ +#define WTF_PLATFORM_CFNETWORK Error USE_macro_should_be_used_with_CFNETWORK + +#define ENABLE_JSC_ZOMBIES 0 + +#endif /* WTF_Platform_h */ diff --git a/js/src/assembler/wtf/SegmentedVector.h b/js/src/assembler/wtf/SegmentedVector.h new file mode 100644 index 0000000..0aed45e --- /dev/null +++ b/js/src/assembler/wtf/SegmentedVector.h @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SegmentedVector_h +#define SegmentedVector_h + +#include "jsprvtd.h" +#include "jsvector.h" + +namespace WTF { + + // An iterator for SegmentedVector. It supports only the pre ++ operator + template class SegmentedVector; + template class SegmentedVectorIterator { + private: + friend class SegmentedVector; + public: + typedef SegmentedVectorIterator Iterator; + + ~SegmentedVectorIterator() { } + + T& operator*() const { return (*m_vector.m_segments[m_segment])[m_index]; } + T* operator->() const { return &(*m_vector.m_segments[m_segment])[m_index]; } + + // Only prefix ++ operator supported + Iterator& operator++() + { + ASSERT(m_index != SegmentSize); + ++m_index; + //if (m_index >= m_vector.m_segments.at(m_segment)->size()) { + if (m_index >= m_vector.m_segments[m_segment]->length()) { + //if (m_segment + 1 < m_vector.m_segments.size()) { + if (m_segment + 1 < m_vector.m_segments.length()) { + //ASSERT(m_vector.m_segments.at(m_segment)->size() > 0); + ASSERT(m_vector.m_segments[m_segment]->length() > 0); + ++m_segment; + m_index = 0; + } else { + // Points to the "end" symbol + m_segment = 0; + m_index = SegmentSize; + } + } + return *this; + } + + bool operator==(const Iterator& other) const + { + return (m_index == other.m_index && m_segment = other.m_segment && &m_vector == &other.m_vector); + } + + bool operator!=(const Iterator& other) const + { + return (m_index != other.m_index || m_segment != other.m_segment || &m_vector != &other.m_vector); + } + + SegmentedVectorIterator& operator=(const SegmentedVectorIterator& other) + { + m_vector = other.m_vector; + m_segment = other.m_segment; + m_index = other.m_index; + return *this; + } + + private: + SegmentedVectorIterator(SegmentedVector& vector, size_t segment, size_t index) + : m_vector(vector) + , m_segment(segment) + , m_index(index) + { + } + + SegmentedVector& m_vector; + size_t m_segment; + size_t m_index; + }; + + // SegmentedVector is just like Vector, but it doesn't move the values + // stored in its buffer when it grows. Therefore, it is safe to keep + // pointers into a SegmentedVector. + template class SegmentedVector { + friend class SegmentedVectorIterator; + public: + typedef SegmentedVectorIterator Iterator; + + SegmentedVector() + : m_size(0) + { + m_segments.append(&m_inlineSegment); + } + + ~SegmentedVector() + { + deleteAllSegments(); + } + + size_t size() const { return m_size; } + bool isEmpty() const { return !size(); } + + T& at(size_t index) + { + if (index < SegmentSize) + return m_inlineSegment[index]; + return segmentFor(index)->at(subscriptFor(index)); + } + + T& operator[](size_t index) + { + return at(index); + } + + T& last() + { + return at(size() - 1); + } + + template void append(const U& value) + { + ++m_size; + + if (m_size <= SegmentSize) { + //m_inlineSegment.uncheckedAppend(value); + m_inlineSegment.append(value); + return; + } + + if (!segmentExistsFor(m_size - 1)) + m_segments.append(new Segment); + //segmentFor(m_size - 1)->uncheckedAppend(value); + segmentFor(m_size - 1)->append(value); + } + + T& alloc() + { + append(T()); + return last(); + } + + void removeLast() + { + if (m_size <= SegmentSize) + m_inlineSegment.removeLast(); + else + segmentFor(m_size - 1)->removeLast(); + --m_size; + } + + void grow(size_t size) + { + ASSERT(size > m_size); + ensureSegmentsFor(size); + m_size = size; + } + + void clear() + { + deleteAllSegments(); + m_segments.resize(1); + m_inlineSegment.clear(); + m_size = 0; + } + + Iterator begin() + { + return Iterator(*this, 0, m_size ? 0 : SegmentSize); + } + + Iterator end() + { + return Iterator(*this, 0, SegmentSize); + } + + private: + typedef js::Vector Segment; + + void deleteAllSegments() + { + // Skip the first segment, because it's our inline segment, which was + // not created by new. + //for (size_t i = 1; i < m_segments.size(); i++) + for (size_t i = 1; i < m_segments.length(); i++) + delete m_segments[i]; + } + + bool segmentExistsFor(size_t index) + { + //return index / SegmentSize < m_segments.size(); + return index / SegmentSize < m_segments.length(); + } + + Segment* segmentFor(size_t index) + { + return m_segments[index / SegmentSize]; + } + + size_t subscriptFor(size_t index) + { + return index % SegmentSize; + } + + void ensureSegmentsFor(size_t size) + { + size_t segmentCount = m_size / SegmentSize; + if (m_size % SegmentSize) + ++segmentCount; + //segmentCount = std::max(segmentCount, 1); // We always have at least our inline segment. + segmentCount = segmentCount > 1 ? segmentCount : 1; // We always have at least our inline segment. + + size_t neededSegmentCount = size / SegmentSize; + if (size % SegmentSize) + ++neededSegmentCount; + + // Fill up to N - 1 segments. + size_t end = neededSegmentCount - 1; + for (size_t i = segmentCount - 1; i < end; ++i) + ensureSegment(i, SegmentSize); + + // Grow segment N to accomodate the remainder. + ensureSegment(end, subscriptFor(size - 1) + 1); + } + + void ensureSegment(size_t segmentIndex, size_t size) + { + ASSERT(segmentIndex <= m_segments.size()); + if (segmentIndex == m_segments.size()) + m_segments.append(new Segment); + m_segments[segmentIndex]->grow(size); + } + + size_t m_size; + Segment m_inlineSegment; + js::Vector m_segments; + }; + +} // namespace WTF + +using WTF::SegmentedVector; + +#endif // SegmentedVector_h diff --git a/js/src/assembler/wtf/VMTags.h b/js/src/assembler/wtf/VMTags.h new file mode 100644 index 0000000..5811850 --- /dev/null +++ b/js/src/assembler/wtf/VMTags.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef VMTags_h +#define VMTags_h + +// On Mac OS X, the VM subsystem allows tagging memory requested from mmap and vm_map +// in order to aid tools that inspect system memory use. +#if WTF_PLATFORM_DARWIN + +#include + +#if !defined(TARGETING_TIGER) + +#if defined(VM_MEMORY_TCMALLOC) +#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(VM_MEMORY_TCMALLOC) +#else +#define VM_TAG_FOR_TCMALLOC_MEMORY VM_MAKE_TAG(53) +#endif // defined(VM_MEMORY_TCMALLOC) + +#if defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) +#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) +#else +#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY VM_MAKE_TAG(64) +#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR) + +#if defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) +#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) +#else +#define VM_TAG_FOR_REGISTERFILE_MEMORY VM_MAKE_TAG(65) +#endif // defined(VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE) + +#else // !defined(TARGETING_TIGER) + +// mmap on Tiger fails with tags that work on Leopard, so fall +// back to Tiger-compatible tags (that also work on Leopard) +// when targeting Tiger. +#define VM_TAG_FOR_TCMALLOC_MEMORY -1 +#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1 +#define VM_TAG_FOR_REGISTERFILE_MEMORY -1 + +#endif // !defined(TARGETING_TIGER) + +// Tags for vm_map and vm_allocate work on both Tiger and Leopard. + +#if defined(VM_MEMORY_JAVASCRIPT_CORE) +#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(VM_MEMORY_JAVASCRIPT_CORE) +#else +#define VM_TAG_FOR_COLLECTOR_MEMORY VM_MAKE_TAG(63) +#endif // defined(VM_MEMORY_JAVASCRIPT_CORE) + +#if defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS) +#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS) +#else +#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(69) +#endif // defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS) + +#else // OS(DARWIN) + +#define VM_TAG_FOR_TCMALLOC_MEMORY -1 +#define VM_TAG_FOR_COLLECTOR_MEMORY -1 +#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY -1 +#define VM_TAG_FOR_REGISTERFILE_MEMORY -1 +#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY -1 + +#endif // OS(DARWIN) + +#endif // VMTags_h diff --git a/js/src/bench.sh b/js/src/bench.sh new file mode 100755 index 0000000..c5b1ec5 --- /dev/null +++ b/js/src/bench.sh @@ -0,0 +1,5 @@ +#!/bin/bash +X="var d = Date.now();"; +for i in t/*.js; do X="$X load(\"$i\");"; done +X="$X print(Date.now() - d);" +echo $X | $1 -j diff --git a/js/src/build/autoconf/acoutput-fast.pl b/js/src/build/autoconf/acoutput-fast.pl new file mode 100644 index 0000000..973dd86 --- /dev/null +++ b/js/src/build/autoconf/acoutput-fast.pl @@ -0,0 +1,202 @@ +#! /usr/bin/env perl +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# acoutput-fast.pl - Quickly create makefiles that are in a common format. +# +# Most of the makefiles in mozilla only refer to two configure variables: +# @srcdir@ +# @top_srcdir@ +# However, configure does not know any better and it runs sed on each file +# with over 150 replacement rules (slow as molasses). +# +# This script takes a list of makefiles as input. For example, +# +# echo $MAKEFILES | acoutput-fast.pl +# +# The script creates each Makefile that only references @srcdir@ and +# @top_srcdir@. For other files, it lists them in a shell command that is +# printed to stdout: +# +# CONFIG_FILES="unhandled_files..."; export CONFIG_FILES +# +# This command can be used to have config.status create the unhandled +# files. For example, +# +# eval "echo $MAKEFILES | acoutput-fast.pl" +# AC_OUTPUT($MAKEFILES) +# +# Send comments, improvements, bugs to Steve Lamm (slamm@netscape.com). + +#use File::Basename; +sub dirname { + my $dir = $_[0]; + return '.' if not $dir =~ m%/%; + $dir =~ s%/[^/][^/]*$%%; + return $dir; +} + +# Create one directory. Assumes it doesn't already exist. +# Will create parent(s) if needed. +sub create_directory { + my $dir = $_[0]; + my $parent = dirname($dir); + create_directory($parent) if not -d $parent; + mkdir "$dir",0777; +} + +# Create all the directories at once. +# This can be much faster than calling mkdir() for each one. +sub create_directories { + my @makefiles = @_; + my @dirs = (); + my $ac_file; + foreach $ac_file (@makefiles) { + push @dirs, dirname($ac_file); + } + # Call mkdir with the directories sorted by subdir count (how many /'s) + if (@dirs) { + foreach $dir (@dirs) { + if (not -d $dir) { + print STDERR "Creating directory $dir\n"; + create_directory($dir); + } + } + } +} + +while($arg = shift) { + if ($arg =~ /^--srcdir=/) { + $ac_given_srcdir = (split /=/, $arg)[1]; + } + if ($arg =~ /^--cygwin-srcdir/) { + $ac_cygwin_srcdir = (split /=/, $arg)[1]; + } +} + +if (!$ac_given_srcdir) { + $ac_given_srcdir = $0; + $ac_given_srcdir =~ s|/?build/autoconf/.*$||; + $ac_given_srcdir = '.' if $ac_given_srcdir eq ''; +} + +if (!$ac_cygwin_srcdir) { + $ac_cygwin_srcdir = $ac_given_srcdir; +} + +# Read list of makefiles from the stdin or, +# from files listed on the command-line. +# +@makefiles=(); +push @makefiles, split while (); + +# Create all the directories at once. +# This can be much faster than calling mkdir() for each one. +create_directories(@makefiles); + +# Output the makefiles. +# +@unhandled=(); +foreach $ac_file (@makefiles) { + if (not $ac_file =~ /Makefile$/ or $ac_file =~ /:/) { + push @unhandled, $ac_file; + next; + } + $ac_file_in = "$ac_given_srcdir/$ac_file.in"; + $ac_dir = dirname($ac_file); + if ($ac_dir eq '.') { + $ac_dir_suffix = ''; + $ac_dots = ''; + } else { + $ac_dir_suffix = "/$ac_dir"; + $ac_dir_suffix =~ s%^/\./%/%; + $ac_dots = $ac_dir_suffix; + $ac_dots =~ s%/[^/]*%../%g; + } + if ($ac_given_srcdir eq '.') { + $srcdir = '.'; + if ($ac_dots eq '') { + $top_srcdir = '.' + } else { + $top_srcdir = $ac_dots; + $top_srcdir =~ s%/$%%; + } + } elsif ($ac_cygwin_srcdir =~ m%^/% or $ac_cygwin_srcdir =~ m%^.:/%) { + $srcdir = "$ac_cygwin_srcdir$ac_dir_suffix"; + $top_srcdir = "$ac_cygwin_srcdir"; + } else { + $srcdir = "$ac_dots$ac_cygwin_srcdir$ac_dir_suffix"; + $top_srcdir = "$ac_dots$ac_cygwin_srcdir"; + } + + if (-e $ac_file) { + next if -M _ < -M $ac_file_in; + print STDERR "updating $ac_file\n"; + } else { + print STDERR "creating $ac_file\n"; + } + + open (INFILE, "<$ac_file_in") + or ( warn "can't read $ac_file_in: No such file or directory\n" and next); + open (OUTFILE, ">$ac_file") + or ( warn "Unable to create $ac_file\n" and next); + + while () { + #if (/\@[_a-zA-Z]*\@.*\@[_a-zA-Z]*\@/) { + # warn "Two defines on a line:$ac_file:$.:$_"; + # push @unhandled, $ac_file; + # last; + #} + + s/\@srcdir\@/$srcdir/g; + s/\@top_srcdir\@/$top_srcdir/g; + + if (/\@[_a-zA-Z]*\@/) { + warn "Unknown variable:$ac_file:$.:$_"; + push @unhandled, $ac_file; + last; + } + print OUTFILE; + } + close INFILE; + close OUTFILE; +} + +# Print the shell command to be evaluated by configure. +# +print "CONFIG_FILES=\"".join(' ', @unhandled)."\"; export CONFIG_FILES\n"; + diff --git a/js/src/build/autoconf/acwinpaths.m4 b/js/src/build/autoconf/acwinpaths.m4 new file mode 100644 index 0000000..5f6810e --- /dev/null +++ b/js/src/build/autoconf/acwinpaths.m4 @@ -0,0 +1,65 @@ +dnl ***** BEGIN LICENSE BLOCK ***** +dnl Version: MPL 1.1/GPL 2.0/LGPL 2.1 +dnl +dnl The contents of this file are subject to the Mozilla Public License Version +dnl 1.1 (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl http://www.mozilla.org/MPL/ +dnl +dnl Software distributed under the License is distributed on an "AS IS" basis, +dnl WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +dnl for the specific language governing rights and limitations under the +dnl License. +dnl +dnl The Original Code is mozilla.org code. +dnl +dnl The Initial Developer of the Original Code is the +dnl Mozilla Foundation +dnl +dnl Portions created by the Initial Developer are Copyright (C) 2009 +dnl the Initial Developer. All Rights Reserved. +dnl +dnl Contributor(s): +dnl Benjamin Smedberg +dnl +dnl Alternatively, the contents of this file may be used under the terms of +dnl either of the GNU General Public License Version 2 or later (the "GPL"), +dnl or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +dnl in which case the provisions of the GPL or the LGPL are applicable instead +dnl of those above. If you wish to allow use of your version of this file only +dnl under the terms of either the GPL or the LGPL, and not to allow others to +dnl use your version of this file under the terms of the MPL, indicate your +dnl decision by deleting the provisions above and replace them with the notice +dnl and other provisions required by the GPL or the LGPL. If you do not delete +dnl the provisions above, a recipient may use your version of this file under +dnl the terms of any one of the MPL, the GPL or the LGPL. +dnl +dnl ***** END LICENSE BLOCK ***** + +define(GENERATE_SUB_ABS, [ +define([AC_OUTPUT_FILES_SUB1], [ +patsubst($@, [/\*)], [/* | ?:/*)]) +]) +]) +GENERATE_SUB_ABS(defn([AC_OUTPUT_FILES])) + +define(GENERATE_SUB_NOSPLIT, [ +define([AC_OUTPUT_FILES], [ +patsubst($@, [-e "s%:% \$ac_given_srcdir/%g"], []) +]) +]) +GENERATE_SUB_NOSPLIT(defn([AC_OUTPUT_FILES_SUB1])) + +define(GENERATE_HEADER_NOSPLIT, [ +define([AC_OUTPUT_HEADER], [ +patsubst($@, [-e "s%:% \$ac_given_srcdir/%g"], []) +]) +]) +GENERATE_HEADER_NOSPLIT(defn([AC_OUTPUT_HEADER])) + +define(GENERATE_SUBDIRS_ABS, [ +define([AC_OUTPUT_SUBDIRS], [ +patsubst($@, [/\*)], [/* | ?:/*)]) +]) +]) +GENERATE_SUBDIRS_ABS(defn([AC_OUTPUT_SUBDIRS])) diff --git a/js/src/build/autoconf/altoptions.m4 b/js/src/build/autoconf/altoptions.m4 new file mode 100644 index 0000000..f9db0a5 --- /dev/null +++ b/js/src/build/autoconf/altoptions.m4 @@ -0,0 +1,154 @@ +dnl ***** BEGIN LICENSE BLOCK ***** +dnl Version: MPL 1.1/GPL 2.0/LGPL 2.1 +dnl +dnl The contents of this file are subject to the Mozilla Public License Version +dnl 1.1 (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl http://www.mozilla.org/MPL/ +dnl +dnl Software distributed under the License is distributed on an "AS IS" basis, +dnl WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +dnl for the specific language governing rights and limitations under the +dnl License. +dnl +dnl The Original Code is mozilla.org code. +dnl +dnl The Initial Developer of the Original Code is +dnl Netscape Communications Corporation. +dnl Portions created by the Initial Developer are Copyright (C) 1999 +dnl the Initial Developer. All Rights Reserved. +dnl +dnl Contributor(s): +dnl +dnl Alternatively, the contents of this file may be used under the terms of +dnl either of the GNU General Public License Version 2 or later (the "GPL"), +dnl or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +dnl in which case the provisions of the GPL or the LGPL are applicable instead +dnl of those above. If you wish to allow use of your version of this file only +dnl under the terms of either the GPL or the LGPL, and not to allow others to +dnl use your version of this file under the terms of the MPL, indicate your +dnl decision by deleting the provisions above and replace them with the notice +dnl and other provisions required by the GPL or the LGPL. If you do not delete +dnl the provisions above, a recipient may use your version of this file under +dnl the terms of any one of the MPL, the GPL or the LGPL. +dnl +dnl ***** END LICENSE BLOCK ***** + +dnl altoptions.m4 - An alternative way of specifying command-line options. +dnl These macros are needed to support a menu-based configurator. +dnl This file also includes the macro, AM_READ_MYCONFIG, for reading +dnl the 'myconfig.m4' file. + +dnl Send comments, improvements, bugs to Steve Lamm (slamm@netscape.com). + + +dnl MOZ_ARG_ENABLE_BOOL( NAME, HELP, IF-YES [, IF-NO [, ELSE]]) +dnl MOZ_ARG_DISABLE_BOOL( NAME, HELP, IF-NO [, IF-YES [, ELSE]]) +dnl MOZ_ARG_ENABLE_STRING( NAME, HELP, IF-SET [, ELSE]) +dnl MOZ_ARG_ENABLE_BOOL_OR_STRING( NAME, HELP, IF-YES, IF-NO, IF-SET[, ELSE]]]) +dnl MOZ_ARG_WITH_BOOL( NAME, HELP, IF-YES [, IF-NO [, ELSE]) +dnl MOZ_ARG_WITHOUT_BOOL( NAME, HELP, IF-NO [, IF-YES [, ELSE]) +dnl MOZ_ARG_WITH_STRING( NAME, HELP, IF-SET [, ELSE]) +dnl MOZ_ARG_HEADER(Comment) +dnl MOZ_CHECK_PTHREADS( NAME, IF-YES [, ELSE ]) +dnl MOZ_READ_MYCONFIG() - Read in 'myconfig.sh' file + + +dnl MOZ_TWO_STRING_TEST(NAME, VAL, STR1, IF-STR1, STR2, IF-STR2 [, ELSE]) +AC_DEFUN([MOZ_TWO_STRING_TEST], +[if test "[$2]" = "[$3]"; then + ifelse([$4], , :, [$4]) + elif test "[$2]" = "[$5]"; then + ifelse([$6], , :, [$6]) + else + ifelse([$7], , + [AC_MSG_ERROR([Option, [$1], does not take an argument ([$2]).])], + [$7]) + fi]) + +dnl MOZ_ARG_ENABLE_BOOL(NAME, HELP, IF-YES [, IF-NO [, ELSE]]) +AC_DEFUN([MOZ_ARG_ENABLE_BOOL], +[AC_ARG_ENABLE([$1], [$2], + [MOZ_TWO_STRING_TEST([$1], [$enableval], yes, [$3], no, [$4])], + [$5])]) + +dnl MOZ_ARG_DISABLE_BOOL(NAME, HELP, IF-NO [, IF-YES [, ELSE]]) +AC_DEFUN([MOZ_ARG_DISABLE_BOOL], +[AC_ARG_ENABLE([$1], [$2], + [MOZ_TWO_STRING_TEST([$1], [$enableval], no, [$3], yes, [$4])], + [$5])]) + +dnl MOZ_ARG_ENABLE_STRING(NAME, HELP, IF-SET [, ELSE]) +AC_DEFUN([MOZ_ARG_ENABLE_STRING], +[AC_ARG_ENABLE([$1], [$2], [$3], [$4])]) + +dnl MOZ_ARG_ENABLE_BOOL_OR_STRING(NAME, HELP, IF-YES, IF-NO, IF-SET[, ELSE]]]) +AC_DEFUN([MOZ_ARG_ENABLE_BOOL_OR_STRING], +[ifelse([$5], , + [errprint([Option, $1, needs an "IF-SET" argument. +]) + m4exit(1)], + [AC_ARG_ENABLE([$1], [$2], + [MOZ_TWO_STRING_TEST([$1], [$enableval], yes, [$3], no, [$4], [$5])], + [$6])])]) + +dnl MOZ_ARG_WITH_BOOL(NAME, HELP, IF-YES [, IF-NO [, ELSE]) +AC_DEFUN([MOZ_ARG_WITH_BOOL], +[AC_ARG_WITH([$1], [$2], + [MOZ_TWO_STRING_TEST([$1], [$withval], yes, [$3], no, [$4])], + [$5])]) + +dnl MOZ_ARG_WITHOUT_BOOL(NAME, HELP, IF-NO [, IF-YES [, ELSE]) +AC_DEFUN([MOZ_ARG_WITHOUT_BOOL], +[AC_ARG_WITH([$1], [$2], + [MOZ_TWO_STRING_TEST([$1], [$withval], no, [$3], yes, [$4])], + [$5])]) + +dnl MOZ_ARG_WITH_STRING(NAME, HELP, IF-SET [, ELSE]) +AC_DEFUN([MOZ_ARG_WITH_STRING], +[AC_ARG_WITH([$1], [$2], [$3], [$4])]) + +dnl MOZ_ARG_HEADER(Comment) +dnl This is used by webconfig to group options +define(MOZ_ARG_HEADER, [# $1]) + +dnl +dnl Apparently, some systems cannot properly check for the pthread +dnl library unless is included so we need to test +dnl using it +dnl +dnl MOZ_CHECK_PTHREADS(lib, success, failure) +AC_DEFUN([MOZ_CHECK_PTHREADS], +[ +AC_MSG_CHECKING([for pthread_create in -l$1]) +echo " + #include + #include + void *foo(void *v) { int a = 1; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + exit(0); + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -l[$1] $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -l[$1] $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + AC_MSG_RESULT([yes]) + [$2] + else + AC_MSG_RESULT([no]) + [$3] + fi +]) + +dnl MOZ_READ_MYCONFIG() - Read in 'myconfig.sh' file +AC_DEFUN([MOZ_READ_MOZCONFIG], +[AC_REQUIRE([AC_INIT_BINSH])dnl +# Read in '.mozconfig' script to set the initial options. +# See the mozconfig2configure script for more details. +_AUTOCONF_TOOLS_DIR=`dirname [$]0`/[$1]/build/autoconf +. $_AUTOCONF_TOOLS_DIR/mozconfig2configure]) diff --git a/js/src/build/autoconf/config.guess b/js/src/build/autoconf/config.guess new file mode 100755 index 0000000..721b21a --- /dev/null +++ b/js/src/build/autoconf/config.guess @@ -0,0 +1,1537 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-08-19' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:[3456]*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T | authenticamd | genuineintel) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) eval $set_cc_for_build + if $CC_FOR_BUILD -E -dM -x c /dev/null | grep __LP64__>/dev/null 2>&1 ; then + UNAME_PROCESSOR=x86_64 + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/js/src/build/autoconf/config.sub b/js/src/build/autoconf/config.sub new file mode 100755 index 0000000..7243829 --- /dev/null +++ b/js/src/build/autoconf/config.sub @@ -0,0 +1,1702 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-12-04' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova* | wince-winmo*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -winmo*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince-winmo*) + os=-wince-winmo + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/js/src/build/autoconf/install-sh b/js/src/build/autoconf/install-sh new file mode 100644 index 0000000..0ff4b6a --- /dev/null +++ b/js/src/build/autoconf/install-sh @@ -0,0 +1,119 @@ +#!/bin/sh + +# +# install - install a program, script, or datafile +# This comes from X11R5; it is not part of GNU. +# +# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" + +instcmd="$mvprog" +chmodcmd="" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +fi + +if [ x"$dst" = x ] +then + echo "install: no destination specified" + exit 1 +fi + + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + +if [ -d $dst ] +then + dst="$dst"/`basename $src` +fi + +# Make a temp file name in the proper directory. + +dstdir=`dirname $dst` +dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + +$doit $instcmd $src $dsttmp + +# and set any options; do chmod last to preserve setuid bits + +if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi +if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi +if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi +if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi + +# Now rename the file to the real destination. + +$doit $rmcmd $dst +$doit $mvcmd $dsttmp $dst + + +exit 0 diff --git a/js/src/build/autoconf/make-makefile b/js/src/build/autoconf/make-makefile new file mode 100644 index 0000000..94a5497 --- /dev/null +++ b/js/src/build/autoconf/make-makefile @@ -0,0 +1,324 @@ +#! /usr/bin/env perl +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# make-makefiles - Quickly create Makefiles for subdirectories. +# Also, creates any needed subdirectories. +# +# usage: make-makefiles [ -t -p -d ] [ | /Makefile ] ... + +# Send comments, improvements, bugs to Steve Lamm (slamm@netscape.com). + +#$debug = 1; + +if ($^O eq 'msys') { + $pwdcmd = 'pwd -W'; +} +else { + $pwdcmd = 'pwd'; +} + +# Determine various tree path variables +# +($topsrcdir, $ptopsrcdir, $depth, @makefiles) = parse_arguments(@ARGV); + +$object_fullpath = `$pwdcmd`; +chdir $depth; +$object_root = `$pwdcmd`; +chomp $object_fullpath; +chomp $object_root; + +# $source_subdir is the path from the object root to where +# 'make-makefile' was called. For example, if make-makefile was +# called from "mozilla/gfx/src", then $source_subdir would be +# "gfx/src/". +$source_subdir = "$object_fullpath/"; +my $quoted_object_root = quotemeta($object_root); +$source_subdir =~ s|^$quoted_object_root/||; + +# Prefix makefiles with $source_subdir so that paths +# will be relative to the top of the object tree. +# +for $makefile (@makefiles) { + $makefile = "$source_subdir$makefile"; +} + +create_directories(@makefiles); + +# Find the path to the source directory based on how 'make-makefile' +# was invoked. The path is either relative to the object directory +# or an absolute path. +$given_srcdir = find_srcdir($topsrcdir, $depth); +$pgiven_srcdir = find_srcdir($ptopsrcdir, $depth); + +if ($debug) { + warn "object_fullpath = $object_fullpath\n"; + warn "object_root = $object_root\n"; + warn "source_subdir = $source_subdir\n"; + warn "makefiles = @makefiles\n"; + warn "given_srcdir = $given_srcdir\n"; +} + +@unhandled = update_makefiles($given_srcdir, $pgiven_srcdir, @makefiles); + +run_config_status(@unhandled); + +# end of Main +############################################################ + +sub dirname { + return $_[0] =~ /(.*)\/.*/ ? "$1" : '.'; +} + +# find_depth: Pull the value of DEPTH out of a Makefile (or Makefile.in) +sub find_depth { + my $depth = ''; + open(MAKEFILE, "<$_[0]") || die "Unable to open $_[0]: $!\n"; + while () { + next unless /^DEPTH\s*=\s*(\..*)/; + $depth = $1; + last; + } + close MAKEFILE; + return $depth; +} + +sub parse_arguments { + my @args = @_; + my $depth = ''; + my $topsrcdir = ''; + my $ptopsrcdir; + my @makefiles = (); + + while (1) { + if ($args[0] eq '-d') { + $depth = $args[1]; + shift @args; + shift @args; + } elsif ($args[0] eq '-t') { + $topsrcdir = $args[1]; + shift @args; + shift @args; + } elsif ($args[0] eq '-p') { + $ptopsrcdir = $args[1]; + shift @args; + shift @args; + } else { + last; + } + } + + if ($topsrcdir eq '') { + $topsrcdir = $0; # Figure out topsrcdir based on program name. + $topsrcdir =~ s|/?build/autoconf/.*$||; + } + if ($ptopsrcdir eq '') { + $ptopsrcdir = $topsrcdir; + } + if ($depth eq '') { + # Use $(DEPTH) in the Makefile or Makefile.in to determine the depth + if (-e "Makefile.in") { + $depth = find_depth("Makefile.in"); + } elsif (-e "Makefile") { + $depth = find_depth("Makefile"); + } elsif (-e "../Makefile") { + $depth = "../".find_depth("../Makefile"); + $depth =~ s/\/\.$//; + } else { + warn "Unable to determine depth (e.g. ../..) to root of objdir tree.\n"; + die "No Makefile(.in) present. Try running with '-d '\n"; + } + } + + # Build the list of makefiles to generate + # + @makefiles = (); + my $makefile; + foreach $makefile (@args) { + $makefile =~ s/\.in$//; + $makefile =~ s/\/$//; + $makefile =~ /Makefile$/ + or $makefile =~ /^\.\// + or $makefile .= "/Makefile"; + push @makefiles, "$makefile"; + } + @makefiles = "Makefile" unless @args; + + return ($topsrcdir, $ptopsrcdir, $depth, @makefiles); +} + + +# Create all the directories at once. +# This can be much faster than calling mkdir() for each one. +sub create_directories { + my @makefiles = @_; + my @dirs = (); + my $ac_file; + foreach $ac_file (@makefiles) { + push @dirs, dirname($ac_file); + } + # Call mkdir with the directories sorted by subdir count (how many /'s) + system "mkdir -p ". join(' ', map("\"$_\"", @dirs)) if @dirs; +} + +# Find the top of the source directory +# (Assuming that the executable is in $top_srcdir/build/autoconf) +sub find_srcdir { + my ($ac_given_srcdir, $depth) = @_; + + if ($debug) { + print "ac_given_srcdir = $ac_given_srcdir\n"; + print "depth = $depth\n"; + } + if ($ac_given_srcdir =~ /^\./ and $depth ne '.') { + my $quoted_depth = quotemeta($depth); + $ac_given_srcdir =~ s|^$quoted_depth/?||; + } + if ($debug) { + print "ac_given_srcdir = $ac_given_srcdir\n"; + } + $ac_given_srcdir = '.' if $ac_given_srcdir eq ''; + return $ac_given_srcdir; +} + +# Output the makefiles. +# +sub update_makefiles { + my ($ac_given_srcdir, $pac_given_srcdir, @makefiles) = @_; + my @unhandled=(); + + my $ac_file; + foreach $ac_file (@makefiles) { + my $ac_file_in = "$ac_given_srcdir/${ac_file}.in"; + my $ac_dir = dirname($ac_file); + my $ac_dots = ''; + my $ac_dir_suffix = ''; + my $srcdir = '.'; + my $top_srcdir = '.'; + + # Determine $srcdir and $top_srcdir + # + if ($ac_dir ne '.') { + $ac_dir_suffix = "/$ac_dir"; + $ac_dir_suffix =~ s%^/\./%/%; + $ac_dots = $ac_dir_suffix; + # Remove .. components from the provided dir suffix, and + # also the forward path components they were reversing. + my $backtracks = $ac_dots =~ s%\.\.(/|$)%%g; + while ($backtracks--) { + $ac_dots =~ s%/[^/]*%%; + } + $ac_dots =~ s%/[^/]*%../%g; + } + if ($ac_given_srcdir eq '.') { + if ($ac_dots ne '') { + $top_srcdir = $ac_dots; + $top_srcdir =~ s%/$%%; + } + } elsif ($pac_given_srcdir =~ m%^/% or $pac_given_srcdir =~ m%^.:/%) { + $srcdir = "$pac_given_srcdir$ac_dir_suffix"; + $top_srcdir = "$pac_given_srcdir"; + } else { + if ($debug) { + print "ac_dots = $ac_dots\n"; + print "ac_dir_suffix = $ac_dir_suffix\n"; + } + $srcdir = "$ac_dots$ac_given_srcdir$ac_dir_suffix"; + $top_srcdir = "$ac_dots$ac_given_srcdir"; + } + + if ($debug) { + print "ac_dir = $ac_dir\n"; + print "ac_file = $ac_file\n"; + print "ac_file_in = $ac_file_in\n"; + print "srcdir = $srcdir\n"; + print "top_srcdir = $top_srcdir\n"; + print "cwd = " . `$pwdcmd` . "\n"; + } + + # Copy the file and make substitutions. + # @srcdir@ -> value of $srcdir + # @top_srcdir@ -> value of $top_srcdir + # + if (-e $ac_file) { + next if -M _ < -M $ac_file_in; # Next if Makefile is up-to-date. + warn "updating $ac_file\n"; + } else { + warn "creating $ac_file\n"; + } + + open INFILE, "<$ac_file_in" or do { + warn "$0: Cannot read $ac_file_in: No such file or directory\n"; + next; + }; + open OUTFILE, ">$ac_file" or do { + warn "$0: Unable to create $ac_file\n"; + next; + }; + + while () { + #if (/\@[_a-zA-Z]*\@.*\@[_a-zA-Z]*\@/) { + # #warn "Two defines on a line:$ac_file:$.:$_"; + # push @unhandled, $ac_file; + # last; + #} + + s/\@srcdir\@/$srcdir/g; + s/\@top_srcdir\@/$top_srcdir/g; + + if (/\@[_a-zA-Z]*\@/) { + #warn "Unknown variable:$ac_file:$.:$_"; + push @unhandled, $ac_file; + last; + } + print OUTFILE; + } + close INFILE; + close OUTFILE; + } + return @unhandled; +} + +sub run_config_status { + my @unhandled = @_; + + # Run config.status with any unhandled files. + # + if (@unhandled) { + $ENV{CONFIG_FILES}= join ' ', @unhandled; + system "./config.status"; + } +} diff --git a/js/src/build/autoconf/match-dir.sh b/js/src/build/autoconf/match-dir.sh new file mode 100644 index 0000000..c579a9d --- /dev/null +++ b/js/src/build/autoconf/match-dir.sh @@ -0,0 +1,101 @@ +#!/bin/sh +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# This script will match a dir with a set of dirs. +# +# Usage: match-dir.sh match [dir1 dir2 ... dirn] +# +# Send comments, improvements, bugs to ramiro@netscape.com +# + +if [ -f Makefile ]; then + MAKEFILE="Makefile" +else + if [ -f Makefile.in ]; then + MAKEFILE="Makefile.in" + else + echo + echo "There ain't no 'Makefile' or 'Makefile.in' over here: $pwd, dude." + echo + exit 1 + fi +fi + +# Use DEPTH in the Makefile.in to determine the depth +depth=`grep -w DEPTH ${MAKEFILE} | grep "\.\." | awk -F"=" '{ print $2; }'` +cwd=`pwd` + +# Determine the depth count +n=`echo $depth | tr '/' ' ' | wc -w` + +cd $depth +objdir=`pwd` + +path=`echo $cwd | sed "s|^${objdir}/||"` + +match=$path + +for i in $* +do +# echo "Looking for $match in $i" + + echo $i | grep -q -x $match + + if [ $? -eq 0 ] + then + echo "1" + + exit 0 + fi + +# echo "Looking for $i in $match" + + echo $match | grep -q $i + + if [ $? -eq 0 ] + then + echo "1" + + exit 0 + fi +done + +echo "0" + +exit 0 diff --git a/js/src/build/autoconf/moznbytetype.m4 b/js/src/build/autoconf/moznbytetype.m4 new file mode 100644 index 0000000..430eae5 --- /dev/null +++ b/js/src/build/autoconf/moznbytetype.m4 @@ -0,0 +1,136 @@ +dnl ***** BEGIN LICENSE BLOCK ***** +dnl Version: MPL 1.1/GPL 2.0/LGPL 2.1 +dnl +dnl The contents of this file are subject to the Mozilla Public License Version +dnl 1.1 (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl http://www.mozilla.org/MPL/ +dnl +dnl Software distributed under the License is distributed on an "AS IS" basis, +dnl WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +dnl for the specific language governing rights and limitations under the +dnl License. +dnl +dnl The Original Code is mozilla.org code. +dnl +dnl The Initial Developer of the Original Code is +dnl The Mozilla Foundation +dnl Portions created by the Initial Developer are Copyright (C) 2008 +dnl the Initial Developer. All Rights Reserved. +dnl +dnl Contributor(s): +dnl Jim Blandy +dnl +dnl Alternatively, the contents of this file may be used under the terms of +dnl either of the GNU General Public License Version 2 or later (the "GPL"), +dnl or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +dnl in which case the provisions of the GPL or the LGPL are applicable instead +dnl of those above. If you wish to allow use of your version of this file only +dnl under the terms of either the GPL or the LGPL, and not to allow others to +dnl use your version of this file under the terms of the MPL, indicate your +dnl decision by deleting the provisions above and replace them with the notice +dnl and other provisions required by the GPL or the LGPL. If you do not delete +dnl the provisions above, a recipient may use your version of this file under +dnl the terms of any one of the MPL, the GPL or the LGPL. +dnl +dnl ***** END LICENSE BLOCK ***** + +dnl MOZ_N_BYTE_TYPE(VARIABLE, SIZE, POSSIBLE-TYPES) +dnl +dnl Check to see which of POSSIBLE-TYPES has a size of SIZE. If we +dnl find one, define VARIABLE to be the size-BYTE type. If no type +dnl matches, exit the configure script with an error message. Types +dnl whose written form contains spaces should appear in POSSIBLE-TYPES +dnl enclosed by shell quotes. +dnl +dnl The cache variable moz_cv_n_byte_type_VARIABLE gets set to the +dnl type, if found. +dnl +dnl for example: +dnl MOZ_N_BYTE_TYPE([JS_INT32_T], [4], [int long 'long long' short]) +dnl +AC_DEFUN(MOZ_N_BYTE_TYPE, +[ +dnl The simplest approach would simply be to run a program that says +dnl printf ("%d\n", sizeof ($type)); +dnl But that won't work when cross-compiling; this will. +AC_CACHE_CHECK([for a $2-byte type], moz_cv_n_byte_type_$1, [ + moz_cv_n_byte_type_$1= + for type in $3; do + AC_TRY_COMPILE([], + [ + int a[sizeof ($type) == $2 ? 1 : -1]; + return 0; + ], + [moz_cv_n_byte_type_$1=$type; break], []) + done + if test ! "$moz_cv_n_byte_type_$1"; then + AC_MSG_ERROR([Couldn't find a $2-byte type]) + fi +]) +AC_DEFINE_UNQUOTED($1, [$moz_cv_n_byte_type_$1], + [a $2-byte type on the target machine]) +]) + +dnl MOZ_SIZE_OF_TYPE(VARIABLE, TYPE, POSSIBLE-SIZES) +dnl +dnl Check to see which of POSSIBLE-SIZES is the sizeof(TYPE). If we find one, +dnl define VARIABLE SIZE. If no size matches, exit the configure script with +dnl an error message. +dnl +dnl The cache variable moz_cv_size_of_VARIABLE gets set to the size, if +dnl found. +dnl +dnl for example: +dnl MOZ_SIZE_OF_TYPE([JS_BYTES_PER_WORD], [void*], [4 8]) +AC_DEFUN(MOZ_SIZE_OF_TYPE, +[ +AC_CACHE_CHECK([for the size of $2], moz_cv_size_of_$1, [ + moz_cv_size_of_$1= + for size in $3; do + AC_TRY_COMPILE([], + [ + int a[sizeof ($2) == $size ? 1 : -1]; + return 0; + ], + [moz_cv_size_of_$1=$size; break], []) + done + if test ! "$moz_cv_size_of_$1"; then + AC_MSG_ERROR([No size found for $2]) + fi +]) +AC_DEFINE_UNQUOTED($1, [$moz_cv_size_of_$1]) +]) + +dnl MOZ_ALIGN_OF_TYPE(VARIABLE, TYPE, POSSIBLE-ALIGNS) +dnl +dnl Check to see which of POSSIBLE-ALIGNS is the necessary alignment of TYPE. +dnl If we find one, define VARIABLE ALIGNMENT. If no alignment matches, exit +dnl the configure script with an error message. +dnl +dnl The cache variable moz_cv_align_of_VARIABLE gets set to the size, if +dnl found. +dnl +dnl for example: +dnl MOZ_ALIGN_OF_TYPE(JS_ALIGN_OF_POINTER, void*, 2 4 8 16) +AC_DEFUN(MOZ_ALIGN_OF_TYPE, +[ +AC_CACHE_CHECK([for the alignment of $2], moz_cv_align_of_$1, [ + moz_cv_align_of_$1= + for align in $3; do + AC_TRY_COMPILE([ + #include + struct aligner { char c; $2 a; }; + ], + [ + int a[offsetof(struct aligner, a) == $align ? 1 : -1]; + return 0; + ], + [moz_cv_align_of_$1=$align; break], []) + done + if test ! "$moz_cv_align_of_$1"; then + AC_MSG_ERROR([No alignment found for $2]) + fi +]) +AC_DEFINE_UNQUOTED($1, [$moz_cv_align_of_$1]) +]) diff --git a/js/src/build/autoconf/mozprog.m4 b/js/src/build/autoconf/mozprog.m4 new file mode 100644 index 0000000..f22b4c6 --- /dev/null +++ b/js/src/build/autoconf/mozprog.m4 @@ -0,0 +1,76 @@ +dnl ***** BEGIN LICENSE BLOCK ***** +dnl Version: MPL 1.1/GPL 2.0/LGPL 2.1 +dnl +dnl The contents of this file are subject to the Mozilla Public License Version +dnl 1.1 (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl http://www.mozilla.org/MPL/ +dnl +dnl Software distributed under the License is distributed on an "AS IS" basis, +dnl WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +dnl for the specific language governing rights and limitations under the +dnl License. +dnl +dnl The Original Code is mozilla.org code. +dnl +dnl The Initial Developer of the Original Code is the +dnl Mozilla Foundation +dnl +dnl Portions created by the Initial Developer are Copyright (C) 2009 +dnl the Initial Developer. All Rights Reserved. +dnl +dnl Contributor(s): +dnl Benjamin Smedberg +dnl +dnl Alternatively, the contents of this file may be used under the terms of +dnl either of the GNU General Public License Version 2 or later (the "GPL"), +dnl or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +dnl in which case the provisions of the GPL or the LGPL are applicable instead +dnl of those above. If you wish to allow use of your version of this file only +dnl under the terms of either the GPL or the LGPL, and not to allow others to +dnl use your version of this file under the terms of the MPL, indicate your +dnl decision by deleting the provisions above and replace them with the notice +dnl and other provisions required by the GPL or the LGPL. If you do not delete +dnl the provisions above, a recipient may use your version of this file under +dnl the terms of any one of the MPL, the GPL or the LGPL. +dnl +dnl ***** END LICENSE BLOCK ***** + +AC_DEFUN(MOZ_PROG_CHECKMSYS, +[AC_REQUIRE([AC_INIT_BINSH])dnl +if test `uname -s | grep -c MINGW 2>/dev/null` != "0"; then + msyshost=1 +fi +]) + +AC_DEFUN(MOZ_PATH_PROG, +[ AC_PATH_PROG($1,$2,$3,$4) + if test "$msyshost"; then + case "[$]$1" in + /*) + tmp_DIRNAME=`dirname "[$]$1"` + tmp_BASENAME=`basename "[$]$1"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + $1="$tmp_PWD/$tmp_BASENAME" + if test -e "[$]$1.exe"; then + $1="[$]$1.exe" + fi + esac + fi +]) + +AC_DEFUN(MOZ_PATH_PROGS, +[ AC_PATH_PROGS($1,$2,$3,$4) + if test "$msyshost"; then + case "[$]$1" in + /*) + tmp_DIRNAME=`dirname "[$]$1"` + tmp_BASENAME=`basename "[$]$1"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + $1="$tmp_PWD/$tmp_BASENAME" + if test -e "[$]$1.exe"; then + $1="[$]$1.exe" + fi + esac + fi +]) diff --git a/js/src/build/autoconf/nspr.m4 b/js/src/build/autoconf/nspr.m4 new file mode 100644 index 0000000..68087b4 --- /dev/null +++ b/js/src/build/autoconf/nspr.m4 @@ -0,0 +1,102 @@ +# -*- tab-width: 4; -*- +# Configure paths for NSPR +# Public domain - Chris Seawood 2001-04-05 +# Based upon gtk.m4 (also PD) by Owen Taylor + +dnl AM_PATH_NSPR([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for NSPR, and define NSPR_CFLAGS and NSPR_LIBS +dnl +dnl If the nspr-config script is available, use it to find the +dnl appropriate CFLAGS and LIBS, and to check for the required +dnl version, and run ACTION-IF-FOUND. +dnl +dnl Otherwise, if NO_NSPR_CONFIG_SYSTEM_VERSION is set, we use it, +dnl NO_NSPR_CONFIG_SYSTEM_CFLAGS, and NO_NSPR_CONFIG_SYSTEM_LIBS to +dnl provide default values, and run ACTION-IF-FOUND. (Some systems +dnl ship NSPR without nspr-config, but can glean the appropriate flags +dnl and version.) +dnl +dnl Otherwise, run ACTION-IF-NOT-FOUND. +AC_DEFUN([AM_PATH_NSPR], +[dnl + +AC_ARG_WITH(nspr-prefix, + [ --with-nspr-prefix=PFX Prefix where NSPR is installed], + nspr_config_prefix="$withval", + nspr_config_prefix="") + +AC_ARG_WITH(nspr-exec-prefix, + [ --with-nspr-exec-prefix=PFX + Exec prefix where NSPR is installed], + nspr_config_exec_prefix="$withval", + nspr_config_exec_prefix="") + + if test -n "$nspr_config_exec_prefix"; then + nspr_config_args="$nspr_config_args --exec-prefix=$nspr_config_exec_prefix" + if test -z "$NSPR_CONFIG"; then + NSPR_CONFIG=$nspr_config_exec_prefix/bin/nspr-config + fi + fi + if test -n "$nspr_config_prefix"; then + nspr_config_args="$nspr_config_args --prefix=$nspr_config_prefix" + if test -z "$NSPR_CONFIG"; then + NSPR_CONFIG=$nspr_config_prefix/bin/nspr-config + fi + fi + + unset ac_cv_path_NSPR_CONFIG + AC_PATH_PROG(NSPR_CONFIG, nspr-config, no) + min_nspr_version=ifelse([$1], ,4.0.0,$1) + AC_MSG_CHECKING(for NSPR - version >= $min_nspr_version) + + no_nspr="" + if test "$NSPR_CONFIG" != "no"; then + NSPR_CFLAGS=`$NSPR_CONFIG $nspr_config_args --cflags` + NSPR_LIBS=`$NSPR_CONFIG $nspr_config_args --libs` + NSPR_VERSION_STRING=`$NSPR_CONFIG $nspr_config_args --version` + elif test -n "${NO_NSPR_CONFIG_SYSTEM_VERSION}"; then + NSPR_CFLAGS="${NO_NSPR_CONFIG_SYSTEM_CFLAGS}" + NSPR_LIBS="${NO_NSPR_CONFIG_SYSTEM_LDFLAGS}" + NSPR_VERSION_STRING="$NO_NSPR_CONFIG_SYSTEM_VERSION" + else + no_nspr="yes" + fi + + if test -z "$no_nspr"; then + nspr_config_major_version=`echo $NSPR_VERSION_STRING | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + nspr_config_minor_version=`echo $NSPR_VERSION_STRING | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + nspr_config_micro_version=`echo $NSPR_VERSION_STRING | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + min_nspr_major_version=`echo $min_nspr_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + min_nspr_minor_version=`echo $min_nspr_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + min_nspr_micro_version=`echo $min_nspr_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "$nspr_config_major_version" -ne "$min_nspr_major_version"; then + no_nspr="yes" + elif test "$nspr_config_major_version" -eq "$min_nspr_major_version" && + test "$nspr_config_minor_version" -lt "$min_nspr_minor_version"; then + no_nspr="yes" + elif test "$nspr_config_major_version" -eq "$min_nspr_major_version" && + test "$nspr_config_minor_version" -eq "$min_nspr_minor_version" && + test "$nspr_config_micro_version" -lt "$min_nspr_micro_version"; then + no_nspr="yes" + fi + fi + + if test -z "$no_nspr"; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + ifelse([$3], , :, [$3]) + fi + + + AC_SUBST(NSPR_CFLAGS) + AC_SUBST(NSPR_LIBS) + +]) diff --git a/js/src/build/autoconf/pkg.m4 b/js/src/build/autoconf/pkg.m4 new file mode 100644 index 0000000..d84d210 --- /dev/null +++ b/js/src/build/autoconf/pkg.m4 @@ -0,0 +1,59 @@ +# PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) +# defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page +# also defines GSTUFF_PKG_ERRORS on error +AC_DEFUN([PKG_CHECK_MODULES], +[succeeded=no + + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + if test "$PKG_CONFIG" = "no" ; then + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + PKG_CONFIG_MIN_VERSION=0.9.0 + if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then + AC_MSG_CHECKING(for $2) + + if $PKG_CONFIG --exists "$2" ; then + AC_MSG_RESULT(yes) + succeeded=yes + + AC_MSG_CHECKING($1_CFLAGS) + $1_CFLAGS=`$PKG_CONFIG --cflags "$2"` + AC_MSG_RESULT($$1_CFLAGS) + + AC_MSG_CHECKING($1_LIBS) + ## Remove evil flags like -Wl,--export-dynamic + $1_LIBS="`$PKG_CONFIG --libs \"$2\" |sed s/-Wl,--export-dynamic//g`" + AC_MSG_RESULT($$1_LIBS) + else + $1_CFLAGS="" + $1_LIBS="" + ## If we have a custom action on failure, don't print errors, but + ## do set a variable so people can do so. + $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + ifelse([$4], ,echo $$1_PKG_ERRORS,) + fi + + AC_SUBST($1_CFLAGS) + AC_SUBST($1_LIBS) + else + echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." + echo "*** See http://www.freedesktop.org/software/pkgconfig" + fi + fi + + if test $succeeded = yes; then + ifelse([$3], , :, [$3]) + else + if test "$COMPILE_ENVIRONMENT"; then + ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4]) + fi + fi +]) + + diff --git a/js/src/build/cl.py b/js/src/build/cl.py new file mode 100644 index 0000000..0198c92 --- /dev/null +++ b/js/src/build/cl.py @@ -0,0 +1,96 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is cl.py: a python wrapper for cl to automatically generate +# dependency information. +# +# The Initial Developer of the Original Code is +# Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2010 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Kyle Huey +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +import os, os.path +import subprocess +import sys + +CL_INCLUDES_PREFIX = os.environ.get("CL_INCLUDES_PREFIX", "Note: including file:") + +def InvokeClWithDependencyGeneration(cmdline): + target = "" + # Figure out what the target is + for arg in cmdline: + if arg.startswith("-Fo"): + target = arg[3:] + break + + if target == None: + print >>sys.stderr, "No target set" and sys.exit(1) + + # The deps target lives here + depstarget = os.path.basename(target) + ".pp" + + cmdline += ['-showIncludes'] + cl = subprocess.Popen(cmdline, stdout=subprocess.PIPE) + + deps = set() + for line in cl.stdout: + # cl -showIncludes prefixes every header with "Note: including file:" + # and an indentation corresponding to the depth (which we don't need) + if line.startswith(CL_INCLUDES_PREFIX): + dep = line[len(CL_INCLUDES_PREFIX):].strip() + # We can't handle pathes with spaces properly in mddepend.pl, but + # we can assume that anything in a path with spaces is a system + # header and throw it away. + if dep.find(' ') == -1: + deps.add(dep) + else: + sys.stdout.write(line) # Make sure we preserve the relevant output + # from cl + + ret = cl.wait() + if ret != 0 or target == "": + sys.exit(ret) + + depsdir = os.path.normpath(os.path.join(os.path.dirname(target), ".deps")) + depstarget = os.path.join(depsdir, depstarget) + if not os.path.isdir(depsdir): + try: + os.makedirs(depsdir) + except OSError: + pass # This suppresses the error we get when the dir exists, at the + # cost of masking failure to create the directory. We'll just + # die on the next line though, so it's not that much of a loss. + + f = open(depstarget, "w") + for dep in sorted(deps): + print >>f, "%s: %s" % (target, dep) + +if __name__ == "__main__": + InvokeClWithDependencyGeneration(sys.argv[1:]) diff --git a/js/src/build/cygwin-wrapper b/js/src/build/cygwin-wrapper new file mode 100644 index 0000000..679f0a1 --- /dev/null +++ b/js/src/build/cygwin-wrapper @@ -0,0 +1,75 @@ +#!/bin/sh +# +# Stupid wrapper to avoid win32 dospath/cygdrive issues +# Try not to spawn programs from within this file. If the stuff in here looks royally +# confusing, see bug: http://bugzilla.mozilla.org/show_bug.cgi?id=206643 +# and look at the older versions of this file that are easier to read, but +# do basically the same thing +# + +prog=$1 +shift +if test -z "$prog"; then + exit 0 +fi + +# If $CYGDRIVE_MOUNT was not set in configure, give $mountpoint the results of mount -p +mountpoint=$CYGDRIVE_MOUNT +if test -z "$mountpoint"; then + mountpoint=`mount -p` + if test -z "$mountpoint"; then + print "Cannot determine cygwin mount points. Exiting" + exit 1 + fi +fi + +# Delete everything but "/cygdrive" (or other mountpoint) from mount=`mount -p` +mountpoint=${mountpoint#*/} +mountpoint=/${mountpoint%%[!A-Za-z0-9_]*} +mountpoint=${mountpoint%/} + +args="" +up="" +if test "${prog}" = "-up"; then + up=1 + prog=${1} + shift +fi + +process=1 + +# Convert the mountpoint in parameters to Win32 filenames +# For instance: /cygdrive/c/foo -> c:/foo +for i in "${@}" +do + if test "${i}" = "-wrap"; then + process=1 + else + if test "${i}" = "-nowrap"; then + process= + else + if test -n "${process}"; then + if test -n "${up}"; then + pathname=${i#-I[a-zA-Z]:/} + if ! test "${pathname}" = "${i}"; then + no_i=${i#-I} + driveletter=${no_i%%:*} + i=-I${mountpoint}/${driveletter}/${pathname} + fi + else + eval 'leader=${i%%'${mountpoint}'/[a-zA-Z]/*}' + if ! test "${leader}" = "${i}"; then + eval 'pathname=${i#'${leader}${mountpoint}'/[a-zA-Z]/}' + eval 'no_mountpoint=${i#'${leader}${mountpoint}'/}' + driveletter=${no_mountpoint%%/*} + i=${leader}${driveletter}:/${pathname} + fi + fi + fi + + args="${args} ${i}" + fi + fi +done + +exec $prog $args diff --git a/js/src/build/hcc b/js/src/build/hcc new file mode 100644 index 0000000..adadbe4 --- /dev/null +++ b/js/src/build/hcc @@ -0,0 +1,111 @@ +#!/bin/sh +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Fix brain-damaged compilers that don't understand -o and -c together +# +CC=`echo $1 | sed -e "s|'||g" -e 's|"||g'` +shift +DASH_C=0 +DASH_O=0 +DUMMY="XxxXxxX" +GET_OBJECT=0 +OBJ="${DUMMY}" +OBJECT="${DUMMY}" + +for i in $* +do + [ "${CHECK_O}" = yes ] && { + case $i in + ./*/*.o) OBJECT="$i" + OPTS="${OPTS} -o" + DASH_O=1 + ;; + ./*.o) OBJECT="`basename $i`" + i="" + DASH_O=1 + ;; + *.o) if [ $i = `basename $i` ] + then + OBJECT="$i" + i="" + else + OPTS="${OPTS} -o" + fi + DASH_O=1 + ;; + *) OPTS="${OPTS} -o $i" + DASH_O=1 + i="" + ;; + esac + CHECK_O=no + } + case $i in + -c) DASH_C=1 + OPTS="${OPTS} -c" + ;; + -o) CHECK_O=yes + ;; + *.c) C_SRC=$i + OPTS="${OPTS} $i" +# cc always creates the .o from the .c name + OBJ=`basename $C_SRC .c`.o + ;; + *.s) S_SRC=$i + OPTS="${OPTS} $i" +# or the .o from the .s name + OBJ=`basename $S_SRC .s`.o + ;; + *.o) OBJECT=$i + OPTS="${OPTS} $i" + ;; + *) OPTS="${OPTS} $i" + ;; + esac +done + +${CC} ${OPTS} || exit $? + +# if there was no -c and -o we're done +[ $DASH_C = 1 -a $DASH_O = 1 ] || exit 0 + +# if $OBJ and $OBJECT are the same we're done +[ $OBJ = $OBJECT ] && exit 0 + +[ -f $OBJ ] && mv -f $OBJ $OBJECT diff --git a/js/src/build/hcpp b/js/src/build/hcpp new file mode 100644 index 0000000..ea55fa4 --- /dev/null +++ b/js/src/build/hcpp @@ -0,0 +1,155 @@ +#!/bin/sh +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Wrapper for brain-damaged compilers that don't understand -o and -c together. +# +CXX=`echo $1 | sed -e "s|'||g" -e 's|"||g'` +shift +DUMMY="XxxXxxX" +DASH_C=0 +DASH_O=0 +GET_OBJECT=0 +C_SRC="${DUMMY}" +CC_SRC="${DUMMY}" +CPP_SRC="${DUMMY}" +S_SRC="${DUMMY}" +OBJECT="${DUMMY}" +NEW_i="${DUMMY}" +PLATFORM=`uname -s` + +for i in $* +do + [ ${GET_OBJECT} -eq 1 ] && { + case $i in + ./*/*.o) OBJECT="$i" + OPTS="${OPTS} -o" + DASH_O=1 + ;; + ./*.o) OBJECT="`basename $i`" + i="" + DASH_O=1 + ;; + *.o) if [ $i = `basename $i` ] + then + i="" + else + OPTS="${OPTS} -o" + DASH_O=1 + fi + ;; + *) OPTS="${OPTS} -o $i" + DASH_O=1 + i="" + ;; + esac + GET_OBJECT=0 + } + case $i in + -c) + DASH_C=1 + OPTS="${OPTS} -c" + ;; + -o) + GET_OBJECT=1 + ;; + *.c) + C_SRC="$i" + OPTS="${OPTS} $i" +# cc always creates the .o from the .c name + OBJ=`basename ${C_SRC} .c`.o + ;; + +.*) + OPTS="${OPTS} $i" + ;; + *.cpp) + CPP_SRC="$i" + if [ "${PLATFORM}" = "SCO_SV" ]; then + OPTS="${OPTS} +.cpp $i" + elif [ "${PLATFORM}" = "IRIX" ]; then + NEW_i=`basename ${CPP_SRC} .cpp`.C + rm -f ${NEW_i} + cp $i ${NEW_i} + OPTS="${OPTS} ${NEW_i}" + else + OPTS="${OPTS} $i" + fi +# cc always creates the .o from the .cpp name + OBJ=`basename ${CPP_SRC} .cpp`.o + ;; + *.cc) + CC_SRC="$i" + OPTS="${OPTS} $i" +# cc always creates the .o from the .cc name + OBJ=`basename ${CC_SRC} .cc`.o + ;; + *.s) + S_SRC="$i" + OPTS="${OPTS} $i" +# cc always creates the .o from the .s name + OBJ=`basename ${S_SRC} .s`.o + ;; + *.o) OBJECT=$i + OPTS="${OPTS} $i" + ;; + *) OPTS="${OPTS} $i" + ;; + esac +done + +${CXX} ${OPTS} || exit $? +rm -f ${NEW_i} + +# Really only needed for NSPR now. +if [ "${PLATFORM}" = "IRIX" -a "$OBJ" != "$OBJECT" ]; then + OBJ=$OBJECT +fi + +# LAME!!! +if [ -f -O ]; then + mv -f -- -O ${OBJECT} +fi + +# if there was no -c and -o we're done +[ ${DASH_C} -eq 1 -a ${DASH_O} -eq 1 ] || exit 0 + +# if $OBJ and $OBJECT are the same we're done +[ $OBJ = $OBJECT ] && exit 0 + +[ -f $OBJ ] && mv -f $OBJ $OBJECT + diff --git a/js/src/build/msys-perl-wrapper b/js/src/build/msys-perl-wrapper new file mode 100644 index 0000000..0f81e1a --- /dev/null +++ b/js/src/build/msys-perl-wrapper @@ -0,0 +1,16 @@ +#!/bin/sh + +args="" + +for i in "${@}" +do + case "$i" in + -I?:/*) + i="$(echo "${i}" | sed -e 's|^-I\(.\):/|-I/\1/|')" + ;; + esac + + args="${args} '${i}'" +done + +eval "exec perl $args" diff --git a/js/src/build/unix/mddepend.pl b/js/src/build/unix/mddepend.pl new file mode 100644 index 0000000..6889141 --- /dev/null +++ b/js/src/build/unix/mddepend.pl @@ -0,0 +1,171 @@ +#!/usr/bin/env perl + +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is this file as it was released upon March 8, 1999. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# mddepend.pl - Reads in dependencies generated my -MD flag. Prints list +# of objects that need to be rebuilt. These can then be added to the +# PHONY target. Using this script copes with the problem of header +# files that have been removed from the build. +# +# Usage: +# mddepend.pl +# +# Send comments, improvements, bugs to Steve Lamm (slamm@netscape.com). + +use strict; + +use constant DEBUG => 0; + +my $outfile = shift @ARGV; +my $silent = $ENV{MAKEFLAGS} =~ /^\w*s|\s-s/; + +my $line = ''; +my %alldeps; +# Parse dependency files +while (<>) { + s/\r?\n$//; # Handle both unix and DOS line endings + $line .= $_; + if ($line =~ /\\$/) { + chop $line; + next; + } + + $line =~ s|\\|/|g; + + my ($obj,$rest) = split /\s*:\s+/, $line, 2; + $line = ''; + next if !$obj || !$rest; + + my @deps = split /\s+/, $rest; + push @{$alldeps{$obj}}, @deps; + if (DEBUG >= 2) { + foreach my $dep (@deps) { print STDERR "add $obj $dep\n"; } + } +} + +# Test dependencies +my %modtimes; # cache +my @objs; # force rebuild on these +OBJ_LOOP: foreach my $obj (keys %alldeps) { + my $mtime = (stat $obj)[9] or next; + + my %not_in_cache; + my $deps = $alldeps{$obj}; + foreach my $dep_file (@{$deps}) { + my $dep_mtime = $modtimes{$dep_file}; + if (not defined $dep_mtime) { + print STDERR "Skipping $dep_file for $obj, will stat() later\n" if DEBUG >= 2; + $not_in_cache{$dep_file} = 1; + next; + } + + print STDERR "Found $dep_file in cache\n" if DEBUG >= 2; + + if ($dep_mtime > $mtime) { + print STDERR "$dep_file($dep_mtime) newer than $obj($mtime)\n" if DEBUG; + } + elsif ($dep_mtime == -1) { + print STDERR "Couldn't stat $dep_file for $obj\n" if DEBUG; + } + else { + print STDERR "$dep_file($dep_mtime) older than $obj($mtime)\n" if DEBUG >= 2; + next; + } + + push @objs, $obj; # dependency is missing or newer + next OBJ_LOOP; # skip checking the rest of the dependencies + } + + foreach my $dep_file (keys %not_in_cache) { + print STDERR "STAT $dep_file for $obj\n" if DEBUG >= 2; + my $dep_mtime = $modtimes{$dep_file} = (stat $dep_file)[9] || -1; + + if ($dep_mtime > $mtime) { + print STDERR "$dep_file($dep_mtime) newer than $obj($mtime)\n" if DEBUG; + } + elsif ($dep_mtime == -1) { + print STDERR "Couldn't stat $dep_file for $obj\n" if DEBUG; + } + else { + print STDERR "$dep_file($dep_mtime) older than $obj($mtime)\n" if DEBUG >= 2; + next; + } + + push @objs, $obj; # dependency is missing or newer + next OBJ_LOOP; # skip checking the rest of the dependencies + } + + # If we get here it means nothing needs to be done for $obj +} + +# Output objects to rebuild (if needed). +if ($outfile eq '-') { + if (@objs) { + print "@objs: FORCE\n"; + } +} elsif (@objs) { + my $old_output; + my $new_output = "@objs: FORCE\n"; + + # Read in the current dependencies file. + open(OLD, "<$outfile") + and $old_output = ; + close(OLD); + + # Only write out the dependencies if they are different. + if ($new_output ne $old_output) { + open(OUT, ">$outfile") and print OUT "$new_output"; + print "Updating dependencies file, $outfile\n" unless $silent; + if (DEBUG) { + print "new: $new_output\n"; + print "was: $old_output\n" if $old_output ne ''; + } + } +} elsif (-s $outfile) { + # Remove the old dependencies because all objects are up to date. + print "Removing old dependencies file, $outfile\n" unless $silent; + + if (DEBUG) { + my $old_output; + open(OLD, "<$outfile") + and $old_output = ; + close(OLD); + print "was: $old_output\n"; + } + + unlink $outfile; +} diff --git a/js/src/build/unix/print-failed-commands.sh b/js/src/build/unix/print-failed-commands.sh new file mode 100755 index 0000000..ac90eb8 --- /dev/null +++ b/js/src/build/unix/print-failed-commands.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# +# Usage from makefile: +# ELOG = . $(topdir)/build/autoconf/print-failed-commands.sh +# $(ELOG) $(CC) $CFLAGS -o $@ $< +# +# This shell script is used by the build system to print out commands that fail +# to execute properly. It is designed to make the "make -s" command more +# useful. +# +# Note that in the example we are sourcing rather than execing the script. +# Since make already started a shell for us, we might as well use it rather +# than starting a new one. + +( exec "$@" ) || { + echo + echo "In the directory " `pwd` + echo "The following command failed to execute properly:" + echo "$@" + exit 1; +} diff --git a/js/src/build/unix/uniq.pl b/js/src/build/unix/uniq.pl new file mode 100644 index 0000000..1b40bda --- /dev/null +++ b/js/src/build/unix/uniq.pl @@ -0,0 +1,63 @@ +#!/usr/bin/env perl + +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is this file as it was released upon December 26, 2000. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Christopher Seawood +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +use Getopt::Std; + +getopts('rs'); +$regexp = 1 if (defined($opt_r)); +$sort = 1 if (defined($opt_s)); + +undef @out; +if ($sort) { + @in = sort @ARGV; +} else { + @in = @ARGV; +} +foreach $d (@in) { + if ($regexp) { + $found = 0; + foreach $dir (@out) { + $found++, last if ($d =~ m/^$dir\// || $d eq $dir); + } + push @out, $d if (!$found); + } else { + push @out, $d if (!grep(/^$d$/, @out)); + } +} +print "@out\n" diff --git a/js/src/build/win32/pgomerge.py b/js/src/build/win32/pgomerge.py new file mode 100644 index 0000000..383457b --- /dev/null +++ b/js/src/build/win32/pgomerge.py @@ -0,0 +1,40 @@ +#!/usr/bin/python +# Usage: pgomerge.py +# Gathers .pgc files from dist/bin and merges them into +# $PWD/$basename.pgd using pgomgr, then deletes them. +# No errors if any of these files don't exist. + +import sys, os, os.path, subprocess +if not sys.platform == "win32": + raise Exception("This script was only meant for Windows.") + +def MergePGOFiles(basename, pgddir, pgcdir): + """Merge pgc files produced from an instrumented binary + into the pgd file for the second pass of profile-guided optimization + with MSVC. |basename| is the name of the DLL or EXE without the + extension. |pgddir| is the path that contains .pgd + (should be the objdir it was built in). |pgcdir| is the path + containing basename!N.pgc files, which is probably dist/bin. + Calls pgomgr to merge each pgc file into the pgd, then deletes + the pgc files.""" + if not os.path.isdir(pgddir) or not os.path.isdir(pgcdir): + return + pgdfile = os.path.abspath(os.path.join(pgddir, basename + ".pgd")) + if not os.path.isfile(pgdfile): + return + for file in os.listdir(pgcdir): + if file.startswith(basename+"!") and file.endswith(".pgc"): + try: + pgcfile = os.path.normpath(os.path.join(pgcdir, file)) + subprocess.call(['pgomgr', '-merge', + pgcfile, + pgdfile]) + os.remove(pgcfile) + except OSError: + pass + +if __name__ == '__main__': + if len(sys.argv) != 3: + print >>sys.stderr, "Usage: pgomerge.py " + sys.exit(1) + MergePGOFiles(sys.argv[1], os.getcwd(), sys.argv[2]) diff --git a/js/src/config.mk b/js/src/config.mk new file mode 100644 index 0000000..f3f802e --- /dev/null +++ b/js/src/config.mk @@ -0,0 +1,193 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +ifdef JS_DIST +DIST = $(JS_DIST) +else +DIST = $(DEPTH)/../../dist +endif + +# Set os+release dependent make variables +OS_ARCH := $(subst /,_,$(shell uname -s | sed /\ /s//_/)) + +# Attempt to differentiate between SunOS 5.4 and x86 5.4 +OS_CPUARCH := $(shell uname -m) +ifeq ($(OS_CPUARCH),i86pc) +OS_RELEASE := $(shell uname -r)_$(OS_CPUARCH) +else +ifeq ($(OS_ARCH),AIX) +OS_RELEASE := $(shell uname -v).$(shell uname -r) +else +OS_RELEASE := $(shell uname -r) +endif +endif +ifeq ($(OS_ARCH),IRIX64) +OS_ARCH := IRIX +endif + +# Handle output from win32 unames other than Netscape's version +ifeq (,$(filter-out Windows_95 Windows_98 CYGWIN_95-4.0 CYGWIN_98-4.10, $(OS_ARCH))) + OS_ARCH := WIN95 +endif +ifeq ($(OS_ARCH),WIN95) + OS_ARCH := WINNT + OS_RELEASE := 4.0 +endif +ifeq ($(OS_ARCH), Windows_NT) + OS_ARCH := WINNT + OS_MINOR_RELEASE := $(shell uname -v) + ifeq ($(OS_MINOR_RELEASE),00) + OS_MINOR_RELEASE = 0 + endif + OS_RELEASE := $(OS_RELEASE).$(OS_MINOR_RELEASE) +endif +ifeq (CYGWIN_NT,$(findstring CYGWIN_NT,$(OS_ARCH))) + OS_RELEASE := $(patsubst CYGWIN_NT-%,%,$(OS_ARCH)) + OS_ARCH := WINNT +endif +ifeq ($(OS_ARCH), CYGWIN32_NT) + OS_ARCH := WINNT +endif +ifeq (MINGW32_NT,$(findstring MINGW32_NT,$(OS_ARCH))) + OS_RELEASE := $(patsubst MINGW32_NT-%,%,$(OS_ARCH)) + OS_ARCH := WINNT +endif + +# Virtually all Linux versions are identical. +# Any distinctions are handled in linux.h +ifeq ($(OS_ARCH),Linux) +OS_CONFIG := Linux_All +else +ifeq ($(OS_ARCH),dgux) +OS_CONFIG := dgux +else +ifeq ($(OS_ARCH),Darwin) +OS_CONFIG := Darwin +else +ifeq ($(OS_ARCH),Darwin64) +OS_CONFIG := Darwin64 +else +OS_CONFIG := $(OS_ARCH)$(OS_OBJTYPE)$(OS_RELEASE) +endif +endif +endif +endif + +ASFLAGS = +DEFINES = + +ifeq ($(OS_ARCH), WINNT) +INSTALL = nsinstall +CP = cp +else +INSTALL = $(DIST)/bin/nsinstall +CP = cp +endif + +ifdef BUILD_OPT +ifdef USE_MSVC +OPTIMIZER = -O2 -GL +INTERP_OPTIMIZER = -O2 -GL +BUILTINS_OPTIMIZER = -O2 -GL +LDFLAGS += -LTCG +else +OPTIMIZER = -Os -fno-exceptions -fno-rtti -fstrict-aliasing -Wstrict-aliasing=3 +BUILTINS_OPTIMIZER = -O9 -fno-exceptions -fno-rtti -fstrict-aliasing +INTERP_OPTIMIZER = -O3 -fno-exceptions -fno-rtti -fstrict-aliasing +endif +DEFINES += -UDEBUG -DNDEBUG -UDEBUG_$(USER) +OBJDIR_TAG = _OPT +else +ifdef USE_MSVC +OPTIMIZER = -Zi +INTERP_OPTIMIZER = -Zi +BUILTINS_OPTIMIZER = $(INTERP_OPTIMIZER) +else +OPTIMIZER = -g3 -fstrict-aliasing -fno-exceptions -fno-rtti -Wstrict-aliasing=3 +INTERP_OPTIMIZER = -g3 -fstrict-aliasing -fno-exceptions -fno-rtti +BUILTINS_OPTIMIZER = $(INTERP_OPTIMIZER) +endif +DEFINES += -DDEBUG -DDEBUG_$(USER) +OBJDIR_TAG = _DBG +endif + +SO_SUFFIX = so + +NS_USE_NATIVE = 1 + +include $(DEPTH)/ref-config/$(OS_CONFIG).mk + +ifndef OBJ_SUFFIX +ifdef USE_MSVC +OBJ_SUFFIX = obj +else +OBJ_SUFFIX = o +endif +endif + +ifndef HOST_BIN_SUFFIX +ifeq ($(OS_ARCH),WINNT) +HOST_BIN_SUFFIX = .exe +else +HOST_BIN_SUFFIX = +endif +endif + +# Name of the binary code directories +ifdef OBJROOT +# prepend $(DEPTH) to the root unless it is an absolute path +OBJDIR = $(if $(filter /%,$(OBJROOT)),$(OBJROOT),$(DEPTH)/$(OBJROOT)) +else +ifeq ($(DEPTH),.) +OBJDIR = $(OS_CONFIG)$(OBJDIR_TAG).$(if $(BUILD_IDG),OBJD,OBJ) +else +OBJDIR = $(DEPTH)/$(OS_CONFIG)$(OBJDIR_TAG).$(if $(BUILD_IDG),OBJD,OBJ) +endif +endif + +VPATH = $(OBJDIR) + +LCJAR = js15lc30.jar + +# Library name +LIBDIR := lib +ifeq ($(CPU_ARCH), x86_64) +LIBDIR := lib64 +endif + diff --git a/js/src/config/Makefile.in b/js/src/config/Makefile.in new file mode 100644 index 0000000..a822746 --- /dev/null +++ b/js/src/config/Makefile.in @@ -0,0 +1,109 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Robert Ginda +# John Taylor +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +# For sanity's sake, we compile nsinstall without the wrapped system +# headers, so that we can use it to set up the wrapped system headers. +VISIBILITY_FLAGS = + +HOST_PROGRAM = nsinstall$(HOST_BIN_SUFFIX) + +ifeq (WINNT,$(HOST_OS_ARCH)) +HOST_CSRCS = nsinstall_win.c +else +HOST_CSRCS = nsinstall.c pathsub.c +endif + +PLSRCS = nfspwd.pl + +TARGETS = $(HOST_PROGRAM) $(PLSRCS:.pl=) $(SIMPLE_PROGRAMS) + +# IMPORTANT: Disable NSBUILDROOT for this directory only, otherwise we have +# a recursive rule for finding nsinstall and the Perl scripts. +ifdef NSBUILDROOT +override NSBUILDROOT := +endif + +ifdef GNU_CC +MODULE_OPTIMIZE_FLAGS = -O3 +endif + +ifndef COMPILER_DEPEND +ifndef MOZ_NATIVE_MAKEDEPEND +DIRS += mkdepend +endif +endif + +include $(topsrcdir)/config/config.mk + +# Do not install util programs +NO_INSTALL=1 + +include $(topsrcdir)/config/rules.mk + +HOST_CFLAGS += -DUNICODE -D_UNICODE + +export:: $(TARGETS) +ifdef HOST_PROGRAM + $(INSTALL) $(HOST_PROGRAM) $(DIST)/bin +endif + +ifdef WRAP_SYSTEM_INCLUDES +export:: + if test ! -d system_wrappers_js; then mkdir system_wrappers_js; fi + $(PERL) $(srcdir)/preprocessor.pl $(DEFINES) $(ACDEFINES) \ + -DBUILD_STATIC_LIBS=$(BUILD_STATIC_LIBS) \ + $(srcdir)/system-headers | $(PERL) $(srcdir)/make-system-wrappers.pl system_wrappers_js + $(INSTALL) system_wrappers_js $(DIST) + +GARBAGE_DIRS += system_wrappers_js +endif + +FORCE: + +ifdef MKDEPEND_DIR +clean clobber realclean clobber_all:: + cd $(MKDEPEND_DIR); $(MAKE) $@ +endif diff --git a/js/src/config/Moz/Milestone.pm b/js/src/config/Moz/Milestone.pm new file mode 100644 index 0000000..8dd1449 --- /dev/null +++ b/js/src/config/Moz/Milestone.pm @@ -0,0 +1,232 @@ +#!/usr/bin/perl -w +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Win32 Version System. +# +# The Initial Developer of the Original Code is Netscape Communications Corporation +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +package Moz::Milestone; +use strict; + +use vars qw($officialMilestone + $milestone); + +local $Moz::Milestone::milestone; +local $Moz::Milestone::officialMilestone; + +# +# Usage: getOfficialMilestone($milestoneFile) +# Returns full milestone (x.x.x.x[ab12pre+]) +# +sub getOfficialMilestone($) { + my $mfile = $_[0]; + open(FILE,"$mfile") || + die ("Can't open $mfile for reading!"); + + my $num = ; + while($num =~ /^\s*#/ || $num !~ /^\d/) { + $num = ; + } + + close(FILE); + if ($num !~ /^\d/) { return; } + chomp($num); + # Remove extra ^M caused by using dos-mode line-endings + chop $num if (substr($num, -1, 1) eq "\r"); + $Moz::Milestone::officialMilestone = $num; + $Moz::Milestone::milestone = &getMilestoneNum; + return $num; +} + +# +# Usage: getMilestoneNum($num) +# Returns: milestone without a + if it exists. +# +sub getMilestoneNum { + if (defined($Moz::Milestone::milestone)) { + return $Moz::Milestone::milestone; + } + + if (defined($Moz::Milestone::officialMilestone)) { + $Moz::Milestone::milestone = $Moz::Milestone::officialMilestone; + } else { + $Moz::Milestone::milestone = $_[0]; + } + + if ($Moz::Milestone::milestone =~ /\+$/) { # for x.x.x+, strip off the + + $Moz::Milestone::milestone =~ s/\+$//; + } + + return $Moz::Milestone::milestone; +} + +# +# Usage: getMilestoneQualifier($num) +# Returns: + if it exists. +# +sub getMilestoneQualifier { + my $milestoneQualifier; + if (defined($Moz::Milestone::officialMilestone)) { + $milestoneQualifier = $Moz::Milestone::officialMilestone; + } else { + $milestoneQualifier = $_[0]; + } + + if ($milestoneQualifier =~ /\+$/) { + return "+"; + } +} + +sub getMilestoneMajor { + my $milestoneMajor; + if (defined($Moz::Milestone::milestone)) { + $milestoneMajor = $Moz::Milestone::milestone; + } else { + $milestoneMajor = $_[0]; + } + my @parts = split(/\./,$milestoneMajor); + return $parts[0]; +} + +sub getMilestoneMinor { + my $milestoneMinor; + if (defined($Moz::Milestone::milestone)) { + $milestoneMinor = $Moz::Milestone::milestone; + } else { + $milestoneMinor = $_[0]; + } + my @parts = split(/\./,$milestoneMinor); + + if ($#parts < 1 ) { return 0; } + return $parts[1]; +} + +sub getMilestoneMini { + my $milestoneMini; + if (defined($Moz::Milestone::milestone)) { + $milestoneMini = $Moz::Milestone::milestone; + } else { + $milestoneMini = $_[0]; + } + my @parts = split(/\./,$milestoneMini); + + if ($#parts < 2 ) { return 0; } + return $parts[2]; +} + +sub getMilestoneMicro { + my $milestoneMicro; + if (defined($Moz::Milestone::milestone)) { + $milestoneMicro = $Moz::Milestone::milestone; + } else { + $milestoneMicro = $_[0]; + } + my @parts = split(/\./,$milestoneMicro); + + if ($#parts < 3 ) { return 0; } + return $parts[3]; +} + +sub getMilestoneAB { + my $milestoneAB; + if (defined($Moz::Milestone::milestone)) { + $milestoneAB = $Moz::Milestone::milestone; + } else { + $milestoneAB = $_[0]; + } + + if ($milestoneAB =~ /a/) { return "alpha"; } + if ($milestoneAB =~ /b/) { return "beta"; } + return "final"; +} + +# +# build_file($template_file,$output_file) +# +sub build_file($$) { + my @FILE; + my @MILESTONE_PARTS; + my $MINI_VERSION = 0; + my $MICRO_VERSION = 0; + my $OFFICIAL = 0; + my $QUALIFIER = ""; + + if (!defined($Moz::Milestone::milestone)) { die("$0: no milestone file set!\n"); } + @MILESTONE_PARTS = split(/\./, &getMilestoneNum); + if ($#MILESTONE_PARTS >= 2) { + $MINI_VERSION = 1; + } else { + $MILESTONE_PARTS[2] = 0; + } + if ($#MILESTONE_PARTS >= 3) { + $MICRO_VERSION = 1; + } else { + $MILESTONE_PARTS[3] = 0; + } + if (! &getMilestoneQualifier) { + $OFFICIAL = 1; + } else { + $QUALIFIER = "+"; + } + + if (-e $_[0]) { + open(FILE, "$_[0]") || die("$0: Can't open $_[0] for reading!\n"); + @FILE = ; + close(FILE); + + open(FILE, ">$_[1]") || die("$0: Can't open $_[1] for writing!\n"); + + # + # There will be more of these based on what we need for files. + # + foreach(@FILE) { + s/__MOZ_MAJOR_VERSION__/$MILESTONE_PARTS[0]/g; + s/__MOZ_MINOR_VERSION__/$MILESTONE_PARTS[1]/g; + s/__MOZ_MINI_VERSION__/$MILESTONE_PARTS[2]/g; + s/__MOZ_MICRO_VERSION__/$MILESTONE_PARTS[3]/g; + if ($MINI_VERSION) { + s/__MOZ_OPTIONAL_MINI_VERSION__/.$MILESTONE_PARTS[2]/g; + } + if ($MICRO_VERSION) { + s/__MOZ_OPTIONAL_MICRO_VERSION__/.$MILESTONE_PARTS[3]/g; + } + + print FILE $_; + } + close(FILE); + } else { + die("$0: $_[0] doesn't exist for autoversioning!\n"); + } + +} + +1; diff --git a/js/src/config/autoconf.mk.in b/js/src/config/autoconf.mk.in new file mode 100644 index 0000000..f4c8150 --- /dev/null +++ b/js/src/config/autoconf.mk.in @@ -0,0 +1,361 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is this file as it was released upon August 6, 1998. +# +# The Initial Developer of the Original Code is +# Christopher Seawood. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Benjamin Smedberg +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# A netscape style .mk file for autoconf builds + +INCLUDED_AUTOCONF_MK = 1 +USE_AUTOCONF = 1 +MOZILLA_CLIENT = 1 +target = @target@ +ac_configure_args = @ac_configure_args@ +BUILD_MODULES = @BUILD_MODULES@ +MOZILLA_VERSION = @MOZILLA_VERSION@ + +MOZ_BUILD_APP = @MOZ_BUILD_APP@ +MOZ_APP_NAME = @MOZ_APP_NAME@ +MOZ_APP_DISPLAYNAME = @MOZ_APP_DISPLAYNAME@ +MOZ_APP_VERSION = @MOZ_APP_VERSION@ + +MOZ_PKG_SPECIAL = @MOZ_PKG_SPECIAL@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +includedir = @includedir@ +libdir = @libdir@ +datadir = @datadir@ +mandir = @mandir@ + +installdir = $(libdir)/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION) +sdkdir = $(libdir)/$(MOZ_APP_NAME)-devel-$(MOZ_APP_VERSION) + +TOP_DIST = @TOP_DIST@ +ifneq (,$(filter /%,$(TOP_DIST))) +DIST = $(TOP_DIST) +else +DIST = $(DEPTH)/$(TOP_DIST) +endif + +MOZ_JS_LIBS = @MOZ_JS_LIBS@ + +MOZ_SYNC_BUILD_FILES = @MOZ_SYNC_BUILD_FILES@ + +MOZ_DEBUG = @MOZ_DEBUG@ +MOZ_DEBUG_SYMBOLS = @MOZ_DEBUG_SYMBOLS@ +MOZ_DEBUG_ENABLE_DEFS = @MOZ_DEBUG_ENABLE_DEFS@ +MOZ_DEBUG_DISABLE_DEFS = @MOZ_DEBUG_DISABLE_DEFS@ +MOZ_DEBUG_FLAGS = @MOZ_DEBUG_FLAGS@ +MOZ_DEBUG_LDFLAGS=@MOZ_DEBUG_LDFLAGS@ +MOZ_EXTENSIONS = @MOZ_EXTENSIONS@ +MOZ_JSDEBUGGER = @MOZ_JSDEBUGGER@ +MOZ_LEAKY = @MOZ_LEAKY@ +MOZ_MEMORY = @MOZ_MEMORY@ +MOZ_PROFILING = @MOZ_PROFILING@ +MOZ_JPROF = @MOZ_JPROF@ +MOZ_SHARK = @MOZ_SHARK@ +MOZ_CALLGRIND = @MOZ_CALLGRIND@ +MOZ_VTUNE = @MOZ_VTUNE@ +JS_HAS_CTYPES = @JS_HAS_CTYPES@ +DEHYDRA_PATH = @DEHYDRA_PATH@ + +NS_TRACE_MALLOC = @NS_TRACE_MALLOC@ +INCREMENTAL_LINKER = @INCREMENTAL_LINKER@ +MACOSX_DEPLOYMENT_TARGET = @MACOSX_DEPLOYMENT_TARGET@ +BUILD_STATIC_LIBS = @BUILD_STATIC_LIBS@ +ENABLE_TESTS = @ENABLE_TESTS@ + +TAR=@TAR@ + +RM = rm -f + +# The MOZ_UI_LOCALE var is used to build a particular locale. Do *not* +# use the var to change any binary files. Do *not* use this var unless you +# write rules for the "clean-locale" and "locale" targets. +MOZ_UI_LOCALE = @MOZ_UI_LOCALE@ + +MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS = @MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS@ +MOZ_COMPONENT_NSPR_LIBS=@MOZ_COMPONENT_NSPR_LIBS@ + +MOZ_FIX_LINK_PATHS=@MOZ_FIX_LINK_PATHS@ + +XPCOM_FROZEN_LDOPTS=@XPCOM_FROZEN_LDOPTS@ +XPCOM_LIBS=@XPCOM_LIBS@ +MOZ_TIMELINE=@MOZ_TIMELINE@ + +ENABLE_STRIP = @ENABLE_STRIP@ +PKG_SKIP_STRIP = @PKG_SKIP_STRIP@ + +MOZ_POST_DSO_LIB_COMMAND = @MOZ_POST_DSO_LIB_COMMAND@ +MOZ_POST_PROGRAM_COMMAND = @MOZ_POST_PROGRAM_COMMAND@ + +MOZ_BUILD_ROOT = @MOZ_BUILD_ROOT@ + +MOZ_NATIVE_NSPR = @MOZ_NATIVE_NSPR@ + +CROSS_COMPILE = @CROSS_COMPILE@ + +OS_CPPFLAGS = @CPPFLAGS@ +OS_CFLAGS = $(OS_CPPFLAGS) @CFLAGS@ +OS_CXXFLAGS = $(OS_CPPFLAGS) @CXXFLAGS@ +OS_LDFLAGS = @LDFLAGS@ + +OS_COMPILE_CFLAGS = $(OS_CPPFLAGS) @COMPILE_CFLAGS@ +OS_COMPILE_CXXFLAGS = $(OS_CPPFLAGS) @COMPILE_CXXFLAGS@ + +OS_INCLUDES = $(NSPR_CFLAGS) +OS_LIBS = @LIBS@ +ACDEFINES = @MOZ_DEFINES@ + +WARNINGS_AS_ERRORS = @WARNINGS_AS_ERRORS@ + +MOZ_OPTIMIZE = @MOZ_OPTIMIZE@ +MOZ_OPTIMIZE_FLAGS = @MOZ_OPTIMIZE_FLAGS@ +MOZ_OPTIMIZE_LDFLAGS = @MOZ_OPTIMIZE_LDFLAGS@ +MOZ_OPTIMIZE_SIZE_TWEAK = @MOZ_OPTIMIZE_SIZE_TWEAK@ + +MOZ_RTTI_FLAGS_ON = @_MOZ_RTTI_FLAGS_ON@ +MOZ_EXCEPTIONS_FLAGS_ON = @_MOZ_EXCEPTIONS_FLAGS_ON@ + +MOZ_PROFILE_GUIDED_OPTIMIZE_DISABLE = @MOZ_PROFILE_GUIDED_OPTIMIZE_DISABLE@ +PROFILE_GEN_CFLAGS = @PROFILE_GEN_CFLAGS@ +PROFILE_GEN_LDFLAGS = @PROFILE_GEN_LDFLAGS@ +PROFILE_USE_CFLAGS = @PROFILE_USE_CFLAGS@ +PROFILE_USE_LDFLAGS = @PROFILE_USE_LDFLAGS@ + +WIN_TOP_SRC = @WIN_TOP_SRC@ +CYGWIN_WRAPPER = @CYGWIN_WRAPPER@ +AS_PERL = @AS_PERL@ +CYGDRIVE_MOUNT = @CYGDRIVE_MOUNT@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +AR_EXTRACT = @AR_EXTRACT@ +AR_LIST = @AR_LIST@ +AR_DELETE = @AR_DELETE@ +AS = @AS@ +ASFLAGS = @ASFLAGS@ +AS_DASH_C_FLAG = @AS_DASH_C_FLAG@ +LD = @LD@ +RC = @RC@ +RCFLAGS = @RCFLAGS@ +WINDRES = @WINDRES@ +IMPLIB = @IMPLIB@ +FILTER = @FILTER@ +BIN_FLAGS = @BIN_FLAGS@ +_MSC_VER = @_MSC_VER@ + +DLL_PREFIX = @DLL_PREFIX@ +LIB_PREFIX = @LIB_PREFIX@ +OBJ_SUFFIX = @OBJ_SUFFIX@ +LIB_SUFFIX = @LIB_SUFFIX@ +DLL_SUFFIX = @DLL_SUFFIX@ +BIN_SUFFIX = @BIN_SUFFIX@ +ASM_SUFFIX = @ASM_SUFFIX@ +IMPORT_LIB_SUFFIX = @IMPORT_LIB_SUFFIX@ +USE_N32 = @USE_N32@ +HAVE_64BIT_OS = @HAVE_64BIT_OS@ + +# Temp hack. It is not my intention to leave this crap in here for ever. +# Im talking to fur right now to solve the problem without introducing +# NS_USE_NATIVE to the build system -ramiro. +NS_USE_NATIVE = @NS_USE_NATIVE@ + +CC = @CC@ +CXX = @CXX@ + +CC_VERSION = @CC_VERSION@ +CXX_VERSION = @CXX_VERSION@ + +GNU_AS = @GNU_AS@ +GNU_LD = @GNU_LD@ +GNU_CC = @GNU_CC@ +GNU_CXX = @GNU_CXX@ +HAVE_GCC3_ABI = @HAVE_GCC3_ABI@ +INTEL_CC = @INTEL_CC@ +INTEL_CXX = @INTEL_CXX@ + +HOST_CC = @HOST_CC@ +HOST_CXX = @HOST_CXX@ +HOST_CFLAGS = @HOST_CFLAGS@ +HOST_CXXFLAGS = @HOST_CXXFLAGS@ +HOST_LDFLAGS = @HOST_LDFLAGS@ +HOST_OPTIMIZE_FLAGS = @HOST_OPTIMIZE_FLAGS@ +HOST_NSPR_MDCPUCFG = @HOST_NSPR_MDCPUCFG@ +HOST_AR = @HOST_AR@ +HOST_AR_FLAGS = @HOST_AR_FLAGS@ +HOST_LD = @HOST_LD@ +HOST_RANLIB = @HOST_RANLIB@ +HOST_BIN_SUFFIX = @HOST_BIN_SUFFIX@ + +HOST_OS_ARCH = @HOST_OS_ARCH@ +host_cpu = @host_cpu@ +host_vendor = @host_vendor@ +host_os = @host_os@ + +TARGET_NSPR_MDCPUCFG = @TARGET_NSPR_MDCPUCFG@ +TARGET_CPU = @TARGET_CPU@ +TARGET_VENDOR = @TARGET_VENDOR@ +TARGET_OS = @TARGET_OS@ +TARGET_MD_ARCH = @TARGET_MD_ARCH@ +TARGET_XPCOM_ABI = @TARGET_XPCOM_ABI@ + +AUTOCONF = @AUTOCONF@ +PERL = @PERL@ +PYTHON = @PYTHON@ +RANLIB = @RANLIB@ +UNZIP = @UNZIP@ +ZIP = @ZIP@ +XARGS = @XARGS@ +STRIP = @STRIP@ +DOXYGEN = @DOXYGEN@ +PBBUILD_BIN = @PBBUILD@ +SDP = @SDP@ +NSINSTALL_BIN = @NSINSTALL_BIN@ + +NSPR_CONFIG = @NSPR_CONFIG@ +NSPR_CFLAGS = @NSPR_CFLAGS@ +NSPR_LIBS = @NSPR_LIBS@ + +USE_DEPENDENT_LIBS = @USE_DEPENDENT_LIBS@ + +JS_NATIVE_EDITLINE = @JS_NATIVE_EDITLINE@ +JS_DISABLE_SHELL = @JS_DISABLE_SHELL@ +EDITLINE_LIBS = @EDITLINE_LIBS@ + +# MKSHLIB_FORCE_ALL is used to force the linker to include all object +# files present in an archive. MKSHLIB_UNFORCE_ALL reverts the linker +# to normal behavior. Makefile's that create shared libraries out of +# archives use these flags to force in all of the .o files in the +# archives into the shared library. +WRAP_MALLOC_LIB = @WRAP_MALLOC_LIB@ +WRAP_MALLOC_CFLAGS = @WRAP_MALLOC_CFLAGS@ +DSO_CFLAGS = @DSO_CFLAGS@ +DSO_PIC_CFLAGS = @DSO_PIC_CFLAGS@ +MKSHLIB = @MKSHLIB@ +MKCSHLIB = @MKCSHLIB@ +MKSHLIB_FORCE_ALL = @MKSHLIB_FORCE_ALL@ +MKSHLIB_UNFORCE_ALL = @MKSHLIB_UNFORCE_ALL@ +DSO_LDOPTS = @DSO_LDOPTS@ +DLL_SUFFIX = @DLL_SUFFIX@ + +NO_LD_ARCHIVE_FLAGS = @NO_LD_ARCHIVE_FLAGS@ + +MOZ_TOOLKIT_REGISTRY_CFLAGS = \ + $(TK_CFLAGS) + +MOZ_NATIVE_MAKEDEPEND = @SYSTEM_MAKEDEPEND@ + +export CL_INCLUDES_PREFIX = @CL_INCLUDES_PREFIX@ + +MOZ_AUTO_DEPS = @MOZ_AUTO_DEPS@ +COMPILER_DEPEND = @COMPILER_DEPEND@ +MDDEPDIR := @MDDEPDIR@ +CC_WRAPPER = @CC_WRAPPER@ +CXX_WRAPPER = @CXX_WRAPPER@ + +MOZ_DEMANGLE_SYMBOLS = @MOZ_DEMANGLE_SYMBOLS@ + +# XXX - these need to be cleaned up and have real checks added -cls +CM_BLDTYPE=dbg +AWT_11=1 +OS_TARGET=@OS_TARGET@ +OS_ARCH=@OS_ARCH@ +OS_RELEASE=@OS_RELEASE@ +OS_TEST=@OS_TEST@ +CPU_ARCH=@CPU_ARCH@ +INTEL_ARCHITECTURE=@INTEL_ARCHITECTURE@ + +# For Solaris build +SOLARIS_SUNPRO_CC = @SOLARIS_SUNPRO_CC@ +SOLARIS_SUNPRO_CXX = @SOLARIS_SUNPRO_CXX@ + +# For AIX build +AIX_OBJMODEL = @AIX_OBJMODEL@ + +# For OS/2 build +MOZ_OS2_TOOLS = @MOZ_OS2_TOOLS@ +MOZ_OS2_HIGH_MEMORY = @MOZ_OS2_HIGH_MEMORY@ + +MOZILLA_OFFICIAL = @MOZILLA_OFFICIAL@ + +# Win32 options +MOZ_BROWSE_INFO = @MOZ_BROWSE_INFO@ +MOZ_TOOLS_DIR = @MOZ_TOOLS_DIR@ +MOZ_QUANTIFY = @MOZ_QUANTIFY@ +MSMANIFEST_TOOL = @MSMANIFEST_TOOL@ +WIN32_REDIST_DIR = @WIN32_REDIST_DIR@ +MOZ_MEMORY_LDFLAGS = @MOZ_MEMORY_LDFLAGS@ + +# Codesighs tools option, enables win32 mapfiles. +MOZ_MAPINFO = @MOZ_MAPINFO@ + +WINCE = @WINCE@ +WINCE_WINDOWS_MOBILE = @WINCE_WINDOWS_MOBILE@ + +QEMU_CANT_RUN_JS_SHELL = @QEMU_CANT_RUN_JS_SHELL@ + +MACOS_SDK_DIR = @MACOS_SDK_DIR@ +NEXT_ROOT = @NEXT_ROOT@ +GCC_VERSION = @GCC_VERSION@ +XCODEBUILD_VERSION= @XCODEBUILD_VERSION@ +HAS_XCODE_2_1 = @HAS_XCODE_2_1@ +UNIVERSAL_BINARY= @UNIVERSAL_BINARY@ +HAVE_DTRACE= @HAVE_DTRACE@ + +VISIBILITY_FLAGS = @VISIBILITY_FLAGS@ +WRAP_SYSTEM_INCLUDES = @WRAP_SYSTEM_INCLUDES@ + +ENABLE_TRACEJIT = @ENABLE_TRACEJIT@ +ENABLE_METHODJIT = @ENABLE_METHODJIT@ +NANOJIT_ARCH = @NANOJIT_ARCH@ +HAVE_ARM_SIMD= @HAVE_ARM_SIMD@ + +JS_SHARED_LIBRARY = @JS_SHARED_LIBRARY@ +HAVE_LINUX_PERF_EVENT_H = @HAVE_LINUX_PERF_EVENT_H@ + +# We only want to do the pymake sanity on Windows, other os's can cope +ifeq (,$(filter-out WINNT WINCE,$(HOST_OS_ARCH))) +# Ensure invariants between GNU Make and pymake +# Checked here since we want the sane error in a file that +# actually can be found regardless of path-style. +ifeq (_:,$(.PYMAKE)_$(findstring :,$(srcdir))) +$(error Windows-style srcdir being used with GNU make. Did you mean to run $(topsrcdir)/build/pymake/make.py instead? [see-also: https://developer.mozilla.org/en/Gmake_vs._Pymake]) +endif +ifeq (1_a,$(.PYMAKE)_$(firstword a$(subst /, ,$(srcdir)))) +$(error MSYS-style srcdir being used with Pymake. Did you mean to run GNU Make instead? [see-also: https://developer.mozilla.org/en/Gmake_vs._Pymake]) +endif +endif # Windows diff --git a/js/src/config/check-sync-dirs.py b/js/src/config/check-sync-dirs.py new file mode 100644 index 0000000..ed2abb3 --- /dev/null +++ b/js/src/config/check-sync-dirs.py @@ -0,0 +1,107 @@ +# check-sync-dirs.py --- check that one directory is an exact subset of another +# +# Usage: python check-sync-dirs.py COPY ORIGINAL +# +# Check that the files present in the directory tree COPY are exact +# copies of their counterparts in the directory tree ORIGINAL. COPY +# need not have all the files in ORIGINAL, but COPY may not have files +# absent from ORIGINAL. +# +# Each directory in COPY may have a file named +# 'check-sync-exceptions', which lists files in COPY that need not be +# the same as the corresponding file in ORIGINAL, or exist at all in +# ORIGINAL. (The 'check-sync-exceptions' file itself is always +# treated as exceptional.) Blank lines and '#' comments in the file +# are ignored. + +import sys +import os +from os.path import join +import filecmp +import textwrap +import fnmatch + +if len(sys.argv) != 3: + print >> sys.stderr, 'TEST-UNEXPECTED-FAIL | check-sync-dirs.py | Usage: %s COPY ORIGINAL' % sys.argv[0] + sys.exit(1) + +copy = os.path.abspath(sys.argv[1]) +original = os.path.abspath(sys.argv[2]) + +# Ignore detritus left lying around by editing tools. +ignored_patterns = ['*~', '.#*', '#*#', '*.orig', '*.rej'] + +# Return the contents of FILENAME, a 'check-sync-exceptions' file, as +# a dictionary whose keys are exactly the list of filenames, along +# with the basename of FILENAME itself. If FILENAME does not exist, +# return the empty dictionary. +def read_exceptions(filename): + if (os.path.exists(filename)): + f = file(filename) + exceptions = {} + for line in f: + line = line.strip() + if line != '' and line[0] != '#': + exceptions[line] = None + exceptions[os.path.basename (filename)] = None + f.close() + return exceptions + else: + return {} + +# Return true if FILENAME matches any pattern in the list of filename +# patterns PATTERNS. +def fnmatch_any(filename, patterns): + for pattern in patterns: + if fnmatch.fnmatch(filename, pattern): + return True + return False + +# Check the contents of the directory tree COPY against ORIGINAL. For each +# file that differs, apply REPORT to COPY, ORIGINAL, and the file's +# relative path. COPY and ORIGINAL should be absolute. Ignore files +# that match patterns given in the list IGNORE. +def check(copy, original, ignore): + os.chdir(copy) + for (dirpath, dirnames, filenames) in os.walk('.'): + exceptions = read_exceptions(join(dirpath, 'check-sync-exceptions')) + for dirname in dirnames: + if (dirname in exceptions): + dirnames.remove(dirname) + break + for filename in filenames: + if (filename in exceptions) or fnmatch_any(filename, ignore): + continue + relative_name = join(dirpath, filename) + original_name = join(original, relative_name) + if (os.path.exists(original_name) + and filecmp.cmp(relative_name, original_name, False)): + continue + report(copy, original, relative_name) + +differences_found = False + +# Print an error message for DIFFERING, which was found to differ +# between COPY and ORIGINAL. Set the global variable differences_found. +def report(copy, original, differing): + global differences_found + if not differences_found: + print >> sys.stderr, 'TEST-UNEXPECTED-FAIL | check-sync-dirs.py | build file copies are not in sync\n' \ + 'TEST-INFO | check-sync-dirs.py | file(s) found in: %s\n' \ + 'TEST-INFO | check-sync-dirs.py | differ from their originals in: %s' \ + % (copy, original) + print >> sys.stderr, 'TEST-INFO | check-sync-dirs.py | differing file: %s' % differing + differences_found = True + +check(copy, original, ignored_patterns) + +if differences_found: + msg = '''In general, the files in '%s' should always be exact copies of +originals in '%s'. A change made to one should also be made to the +other. See 'check-sync-dirs.py' for more details.''' \ + % (copy, original) + print >> sys.stderr, textwrap.fill(msg, 75) + sys.exit(1) + +print >> sys.stderr, 'TEST-PASS | check-sync-dirs.py | %s <= %s' % (copy, original) +sys.exit(0) diff --git a/js/src/config/check-sync-exceptions b/js/src/config/check-sync-exceptions new file mode 100644 index 0000000..b61f4a3 --- /dev/null +++ b/js/src/config/check-sync-exceptions @@ -0,0 +1,14 @@ +Makefile.in +Makefile +autoconf.mk.in +autoconf.mk +check-sync-dirs.py +static-checking-config.mk +nsinstall +nsinstall.exe +host_nsinstall.o +host_pathsub.o + +# This is a copy of nspr's config/make-system-wrappers.pl. +make-system-wrappers.pl +system_wrappers_js diff --git a/js/src/config/config.mk b/js/src/config/config.mk new file mode 100644 index 0000000..8aef9e5 --- /dev/null +++ b/js/src/config/config.mk @@ -0,0 +1,853 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Benjamin Smedberg +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# config.mk +# +# Determines the platform and builds the macros needed to load the +# appropriate platform-specific .mk file, then defines all (most?) +# of the generic macros. +# + +# Define an include-at-most-once flag +#ifdef INCLUDED_CONFIG_MK +#$(error Don't include config.mk twice!) +#endif +INCLUDED_CONFIG_MK = 1 + +EXIT_ON_ERROR = set -e; # Shell loops continue past errors without this. + +ifndef topsrcdir +topsrcdir = $(DEPTH) +endif + +ifndef INCLUDED_AUTOCONF_MK +include $(DEPTH)/config/autoconf.mk +endif + +COMMA = , + +# Sanity check some variables +CHECK_VARS := \ + XPI_NAME \ + LIBRARY_NAME \ + MODULE \ + DEPTH \ + SHORT_LIBNAME \ + XPI_PKGNAME \ + INSTALL_EXTENSION_ID \ + SHARED_LIBRARY_NAME \ + STATIC_LIBRARY_NAME \ + $(NULL) + +# checks for internal spaces or trailing spaces in the variable +# named by $x +check-variable = $(if $(filter-out 0 1,$(words $($(x))z)),$(error Spaces are not allowed in $(x))) + +$(foreach x,$(CHECK_VARS),$(check-variable)) + +core_abspath = $(if $(findstring :,$(1)),$(1),$(if $(filter /%,$(1)),$(1),$(CURDIR)/$(1))) + +nullstr := +space :=$(nullstr) # EOL + +core_winabspath = $(firstword $(subst /, ,$(call core_abspath,$(1)))):$(subst $(space),,$(patsubst %,\\%,$(wordlist 2,$(words $(subst /, ,$(call core_abspath,$(1)))), $(strip $(subst /, ,$(call core_abspath,$(1))))))) + +# FINAL_TARGET specifies the location into which we copy end-user-shipped +# build products (typelibs, components, chrome). +# +# It will usually be the well-loved $(DIST)/bin, today, but can also be an +# XPI-contents staging directory for ambitious and right-thinking extensions. +FINAL_TARGET = $(if $(XPI_NAME),$(DIST)/xpi-stage/$(XPI_NAME),$(DIST)/bin) + +ifdef XPI_NAME +DEFINES += -DXPI_NAME=$(XPI_NAME) +endif + +# MAKE_JARS_TARGET is a staging area for make-jars.pl. When packaging in +# the jar format, make-jars leaves behind a directory structure that's not +# needed in $(FINAL_TARGET). For both, flat, and symlink, the directory +# structure contains the chrome, so leave it in $(FINAL_TARGET). +ifeq (jar,$(MOZ_CHROME_FILE_FORMAT)) +MAKE_JARS_TARGET = $(if $(XPI_NAME),$(FINAL_TARGET).stage,$(DIST)/chrome-stage) +else +MAKE_JARS_TARGET = $(FINAL_TARGET) +endif + +# The VERSION_NUMBER is suffixed onto the end of the DLLs we ship. +VERSION_NUMBER = 50 + +ifeq ($(HOST_OS_ARCH),WINNT) +win_srcdir := $(subst $(topsrcdir),$(WIN_TOP_SRC),$(srcdir)) +BUILD_TOOLS = $(WIN_TOP_SRC)/build/unix +else +win_srcdir := $(srcdir) +BUILD_TOOLS = $(topsrcdir)/build/unix +endif + +CONFIG_TOOLS = $(MOZ_BUILD_ROOT)/config +AUTOCONF_TOOLS = $(topsrcdir)/build/autoconf + +ifeq ($(OS_ARCH),QNX) +ifeq ($(OS_TARGET),NTO) +LD := qcc -Vgcc_ntox86 -nostdlib +else +LD := $(CC) +endif +endif +ifeq ($(OS_ARCH),BeOS) +BEOS_ADDON_WORKAROUND = 1 +endif + +# +# Strip off the excessively long version numbers on these platforms, +# but save the version to allow multiple versions of the same base +# platform to be built in the same tree. +# +ifneq (,$(filter FreeBSD HP-UX IRIX Linux NetBSD OpenBSD OSF1 SunOS,$(OS_ARCH))) +OS_RELEASE := $(basename $(OS_RELEASE)) + +# Allow the user to ignore the OS_VERSION, which is usually irrelevant. +ifdef WANT_MOZILLA_CONFIG_OS_VERSION +OS_VERS := $(suffix $(OS_RELEASE)) +OS_VERSION := $(shell echo $(OS_VERS) | sed 's/-.*//') +endif + +endif + +OS_CONFIG := $(OS_ARCH)$(OS_RELEASE) + +FINAL_LINK_LIBS = $(DEPTH)/config/final-link-libs +FINAL_LINK_COMPS = $(DEPTH)/config/final-link-comps +FINAL_LINK_COMP_NAMES = $(DEPTH)/config/final-link-comp-names + +MOZ_UNICHARUTIL_LIBS = $(LIBXUL_DIST)/lib/$(LIB_PREFIX)unicharutil_s.$(LIB_SUFFIX) +MOZ_WIDGET_SUPPORT_LIBS = $(DIST)/lib/$(LIB_PREFIX)widgetsupport_s.$(LIB_SUFFIX) + +ifdef MOZ_MEMORY +ifneq (,$(filter-out WINNT WINCE,$(OS_ARCH))) +JEMALLOC_LIBS = $(MKSHLIB_FORCE_ALL) $(call EXPAND_MOZLIBNAME,jemalloc) $(MKSHLIB_UNFORCE_ALL) +# If we are linking jemalloc into a program, we want the jemalloc symbols +# to be exported +ifneq (,$(SIMPLE_PROGRAMS)$(PROGRAM)) +JEMALLOC_LIBS += $(MOZ_JEMALLOC_STANDALONE_GLUE_LDOPTS) +endif +endif +endif + +CC := $(CC_WRAPPER) $(CC) +CXX := $(CXX_WRAPPER) $(CXX) + +# determine debug-related options +_DEBUG_CFLAGS := +_DEBUG_LDFLAGS := + +ifdef MOZ_DEBUG + _DEBUG_CFLAGS += $(MOZ_DEBUG_ENABLE_DEFS) $(MOZ_DEBUG_FLAGS) + _DEBUG_LDFLAGS += $(MOZ_DEBUG_LDFLAGS) + XULPPFLAGS += $(MOZ_DEBUG_ENABLE_DEFS) +else + _DEBUG_CFLAGS += $(MOZ_DEBUG_DISABLE_DEFS) + XULPPFLAGS += $(MOZ_DEBUG_DISABLE_DEFS) + ifdef MOZ_DEBUG_SYMBOLS + _DEBUG_CFLAGS += $(MOZ_DEBUG_FLAGS) + _DEBUG_LDFLAGS += $(MOZ_DEBUG_LDFLAGS) + endif +endif + +MOZALLOC_LIB = $(call EXPAND_LIBNAME_PATH,mozalloc,$(DIST)/lib) + +OS_CFLAGS += $(_DEBUG_CFLAGS) +OS_CXXFLAGS += $(_DEBUG_CFLAGS) +OS_LDFLAGS += $(_DEBUG_LDFLAGS) + +# XXX: What does this? Bug 482434 filed for better explanation. +ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_) +ifdef MOZ_DEBUG +ifneq (,$(MOZ_BROWSE_INFO)$(MOZ_BSCFILE)) +OS_CFLAGS += -FR +OS_CXXFLAGS += -FR +endif +else # ! MOZ_DEBUG + +# We don't build a static CRT when building a custom CRT, +# it appears to be broken. So don't link to jemalloc if +# the Makefile wants static CRT linking. +ifeq ($(MOZ_MEMORY)_$(USE_STATIC_LIBS),1_) +# Disable default CRT libs and add the right lib path for the linker +OS_LDFLAGS += $(MOZ_MEMORY_LDFLAGS) +endif + +# MOZ_DEBUG_SYMBOLS generates debug symbols in separate PDB files. +# Used for generating an optimized build with debugging symbols. +# Used in the Windows nightlies to generate symbols for crash reporting. +ifdef MOZ_DEBUG_SYMBOLS +OS_CXXFLAGS += -Zi -UDEBUG -DNDEBUG +OS_CFLAGS += -Zi -UDEBUG -DNDEBUG +ifdef HAVE_64BIT_OS +OS_LDFLAGS += -DEBUG -OPT:REF,ICF +else +OS_LDFLAGS += -DEBUG -OPT:REF +endif +endif + +ifdef MOZ_QUANTIFY +# -FIXED:NO is needed for Quantify to work, but it increases the size +# of executables, so only use it if building for Quantify. +WIN32_EXE_LDFLAGS += -FIXED:NO + +# We need -OPT:NOICF to prevent identical methods from being merged together. +# Otherwise, Quantify doesn't know which method was actually called when it's +# showing you the profile. +OS_LDFLAGS += -OPT:NOICF +endif + +# +# Handle trace-malloc in optimized builds. +# No opt to give sane callstacks. +# +ifdef NS_TRACE_MALLOC +MOZ_OPTIMIZE_FLAGS=-Zi -Od -UDEBUG -DNDEBUG +ifdef HAVE_64BIT_OS +OS_LDFLAGS = -DEBUG -PDB:NONE -OPT:REF,ICF +else +OS_LDFLAGS = -DEBUG -PDB:NONE -OPT:REF +endif +endif # NS_TRACE_MALLOC + +endif # MOZ_DEBUG +endif # WINNT && !GNU_CC + +# +# Build using PIC by default +# Do not use PIC if not building a shared lib (see exceptions below) +# + +ifndef BUILD_STATIC_LIBS +_ENABLE_PIC=1 +endif +ifneq (,$(FORCE_SHARED_LIB)$(FORCE_USE_PIC)) +_ENABLE_PIC=1 +endif + +# In Firefox, all components are linked into either libxul or the static +# meta-component, and should be compiled with PIC. +ifdef MOZ_META_COMPONENT +_ENABLE_PIC=1 +endif + +# If module is going to be merged into the nsStaticModule, +# make sure that the entry points are translated and +# the module is built static. + +ifdef IS_COMPONENT +ifdef EXPORT_LIBRARY +ifneq (,$(BUILD_STATIC_LIBS)) +ifdef MODULE_NAME +DEFINES += -DXPCOM_TRANSLATE_NSGM_ENTRY_POINT=1 +FORCE_STATIC_LIB=1 +endif +endif +endif +endif + +# Determine if module being compiled is destined +# to be merged into libxul + +ifdef MOZ_ENABLE_LIBXUL +ifdef LIBXUL_LIBRARY +ifdef IS_COMPONENT +ifdef MODULE_NAME +DEFINES += -DXPCOM_TRANSLATE_NSGM_ENTRY_POINT=1 +else +$(error Component makefile does not specify MODULE_NAME.) +endif +endif +FORCE_STATIC_LIB=1 +_ENABLE_PIC=1 +SHORT_LIBNAME= +endif +endif + +# If we are building this component into an extension/xulapp, it cannot be +# statically linked. In the future we may want to add a xulapp meta-component +# build option. + +ifdef XPI_NAME +_ENABLE_PIC=1 +ifdef IS_COMPONENT +EXPORT_LIBRARY= +FORCE_STATIC_LIB= +FORCE_SHARED_LIB=1 +endif +endif + +# +# Disable PIC if necessary +# + +ifndef _ENABLE_PIC +DSO_CFLAGS= +ifeq ($(OS_ARCH)_$(HAVE_GCC3_ABI),Darwin_1) +DSO_PIC_CFLAGS=-mdynamic-no-pic +else +DSO_PIC_CFLAGS= +endif +endif + +ifndef SHARED_LIBRARY_NAME +ifdef LIBRARY_NAME +SHARED_LIBRARY_NAME=$(LIBRARY_NAME) +endif +endif + +ifndef STATIC_LIBRARY_NAME +ifdef LIBRARY_NAME +STATIC_LIBRARY_NAME=$(LIBRARY_NAME) +endif +endif + +ifeq (WINNT,$(OS_ARCH)) +MOZ_FAKELIBS = 1 +endif + +# This comes from configure +ifdef MOZ_PROFILE_GUIDED_OPTIMIZE_DISABLE +NO_PROFILE_GUIDED_OPTIMIZE = 1 +endif + +# No sense in profiling tools +ifdef INTERNAL_TOOLS +NO_PROFILE_GUIDED_OPTIMIZE = 1 +endif + +# Don't build SIMPLE_PROGRAMS with PGO, since they don't need it anyway, +# and we don't have the same build logic to re-link them in the second pass. +ifdef SIMPLE_PROGRAMS +NO_PROFILE_GUIDED_OPTIMIZE = 1 +endif + +# Enable profile-based feedback +ifndef NO_PROFILE_GUIDED_OPTIMIZE +ifdef MOZ_PROFILE_GENERATE +OS_CFLAGS += $(PROFILE_GEN_CFLAGS) +OS_CXXFLAGS += $(PROFILE_GEN_CFLAGS) +OS_LDFLAGS += $(PROFILE_GEN_LDFLAGS) +ifeq (WINNT,$(OS_ARCH)) +AR_FLAGS += -LTCG +endif +endif # MOZ_PROFILE_GENERATE + +ifdef MOZ_PROFILE_USE +OS_CFLAGS += $(PROFILE_USE_CFLAGS) +OS_CXXFLAGS += $(PROFILE_USE_CFLAGS) +OS_LDFLAGS += $(PROFILE_USE_LDFLAGS) +ifeq (WINNT,$(OS_ARCH)) +AR_FLAGS += -LTCG +endif +endif # MOZ_PROFILE_USE +endif # NO_PROFILE_GUIDED_OPTIMIZE + + +# Does the makefile specifies the internal XPCOM API linkage? +ifneq (,$(MOZILLA_INTERNAL_API)$(LIBXUL_LIBRARY)) +DEFINES += -DMOZILLA_INTERNAL_API +endif + +# Force XPCOM/widget/gfx methods to be _declspec(dllexport) when we're +# building libxul libraries +ifdef MOZ_ENABLE_LIBXUL +ifdef LIBXUL_LIBRARY +DEFINES += \ + -D_IMPL_NS_COM \ + -DEXPORT_XPT_API \ + -DEXPORT_XPTC_API \ + -D_IMPL_NS_GFX \ + -D_IMPL_NS_WIDGET \ + -DIMPL_XREAPI \ + -DIMPL_NS_NET \ + -DIMPL_THEBES \ + $(NULL) + +ifndef JS_SHARED_LIBRARY +DEFINES += -DSTATIC_EXPORTABLE_JS_API +endif +endif +endif + +# Force _all_ exported methods to be |_declspec(dllexport)| when we're +# building them into the executable. + +ifeq (,$(filter-out WINNT WINCE OS2, $(OS_ARCH))) +ifdef BUILD_STATIC_LIBS +DEFINES += \ + -D_IMPL_NS_GFX \ + -D_IMPL_NS_MSG_BASE \ + -D_IMPL_NS_WIDGET \ + $(NULL) +endif +endif + +# Flags passed to make-jars.pl + +MAKE_JARS_FLAGS = \ + -t $(topsrcdir) \ + -f $(MOZ_CHROME_FILE_FORMAT) \ + $(NULL) + +ifdef USE_EXTENSION_MANIFEST +MAKE_JARS_FLAGS += -e +endif + +ifdef BOTH_MANIFESTS +MAKE_JARS_FLAGS += --both-manifests +endif + +TAR_CREATE_FLAGS = -cvhf + +ifeq ($(OS_ARCH),BSD_OS) +TAR_CREATE_FLAGS = -cvLf +endif + +ifeq ($(OS_ARCH),OS2) +TAR_CREATE_FLAGS = -cvf +endif + +# +# Personal makefile customizations go in these optional make include files. +# +MY_CONFIG := $(DEPTH)/config/myconfig.mk +MY_RULES := $(DEPTH)/config/myrules.mk + +# +# Default command macros; can be overridden in .mk. +# +CCC = $(CXX) +NFSPWD = $(CONFIG_TOOLS)/nfspwd +PURIFY = purify $(PURIFYOPTIONS) +QUANTIFY = quantify $(QUANTIFYOPTIONS) +ifdef CROSS_COMPILE +XPIDL_COMPILE = $(CYGWIN_WRAPPER) $(LIBXUL_DIST)/host/bin/host_xpidl$(HOST_BIN_SUFFIX) +XPIDL_LINK = $(CYGWIN_WRAPPER) $(LIBXUL_DIST)/host/bin/host_xpt_link$(HOST_BIN_SUFFIX) +else +XPIDL_COMPILE = $(CYGWIN_WRAPPER) $(LIBXUL_DIST)/bin/xpidl$(BIN_SUFFIX) +XPIDL_LINK = $(CYGWIN_WRAPPER) $(LIBXUL_DIST)/bin/xpt_link$(BIN_SUFFIX) +endif + +# Java macros +JAVA_GEN_DIR = _javagen +JAVA_DIST_DIR = $(DEPTH)/$(JAVA_GEN_DIR) +JAVA_IFACES_PKG_NAME = org/mozilla/interfaces + +INCLUDES = \ + $(LOCAL_INCLUDES) \ + -I$(srcdir) \ + -I. \ + -I$(DIST)/include -I$(DIST)/include/nsprpub \ + $(if $(LIBXUL_SDK),-I$(LIBXUL_SDK)/include -I$(LIBXUL_SDK)/include/nsprpub) \ + $(OS_INCLUDES) \ + $(NULL) + +include $(topsrcdir)/config/static-checking-config.mk + +CFLAGS = $(OS_CFLAGS) +CXXFLAGS = $(OS_CXXFLAGS) +LDFLAGS = $(OS_LDFLAGS) $(MOZ_FIX_LINK_PATHS) + +# Allow each module to override the *default* optimization settings +# by setting MODULE_OPTIMIZE_FLAGS if the developer has not given +# arguments to --enable-optimize +ifdef MOZ_OPTIMIZE +ifeq (1,$(MOZ_OPTIMIZE)) +ifdef MODULE_OPTIMIZE_FLAGS +CFLAGS += $(MODULE_OPTIMIZE_FLAGS) +CXXFLAGS += $(MODULE_OPTIMIZE_FLAGS) +else +CFLAGS += $(MOZ_OPTIMIZE_FLAGS) +CXXFLAGS += $(MOZ_OPTIMIZE_FLAGS) +endif # MODULE_OPTIMIZE_FLAGS +else +CFLAGS += $(MOZ_OPTIMIZE_FLAGS) +CXXFLAGS += $(MOZ_OPTIMIZE_FLAGS) +endif # MOZ_OPTIMIZE == 1 +LDFLAGS += $(MOZ_OPTIMIZE_LDFLAGS) +endif # MOZ_OPTIMIZE + +ifdef CROSS_COMPILE +HOST_CFLAGS += $(HOST_OPTIMIZE_FLAGS) +else +ifdef MOZ_OPTIMIZE +ifeq (1,$(MOZ_OPTIMIZE)) +ifdef MODULE_OPTIMIZE_FLAGS +HOST_CFLAGS += $(MODULE_OPTIMIZE_FLAGS) +else +HOST_CFLAGS += $(MOZ_OPTIMIZE_FLAGS) +endif # MODULE_OPTIMIZE_FLAGS +else +HOST_CFLAGS += $(MOZ_OPTIMIZE_FLAGS) +endif # MOZ_OPTIMIZE == 1 +endif # MOZ_OPTIMIZE +endif # CROSS_COMPILE + +# Check for FAIL_ON_WARNINGS & FAIL_ON_WARNINGS_DEBUG (Shorthand for Makefiles +# to request that we use the 'warnings as errors' compile flags) + +# NOTE: First, we clear FAIL_ON_WARNINGS[_DEBUG] if we're doing a Windows PGO +# build, since WARNINGS_AS_ERRORS has been suspected of causing isuses in that +# situation. (See bug 437002.) +ifeq (WINNT_1,$(OS_ARCH)_$(MOZ_PROFILE_GENERATE)$(MOZ_PROFILE_USE)) +FAIL_ON_WARNINGS_DEBUG= +FAIL_ON_WARNINGS= +endif # WINNT && (MOS_PROFILE_GENERATE ^ MOZ_PROFILE_USE) + +# Also clear FAIL_ON_WARNINGS[_DEBUG] for Android builds, since +# they have some platform-specific warnings we haven't fixed yet. +ifeq ($(OS_TARGET),Android) +FAIL_ON_WARNINGS_DEBUG= +FAIL_ON_WARNINGS= +endif # Android + +# Now, check for debug version of flag; it turns on normal flag in debug builds. +ifdef FAIL_ON_WARNINGS_DEBUG +ifdef MOZ_DEBUG +FAIL_ON_WARNINGS = 1 +endif # MOZ_DEBUG +endif # FAIL_ON_WARNINGS_DEBUG + +# Check for normal version of flag, and add WARNINGS_AS_ERRORS if it's set to 1. +ifdef FAIL_ON_WARNINGS +CXXFLAGS += $(WARNINGS_AS_ERRORS) +CFLAGS += $(WARNINGS_AS_ERRORS) +endif # FAIL_ON_WARNINGS + +ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_) +#// Currently, unless USE_STATIC_LIBS is defined, the multithreaded +#// DLL version of the RTL is used... +#// +#//------------------------------------------------------------------------ +ifdef USE_STATIC_LIBS +RTL_FLAGS=-MT # Statically linked multithreaded RTL +ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC)) +ifndef MOZ_NO_DEBUG_RTL +RTL_FLAGS=-MTd # Statically linked multithreaded MSVC4.0 debug RTL +endif +endif # MOZ_DEBUG || NS_TRACE_MALLOC + +else # !USE_STATIC_LIBS + +RTL_FLAGS=-MD # Dynamically linked, multithreaded RTL +ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC)) +ifndef MOZ_NO_DEBUG_RTL +RTL_FLAGS=-MDd # Dynamically linked, multithreaded MSVC4.0 debug RTL +endif +endif # MOZ_DEBUG || NS_TRACE_MALLOC +endif # USE_STATIC_LIBS +endif # WINNT && !GNU_CC + +ifeq ($(OS_ARCH),Darwin) +# Darwin doesn't cross-compile, so just set both types of flags here. +HOST_CMFLAGS += -fobjc-exceptions +HOST_CMMFLAGS += -fobjc-exceptions +OS_COMPILE_CMFLAGS += -fobjc-exceptions +OS_COMPILE_CMMFLAGS += -fobjc-exceptions +endif + +COMPILE_CFLAGS = $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CFLAGS) +COMPILE_CXXFLAGS = $(STL_FLAGS) $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(CXXFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CXXFLAGS) +COMPILE_CMFLAGS = $(OS_COMPILE_CMFLAGS) +COMPILE_CMMFLAGS = $(OS_COMPILE_CMMFLAGS) + +ifndef CROSS_COMPILE +HOST_CFLAGS += $(RTL_FLAGS) +endif + +# +# Name of the binary code directories +# +# Override defaults + +# We need to know where to find the libraries we +# put on the link line for binaries, and should +# we link statically or dynamic? Assuming dynamic for now. + +ifneq (WINNT_,$(OS_ARCH)_$(GNU_CC)) +ifneq (,$(filter-out WINCE,$(OS_ARCH))) +LIBS_DIR = -L$(DIST)/bin -L$(DIST)/lib +ifdef LIBXUL_SDK +LIBS_DIR += -L$(LIBXUL_SDK)/bin -L$(LIBXUL_SDK)/lib +endif +endif +endif + +# Default location of include files +IDL_DIR = $(DIST)/idl + +XPIDL_FLAGS = -I$(srcdir) -I$(IDL_DIR) +ifdef LIBXUL_SDK +XPIDL_FLAGS += -I$(LIBXUL_SDK)/idl +endif + +SDK_LIB_DIR = $(DIST)/sdk/lib +SDK_BIN_DIR = $(DIST)/sdk/bin + +DEPENDENCIES = .md + +MOZ_COMPONENT_LIBS=$(XPCOM_LIBS) $(MOZ_COMPONENT_NSPR_LIBS) + +ifeq (xpconnect, $(findstring xpconnect, $(BUILD_MODULES))) +DEFINES += -DXPCONNECT_STANDALONE +endif + +ifeq ($(OS_ARCH),OS2) +ELF_DYNSTR_GC = echo +else +ELF_DYNSTR_GC = : +endif + +ifeq ($(MOZ_WIDGET_TOOLKIT),qt) +OS_LIBS += $(MOZ_QT_LIBS) +endif + +ifndef CROSS_COMPILE +ifdef USE_ELF_DYNSTR_GC +ifdef MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS +ELF_DYNSTR_GC = $(DEPTH)/config/elf-dynstr-gc +endif +endif +endif + +ifeq ($(OS_ARCH),Darwin) +ifdef NEXT_ROOT +export NEXT_ROOT +PBBUILD = NEXT_ROOT= $(PBBUILD_BIN) +else # NEXT_ROOT +PBBUILD = $(PBBUILD_BIN) +endif # NEXT_ROOT +PBBUILD_SETTINGS = GCC_VERSION="$(GCC_VERSION)" SYMROOT=build ARCHS="$(OS_TEST)" +ifdef MACOS_SDK_DIR +PBBUILD_SETTINGS += SDKROOT="$(MACOS_SDK_DIR)" +endif # MACOS_SDK_DIR +ifdef MACOSX_DEPLOYMENT_TARGET +export MACOSX_DEPLOYMENT_TARGET +PBBUILD_SETTINGS += MACOSX_DEPLOYMENT_TARGET="$(MACOSX_DEPLOYMENT_TARGET)" +endif # MACOSX_DEPLOYMENT_TARGET +ifdef MOZ_OPTIMIZE +ifeq (2,$(MOZ_OPTIMIZE)) +# Only override project defaults if the config specified explicit settings +PBBUILD_SETTINGS += GCC_MODEL_TUNING= OPTIMIZATION_CFLAGS="$(MOZ_OPTIMIZE_FLAGS)" +endif # MOZ_OPTIMIZE=2 +endif # MOZ_OPTIMIZE +ifeq (1,$(HAS_XCODE_2_1)) +# Xcode 2.1 puts its build products in a directory corresponding to the +# selected build style/configuration. +XCODE_PRODUCT_DIR = build/$(BUILDSTYLE) +else +XCODE_PRODUCT_DIR = build +endif # HAS_XCODE_2_1=1 +endif # OS_ARCH=Darwin + + +ifdef MOZ_NATIVE_MAKEDEPEND +MKDEPEND_DIR = +MKDEPEND = $(CYGWIN_WRAPPER) $(MOZ_NATIVE_MAKEDEPEND) +else +MKDEPEND_DIR = $(CONFIG_TOOLS)/mkdepend +MKDEPEND = $(CYGWIN_WRAPPER) $(MKDEPEND_DIR)/mkdepend$(BIN_SUFFIX) +endif + +# Set link flags according to whether we want a console. +ifdef MOZ_WINCONSOLE +ifeq ($(MOZ_WINCONSOLE),1) +ifeq ($(OS_ARCH),OS2) +BIN_FLAGS += -Zlinker -PM:VIO +endif +ifeq ($(OS_ARCH),WINNT) +ifdef GNU_CC +WIN32_EXE_LDFLAGS += -mconsole +else +WIN32_EXE_LDFLAGS += -SUBSYSTEM:CONSOLE +endif +endif +else # MOZ_WINCONSOLE +ifeq ($(OS_ARCH),OS2) +BIN_FLAGS += -Zlinker -PM:PM +endif +ifeq ($(OS_ARCH),WINNT) +ifdef GNU_CC +WIN32_EXE_LDFLAGS += -mwindows +else +WIN32_EXE_LDFLAGS += -SUBSYSTEM:WINDOWS +endif +endif +endif +endif + +# If we're building a component on MSVC, we don't want to generate an +# import lib, because that import lib will collide with the name of a +# static version of the same library. +ifeq ($(GNU_LD)$(OS_ARCH),WINNT) +ifdef IS_COMPONENT +LDFLAGS += -IMPLIB:fake.lib +DELETE_AFTER_LINK = fake.lib fake.exp +endif +endif + +# +# Include any personal overrides the user might think are needed. +# +-include $(topsrcdir)/$(MOZ_BUILD_APP)/app-config.mk +-include $(MY_CONFIG) + +###################################################################### +# Now test variables that might have been set or overridden by $(MY_CONFIG). + +DEFINES += -DOSTYPE=\"$(OS_CONFIG)\" +DEFINES += -DOSARCH=$(OS_ARCH) + +###################################################################### + +GARBAGE += $(DEPENDENCIES) $(MKDEPENDENCIES) $(MKDEPENDENCIES).bak core $(wildcard core.[0-9]*) $(wildcard *.err) $(wildcard *.pure) $(wildcard *_pure_*.o) Templates.DB $(FAKE_LIBRARY) + +ifeq ($(OS_ARCH),Darwin) +ifndef NSDISTMODE +NSDISTMODE=absolute_symlink +endif +PWD := $(CURDIR) +endif + +ifdef NSINSTALL_BIN +NSINSTALL = $(CYGWIN_WRAPPER) $(NSINSTALL_BIN) +else +ifeq (OS2,$(CROSS_COMPILE)$(OS_ARCH)) +NSINSTALL = $(MOZ_TOOLS_DIR)/nsinstall +else +NSINSTALL = $(CONFIG_TOOLS)/nsinstall$(HOST_BIN_SUFFIX) +endif # OS2 +endif # NSINSTALL_BIN + + +ifeq (,$(CROSS_COMPILE)$(filter-out WINNT OS2, $(OS_ARCH))) +INSTALL = $(NSINSTALL) +else +ifeq ($(NSDISTMODE),copy) +# copy files, but preserve source mtime +INSTALL = $(NSINSTALL) -t +else +ifeq ($(NSDISTMODE),absolute_symlink) +# install using absolute symbolic links +ifeq ($(OS_ARCH),Darwin) +INSTALL = $(NSINSTALL) -L $(PWD) +else +INSTALL = $(NSINSTALL) -L `$(NFSPWD)` +endif # Darwin +else +# install using relative symbolic links +INSTALL = $(NSINSTALL) -R +endif # absolute_symlink +endif # copy +endif # WINNT/OS2 + +# Use nsinstall in copy mode to install files on the system +SYSINSTALL = $(NSINSTALL) -t + +ifeq ($(OS_ARCH),WINNT) +ifneq (,$(CYGDRIVE_MOUNT)) +export CYGDRIVE_MOUNT +endif +endif + +# +# Localization build automation +# + +# Because you might wish to "make locales AB_CD=ab-CD", we don't hardcode +# MOZ_UI_LOCALE directly, but use an intermediate variable that can be +# overridden by the command line. (Besides, AB_CD is prettier). +AB_CD = $(MOZ_UI_LOCALE) + +ifndef L10NBASEDIR +L10NBASEDIR = $(error L10NBASEDIR not defined by configure) +endif + +EXPAND_LOCALE_SRCDIR = $(if $(filter en-US,$(AB_CD)),$(topsrcdir)/$(1)/en-US,$(L10NBASEDIR)/$(AB_CD)/$(subst /locales,,$(1))) + +ifdef relativesrcdir +LOCALE_SRCDIR = $(call EXPAND_LOCALE_SRCDIR,$(relativesrcdir)) +endif + +ifdef LOCALE_SRCDIR +# if LOCALE_MERGEDIR is set, use mergedir first, then the localization, +# and finally en-US +ifdef LOCALE_MERGEDIR +MAKE_JARS_FLAGS += -c $(LOCALE_MERGEDIR)/$(subst /locales,,$(relativesrcdir)) +endif +MAKE_JARS_FLAGS += -c $(LOCALE_SRCDIR) +ifdef LOCALE_MERGEDIR +MAKE_JARS_FLAGS += -c $(topsrcdir)/$(relativesrcdir)/en-US +endif +endif + +ifdef WINCE +RUN_TEST_PROGRAM = $(PYTHON) $(topsrcdir)/build/mobile/devicemanager-run-test.py +else +ifeq (OS2,$(OS_ARCH)) +RUN_TEST_PROGRAM = $(topsrcdir)/build/os2/test_os2.cmd "$(DIST)" +else +ifneq (WINNT,$(OS_ARCH)) +RUN_TEST_PROGRAM = $(DIST)/bin/run-mozilla.sh +endif # ! WINNT +endif # ! OS2 +endif # ! WINCE + +# +# Java macros +# + +# Make sure any compiled classes work with at least JVM 1.4 +JAVAC_FLAGS += -source 1.4 + +ifdef MOZ_DEBUG +JAVAC_FLAGS += -g +endif + +ifdef TIERS +DIRS += $(foreach tier,$(TIERS),$(tier_$(tier)_dirs)) +STATIC_DIRS += $(foreach tier,$(TIERS),$(tier_$(tier)_staticdirs)) +endif + +OPTIMIZE_JARS_CMD = $(PYTHON) $(call core_abspath,$(topsrcdir)/config/optimizejars.py) diff --git a/js/src/config/fastcwd.pl b/js/src/config/fastcwd.pl new file mode 100644 index 0000000..c327ccf --- /dev/null +++ b/js/src/config/fastcwd.pl @@ -0,0 +1,66 @@ +#!perl5 +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +sub fastcwd { + local($odev, $oino, $cdev, $cino, $tdev, $tino); + local(@path, $path); + local(*DIR); + + ($cdev, $cino) = stat('.'); + for (;;) { + ($odev, $oino) = ($cdev, $cino); + chdir('..'); + ($cdev, $cino) = stat('.'); + last if $odev == $cdev && $oino == $cino; + opendir(DIR, '.'); + for (;;) { + $_ = readdir(DIR); + next if $_ eq '.'; + next if $_ eq '..'; + + last unless $_; + ($tdev, $tino) = lstat($_); + last unless $tdev != $odev || $tino != $oino; + } + closedir(DIR); + unshift(@path, $_); + } + chdir($path = '/' . join('/', @path)); + $path; +} +1; diff --git a/js/src/config/find_vanilla_new_calls b/js/src/config/find_vanilla_new_calls new file mode 100755 index 0000000..bcf7c14 --- /dev/null +++ b/js/src/config/find_vanilla_new_calls @@ -0,0 +1,80 @@ +# /bin/bash + +#---------------------------------------------------------------------------- +# We must avoid using the vanilla new/new[] operators (and consequently, the +# vanilla delete/delete[] operators) in SpiderMonkey, see bug 624878 for why. +# +# This script: +# - Detects if any of the vanilla new/new[] operators are used in a file. +# Its exit code is 1 if it found some, and 0 if it didn't. +# - Doesn't detect delete/delete[] because it appears they can be present +# somehow due to virtual destructors, but this is ok because vanilla +# delete/delete[] calls don't make sense without corresponding new/new[] +# calls, and any explicit calls will be caught by Valgrind's mismatched +# alloc/free checking. +# - Doesn't detect the 'nothrow' variants, which are ok but probably still +# best avoided. +# - Is designed to only run on Linux (though it may also work on Mac); one +# platform will be enough to catch any violations. +# +# If this script fails: +# - You need to find the uses of vanilla new/delete and replace them with +# js_new()/js_delete(). +# - Run this script on each of the .o files, that should narrow it down. +# - After that, one way to find them is to run 'objdump -r -C' on the +# relevant .o files. For example, you might search for 'operator new' and +# find a record like this: +# +# RELOCATION RECORDS FOR [.text._ZN3JSC14ExecutablePool6createEj]: +# OFFSET TYPE VALUE +# 00000009 R_386_PC32 __i686.get_pc_thunk.bx +# 0000000f R_386_GOTPC _GLOBAL_OFFSET_TABLE_ +# 0000001b R_386_PLT32 operator new(unsigned int) +# 0000002e R_386_PC32 JSC::ExecutablePool::ExecutablePool(unsigned int) +# 0000004a R_386_PC32 JSC::ExecutablePool::~ExecutablePool() +# 00000052 R_386_PLT32 operator delete(void*) +# +# This says that vanilla 'new' and 'delete' are both used in +# JSC::ExecutablePool::create(unsigned int). This doesn't always work, +# though. (Nb: use 'c++filt' to demangle names like +# _ZN3JSC14ExecutablePool6createEj.) +# +# If that doesn't work, use grep. +#---------------------------------------------------------------------------- + +if [ -z $1 ] ; then + echo "usage: find_vanilla_new_calls " + exit 1 +fi + +file=$1 + +if [ ! -f $file ] ; then + echo "TEST-UNEXPECTED-FAIL | find_vanilla_new_calls | file '$file' not found" + exit 1 +fi + +tmpfile1=`mktemp` +tmpfile2=`mktemp` +nm -C $file > $tmpfile1 + +# Need to double-escape '[' and ']' to stop grep from interpreting them +# specially. +grep 'operator new(unsigned int)' $tmpfile1 >> $tmpfile2 +grep 'operator new(unsigned long)' $tmpfile1 >> $tmpfile2 +grep 'operator new\\[\\](unsigned int)' $tmpfile1 >> $tmpfile2 +grep 'operator new\\[\\](unsigned long)' $tmpfile1 >> $tmpfile2 +rm -f $tmpfile1 + +if [ -s $tmpfile2 ] ; then + echo "TEST-UNEXPECTED-FAIL | find_vanilla_new_calls | found calls are listed below" + cat $tmpfile2 + echo + rm -f $tmpfile2 + exit 1 +fi + +echo "TEST-PASS | find_vanilla_new_calls | ok" +echo + +exit 0 diff --git a/js/src/config/gcc_hidden.h b/js/src/config/gcc_hidden.h new file mode 100644 index 0000000..58140c1 --- /dev/null +++ b/js/src/config/gcc_hidden.h @@ -0,0 +1,2 @@ +/* Begin all files as hidden visibility */ +#pragma GCC visibility push(hidden) diff --git a/js/src/config/make-system-wrappers.pl b/js/src/config/make-system-wrappers.pl new file mode 100644 index 0000000..31c9af4 --- /dev/null +++ b/js/src/config/make-system-wrappers.pl @@ -0,0 +1,59 @@ +#!/usr/bin/perl +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# IBM Corporation. +# Portions created by the Initial Developer are Copyright (C) 2004 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Brian Ryner +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +$output_dir = shift; + +while () { + chomp; + if (-e "$output_dir/$_") { + next; + } + + if (/(.*)\/[^\/*]/) { + mkdir "$output_dir/$1"; + } + + open OUT, ">$output_dir/$_"; + print OUT "#pragma GCC system_header\n"; # suppress include_next warning + print OUT "#pragma GCC visibility push(default)\n"; + print OUT "#include_next \<$_\>\n"; + print OUT "#pragma GCC visibility pop\n"; + close OUT; +} + diff --git a/js/src/config/milestone.pl b/js/src/config/milestone.pl new file mode 100644 index 0000000..e3cee2a --- /dev/null +++ b/js/src/config/milestone.pl @@ -0,0 +1,112 @@ +#!/usr/bin/perl -w +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Win32 Version System. +# +# The Initial Developer of the Original Code is Netscape Communications Corporation +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +use Getopt::Long; + +use strict; +use vars qw( + $OBJDIR + $SRCDIR + $TOPSRCDIR + $SCRIPTDIR + @TEMPLATE_FILE + $MILESTONE_FILE + $MILESTONE + $MILESTONE_NUM + @MILESTONE_PARTS + $MINI_VERSION + $MICRO_VERSION + $opt_debug + $opt_template + $opt_help + ); + +$SCRIPTDIR = $0; +$SCRIPTDIR =~ s/[^\/]*$//; +push(@INC,$SCRIPTDIR); + +require "Moz/Milestone.pm"; + +&GetOptions('topsrcdir=s' => \$TOPSRCDIR, 'srcdir=s' => \$SRCDIR, 'objdir=s' => \$OBJDIR, 'debug', 'help', 'template'); + +if (defined($opt_help)) { + &usage(); + exit; +} + +if (defined($opt_template)) { + @TEMPLATE_FILE = @ARGV; + if ($opt_debug) { + print("TEMPLATE_FILE = --@TEMPLATE_FILE--\n"); + } +} + +if (!defined($SRCDIR)) { $SRCDIR = '.'; } +if (!defined($OBJDIR)) { $OBJDIR = '.'; } + +$MILESTONE_FILE = "$TOPSRCDIR/config/milestone.txt"; +@MILESTONE_PARTS = (0, 0, 0, 0); + +# +# Grab milestone (top line of $MILESTONE_FILE that starts with a digit) +# +my $milestone = Moz::Milestone::getOfficialMilestone($MILESTONE_FILE); + +if (defined(@TEMPLATE_FILE)) { + my $TFILE; + + foreach $TFILE (@TEMPLATE_FILE) { + my $BUILT_FILE = "$OBJDIR/$TFILE"; + $TFILE = "$SRCDIR/$TFILE.tmpl"; + + if (-e $TFILE) { + + Moz::Milestone::build_file($TFILE,$BUILT_FILE); + + } else { + warn("$0: No such file $TFILE!\n"); + } + } +} else { + print "$milestone\n"; +} + +sub usage() { + print <s_value = NULL; + } + return (sp); +} + +pperror(tag, x0,x1,x2,x3,x4) + int tag,x0,x1,x2,x3,x4; +{ + warning("\"%s\", line %d: ", currentinc->i_file, currentfile->f_line); + warning(x0,x1,x2,x3,x4); +} + + +yyerror(s) + register char *s; +{ + fatalerr("Fatal error: %s\n", s); +} +#else /* not CPP */ + +#include "ifparser.h" +struct _parse_data { + struct filepointer *filep; + struct inclist *inc; + char *filename; + const char *line; +}; + +static const char * +my_if_errors (IfParser *ip, const char *cp, const char *expecting) +{ + struct _parse_data *pd = (struct _parse_data *) ip->data; + int lineno = pd->filep->f_line; + char *filename = pd->filename; + char prefix[300]; + int prefixlen; + int i; + + sprintf (prefix, "\"%s\":%d", filename, lineno); + prefixlen = strlen(prefix); + fprintf (stderr, "%s: %s", prefix, pd->line); + i = cp - pd->line; + if (i > 0 && pd->line[i-1] != '\n') { + putc ('\n', stderr); + } + for (i += prefixlen + 3; i > 0; i--) { + putc (' ', stderr); + } + fprintf (stderr, "^--- expecting %s\n", expecting); + return NULL; +} + + +#define MAXNAMELEN 256 + +static struct symtab ** +lookup_variable (IfParser *ip, const char *var, int len) +{ + char tmpbuf[MAXNAMELEN + 1]; + struct _parse_data *pd = (struct _parse_data *) ip->data; + + if (len > MAXNAMELEN) + return 0; + + strncpy (tmpbuf, var, len); + tmpbuf[len] = '\0'; + return isdefined (tmpbuf, pd->inc, NULL); +} + + +static int +my_eval_defined (IfParser *ip, const char *var, int len) +{ + if (lookup_variable (ip, var, len)) + return 1; + else + return 0; +} + +#define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_') + +static long +my_eval_variable (IfParser *ip, const char *var, int len) +{ + long val; + struct symtab **s; + + s = lookup_variable (ip, var, len); + if (!s) + return 0; + do { + var = (*s)->s_value; + if (!isvarfirstletter(*var) || !strcmp((*s)->s_name, var)) + break; + s = lookup_variable (ip, var, strlen(var)); + } while (s); + + var = ParseIfExpression(ip, var, &val); + if (var && *var) debug(4, ("extraneous: '%s'\n", var)); + return val; +} + +int +cppsetup(char *filename, + char *line, + struct filepointer *filep, + struct inclist *inc) +{ + IfParser ip; + struct _parse_data pd; + long val = 0; + + pd.filep = filep; + pd.inc = inc; + pd.line = line; + pd.filename = filename; + ip.funcs.handle_error = my_if_errors; + ip.funcs.eval_defined = my_eval_defined; + ip.funcs.eval_variable = my_eval_variable; + ip.data = (char *) &pd; + + (void) ParseIfExpression (&ip, line, &val); + if (val) + return IF; + else + return IFFALSE; +} +#endif /* CPP */ + diff --git a/js/src/config/mkdepend/def.h b/js/src/config/mkdepend/def.h new file mode 100644 index 0000000..d6e5f89 --- /dev/null +++ b/js/src/config/mkdepend/def.h @@ -0,0 +1,184 @@ +/* $Xorg: def.h,v 1.4 2001/02/09 02:03:16 xorgcvs Exp $ */ +/* + +Copyright (c) 1993, 1994, 1998 The Open Group. + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/* $XFree86: xc/config/makedepend/def.h,v 3.14 2003/01/17 17:09:49 tsi Exp $ */ + +#ifndef NO_X11 +#include +#include +#endif +#include +#include +#include +#include +#if 0 +#ifndef X_NOT_POSIX +#ifndef _POSIX_SOURCE +#define _POSIX_SOURCE +#endif +#endif +#endif +#include +#include +#include + +#define MAXDEFINES 512 +#define MAXFILES 1024 +#define MAXINCFILES 256 /* "-include" files */ +#define MAXDIRS 1024 +#define SYMTABINC 10 /* must be > 1 for define() to work right */ +#define TRUE 1 +#define FALSE 0 + +/* the following must match the directives table in main.c */ +#define IF 0 +#define IFDEF 1 +#define IFNDEF 2 +#define ELSE 3 +#define ENDIF 4 +#define DEFINE 5 +#define UNDEF 6 +#define INCLUDE 7 +#define LINE 8 +#define PRAGMA 9 +#define ERROR 10 +#define IDENT 11 +#define SCCS 12 +#define ELIF 13 +#define EJECT 14 +#define WARNING 15 +#define INCLUDENEXT 16 +#define IFFALSE 17 /* pseudo value --- never matched */ +#define ELIFFALSE 18 /* pseudo value --- never matched */ +#define INCLUDEDOT 19 /* pseudo value --- never matched */ +#define IFGUESSFALSE 20 /* pseudo value --- never matched */ +#define ELIFGUESSFALSE 21 /* pseudo value --- never matched */ +#define INCLUDENEXTDOT 22 /* pseudo value --- never matched */ + +#ifdef DEBUG +extern int _debugmask; +/* + * debug levels are: + * + * 0 show ifn*(def)*,endif + * 1 trace defined/!defined + * 2 show #include + * 3 show #include SYMBOL + * 4-6 unused + */ +#define debug(level,arg) { if (_debugmask & (1 << level)) warning arg; } +#else +#define debug(level,arg) /**/ +#endif /* DEBUG */ + +typedef unsigned char boolean; + +struct symtab { + char *s_name; + char *s_value; +}; + +/* possible i_flag */ +#define DEFCHECKED (1<<0) /* whether defines have been checked */ +#define NOTIFIED (1<<1) /* whether we have revealed includes */ +#define MARKED (1<<2) /* whether it's in the makefile */ +#define SEARCHED (1<<3) /* whether we have read this */ +#define FINISHED (1<<4) /* whether we are done reading this */ +#define INCLUDED_SYM (1<<5) /* whether #include SYMBOL was found + Can't use i_list if TRUE */ +struct inclist { + char *i_incstring; /* string from #include line */ + char *i_file; /* path name of the include file */ + struct inclist **i_list; /* list of files it itself includes */ + int i_listlen; /* length of i_list */ + struct symtab **i_defs; /* symbol table for this file and its + children when merged */ + int i_ndefs; /* current # defines */ + boolean *i_merged; /* whether we have merged child + defines */ + unsigned char i_flags; +}; + +struct filepointer { + char *f_name; + char *f_p; + char *f_base; + char *f_end; + long f_len; + long f_line; + long cmdinc_count; + char **cmdinc_list; + long cmdinc_line; +}; + +#include +#if defined(macII) && !defined(__STDC__) /* stdlib.h fails to define these */ +char *malloc(), *realloc(); +#endif /* macII */ + +char *copy(char *str); +int match(char *str, char **list); +char *base_name(char *file); +char *getnextline(struct filepointer *fp); +struct symtab **slookup(char *symbol, struct inclist *file); +struct symtab **isdefined(char *symbol, struct inclist *file, + struct inclist **srcfile); +struct symtab **fdefined(char *symbol, struct inclist *file, + struct inclist **srcfile); +struct filepointer *getfile(char *file); +void included_by(struct inclist *ip, + struct inclist *newfile); +struct inclist *newinclude(char *newfile, char *incstring); +void inc_clean (void); +struct inclist *inc_path(char *file, char *include, int type); + +void freefile(struct filepointer *fp); + +void define2(char *name, char *val, struct inclist *file); +void define(char *def, struct inclist *file); +void undefine(char *symbol, struct inclist *file); +int find_includes(struct filepointer *filep, + struct inclist *file, + struct inclist *file_red, + int recursion, boolean failOK); + +void recursive_pr_include(struct inclist *head, + char *file, char *base); +void add_include(struct filepointer *filep, + struct inclist *file, + struct inclist *file_red, + char *include, int type, + boolean failOK); + +int cppsetup(char *filename, + char *line, + struct filepointer *filep, + struct inclist *inc); + + +extern void fatalerr(char *, ...); +extern void warning(char *, ...); +extern void warning1(char *, ...); diff --git a/js/src/config/mkdepend/ifparser.c b/js/src/config/mkdepend/ifparser.c new file mode 100644 index 0000000..0b184c2 --- /dev/null +++ b/js/src/config/mkdepend/ifparser.c @@ -0,0 +1,551 @@ +/* + * $Xorg: ifparser.c,v 1.3 2000/08/17 19:41:50 cpqbld Exp $ + * + * Copyright 1992 Network Computing Devices, Inc. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Network Computing Devices may not be + * used in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. Network Computing Devices makes + * no representations about the suitability of this software for any purpose. + * It is provided ``as is'' without express or implied warranty. + * + * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Author: Jim Fulton + * Network Computing Devices, Inc. + * + * Simple if statement processor + * + * This module can be used to evaluate string representations of C language + * if constructs. It accepts the following grammar: + * + * EXPRESSION := VALUE + * | VALUE BINOP EXPRESSION + * | VALUE '?' EXPRESSION ':' EXPRESSION + * + * VALUE := '(' EXPRESSION ')' + * | '!' VALUE + * | '-' VALUE + * | '+' VALUE + * | '~' VALUE + * | 'defined' '(' variable ')' + * | 'defined' variable + * | # variable '(' variable-list ')' + * | variable + * | number + * + * BINOP := '*' | '/' | '%' + * | '+' | '-' + * | '<<' | '>>' + * | '<' | '>' | '<=' | '>=' + * | '==' | '!=' + * | '&' | '^' | '|' + * | '&&' | '||' + * + * The normal C order of precedence is supported. + * + * + * External Entry Points: + * + * ParseIfExpression parse a string for #if + */ +/* $XFree86: xc/config/makedepend/ifparser.c,v 3.11 2002/09/23 01:48:08 tsi Exp $ */ + +#include "ifparser.h" +#include +#include +#include + +/**************************************************************************** + Internal Macros and Utilities for Parser + ****************************************************************************/ + +#define DO(val) if (!(val)) return NULL +#define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff)) +#define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++ +#define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_') + + +static const char * +parse_variable (IfParser *g, const char *cp, const char **varp) +{ + SKIPSPACE (cp); + + if (!isvarfirstletter (*cp)) + return CALLFUNC(g, handle_error) (g, cp, "variable name"); + + *varp = cp; + /* EMPTY */ + for (cp++; isalnum(*cp) || *cp == '_'; cp++) ; + return cp; +} + + +static const char * +parse_number (IfParser *g, const char *cp, long *valp) +{ + long base = 10; + SKIPSPACE (cp); + + if (!isdigit(*cp)) + return CALLFUNC(g, handle_error) (g, cp, "number"); + + *valp = 0; + + if (*cp == '0') { + cp++; + if ((*cp == 'x') || (*cp == 'X')) { + base = 16; + cp++; + } else { + base = 8; + } + } + + /* Ignore overflows and assume ASCII, what source is usually written in */ + while (1) { + int increment = -1; + if (base == 8) { + if ((*cp >= '0') && (*cp <= '7')) + increment = *cp++ - '0'; + } else if (base == 16) { + if ((*cp >= '0') && (*cp <= '9')) + increment = *cp++ - '0'; + else if ((*cp >= 'A') && (*cp <= 'F')) + increment = *cp++ - ('A' - 10); + else if ((*cp >= 'a') && (*cp <= 'f')) + increment = *cp++ - ('a' - 10); + } else { /* Decimal */ + if ((*cp >= '0') && (*cp <= '9')) + increment = *cp++ - '0'; + } + if (increment < 0) + break; + *valp = (*valp * base) + increment; + } + + /* Skip trailing qualifiers */ + while (*cp == 'U' || *cp == 'u' || *cp == 'L' || *cp == 'l') cp++; + return cp; +} + +static const char * +parse_character (IfParser *g, const char *cp, long *valp) +{ + char val; + + SKIPSPACE (cp); + if (*cp == '\\') + switch (cp[1]) { + case 'n': val = '\n'; break; + case 't': val = '\t'; break; + case 'v': val = '\v'; break; + case 'b': val = '\b'; break; + case 'r': val = '\r'; break; + case 'f': val = '\f'; break; + case 'a': val = '\a'; break; + case '\\': val = '\\'; break; + case '?': val = '\?'; break; + case '\'': val = '\''; break; + case '\"': val = '\"'; break; + case 'x': val = (char) strtol (cp + 2, NULL, 16); break; + default: val = (char) strtol (cp + 1, NULL, 8); break; + } + else + val = *cp; + while (*cp != '\'') cp++; + *valp = (long) val; + return cp; +} + +static const char * +parse_value (IfParser *g, const char *cp, long *valp) +{ + const char *var, *varend; + + *valp = 0; + + SKIPSPACE (cp); + if (!*cp) + return cp; + + switch (*cp) { + case '(': + DO (cp = ParseIfExpression (g, cp + 1, valp)); + SKIPSPACE (cp); + if (*cp != ')') + return CALLFUNC(g, handle_error) (g, cp, ")"); + + return cp + 1; /* skip the right paren */ + + case '!': + DO (cp = parse_value (g, cp + 1, valp)); + *valp = !(*valp); + return cp; + + case '-': + DO (cp = parse_value (g, cp + 1, valp)); + *valp = -(*valp); + return cp; + + case '+': + DO (cp = parse_value (g, cp + 1, valp)); + return cp; + + case '~': + DO (cp = parse_value (g, cp + 1, valp)); + *valp = ~(*valp); + return cp; + + case '#': + DO (cp = parse_variable (g, cp + 1, &var)); + SKIPSPACE (cp); + if (*cp != '(') + return CALLFUNC(g, handle_error) (g, cp, "("); + do { + DO (cp = parse_variable (g, cp + 1, &var)); + SKIPSPACE (cp); + } while (*cp && *cp != ')'); + if (*cp != ')') + return CALLFUNC(g, handle_error) (g, cp, ")"); + *valp = 1; /* XXX */ + return cp + 1; + + case '\'': + DO (cp = parse_character (g, cp + 1, valp)); + if (*cp != '\'') + return CALLFUNC(g, handle_error) (g, cp, "'"); + return cp + 1; + + case 'd': + if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) { + int paren = 0; + int len; + + cp += 7; + SKIPSPACE (cp); + if (*cp == '(') { + paren = 1; + cp++; + } + DO (cp = parse_variable (g, cp, &var)); + len = cp - var; + SKIPSPACE (cp); + if (paren && *cp != ')') + return CALLFUNC(g, handle_error) (g, cp, ")"); + *valp = (*(g->funcs.eval_defined)) (g, var, len); + return cp + paren; /* skip the right paren */ + } + /* fall out */ + } + + if (isdigit(*cp)) { + DO (cp = parse_number (g, cp, valp)); + } else if (!isvarfirstletter(*cp)) + return CALLFUNC(g, handle_error) (g, cp, "variable or number"); + else { + DO (cp = parse_variable (g, cp, &var)); + varend = cp; + SKIPSPACE(cp); + if (*cp != '(') { + *valp = (*(g->funcs.eval_variable)) (g, var, varend - var); + } else { + do { + long dummy; + DO (cp = ParseIfExpression (g, cp + 1, &dummy)); + SKIPSPACE(cp); + if (*cp == ')') + break; + if (*cp != ',') + return CALLFUNC(g, handle_error) (g, cp, ","); + } while (1); + + *valp = 1; /* XXX */ + cp++; + } + } + + return cp; +} + + + +static const char * +parse_product (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_value (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '*': + DO (cp = parse_product (g, cp + 1, &rightval)); + *valp = (*valp * rightval); + break; + + case '/': + DO (cp = parse_product (g, cp + 1, &rightval)); + if (rightval == 0) + return CALLFUNC(g, handle_error) (g, cp, "0"); + *valp = (*valp / rightval); + break; + + case '%': + DO (cp = parse_product (g, cp + 1, &rightval)); + *valp = (*valp % rightval); + break; + } + return cp; +} + + +static const char * +parse_sum (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_product (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '+': + DO (cp = parse_sum (g, cp + 1, &rightval)); + *valp = (*valp + rightval); + break; + + case '-': + DO (cp = parse_sum (g, cp + 1, &rightval)); + *valp = (*valp - rightval); + break; + } + return cp; +} + + +static const char * +parse_shift (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_sum (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '<': + if (cp[1] == '<') { + DO (cp = parse_shift (g, cp + 2, &rightval)); + *valp = (*valp << rightval); + } + break; + + case '>': + if (cp[1] == '>') { + DO (cp = parse_shift (g, cp + 2, &rightval)); + *valp = (*valp >> rightval); + } + break; + } + return cp; +} + + +static const char * +parse_inequality (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_shift (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '<': + if (cp[1] == '=') { + DO (cp = parse_inequality (g, cp + 2, &rightval)); + *valp = (*valp <= rightval); + } else { + DO (cp = parse_inequality (g, cp + 1, &rightval)); + *valp = (*valp < rightval); + } + break; + + case '>': + if (cp[1] == '=') { + DO (cp = parse_inequality (g, cp + 2, &rightval)); + *valp = (*valp >= rightval); + } else { + DO (cp = parse_inequality (g, cp + 1, &rightval)); + *valp = (*valp > rightval); + } + break; + } + return cp; +} + + +static const char * +parse_equality (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_inequality (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '=': + if (cp[1] == '=') + cp++; + DO (cp = parse_equality (g, cp + 1, &rightval)); + *valp = (*valp == rightval); + break; + + case '!': + if (cp[1] != '=') + break; + DO (cp = parse_equality (g, cp + 2, &rightval)); + *valp = (*valp != rightval); + break; + } + return cp; +} + + +static const char * +parse_band (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_equality (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '&': + if (cp[1] != '&') { + DO (cp = parse_band (g, cp + 1, &rightval)); + *valp = (*valp & rightval); + } + break; + } + return cp; +} + + +static const char * +parse_bxor (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_band (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '^': + DO (cp = parse_bxor (g, cp + 1, &rightval)); + *valp = (*valp ^ rightval); + break; + } + return cp; +} + + +static const char * +parse_bor (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_bxor (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '|': + if (cp[1] != '|') { + DO (cp = parse_bor (g, cp + 1, &rightval)); + *valp = (*valp | rightval); + } + break; + } + return cp; +} + + +static const char * +parse_land (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_bor (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '&': + if (cp[1] != '&') + return CALLFUNC(g, handle_error) (g, cp, "&&"); + DO (cp = parse_land (g, cp + 2, &rightval)); + *valp = (*valp && rightval); + break; + } + return cp; +} + + +static const char * +parse_lor (IfParser *g, const char *cp, long *valp) +{ + long rightval; + + DO (cp = parse_land (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '|': + if (cp[1] != '|') + return CALLFUNC(g, handle_error) (g, cp, "||"); + DO (cp = parse_lor (g, cp + 2, &rightval)); + *valp = (*valp || rightval); + break; + } + return cp; +} + + +static const char * +parse_cond(IfParser *g, const char *cp, long *valp) +{ + long trueval, falseval; + + DO (cp = parse_lor (g, cp, valp)); + SKIPSPACE (cp); + + switch (*cp) { + case '?': + DO (cp = parse_cond (g, cp + 1, &trueval)); + SKIPSPACE (cp); + if (*cp != ':') + return CALLFUNC(g, handle_error) (g, cp, ":"); + DO (cp = parse_cond (g, cp + 1, &falseval)); + *valp = (*valp ? trueval : falseval); + break; + } + return cp; +} + + +/**************************************************************************** + External Entry Points + ****************************************************************************/ + +const char * +ParseIfExpression (IfParser *g, const char *cp, long *valp) +{ + return parse_cond (g, cp, valp); +} diff --git a/js/src/config/mkdepend/ifparser.h b/js/src/config/mkdepend/ifparser.h new file mode 100644 index 0000000..89d2a2f --- /dev/null +++ b/js/src/config/mkdepend/ifparser.h @@ -0,0 +1,83 @@ +/* + * $Xorg: ifparser.h,v 1.3 2000/08/17 19:41:51 cpqbld Exp $ + * + * Copyright 1992 Network Computing Devices, Inc. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Network Computing Devices may not be + * used in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. Network Computing Devices makes + * no representations about the suitability of this software for any purpose. + * It is provided ``as is'' without express or implied warranty. + * + * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Author: Jim Fulton + * Network Computing Devices, Inc. + * + * Simple if statement processor + * + * This module can be used to evaluate string representations of C language + * if constructs. It accepts the following grammar: + * + * EXPRESSION := VALUE + * | VALUE BINOP EXPRESSION + * | VALUE '?' EXPRESSION ':' EXPRESSION + * + * VALUE := '(' EXPRESSION ')' + * | '!' VALUE + * | '-' VALUE + * | '~' VALUE + * | 'defined' '(' variable ')' + * | variable + * | number + * + * BINOP := '*' | '/' | '%' + * | '+' | '-' + * | '<<' | '>>' + * | '<' | '>' | '<=' | '>=' + * | '==' | '!=' + * | '&' | '^' | '|' + * | '&&' | '||' + * + * The normal C order of precedence is supported. + * + * + * External Entry Points: + * + * ParseIfExpression parse a string for #if + */ + +/* $XFree86: xc/config/makedepend/ifparser.h,v 3.5 2001/07/25 15:04:40 dawes Exp $ */ + +#include + +typedef int Bool; +#define False 0 +#define True 1 + +typedef struct _if_parser { + struct { /* functions */ + const char *(*handle_error) (struct _if_parser *, const char *, + const char *); + long (*eval_variable) (struct _if_parser *, const char *, int); + int (*eval_defined) (struct _if_parser *, const char *, int); + } funcs; + char *data; +} IfParser; + +const char *ParseIfExpression ( + IfParser *, + const char *, + long * +); + diff --git a/js/src/config/mkdepend/imakemdep.h b/js/src/config/mkdepend/imakemdep.h new file mode 100644 index 0000000..5c58351 --- /dev/null +++ b/js/src/config/mkdepend/imakemdep.h @@ -0,0 +1,733 @@ + +/* $XConsortium: imakemdep.h,v 1.83 95/04/07 19:47:46 kaleb Exp $ */ +/* $XFree86: xc/config/imake/imakemdep.h,v 3.12 1995/07/08 10:22:17 dawes Exp $ */ +/* + +Copyright (c) 1993, 1994 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from the X Consortium. + +*/ + + +/* + * This file contains machine-dependent constants for the imake utility. + * When porting imake, read each of the steps below and add in any necessary + * definitions. In general you should *not* edit ccimake.c or imake.c! + */ + +#ifdef CCIMAKE +/* + * Step 1: imake_ccflags + * Define any special flags that will be needed to get imake.c to compile. + * These will be passed to the compile along with the contents of the + * make variable BOOTSTRAPCFLAGS. + */ +#ifdef hpux +#ifdef hp9000s800 +#define imake_ccflags "-DSYSV" +#else +#define imake_ccflags "-Wc,-Nd4000,-Ns3000 -DSYSV" +#endif +#endif + +#if defined(macII) || defined(_AUX_SOURCE) +#define imake_ccflags "-DmacII -DSYSV" +#endif + +#ifdef stellar +#define imake_ccflags "-DSYSV" +#endif + +#if defined(USL) || defined(Oki) || defined(NCR) +#define imake_ccflags "-Xc -DSVR4" +#endif + +#ifdef sony +#if defined(SYSTYPE_SYSV) || defined(_SYSTYPE_SYSV) +#define imake_ccflags "-DSVR4" +#else +#include +#if NEWSOS < 41 +#define imake_ccflags "-Dbsd43 -DNOSTDHDRS" +#else +#if NEWSOS < 42 +#define imake_ccflags "-Dbsd43" +#endif +#endif +#endif +#endif + +#ifdef _CRAY +#define imake_ccflags "-DSYSV -DUSG" +#endif + +#if defined(_IBMR2) || defined(aix) +#define imake_ccflags "-Daix -DSYSV" +#endif + +#ifdef Mips +# if defined(SYSTYPE_BSD) || defined(BSD) || defined(BSD43) +# define imake_ccflags "-DBSD43" +# else +# define imake_ccflags "-DSYSV" +# endif +#endif + +#ifdef is68k +#define imake_ccflags "-Dluna -Duniosb" +#endif + +#ifdef SYSV386 +# ifdef SVR4 +# define imake_ccflags "-Xc -DSVR4" +# else +# define imake_ccflags "-DSYSV" +# endif +#endif + +#ifdef SVR4 +# ifdef i386 +# define imake_ccflags "-Xc -DSVR4" +# endif +#endif + +#ifdef SYSV +# ifdef i386 +# define imake_ccflags "-DSYSV" +# endif +#endif + +#ifdef __convex__ +#define imake_ccflags "-fn -tm c1" +#endif + +#ifdef apollo +#define imake_ccflags "-DX_NOT_POSIX" +#endif + +#ifdef WIN32 +#define imake_ccflags "-nologo -batch -D__STDC__" +#endif + +#ifdef __uxp__ +#define imake_ccflags "-DSVR4 -DANSICPP" +#endif + +#ifdef __sxg__ +#define imake_ccflags "-DSYSV -DUSG -DNOSTDHDRS" +#endif + +#ifdef sequent +#define imake_ccflags "-DX_NOT_STDC_ENV -DX_NOT_POSIX" +#endif + +#ifdef _SEQUENT_ +#define imake_ccflags "-DSYSV -DUSG" +#endif + +#if defined(SX) || defined(PC_UX) +#define imake_ccflags "-DSYSV" +#endif + +#ifdef nec_ews_svr2 +#define imake_ccflags "-DUSG" +#endif + +#if defined(nec_ews_svr4) || defined(_nec_ews_svr4) || defined(_nec_up) || defined(_nec_ft) +#define imake_ccflags "-DSVR4" +#endif + +#ifdef MACH +#define imake_ccflags "-DNOSTDHDRS" +#endif + +/* this is for OS/2 under EMX. This won't work with DOS */ +#if defined(__EMX__) +#define imake_ccflags "-DBSD43" +#endif + +#else /* not CCIMAKE */ +#ifndef MAKEDEPEND +/* + * Step 2: dup2 + * If your OS doesn't have a dup2() system call to duplicate one file + * descriptor onto another, define such a mechanism here (if you don't + * already fall under the existing category(ies). + */ +#if defined(SYSV) && !defined(_CRAY) && !defined(Mips) && !defined(_SEQUENT_) +#define dup2(fd1,fd2) ((fd1 == fd2) ? fd1 : (close(fd2), \ + fcntl(fd1, F_DUPFD, fd2))) +#endif + + +/* + * Step 3: FIXUP_CPP_WHITESPACE + * If your cpp collapses tabs macro expansions into a single space and + * replaces escaped newlines with a space, define this symbol. This will + * cause imake to attempt to patch up the generated Makefile by looking + * for lines that have colons in them (this is why the rules file escapes + * all colons). One way to tell if you need this is to see whether or not + * your Makefiles have no tabs in them and lots of @@ strings. + */ +#if defined(sun) || defined(SYSV) || defined(SVR4) || defined(hcx) || defined(WIN32) || (defined(AMOEBA) && defined(CROSS_COMPILE)) +#define FIXUP_CPP_WHITESPACE +#endif +#ifdef WIN32 +#define REMOVE_CPP_LEADSPACE +#define INLINE_SYNTAX +#define MAGIC_MAKE_VARS +#endif +#ifdef __minix_vmd +#define FIXUP_CPP_WHITESPACE +#endif + +/* + * Step 4: USE_CC_E, DEFAULT_CC, DEFAULT_CPP + * If you want to use cc -E instead of cpp, define USE_CC_E. + * If use cc -E but want a different compiler, define DEFAULT_CC. + * If the cpp you need is not in /lib/cpp, define DEFAULT_CPP. + */ +#ifdef hpux +#define USE_CC_E +#endif +#ifdef WIN32 +#define USE_CC_E +#define DEFAULT_CC "cl" +#endif +#ifdef apollo +#define DEFAULT_CPP "/usr/lib/cpp" +#endif +#if defined(_IBMR2) && !defined(DEFAULT_CPP) +#define DEFAULT_CPP "/usr/lpp/X11/Xamples/util/cpp/cpp" +#endif +#if defined(sun) && defined(SVR4) +#define DEFAULT_CPP "/usr/ccs/lib/cpp" +#endif +#ifdef __bsdi__ +#define DEFAULT_CPP "/usr/bin/cpp" +#endif +#ifdef __uxp__ +#define DEFAULT_CPP "/usr/ccs/lib/cpp" +#endif +#ifdef __sxg__ +#define DEFAULT_CPP "/usr/lib/cpp" +#endif +#ifdef _CRAY +#define DEFAULT_CPP "/lib/pcpp" +#endif +#if defined(__386BSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +#define DEFAULT_CPP "/usr/libexec/cpp" +#endif +#ifdef MACH +#define USE_CC_E +#endif +#ifdef __minix_vmd +#define DEFAULT_CPP "/usr/lib/cpp" +#endif +#if defined(__EMX__) +/* expects cpp in PATH */ +#define DEFAULT_CPP "cpp" +#endif + +/* + * Step 5: cpp_argv + * The following table contains the flags that should be passed + * whenever a Makefile is being generated. If your preprocessor + * doesn't predefine any unique symbols, choose one and add it to the + * end of this table. Then, do the following: + * + * a. Use this symbol in Imake.tmpl when setting MacroFile. + * b. Put this symbol in the definition of BootstrapCFlags in your + * .cf file. + * c. When doing a make World, always add "BOOTSTRAPCFLAGS=-Dsymbol" + * to the end of the command line. + * + * Note that you may define more than one symbol (useful for platforms + * that support multiple operating systems). + */ + +#define ARGUMENTS 50 /* number of arguments in various arrays */ +char *cpp_argv[ARGUMENTS] = { + "cc", /* replaced by the actual program to exec */ + "-I.", /* add current directory to include path */ +#ifdef unix + "-Uunix", /* remove unix symbol so that filename unix.c okay */ +#endif +#if defined(__386BSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(MACH) +# ifdef __i386__ + "-D__i386__", +# endif +# ifdef __x86_64__ + "-D__x86_64__", +# endif +# ifdef __GNUC__ + "-traditional", +# endif +#endif +#ifdef M4330 + "-DM4330", /* Tektronix */ +#endif +#ifdef M4310 + "-DM4310", /* Tektronix */ +#endif +#if defined(macII) || defined(_AUX_SOURCE) + "-DmacII", /* Apple A/UX */ +#endif +#ifdef USL + "-DUSL", /* USL */ +#endif +#ifdef sony + "-Dsony", /* Sony */ +#if !defined(SYSTYPE_SYSV) && !defined(_SYSTYPE_SYSV) && NEWSOS < 42 + "-Dbsd43", +#endif +#endif +#ifdef _IBMR2 + "-D_IBMR2", /* IBM RS-6000 (we ensured that aix is defined above */ +#ifndef aix +#define aix /* allow BOOTSTRAPCFLAGS="-D_IBMR2" */ +#endif +#endif /* _IBMR2 */ +#ifdef aix + "-Daix", /* AIX instead of AOS */ +#ifndef ibm +#define ibm /* allow BOOTSTRAPCFLAGS="-Daix" */ +#endif +#endif /* aix */ +#ifdef ibm + "-Dibm", /* IBM PS/2 and RT under both AOS and AIX */ +#endif +#ifdef luna + "-Dluna", /* OMRON luna 68K and 88K */ +#ifdef luna1 + "-Dluna1", +#endif +#ifdef luna88k /* need not on UniOS-Mach Vers. 1.13 */ + "-traditional", /* for some older version */ +#endif /* instead of "-DXCOMM=\\#" */ +#ifdef uniosb + "-Duniosb", +#endif +#ifdef uniosu + "-Duniosu", +#endif +#endif /* luna */ +#ifdef _CRAY /* Cray */ + "-Ucray", +#endif +#ifdef Mips + "-DMips", /* Define and use Mips for Mips Co. OS/mach. */ +# if defined(SYSTYPE_BSD) || defined(BSD) || defined(BSD43) + "-DBSD43", /* Mips RISCOS supports two environments */ +# else + "-DSYSV", /* System V environment is the default */ +# endif +#endif /* Mips */ +#ifdef MOTOROLA + "-DMOTOROLA", /* Motorola Delta Systems */ +# ifdef SYSV + "-DSYSV", +# endif +# ifdef SVR4 + "-DSVR4", +# endif +#endif /* MOTOROLA */ +#ifdef i386 + "-Di386", +# ifdef SVR4 + "-DSVR4", +# endif +# ifdef SYSV + "-DSYSV", +# ifdef ISC + "-DISC", +# ifdef ISC40 + "-DISC40", /* ISC 4.0 */ +# else +# ifdef ISC202 + "-DISC202", /* ISC 2.0.2 */ +# else +# ifdef ISC30 + "-DISC30", /* ISC 3.0 */ +# else + "-DISC22", /* ISC 2.2.1 */ +# endif +# endif +# endif +# endif +# ifdef SCO + "-DSCO", +# ifdef SCO324 + "-DSCO324", +# endif +# endif +# endif +# ifdef ESIX + "-DESIX", +# endif +# ifdef ATT + "-DATT", +# endif +# ifdef DELL + "-DDELL", +# endif +#endif +#ifdef SYSV386 /* System V/386 folks, obsolete */ + "-Di386", +# ifdef SVR4 + "-DSVR4", +# endif +# ifdef ISC + "-DISC", +# ifdef ISC40 + "-DISC40", /* ISC 4.0 */ +# else +# ifdef ISC202 + "-DISC202", /* ISC 2.0.2 */ +# else +# ifdef ISC30 + "-DISC30", /* ISC 3.0 */ +# else + "-DISC22", /* ISC 2.2.1 */ +# endif +# endif +# endif +# endif +# ifdef SCO + "-DSCO", +# ifdef SCO324 + "-DSCO324", +# endif +# endif +# ifdef ESIX + "-DESIX", +# endif +# ifdef ATT + "-DATT", +# endif +# ifdef DELL + "-DDELL", +# endif +#endif +#ifdef __osf__ + "-D__osf__", +# ifdef __mips__ + "-D__mips__", +# endif +# ifdef __alpha + "-D__alpha", +# endif +# ifdef __i386__ + "-D__i386__", +# endif +# ifdef __GNUC__ + "-traditional", +# endif +#endif +#ifdef Oki + "-DOki", +#endif +#ifdef sun +#ifdef SVR4 + "-DSVR4", +#endif +#endif +#ifdef WIN32 + "-DWIN32", + "-nologo", + "-batch", + "-D__STDC__", +#endif +#ifdef NCR + "-DNCR", /* NCR */ +#endif +#ifdef linux + "-traditional", + "-Dlinux", +#endif +#ifdef __uxp__ + "-D__uxp__", +#endif +#ifdef __sxg__ + "-D__sxg__", +#endif +#ifdef nec_ews_svr2 + "-Dnec_ews_svr2", +#endif +#ifdef AMOEBA + "-DAMOEBA", +# ifdef CROSS_COMPILE + "-DCROSS_COMPILE", +# ifdef CROSS_i80386 + "-Di80386", +# endif +# ifdef CROSS_sparc + "-Dsparc", +# endif +# ifdef CROSS_mc68000 + "-Dmc68000", +# endif +# else +# ifdef i80386 + "-Di80386", +# endif +# ifdef sparc + "-Dsparc", +# endif +# ifdef mc68000 + "-Dmc68000", +# endif +# endif +#endif +#ifdef __minix_vmd + "-Dminix", +#endif + +#if defined(__EMX__) + "-traditional", + "-Demxos2", +#endif + +}; +#else /* else MAKEDEPEND */ +/* + * Step 6: predefs + * If your compiler and/or preprocessor define any specific symbols, add + * them to the the following table. The definition of struct symtab is + * in util/makedepend/def.h. + */ +struct symtab predefs[] = { +#ifdef apollo + {"apollo", "1"}, +#endif +#ifdef ibm032 + {"ibm032", "1"}, +#endif +#ifdef ibm + {"ibm", "1"}, +#endif +#ifdef aix + {"aix", "1"}, +#endif +#ifdef sun + {"sun", "1"}, +#endif +#ifdef sun2 + {"sun2", "1"}, +#endif +#ifdef sun3 + {"sun3", "1"}, +#endif +#ifdef sun4 + {"sun4", "1"}, +#endif +#ifdef sparc + {"sparc", "1"}, +#endif +#ifdef __sparc__ + {"__sparc__", "1"}, +#endif +#ifdef hpux + {"hpux", "1"}, +#endif +#ifdef __hpux + {"__hpux", "1"}, +#endif +#ifdef __hp9000s800 + {"__hp9000s800", "1"}, +#endif +#ifdef __hp9000s700 + {"__hp9000s700", "1"}, +#endif +#ifdef vax + {"vax", "1"}, +#endif +#ifdef VMS + {"VMS", "1"}, +#endif +#ifdef cray + {"cray", "1"}, +#endif +#ifdef CRAY + {"CRAY", "1"}, +#endif +#ifdef _CRAY + {"_CRAY", "1"}, +#endif +#ifdef att + {"att", "1"}, +#endif +#ifdef mips + {"mips", "1"}, +#endif +#ifdef __mips__ + {"__mips__", "1"}, +#endif +#ifdef ultrix + {"ultrix", "1"}, +#endif +#ifdef stellar + {"stellar", "1"}, +#endif +#ifdef mc68000 + {"mc68000", "1"}, +#endif +#ifdef mc68020 + {"mc68020", "1"}, +#endif +#ifdef __GNUC__ + {"__GNUC__", "1"}, +#endif +#if __STDC__ + {"__STDC__", "1"}, +#endif +#ifdef __HIGHC__ + {"__HIGHC__", "1"}, +#endif +#ifdef CMU + {"CMU", "1"}, +#endif +#ifdef luna + {"luna", "1"}, +#ifdef luna1 + {"luna1", "1"}, +#endif +#ifdef luna2 + {"luna2", "1"}, +#endif +#ifdef luna88k + {"luna88k", "1"}, +#endif +#ifdef uniosb + {"uniosb", "1"}, +#endif +#ifdef uniosu + {"uniosu", "1"}, +#endif +#endif +#ifdef ieeep754 + {"ieeep754", "1"}, +#endif +#ifdef is68k + {"is68k", "1"}, +#endif +#ifdef m68k + {"m68k", "1"}, +#endif +#ifdef m88k + {"m88k", "1"}, +#endif +#ifdef __m88k__ + {"__m88k__", "1"}, +#endif +#ifdef bsd43 + {"bsd43", "1"}, +#endif +#ifdef hcx + {"hcx", "1"}, +#endif +#ifdef sony + {"sony", "1"}, +#ifdef SYSTYPE_SYSV + {"SYSTYPE_SYSV", "1"}, +#endif +#ifdef _SYSTYPE_SYSV + {"_SYSTYPE_SYSV", "1"}, +#endif +#endif +#ifdef __OSF__ + {"__OSF__", "1"}, +#endif +#ifdef __osf__ + {"__osf__", "1"}, +#endif +#ifdef __alpha + {"__alpha", "1"}, +#endif +#ifdef __DECC + {"__DECC", "1"}, +#endif +#ifdef __decc + {"__decc", "1"}, +#endif +#ifdef __uxp__ + {"__uxp__", "1"}, +#endif +#ifdef __sxg__ + {"__sxg__", "1"}, +#endif +#ifdef _SEQUENT_ + {"_SEQUENT_", "1"}, + {"__STDC__", "1"}, +#endif +#ifdef __bsdi__ + {"__bsdi__", "1"}, +#endif +#ifdef nec_ews_svr2 + {"nec_ews_svr2", "1"}, +#endif +#ifdef nec_ews_svr4 + {"nec_ews_svr4", "1"}, +#endif +#ifdef _nec_ews_svr4 + {"_nec_ews_svr4", "1"}, +#endif +#ifdef _nec_up + {"_nec_up", "1"}, +#endif +#ifdef SX + {"SX", "1"}, +#endif +#ifdef nec + {"nec", "1"}, +#endif +#ifdef _nec_ft + {"_nec_ft", "1"}, +#endif +#ifdef PC_UX + {"PC_UX", "1"}, +#endif +#ifdef sgi + {"sgi", "1"}, +#endif +#ifdef __sgi + {"__sgi", "1"}, +#endif +#ifdef __FreeBSD__ + {"__FreeBSD__", "1"}, +#endif +#ifdef __NetBSD__ + {"__NetBSD__", "1"}, +#endif +#ifdef __OpenBSD__ + {"__OpenBSD__", "1"}, +#endif +#ifdef __EMX__ + {"__EMX__", "1"}, +#endif + /* add any additional symbols before this line */ + {NULL, NULL} +}; + +#endif /* MAKEDEPEND */ +#endif /* CCIMAKE */ diff --git a/js/src/config/mkdepend/include.c b/js/src/config/mkdepend/include.c new file mode 100644 index 0000000..3b89f26 --- /dev/null +++ b/js/src/config/mkdepend/include.c @@ -0,0 +1,337 @@ +/* $Xorg: include.c,v 1.4 2001/02/09 02:03:16 xorgcvs Exp $ */ +/* + +Copyright (c) 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/* $XFree86: xc/config/makedepend/include.c,v 3.7 2001/12/14 19:53:20 dawes Exp $ */ + + +#include "def.h" + +#ifdef _MSC_VER +#include +static int +does_file_exist(char *file) +{ + WIN32_FILE_ATTRIBUTE_DATA data; + BOOL b = GetFileAttributesExA(file, GetFileExInfoStandard, &data); + if (!b) + return 0; + return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0; +} +#else +static int +does_file_exist(char *file) +{ + struct stat sb; + return stat(file, &sb) == 0 && !S_ISDIR(sb.st_mode); +} +#endif + +extern struct inclist inclist[ MAXFILES ], + *inclistp, *inclistnext; +extern char *includedirs[ ], + **includedirsnext; +extern char *notdotdot[ ]; +extern boolean show_where_not; +extern boolean warn_multiple; + +static boolean +isdot(char *p) +{ + if(p && *p++ == '.' && *p++ == '\0') + return(TRUE); + return(FALSE); +} + +static boolean +isdotdot(char *p) +{ + if(p && *p++ == '.' && *p++ == '.' && *p++ == '\0') + return(TRUE); + return(FALSE); +} + +static boolean +issymbolic(char *dir, char *component) +{ +#ifdef S_IFLNK + struct stat st; + char buf[ BUFSIZ ], **pp; + + sprintf(buf, "%s%s%s", dir, *dir ? "/" : "", component); + for (pp=notdotdot; *pp; pp++) + if (strcmp(*pp, buf) == 0) + return (TRUE); + if (lstat(buf, &st) == 0 + && (st.st_mode & S_IFMT) == S_IFLNK) { + *pp++ = copy(buf); + if (pp >= ¬dotdot[ MAXDIRS ]) + fatalerr("out of .. dirs, increase MAXDIRS\n"); + return(TRUE); + } +#endif + return(FALSE); +} + +/* + * Occasionally, pathnames are created that look like .../x/../y + * Any of the 'x/..' sequences within the name can be eliminated. + * (but only if 'x' is not a symbolic link!!) + */ +static void +remove_dotdot(char *path) +{ + register char *end, *from, *to, **cp; + char *components[ MAXFILES ], + newpath[ BUFSIZ ]; + boolean component_copied; + + /* + * slice path up into components. + */ + to = newpath; + if (*path == '/') + *to++ = '/'; + *to = '\0'; + cp = components; + for (from=end=path; *end; end++) + if (*end == '/') { + while (*end == '/') + *end++ = '\0'; + if (*from) + *cp++ = from; + from = end; + } + *cp++ = from; + *cp = NULL; + + /* + * Recursively remove all 'x/..' component pairs. + */ + cp = components; + while(*cp) { + if (!isdot(*cp) && !isdotdot(*cp) && isdotdot(*(cp+1)) + && !issymbolic(newpath, *cp)) + { + char **fp = cp + 2; + char **tp = cp; + + do + *tp++ = *fp; /* move all the pointers down */ + while (*fp++); + if (cp != components) + cp--; /* go back and check for nested ".." */ + } else { + cp++; + } + } + /* + * Concatenate the remaining path elements. + */ + cp = components; + component_copied = FALSE; + while(*cp) { + if (component_copied) + *to++ = '/'; + component_copied = TRUE; + for (from = *cp; *from; ) + *to++ = *from++; + *to = '\0'; + cp++; + } + *to++ = '\0'; + + /* + * copy the reconstituted path back to our pointer. + */ + strcpy(path, newpath); +} + +/* + * Add an include file to the list of those included by 'file'. + */ +struct inclist * +newinclude(char *newfile, char *incstring) +{ + register struct inclist *ip; + + /* + * First, put this file on the global list of include files. + */ + ip = inclistp++; + if (inclistp == inclist + MAXFILES - 1) + fatalerr("out of space: increase MAXFILES\n"); + ip->i_file = copy(newfile); + + if (incstring == NULL) + ip->i_incstring = ip->i_file; + else + ip->i_incstring = copy(incstring); + + inclistnext = inclistp; + return(ip); +} + +void +included_by(struct inclist *ip, struct inclist *newfile) +{ + register int i; + + if (ip == NULL) + return; + /* + * Put this include file (newfile) on the list of files included + * by 'file'. If 'file' is NULL, then it is not an include + * file itself (i.e. was probably mentioned on the command line). + * If it is already on the list, don't stick it on again. + */ + if (ip->i_list == NULL) { + ip->i_list = (struct inclist **) + malloc(sizeof(struct inclist *) * ++ip->i_listlen); + ip->i_merged = (boolean *) + malloc(sizeof(boolean) * ip->i_listlen); + } else { + for (i=0; ii_listlen; i++) + if (ip->i_list[ i ] == newfile) { + i = strlen(newfile->i_file); + if (!(ip->i_flags & INCLUDED_SYM) && + !(i > 2 && + newfile->i_file[i-1] == 'c' && + newfile->i_file[i-2] == '.')) + { + /* only bitch if ip has */ + /* no #include SYMBOL lines */ + /* and is not a .c file */ + if (warn_multiple) + { + warning("%s includes %s more than once!\n", + ip->i_file, newfile->i_file); + warning1("Already have\n"); + for (i=0; ii_listlen; i++) + warning1("\t%s\n", ip->i_list[i]->i_file); + } + } + return; + } + ip->i_list = (struct inclist **) realloc(ip->i_list, + sizeof(struct inclist *) * ++ip->i_listlen); + ip->i_merged = (boolean *) + realloc(ip->i_merged, sizeof(boolean) * ip->i_listlen); + } + ip->i_list[ ip->i_listlen-1 ] = newfile; + ip->i_merged[ ip->i_listlen-1 ] = FALSE; +} + +void +inc_clean (void) +{ + register struct inclist *ip; + + for (ip = inclist; ip < inclistp; ip++) { + ip->i_flags &= ~MARKED; + } +} + +struct inclist * +inc_path(char *file, char *include, int type) +{ + static char path[ BUFSIZ ]; + register char **pp, *p; + register struct inclist *ip; + + /* + * Check all previously found include files for a path that + * has already been expanded. + */ + if ((type == INCLUDE) || (type == INCLUDEDOT)) + inclistnext = inclist; + ip = inclistnext; + + for (; ip->i_file; ip++) { + if ((strcmp(ip->i_incstring, include) == 0) && + !(ip->i_flags & INCLUDED_SYM)) { + inclistnext = ip + 1; + return ip; + } + } + + if (inclistnext == inclist) { + /* + * If the path was surrounded by "" or is an absolute path, + * then check the exact path provided. + */ + if ((type == INCLUDEDOT) || + (type == INCLUDENEXTDOT) || + (*include == '/')) { + if (does_file_exist(include)) + return newinclude(include, include); + if (show_where_not) + warning1("\tnot in %s\n", include); + } + + /* + * If the path was surrounded by "" see if this include file is + * in the directory of the file being parsed. + */ + if ((type == INCLUDEDOT) || (type == INCLUDENEXTDOT)) { + for (p=file+strlen(file); p>file; p--) + if (*p == '/') + break; + if (p == file) { + strcpy(path, include); + } else { + strncpy(path, file, (p-file) + 1); + path[ (p-file) + 1 ] = '\0'; + strcpy(path + (p-file) + 1, include); + } + remove_dotdot(path); + if (does_file_exist(path)) + return newinclude(path, include); + if (show_where_not) + warning1("\tnot in %s\n", path); + } + } + + /* + * Check the include directories specified. Standard include dirs + * should be at the end. + */ + if ((type == INCLUDE) || (type == INCLUDEDOT)) + includedirsnext = includedirs; + pp = includedirsnext; + + for (; *pp; pp++) { + sprintf(path, "%s/%s", *pp, include); + remove_dotdot(path); + if (does_file_exist(path)) { + includedirsnext = pp + 1; + return newinclude(path, include); + } + if (show_where_not) + warning1("\tnot in %s\n", path); + } + + return NULL; +} diff --git a/js/src/config/mkdepend/main.c b/js/src/config/mkdepend/main.c new file mode 100644 index 0000000..a86866f --- /dev/null +++ b/js/src/config/mkdepend/main.c @@ -0,0 +1,860 @@ +/* $Xorg: main.c,v 1.5 2001/02/09 02:03:16 xorgcvs Exp $ */ +/* + +Copyright (c) 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/* $XFree86: xc/config/makedepend/main.c,v 3.32 2003/03/26 20:43:48 tsi Exp $ */ + +#include "def.h" +#ifdef hpux +#define sigvec sigvector +#endif /* hpux */ + +#ifdef X_POSIX_C_SOURCE +#define _POSIX_C_SOURCE X_POSIX_C_SOURCE +#include +#undef _POSIX_C_SOURCE +#else +#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) +#include +#else +#define _POSIX_SOURCE +#include +#undef _POSIX_SOURCE +#endif +#endif + +#include + +#ifdef MINIX +#define USE_CHMOD 1 +#endif + +#ifdef DEBUG +int _debugmask; +#endif + +/* #define DEBUG_DUMP */ +#ifdef DEBUG_DUMP +#define DBG_PRINT(file, fmt, args) fprintf(file, fmt, args) +#else +#define DBG_PRINT(file, fmt, args) /* empty */ +#endif + +#define DASH_INC_PRE "#include \"" +#define DASH_INC_POST "\"" + +char *ProgramName; + +char *directives[] = { + "if", + "ifdef", + "ifndef", + "else", + "endif", + "define", + "undef", + "include", + "line", + "pragma", + "error", + "ident", + "sccs", + "elif", + "eject", + "warning", + "include_next", + NULL +}; + +#define MAKEDEPEND +#include "imakemdep.h" /* from config sources */ +#undef MAKEDEPEND + +struct inclist inclist[ MAXFILES ], + *inclistp = inclist, + *inclistnext = inclist, + maininclist; + +static char *filelist[ MAXFILES ]; +char *includedirs[ MAXDIRS + 1 ], + **includedirsnext = includedirs; +char *notdotdot[ MAXDIRS ]; +static int cmdinc_count = 0; +static char *cmdinc_list[ 2 * MAXINCFILES ]; +char *objprefix = ""; +char *objsuffix = OBJSUFFIX; +static char *startat = "# DO NOT DELETE"; +int width = 78; +static boolean append = FALSE; +boolean printed = FALSE; +boolean verbose = FALSE; +boolean show_where_not = FALSE; +/* Warn on multiple includes of same file */ +boolean warn_multiple = FALSE; + +static void setfile_cmdinc(struct filepointer *filep, long count, char **list); +static void redirect(char *line, char *makefile); + +static +#ifdef SIGNALRETURNSINT +int +#else +void +#endif +catch (int sig) +{ + fflush (stdout); + fatalerr ("got signal %d\n", sig); +} + +#if defined(USG) || (defined(i386) && defined(SYSV)) || defined(WIN32) || defined(__UNIXOS2__) || defined(Lynx_22) || defined(__CYGWIN__) +#define USGISH +#endif + +#ifndef USGISH +#ifdef X_NOT_POSIX +#define sigaction sigvec +#define sa_handler sv_handler +#define sa_mask sv_mask +#define sa_flags sv_flags +#endif +struct sigaction sig_act; +#endif /* USGISH */ + +int +main(int argc, char *argv[]) +{ + char **fp = filelist; + char **incp = includedirs; + char *p; + struct inclist *ip; + char *makefile = NULL; + struct filepointer *filecontent; + struct symtab *psymp = predefs; + char *endmarker = NULL; + char *defincdir = NULL; + char **undeflist = NULL; + int numundefs = 0, i; + register char offset; + + ProgramName = argv[0]; + + while (psymp->s_name) + { + define2(psymp->s_name, psymp->s_value, &maininclist); + psymp++; + } + if (argc == 2 && argv[1][0] == '@') { + struct stat ast; + int afd; + char *args; + char **nargv; + int nargc; + char quotechar = '\0'; + + nargc = 1; + if ((afd = open(argv[1]+1, O_RDONLY)) < 0) + fatalerr("cannot open \"%s\"\n", argv[1]+1); + fstat(afd, &ast); + args = (char *)malloc(ast.st_size + 1); + if ((ast.st_size = read(afd, args, ast.st_size)) < 0) + fatalerr("failed to read %s\n", argv[1]+1); + args[ast.st_size] = '\0'; + close(afd); + for (p = args; *p; p++) { + if (quotechar) { + if (quotechar == '\\' || + (*p == quotechar && p[-1] != '\\')) + quotechar = '\0'; + continue; + } + switch (*p) { + case '\\': + case '"': + case '\'': + quotechar = *p; + break; + case ' ': + case '\n': + *p = '\0'; + if (p > args && p[-1]) + nargc++; + break; + } + } + if (p[-1]) + nargc++; + nargv = (char **)malloc(nargc * sizeof(char *)); + nargv[0] = argv[0]; + argc = 1; + for (p = args; argc < nargc; p += strlen(p) + 1) + if (*p) nargv[argc++] = p; + argv = nargv; + } + for(argc--, argv++; argc; argc--, argv++) { + /* if looking for endmarker then check before parsing */ + if (endmarker && strcmp (endmarker, *argv) == 0) { + endmarker = NULL; + continue; + } + if (**argv != '-') { + /* treat +thing as an option for C++ */ + if (endmarker && **argv == '+') + continue; + *fp++ = argv[0]; + continue; + } + switch(argv[0][1]) { + case '-': + endmarker = &argv[0][2]; + if (endmarker[0] == '\0') endmarker = "--"; + break; + case 'D': + offset = 2; + if (argv[0][2] == '\0') { + argv++; + argc--; + offset = 0; + } + /* offset +1 here since first def letter + * cannot be `=` + */ + for (p = argv[0] + offset + 1; *p; p++) + if (*p == '=') { + *p = ' '; + break; + } + define(argv[0] + offset, &maininclist); + break; + case 'I': + if (incp >= includedirs + MAXDIRS) + fatalerr("Too many -I flags.\n"); + *incp++ = argv[0]+2; + if (**(incp-1) == '\0') { + *(incp-1) = *(++argv); + argc--; + } + break; + case 'U': + /* Undef's override all -D's so save them up */ + numundefs++; + if (numundefs == 1) + undeflist = malloc(sizeof(char *)); + else + undeflist = realloc(undeflist, + numundefs * sizeof(char *)); + offset = 2; + if (argv[0][2] == '\0') { + argv++; + argc--; + offset = 0; + } + undeflist[numundefs - 1] = argv[0] + offset; + break; + case 'Y': + defincdir = argv[0]+2; + break; + /* do not use if endmarker processing */ + case 'a': + if (endmarker) break; + append = TRUE; + break; + case 'w': + if (endmarker) break; + if (argv[0][2] == '\0') { + argv++; + argc--; + width = atoi(argv[0]); + } else + width = atoi(argv[0]+2); + break; + case 'o': + if (endmarker) break; + if (argv[0][2] == '\0') { + argv++; + argc--; + objsuffix = argv[0]; + } else + objsuffix = argv[0]+2; + break; + case 'p': + if (endmarker) break; + if (argv[0][2] == '\0') { + argv++; + argc--; + objprefix = argv[0]; + } else + objprefix = argv[0]+2; + break; + case 'v': + if (endmarker) break; + verbose = TRUE; +#ifdef DEBUG + if (argv[0][2]) + _debugmask = atoi(argv[0]+2); +#endif + break; + case 's': + if (endmarker) break; + startat = argv[0]+2; + if (*startat == '\0') { + startat = *(++argv); + argc--; + } + if (*startat != '#') + fatalerr("-s flag's value should start %s\n", + "with '#'."); + break; + case 'f': + if (endmarker) break; + makefile = argv[0]+2; + if (*makefile == '\0') { + makefile = *(++argv); + argc--; + } + break; + + case 'm': + warn_multiple = TRUE; + break; + + /* Ignore -O, -g so we can just pass ${CFLAGS} to + makedepend + */ + case 'O': + case 'g': + break; + case 'i': + if (strcmp(&argv[0][1],"include") == 0) { + char *buf; + if (argc<2) + fatalerr("option -include is a " + "missing its parameter\n"); + if (cmdinc_count >= MAXINCFILES) + fatalerr("Too many -include flags.\n"); + argc--; + argv++; + buf = malloc(strlen(DASH_INC_PRE) + + strlen(argv[0]) + + strlen(DASH_INC_POST) + 1); + if(!buf) + fatalerr("out of memory at " + "-include string\n"); + cmdinc_list[2 * cmdinc_count + 0] = argv[0]; + cmdinc_list[2 * cmdinc_count + 1] = buf; + cmdinc_count++; + break; + } + /* intentional fall through */ + default: + if (endmarker) break; + /* fatalerr("unknown opt = %s\n", argv[0]); */ + warning("ignoring option %s\n", argv[0]); + } + } + /* Now do the undefs from the command line */ + for (i = 0; i < numundefs; i++) + undefine(undeflist[i], &maininclist); + if (numundefs > 0) + free(undeflist); + + if (!defincdir) { +#ifdef PREINCDIR + if (incp >= includedirs + MAXDIRS) + fatalerr("Too many -I flags.\n"); + *incp++ = PREINCDIR; +#endif +#ifdef __UNIXOS2__ + { + char *emxinc = getenv("C_INCLUDE_PATH"); + /* can have more than one component */ + if (emxinc) { + char *beg, *end; + beg= (char*)strdup(emxinc); + for (;;) { + end = (char*)strchr(beg,';'); + if (end) *end = 0; + if (incp >= includedirs + MAXDIRS) + fatalerr("Too many include dirs\n"); + *incp++ = beg; + if (!end) break; + beg = end+1; + } + } + } +#else /* !__UNIXOS2__, does not use INCLUDEDIR at all */ + if (incp >= includedirs + MAXDIRS) + fatalerr("Too many -I flags.\n"); + *incp++ = INCLUDEDIR; +#endif + +#ifdef EXTRAINCDIR + if (incp >= includedirs + MAXDIRS) + fatalerr("Too many -I flags.\n"); + *incp++ = EXTRAINCDIR; +#endif + +#ifdef POSTINCDIR + if (incp >= includedirs + MAXDIRS) + fatalerr("Too many -I flags.\n"); + *incp++ = POSTINCDIR; +#endif + } else if (*defincdir) { + if (incp >= includedirs + MAXDIRS) + fatalerr("Too many -I flags.\n"); + *incp++ = defincdir; + } + + redirect(startat, makefile); + + /* + * catch signals. + */ +#ifdef USGISH +/* should really reset SIGINT to SIG_IGN if it was. */ +#ifdef SIGHUP + signal (SIGHUP, catch); +#endif + signal (SIGINT, catch); +#ifdef SIGQUIT + signal (SIGQUIT, catch); +#endif + signal (SIGILL, catch); +#ifdef SIGBUS + signal (SIGBUS, catch); +#endif + signal (SIGSEGV, catch); +#ifdef SIGSYS + signal (SIGSYS, catch); +#endif +#else + sig_act.sa_handler = catch; +#if defined(_POSIX_SOURCE) || !defined(X_NOT_POSIX) + sigemptyset(&sig_act.sa_mask); + sigaddset(&sig_act.sa_mask, SIGINT); + sigaddset(&sig_act.sa_mask, SIGQUIT); +#ifdef SIGBUS + sigaddset(&sig_act.sa_mask, SIGBUS); +#endif + sigaddset(&sig_act.sa_mask, SIGILL); + sigaddset(&sig_act.sa_mask, SIGSEGV); + sigaddset(&sig_act.sa_mask, SIGHUP); + sigaddset(&sig_act.sa_mask, SIGPIPE); +#ifdef SIGSYS + sigaddset(&sig_act.sa_mask, SIGSYS); +#endif +#else + sig_act.sa_mask = ((1<<(SIGINT -1)) + |(1<<(SIGQUIT-1)) +#ifdef SIGBUS + |(1<<(SIGBUS-1)) +#endif + |(1<<(SIGILL-1)) + |(1<<(SIGSEGV-1)) + |(1<<(SIGHUP-1)) + |(1<<(SIGPIPE-1)) +#ifdef SIGSYS + |(1<<(SIGSYS-1)) +#endif + ); +#endif /* _POSIX_SOURCE */ + sig_act.sa_flags = 0; + sigaction(SIGHUP, &sig_act, (struct sigaction *)0); + sigaction(SIGINT, &sig_act, (struct sigaction *)0); + sigaction(SIGQUIT, &sig_act, (struct sigaction *)0); + sigaction(SIGILL, &sig_act, (struct sigaction *)0); +#ifdef SIGBUS + sigaction(SIGBUS, &sig_act, (struct sigaction *)0); +#endif + sigaction(SIGSEGV, &sig_act, (struct sigaction *)0); +#ifdef SIGSYS + sigaction(SIGSYS, &sig_act, (struct sigaction *)0); +#endif +#endif /* USGISH */ + + /* + * now peruse through the list of files. + */ + for(fp=filelist; *fp; fp++) { + DBG_PRINT(stderr,"file: %s\n",*fp); + filecontent = getfile(*fp); + setfile_cmdinc(filecontent, cmdinc_count, cmdinc_list); + ip = newinclude(*fp, (char *)NULL); + + find_includes(filecontent, ip, ip, 0, FALSE); + freefile(filecontent); + recursive_pr_include(ip, ip->i_file, base_name(*fp)); + inc_clean(); + } + if (printed) + printf("\n"); + return 0; +} + +#ifdef __UNIXOS2__ +/* + * eliminate \r chars from file + */ +static int +elim_cr(char *buf, int sz) +{ + int i,wp; + for (i= wp = 0; if_name = file; + if ((fd = open(file, O_RDONLY)) < 0) { + warning("cannot open \"%s\"\n", file); + content->f_p = content->f_base = content->f_end = (char *)malloc(1); + *content->f_p = '\0'; + return(content); + } + fstat(fd, &st); + content->f_base = (char *)malloc(st.st_size+1); + if (content->f_base == NULL) + fatalerr("cannot allocate mem\n"); + if ((st.st_size = read(fd, content->f_base, st.st_size)) < 0) + fatalerr("failed to read %s\n", file); +#ifdef __UNIXOS2__ + st.st_size = elim_cr(content->f_base,st.st_size); +#endif + close(fd); + content->f_len = st.st_size+1; + content->f_p = content->f_base; + content->f_end = content->f_base + st.st_size; + *content->f_end = '\0'; + content->f_line = 0; + content->cmdinc_count = 0; + content->cmdinc_list = NULL; + content->cmdinc_line = 0; + return(content); +} + +void +setfile_cmdinc(struct filepointer* filep, long count, char** list) +{ + filep->cmdinc_count = count; + filep->cmdinc_list = list; + filep->cmdinc_line = 0; +} + +void +freefile(struct filepointer *fp) +{ + free(fp->f_base); + free(fp); +} + +char *copy(char *str) +{ + char *p = (char *)malloc(strlen(str) + 1); + + strcpy(p, str); + return(p); +} + +int +match(char *str, char **list) +{ + int i; + + for (i=0; *list; i++, list++) + if (strcmp(str, *list) == 0) + return(i); + return(-1); +} + +/* + * Get the next line. We only return lines beginning with '#' since that + * is all this program is ever interested in. + */ +char *getnextline(struct filepointer *filep) +{ + char *p, /* walking pointer */ + *eof, /* end of file pointer */ + *bol; /* beginning of line pointer */ + int lineno; /* line number */ + boolean whitespace = FALSE; + + /* + * Fake the "-include" line files in form of #include to the + * start of each file. + */ + if (filep->cmdinc_line < filep->cmdinc_count) { + char *inc = filep->cmdinc_list[2 * filep->cmdinc_line + 0]; + char *buf = filep->cmdinc_list[2 * filep->cmdinc_line + 1]; + filep->cmdinc_line++; + sprintf(buf,"%s%s%s",DASH_INC_PRE,inc,DASH_INC_POST); + DBG_PRINT(stderr,"%s\n",buf); + return(buf); + } + + p = filep->f_p; + eof = filep->f_end; + if (p >= eof) + return((char *)NULL); + lineno = filep->f_line; + + for (bol = p--; ++p < eof; ) { + if ((bol == p) && ((*p == ' ') || (*p == '\t'))) + { + /* Consume leading white-spaces for this line */ + while (((p+1) < eof) && ((*p == ' ') || (*p == '\t'))) + { + p++; + bol++; + } + whitespace = TRUE; + } + + if (*p == '/' && (p+1) < eof && *(p+1) == '*') { + /* Consume C comments */ + *(p++) = ' '; + *(p++) = ' '; + while (p < eof && *p) { + if (*p == '*' && (p+1) < eof && *(p+1) == '/') { + *(p++) = ' '; + *(p++) = ' '; + break; + } + if (*p == '\n') + lineno++; + *(p++) = ' '; + } + --p; + } + else if (*p == '/' && (p+1) < eof && *(p+1) == '/') { + /* Consume C++ comments */ + *(p++) = ' '; + *(p++) = ' '; + while (p < eof && *p) { + if (*p == '\\' && (p+1) < eof && + *(p+1) == '\n') { + *(p++) = ' '; + lineno++; + } + else if (*p == '?' && (p+3) < eof && + *(p+1) == '?' && + *(p+2) == '/' && + *(p+3) == '\n') { + *(p++) = ' '; + *(p++) = ' '; + *(p++) = ' '; + lineno++; + } + else if (*p == '\n') + break; /* to process end of line */ + *(p++) = ' '; + } + --p; + } + else if (*p == '\\' && (p+1) < eof && *(p+1) == '\n') { + /* Consume backslash line terminations */ + *(p++) = ' '; + *p = ' '; + lineno++; + } + else if (*p == '?' && (p+3) < eof && + *(p+1) == '?' && *(p+2) == '/' && *(p+3) == '\n') { + /* Consume trigraph'ed backslash line terminations */ + *(p++) = ' '; + *(p++) = ' '; + *(p++) = ' '; + *p = ' '; + lineno++; + } + else if (*p == '\n') { + lineno++; + if (*bol == '#') { + char *cp; + + *(p++) = '\0'; + /* punt lines with just # (yacc generated) */ + for (cp = bol+1; + *cp && (*cp == ' ' || *cp == '\t'); cp++); + if (*cp) goto done; + --p; + } + bol = p+1; + whitespace = FALSE; + } + } + if (*bol != '#') + bol = NULL; +done: + if (bol && whitespace) { + warning("%s: non-portable whitespace encountered at line %d\n", + filep->f_name, lineno); + } + filep->f_p = p; + filep->f_line = lineno; +#ifdef DEBUG_DUMP + if (bol) + DBG_PRINT(stderr,"%s\n",bol); +#endif + return(bol); +} + +/* + * Strip the file name down to what we want to see in the Makefile. + * It will have objprefix and objsuffix around it. + */ +char *base_name(char *file) +{ + char *p; + + file = copy(file); + for(p=file+strlen(file); p>file && *p != '.'; p--) ; + + if (*p == '.') + *p = '\0'; + return(file); +} + +#if defined(USG) && !defined(CRAY) && !defined(SVR4) && !defined(__UNIXOS2__) && !defined(clipper) && !defined(__clipper__) +int rename (char *from, char *to) +{ + (void) unlink (to); + if (link (from, to) == 0) { + unlink (from); + return 0; + } else { + return -1; + } +} +#endif /* USGISH */ + +void +redirect(char *line, char *makefile) +{ + struct stat st; + FILE *fdin, *fdout; + char backup[ BUFSIZ ], + buf[ BUFSIZ ]; + boolean found = FALSE; + int len; + + /* + * if makefile is "-" then let it pour onto stdout. + */ + if (makefile && *makefile == '-' && *(makefile+1) == '\0') { + puts(line); + return; + } + + /* + * use a default makefile is not specified. + */ + if (!makefile) { + if (stat("Makefile", &st) == 0) + makefile = "Makefile"; + else if (stat("makefile", &st) == 0) + makefile = "makefile"; + else + fatalerr("[mM]akefile is not present\n"); + } + else + stat(makefile, &st); + if ((fdin = fopen(makefile, "r")) == NULL) + fatalerr("cannot open \"%s\"\n", makefile); + sprintf(backup, "%s.bak", makefile); + unlink(backup); +#if defined(WIN32) || defined(__UNIXOS2__) || defined(__CYGWIN__) + fclose(fdin); +#endif + if (rename(makefile, backup) < 0) + fatalerr("cannot rename %s to %s\n", makefile, backup); +#if defined(WIN32) || defined(__UNIXOS2__) || defined(__CYGWIN__) + if ((fdin = fopen(backup, "r")) == NULL) + fatalerr("cannot open \"%s\"\n", backup); +#endif + if ((fdout = freopen(makefile, "w", stdout)) == NULL) + fatalerr("cannot open \"%s\"\n", backup); + len = strlen(line); + while (!found && fgets(buf, BUFSIZ, fdin)) { + if (*buf == '#' && strncmp(line, buf, len) == 0) + found = TRUE; + fputs(buf, fdout); + } + if (!found) { + if (verbose) + warning("Adding new delimiting line \"%s\" and dependencies...\n", + line); + puts(line); /* same as fputs(fdout); but with newline */ + } else if (append) { + while (fgets(buf, BUFSIZ, fdin)) { + fputs(buf, fdout); + } + } + fflush(fdout); +#if defined(USGISH) || defined(_SEQUENT_) || defined(USE_CHMOD) + chmod(makefile, st.st_mode); +#else + fchmod(fileno(fdout), st.st_mode); +#endif /* USGISH */ +} + +void +fatalerr(char *msg, ...) +{ + va_list args; + fprintf(stderr, "%s: error: ", ProgramName); + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + exit (1); +} + +void +warning(char *msg, ...) +{ + va_list args; + fprintf(stderr, "%s: warning: ", ProgramName); + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); +} + +void +warning1(char *msg, ...) +{ + va_list args; + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); +} diff --git a/js/src/config/mkdepend/mkdepend.man b/js/src/config/mkdepend/mkdepend.man new file mode 100644 index 0000000..595c87e --- /dev/null +++ b/js/src/config/mkdepend/mkdepend.man @@ -0,0 +1,382 @@ +.\" $Xorg: mkdepend.man,v 1.5 2001/02/09 02:03:16 xorgcvs Exp $ +.\" Copyright (c) 1993, 1994, 1998 The Open Group +.\" +.\" Permission to use, copy, modify, distribute, and sell this software and its +.\" documentation for any purpose is hereby granted without fee, provided that +.\" the above copyright notice appear in all copies and that both that +.\" copyright notice and this permission notice appear in supporting +.\" documentation. +.\" +.\" The above copyright notice and this permission notice shall be included in +.\" all copies or substantial portions of the Software. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +.\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +.\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +.\" THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +.\" WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +.\" OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +.\" SOFTWARE. +.\" +.\" Except as contained in this notice, the name of The Open Group shall not +.\" be used in advertising or otherwise to promote the sale, use or other +.\" dealing in this Software without prior written authorization from The +.\" Open Group. +.\" +.\" $XFree86: xc/config/makedepend/mkdepend.man,v 1.7 2002/12/14 02:39:45 dawes Exp $ +.\" +.TH MAKEDEPEND 1 __xorgversion__ +.UC 4 +.SH NAME +makedepend \- create dependencies in makefiles +.SH SYNOPSIS +.B makedepend +[ +.BI \-D name\fB=\fPdef +] [ +.BI \-D name +] [ +.BI \-I includedir +] [ +.BI \-Y includedir +] [ +.B \-a +] [ +.BI \-f makefile +] [ +.BI \-include \ file +] [ +.BI \-o objsuffix +] [ +.BI \-p objprefix +] [ +.BI \-s string +] [ +.BI \-w width +] [ +.B \-v +] [ +.B \-m +] [ +\-\^\- +.I otheroptions +\-\^\- +] +.I sourcefile +\&.\|.\|. +.br +.SH DESCRIPTION +The +.B makedepend +program reads each +.I sourcefile +in sequence and parses it like a C-preprocessor, +processing all +.I #include, +.I #define, +.I #undef, +.I #ifdef, +.I #ifndef, +.I #endif, +.I #if, +.I #elif +and +.I #else +directives so that it can correctly tell which +.I #include, +directives would be used in a compilation. +Any +.I #include, +directives can reference files having other +.I #include +directives, and parsing will occur in these files as well. +.PP +Every file that a +.I sourcefile +includes, +directly or indirectly, +is what +.B makedepend +calls a \fIdependency.\fP +These dependencies are then written to a +.I makefile +in such a way that +.B make(1) +will know which object files must be recompiled when a dependency has changed. +.PP +By default, +.B makedepend +places its output in the file named +.I makefile +if it exists, otherwise +.I Makefile. +An alternate makefile may be specified with the +.B \-f +option. +It first searches the makefile for +the line +.sp +\& # DO NOT DELETE THIS LINE \-\^\- make depend depends on it. +.sp +or one provided with the +.B \-s +option, +as a delimiter for the dependency output. +If it finds it, it will delete everything +following this to the end of the makefile +and put the output after this line. +If it doesn't find it, the program +will append the string to the end of the makefile +and place the output following that. +For each +.I sourcefile +appearing on the command line, +.B makedepend +puts lines in the makefile of the form +.sp + sourcefile.o:\0dfile .\|.\|. +.sp +Where \fIsourcefile.o\fP is the name from the command +line with its suffix replaced with ``.o'', +and \fIdfile\fP is a dependency discovered in a +.I #include +directive while parsing +.I sourcefile +or one of the files it included. +.SH EXAMPLE +Normally, +.B makedepend +will be used in a makefile target so that typing ``make depend'' will +bring the dependencies up to date for the makefile. +For example, +.nf + SRCS\0=\0file1.c\0file2.c\0.\|.\|. + CFLAGS\0=\0\-O\0\-DHACK\0\-I\^.\^.\^/foobar\0\-xyz + depend: + makedepend\0\-\^\-\0$(CFLAGS)\0\-\^\-\0$(SRCS) +.fi +.SH OPTIONS +The program +will ignore any option that it does not understand so that you may use +the same arguments that you would for +.B cc(1). +.TP 5 +.B \-D\fIname\fP=\fIdef\fP \fRor\fP \-D\fIname\fP +Define. +This places a definition for +.I name +in +.B makedepend's +symbol table. +Without +.I =def\| +the symbol becomes defined as ``1''. +.TP 5 +.B \-I\fIincludedir\fP +Include directory. +This option tells +.B makedepend +to prepend +.I includedir +to its list of directories to search when it encounters +a +.I #include +directive. +By default, +.B makedepend +only searches the standard include directories (usually /usr/include +and possibly a compiler-dependent directory). +.TP 5 +.B \-Y\fIincludedir\fP +Replace all of the standard include directories with the single specified +include directory; you can omit the +.I includedir +to simply prevent searching the standard include directories. +.TP 5 +.B \-a +Append the dependencies to the end of the file instead of replacing them. +.TP 5 +.B \-f\fImakefile\fP +Filename. +This allows you to specify an alternate makefile in which +.B makedepend +can place its output. +Specifying ``\-'' as the file name (i.e., \fB\-f\-\fP) sends the +output to standard output instead of modifying an existing file. +.TP 5 +.B \-include \fIfile\fP +Process file as input, and include all the resulting output +before processing the regular input file. This has the same +affect as if the specified file is an include statement that +appears before the very first line of the regular input file. +.TP 5 +.B \-o\fIobjsuffix\fP +Object file suffix. +Some systems may have object files whose suffix is something other +than ``.o''. +This option allows you to specify another suffix, such as +``.b'' with +.I \-o.b +or ``:obj'' +with +.I \-o:obj +and so forth. +.TP 5 +.B \-p\fIobjprefix\fP +Object file prefix. +The prefix is prepended to the name of the object file. This is +usually used to designate a different directory for the object file. +The default is the empty string. +.TP 5 +.B \-s\fIstring\fP +Starting string delimiter. +This option permits you to specify +a different string for +.B makedepend +to look for in the makefile. +.TP 5 +.B \-w\fIwidth\fP +Line width. +Normally, +.B makedepend +will ensure that every output line that it writes will be no wider than +78 characters for the sake of readability. +This option enables you to change this width. +.TP 5 +.B \-v +Verbose operation. +This option causes +.B makedepend +to emit the list of files included by each input file. +.TP 5 +.B \-m +Warn about multiple inclusion. +This option causes +.B makedepend +to produce a warning if any input file includes another file more than +once. In previous versions of +.B makedepend +this was the default behavior; the default has been changed to better +match the behavior of the C compiler, which does not consider multiple +inclusion to be an error. This option is provided for backward +compatibility, and to aid in debugging problems related to multiple +inclusion. +.TP 5 +.B "\-\^\- \fIoptions\fP \-\^\-" +If +.B makedepend +encounters a double hyphen (\-\^\-) in the argument list, +then any unrecognized argument following it +will be silently ignored; a second double hyphen terminates this +special treatment. +In this way, +.B makedepend +can be made to safely ignore esoteric compiler arguments that might +normally be found in a CFLAGS +.B make +macro (see the +.B EXAMPLE +section above). +All options that +.B makedepend +recognizes and appear between the pair of double hyphens +are processed normally. +.SH ALGORITHM +The approach used in this program enables it to run an order of magnitude +faster than any other ``dependency generator'' I have ever seen. +Central to this performance are two assumptions: +that all files compiled by a single +makefile will be compiled with roughly the same +.I \-I +and +.I \-D +options; +and that most files in a single directory will include largely the +same files. +.PP +Given these assumptions, +.B makedepend +expects to be called once for each makefile, with +all source files that are maintained by the +makefile appearing on the command line. +It parses each source and include +file exactly once, maintaining an internal symbol table +for each. +Thus, the first file on the command line will take an amount of time +proportional to the amount of time that a normal C preprocessor takes. +But on subsequent files, if it encounters an include file +that it has already parsed, it does not parse it again. +.PP +For example, +imagine you are compiling two files, +.I file1.c +and +.I file2.c, +they each include the header file +.I header.h, +and the file +.I header.h +in turn includes the files +.I def1.h +and +.I def2.h. +When you run the command +.sp + makedepend\0file1.c\0file2.c +.sp +.B makedepend +will parse +.I file1.c +and consequently, +.I header.h +and then +.I def1.h +and +.I def2.h. +It then decides that the dependencies for this file are +.sp + file1.o:\0header.h\0def1.h\0def2.h +.sp +But when the program parses +.I file2.c +and discovers that it, too, includes +.I header.h, +it does not parse the file, +but simply adds +.I header.h, +.I def1.h +and +.I def2.h +to the list of dependencies for +.I file2.o. +.SH "SEE ALSO" +cc(1), make(1) +.SH BUGS +.B makedepend +parses, but does not currently evaluate, the SVR4 #predicate(token-list) +preprocessor expression; such expressions are simply assumed to be true. +This may cause the wrong +.I #include +directives to be evaluated. +.PP +Imagine you are parsing two files, +say +.I file1.c +and +.I file2.c, +each includes the file +.I def.h. +The list of files that +.I def.h +includes might truly be different when +.I def.h +is included by +.I file1.c +than when it is included by +.I file2.c. +But once +.B makedepend +arrives at a list of dependencies for a file, +it is cast in concrete. +.SH AUTHOR +Todd Brunhoff, Tektronix, Inc. and MIT Project Athena diff --git a/js/src/config/mkdepend/parse.c b/js/src/config/mkdepend/parse.c new file mode 100644 index 0000000..968d2c4 --- /dev/null +++ b/js/src/config/mkdepend/parse.c @@ -0,0 +1,686 @@ +/* $Xorg: parse.c,v 1.6 2001/02/09 02:03:16 xorgcvs Exp $ */ +/* + +Copyright (c) 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/* $XFree86: xc/config/makedepend/parse.c,v 1.12 2002/02/26 05:09:10 tsi Exp $ */ + +#include "def.h" + +extern char *directives[]; +extern struct inclist inclist[ MAXFILES ], + *inclistnext, + maininclist; +extern char *includedirs[ ], + **includedirsnext; + +static int deftype (char *line, struct filepointer *filep, + struct inclist *file_red, struct inclist *file, + int parse_it); +static int zero_value(char *filename, char *exp, struct filepointer *filep, + struct inclist *file_red); +static int merge2defines(struct inclist *file1, struct inclist *file2); + +static int +gobble(struct filepointer *filep, struct inclist *file, + struct inclist *file_red) +{ + char *line; + int type; + + while ((line = getnextline(filep))) { + switch(type = deftype(line, filep, file_red, file, FALSE)) { + case IF: + case IFFALSE: + case IFGUESSFALSE: + case IFDEF: + case IFNDEF: + type = gobble(filep, file, file_red); + while ((type == ELIF) || (type == ELIFFALSE) || + (type == ELIFGUESSFALSE)) + type = gobble(filep, file, file_red); + if (type == ELSE) + (void)gobble(filep, file, file_red); + break; + case ELSE: + case ENDIF: + debug(0,("%s, line %d: #%s\n", + file->i_file, filep->f_line, + directives[type])); + return(type); + case DEFINE: + case UNDEF: + case INCLUDE: + case INCLUDEDOT: + case PRAGMA: + case ERROR: + case IDENT: + case SCCS: + case EJECT: + case WARNING: + case INCLUDENEXT: + case INCLUDENEXTDOT: + break; + case ELIF: + case ELIFFALSE: + case ELIFGUESSFALSE: + return(type); + case -1: + warning("%s", file_red->i_file); + if (file_red != file) + warning1(" (reading %s)", file->i_file); + warning1(", line %d: unknown directive == \"%s\"\n", + filep->f_line, line); + break; + } + } + return(-1); +} + +/* + * Decide what type of # directive this line is. + */ +static int +deftype (char *line, struct filepointer *filep, + struct inclist *file_red, struct inclist *file, int parse_it) +{ + register char *p; + char *directive, savechar, *q; + register int ret; + + /* + * Parse the directive... + */ + directive=line+1; + while (*directive == ' ' || *directive == '\t') + directive++; + + p = directive; + while ((*p == '_') || (*p >= 'a' && *p <= 'z')) + p++; + savechar = *p; + *p = '\0'; + ret = match(directive, directives); + *p = savechar; + + /* If we don't recognize this compiler directive or we happen to just + * be gobbling up text while waiting for an #endif or #elif or #else + * in the case of an #elif we must check the zero_value and return an + * ELIF or an ELIFFALSE. + */ + + if (ret == ELIF && !parse_it) + { + while (*p == ' ' || *p == '\t') + p++; + /* + * parse an expression. + */ + debug(0,("%s, line %d: #elif %s ", + file->i_file, filep->f_line, p)); + ret = zero_value(file->i_file, p, filep, file_red); + if (ret != IF) + { + debug(0,("false...\n")); + if (ret == IFFALSE) + return(ELIFFALSE); + else + return(ELIFGUESSFALSE); + } + else + { + debug(0,("true...\n")); + return(ELIF); + } + } + + if (ret < 0 || ! parse_it) + return(ret); + + /* + * now decide how to parse the directive, and do it. + */ + while (*p == ' ' || *p == '\t') + p++; + q = p + strlen(p); + do { + q--; + } while (*q == ' ' || *q == '\t'); + q[1] = '\0'; + switch (ret) { + case IF: + /* + * parse an expression. + */ + ret = zero_value(file->i_file, p, filep, file_red); + debug(0,("%s, line %d: %s #if %s\n", + file->i_file, filep->f_line, ret?"false":"true", p)); + break; + case IFDEF: + case IFNDEF: + debug(0,("%s, line %d: #%s %s\n", + file->i_file, filep->f_line, directives[ret], p)); + case UNDEF: + /* + * separate the name of a single symbol. + */ + while (isalnum(*p) || *p == '_') + *line++ = *p++; + *line = '\0'; + break; + case INCLUDE: + case INCLUDENEXT: + debug(2,("%s, line %d: #include%s %s\n", + file->i_file, filep->f_line, + (ret == INCLUDE) ? "" : "_next", p)); + + /* Support ANSI macro substitution */ + while (1) { + struct symtab **sym; + + if (!*p || *p == '"' || *p == '<') + break; + + sym = isdefined(p, file_red, NULL); + if (!sym) + break; + + p = (*sym)->s_value; + debug(3,("%s : #includes SYMBOL %s = %s\n", + file->i_incstring, + (*sym) -> s_name, + (*sym) -> s_value)); + /* mark file as having included a 'soft include' */ + file->i_flags |= INCLUDED_SYM; + } + + /* + * Separate the name of the include file. + */ + while (*p && *p != '"' && *p != '<') + p++; + if (! *p) + return(-2); + if (*p++ == '"') { + if (ret == INCLUDE) + ret = INCLUDEDOT; + else + ret = INCLUDENEXTDOT; + while (*p && *p != '"') + *line++ = *p++; + } else + while (*p && *p != '>') + *line++ = *p++; + *line = '\0'; + break; + case DEFINE: + /* + * copy the definition back to the beginning of the line. + */ + strcpy (line, p); + break; + case ELSE: + case ENDIF: + case ELIF: + case PRAGMA: + case ERROR: + case IDENT: + case SCCS: + case EJECT: + case WARNING: + debug(0,("%s, line %d: #%s\n", + file->i_file, filep->f_line, directives[ret])); + /* + * nothing to do. + */ + break; + } + return(ret); +} + +struct symtab ** +fdefined(char *symbol, struct inclist *file, struct inclist **srcfile) +{ + struct inclist **ip; + struct symtab **val; + int i; + static int recurse_lvl = 0; + + if (file->i_flags & DEFCHECKED) + return(NULL); + debug(2,("Looking for %s in %s\n", symbol, file->i_file)); + file->i_flags |= DEFCHECKED; + if ((val = slookup(symbol, file))) + debug(1,("%s defined in %s as %s\n", + symbol, file->i_file, (*val)->s_value)); + if (val == NULL && file->i_list) + { + for (ip = file->i_list, i=0; i < file->i_listlen; i++, ip++) + if (file->i_merged[i]==FALSE) { + val = fdefined(symbol, *ip, srcfile); + file->i_merged[i]=merge2defines(file,*ip); + if (val!=NULL) break; + } + } + else if (val != NULL && srcfile != NULL) *srcfile = file; + recurse_lvl--; + file->i_flags &= ~DEFCHECKED; + + return(val); +} + +struct symtab ** +isdefined(char *symbol, struct inclist *file, struct inclist **srcfile) +{ + struct symtab **val; + + if ((val = slookup(symbol, &maininclist))) { + debug(1,("%s defined on command line\n", symbol)); + if (srcfile != NULL) *srcfile = &maininclist; + return(val); + } + if ((val = fdefined(symbol, file, srcfile))) + return(val); + debug(1,("%s not defined in %s\n", symbol, file->i_file)); + return(NULL); +} + +/* + * Return type based on if the #if expression evaluates to 0 + */ +static int +zero_value(char *filename, + char *exp, + struct filepointer *filep, + struct inclist *file_red) +{ + if (cppsetup(filename, exp, filep, file_red)) + return(IFFALSE); + else + return(IF); +} + +void +define2(char *name, char *val, struct inclist *file) +{ + int first, last, below; + register struct symtab **sp = NULL, **dest; + struct symtab *stab; + + /* Make space if it's needed */ + if (file->i_defs == NULL) + { + file->i_defs = (struct symtab **) + malloc(sizeof (struct symtab*) * SYMTABINC); + file->i_ndefs = 0; + } + else if (!(file->i_ndefs % SYMTABINC)) + file->i_defs = (struct symtab **) + realloc(file->i_defs, + sizeof(struct symtab*)*(file->i_ndefs+SYMTABINC)); + + if (file->i_defs == NULL) + fatalerr("malloc()/realloc() failure in insert_defn()\n"); + + below = first = 0; + last = file->i_ndefs - 1; + while (last >= first) + { + /* Fast inline binary search */ + register char *s1; + register char *s2; + register int middle = (first + last) / 2; + + /* Fast inline strchr() */ + s1 = name; + s2 = file->i_defs[middle]->s_name; + while (*s1++ == *s2++) + if (s2[-1] == '\0') break; + + /* If exact match, set sp and break */ + if (*--s1 == *--s2) + { + sp = file->i_defs + middle; + break; + } + + /* If name > i_defs[middle] ... */ + if (*s1 > *s2) + { + below = first; + first = middle + 1; + } + /* else ... */ + else + { + below = last = middle - 1; + } + } + + /* Search is done. If we found an exact match to the symbol name, + just replace its s_value */ + if (sp != NULL) + { + debug(1,("redefining %s from %s to %s in file %s\n", + name, (*sp)->s_value, val, file->i_file)); + free((*sp)->s_value); + (*sp)->s_value = copy(val); + return; + } + + sp = file->i_defs + file->i_ndefs++; + dest = file->i_defs + below + 1; + while (sp > dest) + { + *sp = sp[-1]; + sp--; + } + stab = (struct symtab *) malloc(sizeof (struct symtab)); + if (stab == NULL) + fatalerr("malloc()/realloc() failure in insert_defn()\n"); + + debug(1,("defining %s to %s in file %s\n", name, val, file->i_file)); + stab->s_name = copy(name); + stab->s_value = copy(val); + *sp = stab; +} + +void +define(char *def, struct inclist *file) +{ + char *val; + + /* Separate symbol name and its value */ + val = def; + while (isalnum(*val) || *val == '_') + val++; + if (*val) + *val++ = '\0'; + while (*val == ' ' || *val == '\t') + val++; + + if (!*val) + val = "1"; + define2(def, val, file); +} + +struct symtab ** +slookup(char *symbol, struct inclist *file) +{ + register int first = 0; + register int last = file->i_ndefs - 1; + + if (file) while (last >= first) + { + /* Fast inline binary search */ + register char *s1; + register char *s2; + register int middle = (first + last) / 2; + + /* Fast inline strchr() */ + s1 = symbol; + s2 = file->i_defs[middle]->s_name; + while (*s1++ == *s2++) + if (s2[-1] == '\0') break; + + /* If exact match, we're done */ + if (*--s1 == *--s2) + { + return file->i_defs + middle; + } + + /* If symbol > i_defs[middle] ... */ + if (*s1 > *s2) + { + first = middle + 1; + } + /* else ... */ + else + { + last = middle - 1; + } + } + return(NULL); +} + +static int +merge2defines(struct inclist *file1, struct inclist *file2) +{ + int i; + + if ((file1==NULL) || (file2==NULL) || + !(file2->i_flags & FINISHED)) + return 0; + + for (i=0; i < file2->i_listlen; i++) + if (file2->i_merged[i]==FALSE) + return 0; + + { + int first1 = 0; + int last1 = file1->i_ndefs - 1; + + int first2 = 0; + int last2 = file2->i_ndefs - 1; + + int first=0; + struct symtab** i_defs = NULL; + int deflen=file1->i_ndefs+file2->i_ndefs; + + debug(2,("merging %s into %s\n", + file2->i_file, file1->i_file)); + + if (deflen>0) + { + /* make sure deflen % SYMTABINC == 0 is still true */ + deflen += (SYMTABINC - deflen % SYMTABINC) % SYMTABINC; + i_defs=(struct symtab**) + malloc(deflen*sizeof(struct symtab*)); + if (i_defs==NULL) return 0; + } + + while ((last1 >= first1) && (last2 >= first2)) + { + char *s1=file1->i_defs[first1]->s_name; + char *s2=file2->i_defs[first2]->s_name; + + if (strcmp(s1,s2) < 0) + i_defs[first++]=file1->i_defs[first1++]; + else if (strcmp(s1,s2) > 0) + i_defs[first++]=file2->i_defs[first2++]; + else /* equal */ + { + i_defs[first++]=file2->i_defs[first2++]; + first1++; + } + } + while (last1 >= first1) + { + i_defs[first++]=file1->i_defs[first1++]; + } + while (last2 >= first2) + { + i_defs[first++]=file2->i_defs[first2++]; + } + + if (file1->i_defs) free(file1->i_defs); + file1->i_defs=i_defs; + file1->i_ndefs=first; + + return 1; + } +} + +void +undefine(char *symbol, struct inclist *file) +{ + register struct symtab **ptr; + struct inclist *srcfile; + while ((ptr = isdefined(symbol, file, &srcfile)) != NULL) + { + srcfile->i_ndefs--; + for (; ptr < srcfile->i_defs + srcfile->i_ndefs; ptr++) + *ptr = ptr[1]; + } +} + +int +find_includes(struct filepointer *filep, struct inclist *file, + struct inclist *file_red, int recursion, boolean failOK) +{ + struct inclist *inclistp; + char **includedirsp; + register char *line; + register int type; + boolean recfailOK; + + while ((line = getnextline(filep))) { + switch(type = deftype(line, filep, file_red, file, TRUE)) { + case IF: + doif: + type = find_includes(filep, file, + file_red, recursion+1, failOK); + while ((type == ELIF) || (type == ELIFFALSE) || + (type == ELIFGUESSFALSE)) + type = gobble(filep, file, file_red); + if (type == ELSE) + gobble(filep, file, file_red); + break; + case IFFALSE: + case IFGUESSFALSE: + doiffalse: + if (type == IFGUESSFALSE || type == ELIFGUESSFALSE) + recfailOK = TRUE; + else + recfailOK = failOK; + type = gobble(filep, file, file_red); + if (type == ELSE) + find_includes(filep, file, + file_red, recursion+1, recfailOK); + else + if (type == ELIF) + goto doif; + else + if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE)) + goto doiffalse; + break; + case IFDEF: + case IFNDEF: + if ((type == IFDEF && isdefined(line, file_red, NULL)) + || (type == IFNDEF && !isdefined(line, file_red, NULL))) { + debug(1,(type == IFNDEF ? + "line %d: %s !def'd in %s via %s%s\n" : "", + filep->f_line, line, + file->i_file, file_red->i_file, ": doit")); + type = find_includes(filep, file, + file_red, recursion+1, failOK); + while (type == ELIF || type == ELIFFALSE || type == ELIFGUESSFALSE) + type = gobble(filep, file, file_red); + if (type == ELSE) + gobble(filep, file, file_red); + } + else { + debug(1,(type == IFDEF ? + "line %d: %s !def'd in %s via %s%s\n" : "", + filep->f_line, line, + file->i_file, file_red->i_file, ": gobble")); + type = gobble(filep, file, file_red); + if (type == ELSE) + find_includes(filep, file, + file_red, recursion+1, failOK); + else if (type == ELIF) + goto doif; + else if (type == ELIFFALSE || type == ELIFGUESSFALSE) + goto doiffalse; + } + break; + case ELSE: + case ELIFFALSE: + case ELIFGUESSFALSE: + case ELIF: + if (!recursion) + gobble(filep, file, file_red); + case ENDIF: + if (recursion) + return(type); + case DEFINE: + define(line, file); + break; + case UNDEF: + if (!*line) { + warning("%s", file_red->i_file); + if (file_red != file) + warning1(" (reading %s)", file->i_file); + warning1(", line %d: incomplete undef == \"%s\"\n", + filep->f_line, line); + break; + } + undefine(line, file_red); + break; + case INCLUDE: + case INCLUDEDOT: + case INCLUDENEXT: + case INCLUDENEXTDOT: + inclistp = inclistnext; + includedirsp = includedirsnext; + debug(2,("%s, reading %s, includes %s\n", + file_red->i_file, file->i_file, line)); + add_include(filep, file, file_red, line, type, failOK); + inclistnext = inclistp; + includedirsnext = includedirsp; + break; + case ERROR: + case WARNING: + warning("%s", file_red->i_file); + if (file_red != file) + warning1(" (reading %s)", file->i_file); + warning1(", line %d: %s\n", + filep->f_line, line); + break; + + case PRAGMA: + case IDENT: + case SCCS: + case EJECT: + break; + case -1: + warning("%s", file_red->i_file); + if (file_red != file) + warning1(" (reading %s)", file->i_file); + warning1(", line %d: unknown directive == \"%s\"\n", + filep->f_line, line); + break; + case -2: + warning("%s", file_red->i_file); + if (file_red != file) + warning1(" (reading %s)", file->i_file); + warning1(", line %d: incomplete include == \"%s\"\n", + filep->f_line, line); + break; + } + } + file->i_flags |= FINISHED; + debug(2,("finished with %s\n", file->i_file)); + return(-1); +} diff --git a/js/src/config/mkdepend/pr.c b/js/src/config/mkdepend/pr.c new file mode 100644 index 0000000..e864793 --- /dev/null +++ b/js/src/config/mkdepend/pr.c @@ -0,0 +1,124 @@ +/* $Xorg: pr.c,v 1.4 2001/02/09 02:03:16 xorgcvs Exp $ */ +/* + +Copyright (c) 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/* $XFree86: xc/config/makedepend/pr.c,v 1.5 2001/12/14 19:53:21 dawes Exp $ */ + +#include "def.h" + +extern struct inclist inclist[ MAXFILES ], + *inclistp; +extern char *objprefix; +extern char *objsuffix; +extern int width; +extern boolean printed; +extern boolean verbose; +extern boolean show_where_not; + +void +add_include(struct filepointer *filep, struct inclist *file, + struct inclist *file_red, char *include, int type, + boolean failOK) +{ + register struct inclist *newfile; + register struct filepointer *content; + + /* + * First decide what the pathname of this include file really is. + */ + newfile = inc_path(file->i_file, include, type); + if (newfile == NULL) { + if (failOK) + return; + if (file != file_red) + warning("%s (reading %s, line %d): ", + file_red->i_file, file->i_file, filep->f_line); + else + warning("%s, line %d: ", file->i_file, filep->f_line); + warning1("cannot find include file \"%s\"\n", include); + show_where_not = TRUE; + newfile = inc_path(file->i_file, include, type); + show_where_not = FALSE; + } + + if (newfile) { + included_by(file, newfile); + if (!(newfile->i_flags & SEARCHED)) { + newfile->i_flags |= SEARCHED; + content = getfile(newfile->i_file); + find_includes(content, newfile, file_red, 0, failOK); + freefile(content); + } + } +} + +static void +pr(struct inclist *ip, char *file, char *base) +{ + static char *lastfile; + static int current_len; + register int len, i; + char buf[ BUFSIZ ]; + + printed = TRUE; + len = strlen(ip->i_file)+1; + if (current_len + len > width || file != lastfile) { + lastfile = file; + sprintf(buf, "\n%s%s%s: %s", objprefix, base, objsuffix, + ip->i_file); + len = current_len = strlen(buf); + } + else { + buf[0] = ' '; + strcpy(buf+1, ip->i_file); + current_len += len; + } + fwrite(buf, len, 1, stdout); + + /* + * If verbose is set, then print out what this file includes. + */ + if (! verbose || ip->i_list == NULL || ip->i_flags & NOTIFIED) + return; + ip->i_flags |= NOTIFIED; + lastfile = NULL; + printf("\n# %s includes:", ip->i_file); + for (i=0; ii_listlen; i++) + printf("\n#\t%s", ip->i_list[ i ]->i_incstring); +} + +void +recursive_pr_include(struct inclist *head, char *file, char *base) +{ + int i; + + if (head->i_flags & MARKED) + return; + head->i_flags |= MARKED; + if (head->i_file != file) + pr(head, file, base); + for (i=0; ii_listlen; i++) + recursive_pr_include(head->i_list[ i ], file, base); +} diff --git a/js/src/config/nfspwd.pl b/js/src/config/nfspwd.pl new file mode 100644 index 0000000..2f0e4fb --- /dev/null +++ b/js/src/config/nfspwd.pl @@ -0,0 +1,50 @@ +#! perl +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +require "fastcwd.pl"; + +$_ = &fastcwd; +if (m@^/[uh]/@o || s@^/tmp_mnt/@/@o) { + print("$_\n"); +} elsif ((($user, $rest) = m@^/usr/people/(\w+)/(.*)@o) + && readlink("/u/$user") eq "/usr/people/$user") { + print("/u/$user/$rest\n"); +} else { + chop($host = `hostname`); + print("/h/$host$_\n"); +} diff --git a/js/src/config/nsinstall.c b/js/src/config/nsinstall.c new file mode 100644 index 0000000..355a092 --- /dev/null +++ b/js/src/config/nsinstall.c @@ -0,0 +1,487 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* +** Netscape portable install command. +** +** Brendan Eich, 7/20/95 +*/ +#include /* OSF/1 requires this before grp.h, so put it first */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pathsub.h" + +#ifdef HAVE_GETOPT_H +#include +#endif + +#ifdef SUNOS4 +#include "sunos4.h" +#endif + +#ifdef NEXTSTEP +#include +#endif + +#ifdef __QNX__ +#include +#endif + +#ifdef NEED_S_ISLNK +#if !defined(S_ISLNK) && defined(S_IFLNK) +#define S_ISLNK(a) (((a) & S_IFMT) == S_IFLNK) +#endif +#endif + +#ifndef _DIRECTORY_SEPARATOR +#define _DIRECTORY_SEPARATOR "/" +#endif /* _DIRECTORY_SEPARATOR */ + +#ifdef NEED_FCHMOD_PROTO +extern int fchmod(int fildes, mode_t mode); +#endif + +static void +usage(void) +{ + fprintf(stderr, + "usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n" + " %*s [-DdltR] file [file ...] directory\n", + program, (int) strlen(program), ""); + exit(2); +} + +static int +mkdirs(char *path, mode_t mode) +{ + char *cp; + struct stat sb; + int res; + int l; + + /* strip trailing "/." */ + l = strlen(path); + if(l > 1 && path[l - 1] == '.' && path[l - 2] == '/') + path[l - 2] = 0; + + while (*path == '/' && path[1] == '/') + path++; + for (cp = strrchr(path, '/'); cp && cp != path && *(cp - 1) == '/'; cp--); + if (cp && cp != path) { + *cp = '\0'; + if ((lstat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) && + mkdirs(path, mode) < 0) { + return -1; + } + *cp = '/'; + } + + res = mkdir(path, mode); + if ((res != 0) && (errno == EEXIST)) + return 0; + else + return res; +} + +static uid_t +touid(char *owner) +{ + struct passwd *pw; + uid_t uid; + char *cp; + + pw = getpwnam(owner); + if (pw) + return pw->pw_uid; + uid = strtol(owner, &cp, 0); + if (uid == 0 && cp == owner) + fail("cannot find uid for %s", owner); + return uid; +} + +static gid_t +togid(char *group) +{ + struct group *gr; + gid_t gid; + char *cp; + + gr = getgrnam(group); + if (gr) + return gr->gr_gid; + gid = strtol(group, &cp, 0); + if (gid == 0 && cp == group) + fail("cannot find gid for %s", group); + return gid; +} + +static void +copyfile( char *name, char *toname, mode_t mode, char *group, char *owner, + int dotimes, uid_t uid, gid_t gid ) +{ + int fromfd, tofd = -1, cc, wc, exists; + char buf[BUFSIZ], *bp; + struct stat sb, tosb; + struct utimbuf utb; + + exists = (lstat(toname, &tosb) == 0); + + fromfd = open(name, O_RDONLY); + if (fromfd < 0 || fstat(fromfd, &sb) < 0) + fail("cannot access %s", name); + if (exists) { + if (S_ISREG(tosb.st_mode)) { + /* See if we can open it. This is more reliable than 'access'. */ + tofd = open(toname, O_CREAT | O_WRONLY, 0666); + } + if (tofd < 0) { + (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); + } + } + if (tofd < 0) { + tofd = open(toname, O_CREAT | O_WRONLY, 0666); + if (tofd < 0) + fail("cannot create %s", toname); + } + + bp = buf; + while ((cc = read(fromfd, bp, sizeof buf)) > 0) + { + while ((wc = write(tofd, bp, (unsigned int)cc)) > 0) + { + if ((cc -= wc) == 0) + break; + bp += wc; + } + if (wc < 0) + fail("cannot write to %s", toname); + } + if (cc < 0) + fail("cannot read from %s", name); + + if (ftruncate(tofd, sb.st_size) < 0) + fail("cannot truncate %s", toname); +#if !defined(VMS) + if (dotimes) + { + utb.actime = sb.st_atime; + utb.modtime = sb.st_mtime; + if (utime(toname, &utb) < 0) + fail("cannot set times of %s", toname); + } +#ifdef HAVE_FCHMOD + if (fchmod(tofd, mode) < 0) +#else + if (chmod(toname, mode) < 0) +#endif + fail("cannot change mode of %s", toname); +#endif + if ((owner || group) && fchown(tofd, uid, gid) < 0) + fail("cannot change owner of %s", toname); + + /* Must check for delayed (NFS) write errors on close. */ + if (close(tofd) < 0) + fail("cannot write to %s", toname); + close(fromfd); +#if defined(VMS) + if (chmod(toname, (mode & (S_IREAD | S_IWRITE))) < 0) + fail("cannot change mode of %s", toname); + if (dotimes) + { + utb.actime = sb.st_atime; + utb.modtime = sb.st_mtime; + if (utime(toname, &utb) < 0) + fail("cannot set times of %s", toname); + } +#endif +} + +static void +copydir( char *from, char *to, mode_t mode, char *group, char *owner, + int dotimes, uid_t uid, gid_t gid) +{ + int i; + DIR *dir; + struct dirent *ep; + struct stat sb; + char *base, *destdir, *direntry, *destentry; + + base = xbasename(from); + + /* create destination directory */ + destdir = xmalloc((unsigned int)(strlen(to) + 1 + strlen(base) + 1)); + sprintf(destdir, "%s%s%s", to, _DIRECTORY_SEPARATOR, base); + if (mkdirs(destdir, mode) != 0) { + fail("cannot make directory %s\n", destdir); + free(destdir); + return; + } + + if (!(dir = opendir(from))) { + fail("cannot open directory %s\n", from); + free(destdir); + return; + } + + direntry = xmalloc((unsigned int)PATH_MAX); + destentry = xmalloc((unsigned int)PATH_MAX); + + while ((ep = readdir(dir))) + { + if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0) + continue; + + sprintf(direntry, "%s/%s", from, ep->d_name); + sprintf(destentry, "%s%s%s", destdir, _DIRECTORY_SEPARATOR, ep->d_name); + + if (stat(direntry, &sb) == 0 && S_ISDIR(sb.st_mode)) + copydir( direntry, destdir, mode, group, owner, dotimes, uid, gid ); + else + copyfile( direntry, destentry, mode, group, owner, dotimes, uid, gid ); + } + + free(destdir); + free(direntry); + free(destentry); + closedir(dir); +} + +int +main(int argc, char **argv) +{ + int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc; + mode_t mode = 0755; + char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, *bp, buf[BUFSIZ]; + uid_t uid; + gid_t gid; + struct stat sb, tosb, fromsb; + struct utimbuf utb; + + program = argv[0]; + cwd = linkname = linkprefix = owner = group = 0; + onlydir = dodir = dolink = dorelsymlink = dotimes = lplen = 0; + + while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) { + switch (opt) { + case 'C': + cwd = optarg; + break; + case 'D': + onlydir = 1; + break; + case 'd': + dodir = 1; + break; + case 'l': + dolink = 1; + break; + case 'L': + linkprefix = optarg; + lplen = strlen(linkprefix); + dolink = 1; + break; + case 'R': + dolink = dorelsymlink = 1; + break; + case 'm': + mode = strtoul(optarg, &cp, 8); + if (mode == 0 && cp == optarg) + usage(); + break; + case 'o': + owner = optarg; + break; + case 'g': + group = optarg; + break; + case 't': + dotimes = 1; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc < 2 - onlydir) + usage(); + + todir = argv[argc-1]; + if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) && + mkdirs(todir, 0777) < 0) { + fail("cannot make directory %s", todir); + } + if (onlydir) + return 0; + + if (!cwd) { +#ifndef NEEDS_GETCWD +#ifndef GETCWD_CANT_MALLOC + cwd = getcwd(0, PATH_MAX); +#else + cwd = malloc(PATH_MAX + 1); + cwd = getcwd(cwd, PATH_MAX); +#endif +#else + cwd = malloc(PATH_MAX + 1); + cwd = getwd(cwd); +#endif + } + + xchdir(todir); +#ifndef NEEDS_GETCWD +#ifndef GETCWD_CANT_MALLOC + todir = getcwd(0, PATH_MAX); +#else + todir = malloc(PATH_MAX + 1); + todir = getcwd(todir, PATH_MAX); +#endif +#else + todir = malloc(PATH_MAX + 1); + todir = getwd(todir); +#endif + tdlen = strlen(todir); + xchdir(cwd); + tdlen = strlen(todir); + + uid = owner ? touid(owner) : (uid_t)(-1); + gid = group ? togid(group) : (gid_t)(-1); + + while (--argc > 0) { + name = *argv++; + len = strlen(name); + base = xbasename(name); + bnlen = strlen(base); + toname = xmalloc((unsigned int)(tdlen + 1 + bnlen + 1)); + sprintf(toname, "%s%s%s", todir, _DIRECTORY_SEPARATOR, base); + exists = (lstat(toname, &tosb) == 0); + + if (dodir) { + /* -d means create a directory, always */ + if (exists && !S_ISDIR(tosb.st_mode)) { + (void) unlink(toname); + exists = 0; + } + if (!exists && mkdir(toname, mode) < 0) + fail("cannot make directory %s", toname); + if ((owner || group) && chown(toname, uid, gid) < 0) + fail("cannot change owner of %s", toname); + } else if (dolink) { + if (access(name, R_OK) != 0) { + fail("cannot access %s", name); + } + if (*name == '/') { + /* source is absolute pathname, link to it directly */ + linkname = 0; + } else { + if (linkprefix) { + /* -L implies -l and prefixes names with a $cwd arg. */ + len += lplen + 1; + linkname = xmalloc((unsigned int)(len + 1)); + sprintf(linkname, "%s/%s", linkprefix, name); + } else if (dorelsymlink) { + /* Symlink the relative path from todir to source name. */ + linkname = xmalloc(PATH_MAX); + + if (*todir == '/') { + /* todir is absolute: skip over common prefix. */ + lplen = relatepaths(todir, cwd, linkname); + strcpy(linkname + lplen, name); + } else { + /* todir is named by a relative path: reverse it. */ + reversepath(todir, name, len, linkname); + xchdir(cwd); + } + + len = strlen(linkname); + } + name = linkname; + } + + /* Check for a pre-existing symlink with identical content. */ + if ((exists && (!S_ISLNK(tosb.st_mode) || + readlink(toname, buf, sizeof buf) != len || + strncmp(buf, name, (unsigned int)len) != 0)) || + ((stat(name, &fromsb) == 0) && + (fromsb.st_mtime > tosb.st_mtime))) { + (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); + exists = 0; + } + if (!exists && symlink(name, toname) < 0) + fail("cannot make symbolic link %s", toname); +#ifdef HAVE_LCHOWN + if ((owner || group) && lchown(toname, uid, gid) < 0) + fail("cannot change owner of %s", toname); +#endif + + if (linkname) { + free(linkname); + linkname = 0; + } + } else { + /* Copy from name to toname, which might be the same file. */ + if( stat(name, &sb) == 0 && S_IFDIR & sb.st_mode ) + { + /* then is directory: must explicitly create destination dir */ + /* and manually copy files over */ + copydir( name, todir, mode, group, owner, dotimes, uid, gid ); + } + else + { + copyfile(name, toname, mode, group, owner, dotimes, uid, gid); + } + } + + free(toname); + } + + free(cwd); + free(todir); + return 0; +} diff --git a/js/src/config/nsinstall.exe.manifest b/js/src/config/nsinstall.exe.manifest new file mode 100644 index 0000000..26768e9 --- /dev/null +++ b/js/src/config/nsinstall.exe.manifest @@ -0,0 +1,22 @@ + + + +nsinstall + + + + + + + + + + + + + diff --git a/js/src/config/nsinstall.py b/js/src/config/nsinstall.py new file mode 100644 index 0000000..7c990c6 --- /dev/null +++ b/js/src/config/nsinstall.py @@ -0,0 +1,155 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla. +# +# The Initial Developer of the Original Code is +# the Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Axel Hecht +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# This is a partial python port of nsinstall. +# It's intended to be used when there's no natively compile nsinstall +# available, and doesn't intend to be fully equivalent. +# Its major use is for l10n repackaging on systems that don't have +# a full build environment set up. +# The basic limitation is, it doesn't even try to link and ignores +# all related options. + +from optparse import OptionParser +import os +import os.path +import sys +import shutil + +def nsinstall(argv): + usage = "usage: %prog [options] arg1 [arg2 ...] target-directory" + p = OptionParser(usage=usage) + + p.add_option('-D', action="store_true", + help="Create a single directory only") + p.add_option('-t', action="store_true", + help="Preserve time stamp") + p.add_option('-m', action="store", + help="Set mode", metavar="mode") + p.add_option('-d', action="store_true", + help="Create directories in target") + p.add_option('-R', action="store_true", + help="Use relative symbolic links (ignored)") + p.add_option('-l', action="store_true", + help="Create link (ignored)") + p.add_option('-L', action="store", metavar="linkprefix", + help="Link prefix (ignored)") + + # The remaining arguments are not used in our tree, thus they're not + # implented. + def BadArg(option, opt, value, parser): + parser.error('option not supported: %s' % opt) + + p.add_option('-C', action="callback", metavar="CWD", + callback=BadArg, + help="NOT SUPPORTED") + p.add_option('-o', action="callback", callback=BadArg, + help="Set owner (NOT SUPPORTED)", metavar="owner") + p.add_option('-g', action="callback", callback=BadArg, + help="Set group (NOT SUPPORTED)", metavar="group") + + (options, args) = p.parse_args(argv) + + if options.m: + # mode is specified + try: + options.m = int(options.m, 8) + except: + sys.stderr.write('nsinstall: ' + options.m + ' is not a valid mode\n') + return 1 + + # just create one directory? + if options.D: + if len(args) != 1: + return 1 + if os.path.exists(args[0]): + if not os.path.isdir(args[0]): + sys.stderr.write('nsinstall: ' + args[0] + ' is not a directory\n') + sys.exit(1) + if options.m: + os.chmod(args[0], options.m) + sys.exit() + if options.m: + os.makedirs(args[0], options.m) + else: + os.makedirs(args[0]) + return 0 + + # nsinstall arg1 [...] directory + if len(args) < 2: + p.error('not enough arguments') + + def copy_all_entries(entries, target): + for e in entries: + dest = os.path.join(target, + os.path.basename(os.path.normpath(e))) + handleTarget(e, dest) + if options.m: + os.chmod(dest, options.m) + + # set up handler + if options.d: + # we're supposed to create directories + def handleTarget(srcpath, targetpath): + # target directory was already created, just use mkdir + os.mkdir(targetpath) + else: + # we're supposed to copy files + def handleTarget(srcpath, targetpath): + if os.path.isdir(srcpath): + if not os.path.exists(targetpath): + os.mkdir(targetpath) + entries = [os.path.join(srcpath, e) for e in os.listdir(srcpath)] + copy_all_entries(entries, targetpath) + # options.t is not relevant for directories + if options.m: + os.chmod(targetpath, options.m) + elif options.t: + shutil.copy2(srcpath, targetpath) + else: + shutil.copy(srcpath, targetpath) + + # the last argument is the target directory + target = args.pop() + # ensure target directory + if not os.path.isdir(target): + os.makedirs(target) + + copy_all_entries(args, target) + return 0 + +if __name__ == '__main__': + sys.exit(nsinstall(sys.argv[1:])) diff --git a/js/src/config/nsinstall_win.c b/js/src/config/nsinstall_win.c new file mode 100644 index 0000000..d9b723b --- /dev/null +++ b/js/src/config/nsinstall_win.c @@ -0,0 +1,711 @@ +/* + * The nsinstall command for Win32 + * + * Our gmake makefiles use the nsinstall command to create the + * object directories or installing headers and libs. This code was originally + * taken from shmsdos.c + */ + +#include +#include +#include +#include +#include +#pragma hdrstop + +/* + * sh_FileFcn -- + * + * A function that operates on a file. The pathname is either + * absolute or relative to the current directory, and contains + * no wildcard characters such as * and ?. Additional arguments + * can be passed to the function via the arg pointer. + */ + +typedef BOOL (*sh_FileFcn)( + wchar_t *pathName, + WIN32_FIND_DATA *fileData, + void *arg); + +static int shellCp (wchar_t **pArgv); +static int shellNsinstall (wchar_t **pArgv); +static int shellMkdir (wchar_t **pArgv); +static BOOL sh_EnumerateFiles(const wchar_t *pattern, const wchar_t *where, + sh_FileFcn fileFcn, void *arg, int *nFiles); +static const char *sh_GetLastErrorMessage(void); +static BOOL sh_DoCopy(wchar_t *srcFileName, DWORD srcFileAttributes, + wchar_t *dstFileName, DWORD dstFileAttributes, + int force, int recursive); + +#define LONGPATH_PREFIX L"\\\\?\\" +#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0])) +#define STR_LEN(a) (ARRAY_LEN(a) - 1) + +/* changes all forward slashes in token to backslashes */ +void changeForwardSlashesToBackSlashes ( wchar_t *arg ) +{ + if ( arg == NULL ) + return; + + while ( *arg ) { + if ( *arg == '/' ) + *arg = '\\'; + arg++; + } +} + +int wmain(int argc, wchar_t *argv[ ]) +{ + return shellNsinstall ( argv + 1 ); +} + +static int +shellNsinstall (wchar_t **pArgv) +{ + int retVal = 0; /* exit status */ + int dirOnly = 0; /* 1 if and only if -D is specified */ + wchar_t **pSrc; + wchar_t **pDst; + + /* + * Process the command-line options. We ignore the + * options except for -D. Some options, such as -m, + * are followed by an argument. We need to skip the + * argument too. + */ + while ( *pArgv && **pArgv == '-' ) { + wchar_t c = (*pArgv)[1]; /* The char after '-' */ + + if ( c == 'D' ) { + dirOnly = 1; + } else if ( c == 'm' ) { + pArgv++; /* skip the next argument */ + } + pArgv++; + } + + if ( !dirOnly ) { + /* There are files to install. Get source files */ + if ( *pArgv ) { + pSrc = pArgv++; + } else { + fprintf( stderr, "nsinstall: not enough arguments\n"); + return 3; + } + } + + /* Get to last token to find destination directory */ + if ( *pArgv ) { + pDst = pArgv++; + if ( dirOnly && *pArgv ) { + fprintf( stderr, "nsinstall: too many arguments with -D\n"); + return 3; + } + } else { + fprintf( stderr, "nsinstall: not enough arguments\n"); + return 3; + } + while ( *pArgv ) + pDst = pArgv++; + + retVal = shellMkdir ( pDst ); + if ( retVal ) + return retVal; + if ( !dirOnly ) + retVal = shellCp ( pSrc ); + return retVal; +} + +static int +shellMkdir (wchar_t **pArgv) +{ + int retVal = 0; /* assume valid return */ + wchar_t *arg; + wchar_t *pArg; + wchar_t path[_MAX_PATH]; + wchar_t tmpPath[_MAX_PATH]; + wchar_t *pTmpPath = tmpPath; + + /* All the options are simply ignored in this implementation */ + while ( *pArgv && **pArgv == '-' ) { + if ( (*pArgv)[1] == 'm' ) { + pArgv++; /* skip the next argument (mode) */ + } + pArgv++; + } + + while ( *pArgv ) { + arg = *pArgv; + changeForwardSlashesToBackSlashes ( arg ); + pArg = arg; + pTmpPath = tmpPath; + while ( 1 ) { + /* create part of path */ + while ( *pArg ) { + *pTmpPath++ = *pArg++; + if ( *pArg == '\\' ) + break; + } + *pTmpPath = '\0'; + + /* check if directory already exists */ + _wgetcwd ( path, _MAX_PATH ); + if ( _wchdir ( tmpPath ) == -1 && + _wmkdir ( tmpPath ) == -1 && // might have hit EEXIST + _wchdir ( tmpPath ) == -1) { // so try again + char buf[2048]; + _snprintf(buf, 2048, "Could not create the directory: %S", + tmpPath); + perror ( buf ); + retVal = 3; + break; + } else { + // get back to the cwd + _wchdir ( path ); + } + if ( *pArg == '\0' ) /* complete path? */ + break; + /* loop for next directory */ + } + + pArgv++; + } + return retVal; +} + +static const char * +sh_GetLastErrorMessage() +{ + static char buf[128]; + + FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* default language */ + buf, + sizeof(buf), + NULL + ); + return buf; +} + +/* + * struct sh_FileData -- + * + * A pointer to the sh_FileData structure is passed into sh_RecordFileData, + * which will fill in the fields. + */ + +struct sh_FileData { + wchar_t pathName[_MAX_PATH]; + DWORD dwFileAttributes; +}; + +/* + * sh_RecordFileData -- + * + * Record the pathname and attributes of the file in + * the sh_FileData structure pointed to by arg. + * + * Always return TRUE (successful completion). + * + * This function is intended to be passed into sh_EnumerateFiles + * to see if a certain pattern expands to exactly one file/directory, + * and if so, record its pathname and attributes. + */ + +static BOOL +sh_RecordFileData(wchar_t *pathName, WIN32_FIND_DATA *findData, void *arg) +{ + struct sh_FileData *fData = (struct sh_FileData *) arg; + + wcscpy(fData->pathName, pathName); + fData->dwFileAttributes = findData->dwFileAttributes; + return TRUE; +} + +static BOOL +sh_DoCopy(wchar_t *srcFileName, + DWORD srcFileAttributes, + wchar_t *dstFileName, + DWORD dstFileAttributes, + int force, + int recursive +) +{ + if (dstFileAttributes != 0xFFFFFFFF) { + if ((dstFileAttributes & FILE_ATTRIBUTE_READONLY) && force) { + dstFileAttributes &= ~FILE_ATTRIBUTE_READONLY; + SetFileAttributes(dstFileName, dstFileAttributes); + } + } + + if (srcFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + fprintf(stderr, "nsinstall: %ls is a directory\n", + srcFileName); + return FALSE; + } else { + DWORD r; + wchar_t longSrc[1004] = LONGPATH_PREFIX; + wchar_t longDst[1004] = LONGPATH_PREFIX; + r = GetFullPathName(srcFileName, 1000, longSrc + STR_LEN(LONGPATH_PREFIX), NULL); + if (!r) { + fprintf(stderr, "nsinstall: couldn't get full path of %ls: %s\n", + srcFileName, sh_GetLastErrorMessage()); + return FALSE; + } + r = GetFullPathName(dstFileName, 1000, longDst + ARRAY_LEN(LONGPATH_PREFIX) - 1, NULL); + if (!r) { + fprintf(stderr, "nsinstall: couldn't get full path of %ls: %s\n", + dstFileName, sh_GetLastErrorMessage()); + return FALSE; + } + + if (!CopyFile(longSrc, longDst, FALSE)) { + fprintf(stderr, "nsinstall: cannot copy %ls to %ls: %s\n", + srcFileName, dstFileName, sh_GetLastErrorMessage()); + return FALSE; + } + } + return TRUE; +} + +/* + * struct sh_CpCmdArg -- + * + * A pointer to the sh_CpCmdArg structure is passed into sh_CpFileCmd. + * The sh_CpCmdArg contains information about the cp command, and + * provide a buffer for constructing the destination file name. + */ + +struct sh_CpCmdArg { + int force; /* -f option, ok to overwrite an existing + * read-only destination file */ + int recursive; /* -r or -R option, recursively copy + * directories. Note: this field is not used + * by nsinstall and should always be 0. */ + wchar_t *dstFileName; /* a buffer for constructing the destination + * file name */ + wchar_t *dstFileNameMarker; /* points to where in the dstFileName buffer + * we should write the file component of the + * destination file */ +}; + +/* + * sh_CpFileCmd -- + * + * Copy a file to the destination directory + * + * This function is intended to be passed into sh_EnumerateFiles to + * copy all the files specified by the pattern to the destination + * directory. + * + * Return TRUE if the file is successfully copied, and FALSE otherwise. + */ + +static BOOL +sh_CpFileCmd(wchar_t *pathName, WIN32_FIND_DATA *findData, void *cpArg) +{ + BOOL retVal = TRUE; + struct sh_CpCmdArg *arg = (struct sh_CpCmdArg *) cpArg; + + wcscpy(arg->dstFileNameMarker, findData->cFileName); + return sh_DoCopy(pathName, findData->dwFileAttributes, + arg->dstFileName, GetFileAttributes(arg->dstFileName), + arg->force, arg->recursive); +} + +static int +shellCp (wchar_t **pArgv) +{ + int retVal = 0; + wchar_t **pSrc; + wchar_t **pDst; + struct sh_CpCmdArg arg; + struct sh_FileData dstData; + int dstIsDir = 0; + int n; + + arg.force = 0; + arg.recursive = 0; + arg.dstFileName = dstData.pathName; + arg.dstFileNameMarker = 0; + + while (*pArgv && **pArgv == '-') { + wchar_t *p = *pArgv; + + while (*(++p)) { + if (*p == 'f') { + arg.force = 1; + } + } + pArgv++; + } + + /* the first source file */ + if (*pArgv) { + pSrc = pArgv++; + } else { + fprintf(stderr, "nsinstall: not enough arguments\n"); + return 3; + } + + /* get to the last token to find destination */ + if (*pArgv) { + pDst = pArgv++; + } else { + fprintf(stderr, "nsinstall: not enough arguments\n"); + return 3; + } + while (*pArgv) { + pDst = pArgv++; + } + + /* + * The destination pattern must unambiguously expand to exactly + * one file or directory. + */ + + changeForwardSlashesToBackSlashes(*pDst); + sh_EnumerateFiles(*pDst, *pDst, sh_RecordFileData, &dstData, &n); + assert(n >= 0); + if (n == 1) { + /* + * Is the destination a file or directory? + */ + + if (dstData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + dstIsDir = 1; + } + } else if (n > 1) { + fprintf(stderr, "nsinstall: %ls: ambiguous destination file " + "or directory\n", *pDst); + return 3; + } else { + /* + * n == 0, meaning that destination file or directory does + * not exist. In this case the destination file directory + * name must be fully specified. + */ + + wchar_t *p; + + for (p = *pDst; *p; p++) { + if (*p == '*' || *p == '?') { + fprintf(stderr, "nsinstall: %ls: No such file or directory\n", + *pDst); + return 3; + } + } + + /* + * Do not include the trailing \, if any, unless it is a root + * directory (\ or X:\). + */ + + if (p > *pDst && p[-1] == '\\' && p != *pDst + 1 && p[-2] != ':') { + p[-1] = '\0'; + } + wcscpy(dstData.pathName, *pDst); + dstData.dwFileAttributes = 0xFFFFFFFF; + } + + /* + * If there are two or more source files, the destination has + * to be a directory. + */ + + if (pDst - pSrc > 1 && !dstIsDir) { + fprintf(stderr, "nsinstall: cannot copy more than" + " one file to the same destination file\n"); + return 3; + } + + if (dstIsDir) { + arg.dstFileNameMarker = arg.dstFileName + wcslen(arg.dstFileName); + + /* + * Now arg.dstFileNameMarker is pointing to the null byte at the + * end of string. We want to make sure that there is a \ at the + * end of string, and arg.dstFileNameMarker should point right + * after that \. + */ + + if (arg.dstFileNameMarker[-1] != '\\') { + *(arg.dstFileNameMarker++) = '\\'; + } + } + + if (!dstIsDir) { + struct sh_FileData srcData; + + assert(pDst - pSrc == 1); + changeForwardSlashesToBackSlashes(*pSrc); + sh_EnumerateFiles(*pSrc, *pSrc, sh_RecordFileData, &srcData, &n); + if (n == 0) { + fprintf(stderr, "nsinstall: %ls: No such file or directory\n", + *pSrc); + retVal = 3; + } else if (n > 1) { + fprintf(stderr, "nsinstall: cannot copy more than one file or " + "directory to the same destination\n"); + retVal = 3; + } else { + assert(n == 1); + if (sh_DoCopy(srcData.pathName, srcData.dwFileAttributes, + dstData.pathName, dstData.dwFileAttributes, + arg.force, arg.recursive) == FALSE) { + retVal = 3; + } + } + return retVal; + } + + for ( ; *pSrc != *pDst; pSrc++) { + BOOL rv; + + changeForwardSlashesToBackSlashes(*pSrc); + rv = sh_EnumerateFiles(*pSrc, *pSrc, sh_CpFileCmd, &arg, &n); + if (rv == FALSE) { + retVal = 3; + } else { + if (n == 0) { + fprintf(stderr, "nsinstall: %ls: No such file or directory\n", + *pSrc); + retVal = 3; + } + } + } + + return retVal; +} + +/* + * sh_EnumerateFiles -- + * + * Enumerate all the files in the specified pattern, which is a pathname + * containing possibly wildcard characters such as * and ?. fileFcn + * is called on each file, passing the expanded file name, a pointer + * to the file's WIN32_FILE_DATA, and the arg pointer. + * + * It is assumed that there are no wildcard characters before the + * character pointed to by 'where'. + * + * On return, *nFiles stores the number of files enumerated. *nFiles is + * set to this number whether sh_EnumerateFiles or 'fileFcn' succeeds + * or not. + * + * Return TRUE if the files are successfully enumerated and all + * 'fileFcn' invocations succeeded. Return FALSE if something went + * wrong. + */ + +static BOOL sh_EnumerateFiles( + const wchar_t *pattern, + const wchar_t *where, + sh_FileFcn fileFcn, + void *arg, + int *nFiles + ) +{ + WIN32_FIND_DATA fileData; + HANDLE hSearch; + const wchar_t *src; + wchar_t *dst; + wchar_t fileName[_MAX_PATH]; + wchar_t *fileNameMarker = fileName; + wchar_t *oldFileNameMarker; + BOOL hasWildcard = FALSE; + BOOL retVal = TRUE; + BOOL patternEndsInDotStar = FALSE; + BOOL patternEndsInDot = FALSE; /* a special case of + * patternEndsInDotStar */ + int numDotsInPattern; + int len; + + /* + * Windows expands patterns ending in ".", ".*", ".**", etc. + * differently from the glob expansion on Unix. For example, + * both "foo." and "foo.*" match "foo", and "*.*" matches + * everything, including filenames with no dots. So we need + * to throw away extra files returned by the FindNextFile() + * function. We require that a matched filename have at least + * the number of dots in the pattern. + */ + len = wcslen(pattern); + if (len >= 2) { + /* Start from the end of pattern and go backward */ + const wchar_t *p = &pattern[len - 1]; + + /* We can have zero or more *'s */ + while (p >= pattern && *p == '*') { + p--; + } + if (p >= pattern && *p == '.') { + patternEndsInDotStar = TRUE; + if (p == &pattern[len - 1]) { + patternEndsInDot = TRUE; + } + p--; + numDotsInPattern = 1; + while (p >= pattern && *p != '\\') { + if (*p == '.') { + numDotsInPattern++; + } + p--; + } + } + } + + *nFiles = 0; + + /* + * Copy pattern to fileName, but only up to and not including + * the first \ after the first wildcard letter. + * + * Make fileNameMarker point to one of the following: + * - the start of fileName, if fileName does not contain any \. + * - right after the \ before the first wildcard letter, if there is + * a wildcard character. + * - right after the last \, if there is no wildcard character. + */ + + dst = fileName; + src = pattern; + while (src < where) { + if (*src == '\\') { + oldFileNameMarker = fileNameMarker; + fileNameMarker = dst + 1; + } + *(dst++) = *(src++); + } + + while (*src && *src != '*' && *src != '?') { + if (*src == '\\') { + oldFileNameMarker = fileNameMarker; + fileNameMarker = dst + 1; + } + *(dst++) = *(src++); + } + + if (*src) { + /* + * Must have seen the first wildcard letter + */ + + hasWildcard = TRUE; + while (*src && *src != '\\') { + *(dst++) = *(src++); + } + } + + /* Now src points to either null or \ */ + + assert(*src == '\0' || *src == '\\'); + assert(hasWildcard || *src == '\0'); + *dst = '\0'; + + /* + * If the pattern does not contain any wildcard characters, then + * we don't need to go the FindFirstFile route. + */ + + if (!hasWildcard) { + /* + * See if it is the root directory, \, or X:\. + */ + + assert(!wcscmp(fileName, pattern)); + assert(wcslen(fileName) >= 1); + if (dst[-1] == '\\' && (dst == fileName + 1 || dst[-2] == ':')) { + fileData.cFileName[0] = '\0'; + } else { + /* + * Do not include the trailing \, if any + */ + + if (dst[-1] == '\\') { + assert(*fileNameMarker == '\0'); + dst[-1] = '\0'; + fileNameMarker = oldFileNameMarker; + } + wcscpy(fileData.cFileName, fileNameMarker); + } + fileData.dwFileAttributes = GetFileAttributes(fileName); + if (fileData.dwFileAttributes == 0xFFFFFFFF) { + return TRUE; + } + *nFiles = 1; + return (*fileFcn)(fileName, &fileData, arg); + } + + hSearch = FindFirstFile(fileName, &fileData); + if (hSearch == INVALID_HANDLE_VALUE) { + return retVal; + } + + do { + if (!wcscmp(fileData.cFileName, L".") + || !wcscmp(fileData.cFileName, L"..")) { + /* + * Skip over . and .. + */ + + continue; + } + + if (patternEndsInDotStar) { + int nDots = 0; + wchar_t *p = fileData.cFileName; + while (*p) { + if (*p == '.') { + nDots++; + } + p++; + } + /* Now p points to the null byte at the end of file name */ + if (patternEndsInDot && (p == fileData.cFileName + || p[-1] != '.')) { + /* + * File name does not end in dot. Skip this file. + * Note: windows file name probably cannot end in dot, + * but we do this check anyway. + */ + continue; + } + if (nDots < numDotsInPattern) { + /* + * Not enough dots in file name. Must be an extra + * file in matching .* pattern. Skip this file. + */ + continue; + } + } + + wcscpy(fileNameMarker, fileData.cFileName); + if (*src && *(src + 1)) { + /* + * More to go. Recurse. + */ + + int n; + + assert(*src == '\\'); + where = fileName + wcslen(fileName); + wcscat(fileName, src); + sh_EnumerateFiles(fileName, where, fileFcn, arg, &n); + *nFiles += n; + } else { + assert(wcschr(fileName, '*') == NULL); + assert(wcschr(fileName, '?') == NULL); + (*nFiles)++; + if ((*fileFcn)(fileName, &fileData, arg) == FALSE) { + retVal = FALSE; + } + } + } while (FindNextFile(hSearch, &fileData)); + + FindClose(hSearch); + return retVal; +} diff --git a/js/src/config/pathsub.c b/js/src/config/pathsub.c new file mode 100644 index 0000000..8384e5f --- /dev/null +++ b/js/src/config/pathsub.c @@ -0,0 +1,247 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* +** Pathname subroutines. +** +** Brendan Eich, 8/29/95 +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pathsub.h" + +#ifdef USE_REENTRANT_LIBC +#include +#endif + +#ifdef SUNOS4 +#include "sunos4.h" +#endif + +#ifndef D_INO +#define D_INO d_ino +#endif + +char *program; + +void +fail(char *format, ...) +{ + int error; + va_list ap; + +#ifdef USE_REENTRANT_LIBC + R_STRERROR_INIT_R(); +#endif + + error = errno; + fprintf(stderr, "%s: ", program); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + if (error) { + +#ifdef USE_REENTRANT_LIBC + R_STRERROR_R(errno); + fprintf(stderr, ": %s", r_strerror_r); +#else + fprintf(stderr, ": %s", strerror(errno)); +#endif + } + + putc('\n', stderr); + exit(1); +} + +char * +getcomponent(char *path, char *name) +{ + if (*path == '\0') + return 0; + if (*path == '/') { + *name++ = '/'; + } else { + do { + *name++ = *path++; + } while (*path != '/' && *path != '\0'); + } + *name = '\0'; + while (*path == '/') + path++; + return path; +} + +#ifdef LAME_READDIR +#include +/* +** The static buffer in Unixware's readdir is too small. +*/ +struct dirent *readdir(DIR *d) +{ + static struct dirent *buf = NULL; + + if(buf == NULL) + buf = (struct dirent *) malloc(sizeof(struct dirent) + MAXPATHLEN); + return(readdir_r(d, buf)); +} +#endif + +char * +ino2name(ino_t ino, char *dir) +{ + DIR *dp; + struct dirent *ep; + char *name; + + dp = opendir(".."); + if (!dp) + fail("cannot read parent directory"); + for (;;) { + if (!(ep = readdir(dp))) + fail("cannot find current directory"); + if (ep->D_INO == ino) + break; + } + name = xstrdup(ep->d_name); + closedir(dp); + return name; +} + +void * +xmalloc(size_t size) +{ + void *p = malloc(size); + if (!p) + fail("cannot allocate %u bytes", size); + return p; +} + +char * +xstrdup(char *s) +{ + return strcpy(xmalloc(strlen(s) + 1), s); +} + +char * +xbasename(char *path) +{ + char *cp; + + while ((cp = strrchr(path, '/')) && cp[1] == '\0') + *cp = '\0'; + if (!cp) return path; + return cp + 1; +} + +void +xchdir(char *dir) +{ + if (chdir(dir) < 0) + fail("cannot change directory to %s", dir); +} + +int +relatepaths(char *from, char *to, char *outpath) +{ + char *cp, *cp2; + int len; + char buf[NAME_MAX]; + + assert(*from == '/' && *to == '/'); + for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++) + if (*cp == '\0') + break; + while (cp[-1] != '/') + cp--, cp2--; + if (cp - 1 == to) { + /* closest common ancestor is /, so use full pathname */ + len = strlen(strcpy(outpath, to)); + if (outpath[len] != '/') { + outpath[len++] = '/'; + outpath[len] = '\0'; + } + } else { + len = 0; + while ((cp2 = getcomponent(cp2, buf)) != 0) { + strcpy(outpath + len, "../"); + len += 3; + } + while ((cp = getcomponent(cp, buf)) != 0) { + sprintf(outpath + len, "%s/", buf); + len += strlen(outpath + len); + } + } + return len; +} + +void +reversepath(char *inpath, char *name, int len, char *outpath) +{ + char *cp, *cp2; + char buf[NAME_MAX]; + struct stat sb; + + cp = strcpy(outpath + PATH_MAX - (len + 1), name); + cp2 = inpath; + while ((cp2 = getcomponent(cp2, buf)) != 0) { + if (strcmp(buf, ".") == 0) + continue; + if (strcmp(buf, "..") == 0) { + if (stat(".", &sb) < 0) + fail("cannot stat current directory"); + name = ino2name(sb.st_ino, ".."); + len = strlen(name); + cp -= len + 1; + strcpy(cp, name); + cp[len] = '/'; + free(name); + xchdir(".."); + } else { + cp -= 3; + strncpy(cp, "../", 3); + xchdir(buf); + } + } + strcpy(outpath, cp); +} diff --git a/js/src/config/pathsub.h b/js/src/config/pathsub.h new file mode 100644 index 0000000..ab1a7fe --- /dev/null +++ b/js/src/config/pathsub.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef pathsub_h___ +#define pathsub_h___ +/* +** Pathname subroutines. +** +** Brendan Eich, 8/29/95 +*/ +#include +#include + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +/* + * Just prevent stupidity + */ +#undef NAME_MAX +#define NAME_MAX 256 + +extern char *program; + +extern void fail(char *format, ...); +extern char *getcomponent(char *path, char *name); +extern char *ino2name(ino_t ino, char *dir); +extern void *xmalloc(size_t size); +extern char *xstrdup(char *s); +extern char *xbasename(char *path); +extern void xchdir(char *dir); + +/* Relate absolute pathnames from and to returning the result in outpath. */ +extern int relatepaths(char *from, char *to, char *outpath); + +/* XXX changes current working directory -- caveat emptor */ +extern void reversepath(char *inpath, char *name, int len, char *outpath); + +#endif /* pathsub_h___ */ diff --git a/js/src/config/preprocessor.pl b/js/src/config/preprocessor.pl new file mode 100644 index 0000000..3da6654 --- /dev/null +++ b/js/src/config/preprocessor.pl @@ -0,0 +1,671 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; tab-width: 4; indent-tabs-mode: nil; -*- +# +# Preprocessor +# Version 1.1 +# +# Copyright (c) 2002, 2003, 2004 by Ian Hickson +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Thanks to bryner and bsmedberg for suggestions. +# Thanks to jon rekai for a patch to not require File::Spec 0.8. + +use strict; + +# takes as arguments the files to process +# defaults to stdin +# output to stdout + +my $stack = new stack; +my $marker = '#'; + +# command line arguments +my @includes; +while ($_ = $ARGV[0], defined($_) && /^-./) { + shift; + last if /^--$/os; + if (/^-D(.*)$/os) { + for ($1) { + if (/^([\w\.]+)=(.*)$/os) { + $stack->define($1, $2); + } elsif (/^([\w\.]+)$/os) { + $stack->define($1, 1); + } else { + die "$0: invalid argument to -D: $_\n"; + } + } + } elsif (/^-F(.*)$/os) { + for ($1) { + if (/^(\w+)$/os) { + $stack->filter($1, 1); + } else { + die "$0: invalid argument to -F: $_\n"; + } + } + } elsif (/^-I(.*)$/os) { + push(@includes, $1); + } elsif (/^-E$/os) { + foreach (keys %ENV) { + # define all variables that have valid names + $stack->define($_, $ENV{$_}) unless m/\W/; + } + } elsif (/^-d$/os) { + $stack->{'dependencies'} = 1; + } elsif (/^--line-endings=crlf$/os) { + $stack->{'lineEndings'} = "\x0D\x0A"; + } elsif (/^--line-endings=cr$/os) { + $stack->{'lineEndings'} = "\x0D"; + } elsif (/^--line-endings=lf$/os) { + $stack->{'lineEndings'} = "\x0A"; + } elsif (/^--line-endings=(.+)$/os) { + die "$0: unrecognised line ending: $1\n"; + } elsif (/^--marker=(.)$/os) { + $marker = $1; + } else { + die "$0: invalid argument: $_\n"; + } +} +unshift(@ARGV, '-') unless @ARGV; +unshift(@ARGV, @includes); + +# do the work +foreach (@ARGV) { include($stack, $_); } +exit(0); + +######################################################################## + +package main; +use File::Spec; +use File::Spec::Unix; # on all platforms, because the #include syntax is unix-based + +# Note: Ideally we would use File::Spec 0.8. When this becomes +# possible, add "0.8" to the first "use" line above, then replace +# occurrences of "::_0_8::" with "->" below. And remove the code for +# File::Spec 0.8 much lower down the file. + +sub include { + my($stack, $filename) = @_; + my $directory = $stack->{'variables'}->{'DIRECTORY'}; + if ($filename ne '-') { + $filename = File::Spec::_0_8::rel2abs($filename, $directory); + # splitpath expects forward-slash paths on windows, so we have to + # change the slashes if using Activestate Perl. + $filename =~ s?\\?/?g if "$^O" eq "MSWin32"; + my($volume, $path) = File::Spec::_0_8::splitpath($filename); + $directory = File::Spec::_0_8::catpath($volume, $path, ''); + } + local $stack->{'variables'}->{'DIRECTORY'} = $directory; + local $stack->{'variables'}->{'FILE'} = $filename; + local $stack->{'variables'}->{'LINE'} = 0; + local *FILE; + open(FILE, $filename) or die "Couldn't open $filename: $!\n"; + my $lineout = 0; + while () { + # on cygwin, line endings are screwed up, so normalise them. + s/[\x0D\x0A]+$/\n/os if ($^O eq 'msys' || $^O eq 'cygwin' || "$^O" eq "MSWin32"); + $stack->newline; + if (/^\Q$marker\E([a-z]+)\n?$/os) { # argumentless processing instruction + process($stack, $1); + } elsif (/^\Q$marker\E([a-z]+)\s(.*?)\n?$/os) { # processing instruction with arguments + process($stack, $1, $2); + } elsif (/^\Q$marker\E/os) { # comment + # ignore it + } elsif ($stack->enabled) { + next if $stack->{'dependencies'}; + + # set the current line number in JavaScript if necessary + my $linein = $stack->{'variables'}->{'LINE'}; + if (++$lineout != $linein) { + if ($filename =~ /\.js(|\.in)$/o) { + $stack->print("//\@line $linein \"$filename\"\n") + } + $lineout = $linein; + } + + # print it, including any newlines + $stack->print(filtered($stack, $_)); + } + } + close(FILE); +} + +sub process { + my($stack, $instruction, @arguments) = @_; + my $method = 'preprocessor'->can($instruction); + if (not defined($method)) { + fatal($stack, 'unknown instruction', $instruction); + } + eval { &$method($stack, @arguments) }; + if ($@) { + fatal($stack, "error evaluating $instruction:", $@); + } +} + +sub filtered { + my($stack, $text) = @_; + foreach my $filter (sort keys %{$stack->{'filters'}}) { + next unless $stack->{'filters'}->{$filter}; + my $method = 'filter'->can($filter); + if (not defined($method)) { + fatal($stack, 'unknown filter', $filter); + } + $text = eval { &$method($stack, $text) }; + if ($@) { + fatal($stack, "error using $filter:", $@); + } + } + return $text; +} + +sub fatal { + my $stack = shift; + my $filename = $stack->{'variables'}->{'FILE'}; + local $" = ' '; + print STDERR "$0:$filename:$.: @_\n"; + exit(1); +} + + +######################################################################## + +package stack; + +# condition evaluated just prior to this context was false +use constant COND_FALSE => 0; + +# condition evaluated just prior to this context was true +use constant COND_TRUE => 1; + +# some prior condition at this level already evaluated to true (or a +# parent condition evaluated to false or must be ignored), so we're +# ignoring all remaining conditions at current level (and nested +# conditions, too) +use constant COND_COMPLETED => 2; + +sub new { + return bless { + 'variables' => { + # %ENV, + 'LINE' => 0, # the line number in the source file + 'DIRECTORY' => '', # current directory + 'FILE' => '', # source filename + '1' => 1, # for convenience (the constant '1' is thus true) + }, + 'filters' => { + # filters + }, + 'values' => [], # the value of the last condition evaluated at the nth level + 'lastConditionState' => [], # whether the condition in the nth-level context was true, false, or not applicable + 'conditionState' => COND_TRUE, + 'dependencies' => 0, # whether we are showing dependencies + 'lineEndings' => "\n", # default to platform conventions + }; +} + +sub newline { + my $self = shift; + $self->{'variables'}->{'LINE'}++; +} + +sub define { + my $self = shift; + my($variable, $value) = @_; + die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/; + $self->{'variables'}->{$variable} = $value; +} + +sub defined { + my $self = shift; + my($variable) = @_; + die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/; + return defined($self->{'variables'}->{$variable}); +} + +sub undefine { + my $self = shift; + my($variable) = @_; + die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/; + delete($self->{'variables'}->{$variable}); +} + +sub get { + my $self = shift; + my($variable, $required) = @_; + die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/; + my $value = $self->{'variables'}->{$variable}; + if (defined($value)) { + return $value; + } else { + die "variable '$variable' is not defined\n" if $required; + return ''; + } +} + +sub replace { + my $self = shift; + my ($value) = @_; + + ${$self->{'values'}}[-1] = $value; + $self->{'conditionState'} = $self->{'conditionState'} != COND_FALSE + ? COND_COMPLETED + : $value ? COND_TRUE : COND_FALSE; +} + +sub push { + my $self = shift; + my($value) = @_; + + push(@{$self->{'values'}}, $value); + my $lastCondition = $self->{'conditionState'}; + push(@{$self->{'lastConditionState'}}, $lastCondition); + $self->{'conditionState'} = $lastCondition != COND_TRUE + ? COND_COMPLETED + : $value ? COND_TRUE : COND_FALSE; +} + +sub pop { + my $self = shift; + $self->{'conditionState'} = pop(@{$self->{'lastConditionState'}}); + return pop(@{$self->{'values'}}); +} + +sub enabled { + my $self = shift; + return $self->{'conditionState'} == COND_TRUE; +} + +sub disabled { + my $self = shift; + return $self->{'conditionState'} != COND_TRUE; +} + +sub filter { + my $self = shift; + my($filter, $value) = @_; + die "not a valid filter name: '$filter'\n" if $filter =~ m/\W/; + $self->{'filters'}->{$filter} = $value; +} + +sub expand { + my $self = shift; + my($line) = @_; + $line =~ s/__(\w+)__/$self->get($1)/gose; + return $line; +} + +sub print { + my $self = shift; + return if $self->{'dependencies'}; + foreach my $line (@_) { + if (chomp $line) { + CORE::print("$line$self->{'lineEndings'}"); + } else { + CORE::print($line); + } + } +} + +sub visit { + my $self = shift; + my($filename) = @_; + my $directory = $stack->{'variables'}->{'DIRECTORY'}; + $filename = File::Spec::_0_8::abs2rel(File::Spec::_0_8::rel2abs($filename, $directory)); + CORE::print("$filename\n"); +} + +######################################################################## + +package preprocessor; + +sub define { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + my $argument = shift; + for ($argument) { + /^(\w+)\s(.*)$/os && do { + return $stack->define($1, $2); + }; + /^(\w+)$/os && do { + return $stack->define($1, 1); + }; + die "invalid argument: '$_'\n"; + } +} + +sub undef { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + $stack->undefine(@_); +} + +sub ifdef { + my $stack = shift; + my $variable = shift; + my $replace = defined(shift); + die "argument expected\n" unless defined($variable); + if ($replace) { + $stack->replace($stack->defined($variable)); + } else { + $stack->push($stack->defined($variable)); + } +} + +sub ifndef { + my $stack = shift; + my $variable = shift; + my $replace = defined(shift); + die "argument expected\n" unless defined($variable); + if ($replace) { + $stack->replace(not $stack->defined($variable)); + } else { + $stack->push(not $stack->defined($variable)); + } +} + +sub if { + my $stack = shift; + die "argument expected\n" unless @_; + my $argument = shift; + my $replace = defined(shift); + for ($argument) { + /^(\w+)==(.*)$/os && do { + # equality + if ($replace) { + return $stack->replace($stack->get($1) eq $2); + } else { + return $stack->push($stack->get($1) eq $2); + } + }; + /^(\w+)!=(.*)$/os && do { + # inequality + if ($replace) { + return $stack->replace($stack->get($1) ne $2); + } else { + return $stack->push($stack->get($1) ne $2); + } + }; + /^(\w+)$/os && do { + # true value + if ($replace) { + return $stack->replace($stack->get($1)); + } else { + return $stack->push($stack->get($1)); + } + }; + /^!(\w+)$/os && do { + # false value + if ($replace) { + return $stack->replace(not $stack->get($1)); + } else { + return $stack->push(not $stack->get($1)); + } + }; + die "invalid argument: '$_'\n"; + } +} + +sub else { + my $stack = shift; + die "argument unexpected\n" if @_; + $stack->replace(1); +} + +sub elif { + my $stack = shift; + die "argument expected\n" unless @_; + &if($stack, @_, 1); +} + +sub elifdef { + my $stack = shift; + die "argument expected\n" unless @_; + &ifdef($stack, @_, 1); +} + +sub elifndef { + my $stack = shift; + die "argument expected\n" unless @_; + &ifndef($stack, @_, 1); +} + +sub endif { + my $stack = shift; + die "argument unexpected\n" if @_; + $stack->pop; +} + +sub error { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + my $line = $stack->expand(@_); + die "$line\n"; +} + +sub expand { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + my $line = $stack->expand(@_); + $stack->print("$line\n"); +} + +sub literal { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + my $line = shift; + $stack->print("$line\n"); +} + +sub include { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + my $filename = File::Spec::_0_8::catpath(File::Spec::_0_8::splitpath(@_)); + if ($stack->{'dependencies'}) { + $stack->visit($filename); + } else { + main::include($stack, $filename); + } +} + +sub includesubst { + my ($stack, $filename) = @_; + return if $stack->disabled; + die "argument expected\n" unless $filename; + $filename =~ s/@(\w+)@/$stack->get($1, 1)/gose; + $filename = File::Spec::_0_8::catpath(File::Spec::_0_8::splitpath($filename)); + if ($stack->{'dependencies'}) { + $stack->visit($filename); + } else { + main::include($stack, $filename); + } +} + +sub filter { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + foreach (split(/\s/os, shift)) { + $stack->filter($_, 1); + } +} + +sub unfilter { + my $stack = shift; + return if $stack->disabled; + die "argument expected\n" unless @_; + foreach (split(/\s/os, shift)) { + $stack->filter($_, 0); + } +} + + +######################################################################## + +package filter; + +sub emptyLines { + my($stack, $text) = @_; + $text = "" if $text eq "\n"; + return $text; +} + +sub spaces { + my($stack, $text) = @_; + $text =~ s/ +/ /gos; # middle spaces + $text =~ s/^ //gos; # start spaces + $text =~ s/ (\n?)$/$1/gos; # end spaces + return $text; +} + +sub slashslash { + my($stack, $text) = @_; + $text =~ s|//.*?(\n?)$|$1|gos; + return $text; +} + +sub substitution { + my($stack, $text) = @_; + $text =~ s/@(\w+)@/$stack->get($1, 1)/gose; + return $text; +} + +sub attemptSubstitution { + my($stack, $text) = @_; + $text =~ s/@(\w+)@/$stack->get($1, 0)/gose; + return $text; +} + +######################################################################## + +######################################################################## +# This code is from File::Spec::Unix 0.8. +# It is not considered a part of the preprocessor.pl source file +# This code is licensed under the same license as File::Spec itself. + +package File::Spec::_0_8; + +use Cwd; + +sub rel2abs { + my ($path, $base) = @_; + if ( ! File::Spec->file_name_is_absolute( $path ) ) { + if ( !defined( $base ) || $base eq '' ) { + $base = cwd() ; + } elsif ( ! File::Spec->file_name_is_absolute( $base ) ) { + $base = rel2abs( $base ); + } else { + $base = File::Spec->canonpath( $base ); + } + $path = File::Spec->catdir( $base, $path ); + } + return File::Spec->canonpath( $path ); +} + +sub splitdir { + return split m|/|, $_[1], -1; # Preserve trailing fields +} + +sub splitpath { + my ($path, $nofile) = @_; + + my ($volume,$directory,$file) = ('','',''); + + if ( $nofile ) { + $directory = $path; + } + else { + $path =~ m|^ ( (?: .* / (?: \.\.?\Z(?!\n) )? )? ) ([^/]*) |xs; + $directory = $1; + $file = $2; + } + + return ($volume,$directory,$file); +} + +sub catpath { + my ($volume,$directory,$file) = @_; + + if ( $directory ne '' && + $file ne '' && + substr( $directory, -1 ) ne '/' && + substr( $file, 0, 1 ) ne '/' + ) { + $directory .= "/$file" ; + } + else { + $directory .= $file ; + } + + return $directory ; +} + +sub abs2rel { + my($path,$base) = @_; + + # Clean up $path + if ( ! File::Spec->file_name_is_absolute( $path ) ) { + $path = rel2abs( $path ) ; + } + else { + $path = File::Spec->canonpath( $path ) ; + } + + # Figure out the effective $base and clean it up. + if ( !defined( $base ) || $base eq '' ) { + $base = cwd(); + } + elsif ( ! File::Spec->file_name_is_absolute( $base ) ) { + $base = rel2abs( $base ) ; + } + else { + $base = File::Spec->canonpath( $base ) ; + } + + # Now, remove all leading components that are the same + my @pathchunks = File::Spec::_0_8::splitdir( $path); + my @basechunks = File::Spec::_0_8::splitdir( $base); + + while (@pathchunks && @basechunks && $pathchunks[0] eq $basechunks[0]) { + shift @pathchunks ; + shift @basechunks ; + } + + $path = CORE::join( '/', @pathchunks ); + $base = CORE::join( '/', @basechunks ); + + # $base now contains the directories the resulting relative path + # must ascend out of before it can descend to $path_directory. So, + # replace all names with $parentDir + $base =~ s|[^/]+|..|g ; + + # Glue the two together, using a separator if necessary, and preventing an + # empty result. + if ( $path ne '' && $base ne '' ) { + $path = "$base/$path" ; + } else { + $path = "$base$path" ; + } + + return File::Spec->canonpath( $path ) ; +} + +# End code from File::Spec::Unix 0.8. +######################################################################## diff --git a/js/src/config/rules.mk b/js/src/config/rules.mk new file mode 100644 index 0000000..3675b8b --- /dev/null +++ b/js/src/config/rules.mk @@ -0,0 +1,2348 @@ +# vim:set ts=8 sw=8 sts=8 noet: +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Chase Phillips +# Benjamin Smedberg +# Jeff Walden +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +ifndef topsrcdir +$(error topsrcdir was not set)) +endif + +ifndef MOZILLA_DIR +MOZILLA_DIR = $(topsrcdir) +endif + +ifndef INCLUDED_CONFIG_MK +include $(topsrcdir)/config/config.mk +endif + +ifndef INCLUDED_VERSION_MK +include $(topsrcdir)/config/version.mk +endif + +ifdef SDK_XPIDLSRCS +XPIDLSRCS += $(SDK_XPIDLSRCS) +endif +ifdef SDK_HEADERS +EXPORTS += $(SDK_HEADERS) +endif + +REPORT_BUILD = @echo $(notdir $<) + +ifeq ($(OS_ARCH),OS2) +EXEC = +else +EXEC = exec +endif + +# Don't copy xulrunner files at install time, when using system xulrunner +ifdef SYSTEM_LIBXUL + SKIP_COPY_XULRUNNER=1 +endif + +# ELOG prints out failed command when building silently (gmake -s). +ifneq (,$(findstring s, $(filter-out --%, $(MAKEFLAGS)))) + ELOG := $(EXEC) sh $(BUILD_TOOLS)/print-failed-commands.sh +else + ELOG := +endif + +ifeq (,$(filter-out WINNT WINCE,$(OS_ARCH))) +ifndef GNU_CC +_LIBNAME_RELATIVE_PATHS=1 +endif +endif + +ifeq (,$(filter-out WINNT WINCE,$(OS_ARCH))) +_VPATH_SRCS = $(abspath $<) +else +_VPATH_SRCS = $< +endif + +# Add $(DIST)/lib to VPATH so that -lfoo dependencies are followed +VPATH += $(DIST)/lib +ifdef LIBXUL_SDK +VPATH += $(LIBXUL_SDK)/lib +endif + +# EXPAND_LIBNAME - $(call EXPAND_LIBNAME,foo) +# expands to foo.lib on platforms with import libs and -lfoo otherwise + +# EXPAND_LIBNAME_PATH - $(call EXPAND_LIBNAME_PATH,foo,dir) +# expands to dir/foo.lib on platforms with import libs and +# -Ldir -lfoo otherwise + +# EXPAND_MOZLIBNAME - $(call EXPAND_MOZLIBNAME,foo) +# expands to $(DIST)/lib/foo.lib on platforms with import libs and +# -lfoo otherwise + +ifdef _LIBNAME_RELATIVE_PATHS +EXPAND_LIBNAME = $(foreach lib,$(1),$(LIB_PREFIX)$(lib).$(LIB_SUFFIX)) +EXPAND_LIBNAME_PATH = $(foreach lib,$(1),$(2)/$(LIB_PREFIX)$(lib).$(LIB_SUFFIX)) +EXPAND_MOZLIBNAME = $(foreach lib,$(1),$(DIST)/lib/$(LIB_PREFIX)$(lib).$(LIB_SUFFIX)) +else +EXPAND_LIBNAME = $(addprefix -l,$(1)) +EXPAND_LIBNAME_PATH = -L$(2) $(addprefix -l,$(1)) +EXPAND_MOZLIBNAME = $(addprefix -l,$(1)) +endif + +ifdef MOZ_FAKELIBS +# If a lib.fake is present, replace it with @lib.fake, otherwise just pass +# the library name through unchanged. +EXPAND_FAKELIBS = $(foreach f,$(1),$(if $(wildcard $(f).fake),@$(wildcard $(f).fake),$(f))) + +# Also override EXPAND_LIBNAME_PATH and EXPAND_MOZLIBNAME on non-RELATIVE_PATH +# platforms, so we can shortcut linking -lfoo if we have foo.a.fake +ifndef _LIBNAME_RELATIVE_PATHS +EXPAND_LIBNAME_PATH = $(if $(wildcard $(2)/$(LIB_PREFIX)$(1).$(LIB_SUFFIX).fake),@$(2)/$(LIB_PREFIX)$(1).$(LIB_SUFFIX).fake,-L$(2) $(addprefix -l,$(1))) +EXPAND_MOZLIBNAME = $(if $(wildcard $(DIST)/lib/$(LIB_PREFIX)$(1).$(LIB_SUFFIX).fake),@$(DIST)/lib/$(LIB_PREFIX)$(1).$(LIB_SUFFIX).fake,$(addprefix -l,$(1))) +endif +else +EXPAND_FAKELIBS = $1 +endif + +ifdef EXTRA_DSO_LIBS +EXTRA_DSO_LIBS := $(call EXPAND_MOZLIBNAME,$(EXTRA_DSO_LIBS)) +endif + +################################################################################ +# Testing frameworks support +################################################################################ + +testxpcobjdir = $(DEPTH)/_tests/xpcshell + +ifdef ENABLE_TESTS + +ifdef XPCSHELL_TESTS +ifndef relativesrcdir +$(error Must define relativesrcdir when defining XPCSHELL_TESTS.) +endif + +# Test file installation +ifneq (,$(filter WINNT os2-emx,$(HOST_OS_ARCH))) +# Windows and OS/2 nsinstall can't recursively copy directories, so use nsinstall.py +TEST_INSTALLER = $(PYTHON) $(topsrcdir)/config/nsinstall.py +else +TEST_INSTALLER = $(INSTALL) +endif + +define _INSTALL_TESTS +$(TEST_INSTALLER) $(wildcard $(srcdir)/$(dir)/*) $(testxpcobjdir)/$(relativesrcdir)/$(dir) + +endef # do not remove the blank line! + +SOLO_FILE ?= $(error Specify a test filename in SOLO_FILE when using check-interactive or check-one) + +libs:: + $(foreach dir,$(XPCSHELL_TESTS),$(_INSTALL_TESTS)) + $(PYTHON) $(MOZILLA_DIR)/config/buildlist.py \ + $(testxpcobjdir)/all-test-dirs.list \ + $(addprefix $(relativesrcdir)/,$(XPCSHELL_TESTS)) + +testxpcsrcdir = $(topsrcdir)/testing/xpcshell + +# Execute all tests in the $(XPCSHELL_TESTS) directories. +# See also testsuite-targets.mk 'xpcshell-tests' target for global execution. +xpcshell-tests: + $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ + -I$(topsrcdir)/build \ + $(testxpcsrcdir)/runxpcshelltests.py \ + --symbols-path=$(DIST)/crashreporter-symbols \ + $(EXTRA_TEST_ARGS) \ + $(DIST)/bin/xpcshell \ + $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir)) + +# Execute a single test, specified in $(SOLO_FILE), but don't automatically +# start the test. Instead, present the xpcshell prompt so the user can +# attach a debugger and then start the test. +check-interactive: + $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ + -I$(topsrcdir)/build \ + $(testxpcsrcdir)/runxpcshelltests.py \ + --symbols-path=$(DIST)/crashreporter-symbols \ + --test-path=$(SOLO_FILE) \ + --profile-name=$(MOZ_APP_NAME) \ + --interactive \ + $(DIST)/bin/xpcshell \ + $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir)) + +# Execute a single test, specified in $(SOLO_FILE) +check-one: + $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ + -I$(topsrcdir)/build \ + $(testxpcsrcdir)/runxpcshelltests.py \ + --symbols-path=$(DIST)/crashreporter-symbols \ + --test-path=$(SOLO_FILE) \ + --profile-name=$(MOZ_APP_NAME) \ + --verbose \ + $(EXTRA_TEST_ARGS) \ + $(DIST)/bin/xpcshell \ + $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir)) + +endif # XPCSHELL_TESTS + +ifdef CPP_UNIT_TESTS + +# Compile the tests to $(DIST)/bin. Make lots of niceties available by default +# through TestHarness.h, by modifying the list of includes and the libs against +# which stuff links. +CPPSRCS += $(CPP_UNIT_TESTS) +SIMPLE_PROGRAMS += $(CPP_UNIT_TESTS:.cpp=$(BIN_SUFFIX)) +INCLUDES += -I$(DIST)/include/testing +LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS) -ljs_static + +# ...and run them the usual way +check:: + @$(EXIT_ON_ERROR) \ + for f in $(subst .cpp,$(BIN_SUFFIX),$(CPP_UNIT_TESTS)); do \ + XPCOM_DEBUG_BREAK=stack-and-abort $(RUN_TEST_PROGRAM) $(DIST)/bin/$$f; \ + done + +endif # CPP_UNIT_TESTS + +.PHONY: check xpcshell-tests check-interactive check-one + +endif # ENABLE_TESTS + + +# +# Library rules +# +# If BUILD_STATIC_LIBS or FORCE_STATIC_LIB is set, build a static library. +# Otherwise, build a shared library. +# + +ifndef LIBRARY +ifdef STATIC_LIBRARY_NAME +LIBRARY := $(LIB_PREFIX)$(STATIC_LIBRARY_NAME).$(LIB_SUFFIX) +ifdef MOZ_FAKELIBS +ifndef SUPPRESS_FAKELIB +FAKE_LIBRARY = $(LIBRARY).fake +endif # SUPPRESS_FAKELIB +endif # MOZ_FAKELIBS +endif # STATIC_LIBRARY_NAME +endif # LIBRARY + +ifndef HOST_LIBRARY +ifdef HOST_LIBRARY_NAME +HOST_LIBRARY := $(LIB_PREFIX)$(HOST_LIBRARY_NAME).$(LIB_SUFFIX) +endif +endif + +ifdef LIBRARY +ifneq (_1,$(FORCE_SHARED_LIB)_$(BUILD_STATIC_LIBS)) +ifdef MKSHLIB + +ifdef LIB_IS_C_ONLY +MKSHLIB = $(MKCSHLIB) +endif + +ifneq (,$(filter OS2 WINNT WINCE,$(OS_ARCH))) +IMPORT_LIBRARY := $(LIB_PREFIX)$(SHARED_LIBRARY_NAME).$(IMPORT_LIB_SUFFIX) +endif + +ifeq (OS2,$(OS_ARCH)) +ifdef SHORT_LIBNAME +SHARED_LIBRARY_NAME := $(SHORT_LIBNAME) +endif +endif + +ifdef MAKE_FRAMEWORK +SHARED_LIBRARY := $(SHARED_LIBRARY_NAME) +else +SHARED_LIBRARY := $(DLL_PREFIX)$(SHARED_LIBRARY_NAME)$(DLL_SUFFIX) +endif + +ifeq ($(OS_ARCH),OS2) +DEF_FILE := $(SHARED_LIBRARY:.dll=.def) +endif + +ifdef MOZ_ENABLE_LIBXUL +EMBED_MANIFEST_AT=2 +endif + +endif # MKSHLIB +endif # FORCE_SHARED_LIB && !BUILD_STATIC_LIBS +endif # LIBRARY + +ifeq (,$(BUILD_STATIC_LIBS)$(FORCE_STATIC_LIB)) +LIBRARY := $(NULL) +endif + +ifeq (_1,$(FORCE_SHARED_LIB)_$(BUILD_STATIC_LIBS)) +SHARED_LIBRARY := $(NULL) +DEF_FILE := $(NULL) +IMPORT_LIBRARY := $(NULL) +endif + +ifdef FORCE_STATIC_LIB +ifndef FORCE_SHARED_LIB +SHARED_LIBRARY := $(NULL) +DEF_FILE := $(NULL) +IMPORT_LIBRARY := $(NULL) +endif +endif + +ifdef FORCE_SHARED_LIB +ifndef FORCE_STATIC_LIB +LIBRARY := $(NULL) +endif +endif + +ifdef JAVA_LIBRARY_NAME +JAVA_LIBRARY := $(JAVA_LIBRARY_NAME).jar +endif + +ifeq (,$(filter-out WINNT WINCE,$(OS_ARCH))) +ifndef GNU_CC + +# +# Unless we're building SIMPLE_PROGRAMS, all C++ files share a PDB file per +# directory. For parallel builds, this PDB file is shared and locked by +# MSPDBSRV.EXE, starting with MSVC8 SP1. If you're using MSVC 7.1 or MSVC8 +# without SP1, don't do parallel builds. +# +# The final PDB for libraries and programs is created by the linker and uses +# a different name from the single PDB file created by the compiler. See +# bug 462740. +# + +ifdef SIMPLE_PROGRAMS +COMPILE_PDBFILE = $(basename $(@F)).pdb +else +COMPILE_PDBFILE = generated.pdb +endif + +LINK_PDBFILE = $(basename $(@F)).pdb +ifdef MOZ_DEBUG +CODFILE=$(basename $(@F)).cod +endif + +ifdef MOZ_MAPINFO +ifdef SHARED_LIBRARY_NAME +MAPFILE=$(SHARED_LIBRARY_NAME).map +else +MAPFILE=$(basename $(@F)).map +endif # SHARED_LIBRARY_NAME +endif # MOZ_MAPINFO + +ifdef DEFFILE +OS_LDFLAGS += -DEF:$(call normalizepath,$(DEFFILE)) +EXTRA_DEPS += $(DEFFILE) +endif + +ifdef MAPFILE +OS_LDFLAGS += -MAP:$(MAPFILE) +endif + +endif # !GNU_CC + +ifdef ENABLE_CXX_EXCEPTIONS +CXXFLAGS += $(MOZ_EXCEPTIONS_FLAGS_ON) -DMOZ_CPP_EXCEPTIONS=1 +endif # ENABLE_CXX_EXCEPTIONS +endif # WINNT + +ifeq ($(SOLARIS_SUNPRO_CXX),1) +ifeq (86,$(findstring 86,$(OS_TEST))) +OS_LDFLAGS += -M $(topsrcdir)/config/solaris_ia32.map +endif # x86 +endif # Solaris Sun Studio C++ + +ifeq (,$(filter-out WINNT WINCE,$(HOST_OS_ARCH))) +HOST_PDBFILE=$(basename $(@F)).pdb +endif + +ifndef TARGETS +TARGETS = $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS) $(HOST_LIBRARY) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(JAVA_LIBRARY) +endif + +ifndef OBJS +_OBJS = \ + $(JRI_STUB_CFILES) \ + $(addsuffix .$(OBJ_SUFFIX), $(JMC_GEN)) \ + $(CSRCS:.c=.$(OBJ_SUFFIX)) \ + $(SSRCS:.S=.$(OBJ_SUFFIX)) \ + $(patsubst %.cc,%.$(OBJ_SUFFIX),$(CPPSRCS:.cpp=.$(OBJ_SUFFIX))) \ + $(CMSRCS:.m=.$(OBJ_SUFFIX)) \ + $(CMMSRCS:.mm=.$(OBJ_SUFFIX)) \ + $(ASFILES:.$(ASM_SUFFIX)=.$(OBJ_SUFFIX)) +OBJS = $(strip $(_OBJS)) +endif + +ifndef HOST_OBJS +_HOST_OBJS = \ + $(addprefix host_,$(HOST_CSRCS:.c=.$(OBJ_SUFFIX))) \ + $(addprefix host_,$(patsubst %.cc,%.$(OBJ_SUFFIX),$(HOST_CPPSRCS:.cpp=.$(OBJ_SUFFIX)))) \ + $(addprefix host_,$(HOST_CMSRCS:.m=.$(OBJ_SUFFIX))) \ + $(addprefix host_,$(HOST_CMMSRCS:.mm=.$(OBJ_SUFFIX))) +HOST_OBJS = $(strip $(_HOST_OBJS)) +endif + +LIBOBJS := $(addprefix \", $(OBJS)) +LIBOBJS := $(addsuffix \", $(LIBOBJS)) + +ifndef MOZ_AUTO_DEPS +ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS)) +MDDEPFILES = $(addprefix $(MDDEPDIR)/,$(OBJS:.$(OBJ_SUFFIX)=.pp)) +ifndef NO_GEN_XPT +MDDEPFILES += $(addprefix $(MDDEPDIR)/,$(XPIDLSRCS:.idl=.xpt)) +endif +endif +endif + +ALL_TRASH = \ + $(GARBAGE) $(TARGETS) $(OBJS) $(PROGOBJS) LOGS TAGS a.out \ + $(filter-out $(ASFILES),$(OBJS:.$(OBJ_SUFFIX)=.s)) $(OBJS:.$(OBJ_SUFFIX)=.ii) \ + $(OBJS:.$(OBJ_SUFFIX)=.i) \ + $(HOST_PROGOBJS) $(HOST_OBJS) $(IMPORT_LIBRARY) $(DEF_FILE)\ + $(EXE_DEF_FILE) so_locations _gen _stubs $(wildcard *.res) $(wildcard *.RES) \ + $(wildcard *.pdb) $(CODFILE) $(MAPFILE) $(IMPORT_LIBRARY) \ + $(SHARED_LIBRARY:$(DLL_SUFFIX)=.exp) $(wildcard *.ilk) \ + $(PROGRAM:$(BIN_SUFFIX)=.exp) $(SIMPLE_PROGRAMS:$(BIN_SUFFIX)=.exp) \ + $(PROGRAM:$(BIN_SUFFIX)=.lib) $(SIMPLE_PROGRAMS:$(BIN_SUFFIX)=.lib) \ + $(SIMPLE_PROGRAMS:$(BIN_SUFFIX)=.$(OBJ_SUFFIX)) \ + $(wildcard gts_tmp_*) $(LIBRARY:%.a=.%.timestamp) +ALL_TRASH_DIRS = \ + $(GARBAGE_DIRS) /no-such-file + +ifdef QTDIR +GARBAGE += $(MOCSRCS) +endif + +ifdef SIMPLE_PROGRAMS +GARBAGE += $(SIMPLE_PROGRAMS:%=%.$(OBJ_SUFFIX)) +endif + +ifdef HOST_SIMPLE_PROGRAMS +GARBAGE += $(HOST_SIMPLE_PROGRAMS:%=%.$(OBJ_SUFFIX)) +endif + +# +# the Solaris WorkShop template repository cache. it occasionally can get +# out of sync, so targets like clobber should kill it. +# +ifeq ($(SOLARIS_SUNPRO_CXX),1) +GARBAGE_DIRS += SunWS_cache +endif + +ifeq ($(OS_ARCH),OpenVMS) +GARBAGE += $(wildcard *.*_defines) +ifdef SHARED_LIBRARY +VMS_SYMVEC_FILE = $(SHARED_LIBRARY:$(DLL_SUFFIX)=_symvec.opt) +ifdef MOZ_DEBUG +VMS_SYMVEC_FILE_MODULE = $(topsrcdir)/build/unix/vms/$(notdir $(SHARED_LIBRARY:$(DLL_SUFFIX)=_dbg_symvec.opt)) +else +VMS_SYMVEC_FILE_MODULE = $(topsrcdir)/build/unix/vms/$(notdir $(SHARED_LIBRARY:$(DLL_SUFFIX)=_symvec.opt)) +endif +VMS_SYMVEC_FILE_COMP = $(topsrcdir)/build/unix/vms/component_symvec.opt +GARBAGE += $(VMS_SYMVEC_FILE) +ifdef IS_COMPONENT +DSO_LDOPTS := $(filter-out -auto_symvec,$(DSO_LDOPTS)) $(VMS_SYMVEC_FILE) +endif +endif +endif + +XPIDL_GEN_DIR = _xpidlgen + +ifdef MOZ_UPDATE_XTERM +# Its good not to have a newline at the end of the titlebar string because it +# makes the make -s output easier to read. Echo -n does not work on all +# platforms, but we can trick sed into doing it. +UPDATE_TITLE = sed -e "s!Y!$(1) in $(shell $(BUILD_TOOLS)/print-depth-path.sh)/$(2)!" $(MOZILLA_DIR)/config/xterm.str; +endif + +define SUBMAKE # $(call SUBMAKE,target,directory) ++@$(UPDATE_TITLE) ++@$(MAKE) $(if $(2),-C $(2)) $(1) + +endef # The extra line is important here! don't delete it + +ifneq (,$(strip $(DIRS))) +LOOP_OVER_DIRS = \ + $(foreach dir,$(DIRS),$(call SUBMAKE,$@,$(dir))) +endif + +# we only use this for the makefiles target and other stuff that doesn't matter +ifneq (,$(strip $(PARALLEL_DIRS))) +LOOP_OVER_PARALLEL_DIRS = \ + $(foreach dir,$(PARALLEL_DIRS),$(call SUBMAKE,$@,$(dir))) +endif + +ifneq (,$(strip $(STATIC_DIRS))) +LOOP_OVER_STATIC_DIRS = \ + $(foreach dir,$(STATIC_DIRS),$(call SUBMAKE,$@,$(dir))) +endif + +ifneq (,$(strip $(TOOL_DIRS))) +LOOP_OVER_TOOL_DIRS = \ + $(foreach dir,$(TOOL_DIRS),$(call SUBMAKE,$@,$(dir))) +endif + +ifdef PARALLEL_DIRS +# create a bunch of fake targets for order-only processing +PARALLEL_DIRS_export = $(addsuffix _export,$(PARALLEL_DIRS)) +PARALLEL_DIRS_libs = $(addsuffix _libs,$(PARALLEL_DIRS)) +PARALLEL_DIRS_tools = $(addsuffix _tools,$(PARALLEL_DIRS)) + +.PHONY: $(PARALLEL_DIRS_export) $(PARALLEL_DIRS_libs) $(PARALLEL_DIRS_tools) +endif + +# +# Now we can differentiate between objects used to build a library, and +# objects used to build an executable in the same directory. +# +ifndef PROGOBJS +PROGOBJS = $(OBJS) +endif + +ifndef HOST_PROGOBJS +HOST_PROGOBJS = $(HOST_OBJS) +endif + +# MAKE_DIRS: List of directories to build while looping over directories. +# A Makefile that needs $(MDDEPDIR) created but doesn't set any of these +# variables we know to check can just set NEED_MDDEPDIR explicitly. +ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS)$(NEED_MDDEPDIR)) +MAKE_DIRS += $(CURDIR)/$(MDDEPDIR) +GARBAGE_DIRS += $(MDDEPDIR) +endif + +# +# Tags: emacs (etags), vi (ctags) +# TAG_PROGRAM := ctags -L - +# +TAG_PROGRAM = xargs etags -a + +# +# Turn on C++ linking if we have any .cpp or .mm files +# (moved this from config.mk so that config.mk can be included +# before the CPPSRCS are defined) +# +ifneq ($(CPPSRCS)$(CMMSRCS),) +CPP_PROG_LINK = 1 +endif +ifneq ($(HOST_CPPSRCS)$(HOST_CMMSRCS),) +HOST_CPP_PROG_LINK = 1 +endif + +# +# Make sure to wrap static libs inside linker specific flags to turn on & off +# inclusion of all symbols inside the static libs +# +ifndef NO_LD_ARCHIVE_FLAGS +ifdef SHARED_LIBRARY_LIBS +EXTRA_DSO_LDOPTS := $(MKSHLIB_FORCE_ALL) $(call EXPAND_FAKELIBS,$(SHARED_LIBRARY_LIBS)) $(MKSHLIB_UNFORCE_ALL) $(EXTRA_DSO_LDOPTS) +endif +endif + +# +# This will strip out symbols that the component should not be +# exporting from the .dynsym section. +# +ifdef IS_COMPONENT +EXTRA_DSO_LDOPTS += $(MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS) +endif # IS_COMPONENT + +# +# Enforce the requirement that MODULE_NAME must be set +# for components in static builds +# +ifdef IS_COMPONENT +ifdef EXPORT_LIBRARY +ifndef FORCE_SHARED_LIB +ifndef MODULE_NAME +$(error MODULE_NAME is required for components which may be used in static builds) +endif +endif +endif +endif + +# +# MacOS X specific stuff +# + +ifeq ($(OS_ARCH),Darwin) +ifdef SHARED_LIBRARY +ifdef IS_COMPONENT +EXTRA_DSO_LDOPTS += -bundle +else +EXTRA_DSO_LDOPTS += -dynamiclib -install_name @executable_path/$(SHARED_LIBRARY) -compatibility_version 1 -current_version 1 -single_module +endif +endif +endif + +# +# On NetBSD a.out systems, use -Bsymbolic. This fixes what would otherwise be +# fatal symbol name clashes between components. +# +ifeq ($(OS_ARCH),NetBSD) +ifeq ($(DLL_SUFFIX),.so.1.0) +ifdef IS_COMPONENT +EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic +endif +endif +endif + +ifeq ($(OS_ARCH),FreeBSD) +ifdef IS_COMPONENT +EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic +endif +endif + +ifeq ($(OS_ARCH),NetBSD) +ifneq (,$(filter arc cobalt hpcmips mipsco newsmips pmax sgimips,$(OS_TEST))) +ifeq ($(MODULE),layout) +OS_CFLAGS += -Wa,-xgot +OS_CXXFLAGS += -Wa,-xgot +endif +endif +endif + +# +# HP-UXBeOS specific section: for COMPONENTS only, add -Bsymbolic flag +# which uses internal symbols first +# +ifeq ($(OS_ARCH),HP-UX) +ifdef IS_COMPONENT +ifeq ($(GNU_CC)$(GNU_CXX),) +EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic +ifneq ($(HAS_EXTRAEXPORTS),1) +MKSHLIB += -Wl,+eNSGetModule -Wl,+eerrno +MKCSHLIB += +eNSGetModule +eerrno +ifneq ($(OS_TEST),ia64) +MKSHLIB += -Wl,+e_shlInit +MKCSHLIB += +e_shlInit +endif # !ia64 +endif # !HAS_EXTRAEXPORTS +endif # non-gnu compilers +endif # IS_COMPONENT +endif # HP-UX + +ifeq ($(OS_ARCH),AIX) +ifdef IS_COMPONENT +ifneq ($(HAS_EXTRAEXPORTS),1) +MKSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall +MKCSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall +endif # HAS_EXTRAEXPORTS +endif # IS_COMPONENT +endif # AIX + +# +# OSF1: add -B symbolic flag for components +# +ifeq ($(OS_ARCH),OSF1) +ifdef IS_COMPONENT +ifeq ($(GNU_CC)$(GNU_CXX),) +EXTRA_DSO_LDOPTS += -B symbolic +endif +endif +endif + +# +# Linux: add -Bsymbolic flag for components +# +ifeq ($(OS_ARCH),Linux) +ifdef IS_COMPONENT +EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic +endif +endif + +# +# GNU doesn't have path length limitation +# + +ifeq ($(OS_ARCH),GNU) +OS_CPPFLAGS += -DPATH_MAX=1024 -DMAXPATHLEN=1024 +endif + +# +# MINGW32 +# +ifeq ($(OS_ARCH),WINNT) +ifdef GNU_CC +ifndef IS_COMPONENT +DSO_LDOPTS += -Wl,--out-implib -Wl,$(IMPORT_LIBRARY) +endif +endif +endif + +ifeq ($(USE_TVFS),1) +IFLAGS1 = -rb +IFLAGS2 = -rb +else +IFLAGS1 = -m 644 +IFLAGS2 = -m 755 +endif + +ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH)) +OUTOPTION = -Fo# eol +else +OUTOPTION = -o # eol +endif # WINNT && !GNU_CC +ifneq (,$(filter WINCE,$(OS_ARCH))) +OUTOPTION = -Fo# eol +endif + +ifeq ($(OS_ARCH), WINCE) +OUTOPTION = -Fo# eol +HOST_OUTOPTION = -Fo# eol +else + +ifeq (,$(CROSS_COMPILE)) +HOST_OUTOPTION = $(OUTOPTION) +else +HOST_OUTOPTION = -o # eol +endif + +endif +################################################################################ + +# SUBMAKEFILES: List of Makefiles for next level down. +# This is used to update or create the Makefiles before invoking them. +SUBMAKEFILES += $(addsuffix /Makefile, $(DIRS) $(TOOL_DIRS) $(PARALLEL_DIRS)) + +# The root makefile doesn't want to do a plain export/libs, because +# of the tiers and because of libxul. Suppress the default rules in favor +# of something else. Makefiles which use this var *must* provide a sensible +# default rule before including rules.mk +ifndef SUPPRESS_DEFAULT_RULES +ifdef TIERS +default all alldep:: + $(foreach tier,$(TIERS),$(call SUBMAKE,tier_$(tier))) +else + +default all:: +ifneq (,$(strip $(STATIC_DIRS))) + $(foreach dir,$(STATIC_DIRS),$(call SUBMAKE,,$(dir))) +endif + $(MAKE) export + $(MAKE) libs + $(MAKE) tools + +# Do depend as well +alldep:: + $(MAKE) export + $(MAKE) depend + $(MAKE) libs + $(MAKE) tools + +endif # TIERS +endif # SUPPRESS_DEFAULT_RULES + +ifeq ($(filter s,$(MAKEFLAGS)),) +ECHO := echo +QUIET := +else +ECHO := true +QUIET := -q +endif + +MAKE_TIER_SUBMAKEFILES = +$(if $(tier_$*_dirs),$(MAKE) $(addsuffix /Makefile,$(tier_$*_dirs))) + +export_tier_%: + @$(ECHO) "$@" + @$(MAKE_TIER_SUBMAKEFILES) + $(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,export,$(dir))) + +libs_tier_%: + @$(ECHO) "$@" + @$(MAKE_TIER_SUBMAKEFILES) + $(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,libs,$(dir))) + +tools_tier_%: + @$(ECHO) "$@" + @$(MAKE_TIER_SUBMAKEFILES) + $(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,tools,$(dir))) + +$(foreach tier,$(TIERS),tier_$(tier)):: + @$(ECHO) "$@: $($@_staticdirs) $($@_dirs)" + $(foreach dir,$($@_staticdirs),$(call SUBMAKE,,$(dir))) + $(MAKE) export_$@ + $(MAKE) libs_$@ + $(MAKE) tools_$@ + +# Do everything from scratch +everything:: + $(MAKE) clean + $(MAKE) alldep + +# Add dummy depend target for tinderboxes +depend:: + +# Target to only regenerate makefiles +makefiles: $(SUBMAKEFILES) +ifneq (,$(DIRS)$(TOOL_DIRS)$(PARALLEL_DIRS)) + $(LOOP_OVER_PARALLEL_DIRS) + $(LOOP_OVER_DIRS) + $(LOOP_OVER_TOOL_DIRS) +endif + +ifdef PARALLEL_DIRS +export:: $(PARALLEL_DIRS_export) + +$(PARALLEL_DIRS_export): %_export: %/Makefile + +@$(call SUBMAKE,export,$*) +endif + +export:: $(SUBMAKEFILES) $(MAKE_DIRS) $(if $(XPIDLSRCS),$(IDL_DIR)) + $(LOOP_OVER_DIRS) + $(LOOP_OVER_TOOL_DIRS) + +ifdef PARALLEL_DIRS +tools:: $(PARALLEL_DIRS_tools) + +$(PARALLEL_DIRS_tools): %_tools: %/Makefile + +@$(call SUBMAKE,tools,$*) +endif + +tools:: $(SUBMAKEFILES) $(MAKE_DIRS) + $(LOOP_OVER_DIRS) +ifneq (,$(strip $(TOOL_DIRS))) + $(foreach dir,$(TOOL_DIRS),$(call SUBMAKE,libs,$(dir))) +endif + +# +# Rule to create list of libraries for final link +# +export:: +ifdef LIBRARY_NAME +ifdef EXPORT_LIBRARY +ifdef IS_COMPONENT +ifdef BUILD_STATIC_LIBS + @$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_LINK_COMPS) $(STATIC_LIBRARY_NAME) +ifdef MODULE_NAME + @$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_LINK_COMP_NAMES) $(MODULE_NAME) +endif +endif # BUILD_STATIC_LIBS +else # !IS_COMPONENT + $(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_LINK_LIBS) $(STATIC_LIBRARY_NAME) +endif # IS_COMPONENT +endif # EXPORT_LIBRARY +endif # LIBRARY_NAME + +# Create dependencies on static (and shared EXTRA_DSO_LIBS) libraries +LIBS_DEPS = $(filter %.$(LIB_SUFFIX), $(LIBS)) +HOST_LIBS_DEPS = $(filter %.$(LIB_SUFFIX), $(HOST_LIBS)) +DSO_LDOPTS_DEPS = $(EXTRA_DSO_LIBS) $(filter %.$(LIB_SUFFIX), $(EXTRA_DSO_LDOPTS)) + +ifndef _LIBNAME_RELATIVE_PATHS + +LIBS_DEPS += $(filter -l%, $(LIBS)) +HOST_LIBS_DEPS += $(filter -l%, $(HOST_LIBS)) +DSO_LDOPTS_DEPS += $(filter -l%, $(EXTRA_DSO_LDOPTS)) + +_LIBDIRS = $(patsubst -L%,%,$(filter -L%, $(LIBS) $(HOST_LIBS) $(EXTRA_DSO_LDOPTS))) +ifneq (,$(_LIBDIRS)) +vpath $(LIB_PREFIX)%.$(LIB_SUFFIX) $(_LIBDIRS) +ifdef IMPORT_LIB_SUFFIX +vpath $(LIB_PREFIX)%.$(IMPORT_LIB_SUFFIX) $(_LIBDIRS) +endif # IMPORT_LIB_SUFFIX +vpath $(DLL_PREFIX)%$(DLL_SUFFIX) $(_LIBDIRS) +endif # _LIBDIRS + +endif # _LIBNAME_RELATIVE_PATHS + +# Dependencies which, if modified, should cause everything to rebuild +GLOBAL_DEPS += Makefile Makefile.in $(DEPTH)/config/autoconf.mk $(topsrcdir)/config/config.mk + +############################################## +ifdef PARALLEL_DIRS +libs:: $(PARALLEL_DIRS_libs) + +$(PARALLEL_DIRS_libs): %_libs: %/Makefile + +@$(call SUBMAKE,libs,$*) +endif + +libs:: $(SUBMAKEFILES) $(MAKE_DIRS) $(HOST_LIBRARY) $(LIBRARY) $(SHARED_LIBRARY) $(IMPORT_LIBRARY) $(HOST_PROGRAM) $(PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(SIMPLE_PROGRAMS) $(JAVA_LIBRARY) +ifndef NO_DIST_INSTALL +ifdef LIBRARY +ifdef EXPORT_LIBRARY # Stage libs that will be linked into a static build +ifdef IS_COMPONENT + $(INSTALL) $(IFLAGS1) $(LIBRARY) $(FAKE_LIBRARY) $(DEPTH)/staticlib/components +else + $(INSTALL) $(IFLAGS1) $(LIBRARY) $(FAKE_LIBRARY) $(DEPTH)/staticlib +endif +endif # EXPORT_LIBRARY +ifdef DIST_INSTALL +ifdef IS_COMPONENT + $(error Shipping static component libs makes no sense.) +else + $(INSTALL) $(IFLAGS1) $(LIBRARY) $(DIST)/lib +endif +endif # DIST_INSTALL +endif # LIBRARY +ifdef SHARED_LIBRARY +ifdef IS_COMPONENT + $(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(FINAL_TARGET)/components + $(ELF_DYNSTR_GC) $(FINAL_TARGET)/components/$(SHARED_LIBRARY) +ifndef NO_COMPONENTS_MANIFEST + @$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/components.manifest" + @$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/components.manifest "binary-component $(SHARED_LIBRARY)" +endif +ifdef BEOS_ADDON_WORKAROUND + ( cd $(FINAL_TARGET)/components && $(CC) -nostart -o $(SHARED_LIBRARY).stub $(SHARED_LIBRARY) ) +endif +else # ! IS_COMPONENT +ifneq (,$(filter OS2 WINNT WINCE,$(OS_ARCH))) + $(INSTALL) $(IFLAGS2) $(IMPORT_LIBRARY) $(DIST)/lib +else + $(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(DIST)/lib +endif + $(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(FINAL_TARGET) +ifdef BEOS_ADDON_WORKAROUND + ( cd $(FINAL_TARGET) && $(CC) -nostart -o $(SHARED_LIBRARY).stub $(SHARED_LIBRARY) ) +endif +endif # IS_COMPONENT +endif # SHARED_LIBRARY +ifdef PROGRAM + $(INSTALL) $(IFLAGS2) $(PROGRAM) $(FINAL_TARGET) +endif +ifdef SIMPLE_PROGRAMS + $(INSTALL) $(IFLAGS2) $(SIMPLE_PROGRAMS) $(FINAL_TARGET) +endif +ifdef HOST_PROGRAM + $(INSTALL) $(IFLAGS2) $(HOST_PROGRAM) $(DIST)/host/bin +endif +ifdef HOST_SIMPLE_PROGRAMS + $(INSTALL) $(IFLAGS2) $(HOST_SIMPLE_PROGRAMS) $(DIST)/host/bin +endif +ifdef HOST_LIBRARY + $(INSTALL) $(IFLAGS1) $(HOST_LIBRARY) $(DIST)/host/lib +endif +ifdef JAVA_LIBRARY +ifdef IS_COMPONENT + $(INSTALL) $(IFLAGS1) $(JAVA_LIBRARY) $(FINAL_TARGET)/components +else + $(INSTALL) $(IFLAGS1) $(JAVA_LIBRARY) $(FINAL_TARGET) +endif +endif # JAVA_LIBRARY +endif # !NO_DIST_INSTALL + $(LOOP_OVER_DIRS) + +############################################## + +ifndef NO_PROFILE_GUIDED_OPTIMIZE +ifdef MOZ_PROFILE_USE +ifeq ($(OS_ARCH)_$(GNU_CC), WINNT_) +# When building with PGO, we have to make sure to re-link +# in the MOZ_PROFILE_USE phase if we linked in the +# MOZ_PROFILE_GENERATE phase. We'll touch this pgo.relink +# file in the link rule in the GENERATE phase to indicate +# that we need a relink. +ifdef SHARED_LIBRARY +$(SHARED_LIBRARY): pgo.relink +endif +ifdef PROGRAM +$(PROGRAM): pgo.relink +endif + +# In the second pass, we need to merge the pgc files into the pgd file. +# The compiler would do this for us automatically if they were in the right +# place, but they're in dist/bin. +ifneq (,$(SHARED_LIBRARY)$(PROGRAM)) +export:: +ifdef PROGRAM + $(PYTHON) $(topsrcdir)/build/win32/pgomerge.py \ + $(PROGRAM:$(BIN_SUFFIX)=) $(DIST)/$(MOZ_APP_NAME) +endif +ifdef SHARED_LIBRARY + $(PYTHON) $(topsrcdir)/build/win32/pgomerge.py \ + $(SHARED_LIBRARY_NAME) $(DIST)/$(MOZ_APP_NAME) +endif +endif # SHARED_LIBRARY || PROGRAM +endif # WINNT_ +endif # MOZ_PROFILE_GENERATE || MOZ_PROFILE_USE +endif # NO_PROFILE_GUIDED_OPTIMIZE + +############################################## + +checkout: + $(MAKE) -C $(topsrcdir) -f client.mk checkout + +clean clobber realclean clobber_all:: $(SUBMAKEFILES) + -rm -f $(ALL_TRASH) + -rm -rf $(ALL_TRASH_DIRS) + $(foreach dir,$(PARALLEL_DIRS) $(DIRS) $(STATIC_DIRS) $(TOOL_DIRS),-$(call SUBMAKE,$@,$(dir))) + +distclean:: $(SUBMAKEFILES) + $(foreach dir,$(PARALLEL_DIRS) $(DIRS) $(STATIC_DIRS) $(TOOL_DIRS),-$(call SUBMAKE,$@,$(dir))) + -rm -rf $(ALL_TRASH_DIRS) + -rm -f $(ALL_TRASH) \ + Makefile .HSancillary \ + $(wildcard *.$(OBJ_SUFFIX)) $(wildcard *.ho) $(wildcard host_*.o*) \ + $(wildcard *.$(LIB_SUFFIX)) $(wildcard *$(DLL_SUFFIX)) \ + $(wildcard *.$(IMPORT_LIB_SUFFIX)) +ifeq ($(OS_ARCH),OS2) + -rm -f $(PROGRAM:.exe=.map) +endif + +alltags: + rm -f TAGS + find $(topsrcdir) -name dist -prune -o \( -name '*.[hc]' -o -name '*.cp' -o -name '*.cpp' -o -name '*.idl' \) -print | $(TAG_PROGRAM) + +# +# PROGRAM = Foo +# creates OBJS, links with LIBS to create Foo +# +$(PROGRAM): $(PROGOBJS) $(LIBS_DEPS) $(EXTRA_DEPS) $(EXE_DEF_FILE) $(RESFILE) $(GLOBAL_DEPS) + @rm -f $@.manifest +ifeq (WINCE,$(OS_ARCH)) + $(LD) -NOLOGO -OUT:$@ $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(PROGOBJS) $(RESFILE) $(call EXPAND_FAKELIBS,$(LIBS) $(EXTRA_LIBS) $(OS_LIBS)) +else +ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH)) + $(LD) -NOLOGO -OUT:$@ -PDB:$(LINK_PDBFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(PROGOBJS) $(RESFILE) $(call EXPAND_FAKELIBS,$(LIBS) $(EXTRA_LIBS) $(OS_LIBS)) +ifdef MSMANIFEST_TOOL + @if test -f $@.manifest; then \ + if test -f "$(srcdir)/$@.manifest"; then \ + echo "Embedding manifest from $(srcdir)/$@.manifest and $@.manifest"; \ + mt.exe -NOLOGO -MANIFEST "$(win_srcdir)/$@.manifest" $@.manifest -OUTPUTRESOURCE:$@\;1; \ + else \ + echo "Embedding manifest from $@.manifest"; \ + mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \ + fi; \ + elif test -f "$(srcdir)/$@.manifest"; then \ + echo "Embedding manifest from $(srcdir)/$@.manifest"; \ + mt.exe -NOLOGO -MANIFEST "$(win_srcdir)/$@.manifest" -OUTPUTRESOURCE:$@\;1; \ + fi +endif # MSVC with manifest tool +ifdef MOZ_PROFILE_GENERATE +# touch it a few seconds into the future to work around FAT's +# 2-second granularity + touch -t `date +%Y%m%d%H%M.%S -d "now+5seconds"` pgo.relink +endif +else # !WINNT || GNU_CC +ifeq ($(CPP_PROG_LINK),1) + $(CCC) -o $@ $(CXXFLAGS) $(WRAP_MALLOC_CFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(LIBS_DIR) $(call EXPAND_FAKELIBS,$(LIBS) $(OS_LIBS) $(EXTRA_LIBS)) $(BIN_FLAGS) $(call EXPAND_FAKELIBS,$(WRAP_MALLOC_LIB)) $(EXE_DEF_FILE) +else # ! CPP_PROG_LINK + $(CC) -o $@ $(CFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(LIBS_DIR) $(call EXPAND_FAKELIBS,$(LIBS) $(OS_LIBS) $(EXTRA_LIBS)) $(BIN_FLAGS) $(EXE_DEF_FILE) +endif # CPP_PROG_LINK +endif # WINNT && !GNU_CC +endif # WINCE + +ifdef ENABLE_STRIP + $(STRIP) $@ +endif +ifdef MOZ_POST_PROGRAM_COMMAND + $(MOZ_POST_PROGRAM_COMMAND) $@ +endif +ifeq ($(OS_ARCH),BeOS) +ifdef BEOS_PROGRAM_RESOURCE + xres -o $@ $(BEOS_PROGRAM_RESOURCE) + mimeset $@ +endif +endif # BeOS + +$(HOST_PROGRAM): $(HOST_PROGOBJS) $(HOST_LIBS_DEPS) $(HOST_EXTRA_DEPS) $(GLOBAL_DEPS) +ifeq (WINCE,$(OS_ARCH)) + $(HOST_LD) -NOLOGO -OUT:$@ $(HOST_OBJS) $(WIN32_EXE_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) +else +ifeq (_WINNT,$(GNU_CC)_$(HOST_OS_ARCH)) + $(HOST_LD) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $(HOST_OBJS) $(WIN32_EXE_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) +ifdef MSMANIFEST_TOOL + @if test -f $@.manifest; then \ + if test -f "$(srcdir)/$@.manifest"; then \ + echo "Embedding manifest from $(srcdir)/$@.manifest and $@.manifest"; \ + mt.exe -NOLOGO -MANIFEST "$(win_srcdir)/$@.manifest" $@.manifest -OUTPUTRESOURCE:$@\;1; \ + else \ + echo "Embedding manifest from $@.manifest"; \ + mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \ + fi; \ + elif test -f "$(srcdir)/$@.manifest"; then \ + echo "Embedding manifest from $(srcdir)/$@.manifest"; \ + mt.exe -NOLOGO -MANIFEST "$(win_srcdir)/$@.manifest" -OUTPUTRESOURCE:$@\;1; \ + fi +endif # MSVC with manifest tool +else +ifeq ($(HOST_CPP_PROG_LINK),1) + $(HOST_CXX) -o $@ $(HOST_CXXFLAGS) $(HOST_LDFLAGS) $(HOST_PROGOBJS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) +else + $(HOST_CC) -o $@ $(HOST_CFLAGS) $(HOST_LDFLAGS) $(HOST_PROGOBJS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) +endif # HOST_CPP_PROG_LINK +endif +endif + +# +# This is an attempt to support generation of multiple binaries +# in one directory, it assumes everything to compile Foo is in +# Foo.o (from either Foo.c or Foo.cpp). +# +# SIMPLE_PROGRAMS = Foo Bar +# creates Foo.o Bar.o, links with LIBS to create Foo, Bar. +# +$(SIMPLE_PROGRAMS): %$(BIN_SUFFIX): %.$(OBJ_SUFFIX) $(LIBS_DEPS) $(EXTRA_DEPS) $(GLOBAL_DEPS) +ifeq (WINCE,$(OS_ARCH)) + $(LD) -nologo -entry:mainACRTStartup -out:$@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(call EXPAND_FAKELIBS,$(LIBS) $(EXTRA_LIBS) $(OS_LIBS)) +else +ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH)) + $(LD) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(call EXPAND_FAKELIBS,$(LIBS) $(EXTRA_LIBS) $(OS_LIBS)) +ifdef MSMANIFEST_TOOL + @if test -f $@.manifest; then \ + mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \ + rm -f $@.manifest; \ + fi +endif # MSVC with manifest tool +else +ifeq ($(CPP_PROG_LINK),1) + $(CCC) $(WRAP_MALLOC_CFLAGS) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(LIBS_DIR) $(call EXPAND_FAKELIBS,$(LIBS) $(OS_LIBS) $(EXTRA_LIBS) $(WRAP_MALLOC_LIB)) $(BIN_FLAGS) +else + $(CC) $(WRAP_MALLOC_CFLAGS) $(CFLAGS) $(OUTOPTION)$@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(LIBS_DIR) $(call EXPAND_FAKELIBS,$(LIBS) $(OS_LIBS) $(EXTRA_LIBS) $(WRAP_MALLOC_LIB)) $(BIN_FLAGS) +endif # CPP_PROG_LINK +endif # WINNT && !GNU_CC +endif # WINCE + +ifdef ENABLE_STRIP + $(STRIP) $@ +endif +ifdef MOZ_POST_PROGRAM_COMMAND + $(MOZ_POST_PROGRAM_COMMAND) $@ +endif + +$(HOST_SIMPLE_PROGRAMS): host_%$(HOST_BIN_SUFFIX): host_%.$(OBJ_SUFFIX) $(HOST_LIBS_DEPS) $(HOST_EXTRA_DEPS) $(GLOBAL_DEPS) +ifeq (WINCE,$(OS_ARCH)) + $(HOST_LD) -NOLOGO -OUT:$@ $(WIN32_EXE_LDFLAGS) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS) +else +ifeq (WINNT_,$(HOST_OS_ARCH)_$(GNU_CC)) + $(HOST_LD) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS) +else +ifneq (,$(HOST_CPPSRCS)$(USE_HOST_CXX)) + $(HOST_CXX) $(HOST_OUTOPTION)$@ $(HOST_CXXFLAGS) $(INCLUDES) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS) +else + $(HOST_CC) $(HOST_OUTOPTION)$@ $(HOST_CFLAGS) $(INCLUDES) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS) +endif +endif +endif + +# +# Purify target. Solaris/sparc only to start. +# Purify does not recognize "egcs" or "c++" so we go with +# "gcc" and "g++" for now. +# +pure: $(PROGRAM) +ifeq ($(CPP_PROG_LINK),1) + $(PURIFY) $(CCC) -o $^.pure $(CXXFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS) +else + $(PURIFY) $(CC) -o $^.pure $(CFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS) +endif +ifndef NO_DIST_INSTALL + $(INSTALL) $(IFLAGS2) $^.pure $(FINAL_TARGET) +endif + +quantify: $(PROGRAM) +ifeq ($(CPP_PROG_LINK),1) + $(QUANTIFY) $(CCC) -o $^.quantify $(CXXFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS) +else + $(QUANTIFY) $(CC) -o $^.quantify $(CFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS) +endif +ifndef NO_DIST_INSTALL + $(INSTALL) $(IFLAGS2) $^.quantify $(FINAL_TARGET) +endif + +# +# This allows us to create static versions of the shared libraries +# that are built using other static libraries. Confused...? +# +ifdef SHARED_LIBRARY_LIBS +ifeq (,$(GNU_LD)$(filter-out OS2 WINNT WINCE, $(OS_ARCH))) +ifneq (,$(BUILD_STATIC_LIBS)$(FORCE_STATIC_LIB)) +LOBJS += $(SHARED_LIBRARY_LIBS) +endif +else +NONFAKE_SHARED_LIBRARY_LIBS = $(filter-out %.fake,$(call EXPAND_FAKELIBS,$(SHARED_LIBRARY_LIBS))) +ifeq (,$(NONFAKE_SHARED_LIBRARY_LIBS)) +# All of our SHARED_LIBRARY_LIBS have fake equivalents. Score! +# Just pass the original object files around. +# For shared libraries, these are already included in EXTRA_DSO_LDOPTS +# above. +ifndef SHARED_LIBRARY +LOBJS += $(shell cat $(addsuffix .fake,$(SHARED_LIBRARY_LIBS))) +endif +SKIP_SUB_LOBJS := 1 +else +ifneq (,$(filter OSF1 BSD_OS FreeBSD NetBSD OpenBSD SunOS Darwin,$(OS_ARCH))) +CLEANUP1 := | egrep -v '(________64ELEL_|__.SYMDEF)' +CLEANUP2 := rm -f ________64ELEL_ __.SYMDEF +else +CLEANUP2 := true +endif +SUB_LOBJS = $(shell for lib in $(SHARED_LIBRARY_LIBS); do $(AR_LIST) $${lib} $(CLEANUP1); done;) +endif # EXPAND_FAKELIBS +endif # SHARED_LIBRARY_LIBS +endif +ifdef MOZILLA_PROBE_LIBS +PROBE_LOBJS = $(shell for lib in $(MOZILLA_PROBE_LIBS); do $(AR_LIST) $${lib} $(CLEANUP1); done;) +endif +ifdef DTRACE_PROBE_OBJ +EXTRA_DEPS += $(DTRACE_PROBE_OBJ) +endif + +$(LIBRARY): $(OBJS) $(LOBJS) $(SHARED_LIBRARY_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS) + rm -f $@ +ifndef SKIP_SUB_LOBJS +ifneq (,$(GNU_LD)$(filter-out OS2 WINNT WINCE, $(OS_ARCH))) +ifdef SHARED_LIBRARY_LIBS + @rm -f $(SUB_LOBJS) + @for lib in $(SHARED_LIBRARY_LIBS); do $(AR_EXTRACT) $${lib}; $(CLEANUP2); done +endif +endif +endif # SKIP_SUB_LOBJS + $(AR) $(AR_FLAGS) $(OBJS) $(LOBJS) $(SUB_LOBJS) + $(RANLIB) $@ +ifndef MOZ_FAKELIBS +# Don't clean these up if we're building a fake lib, because then +# we'll reference nonexistent object files in our fake lib. + @rm -f foodummyfilefoo $(SUB_LOBJS) +endif +# Also produce a .fake file that just contains the names of the object files. +# This can be used as a response file to the linker later instead of +# linking the actual static library. +ifdef MOZ_FAKELIBS +ifndef SUPPRESS_FAKELIB +ifeq (WINNT_,$(HOST_OS_ARCH)_$(.PYMAKE)) + echo "$(strip $(foreach f,$(OBJS) $(SEPARATE_OBJS) $(LOBJS) $(SUB_LOBJS),$(subst \,\\,$(call core_winabspath,$(f))))) " > $@.fake +else + echo "$(strip $(foreach f,$(OBJS) $(SEPARATE_OBJS) $(LOBJS) $(SUB_LOBJS),$(call core_abspath,$(f)))) " > $@.fake +endif +endif +endif + +ifeq (,$(filter-out WINNT WINCE, $(OS_ARCH))) +$(IMPORT_LIBRARY): $(SHARED_LIBRARY) +endif + +ifeq ($(OS_ARCH),OS2) +$(DEF_FILE): $(OBJS) $(SHARED_LIBRARY_LIBS) + rm -f $@ + echo LIBRARY $(SHARED_LIBRARY_NAME) INITINSTANCE TERMINSTANCE > $@ + echo PROTMODE >> $@ + echo CODE LOADONCALL MOVEABLE DISCARDABLE >> $@ + echo DATA PRELOAD MOVEABLE MULTIPLE NONSHARED >> $@ + echo EXPORTS >> $@ + + $(ADD_TO_DEF_FILE) + +$(IMPORT_LIBRARY): $(SHARED_LIBRARY) + rm -f $@ + $(IMPLIB) $@ $^ + $(RANLIB) $@ +endif # OS/2 + +$(HOST_LIBRARY): $(HOST_OBJS) Makefile + rm -f $@ + $(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS) + $(HOST_RANLIB) $@ + +ifdef NO_LD_ARCHIVE_FLAGS +SUB_SHLOBJS = $(SUB_LOBJS) +endif + +ifdef HAVE_DTRACE +ifndef XP_MACOSX +ifdef DTRACE_PROBE_OBJ +ifndef DTRACE_LIB_DEPENDENT +$(DTRACE_PROBE_OBJ): $(OBJS) + dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(OBJS) +endif +endif +endif +endif + +# On Darwin (Mac OS X), dwarf2 debugging uses debug info left in .o files, +# so instead of deleting .o files after repacking them into a dylib, we make +# symlinks back to the originals. The symlinks are a no-op for stabs debugging, +# so no need to conditionalize on OS version or debugging format. + +$(SHARED_LIBRARY): $(OBJS) $(LOBJS) $(DEF_FILE) $(RESFILE) $(SHARED_LIBRARY_LIBS) $(LIBRARY) $(EXTRA_DEPS) $(DSO_LDOPTS_DEPS) $(GLOBAL_DEPS) +ifndef INCREMENTAL_LINKER + rm -f $@ +endif +ifeq ($(OS_ARCH),OpenVMS) + @if test ! -f $(VMS_SYMVEC_FILE); then \ + if test -f $(VMS_SYMVEC_FILE_MODULE); then \ + echo Creating specific component options file $(VMS_SYMVEC_FILE); \ + cp $(VMS_SYMVEC_FILE_MODULE) $(VMS_SYMVEC_FILE); \ + fi; \ + fi +ifdef IS_COMPONENT + @if test ! -f $(VMS_SYMVEC_FILE); then \ + echo Creating generic component options file $(VMS_SYMVEC_FILE); \ + cp $(VMS_SYMVEC_FILE_COMP) $(VMS_SYMVEC_FILE); \ + fi +endif +endif # OpenVMS +ifdef NO_LD_ARCHIVE_FLAGS +ifdef SHARED_LIBRARY_LIBS + @rm -f $(SUB_SHLOBJS) + @for lib in $(SHARED_LIBRARY_LIBS); do $(AR_EXTRACT) $${lib}; $(CLEANUP2); done +ifeq ($(OS_ARCH),Darwin) + @echo Making symlinks to the original object files in the archive libraries $(SHARED_LIBRARY_LIBS) + @for lib in $(SHARED_LIBRARY_LIBS); do \ + libdir=`echo $$lib|sed -e 's,/[^/]*\.a,,'`; \ + ofiles=`$(AR_LIST) $${lib}`; \ + for ofile in $$ofiles; do \ + if [ -f $$libdir/$$ofile ]; then \ + rm -f $$ofile; \ + ln -s $$libdir/$$ofile $$ofile; \ + fi; \ + done; \ + done +endif +endif # SHARED_LIBRARY_LIBS +endif # NO_LD_ARCHIVE_FLAGS +ifdef DTRACE_LIB_DEPENDENT + @rm -f $(PROBE_LOBJS) + @for lib in $(MOZILLA_PROBE_LIBS); do $(AR_EXTRACT) $${lib}; $(CLEANUP2); done +ifndef XP_MACOSX + dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(PROBE_LOBJS) +endif + @for lib in $(MOZILLA_PROBE_LIBS); do \ + ofiles=`$(AR_LIST) $${lib}`; \ + $(AR_DELETE) $${lib} $$ofiles; \ + done + $(MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(LOBJS) $(SUB_SHLOBJS) $(DTRACE_PROBE_OBJ) $(PROBE_LOBJS) $(RESFILE) $(LDFLAGS) $(EXTRA_DSO_LDOPTS) $(call EXPAND_FAKELIBS,$(OS_LIBS) $(EXTRA_LIBS)) $(DEF_FILE) $(SHLIB_LDENDFILE) + @rm -f $(PROBE_LOBJS) + @rm -f $(DTRACE_PROBE_OBJ) + @for lib in $(MOZILLA_PROBE_LIBS); do \ + if [ -L $${lib} ]; then rm -f `readlink $${lib}`; fi; \ + done + @rm -f $(MOZILLA_PROBE_LIBS) + +else # ! DTRACE_LIB_DEPENDENT + $(MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(DTRACE_PROBE_OBJ) $(LOBJS) $(SUB_SHLOBJS) $(RESFILE) $(LDFLAGS) $(EXTRA_DSO_LDOPTS) $(call EXPAND_FAKELIBS,$(OS_LIBS) $(EXTRA_LIBS)) $(DEF_FILE) $(SHLIB_LDENDFILE) +endif # DTRACE_LIB_DEPENDENT + +ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH)) +ifdef MSMANIFEST_TOOL +ifdef EMBED_MANIFEST_AT + @if test -f $@.manifest; then \ + mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;$(EMBED_MANIFEST_AT); \ + rm -f $@.manifest; \ + fi +endif # EMBED_MANIFEST_AT +endif # MSVC with manifest tool +ifdef MOZ_PROFILE_GENERATE + touch -t `date +%Y%m%d%H%M.%S -d "now+5seconds"` pgo.relink +endif +endif # WINNT && !GCC +ifneq ($(OS_ARCH),Darwin) + @rm -f $(SUB_SHLOBJS) +endif # Darwin + @rm -f foodummyfilefoo $(DELETE_AFTER_LINK) + chmod +x $@ +ifdef ENABLE_STRIP + $(STRIP) $@ +endif +ifdef MOZ_POST_DSO_LIB_COMMAND + $(MOZ_POST_DSO_LIB_COMMAND) $@ +endif + +ifdef MOZ_AUTO_DEPS +ifdef COMPILER_DEPEND +ifeq ($(SOLARIS_SUNPRO_CC),1) +_MDDEPFILE = $(MDDEPDIR)/$(@F).pp + +define MAKE_DEPS_AUTO_CC +if test -d $(@D); then \ + echo "Building deps for $< using Sun Studio cc"; \ + $(CC) $(COMPILE_CFLAGS) -xM $< >$(_MDDEPFILE) ; \ +fi +endef +define MAKE_DEPS_AUTO_CXX +if test -d $(@D); then \ + echo "Building deps for $< using Sun Studio CC"; \ + $(CXX) $(COMPILE_CXXFLAGS) -xM $< >$(_MDDEPFILE) ; \ +fi +endef +endif # Sun Studio on Solaris +else # COMPILER_DEPEND +# +# Generate dependencies on the fly +# +_MDDEPFILE = $(MDDEPDIR)/$(@F).pp + +define MAKE_DEPS_AUTO +if test -d $(@D); then \ + echo "Building deps for $<"; \ + $(MKDEPEND) -o'.$(OBJ_SUFFIX)' -f- $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(INCLUDES) $< 2>/dev/null | sed -e "s|^[^ ]*/||" > $(_MDDEPFILE) ; \ +fi +endef + +MAKE_DEPS_AUTO_CC = $(MAKE_DEPS_AUTO) +MAKE_DEPS_AUTO_CXX = $(MAKE_DEPS_AUTO) + +endif # COMPILER_DEPEND + +endif # MOZ_AUTO_DEPS + +# Rules for building native targets must come first because of the host_ prefix +host_%.$(OBJ_SUFFIX): %.c $(GLOBAL_DEPS) + $(REPORT_BUILD) + $(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) + +host_%.$(OBJ_SUFFIX): %.cpp $(GLOBAL_DEPS) + $(REPORT_BUILD) + $(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) + +host_%.$(OBJ_SUFFIX): %.cc $(GLOBAL_DEPS) + $(REPORT_BUILD) + $(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) + +host_%.$(OBJ_SUFFIX): %.m $(GLOBAL_DEPS) + $(REPORT_BUILD) + $(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CFLAGS) $(HOST_CMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) + +host_%.$(OBJ_SUFFIX): %.mm $(GLOBAL_DEPS) + $(REPORT_BUILD) + $(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(HOST_CMMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS) + +%:: %.c $(GLOBAL_DEPS) + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CC) + $(ELOG) $(CC) $(CFLAGS) $(LDFLAGS) $(OUTOPTION)$@ $(_VPATH_SRCS) + +%.$(OBJ_SUFFIX): %.c $(GLOBAL_DEPS) + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CC) + $(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(_VPATH_SRCS) + +# DEFINES and ACDEFINES are needed here to enable conditional compilation of Q_OBJECTs: +# 'moc' only knows about #defines it gets on the command line (-D...), not in +# included headers like mozilla-config.h +moc_%.cpp: %.h $(GLOBAL_DEPS) + $(MOC) $(DEFINES) $(ACDEFINES) $< $(OUTOPTION)$@ + +moc_%.cc: %.cc $(GLOBAL_DEPS) + $(REPORT_BUILD) + $(ELOG) $(MOC) $(DEFINES) $(ACDEFINES) $(_VPATH_SRCS:.cc=.h) $(OUTOPTION)$@ + +ifdef ASFILES +# The AS_DASH_C_FLAG is needed cause not all assemblers (Solaris) accept +# a '-c' flag. +%.$(OBJ_SUFFIX): %.$(ASM_SUFFIX) $(GLOBAL_DEPS) + $(AS) -o $@ $(ASFLAGS) $(AS_DASH_C_FLAG) $(_VPATH_SRCS) +endif + +%.$(OBJ_SUFFIX): %.S $(GLOBAL_DEPS) + $(AS) -o $@ $(ASFLAGS) -c $< + +%:: %.cpp $(GLOBAL_DEPS) + @$(MAKE_DEPS_AUTO_CXX) + $(CCC) $(OUTOPTION)$@ $(CXXFLAGS) $(_VPATH_SRCS) $(LDFLAGS) + +# +# Please keep the next two rules in sync. +# +%.$(OBJ_SUFFIX): %.cc $(GLOBAL_DEPS) + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CXX) + $(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) + +%.$(OBJ_SUFFIX): %.cpp $(GLOBAL_DEPS) + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CXX) +ifdef STRICT_CPLUSPLUS_SUFFIX + echo "#line 1 \"$*.cpp\"" | cat - $*.cpp > t_$*.cc + $(ELOG) $(CCC) -o $@ -c $(COMPILE_CXXFLAGS) t_$*.cc + rm -f t_$*.cc +else + $(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) +endif #STRICT_CPLUSPLUS_SUFFIX + +$(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.mm $(GLOBAL_DEPS) + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CXX) + $(ELOG) $(CCC) -o $@ -c $(COMPILE_CXXFLAGS) $(COMPILE_CMMFLAGS) $(_VPATH_SRCS) + +$(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.m $(GLOBAL_DEPS) + $(REPORT_BUILD) + @$(MAKE_DEPS_AUTO_CC) + $(ELOG) $(CC) -o $@ -c $(COMPILE_CFLAGS) $(COMPILE_CMFLAGS) $(_VPATH_SRCS) + +%.s: %.cpp + $(CCC) -S $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) + +%.s: %.cc + $(CCC) -S $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) + +%.s: %.c + $(CC) -S $(COMPILE_CFLAGS) $(_VPATH_SRCS) + +%.i: %.cpp + $(CCC) -C -E $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) > $*.i + +%.i: %.cc + $(CCC) -C -E $(COMPILE_CXXFLAGS) $(_VPATH_SRCS) > $*.i + +%.i: %.c + $(CC) -C -E $(COMPILE_CFLAGS) $(_VPATH_SRCS) > $*.i + +%.i: %.mm + $(CCC) -C -E $(COMPILE_CXXFLAGS) $(COMPILE_CMMFLAGS) $(_VPATH_SRCS) > $*.i + +%.res: %.rc + @echo Creating Resource file: $@ +ifeq ($(OS_ARCH),OS2) + $(RC) $(RCFLAGS:-D%=-d %) -i $(subst /,\,$(srcdir)) -r $< $@ +else +ifdef GNU_CC + $(RC) $(RCFLAGS) $(filter-out -U%,$(DEFINES)) $(INCLUDES:-I%=--include-dir %) $(OUTOPTION)$@ $(_VPATH_SRCS) +else + $(RC) $(RCFLAGS) -r $(DEFINES) $(INCLUDES) $(OUTOPTION)$@ $(_VPATH_SRCS) +endif +endif + +# need 3 separate lines for OS/2 +%:: %.pl + rm -f $@ + cp $< $@ + chmod +x $@ + +%:: %.sh + rm -f $@; cp $< $@; chmod +x $@ + +# Cancel these implicit rules +# +%: %,v + +%: RCS/%,v + +%: s.% + +%: SCCS/s.% + +############################################################################### +# Java rules +############################################################################### +ifneq (,$(filter OS2 WINNT WINCE,$(OS_ARCH))) +SEP := ; +else +SEP := : +endif + +EMPTY := +SPACE := $(EMPTY) $(EMPTY) + +# Cygwin and MSYS have their own special path form, but javac expects the source +# and class paths to be in the DOS form (i.e. e:/builds/...). This function +# does the appropriate conversion on Windows, but is a noop on other systems. +ifeq (,$(filter-out WINNT WINCE, $(HOST_OS_ARCH))) +ifdef CYGWIN_WRAPPER +normalizepath = $(foreach p,$(1),$(shell cygpath -m $(p))) +else +# assume MSYS +# We use 'pwd -W' to get DOS form of the path. However, since the given path +# could be a file or a non-existent path, we cannot call 'pwd -W' directly +# on the path. Instead, we extract the root path (i.e. "c:/"), call 'pwd -W' +# on it, then merge with the rest of the path. +root-path = $(shell echo $(1) | sed -e "s|\(/[^/]*\)/\?\(.*\)|\1|") +non-root-path = $(shell echo $(1) | sed -e "s|\(/[^/]*\)/\?\(.*\)|\2|") +normalizepath = $(foreach p,$(1),$(if $(filter /%,$(1)),$(patsubst %/,%,$(shell cd $(call root-path,$(1)) && pwd -W))/$(call non-root-path,$(1)),$(1))) +endif +else +normalizepath = $(1) +endif + +_srcdir = $(call normalizepath,$(srcdir)) +ifdef JAVA_SOURCEPATH +SP = $(subst $(SPACE),$(SEP),$(call normalizepath,$(strip $(JAVA_SOURCEPATH)))) +_JAVA_SOURCEPATH = ".$(SEP)$(_srcdir)$(SEP)$(SP)" +else +_JAVA_SOURCEPATH = ".$(SEP)$(_srcdir)" +endif + +ifdef JAVA_CLASSPATH +CP = $(subst $(SPACE),$(SEP),$(call normalizepath,$(strip $(JAVA_CLASSPATH)))) +_JAVA_CLASSPATH = ".$(SEP)$(CP)" +else +_JAVA_CLASSPATH = . +endif + +_JAVA_DIR = _java +$(_JAVA_DIR):: + $(NSINSTALL) -D $@ + +$(_JAVA_DIR)/%.class: %.java $(GLOBAL_DEPS) $(_JAVA_DIR) + $(CYGWIN_WRAPPER) $(JAVAC) $(JAVAC_FLAGS) -classpath $(_JAVA_CLASSPATH) \ + -sourcepath $(_JAVA_SOURCEPATH) -d $(_JAVA_DIR) $(_VPATH_SRCS) + +$(JAVA_LIBRARY): $(addprefix $(_JAVA_DIR)/,$(JAVA_SRCS:.java=.class)) $(GLOBAL_DEPS) + $(JAR) cf $@ -C $(_JAVA_DIR) . + +GARBAGE_DIRS += $(_JAVA_DIR) + +############################################################################### +# Update Makefiles +############################################################################### + +# In GNU make 3.80, makefiles must use the /cygdrive syntax, even if we're +# processing them with AS perl. See bug 232003 +ifdef AS_PERL +CYGWIN_TOPSRCDIR = -nowrap -p $(topsrcdir) -wrap +endif + +# Note: Passing depth to make-makefile is optional. +# It saves the script some work, though. +Makefile: Makefile.in + @$(PERL) $(AUTOCONF_TOOLS)/make-makefile -t $(topsrcdir) -d $(DEPTH) $(CYGWIN_TOPSRCDIR) + +ifdef SUBMAKEFILES +# VPATH does not work on some machines in this case, so add $(srcdir) +$(SUBMAKEFILES): % : $(srcdir)/%.in + $(PERL) $(AUTOCONF_TOOLS)/make-makefile -t $(topsrcdir) -d $(DEPTH) $(CYGWIN_TOPSRCDIR) $@ +endif + +ifdef AUTOUPDATE_CONFIGURE +$(topsrcdir)/configure: $(topsrcdir)/configure.in + (cd $(topsrcdir) && $(AUTOCONF)) && (cd $(DEPTH) && ./config.status --recheck) +endif + +############################################################################### +# Bunch of things that extend the 'export' rule (in order): +############################################################################### + +################################################################################ +# Copy each element of EXPORTS to $(DIST)/include + +ifdef MOZ_JAVAXPCOM +ifneq ($(XPIDLSRCS),) +$(JAVA_DIST_DIR):: + $(NSINSTALL) -D $@ +endif +endif + +ifneq ($(XPI_NAME),) +$(FINAL_TARGET): + $(NSINSTALL) -D $@ + +export:: $(FINAL_TARGET) +endif + +ifndef NO_DIST_INSTALL +ifneq (,$(EXPORTS)) +export:: $(EXPORTS) + $(INSTALL) $(IFLAGS1) $^ $(DIST)/include +endif +endif # NO_DIST_INSTALL + +define EXPORT_NAMESPACE_RULE +ifndef NO_DIST_INSTALL +export:: $(EXPORTS_$(namespace)) + $(INSTALL) $(IFLAGS1) $$^ $(DIST)/include/$(namespace) +endif # NO_DIST_INSTALL +endef + +$(foreach namespace,$(EXPORTS_NAMESPACES),$(eval $(EXPORT_NAMESPACE_RULE))) + +################################################################################ +# Copy each element of PREF_JS_EXPORTS + +ifdef GRE_MODULE +PREF_DIR = greprefs +else +ifneq (,$(XPI_NAME)$(LIBXUL_SDK)) +PREF_DIR = defaults/preferences +else +PREF_DIR = defaults/pref +endif +endif + +ifneq ($(PREF_JS_EXPORTS),) +# on win32, pref files need CRLF line endings... see bug 206029 +ifeq (WINNT,$(OS_ARCH)) +PREF_PPFLAGS = --line-endings=crlf +endif + +ifndef NO_DIST_INSTALL +$(FINAL_TARGET)/$(PREF_DIR): + $(NSINSTALL) -D $@ + +libs:: $(FINAL_TARGET)/$(PREF_DIR) $(PREF_JS_EXPORTS) + $(EXIT_ON_ERROR) \ + for i in $(PREF_JS_EXPORTS); do \ + dest=$(FINAL_TARGET)/$(PREF_DIR)/`basename $$i`; \ + $(RM) -f $$dest; \ + $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $$i > $$dest; \ + done +endif +endif + +################################################################################ +# Copy each element of AUTOCFG_JS_EXPORTS to $(FINAL_TARGET)/defaults/autoconfig + +ifneq ($(AUTOCFG_JS_EXPORTS),) +$(FINAL_TARGET)/defaults/autoconfig:: + $(NSINSTALL) -D $@ + +ifndef NO_DIST_INSTALL +export:: $(AUTOCFG_JS_EXPORTS) $(FINAL_TARGET)/defaults/autoconfig + $(INSTALL) $(IFLAGS1) $^ +endif + +endif +################################################################################ +# Export the elements of $(XPIDLSRCS) +# generating .h and .xpt files and moving them to the appropriate places. + +ifneq ($(XPIDLSRCS),) + +export:: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(XPIDLSRCS)) + +ifndef XPIDL_MODULE +XPIDL_MODULE = $(MODULE) +endif + +ifeq ($(XPIDL_MODULE),) # we need $(XPIDL_MODULE) to make $(XPIDL_MODULE).xpt +export:: FORCE + @echo + @echo "*** Error processing XPIDLSRCS:" + @echo "Please define MODULE or XPIDL_MODULE when defining XPIDLSRCS," + @echo "so we have a module name to use when creating MODULE.xpt." + @echo; sleep 2; false +endif + +$(IDL_DIR):: + $(NSINSTALL) -D $@ + +# generate .h files from into $(XPIDL_GEN_DIR), then export to $(DIST)/include; +# warn against overriding existing .h file. +$(XPIDL_GEN_DIR)/.done: + @if test ! -d $(XPIDL_GEN_DIR); then echo Creating $(XPIDL_GEN_DIR)/.done; rm -rf $(XPIDL_GEN_DIR); mkdir $(XPIDL_GEN_DIR); fi + @touch $@ + +# don't depend on $(XPIDL_GEN_DIR), because the modification date changes +# with any addition to the directory, regenerating all .h files -> everything. + +$(XPIDL_GEN_DIR)/%.h: %.idl $(XPIDL_COMPILE) $(XPIDL_GEN_DIR)/.done + $(REPORT_BUILD) + $(ELOG) $(XPIDL_COMPILE) -m header -w $(XPIDL_FLAGS) -o $(XPIDL_GEN_DIR)/$* $(_VPATH_SRCS) + @if test -n "$(findstring $*.h, $(EXPORTS))"; \ + then echo "*** WARNING: file $*.h generated from $*.idl overrides $(srcdir)/$*.h"; else true; fi + +ifndef NO_GEN_XPT +# generate intermediate .xpt files into $(XPIDL_GEN_DIR), then link +# into $(XPIDL_MODULE).xpt and export it to $(FINAL_TARGET)/components. +$(XPIDL_GEN_DIR)/%.xpt: %.idl $(XPIDL_COMPILE) $(XPIDL_GEN_DIR)/.done + $(REPORT_BUILD) + $(ELOG) $(XPIDL_COMPILE) -m typelib -w $(XPIDL_FLAGS) -e $@ -d $(MDDEPDIR)/$*.pp $(_VPATH_SRCS) + +# no need to link together if XPIDLSRCS contains only XPIDL_MODULE +ifneq ($(XPIDL_MODULE).idl,$(strip $(XPIDLSRCS))) +$(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS)) $(GLOBAL_DEPS) $(XPIDL_LINK) + $(XPIDL_LINK) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS)) +endif # XPIDL_MODULE.xpt != XPIDLSRCS + +libs:: $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt +ifndef NO_DIST_INSTALL + $(INSTALL) $(IFLAGS1) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(FINAL_TARGET)/components +ifndef NO_INTERFACES_MANIFEST + @$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPIDL_MODULE).xpt" + @$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/interfaces.manifest" +endif +endif + +endif # NO_GEN_XPT + +GARBAGE_DIRS += $(XPIDL_GEN_DIR) + +endif # XPIDLSRCS + +ifneq ($(XPIDLSRCS),) +# export .idl files to $(IDL_DIR) +ifndef NO_DIST_INSTALL +export:: $(XPIDLSRCS) $(IDL_DIR) + $(INSTALL) $(IFLAGS1) $^ + +export:: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(XPIDLSRCS)) $(DIST)/include + $(INSTALL) $(IFLAGS1) $^ +endif # NO_DIST_INSTALL + +endif # XPIDLSRCS + + + +# +# General rules for exporting idl files. +# +# WORK-AROUND ONLY, for mozilla/tools/module-deps/bootstrap.pl build. +# Bug to fix idl dependency problems w/o this extra build pass is +# http://bugzilla.mozilla.org/show_bug.cgi?id=145777 +# +$(IDL_DIR):: + $(NSINSTALL) -D $@ + +export-idl:: $(SUBMAKEFILES) $(MAKE_DIRS) + +ifneq ($(XPIDLSRCS),) +ifndef NO_DIST_INSTALL +export-idl:: $(XPIDLSRCS) $(IDL_DIR) + $(INSTALL) $(IFLAGS1) $^ +endif +endif + $(LOOP_OVER_PARALLEL_DIRS) + $(LOOP_OVER_DIRS) + $(LOOP_OVER_TOOL_DIRS) + +ifdef MOZ_JAVAXPCOM +ifneq ($(XPIDLSRCS),) + +JAVA_XPIDLSRCS = $(XPIDLSRCS) + +# A single IDL file can contain multiple interfaces, which result in multiple +# Java interface files. So use hidden dependency files. +JAVADEPFILES = $(addprefix $(JAVA_GEN_DIR)/.,$(JAVA_XPIDLSRCS:.idl=.java.pp)) + +$(JAVA_GEN_DIR): + $(NSINSTALL) -D $@ +GARBAGE_DIRS += $(JAVA_GEN_DIR) + +# generate .java files into _javagen/[package name dirs] +_JAVA_GEN_DIR = $(JAVA_GEN_DIR)/$(JAVA_IFACES_PKG_NAME) +$(_JAVA_GEN_DIR): + $(NSINSTALL) -D $@ + +$(JAVA_GEN_DIR)/.%.java.pp: %.idl $(XPIDL_COMPILE) $(_JAVA_GEN_DIR) + $(REPORT_BUILD) + $(ELOG) $(XPIDL_COMPILE) -m java -w $(XPIDL_FLAGS) -I$(srcdir) -I$(IDL_DIR) -o $(_JAVA_GEN_DIR)/$* $(_VPATH_SRCS) + @touch $@ + +# "Install" generated Java interfaces. We segregate them based on the XPI_NAME. +# If XPI_NAME is not set, install into the "default" directory. +ifneq ($(XPI_NAME),) +JAVA_INSTALL_DIR = $(JAVA_DIST_DIR)/$(XPI_NAME) +else +JAVA_INSTALL_DIR = $(JAVA_DIST_DIR)/default +endif + +$(JAVA_INSTALL_DIR): + $(NSINSTALL) -D $@ + +export:: $(JAVA_DIST_DIR) $(JAVADEPFILES) $(JAVA_INSTALL_DIR) + (cd $(JAVA_GEN_DIR) && tar $(TAR_CREATE_FLAGS) - .) | (cd $(JAVA_INSTALL_DIR) && tar -xf -) + +endif # XPIDLSRCS +endif # MOZ_JAVAXPCOM + +################################################################################ +# Copy each element of EXTRA_COMPONENTS to $(FINAL_TARGET)/components +ifneq (,$(filter %.js,$(EXTRA_COMPONENTS) $(EXTRA_PP_COMPONENTS))) +ifeq (,$(filter %.manifest,$(EXTRA_COMPONENTS) $(EXTRA_PP_COMPONENTS))) +ifndef NO_JS_MANIFEST +$(error .js component without matching .manifest. See https://developer.mozilla.org/en/XPCOM/XPCOM_changes_in_Gecko_2.0) +endif +endif +endif + +ifdef EXTRA_COMPONENTS +libs:: $(EXTRA_COMPONENTS) +ifndef NO_DIST_INSTALL + $(INSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/components +endif + +endif + +ifdef EXTRA_PP_COMPONENTS +libs:: $(EXTRA_PP_COMPONENTS) +ifndef NO_DIST_INSTALL + $(EXIT_ON_ERROR) \ + $(NSINSTALL) -D $(FINAL_TARGET)/components; \ + for i in $^; do \ + fname=`basename $$i`; \ + dest=$(FINAL_TARGET)/components/$${fname}; \ + $(RM) -f $$dest; \ + $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $$i > $$dest; \ + done +endif +endif + +EXTRA_MANIFESTS = $(filter %.manifest,$(EXTRA_COMPONENTS) $(EXTRA_PP_COMPONENTS)) +ifneq (,$(EXTRA_MANIFESTS)) +libs:: + $(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest $(patsubst %,"manifest components/%",$(notdir $(EXTRA_MANIFESTS))) +endif + +################################################################################ +# Copy each element of EXTRA_JS_MODULES to $(FINAL_TARGET)/modules +ifdef EXTRA_JS_MODULES +libs:: $(EXTRA_JS_MODULES) +ifndef NO_DIST_INSTALL + $(INSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/modules +endif + +endif + +ifdef EXTRA_PP_JS_MODULES +libs:: $(EXTRA_PP_JS_MODULES) +ifndef NO_DIST_INSTALL + $(EXIT_ON_ERROR) \ + $(NSINSTALL) -D $(FINAL_TARGET)/modules; \ + for i in $^; do \ + dest=$(FINAL_TARGET)/modules/`basename $$i`; \ + $(RM) -f $$dest; \ + $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $$i > $$dest; \ + done +endif + +endif + +################################################################################ +# SDK + +ifneq (,$(SDK_LIBRARY)) +$(SDK_LIB_DIR):: + $(NSINSTALL) -D $@ + +ifndef NO_DIST_INSTALL +libs:: $(SDK_LIBRARY) $(SDK_LIB_DIR) + $(INSTALL) $(IFLAGS2) $^ +endif + +endif # SDK_LIBRARY + +ifneq (,$(SDK_BINARY)) +$(SDK_BIN_DIR):: + $(NSINSTALL) -D $@ + +ifndef NO_DIST_INSTALL +libs:: $(SDK_BINARY) $(SDK_BIN_DIR) + $(INSTALL) $(IFLAGS2) $^ +endif + +endif # SDK_BINARY + +################################################################################ +# CHROME PACKAGING + +JAR_MANIFEST := $(srcdir)/jar.mn + +chrome:: + $(MAKE) realchrome + $(LOOP_OVER_PARALLEL_DIRS) + $(LOOP_OVER_DIRS) + $(LOOP_OVER_TOOL_DIRS) + +$(FINAL_TARGET)/chrome: + $(NSINSTALL) -D $@ + +libs realchrome:: $(CHROME_DEPS) $(FINAL_TARGET)/chrome +ifneq (,$(wildcard $(JAR_MANIFEST))) +ifndef NO_DIST_INSTALL + $(PYTHON) $(MOZILLA_DIR)/config/JarMaker.py \ + $(QUIET) -j $(FINAL_TARGET)/chrome \ + $(MAKE_JARS_FLAGS) $(XULPPFLAGS) $(DEFINES) $(ACDEFINES) \ + $(JAR_MANIFEST) +endif +endif + +ifneq ($(DIST_FILES),) +$(DIST)/bin: + $(NSINSTALL) -D $@ + +libs:: $(DIST_FILES) $(DIST)/bin + @$(EXIT_ON_ERROR) \ + for f in $(DIST_FILES); do \ + dest=$(FINAL_TARGET)/`basename $$f`; \ + $(RM) -f $$dest; \ + $(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py \ + $(XULAPP_DEFINES) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \ + $(srcdir)/$$f > $$dest; \ + done +endif + +ifneq ($(DIST_CHROME_FILES),) +libs:: $(DIST_CHROME_FILES) + @$(EXIT_ON_ERROR) \ + for f in $(DIST_CHROME_FILES); do \ + dest=$(FINAL_TARGET)/chrome/`basename $$f`; \ + $(RM) -f $$dest; \ + $(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py \ + $(XULAPP_DEFINES) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \ + $(srcdir)/$$f > $$dest; \ + done +endif + +ifneq ($(XPI_PKGNAME),) +libs realchrome:: +ifdef STRIP_XPI +ifndef MOZ_DEBUG + @echo "Stripping $(XPI_PKGNAME) package directory..." + @echo $(FINAL_TARGET) + @cd $(FINAL_TARGET) && find . ! -type d \ + ! -name "*.js" \ + ! -name "*.xpt" \ + ! -name "*.gif" \ + ! -name "*.jpg" \ + ! -name "*.png" \ + ! -name "*.xpm" \ + ! -name "*.txt" \ + ! -name "*.rdf" \ + ! -name "*.sh" \ + ! -name "*.properties" \ + ! -name "*.dtd" \ + ! -name "*.html" \ + ! -name "*.xul" \ + ! -name "*.css" \ + ! -name "*.xml" \ + ! -name "*.jar" \ + ! -name "*.dat" \ + ! -name "*.tbl" \ + ! -name "*.src" \ + ! -name "*.reg" \ + $(PLATFORM_EXCLUDE_LIST) \ + -exec $(STRIP) $(STRIP_FLAGS) {} >/dev/null 2>&1 \; +endif +endif + @echo "Packaging $(XPI_PKGNAME).xpi..." + cd $(FINAL_TARGET) && $(ZIP) -qr ../$(XPI_PKGNAME).xpi * +endif + +ifdef INSTALL_EXTENSION_ID +ifndef XPI_NAME +$(error XPI_NAME must be set for INSTALL_EXTENSION_ID) +endif + +libs:: + $(RM) -rf "$(DIST)/bin/extensions/$(INSTALL_EXTENSION_ID)" + $(NSINSTALL) -D "$(DIST)/bin/extensions/$(INSTALL_EXTENSION_ID)" + cd $(FINAL_TARGET) && tar $(TAR_CREATE_FLAGS) - . | (cd "../../bin/extensions/$(INSTALL_EXTENSION_ID)" && tar -xf -) + +endif + +ifneq (,$(filter flat symlink,$(MOZ_CHROME_FILE_FORMAT))) +_JAR_REGCHROME_DISABLE_JAR=1 +else +_JAR_REGCHROME_DISABLE_JAR=0 +endif + +REGCHROME = $(PERL) -I$(MOZILLA_DIR)/config $(MOZILLA_DIR)/config/add-chrome.pl \ + $(if $(filter gtk2,$(MOZ_WIDGET_TOOLKIT)),-x) \ + $(if $(CROSS_COMPILE),-o $(OS_ARCH)) $(FINAL_TARGET)/chrome/installed-chrome.txt \ + $(_JAR_REGCHROME_DISABLE_JAR) + +REGCHROME_INSTALL = $(PERL) -I$(MOZILLA_DIR)/config $(MOZILLA_DIR)/config/add-chrome.pl \ + $(if $(filter gtk2,$(MOZ_WIDGET_TOOLKIT)),-x) \ + $(if $(CROSS_COMPILE),-o $(OS_ARCH)) $(DESTDIR)$(mozappdir)/chrome/installed-chrome.txt \ + $(_JAR_REGCHROME_DISABLE_JAR) + + +############################################################################# +# Dependency system +############################################################################# +ifdef COMPILER_DEPEND +depend:: + @echo "$(MAKE): No need to run depend target.\ + Using compiler-based depend." 1>&2 +ifeq ($(GNU_CC)$(GNU_CXX),) +# Non-GNU compilers + @echo "`echo '$(MAKE):'|sed 's/./ /g'`"\ + '(Compiler-based depend was turned on by "--enable-md".)' 1>&2 +else +# GNU compilers + @space="`echo '$(MAKE): '|sed 's/./ /g'`";\ + echo "$$space"'Since you are using a GNU compiler,\ + it is on by default.' 1>&2; \ + echo "$$space"'To turn it off, pass --disable-md to configure.' 1>&2 +endif + +else # ! COMPILER_DEPEND + +ifndef MOZ_AUTO_DEPS + +define MAKE_DEPS_NOAUTO + $(MKDEPEND) -w1024 -o'.$(OBJ_SUFFIX)' -f- $(DEFINES) $(ACDEFINES) $(INCLUDES) $< 2>/dev/null | sed -e "s|^[^ ]*/||" > $@ +endef + +$(MDDEPDIR)/%.pp: %.c + $(REPORT_BUILD) + @$(MAKE_DEPS_NOAUTO) + +$(MDDEPDIR)/%.pp: %.cpp + $(REPORT_BUILD) + @$(MAKE_DEPS_NOAUTO) + +$(MDDEPDIR)/%.pp: %.s + $(REPORT_BUILD) + @$(MAKE_DEPS_NOAUTO) + +ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS)) +depend:: $(SUBMAKEFILES) $(MAKE_DIRS) $(MDDEPFILES) +else +depend:: $(SUBMAKEFILES) +endif + $(LOOP_OVER_PARALLEL_DIRS) + $(LOOP_OVER_DIRS) + $(LOOP_OVER_TOOL_DIRS) + +dependclean:: $(SUBMAKEFILES) + rm -f $(MDDEPFILES) + $(LOOP_OVER_PARALLEL_DIRS) + $(LOOP_OVER_DIRS) + $(LOOP_OVER_TOOL_DIRS) + +endif # MOZ_AUTO_DEPS + +endif # COMPILER_DEPEND + + +############################################################################# +# MDDEPDIR is the subdirectory where all the dependency files are placed. +# This uses a make rule (instead of a macro) to support parallel +# builds (-jN). If this were done in the LOOP_OVER_DIRS macro, two +# processes could simultaneously try to create the same directory. +# +# We use $(CURDIR) in the rule's target to ensure that we don't find +# a dependency directory in the source tree via VPATH (perhaps from +# a previous build in the source tree) and thus neglect to create a +# dependency directory in the object directory, where we really need +# it. + +$(CURDIR)/$(MDDEPDIR): + @if test ! -d $@; then echo Creating $@; rm -rf $@; mkdir $@; else true; fi + +ifneq (,$(filter-out all chrome default export realchrome tools clean clobber clobber_all distclean realclean,$(MAKECMDGOALS))) +ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS)) +MDDEPEND_FILES := $(strip $(wildcard $(MDDEPDIR)/*.pp)) + +ifneq (,$(MDDEPEND_FILES)) +# The script mddepend.pl checks the dependencies and writes to stdout +# one rule to force out-of-date objects. For example, +# foo.o boo.o: FORCE +# The script has an advantage over including the *.pp files directly +# because it handles the case when header files are removed from the build. +# 'make' would complain that there is no way to build missing headers. +ALL_PP_RESULTS = $(shell $(PERL) $(BUILD_TOOLS)/mddepend.pl - $(MDDEPEND_FILES)) +$(eval $(ALL_PP_RESULTS)) +endif + +endif +endif +############################################################################# + +-include $(topsrcdir)/$(MOZ_BUILD_APP)/app-rules.mk +-include $(MY_RULES) + +# +# Generate Emacs tags in a file named TAGS if ETAGS was set in $(MY_CONFIG) +# or in $(MY_RULES) +# +ifdef ETAGS +ifneq ($(CSRCS)$(CPPSRCS)$(HEADERS),) +all:: TAGS +TAGS:: $(CSRCS) $(CPPSRCS) $(HEADERS) + $(ETAGS) $(CSRCS) $(CPPSRCS) $(HEADERS) +endif +endif + +################################################################################ +# Special gmake rules. +################################################################################ + + +# +# Disallow parallel builds with MSVC < 8 +# +ifneq (,$(filter 1200 1300 1310,$(_MSC_VER))) +.NOTPARALLEL: +endif + +# +# Re-define the list of default suffixes, so gmake won't have to churn through +# hundreds of built-in suffix rules for stuff we don't need. +# +.SUFFIXES: + +# +# Fake targets. Always run these rules, even if a file/directory with that +# name already exists. +# +.PHONY: all alltags boot checkout chrome realchrome clean clobber clobber_all export install libs makefiles realclean run_apprunner tools $(DIRS) $(TOOL_DIRS) FORCE + +# Used as a dependency to force targets to rebuild +FORCE: + +# Delete target if error occurs when building target +.DELETE_ON_ERROR: + +# Properly set LIBPATTERNS for the platform +.LIBPATTERNS = $(if $(IMPORT_LIB_SUFFIX),$(LIB_PREFIX)%.$(IMPORT_LIB_SUFFIX)) $(LIB_PREFIX)%.$(LIB_SUFFIX) $(DLL_PREFIX)%$(DLL_SUFFIX) + +tags: TAGS + +TAGS: $(SUBMAKEFILES) $(CSRCS) $(CPPSRCS) $(wildcard *.h) + -etags $(CSRCS) $(CPPSRCS) $(wildcard *.h) + $(LOOP_OVER_PARALLEL_DIRS) + $(LOOP_OVER_DIRS) + +echo-variable-%: + @echo "$($*)" + +echo-tiers: + @echo $(TIERS) + +echo-tier-dirs: + @$(foreach tier,$(TIERS),echo '$(tier):'; echo ' dirs: $(tier_$(tier)_dirs)'; echo ' staticdirs: $(tier_$(tier)_staticdirs)'; ) + +echo-dirs: + @echo $(DIRS) + +echo-module: + @echo $(MODULE) + +echo-requires: + @echo $(REQUIRES) + +echo-depth-path: + @$(topsrcdir)/build/unix/print-depth-path.sh + +echo-module-name: + @$(topsrcdir)/build/package/rpm/print-module-name.sh + +echo-module-filelist: + @$(topsrcdir)/build/package/rpm/print-module-filelist.sh + +showtargs: +ifneq (,$(filter $(PROGRAM) $(HOST_PROGRAM) $(SIMPLE_PROGRAMS) $(HOST_LIBRARY) $(LIBRARY) $(SHARED_LIBRARY),$(TARGETS))) + @echo -------------------------------------------------------------------------------- + @echo "PROGRAM = $(PROGRAM)" + @echo "SIMPLE_PROGRAMS = $(SIMPLE_PROGRAMS)" + @echo "LIBRARY = $(LIBRARY)" + @echo "SHARED_LIBRARY = $(SHARED_LIBRARY)" + @echo "SHARED_LIBRARY_LIBS = $(SHARED_LIBRARY_LIBS)" + @echo "LIBS = $(LIBS)" + @echo "DEF_FILE = $(DEF_FILE)" + @echo "IMPORT_LIBRARY = $(IMPORT_LIBRARY)" + @echo "STATIC_LIBS = $(STATIC_LIBS)" + @echo "SHARED_LIBS = $(SHARED_LIBS)" + @echo "EXTRA_DSO_LIBS = $(EXTRA_DSO_LIBS)" + @echo "EXTRA_DSO_LDOPTS = $(EXTRA_DSO_LDOPTS)" + @echo "DEPENDENT_LIBS = $(DEPENDENT_LIBS)" + @echo -------------------------------------------------------------------------------- +endif + $(LOOP_OVER_PARALLEL_DIRS) + $(LOOP_OVER_DIRS) + +showbuild: + @echo "MOZ_BUILD_ROOT = $(MOZ_BUILD_ROOT)" + @echo "MOZ_WIDGET_TOOLKIT = $(MOZ_WIDGET_TOOLKIT)" + @echo "CC = $(CC)" + @echo "CXX = $(CXX)" + @echo "CCC = $(CCC)" + @echo "CPP = $(CPP)" + @echo "LD = $(LD)" + @echo "AR = $(AR)" + @echo "IMPLIB = $(IMPLIB)" + @echo "FILTER = $(FILTER)" + @echo "MKSHLIB = $(MKSHLIB)" + @echo "MKCSHLIB = $(MKCSHLIB)" + @echo "RC = $(RC)" + @echo "CFLAGS = $(CFLAGS)" + @echo "OS_CFLAGS = $(OS_CFLAGS)" + @echo "COMPILE_CFLAGS = $(COMPILE_CFLAGS)" + @echo "CXXFLAGS = $(CXXFLAGS)" + @echo "OS_CXXFLAGS = $(OS_CXXFLAGS)" + @echo "COMPILE_CXXFLAGS = $(COMPILE_CXXFLAGS)" + @echo "COMPILE_CMFLAGS = $(COMPILE_CMFLAGS)" + @echo "COMPILE_CMMFLAGS = $(COMPILE_CMMFLAGS)" + @echo "LDFLAGS = $(LDFLAGS)" + @echo "OS_LDFLAGS = $(OS_LDFLAGS)" + @echo "DSO_LDOPTS = $(DSO_LDOPTS)" + @echo "OS_INCLUDES = $(OS_INCLUDES)" + @echo "OS_LIBS = $(OS_LIBS)" + @echo "EXTRA_LIBS = $(EXTRA_LIBS)" + @echo "BIN_FLAGS = $(BIN_FLAGS)" + @echo "INCLUDES = $(INCLUDES)" + @echo "DEFINES = $(DEFINES)" + @echo "ACDEFINES = $(ACDEFINES)" + @echo "BIN_SUFFIX = $(BIN_SUFFIX)" + @echo "LIB_SUFFIX = $(LIB_SUFFIX)" + @echo "DLL_SUFFIX = $(DLL_SUFFIX)" + @echo "IMPORT_LIB_SUFFIX = $(IMPORT_LIB_SUFFIX)" + @echo "INSTALL = $(INSTALL)" + +showhost: + @echo "HOST_CC = $(HOST_CC)" + @echo "HOST_CXX = $(HOST_CXX)" + @echo "HOST_CFLAGS = $(HOST_CFLAGS)" + @echo "HOST_LDFLAGS = $(HOST_LDFLAGS)" + @echo "HOST_LIBS = $(HOST_LIBS)" + @echo "HOST_EXTRA_LIBS = $(HOST_EXTRA_LIBS)" + @echo "HOST_EXTRA_DEPS = $(HOST_EXTRA_DEPS)" + @echo "HOST_PROGRAM = $(HOST_PROGRAM)" + @echo "HOST_OBJS = $(HOST_OBJS)" + @echo "HOST_PROGOBJS = $(HOST_PROGOBJS)" + @echo "HOST_LIBRARY = $(HOST_LIBRARY)" + +showbuildmods:: + @echo "Build Modules = $(BUILD_MODULES)" + @echo "Module dirs = $(BUILD_MODULE_DIRS)" + +documentation: + @cd $(DEPTH) + $(DOXYGEN) $(DEPTH)/config/doxygen.cfg + +ifdef ENABLE_TESTS +check:: $(SUBMAKEFILES) $(MAKE_DIRS) + $(LOOP_OVER_PARALLEL_DIRS) + $(LOOP_OVER_DIRS) + $(LOOP_OVER_TOOL_DIRS) +endif + + +FREEZE_VARIABLES = \ + CSRCS \ + CPPSRCS \ + EXPORTS \ + XPIDLSRCS \ + DIRS \ + LIBRARY \ + MODULE \ + REQUIRES \ + SHORT_LIBNAME \ + TIERS \ + EXTRA_COMPONENTS \ + EXTRA_PP_COMPONENTS \ + $(NULL) + +$(foreach var,$(FREEZE_VARIABLES),$(eval $(var)_FROZEN := '$($(var))')) + +CHECK_FROZEN_VARIABLES = $(foreach var,$(FREEZE_VARIABLES), \ + $(if $(subst $($(var)_FROZEN),,'$($(var))'),$(error Makefile variable '$(var)' changed value after including rules.mk. Was $($(var)_FROZEN), now $($(var)).))) + +libs export libs:: + $(CHECK_FROZEN_VARIABLES) + +default all:: + if test -d $(DIST)/bin ; then touch $(DIST)/bin/.purgecaches ; fi diff --git a/js/src/config/solaris_ia32.map b/js/src/config/solaris_ia32.map new file mode 100644 index 0000000..712b2d8 --- /dev/null +++ b/js/src/config/solaris_ia32.map @@ -0,0 +1 @@ +hwcap_1 = OVERRIDE; diff --git a/js/src/config/static-checking-config.mk b/js/src/config/static-checking-config.mk new file mode 100644 index 0000000..153c771 --- /dev/null +++ b/js/src/config/static-checking-config.mk @@ -0,0 +1,24 @@ +DEHYDRA_SCRIPT = $(topsrcdir)/config/static-checking.js + +DEHYDRA_MODULES = \ + $(NULL) + +TREEHYDRA_MODULES = \ + $(topsrcdir)/jsstack.js \ + $(NULL) + +DEHYDRA_ARG_PREFIX=-fplugin-arg-gcc_treehydra- + +DEHYDRA_ARGS = \ + $(DEHYDRA_ARG_PREFIX)script=$(DEHYDRA_SCRIPT) \ + $(DEHYDRA_ARG_PREFIX)topsrcdir=$(topsrcdir) \ + $(DEHYDRA_ARG_PREFIX)objdir=$(DEPTH) \ + $(DEHYDRA_ARG_PREFIX)dehydra-modules=$(subst $(NULL) ,$(COMMA),$(strip $(DEHYDRA_MODULES))) \ + $(DEHYDRA_ARG_PREFIX)treehydra-modules=$(subst $(NULL) ,$(COMMA),$(strip $(TREEHYDRA_MODULES))) \ + $(NULL) + +DEHYDRA_FLAGS = -fplugin=$(DEHYDRA_PATH) $(DEHYDRA_ARGS) + +ifdef DEHYDRA_PATH +OS_CXXFLAGS += $(DEHYDRA_FLAGS) +endif diff --git a/js/src/config/static-checking.js b/js/src/config/static-checking.js new file mode 100644 index 0000000..a67cb11 --- /dev/null +++ b/js/src/config/static-checking.js @@ -0,0 +1,143 @@ +/** + * A script for GCC-dehydra to analyze the Mozilla codebase and catch + * patterns that are incorrect, but which cannot be detected by a compiler. */ + +/** + * Activate Treehydra outparams analysis if running in Treehydra. + */ + +function treehydra_enabled() { + return this.hasOwnProperty('TREE_CODE'); +} + +sys.include_path.push(options.topsrcdir); + +include('string-format.js'); + +let modules = []; + +function LoadModules(modulelist) +{ + if (modulelist == "") + return; + + let modulenames = modulelist.split(','); + for each (let modulename in modulenames) { + let module = { __proto__: this }; + include(modulename, module); + modules.push(module); + } +} + +LoadModules(options['dehydra-modules']); +if (treehydra_enabled()) + LoadModules(options['treehydra-modules']); + +function process_type(c) +{ + for each (let module in modules) + if (module.hasOwnProperty('process_type')) + module.process_type(c); +} + +function hasAttribute(c, attrname) +{ + var attr; + + if (c.attributes === undefined) + return false; + + for each (attr in c.attributes) + if (attr.name == 'user' && attr.value[0] == attrname) + return true; + + return false; +} + +// This is useful for detecting method overrides +function signaturesMatch(m1, m2) +{ + if (m1.shortName != m2.shortName) + return false; + + if ((!!m1.isVirtual) != (!!m2.isVirtual)) + return false; + + if (m1.isStatic != m2.isStatic) + return false; + + let p1 = m1.type.parameters; + let p2 = m2.type.parameters; + + if (p1.length != p2.length) + return false; + + for (let i = 0; i < p1.length; ++i) + if (!params_match(p1[i], p2[i])) + return false; + + return true; +} + +function params_match(p1, p2) +{ + [p1, p2] = unwrap_types(p1, p2); + + for (let i in p1) + if (i == "type" && !types_match(p1.type, p2.type)) + return false; + else if (i != "type" && p1[i] !== p2[i]) + return false; + + for (let i in p2) + if (!(i in p1)) + return false; + + return true; +} + +function types_match(t1, t2) +{ + if (!t1 || !t2) + return false; + + [t1, t2] = unwrap_types(t1, t2); + + return t1 === t2; +} + +function unwrap_types(t1, t2) +{ + while (t1.variantOf) + t1 = t1.variantOf; + + while (t2.variantOf) + t2 = t2.variantOf; + + return [t1, t2]; +} + +const forward_functions = [ + 'process_type', + 'process_tree_type', + 'process_decl', + 'process_tree_decl', + 'process_function', + 'process_tree', + 'process_cp_pre_genericize', + 'input_end' +]; + +function setup_forwarding(n) +{ + this[n] = function() { + for each (let module in modules) { + if (module.hasOwnProperty(n)) { + module[n].apply(this, arguments); + } + } + } +} + +for each (let n in forward_functions) + setup_forwarding(n); diff --git a/js/src/config/string-format.js b/js/src/config/string-format.js new file mode 100644 index 0000000..352a5f3 --- /dev/null +++ b/js/src/config/string-format.js @@ -0,0 +1,61 @@ +String.prototype.format = function string_format() { + // there are two modes of operation... unnamed indices are read in order; + // named indices using %(name)s. The two styles cannot be mixed. + // Unnamed indices can be passed as either a single argument to this function, + // multiple arguments to this function, or as a single array argument + let curindex = 0; + let d; + + if (arguments.length > 1) { + d = arguments; + } + else + d = arguments[0]; + + function r(s, key, type) { + if (type == '%') + return '%'; + + let v; + if (key == "") { + if (curindex == -1) + throw Error("Cannot mix named and positional indices in string formatting."); + + if (curindex == 0 && (!(d instanceof Object) || !(0 in d))) { + v = d; + } + else if (!(curindex in d)) + throw Error("Insufficient number of items in format, requesting item %i".format(curindex)); + else { + v = d[curindex]; + } + + ++curindex; + } + else { + key = key.slice(1, -1); + if (curindex > 0) + throw Error("Cannot mix named and positional indices in string formatting."); + curindex = -1; + + if (!(key in d)) + throw Error("Key '%s' not present during string substitution.".format(key)); + v = d[key]; + } + switch (type) { + case "s": + if (v === undefined) + return ""; + return v.toString(); + case "r": + return uneval(v); + case "i": + return parseInt(v); + case "f": + return Number(v); + default: + throw Error("Unexpected format character '%s'.".format(type)); + } + } + return this.replace(/%(\([^)]+\))?(.)/g, r); +}; diff --git a/js/src/config/system-headers b/js/src/config/system-headers new file mode 100644 index 0000000..e1b5e17 --- /dev/null +++ b/js/src/config/system-headers @@ -0,0 +1,1055 @@ +A4Stuff.h +activscp.h +AEDataModel.h +AEObjects.h +AEPackObject.h +AERegistry.h +AEUtils.h +afxcmn.h +afxcoll.h +afxcview.h +afxdisp.h +afxdtctl.h +afxext.h +afxmt.h +afxpriv.h +afxtempl.h +afxwin.h +algorithm +Aliases.h +all.h +alloca.h +alloc.h +alsa/asoundlib.h +alsa/pcm.h +alsa/mixer.h +ansi_parms.h +a.out.h +app/Cursor.h +Appearance.h +AppFileInfo.h +AppKit.h +AppleEvents.h +Application.h +app/Message.h +app/MessageRunner.h +arpa/inet.h +arpa/nameser.h +asm/sigcontext.h +asm/signal.h +ASRegistry.h +assert.h +atk/atk.h +atlbase.h +atlcom.h +atlconv.h +atlctl.cpp +atlctl.h +ATLCTL.H +atlhost.h +atlimpl.cpp +atlwin.cpp +ATSTypes.h +ATSUnicode.h +Balloons.h +base/pblock.h +base/PCR_Base.h +base/session.h +basetyps.h +be/app/Application.h +Beep.h +be/kernel/image.h +be/kernel/OS.h +bfd.h +Bitmap.h +bitset +blapi.h +bsd/libc.h +bsd/syscall.h +bstring.h +builtin.h +Button.h +byteswap.h +#if MOZ_ENABLE_LIBXUL!=1 +#define WRAP_CAIRO_HEADERS +#endif +#if MOZ_TREE_CAIRO!=1 +#define WRAP_CAIRO_HEADERS +#endif +#ifdef WRAP_CAIRO_HEADERS +pixman.h +cairo.h +cairo-atsui.h +cairo-beos.h +cairo-ft.h +cairo-glitz.h +cairo-os2.h +cairo-pdf.h +cairo-ps.h +cairo-tee.h +cairo-quartz.h +cairo-win32.h +cairo-xlib.h +cairo-xlib-xrender.h +cairo-directfb.h +cairo-qpainter.h +#endif +dfiff.h +exception +ffi.h +fusion/reactor.h +fusion/property.h +fusion/conf.h +fusion/build.h +fusion/hash.h +fusion/shm/shm.h +fusion/shm/shm_internal.h +fusion/shm/pool.h +fusion/ref.h +fusion/fusion_internal.h +fusion/lock.h +fusion/types.h +fusion/vector.h +fusion/call.h +fusion/shmalloc.h +fusion/protocol.h +fusion/fusion.h +fusion/arena.h +fusion/object.h +directfbgl.h +directfb_version.h +directfb.h +directfb_util.h +directfb_keynames.h +dgiff.h +direct/util.h +direct/memcpy.h +direct/interface.h +direct/conf.h +direct/tree.h +direct/signals.h +direct/build.h +direct/interface_implementation.h +direct/utf8.h +direct/serial.h +direct/hash.h +direct/direct.h +direct/clock.h +direct/types.h +direct/mem.h +direct/thread.h +direct/debug.h +direct/stream.h +direct/messages.h +direct/trace.h +direct/modules.h +direct/log.h +direct/system.h +direct/list.h +dfb_types.h +directfb_strings.h +directfb_keyboard.h +callconv.h +Carbon/Carbon.h +CarbonEvents.h +Carbon.h +cassert +c_asm.h +cctype +cderr.h +cerrno +cert.h +CFBase.h +CFBundle.h +CFData.h +CFDictionary.h +cf.h +CFNumber.h +CFPlugIn.h +CFPreferences.h +CFString.h +CFURL.h +CGAffineTransform.h +CheckBox.h +climits +Clipboard.h +cmplrs/stsupport.h +Cocoa/Cocoa.h +CodeFragments.h +comdef.h +commctrl.h +COMMCTRL.H +commdlg.h +compat.h +condapi.h +ConditionalMacros.h +config.h +conio.h +console.h +ControlDefinitions.h +Controls.h +CoreFoundation/CoreFoundation.h +CoreServices/CoreServices.h +CPalmRec.cpp +Cpalmrec.h +CPCatgry.cpp +CPDbBMgr.h +CPString.cpp +CPString.h +crtdbg.h +crt_externs.h +crypt.h +cstddef +cstdio +cstdlib +cstring +ctime +ctype.h +curl/curl.h +curl/easy.h +curl/types.h +curses.h +cxxabi.h +DateTimeUtils.h +dbus/dbus.h +dbus/dbus-glib.h +dbus/dbus-glib-lowlevel.h +ddeml.h +Debug.h +deque +dem.h +descrip.h +Devices.h +Dialogs.h +direct.h +dirent.h +DiskInit.h +dlfcn.h +dlgs.h +dl.h +docobj.h +dos/dosextens.h +dos.h +Drag.h +DriverServices.h +DriverSynchronization.h +DropInPanel.h +dvidef.h +elf.h +endian.h +Entry.h +errno.h +Errors.h +Events.h +exdisp.h +ExDisp.h +exe386.h +execinfo.h +extras.h +fabdef.h +fcntl.h +features.h +fibdef.h +File.h +filehdr.h +files.h +Files.h +FindDirectory.h +Finder.h +FinderRegistry.h +FixMath.h +float.h +fnmatch.h +Folders.h +fontconfig/fontconfig.h +fontconfig/fcfreetype.h +Font.h +Fonts.h +fp.h +fpieee.h +frame/log.h +frame/req.h +freetype/freetype.h +freetype/ftcache.h +freetype/ftglyph.h +freetype/ftsynth.h +freetype/ftoutln.h +freetype/ttnameid.h +freetype/tttables.h +freetype/t1tables.h +fribidi/fribidi.h +FSp_fopen.h +fstream +fstream.h +ft2build.h +fts.h +gconf/gconf-client.h +Gdiplus.h +gdk/gdk.h +gdk/gdkkeysyms.h +gdk/gdkprivate.h +gdk/gdkx.h +gdk/gdkdirectfb.h +gdk-pixbuf/gdk-pixbuf.h +Gestalt.h +getopt.h +glibconfig.h +glib.h +glib-object.h +gmodule.h +gnome.h +gnu/libc-version.h +grp.h +gssapi_generic.h +gssapi/gssapi_generic.h +gssapi/gssapi.h +gssapi.h +gtk/gtk.h +gtk/gtkprinter.h +gtk/gtkprintjob.h +gtk/gtkprintunixdialog.h +HIToolbox/HIToolbox.h +hlink.h +htiface.h +ia64/sys/inline.h +Icons.h +iconv.h +IDL.h +ieeefp.h +ifaddrs.h +image.h +imagehlp.h +imm.h +initguid.h +InterfaceDefs.h +InternetConfig.h +IntlResources.h +ints.h +intshcut.h +inttypes.h +iodef.h +io.h +IOKit/IOKitLib.h +IOKit/IOMessage.h +IOKit/pwr_mgt/IOPMLib.h +iomanip +iostream +iostream.h +iterator +jar.h +JavaControl.h +JavaEmbedding/JavaControl.h +JavaVM/jni.h +JManager.h +JNIEnvTests.h +jni.h +#if MOZ_NATIVE_JPEG==1 +jpeglib.h +#endif +JVMManagerTests.h +Kerberos/Kerberos.h +kernel/image.h +kernel/OS.h +key.h +keyt.h +keythi.h +LAction.h +langinfo.h +LApplication.h +LArray.h +LArrayIterator.h +LAttachable.h +LAttachment.h +LaunchServices.h +lber.h +LBroadcaster.h +LButton.h +lcache.h +LCaption.h +LCheckBox.h +LCicnButton.h +LClipboard.h +LCommander.h +LComparator.h +LControl.h +ldap.h +ldaplog.h +ldappr.h +ldap_ssl.h +LDataStream.h +ldfcn.h +LDialogBox.h +ldif.h +LDocApplication.h +LDocument.h +LDragAndDrop.h +LDragTask.h +LEditField.h +LEditText.h +LEventDispatcher.h +LFile.h +LFileStream.h +LFileTypeList.h +LFocusBox.h +LGrafPortView.h +LHandleStream.h +libc_r.h +libelf.h +libelf/libelf.h +libgen.h +libgnome/gnome-url.h +libgnome/libgnome.h +libgnomeui/gnome-icon-lookup.h +libgnomeui/gnome-icon-theme.h +libgnomeui/gnome-ui-init.h +libgnomevfs/gnome-vfs-file-info.h +libgnomevfs/gnome-vfs.h +libgnomevfs/gnome-vfs-init.h +libgnomevfs/gnome-vfs-mime.h +libgnomevfs/gnome-vfs-mime-handlers.h +libgnomevfs/gnome-vfs-mime-utils.h +libgnomevfs/gnome-vfs-ops.h +libgnomevfs/gnome-vfs-standard-callbacks.h +libIDL/IDL.h +lib$routines.h +libnotify/notify.h +limits +limits.h +link.h +linux/kernel.h +linux/limits.h +linux/rtc.h +linux/version.h +list +List.h +Lists.h +LListBox.h +LListener.h +LMenuBar.h +LMenu.h +LModelDirector.h +LModelObject.h +LModelProperty.h +loader.h +locale +locale.h +LOffscreenView.h +logkeys.h +logstrng.h +Looper.h +LowMem.h +LPane.h +LPeriodical.h +LPicture.h +LPlaceHolder.h +LPrintout.h +LProgressBar.h +LPushButton.h +LRadioGroup.h +LRadioGroupView.h +LRunArray.h +LScroller.h +LSharable.h +LSingleDoc.h +LStaticText.h +LStdControl.h +LStream.h +LString.h +LTabGroup.h +LTabGroupView.h +LTableArrayStorage.h +LTableMonoGeometry.h +LTableSingleSelector.h +LTableView.h +LTextEditView.h +LTextTableView.h +LUndoer.h +LVariableArray.h +LView.h +LWindow.h +m68881.h +MacErrors.h +MacHeadersCarbon.h +machine/ansi.h +machine/builtins.h +machine/clock.h +machine/endian.h +machine/frame.h +machine/inline.h +machine/limits.h +machine/signal.h +machine/trap.h +mach/mach_host.h +mach/mach_init.h +mach/mach_interface.h +mach/mach_port.h +mach-o/dyld.h +MacLocales.h +MacMemory.h +MacTCP.h +MacTypes.h +MacWindows.h +malloc.h +map +mapicode.h +mapidefs.h +mapiguid.h +mapi.h +mapitags.h +mapiutil.h +mapix.h +Math64.h +math.h +mbstring.h +mem.h +memory +memory.h +Memory.h +MenuBar.h +Menu.h +Menus.h +Message.h +Mime.h +MixedMode.h +mlang.h +mmsystem.h +model.h +Movies.h +mpw/errno.h +mshtmhst.h +mshtml.h +mswsock.h +Multiprocessing.h +mutex.h +Navigation.h +ncompat.h +ncurses.h +netCore.h +netdb.h +net/if.h +netinet/in.h +netinet/in_systm.h +netinet/tcp.h +new +newexe.h +new.h +nl_types.h +NodeInfo.h +nss.h +nssilock.h +objbase.h +objidl.h +Objsafe.h +ojiapitests.h +ole2.h +oleidl.h +OpenGL/OpenGL.h +OpenTptInternet.h +OpenTransport.h +os2.h +OS.h +osreldate.h +OSUtils.h +Packages.h +Palettes.h +PALM_CMN.H +pango/pango-modules.h +pango/pangocairo.h +pango/pangofc-decoder.h +pango/pangofc-font.h +pango/pangofc-fontmap.h +pango/pango-break.h +pango/pango-fontmap.h +pango/pango.h +pango/pangoxft.h +pango/pango-utils.h +pascal.h +Patches.h +Path.h +pcfs/pc_dir.h +Pgenerr.h +PGenErr.h +Ph.h +photon/Pg.h +photon/PhProto.h +photon/PhRender.h +photon/PpProto.h +photon/PtProgress.h +photon/PtServer.h +photon/PtWebClient.h +photon/PxImage.h +pk11func.h +pk11pub.h +pkcs11t.h +PLStringFuncs.h +PMApplication.h +pmddim.h +poll.h +Polygon.h +portable.h +Power.h +PP_ClassHeaders.cp +PP_Constants.h +PPCToolbox.h +PP_DebugHeaders.cp +PP_KeyCodes.h +PP_Macros.h +PP_Messages.h +PP_Prefix.h +PP_Resources.h +PP_Types.h +Printing.h +Print/PMPrintingDialogExtensions.h +private/qucomextra_p.h +Processes.h +process.h +Process.h +proto/dos.h +proto/exec.h +psap.h +Pt.h +pthread.h +pwd.h +Python.h +QDOffscreen.h +queue +Quickdraw.h +QuickDraw.h +QuickTimeComponents.h +quipu/attr.h +rasdlg.h +raserror.h +ras.h +regex.h +Region.h +resolv.h +Resources.h +Retrace.h +rld_interface.h +rmsdef.h +Roster.h +rpc.h +rpcproxy.h +rpc/types.h +sane/sane.h +sane/sanei.h +sane/saneopts.h +Scrap.h +Screen.h +Script.h +ScrollBar.h +seccomon.h +sec.h +secmod.h +secmodt.h +secrng.h +security.h +secutil.h +semaphore.h +servprov.h +set +setjmp.h +SFNTLayoutTypes.h +SFNTTypes.h +share.h +shellapi.h +shlguid.h +shlobj.h +sigcontext.h +signal.h +SimpleGameSound.h +SIOUX.h +size_t.h +someincludefile.h +Sound.h +sqlite3.h +ssdef.h +sslerr.h +ssl.h +sslproto.h +sstream +stack +StandardFile.h +starlet.h +stat.h +statreg.cpp +statreg.h +stdarg.h +stdbool.h +stddef.h +stdint.h +stdio.h +stdlib.h +storage/FindDirectory.h +StorageKit.h +string +StringCompare.h +string.h +String.h +strings.h +Strings.h +StringView.h +stropts.h +strstrea.h +structs.h +stsdef.h +SupportDefs.h +support/String.h +support/SupportDefs.h +support/TLS.h +svrcore.h +symconst.h +sym.h +synch.h +syncmgr.h +sys/atomic_op.h +sys/bitypes.h +sys/byteorder.h +syscall.h +sys/cdefs.h +sys/cfgodm.h +sys/elf.h +sys/endian.h +sys/errno.h +sys/fault.h +sys/fcntl.h +sys/file.h +sys/filio.h +sys/frame.h +sys/immu.h +sys/inttypes.h +sys/ioccom.h +sys/ioctl.h +sys/ipc.h +sys/ldr.h +sys/link.h +sys/locking.h +syslog.h +sys/lwp.h +sys/machine.h +sys/mman.h +sys/mmu.h +sys/mount.h +sys/mpctl.h +sys/param.h +sys/pda.h +sys/poll.h +sys/ppc.h +sys/prctl.h +sys/priv.h +sys/procfs.h +sys/pstat.h +sys/ptrace.h +sys/queue.h +sys/quota.h +sys/reg.h +sys/regset.h +sys/resource.h +sys/sched.h +sys/select.h +sys/sem.h +sys/sendfile.h +sys/shm.h +sys/siginfo.h +sys/signal.h +sys/socket.h +sys/sockio.h +sys/sparc/frame.h +sys/stack.h +sys/statfs.h +sys/stat.h +sys/statvfs.h +sys/syscall.h +sys/sysctl.h +sys/sysinfo.h +sys/sysmp.h +sys/syssgi.h +sys/systeminfo.h +sys/timeb.h +sys/time.h +sys/times.h +sys/ttycom.h +sys/types.h +sys/ucontext.h +sys/uio.h +sys/un.h +sys/unistd.h +sys/utsname.h +sys/vfs.h +sys/wait.h +tables.h +TArray.h +TArrayIterator.h +task.h +tchar.h +TCHAR.H +termios.h +TextCommon.h +TextEdit.h +TextEncodingConverter.h +TextServices.h +TextUtils.h +TextView.h +th/PCR_Th.h +thread.h +ThreadManagerTests.h +Threads.h +time.h +Timer.h +tlhelp32.h +ToolUtils.h +tr1/functional +trace.h +Traps.h +typeinfo +types.h +Types.h +UAppleEventsMgr.h +UAttachments.h +ucontext.h +uconv.h +UCursor.h +ucx$inetdef.h +UDebugging.h +UDesktop.h +UDrawingState.h +UDrawingUtils.h +UEnvironment.h +UEventMgr.h +UException.h +UExtractFromAEDesc.h +UGWorld.h +UKeyFilters.h +ulocks.h +ulserrno.h +UMemoryMgr.h +UModalDialogs.h +UNavServicesDialogs.h +UnicodeBlockObjects.h +UnicodeConverter.h +UnicodeUtilities.h +unidef.h +unikbd.h +unistd.h +unix.h +unixio.h +unixlib.h +unknwn.h +UPrinting.h +UQuickTime.h +UReanimator.h +URegions.h +URegistrar.h +UResourceMgr.h +utility +urlhist.h +urlmon.h +UScrap.h +UScreenPort.h +UTCUtils.h +UTETextAction.h +UTEViewTextAction.h +UTextEdit.h +UTextTraits.h +utility +utime.h +UWindows.h +values.h +varargs.h +vcclr.h +vector +View.h +Volume.h +wab.h +wait.h +wchar.h +wctype.h +winbase.h +win/compobj.h +windef.h +Window.h +windows.h +Windows.h +windowsx.h +Wininet.h +winnls.h +winperf.h +winreg.h +Winreg.h +winsock2.h +winsock.h +winspool.h +winsvc.h +winuser.h +winver.h +wmem.h +workbench/startup.h +wtypes.h +wx/image.h +wx/listctrl.h +wx/log.h +wx/toolbar.h +wx/wx.h +wx/xrc/xmlres.h +X11/cursorfont.h +X11/extensions/Print.h +X11/extensions/shape.h +X11/extensions/scrnsaver.h +X11/extensions/XIElib.h +X11/extensions/XShm.h +X11/extensions/Xrender.h +X11/extensions/Xdamage.h +X11/extensions/Xcomposite.h +X11/Intrinsic.h +X11/keysymdef.h +X11/keysym.h +X11/Shell.h +X11/StringDefs.h +X11/Xatom.h +X11/Xft/Xft.h +X11/Xfuncproto.h +X11/X.h +X11/XKBlib.h +X11/Xlib.h +X11/Xlibint.h +X11/Xlocale.h +X11/Xos.h +X11/Xutil.h +xpt_struct.h +xpt_xdr.h +zmouse.h +sslt.h +smime.h +cms.h +sechash.h +secoidt.h +certdb.h +secerr.h +nssb64.h +secasn1.h +secder.h +certt.h +ocsp.h +keyhi.h +cryptohi.h +crmf.h +pk11pqg.h +cmmf.h +base64.h +secdert.h +secitem.h +secmime.h +nssckbi.h +pkcs12.h +p12plcy.h +pk11sdr.h +nspr.h +pratom.h +prbit.h +prclist.h +prcmon.h +prcountr.h +prcvar.h +prdtoa.h +prenv.h +prerr.h +prerror.h +prinet.h +prinit.h +prinrval.h +prio.h +pripcsem.h +prlink.h +prlock.h +prlog.h +prlong.h +prmem.h +prmon.h +prmwait.h +prnetdb.h +prolock.h +prpdce.h +prprf.h +prproces.h +prrng.h +prrwlock.h +prshm.h +prshma.h +prsystem.h +prthread.h +prtime.h +prtpool.h +prtrace.h +prtypes.h +prvrsion.h +plbase64.h +plerror.h +plgetopt.h +plresolv.h +plstr.h +plarenas.h +plarena.h +plhash.h +#if MOZ_NATIVE_PNG==1 +png.h +#endif +#if MOZ_NATIVE_ZLIB==1 +zlib.h +#endif +#if MOZ_ENABLE_LIBXUL!=1 +#if BUILD_STATIC_LIBS!=1 +#define WRAP_LCMS_HEADERS +#endif +#endif +#ifdef WRAP_LCMS_HEADERS +icc34.h +lcms.h +#endif +#ifdef MOZ_ENABLE_STARTUP_NOTIFICATION +libsn/sn.h +libsn/sn-common.h +libsn/sn-launchee.h +libsn/sn-launcher.h +libsn/sn-monitor.h +libsn/sn-util.h +#endif +#if MOZ_NATIVE_HUNSPELL==1 +hunspell.hxx +#endif +#if MOZ_NATIVE_BZ2==1 +bzlib.h +#endif +#if MOZ_PLATFORM_MAEMO==5 +hildon-uri.h +hildon-mime.h +hildon-file-chooser-dialog.h +libosso.h +osso-mem.h +#endif +#ifdef MOZ_ENABLE_GIO +gio/gio.h +#endif +#ifdef MOZ_ENABLE_LIBCONIC +conic/conicconnection.h +conic/conicconnectionevent.h +conic/conicstatisticsevent.h +#endif +#if MOZ_NATIVE_LIBEVENT==1 +event.h +#endif +#ifdef MOZ_ENABLE_LIBPROXY +proxy.h +#endif +#if MOZ_PLATFORM_MAEMO==6 +contentaction/contentaction.h +#endif +#if MOZ_TREE_PIXMAN!=1 +pixman.h +#endif +#if MOZ_ENABLE_MEEGOTOUCHSHARE +shareuiinterface.h +#endif +#if MOZ_NATIVE_LIBVPX==1 +vpx/vpx_decoder.h +vpx/vp8dx.h +#endif diff --git a/js/src/config/version.mk b/js/src/config/version.mk new file mode 100644 index 0000000..3877ff1 --- /dev/null +++ b/js/src/config/version.mk @@ -0,0 +1,85 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Win32 Version System. +# +# The Initial Developer of the Original Code is Netscape Communications Corporation +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +ifndef INCLUDED_VERSION_MK +INCLUDED_VERSION_MK=1 + +# Windows gmake build: +# Build default .rc file if $(RESFILE) isn't defined. +# TODO: +# PBI : Private build info. Not used currently. +# Guessing the best way would be to set an env var. +# BINARY : Binary name. Not used currently. +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +ifndef RESFILE +RCFILE=./module.rc +RESFILE=./module.res +_RC_STRING = -QUIET 1 -DEPTH $(DEPTH) -TOPSRCDIR $(topsrcdir) -OBJDIR . -SRCDIR $(srcdir) -DISPNAME $(MOZ_APP_DISPLAYNAME) -APPVERSION $(MOZ_APP_VERSION) +ifdef MOZILLA_OFFICIAL +_RC_STRING += -OFFICIAL 1 +endif +ifdef MOZ_DEBUG +_RC_STRING += -DEBUG 1 +endif +ifdef MODULE +_RC_STRING += -MODNAME $(MODULE) +endif +ifdef PROGRAM +_RC_STRING += -BINARY $(PROGRAM) +else +ifdef _PROGRAM +_RC_STRING += -BINARY $(_PROGRAM) +else +ifdef SHARED_LIBRARY +_RC_STRING += -BINARY $(SHARED_LIBRARY) +endif +endif +endif +ifdef RCINCLUDE +_RC_STRING += -RCINCLUDE $(srcdir)/$(RCINCLUDE) +endif + +GARBAGE += $(RESFILE) $(RCFILE) + +#dummy target so $(RCFILE) doesn't become the default =P +all:: + +$(RCFILE): $(RCINCLUDE) $(topsrcdir)/config/version_win.pl + $(PERL) $(topsrcdir)/config/version_win.pl $(_RC_STRING) + +endif # RESFILE +endif # Windows + +endif diff --git a/js/src/config/version_win.pl b/js/src/config/version_win.pl new file mode 100755 index 0000000..2e5b880 --- /dev/null +++ b/js/src/config/version_win.pl @@ -0,0 +1,436 @@ +#!/usr/bin/perl -w + +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Win32 Version System. +# +# The Initial Developer of the Original Code is Brian Bober +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +#use diagnostics; +require strict; +my $dir = $0; +$dir =~ s/[^\/]*$//; +push(@INC, "$dir"); +require "Moz/Milestone.pm"; +use Getopt::Long; +use Getopt::Std; +use POSIX; + +# Calculate the number of days since Jan. 1, 2000 from a buildid string +sub daysFromBuildID +{ + my ($buildid,) = @_; + + my ($y, $m, $d, $h) = ($buildid =~ /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/); + $d || die("Unrecognized buildid string."); + + my $secondstodays = 60 * 60 * 24; + return sprintf("%d", + (POSIX::mktime(00, 00, 00, $d, $m - 1, $y - 1900) - + POSIX::mktime(00, 00, 00, 01, 00, 100)) / $secondstodays); +} + +#Creates version resource file + +#Paramaters are passed on the command line: + +#Example: -MODNAME nsToolkitCompsModule -DEBUG=1 + +# DEBUG - Mozilla's global debug variable - tells if its debug version +# OFFICIAL - tells Mozilla is building a milestone or nightly +# MSTONE - tells which milestone is being built; +# OBJDIR - Holds the object directory; +# MODNAME - tells what the name of the module is like nsBMPModule +# DEPTH - Holds the path to the root obj dir +# TOPSRCDIR - Holds the path to the root mozilla dir +# SRCDIR - Holds module.ver and source +# BINARY - Holds the name of the binary file +# DISPNAME - Holds the display name of the built application +# APPVERSION - Holds the version string of the built application +# RCINCLUDE - Holds the name of the RC File to include or "" +# QUIET - Turns off output + +#Description and Comment come from module.ver +#Bug 23560 +#http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/rc_7x2d.asp + +#Get next .ver file entry +sub getNextEntry +{ + while () + { + my $mline = $_; + ($mline) = split(/#/,$mline); + my ($entry, $value)=split(/=/,$mline,2); + if (defined($entry)) + { + if (defined($value)) + { + $entry =~ s/^\s*(.*?)\s*$/$1/; + $value =~ s/^\s*(.*?)\s*$/$1/; + return ($entry,$value); + } + } + } + return undef; +} + +my ($quiet,$objdir,$debug,$official,$milestone,$buildid,$module,$binary,$depth,$rcinclude,$srcdir,$fileversion,$productversion); + +GetOptions( "QUIET" => \$quiet, + "DEBUG=s" => \$debug, + "OFFICIAL=s" => \$official, + "MSTONE=s" => \$milestone, + "MODNAME=s" => \$module, + "BINARY=s" => \$binary, + "DISPNAME=s" => \$displayname, + "APPVERSION=s" => \$appversion, + "SRCDIR=s" => \$srcdir, + "TOPSRCDIR=s" => \$topsrcdir, + "DEPTH=s" => \$depth, + "RCINCLUDE=s" => \$rcinclude, + "OBJDIR=s" => \$objdir); +if (!defined($debug)) {$debug="";} +if (!defined($official)) {$official="";} +if (!defined($milestone)) {$milestone="";} +if (!defined($module)) {$module="";} +if (!defined($binary)) {$binary="";} +if (!defined($displayname)) {$displayname="Mozilla";} +if (!defined($appversion)) {$appversion=$milestone;} +if (!defined($depth)) {$depth=".";} +if (!defined($rcinclude)) {$rcinclude="";} +if (!defined($objdir)) {$objdir=".";} +if (!defined($srcdir)) {$srcdir=".";} +if (!defined($topsrcdir)) {$topsrcdir=".";} +my $mfversion = "Personal"; +my $mpversion = "Personal"; +my @fileflags = ("0"); +my $comment=""; +my $description=""; +if (!defined($module)) +{ + $module = $binary; + ($module) = split(/\./,$module); +} + +my $bufferstr=" "; + +my $MILESTONE_FILE = "$topsrcdir/config/milestone.txt"; +my $BUILDID_FILE = "$depth/config/buildid"; + +#Read module.ver file +#Version file overrides for WIN32: +#WIN32_MODULE_COMMENT +#WIN32_MODULE_DESCRIPTION +#WIN32_MODULE_FILEVERSION +#WIN32_MODULE_COMPANYNAME +#WIN32_MODULE_FILEVERSION_STRING +#WIN32_MODULE_NAME +#WIN32_MODULE_COPYRIGHT +#WIN32_MODULE_TRADEMARKS +#WIN32_MODULE_ORIGINAL_FILENAME +#WIN32_MODULE_PRODUCTNAME +#WIN32_MODULE_PRODUCTVERSION +#WIN32_MODULE_PRODUCTVERSION_STRING + +#Override values obtained from the .ver file +my $override_comment; +my $override_description; +my $override_fileversion; +my $override_company; +my $override_mfversion; +my $override_module; +my $override_copyright; +my $override_trademarks; +my $override_filename; +my $override_productname; +my $override_productversion; +my $override_mpversion; +if (open(VERFILE, "<$srcdir/module.ver")) +{ + + my ($a,$b) = getNextEntry(); + while (defined($a)) + { + if ($a eq "WIN32_MODULE_COMMENT") { $override_comment = $b; } + if ($a eq "WIN32_MODULE_DESCRIPTION") { $override_description = $b; } + if ($a eq "WIN32_MODULE_FILEVERSION") { $override_fileversion = $b; } + if ($a eq "WIN32_MODULE_COMPANYNAME") { $override_company = $b; } + if ($a eq "WIN32_MODULE_FILEVERSION_STRING") { $override_mfversion = $b; } + if ($a eq "WIN32_MODULE_NAME") { $override_module = $b; } + if ($a eq "WIN32_MODULE_COPYRIGHT") { $override_copyright = $b; } + if ($a eq "WIN32_MODULE_TRADEMARKS") { $override_trademarks = $b; } + if ($a eq "WIN32_MODULE_ORIGINAL_FILENAME") { $override_filename = $b; } + if ($a eq "WIN32_MODULE_PRODUCTNAME") { $override_productname = $b; } + if ($a eq "WIN32_MODULE_PRODUCTVERSION") { $override_productversion = $b; } + if ($a eq "WIN32_MODULE_PRODUCTVERSION_STRING") { $override_mpversion = $b; } + ($a,$b) = getNextEntry(); + } + close(VERFILE) +} +else +{ + if (!$quiet || $quiet ne "1") { print "$bufferstr" . "WARNING: No module.ver file included ($module, $binary). Default values used\n"; } +} +#Get rid of trailing and leading whitespace +$debug =~ s/^\s*(.*)\s*$/$1/; +$comment =~ s/^\s*(.*)\s*$/$1/; +$official =~ s/^\s*(.*)\s*$/$1/; +$milestone =~ s/^\s*(.*)\s*$/$1/; +$description =~ s/^\s*(.*)\s*$/$1/; +$module =~ s/^\s*(.*)\s*$/$1/; +$depth =~ s/^\s*(.*)\s*$/$1/; +$binary =~ s/^\s*(.*)\s*$/$1/; +$displayname =~ s/^\s*(.*)\s*$/$1/; + +open(BUILDID, "<", $BUILDID_FILE) || die("Couldn't open buildid file: $BUILDID_FILE"); +$buildid = ; +$buildid =~ s/\s*$//; +close BUILDID; + +my $daycount = daysFromBuildID($buildid); + +if ($milestone eq "") { + $milestone = Moz::Milestone::getOfficialMilestone($MILESTONE_FILE); +} + +$mfversion = $mpversion = $milestone; +if ($appversion eq "") { + $appversion = $milestone; +} + +if ($debug eq "1") +{ + push @fileflags, "VS_FF_DEBUG"; + $mpversion .= " Debug"; + $mfversion .= " Debug"; +} + +if ($official ne "1") { + push @fileflags, "VS_FF_PRIVATEBUILD"; +} + +if ($milestone =~ /[a-z]/) { + push @fileflags, "VS_FF_PRERELEASE"; +} + +my @mstone = split(/\./,$milestone); +$mstone[1] =~s/\D.*$//; +if (!$mstone[2]) { + $mstone[2] = "0"; +} +else { + $mstone[2] =~s/\D.*$//; +} +$fileversion = $productversion="$mstone[0],$mstone[1],$mstone[2],$daycount"; + +my @appver = split(/\./,$appversion); +for ($j = 1; $j < 4; $j++) +{ + if (!$appver[$j]) { + $appver[$j] = "0"; + } + else { + $appver[$j] =~s/\D.*$//; + } +} +my $winappversion = "$appver[0],$appver[1],$appver[2],$appver[3]"; + +my $copyright = "License: MPL 1.1/GPL 2.0/LGPL 2.1"; +my $company = "Mozilla Foundation"; +my $trademarks = "Mozilla"; +my $productname = $displayname; + + +if (defined($override_comment)){$override_comment =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g; $comment=$override_comment;} +if (defined($override_description)){$override_description =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g; $description=$override_description;} +if (defined($override_fileversion)){$override_fileversion =~ s/\@MOZ_APP_WINVERSION\@/$winappversion/g; $fileversion=$override_fileversion;} +if (defined($override_mfversion)){$override_mfversion =~ s/\@MOZ_APP_VERSION\@/$appversion/g; $mfversion=$override_mfversion;} +if (defined($override_company)){$company=$override_company;} +if (defined($override_module)){$override_module =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g; $module=$override_module;} +if (defined($override_copyright)){$override_copyright =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g; $copyright=$override_copyright;} +if (defined($override_trademarks)){$override_trademarks =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g; $trademarks=$override_trademarks;} +if (defined($override_filename)){$binary=$override_filename;} +if (defined($override_productname)){$override_productname =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g; $productname=$override_productname;} +if (defined($override_productversion)){$override_productversion =~ s/\@MOZ_APP_WINVERSION\@/$winappversion/g; $productversion=$override_productversion;} +if (defined($override_mpversion)){$override_mpversion =~ s/\@MOZ_APP_VERSION\@/$appversion/g; $mpversion=$override_mpversion;} + + +#Override section + +open(RCFILE, ">$objdir/module.rc") || die("Can't edit module.rc - It must be locked.\n"); +print RCFILE qq{ +// ***** BEGIN LICENSE BLOCK ***** +// Version: MPL 1.1/GPL 2.0/LGPL 2.1 +// +// The contents of this file are subject to the Mozilla Public License Version +// 1.1 (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.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" basis, +// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +// for the specific language governing rights and limitations under the +// License. +// +// The Original Code is the Win32 Version System. +// +// The Initial Developer of the Original Code is Brian Bober +// Portions created by the Initial Developer are Copyright (C) 2001 +// the Initial Developer. All Rights Reserved. +// +// Contributor(s): +// +// Alternatively, the contents of this file may be used under the terms of +// either the GNU General Public License Version 2 or later (the "GPL"), or +// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +// in which case the provisions of the GPL or the LGPL are applicable instead +// of those above. If you wish to allow use of your version of this file only +// under the terms of either the GPL or the LGPL, and not to allow others to +// use your version of this file under the terms of the MPL, indicate your +// decision by deleting the provisions above and replace them with the notice +// and other provisions required by the GPL or the LGPL. If you do not delete +// the provisions above, a recipient may use your version of this file under +// the terms of any one of the MPL, the GPL or the LGPL. +// +// ***** END LICENSE BLOCK ***** + +#include + +// Note: if you contain versioning information in an included +// RC script, it will be discarded +// Use module.ver to explicitly set these values + +// Do not edit this file. Changes won't affect the build. + +}; + +my $versionlevel=0; +my $insideversion=0; +if (open(RCINCLUDE, "<$rcinclude")) +{ + print RCFILE "// From included resource $rcinclude\n"; +# my $mstring=""; + while () + { + $_ =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g; + print RCFILE $_; +# my $instr=$_; +# chomp($instr); +# $mstring .= "$instr\;"; + } + close(RCINCLUDE); +# $mstring =~ s/\/\*.*\*\///g; +# my @mlines = split(/\;/,$mstring); +# for(@mlines) +# { +# my ($nocomment)=split(/\/\//,$_); +# if (defined($nocomment) && $nocomment ne "") +# { +# my ($firststring,$secondstring) = split(/\s+/,$nocomment); +# if (!defined($firststring)) {$firststring="";} +# if (!defined($secondstring)) {$secondstring="";} +# if ($secondstring eq "VERSIONINFO") +# { +#if (!$quiet || $quiet ne "1") { +# print "$bufferstr" . "WARNING: Included RC file ($rcinclude, $module, $binary)\n"; +# print "$bufferstr" . "WARNING: contains versioning information that will be discarded\n"; +# print "$bufferstr" . "WARNING: Remove it and use relevant overrides (in module.ver)\n"; +#} +# $versionlevel = 0; +# $insideversion = 1; +# } +# if ($firststring eq "BEGIN") { $versionlevel++; } +# if ($secondstring eq "END") +# { +# $versionlevel--; +# if ($insideversion==1 && $versionlevel==0) {$versionlevel=0;} +# } +# my $includecheck = $firststring . $secondstring; +# $includecheck =~ s/<|>/"/g; +# $includecheck = lc($includecheck); +# if ($includecheck ne "#include\"winver.h\"") +# { +# if ($insideversion == 0 && $versionlevel == 0) +# { +# print RCFILE "$nocomment\n"; +# } +# } +# } +# } + +} + +my $fileflags = join(' | ', @fileflags); + +print RCFILE qq{ + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +1 VERSIONINFO + FILEVERSION $fileversion + PRODUCTVERSION $productversion + FILEFLAGSMASK 0x3fL + FILEFLAGS $fileflags + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "$comment" + VALUE "LegalCopyright", "$copyright" + VALUE "CompanyName", "$company" + VALUE "FileDescription", "$description" + VALUE "FileVersion", "$mfversion" + VALUE "ProductVersion", "$mpversion" + VALUE "InternalName", "$module" + VALUE "LegalTrademarks", "$trademarks" + VALUE "OriginalFilename", "$binary" + VALUE "ProductName", "$productname" + VALUE "BuildID", "$buildid" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +}; +close(RCFILE); diff --git a/js/src/configure b/js/src/configure new file mode 100755 index 0000000..8a0543e --- /dev/null +++ b/js/src/configure @@ -0,0 +1,16303 @@ +#! /bin/sh + +if test `uname -s | grep -c MINGW 2>/dev/null` != "0"; then + msyshost=1 +fi + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --with-dist-dir=DIR Use DIR as 'dist' staging area. DIR may be + relative to the top of SpiderMonkey build tree, + or absolute." +ac_help="$ac_help + --disable-compile-environment + Disable compiler/library checks." +ac_help="$ac_help + --disable-shared-js + Do not create a shared library." +ac_help="$ac_help + --with-android-ndk=DIR + location where the Android NDK can be found" +ac_help="$ac_help + --with-android-toolchain=DIR + location of the android toolchain, default NDK/build/prebuilt/HOST/arm-eabi-4.4.0" +ac_help="$ac_help + --with-android-version=VER + android platform version, default 5" +ac_help="$ac_help + --with-android-sdk=DIR + location where the Android SDK can be found (base directory, e.g. .../android/platforms/android-6)" +ac_help="$ac_help + --with-symbian-sdk=SYMBIAN_SDK_DIR + The path to the Symbian SDK" +ac_help="$ac_help + --with-windows-version=WINSDK_TARGETVER + Highest Windows version to target using this SDK + 502: Windows Server 2003 + 600: Windows Vista + 601: Windows 7" +ac_help="$ac_help + --enable-macos-target=VER (default=10.5) + Set the minimum MacOS version needed at runtime" +ac_help="$ac_help + --with-macos-sdk=dir Location of platform SDK to use (Mac OS X only)" +ac_help="$ac_help + --with-x use the X Window System" +ac_help="$ac_help + --disable-os2-high-mem Disable high-memory support on OS/2" +ac_help="$ac_help + --enable-profiling Set compile flags necessary for using sampling profilers (e.g. shark, perf)" +ac_help="$ac_help + --disable-windows-mobile-components + Disable Windows Mobile specific components from + CE build" +ac_help="$ac_help + --disable-methodjit Disable method JIT support" +ac_help="$ac_help + --disable-monoic Disable use of MICs by JIT compiler" +ac_help="$ac_help + --disable-polyic Disable use of PICs by JIT compiler" +ac_help="$ac_help + --disable-tracejit Disable tracing JIT support" +ac_help="$ac_help + --enable-methodjit-spew Enable method JIT spew support" +ac_help="$ac_help + --enable-dtrace build with dtrace support if available (default=no)" +ac_help="$ac_help + --with-pthreads Force use of system pthread library with NSPR " +ac_help="$ac_help + --with-system-nspr Use an NSPR that is already built and installed. + Use the 'nspr-config' script in the current path, + or look for the script in the directories given with + --with-nspr-exec-prefix or --with-nspr-prefix. + (Those flags are only checked if you specify + --with-system-nspr.)" +ac_help="$ac_help + --with-nspr-cflags=FLAGS + Pass FLAGS to CC when building code that uses NSPR. + Use this when there's no accurate nspr-config + script available. This is the case when building + SpiderMonkey as part of the Mozilla tree: the + top-level configure script computes NSPR flags + that accomodate the quirks of that environment." +ac_help="$ac_help + --with-nspr-libs=LIBS Pass LIBS to LD when linking code that uses NSPR. + See --with-nspr-cflags for more details." +ac_help="$ac_help + --with-nspr-prefix=PFX Prefix where NSPR is installed" +ac_help="$ac_help + --with-nspr-exec-prefix=PFX + Exec prefix where NSPR is installed" +ac_help="$ac_help + --with-arm-kuser Use kuser helpers (Linux/ARM only -- requires kernel 2.6.13 or later)" +ac_help="$ac_help + --enable-ui-locale=ab-CD + Select the user interface locale (default: en-US)" +ac_help="$ac_help + --disable-tests Do not build test libraries & programs" +ac_help="$ac_help + --enable-thumb2 Enable Thumb2 instruction set (implies ARMv7)" +ac_help="$ac_help + --with-cpu-arch=arch Use specific arm architecture CPU features, default armv7" +ac_help="$ac_help + --enable-debug[=DBG] Enable building with developer debug info + (using compiler flags DBG)" +ac_help="$ac_help + --with-debug-label=LABELS + Define DEBUG_ for each comma-separated + value given." +ac_help="$ac_help + --disable-optimize Disable compiler optimization + --enable-optimize=[OPT] Specify compiler optimization flags [OPT=-O]" +ac_help="$ac_help + --enable-debugger-info-modules + Enable/disable debugger info for specific modules" +ac_help="$ac_help + --enable-debug-symbols[=DBG] + Enable debugging symbols (using compiler flags DBG)" +ac_help="$ac_help + --disable-warnings-as-errors + Disable treating of warnings as errors" +ac_help="$ac_help + --enable-trace-malloc Enable malloc tracing" +ac_help="$ac_help + --enable-jemalloc Replace memory allocator with jemalloc" +ac_help="$ac_help + --enable-wrap-malloc Wrap malloc calls (gnu linker only)" +ac_help="$ac_help + --with-wrap-malloc=DIR Location of malloc wrapper library" +ac_help="$ac_help + --enable-trace-jscalls Enable JS call enter/exit callback (default=no)" +ac_help="$ac_help + --enable-tracevis Enable TraceVis tracing tool (default=no)" +ac_help="$ac_help + --enable-gctimer Enable GC timer (default=no)" +ac_help="$ac_help + --enable-valgrind Enable Valgrind integration hooks (default=no)" +ac_help="$ac_help + --enable-jprof Enable jprof profiling tool (needs mozilla/tools/jprof). Implies --enable-profiling." +ac_help="$ac_help + --enable-shark Enable shark remote profiling. Implies --enable-profiling." +ac_help="$ac_help + --enable-callgrind Enable callgrind profiling" +ac_help="$ac_help + --enable-vtune Enable vtune profiling. Implies --enable-profiling." +ac_help="$ac_help + --enable-gczeal Enable zealous GCing" +ac_help="$ac_help + --with-ccache[=path/to/ccache] + Enable compiling with ccache" +ac_help="$ac_help + --with-static-checking=path/to/gcc_dehydra.so + Enable static checking of code using GCC-dehydra" +ac_help="$ac_help + --enable-strip Enable stripping of libs & executables " +ac_help="$ac_help + --enable-install-strip Enable stripping of libs & executables when packaging " +ac_help="$ac_help + --enable-timeline Enable timeline services " +ac_help="$ac_help + --enable-quantify Enable Quantify support (Windows only) " +ac_help="$ac_help + --enable-xterm-updates Update XTERM titles with current command." +ac_help="$ac_help + --disable-profile-guided-optimization + Don't build with PGO even if called via make profiledbuild" +ac_help="$ac_help + --disable-pedantic Issue all warnings demanded by strict ANSI C " +ac_help="$ac_help + --enable-cpp-rtti Enable C++ RTTI " +ac_help="$ac_help + --enable-cpp-exceptions Enable C++ exceptions " +ac_help="$ac_help + --disable-auto-deps Do not automatically generate dependency info" +ac_help="$ac_help + --disable-md Do not use compiler-based dependencies " +ac_help="$ac_help + --enable-static Enable building of internal static libs" +ac_help="$ac_help + --enable-readline Link js shell to system readline library" +ac_help="$ac_help + --enable-ctypes Enable js-ctypes (default=no)" +ac_help="$ac_help + --with-sync-build-files=DIR + Check that files in 'config' and 'build' match + their originals in 'DIR/config' and 'DIR/build'. + This helps keep the SpiderMonkey build machinery + in sync with Mozilla's, on which it is based." +ac_help="$ac_help + --enable-threadsafe Enable support for multiple threads." + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=jsapi.h + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + +ac_aux_dir= +for ac_dir in ${srcdir}/build/autoconf $srcdir/${srcdir}/build/autoconf; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in ${srcdir}/build/autoconf $srcdir/${srcdir}/build/autoconf" 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:759: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 +echo "configure:780: checking target system type" >&5 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 +echo "configure:798: checking build system type" >&5 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +TARGET_CPU="${target_cpu}" +TARGET_VENDOR="${target_vendor}" +TARGET_OS="${target_os}" + +CFLAGS="${CFLAGS=}" +CPPFLAGS="${CPPFLAGS=}" +CXXFLAGS="${CXXFLAGS=}" +LDFLAGS="${LDFLAGS=}" +HOST_CFLAGS="${HOST_CFLAGS=}" +HOST_CXXFLAGS="${HOST_CXXFLAGS=}" +HOST_LDFLAGS="${HOST_LDFLAGS=}" + +_SUBDIR_CC="$CC" +_SUBDIR_CXX="$CXX" +_SUBDIR_CFLAGS="$CFLAGS" +_SUBDIR_CPPFLAGS="$CPPFLAGS" +_SUBDIR_CXXFLAGS="$CXXFLAGS" +_SUBDIR_LDFLAGS="$LDFLAGS" +_SUBDIR_HOST_CC="$HOST_CC" +_SUBDIR_HOST_CFLAGS="$HOST_CFLAGS" +_SUBDIR_HOST_CXXFLAGS="$HOST_CXXFLAGS" +_SUBDIR_HOST_LDFLAGS="$HOST_LDFLAGS" +_SUBDIR_CONFIG_ARGS="$ac_configure_args" + +NSPR_VERSION=4 + +PERL_VERSION=5.006 +PYTHON_VERSION=2.5 +WINDRES_VERSION=2.14.90 +W32API_VERSION=3.8 + +MSMANIFEST_TOOL= + +MISSING_X= +for ac_prog in mawk gawk nawk awk +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:859: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AWK="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AWK="$ac_cv_prog_AWK" +if test -n "$AWK"; then + echo "$ac_t""$AWK" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AWK" && break +done + + +USE_PTHREADS= +_PTHREAD_LDFLAGS="" + +_topsrcdir=`cd \`dirname $0\`; pwd` +_objdir=`pwd` + +if test "$_topsrcdir" != "$_objdir" +then + # Check for a couple representative files in the source tree + _conflict_files= + for file in $_topsrcdir/Makefile $_topsrcdir/config/autoconf.mk; do + if test -f $file; then + _conflict_files="$_conflict_files $file" + fi + done + if test "$_conflict_files"; then + echo "***" + echo "* Your source tree contains these files:" + for file in $_conflict_files; do + echo "* $file" + done + cat 1>&2 <<-EOF + * This indicates that you previously built in the source tree. + * A source tree build can confuse the separate objdir build. + * + * To clean up the source tree: + * 1. cd $_topsrcdir + * 2. gmake distclean + *** + EOF + exit 1 + break + fi +fi +MOZ_BUILD_ROOT=`pwd` + + +# Check whether --with-dist-dir or --without-dist-dir was given. +if test "${with_dist_dir+set}" = set; then + withval="$with_dist_dir" + TOP_DIST=$withval +else + TOP_DIST=dist +fi + + + +if test -z "$CROSS_COMPILE"; then +case "$target" in +*-cygwin*|*-mingw*|*-msvc*|*-mks*) + if test -z "$CC"; then CC=cl; fi + if test -z "$CXX"; then CXX=cl; fi + if test -z "$CPP"; then CPP="cl -E -nologo"; fi + if test -z "$CXXCPP"; then CXXCPP="cl -TP -E -nologo"; ac_cv_prog_CXXCPP="$CXXCPP"; fi + if test -z "$LD"; then LD=link; fi + if test -z "$AS"; then + case "${target_cpu}" in + i*86) + AS=ml; + ;; + x86_64) + AS=ml64; + ;; + esac + fi + if test -z "$MIDL"; then MIDL=midl; fi + ;; +*-darwin*) + if test -z "$CC"; then CC=gcc-4.2; fi + if test -z "$CXX"; then CXX=g++-4.2; fi + ;; +esac +fi + +COMPILE_ENVIRONMENT=1 +# Check whether --enable-compile-environment or --disable-compile-environment was given. +if test "${enable_compile_environment+set}" = set; then + enableval="$enable_compile_environment" + if test "$enableval" = "no"; then + COMPILE_ENVIRONMENT= + elif test "$enableval" = "yes"; then + : + else + { echo "configure: error: Option, compile-environment, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + + + for ac_prog in $PERL perl5 perl +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:983: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_PERL'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$PERL" in + /*) + ac_cv_path_PERL="$PERL" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_PERL="$PERL" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_PERL="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +PERL="$ac_cv_path_PERL" +if test -n "$PERL"; then + echo "$ac_t""$PERL" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$PERL" && break +done + + if test "$msyshost"; then + case "$PERL" in + /*) + tmp_DIRNAME=`dirname "$PERL"` + tmp_BASENAME=`basename "$PERL"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + PERL="$tmp_PWD/$tmp_BASENAME" + if test -e "$PERL.exe"; then + PERL="$PERL.exe" + fi + esac + fi + +if test -z "$PERL" -o "$PERL" = ":"; then + { echo "configure: error: perl not found in \$PATH" 1>&2; exit 1; } +fi + +# Check whether --enable-shared-js or --disable-shared-js was given. +if test "${enable_shared_js+set}" = set; then + enableval="$enable_shared_js" + if test "$enableval" = "yes"; then + DISABLE_SHARED_JS=0 + elif test "$enableval" = "no"; then + DISABLE_SHARED_JS=1 + else + { echo "configure: error: Option, shared-js, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +if test "$DISABLE_SHARED_JS" = "1" ; then + cat >> confdefs.h <<\EOF +#define STATIC_EXPORTABLE_JS_API 1 +EOF + +else + JS_SHARED_LIBRARY=1 +fi + + + +# Check whether --with-android-ndk or --without-android-ndk was given. +if test "${with_android_ndk+set}" = set; then + withval="$with_android_ndk" + android_ndk=$withval +fi + + +# Check whether --with-android-toolchain or --without-android-toolchain was given. +if test "${with_android_toolchain+set}" = set; then + withval="$with_android_toolchain" + android_toolchain=$withval +fi + + + +# Check whether --with-android-version or --without-android-version was given. +if test "${with_android_version+set}" = set; then + withval="$with_android_version" + android_version=$withval +else + android_version=5 +fi + + +# Check whether --with-android-sdk or --without-android-sdk was given. +if test "${with_android_sdk+set}" = set; then + withval="$with_android_sdk" + android_sdk=$withval +fi + + +if test "$target" = "arm-android-eabi" ; then + if test -z "$android_ndk" ; then + { echo "configure: error: You must specify --with-android-ndk=/path/to/ndk when targeting Android." 1>&2; exit 1; } + fi + + if test -z "$android_sdk" ; then + { echo "configure: error: You must specify --with-android-sdk=/path/to/sdk when targeting Android." 1>&2; exit 1; } + fi + + android_platform_tools="$android_sdk"/../../platform-tools + if test ! -d "$android_platform_tools" ; then + android_platform_tools="$android_sdk"/tools # SDK Tools < r8 + fi + + if test -z "$android_toolchain" ; then + android_toolchain="$android_ndk"/build/prebuilt/`uname -s | tr "[:upper:]" "[:lower:]"`-x86/arm-eabi-4.4.0 + fi + + if test -z "$android_platform" ; then + android_platform="$android_ndk"/build/platforms/android-"$android_version"/arch-"$target_cpu" + fi + + AS="$android_toolchain"/bin/arm-eabi-as + CC="$android_toolchain"/bin/arm-eabi-gcc + CXX="$android_toolchain"/bin/arm-eabi-g++ + CPP="$android_toolchain"/bin/arm-eabi-cpp + LD="$android_toolchain"/bin/arm-eabi-ld + AR="$android_toolchain"/bin/arm-eabi-ar + RANLIB="$android_toolchain"/bin/arm-eabi-ranlib + STRIP="$android_toolchain"/bin/arm-eabi-strip + + CPPFLAGS="-I$android_platform/usr/include $CPPFLAGS" + CFLAGS="-mandroid -I$android_platform/usr/include -fno-short-enums -fno-exceptions $CFLAGS" + CXXFLAGS="-mandroid -I$android_platform/usr/include -fno-short-enums -fno-exceptions $CXXFLAGS" + + LDFLAGS="-mandroid -L$android_platform/usr/lib -Wl,-rpath-link=$android_platform/usr/lib --sysroot=$android_platform -llog -Wl,--allow-shlib-undefined $LDFLAGS" + + if test -z "$HOST_CPPFLAGS" ; then + HOST_CPPFLAGS=" " + fi + if test -z "$HOST_CFLAGS" ; then + HOST_CFLAGS=" " + fi + if test -z "$HOST_CXXFLAGS" ; then + HOST_CXXFLAGS=" " + fi + if test -z "$HOST_LDFLAGS" ; then + HOST_LDFLAGS=" " + fi + + ANDROID_NDK="${android_ndk}" + ANDROID_TOOLCHAIN="{android_toolchain}" + ANDROID_PLATFORM="{android_platform}" + ANDROID_SDK="${android_sdk}" + ANDROID_PLATFORM_TOOLS="${android_platform_tools}" + ANDROID_VERSION="${android_version}" + + # save these for libffi's subconfigure, + # which doesn't know how to figure this stuff out on its own + ANDROID_CFLAGS="$CFLAGS" + ANDROID_CPPFLAGS="$CPPFLAGS" + ANDROID_LDFLAGS="$LDFLAGS" + + cat >> confdefs.h <<\EOF +#define ANDROID 1 +EOF + + cat >> confdefs.h <&6 +echo "configure:1194: checking for host c compiler" >&5 + for ac_prog in $HOST_CC gcc cc /usr/ucb/cc cl icc +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1200: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_HOST_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$HOST_CC"; then + ac_cv_prog_HOST_CC="$HOST_CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_HOST_CC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +HOST_CC="$ac_cv_prog_HOST_CC" +if test -n "$HOST_CC"; then + echo "$ac_t""$HOST_CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$HOST_CC" && break +done +test -n "$HOST_CC" || HOST_CC="""" + + if test -z "$HOST_CC"; then + { echo "configure: error: no acceptable c compiler found in \$PATH" 1>&2; exit 1; } + fi + echo "$ac_t""$HOST_CC" 1>&6 + echo $ac_n "checking for host c++ compiler""... $ac_c" 1>&6 +echo "configure:1235: checking for host c++ compiler" >&5 + for ac_prog in $HOST_CXX $CCC c++ g++ gcc CC cxx cc++ cl icc +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1241: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_HOST_CXX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$HOST_CXX"; then + ac_cv_prog_HOST_CXX="$HOST_CXX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_HOST_CXX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +HOST_CXX="$ac_cv_prog_HOST_CXX" +if test -n "$HOST_CXX"; then + echo "$ac_t""$HOST_CXX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$HOST_CXX" && break +done +test -n "$HOST_CXX" || HOST_CXX="""" + + if test -z "$HOST_CXX"; then + { echo "configure: error: no acceptable c++ compiler found in \$PATH" 1>&2; exit 1; } + fi + echo "$ac_t""$HOST_CXX" 1>&6 + + if test -z "$HOST_CFLAGS"; then + HOST_CFLAGS="$CFLAGS" + fi + if test -z "$HOST_CXXFLAGS"; then + HOST_CXXFLAGS="$CXXFLAGS" + fi + if test -z "$HOST_LDFLAGS"; then + HOST_LDFLAGS="$LDFLAGS" + fi + if test -z "$HOST_AR_FLAGS"; then + HOST_AR_FLAGS="$AR_FLAGS" + fi + for ac_prog in $HOST_RANLIB ranlib +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1293: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_HOST_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$HOST_RANLIB"; then + ac_cv_prog_HOST_RANLIB="$HOST_RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy=":" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_HOST_RANLIB="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +HOST_RANLIB="$ac_cv_prog_HOST_RANLIB" +if test -n "$HOST_RANLIB"; then + echo "$ac_t""$HOST_RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$HOST_RANLIB" && break +done +test -n "$HOST_RANLIB" || HOST_RANLIB="ranlib" + + for ac_prog in $HOST_AR ar +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1328: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_HOST_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$HOST_AR"; then + ac_cv_prog_HOST_AR="$HOST_AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy=":" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_HOST_AR="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +HOST_AR="$ac_cv_prog_HOST_AR" +if test -n "$HOST_AR"; then + echo "$ac_t""$HOST_AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$HOST_AR" && break +done +test -n "$HOST_AR" || HOST_AR="ar" + + CC="$HOST_CC" + CFLAGS="$HOST_CFLAGS" + LDFLAGS="$HOST_LDFLAGS" + + echo $ac_n "checking whether the host c compiler ($HOST_CC $HOST_CFLAGS $HOST_LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1363: checking whether the host c compiler ($HOST_CC $HOST_CFLAGS $HOST_LDFLAGS) works" >&5 + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_prog_hostcc_works=1 echo "$ac_t""yes" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + { echo "configure: error: installation or configuration problem: host compiler $HOST_CC cannot create executables." 1>&2; exit 1; } +fi +rm -f conftest* + + CC="$HOST_CXX" + CFLAGS="$HOST_CXXFLAGS" + + echo $ac_n "checking whether the host c++ compiler ($HOST_CXX $HOST_CXXFLAGS $HOST_LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1387: checking whether the host c++ compiler ($HOST_CXX $HOST_CXXFLAGS $HOST_LDFLAGS) works" >&5 + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_prog_hostcxx_works=1 echo "$ac_t""yes" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + { echo "configure: error: installation or configuration problem: host compiler $HOST_CXX cannot create executables." 1>&2; exit 1; } +fi +rm -f conftest* + + CC=$_SAVE_CC + CFLAGS=$_SAVE_CFLAGS + LDFLAGS=$_SAVE_LDFLAGS + + case "$build:$target" in + powerpc-apple-darwin8*:i?86-apple-darwin*) + _SAVE_CFLAGS=$CFLAGS + _SAVE_CXXFLAGS=$CXXLAGS + CFLAGS="-isysroot /Developer/SDKs/MacOSX10.5.sdk $CFLAGS" + CXXFLAGS="-isysroot /Developer/SDKs/MacOSX10.5.sdk $CXXFLAGS" + ;; + esac + + case "$target" in + *symbian*) + # Check whether --with-symbian-sdk or --without-symbian-sdk was given. +if test "${with_symbian_sdk+set}" = set; then + withval="$with_symbian_sdk" + SYMBIAN_SDK_DIR=$withval +fi + + + OS_EXE_CFLAGS="$OS_EXE_CFLAGS -D__EXE__" + CFLAGS="-MD -nostdinc" + SYMBIAN_SYS_INCLUDE="-I$SYMBIAN_SDK_DIR/Epoc32/include -I$SYMBIAN_SDK_DIR/Epoc32/include/variant -I$SYMBIAN_SDK_DIR/Epoc32/include/stdapis" + + case "$target" in + *-symbianelf) + OS_TARGET=GCCE + CC=arm-none-symbianelf-gcc.exe + CXX=arm-none-symbianelf-g++.exe + LD=arm-none-symbianelf-ld.exe + AR=arm-none-symbianelf-ar.exe + CPP=arm-none-symbianelf-cpp.exe + CFLAGS="$CFLAGS -c -Wall -Wno-unknown-pragmas -fexceptions -march=armv5t -mapcs -pipe -msoft-float" + CXXFLAGS="$CFLAGS -Wno-ctor-dtor-privacy" + GCCE_INCLUDE="-include $SYMBIAN_SDK_DIR/EPOC32/INCLUDE/GCCE/GCCE.h -D__PRODUCT_INCLUDE__=$SYMBIAN_SDK_DIR/Epoc32/include/variant/Symbian_OS_v9.2.hrh" + CFLAGS="$CFLAGS ${GCCE_INCLUDE} -x c" + CXXFLAGS="$CXXFLAGS ${GCCE_INCLUDE} -x c++" + CPPFLAGS="$CPPFLAGS ${SYMBIAN_SYS_INCLUDE}" + ;; + *-symbianwinscw) + OS_TARGET=WINSCW + ;; + esac + ;; + esac + + for ac_prog in $CC "${target_alias}-gcc" "${target}-gcc" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1460: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CC" && break +done +test -n "$CC" || CC=":" + + unset ac_cv_prog_CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1494: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1524: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1575: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1607: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 1618 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:1623: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1649: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:1654: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:1682: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + + for ac_prog in $CXX "${target_alias}-g++" "${target}-g++" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1718: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CXX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CXX="$ac_cv_prog_CXX" +if test -n "$CXX"; then + echo "$ac_t""$CXX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CXX" && break +done +test -n "$CXX" || CXX=":" + + unset ac_cv_prog_CXX + for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1754: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CXX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CXX="$ac_cv_prog_CXX" +if test -n "$CXX"; then + echo "$ac_t""$CXX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CXX" && break +done +test -n "$CXX" || CXX="gcc" + + +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1786: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + +cat > conftest.$ac_ext << EOF + +#line 1797 "configure" +#include "confdefs.h" + +int main(){return(0);} +EOF +if { (eval echo configure:1802: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cxx_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cxx_cross=no + else + ac_cv_prog_cxx_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cxx_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6 +if test $ac_cv_prog_cxx_works = no; then + { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1828: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6 +cross_compiling=$ac_cv_prog_cxx_cross + +echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6 +echo "configure:1833: checking whether we are using GNU C++" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.C <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gxx=yes +else + ac_cv_prog_gxx=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gxx" 1>&6 + +if test $ac_cv_prog_gxx = yes; then + GXX=yes +else + GXX= +fi + +ac_test_CXXFLAGS="${CXXFLAGS+set}" +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS= +echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 +echo "configure:1861: checking whether ${CXX-g++} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.cc +if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then + ac_cv_prog_cxx_g=yes +else + ac_cv_prog_cxx_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi + + + case "$build:$target" in + powerpc-apple-darwin8*:i?86-apple-darwin*) + CFLAGS=$_SAVE_CFLAGS + CXXFLAGS=$_SAVE_CXXFLAGS + ;; + esac + + for ac_prog in $RANLIB "${target_alias}-ranlib" "${target}-ranlib" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1905: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$RANLIB" && break +done +test -n "$RANLIB" || RANLIB=":" + + for ac_prog in $AR "${target_alias}-ar" "${target}-ar" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1940: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AR="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AR" && break +done +test -n "$AR" || AR=":" + + for ac_prog in $AS "${target_alias}-as" "${target}-as" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1975: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_AS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$AS" in + /*) + ac_cv_path_AS="$AS" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_AS="$AS" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_AS="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +AS="$ac_cv_path_AS" +if test -n "$AS"; then + echo "$ac_t""$AS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AS" && break +done +test -n "$AS" || AS=":" + + if test "$msyshost"; then + case "$AS" in + /*) + tmp_DIRNAME=`dirname "$AS"` + tmp_BASENAME=`basename "$AS"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + AS="$tmp_PWD/$tmp_BASENAME" + if test -e "$AS.exe"; then + AS="$AS.exe" + fi + esac + fi + + for ac_prog in $LD "${target_alias}-ld" "${target}-ld" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2029: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LD"; then + ac_cv_prog_LD="$LD" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LD="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +LD="$ac_cv_prog_LD" +if test -n "$LD"; then + echo "$ac_t""$LD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$LD" && break +done +test -n "$LD" || LD=":" + + for ac_prog in $STRIP "${target_alias}-strip" "${target}-strip" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2064: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_STRIP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_STRIP="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +STRIP="$ac_cv_prog_STRIP" +if test -n "$STRIP"; then + echo "$ac_t""$STRIP" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$STRIP" && break +done +test -n "$STRIP" || STRIP=":" + + for ac_prog in $WINDRES "${target_alias}-windres" "${target}-windres" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2099: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_WINDRES'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$WINDRES"; then + ac_cv_prog_WINDRES="$WINDRES" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_WINDRES="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +WINDRES="$ac_cv_prog_WINDRES" +if test -n "$WINDRES"; then + echo "$ac_t""$WINDRES" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$WINDRES" && break +done +test -n "$WINDRES" || WINDRES=":" + + cat >> confdefs.h <<\EOF +#define CROSS_COMPILE 1 +EOF + + + cross_compiling=yes +else + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2139: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2169: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2220: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:2252: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 2263 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:2268: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:2294: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:2299: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:2327: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + + for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2363: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CXX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CXX="$ac_cv_prog_CXX" +if test -n "$CXX"; then + echo "$ac_t""$CXX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CXX" && break +done +test -n "$CXX" || CXX="gcc" + + +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:2395: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + +cat > conftest.$ac_ext << EOF + +#line 2406 "configure" +#include "confdefs.h" + +int main(){return(0);} +EOF +if { (eval echo configure:2411: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cxx_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cxx_cross=no + else + ac_cv_prog_cxx_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cxx_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6 +if test $ac_cv_prog_cxx_works = no; then + { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:2437: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6 +cross_compiling=$ac_cv_prog_cxx_cross + +echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6 +echo "configure:2442: checking whether we are using GNU C++" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.C <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gxx=yes +else + ac_cv_prog_gxx=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gxx" 1>&6 + +if test $ac_cv_prog_gxx = yes; then + GXX=yes +else + GXX= +fi + +ac_test_CXXFLAGS="${CXXFLAGS+set}" +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS= +echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 +echo "configure:2470: checking whether ${CXX-g++} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.cc +if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then + ac_cv_prog_cxx_g=yes +else + ac_cv_prog_cxx_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi + + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2504: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + for ac_prog in $AS as +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2536: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_AS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$AS" in + /*) + ac_cv_path_AS="$AS" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_AS="$AS" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_AS="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +AS="$ac_cv_path_AS" +if test -n "$AS"; then + echo "$ac_t""$AS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AS" && break +done +test -n "$AS" || AS="$CC" + + if test "$msyshost"; then + case "$AS" in + /*) + tmp_DIRNAME=`dirname "$AS"` + tmp_BASENAME=`basename "$AS"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + AS="$tmp_PWD/$tmp_BASENAME" + if test -e "$AS.exe"; then + AS="$AS.exe" + fi + esac + fi + + for ac_prog in ar +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2590: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AR="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AR" && break +done +test -n "$AR" || AR=":" + + for ac_prog in ld +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2625: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LD"; then + ac_cv_prog_LD="$LD" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LD="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +LD="$ac_cv_prog_LD" +if test -n "$LD"; then + echo "$ac_t""$LD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$LD" && break +done +test -n "$LD" || LD=":" + + for ac_prog in strip +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2660: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_STRIP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_STRIP="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +STRIP="$ac_cv_prog_STRIP" +if test -n "$STRIP"; then + echo "$ac_t""$STRIP" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$STRIP" && break +done +test -n "$STRIP" || STRIP=":" + + for ac_prog in windres +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2695: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_WINDRES'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$WINDRES"; then + ac_cv_prog_WINDRES="$WINDRES" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_WINDRES="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +WINDRES="$ac_cv_prog_WINDRES" +if test -n "$WINDRES"; then + echo "$ac_t""$WINDRES" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$WINDRES" && break +done +test -n "$WINDRES" || WINDRES=":" + + if test -z "$HOST_CC"; then + HOST_CC='$(CC)' + fi + if test -z "$HOST_CFLAGS"; then + HOST_CFLAGS='$(CFLAGS)' + fi + if test -z "$HOST_CXX"; then + HOST_CXX='$(CXX)' + fi + if test -z "$HOST_CXXFLAGS"; then + HOST_CXXFLAGS='$(CXXFLAGS)' + fi + if test -z "$HOST_LDFLAGS"; then + HOST_LDFLAGS='$(LDFLAGS)' + fi + if test -z "$HOST_RANLIB"; then + HOST_RANLIB='$(RANLIB)' + fi + if test -z "$HOST_AR"; then + HOST_AR='$(AR)' + fi + if test -z "$HOST_AR_FLAGS"; then + HOST_AR_FLAGS='$(AR_FLAGS)' + fi +fi + +GNU_AS= +GNU_LD= +GNU_CC= +GNU_CXX= +CC_VERSION='N/A' +CXX_VERSION='N/A' +if test "$GCC" = "yes"; then + GNU_CC=1 + CC_VERSION=`$CC -v 2>&1 | grep 'gcc version'` +fi +if test "$GXX" = "yes"; then + GNU_CXX=1 + CXX_VERSION=`$CXX -v 2>&1 | grep 'gcc version'` +fi +if test "`echo | $AS -v 2>&1 | grep -c GNU`" != "0"; then + GNU_AS=1 +fi +if test "`echo | $LD -v 2>&1 | grep -c GNU`" != "0"; then + GNU_LD=1 +fi +if test "$GNU_CC"; then + if `$CC -print-prog-name=ld` -v 2>&1 | grep -c GNU >/dev/null; then + GCC_USE_GNU_LD=1 + fi +fi + +INTEL_CC= +INTEL_CXX= +if test "$GCC" = yes; then + if test "`$CC -help 2>&1 | grep -c 'Intel(R) C++ Compiler'`" != "0"; then + INTEL_CC=1 + fi +fi + +if test "$GXX" = yes; then + if test "`$CXX -help 2>&1 | grep -c 'Intel(R) C++ Compiler'`" != "0"; then + INTEL_CXX=1 + fi +fi + +case "$target" in +*-wince|*-winmo) + WINVER=500 + WINSDK_TARGETVER=502 + ;; +*) + WINVER=502 + WINSDK_TARGETVER=601 + ;; +esac + +# Check whether --with-windows-version or --without-windows-version was given. +if test "${with_windows_version+set}" = set; then + withval="$with_windows_version" + WINSDK_TARGETVER=$withval +fi + + +case "$WINSDK_TARGETVER" in +502|600|601) + MOZ_WINSDK_TARGETVER=0${WINSDK_TARGETVER}0000 + ;; + +*) + { echo "configure: error: Invalid value for --with-windows-version ($WINSDK_TARGETVER), must be 502, 600 or 601" 1>&2; exit 1; }; + ;; + +esac + +case "$target" in +*-cygwin*|*-mingw*|*-msvc*|*-mks*|*-wince|*-winmo) + if test "$GCC" != "yes"; then + # Check to see if we are really running in a msvc environemnt + _WIN32_MSVC=1 + + # Make sure compilers are valid + CFLAGS="$CFLAGS -TC -nologo" + CXXFLAGS="$CXXFLAGS -TP -nologo" + # MSVC warning C4345 warns of newly conformant behavior as of VS2003. + # _CRT_SECURE_NO_WARNINGS disables warnings about using MSVC-specific + # secure CRT functions. + CXXFLAGS="$CXXFLAGS -wd4345 -D_CRT_SECURE_NO_WARNINGS" + + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + cat > conftest.$ac_ext < +int main() { + printf("Hello World\n"); +; return 0; } +EOF +if { (eval echo configure:2849: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + { echo "configure: error: \$(CC) test failed. You must have MS VC++ in your path to build." 1>&2; exit 1; } +fi +rm -f conftest* + + ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + cat > conftest.$ac_ext < +int main() { + unsigned *test = new unsigned(42); +; return 0; } +EOF +if { (eval echo configure:2874: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + { echo "configure: error: \$(CXX) test failed. You must have MS VC++ in your path to build." 1>&2; exit 1; } +fi +rm -f conftest* + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + + + _MSVC_VER_FILTER='s|.* ([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?).*|\1|p' + + + # Determine compiler version + CC_VERSION=`"${CC}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"` + _CC_MAJOR_VERSION=`echo ${CC_VERSION} | $AWK -F\. '{ print $1 }'` + _CC_MINOR_VERSION=`echo ${CC_VERSION} | $AWK -F\. '{ print $2 }'` + _CC_RELEASE=`echo ${CC_VERSION} | $AWK -F\. '{ print $3 }'` + _CC_BUILD=`echo ${CC_VERSION} | $AWK -F\. '{ print $4 }'` + _MSC_VER=${_CC_MAJOR_VERSION}${_CC_MINOR_VERSION} + + CXX_VERSION=`"${CXX}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"` + _CXX_MAJOR_VERSION=`echo ${CXX_VERSION} | $AWK -F\. '{ print $1 }'` + + if test "$_CC_MAJOR_VERSION" != "$_CXX_MAJOR_VERSION"; then + { echo "configure: error: The major versions of \$CC and \$CXX do not match." 1>&2; exit 1; } + fi + + if test "$_CC_MAJOR_VERSION" = "14"; then + if test "$_CC_RELEASE" -lt 50727 -o \ + \( "$_CC_RELEASE" -eq 50727 -a "$_CC_BUILD" -lt 762 \); then + { echo "configure: error: This version ($CC_VERSION) of the MSVC compiler is unsupported. You probably need to install Service Pack 1 of Visual Studio 2005. See https://developer.mozilla.org/en/Windows_Build_Prerequisites." 1>&2; exit 1; } + fi + + _CC_SUITE=8 + CXXFLAGS="$CXXFLAGS -Zc:wchar_t-" + cat >> confdefs.h <<\EOF +#define _CRT_SECURE_NO_DEPRECATE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _CRT_NONSTDC_NO_DEPRECATE 1 +EOF + + elif test "$_CC_MAJOR_VERSION" = "15"; then + _CC_SUITE=9 + CXXFLAGS="$CXXFLAGS -Zc:wchar_t-" + cat >> confdefs.h <<\EOF +#define _CRT_SECURE_NO_WARNINGS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _CRT_NONSTDC_NO_WARNINGS 1 +EOF + + elif test "$_CC_MAJOR_VERSION" = "16"; then + _CC_SUITE=10 + CXXFLAGS="$CXXFLAGS -Zc:wchar_t-" + cat >> confdefs.h <<\EOF +#define _CRT_SECURE_NO_WARNINGS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _CRT_NONSTDC_NO_WARNINGS 1 +EOF + + else + { echo "configure: error: This version ($CC_VERSION) of the MSVC compiler is unsupported. See https://developer.mozilla.org/en/Windows_Build_Prerequisites." 1>&2; exit 1; } + fi + + _MOZ_RTTI_FLAGS_ON='-GR' + _MOZ_RTTI_FLAGS_OFF='-GR-' + _MOZ_EXCEPTIONS_FLAGS_ON='-EHsc' + _MOZ_EXCEPTIONS_FLAGS_OFF='' + + if test -n "$WIN32_REDIST_DIR"; then + WIN32_REDIST_DIR=`cd "$WIN32_REDIST_DIR" && pwd` + fi + + MSMT_TOOL=`mt 2>&1|grep 'Microsoft (R) Manifest Tool'` + if test -z "$MSMT_TOOL"; then + { echo "configure: error: Microsoft (R) Manifest Tool must be in your \$PATH." 1>&2; exit 1; } + fi + + + _MSMT_VER_FILTER='s|.* \([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*|\1|p' + + MSMANIFEST_TOOL_VERSION=`echo ${MSMT_TOOL}|sed -ne "$_MSMT_VER_FILTER"` + if test -z "$MSMANIFEST_TOOL_VERSION"; then + echo "configure: warning: Unknown version of the Microsoft (R) Manifest Tool." 1>&2 + fi + + MSMANIFEST_TOOL=1 + unset MSMT_TOOL + + # Check linker version + _LD_FULL_VERSION=`"${LD}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"` + _LD_MAJOR_VERSION=`echo ${_LD_FULL_VERSION} | $AWK -F\. '{ print $1 }'` + if test "$_LD_MAJOR_VERSION" != "$_CC_SUITE"; then + { echo "configure: error: The linker major version, $_LD_FULL_VERSION, does not match the compiler suite version, $_CC_SUITE." 1>&2; exit 1; } + fi + + INCREMENTAL_LINKER=1 + + # Identify which version of the SDK we're building with + # Windows Server 2008 and newer SDKs have WinSDKVer.h, get the version + # from there + echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:2990: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3011: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3028: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3045: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +for ac_hdr in winsdkver.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:3073: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3083: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + if test "$ac_cv_header_winsdkver_h" = "yes"; then + # Get the highest _WIN32_WINNT and NTDDI versions supported + # Take the higher of the two + # This is done because the Windows 7 beta SDK reports its + # NTDDI_MAXVER to be 0x06000100 instead of 0x06010000, as it should + echo $ac_n "checking for highest Windows version supported by this SDK""... $ac_c" 1>&6 +echo "configure:3115: checking for highest Windows version supported by this SDK" >&5 +if eval "test \"`echo '$''{'ac_cv_winsdk_maxver'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.h < +#include + +#if (NTDDI_VERSION_FROM_WIN32_WINNT(_WIN32_WINNT_MAXVER) > NTDDI_MAXVER) +#define WINSDK_MAXVER NTDDI_VERSION_FROM_WIN32_WINNT(_WIN32_WINNT_MAXVER) +#else +#define WINSDK_MAXVER NTDDI_MAXVER +#endif + +WINSDK_MAXVER +EOF + ac_cv_winsdk_maxver=`$CPP conftest.h 2>/dev/null | tail -n1` + rm -f conftest.h + +fi + +echo "$ac_t""$ac_cv_winsdk_maxver" 1>&6 + MOZ_WINSDK_MAXVER=${ac_cv_winsdk_maxver} + else + # The Vista SDK is the only one to have sdkddkver.h but not + # WinSDKVer.h + for ac_hdr in sdkddkver.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:3145: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3155: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + if test "$ac_cv_header_sdkddkver_h" = "yes"; then + MOZ_WINSDK_MAXVER=0x06000000 + else + # Assume the Server 2003 Platform SDK + MOZ_WINSDK_MAXVER=0x05020000 + fi + fi + + unset _MSVC_VER_FILTER + + echo $ac_n "checking for std::_Throw""... $ac_c" 1>&6 +echo "configure:3192: checking for std::_Throw" >&5 +if eval "test \"`echo '$''{'ac_cv_have_std__Throw'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + + ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + _SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="${CXXFLAGS} -D_HAS_EXCEPTIONS=0" + cat > conftest.$ac_ext < +int main() { +std::_Throw(std::exception()); return 0; +; return 0; } +EOF +if { (eval echo configure:3215: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_have_std__Throw="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_have_std__Throw="no" +fi +rm -f conftest* + CXXFLAGS="$_SAVE_CXXFLAGS" + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + +fi + +echo "$ac_t""$ac_cv_have_std__Throw" 1>&6 + + if test "$ac_cv_have_std__Throw" == "yes"; then + echo $ac_n "checking for |class __declspec(dllimport) exception| bug""... $ac_c" 1>&6 +echo "configure:3240: checking for |class __declspec(dllimport) exception| bug" >&5 +if eval "test \"`echo '$''{'ac_cv_have_dllimport_exception_bug'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + + ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + _SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="${CXXFLAGS} -D_HAS_EXCEPTIONS=0" + cat > conftest.$ac_ext < +int main() { +std::vector v; return v.at(1); +; return 0; } +EOF +if { (eval echo configure:3263: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_have_dllimport_exception_bug="no" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_have_dllimport_exception_bug="yes" +fi +rm -f conftest* + CXXFLAGS="$_SAVE_CXXFLAGS" + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + +fi + +echo "$ac_t""$ac_cv_have_dllimport_exception_bug" 1>&6 + if test "$ac_cv_have_dllimport_exception_bug" = "no"; then + WRAP_STL_INCLUDES=1 + MOZ_MSVC_STL_WRAP__Throw=1 + cat >> confdefs.h <<\EOF +#define MOZ_MSVC_STL_WRAP__Throw 1 +EOF + + fi + else + echo $ac_n "checking for overridable _RAISE""... $ac_c" 1>&6 +echo "configure:3295: checking for overridable _RAISE" >&5 +if eval "test \"`echo '$''{'ac_cv_have__RAISE'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + + ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + _SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="${CXXFLAGS} -D_HAS_EXCEPTIONS=0" + cat > conftest.$ac_ext < + #undef _RAISE + #define _RAISE(x) externallyDefinedFunction((x).what()) + #include + +int main() { +std::vector v; return v.at(1); +; return 0; } +EOF +if { (eval echo configure:3322: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_have__RAISE="no" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_have__RAISE="yes" +fi +rm -f conftest* + CXXFLAGS="$_SAVE_CXXFLAGS" + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + +fi + +echo "$ac_t""$ac_cv_have__RAISE" 1>&6 + if test "$ac_cv_have__RAISE" = "yes"; then + WRAP_STL_INCLUDES=1 + MOZ_MSVC_STL_WRAP__RAISE=1 + cat >> confdefs.h <<\EOF +#define MOZ_MSVC_STL_WRAP__RAISE 1 +EOF + + else + { echo "configure: error: Gecko exception wrapping doesn't understand your your MSVC/SDK. Please file a bug describing this error and your build configuration." 1>&2; exit 1; } + fi + fi + + if test "$WRAP_STL_INCLUDES" = "1"; then + STL_FLAGS='-D_HAS_EXCEPTIONS=0 -I$(DIST)/stl_wrappers' + fi + else + # Check w32api version + _W32API_MAJOR_VERSION=`echo $W32API_VERSION | $AWK -F\. '{ print $1 }'` + _W32API_MINOR_VERSION=`echo $W32API_VERSION | $AWK -F\. '{ print $2 }'` + echo $ac_n "checking for w32api version >= $W32API_VERSION""... $ac_c" 1>&6 +echo "configure:3364: checking for w32api version >= $W32API_VERSION" >&5 + cat > conftest.$ac_ext < +int main() { +#if (__W32API_MAJOR_VERSION < $_W32API_MAJOR_VERSION) || \ + (__W32API_MAJOR_VERSION == $_W32API_MAJOR_VERSION && \ + __W32API_MINOR_VERSION < $_W32API_MINOR_VERSION) + #error "test failed." + #endif + +; return 0; } +EOF +if { (eval echo configure:3378: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + res=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + res=no +fi +rm -f conftest* + echo "$ac_t""$res" 1>&6 + if test "$res" != "yes"; then + { echo "configure: error: w32api version $W32API_VERSION or higher required." 1>&2; exit 1; } + fi + # Check windres version + echo $ac_n "checking for windres version >= $WINDRES_VERSION""... $ac_c" 1>&6 +echo "configure:3394: checking for windres version >= $WINDRES_VERSION" >&5 + _WINDRES_VERSION=`${WINDRES} --version 2>&1 | grep -i windres 2>/dev/null | $AWK '{ print $3 }'` + echo "$ac_t""$_WINDRES_VERSION" 1>&6 + _WINDRES_MAJOR_VERSION=`echo $_WINDRES_VERSION | $AWK -F\. '{ print $1 }'` + _WINDRES_MINOR_VERSION=`echo $_WINDRES_VERSION | $AWK -F\. '{ print $2 }'` + _WINDRES_RELEASE_VERSION=`echo $_WINDRES_VERSION | $AWK -F\. '{ print $3 }'` + WINDRES_MAJOR_VERSION=`echo $WINDRES_VERSION | $AWK -F\. '{ print $1 }'` + WINDRES_MINOR_VERSION=`echo $WINDRES_VERSION | $AWK -F\. '{ print $2 }'` + WINDRES_RELEASE_VERSION=`echo $WINDRES_VERSION | $AWK -F\. '{ print $3 }'` + if test "$_WINDRES_MAJOR_VERSION" -lt "$WINDRES_MAJOR_VERSION" -o \ + "$_WINDRES_MAJOR_VERSION" -eq "$WINDRES_MAJOR_VERSION" -a \ + "$_WINDRES_MINOR_VERSION" -lt "$WINDRES_MINOR_VERSION" -o \ + "$_WINDRES_MAJOR_VERSION" -eq "$WINDRES_MAJOR_VERSION" -a \ + "$_WINDRES_MINOR_VERSION" -eq "$WINDRES_MINOR_VERSION" -a \ + "$_WINDRES_RELEASE_VERSION" -lt "$WINDRES_RELEASE_VERSION" + then + { echo "configure: error: windres version $WINDRES_VERSION or higher is required to build." 1>&2; exit 1; } + fi + + # Server 2003 is the highest version supported + MOZ_WINSDK_MAXVER=0x05020000 + fi # !GNU_CC + + cat >> confdefs.h <> confdefs.h <> confdefs.h <&6 +echo "configure:3434: checking for Windows SDK being recent enough" >&5 + if $PERL -e "exit(0x$MOZ_WINSDK_TARGETVER > $MOZ_WINSDK_MAXVER)"; then + echo "$ac_t"""yes"" 1>&6 + else + echo "$ac_t"""no"" 1>&6 + { echo "configure: error: You are targeting Windows version 0x$MOZ_WINSDK_TARGETVER, but your SDK only supports up to version $MOZ_WINSDK_MAXVER. Install and use an updated SDK, or target a lower version using --with-windows-version. Alternatively, try running the Windows SDK Configuration Tool and selecting a newer SDK. See https://developer.mozilla.org/En/Windows_SDK_versions for more details on fixing this." 1>&2; exit 1; } + fi + + cat >> confdefs.h <> confdefs.h <> confdefs.h <> confdefs.h <&6 +echo "configure:3465: checking whether $CC and cc understand -c and -o together" >&5 +else + echo $ac_n "checking whether cc understands -c and -o together""... $ac_c" 1>&6 +echo "configure:3468: checking whether cc understands -c and -o together" >&5 +fi +set dummy $CC; ac_cc="`echo $2 | + sed -e 's/[^a-zA-Z0-9_]/_/g' -e 's/^[0-9]/_/'`" +if eval "test \"`echo '$''{'ac_cv_prog_cc_${ac_cc}_c_o'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'foo(){}' > conftest.c +# Make sure it works both with $CC and with simple cc. +# We do the test twice because some compilers refuse to overwrite an +# existing .o file with -o, though they will create one. +ac_try='${CC-cc} -c conftest.c -o conftest.o 1>&5' +if { (eval echo configure:3480: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } && + test -f conftest.o && { (eval echo configure:3481: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; +then + eval ac_cv_prog_cc_${ac_cc}_c_o=yes + if test "x$CC" != xcc; then + # Test first that cc exists at all. + if { ac_try='cc -c conftest.c 1>&5'; { (eval echo configure:3486: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then + ac_try='cc -c conftest.c -o conftest.o 1>&5' + if { (eval echo configure:3488: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } && + test -f conftest.o && { (eval echo configure:3489: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; + then + # cc works too. + : + else + # cc exists but doesn't like -o. + eval ac_cv_prog_cc_${ac_cc}_c_o=no + fi + fi + fi +else + eval ac_cv_prog_cc_${ac_cc}_c_o=no +fi +rm -f conftest* + +fi +if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" = yes"; then + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 + cat >> confdefs.h <<\EOF +#define NO_MINUS_C_MINUS_O 1 +EOF + +fi + + if grep "NO_MINUS_C_MINUS_O 1" ./confdefs.h >/dev/null; then + USING_HCC=1 + _OLDCC=$CC + _OLDCXX=$CXX + CC="${srcdir}/build/hcc '$CC'" + CXX="${srcdir}/build/hcpp '$CXX'" + fi +fi + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:3525: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3546: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3563: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3580: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +echo $ac_n "checking how to run the C++ preprocessor""... $ac_c" 1>&6 +echo "configure:3605: checking how to run the C++ preprocessor" >&5 +if test -z "$CXXCPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CXXCPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + CXXCPP="${CXX-g++} -E" + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3623: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CXXCPP=/lib/cpp +fi +rm -f conftest* + ac_cv_prog_CXXCPP="$CXXCPP" +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross +fi +fi +CXXCPP="$ac_cv_prog_CXXCPP" +echo "$ac_t""$CXXCPP" 1>&6 + + +if test -n "$_WIN32_MSVC"; then + SKIP_PATH_CHECKS=1 + SKIP_COMPILER_CHECKS=1 + SKIP_LIBRARY_CHECKS=1 + + # Since we're skipping compiler and library checks, hard-code + # some facts here. + + # Common to all MSVC environments: + # Windows lacks , but has __int8, and so on. + cat >> confdefs.h <<\EOF +#define JS_HAVE___INTN 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_LOCALECONV 1 +EOF + + + case "$target" in + *-wince|*-winmo) + cat >> confdefs.h <<\EOF +#define HAVE_SYSTEMTIMETOFILETIME 1 +EOF + + cat >> confdefs.h <<\EOF +#define JS_CRTDEFS_H_HAS_INTPTR_T 1 +EOF + + ;; + *) + cat >> confdefs.h <<\EOF +#define HAVE_SYSTEMTIMETOFILETIME 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_GETSYSTEMTIMEASFILETIME 1 +EOF + + # Windows defines intptr_t and uintptr_t. + # VS2005: http://msdn.microsoft.com/en-us/library/323b6b3k(VS.80).aspx + # VS2008: http://msdn.microsoft.com/en-us/library/323b6b3k.aspx + cat >> confdefs.h <<\EOF +#define JS_STDDEF_H_HAS_INTPTR_T 1 +EOF + + ;; + esac +fi + +fi # COMPILE_ENVIRONMENT + +if test "$cross_compiling" = "yes"; then + CROSS_COMPILE=1 +else + CROSS_COMPILE= +fi + +# Check to see if we are running in a broken QEMU scratchbox. +# We know that anything below 1.0.16 is broken. +for ac_prog in sb-conf ve +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3713: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_SBCONF'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$SBCONF"; then + ac_cv_prog_SBCONF="$SBCONF" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_SBCONF="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +SBCONF="$ac_cv_prog_SBCONF" +if test -n "$SBCONF"; then + echo "$ac_t""$SBCONF" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$SBCONF" && break +done +test -n "$SBCONF" || SBCONF="""" + +if test -n "$SBCONF"; then + _sb_version=`$SBCONF ve` + _sb_version_major=`echo $_sb_version | cut -f1 -d.` + _sb_version_minor=`echo $_sb_version | cut -f2 -d.` + _sb_version_point=`echo $_sb_version | cut -f3 -d.` + if test $_sb_version_major -eq 1 -a $_sb_version_minor -eq 0 -a $_sb_version_point -le 16; then + QEMU_CANT_RUN_JS_SHELL=1 + fi +fi + + + + + + + + + + + + + + + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:3780: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 +echo "configure:3833: checking whether ln -s works" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + rm -f conftestdata +if ln -s X conftestdata 2>/dev/null +then + rm -f conftestdata + ac_cv_prog_LN_S="ln -s" +else + ac_cv_prog_LN_S=ln +fi +fi +LN_S="$ac_cv_prog_LN_S" +if test "$ac_cv_prog_LN_S" = "ln -s"; then + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$TINDERBOX_SKIP_PERL_VERSION_CHECK"; then +echo $ac_n "checking for minimum required perl version >= $PERL_VERSION""... $ac_c" 1>&6 +echo "configure:3856: checking for minimum required perl version >= $PERL_VERSION" >&5 +_perl_version=`PERL_VERSION=$PERL_VERSION $PERL -e 'print "$]"; if ($] >= $ENV{PERL_VERSION}) { exit(0); } else { exit(1); }' 2>&5` +_perl_res=$? +echo "$ac_t""$_perl_version" 1>&6 + +if test "$_perl_res" != 0; then + { echo "configure: error: Perl $PERL_VERSION or higher is required." 1>&2; exit 1; } +fi +fi + +echo $ac_n "checking for full perl installation""... $ac_c" 1>&6 +echo "configure:3867: checking for full perl installation" >&5 +_perl_archlib=`$PERL -e 'use Config; if ( -d $Config{archlib} ) { exit(0); } else { exit(1); }' 2>&5` +_perl_res=$? +if test "$_perl_res" != 0; then + echo "$ac_t""no" 1>&6 + { echo "configure: error: Cannot find Config.pm or \$Config{archlib}. A full perl installation is required." 1>&2; exit 1; } +else + echo "$ac_t""yes" 1>&6 +fi + + for ac_prog in $PYTHON python2.7 python2.6 python2.5 python +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3882: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_PYTHON'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$PYTHON" in + /*) + ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_PYTHON="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +PYTHON="$ac_cv_path_PYTHON" +if test -n "$PYTHON"; then + echo "$ac_t""$PYTHON" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$PYTHON" && break +done + + if test "$msyshost"; then + case "$PYTHON" in + /*) + tmp_DIRNAME=`dirname "$PYTHON"` + tmp_BASENAME=`basename "$PYTHON"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + PYTHON="$tmp_PWD/$tmp_BASENAME" + if test -e "$PYTHON.exe"; then + PYTHON="$PYTHON.exe" + fi + esac + fi + +if test -z "$PYTHON"; then + { echo "configure: error: python was not found in \$PATH" 1>&2; exit 1; } +fi + +if test -z "$COMPILE_ENVIRONMENT"; then + NSINSTALL_BIN='$(PYTHON) $(topsrcdir)/config/nsinstall.py' +fi + + + # Extract the first word of "doxygen", so it can be a program name with args. +set dummy doxygen; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3942: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_DOXYGEN'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$DOXYGEN" in + /*) + ac_cv_path_DOXYGEN="$DOXYGEN" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_DOXYGEN="$DOXYGEN" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_DOXYGEN="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_DOXYGEN" && ac_cv_path_DOXYGEN=":" + ;; +esac +fi +DOXYGEN="$ac_cv_path_DOXYGEN" +if test -n "$DOXYGEN"; then + echo "$ac_t""$DOXYGEN" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test "$msyshost"; then + case "$DOXYGEN" in + /*) + tmp_DIRNAME=`dirname "$DOXYGEN"` + tmp_BASENAME=`basename "$DOXYGEN"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + DOXYGEN="$tmp_PWD/$tmp_BASENAME" + if test -e "$DOXYGEN.exe"; then + DOXYGEN="$DOXYGEN.exe" + fi + esac + fi + + # Extract the first word of "autoconf", so it can be a program name with args. +set dummy autoconf; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3991: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_AUTOCONF'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$AUTOCONF" in + /*) + ac_cv_path_AUTOCONF="$AUTOCONF" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_AUTOCONF="$AUTOCONF" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_AUTOCONF="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_AUTOCONF" && ac_cv_path_AUTOCONF=":" + ;; +esac +fi +AUTOCONF="$ac_cv_path_AUTOCONF" +if test -n "$AUTOCONF"; then + echo "$ac_t""$AUTOCONF" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test "$msyshost"; then + case "$AUTOCONF" in + /*) + tmp_DIRNAME=`dirname "$AUTOCONF"` + tmp_BASENAME=`basename "$AUTOCONF"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + AUTOCONF="$tmp_PWD/$tmp_BASENAME" + if test -e "$AUTOCONF.exe"; then + AUTOCONF="$AUTOCONF.exe" + fi + esac + fi + + # Extract the first word of "unzip", so it can be a program name with args. +set dummy unzip; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:4040: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_UNZIP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$UNZIP" in + /*) + ac_cv_path_UNZIP="$UNZIP" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_UNZIP="$UNZIP" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_UNZIP="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_UNZIP" && ac_cv_path_UNZIP=":" + ;; +esac +fi +UNZIP="$ac_cv_path_UNZIP" +if test -n "$UNZIP"; then + echo "$ac_t""$UNZIP" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test "$msyshost"; then + case "$UNZIP" in + /*) + tmp_DIRNAME=`dirname "$UNZIP"` + tmp_BASENAME=`basename "$UNZIP"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + UNZIP="$tmp_PWD/$tmp_BASENAME" + if test -e "$UNZIP.exe"; then + UNZIP="$UNZIP.exe" + fi + esac + fi + + for ac_prog in zip +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:4091: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_ZIP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$ZIP" in + /*) + ac_cv_path_ZIP="$ZIP" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_ZIP="$ZIP" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_ZIP="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +ZIP="$ac_cv_path_ZIP" +if test -n "$ZIP"; then + echo "$ac_t""$ZIP" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$ZIP" && break +done + + if test "$msyshost"; then + case "$ZIP" in + /*) + tmp_DIRNAME=`dirname "$ZIP"` + tmp_BASENAME=`basename "$ZIP"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + ZIP="$tmp_PWD/$tmp_BASENAME" + if test -e "$ZIP.exe"; then + ZIP="$ZIP.exe" + fi + esac + fi + +if test -z "$ZIP" -o "$ZIP" = ":"; then + { echo "configure: error: zip not found in \$PATH" 1>&2; exit 1; } +fi + # Extract the first word of "makedepend", so it can be a program name with args. +set dummy makedepend; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:4145: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_SYSTEM_MAKEDEPEND'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$SYSTEM_MAKEDEPEND" in + /*) + ac_cv_path_SYSTEM_MAKEDEPEND="$SYSTEM_MAKEDEPEND" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_SYSTEM_MAKEDEPEND="$SYSTEM_MAKEDEPEND" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_SYSTEM_MAKEDEPEND="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +SYSTEM_MAKEDEPEND="$ac_cv_path_SYSTEM_MAKEDEPEND" +if test -n "$SYSTEM_MAKEDEPEND"; then + echo "$ac_t""$SYSTEM_MAKEDEPEND" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test "$msyshost"; then + case "$SYSTEM_MAKEDEPEND" in + /*) + tmp_DIRNAME=`dirname "$SYSTEM_MAKEDEPEND"` + tmp_BASENAME=`basename "$SYSTEM_MAKEDEPEND"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + SYSTEM_MAKEDEPEND="$tmp_PWD/$tmp_BASENAME" + if test -e "$SYSTEM_MAKEDEPEND.exe"; then + SYSTEM_MAKEDEPEND="$SYSTEM_MAKEDEPEND.exe" + fi + esac + fi + + # Extract the first word of "xargs", so it can be a program name with args. +set dummy xargs; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:4193: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_XARGS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$XARGS" in + /*) + ac_cv_path_XARGS="$XARGS" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_XARGS="$XARGS" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_XARGS="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +XARGS="$ac_cv_path_XARGS" +if test -n "$XARGS"; then + echo "$ac_t""$XARGS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test "$msyshost"; then + case "$XARGS" in + /*) + tmp_DIRNAME=`dirname "$XARGS"` + tmp_BASENAME=`basename "$XARGS"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + XARGS="$tmp_PWD/$tmp_BASENAME" + if test -e "$XARGS.exe"; then + XARGS="$XARGS.exe" + fi + esac + fi + +if test -z "$XARGS" -o "$XARGS" = ":"; then + { echo "configure: error: xargs not found in \$PATH ." 1>&2; exit 1; } +fi + +if test "$COMPILE_ENVIRONMENT"; then + + +case "$target_os" in +darwin*) + + GCC_VERSION_FULL=`echo $CXX_VERSION | $PERL -pe 's/^.*gcc version ([^ ]*).*/$1/'` + GCC_VERSION=`echo $GCC_VERSION_FULL | $PERL -pe '(split(/\./))[0]>=4&&s/(^\d*\.\d*).*/$1/;'` + + if test "$GCC_VERSION_FULL" = "4.0.0" ; then + + GCC_BUILD=`echo $CXX_VERSION | $PERL -pe 's/^.*build ([^ )]*).*/$1/'` + + if test "$GCC_BUILD" = "4061" ; then + { echo "configure: error: You are attempting to use Apple gcc 4.0 build 4061. +This compiler was supplied with Xcode 2.0, and contains bugs that prevent it +from building Mozilla. Upgrade to Xcode 2.1 or later." 1>&2; exit 1; } + fi + fi + + for ac_prog in pbbuild xcodebuild pbxbuild +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:4267: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_PBBUILD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$PBBUILD" in + /*) + ac_cv_path_PBBUILD="$PBBUILD" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_PBBUILD="$PBBUILD" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_PBBUILD="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +PBBUILD="$ac_cv_path_PBBUILD" +if test -n "$PBBUILD"; then + echo "$ac_t""$PBBUILD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$PBBUILD" && break +done + + if test "$msyshost"; then + case "$PBBUILD" in + /*) + tmp_DIRNAME=`dirname "$PBBUILD"` + tmp_BASENAME=`basename "$PBBUILD"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + PBBUILD="$tmp_PWD/$tmp_BASENAME" + if test -e "$PBBUILD.exe"; then + PBBUILD="$PBBUILD.exe" + fi + esac + fi + + + case "$PBBUILD" in + *xcodebuild*) + + XCODEBUILD_VERSION=`$PBBUILD -version 2>/dev/null | xargs | sed -e 's/.*DevToolsCore-\([0-9]*\).*/\1/'` + + if test -n "$XCODEBUILD_VERSION" && test "$XCODEBUILD_VERSION" -ge 620 ; then + HAS_XCODE_2_1=1; + fi + ;; + esac + + # Extract the first word of "sdp", so it can be a program name with args. +set dummy sdp; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:4330: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_SDP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$SDP" in + /*) + ac_cv_path_SDP="$SDP" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_SDP="$SDP" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH:/usr/bin:/Developer/Tools" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_SDP="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_SDP" && ac_cv_path_SDP=":" + ;; +esac +fi +SDP="$ac_cv_path_SDP" +if test -n "$SDP"; then + echo "$ac_t""$SDP" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test "$msyshost"; then + case "$SDP" in + /*) + tmp_DIRNAME=`dirname "$SDP"` + tmp_BASENAME=`basename "$SDP"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + SDP="$tmp_PWD/$tmp_BASENAME" + if test -e "$SDP.exe"; then + SDP="$SDP.exe" + fi + esac + fi + + ;; +esac + + + + + + + + +# Check whether --enable-macos-target or --disable-macos-target was given. +if test "${enable_macos_target+set}" = set; then + enableval="$enable_macos_target" + _MACOSX_DEPLOYMENT_TARGET=$enableval +fi + + +case "$target" in +*-darwin*) + if test -n "$_MACOSX_DEPLOYMENT_TARGET" ; then + export MACOSX_DEPLOYMENT_TARGET=$_MACOSX_DEPLOYMENT_TARGET + cat >> confdefs.h <&2; exit 1; } + fi + + GCC_VERSION_MAJOR=`echo $GCC_VERSION_FULL | $PERL -pe 's/(^\d*).*/$1/;'` + if test "$GCC_VERSION_MAJOR" -lt "4" ; then + { echo "configure: error: You need to upgrade the compiler version to 4.x" 1>&2; exit 1; } + else + CFLAGS="$CFLAGS -isysroot ${MACOS_SDK_DIR}" + CXXFLAGS="$CXXFLAGS -isysroot ${MACOS_SDK_DIR}" + + CPP="$CPP -isysroot ${MACOS_SDK_DIR}" + CXXCPP="$CXXCPP -isysroot ${MACOS_SDK_DIR}" + + if test "$GCC_VERSION_FULL" = "4.0.0" ; then + LDFLAGS="$LDFLAGS -Wl,-syslibroot,${MACOS_SDK_DIR}" + fi + fi + + + echo $ac_n "checking for valid compiler/Mac OS X SDK combination""... $ac_c" 1>&6 +echo "configure:4456: checking for valid compiler/Mac OS X SDK combination" >&5 + ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + cat > conftest.$ac_ext < + int main() { return 0; } +int main() { +result=yes +; return 0; } +EOF +if { (eval echo configure:4473: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + result=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + echo "$ac_t""$result" 1>&6 + + if test "$result" = "no" ; then + { echo "configure: error: The selected compiler and Mac OS X SDK are incompatible." 1>&2; exit 1; } + fi +fi + +fi # COMPILE_ENVIRONMENT + +if test -n "$MAKE"; then + if test `echo $MAKE | grep -c make.py` != 1; then + NOT_PYMAKE=$MAKE + fi +fi + +case "$host_os" in +cygwin*|mingw*|mks*|msvc*) + for ac_prog in $GMAKE $NOT_PYMAKE make gmake +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:4510: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_GMAKE'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$GMAKE" in + /*) + ac_cv_path_GMAKE="$GMAKE" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_GMAKE="$GMAKE" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_GMAKE="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +GMAKE="$ac_cv_path_GMAKE" +if test -n "$GMAKE"; then + echo "$ac_t""$GMAKE" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$GMAKE" && break +done +test -n "$GMAKE" || GMAKE=":" + + if test "$msyshost"; then + case "$GMAKE" in + /*) + tmp_DIRNAME=`dirname "$GMAKE"` + tmp_BASENAME=`basename "$GMAKE"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + GMAKE="$tmp_PWD/$tmp_BASENAME" + if test -e "$GMAKE.exe"; then + GMAKE="$GMAKE.exe" + fi + esac + fi + + ;; +*) + for ac_prog in $GMAKE $NOT_PYMAKE gmake make +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:4566: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_GMAKE'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$GMAKE" in + /*) + ac_cv_path_GMAKE="$GMAKE" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_GMAKE="$GMAKE" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_GMAKE="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +GMAKE="$ac_cv_path_GMAKE" +if test -n "$GMAKE"; then + echo "$ac_t""$GMAKE" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$GMAKE" && break +done +test -n "$GMAKE" || GMAKE=":" + + if test "$msyshost"; then + case "$GMAKE" in + /*) + tmp_DIRNAME=`dirname "$GMAKE"` + tmp_BASENAME=`basename "$GMAKE"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + GMAKE="$tmp_PWD/$tmp_BASENAME" + if test -e "$GMAKE.exe"; then + GMAKE="$GMAKE.exe" + fi + esac + fi + + ;; +esac +if test "$GMAKE" = ":"; then + { echo "configure: error: GNU make not found" 1>&2; exit 1; } +fi + + +if test "$COMPILE_ENVIRONMENT"; then + +# If we find X, set shell vars x_includes and x_libraries to the +# paths, otherwise set no_x=yes. +# Uses ac_ vars as temps to allow command line to override cache and checks. +# --without-x overrides everything else, but does not touch the cache. +echo $ac_n "checking for X""... $ac_c" 1>&6 +echo "configure:4629: checking for X" >&5 + +# Check whether --with-x or --without-x was given. +if test "${with_x+set}" = set; then + withval="$with_x" + : +fi + +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then + # Both variables are already set. + have_x=yes + else +if eval "test \"`echo '$''{'ac_cv_have_x'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # One or both of the vars are not set, and there is no cached value. +ac_x_includes=NO ac_x_libraries=NO +rm -fr conftestdir +if mkdir conftestdir; then + cd conftestdir + # Make sure to not put "make" in the Imakefile rules, since we grep it out. + cat > Imakefile <<'EOF' +acfindx: + @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"' +EOF + if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering...", which would confuse us. + eval `${MAKE-make} acfindx 2>/dev/null | grep -v make` + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl; do + if test ! -f $ac_im_usrlibdir/libX11.$ac_extension && + test -f $ac_im_libdir/libX11.$ac_extension; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case "$ac_im_incroot" in + /usr/include) ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes="$ac_im_incroot" ;; + esac + case "$ac_im_usrlibdir" in + /usr/lib | /lib) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries="$ac_im_usrlibdir" ;; + esac + fi + cd .. + rm -fr conftestdir +fi + +if test "$ac_x_includes" = NO; then + # Guess where to find include files, by looking for this one X11 .h file. + test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h + + # First, try using that file with no special directory specified. +cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:4696: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + # We can compile using X headers with no special include directory. +ac_x_includes= +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + # Look for the header file in a standard set of common directories. +# Check X11 before X11Rn because it is often a symlink to the current release. + for ac_dir in \ + /usr/X11/include \ + /usr/X11R6/include \ + /usr/X11R5/include \ + /usr/X11R4/include \ + \ + /usr/include/X11 \ + /usr/include/X11R6 \ + /usr/include/X11R5 \ + /usr/include/X11R4 \ + \ + /usr/local/X11/include \ + /usr/local/X11R6/include \ + /usr/local/X11R5/include \ + /usr/local/X11R4/include \ + \ + /usr/local/include/X11 \ + /usr/local/include/X11R6 \ + /usr/local/include/X11R5 \ + /usr/local/include/X11R4 \ + \ + /usr/X386/include \ + /usr/x386/include \ + /usr/XFree86/include/X11 \ + \ + /usr/include \ + /usr/local/include \ + /usr/unsupported/include \ + /usr/athena/include \ + /usr/local/x11r5/include \ + /usr/lpp/Xamples/include \ + \ + /usr/openwin/include \ + /usr/openwin/share/include \ + ; \ + do + if test -r "$ac_dir/$x_direct_test_include"; then + ac_x_includes=$ac_dir + break + fi + done +fi +rm -f conftest* +fi # $ac_x_includes = NO + +if test "$ac_x_libraries" = NO; then + # Check for the libraries. + + test -z "$x_direct_test_library" && x_direct_test_library=Xt + test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc + + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS="$LIBS" + LIBS="-l$x_direct_test_library $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + LIBS="$ac_save_LIBS" +# We can link X programs with no special library path. +ac_x_libraries= +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + LIBS="$ac_save_LIBS" +# First see if replacing the include by lib works. +# Check X11 before X11Rn because it is often a symlink to the current release. +for ac_dir in `echo "$ac_x_includes" | sed s/include/lib/` \ + /usr/X11/lib \ + /usr/X11R6/lib \ + /usr/X11R5/lib \ + /usr/X11R4/lib \ + \ + /usr/lib/X11 \ + /usr/lib/X11R6 \ + /usr/lib/X11R5 \ + /usr/lib/X11R4 \ + \ + /usr/local/X11/lib \ + /usr/local/X11R6/lib \ + /usr/local/X11R5/lib \ + /usr/local/X11R4/lib \ + \ + /usr/local/lib/X11 \ + /usr/local/lib/X11R6 \ + /usr/local/lib/X11R5 \ + /usr/local/lib/X11R4 \ + \ + /usr/X386/lib \ + /usr/x386/lib \ + /usr/XFree86/lib/X11 \ + \ + /usr/lib \ + /usr/local/lib \ + /usr/unsupported/lib \ + /usr/athena/lib \ + /usr/local/x11r5/lib \ + /usr/lpp/Xamples/lib \ + /lib/usr/lib/X11 \ + \ + /usr/openwin/lib \ + /usr/openwin/share/lib \ + ; \ +do + for ac_extension in a so sl; do + if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi +rm -f conftest* +fi # $ac_x_libraries = NO + +if test "$ac_x_includes" = NO || test "$ac_x_libraries" = NO; then + # Didn't find X anywhere. Cache the known absence of X. + ac_cv_have_x="have_x=no" +else + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$ac_x_includes ac_x_libraries=$ac_x_libraries" +fi +fi + fi + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + echo "$ac_t""$have_x" 1>&6 + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$x_includes ac_x_libraries=$x_libraries" + echo "$ac_t""libraries $x_libraries, headers $x_includes" 1>&6 +fi + +if test "$no_x" = yes; then + # Not all programs may use this symbol, but it does not hurt to define it. + cat >> confdefs.h <<\EOF +#define X_DISPLAY_MISSING 1 +EOF + + X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= +else + if test -n "$x_includes"; then + X_CFLAGS="$X_CFLAGS -I$x_includes" + fi + + # It would also be nice to do this for all -L options, not just this one. + if test -n "$x_libraries"; then + X_LIBS="$X_LIBS -L$x_libraries" + # For Solaris; some versions of Sun CC require a space after -R and + # others require no space. Words are not sufficient . . . . + case "`(uname -sr) 2>/dev/null`" in + "SunOS 5"*) + echo $ac_n "checking whether -R must be followed by a space""... $ac_c" 1>&6 +echo "configure:4878: checking whether -R must be followed by a space" >&5 + ac_xsave_LIBS="$LIBS"; LIBS="$LIBS -R$x_libraries" + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_R_nospace=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_R_nospace=no +fi +rm -f conftest* + if test $ac_R_nospace = yes; then + echo "$ac_t""no" 1>&6 + X_LIBS="$X_LIBS -R$x_libraries" + else + LIBS="$ac_xsave_LIBS -R $x_libraries" + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_R_space=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_R_space=no +fi +rm -f conftest* + if test $ac_R_space = yes; then + echo "$ac_t""yes" 1>&6 + X_LIBS="$X_LIBS -R $x_libraries" + else + echo "$ac_t""neither works" 1>&6 + fi + fi + LIBS="$ac_xsave_LIBS" + esac + fi + + # Check for system-dependent libraries X programs must link with. + # Do this before checking for the system-independent R6 libraries + # (-lICE), since we may need -lsocket or whatever for X linking. + + if test "$ISC" = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" + else + # Martyn.Johnson@cl.cam.ac.uk says this is needed for Ultrix, if the X + # libraries were built with DECnet support. And karl@cs.umb.edu says + # the Alpha needs dnet_stub (dnet does not exist). + echo $ac_n "checking for dnet_ntoa in -ldnet""... $ac_c" 1>&6 +echo "configure:4943: checking for dnet_ntoa in -ldnet" >&5 +ac_lib_var=`echo dnet'_'dnet_ntoa | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldnet $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + echo $ac_n "checking for dnet_ntoa in -ldnet_stub""... $ac_c" 1>&6 +echo "configure:4984: checking for dnet_ntoa in -ldnet_stub" >&5 +ac_lib_var=`echo dnet_stub'_'dnet_ntoa | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldnet_stub $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" +else + echo "$ac_t""no" 1>&6 +fi + + fi + + # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, + # to get the SysV transport functions. + # chad@anasazi.com says the Pyramis MIS-ES running DC/OSx (SVR4) + # needs -lnsl. + # The nsl library prevents programs from opening the X display + # on Irix 5.2, according to dickey@clark.net. + echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6 +echo "configure:5032: checking for gethostbyname" >&5 +if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname) +choke me +#else +gethostbyname(); +#endif + +; return 0; } +EOF +if { (eval echo configure:5060: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_gethostbyname=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_gethostbyname=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_func_gethostbyname = no; then + echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6 +echo "configure:5081: checking for gethostbyname in -lnsl" >&5 +ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lnsl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" +else + echo "$ac_t""no" 1>&6 +fi + + fi + + # lieder@skyler.mavd.honeywell.com says without -lsocket, + # socket/setsockopt and other routines are undefined under SCO ODT + # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary + # on later versions), says simon@lia.di.epfl.ch: it contains + # gethostby* variants that don't use the nameserver (or something). + # -lsocket must be given before -lnsl if both are needed. + # We assume that if connect needs -lnsl, so does gethostbyname. + echo $ac_n "checking for connect""... $ac_c" 1>&6 +echo "configure:5130: checking for connect" >&5 +if eval "test \"`echo '$''{'ac_cv_func_connect'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char connect(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_connect) || defined (__stub___connect) +choke me +#else +connect(); +#endif + +; return 0; } +EOF +if { (eval echo configure:5158: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_connect=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_connect=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'connect`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_func_connect = no; then + echo $ac_n "checking for connect in -lsocket""... $ac_c" 1>&6 +echo "configure:5179: checking for connect in -lsocket" >&5 +ac_lib_var=`echo socket'_'connect | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsocket $X_EXTRA_LIBS $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" +else + echo "$ac_t""no" 1>&6 +fi + + fi + + # gomez@mi.uni-erlangen.de says -lposix is necessary on A/UX. + echo $ac_n "checking for remove""... $ac_c" 1>&6 +echo "configure:5222: checking for remove" >&5 +if eval "test \"`echo '$''{'ac_cv_func_remove'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char remove(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_remove) || defined (__stub___remove) +choke me +#else +remove(); +#endif + +; return 0; } +EOF +if { (eval echo configure:5250: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_remove=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_remove=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'remove`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_func_remove = no; then + echo $ac_n "checking for remove in -lposix""... $ac_c" 1>&6 +echo "configure:5271: checking for remove in -lposix" >&5 +ac_lib_var=`echo posix'_'remove | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lposix $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" +else + echo "$ac_t""no" 1>&6 +fi + + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + echo $ac_n "checking for shmat""... $ac_c" 1>&6 +echo "configure:5314: checking for shmat" >&5 +if eval "test \"`echo '$''{'ac_cv_func_shmat'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shmat(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_shmat) || defined (__stub___shmat) +choke me +#else +shmat(); +#endif + +; return 0; } +EOF +if { (eval echo configure:5342: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_shmat=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_shmat=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'shmat`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + + if test $ac_cv_func_shmat = no; then + echo $ac_n "checking for shmat in -lipc""... $ac_c" 1>&6 +echo "configure:5363: checking for shmat in -lipc" >&5 +ac_lib_var=`echo ipc'_'shmat | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lipc $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" +else + echo "$ac_t""no" 1>&6 +fi + + fi + fi + + # Check for libraries that X11R6 Xt/Xaw programs need. + ac_save_LDFLAGS="$LDFLAGS" + test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" + # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to + # check for ICE first), but we must link in the order -lSM -lICE or + # we get undefined symbols. So assume we have SM if we have ICE. + # These have to be linked with before -lX11, unlike the other + # libraries we check for below, so use a different variable. + # --interran@uluru.Stanford.EDU, kb@cs.umb.edu. + echo $ac_n "checking for IceConnectionNumber in -lICE""... $ac_c" 1>&6 +echo "configure:5415: checking for IceConnectionNumber in -lICE" >&5 +ac_lib_var=`echo ICE'_'IceConnectionNumber | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lICE $X_EXTRA_LIBS $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" +else + echo "$ac_t""no" 1>&6 +fi + + LDFLAGS="$ac_save_LDFLAGS" + +fi + + +XCFLAGS="$X_CFLAGS" + +fi # COMPILE_ENVIRONMENT + +AS_BIN=$AS +AR_LIST='$(AR) t' +AR_EXTRACT='$(AR) x' +AR_DELETE='$(AR) d' +AS='$(CC)' +AS_DASH_C_FLAG='-c' +DLL_PREFIX=lib +LIB_PREFIX=lib +DLL_SUFFIX=.so +OBJ_SUFFIX=o +LIB_SUFFIX=a +ASM_SUFFIX=s +IMPORT_LIB_SUFFIX= +TARGET_MD_ARCH=unix +DIRENT_INO=d_ino +CYGWIN_WRAPPER= +WIN_TOP_SRC= +MOZ_USER_DIR=".mozilla" + +MOZ_JS_LIBS='-L$(libdir) -lmozjs' +MOZ_FIX_LINK_PATHS='-Wl,-rpath-link,$(LIBXUL_DIST)/bin -Wl,-rpath-link,$(prefix)/lib' + +MOZ_COMPONENT_NSPR_LIBS='-L$(LIBXUL_DIST)/bin $(NSPR_LIBS)' + +USE_DEPENDENT_LIBS=1 + +_PLATFORM_DEFAULT_TOOLKIT=cairo-gtk2 + +if test -n "$CROSS_COMPILE"; then + OS_TARGET="${target_os}" + OS_ARCH=`echo $target_os | sed -e 's|/|_|g'` + OS_RELEASE= + case "${target_os}" in + linux*) OS_ARCH=Linux OS_TARGET=Linux ;; + kfreebsd*-gnu) OS_ARCH=GNU_kFreeBSD OS_TARGET=GNU_kFreeBSD ;; + gnu*) OS_ARCH=GNU ;; + solaris*) OS_ARCH=SunOS OS_RELEASE=5 ;; + mingw*) OS_ARCH=WINNT ;; + wince*) OS_ARCH=WINCE ;; + winmo*) OS_ARCH=WINCE ;; + darwin*) OS_ARCH=Darwin OS_TARGET=Darwin ;; + esac + case "${target}" in + arm-android-eabi) OS_ARCH=Linux OS_TARGET=Android ;; + esac +else + OS_TARGET=`uname -s` + OS_ARCH=`uname -s | sed -e 's|/|_|g'` + OS_RELEASE=`uname -r` +fi + +# Before this used `uname -m` when not cross compiling +# but that breaks when you have a 64 bit kernel with a 32 bit userland. +OS_TEST="${target_cpu}" + +_COMPILER_PREFIX= + +HOST_OS_ARCH=`echo $host_os | sed -e 's|/|_|g'` + +####################################################################### +# Master "Core Components" macros for getting the OS target # +####################################################################### + +# +# If OS_TARGET is not specified, it defaults to $(OS_ARCH), i.e., no +# cross-compilation. +# + +# +# Define and override various archtecture-specific variables, including +# HOST_OS_ARCH +# OS_ARCH +# OS_TEST +# OS_TARGET +# OS_RELEASE +# OS_MINOR_RELEASE +# + +case "$HOST_OS_ARCH" in +cygwin*|mingw*|mks*|msvc*) + HOST_OS_ARCH=WINNT + ;; +darwin*) + HOST_OS_ARCH=Darwin + ;; +linux*) + HOST_OS_ARCH=Linux + ;; +solaris*) + HOST_OS_ARCH=SunOS + SOLARIS_SUNPRO_CC= + SOLARIS_SUNPRO_CXX= + if test -z "$GNU_CC"; then + if test "`$CC -V 2>&1 | egrep -c 'Sun.*C '`" != "0"; then + SOLARIS_SUNPRO_CC=1 + fi + fi + + if test -z "$GNU_CXX"; then + if test "`$CXX -V 2>&1 | egrep -c 'Sun.*C\+\+ '`" != "0"; then + SOLARIS_SUNPRO_CXX=1 + fi + fi + + + ;; +BSD_386) + HOST_OS_ARCH=BSD + ;; +dgux) + HOST_OS_ARCH=DGUX + ;; +IRIX64) + HOST_OS_ARCH=IRIX + ;; +UNIX_SV) + if "`cat /etc/bcheckrc | grep -c NCR 2>/dev/null`" != "0"; then + HOST_OS_ARCH=NCR + else + HOST_OS_ARCH=UNIXWARE + fi + ;; +ncr) + HOST_OS_ARCH=NCR + ;; +UNIX_SYSTEM_V) + HOST_OS_ARCH=NEC + ;; +OSF1) + ;; +*OpenVMS*) + HOST_OS_ARCH=OpenVMS + ;; +OS_2) + HOST_OS_ARCH=OS2 + ;; +QNX) + ;; +SCO_SV) + HOST_OS_ARCH=SCOOS + ;; +SINIX-N | SINIX-Y | SINIX-Z |ReliantUNIX-M) + HOST_OS_ARCH=SINIX + ;; +UnixWare) + HOST_OS_ARCH=UNIXWARE + ;; +esac + +case "$OS_ARCH" in +WINNT) + if test -z "$CROSS_COMPILE" ; then + OS_TEST=`uname -p` + fi + ;; +Windows_NT) +# +# If uname -s returns "Windows_NT", we assume that we are using +# the uname.exe in MKS toolkit. +# +# The -r option of MKS uname only returns the major version number. +# So we need to use its -v option to get the minor version number. +# Moreover, it doesn't have the -p option, so we need to use uname -m. +# + OS_ARCH=WINNT + OS_TARGET=WINNT + OS_MINOR_RELEASE=`uname -v` + if test "$OS_MINOR_RELEASE" = "00"; then + OS_MINOR_RELEASE=0 + fi + OS_RELEASE="${OS_RELEASE}.${OS_MINOR_RELEASE}" + ;; +CYGWIN32_NT|CYGWIN_NT*|MINGW*_NT*) +# +# If uname -s returns "CYGWIN_NT-4.0", we assume that we are using +# the uname.exe in the Cygwin tools. +# Prior to the Beta 20 release, Cygwin was called GNU-Win32. +# If uname -s returns "CYGWIN32/NT", we assume that we are using +# the uname.exe in the GNU-Win32 tools. +# If uname -s returns MINGW32_NT-5.1, we assume that we are using +# the uname.exe in the MSYS tools. +# + OS_RELEASE=`expr $OS_ARCH : '.*NT-\(.*\)'` + OS_ARCH=WINNT + OS_TARGET=WINNT + ;; +AIX) + OS_RELEASE=`uname -v`.`uname -r` + OS_TEST=${target_cpu} + if test -z "$GNU_CC"; then + if test "`$CC -qversion 2>&1 | egrep -c 'IBM XL'`" != "0"; then + AIX_IBM_XLC=1 + fi + fi + ;; +BSD_386) + OS_ARCH=BSD + ;; +dgux) + OS_ARCH=DGUX + ;; +IRIX64) + OS_ARCH=IRIX + ;; +UNIX_SV) + if "`cat /etc/bcheckrc | grep -c NCR 2>/dev/null`" != "0"; then + OS_ARCH=NCR + else + OS_ARCH=UNIXWARE + OS_RELEASE=`uname -v` + fi + ;; +ncr) + OS_ARCH=NCR + ;; +UNIX_SYSTEM_V) + OS_ARCH=NEC + ;; +OSF1) + case `uname -v` in + 148) + OS_RELEASE=V3.2C + ;; + 564) + OS_RELEASE=V4.0B + ;; + 878) + OS_RELEASE=V4.0D + ;; + esac + ;; +*OpenVMS*) + OS_ARCH=OpenVMS + OS_RELEASE=`uname -v` + OS_TEST=`uname -p` + ;; +OS_2) + OS_ARCH=OS2 + OS_TARGET=OS2 + OS_RELEASE=`uname -v` + ;; +QNX) + if test "$OS_TARGET" != "NTO"; then + + OS_RELEASE=`uname -v | sed 's/^\([0-9]\)\([0-9]*\)$/\1.\2/'` + + fi + OS_TEST=x86 + ;; +SCO_SV) + OS_ARCH=SCOOS + OS_RELEASE=5.0 + ;; +SINIX-N | SINIX-Y | SINIX-Z |ReliantUNIX-M) + OS_ARCH=SINIX + OS_TEST=`uname -p` + ;; +UnixWare) + OS_ARCH=UNIXWARE + OS_RELEASE=`uname -v` + ;; +WINCE) + OS_ARCH=WINCE + case "${target_os}" in + *winmo) + OS_TARGET=WINMO + WINCE_WINDOWS_MOBILE=1 + cat >> confdefs.h <<\EOF +#define WINCE_WINDOWS_MOBILE 1 +EOF + + ;; + *) + OS_TARGET=WINCE + ;; + esac + ;; +Darwin) + case "${target_cpu}" in + powerpc*) + OS_TEST=ppc + ;; + i*86*) + OS_TEST=i386 + ;; + x86_64) + OS_TEST=x86_64 + ;; + *) + if test -z "$CROSS_COMPILE" ; then + OS_TEST=`uname -p` + fi + ;; + esac + ;; +esac + +if test "$OS_ARCH" = "NCR"; then + + OS_RELEASE=`awk '{print $3}' /etc/.relid | sed 's/^\([0-9]\)\(.\)\(..\)\(.*\)$/\2.\3/'` + +fi + +# Only set CPU_ARCH if we recognize the value of OS_TEST + +case "$OS_TEST" in +*86 | i86pc) + CPU_ARCH=x86 + ;; + +powerpc64 | ppc64) + CPU_ARCH=ppc64 + ;; + +powerpc | ppc | rs6000) + CPU_ARCH=ppc + ;; + +Alpha | alpha | ALPHA) + CPU_ARCH=Alpha + ;; + +s390) + CPU_ARCH=s390 + ;; + +s390x) + CPU_ARCH=s390x + ;; + +hppa* | parisc) + CPU_ARCH=hppa + ;; + +sun4u | sparc*) + CPU_ARCH=sparc + ;; + +x86_64 | ia64) + CPU_ARCH="$OS_TEST" + ;; + +arm*) + CPU_ARCH=arm + ;; + +mips|mipsel) + CPU_ARCH="mips" + ;; +esac + +if test -z "$OS_TARGET"; then + OS_TARGET=$OS_ARCH +fi +OS_CONFIG="${OS_TARGET}${OS_RELEASE}" + +INTEL_ARCHITECTURE= +case "$OS_TEST" in + x86_64|i?86) + INTEL_ARCHITECTURE=1 +esac + +if test "$GNU_CC"; then + # FIXME: Let us build with strict aliasing. bug 414641. + CFLAGS="$CFLAGS -fno-strict-aliasing" + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$@ -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$@ -o $@' + DSO_LDOPTS='-shared' + if test "$GCC_USE_GNU_LD"; then + # Don't allow undefined symbols in libraries + DSO_LDOPTS="$DSO_LDOPTS -Wl,-z,defs" + fi + WARNINGS_AS_ERRORS='-Werror' + DSO_CFLAGS='' + DSO_PIC_CFLAGS='-fPIC' + ASFLAGS="$ASFLAGS -fPIC" + _MOZ_RTTI_FLAGS_ON=${_COMPILER_PREFIX}-frtti + _MOZ_RTTI_FLAGS_OFF=${_COMPILER_PREFIX}-fno-rtti + _MOZ_EXCEPTIONS_FLAGS_ON='-fexceptions' + _MOZ_EXCEPTIONS_FLAGS_OFF='-fno-exceptions' + + # Turn on GNU specific features + # -Wall - turn on all warnings + # -pedantic - make compiler warn about non-ANSI stuff, and + # be a little bit stricter + # Warnings slamm took out for now (these were giving more noise than help): + # -Wbad-function-cast - warns when casting a function to a new return type + # -Wshadow - removed because it generates more noise than help --pete + _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall -W -Wno-unused -Wpointer-arith" + if test -z "$INTEL_CC"; then + # Don't use -Wcast-align with ICC + case "$CPU_ARCH" in + # And don't use it on hppa, ia64, sparc, arm, since it's noisy there + hppa | ia64 | sparc | arm) + ;; + *) + _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wcast-align" + ;; + esac + fi + + _PEDANTIC=1 + + if test -z "$INTEL_CC"; then + _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -W" + fi + + _DEFINES_CFLAGS='-include $(DEPTH)/js-confdefs.h -DMOZILLA_CLIENT' + _USE_CPP_INCLUDE_FLAG=1 +elif test "$SOLARIS_SUNPRO_CC"; then + DSO_CFLAGS='' + if test "$CPU_ARCH" = "sparc"; then + # for Sun Studio on Solaris/SPARC + DSO_PIC_CFLAGS='-xcode=pic32' + else + DSO_PIC_CFLAGS='-KPIC' + fi + _DEFINES_CFLAGS='$(ACDEFINES) -D_JS_CONFDEFS_H_ -DMOZILLA_CLIENT' +else + MKSHLIB='$(LD) $(DSO_LDOPTS) -h $@ -o $@' + MKCSHLIB='$(LD) $(DSO_LDOPTS) -h $@ -o $@' + + DSO_LDOPTS='-shared' + if test "$GNU_LD"; then + # Don't allow undefined symbols in libraries + DSO_LDOPTS="$DSO_LDOPTS -z defs" + fi + + DSO_CFLAGS='' + DSO_PIC_CFLAGS='-KPIC' + _DEFINES_CFLAGS='$(ACDEFINES) -D_JS_CONFDEFS_H_ -DMOZILLA_CLIENT' +fi + +if test "$GNU_CXX"; then + # FIXME: Let us build with strict aliasing. bug 414641. + CXXFLAGS="$CXXFLAGS -fno-strict-aliasing" + # Turn on GNU specific features + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual -Wsynth -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor" + if test -z "$INTEL_CC"; then + # Don't use -Wcast-align with ICC + case "$CPU_ARCH" in + # And don't use it on hppa, ia64, sparc, arm, since it's noisy there + hppa | ia64 | sparc | arm) + ;; + *) + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wcast-align" + ;; + esac + fi + + _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -include $(DEPTH)/js-confdefs.h' + _USE_CPP_INCLUDE_FLAG=1 + + echo $ac_n "checking whether the compiler supports -Wno-invalid-offsetof""... $ac_c" 1>&6 +echo "configure:5917: checking whether the compiler supports -Wno-invalid-offsetof" >&5 +if eval "test \"`echo '$''{'ac_has_wno_invalid_offsetof'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + + ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + _SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS ${_COMPILER_PREFIX}-Wno-invalid-offsetof" + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_has_wno_invalid_offsetof="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_has_wno_invalid_offsetof="no" +fi +rm -f conftest* + CXXFLAGS="$_SAVE_CXXFLAGS" + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + +fi + +echo "$ac_t""$ac_has_wno_invalid_offsetof" 1>&6 + if test "$ac_has_wno_invalid_offsetof" = "yes"; then + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} ${_COMPILER_PREFIX}-Wno-invalid-offsetof" + fi + + echo $ac_n "checking whether the compiler supports -Wno-variadic-macros""... $ac_c" 1>&6 +echo "configure:5967: checking whether the compiler supports -Wno-variadic-macros" >&5 +if eval "test \"`echo '$''{'ac_has_wno_variadic_macros'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + + ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + _SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS ${_COMPILER_PREFIX}-Wno-variadic-macros" + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_has_wno_variadic_macros="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_has_wno_variadic_macros="no" +fi +rm -f conftest* + CXXFLAGS="$_SAVE_CXXFLAGS" + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + +fi + +echo "$ac_t""$ac_has_wno_variadic_macros" 1>&6 + if test "$ac_has_wno_variadic_macros" = "yes"; then + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} ${_COMPILER_PREFIX}-Wno-variadic-macros" + fi + + echo $ac_n "checking whether the compiler supports -Werror=return-type""... $ac_c" 1>&6 +echo "configure:6017: checking whether the compiler supports -Werror=return-type" >&5 +if eval "test \"`echo '$''{'ac_has_werror_return_type'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + + ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + _SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -Werror=return-type" + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_has_werror_return_type="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_has_werror_return_type="no" +fi +rm -f conftest* + CXXFLAGS="$_SAVE_CXXFLAGS" + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + +fi + +echo "$ac_t""$ac_has_werror_return_type" 1>&6 + if test "$ac_has_werror_return_type" = "yes"; then + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type" + fi + +else + _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -D_JS_CONFDEFS_H_ $(ACDEFINES)' +fi + +MKSHLIB_FORCE_ALL= +MKSHLIB_UNFORCE_ALL= + +if test "$COMPILE_ENVIRONMENT"; then +if test "$GNU_CC"; then + echo $ac_n "checking whether ld has archive extraction flags""... $ac_c" 1>&6 +echo "configure:6076: checking whether ld has archive extraction flags" >&5 + if eval "test \"`echo '$''{'ac_cv_mkshlib_force_and_unforce'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + _SAVE_LDFLAGS=$LDFLAGS; _SAVE_LIBS=$LIBS + ac_cv_mkshlib_force_and_unforce="no" + exec 3<&0 < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_mkshlib_force_and_unforce=$line; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* + done + exec 0<&3 3<&- + LDFLAGS=$_SAVE_LDFLAGS; LIBS=$_SAVE_LIBS + +fi + + if test "$ac_cv_mkshlib_force_and_unforce" = "no"; then + echo "$ac_t""no" 1>&6 + else + echo "$ac_t""yes" 1>&6 + eval $ac_cv_mkshlib_force_and_unforce + MKSHLIB_FORCE_ALL=$force + MKSHLIB_UNFORCE_ALL=$unforce + fi +fi # GNU_CC +fi # COMPILE_ENVIRONMENT + +if test "$COMPILE_ENVIRONMENT"; then +configure_static_assert_macros=' +#define CONFIGURE_STATIC_ASSERT(condition) CONFIGURE_STATIC_ASSERT_IMPL(condition, __LINE__) +#define CONFIGURE_STATIC_ASSERT_IMPL(condition, line) CONFIGURE_STATIC_ASSERT_IMPL2(condition, line) +#define CONFIGURE_STATIC_ASSERT_IMPL2(condition, line) typedef int static_assert_line_##line[(condition) ? 1 : -1] +' + +echo $ac_n "checking that static assertion macros used in autoconf tests work""... $ac_c" 1>&6 +echo "configure:6133: checking that static assertion macros used in autoconf tests work" >&5 +if eval "test \"`echo '$''{'ac_cv_static_assertion_macros_work'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + ac_cv_static_assertion_macros_work="yes" + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_static_assertion_macros_work="no" +fi +rm -f conftest* + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_static_assertion_macros_work="no" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* + ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_static_assertion_macros_work="no" +fi +rm -f conftest* + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_static_assertion_macros_work="no" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + +fi + +echo "$ac_t"""$ac_cv_static_assertion_macros_work"" 1>&6 +if test "$ac_cv_static_assertion_macros_work" = "no"; then + { echo "configure: error: Compiler cannot compile macros used in autoconf tests." 1>&2; exit 1; } +fi +fi # COMPILE_ENVIRONMENT + +if test "$COMPILE_ENVIRONMENT"; then + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking for 64-bit OS""... $ac_c" 1>&6 +echo "configure:6245: checking for 64-bit OS" >&5 +cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + result="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + result="no" +fi +rm -f conftest* +echo "$ac_t"""$result"" 1>&6 +if test "$result" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_64BIT_OS 1 +EOF + + HAVE_64BIT_OS=1 +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +fi # COMPILE_ENVIRONMENT + +MOZ_OS2_HIGH_MEMORY=1 +# Check whether --enable-os2-high-mem or --disable-os2-high-mem was given. +if test "${enable_os2_high_mem+set}" = set; then + enableval="$enable_os2_high_mem" + if test "$enableval" = "no"; then + MOZ_OS2_HIGH_MEMORY= + elif test "$enableval" = "yes"; then + MOZ_OS2_HIGH_MEMORY=1 + else + { echo "configure: error: Option, os2-high-mem, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + + +# Check whether --enable-profiling or --disable-profiling was given. +if test "${enable_profiling+set}" = set; then + enableval="$enable_profiling" + if test "$enableval" = "yes"; then + MOZ_PROFILING=1 + elif test "$enableval" = "no"; then + MOZ_PROFILING= + else + { echo "configure: error: Option, profiling, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +case "$host" in +*-beos*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_BEOS -DBeOS -DBEOS -D_POSIX_SOURCE -DNO_X11" + HOST_NSPR_MDCPUCFG='\"md/_beos.cfg\"' + HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O3}" + ;; + +*cygwin*|*mingw*|*mks*|*msvc*|*wince|*winmo) + # we need Python 2.5 on Windows + PYTHON_VERSION=2.5 + if test -n "$_WIN32_MSVC"; then + HOST_AR=lib + HOST_AR_FLAGS='-NOLOGO -OUT:"$@"' + HOST_CFLAGS="$HOST_CFLAGS -TC -nologo -Fd\$(HOST_PDBFILE)" + HOST_RANLIB='echo ranlib' + else + HOST_CFLAGS="$HOST_CFLAGS -mno-cygwin" + fi + HOST_CFLAGS="$HOST_CFLAGS -DXP_WIN32 -DXP_WIN -DWIN32 -D_WIN32 -DNO_X11" + HOST_NSPR_MDCPUCFG='\"md/_winnt.cfg\"' + HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O2}" + HOST_BIN_SUFFIX=.exe + case "$host" in + *mingw*) + PERL="/bin/sh ${_topsrcdir}/build/msys-perl-wrapper" + ;; + *) + CYGWIN_WRAPPER="${srcdir}/build/cygwin-wrapper" + if test "`echo ${srcdir} | grep -c ^/ 2>/dev/null`" = 0; then + _pwd=`pwd` + CYGWIN_WRAPPER="${_pwd}/${srcdir}/build/cygwin-wrapper" + fi + if test "`${PERL} -v | grep -c cygwin 2>/dev/null`" = 0; then + AS_PERL=1 + PERL="${CYGWIN_WRAPPER} $PERL" + fi + + if test "`${PYTHON} -c 'import sys; print sys.platform;'`" != "cygwin"; then + PYTHON="${CYGWIN_WRAPPER} $PYTHON" + fi + ;; + esac + + case "${host_cpu}" in + x86_64) + HOST_CFLAGS="$HOST_CFLAGS -D_AMD64_" + ;; + esac + ;; + +*-darwin*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX -DXP_MACOSX -DNO_X11" + HOST_NSPR_MDCPUCFG='\"md/_darwin.cfg\"' + HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O3}" + ;; + +*-linux*|*-kfreebsd*-gnu|*-gnu*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX" + HOST_NSPR_MDCPUCFG='\"md/_linux.cfg\"' + HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O3}" + ;; + +*os2*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_OS2 -DNO_X11 -Zomf" + HOST_NSPR_MDCPUCFG='\"md/_os2.cfg\"' + HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O2}" + HOST_BIN_SUFFIX=.exe + MOZ_FIX_LINK_PATHS= + ;; + +*-osf*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX" + HOST_NSPR_MDCPUCFG='\"md/_osf1.cfg\"' + HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O2}" + ;; + +*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX" + HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O2}" + ;; +esac + +echo $ac_n "checking for Python version >= $PYTHON_VERSION but not 3.x""... $ac_c" 1>&6 +echo "configure:6393: checking for Python version >= $PYTHON_VERSION but not 3.x" >&5 + +$PYTHON -c "import sys; sys.exit(sys.version[:3] < sys.argv[1] or sys.version[:2] != '2.')" $PYTHON_VERSION +_python_res=$? + +if test "$_python_res" != 0; then + { echo "configure: error: Python $PYTHON_VERSION or higher (but not Python 3.x) is required." 1>&2; exit 1; } +fi +echo "$ac_t""yes" 1>&6 + + +case "$target" in +*-aix*) + cat >> confdefs.h <<\EOF +#define AIX 1 +EOF + + if test ! "$GNU_CC"; then + if test ! "$HAVE_64BIT_OS"; then + # Compiling with Visual Age C++ object model compat is the + # default. To compile with object model ibm, add + # AIX_OBJMODEL=ibm to .mozconfig. + if test "$AIX_OBJMODEL" = "ibm"; then + CXXFLAGS="$CXXFLAGS -qobjmodel=ibm" + else + AIX_OBJMODEL=compat + fi + else + AIX_OBJMODEL=compat + fi + + DSO_LDOPTS='-qmkshrobj=1' + DSO_CFLAGS='-qflag=w:w' + DSO_PIC_CFLAGS= + LDFLAGS="$LDFLAGS -Wl,-brtl -blibpath:/usr/lib:/lib" + MOZ_FIX_LINK_PATHS= + MKSHLIB='$(CXX) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + if test "$COMPILE_ENVIRONMENT"; then + + ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + echo $ac_n "checking for IBM XLC/C++ compiler version >= 9.0.0.7""... $ac_c" 1>&6 +echo "configure:6441: checking for IBM XLC/C++ compiler version >= 9.0.0.7" >&5 + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + _BAD_COMPILER= +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + _BAD_COMPILER=1 +fi +rm -f conftest* + if test -n "$_BAD_COMPILER"; then + echo "$ac_t""no" 1>&6 + { echo "configure: error: IBM XLC/C++ 9.0.0.7 or higher is required to build." 1>&2; exit 1; } + else + echo "$ac_t""yes" 1>&6 + fi + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + TARGET_COMPILER_ABI="ibmc" + CC_VERSION=`lslpp -Lcq vac.C 2>/dev/null | awk -F: '{ print $3 }'` + CXX_VERSION=`lslpp -Lcq vacpp.cmp.core 2>/dev/null | awk -F: '{ print $3 }'` + fi + fi + case "${target_os}" in + aix4.1*) + DLL_SUFFIX='_shr.a' + ;; + esac + if test "$COMPILE_ENVIRONMENT"; then + for ac_hdr in sys/inttypes.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:6490: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:6500: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + fi + cat >> confdefs.h <<\EOF +#define JS_SYS_TYPES_H_DEFINES_EXACT_SIZE_TYPES 1 +EOF + + cat >> confdefs.h <<\EOF +#define NSCAP_DISABLE_DEBUG_PTR_TYPES 1 +EOF + + ;; + +*-beos*) + no_x=yes + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_LDOPTS) -Wl,-h,$@ -o $@' + _PLATFORM_DEFAULT_TOOLKIT="cairo-beos" + DSO_LDOPTS='-nostart' + TK_LIBS='-lbe -lroot' + LIBS="$LIBS -lbe" + if test "$COMPILE_ENVIRONMENT"; then + echo $ac_n "checking for main in -lbind""... $ac_c" 1>&6 +echo "configure:6546: checking for main in -lbind" >&5 +ac_lib_var=`echo bind'_'main | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lbind $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -lbind" +else + echo "$ac_t""no" 1>&6 +fi + + echo $ac_n "checking for main in -lzeta""... $ac_c" 1>&6 +echo "configure:6582: checking for main in -lzeta" >&5 +ac_lib_var=`echo zeta'_'main | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lzeta $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -lzeta" +else + echo "$ac_t""no" 1>&6 +fi + + fi + _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-multichar" + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-multichar" + _MOZ_USE_RTTI=1 + USE_DEPENDENT_LIBS= + MOZ_USER_DIR="Mozilla" + ;; + +*-bsdi*) + _PEDANTIC= + case $OS_RELEASE in + 4.*|5.*) + STRIP="$STRIP -d" + ;; + *) + DSO_CFLAGS='' + DSO_LDOPTS='-r' + _WARNINGS_CFLAGS="-Wall" + _WARNINGS_CXXFLAGS="-Wall" + # The test above doesn't work properly, at least on 3.1. + MKSHLIB_FORCE_ALL='' + MKSHLIB_UNFORCE_ALL='' + ;; + esac + ;; + +*-darwin*) + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + # If we're building with --enable-profiling, we need a frame pointer. + if test -z "$MOZ_PROFILING"; then + MOZ_OPTIMIZE_FLAGS="-O3 -fomit-frame-pointer" + else + MOZ_OPTIMIZE_FLAGS="-O3 -fno-omit-frame-pointer" + fi + _PEDANTIC= + CFLAGS="$CFLAGS -fpascal-strings -fno-common" + CXXFLAGS="$CXXFLAGS -fpascal-strings -fno-common" + DLL_SUFFIX=".dylib" + DSO_LDOPTS='' + STRIP="$STRIP -x -S" + _PLATFORM_DEFAULT_TOOLKIT='cairo-cocoa' + TARGET_NSPR_MDCPUCFG='\"md/_darwin.cfg\"' + LDFLAGS="$LDFLAGS -framework Cocoa -lobjc" + LIBXUL_LIBS='$(XPCOM_FROZEN_LDOPTS) $(LIBXUL_DIST)/bin/XUL' + # The ExceptionHandling framework is needed for Objective-C exception + # logging code in nsObjCExceptions.h. Currently we only use that in debug + # builds. + MOZ_DEBUG_LDFLAGS="$MOZ_DEBUG_LDFLAGS -framework ExceptionHandling" + + if test "x$enable_dtrace" = "xyes"; then + echo "Skipping -dead_strip because DTrace is enabled. See bug 403132." + else + echo $ac_n "checking for -dead_strip option to ld""... $ac_c" 1>&6 +echo "configure:6671: checking for -dead_strip option to ld" >&5 + _SAVE_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -Wl,-dead_strip" + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + _HAVE_DEAD_STRIP=1 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + _HAVE_DEAD_STRIP= +fi +rm -f conftest* + if test -n "$_HAVE_DEAD_STRIP" ; then + echo "$ac_t""yes" 1>&6 + MOZ_OPTIMIZE_LDFLAGS="-Wl,-dead_strip" + else + echo "$ac_t""no" 1>&6 + fi + + LDFLAGS=$_SAVE_LDFLAGS + fi + MOZ_FIX_LINK_PATHS='-Wl,-executable_path,$(LIBXUL_DIST)/bin' + ;; + +*-freebsd*) + if test `test -x /usr/bin/objformat && /usr/bin/objformat || echo elf` != "elf"; then + DLL_SUFFIX=".so.1.0" + DSO_LDOPTS="-shared" + fi + if test ! "$GNU_CC"; then + DSO_LDOPTS="-Bshareable $DSO_LDOPTS" + fi + ;; + +ia64*-hpux*) + DLL_SUFFIX=".so" + if test ! "$GNU_CC"; then + DSO_LDOPTS='-b' + DSO_CFLAGS="" + DSO_PIC_CFLAGS= + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_LDOPTS) -o $@' + CXXFLAGS="$CXXFLAGS -Wc,-ansi_for_scope,on" + else + DSO_LDOPTS='-b -E' + MKSHLIB='$(LD) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(LD) $(DSO_LDOPTS) -o $@' + fi + MOZ_FIX_LINK_PATHS= + SYSTEM_MAKEDEPEND= + cat >> confdefs.h <<\EOF +#define NSCAP_DISABLE_DEBUG_PTR_TYPES 1 +EOF + + cat >> confdefs.h <<\EOF +#define _LARGEFILE64_SOURCE 1 +EOF + + ;; + +*-hpux*) + DLL_SUFFIX=".sl" + if test ! "$GNU_CC"; then + DSO_LDOPTS='-b -Wl,+s' + DSO_CFLAGS="" + DSO_PIC_CFLAGS="+Z" + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_LDOPTS) -L$(LIBXUL_DIST)/bin -o $@' + MKCSHLIB='$(LD) -b +s -L$(LIBXUL_DIST)/bin -o $@' + CXXFLAGS="$CXXFLAGS -Wc,-ansi_for_scope,on" + else + DSO_LDOPTS='-b -E +s' + MKSHLIB='$(LD) $(DSO_LDOPTS) -L$(LIBXUL_DIST)/bin -L$(LIBXUL_DIST)/lib -o $@' + MKCSHLIB='$(LD) $(DSO_LDOPTS) -L$(LIBXUL_DIST)/bin -L$(LIBXUL_DIST)/lib -o $@' + fi + MOZ_POST_PROGRAM_COMMAND='chatr +s enable' + cat >> confdefs.h <<\EOF +#define NSCAP_DISABLE_DEBUG_PTR_TYPES 1 +EOF + + ;; + +*-irix5*) + cat >> confdefs.h <<\EOF +#define IRIX 1 +EOF + + DSO_LDOPTS='-elf -shared' + + if test "$GNU_CC"; then + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + MKSHLIB_FORCE_ALL='-Wl,-all' + MKSHLIB_UNFORCE_ALL='-Wl,-none' + CXXFLAGS="$CXXFLAGS -D_LANGUAGE_C_PLUS_PLUS" + else + MKSHLIB='$(LD) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(LD) $(DSO_LDOPTS) -o $@' + MKSHLIB_FORCE_ALL='-all' + MKSHLIB_UNFORCE_ALL='-none' + fi + ;; + +*-irix6*) + cat >> confdefs.h <<\EOF +#define IRIX 1 +EOF + + USE_N32=1 + TARGET_COMPILER_ABI=n32 + DSO_LDOPTS='-elf -shared' + MKSHLIB='$(CCC) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + _MOZ_EXCEPTIONS_FLAGS_OFF="-LANG:exceptions=OFF" + _MOZ_EXCEPTIONS_FLAGS_ON="-LANG:exceptions=ON" + if test "$GNU_CC"; then + MKSHLIB_FORCE_ALL='-Wl,-all' + MKSHLIB_UNFORCE_ALL='-Wl,-none' + _WARNINGS_CFLAGS="-Wall" + _WARNINGS_CXXFLAGS="-Wall" + CXXFLAGS="$CXXFLAGS -D_LANGUAGE_C_PLUS_PLUS" + else + MKSHLIB_FORCE_ALL='-all' + MKSHLIB_UNFORCE_ALL='-none' + AR_LIST="$AR t" + AR_EXTRACT="$AR x" + AR_DELETE="$AR d" + AR='$(CXX) -ar' + AR_FLAGS='-o $@' + CFLAGS="$CFLAGS -woff 3262 -G 4" + CXXFLAGS="$CXXFLAGS -woff 3262 -G 4" + if test -n "$USE_N32"; then + ASFLAGS="$ASFLAGS -n32" + CFLAGS="$CFLAGS -n32" + CXXFLAGS="$CXXFLAGS -n32" + LDFLAGS="$LDFLAGS -n32" + fi + cat >> confdefs.h <<\EOF +#define NSCAP_DISABLE_DEBUG_PTR_TYPES 1 +EOF + + echo "configure: warning: Clearing MOZ_FIX_LINK_PATHS for OSF/1 as fix for bug 333545 (till the reference bug 332075 is fixed." 1>&2 + MOZ_FIX_LINK_PATHS= + fi + if test -z "$GNU_CXX"; then + MIPSPRO_CXX=1 + fi + ;; + +*-*linux*) + # Note: both GNU_CC and INTEL_CC are set when using Intel's C compiler. + # Similarly for GNU_CXX and INTEL_CXX. + if test "$INTEL_CC" -o "$INTEL_CXX"; then + # -Os has been broken on Intel's C/C++ compilers for quite a + # while; Intel recommends against using it. + MOZ_OPTIMIZE_FLAGS="-O2" + MOZ_DEBUG_FLAGS="-g" + elif test "$GNU_CC" -o "$GNU_CXX"; then + GCC_VERSION=`$CC -v 2>&1 | awk '/^gcc version/ { print $3 }'` + case $GCC_VERSION in + 4.1.*|4.2.*|4.5.*) + # -Os is broken on gcc 4.1.x 4.2.x, 4.5.x we need to tweak it to get good results. + MOZ_OPTIMIZE_SIZE_TWEAK="-finline-limit=50" + esac + # If we're building with --enable-profiling, we need a frame pointer. + if test -z "$MOZ_PROFILING"; then + MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fomit-frame-pointer $MOZ_OPTIMIZE_SIZE_TWEAK" + else + MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-omit-frame-pointer $MOZ_OPTIMIZE_SIZE_TWEAK" + fi + MOZ_DEBUG_FLAGS="-g" + fi + + TARGET_NSPR_MDCPUCFG='\"md/_linux.cfg\"' + + case "${target_cpu}" in + alpha*) + CFLAGS="$CFLAGS -mieee" + CXXFLAGS="$CXXFLAGS -mieee" + ;; + mips*) + MOZ_DEBUG_FLAGS="-g" # We want inlining + ;; + esac + ;; + +*-wince*|*-winmo*) + TARGET_COMPILER_ABI=msvc + MOZ_TOOLS_DIR=`echo $MOZ_TOOLS` + AR_LIST="$AR -list" + AR_EXTRACT="$AR -extract" + AR_DELETE="$AR d" + AR_FLAGS='-OUT:"$@"' + AS="$AS_BIN" + + DSO_CFLAGS= + DSO_PIC_CFLAGS= + DLL_SUFFIX=.dll + BIN_SUFFIX='.exe' + if test -z "$RC"; then + RC=rc.exe + fi + # certain versions of cygwin's makedepend barf on the + # #include vs -I./dist/include/string issue so don't use it + SYSTEM_MAKEDEPEND= + + HOST_CC=cl + HOST_CXX=cl + HOST_LD=link + HOST_AR='lib -OUT:$@' + HOST_RANLIB='echo ranlib' + HOST_CFLAGS="$HOST_CFLAGS -D_X86_" + + + WARNINGS_AS_ERRORS='-WX' + MOZ_OPTIMIZE_FLAGS='-Ox' + AR_FLAGS='-NOLOGO -OUT:"$@"' + ASM_SUFFIX=asm + CFLAGS="$CFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)" + CXXFLAGS="$CXXFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)" + DLL_PREFIX= + DOXYGEN=: + DSO_LDOPTS=-SUBSYSTEM:WINDOWSCE + DYNAMIC_XPCOM_LIBS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xpcom_core.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + GARBAGE= + IMPORT_LIB_SUFFIX=lib + LIBS="$LIBS \$(LIBXUL_DIST)/lib/mozalloc.lib" + LIBXUL_LIBS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xul.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + LIB_PREFIX= + LIB_SUFFIX=lib + MKCSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ $(DSO_LDOPTS)' + MKSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ $(DSO_LDOPTS)' + MKSHLIB_FORCE_ALL= + MKSHLIB_UNFORCE_ALL= + MOZ_COMPONENT_NSPR_LIBS='$(NSPR_LIBS)' + MOZ_COMPONENT_NSPR_LIBS='$(NSPR_LIBS)' + MOZ_DEBUG_FLAGS='-Zi' + MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV' + MOZ_FIX_LINK_PATHS= + MOZ_JS_LIBS='$(libdir)/mozjs.lib' + OBJ_SUFFIX=obj + RANLIB='echo not_ranlib' + STRIP='echo not_strip' + TARGET_NSPR_MDCPUCFG='\"md/_wince.cfg\"' + UNZIP=unzip + XARGS=xargs + XPCOM_FROZEN_LDOPTS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + ZIP=zip + + cat >> confdefs.h <<\EOF +#define HAVE_SNPRINTF 1 +EOF + + cat >> confdefs.h <<\EOF +#define _WINDOWS 1 +EOF + + cat >> confdefs.h <<\EOF +#define WIN32 1 +EOF + + cat >> confdefs.h <<\EOF +#define XP_WIN 1 +EOF + + cat >> confdefs.h <<\EOF +#define XP_WIN32 1 +EOF + + cat >> confdefs.h <<\EOF +#define HW_THREADS 1 +EOF + + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + + cat >> confdefs.h <<\EOF +#define NEW_H +EOF + + cat >> confdefs.h <<\EOF +#define WIN32_LEAN_AND_MEAN 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_LOCALTIME_R 1 +EOF + + + TARGET_MD_ARCH=win32 + _PLATFORM_DEFAULT_TOOLKIT='cairo-windows' + BIN_SUFFIX='.exe' + MOZ_USER_DIR="Mozilla" + + WINCE_WINDOWS_MOBILE=1 + + # Check whether --enable-windows-mobile-components or --disable-windows-mobile-components was given. +if test "${enable_windows_mobile_components+set}" = set; then + enableval="$enable_windows_mobile_components" + if test "$enableval" = "no"; then + WINCE_WINDOWS_MOBILE= + elif test "$enableval" = "yes"; then + WINCE_WINDOWS_MOBILE=1 + else + { echo "configure: error: Option, windows-mobile-components, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + + if test "$WINCE_WINDOWS_MOBILE"; then + cat >> confdefs.h <<\EOF +#define WINCE_WINDOWS_MOBILE 1 +EOF + + fi +;; + +*-symbian*) + + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYMBIAN 1 +EOF + + cat >> confdefs.h <<\EOF +#define __arm__ 1 +EOF + + cat >> confdefs.h <<\EOF +#define __SYMBIAN32__ 1 +EOF + + cat >> confdefs.h <<\EOF +#define _UNICODE 1 +EOF + + cat >> confdefs.h <<\EOF +#define NDEBUG 1 +EOF + + cat >> confdefs.h <<\EOF +#define __SUPPORT_CPP_EXCEPTIONS__ 1 +EOF + + cat >> confdefs.h <<\EOF +#define MOZ_STDERR_TO_STDOUT 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_SOCKLEN_T 1 +EOF + + cat >> confdefs.h <<\EOF +#define __GCCE__ 1 +EOF + + + CPU_ARCH=ARM + OS_RELEASE=9.2 + OS_ARCH=SYMBIAN + USE_PTHREADS=1 + LIB_SUFFIX=lib + DLL_SUFFIX=dll + MKSHLIB= + DSO_LDOPTS= + DSO_CFLAGS= + VISIBILITY_FLAGS= + TARGET_NSPR_MDCPUCFG='\"md/_symbian.cfg\"' + RANLIB='echo no ranlib ' +;; + +*-mingw*|*-cygwin*|*-msvc*|*-mks*) + DSO_CFLAGS= + DSO_PIC_CFLAGS= + DLL_SUFFIX=.dll + RC=rc.exe + # certain versions of cygwin's makedepend barf on the + # #include vs -I./dist/include/string issue so don't use it + SYSTEM_MAKEDEPEND= + if test -n "$GNU_CC"; then + CC="$CC -mno-cygwin" + CXX="$CXX -mno-cygwin" + CPP="$CPP -mno-cygwin" + CFLAGS="$CFLAGS -mms-bitfields" + CXXFLAGS="$CXXFLAGS -mms-bitfields" + DSO_LDOPTS='-shared' + MKSHLIB='$(CXX) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + RC='$(WINDRES)' + # Use temp file for windres (bug 213281) + RCFLAGS='-O coff --use-temp-file' + # mingw doesn't require kernel32, user32, and advapi32 explicitly + LIBS="$LIBS -lgdi32 -lwinmm -lwsock32" + MOZ_JS_LIBS='-L$(libdir) -lmozjs' + MOZ_FIX_LINK_PATHS= + DYNAMIC_XPCOM_LIBS='-L$(LIBXUL_DIST)/lib -lxpcom -lxpcom_core -lmozalloc' + XPCOM_FROZEN_LDOPTS='-L$(LIBXUL_DIST)/lib -lxpcom -lmozalloc' + DLL_PREFIX= + IMPORT_LIB_SUFFIX=dll.a + GCC_VERSION=`$CC -v 2>&1 | awk '/^gcc version/ { print $3 }'` + else + TARGET_COMPILER_ABI=msvc + HOST_CC='$(CC)' + HOST_CXX='$(CXX)' + HOST_LD='$(LD)' + if test "$AS_BIN"; then + AS="$(basename "$AS_BIN")" + fi + AR='lib -NOLOGO -OUT:"$@"' + AR_FLAGS= + RANLIB='echo not_ranlib' + STRIP='echo not_strip' + PKG_SKIP_STRIP=1 + XARGS=xargs + ZIP=zip + UNZIP=unzip + DOXYGEN=: + GARBAGE='$(OBJDIR)/vc20.pdb $(OBJDIR)/vc40.pdb' + ASM_SUFFIX=asm + OBJ_SUFFIX=obj + LIB_SUFFIX=lib + DLL_PREFIX= + LIB_PREFIX= + IMPORT_LIB_SUFFIX=lib + MKSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)' + MKCSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)' + MKSHLIB_FORCE_ALL= + MKSHLIB_UNFORCE_ALL= + DSO_LDOPTS=-SUBSYSTEM:WINDOWS + _USE_CPP_INCLUDE_FLAG=1 + _DEFINES_CFLAGS='-FI $(DEPTH)/js-confdefs.h -DMOZILLA_CLIENT' + _DEFINES_CXXFLAGS='-FI $(DEPTH)/js-confdefs.h -DMOZILLA_CLIENT' + CFLAGS="$CFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)" + CXXFLAGS="$CXXFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)" + # MSVC warnings C4244 and C4800 are ubiquitous, useless, and annoying. + CXXFLAGS="$CXXFLAGS -wd4244 -wd4800" + LIBS="$LIBS kernel32.lib user32.lib gdi32.lib winmm.lib wsock32.lib advapi32.lib" + MOZ_DEBUG_FLAGS='-Zi' + MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV' + WARNINGS_AS_ERRORS='-WX' + # If we're building with --enable-profiling, we need -Oy-, which forces a frame pointer. + if test -z "$MOZ_PROFILING"; then + MOZ_OPTIMIZE_FLAGS='-O1' + else + MOZ_OPTIMIZE_FLAGS='-O1 -Oy-' + fi + MOZ_JS_LIBS='$(libdir)/mozjs.lib' + MOZ_FIX_LINK_PATHS= + DYNAMIC_XPCOM_LIBS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xpcom_core.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + XPCOM_FROZEN_LDOPTS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + LIBXUL_LIBS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xul.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + MOZ_COMPONENT_NSPR_LIBS='$(NSPR_LIBS)' + if test $_MSC_VER -ge 1400; then + LDFLAGS="$LDFLAGS -LARGEADDRESSAWARE -NXCOMPAT" + PROFILE_GEN_CFLAGS="-GL" + PROFILE_GEN_LDFLAGS="-LTCG:PGINSTRUMENT" + PROFILE_USE_CFLAGS="-GL -wd4624 -wd4952" + PROFILE_USE_LDFLAGS="-LTCG:PGUPDATE" + LDFLAGS="$LDFLAGS -DYNAMICBASE" + fi + fi + cat >> confdefs.h <<\EOF +#define HAVE_SNPRINTF 1 +EOF + + cat >> confdefs.h <<\EOF +#define _WINDOWS 1 +EOF + + cat >> confdefs.h <<\EOF +#define WIN32 1 +EOF + + cat >> confdefs.h <<\EOF +#define XP_WIN 1 +EOF + + cat >> confdefs.h <<\EOF +#define XP_WIN32 1 +EOF + + cat >> confdefs.h <<\EOF +#define HW_THREADS 1 +EOF + + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + + cat >> confdefs.h <<\EOF +#define NEW_H +EOF + + cat >> confdefs.h <<\EOF +#define WIN32_LEAN_AND_MEAN 1 +EOF + + TARGET_MD_ARCH=win32 + _PLATFORM_DEFAULT_TOOLKIT='cairo-windows' + BIN_SUFFIX='.exe' + MOZ_USER_DIR="Mozilla" + + TARGET_NSPR_MDCPUCFG='\"md/_win95.cfg\"' + + no_x=yes + cat >> confdefs.h <<\EOF +#define NO_X11 1 +EOF + + + case "$host" in + *-mingw*) + CYGPATH_W=echo + CYGPATH_S=cat + MOZ_BUILD_ROOT=`cd $MOZ_BUILD_ROOT && pwd -W` + ;; + *-cygwin*|*-msvc*|*-mks*) + CYGPATH_W="cygpath -a -w" + CYGPATH_S="sed -e s|\\\\|/|g" + MOZ_BUILD_ROOT=`$CYGPATH_W $MOZ_BUILD_ROOT | $CYGPATH_S` + ;; + esac + case "$host" in + *-mingw*|*-cygwin*|*-msvc*|*-mks*) + + if test -z "$MOZ_TOOLS"; then + { echo "configure: error: MOZ_TOOLS is not set" 1>&2; exit 1; } + fi + + MOZ_TOOLS_DIR=`cd $MOZ_TOOLS && pwd -W` + if test "$?" != "0" -o -z "$MOZ_TOOLS_DIR"; then + { echo "configure: error: cd \$MOZ_TOOLS failed. MOZ_TOOLS ==? $MOZ_TOOLS" 1>&2; exit 1; } + fi + MOZ_TOOLS_BIN_DIR="$(cd "$MOZ_TOOLS_DIR/bin" && pwd)" + if test `echo ${PATH}: | grep -ic "$MOZ_TOOLS_BINDIR:"` = 0; then + { echo "configure: error: \$MOZ_TOOLS\\bin must be in your path." 1>&2; exit 1; } + fi + MOZ_TOOLS_DIR=`$CYGPATH_W $MOZ_TOOLS_DIR | $CYGPATH_S` + ;; + esac + + + case "$host_os" in + cygwin*|msvc*|mks*) + echo "configure: warning: Using a cygwin build environment is unsupported. Configure cannot check for the presence of necessary headers. Please upgrade to MozillaBuild; see https://developer.mozilla.org/en/Windows_Build_Prerequisites." 1>&2 + ;; + esac + + case "$target" in + i*86-*) + if test "$HAVE_64BIT_OS"; then + { echo "configure: error: You are targeting i386 but using the 64-bit compiler." 1>&2; exit 1; } + fi + + if test $_MSC_VER -ge 1400; then + LDFLAGS="$LDFLAGS -SAFESEH" + fi + + if test -n "$GNU_CC"; then + CFLAGS="$CFLAGS -mstackrealign" + CXXFLAGS="$CXXFLAGS -mstackrealign" + fi + + for ac_hdr in mmintrin.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:7254: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:7264: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + cat >> confdefs.h <<\EOF +#define _X86_ 1 +EOF + + ;; + alpha-*) + cat >> confdefs.h <<\EOF +#define _ALPHA_ 1 +EOF + + ;; + mips-*) + cat >> confdefs.h <<\EOF +#define _MIPS_ 1 +EOF + + ;; + x86_64-*) + cat >> confdefs.h <<\EOF +#define _AMD64_ 1 +EOF + + ;; + *) + cat >> confdefs.h <<\EOF +#define _CPU_ARCH_NOT_DEFINED 1 +EOF + + ;; + esac + + if test "$HAVE_64BIT_OS"; then + cat >> confdefs.h <<\EOF +#define _WIN64 1 +EOF + + fi + ;; + +*-netbsd*) + DSO_CFLAGS='' + CFLAGS="$CFLAGS -Dunix" + CXXFLAGS="$CXXFLAGS -Dunix" + if $CC -E - -dM /dev/null; then + DLL_SUFFIX=".so" + DSO_PIC_CFLAGS='-fPIC -DPIC' + DSO_LDOPTS='-shared' + BIN_FLAGS='-Wl,--export-dynamic' + else + DSO_PIC_CFLAGS='-fPIC -DPIC' + DLL_SUFFIX=".so.1.0" + DSO_LDOPTS='-shared' + fi + # This will fail on a.out systems prior to 1.5.1_ALPHA. + MKSHLIB_FORCE_ALL='-Wl,--whole-archive' + MKSHLIB_UNFORCE_ALL='-Wl,--no-whole-archive' + if test "$LIBRUNPATH"; then + DSO_LDOPTS="-Wl,-R$LIBRUNPATH $DSO_LDOPTS" + fi + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-soname,lib$(LIBRARY_NAME)$(DLL_SUFFIX) -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-soname,lib$(LIBRARY_NAME)$(DLL_SUFFIX) -o $@' + ;; + +*-nto*) + cat >> confdefs.h <<\EOF +#define NTO 1 +EOF + + cat >> confdefs.h <<\EOF +#define _QNX_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _i386 1 +EOF + + OS_TARGET=NTO + WARNINGS_AS_ERRORS='' + MOZ_OPTIMIZE_FLAGS="-O" + MOZ_DEBUG_FLAGS="-gstabs" + USE_PTHREADS=1 + _PEDANTIC= + LIBS="$LIBS -lsocket -lstdc++" + _DEFINES_CFLAGS='-include $(DEPTH)/js-confdefs.h -DMOZILLA_CLIENT -D_POSIX_C_SOURCE=199506' + _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -include $(DEPTH)/js-confdefs.h -D_POSIX_C_SOURCE=199506' + if test "$with_x" != "yes" + then + _PLATFORM_DEFAULT_TOOLKIT="photon" + TK_CFLAGS='-I/usr/include/photon' + TK_LIBS='-lph' + fi + case "${target_cpu}" in + ppc*) + cat >> confdefs.h <<\EOF +#define HAVE_VA_LIST_AS_ARRAY 1 +EOF + + ;; + esac + ;; + +*-openbsd*) + DLL_SUFFIX=".so.1.0" + DSO_CFLAGS='' + DSO_PIC_CFLAGS='-fPIC' + DSO_LDOPTS='-shared -fPIC' + if test "$LIBRUNPATH"; then + DSO_LDOPTS="-R$LIBRUNPATH $DSO_LDOPTS" + fi + ;; + +*-openvms*) + cat >> confdefs.h <<\EOF +#define NO_PW_GECOS 1 +EOF + + cat >> confdefs.h <<\EOF +#define NO_UDSOCK 1 +EOF + + cat >> confdefs.h <<\EOF +#define POLL_WITH_XCONNECTIONNUMBER 1 +EOF + + USE_PTHREADS=1 + MKSHLIB_FORCE_ALL='-all' + MKSHLIB_UNFORCE_ALL='-none' + AS='as' + AS_DASH_C_FLAG='-Wc/names=as_is' + AR_FLAGS='c $@' + DSO_LDOPTS='-shared -auto_symvec' + DSO_PIC_CFLAGS= + MOZ_DEBUG_LDFLAGS='-g' + COMPAQ_CXX=1 + CC_VERSION=`$CC -V 2>&1 | awk '/ C / { print $3 }'` + CXX_VERSION=`$CXX -V 2>&1 | awk '/ C\+\+ / { print $3 }'` + ;; + + +*-os2*) + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + cat >> confdefs.h <<\EOF +#define OS2 1 +EOF + + cat >> confdefs.h <<\EOF +#define XP_OS2 1 +EOF + + cat >> confdefs.h <<\EOF +#define OS2EMX_PLAIN_CHAR 1 +EOF + + cat >> confdefs.h <<\EOF +#define TCPV40HDRS 1 +EOF + + DLL_PREFIX= + LIB_PREFIX= + LIB_SUFFIX=lib + BIN_SUFFIX=".exe" + DLL_SUFFIX=".dll" + IMPORT_LIB_SUFFIX=lib + DSO_PIC_CFLAGS= + AR=emxomfar + AR_FLAGS='r $@' + CFLAGS="$CFLAGS -Zomf" + CXXFLAGS="$CXXFLAGS -Zomf" + DSO_LDOPTS='-Zdll' + BIN_FLAGS='-Zlinker /ST:0x100000' + IMPLIB='emximp -o' + FILTER='true' + LDFLAGS='-Zmap' + WARNINGS_AS_ERRORS='-Werror' + MOZ_DEBUG_FLAGS="-g -fno-inline" + MOZ_OPTIMIZE_FLAGS="-O2" + MOZ_OPTIMIZE_LDFLAGS="-s -Zlinker /EXEPACK:2 -Zlinker /PACKCODE -Zlinker /PACKDATA" + DYNAMIC_XPCOM_LIBS='-L$(LIBXUL_DIST)/lib $(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xpcom_core.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + LIBXUL_LIBS='-L$(LIBXUL_DIST)/lib $(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xul.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + TARGET_MD_ARCH=os2 + _PLATFORM_DEFAULT_TOOLKIT="cairo-os2" + RC=rc.exe + RCFLAGS='-n' + MOZ_USER_DIR="Mozilla" + + if test "$MOZTOOLS"; then + MOZ_TOOLS_DIR=`echo $MOZTOOLS | sed -e 's|\\\\|/|g'` + else + { echo "configure: error: MOZTOOLS is not set" 1>&2; exit 1; } + fi + if test -n "$MOZ_OS2_HIGH_MEMORY"; then + DSO_LDOPTS="$DSO_LDOPTS -Zhigh-mem" + LDFLAGS="$LDFLAGS -Zhigh-mem" + MOZ_OPTIMIZE_LDFLAGS="$MOZ_OPTIMIZE_LDFLAGS -Zhigh-mem" + cat >> confdefs.h <<\EOF +#define MOZ_OS2_HIGH_MEMORY 1 +EOF + + fi + + # GCC for OS/2 currently predefines these, but we don't want them + _DEFINES_CFLAGS="$_DEFINES_CFLAGS -Uunix -U__unix -U__unix__" + _DEFINES_CXXFLAGS="$_DEFINES_CXXFLAGS -Uunix -U__unix -U__unix__" + + echo $ac_n "checking for __declspec(dllexport)""... $ac_c" 1>&6 +echo "configure:7496: checking for __declspec(dllexport)" >&5 +if eval "test \"`echo '$''{'ac_os2_declspec'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_os2_declspec="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_os2_declspec="no" +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_os2_declspec" 1>&6 + if test "$ac_os2_declspec" != "yes"; then + { echo "configure: error: Compiler does not support __declspec(dllexport), install GCC-4.3.2 or newer" 1>&2; exit 1; } + fi + ;; + +alpha*-*-osf*) + if test "$GNU_CC"; then + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-soname,$@ -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-soname,$@ -o $@' + + else + MOZ_DEBUG_FLAGS='-g' + ASFLAGS='-I$(topsrcdir)/xpcom/reflect/xptcall/public -g' + CFLAGS="$CFLAGS -ieee" + CXXFLAGS="$CXXFLAGS "'-noexceptions -ieee -ptr $(DIST)/cxx_repository' + DSO_LDOPTS='-shared -msym -expect_unresolved \* -update_registry $(DIST)/so_locations' + DSO_CFLAGS= + DSO_PIC_CFLAGS= + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -soname $@ -o $@' + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -soname $@ -o $@' + MKSHLIB_FORCE_ALL='-all' + MKSHLIB_UNFORCE_ALL='-none' + cat >> confdefs.h <<\EOF +#define NSCAP_DISABLE_TEST_DONTQUERY_CASES 1 +EOF + + cat >> confdefs.h <<\EOF +#define NSCAP_DISABLE_DEBUG_PTR_TYPES 1 +EOF + + fi + if test -z "$GNU_CXX"; then + COMPAQ_CXX=1 + fi + cat >> confdefs.h <<\EOF +#define NEED_USLEEP_PROTOTYPE 1 +EOF + + ;; + +*-qnx*) + DIRENT_INO=d_stat.st_ino + cat >> confdefs.h <<\EOF +#define NSCAP_DISABLE_TEST_DONTQUERY_CASES 1 +EOF + + cat >> confdefs.h <<\EOF +#define NSCAP_DISABLE_DEBUG_PTR_TYPES 1 +EOF + + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + + if test "$no_x" = "yes"; then + _PLATFORM_DEFAULT_TOOLKIT='photon' + TK_CFLAGS='-I/usr/nto/include/photon' + TK_LIBS='-lphoton -lphrender' + fi + ;; + +*-sco*) + cat >> confdefs.h <<\EOF +#define NSCAP_DISABLE_TEST_DONTQUERY_CASES 1 +EOF + + cat >> confdefs.h <<\EOF +#define NSCAP_DISABLE_DEBUG_PTR_TYPES 1 +EOF + + CXXFLAGS="$CXXFLAGS -I/usr/include/CC" + if test ! "$GNU_CC"; then + DSO_LDOPTS='-G' + fi + ;; + +*-solaris*) + cat >> confdefs.h <<\EOF +#define SOLARIS 1 +EOF + + TARGET_NSPR_MDCPUCFG='\"md/_solaris.cfg\"' + if test -z "$CROSS_COMPILE" && pkginfo -q SUNWpr && pkginfo -q SUNWprd; then + NO_NSPR_CONFIG_SYSTEM_LDFLAGS="-L/usr/lib/mps -R/usr/lib/mps -lnspr4" + NO_NSPR_CONFIG_SYSTEM_CFLAGS="-I/usr/include/mps" + NO_NSPR_CONFIG_SYSTEM_VERSION="`pkgparam SUNWpr SUNW_PRODVERS | sed -e 's/^[1-9][0-9]*\.[0-9][0-9]*$/&.0/'`" + fi + SYSTEM_MAKEDEPEND= + MOZ_FIX_LINK_PATHS= + # $ORIGIN/.. is for shared libraries under components/ to locate shared + # libraries one level up (e.g. libnspr4.so) + if test "$SOLARIS_SUNPRO_CC"; then + LDFLAGS="$LDFLAGS -z ignore -R '\$\$ORIGIN:\$\$ORIGIN/..' -z lazyload -z combreloc -z muldefs" + LIBS="-lCrun -lCstd -lc $LIBS" + NS_USE_NATIVE=1 + cat >> confdefs.h <<\EOF +#define NSCAP_DISABLE_DEBUG_PTR_TYPES 1 +EOF + + CFLAGS="$CFLAGS -xlibmieee -xstrconst -xbuiltin=%all -D__FUNCTION__=__func__" + CXXFLAGS="$CXXFLAGS -xlibmieee -xbuiltin=%all -features=tmplife,tmplrefstatic,extensions -norunpath -D__FUNCTION__=__func__ -template=no%extdef" + _MOZ_EXCEPTIONS_FLAGS_ON='-features=except' + _MOZ_EXCEPTIONS_FLAGS_OFF='-features=no%except' + LDFLAGS="-xildoff $LDFLAGS" + if test -z "$CROSS_COMPILE" -a -f /usr/lib/ld/map.noexstk; then + _SAVE_LDFLAGS=$LDFLAGS + LDFLAGS="-M /usr/lib/ld/map.noexstk $LDFLAGS" + cat > conftest.$ac_ext < +int main() { +printf("Hello World\n"); +; return 0; } +EOF +if { (eval echo configure:7636: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + LDFLAGS=$_SAVE_LDFLAGS +fi +rm -f conftest* + fi + WARNINGS_AS_ERRORS='-Werror' + MOZ_OPTIMIZE_FLAGS="-xO4" + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_FLAGS) $(DSO_LDOPTS) -h $@ -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_FLAGS) $(DSO_LDOPTS) -h $@ -o $@' + MKSHLIB_FORCE_ALL='-z allextract' + MKSHLIB_UNFORCE_ALL='-z defaultextract' + DSO_LDOPTS='-G' + AR_LIST="$AR t" + AR_EXTRACT="$AR x" + AR_DELETE="$AR d" + AR='$(CXX) -xar' + AR_FLAGS='-o $@' + AS='/usr/ccs/bin/as' + ASFLAGS="$ASFLAGS -K PIC -L -P -D_ASM -D__STDC__=0" + AS_DASH_C_FLAG='' + TARGET_COMPILER_ABI="sunc" + CC_VERSION=`$CC -V 2>&1 | grep '^cc:' 2>/dev/null | $AWK -F\: '{ print $2 }'` + CXX_VERSION=`$CXX -V 2>&1 | grep '^CC:' 2>/dev/null | $AWK -F\: '{ print $2 }'` + echo $ac_n "checking for Sun C++ compiler version >= 5.9""... $ac_c" 1>&6 +echo "configure:7665: checking for Sun C++ compiler version >= 5.9" >&5 + + ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + _BAD_COMPILER= +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + _BAD_COMPILER=1 +fi +rm -f conftest* + if test -n "$_BAD_COMPILER"; then + _res="no" + { echo "configure: error: Sun C++ 5.9 (Sun Studio 12) or higher is required to build. Your compiler version is $CXX_VERSION ." 1>&2; exit 1; } + else + _res="yes" + fi + cat > conftest.$ac_ext <= 0x5100) + #error "Sun C++ 5.10 or above" + #endif +; return 0; } +EOF +if { (eval echo configure:7710: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + _ABOVE_SS12U1= +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + _ABOVE_SS12U1=1 +fi +rm -f conftest* + if test "$_ABOVE_SS12U1"; then + # disable xannotate + CXXFLAGS="$CXXFLAGS -xannotate=no" + fi + echo "$ac_t""$_res" 1>&6 + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + else + LDFLAGS="$LDFLAGS -Wl,-z,ignore -Wl,-R,'\$\$ORIGIN:\$\$ORIGIN/..' -Wl,-z,lazyload -Wl,-z,combreloc -Wl,-z,muldefs" + LIBS="-lc $LIBS" + MKSHLIB_FORCE_ALL='-Wl,-z -Wl,allextract' + MKSHLIB_UNFORCE_ALL='-Wl,-z -Wl,defaultextract' + ASFLAGS="$ASFLAGS -fPIC" + DSO_LDOPTS='-shared' + _WARNINGS_CFLAGS='' + _WARNINGS_CXXFLAGS='' + if test "$OS_RELEASE" = "5.3"; then + cat >> confdefs.h <<\EOF +#define MUST_UNDEF_HAVE_BOOLEAN_AFTER_INCLUDES 1 +EOF + + fi + fi + if test "$OS_RELEASE" = "5.5.1"; then + cat >> confdefs.h <<\EOF +#define NEED_USLEEP_PROTOTYPE 1 +EOF + + fi + ;; + +*-sunos*) + DSO_LDOPTS='-Bdynamic' + MKSHLIB='-$(LD) $(DSO_LDOPTS) -o $@' + MKCSHLIB='-$(LD) $(DSO_LDOPTS) -o $@' + cat >> confdefs.h <<\EOF +#define SUNOS4 1 +EOF + + cat >> confdefs.h <<\EOF +#define SPRINTF_RETURNS_STRING 1 +EOF + + case "$(target_os)" in + sunos4.1*) + DLL_SUFFIX='.so.1.0' + ;; + esac + ;; + +*-sysv4.2uw7*) + NSPR_LIBS="-lnspr$NSPR_VERSION -lplc$NSPR_VERSION -lplds$NSPR_VERSION -L/usr/ccs/lib -lcrt" + ;; + +*-os2*) + HOST_NSPR_MDCPUCFG='\"md/_os2.cfg\"' + ;; + +*-android*) + cat >> confdefs.h <<\EOF +#define NO_PW_GECOS 1 +EOF + + no_x=yes + _PLATFORM_DEFAULT_TOOLKIT=cairo-android + TARGET_NSPR_MDCPUCFG='\"md/_linux.cfg\"' + + MOZ_GFX_OPTIMIZE_MOBILE=1 + # If we're building with --enable-profiling, we need a frame pointer. + if test -z "$MOZ_PROFILING"; then + MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fomit-frame-pointer" + else + MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fno-omit-frame-pointer" + fi + # The Maemo builders don't know about this flag + MOZ_ARM_VFP_FLAGS="-mfpu=vfp" + ;; + +esac + +cat >> confdefs.h <> confdefs.h <<\EOF +#define JS_CPU_X86 1 +EOF + + cat >> confdefs.h <<\EOF +#define JS_NUNBOX32 1 +EOF + + ;; +x86_64*-*) + ENABLE_TRACEJIT=1 + NANOJIT_ARCH=X64 + ENABLE_METHODJIT=1 + ENABLE_MONOIC=1 + ENABLE_POLYIC=1 + ENABLE_POLYIC_TYPED_ARRAY=1 + cat >> confdefs.h <<\EOF +#define JS_CPU_X64 1 +EOF + + cat >> confdefs.h <<\EOF +#define JS_PUNBOX64 1 +EOF + + ;; +arm*-*) + ENABLE_TRACEJIT=1 + NANOJIT_ARCH=ARM + ENABLE_METHODJIT=1 + ENABLE_MONOIC=1 + ENABLE_POLYIC=1 + cat >> confdefs.h <<\EOF +#define JS_CPU_ARM 1 +EOF + + cat >> confdefs.h <<\EOF +#define JS_NUNBOX32 1 +EOF + + ;; +sparc*-*) + ENABLE_TRACEJIT=1 + NANOJIT_ARCH=Sparc + cat >> confdefs.h <<\EOF +#define JS_CPU_SPARC 1 +EOF + + ;; +esac + +# Check whether --enable-methodjit or --disable-methodjit was given. +if test "${enable_methodjit+set}" = set; then + enableval="$enable_methodjit" + if test "$enableval" = "no"; then + ENABLE_METHODJIT= + elif test "$enableval" = "yes"; then + : + else + { echo "configure: error: Option, methodjit, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +# Check whether --enable-monoic or --disable-monoic was given. +if test "${enable_monoic+set}" = set; then + enableval="$enable_monoic" + if test "$enableval" = "no"; then + ENABLE_MONOIC= + elif test "$enableval" = "yes"; then + : + else + { echo "configure: error: Option, monoic, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +# Check whether --enable-polyic or --disable-polyic was given. +if test "${enable_polyic+set}" = set; then + enableval="$enable_polyic" + if test "$enableval" = "no"; then + ENABLE_POLYIC= + elif test "$enableval" = "yes"; then + : + else + { echo "configure: error: Option, polyic, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +# Check whether --enable-tracejit or --disable-tracejit was given. +if test "${enable_tracejit+set}" = set; then + enableval="$enable_tracejit" + if test "$enableval" = "no"; then + ENABLE_TRACEJIT= + elif test "$enableval" = "yes"; then + : + else + { echo "configure: error: Option, tracejit, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +# Check whether --enable-methodjit-spew or --disable-methodjit-spew was given. +if test "${enable_methodjit_spew+set}" = set; then + enableval="$enable_methodjit_spew" + if test "$enableval" = "yes"; then + ENABLE_METHODJIT_SPEW=1 + elif test "$enableval" = "no"; then + ENABLE_METHODJIT_SPEW= + else + { echo "configure: error: Option, methodjit-spew, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + + + +if test "$ENABLE_METHODJIT"; then + cat >> confdefs.h <<\EOF +#define JS_METHODJIT 1 +EOF + +fi + +if test "$ENABLE_MONOIC"; then + cat >> confdefs.h <<\EOF +#define JS_MONOIC 1 +EOF + +fi + +if test "$ENABLE_POLYIC"; then + cat >> confdefs.h <<\EOF +#define JS_POLYIC 1 +EOF + +fi + +if test "$ENABLE_POLYIC_TYPED_ARRAY"; then + cat >> confdefs.h <<\EOF +#define JS_POLYIC_TYPED_ARRAY 1 +EOF + +fi + +if test "$ENABLE_METHODJIT_SPEW"; then + cat >> confdefs.h <<\EOF +#define JS_METHODJIT_SPEW 1 +EOF + +fi + +if test "$ENABLE_TRACEJIT"; then + +cat >> confdefs.h <<\EOF +#define FEATURE_NANOJIT 1 +EOF + +cat >> confdefs.h <<\EOF +#define JS_TRACER 1 +EOF + + +case "$target" in +i?86-*) + cat >> confdefs.h <<\EOF +#define AVMPLUS_IA32 1 +EOF + + ;; +x86_64*-*) + cat >> confdefs.h <<\EOF +#define AVMPLUS_AMD64 1 +EOF + + cat >> confdefs.h <<\EOF +#define AVMPLUS_64BIT 1 +EOF + + ;; +arm*-*) + cat >> confdefs.h <<\EOF +#define AVMPLUS_ARM 1 +EOF + + ;; +sparc-*) + cat >> confdefs.h <<\EOF +#define AVMPLUS_SPARC 1 +EOF + + ;; +esac + +case "$target" in +*-linux*|*-android-eabi) + cat >> confdefs.h <<\EOF +#define AVMPLUS_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define AVMPLUS_LINUX 1 +EOF + + ;; +*-darwin*) + cat >> confdefs.h <<\EOF +#define AVMPLUS_UNIX 1 +EOF + + ;; +*-solaris*) + cat >> confdefs.h <<\EOF +#define AVMPLUS_UNIX 1 +EOF + + ;; +*-freebsd*|*-kfreebsd*) + cat >> confdefs.h <<\EOF +#define AVMPLUS_UNIX 1 +EOF + + ;; +*-gnu*) + cat >> confdefs.h <<\EOF +#define AVMPLUS_UNIX 1 +EOF + + ;; +*-cygwin*|*-mingw*|*-mks*|*-msvc*|*-wince|*-winmo) + cat >> confdefs.h <<\EOF +#define AVMPLUS_WIN32 1 +EOF + + ;; +*-os2*) + cat >> confdefs.h <<\EOF +#define AVMPLUS_OS2 1 +EOF + + ;; +*) + { echo "configure: error: Unrecognized nanojit platform. Use --disable-tracejit to build without tracing JIT support." 1>&2; exit 1; } +esac + +fi # ENABLE_TRACEJIT + + + + +if test -z "$SKIP_COMPILER_CHECKS"; then +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:8126: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +#include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:8139: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:8206: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:8230: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:8284: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for mode_t""... $ac_c" 1>&6 +echo "configure:8305: checking for mode_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])mode_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_mode_t=yes +else + rm -rf conftest* + ac_cv_type_mode_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_mode_t" 1>&6 +if test $ac_cv_type_mode_t = no; then + cat >> confdefs.h <<\EOF +#define mode_t int +EOF + +fi + +echo $ac_n "checking for off_t""... $ac_c" 1>&6 +echo "configure:8338: checking for off_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_off_t=yes +else + rm -rf conftest* + ac_cv_type_off_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_off_t" 1>&6 +if test $ac_cv_type_off_t = no; then + cat >> confdefs.h <<\EOF +#define off_t long +EOF + +fi + +echo $ac_n "checking for pid_t""... $ac_c" 1>&6 +echo "configure:8371: checking for pid_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_pid_t=yes +else + rm -rf conftest* + ac_cv_type_pid_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_pid_t" 1>&6 +if test $ac_cv_type_pid_t = no; then + cat >> confdefs.h <<\EOF +#define pid_t int +EOF + +fi + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:8404: checking for size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_size_t=yes +else + rm -rf conftest* + ac_cv_type_size_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_size_t" 1>&6 +if test $ac_cv_type_size_t = no; then + cat >> confdefs.h <<\EOF +#define size_t unsigned +EOF + +fi + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + +echo $ac_n "checking for __stdcall""... $ac_c" 1>&6 +echo "configure:8444: checking for __stdcall" >&5 +if eval "test \"`echo '$''{'ac_cv___stdcall'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < struct foo; + template <> struct foo {}; + template <> struct foo {}; +int main() { + +; return 0; } +EOF +if { (eval echo configure:8458: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv___stdcall=true +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv___stdcall=false +fi +rm -f conftest* +fi + +if test "$ac_cv___stdcall" = true ; then + cat >> confdefs.h <<\EOF +#define HAVE_STDCALL 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking for ssize_t""... $ac_c" 1>&6 +echo "configure:8487: checking for ssize_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_ssize_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + #include +int main() { +ssize_t foo = 0; +; return 0; } +EOF +if { (eval echo configure:8500: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_type_ssize_t=true +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_type_ssize_t=false +fi +rm -f conftest* +fi + +if test "$ac_cv_type_ssize_t" = true ; then + cat >> confdefs.h <<\EOF +#define HAVE_SSIZE_T 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +echo $ac_n "checking for st_blksize in struct stat""... $ac_c" 1>&6 +echo "configure:8522: checking for st_blksize in struct stat" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_st_blksize'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +struct stat s; s.st_blksize; +; return 0; } +EOF +if { (eval echo configure:8535: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_st_blksize=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_st_blksize=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_st_blksize" 1>&6 +if test $ac_cv_struct_st_blksize = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ST_BLKSIZE 1 +EOF + +fi + +echo $ac_n "checking for siginfo_t""... $ac_c" 1>&6 +echo "configure:8556: checking for siginfo_t" >&5 +if eval "test \"`echo '$''{'ac_cv_siginfo_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +siginfo_t* info; +; return 0; } +EOF +if { (eval echo configure:8569: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_siginfo_t=true +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_siginfo_t=false +fi +rm -f conftest* +fi + +if test "$ac_cv_siginfo_t" = true ; then + cat >> confdefs.h <<\EOF +#define HAVE_SIGINFO_T 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +ac_safe=`echo "stdint.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for stdint.h""... $ac_c" 1>&6 +echo "configure:8594: checking for stdint.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:8604: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + +if test "$ac_cv_header_stdint_h" = yes; then + cat >> confdefs.h <<\EOF +#define JS_HAVE_STDINT_H 1 +EOF + +else + +echo $ac_n "checking for a 1-byte type""... $ac_c" 1>&6 +echo "configure:8633: checking for a 1-byte type" >&5 +if eval "test \"`echo '$''{'moz_cv_n_byte_type_JS_INT8_TYPE'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + moz_cv_n_byte_type_JS_INT8_TYPE= + for type in char; do + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + moz_cv_n_byte_type_JS_INT8_TYPE=$type; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* + done + if test ! "$moz_cv_n_byte_type_JS_INT8_TYPE"; then + { echo "configure: error: Couldn't find a 1-byte type" 1>&2; exit 1; } + fi + +fi + +echo "$ac_t""$moz_cv_n_byte_type_JS_INT8_TYPE" 1>&6 +cat >> confdefs.h <&6 +echo "configure:8674: checking for a 2-byte type" >&5 +if eval "test \"`echo '$''{'moz_cv_n_byte_type_JS_INT16_TYPE'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + moz_cv_n_byte_type_JS_INT16_TYPE= + for type in short int long; do + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + moz_cv_n_byte_type_JS_INT16_TYPE=$type; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* + done + if test ! "$moz_cv_n_byte_type_JS_INT16_TYPE"; then + { echo "configure: error: Couldn't find a 2-byte type" 1>&2; exit 1; } + fi + +fi + +echo "$ac_t""$moz_cv_n_byte_type_JS_INT16_TYPE" 1>&6 +cat >> confdefs.h <&6 +echo "configure:8715: checking for a 4-byte type" >&5 +if eval "test \"`echo '$''{'moz_cv_n_byte_type_JS_INT32_TYPE'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + moz_cv_n_byte_type_JS_INT32_TYPE= + for type in int long 'long long' short; do + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + moz_cv_n_byte_type_JS_INT32_TYPE=$type; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* + done + if test ! "$moz_cv_n_byte_type_JS_INT32_TYPE"; then + { echo "configure: error: Couldn't find a 4-byte type" 1>&2; exit 1; } + fi + +fi + +echo "$ac_t""$moz_cv_n_byte_type_JS_INT32_TYPE" 1>&6 +cat >> confdefs.h <&6 +echo "configure:8756: checking for a 8-byte type" >&5 +if eval "test \"`echo '$''{'moz_cv_n_byte_type_JS_INT64_TYPE'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + moz_cv_n_byte_type_JS_INT64_TYPE= + for type in int long 'long long'; do + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + moz_cv_n_byte_type_JS_INT64_TYPE=$type; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* + done + if test ! "$moz_cv_n_byte_type_JS_INT64_TYPE"; then + { echo "configure: error: Couldn't find a 8-byte type" 1>&2; exit 1; } + fi + +fi + +echo "$ac_t""$moz_cv_n_byte_type_JS_INT64_TYPE" 1>&6 +cat >> confdefs.h <&6 +echo "configure:8797: checking for a sizeof (void *)-byte type" >&5 +if eval "test \"`echo '$''{'moz_cv_n_byte_type_JS_INTPTR_TYPE'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + moz_cv_n_byte_type_JS_INTPTR_TYPE= + for type in int long 'long long' short; do + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + moz_cv_n_byte_type_JS_INTPTR_TYPE=$type; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* + done + if test ! "$moz_cv_n_byte_type_JS_INTPTR_TYPE"; then + { echo "configure: error: Couldn't find a sizeof (void *)-byte type" 1>&2; exit 1; } + fi + +fi + +echo "$ac_t""$moz_cv_n_byte_type_JS_INTPTR_TYPE" 1>&6 +cat >> confdefs.h <&6 +echo "configure:8840: checking for the size of void*" >&5 +if eval "test \"`echo '$''{'moz_cv_size_of_JS_BYTES_PER_WORD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + moz_cv_size_of_JS_BYTES_PER_WORD= + for size in 4 8; do + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + moz_cv_size_of_JS_BYTES_PER_WORD=$size; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* + done + if test ! "$moz_cv_size_of_JS_BYTES_PER_WORD"; then + { echo "configure: error: No size found for void*" 1>&2; exit 1; } + fi + +fi + +echo "$ac_t""$moz_cv_size_of_JS_BYTES_PER_WORD" 1>&6 +cat >> confdefs.h <> confdefs.h <<\EOF +#define JS_BITS_PER_WORD_LOG2 5 +EOF + +elif test "$moz_cv_size_of_JS_BYTES_PER_WORD" -eq "8"; then + cat >> confdefs.h <<\EOF +#define JS_BITS_PER_WORD_LOG2 6 +EOF + +else + { echo "configure: error: Unexpected JS_BYTES_PER_WORD" 1>&2; exit 1; } +fi + + +echo $ac_n "checking for the alignment of void*""... $ac_c" 1>&6 +echo "configure:8895: checking for the alignment of void*" >&5 +if eval "test \"`echo '$''{'moz_cv_align_of_JS_ALIGN_OF_POINTER'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + moz_cv_align_of_JS_ALIGN_OF_POINTER= + for align in 2 4 8 16; do + cat > conftest.$ac_ext < + struct aligner { char c; void* a; }; + +int main() { + + int a[offsetof(struct aligner, a) == $align ? 1 : -1]; + return 0; + +; return 0; } +EOF +if { (eval echo configure:8916: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + moz_cv_align_of_JS_ALIGN_OF_POINTER=$align; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* + done + if test ! "$moz_cv_align_of_JS_ALIGN_OF_POINTER"; then + { echo "configure: error: No alignment found for void*" 1>&2; exit 1; } + fi + +fi + +echo "$ac_t""$moz_cv_align_of_JS_ALIGN_OF_POINTER" 1>&6 +cat >> confdefs.h <&6 +echo "configure:8939: checking for the size of double" >&5 +if eval "test \"`echo '$''{'moz_cv_size_of_JS_BYTES_PER_DOUBLE'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + moz_cv_size_of_JS_BYTES_PER_DOUBLE= + for size in 6 8 10 12 14; do + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + moz_cv_size_of_JS_BYTES_PER_DOUBLE=$size; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* + done + if test ! "$moz_cv_size_of_JS_BYTES_PER_DOUBLE"; then + { echo "configure: error: No size found for double" 1>&2; exit 1; } + fi + +fi + +echo "$ac_t""$moz_cv_size_of_JS_BYTES_PER_DOUBLE" 1>&6 +cat >> confdefs.h <&6 +echo "configure:8980: checking for int16_t" >&5 +if eval "test \"`echo '$''{'ac_cv_int16_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + #include +int main() { +int16_t foo = 0; +; return 0; } +EOF +if { (eval echo configure:8993: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_int16_t=true +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_int16_t=false +fi +rm -f conftest* +fi + +if test "$ac_cv_int16_t" = true ; then + cat >> confdefs.h <<\EOF +#define HAVE_INT16_T 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +echo $ac_n "checking for int32_t""... $ac_c" 1>&6 +echo "configure:9015: checking for int32_t" >&5 +if eval "test \"`echo '$''{'ac_cv_int32_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + #include +int main() { +int32_t foo = 0; +; return 0; } +EOF +if { (eval echo configure:9028: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_int32_t=true +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_int32_t=false +fi +rm -f conftest* +fi + +if test "$ac_cv_int32_t" = true ; then + cat >> confdefs.h <<\EOF +#define HAVE_INT32_T 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +echo $ac_n "checking for int64_t""... $ac_c" 1>&6 +echo "configure:9050: checking for int64_t" >&5 +if eval "test \"`echo '$''{'ac_cv_int64_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + #include +int main() { +int64_t foo = 0; +; return 0; } +EOF +if { (eval echo configure:9063: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_int64_t=true +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_int64_t=false +fi +rm -f conftest* +fi + +if test "$ac_cv_int64_t" = true ; then + cat >> confdefs.h <<\EOF +#define HAVE_INT64_T 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +echo $ac_n "checking for int64""... $ac_c" 1>&6 +echo "configure:9085: checking for int64" >&5 +if eval "test \"`echo '$''{'ac_cv_int64'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + #include +int main() { +int64 foo = 0; +; return 0; } +EOF +if { (eval echo configure:9098: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_int64=true +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_int64=false +fi +rm -f conftest* +fi + +if test "$ac_cv_int64" = true ; then + cat >> confdefs.h <<\EOF +#define HAVE_INT64 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +echo $ac_n "checking for uint""... $ac_c" 1>&6 +echo "configure:9120: checking for uint" >&5 +if eval "test \"`echo '$''{'ac_cv_uint'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + #include +int main() { +uint foo = 0; +; return 0; } +EOF +if { (eval echo configure:9133: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_uint=true +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_uint=false +fi +rm -f conftest* +fi + +if test "$ac_cv_uint" = true ; then + cat >> confdefs.h <<\EOF +#define HAVE_UINT 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +echo $ac_n "checking for uint_t""... $ac_c" 1>&6 +echo "configure:9155: checking for uint_t" >&5 +if eval "test \"`echo '$''{'ac_cv_uint_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + #include +int main() { +uint_t foo = 0; +; return 0; } +EOF +if { (eval echo configure:9168: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_uint_t=true +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_uint_t=false +fi +rm -f conftest* +fi + +if test "$ac_cv_uint_t" = true ; then + cat >> confdefs.h <<\EOF +#define HAVE_UINT_T 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +echo $ac_n "checking for uint16_t""... $ac_c" 1>&6 +echo "configure:9190: checking for uint16_t" >&5 +if eval "test \"`echo '$''{'ac_cv_uint16_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + #include +int main() { +uint16_t foo = 0; +; return 0; } +EOF +if { (eval echo configure:9203: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_uint16_t=true +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_uint16_t=false +fi +rm -f conftest* +fi + +if test "$ac_cv_uint16_t" = true ; then + cat >> confdefs.h <<\EOF +#define HAVE_UINT16_T 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + +echo $ac_n "checking for uname.domainname""... $ac_c" 1>&6 +echo "configure:9234: checking for uname.domainname" >&5 +if eval "test \"`echo '$''{'ac_cv_have_uname_domainname_field'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { + struct utsname *res; char *domain; + (void)uname(res); if (res != 0) { domain = res->domainname; } +; return 0; } +EOF +if { (eval echo configure:9247: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_have_uname_domainname_field=true +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_have_uname_domainname_field=false +fi +rm -f conftest* +fi + + +if test "$ac_cv_have_uname_domainname_field" = "true"; then + cat >> confdefs.h <<\EOF +#define HAVE_UNAME_DOMAINNAME_FIELD 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking for uname.__domainname""... $ac_c" 1>&6 +echo "configure:9271: checking for uname.__domainname" >&5 +if eval "test \"`echo '$''{'ac_cv_have_uname_us_domainname_field'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { + struct utsname *res; char *domain; + (void)uname(res); if (res != 0) { domain = res->__domainname; } +; return 0; } +EOF +if { (eval echo configure:9284: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_have_uname_us_domainname_field=true +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_have_uname_us_domainname_field=false +fi +rm -f conftest* +fi + + +if test "$ac_cv_have_uname_us_domainname_field" = "true"; then + cat >> confdefs.h <<\EOF +#define HAVE_UNAME_US_DOMAINNAME_FIELD 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + +if test "$GNU_CC"; then + echo $ac_n "checking for visibility(hidden) attribute""... $ac_c" 1>&6 +echo "configure:9317: checking for visibility(hidden) attribute" >&5 +if eval "test \"`echo '$''{'ac_cv_visibility_hidden'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c </dev/null 2>&1; then + if egrep '\.(hidden|private_extern).*foo' conftest.s >/dev/null; then + ac_cv_visibility_hidden=yes + fi + fi + rm -f conftest.cs + +fi + +echo "$ac_t""$ac_cv_visibility_hidden" 1>&6 + if test "$ac_cv_visibility_hidden" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_VISIBILITY_HIDDEN_ATTRIBUTE 1 +EOF + + + echo $ac_n "checking for visibility(default) attribute""... $ac_c" 1>&6 +echo "configure:9342: checking for visibility(default) attribute" >&5 +if eval "test \"`echo '$''{'ac_cv_visibility_default'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c </dev/null 2>&1; then + if ! egrep '\.(hidden|private_extern).*foo' conftest.s >/dev/null; then + ac_cv_visibility_default=yes + fi + fi + rm -f conftest.cs + +fi + +echo "$ac_t""$ac_cv_visibility_default" 1>&6 + if test "$ac_cv_visibility_default" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_VISIBILITY_ATTRIBUTE 1 +EOF + + + echo $ac_n "checking for visibility pragma support""... $ac_c" 1>&6 +echo "configure:9367: checking for visibility pragma support" >&5 +if eval "test \"`echo '$''{'ac_cv_visibility_pragma'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c </dev/null 2>&1; then + if egrep '\.(hidden|private_extern).*foo_hidden' conftest.s >/dev/null; then + if ! egrep '\.(hidden|private_extern).*foo_default' conftest.s > /dev/null; then + ac_cv_visibility_pragma=yes + fi + fi + fi + rm -f conftest.cs + +fi + +echo "$ac_t""$ac_cv_visibility_pragma" 1>&6 + if test "$ac_cv_visibility_pragma" = "yes"; then + echo $ac_n "checking For gcc visibility bug with class-level attributes (GCC bug 26905)""... $ac_c" 1>&6 +echo "configure:9392: checking For gcc visibility bug with class-level attributes (GCC bug 26905)" >&5 +if eval "test \"`echo '$''{'ac_cv_have_visibility_class_bug'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c < /dev/null 2>&1 ; then + ac_cv_have_visibility_class_bug=yes + else + if test `egrep -c '@PLT|\\$stub' conftest.S` = 0; then + ac_cv_have_visibility_class_bug=yes + fi + fi + rm -rf conftest.{c,S} + +fi + +echo "$ac_t""$ac_cv_have_visibility_class_bug" 1>&6 + + echo $ac_n "checking For x86_64 gcc visibility bug with builtins (GCC bug 20297)""... $ac_c" 1>&6 +echo "configure:9420: checking For x86_64 gcc visibility bug with builtins (GCC bug 20297)" >&5 +if eval "test \"`echo '$''{'ac_cv_have_visibility_builtin_bug'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c < +#pragma GCC visibility pop + +__attribute__ ((visibility ("default"))) void Func() { + char c[100]; + memset(c, 0, sizeof(c)); +} +EOF + ac_cv_have_visibility_builtin_bug=no + if ! ${CC-cc} ${CFLAGS} ${DSO_PIC_CFLAGS} ${DSO_LDOPTS} -O2 -S -o conftest.S conftest.c > /dev/null 2>&1 ; then + ac_cv_have_visibility_builtin_bug=yes + else + if test `grep -c "@PLT" conftest.S` = 0; then + ac_cv_visibility_builtin_bug=yes + fi + fi + rm -f conftest.{c,S} + +fi + +echo "$ac_t""$ac_cv_have_visibility_builtin_bug" 1>&6 + if test "$ac_cv_have_visibility_builtin_bug" = "no" -a \ + "$ac_cv_have_visibility_class_bug" = "no"; then + VISIBILITY_FLAGS='-I$(DIST)/system_wrappers_js -include $(topsrcdir)/config/gcc_hidden.h' + WRAP_SYSTEM_INCLUDES=1 + STL_FLAGS='-I$(DIST)/stl_wrappers' + WRAP_STL_INCLUDES=1 + else + VISIBILITY_FLAGS='-fvisibility=hidden' + fi # have visibility pragma bug + fi # have visibility pragma + fi # have visibility(default) attribute + fi # have visibility(hidden) attribute +fi # GNU_CC + +# visibility hidden flag for Sun Studio on Solaris +if test "$SOLARIS_SUNPRO_CC"; then +VISIBILITY_FLAGS='-xldscope=hidden' +fi # Sun Studio on Solaris + + + + +if test "$GNU_CC"; then + CFLAGS_save="${CFLAGS}" + CFLAGS="${CFLAGS} -Werror" + echo $ac_n "checking for __force_align_arg_pointer__ attribute""... $ac_c" 1>&6 +echo "configure:9474: checking for __force_align_arg_pointer__ attribute" >&5 +if eval "test \"`echo '$''{'ac_cv_force_align_arg_pointer'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_force_align_arg_pointer="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_force_align_arg_pointer="no" +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_force_align_arg_pointer" 1>&6 + CFLAGS="${CFLAGS_save}" + if test "$ac_cv_force_align_arg_pointer" = "yes"; then + HAVE_GCC_ALIGN_ARG_POINTER=1 + else + HAVE_GCC_ALIGN_ARG_POINTER= + fi +fi + + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 +echo "configure:9513: checking for $ac_hdr that defines DIR" >&5 +if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include <$ac_hdr> +int main() { +DIR *dirp = 0; +; return 0; } +EOF +if { (eval echo configure:9526: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then +echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 +echo "configure:9551: checking for opendir in -ldir" >&5 +ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldir $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -ldir" +else + echo "$ac_t""no" 1>&6 +fi + +else +echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 +echo "configure:9592: checking for opendir in -lx" >&5 +ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lx $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -lx" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +case "$target_os" in +freebsd*) +# for stuff like -lXshm + CPPFLAGS="${CPPFLAGS} ${X_CFLAGS}" + ;; +esac +for ac_hdr in sys/byteorder.h compat.h getopt.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:9643: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:9653: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +for ac_hdr in sys/bitypes.h memory.h unistd.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:9683: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:9693: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +for ac_hdr in gnu/libc-version.h nl_types.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:9723: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:9733: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +for ac_hdr in malloc.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:9763: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:9773: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +for ac_hdr in X11/XKBlib.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:9803: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:9813: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +for ac_hdr in io.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:9843: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:9853: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + +for ac_hdr in sys/statvfs.h sys/statfs.h sys/vfs.h sys/mount.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:9884: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:9894: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + +for ac_hdr in sys/quota.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:9925: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:9935: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +for ac_hdr in linux/quota.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:9965: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:9975: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + +for ac_hdr in mmintrin.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:10006: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:10016: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + +NEW_H=new.h +ac_safe=`echo "new" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for new""... $ac_c" 1>&6 +echo "configure:10053: checking for new" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:10063: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + NEW_H=new +else + echo "$ac_t""no" 1>&6 +fi + +cat >> confdefs.h < +EOF + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + +# Check whether --enable-dtrace or --disable-dtrace was given. +if test "${enable_dtrace+set}" = set; then + enableval="$enable_dtrace" + enable_dtrace="yes" +fi + +if test "x$enable_dtrace" = "xyes"; then + ac_safe=`echo "sys/sdt.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for sys/sdt.h""... $ac_c" 1>&6 +echo "configure:10105: checking for sys/sdt.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:10115: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + HAVE_DTRACE=1 +else + echo "$ac_t""no" 1>&6 +fi + + if test -n "$HAVE_DTRACE"; then + cat >> confdefs.h <<\EOF +#define INCLUDE_MOZILLA_DTRACE 1 +EOF + + else + { echo "configure: error: dtrace enabled but sys/sdt.h not found" 1>&2; exit 1; }; + fi +fi + + +case $target in +*-aix4.3*|*-aix5*) + ;; +*) + for ac_hdr in sys/cdefs.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:10155: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:10165: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + ;; +esac + +ac_safe=`echo "linux/perf_event.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for linux/perf_event.h""... $ac_c" 1>&6 +echo "configure:10196: checking for linux/perf_event.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:10206: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + HAVE_LINUX_PERF_EVENT_H=1 +else + echo "$ac_t""no" 1>&6 +fi + + + +case $target in +*-hpux11.*) + ;; +*) + echo $ac_n "checking for gethostbyname_r in -lc_r""... $ac_c" 1>&6 +echo "configure:10234: checking for gethostbyname_r in -lc_r" >&5 +ac_lib_var=`echo c_r'_'gethostbyname_r | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lc_r $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo c_r | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <&6 +fi + + ;; +esac + +case $target in +*-darwin*) + ;; +*-beos*) + ;; +*-os2*) + ;; +*) + +echo $ac_n "checking for library containing dlopen""... $ac_c" 1>&6 +echo "configure:10293: checking for library containing dlopen" >&5 +if eval "test \"`echo '$''{'ac_cv_search_dlopen'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_func_search_save_LIBS="$LIBS" +ac_cv_search_dlopen="no" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_search_dlopen="none required" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +test "$ac_cv_search_dlopen" = "no" && for i in dl; do +LIBS="-l$i $ac_func_search_save_LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_search_dlopen="-l$i" +break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +done +LIBS="$ac_func_search_save_LIBS" +fi + +echo "$ac_t""$ac_cv_search_dlopen" 1>&6 +if test "$ac_cv_search_dlopen" != "no"; then + test "$ac_cv_search_dlopen" = "none required" || LIBS="$ac_cv_search_dlopen $LIBS" + ac_safe=`echo "dlfcn.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for dlfcn.h""... $ac_c" 1>&6 +echo "configure:10351: checking for dlfcn.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:10361: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_DLOPEN 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +else : + +fi + ;; +esac + +_SAVE_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -D_GNU_SOURCE" +for ac_func in dladdr +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:10396: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:10424: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + +CFLAGS="$_SAVE_CFLAGS" + +if test ! "$GNU_CXX"; then + + case $target in + *-aix*) + echo $ac_n "checking for demangle in -lC_r""... $ac_c" 1>&6 +echo "configure:10455: checking for demangle in -lC_r" >&5 +ac_lib_var=`echo C_r'_'demangle | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lC_r $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo C_r | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <&6 +fi + + ;; + *) + echo $ac_n "checking for demangle in -lC""... $ac_c" 1>&6 +echo "configure:10504: checking for demangle in -lC" >&5 +ac_lib_var=`echo C'_'demangle | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lC $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo C | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <&6 +fi + + ;; + esac +fi + +case $target in +*-os2*) + ;; +*) + echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6 +echo "configure:10559: checking for socket in -lsocket" >&5 +ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsocket $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <&6 +fi + +esac + +echo $ac_n "checking for ARM SIMD support in compiler""... $ac_c" 1>&6 +echo "configure:10608: checking for ARM SIMD support in compiler" >&5 +cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + result="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + result="no" +fi +rm -f conftest* +echo "$ac_t"""$result"" 1>&6 +if test "$result" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_ARM_SIMD 1 +EOF + + HAVE_ARM_SIMD=1 +fi + + +echo $ac_n "checking for ARM NEON support in compiler""... $ac_c" 1>&6 +echo "configure:10638: checking for ARM NEON support in compiler" >&5 +_SAVE_CFLAGS="$CFLAGS" +if test "$GNU_CC"; then + # gcc needs -mfpu=neon to recognize NEON instructions + CFLAGS="$CFLAGS -mfpu=neon -mfloat-abi=softfp" +fi +cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + result="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + result="no" +fi +rm -f conftest* +echo "$ac_t"""$result"" 1>&6 +if test "$result" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_ARM_NEON 1 +EOF + + HAVE_ARM_NEON=1 +fi +CFLAGS="$_SAVE_CFLAGS" + + +case "$target_os" in +darwin*) + USE_PTHREADS=1 + ;; +*) + +echo $ac_n "checking for pthread_create in -lpthreads""... $ac_c" 1>&6 +echo "configure:10680: checking for pthread_create in -lpthreads" >&5 +echo " + #include + #include + void *foo(void *v) { int a = 1; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + exit(0); + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lpthreads $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lpthreads $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + echo "$ac_t""yes" 1>&6 + USE_PTHREADS=1 _PTHREAD_LDFLAGS="-lpthreads" + else + echo "$ac_t""no" 1>&6 + +echo $ac_n "checking for pthread_create in -lpthread""... $ac_c" 1>&6 +echo "configure:10703: checking for pthread_create in -lpthread" >&5 +echo " + #include + #include + void *foo(void *v) { int a = 1; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + exit(0); + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lpthread $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lpthread $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + echo "$ac_t""yes" 1>&6 + USE_PTHREADS=1 _PTHREAD_LDFLAGS="-lpthread" + else + echo "$ac_t""no" 1>&6 + +echo $ac_n "checking for pthread_create in -lc_r""... $ac_c" 1>&6 +echo "configure:10726: checking for pthread_create in -lc_r" >&5 +echo " + #include + #include + void *foo(void *v) { int a = 1; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + exit(0); + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lc_r $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lc_r $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + echo "$ac_t""yes" 1>&6 + USE_PTHREADS=1 _PTHREAD_LDFLAGS="-lc_r" + else + echo "$ac_t""no" 1>&6 + +echo $ac_n "checking for pthread_create in -lc""... $ac_c" 1>&6 +echo "configure:10749: checking for pthread_create in -lc" >&5 +echo " + #include + #include + void *foo(void *v) { int a = 1; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + exit(0); + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lc $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lc $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + echo "$ac_t""yes" 1>&6 + USE_PTHREADS=1 + + else + echo "$ac_t""no" 1>&6 + + fi + + + fi + + + fi + + + fi + + ;; +esac + +# Check whether --with-pthreads or --without-pthreads was given. +if test "${with_pthreads+set}" = set; then + withval="$with_pthreads" + if test "$withval" = "yes"; then + if test "$USE_PTHREADS"x = x; then + { echo "configure: error: --with-pthreads specified for a system without pthread support " 1>&2; exit 1; }; +fi + elif test "$withval" = "no"; then + USE_PTHREADS= + _PTHREAD_LDFLAGS= + + else + { echo "configure: error: Option, pthreads, does not take an argument ($withval)." 1>&2; exit 1; } + fi +fi + + +if test "$USE_PTHREADS"x != x +then + rm -f conftest* + ac_cv_have_dash_pthread=no + echo $ac_n "checking whether ${CC-cc} accepts -pthread""... $ac_c" 1>&6 +echo "configure:10808: checking whether ${CC-cc} accepts -pthread" >&5 + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} -pthread -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out | grep pthread`" -a -z "`egrep -i '(error|incorrect)' conftest.out`" ; then + ac_cv_have_dash_pthread=yes + case "$target_os" in + freebsd*) +# Freebsd doesn't use -pthread for compiles, it uses them for linking + ;; + *) + CFLAGS="$CFLAGS -pthread" + CXXFLAGS="$CXXFLAGS -pthread" + ;; + esac + fi + fi + rm -f conftest* + echo "$ac_t""$ac_cv_have_dash_pthread" 1>&6 + + ac_cv_have_dash_pthreads=no + if test "$ac_cv_have_dash_pthread" = "no"; then + echo $ac_n "checking whether ${CC-cc} accepts -pthreads""... $ac_c" 1>&6 +echo "configure:10831: checking whether ${CC-cc} accepts -pthreads" >&5 + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} -pthreads -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out | grep pthreads`" -a -z "`egrep -i '(error|incorrect)' conftest.out`" ; then + ac_cv_have_dash_pthreads=yes + CFLAGS="$CFLAGS -pthreads" + CXXFLAGS="$CXXFLAGS -pthreads" + fi + fi + rm -f conftest* + echo "$ac_t""$ac_cv_have_dash_pthreads" 1>&6 + fi + + case "$target" in + *-*-freebsd*) + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + cat >> confdefs.h <<\EOF +#define _THREAD_SAFE 1 +EOF + + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS="-pthread" + else + _PTHREAD_LDFLAGS="-lc_r" + fi + ;; + + *-*-openbsd*|*-*-bsdi*) + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + cat >> confdefs.h <<\EOF +#define _THREAD_SAFE 1 +EOF + + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS="-pthread" + fi + ;; + + *-*-linux*|*-*-kfreebsd*-gnu|*-*-gnu*) + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + ;; + + *-*-nto*) + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + ;; + + *-aix4.3*|*-aix5*) + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + ;; + + *-hpux11.*) + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + ;; + + alpha*-*-osf*) + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + ;; + + *-*-solaris*) + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + if test "$SOLARIS_SUNPRO_CC"; then + CFLAGS="$CFLAGS -mt" + CXXFLAGS="$CXXFLAGS -mt" + fi + ;; + esac + LDFLAGS="${_PTHREAD_LDFLAGS} ${LDFLAGS}" +fi + +echo $ac_n "checking whether mmap() sees write()s""... $ac_c" 1>&6 +echo "configure:10926: checking whether mmap() sees write()s" >&5 + + +mmap_test_prog=' + #include + #include + #include + #include + #include + #include + + char fname[] = "conftest.file"; + char zbuff[1024]; /* Fractional page is probably worst case */ + + int main() { + char *map; + int fd; + int i; + unlink(fname); + fd = open(fname, O_RDWR | O_CREAT, 0660); + if(fd<0) return 1; + unlink(fname); + write(fd, zbuff, sizeof(zbuff)); + lseek(fd, 0, SEEK_SET); + map = (char*)mmap(0, sizeof(zbuff), PROT_READ, MAP_SHARED, fd, 0); + if(map==(char*)-1) return 2; + for(i=0; fname[i]; i++) { + int rc = write(fd, &fname[i], 1); + if(map[i]!=fname[i]) return 4; + } + return 0; + } +' + + +if test "$cross_compiling" = yes; then + result="yes" +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + result="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + result="no" +fi +rm -fr conftest* +fi + + +echo "$ac_t"""$result"" 1>&6 + +if test "$result" = "no"; then + cat >> confdefs.h <<\EOF +#define MMAP_MISSES_WRITES 1 +EOF + +fi + + +if test $ac_cv_prog_gcc = yes; then + echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 +echo "configure:10994: checking whether ${CC-cc} needs -traditional" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_pattern="Autoconf.*'x'" + cat > conftest.$ac_ext < +Autoconf TIOCGETP +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +else + rm -rf conftest* + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat > conftest.$ac_ext < +Autoconf TCGETA +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi + +echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6 + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6 +echo "configure:11040: checking for 8-bit clean memcmp" >&5 +if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_memcmp_clean=no +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_memcmp_clean=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_memcmp_clean=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6 +test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" + +for ac_func in fchmod flockfile getc_unlocked _getc_nolock getpagesize \ + lchown localtime_r lstat64 memmove random rint sbrk snprintf \ + stat64 statvfs statvfs64 strerror strtok_r truncate64 +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:11080: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:11108: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +_SAVE_LDFLAGS=$LDFLAGS +LDFLAGS="$LDFLAGS -lrt" +echo $ac_n "checking for clock_gettime(CLOCK_MONOTONIC) and -lrt""... $ac_c" 1>&6 +echo "configure:11136: checking for clock_gettime(CLOCK_MONOTONIC) and -lrt" >&5 +if eval "test \"`echo '$''{'ac_cv_have_clock_monotonic'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); +; return 0; } +EOF +if { (eval echo configure:11149: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_have_clock_monotonic=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_have_clock_monotonic=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_have_clock_monotonic" 1>&6 +LDFLAGS=$_SAVE_LDFLAGS +if test "$ac_cv_have_clock_monotonic" = "yes"; then + HAVE_CLOCK_MONOTONIC=1 + REALTIME_LIBS=-lrt + cat >> confdefs.h <<\EOF +#define HAVE_CLOCK_MONOTONIC 1 +EOF + + + +fi + +cat > conftest.$ac_ext < +int main() { +SYSTEMTIME st;FILETIME ft;SystemTimeToFileTime(&st,&ft); +; return 0; } +EOF +if { (eval echo configure:11182: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_have_systemtimetofiletime="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_have_systemtimetofiletime="no" +fi +rm -f conftest* +if test "$ac_cv_have_systemtimetofiletime" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_SYSTEMTIMETOFILETIME 1 +EOF + +fi +cat > conftest.$ac_ext < +int main() { +FILETIME ft;GetSystemTimeAsFileTime(&ft); +; return 0; } +EOF +if { (eval echo configure:11206: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_have_getsystemtimeasfiletime="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_have_getsystemtimeasfiletime="no" +fi +rm -f conftest* +if test "$ac_cv_have_getsystemtimeasfiletime" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_GETSYSTEMTIMEASFILETIME 1 +EOF + +fi + +if test -z "$MACOS_DEPLOYMENT_TARGET" || test "$MACOS_DEPLOYMENT_TARGET" -ge "100300"; then + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + +echo $ac_n "checking for wcrtomb""... $ac_c" 1>&6 +echo "configure:11233: checking for wcrtomb" >&5 +if eval "test \"`echo '$''{'ac_cv_have_wcrtomb'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +mbstate_t ps={0};wcrtomb(0,'f',&ps); +; return 0; } +EOF +if { (eval echo configure:11245: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_have_wcrtomb="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_have_wcrtomb="no" +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_have_wcrtomb" 1>&6 +if test "$ac_cv_have_wcrtomb" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_WCRTOMB 1 +EOF + +fi +echo $ac_n "checking for mbrtowc""... $ac_c" 1>&6 +echo "configure:11265: checking for mbrtowc" >&5 +if eval "test \"`echo '$''{'ac_cv_have_mbrtowc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +mbstate_t ps={0};mbrtowc(0,0,0,&ps); +; return 0; } +EOF +if { (eval echo configure:11277: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_have_mbrtowc="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_have_mbrtowc="no" +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_have_mbrtowc" 1>&6 +if test "$ac_cv_have_mbrtowc" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_MBRTOWC 1 +EOF + +fi +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +fi + +echo $ac_n "checking for res_ninit()""... $ac_c" 1>&6 +echo "configure:11306: checking for res_ninit()" >&5 +if eval "test \"`echo '$''{'ac_cv_func_res_ninit'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + +int main() { +int foo = res_ninit(&_res); +; return 0; } +EOF +if { (eval echo configure:11323: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_func_res_ninit=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_func_res_ninit=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_func_res_ninit" 1>&6 + +if test "$ac_cv_func_res_ninit" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_RES_NINIT 1 +EOF + +fi + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + +echo $ac_n "checking for gnu_get_libc_version()""... $ac_c" 1>&6 +echo "configure:11353: checking for gnu_get_libc_version()" >&5 +if eval "test \"`echo '$''{'ac_cv_func_gnu_get_libc_version'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + #endif + +int main() { +const char *glibc_version = gnu_get_libc_version(); +; return 0; } +EOF +if { (eval echo configure:11369: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_func_gnu_get_libc_version=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_func_gnu_get_libc_version=no + +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_func_gnu_get_libc_version" 1>&6 + +if test "$ac_cv_func_gnu_get_libc_version" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_GNU_GET_LIBC_VERSION 1 +EOF + +fi + +case $target_os in + os2*|msvc*|mks*|cygwin*|mingw*|darwin*|wince*|winmo*|beos*) + ;; + *) + +echo $ac_n "checking for iconv in -lc""... $ac_c" 1>&6 +echo "configure:11398: checking for iconv in -lc" >&5 +ac_lib_var=`echo c'_'iconv | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lc $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + _ICONV_LIBS="$_ICONV_LIBS" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for iconv in -liconv""... $ac_c" 1>&6 +echo "configure:11439: checking for iconv in -liconv" >&5 +ac_lib_var=`echo iconv'_'iconv | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-liconv $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + _ICONV_LIBS="$_ICONV_LIBS -liconv" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for libiconv in -liconv""... $ac_c" 1>&6 +echo "configure:11480: checking for libiconv in -liconv" >&5 +ac_lib_var=`echo iconv'_'libiconv | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-liconv $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + _ICONV_LIBS="$_ICONV_LIBS -liconv" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +fi + +_SAVE_LIBS=$LIBS +LIBS="$LIBS $_ICONV_LIBS" +echo $ac_n "checking for iconv()""... $ac_c" 1>&6 +echo "configure:11529: checking for iconv()" >&5 +if eval "test \"`echo '$''{'ac_cv_func_iconv'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + #include + +int main() { + + iconv_t h = iconv_open("", ""); + iconv(h, NULL, NULL, NULL, NULL); + iconv_close(h); + +; return 0; } +EOF +if { (eval echo configure:11548: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_func_iconv=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_func_iconv=no + +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_func_iconv" 1>&6 +if test "$ac_cv_func_iconv" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_ICONV 1 +EOF + + DYNAMIC_XPCOM_LIBS="$DYNAMIC_XPCOM_LIBS $_ICONV_LIBS" + LIBXUL_LIBS="$LIBXUL_LIBS $_ICONV_LIBS" + LIBICONV="$_ICONV_LIBS" + echo $ac_n "checking for iconv() with const input""... $ac_c" 1>&6 +echo "configure:11572: checking for iconv() with const input" >&5 +if eval "test \"`echo '$''{'ac_cv_func_const_iconv'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + #include + +int main() { + + const char *input = "testing"; + iconv_t h = iconv_open("", ""); + iconv(h, &input, NULL, NULL, NULL); + iconv_close(h); + +; return 0; } +EOF +if { (eval echo configure:11592: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_func_const_iconv=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_func_const_iconv=no + +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_func_const_iconv" 1>&6 + if test "$ac_cv_func_const_iconv" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_ICONV_WITH_CONST_INPUT 1 +EOF + + fi +fi +LIBS=$_SAVE_LIBS + + ;; +esac + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + +echo $ac_n "checking for an implementation of va_copy()""... $ac_c" 1>&6 +echo "configure:11628: checking for an implementation of va_copy()" >&5 +if eval "test \"`echo '$''{'ac_cv_va_copy'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + if test "$cross_compiling" = yes; then + ac_cv_va_copy=no + +else + cat > conftest.$ac_ext < + void f (int i, ...) { + va_list args1, args2; + va_start (args1, i); + va_copy (args2, args1); + if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42) + exit (1); + va_end (args1); va_end (args2); + } + int main() { f (0, 42); return 0; } +EOF +if { (eval echo configure:11652: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_va_copy=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_va_copy=no +fi +rm -fr conftest* +fi + + +fi + +echo "$ac_t""$ac_cv_va_copy" 1>&6 +echo $ac_n "checking for an implementation of __va_copy()""... $ac_c" 1>&6 +echo "configure:11669: checking for an implementation of __va_copy()" >&5 +if eval "test \"`echo '$''{'ac_cv___va_copy'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + if test "$cross_compiling" = yes; then + ac_cv___va_copy=no + +else + cat > conftest.$ac_ext < + void f (int i, ...) { + va_list args1, args2; + va_start (args1, i); + __va_copy (args2, args1); + if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42) + exit (1); + va_end (args1); va_end (args2); + } + int main() { f (0, 42); return 0; } +EOF +if { (eval echo configure:11693: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv___va_copy=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv___va_copy=no +fi +rm -fr conftest* +fi + + +fi + +echo "$ac_t""$ac_cv___va_copy" 1>&6 +echo $ac_n "checking whether va_lists can be copied by value""... $ac_c" 1>&6 +echo "configure:11710: checking whether va_lists can be copied by value" >&5 +if eval "test \"`echo '$''{'ac_cv_va_val_copy'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + if test "$cross_compiling" = yes; then + ac_cv_va_val_copy=yes + +else + cat > conftest.$ac_ext < + void f (int i, ...) { + va_list args1, args2; + va_start (args1, i); + args2 = args1; + if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42) + exit (1); + va_end (args1); va_end (args2); + } + int main() { f (0, 42); return 0; } +EOF +if { (eval echo configure:11734: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_va_val_copy=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_va_val_copy=no +fi +rm -fr conftest* +fi + + +fi + +if test "x$ac_cv_va_copy" = "xyes"; then + cat >> confdefs.h <<\EOF +#define VA_COPY va_copy +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_VA_COPY 1 +EOF + +elif test "x$ac_cv___va_copy" = "xyes"; then + cat >> confdefs.h <<\EOF +#define VA_COPY __va_copy +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_VA_COPY 1 +EOF + +fi + +if test "x$ac_cv_va_val_copy" = "xno"; then + cat >> confdefs.h <<\EOF +#define HAVE_VA_LIST_AS_ARRAY 1 +EOF + +fi +echo "$ac_t""$ac_cv_va_val_copy" 1>&6 + +case "$target" in + *-linux*) + _curdir=`pwd` + export _curdir + rm -rf conftest* _conftest + mkdir _conftest + cat >> conftest.C <<\EOF +#include +#include +#include +#ifdef _dl_loaded +void __dump_link_map(void) { + struct link_map *map = _dl_loaded; + while (NULL != map) {printf("0x%08x %s\n", map->l_addr, map->l_name); map = map->l_next;} +} +int main() { + dlopen("./conftest1.so",RTLD_LAZY); + dlopen("./../_conftest/conftest1.so",RTLD_LAZY); + dlopen("CURDIR/_conftest/conftest1.so",RTLD_LAZY); + dlopen("CURDIR/_conftest/../_conftest/conftest1.so",RTLD_LAZY); + __dump_link_map(); +} +#else +/* _dl_loaded isn't defined, so this should be either a libc5 (glibc1) system, or a glibc2 system that doesn't have the multiple load bug (i.e., RH6.0).*/ +int main() { printf("./conftest1.so\n"); } +#endif +EOF + + $PERL -p -i -e "s/CURDIR/\$ENV{_curdir}/g;" conftest.C + + cat >> conftest1.C <<\EOF +#include +void foo(void) {printf("foo in dll called\n");} +EOF + ${CXX-g++} -fPIC -c -g conftest1.C + ${CXX-g++} -shared -Wl,-h -Wl,conftest1.so -o conftest1.so conftest1.o + ${CXX-g++} -g conftest.C -o conftest -ldl + cp -f conftest1.so conftest _conftest + cd _conftest + if test `./conftest | grep conftest1.so | wc -l` -gt 1 + then + echo + echo "*** Your libc has a bug that can result in loading the same dynamic" + echo "*** library multiple times. This bug is known to be fixed in glibc-2.0.7-32" + echo "*** or later. However, if you choose not to upgrade, the only effect" + echo "*** will be excessive memory usage at runtime." + echo + fi + cd ${_curdir} + rm -rf conftest* _conftest + ;; +esac + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + +ARM_ABI_PREFIX= +HAVE_GCC3_ABI= +if test "$GNU_CC"; then + if test "$CPU_ARCH" = "arm" ; then + echo $ac_n "checking for ARM EABI""... $ac_c" 1>&6 +echo "configure:11843: checking for ARM EABI" >&5 +if eval "test \"`echo '$''{'ac_cv_gcc_arm_eabi'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_gcc_arm_eabi="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_gcc_arm_eabi="no" +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_gcc_arm_eabi" 1>&6 + if test "$ac_cv_gcc_arm_eabi" = "yes"; then + HAVE_ARM_EABI=1 + ARM_ABI_PREFIX=eabi- + else + ARM_ABI_PREFIX=oabi- + fi + fi + + echo $ac_n "checking for gcc 3.0 ABI""... $ac_c" 1>&6 +echo "configure:11883: checking for gcc 3.0 ABI" >&5 +if eval "test \"`echo '$''{'ac_cv_gcc_three_abi'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <= 100 /* G++ V3 ABI */ + return 0; +#else +#error Not gcc3. +#endif + +; return 0; } +EOF +if { (eval echo configure:11901: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_gcc_three_abi="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_gcc_three_abi="no" +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_gcc_three_abi" 1>&6 + if test "$ac_cv_gcc_three_abi" = "yes"; then + TARGET_COMPILER_ABI="${TARGET_COMPILER_ABI-${ARM_ABI_PREFIX}gcc3}" + HAVE_GCC3_ABI=1 + else + TARGET_COMPILER_ABI="${TARGET_COMPILER_ABI-${ARM_ABI_PREFIX}gcc2}" + fi +fi + + + +echo $ac_n "checking for C++ \"explicit\" keyword""... $ac_c" 1>&6 +echo "configure:11925: checking for C++ \"explicit\" keyword" >&5 +if eval "test \"`echo '$''{'ac_cv_cpp_explicit'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_cpp_explicit=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_cpp_explicit=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_cpp_explicit" 1>&6 +if test "$ac_cv_cpp_explicit" = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_CPP_EXPLICIT 1 +EOF + +fi + +echo $ac_n "checking for C++ \"typename\" keyword""... $ac_c" 1>&6 +echo "configure:11961: checking for C++ \"typename\" keyword" >&5 +if eval "test \"`echo '$''{'ac_cv_cpp_typename'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < class tplt { + public: + typedef typename T::num_type t_num_type; + t_num_type foo(typename T::num_type num) { + return num; + } + }; +int main() { +tplt A; + A.foo(0); +; return 0; } +EOF +if { (eval echo configure:11985: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_cpp_typename=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_cpp_typename=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_cpp_typename" 1>&6 +if test "$ac_cv_cpp_typename" = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_CPP_TYPENAME 1 +EOF + +fi + +echo $ac_n "checking for modern C++ template specialization syntax support""... $ac_c" 1>&6 +echo "configure:12006: checking for modern C++ template specialization syntax support" >&5 +if eval "test \"`echo '$''{'ac_cv_cpp_modern_specialize_template_syntax'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < struct X { int a; }; + class Y {}; + template <> struct X { double a; }; +int main() { +X int_x; + X y_x; +; return 0; } +EOF +if { (eval echo configure:12021: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_cpp_modern_specialize_template_syntax=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_cpp_modern_specialize_template_syntax=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_cpp_modern_specialize_template_syntax" 1>&6 +if test "$ac_cv_cpp_modern_specialize_template_syntax" = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_CPP_MODERN_SPECIALIZE_TEMPLATE_SYNTAX 1 +EOF + +fi + + +echo $ac_n "checking whether partial template specialization works""... $ac_c" 1>&6 +echo "configure:12043: checking whether partial template specialization works" >&5 +if eval "test \"`echo '$''{'ac_cv_cpp_partial_specialization'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < class Foo {}; + template class Foo {}; +int main() { +return 0; +; return 0; } +EOF +if { (eval echo configure:12056: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_cpp_partial_specialization=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_cpp_partial_specialization=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_cpp_partial_specialization" 1>&6 +if test "$ac_cv_cpp_partial_specialization" = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_CPP_PARTIAL_SPECIALIZATION 1 +EOF + +fi + +echo $ac_n "checking whether operators must be re-defined for templates derived from templates""... $ac_c" 1>&6 +echo "configure:12077: checking whether operators must be re-defined for templates derived from templates" >&5 +if eval "test \"`echo '$''{'ac_cv_need_derived_template_operators'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < class Base { }; + template + Base operator+(const Base& lhs, const Base& rhs) { return lhs; } + template class Derived : public Base { }; +int main() { +Derived a, b; + Base c = a + b; + return 0; +; return 0; } +EOF +if { (eval echo configure:12094: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_need_derived_template_operators=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_need_derived_template_operators=yes +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_need_derived_template_operators" 1>&6 +if test "$ac_cv_need_derived_template_operators" = yes ; then + cat >> confdefs.h <<\EOF +#define NEED_CPP_DERIVED_TEMPLATE_OPERATORS 1 +EOF + +fi + + +echo $ac_n "checking whether we need to cast a derived template to pass as its base class""... $ac_c" 1>&6 +echo "configure:12116: checking whether we need to cast a derived template to pass as its base class" >&5 +if eval "test \"`echo '$''{'ac_cv_need_cpp_template_cast_to_base'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < class Base { }; + template class Derived : public Base { }; + template int foo(const Base&) { return 0; } +int main() { +Derived bar; return foo(bar); +; return 0; } +EOF +if { (eval echo configure:12130: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_need_cpp_template_cast_to_base=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_need_cpp_template_cast_to_base=yes +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_need_cpp_template_cast_to_base" 1>&6 +if test "$ac_cv_need_cpp_template_cast_to_base" = yes ; then + cat >> confdefs.h <<\EOF +#define NEED_CPP_TEMPLATE_CAST_TO_BASE 1 +EOF + +fi + +echo $ac_n "checking whether the compiler can resolve const ambiguities for templates""... $ac_c" 1>&6 +echo "configure:12151: checking whether the compiler can resolve const ambiguities for templates" >&5 +if eval "test \"`echo '$''{'ac_cv_can_resolve_const_ambiguity'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < class ptrClass { + public: T* ptr; + }; + + template T* a(ptrClass *arg) { + return arg->ptr; + } + + template + const T* a(const ptrClass *arg) { + return arg->ptr; + } + +int main() { + ptrClass i; + a(&i); +; return 0; } +EOF +if { (eval echo configure:12177: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_can_resolve_const_ambiguity=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_can_resolve_const_ambiguity=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_can_resolve_const_ambiguity" 1>&6 +if test "$ac_cv_can_resolve_const_ambiguity" = no ; then + cat >> confdefs.h <<\EOF +#define CANT_RESOLVE_CPP_CONST_AMBIGUITY 1 +EOF + +fi + + +echo $ac_n "checking whether the C++ \"using\" keyword can change access""... $ac_c" 1>&6 +echo "configure:12199: checking whether the C++ \"using\" keyword can change access" >&5 +if eval "test \"`echo '$''{'ac_cv_cpp_access_changing_using2'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_cpp_access_changing_using2=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_cpp_access_changing_using2=yes +fi +rm -f conftest* +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_cpp_access_changing_using2=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_cpp_access_changing_using2" 1>&6 +if test "$ac_cv_cpp_access_changing_using2" = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_CPP_ACCESS_CHANGING_USING 1 +EOF + +fi + +echo $ac_n "checking whether the C++ \"using\" keyword resolves ambiguity""... $ac_c" 1>&6 +echo "configure:12251: checking whether the C++ \"using\" keyword resolves ambiguity" >&5 +if eval "test \"`echo '$''{'ac_cv_cpp_ambiguity_resolving_using'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_cpp_ambiguity_resolving_using=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_cpp_ambiguity_resolving_using=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_cpp_ambiguity_resolving_using" 1>&6 +if test "$ac_cv_cpp_ambiguity_resolving_using" = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_CPP_AMBIGUITY_RESOLVING_USING 1 +EOF + +fi + +echo $ac_n "checking for \"std::\" namespace""... $ac_c" 1>&6 +echo "configure:12293: checking for \"std::\" namespace" >&5 +if eval "test \"`echo '$''{'ac_cv_cpp_namespace_std'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +return std::min(0, 1); +; return 0; } +EOF +if { (eval echo configure:12305: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_cpp_namespace_std=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_cpp_namespace_std=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_cpp_namespace_std" 1>&6 +if test "$ac_cv_cpp_namespace_std" = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_CPP_NAMESPACE_STD 1 +EOF + +fi + +echo $ac_n "checking whether standard template operator!=() is ambiguous""... $ac_c" 1>&6 +echo "configure:12326: checking whether standard template operator!=() is ambiguous" >&5 +if eval "test \"`echo '$''{'ac_cv_cpp_unambiguous_std_notequal'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + struct T1 {}; + int operator==(const T1&, const T1&) { return 0; } + int operator!=(const T1&, const T1&) { return 0; } +int main() { +T1 a,b; return a != b; +; return 0; } +EOF +if { (eval echo configure:12341: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_cpp_unambiguous_std_notequal=unambiguous +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_cpp_unambiguous_std_notequal=ambiguous +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_cpp_unambiguous_std_notequal" 1>&6 +if test "$ac_cv_cpp_unambiguous_std_notequal" = unambiguous ; then + cat >> confdefs.h <<\EOF +#define HAVE_CPP_UNAMBIGUOUS_STD_NOTEQUAL 1 +EOF + +fi + + +echo $ac_n "checking for C++ reinterpret_cast""... $ac_c" 1>&6 +echo "configure:12363: checking for C++ reinterpret_cast" >&5 +if eval "test \"`echo '$''{'ac_cv_cpp_reinterpret_cast'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <(z); +; return 0; } +EOF +if { (eval echo configure:12376: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_cpp_reinterpret_cast=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_cpp_reinterpret_cast=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_cpp_reinterpret_cast" 1>&6 +if test "$ac_cv_cpp_reinterpret_cast" = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_CPP_NEW_CASTS 1 +EOF + +fi + +echo $ac_n "checking for C++ dynamic_cast to void*""... $ac_c" 1>&6 +echo "configure:12397: checking for C++ dynamic_cast to void*" >&5 +if eval "test \"`echo '$''{'ac_cv_cpp_dynamic_cast_void_ptr'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_cpp_dynamic_cast_void_ptr=no +else + cat > conftest.$ac_ext <(subx))) || + (((void*)&mdo != (void*)suby) && + ((void*)&mdo == dynamic_cast(suby)))); + } +EOF +if { (eval echo configure:12424: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_cpp_dynamic_cast_void_ptr=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_cpp_dynamic_cast_void_ptr=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_cpp_dynamic_cast_void_ptr" 1>&6 +if test "$ac_cv_cpp_dynamic_cast_void_ptr" = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR 1 +EOF + +fi + + +echo $ac_n "checking whether C++ requires implementation of unused virtual methods""... $ac_c" 1>&6 +echo "configure:12448: checking whether C++ requires implementation of unused virtual methods" >&5 +if eval "test \"`echo '$''{'ac_cv_cpp_unused_required'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_cpp_unused_required=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_cpp_unused_required=yes +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_cpp_unused_required" 1>&6 +if test "$ac_cv_cpp_unused_required" = yes ; then + cat >> confdefs.h <<\EOF +#define NEED_CPP_UNUSED_IMPLEMENTATIONS 1 +EOF + +fi + + + +echo $ac_n "checking for trouble comparing to zero near std::operator!=()""... $ac_c" 1>&6 +echo "configure:12483: checking for trouble comparing to zero near std::operator!=()" >&5 +if eval "test \"`echo '$''{'ac_cv_trouble_comparing_to_zero'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + template class Foo {}; + class T2; + template int operator==(const T2*, const T&) { return 0; } + template int operator!=(const T2*, const T&) { return 0; } +int main() { +Foo f; return (0 != f); +; return 0; } +EOF +if { (eval echo configure:12499: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_trouble_comparing_to_zero=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_trouble_comparing_to_zero=yes +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_trouble_comparing_to_zero" 1>&6 +if test "$ac_cv_trouble_comparing_to_zero" = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_CPP_TROUBLE_COMPARING_TO_ZERO 1 +EOF + +fi + +# try harder, when checking for __thread support, see bug 521750 comment #33 and below +_SAVE_LDFLAGS=$LDFLAGS +LDFLAGS="$LDFLAGS $DSO_PIC_CFLAGS $DSO_LDOPTS" +echo $ac_n "checking for __thread keyword for TLS variables""... $ac_c" 1>&6 +echo "configure:12523: checking for __thread keyword for TLS variables" >&5 +if eval "test \"`echo '$''{'ac_cv_thread_keyword'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_thread_keyword=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_thread_keyword=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_thread_keyword" 1>&6 +LDFLAGS=$_SAVE_LDFLAGS +if test "$ac_cv_thread_keyword" = yes; then + # mips builds fail with TLS variables because of a binutils bug. + # See bug 528687 + case "${target}" in + mips*-*) + : + ;; + *-android*) + : + ;; + *) + cat >> confdefs.h <<\EOF +#define HAVE_THREAD_TLS_KEYWORD 1 +EOF + + ;; + esac +fi + + +MALLOC_H= +ac_safe=`echo "malloc.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for malloc.h""... $ac_c" 1>&6 +echo "configure:12572: checking for malloc.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:12582: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + MALLOC_H=malloc.h +else + echo "$ac_t""no" 1>&6 +fi + +if test "$MALLOC_H" = ""; then + ac_safe=`echo "malloc/malloc.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for malloc/malloc.h""... $ac_c" 1>&6 +echo "configure:12606: checking for malloc/malloc.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:12616: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + MALLOC_H=malloc/malloc.h +else + echo "$ac_t""no" 1>&6 +fi + + if test "$MALLOC_H" = ""; then + ac_safe=`echo "sys/malloc.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for sys/malloc.h""... $ac_c" 1>&6 +echo "configure:12640: checking for sys/malloc.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:12650: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + MALLOC_H=sys/malloc.h +else + echo "$ac_t""no" 1>&6 +fi + + fi +fi +if test "$MALLOC_H" != ""; then + cat >> confdefs.h < +EOF + +fi + +MOZ_ALLOCATING_FUNCS="strndup posix_memalign memalign valloc" +for ac_func in strndup posix_memalign memalign valloc +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:12684: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:12715: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + + +echo $ac_n "checking for __attribute__((always_inline))""... $ac_c" 1>&6 +echo "configure:12742: checking for __attribute__((always_inline))" >&5 +if eval "test \"`echo '$''{'ac_cv_attribute_always_inline'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_attribute_always_inline=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_attribute_always_inline=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_attribute_always_inline" 1>&6 + +echo $ac_n "checking for __attribute__((malloc))""... $ac_c" 1>&6 +echo "configure:12769: checking for __attribute__((malloc))" >&5 +if eval "test \"`echo '$''{'ac_cv_attribute_malloc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_attribute_malloc=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_attribute_malloc=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_attribute_malloc" 1>&6 + +echo $ac_n "checking for __attribute__((warn_unused_result))""... $ac_c" 1>&6 +echo "configure:12796: checking for __attribute__((warn_unused_result))" >&5 +if eval "test \"`echo '$''{'ac_cv_attribute_warn_unused'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_attribute_warn_unused=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_attribute_warn_unused=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_attribute_warn_unused" 1>&6 + +echo $ac_n "checking for __attribute__((noreturn))""... $ac_c" 1>&6 +echo "configure:12823: checking for __attribute__((noreturn))" >&5 +if eval "test \"`echo '$''{'ac_cv_attribute_noreturn'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_attribute_noreturn=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_attribute_noreturn=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_attribute_noreturn" 1>&6 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + + +echo $ac_n "checking for LC_MESSAGES""... $ac_c" 1>&6 +echo "configure:12859: checking for LC_MESSAGES" >&5 +if eval "test \"`echo '$''{'ac_cv_i18n_lc_messages'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +int category = LC_MESSAGES; +; return 0; } +EOF +if { (eval echo configure:12871: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_i18n_lc_messages=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_i18n_lc_messages=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_i18n_lc_messages" 1>&6 +if test "$ac_cv_i18n_lc_messages" = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_I18N_LC_MESSAGES 1 +EOF + +fi + +for ac_func in localeconv +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:12894: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:12922: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +fi # SKIP_COMPILER_CHECKS + +TARGET_XPCOM_ABI= +if test -n "${CPU_ARCH}" -a -n "${TARGET_COMPILER_ABI}"; then + TARGET_XPCOM_ABI="${CPU_ARCH}-${TARGET_COMPILER_ABI}" +fi + + +if test "$ac_cv_attribute_always_inline" = yes ; then + cat >> confdefs.h <<\EOF +#define NS_ALWAYS_INLINE __attribute__((always_inline)) +EOF + +else + cat >> confdefs.h <<\EOF +#define NS_ALWAYS_INLINE +EOF + +fi + +if test "$ac_cv_attribute_malloc" = yes ; then + cat >> confdefs.h <<\EOF +#define NS_ATTR_MALLOC __attribute__((malloc)) +EOF + +else + cat >> confdefs.h <<\EOF +#define NS_ATTR_MALLOC +EOF + +fi + +if test "$ac_cv_attribute_warn_unused" = yes ; then + cat >> confdefs.h <<\EOF +#define NS_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +EOF + +else + cat >> confdefs.h <<\EOF +#define NS_WARN_UNUSED_RESULT +EOF + +fi + +if test "$ac_cv_attribute_noreturn" = yes ; then + cat >> confdefs.h <<\EOF +#define NS_NORETURN __attribute__((noreturn)) +EOF + +else + cat >> confdefs.h <<\EOF +#define NS_NORETURN +EOF + +fi + + +if test -n "$SKIP_COMPILER_CHECKS"; then + cat >> confdefs.h <<\EOF +#define MALLOC_H +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_FORCEINLINE 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_LOCALECONV 1 +EOF + +fi # SKIP_COMPILER_CHECKS + +# External Packages + +# Check whether --with-system-nspr or --without-system-nspr was given. +if test "${with_system_nspr+set}" = set; then + withval="$with_system_nspr" + if test "$withval" = "yes"; then + _USE_SYSTEM_NSPR=1 + elif test "$withval" = "no"; then + : + else + { echo "configure: error: Option, system-nspr, does not take an argument ($withval)." 1>&2; exit 1; } + fi +fi + + +# Check whether --with-nspr-cflags or --without-nspr-cflags was given. +if test "${with_nspr_cflags+set}" = set; then + withval="$with_nspr_cflags" + NSPR_CFLAGS=$withval +fi + +# Check whether --with-nspr-libs or --without-nspr-libs was given. +if test "${with_nspr_libs+set}" = set; then + withval="$with_nspr_libs" + NSPR_LIBS=$withval +fi + + + + +if test "$_USE_SYSTEM_NSPR" && (test "$NSPR_CFLAGS" -o "$NSPR_LIBS"); then + { echo "configure: error: --with-system-nspr and --with-nspr-libs/cflags are mutually exclusive. +See 'configure --help'." 1>&2; exit 1; } +fi + +if test -n "$_USE_SYSTEM_NSPR"; then + MOZ_NATIVE_NSPR= + +# Check whether --with-nspr-prefix or --without-nspr-prefix was given. +if test "${with_nspr_prefix+set}" = set; then + withval="$with_nspr_prefix" + nspr_config_prefix="$withval" +else + nspr_config_prefix="" +fi + + +# Check whether --with-nspr-exec-prefix or --without-nspr-exec-prefix was given. +if test "${with_nspr_exec_prefix+set}" = set; then + withval="$with_nspr_exec_prefix" + nspr_config_exec_prefix="$withval" +else + nspr_config_exec_prefix="" +fi + + + if test -n "$nspr_config_exec_prefix"; then + nspr_config_args="$nspr_config_args --exec-prefix=$nspr_config_exec_prefix" + if test -z "$NSPR_CONFIG"; then + NSPR_CONFIG=$nspr_config_exec_prefix/bin/nspr-config + fi + fi + if test -n "$nspr_config_prefix"; then + nspr_config_args="$nspr_config_args --prefix=$nspr_config_prefix" + if test -z "$NSPR_CONFIG"; then + NSPR_CONFIG=$nspr_config_prefix/bin/nspr-config + fi + fi + + unset ac_cv_path_NSPR_CONFIG + # Extract the first word of "nspr-config", so it can be a program name with args. +set dummy nspr-config; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:13092: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_NSPR_CONFIG'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$NSPR_CONFIG" in + /*) + ac_cv_path_NSPR_CONFIG="$NSPR_CONFIG" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_NSPR_CONFIG="$NSPR_CONFIG" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_NSPR_CONFIG="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NSPR_CONFIG" && ac_cv_path_NSPR_CONFIG="no" + ;; +esac +fi +NSPR_CONFIG="$ac_cv_path_NSPR_CONFIG" +if test -n "$NSPR_CONFIG"; then + echo "$ac_t""$NSPR_CONFIG" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + min_nspr_version=4.7.0 + echo $ac_n "checking for NSPR - version >= $min_nspr_version""... $ac_c" 1>&6 +echo "configure:13127: checking for NSPR - version >= $min_nspr_version" >&5 + + no_nspr="" + if test "$NSPR_CONFIG" != "no"; then + NSPR_CFLAGS=`$NSPR_CONFIG $nspr_config_args --cflags` + NSPR_LIBS=`$NSPR_CONFIG $nspr_config_args --libs` + NSPR_VERSION_STRING=`$NSPR_CONFIG $nspr_config_args --version` + elif test -n "${NO_NSPR_CONFIG_SYSTEM_VERSION}"; then + NSPR_CFLAGS="${NO_NSPR_CONFIG_SYSTEM_CFLAGS}" + NSPR_LIBS="${NO_NSPR_CONFIG_SYSTEM_LDFLAGS}" + NSPR_VERSION_STRING="$NO_NSPR_CONFIG_SYSTEM_VERSION" + else + no_nspr="yes" + fi + + if test -z "$no_nspr"; then + nspr_config_major_version=`echo $NSPR_VERSION_STRING | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'` + nspr_config_minor_version=`echo $NSPR_VERSION_STRING | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` + nspr_config_micro_version=`echo $NSPR_VERSION_STRING | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` + min_nspr_major_version=`echo $min_nspr_version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'` + min_nspr_minor_version=`echo $min_nspr_version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` + min_nspr_micro_version=`echo $min_nspr_version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` + if test "$nspr_config_major_version" -ne "$min_nspr_major_version"; then + no_nspr="yes" + elif test "$nspr_config_major_version" -eq "$min_nspr_major_version" && + test "$nspr_config_minor_version" -lt "$min_nspr_minor_version"; then + no_nspr="yes" + elif test "$nspr_config_major_version" -eq "$min_nspr_major_version" && + test "$nspr_config_minor_version" -eq "$min_nspr_minor_version" && + test "$nspr_config_micro_version" -lt "$min_nspr_micro_version"; then + no_nspr="yes" + fi + fi + + if test -z "$no_nspr"; then + echo "$ac_t""yes" 1>&6 + MOZ_NATIVE_NSPR=1 + else + echo "$ac_t""no" 1>&6 + { echo "configure: error: your don't have NSPR installed or your version is too old" 1>&2; exit 1; } + fi + + + + + + +fi + +if test -n "$MOZ_NATIVE_NSPR"; then + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $NSPR_CFLAGS" + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + MOZ_NATIVE_NSPR=1 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + { echo "configure: error: system NSPR does not support PR_STATIC_ASSERT" 1>&2; exit 1; } +fi +rm -f conftest* + CFLAGS=$_SAVE_CFLAGS +fi + + +# Application + +BUILD_STATIC_LIBS= +ENABLE_TESTS=1 + +MOZ_THUMB2= +USE_ARM_KUSER= + +case "${target}" in + arm-android-eabi) + USE_ARM_KUSER=1 + MOZ_THUMB2=1 + ;; +esac + +# Check whether --with-arm-kuser or --without-arm-kuser was given. +if test "${with_arm_kuser+set}" = set; then + withval="$with_arm_kuser" + if test "$withval" = "yes"; then + USE_ARM_KUSER=1 + elif test "$withval" = "no"; then + : + else + { echo "configure: error: Option, arm-kuser, does not take an argument ($withval)." 1>&2; exit 1; } + fi +fi + +if test -n "$USE_ARM_KUSER"; then + cat >> confdefs.h <<\EOF +#define USE_ARM_KUSER 1 +EOF + +fi + +# Components and Features + +# Check whether --enable-ui-locale or --disable-ui-locale was given. +if test "${enable_ui_locale+set}" = set; then + enableval="$enable_ui_locale" + MOZ_UI_LOCALE=$enableval +fi + + + +# Check whether --enable-tests or --disable-tests was given. +if test "${enable_tests+set}" = set; then + enableval="$enable_tests" + if test "$enableval" = "no"; then + ENABLE_TESTS= + elif test "$enableval" = "yes"; then + ENABLE_TESTS=1 + else + { echo "configure: error: Option, tests, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +# Individual module options + +case "$target_cpu" in + arm*) + MOZ_ARM_ARCH=armv7 + ;; +esac +# Check whether --enable-thumb2 or --disable-thumb2 was given. +if test "${enable_thumb2+set}" = set; then + enableval="$enable_thumb2" + if test "$enableval" = "yes"; then + MOZ_THUMB2=1 + elif test "$enableval" = "no"; then + MOZ_THUMB2= + else + { echo "configure: error: Option, thumb2, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + +if test -n "$MOZ_THUMB2"; then + MOZ_ARM_ARCH=armv7 +fi + +# Check whether --with-cpu-arch or --without-cpu-arch was given. +if test "${with_cpu_arch+set}" = set; then + withval="$with_cpu_arch" + MOZ_ARM_ARCH=$withval +fi + + +if test -n "$MOZ_THUMB2"; then + case "$target_cpu" in + arm*) + if test "$MOZ_ARM_ARCH" != "armv7"; then + { echo "configure: error: --enable-thumb2 is not compatible with cpu-arch=$MOZ_ARM_ARCH" 1>&2; exit 1; } + fi + if test "$GNU_CC"; then + cat >> confdefs.h <<\EOF +#define MOZ_THUMB2 1 +EOF + + cat >> confdefs.h <<\EOF +#define MOZ_ARM_ARCH 1 +EOF + + CFLAGS="$CFLAGS -march=armv7-a -mthumb -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS" + CXXFLAGS="$CXXFLAGS -march=armv7-a -mthumb -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS" + ASFLAGS="$ASFLAGS -march=armv7-a -mthumb -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS" + else + { echo "configure: error: --enable-thumb2 is not supported for non-GNU toolchains" 1>&2; exit 1; } + fi + ;; + *) + { echo "configure: error: --enable-thumb2 is not supported for non-ARM CPU architectures" 1>&2; exit 1; } + ;; + esac +elif test "$MOZ_ARM_ARCH" = "armv7"; then + case "$target_cpu" in + arm*) + if test "$GNU_CC"; then + cat >> confdefs.h <<\EOF +#define MOZ_ARM_ARCH 1 +EOF + + CFLAGS="$CFLAGS -march=armv7-a -marm -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS" + CXXFLAGS="$CXXFLAGS -march=armv7-a -marm -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS" + ASFLAGS="$ASFLAGS -march=armv7-a -marm -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS" + else + { echo "configure: error: --with-cpu-arch=armv7 is not supported for non-GNU toolchains" 1>&2; exit 1; } + fi + ;; + *) + { echo "configure: error: --with-cpu-arch=armv7 is not supported for non-ARM CPU architectures" 1>&2; exit 1; } + ;; + esac +else + case "$target_cpu" in + arm*) + if test "$GNU_CC"; then + CFLAGS="$CFLAGS -march=armv5te -mthumb-interwork -msoft-float" + CXXFLAGS="$CXXFLAGS -march=armv5te -mthumb-interwork -msoft-float" + ASFLAGS="$ASFLAGS -march=armv5te -mthumb-interwork -msoft-float" + fi + ;; + esac +fi + + + + +# Debugging and Optimizations + +if test -z "$MOZ_DEBUG_FLAGS"; then + MOZ_DEBUG_FLAGS="-g" +fi + +# Check whether --enable-debug or --disable-debug was given. +if test "${enable_debug+set}" = set; then + enableval="$enable_debug" + if test "$enableval" != "no"; then + MOZ_DEBUG=1 + if test -n "$enableval" -a "$enableval" != "yes"; then + MOZ_DEBUG_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'` + _MOZ_DEBUG_FLAGS_SET=1 + fi + else + MOZ_DEBUG= + fi +else + MOZ_DEBUG= +fi + + +MOZ_DEBUG_ENABLE_DEFS="-DDEBUG -D_DEBUG -DTRACING" +# Check whether --with-debug-label or --without-debug-label was given. +if test "${with_debug_label+set}" = set; then + withval="$with_debug_label" + for option in `echo $withval | sed 's/,/ /g'`; do + MOZ_DEBUG_ENABLE_DEFS="$MOZ_DEBUG_ENABLE_DEFS -DDEBUG_${option}" +done +fi + + +MOZ_DEBUG_DISABLE_DEFS="-DNDEBUG -DTRIMMED" + +if test -n "$MOZ_DEBUG"; then + echo $ac_n "checking for valid debug flags""... $ac_c" 1>&6 +echo "configure:13393: checking for valid debug flags" >&5 + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $MOZ_DEBUG_FLAGS" + cat > conftest.$ac_ext < +int main() { +printf("Hello World\n"); +; return 0; } +EOF +if { (eval echo configure:13404: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + _results=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + _results=no +fi +rm -f conftest* + echo "$ac_t""$_results" 1>&6 + if test "$_results" = "no"; then + { echo "configure: error: These compiler flags are invalid: $MOZ_DEBUG_FLAGS" 1>&2; exit 1; } + fi + CFLAGS=$_SAVE_CFLAGS +fi + +if test -z "$MOZ_OPTIMIZE_FLAGS"; then + MOZ_OPTIMIZE_FLAGS="-O" +fi + +# Check whether --enable-optimize or --disable-optimize was given. +if test "${enable_optimize+set}" = set; then + enableval="$enable_optimize" + if test "$enableval" != "no"; then + MOZ_OPTIMIZE=1 + if test -n "$enableval" -a "$enableval" != "yes"; then + MOZ_OPTIMIZE_FLAGS=`echo "$enableval" | sed -e 's|\\\ | |g'` + MOZ_OPTIMIZE=2 + fi +else + MOZ_OPTIMIZE= +fi +else + MOZ_OPTIMIZE=1 +fi + + +if test "$COMPILE_ENVIRONMENT"; then +if test -n "$MOZ_OPTIMIZE"; then + echo $ac_n "checking for valid optimization flags""... $ac_c" 1>&6 +echo "configure:13445: checking for valid optimization flags" >&5 + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $MOZ_OPTIMIZE_FLAGS" + cat > conftest.$ac_ext < +int main() { +printf("Hello World\n"); +; return 0; } +EOF +if { (eval echo configure:13456: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + _results=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + _results=no +fi +rm -f conftest* + echo "$ac_t""$_results" 1>&6 + if test "$_results" = "no"; then + { echo "configure: error: These compiler flags are invalid: $MOZ_OPTIMIZE_FLAGS" 1>&2; exit 1; } + fi + CFLAGS=$_SAVE_CFLAGS +fi +fi # COMPILE_ENVIRONMENT + + + + + + +# Check whether --enable-debugger-info-modules or --disable-debugger-info-modules was given. +if test "${enable_debugger_info_modules+set}" = set; then + enableval="$enable_debugger_info_modules" + if test "$enableval" != "no"; then + echo "configure: warning: --enable-debugger-info-modules is deprecated, use --enable-debug-symbols instead" 1>&2 + MOZ_DEBUG_SYMBOLS=1 + fi +fi + + +# Check whether --enable-debug-symbols or --disable-debug-symbols was given. +if test "${enable_debug_symbols+set}" = set; then + enableval="$enable_debug_symbols" + if test "$enableval" != "no"; then + MOZ_DEBUG_SYMBOLS=1 + if test -n "$enableval" -a "$enableval" != "yes"; then + if test -z "$_MOZ_DEBUG_FLAGS_SET"; then + MOZ_DEBUG_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'` + else + { echo "configure: error: --enable-debug-symbols flags cannot be used with --enable-debug flags" 1>&2; exit 1; } + fi + fi + fi +fi + + +if test -n "$MOZ_DEBUG" -o -n "$MOZ_DEBUG_SYMBOLS"; then + cat >> confdefs.h <<\EOF +#define MOZ_DEBUG_SYMBOLS 1 +EOF + + export MOZ_DEBUG_SYMBOLS +fi + +# Check whether --enable-warnings-as-errors or --disable-warnings-as-errors was given. +if test "${enable_warnings_as_errors+set}" = set; then + enableval="$enable_warnings_as_errors" + if test "$enableval" = "no"; then + MOZ_DISABLE_WARNINGS_AS_ERRORS=1 + elif test "$enableval" = "yes"; then + MOZ_DISABLE_WARNINGS_AS_ERRORS= + else + { echo "configure: error: Option, warnings-as-errors, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + +if test "$MOZ_DISABLE_WARNINGS_AS_ERRORS"; then + WARNINGS_AS_ERRORS='' +fi + +NS_TRACE_MALLOC=${MOZ_TRACE_MALLOC} +# Check whether --enable-trace-malloc or --disable-trace-malloc was given. +if test "${enable_trace_malloc+set}" = set; then + enableval="$enable_trace_malloc" + if test "$enableval" = "yes"; then + NS_TRACE_MALLOC=1 + elif test "$enableval" = "no"; then + NS_TRACE_MALLOC= + else + { echo "configure: error: Option, trace-malloc, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + +if test "$NS_TRACE_MALLOC"; then + # Please, Mr. Linker Man, don't take away our symbol names + MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS= + cat >> confdefs.h <<\EOF +#define NS_TRACE_MALLOC 1 +EOF + +fi + + +# Check whether --enable-jemalloc or --disable-jemalloc was given. +if test "${enable_jemalloc+set}" = set; then + enableval="$enable_jemalloc" + if test "$enableval" = "yes"; then + MOZ_MEMORY=1 + elif test "$enableval" = "no"; then + MOZ_MEMORY= + else + { echo "configure: error: Option, jemalloc, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +if test "$NS_TRACE_MALLOC"; then + MOZ_MEMORY= +fi + +if test "$MOZ_MEMORY"; then + + if test "$OS_ARCH" = "WINNT"; then + if test -z "$HAVE_64BIT_OS"; then + cat >> confdefs.h <> confdefs.h <&6 +echo "configure:13585: checking size of int *" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_int_p'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_sizeof_int_p=4 +else + cat > conftest.$ac_ext < +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(int *)); + exit(0); +} +EOF +if { (eval echo configure:13604: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_int_p=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_int_p=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_int_p" 1>&6 +cat >> confdefs.h <> confdefs.h <> confdefs.h <&2; exit 1; } + ;; + esac + fi + + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY 1 +EOF + + if test "x$MOZ_DEBUG" = "x1"; then + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY_DEBUG 1 +EOF + + fi + case "${target}" in + *-darwin*) + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY_DARWIN 1 +EOF + + ;; + *-*freebsd*) + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY_BSD 1 +EOF + + ;; + *-*linux*) + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY_LINUX 1 +EOF + + ;; + *-netbsd*) + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY_BSD 1 +EOF + + ;; + *-solaris*) + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY_SOLARIS 1 +EOF + + ;; + *-msvc*|*-mks*|*-cygwin*|*-mingw*) + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY_WINDOWS 1 +EOF + + # the interesting bits will get passed down in MOZ_MEMORY_LDFLAGS + ;; + *-*wince) + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY_WINCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY_WINDOWS 1 +EOF + + if test -z "$WINCE_WINDOWS_MOBILE"; then + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY_WINCE6 1 +EOF + + fi + ;; + *-*winmo) + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY_WINCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY_WINDOWS 1 +EOF + + ;; + *-android*) + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY_LINUX 1 +EOF + + cat >> confdefs.h <<\EOF +#define MOZ_MEMORY_ANDROID 1 +EOF + + ;; + *) + { echo "configure: error: --enable-jemalloc not supported on ${target}" 1>&2; exit 1; } + ;; + esac + + if test "$OS_ARCH" != "Darwin"; then + cat >> confdefs.h <<\EOF +#define HAVE_JEMALLOC_VALLOC 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_JEMALLOC_POSIX_MEMALIGN 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_JEMALLOC_MEMALIGN 1 +EOF + + fi +fi + + + +# Check whether --enable-wrap-malloc or --disable-wrap-malloc was given. +if test "${enable_wrap_malloc+set}" = set; then + enableval="$enable_wrap_malloc" + if test "$enableval" = "yes"; then + _WRAP_MALLOC=1 + elif test "$enableval" = "no"; then + _WRAP_MALLOC= + else + { echo "configure: error: Option, wrap-malloc, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +if test -n "$_WRAP_MALLOC"; then + if test "$GNU_CC"; then + WRAP_MALLOC_CFLAGS="${LDFLAGS} -Wl,--wrap -Wl,malloc -Wl,--wrap -Wl,calloc -Wl,--wrap -Wl,valloc -Wl,--wrap -Wl,free -Wl,--wrap -Wl,realloc -Wl,--wrap -Wl,memalign -Wl,--wrap -Wl,__builtin_new -Wl,--wrap -Wl,__builtin_vec_new -Wl,--wrap -Wl,__builtin_delete -Wl,--wrap -Wl,__builtin_vec_delete -Wl,--wrap -Wl,PR_Free -Wl,--wrap -Wl,PR_Malloc -Wl,--wrap -Wl,PR_Calloc -Wl,--wrap -Wl,PR_Realloc -Wl,--wrap -Wl,strdup -Wl,--wrap -Wl,strndup -Wl,--wrap -Wl,posix_memalign" + MKSHLIB='$(CXX) $(DSO_LDOPTS) $(WRAP_MALLOC_CFLAGS) $(WRAP_MALLOC_LIB) -o $@' + fi +fi + +# Check whether --with-wrap-malloc or --without-wrap-malloc was given. +if test "${with_wrap_malloc+set}" = set; then + withval="$with_wrap_malloc" + WRAP_MALLOC_LIB=$withval +fi + + +# Check whether --enable-trace-jscalls or --disable-trace-jscalls was given. +if test "${enable_trace_jscalls+set}" = set; then + enableval="$enable_trace_jscalls" + if test "$enableval" = "yes"; then + MOZ_TRACE_JSCALLS=1 + elif test "$enableval" = "no"; then + MOZ_TRACE_JSCALLS= + else + { echo "configure: error: Option, trace-jscalls, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + +if test -n "$MOZ_TRACE_JSCALLS"; then + cat >> confdefs.h <<\EOF +#define MOZ_TRACE_JSCALLS 1 +EOF + +fi + +# Check whether --enable-tracevis or --disable-tracevis was given. +if test "${enable_tracevis+set}" = set; then + enableval="$enable_tracevis" + if test "$enableval" = "yes"; then + MOZ_TRACEVIS=1 + elif test "$enableval" = "no"; then + MOZ_TRACEVIS= + else + { echo "configure: error: Option, tracevis, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + +if test -n "$MOZ_TRACEVIS"; then + cat >> confdefs.h <<\EOF +#define MOZ_TRACEVIS 1 +EOF + + if test -z "$ENABLE_TRACEJIT"; then + { echo "configure: error: --enable-tracevis is incompatible with --disable-tracejit" 1>&2; exit 1; } + fi +fi + +# Check whether --enable-gctimer or --disable-gctimer was given. +if test "${enable_gctimer+set}" = set; then + enableval="$enable_gctimer" + if test "$enableval" = "yes"; then + MOZ_GCTIMER=1 + elif test "$enableval" = "no"; then + MOZ_GCTIMER= + else + { echo "configure: error: Option, gctimer, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + +if test -n "$MOZ_GCTIMER"; then + cat >> confdefs.h <<\EOF +#define MOZ_GCTIMER 1 +EOF + +fi + +# Check whether --enable-valgrind or --disable-valgrind was given. +if test "${enable_valgrind+set}" = set; then + enableval="$enable_valgrind" + if test "$enableval" = "yes"; then + MOZ_VALGRIND=1 + elif test "$enableval" = "no"; then + MOZ_VALGRIND= + else + { echo "configure: error: Option, valgrind, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + +if test -n "$MOZ_VALGRIND"; then + ac_safe=`echo "valgrind/valgrind.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for valgrind/valgrind.h""... $ac_c" 1>&6 +echo "configure:13851: checking for valgrind/valgrind.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:13861: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +{ echo "configure: error: --enable-valgrind specified but Valgrind is not installed" 1>&2; exit 1; } +fi + + cat >> confdefs.h <<\EOF +#define MOZ_VALGRIND 1 +EOF + +fi + +# Check whether --enable-jprof or --disable-jprof was given. +if test "${enable_jprof+set}" = set; then + enableval="$enable_jprof" + if test "$enableval" = "yes"; then + MOZ_JPROF=1 + elif test "$enableval" = "no"; then + MOZ_JPROF= + else + { echo "configure: error: Option, jprof, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + +if test -n "$MOZ_JPROF"; then + MOZ_PROFILING=1 + cat >> confdefs.h <<\EOF +#define MOZ_JPROF 1 +EOF + +fi + +# Check whether --enable-shark or --disable-shark was given. +if test "${enable_shark+set}" = set; then + enableval="$enable_shark" + if test "$enableval" = "yes"; then + MOZ_SHARK=1 + elif test "$enableval" = "no"; then + MOZ_SHARK= + else + { echo "configure: error: Option, shark, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + +if test -n "$MOZ_SHARK"; then + MOZ_PROFILING=1 + cat >> confdefs.h <<\EOF +#define MOZ_SHARK 1 +EOF + +fi + +# Check whether --enable-callgrind or --disable-callgrind was given. +if test "${enable_callgrind+set}" = set; then + enableval="$enable_callgrind" + if test "$enableval" = "yes"; then + MOZ_CALLGRIND=1 + elif test "$enableval" = "no"; then + MOZ_CALLGRIND= + else + { echo "configure: error: Option, callgrind, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + +if test -n "$MOZ_CALLGRIND"; then + cat >> confdefs.h <<\EOF +#define MOZ_CALLGRIND 1 +EOF + +fi + +# Check whether --enable-vtune or --disable-vtune was given. +if test "${enable_vtune+set}" = set; then + enableval="$enable_vtune" + if test "$enableval" = "yes"; then + MOZ_VTUNE=1 + elif test "$enableval" = "no"; then + MOZ_VTUNE= + else + { echo "configure: error: Option, vtune, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + +if test -n "$MOZ_VTUNE"; then + MOZ_PROFILING=1 + cat >> confdefs.h <<\EOF +#define MOZ_VTUNE 1 +EOF + +fi + +if test -n "$MOZ_PROFILING"; then + cat >> confdefs.h <<\EOF +#define MOZ_PROFILING 1 +EOF + +fi + +# Check whether --enable-gczeal or --disable-gczeal was given. +if test "${enable_gczeal+set}" = set; then + enableval="$enable_gczeal" + if test "$enableval" = "yes"; then + JS_GC_ZEAL=1 + elif test "$enableval" = "no"; then + JS_GC_ZEAL= + else + { echo "configure: error: Option, gczeal, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + +if test -n "$JS_GC_ZEAL"; then + cat >> confdefs.h <<\EOF +#define JS_GC_ZEAL 1 +EOF + +fi + +# Check whether --with-ccache or --without-ccache was given. +if test "${with_ccache+set}" = set; then + withval="$with_ccache" + CCACHE=$withval +else + CCACHE="no" +fi + + +if test "$CCACHE" != "no"; then + if test -z "$CCACHE" -o "$CCACHE" = "yes"; then + CCACHE= + else + if test ! -e "$CCACHE"; then + { echo "configure: error: $CCACHE not found" 1>&2; exit 1; } + fi + fi + for ac_prog in $CCACHE ccache +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:14016: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_CCACHE'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$CCACHE" in + /*) + ac_cv_path_CCACHE="$CCACHE" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_CCACHE="$CCACHE" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_CCACHE="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +CCACHE="$ac_cv_path_CCACHE" +if test -n "$CCACHE"; then + echo "$ac_t""$CCACHE" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CCACHE" && break +done + + if test "$msyshost"; then + case "$CCACHE" in + /*) + tmp_DIRNAME=`dirname "$CCACHE"` + tmp_BASENAME=`basename "$CCACHE"` + tmp_PWD=`cd "$tmp_DIRNAME" && pwd -W` + CCACHE="$tmp_PWD/$tmp_BASENAME" + if test -e "$CCACHE.exe"; then + CCACHE="$CCACHE.exe" + fi + esac + fi + + if test -z "$CCACHE" -o "$CCACHE" = ":"; then + { echo "configure: error: ccache not found" 1>&2; exit 1; } + elif test -x "$CCACHE"; then + CC="$CCACHE $CC" + CXX="$CCACHE $CXX" + else + { echo "configure: error: $CCACHE is not executable" 1>&2; exit 1; } + fi +fi + + +# Check whether --with-static-checking or --without-static-checking was given. +if test "${with_static_checking+set}" = set; then + withval="$with_static_checking" + DEHYDRA_PATH=$withval +else + DEHYDRA_PATH= +fi + + +if test -n "$DEHYDRA_PATH"; then + if test ! -f "$DEHYDRA_PATH"; then + { echo "configure: error: The dehydra plugin is not at the specified path." 1>&2; exit 1; } + fi + cat >> confdefs.h <<\EOF +#define NS_STATIC_CHECKING 1 +EOF + +fi + + +# Check whether --enable-strip or --disable-strip was given. +if test "${enable_strip+set}" = set; then + enableval="$enable_strip" + if test "$enableval" = "yes"; then + ENABLE_STRIP=1 + elif test "$enableval" = "no"; then + ENABLE_STRIP= + else + { echo "configure: error: Option, strip, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +# Check whether --enable-install-strip or --disable-install-strip was given. +if test "${enable_install_strip+set}" = set; then + enableval="$enable_install_strip" + if test "$enableval" = "yes"; then + PKG_SKIP_STRIP= + elif test "$enableval" = "no"; then + PKG_SKIP_STRIP=1 + else + { echo "configure: error: Option, install-strip, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +# Profiling and Instrumenting + +# Check whether --enable-timeline or --disable-timeline was given. +if test "${enable_timeline+set}" = set; then + enableval="$enable_timeline" + if test "$enableval" = "yes"; then + MOZ_TIMELINE=1 + elif test "$enableval" = "no"; then + MOZ_TIMELINE= + else + { echo "configure: error: Option, timeline, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + +if test -n "$MOZ_TIMELINE"; then + cat >> confdefs.h <<\EOF +#define MOZ_TIMELINE 1 +EOF + +fi + +# Check whether --enable-quantify or --disable-quantify was given. +if test "${enable_quantify+set}" = set; then + enableval="$enable_quantify" + if test "$enableval" = "yes"; then + MOZ_QUANTIFY=1 + elif test "$enableval" = "no"; then + MOZ_QUANTIFY= + else + { echo "configure: error: Option, quantify, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +if test -z "$SKIP_LIBRARY_CHECKS"; then + + ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + for ac_func in __cxa_demangle +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:14167: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:14198: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +HAVE_DEMANGLE= +fi +done + + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +fi + +# Demangle only for debug or trace-malloc builds +MOZ_DEMANGLE_SYMBOLS= +if test "$HAVE_DEMANGLE" -a "$HAVE_GCC3_ABI" && test "$MOZ_DEBUG" -o "$NS_TRACE_MALLOC"; then + MOZ_DEMANGLE_SYMBOLS=1 + cat >> confdefs.h <<\EOF +#define MOZ_DEMANGLE_SYMBOLS 1 +EOF + +fi + + +if test "$HAVE_GCC3_ABI" -a -z "$SKIP_LIBRARY_CHECKS"; then + ac_safe=`echo "unwind.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for unwind.h""... $ac_c" 1>&6 +echo "configure:14246: checking for unwind.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:14256: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + for ac_func in _Unwind_Backtrace +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:14275: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:14303: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + +else + echo "$ac_t""no" 1>&6 +fi + +fi + +# Misc. Options + +# Check whether --enable-xterm-updates or --disable-xterm-updates was given. +if test "${enable_xterm_updates+set}" = set; then + enableval="$enable_xterm_updates" + if test "$enableval" = "yes"; then + MOZ_UPDATE_XTERM=1 + elif test "$enableval" = "no"; then + MOZ_UPDATE_XTERM= + else + { echo "configure: error: Option, xterm-updates, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +if test -z "$SKIP_COMPILER_CHECKS"; then +# Compiler Options + +echo $ac_n "checking for gcc -pipe support""... $ac_c" 1>&6 +echo "configure:14352: checking for gcc -pipe support" >&5 +if test -n "$GNU_CC" -a -n "$GNU_CXX" -a -n "$GNU_AS"; then + echo '#include ' > dummy-hello.c + echo 'int main() { printf("Hello World\n"); exit(0); }' >> dummy-hello.c + ${CC} -S dummy-hello.c -o dummy-hello.s 2>&5 + cat dummy-hello.s 2> /dev/null | ${AS_BIN} -o dummy-hello.S - 2>&5 + if test $? = 0; then + _res_as_stdin="yes" + else + _res_as_stdin="no" + fi + if test "$_res_as_stdin" = "yes"; then + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -pipe" + cat > conftest.$ac_ext < +int main() { +printf("Hello World\n"); +; return 0; } +EOF +if { (eval echo configure:14374: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + _res_gcc_pipe="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + _res_gcc_pipe="no" +fi +rm -f conftest* + CFLAGS=$_SAVE_CFLAGS + fi + if test "$_res_as_stdin" = "yes" -a "$_res_gcc_pipe" = "yes"; then + _res="yes"; + CFLAGS="$CFLAGS -pipe" + CXXFLAGS="$CXXFLAGS -pipe" + else + _res="no" + fi + rm -f dummy-hello.c dummy-hello.s dummy-hello.S dummy-hello a.out + echo "$ac_t""$_res" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +# Check whether --enable-profile-guided-optimization or --disable-profile-guided-optimization was given. +if test "${enable_profile_guided_optimization+set}" = set; then + enableval="$enable_profile_guided_optimization" + if test "$enableval" = "no"; then + MOZ_PROFILE_GUIDED_OPTIMIZE_DISABLE=1 + elif test "$enableval" = "yes"; then + MOZ_PROFILE_GUIDED_OPTIMIZE_DISABLE= + else + { echo "configure: error: Option, profile-guided-optimization, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + + + +_SAVE_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fprofile-generate -fprofile-correction" + +echo $ac_n "checking whether C compiler supports -fprofile-generate""... $ac_c" 1>&6 +echo "configure:14419: checking whether C compiler supports -fprofile-generate" >&5 +cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + PROFILE_GEN_CFLAGS="-fprofile-generate" + result="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + result="no" +fi +rm -f conftest* +echo "$ac_t""$result" 1>&6 + +if test $result = "yes"; then + PROFILE_GEN_LDFLAGS="-fprofile-generate" + PROFILE_USE_CFLAGS="-fprofile-use -fprofile-correction -Wcoverage-mismatch -freorder-blocks-and-partition" + PROFILE_USE_LDFLAGS="-fprofile-use" +fi + +CFLAGS="$_SAVE_CFLAGS" + +if test -n "$INTEL_CC"; then + PROFILE_GEN_CFLAGS="-prof-gen -prof-dir ." + PROFILE_GEN_LDFLAGS= + PROFILE_USE_CFLAGS="-prof-use -prof-dir ." + PROFILE_USE_LDFLAGS= +fi + +if test "$SOLARIS_SUNPRO_CC"; then + PROFILE_GEN_CFLAGS="-xprofile=collect:$_objdir/$enable_application" + PROFILE_GEN_LDFLAGS="-xprofile=collect:$_objdir/$enable_application" + PROFILE_USE_CFLAGS="-xprofile=use:$_objdir/$enable_application" + PROFILE_USE_LDFLAGS="-xprofile=use:$_objdir/$enable_application" +fi + + + + + + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + +# Check whether --enable-pedantic or --disable-pedantic was given. +if test "${enable_pedantic+set}" = set; then + enableval="$enable_pedantic" + if test "$enableval" = "no"; then + _PEDANTIC= + elif test "$enableval" = "yes"; then + : + else + { echo "configure: error: Option, pedantic, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + +if test "$_PEDANTIC"; then + _SAVE_CXXFLAGS=$CXXFLAGS + CXXFLAGS="$CXXFLAGS ${_WARNINGS_CXXFLAGS} ${_COMPILER_PREFIX}-pedantic ${_COMPILER_PREFIX}-Wno-long-long" + echo $ac_n "checking whether C++ compiler has -pedantic long long bug""... $ac_c" 1>&6 +echo "configure:14492: checking whether C++ compiler has -pedantic long long bug" >&5 + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + result="no" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + result="yes" +fi +rm -f conftest* + echo "$ac_t""$result" 1>&6 + CXXFLAGS="$_SAVE_CXXFLAGS" + + case "$result" in + no) + _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} ${_COMPILER_PREFIX}-pedantic ${_COMPILER_PREFIX}-Wno-long-long" + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} ${_COMPILER_PREFIX}-pedantic ${_COMPILER_PREFIX}-Wno-long-long" + ;; + yes) + { echo "configure: error: Your compiler appears to have a known bug where long long is miscompiled when using -pedantic. Reconfigure using --disable-pedantic. " 1>&2; exit 1; } + ;; + esac +fi + +echo $ac_n "checking for correct temporary object destruction order""... $ac_c" 1>&6 +echo "configure:14526: checking for correct temporary object destruction order" >&5 +if test "$cross_compiling" = yes; then + result="maybe" +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + result="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + result="no" +fi +rm -fr conftest* +fi + +echo "$ac_t""$result" 1>&6 + +if test "$result" = "no"; then + { echo "configure: error: Your compiler does not follow the C++ specification for temporary object destruction order." 1>&2; exit 1; } +fi + +_SAVE_CXXFLAGS=$CXXFLAGS +CXXFLAGS="$CXXFLAGS ${_WARNINGS_CXXFLAGS}" +echo $ac_n "checking for correct overload resolution with const and templates""... $ac_c" 1>&6 +echo "configure:14575: checking for correct overload resolution with const and templates" >&5 +if eval "test \"`echo '$''{'ac_nscap_nonconst_opeq_bug'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < + class Pointer + { + public: + T* myPtr; + }; + + template + int operator==(const Pointer& rhs, U* lhs) + { + return rhs.myPtr == lhs; + } + + template + int operator==(const Pointer& rhs, const U* lhs) + { + return rhs.myPtr == lhs; + } + +int main() { + + Pointer foo; + const int* bar; + return foo == bar; + +; return 0; } +EOF +if { (eval echo configure:14610: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_nscap_nonconst_opeq_bug="no" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_nscap_nonconst_opeq_bug="yes" +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_nscap_nonconst_opeq_bug" 1>&6 +CXXFLAGS="$_SAVE_CXXFLAGS" + +if test "$ac_nscap_nonconst_opeq_bug" = "yes" ; then + cat >> confdefs.h <<\EOF +#define NSCAP_DONT_PROVIDE_NONCONST_OPEQ 1 +EOF + +fi + +echo $ac_n "checking for tm_zone tm_gmtoff in struct tm""... $ac_c" 1>&6 +echo "configure:14633: checking for tm_zone tm_gmtoff in struct tm" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_tm_zone_tm_gmtoff'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +struct tm tm; tm.tm_zone = 0; tm.tm_gmtoff = 1; +; return 0; } +EOF +if { (eval echo configure:14645: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_tm_zone_tm_gmtoff="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_tm_zone_tm_gmtoff="no" +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_tm_zone_tm_gmtoff" 1>&6 +if test "$ac_cv_struct_tm_zone_tm_gmtoff" = "yes" ; then + cat >> confdefs.h <<\EOF +#define HAVE_TM_ZONE_TM_GMTOFF 1 +EOF + +fi + +fi # SKIP_COMPILER_CHECKS + +# Check whether --enable-cpp-rtti or --disable-cpp-rtti was given. +if test "${enable_cpp_rtti+set}" = set; then + enableval="$enable_cpp_rtti" + if test "$enableval" = "yes"; then + _MOZ_USE_RTTI=1 + elif test "$enableval" = "no"; then + _MOZ_USE_RTTI= + else + { echo "configure: error: Option, cpp-rtti, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +if test "$_MOZ_USE_RTTI"; then + _MOZ_RTTI_FLAGS=$_MOZ_RTTI_FLAGS_ON +else + _MOZ_RTTI_FLAGS=$_MOZ_RTTI_FLAGS_OFF +fi + + + +# Check whether --enable-cpp-exceptions or --disable-cpp-exceptions was given. +if test "${enable_cpp_exceptions+set}" = set; then + enableval="$enable_cpp_exceptions" + if test "$enableval" = "yes"; then + _MOZ_CPP_EXCEPTIONS=1 + elif test "$enableval" = "no"; then + _MOZ_CPP_EXCEPTIONS= + else + { echo "configure: error: Option, cpp-exceptions, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +if test "$_MOZ_CPP_EXCEPTIONS"; then + _MOZ_EXCEPTIONS_FLAGS=$_MOZ_EXCEPTIONS_FLAGS_ON + cat >> confdefs.h <<\EOF +#define MOZ_CPP_EXCEPTIONS 1 +EOF + +else + _MOZ_EXCEPTIONS_FLAGS=$_MOZ_EXCEPTIONS_FLAGS_OFF +fi + + + +# Irix & OSF native compilers do not like exception declarations +# when exceptions are disabled +if test -n "$MIPSPRO_CXX" -o -n "$COMPAQ_CXX" -o -n "$VACPP"; then + cat >> confdefs.h <<\EOF +#define CPP_THROW_NEW +EOF + +else + cat >> confdefs.h <<\EOF +#define CPP_THROW_NEW throw() +EOF + +fi +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + +# Build dependencies + +MOZ_AUTO_DEPS=1 +# Check whether --enable-auto-deps or --disable-auto-deps was given. +if test "${enable_auto_deps+set}" = set; then + enableval="$enable_auto_deps" + if test "$enableval" = "no"; then + MOZ_AUTO_DEPS= + elif test "$enableval" = "yes"; then + MOZ_AUTO_DEPS=1 + else + { echo "configure: error: Option, auto-deps, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +if test -n "$MOZ_AUTO_DEPS"; then +_cpp_md_flag= +# Check whether --enable-md or --disable-md was given. +if test "${enable_md+set}" = set; then + enableval="$enable_md" + if test "$enableval" = "no"; then + _cpp_md_flag= + elif test "$enableval" = "yes"; then + _cpp_md_flag=1 + else + { echo "configure: error: Option, md, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +else + if test "$GNU_CC" -a "$GNU_CXX" -a "$OS_ARCH" != "WINNT" -a "$OS_ARCH" != "WINCE"; then + _cpp_md_flag=1 + fi + if test "$SOLARIS_SUNPRO_CC"; then + _cpp_md_flag=1 + fi +fi + +if test "$_cpp_md_flag"; then + COMPILER_DEPEND=1 + if test "$OS_ARCH" = "OpenVMS"; then + _DEPEND_CFLAGS='$(subst =, ,$(filter-out %/.pp,-MM=-MD=-MF=$(MDDEPDIR)/$(basename $(@F)).pp))' + else + _DEPEND_CFLAGS='$(filter-out %/.pp,-MD -MF $(MDDEPDIR)/$(basename $(@F)).pp)' + fi + if test "$SOLARIS_SUNPRO_CC"; then + _DEPEND_CFLAGS= + fi +else + COMPILER_DEPEND= + if test -z "$_WIN32_MSVC"; then + _USE_CPP_INCLUDE_FLAG= + _DEFINES_CFLAGS='$(ACDEFINES) -D_JS_CONFDEFS_H_ -DMOZILLA_CLIENT' + _DEFINES_CXXFLAGS='$(ACDEFINES) -D_JS_CONFDEFS_H_ -DMOZILLA_CLIENT' + else + echo '#include ' > dummy-hello.c + + CL_INCLUDES_PREFIX=`"${CC}" -showIncludes -c -Fonul dummy-hello.c 2>&1 | sed -ne 's/^\([^:]*:[^:]*:\).*stdio.h$/\1/p'` + + if test -z "$CL_INCLUDES_PREFIX"; then + { echo "configure: error: Cannot find cl -showIncludes prefix." 1>&2; exit 1; } + fi + + rm -f dummy-hello.c + _topsrcdirwin=`cd \`dirname $0\`; pwd -W` + CC_WRAPPER="$PYTHON -O $_topsrcdirwin/build/cl.py" + CXX_WRAPPER="$PYTHON -O $_topsrcdirwin/build/cl.py" + COMPILER_DEPEND=1 + fi +fi +fi # MOZ_AUTO_DEPS +MDDEPDIR='.deps' + + + + + + + +# Static build options + +# Check whether --enable-static or --disable-static was given. +if test "${enable_static+set}" = set; then + enableval="$enable_static" + if test "$enableval" = "yes"; then + BUILD_STATIC_LIBS=1 + elif test "$enableval" = "no"; then + BUILD_STATIC_LIBS= + else + { echo "configure: error: Option, static, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +# Check whether --enable-readline or --disable-readline was given. +if test "${enable_readline+set}" = set; then + enableval="$enable_readline" + if test "$enableval" = "yes"; then + JS_WANT_READLINE=1 + elif test "$enableval" = "no"; then + JS_WANT_READLINE= + else + { echo "configure: error: Option, readline, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +JS_NATIVE_EDITLINE= +EDITLINE_LIBS= +JS_DISABLE_SHELL= + +case "$target" in +*-wince*|*-winmo*|*-mingw*|*-cygwin*|*-msvc*|*-mks*) + NO_EDITLINE=1 + ;; +*-symbian*) + NO_EDITLINE=1 + JS_DISABLE_SHELL=1 + ;; +*) + ;; +esac + +if test -z "$SKIP_LIBRARY_CHECKS" -a -z "$NO_EDITLINE"; then + if test -n "$JS_WANT_READLINE"; then + echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6 +echo "configure:14859: checking for readline in -lreadline" >&5 +ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lreadline $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + EDITLINE_LIBS="-lreadline" +else + echo "$ac_t""no" 1>&6 +{ echo "configure: error: No system readline library found." 1>&2; exit 1; } +fi + + else + JS_NATIVE_EDITLINE=1 + EDITLINE_LIBS='$(DEPTH)/editline/$(LIB_PREFIX)editline.$(LIB_SUFFIX)' + fi + + cat >> confdefs.h <<\EOF +#define EDITLINE 1 +EOF + +fi + + + + +# Standalone module options (Not for building Mozilla) + +# Check whether --enable-ctypes or --disable-ctypes was given. +if test "${enable_ctypes+set}" = set; then + enableval="$enable_ctypes" + if test "$enableval" = "yes"; then + JS_HAS_CTYPES=1 + elif test "$enableval" = "no"; then + JS_HAS_CTYPES= + else + { echo "configure: error: Option, ctypes, does not take an argument ($enableval)." 1>&2; exit 1; } + fi +fi + + +if test "$JS_HAS_CTYPES"; then + if test -n "$_MSC_VER" -a \( "$AS" != "ml.exe" -a "$AS" != "ml64.exe" \); then + { echo "configure: error: \"$AS\" is not a suitable assembler to build js-ctypes. If you are building with MS Visual Studio 8 Express, you may download the MASM 8.0 package, upgrade to Visual Studio 9 Express, or install the Vista SDK. Or do not use --enable-ctypes." 1>&2; exit 1; } + fi + cat >> confdefs.h <<\EOF +#define JS_HAS_CTYPES 1 +EOF + +fi + +if test "$MOZ_DEBUG" -o "$NS_TRACE_MALLOC"; then + MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS= +fi + +# Check whether --with-sync-build-files or --without-sync-build-files was given. +if test "${with_sync_build_files+set}" = set; then + withval="$with_sync_build_files" + MOZ_SYNC_BUILD_FILES=$withval +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +CFLAGS=`echo \ + $_WARNINGS_CFLAGS \ + $CFLAGS` + +CXXFLAGS=`echo \ + $_MOZ_RTTI_FLAGS \ + $_MOZ_EXCEPTIONS_FLAGS \ + $_WARNINGS_CXXFLAGS \ + $CXXFLAGS` + +COMPILE_CFLAGS=`echo \ + $_DEFINES_CFLAGS \ + $_DEPEND_CFLAGS \ + $COMPILE_CFLAGS` + +COMPILE_CXXFLAGS=`echo \ + $_DEFINES_CXXFLAGS \ + $_DEPEND_CFLAGS \ + $COMPILE_CXXFLAGS` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +cat >> confdefs.h <&6 +echo "configure:15127: checking for posix_fallocate" >&5 +cat > conftest.$ac_ext < +int main() { +posix_fallocate(0, 0, 0); +; return 0; } +EOF +if { (eval echo configure:15137: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv___posix_fallocate=true +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv___posix_fallocate=false +fi +rm -f conftest* + +if test "$ac_cv___posix_fallocate" = true ; then + cat >> confdefs.h <<\EOF +#define HAVE_POSIX_FALLOCATE 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test "$COMPILE_ENVIRONMENT"; then +if test "$MOZ_X11"; then + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $XCFLAGS" + cat > conftest.$ac_ext < + #include + #include + #include + +int main() { + + Display *dpy = 0; + if ((dpy = XOpenDisplay(NULL)) == NULL) { + fprintf(stderr, ": can't open %s\n", XDisplayName(NULL)); + exit(1); + } + +; return 0; } +EOF +if { (eval echo configure:15181: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + { echo "configure: error: Could not compile basic X program." 1>&2; exit 1; } +fi +rm -f conftest* + CFLAGS="$_SAVE_CFLAGS" + + if test ! -z "$MISSING_X"; then + { echo "configure: error: Could not find the following X libraries: $MISSING_X " 1>&2; exit 1; }; + fi + +fi # MOZ_X11 +fi # COMPILE_ENVIRONMENT + + +if test "$OS_ARCH" = "BeOS"; then + cat >> confdefs.h <<\EOF +#define XP_BEOS 1 +EOF + +elif test "$OS_ARCH" = "Darwin"; then + cat >> confdefs.h <<\EOF +#define XP_MACOSX 1 +EOF + + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define UNIX_ASYNC_DNS 1 +EOF + +elif test "$OS_ARCH" = "OpenVMS"; then + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + +elif test "$OS_ARCH" != "WINNT" -a "$OS_ARCH" != "OS2" -a "$OS_ARCH" != "WINCE"; then + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define UNIX_ASYNC_DNS 1 +EOF + +fi + +# Check whether --enable-threadsafe or --disable-threadsafe was given. +if test "${enable_threadsafe+set}" = set; then + enableval="$enable_threadsafe" + cat >> confdefs.h <<\EOF +#define JS_THREADSAFE 1 +EOF + +fi + + +if test "$MOZ_DEBUG"; then + cat >> confdefs.h <<\EOF +#define MOZ_REFLOW_PERF 1 +EOF + + cat >> confdefs.h <<\EOF +#define MOZ_REFLOW_PERF_DSP 1 +EOF + +fi + +if test "$ACCESSIBILITY" -a "$MOZ_ENABLE_GTK2" ; then + cat >> confdefs.h <<\EOF +#define MOZ_ACCESSIBILITY_ATK 1 +EOF + + ATK_FULL_VERSION=`$PKG_CONFIG --modversion atk` + ATK_MAJOR_VERSION=`echo ${ATK_FULL_VERSION} | $AWK -F\. '{ print $1 }'` + ATK_MINOR_VERSION=`echo ${ATK_FULL_VERSION} | $AWK -F\. '{ print $2 }'` + ATK_REV_VERSION=`echo ${ATK_FULL_VERSION} | $AWK -F\. '{ print $3 }'` + cat >> confdefs.h <> confdefs.h <> confdefs.h <&6 +echo "configure:15282: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:15310: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + +for ac_func in localeconv +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:15337: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:15365: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +case "$host_os" in +mingw*) + WIN_TOP_SRC=`cd $srcdir; pwd -W` + ;; +cygwin*|msvc*|mks*) + HOST_CC="\$(CYGWIN_WRAPPER) $HOST_CC" + HOST_CXX="\$(CYGWIN_WRAPPER) $HOST_CXX" + CC="\$(CYGWIN_WRAPPER) $CC" + CXX="\$(CYGWIN_WRAPPER) $CXX" + CPP="\$(CYGWIN_WRAPPER) $CPP" + LD="\$(CYGWIN_WRAPPER) $LD" + AS="\$(CYGWIN_WRAPPER) $AS" + RC="\$(CYGWIN_WRAPPER) $RC" + CYGDRIVE_MOUNT=`mount -p | awk '{ if (/^\//) { print $1; exit } }'` + WIN_TOP_SRC=`cygpath -a -w $srcdir | sed -e 's|\\\\|/|g'` + ;; +esac + + + + + + + + + +# Save the defines header file before autoconf removes it. +# (Do not add AC_DEFINE calls after this line.) + _CONFIG_TMP=confdefs-tmp.h + _CONFIG_DEFS_H=js-confdefs.h + + cat > $_CONFIG_TMP <<\EOF +/* List of defines generated by configure. Included with preprocessor flag, + * -include, to avoid long list of -D defines on the compile command-line. + * Do not edit. + */ + +#ifndef _JS_CONFDEFS_H_ +#define _JS_CONFDEFS_H_ +EOF + +_EGREP_PATTERN='^#define (' +if test -n "$_NON_GLOBAL_ACDEFINES"; then + for f in $_NON_GLOBAL_ACDEFINES; do + _EGREP_PATTERN="${_EGREP_PATTERN}$f|" + done +fi +_EGREP_PATTERN="${_EGREP_PATTERN}dummy_never_defined)" + + sort confdefs.h | egrep -v "$_EGREP_PATTERN" >> $_CONFIG_TMP + + cat >> $_CONFIG_TMP <<\EOF + +#endif /* _JS_CONFDEFS_H_ */ + +EOF + + # Only write js-confdefs.h when something changes (or it doesn't exist) + if cmp -s $_CONFIG_TMP $_CONFIG_DEFS_H; then + rm $_CONFIG_TMP + else + echo "$ac_t"""creating $_CONFIG_DEFS_H"" 1>&6 + mv -f $_CONFIG_TMP $_CONFIG_DEFS_H + + echo ==== $_CONFIG_DEFS_H ================================= + cat $_CONFIG_DEFS_H + fi + +rm -f confdefs.h.save +mv confdefs.h confdefs.h.save +egrep -v "$_EGREP_PATTERN" confdefs.h.save > confdefs.h +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +cat > conftest.defs <<\EOF +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g +s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g +s%\[%\\&%g +s%\]%\\&%g +s%\$%$$%g +EOF +DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` +rm -f conftest.defs + +MOZ_DEFINES=$DEFS + +rm -f confdefs.h +mv confdefs.h.save confdefs.h + +MAKEFILES=" + Makefile + shell/Makefile + lirasm/Makefile + jsapi-tests/Makefile + tests/Makefile + config/Makefile + config/autoconf.mk + config/mkdepend/Makefile +" + +if test -n "$JS_NATIVE_EDITLINE"; then + MAKEFILES="$MAKEFILES +editline/Makefile +" +fi + +if test -z "${AS_PERL}"; then +echo $MAKEFILES | ${PERL} $srcdir/build/autoconf/acoutput-fast.pl > conftest.sh +else +echo $MAKEFILES | ${PERL} $srcdir/build/autoconf/acoutput-fast.pl -nowrap --cygwin-srcdir=$srcdir > conftest.sh +fi +. ./conftest.sh +rm conftest.sh + +echo $MAKEFILES > unallmakefiles + +mv -f config/autoconf.mk config/autoconf.mk.orig 2> /dev/null + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "$MAKEFILES js-config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@AWK@%$AWK%g +s%@TOP_DIST@%$TOP_DIST%g +s%@COMPILE_ENVIRONMENT@%$COMPILE_ENVIRONMENT%g +s%@PERL@%$PERL%g +s%@JS_SHARED_LIBRARY@%$JS_SHARED_LIBRARY%g +s%@ANDROID_VERSION@%$ANDROID_VERSION%g +s%@ANDROID_NDK@%$ANDROID_NDK%g +s%@ANDROID_TOOLCHAIN@%$ANDROID_TOOLCHAIN%g +s%@ANDROID_PLATFORM@%$ANDROID_PLATFORM%g +s%@ANDROID_SDK@%$ANDROID_SDK%g +s%@ANDROID_PLATFORM_TOOLS@%$ANDROID_PLATFORM_TOOLS%g +s%@HOST_CC@%$HOST_CC%g +s%@HOST_CXX@%$HOST_CXX%g +s%@HOST_RANLIB@%$HOST_RANLIB%g +s%@HOST_AR@%$HOST_AR%g +s%@CC@%$CC%g +s%@CXX@%$CXX%g +s%@RANLIB@%$RANLIB%g +s%@AR@%$AR%g +s%@AS@%$AS%g +s%@LD@%$LD%g +s%@STRIP@%$STRIP%g +s%@WINDRES@%$WINDRES%g +s%@CPP@%$CPP%g +s%@CXXCPP@%$CXXCPP%g +s%@SBCONF@%$SBCONF%g +s%@QEMU_CANT_RUN_JS_SHELL@%$QEMU_CANT_RUN_JS_SHELL%g +s%@_MSC_VER@%$_MSC_VER%g +s%@GNU_AS@%$GNU_AS%g +s%@GNU_LD@%$GNU_LD%g +s%@GNU_CC@%$GNU_CC%g +s%@GNU_CXX@%$GNU_CXX%g +s%@INTEL_CC@%$INTEL_CC%g +s%@INTEL_CXX@%$INTEL_CXX%g +s%@STL_FLAGS@%$STL_FLAGS%g +s%@WRAP_STL_INCLUDES@%$WRAP_STL_INCLUDES%g +s%@MOZ_MSVC_STL_WRAP__Throw@%$MOZ_MSVC_STL_WRAP__Throw%g +s%@MOZ_MSVC_STL_WRAP__RAISE@%$MOZ_MSVC_STL_WRAP__RAISE%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@LN_S@%$LN_S%g +s%@PYTHON@%$PYTHON%g +s%@NSINSTALL_BIN@%$NSINSTALL_BIN%g +s%@DOXYGEN@%$DOXYGEN%g +s%@AUTOCONF@%$AUTOCONF%g +s%@UNZIP@%$UNZIP%g +s%@ZIP@%$ZIP%g +s%@SYSTEM_MAKEDEPEND@%$SYSTEM_MAKEDEPEND%g +s%@XARGS@%$XARGS%g +s%@PBBUILD@%$PBBUILD%g +s%@SDP@%$SDP%g +s%@GCC_VERSION@%$GCC_VERSION%g +s%@XCODEBUILD_VERSION@%$XCODEBUILD_VERSION%g +s%@HAS_XCODE_2_1@%$HAS_XCODE_2_1%g +s%@UNIVERSAL_BINARY@%$UNIVERSAL_BINARY%g +s%@MACOSX_DEPLOYMENT_TARGET@%$MACOSX_DEPLOYMENT_TARGET%g +s%@MACOS_SDK_DIR@%$MACOS_SDK_DIR%g +s%@NEXT_ROOT@%$NEXT_ROOT%g +s%@GMAKE@%$GMAKE%g +s%@X_CFLAGS@%$X_CFLAGS%g +s%@X_PRE_LIBS@%$X_PRE_LIBS%g +s%@X_LIBS@%$X_LIBS%g +s%@X_EXTRA_LIBS@%$X_EXTRA_LIBS%g +s%@SOLARIS_SUNPRO_CC@%$SOLARIS_SUNPRO_CC%g +s%@SOLARIS_SUNPRO_CXX@%$SOLARIS_SUNPRO_CXX%g +s%@HAVE_64BIT_OS@%$HAVE_64BIT_OS%g +s%@MOZ_OS2_HIGH_MEMORY@%$MOZ_OS2_HIGH_MEMORY%g +s%@AIX_OBJMODEL@%$AIX_OBJMODEL%g +s%@NO_LD_ARCHIVE_FLAGS@%$NO_LD_ARCHIVE_FLAGS%g +s%@ENABLE_METHODJIT@%$ENABLE_METHODJIT%g +s%@ENABLE_TRACEJIT@%$ENABLE_TRACEJIT%g +s%@NANOJIT_ARCH@%$NANOJIT_ARCH%g +s%@WRAP_SYSTEM_INCLUDES@%$WRAP_SYSTEM_INCLUDES%g +s%@VISIBILITY_FLAGS@%$VISIBILITY_FLAGS%g +s%@HAVE_GCC_ALIGN_ARG_POINTER@%$HAVE_GCC_ALIGN_ARG_POINTER%g +s%@HAVE_DTRACE@%$HAVE_DTRACE%g +s%@HAVE_LINUX_PERF_EVENT_H@%$HAVE_LINUX_PERF_EVENT_H%g +s%@HAVE_ARM_SIMD@%$HAVE_ARM_SIMD%g +s%@HAVE_ARM_NEON@%$HAVE_ARM_NEON%g +s%@LIBOBJS@%$LIBOBJS%g +s%@HAVE_CLOCK_MONOTONIC@%$HAVE_CLOCK_MONOTONIC%g +s%@REALTIME_LIBS@%$REALTIME_LIBS%g +s%@HAVE_GCC3_ABI@%$HAVE_GCC3_ABI%g +s%@NSPR_CFLAGS@%$NSPR_CFLAGS%g +s%@NSPR_LIBS@%$NSPR_LIBS%g +s%@NSPR_CONFIG@%$NSPR_CONFIG%g +s%@MOZ_UI_LOCALE@%$MOZ_UI_LOCALE%g +s%@MOZ_THUMB2@%$MOZ_THUMB2%g +s%@MOZ_ARM_ARCH@%$MOZ_ARM_ARCH%g +s%@MOZ_OPTIMIZE@%$MOZ_OPTIMIZE%g +s%@MOZ_OPTIMIZE_FLAGS@%$MOZ_OPTIMIZE_FLAGS%g +s%@MOZ_OPTIMIZE_LDFLAGS@%$MOZ_OPTIMIZE_LDFLAGS%g +s%@MOZ_OPTIMIZE_SIZE_TWEAK@%$MOZ_OPTIMIZE_SIZE_TWEAK%g +s%@NS_TRACE_MALLOC@%$NS_TRACE_MALLOC%g +s%@MOZ_MEMORY@%$MOZ_MEMORY%g +s%@MOZ_MEMORY_LDFLAGS@%$MOZ_MEMORY_LDFLAGS%g +s%@CCACHE@%$CCACHE%g +s%@DEHYDRA_PATH@%$DEHYDRA_PATH%g +s%@MOZ_DEMANGLE_SYMBOLS@%$MOZ_DEMANGLE_SYMBOLS%g +s%@MOZ_PROFILE_GUIDED_OPTIMIZE_DISABLE@%$MOZ_PROFILE_GUIDED_OPTIMIZE_DISABLE%g +s%@PROFILE_GEN_CFLAGS@%$PROFILE_GEN_CFLAGS%g +s%@PROFILE_GEN_LDFLAGS@%$PROFILE_GEN_LDFLAGS%g +s%@PROFILE_USE_CFLAGS@%$PROFILE_USE_CFLAGS%g +s%@PROFILE_USE_LDFLAGS@%$PROFILE_USE_LDFLAGS%g +s%@_MOZ_RTTI_FLAGS_ON@%$_MOZ_RTTI_FLAGS_ON%g +s%@_MOZ_EXCEPTIONS_FLAGS_ON@%$_MOZ_EXCEPTIONS_FLAGS_ON%g +s%@CL_INCLUDES_PREFIX@%$CL_INCLUDES_PREFIX%g +s%@MOZ_AUTO_DEPS@%$MOZ_AUTO_DEPS%g +s%@COMPILER_DEPEND@%$COMPILER_DEPEND%g +s%@MDDEPDIR@%$MDDEPDIR%g +s%@CC_WRAPPER@%$CC_WRAPPER%g +s%@CXX_WRAPPER@%$CXX_WRAPPER%g +s%@JS_NATIVE_EDITLINE@%$JS_NATIVE_EDITLINE%g +s%@JS_DISABLE_SHELL@%$JS_DISABLE_SHELL%g +s%@EDITLINE_LIBS@%$EDITLINE_LIBS%g +s%@JS_HAS_CTYPES@%$JS_HAS_CTYPES%g +s%@MOZ_SYNC_BUILD_FILES@%$MOZ_SYNC_BUILD_FILES%g +s%@AR_FLAGS@%$AR_FLAGS%g +s%@AR_LIST@%$AR_LIST%g +s%@AR_EXTRACT@%$AR_EXTRACT%g +s%@AR_DELETE@%$AR_DELETE%g +s%@ASFLAGS@%$ASFLAGS%g +s%@AS_DASH_C_FLAG@%$AS_DASH_C_FLAG%g +s%@RC@%$RC%g +s%@RCFLAGS@%$RCFLAGS%g +s%@IMPLIB@%$IMPLIB%g +s%@FILTER@%$FILTER%g +s%@BIN_FLAGS@%$BIN_FLAGS%g +s%@NS_USE_NATIVE@%$NS_USE_NATIVE%g +s%@MOZ_JS_LIBS@%$MOZ_JS_LIBS%g +s%@MOZ_PSM@%$MOZ_PSM%g +s%@MOZ_DEBUG@%$MOZ_DEBUG%g +s%@MOZ_DEBUG_SYMBOLS@%$MOZ_DEBUG_SYMBOLS%g +s%@MOZ_DEBUG_ENABLE_DEFS@%$MOZ_DEBUG_ENABLE_DEFS%g +s%@MOZ_DEBUG_DISABLE_DEFS@%$MOZ_DEBUG_DISABLE_DEFS%g +s%@MOZ_DEBUG_FLAGS@%$MOZ_DEBUG_FLAGS%g +s%@MOZ_DEBUG_LDFLAGS@%$MOZ_DEBUG_LDFLAGS%g +s%@WARNINGS_AS_ERRORS@%$WARNINGS_AS_ERRORS%g +s%@MOZ_LEAKY@%$MOZ_LEAKY%g +s%@MOZ_JPROF@%$MOZ_JPROF%g +s%@MOZ_SHARK@%$MOZ_SHARK%g +s%@MOZ_CALLGRIND@%$MOZ_CALLGRIND%g +s%@MOZ_VTUNE@%$MOZ_VTUNE%g +s%@MOZ_PROFILING@%$MOZ_PROFILING%g +s%@MOZ_JSLOADER@%$MOZ_JSLOADER%g +s%@MOZ_QUANTIFY@%$MOZ_QUANTIFY%g +s%@LIBICONV@%$LIBICONV%g +s%@BUILD_STATIC_LIBS@%$BUILD_STATIC_LIBS%g +s%@ENABLE_TESTS@%$ENABLE_TESTS%g +s%@ENABLE_STRIP@%$ENABLE_STRIP%g +s%@PKG_SKIP_STRIP@%$PKG_SKIP_STRIP%g +s%@INCREMENTAL_LINKER@%$INCREMENTAL_LINKER%g +s%@MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS@%$MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS%g +s%@MOZ_COMPONENT_NSPR_LIBS@%$MOZ_COMPONENT_NSPR_LIBS%g +s%@MOZ_FIX_LINK_PATHS@%$MOZ_FIX_LINK_PATHS%g +s%@USE_DEPENDENT_LIBS@%$USE_DEPENDENT_LIBS%g +s%@MOZ_BUILD_ROOT@%$MOZ_BUILD_ROOT%g +s%@MOZ_OS2_TOOLS@%$MOZ_OS2_TOOLS%g +s%@MOZ_POST_DSO_LIB_COMMAND@%$MOZ_POST_DSO_LIB_COMMAND%g +s%@MOZ_POST_PROGRAM_COMMAND@%$MOZ_POST_PROGRAM_COMMAND%g +s%@MOZ_TIMELINE@%$MOZ_TIMELINE%g +s%@MOZ_APP_NAME@%$MOZ_APP_NAME%g +s%@MOZ_APP_DISPLAYNAME@%$MOZ_APP_DISPLAYNAME%g +s%@MOZ_APP_UA_NAME@%$MOZ_APP_UA_NAME%g +s%@MOZ_APP_VERSION@%$MOZ_APP_VERSION%g +s%@MOZ_UA_FIREFOX_VERSION@%$MOZ_UA_FIREFOX_VERSION%g +s%@FIREFOX_VERSION@%$FIREFOX_VERSION%g +s%@MOZ_PKG_SPECIAL@%$MOZ_PKG_SPECIAL%g +s%@MOZILLA_OFFICIAL@%$MOZILLA_OFFICIAL%g +s%@MOZ_MAPINFO@%$MOZ_MAPINFO%g +s%@MOZ_BROWSE_INFO@%$MOZ_BROWSE_INFO%g +s%@MOZ_TOOLS_DIR@%$MOZ_TOOLS_DIR%g +s%@CYGWIN_WRAPPER@%$CYGWIN_WRAPPER%g +s%@AS_PERL@%$AS_PERL%g +s%@WIN32_REDIST_DIR@%$WIN32_REDIST_DIR%g +s%@WINCE@%$WINCE%g +s%@WINCE_SDK_DIR@%$WINCE_SDK_DIR%g +s%@WINCE_WINDOWS_MOBILE@%$WINCE_WINDOWS_MOBILE%g +s%@MOZ_NATIVE_NSPR@%$MOZ_NATIVE_NSPR%g +s%@COMPILE_CFLAGS@%$COMPILE_CFLAGS%g +s%@COMPILE_CXXFLAGS@%$COMPILE_CXXFLAGS%g +s%@CROSS_COMPILE@%$CROSS_COMPILE%g +s%@HOST_CFLAGS@%$HOST_CFLAGS%g +s%@HOST_CXXFLAGS@%$HOST_CXXFLAGS%g +s%@HOST_LDFLAGS@%$HOST_LDFLAGS%g +s%@HOST_OPTIMIZE_FLAGS@%$HOST_OPTIMIZE_FLAGS%g +s%@HOST_AR_FLAGS@%$HOST_AR_FLAGS%g +s%@HOST_LD@%$HOST_LD%g +s%@HOST_NSPR_MDCPUCFG@%$HOST_NSPR_MDCPUCFG%g +s%@HOST_BIN_SUFFIX@%$HOST_BIN_SUFFIX%g +s%@HOST_OS_ARCH@%$HOST_OS_ARCH%g +s%@TARGET_CPU@%$TARGET_CPU%g +s%@TARGET_VENDOR@%$TARGET_VENDOR%g +s%@TARGET_OS@%$TARGET_OS%g +s%@TARGET_NSPR_MDCPUCFG@%$TARGET_NSPR_MDCPUCFG%g +s%@TARGET_MD_ARCH@%$TARGET_MD_ARCH%g +s%@TARGET_XPCOM_ABI@%$TARGET_XPCOM_ABI%g +s%@OS_TARGET@%$OS_TARGET%g +s%@OS_ARCH@%$OS_ARCH%g +s%@OS_RELEASE@%$OS_RELEASE%g +s%@OS_TEST@%$OS_TEST%g +s%@CPU_ARCH@%$CPU_ARCH%g +s%@INTEL_ARCHITECTURE@%$INTEL_ARCHITECTURE%g +s%@WRAP_MALLOC_CFLAGS@%$WRAP_MALLOC_CFLAGS%g +s%@WRAP_MALLOC_LIB@%$WRAP_MALLOC_LIB%g +s%@MKSHLIB@%$MKSHLIB%g +s%@MKCSHLIB@%$MKCSHLIB%g +s%@MKSHLIB_FORCE_ALL@%$MKSHLIB_FORCE_ALL%g +s%@MKSHLIB_UNFORCE_ALL@%$MKSHLIB_UNFORCE_ALL%g +s%@DSO_CFLAGS@%$DSO_CFLAGS%g +s%@DSO_PIC_CFLAGS@%$DSO_PIC_CFLAGS%g +s%@DSO_LDOPTS@%$DSO_LDOPTS%g +s%@LIB_PREFIX@%$LIB_PREFIX%g +s%@DLL_PREFIX@%$DLL_PREFIX%g +s%@DLL_SUFFIX@%$DLL_SUFFIX%g +s%@LIB_SUFFIX@%$LIB_SUFFIX%g +s%@OBJ_SUFFIX@%$OBJ_SUFFIX%g +s%@BIN_SUFFIX@%$BIN_SUFFIX%g +s%@ASM_SUFFIX@%$ASM_SUFFIX%g +s%@IMPORT_LIB_SUFFIX@%$IMPORT_LIB_SUFFIX%g +s%@USE_N32@%$USE_N32%g +s%@CC_VERSION@%$CC_VERSION%g +s%@CXX_VERSION@%$CXX_VERSION%g +s%@MSMANIFEST_TOOL@%$MSMANIFEST_TOOL%g +s%@CYGDRIVE_MOUNT@%$CYGDRIVE_MOUNT%g +s%@WIN_TOP_SRC@%$WIN_TOP_SRC%g +s%@MOZILLA_VERSION@%$MOZILLA_VERSION%g +s%@ac_configure_args@%$ac_configure_args%g +s%@MOZ_DEFINES@%$MOZ_DEFINES%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /* | ?:/*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" ` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + + + + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" ` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + + +if cmp -s config/autoconf.mk config/autoconf.mk.orig; then + echo "config/autoconf.mk is unchanged" + mv -f config/autoconf.mk.orig config/autoconf.mk 2> /dev/null +else + rm -f config/autoconf.mk.orig 2> /dev/null +fi + +# Produce the js-config script at configure time; see the comments for +# 'js-config' in Makefile.in. +echo "$ac_t""invoking make to create js-config script" 1>&6 +$GMAKE js-config + +# Build jsctypes if it's enabled. +if test "$JS_HAS_CTYPES"; then + # Run the libffi 'configure' script. + ac_configure_args="--disable-shared --enable-static --disable-raw-api" + if test "$MOZ_DEBUG"; then + ac_configure_args="$ac_configure_args --enable-debug" + fi + if test "$DSO_PIC_CFLAGS"; then + ac_configure_args="$ac_configure_args --with-pic" + fi + if test "$CROSS_COMPILE"; then + case "$target" in + *-mingw*) + ac_configure_args="$ac_configure_args --build=$build --host=${target_cpu}-${target_os} HOST_CC=\"$HOST_CC\" CC=\"$CC\"" + ;; + *-android*) + CFLAGS="$ANDROID_CFLAGS" + CPPFLAGS="$ANDROID_CPPFLAGS" + LDFLAGS="$ANDROID_LDFLAGS" + + export AS CC CXX CPP LD AR RANLIB STRIP CPPFLAGS CFLAGS LDFLAGS + + ac_configure_args="$ac_configure_args --build=$build --host=${target_cpu}-${target_os} HOST_CC=\"$HOST_CC\"" + ;; + *) + ac_configure_args="$ac_configure_args --build=$build --host=$target HOST_CC=\"$HOST_CC\" CC=\"$CC\"" + ;; + esac + fi + if test "$_MSC_VER"; then + # Use a wrapper script for cl and ml that looks more like gcc. + # autotools can't quite handle an MSVC build environment yet. + ac_configure_args="$ac_configure_args LD=link CPP=\"cl -nologo -EP\" SHELL=sh.exe" + case "${target_cpu}" in + x86_64) + # Need target since MSYS tools into mozilla-build may be 32bit + ac_configure_args="$ac_configure_args CC=\"$_topsrcdir/ctypes/libffi/msvcc.sh -m64\" --build=$build --host=$target" + ;; + *) + ac_configure_args="$ac_configure_args CC=$_topsrcdir/ctypes/libffi/msvcc.sh" + ;; + esac + fi + if test "$SOLARIS_SUNPRO_CC"; then + # Always use gcc for libffi on Solaris + if test ! "$HAVE_64BIT_OS"; then + ac_configure_args="$ac_configure_args CC=gcc CFLAGS=-m32 LD= LDFLAGS=" + else + ac_configure_args="$ac_configure_args CC=gcc CFLAGS=-m64 LD= LDFLAGS=" + fi + fi + if test "$AIX_IBM_XLC"; then + # Always use gcc for libffi on IBM AIX5/AIX6 + if test ! "$HAVE_64BIT_OS"; then + ac_configure_args="$ac_configure_args CC=gcc CFLAGS=-maix32" + else + ac_configure_args="$ac_configure_args CC=gcc CFLAGS=-maix64" + fi + fi + if test "$OS_ARCH" = "OS2"; then + ac_configure_args="$ac_configure_args CFLAGS=-Zomf AR=emxomfar" + fi + if test -n "$MOZ_THUMB2"; then + ac_configure_args="$ac_configure_args --enable-thumb2" + fi + if test -n "$MOZ_ARM_ARCH"; then + ac_configure_args="$ac_configure_args --with-cpu-arch=$MOZ_ARM_ARCH" + fi + + # Use a separate cache file for libffi, since it does things differently + # from our configure. + mkdir -p $_objdir/ctypes/libffi + old_cache_file=$cache_file + cache_file=$_objdir/ctypes/libffi/config.cache + old_config_files=$CONFIG_FILES + unset CONFIG_FILES + + +if test "$no_recursion" != yes; then + + # Remove --cache-file and --srcdir arguments so they do not pile up. + ac_sub_configure_args= + ac_prev= + for ac_arg in $ac_configure_args; do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case "$ac_arg" in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + *) ac_sub_configure_args="$ac_sub_configure_args $ac_arg" ;; + esac + done + + for ac_config_dir in ctypes/libffi; do + + # Do not complain, so a configure script can configure whichever + # parts of a large source tree are present. + if test ! -d $srcdir/$ac_config_dir; then + continue + fi + + echo configuring in $ac_config_dir + + case "$srcdir" in + .) ;; + *) + if test -d ./$ac_config_dir || mkdir ./$ac_config_dir; then :; + else + { echo "configure: error: can not create `pwd`/$ac_config_dir" 1>&2; exit 1; } + fi + ;; + esac + + ac_popdir=`pwd` + cd $ac_config_dir + + # A "../" for each directory in /$ac_config_dir. + ac_dots=`echo $ac_config_dir|sed -e 's%^\./%%' -e 's%[^/]$%&/%' -e 's%[^/]*/%../%g'` + + case "$srcdir" in + .) # No --srcdir option. We are building in place. + ac_sub_srcdir=$srcdir ;; + /* | ?:/*) # Absolute path. + ac_sub_srcdir=$srcdir/$ac_config_dir ;; + *) # Relative path. + ac_sub_srcdir=$ac_dots$srcdir/$ac_config_dir ;; + esac + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_sub_srcdir/configure; then + ac_sub_configure=$ac_sub_srcdir/configure + elif test -f $ac_sub_srcdir/configure.in; then + ac_sub_configure=$ac_configure + else + echo "configure: warning: no configuration information is in $ac_config_dir" 1>&2 + ac_sub_configure= + fi + + # The recursion is here. + if test -n "$ac_sub_configure"; then + + # Make the cache file name correct relative to the subdirectory. + case "$cache_file" in + /* | ?:/*) ac_sub_cache_file=$cache_file ;; + *) # Relative path. + ac_sub_cache_file="$ac_dots$cache_file" ;; + esac + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo "running ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_sub_srcdir" + # The eval makes quoting arguments work. + if eval ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_sub_srcdir + then : + else + { echo "configure: error: $ac_sub_configure failed for $ac_config_dir" 1>&2; exit 1; } + fi + fi + + cd $ac_popdir + done +fi + + + cache_file=$old_cache_file + ac_configure_args="$_SUBDIR_CONFIG_ARGS" + CONFIG_FILES=$old_config_files +fi + diff --git a/js/src/configure.in b/js/src/configure.in new file mode 100644 index 0000000..5d5365b --- /dev/null +++ b/js/src/configure.in @@ -0,0 +1,6157 @@ +dnl -*- Mode: Autoconf; tab-width: 4; indent-tabs-mode: nil; -*- +dnl vi: set tabstop=4 shiftwidth=4 expandtab: +dnl ***** BEGIN LICENSE BLOCK ***** +dnl Version: MPL 1.1/GPL 2.0/LGPL 2.1 +dnl +dnl The contents of this file are subject to the Mozilla Public License Version +dnl 1.1 (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl http://www.mozilla.org/MPL/ +dnl +dnl Software distributed under the License is distributed on an "AS IS" basis, +dnl WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +dnl for the specific language governing rights and limitations under the +dnl License. +dnl +dnl The Original Code is this file as it was released upon August 6, 1998. +dnl +dnl The Initial Developer of the Original Code is +dnl Christopher Seawood. +dnl Portions created by the Initial Developer are Copyright (C) 1998-2001 +dnl the Initial Developer. All Rights Reserved. +dnl +dnl Contributor(s): +dnl Jamie Zawinski +dnl gettimeofday args check +dnl Christopher Blizzard +dnl gnomefe update & enable-pthreads +dnl Ramiro Estrugo +dnl X11 makedepend support +dnl Insure support. +dnl Henry Sobotka +dnl OS/2 support +dnl Dan Mosedale +dnl LDAP support +dnl Seth Spitzer +dnl xpctools support +dnl Benjamin Smedberg +dnl Howard Chu +dnl MSYS support +dnl Mark Mentovai : +dnl Mac OS X 10.4 support +dnl Giorgio Maone +dnl MSVC l10n compatible version check +dnl Ben Turner +dnl Windows x64 support +dnl Makoto Kato +dnl +dnl Alternatively, the contents of this file may be used under the terms of +dnl either the GNU General Public License Version 2 or later (the "GPL"), or +dnl the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +dnl in which case the provisions of the GPL or the LGPL are applicable instead +dnl of those above. If you wish to allow use of your version of this file only +dnl under the terms of either the GPL or the LGPL, and not to allow others to +dnl use your version of this file under the terms of the MPL, indicate your +dnl decision by deleting the provisions above and replace them with the notice +dnl and other provisions required by the GPL or the LGPL. If you do not delete +dnl the provisions above, a recipient may use your version of this file under +dnl the terms of any one of the MPL, the GPL or the LGPL. +dnl +dnl ***** END LICENSE BLOCK ***** + +dnl Process this file with autoconf to produce a configure script. +dnl ======================================================== + +AC_PREREQ(2.13) +AC_INIT(jsapi.h) +AC_CONFIG_AUX_DIR(${srcdir}/build/autoconf) +AC_CONFIG_HEADER(js-config.h) +AC_CANONICAL_SYSTEM +TARGET_CPU="${target_cpu}" +TARGET_VENDOR="${target_vendor}" +TARGET_OS="${target_os}" + +dnl ======================================================== +dnl = +dnl = Don't change the following two lines. Doing so breaks: +dnl = +dnl = CFLAGS="-foo" ./configure +dnl = +dnl ======================================================== +CFLAGS="${CFLAGS=}" +CPPFLAGS="${CPPFLAGS=}" +CXXFLAGS="${CXXFLAGS=}" +LDFLAGS="${LDFLAGS=}" +HOST_CFLAGS="${HOST_CFLAGS=}" +HOST_CXXFLAGS="${HOST_CXXFLAGS=}" +HOST_LDFLAGS="${HOST_LDFLAGS=}" + +dnl ======================================================== +dnl = Preserve certain environment flags passed to configure +dnl = We want sub projects to receive the same flags +dnl = untainted by this configure script +dnl ======================================================== +_SUBDIR_CC="$CC" +_SUBDIR_CXX="$CXX" +_SUBDIR_CFLAGS="$CFLAGS" +_SUBDIR_CPPFLAGS="$CPPFLAGS" +_SUBDIR_CXXFLAGS="$CXXFLAGS" +_SUBDIR_LDFLAGS="$LDFLAGS" +_SUBDIR_HOST_CC="$HOST_CC" +_SUBDIR_HOST_CFLAGS="$HOST_CFLAGS" +_SUBDIR_HOST_CXXFLAGS="$HOST_CXXFLAGS" +_SUBDIR_HOST_LDFLAGS="$HOST_LDFLAGS" +_SUBDIR_CONFIG_ARGS="$ac_configure_args" + +dnl Set the version number of the libs included with mozilla +dnl ======================================================== +NSPR_VERSION=4 + +dnl Set the minimum version of toolkit libs used by mozilla +dnl ======================================================== +PERL_VERSION=5.006 +PYTHON_VERSION=2.5 +WINDRES_VERSION=2.14.90 +W32API_VERSION=3.8 + +MSMANIFEST_TOOL= + +dnl Set various checks +dnl ======================================================== +MISSING_X= +AC_PROG_AWK + +dnl Initialize the Pthread test variables early so they can be +dnl overridden by each platform. +dnl ======================================================== +USE_PTHREADS= +_PTHREAD_LDFLAGS="" + +dnl Do not allow a separate objdir build if a srcdir build exists. +dnl ============================================================== +_topsrcdir=`cd \`dirname $0\`; pwd` +_objdir=`pwd` + +if test "$_topsrcdir" != "$_objdir" +then + # Check for a couple representative files in the source tree + _conflict_files= + for file in $_topsrcdir/Makefile $_topsrcdir/config/autoconf.mk; do + if test -f $file; then + _conflict_files="$_conflict_files $file" + fi + done + if test "$_conflict_files"; then + echo "***" + echo "* Your source tree contains these files:" + for file in $_conflict_files; do + echo "* $file" + done + cat 1>&2 <<-EOF + * This indicates that you previously built in the source tree. + * A source tree build can confuse the separate objdir build. + * + * To clean up the source tree: + * 1. cd $_topsrcdir + * 2. gmake distclean + *** + EOF + exit 1 + break + fi +fi +MOZ_BUILD_ROOT=`pwd` + +dnl Choose where to put the 'dist' directory. +dnl ============================================================== + +MOZ_ARG_WITH_STRING(dist-dir, +[ --with-dist-dir=DIR Use DIR as 'dist' staging area. DIR may be + relative to the top of SpiderMonkey build tree, + or absolute.], + TOP_DIST=$withval, + TOP_DIST=dist) +AC_SUBST(TOP_DIST) + +dnl Default to MSVC for win32 and gcc-4.2 for darwin +dnl ============================================================== +if test -z "$CROSS_COMPILE"; then +case "$target" in +*-cygwin*|*-mingw*|*-msvc*|*-mks*) + if test -z "$CC"; then CC=cl; fi + if test -z "$CXX"; then CXX=cl; fi + if test -z "$CPP"; then CPP="cl -E -nologo"; fi + if test -z "$CXXCPP"; then CXXCPP="cl -TP -E -nologo"; ac_cv_prog_CXXCPP="$CXXCPP"; fi + if test -z "$LD"; then LD=link; fi + if test -z "$AS"; then + case "${target_cpu}" in + i*86) + AS=ml; + ;; + x86_64) + AS=ml64; + ;; + esac + fi + if test -z "$MIDL"; then MIDL=midl; fi + ;; +*-darwin*) + if test -z "$CC"; then CC=gcc-4.2; fi + if test -z "$CXX"; then CXX=g++-4.2; fi + ;; +esac +fi + +COMPILE_ENVIRONMENT=1 +MOZ_ARG_DISABLE_BOOL(compile-environment, +[ --disable-compile-environment + Disable compiler/library checks.], + COMPILE_ENVIRONMENT= ) +AC_SUBST(COMPILE_ENVIRONMENT) + +dnl Check for Perl first -- needed for win32 SDK checks +MOZ_PATH_PROGS(PERL, $PERL perl5 perl ) +if test -z "$PERL" -o "$PERL" = ":"; then + AC_MSG_ERROR([perl not found in \$PATH]) +fi + +MOZ_ARG_ENABLE_BOOL(shared-js, +[ --disable-shared-js + Do not create a shared library.], + DISABLE_SHARED_JS=0, + DISABLE_SHARED_JS=1) + +if test "$DISABLE_SHARED_JS" = "1" ; then + AC_DEFINE(STATIC_EXPORTABLE_JS_API) +else + JS_SHARED_LIBRARY=1 +fi +AC_SUBST(JS_SHARED_LIBRARY) + +dnl ======================================================== +dnl = Android uses a very custom (hacky) toolchain; we need to do this +dnl = here, so that the compiler checks can succeed +dnl ======================================================== + +MOZ_ARG_WITH_STRING(android-ndk, +[ --with-android-ndk=DIR + location where the Android NDK can be found], + android_ndk=$withval) + +MOZ_ARG_WITH_STRING(android-toolchain, +[ --with-android-toolchain=DIR + location of the android toolchain, default NDK/build/prebuilt/HOST/arm-eabi-4.4.0], + android_toolchain=$withval) + + +MOZ_ARG_WITH_STRING(android-version, +[ --with-android-version=VER + android platform version, default 5], + android_version=$withval, + android_version=5) + +MOZ_ARG_WITH_STRING(android-sdk, +[ --with-android-sdk=DIR + location where the Android SDK can be found (base directory, e.g. .../android/platforms/android-6)], + android_sdk=$withval) + +if test "$target" = "arm-android-eabi" ; then + if test -z "$android_ndk" ; then + AC_MSG_ERROR([You must specify --with-android-ndk=/path/to/ndk when targeting Android.]) + fi + + if test -z "$android_sdk" ; then + AC_MSG_ERROR([You must specify --with-android-sdk=/path/to/sdk when targeting Android.]) + fi + + android_platform_tools="$android_sdk"/../../platform-tools + if test ! -d "$android_platform_tools" ; then + android_platform_tools="$android_sdk"/tools # SDK Tools < r8 + fi + + if test -z "$android_toolchain" ; then + android_toolchain="$android_ndk"/build/prebuilt/`uname -s | tr "[[:upper:]]" "[[:lower:]]"`-x86/arm-eabi-4.4.0 + fi + + if test -z "$android_platform" ; then + android_platform="$android_ndk"/build/platforms/android-"$android_version"/arch-"$target_cpu" + fi + + dnl set up compilers + AS="$android_toolchain"/bin/arm-eabi-as + CC="$android_toolchain"/bin/arm-eabi-gcc + CXX="$android_toolchain"/bin/arm-eabi-g++ + CPP="$android_toolchain"/bin/arm-eabi-cpp + LD="$android_toolchain"/bin/arm-eabi-ld + AR="$android_toolchain"/bin/arm-eabi-ar + RANLIB="$android_toolchain"/bin/arm-eabi-ranlib + STRIP="$android_toolchain"/bin/arm-eabi-strip + + CPPFLAGS="-I$android_platform/usr/include $CPPFLAGS" + CFLAGS="-mandroid -I$android_platform/usr/include -fno-short-enums -fno-exceptions $CFLAGS" + CXXFLAGS="-mandroid -I$android_platform/usr/include -fno-short-enums -fno-exceptions $CXXFLAGS" + + dnl Add -llog by default, since we use it all over the place. + dnl Add --allow-shlib-undefined, because libGLESv2 links to an + dnl undefined symbol (present on the hardware, just not in the + dnl NDK.) + LDFLAGS="-mandroid -L$android_platform/usr/lib -Wl,-rpath-link=$android_platform/usr/lib --sysroot=$android_platform -llog -Wl,--allow-shlib-undefined $LDFLAGS" + + dnl prevent cross compile section from using these flags as host flags + if test -z "$HOST_CPPFLAGS" ; then + HOST_CPPFLAGS=" " + fi + if test -z "$HOST_CFLAGS" ; then + HOST_CFLAGS=" " + fi + if test -z "$HOST_CXXFLAGS" ; then + HOST_CXXFLAGS=" " + fi + if test -z "$HOST_LDFLAGS" ; then + HOST_LDFLAGS=" " + fi + + ANDROID_NDK="${android_ndk}" + ANDROID_TOOLCHAIN="{android_toolchain}" + ANDROID_PLATFORM="{android_platform}" + ANDROID_SDK="${android_sdk}" + ANDROID_PLATFORM_TOOLS="${android_platform_tools}" + ANDROID_VERSION="${android_version}" + + # save these for libffi's subconfigure, + # which doesn't know how to figure this stuff out on its own + ANDROID_CFLAGS="$CFLAGS" + ANDROID_CPPFLAGS="$CPPFLAGS" + ANDROID_LDFLAGS="$LDFLAGS" + + AC_DEFINE(ANDROID) + AC_DEFINE_UNQUOTED(ANDROID_VERSION, $android_version) + AC_SUBST(ANDROID_VERSION) + CROSS_COMPILE=1 + MOZ_CHROME_FILE_FORMAT=omni +fi + +AC_SUBST(ANDROID_NDK) +AC_SUBST(ANDROID_TOOLCHAIN) +AC_SUBST(ANDROID_PLATFORM) +AC_SUBST(ANDROID_SDK) +AC_SUBST(ANDROID_PLATFORM_TOOLS) + +dnl ======================================================== +dnl Checks for compilers. +dnl ======================================================== +dnl Set CROSS_COMPILE in the environment when running configure +dnl to use the cross-compile setup for now +dnl ======================================================== + +dnl AR_FLAGS set here so HOST_AR_FLAGS can be set correctly (see bug 538269) +AR_FLAGS='cr $@' + +if test "$COMPILE_ENVIRONMENT"; then + +# Note: +# In Mozilla, we use the names $target, $host and $build incorrectly, but are +# too far gone to back out now. See Bug 475488: +# - When we say $target, we mean $host, that is, the system on which +# Mozilla will be run. +# - When we say $host, we mean $build, that is, the system on which Mozilla +# is built. +# - $target (in its correct usage) is for compilers who generate code for a +# different platform than $host, so it would not be used by Mozilla. +if test "$target" != "$host"; then + echo "cross compiling from $host to $target" + + _SAVE_CC="$CC" + _SAVE_CFLAGS="$CFLAGS" + _SAVE_LDFLAGS="$LDFLAGS" + + AC_MSG_CHECKING([for host c compiler]) + AC_CHECK_PROGS(HOST_CC, $HOST_CC gcc cc /usr/ucb/cc cl icc, "") + if test -z "$HOST_CC"; then + AC_MSG_ERROR([no acceptable c compiler found in \$PATH]) + fi + AC_MSG_RESULT([$HOST_CC]) + AC_MSG_CHECKING([for host c++ compiler]) + AC_CHECK_PROGS(HOST_CXX, $HOST_CXX $CCC c++ g++ gcc CC cxx cc++ cl icc, "") + if test -z "$HOST_CXX"; then + AC_MSG_ERROR([no acceptable c++ compiler found in \$PATH]) + fi + AC_MSG_RESULT([$HOST_CXX]) + + if test -z "$HOST_CFLAGS"; then + HOST_CFLAGS="$CFLAGS" + fi + if test -z "$HOST_CXXFLAGS"; then + HOST_CXXFLAGS="$CXXFLAGS" + fi + if test -z "$HOST_LDFLAGS"; then + HOST_LDFLAGS="$LDFLAGS" + fi + if test -z "$HOST_AR_FLAGS"; then + HOST_AR_FLAGS="$AR_FLAGS" + fi + AC_CHECK_PROGS(HOST_RANLIB, $HOST_RANLIB ranlib, ranlib, :) + AC_CHECK_PROGS(HOST_AR, $HOST_AR ar, ar, :) + CC="$HOST_CC" + CFLAGS="$HOST_CFLAGS" + LDFLAGS="$HOST_LDFLAGS" + + AC_MSG_CHECKING([whether the host c compiler ($HOST_CC $HOST_CFLAGS $HOST_LDFLAGS) works]) + AC_TRY_COMPILE([], [return(0);], + [ac_cv_prog_hostcc_works=1 AC_MSG_RESULT([yes])], + AC_MSG_ERROR([installation or configuration problem: host compiler $HOST_CC cannot create executables.]) ) + + CC="$HOST_CXX" + CFLAGS="$HOST_CXXFLAGS" + + AC_MSG_CHECKING([whether the host c++ compiler ($HOST_CXX $HOST_CXXFLAGS $HOST_LDFLAGS) works]) + AC_TRY_COMPILE([], [return(0);], + [ac_cv_prog_hostcxx_works=1 AC_MSG_RESULT([yes])], + AC_MSG_ERROR([installation or configuration problem: host compiler $HOST_CXX cannot create executables.]) ) + + CC=$_SAVE_CC + CFLAGS=$_SAVE_CFLAGS + LDFLAGS=$_SAVE_LDFLAGS + + case "$build:$target" in + powerpc-apple-darwin8*:i?86-apple-darwin*) + dnl The Darwin cross compiler doesn't necessarily point itself at a + dnl root that has libraries for the proper architecture, it defaults + dnl to the system root. The libraries in the system root on current + dnl versions of PPC OS X 10.4 aren't fat, so these target compiler + dnl checks will fail. Fake a working SDK in that case. + _SAVE_CFLAGS=$CFLAGS + _SAVE_CXXFLAGS=$CXXLAGS + CFLAGS="-isysroot /Developer/SDKs/MacOSX10.5.sdk $CFLAGS" + CXXFLAGS="-isysroot /Developer/SDKs/MacOSX10.5.sdk $CXXFLAGS" + ;; + esac + + case "$target" in + *symbian*) + AC_ARG_WITH(symbian-sdk, + [ --with-symbian-sdk=SYMBIAN_SDK_DIR + The path to the Symbian SDK], + SYMBIAN_SDK_DIR=$withval) + + OS_EXE_CFLAGS="$OS_EXE_CFLAGS -D__EXE__" + CFLAGS="-MD -nostdinc" + SYMBIAN_SYS_INCLUDE="-I$SYMBIAN_SDK_DIR/Epoc32/include -I$SYMBIAN_SDK_DIR/Epoc32/include/variant -I$SYMBIAN_SDK_DIR/Epoc32/include/stdapis" + + case "$target" in + *-symbianelf) + OS_TARGET=GCCE + CC=arm-none-symbianelf-gcc.exe + CXX=arm-none-symbianelf-g++.exe + LD=arm-none-symbianelf-ld.exe + AR=arm-none-symbianelf-ar.exe + CPP=arm-none-symbianelf-cpp.exe + CFLAGS="$CFLAGS -c -Wall -Wno-unknown-pragmas -fexceptions -march=armv5t -mapcs -pipe -msoft-float" + CXXFLAGS="$CFLAGS -Wno-ctor-dtor-privacy" + GCCE_INCLUDE="-include $SYMBIAN_SDK_DIR/EPOC32/INCLUDE/GCCE/GCCE.h -D__PRODUCT_INCLUDE__=$SYMBIAN_SDK_DIR/Epoc32/include/variant/Symbian_OS_v9.2.hrh" + CFLAGS="$CFLAGS ${GCCE_INCLUDE} -x c" + CXXFLAGS="$CXXFLAGS ${GCCE_INCLUDE} -x c++" + CPPFLAGS="$CPPFLAGS ${SYMBIAN_SYS_INCLUDE}" + ;; + *-symbianwinscw) + dnl TODO: add emulator build code + OS_TARGET=WINSCW + ;; + esac + ;; + esac + + AC_CHECK_PROGS(CC, $CC "${target_alias}-gcc" "${target}-gcc", :) + unset ac_cv_prog_CC + AC_PROG_CC + AC_CHECK_PROGS(CXX, $CXX "${target_alias}-g++" "${target}-g++", :) + unset ac_cv_prog_CXX + AC_PROG_CXX + + case "$build:$target" in + powerpc-apple-darwin8*:i?86-apple-darwin*) + dnl Revert the changes made above. From this point on, the target + dnl compiler will never be used without applying the SDK to CFLAGS + dnl (see --with-macos-sdk below). + CFLAGS=$_SAVE_CFLAGS + CXXFLAGS=$_SAVE_CXXFLAGS + ;; + esac + + AC_CHECK_PROGS(RANLIB, $RANLIB "${target_alias}-ranlib" "${target}-ranlib", :) + AC_CHECK_PROGS(AR, $AR "${target_alias}-ar" "${target}-ar", :) + MOZ_PATH_PROGS(AS, $AS "${target_alias}-as" "${target}-as", :) + AC_CHECK_PROGS(LD, $LD "${target_alias}-ld" "${target}-ld", :) + AC_CHECK_PROGS(STRIP, $STRIP "${target_alias}-strip" "${target}-strip", :) + AC_CHECK_PROGS(WINDRES, $WINDRES "${target_alias}-windres" "${target}-windres", :) + AC_DEFINE(CROSS_COMPILE) + + dnl If we cross compile for ppc on Mac OS X x86, cross_compiling will + dnl have erroneously been set to "no", because the x86 build host is + dnl able to run ppc code in a translated environment, making a cross + dnl compiler appear native. So we override that here. + cross_compiling=yes +else + AC_PROG_CC + AC_PROG_CXX + AC_PROG_RANLIB + MOZ_PATH_PROGS(AS, $AS as, $CC) + AC_CHECK_PROGS(AR, ar, :) + AC_CHECK_PROGS(LD, ld, :) + AC_CHECK_PROGS(STRIP, strip, :) + AC_CHECK_PROGS(WINDRES, windres, :) + if test -z "$HOST_CC"; then + HOST_CC='$(CC)' + fi + if test -z "$HOST_CFLAGS"; then + HOST_CFLAGS='$(CFLAGS)' + fi + if test -z "$HOST_CXX"; then + HOST_CXX='$(CXX)' + fi + if test -z "$HOST_CXXFLAGS"; then + HOST_CXXFLAGS='$(CXXFLAGS)' + fi + if test -z "$HOST_LDFLAGS"; then + HOST_LDFLAGS='$(LDFLAGS)' + fi + if test -z "$HOST_RANLIB"; then + HOST_RANLIB='$(RANLIB)' + fi + if test -z "$HOST_AR"; then + HOST_AR='$(AR)' + fi + if test -z "$HOST_AR_FLAGS"; then + HOST_AR_FLAGS='$(AR_FLAGS)' + fi +fi + +GNU_AS= +GNU_LD= +GNU_CC= +GNU_CXX= +CC_VERSION='N/A' +CXX_VERSION='N/A' +if test "$GCC" = "yes"; then + GNU_CC=1 + CC_VERSION=`$CC -v 2>&1 | grep 'gcc version'` +fi +if test "$GXX" = "yes"; then + GNU_CXX=1 + CXX_VERSION=`$CXX -v 2>&1 | grep 'gcc version'` +fi +if test "`echo | $AS -v 2>&1 | grep -c GNU`" != "0"; then + GNU_AS=1 +fi +if test "`echo | $LD -v 2>&1 | grep -c GNU`" != "0"; then + GNU_LD=1 +fi +if test "$GNU_CC"; then + if `$CC -print-prog-name=ld` -v 2>&1 | grep -c GNU >/dev/null; then + GCC_USE_GNU_LD=1 + fi +fi + +INTEL_CC= +INTEL_CXX= +if test "$GCC" = yes; then + if test "`$CC -help 2>&1 | grep -c 'Intel(R) C++ Compiler'`" != "0"; then + INTEL_CC=1 + fi +fi + +if test "$GXX" = yes; then + if test "`$CXX -help 2>&1 | grep -c 'Intel(R) C++ Compiler'`" != "0"; then + INTEL_CXX=1 + fi +fi + +dnl Special win32 checks +dnl ======================================================== +case "$target" in +*-wince|*-winmo) + WINVER=500 + WINSDK_TARGETVER=502 + ;; +*) + WINVER=502 + dnl Target the Windows 7 SDK by default + WINSDK_TARGETVER=601 + ;; +esac + +MOZ_ARG_WITH_STRING(windows-version, +[ --with-windows-version=WINSDK_TARGETVER + Highest Windows version to target using this SDK + 502: Windows Server 2003 + 600: Windows Vista + 601: Windows 7], + WINSDK_TARGETVER=$withval) + +case "$WINSDK_TARGETVER" in +502|600|601) + MOZ_WINSDK_TARGETVER=0${WINSDK_TARGETVER}0000 + ;; + +*) + AC_MSG_ERROR([Invalid value for --with-windows-version ($WINSDK_TARGETVER), must be 502, 600 or 601]); + ;; + +esac + +case "$target" in +*-cygwin*|*-mingw*|*-msvc*|*-mks*|*-wince|*-winmo) + if test "$GCC" != "yes"; then + # Check to see if we are really running in a msvc environemnt + _WIN32_MSVC=1 + + # Make sure compilers are valid + CFLAGS="$CFLAGS -TC -nologo" + CXXFLAGS="$CXXFLAGS -TP -nologo" + # MSVC warning C4345 warns of newly conformant behavior as of VS2003. + # _CRT_SECURE_NO_WARNINGS disables warnings about using MSVC-specific + # secure CRT functions. + CXXFLAGS="$CXXFLAGS -wd4345 -D_CRT_SECURE_NO_WARNINGS" + AC_LANG_SAVE + AC_LANG_C + AC_TRY_COMPILE([#include ], + [ printf("Hello World\n"); ],, + AC_MSG_ERROR([\$(CC) test failed. You must have MS VC++ in your path to build.]) ) + + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE([#include ], + [ unsigned *test = new unsigned(42); ],, + AC_MSG_ERROR([\$(CXX) test failed. You must have MS VC++ in your path to build.]) ) + AC_LANG_RESTORE + + changequote(,) + _MSVC_VER_FILTER='s|.* ([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?).*|\1|p' + changequote([,]) + + # Determine compiler version + CC_VERSION=`"${CC}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"` + _CC_MAJOR_VERSION=`echo ${CC_VERSION} | $AWK -F\. '{ print $1 }'` + _CC_MINOR_VERSION=`echo ${CC_VERSION} | $AWK -F\. '{ print $2 }'` + _CC_RELEASE=`echo ${CC_VERSION} | $AWK -F\. '{ print $3 }'` + _CC_BUILD=`echo ${CC_VERSION} | $AWK -F\. '{ print $4 }'` + _MSC_VER=${_CC_MAJOR_VERSION}${_CC_MINOR_VERSION} + + CXX_VERSION=`"${CXX}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"` + _CXX_MAJOR_VERSION=`echo ${CXX_VERSION} | $AWK -F\. '{ print $1 }'` + + if test "$_CC_MAJOR_VERSION" != "$_CXX_MAJOR_VERSION"; then + AC_MSG_ERROR([The major versions of \$CC and \$CXX do not match.]) + fi + + if test "$_CC_MAJOR_VERSION" = "14"; then + dnl Require VC8SP1 or newer. + dnl VC8 is 14.00.50727.42, VC8SP1 is 14.00.50727.762. + if test "$_CC_RELEASE" -lt 50727 -o \ + \( "$_CC_RELEASE" -eq 50727 -a "$_CC_BUILD" -lt 762 \); then + AC_MSG_ERROR([This version ($CC_VERSION) of the MSVC compiler is unsupported. You probably need to install Service Pack 1 of Visual Studio 2005. See https://developer.mozilla.org/en/Windows_Build_Prerequisites.]) + fi + + _CC_SUITE=8 + CXXFLAGS="$CXXFLAGS -Zc:wchar_t-" + AC_DEFINE(_CRT_SECURE_NO_DEPRECATE) + AC_DEFINE(_CRT_NONSTDC_NO_DEPRECATE) + elif test "$_CC_MAJOR_VERSION" = "15"; then + _CC_SUITE=9 + CXXFLAGS="$CXXFLAGS -Zc:wchar_t-" + AC_DEFINE(_CRT_SECURE_NO_WARNINGS) + AC_DEFINE(_CRT_NONSTDC_NO_WARNINGS) + elif test "$_CC_MAJOR_VERSION" = "16"; then + _CC_SUITE=10 + CXXFLAGS="$CXXFLAGS -Zc:wchar_t-" + AC_DEFINE(_CRT_SECURE_NO_WARNINGS) + AC_DEFINE(_CRT_NONSTDC_NO_WARNINGS) + else + AC_MSG_ERROR([This version ($CC_VERSION) of the MSVC compiler is unsupported. See https://developer.mozilla.org/en/Windows_Build_Prerequisites.]) + fi + + _MOZ_RTTI_FLAGS_ON='-GR' + _MOZ_RTTI_FLAGS_OFF='-GR-' + _MOZ_EXCEPTIONS_FLAGS_ON='-EHsc' + _MOZ_EXCEPTIONS_FLAGS_OFF='' + + if test -n "$WIN32_REDIST_DIR"; then + WIN32_REDIST_DIR=`cd "$WIN32_REDIST_DIR" && pwd` + fi + + dnl Ensure that mt.exe is 'Microsoft (R) Manifest Tool', + dnl not something else like "magnetic tape manipulation utility". + MSMT_TOOL=`mt 2>&1|grep 'Microsoft (R) Manifest Tool'` + if test -z "$MSMT_TOOL"; then + AC_MSG_ERROR([Microsoft (R) Manifest Tool must be in your \$PATH.]) + fi + + changequote(,) + _MSMT_VER_FILTER='s|.* \([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*|\1|p' + changequote([,]) + MSMANIFEST_TOOL_VERSION=`echo ${MSMT_TOOL}|sed -ne "$_MSMT_VER_FILTER"` + if test -z "$MSMANIFEST_TOOL_VERSION"; then + AC_MSG_WARN([Unknown version of the Microsoft (R) Manifest Tool.]) + fi + + MSMANIFEST_TOOL=1 + unset MSMT_TOOL + + # Check linker version + _LD_FULL_VERSION=`"${LD}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"` + _LD_MAJOR_VERSION=`echo ${_LD_FULL_VERSION} | $AWK -F\. '{ print $1 }'` + if test "$_LD_MAJOR_VERSION" != "$_CC_SUITE"; then + AC_MSG_ERROR([The linker major version, $_LD_FULL_VERSION, does not match the compiler suite version, $_CC_SUITE.]) + fi + + INCREMENTAL_LINKER=1 + + # Identify which version of the SDK we're building with + # Windows Server 2008 and newer SDKs have WinSDKVer.h, get the version + # from there + AC_CHECK_HEADERS([winsdkver.h]) + if test "$ac_cv_header_winsdkver_h" = "yes"; then + # Get the highest _WIN32_WINNT and NTDDI versions supported + # Take the higher of the two + # This is done because the Windows 7 beta SDK reports its + # NTDDI_MAXVER to be 0x06000100 instead of 0x06010000, as it should + AC_CACHE_CHECK(for highest Windows version supported by this SDK, + ac_cv_winsdk_maxver, + [cat > conftest.h < +#include + +#if (NTDDI_VERSION_FROM_WIN32_WINNT(_WIN32_WINNT_MAXVER) > NTDDI_MAXVER) +#define WINSDK_MAXVER NTDDI_VERSION_FROM_WIN32_WINNT(_WIN32_WINNT_MAXVER) +#else +#define WINSDK_MAXVER NTDDI_MAXVER +#endif + +WINSDK_MAXVER +EOF + ac_cv_winsdk_maxver=`$CPP conftest.h 2>/dev/null | tail -n1` + rm -f conftest.h + ]) + MOZ_WINSDK_MAXVER=${ac_cv_winsdk_maxver} + else + # The Vista SDK is the only one to have sdkddkver.h but not + # WinSDKVer.h + AC_CHECK_HEADERS([sdkddkver.h]) + if test "$ac_cv_header_sdkddkver_h" = "yes"; then + MOZ_WINSDK_MAXVER=0x06000000 + else + # Assume the Server 2003 Platform SDK + MOZ_WINSDK_MAXVER=0x05020000 + fi + fi + + unset _MSVC_VER_FILTER + + AC_CACHE_CHECK(for std::_Throw, ac_cv_have_std__Throw, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + _SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="${CXXFLAGS} -D_HAS_EXCEPTIONS=0" + AC_TRY_COMPILE([#include ], + [std::_Throw(std::exception()); return 0;], + ac_cv_have_std__Throw="yes", + ac_cv_have_std__Throw="no") + CXXFLAGS="$_SAVE_CXXFLAGS" + AC_LANG_RESTORE + ]) + + if test "$ac_cv_have_std__Throw" == "yes"; then + AC_CACHE_CHECK(for |class __declspec(dllimport) exception| bug, + ac_cv_have_dllimport_exception_bug, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + _SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="${CXXFLAGS} -D_HAS_EXCEPTIONS=0" + AC_TRY_LINK([#include ], + [std::vector v; return v.at(1);], + ac_cv_have_dllimport_exception_bug="no", + ac_cv_have_dllimport_exception_bug="yes") + CXXFLAGS="$_SAVE_CXXFLAGS" + AC_LANG_RESTORE + ]) + if test "$ac_cv_have_dllimport_exception_bug" = "no"; then + WRAP_STL_INCLUDES=1 + MOZ_MSVC_STL_WRAP__Throw=1 + AC_DEFINE(MOZ_MSVC_STL_WRAP__Throw) + fi + else + AC_CACHE_CHECK(for overridable _RAISE, + ac_cv_have__RAISE, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + _SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="${CXXFLAGS} -D_HAS_EXCEPTIONS=0" + AC_TRY_COMPILE([#include + #undef _RAISE + #define _RAISE(x) externallyDefinedFunction((x).what()) + #include + ], + [std::vector v; return v.at(1);], + ac_cv_have__RAISE="no", + ac_cv_have__RAISE="yes") + CXXFLAGS="$_SAVE_CXXFLAGS" + AC_LANG_RESTORE + ]) + if test "$ac_cv_have__RAISE" = "yes"; then + WRAP_STL_INCLUDES=1 + MOZ_MSVC_STL_WRAP__RAISE=1 + AC_DEFINE(MOZ_MSVC_STL_WRAP__RAISE) + else + AC_MSG_ERROR([Gecko exception wrapping doesn't understand your your MSVC/SDK. Please file a bug describing this error and your build configuration.]) + fi + fi + + if test "$WRAP_STL_INCLUDES" = "1"; then + STL_FLAGS='-D_HAS_EXCEPTIONS=0 -I$(DIST)/stl_wrappers' + fi + else + # Check w32api version + _W32API_MAJOR_VERSION=`echo $W32API_VERSION | $AWK -F\. '{ print $1 }'` + _W32API_MINOR_VERSION=`echo $W32API_VERSION | $AWK -F\. '{ print $2 }'` + AC_MSG_CHECKING([for w32api version >= $W32API_VERSION]) + AC_TRY_COMPILE([#include ], + #if (__W32API_MAJOR_VERSION < $_W32API_MAJOR_VERSION) || \ + (__W32API_MAJOR_VERSION == $_W32API_MAJOR_VERSION && \ + __W32API_MINOR_VERSION < $_W32API_MINOR_VERSION) + #error "test failed." + #endif + , [ res=yes ], [ res=no ]) + AC_MSG_RESULT([$res]) + if test "$res" != "yes"; then + AC_MSG_ERROR([w32api version $W32API_VERSION or higher required.]) + fi + # Check windres version + AC_MSG_CHECKING([for windres version >= $WINDRES_VERSION]) + _WINDRES_VERSION=`${WINDRES} --version 2>&1 | grep -i windres 2>/dev/null | $AWK '{ print $3 }'` + AC_MSG_RESULT([$_WINDRES_VERSION]) + _WINDRES_MAJOR_VERSION=`echo $_WINDRES_VERSION | $AWK -F\. '{ print $1 }'` + _WINDRES_MINOR_VERSION=`echo $_WINDRES_VERSION | $AWK -F\. '{ print $2 }'` + _WINDRES_RELEASE_VERSION=`echo $_WINDRES_VERSION | $AWK -F\. '{ print $3 }'` + WINDRES_MAJOR_VERSION=`echo $WINDRES_VERSION | $AWK -F\. '{ print $1 }'` + WINDRES_MINOR_VERSION=`echo $WINDRES_VERSION | $AWK -F\. '{ print $2 }'` + WINDRES_RELEASE_VERSION=`echo $WINDRES_VERSION | $AWK -F\. '{ print $3 }'` + if test "$_WINDRES_MAJOR_VERSION" -lt "$WINDRES_MAJOR_VERSION" -o \ + "$_WINDRES_MAJOR_VERSION" -eq "$WINDRES_MAJOR_VERSION" -a \ + "$_WINDRES_MINOR_VERSION" -lt "$WINDRES_MINOR_VERSION" -o \ + "$_WINDRES_MAJOR_VERSION" -eq "$WINDRES_MAJOR_VERSION" -a \ + "$_WINDRES_MINOR_VERSION" -eq "$WINDRES_MINOR_VERSION" -a \ + "$_WINDRES_RELEASE_VERSION" -lt "$WINDRES_RELEASE_VERSION" + then + AC_MSG_ERROR([windres version $WINDRES_VERSION or higher is required to build.]) + fi + + # Server 2003 is the highest version supported + MOZ_WINSDK_MAXVER=0x05020000 + fi # !GNU_CC + + AC_DEFINE_UNQUOTED(WINVER,0x$WINVER) + AC_DEFINE_UNQUOTED(_WIN32_WINNT,0x$WINVER) + # Require OS features provided by IE 5.0 + AC_DEFINE_UNQUOTED(_WIN32_IE,0x0500) + + # If the maximum version supported by this SDK is lower than the target + # version, error out + AC_MSG_CHECKING([for Windows SDK being recent enough]) + if $PERL -e "exit(0x$MOZ_WINSDK_TARGETVER > $MOZ_WINSDK_MAXVER)"; then + AC_MSG_RESULT("yes") + else + AC_MSG_RESULT("no") + AC_MSG_ERROR([You are targeting Windows version 0x$MOZ_WINSDK_TARGETVER, but your SDK only supports up to version $MOZ_WINSDK_MAXVER. Install and use an updated SDK, or target a lower version using --with-windows-version. Alternatively, try running the Windows SDK Configuration Tool and selecting a newer SDK. See https://developer.mozilla.org/En/Windows_SDK_versions for more details on fixing this.]) + fi + + AC_DEFINE_UNQUOTED(MOZ_WINSDK_TARGETVER,0x$MOZ_WINSDK_TARGETVER) + # Definitions matching sdkddkver.h + AC_DEFINE_UNQUOTED(MOZ_NTDDI_WS03, 0x05020000) + AC_DEFINE_UNQUOTED(MOZ_NTDDI_LONGHORN, 0x06000000) + AC_DEFINE_UNQUOTED(MOZ_NTDDI_WIN7, 0x06010000) + ;; +esac + +dnl Test breaks icc on OS/2 && MSVC +if test "$CC" != "icc" -a -z "$_WIN32_MSVC"; then + AC_PROG_CC_C_O + if grep "NO_MINUS_C_MINUS_O 1" ./confdefs.h >/dev/null; then + USING_HCC=1 + _OLDCC=$CC + _OLDCXX=$CXX + CC="${srcdir}/build/hcc '$CC'" + CXX="${srcdir}/build/hcpp '$CXX'" + fi +fi + +AC_PROG_CPP +AC_PROG_CXXCPP + +if test -n "$_WIN32_MSVC"; then + SKIP_PATH_CHECKS=1 + SKIP_COMPILER_CHECKS=1 + SKIP_LIBRARY_CHECKS=1 + + # Since we're skipping compiler and library checks, hard-code + # some facts here. + + # Common to all MSVC environments: + # Windows lacks , but has __int8, and so on. + AC_DEFINE(JS_HAVE___INTN) + AC_DEFINE(HAVE_LOCALECONV) + + case "$target" in + *-wince|*-winmo) + AC_DEFINE(HAVE_SYSTEMTIMETOFILETIME) + AC_DEFINE(JS_CRTDEFS_H_HAS_INTPTR_T) + ;; + *) + AC_DEFINE(HAVE_SYSTEMTIMETOFILETIME) + AC_DEFINE(HAVE_GETSYSTEMTIMEASFILETIME) + # Windows defines intptr_t and uintptr_t. + # VS2005: http://msdn.microsoft.com/en-us/library/323b6b3k(VS.80).aspx + # VS2008: http://msdn.microsoft.com/en-us/library/323b6b3k.aspx + AC_DEFINE(JS_STDDEF_H_HAS_INTPTR_T) + ;; + esac +fi + +fi # COMPILE_ENVIRONMENT + +if test "$cross_compiling" = "yes"; then + CROSS_COMPILE=1 +else + CROSS_COMPILE= +fi + +# Check to see if we are running in a broken QEMU scratchbox. +# We know that anything below 1.0.16 is broken. +AC_CHECK_PROGS(SBCONF, sb-conf ve, "") +if test -n "$SBCONF"; then + _sb_version=`$SBCONF ve` + _sb_version_major=`echo $_sb_version | cut -f1 -d.` + _sb_version_minor=`echo $_sb_version | cut -f2 -d.` + _sb_version_point=`echo $_sb_version | cut -f3 -d.` + if test $_sb_version_major -eq 1 -a $_sb_version_minor -eq 0 -a $_sb_version_point -le 16; then + QEMU_CANT_RUN_JS_SHELL=1 + fi +fi +AC_SUBST(QEMU_CANT_RUN_JS_SHELL) + +AC_SUBST(_MSC_VER) + +AC_SUBST(GNU_AS) +AC_SUBST(GNU_LD) +AC_SUBST(GNU_CC) +AC_SUBST(GNU_CXX) +AC_SUBST(INTEL_CC) +AC_SUBST(INTEL_CXX) + +AC_SUBST(STL_FLAGS) +AC_SUBST(WRAP_STL_INCLUDES) +AC_SUBST(MOZ_MSVC_STL_WRAP__Throw) +AC_SUBST(MOZ_MSVC_STL_WRAP__RAISE) + +dnl ======================================================== +dnl Checks for programs. +dnl ======================================================== +AC_PROG_INSTALL +AC_PROG_LN_S + +if test -z "$TINDERBOX_SKIP_PERL_VERSION_CHECK"; then +AC_MSG_CHECKING([for minimum required perl version >= $PERL_VERSION]) +_perl_version=`PERL_VERSION=$PERL_VERSION $PERL -e 'print "$]"; if ($] >= $ENV{PERL_VERSION}) { exit(0); } else { exit(1); }' 2>&5` +_perl_res=$? +AC_MSG_RESULT([$_perl_version]) + +if test "$_perl_res" != 0; then + AC_MSG_ERROR([Perl $PERL_VERSION or higher is required.]) +fi +fi + +AC_MSG_CHECKING([for full perl installation]) +_perl_archlib=`$PERL -e 'use Config; if ( -d $Config{archlib} ) { exit(0); } else { exit(1); }' 2>&5` +_perl_res=$? +if test "$_perl_res" != 0; then + AC_MSG_RESULT([no]) + AC_MSG_ERROR([Cannot find Config.pm or \$Config{archlib}. A full perl installation is required.]) +else + AC_MSG_RESULT([yes]) +fi + +MOZ_PATH_PROGS(PYTHON, $PYTHON python2.7 python2.6 python2.5 python) +if test -z "$PYTHON"; then + AC_MSG_ERROR([python was not found in \$PATH]) +fi + +if test -z "$COMPILE_ENVIRONMENT"; then + NSINSTALL_BIN='$(PYTHON) $(topsrcdir)/config/nsinstall.py' +fi +AC_SUBST(NSINSTALL_BIN) + +MOZ_PATH_PROG(DOXYGEN, doxygen, :) +MOZ_PATH_PROG(AUTOCONF, autoconf, :) +MOZ_PATH_PROG(UNZIP, unzip, :) +MOZ_PATH_PROGS(ZIP, zip) +if test -z "$ZIP" -o "$ZIP" = ":"; then + AC_MSG_ERROR([zip not found in \$PATH]) +fi +MOZ_PATH_PROG(SYSTEM_MAKEDEPEND, makedepend) +MOZ_PATH_PROG(XARGS, xargs) +if test -z "$XARGS" -o "$XARGS" = ":"; then + AC_MSG_ERROR([xargs not found in \$PATH .]) +fi + +if test "$COMPILE_ENVIRONMENT"; then + +dnl ======================================================== +dnl = Mac OS X toolchain support +dnl ======================================================== + +case "$target_os" in +darwin*) + dnl Current known valid versions for GCC_VERSION are 2.95.2 3.1 3.3 4.0. + dnl 4.0 identifies itself as 4.0.x, so strip the decidecimal for + dnl the environment and includedir purposes (when using an SDK, below), + dnl but remember the full version number for the libdir (SDK). + changequote(,) + GCC_VERSION_FULL=`echo $CXX_VERSION | $PERL -pe 's/^.*gcc version ([^ ]*).*/$1/'` + GCC_VERSION=`echo $GCC_VERSION_FULL | $PERL -pe '(split(/\./))[0]>=4&&s/(^\d*\.\d*).*/$1/;'` + changequote([,]) + if test "$GCC_VERSION_FULL" = "4.0.0" ; then + dnl Bug 280479, but this keeps popping up in bug 292530 too because + dnl 4.0.0/4061 is the default compiler in Tiger. + changequote(,) + GCC_BUILD=`echo $CXX_VERSION | $PERL -pe 's/^.*build ([^ )]*).*/$1/'` + changequote([,]) + if test "$GCC_BUILD" = "4061" ; then + AC_MSG_ERROR([You are attempting to use Apple gcc 4.0 build 4061. +This compiler was supplied with Xcode 2.0, and contains bugs that prevent it +from building Mozilla. Upgrade to Xcode 2.1 or later.]) + fi + fi + + dnl xcodebuild needs GCC_VERSION defined in the environment, since it + dnl doesn't respect the CC/CXX setting. With GCC_VERSION set, it will use + dnl /usr/bin/g(cc|++)-$GCC_VERSION. + MOZ_PATH_PROGS(PBBUILD, pbbuild xcodebuild pbxbuild) + + case "$PBBUILD" in + *xcodebuild*) + changequote(,) + XCODEBUILD_VERSION=`$PBBUILD -version 2>/dev/null | xargs | sed -e 's/.*DevToolsCore-\([0-9]*\).*/\1/'` + changequote([,]) + if test -n "$XCODEBUILD_VERSION" && test "$XCODEBUILD_VERSION" -ge 620 ; then + HAS_XCODE_2_1=1; + fi + ;; + esac + + dnl sdp was formerly in /Developer/Tools. As of Mac OS X 10.4 (Darwin 8), + dnl it has moved into /usr/bin. + MOZ_PATH_PROG(SDP, sdp, :, [$PATH:/usr/bin:/Developer/Tools]) + ;; +esac + +AC_SUBST(GCC_VERSION) +AC_SUBST(XCODEBUILD_VERSION) +AC_SUBST(HAS_XCODE_2_1) + +dnl The universal machinery sets UNIVERSAL_BINARY to inform packager.mk +dnl that a universal binary is being produced. +AC_SUBST(UNIVERSAL_BINARY) + +dnl ======================================================== +dnl Check for MacOS deployment target version +dnl ======================================================== + +MOZ_ARG_ENABLE_STRING(macos-target, + [ --enable-macos-target=VER (default=10.5) + Set the minimum MacOS version needed at runtime], + [_MACOSX_DEPLOYMENT_TARGET=$enableval]) + +case "$target" in +*-darwin*) + if test -n "$_MACOSX_DEPLOYMENT_TARGET" ; then + dnl Use the specified value + export MACOSX_DEPLOYMENT_TARGET=$_MACOSX_DEPLOYMENT_TARGET + AC_DEFINE_UNQUOTED(__ENVIRONMENT_MAC_OS_X_VERION_MIN_REQUIRED__,$_MACOSX_DEPLOYMENT_TARGET) + else + dnl No value specified on the command line or in the environment, + dnl use architecture minimum. + case "${target_cpu}" in + ppc*) + export MACOSX_DEPLOYMENT_TARGET=10.5 + ;; + i*86) + export MACOSX_DEPLOYMENT_TARGET=10.5 + ;; + x86_64) + export MACOSX_DEPLOYMENT_TARGET=10.6 + ;; + esac + fi + ;; +esac + +AC_SUBST(MACOSX_DEPLOYMENT_TARGET) + +dnl ======================================================== +dnl = Mac OS X SDK support +dnl ======================================================== +MACOS_SDK_DIR= +NEXT_ROOT= +MOZ_ARG_WITH_STRING(macos-sdk, +[ --with-macos-sdk=dir Location of platform SDK to use (Mac OS X only)], + MACOS_SDK_DIR=$withval) + +dnl MACOS_SDK_DIR will be set to the SDK location whenever one is in use. +dnl NEXT_ROOT will be set and exported only if it's needed. +AC_SUBST(MACOS_SDK_DIR) +AC_SUBST(NEXT_ROOT) + +if test "$MACOS_SDK_DIR"; then + dnl Sync this section with the ones in NSPR and NSS. + dnl Changes to the cross environment here need to be accounted for in + dnl the libIDL checks (below) and xpidl build. + + if test ! -d "$MACOS_SDK_DIR"; then + AC_MSG_ERROR([SDK not found. When using --with-macos-sdk, you must +specify a valid SDK. SDKs are installed when the optional cross-development +tools are selected during the Xcode/Developer Tools installation.]) + fi + + GCC_VERSION_MAJOR=`echo $GCC_VERSION_FULL | $PERL -pe 's/(^\d*).*/$1/;'` + if test "$GCC_VERSION_MAJOR" -lt "4" ; then + AC_MSG_ERROR([You need to upgrade the compiler version to 4.x]) + else + CFLAGS="$CFLAGS -isysroot ${MACOS_SDK_DIR}" + CXXFLAGS="$CXXFLAGS -isysroot ${MACOS_SDK_DIR}" + + dnl CPP/CXXCPP needs to be set for AC_CHECK_HEADER. + CPP="$CPP -isysroot ${MACOS_SDK_DIR}" + CXXCPP="$CXXCPP -isysroot ${MACOS_SDK_DIR}" + + if test "$GCC_VERSION_FULL" = "4.0.0" ; then + dnl If gcc >= 4.0, we're guaranteed to be on Tiger, which has an ld + dnl that supports -syslibroot. Don't set NEXT_ROOT because it will + dnl be ignored and cause warnings when -syslibroot is specified. + dnl gcc 4.0.1 will pass -syslibroot to ld automatically based on + dnl the -isysroot it receives, so this is only needed with 4.0.0. + LDFLAGS="$LDFLAGS -Wl,-syslibroot,${MACOS_SDK_DIR}" + fi + fi + + AC_LANG_SAVE + AC_MSG_CHECKING([for valid compiler/Mac OS X SDK combination]) + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE([#include + int main() { return 0; }], + result=yes, + result=no) + AC_LANG_RESTORE + AC_MSG_RESULT($result) + + if test "$result" = "no" ; then + AC_MSG_ERROR([The selected compiler and Mac OS X SDK are incompatible.]) + fi +fi + +fi # COMPILE_ENVIRONMENT + +if test -n "$MAKE"; then + if test `echo $MAKE | grep -c make.py` != 1; then + NOT_PYMAKE=$MAKE + fi +fi + +case "$host_os" in +cygwin*|mingw*|mks*|msvc*) + MOZ_PATH_PROGS(GMAKE, $GMAKE $NOT_PYMAKE make gmake, :) + ;; +*) + MOZ_PATH_PROGS(GMAKE, $GMAKE $NOT_PYMAKE gmake make, :) + ;; +esac +if test "$GMAKE" = ":"; then + AC_MSG_ERROR([GNU make not found]) +fi +AC_SUBST(GMAKE) + +if test "$COMPILE_ENVIRONMENT"; then + +AC_PATH_XTRA + +XCFLAGS="$X_CFLAGS" + +fi # COMPILE_ENVIRONMENT + +dnl ======================================================== +dnl set the defaults first +dnl ======================================================== +AS_BIN=$AS +AR_LIST='$(AR) t' +AR_EXTRACT='$(AR) x' +AR_DELETE='$(AR) d' +AS='$(CC)' +AS_DASH_C_FLAG='-c' +DLL_PREFIX=lib +LIB_PREFIX=lib +DLL_SUFFIX=.so +OBJ_SUFFIX=o +LIB_SUFFIX=a +ASM_SUFFIX=s +IMPORT_LIB_SUFFIX= +TARGET_MD_ARCH=unix +DIRENT_INO=d_ino +CYGWIN_WRAPPER= +WIN_TOP_SRC= +MOZ_USER_DIR=".mozilla" + +MOZ_JS_LIBS='-L$(libdir) -lmozjs' +MOZ_FIX_LINK_PATHS='-Wl,-rpath-link,$(LIBXUL_DIST)/bin -Wl,-rpath-link,$(prefix)/lib' + +MOZ_COMPONENT_NSPR_LIBS='-L$(LIBXUL_DIST)/bin $(NSPR_LIBS)' + +USE_DEPENDENT_LIBS=1 + +_PLATFORM_DEFAULT_TOOLKIT=cairo-gtk2 + +if test -n "$CROSS_COMPILE"; then + OS_TARGET="${target_os}" + OS_ARCH=`echo $target_os | sed -e 's|/|_|g'` + OS_RELEASE= + case "${target_os}" in + linux*) OS_ARCH=Linux OS_TARGET=Linux ;; + kfreebsd*-gnu) OS_ARCH=GNU_kFreeBSD OS_TARGET=GNU_kFreeBSD ;; + gnu*) OS_ARCH=GNU ;; + solaris*) OS_ARCH=SunOS OS_RELEASE=5 ;; + mingw*) OS_ARCH=WINNT ;; + wince*) OS_ARCH=WINCE ;; + winmo*) OS_ARCH=WINCE ;; + darwin*) OS_ARCH=Darwin OS_TARGET=Darwin ;; + esac + case "${target}" in + arm-android-eabi) OS_ARCH=Linux OS_TARGET=Android ;; + esac +else + OS_TARGET=`uname -s` + OS_ARCH=`uname -s | sed -e 's|/|_|g'` + OS_RELEASE=`uname -r` +fi + +# Before this used `uname -m` when not cross compiling +# but that breaks when you have a 64 bit kernel with a 32 bit userland. +OS_TEST="${target_cpu}" + +_COMPILER_PREFIX= + +HOST_OS_ARCH=`echo $host_os | sed -e 's|/|_|g'` + +####################################################################### +# Master "Core Components" macros for getting the OS target # +####################################################################### + +# +# If OS_TARGET is not specified, it defaults to $(OS_ARCH), i.e., no +# cross-compilation. +# + +# +# Define and override various archtecture-specific variables, including +# HOST_OS_ARCH +# OS_ARCH +# OS_TEST +# OS_TARGET +# OS_RELEASE +# OS_MINOR_RELEASE +# + +case "$HOST_OS_ARCH" in +cygwin*|mingw*|mks*|msvc*) + HOST_OS_ARCH=WINNT + ;; +darwin*) + HOST_OS_ARCH=Darwin + ;; +linux*) + HOST_OS_ARCH=Linux + ;; +solaris*) + HOST_OS_ARCH=SunOS + SOLARIS_SUNPRO_CC= + SOLARIS_SUNPRO_CXX= + if test -z "$GNU_CC"; then + if test "`$CC -V 2>&1 | egrep -c 'Sun.*C '`" != "0"; then + SOLARIS_SUNPRO_CC=1 + fi + fi + + if test -z "$GNU_CXX"; then + if test "`$CXX -V 2>&1 | egrep -c 'Sun.*C\+\+ '`" != "0"; then + SOLARIS_SUNPRO_CXX=1 + fi + fi + AC_SUBST(SOLARIS_SUNPRO_CC) + AC_SUBST(SOLARIS_SUNPRO_CXX) + ;; +BSD_386) + HOST_OS_ARCH=BSD + ;; +dgux) + HOST_OS_ARCH=DGUX + ;; +IRIX64) + HOST_OS_ARCH=IRIX + ;; +UNIX_SV) + if "`cat /etc/bcheckrc | grep -c NCR 2>/dev/null`" != "0"; then + HOST_OS_ARCH=NCR + else + HOST_OS_ARCH=UNIXWARE + fi + ;; +ncr) + HOST_OS_ARCH=NCR + ;; +UNIX_SYSTEM_V) + HOST_OS_ARCH=NEC + ;; +OSF1) + ;; +*OpenVMS*) + HOST_OS_ARCH=OpenVMS + ;; +OS_2) + HOST_OS_ARCH=OS2 + ;; +QNX) + ;; +SCO_SV) + HOST_OS_ARCH=SCOOS + ;; +SINIX-N | SINIX-Y | SINIX-Z |ReliantUNIX-M) + HOST_OS_ARCH=SINIX + ;; +UnixWare) + HOST_OS_ARCH=UNIXWARE + ;; +esac + +case "$OS_ARCH" in +WINNT) + if test -z "$CROSS_COMPILE" ; then + OS_TEST=`uname -p` + fi + ;; +Windows_NT) +# +# If uname -s returns "Windows_NT", we assume that we are using +# the uname.exe in MKS toolkit. +# +# The -r option of MKS uname only returns the major version number. +# So we need to use its -v option to get the minor version number. +# Moreover, it doesn't have the -p option, so we need to use uname -m. +# + OS_ARCH=WINNT + OS_TARGET=WINNT + OS_MINOR_RELEASE=`uname -v` + if test "$OS_MINOR_RELEASE" = "00"; then + OS_MINOR_RELEASE=0 + fi + OS_RELEASE="${OS_RELEASE}.${OS_MINOR_RELEASE}" + ;; +CYGWIN32_NT|CYGWIN_NT*|MINGW*_NT*) +# +# If uname -s returns "CYGWIN_NT-4.0", we assume that we are using +# the uname.exe in the Cygwin tools. +# Prior to the Beta 20 release, Cygwin was called GNU-Win32. +# If uname -s returns "CYGWIN32/NT", we assume that we are using +# the uname.exe in the GNU-Win32 tools. +# If uname -s returns MINGW32_NT-5.1, we assume that we are using +# the uname.exe in the MSYS tools. +# + OS_RELEASE=`expr $OS_ARCH : '.*NT-\(.*\)'` + OS_ARCH=WINNT + OS_TARGET=WINNT + ;; +AIX) + OS_RELEASE=`uname -v`.`uname -r` + OS_TEST=${target_cpu} + if test -z "$GNU_CC"; then + if test "`$CC -qversion 2>&1 | egrep -c 'IBM XL'`" != "0"; then + AIX_IBM_XLC=1 + fi + fi + ;; +BSD_386) + OS_ARCH=BSD + ;; +dgux) + OS_ARCH=DGUX + ;; +IRIX64) + OS_ARCH=IRIX + ;; +UNIX_SV) + if "`cat /etc/bcheckrc | grep -c NCR 2>/dev/null`" != "0"; then + OS_ARCH=NCR + else + OS_ARCH=UNIXWARE + OS_RELEASE=`uname -v` + fi + ;; +ncr) + OS_ARCH=NCR + ;; +UNIX_SYSTEM_V) + OS_ARCH=NEC + ;; +OSF1) + case `uname -v` in + 148) + OS_RELEASE=V3.2C + ;; + 564) + OS_RELEASE=V4.0B + ;; + 878) + OS_RELEASE=V4.0D + ;; + esac + ;; +*OpenVMS*) + OS_ARCH=OpenVMS + OS_RELEASE=`uname -v` + OS_TEST=`uname -p` + ;; +OS_2) + OS_ARCH=OS2 + OS_TARGET=OS2 + OS_RELEASE=`uname -v` + ;; +QNX) + if test "$OS_TARGET" != "NTO"; then + changequote(,) + OS_RELEASE=`uname -v | sed 's/^\([0-9]\)\([0-9]*\)$/\1.\2/'` + changequote([,]) + fi + OS_TEST=x86 + ;; +SCO_SV) + OS_ARCH=SCOOS + OS_RELEASE=5.0 + ;; +SINIX-N | SINIX-Y | SINIX-Z |ReliantUNIX-M) + OS_ARCH=SINIX + OS_TEST=`uname -p` + ;; +UnixWare) + OS_ARCH=UNIXWARE + OS_RELEASE=`uname -v` + ;; +WINCE) + OS_ARCH=WINCE + case "${target_os}" in + *winmo) + OS_TARGET=WINMO + WINCE_WINDOWS_MOBILE=1 + AC_DEFINE(WINCE_WINDOWS_MOBILE) + ;; + *) + OS_TARGET=WINCE + ;; + esac + ;; +Darwin) + case "${target_cpu}" in + powerpc*) + OS_TEST=ppc + ;; + i*86*) + OS_TEST=i386 + ;; + x86_64) + OS_TEST=x86_64 + ;; + *) + if test -z "$CROSS_COMPILE" ; then + OS_TEST=`uname -p` + fi + ;; + esac + ;; +esac + +if test "$OS_ARCH" = "NCR"; then + changequote(,) + OS_RELEASE=`awk '{print $3}' /etc/.relid | sed 's/^\([0-9]\)\(.\)\(..\)\(.*\)$/\2.\3/'` + changequote([,]) +fi + +# Only set CPU_ARCH if we recognize the value of OS_TEST + +case "$OS_TEST" in +*86 | i86pc) + CPU_ARCH=x86 + ;; + +powerpc64 | ppc64) + CPU_ARCH=ppc64 + ;; + +powerpc | ppc | rs6000) + CPU_ARCH=ppc + ;; + +Alpha | alpha | ALPHA) + CPU_ARCH=Alpha + ;; + +s390) + CPU_ARCH=s390 + ;; + +s390x) + CPU_ARCH=s390x + ;; + +hppa* | parisc) + CPU_ARCH=hppa + ;; + +sun4u | sparc*) + CPU_ARCH=sparc + ;; + +x86_64 | ia64) + CPU_ARCH="$OS_TEST" + ;; + +arm*) + CPU_ARCH=arm + ;; + +mips|mipsel) + CPU_ARCH="mips" + ;; +esac + +if test -z "$OS_TARGET"; then + OS_TARGET=$OS_ARCH +fi +OS_CONFIG="${OS_TARGET}${OS_RELEASE}" + +dnl Set INTEL_ARCHITECTURE if we're compiling for x86-32 or x86-64. +dnl =============================================================== +INTEL_ARCHITECTURE= +case "$OS_TEST" in + x86_64|i?86) + INTEL_ARCHITECTURE=1 +esac + +dnl ======================================================== +dnl GNU specific defaults +dnl ======================================================== +if test "$GNU_CC"; then + # FIXME: Let us build with strict aliasing. bug 414641. + CFLAGS="$CFLAGS -fno-strict-aliasing" + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$@ -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$@ -o $@' + DSO_LDOPTS='-shared' + if test "$GCC_USE_GNU_LD"; then + # Don't allow undefined symbols in libraries + DSO_LDOPTS="$DSO_LDOPTS -Wl,-z,defs" + fi + WARNINGS_AS_ERRORS='-Werror' + DSO_CFLAGS='' + DSO_PIC_CFLAGS='-fPIC' + ASFLAGS="$ASFLAGS -fPIC" + _MOZ_RTTI_FLAGS_ON=${_COMPILER_PREFIX}-frtti + _MOZ_RTTI_FLAGS_OFF=${_COMPILER_PREFIX}-fno-rtti + _MOZ_EXCEPTIONS_FLAGS_ON='-fexceptions' + _MOZ_EXCEPTIONS_FLAGS_OFF='-fno-exceptions' + + # Turn on GNU specific features + # -Wall - turn on all warnings + # -pedantic - make compiler warn about non-ANSI stuff, and + # be a little bit stricter + # Warnings slamm took out for now (these were giving more noise than help): + # -Wbad-function-cast - warns when casting a function to a new return type + # -Wshadow - removed because it generates more noise than help --pete + _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall -W -Wno-unused -Wpointer-arith" + if test -z "$INTEL_CC"; then + # Don't use -Wcast-align with ICC + case "$CPU_ARCH" in + # And don't use it on hppa, ia64, sparc, arm, since it's noisy there + hppa | ia64 | sparc | arm) + ;; + *) + _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wcast-align" + ;; + esac + fi + + dnl Turn pedantic on but disable the warnings for long long + _PEDANTIC=1 + + if test -z "$INTEL_CC"; then + _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -W" + fi + + _DEFINES_CFLAGS='-include $(DEPTH)/js-confdefs.h -DMOZILLA_CLIENT' + _USE_CPP_INCLUDE_FLAG=1 +elif test "$SOLARIS_SUNPRO_CC"; then + DSO_CFLAGS='' + if test "$CPU_ARCH" = "sparc"; then + # for Sun Studio on Solaris/SPARC + DSO_PIC_CFLAGS='-xcode=pic32' + else + DSO_PIC_CFLAGS='-KPIC' + fi + _DEFINES_CFLAGS='$(ACDEFINES) -D_JS_CONFDEFS_H_ -DMOZILLA_CLIENT' +else + MKSHLIB='$(LD) $(DSO_LDOPTS) -h $@ -o $@' + MKCSHLIB='$(LD) $(DSO_LDOPTS) -h $@ -o $@' + + DSO_LDOPTS='-shared' + if test "$GNU_LD"; then + # Don't allow undefined symbols in libraries + DSO_LDOPTS="$DSO_LDOPTS -z defs" + fi + + DSO_CFLAGS='' + DSO_PIC_CFLAGS='-KPIC' + _DEFINES_CFLAGS='$(ACDEFINES) -D_JS_CONFDEFS_H_ -DMOZILLA_CLIENT' +fi + +if test "$GNU_CXX"; then + # FIXME: Let us build with strict aliasing. bug 414641. + CXXFLAGS="$CXXFLAGS -fno-strict-aliasing" + # Turn on GNU specific features + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual -Wsynth -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor" + if test -z "$INTEL_CC"; then + # Don't use -Wcast-align with ICC + case "$CPU_ARCH" in + # And don't use it on hppa, ia64, sparc, arm, since it's noisy there + hppa | ia64 | sparc | arm) + ;; + *) + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wcast-align" + ;; + esac + fi + + _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -include $(DEPTH)/js-confdefs.h' + _USE_CPP_INCLUDE_FLAG=1 + + AC_CACHE_CHECK(whether the compiler supports -Wno-invalid-offsetof, + ac_has_wno_invalid_offsetof, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + _SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS ${_COMPILER_PREFIX}-Wno-invalid-offsetof" + AC_TRY_COMPILE([], + [return(0);], + ac_has_wno_invalid_offsetof="yes", + ac_has_wno_invalid_offsetof="no") + CXXFLAGS="$_SAVE_CXXFLAGS" + AC_LANG_RESTORE + ]) + if test "$ac_has_wno_invalid_offsetof" = "yes"; then + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} ${_COMPILER_PREFIX}-Wno-invalid-offsetof" + fi + + AC_CACHE_CHECK(whether the compiler supports -Wno-variadic-macros, + ac_has_wno_variadic_macros, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + _SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS ${_COMPILER_PREFIX}-Wno-variadic-macros" + AC_TRY_COMPILE([], + [return(0);], + ac_has_wno_variadic_macros="yes", + ac_has_wno_variadic_macros="no") + CXXFLAGS="$_SAVE_CXXFLAGS" + AC_LANG_RESTORE + ]) + if test "$ac_has_wno_variadic_macros" = "yes"; then + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} ${_COMPILER_PREFIX}-Wno-variadic-macros" + fi + + AC_CACHE_CHECK(whether the compiler supports -Werror=return-type, + ac_has_werror_return_type, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + _SAVE_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -Werror=return-type" + AC_TRY_COMPILE([], + [return(0);], + ac_has_werror_return_type="yes", + ac_has_werror_return_type="no") + CXXFLAGS="$_SAVE_CXXFLAGS" + AC_LANG_RESTORE + ]) + if test "$ac_has_werror_return_type" = "yes"; then + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type" + fi + +else + _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -D_JS_CONFDEFS_H_ $(ACDEFINES)' +fi + +dnl gcc can come with its own linker so it is better to use the pass-thru calls +dnl MKSHLIB_FORCE_ALL is used to force the linker to include all object +dnl files present in an archive. MKSHLIB_UNFORCE_ALL reverts the linker to +dnl normal behavior. +dnl ======================================================== +MKSHLIB_FORCE_ALL= +MKSHLIB_UNFORCE_ALL= + +if test "$COMPILE_ENVIRONMENT"; then +if test "$GNU_CC"; then + AC_MSG_CHECKING(whether ld has archive extraction flags) + AC_CACHE_VAL(ac_cv_mkshlib_force_and_unforce, + [_SAVE_LDFLAGS=$LDFLAGS; _SAVE_LIBS=$LIBS + ac_cv_mkshlib_force_and_unforce="no" + exec 3<&0 </dev/null`" = 0; then + _pwd=`pwd` + CYGWIN_WRAPPER="${_pwd}/${srcdir}/build/cygwin-wrapper" + fi + if test "`${PERL} -v | grep -c cygwin 2>/dev/null`" = 0; then + AS_PERL=1 + PERL="${CYGWIN_WRAPPER} $PERL" + fi + + if test "`${PYTHON} -c 'import sys; print sys.platform;'`" != "cygwin"; then + PYTHON="${CYGWIN_WRAPPER} $PYTHON" + fi + ;; + esac + + case "${host_cpu}" in + x86_64) + HOST_CFLAGS="$HOST_CFLAGS -D_AMD64_" + ;; + esac + ;; + +*-darwin*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX -DXP_MACOSX -DNO_X11" + HOST_NSPR_MDCPUCFG='\"md/_darwin.cfg\"' + HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O3}" + ;; + +*-linux*|*-kfreebsd*-gnu|*-gnu*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX" + HOST_NSPR_MDCPUCFG='\"md/_linux.cfg\"' + HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O3}" + ;; + +*os2*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_OS2 -DNO_X11 -Zomf" + HOST_NSPR_MDCPUCFG='\"md/_os2.cfg\"' + HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O2}" + HOST_BIN_SUFFIX=.exe + MOZ_FIX_LINK_PATHS= + ;; + +*-osf*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX" + HOST_NSPR_MDCPUCFG='\"md/_osf1.cfg\"' + HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O2}" + ;; + +*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX" + HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O2}" + ;; +esac + +dnl We require version 2.4 or newer of Python to build, +dnl and 2.5 or newer on Windows. +AC_MSG_CHECKING([for Python version >= $PYTHON_VERSION but not 3.x]) +changequote(,) +$PYTHON -c "import sys; sys.exit(sys.version[:3] < sys.argv[1] or sys.version[:2] != '2.')" $PYTHON_VERSION +_python_res=$? +changequote([,]) +if test "$_python_res" != 0; then + AC_MSG_ERROR([Python $PYTHON_VERSION or higher (but not Python 3.x) is required.]) +fi +AC_MSG_RESULT([yes]) + +dnl ======================================================== +dnl System overrides of the defaults for target +dnl ======================================================== + +case "$target" in +*-aix*) + AC_DEFINE(AIX) + if test ! "$GNU_CC"; then + if test ! "$HAVE_64BIT_OS"; then + # Compiling with Visual Age C++ object model compat is the + # default. To compile with object model ibm, add + # AIX_OBJMODEL=ibm to .mozconfig. + if test "$AIX_OBJMODEL" = "ibm"; then + CXXFLAGS="$CXXFLAGS -qobjmodel=ibm" + else + AIX_OBJMODEL=compat + fi + else + AIX_OBJMODEL=compat + fi + AC_SUBST(AIX_OBJMODEL) + DSO_LDOPTS='-qmkshrobj=1' + DSO_CFLAGS='-qflag=w:w' + DSO_PIC_CFLAGS= + LDFLAGS="$LDFLAGS -Wl,-brtl -blibpath:/usr/lib:/lib" + MOZ_FIX_LINK_PATHS= + MKSHLIB='$(CXX) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + if test "$COMPILE_ENVIRONMENT"; then + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_MSG_CHECKING([for IBM XLC/C++ compiler version >= 9.0.0.7]) + AC_TRY_COMPILE([], + [#if (__IBMCPP__ < 900) + #error "Bad compiler" + #endif], + _BAD_COMPILER=,_BAD_COMPILER=1) + if test -n "$_BAD_COMPILER"; then + AC_MSG_RESULT([no]) + AC_MSG_ERROR([IBM XLC/C++ 9.0.0.7 or higher is required to build.]) + else + AC_MSG_RESULT([yes]) + fi + AC_LANG_RESTORE + TARGET_COMPILER_ABI="ibmc" + CC_VERSION=`lslpp -Lcq vac.C 2>/dev/null | awk -F: '{ print $3 }'` + CXX_VERSION=`lslpp -Lcq vacpp.cmp.core 2>/dev/null | awk -F: '{ print $3 }'` + fi + fi + case "${target_os}" in + aix4.1*) + DLL_SUFFIX='_shr.a' + ;; + esac + if test "$COMPILE_ENVIRONMENT"; then + AC_CHECK_HEADERS(sys/inttypes.h) + fi + AC_DEFINE(JS_SYS_TYPES_H_DEFINES_EXACT_SIZE_TYPES) + AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) + ;; + +*-beos*) + no_x=yes + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_LDOPTS) -Wl,-h,$@ -o $@' + _PLATFORM_DEFAULT_TOOLKIT="cairo-beos" + DSO_LDOPTS='-nostart' + TK_LIBS='-lbe -lroot' + LIBS="$LIBS -lbe" + if test "$COMPILE_ENVIRONMENT"; then + AC_CHECK_LIB(bind,main,LIBS="$LIBS -lbind") + AC_CHECK_LIB(zeta,main,LIBS="$LIBS -lzeta") + fi + _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-multichar" + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-multichar" + _MOZ_USE_RTTI=1 + USE_DEPENDENT_LIBS= + MOZ_USER_DIR="Mozilla" + ;; + +*-bsdi*) + dnl -pedantic doesn't play well with BSDI's _very_ modified gcc (shlicc2) + _PEDANTIC= + case $OS_RELEASE in + 4.*|5.*) + STRIP="$STRIP -d" + ;; + *) + DSO_CFLAGS='' + DSO_LDOPTS='-r' + _WARNINGS_CFLAGS="-Wall" + _WARNINGS_CXXFLAGS="-Wall" + # The test above doesn't work properly, at least on 3.1. + MKSHLIB_FORCE_ALL='' + MKSHLIB_UNFORCE_ALL='' + ;; + esac + ;; + +*-darwin*) + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + # If we're building with --enable-profiling, we need a frame pointer. + if test -z "$MOZ_PROFILING"; then + MOZ_OPTIMIZE_FLAGS="-O3 -fomit-frame-pointer" + else + MOZ_OPTIMIZE_FLAGS="-O3 -fno-omit-frame-pointer" + fi + _PEDANTIC= + CFLAGS="$CFLAGS -fpascal-strings -fno-common" + CXXFLAGS="$CXXFLAGS -fpascal-strings -fno-common" + DLL_SUFFIX=".dylib" + DSO_LDOPTS='' + STRIP="$STRIP -x -S" + _PLATFORM_DEFAULT_TOOLKIT='cairo-cocoa' + TARGET_NSPR_MDCPUCFG='\"md/_darwin.cfg\"' + LDFLAGS="$LDFLAGS -framework Cocoa -lobjc" + LIBXUL_LIBS='$(XPCOM_FROZEN_LDOPTS) $(LIBXUL_DIST)/bin/XUL' + # The ExceptionHandling framework is needed for Objective-C exception + # logging code in nsObjCExceptions.h. Currently we only use that in debug + # builds. + MOZ_DEBUG_LDFLAGS="$MOZ_DEBUG_LDFLAGS -framework ExceptionHandling" + + dnl DTrace and -dead_strip don't interact well. See bug 403132. + dnl =================================================================== + if test "x$enable_dtrace" = "xyes"; then + echo "Skipping -dead_strip because DTrace is enabled. See bug 403132." + else + dnl check for the presence of the -dead_strip linker flag + AC_MSG_CHECKING([for -dead_strip option to ld]) + _SAVE_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -Wl,-dead_strip" + AC_TRY_LINK(,[return 0;],_HAVE_DEAD_STRIP=1,_HAVE_DEAD_STRIP=) + if test -n "$_HAVE_DEAD_STRIP" ; then + AC_MSG_RESULT([yes]) + MOZ_OPTIMIZE_LDFLAGS="-Wl,-dead_strip" + else + AC_MSG_RESULT([no]) + fi + + LDFLAGS=$_SAVE_LDFLAGS + fi + MOZ_FIX_LINK_PATHS='-Wl,-executable_path,$(LIBXUL_DIST)/bin' + ;; + +*-freebsd*) + if test `test -x /usr/bin/objformat && /usr/bin/objformat || echo elf` != "elf"; then + DLL_SUFFIX=".so.1.0" + DSO_LDOPTS="-shared" + fi + if test ! "$GNU_CC"; then + DSO_LDOPTS="-Bshareable $DSO_LDOPTS" + fi + ;; + +ia64*-hpux*) + DLL_SUFFIX=".so" + if test ! "$GNU_CC"; then + DSO_LDOPTS='-b' + DSO_CFLAGS="" + DSO_PIC_CFLAGS= + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_LDOPTS) -o $@' + CXXFLAGS="$CXXFLAGS -Wc,-ansi_for_scope,on" + else + DSO_LDOPTS='-b -E' + MKSHLIB='$(LD) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(LD) $(DSO_LDOPTS) -o $@' + fi + MOZ_FIX_LINK_PATHS= + SYSTEM_MAKEDEPEND= + AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) + AC_DEFINE(_LARGEFILE64_SOURCE) + ;; + +*-hpux*) + DLL_SUFFIX=".sl" + if test ! "$GNU_CC"; then + DSO_LDOPTS='-b -Wl,+s' + DSO_CFLAGS="" + DSO_PIC_CFLAGS="+Z" + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_LDOPTS) -L$(LIBXUL_DIST)/bin -o $@' + MKCSHLIB='$(LD) -b +s -L$(LIBXUL_DIST)/bin -o $@' + CXXFLAGS="$CXXFLAGS -Wc,-ansi_for_scope,on" + else + DSO_LDOPTS='-b -E +s' + MKSHLIB='$(LD) $(DSO_LDOPTS) -L$(LIBXUL_DIST)/bin -L$(LIBXUL_DIST)/lib -o $@' + MKCSHLIB='$(LD) $(DSO_LDOPTS) -L$(LIBXUL_DIST)/bin -L$(LIBXUL_DIST)/lib -o $@' + fi + MOZ_POST_PROGRAM_COMMAND='chatr +s enable' + AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) + ;; + +*-irix5*) + AC_DEFINE(IRIX) + DSO_LDOPTS='-elf -shared' + + if test "$GNU_CC"; then + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + MKSHLIB_FORCE_ALL='-Wl,-all' + MKSHLIB_UNFORCE_ALL='-Wl,-none' + CXXFLAGS="$CXXFLAGS -D_LANGUAGE_C_PLUS_PLUS" + else + MKSHLIB='$(LD) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(LD) $(DSO_LDOPTS) -o $@' + MKSHLIB_FORCE_ALL='-all' + MKSHLIB_UNFORCE_ALL='-none' + fi + ;; + +*-irix6*) + AC_DEFINE(IRIX) + dnl the irix specific xptcinvoke code is written against the n32 ABI so we *must* + dnl compile and link using -n32 + USE_N32=1 + TARGET_COMPILER_ABI=n32 + DSO_LDOPTS='-elf -shared' + MKSHLIB='$(CCC) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + _MOZ_EXCEPTIONS_FLAGS_OFF="-LANG:exceptions=OFF" + _MOZ_EXCEPTIONS_FLAGS_ON="-LANG:exceptions=ON" + if test "$GNU_CC"; then + MKSHLIB_FORCE_ALL='-Wl,-all' + MKSHLIB_UNFORCE_ALL='-Wl,-none' + _WARNINGS_CFLAGS="-Wall" + _WARNINGS_CXXFLAGS="-Wall" + CXXFLAGS="$CXXFLAGS -D_LANGUAGE_C_PLUS_PLUS" + else + MKSHLIB_FORCE_ALL='-all' + MKSHLIB_UNFORCE_ALL='-none' + AR_LIST="$AR t" + AR_EXTRACT="$AR x" + AR_DELETE="$AR d" + AR='$(CXX) -ar' + AR_FLAGS='-o $@' + CFLAGS="$CFLAGS -woff 3262 -G 4" + CXXFLAGS="$CXXFLAGS -woff 3262 -G 4" + if test -n "$USE_N32"; then + ASFLAGS="$ASFLAGS -n32" + CFLAGS="$CFLAGS -n32" + CXXFLAGS="$CXXFLAGS -n32" + LDFLAGS="$LDFLAGS -n32" + fi + AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) + AC_MSG_WARN([Clearing MOZ_FIX_LINK_PATHS for OSF/1 as fix for bug 333545 (till the reference bug 332075 is fixed.]) + MOZ_FIX_LINK_PATHS= + fi + if test -z "$GNU_CXX"; then + MIPSPRO_CXX=1 + fi + ;; + +*-*linux*) + # Note: both GNU_CC and INTEL_CC are set when using Intel's C compiler. + # Similarly for GNU_CXX and INTEL_CXX. + if test "$INTEL_CC" -o "$INTEL_CXX"; then + # -Os has been broken on Intel's C/C++ compilers for quite a + # while; Intel recommends against using it. + MOZ_OPTIMIZE_FLAGS="-O2" + MOZ_DEBUG_FLAGS="-g" + elif test "$GNU_CC" -o "$GNU_CXX"; then + GCC_VERSION=`$CC -v 2>&1 | awk '/^gcc version/ { print $3 }'` + case $GCC_VERSION in + 4.1.*|4.2.*|4.5.*) + # -Os is broken on gcc 4.1.x 4.2.x, 4.5.x we need to tweak it to get good results. + MOZ_OPTIMIZE_SIZE_TWEAK="-finline-limit=50" + esac + # If we're building with --enable-profiling, we need a frame pointer. + if test -z "$MOZ_PROFILING"; then + MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fomit-frame-pointer $MOZ_OPTIMIZE_SIZE_TWEAK" + else + MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-omit-frame-pointer $MOZ_OPTIMIZE_SIZE_TWEAK" + fi + MOZ_DEBUG_FLAGS="-g" + fi + + TARGET_NSPR_MDCPUCFG='\"md/_linux.cfg\"' + + case "${target_cpu}" in + alpha*) + CFLAGS="$CFLAGS -mieee" + CXXFLAGS="$CXXFLAGS -mieee" + ;; + mips*) + MOZ_DEBUG_FLAGS="-g" # We want inlining + ;; + esac + ;; + +*-wince*|*-winmo*) + TARGET_COMPILER_ABI=msvc + MOZ_TOOLS_DIR=`echo $MOZ_TOOLS` + AR_LIST="$AR -list" + AR_EXTRACT="$AR -extract" + AR_DELETE="$AR d" + AR_FLAGS='-OUT:"$@"' + AS="$AS_BIN" + + DSO_CFLAGS= + DSO_PIC_CFLAGS= + DLL_SUFFIX=.dll + BIN_SUFFIX='.exe' + if test -z "$RC"; then + RC=rc.exe + fi + # certain versions of cygwin's makedepend barf on the + # #include vs -I./dist/include/string issue so don't use it + SYSTEM_MAKEDEPEND= + + HOST_CC=cl + HOST_CXX=cl + HOST_LD=link + HOST_AR='lib -OUT:$@' + HOST_RANLIB='echo ranlib' + HOST_CFLAGS="$HOST_CFLAGS -D_X86_" + + + WARNINGS_AS_ERRORS='-WX' + MOZ_OPTIMIZE_FLAGS='-Ox' + AR_FLAGS='-NOLOGO -OUT:"$@"' + ASM_SUFFIX=asm + CFLAGS="$CFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)" + CXXFLAGS="$CXXFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)" + DLL_PREFIX= + DOXYGEN=: + DSO_LDOPTS=-SUBSYSTEM:WINDOWSCE + DYNAMIC_XPCOM_LIBS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xpcom_core.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + GARBAGE= + IMPORT_LIB_SUFFIX=lib + dnl Need to force-link against mozalloc because it's used in the shunt + LIBS="$LIBS \$(LIBXUL_DIST)/lib/mozalloc.lib" + LIBXUL_LIBS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xul.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + LIB_PREFIX= + LIB_SUFFIX=lib + MKCSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ $(DSO_LDOPTS)' + MKSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ $(DSO_LDOPTS)' + MKSHLIB_FORCE_ALL= + MKSHLIB_UNFORCE_ALL= + MOZ_COMPONENT_NSPR_LIBS='$(NSPR_LIBS)' + MOZ_COMPONENT_NSPR_LIBS='$(NSPR_LIBS)' + MOZ_DEBUG_FLAGS='-Zi' + MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV' + MOZ_FIX_LINK_PATHS= + MOZ_JS_LIBS='$(libdir)/mozjs.lib' + OBJ_SUFFIX=obj + RANLIB='echo not_ranlib' + STRIP='echo not_strip' + TARGET_NSPR_MDCPUCFG='\"md/_wince.cfg\"' + UNZIP=unzip + XARGS=xargs + XPCOM_FROZEN_LDOPTS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + ZIP=zip + + AC_DEFINE(HAVE_SNPRINTF) + AC_DEFINE(_WINDOWS) + AC_DEFINE(WIN32) + AC_DEFINE(XP_WIN) + AC_DEFINE(XP_WIN32) + AC_DEFINE(HW_THREADS) + AC_DEFINE(STDC_HEADERS) + AC_DEFINE(NEW_H, ) + AC_DEFINE(WIN32_LEAN_AND_MEAN) + AC_DEFINE(HAVE_LOCALTIME_R) + + TARGET_MD_ARCH=win32 + _PLATFORM_DEFAULT_TOOLKIT='cairo-windows' + BIN_SUFFIX='.exe' + MOZ_USER_DIR="Mozilla" + + dnl Default to Windows Mobile components enabled + WINCE_WINDOWS_MOBILE=1 + + MOZ_ARG_DISABLE_BOOL(windows-mobile-components, + [ --disable-windows-mobile-components + Disable Windows Mobile specific components from + CE build], + WINCE_WINDOWS_MOBILE=, + WINCE_WINDOWS_MOBILE=1) + + if test "$WINCE_WINDOWS_MOBILE"; then + AC_DEFINE(WINCE_WINDOWS_MOBILE) + fi +;; + +*-symbian*) + + AC_DEFINE(XP_UNIX) + AC_DEFINE(SYMBIAN) + AC_DEFINE(__arm__) + AC_DEFINE(__SYMBIAN32__) + AC_DEFINE(_UNICODE) + AC_DEFINE(NDEBUG) + AC_DEFINE(__SUPPORT_CPP_EXCEPTIONS__) + AC_DEFINE(MOZ_STDERR_TO_STDOUT) + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + AC_DEFINE(HAVE_SOCKLEN_T) + AC_DEFINE(__GCCE__) + + CPU_ARCH=ARM + OS_RELEASE=9.2 + OS_ARCH=SYMBIAN + USE_PTHREADS=1 + LIB_SUFFIX=lib + DLL_SUFFIX=dll + MKSHLIB= + DSO_LDOPTS= + DSO_CFLAGS= + VISIBILITY_FLAGS= + TARGET_NSPR_MDCPUCFG='\"md/_symbian.cfg\"' + RANLIB='echo no ranlib ' +;; + +*-mingw*|*-cygwin*|*-msvc*|*-mks*) + DSO_CFLAGS= + DSO_PIC_CFLAGS= + DLL_SUFFIX=.dll + RC=rc.exe + # certain versions of cygwin's makedepend barf on the + # #include vs -I./dist/include/string issue so don't use it + SYSTEM_MAKEDEPEND= + if test -n "$GNU_CC"; then + CC="$CC -mno-cygwin" + CXX="$CXX -mno-cygwin" + CPP="$CPP -mno-cygwin" + CFLAGS="$CFLAGS -mms-bitfields" + CXXFLAGS="$CXXFLAGS -mms-bitfields" + DSO_LDOPTS='-shared' + MKSHLIB='$(CXX) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + RC='$(WINDRES)' + # Use temp file for windres (bug 213281) + RCFLAGS='-O coff --use-temp-file' + # mingw doesn't require kernel32, user32, and advapi32 explicitly + LIBS="$LIBS -lgdi32 -lwinmm -lwsock32" + MOZ_JS_LIBS='-L$(libdir) -lmozjs' + MOZ_FIX_LINK_PATHS= + DYNAMIC_XPCOM_LIBS='-L$(LIBXUL_DIST)/lib -lxpcom -lxpcom_core -lmozalloc' + XPCOM_FROZEN_LDOPTS='-L$(LIBXUL_DIST)/lib -lxpcom -lmozalloc' + DLL_PREFIX= + IMPORT_LIB_SUFFIX=dll.a + GCC_VERSION=`$CC -v 2>&1 | awk '/^gcc version/ { print $3 }'` + else + TARGET_COMPILER_ABI=msvc + HOST_CC='$(CC)' + HOST_CXX='$(CXX)' + HOST_LD='$(LD)' + if test "$AS_BIN"; then + AS="$(basename "$AS_BIN")" + fi + AR='lib -NOLOGO -OUT:"$@"' + AR_FLAGS= + RANLIB='echo not_ranlib' + STRIP='echo not_strip' + PKG_SKIP_STRIP=1 + XARGS=xargs + ZIP=zip + UNZIP=unzip + DOXYGEN=: + GARBAGE='$(OBJDIR)/vc20.pdb $(OBJDIR)/vc40.pdb' + ASM_SUFFIX=asm + OBJ_SUFFIX=obj + LIB_SUFFIX=lib + DLL_PREFIX= + LIB_PREFIX= + IMPORT_LIB_SUFFIX=lib + MKSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)' + MKCSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)' + MKSHLIB_FORCE_ALL= + MKSHLIB_UNFORCE_ALL= + DSO_LDOPTS=-SUBSYSTEM:WINDOWS + _USE_CPP_INCLUDE_FLAG=1 + _DEFINES_CFLAGS='-FI $(DEPTH)/js-confdefs.h -DMOZILLA_CLIENT' + _DEFINES_CXXFLAGS='-FI $(DEPTH)/js-confdefs.h -DMOZILLA_CLIENT' + CFLAGS="$CFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)" + CXXFLAGS="$CXXFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)" + # MSVC warnings C4244 and C4800 are ubiquitous, useless, and annoying. + CXXFLAGS="$CXXFLAGS -wd4244 -wd4800" + LIBS="$LIBS kernel32.lib user32.lib gdi32.lib winmm.lib wsock32.lib advapi32.lib" + MOZ_DEBUG_FLAGS='-Zi' + MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV' + WARNINGS_AS_ERRORS='-WX' + # If we're building with --enable-profiling, we need -Oy-, which forces a frame pointer. + if test -z "$MOZ_PROFILING"; then + MOZ_OPTIMIZE_FLAGS='-O1' + else + MOZ_OPTIMIZE_FLAGS='-O1 -Oy-' + fi + MOZ_JS_LIBS='$(libdir)/mozjs.lib' + MOZ_FIX_LINK_PATHS= + DYNAMIC_XPCOM_LIBS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xpcom_core.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + XPCOM_FROZEN_LDOPTS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + LIBXUL_LIBS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xul.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + MOZ_COMPONENT_NSPR_LIBS='$(NSPR_LIBS)' + if test $_MSC_VER -ge 1400; then + LDFLAGS="$LDFLAGS -LARGEADDRESSAWARE -NXCOMPAT" + dnl For profile-guided optimization + PROFILE_GEN_CFLAGS="-GL" + PROFILE_GEN_LDFLAGS="-LTCG:PGINSTRUMENT" + dnl XXX: PGO builds can fail with warnings treated as errors, + dnl specifically "no profile data available" appears to be + dnl treated as an error sometimes. This might be a consequence + dnl of using WARNINGS_AS_ERRORS in some modules, combined + dnl with the linker doing most of the work in the whole-program + dnl optimization/PGO case. I think it's probably a compiler bug, + dnl but we work around it here. + PROFILE_USE_CFLAGS="-GL -wd4624 -wd4952" + dnl XXX: should be -LTCG:PGOPTIMIZE, but that fails on libxul. + dnl Probably also a compiler bug, but what can you do? + PROFILE_USE_LDFLAGS="-LTCG:PGUPDATE" + LDFLAGS="$LDFLAGS -DYNAMICBASE" + fi + fi + AC_DEFINE(HAVE_SNPRINTF) + AC_DEFINE(_WINDOWS) + AC_DEFINE(WIN32) + AC_DEFINE(XP_WIN) + AC_DEFINE(XP_WIN32) + AC_DEFINE(HW_THREADS) + AC_DEFINE(STDC_HEADERS) + AC_DEFINE(NEW_H, ) + AC_DEFINE(WIN32_LEAN_AND_MEAN) + TARGET_MD_ARCH=win32 + _PLATFORM_DEFAULT_TOOLKIT='cairo-windows' + BIN_SUFFIX='.exe' + MOZ_USER_DIR="Mozilla" + + dnl Hardcode to win95 for now - cls + TARGET_NSPR_MDCPUCFG='\"md/_win95.cfg\"' + + dnl set NO_X11 defines here as the general check is skipped on win32 + no_x=yes + AC_DEFINE(NO_X11) + + dnl MinGW/MSYS doesn't provide or need cygpath + case "$host" in + *-mingw*) + CYGPATH_W=echo + CYGPATH_S=cat + MOZ_BUILD_ROOT=`cd $MOZ_BUILD_ROOT && pwd -W` + ;; + *-cygwin*|*-msvc*|*-mks*) + CYGPATH_W="cygpath -a -w" + CYGPATH_S="sed -e s|\\\\|/|g" + MOZ_BUILD_ROOT=`$CYGPATH_W $MOZ_BUILD_ROOT | $CYGPATH_S` + ;; + esac + case "$host" in + *-mingw*|*-cygwin*|*-msvc*|*-mks*) + + if test -z "$MOZ_TOOLS"; then + AC_MSG_ERROR([MOZ_TOOLS is not set]) + fi + + MOZ_TOOLS_DIR=`cd $MOZ_TOOLS && pwd -W` + if test "$?" != "0" -o -z "$MOZ_TOOLS_DIR"; then + AC_MSG_ERROR([cd \$MOZ_TOOLS failed. MOZ_TOOLS ==? $MOZ_TOOLS]) + fi + MOZ_TOOLS_BIN_DIR="$(cd "$MOZ_TOOLS_DIR/bin" && pwd)" + if test `echo ${PATH}: | grep -ic "$MOZ_TOOLS_BINDIR:"` = 0; then + AC_MSG_ERROR([\$MOZ_TOOLS\\bin must be in your path.]) + fi + MOZ_TOOLS_DIR=`$CYGPATH_W $MOZ_TOOLS_DIR | $CYGPATH_S` + ;; + esac + + + case "$host_os" in + cygwin*|msvc*|mks*) + AC_MSG_WARN([Using a cygwin build environment is unsupported. Configure cannot check for the presence of necessary headers. Please upgrade to MozillaBuild; see https://developer.mozilla.org/en/Windows_Build_Prerequisites.]) + ;; + esac + + case "$target" in + i*86-*) + if test "$HAVE_64BIT_OS"; then + AC_MSG_ERROR([You are targeting i386 but using the 64-bit compiler.]) + fi + + if test $_MSC_VER -ge 1400; then + LDFLAGS="$LDFLAGS -SAFESEH" + fi + + if test -n "$GNU_CC"; then + CFLAGS="$CFLAGS -mstackrealign" + CXXFLAGS="$CXXFLAGS -mstackrealign" + fi + + AC_CHECK_HEADERS(mmintrin.h) + AC_DEFINE(_X86_) + ;; + alpha-*) + AC_DEFINE(_ALPHA_) + ;; + mips-*) + AC_DEFINE(_MIPS_) + ;; + x86_64-*) + AC_DEFINE(_AMD64_) + ;; + *) + AC_DEFINE(_CPU_ARCH_NOT_DEFINED) + ;; + esac + + if test "$HAVE_64BIT_OS"; then + AC_DEFINE(_WIN64) + fi + ;; + +*-netbsd*) + DSO_CFLAGS='' + CFLAGS="$CFLAGS -Dunix" + CXXFLAGS="$CXXFLAGS -Dunix" + if $CC -E - -dM /dev/null; then + DLL_SUFFIX=".so" + DSO_PIC_CFLAGS='-fPIC -DPIC' + DSO_LDOPTS='-shared' + BIN_FLAGS='-Wl,--export-dynamic' + else + DSO_PIC_CFLAGS='-fPIC -DPIC' + DLL_SUFFIX=".so.1.0" + DSO_LDOPTS='-shared' + fi + # This will fail on a.out systems prior to 1.5.1_ALPHA. + MKSHLIB_FORCE_ALL='-Wl,--whole-archive' + MKSHLIB_UNFORCE_ALL='-Wl,--no-whole-archive' + if test "$LIBRUNPATH"; then + DSO_LDOPTS="-Wl,-R$LIBRUNPATH $DSO_LDOPTS" + fi + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-soname,lib$(LIBRARY_NAME)$(DLL_SUFFIX) -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-soname,lib$(LIBRARY_NAME)$(DLL_SUFFIX) -o $@' + ;; + +*-nto*) + AC_DEFINE(NTO) + AC_DEFINE(_QNX_SOURCE) + AC_DEFINE(_i386) + OS_TARGET=NTO + WARNINGS_AS_ERRORS='' + MOZ_OPTIMIZE_FLAGS="-O" + MOZ_DEBUG_FLAGS="-gstabs" + USE_PTHREADS=1 + _PEDANTIC= + LIBS="$LIBS -lsocket -lstdc++" + _DEFINES_CFLAGS='-include $(DEPTH)/js-confdefs.h -DMOZILLA_CLIENT -D_POSIX_C_SOURCE=199506' + _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -include $(DEPTH)/js-confdefs.h -D_POSIX_C_SOURCE=199506' + if test "$with_x" != "yes" + then + _PLATFORM_DEFAULT_TOOLKIT="photon" + TK_CFLAGS='-I/usr/include/photon' + TK_LIBS='-lph' + fi + case "${target_cpu}" in + ppc*) + AC_DEFINE(HAVE_VA_LIST_AS_ARRAY) + ;; + esac + ;; + +*-openbsd*) + DLL_SUFFIX=".so.1.0" + DSO_CFLAGS='' + DSO_PIC_CFLAGS='-fPIC' + DSO_LDOPTS='-shared -fPIC' + if test "$LIBRUNPATH"; then + DSO_LDOPTS="-R$LIBRUNPATH $DSO_LDOPTS" + fi + ;; + +*-openvms*) + AC_DEFINE(NO_PW_GECOS) + AC_DEFINE(NO_UDSOCK) + AC_DEFINE(POLL_WITH_XCONNECTIONNUMBER) + USE_PTHREADS=1 + MKSHLIB_FORCE_ALL='-all' + MKSHLIB_UNFORCE_ALL='-none' + AS='as' + AS_DASH_C_FLAG='-Wc/names=as_is' + AR_FLAGS='c $@' + DSO_LDOPTS='-shared -auto_symvec' + DSO_PIC_CFLAGS= + MOZ_DEBUG_LDFLAGS='-g' + COMPAQ_CXX=1 + CC_VERSION=`$CC -V 2>&1 | awk '/ C / { print $3 }'` + CXX_VERSION=`$CXX -V 2>&1 | awk '/ C\+\+ / { print $3 }'` + ;; + + +*-os2*) + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' + AC_DEFINE(OS2) + AC_DEFINE(XP_OS2) + AC_DEFINE(OS2EMX_PLAIN_CHAR) + AC_DEFINE(TCPV40HDRS) + DLL_PREFIX= + LIB_PREFIX= + LIB_SUFFIX=lib + BIN_SUFFIX=".exe" + DLL_SUFFIX=".dll" + IMPORT_LIB_SUFFIX=lib + DSO_PIC_CFLAGS= + AR=emxomfar + AR_FLAGS='r $@' + CFLAGS="$CFLAGS -Zomf" + CXXFLAGS="$CXXFLAGS -Zomf" + DSO_LDOPTS='-Zdll' + BIN_FLAGS='-Zlinker /ST:0x100000' + IMPLIB='emximp -o' + FILTER='true' + LDFLAGS='-Zmap' + WARNINGS_AS_ERRORS='-Werror' + MOZ_DEBUG_FLAGS="-g -fno-inline" + MOZ_OPTIMIZE_FLAGS="-O2" + MOZ_OPTIMIZE_LDFLAGS="-s -Zlinker /EXEPACK:2 -Zlinker /PACKCODE -Zlinker /PACKDATA" + DYNAMIC_XPCOM_LIBS='-L$(LIBXUL_DIST)/lib $(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xpcom_core.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + LIBXUL_LIBS='-L$(LIBXUL_DIST)/lib $(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xul.lib $(LIBXUL_DIST)/lib/mozalloc.lib' + TARGET_MD_ARCH=os2 + _PLATFORM_DEFAULT_TOOLKIT="cairo-os2" + RC=rc.exe + RCFLAGS='-n' + MOZ_USER_DIR="Mozilla" + + if test "$MOZTOOLS"; then + MOZ_TOOLS_DIR=`echo $MOZTOOLS | sed -e 's|\\\\|/|g'` + else + AC_MSG_ERROR([MOZTOOLS is not set]) + fi + if test -n "$MOZ_OS2_HIGH_MEMORY"; then + DSO_LDOPTS="$DSO_LDOPTS -Zhigh-mem" + LDFLAGS="$LDFLAGS -Zhigh-mem" + MOZ_OPTIMIZE_LDFLAGS="$MOZ_OPTIMIZE_LDFLAGS -Zhigh-mem" + AC_DEFINE(MOZ_OS2_HIGH_MEMORY) + fi + + # GCC for OS/2 currently predefines these, but we don't want them + _DEFINES_CFLAGS="$_DEFINES_CFLAGS -Uunix -U__unix -U__unix__" + _DEFINES_CXXFLAGS="$_DEFINES_CXXFLAGS -Uunix -U__unix -U__unix__" + + AC_CACHE_CHECK(for __declspec(dllexport), + ac_os2_declspec, + [AC_TRY_COMPILE([__declspec(dllexport) void ac_os2_declspec(void) {}], + [return 0;], + ac_os2_declspec="yes", + ac_os2_declspec="no")]) + if test "$ac_os2_declspec" != "yes"; then + AC_MSG_ERROR([Compiler does not support __declspec(dllexport), install GCC-4.3.2 or newer]) + fi + ;; + +alpha*-*-osf*) + if test "$GNU_CC"; then + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-soname,$@ -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-soname,$@ -o $@' + + else + MOZ_DEBUG_FLAGS='-g' + ASFLAGS='-I$(topsrcdir)/xpcom/reflect/xptcall/public -g' + CFLAGS="$CFLAGS -ieee" + CXXFLAGS="$CXXFLAGS "'-noexceptions -ieee -ptr $(DIST)/cxx_repository' + DSO_LDOPTS='-shared -msym -expect_unresolved \* -update_registry $(DIST)/so_locations' + DSO_CFLAGS= + DSO_PIC_CFLAGS= + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -soname $@ -o $@' + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -soname $@ -o $@' + MKSHLIB_FORCE_ALL='-all' + MKSHLIB_UNFORCE_ALL='-none' + dnl Might fix the libxpcom.so breakage on this platform as well.... + AC_DEFINE(NSCAP_DISABLE_TEST_DONTQUERY_CASES) + AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) + fi + if test -z "$GNU_CXX"; then + COMPAQ_CXX=1 + fi + AC_DEFINE(NEED_USLEEP_PROTOTYPE) + ;; + +*-qnx*) + DIRENT_INO=d_stat.st_ino + dnl Solves the problems the QNX compiler has with nsCOMPtr.h. + AC_DEFINE(NSCAP_DISABLE_TEST_DONTQUERY_CASES) + AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) + dnl Explicit set STDC_HEADERS to workaround QNX 6.0's failing of std test + AC_DEFINE(STDC_HEADERS) + if test "$no_x" = "yes"; then + _PLATFORM_DEFAULT_TOOLKIT='photon' + TK_CFLAGS='-I/usr/nto/include/photon' + TK_LIBS='-lphoton -lphrender' + fi + ;; + +*-sco*) + AC_DEFINE(NSCAP_DISABLE_TEST_DONTQUERY_CASES) + AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) + CXXFLAGS="$CXXFLAGS -I/usr/include/CC" + if test ! "$GNU_CC"; then + DSO_LDOPTS='-G' + fi + ;; + +*-solaris*) + AC_DEFINE(SOLARIS) + TARGET_NSPR_MDCPUCFG='\"md/_solaris.cfg\"' + if test -z "$CROSS_COMPILE" && pkginfo -q SUNWpr && pkginfo -q SUNWprd; then + NO_NSPR_CONFIG_SYSTEM_LDFLAGS="-L/usr/lib/mps -R/usr/lib/mps -lnspr4" + NO_NSPR_CONFIG_SYSTEM_CFLAGS="-I/usr/include/mps" + NO_NSPR_CONFIG_SYSTEM_VERSION=["`pkgparam SUNWpr SUNW_PRODVERS | sed -e 's/^[1-9][0-9]*\.[0-9][0-9]*$/&.0/'`"] + fi + SYSTEM_MAKEDEPEND= + MOZ_FIX_LINK_PATHS= + # $ORIGIN/.. is for shared libraries under components/ to locate shared + # libraries one level up (e.g. libnspr4.so) + if test "$SOLARIS_SUNPRO_CC"; then + LDFLAGS="$LDFLAGS -z ignore -R '\$\$ORIGIN:\$\$ORIGIN/..' -z lazyload -z combreloc -z muldefs" + LIBS="-lCrun -lCstd -lc $LIBS" + NS_USE_NATIVE=1 + AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) + CFLAGS="$CFLAGS -xlibmieee -xstrconst -xbuiltin=%all -D__FUNCTION__=__func__" + CXXFLAGS="$CXXFLAGS -xlibmieee -xbuiltin=%all -features=tmplife,tmplrefstatic,extensions -norunpath -D__FUNCTION__=__func__ -template=no%extdef" + _MOZ_EXCEPTIONS_FLAGS_ON='-features=except' + _MOZ_EXCEPTIONS_FLAGS_OFF='-features=no%except' + LDFLAGS="-xildoff $LDFLAGS" + if test -z "$CROSS_COMPILE" -a -f /usr/lib/ld/map.noexstk; then + _SAVE_LDFLAGS=$LDFLAGS + LDFLAGS="-M /usr/lib/ld/map.noexstk $LDFLAGS" + AC_TRY_LINK([#include ], + [printf("Hello World\n");], + , + [LDFLAGS=$_SAVE_LDFLAGS]) + fi + WARNINGS_AS_ERRORS='-Werror' + MOZ_OPTIMIZE_FLAGS="-xO4" + MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_FLAGS) $(DSO_LDOPTS) -h $@ -o $@' + MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_FLAGS) $(DSO_LDOPTS) -h $@ -o $@' + MKSHLIB_FORCE_ALL='-z allextract' + MKSHLIB_UNFORCE_ALL='-z defaultextract' + DSO_LDOPTS='-G' + AR_LIST="$AR t" + AR_EXTRACT="$AR x" + AR_DELETE="$AR d" + AR='$(CXX) -xar' + AR_FLAGS='-o $@' + AS='/usr/ccs/bin/as' + ASFLAGS="$ASFLAGS -K PIC -L -P -D_ASM -D__STDC__=0" + AS_DASH_C_FLAG='' + TARGET_COMPILER_ABI="sunc" + CC_VERSION=`$CC -V 2>&1 | grep '^cc:' 2>/dev/null | $AWK -F\: '{ print $2 }'` + CXX_VERSION=`$CXX -V 2>&1 | grep '^CC:' 2>/dev/null | $AWK -F\: '{ print $2 }'` + AC_MSG_CHECKING([for Sun C++ compiler version >= 5.9]) + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE([], + [#if (__SUNPRO_CC < 0x590) + #error "Denied" + #endif], + _BAD_COMPILER=,_BAD_COMPILER=1) + if test -n "$_BAD_COMPILER"; then + _res="no" + AC_MSG_ERROR([Sun C++ 5.9 (Sun Studio 12) or higher is required to build. Your compiler version is $CXX_VERSION .]) + else + _res="yes" + fi + AC_TRY_COMPILE([], + [#if (__SUNPRO_CC >= 0x5100) + #error "Sun C++ 5.10 or above" + #endif], + _ABOVE_SS12U1=,_ABOVE_SS12U1=1) + if test "$_ABOVE_SS12U1"; then + # disable xannotate + CXXFLAGS="$CXXFLAGS -xannotate=no" + fi + AC_MSG_RESULT([$_res]) + AC_LANG_RESTORE + else + LDFLAGS="$LDFLAGS -Wl,-z,ignore -Wl,-R,'\$\$ORIGIN:\$\$ORIGIN/..' -Wl,-z,lazyload -Wl,-z,combreloc -Wl,-z,muldefs" + LIBS="-lc $LIBS" + MKSHLIB_FORCE_ALL='-Wl,-z -Wl,allextract' + MKSHLIB_UNFORCE_ALL='-Wl,-z -Wl,defaultextract' + ASFLAGS="$ASFLAGS -fPIC" + DSO_LDOPTS='-shared' + _WARNINGS_CFLAGS='' + _WARNINGS_CXXFLAGS='' + if test "$OS_RELEASE" = "5.3"; then + AC_DEFINE(MUST_UNDEF_HAVE_BOOLEAN_AFTER_INCLUDES) + fi + fi + if test "$OS_RELEASE" = "5.5.1"; then + AC_DEFINE(NEED_USLEEP_PROTOTYPE) + fi + ;; + +*-sunos*) + DSO_LDOPTS='-Bdynamic' + MKSHLIB='-$(LD) $(DSO_LDOPTS) -o $@' + MKCSHLIB='-$(LD) $(DSO_LDOPTS) -o $@' + AC_DEFINE(SUNOS4) + AC_DEFINE(SPRINTF_RETURNS_STRING) + case "$(target_os)" in + sunos4.1*) + DLL_SUFFIX='.so.1.0' + ;; + esac + ;; + +*-sysv4.2uw7*) + NSPR_LIBS="-lnspr$NSPR_VERSION -lplc$NSPR_VERSION -lplds$NSPR_VERSION -L/usr/ccs/lib -lcrt" + ;; + +*-os2*) + HOST_NSPR_MDCPUCFG='\"md/_os2.cfg\"' + ;; + +*-android*) + AC_DEFINE(NO_PW_GECOS) + no_x=yes + _PLATFORM_DEFAULT_TOOLKIT=cairo-android + TARGET_NSPR_MDCPUCFG='\"md/_linux.cfg\"' + + MOZ_GFX_OPTIMIZE_MOBILE=1 + # If we're building with --enable-profiling, we need a frame pointer. + if test -z "$MOZ_PROFILING"; then + MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fomit-frame-pointer" + else + MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fno-omit-frame-pointer" + fi + # The Maemo builders don't know about this flag + MOZ_ARM_VFP_FLAGS="-mfpu=vfp" + ;; + +esac + +dnl Only one oddball right now (QNX), but this gives us flexibility +dnl if any other platforms need to override this in the future. +AC_DEFINE_UNQUOTED(D_INO,$DIRENT_INO) + +dnl ======================================================== +dnl Any platform that doesn't have MKSHLIB_FORCE_ALL defined +dnl by now will not have any way to link most binaries (tests +dnl as well as viewer, apprunner, etc.), because some symbols +dnl will be left out of the "composite" .so's by ld as unneeded. +dnl So, by defining NO_LD_ARCHIVE_FLAGS for these platforms, +dnl they can link in the static libs that provide the missing +dnl symbols. +dnl ======================================================== +NO_LD_ARCHIVE_FLAGS= +if test -z "$MKSHLIB_FORCE_ALL" -o -z "$MKSHLIB_UNFORCE_ALL"; then + NO_LD_ARCHIVE_FLAGS=1 +fi +case "$target" in +*-os2*) + NO_LD_ARCHIVE_FLAGS= + ;; +*-aix4.3*|*-aix5*) + NO_LD_ARCHIVE_FLAGS= + ;; +*-openvms*) + NO_LD_ARCHIVE_FLAGS= + ;; +*-msvc*|*-mks*|*-mingw*|*-cygwin*|*-wince|*-winmo) + if test -z "$GNU_CC"; then + NO_LD_ARCHIVE_FLAGS= + fi + ;; +esac +AC_SUBST(NO_LD_ARCHIVE_FLAGS) + +dnl ======================================================== +dnl = Flags to strip unused symbols from .so components +dnl ======================================================== +case "$target" in + *-linux*|*-kfreebsd*-gnu|*-gnu*) + MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS='-Wl,--version-script -Wl,$(BUILD_TOOLS)/gnu-ld-scripts/components-version-script' + ;; + *-solaris*) + if test -z "$GNU_CC"; then + MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS='-M $(BUILD_TOOLS)/gnu-ld-scripts/components-mapfile' + else + if test -z "$GCC_USE_GNU_LD"; then + MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS='-Wl,-M -Wl,$(BUILD_TOOLS)/gnu-ld-scripts/components-mapfile' + else + MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS='-Wl,--version-script -Wl,$(BUILD_TOOLS)/gnu-ld-scripts/components-version-script' + fi + fi + ;; + *-nto*) + MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS='-Wl,--version-script,$(BUILD_TOOLS)/gnu-ld-scripts/components-version-script' + ;; + *-darwin*) + MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS='-Wl,-exported_symbols_list -Wl,$(BUILD_TOOLS)/gnu-ld-scripts/components-export-list' + ;; + *-cygwin*|*-mingw*|*-mks*|*-msvc|*-wince|*-winmo) + if test -n "$GNU_CC"; then + MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS='-Wl,--version-script,$(BUILD_TOOLS)/gnu-ld-scripts/components-version-script' + fi + ;; +esac + +if test -z "$COMPILE_ENVIRONMENT"; then + SKIP_COMPILER_CHECKS=1 + SKIP_LIBRARY_CHECKS=1 +fi + +dnl Configure JIT support + +case "$target" in +i?86-*) + ENABLE_TRACEJIT=1 + NANOJIT_ARCH=i386 + ENABLE_METHODJIT=1 + ENABLE_MONOIC=1 + ENABLE_POLYIC=1 + ENABLE_POLYIC_TYPED_ARRAY=1 + AC_DEFINE(JS_CPU_X86) + AC_DEFINE(JS_NUNBOX32) + ;; +x86_64*-*) + ENABLE_TRACEJIT=1 + NANOJIT_ARCH=X64 + ENABLE_METHODJIT=1 + ENABLE_MONOIC=1 + ENABLE_POLYIC=1 + ENABLE_POLYIC_TYPED_ARRAY=1 + AC_DEFINE(JS_CPU_X64) + AC_DEFINE(JS_PUNBOX64) + ;; +arm*-*) + ENABLE_TRACEJIT=1 + NANOJIT_ARCH=ARM + ENABLE_METHODJIT=1 + ENABLE_MONOIC=1 + ENABLE_POLYIC=1 + AC_DEFINE(JS_CPU_ARM) + AC_DEFINE(JS_NUNBOX32) + ;; +sparc*-*) + ENABLE_TRACEJIT=1 + NANOJIT_ARCH=Sparc + AC_DEFINE(JS_CPU_SPARC) + ;; +esac + +MOZ_ARG_DISABLE_BOOL(methodjit, +[ --disable-methodjit Disable method JIT support], + ENABLE_METHODJIT= ) + +MOZ_ARG_DISABLE_BOOL(monoic, +[ --disable-monoic Disable use of MICs by JIT compiler], + ENABLE_MONOIC= ) + +MOZ_ARG_DISABLE_BOOL(polyic, +[ --disable-polyic Disable use of PICs by JIT compiler], + ENABLE_POLYIC= ) + +MOZ_ARG_DISABLE_BOOL(tracejit, +[ --disable-tracejit Disable tracing JIT support], + ENABLE_TRACEJIT=) + +MOZ_ARG_ENABLE_BOOL(methodjit-spew, +[ --enable-methodjit-spew Enable method JIT spew support], + ENABLE_METHODJIT_SPEW=1, + ENABLE_METHODJIT_SPEW= ) + +AC_SUBST(ENABLE_METHODJIT) + +if test "$ENABLE_METHODJIT"; then + AC_DEFINE(JS_METHODJIT) +fi + +if test "$ENABLE_MONOIC"; then + AC_DEFINE(JS_MONOIC) +fi + +if test "$ENABLE_POLYIC"; then + AC_DEFINE(JS_POLYIC) +fi + +if test "$ENABLE_POLYIC_TYPED_ARRAY"; then + AC_DEFINE(JS_POLYIC_TYPED_ARRAY) +fi + +if test "$ENABLE_METHODJIT_SPEW"; then + AC_DEFINE(JS_METHODJIT_SPEW) +fi + +if test "$ENABLE_TRACEJIT"; then + +AC_DEFINE(FEATURE_NANOJIT) +AC_DEFINE(JS_TRACER) + +case "$target" in +i?86-*) + AC_DEFINE(AVMPLUS_IA32) + ;; +x86_64*-*) + AC_DEFINE(AVMPLUS_AMD64) + AC_DEFINE(AVMPLUS_64BIT) + ;; +arm*-*) + AC_DEFINE(AVMPLUS_ARM) + ;; +sparc-*) + AC_DEFINE(AVMPLUS_SPARC) + ;; +esac + +case "$target" in +*-linux*|*-android-eabi) + AC_DEFINE(AVMPLUS_UNIX) + AC_DEFINE(AVMPLUS_LINUX) + ;; +*-darwin*) + AC_DEFINE(AVMPLUS_UNIX) + ;; +*-solaris*) + AC_DEFINE(AVMPLUS_UNIX) + ;; +*-freebsd*|*-kfreebsd*) + AC_DEFINE(AVMPLUS_UNIX) + ;; +*-gnu*) + AC_DEFINE(AVMPLUS_UNIX) + ;; +*-cygwin*|*-mingw*|*-mks*|*-msvc*|*-wince|*-winmo) + AC_DEFINE(AVMPLUS_WIN32) + ;; +*-os2*) + AC_DEFINE(AVMPLUS_OS2) + ;; +*) + AC_MSG_ERROR([Unrecognized nanojit platform. Use --disable-tracejit to build without tracing JIT support.]) +esac + +fi # ENABLE_TRACEJIT + +AC_SUBST(ENABLE_TRACEJIT) +AC_SUBST(NANOJIT_ARCH) + +if test -z "$SKIP_COMPILER_CHECKS"; then +dnl Checks for typedefs, structures, and compiler characteristics. +dnl ======================================================== +AC_HEADER_STDC +AC_C_CONST +AC_TYPE_MODE_T +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_LANG_CPLUSPLUS +AC_MSG_CHECKING(for __stdcall) +AC_CACHE_VAL(ac_cv___stdcall, + [AC_TRY_COMPILE([template struct foo; + template <> struct foo {}; + template <> struct foo {};], + [], + [ac_cv___stdcall=true], + [ac_cv___stdcall=false])]) +if test "$ac_cv___stdcall" = true ; then + AC_DEFINE(HAVE_STDCALL) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AC_LANG_C +AC_MSG_CHECKING(for ssize_t) +AC_CACHE_VAL(ac_cv_type_ssize_t, + [AC_TRY_COMPILE([#include + #include ], + [ssize_t foo = 0;], + [ac_cv_type_ssize_t=true], + [ac_cv_type_ssize_t=false])]) +if test "$ac_cv_type_ssize_t" = true ; then + AC_DEFINE(HAVE_SSIZE_T) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AC_STRUCT_ST_BLKSIZE +AC_MSG_CHECKING(for siginfo_t) +AC_CACHE_VAL(ac_cv_siginfo_t, + [AC_TRY_COMPILE([#define _POSIX_C_SOURCE 199506L + #include ], + [siginfo_t* info;], + [ac_cv_siginfo_t=true], + [ac_cv_siginfo_t=false])]) +if test "$ac_cv_siginfo_t" = true ; then + AC_DEFINE(HAVE_SIGINFO_T) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +dnl Find exact-width integer types, or figure them out +dnl ourselves. +dnl ======================================================== +dnl Once this is working, we can delete the code for int16_t, +dnl etc. below. + +AC_CHECK_HEADER(stdint.h) +if test "$ac_cv_header_stdint_h" = yes; then + AC_DEFINE(JS_HAVE_STDINT_H) +else + dnl We'll figure them out for ourselves. List more likely types + dnl earlier. If we ever really encounter a size for which none of + dnl the listed types are appropriate, we'll get a configure-time + dnl error; just add the right answer. + MOZ_N_BYTE_TYPE(JS_INT8_TYPE, 1, [char]) + MOZ_N_BYTE_TYPE(JS_INT16_TYPE, 2, [short int long]) + MOZ_N_BYTE_TYPE(JS_INT32_TYPE, 4, [int long 'long long' short]) + MOZ_N_BYTE_TYPE(JS_INT64_TYPE, 8, [int long 'long long']) + MOZ_N_BYTE_TYPE(JS_INTPTR_TYPE, sizeof (void *), + [int long 'long long' short]) +fi + +MOZ_SIZE_OF_TYPE(JS_BYTES_PER_WORD, void*, 4 8) +if test "$moz_cv_size_of_JS_BYTES_PER_WORD" -eq "4"; then + AC_DEFINE(JS_BITS_PER_WORD_LOG2, 5) +elif test "$moz_cv_size_of_JS_BYTES_PER_WORD" -eq "8"; then + AC_DEFINE(JS_BITS_PER_WORD_LOG2, 6) +else + AC_MSG_ERROR([Unexpected JS_BYTES_PER_WORD]) +fi + +MOZ_ALIGN_OF_TYPE(JS_ALIGN_OF_POINTER, void*, 2 4 8 16) +MOZ_SIZE_OF_TYPE(JS_BYTES_PER_DOUBLE, double, 6 8 10 12 14) + +dnl Check for int16_t, int32_t, int64_t, int64, uint, uint_t, and uint16_t. +dnl ======================================================== +AC_MSG_CHECKING(for int16_t) +AC_CACHE_VAL(ac_cv_int16_t, + [AC_TRY_COMPILE([#include + #include ], + [int16_t foo = 0;], + [ac_cv_int16_t=true], + [ac_cv_int16_t=false])]) +if test "$ac_cv_int16_t" = true ; then + AC_DEFINE(HAVE_INT16_T) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AC_MSG_CHECKING(for int32_t) +AC_CACHE_VAL(ac_cv_int32_t, + [AC_TRY_COMPILE([#include + #include ], + [int32_t foo = 0;], + [ac_cv_int32_t=true], + [ac_cv_int32_t=false])]) +if test "$ac_cv_int32_t" = true ; then + AC_DEFINE(HAVE_INT32_T) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AC_MSG_CHECKING(for int64_t) +AC_CACHE_VAL(ac_cv_int64_t, + [AC_TRY_COMPILE([#include + #include ], + [int64_t foo = 0;], + [ac_cv_int64_t=true], + [ac_cv_int64_t=false])]) +if test "$ac_cv_int64_t" = true ; then + AC_DEFINE(HAVE_INT64_T) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AC_MSG_CHECKING(for int64) +AC_CACHE_VAL(ac_cv_int64, + [AC_TRY_COMPILE([#include + #include ], + [int64 foo = 0;], + [ac_cv_int64=true], + [ac_cv_int64=false])]) +if test "$ac_cv_int64" = true ; then + AC_DEFINE(HAVE_INT64) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AC_MSG_CHECKING(for uint) +AC_CACHE_VAL(ac_cv_uint, + [AC_TRY_COMPILE([#include + #include ], + [uint foo = 0;], + [ac_cv_uint=true], + [ac_cv_uint=false])]) +if test "$ac_cv_uint" = true ; then + AC_DEFINE(HAVE_UINT) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AC_MSG_CHECKING(for uint_t) +AC_CACHE_VAL(ac_cv_uint_t, + [AC_TRY_COMPILE([#include + #include ], + [uint_t foo = 0;], + [ac_cv_uint_t=true], + [ac_cv_uint_t=false])]) +if test "$ac_cv_uint_t" = true ; then + AC_DEFINE(HAVE_UINT_T) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AC_MSG_CHECKING(for uint16_t) +AC_CACHE_VAL(ac_cv_uint16_t, + [AC_TRY_COMPILE([#include + #include ], + [uint16_t foo = 0;], + [ac_cv_uint16_t=true], + [ac_cv_uint16_t=false])]) +if test "$ac_cv_uint16_t" = true ; then + AC_DEFINE(HAVE_UINT16_T) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +dnl On the gcc trunk (as of 2001-02-09) _GNU_SOURCE, and thus __USE_GNU, +dnl are defined when compiling C++ but not C. Since the result of this +dnl test is used only in C++, do it in C++. +AC_LANG_CPLUSPLUS + +AC_MSG_CHECKING(for uname.domainname) +AC_CACHE_VAL(ac_cv_have_uname_domainname_field, + [AC_TRY_COMPILE([#include ], + [ struct utsname *res; char *domain; + (void)uname(res); if (res != 0) { domain = res->domainname; } ], + [ac_cv_have_uname_domainname_field=true], + [ac_cv_have_uname_domainname_field=false])]) + +if test "$ac_cv_have_uname_domainname_field" = "true"; then + AC_DEFINE(HAVE_UNAME_DOMAINNAME_FIELD) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING(for uname.__domainname) +AC_CACHE_VAL(ac_cv_have_uname_us_domainname_field, + [AC_TRY_COMPILE([#include ], + [ struct utsname *res; char *domain; + (void)uname(res); if (res != 0) { domain = res->__domainname; } ], + [ac_cv_have_uname_us_domainname_field=true], + [ac_cv_have_uname_us_domainname_field=false])]) + +if test "$ac_cv_have_uname_us_domainname_field" = "true"; then + AC_DEFINE(HAVE_UNAME_US_DOMAINNAME_FIELD) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +AC_LANG_C + +dnl Check for .hidden assembler directive and visibility attribute. +dnl Borrowed from glibc configure.in +dnl =============================================================== +if test "$GNU_CC"; then + AC_CACHE_CHECK(for visibility(hidden) attribute, + ac_cv_visibility_hidden, + [cat > conftest.c </dev/null 2>&1; then + if egrep '\.(hidden|private_extern).*foo' conftest.s >/dev/null; then + ac_cv_visibility_hidden=yes + fi + fi + rm -f conftest.[cs] + ]) + if test "$ac_cv_visibility_hidden" = "yes"; then + AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE) + + AC_CACHE_CHECK(for visibility(default) attribute, + ac_cv_visibility_default, + [cat > conftest.c </dev/null 2>&1; then + if ! egrep '\.(hidden|private_extern).*foo' conftest.s >/dev/null; then + ac_cv_visibility_default=yes + fi + fi + rm -f conftest.[cs] + ]) + if test "$ac_cv_visibility_default" = "yes"; then + AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE) + + AC_CACHE_CHECK(for visibility pragma support, + ac_cv_visibility_pragma, + [cat > conftest.c </dev/null 2>&1; then + if egrep '\.(hidden|private_extern).*foo_hidden' conftest.s >/dev/null; then + if ! egrep '\.(hidden|private_extern).*foo_default' conftest.s > /dev/null; then + ac_cv_visibility_pragma=yes + fi + fi + fi + rm -f conftest.[cs] + ]) + if test "$ac_cv_visibility_pragma" = "yes"; then + AC_CACHE_CHECK(For gcc visibility bug with class-level attributes (GCC bug 26905), + ac_cv_have_visibility_class_bug, + [cat > conftest.c < /dev/null 2>&1 ; then + ac_cv_have_visibility_class_bug=yes + else + if test `egrep -c '@PLT|\\$stub' conftest.S` = 0; then + ac_cv_have_visibility_class_bug=yes + fi + fi + rm -rf conftest.{c,S} + ]) + + AC_CACHE_CHECK(For x86_64 gcc visibility bug with builtins (GCC bug 20297), + ac_cv_have_visibility_builtin_bug, + [cat > conftest.c < +#pragma GCC visibility pop + +__attribute__ ((visibility ("default"))) void Func() { + char c[[100]]; + memset(c, 0, sizeof(c)); +} +EOF + ac_cv_have_visibility_builtin_bug=no + if ! ${CC-cc} ${CFLAGS} ${DSO_PIC_CFLAGS} ${DSO_LDOPTS} -O2 -S -o conftest.S conftest.c > /dev/null 2>&1 ; then + ac_cv_have_visibility_builtin_bug=yes + else + if test `grep -c "@PLT" conftest.S` = 0; then + ac_cv_visibility_builtin_bug=yes + fi + fi + rm -f conftest.{c,S} + ]) + if test "$ac_cv_have_visibility_builtin_bug" = "no" -a \ + "$ac_cv_have_visibility_class_bug" = "no"; then + VISIBILITY_FLAGS='-I$(DIST)/system_wrappers_js -include $(topsrcdir)/config/gcc_hidden.h' + WRAP_SYSTEM_INCLUDES=1 + STL_FLAGS='-I$(DIST)/stl_wrappers' + WRAP_STL_INCLUDES=1 + else + VISIBILITY_FLAGS='-fvisibility=hidden' + fi # have visibility pragma bug + fi # have visibility pragma + fi # have visibility(default) attribute + fi # have visibility(hidden) attribute +fi # GNU_CC + +# visibility hidden flag for Sun Studio on Solaris +if test "$SOLARIS_SUNPRO_CC"; then +VISIBILITY_FLAGS='-xldscope=hidden' +fi # Sun Studio on Solaris + +AC_SUBST(WRAP_SYSTEM_INCLUDES) +AC_SUBST(VISIBILITY_FLAGS) + +dnl Check for __force_align_arg_pointer__ for SSE2 on gcc +dnl ======================================================== +if test "$GNU_CC"; then + CFLAGS_save="${CFLAGS}" + CFLAGS="${CFLAGS} -Werror" + AC_CACHE_CHECK(for __force_align_arg_pointer__ attribute, + ac_cv_force_align_arg_pointer, + [AC_TRY_COMPILE([__attribute__ ((__force_align_arg_pointer__)) void test() {}], + [], + ac_cv_force_align_arg_pointer="yes", + ac_cv_force_align_arg_pointer="no")]) + CFLAGS="${CFLAGS_save}" + if test "$ac_cv_force_align_arg_pointer" = "yes"; then + HAVE_GCC_ALIGN_ARG_POINTER=1 + else + HAVE_GCC_ALIGN_ARG_POINTER= + fi +fi +AC_SUBST(HAVE_GCC_ALIGN_ARG_POINTER) + +dnl Checks for header files. +dnl ======================================================== +AC_HEADER_DIRENT +case "$target_os" in +freebsd*) +# for stuff like -lXshm + CPPFLAGS="${CPPFLAGS} ${X_CFLAGS}" + ;; +esac +AC_CHECK_HEADERS(sys/byteorder.h compat.h getopt.h) +AC_CHECK_HEADERS(sys/bitypes.h memory.h unistd.h) +AC_CHECK_HEADERS(gnu/libc-version.h nl_types.h) +AC_CHECK_HEADERS(malloc.h) +AC_CHECK_HEADERS(X11/XKBlib.h) +AC_CHECK_HEADERS(io.h) + +dnl These are all the places some variant of statfs can be hiding. +AC_CHECK_HEADERS(sys/statvfs.h sys/statfs.h sys/vfs.h sys/mount.h) + +dnl Quota support +AC_CHECK_HEADERS(sys/quota.h) +AC_CHECK_HEADERS(linux/quota.h) + +dnl Try for MMX support +dnl NB - later gcc versions require -mmmx for this header to be successfully +dnl included (or another option which implies it, such as -march=pentium-mmx) +AC_CHECK_HEADERS(mmintrin.h) + +dnl Check whether the compiler supports the new-style C++ standard +dnl library headers (i.e. ) or needs the old "new.h" +AC_LANG_CPLUSPLUS +NEW_H=new.h +AC_CHECK_HEADER(new, [NEW_H=new]) +AC_DEFINE_UNQUOTED(NEW_H, <$NEW_H>) +AC_LANG_C + +AC_ARG_ENABLE(dtrace, + [ --enable-dtrace build with dtrace support if available (default=no)], + [enable_dtrace="yes"],) +if test "x$enable_dtrace" = "xyes"; then + AC_CHECK_HEADER(sys/sdt.h, HAVE_DTRACE=1) + if test -n "$HAVE_DTRACE"; then + AC_DEFINE(INCLUDE_MOZILLA_DTRACE) + else + AC_MSG_ERROR([dtrace enabled but sys/sdt.h not found]); + fi +fi +AC_SUBST(HAVE_DTRACE) + +case $target in +*-aix4.3*|*-aix5*) + ;; +*) + AC_CHECK_HEADERS(sys/cdefs.h) + ;; +esac + +dnl Performance measurement headers. +AC_CHECK_HEADER(linux/perf_event.h, HAVE_LINUX_PERF_EVENT_H=1) +AC_SUBST(HAVE_LINUX_PERF_EVENT_H) + +dnl Checks for libraries. +dnl ======================================================== +case $target in +*-hpux11.*) + ;; +*) + AC_CHECK_LIB(c_r, gethostbyname_r) + ;; +esac + +dnl We don't want to link with libdl even if it's present on OS X, since +dnl it's not used and not part of the default installation. +dnl The same goes for BeOS. OS/2 has dlfcn in libc. +dnl We don't want to link against libm or libpthread on Darwin since +dnl they both are just symlinks to libSystem and explicitly linking +dnl against libSystem causes issues when debugging (see bug 299601). +case $target in +*-darwin*) + ;; +*-beos*) + ;; +*-os2*) + ;; +*) + AC_SEARCH_LIBS(dlopen, dl, + AC_CHECK_HEADER(dlfcn.h, + AC_DEFINE(HAVE_DLOPEN))) + ;; +esac + +_SAVE_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -D_GNU_SOURCE" +AC_CHECK_FUNCS(dladdr) +CFLAGS="$_SAVE_CFLAGS" + +if test ! "$GNU_CXX"; then + + case $target in + *-aix*) + AC_CHECK_LIB(C_r, demangle) + ;; + *) + AC_CHECK_LIB(C, demangle) + ;; + esac +fi + +dnl OS/2 has socket in libc. +case $target in +*-os2*) + ;; +*) + AC_CHECK_LIB(socket, socket) +esac + +AC_MSG_CHECKING(for ARM SIMD support in compiler) +AC_TRY_COMPILE([], + [asm("uqadd8 r1, r1, r2");], + result="yes", result="no") +AC_MSG_RESULT("$result") +if test "$result" = "yes"; then + AC_DEFINE(HAVE_ARM_SIMD) + HAVE_ARM_SIMD=1 +fi +AC_SUBST(HAVE_ARM_SIMD) + +AC_MSG_CHECKING(for ARM NEON support in compiler) +_SAVE_CFLAGS="$CFLAGS" +if test "$GNU_CC"; then + # gcc needs -mfpu=neon to recognize NEON instructions + CFLAGS="$CFLAGS -mfpu=neon -mfloat-abi=softfp" +fi +AC_TRY_COMPILE([], + [asm("vadd.i8 d0, d0, d0");], + result="yes", result="no") +AC_MSG_RESULT("$result") +if test "$result" = "yes"; then + AC_DEFINE(HAVE_ARM_NEON) + HAVE_ARM_NEON=1 +fi +CFLAGS="$_SAVE_CFLAGS" +AC_SUBST(HAVE_ARM_NEON) + +dnl ======================================================== +dnl = pthread support +dnl = Start by checking whether the system support pthreads +dnl ======================================================== +case "$target_os" in +darwin*) + USE_PTHREADS=1 + ;; +*) + MOZ_CHECK_PTHREADS(pthreads, + USE_PTHREADS=1 _PTHREAD_LDFLAGS="-lpthreads", + MOZ_CHECK_PTHREADS(pthread, + USE_PTHREADS=1 _PTHREAD_LDFLAGS="-lpthread", + MOZ_CHECK_PTHREADS(c_r, + USE_PTHREADS=1 _PTHREAD_LDFLAGS="-lc_r", + MOZ_CHECK_PTHREADS(c, + USE_PTHREADS=1 + ) + ) + ) + ) + ;; +esac + +dnl ======================================================== +dnl Check the command line for --with-pthreads +dnl ======================================================== +MOZ_ARG_WITH_BOOL(pthreads, +[ --with-pthreads Force use of system pthread library with NSPR ], +[ if test "$USE_PTHREADS"x = x; then + AC_MSG_ERROR([ --with-pthreads specified for a system without pthread support ]); +fi], + USE_PTHREADS= + _PTHREAD_LDFLAGS= +) + +dnl ======================================================== +dnl Do the platform specific pthread hackery +dnl ======================================================== +if test "$USE_PTHREADS"x != x +then + dnl + dnl See if -pthread is supported. + dnl + rm -f conftest* + ac_cv_have_dash_pthread=no + AC_MSG_CHECKING(whether ${CC-cc} accepts -pthread) + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} -pthread -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out | grep pthread`" -a -z "`egrep -i '(error|incorrect)' conftest.out`" ; then + ac_cv_have_dash_pthread=yes + case "$target_os" in + freebsd*) +# Freebsd doesn't use -pthread for compiles, it uses them for linking + ;; + *) + CFLAGS="$CFLAGS -pthread" + CXXFLAGS="$CXXFLAGS -pthread" + ;; + esac + fi + fi + rm -f conftest* + AC_MSG_RESULT($ac_cv_have_dash_pthread) + + dnl + dnl See if -pthreads is supported. + dnl + ac_cv_have_dash_pthreads=no + if test "$ac_cv_have_dash_pthread" = "no"; then + AC_MSG_CHECKING(whether ${CC-cc} accepts -pthreads) + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} -pthreads -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out | grep pthreads`" -a -z "`egrep -i '(error|incorrect)' conftest.out`" ; then + ac_cv_have_dash_pthreads=yes + CFLAGS="$CFLAGS -pthreads" + CXXFLAGS="$CXXFLAGS -pthreads" + fi + fi + rm -f conftest* + AC_MSG_RESULT($ac_cv_have_dash_pthreads) + fi + + case "$target" in + *-*-freebsd*) + AC_DEFINE(_REENTRANT) + AC_DEFINE(_THREAD_SAFE) + dnl -pthread links in -lc_r, so don't specify it explicitly. + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS="-pthread" + else + _PTHREAD_LDFLAGS="-lc_r" + fi + ;; + + *-*-openbsd*|*-*-bsdi*) + AC_DEFINE(_REENTRANT) + AC_DEFINE(_THREAD_SAFE) + dnl -pthread links in -lc_r, so don't specify it explicitly. + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS="-pthread" + fi + ;; + + *-*-linux*|*-*-kfreebsd*-gnu|*-*-gnu*) + AC_DEFINE(_REENTRANT) + ;; + + *-*-nto*) + AC_DEFINE(_REENTRANT) + ;; + + *-aix4.3*|*-aix5*) + AC_DEFINE(_REENTRANT) + ;; + + *-hpux11.*) + AC_DEFINE(_REENTRANT) + ;; + + alpha*-*-osf*) + AC_DEFINE(_REENTRANT) + ;; + + *-*-solaris*) + AC_DEFINE(_REENTRANT) + if test "$SOLARIS_SUNPRO_CC"; then + CFLAGS="$CFLAGS -mt" + CXXFLAGS="$CXXFLAGS -mt" + fi + ;; + esac + LDFLAGS="${_PTHREAD_LDFLAGS} ${LDFLAGS}" +fi + +dnl ======================================================== +dnl See if mmap sees writes +dnl For cross compiling, just define it as no, which is a safe default +dnl ======================================================== +AC_MSG_CHECKING(whether mmap() sees write()s) + +changequote(,) +mmap_test_prog=' + #include + #include + #include + #include + #include + #include + + char fname[] = "conftest.file"; + char zbuff[1024]; /* Fractional page is probably worst case */ + + int main() { + char *map; + int fd; + int i; + unlink(fname); + fd = open(fname, O_RDWR | O_CREAT, 0660); + if(fd<0) return 1; + unlink(fname); + write(fd, zbuff, sizeof(zbuff)); + lseek(fd, 0, SEEK_SET); + map = (char*)mmap(0, sizeof(zbuff), PROT_READ, MAP_SHARED, fd, 0); + if(map==(char*)-1) return 2; + for(i=0; fname[i]; i++) { + int rc = write(fd, &fname[i], 1); + if(map[i]!=fname[i]) return 4; + } + return 0; + } +' +changequote([,]) + +AC_TRY_RUN($mmap_test_prog , result="yes", result="no", result="yes") + +AC_MSG_RESULT("$result") + +if test "$result" = "no"; then + AC_DEFINE(MMAP_MISSES_WRITES) +fi + + +dnl Checks for library functions. +dnl ======================================================== +AC_PROG_GCC_TRADITIONAL +AC_FUNC_MEMCMP +AC_CHECK_FUNCS([fchmod flockfile getc_unlocked _getc_nolock getpagesize \ + lchown localtime_r lstat64 memmove random rint sbrk snprintf \ + stat64 statvfs statvfs64 strerror strtok_r truncate64]) + +dnl check for clock_gettime(), the CLOCK_MONOTONIC clock, and -lrt +_SAVE_LDFLAGS=$LDFLAGS +LDFLAGS="$LDFLAGS -lrt" +AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC) and -lrt, + ac_cv_have_clock_monotonic, + [AC_TRY_LINK([#include ], + [ struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); ], + ac_cv_have_clock_monotonic=yes, + ac_cv_have_clock_monotonic=no)]) +LDFLAGS=$_SAVE_LDFLAGS +if test "$ac_cv_have_clock_monotonic" = "yes"; then + HAVE_CLOCK_MONOTONIC=1 + REALTIME_LIBS=-lrt + AC_DEFINE(HAVE_CLOCK_MONOTONIC) + AC_SUBST(HAVE_CLOCK_MONOTONIC) + AC_SUBST(REALTIME_LIBS) +fi + +dnl Windows functions, for mingw. +AC_TRY_LINK([#include ], + [SYSTEMTIME st;FILETIME ft;SystemTimeToFileTime(&st,&ft);], + ac_cv_have_systemtimetofiletime="yes", + ac_cv_have_systemtimetofiletime="no") +if test "$ac_cv_have_systemtimetofiletime" = "yes"; then + AC_DEFINE(HAVE_SYSTEMTIMETOFILETIME) +fi +AC_TRY_LINK([#include ], + [FILETIME ft;GetSystemTimeAsFileTime(&ft);], + ac_cv_have_getsystemtimeasfiletime="yes", + ac_cv_have_getsystemtimeasfiletime="no") +if test "$ac_cv_have_getsystemtimeasfiletime" = "yes"; then + AC_DEFINE(HAVE_GETSYSTEMTIMEASFILETIME) +fi + +dnl check for wcrtomb/mbrtowc +dnl ======================================================================= +if test -z "$MACOS_DEPLOYMENT_TARGET" || test "$MACOS_DEPLOYMENT_TARGET" -ge "100300"; then +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_CACHE_CHECK(for wcrtomb, + ac_cv_have_wcrtomb, + [AC_TRY_LINK([#include ], + [mbstate_t ps={0};wcrtomb(0,'f',&ps);], + ac_cv_have_wcrtomb="yes", + ac_cv_have_wcrtomb="no")]) +if test "$ac_cv_have_wcrtomb" = "yes"; then + AC_DEFINE(HAVE_WCRTOMB) +fi +AC_CACHE_CHECK(for mbrtowc, + ac_cv_have_mbrtowc, + [AC_TRY_LINK([#include ], + [mbstate_t ps={0};mbrtowc(0,0,0,&ps);], + ac_cv_have_mbrtowc="yes", + ac_cv_have_mbrtowc="no")]) +if test "$ac_cv_have_mbrtowc" = "yes"; then + AC_DEFINE(HAVE_MBRTOWC) +fi +AC_LANG_RESTORE +fi + +AC_CACHE_CHECK( + [for res_ninit()], + ac_cv_func_res_ninit, + [AC_TRY_LINK([ + #ifdef linux + #define _BSD_SOURCE 1 + #endif + #include + ], + [int foo = res_ninit(&_res);], + [ac_cv_func_res_ninit=yes], + [ac_cv_func_res_ninit=no]) + ]) + +if test "$ac_cv_func_res_ninit" = "yes"; then + AC_DEFINE(HAVE_RES_NINIT) +dnl must add the link line we do something as foolish as this... dougt +dnl else +dnl AC_CHECK_LIB(bind, res_ninit, AC_DEFINE(HAVE_RES_NINIT), +dnl AC_CHECK_LIB(resolv, res_ninit, AC_DEFINE(HAVE_RES_NINIT))) +fi + +AC_LANG_CPLUSPLUS +AC_CACHE_CHECK( + [for gnu_get_libc_version()], + ac_cv_func_gnu_get_libc_version, + [AC_TRY_LINK([ + #ifdef HAVE_GNU_LIBC_VERSION_H + #include + #endif + ], + [const char *glibc_version = gnu_get_libc_version();], + [ac_cv_func_gnu_get_libc_version=yes], + [ac_cv_func_gnu_get_libc_version=no] + )] + ) + +if test "$ac_cv_func_gnu_get_libc_version" = "yes"; then + AC_DEFINE(HAVE_GNU_GET_LIBC_VERSION) +fi + +case $target_os in + os2*|msvc*|mks*|cygwin*|mingw*|darwin*|wince*|winmo*|beos*) + ;; + *) + +AC_CHECK_LIB(c, iconv, [_ICONV_LIBS="$_ICONV_LIBS"], + AC_CHECK_LIB(iconv, iconv, [_ICONV_LIBS="$_ICONV_LIBS -liconv"], + AC_CHECK_LIB(iconv, libiconv, [_ICONV_LIBS="$_ICONV_LIBS -liconv"]))) +_SAVE_LIBS=$LIBS +LIBS="$LIBS $_ICONV_LIBS" +AC_CACHE_CHECK( + [for iconv()], + ac_cv_func_iconv, + [AC_TRY_LINK([ + #include + #include + ], + [ + iconv_t h = iconv_open("", ""); + iconv(h, NULL, NULL, NULL, NULL); + iconv_close(h); + ], + [ac_cv_func_iconv=yes], + [ac_cv_func_iconv=no] + )] + ) +if test "$ac_cv_func_iconv" = "yes"; then + AC_DEFINE(HAVE_ICONV) + DYNAMIC_XPCOM_LIBS="$DYNAMIC_XPCOM_LIBS $_ICONV_LIBS" + LIBXUL_LIBS="$LIBXUL_LIBS $_ICONV_LIBS" + LIBICONV="$_ICONV_LIBS" + AC_CACHE_CHECK( + [for iconv() with const input], + ac_cv_func_const_iconv, + [AC_TRY_COMPILE([ + #include + #include + ], + [ + const char *input = "testing"; + iconv_t h = iconv_open("", ""); + iconv(h, &input, NULL, NULL, NULL); + iconv_close(h); + ], + [ac_cv_func_const_iconv=yes], + [ac_cv_func_const_iconv=no] + )] + ) + if test "$ac_cv_func_const_iconv" = "yes"; then + AC_DEFINE(HAVE_ICONV_WITH_CONST_INPUT) + fi +fi +LIBS=$_SAVE_LIBS + + ;; +esac + +AC_LANG_C + +dnl ********************** +dnl *** va_copy checks *** +dnl ********************** +dnl we currently check for all three va_copy possibilities, so we get +dnl all results in config.log for bug reports. +AC_MSG_CHECKING(for an implementation of va_copy()) +AC_CACHE_VAL(ac_cv_va_copy,[ + AC_TRY_RUN([ + #include + void f (int i, ...) { + va_list args1, args2; + va_start (args1, i); + va_copy (args2, args1); + if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42) + exit (1); + va_end (args1); va_end (args2); + } + int main() { f (0, 42); return 0; }], + ac_cv_va_copy=yes, + ac_cv_va_copy=no, + ac_cv_va_copy=no + ) +]) +AC_MSG_RESULT($ac_cv_va_copy) +AC_MSG_CHECKING(for an implementation of __va_copy()) +AC_CACHE_VAL(ac_cv___va_copy,[ + AC_TRY_RUN([ + #include + void f (int i, ...) { + va_list args1, args2; + va_start (args1, i); + __va_copy (args2, args1); + if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42) + exit (1); + va_end (args1); va_end (args2); + } + int main() { f (0, 42); return 0; }], + ac_cv___va_copy=yes, + ac_cv___va_copy=no, + ac_cv___va_copy=no + ) +]) +AC_MSG_RESULT($ac_cv___va_copy) +AC_MSG_CHECKING(whether va_lists can be copied by value) +AC_CACHE_VAL(ac_cv_va_val_copy,[ + AC_TRY_RUN([ + #include + void f (int i, ...) { + va_list args1, args2; + va_start (args1, i); + args2 = args1; + if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42) + exit (1); + va_end (args1); va_end (args2); + } + int main() { f (0, 42); return 0; }], + ac_cv_va_val_copy=yes, + ac_cv_va_val_copy=no, + ac_cv_va_val_copy=yes + ) +]) +if test "x$ac_cv_va_copy" = "xyes"; then + AC_DEFINE(VA_COPY, va_copy) + AC_DEFINE(HAVE_VA_COPY) +elif test "x$ac_cv___va_copy" = "xyes"; then + AC_DEFINE(VA_COPY, __va_copy) + AC_DEFINE(HAVE_VA_COPY) +fi + +if test "x$ac_cv_va_val_copy" = "xno"; then + AC_DEFINE(HAVE_VA_LIST_AS_ARRAY) +fi +AC_MSG_RESULT($ac_cv_va_val_copy) + +dnl Check for dll-challenged libc's. +dnl This check is apparently only needed for Linux. +case "$target" in + *-linux*) + dnl =================================================================== + _curdir=`pwd` + export _curdir + rm -rf conftest* _conftest + mkdir _conftest + cat >> conftest.C <<\EOF +#include +#include +#include +#ifdef _dl_loaded +void __dump_link_map(void) { + struct link_map *map = _dl_loaded; + while (NULL != map) {printf("0x%08x %s\n", map->l_addr, map->l_name); map = map->l_next;} +} +int main() { + dlopen("./conftest1.so",RTLD_LAZY); + dlopen("./../_conftest/conftest1.so",RTLD_LAZY); + dlopen("CURDIR/_conftest/conftest1.so",RTLD_LAZY); + dlopen("CURDIR/_conftest/../_conftest/conftest1.so",RTLD_LAZY); + __dump_link_map(); +} +#else +/* _dl_loaded isn't defined, so this should be either a libc5 (glibc1) system, or a glibc2 system that doesn't have the multiple load bug (i.e., RH6.0).*/ +int main() { printf("./conftest1.so\n"); } +#endif +EOF + + $PERL -p -i -e "s/CURDIR/\$ENV{_curdir}/g;" conftest.C + + cat >> conftest1.C <<\EOF +#include +void foo(void) {printf("foo in dll called\n");} +EOF + ${CXX-g++} -fPIC -c -g conftest1.C + ${CXX-g++} -shared -Wl,-h -Wl,conftest1.so -o conftest1.so conftest1.o + ${CXX-g++} -g conftest.C -o conftest -ldl + cp -f conftest1.so conftest _conftest + cd _conftest + if test `./conftest | grep conftest1.so | wc -l` -gt 1 + then + echo + echo "*** Your libc has a bug that can result in loading the same dynamic" + echo "*** library multiple times. This bug is known to be fixed in glibc-2.0.7-32" + echo "*** or later. However, if you choose not to upgrade, the only effect" + echo "*** will be excessive memory usage at runtime." + echo + fi + cd ${_curdir} + rm -rf conftest* _conftest + dnl =================================================================== + ;; +esac + +dnl =================================================================== +dnl ======================================================== +dnl Put your C++ language/feature checks below +dnl ======================================================== +AC_LANG_CPLUSPLUS + +ARM_ABI_PREFIX= +HAVE_GCC3_ABI= +if test "$GNU_CC"; then + if test "$CPU_ARCH" = "arm" ; then + AC_CACHE_CHECK(for ARM EABI, + ac_cv_gcc_arm_eabi, + [AC_TRY_COMPILE([], + [ +#if defined(__ARM_EABI__) + return 0; +#else +#error Not ARM EABI. +#endif + ], + ac_cv_gcc_arm_eabi="yes", + ac_cv_gcc_arm_eabi="no")]) + if test "$ac_cv_gcc_arm_eabi" = "yes"; then + HAVE_ARM_EABI=1 + ARM_ABI_PREFIX=eabi- + else + ARM_ABI_PREFIX=oabi- + fi + fi + + AC_CACHE_CHECK(for gcc 3.0 ABI, + ac_cv_gcc_three_abi, + [AC_TRY_COMPILE([], + [ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + return 0; +#else +#error Not gcc3. +#endif + ], + ac_cv_gcc_three_abi="yes", + ac_cv_gcc_three_abi="no")]) + if test "$ac_cv_gcc_three_abi" = "yes"; then + TARGET_COMPILER_ABI="${TARGET_COMPILER_ABI-${ARM_ABI_PREFIX}gcc3}" + HAVE_GCC3_ABI=1 + else + TARGET_COMPILER_ABI="${TARGET_COMPILER_ABI-${ARM_ABI_PREFIX}gcc2}" + fi +fi +AC_SUBST(HAVE_GCC3_ABI) + + +AC_CACHE_CHECK(for C++ \"explicit\" keyword, + ac_cv_cpp_explicit, + [AC_TRY_COMPILE(class X { + public: explicit X(int i) : i_(i) {} + private: int i_; + };, + X x(3);, + ac_cv_cpp_explicit=yes, + ac_cv_cpp_explicit=no)]) +if test "$ac_cv_cpp_explicit" = yes ; then + AC_DEFINE(HAVE_CPP_EXPLICIT) +fi + +AC_CACHE_CHECK(for C++ \"typename\" keyword, + ac_cv_cpp_typename, + [AC_TRY_COMPILE(class param { + public: + typedef unsigned long num_type; + }; + + template class tplt { + public: + typedef typename T::num_type t_num_type; + t_num_type foo(typename T::num_type num) { + return num; + } + };, + tplt A; + A.foo(0);, + ac_cv_cpp_typename=yes, + ac_cv_cpp_typename=no)]) +if test "$ac_cv_cpp_typename" = yes ; then + AC_DEFINE(HAVE_CPP_TYPENAME) +fi + +dnl Check for support of modern template specialization syntax +dnl Test code and requirement from scc@netscape.com. +dnl Autoconf cut-and-paste job by waterson@netscape.com +AC_CACHE_CHECK(for modern C++ template specialization syntax support, + ac_cv_cpp_modern_specialize_template_syntax, + [AC_TRY_COMPILE(template struct X { int a; }; + class Y {}; + template <> struct X { double a; };, + X int_x; + X y_x;, + ac_cv_cpp_modern_specialize_template_syntax=yes, + ac_cv_cpp_modern_specialize_template_syntax=no)]) +if test "$ac_cv_cpp_modern_specialize_template_syntax" = yes ; then + AC_DEFINE(HAVE_CPP_MODERN_SPECIALIZE_TEMPLATE_SYNTAX) +fi + + +dnl Some compilers support only full specialization, and some don't. +AC_CACHE_CHECK(whether partial template specialization works, + ac_cv_cpp_partial_specialization, + [AC_TRY_COMPILE(template class Foo {}; + template class Foo {};, + return 0;, + ac_cv_cpp_partial_specialization=yes, + ac_cv_cpp_partial_specialization=no)]) +if test "$ac_cv_cpp_partial_specialization" = yes ; then + AC_DEFINE(HAVE_CPP_PARTIAL_SPECIALIZATION) +fi + +dnl Some compilers have limited support for operators with templates; +dnl specifically, it is necessary to define derived operators when a base +dnl class's operator declaration should suffice. +AC_CACHE_CHECK(whether operators must be re-defined for templates derived from templates, + ac_cv_need_derived_template_operators, + [AC_TRY_COMPILE([template class Base { }; + template + Base operator+(const Base& lhs, const Base& rhs) { return lhs; } + template class Derived : public Base { };], + [Derived a, b; + Base c = a + b; + return 0;], + ac_cv_need_derived_template_operators=no, + ac_cv_need_derived_template_operators=yes)]) +if test "$ac_cv_need_derived_template_operators" = yes ; then + AC_DEFINE(NEED_CPP_DERIVED_TEMPLATE_OPERATORS) +fi + + +dnl Some compilers have trouble detecting that a template class +dnl that derives from another template is actually an instance +dnl of the base class. This test checks for that. +AC_CACHE_CHECK(whether we need to cast a derived template to pass as its base class, + ac_cv_need_cpp_template_cast_to_base, + [AC_TRY_COMPILE([template class Base { }; + template class Derived : public Base { }; + template int foo(const Base&) { return 0; }], + [Derived bar; return foo(bar);], + ac_cv_need_cpp_template_cast_to_base=no, + ac_cv_need_cpp_template_cast_to_base=yes)]) +if test "$ac_cv_need_cpp_template_cast_to_base" = yes ; then + AC_DEFINE(NEED_CPP_TEMPLATE_CAST_TO_BASE) +fi + +dnl Some compilers have trouble resolving the ambiguity between two +dnl functions whose arguments differ only by cv-qualifications. +AC_CACHE_CHECK(whether the compiler can resolve const ambiguities for templates, + ac_cv_can_resolve_const_ambiguity, + [AC_TRY_COMPILE([ + template class ptrClass { + public: T* ptr; + }; + + template T* a(ptrClass *arg) { + return arg->ptr; + } + + template + const T* a(const ptrClass *arg) { + return arg->ptr; + } + ], + [ ptrClass i; + a(&i); ], + ac_cv_can_resolve_const_ambiguity=yes, + ac_cv_can_resolve_const_ambiguity=no)]) +if test "$ac_cv_can_resolve_const_ambiguity" = no ; then + AC_DEFINE(CANT_RESOLVE_CPP_CONST_AMBIGUITY) +fi + +dnl +dnl We don't do exceptions on unix. The only reason this used to be here +dnl is that mozilla/xpcom/tests/TestCOMPtr.cpp has a test which uses +dnl exceptions. But, we turn exceptions off by default and this test breaks. +dnl So im commenting this out until someone writes some artificial +dnl intelligence to detect not only if the compiler has exceptions, but if +dnl they are enabled as well. +dnl +dnl AC_CACHE_CHECK(for C++ \"exceptions\", +dnl ac_cv_cpp_exceptions, +dnl [AC_TRY_COMPILE(class X { public: X() {} }; +dnl static void F() { throw X(); }, +dnl try { F(); } catch(X & e) { }, +dnl ac_cv_cpp_exceptions=yes, +dnl ac_cv_cpp_exceptions=no)]) +dnl if test $ac_cv_cpp_exceptions = yes ; then +dnl AC_DEFINE(HAVE_CPP_EXCEPTIONS) +dnl fi + +dnl Some compilers have marginal |using| support; for example, gcc-2.7.2.3 +dnl supports it well enough to allow us to use it to change access, but not +dnl to resolve ambiguity. The next two tests determine how well the |using| +dnl keyword is supported. +dnl +dnl Check to see if we can change access with |using|. Test both a +dnl legal and an illegal example. +AC_CACHE_CHECK(whether the C++ \"using\" keyword can change access, + ac_cv_cpp_access_changing_using2, + [AC_TRY_COMPILE( + class A { protected: int foo() { return 0; } }; + class B : public A { public: using A::foo; };, + B b; return b.foo();, + [AC_TRY_COMPILE( + class A { public: int foo() { return 1; } }; + class B : public A { private: using A::foo; };, + B b; return b.foo();, + ac_cv_cpp_access_changing_using2=no, + ac_cv_cpp_access_changing_using2=yes)], + ac_cv_cpp_access_changing_using2=no)]) +if test "$ac_cv_cpp_access_changing_using2" = yes ; then + AC_DEFINE(HAVE_CPP_ACCESS_CHANGING_USING) +fi + +dnl Check to see if we can resolve ambiguity with |using|. +AC_CACHE_CHECK(whether the C++ \"using\" keyword resolves ambiguity, + ac_cv_cpp_ambiguity_resolving_using, + [AC_TRY_COMPILE(class X { + public: int go(const X&) {return 3;} + int jo(const X&) {return 3;} + }; + class Y : public X { + public: int go(int) {return 2;} + int jo(int) {return 2;} + using X::jo; + private: using X::go; + };, + X x; Y y; y.jo(x);, + ac_cv_cpp_ambiguity_resolving_using=yes, + ac_cv_cpp_ambiguity_resolving_using=no)]) +if test "$ac_cv_cpp_ambiguity_resolving_using" = yes ; then + AC_DEFINE(HAVE_CPP_AMBIGUITY_RESOLVING_USING) +fi + +dnl Check to see if the |std| namespace is supported. If so, we'll want +dnl to qualify any standard library calls with "std::" to ensure that +dnl those functions can be resolved. +AC_CACHE_CHECK(for \"std::\" namespace, + ac_cv_cpp_namespace_std, + [AC_TRY_COMPILE([#include ], + [return std::min(0, 1);], + ac_cv_cpp_namespace_std=yes, + ac_cv_cpp_namespace_std=no)]) +if test "$ac_cv_cpp_namespace_std" = yes ; then + AC_DEFINE(HAVE_CPP_NAMESPACE_STD) +fi + +dnl Older compilers are overly ambitious with respect to using the standard +dnl template library's |operator!=()| when |operator==()| is defined. In +dnl which case, defining |operator!=()| in addition to |operator==()| causes +dnl ambiguity at compile-time. This test checks for that case. +AC_CACHE_CHECK(whether standard template operator!=() is ambiguous, + ac_cv_cpp_unambiguous_std_notequal, + [AC_TRY_COMPILE([#include + struct T1 {}; + int operator==(const T1&, const T1&) { return 0; } + int operator!=(const T1&, const T1&) { return 0; }], + [T1 a,b; return a != b;], + ac_cv_cpp_unambiguous_std_notequal=unambiguous, + ac_cv_cpp_unambiguous_std_notequal=ambiguous)]) +if test "$ac_cv_cpp_unambiguous_std_notequal" = unambiguous ; then + AC_DEFINE(HAVE_CPP_UNAMBIGUOUS_STD_NOTEQUAL) +fi + + +AC_CACHE_CHECK(for C++ reinterpret_cast, + ac_cv_cpp_reinterpret_cast, + [AC_TRY_COMPILE(struct X { int i; }; + struct Y { int i; };, + X x; X*const z = &x;Y*y = reinterpret_cast(z);, + ac_cv_cpp_reinterpret_cast=yes, + ac_cv_cpp_reinterpret_cast=no)]) +if test "$ac_cv_cpp_reinterpret_cast" = yes ; then + AC_DEFINE(HAVE_CPP_NEW_CASTS) +fi + +dnl See if a dynamic_cast to void* gives the most derived object. +AC_CACHE_CHECK(for C++ dynamic_cast to void*, + ac_cv_cpp_dynamic_cast_void_ptr, + [AC_TRY_RUN([class X { int i; public: virtual ~X() { } }; + class Y { int j; public: virtual ~Y() { } }; + class Z : public X, public Y { int k; }; + + int main() { + Z mdo; + X *subx = (X*)&mdo; + Y *suby = (Y*)&mdo; + return !((((void*)&mdo != (void*)subx) && + ((void*)&mdo == dynamic_cast(subx))) || + (((void*)&mdo != (void*)suby) && + ((void*)&mdo == dynamic_cast(suby)))); + }], + ac_cv_cpp_dynamic_cast_void_ptr=yes, + ac_cv_cpp_dynamic_cast_void_ptr=no, + ac_cv_cpp_dynamic_cast_void_ptr=no)]) +if test "$ac_cv_cpp_dynamic_cast_void_ptr" = yes ; then + AC_DEFINE(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR) +fi + + +dnl note that this one is reversed - if the test fails, then +dnl we require implementations of unused virtual methods. Which +dnl really blows because it means we'll have useless vtable +dnl bloat. +AC_CACHE_CHECK(whether C++ requires implementation of unused virtual methods, + ac_cv_cpp_unused_required, + [AC_TRY_LINK(class X {private: virtual void never_called();};, + X x;, + ac_cv_cpp_unused_required=no, + ac_cv_cpp_unused_required=yes)]) +if test "$ac_cv_cpp_unused_required" = yes ; then + AC_DEFINE(NEED_CPP_UNUSED_IMPLEMENTATIONS) +fi + + +dnl Some compilers have trouble comparing a constant reference to a templatized +dnl class to zero, and require an explicit operator==() to be defined that takes +dnl an int. This test separates the strong from the weak. + +AC_CACHE_CHECK(for trouble comparing to zero near std::operator!=(), + ac_cv_trouble_comparing_to_zero, + [AC_TRY_COMPILE([#include + template class Foo {}; + class T2; + template int operator==(const T2*, const T&) { return 0; } + template int operator!=(const T2*, const T&) { return 0; }], + [Foo f; return (0 != f);], + ac_cv_trouble_comparing_to_zero=no, + ac_cv_trouble_comparing_to_zero=yes)]) +if test "$ac_cv_trouble_comparing_to_zero" = yes ; then + AC_DEFINE(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO) +fi + +# try harder, when checking for __thread support, see bug 521750 comment #33 and below +_SAVE_LDFLAGS=$LDFLAGS +LDFLAGS="$LDFLAGS $DSO_PIC_CFLAGS $DSO_LDOPTS" +AC_CACHE_CHECK(for __thread keyword for TLS variables, + ac_cv_thread_keyword, + [AC_TRY_LINK([__thread bool tlsIsMainThread = false;], + [return tlsIsMainThread;], + ac_cv_thread_keyword=yes, + ac_cv_thread_keyword=no)]) +LDFLAGS=$_SAVE_LDFLAGS +if test "$ac_cv_thread_keyword" = yes; then + # mips builds fail with TLS variables because of a binutils bug. + # See bug 528687 + case "${target}" in + mips*-*) + : + ;; + *-android*) + : + ;; + *) + AC_DEFINE(HAVE_THREAD_TLS_KEYWORD) + ;; + esac +fi + +dnl Check for the existence of various allocation headers/functions + +MALLOC_H= +AC_CHECK_HEADER(malloc.h, [MALLOC_H=malloc.h]) +if test "$MALLOC_H" = ""; then + AC_CHECK_HEADER(malloc/malloc.h, [MALLOC_H=malloc/malloc.h]) + if test "$MALLOC_H" = ""; then + AC_CHECK_HEADER(sys/malloc.h, [MALLOC_H=sys/malloc.h]) + fi +fi +if test "$MALLOC_H" != ""; then + AC_DEFINE_UNQUOTED(MALLOC_H, <$MALLOC_H>) +fi + +MOZ_ALLOCATING_FUNCS="strndup posix_memalign memalign valloc" +AC_CHECK_FUNCS(strndup posix_memalign memalign valloc) + +dnl See if compiler supports some gcc-style attributes + +AC_CACHE_CHECK(for __attribute__((always_inline)), + ac_cv_attribute_always_inline, + [AC_TRY_COMPILE([], + [inline void f(void) __attribute__((always_inline));], + ac_cv_attribute_always_inline=yes, + ac_cv_attribute_always_inline=no)]) + +AC_CACHE_CHECK(for __attribute__((malloc)), + ac_cv_attribute_malloc, + [AC_TRY_COMPILE([], + [void* f(int) __attribute__((malloc));], + ac_cv_attribute_malloc=yes, + ac_cv_attribute_malloc=no)]) + +AC_CACHE_CHECK(for __attribute__((warn_unused_result)), + ac_cv_attribute_warn_unused, + [AC_TRY_COMPILE([], + [int f(void) __attribute__((warn_unused_result));], + ac_cv_attribute_warn_unused=yes, + ac_cv_attribute_warn_unused=no)]) + +AC_CACHE_CHECK(for __attribute__((noreturn)), + ac_cv_attribute_noreturn, + [AC_TRY_COMPILE([], + [void f(void) __attribute__((noreturn));], + ac_cv_attribute_noreturn=yes, + ac_cv_attribute_noreturn=no)]) + +dnl End of C++ language/feature checks +AC_LANG_C + +dnl ======================================================== +dnl = Internationalization checks +dnl ======================================================== +dnl +dnl Internationalization and Locale support is different +dnl on various UNIX platforms. Checks for specific i18n +dnl features go here. + +dnl check for LC_MESSAGES +AC_CACHE_CHECK(for LC_MESSAGES, + ac_cv_i18n_lc_messages, + [AC_TRY_COMPILE([#include ], + [int category = LC_MESSAGES;], + ac_cv_i18n_lc_messages=yes, + ac_cv_i18n_lc_messages=no)]) +if test "$ac_cv_i18n_lc_messages" = yes; then + AC_DEFINE(HAVE_I18N_LC_MESSAGES) +fi + +AC_HAVE_FUNCS(localeconv) + +fi # SKIP_COMPILER_CHECKS + +TARGET_XPCOM_ABI= +if test -n "${CPU_ARCH}" -a -n "${TARGET_COMPILER_ABI}"; then + TARGET_XPCOM_ABI="${CPU_ARCH}-${TARGET_COMPILER_ABI}" +fi + +dnl Mozilla specific options +dnl ======================================================== +dnl The macros used for command line options +dnl are defined in build/autoconf/altoptions.m4. + +dnl If the compiler supports these attributes, define them as +dnl convenience macros. +if test "$ac_cv_attribute_always_inline" = yes ; then + AC_DEFINE(NS_ALWAYS_INLINE, [__attribute__((always_inline))]) +else + AC_DEFINE(NS_ALWAYS_INLINE,) +fi + +if test "$ac_cv_attribute_malloc" = yes ; then + AC_DEFINE(NS_ATTR_MALLOC, [__attribute__((malloc))]) +else + AC_DEFINE(NS_ATTR_MALLOC,) +fi + +if test "$ac_cv_attribute_warn_unused" = yes ; then + AC_DEFINE(NS_WARN_UNUSED_RESULT, [__attribute__((warn_unused_result))]) +else + AC_DEFINE(NS_WARN_UNUSED_RESULT,) +fi + +if test "$ac_cv_attribute_noreturn" = yes ; then + AC_DEFINE(NS_NORETURN, [__attribute__((noreturn))]) +else + AC_DEFINE(NS_NORETURN,) +fi + +dnl We can't run TRY_COMPILE tests on Windows, so hard-code some +dnl features that Windows actually does support. + +if test -n "$SKIP_COMPILER_CHECKS"; then + dnl Windows has malloc.h + AC_DEFINE(MALLOC_H, []) + AC_DEFINE(HAVE_FORCEINLINE) + AC_DEFINE(HAVE_LOCALECONV) +fi # SKIP_COMPILER_CHECKS + +dnl ======================================================== +dnl = +dnl = Check for external package dependencies +dnl = +dnl ======================================================== +MOZ_ARG_HEADER(External Packages) + +dnl ======================================================== +dnl = Find the right NSPR to use. +dnl ======================================================== +MOZ_ARG_WITH_BOOL(system-nspr, +[ --with-system-nspr Use an NSPR that is already built and installed. + Use the 'nspr-config' script in the current path, + or look for the script in the directories given with + --with-nspr-exec-prefix or --with-nspr-prefix. + (Those flags are only checked if you specify + --with-system-nspr.)], + _USE_SYSTEM_NSPR=1 ) + +MOZ_ARG_WITH_STRING(nspr-cflags, +[ --with-nspr-cflags=FLAGS + Pass FLAGS to CC when building code that uses NSPR. + Use this when there's no accurate nspr-config + script available. This is the case when building + SpiderMonkey as part of the Mozilla tree: the + top-level configure script computes NSPR flags + that accomodate the quirks of that environment.], + NSPR_CFLAGS=$withval) +MOZ_ARG_WITH_STRING(nspr-libs, +[ --with-nspr-libs=LIBS Pass LIBS to LD when linking code that uses NSPR. + See --with-nspr-cflags for more details.], + NSPR_LIBS=$withval) +AC_SUBST(NSPR_CFLAGS) +AC_SUBST(NSPR_LIBS) + +dnl Pass either --with-system-nspr or (--with-nspr-cflags and +dnl --with-nspr-libs), but not both. +if test "$_USE_SYSTEM_NSPR" && (test "$NSPR_CFLAGS" -o "$NSPR_LIBS"); then + AC_MSG_ERROR([--with-system-nspr and --with-nspr-libs/cflags are mutually exclusive. +See 'configure --help'.]) +fi + +dnl Top-level Mozilla switched to requiring NSPR 4.8.6 (bug 560582), but we don't need it in JS. +if test -n "$_USE_SYSTEM_NSPR"; then + MOZ_NATIVE_NSPR= + AM_PATH_NSPR(4.7.0, [MOZ_NATIVE_NSPR=1], [AC_MSG_ERROR([your don't have NSPR installed or your version is too old])]) +fi + +if test -n "$MOZ_NATIVE_NSPR"; then + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $NSPR_CFLAGS" + AC_TRY_COMPILE([#include "prlog.h"], + [#ifndef PR_STATIC_ASSERT + #error PR_STATIC_ASSERT not defined + #endif], + [MOZ_NATIVE_NSPR=1], + AC_MSG_ERROR([system NSPR does not support PR_STATIC_ASSERT])) + CFLAGS=$_SAVE_CFLAGS +fi + +dnl ======================================================== +dnl = +dnl = Application +dnl = +dnl ======================================================== + +MOZ_ARG_HEADER(Application) + +BUILD_STATIC_LIBS= +ENABLE_TESTS=1 + +MOZ_THUMB2= +USE_ARM_KUSER= + +case "${target}" in + arm-android-eabi) + USE_ARM_KUSER=1 + MOZ_THUMB2=1 + ;; +esac + +dnl ======================================================== +dnl Use ARM userspace kernel helpers; tell NSPR to enable +dnl their usage and use them in spidermonkey. +dnl ======================================================== +MOZ_ARG_WITH_BOOL(arm-kuser, +[ --with-arm-kuser Use kuser helpers (Linux/ARM only -- requires kernel 2.6.13 or later)], + USE_ARM_KUSER=1,) +if test -n "$USE_ARM_KUSER"; then + AC_DEFINE(USE_ARM_KUSER) +fi + +dnl ======================================================== +dnl = +dnl = Components & Features +dnl = +dnl ======================================================== +MOZ_ARG_HEADER(Components and Features) + +dnl ======================================================== +dnl = Localization +dnl ======================================================== +MOZ_ARG_ENABLE_STRING(ui-locale, +[ --enable-ui-locale=ab-CD + Select the user interface locale (default: en-US)], + MOZ_UI_LOCALE=$enableval ) +AC_SUBST(MOZ_UI_LOCALE) + +dnl ======================================================== +dnl build the tests by default +dnl ======================================================== +MOZ_ARG_DISABLE_BOOL(tests, +[ --disable-tests Do not build test libraries & programs], + ENABLE_TESTS=, + ENABLE_TESTS=1 ) + +dnl ======================================================== +dnl = +dnl = Module specific options +dnl = +dnl ======================================================== +MOZ_ARG_HEADER(Individual module options) + +dnl Setup default CPU arch for arm target +case "$target_cpu" in + arm*) + MOZ_ARM_ARCH=armv7 + ;; +esac +dnl ======================================================== +dnl = Enable building the Thumb2 instruction set +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(thumb2, + [ --enable-thumb2 Enable Thumb2 instruction set (implies ARMv7)], + MOZ_THUMB2=1, + MOZ_THUMB2=) +if test -n "$MOZ_THUMB2"; then + MOZ_ARM_ARCH=armv7 +fi + +dnl ======================================================== +dnl = Enable building for ARM specific CPU features +dnl ======================================================== +MOZ_ARG_WITH_STRING(cpu-arch, +[ --with-cpu-arch=arch Use specific arm architecture CPU features, default armv7], + MOZ_ARM_ARCH=$withval) + +if test -n "$MOZ_THUMB2"; then + case "$target_cpu" in + arm*) + if test "$MOZ_ARM_ARCH" != "armv7"; then + AC_MSG_ERROR([--enable-thumb2 is not compatible with cpu-arch=$MOZ_ARM_ARCH]) + fi + if test "$GNU_CC"; then + AC_DEFINE(MOZ_THUMB2) + AC_DEFINE(MOZ_ARM_ARCH) + CFLAGS="$CFLAGS -march=armv7-a -mthumb -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS" + CXXFLAGS="$CXXFLAGS -march=armv7-a -mthumb -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS" + ASFLAGS="$ASFLAGS -march=armv7-a -mthumb -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS" + else + AC_MSG_ERROR([--enable-thumb2 is not supported for non-GNU toolchains]) + fi + ;; + *) + AC_MSG_ERROR([--enable-thumb2 is not supported for non-ARM CPU architectures]) + ;; + esac +elif test "$MOZ_ARM_ARCH" = "armv7"; then + case "$target_cpu" in + arm*) + if test "$GNU_CC"; then + AC_DEFINE(MOZ_ARM_ARCH) + CFLAGS="$CFLAGS -march=armv7-a -marm -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS" + CXXFLAGS="$CXXFLAGS -march=armv7-a -marm -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS" + ASFLAGS="$ASFLAGS -march=armv7-a -marm -mfloat-abi=softfp $MOZ_ARM_VFP_FLAGS" + else + AC_MSG_ERROR([--with-cpu-arch=armv7 is not supported for non-GNU toolchains]) + fi + ;; + *) + AC_MSG_ERROR([--with-cpu-arch=armv7 is not supported for non-ARM CPU architectures]) + ;; + esac +else + case "$target_cpu" in + arm*) + if test "$GNU_CC"; then + CFLAGS="$CFLAGS -march=armv5te -mthumb-interwork -msoft-float" + CXXFLAGS="$CXXFLAGS -march=armv5te -mthumb-interwork -msoft-float" + ASFLAGS="$ASFLAGS -march=armv5te -mthumb-interwork -msoft-float" + fi + ;; + esac +fi + +AC_SUBST(MOZ_THUMB2) +AC_SUBST(MOZ_ARM_ARCH) + +dnl ======================================================== +dnl = +dnl = Debugging Options +dnl = +dnl ======================================================== +MOZ_ARG_HEADER(Debugging and Optimizations) + +dnl ======================================================== +dnl = Disable building with debug info. +dnl = Debugging is OFF by default +dnl ======================================================== +if test -z "$MOZ_DEBUG_FLAGS"; then + MOZ_DEBUG_FLAGS="-g" +fi + +MOZ_ARG_ENABLE_STRING(debug, +[ --enable-debug[=DBG] Enable building with developer debug info + (using compiler flags DBG)], +[ if test "$enableval" != "no"; then + MOZ_DEBUG=1 + if test -n "$enableval" -a "$enableval" != "yes"; then + MOZ_DEBUG_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'` + _MOZ_DEBUG_FLAGS_SET=1 + fi + else + MOZ_DEBUG= + fi ], + MOZ_DEBUG=) + +MOZ_DEBUG_ENABLE_DEFS="-DDEBUG -D_DEBUG -DTRACING" +MOZ_ARG_WITH_STRING(debug-label, +[ --with-debug-label=LABELS + Define DEBUG_ for each comma-separated + value given.], +[ for option in `echo $withval | sed 's/,/ /g'`; do + MOZ_DEBUG_ENABLE_DEFS="$MOZ_DEBUG_ENABLE_DEFS -DDEBUG_${option}" +done]) + +MOZ_DEBUG_DISABLE_DEFS="-DNDEBUG -DTRIMMED" + +if test -n "$MOZ_DEBUG"; then + AC_MSG_CHECKING([for valid debug flags]) + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $MOZ_DEBUG_FLAGS" + AC_TRY_COMPILE([#include ], + [printf("Hello World\n");], + _results=yes, + _results=no) + AC_MSG_RESULT([$_results]) + if test "$_results" = "no"; then + AC_MSG_ERROR([These compiler flags are invalid: $MOZ_DEBUG_FLAGS]) + fi + CFLAGS=$_SAVE_CFLAGS +fi + +dnl ======================================================== +dnl = Enable code optimization. ON by default. +dnl ======================================================== +if test -z "$MOZ_OPTIMIZE_FLAGS"; then + MOZ_OPTIMIZE_FLAGS="-O" +fi + +MOZ_ARG_ENABLE_STRING(optimize, +[ --disable-optimize Disable compiler optimization + --enable-optimize=[OPT] Specify compiler optimization flags [OPT=-O]], +[ if test "$enableval" != "no"; then + MOZ_OPTIMIZE=1 + if test -n "$enableval" -a "$enableval" != "yes"; then + MOZ_OPTIMIZE_FLAGS=`echo "$enableval" | sed -e 's|\\\ | |g'` + MOZ_OPTIMIZE=2 + fi +else + MOZ_OPTIMIZE= +fi ], MOZ_OPTIMIZE=1) + +if test "$COMPILE_ENVIRONMENT"; then +if test -n "$MOZ_OPTIMIZE"; then + AC_MSG_CHECKING([for valid optimization flags]) + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $MOZ_OPTIMIZE_FLAGS" + AC_TRY_COMPILE([#include ], + [printf("Hello World\n");], + _results=yes, + _results=no) + AC_MSG_RESULT([$_results]) + if test "$_results" = "no"; then + AC_MSG_ERROR([These compiler flags are invalid: $MOZ_OPTIMIZE_FLAGS]) + fi + CFLAGS=$_SAVE_CFLAGS +fi +fi # COMPILE_ENVIRONMENT + +AC_SUBST(MOZ_OPTIMIZE) +AC_SUBST(MOZ_OPTIMIZE_FLAGS) +AC_SUBST(MOZ_OPTIMIZE_LDFLAGS) +AC_SUBST(MOZ_OPTIMIZE_SIZE_TWEAK) + +dnl ======================================================== +dnl = (Deprecated) generation of debugger info for specific modules +dnl ======================================================== +MOZ_ARG_ENABLE_STRING(debugger-info-modules, +[ --enable-debugger-info-modules + Enable/disable debugger info for specific modules], +[ if test "$enableval" != "no"; then + AC_MSG_WARN([--enable-debugger-info-modules is deprecated, use --enable-debug-symbols instead]) + MOZ_DEBUG_SYMBOLS=1 + fi ]) + +dnl ======================================================== +dnl = Enable generation of debug symbols +dnl ======================================================== +MOZ_ARG_ENABLE_STRING(debug-symbols, +[ --enable-debug-symbols[=DBG] + Enable debugging symbols (using compiler flags DBG)], +[ if test "$enableval" != "no"; then + MOZ_DEBUG_SYMBOLS=1 + if test -n "$enableval" -a "$enableval" != "yes"; then + if test -z "$_MOZ_DEBUG_FLAGS_SET"; then + MOZ_DEBUG_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'` + else + AC_MSG_ERROR([--enable-debug-symbols flags cannot be used with --enable-debug flags]) + fi + fi + fi ]) + +if test -n "$MOZ_DEBUG" -o -n "$MOZ_DEBUG_SYMBOLS"; then + AC_DEFINE(MOZ_DEBUG_SYMBOLS) + export MOZ_DEBUG_SYMBOLS +fi + +dnl ======================================================== +dnl = Disable any treating of compile warnings as errors +dnl ======================================================== +MOZ_ARG_DISABLE_BOOL(warnings-as-errors, +[ --disable-warnings-as-errors + Disable treating of warnings as errors], + MOZ_DISABLE_WARNINGS_AS_ERRORS=1, + MOZ_DISABLE_WARNINGS_AS_ERRORS= ) +if test "$MOZ_DISABLE_WARNINGS_AS_ERRORS"; then + WARNINGS_AS_ERRORS='' +fi + +dnl = Enable trace malloc +dnl ======================================================== +NS_TRACE_MALLOC=${MOZ_TRACE_MALLOC} +MOZ_ARG_ENABLE_BOOL(trace-malloc, +[ --enable-trace-malloc Enable malloc tracing], + NS_TRACE_MALLOC=1, + NS_TRACE_MALLOC= ) +if test "$NS_TRACE_MALLOC"; then + # Please, Mr. Linker Man, don't take away our symbol names + MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS= + AC_DEFINE(NS_TRACE_MALLOC) +fi +AC_SUBST(NS_TRACE_MALLOC) + +dnl ======================================================== +dnl = Enable jemalloc +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(jemalloc, +[ --enable-jemalloc Replace memory allocator with jemalloc], + MOZ_MEMORY=1, + MOZ_MEMORY=) + +if test "$NS_TRACE_MALLOC"; then + MOZ_MEMORY= +fi + +if test "$MOZ_MEMORY"; then + + dnl Don't try to run compiler tests on Windows + if test "$OS_ARCH" = "WINNT"; then + if test -z "$HAVE_64BIT_OS"; then + AC_DEFINE_UNQUOTED([MOZ_MEMORY_SIZEOF_PTR_2POW], 2) + else + AC_DEFINE_UNQUOTED([MOZ_MEMORY_SIZEOF_PTR_2POW], 3) + fi + else + AC_CHECK_SIZEOF([int *], [4]) + case "${ac_cv_sizeof_int_p}" in + 4) + AC_DEFINE_UNQUOTED([MOZ_MEMORY_SIZEOF_PTR_2POW], 2) + ;; + 8) + AC_DEFINE_UNQUOTED([MOZ_MEMORY_SIZEOF_PTR_2POW], 3) + ;; + *) + AC_MSG_ERROR([Unexpected pointer size]) + ;; + esac + fi + + AC_DEFINE(MOZ_MEMORY) + if test "x$MOZ_DEBUG" = "x1"; then + AC_DEFINE(MOZ_MEMORY_DEBUG) + fi + dnl The generic feature tests that determine how to compute ncpus are long and + dnl complicated. Therefore, simply define special cpp variables for the + dnl platforms we have special knowledge of. + case "${target}" in + *-darwin*) + AC_DEFINE(MOZ_MEMORY_DARWIN) + ;; + *-*freebsd*) + AC_DEFINE(MOZ_MEMORY_BSD) + ;; + *-*linux*) + AC_DEFINE(MOZ_MEMORY_LINUX) + ;; + *-netbsd*) + AC_DEFINE(MOZ_MEMORY_BSD) + ;; + *-solaris*) + AC_DEFINE(MOZ_MEMORY_SOLARIS) + ;; + *-msvc*|*-mks*|*-cygwin*|*-mingw*) + AC_DEFINE(MOZ_MEMORY_WINDOWS) + # the interesting bits will get passed down in MOZ_MEMORY_LDFLAGS + ;; + *-*wince) + AC_DEFINE(MOZ_MEMORY_WINCE) + AC_DEFINE(MOZ_MEMORY_WINDOWS) + if test -z "$WINCE_WINDOWS_MOBILE"; then + AC_DEFINE(MOZ_MEMORY_WINCE6) + fi + ;; + *-*winmo) + AC_DEFINE(MOZ_MEMORY_WINCE) + AC_DEFINE(MOZ_MEMORY_WINDOWS) + ;; + *-android*) + AC_DEFINE(MOZ_MEMORY_LINUX) + AC_DEFINE(MOZ_MEMORY_ANDROID) + ;; + *) + AC_MSG_ERROR([--enable-jemalloc not supported on ${target}]) + ;; + esac + + if test "$OS_ARCH" != "Darwin"; then + dnl NB: this must be kept in sync with jemalloc.h + AC_DEFINE(HAVE_JEMALLOC_VALLOC) + AC_DEFINE(HAVE_JEMALLOC_POSIX_MEMALIGN) + AC_DEFINE(HAVE_JEMALLOC_MEMALIGN) + fi +fi +AC_SUBST(MOZ_MEMORY) +AC_SUBST(MOZ_MEMORY_LDFLAGS) + +dnl ======================================================== +dnl = Use malloc wrapper lib +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(wrap-malloc, +[ --enable-wrap-malloc Wrap malloc calls (gnu linker only)], + _WRAP_MALLOC=1, + _WRAP_MALLOC= ) + +if test -n "$_WRAP_MALLOC"; then + if test "$GNU_CC"; then + WRAP_MALLOC_CFLAGS="${LDFLAGS} -Wl,--wrap -Wl,malloc -Wl,--wrap -Wl,calloc -Wl,--wrap -Wl,valloc -Wl,--wrap -Wl,free -Wl,--wrap -Wl,realloc -Wl,--wrap -Wl,memalign -Wl,--wrap -Wl,__builtin_new -Wl,--wrap -Wl,__builtin_vec_new -Wl,--wrap -Wl,__builtin_delete -Wl,--wrap -Wl,__builtin_vec_delete -Wl,--wrap -Wl,PR_Free -Wl,--wrap -Wl,PR_Malloc -Wl,--wrap -Wl,PR_Calloc -Wl,--wrap -Wl,PR_Realloc -Wl,--wrap -Wl,strdup -Wl,--wrap -Wl,strndup -Wl,--wrap -Wl,posix_memalign" + MKSHLIB='$(CXX) $(DSO_LDOPTS) $(WRAP_MALLOC_CFLAGS) $(WRAP_MALLOC_LIB) -o $@' + fi +fi + +dnl ======================================================== +dnl = Location of malloc wrapper lib +dnl ======================================================== +MOZ_ARG_WITH_STRING(wrap-malloc, +[ --with-wrap-malloc=DIR Location of malloc wrapper library], + WRAP_MALLOC_LIB=$withval) + +dnl ======================================================== +dnl = Use JS Call tracing +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(trace-jscalls, +[ --enable-trace-jscalls Enable JS call enter/exit callback (default=no)], + MOZ_TRACE_JSCALLS=1, + MOZ_TRACE_JSCALLS= ) +if test -n "$MOZ_TRACE_JSCALLS"; then + AC_DEFINE(MOZ_TRACE_JSCALLS) +fi + +dnl ======================================================== +dnl = Use TraceVis +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(tracevis, +[ --enable-tracevis Enable TraceVis tracing tool (default=no)], + MOZ_TRACEVIS=1, + MOZ_TRACEVIS= ) +if test -n "$MOZ_TRACEVIS"; then + AC_DEFINE(MOZ_TRACEVIS) + if test -z "$ENABLE_TRACEJIT"; then + AC_MSG_ERROR([--enable-tracevis is incompatible with --disable-tracejit]) + fi +fi + +dnl ======================================================== +dnl = Use GCTimer +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(gctimer, +[ --enable-gctimer Enable GC timer (default=no)], + MOZ_GCTIMER=1, + MOZ_GCTIMER= ) +if test -n "$MOZ_GCTIMER"; then + AC_DEFINE(MOZ_GCTIMER) +fi + +dnl ======================================================== +dnl = Use Valgrind +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(valgrind, +[ --enable-valgrind Enable Valgrind integration hooks (default=no)], + MOZ_VALGRIND=1, + MOZ_VALGRIND= ) +if test -n "$MOZ_VALGRIND"; then + AC_CHECK_HEADER([valgrind/valgrind.h], [], + AC_MSG_ERROR( + [--enable-valgrind specified but Valgrind is not installed])) + AC_DEFINE(MOZ_VALGRIND) +fi + +dnl ======================================================== +dnl jprof +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(jprof, +[ --enable-jprof Enable jprof profiling tool (needs mozilla/tools/jprof). Implies --enable-profiling.], + MOZ_JPROF=1, + MOZ_JPROF= ) +if test -n "$MOZ_JPROF"; then + MOZ_PROFILING=1 + AC_DEFINE(MOZ_JPROF) +fi + +dnl ======================================================== +dnl shark +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(shark, +[ --enable-shark Enable shark remote profiling. Implies --enable-profiling.], + MOZ_SHARK=1, + MOZ_SHARK= ) +if test -n "$MOZ_SHARK"; then + MOZ_PROFILING=1 + AC_DEFINE(MOZ_SHARK) +fi + +dnl ======================================================== +dnl callgrind +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(callgrind, +[ --enable-callgrind Enable callgrind profiling], + MOZ_CALLGRIND=1, + MOZ_CALLGRIND= ) +if test -n "$MOZ_CALLGRIND"; then + AC_DEFINE(MOZ_CALLGRIND) +fi + +dnl ======================================================== +dnl vtune +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(vtune, +[ --enable-vtune Enable vtune profiling. Implies --enable-profiling.], + MOZ_VTUNE=1, + MOZ_VTUNE= ) +if test -n "$MOZ_VTUNE"; then + MOZ_PROFILING=1 + AC_DEFINE(MOZ_VTUNE) +fi + +dnl ======================================================== +dnl Profiling +dnl ======================================================== +if test -n "$MOZ_PROFILING"; then + AC_DEFINE(MOZ_PROFILING) +fi + +dnl ======================================================== +dnl Zealous JavaScript GC +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(gczeal, +[ --enable-gczeal Enable zealous GCing], + JS_GC_ZEAL=1, + JS_GC_ZEAL= ) +if test -n "$JS_GC_ZEAL"; then + AC_DEFINE(JS_GC_ZEAL) +fi + +dnl ====================================================== +dnl = Enable compiling with ccache +dnl ====================================================== +MOZ_ARG_WITH_STRING(ccache, +[ --with-ccache[=path/to/ccache] + Enable compiling with ccache], + CCACHE=$withval, CCACHE="no") + +if test "$CCACHE" != "no"; then + if test -z "$CCACHE" -o "$CCACHE" = "yes"; then + CCACHE= + else + if test ! -e "$CCACHE"; then + AC_MSG_ERROR([$CCACHE not found]) + fi + fi + MOZ_PATH_PROGS(CCACHE, $CCACHE ccache) + if test -z "$CCACHE" -o "$CCACHE" = ":"; then + AC_MSG_ERROR([ccache not found]) + elif test -x "$CCACHE"; then + CC="$CCACHE $CC" + CXX="$CCACHE $CXX" + else + AC_MSG_ERROR([$CCACHE is not executable]) + fi +fi + +dnl ======================================================== +dnl = Enable static checking using gcc-dehydra +dnl ======================================================== + +MOZ_ARG_WITH_STRING(static-checking, +[ --with-static-checking=path/to/gcc_dehydra.so + Enable static checking of code using GCC-dehydra], + DEHYDRA_PATH=$withval, + DEHYDRA_PATH= ) + +if test -n "$DEHYDRA_PATH"; then + if test ! -f "$DEHYDRA_PATH"; then + AC_MSG_ERROR([The dehydra plugin is not at the specified path.]) + fi + AC_DEFINE(NS_STATIC_CHECKING) +fi +AC_SUBST(DEHYDRA_PATH) + +dnl ======================================================== +dnl = Enable stripping of libs & executables +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(strip, +[ --enable-strip Enable stripping of libs & executables ], + ENABLE_STRIP=1, + ENABLE_STRIP= ) + +dnl ======================================================== +dnl = Enable stripping of libs & executables when packaging +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(install-strip, +[ --enable-install-strip Enable stripping of libs & executables when packaging ], + PKG_SKIP_STRIP= , + PKG_SKIP_STRIP=1) + +dnl ======================================================== +dnl = +dnl = Profiling and Instrumenting +dnl = +dnl ======================================================== +MOZ_ARG_HEADER(Profiling and Instrumenting) + +dnl ======================================================== +dnl = Enable timeline service, which provides lightweight +dnl = instrumentation of mozilla for performance measurement. +dnl = Timeline is off by default. +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(timeline, +[ --enable-timeline Enable timeline services ], + MOZ_TIMELINE=1, + MOZ_TIMELINE= ) +if test -n "$MOZ_TIMELINE"; then + AC_DEFINE(MOZ_TIMELINE) +fi + +dnl ======================================================== +dnl = Support for Quantify (Windows) +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(quantify, +[ --enable-quantify Enable Quantify support (Windows only) ], + MOZ_QUANTIFY=1, + MOZ_QUANTIFY= ) + +dnl ======================================================== +dnl = Support for demangling undefined symbols +dnl ======================================================== +if test -z "$SKIP_LIBRARY_CHECKS"; then + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_CHECK_FUNCS(__cxa_demangle, HAVE_DEMANGLE=1, HAVE_DEMANGLE=) + AC_LANG_RESTORE +fi + +# Demangle only for debug or trace-malloc builds +MOZ_DEMANGLE_SYMBOLS= +if test "$HAVE_DEMANGLE" -a "$HAVE_GCC3_ABI" && test "$MOZ_DEBUG" -o "$NS_TRACE_MALLOC"; then + MOZ_DEMANGLE_SYMBOLS=1 + AC_DEFINE(MOZ_DEMANGLE_SYMBOLS) +fi +AC_SUBST(MOZ_DEMANGLE_SYMBOLS) + +dnl ======================================================== +dnl = Support for gcc stack unwinding (from gcc 3.3) +dnl ======================================================== +if test "$HAVE_GCC3_ABI" -a -z "$SKIP_LIBRARY_CHECKS"; then + AC_CHECK_HEADER(unwind.h, AC_CHECK_FUNCS(_Unwind_Backtrace)) +fi + +dnl ======================================================== +dnl = +dnl = Misc. Options +dnl = +dnl ======================================================== +MOZ_ARG_HEADER(Misc. Options) + +dnl ======================================================== +dnl update xterm title +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(xterm-updates, +[ --enable-xterm-updates Update XTERM titles with current command.], + MOZ_UPDATE_XTERM=1, + MOZ_UPDATE_XTERM= ) + +if test -z "$SKIP_COMPILER_CHECKS"; then +dnl ======================================================== +dnl = +dnl = Compiler Options +dnl = +dnl ======================================================== +MOZ_ARG_HEADER(Compiler Options) + +dnl ======================================================== +dnl Check for gcc -pipe support +dnl ======================================================== +AC_MSG_CHECKING([for gcc -pipe support]) +if test -n "$GNU_CC" -a -n "$GNU_CXX" -a -n "$GNU_AS"; then + echo '#include ' > dummy-hello.c + echo 'int main() { printf("Hello World\n"); exit(0); }' >> dummy-hello.c + ${CC} -S dummy-hello.c -o dummy-hello.s 2>&5 + cat dummy-hello.s 2> /dev/null | ${AS_BIN} -o dummy-hello.S - 2>&5 + if test $? = 0; then + _res_as_stdin="yes" + else + _res_as_stdin="no" + fi + if test "$_res_as_stdin" = "yes"; then + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -pipe" + AC_TRY_COMPILE( [ #include ], + [printf("Hello World\n");], + [_res_gcc_pipe="yes"], + [_res_gcc_pipe="no"] ) + CFLAGS=$_SAVE_CFLAGS + fi + if test "$_res_as_stdin" = "yes" -a "$_res_gcc_pipe" = "yes"; then + _res="yes"; + CFLAGS="$CFLAGS -pipe" + CXXFLAGS="$CXXFLAGS -pipe" + else + _res="no" + fi + rm -f dummy-hello.c dummy-hello.s dummy-hello.S dummy-hello a.out + AC_MSG_RESULT([$_res]) +else + AC_MSG_RESULT([no]) +fi + +dnl ======================================================== +dnl Profile guided optimization +dnl ======================================================== +dnl Test for profiling options +dnl Under gcc 3.4+, use -fprofile-generate/-fprofile-use + +dnl Provide a switch to disable PGO even when called via profiledbuild. +MOZ_ARG_DISABLE_BOOL(profile-guided-optimization, +[ --disable-profile-guided-optimization + Don't build with PGO even if called via make profiledbuild], +MOZ_PROFILE_GUIDED_OPTIMIZE_DISABLE=1, +MOZ_PROFILE_GUIDED_OPTIMIZE_DISABLE=) + +AC_SUBST(MOZ_PROFILE_GUIDED_OPTIMIZE_DISABLE) + +_SAVE_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fprofile-generate -fprofile-correction" + +AC_MSG_CHECKING([whether C compiler supports -fprofile-generate]) +AC_TRY_COMPILE([], [return 0;], + [ PROFILE_GEN_CFLAGS="-fprofile-generate" + result="yes" ], result="no") +AC_MSG_RESULT([$result]) + +if test $result = "yes"; then + PROFILE_GEN_LDFLAGS="-fprofile-generate" + PROFILE_USE_CFLAGS="-fprofile-use -fprofile-correction -Wcoverage-mismatch -freorder-blocks-and-partition" + PROFILE_USE_LDFLAGS="-fprofile-use" +fi + +CFLAGS="$_SAVE_CFLAGS" + +if test -n "$INTEL_CC"; then + PROFILE_GEN_CFLAGS="-prof-gen -prof-dir ." + PROFILE_GEN_LDFLAGS= + PROFILE_USE_CFLAGS="-prof-use -prof-dir ." + PROFILE_USE_LDFLAGS= +fi + +dnl Sun Studio on Solaris +if test "$SOLARIS_SUNPRO_CC"; then + PROFILE_GEN_CFLAGS="-xprofile=collect:$_objdir/$enable_application" + PROFILE_GEN_LDFLAGS="-xprofile=collect:$_objdir/$enable_application" + PROFILE_USE_CFLAGS="-xprofile=use:$_objdir/$enable_application" + PROFILE_USE_LDFLAGS="-xprofile=use:$_objdir/$enable_application" +fi + +AC_SUBST(PROFILE_GEN_CFLAGS) +AC_SUBST(PROFILE_GEN_LDFLAGS) +AC_SUBST(PROFILE_USE_CFLAGS) +AC_SUBST(PROFILE_USE_LDFLAGS) + +AC_LANG_CPLUSPLUS + +dnl ======================================================== +dnl Test for -pedantic bustage +dnl ======================================================== +MOZ_ARG_DISABLE_BOOL(pedantic, +[ --disable-pedantic Issue all warnings demanded by strict ANSI C ], +_PEDANTIC= ) +if test "$_PEDANTIC"; then + _SAVE_CXXFLAGS=$CXXFLAGS + CXXFLAGS="$CXXFLAGS ${_WARNINGS_CXXFLAGS} ${_COMPILER_PREFIX}-pedantic ${_COMPILER_PREFIX}-Wno-long-long" + AC_MSG_CHECKING([whether C++ compiler has -pedantic long long bug]) + AC_TRY_COMPILE([$configure_static_assert_macros], + [CONFIGURE_STATIC_ASSERT(sizeof(long long) == 8)], + result="no", result="yes" ) + AC_MSG_RESULT([$result]) + CXXFLAGS="$_SAVE_CXXFLAGS" + + case "$result" in + no) + _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} ${_COMPILER_PREFIX}-pedantic ${_COMPILER_PREFIX}-Wno-long-long" + _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} ${_COMPILER_PREFIX}-pedantic ${_COMPILER_PREFIX}-Wno-long-long" + ;; + yes) + AC_MSG_ERROR([Your compiler appears to have a known bug where long long is miscompiled when using -pedantic. Reconfigure using --disable-pedantic. ]) + ;; + esac +fi + +dnl ======================================================== +dnl Test for correct temporary object destruction order +dnl ======================================================== +dnl We want to make sure the compiler follows the C++ spec here as +dnl xpcom and the string classes depend on it (bug 235381). +AC_MSG_CHECKING([for correct temporary object destruction order]) +AC_TRY_RUN([ class A { + public: A(int& x) : mValue(x) {} + ~A() { mValue--; } + operator char**() { return 0; } + private: int& mValue; + }; + void func(char **arg) {} + int m=2; + void test() { + func(A(m)); + if (m==1) m = 0; + } + int main() { + test(); + return(m); + } + ], + result="yes", result="no", result="maybe") +AC_MSG_RESULT([$result]) + +if test "$result" = "no"; then + AC_MSG_ERROR([Your compiler does not follow the C++ specification for temporary object destruction order.]) +fi + +dnl ======================================================== +dnl Autoconf test for gcc 2.7.2.x (and maybe others?) so that we don't +dnl provide non-const forms of the operator== for comparing nsCOMPtrs to +dnl raw pointers in nsCOMPtr.h. (VC++ has the same bug.) +dnl ======================================================== +_SAVE_CXXFLAGS=$CXXFLAGS +CXXFLAGS="$CXXFLAGS ${_WARNINGS_CXXFLAGS}" +AC_CACHE_CHECK(for correct overload resolution with const and templates, + ac_nscap_nonconst_opeq_bug, + [AC_TRY_COMPILE([ + template + class Pointer + { + public: + T* myPtr; + }; + + template + int operator==(const Pointer& rhs, U* lhs) + { + return rhs.myPtr == lhs; + } + + template + int operator==(const Pointer& rhs, const U* lhs) + { + return rhs.myPtr == lhs; + } + ], + [ + Pointer foo; + const int* bar; + return foo == bar; + ], + ac_nscap_nonconst_opeq_bug="no", + ac_nscap_nonconst_opeq_bug="yes")]) +CXXFLAGS="$_SAVE_CXXFLAGS" + +if test "$ac_nscap_nonconst_opeq_bug" = "yes" ; then + AC_DEFINE(NSCAP_DONT_PROVIDE_NONCONST_OPEQ) +fi + +dnl ======================================================== +dnl Check for tm_zone, tm_gmtoff in struct tm +dnl ======================================================== +AC_CACHE_CHECK(for tm_zone tm_gmtoff in struct tm, + ac_cv_struct_tm_zone_tm_gmtoff, + [AC_TRY_COMPILE([#include ], + [struct tm tm; tm.tm_zone = 0; tm.tm_gmtoff = 1;], + [ac_cv_struct_tm_zone_tm_gmtoff="yes"], + [ac_cv_struct_tm_zone_tm_gmtoff="no"])]) +if test "$ac_cv_struct_tm_zone_tm_gmtoff" = "yes" ; then + AC_DEFINE(HAVE_TM_ZONE_TM_GMTOFF) +fi + +fi # SKIP_COMPILER_CHECKS + +dnl ======================================================== +dnl C++ rtti +dnl Should be smarter and check that the compiler does indeed have rtti +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(cpp-rtti, +[ --enable-cpp-rtti Enable C++ RTTI ], +[ _MOZ_USE_RTTI=1 ], +[ _MOZ_USE_RTTI= ]) + +if test "$_MOZ_USE_RTTI"; then + _MOZ_RTTI_FLAGS=$_MOZ_RTTI_FLAGS_ON +else + _MOZ_RTTI_FLAGS=$_MOZ_RTTI_FLAGS_OFF +fi + +AC_SUBST(_MOZ_RTTI_FLAGS_ON) + +dnl ======================================================== +dnl C++ exceptions (g++/VC/irix6/Sun only - for now) +dnl Should be smarter and check that the compiler does indeed have exceptions +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(cpp-exceptions, +[ --enable-cpp-exceptions Enable C++ exceptions ], +[ _MOZ_CPP_EXCEPTIONS=1 ], +[ _MOZ_CPP_EXCEPTIONS= ]) + +if test "$_MOZ_CPP_EXCEPTIONS"; then + _MOZ_EXCEPTIONS_FLAGS=$_MOZ_EXCEPTIONS_FLAGS_ON + AC_DEFINE(MOZ_CPP_EXCEPTIONS) +else + _MOZ_EXCEPTIONS_FLAGS=$_MOZ_EXCEPTIONS_FLAGS_OFF +fi + +AC_SUBST(_MOZ_EXCEPTIONS_FLAGS_ON) + +# Irix & OSF native compilers do not like exception declarations +# when exceptions are disabled +if test -n "$MIPSPRO_CXX" -o -n "$COMPAQ_CXX" -o -n "$VACPP"; then + AC_DEFINE(CPP_THROW_NEW, []) +else + AC_DEFINE(CPP_THROW_NEW, [throw()]) +fi +AC_LANG_C + +dnl ======================================================== +dnl = +dnl = Build depencency options +dnl = +dnl ======================================================== +MOZ_ARG_HEADER(Build dependencies) + +dnl ======================================================== +dnl = Do not auto generate dependency info +dnl ======================================================== +MOZ_AUTO_DEPS=1 +MOZ_ARG_DISABLE_BOOL(auto-deps, +[ --disable-auto-deps Do not automatically generate dependency info], + MOZ_AUTO_DEPS=, + MOZ_AUTO_DEPS=1) + +if test -n "$MOZ_AUTO_DEPS"; then +dnl ======================================================== +dnl = Use mkdepend instead of $CC -MD for dependency generation +dnl ======================================================== +_cpp_md_flag= +MOZ_ARG_DISABLE_BOOL(md, +[ --disable-md Do not use compiler-based dependencies ], + [_cpp_md_flag=], + [_cpp_md_flag=1], + [dnl Default is to turn on -MD if using GNU-compatible compilers + if test "$GNU_CC" -a "$GNU_CXX" -a "$OS_ARCH" != "WINNT" -a "$OS_ARCH" != "WINCE"; then + _cpp_md_flag=1 + fi + dnl Default is to use -xM if using Sun Studio on Solaris + if test "$SOLARIS_SUNPRO_CC"; then + _cpp_md_flag=1 + fi]) +if test "$_cpp_md_flag"; then + COMPILER_DEPEND=1 + if test "$OS_ARCH" = "OpenVMS"; then + _DEPEND_CFLAGS='$(subst =, ,$(filter-out %/.pp,-MM=-MD=-MF=$(MDDEPDIR)/$(basename $(@F)).pp))' + else + _DEPEND_CFLAGS='$(filter-out %/.pp,-MD -MF $(MDDEPDIR)/$(basename $(@F)).pp)' + fi + dnl Sun Studio on Solaris use -xM instead of -MD, see config/rules.mk + if test "$SOLARIS_SUNPRO_CC"; then + _DEPEND_CFLAGS= + fi +else + COMPILER_DEPEND= + dnl Don't override this for MSVC + if test -z "$_WIN32_MSVC"; then + _USE_CPP_INCLUDE_FLAG= + _DEFINES_CFLAGS='$(ACDEFINES) -D_JS_CONFDEFS_H_ -DMOZILLA_CLIENT' + _DEFINES_CXXFLAGS='$(ACDEFINES) -D_JS_CONFDEFS_H_ -DMOZILLA_CLIENT' + else + echo '#include ' > dummy-hello.c + changequote(,) + CL_INCLUDES_PREFIX=`"${CC}" -showIncludes -c -Fonul dummy-hello.c 2>&1 | sed -ne 's/^\([^:]*:[^:]*:\).*stdio.h$/\1/p'` + changequote([,]) + if test -z "$CL_INCLUDES_PREFIX"; then + AC_MSG_ERROR([Cannot find cl -showIncludes prefix.]) + fi + AC_SUBST(CL_INCLUDES_PREFIX) + rm -f dummy-hello.c + _topsrcdirwin=`cd \`dirname $0\`; pwd -W` + dnl cl.py provides dependency generation for MSVC + CC_WRAPPER="$PYTHON -O $_topsrcdirwin/build/cl.py" + CXX_WRAPPER="$PYTHON -O $_topsrcdirwin/build/cl.py" + COMPILER_DEPEND=1 + fi +fi +fi # MOZ_AUTO_DEPS +MDDEPDIR='.deps' +AC_SUBST(MOZ_AUTO_DEPS) +AC_SUBST(COMPILER_DEPEND) +AC_SUBST(MDDEPDIR) +AC_SUBST(CC_WRAPPER) +AC_SUBST(CXX_WRAPPER) + + +dnl ======================================================== +dnl = +dnl = Static Build Options +dnl = +dnl ======================================================== +MOZ_ARG_HEADER(Static build options) + +MOZ_ARG_ENABLE_BOOL(static, +[ --enable-static Enable building of internal static libs], + BUILD_STATIC_LIBS=1, + BUILD_STATIC_LIBS=) + +dnl ======================================================== +dnl = Link js shell to system readline +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(readline, +[ --enable-readline Link js shell to system readline library], + JS_WANT_READLINE=1, + JS_WANT_READLINE= ) + +JS_NATIVE_EDITLINE= +EDITLINE_LIBS= +JS_DISABLE_SHELL= + +case "$target" in +*-wince*|*-winmo*|*-mingw*|*-cygwin*|*-msvc*|*-mks*) + NO_EDITLINE=1 + ;; +*-symbian*) + NO_EDITLINE=1 + JS_DISABLE_SHELL=1 + ;; +*) + ;; +esac + +if test -z "$SKIP_LIBRARY_CHECKS" -a -z "$NO_EDITLINE"; then + if test -n "$JS_WANT_READLINE"; then + AC_CHECK_LIB(readline, readline, + EDITLINE_LIBS="-lreadline", + AC_MSG_ERROR([No system readline library found.])) + else + dnl By default, we use editline + JS_NATIVE_EDITLINE=1 + EDITLINE_LIBS='$(DEPTH)/editline/$(LIB_PREFIX)editline.$(LIB_SUFFIX)' + fi + + dnl Either way, we want to build with line editing support. + AC_DEFINE(EDITLINE) +fi +AC_SUBST(JS_NATIVE_EDITLINE) +AC_SUBST(JS_DISABLE_SHELL) +AC_SUBST(EDITLINE_LIBS) + +dnl ======================================================== +dnl = +dnl = Standalone module options +dnl = +dnl ======================================================== +MOZ_ARG_HEADER(Standalone module options (Not for building Mozilla)) + +dnl ======================================================== +dnl = Build jsctypes if it's enabled +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(ctypes, +[ --enable-ctypes Enable js-ctypes (default=no)], + JS_HAS_CTYPES=1, + JS_HAS_CTYPES= ) +AC_SUBST(JS_HAS_CTYPES) +if test "$JS_HAS_CTYPES"; then + dnl Error out if we're on MSVC and MASM is unavailable. + if test -n "$_MSC_VER" -a \( "$AS" != "ml.exe" -a "$AS" != "ml64.exe" \); then + AC_MSG_ERROR([\"$AS\" is not a suitable assembler to build js-ctypes. If you are building with MS Visual Studio 8 Express, you may download the MASM 8.0 package, upgrade to Visual Studio 9 Express, or install the Vista SDK. Or do not use --enable-ctypes.]) + fi + AC_DEFINE(JS_HAS_CTYPES) +fi + +if test "$MOZ_DEBUG" -o "$NS_TRACE_MALLOC"; then + MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS= +fi + +MOZ_ARG_WITH_STRING(sync-build-files, +[ --with-sync-build-files=DIR + Check that files in 'config' and 'build' match + their originals in 'DIR/config' and 'DIR/build'. + This helps keep the SpiderMonkey build machinery + in sync with Mozilla's, on which it is based.], +[MOZ_SYNC_BUILD_FILES=$withval ] ) +AC_SUBST(MOZ_SYNC_BUILD_FILES) + +dnl ======================================================== +dnl = +dnl = Maintainer debug option (no --enable equivalent) +dnl = +dnl ======================================================== + +AC_SUBST(AR) +AC_SUBST(AR_FLAGS) +AC_SUBST(AR_LIST) +AC_SUBST(AR_EXTRACT) +AC_SUBST(AR_DELETE) +AC_SUBST(AS) +AC_SUBST(ASFLAGS) +AC_SUBST(AS_DASH_C_FLAG) +AC_SUBST(LD) +AC_SUBST(RC) +AC_SUBST(RCFLAGS) +AC_SUBST(WINDRES) +AC_SUBST(IMPLIB) +AC_SUBST(FILTER) +AC_SUBST(BIN_FLAGS) +AC_SUBST(NS_USE_NATIVE) +AC_SUBST(MOZ_JS_LIBS) +AC_SUBST(MOZ_PSM) +AC_SUBST(MOZ_DEBUG) +AC_SUBST(MOZ_DEBUG_SYMBOLS) +AC_SUBST(MOZ_DEBUG_ENABLE_DEFS) +AC_SUBST(MOZ_DEBUG_DISABLE_DEFS) +AC_SUBST(MOZ_DEBUG_FLAGS) +AC_SUBST(MOZ_DEBUG_LDFLAGS) +AC_SUBST(WARNINGS_AS_ERRORS) +AC_SUBST(MOZ_LEAKY) +AC_SUBST(MOZ_JPROF) +AC_SUBST(MOZ_SHARK) +AC_SUBST(MOZ_CALLGRIND) +AC_SUBST(MOZ_VTUNE) +AC_SUBST(MOZ_PROFILING) +AC_SUBST(MOZ_JSLOADER) +AC_SUBST(MOZ_QUANTIFY) +AC_SUBST(LIBICONV) + +AC_SUBST(BUILD_STATIC_LIBS) +AC_SUBST(ENABLE_TESTS) + +AC_SUBST(ENABLE_STRIP) +AC_SUBST(PKG_SKIP_STRIP) +AC_SUBST(INCREMENTAL_LINKER) +AC_SUBST(MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS) +AC_SUBST(MOZ_COMPONENT_NSPR_LIBS) + +AC_SUBST(MOZ_FIX_LINK_PATHS) + +AC_SUBST(USE_DEPENDENT_LIBS) + +AC_SUBST(MOZ_BUILD_ROOT) +AC_SUBST(MOZ_OS2_TOOLS) + +AC_SUBST(MOZ_POST_DSO_LIB_COMMAND) +AC_SUBST(MOZ_POST_PROGRAM_COMMAND) +AC_SUBST(MOZ_TIMELINE) + +AC_SUBST(MOZ_APP_NAME) +AC_SUBST(MOZ_APP_DISPLAYNAME) +AC_SUBST(MOZ_APP_UA_NAME) +AC_SUBST(MOZ_APP_VERSION) +AC_SUBST(MOZ_UA_FIREFOX_VERSION) +AC_SUBST(FIREFOX_VERSION) + +AC_SUBST(MOZ_PKG_SPECIAL) + +AC_SUBST(MOZILLA_OFFICIAL) + +dnl win32 options +AC_SUBST(MOZ_MAPINFO) +AC_SUBST(MOZ_BROWSE_INFO) +AC_SUBST(MOZ_TOOLS_DIR) +AC_SUBST(CYGWIN_WRAPPER) +AC_SUBST(AS_PERL) +AC_SUBST(WIN32_REDIST_DIR) +AC_SUBST(PYTHON) + +AC_SUBST(WINCE) +AC_SUBST(WINCE_SDK_DIR) +AC_SUBST(WINCE_WINDOWS_MOBILE) + +dnl Echo the CFLAGS to remove extra whitespace. +CFLAGS=`echo \ + $_WARNINGS_CFLAGS \ + $CFLAGS` + +CXXFLAGS=`echo \ + $_MOZ_RTTI_FLAGS \ + $_MOZ_EXCEPTIONS_FLAGS \ + $_WARNINGS_CXXFLAGS \ + $CXXFLAGS` + +COMPILE_CFLAGS=`echo \ + $_DEFINES_CFLAGS \ + $_DEPEND_CFLAGS \ + $COMPILE_CFLAGS` + +COMPILE_CXXFLAGS=`echo \ + $_DEFINES_CXXFLAGS \ + $_DEPEND_CFLAGS \ + $COMPILE_CXXFLAGS` + +AC_SUBST(SYSTEM_MAKEDEPEND) + +AC_SUBST(NSPR_CFLAGS) +AC_SUBST(NSPR_LIBS) +AC_SUBST(MOZ_NATIVE_NSPR) + +AC_SUBST(CFLAGS) +AC_SUBST(CXXFLAGS) +AC_SUBST(CPPFLAGS) +AC_SUBST(COMPILE_CFLAGS) +AC_SUBST(COMPILE_CXXFLAGS) +AC_SUBST(LDFLAGS) +AC_SUBST(LIBS) +AC_SUBST(CROSS_COMPILE) + +AC_SUBST(HOST_CC) +AC_SUBST(HOST_CXX) +AC_SUBST(HOST_CFLAGS) +AC_SUBST(HOST_CXXFLAGS) +AC_SUBST(HOST_LDFLAGS) +AC_SUBST(HOST_OPTIMIZE_FLAGS) +AC_SUBST(HOST_AR) +AC_SUBST(HOST_AR_FLAGS) +AC_SUBST(HOST_LD) +AC_SUBST(HOST_RANLIB) +AC_SUBST(HOST_NSPR_MDCPUCFG) +AC_SUBST(HOST_BIN_SUFFIX) +AC_SUBST(HOST_OS_ARCH) + +AC_SUBST(TARGET_CPU) +AC_SUBST(TARGET_VENDOR) +AC_SUBST(TARGET_OS) +AC_SUBST(TARGET_NSPR_MDCPUCFG) +AC_SUBST(TARGET_MD_ARCH) +AC_SUBST(TARGET_XPCOM_ABI) +AC_SUBST(OS_TARGET) +AC_SUBST(OS_ARCH) +AC_SUBST(OS_RELEASE) +AC_SUBST(OS_TEST) +AC_SUBST(CPU_ARCH) +AC_SUBST(INTEL_ARCHITECTURE) + +AC_SUBST(WRAP_MALLOC_CFLAGS) +AC_SUBST(WRAP_MALLOC_LIB) +AC_SUBST(MKSHLIB) +AC_SUBST(MKCSHLIB) +AC_SUBST(MKSHLIB_FORCE_ALL) +AC_SUBST(MKSHLIB_UNFORCE_ALL) +AC_SUBST(DSO_CFLAGS) +AC_SUBST(DSO_PIC_CFLAGS) +AC_SUBST(DSO_LDOPTS) +AC_SUBST(LIB_PREFIX) +AC_SUBST(DLL_PREFIX) +AC_SUBST(DLL_SUFFIX) +AC_DEFINE_UNQUOTED(MOZ_DLL_SUFFIX, "$DLL_SUFFIX") +AC_SUBST(LIB_SUFFIX) +AC_SUBST(OBJ_SUFFIX) +AC_SUBST(BIN_SUFFIX) +AC_SUBST(ASM_SUFFIX) +AC_SUBST(IMPORT_LIB_SUFFIX) +AC_SUBST(USE_N32) +AC_SUBST(CC_VERSION) +AC_SUBST(CXX_VERSION) +AC_SUBST(MSMANIFEST_TOOL) + +if test "$USING_HCC"; then + CC='${topsrcdir}/build/hcc' + CC="$CC '$_OLDCC'" + CXX='${topsrcdir}/build/hcpp' + CXX="$CXX '$_OLDCXX'" + AC_SUBST(CC) + AC_SUBST(CXX) +fi + +AC_MSG_CHECKING([for posix_fallocate]) +AC_TRY_LINK([#define _XOPEN_SOURCE 600 + #include ], + [posix_fallocate(0, 0, 0);], + [ac_cv___posix_fallocate=true], + [ac_cv___posix_fallocate=false]) + +if test "$ac_cv___posix_fallocate" = true ; then + AC_DEFINE(HAVE_POSIX_FALLOCATE) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +dnl Check for missing components +if test "$COMPILE_ENVIRONMENT"; then +if test "$MOZ_X11"; then + dnl ==================================================== + dnl = Check if X headers exist + dnl ==================================================== + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $XCFLAGS" + AC_TRY_COMPILE([ + #include + #include + #include + #include + ], + [ + Display *dpy = 0; + if ((dpy = XOpenDisplay(NULL)) == NULL) { + fprintf(stderr, ": can't open %s\n", XDisplayName(NULL)); + exit(1); + } + ], [], + [ AC_MSG_ERROR([Could not compile basic X program.]) ]) + CFLAGS="$_SAVE_CFLAGS" + + if test ! -z "$MISSING_X"; then + AC_MSG_ERROR([ Could not find the following X libraries: $MISSING_X ]); + fi + +fi # MOZ_X11 +fi # COMPILE_ENVIRONMENT + +dnl Set various defines and substitutions +dnl ======================================================== + +if test "$OS_ARCH" = "BeOS"; then + AC_DEFINE(XP_BEOS) +elif test "$OS_ARCH" = "Darwin"; then + AC_DEFINE(XP_MACOSX) + AC_DEFINE(XP_UNIX) + AC_DEFINE(UNIX_ASYNC_DNS) +elif test "$OS_ARCH" = "OpenVMS"; then + AC_DEFINE(XP_UNIX) +elif test "$OS_ARCH" != "WINNT" -a "$OS_ARCH" != "OS2" -a "$OS_ARCH" != "WINCE"; then + AC_DEFINE(XP_UNIX) + AC_DEFINE(UNIX_ASYNC_DNS) +fi + +AC_ARG_ENABLE(threadsafe, + [ --enable-threadsafe Enable support for multiple threads.], + [AC_DEFINE(JS_THREADSAFE)],) + +if test "$MOZ_DEBUG"; then + AC_DEFINE(MOZ_REFLOW_PERF) + AC_DEFINE(MOZ_REFLOW_PERF_DSP) +fi + +if test "$ACCESSIBILITY" -a "$MOZ_ENABLE_GTK2" ; then + AC_DEFINE(MOZ_ACCESSIBILITY_ATK) + ATK_FULL_VERSION=`$PKG_CONFIG --modversion atk` + ATK_MAJOR_VERSION=`echo ${ATK_FULL_VERSION} | $AWK -F\. '{ print $1 }'` + ATK_MINOR_VERSION=`echo ${ATK_FULL_VERSION} | $AWK -F\. '{ print $2 }'` + ATK_REV_VERSION=`echo ${ATK_FULL_VERSION} | $AWK -F\. '{ print $3 }'` + AC_DEFINE_UNQUOTED(ATK_MAJOR_VERSION, $ATK_MAJOR_VERSION) + AC_DEFINE_UNQUOTED(ATK_MINOR_VERSION, $ATK_MINOR_VERSION) + AC_DEFINE_UNQUOTED(ATK_REV_VERSION, $ATK_REV_VERSION) +fi + +dnl ======================================================== +dnl JavaScript shell +dnl ======================================================== + +AC_HAVE_FUNCS(setlocale) +AC_HAVE_FUNCS(localeconv) + +dnl ======================================================== +dnl Use cygwin wrapper for win32 builds, except MSYS/MinGW +dnl ======================================================== +case "$host_os" in +mingw*) + WIN_TOP_SRC=`cd $srcdir; pwd -W` + ;; +cygwin*|msvc*|mks*) + HOST_CC="\$(CYGWIN_WRAPPER) $HOST_CC" + HOST_CXX="\$(CYGWIN_WRAPPER) $HOST_CXX" + CC="\$(CYGWIN_WRAPPER) $CC" + CXX="\$(CYGWIN_WRAPPER) $CXX" + CPP="\$(CYGWIN_WRAPPER) $CPP" + LD="\$(CYGWIN_WRAPPER) $LD" + AS="\$(CYGWIN_WRAPPER) $AS" + RC="\$(CYGWIN_WRAPPER) $RC" + CYGDRIVE_MOUNT=`mount -p | awk '{ if (/^\//) { print $1; exit } }'` + WIN_TOP_SRC=`cygpath -a -w $srcdir | sed -e 's|\\\\|/|g'` + ;; +esac + +AC_SUBST(CYGDRIVE_MOUNT) +AC_SUBST(WIN_TOP_SRC) + +AC_SUBST(MOZILLA_VERSION) + +AC_SUBST(ac_configure_args) + +dnl Spit out some output +dnl ======================================================== + +# Save the defines header file before autoconf removes it. +# (Do not add AC_DEFINE calls after this line.) + _CONFIG_TMP=confdefs-tmp.h + _CONFIG_DEFS_H=js-confdefs.h + + cat > $_CONFIG_TMP <<\EOF +/* List of defines generated by configure. Included with preprocessor flag, + * -include, to avoid long list of -D defines on the compile command-line. + * Do not edit. + */ + +#ifndef _JS_CONFDEFS_H_ +#define _JS_CONFDEFS_H_ +EOF + +_EGREP_PATTERN='^#define (' +if test -n "$_NON_GLOBAL_ACDEFINES"; then + for f in $_NON_GLOBAL_ACDEFINES; do + _EGREP_PATTERN="${_EGREP_PATTERN}$f|" + done +fi +_EGREP_PATTERN="${_EGREP_PATTERN}dummy_never_defined)" + + sort confdefs.h | egrep -v "$_EGREP_PATTERN" >> $_CONFIG_TMP + + cat >> $_CONFIG_TMP <<\EOF + +#endif /* _JS_CONFDEFS_H_ */ + +EOF + + # Only write js-confdefs.h when something changes (or it doesn't exist) + if cmp -s $_CONFIG_TMP $_CONFIG_DEFS_H; then + rm $_CONFIG_TMP + else + AC_MSG_RESULT("creating $_CONFIG_DEFS_H") + mv -f $_CONFIG_TMP $_CONFIG_DEFS_H + + echo ==== $_CONFIG_DEFS_H ================================= + cat $_CONFIG_DEFS_H + fi + +dnl Probably shouldn't call this manually but we always want the output of DEFS +rm -f confdefs.h.save +mv confdefs.h confdefs.h.save +egrep -v "$_EGREP_PATTERN" confdefs.h.save > confdefs.h +AC_OUTPUT_MAKE_DEFS() +MOZ_DEFINES=$DEFS +AC_SUBST(MOZ_DEFINES) +rm -f confdefs.h +mv confdefs.h.save confdefs.h + +MAKEFILES=" + Makefile + shell/Makefile + lirasm/Makefile + jsapi-tests/Makefile + tests/Makefile + config/Makefile + config/autoconf.mk + config/mkdepend/Makefile +" + +if test -n "$JS_NATIVE_EDITLINE"; then + MAKEFILES="$MAKEFILES +editline/Makefile +" +fi + +dnl +dnl Run a perl script to quickly create the makefiles. +dnl If it succeeds, it outputs a shell command to set CONFIG_FILES +dnl for the files it cannot handle correctly. This way, config.status +dnl will handle these files. +dnl If it fails, nothing is set and config.status will run as usual. +dnl +dnl This does not change the $MAKEFILES variable. +dnl +dnl OpenVMS gets a line overflow on the long eval command, so use a temp file. +dnl +if test -z "${AS_PERL}"; then +echo $MAKEFILES | ${PERL} $srcdir/build/autoconf/acoutput-fast.pl > conftest.sh +else +echo $MAKEFILES | ${PERL} $srcdir/build/autoconf/acoutput-fast.pl -nowrap --cygwin-srcdir=$srcdir > conftest.sh +fi +. ./conftest.sh +rm conftest.sh + +echo $MAKEFILES > unallmakefiles + +mv -f config/autoconf.mk config/autoconf.mk.orig 2> /dev/null + +AC_OUTPUT($MAKEFILES) + +dnl Prevent the regeneration of autoconf.mk forcing rebuilds of the world +if cmp -s config/autoconf.mk config/autoconf.mk.orig; then + echo "config/autoconf.mk is unchanged" + mv -f config/autoconf.mk.orig config/autoconf.mk 2> /dev/null +else + rm -f config/autoconf.mk.orig 2> /dev/null +fi + +# Produce the js-config script at configure time; see the comments for +# 'js-config' in Makefile.in. +AC_MSG_RESULT(invoking make to create js-config script) +$GMAKE js-config + +# Build jsctypes if it's enabled. +if test "$JS_HAS_CTYPES"; then + # Run the libffi 'configure' script. + ac_configure_args="--disable-shared --enable-static --disable-raw-api" + if test "$MOZ_DEBUG"; then + ac_configure_args="$ac_configure_args --enable-debug" + fi + if test "$DSO_PIC_CFLAGS"; then + ac_configure_args="$ac_configure_args --with-pic" + fi + if test "$CROSS_COMPILE"; then + case "$target" in + *-mingw*) + ac_configure_args="$ac_configure_args --build=$build --host=${target_cpu}-${target_os} HOST_CC=\"$HOST_CC\" CC=\"$CC\"" + ;; + *-android*) + CFLAGS="$ANDROID_CFLAGS" + CPPFLAGS="$ANDROID_CPPFLAGS" + LDFLAGS="$ANDROID_LDFLAGS" + + export AS CC CXX CPP LD AR RANLIB STRIP CPPFLAGS CFLAGS LDFLAGS + + ac_configure_args="$ac_configure_args --build=$build --host=${target_cpu}-${target_os} HOST_CC=\"$HOST_CC\"" + ;; + *) + ac_configure_args="$ac_configure_args --build=$build --host=$target HOST_CC=\"$HOST_CC\" CC=\"$CC\"" + ;; + esac + fi + if test "$_MSC_VER"; then + # Use a wrapper script for cl and ml that looks more like gcc. + # autotools can't quite handle an MSVC build environment yet. + ac_configure_args="$ac_configure_args LD=link CPP=\"cl -nologo -EP\" SHELL=sh.exe" + case "${target_cpu}" in + x86_64) + # Need target since MSYS tools into mozilla-build may be 32bit + ac_configure_args="$ac_configure_args CC=\"$_topsrcdir/ctypes/libffi/msvcc.sh -m64\" --build=$build --host=$target" + ;; + *) + ac_configure_args="$ac_configure_args CC=$_topsrcdir/ctypes/libffi/msvcc.sh" + ;; + esac + fi + if test "$SOLARIS_SUNPRO_CC"; then + # Always use gcc for libffi on Solaris + if test ! "$HAVE_64BIT_OS"; then + ac_configure_args="$ac_configure_args CC=gcc CFLAGS=-m32 LD= LDFLAGS=" + else + ac_configure_args="$ac_configure_args CC=gcc CFLAGS=-m64 LD= LDFLAGS=" + fi + fi + if test "$AIX_IBM_XLC"; then + # Always use gcc for libffi on IBM AIX5/AIX6 + if test ! "$HAVE_64BIT_OS"; then + ac_configure_args="$ac_configure_args CC=gcc CFLAGS=-maix32" + else + ac_configure_args="$ac_configure_args CC=gcc CFLAGS=-maix64" + fi + fi + if test "$OS_ARCH" = "OS2"; then + ac_configure_args="$ac_configure_args CFLAGS=-Zomf AR=emxomfar" + fi + if test -n "$MOZ_THUMB2"; then + ac_configure_args="$ac_configure_args --enable-thumb2" + fi + if test -n "$MOZ_ARM_ARCH"; then + ac_configure_args="$ac_configure_args --with-cpu-arch=$MOZ_ARM_ARCH" + fi + + # Use a separate cache file for libffi, since it does things differently + # from our configure. + mkdir -p $_objdir/ctypes/libffi + old_cache_file=$cache_file + cache_file=$_objdir/ctypes/libffi/config.cache + old_config_files=$CONFIG_FILES + unset CONFIG_FILES + AC_OUTPUT_SUBDIRS(ctypes/libffi) + cache_file=$old_cache_file + ac_configure_args="$_SUBDIR_CONFIG_ARGS" + CONFIG_FILES=$old_config_files +fi + diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp new file mode 100644 index 0000000..763d6e6 --- /dev/null +++ b/js/src/ctypes/CTypes.cpp @@ -0,0 +1,6276 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is js-ctypes. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation . + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Witte + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "CTypes.h" +#include "Library.h" +#include "jsnum.h" +#include + +#include +#if defined(XP_WIN) || defined(XP_OS2) +#include +#endif + +#if defined(SOLARIS) +#include +#endif + +#ifdef HAVE_SSIZE_T +#include +#endif + +using namespace std; + +namespace js { +namespace ctypes { + +/******************************************************************************* +** Helper classes +*******************************************************************************/ + +class ScopedContextThread +{ +public: + ScopedContextThread(JSContext* cx) : mCx(cx) { JS_SetContextThread(cx); } + ~ScopedContextThread() { JS_ClearContextThread(mCx); } +private: + JSContext* mCx; +}; + +/******************************************************************************* +** JSAPI function prototypes +*******************************************************************************/ + +static JSBool ConstructAbstract(JSContext* cx, uintN argc, jsval* vp); + +namespace CType { + static JSBool ConstructData(JSContext* cx, uintN argc, jsval* vp); + static JSBool ConstructBasic(JSContext* cx, JSObject* obj, uintN argc, jsval* vp); + + static void Trace(JSTracer* trc, JSObject* obj); + static void Finalize(JSContext* cx, JSObject* obj); + static void FinalizeProtoClass(JSContext* cx, JSObject* obj); + + static JSBool PrototypeGetter(JSContext* cx, JSObject* obj, jsid idval, + jsval* vp); + static JSBool NameGetter(JSContext* cx, JSObject* obj, jsid idval, + jsval* vp); + static JSBool SizeGetter(JSContext* cx, JSObject* obj, jsid idval, + jsval* vp); + static JSBool PtrGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); + static JSBool CreateArray(JSContext* cx, uintN argc, jsval* vp); + static JSBool ToString(JSContext* cx, uintN argc, jsval* vp); + static JSBool ToSource(JSContext* cx, uintN argc, jsval* vp); + static JSBool HasInstance(JSContext* cx, JSObject* obj, const jsval* v, JSBool* bp); +} + +namespace PointerType { + static JSBool Create(JSContext* cx, uintN argc, jsval* vp); + static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, jsval* vp); + + static JSBool TargetTypeGetter(JSContext* cx, JSObject* obj, jsid idval, + jsval* vp); + static JSBool ContentsGetter(JSContext* cx, JSObject* obj, jsid idval, + jsval* vp); + static JSBool ContentsSetter(JSContext* cx, JSObject* obj, jsid idval, JSBool strict, + jsval* vp); + static JSBool IsNull(JSContext* cx, uintN argc, jsval* vp); +} + +namespace ArrayType { + static JSBool Create(JSContext* cx, uintN argc, jsval* vp); + static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, jsval* vp); + + static JSBool ElementTypeGetter(JSContext* cx, JSObject* obj, jsid idval, + jsval* vp); + static JSBool LengthGetter(JSContext* cx, JSObject* obj, jsid idval, + jsval* vp); + static JSBool Getter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); + static JSBool Setter(JSContext* cx, JSObject* obj, jsid idval, JSBool strict, jsval* vp); + static JSBool AddressOfElement(JSContext* cx, uintN argc, jsval* vp); +} + +namespace StructType { + static JSBool Create(JSContext* cx, uintN argc, jsval* vp); + static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, jsval* vp); + + static JSBool FieldsArrayGetter(JSContext* cx, JSObject* obj, jsid idval, + jsval* vp); + static JSBool FieldGetter(JSContext* cx, JSObject* obj, jsid idval, + jsval* vp); + static JSBool FieldSetter(JSContext* cx, JSObject* obj, jsid idval, JSBool strict, + jsval* vp); + static JSBool AddressOfField(JSContext* cx, uintN argc, jsval* vp); + static JSBool Define(JSContext* cx, uintN argc, jsval* vp); +} + +namespace FunctionType { + static JSBool Create(JSContext* cx, uintN argc, jsval* vp); + static JSBool ConstructData(JSContext* cx, JSObject* typeObj, + JSObject* dataObj, JSObject* fnObj, JSObject* thisObj); + + static JSBool Call(JSContext* cx, uintN argc, jsval* vp); + + static JSBool ArgTypesGetter(JSContext* cx, JSObject* obj, jsid idval, + jsval* vp); + static JSBool ReturnTypeGetter(JSContext* cx, JSObject* obj, jsid idval, + jsval* vp); + static JSBool ABIGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); + static JSBool IsVariadicGetter(JSContext* cx, JSObject* obj, jsid idval, + jsval* vp); +} + +namespace CClosure { + static void Trace(JSTracer* trc, JSObject* obj); + static void Finalize(JSContext* cx, JSObject* obj); + + // libffi callback + static void ClosureStub(ffi_cif* cif, void* result, void** args, + void* userData); +} + +namespace CData { + static void Finalize(JSContext* cx, JSObject* obj); + + static JSBool ValueGetter(JSContext* cx, JSObject* obj, jsid idval, + jsval* vp); + static JSBool ValueSetter(JSContext* cx, JSObject* obj, jsid idval, + JSBool strict, jsval* vp); + static JSBool Address(JSContext* cx, uintN argc, jsval* vp); + static JSBool ReadString(JSContext* cx, uintN argc, jsval* vp); + static JSBool ToSource(JSContext* cx, uintN argc, jsval* vp); +} + +// Int64Base provides functions common to Int64 and UInt64. +namespace Int64Base { + JSObject* Construct(JSContext* cx, JSObject* proto, JSUint64 data, + bool isUnsigned); + + JSUint64 GetInt(JSContext* cx, JSObject* obj); + + JSBool ToString(JSContext* cx, JSObject* obj, uintN argc, jsval* vp, + bool isUnsigned); + + JSBool ToSource(JSContext* cx, JSObject* obj, uintN argc, jsval* vp, + bool isUnsigned); + + static void Finalize(JSContext* cx, JSObject* obj); +} + +namespace Int64 { + static JSBool Construct(JSContext* cx, uintN argc, jsval* vp); + + static JSBool ToString(JSContext* cx, uintN argc, jsval* vp); + static JSBool ToSource(JSContext* cx, uintN argc, jsval* vp); + + static JSBool Compare(JSContext* cx, uintN argc, jsval* vp); + static JSBool Lo(JSContext* cx, uintN argc, jsval* vp); + static JSBool Hi(JSContext* cx, uintN argc, jsval* vp); + static JSBool Join(JSContext* cx, uintN argc, jsval* vp); +} + +namespace UInt64 { + static JSBool Construct(JSContext* cx, uintN argc, jsval* vp); + + static JSBool ToString(JSContext* cx, uintN argc, jsval* vp); + static JSBool ToSource(JSContext* cx, uintN argc, jsval* vp); + + static JSBool Compare(JSContext* cx, uintN argc, jsval* vp); + static JSBool Lo(JSContext* cx, uintN argc, jsval* vp); + static JSBool Hi(JSContext* cx, uintN argc, jsval* vp); + static JSBool Join(JSContext* cx, uintN argc, jsval* vp); +} + +/******************************************************************************* +** JSClass definitions and initialization functions +*******************************************************************************/ + +// Class representing the 'ctypes' object itself. This exists to contain the +// JSCTypesCallbacks set of function pointers. +static JSClass sCTypesGlobalClass = { + "ctypes", + JSCLASS_HAS_RESERVED_SLOTS(CTYPESGLOBAL_SLOTS), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSClass sCABIClass = { + "CABI", + JSCLASS_HAS_RESERVED_SLOTS(CABI_SLOTS), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +// Class representing ctypes.{C,Pointer,Array,Struct,Function}Type.prototype. +// This exists to give said prototypes a class of "CType", and to provide +// reserved slots for stashing various other prototype objects. +static JSClass sCTypeProtoClass = { + "CType", + JSCLASS_HAS_RESERVED_SLOTS(CTYPEPROTO_SLOTS), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CType::FinalizeProtoClass, + NULL, NULL, ConstructAbstract, ConstructAbstract, NULL, NULL, NULL, NULL +}; + +// Class representing ctypes.CData.prototype and the 'prototype' properties +// of CTypes. This exists to give said prototypes a class of "CData". +static JSClass sCDataProtoClass = { + "CData", + 0, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSClass sCTypeClass = { + "CType", + JSCLASS_HAS_RESERVED_SLOTS(CTYPE_SLOTS) | JSCLASS_MARK_IS_TRACE, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CType::Finalize, + NULL, NULL, CType::ConstructData, CType::ConstructData, NULL, + CType::HasInstance, JS_CLASS_TRACE(CType::Trace), NULL +}; + +static JSClass sCDataClass = { + "CData", + JSCLASS_HAS_RESERVED_SLOTS(CDATA_SLOTS), + JS_PropertyStub, JS_PropertyStub, ArrayType::Getter, ArrayType::Setter, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CData::Finalize, + NULL, NULL, FunctionType::Call, FunctionType::Call, NULL, NULL, NULL, NULL +}; + +static JSClass sCClosureClass = { + "CClosure", + JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS) | JSCLASS_MARK_IS_TRACE, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CClosure::Finalize, + NULL, NULL, NULL, NULL, NULL, NULL, JS_CLASS_TRACE(CClosure::Trace), NULL +}; + +#define CTYPESFN_FLAGS \ + (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) + +#define CTYPESCTOR_FLAGS \ + (CTYPESFN_FLAGS | JSFUN_CONSTRUCTOR) + +#define CTYPESPROP_FLAGS \ + (JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) + +#define CDATAFN_FLAGS \ + (JSPROP_READONLY | JSPROP_PERMANENT) + +static JSPropertySpec sCTypeProps[] = { + { "name", 0, CTYPESPROP_FLAGS, CType::NameGetter, NULL }, + { "size", 0, CTYPESPROP_FLAGS, CType::SizeGetter, NULL }, + { "ptr", 0, CTYPESPROP_FLAGS, CType::PtrGetter, NULL }, + { "prototype", 0, CTYPESPROP_FLAGS, CType::PrototypeGetter, NULL }, + { 0, 0, 0, NULL, NULL } +}; + +static JSFunctionSpec sCTypeFunctions[] = { + JS_FN("array", CType::CreateArray, 0, CTYPESFN_FLAGS), + JS_FN("toString", CType::ToString, 0, CTYPESFN_FLAGS), + JS_FN("toSource", CType::ToSource, 0, CTYPESFN_FLAGS), + JS_FS_END +}; + +static JSPropertySpec sCDataProps[] = { + { "value", 0, JSPROP_SHARED | JSPROP_PERMANENT, + CData::ValueGetter, CData::ValueSetter }, + { 0, 0, 0, NULL, NULL } +}; + +static JSFunctionSpec sCDataFunctions[] = { + JS_FN("address", CData::Address, 0, CDATAFN_FLAGS), + JS_FN("readString", CData::ReadString, 0, CDATAFN_FLAGS), + JS_FN("toSource", CData::ToSource, 0, CDATAFN_FLAGS), + JS_FN("toString", CData::ToSource, 0, CDATAFN_FLAGS), + JS_FS_END +}; + +static JSFunctionSpec sPointerFunction = + JS_FN("PointerType", PointerType::Create, 1, CTYPESCTOR_FLAGS); + +static JSPropertySpec sPointerProps[] = { + { "targetType", 0, CTYPESPROP_FLAGS, PointerType::TargetTypeGetter, NULL }, + { 0, 0, 0, NULL, NULL } +}; + +static JSFunctionSpec sPointerInstanceFunctions[] = { + JS_FN("isNull", PointerType::IsNull, 0, CTYPESFN_FLAGS), + JS_FS_END +}; + +static JSPropertySpec sPointerInstanceProps[] = { + { "contents", 0, JSPROP_SHARED | JSPROP_PERMANENT, + PointerType::ContentsGetter, PointerType::ContentsSetter }, + { 0, 0, 0, NULL, NULL } +}; + +static JSFunctionSpec sArrayFunction = + JS_FN("ArrayType", ArrayType::Create, 1, CTYPESCTOR_FLAGS); + +static JSPropertySpec sArrayProps[] = { + { "elementType", 0, CTYPESPROP_FLAGS, ArrayType::ElementTypeGetter, NULL }, + { "length", 0, CTYPESPROP_FLAGS, ArrayType::LengthGetter, NULL }, + { 0, 0, 0, NULL, NULL } +}; + +static JSFunctionSpec sArrayInstanceFunctions[] = { + JS_FN("addressOfElement", ArrayType::AddressOfElement, 1, CDATAFN_FLAGS), + JS_FS_END +}; + +static JSPropertySpec sArrayInstanceProps[] = { + { "length", 0, JSPROP_SHARED | JSPROP_READONLY | JSPROP_PERMANENT, + ArrayType::LengthGetter, NULL }, + { 0, 0, 0, NULL, NULL } +}; + +static JSFunctionSpec sStructFunction = + JS_FN("StructType", StructType::Create, 2, CTYPESCTOR_FLAGS); + +static JSPropertySpec sStructProps[] = { + { "fields", 0, CTYPESPROP_FLAGS, StructType::FieldsArrayGetter, NULL }, + { 0, 0, 0, NULL, NULL } +}; + +static JSFunctionSpec sStructFunctions[] = { + JS_FN("define", StructType::Define, 1, CDATAFN_FLAGS), + JS_FS_END +}; + +static JSFunctionSpec sStructInstanceFunctions[] = { + JS_FN("addressOfField", StructType::AddressOfField, 1, CDATAFN_FLAGS), + JS_FS_END +}; + +static JSFunctionSpec sFunctionFunction = + JS_FN("FunctionType", FunctionType::Create, 2, CTYPESCTOR_FLAGS); + +static JSPropertySpec sFunctionProps[] = { + { "argTypes", 0, CTYPESPROP_FLAGS, FunctionType::ArgTypesGetter, NULL }, + { "returnType", 0, CTYPESPROP_FLAGS, FunctionType::ReturnTypeGetter, NULL }, + { "abi", 0, CTYPESPROP_FLAGS, FunctionType::ABIGetter, NULL }, + { "isVariadic", 0, CTYPESPROP_FLAGS, FunctionType::IsVariadicGetter, NULL }, + { 0, 0, 0, NULL, NULL } +}; + +static JSClass sInt64ProtoClass = { + "Int64", + 0, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSClass sUInt64ProtoClass = { + "UInt64", + 0, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSClass sInt64Class = { + "Int64", + JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Int64Base::Finalize, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSClass sUInt64Class = { + "UInt64", + JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS), + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Int64Base::Finalize, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSFunctionSpec sInt64StaticFunctions[] = { + JS_FN("compare", Int64::Compare, 2, CTYPESFN_FLAGS), + JS_FN("lo", Int64::Lo, 1, CTYPESFN_FLAGS), + JS_FN("hi", Int64::Hi, 1, CTYPESFN_FLAGS), + JS_FN("join", Int64::Join, 2, CTYPESFN_FLAGS), + JS_FS_END +}; + +static JSFunctionSpec sUInt64StaticFunctions[] = { + JS_FN("compare", UInt64::Compare, 2, CTYPESFN_FLAGS), + JS_FN("lo", UInt64::Lo, 1, CTYPESFN_FLAGS), + JS_FN("hi", UInt64::Hi, 1, CTYPESFN_FLAGS), + JS_FN("join", UInt64::Join, 2, CTYPESFN_FLAGS), + JS_FS_END +}; + +static JSFunctionSpec sInt64Functions[] = { + JS_FN("toString", Int64::ToString, 0, CTYPESFN_FLAGS), + JS_FN("toSource", Int64::ToSource, 0, CTYPESFN_FLAGS), + JS_FS_END +}; + +static JSFunctionSpec sUInt64Functions[] = { + JS_FN("toString", UInt64::ToString, 0, CTYPESFN_FLAGS), + JS_FN("toSource", UInt64::ToSource, 0, CTYPESFN_FLAGS), + JS_FS_END +}; + +static JSFunctionSpec sModuleFunctions[] = { + JS_FN("open", Library::Open, 1, CTYPESFN_FLAGS), + JS_FN("cast", CData::Cast, 2, CTYPESFN_FLAGS), + JS_FN("libraryName", Library::Name, 1, CTYPESFN_FLAGS), + JS_FS_END +}; + +static inline bool FloatIsFinite(jsdouble f) { +#ifdef WIN32 + return _finite(f) != 0; +#else + return finite(f); +#endif +} + +JS_ALWAYS_INLINE JSString* +NewUCString(JSContext* cx, const AutoString& from) +{ + return JS_NewUCStringCopyN(cx, from.begin(), from.length()); +} + +JS_ALWAYS_INLINE size_t +Align(size_t val, size_t align) +{ + return ((val - 1) | (align - 1)) + 1; +} + +static ABICode +GetABICode(JSContext* cx, JSObject* obj) +{ + // make sure we have an object representing a CABI class, + // and extract the enumerated class type from the reserved slot. + if (JS_GET_CLASS(cx, obj) != &sCABIClass) + return INVALID_ABI; + + jsval result; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_ABICODE, &result)); + + return ABICode(JSVAL_TO_INT(result)); +} + +JSErrorFormatString ErrorFormatString[CTYPESERR_LIMIT] = { +#define MSG_DEF(name, number, count, exception, format) \ + { format, count, exception } , +#include "ctypes.msg" +#undef MSG_DEF +}; + +const JSErrorFormatString* +GetErrorMessage(void* userRef, const char* locale, const uintN errorNumber) +{ + if (0 < errorNumber && errorNumber < CTYPESERR_LIMIT) + return &ErrorFormatString[errorNumber]; + return NULL; +} + +JSBool +TypeError(JSContext* cx, const char* expected, jsval actual) +{ + JSString* str = JS_ValueToSource(cx, actual); + JSAutoByteString bytes; + + const char* src; + if (str) { + src = bytes.encode(cx, str); + if (!src) + return false; + } else { + JS_ClearPendingException(cx); + src = "<>"; + } + JS_ReportErrorNumber(cx, GetErrorMessage, NULL, + CTYPESMSG_TYPE_ERROR, expected, src); + return false; +} + +static JSObject* +InitCTypeClass(JSContext* cx, JSObject* parent) +{ + JSFunction* fun = JS_DefineFunction(cx, parent, "CType", ConstructAbstract, 0, + CTYPESCTOR_FLAGS); + if (!fun) + return NULL; + + JSObject* ctor = JS_GetFunctionObject(fun); + JSObject* fnproto = JS_GetPrototype(cx, ctor); + JS_ASSERT(ctor); + JS_ASSERT(fnproto); + + // Set up ctypes.CType.prototype. + JSObject* prototype = JS_NewObject(cx, &sCTypeProtoClass, fnproto, parent); + if (!prototype) + return NULL; + + if (!JS_DefineProperty(cx, ctor, "prototype", OBJECT_TO_JSVAL(prototype), + NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) + return NULL; + + if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(ctor), + NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) + return NULL; + + // Define properties and functions common to all CTypes. + if (!JS_DefineProperties(cx, prototype, sCTypeProps) || + !JS_DefineFunctions(cx, prototype, sCTypeFunctions)) + return NULL; + + if (!JS_FreezeObject(cx, ctor) || !JS_FreezeObject(cx, prototype)) + return NULL; + + return prototype; +} + +static JSObject* +InitCDataClass(JSContext* cx, JSObject* parent, JSObject* CTypeProto) +{ + JSFunction* fun = JS_DefineFunction(cx, parent, "CData", ConstructAbstract, 0, + CTYPESCTOR_FLAGS); + if (!fun) + return NULL; + + JSObject* ctor = JS_GetFunctionObject(fun); + JS_ASSERT(ctor); + + // Set up ctypes.CData.__proto__ === ctypes.CType.prototype. + // (Note that 'ctypes.CData instanceof Function' is still true, thanks to the + // prototype chain.) + if (!JS_SetPrototype(cx, ctor, CTypeProto)) + return NULL; + + // Set up ctypes.CData.prototype. + JSObject* prototype = JS_NewObject(cx, &sCDataProtoClass, NULL, parent); + if (!prototype) + return NULL; + + if (!JS_DefineProperty(cx, ctor, "prototype", OBJECT_TO_JSVAL(prototype), + NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) + return NULL; + + if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(ctor), + NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) + return NULL; + + // Define properties and functions common to all CDatas. + if (!JS_DefineProperties(cx, prototype, sCDataProps) || + !JS_DefineFunctions(cx, prototype, sCDataFunctions)) + return NULL; + + if (//!JS_FreezeObject(cx, prototype) || // XXX fixme - see bug 541212! + !JS_FreezeObject(cx, ctor)) + return NULL; + + return prototype; +} + +static JSBool +DefineABIConstant(JSContext* cx, + JSObject* parent, + const char* name, + ABICode code) +{ + JSObject* obj = JS_DefineObject(cx, parent, name, &sCABIClass, NULL, + JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); + if (!obj) + return false; + if (!JS_SetReservedSlot(cx, obj, SLOT_ABICODE, INT_TO_JSVAL(code))) + return false; + return JS_FreezeObject(cx, obj); +} + +// Set up a single type constructor for +// ctypes.{Pointer,Array,Struct,Function}Type. +static JSBool +InitTypeConstructor(JSContext* cx, + JSObject* parent, + JSObject* CTypeProto, + JSObject* CDataProto, + JSFunctionSpec spec, + JSFunctionSpec* fns, + JSPropertySpec* props, + JSFunctionSpec* instanceFns, + JSPropertySpec* instanceProps, + JSObject*& typeProto, + JSObject*& dataProto) +{ + JSFunction* fun = JS_DefineFunction(cx, parent, spec.name, spec.call, + spec.nargs, spec.flags); + if (!fun) + return false; + + JSObject* obj = JS_GetFunctionObject(fun); + if (!obj) + return false; + + // Set up the .prototype and .prototype.constructor properties. + typeProto = JS_NewObject(cx, &sCTypeProtoClass, CTypeProto, parent); + if (!typeProto) + return false; + + // Define property before proceeding, for GC safety. + if (!JS_DefineProperty(cx, obj, "prototype", OBJECT_TO_JSVAL(typeProto), + NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) + return false; + + if (fns && !JS_DefineFunctions(cx, typeProto, fns)) + return false; + + if (!JS_DefineProperties(cx, typeProto, props)) + return false; + + if (!JS_DefineProperty(cx, typeProto, "constructor", OBJECT_TO_JSVAL(obj), + NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) + return false; + + // Stash ctypes.{Pointer,Array,Struct}Type.prototype on a reserved slot of + // the type constructor, for faster lookup. + if (!JS_SetReservedSlot(cx, obj, SLOT_FN_CTORPROTO, OBJECT_TO_JSVAL(typeProto))) + return false; + + // Create an object to serve as the common ancestor for all CData objects + // created from the given type constructor. This has ctypes.CData.prototype + // as its prototype, such that it inherits the properties and functions + // common to all CDatas. + dataProto = JS_NewObject(cx, &sCDataProtoClass, CDataProto, parent); + if (!dataProto) + return false; + js::AutoObjectRooter protoroot(cx, dataProto); + + // Define functions and properties on the 'dataProto' object that are common + // to all CData objects created from this type constructor. (These will + // become functions and properties on CData objects created from this type.) + if (instanceFns && !JS_DefineFunctions(cx, dataProto, instanceFns)) + return false; + + if (instanceProps && !JS_DefineProperties(cx, dataProto, instanceProps)) + return false; + + if (!JS_FreezeObject(cx, obj) || + //!JS_FreezeObject(cx, dataProto) || // XXX fixme - see bug 541212! + !JS_FreezeObject(cx, typeProto)) + return false; + + return true; +} + +JSObject* +InitInt64Class(JSContext* cx, + JSObject* parent, + JSClass* clasp, + JSNative construct, + JSFunctionSpec* fs, + JSFunctionSpec* static_fs) +{ + // Init type class and constructor + JSObject* prototype = JS_InitClass(cx, parent, NULL, clasp, construct, + 0, NULL, fs, NULL, static_fs); + if (!prototype) + return NULL; + + JSObject* ctor = JS_GetConstructor(cx, prototype); + if (!ctor) + return NULL; + if (!JS_FreezeObject(cx, ctor)) + return NULL; + + // Stash ctypes.{Int64,UInt64}.prototype on a reserved slot of the 'join' + // function. + jsval join; + ASSERT_OK(JS_GetProperty(cx, ctor, "join", &join)); + if (!JS_SetReservedSlot(cx, JSVAL_TO_OBJECT(join), SLOT_FN_INT64PROTO, + OBJECT_TO_JSVAL(prototype))) + return NULL; + + if (!JS_FreezeObject(cx, prototype)) + return NULL; + + return prototype; +} + +static JSBool +AttachProtos(JSContext* cx, JSObject* proto, JSObject** protos) +{ + // For a given 'proto' of [[Class]] "CTypeProto", attach each of the 'protos' + // to the appropriate CTypeProtoSlot. (SLOT_UINT64PROTO is the last slot + // of [[Class]] "CTypeProto".) + for (JSUint32 i = 0; i <= SLOT_UINT64PROTO; ++i) { + if (!JS_SetReservedSlot(cx, proto, i, OBJECT_TO_JSVAL(protos[i]))) + return false; + } + + return true; +} + +JSBool +InitTypeClasses(JSContext* cx, JSObject* parent) +{ + // Initialize the ctypes.CType class. This acts as an abstract base class for + // the various types, and provides the common API functions. It has: + // * [[Class]] "Function" + // * __proto__ === Function.prototype + // * A constructor that throws a TypeError. (You can't construct an + // abstract type!) + // * 'prototype' property: + // * [[Class]] "CTypeProto" + // * __proto__ === Function.prototype + // * A constructor that throws a TypeError. (You can't construct an + // abstract type instance!) + // * 'constructor' property === ctypes.CType + // * Provides properties and functions common to all CTypes. + JSObject* CTypeProto = InitCTypeClass(cx, parent); + if (!CTypeProto) + return false; + + // Initialize the ctypes.CData class. This acts as an abstract base class for + // instances of the various types, and provides the common API functions. + // It has: + // * [[Class]] "Function" + // * __proto__ === Function.prototype + // * A constructor that throws a TypeError. (You can't construct an + // abstract type instance!) + // * 'prototype' property: + // * [[Class]] "CDataProto" + // * 'constructor' property === ctypes.CData + // * Provides properties and functions common to all CDatas. + JSObject* CDataProto = InitCDataClass(cx, parent, CTypeProto); + if (!CDataProto) + return false; + + // Create and attach the special class constructors: ctypes.PointerType, + // ctypes.ArrayType, ctypes.StructType, and ctypes.FunctionType. + // Each of these constructors 'c' has, respectively: + // * [[Class]] "Function" + // * __proto__ === Function.prototype + // * A constructor that creates a user-defined type. + // * 'prototype' property: + // * [[Class]] "CTypeProto" + // * __proto__ === ctypes.CType.prototype + // * 'constructor' property === 'c' + // We also construct an object 'p' to serve, given a type object 't' + // constructed from one of these type constructors, as + // 't.prototype.__proto__'. This object has: + // * [[Class]] "CDataProto" + // * __proto__ === ctypes.CData.prototype + // * Properties and functions common to all CDatas. + // Therefore an instance 't' of ctypes.{Pointer,Array,Struct,Function}Type + // will have, resp.: + // * [[Class]] "CType" + // * __proto__ === ctypes.{Pointer,Array,Struct,Function}Type.prototype + // * A constructor which creates and returns a CData object, containing + // binary data of the given type. + // * 'prototype' property: + // * [[Class]] "CDataProto" + // * __proto__ === 'p', the prototype object from above + // * 'constructor' property === 't' + JSObject* protos[CTYPEPROTO_SLOTS]; + if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto, + sPointerFunction, NULL, sPointerProps, + sPointerInstanceFunctions, sPointerInstanceProps, + protos[SLOT_POINTERPROTO], protos[SLOT_POINTERDATAPROTO])) + return false; + js::AutoObjectRooter proot(cx, protos[SLOT_POINTERDATAPROTO]); + + if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto, + sArrayFunction, NULL, sArrayProps, + sArrayInstanceFunctions, sArrayInstanceProps, + protos[SLOT_ARRAYPROTO], protos[SLOT_ARRAYDATAPROTO])) + return false; + js::AutoObjectRooter aroot(cx, protos[SLOT_ARRAYDATAPROTO]); + + if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto, + sStructFunction, sStructFunctions, sStructProps, + sStructInstanceFunctions, NULL, + protos[SLOT_STRUCTPROTO], protos[SLOT_STRUCTDATAPROTO])) + return false; + js::AutoObjectRooter sroot(cx, protos[SLOT_STRUCTDATAPROTO]); + + if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto, + sFunctionFunction, NULL, sFunctionProps, NULL, NULL, + protos[SLOT_FUNCTIONPROTO], protos[SLOT_FUNCTIONDATAPROTO])) + return false; + js::AutoObjectRooter froot(cx, protos[SLOT_FUNCTIONDATAPROTO]); + + protos[SLOT_CDATAPROTO] = CDataProto; + + // Create and attach the ctypes.{Int64,UInt64} constructors. + // Each of these has, respectively: + // * [[Class]] "Function" + // * __proto__ === Function.prototype + // * A constructor that creates a ctypes.{Int64,UInt64} object, respectively. + // * 'prototype' property: + // * [[Class]] {"Int64Proto","UInt64Proto"} + // * 'constructor' property === ctypes.{Int64,UInt64} + protos[SLOT_INT64PROTO] = InitInt64Class(cx, parent, &sInt64ProtoClass, + Int64::Construct, sInt64Functions, sInt64StaticFunctions); + if (!protos[SLOT_INT64PROTO]) + return false; + protos[SLOT_UINT64PROTO] = InitInt64Class(cx, parent, &sUInt64ProtoClass, + UInt64::Construct, sUInt64Functions, sUInt64StaticFunctions); + if (!protos[SLOT_UINT64PROTO]) + return false; + + // Attach the prototypes just created to each of ctypes.CType.prototype, + // and the special type constructors, so we can access them when constructing + // instances of those types. + if (!AttachProtos(cx, CTypeProto, protos) || + !AttachProtos(cx, protos[SLOT_POINTERPROTO], protos) || + !AttachProtos(cx, protos[SLOT_ARRAYPROTO], protos) || + !AttachProtos(cx, protos[SLOT_STRUCTPROTO], protos) || + !AttachProtos(cx, protos[SLOT_FUNCTIONPROTO], protos)) + return false; + + // Attach objects representing ABI constants. + if (!DefineABIConstant(cx, parent, "default_abi", ABI_DEFAULT) || + !DefineABIConstant(cx, parent, "stdcall_abi", ABI_STDCALL) || + !DefineABIConstant(cx, parent, "winapi_abi", ABI_WINAPI)) + return false; + + // Create objects representing the builtin types, and attach them to the + // ctypes object. Each type object 't' has: + // * [[Class]] "CType" + // * __proto__ === ctypes.CType.prototype + // * A constructor which creates and returns a CData object, containing + // binary data of the given type. + // * 'prototype' property: + // * [[Class]] "CDataProto" + // * __proto__ === ctypes.CData.prototype + // * 'constructor' property === 't' +#define DEFINE_TYPE(name, type, ffiType) \ + JSObject* typeObj_##name = \ + CType::DefineBuiltin(cx, parent, #name, CTypeProto, CDataProto, #name, \ + TYPE_##name, INT_TO_JSVAL(sizeof(type)), \ + INT_TO_JSVAL(ffiType.alignment), &ffiType); \ + if (!typeObj_##name) \ + return false; +#include "typedefs.h" + + // Alias 'ctypes.unsigned' as 'ctypes.unsigned_int', since they represent + // the same type in C. + if (!JS_DefineProperty(cx, parent, "unsigned", + OBJECT_TO_JSVAL(typeObj_unsigned_int), NULL, NULL, + JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) + return false; + + // Create objects representing the special types void_t and voidptr_t. + JSObject* typeObj = + CType::DefineBuiltin(cx, parent, "void_t", CTypeProto, CDataProto, "void", + TYPE_void_t, JSVAL_VOID, JSVAL_VOID, &ffi_type_void); + if (!typeObj) + return false; + + typeObj = PointerType::CreateInternal(cx, typeObj); + if (!typeObj) + return false; + if (!JS_DefineProperty(cx, parent, "voidptr_t", OBJECT_TO_JSVAL(typeObj), + NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) + return false; + + return true; +} + +bool +IsCTypesGlobal(JSContext* cx, JSObject* obj) +{ + return JS_GET_CLASS(cx, obj) == &sCTypesGlobalClass; +} + +// Get the JSCTypesCallbacks struct from the 'ctypes' object 'obj'. +JSCTypesCallbacks* +GetCallbacks(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(IsCTypesGlobal(cx, obj)); + + jsval result; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_CALLBACKS, &result)); + if (JSVAL_IS_VOID(result)) + return NULL; + + return static_cast(JSVAL_TO_PRIVATE(result)); +} + +JS_BEGIN_EXTERN_C + +JS_PUBLIC_API(JSBool) +JS_InitCTypesClass(JSContext* cx, JSObject* global) +{ + // attach ctypes property to global object + JSObject* ctypes = JS_NewObject(cx, &sCTypesGlobalClass, NULL, NULL); + if (!ctypes) + return false; + + if (!JS_DefineProperty(cx, global, "ctypes", OBJECT_TO_JSVAL(ctypes), + JS_PropertyStub, JS_StrictPropertyStub, JSPROP_READONLY | JSPROP_PERMANENT)) { + return false; + } + + if (!InitTypeClasses(cx, ctypes)) + return false; + + // attach API functions + if (!JS_DefineFunctions(cx, ctypes, sModuleFunctions)) + return false; + + // Seal the ctypes object, to prevent modification. + return JS_FreezeObject(cx, ctypes); +} + +JS_PUBLIC_API(JSBool) +JS_SetCTypesCallbacks(JSContext* cx, + JSObject* ctypesObj, + JSCTypesCallbacks* callbacks) +{ + JS_ASSERT(callbacks); + JS_ASSERT(IsCTypesGlobal(cx, ctypesObj)); + + // Set the callbacks on a reserved slot. + return JS_SetReservedSlot(cx, ctypesObj, SLOT_CALLBACKS, + PRIVATE_TO_JSVAL(callbacks)); +} + +JS_END_EXTERN_C + +/******************************************************************************* +** Type conversion functions +*******************************************************************************/ + +// Enforce some sanity checks on type widths and properties. +// Where the architecture is 64-bit, make sure it's LP64 or LLP64. (ctypes.int +// autoconverts to a primitive JS number; to support ILP64 architectures, it +// would need to autoconvert to an Int64 object instead. Therefore we enforce +// this invariant here.) +JS_STATIC_ASSERT(sizeof(bool) == 1 || sizeof(bool) == 4); +JS_STATIC_ASSERT(sizeof(char) == 1); +JS_STATIC_ASSERT(sizeof(short) == 2); +JS_STATIC_ASSERT(sizeof(int) == 4); +JS_STATIC_ASSERT(sizeof(unsigned) == 4); +JS_STATIC_ASSERT(sizeof(long) == 4 || sizeof(long) == 8); +JS_STATIC_ASSERT(sizeof(long long) == 8); +JS_STATIC_ASSERT(sizeof(size_t) == sizeof(uintptr_t)); +JS_STATIC_ASSERT(sizeof(float) == 4); +JS_STATIC_ASSERT(sizeof(PRFuncPtr) == sizeof(void*)); +JS_STATIC_ASSERT(numeric_limits::is_signed); + +// Templated helper to convert FromType to TargetType, for the default case +// where the trivial POD constructor will do. +template +struct ConvertImpl { + static JS_ALWAYS_INLINE TargetType Convert(FromType d) { + return TargetType(d); + } +}; + +#ifdef _MSC_VER +// MSVC can't perform double to unsigned __int64 conversion when the +// double is greater than 2^63 - 1. Help it along a little. +template<> +struct ConvertImpl { + static JS_ALWAYS_INLINE JSUint64 Convert(jsdouble d) { + return d > 0x7fffffffffffffffui64 ? + JSUint64(d - 0x8000000000000000ui64) + 0x8000000000000000ui64 : + JSUint64(d); + } +}; +#endif + +template +static JS_ALWAYS_INLINE TargetType Convert(FromType d) +{ + return ConvertImpl::Convert(d); +} + +template +static JS_ALWAYS_INLINE bool IsAlwaysExact() +{ + // Return 'true' if TargetType can always exactly represent FromType. + // This means that: + // 1) TargetType must be the same or more bits wide as FromType. For integers + // represented in 'n' bits, unsigned variants will have 'n' digits while + // signed will have 'n - 1'. For floating point types, 'digits' is the + // mantissa width. + // 2) If FromType is signed, TargetType must also be signed. (Floating point + // types are always signed.) + // 3) If TargetType is an exact integral type, FromType must be also. + if (numeric_limits::digits < numeric_limits::digits) + return false; + + if (numeric_limits::is_signed && + !numeric_limits::is_signed) + return false; + + if (!numeric_limits::is_exact && + numeric_limits::is_exact) + return false; + + return true; +} + +// Templated helper to determine if FromType 'i' converts losslessly to +// TargetType 'j'. Default case where both types are the same signedness. +template +struct IsExactImpl { + static JS_ALWAYS_INLINE bool Test(FromType i, TargetType j) { + JS_STATIC_ASSERT(numeric_limits::is_exact); + return FromType(j) == i; + } +}; + +// Specialization where TargetType is unsigned, FromType is signed. +template +struct IsExactImpl { + static JS_ALWAYS_INLINE bool Test(FromType i, TargetType j) { + JS_STATIC_ASSERT(numeric_limits::is_exact); + return i >= 0 && FromType(j) == i; + } +}; + +// Specialization where TargetType is signed, FromType is unsigned. +template +struct IsExactImpl { + static JS_ALWAYS_INLINE bool Test(FromType i, TargetType j) { + JS_STATIC_ASSERT(numeric_limits::is_exact); + return TargetType(i) >= 0 && FromType(j) == i; + } +}; + +// Convert FromType 'i' to TargetType 'result', returning true iff 'result' +// is an exact representation of 'i'. +template +static JS_ALWAYS_INLINE bool ConvertExact(FromType i, TargetType* result) +{ + // Require that TargetType is integral, to simplify conversion. + JS_STATIC_ASSERT(numeric_limits::is_exact); + + *result = Convert(i); + + // See if we can avoid a dynamic check. + if (IsAlwaysExact()) + return true; + + // Return 'true' if 'i' is exactly representable in 'TargetType'. + return IsExactImpl::is_signed, + numeric_limits::is_signed>::Test(i, *result); +} + +// Templated helper to determine if Type 'i' is negative. Default case +// where IntegerType is unsigned. +template +struct IsNegativeImpl { + static JS_ALWAYS_INLINE bool Test(Type i) { + return false; + } +}; + +// Specialization where Type is signed. +template +struct IsNegativeImpl { + static JS_ALWAYS_INLINE bool Test(Type i) { + return i < 0; + } +}; + +// Determine whether Type 'i' is negative. +template +static JS_ALWAYS_INLINE bool IsNegative(Type i) +{ + return IsNegativeImpl::is_signed>::Test(i); +} + +// Implicitly convert val to bool, allowing JSBool, jsint, and jsdouble +// arguments numerically equal to 0 or 1. +static bool +jsvalToBool(JSContext* cx, jsval val, bool* result) +{ + if (JSVAL_IS_BOOLEAN(val)) { + *result = JSVAL_TO_BOOLEAN(val) != JS_FALSE; + return true; + } + if (JSVAL_IS_INT(val)) { + jsint i = JSVAL_TO_INT(val); + *result = i != 0; + return i == 0 || i == 1; + } + if (JSVAL_IS_DOUBLE(val)) { + jsdouble d = JSVAL_TO_DOUBLE(val); + *result = d != 0; + // Allow -0. + return d == 1 || d == 0; + } + // Don't silently convert null to bool. It's probably a mistake. + return false; +} + +// Implicitly convert val to IntegerType, allowing JSBool, jsint, jsdouble, +// Int64, UInt64, and CData integer types 't' where all values of 't' are +// representable by IntegerType. +template +static bool +jsvalToInteger(JSContext* cx, jsval val, IntegerType* result) +{ + JS_STATIC_ASSERT(numeric_limits::is_exact); + + if (JSVAL_IS_INT(val)) { + // Make sure the integer fits in the alotted precision, and has the right + // sign. + jsint i = JSVAL_TO_INT(val); + return ConvertExact(i, result); + } + if (JSVAL_IS_DOUBLE(val)) { + // Don't silently lose bits here -- check that val really is an + // integer value, and has the right sign. + jsdouble d = JSVAL_TO_DOUBLE(val); + return ConvertExact(d, result); + } + if (!JSVAL_IS_PRIMITIVE(val)) { + JSObject* obj = JSVAL_TO_OBJECT(val); + if (CData::IsCData(cx, obj)) { + JSObject* typeObj = CData::GetCType(cx, obj); + void* data = CData::GetData(cx, obj); + + // Check whether the source type is always representable, with exact + // precision, by the target type. If it is, convert the value. + switch (CType::GetTypeCode(cx, typeObj)) { +#define DEFINE_INT_TYPE(name, fromType, ffiType) \ + case TYPE_##name: \ + if (!IsAlwaysExact()) \ + return false; \ + *result = IntegerType(*static_cast(data)); \ + return true; +#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#include "typedefs.h" + case TYPE_void_t: + case TYPE_bool: + case TYPE_float: + case TYPE_double: + case TYPE_float32_t: + case TYPE_float64_t: + case TYPE_char: + case TYPE_signed_char: + case TYPE_unsigned_char: + case TYPE_jschar: + case TYPE_pointer: + case TYPE_function: + case TYPE_array: + case TYPE_struct: + // Not a compatible number type. + return false; + } + } + + if (Int64::IsInt64(cx, obj)) { + // Make sure the integer fits in IntegerType. + JSInt64 i = Int64Base::GetInt(cx, obj); + return ConvertExact(i, result); + } + + if (UInt64::IsUInt64(cx, obj)) { + // Make sure the integer fits in IntegerType. + JSUint64 i = Int64Base::GetInt(cx, obj); + return ConvertExact(i, result); + } + + return false; + } + if (JSVAL_IS_BOOLEAN(val)) { + // Implicitly promote boolean values to 0 or 1, like C. + *result = JSVAL_TO_BOOLEAN(val); + JS_ASSERT(*result == 0 || *result == 1); + return true; + } + // Don't silently convert null to an integer. It's probably a mistake. + return false; +} + +// Implicitly convert val to FloatType, allowing jsint, jsdouble, +// Int64, UInt64, and CData numeric types 't' where all values of 't' are +// representable by FloatType. +template +static bool +jsvalToFloat(JSContext *cx, jsval val, FloatType* result) +{ + JS_STATIC_ASSERT(!numeric_limits::is_exact); + + // The following casts may silently throw away some bits, but there's + // no good way around it. Sternly requiring that the 64-bit double + // argument be exactly representable as a 32-bit float is + // unrealistic: it would allow 1/2 to pass but not 1/3. + if (JSVAL_IS_INT(val)) { + *result = FloatType(JSVAL_TO_INT(val)); + return true; + } + if (JSVAL_IS_DOUBLE(val)) { + *result = FloatType(JSVAL_TO_DOUBLE(val)); + return true; + } + if (!JSVAL_IS_PRIMITIVE(val)) { + JSObject* obj = JSVAL_TO_OBJECT(val); + if (CData::IsCData(cx, obj)) { + JSObject* typeObj = CData::GetCType(cx, obj); + void* data = CData::GetData(cx, obj); + + // Check whether the source type is always representable, with exact + // precision, by the target type. If it is, convert the value. + switch (CType::GetTypeCode(cx, typeObj)) { +#define DEFINE_FLOAT_TYPE(name, fromType, ffiType) \ + case TYPE_##name: \ + if (!IsAlwaysExact()) \ + return false; \ + *result = FloatType(*static_cast(data)); \ + return true; +#define DEFINE_INT_TYPE(x, y, z) DEFINE_FLOAT_TYPE(x, y, z) +#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#include "typedefs.h" + case TYPE_void_t: + case TYPE_bool: + case TYPE_char: + case TYPE_signed_char: + case TYPE_unsigned_char: + case TYPE_jschar: + case TYPE_pointer: + case TYPE_function: + case TYPE_array: + case TYPE_struct: + // Not a compatible number type. + return false; + } + } + } + // Don't silently convert true to 1.0 or false to 0.0, even though C/C++ + // does it. It's likely to be a mistake. + return false; +} + +template +static bool +StringToInteger(JSContext* cx, JSString* string, IntegerType* result) +{ + JS_STATIC_ASSERT(numeric_limits::is_exact); + + const jschar* cp = string->getChars(NULL); + if (!cp) + return false; + + const jschar* end = cp + string->length(); + if (cp == end) + return false; + + IntegerType sign = 1; + if (cp[0] == '-') { + if (!numeric_limits::is_signed) + return false; + + sign = -1; + ++cp; + } + + // Assume base-10, unless the string begins with '0x' or '0X'. + IntegerType base = 10; + if (end - cp > 2 && cp[0] == '0' && (cp[1] == 'x' || cp[1] == 'X')) { + cp += 2; + base = 16; + } + + // Scan the string left to right and build the number, + // checking for valid characters 0 - 9, a - f, A - F and overflow. + IntegerType i = 0; + while (cp != end) { + jschar c = *cp++; + if (c >= '0' && c <= '9') + c -= '0'; + else if (base == 16 && c >= 'a' && c <= 'f') + c = c - 'a' + 10; + else if (base == 16 && c >= 'A' && c <= 'F') + c = c - 'A' + 10; + else + return false; + + IntegerType ii = i; + i = ii * base + sign * c; + if (i / base != ii) // overflow + return false; + } + + *result = i; + return true; +} + +// Implicitly convert val to IntegerType, allowing jsint, jsdouble, +// Int64, UInt64, and optionally a decimal or hexadecimal string argument. +// (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.) +template +static bool +jsvalToBigInteger(JSContext* cx, + jsval val, + bool allowString, + IntegerType* result) +{ + JS_STATIC_ASSERT(numeric_limits::is_exact); + + if (JSVAL_IS_INT(val)) { + // Make sure the integer fits in the alotted precision, and has the right + // sign. + jsint i = JSVAL_TO_INT(val); + return ConvertExact(i, result); + } + if (JSVAL_IS_DOUBLE(val)) { + // Don't silently lose bits here -- check that val really is an + // integer value, and has the right sign. + jsdouble d = JSVAL_TO_DOUBLE(val); + return ConvertExact(d, result); + } + if (allowString && JSVAL_IS_STRING(val)) { + // Allow conversion from base-10 or base-16 strings, provided the result + // fits in IntegerType. (This allows an Int64 or UInt64 object to be passed + // to the JS array element operator, which will automatically call + // toString() on the object for us.) + return StringToInteger(cx, JSVAL_TO_STRING(val), result); + } + if (!JSVAL_IS_PRIMITIVE(val)) { + // Allow conversion from an Int64 or UInt64 object directly. + JSObject* obj = JSVAL_TO_OBJECT(val); + + if (UInt64::IsUInt64(cx, obj)) { + // Make sure the integer fits in IntegerType. + JSUint64 i = Int64Base::GetInt(cx, obj); + return ConvertExact(i, result); + } + + if (Int64::IsInt64(cx, obj)) { + // Make sure the integer fits in IntegerType. + JSInt64 i = Int64Base::GetInt(cx, obj); + return ConvertExact(i, result); + } + } + return false; +} + +// Implicitly convert val to a size value, where the size value is represented +// by size_t but must also fit in a jsdouble. +static bool +jsvalToSize(JSContext* cx, jsval val, bool allowString, size_t* result) +{ + if (!jsvalToBigInteger(cx, val, allowString, result)) + return false; + + // Also check that the result fits in a jsdouble. + return Convert(jsdouble(*result)) == *result; +} + +// Implicitly convert val to IntegerType, allowing jsint, jsdouble, +// Int64, UInt64, and optionally a decimal or hexadecimal string argument. +// (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.) +template +static bool +jsidToBigInteger(JSContext* cx, + jsid val, + bool allowString, + IntegerType* result) +{ + JS_STATIC_ASSERT(numeric_limits::is_exact); + + if (JSID_IS_INT(val)) { + // Make sure the integer fits in the alotted precision, and has the right + // sign. + jsint i = JSID_TO_INT(val); + return ConvertExact(i, result); + } + if (allowString && JSID_IS_STRING(val)) { + // Allow conversion from base-10 or base-16 strings, provided the result + // fits in IntegerType. (This allows an Int64 or UInt64 object to be passed + // to the JS array element operator, which will automatically call + // toString() on the object for us.) + return StringToInteger(cx, JSID_TO_STRING(val), result); + } + if (JSID_IS_OBJECT(val)) { + // Allow conversion from an Int64 or UInt64 object directly. + JSObject* obj = JSID_TO_OBJECT(val); + + if (UInt64::IsUInt64(cx, obj)) { + // Make sure the integer fits in IntegerType. + JSUint64 i = Int64Base::GetInt(cx, obj); + return ConvertExact(i, result); + } + + if (Int64::IsInt64(cx, obj)) { + // Make sure the integer fits in IntegerType. + JSInt64 i = Int64Base::GetInt(cx, obj); + return ConvertExact(i, result); + } + } + return false; +} + +// Implicitly convert val to a size value, where the size value is represented +// by size_t but must also fit in a jsdouble. +static bool +jsidToSize(JSContext* cx, jsid val, bool allowString, size_t* result) +{ + if (!jsidToBigInteger(cx, val, allowString, result)) + return false; + + // Also check that the result fits in a jsdouble. + return Convert(jsdouble(*result)) == *result; +} + +// Implicitly convert a size value to a jsval, ensuring that the size_t value +// fits in a jsdouble. +static JSBool +SizeTojsval(JSContext* cx, size_t size, jsval* result) +{ + if (Convert(jsdouble(size)) != size) { + JS_ReportError(cx, "size overflow"); + return false; + } + + return JS_NewNumberValue(cx, jsdouble(size), result); +} + +// Forcefully convert val to IntegerType when explicitly requested. +template +static bool +jsvalToIntegerExplicit(JSContext* cx, jsval val, IntegerType* result) +{ + JS_STATIC_ASSERT(numeric_limits::is_exact); + + if (JSVAL_IS_DOUBLE(val)) { + // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast. + jsdouble d = JSVAL_TO_DOUBLE(val); + *result = FloatIsFinite(d) ? IntegerType(d) : 0; + return true; + } + if (!JSVAL_IS_PRIMITIVE(val)) { + // Convert Int64 and UInt64 values by C-style cast. + JSObject* obj = JSVAL_TO_OBJECT(val); + if (Int64::IsInt64(cx, obj)) { + JSInt64 i = Int64Base::GetInt(cx, obj); + *result = IntegerType(i); + return true; + } + if (UInt64::IsUInt64(cx, obj)) { + JSUint64 i = Int64Base::GetInt(cx, obj); + *result = IntegerType(i); + return true; + } + } + return false; +} + +// Forcefully convert val to a pointer value when explicitly requested. +static bool +jsvalToPtrExplicit(JSContext* cx, jsval val, uintptr_t* result) +{ + if (JSVAL_IS_INT(val)) { + // jsint always fits in intptr_t. If the integer is negative, cast through + // an intptr_t intermediate to sign-extend. + jsint i = JSVAL_TO_INT(val); + *result = i < 0 ? uintptr_t(intptr_t(i)) : uintptr_t(i); + return true; + } + if (JSVAL_IS_DOUBLE(val)) { + jsdouble d = JSVAL_TO_DOUBLE(val); + if (d < 0) { + // Cast through an intptr_t intermediate to sign-extend. + intptr_t i = Convert(d); + if (jsdouble(i) != d) + return false; + + *result = uintptr_t(i); + return true; + } + + // Don't silently lose bits here -- check that val really is an + // integer value, and has the right sign. + *result = Convert(d); + return jsdouble(*result) == d; + } + if (!JSVAL_IS_PRIMITIVE(val)) { + JSObject* obj = JSVAL_TO_OBJECT(val); + if (Int64::IsInt64(cx, obj)) { + JSInt64 i = Int64Base::GetInt(cx, obj); + intptr_t p = intptr_t(i); + + // Make sure the integer fits in the alotted precision. + if (JSInt64(p) != i) + return false; + *result = uintptr_t(p); + return true; + } + + if (UInt64::IsUInt64(cx, obj)) { + JSUint64 i = Int64Base::GetInt(cx, obj); + + // Make sure the integer fits in the alotted precision. + *result = uintptr_t(i); + return JSUint64(*result) == i; + } + } + return false; +} + +template +void +IntegerToString(IntegerType i, jsuint radix, Vector& result) +{ + JS_STATIC_ASSERT(numeric_limits::is_exact); + + // The buffer must be big enough for all the bits of IntegerType to fit, + // in base-2, including '-'. + CharType buffer[sizeof(IntegerType) * 8 + 1]; + CharType* end = buffer + sizeof(buffer) / sizeof(CharType); + CharType* cp = end; + + // Build the string in reverse. We use multiplication and subtraction + // instead of modulus because that's much faster. + const bool isNegative = IsNegative(i); + size_t sign = isNegative ? -1 : 1; + do { + IntegerType ii = i / IntegerType(radix); + size_t index = sign * size_t(i - ii * IntegerType(radix)); + *--cp = "0123456789abcdefghijklmnopqrstuvwxyz"[index]; + i = ii; + } while (i != 0); + + if (isNegative) + *--cp = '-'; + + JS_ASSERT(cp >= buffer); + result.append(cp, end); +} + +template +static size_t +strnlen(const CharType* begin, size_t max) +{ + for (const CharType* s = begin; s != begin + max; ++s) + if (*s == 0) + return s - begin; + + return max; +} + +// Convert C binary value 'data' of CType 'typeObj' to a JS primitive, where +// possible; otherwise, construct and return a CData object. The following +// semantics apply when constructing a CData object for return: +// * If 'wantPrimitive' is true, the caller indicates that 'result' must be +// a JS primitive, and ConvertToJS will fail if 'result' would be a CData +// object. Otherwise: +// * If a CData object 'parentObj' is supplied, the new CData object is +// dependent on the given parent and its buffer refers to a slice of the +// parent's buffer. +// * If 'parentObj' is null, the new CData object may or may not own its +// resulting buffer depending on the 'ownResult' argument. +JSBool +ConvertToJS(JSContext* cx, + JSObject* typeObj, + JSObject* parentObj, + void* data, + bool wantPrimitive, + bool ownResult, + jsval* result) +{ + JS_ASSERT(!parentObj || CData::IsCData(cx, parentObj)); + JS_ASSERT(!parentObj || !ownResult); + JS_ASSERT(!wantPrimitive || !ownResult); + + TypeCode typeCode = CType::GetTypeCode(cx, typeObj); + + switch (typeCode) { + case TYPE_void_t: + *result = JSVAL_VOID; + break; + case TYPE_bool: + *result = *static_cast(data) ? JSVAL_TRUE : JSVAL_FALSE; + break; +#define DEFINE_INT_TYPE(name, type, ffiType) \ + case TYPE_##name: { \ + type value = *static_cast(data); \ + if (sizeof(type) < 4) \ + *result = INT_TO_JSVAL(jsint(value)); \ + else if (!JS_NewNumberValue(cx, jsdouble(value), result)) \ + return false; \ + break; \ + } +#define DEFINE_WRAPPED_INT_TYPE(name, type, ffiType) \ + case TYPE_##name: { \ + /* Return an Int64 or UInt64 object - do not convert to a JS number. */ \ + JSUint64 value; \ + JSObject* proto; \ + if (!numeric_limits::is_signed) { \ + value = *static_cast(data); \ + /* Get ctypes.UInt64.prototype from ctypes.CType.prototype. */ \ + proto = CType::GetProtoFromType(cx, typeObj, SLOT_UINT64PROTO); \ + } else { \ + value = JSInt64(*static_cast(data)); \ + /* Get ctypes.Int64.prototype from ctypes.CType.prototype. */ \ + proto = CType::GetProtoFromType(cx, typeObj, SLOT_INT64PROTO); \ + } \ + \ + JSObject* obj = Int64Base::Construct(cx, proto, value, \ + !numeric_limits::is_signed); \ + if (!obj) \ + return false; \ + *result = OBJECT_TO_JSVAL(obj); \ + break; \ + } +#define DEFINE_FLOAT_TYPE(name, type, ffiType) \ + case TYPE_##name: { \ + type value = *static_cast(data); \ + if (!JS_NewNumberValue(cx, jsdouble(value), result)) \ + return false; \ + break; \ + } +#define DEFINE_CHAR_TYPE(name, type, ffiType) \ + case TYPE_##name: \ + /* Convert to an integer. We have no idea what character encoding to */ \ + /* use, if any. */ \ + *result = INT_TO_JSVAL(*static_cast(data)); \ + break; +#include "typedefs.h" + case TYPE_jschar: { + // Convert the jschar to a 1-character string. + JSString* str = JS_NewUCStringCopyN(cx, static_cast(data), 1); + if (!str) + return false; + + *result = STRING_TO_JSVAL(str); + break; + } + case TYPE_pointer: + case TYPE_array: + case TYPE_struct: { + // We're about to create a new CData object to return. If the caller doesn't + // want this, return early. + if (wantPrimitive) { + JS_ReportError(cx, "cannot convert to primitive value"); + return false; + } + + JSObject* obj = CData::Create(cx, typeObj, parentObj, data, ownResult); + if (!obj) + return false; + + *result = OBJECT_TO_JSVAL(obj); + break; + } + case TYPE_function: + JS_NOT_REACHED("cannot return a FunctionType"); + } + + return true; +} + +// Implicitly convert jsval 'val' to a C binary representation of CType +// 'targetType', storing the result in 'buffer'. Adequate space must be +// provided in 'buffer' by the caller. This function generally does minimal +// coercion between types. There are two cases in which this function is used: +// 1) The target buffer is internal to a CData object; we simply write data +// into it. +// 2) We are converting an argument for an ffi call, in which case 'isArgument' +// will be true. This allows us to handle a special case: if necessary, +// we can autoconvert a JS string primitive to a pointer-to-character type. +// In this case, ownership of the allocated string is handed off to the +// caller; 'freePointer' will be set to indicate this. +JSBool +ImplicitConvert(JSContext* cx, + jsval val, + JSObject* targetType, + void* buffer, + bool isArgument, + bool* freePointer) +{ + JS_ASSERT(CType::IsSizeDefined(cx, targetType)); + + // First, check if val is a CData object of type targetType. + JSObject* sourceData = NULL; + JSObject* sourceType = NULL; + if (!JSVAL_IS_PRIMITIVE(val) && + CData::IsCData(cx, JSVAL_TO_OBJECT(val))) { + sourceData = JSVAL_TO_OBJECT(val); + sourceType = CData::GetCType(cx, sourceData); + + // If the types are equal, copy the buffer contained within the CData. + // (Note that the buffers may overlap partially or completely.) + if (CType::TypesEqual(cx, sourceType, targetType)) { + size_t size = CType::GetSize(cx, sourceType); + memmove(buffer, CData::GetData(cx, sourceData), size); + return true; + } + } + + TypeCode targetCode = CType::GetTypeCode(cx, targetType); + + switch (targetCode) { + case TYPE_bool: { + // Do not implicitly lose bits, but allow the values 0, 1, and -0. + // Programs can convert explicitly, if needed, using `Boolean(v)` or `!!v`. + bool result; + if (!jsvalToBool(cx, val, &result)) + return TypeError(cx, "boolean", val); + *static_cast(buffer) = result; + break; + } +#define DEFINE_INT_TYPE(name, type, ffiType) \ + case TYPE_##name: { \ + /* Do not implicitly lose bits. */ \ + type result; \ + if (!jsvalToInteger(cx, val, &result)) \ + return TypeError(cx, #name, val); \ + *static_cast(buffer) = result; \ + break; \ + } +#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#define DEFINE_FLOAT_TYPE(name, type, ffiType) \ + case TYPE_##name: { \ + type result; \ + if (!jsvalToFloat(cx, val, &result)) \ + return TypeError(cx, #name, val); \ + *static_cast(buffer) = result; \ + break; \ + } +#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#define DEFINE_JSCHAR_TYPE(name, type, ffiType) \ + case TYPE_##name: { \ + /* Convert from a 1-character string, regardless of encoding, */ \ + /* or from an integer, provided the result fits in 'type'. */ \ + type result; \ + if (JSVAL_IS_STRING(val)) { \ + JSString* str = JSVAL_TO_STRING(val); \ + if (str->length() != 1) \ + return TypeError(cx, #name, val); \ + const jschar *chars = str->getChars(cx); \ + if (!chars) \ + return false; \ + result = chars[0]; \ + } else if (!jsvalToInteger(cx, val, &result)) { \ + return TypeError(cx, #name, val); \ + } \ + *static_cast(buffer) = result; \ + break; \ + } +#include "typedefs.h" + case TYPE_pointer: { + if (JSVAL_IS_NULL(val)) { + // Convert to a null pointer. + *static_cast(buffer) = NULL; + break; + } + + JSObject* baseType = PointerType::GetBaseType(cx, targetType); + if (sourceData) { + // First, determine if the targetType is ctypes.void_t.ptr. + TypeCode sourceCode = CType::GetTypeCode(cx, sourceType); + void* sourceBuffer = CData::GetData(cx, sourceData); + bool voidptrTarget = CType::GetTypeCode(cx, baseType) == TYPE_void_t; + + if (sourceCode == TYPE_pointer && voidptrTarget) { + // Autoconvert if targetType is ctypes.voidptr_t. + *static_cast(buffer) = *static_cast(sourceBuffer); + break; + } + if (sourceCode == TYPE_array) { + // Autoconvert an array to a ctypes.void_t.ptr or to + // sourceType.elementType.ptr, just like C. + JSObject* elementType = ArrayType::GetBaseType(cx, sourceType); + if (voidptrTarget || CType::TypesEqual(cx, baseType, elementType)) { + *static_cast(buffer) = sourceBuffer; + break; + } + } + + } else if (isArgument && JSVAL_IS_STRING(val)) { + // Convert the string for the ffi call. This requires allocating space + // which the caller assumes ownership of. + // TODO: Extend this so we can safely convert strings at other times also. + JSString* sourceString = JSVAL_TO_STRING(val); + size_t sourceLength = sourceString->length(); + const jschar* sourceChars = sourceString->getChars(cx); + if (!sourceChars) + return false; + + switch (CType::GetTypeCode(cx, baseType)) { + case TYPE_char: + case TYPE_signed_char: + case TYPE_unsigned_char: { + // Convert from UTF-16 to UTF-8. + size_t nbytes = + js_GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength); + if (nbytes == (size_t) -1) + return false; + + char** charBuffer = static_cast(buffer); + *charBuffer = js_array_new(nbytes + 1); + if (!*charBuffer) { + JS_ReportAllocationOverflow(cx); + return false; + } + + ASSERT_OK(js_DeflateStringToUTF8Buffer(cx, sourceChars, sourceLength, + *charBuffer, &nbytes)); + (*charBuffer)[nbytes] = 0; + *freePointer = true; + break; + } + case TYPE_jschar: { + // Copy the jschar string data. (We could provide direct access to the + // JSString's buffer, but this approach is safer if the caller happens + // to modify the string.) + jschar** jscharBuffer = static_cast(buffer); + *jscharBuffer = js_array_new(sourceLength + 1); + if (!*jscharBuffer) { + JS_ReportAllocationOverflow(cx); + return false; + } + + *freePointer = true; + memcpy(*jscharBuffer, sourceChars, sourceLength * sizeof(jschar)); + (*jscharBuffer)[sourceLength] = 0; + break; + } + default: + return TypeError(cx, "pointer", val); + } + break; + } + return TypeError(cx, "pointer", val); + } + case TYPE_array: { + JSObject* baseType = ArrayType::GetBaseType(cx, targetType); + size_t targetLength = ArrayType::GetLength(cx, targetType); + + if (JSVAL_IS_STRING(val)) { + JSString* sourceString = JSVAL_TO_STRING(val); + size_t sourceLength = sourceString->length(); + const jschar* sourceChars = sourceString->getChars(cx); + if (!sourceChars) + return false; + + switch (CType::GetTypeCode(cx, baseType)) { + case TYPE_char: + case TYPE_signed_char: + case TYPE_unsigned_char: { + // Convert from UTF-16 to UTF-8. + size_t nbytes = + js_GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength); + if (nbytes == (size_t) -1) + return false; + + if (targetLength < nbytes) { + JS_ReportError(cx, "ArrayType has insufficient length"); + return false; + } + + char* charBuffer = static_cast(buffer); + ASSERT_OK(js_DeflateStringToUTF8Buffer(cx, sourceChars, sourceLength, + charBuffer, &nbytes)); + + if (targetLength > nbytes) + charBuffer[nbytes] = 0; + + break; + } + case TYPE_jschar: { + // Copy the string data, jschar for jschar, including the terminator + // if there's space. + if (targetLength < sourceLength) { + JS_ReportError(cx, "ArrayType has insufficient length"); + return false; + } + + memcpy(buffer, sourceChars, sourceLength * sizeof(jschar)); + if (targetLength > sourceLength) + static_cast(buffer)[sourceLength] = 0; + + break; + } + default: + return TypeError(cx, "array", val); + } + + } else if (!JSVAL_IS_PRIMITIVE(val) && + JS_IsArrayObject(cx, JSVAL_TO_OBJECT(val))) { + // Convert each element of the array by calling ImplicitConvert. + JSObject* sourceArray = JSVAL_TO_OBJECT(val); + jsuint sourceLength; + if (!JS_GetArrayLength(cx, sourceArray, &sourceLength) || + targetLength != size_t(sourceLength)) { + JS_ReportError(cx, "ArrayType length does not match source array length"); + return false; + } + + // Convert into an intermediate, in case of failure. + size_t elementSize = CType::GetSize(cx, baseType); + size_t arraySize = elementSize * targetLength; + AutoPtr::Array intermediate(js_array_new(arraySize)); + if (!intermediate) { + JS_ReportAllocationOverflow(cx); + return false; + } + + for (jsuint i = 0; i < sourceLength; ++i) { + js::AutoValueRooter item(cx); + if (!JS_GetElement(cx, sourceArray, i, item.jsval_addr())) + return false; + + char* data = intermediate.get() + elementSize * i; + if (!ImplicitConvert(cx, item.jsval_value(), baseType, data, false, NULL)) + return false; + } + + memcpy(buffer, intermediate.get(), arraySize); + + } else { + // Don't implicitly convert to string. Users can implicitly convert + // with `String(x)` or `""+x`. + return TypeError(cx, "array", val); + } + break; + } + case TYPE_struct: { + if (!JSVAL_IS_PRIMITIVE(val) && !sourceData) { + // Enumerate the properties of the object; if they match the struct + // specification, convert the fields. + JSObject* obj = JSVAL_TO_OBJECT(val); + JSObject* iter = JS_NewPropertyIterator(cx, obj); + if (!iter) + return false; + js::AutoObjectRooter iterroot(cx, iter); + + // Convert into an intermediate, in case of failure. + size_t structSize = CType::GetSize(cx, targetType); + AutoPtr::Array intermediate(js_array_new(structSize)); + if (!intermediate) { + JS_ReportAllocationOverflow(cx); + return false; + } + + jsid id; + size_t i = 0; + while (1) { + if (!JS_NextProperty(cx, iter, &id)) + return false; + if (JSID_IS_VOID(id)) + break; + + if (!JSID_IS_STRING(id)) { + JS_ReportError(cx, "property name is not a string"); + return false; + } + + JSFlatString *name = JSID_TO_FLAT_STRING(id); + const FieldInfo* field = StructType::LookupField(cx, targetType, name); + if (!field) + return false; + + js::AutoValueRooter prop(cx); + if (!JS_GetPropertyById(cx, obj, id, prop.jsval_addr())) + return false; + + // Convert the field via ImplicitConvert(). + char* fieldData = intermediate.get() + field->mOffset; + if (!ImplicitConvert(cx, prop.jsval_value(), field->mType, fieldData, false, NULL)) + return false; + + ++i; + } + + const FieldInfoHash* fields = StructType::GetFieldInfo(cx, targetType); + if (i != fields->count()) { + JS_ReportError(cx, "missing fields"); + return false; + } + + memcpy(buffer, intermediate.get(), structSize); + break; + } + + return TypeError(cx, "struct", val); + } + case TYPE_void_t: + case TYPE_function: + JS_NOT_REACHED("invalid type"); + return false; + } + + return true; +} + +// Convert jsval 'val' to a C binary representation of CType 'targetType', +// storing the result in 'buffer'. This function is more forceful than +// ImplicitConvert. +JSBool +ExplicitConvert(JSContext* cx, jsval val, JSObject* targetType, void* buffer) +{ + // If ImplicitConvert succeeds, use that result. + if (ImplicitConvert(cx, val, targetType, buffer, false, NULL)) + return true; + + // If ImplicitConvert failed, and there is no pending exception, then assume + // hard failure (out of memory, or some other similarly serious condition). + // We store any pending exception in case we need to re-throw it. + js::AutoValueRooter ex(cx); + if (!JS_GetPendingException(cx, ex.jsval_addr())) + return false; + + // Otherwise, assume soft failure. Clear the pending exception so that we + // can throw a different one as required. + JS_ClearPendingException(cx); + + TypeCode type = CType::GetTypeCode(cx, targetType); + + switch (type) { + case TYPE_bool: { + // Convert according to the ECMAScript ToBoolean() function. + JSBool result; + ASSERT_OK(JS_ValueToBoolean(cx, val, &result)); + *static_cast(buffer) = result != JS_FALSE; + break; + } +#define DEFINE_INT_TYPE(name, type, ffiType) \ + case TYPE_##name: { \ + /* Convert numeric values with a C-style cast, and */ \ + /* allow conversion from a base-10 or base-16 string. */ \ + type result; \ + if (!jsvalToIntegerExplicit(cx, val, &result) && \ + (!JSVAL_IS_STRING(val) || \ + !StringToInteger(cx, JSVAL_TO_STRING(val), &result))) \ + return TypeError(cx, #name, val); \ + *static_cast(buffer) = result; \ + break; \ + } +#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_CHAR_TYPE(x, y, z) +#include "typedefs.h" + case TYPE_pointer: { + // Convert a number, Int64 object, or UInt64 object to a pointer. + uintptr_t result; + if (!jsvalToPtrExplicit(cx, val, &result)) + return TypeError(cx, "pointer", val); + *static_cast(buffer) = result; + break; + } + case TYPE_float32_t: + case TYPE_float64_t: + case TYPE_float: + case TYPE_double: + case TYPE_array: + case TYPE_struct: + // ImplicitConvert is sufficient. Re-throw the exception it generated. + JS_SetPendingException(cx, ex.jsval_value()); + return false; + case TYPE_void_t: + case TYPE_function: + JS_NOT_REACHED("invalid type"); + return false; + } + return true; +} + +// Given a CType 'typeObj', generate a string describing the C type declaration +// corresponding to 'typeObj'. For instance, the CType constructed from +// 'ctypes.int32_t.ptr.array(4).ptr.ptr' will result in the type string +// 'int32_t*(**)[4]'. +static JSString* +BuildTypeName(JSContext* cx, JSObject* typeObj) +{ + AutoString result; + + // Walk the hierarchy of types, outermost to innermost, building up the type + // string. This consists of the base type, which goes on the left. + // Derived type modifiers (* and []) build from the inside outward, with + // pointers on the left and arrays on the right. An excellent description + // of the rules for building C type declarations can be found at: + // http://unixwiz.net/techtips/reading-cdecl.html + TypeCode prevGrouping = CType::GetTypeCode(cx, typeObj), currentGrouping; + while (1) { + currentGrouping = CType::GetTypeCode(cx, typeObj); + switch (currentGrouping) { + case TYPE_pointer: { + // Pointer types go on the left. + PrependString(result, "*"); + + typeObj = PointerType::GetBaseType(cx, typeObj); + prevGrouping = currentGrouping; + continue; + } + case TYPE_array: { + if (prevGrouping == TYPE_pointer) { + // Outer type is pointer, inner type is array. Grouping is required. + PrependString(result, "("); + AppendString(result, ")"); + } + + // Array types go on the right. + AppendString(result, "["); + size_t length; + if (ArrayType::GetSafeLength(cx, typeObj, &length)) + IntegerToString(length, 10, result); + + AppendString(result, "]"); + + typeObj = ArrayType::GetBaseType(cx, typeObj); + prevGrouping = currentGrouping; + continue; + } + case TYPE_function: { + FunctionInfo* fninfo = FunctionType::GetFunctionInfo(cx, typeObj); + + // Add in the calling convention, if it's not cdecl. + ABICode abi = GetABICode(cx, fninfo->mABI); + if (abi == ABI_STDCALL) + PrependString(result, "__stdcall "); + else if (abi == ABI_WINAPI) + PrependString(result, "WINAPI "); + + // Wrap the entire expression so far with parens. + PrependString(result, "("); + AppendString(result, ")"); + + // Argument list goes on the right. + AppendString(result, "("); + for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) { + JSString* argName = CType::GetName(cx, fninfo->mArgTypes[i]); + AppendString(result, argName); + if (i != fninfo->mArgTypes.length() - 1 || + fninfo->mIsVariadic) + AppendString(result, ", "); + } + if (fninfo->mIsVariadic) + AppendString(result, "..."); + AppendString(result, ")"); + + // Set 'typeObj' to the return type, and let the loop process it. + // 'prevGrouping' doesn't matter here, because functions cannot return + // arrays -- thus the parenthetical rules don't get tickled. + typeObj = fninfo->mReturnType; + continue; + } + default: + // Either a basic or struct type. Use the type's name as the base type. + break; + } + break; + } + + // Stick the base type and derived type parts together. + JSString* baseName = CType::GetName(cx, typeObj); + PrependString(result, baseName); + return NewUCString(cx, result); +} + +// Given a CType 'typeObj', generate a string 'result' such that 'eval(result)' +// would construct the same CType. If 'makeShort' is true, assume that any +// StructType 't' is bound to an in-scope variable of name 't.name', and use +// that variable in place of generating a string to construct the type 't'. +// (This means the type comparison function CType::TypesEqual will return true +// when comparing the input and output of BuildTypeSource, since struct +// equality is determined by strict JSObject pointer equality.) +static void +BuildTypeSource(JSContext* cx, + JSObject* typeObj, + bool makeShort, + AutoString& result) +{ + // Walk the types, building up the toSource() string. + switch (CType::GetTypeCode(cx, typeObj)) { + case TYPE_void_t: +#define DEFINE_TYPE(name, type, ffiType) \ + case TYPE_##name: +#include "typedefs.h" + { + AppendString(result, "ctypes."); + JSString* nameStr = CType::GetName(cx, typeObj); + AppendString(result, nameStr); + break; + } + case TYPE_pointer: { + JSObject* baseType = PointerType::GetBaseType(cx, typeObj); + + // Specialcase ctypes.voidptr_t. + if (CType::GetTypeCode(cx, baseType) == TYPE_void_t) { + AppendString(result, "ctypes.voidptr_t"); + break; + } + + // Recursively build the source string, and append '.ptr'. + BuildTypeSource(cx, baseType, makeShort, result); + AppendString(result, ".ptr"); + break; + } + case TYPE_function: { + FunctionInfo* fninfo = FunctionType::GetFunctionInfo(cx, typeObj); + + AppendString(result, "ctypes.FunctionType("); + + switch (GetABICode(cx, fninfo->mABI)) { + case ABI_DEFAULT: + AppendString(result, "ctypes.default_abi, "); + break; + case ABI_STDCALL: + AppendString(result, "ctypes.stdcall_abi, "); + break; + case ABI_WINAPI: + AppendString(result, "ctypes.winapi_abi, "); + break; + case INVALID_ABI: + JS_NOT_REACHED("invalid abi"); + break; + } + + // Recursively build the source string describing the function return and + // argument types. + BuildTypeSource(cx, fninfo->mReturnType, true, result); + + if (fninfo->mArgTypes.length() > 0) { + AppendString(result, ", ["); + for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) { + BuildTypeSource(cx, fninfo->mArgTypes[i], true, result); + if (i != fninfo->mArgTypes.length() - 1 || + fninfo->mIsVariadic) + AppendString(result, ", "); + } + if (fninfo->mIsVariadic) + AppendString(result, "\"...\""); + AppendString(result, "]"); + } + + AppendString(result, ")"); + break; + } + case TYPE_array: { + // Recursively build the source string, and append '.array(n)', + // where n is the array length, or the empty string if the array length + // is undefined. + JSObject* baseType = ArrayType::GetBaseType(cx, typeObj); + BuildTypeSource(cx, baseType, makeShort, result); + AppendString(result, ".array("); + + size_t length; + if (ArrayType::GetSafeLength(cx, typeObj, &length)) + IntegerToString(length, 10, result); + + AppendString(result, ")"); + break; + } + case TYPE_struct: { + JSString* name = CType::GetName(cx, typeObj); + + if (makeShort) { + // Shorten the type declaration by assuming that StructType 't' is bound + // to an in-scope variable of name 't.name'. + AppendString(result, name); + break; + } + + // Write the full struct declaration. + AppendString(result, "ctypes.StructType(\""); + AppendString(result, name); + AppendString(result, "\""); + + // If it's an opaque struct, we're done. + if (!CType::IsSizeDefined(cx, typeObj)) { + AppendString(result, ")"); + break; + } + + AppendString(result, ", ["); + + const FieldInfoHash* fields = StructType::GetFieldInfo(cx, typeObj); + size_t length = fields->count(); + Array fieldsArray; + if (!fieldsArray.resize(length)) + break; + + for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) + fieldsArray[r.front().value.mIndex] = &r.front(); + + for (size_t i = 0; i < length; ++i) { + const FieldInfoHash::Entry* entry = fieldsArray[i]; + AppendString(result, "{ \""); + AppendString(result, entry->key); + AppendString(result, "\": "); + BuildTypeSource(cx, entry->value.mType, true, result); + AppendString(result, " }"); + if (i != length - 1) + AppendString(result, ", "); + } + + AppendString(result, "])"); + break; + } + } +} + +// Given a CData object of CType 'typeObj' with binary value 'data', generate a +// string 'result' such that 'eval(result)' would construct a CData object with +// the same CType and containing the same binary value. This assumes that any +// StructType 't' is bound to an in-scope variable of name 't.name'. (This means +// the type comparison function CType::TypesEqual will return true when +// comparing the types, since struct equality is determined by strict JSObject +// pointer equality.) Further, if 'isImplicit' is true, ensure that the +// resulting string can ImplicitConvert successfully if passed to another data +// constructor. (This is important when called recursively, since fields of +// structs and arrays are converted with ImplicitConvert.) +static JSBool +BuildDataSource(JSContext* cx, + JSObject* typeObj, + void* data, + bool isImplicit, + AutoString& result) +{ + TypeCode type = CType::GetTypeCode(cx, typeObj); + switch (type) { + case TYPE_bool: + if (*static_cast(data)) + AppendString(result, "true"); + else + AppendString(result, "false"); + break; +#define DEFINE_INT_TYPE(name, type, ffiType) \ + case TYPE_##name: \ + /* Serialize as a primitive decimal integer. */ \ + IntegerToString(*static_cast(data), 10, result); \ + break; +#define DEFINE_WRAPPED_INT_TYPE(name, type, ffiType) \ + case TYPE_##name: \ + /* Serialize as a wrapped decimal integer. */ \ + if (!numeric_limits::is_signed) \ + AppendString(result, "ctypes.UInt64(\""); \ + else \ + AppendString(result, "ctypes.Int64(\""); \ + \ + IntegerToString(*static_cast(data), 10, result); \ + AppendString(result, "\")"); \ + break; +#define DEFINE_FLOAT_TYPE(name, type, ffiType) \ + case TYPE_##name: { \ + /* Serialize as a primitive double. */ \ + double fp = *static_cast(data); \ + ToCStringBuf cbuf; \ + char* str = NumberToCString(cx, &cbuf, fp); \ + if (!str) { \ + JS_ReportOutOfMemory(cx); \ + return false; \ + } \ + \ + result.append(str, strlen(str)); \ + break; \ + } +#define DEFINE_CHAR_TYPE(name, type, ffiType) \ + case TYPE_##name: \ + /* Serialize as an integer. */ \ + IntegerToString(*static_cast(data), 10, result); \ + break; +#include "typedefs.h" + case TYPE_jschar: { + // Serialize as a 1-character JS string. + JSString* str = JS_NewUCStringCopyN(cx, static_cast(data), 1); + if (!str) + return false; + + // Escape characters, and quote as necessary. + JSString* src = JS_ValueToSource(cx, STRING_TO_JSVAL(str)); + if (!src) + return false; + + AppendString(result, src); + break; + } + case TYPE_pointer: + case TYPE_function: { + if (isImplicit) { + // The result must be able to ImplicitConvert successfully. + // Wrap in a type constructor, then serialize for ExplicitConvert. + BuildTypeSource(cx, typeObj, true, result); + AppendString(result, "("); + } + + // Serialize the pointer value as a wrapped hexadecimal integer. + uintptr_t ptr = *static_cast(data); + AppendString(result, "ctypes.UInt64(\"0x"); + IntegerToString(ptr, 16, result); + AppendString(result, "\")"); + + if (isImplicit) + AppendString(result, ")"); + + break; + } + case TYPE_array: { + // Serialize each element of the array recursively. Each element must + // be able to ImplicitConvert successfully. + JSObject* baseType = ArrayType::GetBaseType(cx, typeObj); + AppendString(result, "["); + + size_t length = ArrayType::GetLength(cx, typeObj); + size_t elementSize = CType::GetSize(cx, baseType); + for (size_t i = 0; i < length; ++i) { + char* element = static_cast(data) + elementSize * i; + if (!BuildDataSource(cx, baseType, element, true, result)) + return false; + + if (i + 1 < length) + AppendString(result, ", "); + } + AppendString(result, "]"); + break; + } + case TYPE_struct: { + if (isImplicit) { + // The result must be able to ImplicitConvert successfully. + // Serialize the data as an object with properties, rather than + // a sequence of arguments to the StructType constructor. + AppendString(result, "{"); + } + + // Serialize each field of the struct recursively. Each field must + // be able to ImplicitConvert successfully. + const FieldInfoHash* fields = StructType::GetFieldInfo(cx, typeObj); + size_t length = fields->count(); + Array fieldsArray; + if (!fieldsArray.resize(length)) + return false; + + for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) + fieldsArray[r.front().value.mIndex] = &r.front(); + + for (size_t i = 0; i < length; ++i) { + const FieldInfoHash::Entry* entry = fieldsArray[i]; + + if (isImplicit) { + AppendString(result, "\""); + AppendString(result, entry->key); + AppendString(result, "\": "); + } + + char* fieldData = static_cast(data) + entry->value.mOffset; + if (!BuildDataSource(cx, entry->value.mType, fieldData, true, result)) + return false; + + if (i + 1 != length) + AppendString(result, ", "); + } + + if (isImplicit) + AppendString(result, "}"); + + break; + } + case TYPE_void_t: + JS_NOT_REACHED("invalid type"); + break; + } + + return true; +} + +/******************************************************************************* +** JSAPI callback function implementations +*******************************************************************************/ + +JSBool +ConstructAbstract(JSContext* cx, + uintN argc, + jsval* vp) +{ + // Calling an abstract base class constructor is disallowed. + JS_ReportError(cx, "cannot construct from abstract type"); + return JS_FALSE; +} + +/******************************************************************************* +** CType implementation +*******************************************************************************/ + +JSBool +CType::ConstructData(JSContext* cx, + uintN argc, + jsval* vp) +{ + // get the callee object... + JSObject* obj = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); + if (!CType::IsCType(cx, obj)) { + JS_ReportError(cx, "not a CType"); + return JS_FALSE; + } + + // How we construct the CData object depends on what type we represent. + // An instance 'd' of a CData object of type 't' has: + // * [[Class]] "CData" + // * __proto__ === t.prototype + switch (GetTypeCode(cx, obj)) { + case TYPE_void_t: + JS_ReportError(cx, "cannot construct from void_t"); + return JS_FALSE; + case TYPE_function: + JS_ReportError(cx, "cannot construct from FunctionType; use FunctionType.ptr instead"); + return JS_FALSE; + case TYPE_pointer: + return PointerType::ConstructData(cx, obj, argc, vp); + case TYPE_array: + return ArrayType::ConstructData(cx, obj, argc, vp); + case TYPE_struct: + return StructType::ConstructData(cx, obj, argc, vp); + default: + return ConstructBasic(cx, obj, argc, vp); + } +} + +JSBool +CType::ConstructBasic(JSContext* cx, + JSObject* obj, + uintN argc, + jsval* vp) +{ + if (argc > 1) { + JS_ReportError(cx, "CType constructor takes zero or one argument"); + return JS_FALSE; + } + + // construct a CData object + JSObject* result = CData::Create(cx, obj, NULL, NULL, true); + if (!result) + return JS_FALSE; + + if (argc == 1) { + if (!ExplicitConvert(cx, JS_ARGV(cx, vp)[0], obj, CData::GetData(cx, result))) + return JS_FALSE; + } + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + return JS_TRUE; +} + +JSObject* +CType::Create(JSContext* cx, + JSObject* typeProto, + JSObject* dataProto, + TypeCode type, + JSString* name, + jsval size, + jsval align, + ffi_type* ffiType) +{ + JSObject* parent = JS_GetParent(cx, typeProto); + JS_ASSERT(parent); + + // Create a CType object with the properties and slots common to all CTypes. + // Each type object 't' has: + // * [[Class]] "CType" + // * __proto__ === 'typeProto'; one of ctypes.{CType,PointerType,ArrayType, + // StructType}.prototype + // * A constructor which creates and returns a CData object, containing + // binary data of the given type. + // * 'prototype' property: + // * [[Class]] "CDataProto" + // * __proto__ === 'dataProto'; an object containing properties and + // functions common to all CData objects of types derived from + // 'typeProto'. (For instance, this could be ctypes.CData.prototype + // for simple types, or something representing structs for StructTypes.) + // * 'constructor' property === 't' + // * Additional properties specified by 'ps', as appropriate for the + // specific type instance 't'. + JSObject* typeObj = JS_NewObject(cx, &sCTypeClass, typeProto, parent); + if (!typeObj) + return NULL; + js::AutoObjectRooter root(cx, typeObj); + + // Set up the reserved slots. + if (!JS_SetReservedSlot(cx, typeObj, SLOT_TYPECODE, INT_TO_JSVAL(type)) || + (ffiType && !JS_SetReservedSlot(cx, typeObj, SLOT_FFITYPE, PRIVATE_TO_JSVAL(ffiType))) || + (name && !JS_SetReservedSlot(cx, typeObj, SLOT_NAME, STRING_TO_JSVAL(name))) || + !JS_SetReservedSlot(cx, typeObj, SLOT_SIZE, size) || + !JS_SetReservedSlot(cx, typeObj, SLOT_ALIGN, align)) + return NULL; + + if (dataProto) { + // Set up the 'prototype' and 'prototype.constructor' properties. + JSObject* prototype = JS_NewObject(cx, &sCDataProtoClass, dataProto, parent); + if (!prototype) + return NULL; + js::AutoObjectRooter protoroot(cx, prototype); + + if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(typeObj), + NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT)) + return NULL; + + // Set the 'prototype' object. + if (//!JS_FreezeObject(cx, prototype) || // XXX fixme - see bug 541212! + !JS_SetReservedSlot(cx, typeObj, SLOT_PROTO, OBJECT_TO_JSVAL(prototype))) + return NULL; + } + + if (!JS_FreezeObject(cx, typeObj)) + return NULL; + + // Assert a sanity check on size and alignment: size % alignment should always + // be zero. + JS_ASSERT_IF(IsSizeDefined(cx, typeObj), + GetSize(cx, typeObj) % GetAlignment(cx, typeObj) == 0); + + return typeObj; +} + +JSObject* +CType::DefineBuiltin(JSContext* cx, + JSObject* parent, + const char* propName, + JSObject* typeProto, + JSObject* dataProto, + const char* name, + TypeCode type, + jsval size, + jsval align, + ffi_type* ffiType) +{ + JSString* nameStr = JS_NewStringCopyZ(cx, name); + if (!nameStr) + return NULL; + js::AutoStringRooter nameRoot(cx, nameStr); + + // Create a new CType object with the common properties and slots. + JSObject* typeObj = Create(cx, typeProto, dataProto, type, nameStr, size, + align, ffiType); + if (!typeObj) + return NULL; + + // Define the CType as a 'propName' property on 'parent'. + if (!JS_DefineProperty(cx, parent, propName, OBJECT_TO_JSVAL(typeObj), + NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) + return NULL; + + return typeObj; +} + +void +CType::Finalize(JSContext* cx, JSObject* obj) +{ + // Make sure our TypeCode slot is legit. If it's not, bail. + jsval slot; + if (!JS_GetReservedSlot(cx, obj, SLOT_TYPECODE, &slot) || JSVAL_IS_VOID(slot)) + return; + + // The contents of our slots depends on what kind of type we are. + switch (TypeCode(JSVAL_TO_INT(slot))) { + case TYPE_function: { + // Free the FunctionInfo. + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FNINFO, &slot)); + if (!JSVAL_IS_VOID(slot)) + js_delete(static_cast(JSVAL_TO_PRIVATE(slot))); + break; + } + + case TYPE_struct: { + // Free the FieldInfoHash table. + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FIELDINFO, &slot)); + if (!JSVAL_IS_VOID(slot)) { + void* info = JSVAL_TO_PRIVATE(slot); + js_delete(static_cast(info)); + } + } + + // Fall through. + case TYPE_array: { + // Free the ffi_type info. + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FFITYPE, &slot)); + if (!JSVAL_IS_VOID(slot)) { + ffi_type* ffiType = static_cast(JSVAL_TO_PRIVATE(slot)); + js_array_delete(ffiType->elements); + js_delete(ffiType); + } + + break; + } + default: + // Nothing to do here. + break; + } +} + +void +CType::FinalizeProtoClass(JSContext* cx, JSObject* obj) +{ + // Finalize the CTypeProto class. The only important bit here is our + // SLOT_CLOSURECX -- it contains the JSContext that was (lazily) instantiated + // for use with FunctionType closures. And if we're here, in this finalizer, + // we're guaranteed to not need it anymore. Note that this slot will only + // be set for the object (of class CTypeProto) ctypes.FunctionType.prototype. + jsval slot; + if (!JS_GetReservedSlot(cx, obj, SLOT_CLOSURECX, &slot) || JSVAL_IS_VOID(slot)) + return; + + JSContext* closureCx = static_cast(JSVAL_TO_PRIVATE(slot)); + JS_SetContextThread(closureCx); + JS_DestroyContextNoGC(closureCx); +} + +void +CType::Trace(JSTracer* trc, JSObject* obj) +{ + JSContext* cx = trc->context; + + // Make sure our TypeCode slot is legit. If it's not, bail. + jsval slot = js::Jsvalify(obj->getSlot(SLOT_TYPECODE)); + if (JSVAL_IS_VOID(slot)) + return; + + // The contents of our slots depends on what kind of type we are. + switch (TypeCode(JSVAL_TO_INT(slot))) { + case TYPE_struct: { + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FIELDINFO, &slot)); + if (JSVAL_IS_VOID(slot)) + return; + + FieldInfoHash* fields = + static_cast(JSVAL_TO_PRIVATE(slot)); + for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) { + JS_CALL_TRACER(trc, r.front().key, JSTRACE_STRING, "fieldName"); + JS_CALL_TRACER(trc, r.front().value.mType, JSTRACE_OBJECT, "fieldType"); + } + + break; + } + case TYPE_function: { + // Check if we have a FunctionInfo. + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FNINFO, &slot)); + if (JSVAL_IS_VOID(slot)) + return; + + FunctionInfo* fninfo = static_cast(JSVAL_TO_PRIVATE(slot)); + JS_ASSERT(fninfo); + + // Identify our objects to the tracer. + JS_CALL_TRACER(trc, fninfo->mABI, JSTRACE_OBJECT, "abi"); + JS_CALL_TRACER(trc, fninfo->mReturnType, JSTRACE_OBJECT, "returnType"); + for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) + JS_CALL_TRACER(trc, fninfo->mArgTypes[i], JSTRACE_OBJECT, "argType"); + + break; + } + default: + // Nothing to do here. + break; + } +} + +bool +CType::IsCType(JSContext* cx, JSObject* obj) +{ + return JS_GET_CLASS(cx, obj) == &sCTypeClass; +} + +TypeCode +CType::GetTypeCode(JSContext* cx, JSObject* typeObj) +{ + JS_ASSERT(IsCType(cx, typeObj)); + + jsval result; + ASSERT_OK(JS_GetReservedSlot(cx, typeObj, SLOT_TYPECODE, &result)); + return TypeCode(JSVAL_TO_INT(result)); +} + +bool +CType::TypesEqual(JSContext* cx, JSObject* t1, JSObject* t2) +{ + JS_ASSERT(IsCType(cx, t1) && IsCType(cx, t2)); + + // Fast path: check for object equality. + if (t1 == t2) + return true; + + // First, perform shallow comparison. + TypeCode c1 = GetTypeCode(cx, t1); + TypeCode c2 = GetTypeCode(cx, t2); + if (c1 != c2) + return false; + + // Determine whether the types require shallow or deep comparison. + switch (c1) { + case TYPE_pointer: { + // Compare base types. + JSObject* b1 = PointerType::GetBaseType(cx, t1); + JSObject* b2 = PointerType::GetBaseType(cx, t2); + return TypesEqual(cx, b1, b2); + } + case TYPE_function: { + FunctionInfo* f1 = FunctionType::GetFunctionInfo(cx, t1); + FunctionInfo* f2 = FunctionType::GetFunctionInfo(cx, t2); + + // Compare abi, return type, and argument types. + if (f1->mABI != f2->mABI) + return false; + + if (!TypesEqual(cx, f1->mReturnType, f2->mReturnType)) + return false; + + if (f1->mArgTypes.length() != f2->mArgTypes.length()) + return false; + + if (f1->mIsVariadic != f2->mIsVariadic) + return false; + + for (size_t i = 0; i < f1->mArgTypes.length(); ++i) { + if (!TypesEqual(cx, f1->mArgTypes[i], f2->mArgTypes[i])) + return false; + } + + return true; + } + case TYPE_array: { + // Compare length, then base types. + // An undefined length array matches other undefined length arrays. + size_t s1 = 0, s2 = 0; + bool d1 = ArrayType::GetSafeLength(cx, t1, &s1); + bool d2 = ArrayType::GetSafeLength(cx, t2, &s2); + if (d1 != d2 || (d1 && s1 != s2)) + return false; + + JSObject* b1 = ArrayType::GetBaseType(cx, t1); + JSObject* b2 = ArrayType::GetBaseType(cx, t2); + return TypesEqual(cx, b1, b2); + } + case TYPE_struct: + // Require exact type object equality. + return false; + default: + // Shallow comparison is sufficient. + return true; + } +} + +bool +CType::GetSafeSize(JSContext* cx, JSObject* obj, size_t* result) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + + jsval size; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_SIZE, &size)); + + // The "size" property can be a jsint, a jsdouble, or JSVAL_VOID + // (for arrays of undefined length), and must always fit in a size_t. + if (JSVAL_IS_INT(size)) { + *result = JSVAL_TO_INT(size); + return true; + } + if (JSVAL_IS_DOUBLE(size)) { + *result = Convert(JSVAL_TO_DOUBLE(size)); + return true; + } + + JS_ASSERT(JSVAL_IS_VOID(size)); + return false; +} + +size_t +CType::GetSize(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + + jsval size; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_SIZE, &size)); + + JS_ASSERT(!JSVAL_IS_VOID(size)); + + // The "size" property can be a jsint, a jsdouble, or JSVAL_VOID + // (for arrays of undefined length), and must always fit in a size_t. + // For callers who know it can never be JSVAL_VOID, return a size_t directly. + if (JSVAL_IS_INT(size)) + return JSVAL_TO_INT(size); + return Convert(JSVAL_TO_DOUBLE(size)); +} + +bool +CType::IsSizeDefined(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + + jsval size; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_SIZE, &size)); + + // The "size" property can be a jsint, a jsdouble, or JSVAL_VOID + // (for arrays of undefined length), and must always fit in a size_t. + JS_ASSERT(JSVAL_IS_INT(size) || JSVAL_IS_DOUBLE(size) || JSVAL_IS_VOID(size)); + return !JSVAL_IS_VOID(size); +} + +size_t +CType::GetAlignment(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + + jsval slot; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_ALIGN, &slot)); + return static_cast(JSVAL_TO_INT(slot)); +} + +ffi_type* +CType::GetFFIType(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + + jsval slot; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FFITYPE, &slot)); + + if (!JSVAL_IS_VOID(slot)) { + return static_cast(JSVAL_TO_PRIVATE(slot)); + } + + AutoPtr result; + switch (CType::GetTypeCode(cx, obj)) { + case TYPE_array: + result = ArrayType::BuildFFIType(cx, obj); + break; + + case TYPE_struct: + result = StructType::BuildFFIType(cx, obj); + break; + + default: + JS_NOT_REACHED("simple types must have an ffi_type"); + } + + if (!result || + !JS_SetReservedSlot(cx, obj, SLOT_FFITYPE, PRIVATE_TO_JSVAL(result.get()))) + return NULL; + + return result.forget(); +} + +JSString* +CType::GetName(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + + jsval string; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_NAME, &string)); + if (JSVAL_IS_VOID(string)) { + // Build the type name lazily. + JSString* name = BuildTypeName(cx, obj); + if (!name || !JS_SetReservedSlot(cx, obj, SLOT_NAME, STRING_TO_JSVAL(name))) + return NULL; + + return name; + } + + return JSVAL_TO_STRING(string); +} + +JSObject* +CType::GetProtoFromCtor(JSContext* cx, JSObject* obj, CTypeProtoSlot slot) +{ + // Get ctypes.{Pointer,Array,Struct}Type.prototype from a reserved slot + // on the type constructor. + jsval protoslot; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FN_CTORPROTO, &protoslot)); + JSObject* proto = JSVAL_TO_OBJECT(protoslot); + JS_ASSERT(proto); + JS_ASSERT(JS_GET_CLASS(cx, proto) == &sCTypeProtoClass); + + // Get the desired prototype. + jsval result; + ASSERT_OK(JS_GetReservedSlot(cx, proto, slot, &result)); + return JSVAL_TO_OBJECT(result); +} + +JSObject* +CType::GetProtoFromType(JSContext* cx, JSObject* obj, CTypeProtoSlot slot) +{ + JS_ASSERT(IsCType(cx, obj)); + + // Get the prototype of the type object. + JSObject* proto = JS_GetPrototype(cx, obj); + JS_ASSERT(proto); + JS_ASSERT(JS_GET_CLASS(cx, proto) == &sCTypeProtoClass); + + // Get the requested ctypes.{Pointer,Array,Struct,Function}Type.prototype. + jsval result; + ASSERT_OK(JS_GetReservedSlot(cx, proto, slot, &result)); + return JSVAL_TO_OBJECT(result); +} + +JSBool +CType::PrototypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) +{ + if (!CType::IsCType(cx, obj)) { + JS_ReportError(cx, "not a CType"); + return JS_FALSE; + } + + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_PROTO, vp)); + JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp) || JSVAL_IS_VOID(*vp)); + return JS_TRUE; +} + +JSBool +CType::NameGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) +{ + if (!CType::IsCType(cx, obj)) { + JS_ReportError(cx, "not a CType"); + return JS_FALSE; + } + + JSString* name = CType::GetName(cx, obj); + if (!name) + return JS_FALSE; + + *vp = STRING_TO_JSVAL(name); + return JS_TRUE; +} + +JSBool +CType::SizeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) +{ + if (!CType::IsCType(cx, obj)) { + JS_ReportError(cx, "not a CType"); + return JS_FALSE; + } + + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_SIZE, vp)); + JS_ASSERT(JSVAL_IS_NUMBER(*vp) || JSVAL_IS_VOID(*vp)); + return JS_TRUE; +} + +JSBool +CType::PtrGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) +{ + if (!CType::IsCType(cx, obj)) { + JS_ReportError(cx, "not a CType"); + return JS_FALSE; + } + + JSObject* pointerType = PointerType::CreateInternal(cx, obj); + if (!pointerType) + return JS_FALSE; + + *vp = OBJECT_TO_JSVAL(pointerType); + return JS_TRUE; +} + +JSBool +CType::CreateArray(JSContext* cx, uintN argc, jsval* vp) +{ + JSObject* baseType = JS_THIS_OBJECT(cx, vp); + if (!baseType || !CType::IsCType(cx, baseType)) { + JS_ReportError(cx, "not a CType"); + return JS_FALSE; + } + + // Construct and return a new ArrayType object. + if (argc > 1) { + JS_ReportError(cx, "array takes zero or one argument"); + return JS_FALSE; + } + + // Convert the length argument to a size_t. + jsval* argv = JS_ARGV(cx, vp); + size_t length = 0; + if (argc == 1 && !jsvalToSize(cx, argv[0], false, &length)) { + JS_ReportError(cx, "argument must be a nonnegative integer"); + return JS_FALSE; + } + + JSObject* result = ArrayType::CreateInternal(cx, baseType, length, argc == 1); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + return JS_TRUE; +} + +JSBool +CType::ToString(JSContext* cx, uintN argc, jsval* vp) +{ + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !CType::IsCType(cx, obj)) { + JS_ReportError(cx, "not a CType"); + return JS_FALSE; + } + + AutoString type; + AppendString(type, "type "); + AppendString(type, GetName(cx, obj)); + + JSString* result = NewUCString(cx, type); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result)); + return JS_TRUE; +} + +JSBool +CType::ToSource(JSContext* cx, uintN argc, jsval* vp) +{ + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !CType::IsCType(cx, obj)) { + JS_ReportError(cx, "not a CType"); + return JS_FALSE; + } + + AutoString source; + BuildTypeSource(cx, obj, false, source); + JSString* result = NewUCString(cx, source); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result)); + return JS_TRUE; +} + +JSBool +CType::HasInstance(JSContext* cx, JSObject* obj, const jsval* v, JSBool* bp) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + + jsval slot; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_PROTO, &slot)); + JSObject* prototype = JSVAL_TO_OBJECT(slot); + JS_ASSERT(prototype); + JS_ASSERT(JS_GET_CLASS(cx, prototype) == &sCDataProtoClass); + + *bp = JS_FALSE; + if (JSVAL_IS_PRIMITIVE(*v)) + return JS_TRUE; + + JSObject* proto = JSVAL_TO_OBJECT(*v); + while ((proto = JS_GetPrototype(cx, proto))) { + if (proto == prototype) { + *bp = JS_TRUE; + break; + } + } + return JS_TRUE; +} + +/******************************************************************************* +** PointerType implementation +*******************************************************************************/ + +JSBool +PointerType::Create(JSContext* cx, uintN argc, jsval* vp) +{ + // Construct and return a new PointerType object. + if (argc != 1) { + JS_ReportError(cx, "PointerType takes one argument"); + return JS_FALSE; + } + + jsval arg = JS_ARGV(cx, vp)[0]; + if (JSVAL_IS_PRIMITIVE(arg) || !CType::IsCType(cx, JSVAL_TO_OBJECT(arg))) { + JS_ReportError(cx, "first argument must be a CType"); + return JS_FALSE; + } + + JSObject* result = CreateInternal(cx, JSVAL_TO_OBJECT(arg)); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + return JS_TRUE; +} + +JSObject* +PointerType::CreateInternal(JSContext* cx, JSObject* baseType) +{ + // check if we have a cached PointerType on our base CType. + jsval slot; + ASSERT_OK(JS_GetReservedSlot(cx, baseType, SLOT_PTR, &slot)); + if (!JSVAL_IS_VOID(slot)) + return JSVAL_TO_OBJECT(slot); + + // Get ctypes.PointerType.prototype and the common prototype for CData objects + // of this type. + JSObject* typeProto; + JSObject* dataProto; + typeProto = CType::GetProtoFromType(cx, baseType, SLOT_POINTERPROTO); + dataProto = CType::GetProtoFromType(cx, baseType, SLOT_POINTERDATAPROTO); + + // Create a new CType object with the common properties and slots. + JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_pointer, + NULL, INT_TO_JSVAL(sizeof(void*)), + INT_TO_JSVAL(ffi_type_pointer.alignment), + &ffi_type_pointer); + if (!typeObj) + return NULL; + js::AutoObjectRooter root(cx, typeObj); + + // Set the target type. (This will be 'null' for an opaque pointer type.) + if (!JS_SetReservedSlot(cx, typeObj, SLOT_TARGET_T, OBJECT_TO_JSVAL(baseType))) + return NULL; + + // Finally, cache our newly-created PointerType on our pointed-to CType. + if (!JS_SetReservedSlot(cx, baseType, SLOT_PTR, OBJECT_TO_JSVAL(typeObj))) + return NULL; + + return typeObj; +} + +JSBool +PointerType::ConstructData(JSContext* cx, + JSObject* obj, + uintN argc, + jsval* vp) +{ + if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_pointer) { + JS_ReportError(cx, "not a PointerType"); + return JS_FALSE; + } + + if (argc > 2) { + JS_ReportError(cx, "constructor takes 0, 1, or 2 arguments"); + return JS_FALSE; + } + + JSObject* result = CData::Create(cx, obj, NULL, NULL, true); + if (!result) + return JS_FALSE; + + // Set return value early, must not observe *vp after + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + + if (argc == 0) { + // Construct a null pointer. + return JS_TRUE; + } + + jsval* argv = JS_ARGV(cx, vp); + if (argc >= 1) { + JSObject* baseObj = PointerType::GetBaseType(cx, obj); + if (CType::GetTypeCode(cx, baseObj) == TYPE_function && + JSVAL_IS_OBJECT(argv[0]) && + JS_ObjectIsCallable(cx, JSVAL_TO_OBJECT(argv[0]))) { + // Construct a FunctionType.ptr from a JS function, and allow an + // optional 'this' argument. + JSObject* thisObj = NULL; + if (argc == 2) { + if (JSVAL_IS_OBJECT(argv[1])) { + thisObj = JSVAL_TO_OBJECT(argv[1]); + } else if (!JS_ValueToObject(cx, argv[1], &thisObj)) { + return JS_FALSE; + } + } + + JSObject* fnObj = JSVAL_TO_OBJECT(argv[0]); + return FunctionType::ConstructData(cx, baseObj, result, fnObj, thisObj); + } + + if (argc == 2) { + JS_ReportError(cx, "first argument must be a function"); + return JS_FALSE; + } + } + + // Construct from a raw pointer value. + return ExplicitConvert(cx, argv[0], obj, CData::GetData(cx, result)); +} + +JSObject* +PointerType::GetBaseType(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_pointer); + + jsval type; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_TARGET_T, &type)); + JS_ASSERT(!JSVAL_IS_NULL(type)); + return JSVAL_TO_OBJECT(type); +} + +JSBool +PointerType::TargetTypeGetter(JSContext* cx, + JSObject* obj, + jsid idval, + jsval* vp) +{ + if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_pointer) { + JS_ReportError(cx, "not a PointerType"); + return JS_FALSE; + } + + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_TARGET_T, vp)); + JS_ASSERT(JSVAL_IS_OBJECT(*vp)); + return JS_TRUE; +} + +JSBool +PointerType::IsNull(JSContext* cx, uintN argc, jsval* vp) +{ + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !CData::IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return JS_FALSE; + } + + // Get pointer type and base type. + JSObject* typeObj = CData::GetCType(cx, obj); + if (CType::GetTypeCode(cx, typeObj) != TYPE_pointer) { + JS_ReportError(cx, "not a PointerType"); + return JS_FALSE; + } + + void* data = *static_cast(CData::GetData(cx, obj)); + jsval result = BOOLEAN_TO_JSVAL(data == NULL); + JS_SET_RVAL(cx, vp, result); + return JS_TRUE; +} + +JSBool +PointerType::ContentsGetter(JSContext* cx, + JSObject* obj, + jsid idval, + jsval* vp) +{ + if (!CData::IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return JS_FALSE; + } + + // Get pointer type and base type. + JSObject* typeObj = CData::GetCType(cx, obj); + if (CType::GetTypeCode(cx, typeObj) != TYPE_pointer) { + JS_ReportError(cx, "not a PointerType"); + return JS_FALSE; + } + + JSObject* baseType = GetBaseType(cx, typeObj); + if (!CType::IsSizeDefined(cx, baseType)) { + JS_ReportError(cx, "cannot get contents of undefined size"); + return JS_FALSE; + } + + void* data = *static_cast(CData::GetData(cx, obj)); + if (data == NULL) { + JS_ReportError(cx, "cannot read contents of null pointer"); + return JS_FALSE; + } + + jsval result; + if (!ConvertToJS(cx, baseType, NULL, data, false, false, &result)) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, result); + return JS_TRUE; +} + +JSBool +PointerType::ContentsSetter(JSContext* cx, + JSObject* obj, + jsid idval, + JSBool strict, + jsval* vp) +{ + if (!CData::IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return JS_FALSE; + } + + // Get pointer type and base type. + JSObject* typeObj = CData::GetCType(cx, obj); + if (CType::GetTypeCode(cx, typeObj) != TYPE_pointer) { + JS_ReportError(cx, "not a PointerType"); + return JS_FALSE; + } + + JSObject* baseType = GetBaseType(cx, typeObj); + if (!CType::IsSizeDefined(cx, baseType)) { + JS_ReportError(cx, "cannot set contents of undefined size"); + return JS_FALSE; + } + + void* data = *static_cast(CData::GetData(cx, obj)); + if (data == NULL) { + JS_ReportError(cx, "cannot write contents to null pointer"); + return JS_FALSE; + } + + return ImplicitConvert(cx, *vp, baseType, data, false, NULL); +} + +/******************************************************************************* +** ArrayType implementation +*******************************************************************************/ + +JSBool +ArrayType::Create(JSContext* cx, uintN argc, jsval* vp) +{ + // Construct and return a new ArrayType object. + if (argc < 1 || argc > 2) { + JS_ReportError(cx, "ArrayType takes one or two arguments"); + return JS_FALSE; + } + + jsval* argv = JS_ARGV(cx, vp); + if (JSVAL_IS_PRIMITIVE(argv[0]) || + !CType::IsCType(cx, JSVAL_TO_OBJECT(argv[0]))) { + JS_ReportError(cx, "first argument must be a CType"); + return JS_FALSE; + } + + // Convert the length argument to a size_t. + size_t length = 0; + if (argc == 2 && !jsvalToSize(cx, argv[1], false, &length)) { + JS_ReportError(cx, "second argument must be a nonnegative integer"); + return JS_FALSE; + } + + JSObject* baseType = JSVAL_TO_OBJECT(argv[0]); + JSObject* result = CreateInternal(cx, baseType, length, argc == 2); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + return JS_TRUE; +} + +JSObject* +ArrayType::CreateInternal(JSContext* cx, + JSObject* baseType, + size_t length, + bool lengthDefined) +{ + // Get ctypes.ArrayType.prototype and the common prototype for CData objects + // of this type, from ctypes.CType.prototype. + JSObject* typeProto = CType::GetProtoFromType(cx, baseType, SLOT_ARRAYPROTO); + JSObject* dataProto = CType::GetProtoFromType(cx, baseType, SLOT_ARRAYDATAPROTO); + + // Determine the size of the array from the base type, if possible. + // The size of the base type must be defined. + // If our length is undefined, both our size and length will be undefined. + size_t baseSize; + if (!CType::GetSafeSize(cx, baseType, &baseSize)) { + JS_ReportError(cx, "base size must be defined"); + return NULL; + } + + jsval sizeVal = JSVAL_VOID; + jsval lengthVal = JSVAL_VOID; + if (lengthDefined) { + // Check for overflow, and convert to a jsint or jsdouble as required. + size_t size = length * baseSize; + if (length > 0 && size / length != baseSize) { + JS_ReportError(cx, "size overflow"); + return NULL; + } + if (!SizeTojsval(cx, size, &sizeVal) || + !SizeTojsval(cx, length, &lengthVal)) + return NULL; + } + + size_t align = CType::GetAlignment(cx, baseType); + + // Create a new CType object with the common properties and slots. + JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_array, NULL, + sizeVal, INT_TO_JSVAL(align), NULL); + if (!typeObj) + return NULL; + js::AutoObjectRooter root(cx, typeObj); + + // Set the element type. + if (!JS_SetReservedSlot(cx, typeObj, SLOT_ELEMENT_T, OBJECT_TO_JSVAL(baseType))) + return NULL; + + // Set the length. + if (!JS_SetReservedSlot(cx, typeObj, SLOT_LENGTH, lengthVal)) + return NULL; + + return typeObj; +} + +JSBool +ArrayType::ConstructData(JSContext* cx, + JSObject* obj, + uintN argc, + jsval* vp) +{ + if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_array) { + JS_ReportError(cx, "not an ArrayType"); + return JS_FALSE; + } + + // Decide whether we have an object to initialize from. We'll override this + // if we get a length argument instead. + bool convertObject = argc == 1; + + // Check if we're an array of undefined length. If we are, allow construction + // with a length argument, or with an actual JS array. + if (CType::IsSizeDefined(cx, obj)) { + if (argc > 1) { + JS_ReportError(cx, "constructor takes zero or one argument"); + return JS_FALSE; + } + + } else { + if (argc != 1) { + JS_ReportError(cx, "constructor takes one argument"); + return JS_FALSE; + } + + JSObject* baseType = GetBaseType(cx, obj); + + jsval* argv = JS_ARGV(cx, vp); + size_t length; + if (jsvalToSize(cx, argv[0], false, &length)) { + // Have a length, rather than an object to initialize from. + convertObject = false; + + } else if (!JSVAL_IS_PRIMITIVE(argv[0])) { + // We were given an object with a .length property. + // This could be a JS array, or a CData array. + JSObject* arg = JSVAL_TO_OBJECT(argv[0]); + js::AutoValueRooter lengthVal(cx); + if (!JS_GetProperty(cx, arg, "length", lengthVal.jsval_addr()) || + !jsvalToSize(cx, lengthVal.jsval_value(), false, &length)) { + JS_ReportError(cx, "argument must be an array object or length"); + return JS_FALSE; + } + + } else if (JSVAL_IS_STRING(argv[0])) { + // We were given a string. Size the array to the appropriate length, + // including space for the terminator. + JSString* sourceString = JSVAL_TO_STRING(argv[0]); + size_t sourceLength = sourceString->length(); + const jschar* sourceChars = sourceString->getChars(cx); + if (!sourceChars) + return false; + + switch (CType::GetTypeCode(cx, baseType)) { + case TYPE_char: + case TYPE_signed_char: + case TYPE_unsigned_char: { + // Determine the UTF-8 length. + length = js_GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength); + if (length == (size_t) -1) + return false; + + ++length; + break; + } + case TYPE_jschar: + length = sourceLength + 1; + break; + default: + return TypeError(cx, "array", argv[0]); + } + + } else { + JS_ReportError(cx, "argument must be an array object or length"); + return JS_FALSE; + } + + // Construct a new ArrayType of defined length, for the new CData object. + obj = CreateInternal(cx, baseType, length, true); + if (!obj) + return JS_FALSE; + } + + // Root the CType object, in case we created one above. + js::AutoObjectRooter root(cx, obj); + + JSObject* result = CData::Create(cx, obj, NULL, NULL, true); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + + if (convertObject) { + if (!ExplicitConvert(cx, JS_ARGV(cx, vp)[0], obj, CData::GetData(cx, result))) + return JS_FALSE; + } + + return JS_TRUE; +} + +JSObject* +ArrayType::GetBaseType(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_array); + + jsval type; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_ELEMENT_T, &type)); + JS_ASSERT(!JSVAL_IS_NULL(type)); + return JSVAL_TO_OBJECT(type); +} + +bool +ArrayType::GetSafeLength(JSContext* cx, JSObject* obj, size_t* result) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_array); + + jsval length; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_LENGTH, &length)); + + // The "length" property can be a jsint, a jsdouble, or JSVAL_VOID + // (for arrays of undefined length), and must always fit in a size_t. + if (JSVAL_IS_INT(length)) { + *result = JSVAL_TO_INT(length); + return true; + } + if (JSVAL_IS_DOUBLE(length)) { + *result = Convert(JSVAL_TO_DOUBLE(length)); + return true; + } + + JS_ASSERT(JSVAL_IS_VOID(length)); + return false; +} + +size_t +ArrayType::GetLength(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_array); + + jsval length; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_LENGTH, &length)); + + JS_ASSERT(!JSVAL_IS_VOID(length)); + + // The "length" property can be a jsint, a jsdouble, or JSVAL_VOID + // (for arrays of undefined length), and must always fit in a size_t. + // For callers who know it can never be JSVAL_VOID, return a size_t directly. + if (JSVAL_IS_INT(length)) + return JSVAL_TO_INT(length); + return Convert(JSVAL_TO_DOUBLE(length)); +} + +ffi_type* +ArrayType::BuildFFIType(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_array); + JS_ASSERT(CType::IsSizeDefined(cx, obj)); + + JSObject* baseType = ArrayType::GetBaseType(cx, obj); + ffi_type* ffiBaseType = CType::GetFFIType(cx, baseType); + if (!ffiBaseType) + return NULL; + + size_t length = ArrayType::GetLength(cx, obj); + + // Create an ffi_type to represent the array. This is necessary for the case + // where the array is part of a struct. Since libffi has no intrinsic + // support for array types, we approximate it by creating a struct type + // with elements of type 'baseType' and with appropriate size and alignment + // values. It would be nice to not do all the work of setting up 'elements', + // but some libffi platforms currently require that it be meaningful. I'm + // looking at you, x86_64. + AutoPtr ffiType(js_new()); + if (!ffiType) { + JS_ReportOutOfMemory(cx); + return NULL; + } + + ffiType->type = FFI_TYPE_STRUCT; + ffiType->size = CType::GetSize(cx, obj); + ffiType->alignment = CType::GetAlignment(cx, obj); + ffiType->elements = js_array_new(length + 1); + if (!ffiType->elements) { + JS_ReportAllocationOverflow(cx); + return NULL; + } + + for (size_t i = 0; i < length; ++i) + ffiType->elements[i] = ffiBaseType; + ffiType->elements[length] = NULL; + + return ffiType.forget(); +} + +JSBool +ArrayType::ElementTypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) +{ + if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_array) { + JS_ReportError(cx, "not an ArrayType"); + return JS_FALSE; + } + + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_ELEMENT_T, vp)); + JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp)); + return JS_TRUE; +} + +JSBool +ArrayType::LengthGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) +{ + // This getter exists for both CTypes and CDatas of the ArrayType persuasion. + // If we're dealing with a CData, get the CType from it. + if (CData::IsCData(cx, obj)) + obj = CData::GetCType(cx, obj); + + if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_array) { + JS_ReportError(cx, "not an ArrayType"); + return JS_FALSE; + } + + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_LENGTH, vp)); + JS_ASSERT(JSVAL_IS_NUMBER(*vp) || JSVAL_IS_VOID(*vp)); + return JS_TRUE; +} + +JSBool +ArrayType::Getter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) +{ + // This should never happen, but we'll check to be safe. + if (!CData::IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return JS_FALSE; + } + + // Bail early if we're not an ArrayType. (This setter is present for all + // CData, regardless of CType.) + JSObject* typeObj = CData::GetCType(cx, obj); + if (CType::GetTypeCode(cx, typeObj) != TYPE_array) + return JS_TRUE; + + // Convert the index to a size_t and bounds-check it. + size_t index; + size_t length = GetLength(cx, typeObj); + bool ok = jsidToSize(cx, idval, true, &index); + if (!ok && JSID_IS_STRING(idval)) { + // String either isn't a number, or doesn't fit in size_t. + // Chances are it's a regular property lookup, so return. + return JS_TRUE; + } + if (!ok || index >= length) { + JS_ReportError(cx, "invalid index"); + return JS_FALSE; + } + + JSObject* baseType = GetBaseType(cx, typeObj); + size_t elementSize = CType::GetSize(cx, baseType); + char* data = static_cast(CData::GetData(cx, obj)) + elementSize * index; + return ConvertToJS(cx, baseType, obj, data, false, false, vp); +} + +JSBool +ArrayType::Setter(JSContext* cx, JSObject* obj, jsid idval, JSBool strict, jsval* vp) +{ + // This should never happen, but we'll check to be safe. + if (!CData::IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return JS_FALSE; + } + + // Bail early if we're not an ArrayType. (This setter is present for all + // CData, regardless of CType.) + JSObject* typeObj = CData::GetCType(cx, obj); + if (CType::GetTypeCode(cx, typeObj) != TYPE_array) + return JS_TRUE; + + // Convert the index to a size_t and bounds-check it. + size_t index; + size_t length = GetLength(cx, typeObj); + bool ok = jsidToSize(cx, idval, true, &index); + if (!ok && JSID_IS_STRING(idval)) { + // String either isn't a number, or doesn't fit in size_t. + // Chances are it's a regular property lookup, so return. + return JS_TRUE; + } + if (!ok || index >= length) { + JS_ReportError(cx, "invalid index"); + return JS_FALSE; + } + + JSObject* baseType = GetBaseType(cx, typeObj); + size_t elementSize = CType::GetSize(cx, baseType); + char* data = static_cast(CData::GetData(cx, obj)) + elementSize * index; + return ImplicitConvert(cx, *vp, baseType, data, false, NULL); +} + +JSBool +ArrayType::AddressOfElement(JSContext* cx, uintN argc, jsval* vp) +{ + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !CData::IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return JS_FALSE; + } + + JSObject* typeObj = CData::GetCType(cx, obj); + if (CType::GetTypeCode(cx, typeObj) != TYPE_array) { + JS_ReportError(cx, "not an ArrayType"); + return JS_FALSE; + } + + if (argc != 1) { + JS_ReportError(cx, "addressOfElement takes one argument"); + return JS_FALSE; + } + + JSObject* baseType = GetBaseType(cx, typeObj); + JSObject* pointerType = PointerType::CreateInternal(cx, baseType); + if (!pointerType) + return JS_FALSE; + js::AutoObjectRooter root(cx, pointerType); + + // Create a PointerType CData object containing null. + JSObject* result = CData::Create(cx, pointerType, NULL, NULL, true); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + + // Convert the index to a size_t and bounds-check it. + size_t index; + size_t length = GetLength(cx, typeObj); + if (!jsvalToSize(cx, JS_ARGV(cx, vp)[0], false, &index) || + index >= length) { + JS_ReportError(cx, "invalid index"); + return JS_FALSE; + } + + // Manually set the pointer inside the object, so we skip the conversion step. + void** data = static_cast(CData::GetData(cx, result)); + size_t elementSize = CType::GetSize(cx, baseType); + *data = static_cast(CData::GetData(cx, obj)) + elementSize * index; + return JS_TRUE; +} + +/******************************************************************************* +** StructType implementation +*******************************************************************************/ + +// For a struct field descriptor 'val' of the form { name : type }, extract +// 'name' and 'type'. +static JSFlatString* +ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj) +{ + if (JSVAL_IS_PRIMITIVE(val)) { + JS_ReportError(cx, "struct field descriptors require a valid name and type"); + return NULL; + } + + JSObject* obj = JSVAL_TO_OBJECT(val); + JSObject* iter = JS_NewPropertyIterator(cx, obj); + if (!iter) + return NULL; + js::AutoObjectRooter iterroot(cx, iter); + + jsid nameid; + if (!JS_NextProperty(cx, iter, &nameid)) + return NULL; + if (JSID_IS_VOID(nameid)) { + JS_ReportError(cx, "struct field descriptors require a valid name and type"); + return NULL; + } + + if (!JSID_IS_STRING(nameid)) { + JS_ReportError(cx, "struct field descriptors require a valid name and type"); + return NULL; + } + + // make sure we have one, and only one, property + jsid id; + if (!JS_NextProperty(cx, iter, &id)) + return NULL; + if (!JSID_IS_VOID(id)) { + JS_ReportError(cx, "struct field descriptors must contain one property"); + return NULL; + } + + js::AutoValueRooter propVal(cx); + if (!JS_GetPropertyById(cx, obj, nameid, propVal.jsval_addr())) + return NULL; + + if (propVal.value().isPrimitive() || + !CType::IsCType(cx, JSVAL_TO_OBJECT(propVal.jsval_value()))) { + JS_ReportError(cx, "struct field descriptors require a valid name and type"); + return NULL; + } + + // Undefined size or zero size struct members are illegal. + // (Zero-size arrays are legal as struct members in C++, but libffi will + // choke on a zero-size struct, so we disallow them.) + *typeObj = JSVAL_TO_OBJECT(propVal.jsval_value()); + size_t size; + if (!CType::GetSafeSize(cx, *typeObj, &size) || size == 0) { + JS_ReportError(cx, "struct field types must have defined and nonzero size"); + return NULL; + } + + return JSID_TO_FLAT_STRING(nameid); +} + +// For a struct field with 'name' and 'type', add an element of the form +// { name : type }. +static JSBool +AddFieldToArray(JSContext* cx, + jsval* element, + JSFlatString* name, + JSObject* typeObj) +{ + JSObject* fieldObj = JS_NewObject(cx, NULL, NULL, NULL); + if (!fieldObj) + return false; + + *element = OBJECT_TO_JSVAL(fieldObj); + + if (!JS_DefineUCProperty(cx, fieldObj, + name->chars(), name->length(), + OBJECT_TO_JSVAL(typeObj), NULL, NULL, + JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) + return false; + + return JS_FreezeObject(cx, fieldObj); +} + +JSBool +StructType::Create(JSContext* cx, uintN argc, jsval* vp) +{ + // Construct and return a new StructType object. + if (argc < 1 || argc > 2) { + JS_ReportError(cx, "StructType takes one or two arguments"); + return JS_FALSE; + } + + jsval* argv = JS_ARGV(cx, vp); + jsval name = argv[0]; + if (!JSVAL_IS_STRING(name)) { + JS_ReportError(cx, "first argument must be a string"); + return JS_FALSE; + } + + // Get ctypes.StructType.prototype from the ctypes.StructType constructor. + JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); + JSObject* typeProto = CType::GetProtoFromCtor(cx, callee, SLOT_STRUCTPROTO); + + // Create a simple StructType with no defined fields. The result will be + // non-instantiable as CData, will have no 'prototype' property, and will + // have undefined size and alignment and no ffi_type. + JSObject* result = CType::Create(cx, typeProto, NULL, TYPE_struct, + JSVAL_TO_STRING(name), JSVAL_VOID, JSVAL_VOID, NULL); + if (!result) + return JS_FALSE; + js::AutoObjectRooter root(cx, result); + + if (argc == 2) { + if (JSVAL_IS_PRIMITIVE(argv[1]) || + !JS_IsArrayObject(cx, JSVAL_TO_OBJECT(argv[1]))) { + JS_ReportError(cx, "second argument must be an array"); + return JS_FALSE; + } + + // Define the struct fields. + if (!DefineInternal(cx, result, JSVAL_TO_OBJECT(argv[1]))) + return JS_FALSE; + } + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + return JS_TRUE; +} + +JSBool +StructType::DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj) +{ + jsuint len; + ASSERT_OK(JS_GetArrayLength(cx, fieldsObj, &len)); + + // Get the common prototype for CData objects of this type from + // ctypes.CType.prototype. + JSObject* dataProto = + CType::GetProtoFromType(cx, typeObj, SLOT_STRUCTDATAPROTO); + + // Set up the 'prototype' and 'prototype.constructor' properties. + // The prototype will reflect the struct fields as properties on CData objects + // created from this type. + JSObject* prototype = JS_NewObject(cx, &sCDataProtoClass, dataProto, NULL); + if (!prototype) + return JS_FALSE; + js::AutoObjectRooter protoroot(cx, prototype); + + if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(typeObj), + NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT)) + return JS_FALSE; + + // Create a FieldInfoHash to stash on the type object, and an array to root + // its constituents. (We cannot simply stash the hash in a reserved slot now + // to get GC safety for free, since if anything in this function fails we + // do not want to mutate 'typeObj'.) + AutoPtr fields(js_new()); + Array fieldRootsArray; + if (!fields || !fields->init(len) || !fieldRootsArray.appendN(JSVAL_VOID, len)) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + js::AutoArrayRooter fieldRoots(cx, fieldRootsArray.length(), + fieldRootsArray.begin()); + + // Process the field types. + size_t structSize, structAlign; + if (len != 0) { + structSize = 0; + structAlign = 0; + + for (jsuint i = 0; i < len; ++i) { + js::AutoValueRooter item(cx); + if (!JS_GetElement(cx, fieldsObj, i, item.jsval_addr())) + return JS_FALSE; + + JSObject* fieldType = NULL; + JSFlatString* name = ExtractStructField(cx, item.jsval_value(), &fieldType); + if (!name) + return JS_FALSE; + fieldRootsArray[i] = OBJECT_TO_JSVAL(fieldType); + + // Make sure each field name is unique, and add it to the hash. + FieldInfoHash::AddPtr entryPtr = fields->lookupForAdd(name); + if (entryPtr) { + JS_ReportError(cx, "struct fields must have unique names"); + return JS_FALSE; + } + ASSERT_OK(fields->add(entryPtr, name, FieldInfo())); + FieldInfo& info = entryPtr->value; + info.mType = fieldType; + info.mIndex = i; + + // Add the field to the StructType's 'prototype' property. + if (!JS_DefineUCProperty(cx, prototype, + name->chars(), name->length(), JSVAL_VOID, + StructType::FieldGetter, StructType::FieldSetter, + JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_PERMANENT)) + return JS_FALSE; + + size_t fieldSize = CType::GetSize(cx, fieldType); + size_t fieldAlign = CType::GetAlignment(cx, fieldType); + size_t fieldOffset = Align(structSize, fieldAlign); + // Check for overflow. Since we hold invariant that fieldSize % fieldAlign + // be zero, we can safely check fieldOffset + fieldSize without first + // checking fieldOffset for overflow. + if (fieldOffset + fieldSize < structSize) { + JS_ReportError(cx, "size overflow"); + return JS_FALSE; + } + info.mOffset = fieldOffset; + structSize = fieldOffset + fieldSize; + + if (fieldAlign > structAlign) + structAlign = fieldAlign; + } + + // Pad the struct tail according to struct alignment. + size_t structTail = Align(structSize, structAlign); + if (structTail < structSize) { + JS_ReportError(cx, "size overflow"); + return JS_FALSE; + } + structSize = structTail; + + } else { + // Empty structs are illegal in C, but are legal and have a size of + // 1 byte in C++. We're going to allow them, and trick libffi into + // believing this by adding a char member. The resulting struct will have + // no getters or setters, and will be initialized to zero. + structSize = 1; + structAlign = 1; + } + + jsval sizeVal; + if (!SizeTojsval(cx, structSize, &sizeVal)) + return JS_FALSE; + + if (!JS_SetReservedSlot(cx, typeObj, SLOT_FIELDINFO, + PRIVATE_TO_JSVAL(fields.get()))) + return JS_FALSE; + fields.forget(); + + if (!JS_SetReservedSlot(cx, typeObj, SLOT_SIZE, sizeVal) || + !JS_SetReservedSlot(cx, typeObj, SLOT_ALIGN, INT_TO_JSVAL(structAlign)) || + //!JS_FreezeObject(cx, prototype) || // XXX fixme - see bug 541212! + !JS_SetReservedSlot(cx, typeObj, SLOT_PROTO, OBJECT_TO_JSVAL(prototype))) + return JS_FALSE; + + return JS_TRUE; +} + +ffi_type* +StructType::BuildFFIType(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_struct); + JS_ASSERT(CType::IsSizeDefined(cx, obj)); + + const FieldInfoHash* fields = GetFieldInfo(cx, obj); + size_t len = fields->count(); + + size_t structSize = CType::GetSize(cx, obj); + size_t structAlign = CType::GetAlignment(cx, obj); + + AutoPtr ffiType(js_new()); + if (!ffiType) { + JS_ReportOutOfMemory(cx); + return NULL; + } + ffiType->type = FFI_TYPE_STRUCT; + + AutoPtr::Array elements; + if (len != 0) { + elements = js_array_new(len + 1); + if (!elements) { + JS_ReportOutOfMemory(cx); + return NULL; + } + elements[len] = NULL; + + for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) { + const FieldInfoHash::Entry& entry = r.front(); + ffi_type* fieldType = CType::GetFFIType(cx, entry.value.mType); + if (!fieldType) + return NULL; + elements[entry.value.mIndex] = fieldType; + } + + } else { + // Represent an empty struct as having a size of 1 byte, just like C++. + JS_ASSERT(structSize == 1); + JS_ASSERT(structAlign == 1); + elements = js_array_new(2); + if (!elements) { + JS_ReportOutOfMemory(cx); + return NULL; + } + elements[0] = &ffi_type_uint8; + elements[1] = NULL; + } + + ffiType->elements = elements.get(); + +#ifdef DEBUG + // Perform a sanity check: the result of our struct size and alignment + // calculations should match libffi's. We force it to do this calculation + // by calling ffi_prep_cif. + ffi_cif cif; + ffiType->size = 0; + ffiType->alignment = 0; + ffi_status status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, ffiType.get(), NULL); + JS_ASSERT(status == FFI_OK); + JS_ASSERT(structSize == ffiType->size); + JS_ASSERT(structAlign == ffiType->alignment); +#else + // Fill in the ffi_type's size and align fields. This makes libffi treat the + // type as initialized; it will not recompute the values. (We assume + // everything agrees; if it doesn't, we really want to know about it, which + // is the purpose of the above debug-only check.) + ffiType->size = structSize; + ffiType->alignment = structAlign; +#endif + + elements.forget(); + return ffiType.forget(); +} + +JSBool +StructType::Define(JSContext* cx, uintN argc, jsval* vp) +{ + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || + !CType::IsCType(cx, obj) || + CType::GetTypeCode(cx, obj) != TYPE_struct) { + JS_ReportError(cx, "not a StructType"); + return JS_FALSE; + } + + if (CType::IsSizeDefined(cx, obj)) { + JS_ReportError(cx, "StructType has already been defined"); + return JS_FALSE; + } + + if (argc != 1) { + JS_ReportError(cx, "define takes one argument"); + return JS_FALSE; + } + + jsval arg = JS_ARGV(cx, vp)[0]; + if (JSVAL_IS_PRIMITIVE(arg) || + !JS_IsArrayObject(cx, JSVAL_TO_OBJECT(arg))) { + JS_ReportError(cx, "argument must be an array"); + return JS_FALSE; + } + + return DefineInternal(cx, obj, JSVAL_TO_OBJECT(arg)); +} + +JSBool +StructType::ConstructData(JSContext* cx, + JSObject* obj, + uintN argc, + jsval* vp) +{ + if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_struct) { + JS_ReportError(cx, "not a StructType"); + return JS_FALSE; + } + + if (!CType::IsSizeDefined(cx, obj)) { + JS_ReportError(cx, "cannot construct an opaque StructType"); + return JS_FALSE; + } + + JSObject* result = CData::Create(cx, obj, NULL, NULL, true); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + + if (argc == 0) + return JS_TRUE; + + char* buffer = static_cast(CData::GetData(cx, result)); + const FieldInfoHash* fields = GetFieldInfo(cx, obj); + + jsval* argv = JS_ARGV(cx, vp); + if (argc == 1) { + // There are two possible interpretations of the argument: + // 1) It may be an object '{ ... }' with properties representing the + // struct fields intended to ExplicitConvert wholesale to our StructType. + // 2) If the struct contains one field, the arg may be intended to + // ImplicitConvert directly to that arg's CType. + // Thankfully, the conditions for these two possibilities to succeed + // are mutually exclusive, so we can pick the right one. + + // Try option 1) first. + if (ExplicitConvert(cx, argv[0], obj, buffer)) + return JS_TRUE; + + if (fields->count() != 1) + return JS_FALSE; + + // If ExplicitConvert failed, and there is no pending exception, then assume + // hard failure (out of memory, or some other similarly serious condition). + if (!JS_IsExceptionPending(cx)) + return JS_FALSE; + + // Otherwise, assume soft failure, and clear the pending exception so that we + // can throw a different one as required. + JS_ClearPendingException(cx); + + // Fall through to try option 2). + } + + // We have a type constructor of the form 'ctypes.StructType(a, b, c, ...)'. + // ImplicitConvert each field. + if (argc == fields->count()) { + for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) { + const FieldInfo& field = r.front().value; + STATIC_ASSUME(field.mIndex < fields->count()); /* Quantified invariant */ + if (!ImplicitConvert(cx, argv[field.mIndex], field.mType, + buffer + field.mOffset, + false, NULL)) + return JS_FALSE; + } + + return JS_TRUE; + } + + JS_ReportError(cx, "constructor takes 0, 1, or %u arguments", + fields->count()); + return JS_FALSE; +} + +const FieldInfoHash* +StructType::GetFieldInfo(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_struct); + + jsval slot; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FIELDINFO, &slot)); + JS_ASSERT(!JSVAL_IS_VOID(slot) && JSVAL_TO_PRIVATE(slot)); + + return static_cast(JSVAL_TO_PRIVATE(slot)); +} + +const FieldInfo* +StructType::LookupField(JSContext* cx, JSObject* obj, JSFlatString *name) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_struct); + + FieldInfoHash::Ptr ptr = GetFieldInfo(cx, obj)->lookup(name); + if (ptr) + return &ptr->value; + + JSAutoByteString bytes(cx, name); + if (!bytes) + return NULL; + + JS_ReportError(cx, "%s does not name a field", bytes.ptr()); + return NULL; +} + +JSObject* +StructType::BuildFieldsArray(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_struct); + JS_ASSERT(CType::IsSizeDefined(cx, obj)); + + const FieldInfoHash* fields = GetFieldInfo(cx, obj); + size_t len = fields->count(); + + // Prepare a new array for the 'fields' property of the StructType. + Array fieldsVec; + if (!fieldsVec.appendN(JSVAL_VOID, len)) + return NULL; + js::AutoArrayRooter root(cx, fieldsVec.length(), fieldsVec.begin()); + + for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) { + const FieldInfoHash::Entry& entry = r.front(); + // Add the field descriptor to the array. + if (!AddFieldToArray(cx, &fieldsVec[entry.value.mIndex], + entry.key, entry.value.mType)) + return NULL; + } + + JSObject* fieldsProp = JS_NewArrayObject(cx, len, fieldsVec.begin()); + if (!fieldsProp) + return NULL; + + // Seal the fields array. + if (!JS_FreezeObject(cx, fieldsProp)) + return NULL; + + return fieldsProp; +} + +JSBool +StructType::FieldsArrayGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) +{ + if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_struct) { + JS_ReportError(cx, "not a StructType"); + return JS_FALSE; + } + + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FIELDS, vp)); + + if (!CType::IsSizeDefined(cx, obj)) { + JS_ASSERT(JSVAL_IS_VOID(*vp)); + return JS_TRUE; + } + + if (JSVAL_IS_VOID(*vp)) { + // Build the 'fields' array lazily. + JSObject* fields = BuildFieldsArray(cx, obj); + if (!fields || + !JS_SetReservedSlot(cx, obj, SLOT_FIELDS, OBJECT_TO_JSVAL(fields))) + return JS_FALSE; + + *vp = OBJECT_TO_JSVAL(fields); + } + + JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp) && + JS_IsArrayObject(cx, JSVAL_TO_OBJECT(*vp))); + return JS_TRUE; +} + +JSBool +StructType::FieldGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) +{ + if (!CData::IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return JS_FALSE; + } + + JSObject* typeObj = CData::GetCType(cx, obj); + if (CType::GetTypeCode(cx, typeObj) != TYPE_struct) { + JS_ReportError(cx, "not a StructType"); + return JS_FALSE; + } + + const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval)); + if (!field) + return JS_FALSE; + + char* data = static_cast(CData::GetData(cx, obj)) + field->mOffset; + return ConvertToJS(cx, field->mType, obj, data, false, false, vp); +} + +JSBool +StructType::FieldSetter(JSContext* cx, JSObject* obj, jsid idval, JSBool strict, jsval* vp) +{ + if (!CData::IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return JS_FALSE; + } + + JSObject* typeObj = CData::GetCType(cx, obj); + if (CType::GetTypeCode(cx, typeObj) != TYPE_struct) { + JS_ReportError(cx, "not a StructType"); + return JS_FALSE; + } + + const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval)); + if (!field) + return JS_FALSE; + + char* data = static_cast(CData::GetData(cx, obj)) + field->mOffset; + return ImplicitConvert(cx, *vp, field->mType, data, false, NULL); +} + +JSBool +StructType::AddressOfField(JSContext* cx, uintN argc, jsval* vp) +{ + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !CData::IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return JS_FALSE; + } + + JSObject* typeObj = CData::GetCType(cx, obj); + if (CType::GetTypeCode(cx, typeObj) != TYPE_struct) { + JS_ReportError(cx, "not a StructType"); + return JS_FALSE; + } + + if (argc != 1) { + JS_ReportError(cx, "addressOfField takes one argument"); + return JS_FALSE; + } + + JSFlatString *str = JS_FlattenString(cx, JSVAL_TO_STRING(JS_ARGV(cx, vp)[0])); + if (!str) + return JS_FALSE; + + const FieldInfo* field = LookupField(cx, typeObj, str); + if (!field) + return JS_FALSE; + + JSObject* baseType = field->mType; + JSObject* pointerType = PointerType::CreateInternal(cx, baseType); + if (!pointerType) + return JS_FALSE; + js::AutoObjectRooter root(cx, pointerType); + + // Create a PointerType CData object containing null. + JSObject* result = CData::Create(cx, pointerType, NULL, NULL, true); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + + // Manually set the pointer inside the object, so we skip the conversion step. + void** data = static_cast(CData::GetData(cx, result)); + *data = static_cast(CData::GetData(cx, obj)) + field->mOffset; + return JS_TRUE; +} + +/******************************************************************************* +** FunctionType implementation +*******************************************************************************/ + +// Helper class for handling allocation of function arguments. +struct AutoValue +{ + AutoValue() : mData(NULL) { } + + ~AutoValue() + { + js_array_delete(static_cast(mData)); + } + + bool SizeToType(JSContext* cx, JSObject* type) + { + // Allocate a minimum of sizeof(ffi_arg) to handle small integers. + size_t size = Align(CType::GetSize(cx, type), sizeof(ffi_arg)); + mData = js_array_new(size); + if (mData) + memset(mData, 0, size); + return mData != NULL; + } + + void* mData; +}; + +static bool +GetABI(JSContext* cx, jsval abiType, ffi_abi* result) +{ + if (JSVAL_IS_PRIMITIVE(abiType)) + return false; + + ABICode abi = GetABICode(cx, JSVAL_TO_OBJECT(abiType)); + + // determine the ABI from the subset of those available on the + // given platform. ABI_DEFAULT specifies the default + // C calling convention (cdecl) on each platform. + switch (abi) { + case ABI_DEFAULT: + *result = FFI_DEFAULT_ABI; + return true; + case ABI_STDCALL: + case ABI_WINAPI: +#if (defined(_WIN32) && !defined(_WIN64)) || defined(_OS2) + *result = FFI_STDCALL; + return true; +#endif + case INVALID_ABI: + break; + } + return false; +} + +static JSObject* +PrepareType(JSContext* cx, jsval type) +{ + if (JSVAL_IS_PRIMITIVE(type) || + !CType::IsCType(cx, JSVAL_TO_OBJECT(type))) { + JS_ReportError(cx, "not a ctypes type"); + return NULL; + } + + JSObject* result = JSVAL_TO_OBJECT(type); + TypeCode typeCode = CType::GetTypeCode(cx, result); + + if (typeCode == TYPE_array) { + // convert array argument types to pointers, just like C. + // ImplicitConvert will do the same, when passing an array as data. + JSObject* baseType = ArrayType::GetBaseType(cx, result); + result = PointerType::CreateInternal(cx, baseType); + if (!result) + return NULL; + + } else if (typeCode == TYPE_void_t || typeCode == TYPE_function) { + // disallow void or function argument types + JS_ReportError(cx, "Cannot have void or function argument type"); + return NULL; + } + + if (!CType::IsSizeDefined(cx, result)) { + JS_ReportError(cx, "Argument type must have defined size"); + return NULL; + } + + // libffi cannot pass types of zero size by value. + JS_ASSERT(CType::GetSize(cx, result) != 0); + + return result; +} + +static JSObject* +PrepareReturnType(JSContext* cx, jsval type) +{ + if (JSVAL_IS_PRIMITIVE(type) || + !CType::IsCType(cx, JSVAL_TO_OBJECT(type))) { + JS_ReportError(cx, "not a ctypes type"); + return NULL; + } + + JSObject* result = JSVAL_TO_OBJECT(type); + TypeCode typeCode = CType::GetTypeCode(cx, result); + + // Arrays and functions can never be return types. + if (typeCode == TYPE_array || typeCode == TYPE_function) { + JS_ReportError(cx, "Return type cannot be an array or function"); + return NULL; + } + + if (typeCode != TYPE_void_t && !CType::IsSizeDefined(cx, result)) { + JS_ReportError(cx, "Return type must have defined size"); + return NULL; + } + + // libffi cannot pass types of zero size by value. + JS_ASSERT(typeCode == TYPE_void_t || CType::GetSize(cx, result) != 0); + + return result; +} + +static JS_ALWAYS_INLINE JSBool +IsEllipsis(JSContext* cx, jsval v, bool* isEllipsis) +{ + *isEllipsis = false; + if (!JSVAL_IS_STRING(v)) + return true; + JSString* str = JSVAL_TO_STRING(v); + if (str->length() != 3) + return true; + const jschar* chars = str->getChars(cx); + if (!chars) + return false; + jschar dot = '.'; + *isEllipsis = (chars[0] == dot && + chars[1] == dot && + chars[2] == dot); + return true; +} + +static JSBool +PrepareCIF(JSContext* cx, + FunctionInfo* fninfo) +{ + ffi_abi abi; + if (!GetABI(cx, OBJECT_TO_JSVAL(fninfo->mABI), &abi)) { + JS_ReportError(cx, "Invalid ABI specification"); + return false; + } + + ffi_type* rtype = CType::GetFFIType(cx, fninfo->mReturnType); + if (!rtype) + return false; + + ffi_status status = + ffi_prep_cif(&fninfo->mCIF, + abi, + fninfo->mFFITypes.length(), + rtype, + fninfo->mFFITypes.begin()); + + switch (status) { + case FFI_OK: + return true; + case FFI_BAD_ABI: + JS_ReportError(cx, "Invalid ABI specification"); + return false; + case FFI_BAD_TYPEDEF: + JS_ReportError(cx, "Invalid type specification"); + return false; + default: + JS_ReportError(cx, "Unknown libffi error"); + return false; + } +} + +void +FunctionType::BuildSymbolName(JSContext* cx, + JSString* name, + JSObject* typeObj, + AutoCString& result) +{ + FunctionInfo* fninfo = GetFunctionInfo(cx, typeObj); + + switch (GetABICode(cx, fninfo->mABI)) { + case ABI_DEFAULT: + case ABI_WINAPI: + // For cdecl or WINAPI functions, no mangling is necessary. + AppendString(result, name); + break; + + case ABI_STDCALL: { + // On WIN32, stdcall functions look like: + // _foo@40 + // where 'foo' is the function name, and '40' is the aligned size of the + // arguments. + AppendString(result, "_"); + AppendString(result, name); + AppendString(result, "@"); + + // Compute the suffix by aligning each argument to sizeof(ffi_arg). + size_t size = 0; + for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) { + JSObject* argType = fninfo->mArgTypes[i]; + size += Align(CType::GetSize(cx, argType), sizeof(ffi_arg)); + } + + IntegerToString(size, 10, result); + break; + } + + case INVALID_ABI: + JS_NOT_REACHED("invalid abi"); + break; + } +} + +static FunctionInfo* +NewFunctionInfo(JSContext* cx, + jsval abiType, + jsval returnType, + jsval* argTypes, + uintN argLength) +{ + AutoPtr fninfo(js_new()); + if (!fninfo) { + JS_ReportOutOfMemory(cx); + return NULL; + } + + ffi_abi abi; + if (!GetABI(cx, abiType, &abi)) { + JS_ReportError(cx, "Invalid ABI specification"); + return NULL; + } + fninfo->mABI = JSVAL_TO_OBJECT(abiType); + + // prepare the result type + fninfo->mReturnType = PrepareReturnType(cx, returnType); + if (!fninfo->mReturnType) + return NULL; + + // prepare the argument types + if (!fninfo->mArgTypes.reserve(argLength) || + !fninfo->mFFITypes.reserve(argLength)) { + JS_ReportOutOfMemory(cx); + return NULL; + } + + fninfo->mIsVariadic = false; + + for (JSUint32 i = 0; i < argLength; ++i) { + bool isEllipsis; + if (!IsEllipsis(cx, argTypes[i], &isEllipsis)) + return false; + if (isEllipsis) { + fninfo->mIsVariadic = true; + if (i < 1) { + JS_ReportError(cx, "\"...\" may not be the first and only parameter " + "type of a variadic function declaration"); + return NULL; + } + if (i < argLength - 1) { + JS_ReportError(cx, "\"...\" must be the last parameter type of a " + "variadic function declaration"); + return NULL; + } + if (GetABICode(cx, fninfo->mABI) != ABI_DEFAULT) { + JS_ReportError(cx, "Variadic functions must use the __cdecl calling " + "convention"); + return NULL; + } + break; + } + + JSObject* argType = PrepareType(cx, argTypes[i]); + if (!argType) + return NULL; + + ffi_type* ffiType = CType::GetFFIType(cx, argType); + if (!ffiType) + return NULL; + + fninfo->mArgTypes.append(argType); + fninfo->mFFITypes.append(ffiType); + } + + if (fninfo->mIsVariadic) + // wait to PrepareCIF until function is called + return fninfo.forget(); + + if (!PrepareCIF(cx, fninfo.get())) + return NULL; + + return fninfo.forget(); +} + +JSBool +FunctionType::Create(JSContext* cx, uintN argc, jsval* vp) +{ + // Construct and return a new FunctionType object. + if (argc < 2 || argc > 3) { + JS_ReportError(cx, "FunctionType takes two or three arguments"); + return JS_FALSE; + } + + jsval* argv = JS_ARGV(cx, vp); + Array argTypes; + JSObject* arrayObj = NULL; + + if (argc == 3) { + // Prepare an array of jsvals for the arguments. + if (JSVAL_IS_PRIMITIVE(argv[2]) || + !JS_IsArrayObject(cx, JSVAL_TO_OBJECT(argv[2]))) { + JS_ReportError(cx, "third argument must be an array"); + return JS_FALSE; + } + + arrayObj = JSVAL_TO_OBJECT(argv[2]); + jsuint len; + ASSERT_OK(JS_GetArrayLength(cx, arrayObj, &len)); + + if (!argTypes.appendN(JSVAL_VOID, len)) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + } + + // Pull out the argument types from the array, if any. + JS_ASSERT(!argTypes.length() || arrayObj); + js::AutoArrayRooter items(cx, argTypes.length(), argTypes.begin()); + for (jsuint i = 0; i < argTypes.length(); ++i) { + if (!JS_GetElement(cx, arrayObj, i, &argTypes[i])) + return JS_FALSE; + } + + JSObject* result = CreateInternal(cx, argv[0], argv[1], + argTypes.begin(), argTypes.length()); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + return JS_TRUE; +} + +JSObject* +FunctionType::CreateInternal(JSContext* cx, + jsval abi, + jsval rtype, + jsval* argtypes, + jsuint arglen) +{ + // Determine and check the types, and prepare the function CIF. + AutoPtr fninfo(NewFunctionInfo(cx, abi, rtype, argtypes, arglen)); + if (!fninfo) + return NULL; + + // Get ctypes.FunctionType.prototype and the common prototype for CData objects + // of this type, from ctypes.CType.prototype. + JSObject* typeProto = CType::GetProtoFromType(cx, fninfo->mReturnType, + SLOT_FUNCTIONPROTO); + JSObject* dataProto = CType::GetProtoFromType(cx, fninfo->mReturnType, + SLOT_FUNCTIONDATAPROTO); + + // Create a new CType object with the common properties and slots. + JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_function, + NULL, JSVAL_VOID, JSVAL_VOID, NULL); + if (!typeObj) + return NULL; + js::AutoObjectRooter root(cx, typeObj); + + // Stash the FunctionInfo in a reserved slot. + if (!JS_SetReservedSlot(cx, typeObj, SLOT_FNINFO, + PRIVATE_TO_JSVAL(fninfo.get()))) + return NULL; + fninfo.forget(); + + return typeObj; +} + +// Construct a function pointer to a JS function (see CClosure::Create()). +// Regular function pointers are constructed directly in +// PointerType::ConstructData(). +JSBool +FunctionType::ConstructData(JSContext* cx, + JSObject* typeObj, + JSObject* dataObj, + JSObject* fnObj, + JSObject* thisObj) +{ + JS_ASSERT(CType::GetTypeCode(cx, typeObj) == TYPE_function); + + PRFuncPtr* data = static_cast(CData::GetData(cx, dataObj)); + + FunctionInfo* fninfo = FunctionType::GetFunctionInfo(cx, typeObj); + if (fninfo->mIsVariadic) { + JS_ReportError(cx, "Can't declare a variadic callback function"); + return JS_FALSE; + } + if (GetABICode(cx, fninfo->mABI) == ABI_WINAPI) { + JS_ReportError(cx, "Can't declare a ctypes.winapi_abi callback function, " + "use ctypes.stdcall_abi instead"); + return JS_FALSE; + } + + JSObject* closureObj = CClosure::Create(cx, typeObj, fnObj, thisObj, data); + if (!closureObj) + return JS_FALSE; + js::AutoObjectRooter root(cx, closureObj); + + // Set the closure object as the referent of the new CData object. + if (!JS_SetReservedSlot(cx, dataObj, SLOT_REFERENT, + OBJECT_TO_JSVAL(closureObj))) + return JS_FALSE; + + // Seal the CData object, to prevent modification of the function pointer. + // This permanently associates this object with the closure, and avoids + // having to do things like reset SLOT_REFERENT when someone tries to + // change the pointer value. + // XXX This will need to change when bug 541212 is fixed -- CData::ValueSetter + // could be called on a frozen object. + return JS_FreezeObject(cx, dataObj); +} + +typedef Array AutoValueAutoArray; + +static JSBool +ConvertArgument(JSContext* cx, + jsval arg, + JSObject* type, + AutoValue* value, + AutoValueAutoArray* strings) +{ + if (!value->SizeToType(cx, type)) { + JS_ReportAllocationOverflow(cx); + return false; + } + + bool freePointer = false; + if (!ImplicitConvert(cx, arg, type, value->mData, true, &freePointer)) + return false; + + if (freePointer) { + // ImplicitConvert converted a string for us, which we have to free. + // Keep track of it. + if (!strings->growBy(1)) { + JS_ReportOutOfMemory(cx); + return false; + } + strings->back().mData = *static_cast(value->mData); + } + + return true; +} + +JSBool +FunctionType::Call(JSContext* cx, + uintN argc, + jsval* vp) +{ + // get the callee object... + JSObject* obj = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); + if (!CData::IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return false; + } + + JSObject* typeObj = CData::GetCType(cx, obj); + if (CType::GetTypeCode(cx, typeObj) != TYPE_pointer) { + JS_ReportError(cx, "not a FunctionType.ptr"); + return false; + } + + typeObj = PointerType::GetBaseType(cx, typeObj); + if (CType::GetTypeCode(cx, typeObj) != TYPE_function) { + JS_ReportError(cx, "not a FunctionType.ptr"); + return false; + } + + FunctionInfo* fninfo = GetFunctionInfo(cx, typeObj); + JSUint32 argcFixed = fninfo->mArgTypes.length(); + + if ((!fninfo->mIsVariadic && argc != argcFixed) || + (fninfo->mIsVariadic && argc < argcFixed)) { + JS_ReportError(cx, "Number of arguments does not match declaration"); + return false; + } + + // Check if we have a Library object. If we do, make sure it's open. + jsval slot; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_REFERENT, &slot)); + if (!JSVAL_IS_VOID(slot) && Library::IsLibrary(cx, JSVAL_TO_OBJECT(slot))) { + PRLibrary* library = Library::GetLibrary(cx, JSVAL_TO_OBJECT(slot)); + if (!library) { + JS_ReportError(cx, "library is not open"); + return false; + } + } + + // prepare the values for each argument + AutoValueAutoArray values; + AutoValueAutoArray strings; + if (!values.resize(argc)) { + JS_ReportOutOfMemory(cx); + return false; + } + + jsval* argv = JS_ARGV(cx, vp); + for (jsuint i = 0; i < argcFixed; ++i) + if (!ConvertArgument(cx, argv[i], fninfo->mArgTypes[i], &values[i], &strings)) + return false; + + if (fninfo->mIsVariadic) { + if (!fninfo->mFFITypes.resize(argc)) { + JS_ReportOutOfMemory(cx); + return false; + } + + JSObject* obj; // Could reuse obj instead of declaring a second + JSObject* type; // JSObject*, but readability would suffer. + + for (JSUint32 i = argcFixed; i < argc; ++i) { + if (JSVAL_IS_PRIMITIVE(argv[i]) || + !CData::IsCData(cx, obj = JSVAL_TO_OBJECT(argv[i]))) { + // Since we know nothing about the CTypes of the ... arguments, + // they absolutely must be CData objects already. + JS_ReportError(cx, "argument %d of type %s is not a CData object", + i, JS_GetTypeName(cx, JS_TypeOfValue(cx, argv[i]))); + return false; + } + if (!(type = CData::GetCType(cx, obj)) || + !(type = PrepareType(cx, OBJECT_TO_JSVAL(type))) || + // Relying on ImplicitConvert only for the limited purpose of + // converting one CType to another (e.g., T[] to T*). + !ConvertArgument(cx, argv[i], type, &values[i], &strings) || + !(fninfo->mFFITypes[i] = CType::GetFFIType(cx, type))) { + // These functions report their own errors. + return false; + } + } + if (!PrepareCIF(cx, fninfo)) + return false; + } + + // initialize a pointer to an appropriate location, for storing the result + AutoValue returnValue; + TypeCode typeCode = CType::GetTypeCode(cx, fninfo->mReturnType); + if (typeCode != TYPE_void_t && + !returnValue.SizeToType(cx, fninfo->mReturnType)) { + JS_ReportAllocationOverflow(cx); + return false; + } + + uintptr_t fn = *reinterpret_cast(CData::GetData(cx, obj)); + + // suspend the request before we call into the function, since the call + // may block or otherwise take a long time to return. + { + JSAutoSuspendRequest suspend(cx); + ffi_call(&fninfo->mCIF, FFI_FN(fn), returnValue.mData, + reinterpret_cast(values.begin())); + } + + // Small integer types get returned as a word-sized ffi_arg. Coerce it back + // into the correct size for ConvertToJS. + switch (typeCode) { +#define DEFINE_INT_TYPE(name, type, ffiType) \ + case TYPE_##name: \ + if (sizeof(type) < sizeof(ffi_arg)) { \ + ffi_arg data = *static_cast(returnValue.mData); \ + *static_cast(returnValue.mData) = static_cast(data); \ + } \ + break; +#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#include "typedefs.h" + default: + break; + } + + // prepare a JS object from the result + return ConvertToJS(cx, fninfo->mReturnType, NULL, returnValue.mData, + false, true, vp); +} + +FunctionInfo* +FunctionType::GetFunctionInfo(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(CType::IsCType(cx, obj)); + JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_function); + + jsval slot; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FNINFO, &slot)); + JS_ASSERT(!JSVAL_IS_VOID(slot) && JSVAL_TO_PRIVATE(slot)); + + return static_cast(JSVAL_TO_PRIVATE(slot)); +} + +static JSBool +CheckFunctionType(JSContext* cx, JSObject* obj) +{ + if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_function) { + JS_ReportError(cx, "not a FunctionType"); + return JS_FALSE; + } + return JS_TRUE; +} + +JSBool +FunctionType::ArgTypesGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) +{ + if (!CheckFunctionType(cx, obj)) + return JS_FALSE; + + // Check if we have a cached argTypes array. + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_ARGS_T, vp)); + if (!JSVAL_IS_VOID(*vp)) + return JS_TRUE; + + FunctionInfo* fninfo = GetFunctionInfo(cx, obj); + size_t len = fninfo->mArgTypes.length(); + + // Prepare a new array. + Array vec; + if (!vec.resize(len)) + return JS_FALSE; + + for (size_t i = 0; i < len; ++i) + vec[i] = OBJECT_TO_JSVAL(fninfo->mArgTypes[i]); + + JSObject* argTypes = JS_NewArrayObject(cx, len, vec.begin()); + if (!argTypes) + return JS_FALSE; + + // Seal and cache it. + if (!JS_FreezeObject(cx, argTypes) || + !JS_SetReservedSlot(cx, obj, SLOT_ARGS_T, OBJECT_TO_JSVAL(argTypes))) + return JS_FALSE; + + *vp = OBJECT_TO_JSVAL(argTypes); + return JS_TRUE; +} + +JSBool +FunctionType::ReturnTypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) +{ + if (!CheckFunctionType(cx, obj)) + return JS_FALSE; + + // Get the returnType object from the FunctionInfo. + *vp = OBJECT_TO_JSVAL(GetFunctionInfo(cx, obj)->mReturnType); + return JS_TRUE; +} + +JSBool +FunctionType::ABIGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) +{ + if (!CheckFunctionType(cx, obj)) + return JS_FALSE; + + // Get the abi object from the FunctionInfo. + *vp = OBJECT_TO_JSVAL(GetFunctionInfo(cx, obj)->mABI); + return JS_TRUE; +} + +JSBool +FunctionType::IsVariadicGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) +{ + if (!CheckFunctionType(cx, obj)) + return JS_FALSE; + + *vp = BOOLEAN_TO_JSVAL(GetFunctionInfo(cx, obj)->mIsVariadic); + return JS_TRUE; +} + +/******************************************************************************* +** CClosure implementation +*******************************************************************************/ + +JSObject* +CClosure::Create(JSContext* cx, + JSObject* typeObj, + JSObject* fnObj, + JSObject* thisObj, + PRFuncPtr* fnptr) +{ + JS_ASSERT(fnObj); + + JSObject* result = JS_NewObject(cx, &sCClosureClass, NULL, NULL); + if (!result) + return NULL; + js::AutoObjectRooter root(cx, result); + + // Get the FunctionInfo from the FunctionType. + FunctionInfo* fninfo = FunctionType::GetFunctionInfo(cx, typeObj); + JS_ASSERT(!fninfo->mIsVariadic); + JS_ASSERT(GetABICode(cx, fninfo->mABI) != ABI_WINAPI); + + AutoPtr cinfo(js_new()); + if (!cinfo) { + JS_ReportOutOfMemory(cx); + return NULL; + } + + // Get the prototype of the FunctionType object, of class CTypeProto, + // which stores our JSContext for use with the closure. + JSObject* proto = JS_GetPrototype(cx, typeObj); + JS_ASSERT(proto); + JS_ASSERT(JS_GET_CLASS(cx, proto) == &sCTypeProtoClass); + + // Get a JSContext for use with the closure. + jsval slot; + ASSERT_OK(JS_GetReservedSlot(cx, proto, SLOT_CLOSURECX, &slot)); + if (!JSVAL_IS_VOID(slot)) { + // Use the existing JSContext. + cinfo->cx = static_cast(JSVAL_TO_PRIVATE(slot)); + JS_ASSERT(cinfo->cx); + } else { + // Lazily instantiate a new JSContext, and stash it on + // ctypes.FunctionType.prototype. + JSRuntime* runtime = JS_GetRuntime(cx); + cinfo->cx = JS_NewContext(runtime, 8192); + if (!cinfo->cx) { + JS_ReportOutOfMemory(cx); + return NULL; + } + + if (!JS_SetReservedSlot(cx, proto, SLOT_CLOSURECX, + PRIVATE_TO_JSVAL(cinfo->cx))) { + JS_DestroyContextNoGC(cinfo->cx); + return NULL; + } + + JS_ClearContextThread(cinfo->cx); + } + +#ifdef DEBUG + // We want *this* context's thread here so use cx instead of cinfo->cx. + cinfo->cxThread = JS_GetContextThread(cx); +#endif + + cinfo->closureObj = result; + cinfo->typeObj = typeObj; + cinfo->thisObj = thisObj; + cinfo->jsfnObj = fnObj; + + // Create an ffi_closure object and initialize it. + void* code; + cinfo->closure = + static_cast(ffi_closure_alloc(sizeof(ffi_closure), &code)); + if (!cinfo->closure || !code) { + JS_ReportError(cx, "couldn't create closure - libffi error"); + return NULL; + } + + ffi_status status = ffi_prep_closure_loc(cinfo->closure, &fninfo->mCIF, + CClosure::ClosureStub, cinfo.get(), code); + if (status != FFI_OK) { + ffi_closure_free(cinfo->closure); + JS_ReportError(cx, "couldn't create closure - libffi error"); + return NULL; + } + + // Stash the ClosureInfo struct on our new object. + if (!JS_SetReservedSlot(cx, result, SLOT_CLOSUREINFO, + PRIVATE_TO_JSVAL(cinfo.get()))) { + ffi_closure_free(cinfo->closure); + return NULL; + } + cinfo.forget(); + + // Casting between void* and a function pointer is forbidden in C and C++. + // Do it via an integral type. + *fnptr = reinterpret_cast(reinterpret_cast(code)); + return result; +} + +void +CClosure::Trace(JSTracer* trc, JSObject* obj) +{ + JSContext* cx = trc->context; + + // Make sure our ClosureInfo slot is legit. If it's not, bail. + jsval slot; + if (!JS_GetReservedSlot(cx, obj, SLOT_CLOSUREINFO, &slot) || + JSVAL_IS_VOID(slot)) + return; + + ClosureInfo* cinfo = static_cast(JSVAL_TO_PRIVATE(slot)); + + // Identify our objects to the tracer. (There's no need to identify + // 'closureObj', since that's us.) + JS_CALL_OBJECT_TRACER(trc, cinfo->typeObj, "typeObj"); + JS_CALL_OBJECT_TRACER(trc, cinfo->jsfnObj, "jsfnObj"); + if (cinfo->thisObj) + JS_CALL_OBJECT_TRACER(trc, cinfo->thisObj, "thisObj"); +} + +void +CClosure::Finalize(JSContext* cx, JSObject* obj) +{ + // Make sure our ClosureInfo slot is legit. If it's not, bail. + jsval slot; + if (!JS_GetReservedSlot(cx, obj, SLOT_CLOSUREINFO, &slot) || + JSVAL_IS_VOID(slot)) + return; + + ClosureInfo* cinfo = static_cast(JSVAL_TO_PRIVATE(slot)); + if (cinfo->closure) + ffi_closure_free(cinfo->closure); + + js_delete(cinfo); +} + +void +CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData) +{ + JS_ASSERT(cif); + JS_ASSERT(result); + JS_ASSERT(args); + JS_ASSERT(userData); + + // Retrieve the essentials from our closure object. + ClosureInfo* cinfo = static_cast(userData); + JSContext* cx = cinfo->cx; + JSObject* typeObj = cinfo->typeObj; + JSObject* thisObj = cinfo->thisObj; + JSObject* jsfnObj = cinfo->jsfnObj; + + ScopedContextThread scopedThread(cx); + + // Assert that we're on the thread we were created from. + JS_ASSERT(cinfo->cxThread == JS_GetContextThread(cx)); + + JSAutoRequest ar(cx); + + JSAutoEnterCompartment ac; + if (!ac.enter(cx, jsfnObj)) + return; + + // Assert that our CIFs agree. + FunctionInfo* fninfo = FunctionType::GetFunctionInfo(cx, typeObj); + JS_ASSERT(cif == &fninfo->mCIF); + + TypeCode typeCode = CType::GetTypeCode(cx, fninfo->mReturnType); + + // Initialize the result to zero, in case something fails. Small integer types + // are promoted to a word-sized ffi_arg, so we must be careful to zero the + // whole word. + if (cif->rtype != &ffi_type_void) { + size_t size = cif->rtype->size; + switch (typeCode) { +#define DEFINE_INT_TYPE(name, type, ffiType) \ + case TYPE_##name: +#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#include "typedefs.h" + size = Align(size, sizeof(ffi_arg)); + break; + default: + break; + } + memset(result, 0, size); + } + + // Get a death grip on 'closureObj'. + js::AutoObjectRooter root(cx, cinfo->closureObj); + + // Set up an array for converted arguments. + Array argv; + if (!argv.appendN(JSVAL_VOID, cif->nargs)) { + JS_ReportOutOfMemory(cx); + return; + } + + js::AutoArrayRooter roots(cx, argv.length(), argv.begin()); + for (JSUint32 i = 0; i < cif->nargs; ++i) { + // Convert each argument, and have any CData objects created depend on + // the existing buffers. + if (!ConvertToJS(cx, fninfo->mArgTypes[i], NULL, args[i], false, false, + &argv[i])) + return; + } + + // Call the JS function. 'thisObj' may be NULL, in which case the JS engine + // will find an appropriate object to use. + jsval rval; + if (!JS_CallFunctionValue(cx, thisObj, OBJECT_TO_JSVAL(jsfnObj), cif->nargs, + argv.begin(), &rval)) + return; + + // Convert the result. Note that we pass 'isArgument = false', such that + // ImplicitConvert will *not* autoconvert a JS string into a pointer-to-char + // type, which would require an allocation that we can't track. The JS + // function must perform this conversion itself and return a PointerType + // CData; thusly, the burden of freeing the data is left to the user. + if (!ImplicitConvert(cx, rval, fninfo->mReturnType, result, false, NULL)) + return; + + // Small integer types must be returned as a word-sized ffi_arg. Coerce it + // back into the size libffi expects. + switch (typeCode) { +#define DEFINE_INT_TYPE(name, type, ffiType) \ + case TYPE_##name: \ + if (sizeof(type) < sizeof(ffi_arg)) { \ + ffi_arg data = *static_cast(result); \ + *static_cast(result) = data; \ + } \ + break; +#define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#define DEFINE_BOOL_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#define DEFINE_CHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_INT_TYPE(x, y, z) +#include "typedefs.h" + default: + break; + } +} + +/******************************************************************************* +** CData implementation +*******************************************************************************/ + +// Create a new CData object of type 'typeObj' containing binary data supplied +// in 'source', optionally with a referent object 'refObj'. +// +// * 'typeObj' must be a CType of defined (but possibly zero) size. +// +// * If an object 'refObj' is supplied, the new CData object stores the +// referent object in a reserved slot for GC safety, such that 'refObj' will +// be held alive by the resulting CData object. 'refObj' may or may not be +// a CData object; merely an object we want to keep alive. +// * If 'refObj' is a CData object, 'ownResult' must be false. +// * Otherwise, 'refObj' is a Library or CClosure object, and 'ownResult' +// may be true or false. +// * Otherwise 'refObj' is NULL. In this case, 'ownResult' may be true or false. +// +// * If 'ownResult' is true, the CData object will allocate an appropriately +// sized buffer, and free it upon finalization. If 'source' data is +// supplied, the data will be copied from 'source' into the buffer; +// otherwise, the entirety of the new buffer will be initialized to zero. +// * If 'ownResult' is false, the new CData's buffer refers to a slice of +// another buffer kept alive by 'refObj'. 'source' data must be provided, +// and the new CData's buffer will refer to 'source'. +JSObject* +CData::Create(JSContext* cx, + JSObject* typeObj, + JSObject* refObj, + void* source, + bool ownResult) +{ + JS_ASSERT(typeObj); + JS_ASSERT(CType::IsCType(cx, typeObj)); + JS_ASSERT(CType::IsSizeDefined(cx, typeObj)); + JS_ASSERT(ownResult || source); + JS_ASSERT_IF(refObj && CData::IsCData(cx, refObj), !ownResult); + + // Get the 'prototype' property from the type. + jsval slot; + ASSERT_OK(JS_GetReservedSlot(cx, typeObj, SLOT_PROTO, &slot)); + JS_ASSERT(!JSVAL_IS_PRIMITIVE(slot)); + + JSObject* proto = JSVAL_TO_OBJECT(slot); + JSObject* parent = JS_GetParent(cx, typeObj); + JS_ASSERT(parent); + + JSObject* dataObj = JS_NewObject(cx, &sCDataClass, proto, parent); + if (!dataObj) + return NULL; + js::AutoObjectRooter root(cx, dataObj); + + // set the CData's associated type + if (!JS_SetReservedSlot(cx, dataObj, SLOT_CTYPE, OBJECT_TO_JSVAL(typeObj))) + return NULL; + + // Stash the referent object, if any, for GC safety. + if (refObj && + !JS_SetReservedSlot(cx, dataObj, SLOT_REFERENT, OBJECT_TO_JSVAL(refObj))) + return NULL; + + // Set our ownership flag. + if (!JS_SetReservedSlot(cx, dataObj, SLOT_OWNS, BOOLEAN_TO_JSVAL(ownResult))) + return NULL; + + // attach the buffer. since it might not be 2-byte aligned, we need to + // allocate an aligned space for it and store it there. :( + char** buffer = js_new(); + if (!buffer) { + JS_ReportOutOfMemory(cx); + return NULL; + } + + char* data; + if (!ownResult) { + data = static_cast(source); + } else { + // Initialize our own buffer. + size_t size = CType::GetSize(cx, typeObj); + data = js_array_new(size); + if (!data) { + // Report a catchable allocation error. + JS_ReportAllocationOverflow(cx); + js_delete(buffer); + return NULL; + } + + if (!source) + memset(data, 0, size); + else + memcpy(data, source, size); + } + + *buffer = data; + if (!JS_SetReservedSlot(cx, dataObj, SLOT_DATA, PRIVATE_TO_JSVAL(buffer))) { + if (ownResult) + js_array_delete(data); + js_delete(buffer); + return NULL; + } + + return dataObj; +} + +void +CData::Finalize(JSContext* cx, JSObject* obj) +{ + // Delete our buffer, and the data it contains if we own it. + jsval slot; + if (!JS_GetReservedSlot(cx, obj, SLOT_OWNS, &slot) || JSVAL_IS_VOID(slot)) + return; + + JSBool owns = JSVAL_TO_BOOLEAN(slot); + + if (!JS_GetReservedSlot(cx, obj, SLOT_DATA, &slot) || JSVAL_IS_VOID(slot)) + return; + char** buffer = static_cast(JSVAL_TO_PRIVATE(slot)); + + if (owns) + js_array_delete(*buffer); + js_delete(buffer); +} + +JSObject* +CData::GetCType(JSContext* cx, JSObject* dataObj) +{ + JS_ASSERT(CData::IsCData(cx, dataObj)); + + jsval slot; + ASSERT_OK(JS_GetReservedSlot(cx, dataObj, SLOT_CTYPE, &slot)); + JSObject* typeObj = JSVAL_TO_OBJECT(slot); + JS_ASSERT(CType::IsCType(cx, typeObj)); + return typeObj; +} + +void* +CData::GetData(JSContext* cx, JSObject* dataObj) +{ + JS_ASSERT(CData::IsCData(cx, dataObj)); + + jsval slot; + ASSERT_OK(JS_GetReservedSlot(cx, dataObj, SLOT_DATA, &slot)); + + void** buffer = static_cast(JSVAL_TO_PRIVATE(slot)); + JS_ASSERT(buffer); + JS_ASSERT(*buffer); + return *buffer; +} + +bool +CData::IsCData(JSContext* cx, JSObject* obj) +{ + return JS_GET_CLASS(cx, obj) == &sCDataClass; +} + +JSBool +CData::ValueGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) +{ + if (!IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return JS_FALSE; + } + + // Convert the value to a primitive; do not create a new CData object. + if (!ConvertToJS(cx, GetCType(cx, obj), NULL, GetData(cx, obj), true, false, vp)) + return JS_FALSE; + + return JS_TRUE; +} + +JSBool +CData::ValueSetter(JSContext* cx, JSObject* obj, jsid idval, JSBool strict, jsval* vp) +{ + if (!IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return JS_FALSE; + } + + return ImplicitConvert(cx, *vp, GetCType(cx, obj), GetData(cx, obj), false, NULL); +} + +JSBool +CData::Address(JSContext* cx, uintN argc, jsval* vp) +{ + if (argc != 0) { + JS_ReportError(cx, "address takes zero arguments"); + return JS_FALSE; + } + + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return JS_FALSE; + } + + JSObject* typeObj = CData::GetCType(cx, obj); + JSObject* pointerType = PointerType::CreateInternal(cx, typeObj); + if (!pointerType) + return JS_FALSE; + js::AutoObjectRooter root(cx, pointerType); + + // Create a PointerType CData object containing null. + JSObject* result = CData::Create(cx, pointerType, NULL, NULL, true); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + + // Manually set the pointer inside the object, so we skip the conversion step. + void** data = static_cast(GetData(cx, result)); + *data = GetData(cx, obj); + return JS_TRUE; +} + +JSBool +CData::Cast(JSContext* cx, uintN argc, jsval* vp) +{ + if (argc != 2) { + JS_ReportError(cx, "cast takes two arguments"); + return JS_FALSE; + } + + jsval* argv = JS_ARGV(cx, vp); + if (JSVAL_IS_PRIMITIVE(argv[0]) || + !CData::IsCData(cx, JSVAL_TO_OBJECT(argv[0]))) { + JS_ReportError(cx, "first argument must be a CData"); + return JS_FALSE; + } + JSObject* sourceData = JSVAL_TO_OBJECT(argv[0]); + JSObject* sourceType = CData::GetCType(cx, sourceData); + + if (JSVAL_IS_PRIMITIVE(argv[1]) || + !CType::IsCType(cx, JSVAL_TO_OBJECT(argv[1]))) { + JS_ReportError(cx, "second argument must be a CType"); + return JS_FALSE; + } + + JSObject* targetType = JSVAL_TO_OBJECT(argv[1]); + size_t targetSize; + if (!CType::GetSafeSize(cx, targetType, &targetSize) || + targetSize > CType::GetSize(cx, sourceType)) { + JS_ReportError(cx, + "target CType has undefined or larger size than source CType"); + return JS_FALSE; + } + + // Construct a new CData object with a type of 'targetType' and a referent + // of 'sourceData'. + void* data = CData::GetData(cx, sourceData); + JSObject* result = CData::Create(cx, targetType, sourceData, data, false); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + return JS_TRUE; +} + +JSBool +CData::ReadString(JSContext* cx, uintN argc, jsval* vp) +{ + if (argc != 0) { + JS_ReportError(cx, "readString takes zero arguments"); + return JS_FALSE; + } + + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return JS_FALSE; + } + + // Make sure we are a pointer to, or an array of, an 8-bit or 16-bit + // character or integer type. + JSObject* baseType; + JSObject* typeObj = GetCType(cx, obj); + TypeCode typeCode = CType::GetTypeCode(cx, typeObj); + void* data; + size_t maxLength = -1; + switch (typeCode) { + case TYPE_pointer: + baseType = PointerType::GetBaseType(cx, typeObj); + data = *static_cast(GetData(cx, obj)); + if (data == NULL) { + JS_ReportError(cx, "cannot read contents of null pointer"); + return JS_FALSE; + } + break; + case TYPE_array: + baseType = ArrayType::GetBaseType(cx, typeObj); + data = GetData(cx, obj); + maxLength = ArrayType::GetLength(cx, typeObj); + break; + default: + JS_ReportError(cx, "not a PointerType or ArrayType"); + return JS_FALSE; + } + + // Convert the string buffer, taking care to determine the correct string + // length in the case of arrays (which may contain embedded nulls). + JSString* result; + switch (CType::GetTypeCode(cx, baseType)) { + case TYPE_int8_t: + case TYPE_uint8_t: + case TYPE_char: + case TYPE_signed_char: + case TYPE_unsigned_char: { + char* bytes = static_cast(data); + size_t length = strnlen(bytes, maxLength); + + // Determine the length. + size_t dstlen; + if (!js_InflateUTF8StringToBuffer(cx, bytes, length, NULL, &dstlen)) + return JS_FALSE; + + jschar* dst = + static_cast(JS_malloc(cx, (dstlen + 1) * sizeof(jschar))); + if (!dst) + return JS_FALSE; + + ASSERT_OK(js_InflateUTF8StringToBuffer(cx, bytes, length, dst, &dstlen)); + dst[dstlen] = 0; + + result = JS_NewUCString(cx, dst, dstlen); + break; + } + case TYPE_int16_t: + case TYPE_uint16_t: + case TYPE_short: + case TYPE_unsigned_short: + case TYPE_jschar: { + jschar* chars = static_cast(data); + size_t length = strnlen(chars, maxLength); + result = JS_NewUCStringCopyN(cx, chars, length); + break; + } + default: + JS_ReportError(cx, + "base type is not an 8-bit or 16-bit integer or character type"); + return JS_FALSE; + } + + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result)); + return JS_TRUE; +} + +JSBool +CData::ToSource(JSContext* cx, uintN argc, jsval* vp) +{ + if (argc != 0) { + JS_ReportError(cx, "toSource takes zero arguments"); + return JS_FALSE; + } + + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !CData::IsCData(cx, obj)) { + JS_ReportError(cx, "not a CData"); + return JS_FALSE; + } + + JSObject* typeObj = CData::GetCType(cx, obj); + void* data = CData::GetData(cx, obj); + + // Walk the types, building up the toSource() string. + // First, we build up the type expression: + // 't.ptr' for pointers; + // 't.array([n])' for arrays; + // 'n' for structs, where n = t.name, the struct's name. (We assume this is + // bound to a variable in the current scope.) + AutoString source; + BuildTypeSource(cx, typeObj, true, source); + AppendString(source, "("); + if (!BuildDataSource(cx, typeObj, data, false, source)) + return JS_FALSE; + + AppendString(source, ")"); + + JSString* result = NewUCString(cx, source); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result)); + return JS_TRUE; +} + +/******************************************************************************* +** Int64 and UInt64 implementation +*******************************************************************************/ + +JSObject* +Int64Base::Construct(JSContext* cx, + JSObject* proto, + JSUint64 data, + bool isUnsigned) +{ + JSClass* clasp = isUnsigned ? &sUInt64Class : &sInt64Class; + JSObject* result = JS_NewObject(cx, clasp, proto, JS_GetParent(cx, proto)); + if (!result) + return NULL; + js::AutoObjectRooter root(cx, result); + + // attach the Int64's data + JSUint64* buffer = js_new(data); + if (!buffer) { + JS_ReportOutOfMemory(cx); + return NULL; + } + + if (!JS_SetReservedSlot(cx, result, SLOT_INT64, PRIVATE_TO_JSVAL(buffer))) { + js_delete(buffer); + return NULL; + } + + if (!JS_FreezeObject(cx, result)) + return NULL; + + return result; +} + +void +Int64Base::Finalize(JSContext* cx, JSObject* obj) +{ + jsval slot; + if (!JS_GetReservedSlot(cx, obj, SLOT_INT64, &slot) || JSVAL_IS_VOID(slot)) + return; + + js_delete(static_cast(JSVAL_TO_PRIVATE(slot))); +} + +JSUint64 +Int64Base::GetInt(JSContext* cx, JSObject* obj) { + JS_ASSERT(Int64::IsInt64(cx, obj) || UInt64::IsUInt64(cx, obj)); + + jsval slot; + ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_INT64, &slot)); + return *static_cast(JSVAL_TO_PRIVATE(slot)); +} + +JSBool +Int64Base::ToString(JSContext* cx, + JSObject* obj, + uintN argc, + jsval* vp, + bool isUnsigned) +{ + if (argc > 1) { + JS_ReportError(cx, "toString takes zero or one argument"); + return JS_FALSE; + } + + jsuint radix = 10; + if (argc == 1) { + jsval arg = JS_ARGV(cx, vp)[0]; + if (JSVAL_IS_INT(arg)) + radix = JSVAL_TO_INT(arg); + if (!JSVAL_IS_INT(arg) || radix < 2 || radix > 36) { + JS_ReportError(cx, "radix argument must be an integer between 2 and 36"); + return JS_FALSE; + } + } + + AutoString intString; + if (isUnsigned) { + IntegerToString(GetInt(cx, obj), radix, intString); + } else { + IntegerToString(static_cast(GetInt(cx, obj)), radix, intString); + } + + JSString *result = NewUCString(cx, intString); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result)); + return JS_TRUE; +} + +JSBool +Int64Base::ToSource(JSContext* cx, + JSObject* obj, + uintN argc, + jsval* vp, + bool isUnsigned) +{ + if (argc != 0) { + JS_ReportError(cx, "toSource takes zero arguments"); + return JS_FALSE; + } + + // Return a decimal string suitable for constructing the number. + AutoString source; + if (isUnsigned) { + AppendString(source, "ctypes.UInt64(\""); + IntegerToString(GetInt(cx, obj), 10, source); + } else { + AppendString(source, "ctypes.Int64(\""); + IntegerToString(static_cast(GetInt(cx, obj)), 10, source); + } + AppendString(source, "\")"); + + JSString *result = NewUCString(cx, source); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result)); + return JS_TRUE; +} + +JSBool +Int64::Construct(JSContext* cx, + uintN argc, + jsval* vp) +{ + // Construct and return a new Int64 object. + if (argc != 1) { + JS_ReportError(cx, "Int64 takes one argument"); + return JS_FALSE; + } + + jsval* argv = JS_ARGV(cx, vp); + JSInt64 i = 0; + if (!jsvalToBigInteger(cx, argv[0], true, &i)) + return TypeError(cx, "int64", argv[0]); + + // Get ctypes.Int64.prototype from the 'prototype' property of the ctor. + jsval slot; + ASSERT_OK(JS_GetProperty(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), + "prototype", &slot)); + JSObject* proto = JSVAL_TO_OBJECT(slot); + JS_ASSERT(JS_GET_CLASS(cx, proto) == &sInt64ProtoClass); + + JSObject* result = Int64Base::Construct(cx, proto, i, false); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + return JS_TRUE; +} + +bool +Int64::IsInt64(JSContext* cx, JSObject* obj) +{ + return JS_GET_CLASS(cx, obj) == &sInt64Class; +} + +JSBool +Int64::ToString(JSContext* cx, uintN argc, jsval* vp) +{ + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !Int64::IsInt64(cx, obj)) { + JS_ReportError(cx, "not an Int64"); + return JS_FALSE; + } + + return Int64Base::ToString(cx, obj, argc, vp, false); +} + +JSBool +Int64::ToSource(JSContext* cx, uintN argc, jsval* vp) +{ + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !Int64::IsInt64(cx, obj)) { + JS_ReportError(cx, "not an Int64"); + return JS_FALSE; + } + + return Int64Base::ToSource(cx, obj, argc, vp, false); +} + +JSBool +Int64::Compare(JSContext* cx, uintN argc, jsval* vp) +{ + jsval* argv = JS_ARGV(cx, vp); + if (argc != 2 || + JSVAL_IS_PRIMITIVE(argv[0]) || + JSVAL_IS_PRIMITIVE(argv[1]) || + !Int64::IsInt64(cx, JSVAL_TO_OBJECT(argv[0])) || + !Int64::IsInt64(cx, JSVAL_TO_OBJECT(argv[1]))) { + JS_ReportError(cx, "compare takes two Int64 arguments"); + return JS_FALSE; + } + + JSObject* obj1 = JSVAL_TO_OBJECT(argv[0]); + JSObject* obj2 = JSVAL_TO_OBJECT(argv[1]); + + JSInt64 i1 = Int64Base::GetInt(cx, obj1); + JSInt64 i2 = Int64Base::GetInt(cx, obj2); + + if (i1 == i2) + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(0)); + else if (i1 < i2) + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(-1)); + else + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(1)); + + return JS_TRUE; +} + +#define LO_MASK ((JSUint64(1) << 32) - 1) +#define INT64_LO(i) ((i) & LO_MASK) +#define INT64_HI(i) ((i) >> 32) + +JSBool +Int64::Lo(JSContext* cx, uintN argc, jsval* vp) +{ + jsval* argv = JS_ARGV(cx, vp); + if (argc != 1 || JSVAL_IS_PRIMITIVE(argv[0]) || + !Int64::IsInt64(cx, JSVAL_TO_OBJECT(argv[0]))) { + JS_ReportError(cx, "lo takes one Int64 argument"); + return JS_FALSE; + } + + JSObject* obj = JSVAL_TO_OBJECT(argv[0]); + JSInt64 u = Int64Base::GetInt(cx, obj); + jsdouble d = JSUint32(INT64_LO(u)); + + jsval result; + if (!JS_NewNumberValue(cx, d, &result)) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, result); + return JS_TRUE; +} + +JSBool +Int64::Hi(JSContext* cx, uintN argc, jsval* vp) +{ + jsval* argv = JS_ARGV(cx, vp); + if (argc != 1 || JSVAL_IS_PRIMITIVE(argv[0]) || + !Int64::IsInt64(cx, JSVAL_TO_OBJECT(argv[0]))) { + JS_ReportError(cx, "hi takes one Int64 argument"); + return JS_FALSE; + } + + JSObject* obj = JSVAL_TO_OBJECT(argv[0]); + JSInt64 u = Int64Base::GetInt(cx, obj); + jsdouble d = JSInt32(INT64_HI(u)); + + jsval result; + if (!JS_NewNumberValue(cx, d, &result)) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, result); + return JS_TRUE; +} + +JSBool +Int64::Join(JSContext* cx, uintN argc, jsval* vp) +{ + if (argc != 2) { + JS_ReportError(cx, "join takes two arguments"); + return JS_FALSE; + } + + jsval* argv = JS_ARGV(cx, vp); + JSInt32 hi; + JSUint32 lo; + if (!jsvalToInteger(cx, argv[0], &hi)) + return TypeError(cx, "int32", argv[0]); + if (!jsvalToInteger(cx, argv[1], &lo)) + return TypeError(cx, "uint32", argv[1]); + + JSInt64 i = (JSInt64(hi) << 32) + JSInt64(lo); + + // Get Int64.prototype from the function's reserved slot. + JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); + + jsval slot; + ASSERT_OK(JS_GetReservedSlot(cx, callee, SLOT_FN_INT64PROTO, &slot)); + JSObject* proto = JSVAL_TO_OBJECT(slot); + JS_ASSERT(JS_GET_CLASS(cx, proto) == &sInt64ProtoClass); + + JSObject* result = Int64Base::Construct(cx, proto, i, false); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + return JS_TRUE; +} + +JSBool +UInt64::Construct(JSContext* cx, + uintN argc, + jsval* vp) +{ + // Construct and return a new UInt64 object. + if (argc != 1) { + JS_ReportError(cx, "UInt64 takes one argument"); + return JS_FALSE; + } + + jsval* argv = JS_ARGV(cx, vp); + JSUint64 u = 0; + if (!jsvalToBigInteger(cx, argv[0], true, &u)) + return TypeError(cx, "uint64", argv[0]); + + // Get ctypes.UInt64.prototype from the 'prototype' property of the ctor. + jsval slot; + ASSERT_OK(JS_GetProperty(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), + "prototype", &slot)); + JSObject* proto = JSVAL_TO_OBJECT(slot); + JS_ASSERT(JS_GET_CLASS(cx, proto) == &sUInt64ProtoClass); + + JSObject* result = Int64Base::Construct(cx, proto, u, true); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + return JS_TRUE; +} + +bool +UInt64::IsUInt64(JSContext* cx, JSObject* obj) +{ + return JS_GET_CLASS(cx, obj) == &sUInt64Class; +} + +JSBool +UInt64::ToString(JSContext* cx, uintN argc, jsval* vp) +{ + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !UInt64::IsUInt64(cx, obj)) { + JS_ReportError(cx, "not a UInt64"); + return JS_FALSE; + } + + return Int64Base::ToString(cx, obj, argc, vp, true); +} + +JSBool +UInt64::ToSource(JSContext* cx, uintN argc, jsval* vp) +{ + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !UInt64::IsUInt64(cx, obj)) { + JS_ReportError(cx, "not a UInt64"); + return JS_FALSE; + } + + return Int64Base::ToSource(cx, obj, argc, vp, true); +} + +JSBool +UInt64::Compare(JSContext* cx, uintN argc, jsval* vp) +{ + jsval* argv = JS_ARGV(cx, vp); + if (argc != 2 || + JSVAL_IS_PRIMITIVE(argv[0]) || + JSVAL_IS_PRIMITIVE(argv[1]) || + !UInt64::IsUInt64(cx, JSVAL_TO_OBJECT(argv[0])) || + !UInt64::IsUInt64(cx, JSVAL_TO_OBJECT(argv[1]))) { + JS_ReportError(cx, "compare takes two UInt64 arguments"); + return JS_FALSE; + } + + JSObject* obj1 = JSVAL_TO_OBJECT(argv[0]); + JSObject* obj2 = JSVAL_TO_OBJECT(argv[1]); + + JSUint64 u1 = Int64Base::GetInt(cx, obj1); + JSUint64 u2 = Int64Base::GetInt(cx, obj2); + + if (u1 == u2) + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(0)); + else if (u1 < u2) + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(-1)); + else + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(1)); + + return JS_TRUE; +} + +JSBool +UInt64::Lo(JSContext* cx, uintN argc, jsval* vp) +{ + jsval* argv = JS_ARGV(cx, vp); + if (argc != 1 || JSVAL_IS_PRIMITIVE(argv[0]) || + !UInt64::IsUInt64(cx, JSVAL_TO_OBJECT(argv[0]))) { + JS_ReportError(cx, "lo takes one UInt64 argument"); + return JS_FALSE; + } + + JSObject* obj = JSVAL_TO_OBJECT(argv[0]); + JSUint64 u = Int64Base::GetInt(cx, obj); + jsdouble d = JSUint32(INT64_LO(u)); + + jsval result; + if (!JS_NewNumberValue(cx, d, &result)) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, result); + return JS_TRUE; +} + +JSBool +UInt64::Hi(JSContext* cx, uintN argc, jsval* vp) +{ + jsval* argv = JS_ARGV(cx, vp); + if (argc != 1 || JSVAL_IS_PRIMITIVE(argv[0]) || + !UInt64::IsUInt64(cx, JSVAL_TO_OBJECT(argv[0]))) { + JS_ReportError(cx, "hi takes one UInt64 argument"); + return JS_FALSE; + } + + JSObject* obj = JSVAL_TO_OBJECT(argv[0]); + JSUint64 u = Int64Base::GetInt(cx, obj); + jsdouble d = JSUint32(INT64_HI(u)); + + jsval result; + if (!JS_NewNumberValue(cx, d, &result)) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, result); + return JS_TRUE; +} + +JSBool +UInt64::Join(JSContext* cx, uintN argc, jsval* vp) +{ + if (argc != 2) { + JS_ReportError(cx, "join takes two arguments"); + return JS_FALSE; + } + + jsval* argv = JS_ARGV(cx, vp); + JSUint32 hi; + JSUint32 lo; + if (!jsvalToInteger(cx, argv[0], &hi)) + return TypeError(cx, "uint32_t", argv[0]); + if (!jsvalToInteger(cx, argv[1], &lo)) + return TypeError(cx, "uint32_t", argv[1]); + + JSUint64 u = (JSUint64(hi) << 32) + JSUint64(lo); + + // Get UInt64.prototype from the function's reserved slot. + JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); + + jsval slot; + ASSERT_OK(JS_GetReservedSlot(cx, callee, SLOT_FN_INT64PROTO, &slot)); + JSObject* proto = JSVAL_TO_OBJECT(slot); + JS_ASSERT(JS_GET_CLASS(cx, proto) == &sUInt64ProtoClass); + + JSObject* result = Int64Base::Construct(cx, proto, u, true); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + return JS_TRUE; +} + +} +} + diff --git a/js/src/ctypes/CTypes.h b/js/src/ctypes/CTypes.h new file mode 100644 index 0000000..a5942e0 --- /dev/null +++ b/js/src/ctypes/CTypes.h @@ -0,0 +1,520 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is js-ctypes. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation . + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Witte + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef CTYPES_H +#define CTYPES_H + +#include "jscntxt.h" +#include "jsapi.h" +#include "jshashtable.h" +#include "prlink.h" +#include "ffi.h" + +namespace js { +namespace ctypes { + +/******************************************************************************* +** Utility classes +*******************************************************************************/ + +template +class OperatorDelete +{ +public: + static void destroy(T* ptr) { js_delete(ptr); } +}; + +template +class OperatorArrayDelete +{ +public: + static void destroy(T* ptr) { js_array_delete(ptr); } +}; + +// Class that takes ownership of a pointer T*, and calls js_delete() or +// js_array_delete() upon destruction. +template > +class AutoPtr { +private: + typedef AutoPtr self_type; + +public: + // An AutoPtr variant that calls js_array_delete() instead. + typedef AutoPtr > Array; + + AutoPtr() : mPtr(NULL) { } + explicit AutoPtr(T* ptr) : mPtr(ptr) { } + ~AutoPtr() { DeleteTraits::destroy(mPtr); } + + T* operator->() { return mPtr; } + bool operator!() { return mPtr == NULL; } + T& operator[](size_t i) { return *(mPtr + i); } + // Note: we cannot safely provide an 'operator T*()', since this would allow + // the compiler to perform implicit conversion from one AutoPtr to another + // via the constructor AutoPtr(T*). + + T* get() { return mPtr; } + void set(T* other) { JS_ASSERT(mPtr == NULL); mPtr = other; } + T* forget() { T* result = mPtr; mPtr = NULL; return result; } + + self_type& operator=(T* rhs) { mPtr = rhs; return *this; } + +private: + // Do not allow copy construction or assignment from another AutoPtr. + template AutoPtr(AutoPtr&); + template self_type& operator=(AutoPtr& rhs); + + T* mPtr; +}; + +// Container class for Vector, using SystemAllocPolicy. +template +class Array : public Vector +{ +}; + +// String and AutoString classes, based on Vector. +typedef Vector String; +typedef Vector AutoString; +typedef Vector CString; +typedef Vector AutoCString; + +// Convenience functions to append, insert, and compare Strings. +template +void +AppendString(Vector &v, const char (&array)[ArrayLength]) +{ + // Don't include the trailing '\0'. + size_t alen = ArrayLength - 1; + size_t vlen = v.length(); + if (!v.resize(vlen + alen)) + return; + + for (size_t i = 0; i < alen; ++i) + v[i + vlen] = array[i]; +} + +template +void +AppendString(Vector &v, Vector &w) +{ + v.append(w.begin(), w.length()); +} + +template +void +AppendString(Vector &v, JSString* str) +{ + JS_ASSERT(str); + const jschar *chars = str->getChars(NULL); + if (!chars) + return; + v.append(chars, str->length()); +} + +template +void +AppendString(Vector &v, JSString* str) +{ + JS_ASSERT(str); + size_t vlen = v.length(); + size_t alen = str->length(); + if (!v.resize(vlen + alen)) + return; + + const jschar *chars = str->getChars(NULL); + if (!chars) + return; + + for (size_t i = 0; i < alen; ++i) + v[i + vlen] = char(chars[i]); +} + +template +void +PrependString(Vector &v, const char (&array)[ArrayLength]) +{ + // Don't include the trailing '\0'. + size_t alen = ArrayLength - 1; + size_t vlen = v.length(); + if (!v.resize(vlen + alen)) + return; + + // Move vector data forward. This is safe since we've already resized. + memmove(v.begin() + alen, v.begin(), vlen * sizeof(T)); + + // Copy data to insert. + for (size_t i = 0; i < alen; ++i) + v[i] = array[i]; +} + +template +void +PrependString(Vector &v, JSString* str) +{ + JS_ASSERT(str); + size_t vlen = v.length(); + size_t alen = str->length(); + if (!v.resize(vlen + alen)) + return; + + const jschar *chars = str->getChars(NULL); + if (!chars) + return; + + // Move vector data forward. This is safe since we've already resized. + memmove(v.begin() + alen, v.begin(), vlen * sizeof(jschar)); + + // Copy data to insert. + memcpy(v.begin(), chars, alen * sizeof(jschar)); +} + +/******************************************************************************* +** Function and struct API definitions +*******************************************************************************/ + +JS_ALWAYS_INLINE void +ASSERT_OK(JSBool ok) +{ + JS_ASSERT(ok); +} + +// for JS error reporting +enum ErrorNum { +#define MSG_DEF(name, number, count, exception, format) \ + name = number, +#include "ctypes.msg" +#undef MSG_DEF + CTYPESERR_LIMIT +}; + +const JSErrorFormatString* +GetErrorMessage(void* userRef, const char* locale, const uintN errorNumber); +JSBool TypeError(JSContext* cx, const char* expected, jsval actual); + +/** + * ABI constants that specify the calling convention to use. + * ctypes.default_abi corresponds to the cdecl convention, and in almost all + * cases is the correct choice. ctypes.stdcall_abi is provided for calling + * stdcall functions on Win32, and implies stdcall symbol name decoration; + * ctypes.winapi_abi is just stdcall but without decoration. + */ +enum ABICode { + ABI_DEFAULT, + ABI_STDCALL, + ABI_WINAPI, + INVALID_ABI +}; + +enum TypeCode { + TYPE_void_t, +#define DEFINE_TYPE(name, type, ffiType) TYPE_##name, +#include "typedefs.h" + TYPE_pointer, + TYPE_function, + TYPE_array, + TYPE_struct +}; + +// Descriptor of one field in a StructType. The name of the field is stored +// as the key to the hash entry. +struct FieldInfo +{ + JSObject* mType; // CType of the field + size_t mIndex; // index of the field in the struct (first is 0) + size_t mOffset; // offset of the field in the struct, in bytes +}; + +// Hash policy for FieldInfos. +struct FieldHashPolicy +{ + typedef JSFlatString* Key; + typedef Key Lookup; + + static uint32 hash(const Lookup &l) { + const jschar* s = l->chars(); + size_t n = l->length(); + uint32 hash = 0; + for (; n > 0; s++, n--) + hash = hash * 33 + *s; + return hash; + } + + static JSBool match(const Key &k, const Lookup &l) { + if (k == l) + return true; + + if (k->length() != l->length()) + return false; + + return memcmp(k->chars(), l->chars(), k->length() * sizeof(jschar)) == 0; + } +}; + +typedef HashMap FieldInfoHash; + +// Descriptor of ABI, return type, argument types, and variadicity for a +// FunctionType. +struct FunctionInfo +{ + // Initialized in NewFunctionInfo when !mIsVariadic, but only later, in + // FunctionType::Call, when mIsVariadic. Not always consistent with + // mFFITypes, due to lazy initialization when mIsVariadic. + ffi_cif mCIF; + + // Calling convention of the function. Convert to ffi_abi using GetABI + // and OBJECT_TO_JSVAL. Stored as a JSObject* for ease of tracing. + JSObject* mABI; + + // The CType of the value returned by the function. + JSObject* mReturnType; + + // A fixed array of known parameter types, excluding any variadic + // parameters (if mIsVariadic). + Array mArgTypes; + + // A variable array of ffi_type*s corresponding to both known parameter + // types and dynamic (variadic) parameter types. Longer than mArgTypes + // only if mIsVariadic. + Array mFFITypes; + + // Flag indicating whether the function behaves like a C function with + // ... as the final formal parameter. + bool mIsVariadic; +}; + +// Parameters necessary for invoking a JS function from a C closure. +struct ClosureInfo +{ + JSContext* cx; // JSContext to use + JSObject* closureObj; // CClosure object + JSObject* typeObj; // FunctionType describing the C function + JSObject* thisObj; // 'this' object to use for the JS function call + JSObject* jsfnObj; // JS function + ffi_closure* closure; // The C closure itself +#ifdef DEBUG + jsword cxThread; // The thread on which the context may be used +#endif +}; + +bool IsCTypesGlobal(JSContext* cx, JSObject* obj); + +JSCTypesCallbacks* GetCallbacks(JSContext* cx, JSObject* obj); + +JSBool InitTypeClasses(JSContext* cx, JSObject* parent); + +JSBool ConvertToJS(JSContext* cx, JSObject* typeObj, JSObject* dataObj, + void* data, bool wantPrimitive, bool ownResult, jsval* result); + +JSBool ImplicitConvert(JSContext* cx, jsval val, JSObject* targetType, + void* buffer, bool isArgument, bool* freePointer); + +JSBool ExplicitConvert(JSContext* cx, jsval val, JSObject* targetType, + void* buffer); + +/******************************************************************************* +** JSClass reserved slot definitions +*******************************************************************************/ + +enum CTypesGlobalSlot { + SLOT_CALLBACKS = 0, // pointer to JSCTypesCallbacks struct + CTYPESGLOBAL_SLOTS +}; + +enum CABISlot { + SLOT_ABICODE = 0, // ABICode of the CABI object + CABI_SLOTS +}; + +enum CTypeProtoSlot { + SLOT_POINTERPROTO = 0, // ctypes.PointerType.prototype object + SLOT_ARRAYPROTO = 1, // ctypes.ArrayType.prototype object + SLOT_STRUCTPROTO = 2, // ctypes.StructType.prototype object + SLOT_FUNCTIONPROTO = 3, // ctypes.FunctionType.prototype object + SLOT_CDATAPROTO = 4, // ctypes.CData.prototype object + SLOT_POINTERDATAPROTO = 5, // common ancestor of all CData objects of PointerType + SLOT_ARRAYDATAPROTO = 6, // common ancestor of all CData objects of ArrayType + SLOT_STRUCTDATAPROTO = 7, // common ancestor of all CData objects of StructType + SLOT_FUNCTIONDATAPROTO = 8, // common ancestor of all CData objects of FunctionType + SLOT_INT64PROTO = 9, // ctypes.Int64.prototype object + SLOT_UINT64PROTO = 10, // ctypes.UInt64.prototype object + SLOT_CLOSURECX = 11, // JSContext for use with FunctionType closures + CTYPEPROTO_SLOTS +}; + +enum CTypeSlot { + SLOT_PROTO = 0, // 'prototype' property of the CType object + SLOT_TYPECODE = 1, // TypeCode of the CType object + SLOT_FFITYPE = 2, // ffi_type representing the type + SLOT_NAME = 3, // name of the type + SLOT_SIZE = 4, // size of the type, in bytes + SLOT_ALIGN = 5, // alignment of the type, in bytes + SLOT_PTR = 6, // cached PointerType object for type.ptr + // Note that some of the slots below can overlap, since they're for + // mutually exclusive types. + SLOT_TARGET_T = 7, // (PointerTypes only) 'targetType' property + SLOT_ELEMENT_T = 7, // (ArrayTypes only) 'elementType' property + SLOT_LENGTH = 8, // (ArrayTypes only) 'length' property + SLOT_FIELDS = 7, // (StructTypes only) 'fields' property + SLOT_FIELDINFO = 8, // (StructTypes only) FieldInfoHash table + SLOT_FNINFO = 7, // (FunctionTypes only) FunctionInfo struct + SLOT_ARGS_T = 8, // (FunctionTypes only) 'argTypes' property (cached) + CTYPE_SLOTS +}; + +enum CDataSlot { + SLOT_CTYPE = 0, // CType object representing the underlying type + SLOT_REFERENT = 1, // JSObject this object must keep alive, if any + SLOT_DATA = 2, // pointer to a buffer containing the binary data + SLOT_OWNS = 3, // JSVAL_TRUE if this CData owns its own buffer + CDATA_SLOTS +}; + +enum CClosureSlot { + SLOT_CLOSUREINFO = 0, // ClosureInfo struct + CCLOSURE_SLOTS +}; + +enum TypeCtorSlot { + SLOT_FN_CTORPROTO = 0 // ctypes.{Pointer,Array,Struct}Type.prototype + // JSFunction objects always get exactly two slots. +}; + +enum Int64Slot { + SLOT_INT64 = 0, // pointer to a 64-bit buffer containing the integer + INT64_SLOTS +}; + +enum Int64FunctionSlot { + SLOT_FN_INT64PROTO = 0 // ctypes.{Int64,UInt64}.prototype object + // JSFunction objects always get exactly two slots. +}; + +/******************************************************************************* +** Object API definitions +*******************************************************************************/ + +namespace CType { + JSObject* Create(JSContext* cx, JSObject* typeProto, JSObject* dataProto, + TypeCode type, JSString* name, jsval size, jsval align, ffi_type* ffiType); + + JSObject* DefineBuiltin(JSContext* cx, JSObject* parent, const char* propName, + JSObject* typeProto, JSObject* dataProto, const char* name, TypeCode type, + jsval size, jsval align, ffi_type* ffiType); + + bool IsCType(JSContext* cx, JSObject* obj); + TypeCode GetTypeCode(JSContext* cx, JSObject* typeObj); + bool TypesEqual(JSContext* cx, JSObject* t1, JSObject* t2); + size_t GetSize(JSContext* cx, JSObject* obj); + bool GetSafeSize(JSContext* cx, JSObject* obj, size_t* result); + bool IsSizeDefined(JSContext* cx, JSObject* obj); + size_t GetAlignment(JSContext* cx, JSObject* obj); + ffi_type* GetFFIType(JSContext* cx, JSObject* obj); + JSString* GetName(JSContext* cx, JSObject* obj); + JSObject* GetProtoFromCtor(JSContext* cx, JSObject* obj, CTypeProtoSlot slot); + JSObject* GetProtoFromType(JSContext* cx, JSObject* obj, CTypeProtoSlot slot); + JSCTypesCallbacks* GetCallbacksFromType(JSContext* cx, JSObject* obj); +} + +namespace PointerType { + JSObject* CreateInternal(JSContext* cx, JSObject* baseType); + + JSObject* GetBaseType(JSContext* cx, JSObject* obj); +} + +namespace ArrayType { + JSObject* CreateInternal(JSContext* cx, JSObject* baseType, size_t length, + bool lengthDefined); + + JSObject* GetBaseType(JSContext* cx, JSObject* obj); + size_t GetLength(JSContext* cx, JSObject* obj); + bool GetSafeLength(JSContext* cx, JSObject* obj, size_t* result); + ffi_type* BuildFFIType(JSContext* cx, JSObject* obj); +} + +namespace StructType { + JSBool DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj); + + const FieldInfoHash* GetFieldInfo(JSContext* cx, JSObject* obj); + const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSFlatString *name); + JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj); + ffi_type* BuildFFIType(JSContext* cx, JSObject* obj); +} + +namespace FunctionType { + JSObject* CreateInternal(JSContext* cx, jsval abi, jsval rtype, + jsval* argtypes, jsuint arglen); + + JSObject* ConstructWithObject(JSContext* cx, JSObject* typeObj, + JSObject* refObj, PRFuncPtr fnptr, JSObject* result); + + FunctionInfo* GetFunctionInfo(JSContext* cx, JSObject* obj); + JSObject* GetLibrary(JSContext* cx, JSObject* obj); + void BuildSymbolName(JSContext* cx, JSString* name, JSObject* typeObj, + AutoCString& result); +} + +namespace CClosure { + JSObject* Create(JSContext* cx, JSObject* typeObj, JSObject* fnObj, + JSObject* thisObj, PRFuncPtr* fnptr); +} + +namespace CData { + JSObject* Create(JSContext* cx, JSObject* typeObj, JSObject* refObj, + void* data, bool ownResult); + + JSObject* GetCType(JSContext* cx, JSObject* dataObj); + void* GetData(JSContext* cx, JSObject* dataObj); + bool IsCData(JSContext* cx, JSObject* obj); + + // Attached by JSAPI as the function 'ctypes.cast' + JSBool Cast(JSContext* cx, uintN argc, jsval* vp); +} + +namespace Int64 { + bool IsInt64(JSContext* cx, JSObject* obj); +} + +namespace UInt64 { + bool IsUInt64(JSContext* cx, JSObject* obj); +} + +} +} + +#endif diff --git a/js/src/ctypes/Library.cpp b/js/src/ctypes/Library.cpp new file mode 100644 index 0000000..7e14bba --- /dev/null +++ b/js/src/ctypes/Library.cpp @@ -0,0 +1,385 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is js-ctypes. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation . + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle , + * Fredrik Larsson + * Dan Witte + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jscntxt.h" +#include "Library.h" +#include "CTypes.h" +#include "prlink.h" + +namespace js { +namespace ctypes { + +/******************************************************************************* +** JSAPI function prototypes +*******************************************************************************/ + +namespace Library +{ + static void Finalize(JSContext* cx, JSObject* obj); + + static JSBool Close(JSContext* cx, uintN argc, jsval* vp); + static JSBool Declare(JSContext* cx, uintN argc, jsval* vp); +} + +/******************************************************************************* +** JSObject implementation +*******************************************************************************/ + +static JSClass sLibraryClass = { + "Library", + JSCLASS_HAS_RESERVED_SLOTS(LIBRARY_SLOTS) | JSCLASS_MARK_IS_TRACE, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub,JS_ResolveStub, JS_ConvertStub, Library::Finalize, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +#define CTYPESFN_FLAGS \ + (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) + +static JSFunctionSpec sLibraryFunctions[] = { + JS_FN("close", Library::Close, 0, CTYPESFN_FLAGS), + JS_FN("declare", Library::Declare, 0, CTYPESFN_FLAGS), + JS_FS_END +}; + +JSBool +Library::Name(JSContext* cx, uintN argc, jsval *vp) +{ + if (argc != 1) { + JS_ReportError(cx, "libraryName takes one argument"); + return JS_FALSE; + } + + jsval arg = JS_ARGV(cx, vp)[0]; + JSString* str = NULL; + if (JSVAL_IS_STRING(arg)) { + str = JSVAL_TO_STRING(arg); + } + else { + JS_ReportError(cx, "name argument must be a string"); + return JS_FALSE; + } + + AutoString resultString; + AppendString(resultString, DLL_PREFIX); + AppendString(resultString, str); + AppendString(resultString, DLL_SUFFIX); + + JSString *result = JS_NewUCStringCopyN(cx, resultString.begin(), + resultString.length()); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result)); + return JS_TRUE; +} + +JSObject* +Library::Create(JSContext* cx, jsval path, JSCTypesCallbacks* callbacks) +{ + JSObject* libraryObj = JS_NewObject(cx, &sLibraryClass, NULL, NULL); + if (!libraryObj) + return NULL; + js::AutoObjectRooter root(cx, libraryObj); + + // initialize the library + if (!JS_SetReservedSlot(cx, libraryObj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(NULL))) + return NULL; + + // attach API functions + if (!JS_DefineFunctions(cx, libraryObj, sLibraryFunctions)) + return NULL; + + if (!JSVAL_IS_STRING(path)) { + JS_ReportError(cx, "open takes a string argument"); + return NULL; + } + + PRLibSpec libSpec; + JSFlatString* pathStr = JS_FlattenString(cx, JSVAL_TO_STRING(path)); + if (!pathStr) + return NULL; +#ifdef XP_WIN + // On Windows, converting to native charset may corrupt path string. + // So, we have to use Unicode path directly. + const PRUnichar* pathChars = JS_GetFlatStringChars(pathStr); + if (!pathChars) + return NULL; + + libSpec.value.pathname_u = pathChars; + libSpec.type = PR_LibSpec_PathnameU; +#else + // Convert to platform native charset if the appropriate callback has been + // provided. + char* pathBytes; + if (callbacks && callbacks->unicodeToNative) { + pathBytes = + callbacks->unicodeToNative(cx, pathStr->chars(), pathStr->length()); + if (!pathBytes) + return NULL; + + } else { + // Fallback: assume the platform native charset is UTF-8. This is true + // for Mac OS X, Android, and probably Linux. + size_t nbytes = + js_GetDeflatedUTF8StringLength(cx, pathStr->chars(), pathStr->length()); + if (nbytes == (size_t) -1) + return NULL; + + pathBytes = static_cast(JS_malloc(cx, nbytes + 1)); + if (!pathBytes) + return NULL; + + ASSERT_OK(js_DeflateStringToUTF8Buffer(cx, pathStr->chars(), + pathStr->length(), pathBytes, &nbytes)); + pathBytes[nbytes] = 0; + } + + libSpec.value.pathname = pathBytes; + libSpec.type = PR_LibSpec_Pathname; +#endif + + PRLibrary* library = PR_LoadLibraryWithFlags(libSpec, 0); +#ifndef XP_WIN + JS_free(cx, pathBytes); +#endif + if (!library) { + JS_ReportError(cx, "couldn't open library"); + return NULL; + } + + // stash the library + if (!JS_SetReservedSlot(cx, libraryObj, SLOT_LIBRARY, + PRIVATE_TO_JSVAL(library))) + return NULL; + + return libraryObj; +} + +bool +Library::IsLibrary(JSContext* cx, JSObject* obj) +{ + return JS_GET_CLASS(cx, obj) == &sLibraryClass; +} + +PRLibrary* +Library::GetLibrary(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(IsLibrary(cx, obj)); + + jsval slot; + JS_GetReservedSlot(cx, obj, SLOT_LIBRARY, &slot); + return static_cast(JSVAL_TO_PRIVATE(slot)); +} + +void +Library::Finalize(JSContext* cx, JSObject* obj) +{ + // unload the library + PRLibrary* library = GetLibrary(cx, obj); + if (library) + PR_UnloadLibrary(library); +} + +JSBool +Library::Open(JSContext* cx, uintN argc, jsval *vp) +{ + JSObject* ctypesObj = JS_THIS_OBJECT(cx, vp); + if (!ctypesObj || !IsCTypesGlobal(cx, ctypesObj)) { + JS_ReportError(cx, "not a ctypes object"); + return JS_FALSE; + } + + if (argc != 1 || JSVAL_IS_VOID(JS_ARGV(cx, vp)[0])) { + JS_ReportError(cx, "open requires a single argument"); + return JS_FALSE; + } + + JSObject* library = Create(cx, JS_ARGV(cx, vp)[0], GetCallbacks(cx, ctypesObj)); + if (!library) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(library)); + return JS_TRUE; +} + +JSBool +Library::Close(JSContext* cx, uintN argc, jsval* vp) +{ + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !IsLibrary(cx, obj)) { + JS_ReportError(cx, "not a library"); + return JS_FALSE; + } + + if (argc != 0) { + JS_ReportError(cx, "close doesn't take any arguments"); + return JS_FALSE; + } + + // delete our internal objects + Finalize(cx, obj); + JS_SetReservedSlot(cx, obj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(NULL)); + + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return JS_TRUE; +} + +JSBool +Library::Declare(JSContext* cx, uintN argc, jsval* vp) +{ + JSObject* obj = JS_THIS_OBJECT(cx, vp); + if (!obj || !IsLibrary(cx, obj)) { + JS_ReportError(cx, "not a library"); + return JS_FALSE; + } + + PRLibrary* library = GetLibrary(cx, obj); + if (!library) { + JS_ReportError(cx, "library not open"); + return JS_FALSE; + } + + // We allow two API variants: + // 1) library.declare(name, abi, returnType, argType1, ...) + // declares a function with the given properties, and resolves the symbol + // address in the library. + // 2) library.declare(name, type) + // declares a symbol of 'type', and resolves it. The object that comes + // back will be of type 'type', and will point into the symbol data. + // This data will be both readable and writable via the usual CData + // accessors. If 'type' is a PointerType to a FunctionType, the result will + // be a function pointer, as with 1). + if (argc < 2) { + JS_ReportError(cx, "declare requires at least two arguments"); + return JS_FALSE; + } + + jsval* argv = JS_ARGV(cx, vp); + if (!JSVAL_IS_STRING(argv[0])) { + JS_ReportError(cx, "first argument must be a string"); + return JS_FALSE; + } + + JSObject* fnObj = NULL; + JSObject* typeObj; + js::AutoObjectRooter root(cx); + bool isFunction = argc > 2; + if (isFunction) { + // Case 1). + // Create a FunctionType representing the function. + fnObj = FunctionType::CreateInternal(cx, + argv[1], argv[2], &argv[3], argc - 3); + if (!fnObj) + return JS_FALSE; + root.setObject(fnObj); + + // Make a function pointer type. + typeObj = PointerType::CreateInternal(cx, fnObj); + if (!typeObj) + return JS_FALSE; + root.setObject(typeObj); + + } else { + // Case 2). + if (JSVAL_IS_PRIMITIVE(argv[1]) || + !CType::IsCType(cx, JSVAL_TO_OBJECT(argv[1])) || + !CType::IsSizeDefined(cx, JSVAL_TO_OBJECT(argv[1]))) { + JS_ReportError(cx, "second argument must be a type of defined size"); + return JS_FALSE; + } + + typeObj = JSVAL_TO_OBJECT(argv[1]); + if (CType::GetTypeCode(cx, typeObj) == TYPE_pointer) { + fnObj = PointerType::GetBaseType(cx, typeObj); + isFunction = fnObj && CType::GetTypeCode(cx, fnObj) == TYPE_function; + } + } + + void* data; + PRFuncPtr fnptr; + JSString* nameStr = JSVAL_TO_STRING(argv[0]); + AutoCString symbol; + if (isFunction) { + // Build the symbol, with mangling if necessary. + FunctionType::BuildSymbolName(cx, nameStr, fnObj, symbol); + AppendString(symbol, "\0"); + + // Look up the function symbol. + fnptr = PR_FindFunctionSymbol(library, symbol.begin()); + if (!fnptr) { + JS_ReportError(cx, "couldn't find function symbol in library"); + return JS_FALSE; + } + data = &fnptr; + + } else { + // 'typeObj' is another data type. Look up the data symbol. + AppendString(symbol, nameStr); + AppendString(symbol, "\0"); + + data = PR_FindSymbol(library, symbol.begin()); + if (!data) { + JS_ReportError(cx, "couldn't find symbol in library"); + return JS_FALSE; + } + } + + JSObject* result = CData::Create(cx, typeObj, obj, data, isFunction); + if (!result) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result)); + + // Seal the CData object, to prevent modification of the function pointer. + // This permanently associates this object with the library, and avoids + // having to do things like reset SLOT_REFERENT when someone tries to + // change the pointer value. + // XXX This will need to change when bug 541212 is fixed -- CData::ValueSetter + // could be called on a sealed object. + if (isFunction && !JS_FreezeObject(cx, result)) + return JS_FALSE; + + return JS_TRUE; +} + +} +} + diff --git a/js/src/ctypes/Library.h b/js/src/ctypes/Library.h new file mode 100644 index 0000000..0293fd2 --- /dev/null +++ b/js/src/ctypes/Library.h @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is js-ctypes. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation . + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Finkle , + * Dan Witte + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef LIBRARY_H +#define LIBRARY_H + +#include "jsapi.h" + +struct PRLibrary; + +namespace js { +namespace ctypes { + +enum LibrarySlot { + SLOT_LIBRARY = 0, + LIBRARY_SLOTS +}; + +namespace Library +{ + JSBool Name(JSContext* cx, uintN argc, jsval *vp); + + JSObject* Create(JSContext* cx, jsval path, JSCTypesCallbacks* callbacks); + + bool IsLibrary(JSContext* cx, JSObject* obj); + PRLibrary* GetLibrary(JSContext* cx, JSObject* obj); + + JSBool Open(JSContext* cx, uintN argc, jsval* vp); +} + +} +} + +#endif diff --git a/js/src/ctypes/ctypes.msg b/js/src/ctypes/ctypes.msg new file mode 100644 index 0000000..479f9de --- /dev/null +++ b/js/src/ctypes/ctypes.msg @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is js-ctypes. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation . + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Witte + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This is the jsctypes error message file. + * + * For syntax details, see js/src/js.msg. + */ + +MSG_DEF(CTYPESMSG_PLACEHOLDER_0, 0, 0, JSEXN_NONE, NULL) +MSG_DEF(CTYPESMSG_TYPE_ERROR, 1, 2, JSEXN_TYPEERR, "expected type {0}, got {1}") + diff --git a/js/src/ctypes/libffi.patch b/js/src/ctypes/libffi.patch new file mode 100644 index 0000000..6d29b58 --- /dev/null +++ b/js/src/ctypes/libffi.patch @@ -0,0 +1,1076 @@ +Patch libffi to fix bug 550602, bug 538216, bug545634, bug 594611, and bug 605421. + +diff --git a/js/src/ctypes/libffi/Makefile.in b/js/src/ctypes/libffi/Makefile.in +--- a/js/src/ctypes/libffi/Makefile.in ++++ b/js/src/ctypes/libffi/Makefile.in +@@ -192,17 +192,17 @@ LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIB + CCLD = $(CC) + LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ + SOURCES = $(libffi_la_SOURCES) $(nodist_libffi_la_SOURCES) \ + $(libffi_convenience_la_SOURCES) \ + $(nodist_libffi_convenience_la_SOURCES) + DIST_SOURCES = $(libffi_la_SOURCES) $(libffi_convenience_la_SOURCES) +-INFO_DEPS = $(srcdir)/doc/libffi.info ++INFO_DEPS = + am__TEXINFO_TEX_DIR = $(srcdir) + DVIS = doc/libffi.dvi + PDFS = doc/libffi.pdf + PSS = doc/libffi.ps + HTMLS = doc/libffi.html + TEXINFOS = doc/libffi.texi + TEXI2DVI = texi2dvi + TEXI2PDF = $(TEXI2DVI) --pdf --batch +@@ -966,7 +966,7 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/win32.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/win64.Plo@am__quote@ + +-.S.o: ++%.o: %.S + @am__fastdepCCAS_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + @am__fastdepCCAS_TRUE@ $(CPPASCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ + @am__fastdepCCAS_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@@ -974,7 +974,7 @@ distclean-compile: + @AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + @am__fastdepCCAS_FALSE@ $(CPPASCOMPILE) -c -o $@ $< + +-.S.obj: ++%.obj: %.S + @am__fastdepCCAS_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ + @am__fastdepCCAS_TRUE@ $(CPPASCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ + @am__fastdepCCAS_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@@ -982,7 +982,7 @@ distclean-compile: + @AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + @am__fastdepCCAS_FALSE@ $(CPPASCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +-.S.lo: ++%.lo: %.S + @am__fastdepCCAS_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ + @am__fastdepCCAS_TRUE@ $(LTCPPASCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ + @am__fastdepCCAS_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@@ -990,7 +990,7 @@ distclean-compile: + @AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + @am__fastdepCCAS_FALSE@ $(LTCPPASCOMPILE) -c -o $@ $< + +-.c.o: ++%.o: %.c + @am__fastdepCC_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ + @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@@ -998,7 +998,7 @@ distclean-compile: + @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + @am__fastdepCC_FALSE@ $(COMPILE) -c -o $@ $< + +-.c.obj: ++%.obj: %.c + @am__fastdepCC_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ + @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ + @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@@ -1006,7 +1006,7 @@ distclean-compile: + @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + @am__fastdepCC_FALSE@ $(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +-.c.lo: ++%.lo: %.c + @am__fastdepCC_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ + @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ + @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@@ -1108,7 +1108,7 @@ mostlyclean-vti: + + maintainer-clean-vti: + @MAINTAINER_MODE_TRUE@ -rm -f $(srcdir)/doc/stamp-vti $(srcdir)/doc/version.texi +-.dvi.ps: ++%.ps: %.dvi + TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ + $(DVIPS) -o $@ $< + +diff --git a/js/src/ctypes/libffi/configure b/js/src/ctypes/libffi/configure +--- a/js/src/ctypes/libffi/configure ++++ b/js/src/ctypes/libffi/configure +@@ -9016,17 +9016,17 @@ if test -z "$aix_libpath"; then aix_libp + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' +- fix_srcfile_path='`cygpath -w "$srcfile"`' ++ fix_srcfile_path='' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + +diff --git a/js/src/ctypes/libffi/src/x86/ffi64.c b/js/src/ctypes/libffi/src/x86/ffi64.c +--- a/js/src/ctypes/libffi/src/x86/ffi64.c ++++ b/js/src/ctypes/libffi/src/x86/ffi64.c +@@ -373,29 +373,29 @@ ffi_prep_cif_machdep (ffi_cif *cif) + || gprcount + ngpr > MAX_GPR_REGS + || ssecount + nsse > MAX_SSE_REGS) + { + long align = cif->arg_types[i]->alignment; + + if (align < 8) + align = 8; + +- bytes = ALIGN(bytes, align); ++ bytes = ALIGN (bytes, align); + bytes += cif->arg_types[i]->size; + } + else + { + gprcount += ngpr; + ssecount += nsse; + } + } + if (ssecount) + flags |= 1 << 11; + cif->flags = flags; +- cif->bytes = bytes; ++ cif->bytes = ALIGN (bytes, 8); + + return FFI_OK; + } + + void + ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) + { + enum x86_64_reg_class classes[MAX_CLASSES]; +diff --git a/js/src/ctypes/libffi/src/arm/ffi.c b/js/src/ctypes/libffi/src/arm/ffi.c +--- a/js/src/ctypes/libffi/src/arm/ffi.c ++++ b/js/src/ctypes/libffi/src/arm/ffi.c +@@ -24,22 +24,30 @@ + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + + #include + #include + + #include + ++/* Forward declares. */ ++static int vfp_type_p (ffi_type *); ++static void layout_vfp_args (ffi_cif *); ++ + /* ffi_prep_args is called by the assembly routine once stack space +- has been allocated for the function's arguments */ +- +-void ffi_prep_args(char *stack, extended_cif *ecif) ++ has been allocated for the function's arguments ++ ++ The vfp_space parameter is the load area for VFP regs, the return ++ value is cif->vfp_used (word bitset of VFP regs used for passing ++ arguments). These are only used for the VFP hard-float ABI. ++*/ ++int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space) + { +- register unsigned int i; ++ register unsigned int i, vi = 0; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if ( ecif->cif->flags == FFI_TYPE_STRUCT ) { + *(void **) argp = ecif->rvalue; +@@ -49,16 +57,31 @@ void ffi_prep_args(char *stack, extended + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + (i != 0); + i--, p_arg++) + { + size_t z; + ++ /* Allocated in VFP registers. */ ++ if (ecif->cif->abi == FFI_VFP ++ && vi < ecif->cif->vfp_nargs && vfp_type_p (*p_arg)) ++ { ++ float* vfp_slot = vfp_space + ecif->cif->vfp_args[vi++]; ++ if ((*p_arg)->type == FFI_TYPE_FLOAT) ++ *((float*)vfp_slot) = *((float*)*p_argv); ++ else if ((*p_arg)->type == FFI_TYPE_DOUBLE) ++ *((double*)vfp_slot) = *((double*)*p_argv); ++ else ++ memcpy(vfp_slot, *p_argv, (*p_arg)->size); ++ p_argv++; ++ continue; ++ } ++ + /* Align if necessary */ + if (((*p_arg)->alignment - 1) & (unsigned) argp) { + argp = (char *) ALIGN(argp, (*p_arg)->alignment); + } + + if ((*p_arg)->type == FFI_TYPE_STRUCT) + argp = (char *) ALIGN(argp, 4); + +@@ -98,23 +121,25 @@ void ffi_prep_args(char *stack, extended + } + else + { + memcpy(argp, *p_argv, z); + } + p_argv++; + argp += z; + } +- +- return; ++ ++ /* Indicate the VFP registers used. */ ++ return ecif->cif->vfp_used; + } + + /* Perform machine dependent cif processing */ + ffi_status ffi_prep_cif_machdep(ffi_cif *cif) + { ++ int type_code; + /* Round the stack up to a multiple of 8 bytes. This isn't needed + everywhere, but it is on some platforms, and it doesn't harm anything + when it isn't needed. */ + cif->bytes = (cif->bytes + 7) & ~7; + + /* Set the return type flag */ + switch (cif->rtype->type) + { +@@ -125,137 +150,176 @@ ffi_status ffi_prep_cif_machdep(ffi_cif + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags = (unsigned) FFI_TYPE_SINT64; + break; + + case FFI_TYPE_STRUCT: +- if (cif->rtype->size <= 4) ++ if (cif->abi == FFI_VFP ++ && (type_code = vfp_type_p (cif->rtype)) != 0) ++ { ++ /* A Composite Type passed in VFP registers, either ++ FFI_TYPE_STRUCT_VFP_FLOAT or FFI_TYPE_STRUCT_VFP_DOUBLE. */ ++ cif->flags = (unsigned) type_code; ++ } ++ else if (cif->rtype->size <= 4) + /* A Composite Type not larger than 4 bytes is returned in r0. */ + cif->flags = (unsigned)FFI_TYPE_INT; + else + /* A Composite Type larger than 4 bytes, or whose size cannot + be determined statically ... is stored in memory at an + address passed [in r0]. */ + cif->flags = (unsigned)FFI_TYPE_STRUCT; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + ++ /* Map out the register placements of VFP register args. ++ The VFP hard-float calling conventions are slightly more sophisticated than ++ the base calling conventions, so we do it here instead of in ffi_prep_args(). */ ++ if (cif->abi == FFI_VFP) ++ layout_vfp_args (cif); ++ + return FFI_OK; + } + +-extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, +- unsigned, unsigned, unsigned *, void (*fn)(void)); ++/* Prototypes for assembly functions, in sysv.S */ ++extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *); ++extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *); + + void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) + { + extended_cif ecif; + + int small_struct = (cif->flags == FFI_TYPE_INT + && cif->rtype->type == FFI_TYPE_STRUCT); ++ int vfp_struct = (cif->flags == FFI_TYPE_STRUCT_VFP_FLOAT ++ || cif->flags == FFI_TYPE_STRUCT_VFP_DOUBLE); + + ecif.cif = cif; + ecif.avalue = avalue; + + unsigned int temp; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (cif->flags == FFI_TYPE_STRUCT)) + { + ecif.rvalue = alloca(cif->rtype->size); + } + else if (small_struct) + ecif.rvalue = &temp; ++ else if (vfp_struct) ++ { ++ /* Largest case is double x 4. */ ++ ecif.rvalue = alloca(32); ++ } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: +- ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, +- fn); ++ ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue); ++ break; + ++ case FFI_VFP: ++ ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue); + break; ++ + default: + FFI_ASSERT(0); + break; + } + if (small_struct) + memcpy (rvalue, &temp, cif->rtype->size); ++ else if (vfp_struct) ++ memcpy (rvalue, ecif.rvalue, cif->rtype->size); + } + + /** private members **/ + + static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, +- void** args, ffi_cif* cif); ++ void** args, ffi_cif* cif, float *vfp_stack); + + void ffi_closure_SYSV (ffi_closure *); + ++void ffi_closure_VFP (ffi_closure *); ++ + /* This function is jumped to by the trampoline */ + + unsigned int +-ffi_closure_SYSV_inner (closure, respp, args) ++ffi_closure_SYSV_inner (closure, respp, args, vfp_args) + ffi_closure *closure; + void **respp; + void *args; ++ void *vfp_args; + { + // our various things... + ffi_cif *cif; + void **arg_area; + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void*)); + + /* this call will initialize ARG_AREA, such that each + * element in that array points to the corresponding + * value on the stack; and if the function returns + * a structure, it will re-set RESP to point to the + * structure return address. */ + +- ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif); ++ ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args); + + (closure->fun) (cif, *respp, arg_area, closure->user_data); + + return cif->flags; + } + + /*@-exportheader@*/ + static void + ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, +- void **avalue, ffi_cif *cif) ++ void **avalue, ffi_cif *cif, ++ /* Used only under VFP hard-float ABI. */ ++ float *vfp_stack) + /*@=exportheader@*/ + { +- register unsigned int i; ++ register unsigned int i, vi = 0; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if ( cif->flags == FFI_TYPE_STRUCT ) { + *rvalue = *(void **) argp; + argp += 4; + } + + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + { + size_t z; ++ size_t alignment; ++ ++ if (cif->abi == FFI_VFP ++ && vi < cif->vfp_nargs && vfp_type_p (*p_arg)) ++ { ++ *p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]); ++ continue; ++ } + +- size_t alignment = (*p_arg)->alignment; ++ alignment = (*p_arg)->alignment; + if (alignment < 4) + alignment = 4; + /* Align if necessary */ + if ((alignment - 1) & (unsigned) argp) { + argp = (char *) ALIGN(argp, alignment); + } + + z = (*p_arg)->size; +@@ -290,20 +354,147 @@ ffi_prep_incoming_args_SYSV(char *stack, + + ffi_status + ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) + { +- FFI_ASSERT (cif->abi == FFI_SYSV); ++ void (*closure_func)(ffi_closure*) = NULL; + ++ if (cif->abi == FFI_SYSV) ++ closure_func = &ffi_closure_SYSV; ++ else if (cif->abi == FFI_VFP) ++ closure_func = &ffi_closure_VFP; ++ else ++ FFI_ASSERT (0); ++ + FFI_INIT_TRAMPOLINE (&closure->tramp[0], \ +- &ffi_closure_SYSV, \ ++ closure_func, \ + codeloc); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; + } ++ ++/* Below are routines for VFP hard-float support. */ ++ ++static int rec_vfp_type_p (ffi_type *t, int *elt, int *elnum) ++{ ++ switch (t->type) ++ { ++ case FFI_TYPE_FLOAT: ++ case FFI_TYPE_DOUBLE: ++ *elt = (int) t->type; ++ *elnum = 1; ++ return 1; ++ ++ case FFI_TYPE_STRUCT_VFP_FLOAT: ++ *elt = FFI_TYPE_FLOAT; ++ *elnum = t->size / sizeof (float); ++ return 1; ++ ++ case FFI_TYPE_STRUCT_VFP_DOUBLE: ++ *elt = FFI_TYPE_DOUBLE; ++ *elnum = t->size / sizeof (double); ++ return 1; ++ ++ case FFI_TYPE_STRUCT:; ++ { ++ int base_elt = 0, total_elnum = 0; ++ ffi_type **el = t->elements; ++ while (*el) ++ { ++ int el_elt = 0, el_elnum = 0; ++ if (! rec_vfp_type_p (*el, &el_elt, &el_elnum) ++ || (base_elt && base_elt != el_elt) ++ || total_elnum + el_elnum > 4) ++ return 0; ++ base_elt = el_elt; ++ total_elnum += el_elnum; ++ el++; ++ } ++ *elnum = total_elnum; ++ *elt = base_elt; ++ return 1; ++ } ++ default: ; ++ } ++ return 0; ++} ++ ++static int vfp_type_p (ffi_type *t) ++{ ++ int elt, elnum; ++ if (rec_vfp_type_p (t, &elt, &elnum)) ++ { ++ if (t->type == FFI_TYPE_STRUCT) ++ { ++ if (elnum == 1) ++ t->type = elt; ++ else ++ t->type = (elt == FFI_TYPE_FLOAT ++ ? FFI_TYPE_STRUCT_VFP_FLOAT ++ : FFI_TYPE_STRUCT_VFP_DOUBLE); ++ } ++ return (int) t->type; ++ } ++ return 0; ++} ++ ++static void place_vfp_arg (ffi_cif *cif, ffi_type *t) ++{ ++ int reg = cif->vfp_reg_free; ++ int nregs = t->size / sizeof (float); ++ int align = ((t->type == FFI_TYPE_STRUCT_VFP_FLOAT ++ || t->type == FFI_TYPE_FLOAT) ? 1 : 2); ++ /* Align register number. */ ++ if ((reg & 1) && align == 2) ++ reg++; ++ while (reg + nregs <= 16) ++ { ++ int s, new_used = 0; ++ for (s = reg; s < reg + nregs; s++) ++ { ++ new_used |= (1 << s); ++ if (cif->vfp_used & (1 << s)) ++ { ++ reg += align; ++ goto next_reg; ++ } ++ } ++ /* Found regs to allocate. */ ++ cif->vfp_used |= new_used; ++ cif->vfp_args[cif->vfp_nargs++] = reg; ++ ++ /* Update vfp_reg_free. */ ++ if (cif->vfp_used & (1 << cif->vfp_reg_free)) ++ { ++ reg += nregs; ++ while (cif->vfp_used & (1 << reg)) ++ reg += 1; ++ cif->vfp_reg_free = reg; ++ } ++ return; ++ next_reg: ; ++ } ++} ++ ++static void layout_vfp_args (ffi_cif *cif) ++{ ++ int i; ++ /* Init VFP fields */ ++ cif->vfp_used = 0; ++ cif->vfp_nargs = 0; ++ cif->vfp_reg_free = 0; ++ memset (cif->vfp_args, -1, 16); /* Init to -1. */ ++ ++ for (i = 0; i < cif->nargs; i++) ++ { ++ ffi_type *t = cif->arg_types[i]; ++ if (vfp_type_p (t)) ++ place_vfp_arg (cif, t); ++ } ++} +diff --git a/js/src/ctypes/libffi/src/arm/ffitarget.h b/js/src/ctypes/libffi/src/arm/ffitarget.h +--- a/js/src/ctypes/libffi/src/arm/ffitarget.h ++++ b/js/src/ctypes/libffi/src/arm/ffitarget.h +@@ -29,21 +29,35 @@ + + #ifndef LIBFFI_ASM + typedef unsigned long ffi_arg; + typedef signed long ffi_sarg; + + typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, ++ FFI_VFP, + FFI_LAST_ABI, ++#ifdef __ARM_PCS_VFP ++ FFI_DEFAULT_ABI = FFI_VFP ++#else + FFI_DEFAULT_ABI = FFI_SYSV ++#endif + } ffi_abi; + #endif + ++#define FFI_EXTRA_CIF_FIELDS \ ++ int vfp_used; \ ++ short vfp_reg_free, vfp_nargs; \ ++ signed char vfp_args[16] \ ++ ++/* Internally used. */ ++#define FFI_TYPE_STRUCT_VFP_FLOAT (FFI_TYPE_LAST + 1) ++#define FFI_TYPE_STRUCT_VFP_DOUBLE (FFI_TYPE_LAST + 2) ++ + /* ---- Definitions for closures ----------------------------------------- */ + + #define FFI_CLOSURES 1 + #define FFI_TRAMPOLINE_SIZE 20 + #define FFI_NATIVE_RAW_API 0 + + #endif + +diff --git a/js/src/ctypes/libffi/src/arm/sysv.S b/js/src/ctypes/libffi/src/arm/sysv.S +--- a/js/src/ctypes/libffi/src/arm/sysv.S ++++ b/js/src/ctypes/libffi/src/arm/sysv.S +@@ -137,54 +137,52 @@ _L__\name: + ldr\cond pc, [sp], #4 + .else + ldm\cond\dirn sp!, {\regs, pc} + .endif + #endif + .endm + + +- @ r0: ffi_prep_args ++ @ r0: fn + @ r1: &ecif + @ r2: cif->bytes + @ r3: fig->flags + @ sp+0: ecif.rvalue +- @ sp+4: fn + + @ This assumes we are using gas. + ARM_FUNC_START ffi_call_SYSV + @ Save registers + stmfd sp!, {r0-r3, fp, lr} + UNWIND .save {r0-r3, fp, lr} + mov fp, sp + + UNWIND .setfp fp, sp + + @ Make room for all of the new args. + sub sp, fp, r2 + + @ Place all of the ffi_prep_args in position +- mov ip, r0 + mov r0, sp + @ r1 already set + + @ Call ffi_prep_args(stack, &ecif) +- call_reg(ip) ++ bl ffi_prep_args + + @ move first 4 parameters in registers + ldmia sp, {r0-r3} + + @ and adjust stack +- ldr ip, [fp, #8] +- cmp ip, #16 +- movhs ip, #16 +- add sp, sp, ip ++ sub lr, fp, sp @ cif->bytes == fp - sp ++ ldr ip, [fp] @ load fn() in advance ++ cmp lr, #16 ++ movhs lr, #16 ++ add sp, sp, lr + + @ call (fn) (...) +- ldr ip, [fp, #28] + call_reg(ip) + + @ Remove the space we pushed for the args + mov sp, fp + + @ Load r2 with the pointer to storage for the return value + ldr r2, [sp, #24] + +@@ -225,16 +223,111 @@ ARM_FUNC_START ffi_call_SYSV + + LSYM(Lepilogue): + RETLDM "r0-r3,fp" + + .ffi_call_SYSV_end: + UNWIND .fnend + .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) + ++ ++ @ r0: fn ++ @ r1: &ecif ++ @ r2: cif->bytes ++ @ r3: fig->flags ++ @ sp+0: ecif.rvalue ++ ++ARM_FUNC_START ffi_call_VFP ++ @ Save registers ++ stmfd sp!, {r0-r3, fp, lr} ++ UNWIND .save {r0-r3, fp, lr} ++ mov fp, sp ++ UNWIND .setfp fp, sp ++ ++ @ Make room for all of the new args. ++ sub sp, sp, r2 ++ ++ @ Make room for loading VFP args ++ sub sp, sp, #64 ++ ++ @ Place all of the ffi_prep_args in position ++ mov r0, sp ++ @ r1 already set ++ sub r2, fp, #64 @ VFP scratch space ++ ++ @ Call ffi_prep_args(stack, &ecif, vfp_space) ++ bl ffi_prep_args ++ ++ @ Load VFP register args if needed ++ cmp r0, #0 ++ beq LSYM(Lbase_args) ++ ++ @ Load only d0 if possible ++ cmp r0, #3 ++ sub ip, fp, #64 ++ flddle d0, [ip] ++ fldmiadgt ip, {d0-d7} ++ ++LSYM(Lbase_args): ++ @ move first 4 parameters in registers ++ ldmia sp, {r0-r3} ++ ++ @ and adjust stack ++ sub lr, ip, sp @ cif->bytes == (fp - 64) - sp ++ ldr ip, [fp] @ load fn() in advance ++ cmp lr, #16 ++ movhs lr, #16 ++ add sp, sp, lr ++ ++ @ call (fn) (...) ++ call_reg(ip) ++ ++ @ Remove the space we pushed for the args ++ mov sp, fp ++ ++ @ Load r2 with the pointer to storage for ++ @ the return value ++ ldr r2, [sp, #24] ++ ++ @ Load r3 with the return type code ++ ldr r3, [sp, #12] ++ ++ @ If the return value pointer is NULL, ++ @ assume no return value. ++ cmp r2, #0 ++ beq LSYM(Lepilogue_vfp) ++ ++ cmp r3, #FFI_TYPE_INT ++ streq r0, [r2] ++ beq LSYM(Lepilogue_vfp) ++ ++ cmp r3, #FFI_TYPE_SINT64 ++ stmeqia r2, {r0, r1} ++ beq LSYM(Lepilogue_vfp) ++ ++ cmp r3, #FFI_TYPE_FLOAT ++ fstseq s0, [r2] ++ beq LSYM(Lepilogue_vfp) ++ ++ cmp r3, #FFI_TYPE_DOUBLE ++ fstdeq d0, [r2] ++ beq LSYM(Lepilogue_vfp) ++ ++ cmp r3, #FFI_TYPE_STRUCT_VFP_FLOAT ++ cmpne r3, #FFI_TYPE_STRUCT_VFP_DOUBLE ++ fstmiadeq r2, {d0-d3} ++ ++LSYM(Lepilogue_vfp): ++ RETLDM "r0-r3,fp" ++ ++.ffi_call_VFP_end: ++ UNWIND .fnend ++ .size CNAME(ffi_call_VFP),.ffi_call_VFP_end-CNAME(ffi_call_VFP) ++ ++ + /* + unsigned int FFI_HIDDEN + ffi_closure_SYSV_inner (closure, respp, args) + ffi_closure *closure; + void **respp; + void *args; + */ + +@@ -297,11 +390,73 @@ ARM_FUNC_START ffi_closure_SYSV + ldfd f0, [sp] + b .Lclosure_epilogue + #endif + + .ffi_closure_SYSV_end: + UNWIND .fnend + .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) + ++ ++ARM_FUNC_START ffi_closure_VFP ++ fstmfdd sp!, {d0-d7} ++ @ r0-r3, then d0-d7 ++ UNWIND .pad #80 ++ add ip, sp, #80 ++ stmfd sp!, {ip, lr} ++ UNWIND .save {r0, lr} ++ add r2, sp, #72 ++ add r3, sp, #8 ++ .pad #72 ++ sub sp, sp, #72 ++ str sp, [sp, #64] ++ add r1, sp, #64 ++ bl ffi_closure_SYSV_inner ++ ++ cmp r0, #FFI_TYPE_INT ++ beq .Lretint_vfp ++ ++ cmp r0, #FFI_TYPE_FLOAT ++ beq .Lretfloat_vfp ++ ++ cmp r0, #FFI_TYPE_DOUBLE ++ cmpne r0, #FFI_TYPE_LONGDOUBLE ++ beq .Lretdouble_vfp ++ ++ cmp r0, #FFI_TYPE_SINT64 ++ beq .Lretlonglong_vfp ++ ++ cmp r0, #FFI_TYPE_STRUCT_VFP_FLOAT ++ beq .Lretfloat_struct_vfp ++ ++ cmp r0, #FFI_TYPE_STRUCT_VFP_DOUBLE ++ beq .Lretdouble_struct_vfp ++ ++.Lclosure_epilogue_vfp: ++ add sp, sp, #72 ++ ldmfd sp, {sp, pc} ++ ++.Lretfloat_vfp: ++ flds s0, [sp] ++ b .Lclosure_epilogue_vfp ++.Lretdouble_vfp: ++ fldd d0, [sp] ++ b .Lclosure_epilogue_vfp ++.Lretint_vfp: ++ ldr r0, [sp] ++ b .Lclosure_epilogue_vfp ++.Lretlonglong_vfp: ++ ldmia sp, {r0, r1} ++ b .Lclosure_epilogue_vfp ++.Lretfloat_struct_vfp: ++ fldmiad sp, {d0-d1} ++ b .Lclosure_epilogue_vfp ++.Lretdouble_struct_vfp: ++ fldmiad sp, {d0-d3} ++ b .Lclosure_epilogue_vfp ++ ++.ffi_closure_VFP_end: ++ UNWIND .fnend ++ .size CNAME(ffi_closure_VFP),.ffi_closure_VFP_end-CNAME(ffi_closure_VFP) ++ + #if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",%progbits + #endif +diff --git a/js/src/ctypes/libffi/testsuite/lib/libffi-dg.exp b/js/src/ctypes/libffi/testsuite/lib/libffi-dg.exp +--- a/js/src/ctypes/libffi/testsuite/lib/libffi-dg.exp ++++ b/js/src/ctypes/libffi/testsuite/lib/libffi-dg.exp +@@ -261,16 +261,66 @@ proc dg-xfail-if { args } { + set args [lreplace $args 0 0] + set selector "target [join [lindex $args 1]]" + if { [dg-process-target $selector] == "S" } { + global compiler_conditional_xfail_data + set compiler_conditional_xfail_data $args + } + } + ++proc check-flags { args } { ++ ++ # The args are within another list; pull them out. ++ set args [lindex $args 0] ++ ++ # The next two arguments are optional. If they were not specified, ++ # use the defaults. ++ if { [llength $args] == 2 } { ++ lappend $args [list "*"] ++ } ++ if { [llength $args] == 3 } { ++ lappend $args [list ""] ++ } ++ ++ # If the option strings are the defaults, or the same as the ++ # defaults, there is no need to call check_conditional_xfail to ++ # compare them to the actual options. ++ if { [string compare [lindex $args 2] "*"] == 0 ++ && [string compare [lindex $args 3] "" ] == 0 } { ++ set result 1 ++ } else { ++ # The target list might be an effective-target keyword, so replace ++ # the original list with "*-*-*", since we already know it matches. ++ set result [check_conditional_xfail [lreplace $args 1 1 "*-*-*"]] ++ } ++ ++ return $result ++} ++ ++proc dg-skip-if { args } { ++ # Verify the number of arguments. The last two are optional. ++ set args [lreplace $args 0 0] ++ if { [llength $args] < 2 || [llength $args] > 4 } { ++ error "dg-skip-if 2: need 2, 3, or 4 arguments" ++ } ++ ++ # Don't bother if we're already skipping the test. ++ upvar dg-do-what dg-do-what ++ if { [lindex ${dg-do-what} 1] == "N" } { ++ return ++ } ++ ++ set selector [list target [lindex $args 1]] ++ if { [dg-process-target $selector] == "S" } { ++ if [check-flags $args] { ++ upvar dg-do-what dg-do-what ++ set dg-do-what [list [lindex ${dg-do-what} 0] "N" "P"] ++ } ++ } ++} + + # We need to make sure that additional_files and additional_sources + # are both cleared out after every test. It is not enough to clear + # them out *before* the next test run because gcc-target-compile gets + # run directly from some .exp files (outside of any test). (Those + # uses should eventually be eliminated.) + + # Because the DG framework doesn't provide a hook that is run at the +diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_double_va.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_double_va.c +--- a/js/src/ctypes/libffi/testsuite/libffi.call/cls_double_va.c ++++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_double_va.c +@@ -1,16 +1,18 @@ + /* Area: ffi_call, closure_call + Purpose: Test doubles passed in variable argument lists. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/6/2007 */ + + /* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ + /* { dg-output "" { xfail avr32*-*-* } } */ ++/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */ ++ + #include "ffitest.h" + + static void + cls_double_va_fn(ffi_cif* cif __UNUSED__, void* resp, + void** args, void* userdata __UNUSED__) + { + char* format = *(char**)args[0]; + double doubleValue = *(double*)args[1]; +diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c +--- a/js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c ++++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c +@@ -1,16 +1,18 @@ + /* Area: ffi_call, closure_call + Purpose: Test long doubles passed in variable argument lists. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/6/2007 */ + + /* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ + /* { dg-output "" { xfail avr32*-*-* x86_64-*-mingw* } } */ ++/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */ ++ + #include "ffitest.h" + + static void + cls_longdouble_va_fn(ffi_cif* cif __UNUSED__, void* resp, + void** args, void* userdata __UNUSED__) + { + char* format = *(char**)args[0]; + long double ldValue = *(long double*)args[1]; +diff -r bb9089ae2322 js/src/ctypes/libffi/include/ffi.h.in +--- a/js/src/ctypes/libffi/include/ffi.h.in Fri Jan 21 15:40:14 2011 -0800 ++++ b/js/src/ctypes/libffi/include/ffi.h.in Thu Jan 27 19:10:51 2011 +0100 +@@ -72,25 +72,37 @@ extern "C" { + #endif + + #include + #include + + /* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). + But we can find it either under the correct ANSI name, or under GNU + C's internal name. */ ++ ++#define FFI_64_BIT_MAX 9223372036854775807 ++ + #ifdef LONG_LONG_MAX + # define FFI_LONG_LONG_MAX LONG_LONG_MAX + #else + # ifdef LLONG_MAX + # define FFI_LONG_LONG_MAX LLONG_MAX + # else + # ifdef __GNUC__ + # define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ + # endif ++# ifdef _AIX ++# ifndef __PPC64__ ++# if defined (__IBMC__) || defined (__IBMCPP__) ++# define FFI_LONG_LONG_MAX LONGLONG_MAX ++# endif ++# endif /* __PPC64__ */ ++# undef FFI_64_BIT_MAX ++# define FFI_64_BIT_MAX 9223372036854775807LL ++# endif + # endif + #endif + + /* The closure code assumes that this works on pointers, i.e. a size_t */ + /* can hold a pointer. */ + + typedef struct _ffi_type + { +@@ -127,27 +139,27 @@ typedef struct _ffi_type + #elif INT_MAX == 9223372036854775807 + # define ffi_type_uint ffi_type_uint64 + # define ffi_type_sint ffi_type_sint64 + #else + #error "int size not supported" + #endif + + #if LONG_MAX == 2147483647 +-# if FFI_LONG_LONG_MAX != 9223372036854775807 ++# if FFI_LONG_LONG_MAX != FFI_64_BIT_MAX + #error "no 64-bit data type supported" + # endif +-#elif LONG_MAX != 9223372036854775807 ++#elif LONG_MAX != FFI_64_BIT_MAX + #error "long size not supported" + #endif + + #if LONG_MAX == 2147483647 + # define ffi_type_ulong ffi_type_uint32 + # define ffi_type_slong ffi_type_sint32 +-#elif LONG_MAX == 9223372036854775807 ++#elif LONG_MAX == FFI_64_BIT_MAX + # define ffi_type_ulong ffi_type_uint64 + # define ffi_type_slong ffi_type_sint64 + #else + #error "long size not supported" + #endif + + /* These are defined in types.c */ + extern ffi_type ffi_type_void; +@@ -190,17 +202,17 @@ typedef struct { + #endif + } ffi_cif; + + /* ---- Definitions for the raw API -------------------------------------- */ + + #ifndef FFI_SIZEOF_ARG + # if LONG_MAX == 2147483647 + # define FFI_SIZEOF_ARG 4 +-# elif LONG_MAX == 9223372036854775807 ++# elif LONG_MAX == FFI_64_BIT_MAX + # define FFI_SIZEOF_ARG 8 + # endif + #endif + + #ifndef FFI_SIZEOF_JAVA_RAW + # define FFI_SIZEOF_JAVA_RAW FFI_SIZEOF_ARG + #endif + diff --git a/js/src/ctypes/libffi/ChangeLog b/js/src/ctypes/libffi/ChangeLog new file mode 100644 index 0000000..5768c10 --- /dev/null +++ b/js/src/ctypes/libffi/ChangeLog @@ -0,0 +1,4259 @@ +2010-08-05 Dan Witte + + * Makefile.am: Pass FFI_DEBUG define to msvcc.sh for linking to the + debug CRT when --enable-debug is given. + * configure.ac: Define it. + * msvcc.sh: Translate -g and -DFFI_DEBUG appropriately. + +2010-08-04 Dan Witte + + * src/x86/ffitarget.h: Add X86_ANY define for all x86/x86_64 + platforms. + * src/x86/ffi.c: Remove redundant ifdef checks. + * src/prep_cif.c: Push stack space computation into src/x86/ffi.c + for X86_ANY so return value space doesn't get added twice. + +2010-08-03 Neil Rashbrooke + + * msvcc.sh: Don't pass -safeseh to ml64 because behavior is buggy. + +2010-07-22 Dan Witte + + * src/*/ffitarget.h: Make FFI_LAST_ABI one past the last valid ABI. + * src/prep_cif.c: Fix ABI assertion. + * src/cris/ffi.c: Ditto. + +2010-07-10 Evan Phoenix + + * src/closures.c (selinux_enabled_check): Fix strncmp usage bug. + +2010-07-07 Dan Horák + + * include/ffi.h.in: Protect #define with #ifndef. + * src/powerpc/ffitarget.h: Ditto. + * src/s390/ffitarget.h: Ditto. + * src/sparc/ffitarget.h: Ditto. + +2010-05-11 Dan Witte + + * doc/libffi.tex: Document previous change. + +2010-05-11 Makoto Kato + + * src/x86/ffi.c (ffi_call): Don't copy structs passed by value. + +2010-05-05 Michael Kohler + + * src/dlmalloc.c (dlfree): Fix spelling. + * src/ia64/ffi.c (ffi_prep_cif_machdep): Ditto. + * configure.ac: Ditto. + * configure: Rebuilt. + +2010-04-13 Dan Witte + + * msvcc.sh: Build with -W3 instead of -Wall. + * src/powerpc/ffi_darwin.c: Remove build warnings. + * src/x86/ffi.c: Ditto. + * src/x86/ffitarget.h: Ditto. + +2010-03-30 Dan Witte + + * msvcc.sh: Disable build warnings. + * README (tested): Clarify windows build procedure. + +2010-03-14 Matthias Klose + + * src/x86/ffi64.c: Fix typo in comment. + * src/x86/ffi.c: Use /* ... */ comment style. + +2010-07-07 Neil Roberts + + * src/x86/sysv.S (ffi_call_SYSV): Align the stack pointer to + 16-bytes. + +2010-07-02 Jakub Jelinek + + * Makefile.am (AM_MAKEFLAGS): Pass also mandir to submakes. + * Makefile.in: Regenerated. + +2010-05-19 Rainer Orth + + * configure.ac (libffi_cv_as_x86_pcrel): Check for illegal in as + output, too. + (libffi_cv_as_ascii_pseudo_op): Check for .ascii. + (libffi_cv_as_string_pseudo_op): Check for .string. + * configure: Regenerate. + * fficonfig.h.in: Regenerate. + * src/x86/sysv.S (.eh_frame): Use .ascii, .string or error. + +2010-04-07 Jakub Jelinek + + * regex.c (byte_re_match_2_internal): Avoid set but not used + warning. + +2010-04-02 Ralf Wildenhues + + * Makefile.in: Regenerate. + * aclocal.m4: Regenerate. + * include/Makefile.in: Regenerate. + * man/Makefile.in: Regenerate. + * testsuite/Makefile.in: Regenerate. + +2010-03-15 Rainer Orth + + * configure.ac (libffi_cv_as_x86_64_unwind_section_type): New test. + * configure: Regenerate. + * fficonfig.h.in: Regenerate. + * libffi/src/x86/unix64.S (.eh_frame) + [HAVE_AS_X86_64_UNWIND_SECTION_TYPE]: Use @unwind section type. + +2010-02-24 Rainer Orth + + * doc/libffi.texi (The Closure API): Fix typo. + * doc/libffi.info: Remove. + +2010-02-15 Matthias Klose + + * src/arm/sysv.S (__ARM_ARCH__): Define for processor + __ARM_ARCH_7EM__. + +2010-01-07 Rainer Orth + + PR libffi/40701 + * testsuite/libffi.call/ffitest.h [__alpha__ && __osf__] (PRIdLL, + PRIuLL, PRId64, PRIu64, PRIuPTR): Define. + * testsuite/libffi.call/cls_align_sint64.c: Add -Wno-format on + alpha*-dec-osf*. + * testsuite/libffi.call/cls_align_uint64.c: Likewise. + * testsuite/libffi.call/cls_ulonglong.c: Likewise. + * testsuite/libffi.call/return_ll1.c: Likewise. + * testsuite/libffi.call/stret_medium2.c: Likewise. + * testsuite/libffi.special/ffitestcxx.h (allocate_mmap): Cast + MAP_FAILED to char *. + +2010-01-06 Rainer Orth + + * src/mips/n32.S: Use .abicalls and .eh_frame with __GNUC__. + +2009-12-31 Anthony Green + + * README: Update for libffi 3.0.9. + +2009-12-27 Matthias Klose + + * configure.ac (HAVE_LONG_DOUBLE): Define for mips when + appropriate. + * configure: Rebuilt. + +2009-12-26 Anthony Green + + * testsuite/libffi.call/cls_longdouble_va.c: Mark as xfail for + avr32*-*-*. + * testsuite/libffi.call/cls_double_va.c: Ditto. + +2009-12-26 Andreas Tobler + + * testsuite/libffi.call/ffitest.h: Conditionally include stdint.h + and inttypes.h. + * testsuite/libffi.special/unwindtest.cc: Ditto. + +2009-12-26 Andreas Tobler + + * configure.ac: Add amd64-*-openbsd*. + * configure: Rebuilt. + * testsuite/lib/libffi-dg.exp (libffi_target_compile): Link + openbsd programs with -lpthread. + +2009-12-26 Anthony Green + + * testsuite/libffi.call/cls_double_va.c, + testsuite/libffi.call/cls_longdouble.c, + testsuite/libffi.call/cls_longdouble_va.c, + testsuite/libffi.call/cls_pointer.c, + testsuite/libffi.call/cls_pointer_stack.c: Remove xfail for + mips*-*-* and arm*-*-*. + * testsuite/libffi.call/cls_align_longdouble_split.c, + testsuite/libffi.call/cls_align_longdouble_split2.c, + testsuite/libffi.call/stret_medium2.c, + testsuite/libffi.call/stret_medium.c, + testsuite/libffi.call/stret_large.c, + testsuite/libffi.call/stret_large2.c: Remove xfail for arm*-*-*. + +2009-12-31 Kay Tietz + + * testsuite/libffi.call/ffitest.h, + testsuite/libffi.special/ffitestcxx.h (PRIdLL, PRuLL): Fix + definitions. + +2009-12-31 Carlo Bramini + + * configure.ac (AM_LTLDFLAGS): Define for windows hosts. + * Makefile.am (libffi_la_LDFLAGS): Add AM_LTLDFLAGS. + * configure: Rebuilt. + * Makefile.in: Rebuilt. + +2009-12-31 Anthony Green + Blake Chaffin. + + * testsuite/libffi.call/huge_struct.c: New test case from Blake + Chaffin @ Apple. + +2009-12-28 David Edelsohn + + * src/powerpc/ffi_darwin.c (ffi_prep_args): Copy abi and nargs to + local variables. + (aix_adjust_aggregate_sizes): New function. + (ffi_prep_cif_machdep): Call it. + +2009-12-26 Andreas Tobler + + * configure.ac: Define FFI_MMAP_EXEC_WRIT for the given targets. + * configure: Regenerate. + * fficonfig.h.in: Likewise. + * src/closures.c: Remove the FFI_MMAP_EXEC_WRIT definition for + Solaris/x86. + +2009-12-26 Andreas Schwab + + * src/powerpc/ffi.c (ffi_prep_args_SYSV): Advance intarg_count + when a float arguments is passed in memory. + (ffi_closure_helper_SYSV): Mark general registers as used up when + a 64bit or soft-float long double argument is passed in memory. + +2009-12-25 Matthias Klose + + * man/ffi_call.3: Fix #include in examples. + * doc/libffi.texi: Add dircategory. + +2009-12-25 Frank Everdij + + * include/ffi.h.in: Placed '__GNUC__' ifdef around + '__attribute__((aligned(8)))' in ffi_closure, fixes compile for + IRIX MIPSPro c99. + * include/ffi_common.h: Added '__sgi' define to non + '__attribute__((__mode__()))' integer typedefs. + * src/mips/ffi.c (ffi_call, ffi_closure_mips_inner_O32, + ffi_closure_mips_inner_N32): Added 'defined(_MIPSEB)' to BE check. + (ffi_closure_mips_inner_O32, ffi_closure_mips_inner_N32): Added + FFI_LONGDOUBLE support and alignment(N32 only). + * src/mips/ffitarget.h: Corrected '#include ' for IRIX and + fixed non '__attribute__((__mode__()))' integer typedefs. + * src/mips/n32.S: Put '#ifdef linux' around '.abicalls' and '.eh_frame' + since they are Linux/GNU Assembler specific. + +2009-12-25 Bradley Smith + + * configure.ac, Makefile.am, src/avr32/ffi.c, + src/avr32/ffitarget.h, + src/avr32/sysv.S: Add AVR32 port. + * configure, Makefile.in: Rebuilt. + +2009-12-21 Andreas Tobler + + * configure.ac: Make i?86 build on FreeBSD and OpenBSD. + * configure: Regenerate. + +2009-12-15 John David Anglin + + * testsuite/libffi.call/ffitest.h: Define PRIuPTR on PA HP-UX. + +2009-12-13 John David Anglin + + * src/pa/ffi.c (ffi_closure_inner_pa32): Handle FFI_TYPE_LONGDOUBLE + type on HP-UX. + +2009-12-11 Eric Botcazou + + * src/sparc/ffi.c (ffi_closure_sparc_inner_v9): Properly align 'long + double' arguments. + +2009-12-11 Eric Botcazou + + * testsuite/libffi.call/ffitest.h: Define PRIuPTR on Solaris < 10. + +2009-12-10 Rainer Orth + + PR libffi/40700 + * src/closures.c [X86_64 && __sun__ && __svr4__] + (FFI_MMAP_EXEC_WRIT): Define. + +2009-12-08 David Daney + + * testsuite/libffi.call/stret_medium.c: Remove xfail for mips*-*-* + * testsuite/libffi.call/cls_align_longdouble_split2.c: Same. + * testsuite/libffi.call/stret_large.c: Same. + * testsuite/libffi.call/cls_align_longdouble_split.c: Same. + * testsuite/libffi.call/stret_large2.c: Same. + * testsuite/libffi.call/stret_medium2.c: Same. + +2009-12-07 David Edelsohn + + * src/powerpc/aix_closure.S (libffi_closure_ASM): Fix tablejump + typo. + +2009-12-05 David Edelsohn + + * src/powerpc/aix.S: Update AIX32 code to be consistent with AIX64 + code. + * src/powerpc/aix_closure.S: Same. + +2009-12-05 Ralf Wildenhues + + * Makefile.in: Regenerate. + * configure: Regenerate. + * include/Makefile.in: Regenerate. + * man/Makefile.in: Regenerate. + * testsuite/Makefile.in: Regenerate. + +2009-12-04 David Edelsohn + + * src/powerpc/aix_closure.S: Reorganize 64-bit code to match + linux64_closure.S. + +2009-12-04 Uros Bizjak + + PR libffi/41908 + * src/x86/ffi64.c (classify_argument): Update from + gcc/config/i386/i386.c. + (ffi_closure_unix64_inner): Do not use the address of two consecutive + SSE registers directly. + * testsuite/libffi.call/cls_dbls_struct.c (main): Remove xfail + for x86_64 linux targets. + +2009-12-04 David Edelsohn + + * src/powerpc/ffi_darwin.c (ffi_closure_helper_DARWIN): Increment + pfr for long double split between fpr13 and stack. + +2009-12-03 David Edelsohn + + * src/powerpc/ffi_darwin.c (ffi_prep_args): Increment next_arg and + fparg_count twice for long double. + +2009-12-03 David Edelsohn + + PR libffi/42243 + * src/powerpc/ffi_darwin.c (ffi_prep_args): Remove extra parentheses. + +2009-12-03 Uros Bizjak + + * testsuite/libffi.call/cls_longdouble_va.c (main): Fix format string. + Remove xfails for x86 linux targets. + +2009-12-02 David Edelsohn + + * src/powerpc/ffi_darwin.c (ffi_prep_args): Fix typo in INT64 + case. + +2009-12-01 David Edelsohn + + * src/powerpc/aix.S (ffi_call_AIX): Convert to more standard + register usage. Call ffi_prep_args directly. Add long double + return value support. + * src/powerpc/ffi_darwin.c (ffi_prep_args): Double arg increment + applies to FFI_TYPE_DOUBLE. Correct fpr_base increment typo. + Separate FFI_TYPE_SINT32 and FFI_TYPE_UINT32 cases. + (ffi_prep_cif_machdep): Only 16 byte stack alignment in 64 bit + mode. + (ffi_closure_helper_DARWIN): Remove nf and ng counters. Move temp + into case. + * src/powerpc/aix_closure.S: Maintain 16 byte stack alignment. + Allocate result area between params and FPRs. + +2009-11-30 David Edelsohn + + PR target/35484 + * src/powerpc/ffitarget.h (POWERPC64): Define for PPC64 Linux and + AIX64. + * src/powerpc/aix.S: Implement AIX64 version. + * src/powerpc/aix_closure.S: Implement AIX64 version. + (ffi_closure_ASM): Use extsb, lha and displament addresses. + * src/powerpc/ffi_darwin.c (ffi_prep_args): Implement AIX64 + support. + (ffi_prep_cif_machdep): Same. + (ffi_call): Same. + (ffi_closure_helper_DARWIN): Same. + +2009-11-02 Andreas Tobler + + PR libffi/41908 + * testsuite/libffi.call/testclosure.c: New test. + +2009-09-28 Kai Tietz + + * src/x86/win64.S (_ffi_call_win64 stack): Remove for gnu + assembly version use of ___chkstk. + +2009-09-23 Matthias Klose + + PR libffi/40242, PR libffi/41443 + * src/arm/sysv.S (__ARM_ARCH__): Define for processors + __ARM_ARCH_6T2__, __ARM_ARCH_6M__, __ARM_ARCH_7__, + __ARM_ARCH_7A__, __ARM_ARCH_7R__, __ARM_ARCH_7M__. + Change the conditionals to __SOFTFP__ || __ARM_EABI__ + for -mfloat-abi=softfp to work. + +2009-09-17 Loren J. Rittle + + PR testsuite/32843 (strikes again) + * src/x86/ffi.c (ffi_prep_cif_machdep): Add X86_FREEBSD to + enable proper extension on char and short. + +2009-09-15 David Daney + + * src/java_raw_api.c (ffi_java_raw_to_rvalue): Remove special + handling for FFI_TYPE_POINTER. + * src/mips/ffitarget.h (FFI_TYPE_STRUCT_D_SOFT, + FFI_TYPE_STRUCT_F_SOFT, FFI_TYPE_STRUCT_DD_SOFT, + FFI_TYPE_STRUCT_FF_SOFT, FFI_TYPE_STRUCT_FD_SOFT, + FFI_TYPE_STRUCT_DF_SOFT, FFI_TYPE_STRUCT_SOFT): New defines. + (FFI_N32_SOFT_FLOAT, FFI_N64_SOFT_FLOAT): New ffi_abi enumerations. + (enum ffi_abi): Set FFI_DEFAULT_ABI for soft-float. + * src/mips/n32.S (ffi_call_N32): Add handling for soft-float + structure and pointer returns. + (ffi_closure_N32): Add handling for pointer returns. + * src/mips/ffi.c (ffi_prep_args, calc_n32_struct_flags, + calc_n32_return_struct_flags): Handle soft-float. + (ffi_prep_cif_machdep): Handle soft-float, fix pointer handling. + (ffi_call_N32): Declare proper argument types. + (ffi_call, copy_struct_N32, ffi_closure_mips_inner_N32): Handle + soft-float. + +2009-08-24 Ralf Wildenhues + + * configure.ac (AC_PREREQ): Bump to 2.64. + +2009-08-22 Ralf Wildenhues + + * Makefile.am (install-html, install-pdf): Remove. + * Makefile.in: Regenerate. + + * Makefile.in: Regenerate. + * aclocal.m4: Regenerate. + * configure: Regenerate. + * fficonfig.h.in: Regenerate. + * include/Makefile.in: Regenerate. + * man/Makefile.in: Regenerate. + * testsuite/Makefile.in: Regenerate. + +2009-07-30 Ralf Wildenhues + + * configure.ac (_AC_ARG_VAR_PRECIOUS): Use m4_rename_force. + +2009-07-24 Dave Korn + + PR libffi/40807 + * src/x86/ffi.c (ffi_prep_cif_machdep): Also use sign/zero-extending + return types for X86_WIN32. + * src/x86/win32.S (_ffi_call_SYSV): Handle omitted return types. + (_ffi_call_STDCALL, _ffi_closure_SYSV, _ffi_closure_raw_SYSV, + _ffi_closure_STDCALL): Likewise. + + * src/closures.c (is_selinux_enabled): Define to const 0 for Cygwin. + (dlmmap, dlmunmap): Also use these functions on Cygwin. + +2009-07-11 Richard Sandiford + + PR testsuite/40699 + PR testsuite/40707 + PR testsuite/40709 + * testsuite/lib/libffi-dg.exp: Revert 2009-07-02, 2009-07-01 and + 2009-06-30 commits. + +2009-07-01 Richard Sandiford + + * testsuite/lib/libffi-dg.exp (libffi-init): Set ld_library_path + to "" before adding paths. (This reinstates an assignment that + was removed by my 2009-06-30 commit, but changes the initial + value from "." to "".) + +2009-07-01 H.J. Lu + + PR testsuite/40601 + * testsuite/lib/libffi-dg.exp (libffi-init): Properly set + gccdir. Adjust ld_library_path for gcc only if gccdir isn't + empty. + +2009-06-30 Richard Sandiford + + * testsuite/lib/libffi-dg.exp (libffi-init): Don't add "." + to ld_library_path. Use add_path. Add just find_libgcc_s + to ld_library_path, not every libgcc multilib directory. + +2009-06-16 Wim Lewis + + * src/powerpc/ffi.c: Avoid clobbering cr3 and cr4, which are + supposed to be callee-saved. + * src/powerpc/sysv.S (small_struct_return_value): Fix overrun of + return buffer for odd-size structs. + +2009-06-16 Andreas Tobler + + PR libffi/40444 + * testsuite/lib/libffi-dg.exp (libffi_target_compile): Add + allow_stack_execute for Darwin. + +2009-06-16 Andrew Haley + + * configure.ac (TARGETDIR): Add missing blank lines. + * configure: Regenerate. + +2009-06-16 Andrew Haley + + * testsuite/libffi.call/cls_align_sint64.c, + testsuite/libffi.call/cls_align_uint64.c, + testsuite/libffi.call/cls_longdouble_va.c, + testsuite/libffi.call/cls_ulonglong.c, + testsuite/libffi.call/return_ll1.c, + testsuite/libffi.call/stret_medium2.c: Fix printf format + specifiers. + * testsuite/libffi.call/ffitest.h, + testsuite/libffi.special/ffitestcxx.h (PRIdLL, PRIuLL): Define. + +2009-06-15 Andrew Haley + + * testsuite/libffi.call/err_bad_typedef.c: xfail everywhere. + * testsuite/libffi.call/err_bad_abi.c: Likewise. + +2009-06-12 Andrew Haley + + * Makefile.am: Remove info_TEXINFOS. + +2009-06-12 Andrew Haley + + * ChangeLog.libffi: testsuite/libffi.call/cls_align_sint64.c, + testsuite/libffi.call/cls_align_uint64.c, + testsuite/libffi.call/cls_ulonglong.c, + testsuite/libffi.call/return_ll1.c, + testsuite/libffi.call/stret_medium2.c: Fix printf format + specifiers. + testsuite/libffi.special/unwindtest.cc: include stdint.h. + +2009-06-11 Timothy Wall + + * Makefile.am, + configure.ac, + include/ffi.h.in, + include/ffi_common.h, + src/closures.c, + src/dlmalloc.c, + src/x86/ffi.c, + src/x86/ffitarget.h, + src/x86/win64.S (new), + README: Added win64 support (mingw or MSVC) + * Makefile.in, + include/Makefile.in, + man/Makefile.in, + testsuite/Makefile.in, + configure, + aclocal.m4: Regenerated + * ltcf-c.sh: properly escape cygwin/w32 path + * man/ffi_call.3: Clarify size requirements for return value. + * src/x86/ffi64.c: Fix filename in comment. + * src/x86/win32.S: Remove unused extern. + + * testsuite/libffi.call/closure_fn0.c, + testsuite/libffi.call/closure_fn1.c, + testsuite/libffi.call/closure_fn2.c, + testsuite/libffi.call/closure_fn3.c, + testsuite/libffi.call/closure_fn4.c, + testsuite/libffi.call/closure_fn5.c, + testsuite/libffi.call/closure_fn6.c, + testsuite/libffi.call/closure_stdcall.c, + testsuite/libffi.call/cls_12byte.c, + testsuite/libffi.call/cls_16byte.c, + testsuite/libffi.call/cls_18byte.c, + testsuite/libffi.call/cls_19byte.c, + testsuite/libffi.call/cls_1_1byte.c, + testsuite/libffi.call/cls_20byte.c, + testsuite/libffi.call/cls_20byte1.c, + testsuite/libffi.call/cls_24byte.c, + testsuite/libffi.call/cls_2byte.c, + testsuite/libffi.call/cls_3_1byte.c, + testsuite/libffi.call/cls_3byte1.c, + testsuite/libffi.call/cls_3byte2.c, + testsuite/libffi.call/cls_4_1byte.c, + testsuite/libffi.call/cls_4byte.c, + testsuite/libffi.call/cls_5_1_byte.c, + testsuite/libffi.call/cls_5byte.c, + testsuite/libffi.call/cls_64byte.c, + testsuite/libffi.call/cls_6_1_byte.c, + testsuite/libffi.call/cls_6byte.c, + testsuite/libffi.call/cls_7_1_byte.c, + testsuite/libffi.call/cls_7byte.c, + testsuite/libffi.call/cls_8byte.c, + testsuite/libffi.call/cls_9byte1.c, + testsuite/libffi.call/cls_9byte2.c, + testsuite/libffi.call/cls_align_double.c, + testsuite/libffi.call/cls_align_float.c, + testsuite/libffi.call/cls_align_longdouble.c, + testsuite/libffi.call/cls_align_longdouble_split.c, + testsuite/libffi.call/cls_align_longdouble_split2.c, + testsuite/libffi.call/cls_align_pointer.c, + testsuite/libffi.call/cls_align_sint16.c, + testsuite/libffi.call/cls_align_sint32.c, + testsuite/libffi.call/cls_align_sint64.c, + testsuite/libffi.call/cls_align_uint16.c, + testsuite/libffi.call/cls_align_uint32.c, + testsuite/libffi.call/cls_align_uint64.c, + testsuite/libffi.call/cls_dbls_struct.c, + testsuite/libffi.call/cls_double.c, + testsuite/libffi.call/cls_double_va.c, + testsuite/libffi.call/cls_float.c, + testsuite/libffi.call/cls_longdouble.c, + testsuite/libffi.call/cls_longdouble_va.c, + testsuite/libffi.call/cls_multi_schar.c, + testsuite/libffi.call/cls_multi_sshort.c, + testsuite/libffi.call/cls_multi_sshortchar.c, + testsuite/libffi.call/cls_multi_uchar.c, + testsuite/libffi.call/cls_multi_ushort.c, + testsuite/libffi.call/cls_multi_ushortchar.c, + testsuite/libffi.call/cls_pointer.c, + testsuite/libffi.call/cls_pointer_stack.c, + testsuite/libffi.call/cls_schar.c, + testsuite/libffi.call/cls_sint.c, + testsuite/libffi.call/cls_sshort.c, + testsuite/libffi.call/cls_uchar.c, + testsuite/libffi.call/cls_uint.c, + testsuite/libffi.call/cls_ulonglong.c, + testsuite/libffi.call/cls_ushort.c, + testsuite/libffi.call/err_bad_abi.c, + testsuite/libffi.call/err_bad_typedef.c, + testsuite/libffi.call/float2.c, + testsuite/libffi.call/huge_struct.c, + testsuite/libffi.call/nested_struct.c, + testsuite/libffi.call/nested_struct1.c, + testsuite/libffi.call/nested_struct10.c, + testsuite/libffi.call/nested_struct2.c, + testsuite/libffi.call/nested_struct3.c, + testsuite/libffi.call/nested_struct4.c, + testsuite/libffi.call/nested_struct5.c, + testsuite/libffi.call/nested_struct6.c, + testsuite/libffi.call/nested_struct7.c, + testsuite/libffi.call/nested_struct8.c, + testsuite/libffi.call/nested_struct9.c, + testsuite/libffi.call/problem1.c, + testsuite/libffi.call/return_ldl.c, + testsuite/libffi.call/return_ll1.c, + testsuite/libffi.call/stret_large.c, + testsuite/libffi.call/stret_large2.c, + testsuite/libffi.call/stret_medium.c, + testsuite/libffi.call/stret_medium2.c, + testsuite/libffi.special/unwindtest.cc: use ffi_closure_alloc instead + of checking for MMAP. Use intptr_t instead of long casts. + +2009-06-11 Kaz Kojima + + * testsuite/libffi.call/cls_longdouble_va.c: Add xfail sh*-*-linux-*. + * testsuite/libffi.call/err_bad_abi.c: Add xfail sh*-*-*. + * testsuite/libffi.call/err_bad_typedef.c: Likewise. + +2009-06-09 Andrew Haley + + * src/x86/freebsd.S: Add missing file. + +2009-06-08 Andrew Haley + + Import from libffi 3.0.8: + + * doc/libffi.texi: New file. + * doc/libffi.info: Likewise. + * doc/stamp-vti: Likewise. + * man/Makefile.am: New file. + * man/ffi_call.3: New file. + + * Makefile.am (EXTRA_DIST): Add src/x86/darwin64.S, + src/dlmalloc.c. + (nodist_libffi_la_SOURCES): Add X86_FREEBSD. + + * configure.ac: Bump version to 3.0.8. + parisc*-*-linux*: Add. + i386-*-freebsd* | i386-*-openbsd*: Add. + powerpc-*-beos*: Add. + AM_CONDITIONAL X86_FREEBSD: Add. + AC_CONFIG_FILES: Add man/Makefile. + + * include/ffi.h.in (FFI_FN): Change void (*)() to void (*)(void). + +2009-06-08 Andrew Haley + + * README: Import from libffi 3.0.8. + +2009-06-08 Andrew Haley + + * testsuite/libffi.call/err_bad_abi.c: Add xfails. + * testsuite/libffi.call/cls_longdouble_va.c: Add xfails. + * testsuite/libffi.call/cls_dbls_struct.c: Add xfail x86_64-*-linux-*. + * testsuite/libffi.call/err_bad_typedef.c: Add xfails. + + * testsuite/libffi.call/stret_medium2.c: Add __UNUSED__ to args. + * testsuite/libffi.call/stret_medium.c: Likewise. + * testsuite/libffi.call/stret_large2.c: Likewise. + * testsuite/libffi.call/stret_large.c: Likewise. + +2008-12-26 Timothy Wall + + * testsuite/libffi.call/cls_longdouble.c, + testsuite/libffi.call/cls_longdouble_va.c, + testsuite/libffi.call/cls_align_longdouble.c, + testsuite/libffi.call/cls_align_longdouble_split.c, + testsuite/libffi.call/cls_align_longdouble_split2.c: mark expected + failures on x86_64 cygwin/mingw. + +2008-12-22 Timothy Wall + + * testsuite/libffi.call/closure_fn0.c, + testsuite/libffi.call/closure_fn1.c, + testsuite/libffi.call/closure_fn2.c, + testsuite/libffi.call/closure_fn3.c, + testsuite/libffi.call/closure_fn4.c, + testsuite/libffi.call/closure_fn5.c, + testsuite/libffi.call/closure_fn6.c, + testsuite/libffi.call/closure_loc_fn0.c, + testsuite/libffi.call/closure_stdcall.c, + testsuite/libffi.call/cls_align_pointer.c, + testsuite/libffi.call/cls_pointer.c, + testsuite/libffi.call/cls_pointer_stack.c: use portable cast from + pointer to integer (intptr_t). + * testsuite/libffi.call/cls_longdouble.c: disable for win64. + +2008-07-24 Anthony Green + + * testsuite/libffi.call/cls_dbls_struct.c, + testsuite/libffi.call/cls_double_va.c, + testsuite/libffi.call/cls_longdouble.c, + testsuite/libffi.call/cls_longdouble_va.c, + testsuite/libffi.call/cls_pointer.c, + testsuite/libffi.call/cls_pointer_stack.c, + testsuite/libffi.call/err_bad_abi.c: Clean up failures from + compiler warnings. + +2008-03-04 Anthony Green + Blake Chaffin + hos@tamanegi.org + + * testsuite/libffi.call/cls_align_longdouble_split2.c + testsuite/libffi.call/cls_align_longdouble_split.c + testsuite/libffi.call/cls_dbls_struct.c + testsuite/libffi.call/cls_double_va.c + testsuite/libffi.call/cls_longdouble.c + testsuite/libffi.call/cls_longdouble_va.c + testsuite/libffi.call/cls_pointer.c + testsuite/libffi.call/cls_pointer_stack.c + testsuite/libffi.call/err_bad_abi.c + testsuite/libffi.call/err_bad_typedef.c + testsuite/libffi.call/stret_large2.c + testsuite/libffi.call/stret_large.c + testsuite/libffi.call/stret_medium2.c + testsuite/libffi.call/stret_medium.c: New tests from Apple. + +2009-06-05 Andrew Haley + + * src/x86/ffitarget.h, src/x86/ffi.c: Merge stdcall changes from + libffi. + +2009-06-04 Andrew Haley + + * src/x86/ffitarget.h, src/x86/win32.S, src/x86/ffi.c: Back out + stdcall changes. + +2008-02-26 Anthony Green + Thomas Heller + + * src/x86/ffi.c (ffi_closure_SYSV_inner): Change C++ comment to C + comment. + +2008-02-03 Timothy Wall + + * src/x86/ffi.c (FFI_INIT_TRAMPOLINE_STDCALL): Calculate jump return + offset based on code pointer, not data pointer. + +2008-01-31 Timothy Wall + + * testsuite/libffi.call/closure_stdcall.c: Add test for stdcall + closures. + * src/x86/ffitarget.h: Increase size of trampoline for stdcall + closures. + * src/x86/win32.S: Add assembly for stdcall closure. + * src/x86/ffi.c: Initialize stdcall closure trampoline. + +2009-06-04 Andrew Haley + + * include/ffi.h.in: Change void (*)() to void (*)(void). + * src/x86/ffi.c: Likewise. + +2009-06-04 Andrew Haley + + * src/powerpc/ppc_closure.S: Insert licence header. + * src/powerpc/linux64_closure.S: Likewise. + * src/m68k/sysv.S: Likewise. + + * src/sh64/ffi.c: Change void (*)() to void (*)(void). + * src/powerpc/ffi.c: Likewise. + * src/powerpc/ffi_darwin.c: Likewise. + * src/m32r/ffi.c: Likewise. + * src/sh64/ffi.c: Likewise. + * src/x86/ffi64.c: Likewise. + * src/alpha/ffi.c: Likewise. + * src/alpha/osf.S: Likewise. + * src/frv/ffi.c: Likewise. + * src/s390/ffi.c: Likewise. + * src/pa/ffi.c: Likewise. + * src/pa/hpux32.S: Likewise. + * src/ia64/unix.S: Likewise. + * src/ia64/ffi.c: Likewise. + * src/sparc/ffi.c: Likewise. + * src/mips/ffi.c: Likewise. + * src/sh/ffi.c: Likewise. + +2008-02-15 David Daney + + * src/mips/ffi.c (USE__BUILTIN___CLEAR_CACHE): + Define (conditionally), and use it to include cachectl.h. + (ffi_prep_closure_loc): Fix cache flushing. + * src/mips/ffitarget.h (_ABIN32, _ABI64, _ABIO32): Define. + +2009-06-04 Andrew Haley + + include/ffi.h.in, + src/arm/ffitarget.h, + src/arm/ffi.c, + src/arm/sysv.S, + src/powerpc/ffitarget.h, + src/closures.c, + src/sh64/ffitarget.h, + src/sh64/ffi.c, + src/sh64/sysv.S, + src/types.c, + src/x86/ffi64.c, + src/x86/ffitarget.h, + src/x86/win32.S, + src/x86/darwin.S, + src/x86/ffi.c, + src/x86/sysv.S, + src/x86/unix64.S, + src/alpha/ffitarget.h, + src/alpha/ffi.c, + src/alpha/osf.S, + src/m68k/ffitarget.h, + src/frv/ffitarget.h, + src/frv/ffi.c, + src/s390/ffitarget.h, + src/s390/sysv.S, + src/cris/ffitarget.h, + src/pa/linux.S, + src/pa/ffitarget.h, + src/pa/ffi.c, + src/raw_api.c, + src/ia64/ffitarget.h, + src/ia64/unix.S, + src/ia64/ffi.c, + src/ia64/ia64_flags.h, + src/java_raw_api.c, + src/debug.c, + src/sparc/v9.S, + src/sparc/ffitarget.h, + src/sparc/ffi.c, + src/sparc/v8.S, + src/mips/ffitarget.h, + src/mips/n32.S, + src/mips/o32.S, + src/mips/ffi.c, + src/prep_cif.c, + src/sh/ffitarget.h, + src/sh/ffi.c, + src/sh/sysv.S: Update license text. + +2009-05-22 Dave Korn + + * src/x86/win32.S (_ffi_closure_STDCALL): New function. + (.eh_frame): Add FDE for it. + +2009-05-22 Dave Korn + + * configure.ac: Also check if assembler supports pc-relative + relocs on X86_WIN32 targets. + * configure: Regenerate. + * src/x86/win32.S (ffi_prep_args): Declare extern, not global. + (_ffi_call_SYSV): Add missing function type symbol .def and + add EH markup labels. + (_ffi_call_STDCALL): Likewise. + (_ffi_closure_SYSV): Likewise. + (_ffi_closure_raw_SYSV): Likewise. + (.eh_frame): Add hand-crafted EH data. + +2009-04-09 Jakub Jelinek + + * testsuite/lib/libffi-dg.exp: Change copyright header to refer to + version 3 of the GNU General Public License and to point readers + at the COPYING3 file and the FSF's license web page. + * testsuite/libffi.call/call.exp: Likewise. + * testsuite/libffi.special/special.exp: Likewise. + +2009-03-01 Ralf Wildenhues + + * configure: Regenerate. + +2008-12-18 Rainer Orth + + PR libffi/26048 + * configure.ac (HAVE_AS_X86_PCREL): New test. + * configure: Regenerate. + * fficonfig.h.in: Regenerate. + * src/x86/sysv.S [!FFI_NO_RAW_API]: Precalculate + RAW_CLOSURE_CIF_OFFSET, RAW_CLOSURE_FUN_OFFSET, + RAW_CLOSURE_USER_DATA_OFFSET for the Solaris 10/x86 assembler. + (.eh_frame): Only use SYMBOL-. iff HAVE_AS_X86_PCREL. + * src/x86/unix64.S (.Lstore_table): Move to .text section. + (.Lload_table): Likewise. + (.eh_frame): Only use SYMBOL-. iff HAVE_AS_X86_PCREL. + +2008-12-18 Ralf Wildenhues + + * configure: Regenerate. + +2008-11-21 Eric Botcazou + + * src/sparc/ffi.c (ffi_prep_cif_machdep): Add support for + signed/unsigned int8/16 return values. + * src/sparc/v8.S (ffi_call_v8): Likewise. + (ffi_closure_v8): Likewise. + +2008-09-26 Peter O'Gorman + Steve Ellcey + + * configure: Regenerate for new libtool. + * Makefile.in: Ditto. + * include/Makefile.in: Ditto. + * aclocal.m4: Ditto. + +2008-08-25 Andreas Tobler + + * src/powerpc/ffitarget.h (ffi_abi): Add FFI_LINUX and + FFI_LINUX_SOFT_FLOAT to the POWERPC_FREEBSD enum. + Add note about flag bits used for FFI_SYSV_TYPE_SMALL_STRUCT. + Adjust copyright notice. + * src/powerpc/ffi.c: Add two new flags to indicate if we have one + register or two register to use for FFI_SYSV structs. + (ffi_prep_cif_machdep): Pass the right register flag introduced above. + (ffi_closure_helper_SYSV): Fix the return type for + FFI_SYSV_TYPE_SMALL_STRUCT. Comment. + Adjust copyright notice. + +2008-07-16 Kaz Kojima + + * src/sh/ffi.c (ffi_prep_closure_loc): Turn INSN into an unsigned + int. + +2008-06-17 Ralf Wildenhues + + * configure: Regenerate. + * include/Makefile.in: Regenerate. + * testsuite/Makefile.in: Regenerate. + +2008-06-07 Joseph Myers + + * configure.ac (parisc*-*-linux*, powerpc-*-sysv*, + powerpc-*-beos*): Remove. + * configure: Regenerate. + +2008-05-09 Julian Brown + + * Makefile.am (LTLDFLAGS): New. + (libffi_la_LDFLAGS): Use above. + * Makefile.in: Regenerate. + +2008-04-18 Paolo Bonzini + + PR bootstrap/35457 + * aclocal.m4: Regenerate. + * configure: Regenerate. + +2008-03-26 Kaz Kojima + + * src/sh/sysv.S: Add .note.GNU-stack on Linux. + * src/sh64/sysv.S: Likewise. + +2008-03-26 Daniel Jacobowitz + + * src/arm/sysv.S: Fix ARM comment marker. + +2008-03-26 Jakub Jelinek + + * src/alpha/osf.S: Add .note.GNU-stack on Linux. + * src/s390/sysv.S: Likewise. + * src/powerpc/ppc_closure.S: Likewise. + * src/powerpc/sysv.S: Likewise. + * src/x86/unix64.S: Likewise. + * src/x86/sysv.S: Likewise. + * src/sparc/v8.S: Likewise. + * src/sparc/v9.S: Likewise. + * src/m68k/sysv.S: Likewise. + * src/arm/sysv.S: Likewise. + +2008-03-16 Ralf Wildenhues + + * aclocal.m4: Regenerate. + * configure: Likewise. + * Makefile.in: Likewise. + * include/Makefile.in: Likewise. + * testsuite/Makefile.in: Likewise. + +2008-02-12 Bjoern Koenig + Andreas Tobler + + * configure.ac: Add amd64-*-freebsd* target. + * configure: Regenerate. + +2008-01-30 H.J. Lu + + PR libffi/34612 + * src/x86/sysv.S (ffi_closure_SYSV): Pop 4 byte from stack when + returning struct. + + * testsuite/libffi.call/call.exp: Add "-O2 -fomit-frame-pointer" + tests. + +2008-01-24 David Edelsohn + + * configure: Regenerate. + +2008-01-06 Andreas Tobler + + * src/x86/ffi.c (ffi_prep_cif_machdep): Fix thinko. + +2008-01-05 Andreas Tobler + + PR testsuite/32843 + * src/x86/ffi.c (ffi_prep_cif_machdep): Add code for + signed/unsigned int8/16 for X86_DARWIN. + Updated copyright info. + Handle one and two byte structs with special cif->flags. + * src/x86/ffitarget.h: Add special types for one and two byte structs. + Updated copyright info. + * src/x86/darwin.S (ffi_call_SYSV): Rewrite to use a jump table like + sysv.S + Remove code to pop args from the stack after call. + Special-case signed/unsigned for int8/16, one and two byte structs. + (ffi_closure_raw_SYSV): Handle FFI_TYPE_UINT8, + FFI_TYPE_SINT8, FFI_TYPE_UINT16, FFI_TYPE_SINT16, FFI_TYPE_UINT32, + FFI_TYPE_SINT32. + Updated copyright info. + +2007-12-08 David Daney + + * src/mips/n32.S (ffi_call_N32): Replace dadd with ADDU, dsub with + SUBU, add with ADDU and use smaller code sequences. + +2007-12-07 David Daney + + * src/mips/ffi.c (ffi_prep_cif_machdep): Handle long double return + type. + +2007-12-06 David Daney + + * include/ffi.h.in (FFI_SIZEOF_JAVA_RAW): Define if not already + defined. + (ffi_java_raw): New typedef. + (ffi_java_raw_call, ffi_java_ptrarray_to_raw, + ffi_java_raw_to_ptrarray): Change parameter types from ffi_raw to + ffi_java_raw. + (ffi_java_raw_closure) : Same. + (ffi_prep_java_raw_closure, ffi_prep_java_raw_closure_loc): Change + parameter types. + * src/java_raw_api.c (ffi_java_raw_size): Replace FFI_SIZEOF_ARG with + FFI_SIZEOF_JAVA_RAW. + (ffi_java_raw_to_ptrarray): Change type of raw to ffi_java_raw. + Replace FFI_SIZEOF_ARG with FFI_SIZEOF_JAVA_RAW. Use + sizeof(ffi_java_raw) for alignment calculations. + (ffi_java_ptrarray_to_raw): Same. + (ffi_java_rvalue_to_raw): Add special handling for FFI_TYPE_POINTER + if FFI_SIZEOF_JAVA_RAW == 4. + (ffi_java_raw_to_rvalue): Same. + (ffi_java_raw_call): Change type of raw to ffi_java_raw. + (ffi_java_translate_args): Same. + (ffi_prep_java_raw_closure_loc, ffi_prep_java_raw_closure): Change + parameter types. + * src/mips/ffitarget.h (FFI_SIZEOF_JAVA_RAW): Define for N32 ABI. + +2007-12-06 David Daney + + * src/mips/n32.S (ffi_closure_N32): Use 64-bit add instruction on + pointer values. + +2007-12-01 Andreas Tobler + + PR libffi/31937 + * src/powerpc/ffitarget.h: Introduce new ABI FFI_LINUX_SOFT_FLOAT. + Add local FFI_TYPE_UINT128 to handle soft-float long-double-128. + * src/powerpc/ffi.c: Distinguish between __NO_FPRS__ and not and + set the NUM_FPR_ARG_REGISTERS according to. + Add support for potential soft-float support under hard-float + architecture. + (ffi_prep_args_SYSV): Set NUM_FPR_ARG_REGISTERS to 0 in case of + FFI_LINUX_SOFT_FLOAT, handle float, doubles and long-doubles according + to the FFI_LINUX_SOFT_FLOAT ABI. + (ffi_prep_cif_machdep): Likewise. + (ffi_closure_helper_SYSV): Likewise. + * src/powerpc/ppc_closure.S: Make sure not to store float/double + on archs where __NO_FPRS__ is true. + Add FFI_TYPE_UINT128 support. + * src/powerpc/sysv.S: Add support for soft-float long-double-128. + Adjust copyright notice. + +2007-11-25 Andreas Tobler + + * src/closures.c: Move defintion of MAYBE_UNUSED from here to ... + * include/ffi_common.h: ... here. + Update copyright. + +2007-11-17 Andreas Tobler + + * src/powerpc/sysv.S: Load correct cr to compare if we have long double. + * src/powerpc/linux64.S: Likewise. + * src/powerpc/ffi.c: Add a comment to show which part goes into cr6. + * testsuite/libffi.call/return_ldl.c: New test. + +2007-09-04 + + * src/arm/sysv.S (UNWIND): New. + (Whole file): Conditionally compile unwinder directives. + * src/arm/sysv.S: Add unwinder directives. + + * src/arm/ffi.c (ffi_prep_args): Align structs by at least 4 bytes. + Only treat r0 as a struct address if we're actually returning a + struct by address. + Only copy the bytes that are actually within a struct. + (ffi_prep_cif_machdep): A Composite Type not larger than 4 bytes + is returned in r0, not passed by address. + (ffi_call): Allocate a word-sized temporary for the case where + a composite is returned in r0. + (ffi_prep_incoming_args_SYSV): Align as necessary. + +2007-08-05 Steven Newbury + + * src/arm/ffi.c (FFI_INIT_TRAMPOLINE): Use __clear_cache instead of + directly using the sys_cacheflush syscall. + +2007-07-27 Andrew Haley + + * src/arm/sysv.S (ffi_closure_SYSV): Add soft-float. + +2007-09-03 Maciej W. Rozycki + + * Makefile.am: Unify MIPS_IRIX and MIPS_LINUX into MIPS. + * configure.ac: Likewise. + * Makefile.in: Regenerate. + * include/Makefile.in: Likewise. + * testsuite/Makefile.in: Likewise. + * configure: Likewise. + +2007-08-24 David Daney + + * testsuite/libffi.call/return_sl.c: New test. + +2007-08-10 David Daney + + * testsuite/libffi.call/cls_multi_ushort.c, + testsuite/libffi.call/cls_align_uint16.c, + testsuite/libffi.call/nested_struct1.c, + testsuite/libffi.call/nested_struct3.c, + testsuite/libffi.call/cls_7_1_byte.c, + testsuite/libffi.call/nested_struct5.c, + testsuite/libffi.call/cls_double.c, + testsuite/libffi.call/nested_struct7.c, + testsuite/libffi.call/cls_sint.c, + testsuite/libffi.call/nested_struct9.c, + testsuite/libffi.call/cls_20byte1.c, + testsuite/libffi.call/cls_multi_sshortchar.c, + testsuite/libffi.call/cls_align_sint64.c, + testsuite/libffi.call/cls_3byte2.c, + testsuite/libffi.call/cls_multi_schar.c, + testsuite/libffi.call/cls_multi_uchar.c, + testsuite/libffi.call/cls_19byte.c, + testsuite/libffi.call/cls_9byte1.c, + testsuite/libffi.call/cls_align_float.c, + testsuite/libffi.call/closure_fn1.c, + testsuite/libffi.call/problem1.c, + testsuite/libffi.call/closure_fn3.c, + testsuite/libffi.call/cls_sshort.c, + testsuite/libffi.call/closure_fn5.c, + testsuite/libffi.call/cls_align_double.c, + testsuite/libffi.call/nested_struct.c, + testsuite/libffi.call/cls_2byte.c, + testsuite/libffi.call/nested_struct10.c, + testsuite/libffi.call/cls_4byte.c, + testsuite/libffi.call/cls_6byte.c, + testsuite/libffi.call/cls_8byte.c, + testsuite/libffi.call/cls_multi_sshort.c, + testsuite/libffi.call/cls_align_sint16.c, + testsuite/libffi.call/cls_align_uint32.c, + testsuite/libffi.call/cls_20byte.c, + testsuite/libffi.call/cls_float.c, + testsuite/libffi.call/nested_struct2.c, + testsuite/libffi.call/cls_5_1_byte.c, + testsuite/libffi.call/nested_struct4.c, + testsuite/libffi.call/cls_24byte.c, + testsuite/libffi.call/nested_struct6.c, + testsuite/libffi.call/cls_64byte.c, + testsuite/libffi.call/nested_struct8.c, + testsuite/libffi.call/cls_uint.c, + testsuite/libffi.call/cls_multi_ushortchar.c, + testsuite/libffi.call/cls_schar.c, + testsuite/libffi.call/cls_uchar.c, + testsuite/libffi.call/cls_align_uint64.c, + testsuite/libffi.call/cls_ulonglong.c, + testsuite/libffi.call/cls_align_longdouble.c, + testsuite/libffi.call/cls_1_1byte.c, + testsuite/libffi.call/cls_12byte.c, + testsuite/libffi.call/cls_3_1byte.c, + testsuite/libffi.call/cls_3byte1.c, + testsuite/libffi.call/cls_4_1byte.c, + testsuite/libffi.call/cls_6_1_byte.c, + testsuite/libffi.call/cls_16byte.c, + testsuite/libffi.call/cls_18byte.c, + testsuite/libffi.call/closure_fn0.c, + testsuite/libffi.call/cls_9byte2.c, + testsuite/libffi.call/closure_fn2.c, + testsuite/libffi.call/closure_fn4.c, + testsuite/libffi.call/cls_ushort.c, + testsuite/libffi.call/closure_fn6.c, + testsuite/libffi.call/cls_5byte.c, + testsuite/libffi.call/cls_align_pointer.c, + testsuite/libffi.call/cls_7byte.c, + testsuite/libffi.call/cls_align_sint32.c, + testsuite/libffi.special/unwindtest_ffi_call.cc, + testsuite/libffi.special/unwindtest.cc: Remove xfail for mips64*-*-*. + +2007-08-10 David Daney + + PR libffi/28313 + * configure.ac: Don't treat mips64 as a special case. + * Makefile.am (nodist_libffi_la_SOURCES): Add n32.S. + * configure: Regenerate + * Makefile.in: Ditto. + * fficonfig.h.in: Ditto. + * src/mips/ffitarget.h (REG_L, REG_S, SUBU, ADDU, SRL, LI): Indent. + (LA, EH_FRAME_ALIGN, FDE_ADDR_BYTES): New preprocessor macros. + (FFI_DEFAULT_ABI): Set for n64 case. + (FFI_CLOSURES, FFI_TRAMPOLINE_SIZE): Define for n32 and n64 cases. + * src/mips/n32.S (ffi_call_N32): Add debug macros and labels for FDE. + (ffi_closure_N32): New function. + (.eh_frame): New section + * src/mips/o32.S: Clean up comments. + (ffi_closure_O32): Pass ffi_closure parameter in $12. + * src/mips/ffi.c: Use FFI_MIPS_N32 instead of + _MIPS_SIM == _ABIN32 throughout. + (FFI_MIPS_STOP_HERE): New, use in place of + ffi_stop_here. + (ffi_prep_args): Use unsigned long to hold pointer values. Rewrite + to support n32/n64 ABIs. + (calc_n32_struct_flags): Rewrite. + (calc_n32_return_struct_flags): Remove unused variable. Reverse + position of flag bits. + (ffi_prep_cif_machdep): Rewrite n32 portion. + (ffi_call): Enable for n64. Add special handling for small structure + return values. + (ffi_prep_closure_loc): Add n32 and n64 support. + (ffi_closure_mips_inner_O32): Add cast to silence warning. + (copy_struct_N32, ffi_closure_mips_inner_N32): New functions. + +2007-08-08 David Daney + + * testsuite/libffi.call/ffitest.h (ffi_type_mylong): Remove definition. + * testsuite/libffi.call/cls_align_uint16.c (main): Use correct type + specifiers. + * testsuite/libffi.call/nested_struct1.c (main): Ditto. + * testsuite/libffi.call/cls_sint.c (main): Ditto. + * testsuite/libffi.call/nested_struct9.c (main): Ditto. + * testsuite/libffi.call/cls_20byte1.c (main): Ditto. + * testsuite/libffi.call/cls_9byte1.c (main): Ditto. + * testsuite/libffi.call/closure_fn1.c (main): Ditto. + * testsuite/libffi.call/closure_fn3.c (main): Ditto. + * testsuite/libffi.call/return_dbl2.c (main): Ditto. + * testsuite/libffi.call/cls_sshort.c (main): Ditto. + * testsuite/libffi.call/return_fl3.c (main): Ditto. + * testsuite/libffi.call/closure_fn5.c (main): Ditto. + * testsuite/libffi.call/nested_struct.c (main): Ditto. + * testsuite/libffi.call/nested_struct10.c (main): Ditto. + * testsuite/libffi.call/return_ll1.c (main): Ditto. + * testsuite/libffi.call/cls_8byte.c (main): Ditto. + * testsuite/libffi.call/cls_align_uint32.c (main): Ditto. + * testsuite/libffi.call/cls_align_sint16.c (main): Ditto. + * testsuite/libffi.call/cls_20byte.c (main): Ditto. + * testsuite/libffi.call/nested_struct2.c (main): Ditto. + * testsuite/libffi.call/cls_24byte.c (main): Ditto. + * testsuite/libffi.call/nested_struct6.c (main): Ditto. + * testsuite/libffi.call/cls_uint.c (main): Ditto. + * testsuite/libffi.call/cls_12byte.c (main): Ditto. + * testsuite/libffi.call/cls_16byte.c (main): Ditto. + * testsuite/libffi.call/closure_fn0.c (main): Ditto. + * testsuite/libffi.call/cls_9byte2.c (main): Ditto. + * testsuite/libffi.call/closure_fn2.c (main): Ditto. + * testsuite/libffi.call/return_dbl1.c (main): Ditto. + * testsuite/libffi.call/closure_fn4.c (main): Ditto. + * testsuite/libffi.call/closure_fn6.c (main): Ditto. + * testsuite/libffi.call/cls_align_sint32.c (main): Ditto. + +2007-08-07 Andrew Haley + + * src/x86/sysv.S (ffi_closure_raw_SYSV): Fix typo in previous + checkin. + +2007-08-06 Andrew Haley + + PR testsuite/32843 + * src/x86/sysv.S (ffi_closure_raw_SYSV): Handle FFI_TYPE_UINT8, + FFI_TYPE_SINT8, FFI_TYPE_UINT16, FFI_TYPE_SINT16, FFI_TYPE_UINT32, + FFI_TYPE_SINT32. + +2007-08-02 David Daney + + * testsuite/libffi.call/return_ul.c (main): Define return type as + ffi_arg. Use proper printf conversion specifier. + +2007-07-30 Andrew Haley + + PR testsuite/32843 + * src/x86/ffi.c (ffi_prep_cif_machdep): in x86 case, add code for + signed/unsigned int8/16. + * src/x86/sysv.S (ffi_call_SYSV): Rewrite to: + Use a jump table. + Remove code to pop args from the stack after call. + Special-case signed/unsigned int8/16. + * testsuite/libffi.call/return_sc.c (main): Revert. + +2007-07-26 Richard Guenther + + PR testsuite/32843 + * testsuite/libffi.call/return_sc.c (main): Verify call + result as signed char, not ffi_arg. + +2007-07-16 Rainer Orth + + * configure.ac (i?86-*-solaris2.1[0-9]): Set TARGET to X86_64. + * configure: Regenerate. + +2007-07-11 David Daney + + * src/mips/ffi.c: Don't include sys/cachectl.h. + (ffi_prep_closure_loc): Use __builtin___clear_cache() instead of + cacheflush(). + +2007-05-18 Aurelien Jarno + + * src/arm/ffi.c (ffi_prep_closure_loc): Renamed and ajusted + from (ffi_prep_closure): ... this. + (FFI_INIT_TRAMPOLINE): Adjust. + +2005-12-31 Phil Blundell + + * src/arm/ffi.c (ffi_prep_incoming_args_SYSV, + ffi_closure_SYSV_inner, ffi_prep_closure): New, add closure support. + * src/arm/sysv.S(ffi_closure_SYSV): Likewise. + * src/arm/ffitarget.h (FFI_TRAMPOLINE_SIZE): Likewise. + (FFI_CLOSURES): Enable closure support. + +2007-07-03 Andrew Haley + + * testsuite/libffi.call/cls_multi_ushort.c, + testsuite/libffi.call/cls_align_uint16.c, + testsuite/libffi.call/nested_struct1.c, + testsuite/libffi.call/nested_struct3.c, + testsuite/libffi.call/cls_7_1_byte.c, + testsuite/libffi.call/cls_double.c, + testsuite/libffi.call/nested_struct5.c, + testsuite/libffi.call/nested_struct7.c, + testsuite/libffi.call/cls_sint.c, + testsuite/libffi.call/nested_struct9.c, + testsuite/libffi.call/cls_20byte1.c, + testsuite/libffi.call/cls_multi_sshortchar.c, + testsuite/libffi.call/cls_align_sint64.c, + testsuite/libffi.call/cls_3byte2.c, + testsuite/libffi.call/cls_multi_schar.c, + testsuite/libffi.call/cls_multi_uchar.c, + testsuite/libffi.call/cls_19byte.c, + testsuite/libffi.call/cls_9byte1.c, + testsuite/libffi.call/cls_align_float.c, + testsuite/libffi.call/closure_fn1.c, + testsuite/libffi.call/problem1.c, + testsuite/libffi.call/closure_fn3.c, + testsuite/libffi.call/cls_sshort.c, + testsuite/libffi.call/closure_fn5.c, + testsuite/libffi.call/cls_align_double.c, + testsuite/libffi.call/cls_2byte.c, + testsuite/libffi.call/nested_struct.c, + testsuite/libffi.call/nested_struct10.c, + testsuite/libffi.call/cls_4byte.c, + testsuite/libffi.call/cls_6byte.c, + testsuite/libffi.call/cls_8byte.c, + testsuite/libffi.call/cls_multi_sshort.c, + testsuite/libffi.call/cls_align_uint32.c, + testsuite/libffi.call/cls_align_sint16.c, + testsuite/libffi.call/cls_float.c, + testsuite/libffi.call/cls_20byte.c, + testsuite/libffi.call/cls_5_1_byte.c, + testsuite/libffi.call/nested_struct2.c, + testsuite/libffi.call/cls_24byte.c, + testsuite/libffi.call/nested_struct4.c, + testsuite/libffi.call/nested_struct6.c, + testsuite/libffi.call/cls_64byte.c, + testsuite/libffi.call/nested_struct8.c, + testsuite/libffi.call/cls_uint.c, + testsuite/libffi.call/cls_multi_ushortchar.c, + testsuite/libffi.call/cls_schar.c, + testsuite/libffi.call/cls_uchar.c, + testsuite/libffi.call/cls_align_uint64.c, + testsuite/libffi.call/cls_ulonglong.c, + testsuite/libffi.call/cls_align_longdouble.c, + testsuite/libffi.call/cls_1_1byte.c, + testsuite/libffi.call/cls_12byte.c, + testsuite/libffi.call/cls_3_1byte.c, + testsuite/libffi.call/cls_3byte1.c, + testsuite/libffi.call/cls_4_1byte.c, + testsuite/libffi.call/cls_6_1_byte.c, + testsuite/libffi.call/cls_16byte.c, + testsuite/libffi.call/cls_18byte.c, + testsuite/libffi.call/closure_fn0.c, + testsuite/libffi.call/cls_9byte2.c, + testsuite/libffi.call/closure_fn2.c, + testsuite/libffi.call/closure_fn4.c, + testsuite/libffi.call/cls_ushort.c, + testsuite/libffi.call/closure_fn6.c, + testsuite/libffi.call/cls_5byte.c, + testsuite/libffi.call/cls_align_pointer.c, + testsuite/libffi.call/cls_7byte.c, + testsuite/libffi.call/cls_align_sint32.c, + testsuite/libffi.special/unwindtest_ffi_call.cc, + testsuite/libffi.special/unwindtest.cc: Enable for ARM. + +2007-07-05 H.J. Lu + + * aclocal.m4: Regenerated. + +2007-06-02 Paolo Bonzini + + * configure: Regenerate. + +2007-05-23 Steve Ellcey + + * Makefile.in: Regenerate. + * configure: Regenerate. + * aclocal.m4: Regenerate. + * include/Makefile.in: Regenerate. + * testsuite/Makefile.in: Regenerate. + +2007-05-10 Roman Zippel + + * src/m68k/ffi.c (ffi_prep_incoming_args_SYSV, + ffi_closure_SYSV_inner,ffi_prep_closure): New, add closure support. + * src/m68k/sysv.S(ffi_closure_SYSV,ffi_closure_struct_SYSV): Likewise. + * src/m68k/ffitarget.h (FFI_TRAMPOLINE_SIZE): Likewise. + (FFI_CLOSURES): Enable closure support. + +2007-05-10 Roman Zippel + + * configure.ac (HAVE_AS_CFI_PSEUDO_OP): New test. + * configure: Regenerate. + * fficonfig.h.in: Regenerate. + * src/m68k/sysv.S (CFI_STARTPROC,CFI_ENDPROC, + CFI_OFFSET,CFI_DEF_CFA): New macros. + (ffi_call_SYSV): Add callframe annotation. + +2007-05-10 Roman Zippel + + * src/m68k/ffi.c (ffi_prep_args,ffi_prep_cif_machdep): Fix + numerous test suite failures. + * src/m68k/sysv.S (ffi_call_SYSV): Likewise. + +2007-04-11 Paolo Bonzini + + * Makefile.am (EXTRA_DIST): Bring up to date. + * Makefile.in: Regenerate. + * src/frv/eabi.S: Remove RCS keyword. + +2007-04-06 Richard Henderson + + * configure.ac: Tidy target case. + (HAVE_LONG_DOUBLE): Allow the target to override. + * configure: Regenerate. + * include/ffi.h.in: Don't define ffi_type_foo if + LIBFFI_HIDE_BASIC_TYPES is defined. + (ffi_type_longdouble): If not HAVE_LONG_DOUBLE, define + to ffi_type_double. + * types.c (LIBFFI_HIDE_BASIC_TYPES): Define. + (FFI_TYPEDEF, ffi_type_void): Mark the data const. + (ffi_type_longdouble): Special case for Alpha. Don't define + if long double == double. + + * src/alpha/ffi.c (FFI_TYPE_LONGDOUBLE): Assert unique value. + (ffi_prep_cif_machdep): Handle it as the 128-bit type. + (ffi_call, ffi_closure_osf_inner): Likewise. + (ffi_closure_osf_inner): Likewise. Mark hidden. + (ffi_call_osf, ffi_closure_osf): Mark hidden. + * src/alpha/ffitarget.h (FFI_LAST_ABI): Tidy definition. + * src/alpha/osf.S (ffi_call_osf, ffi_closure_osf): Mark hidden. + (load_table): Handle 128-bit long double. + + * testsuite/libffi.call/float4.c: Add -mieee for alpha. + +2007-04-06 Tom Tromey + + PR libffi/31491: + * README: Fixed bug in example. + +2007-04-03 Jakub Jelinek + + * src/closures.c: Include sys/statfs.h. + (_GNU_SOURCE): Define on Linux. + (FFI_MMAP_EXEC_SELINUX): Define. + (selinux_enabled): New variable. + (selinux_enabled_check): New function. + (is_selinux_enabled): Define. + (dlmmap): Use it. + +2007-03-24 Uros Bizjak + + * testsuite/libffi.call/return_fl2.c (return_fl): Mark as static. + Use 'volatile float sum' to create sum of floats to avoid false + negative due to excess precision on ix86 targets. + (main): Ditto. + +2007-03-08 Alexandre Oliva + + * src/powerpc/ffi.c (flush_icache): Fix left-over from previous + patch. + (ffi_prep_closure_loc): Remove unneeded casts. Add needed ones. + +2007-03-07 Alexandre Oliva + + * include/ffi.h.in (ffi_closure_alloc, ffi_closure_free): New. + (ffi_prep_closure_loc): New. + (ffi_prep_raw_closure_loc): New. + (ffi_prep_java_raw_closure_loc): New. + * src/closures.c: New file. + * src/dlmalloc.c [FFI_MMAP_EXEC_WRIT] (struct malloc_segment): + Replace sflags with exec_offset. + [FFI_MMAP_EXEC_WRIT] (mmap_exec_offset, add_segment_exec_offset, + sub_segment_exec_offset): New macros. + (get_segment_flags, set_segment_flags, check_segment_merge): New + macros. + (is_mmapped_segment, is_extern_segment): Use get_segment_flags. + (add_segment, sys_alloc, create_mspace, create_mspace_with_base, + destroy_mspace): Use new macros. + (sys_alloc): Silence warning. + * Makefile.am (libffi_la_SOURCES): Add src/closures.c. + * Makefile.in: Rebuilt. + * src/prep_cif [FFI_CLOSURES] (ffi_prep_closure): Implement in + terms of ffi_prep_closure_loc. + * src/raw_api.c (ffi_prep_raw_closure_loc): Renamed and adjusted + from... + (ffi_prep_raw_closure): ... this. Re-implement in terms of the + renamed version. + * src/java_raw_api (ffi_prep_java_raw_closure_loc): Renamed and + adjusted from... + (ffi_prep_java_raw_closure): ... this. Re-implement in terms of + the renamed version. + * src/alpha/ffi.c (ffi_prep_closure_loc): Renamed from + (ffi_prep_closure): ... this. + * src/pa/ffi.c: Likewise. + * src/cris/ffi.c: Likewise. Adjust. + * src/frv/ffi.c: Likewise. + * src/ia64/ffi.c: Likewise. + * src/mips/ffi.c: Likewise. + * src/powerpc/ffi_darwin.c: Likewise. + * src/s390/ffi.c: Likewise. + * src/sh/ffi.c: Likewise. + * src/sh64/ffi.c: Likewise. + * src/sparc/ffi.c: Likewise. + * src/x86/ffi64.c: Likewise. + * src/x86/ffi.c: Likewise. + (FFI_INIT_TRAMPOLINE): Adjust. + (ffi_prep_raw_closure_loc): Renamed and adjusted from... + (ffi_prep_raw_closure): ... this. + * src/powerpc/ffi.c (ffi_prep_closure_loc): Renamed from + (ffi_prep_closure): ... this. + (flush_icache): Adjust. + +2007-03-07 Alexandre Oliva + + * src/dlmalloc.c: New file, imported version 2.8.3 of Doug + Lea's malloc. + +2007-03-01 Brooks Moses + + * Makefile.am: Add dummy install-pdf target. + * Makefile.in: Regenerate + +2007-02-13 Andreas Krebbel + + * src/s390/ffi.c (ffi_prep_args, ffi_prep_cif_machdep, + ffi_closure_helper_SYSV): Add long double handling. + +2007-02-02 Jakub Jelinek + + * src/powerpc/linux64.S (ffi_call_LINUX64): Move restore of r2 + immediately after bctrl instruction. + +2007-01-18 Alexandre Oliva + + * Makefile.am (all-recursive, install-recursive, + mostlyclean-recursive, clean-recursive, distclean-recursive, + maintainer-clean-recursive): Add missing targets. + * Makefile.in: Rebuilt. + +2006-12-14 Andreas Tobler + + * configure.ac: Add TARGET for x86_64-*-darwin*. + * Makefile.am (nodist_libffi_la_SOURCES): Add rules for 64-bit sources + for X86_DARWIN. + * src/x86/ffitarget.h: Set trampoline size for x86_64-*-darwin*. + * src/x86/darwin64.S: New file for x86_64-*-darwin* support. + * configure: Regenerate. + * Makefile.in: Regenerate. + * include/Makefile.in: Regenerate. + * testsuite/Makefile.in: Regenerate. + * testsuite/libffi.special/unwindtest_ffi_call.cc: New test case for + ffi_call only. + +2006-12-13 Andreas Tobler + + * aclocal.m4: Regenerate with aclocal -I .. as written in the + Makefile.am. + +2006-10-31 Geoffrey Keating + + * src/powerpc/ffi_darwin.c (darwin_adjust_aggregate_sizes): New. + (ffi_prep_cif_machdep): Call darwin_adjust_aggregate_sizes for + Darwin. + * testsuite/libffi.call/nested_struct4.c: Remove Darwin XFAIL. + * testsuite/libffi.call/nested_struct6.c: Remove Darwin XFAIL. + +2006-10-10 Paolo Bonzini + Sandro Tolaini + + * configure.ac [i*86-*-darwin*]: Set X86_DARWIN symbol and + conditional. + * configure: Regenerated. + * Makefile.am (nodist_libffi_la_SOURCES) [X86_DARWIN]: New case. + (EXTRA_DIST): Add src/x86/darwin.S. + * Makefile.in: Regenerated. + * include/Makefile.in: Regenerated. + * testsuite/Makefile.in: Regenerated. + + * src/x86/ffi.c (ffi_prep_cif_machdep) [X86_DARWIN]: Treat like + X86_WIN32, and additionally align stack to 16 bytes. + * src/x86/darwin.S: New, based on sysv.S. + * src/prep_cif.c (ffi_prep_cif) [X86_DARWIN]: Align > 8-byte structs. + +2006-09-12 David Daney + + PR libffi/23935 + * include/Makefile.am: Install both ffi.h and ffitarget.h in + $(libdir)/gcc/$(target_alias)/$(gcc_version)/include. + * aclocal.m4: Regenerated for automake 1.9.6. + * Makefile.in: Regenerated. + * include/Makefile.in: Regenerated. + * testsuite/Makefile.in: Regenerated. + +2006-08-17 Andreas Tobler + + * include/ffi_common.h (struct): Revert accidental commit. + +2006-08-15 Andreas Tobler + + * include/ffi_common.h: Remove lint directives. + * include/ffi.h.in: Likewise. + +2006-07-25 Torsten Schoenfeld + + * include/ffi.h.in (ffi_type_ulong, ffi_type_slong): Define correctly + for 32-bit architectures. + * testsuite/libffi.call/return_ul.c: New test case. + +2006-07-19 David Daney + + * testsuite/libffi.call/closure_fn6.c: Remove xfail for mips, + xfail remains for mips64. + +2006-05-23 Carlos O'Donell + + * Makefile.am: Add install-html target. Add install-html to .PHONY + * Makefile.in: Regenerate. + * aclocal.m4: Regenerate. + * include/Makefile.in: Regenerate. + * testsuite/Makefile.in: Regenerate. + +2006-05-18 John David Anglin + + * pa/ffi.c (ffi_prep_args_pa32): Load floating point arguments from + stack slot. + +2006-04-22 Andreas Tobler + + * README: Remove notice about 'Crazy Comments'. + * src/debug.c: Remove lint directives. Cleanup white spaces. + * src/java_raw_api.c: Likewise. + * src/prep_cif.c: Likewise. + * src/raw_api.c: Likewise. + * src/ffitest.c: Delete. No longer needed, all test cases migrated + to the testsuite. + * src/arm/ffi.c: Remove lint directives. + * src/m32r/ffi.c: Likewise. + * src/pa/ffi.c: Likewise. + * src/powerpc/ffi.c: Likewise. + * src/powerpc/ffi_darwin.c: Likewise. + * src/sh/ffi.c: Likewise. + * src/sh64/ffi.c: Likewise. + * src/x86/ffi.c: Likewise. + * testsuite/libffi.call/float2.c: Likewise. + * testsuite/libffi.call/promotion.c: Likewise. + * testsuite/libffi.call/struct1.c: Likewise. + +2006-04-13 Andreas Tobler + + * src/pa/hpux32.S: Correct unwind offset calculation for + ffi_closure_pa32. + * src/pa/linux.S: Likewise. + +2006-04-12 James E Wilson + + PR libgcj/26483 + * src/ia64/ffi.c (stf_spill, ldf_fill): Rewrite as macros. + (hfa_type_load): Call stf_spill. + (hfa_type_store): Call ldf_fill. + (ffi_call): Adjust calls to above routines. Add local temps for + macro result. + +2006-04-10 Matthias Klose + + * testsuite/lib/libffi-dg.exp (libffi-init): Recognize multilib + directory names containing underscores. + +2006-04-07 James E Wilson + + * testsuite/libffi.call/float4.c: New testcase. + +2006-04-05 John David Anglin + Andreas Tobler + + * Makefile.am: Add PA_HPUX port. + * Makefile.in: Regenerate. + * include/Makefile.in: Likewise. + * testsuite/Makefile.in: Likewise. + * configure.ac: Add PA_HPUX rules. + * configure: Regenerate. + * src/pa/ffitarget.h: Rename linux target to PA_LINUX. + Add PA_HPUX and PA64_HPUX. + Rename FFI_LINUX ABI to FFI_PA32 ABI. + (FFI_TRAMPOLINE_SIZE): Define for 32-bit HP-UX targets. + (FFI_TYPE_SMALL_STRUCT2): Define. + (FFI_TYPE_SMALL_STRUCT4): Likewise. + (FFI_TYPE_SMALL_STRUCT8): Likewise. + (FFI_TYPE_SMALL_STRUCT3): Redefine. + (FFI_TYPE_SMALL_STRUCT5): Likewise. + (FFI_TYPE_SMALL_STRUCT6): Likewise. + (FFI_TYPE_SMALL_STRUCT7): Likewise. + * src/pa/ffi.c (ROUND_DOWN): Delete. + (fldw, fstw, fldd, fstd): Use '__asm__'. + (ffi_struct_type): Add support for FFI_TYPE_SMALL_STRUCT2, + FFI_TYPE_SMALL_STRUCT4 and FFI_TYPE_SMALL_STRUCT8. + (ffi_prep_args_LINUX): Rename to ffi_prep_args_pa32. Update comment. + Simplify incrementing of stack slot variable. Change type of local + 'n' to unsigned int. + (ffi_size_stack_LINUX): Rename to ffi_size_stack_pa32. Handle long + double on PA_HPUX. + (ffi_prep_cif_machdep): Likewise. + (ffi_call): Likewise. + (ffi_closure_inner_LINUX): Rename to ffi_closure_inner_pa32. Change + return type to ffi_status. Simplify incrementing of stack slot + variable. Only copy floating point argument registers when PA_LINUX + is true. Reformat debug statement. + Add support for FFI_TYPE_SMALL_STRUCT2, FFI_TYPE_SMALL_STRUCT4 and + FFI_TYPE_SMALL_STRUCT8. + (ffi_closure_LINUX): Rename to ffi_closure_pa32. Add 'extern' to + declaration. + (ffi_prep_closure): Make linux trampoline conditional on PA_LINUX. + Add nops to cache flush. Add trampoline for PA_HPUX. + * src/pa/hpux32.S: New file. + * src/pa/linux.S (ffi_call_LINUX): Rename to ffi_call_pa32. Rename + ffi_prep_args_LINUX to ffi_prep_args_pa32. + Localize labels. Add support for 2, 4 and 8-byte small structs. Handle + unaligned destinations in 3, 5, 6 and 7-byte small structs. Order + argument type checks so that common argument types appear first. + (ffi_closure_LINUX): Rename to ffi_closure_pa32. Rename + ffi_closure_inner_LINUX to ffi_closure_inner_pa32. + +2006-03-24 Alan Modra + + * src/powerpc/ffitarget.h (enum ffi_abi): Add FFI_LINUX. Default + for 32-bit using IBM extended double format. Fix FFI_LAST_ABI. + * src/powerpc/ffi.c (ffi_prep_args_SYSV): Handle linux variant of + FFI_TYPE_LONGDOUBLE. + (ffi_prep_args64): Assert using IBM extended double. + (ffi_prep_cif_machdep): Don't munge FFI_TYPE_LONGDOUBLE type. + Handle FFI_LINUX FFI_TYPE_LONGDOUBLE return and args. + (ffi_call): Handle FFI_LINUX. + (ffi_closure_helper_SYSV): Non FFI_LINUX long double return needs + gpr3 return pointer as for struct return. Handle FFI_LINUX + FFI_TYPE_LONGDOUBLE return and args. Don't increment "nf" + unnecessarily. + * src/powerpc/ppc_closure.S (ffi_closure_SYSV): Load both f1 and f2 + for FFI_TYPE_LONGDOUBLE. Move epilogue insns into case table. + Don't use r6 as pointer to results, instead use sp offset. Don't + make a special call to load lr with case table address, instead + use offset from previous call. + * src/powerpc/sysv.S (ffi_call_SYSV): Save long double return. + * src/powerpc/linux64.S (ffi_call_LINUX64): Simplify long double + return. + +2006-03-15 Kaz Kojima + + * src/sh64/ffi.c (ffi_prep_cif_machdep): Handle float arguments + passed with FP registers correctly. + (ffi_closure_helper_SYSV): Likewise. + * src/sh64/sysv.S: Likewise. + +2006-03-01 Andreas Tobler + + * testsuite/libffi.special/unwindtest.cc (closure_test_fn): Mark cif, + args and userdata unused. + (closure_test_fn1): Mark cif and userdata unused. + (main): Remove unused res. + +2006-02-28 Andreas Tobler + + * testsuite/libffi.call/call.exp: Adjust FSF address. Add test runs for + -O2, -O3, -Os and the warning flags -W -Wall. + * testsuite/libffi.special/special.exp: Likewise. + * testsuite/libffi.call/ffitest.h: Add an __UNUSED__ macro to mark + unused parameter unused for gcc or else do nothing. + * testsuite/libffi.special/ffitestcxx.h: Likewise. + * testsuite/libffi.call/cls_12byte.c (cls_struct_12byte_gn): Mark cif + and userdata unused. + * testsuite/libffi.call/cls_16byte.c (cls_struct_16byte_gn): Likewise. + * testsuite/libffi.call/cls_18byte.c (cls_struct_18byte_gn): Likewise. + * testsuite/libffi.call/cls_19byte.c (cls_struct_19byte_gn): Likewise. + * testsuite/libffi.call/cls_1_1byte.c (cls_struct_1_1byte_gn): Likewise. + * testsuite/libffi.call/cls_20byte.c (cls_struct_20byte_gn): Likewise. + * testsuite/libffi.call/cls_20byte1.c (cls_struct_20byte_gn): Likewise. + * testsuite/libffi.call/cls_24byte.c (cls_struct_24byte_gn): Likewise. + * testsuite/libffi.call/cls_2byte.c (cls_struct_2byte_gn): Likewise. + * testsuite/libffi.call/cls_3_1byte.c (cls_struct_3_1byte_gn): Likewise. + * testsuite/libffi.call/cls_3byte1.c (cls_struct_3byte_gn): Likewise. + * testsuite/libffi.call/cls_3byte2.c (cls_struct_3byte_gn1): Likewise. + * testsuite/libffi.call/cls_4_1byte.c (cls_struct_4_1byte_gn): Likewise. + * testsuite/libffi.call/cls_4byte.c (cls_struct_4byte_gn): Likewise. + * testsuite/libffi.call/cls_5_1_byte.c (cls_struct_5byte_gn): Likewise. + * testsuite/libffi.call/cls_5byte.c (cls_struct_5byte_gn): Likewise. + * testsuite/libffi.call/cls_64byte.c (cls_struct_64byte_gn): Likewise. + * testsuite/libffi.call/cls_6_1_byte.c (cls_struct_6byte_gn): Likewise. + * testsuite/libffi.call/cls_6byte.c (cls_struct_6byte_gn): Likewise. + * testsuite/libffi.call/cls_7_1_byte.c (cls_struct_7byte_gn): Likewise. + * testsuite/libffi.call/cls_7byte.c (cls_struct_7byte_gn): Likewise. + * testsuite/libffi.call/cls_8byte.c (cls_struct_8byte_gn): Likewise. + * testsuite/libffi.call/cls_9byte1.c (cls_struct_9byte_gn): Likewise. + * testsuite/libffi.call/cls_9byte2.c (cls_struct_9byte_gn): Likewise. + * testsuite/libffi.call/cls_align_double.c (cls_struct_align_gn): + Likewise. + * testsuite/libffi.call/cls_align_float.c (cls_struct_align_gn): + Likewise. + * testsuite/libffi.call/cls_align_longdouble.c (cls_struct_align_gn): + Likewise. + * testsuite/libffi.call/cls_align_pointer.c (cls_struct_align_fn): Cast + void* to avoid compiler warning. + (main): Likewise. + (cls_struct_align_gn): Mark cif and userdata unused. + * testsuite/libffi.call/cls_align_sint16.c (cls_struct_align_gn): + Likewise. + * testsuite/libffi.call/cls_align_sint32.c (cls_struct_align_gn): + Likewise. + * testsuite/libffi.call/cls_align_sint64.c (cls_struct_align_gn): + Likewise. + * testsuite/libffi.call/cls_align_uint16.c (cls_struct_align_gn): + Likewise. + * testsuite/libffi.call/cls_align_uint32.c (cls_struct_align_gn): + Likewise. + * testsuite/libffi.call/cls_double.c (cls_ret_double_fn): Likewise. + * testsuite/libffi.call/cls_float.c (cls_ret_float_fn): Likewise. + * testsuite/libffi.call/cls_multi_schar.c (test_func_gn): Mark cif and + data unused. + (main): Cast res_call to silence gcc. + * testsuite/libffi.call/cls_multi_sshort.c (test_func_gn): Mark cif and + data unused. + (main): Cast res_call to silence gcc. + * testsuite/libffi.call/cls_multi_sshortchar.c (test_func_gn): Mark cif + and data unused. + (main): Cast res_call to silence gcc. + * testsuite/libffi.call/cls_multi_uchar.c (test_func_gn): Mark cif and + data unused. + (main): Cast res_call to silence gcc. + * testsuite/libffi.call/cls_multi_ushort.c (test_func_gn): Mark cif and + data unused. + (main): Cast res_call to silence gcc. + * testsuite/libffi.call/cls_multi_ushortchar.c (test_func_gn): Mark cif + and data unused. + (main): Cast res_call to silence gcc. + * testsuite/libffi.call/cls_schar.c (cls_ret_schar_fn): Mark cif and + userdata unused. + (cls_ret_schar_fn): Cast printf parameter to silence gcc. + * testsuite/libffi.call/cls_sint.c (cls_ret_sint_fn): Mark cif and + userdata unused. + (cls_ret_sint_fn): Cast printf parameter to silence gcc. + * testsuite/libffi.call/cls_sshort.c (cls_ret_sshort_fn): Mark cif and + userdata unused. + (cls_ret_sshort_fn): Cast printf parameter to silence gcc. + * testsuite/libffi.call/cls_uchar.c (cls_ret_uchar_fn): Mark cif and + userdata unused. + (cls_ret_uchar_fn): Cast printf parameter to silence gcc. + * testsuite/libffi.call/cls_uint.c (cls_ret_uint_fn): Mark cif and + userdata unused. + (cls_ret_uint_fn): Cast printf parameter to silence gcc. + * testsuite/libffi.call/cls_ulonglong.c (cls_ret_ulonglong_fn): Mark cif + and userdata unused. + * testsuite/libffi.call/cls_ushort.c (cls_ret_ushort_fn): Mark cif and + userdata unused. + (cls_ret_ushort_fn): Cast printf parameter to silence gcc. + * testsuite/libffi.call/float.c (floating): Remove unused parameter e. + * testsuite/libffi.call/float1.c (main): Remove unused variable i. + Cleanup white spaces. + * testsuite/libffi.call/negint.c (checking): Remove unused variable i. + * testsuite/libffi.call/nested_struct.c (cls_struct_combined_gn): Mark + cif and userdata unused. + * testsuite/libffi.call/nested_struct1.c (cls_struct_combined_gn): + Likewise. + * testsuite/libffi.call/nested_struct10.c (B_gn): Likewise. + * testsuite/libffi.call/nested_struct2.c (B_fn): Adjust printf + formatters to silence gcc. + (B_gn): Mark cif and userdata unused. + * testsuite/libffi.call/nested_struct3.c (B_gn): Mark cif and userdata + unused. + * testsuite/libffi.call/nested_struct4.c: Mention related PR. + (B_gn): Mark cif and userdata unused. + * testsuite/libffi.call/nested_struct5.c (B_gn): Mark cif and userdata + unused. + * testsuite/libffi.call/nested_struct6.c: Mention related PR. + (B_gn): Mark cif and userdata unused. + * testsuite/libffi.call/nested_struct7.c (B_gn): Mark cif and userdata + unused. + * testsuite/libffi.call/nested_struct8.c (B_gn): Likewise. + * testsuite/libffi.call/nested_struct9.c (B_gn): Likewise. + * testsuite/libffi.call/problem1.c (stub): Likewise. + * testsuite/libffi.call/pyobjc-tc.c (main): Cast the result to silence + gcc. + * testsuite/libffi.call/return_fl2.c (return_fl): Add the note mentioned + in the last commit for this test case in the test case itself. + * testsuite/libffi.call/closure_fn0.c (closure_test_fn0): Mark cif as + unused. + * testsuite/libffi.call/closure_fn1.c (closure_test_fn1): Likewise. + * testsuite/libffi.call/closure_fn2.c (closure_test_fn2): Likewise. + * testsuite/libffi.call/closure_fn3.c (closure_test_fn3): Likewise. + * testsuite/libffi.call/closure_fn4.c (closure_test_fn0): Likewise. + * testsuite/libffi.call/closure_fn5.c (closure_test_fn5): Likewise. + * testsuite/libffi.call/closure_fn6.c (closure_test_fn0): Likewise. + +2006-02-22 Kaz Kojima + + * src/sh/sysv.S: Fix register numbers in the FDE for + ffi_closure_SYSV. + +2006-02-20 Andreas Tobler + + * testsuite/libffi.call/return_fl2.c (return_fl): Remove static + declaration to avoid a false negative on ix86. See PR323. + +2006-02-18 Kaz Kojima + + * src/sh/ffi.c (ffi_closure_helper_SYSV): Remove unused variable + and cast integer to void * if needed. Update the pointer to + the FP register saved area correctly. + +2006-02-17 Andreas Tobler + + * testsuite/libffi.call/nested_struct6.c: XFAIL this test until PR25630 + is fixed. + * testsuite/libffi.call/nested_struct4.c: Likewise. + +2006-02-16 Andreas Tobler + + * testsuite/libffi.call/return_dbl.c: New test case. + * testsuite/libffi.call/return_dbl1.c: Likewise. + * testsuite/libffi.call/return_dbl2.c: Likewise. + * testsuite/libffi.call/return_fl.c: Likewise. + * testsuite/libffi.call/return_fl1.c: Likewise. + * testsuite/libffi.call/return_fl2.c: Likewise. + * testsuite/libffi.call/return_fl3.c: Likewise. + * testsuite/libffi.call/closure_fn6.c: Likewise. + + * testsuite/libffi.call/nested_struct2.c: Remove ffi_type_mylong + definition. + * testsuite/libffi.call/ffitest.h: Add ffi_type_mylong definition + here to be used by other test cases too. + + * testsuite/libffi.call/nested_struct10.c: New test case. + * testsuite/libffi.call/nested_struct9.c: Likewise. + * testsuite/libffi.call/nested_struct8.c: Likewise. + * testsuite/libffi.call/nested_struct7.c: Likewise. + * testsuite/libffi.call/nested_struct6.c: Likewise. + * testsuite/libffi.call/nested_struct5.c: Likewise. + * testsuite/libffi.call/nested_struct4.c: Likewise. + +2006-01-21 Andreas Tobler + + * configure.ac: Enable libffi for sparc64-*-freebsd*. + * configure: Rebuilt. + +2006-01-18 Jakub Jelinek + + * src/powerpc/sysv.S (smst_two_register): Don't call __ashldi3, + instead do the shifting inline. + * src/powerpc/ppc_closure.S (ffi_closure_SYSV): Don't compute %r5 + shift count unconditionally. Simplify load sequences for 1, 2, 3, 4 + and 8 byte structs, for the remaining struct sizes don't call + __lshrdi3, instead do the shifting inline. + +2005-12-07 Thiemo Seufer + + * src/mips/ffitarget.h: Remove obsolete sgidefs.h include. Add + missing parentheses. + * src/mips/o32.S (ffi_call_O32): Code formatting. Define + and use A3_OFF, FP_OFF, RA_OFF. Micro-optimizations. + (ffi_closure_O32): Likewise, but with newly defined A3_OFF2, + A2_OFF2, A1_OFF2, A0_OFF2, RA_OFF2, FP_OFF2, S0_OFF2, GP_OFF2, + V1_OFF2, V0_OFF2, FA_1_1_OFF2, FA_1_0_OFF2, FA_0_1_OFF2, + FA_0_0_OFF2. + * src/mips/ffi.c (ffi_prep_args): Code formatting. Fix + endianness bugs. + (ffi_prep_closure): Improve trampoline instruction scheduling. + (ffi_closure_mips_inner_O32): Fix endianness bugs. + +2005-12-03 Alan Modra + + * src/powerpc/ffi.c: Formatting. + (ffi_prep_args_SYSV): Avoid possible aliasing problems by using unions. + (ffi_prep_args64): Likewise. + +2005-09-30 Geoffrey Keating + + * testsuite/lib/libffi-dg.exp (libffi_target_compile): For + darwin, use -shared-libgcc not -lgcc_s, and explain why. + +2005-09-26 Tom Tromey + + * testsuite/libffi.call/float1.c (value_type): New typedef. + (CANARY): New define. + (main): Check for result buffer overflow. + * src/powerpc/linux64.S: Handle linux64 long double returns. + * src/powerpc/ffi.c (FLAG_RETURNS_128BITS): New constant. + (ffi_prep_cif_machdep): Handle linux64 long double returns. + +2005-08-25 Alan Modra + + PR target/23404 + * src/powerpc/ffi.c (ffi_prep_args_SYSV): Correct placement of stack + homed fp args. + (ffi_status ffi_prep_cif_machdep): Correct stack sizing for same. + +2005-08-11 Jakub Jelinek + + * configure.ac (HAVE_HIDDEN_VISIBILITY_ATTRIBUTE): New test. + (AH_BOTTOM): Add FFI_HIDDEN definition. + * configure: Rebuilt. + * fficonfig.h.in: Rebuilt. + * src/powerpc/ffi.c (hidden): Remove. + (ffi_closure_LINUX64, ffi_prep_args64, ffi_call_LINUX64, + ffi_closure_helper_LINUX64): Use FFI_HIDDEN instead of hidden. + * src/powerpc/linux64_closure.S (ffi_closure_LINUX64, + .ffi_closure_LINUX64): Use FFI_HIDDEN instead of .hidden. + * src/x86/ffi.c (ffi_closure_SYSV, ffi_closure_raw_SYSV): Remove, + add FFI_HIDDEN to its prototype. + (ffi_closure_SYSV_inner): New. + * src/x86/sysv.S (ffi_closure_SYSV, ffi_closure_raw_SYSV): New. + * src/x86/win32.S (ffi_closure_SYSV, ffi_closure_raw_SYSV): New. + +2005-08-10 Alfred M. Szmidt + + PR libffi/21819: + * configure: Rebuilt. + * configure.ac: Handle i*86-*-gnu*. + +2005-08-09 Jakub Jelinek + + * src/powerpc/ppc_closure.S (ffi_closure_SYSV): Use + DW_CFA_offset_extended_sf rather than + DW_CFA_GNU_negative_offset_extended. + * src/powerpc/sysv.S (ffi_call_SYSV): Likewise. + +2005-07-22 SUGIOKA Toshinobu + + * src/sh/sysv.S (ffi_call_SYSV): Stop argument popping correctly + on sh3. + (ffi_closure_SYSV): Change the stack layout for sh3 struct argument. + * src/sh/ffi.c (ffi_prep_args): Fix sh3 argument copy, when it is + partially on register. + (ffi_closure_helper_SYSV): Likewise. + (ffi_prep_cif_machdep): Don't set too many cif->flags. + +2005-07-20 Kaz Kojima + + * src/sh/ffi.c (ffi_call): Handle small structures correctly. + Remove empty line. + * src/sh64/ffi.c (simple_type): Remove. + (return_type): Handle small structures correctly. + (ffi_prep_args): Likewise. + (ffi_call): Likewise. + (ffi_closure_helper_SYSV): Likewise. + * src/sh64/sysv.S (ffi_call_SYSV): Handle 1, 2 and 4-byte return. + Emit position independent code if PIC and remove wrong datalabel + prefixes from EH data. + +2005-07-19 Andreas Tobler + + * Makefile.am (nodist_libffi_la_SOURCES): Add POWERPC_FREEBSD. + * Makefile.in: Regenerate. + * include/Makefile.in: Likewise. + * testsuite/Makefile.in: Likewise. + * configure.ac: Add POWERPC_FREEBSD rules. + * configure: Regenerate. + * src/powerpc/ffitarget.h: Add POWERPC_FREEBSD rules. + (FFI_SYSV_TYPE_SMALL_STRUCT): Define. + * src/powerpc/ffi.c: Add flags to handle small structure returns + in ffi_call_SYSV. + (ffi_prep_cif_machdep): Handle small structures for SYSV 4 ABI. + Aka FFI_SYSV. + (ffi_closure_helper_SYSV): Likewise. + * src/powerpc/ppc_closure.S: Add return types for small structures. + * src/powerpc/sysv.S: Add bits to handle small structures for + final SYSV 4 ABI. + +2005-07-10 Andreas Tobler + + * testsuite/libffi.call/cls_5_1_byte.c: New test file. + * testsuite/libffi.call/cls_6_1_byte.c: Likewise. + * testsuite/libffi.call/cls_7_1_byte.c: Likewise. + +2005-07-05 Randolph Chung + + * src/pa/ffi.c (ffi_struct_type): Rename FFI_TYPE_SMALL_STRUCT1 + as FFI_TYPE_SMALL_STRUCT3. Break out handling for 5-7 byte + structures. Kill compilation warnings. + (ffi_closure_inner_LINUX): Print return values as hex in debug + message. Rename FFI_TYPE_SMALL_STRUCT1 as FFI_TYPE_SMALL_STRUCT3. + Properly handle 5-7 byte structure returns. + * src/pa/ffitarget.h (FFI_TYPE_SMALL_STRUCT1) + (FFI_TYPE_SMALL_STRUCT2): Remove. + (FFI_TYPE_SMALL_STRUCT3, FFI_TYPE_SMALL_STRUCT5) + (FFI_TYPE_SMALL_STRUCT6, FFI_TYPE_SMALL_STRUCT7): Define. + * src/pa/linux.S: Mark source file as using PA1.1 assembly. + (checksmst1, checksmst2): Remove. + (checksmst3): Optimize handling of 3-byte struct returns. + (checksmst567): Properly handle 5-7 byte struct returns. + +2005-06-15 Rainer Orth + + PR libgcj/21943 + * src/mips/n32.S: Enforce PIC code. + * src/mips/o32.S: Likewise. + +2005-06-15 Rainer Orth + + * configure.ac: Treat i*86-*-solaris2.10 and up as X86_64. + * configure: Regenerate. + +2005-06-01 Alan Modra + + * src/powerpc/ppc_closure.S (ffi_closure_SYSV): Don't use JUMPTARGET + to call ffi_closure_helper_SYSV. Append @local instead. + * src/powerpc/sysv.S (ffi_call_SYSV): Likewise for ffi_prep_args_SYSV. + +2005-05-17 Kelley Cook + + * configure.ac: Use AC_C_BIGENDIAN instead of AC_C_BIGENDIAN_CROSS. + Use AC_CHECK_SIZEOF instead of AC_COMPILE_CHECK_SIZEOF. + * Makefile.am (ACLOCAL_AMFLAGS): Remove -I ../config. + * aclocal.m4, configure, fficonfig.h.in, Makefile.in, + include/Makefile.in, testsuite/Makefile.in: Regenerate. + +2005-05-09 Mike Stump + + * configure: Regenerate. + +2005-05-08 Richard Henderson + + PR libffi/21285 + * src/alpha/osf.S: Update unwind into to match code. + +2005-05-04 Andreas Degert + Richard Henderson + + * src/x86/ffi64.c (ffi_prep_cif_machdep): Save sse-used flag in + bit 11 of flags. + (ffi_call): Mask return type field. Pass ssecount to ffi_call_unix64. + (ffi_prep_closure): Set carry bit if sse-used flag set. + * src/x86/unix64.S (ffi_call_unix64): Add ssecount argument. + Only load sse registers if ssecount non-zero. + (ffi_closure_unix64): Only save sse registers if carry set on entry. + +2005-04-29 Ralf Corsepius + + * configure.ac: Add i*86-*-rtems*, sparc*-*-rtems*, + powerpc-*rtems*, arm*-*-rtems*, sh-*-rtems*. + * configure: Regenerate. + +2005-04-20 Hans-Peter Nilsson + + * testsuite/lib/libffi-dg.exp (libffi-dg-test-1): In regsub use, + have Tcl8.3-compatible intermediate variable. + +2005-04-18 Simon Posnjak + Hans-Peter Nilsson + + * Makefile.am: Add CRIS support. + * configure.ac: Likewise. + * Makefile.in, configure, testsuite/Makefile.in, + include/Makefile.in: Regenerate. + * src/cris: New directory. + * src/cris/ffi.c, src/cris/sysv.S, src/cris/ffitarget.h: New files. + * src/prep_cif.c (ffi_prep_cif): Wrap in #ifndef __CRIS__. + + * testsuite/lib/libffi-dg.exp (libffi-dg-test-1): Replace \n with + \r?\n in output tests. + +2005-04-12 Mike Stump + + * configure: Regenerate. + +2005-03-30 Hans Boehm + + * src/ia64/ffitarget.h (ffi_arg): Use long long instead of DI. + +2005-03-30 Steve Ellcey + + * src/ia64/ffitarget.h (ffi_arg) ADD DI attribute. + (ffi_sarg) Ditto. + * src/ia64/unix.S (ffi_closure_unix): Extend gp + to 64 bits in ILP32 mode. + Load 64 bits even for short data. + +2005-03-23 Mike Stump + + * src/powerpc/darwin.S: Update for -m64 multilib. + * src/powerpc/darwin_closure.S: Likewise. + +2005-03-21 Zack Weinberg + + * configure.ac: Do not invoke TL_AC_GCC_VERSION. + Do not set tool_include_dir. + * aclocal.m4, configure, Makefile.in, testsuite/Makefile.in: + Regenerate. + * include/Makefile.am: Set gcc_version and toollibffidir. + * include/Makefile.in: Regenerate. + +2005-02-22 Andrew Haley + + * src/powerpc/ffi.c (ffi_prep_cif_machdep): Bump alignment to + odd-numbered register pairs for 64-bit integer types. + +2005-02-23 Andreas Tobler + + PR libffi/20104 + * testsuite/libffi.call/return_ll1.c: New test case. + +2005-02-11 Janis Johnson + + * testsuite/libffi.call/cls_align_longdouble.c: Remove dg-options. + * testsuite/libffi.call/float.c: Ditto. + * testsuite/libffi.call/float2.c: Ditto. + * testsuite/libffi.call/float3.c: Ditto. + +2005-02-08 Andreas Tobler + + * src/frv/ffitarget.h: Remove PPC stuff which does not belong to frv. + +2005-01-12 Eric Botcazou + + * testsuite/libffi.special/special.exp (cxx_options): Add + -shared-libgcc. + +2004-12-31 Richard Henderson + + * src/types.c (FFI_AGGREGATE_TYPEDEF): Remove. + (FFI_TYPEDEF): Rename from FFI_INTEGRAL_TYPEDEF. Replace size and + offset parameters with a type parameter; deduce size and structure + alignment. Update all users. + +2004-12-31 Richard Henderson + + * src/types.c (FFI_TYPE_POINTER): Define with sizeof. + (FFI_TYPE_LONGDOUBLE): Fix for ia64. + * src/ia64/ffitarget.h (struct ffi_ia64_trampoline_struct): Move + into ffi_prep_closure. + * src/ia64/ia64_flags.h, src/ia64/ffi.c, src/ia64/unix.S: Rewrite + from scratch. + +2004-12-27 Richard Henderson + + * src/x86/unix64.S: Fix typo in unwind info. + +2004-12-25 Richard Henderson + + * src/x86/ffi64.c (struct register_args): Rename from stackLayout. + (enum x86_64_reg_class): Add X86_64_COMPLEX_X87_CLASS. + (merge_classes): Check for it. + (SSE_CLASS_P): New. + (classify_argument): Pass byte_offset by value; perform all updates + inside struct case. + (examine_argument): Add classes argument; handle + X86_64_COMPLEX_X87_CLASS. + (ffi_prep_args): Merge into ... + (ffi_call): ... here. Share stack frame with ffi_call_unix64. + (ffi_prep_cif_machdep): Setup cif->flags for proper structure return. + (ffi_fill_return_value): Remove. + (ffi_prep_closure): Remove dead assert. + (ffi_closure_unix64_inner): Rename from ffi_closure_UNIX64_inner. + Rewrite to use struct register_args instead of va_list. Create + flags for handling structure returns. + * src/x86/unix64.S: Remove dead strings. + (ffi_call_unix64): Rename from ffi_call_UNIX64. Rewrite to share + stack frame with ffi_call. Handle structure returns properly. + (float2sse, floatfloat2sse, double2sse): Remove. + (sse2float, sse2double, sse2floatfloat): Remove. + (ffi_closure_unix64): Rename from ffi_closure_UNIX64. Rewrite + to handle structure returns properly. + +2004-12-08 David Edelsohn + + * Makefile.am (AM_MAKEFLAGS): Remove duplicate LIBCFLAGS and + PICFLAG. + * Makefile.in: Regenerated. + +2004-12-02 Richard Sandiford + + * configure.ac: Use TL_AC_GCC_VERSION to set gcc_version. + * configure, aclocal.m4, Makefile.in: Regenerate. + * include/Makefile.in, testsuite/Makefile.in: Regenerate. + +2004-11-29 Kelley Cook + + * configure: Regenerate for libtool change. + +2004-11-25 Kelley Cook + + * configure: Regenerate for libtool reversion. + +2004-11-24 Kelley Cook + + * configure: Regenerate for libtool change. + +2004-11-23 John David Anglin + + * testsuite/lib/libffi-dg.exp: Use new procs in target-libpath.exp. + +2004-11-23 Richard Sandiford + + * src/mips/o32.S (ffi_call_O32, ffi_closure_O32): Use jalr instead + of jal. Use an absolute encoding for the frame information. + +2004-11-23 Kelley Cook + + * Makefile.am: Remove no-dependencies. Add ACLOCAL_AMFLAGS. + * acinclude.m4: Delete logic for sincludes. + * aclocal.m4, Makefile.in, configure: Regenerate. + * include/Makefile: Likewise. + * testsuite/Makefile: Likewise. + +2004-11-22 Eric Botcazou + + * src/sparc/ffi.c (ffi_prep_closure): Align doubles and 64-bit integers + on a 8-byte boundary. + * src/sparc/v8.S (ffi_closure_v8): Reserve frame space for arguments. + +2004-10-27 Richard Earnshaw + + * src/arm/ffi.c (ffi_prep_cif_machdep): Handle functions that return + long long values. Round stack allocation to a multiple of 8 bytes + for ATPCS compatibility. + * src/arm/sysv.S (ffi_call_SYSV): Rework to avoid use of APCS register + names. Handle returning long long types. Add Thumb and interworking + support. Improve soft-float code. + +2004-10-27 Richard Earnshaw + + * testsuite/lib/libffi-db.exp (load_gcc_lib): New function. + (libffi_exit): New function. + (libffi_init): Build the testglue wrapper if needed. + +2004-10-25 Eric Botcazou + + PR other/18138 + * testsuite/lib/libffi-dg.exp: Accept more than one multilib libgcc. + +2004-10-25 Kazuhiro Inaoka + + * src/m32r/libffitarget.h (FFI_CLOSURES): Set to 0. + +2004-10-20 Kaz Kojima + + * src/sh/sysv.S (ffi_call_SYSV): Don't align for double data. + * testsuite/libffi.call/float3.c: New test case. + +2004-10-18 Kaz Kojima + + * src/sh/ffi.c (ffi_prep_closure): Set T bit in trampoline for + the function returning a structure pointed with R2. + * src/sh/sysv.S (ffi_closure_SYSV): Use R2 as the pointer to + the structure return value if T bit set. Emit position + independent code and EH data if PIC. + +2004-10-13 Kazuhiro Inaoka + + * Makefile.am: Add m32r support. + * configure.ac: Likewise. + * Makefile.in: Regenerate. + * confiugre: Regenerate. + * src/types.c: Add m32r port to FFI_INTERNAL_TYPEDEF + (uint64, sint64, double, longdouble) + * src/m32r: New directory. + * src/m32r/ffi.c: New file. + * src/m32r/sysv.S: Likewise. + * src/m32r/ffitarget.h: Likewise. + +2004-10-02 Kaz Kojima + + * testsuite/libffi.call/negint.c: New test case. + +2004-09-14 H.J. Lu + + PR libgcj/17465 + * testsuite/lib/libffi-dg.exp: Don't use global ld_library_path. + Set up LD_LIBRARY_PATH, SHLIB_PATH, LD_LIBRARYN32_PATH, + LD_LIBRARY64_PATH, LD_LIBRARY_PATH_32, LD_LIBRARY_PATH_64 and + DYLD_LIBRARY_PATH. + +2004-09-05 Andreas Tobler + + * testsuite/libffi.call/many_win32.c: Remove whitespaces. + * testsuite/libffi.call/promotion.c: Likewise. + * testsuite/libffi.call/return_ll.c: Remove unused var. Cleanup + whitespaces. + * testsuite/libffi.call/return_sc.c: Likewise. + * testsuite/libffi.call/return_uc.c: Likewise. + +2004-09-05 Andreas Tobler + + * src/powerpc/darwin.S: Fix comments and identation. + * src/powerpc/darwin_closure.S: Likewise. + +2004-09-02 Andreas Tobler + + * src/powerpc/ffi_darwin.c: Add flag for longdouble return values. + (ffi_prep_args): Handle longdouble arguments. + (ffi_prep_cif_machdep): Set flags for longdouble. Calculate space for + longdouble. + (ffi_closure_helper_DARWIN): Add closure handling for longdouble. + * src/powerpc/darwin.S (_ffi_call_DARWIN): Add handling of longdouble + values. + * src/powerpc/darwin_closure.S (_ffi_closure_ASM): Likewise. + * src/types.c: Defined longdouble size and alignment for darwin. + +2004-09-02 Andreas Tobler + + * src/powerpc/aix.S: Remove whitespaces. + * src/powerpc/aix_closure.S: Likewise. + * src/powerpc/asm.h: Likewise. + * src/powerpc/ffi.c: Likewise. + * src/powerpc/ffitarget.h: Likewise. + * src/powerpc/linux64.S: Likewise. + * src/powerpc/linux64_closure.S: Likewise. + * src/powerpc/ppc_closure.S: Likewise. + * src/powerpc/sysv.S: Likewise. + +2004-08-30 Anthony Green + + * Makefile.am: Add frv support. + * Makefile.in, testsuite/Makefile.in: Rebuilt. + * configure.ac: Read configure.host. + * configure.in: Read configure.host. + * configure.host: New file. frv-elf needs libgloss. + * include/ffi.h.in: Force ffi_closure to have a nice big (8) + alignment. This is needed to frv and shouldn't harm the others. + * include/ffi_common.h (ALIGN_DOWN): New macro. + * src/frv/ffi.c, src/frv/ffitarget.h, src/frv/eabi.S: New files. + +2004-08-24 David Daney + + * testsuite/libffi.call/closure_fn0.c: Xfail mips64* instead of mips*. + * testsuite/libffi.call/closure_fn1.c: Likewise. + * testsuite/libffi.call/closure_fn2.c Likewise. + * testsuite/libffi.call/closure_fn3.c: Likewise. + * testsuite/libffi.call/closure_fn4.c: Likewise. + * testsuite/libffi.call/closure_fn5.c: Likewise. + * testsuite/libffi.call/cls_18byte.c: Likewise. + * testsuite/libffi.call/cls_19byte.c: Likewise. + * testsuite/libffi.call/cls_1_1byte.c: Likewise. + * testsuite/libffi.call/cls_20byte.c: Likewise. + * testsuite/libffi.call/cls_20byte1.c: Likewise. + * testsuite/libffi.call/cls_24byte.c: Likewise. + * testsuite/libffi.call/cls_2byte.c: Likewise. + * testsuite/libffi.call/cls_3_1byte.c: Likewise. + * testsuite/libffi.call/cls_3byte1.c: Likewise. + * testsuite/libffi.call/cls_3byte2.c: Likewise. + * testsuite/libffi.call/cls_4_1byte.c: Likewise. + * testsuite/libffi.call/cls_4byte.c: Likewise. + * testsuite/libffi.call/cls_64byte.c: Likewise. + * testsuite/libffi.call/cls_6byte.c: Likewise. + * testsuite/libffi.call/cls_7byte.c: Likewise. + * testsuite/libffi.call/cls_8byte.c: Likewise. + * testsuite/libffi.call/cls_9byte1.c: Likewise. + * testsuite/libffi.call/cls_9byte2.c: Likewise. + * testsuite/libffi.call/cls_align_double.c: Likewise. + * testsuite/libffi.call/cls_align_float.c: Likewise. + * testsuite/libffi.call/cls_align_longdouble.c: Likewise. + * testsuite/libffi.call/cls_align_pointer.c: Likewise. + * testsuite/libffi.call/cls_align_sint16.c: Likewise. + * testsuite/libffi.call/cls_align_sint32.c: Likewise. + * testsuite/libffi.call/cls_align_sint64.c: Likewise. + * testsuite/libffi.call/cls_align_uint16.c: Likewise. + * testsuite/libffi.call/cls_align_uint32.c: Likewise. + * testsuite/libffi.call/cls_align_uint64.c: Likewise. + * testsuite/libffi.call/cls_double.c: Likewise. + * testsuite/libffi.call/cls_float.c: Likewise. + * testsuite/libffi.call/cls_multi_schar.c: Likewise. + * testsuite/libffi.call/cls_multi_sshort.c: Likewise. + * testsuite/libffi.call/cls_multi_sshortchar.c: Likewise. + * testsuite/libffi.call/cls_multi_uchar.c: Likewise. + * testsuite/libffi.call/cls_multi_ushort.c: Likewise. + * testsuite/libffi.call/cls_multi_ushortchar.c: Likewise. + * testsuite/libffi.call/cls_schar.c: Likewise. + * testsuite/libffi.call/cls_sint.c: Likewise. + * testsuite/libffi.call/cls_sshort.c: Likewise. + * testsuite/libffi.call/cls_uchar.c: Likewise. + * testsuite/libffi.call/cls_uint.c: Likewise. + * testsuite/libffi.call/cls_ulonglong.c: Likewise. + * testsuite/libffi.call/cls_ushort.c: Likewise. + * testsuite/libffi.call/nested_struct.c: Likewise. + * testsuite/libffi.call/nested_struct1.c: Likewise. + * testsuite/libffi.call/nested_struct2.c: Likewise. + * testsuite/libffi.call/nested_struct3.c: Likewise. + * testsuite/libffi.call/problem1.c: Likewise. + * testsuite/libffi.special/unwindtest.cc: Likewise. + * testsuite/libffi.call/cls_12byte.c: Likewise and set return value + to zero. + * testsuite/libffi.call/cls_16byte.c: Likewise. + * testsuite/libffi.call/cls_5byte.c: Likewise. + +2004-08-23 David Daney + + PR libgcj/13141 + * src/mips/ffitarget.h (FFI_O32_SOFT_FLOAT): New ABI. + * src/mips/ffi.c (ffi_prep_args): Fix alignment calculation. + (ffi_prep_cif_machdep): Handle FFI_O32_SOFT_FLOAT floating point + parameters and return types. + (ffi_call): Handle FFI_O32_SOFT_FLOAT ABI. + (ffi_prep_closure): Ditto. + (ffi_closure_mips_inner_O32): Handle FFI_O32_SOFT_FLOAT ABI, fix + alignment calculations. + * src/mips/o32.S (ffi_closure_O32): Don't use floating point + instructions if FFI_O32_SOFT_FLOAT, make stack frame ABI compliant. + +2004-08-14 Casey Marshall + + * src/mips/ffi.c (ffi_pref_cif_machdep): set `cif->flags' to + contain `FFI_TYPE_UINT64' as return type for any 64-bit + integer (O32 ABI only). + (ffi_prep_closure): new function. + (ffi_closure_mips_inner_O32): new function. + * src/mips/ffitarget.h: Define `FFI_CLOSURES' and + `FFI_TRAMPOLINE_SIZE' appropriately if the ABI is o32. + * src/mips/o32.S (ffi_call_O32): add labels for .eh_frame. Return + 64 bit integers correctly. + (ffi_closure_O32): new function. + Added DWARF-2 unwind info for both functions. + +2004-08-10 Andrew Haley + + * src/x86/ffi64.c (ffi_prep_args ): 8-align all stack arguments. + +2004-08-01 Robert Millan + + * configure.ac: Detect knetbsd-gnu and kfreebsd-gnu. + * configure: Regenerate. + +2004-07-30 Maciej W. Rozycki + + * acinclude.m4 (AC_FUNC_MMAP_BLACKLIST): Check for + and mmap() explicitly instead of relying on preset autoconf cache + variables. + * aclocal.m4: Regenerate. + * configure: Regenerate. + +2004-07-11 Ulrich Weigand + + * src/s390/ffi.c (ffi_prep_args): Fix C aliasing violation. + (ffi_check_float_struct): Remove unused prototype. + +2004-06-30 Geoffrey Keating + + * src/powerpc/ffi_darwin.c (flush_icache): ';' is a comment + character on Darwin, use '\n\t' instead. + +2004-06-26 Matthias Klose + + * libtool-version: Fix typo in revision/age. + +2004-06-17 Matthias Klose + + * libtool-version: New. + * Makefile.am (libffi_la_LDFLAGS): Use -version-info for soname. + * Makefile.in: Regenerate. + +2004-06-15 Paolo Bonzini + + * Makefile.am: Remove useless multilib rules. + * Makefile.in: Regenerate. + * aclocal.m4: Regenerate with automake 1.8.5. + * configure.ac: Remove useless multilib configury. + * configure: Regenerate. + +2004-06-15 Paolo Bonzini + + * .cvsignore: New file. + +2004-06-10 Jakub Jelinek + + * src/ia64/unix.S (ffi_call_unix): Insert group barrier break + fp_done. + (ffi_closure_UNIX): Fix f14/f15 adjustment if FLOAT_SZ is ever + changed from 8. + +2004-06-06 Sean McNeil + + * configure.ac: Add x86_64-*-freebsd* support. + * configure: Regenerate. + +2004-04-26 Joe Buck + + Bug 15093 + * configure.ac: Test for existence of mmap and sys/mman.h before + checking blacklist. Fix suggested by Jim Wilson. + * configure: Regenerate. + +2004-04-26 Matt Austern + + * src/powerpc/darwin.S: Go through a non-lazy pointer for initial + FDE location. + * src/powerpc/darwin_closure.S: Likewise. + +2004-04-24 Andreas Tobler + + * testsuite/libffi.call/cls_multi_schar.c (main): Fix initialization + error. Reported by Thomas Heller . + * testsuite/libffi.call/cls_multi_sshort.c (main): Likewise. + * testsuite/libffi.call/cls_multi_ushort.c (main): Likewise. + +2004-03-20 Matthias Klose + + * src/pa/linux.S: Fix typo. + +2004-03-19 Matthias Klose + + * Makefile.am: Update. + * Makefile.in: Regenerate. + * src/pa/ffi.h.in: Remove. + * src/pa/ffitarget.h: New file. + +2004-02-10 Randolph Chung + + * Makefile.am: Add PA support. + * Makefile.in: Regenerate. + * include/Makefile.in: Regenerate. + * configure.ac: Add PA target. + * configure: Regenerate. + * src/pa/ffi.c: New file. + * src/pa/ffi.h.in: Add PA support. + * src/pa/linux.S: New file. + * prep_cif.c: Add PA support. + +2004-03-16 Hosaka Yuji + + * src/types.c: Fix alignment size of X86_WIN32 case int64 and + double. + * src/x86/ffi.c (ffi_prep_args): Replace ecif->cif->rtype->type + with ecif->cif->flags. + (ffi_call, ffi_prep_incoming_args_SYSV): Replace cif->rtype->type + with cif->flags. + (ffi_prep_cif_machdep): Add X86_WIN32 struct case. + (ffi_closure_SYSV): Add 1 or 2-bytes struct case for X86_WIN32. + * src/x86/win32.S (retstruct1b, retstruct2b, sc_retstruct1b, + sc_retstruct2b): Add for 1 or 2-bytes struct case. + +2004-03-15 Kelley Cook + + * configure.in: Rename file to ... + * configure.ac: ... this. + * fficonfig.h.in: Regenerate. + * Makefile.in: Regenerate. + * include/Makefile.in: Regenerate. + * testsuite/Makefile.in: Regenerate. + +2004-03-12 Matt Austern + + * src/powerpc/darwin.S: Fix EH information so it corresponds to + changes in EH format resulting from addition of linkonce support. + * src/powerpc/darwin_closure.S: Likewise. + +2004-03-11 Andreas Tobler + Paolo Bonzini + + * Makefile.am (AUTOMAKE_OPTIONS): Set them. + Remove VPATH. Remove rules for object files. Remove multilib support. + (AM_CCASFLAGS): Add. + * configure.in (AC_CONFIG_HEADERS): Relace AM_CONFIG_HEADER. + (AC_PREREQ): Bump version to 2.59. + (AC_INIT): Fill with version info and bug address. + (ORIGINAL_LD_FOR_MULTILIBS): Remove. + (AM_ENABLE_MULTILIB): Use this instead of AC_ARG_ENABLE. + De-precious CC so that the right flags are passed down to multilibs. + (AC_MSG_ERROR): Replace obsolete macro AC_ERROR. + (AC_CONFIG_FILES): Replace obsolete macro AC_LINK_FILES. + (AC_OUTPUT): Reorganize the output with AC_CONFIG_COMMANDS. + * configure: Rebuilt. + * aclocal.m4: Likewise. + * Makefile.in, include/Makefile.in, testsuite/Makefile.in: Likewise. + * fficonfig.h.in: Likewise. + +2004-03-11 Andreas Schwab + + * src/ia64/ffi.c (ffi_prep_incoming_args_UNIX): Get floating point + arguments from fp registers only for the first 8 parameter slots. + Don't convert a float parameter when passed in memory. + +2004-03-09 Hans-Peter Nilsson + + * configure: Regenerate for config/accross.m4 correction. + +2004-02-25 Matt Kraai + + * src/powerpc/ffi.c (ffi_prep_args_SYSV): Change + ecif->cif->bytes to bytes. + (ffi_prep_cif_machdep): Add braces around nested if statement. + +2004-02-09 Alan Modra + + * src/types.c (pointer): POWERPC64 has 8 byte pointers. + + * src/powerpc/ffi.c (ffi_prep_args64): Correct long double handling. + (ffi_closure_helper_LINUX64): Fix typo. + * testsuite/libffi.call/cls_align_longdouble.c: Pass -mlong-double-128 + for powerpc64-*-*. + * testsuite/libffi.call/float.c: Likewise. + * testsuite/libffi.call/float2.c: Likewise. + +2004-02-08 Alan Modra + + * src/powerpc/ffi.c (ffi_prep_cif_machdep ): Correct + long double function return and long double arg handling. + (ffi_closure_helper_LINUX64): Formatting. Delete unused "ng" var. + Use "end_pfr" instead of "nf". Correct long double handling. + Localise "temp". + * src/powerpc/linux64.S (ffi_call_LINUX64): Save f2 long double + return value. + * src/powerpc/linux64_closure.S (ffi_closure_LINUX64): Allocate + space for long double return value. Adjust stack frame and offsets. + Load f2 long double return. + +2004-02-07 Alan Modra + + * src/types.c: Use 16 byte long double for POWERPC64. + +2004-01-25 Eric Botcazou + + * src/sparc/ffi.c (ffi_prep_args_v9): Shift the parameter array + when the structure return address is passed in %o0. + (ffi_V9_return_struct): Rename into ffi_v9_layout_struct. + (ffi_v9_layout_struct): Align the field following a nested structure + on a word boundary. Use memmove instead of memcpy. + (ffi_call): Update call to ffi_V9_return_struct. + (ffi_prep_closure): Define 'ctx' only for V8. + (ffi_closure_sparc_inner): Clone into ffi_closure_sparc_inner_v8 + and ffi_closure_sparc_inner_v9. + (ffi_closure_sparc_inner_v8): Return long doubles by reference. + Always skip the structure return address. For structures and long + doubles, copy the argument directly. + (ffi_closure_sparc_inner_v9): Skip the structure return address only + if required. Shift the maximum floating-point slot accordingly. For + big structures, copy the argument directly; otherwise, left-justify the + argument and call ffi_v9_layout_struct to lay out the structure on + the stack. + * src/sparc/v8.S: Undef STACKFRAME before defining it. + (ffi_closure_v8): Pass the structure return address. Update call to + ffi_closure_sparc_inner_v8. Short-circuit FFI_TYPE_INT handling. + Skip the 'unimp' insn when returning long doubles and structures. + * src/sparc/v9.S: Undef STACKFRAME before defining it. + (ffi_closure_v9): Increase the frame size by 2 words. Short-circuit + FFI_TYPE_INT handling. Load structures both in integers and + floating-point registers on return. + * README: Update status of the SPARC port. + +2004-01-24 Andreas Tobler + + * testsuite/libffi.call/pyobjc-tc.c (main): Treat result value + as of type ffi_arg. + * testsuite/libffi.call/struct3.c (main): Fix CHECK. + +2004-01-22 Ulrich Weigand + + * testsuite/libffi.call/cls_uint.c (cls_ret_uint_fn): Treat result + value as of type ffi_arg, not unsigned int. + +2004-01-21 Michael Ritzert + + * ffi64.c (ffi_prep_args): Cast the RHS of an assignment instead + of the LHS. + +2004-01-12 Andreas Tobler + + * testsuite/lib/libffi-dg.exp: Set LD_LIBRARY_PATH_32 for + Solaris. + +2004-01-08 Rainer Orth + + * testsuite/libffi.call/ffitest.h (allocate_mmap): Cast MAP_FAILED + to void *. + +2003-12-10 Richard Henderson + + * testsuite/libffi.call/cls_align_pointer.c: Cast pointers to + size_t instead of int. + +2003-12-04 Hosaka Yuji + + * testsuite/libffi.call/many_win32.c: Include . + * testsuite/libffi.call/many_win32.c (main): Replace variable + int i with unsigned long ul. + + * testsuite/libffi.call/cls_align_uint64.c: New test case. + * testsuite/libffi.call/cls_align_sint64.c: Likewise. + * testsuite/libffi.call/cls_align_uint32.c: Likewise. + * testsuite/libffi.call/cls_align_sint32.c: Likewise. + * testsuite/libffi.call/cls_align_uint16.c: Likewise. + * testsuite/libffi.call/cls_align_sint16.c: Likewise. + * testsuite/libffi.call/cls_align_float.c: Likewise. + * testsuite/libffi.call/cls_align_double.c: Likewise. + * testsuite/libffi.call/cls_align_longdouble.c: Likewise. + * testsuite/libffi.call/cls_align_pointer.c: Likewise. + +2003-12-02 Hosaka Yuji + + PR other/13221 + * src/x86/ffi.c (ffi_prep_args, ffi_prep_incoming_args_SYSV): + Align arguments to 32 bits. + +2003-12-01 Andreas Tobler + + PR other/13221 + * testsuite/libffi.call/cls_multi_sshort.c: New test case. + * testsuite/libffi.call/cls_multi_sshortchar.c: Likewise. + * testsuite/libffi.call/cls_multi_uchar.c: Likewise. + * testsuite/libffi.call/cls_multi_schar.c: Likewise. + * testsuite/libffi.call/cls_multi_ushortchar.c: Likewise. + * testsuite/libffi.call/cls_multi_ushort.c: Likewise. + + * testsuite/libffi.special/unwindtest.cc: Cosmetics. + +2003-11-26 Kaveh R. Ghazi + + * testsuite/libffi.call/ffitest.h: Include . + * testsuite/libffi.special/ffitestcxx.h: Likewise. + +2003-11-22 Andreas Tobler + + * Makefile.in: Rebuilt. + * configure: Likewise. + * testsuite/libffi.special/unwindtest.cc: Convert the mmap to + the right type. + +2003-11-21 Andreas Jaeger + Andreas Tobler + + * acinclude.m4: Add AC_FUNC_MMAP_BLACKLIST. + * configure.in: Call AC_FUNC_MMAP_BLACKLIST. + * Makefile.in: Rebuilt. + * aclocal.m4: Likewise. + * configure: Likewise. + * fficonfig.h.in: Likewise. + * testsuite/lib/libffi-dg.exp: Add include dir. + * testsuite/libffi.call/ffitest.h: Add MMAP definitions. + * testsuite/libffi.special/ffitestcxx.h: Likewise. + * testsuite/libffi.call/closure_fn0.c: Use MMAP functionality + for ffi_closure if available. + * testsuite/libffi.call/closure_fn1.c: Likewise. + * testsuite/libffi.call/closure_fn2.c: Likewise. + * testsuite/libffi.call/closure_fn3.c: Likewise. + * testsuite/libffi.call/closure_fn4.c: Likewise. + * testsuite/libffi.call/closure_fn5.c: Likewise. + * testsuite/libffi.call/cls_12byte.c: Likewise. + * testsuite/libffi.call/cls_16byte.c: Likewise. + * testsuite/libffi.call/cls_18byte.c: Likewise. + * testsuite/libffi.call/cls_19byte.c: Likewise. + * testsuite/libffi.call/cls_1_1byte.c: Likewise. + * testsuite/libffi.call/cls_20byte.c: Likewise. + * testsuite/libffi.call/cls_20byte1.c: Likewise. + * testsuite/libffi.call/cls_24byte.c: Likewise. + * testsuite/libffi.call/cls_2byte.c: Likewise. + * testsuite/libffi.call/cls_3_1byte.c: Likewise. + * testsuite/libffi.call/cls_3byte1.c: Likewise. + * testsuite/libffi.call/cls_3byte2.c: Likewise. + * testsuite/libffi.call/cls_4_1byte.c: Likewise. + * testsuite/libffi.call/cls_4byte.c: Likewise. + * testsuite/libffi.call/cls_5byte.c: Likewise. + * testsuite/libffi.call/cls_64byte.c: Likewise. + * testsuite/libffi.call/cls_6byte.c: Likewise. + * testsuite/libffi.call/cls_7byte.c: Likewise. + * testsuite/libffi.call/cls_8byte.c: Likewise. + * testsuite/libffi.call/cls_9byte1.c: Likewise. + * testsuite/libffi.call/cls_9byte2.c: Likewise. + * testsuite/libffi.call/cls_double.c: Likewise. + * testsuite/libffi.call/cls_float.c: Likewise. + * testsuite/libffi.call/cls_schar.c: Likewise. + * testsuite/libffi.call/cls_sint.c: Likewise. + * testsuite/libffi.call/cls_sshort.c: Likewise. + * testsuite/libffi.call/cls_uchar.c: Likewise. + * testsuite/libffi.call/cls_uint.c: Likewise. + * testsuite/libffi.call/cls_ulonglong.c: Likewise. + * testsuite/libffi.call/cls_ushort.c: Likewise. + * testsuite/libffi.call/nested_struct.c: Likewise. + * testsuite/libffi.call/nested_struct1.c: Likewise. + * testsuite/libffi.call/nested_struct2.c: Likewise. + * testsuite/libffi.call/nested_struct3.c: Likewise. + * testsuite/libffi.call/problem1.c: Likewise. + * testsuite/libffi.special/unwindtest.cc: Likewise. + +2003-11-20 Andreas Tobler + + * testsuite/lib/libffi-dg.exp: Make the -lgcc_s conditional. + +2003-11-19 Andreas Tobler + + * testsuite/lib/libffi-dg.exp: Add DYLD_LIBRARY_PATH for darwin. + Add -lgcc_s to additional flags. + +2003-11-12 Andreas Tobler + + * configure.in, include/Makefile.am: PR libgcj/11147, install + the ffitarget.h header file in a gcc versioned and target + dependent place. + * configure: Regenerated. + * Makefile.in, include/Makefile.in: Likewise. + * testsuite/Makefile.in: Likewise. + +2003-11-09 Andreas Tobler + + * testsuite/libffi.call/closure_fn0.c: Print result and check + with dg-output to make debugging easier. + * testsuite/libffi.call/closure_fn1.c: Likewise. + * testsuite/libffi.call/closure_fn2.c: Likewise. + * testsuite/libffi.call/closure_fn3.c: Likewise. + * testsuite/libffi.call/closure_fn4.c: Likewise. + * testsuite/libffi.call/closure_fn5.c: Likewise. + * testsuite/libffi.call/cls_12byte.c: Likewise. + * testsuite/libffi.call/cls_16byte.c: Likewise. + * testsuite/libffi.call/cls_18byte.c: Likewise. + * testsuite/libffi.call/cls_19byte.c: Likewise. + * testsuite/libffi.call/cls_1_1byte.c: Likewise. + * testsuite/libffi.call/cls_20byte.c: Likewise. + * testsuite/libffi.call/cls_20byte1.c: Likewise. + * testsuite/libffi.call/cls_24byte.c: Likewise. + * testsuite/libffi.call/cls_2byte.c: Likewise. + * testsuite/libffi.call/cls_3_1byte.c: Likewise. + * testsuite/libffi.call/cls_3byte1.c: Likewise. + * testsuite/libffi.call/cls_3byte2.c: Likewise. + * testsuite/libffi.call/cls_4_1byte.c: Likewise. + * testsuite/libffi.call/cls_4byte.c: Likewise. + * testsuite/libffi.call/cls_5byte.c: Likewise. + * testsuite/libffi.call/cls_64byte.c: Likewise. + * testsuite/libffi.call/cls_6byte.c: Likewise. + * testsuite/libffi.call/cls_7byte.c: Likewise. + * testsuite/libffi.call/cls_8byte.c: Likewise. + * testsuite/libffi.call/cls_9byte1.c: Likewise. + * testsuite/libffi.call/cls_9byte2.c: Likewise. + * testsuite/libffi.call/cls_double.c: Likewise. + * testsuite/libffi.call/cls_float.c: Likewise. + * testsuite/libffi.call/cls_schar.c: Likewise. + * testsuite/libffi.call/cls_sint.c: Likewise. + * testsuite/libffi.call/cls_sshort.c: Likewise. + * testsuite/libffi.call/cls_uchar.c: Likewise. + * testsuite/libffi.call/cls_uint.c: Likewise. + * testsuite/libffi.call/cls_ulonglong.c: Likewise. + * testsuite/libffi.call/cls_ushort.c: Likewise. + * testsuite/libffi.call/problem1.c: Likewise. + + * testsuite/libffi.special/unwindtest.cc: Make ffi_closure + static. + +2003-11-08 Andreas Tobler + + * testsuite/libffi.call/cls_9byte2.c: New test case. + * testsuite/libffi.call/cls_9byte1.c: Likewise. + * testsuite/libffi.call/cls_64byte.c: Likewise. + * testsuite/libffi.call/cls_20byte1.c: Likewise. + * testsuite/libffi.call/cls_19byte.c: Likewise. + * testsuite/libffi.call/cls_18byte.c: Likewise. + * testsuite/libffi.call/closure_fn4.c: Likewise. + * testsuite/libffi.call/closure_fn5.c: Likewise. + * testsuite/libffi.call/cls_schar.c: Likewise. + * testsuite/libffi.call/cls_sint.c: Likewise. + * testsuite/libffi.call/cls_sshort.c: Likewise. + * testsuite/libffi.call/nested_struct2.c: Likewise. + * testsuite/libffi.call/nested_struct3.c: Likewise. + +2003-11-08 Andreas Tobler + + * testsuite/libffi.call/cls_double.c: Do a check on the result. + * testsuite/libffi.call/cls_uchar.c: Likewise. + * testsuite/libffi.call/cls_uint.c: Likewise. + * testsuite/libffi.call/cls_ulonglong.c: Likewise. + * testsuite/libffi.call/cls_ushort.c: Likewise. + * testsuite/libffi.call/return_sc.c: Cleanup whitespaces. + +2003-11-06 Andreas Tobler + + * src/prep_cif.c (ffi_prep_cif): Move the validity check after + the initialization. + +2003-10-23 Andreas Tobler + + * src/java_raw_api.c (ffi_java_ptrarray_to_raw): Replace + FFI_ASSERT(FALSE) with FFI_ASSERT(0). + +2003-10-22 David Daney + + * src/mips/ffitarget.h: Replace undefined UINT32 and friends with + __attribute__((__mode__(__SI__))) and friends. + +2003-10-22 Andreas Schwab + + * src/ia64/ffi.c: Replace FALSE/TRUE with false/true. + +2003-10-21 Andreas Tobler + + * configure.in: AC_LINK_FILES(ffitarget.h). + * configure: Regenerate. + * Makefile.in: Likewise. + * include/Makefile.in: Likewise. + * testsuite/Makefile.in: Likewise. + * fficonfig.h.in: Likewise. + +2003-10-21 Paolo Bonzini + Richard Henderson + + Avoid that ffi.h includes fficonfig.h. + + * Makefile.am (EXTRA_DIST): Include ffitarget.h files + (TARGET_SRC_MIPS_GCC): Renamed to TARGET_SRC_MIPS_IRIX. + (TARGET_SRC_MIPS_SGI): Removed. + (MIPS_GCC): Renamed to TARGET_SRC_MIPS_IRIX. + (MIPS_SGI): Removed. + (CLEANFILES): Removed. + (mostlyclean-am, clean-am, mostlyclean-sub, clean-sub): New + targets. + * acconfig.h: Removed. + * configure.in: Compute sizeofs only for double and long double. + Use them to define and subst HAVE_LONG_DOUBLE. Include comments + into AC_DEFINE instead of using acconfig.h. Create + include/ffitarget.h instead of include/fficonfig.h. Rename + MIPS_GCC to MIPS_IRIX, drop MIPS_SGI since we are in gcc's tree. + AC_DEFINE EH_FRAME_FLAGS. + * include/Makefile.am (DISTCLEANFILES): New automake macro. + (hack_DATA): Add ffitarget.h. + * include/ffi.h.in: Remove all system specific definitions. + Declare raw API even if it is not installed, why bother? + Use limits.h instead of SIZEOF_* to define ffi_type_*. Do + not define EH_FRAME_FLAGS, it is in fficonfig.h now. Include + ffitarget.h instead of fficonfig.h. Remove ALIGN macro. + (UINT_ARG, INT_ARG): Removed, use ffi_arg and ffi_sarg instead. + * include/ffi_common.h (bool): Do not define. + (ffi_assert): Accept failed assertion. + (ffi_type_test): Return void and accept file/line. + (FFI_ASSERT): Pass stringized failed assertion. + (FFI_ASSERT_AT): New macro. + (FFI_ASSERT_VALID_TYPE): New macro. + (UINT8, SINT8, UINT16, SINT16, UINT32, SINT32, + UINT64, SINT64): Define here with gcc's __attribute__ macro + instead of in ffi.h + (FLOAT32, ALIGN): Define here instead of in ffi.h + * include/ffi-mips.h: Removed. Its content moved to + src/mips/ffitarget.h after separating assembly and C sections. + * src/alpha/ffi.c, src/alpha/ffi.c, src/java_raw_api.c + src/prep_cif.c, src/raw_api.c, src/ia64/ffi.c, + src/mips/ffi.c, src/mips/n32.S, src/mips/o32.S, + src/mips/ffitarget.h, src/sparc/ffi.c, src/x86/ffi64.c: + SIZEOF_ARG -> FFI_SIZEOF_ARG. + * src/ia64/ffi.c: Include stdbool.h (provided by GCC 2.95+). + * src/debug.c (ffi_assert): Accept stringized failed assertion. + (ffi_type_test): Rewritten. + * src/prep-cif.c (initialize_aggregate, ffi_prep_cif): Call + FFI_ASSERT_VALID_TYPE. + * src/alpha/ffitarget.h, src/arm/ffitarget.h, + src/ia64/ffitarget.h, src/m68k/ffitarget.h, + src/mips/ffitarget.h, src/powerpc/ffitarget.h, + src/s390/ffitarget.h, src/sh/ffitarget.h, + src/sh64/ffitarget.h, src/sparc/ffitarget.h, + src/x86/ffitarget.h: New files. + * src/alpha/osf.S, src/arm/sysv.S, src/ia64/unix.S, + src/m68k/sysv.S, src/mips/n32.S, src/mips/o32.S, + src/powerpc/aix.S, src/powerpc/darwin.S, + src/powerpc/ffi_darwin.c, src/powerpc/linux64.S, + src/powerpc/linux64_closure.S, src/powerpc/ppc_closure.S, + src/powerpc/sysv.S, src/s390/sysv.S, src/sh/sysv.S, + src/sh64/sysv.S, src/sparc/v8.S, src/sparc/v9.S, + src/x86/sysv.S, src/x86/unix64.S, src/x86/win32.S: + include fficonfig.h + +2003-10-20 Rainer Orth + + * src/mips/ffi.c: Use _ABIN32, _ABIO32 instead of external + _MIPS_SIM_NABI32, _MIPS_SIM_ABI32. + +2003-10-19 Andreas Tobler + + * src/powerpc/ffi_darwin.c (ffi_prep_args): Declare bytes again. + Used when FFI_DEBUG = 1. + +2003-10-14 Alan Modra + + * src/types.c (double, longdouble): Default POWERPC64 to 8 byte size + and align. + +2003-10-06 Rainer Orth + + * include/ffi_mips.h: Define FFI_MIPS_N32 for N32/N64 ABIs, + FFI_MIPS_O32 for O32 ABI. + +2003-10-01 Andreas Tobler + + * testsuite/lib/libffi-dg.exp: Set LD_LIBRARY_PATH_64 for + SPARC64. Cleanup whitespaces. + +2003-09-19 Andreas Tobler + + * testsuite/libffi.call/closure_fn0.c: Xfail mips, arm, + strongarm, xscale. Cleanup whitespaces. + * testsuite/libffi.call/closure_fn1.c: Likewise. + * testsuite/libffi.call/closure_fn2.c: Likewise. + * testsuite/libffi.call/closure_fn3.c: Likewise. + * testsuite/libffi.call/cls_12byte.c: Likewise. + * testsuite/libffi.call/cls_16byte.c: Likewise. + * testsuite/libffi.call/cls_1_1byte.c: Likewise. + * testsuite/libffi.call/cls_20byte.c: Likewise. + * testsuite/libffi.call/cls_24byte.c: Likewise. + * testsuite/libffi.call/cls_2byte.c: Likewise. + * testsuite/libffi.call/cls_3_1byte.c: Likewise. + * testsuite/libffi.call/cls_3byte1.c: Likewise. + * testsuite/libffi.call/cls_3byte2.c: Likewise. + * testsuite/libffi.call/cls_4_1byte.c: Likewise. + * testsuite/libffi.call/cls_4byte.c: Likewise. + * testsuite/libffi.call/cls_5byte.c: Likewise. + * testsuite/libffi.call/cls_6byte.c: Likewise. + * testsuite/libffi.call/cls_7byte.c: Likewise. + * testsuite/libffi.call/cls_8byte.c: Likewise. + * testsuite/libffi.call/cls_double.c: Likewise. + * testsuite/libffi.call/cls_float.c: Likewise. + * testsuite/libffi.call/cls_uchar.c: Likewise. + * testsuite/libffi.call/cls_uint.c: Likewise. + * testsuite/libffi.call/cls_ulonglong.c: Likewise. + * testsuite/libffi.call/cls_ushort.c: Likewise. + * testsuite/libffi.call/nested_struct.c: Likewise. + * testsuite/libffi.call/nested_struct1.c: Likewise. + * testsuite/libffi.call/problem1.c: Likewise. + * testsuite/libffi.special/unwindtest.cc: Likewise. + * testsuite/libffi.call/pyobjc-tc.c: Cleanup whitespaces. + +2003-09-18 David Edelsohn + + * src/powerpc/aix.S: Cleanup whitespaces. + * src/powerpc/aix_closure.S: Likewise. + +2003-09-18 Andreas Tobler + + * src/powerpc/darwin.S: Cleanup whitespaces, comment formatting. + * src/powerpc/darwin_closure.S: Likewise. + * src/powerpc/ffi_darwin.c: Likewise. + +2003-09-18 Andreas Tobler + David Edelsohn + + * src/types.c (double): Add AIX and Darwin to the right TYPEDEF. + * src/powerpc/aix_closure.S: Remove the pointer to the outgoing + parameter stack. + * src/powerpc/darwin_closure.S: Likewise. + * src/powerpc/ffi_darwin.c (ffi_prep_args): Handle structures + according to the Darwin/AIX ABI. + (ffi_prep_cif_machdep): Likewise. + (ffi_closure_helper_DARWIN): Likewise. + Remove the outgoing parameter stack logic. Simplify the evaluation + of the different CASE types. + (ffi_prep_clousure): Avoid the casts on lvalues. Change the branch + statement in the trampoline code. + +2003-09-18 Kaz Kojima + + * src/sh/ffi.c (ffi_prep_args): Take account into the alignement + for the register size. + (ffi_closure_helper_SYSV): Handle the structure return value + address correctly. + (ffi_closure_helper_SYSV): Return the appropriate type when + the registers are used for the structure return value. + * src/sh/sysv.S (ffi_closure_SYSV): Fix the stack layout for + the 64-bit return value. Update copyright years. + +2003-09-17 Rainer Orth + + * testsuite/lib/libffi-dg.exp (libffi_target_compile): Search in + srcdir for ffi_mips.h. + +2003-09-12 Alan Modra + + * src/prep_cif.c (initialize_aggregate): Include tail padding in + structure size. + * src/powerpc/linux64_closure.S (ffi_closure_LINUX64): Correct + placement of float result. + * testsuite/libffi.special/unwindtest.cc (closure_test_fn1): Correct + cast of "resp" for big-endian 64 bit machines. + +2003-09-11 Alan Modra + + * src/types.c (double, longdouble): Merge identical SH and ARM + typedefs, and add POWERPC64. + * src/powerpc/ffi.c (ffi_prep_args64): Correct next_arg calc for + struct split over gpr and rest. + (ffi_prep_cif_machdep): Correct intarg_count for structures. + * src/powerpc/linux64.S (ffi_call_LINUX64): Fix gpr offsets. + +2003-09-09 Andreas Tobler + + * src/powerpc/ffi.c (ffi_closure_helper_SYSV) Handle struct + passing correctly. + +2003-09-09 Alan Modra + + * configure: Regenerate. + +2003-09-04 Andreas Tobler + + * Makefile.am: Remove build rules for ffitest. + * Makefile.in: Rebuilt. + +2003-09-04 Andreas Tobler + + * src/java_raw_api.c: Include to fix compiler warning + about implicit declaration of abort(). + +2003-09-04 Andreas Tobler + + * Makefile.am: Add dejagnu test framework. Fixes PR other/11411. + * Makefile.in: Rebuilt. + * configure.in: Add dejagnu test framework. + * configure: Rebuilt. + + * testsuite/Makefile.am: New file. + * testsuite/Makefile.in: Built + * testsuite/lib/libffi-dg.exp: New file. + * testsuite/config/default.exp: Likewise. + * testsuite/libffi.call/call.exp: Likewise. + * testsuite/libffi.call/ffitest.h: Likewise. + * testsuite/libffi.call/closure_fn0.c: Likewise. + * testsuite/libffi.call/closure_fn1.c: Likewise. + * testsuite/libffi.call/closure_fn2.c: Likewise. + * testsuite/libffi.call/closure_fn3.c: Likewise. + * testsuite/libffi.call/cls_1_1byte.c: Likewise. + * testsuite/libffi.call/cls_3_1byte.c: Likewise. + * testsuite/libffi.call/cls_4_1byte.c: Likewise. + * testsuite/libffi.call/cls_2byte.c: Likewise. + * testsuite/libffi.call/cls_3byte1.c: Likewise. + * testsuite/libffi.call/cls_3byte2.c: Likewise. + * testsuite/libffi.call/cls_4byte.c: Likewise. + * testsuite/libffi.call/cls_5byte.c: Likewise. + * testsuite/libffi.call/cls_6byte.c: Likewise. + * testsuite/libffi.call/cls_7byte.c: Likewise. + * testsuite/libffi.call/cls_8byte.c: Likewise. + * testsuite/libffi.call/cls_12byte.c: Likewise. + * testsuite/libffi.call/cls_16byte.c: Likewise. + * testsuite/libffi.call/cls_20byte.c: Likewise. + * testsuite/libffi.call/cls_24byte.c: Likewise. + * testsuite/libffi.call/cls_double.c: Likewise. + * testsuite/libffi.call/cls_float.c: Likewise. + * testsuite/libffi.call/cls_uchar.c: Likewise. + * testsuite/libffi.call/cls_uint.c: Likewise. + * testsuite/libffi.call/cls_ulonglong.c: Likewise. + * testsuite/libffi.call/cls_ushort.c: Likewise. + * testsuite/libffi.call/float.c: Likewise. + * testsuite/libffi.call/float1.c: Likewise. + * testsuite/libffi.call/float2.c: Likewise. + * testsuite/libffi.call/many.c: Likewise. + * testsuite/libffi.call/many_win32.c: Likewise. + * testsuite/libffi.call/nested_struct.c: Likewise. + * testsuite/libffi.call/nested_struct1.c: Likewise. + * testsuite/libffi.call/pyobjc-tc.c: Likewise. + * testsuite/libffi.call/problem1.c: Likewise. + * testsuite/libffi.call/promotion.c: Likewise. + * testsuite/libffi.call/return_ll.c: Likewise. + * testsuite/libffi.call/return_sc.c: Likewise. + * testsuite/libffi.call/return_uc.c: Likewise. + * testsuite/libffi.call/strlen.c: Likewise. + * testsuite/libffi.call/strlen_win32.c: Likewise. + * testsuite/libffi.call/struct1.c: Likewise. + * testsuite/libffi.call/struct2.c: Likewise. + * testsuite/libffi.call/struct3.c: Likewise. + * testsuite/libffi.call/struct4.c: Likewise. + * testsuite/libffi.call/struct5.c: Likewise. + * testsuite/libffi.call/struct6.c: Likewise. + * testsuite/libffi.call/struct7.c: Likewise. + * testsuite/libffi.call/struct8.c: Likewise. + * testsuite/libffi.call/struct9.c: Likewise. + * testsuite/libffi.special/special.exp: New file. + * testsuite/libffi.special/ffitestcxx.h: Likewise. + * testsuite/libffi.special/unwindtest.cc: Likewise. + + +2003-08-13 Kaz Kojima + + * src/sh/ffi.c (OFS_INT16): Set 0 for little endian case. Update + copyright years. + +2003-08-02 Alan Modra + + * src/powerpc/ffi.c (ffi_prep_args64): Modify for changed gcc + structure passing. + (ffi_closure_helper_LINUX64): Likewise. + * src/powerpc/linux64.S: Remove code writing to parm save area. + * src/powerpc/linux64_closure.S (ffi_closure_LINUX64): Use return + address in lr from ffi_closure_helper_LINUX64 call to calculate + table address. Optimize function tail. + +2003-07-28 Andreas Tobler + + * src/sparc/ffi.c: Handle all floating point registers. + * src/sparc/v9.S: Likewise. Fixes second part of PR target/11410. + +2003-07-11 Gerald Pfeifer + + * README: Note that libffi is not part of GCC. Update the project + URL and status. + +2003-06-19 Franz Sirl + + * src/powerpc/ppc_closure.S: Include ffi.h. + +2003-06-13 Rainer Orth + + * src/x86/sysv.S: Avoid gas-only .uleb128/.sleb128 directives. + Use C style comments. + +2003-06-13 Kaz Kojima + + * Makefile.am: Add SHmedia support. Fix a typo of SH support. + * Makefile.in: Regenerate. + * configure.in (sh64-*-linux*, sh5*-*-linux*): Add target. + * configure: Regenerate. + * include/ffi.h.in: Add SHmedia support. + * src/sh64/ffi.c: New file. + * src/sh64/sysv.S: New file. + +2003-05-16 Jakub Jelinek + + * configure.in (HAVE_RO_EH_FRAME): Check whether .eh_frame section + should be read-only. + * configure: Rebuilt. + * fficonfig.h.in: Rebuilt. + * include/ffi.h.in (EH_FRAME_FLAGS): Define. + * src/alpha/osf.S: Use EH_FRAME_FLAGS. + * src/powerpc/linux64.S: Likewise. + * src/powerpc/linux64_closure.S: Likewise. Include ffi.h. + * src/powerpc/sysv.S: Use EH_FRAME_FLAGS. Use pcrel encoding + if -fpic/-fPIC/-mrelocatable. + * src/powerpc/powerpc_closure.S: Likewise. + * src/sparc/v8.S: If HAVE_RO_EH_FRAME is defined, don't include + #write in .eh_frame flags. + * src/sparc/v9.S: Likewise. + * src/x86/unix64.S: Use EH_FRAME_FLAGS. + * src/x86/sysv.S: Likewise. Use pcrel encoding if -fpic/-fPIC. + * src/s390/sysv.S: Use EH_FRAME_FLAGS. Include ffi.h. + +2003-05-07 Jeff Sturm + + Fixes PR bootstrap/10656 + * configure.in (HAVE_AS_REGISTER_PSEUDO_OP): Test assembler + support for .register pseudo-op. + * src/sparc/v8.S: Use it. + * fficonfig.h.in: Rebuilt. + * configure: Rebuilt. + +2003-04-18 Jakub Jelinek + + * include/ffi.h.in (POWERPC64): Define if 64-bit. + (enum ffi_abi): Add FFI_LINUX64 on POWERPC. + Make it the default on POWERPC64. + (FFI_TRAMPOLINE_SIZE): Define to 24 on POWERPC64. + * configure.in: Change powerpc-*-linux* into powerpc*-*-linux*. + * configure: Rebuilt. + * src/powerpc/ffi.c (hidden): Define. + (ffi_prep_args_SYSV): Renamed from + ffi_prep_args. Cast pointers to unsigned long to shut up warnings. + (NUM_GPR_ARG_REGISTERS64, NUM_FPR_ARG_REGISTERS64, + ASM_NEEDS_REGISTERS64): New. + (ffi_prep_args64): New function. + (ffi_prep_cif_machdep): Handle FFI_LINUX64 ABI. + (ffi_call): Likewise. + (ffi_prep_closure): Likewise. + (flush_icache): Surround by #ifndef POWERPC64. + (ffi_dblfl): New union type. + (ffi_closure_helper_SYSV): Use it to avoid aliasing problems. + (ffi_closure_helper_LINUX64): New function. + * src/powerpc/ppc_closure.S: Surround whole file by #ifndef + __powerpc64__. + * src/powerpc/sysv.S: Likewise. + (ffi_call_SYSV): Rename ffi_prep_args to ffi_prep_args_SYSV. + * src/powerpc/linux64.S: New file. + * src/powerpc/linux64_closure.S: New file. + * Makefile.am (EXTRA_DIST): Add src/powerpc/linux64.S and + src/powerpc/linux64_closure.S. + (TARGET_SRC_POWERPC): Likewise. + + * src/ffitest.c (closure_test_fn, closure_test_fn1, closure_test_fn2, + closure_test_fn3): Fix result printing on big-endian 64-bit + machines. + (main): Print tst2_arg instead of uninitialized tst2_result. + + * src/ffitest.c (main): Hide what closure pointer really points to + from the compiler. + +2003-04-16 Richard Earnshaw + + * configure.in (arm-*-netbsdelf*): Add configuration. + (configure): Regenerated. + +2003-04-04 Loren J. Rittle + + * include/Makefile.in: Regenerate. + +2003-03-21 Zdenek Dvorak + + * libffi/include/ffi.h.in: Define X86 instead of X86_64 in 32 + bit mode. + * libffi/src/x86/ffi.c (ffi_closure_SYSV, ffi_closure_raw_SYSV): + Receive closure pointer through parameter, read args using + __builtin_dwarf_cfa. + (FFI_INIT_TRAMPOLINE): Send closure reference through eax. + +2003-03-12 Andreas Schwab + + * configure.in: Avoid trailing /. in toolexeclibdir. + * configure: Rebuilt. + +2003-03-03 Andreas Tobler + + * src/powerpc/darwin_closure.S: Recode to fit dynamic libraries. + +2003-02-06 Andreas Tobler + + * libffi/src/powerpc/darwin_closure.S: + Fix alignement bug, allocate 8 bytes for the result. + * libffi/src/powerpc/aix_closure.S: + Likewise. + * libffi/src/powerpc/ffi_darwin.c: + Update stackframe description for aix/darwin_closure.S. + +2003-02-06 Jakub Jelinek + + * src/s390/ffi.c (ffi_closure_helper_SYSV): Add hidden visibility + attribute. + +2003-01-31 Christian Cornelssen , + Andreas Schwab + + * configure.in: Adjust command to source config-ml.in to account + for changes to the libffi_basedir definition. + (libffi_basedir): Remove ${srcdir} from value and include trailing + slash if nonempty. + + * configure: Regenerate. + +2003-01-29 Franz Sirl + + * src/powerpc/ppc_closure.S: Recode to fit shared libs. + +2003-01-28 Andrew Haley + + * include/ffi.h.in: Enable FFI_CLOSURES for x86_64. + * src/x86/ffi64.c (ffi_prep_closure): New. + (ffi_closure_UNIX64_inner): New. + * src/x86/unix64.S (ffi_closure_UNIX64): New. + +2003-01-27 Alexandre Oliva + + * configure.in (toolexecdir, toolexeclibdir): Set and AC_SUBST. + Remove USE_LIBDIR conditional. + * Makefile.am (toolexecdir, toolexeclibdir): Don't override. + * Makefile.in, configure: Rebuilt. + +2003-01027 David Edelsohn + + * Makefile.am (TARGET_SRC_POWERPC_AIX): Fix typo. + * Makefile.in: Regenerate. + +2003-01-22 Andrew Haley + + * src/powerpc/darwin.S (_ffi_call_AIX): Add Augmentation size to + unwind info. + +2003-01-21 Andreas Tobler + + * src/powerpc/darwin.S: Add unwind info. + * src/powerpc/darwin_closure.S: Likewise. + +2003-01-14 Andrew Haley + + * src/x86/ffi64.c (ffi_prep_args): Check for void retval. + (ffi_prep_cif_machdep): Likewise. + * src/x86/unix64.S: Add unwind info. + +2003-01-14 Andreas Jaeger + + * src/ffitest.c (main): Only use ffi_closures if those are + supported. + +2003-01-13 Andreas Tobler + + * libffi/src/ffitest.c + add closure testcases + +2003-01-13 Kevin B. Hendricks + + * libffi/src/powerpc/ffi.c + fix alignment bug for float (4 byte aligned iso 8 byte) + +2003-01-09 Geoffrey Keating + + * src/powerpc/ffi_darwin.c: Remove RCS version string. + * src/powerpc/darwin.S: Remove RCS version string. + +2003-01-03 Jeff Sturm + + * include/ffi.h.in: Add closure defines for SPARC, SPARC64. + * src/ffitest.c (main): Use static storage for closure. + * src/sparc/ffi.c (ffi_prep_closure, ffi_closure_sparc_inner): New. + * src/sparc/v8.S (ffi_closure_v8): New. + * src/sparc/v9.S (ffi_closure_v9): New. + +2002-11-10 Ranjit Mathew + + * include/ffi.h.in: Added FFI_STDCALL ffi_type + enumeration for X86_WIN32. + * src/x86/win32.S: Added ffi_call_STDCALL function + definition. + * src/x86/ffi.c (ffi_call/ffi_raw_call): Added + switch cases for recognising FFI_STDCALL and + calling ffi_call_STDCALL if target is X86_WIN32. + * src/ffitest.c (my_stdcall_strlen/stdcall_many): + stdcall versions of the "my_strlen" and "many" + test functions (for X86_WIN32). + Added test cases to test stdcall invocation using + these functions. + +2002-12-02 Kaz Kojima + + * src/sh/sysv.S: Add DWARF2 unwind info. + +2002-11-27 Ulrich Weigand + + * src/s390/sysv.S (.eh_frame section): Make section read-only. + +2002-11-26 Jim Wilson + + * src/types.c (FFI_TYPE_POINTER): Has size 8 on IA64. + +2002-11-23 H.J. Lu + + * acinclude.m4: Add dummy AM_PROG_LIBTOOL. + Include ../config/accross.m4. + * aclocal.m4; Rebuild. + * configure: Likewise. + +2002-11-15 Ulrich Weigand + + * src/s390/sysv.S (.eh_frame section): Adapt to pcrel FDE encoding. + +2002-11-11 DJ Delorie + + * configure.in: Look for common files in the right place. + +2002-10-08 Ulrich Weigand + + * src/java_raw_api.c (ffi_java_raw_to_ptrarray): Interpret + raw data as _Jv_word values, not ffi_raw. + (ffi_java_ptrarray_to_raw): Likewise. + (ffi_java_rvalue_to_raw): New function. + (ffi_java_raw_call): Call it. + (ffi_java_raw_to_rvalue): New function. + (ffi_java_translate_args): Call it. + * src/ffitest.c (closure_test_fn): Interpret return value + as ffi_arg, not int. + * src/s390/ffi.c (ffi_prep_cif_machdep): Add missing + FFI_TYPE_POINTER case. + (ffi_closure_helper_SYSV): Likewise. Also, assume return + values extended to word size. + +2002-10-02 Andreas Jaeger + + * src/x86/ffi64.c (ffi_prep_cif_machdep): Remove debug output. + +2002-10-01 Bo Thorsen + + * include/ffi.h.in: Fix i386 win32 compilation. + +2002-09-30 Ulrich Weigand + + * configure.in: Add s390x-*-linux-* target. + * configure: Regenerate. + * include/ffi.h.in: Define S390X for s390x targets. + (FFI_CLOSURES): Define for s390/s390x. + (FFI_TRAMPOLINE_SIZE): Likewise. + (FFI_NATIVE_RAW_API): Likewise. + * src/prep_cif.c (ffi_prep_cif): Do not compute stack space for s390. + * src/types.c (FFI_TYPE_POINTER): Use 8-byte pointers on s390x. + * src/s390/ffi.c: Major rework of existing code. Add support for + s390x targets. Add closure support. + * src/s390/sysv.S: Likewise. + +2002-09-29 Richard Earnshaw + + * src/arm/sysv.S: Fix typo. + +2002-09-28 Richard Earnshaw + + * src/arm/sysv.S: If we don't have machine/asm.h and the pre-processor + has defined __USER_LABEL_PREFIX__, then use it in CNAME. + (ffi_call_SYSV): Handle soft-float. + +2002-09-27 Bo Thorsen + + * include/ffi.h.in: Fix multilib x86-64 support. + +2002-09-22 Kaveh R. Ghazi + + * Makefile.am (all-multi): Fix multilib parallel build. + +2002-07-19 Kaz Kojima + + * configure.in (sh[34]*-*-linux*): Add brackets. + * configure: Regenerate. + +2002-07-18 Kaz Kojima + + * Makefile.am: Add SH support. + * Makefile.in: Regenerate. + * configure.in (sh-*-linux*, sh[34]*-*-linux*): Add target. + * configure: Regenerate. + * include/ffi.h.in: Add SH support. + * src/sh/ffi.c: New file. + * src/sh/sysv.S: New file. + * src/types.c: Add SH support. + +2002-07-16 Bo Thorsen + + * src/x86/ffi64.c: New file that adds x86-64 support. + * src/x86/unix64.S: New file that handles argument setup for + x86-64. + * src/x86/sysv.S: Don't use this on x86-64. + * src/x86/ffi.c: Don't use this on x86-64. + Remove unused vars. + * src/prep_cif.c (ffi_prep_cif): Don't do stack size calculation + for x86-64. + * src/ffitest.c (struct6): New test that tests a special case in + the x86-64 ABI. + (struct7): Likewise. + (struct8): Likewise. + (struct9): Likewise. + (closure_test_fn): Silence warning about this when it's not used. + (main): Add the new tests. + (main): Fix a couple of wrong casts and silence some compiler warnings. + * include/ffi.h.in: Add x86-64 ABI definition. + * fficonfig.h.in: Regenerate. + * Makefile.am: Add x86-64 support. + * configure.in: Likewise. + * Makefile.in: Regenerate. + * configure: Likewise. + +2002-06-24 Bo Thorsen + + * src/types.c: Merge settings for similar architectures. + Add x86-64 sizes and alignments. + +2002-06-23 Bo Thorsen + + * src/arm/ffi.c (ffi_prep_args): Remove unused vars. + * src/sparc/ffi.c (ffi_prep_args_v8): Likewise. + * src/mips/ffi.c (ffi_prep_args): Likewise. + * src/m68k/ffi.c (ffi_prep_args): Likewise. + +2002-07-18 H.J. Lu (hjl@gnu.org) + + * Makefile.am (TARGET_SRC_MIPS_LINUX): New. + (libffi_la_SOURCES): Support MIPS_LINUX. + (libffi_convenience_la_SOURCES): Likewise. + * Makefile.in: Regenerated. + + * configure.in (mips64*-*): Skip. + (mips*-*-linux*): New. + * configure: Regenerated. + + * src/mips/ffi.c: Include . + +2002-06-06 Ulrich Weigand + + * src/s390/sysv.S: Save/restore %r6. Add DWARF-2 unwind info. + +2002-05-27 Roger Sayle + + * src/x86/ffi.c (ffi_prep_args): Remove reference to avn. + +2002-05-27 Bo Thorsen + + * src/x86/ffi.c (ffi_prep_args): Remove unused variable and + fix formatting. + +2002-05-13 Andreas Tobler + + * src/powerpc/ffi_darwin.c (ffi_prep_closure): Declare fd at + beginning of function (for older apple cc). + +2002-05-08 Alexandre Oliva + + * configure.in (ORIGINAL_LD_FOR_MULTILIBS): Preserve LD at + script entry, and set LD to it when configuring multilibs. + * configure: Rebuilt. + +2002-05-05 Jason Thorpe + + * configure.in (sparc64-*-netbsd*): Add target. + (sparc-*-netbsdelf*): Likewise. + * configure: Regenerate. + +2002-04-28 David S. Miller + + * configure.in, configure: Fix SPARC test in previous change. + +2002-04-29 Gerhard Tonn + + * Makefile.am: Add Linux for S/390 support. + * Makefile.in: Regenerate. + * configure.in: Add Linux for S/390 support. + * configure: Regenerate. + * include/ffi.h.in: Add Linux for S/390 support. + * src/s390/ffi.c: New file from libffi CVS tree. + * src/s390/sysv.S: New file from libffi CVS tree. + +2002-04-28 Jakub Jelinek + + * configure.in (HAVE_AS_SPARC_UA_PCREL): Check for working + %r_disp32(). + * src/sparc/v8.S: Use it. + * src/sparc/v9.S: Likewise. + * fficonfig.h.in: Rebuilt. + * configure: Rebuilt. + +2002-04-08 Hans Boehm + + * src/java_raw_api.c (ffi_java_raw_size): Handle FFI_TYPE_DOUBLE + correctly. + * src/ia64/unix.S: Add unwind information. Fix comments. + Save sp in a way that's compatible with unwind info. + (ffi_call_unix): Correctly restore sp in all cases. + * src/ia64/ffi.c: Add, fix comments. + +2002-04-08 Jakub Jelinek + + * src/sparc/v8.S: Make .eh_frame dependent on target word size. + +2002-04-06 Jason Thorpe + + * configure.in (alpha*-*-netbsd*): Add target. + * configure: Regenerate. + +2002-04-04 Jeff Sturm + + * src/sparc/v8.S: Add unwind info. + * src/sparc/v9.S: Likewise. + +2002-03-30 Krister Walfridsson + + * configure.in: Enable i*86-*-netbsdelf*. + * configure: Rebuilt. + +2002-03-29 David Billinghurst + + PR other/2620 + * src/mips/n32.s: Delete + * src/mips/o32.s: Delete + +2002-03-21 Loren J. Rittle + + * configure.in: Enable alpha*-*-freebsd*. + * configure: Rebuilt. + +2002-03-17 Bryce McKinlay + + * Makefile.am: libfficonvenience -> libffi_convenience. + * Makefile.in: Rebuilt. + + * Makefile.am: Define ffitest_OBJECTS. + * Makefile.in: Rebuilt. + +2002-03-07 Andreas Tobler + David Edelsohn + + * Makefile.am (EXTRA_DIST): Add Darwin and AIX closure files. + (TARGET_SRC_POWERPC_AIX): Add aix_closure.S. + (TARGET_SRC_POWERPC_DARWIN): Add darwin_closure.S. + * Makefile.in: Regenerate. + * include/ffi.h.in: Add AIX and Darwin closure definitions. + * src/powerpc/ffi_darwin.c (ffi_prep_closure): New function. + (flush_icache, flush_range): New functions. + (ffi_closure_helper_DARWIN): New function. + * src/powerpc/aix_closure.S: New file. + * src/powerpc/darwin_closure.S: New file. + +2002-02-24 Jeff Sturm + + * include/ffi.h.in: Add typedef for ffi_arg. + * src/ffitest.c (main): Declare rint with ffi_arg. + +2002-02-21 Andreas Tobler + + * src/powerpc/ffi_darwin.c (ffi_prep_args): Skip appropriate + number of GPRs for floating-point arguments. + +2002-01-31 Anthony Green + + * configure: Rebuilt. + * configure.in: Replace CHECK_SIZEOF and endian tests with + cross-compiler friendly macros. + * aclocal.m4 (AC_COMPILE_CHECK_SIZEOF, AC_C_BIGENDIAN_CROSS): New + macros. + +2002-01-18 David Edelsohn + + * src/powerpc/darwin.S (_ffi_call_AIX): New. + * src/powerpc/aix.S (ffi_call_DARWIN): New. + +2002-01-17 David Edelsohn + + * Makefile.am (EXTRA_DIST): Add Darwin and AIX files. + (TARGET_SRC_POWERPC_AIX): New. + (POWERPC_AIX): New stanza. + * Makefile.in: Regenerate. + * configure.in: Add AIX case. + * configure: Regenerate. + * include/ffi.h.in (ffi_abi): Add FFI_AIX. + * src/powerpc/ffi_darwin.c (ffi_status): Use "long" to scale frame + size. Fix "long double" support. + (ffi_call): Add FFI_AIX case. + * src/powerpc/aix.S: New. + +2001-10-09 John Hornkvist + + Implement Darwin PowerPC ABI. + * configure.in: Handle powerpc-*-darwin*. + * Makefile.am: Set source files for POWERPC_DARWIN. + * configure: Rebuilt. + * Makefile.in: Rebuilt. + * include/ffi.h.in: Define FFI_DARWIN and FFI_DEFAULT_ABI for + POWERPC_DARWIN. + * src/powerpc/darwin.S: New file. + * src/powerpc/ffi_darwin.c: New file. + +2001-10-07 Joseph S. Myers + + * src/x86/ffi.c: Fix spelling error of "separate" as "seperate". + +2001-07-16 Rainer Orth + + * src/x86/sysv.S: Avoid gas-only .balign directive. + Use C style comments. + +2001-07-16 Rainer Orth + + * src/alpha/ffi.c (ffi_prep_closure): Avoid gas-only mnemonic. + Fixes PR bootstrap/3563. + +2001-06-26 Rainer Orth + + * src/alpha/osf.S (ffi_closure_osf): Use .rdata for ECOFF. + +2001-06-25 Rainer Orth + + * configure.in: Recognize sparc*-sun-* host. + * configure: Regenerate. + +2001-06-06 Andrew Haley + + * src/alpha/osf.S (__FRAME_BEGIN__): Conditionalize for ELF. + +2001-06-03 Andrew Haley + + * src/alpha/osf.S: Add unwind info. + * src/powerpc/sysv.S: Add unwind info. + * src/powerpc/ppc_closure.S: Likewise. + +2000-05-31 Jeff Sturm + + * configure.in: Fix AC_ARG_ENABLE usage. + * configure: Rebuilt. + +2001-05-06 Bryce McKinlay + + * configure.in: Remove warning about beta code. + * configure: Rebuilt. + +2001-04-25 Hans Boehm + + * src/ia64/unix.S: Restore stack pointer when returning from + ffi_closure_UNIX. + * src/ia64/ffi.c: Fix typo in comment. + +2001-04-18 Jim Wilson + + * src/ia64/unix.S: Delete unnecessary increment and decrement of loc2 + to eliminate RAW DV. + +2001-04-12 Bryce McKinlay + + * Makefile.am: Make a libtool convenience library. + * Makefile.in: Rebuilt. + +2001-03-29 Bryce McKinlay + + * configure.in: Use different syntax for subdirectory creation. + * configure: Rebuilt. + +2001-03-27 Jon Beniston + + * configure.in: Added X86_WIN32 target (Win32, CygWin, MingW). + * configure: Rebuilt. + * Makefile.am: Added X86_WIN32 target support. + * Makefile.in: Rebuilt. + + * include/ffi.h.in: Added X86_WIN32 target support. + + * src/ffitest.c: Doesn't run structure tests for X86_WIN32 targets. + * src/types.c: Added X86_WIN32 target support. + + * src/x86/win32.S: New file. Based on sysv.S, but with EH + stuff removed and made to work with CygWin's gas. + +2001-03-26 Bryce McKinlay + + * configure.in: Make target subdirectory in build dir. + * Makefile.am: Override suffix based rules to specify correct output + subdirectory. + * Makefile.in: Rebuilt. + * configure: Rebuilt. + +2001-03-23 Kevin B Hendricks + + * src/powerpc/ppc_closure.S: New file. + * src/powerpc/ffi.c (ffi_prep_args): Fixed ABI compatibility bug + involving long long and register pairs. + (ffi_prep_closure): New function. + (flush_icache): Likewise. + (ffi_closure_helper_SYSV): Likewise. + * include/ffi.h.in (FFI_CLOSURES): Define on PPC. + (FFI_TRAMPOLINE_SIZE): Likewise. + (FFI_NATIVE_RAW_API): Likewise. + * Makefile.in: Rebuilt. + * Makefile.am (EXTRA_DIST): Added src/powerpc/ppc_closure.S. + (TARGET_SRC_POWERPC): Likewise. + +2001-03-19 Tom Tromey + + * Makefile.in: Rebuilt. + * Makefile.am (ffitest_LDFLAGS): New macro. + +2001-03-02 Nick Clifton + + * include/ffi.h.in: Remove RCS ident string. + * include/ffi_mips.h: Remove RCS ident string. + * src/debug.c: Remove RCS ident string. + * src/ffitest.c: Remove RCS ident string. + * src/prep_cif.c: Remove RCS ident string. + * src/types.c: Remove RCS ident string. + * src/alpha/ffi.c: Remove RCS ident string. + * src/alpha/osf.S: Remove RCS ident string. + * src/arm/ffi.c: Remove RCS ident string. + * src/arm/sysv.S: Remove RCS ident string. + * src/mips/ffi.c: Remove RCS ident string. + * src/mips/n32.S: Remove RCS ident string. + * src/mips/o32.S: Remove RCS ident string. + * src/sparc/ffi.c: Remove RCS ident string. + * src/sparc/v8.S: Remove RCS ident string. + * src/sparc/v9.S: Remove RCS ident string. + * src/x86/ffi.c: Remove RCS ident string. + * src/x86/sysv.S: Remove RCS ident string. + +2001-02-08 Joseph S. Myers + + * include/ffi.h.in: Change sourceware.cygnus.com references to + gcc.gnu.org. + +2000-12-09 Richard Henderson + + * src/alpha/ffi.c (ffi_call): Simplify struct return test. + (ffi_closure_osf_inner): Index rather than increment avalue + and arg_types. Give ffi_closure_osf the raw return value type. + * src/alpha/osf.S (ffi_closure_osf): Handle return value type + promotion. + +2000-12-07 Richard Henderson + + * src/raw_api.c (ffi_translate_args): Fix typo. + (ffi_prep_closure): Likewise. + + * include/ffi.h.in [ALPHA]: Define FFI_CLOSURES and + FFI_TRAMPOLINE_SIZE. + * src/alpha/ffi.c (ffi_prep_cif_machdep): Adjust minimal + cif->bytes for new ffi_call_osf implementation. + (ffi_prep_args): Absorb into ... + (ffi_call): ... here. Do all stack allocation here and + avoid a callback function. + (ffi_prep_closure, ffi_closure_osf_inner): New. + * src/alpha/osf.S (ffi_call_osf): Reimplement with no callback. + (ffi_closure_osf): New. + +2000-09-10 Alexandre Oliva + + * config.guess, config.sub, install-sh: Removed. + * ltconfig, ltmain.sh, missing, mkinstalldirs: Likewise. + * Makefile.in: Rebuilt. + + * acinclude.m4: Include libtool macros from the top level. + * aclocal.m4, configure: Rebuilt. + +2000-08-22 Alexandre Oliva + + * configure.in [i*86-*-freebsd*] (TARGET, TARGETDIR): Set. + * configure: Rebuilt. + +2000-05-11 Scott Bambrough + + * libffi/src/arm/sysv.S (ffi_call_SYSV): Doubles are not saved to + memory correctly. Use conditional instructions, not branches where + possible. + +2000-05-04 Tom Tromey + + * configure: Rebuilt. + * configure.in: Match `arm*-*-linux-*'. + From Chris Dornan . + +2000-04-28 Jakub Jelinek + + * Makefile.am (SUBDIRS): Define. + (AM_MAKEFLAGS): Likewise. + (Multilib support.): Add section. + * Makefile.in: Rebuilt. + * ltconfig (extra_compiler_flags, extra_compiler_flags_value): + New variables. Set for gcc using -print-multi-lib. Export them + to libtool. + (sparc64-*-linux-gnu*): Use libsuff 64 for search paths. + * ltmain.sh (B|b|V): Don't throw away gcc's -B, -b and -V options + for -shared links. + (extra_compiler_flags_value, extra_compiler_flags): Check these + for extra compiler options which need to be passed down in + compiler_flags. + +2000-04-16 Anthony Green + + * configure: Rebuilt. + * configure.in: Change i*86-pc-linux* to i*86-*-linux*. + +2000-04-14 Jakub Jelinek + + * include/ffi.h.in (SPARC64): Define for 64bit SPARC builds. + Set SPARC FFI_DEFAULT_ABI based on SPARC64 define. + * src/sparc/ffi.c (ffi_prep_args_v8): Renamed from ffi_prep_args. + Replace all void * sizeofs with sizeof(int). + Only compare type with FFI_TYPE_LONGDOUBLE if LONGDOUBLE is + different than DOUBLE. + Remove FFI_TYPE_SINT32 and FFI_TYPE_UINT32 cases (handled elsewhere). + (ffi_prep_args_v9): New function. + (ffi_prep_cif_machdep): Handle V9 ABI and long long on V8. + (ffi_V9_return_struct): New function. + (ffi_call): Handle FFI_V9 ABI from 64bit code and FFI_V8 ABI from + 32bit code (not yet cross-arch calls). + * src/sparc/v8.S: Add struct return delay nop. + Handle long long. + * src/sparc/v9.S: New file. + * src/prep_cif.c (ffi_prep_cif): Return structure pointer + is used on sparc64 only for structures larger than 32 bytes. + Pass by reference for structures is done for structure arguments + larger than 16 bytes. + * src/ffitest.c (main): Use 64bit rint on sparc64. + Run long long tests on sparc. + * src/types.c (FFI_TYPE_POINTER): Pointer is 64bit on alpha and + sparc64. + (FFI_TYPE_LONGDOUBLE): long double is 128 bit aligned to 128 bits + on sparc64. + * configure.in (sparc-*-linux*): New supported target. + (sparc64-*-linux*): Likewise. + * configure: Rebuilt. + * Makefile.am: Add v9.S to SPARC files. + * Makefile.in: Likewise. + (LINK): Surround $(CCLD) into double quotes, so that multilib + compiles work correctly. + +2000-04-04 Alexandre Petit-Bianco + + * configure: Rebuilt. + * configure.in: (i*86-*-solaris*): New libffi target. Patch + proposed by Bryce McKinlay. + +2000-03-20 Tom Tromey + + * Makefile.in: Hand edit for java_raw_api.lo. + +2000-03-08 Bryce McKinlay + + * config.guess, config.sub: Update from the gcc tree. + Fix for PR libgcj/168. + +2000-03-03 Tom Tromey + + * Makefile.in: Fixed ia64 by hand. + + * configure: Rebuilt. + * configure.in (--enable-multilib): New option. + (libffi_basedir): New subst. + (AC_OUTPUT): Added multilib code. + +2000-03-02 Tom Tromey + + * Makefile.in: Rebuilt. + * Makefile.am (TARGET_SRC_IA64): Use `ia64', not `alpha', as + directory name. + +2000-02-25 Hans Boehm + + * src/ia64/ffi.c, src/ia64/ia64_flags.h, src/ia64/unix.S: New + files. + * src/raw_api.c (ffi_translate_args): Fixed typo in argument + list. + (ffi_prep_raw_closure): Use ffi_translate_args, not + ffi_closure_translate. + * src/java_raw_api.c: New file. + * src/ffitest.c (closure_test_fn): New function. + (main): Define `rint' as long long on IA64. Added new test when + FFI_CLOSURES is defined. + * include/ffi.h.in (ALIGN): Use size_t, not unsigned. + (ffi_abi): Recognize IA64. + (ffi_raw): Added `flt' field. + Added "Java raw API" code. + * configure.in: Recognize ia64. + * Makefile.am (TARGET_SRC_IA64): New macro. + (libffi_la_common_SOURCES): Added java_raw_api.c. + (libffi_la_SOURCES): Define in IA64 case. + +2000-01-04 Tom Tromey + + * Makefile.in: Rebuilt with newer automake. + +1999-12-31 Tom Tromey + + * Makefile.am (INCLUDES): Added -I$(top_srcdir)/src. + +1999-09-01 Tom Tromey + + * include/ffi.h.in: Removed PACKAGE and VERSION defines and + undefs. + * fficonfig.h.in: Rebuilt. + * configure: Rebuilt. + * configure.in: Pass 3rd argument to AM_INIT_AUTOMAKE. + Use AM_PROG_LIBTOOL (automake 1.4 compatibility). + * acconfig.h: Don't #undef PACKAGE or VERSION. + +1999-08-09 Anthony Green + + * include/ffi.h.in: Try to work around messy header problem + with PACKAGE and VERSION. + + * configure: Rebuilt. + * configure.in: Change version to 2.00-beta. + + * fficonfig.h.in: Rebuilt. + * acconfig.h (FFI_NO_STRUCTS, FFI_NO_RAW_API): Define. + + * src/x86/ffi.c (ffi_raw_call): Rename. + +1999-08-02 Kresten Krab Thorup + + * src/x86/ffi.c (ffi_closure_SYSV): New function. + (ffi_prep_incoming_args_SYSV): Ditto. + (ffi_prep_closure): Ditto. + (ffi_closure_raw_SYSV): Ditto. + (ffi_prep_raw_closure): More ditto. + (ffi_call_raw): Final ditto. + + * include/ffi.h.in: Add definitions for closure and raw API. + + * src/x86/ffi.c (ffi_prep_cif_machdep): Added case for + FFI_TYPE_UINT64. + + * Makefile.am (libffi_la_common_SOURCES): Added raw_api.c + + * src/raw_api.c: New file. + + * include/ffi.h.in (ffi_raw): New type. + (UINT_ARG, SINT_ARG): New defines. + (ffi_closure, ffi_raw_closure): New types. + (ffi_prep_closure, ffi_prep_raw_closure): New declarations. + + * configure.in: Add check for endianness and sizeof void*. + + * src/x86/sysv.S (ffi_call_SYSV): Call fixup routine via argument, + instead of directly. + + * configure: Rebuilt. + +Thu Jul 8 14:28:42 1999 Anthony Green + + * configure.in: Add x86 and powerpc BeOS configurations. + From Makoto Kato . + +1999-05-09 Anthony Green + + * configure.in: Add warning about this being beta code. + Remove src/Makefile.am from the picture. + * configure: Rebuilt. + + * Makefile.am: Move logic from src/Makefile.am. Add changes + to support libffi as a target library. + * Makefile.in: Rebuilt. + + * aclocal.m4, config.guess, config.sub, ltconfig, ltmain.sh: + Upgraded to new autoconf, automake, libtool. + + * README: Tweaks. + + * LICENSE: Update copyright date. + + * src/Makefile.am, src/Makefile.in: Removed. + +1998-11-29 Anthony Green + + * include/ChangeLog: Removed. + * src/ChangeLog: Removed. + * src/mips/ChangeLog: Removed. + * src/sparc/ChangeLog: Remboved. + * src/x86/ChangeLog: Removed. + + * ChangeLog.v1: Created. diff --git a/js/src/ctypes/libffi/ChangeLog.libffi b/js/src/ctypes/libffi/ChangeLog.libffi new file mode 100644 index 0000000..5272f33 --- /dev/null +++ b/js/src/ctypes/libffi/ChangeLog.libffi @@ -0,0 +1,613 @@ +2010-01-15 Anthony Green + + * README: Add notes on building with Microsoft Visual C++. + +2010-01-15 Daniel Witte + + * msvcc.sh: New file. + + * src/x86/win32.S: Port assembly routines to MSVC and #ifdef. + * src/x86/ffi.c: Tweak function declaration and remove excess + parens. + * include/ffi.h.in: Add __declspec(align(8)) to typedef struct + ffi_closure. + + * src/x86/ffi.c: Merge ffi_call_SYSV and ffi_call_STDCALL into new + function ffi_call_win32 on X86_WIN32. + * src/x86/win32.S (ffi_call_SYSV): Rename to ffi_call_win32. + (ffi_call_STDCALL): Remove. + + * src/prep_cif.c (ffi_prep_cif): Move stack space allocation code + to ffi_prep_cif_machdep for x86. + * src/x86/ffi.c (ffi_prep_cif_machdep): To here. + +2010-01-15 Oliver Kiddle + + * src/x86/ffitarget.h (ffi_abi): Check for __i386 and __amd64 for + Sun Studio compiler compatibility. + +2010-01-12 Conrad Irwin + + * doc/libffi.texi: Add closure example. + * doc/libffi.info: Rebuilt. + +2009-12-25 Samuli Suominen + + * configure.ac: Undefine _AC_ARG_VAR_PRECIOUS for autoconf 2.64. + * configure: Rebuilt. + * fficonfig.h.in: Rebuilt. + +2009-06-16 Andrew Haley + + * testsuite/libffi.call/cls_align_sint64.c, + testsuite/libffi.call/cls_align_uint64.c, + testsuite/libffi.call/cls_longdouble_va.c, + testsuite/libffi.call/cls_ulonglong.c, + testsuite/libffi.call/return_ll1.c, + testsuite/libffi.call/stret_medium2.c: Fix printf format + specifiers. + * testsuite/libffi.call/huge_struct.c: Ad x86 XFAILs. + * testsuite/libffi.call/float2.c: Fix dg-excess-errors. + * testsuite/libffi.call/ffitest.h, + testsuite/libffi.special/ffitestcxx.h (PRIdLL, PRIuLL): Define. + +2009-06-12 Andrew Haley + + * testsuite/libffi.call/cls_align_sint64.c, + testsuite/libffi.call/cls_align_uint64.c, + testsuite/libffi.call/cls_ulonglong.c, + testsuite/libffi.call/return_ll1.c, + testsuite/libffi.call/stret_medium2.c: Fix printf format + specifiers. + testsuite/libffi.special/unwindtest.cc: include stdint.h. + +2009-06-11 Timothy Wall + + * Makefile.am, + configure.ac, + include/ffi.h.in, + include/ffi_common.h, + src/closures.c, + src/dlmalloc.c, + src/x86/ffi.c, + src/x86/ffitarget.h, + src/x86/win64.S (new), + README: Added win64 support (mingw or MSVC) + * Makefile.in, + include/Makefile.in, + man/Makefile.in, + testsuite/Makefile.in, + configure, + aclocal.m4: Regenerated + * ltcf-c.sh: properly escape cygwin/w32 path + * man/ffi_call.3: Clarify size requirements for return value. + * src/x86/ffi64.c: Fix filename in comment. + * src/x86/win32.S: Remove unused extern. + + * testsuite/libffi.call/closure_fn0.c, + testsuite/libffi.call/closure_fn1.c, + testsuite/libffi.call/closure_fn2.c, + testsuite/libffi.call/closure_fn3.c, + testsuite/libffi.call/closure_fn4.c, + testsuite/libffi.call/closure_fn5.c, + testsuite/libffi.call/closure_fn6.c, + testsuite/libffi.call/closure_stdcall.c, + testsuite/libffi.call/cls_12byte.c, + testsuite/libffi.call/cls_16byte.c, + testsuite/libffi.call/cls_18byte.c, + testsuite/libffi.call/cls_19byte.c, + testsuite/libffi.call/cls_1_1byte.c, + testsuite/libffi.call/cls_20byte.c, + testsuite/libffi.call/cls_20byte1.c, + testsuite/libffi.call/cls_24byte.c, + testsuite/libffi.call/cls_2byte.c, + testsuite/libffi.call/cls_3_1byte.c, + testsuite/libffi.call/cls_3byte1.c, + testsuite/libffi.call/cls_3byte2.c, + testsuite/libffi.call/cls_4_1byte.c, + testsuite/libffi.call/cls_4byte.c, + testsuite/libffi.call/cls_5_1_byte.c, + testsuite/libffi.call/cls_5byte.c, + testsuite/libffi.call/cls_64byte.c, + testsuite/libffi.call/cls_6_1_byte.c, + testsuite/libffi.call/cls_6byte.c, + testsuite/libffi.call/cls_7_1_byte.c, + testsuite/libffi.call/cls_7byte.c, + testsuite/libffi.call/cls_8byte.c, + testsuite/libffi.call/cls_9byte1.c, + testsuite/libffi.call/cls_9byte2.c, + testsuite/libffi.call/cls_align_double.c, + testsuite/libffi.call/cls_align_float.c, + testsuite/libffi.call/cls_align_longdouble.c, + testsuite/libffi.call/cls_align_longdouble_split.c, + testsuite/libffi.call/cls_align_longdouble_split2.c, + testsuite/libffi.call/cls_align_pointer.c, + testsuite/libffi.call/cls_align_sint16.c, + testsuite/libffi.call/cls_align_sint32.c, + testsuite/libffi.call/cls_align_sint64.c, + testsuite/libffi.call/cls_align_uint16.c, + testsuite/libffi.call/cls_align_uint32.c, + testsuite/libffi.call/cls_align_uint64.c, + testsuite/libffi.call/cls_dbls_struct.c, + testsuite/libffi.call/cls_double.c, + testsuite/libffi.call/cls_double_va.c, + testsuite/libffi.call/cls_float.c, + testsuite/libffi.call/cls_longdouble.c, + testsuite/libffi.call/cls_longdouble_va.c, + testsuite/libffi.call/cls_multi_schar.c, + testsuite/libffi.call/cls_multi_sshort.c, + testsuite/libffi.call/cls_multi_sshortchar.c, + testsuite/libffi.call/cls_multi_uchar.c, + testsuite/libffi.call/cls_multi_ushort.c, + testsuite/libffi.call/cls_multi_ushortchar.c, + testsuite/libffi.call/cls_pointer.c, + testsuite/libffi.call/cls_pointer_stack.c, + testsuite/libffi.call/cls_schar.c, + testsuite/libffi.call/cls_sint.c, + testsuite/libffi.call/cls_sshort.c, + testsuite/libffi.call/cls_uchar.c, + testsuite/libffi.call/cls_uint.c, + testsuite/libffi.call/cls_ulonglong.c, + testsuite/libffi.call/cls_ushort.c, + testsuite/libffi.call/err_bad_abi.c, + testsuite/libffi.call/err_bad_typedef.c, + testsuite/libffi.call/float2.c, + testsuite/libffi.call/huge_struct.c, + testsuite/libffi.call/nested_struct.c, + testsuite/libffi.call/nested_struct1.c, + testsuite/libffi.call/nested_struct10.c, + testsuite/libffi.call/nested_struct2.c, + testsuite/libffi.call/nested_struct3.c, + testsuite/libffi.call/nested_struct4.c, + testsuite/libffi.call/nested_struct5.c, + testsuite/libffi.call/nested_struct6.c, + testsuite/libffi.call/nested_struct7.c, + testsuite/libffi.call/nested_struct8.c, + testsuite/libffi.call/nested_struct9.c, + testsuite/libffi.call/problem1.c, + testsuite/libffi.call/return_ldl.c, + testsuite/libffi.call/return_ll1.c, + testsuite/libffi.call/stret_large.c, + testsuite/libffi.call/stret_large2.c, + testsuite/libffi.call/stret_medium.c, + testsuite/libffi.call/stret_medium2.c, + testsuite/libffi.special/unwindtest.cc: use ffi_closure_alloc instead + of checking for MMAP. Use intptr_t instead of long casts. + +2009-06-04 Andrew Haley + + * src/powerpc/ffitarget.h: Fix misapplied merge from gcc. + +2009-06-04 Andrew Haley + + * src/mips/o32.S, + src/mips/n32.S: Fix licence formatting. + +2009-06-04 Andrew Haley + + * src/x86/darwin.S: Fix licence formatting. + src/x86/win32.S: Likewise. + src/sh64/sysv.S: Likewise. + src/sh/sysv.S: Likewise. + +2009-06-04 Andrew Haley + + * src/sh64/ffi.c: Remove lint directives. Was missing from merge + of Andreas Tobler's patch from 2006-04-22. + +2009-06-04 Andrew Haley + + * src/sh/ffi.c: Apply missing hunk from Alexandre Oliva's patch of + 2007-03-07. + +2008-12-26 Timothy Wall + + * testsuite/libffi.call/cls_longdouble.c, + testsuite/libffi.call/cls_longdouble_va.c, + testsuite/libffi.call/cls_align_longdouble.c, + testsuite/libffi.call/cls_align_longdouble_split.c, + testsuite/libffi.call/cls_align_longdouble_split2.c: mark expected + failures on x86_64 cygwin/mingw. + +2008-12-22 Timothy Wall + + * testsuite/libffi.call/closure_fn0.c, + testsuite/libffi.call/closure_fn1.c, + testsuite/libffi.call/closure_fn2.c, + testsuite/libffi.call/closure_fn3.c, + testsuite/libffi.call/closure_fn4.c, + testsuite/libffi.call/closure_fn5.c, + testsuite/libffi.call/closure_fn6.c, + testsuite/libffi.call/closure_loc_fn0.c, + testsuite/libffi.call/closure_stdcall.c, + testsuite/libffi.call/cls_align_pointer.c, + testsuite/libffi.call/cls_pointer.c, + testsuite/libffi.call/cls_pointer_stack.c: use portable cast from + pointer to integer (intptr_t). + * testsuite/libffi.call/cls_longdouble.c: disable for win64. + +2008-12-19 Anthony Green + + * configure.ac: Bump version to 3.0.8. + * configure, doc/stamp-vti, doc/version.texi: Rebuilt. + * libtool-version: Increment revision. + * README: Update for new release. + +2008-11-11 Anthony Green + + * configure.ac: Bump version to 3.0.7. + * configure, doc/stamp-vti, doc/version.texi: Rebuilt. + * libtool-version: Increment revision. + * README: Update for new release. + +2008-08-25 Andreas Tobler + + * src/powerpc/ffitarget.h (ffi_abi): Add FFI_LINUX and + FFI_LINUX_SOFT_FLOAT to the POWERPC_FREEBSD enum. + Add note about flag bits used for FFI_SYSV_TYPE_SMALL_STRUCT. + Adjust copyright notice. + * src/powerpc/ffi.c: Add two new flags to indicate if we have one + register or two register to use for FFI_SYSV structs. + (ffi_prep_cif_machdep): Pass the right register flag introduced above. + (ffi_closure_helper_SYSV): Fix the return type for + FFI_SYSV_TYPE_SMALL_STRUCT. Comment. + Adjust copyright notice. + +2008-07-24 Anthony Green + + * testsuite/libffi.call/cls_dbls_struct.c, + testsuite/libffi.call/cls_double_va.c, + testsuite/libffi.call/cls_longdouble.c, + testsuite/libffi.call/cls_longdouble_va.c, + testsuite/libffi.call/cls_pointer.c, + testsuite/libffi.call/cls_pointer_stack.c, + testsuite/libffi.call/err_bad_abi.c: Clean up failures from + compiler warnings. + +2008-07-17 Anthony Green + + * configure.ac: Bump version to 3.0.6. + * configure, doc/stamp-vti, doc/version.texi: Rebuilt. + * libtool-version: Increment revision. Add documentation. + * README: Update for new release. + +2008-07-16 Kaz Kojima + + * src/sh/ffi.c (ffi_prep_closure_loc): Turn INSN into an unsigned + int. + +2008-07-16 Kaz Kojima + + * src/sh/sysv.S: Add .note.GNU-stack on Linux. + * src/sh64/sysv.S: Likewise. + +2008-04-03 Anthony Green + + * libffi.pc.in (Libs): Add -L${libdir}. + * configure.ac: Bump version to 3.0.5. + * configure, doc/stamp-vti, doc/version.texi: Rebuilt. + * libtool-version: Increment revision. + * README: Update for new release. + +2008-04-03 Anthony Green + Xerces Ranby + + * include/ffi.h.in: Wrap definition of target architecture to + protect from double definitions. + +2008-03-22 Moriyoshi Koizumi + + * src/x86/ffi.c (ffi_prep_closure_loc): Fix for bug revealed in + closure_loc_fn0.c. + * testsuite/libffi.call/closure_loc_fn0.c (closure_loc_test_fn0): + New test. + +2008-03-04 Anthony Green + Blake Chaffin + hos@tamanegi.org + + * testsuite/libffi.call/cls_align_longdouble_split2.c + testsuite/libffi.call/cls_align_longdouble_split.c + testsuite/libffi.call/cls_dbls_struct.c + testsuite/libffi.call/cls_double_va.c + testsuite/libffi.call/cls_longdouble.c + testsuite/libffi.call/cls_longdouble_va.c + testsuite/libffi.call/cls_pointer.c + testsuite/libffi.call/cls_pointer_stack.c + testsuite/libffi.call/err_bad_abi.c + testsuite/libffi.call/err_bad_typedef.c + testsuite/libffi.call/huge_struct.c + testsuite/libffi.call/stret_large2.c + testsuite/libffi.call/stret_large.c + testsuite/libffi.call/stret_medium2.c + testsuite/libffi.call/stret_medium.c: New tests from Apple. + +2008-02-26 Jakub Jelinek + Anthony Green + + * src/alpha/osf.S: Add .note.GNU-stack on Linux. + * src/s390/sysv.S: Likewise. + * src/powerpc/linux64.S: Likewise. + * src/powerpc/linux64_closure.S: Likewise. + * src/powerpc/ppc_closure.S: Likewise. + * src/powerpc/sysv.S: Likewise. + * src/x86/unix64.S: Likewise. + * src/x86/sysv.S: Likewise. + * src/sparc/v8.S: Likewise. + * src/sparc/v9.S: Likewise. + * src/m68k/sysv.S: Likewise. + * src/ia64/unix.S: Likewise. + * src/arm/sysv.S: Likewise. + +2008-02-26 Anthony Green + Thomas Heller + + * src/x86/ffi.c (ffi_closure_SYSV_inner): Change C++ comment to C + comment. + +2008-02-26 Anthony Green + Thomas Heller + + * include/ffi.h.in: Change void (*)() to void (*)(void). + +2008-02-26 Anthony Green + Thomas Heller + + * src/alpha/ffi.c: Change void (*)() to void (*)(void). + src/alpha/osf.S, src/arm/ffi.c, src/frv/ffi.c, src/ia64/ffi.c, + src/ia64/unix.S, src/java_raw_api.c, src/m32r/ffi.c, + src/mips/ffi.c, src/pa/ffi.c, src/pa/hpux32.S, src/pa/linux.S, + src/powerpc/ffi.c, src/powerpc/ffi_darwin.c, src/raw_api.c, + src/s390/ffi.c, src/sh/ffi.c, src/sh64/ffi.c, src/sparc/ffi.c, + src/x86/ffi.c, src/x86/unix64.S, src/x86/darwin64.S, + src/x86/ffi64.c: Ditto. + +2008-02-24 Anthony Green + + * configure.ac: Accept openbsd*, not just openbsd. + Bump version to 3.0.4. + * configure, doc/stamp-vti, doc/version.texi: Rebuilt. + * libtool-version: Increment revision. + * README: Update for new release. + +2008-02-22 Anthony Green + + * README: Clean up list of tested platforms. + +2008-02-22 Anthony Green + + * configure.ac: Bump version to 3.0.3. + * configure, doc/stamp-vti, doc/version.texi: Rebuilt. + * libtool-version: Increment revision. + * README: Update for new release. Clean up test docs. + +2008-02-22 Bjoern Koenig + Andreas Tobler + + * configure.ac: Add amd64-*-freebsd* target. + * configure: Regenerate. + +2008-02-22 Thomas Heller + + * configure.ac: Add x86 OpenBSD support. + * configure: Rebuilt. + +2008-02-21 Thomas Heller + + * README: Change "make test" to "make check". + +2008-02-21 Anthony Green + + * configure.ac: Bump version to 3.0.2. + * configure, doc/stamp-vti, doc/version.texi: Rebuilt. + * libtool-version: Increment revision. + * README: Update for new release. + +2008-02-21 Björn König + + * src/x86/freebsd.S: New file. + * configure.ac: Add x86 FreeBSD support. + * Makefile.am: Ditto. + +2008-02-15 Anthony Green + + * configure.ac: Bump version to 3.0.1. + * configure, doc/stamp-vti, doc/version.texi: Rebuilt. + * libtool-version: Increment revision. + * README: Update for new release. + +2008-02-15 David Daney + + * src/mips/ffi.c: Remove extra '>' from include directive. + (ffi_prep_closure_loc): Use clear_location instead of tramp. + +2008-02-15 Anthony Green + + * configure.ac: Bump version to 3.0.0. + * configure, doc/stamp-vti, doc/version.texi: Rebuilt. + +2008-02-15 David Daney + + * src/mips/ffi.c (USE__BUILTIN___CLEAR_CACHE): + Define (conditionally), and use it to include cachectl.h. + (ffi_prep_closure_loc): Fix cache flushing. + * src/mips/ffitarget.h (_ABIN32, _ABI64, _ABIO32): Define. + +2008-02-15 Anthony Green + + * man/ffi_call.3, man/ffi_prep_cif.3, man/ffi.3: + Update dates and remove all references to ffi_prep_closure. + * configure.ac: Bump version to 2.99.9. + * configure, doc/stamp-vti, doc/version.texi: Rebuilt. + +2008-02-15 Anthony Green + + * man/ffi_prep_closure.3: Delete. + * man/Makefile.am (EXTRA_DIST): Remove ffi_prep_closure.3. + (man_MANS): Ditto. + * man/Makefile.in: Rebuilt. + * configure.ac: Bump version to 2.99.8. + * configure, doc/stamp-vti, doc/version.texi: Rebuilt. + +2008-02-14 Anthony Green + + * configure.ac: Bump version to 2.99.7. + * configure, doc/stamp-vti, doc/version.texi: Rebuilt. + * include/ffi.h.in LICENSE src/debug.c src/closures.c + src/ffitest.c src/s390/sysv.S src/s390/ffitarget.h + src/types.c src/m68k/ffitarget.h src/raw_api.c src/frv/ffi.c + src/frv/ffitarget.h src/sh/ffi.c src/sh/sysv.S + src/sh/ffitarget.h src/powerpc/ffitarget.h src/pa/ffi.c + src/pa/ffitarget.h src/pa/linux.S src/java_raw_api.c + src/cris/ffitarget.h src/x86/ffi.c src/x86/sysv.S + src/x86/unix64.S src/x86/win32.S src/x86/ffitarget.h + src/x86/ffi64.c src/x86/darwin.S src/ia64/ffi.c + src/ia64/ffitarget.h src/ia64/ia64_flags.h src/ia64/unix.S + src/sparc/ffi.c src/sparc/v9.S src/sparc/ffitarget.h + src/sparc/v8.S src/alpha/ffi.c src/alpha/ffitarget.h + src/alpha/osf.S src/sh64/ffi.c src/sh64/sysv.S + src/sh64/ffitarget.h src/mips/ffi.c src/mips/ffitarget.h + src/mips/n32.S src/mips/o32.S src/arm/ffi.c src/arm/sysv.S + src/arm/ffitarget.h src/prep_cif.c: Update license text. + +2008-02-14 Anthony Green + + * README: Update tested platforms. + * configure.ac: Bump version to 2.99.6. + * configure: Rebuilt. + +2008-02-14 Anthony Green + + * configure.ac: Bump version to 2.99.5. + * configure: Rebuilt. + * Makefile.am (EXTRA_DIST): Add darwin64.S + * Makefile.in: Rebuilt. + * testsuite/lib/libffi-dg.exp: Remove libstdc++ bits from GCC tree. + * LICENSE: Update WARRANTY. + +2008-02-14 Anthony Green + + * libffi.pc.in (libdir): Fix libdir definition. + * configure.ac: Bump version to 2.99.4. + * configure: Rebuilt. + +2008-02-14 Anthony Green + + * README: Update. + * libffi.info: New file. + * doc/stamp-vti: New file. + * configure.ac: Bump version to 2.99.3. + * configure: Rebuilt. + +2008-02-14 Anthony Green + + * Makefile.am (SUBDIRS): Add man dir. + * Makefile.in: Rebuilt. + * configure.ac: Create Makefile. + * configure: Rebuilt. + * man/ffi_call.3 man/ffi_prep_cif.3 man/ffi_prep_closure.3 + man/Makefile.am man/Makefile.in: New files. + +2008-02-14 Tom Tromey + + * aclocal.m4, Makefile.in, configure, fficonfig.h.in: Rebuilt. + * mdate-sh, texinfo.tex: New files. + * Makefile.am (info_TEXINFOS): New variable. + * doc/libffi.texi: New file. + * doc/version.texi: Likewise. + +2008-02-14 Anthony Green + + * Makefile.am (AM_CFLAGS): Don't compile with -D$(TARGET). + (lib_LTLIBRARIES): Define. + (toolexeclib_LIBRARIES): Undefine. + * Makefile.in: Rebuilt. + * configure.ac: Reset version to 2.99.1. + * configure.in: Rebuilt. + +2008-02-14 Anthony Green + + * libffi.pc.in: Use @PACKAGE_NAME@ and @PACKAGE_VERSION@. + * configure.ac: Reset version to 2.99.1. + * configure.in: Rebuilt. + * Makefile.am (EXTRA_DIST): Add ChangeLog.libffi. + * Makefile.in: Rebuilt. + * LICENSE: Update copyright notice. + +2008-02-14 Anthony Green + + * include/Makefile.am (nodist_includes_HEADERS): Define. Don't + distribute ffitarget.h or ffi.h from the build include dir. + * Makefile.in: Rebuilt. + +2008-02-14 Anthony Green + + * include/Makefile.am (includesdir): Install headers under libdir. + (pkgconfigdir): Define. Install libffi.pc. + * include/Makefile.in: Rebuilt. + * libffi.pc.in: Create. + * libtool-version: Increment CURRENT + * configure.ac: Add libffi.pc.in + * configure: Rebuilt. + +2008-02-03 Anthony Green + + * include/Makefile.am (includesdir): Fix header install with + DESTDIR. + * include/Makefile.in: Rebuilt. + +2008-02-03 Timothy Wall + + * src/x86/ffi.c (FFI_INIT_TRAMPOLINE_STDCALL): Calculate jump return + offset based on code pointer, not data pointer. + +2008-02-01 Anthony Green + + * include/Makefile.am: Fix header installs. + * Makefile.am: Ditto. + * include/Makefile.in: Rebuilt. + * Makefile.in: Ditto. + +2008-02-01 Anthony Green + + * src/x86/ffi.c (FFI_INIT_TRAMPOLINE_STDCALL, + FFI_INIT_TRAMPOLINE): Revert my broken changes to twall's last + patch. + +2008-01-31 Anthony Green + + * Makefile.am (EXTRA_DIST): Add missing files. + * testsuite/Makefile.am: Ditto. + * Makefile.in, testsuite/Makefile.in: Rebuilt. + +2008-01-31 Timothy Wall + + * testsuite/libffi.call/closure_stdcall.c: Add test for stdcall + closures. + * src/x86/ffitarget.h: Increase size of trampoline for stdcall + closures. + * src/x86/win32.S: Add assembly for stdcall closure. + * src/x86/ffi.c: Initialize stdcall closure trampoline. + +2008-01-30 H.J. Lu + + PR libffi/34612 + * src/x86/sysv.S (ffi_closure_SYSV): Pop 4 byte from stack when + returning struct. + + * testsuite/libffi.call/call.exp: Add "-O2 -fomit-frame-pointer" + tests. + +2008-01-30 Anthony Green + + * Makefile.am, include/Makefile.am: Move headers to + libffi_la_SOURCES for new automake. + * Makefile.in, include/Makefile.in: Rebuilt. + + * testsuite/lib/wrapper.exp: Copied from gcc tree to allow for + execution outside of gcc tree. + * testsuite/lib/target-libpath.exp: Ditto. + + * testsuite/lib/libffi-dg.exp: Many changes to allow for execution + outside of gcc tree. + diff --git a/js/src/ctypes/libffi/ChangeLog.libgcj b/js/src/ctypes/libffi/ChangeLog.libgcj new file mode 100644 index 0000000..ea5d02f --- /dev/null +++ b/js/src/ctypes/libffi/ChangeLog.libgcj @@ -0,0 +1,40 @@ +2004-01-14 Kelley Cook + + * configure.in: Add in AC_PREREQ(2.13) + +2003-02-20 Alexandre Oliva + + * configure.in: Propagate ORIGINAL_LD_FOR_MULTILIBS to + config.status. + * configure: Rebuilt. + +2002-01-27 Alexandre Oliva + + * configure.in (toolexecdir, toolexeclibdir): Set and AC_SUBST. + Remove USE_LIBDIR conditional. + * Makefile.am (toolexecdir, toolexeclibdir): Don't override. + * Makefile.in, configure: Rebuilt. + +Mon Aug 9 18:33:38 1999 Rainer Orth + + * include/Makefile.in: Rebuilt. + * Makefile.in: Rebuilt + * Makefile.am (toolexeclibdir): Add $(MULTISUBDIR) even for native + builds. + Use USE_LIBDIR. + + * configure: Rebuilt. + * configure.in (USE_LIBDIR): Define for native builds. + Use lowercase in configure --help explanations. + +1999-08-08 Anthony Green + + * include/ffi.h.in (FFI_FN): Remove `...'. + +1999-08-08 Anthony Green + + * Makefile.in: Rebuilt. + * Makefile.am (AM_CFLAGS): Compile with -fexceptions. + + * src/x86/sysv.S: Add exception handling metadata. + diff --git a/js/src/ctypes/libffi/ChangeLog.v1 b/js/src/ctypes/libffi/ChangeLog.v1 new file mode 100644 index 0000000..369820c --- /dev/null +++ b/js/src/ctypes/libffi/ChangeLog.v1 @@ -0,0 +1,764 @@ +The libffi version 1 ChangeLog archive. + +Version 1 of libffi had per-directory ChangeLogs. Current and future +versions have a single ChangeLog file in the root directory. The +version 1 ChangeLogs have all been concatonated into this file for +future reference only. + +--- libffi ---------------------------------------------------------------- + +Mon Oct 5 02:17:50 1998 Anthony Green + + * configure.in: Boosted rev. + * configure, Makefile.in, aclocal.m4: Rebuilt. + * README: Boosted rev and updated release notes. + +Mon Oct 5 01:03:03 1998 Anthony Green + + * configure.in: Boosted rev. + * configure, Makefile.in, aclocal.m4: Rebuilt. + * README: Boosted rev and updated release notes. + +1998-07-25 Andreas Schwab + + * m68k/ffi.c (ffi_prep_cif_machdep): Use bitmask for cif->flags. + Correctly handle small structures. + (ffi_prep_args): Also handle small structures. + (ffi_call): Pass size of return type to ffi_call_SYSV. + * m68k/sysv.S: Adjust for above changes. Correctly align small + structures in the return value. + + * types.c (uint64, sint64) [M68K]: Change alignment to 4. + +Fri Apr 17 17:26:58 1998 Anthony Green + + * configure.in: Boosted rev. + * configure,Makefile.in,aclocal.m4: Rebuilt. + * README: Boosted rev and added release notes. + +Sun Feb 22 00:50:41 1998 Geoff Keating + + * configure.in: Add PowerPC config bits. + +1998-02-14 Andreas Schwab + + * configure.in: Add m68k config bits. Change AC_CANONICAL_SYSTEM + to AC_CANONICAL_HOST, this is not a compiler. Use $host instead + of $target. Remove AC_CHECK_SIZEOF(char), we already know the + result. Fix argument of AC_ARG_ENABLE. + * configure, fficonfig.h.in: Rebuilt. + +Tue Feb 10 20:53:40 1998 Richard Henderson + + * configure.in: Add Alpha config bits. + +Tue May 13 13:39:20 1997 Anthony Green + + * README: Updated dates and reworded Irix comments. + + * configure.in: Removed AC_PROG_RANLIB. + + * Makefile.in, aclocal.m4, config.guess, config.sub, configure, + ltmain.sh, */Makefile.in: libtoolized again and rebuilt with + automake and autoconf. + +Sat May 10 18:44:50 1997 Tom Tromey + + * configure, aclocal.m4: Rebuilt. + * configure.in: Don't compute EXTRADIST; now handled in + src/Makefile.in. Removed macros implied by AM_INIT_AUTOMAKE. + Don't run AM_MAINTAINER_MODE. + +Thu May 8 14:34:05 1997 Anthony Green + + * missing, ltmain.sh, ltconfig.sh: Created. These are new files + required by automake and libtool. + + * README: Boosted rev to 1.14. Added notes. + + * acconfig.h: Moved PACKAGE and VERSION for new automake. + + * configure.in: Changes for libtool. + + * Makefile.am (check): make test now make check. Uses libtool now. + + * Makefile.in, configure.in, aclocal.h, fficonfig.h.in: Rebuilt. + +Thu May 1 16:27:07 1997 Anthony Green + + * missing: Added file required by new automake. + +Tue Nov 26 14:10:42 1996 Anthony Green + + * acconfig.h: Added USING_PURIFY flag. This is defined when + --enable-purify-safety was used at configure time. + + * configure.in (allsources): Added --enable-purify-safety switch. + (VERSION): Boosted rev to 1.13. + * configure: Rebuilt. + +Fri Nov 22 06:46:12 1996 Anthony Green + + * configure.in (VERSION): Boosted rev to 1.12. + Removed special CFLAGS hack for gcc. + * configure: Rebuilt. + + * README: Boosted rev to 1.12. Added notes. + + * Many files: Cygnus Support changed to Cygnus Solutions. + +Wed Oct 30 11:15:25 1996 Anthony Green + + * configure.in (VERSION): Boosted rev to 1.11. + * configure: Rebuilt. + + * README: Boosted rev to 1.11. Added notes about GNU make. + +Tue Oct 29 12:25:12 1996 Anthony Green + + * configure.in: Fixed -Wall trick. + (VERSION): Boosted rev. + * configure: Rebuilt + + * acconfig.h: Needed for --enable-debug configure switch. + + * README: Boosted rev to 1.09. Added more notes on building + libffi, and LCLint. + + * configure.in: Added --enable-debug switch. Boosted rev to + 1.09. + * configure: Rebuilt + +Tue Oct 15 13:11:28 1996 Anthony Green + + * configure.in (VERSION): Boosted rev to 1.08 + * configure: Rebuilt. + + * README: Added n32 bug fix notes. + + * Makefile.am: Added "make lint" production. + * Makefile.in: Rebuilt. + +Mon Oct 14 10:54:46 1996 Anthony Green + + * README: Added web page reference. + + * configure.in, README: Boosted rev to 1.05 + * configure: Rebuilt. + + * README: Fixed n32 sample code. + +Fri Oct 11 17:09:28 1996 Anthony Green + + * README: Added sparc notes. + + * configure.in, README: Boosted rev to 1.04. + * configure: Rebuilt. + +Thu Oct 10 10:31:03 1996 Anthony Green + + * configure.in, README: Boosted rev to 1.03. + * configure: Rebuilt. + + * README: Added struct notes. + + * Makefile.am (EXTRA_DIST): Added LICENSE to distribution. + * Makefile.in: Rebuilt. + + * README: Removed Linux section. No special notes now + because aggregates arg/return types work. + +Wed Oct 9 16:16:42 1996 Anthony Green + + * README, configure.in (VERSION): Boosted rev to 1.02 + * configure: Rebuilt. + +Tue Oct 8 11:56:33 1996 Anthony Green + + * README (NOTE): Added n32 notes. + + * Makefile.am: Added test production. + * Makefile: Rebuilt + + * README: spell checked! + + * configure.in (VERSION): Boosted rev to 1.01 + * configure: Rebuilt. + +Mon Oct 7 15:50:22 1996 Anthony Green + + * configure.in: Added nasty bit to support SGI tools. + * configure: Rebuilt. + + * README: Added SGI notes. Added note about automake bug. + +Mon Oct 7 11:00:28 1996 Anthony Green + + * README: Rewrote intro, and fixed examples. + +Fri Oct 4 10:19:55 1996 Anthony Green + + * configure.in: -D$TARGET is no longer used as a compiler switch. + It is now inserted into ffi.h at configure time. + * configure: Rebuilt. + + * FFI_ABI and FFI_STATUS are now ffi_abi and ffi_status. + +Thu Oct 3 13:47:34 1996 Anthony Green + + * README, LICENSE: Created. Wrote some docs. + + * configure.in: Don't barf on i586-unknown-linuxaout. + Added EXTRADIST code for "make dist". + * configure: Rebuilt. + + * */Makefile.in: Rebuilt with patched automake. + +Tue Oct 1 17:12:25 1996 Anthony Green + + * Makefile.am, aclocal.m4, config.guess, config.sub, + configure.in, fficonfig.h.in, install-sh, mkinstalldirs, + stamp-h.in: Created + * Makefile.in, configure: Generated + +--- libffi/include -------------------------------------------------------- + +Tue Feb 24 13:09:36 1998 Anthony Green + + * ffi_mips.h: Updated FFI_TYPE_STRUCT_* values based on + ffi.h.in changes. This is a work-around for SGI's "simple" + assembler. + +Sun Feb 22 00:51:55 1998 Geoff Keating + + * ffi.h.in: PowerPC support. + +1998-02-14 Andreas Schwab + + * ffi.h.in: Add m68k support. + (FFI_TYPE_LONGDOUBLE): Make it a separate value. + +Tue Feb 10 20:55:16 1998 Richard Henderson + + * ffi.h.in (SIZEOF_ARG): Use a pointer type by default. + + * ffi.h.in: Alpha support. + +Fri Nov 22 06:48:45 1996 Anthony Green + + * ffi.h.in, ffi_common.h: Cygnus Support -> Cygnus Solutions. + +Wed Nov 20 22:31:01 1996 Anthony Green + + * ffi.h.in: Added ffi_type_void definition. + +Tue Oct 29 12:22:40 1996 Anthony Green + + * Makefile.am (hack_DATA): Always install ffi_mips.h. + + * ffi.h.in: Removed FFI_DEBUG. It's now in the correct + place (acconfig.h). + Added #include for size_t definition. + +Tue Oct 15 17:23:35 1996 Anthony Green + + * ffi.h.in, ffi_common.h, ffi_mips.h: More clean up. + Commented out #define of FFI_DEBUG. + +Tue Oct 15 13:01:06 1996 Anthony Green + + * ffi_common.h: Added bool definition. + + * ffi.h.in, ffi_common.h: Clean up based on LCLint output. + Added funny /*@...@*/ comments to annotate source. + +Mon Oct 14 12:29:23 1996 Anthony Green + + * ffi.h.in: Interface changes based on feedback from Jim + Blandy. + +Fri Oct 11 16:49:35 1996 Anthony Green + + * ffi.h.in: Small change for sparc support. + +Thu Oct 10 14:53:37 1996 Anthony Green + + * ffi_mips.h: Added FFI_TYPE_STRUCT_* definitions for + special structure return types. + +Wed Oct 9 13:55:57 1996 Anthony Green + + * ffi.h.in: Added SIZEOF_ARG definition for X86 + +Tue Oct 8 11:40:36 1996 Anthony Green + + * ffi.h.in (FFI_FN): Added macro for eliminating compiler warnings. + Use it to case your function pointers to the proper type. + + * ffi_mips.h (SIZEOF_ARG): Added magic to fix type promotion bug. + + * Makefile.am (EXTRA_DIST): Added ffi_mips.h to EXTRA_DIST. + * Makefile: Rebuilt. + + * ffi_mips.h: Created. Moved all common mips definitions here. + +Mon Oct 7 10:58:12 1996 Anthony Green + + * ffi.h.in: The SGI assember is very picky about parens. Redefined + some macros to avoid problems. + + * ffi.h.in: Added FFI_DEFAULT_ABI definitions. Also added + externs for pointer, and 64bit integral ffi_types. + +Fri Oct 4 09:51:37 1996 Anthony Green + + * ffi.h.in: Added FFI_ABI member to ffi_cif and changed + function prototypes accordingly. + Added #define @TARGET@. Now programs including ffi.h don't + have to specify this themselves. + +Thu Oct 3 15:36:44 1996 Anthony Green + + * ffi.h.in: Changed ffi_prep_cif's values from void* to void** + + * Makefile.am (EXTRA_DIST): Added EXTRA_DIST for "make dist" + to work. + * Makefile.in: Regenerated. + +Wed Oct 2 10:16:59 1996 Anthony Green + + * Makefile.am: Created + * Makefile.in: Generated + + * ffi_common.h: Added rcsid comment + +Tue Oct 1 17:13:51 1996 Anthony Green + + * ffi.h.in, ffi_common.h: Created + +--- libffi/src ------------------------------------------------------------ + +Mon Oct 5 02:17:50 1998 Anthony Green + + * arm/ffi.c, arm/sysv.S: Created. + + * Makefile.am: Added arm files. + * Makefile.in: Rebuilt. + +Mon Oct 5 01:41:38 1998 Anthony Green + + * Makefile.am (libffi_la_LDFLAGS): Incremented revision. + +Sun Oct 4 16:27:17 1998 Anthony Green + + * alpha/osf.S (ffi_call_osf): Patch for DU assembler. + + * ffitest.c (main): long long and long double return values work + for x86. + +Fri Apr 17 11:50:58 1998 Anthony Green + + * Makefile.in: Rebuilt. + + * ffitest.c (main): Floating point tests not executed for systems + with broken lond double (SunOS 4 w/ GCC). + + * types.c: Fixed x86 alignment info for long long types. + +Thu Apr 16 07:15:28 1998 Anthony Green + + * ffitest.c: Added more notes about GCC bugs under Irix 6. + +Wed Apr 15 08:42:22 1998 Anthony Green + + * ffitest.c (struct5): New test function. + (main): New test with struct5. + +Thu Mar 5 10:48:11 1998 Anthony Green + + * prep_cif.c (initialize_aggregate): Fix assertion for + nested structures. + +Tue Feb 24 16:33:41 1998 Anthony Green + + * prep_cif.c (ffi_prep_cif): Added long double support for sparc. + +Sun Feb 22 00:52:18 1998 Geoff Keating + + * powerpc/asm.h: New file. + * powerpc/ffi.c: New file. + * powerpc/sysv.S: New file. + * Makefile.am: PowerPC port. + * ffitest.c (main): Allow all tests to run even in presence of gcc + bug on PowerPC. + +1998-02-17 Anthony Green + + * mips/ffi.c: Fixed comment typo. + + * x86/ffi.c (ffi_prep_cif_machdep), x86/sysv.S (retfloat): + Fixed x86 long double return handling. + + * types.c: Fixed x86 long double alignment info. + +1998-02-14 Andreas Schwab + + * types.c: Add m68k support. + + * ffitest.c (floating): Add long double parameter. + (return_ll, ldblit): New functions to test long long and long + double return value. + (main): Fix type error in assignment of ts[1-4]_type.elements. + Add tests for long long and long double arguments and return + values. + + * prep_cif.c (ffi_prep_cif) [M68K]: Don't allocate argument for + struct value pointer. + + * m68k/ffi.c, m68k/sysv.S: New files. + * Makefile.am: Add bits for m68k port. Add kludge to work around + automake deficiency. + (test): Don't require "." in $PATH. + * Makefile.in: Rebuilt. + +Wed Feb 11 07:36:50 1998 Anthony Green + + * Makefile.in: Rebuilt. + +Tue Feb 10 20:56:00 1998 Richard Henderson + + * alpha/ffi.c, alpha/osf.S: New files. + * Makefile.am: Alpha port. + +Tue Nov 18 14:12:07 1997 Anthony Green + + * mips/ffi.c (ffi_prep_cif_machdep): Initialize rstruct_flag + for n32. + +Tue Jun 3 17:18:20 1997 Anthony Green + + * ffitest.c (main): Added hack to get structure tests working + correctly. + +Sat May 10 19:06:42 1997 Tom Tromey + + * Makefile.in: Rebuilt. + * Makefile.am (EXTRA_DIST): Explicitly list all distributable + files in subdirs. + (VERSION, CC): Removed. + +Thu May 8 17:19:01 1997 Anthony Green + + * Makefile.am: Many changes for new automake and libtool. + * Makefile.in: Rebuilt. + +Fri Nov 22 06:57:56 1996 Anthony Green + + * ffitest.c (main): Fixed test case for non mips machines. + +Wed Nov 20 22:31:59 1996 Anthony Green + + * types.c: Added ffi_type_void declaration. + +Tue Oct 29 13:07:19 1996 Anthony Green + + * ffitest.c (main): Fixed character constants. + (main): Emit warning for structure test 3 failure on Sun. + + * Makefile.am (VPATH): Fixed VPATH def'n so automake won't + strip it out. + Moved distdir hack from libffi to automake. + (ffitest): Added missing -c for $(COMPILE) (change in automake). + * Makefile.in: Rebuilt. + +Tue Oct 15 13:08:20 1996 Anthony Green + + * Makefile.am: Added "make lint" production. + * Makefile.in: Rebuilt. + + * prep_cif.c (STACK_ARG_SIZE): Improved STACK_ARG_SIZE macro. + Clean up based on LCLint output. Added funny /*@...@*/ comments to + annotate source. + + * ffitest.c, debug.c: Cleaned up code. + +Mon Oct 14 12:26:56 1996 Anthony Green + + * ffitest.c: Changes based on interface changes. + + * prep_cif.c (ffi_prep_cif): Cleaned up interface based on + feedback from Jim Blandy. + +Fri Oct 11 15:53:18 1996 Anthony Green + + * ffitest.c: Reordered tests while porting to sparc. + Made changes to handle lame structure passing for sparc. + Removed calls to fflush(). + + * prep_cif.c (ffi_prep_cif): Added special case for sparc + aggregate type arguments. + +Thu Oct 10 09:56:51 1996 Anthony Green + + * ffitest.c (main): Added structure passing/returning tests. + + * prep_cif.c (ffi_prep_cif): Perform proper initialization + of structure return types if needed. + (initialize_aggregate): Bug fix + +Wed Oct 9 16:04:20 1996 Anthony Green + + * types.c: Added special definitions for x86 (double doesn't + need double word alignment). + + * ffitest.c: Added many tests + +Tue Oct 8 09:19:22 1996 Anthony Green + + * prep_cif.c (ffi_prep_cif): Fixed assertion. + + * debug.c (ffi_assert): Must return a non void now. + + * Makefile.am: Added test production. + * Makefile: Rebuilt. + + * ffitest.c (main): Created. + + * types.c: Created. Stripped common code out of */ffi.c. + + * prep_cif.c: Added missing stdlib.h include. + + * debug.c (ffi_type_test): Used "a" to eliminate compiler + warnings in non-debug builds. Included ffi_common.h. + +Mon Oct 7 15:36:42 1996 Anthony Green + + * Makefile.am: Added a rule for .s -> .o + This is required by the SGI compiler. + * Makefile: Rebuilt. + +Fri Oct 4 09:51:08 1996 Anthony Green + + * prep_cif.c (initialize_aggregate): Moved abi specification + to ffi_prep_cif(). + +Thu Oct 3 15:37:37 1996 Anthony Green + + * prep_cif.c (ffi_prep_cif): Changed values from void* to void**. + (initialize_aggregate): Fixed aggregate type initialization. + + * Makefile.am (EXTRA_DIST): Added support code for "make dist". + * Makefile.in: Regenerated. + +Wed Oct 2 11:41:57 1996 Anthony Green + + * debug.c, prep_cif: Created. + + * Makefile.am: Added debug.o and prep_cif.o to OBJ. + * Makefile.in: Regenerated. + + * Makefile.am (INCLUDES): Added missing -I../include + * Makefile.in: Regenerated. + +Tue Oct 1 17:11:51 1996 Anthony Green + + * error.c, Makefile.am: Created. + * Makefile.in: Generated. + +--- libffi/src/x86 -------------------------------------------------------- + +Sun Oct 4 16:27:17 1998 Anthony Green + + * sysv.S (retlongdouble): Fixed long long return value support. + * ffi.c (ffi_prep_cif_machdep): Ditto. + +Wed May 13 04:30:33 1998 Anthony Green + + * ffi.c (ffi_prep_cif_machdep): Fixed long double return value + support. + +Wed Apr 15 08:43:20 1998 Anthony Green + + * ffi.c (ffi_prep_args): small struct support was missing. + +Thu May 8 16:53:58 1997 Anthony Green + + * objects.mak: Removed. + +Mon Dec 2 15:12:58 1996 Tom Tromey + + * sysv.S: Use .balign, for a.out Linux boxes. + +Tue Oct 15 13:06:50 1996 Anthony Green + + * ffi.c: Clean up based on LCLint output. + Added funny /*@...@*/ comments to annotate source. + +Fri Oct 11 16:43:38 1996 Anthony Green + + * ffi.c (ffi_call): Added assertion for bad ABIs. + +Wed Oct 9 13:57:27 1996 Anthony Green + + * sysv.S (retdouble): Fixed double return problems. + + * ffi.c (ffi_call): Corrected fn arg definition. + (ffi_prep_cif_machdep): Fixed double return problems + +Tue Oct 8 12:12:49 1996 Anthony Green + + * ffi.c: Moved ffi_type definitions to types.c. + (ffi_prep_args): Fixed type promotion bug. + +Mon Oct 7 15:53:06 1996 Anthony Green + + * ffi.c (FFI_*_TYPEDEF): Removed redundant ';' + +Fri Oct 4 09:54:53 1996 Anthony Green + + * ffi.c (ffi_call): Removed FFI_ABI arg, and swapped + remaining args. + +Wed Oct 2 10:07:05 1996 Anthony Green + + * ffi.c, sysv.S, objects.mak: Created. + (ffi_prep_cif): cif->rvalue no longer initialized to NULL. + (ffi_prep_cif_machdep): Moved machine independent cif processing + to src/prep_cif.c. Introduced ffi_prep_cif_machdep(). + +--- libffi/src/mips ------------------------------------------------------- + +Tue Feb 17 17:18:07 1998 Anthony Green + + * o32.S: Fixed typo in comment. + + * ffi.c (ffi_prep_cif_machdep): Fixed argument processing. + +Thu May 8 16:53:58 1997 Anthony Green + + * o32.s, n32.s: Wrappers for SGI tool support. + + * objects.mak: Removed. + +Tue Oct 29 14:37:45 1996 Anthony Green + + * ffi.c (ffi_prep_args): Changed int z to size_t z. + +Tue Oct 15 13:17:25 1996 Anthony Green + + * n32.S: Fixed bad stack munging. + + * ffi.c: Moved prototypes for ffi_call_?32() to here from + ffi_mips.h because extended_cif is not defined in ffi_mips.h. + +Mon Oct 14 12:42:02 1996 Anthony Green + + * ffi.c: Interface changes based on feedback from Jim Blandy. + +Thu Oct 10 11:22:16 1996 Anthony Green + + * n32.S, ffi.c: Lots of changes to support passing and + returning structures with the n32 calling convention. + + * n32.S: Fixed fn pointer bug. + + * ffi.c (ffi_prep_cif_machdep): Fix for o32 structure + return values. + (ffi_prep_args): Fixed n32 structure passing when structures + partially fit in registers. + +Wed Oct 9 13:49:25 1996 Anthony Green + + * objects.mak: Added n32.o. + + * n32.S: Created. + + * ffi.c (ffi_prep_args): Added magic to support proper + n32 processing. + +Tue Oct 8 10:37:35 1996 Anthony Green + + * ffi.c: Moved ffi_type definitions to types.c. + (ffi_prep_args): Fixed type promotion bug. + + * o32.S: This code is only built for o32 compiles. + A lot of the #define cruft has moved to ffi_mips.h. + + * ffi.c (ffi_prep_cif_machdep): Fixed arg flags. Second arg + is only processed if the first is either a float or double. + +Mon Oct 7 15:33:59 1996 Anthony Green + + * o32.S: Modified to compile under each of o32, n32 and n64. + + * ffi.c (FFI_*_TYPEDEF): Removed redundant ';' + +Fri Oct 4 09:53:25 1996 Anthony Green + + * ffi.c (ffi_call): Removed FFI_ABI arg, and swapped + remaining args. + +Wed Oct 2 17:41:22 1996 Anthony Green + + * o32.S: Removed crufty definitions. + +Wed Oct 2 12:53:42 1996 Anthony Green + + * ffi.c (ffi_prep_cif): cif->rvalue no longer initialized to NULL. + (ffi_prep_cif_machdep): Moved all machine independent cif processing + to src/prep_cif.c. Introduced ffi_prep_cif_machdep. Return types + of FFI_TYPE_STRUCT are no different than FFI_TYPE_INT. + +Tue Oct 1 17:11:02 1996 Anthony Green + + * ffi.c, o32.S, object.mak: Created + +--- libffi/src/sparc ------------------------------------------------------ + +Tue Feb 24 16:33:18 1998 Anthony Green + + * ffi.c (ffi_prep_args): Added long double support. + +Thu May 8 16:53:58 1997 Anthony Green + + * objects.mak: Removed. + +Thu May 1 16:07:56 1997 Anthony Green + + * v8.S: Fixed minor portability problem reported by + Russ McManus . + +Tue Nov 26 14:12:43 1996 Anthony Green + + * v8.S: Used STACKFRAME define elsewhere. + + * ffi.c (ffi_prep_args): Zero out space when USING_PURIFY + is set. + (ffi_prep_cif_machdep): Allocate the correct stack frame + space for functions with < 6 args. + +Tue Oct 29 15:08:55 1996 Anthony Green + + * ffi.c (ffi_prep_args): int z is now size_t z. + +Mon Oct 14 13:31:24 1996 Anthony Green + + * v8.S (ffi_call_V8): Gordon rewrites this again. It looks + great now. + + * ffi.c (ffi_call): The comment about hijacked registers + is no longer valid after gordoni hacked v8.S. + + * v8.S (ffi_call_V8): Rewrote with gordoni. Much simpler. + + * v8.S, ffi.c: ffi_call() had changed to accept more than + two args, so v8.S had to change (because it hijacks incoming + arg registers). + + * ffi.c: Interface changes based on feedback from Jim Blandy. + +Thu Oct 10 17:48:16 1996 Anthony Green + + * ffi.c, v8.S, objects.mak: Created. + + diff --git a/js/src/ctypes/libffi/LICENSE b/js/src/ctypes/libffi/LICENSE new file mode 100644 index 0000000..ec2fd69 --- /dev/null +++ b/js/src/ctypes/libffi/LICENSE @@ -0,0 +1,21 @@ +libffi - Copyright (c) 1996-2009 Anthony Green, Red Hat, Inc and others. +See source files for details. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +``Software''), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/js/src/ctypes/libffi/Makefile.am b/js/src/ctypes/libffi/Makefile.am new file mode 100644 index 0000000..aa4a55c --- /dev/null +++ b/js/src/ctypes/libffi/Makefile.am @@ -0,0 +1,198 @@ +## Process this with automake to create Makefile.in + +AUTOMAKE_OPTIONS = foreign subdir-objects + +SUBDIRS = include testsuite man + +EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj configure.host \ + src/alpha/ffi.c src/alpha/osf.S src/alpha/ffitarget.h \ + src/arm/ffi.c src/arm/sysv.S src/arm/ffitarget.h \ + src/avr32/ffi.c src/avr32/sysv.S src/avr32/ffitarget.h \ + src/cris/ffi.c src/cris/sysv.S src/cris/ffitarget.h \ + src/ia64/ffi.c src/ia64/ffitarget.h src/ia64/ia64_flags.h \ + src/ia64/unix.S \ + src/mips/ffi.c src/mips/n32.S src/mips/o32.S \ + src/mips/ffitarget.h \ + src/m32r/ffi.c src/m32r/sysv.S src/m32r/ffitarget.h \ + src/m68k/ffi.c src/m68k/sysv.S src/m68k/ffitarget.h \ + src/powerpc/ffi.c src/powerpc/sysv.S \ + src/powerpc/linux64.S src/powerpc/linux64_closure.S \ + src/powerpc/ppc_closure.S src/powerpc/asm.h \ + src/powerpc/aix.S src/powerpc/darwin.S \ + src/powerpc/aix_closure.S src/powerpc/darwin_closure.S \ + src/powerpc/ffi_darwin.c src/powerpc/ffitarget.h \ + src/s390/ffi.c src/s390/sysv.S src/s390/ffitarget.h \ + src/sh/ffi.c src/sh/sysv.S src/sh/ffitarget.h \ + src/sh64/ffi.c src/sh64/sysv.S src/sh64/ffitarget.h \ + src/sparc/v8.S src/sparc/v9.S src/sparc/ffitarget.h \ + src/sparc/ffi.c src/x86/darwin64.S \ + src/x86/ffi.c src/x86/sysv.S src/x86/win32.S src/x86/win64.S \ + src/x86/darwin.S src/x86/freebsd.S \ + src/x86/ffi64.c src/x86/unix64.S src/x86/ffitarget.h \ + src/pa/ffitarget.h src/pa/ffi.c src/pa/linux.S src/pa/hpux32.S \ + src/frv/ffi.c src/frv/eabi.S src/frv/ffitarget.h src/dlmalloc.c \ + libtool-version ChangeLog.libffi m4/libtool.m4 \ + m4/lt~obsolete.m4 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 + +info_TEXINFOS = doc/libffi.texi + +## ################################################################ + +## +## This section is for make and multilib madness. +## + +# Work around what appears to be a GNU make bug handling MAKEFLAGS +# values defined in terms of make variables, as is the case for CC and +# friends when we are called from the top level Makefile. +AM_MAKEFLAGS = \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC_FOR_BUILD=$(CC_FOR_BUILD)" \ + "CFLAGS=$(CFLAGS)" \ + "CXXFLAGS=$(CXXFLAGS)" \ + "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \ + "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ + "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \ + "JC1FLAGS=$(JC1FLAGS)" \ + "LDFLAGS=$(LDFLAGS)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \ + "MAKE=$(MAKE)" \ + "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \ + "PICFLAG=$(PICFLAG)" \ + "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \ + "RUNTESTFLAGS=$(RUNTESTFLAGS)" \ + "SHELL=$(SHELL)" \ + "exec_prefix=$(exec_prefix)" \ + "infodir=$(infodir)" \ + "libdir=$(libdir)" \ + "mandir=$(mandir)" \ + "prefix=$(prefix)" \ + "AR=$(AR)" \ + "AS=$(AS)" \ + "CC=$(CC)" \ + "CXX=$(CXX)" \ + "LD=$(LD)" \ + "NM=$(NM)" \ + "RANLIB=$(RANLIB)" \ + "DESTDIR=$(DESTDIR)" + +MAKEOVERRIDES= + +ACLOCAL_AMFLAGS=$(ACLOCAL_AMFLAGS) -I m4 + +lib_LTLIBRARIES = libffi.la +noinst_LTLIBRARIES = libffi_convenience.la + +libffi_la_SOURCES = src/debug.c src/prep_cif.c src/types.c \ + src/raw_api.c src/java_raw_api.c src/closures.c + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libffi.pc + +nodist_libffi_la_SOURCES = + +if MIPS +nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S src/mips/n32.S +endif +if X86 +nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/sysv.S +endif +if X86_FREEBSD +nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/freebsd.S +endif +if X86_WIN32 +nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/win32.S +endif +if X86_WIN64 +nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/win64.S +endif +if X86_DARWIN +nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/darwin.S src/x86/ffi64.c src/x86/darwin64.S +endif +if SPARC +nodist_libffi_la_SOURCES += src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S +endif +if ALPHA +nodist_libffi_la_SOURCES += src/alpha/ffi.c src/alpha/osf.S +endif +if IA64 +nodist_libffi_la_SOURCES += src/ia64/ffi.c src/ia64/unix.S +endif +if M32R +nodist_libffi_la_SOURCES += src/m32r/sysv.S src/m32r/ffi.c +endif +if M68K +nodist_libffi_la_SOURCES += src/m68k/ffi.c src/m68k/sysv.S +endif +if POWERPC +nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S +endif +if POWERPC_AIX +nodist_libffi_la_SOURCES += src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closure.S +endif +if POWERPC_DARWIN +nodist_libffi_la_SOURCES += src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S +endif +if POWERPC_FREEBSD +nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S +endif +if ARM +nodist_libffi_la_SOURCES += src/arm/sysv.S src/arm/ffi.c +endif +if AVR32 +nodist_libffi_la_SOURCES += src/avr32/sysv.S src/avr32/ffi.c +endif +if LIBFFI_CRIS +nodist_libffi_la_SOURCES += src/cris/sysv.S src/cris/ffi.c +endif +if FRV +nodist_libffi_la_SOURCES += src/frv/eabi.S src/frv/ffi.c +endif +if MOXIE +nodist_libffi_la_SOURCES += src/moxie/eabi.S src/moxie/ffi.c +endif +if S390 +nodist_libffi_la_SOURCES += src/s390/sysv.S src/s390/ffi.c +endif +if X86_64 +nodist_libffi_la_SOURCES += src/x86/ffi64.c src/x86/unix64.S src/x86/ffi.c src/x86/sysv.S +endif +if SH +nodist_libffi_la_SOURCES += src/sh/sysv.S src/sh/ffi.c +endif +if SH64 +nodist_libffi_la_SOURCES += src/sh64/sysv.S src/sh64/ffi.c +endif +if PA_LINUX +nodist_libffi_la_SOURCES += src/pa/linux.S src/pa/ffi.c +endif +if PA_HPUX +nodist_libffi_la_SOURCES += src/pa/hpux32.S src/pa/ffi.c +endif + +libffi_convenience_la_SOURCES = $(libffi_la_SOURCES) +nodist_libffi_convenience_la_SOURCES = $(nodist_libffi_la_SOURCES) + +AM_CFLAGS = -Wall -g -fexceptions +if FFI_DEBUG +# Build debug. Define FFI_DEBUG on the commandline so that, when building with +# MSVC, it can link against the debug CRT. +AM_CFLAGS += -DFFI_DEBUG +else +# Build opt. +AM_CFLAGS += -O2 +endif + +libffi_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LTLDFLAGS) $(AM_LTLDFLAGS) + +AM_CPPFLAGS = -I. -I$(top_srcdir)/include -Iinclude -I$(top_srcdir)/src +AM_CCASFLAGS = $(AM_CPPFLAGS) + +# No install-html or install-pdf support in automake yet +.PHONY: install-html install-pdf +install-html: +install-pdf: diff --git a/js/src/ctypes/libffi/Makefile.in b/js/src/ctypes/libffi/Makefile.in new file mode 100644 index 0000000..bc59027 --- /dev/null +++ b/js/src/ctypes/libffi/Makefile.in @@ -0,0 +1,1820 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +@MIPS_TRUE@am__append_1 = src/mips/ffi.c src/mips/o32.S src/mips/n32.S +@X86_TRUE@am__append_2 = src/x86/ffi.c src/x86/sysv.S +@X86_FREEBSD_TRUE@am__append_3 = src/x86/ffi.c src/x86/freebsd.S +@X86_WIN32_TRUE@am__append_4 = src/x86/ffi.c src/x86/win32.S +@X86_WIN64_TRUE@am__append_5 = src/x86/ffi.c src/x86/win64.S +@X86_DARWIN_TRUE@am__append_6 = src/x86/ffi.c src/x86/darwin.S src/x86/ffi64.c src/x86/darwin64.S +@SPARC_TRUE@am__append_7 = src/sparc/ffi.c src/sparc/v8.S src/sparc/v9.S +@ALPHA_TRUE@am__append_8 = src/alpha/ffi.c src/alpha/osf.S +@IA64_TRUE@am__append_9 = src/ia64/ffi.c src/ia64/unix.S +@M32R_TRUE@am__append_10 = src/m32r/sysv.S src/m32r/ffi.c +@M68K_TRUE@am__append_11 = src/m68k/ffi.c src/m68k/sysv.S +@POWERPC_TRUE@am__append_12 = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S +@POWERPC_AIX_TRUE@am__append_13 = src/powerpc/ffi_darwin.c src/powerpc/aix.S src/powerpc/aix_closure.S +@POWERPC_DARWIN_TRUE@am__append_14 = src/powerpc/ffi_darwin.c src/powerpc/darwin.S src/powerpc/darwin_closure.S +@POWERPC_FREEBSD_TRUE@am__append_15 = src/powerpc/ffi.c src/powerpc/sysv.S src/powerpc/ppc_closure.S +@ARM_TRUE@am__append_16 = src/arm/sysv.S src/arm/ffi.c +@AVR32_TRUE@am__append_17 = src/avr32/sysv.S src/avr32/ffi.c +@LIBFFI_CRIS_TRUE@am__append_18 = src/cris/sysv.S src/cris/ffi.c +@FRV_TRUE@am__append_19 = src/frv/eabi.S src/frv/ffi.c +@MOXIE_TRUE@am__append_20 = src/moxie/eabi.S src/moxie/ffi.c +@S390_TRUE@am__append_21 = src/s390/sysv.S src/s390/ffi.c +@X86_64_TRUE@am__append_22 = src/x86/ffi64.c src/x86/unix64.S src/x86/ffi.c src/x86/sysv.S +@SH_TRUE@am__append_23 = src/sh/sysv.S src/sh/ffi.c +@SH64_TRUE@am__append_24 = src/sh64/sysv.S src/sh64/ffi.c +@PA_LINUX_TRUE@am__append_25 = src/pa/linux.S src/pa/ffi.c +@PA_HPUX_TRUE@am__append_26 = src/pa/hpux32.S src/pa/ffi.c +# Build debug. Define FFI_DEBUG on the commandline so that, when building with +# MSVC, it can link against the debug CRT. +@FFI_DEBUG_TRUE@am__append_27 = -DFFI_DEBUG +# Build opt. +@FFI_DEBUG_FALSE@am__append_28 = -O2 +subdir = . +DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/doc/stamp-vti \ + $(srcdir)/doc/version.texi $(srcdir)/fficonfig.h.in \ + $(srcdir)/libffi.pc.in $(top_srcdir)/configure ChangeLog \ + compile config.guess config.sub depcomp install-sh ltmain.sh \ + mdate-sh missing texinfo.tex +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = fficonfig.h +CONFIG_CLEAN_FILES = libffi.pc +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(infodir)" \ + "$(DESTDIR)$(pkgconfigdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) +libffi_la_LIBADD = +am__dirstamp = $(am__leading_dot)dirstamp +am_libffi_la_OBJECTS = src/debug.lo src/prep_cif.lo src/types.lo \ + src/raw_api.lo src/java_raw_api.lo src/closures.lo +@MIPS_TRUE@am__objects_1 = src/mips/ffi.lo src/mips/o32.lo \ +@MIPS_TRUE@ src/mips/n32.lo +@X86_TRUE@am__objects_2 = src/x86/ffi.lo src/x86/sysv.lo +@X86_FREEBSD_TRUE@am__objects_3 = src/x86/ffi.lo src/x86/freebsd.lo +@X86_WIN32_TRUE@am__objects_4 = src/x86/ffi.lo src/x86/win32.lo +@X86_WIN64_TRUE@am__objects_5 = src/x86/ffi.lo src/x86/win64.lo +@X86_DARWIN_TRUE@am__objects_6 = src/x86/ffi.lo src/x86/darwin.lo \ +@X86_DARWIN_TRUE@ src/x86/ffi64.lo src/x86/darwin64.lo +@SPARC_TRUE@am__objects_7 = src/sparc/ffi.lo src/sparc/v8.lo \ +@SPARC_TRUE@ src/sparc/v9.lo +@ALPHA_TRUE@am__objects_8 = src/alpha/ffi.lo src/alpha/osf.lo +@IA64_TRUE@am__objects_9 = src/ia64/ffi.lo src/ia64/unix.lo +@M32R_TRUE@am__objects_10 = src/m32r/sysv.lo src/m32r/ffi.lo +@M68K_TRUE@am__objects_11 = src/m68k/ffi.lo src/m68k/sysv.lo +@POWERPC_TRUE@am__objects_12 = src/powerpc/ffi.lo src/powerpc/sysv.lo \ +@POWERPC_TRUE@ src/powerpc/ppc_closure.lo \ +@POWERPC_TRUE@ src/powerpc/linux64.lo \ +@POWERPC_TRUE@ src/powerpc/linux64_closure.lo +@POWERPC_AIX_TRUE@am__objects_13 = src/powerpc/ffi_darwin.lo \ +@POWERPC_AIX_TRUE@ src/powerpc/aix.lo \ +@POWERPC_AIX_TRUE@ src/powerpc/aix_closure.lo +@POWERPC_DARWIN_TRUE@am__objects_14 = src/powerpc/ffi_darwin.lo \ +@POWERPC_DARWIN_TRUE@ src/powerpc/darwin.lo \ +@POWERPC_DARWIN_TRUE@ src/powerpc/darwin_closure.lo +@POWERPC_FREEBSD_TRUE@am__objects_15 = src/powerpc/ffi.lo \ +@POWERPC_FREEBSD_TRUE@ src/powerpc/sysv.lo \ +@POWERPC_FREEBSD_TRUE@ src/powerpc/ppc_closure.lo +@ARM_TRUE@am__objects_16 = src/arm/sysv.lo src/arm/ffi.lo +@AVR32_TRUE@am__objects_17 = src/avr32/sysv.lo src/avr32/ffi.lo +@LIBFFI_CRIS_TRUE@am__objects_18 = src/cris/sysv.lo src/cris/ffi.lo +@FRV_TRUE@am__objects_19 = src/frv/eabi.lo src/frv/ffi.lo +@MOXIE_TRUE@am__objects_20 = src/moxie/eabi.lo src/moxie/ffi.lo +@S390_TRUE@am__objects_21 = src/s390/sysv.lo src/s390/ffi.lo +@X86_64_TRUE@am__objects_22 = src/x86/ffi64.lo src/x86/unix64.lo \ +@X86_64_TRUE@ src/x86/ffi.lo src/x86/sysv.lo +@SH_TRUE@am__objects_23 = src/sh/sysv.lo src/sh/ffi.lo +@SH64_TRUE@am__objects_24 = src/sh64/sysv.lo src/sh64/ffi.lo +@PA_LINUX_TRUE@am__objects_25 = src/pa/linux.lo src/pa/ffi.lo +@PA_HPUX_TRUE@am__objects_26 = src/pa/hpux32.lo src/pa/ffi.lo +nodist_libffi_la_OBJECTS = $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) $(am__objects_4) $(am__objects_5) \ + $(am__objects_6) $(am__objects_7) $(am__objects_8) \ + $(am__objects_9) $(am__objects_10) $(am__objects_11) \ + $(am__objects_12) $(am__objects_13) $(am__objects_14) \ + $(am__objects_15) $(am__objects_16) $(am__objects_17) \ + $(am__objects_18) $(am__objects_19) $(am__objects_20) \ + $(am__objects_21) $(am__objects_22) $(am__objects_23) \ + $(am__objects_24) $(am__objects_25) $(am__objects_26) +libffi_la_OBJECTS = $(am_libffi_la_OBJECTS) \ + $(nodist_libffi_la_OBJECTS) +libffi_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libffi_la_LDFLAGS) $(LDFLAGS) -o $@ +libffi_convenience_la_LIBADD = +am__objects_27 = src/debug.lo src/prep_cif.lo src/types.lo \ + src/raw_api.lo src/java_raw_api.lo src/closures.lo +am_libffi_convenience_la_OBJECTS = $(am__objects_27) +am__objects_28 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \ + $(am__objects_4) $(am__objects_5) $(am__objects_6) \ + $(am__objects_7) $(am__objects_8) $(am__objects_9) \ + $(am__objects_10) $(am__objects_11) $(am__objects_12) \ + $(am__objects_13) $(am__objects_14) $(am__objects_15) \ + $(am__objects_16) $(am__objects_17) $(am__objects_18) \ + $(am__objects_19) $(am__objects_20) $(am__objects_21) \ + $(am__objects_22) $(am__objects_23) $(am__objects_24) \ + $(am__objects_25) $(am__objects_26) +nodist_libffi_convenience_la_OBJECTS = $(am__objects_28) +libffi_convenience_la_OBJECTS = $(am_libffi_convenience_la_OBJECTS) \ + $(nodist_libffi_convenience_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CPPASCOMPILE = $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) +LTCPPASCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libffi_la_SOURCES) $(nodist_libffi_la_SOURCES) \ + $(libffi_convenience_la_SOURCES) \ + $(nodist_libffi_convenience_la_SOURCES) +DIST_SOURCES = $(libffi_la_SOURCES) $(libffi_convenience_la_SOURCES) +INFO_DEPS = +am__TEXINFO_TEX_DIR = $(srcdir) +DVIS = doc/libffi.dvi +PDFS = doc/libffi.pdf +PSS = doc/libffi.ps +HTMLS = doc/libffi.html +TEXINFOS = doc/libffi.texi +TEXI2DVI = texi2dvi +TEXI2PDF = $(TEXI2DVI) --pdf --batch +MAKEINFOHTML = $(MAKEINFO) --html +AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS) +DVIPS = dvips +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +DATA = $(pkgconfig_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir dist dist-all distcheck +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d "$(distdir)" \ + || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr "$(distdir)"; }; } +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_LTLDFLAGS = @AM_LTLDFLAGS@ +AM_RUNTESTFLAGS = @AM_RUNTESTFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_LONG_DOUBLE = @HAVE_LONG_DOUBLE@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TARGET = @TARGET@ +TARGETDIR = @TARGETDIR@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +toolexecdir = @toolexecdir@ +toolexeclibdir = @toolexeclibdir@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign subdir-objects +SUBDIRS = include testsuite man +EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj configure.host \ + src/alpha/ffi.c src/alpha/osf.S src/alpha/ffitarget.h \ + src/arm/ffi.c src/arm/sysv.S src/arm/ffitarget.h \ + src/avr32/ffi.c src/avr32/sysv.S src/avr32/ffitarget.h \ + src/cris/ffi.c src/cris/sysv.S src/cris/ffitarget.h \ + src/ia64/ffi.c src/ia64/ffitarget.h src/ia64/ia64_flags.h \ + src/ia64/unix.S \ + src/mips/ffi.c src/mips/n32.S src/mips/o32.S \ + src/mips/ffitarget.h \ + src/m32r/ffi.c src/m32r/sysv.S src/m32r/ffitarget.h \ + src/m68k/ffi.c src/m68k/sysv.S src/m68k/ffitarget.h \ + src/powerpc/ffi.c src/powerpc/sysv.S \ + src/powerpc/linux64.S src/powerpc/linux64_closure.S \ + src/powerpc/ppc_closure.S src/powerpc/asm.h \ + src/powerpc/aix.S src/powerpc/darwin.S \ + src/powerpc/aix_closure.S src/powerpc/darwin_closure.S \ + src/powerpc/ffi_darwin.c src/powerpc/ffitarget.h \ + src/s390/ffi.c src/s390/sysv.S src/s390/ffitarget.h \ + src/sh/ffi.c src/sh/sysv.S src/sh/ffitarget.h \ + src/sh64/ffi.c src/sh64/sysv.S src/sh64/ffitarget.h \ + src/sparc/v8.S src/sparc/v9.S src/sparc/ffitarget.h \ + src/sparc/ffi.c src/x86/darwin64.S \ + src/x86/ffi.c src/x86/sysv.S src/x86/win32.S src/x86/win64.S \ + src/x86/darwin.S src/x86/freebsd.S \ + src/x86/ffi64.c src/x86/unix64.S src/x86/ffitarget.h \ + src/pa/ffitarget.h src/pa/ffi.c src/pa/linux.S src/pa/hpux32.S \ + src/frv/ffi.c src/frv/eabi.S src/frv/ffitarget.h src/dlmalloc.c \ + libtool-version ChangeLog.libffi m4/libtool.m4 \ + m4/lt~obsolete.m4 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 + +info_TEXINFOS = doc/libffi.texi + +# Work around what appears to be a GNU make bug handling MAKEFLAGS +# values defined in terms of make variables, as is the case for CC and +# friends when we are called from the top level Makefile. +AM_MAKEFLAGS = \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC_FOR_BUILD=$(CC_FOR_BUILD)" \ + "CFLAGS=$(CFLAGS)" \ + "CXXFLAGS=$(CXXFLAGS)" \ + "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \ + "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ + "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \ + "JC1FLAGS=$(JC1FLAGS)" \ + "LDFLAGS=$(LDFLAGS)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \ + "MAKE=$(MAKE)" \ + "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \ + "PICFLAG=$(PICFLAG)" \ + "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \ + "RUNTESTFLAGS=$(RUNTESTFLAGS)" \ + "SHELL=$(SHELL)" \ + "exec_prefix=$(exec_prefix)" \ + "infodir=$(infodir)" \ + "libdir=$(libdir)" \ + "mandir=$(mandir)" \ + "prefix=$(prefix)" \ + "AR=$(AR)" \ + "AS=$(AS)" \ + "CC=$(CC)" \ + "CXX=$(CXX)" \ + "LD=$(LD)" \ + "NM=$(NM)" \ + "RANLIB=$(RANLIB)" \ + "DESTDIR=$(DESTDIR)" + +MAKEOVERRIDES = +ACLOCAL_AMFLAGS = $(ACLOCAL_AMFLAGS) -I m4 +lib_LTLIBRARIES = libffi.la +noinst_LTLIBRARIES = libffi_convenience.la +libffi_la_SOURCES = src/debug.c src/prep_cif.c src/types.c \ + src/raw_api.c src/java_raw_api.c src/closures.c + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libffi.pc +nodist_libffi_la_SOURCES = $(am__append_1) $(am__append_2) \ + $(am__append_3) $(am__append_4) $(am__append_5) \ + $(am__append_6) $(am__append_7) $(am__append_8) \ + $(am__append_9) $(am__append_10) $(am__append_11) \ + $(am__append_12) $(am__append_13) $(am__append_14) \ + $(am__append_15) $(am__append_16) $(am__append_17) \ + $(am__append_18) $(am__append_19) $(am__append_20) \ + $(am__append_21) $(am__append_22) $(am__append_23) \ + $(am__append_24) $(am__append_25) $(am__append_26) +libffi_convenience_la_SOURCES = $(libffi_la_SOURCES) +nodist_libffi_convenience_la_SOURCES = $(nodist_libffi_la_SOURCES) +AM_CFLAGS = -Wall -g -fexceptions $(am__append_27) $(am__append_28) +libffi_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LTLDFLAGS) $(AM_LTLDFLAGS) +AM_CPPFLAGS = -I. -I$(top_srcdir)/include -Iinclude -I$(top_srcdir)/src +AM_CCASFLAGS = $(AM_CPPFLAGS) +all: fficonfig.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +.SUFFIXES: .S .c .dvi .lo .o .obj .ps +am--refresh: + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +fficonfig.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/fficonfig.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status fficonfig.h +$(srcdir)/fficonfig.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f fficonfig.h stamp-h1 +libffi.pc: $(top_builddir)/config.status $(srcdir)/libffi.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +src/$(am__dirstamp): + @$(MKDIR_P) src + @: > src/$(am__dirstamp) +src/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/$(DEPDIR) + @: > src/$(DEPDIR)/$(am__dirstamp) +src/debug.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) +src/prep_cif.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) +src/types.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) +src/raw_api.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) +src/java_raw_api.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) +src/closures.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) +src/mips/$(am__dirstamp): + @$(MKDIR_P) src/mips + @: > src/mips/$(am__dirstamp) +src/mips/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/mips/$(DEPDIR) + @: > src/mips/$(DEPDIR)/$(am__dirstamp) +src/mips/ffi.lo: src/mips/$(am__dirstamp) \ + src/mips/$(DEPDIR)/$(am__dirstamp) +src/mips/o32.lo: src/mips/$(am__dirstamp) \ + src/mips/$(DEPDIR)/$(am__dirstamp) +src/mips/n32.lo: src/mips/$(am__dirstamp) \ + src/mips/$(DEPDIR)/$(am__dirstamp) +src/x86/$(am__dirstamp): + @$(MKDIR_P) src/x86 + @: > src/x86/$(am__dirstamp) +src/x86/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/x86/$(DEPDIR) + @: > src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/ffi.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/sysv.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/freebsd.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/win32.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/win64.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/darwin.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/ffi64.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/x86/darwin64.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/sparc/$(am__dirstamp): + @$(MKDIR_P) src/sparc + @: > src/sparc/$(am__dirstamp) +src/sparc/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/sparc/$(DEPDIR) + @: > src/sparc/$(DEPDIR)/$(am__dirstamp) +src/sparc/ffi.lo: src/sparc/$(am__dirstamp) \ + src/sparc/$(DEPDIR)/$(am__dirstamp) +src/sparc/v8.lo: src/sparc/$(am__dirstamp) \ + src/sparc/$(DEPDIR)/$(am__dirstamp) +src/sparc/v9.lo: src/sparc/$(am__dirstamp) \ + src/sparc/$(DEPDIR)/$(am__dirstamp) +src/alpha/$(am__dirstamp): + @$(MKDIR_P) src/alpha + @: > src/alpha/$(am__dirstamp) +src/alpha/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/alpha/$(DEPDIR) + @: > src/alpha/$(DEPDIR)/$(am__dirstamp) +src/alpha/ffi.lo: src/alpha/$(am__dirstamp) \ + src/alpha/$(DEPDIR)/$(am__dirstamp) +src/alpha/osf.lo: src/alpha/$(am__dirstamp) \ + src/alpha/$(DEPDIR)/$(am__dirstamp) +src/ia64/$(am__dirstamp): + @$(MKDIR_P) src/ia64 + @: > src/ia64/$(am__dirstamp) +src/ia64/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/ia64/$(DEPDIR) + @: > src/ia64/$(DEPDIR)/$(am__dirstamp) +src/ia64/ffi.lo: src/ia64/$(am__dirstamp) \ + src/ia64/$(DEPDIR)/$(am__dirstamp) +src/ia64/unix.lo: src/ia64/$(am__dirstamp) \ + src/ia64/$(DEPDIR)/$(am__dirstamp) +src/m32r/$(am__dirstamp): + @$(MKDIR_P) src/m32r + @: > src/m32r/$(am__dirstamp) +src/m32r/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/m32r/$(DEPDIR) + @: > src/m32r/$(DEPDIR)/$(am__dirstamp) +src/m32r/sysv.lo: src/m32r/$(am__dirstamp) \ + src/m32r/$(DEPDIR)/$(am__dirstamp) +src/m32r/ffi.lo: src/m32r/$(am__dirstamp) \ + src/m32r/$(DEPDIR)/$(am__dirstamp) +src/m68k/$(am__dirstamp): + @$(MKDIR_P) src/m68k + @: > src/m68k/$(am__dirstamp) +src/m68k/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/m68k/$(DEPDIR) + @: > src/m68k/$(DEPDIR)/$(am__dirstamp) +src/m68k/ffi.lo: src/m68k/$(am__dirstamp) \ + src/m68k/$(DEPDIR)/$(am__dirstamp) +src/m68k/sysv.lo: src/m68k/$(am__dirstamp) \ + src/m68k/$(DEPDIR)/$(am__dirstamp) +src/powerpc/$(am__dirstamp): + @$(MKDIR_P) src/powerpc + @: > src/powerpc/$(am__dirstamp) +src/powerpc/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/powerpc/$(DEPDIR) + @: > src/powerpc/$(DEPDIR)/$(am__dirstamp) +src/powerpc/ffi.lo: src/powerpc/$(am__dirstamp) \ + src/powerpc/$(DEPDIR)/$(am__dirstamp) +src/powerpc/sysv.lo: src/powerpc/$(am__dirstamp) \ + src/powerpc/$(DEPDIR)/$(am__dirstamp) +src/powerpc/ppc_closure.lo: src/powerpc/$(am__dirstamp) \ + src/powerpc/$(DEPDIR)/$(am__dirstamp) +src/powerpc/linux64.lo: src/powerpc/$(am__dirstamp) \ + src/powerpc/$(DEPDIR)/$(am__dirstamp) +src/powerpc/linux64_closure.lo: src/powerpc/$(am__dirstamp) \ + src/powerpc/$(DEPDIR)/$(am__dirstamp) +src/powerpc/ffi_darwin.lo: src/powerpc/$(am__dirstamp) \ + src/powerpc/$(DEPDIR)/$(am__dirstamp) +src/powerpc/aix.lo: src/powerpc/$(am__dirstamp) \ + src/powerpc/$(DEPDIR)/$(am__dirstamp) +src/powerpc/aix_closure.lo: src/powerpc/$(am__dirstamp) \ + src/powerpc/$(DEPDIR)/$(am__dirstamp) +src/powerpc/darwin.lo: src/powerpc/$(am__dirstamp) \ + src/powerpc/$(DEPDIR)/$(am__dirstamp) +src/powerpc/darwin_closure.lo: src/powerpc/$(am__dirstamp) \ + src/powerpc/$(DEPDIR)/$(am__dirstamp) +src/arm/$(am__dirstamp): + @$(MKDIR_P) src/arm + @: > src/arm/$(am__dirstamp) +src/arm/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/arm/$(DEPDIR) + @: > src/arm/$(DEPDIR)/$(am__dirstamp) +src/arm/sysv.lo: src/arm/$(am__dirstamp) \ + src/arm/$(DEPDIR)/$(am__dirstamp) +src/arm/ffi.lo: src/arm/$(am__dirstamp) \ + src/arm/$(DEPDIR)/$(am__dirstamp) +src/avr32/$(am__dirstamp): + @$(MKDIR_P) src/avr32 + @: > src/avr32/$(am__dirstamp) +src/avr32/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/avr32/$(DEPDIR) + @: > src/avr32/$(DEPDIR)/$(am__dirstamp) +src/avr32/sysv.lo: src/avr32/$(am__dirstamp) \ + src/avr32/$(DEPDIR)/$(am__dirstamp) +src/avr32/ffi.lo: src/avr32/$(am__dirstamp) \ + src/avr32/$(DEPDIR)/$(am__dirstamp) +src/cris/$(am__dirstamp): + @$(MKDIR_P) src/cris + @: > src/cris/$(am__dirstamp) +src/cris/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/cris/$(DEPDIR) + @: > src/cris/$(DEPDIR)/$(am__dirstamp) +src/cris/sysv.lo: src/cris/$(am__dirstamp) \ + src/cris/$(DEPDIR)/$(am__dirstamp) +src/cris/ffi.lo: src/cris/$(am__dirstamp) \ + src/cris/$(DEPDIR)/$(am__dirstamp) +src/frv/$(am__dirstamp): + @$(MKDIR_P) src/frv + @: > src/frv/$(am__dirstamp) +src/frv/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/frv/$(DEPDIR) + @: > src/frv/$(DEPDIR)/$(am__dirstamp) +src/frv/eabi.lo: src/frv/$(am__dirstamp) \ + src/frv/$(DEPDIR)/$(am__dirstamp) +src/frv/ffi.lo: src/frv/$(am__dirstamp) \ + src/frv/$(DEPDIR)/$(am__dirstamp) +src/moxie/$(am__dirstamp): + @$(MKDIR_P) src/moxie + @: > src/moxie/$(am__dirstamp) +src/moxie/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/moxie/$(DEPDIR) + @: > src/moxie/$(DEPDIR)/$(am__dirstamp) +src/moxie/eabi.lo: src/moxie/$(am__dirstamp) \ + src/moxie/$(DEPDIR)/$(am__dirstamp) +src/moxie/ffi.lo: src/moxie/$(am__dirstamp) \ + src/moxie/$(DEPDIR)/$(am__dirstamp) +src/s390/$(am__dirstamp): + @$(MKDIR_P) src/s390 + @: > src/s390/$(am__dirstamp) +src/s390/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/s390/$(DEPDIR) + @: > src/s390/$(DEPDIR)/$(am__dirstamp) +src/s390/sysv.lo: src/s390/$(am__dirstamp) \ + src/s390/$(DEPDIR)/$(am__dirstamp) +src/s390/ffi.lo: src/s390/$(am__dirstamp) \ + src/s390/$(DEPDIR)/$(am__dirstamp) +src/x86/unix64.lo: src/x86/$(am__dirstamp) \ + src/x86/$(DEPDIR)/$(am__dirstamp) +src/sh/$(am__dirstamp): + @$(MKDIR_P) src/sh + @: > src/sh/$(am__dirstamp) +src/sh/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/sh/$(DEPDIR) + @: > src/sh/$(DEPDIR)/$(am__dirstamp) +src/sh/sysv.lo: src/sh/$(am__dirstamp) \ + src/sh/$(DEPDIR)/$(am__dirstamp) +src/sh/ffi.lo: src/sh/$(am__dirstamp) src/sh/$(DEPDIR)/$(am__dirstamp) +src/sh64/$(am__dirstamp): + @$(MKDIR_P) src/sh64 + @: > src/sh64/$(am__dirstamp) +src/sh64/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/sh64/$(DEPDIR) + @: > src/sh64/$(DEPDIR)/$(am__dirstamp) +src/sh64/sysv.lo: src/sh64/$(am__dirstamp) \ + src/sh64/$(DEPDIR)/$(am__dirstamp) +src/sh64/ffi.lo: src/sh64/$(am__dirstamp) \ + src/sh64/$(DEPDIR)/$(am__dirstamp) +src/pa/$(am__dirstamp): + @$(MKDIR_P) src/pa + @: > src/pa/$(am__dirstamp) +src/pa/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/pa/$(DEPDIR) + @: > src/pa/$(DEPDIR)/$(am__dirstamp) +src/pa/linux.lo: src/pa/$(am__dirstamp) \ + src/pa/$(DEPDIR)/$(am__dirstamp) +src/pa/ffi.lo: src/pa/$(am__dirstamp) src/pa/$(DEPDIR)/$(am__dirstamp) +src/pa/hpux32.lo: src/pa/$(am__dirstamp) \ + src/pa/$(DEPDIR)/$(am__dirstamp) +libffi.la: $(libffi_la_OBJECTS) $(libffi_la_DEPENDENCIES) + $(libffi_la_LINK) -rpath $(libdir) $(libffi_la_OBJECTS) $(libffi_la_LIBADD) $(LIBS) +libffi_convenience.la: $(libffi_convenience_la_OBJECTS) $(libffi_convenience_la_DEPENDENCIES) + $(LINK) $(libffi_convenience_la_OBJECTS) $(libffi_convenience_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f src/alpha/ffi.$(OBJEXT) + -rm -f src/alpha/ffi.lo + -rm -f src/alpha/osf.$(OBJEXT) + -rm -f src/alpha/osf.lo + -rm -f src/arm/ffi.$(OBJEXT) + -rm -f src/arm/ffi.lo + -rm -f src/arm/sysv.$(OBJEXT) + -rm -f src/arm/sysv.lo + -rm -f src/avr32/ffi.$(OBJEXT) + -rm -f src/avr32/ffi.lo + -rm -f src/avr32/sysv.$(OBJEXT) + -rm -f src/avr32/sysv.lo + -rm -f src/closures.$(OBJEXT) + -rm -f src/closures.lo + -rm -f src/cris/ffi.$(OBJEXT) + -rm -f src/cris/ffi.lo + -rm -f src/cris/sysv.$(OBJEXT) + -rm -f src/cris/sysv.lo + -rm -f src/debug.$(OBJEXT) + -rm -f src/debug.lo + -rm -f src/frv/eabi.$(OBJEXT) + -rm -f src/frv/eabi.lo + -rm -f src/frv/ffi.$(OBJEXT) + -rm -f src/frv/ffi.lo + -rm -f src/ia64/ffi.$(OBJEXT) + -rm -f src/ia64/ffi.lo + -rm -f src/ia64/unix.$(OBJEXT) + -rm -f src/ia64/unix.lo + -rm -f src/java_raw_api.$(OBJEXT) + -rm -f src/java_raw_api.lo + -rm -f src/m32r/ffi.$(OBJEXT) + -rm -f src/m32r/ffi.lo + -rm -f src/m32r/sysv.$(OBJEXT) + -rm -f src/m32r/sysv.lo + -rm -f src/m68k/ffi.$(OBJEXT) + -rm -f src/m68k/ffi.lo + -rm -f src/m68k/sysv.$(OBJEXT) + -rm -f src/m68k/sysv.lo + -rm -f src/mips/ffi.$(OBJEXT) + -rm -f src/mips/ffi.lo + -rm -f src/mips/n32.$(OBJEXT) + -rm -f src/mips/n32.lo + -rm -f src/mips/o32.$(OBJEXT) + -rm -f src/mips/o32.lo + -rm -f src/moxie/eabi.$(OBJEXT) + -rm -f src/moxie/eabi.lo + -rm -f src/moxie/ffi.$(OBJEXT) + -rm -f src/moxie/ffi.lo + -rm -f src/pa/ffi.$(OBJEXT) + -rm -f src/pa/ffi.lo + -rm -f src/pa/hpux32.$(OBJEXT) + -rm -f src/pa/hpux32.lo + -rm -f src/pa/linux.$(OBJEXT) + -rm -f src/pa/linux.lo + -rm -f src/powerpc/aix.$(OBJEXT) + -rm -f src/powerpc/aix.lo + -rm -f src/powerpc/aix_closure.$(OBJEXT) + -rm -f src/powerpc/aix_closure.lo + -rm -f src/powerpc/darwin.$(OBJEXT) + -rm -f src/powerpc/darwin.lo + -rm -f src/powerpc/darwin_closure.$(OBJEXT) + -rm -f src/powerpc/darwin_closure.lo + -rm -f src/powerpc/ffi.$(OBJEXT) + -rm -f src/powerpc/ffi.lo + -rm -f src/powerpc/ffi_darwin.$(OBJEXT) + -rm -f src/powerpc/ffi_darwin.lo + -rm -f src/powerpc/linux64.$(OBJEXT) + -rm -f src/powerpc/linux64.lo + -rm -f src/powerpc/linux64_closure.$(OBJEXT) + -rm -f src/powerpc/linux64_closure.lo + -rm -f src/powerpc/ppc_closure.$(OBJEXT) + -rm -f src/powerpc/ppc_closure.lo + -rm -f src/powerpc/sysv.$(OBJEXT) + -rm -f src/powerpc/sysv.lo + -rm -f src/prep_cif.$(OBJEXT) + -rm -f src/prep_cif.lo + -rm -f src/raw_api.$(OBJEXT) + -rm -f src/raw_api.lo + -rm -f src/s390/ffi.$(OBJEXT) + -rm -f src/s390/ffi.lo + -rm -f src/s390/sysv.$(OBJEXT) + -rm -f src/s390/sysv.lo + -rm -f src/sh/ffi.$(OBJEXT) + -rm -f src/sh/ffi.lo + -rm -f src/sh/sysv.$(OBJEXT) + -rm -f src/sh/sysv.lo + -rm -f src/sh64/ffi.$(OBJEXT) + -rm -f src/sh64/ffi.lo + -rm -f src/sh64/sysv.$(OBJEXT) + -rm -f src/sh64/sysv.lo + -rm -f src/sparc/ffi.$(OBJEXT) + -rm -f src/sparc/ffi.lo + -rm -f src/sparc/v8.$(OBJEXT) + -rm -f src/sparc/v8.lo + -rm -f src/sparc/v9.$(OBJEXT) + -rm -f src/sparc/v9.lo + -rm -f src/types.$(OBJEXT) + -rm -f src/types.lo + -rm -f src/x86/darwin.$(OBJEXT) + -rm -f src/x86/darwin.lo + -rm -f src/x86/darwin64.$(OBJEXT) + -rm -f src/x86/darwin64.lo + -rm -f src/x86/ffi.$(OBJEXT) + -rm -f src/x86/ffi.lo + -rm -f src/x86/ffi64.$(OBJEXT) + -rm -f src/x86/ffi64.lo + -rm -f src/x86/freebsd.$(OBJEXT) + -rm -f src/x86/freebsd.lo + -rm -f src/x86/sysv.$(OBJEXT) + -rm -f src/x86/sysv.lo + -rm -f src/x86/unix64.$(OBJEXT) + -rm -f src/x86/unix64.lo + -rm -f src/x86/win32.$(OBJEXT) + -rm -f src/x86/win32.lo + -rm -f src/x86/win64.$(OBJEXT) + -rm -f src/x86/win64.lo + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/closures.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/debug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/java_raw_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/prep_cif.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/raw_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/types.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/alpha/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/alpha/$(DEPDIR)/osf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/arm/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/arm/$(DEPDIR)/sysv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/avr32/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/avr32/$(DEPDIR)/sysv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/cris/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/cris/$(DEPDIR)/sysv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/frv/$(DEPDIR)/eabi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/frv/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/ia64/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/ia64/$(DEPDIR)/unix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/m32r/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/m32r/$(DEPDIR)/sysv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/m68k/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/m68k/$(DEPDIR)/sysv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/mips/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/mips/$(DEPDIR)/n32.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/mips/$(DEPDIR)/o32.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/moxie/$(DEPDIR)/eabi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/moxie/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/pa/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/pa/$(DEPDIR)/hpux32.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/pa/$(DEPDIR)/linux.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/powerpc/$(DEPDIR)/aix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/powerpc/$(DEPDIR)/aix_closure.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/powerpc/$(DEPDIR)/darwin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/powerpc/$(DEPDIR)/darwin_closure.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/powerpc/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/powerpc/$(DEPDIR)/ffi_darwin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/powerpc/$(DEPDIR)/linux64.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/powerpc/$(DEPDIR)/linux64_closure.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/powerpc/$(DEPDIR)/ppc_closure.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/powerpc/$(DEPDIR)/sysv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/s390/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/s390/$(DEPDIR)/sysv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/sh/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/sh/$(DEPDIR)/sysv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/sh64/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/sh64/$(DEPDIR)/sysv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/sparc/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/sparc/$(DEPDIR)/v8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/sparc/$(DEPDIR)/v9.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/darwin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/darwin64.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/ffi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/ffi64.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/freebsd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/sysv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/unix64.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/win32.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/win64.Plo@am__quote@ + +%.o: %.S +@am__fastdepCCAS_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCCAS_TRUE@ $(CPPASCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCCAS_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCCAS_FALSE@ $(CPPASCOMPILE) -c -o $@ $< + +%.obj: %.S +@am__fastdepCCAS_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCCAS_TRUE@ $(CPPASCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCCAS_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCCAS_FALSE@ $(CPPASCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +%.lo: %.S +@am__fastdepCCAS_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCCAS_TRUE@ $(LTCPPASCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCCAS_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCCAS_FALSE@ $(LTCPPASCOMPILE) -c -o $@ $< + +%.o: %.c +@am__fastdepCC_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c -o $@ $< + +%.obj: %.c +@am__fastdepCC_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +%.lo: %.c +@am__fastdepCC_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf src/.libs src/_libs + -rm -rf src/alpha/.libs src/alpha/_libs + -rm -rf src/arm/.libs src/arm/_libs + -rm -rf src/avr32/.libs src/avr32/_libs + -rm -rf src/cris/.libs src/cris/_libs + -rm -rf src/frv/.libs src/frv/_libs + -rm -rf src/ia64/.libs src/ia64/_libs + -rm -rf src/m32r/.libs src/m32r/_libs + -rm -rf src/m68k/.libs src/m68k/_libs + -rm -rf src/mips/.libs src/mips/_libs + -rm -rf src/moxie/.libs src/moxie/_libs + -rm -rf src/pa/.libs src/pa/_libs + -rm -rf src/powerpc/.libs src/powerpc/_libs + -rm -rf src/s390/.libs src/s390/_libs + -rm -rf src/sh/.libs src/sh/_libs + -rm -rf src/sh64/.libs src/sh64/_libs + -rm -rf src/sparc/.libs src/sparc/_libs + -rm -rf src/x86/.libs src/x86/_libs + +distclean-libtool: + -rm -f libtool config.lt +doc/$(am__dirstamp): + @$(MKDIR_P) doc + @: > doc/$(am__dirstamp) + +$(srcdir)/doc/libffi.info: doc/libffi.texi $(srcdir)/doc/version.texi + restore=: && backupdir="$(am__leading_dot)am$$$$" && \ + am__cwd=`pwd` && $(am__cd) $(srcdir) && \ + rm -rf $$backupdir && mkdir $$backupdir && \ + if ($(MAKEINFO) --version) >/dev/null 2>&1; then \ + for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \ + if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \ + done; \ + else :; fi && \ + cd "$$am__cwd"; \ + if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I doc -I $(srcdir)/doc \ + -o $@ $(srcdir)/doc/libffi.texi; \ + then \ + rc=0; \ + $(am__cd) $(srcdir); \ + else \ + rc=$$?; \ + $(am__cd) $(srcdir) && \ + $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \ + fi; \ + rm -rf $$backupdir; exit $$rc + +doc/libffi.dvi: doc/libffi.texi $(srcdir)/doc/version.texi doc/$(am__dirstamp) + TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ + MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I doc -I $(srcdir)/doc' \ + $(TEXI2DVI) -o $@ `test -f 'doc/libffi.texi' || echo '$(srcdir)/'`doc/libffi.texi + +doc/libffi.pdf: doc/libffi.texi $(srcdir)/doc/version.texi doc/$(am__dirstamp) + TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ + MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I doc -I $(srcdir)/doc' \ + $(TEXI2PDF) -o $@ `test -f 'doc/libffi.texi' || echo '$(srcdir)/'`doc/libffi.texi + +doc/libffi.html: doc/libffi.texi $(srcdir)/doc/version.texi doc/$(am__dirstamp) + rm -rf $(@:.html=.htp) + if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I doc -I $(srcdir)/doc \ + -o $(@:.html=.htp) `test -f 'doc/libffi.texi' || echo '$(srcdir)/'`doc/libffi.texi; \ + then \ + rm -rf $@; \ + if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \ + mv $(@:.html=) $@; else mv $(@:.html=.htp) $@; fi; \ + else \ + if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \ + rm -rf $(@:.html=); else rm -Rf $(@:.html=.htp) $@; fi; \ + exit 1; \ + fi +$(srcdir)/doc/version.texi: @MAINTAINER_MODE_TRUE@ $(srcdir)/doc/stamp-vti +$(srcdir)/doc/stamp-vti: doc/libffi.texi $(top_srcdir)/configure + test -f doc/$(am__dirstamp) || $(MAKE) $(AM_MAKEFLAGS) doc/$(am__dirstamp) + @(dir=.; test -f ./doc/libffi.texi || dir=$(srcdir); \ + set `$(SHELL) $(srcdir)/mdate-sh $$dir/doc/libffi.texi`; \ + echo "@set UPDATED $$1 $$2 $$3"; \ + echo "@set UPDATED-MONTH $$2 $$3"; \ + echo "@set EDITION $(VERSION)"; \ + echo "@set VERSION $(VERSION)") > vti.tmp + @cmp -s vti.tmp $(srcdir)/doc/version.texi \ + || (echo "Updating $(srcdir)/doc/version.texi"; \ + cp vti.tmp $(srcdir)/doc/version.texi) + -@rm -f vti.tmp + @cp $(srcdir)/doc/version.texi $@ + +mostlyclean-vti: + -rm -f vti.tmp + +maintainer-clean-vti: +@MAINTAINER_MODE_TRUE@ -rm -f $(srcdir)/doc/stamp-vti $(srcdir)/doc/version.texi +%.ps: %.dvi + TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ + $(DVIPS) -o $@ $< + +uninstall-dvi-am: + @$(NORMAL_UNINSTALL) + @list='$(DVIS)'; test -n "$(dvidir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(dvidir)/$$f'"; \ + rm -f "$(DESTDIR)$(dvidir)/$$f"; \ + done + +uninstall-html-am: + @$(NORMAL_UNINSTALL) + @list='$(HTMLS)'; test -n "$(htmldir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " rm -rf '$(DESTDIR)$(htmldir)/$$f'"; \ + rm -rf "$(DESTDIR)$(htmldir)/$$f"; \ + done + +uninstall-info-am: + @$(PRE_UNINSTALL) + @if test -d '$(DESTDIR)$(infodir)' && \ + (install-info --version && \ + install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \ + list='$(INFO_DEPS)'; \ + for file in $$list; do \ + relfile=`echo "$$file" | sed 's|^.*/||'`; \ + echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \ + if install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \ + then :; else test ! -f "$(DESTDIR)$(infodir)/$$relfile" || exit 1; fi; \ + done; \ + else :; fi + @$(NORMAL_UNINSTALL) + @list='$(INFO_DEPS)'; \ + for file in $$list; do \ + relfile=`echo "$$file" | sed 's|^.*/||'`; \ + relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \ + (if test -d "$(DESTDIR)$(infodir)" && cd "$(DESTDIR)$(infodir)"; then \ + echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \ + rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \ + else :; fi); \ + done + +uninstall-pdf-am: + @$(NORMAL_UNINSTALL) + @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(pdfdir)/$$f'"; \ + rm -f "$(DESTDIR)$(pdfdir)/$$f"; \ + done + +uninstall-ps-am: + @$(NORMAL_UNINSTALL) + @list='$(PSS)'; test -n "$(psdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(psdir)/$$f'"; \ + rm -f "$(DESTDIR)$(psdir)/$$f"; \ + done + +dist-info: $(INFO_DEPS) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + list='$(INFO_DEPS)'; \ + for base in $$list; do \ + case $$base in \ + $(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \ + esac; \ + if test -f $$base; then d=.; else d=$(srcdir); fi; \ + base_i=`echo "$$base" | sed 's|\.info$$||;s|$$|.i|'`; \ + for file in $$d/$$base $$d/$$base-[0-9] $$d/$$base-[0-9][0-9] $$d/$$base_i[0-9] $$d/$$base_i[0-9][0-9]; do \ + if test -f $$file; then \ + relfile=`expr "$$file" : "$$d/\(.*\)"`; \ + test -f "$(distdir)/$$relfile" || \ + cp -p $$file "$(distdir)/$$relfile"; \ + else :; fi; \ + done; \ + done + +mostlyclean-aminfo: + -rm -rf libffi.aux libffi.cp libffi.cps libffi.fn libffi.ky libffi.log \ + libffi.pg libffi.tmp libffi.toc libffi.tp libffi.vr + +clean-aminfo: + -test -z "doc/libffi.dvi doc/libffi.pdf doc/libffi.ps doc/libffi.html" \ + || rm -rf doc/libffi.dvi doc/libffi.pdf doc/libffi.ps doc/libffi.html + +maintainer-clean-aminfo: + @list='$(INFO_DEPS)'; for i in $$list; do \ + i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \ + echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \ + rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \ + done +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgconfigdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgconfigdir)" && rm -f $$files + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) fficonfig.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) fficonfig.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) fficonfig.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) fficonfig.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-info + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @$(am__cd) '$(distuninstallcheck_dir)' \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile $(INFO_DEPS) $(LTLIBRARIES) $(DATA) fficonfig.h +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(infodir)" "$(DESTDIR)$(pkgconfigdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f doc/$(am__dirstamp) + -rm -f src/$(DEPDIR)/$(am__dirstamp) + -rm -f src/$(am__dirstamp) + -rm -f src/alpha/$(DEPDIR)/$(am__dirstamp) + -rm -f src/alpha/$(am__dirstamp) + -rm -f src/arm/$(DEPDIR)/$(am__dirstamp) + -rm -f src/arm/$(am__dirstamp) + -rm -f src/avr32/$(DEPDIR)/$(am__dirstamp) + -rm -f src/avr32/$(am__dirstamp) + -rm -f src/cris/$(DEPDIR)/$(am__dirstamp) + -rm -f src/cris/$(am__dirstamp) + -rm -f src/frv/$(DEPDIR)/$(am__dirstamp) + -rm -f src/frv/$(am__dirstamp) + -rm -f src/ia64/$(DEPDIR)/$(am__dirstamp) + -rm -f src/ia64/$(am__dirstamp) + -rm -f src/m32r/$(DEPDIR)/$(am__dirstamp) + -rm -f src/m32r/$(am__dirstamp) + -rm -f src/m68k/$(DEPDIR)/$(am__dirstamp) + -rm -f src/m68k/$(am__dirstamp) + -rm -f src/mips/$(DEPDIR)/$(am__dirstamp) + -rm -f src/mips/$(am__dirstamp) + -rm -f src/moxie/$(DEPDIR)/$(am__dirstamp) + -rm -f src/moxie/$(am__dirstamp) + -rm -f src/pa/$(DEPDIR)/$(am__dirstamp) + -rm -f src/pa/$(am__dirstamp) + -rm -f src/powerpc/$(DEPDIR)/$(am__dirstamp) + -rm -f src/powerpc/$(am__dirstamp) + -rm -f src/s390/$(DEPDIR)/$(am__dirstamp) + -rm -f src/s390/$(am__dirstamp) + -rm -f src/sh/$(DEPDIR)/$(am__dirstamp) + -rm -f src/sh/$(am__dirstamp) + -rm -f src/sh64/$(DEPDIR)/$(am__dirstamp) + -rm -f src/sh64/$(am__dirstamp) + -rm -f src/sparc/$(DEPDIR)/$(am__dirstamp) + -rm -f src/sparc/$(am__dirstamp) + -rm -f src/x86/$(DEPDIR)/$(am__dirstamp) + -rm -f src/x86/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-aminfo clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-noinstLTLIBRARIES mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf src/$(DEPDIR) src/alpha/$(DEPDIR) src/arm/$(DEPDIR) src/avr32/$(DEPDIR) src/cris/$(DEPDIR) src/frv/$(DEPDIR) src/ia64/$(DEPDIR) src/m32r/$(DEPDIR) src/m68k/$(DEPDIR) src/mips/$(DEPDIR) src/moxie/$(DEPDIR) src/pa/$(DEPDIR) src/powerpc/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/x86/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: $(DVIS) + +html: html-recursive + +html-am: $(HTMLS) + +info: info-recursive + +info-am: $(INFO_DEPS) + +install-data-am: install-info-am install-pkgconfigDATA + +install-dvi: install-dvi-recursive + +install-dvi-am: $(DVIS) + @$(NORMAL_INSTALL) + test -z "$(dvidir)" || $(MKDIR_P) "$(DESTDIR)$(dvidir)" + @list='$(DVIS)'; test -n "$(dvidir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dvidir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(dvidir)" || exit $$?; \ + done +install-exec-am: install-libLTLIBRARIES + +install-html-am: $(HTMLS) + @$(NORMAL_INSTALL) + test -z "$(htmldir)" || $(MKDIR_P) "$(DESTDIR)$(htmldir)" + @list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \ + for p in $$list; do \ + if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \ + $(am__strip_dir) \ + if test -d "$$d$$p"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \ + $(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \ + echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \ + $(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \ + else \ + list2="$$list2 $$d$$p"; \ + fi; \ + done; \ + test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \ + done; } +install-info: install-info-recursive + +install-info-am: $(INFO_DEPS) + @$(NORMAL_INSTALL) + test -z "$(infodir)" || $(MKDIR_P) "$(DESTDIR)$(infodir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ + for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + esac; \ + if test -f $$file; then d=.; else d=$(srcdir); fi; \ + file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \ + for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \ + $$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \ + if test -f $$ifile; then \ + echo "$$ifile"; \ + else : ; fi; \ + done; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done + @$(POST_INSTALL) + @if (install-info --version && \ + install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \ + list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ + for file in $$list; do \ + relfile=`echo "$$file" | sed 's|^.*/||'`; \ + echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\ + install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\ + done; \ + else : ; fi +install-man: + +install-pdf-am: $(PDFS) + @$(NORMAL_INSTALL) + test -z "$(pdfdir)" || $(MKDIR_P) "$(DESTDIR)$(pdfdir)" + @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pdfdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pdfdir)" || exit $$?; done +install-ps: install-ps-recursive + +install-ps-am: $(PSS) + @$(NORMAL_INSTALL) + test -z "$(psdir)" || $(MKDIR_P) "$(DESTDIR)$(psdir)" + @list='$(PSS)'; test -n "$(psdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(psdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(psdir)" || exit $$?; done +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf src/$(DEPDIR) src/alpha/$(DEPDIR) src/arm/$(DEPDIR) src/avr32/$(DEPDIR) src/cris/$(DEPDIR) src/frv/$(DEPDIR) src/ia64/$(DEPDIR) src/m32r/$(DEPDIR) src/m68k/$(DEPDIR) src/mips/$(DEPDIR) src/moxie/$(DEPDIR) src/pa/$(DEPDIR) src/powerpc/$(DEPDIR) src/s390/$(DEPDIR) src/sh/$(DEPDIR) src/sh64/$(DEPDIR) src/sparc/$(DEPDIR) src/x86/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-aminfo \ + maintainer-clean-generic maintainer-clean-vti + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-aminfo mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool mostlyclean-vti + +pdf: pdf-recursive + +pdf-am: $(PDFS) + +ps: ps-recursive + +ps-am: $(PSS) + +uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \ + uninstall-libLTLIBRARIES uninstall-pdf-am \ + uninstall-pkgconfigDATA uninstall-ps-am + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \ + ctags-recursive install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-aminfo \ + clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-noinstLTLIBRARIES ctags ctags-recursive dist dist-all \ + dist-bzip2 dist-gzip dist-info dist-lzma dist-shar dist-tarZ \ + dist-xz dist-zip distcheck distclean distclean-compile \ + distclean-generic distclean-hdr distclean-libtool \ + distclean-tags distcleancheck distdir distuninstallcheck dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-pkgconfigDATA \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-aminfo maintainer-clean-generic \ + maintainer-clean-vti mostlyclean mostlyclean-aminfo \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + mostlyclean-vti pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-dvi-am uninstall-html-am \ + uninstall-info-am uninstall-libLTLIBRARIES uninstall-pdf-am \ + uninstall-pkgconfigDATA uninstall-ps-am + + +# No install-html or install-pdf support in automake yet +.PHONY: install-html install-pdf +install-html: +install-pdf: + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/js/src/ctypes/libffi/README b/js/src/ctypes/libffi/README new file mode 100644 index 0000000..1ed0ca5 --- /dev/null +++ b/js/src/ctypes/libffi/README @@ -0,0 +1,327 @@ +Status +====== + +libffi-3.0.10 was released on XXXXXXXXXX, 2010. Check the libffi web +page for updates: . + + +What is libffi? +=============== + +Compilers for high level languages generate code that follow certain +conventions. These conventions are necessary, in part, for separate +compilation to work. One such convention is the "calling +convention". The "calling convention" is essentially a set of +assumptions made by the compiler about where function arguments will +be found on entry to a function. A "calling convention" also specifies +where the return value for a function is found. + +Some programs may not know at the time of compilation what arguments +are to be passed to a function. For instance, an interpreter may be +told at run-time about the number and types of arguments used to call +a given function. Libffi can be used in such programs to provide a +bridge from the interpreter program to compiled code. + +The libffi library provides a portable, high level programming +interface to various calling conventions. This allows a programmer to +call any function specified by a call interface description at run +time. + +FFI stands for Foreign Function Interface. A foreign function +interface is the popular name for the interface that allows code +written in one language to call code written in another language. The +libffi library really only provides the lowest, machine dependent +layer of a fully featured foreign function interface. A layer must +exist above libffi that handles type conversions for values passed +between the two languages. + + +Supported Platforms +=================== + +Libffi has been ported to many different platforms. +For specific configuration details and testing status, please +refer to the wiki page here: + + http://www.moxielogic.org/wiki/index.php?title=Libffi_3.0.10 + +At the time of release, the following basic configurations have been +tested: + +|--------------+------------------| +| Architecture | Operating System | +|--------------+------------------| +| Alpha | Linux | +| Alpha | Tru64 | +| ARM | Linux | +| AVR32 | Linux | +| HPPA | HPUX | +| IA-64 | Linux | +| MIPS | IRIX | +| MIPS | Linux | +| MIPS64 | Linux | +| PowerPC | Linux | +| PowerPC | Mac OSX | +| PowerPC | FreeBSD | +| PowerPC64 | Linux | +| S390 | Linux | +| S390X | Linux | +| SPARC | Linux | +| SPARC | Solaris | +| SPARC64 | Linux | +| SPARC64 | FreeBSD | +| X86 | FreeBSD | +| X86 | kFreeBSD | +| X86 | Linux | +| X86 | Mac OSX | +| X86 | OpenBSD | +| X86 | OS/2 | +| X86 | Solaris | +| X86 | Windows/Cygwin | +| X86 | Windows/MingW | +| X86-64 | FreeBSD | +| X86-64 | Linux | +| X86-64 | OpenBSD | +| X86-64 | Windows/MingW | +|--------------+------------------| + +Please send additional platform test results to +libffi-discuss@sourceware.org and feel free to update the wiki page +above. + +Installing libffi +================= + +First you must configure the distribution for your particular +system. Go to the directory you wish to build libffi in and run the +"configure" program found in the root directory of the libffi source +distribution. + +You may want to tell configure where to install the libffi library and +header files. To do that, use the --prefix configure switch. Libffi +will install under /usr/local by default. + +If you want to enable extra run-time debugging checks use the the +--enable-debug configure switch. This is useful when your program dies +mysteriously while using libffi. + +Another useful configure switch is --enable-purify-safety. Using this +will add some extra code which will suppress certain warnings when you +are using Purify with libffi. Only use this switch when using +Purify, as it will slow down the library. + +It's also possible to build libffi on Windows platforms with +Microsoft's Visual C++ compiler. In this case, use the msvcc.sh +wrapper script during configuration like so: + +path/to/configure CC=path/to/msvcc.sh LD=link CPP=\"cl -nologo -EP\" + +For 64-bit Windows builds, use CC="path/to/msvcc.sh -m64". +You may also need to specify --build appropriately. When building with MSVC +under a MingW environment, you may need to remove the line in configure +that sets 'fix_srcfile_path' to a 'cygpath' command. ('cygpath' is not +present in MingW, and is not required when using MingW-style paths.) + +Configure has many other options. Use "configure --help" to see them all. + +Once configure has finished, type "make". Note that you must be using +GNU make. You can ftp GNU make from prep.ai.mit.edu:/pub/gnu. + +To ensure that libffi is working as advertised, type "make check". +This will require that you have DejaGNU installed. + +To install the library and header files, type "make install". + + +History +======= + +See the ChangeLog files for details. + +3.0.10 ???-??-?? + Fix the N64 build on mips-sgi-irix6.5. + Testsuite fixes for Tru64 Unix. + Enable builds with Microsoft's compiler. + Enable x86 builds with Sun's compiler. + +3.0.9 Dec-31-09 + Add AVR32 and win64 ports. Add ARM softfp support. + Many fixes for AIX, Solaris, HP-UX, *BSD. + Several PowerPC and x86-64 bug fixes. + Build DLL for windows. + +3.0.8 Dec-19-08 + Add *BSD, BeOS, and PA-Linux support. + +3.0.7 Nov-11-08 + Fix for ppc FreeBSD. + (thanks to Andreas Tobler) + +3.0.6 Jul-17-08 + Fix for closures on sh. + Mark the sh/sh64 stack as non-executable. + (both thanks to Kaz Kojima) + +3.0.5 Apr-3-08 + Fix libffi.pc file. + Fix #define ARM for IcedTea users. + Fix x86 closure bug. + +3.0.4 Feb-24-08 + Fix x86 OpenBSD configury. + +3.0.3 Feb-22-08 + Enable x86 OpenBSD thanks to Thomas Heller, and + x86-64 FreeBSD thanks to Björn König and Andreas Tobler. + Clean up test instruction in README. + +3.0.2 Feb-21-08 + Improved x86 FreeBSD support. + Thanks to Björn König. + +3.0.1 Feb-15-08 + Fix instruction cache flushing bug on MIPS. + Thanks to David Daney. + +3.0.0 Feb-15-08 + Many changes, mostly thanks to the GCC project. + Cygnus Solutions is now Red Hat. + + [10 years go by...] + +1.20 Oct-5-98 + Raffaele Sena produces ARM port. + +1.19 Oct-5-98 + Fixed x86 long double and long long return support. + m68k bug fixes from Andreas Schwab. + Patch for DU assembler compatibility for the Alpha from Richard + Henderson. + +1.18 Apr-17-98 + Bug fixes and MIPS configuration changes. + +1.17 Feb-24-98 + Bug fixes and m68k port from Andreas Schwab. PowerPC port from + Geoffrey Keating. Various bug x86, Sparc and MIPS bug fixes. + +1.16 Feb-11-98 + Richard Henderson produces Alpha port. + +1.15 Dec-4-97 + Fixed an n32 ABI bug. New libtool, auto* support. + +1.14 May-13-97 + libtool is now used to generate shared and static libraries. + Fixed a minor portability problem reported by Russ McManus + . + +1.13 Dec-2-96 + Added --enable-purify-safety to keep Purify from complaining + about certain low level code. + Sparc fix for calling functions with < 6 args. + Linux x86 a.out fix. + +1.12 Nov-22-96 + Added missing ffi_type_void, needed for supporting void return + types. Fixed test case for non MIPS machines. Cygnus Support + is now Cygnus Solutions. + +1.11 Oct-30-96 + Added notes about GNU make. + +1.10 Oct-29-96 + Added configuration fix for non GNU compilers. + +1.09 Oct-29-96 + Added --enable-debug configure switch. Clean-ups based on LCLint + feedback. ffi_mips.h is always installed. Many configuration + fixes. Fixed ffitest.c for sparc builds. + +1.08 Oct-15-96 + Fixed n32 problem. Many clean-ups. + +1.07 Oct-14-96 + Gordon Irlam rewrites v8.S again. Bug fixes. + +1.06 Oct-14-96 + Gordon Irlam improved the sparc port. + +1.05 Oct-14-96 + Interface changes based on feedback. + +1.04 Oct-11-96 + Sparc port complete (modulo struct passing bug). + +1.03 Oct-10-96 + Passing struct args, and returning struct values works for + all architectures/calling conventions. Expanded tests. + +1.02 Oct-9-96 + Added SGI n32 support. Fixed bugs in both o32 and Linux support. + Added "make test". + +1.01 Oct-8-96 + Fixed float passing bug in mips version. Restructured some + of the code. Builds cleanly with SGI tools. + +1.00 Oct-7-96 + First release. No public announcement. + + +Authors & Credits +================= + +libffi was originally written by Anthony Green . + +The developers of the GNU Compiler Collection project have made +innumerable valuable contributions. See the ChangeLog file for +details. + +Some of the ideas behind libffi were inspired by Gianni Mariani's free +gencall library for Silicon Graphics machines. + +The closure mechanism was designed and implemented by Kresten Krab +Thorup. + +Major processor architecture ports were contributed by the following +developers: + +alpha Richard Henderson +arm Raffaele Sena +cris Simon Posnjak, Hans-Peter Nilsson +frv Anthony Green +ia64 Hans Boehm +m32r Kazuhiro Inaoka +m68k Andreas Schwab +mips Anthony Green, Casey Marshall +mips64 David Daney +pa Randolph Chung, Dave Anglin, Andreas Tobler +powerpc Geoffrey Keating, Andreas Tobler, + David Edelsohn, John Hornkvist +powerpc64 Jakub Jelinek +s390 Gerhard Tonn, Ulrich Weigand +sh Kaz Kojima +sh64 Kaz Kojima +sparc Anthony Green, Gordon Irlam +x86 Anthony Green, Jon Beniston +x86-64 Bo Thorsen + +Jesper Skov and Andrew Haley both did more than their fair share of +stepping through the code and tracking down bugs. + +Thanks also to Tom Tromey for bug fixes, documentation and +configuration help. + +Thanks to Jim Blandy, who provided some useful feedback on the libffi +interface. + +Andreas Tobler has done a tremendous amount of work on the testsuite. + +Alex Oliva solved the executable page problem for SElinux. + +The list above is almost certainly incomplete and inaccurate. I'm +happy to make corrections or additions upon request. + +If you have a problem, or have found a bug, please send a note to +green@redhat.com. diff --git a/js/src/ctypes/libffi/acinclude.m4 b/js/src/ctypes/libffi/acinclude.m4 new file mode 100644 index 0000000..3e8f8ba --- /dev/null +++ b/js/src/ctypes/libffi/acinclude.m4 @@ -0,0 +1,92 @@ +# mmap(2) blacklisting. Some platforms provide the mmap library routine +# but don't support all of the features we need from it. +AC_DEFUN([AC_FUNC_MMAP_BLACKLIST], +[ +AC_CHECK_HEADER([sys/mman.h], + [libffi_header_sys_mman_h=yes], [libffi_header_sys_mman_h=no]) +AC_CHECK_FUNC([mmap], [libffi_func_mmap=yes], [libffi_func_mmap=no]) +if test "$libffi_header_sys_mman_h" != yes \ + || test "$libffi_func_mmap" != yes; then + ac_cv_func_mmap_file=no + ac_cv_func_mmap_dev_zero=no + ac_cv_func_mmap_anon=no +else + AC_CACHE_CHECK([whether read-only mmap of a plain file works], + ac_cv_func_mmap_file, + [# Add a system to this blacklist if + # mmap(0, stat_size, PROT_READ, MAP_PRIVATE, fd, 0) doesn't return a + # memory area containing the same data that you'd get if you applied + # read() to the same fd. The only system known to have a problem here + # is VMS, where text files have record structure. + case "$host_os" in + vms* | ultrix*) + ac_cv_func_mmap_file=no ;; + *) + ac_cv_func_mmap_file=yes;; + esac]) + AC_CACHE_CHECK([whether mmap from /dev/zero works], + ac_cv_func_mmap_dev_zero, + [# Add a system to this blacklist if it has mmap() but /dev/zero + # does not exist, or if mmapping /dev/zero does not give anonymous + # zeroed pages with both the following properties: + # 1. If you map N consecutive pages in with one call, and then + # unmap any subset of those pages, the pages that were not + # explicitly unmapped remain accessible. + # 2. If you map two adjacent blocks of memory and then unmap them + # both at once, they must both go away. + # Systems known to be in this category are Windows (all variants), + # VMS, and Darwin. + case "$host_os" in + vms* | cygwin* | pe | mingw* | darwin* | ultrix* | hpux10* | hpux11.00) + ac_cv_func_mmap_dev_zero=no ;; + *) + ac_cv_func_mmap_dev_zero=yes;; + esac]) + + # Unlike /dev/zero, the MAP_ANON(YMOUS) defines can be probed for. + AC_CACHE_CHECK([for MAP_ANON(YMOUS)], ac_cv_decl_map_anon, + [AC_TRY_COMPILE( +[#include +#include +#include + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif +], +[int n = MAP_ANONYMOUS;], + ac_cv_decl_map_anon=yes, + ac_cv_decl_map_anon=no)]) + + if test $ac_cv_decl_map_anon = no; then + ac_cv_func_mmap_anon=no + else + AC_CACHE_CHECK([whether mmap with MAP_ANON(YMOUS) works], + ac_cv_func_mmap_anon, + [# Add a system to this blacklist if it has mmap() and MAP_ANON or + # MAP_ANONYMOUS, but using mmap(..., MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + # doesn't give anonymous zeroed pages with the same properties listed + # above for use of /dev/zero. + # Systems known to be in this category are Windows, VMS, and SCO Unix. + case "$host_os" in + vms* | cygwin* | pe | mingw* | sco* | udk* ) + ac_cv_func_mmap_anon=no ;; + *) + ac_cv_func_mmap_anon=yes;; + esac]) + fi +fi + +if test $ac_cv_func_mmap_file = yes; then + AC_DEFINE(HAVE_MMAP_FILE, 1, + [Define if read-only mmap of a plain file works.]) +fi +if test $ac_cv_func_mmap_dev_zero = yes; then + AC_DEFINE(HAVE_MMAP_DEV_ZERO, 1, + [Define if mmap of /dev/zero works.]) +fi +if test $ac_cv_func_mmap_anon = yes; then + AC_DEFINE(HAVE_MMAP_ANON, 1, + [Define if mmap with MAP_ANON(YMOUS) works.]) +fi +]) diff --git a/js/src/ctypes/libffi/aclocal.m4 b/js/src/ctypes/libffi/aclocal.m4 new file mode 100644 index 0000000..d5eb6a6 --- /dev/null +++ b/js/src/ctypes/libffi/aclocal.m4 @@ -0,0 +1,8998 @@ +# generated automatically by aclocal 1.11.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.65],, +[m4_warning([this file was generated for autoconf 2.65. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 56 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl +_LT_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "X$" | $Xsed -e "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\[$]0 --fallback-echo"')dnl " + lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` + ;; +esac + +_LT_OUTPUT_LIBTOOL_INIT +]) + + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +cat >"$CONFIG_LT" <<_LTEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate a libtool stub with the current configuration. + +lt_cl_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AS_SHELL_SANITIZE +_AS_PREPARE + +exec AS_MESSAGE_FD>&1 +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2008 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +if test "$no_create" != yes; then + lt_cl_success=: + test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" + exec AS_MESSAGE_LOG_FD>/dev/null + $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false + exec AS_MESSAGE_LOG_FD>>config.log + $lt_cl_success || AS_EXIT(1) +fi +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_XSI_SHELLFNS + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES +# -------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX +# ----------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_SHELL_INIT + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[_LT_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +[$]* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(lt_ECHO) +]) +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], + [An echo program that does not interpret backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[AC_CHECK_TOOL(AR, ar, false) +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1]) + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line __oline__ "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[[3-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method == "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC*) + # IBM XL 8.0 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac +AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE(int foo(void) {}, + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + ) + LDFLAGS="$save_LDFLAGS" + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], + [[If ld is used when linking, flag to hardcode $libdir into a binary + during linking. This must work even if $libdir does not exist]]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [fix_srcfile_path], [1], + [Fix the shell variable $srcfile for the compiler]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_PROG_CXX +# ------------ +# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ +# compiler, we have our own version here. +m4_defun([_LT_PROG_CXX], +[ +pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) +AC_PROG_CXX +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_CXX + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_CXX], []) + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[AC_REQUIRE([_LT_PROG_CXX])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + gnu*) + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 will use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + xl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=echo + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +]) +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_PROG_F77 +# ------------ +# Since AC_PROG_F77 is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_F77], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) +AC_PROG_F77 +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_F77 + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_F77], []) + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_REQUIRE([_LT_PROG_F77])dnl +AC_LANG_PUSH(Fortran 77) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${F77-"f77"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_PROG_FC +# ----------- +# Since AC_PROG_FC is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_FC], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) +AC_PROG_FC +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_FC + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_FC], []) + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_REQUIRE([_LT_PROG_FC])dnl +AC_LANG_PUSH(Fortran) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${FC-"f95"} + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC="$lt_save_CC" +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC="$lt_save_CC" +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_XSI_SHELLFNS +# --------------------- +# Bourne and XSI compatible variants of some useful shell functions. +m4_defun([_LT_PROG_XSI_SHELLFNS], +[case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $[*] )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +dnl func_dirname_and_basename +dnl A portable version of this function is already defined in general.m4sh +dnl so there is no need for it here. + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[[^=]]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$[@]"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]+=\$[2]" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]=\$$[1]\$[2]" +} + +_LT_EOF + ;; + esac +]) + +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [0], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) + +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) + +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# Generated from ltversion.in. + +# serial 3017 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.2.6b]) +m4_define([LT_PACKAGE_REVISION], [1.3017]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.2.6b' +macro_revision='1.3017' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) + +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 4 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# Figure out how to run the assembler. -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_PROG_AS +# ---------- +AC_DEFUN([AM_PROG_AS], +[# By default we simply use the C compiler to build assembly code. +AC_REQUIRE([AC_PROG_CC]) +test "${CCAS+set}" = set || CCAS=$CC +test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS +AC_ARG_VAR([CCAS], [assembler compiler command (defaults to CC)]) +AC_ARG_VAR([CCASFLAGS], [assembler compiler flags (defaults to CFLAGS)]) +_AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES([CCAS])])dnl +]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 10 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 5 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless `enable' is passed literally. +# For symmetry, `disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], +[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_PROG_CC_C_O +# -------------- +# Like AC_PROG_CC_C_O, but changed for automake. +AC_DEFUN([AM_PROG_CC_C_O], +[AC_REQUIRE([AC_PROG_CC_C_O])dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +dnl Make sure AC_PROG_CC is never called again, or it will override our +dnl setting of CC. +m4_define([AC_PROG_CC], + [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([acinclude.m4]) diff --git a/js/src/ctypes/libffi/compile b/js/src/ctypes/libffi/compile new file mode 100755 index 0000000..1b1d232 --- /dev/null +++ b/js/src/ctypes/libffi/compile @@ -0,0 +1,142 @@ +#! /bin/sh +# Wrapper for compilers which do not understand `-c -o'. + +scriptversion=2005-05-14.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand `-c -o'. +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file `INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; +esac + +ofile= +cfile= +eat= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as `compile cc -o foo foo.c'. + # So we strip `-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no `-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # `.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` + +# Create the lock directory. +# Note: use `[/.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/js/src/ctypes/libffi/config.guess b/js/src/ctypes/libffi/config.guess new file mode 100755 index 0000000..d53e309 --- /dev/null +++ b/js/src/ctypes/libffi/config.guess @@ -0,0 +1,1498 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-11-19' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/js/src/ctypes/libffi/config.sub b/js/src/ctypes/libffi/config.sub new file mode 100755 index 0000000..17c9145 --- /dev/null +++ b/js/src/ctypes/libffi/config.sub @@ -0,0 +1,1702 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-11-07' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | picochip) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/js/src/ctypes/libffi/configure b/js/src/ctypes/libffi/configure new file mode 100755 index 0000000..67ccf20 --- /dev/null +++ b/js/src/ctypes/libffi/configure @@ -0,0 +1,15041 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.65 for libffi 3.0.10rc0. +# +# Report bugs to . +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and +$0: http://gcc.gnu.org/bugs.html about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +$* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL $0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + + + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='libffi' +PACKAGE_TARNAME='libffi' +PACKAGE_VERSION='3.0.10rc0' +PACKAGE_STRING='libffi 3.0.10rc0' +PACKAGE_BUGREPORT='http://gcc.gnu.org/bugs.html' +PACKAGE_URL='' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +toolexeclibdir +toolexecdir +FFI_DEBUG_FALSE +FFI_DEBUG_TRUE +TARGETDIR +TARGET +HAVE_LONG_DOUBLE +ALLOCA +PA64_HPUX_FALSE +PA64_HPUX_TRUE +PA_HPUX_FALSE +PA_HPUX_TRUE +PA_LINUX_FALSE +PA_LINUX_TRUE +SH64_FALSE +SH64_TRUE +SH_FALSE +SH_TRUE +X86_64_FALSE +X86_64_TRUE +S390_FALSE +S390_TRUE +FRV_FALSE +FRV_TRUE +LIBFFI_CRIS_FALSE +LIBFFI_CRIS_TRUE +AVR32_FALSE +AVR32_TRUE +ARM_FALSE +ARM_TRUE +POWERPC_FREEBSD_FALSE +POWERPC_FREEBSD_TRUE +POWERPC_DARWIN_FALSE +POWERPC_DARWIN_TRUE +POWERPC_AIX_FALSE +POWERPC_AIX_TRUE +POWERPC_FALSE +POWERPC_TRUE +MOXIE_FALSE +MOXIE_TRUE +M68K_FALSE +M68K_TRUE +M32R_FALSE +M32R_TRUE +IA64_FALSE +IA64_TRUE +ALPHA_FALSE +ALPHA_TRUE +X86_DARWIN_FALSE +X86_DARWIN_TRUE +X86_WIN64_FALSE +X86_WIN64_TRUE +X86_WIN32_FALSE +X86_WIN32_TRUE +X86_FREEBSD_FALSE +X86_FREEBSD_TRUE +X86_FALSE +X86_TRUE +SPARC_FALSE +SPARC_TRUE +MIPS_FALSE +MIPS_TRUE +AM_LTLDFLAGS +AM_RUNTESTFLAGS +TESTSUBDIR_FALSE +TESTSUBDIR_TRUE +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +CPP +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +lt_ECHO +RANLIB +AR +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +EGREP +GREP +SED +LIBTOOL +am__fastdepCCAS_FALSE +am__fastdepCCAS_TRUE +CCASDEPMODE +CCASFLAGS +CCAS +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_dependency_tracking +enable_shared +enable_static +with_pic +enable_fast_install +with_gnu_ld +enable_libtool_lock +enable_maintainer_mode +enable_debug +enable_structs +enable_raw_api +enable_purify_safety +' + ac_precious_vars='build_alias +host_alias +target_alias +CCAS +CCASFLAGS +CPP +CPPFLAGS' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information." + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures libffi 3.0.10rc0 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/libffi] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of libffi 3.0.10rc0:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer + --enable-debug debugging mode + --disable-structs omit code for struct support + --disable-raw-api make the raw api unavailable + --enable-purify-safety purify-safe mode + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CCAS assembler compiler command (defaults to CC) + CCASFLAGS assembler compiler flags (defaults to CFLAGS) + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +libffi configure 3.0.10rc0 +generated by GNU Autoconf 2.65 + +Copyright (C) 2009 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_func + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +( cat <<\_ASBOX +## ------------------------------------------- ## +## Report this to http://gcc.gnu.org/bugs.html ## +## ------------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES +# -------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_c_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid; break +else + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=$ac_mid; break +else + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid +else + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval () { return $2; } +static unsigned long int ulongval () { return $2; } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + echo >>conftest.val; read $3 config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by libffi $as_me 3.0.10rc0, which was +generated by GNU Autoconf 2.65. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + ac_site_file1=$CONFIG_SITE +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_config_headers="$ac_config_headers fficonfig.h" + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + for ac_t in install-sh install.sh shtool; do + if test -f "$ac_dir/$ac_t"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/$ac_t -c" + break 2 + fi + done +done +if test -z "$ac_aux_dir"; then + as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if test "${ac_cv_build+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if test "${ac_cv_host+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if test "${ac_cv_target+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +target_alias=${target_alias-$host_alias} + +. ${srcdir}/configure.host + +am__api_version='1.11' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error "ls -t appears to fail. Make sure there is not a broken +alias in your environment" "$LINENO" 5 + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='libffi' + VERSION='3.0.10rc0' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + + +# The same as in boehm-gc and libstdc++. Have to borrow it from there. +# We must force CC to /not/ be precious variables; otherwise +# the wrong, non-multilib-adjusted value will be used in multilibs. +# As a side effect, we have to subst CFLAGS ourselves. +# Also save and restore CFLAGS, since AC_PROG_CC will come up with +# defaults of its own if none are provided. + + + +save_CFLAGS=$CFLAGS +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "no acceptable C compiler found in \$PATH +See \`config.log' for more details." "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "C compiler cannot create executables +See \`config.log' for more details." "$LINENO" 5; }; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of object files: cannot compile +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +CFLAGS=$save_CFLAGS + + + + + +# By default we simply use the C compiler to build assembly code. + +test "${CCAS+set}" = set || CCAS=$CC +test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS + + + +depcc="$CCAS" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CCAS_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CCAS_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CCAS_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CCAS_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CCAS_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CCAS_dependencies_compiler_type" >&6; } +CCASDEPMODE=depmode=$am_cv_CCAS_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CCAS_dependencies_compiler_type" = gcc3; then + am__fastdepCCAS_TRUE= + am__fastdepCCAS_FALSE='#' +else + am__fastdepCCAS_TRUE='#' + am__fastdepCCAS_FALSE= +fi + + +if test "x$CC" != xcc; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5 +$as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5 +$as_echo_n "checking whether cc understands -c and -o together... " >&6; } +fi +set dummy $CC; ac_cc=`$as_echo "$2" | + sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +if { as_var=ac_cv_prog_cc_${ac_cc}_c_o; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +# Make sure it works both with $CC and with simple cc. +# We do the test twice because some compilers refuse to overwrite an +# existing .o file with -o, though they will create one. +ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5' +rm -f conftest2.* +if { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && + test -f conftest2.$ac_objext && { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; +then + eval ac_cv_prog_cc_${ac_cc}_c_o=yes + if test "x$CC" != xcc; then + # Test first that cc exists at all. + if { ac_try='cc -c conftest.$ac_ext >&5' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5' + rm -f conftest2.* + if { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && + test -f conftest2.$ac_objext && { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; + then + # cc works too. + : + else + # cc exists but doesn't like -o. + eval ac_cv_prog_cc_${ac_cc}_c_o=no + fi + fi + fi +else + eval ac_cv_prog_cc_${ac_cc}_c_o=no +fi +rm -f core conftest* + +fi +if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +$as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h + +fi + +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi + + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.2.6b' +macro_revision='1.3017' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if test "${ac_cv_path_SED+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if test "${ac_cv_path_GREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if test "${ac_cv_path_FGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if test "${lt_cv_path_NM+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$ac_tool_prefix"; then + for ac_prog in "dumpbin -symbols" "link -dump -symbols" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DUMPBIN+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in "dumpbin -symbols" "link -dump -symbols" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if test "${lt_cv_nm_interface+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:5053: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:5056: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:5059: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if test "${lt_cv_sys_max_cmd_len+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`$SHELL $0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if test "${lt_cv_ld_reload_flag+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OBJDUMP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if test "${lt_cv_deplibs_check_method+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AR+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + + + + + + + + + + + + + + + + + + + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 6265 "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if test "${lt_cv_cc_needs_belf+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DSYMUTIL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_NMEDIT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_LIPO+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OTOOL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OTOOL64+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if test "${lt_cv_apple_cc_single_mod+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if test "${lt_cv_ld_exported_symbols_list+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +eval as_val=\$$as_ac_Header + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + +# Set options + + + + enable_dlopen=no + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; pic_mode="$withval" +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if test "${lt_cv_objdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + + + + + + + + + + + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag=' -fno-builtin' + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:7791: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:7795: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 +$as_echo "$lt_prog_compiler_pic" >&6; } + + + + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if test "${lt_cv_prog_compiler_pic_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:8130: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:8134: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if test "${lt_cv_prog_compiler_static_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:8235: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:8239: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:8290: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:8294: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld='-rpath $libdir' + archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + whole_archive_flag_spec='' + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo(void) {} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + archive_cmds_need_lc=no + else + archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5 +$as_echo "$archive_cmds_need_lc" >&6; } + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = x""yes; then : + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if test "${ac_cv_lib_dld_shl_load+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if test "${ac_cv_lib_svld_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if test "${ac_cv_lib_dld_dld_link+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = x""yes; then : + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if test "${lt_cv_dlopen_self+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 10660 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if test "${lt_cv_dlopen_self_static+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 10756 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + +for ac_header in sys/mman.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_mman_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_MMAN_H 1 +_ACEOF + +fi + +done + +for ac_func in mmap +do : + ac_fn_c_check_func "$LINENO" "mmap" "ac_cv_func_mmap" +if test "x$ac_cv_func_mmap" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MMAP 1 +_ACEOF + +fi +done + + +ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_mman_h" = x""yes; then : + libffi_header_sys_mman_h=yes +else + libffi_header_sys_mman_h=no +fi + + +ac_fn_c_check_func "$LINENO" "mmap" "ac_cv_func_mmap" +if test "x$ac_cv_func_mmap" = x""yes; then : + libffi_func_mmap=yes +else + libffi_func_mmap=no +fi + +if test "$libffi_header_sys_mman_h" != yes \ + || test "$libffi_func_mmap" != yes; then + ac_cv_func_mmap_file=no + ac_cv_func_mmap_dev_zero=no + ac_cv_func_mmap_anon=no +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether read-only mmap of a plain file works" >&5 +$as_echo_n "checking whether read-only mmap of a plain file works... " >&6; } +if test "${ac_cv_func_mmap_file+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Add a system to this blacklist if + # mmap(0, stat_size, PROT_READ, MAP_PRIVATE, fd, 0) doesn't return a + # memory area containing the same data that you'd get if you applied + # read() to the same fd. The only system known to have a problem here + # is VMS, where text files have record structure. + case "$host_os" in + vms* | ultrix*) + ac_cv_func_mmap_file=no ;; + *) + ac_cv_func_mmap_file=yes;; + esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_file" >&5 +$as_echo "$ac_cv_func_mmap_file" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mmap from /dev/zero works" >&5 +$as_echo_n "checking whether mmap from /dev/zero works... " >&6; } +if test "${ac_cv_func_mmap_dev_zero+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Add a system to this blacklist if it has mmap() but /dev/zero + # does not exist, or if mmapping /dev/zero does not give anonymous + # zeroed pages with both the following properties: + # 1. If you map N consecutive pages in with one call, and then + # unmap any subset of those pages, the pages that were not + # explicitly unmapped remain accessible. + # 2. If you map two adjacent blocks of memory and then unmap them + # both at once, they must both go away. + # Systems known to be in this category are Windows (all variants), + # VMS, and Darwin. + case "$host_os" in + vms* | cygwin* | pe | mingw* | darwin* | ultrix* | hpux10* | hpux11.00) + ac_cv_func_mmap_dev_zero=no ;; + *) + ac_cv_func_mmap_dev_zero=yes;; + esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_dev_zero" >&5 +$as_echo "$ac_cv_func_mmap_dev_zero" >&6; } + + # Unlike /dev/zero, the MAP_ANON(YMOUS) defines can be probed for. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MAP_ANON(YMOUS)" >&5 +$as_echo_n "checking for MAP_ANON(YMOUS)... " >&6; } +if test "${ac_cv_decl_map_anon+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +int +main () +{ +int n = MAP_ANONYMOUS; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_decl_map_anon=yes +else + ac_cv_decl_map_anon=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_decl_map_anon" >&5 +$as_echo "$ac_cv_decl_map_anon" >&6; } + + if test $ac_cv_decl_map_anon = no; then + ac_cv_func_mmap_anon=no + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mmap with MAP_ANON(YMOUS) works" >&5 +$as_echo_n "checking whether mmap with MAP_ANON(YMOUS) works... " >&6; } +if test "${ac_cv_func_mmap_anon+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Add a system to this blacklist if it has mmap() and MAP_ANON or + # MAP_ANONYMOUS, but using mmap(..., MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + # doesn't give anonymous zeroed pages with the same properties listed + # above for use of /dev/zero. + # Systems known to be in this category are Windows, VMS, and SCO Unix. + case "$host_os" in + vms* | cygwin* | pe | mingw* | sco* | udk* ) + ac_cv_func_mmap_anon=no ;; + *) + ac_cv_func_mmap_anon=yes;; + esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_anon" >&5 +$as_echo "$ac_cv_func_mmap_anon" >&6; } + fi +fi + +if test $ac_cv_func_mmap_file = yes; then + +$as_echo "#define HAVE_MMAP_FILE 1" >>confdefs.h + +fi +if test $ac_cv_func_mmap_dev_zero = yes; then + +$as_echo "#define HAVE_MMAP_DEV_ZERO 1" >>confdefs.h + +fi +if test $ac_cv_func_mmap_anon = yes; then + +$as_echo "#define HAVE_MMAP_ANON 1" >>confdefs.h + +fi + + + if test -d $srcdir/testsuite; then + TESTSUBDIR_TRUE= + TESTSUBDIR_FALSE='#' +else + TESTSUBDIR_TRUE='#' + TESTSUBDIR_FALSE= +fi + + +TARGETDIR="unknown" +case "$host" in + alpha*-*-*) + TARGET=ALPHA; TARGETDIR=alpha; + # Support 128-bit long double, changeable via command-line switch. + HAVE_LONG_DOUBLE='defined(__LONG_DOUBLE_128__)' + ;; + + arm*-*-*) + TARGET=ARM; TARGETDIR=arm + ;; + + amd64-*-freebsd* | amd64-*-openbsd*) + TARGET=X86_64; TARGETDIR=x86 + ;; + + amd64-*-freebsd*) + TARGET=X86_64; TARGETDIR=x86 + ;; + + avr32*-*-*) + TARGET=AVR32; TARGETDIR=avr32 + ;; + + cris-*-*) + TARGET=LIBFFI_CRIS; TARGETDIR=cris + ;; + + frv-*-*) + TARGET=FRV; TARGETDIR=frv + ;; + + hppa*-*-linux* | parisc*-*-linux*) + TARGET=PA_LINUX; TARGETDIR=pa + ;; + hppa*64-*-hpux*) + TARGET=PA64_HPUX; TARGETDIR=pa + ;; + hppa*-*-hpux*) + TARGET=PA_HPUX; TARGETDIR=pa + ;; + + i?86-*-freebsd* | i?86-*-openbsd*) + TARGET=X86_FREEBSD; TARGETDIR=x86 + ;; + i?86-win32* | i?86-*-cygwin* | i?86-*-mingw* | i?86-*-os2*) + TARGET=X86_WIN32; TARGETDIR=x86 + # All mingw/cygwin/win32 builds require this for sharedlib + AM_LTLDFLAGS="-no-undefined" + ;; + i?86-*-darwin*) + TARGET=X86_DARWIN; TARGETDIR=x86 + ;; + i?86-*-solaris2.1[0-9]*) + TARGET=X86_64; TARGETDIR=x86 + ;; + i?86-*-*) + TARGET=X86; TARGETDIR=x86 + ;; + + ia64*-*-*) + TARGET=IA64; TARGETDIR=ia64 + ;; + + m32r*-*-*) + TARGET=M32R; TARGETDIR=m32r + ;; + + m68k-*-*) + TARGET=M68K; TARGETDIR=m68k + ;; + + mips-sgi-irix5.* | mips-sgi-irix6.*) + TARGET=MIPS; TARGETDIR=mips + ;; + mips*-*-linux*) + # Support 128-bit long double for NewABI. + HAVE_LONG_DOUBLE='defined(__mips64)' + TARGET=MIPS; TARGETDIR=mips + ;; + + moxie-*-*) + TARGET=MOXIE; TARGETDIR=moxie + ;; + + powerpc*-*-linux* | powerpc-*-sysv*) + TARGET=POWERPC; TARGETDIR=powerpc + ;; + powerpc-*-beos*) + TARGET=POWERPC; TARGETDIR=powerpc + ;; + powerpc-*-darwin*) + TARGET=POWERPC_DARWIN; TARGETDIR=powerpc + ;; + powerpc-*-aix* | rs6000-*-aix*) + TARGET=POWERPC_AIX; TARGETDIR=powerpc + ;; + powerpc-*-freebsd*) + TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc + ;; + powerpc*-*-rtems*) + TARGET=POWERPC; TARGETDIR=powerpc + ;; + + s390-*-* | s390x-*-*) + TARGET=S390; TARGETDIR=s390 + ;; + + sh-*-* | sh[34]*-*-*) + TARGET=SH; TARGETDIR=sh + ;; + sh64-*-* | sh5*-*-*) + TARGET=SH64; TARGETDIR=sh64 + ;; + + sparc*-*-*) + TARGET=SPARC; TARGETDIR=sparc + ;; + + x86_64-*-darwin*) + TARGET=X86_DARWIN; TARGETDIR=x86 + ;; + + x86_64-*-cygwin* | x86_64-*-mingw*) + TARGET=X86_WIN64; TARGETDIR=x86 + ;; + + x86_64-*-*) + TARGET=X86_64; TARGETDIR=x86 + ;; +esac + + + + +if test $TARGETDIR = unknown; then + as_fn_error "\"libffi has not been ported to $host.\"" "$LINENO" 5 +fi + + if test x$TARGET = xMIPS; then + MIPS_TRUE= + MIPS_FALSE='#' +else + MIPS_TRUE='#' + MIPS_FALSE= +fi + + if test x$TARGET = xSPARC; then + SPARC_TRUE= + SPARC_FALSE='#' +else + SPARC_TRUE='#' + SPARC_FALSE= +fi + + if test x$TARGET = xX86; then + X86_TRUE= + X86_FALSE='#' +else + X86_TRUE='#' + X86_FALSE= +fi + + if test x$TARGET = xX86_FREEBSD; then + X86_FREEBSD_TRUE= + X86_FREEBSD_FALSE='#' +else + X86_FREEBSD_TRUE='#' + X86_FREEBSD_FALSE= +fi + + if test x$TARGET = xX86_WIN32; then + X86_WIN32_TRUE= + X86_WIN32_FALSE='#' +else + X86_WIN32_TRUE='#' + X86_WIN32_FALSE= +fi + + if test x$TARGET = xX86_WIN64; then + X86_WIN64_TRUE= + X86_WIN64_FALSE='#' +else + X86_WIN64_TRUE='#' + X86_WIN64_FALSE= +fi + + if test x$TARGET = xX86_DARWIN; then + X86_DARWIN_TRUE= + X86_DARWIN_FALSE='#' +else + X86_DARWIN_TRUE='#' + X86_DARWIN_FALSE= +fi + + if test x$TARGET = xALPHA; then + ALPHA_TRUE= + ALPHA_FALSE='#' +else + ALPHA_TRUE='#' + ALPHA_FALSE= +fi + + if test x$TARGET = xIA64; then + IA64_TRUE= + IA64_FALSE='#' +else + IA64_TRUE='#' + IA64_FALSE= +fi + + if test x$TARGET = xM32R; then + M32R_TRUE= + M32R_FALSE='#' +else + M32R_TRUE='#' + M32R_FALSE= +fi + + if test x$TARGET = xM68K; then + M68K_TRUE= + M68K_FALSE='#' +else + M68K_TRUE='#' + M68K_FALSE= +fi + + if test x$TARGET = xMOXIE; then + MOXIE_TRUE= + MOXIE_FALSE='#' +else + MOXIE_TRUE='#' + MOXIE_FALSE= +fi + + if test x$TARGET = xPOWERPC; then + POWERPC_TRUE= + POWERPC_FALSE='#' +else + POWERPC_TRUE='#' + POWERPC_FALSE= +fi + + if test x$TARGET = xPOWERPC_AIX; then + POWERPC_AIX_TRUE= + POWERPC_AIX_FALSE='#' +else + POWERPC_AIX_TRUE='#' + POWERPC_AIX_FALSE= +fi + + if test x$TARGET = xPOWERPC_DARWIN; then + POWERPC_DARWIN_TRUE= + POWERPC_DARWIN_FALSE='#' +else + POWERPC_DARWIN_TRUE='#' + POWERPC_DARWIN_FALSE= +fi + + if test x$TARGET = xPOWERPC_FREEBSD; then + POWERPC_FREEBSD_TRUE= + POWERPC_FREEBSD_FALSE='#' +else + POWERPC_FREEBSD_TRUE='#' + POWERPC_FREEBSD_FALSE= +fi + + if test x$TARGET = xARM; then + ARM_TRUE= + ARM_FALSE='#' +else + ARM_TRUE='#' + ARM_FALSE= +fi + + if test x$TARGET = xAVR32; then + AVR32_TRUE= + AVR32_FALSE='#' +else + AVR32_TRUE='#' + AVR32_FALSE= +fi + + if test x$TARGET = xLIBFFI_CRIS; then + LIBFFI_CRIS_TRUE= + LIBFFI_CRIS_FALSE='#' +else + LIBFFI_CRIS_TRUE='#' + LIBFFI_CRIS_FALSE= +fi + + if test x$TARGET = xFRV; then + FRV_TRUE= + FRV_FALSE='#' +else + FRV_TRUE='#' + FRV_FALSE= +fi + + if test x$TARGET = xS390; then + S390_TRUE= + S390_FALSE='#' +else + S390_TRUE='#' + S390_FALSE= +fi + + if test x$TARGET = xX86_64; then + X86_64_TRUE= + X86_64_FALSE='#' +else + X86_64_TRUE='#' + X86_64_FALSE= +fi + + if test x$TARGET = xSH; then + SH_TRUE= + SH_FALSE='#' +else + SH_TRUE='#' + SH_FALSE= +fi + + if test x$TARGET = xSH64; then + SH64_TRUE= + SH64_FALSE='#' +else + SH64_TRUE='#' + SH64_FALSE= +fi + + if test x$TARGET = xPA_LINUX; then + PA_LINUX_TRUE= + PA_LINUX_FALSE='#' +else + PA_LINUX_TRUE='#' + PA_LINUX_FALSE= +fi + + if test x$TARGET = xPA_HPUX; then + PA_HPUX_TRUE= + PA_HPUX_FALSE='#' +else + PA_HPUX_TRUE='#' + PA_HPUX_FALSE= +fi + + if test x$TARGET = xPA64_HPUX; then + PA64_HPUX_TRUE= + PA64_HPUX_FALSE='#' +else + PA64_HPUX_TRUE='#' + PA64_HPUX_FALSE= +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +for ac_func in memcpy +do : + ac_fn_c_check_func "$LINENO" "memcpy" "ac_cv_func_memcpy" +if test "x$ac_cv_func_memcpy" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MEMCPY 1 +_ACEOF + +fi +done + +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 +$as_echo_n "checking for working alloca.h... " >&6; } +if test "${ac_cv_working_alloca_h+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +char *p = (char *) alloca (2 * sizeof (int)); + if (p) return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_working_alloca_h=yes +else + ac_cv_working_alloca_h=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 +$as_echo "$ac_cv_working_alloca_h" >&6; } +if test $ac_cv_working_alloca_h = yes; then + +$as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 +$as_echo_n "checking for alloca... " >&6; } +if test "${ac_cv_func_alloca_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# ifdef _MSC_VER +# include +# define alloca _alloca +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +int +main () +{ +char *p = (char *) alloca (1); + if (p) return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_func_alloca_works=yes +else + ac_cv_func_alloca_works=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 +$as_echo "$ac_cv_func_alloca_works" >&6; } + +if test $ac_cv_func_alloca_works = yes; then + +$as_echo "#define HAVE_ALLOCA 1" >>confdefs.h + +else + # The SVR3 libPW and SVR4 libucb both contain incompatible functions +# that cause trouble. Some versions do not even contain alloca or +# contain a buggy version. If you still want to use their alloca, +# use ar to extract alloca.o from them instead of compiling alloca.c. + +ALLOCA=\${LIBOBJDIR}alloca.$ac_objext + +$as_echo "#define C_ALLOCA 1" >>confdefs.h + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5 +$as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; } +if test "${ac_cv_os_cray+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined CRAY && ! defined CRAY2 +webecray +#else +wenotbecray +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "webecray" >/dev/null 2>&1; then : + ac_cv_os_cray=yes +else + ac_cv_os_cray=no +fi +rm -f conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5 +$as_echo "$ac_cv_os_cray" >&6; } +if test $ac_cv_os_cray = yes; then + for ac_func in _getb67 GETB67 getb67; do + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +eval as_val=\$$as_ac_var + if test "x$as_val" = x""yes; then : + +cat >>confdefs.h <<_ACEOF +#define CRAY_STACKSEG_END $ac_func +_ACEOF + + break +fi + + done +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 +$as_echo_n "checking stack direction for C alloca... " >&6; } +if test "${ac_cv_c_stack_direction+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_c_stack_direction=0 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +find_stack_direction () +{ + static char *addr = 0; + auto char dummy; + if (addr == 0) + { + addr = &dummy; + return find_stack_direction (); + } + else + return (&dummy > addr) ? 1 : -1; +} + +int +main () +{ + return find_stack_direction () < 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_stack_direction=1 +else + ac_cv_c_stack_direction=-1 +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 +$as_echo "$ac_cv_c_stack_direction" >&6; } +cat >>confdefs.h <<_ACEOF +#define STACK_DIRECTION $ac_cv_c_stack_direction +_ACEOF + + +fi + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of double" >&5 +$as_echo_n "checking size of double... " >&6; } +if test "${ac_cv_sizeof_double+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_double" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (double) +See \`config.log' for more details." "$LINENO" 5; }; } + else + ac_cv_sizeof_double=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_double" >&5 +$as_echo "$ac_cv_sizeof_double" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_DOUBLE $ac_cv_sizeof_double +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long double" >&5 +$as_echo_n "checking size of long double... " >&6; } +if test "${ac_cv_sizeof_long_double+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_long_double" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (long double) +See \`config.log' for more details." "$LINENO" 5; }; } + else + ac_cv_sizeof_long_double=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_double" >&5 +$as_echo "$ac_cv_sizeof_long_double" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG_DOUBLE $ac_cv_sizeof_long_double +_ACEOF + + + +# Also AC_SUBST this variable for ffi.h. +if test -z "$HAVE_LONG_DOUBLE"; then + HAVE_LONG_DOUBLE=0 + if test $ac_cv_sizeof_double != $ac_cv_sizeof_long_double; then + if test $ac_cv_sizeof_long_double != 0; then + HAVE_LONG_DOUBLE=1 + +$as_echo "#define HAVE_LONG_DOUBLE 1" >>confdefs.h + + fi + fi +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +$as_echo_n "checking whether byte ordering is bigendian... " >&6; } +if test "${ac_cv_c_bigendian+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_bigendian=unknown + # See if we're dealing with a universal compiler. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __APPLE_CC__ + not a universal capable compiler + #endif + typedef int dummy; + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # Check for potential -arch flags. It is not universal unless + # there are at least two -arch flags with different values. + ac_arch= + ac_prev= + for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do + if test -n "$ac_prev"; then + case $ac_word in + i?86 | x86_64 | ppc | ppc64) + if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then + ac_arch=$ac_word + else + ac_cv_c_bigendian=universal + break + fi + ;; + esac + ac_prev= + elif test "x$ac_word" = "x-arch"; then + ac_prev=arch + fi + done +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test $ac_cv_c_bigendian = unknown; then + # See if sys/param.h defines the BYTE_ORDER macro. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ + && LITTLE_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to _BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#ifndef _BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # Compile a test program. + if test "$cross_compiling" = yes; then : + # Try to guess by grepping values from an object file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +short int ascii_mm[] = + { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; + short int ascii_ii[] = + { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; + int use_ascii (int i) { + return ascii_mm[i] + ascii_ii[i]; + } + short int ebcdic_ii[] = + { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; + short int ebcdic_mm[] = + { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; + int use_ebcdic (int i) { + return ebcdic_mm[i] + ebcdic_ii[i]; + } + extern int foo; + +int +main () +{ +return use_ascii (foo) == use_ebcdic (foo); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + ac_cv_c_bigendian=yes + fi + if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_bigendian=no +else + ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +$as_echo "$ac_cv_c_bigendian" >&6; } + case $ac_cv_c_bigendian in #( + yes) + $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h +;; #( + no) + ;; #( + universal) + +$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + + ;; #( + *) + as_fn_error "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler .cfi pseudo-op support" >&5 +$as_echo_n "checking assembler .cfi pseudo-op support... " >&6; } +if test "${libffi_cv_as_cfi_pseudo_op+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + libffi_cv_as_cfi_pseudo_op=unknown + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +asm (".cfi_startproc\n\t.cfi_endproc"); +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + libffi_cv_as_cfi_pseudo_op=yes +else + libffi_cv_as_cfi_pseudo_op=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libffi_cv_as_cfi_pseudo_op" >&5 +$as_echo "$libffi_cv_as_cfi_pseudo_op" >&6; } +if test "x$libffi_cv_as_cfi_pseudo_op" = xyes; then + +$as_echo "#define HAVE_AS_CFI_PSEUDO_OP 1" >>confdefs.h + +fi + +if test x$TARGET = xSPARC; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler and linker support unaligned pc related relocs" >&5 +$as_echo_n "checking assembler and linker support unaligned pc related relocs... " >&6; } +if test "${libffi_cv_as_sparc_ua_pcrel+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + save_CFLAGS="$CFLAGS" + save_LDFLAGS="$LDFLAGS" + CFLAGS="$CFLAGS -fpic" + LDFLAGS="$LDFLAGS -shared" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +asm (".text; foo: nop; .data; .align 4; .byte 0; .uaword %r_disp32(foo); .text"); +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + libffi_cv_as_sparc_ua_pcrel=yes +else + libffi_cv_as_sparc_ua_pcrel=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="$save_CFLAGS" + LDFLAGS="$save_LDFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libffi_cv_as_sparc_ua_pcrel" >&5 +$as_echo "$libffi_cv_as_sparc_ua_pcrel" >&6; } + if test "x$libffi_cv_as_sparc_ua_pcrel" = xyes; then + +$as_echo "#define HAVE_AS_SPARC_UA_PCREL 1" >>confdefs.h + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler .register pseudo-op support" >&5 +$as_echo_n "checking assembler .register pseudo-op support... " >&6; } +if test "${libffi_cv_as_register_pseudo_op+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + libffi_cv_as_register_pseudo_op=unknown + # Check if we have .register + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +asm (".register %g2, #scratch"); +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + libffi_cv_as_register_pseudo_op=yes +else + libffi_cv_as_register_pseudo_op=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libffi_cv_as_register_pseudo_op" >&5 +$as_echo "$libffi_cv_as_register_pseudo_op" >&6; } + if test "x$libffi_cv_as_register_pseudo_op" = xyes; then + +$as_echo "#define HAVE_AS_REGISTER_PSEUDO_OP 1" >>confdefs.h + + fi +fi + +if test x$TARGET = xX86 || test x$TARGET = xX86_WIN32 || test x$TARGET = xX86_64; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler supports pc related relocs" >&5 +$as_echo_n "checking assembler supports pc related relocs... " >&6; } +if test "${libffi_cv_as_x86_pcrel+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + libffi_cv_as_x86_pcrel=yes + echo '.text; foo: nop; .data; .long foo-.; .text' > conftest.s + if $CC $CFLAGS -c conftest.s 2>&1 | $EGREP -i 'illegal|warning' > /dev/null; then + libffi_cv_as_x86_pcrel=no + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libffi_cv_as_x86_pcrel" >&5 +$as_echo "$libffi_cv_as_x86_pcrel" >&6; } + if test "x$libffi_cv_as_x86_pcrel" = xyes; then + +$as_echo "#define HAVE_AS_X86_PCREL 1" >>confdefs.h + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler .ascii pseudo-op support" >&5 +$as_echo_n "checking assembler .ascii pseudo-op support... " >&6; } +if test "${libffi_cv_as_ascii_pseudo_op+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + libffi_cv_as_ascii_pseudo_op=unknown + # Check if we have .ascii + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +asm (".ascii \"string\""); +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + libffi_cv_as_ascii_pseudo_op=yes +else + libffi_cv_as_ascii_pseudo_op=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libffi_cv_as_ascii_pseudo_op" >&5 +$as_echo "$libffi_cv_as_ascii_pseudo_op" >&6; } + if test "x$libffi_cv_as_ascii_pseudo_op" = xyes; then + +$as_echo "#define HAVE_AS_ASCII_PSEUDO_OP 1" >>confdefs.h + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler .string pseudo-op support" >&5 +$as_echo_n "checking assembler .string pseudo-op support... " >&6; } +if test "${libffi_cv_as_string_pseudo_op+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + libffi_cv_as_string_pseudo_op=unknown + # Check if we have .string + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +asm (".string \"string\""); +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + libffi_cv_as_string_pseudo_op=yes +else + libffi_cv_as_string_pseudo_op=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libffi_cv_as_string_pseudo_op" >&5 +$as_echo "$libffi_cv_as_string_pseudo_op" >&6; } + if test "x$libffi_cv_as_string_pseudo_op" = xyes; then + +$as_echo "#define HAVE_AS_STRING_PSEUDO_OP 1" >>confdefs.h + + fi +fi + +case "$target" in + *-apple-darwin10* | *-*-freebsd* | *-*-openbsd* | *-pc-solaris*) + +$as_echo "#define FFI_MMAP_EXEC_WRIT 1" >>confdefs.h + + ;; +esac + +if test x$TARGET = xX86_64; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler supports unwind section type" >&5 +$as_echo_n "checking assembler supports unwind section type... " >&6; } +if test "${libffi_cv_as_x86_64_unwind_section_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + libffi_cv_as_x86_64_unwind_section_type=yes + echo '.section .eh_frame,"a",@unwind' > conftest.s + if $CC $CFLAGS -c conftest.s 2>&1 | grep -i warning > /dev/null; then + libffi_cv_as_x86_64_unwind_section_type=no + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libffi_cv_as_x86_64_unwind_section_type" >&5 +$as_echo "$libffi_cv_as_x86_64_unwind_section_type" >&6; } + if test "x$libffi_cv_as_x86_64_unwind_section_type" = xyes; then + +$as_echo "#define HAVE_AS_X86_64_UNWIND_SECTION_TYPE 1" >>confdefs.h + + fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether .eh_frame section should be read-only" >&5 +$as_echo_n "checking whether .eh_frame section should be read-only... " >&6; } +if test "${libffi_cv_ro_eh_frame+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + libffi_cv_ro_eh_frame=no + echo 'extern void foo (void); void bar (void) { foo (); foo (); }' > conftest.c + if $CC $CFLAGS -S -fpic -fexceptions -o conftest.s conftest.c > /dev/null 2>&1; then + if grep '.section.*eh_frame.*"a"' conftest.s > /dev/null; then + libffi_cv_ro_eh_frame=yes + elif grep '.section.*eh_frame.*#alloc' conftest.c \ + | grep -v '#write' > /dev/null; then + libffi_cv_ro_eh_frame=yes + fi + fi + rm -f conftest.* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libffi_cv_ro_eh_frame" >&5 +$as_echo "$libffi_cv_ro_eh_frame" >&6; } +if test "x$libffi_cv_ro_eh_frame" = xyes; then + +$as_echo "#define HAVE_RO_EH_FRAME 1" >>confdefs.h + + +$as_echo "#define EH_FRAME_FLAGS \"a\"" >>confdefs.h + +else + +$as_echo "#define EH_FRAME_FLAGS \"aw\"" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((visibility(\"hidden\")))" >&5 +$as_echo_n "checking for __attribute__((visibility(\"hidden\")))... " >&6; } +if test "${libffi_cv_hidden_visibility_attribute+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + echo 'int __attribute__ ((visibility ("hidden"))) foo (void) { return 1; }' > conftest.c + libffi_cv_hidden_visibility_attribute=no + if { ac_try='${CC-cc} -Werror -S conftest.c -o conftest.s 1>&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + if grep '\.hidden.*foo' conftest.s >/dev/null; then + libffi_cv_hidden_visibility_attribute=yes + fi + fi + rm -f conftest.* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libffi_cv_hidden_visibility_attribute" >&5 +$as_echo "$libffi_cv_hidden_visibility_attribute" >&6; } +if test $libffi_cv_hidden_visibility_attribute = yes; then + +$as_echo "#define HAVE_HIDDEN_VISIBILITY_ATTRIBUTE 1" >>confdefs.h + +fi + + + + + + + + +# Check whether --enable-debug was given. +if test "${enable_debug+set}" = set; then : + enableval=$enable_debug; if test "$enable_debug" = "yes"; then + +$as_echo "#define FFI_DEBUG 1" >>confdefs.h + + fi +fi + + if test "$enable_debug" = "yes"; then + FFI_DEBUG_TRUE= + FFI_DEBUG_FALSE='#' +else + FFI_DEBUG_TRUE='#' + FFI_DEBUG_FALSE= +fi + + +# Check whether --enable-structs was given. +if test "${enable_structs+set}" = set; then : + enableval=$enable_structs; if test "$enable_structs" = "no"; then + +$as_echo "#define FFI_NO_STRUCTS 1" >>confdefs.h + + fi +fi + + +# Check whether --enable-raw-api was given. +if test "${enable_raw_api+set}" = set; then : + enableval=$enable_raw_api; if test "$enable_raw_api" = "no"; then + +$as_echo "#define FFI_NO_RAW_API 1" >>confdefs.h + + fi +fi + + +# Check whether --enable-purify-safety was given. +if test "${enable_purify_safety+set}" = set; then : + enableval=$enable_purify_safety; if test "$enable_purify_safety" = "yes"; then + +$as_echo "#define USING_PURIFY 1" >>confdefs.h + + fi +fi + + +if test -n "$with_cross_host" && + test x"$with_cross_host" != x"no"; then + toolexecdir='$(exec_prefix)/$(target_alias)' + toolexeclibdir='$(toolexecdir)/lib' +else + toolexecdir='$(libdir)/gcc-lib/$(target_alias)' + toolexeclibdir='$(libdir)' +fi +multi_os_directory=`$CC -print-multi-os-directory` +case $multi_os_directory in + .) ;; # Avoid trailing /. + *) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; +esac + + + +if test "${multilib}" = "yes"; then + multilib_arg="--enable-multilib" +else + multilib_arg= +fi + +ac_config_commands="$ac_config_commands include" + +ac_config_commands="$ac_config_commands src" + + +ac_config_links="$ac_config_links include/ffitarget.h:src/$TARGETDIR/ffitarget.h" + + +ac_config_files="$ac_config_files include/Makefile include/ffi.h Makefile testsuite/Makefile man/Makefile libffi.pc" + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCCAS_TRUE}" && test -z "${am__fastdepCCAS_FALSE}"; then + as_fn_error "conditional \"am__fastdepCCAS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${TESTSUBDIR_TRUE}" && test -z "${TESTSUBDIR_FALSE}"; then + as_fn_error "conditional \"TESTSUBDIR\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MIPS_TRUE}" && test -z "${MIPS_FALSE}"; then + as_fn_error "conditional \"MIPS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${SPARC_TRUE}" && test -z "${SPARC_FALSE}"; then + as_fn_error "conditional \"SPARC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${X86_TRUE}" && test -z "${X86_FALSE}"; then + as_fn_error "conditional \"X86\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${X86_FREEBSD_TRUE}" && test -z "${X86_FREEBSD_FALSE}"; then + as_fn_error "conditional \"X86_FREEBSD\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${X86_WIN32_TRUE}" && test -z "${X86_WIN32_FALSE}"; then + as_fn_error "conditional \"X86_WIN32\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${X86_WIN64_TRUE}" && test -z "${X86_WIN64_FALSE}"; then + as_fn_error "conditional \"X86_WIN64\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${X86_DARWIN_TRUE}" && test -z "${X86_DARWIN_FALSE}"; then + as_fn_error "conditional \"X86_DARWIN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ALPHA_TRUE}" && test -z "${ALPHA_FALSE}"; then + as_fn_error "conditional \"ALPHA\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${IA64_TRUE}" && test -z "${IA64_FALSE}"; then + as_fn_error "conditional \"IA64\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${M32R_TRUE}" && test -z "${M32R_FALSE}"; then + as_fn_error "conditional \"M32R\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${M68K_TRUE}" && test -z "${M68K_FALSE}"; then + as_fn_error "conditional \"M68K\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MOXIE_TRUE}" && test -z "${MOXIE_FALSE}"; then + as_fn_error "conditional \"MOXIE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${POWERPC_TRUE}" && test -z "${POWERPC_FALSE}"; then + as_fn_error "conditional \"POWERPC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${POWERPC_AIX_TRUE}" && test -z "${POWERPC_AIX_FALSE}"; then + as_fn_error "conditional \"POWERPC_AIX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${POWERPC_DARWIN_TRUE}" && test -z "${POWERPC_DARWIN_FALSE}"; then + as_fn_error "conditional \"POWERPC_DARWIN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${POWERPC_FREEBSD_TRUE}" && test -z "${POWERPC_FREEBSD_FALSE}"; then + as_fn_error "conditional \"POWERPC_FREEBSD\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ARM_TRUE}" && test -z "${ARM_FALSE}"; then + as_fn_error "conditional \"ARM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AVR32_TRUE}" && test -z "${AVR32_FALSE}"; then + as_fn_error "conditional \"AVR32\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LIBFFI_CRIS_TRUE}" && test -z "${LIBFFI_CRIS_FALSE}"; then + as_fn_error "conditional \"LIBFFI_CRIS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${FRV_TRUE}" && test -z "${FRV_FALSE}"; then + as_fn_error "conditional \"FRV\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${S390_TRUE}" && test -z "${S390_FALSE}"; then + as_fn_error "conditional \"S390\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${X86_64_TRUE}" && test -z "${X86_64_FALSE}"; then + as_fn_error "conditional \"X86_64\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${SH_TRUE}" && test -z "${SH_FALSE}"; then + as_fn_error "conditional \"SH\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${SH64_TRUE}" && test -z "${SH64_FALSE}"; then + as_fn_error "conditional \"SH64\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${PA_LINUX_TRUE}" && test -z "${PA_LINUX_FALSE}"; then + as_fn_error "conditional \"PA_LINUX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${PA_HPUX_TRUE}" && test -z "${PA_HPUX_FALSE}"; then + as_fn_error "conditional \"PA_HPUX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${PA64_HPUX_TRUE}" && test -z "${PA64_HPUX_FALSE}"; then + as_fn_error "conditional \"PA64_HPUX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +if test -z "${FFI_DEBUG_TRUE}" && test -z "${FFI_DEBUG_FALSE}"; then + as_fn_error "conditional \"FFI_DEBUG\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by libffi $as_me 3.0.10rc0, which was +generated by GNU Autoconf 2.65. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_links="$ac_config_links" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration links: +$config_links + +Configuration commands: +$config_commands + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +libffi config.status 3.0.10rc0 +configured by $0, generated by GNU Autoconf 2.65, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2009 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "X$macro_version" | $Xsed -e "$delay_single_quote_subst"`' +macro_revision='`$ECHO "X$macro_revision" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared='`$ECHO "X$enable_shared" | $Xsed -e "$delay_single_quote_subst"`' +enable_static='`$ECHO "X$enable_static" | $Xsed -e "$delay_single_quote_subst"`' +pic_mode='`$ECHO "X$pic_mode" | $Xsed -e "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "X$enable_fast_install" | $Xsed -e "$delay_single_quote_subst"`' +host_alias='`$ECHO "X$host_alias" | $Xsed -e "$delay_single_quote_subst"`' +host='`$ECHO "X$host" | $Xsed -e "$delay_single_quote_subst"`' +host_os='`$ECHO "X$host_os" | $Xsed -e "$delay_single_quote_subst"`' +build_alias='`$ECHO "X$build_alias" | $Xsed -e "$delay_single_quote_subst"`' +build='`$ECHO "X$build" | $Xsed -e "$delay_single_quote_subst"`' +build_os='`$ECHO "X$build_os" | $Xsed -e "$delay_single_quote_subst"`' +SED='`$ECHO "X$SED" | $Xsed -e "$delay_single_quote_subst"`' +Xsed='`$ECHO "X$Xsed" | $Xsed -e "$delay_single_quote_subst"`' +GREP='`$ECHO "X$GREP" | $Xsed -e "$delay_single_quote_subst"`' +EGREP='`$ECHO "X$EGREP" | $Xsed -e "$delay_single_quote_subst"`' +FGREP='`$ECHO "X$FGREP" | $Xsed -e "$delay_single_quote_subst"`' +LD='`$ECHO "X$LD" | $Xsed -e "$delay_single_quote_subst"`' +NM='`$ECHO "X$NM" | $Xsed -e "$delay_single_quote_subst"`' +LN_S='`$ECHO "X$LN_S" | $Xsed -e "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "X$max_cmd_len" | $Xsed -e "$delay_single_quote_subst"`' +ac_objext='`$ECHO "X$ac_objext" | $Xsed -e "$delay_single_quote_subst"`' +exeext='`$ECHO "X$exeext" | $Xsed -e "$delay_single_quote_subst"`' +lt_unset='`$ECHO "X$lt_unset" | $Xsed -e "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "X$lt_SP2NL" | $Xsed -e "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "X$lt_NL2SP" | $Xsed -e "$delay_single_quote_subst"`' +reload_flag='`$ECHO "X$reload_flag" | $Xsed -e "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "X$reload_cmds" | $Xsed -e "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "X$OBJDUMP" | $Xsed -e "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "X$deplibs_check_method" | $Xsed -e "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "X$file_magic_cmd" | $Xsed -e "$delay_single_quote_subst"`' +AR='`$ECHO "X$AR" | $Xsed -e "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "X$AR_FLAGS" | $Xsed -e "$delay_single_quote_subst"`' +STRIP='`$ECHO "X$STRIP" | $Xsed -e "$delay_single_quote_subst"`' +RANLIB='`$ECHO "X$RANLIB" | $Xsed -e "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "X$old_postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "X$old_postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "X$old_archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' +CC='`$ECHO "X$CC" | $Xsed -e "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "X$CFLAGS" | $Xsed -e "$delay_single_quote_subst"`' +compiler='`$ECHO "X$compiler" | $Xsed -e "$delay_single_quote_subst"`' +GCC='`$ECHO "X$GCC" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "X$lt_cv_sys_global_symbol_pipe" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "X$lt_cv_sys_global_symbol_to_cdecl" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' +objdir='`$ECHO "X$objdir" | $Xsed -e "$delay_single_quote_subst"`' +SHELL='`$ECHO "X$SHELL" | $Xsed -e "$delay_single_quote_subst"`' +ECHO='`$ECHO "X$ECHO" | $Xsed -e "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "X$MAGIC_CMD" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "X$lt_prog_compiler_no_builtin_flag" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "X$lt_prog_compiler_wl" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "X$lt_prog_compiler_pic" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "X$lt_prog_compiler_static" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "X$lt_cv_prog_compiler_c_o" | $Xsed -e "$delay_single_quote_subst"`' +need_locks='`$ECHO "X$need_locks" | $Xsed -e "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "X$DSYMUTIL" | $Xsed -e "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "X$NMEDIT" | $Xsed -e "$delay_single_quote_subst"`' +LIPO='`$ECHO "X$LIPO" | $Xsed -e "$delay_single_quote_subst"`' +OTOOL='`$ECHO "X$OTOOL" | $Xsed -e "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "X$OTOOL64" | $Xsed -e "$delay_single_quote_subst"`' +libext='`$ECHO "X$libext" | $Xsed -e "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "X$shrext_cmds" | $Xsed -e "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "X$extract_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "X$archive_cmds_need_lc" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "X$enable_shared_with_static_runtimes" | $Xsed -e "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "X$export_dynamic_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "X$whole_archive_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "X$compiler_needs_object" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "X$old_archive_from_new_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "X$old_archive_from_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "X$archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "X$archive_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' +module_cmds='`$ECHO "X$module_cmds" | $Xsed -e "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "X$module_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "X$with_gnu_ld" | $Xsed -e "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "X$allow_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "X$no_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "X$hardcode_libdir_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld='`$ECHO "X$hardcode_libdir_flag_spec_ld" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "X$hardcode_libdir_separator" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "X$hardcode_direct" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "X$hardcode_direct_absolute" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "X$hardcode_minus_L" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "X$hardcode_shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "X$hardcode_automatic" | $Xsed -e "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "X$inherit_rpath" | $Xsed -e "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "X$link_all_deplibs" | $Xsed -e "$delay_single_quote_subst"`' +fix_srcfile_path='`$ECHO "X$fix_srcfile_path" | $Xsed -e "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "X$always_export_symbols" | $Xsed -e "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "X$export_symbols_cmds" | $Xsed -e "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "X$exclude_expsyms" | $Xsed -e "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "X$include_expsyms" | $Xsed -e "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "X$prelink_cmds" | $Xsed -e "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "X$file_list_spec" | $Xsed -e "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "X$variables_saved_for_relink" | $Xsed -e "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "X$need_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' +need_version='`$ECHO "X$need_version" | $Xsed -e "$delay_single_quote_subst"`' +version_type='`$ECHO "X$version_type" | $Xsed -e "$delay_single_quote_subst"`' +runpath_var='`$ECHO "X$runpath_var" | $Xsed -e "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "X$shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "X$shlibpath_overrides_runpath" | $Xsed -e "$delay_single_quote_subst"`' +libname_spec='`$ECHO "X$libname_spec" | $Xsed -e "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "X$library_names_spec" | $Xsed -e "$delay_single_quote_subst"`' +soname_spec='`$ECHO "X$soname_spec" | $Xsed -e "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "X$postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "X$postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "X$finish_cmds" | $Xsed -e "$delay_single_quote_subst"`' +finish_eval='`$ECHO "X$finish_eval" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "X$hardcode_into_libs" | $Xsed -e "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "X$sys_lib_search_path_spec" | $Xsed -e "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "X$sys_lib_dlsearch_path_spec" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "X$hardcode_action" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "X$enable_dlopen" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "X$enable_dlopen_self" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "X$enable_dlopen_self_static" | $Xsed -e "$delay_single_quote_subst"`' +old_striplib='`$ECHO "X$old_striplib" | $Xsed -e "$delay_single_quote_subst"`' +striplib='`$ECHO "X$striplib" | $Xsed -e "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# Quote evaled strings. +for var in SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +AR \ +AR_FLAGS \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +SHELL \ +ECHO \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_wl \ +lt_prog_compiler_pic \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_flag_spec_ld \ +hardcode_libdir_separator \ +fix_srcfile_path \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +finish_eval \ +old_striplib \ +striplib; do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec; do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\$0 --fallback-echo"') lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\$0 --fallback-echo"\$/\$0 --fallback-echo"/'\` + ;; +esac + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + +TARGETDIR="$TARGETDIR" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "fficonfig.h") CONFIG_HEADERS="$CONFIG_HEADERS fficonfig.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "include") CONFIG_COMMANDS="$CONFIG_COMMANDS include" ;; + "src") CONFIG_COMMANDS="$CONFIG_COMMANDS src" ;; + "include/ffitarget.h") CONFIG_LINKS="$CONFIG_LINKS include/ffitarget.h:src/$TARGETDIR/ffitarget.h" ;; + "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; + "include/ffi.h") CONFIG_FILES="$CONFIG_FILES include/ffi.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "testsuite/Makefile") CONFIG_FILES="$CONFIG_FILES testsuite/Makefile" ;; + "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; + "libffi.pc") CONFIG_FILES="$CONFIG_FILES libffi.pc" ;; + + *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_LINKS+set}" = set || CONFIG_LINKS=$config_links + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_t=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_t"; then + break + elif $ac_last_try; then + as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :L $CONFIG_LINKS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$tmp/config.h" "$ac_file" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + :L) + # + # CONFIG_LINK + # + + if test "$ac_source" = "$ac_file" && test "$srcdir" = '.'; then + : + else + # Prefer the file from the source tree if names are identical. + if test "$ac_source" = "$ac_file" || test ! -r "$ac_source"; then + ac_source=$srcdir/$ac_source + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: linking $ac_source to $ac_file" >&5 +$as_echo "$as_me: linking $ac_source to $ac_file" >&6;} + + if test ! -r "$ac_source"; then + as_fn_error "$ac_source: file not found" "$LINENO" 5 + fi + rm -f "$ac_file" + + # Try a relative symlink, then a hard link, then a copy. + case $srcdir in + [\\/$]* | ?:[\\/]* ) ac_rel_source=$ac_source ;; + *) ac_rel_source=$ac_top_build_prefix$ac_source ;; + esac + ln -s "$ac_rel_source" "$ac_file" 2>/dev/null || + ln "$ac_source" "$ac_file" 2>/dev/null || + cp -p "$ac_source" "$ac_file" || + as_fn_error "cannot link or copy $ac_source to $ac_file" "$LINENO" 5 + fi + ;; + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="" + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that does not interpret backslashes. +ECHO=$lt_ECHO + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $* )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[^=]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[^.]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$@"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1+=\$2" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1=\$$1\$2" +} + +_LT_EOF + ;; + esac + + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + ;; + "include":C) test -d include || mkdir include ;; + "src":C) +test -d src || mkdir src +test -d src/$TARGETDIR || mkdir src/$TARGETDIR + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit $? +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/js/src/ctypes/libffi/configure.ac b/js/src/ctypes/libffi/configure.ac new file mode 100644 index 0000000..50f24bc --- /dev/null +++ b/js/src/ctypes/libffi/configure.ac @@ -0,0 +1,459 @@ +dnl Process this with autoconf to create configure + +AC_PREREQ(2.63) + +AC_INIT([libffi], [3.0.10rc0], [http://gcc.gnu.org/bugs.html]) +AC_CONFIG_HEADERS([fficonfig.h]) + +AC_CANONICAL_SYSTEM +target_alias=${target_alias-$host_alias} + +. ${srcdir}/configure.host + +AM_INIT_AUTOMAKE + +# The same as in boehm-gc and libstdc++. Have to borrow it from there. +# We must force CC to /not/ be precious variables; otherwise +# the wrong, non-multilib-adjusted value will be used in multilibs. +# As a side effect, we have to subst CFLAGS ourselves. +# Also save and restore CFLAGS, since AC_PROG_CC will come up with +# defaults of its own if none are provided. + +m4_rename([_AC_ARG_VAR_PRECIOUS],[real_PRECIOUS]) +m4_define([_AC_ARG_VAR_PRECIOUS],[]) +save_CFLAGS=$CFLAGS +AC_PROG_CC +CFLAGS=$save_CFLAGS +m4_undefine([_AC_ARG_VAR_PRECIOUS]) +m4_rename([real_PRECIOUS],[_AC_ARG_VAR_PRECIOUS]) + +AC_SUBST(CFLAGS) + +AM_PROG_AS +AM_PROG_CC_C_O +AC_PROG_LIBTOOL +AC_CONFIG_MACRO_DIR([m4]) + +AM_MAINTAINER_MODE + +AC_CHECK_HEADERS(sys/mman.h) +AC_CHECK_FUNCS(mmap) +AC_FUNC_MMAP_BLACKLIST + +dnl The -no-testsuite modules omit the test subdir. +AM_CONDITIONAL(TESTSUBDIR, test -d $srcdir/testsuite) + +TARGETDIR="unknown" +case "$host" in + alpha*-*-*) + TARGET=ALPHA; TARGETDIR=alpha; + # Support 128-bit long double, changeable via command-line switch. + HAVE_LONG_DOUBLE='defined(__LONG_DOUBLE_128__)' + ;; + + arm*-*-*) + TARGET=ARM; TARGETDIR=arm + ;; + + amd64-*-freebsd* | amd64-*-openbsd*) + TARGET=X86_64; TARGETDIR=x86 + ;; + + amd64-*-freebsd*) + TARGET=X86_64; TARGETDIR=x86 + ;; + + avr32*-*-*) + TARGET=AVR32; TARGETDIR=avr32 + ;; + + cris-*-*) + TARGET=LIBFFI_CRIS; TARGETDIR=cris + ;; + + frv-*-*) + TARGET=FRV; TARGETDIR=frv + ;; + + hppa*-*-linux* | parisc*-*-linux*) + TARGET=PA_LINUX; TARGETDIR=pa + ;; + hppa*64-*-hpux*) + TARGET=PA64_HPUX; TARGETDIR=pa + ;; + hppa*-*-hpux*) + TARGET=PA_HPUX; TARGETDIR=pa + ;; + + i?86-*-freebsd* | i?86-*-openbsd*) + TARGET=X86_FREEBSD; TARGETDIR=x86 + ;; + i?86-win32* | i?86-*-cygwin* | i?86-*-mingw* | i?86-*-os2*) + TARGET=X86_WIN32; TARGETDIR=x86 + # All mingw/cygwin/win32 builds require this for sharedlib + AM_LTLDFLAGS="-no-undefined" + ;; + i?86-*-darwin*) + TARGET=X86_DARWIN; TARGETDIR=x86 + ;; + i?86-*-solaris2.1[[0-9]]*) + TARGET=X86_64; TARGETDIR=x86 + ;; + i?86-*-*) + TARGET=X86; TARGETDIR=x86 + ;; + + ia64*-*-*) + TARGET=IA64; TARGETDIR=ia64 + ;; + + m32r*-*-*) + TARGET=M32R; TARGETDIR=m32r + ;; + + m68k-*-*) + TARGET=M68K; TARGETDIR=m68k + ;; + + mips-sgi-irix5.* | mips-sgi-irix6.*) + TARGET=MIPS; TARGETDIR=mips + ;; + mips*-*-linux*) + # Support 128-bit long double for NewABI. + HAVE_LONG_DOUBLE='defined(__mips64)' + TARGET=MIPS; TARGETDIR=mips + ;; + + moxie-*-*) + TARGET=MOXIE; TARGETDIR=moxie + ;; + + powerpc*-*-linux* | powerpc-*-sysv*) + TARGET=POWERPC; TARGETDIR=powerpc + ;; + powerpc-*-beos*) + TARGET=POWERPC; TARGETDIR=powerpc + ;; + powerpc-*-darwin*) + TARGET=POWERPC_DARWIN; TARGETDIR=powerpc + ;; + powerpc-*-aix* | rs6000-*-aix*) + TARGET=POWERPC_AIX; TARGETDIR=powerpc + ;; + powerpc-*-freebsd*) + TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc + ;; + powerpc*-*-rtems*) + TARGET=POWERPC; TARGETDIR=powerpc + ;; + + s390-*-* | s390x-*-*) + TARGET=S390; TARGETDIR=s390 + ;; + + sh-*-* | sh[[34]]*-*-*) + TARGET=SH; TARGETDIR=sh + ;; + sh64-*-* | sh5*-*-*) + TARGET=SH64; TARGETDIR=sh64 + ;; + + sparc*-*-*) + TARGET=SPARC; TARGETDIR=sparc + ;; + + x86_64-*-darwin*) + TARGET=X86_DARWIN; TARGETDIR=x86 + ;; + + x86_64-*-cygwin* | x86_64-*-mingw*) + TARGET=X86_WIN64; TARGETDIR=x86 + ;; + + x86_64-*-*) + TARGET=X86_64; TARGETDIR=x86 + ;; +esac + +AC_SUBST(AM_RUNTESTFLAGS) +AC_SUBST(AM_LTLDFLAGS) + +if test $TARGETDIR = unknown; then + AC_MSG_ERROR(["libffi has not been ported to $host."]) +fi + +AM_CONDITIONAL(MIPS, test x$TARGET = xMIPS) +AM_CONDITIONAL(SPARC, test x$TARGET = xSPARC) +AM_CONDITIONAL(X86, test x$TARGET = xX86) +AM_CONDITIONAL(X86_FREEBSD, test x$TARGET = xX86_FREEBSD) +AM_CONDITIONAL(X86_WIN32, test x$TARGET = xX86_WIN32) +AM_CONDITIONAL(X86_WIN64, test x$TARGET = xX86_WIN64) +AM_CONDITIONAL(X86_DARWIN, test x$TARGET = xX86_DARWIN) +AM_CONDITIONAL(ALPHA, test x$TARGET = xALPHA) +AM_CONDITIONAL(IA64, test x$TARGET = xIA64) +AM_CONDITIONAL(M32R, test x$TARGET = xM32R) +AM_CONDITIONAL(M68K, test x$TARGET = xM68K) +AM_CONDITIONAL(MOXIE, test x$TARGET = xMOXIE) +AM_CONDITIONAL(POWERPC, test x$TARGET = xPOWERPC) +AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX) +AM_CONDITIONAL(POWERPC_DARWIN, test x$TARGET = xPOWERPC_DARWIN) +AM_CONDITIONAL(POWERPC_FREEBSD, test x$TARGET = xPOWERPC_FREEBSD) +AM_CONDITIONAL(ARM, test x$TARGET = xARM) +AM_CONDITIONAL(AVR32, test x$TARGET = xAVR32) +AM_CONDITIONAL(LIBFFI_CRIS, test x$TARGET = xLIBFFI_CRIS) +AM_CONDITIONAL(FRV, test x$TARGET = xFRV) +AM_CONDITIONAL(S390, test x$TARGET = xS390) +AM_CONDITIONAL(X86_64, test x$TARGET = xX86_64) +AM_CONDITIONAL(SH, test x$TARGET = xSH) +AM_CONDITIONAL(SH64, test x$TARGET = xSH64) +AM_CONDITIONAL(PA_LINUX, test x$TARGET = xPA_LINUX) +AM_CONDITIONAL(PA_HPUX, test x$TARGET = xPA_HPUX) +AM_CONDITIONAL(PA64_HPUX, test x$TARGET = xPA64_HPUX) + +AC_HEADER_STDC +AC_CHECK_FUNCS(memcpy) +AC_FUNC_ALLOCA + +AC_CHECK_SIZEOF(double) +AC_CHECK_SIZEOF(long double) + +# Also AC_SUBST this variable for ffi.h. +if test -z "$HAVE_LONG_DOUBLE"; then + HAVE_LONG_DOUBLE=0 + if test $ac_cv_sizeof_double != $ac_cv_sizeof_long_double; then + if test $ac_cv_sizeof_long_double != 0; then + HAVE_LONG_DOUBLE=1 + AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the long double type and it is bigger than a double]) + fi + fi +fi +AC_SUBST(HAVE_LONG_DOUBLE) + +AC_C_BIGENDIAN + +AC_CACHE_CHECK([assembler .cfi pseudo-op support], + libffi_cv_as_cfi_pseudo_op, [ + libffi_cv_as_cfi_pseudo_op=unknown + AC_TRY_COMPILE([asm (".cfi_startproc\n\t.cfi_endproc");],, + [libffi_cv_as_cfi_pseudo_op=yes], + [libffi_cv_as_cfi_pseudo_op=no]) +]) +if test "x$libffi_cv_as_cfi_pseudo_op" = xyes; then + AC_DEFINE(HAVE_AS_CFI_PSEUDO_OP, 1, + [Define if your assembler supports .cfi_* directives.]) +fi + +if test x$TARGET = xSPARC; then + AC_CACHE_CHECK([assembler and linker support unaligned pc related relocs], + libffi_cv_as_sparc_ua_pcrel, [ + save_CFLAGS="$CFLAGS" + save_LDFLAGS="$LDFLAGS" + CFLAGS="$CFLAGS -fpic" + LDFLAGS="$LDFLAGS -shared" + AC_TRY_LINK([asm (".text; foo: nop; .data; .align 4; .byte 0; .uaword %r_disp32(foo); .text");],, + [libffi_cv_as_sparc_ua_pcrel=yes], + [libffi_cv_as_sparc_ua_pcrel=no]) + CFLAGS="$save_CFLAGS" + LDFLAGS="$save_LDFLAGS"]) + if test "x$libffi_cv_as_sparc_ua_pcrel" = xyes; then + AC_DEFINE(HAVE_AS_SPARC_UA_PCREL, 1, + [Define if your assembler and linker support unaligned PC relative relocs.]) + fi + + AC_CACHE_CHECK([assembler .register pseudo-op support], + libffi_cv_as_register_pseudo_op, [ + libffi_cv_as_register_pseudo_op=unknown + # Check if we have .register + AC_TRY_COMPILE([asm (".register %g2, #scratch");],, + [libffi_cv_as_register_pseudo_op=yes], + [libffi_cv_as_register_pseudo_op=no]) + ]) + if test "x$libffi_cv_as_register_pseudo_op" = xyes; then + AC_DEFINE(HAVE_AS_REGISTER_PSEUDO_OP, 1, + [Define if your assembler supports .register.]) + fi +fi + +if test x$TARGET = xX86 || test x$TARGET = xX86_WIN32 || test x$TARGET = xX86_64; then + AC_CACHE_CHECK([assembler supports pc related relocs], + libffi_cv_as_x86_pcrel, [ + libffi_cv_as_x86_pcrel=yes + echo '.text; foo: nop; .data; .long foo-.; .text' > conftest.s + if $CC $CFLAGS -c conftest.s 2>&1 | $EGREP -i 'illegal|warning' > /dev/null; then + libffi_cv_as_x86_pcrel=no + fi + ]) + if test "x$libffi_cv_as_x86_pcrel" = xyes; then + AC_DEFINE(HAVE_AS_X86_PCREL, 1, + [Define if your assembler supports PC relative relocs.]) + fi + + AC_CACHE_CHECK([assembler .ascii pseudo-op support], + libffi_cv_as_ascii_pseudo_op, [ + libffi_cv_as_ascii_pseudo_op=unknown + # Check if we have .ascii + AC_TRY_COMPILE([asm (".ascii \"string\"");],, + [libffi_cv_as_ascii_pseudo_op=yes], + [libffi_cv_as_ascii_pseudo_op=no]) + ]) + if test "x$libffi_cv_as_ascii_pseudo_op" = xyes; then + AC_DEFINE(HAVE_AS_ASCII_PSEUDO_OP, 1, + [Define if your assembler supports .ascii.]) + fi + + AC_CACHE_CHECK([assembler .string pseudo-op support], + libffi_cv_as_string_pseudo_op, [ + libffi_cv_as_string_pseudo_op=unknown + # Check if we have .string + AC_TRY_COMPILE([asm (".string \"string\"");],, + [libffi_cv_as_string_pseudo_op=yes], + [libffi_cv_as_string_pseudo_op=no]) + ]) + if test "x$libffi_cv_as_string_pseudo_op" = xyes; then + AC_DEFINE(HAVE_AS_STRING_PSEUDO_OP, 1, + [Define if your assembler supports .string.]) + fi +fi + +case "$target" in + *-apple-darwin10* | *-*-freebsd* | *-*-openbsd* | *-pc-solaris*) + AC_DEFINE(FFI_MMAP_EXEC_WRIT, 1, + [Cannot use malloc on this target, so, we revert to + alternative means]) + ;; +esac + +if test x$TARGET = xX86_64; then + AC_CACHE_CHECK([assembler supports unwind section type], + libffi_cv_as_x86_64_unwind_section_type, [ + libffi_cv_as_x86_64_unwind_section_type=yes + echo '.section .eh_frame,"a",@unwind' > conftest.s + if $CC $CFLAGS -c conftest.s 2>&1 | grep -i warning > /dev/null; then + libffi_cv_as_x86_64_unwind_section_type=no + fi + ]) + if test "x$libffi_cv_as_x86_64_unwind_section_type" = xyes; then + AC_DEFINE(HAVE_AS_X86_64_UNWIND_SECTION_TYPE, 1, + [Define if your assembler supports unwind section type.]) + fi +fi + +AC_CACHE_CHECK([whether .eh_frame section should be read-only], + libffi_cv_ro_eh_frame, [ + libffi_cv_ro_eh_frame=no + echo 'extern void foo (void); void bar (void) { foo (); foo (); }' > conftest.c + if $CC $CFLAGS -S -fpic -fexceptions -o conftest.s conftest.c > /dev/null 2>&1; then + if grep '.section.*eh_frame.*"a"' conftest.s > /dev/null; then + libffi_cv_ro_eh_frame=yes + elif grep '.section.*eh_frame.*#alloc' conftest.c \ + | grep -v '#write' > /dev/null; then + libffi_cv_ro_eh_frame=yes + fi + fi + rm -f conftest.* + ]) +if test "x$libffi_cv_ro_eh_frame" = xyes; then + AC_DEFINE(HAVE_RO_EH_FRAME, 1, + [Define if .eh_frame sections should be read-only.]) + AC_DEFINE(EH_FRAME_FLAGS, "a", + [Define to the flags needed for the .section .eh_frame directive.]) +else + AC_DEFINE(EH_FRAME_FLAGS, "aw", + [Define to the flags needed for the .section .eh_frame directive.]) +fi + +AC_CACHE_CHECK([for __attribute__((visibility("hidden")))], + libffi_cv_hidden_visibility_attribute, [ + echo 'int __attribute__ ((visibility ("hidden"))) foo (void) { return 1; }' > conftest.c + libffi_cv_hidden_visibility_attribute=no + if AC_TRY_COMMAND(${CC-cc} -Werror -S conftest.c -o conftest.s 1>&AS_MESSAGE_LOG_FD); then + if grep '\.hidden.*foo' conftest.s >/dev/null; then + libffi_cv_hidden_visibility_attribute=yes + fi + fi + rm -f conftest.* + ]) +if test $libffi_cv_hidden_visibility_attribute = yes; then + AC_DEFINE(HAVE_HIDDEN_VISIBILITY_ATTRIBUTE, 1, + [Define if __attribute__((visibility("hidden"))) is supported.]) +fi + +AH_BOTTOM([ +#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE +#ifdef LIBFFI_ASM +#define FFI_HIDDEN(name) .hidden name +#else +#define FFI_HIDDEN __attribute__ ((visibility ("hidden"))) +#endif +#else +#ifdef LIBFFI_ASM +#define FFI_HIDDEN(name) +#else +#define FFI_HIDDEN +#endif +#endif +]) + +AC_SUBST(TARGET) +AC_SUBST(TARGETDIR) + +AC_SUBST(SHELL) + +AC_ARG_ENABLE(debug, +[ --enable-debug debugging mode], + if test "$enable_debug" = "yes"; then + AC_DEFINE(FFI_DEBUG, 1, [Define this if you want extra debugging.]) + fi) +AM_CONDITIONAL(FFI_DEBUG, test "$enable_debug" = "yes") + +AC_ARG_ENABLE(structs, +[ --disable-structs omit code for struct support], + if test "$enable_structs" = "no"; then + AC_DEFINE(FFI_NO_STRUCTS, 1, [Define this is you do not want support for aggregate types.]) + fi) + +AC_ARG_ENABLE(raw-api, +[ --disable-raw-api make the raw api unavailable], + if test "$enable_raw_api" = "no"; then + AC_DEFINE(FFI_NO_RAW_API, 1, [Define this is you do not want support for the raw API.]) + fi) + +AC_ARG_ENABLE(purify-safety, +[ --enable-purify-safety purify-safe mode], + if test "$enable_purify_safety" = "yes"; then + AC_DEFINE(USING_PURIFY, 1, [Define this if you are using Purify and want to suppress spurious messages.]) + fi) + +if test -n "$with_cross_host" && + test x"$with_cross_host" != x"no"; then + toolexecdir='$(exec_prefix)/$(target_alias)' + toolexeclibdir='$(toolexecdir)/lib' +else + toolexecdir='$(libdir)/gcc-lib/$(target_alias)' + toolexeclibdir='$(libdir)' +fi +multi_os_directory=`$CC -print-multi-os-directory` +case $multi_os_directory in + .) ;; # Avoid trailing /. + *) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; +esac +AC_SUBST(toolexecdir) +AC_SUBST(toolexeclibdir) + +if test "${multilib}" = "yes"; then + multilib_arg="--enable-multilib" +else + multilib_arg= +fi + +AC_CONFIG_COMMANDS(include, [test -d include || mkdir include]) +AC_CONFIG_COMMANDS(src, [ +test -d src || mkdir src +test -d src/$TARGETDIR || mkdir src/$TARGETDIR +], [TARGETDIR="$TARGETDIR"]) + +AC_CONFIG_LINKS(include/ffitarget.h:src/$TARGETDIR/ffitarget.h) + +AC_CONFIG_FILES(include/Makefile include/ffi.h Makefile testsuite/Makefile man/Makefile libffi.pc) + +AC_OUTPUT diff --git a/js/src/ctypes/libffi/configure.host b/js/src/ctypes/libffi/configure.host new file mode 100644 index 0000000..f52457b --- /dev/null +++ b/js/src/ctypes/libffi/configure.host @@ -0,0 +1,11 @@ +# configure.host +# +# This shell script handles all host based configuration for libffi. +# + +# THIS TABLE IS SORTED. KEEP IT THAT WAY. +case "${host}" in + frv*-elf) + LDFLAGS=`echo $LDFLAGS | sed "s/\-B[^ ]*libgloss\/frv\///"`\ -B`pwd`/../libgloss/frv/ + ;; +esac diff --git a/js/src/ctypes/libffi/depcomp b/js/src/ctypes/libffi/depcomp new file mode 100755 index 0000000..ca5ea4e --- /dev/null +++ b/js/src/ctypes/libffi/depcomp @@ -0,0 +1,584 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2006-10-15.18 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006 Free Software +# Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program 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 General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + stat=$? + + if test -f "$tmpdepfile"; then : + else + stripped=`echo "$stripped" | sed 's,^.*/,,'` + tmpdepfile="$stripped.u" + fi + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + outname="$stripped.o" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add `dependent.h:' lines. + sed -ne '2,${; s/^ *//; s/ \\*$//; s/$/:/; p;}' "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/js/src/ctypes/libffi/doc/libffi.info b/js/src/ctypes/libffi/doc/libffi.info new file mode 100644 index 0000000..449320c --- /dev/null +++ b/js/src/ctypes/libffi/doc/libffi.info @@ -0,0 +1,593 @@ +This is ../libffi/doc/libffi.info, produced by makeinfo version 4.13 +from ../libffi/doc/libffi.texi. + +This manual is for Libffi, a portable foreign-function interface +library. + + Copyright (C) 2008, 2010 Red Hat, Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or + (at your option) any later version. A copy of the license is + included in the section entitled "GNU General Public License". + + +INFO-DIR-SECTION Development +START-INFO-DIR-ENTRY +* libffi: (libffi). Portable foreign-function interface library. +END-INFO-DIR-ENTRY + + +File: libffi.info, Node: Top, Next: Introduction, Up: (dir) + +libffi +****** + +This manual is for Libffi, a portable foreign-function interface +library. + + Copyright (C) 2008, 2010 Red Hat, Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or + (at your option) any later version. A copy of the license is + included in the section entitled "GNU General Public License". + + +* Menu: + +* Introduction:: What is libffi? +* Using libffi:: How to use libffi. +* Missing Features:: Things libffi can't do. +* Index:: Index. + + +File: libffi.info, Node: Introduction, Next: Using libffi, Prev: Top, Up: Top + +1 What is libffi? +***************** + +Compilers for high level languages generate code that follow certain +conventions. These conventions are necessary, in part, for separate +compilation to work. One such convention is the "calling convention". +The calling convention is a set of assumptions made by the compiler +about where function arguments will be found on entry to a function. A +calling convention also specifies where the return value for a function +is found. The calling convention is also sometimes called the "ABI" or +"Application Binary Interface". + + Some programs may not know at the time of compilation what arguments +are to be passed to a function. For instance, an interpreter may be +told at run-time about the number and types of arguments used to call a +given function. `Libffi' can be used in such programs to provide a +bridge from the interpreter program to compiled code. + + The `libffi' library provides a portable, high level programming +interface to various calling conventions. This allows a programmer to +call any function specified by a call interface description at run time. + + FFI stands for Foreign Function Interface. A foreign function +interface is the popular name for the interface that allows code +written in one language to call code written in another language. The +`libffi' library really only provides the lowest, machine dependent +layer of a fully featured foreign function interface. A layer must +exist above `libffi' that handles type conversions for values passed +between the two languages. + + +File: libffi.info, Node: Using libffi, Next: Missing Features, Prev: Introduction, Up: Top + +2 Using libffi +************** + +* Menu: + +* The Basics:: The basic libffi API. +* Simple Example:: A simple example. +* Types:: libffi type descriptions. +* Multiple ABIs:: Different passing styles on one platform. +* The Closure API:: Writing a generic function. +* Closure Example:: A closure example. + + +File: libffi.info, Node: The Basics, Next: Simple Example, Up: Using libffi + +2.1 The Basics +============== + +`Libffi' assumes that you have a pointer to the function you wish to +call and that you know the number and types of arguments to pass it, as +well as the return type of the function. + + The first thing you must do is create an `ffi_cif' object that +matches the signature of the function you wish to call. This is a +separate step because it is common to make multiple calls using a +single `ffi_cif'. The "cif" in `ffi_cif' stands for Call InterFace. +To prepare a call interface object, use the function `ffi_prep_cif'. + + -- Function: ffi_status ffi_prep_cif (ffi_cif *CIF, ffi_abi ABI, + unsigned int NARGS, ffi_type *RTYPE, ffi_type **ARGTYPES) + This initializes CIF according to the given parameters. + + ABI is the ABI to use; normally `FFI_DEFAULT_ABI' is what you + want. *note Multiple ABIs:: for more information. + + NARGS is the number of arguments that this function accepts. + `libffi' does not yet handle varargs functions; see *note Missing + Features:: for more information. + + RTYPE is a pointer to an `ffi_type' structure that describes the + return type of the function. *Note Types::. + + ARGTYPES is a vector of `ffi_type' pointers. ARGTYPES must have + NARGS elements. If NARGS is 0, this argument is ignored. + + `ffi_prep_cif' returns a `libffi' status code, of type + `ffi_status'. This will be either `FFI_OK' if everything worked + properly; `FFI_BAD_TYPEDEF' if one of the `ffi_type' objects is + incorrect; or `FFI_BAD_ABI' if the ABI parameter is invalid. + + To call a function using an initialized `ffi_cif', use the +`ffi_call' function: + + -- Function: void ffi_call (ffi_cif *CIF, void *FN, void *RVALUE, void + **AVALUES) + This calls the function FN according to the description given in + CIF. CIF must have already been prepared using `ffi_prep_cif'. + + RVALUE is a pointer to a chunk of memory that will hold the result + of the function call. This must be large enough to hold the + result and must be suitably aligned; it is the caller's + responsibility to ensure this. If CIF declares that the function + returns `void' (using `ffi_type_void'), then RVALUE is ignored. + If RVALUE is `NULL', then the return value is discarded. + + AVALUES is a vector of `void *' pointers that point to the memory + locations holding the argument values for a call. If CIF declares + that the function has no arguments (i.e., NARGS was 0), then + AVALUES is ignored. Note that argument values may be modified by + the callee (for instance, structs passed by value); the burden of + copying pass-by-value arguments is placed on the caller. + + +File: libffi.info, Node: Simple Example, Next: Types, Prev: The Basics, Up: Using libffi + +2.2 Simple Example +================== + +Here is a trivial example that calls `puts' a few times. + + #include + #include + + int main() + { + ffi_cif cif; + ffi_type *args[1]; + void *values[1]; + char *s; + int rc; + + /* Initialize the argument info vectors */ + args[0] = &ffi_type_pointer; + values[0] = &s; + + /* Initialize the cif */ + if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_uint, args) == FFI_OK) + { + s = "Hello World!"; + ffi_call(&cif, puts, &rc, values); + /* rc now holds the result of the call to puts */ + + /* values holds a pointer to the function's arg, so to + call puts() again all we need to do is change the + value of s */ + s = "This is cool!"; + ffi_call(&cif, puts, &rc, values); + } + + return 0; + } + + +File: libffi.info, Node: Types, Next: Multiple ABIs, Prev: Simple Example, Up: Using libffi + +2.3 Types +========= + +* Menu: + +* Primitive Types:: Built-in types. +* Structures:: Structure types. +* Type Example:: Structure type example. + + +File: libffi.info, Node: Primitive Types, Next: Structures, Up: Types + +2.3.1 Primitive Types +--------------------- + +`Libffi' provides a number of built-in type descriptors that can be +used to describe argument and return types: + +`ffi_type_void' + The type `void'. This cannot be used for argument types, only for + return values. + +`ffi_type_uint8' + An unsigned, 8-bit integer type. + +`ffi_type_sint8' + A signed, 8-bit integer type. + +`ffi_type_uint16' + An unsigned, 16-bit integer type. + +`ffi_type_sint16' + A signed, 16-bit integer type. + +`ffi_type_uint32' + An unsigned, 32-bit integer type. + +`ffi_type_sint32' + A signed, 32-bit integer type. + +`ffi_type_uint64' + An unsigned, 64-bit integer type. + +`ffi_type_sint64' + A signed, 64-bit integer type. + +`ffi_type_float' + The C `float' type. + +`ffi_type_double' + The C `double' type. + +`ffi_type_uchar' + The C `unsigned char' type. + +`ffi_type_schar' + The C `signed char' type. (Note that there is not an exact + equivalent to the C `char' type in `libffi'; ordinarily you should + either use `ffi_type_schar' or `ffi_type_uchar' depending on + whether `char' is signed.) + +`ffi_type_ushort' + The C `unsigned short' type. + +`ffi_type_sshort' + The C `short' type. + +`ffi_type_uint' + The C `unsigned int' type. + +`ffi_type_sint' + The C `int' type. + +`ffi_type_ulong' + The C `unsigned long' type. + +`ffi_type_slong' + The C `long' type. + +`ffi_type_longdouble' + On platforms that have a C `long double' type, this is defined. + On other platforms, it is not. + +`ffi_type_pointer' + A generic `void *' pointer. You should use this for all pointers, + regardless of their real type. + + Each of these is of type `ffi_type', so you must take the address +when passing to `ffi_prep_cif'. + + +File: libffi.info, Node: Structures, Next: Type Example, Prev: Primitive Types, Up: Types + +2.3.2 Structures +---------------- + +Although `libffi' has no special support for unions or bit-fields, it +is perfectly happy passing structures back and forth. You must first +describe the structure to `libffi' by creating a new `ffi_type' object +for it. + + -- ffi_type: + The `ffi_type' has the following members: + `size_t size' + This is set by `libffi'; you should initialize it to zero. + + `unsigned short alignment' + This is set by `libffi'; you should initialize it to zero. + + `unsigned short type' + For a structure, this should be set to `FFI_TYPE_STRUCT'. + + `ffi_type **elements' + This is a `NULL'-terminated array of pointers to `ffi_type' + objects. There is one element per field of the struct. + + +File: libffi.info, Node: Type Example, Prev: Structures, Up: Types + +2.3.3 Type Example +------------------ + +The following example initializes a `ffi_type' object representing the +`tm' struct from Linux's `time.h'. + + Here is how the struct is defined: + + struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + /* Those are for future use. */ + long int __tm_gmtoff__; + __const char *__tm_zone__; + }; + + Here is the corresponding code to describe this struct to `libffi': + + { + ffi_type tm_type; + ffi_type *tm_type_elements[12]; + int i; + + tm_type.size = tm_type.alignment = 0; + tm_type.elements = &tm_type_elements; + + for (i = 0; i < 9; i++) + tm_type_elements[i] = &ffi_type_sint; + + tm_type_elements[9] = &ffi_type_slong; + tm_type_elements[10] = &ffi_type_pointer; + tm_type_elements[11] = NULL; + + /* tm_type can now be used to represent tm argument types and + return types for ffi_prep_cif() */ + } + + +File: libffi.info, Node: Multiple ABIs, Next: The Closure API, Prev: Types, Up: Using libffi + +2.4 Multiple ABIs +================= + +A given platform may provide multiple different ABIs at once. For +instance, the x86 platform has both `stdcall' and `fastcall' functions. + + `libffi' provides some support for this. However, this is +necessarily platform-specific. + + +File: libffi.info, Node: The Closure API, Next: Closure Example, Prev: Multiple ABIs, Up: Using libffi + +2.5 The Closure API +=================== + +`libffi' also provides a way to write a generic function - a function +that can accept and decode any combination of arguments. This can be +useful when writing an interpreter, or to provide wrappers for +arbitrary functions. + + This facility is called the "closure API". Closures are not +supported on all platforms; you can check the `FFI_CLOSURES' define to +determine whether they are supported on the current platform. + + Because closures work by assembling a tiny function at runtime, they +require special allocation on platforms that have a non-executable +heap. Memory management for closures is handled by a pair of functions: + + -- Function: void *ffi_closure_alloc (size_t SIZE, void **CODE) + Allocate a chunk of memory holding SIZE bytes. This returns a + pointer to the writable address, and sets *CODE to the + corresponding executable address. + + SIZE should be sufficient to hold a `ffi_closure' object. + + -- Function: void ffi_closure_free (void *WRITABLE) + Free memory allocated using `ffi_closure_alloc'. The argument is + the writable address that was returned. + + Once you have allocated the memory for a closure, you must construct +a `ffi_cif' describing the function call. Finally you can prepare the +closure function: + + -- Function: ffi_status ffi_prep_closure_loc (ffi_closure *CLOSURE, + ffi_cif *CIF, void (*FUN) (ffi_cif *CIF, void *RET, void + **ARGS, void *USER_DATA), void *USER_DATA, void *CODELOC) + Prepare a closure function. + + CLOSURE is the address of a `ffi_closure' object; this is the + writable address returned by `ffi_closure_alloc'. + + CIF is the `ffi_cif' describing the function parameters. + + USER_DATA is an arbitrary datum that is passed, uninterpreted, to + your closure function. + + CODELOC is the executable address returned by `ffi_closure_alloc'. + + FUN is the function which will be called when the closure is + invoked. It is called with the arguments: + CIF + The `ffi_cif' passed to `ffi_prep_closure_loc'. + + RET + A pointer to the memory used for the function's return value. + FUN must fill this, unless the function is declared as + returning `void'. + + ARGS + A vector of pointers to memory holding the arguments to the + function. + + USER_DATA + The same USER_DATA that was passed to `ffi_prep_closure_loc'. + + `ffi_prep_closure_loc' will return `FFI_OK' if everything went ok, + and something else on error. + + After calling `ffi_prep_closure_loc', you can cast CODELOC to the + appropriate pointer-to-function type. + + You may see old code referring to `ffi_prep_closure'. This function +is deprecated, as it cannot handle the need for separate writable and +executable addresses. + + +File: libffi.info, Node: Closure Example, Prev: The Closure API, Up: Using libffi + +2.6 Closure Example +=================== + +A trivial example that creates a new `puts' by binding `fputs' with +`stdin'. + + #include + #include + + /* Acts like puts with the file given at time of enclosure. */ + void puts_binding(ffi_cif *cif, unsigned int *ret, void* args[], + FILE *stream) + { + *ret = fputs(*(char **)args[0], stream); + } + + int main() + { + ffi_cif cif; + ffi_type *args[1]; + ffi_closure *closure; + + int (*bound_puts)(char *); + int rc; + + /* Allocate closure and bound_puts */ + closure = ffi_closure_alloc(sizeof(ffi_closure), &bound_puts); + + if (closure) + { + /* Initialize the argument info vectors */ + args[0] = &ffi_type_pointer; + + /* Initialize the cif */ + if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_uint, args) == FFI_OK) + { + /* Initialize the closure, setting stream to stdout */ + if (ffi_prep_closure_loc(closure, &cif, puts_binding, + stdout, bound_puts) == FFI_OK) + { + rc = bound_puts("Hello World!"); + /* rc now holds the result of the call to fputs */ + } + } + } + + /* Deallocate both closure, and bound_puts */ + ffi_closure_free(closure); + + return 0; + } + + +File: libffi.info, Node: Missing Features, Next: Index, Prev: Using libffi, Up: Top + +3 Missing Features +****************** + +`libffi' is missing a few features. We welcome patches to add support +for these. + + * There is no support for calling varargs functions. This may work + on some platforms, depending on how the ABI is defined, but it is + not reliable. + + * There is no support for bit fields in structures. + + * The closure API is + + * The "raw" API is undocumented. + + +File: libffi.info, Node: Index, Prev: Missing Features, Up: Top + +Index +***** + +[index] +* Menu: + +* : Structures. (line 12) +* ABI: Introduction. (line 13) +* Application Binary Interface: Introduction. (line 13) +* calling convention: Introduction. (line 13) +* cif: The Basics. (line 14) +* closure API: The Closure API. (line 13) +* closures: The Closure API. (line 13) +* FFI: Introduction. (line 31) +* ffi_call: The Basics. (line 41) +* ffi_closure_alloc: The Closure API. (line 19) +* ffi_closure_free: The Closure API. (line 26) +* FFI_CLOSURES: The Closure API. (line 13) +* ffi_prep_cif: The Basics. (line 16) +* ffi_prep_closure_loc: The Closure API. (line 34) +* ffi_status <1>: The Closure API. (line 37) +* ffi_status: The Basics. (line 18) +* ffi_type: Structures. (line 11) +* ffi_type_double: Primitive Types. (line 41) +* ffi_type_float: Primitive Types. (line 38) +* ffi_type_longdouble: Primitive Types. (line 71) +* ffi_type_pointer: Primitive Types. (line 75) +* ffi_type_schar: Primitive Types. (line 47) +* ffi_type_sint: Primitive Types. (line 62) +* ffi_type_sint16: Primitive Types. (line 23) +* ffi_type_sint32: Primitive Types. (line 29) +* ffi_type_sint64: Primitive Types. (line 35) +* ffi_type_sint8: Primitive Types. (line 17) +* ffi_type_slong: Primitive Types. (line 68) +* ffi_type_sshort: Primitive Types. (line 56) +* ffi_type_uchar: Primitive Types. (line 44) +* ffi_type_uint: Primitive Types. (line 59) +* ffi_type_uint16: Primitive Types. (line 20) +* ffi_type_uint32: Primitive Types. (line 26) +* ffi_type_uint64: Primitive Types. (line 32) +* ffi_type_uint8: Primitive Types. (line 14) +* ffi_type_ulong: Primitive Types. (line 65) +* ffi_type_ushort: Primitive Types. (line 53) +* ffi_type_void: Primitive Types. (line 10) +* Foreign Function Interface: Introduction. (line 31) +* void <1>: The Closure API. (line 20) +* void: The Basics. (line 43) + + + +Tag Table: +Node: Top706 +Node: Introduction1448 +Node: Using libffi3084 +Node: The Basics3570 +Node: Simple Example6356 +Node: Types7383 +Node: Primitive Types7666 +Node: Structures9486 +Node: Type Example10346 +Node: Multiple ABIs11569 +Node: The Closure API11940 +Node: Closure Example14884 +Node: Missing Features16443 +Node: Index16936 + +End Tag Table diff --git a/js/src/ctypes/libffi/doc/libffi.texi b/js/src/ctypes/libffi/doc/libffi.texi new file mode 100644 index 0000000..5cdd667 --- /dev/null +++ b/js/src/ctypes/libffi/doc/libffi.texi @@ -0,0 +1,600 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename libffi.info +@settitle libffi +@setchapternewpage off +@c %**end of header + +@c Merge the standard indexes into a single one. +@syncodeindex fn cp +@syncodeindex vr cp +@syncodeindex ky cp +@syncodeindex pg cp +@syncodeindex tp cp + +@include version.texi + +@copying + +This manual is for Libffi, a portable foreign-function interface +library. + +Copyright @copyright{} 2008, 2010 Red Hat, Inc. + +@quotation +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. A copy of the license is included in the +section entitled ``GNU General Public License''. + +@end quotation +@end copying + +@dircategory Development +@direntry +* libffi: (libffi). Portable foreign-function interface library. +@end direntry + +@titlepage +@title Libffi +@page +@vskip 0pt plus 1filll +@insertcopying +@end titlepage + + +@ifnottex +@node Top +@top libffi + +@insertcopying + +@menu +* Introduction:: What is libffi? +* Using libffi:: How to use libffi. +* Missing Features:: Things libffi can't do. +* Index:: Index. +@end menu + +@end ifnottex + + +@node Introduction +@chapter What is libffi? + +Compilers for high level languages generate code that follow certain +conventions. These conventions are necessary, in part, for separate +compilation to work. One such convention is the @dfn{calling +convention}. The calling convention is a set of assumptions made by +the compiler about where function arguments will be found on entry to +a function. A calling convention also specifies where the return +value for a function is found. The calling convention is also +sometimes called the @dfn{ABI} or @dfn{Application Binary Interface}. +@cindex calling convention +@cindex ABI +@cindex Application Binary Interface + +Some programs may not know at the time of compilation what arguments +are to be passed to a function. For instance, an interpreter may be +told at run-time about the number and types of arguments used to call +a given function. @samp{Libffi} can be used in such programs to +provide a bridge from the interpreter program to compiled code. + +The @samp{libffi} library provides a portable, high level programming +interface to various calling conventions. This allows a programmer to +call any function specified by a call interface description at run +time. + +@acronym{FFI} stands for Foreign Function Interface. A foreign +function interface is the popular name for the interface that allows +code written in one language to call code written in another language. +The @samp{libffi} library really only provides the lowest, machine +dependent layer of a fully featured foreign function interface. A +layer must exist above @samp{libffi} that handles type conversions for +values passed between the two languages. +@cindex FFI +@cindex Foreign Function Interface + + +@node Using libffi +@chapter Using libffi + +@menu +* The Basics:: The basic libffi API. +* Simple Example:: A simple example. +* Types:: libffi type descriptions. +* Multiple ABIs:: Different passing styles on one platform. +* The Closure API:: Writing a generic function. +* Closure Example:: A closure example. +@end menu + + +@node The Basics +@section The Basics + +@samp{Libffi} assumes that you have a pointer to the function you wish +to call and that you know the number and types of arguments to pass +it, as well as the return type of the function. + +The first thing you must do is create an @code{ffi_cif} object that +matches the signature of the function you wish to call. This is a +separate step because it is common to make multiple calls using a +single @code{ffi_cif}. The @dfn{cif} in @code{ffi_cif} stands for +Call InterFace. To prepare a call interface object, use the function +@code{ffi_prep_cif}. +@cindex cif + +@findex ffi_prep_cif +@defun ffi_status ffi_prep_cif (ffi_cif *@var{cif}, ffi_abi @var{abi}, unsigned int @var{nargs}, ffi_type *@var{rtype}, ffi_type **@var{argtypes}) +This initializes @var{cif} according to the given parameters. + +@var{abi} is the ABI to use; normally @code{FFI_DEFAULT_ABI} is what +you want. @ref{Multiple ABIs} for more information. + +@var{nargs} is the number of arguments that this function accepts. +@samp{libffi} does not yet handle varargs functions; see @ref{Missing +Features} for more information. + +@var{rtype} is a pointer to an @code{ffi_type} structure that +describes the return type of the function. @xref{Types}. + +@var{argtypes} is a vector of @code{ffi_type} pointers. +@var{argtypes} must have @var{nargs} elements. If @var{nargs} is 0, +this argument is ignored. + +@code{ffi_prep_cif} returns a @code{libffi} status code, of type +@code{ffi_status}. This will be either @code{FFI_OK} if everything +worked properly; @code{FFI_BAD_TYPEDEF} if one of the @code{ffi_type} +objects is incorrect; or @code{FFI_BAD_ABI} if the @var{abi} parameter +is invalid. +@end defun + + +To call a function using an initialized @code{ffi_cif}, use the +@code{ffi_call} function: + +@findex ffi_call +@defun void ffi_call (ffi_cif *@var{cif}, void *@var{fn}, void *@var{rvalue}, void **@var{avalues}) +This calls the function @var{fn} according to the description given in +@var{cif}. @var{cif} must have already been prepared using +@code{ffi_prep_cif}. + +@var{rvalue} is a pointer to a chunk of memory that will hold the +result of the function call. This must be large enough to hold the +result and must be suitably aligned; it is the caller's responsibility +to ensure this. If @var{cif} declares that the function returns +@code{void} (using @code{ffi_type_void}), then @var{rvalue} is +ignored. If @var{rvalue} is @samp{NULL}, then the return value is +discarded. + +@var{avalues} is a vector of @code{void *} pointers that point to the +memory locations holding the argument values for a call. If @var{cif} +declares that the function has no arguments (i.e., @var{nargs} was 0), +then @var{avalues} is ignored. Note that argument values may be +modified by the callee (for instance, structs passed by value); the +burden of copying pass-by-value arguments is placed on the caller. +@end defun + + +@node Simple Example +@section Simple Example + +Here is a trivial example that calls @code{puts} a few times. + +@example +#include +#include + +int main() +@{ + ffi_cif cif; + ffi_type *args[1]; + void *values[1]; + char *s; + int rc; + + /* Initialize the argument info vectors */ + args[0] = &ffi_type_pointer; + values[0] = &s; + + /* Initialize the cif */ + if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_uint, args) == FFI_OK) + @{ + s = "Hello World!"; + ffi_call(&cif, puts, &rc, values); + /* rc now holds the result of the call to puts */ + + /* values holds a pointer to the function's arg, so to + call puts() again all we need to do is change the + value of s */ + s = "This is cool!"; + ffi_call(&cif, puts, &rc, values); + @} + + return 0; +@} +@end example + + +@node Types +@section Types + +@menu +* Primitive Types:: Built-in types. +* Structures:: Structure types. +* Type Example:: Structure type example. +@end menu + +@node Primitive Types +@subsection Primitive Types + +@code{Libffi} provides a number of built-in type descriptors that can +be used to describe argument and return types: + +@table @code +@item ffi_type_void +@tindex ffi_type_void +The type @code{void}. This cannot be used for argument types, only +for return values. + +@item ffi_type_uint8 +@tindex ffi_type_uint8 +An unsigned, 8-bit integer type. + +@item ffi_type_sint8 +@tindex ffi_type_sint8 +A signed, 8-bit integer type. + +@item ffi_type_uint16 +@tindex ffi_type_uint16 +An unsigned, 16-bit integer type. + +@item ffi_type_sint16 +@tindex ffi_type_sint16 +A signed, 16-bit integer type. + +@item ffi_type_uint32 +@tindex ffi_type_uint32 +An unsigned, 32-bit integer type. + +@item ffi_type_sint32 +@tindex ffi_type_sint32 +A signed, 32-bit integer type. + +@item ffi_type_uint64 +@tindex ffi_type_uint64 +An unsigned, 64-bit integer type. + +@item ffi_type_sint64 +@tindex ffi_type_sint64 +A signed, 64-bit integer type. + +@item ffi_type_float +@tindex ffi_type_float +The C @code{float} type. + +@item ffi_type_double +@tindex ffi_type_double +The C @code{double} type. + +@item ffi_type_uchar +@tindex ffi_type_uchar +The C @code{unsigned char} type. + +@item ffi_type_schar +@tindex ffi_type_schar +The C @code{signed char} type. (Note that there is not an exact +equivalent to the C @code{char} type in @code{libffi}; ordinarily you +should either use @code{ffi_type_schar} or @code{ffi_type_uchar} +depending on whether @code{char} is signed.) + +@item ffi_type_ushort +@tindex ffi_type_ushort +The C @code{unsigned short} type. + +@item ffi_type_sshort +@tindex ffi_type_sshort +The C @code{short} type. + +@item ffi_type_uint +@tindex ffi_type_uint +The C @code{unsigned int} type. + +@item ffi_type_sint +@tindex ffi_type_sint +The C @code{int} type. + +@item ffi_type_ulong +@tindex ffi_type_ulong +The C @code{unsigned long} type. + +@item ffi_type_slong +@tindex ffi_type_slong +The C @code{long} type. + +@item ffi_type_longdouble +@tindex ffi_type_longdouble +On platforms that have a C @code{long double} type, this is defined. +On other platforms, it is not. + +@item ffi_type_pointer +@tindex ffi_type_pointer +A generic @code{void *} pointer. You should use this for all +pointers, regardless of their real type. +@end table + +Each of these is of type @code{ffi_type}, so you must take the address +when passing to @code{ffi_prep_cif}. + + +@node Structures +@subsection Structures + +Although @samp{libffi} has no special support for unions or +bit-fields, it is perfectly happy passing structures back and forth. +You must first describe the structure to @samp{libffi} by creating a +new @code{ffi_type} object for it. + +@tindex ffi_type +@deftp ffi_type +The @code{ffi_type} has the following members: +@table @code +@item size_t size +This is set by @code{libffi}; you should initialize it to zero. + +@item unsigned short alignment +This is set by @code{libffi}; you should initialize it to zero. + +@item unsigned short type +For a structure, this should be set to @code{FFI_TYPE_STRUCT}. + +@item ffi_type **elements +This is a @samp{NULL}-terminated array of pointers to @code{ffi_type} +objects. There is one element per field of the struct. +@end table +@end deftp + + +@node Type Example +@subsection Type Example + +The following example initializes a @code{ffi_type} object +representing the @code{tm} struct from Linux's @file{time.h}. + +Here is how the struct is defined: + +@example +struct tm @{ + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + /* Those are for future use. */ + long int __tm_gmtoff__; + __const char *__tm_zone__; +@}; +@end example + +Here is the corresponding code to describe this struct to +@code{libffi}: + +@example + @{ + ffi_type tm_type; + ffi_type *tm_type_elements[12]; + int i; + + tm_type.size = tm_type.alignment = 0; + tm_type.elements = &tm_type_elements; + + for (i = 0; i < 9; i++) + tm_type_elements[i] = &ffi_type_sint; + + tm_type_elements[9] = &ffi_type_slong; + tm_type_elements[10] = &ffi_type_pointer; + tm_type_elements[11] = NULL; + + /* tm_type can now be used to represent tm argument types and + return types for ffi_prep_cif() */ + @} +@end example + + +@node Multiple ABIs +@section Multiple ABIs + +A given platform may provide multiple different ABIs at once. For +instance, the x86 platform has both @samp{stdcall} and @samp{fastcall} +functions. + +@code{libffi} provides some support for this. However, this is +necessarily platform-specific. + +@c FIXME: document the platforms + +@node The Closure API +@section The Closure API + +@code{libffi} also provides a way to write a generic function -- a +function that can accept and decode any combination of arguments. +This can be useful when writing an interpreter, or to provide wrappers +for arbitrary functions. + +This facility is called the @dfn{closure API}. Closures are not +supported on all platforms; you can check the @code{FFI_CLOSURES} +define to determine whether they are supported on the current +platform. +@cindex closures +@cindex closure API +@findex FFI_CLOSURES + +Because closures work by assembling a tiny function at runtime, they +require special allocation on platforms that have a non-executable +heap. Memory management for closures is handled by a pair of +functions: + +@findex ffi_closure_alloc +@defun void *ffi_closure_alloc (size_t @var{size}, void **@var{code}) +Allocate a chunk of memory holding @var{size} bytes. This returns a +pointer to the writable address, and sets *@var{code} to the +corresponding executable address. + +@var{size} should be sufficient to hold a @code{ffi_closure} object. +@end defun + +@findex ffi_closure_free +@defun void ffi_closure_free (void *@var{writable}) +Free memory allocated using @code{ffi_closure_alloc}. The argument is +the writable address that was returned. +@end defun + + +Once you have allocated the memory for a closure, you must construct a +@code{ffi_cif} describing the function call. Finally you can prepare +the closure function: + +@findex ffi_prep_closure_loc +@defun ffi_status ffi_prep_closure_loc (ffi_closure *@var{closure}, ffi_cif *@var{cif}, void (*@var{fun}) (ffi_cif *@var{cif}, void *@var{ret}, void **@var{args}, void *@var{user_data}), void *@var{user_data}, void *@var{codeloc}) +Prepare a closure function. + +@var{closure} is the address of a @code{ffi_closure} object; this is +the writable address returned by @code{ffi_closure_alloc}. + +@var{cif} is the @code{ffi_cif} describing the function parameters. + +@var{user_data} is an arbitrary datum that is passed, uninterpreted, +to your closure function. + +@var{codeloc} is the executable address returned by +@code{ffi_closure_alloc}. + +@var{fun} is the function which will be called when the closure is +invoked. It is called with the arguments: +@table @var +@item cif +The @code{ffi_cif} passed to @code{ffi_prep_closure_loc}. + +@item ret +A pointer to the memory used for the function's return value. +@var{fun} must fill this, unless the function is declared as returning +@code{void}. +@c FIXME: is this NULL for void-returning functions? + +@item args +A vector of pointers to memory holding the arguments to the function. + +@item user_data +The same @var{user_data} that was passed to +@code{ffi_prep_closure_loc}. +@end table + +@code{ffi_prep_closure_loc} will return @code{FFI_OK} if everything +went ok, and something else on error. +@c FIXME: what? + +After calling @code{ffi_prep_closure_loc}, you can cast @var{codeloc} +to the appropriate pointer-to-function type. +@end defun + +You may see old code referring to @code{ffi_prep_closure}. This +function is deprecated, as it cannot handle the need for separate +writable and executable addresses. + +@node Closure Example +@section Closure Example + +A trivial example that creates a new @code{puts} by binding +@code{fputs} with @code{stdin}. + +@example +#include +#include + +/* Acts like puts with the file given at time of enclosure. */ +void puts_binding(ffi_cif *cif, unsigned int *ret, void* args[], + FILE *stream) +@{ + *ret = fputs(*(char **)args[0], stream); +@} + +int main() +@{ + ffi_cif cif; + ffi_type *args[1]; + ffi_closure *closure; + + int (*bound_puts)(char *); + int rc; + + /* Allocate closure and bound_puts */ + closure = ffi_closure_alloc(sizeof(ffi_closure), &bound_puts); + + if (closure) + @{ + /* Initialize the argument info vectors */ + args[0] = &ffi_type_pointer; + + /* Initialize the cif */ + if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_uint, args) == FFI_OK) + @{ + /* Initialize the closure, setting stream to stdout */ + if (ffi_prep_closure_loc(closure, &cif, puts_binding, + stdout, bound_puts) == FFI_OK) + @{ + rc = bound_puts("Hello World!"); + /* rc now holds the result of the call to fputs */ + @} + @} + @} + + /* Deallocate both closure, and bound_puts */ + ffi_closure_free(closure); + + return 0; +@} + +@end example + + +@node Missing Features +@chapter Missing Features + +@code{libffi} is missing a few features. We welcome patches to add +support for these. + +@itemize @bullet +@item +There is no support for calling varargs functions. This may work on +some platforms, depending on how the ABI is defined, but it is not +reliable. + +@item +There is no support for bit fields in structures. + +@item +The closure API is + +@c FIXME: ... + +@item +The ``raw'' API is undocumented. +@c argument promotion? +@c unions? +@c anything else? +@end itemize + + +@node Index +@unnumbered Index + +@printindex cp + +@bye diff --git a/js/src/ctypes/libffi/doc/stamp-vti b/js/src/ctypes/libffi/doc/stamp-vti new file mode 100644 index 0000000..81d0b79 --- /dev/null +++ b/js/src/ctypes/libffi/doc/stamp-vti @@ -0,0 +1,4 @@ +@set UPDATED 14 February 2008 +@set UPDATED-MONTH February 2008 +@set EDITION 3.0.8 +@set VERSION 3.0.8 diff --git a/js/src/ctypes/libffi/doc/version.texi b/js/src/ctypes/libffi/doc/version.texi new file mode 100644 index 0000000..81d0b79 --- /dev/null +++ b/js/src/ctypes/libffi/doc/version.texi @@ -0,0 +1,4 @@ +@set UPDATED 14 February 2008 +@set UPDATED-MONTH February 2008 +@set EDITION 3.0.8 +@set VERSION 3.0.8 diff --git a/js/src/ctypes/libffi/fficonfig.h.in b/js/src/ctypes/libffi/fficonfig.h.in new file mode 100644 index 0000000..e012ebb --- /dev/null +++ b/js/src/ctypes/libffi/fficonfig.h.in @@ -0,0 +1,193 @@ +/* fficonfig.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +#undef CRAY_STACKSEG_END + +/* Define to 1 if using `alloca.c'. */ +#undef C_ALLOCA + +/* Define to the flags needed for the .section .eh_frame directive. */ +#undef EH_FRAME_FLAGS + +/* Define this if you want extra debugging. */ +#undef FFI_DEBUG + +/* Cannot use malloc on this target, so, we revert to alternative means */ +#undef FFI_MMAP_EXEC_WRIT + +/* Define this is you do not want support for the raw API. */ +#undef FFI_NO_RAW_API + +/* Define this is you do not want support for aggregate types. */ +#undef FFI_NO_STRUCTS + +/* Define to 1 if you have `alloca', as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#undef HAVE_ALLOCA_H + +/* Define if your assembler supports .ascii. */ +#undef HAVE_AS_ASCII_PSEUDO_OP + +/* Define if your assembler supports .cfi_* directives. */ +#undef HAVE_AS_CFI_PSEUDO_OP + +/* Define if your assembler supports .register. */ +#undef HAVE_AS_REGISTER_PSEUDO_OP + +/* Define if your assembler and linker support unaligned PC relative relocs. + */ +#undef HAVE_AS_SPARC_UA_PCREL + +/* Define if your assembler supports .string. */ +#undef HAVE_AS_STRING_PSEUDO_OP + +/* Define if your assembler supports unwind section type. */ +#undef HAVE_AS_X86_64_UNWIND_SECTION_TYPE + +/* Define if your assembler supports PC relative relocs. */ +#undef HAVE_AS_X86_PCREL + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define if __attribute__((visibility("hidden"))) is supported. */ +#undef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define if you have the long double type and it is bigger than a double */ +#undef HAVE_LONG_DOUBLE + +/* Define to 1 if you have the `memcpy' function. */ +#undef HAVE_MEMCPY + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `mmap' function. */ +#undef HAVE_MMAP + +/* Define if mmap with MAP_ANON(YMOUS) works. */ +#undef HAVE_MMAP_ANON + +/* Define if mmap of /dev/zero works. */ +#undef HAVE_MMAP_DEV_ZERO + +/* Define if read-only mmap of a plain file works. */ +#undef HAVE_MMAP_FILE + +/* Define if .eh_frame sections should be read-only. */ +#undef HAVE_RO_EH_FRAME + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MMAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +#undef NO_MINUS_C_MINUS_O + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of `double', as computed by sizeof. */ +#undef SIZEOF_DOUBLE + +/* The size of `long double', as computed by sizeof. */ +#undef SIZEOF_LONG_DOUBLE + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +#undef STACK_DIRECTION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define this if you are using Purify and want to suppress spurious messages. + */ +#undef USING_PURIFY + +/* Version number of package */ +#undef VERSION + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif + + +#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE +#ifdef LIBFFI_ASM +#define FFI_HIDDEN(name) .hidden name +#else +#define FFI_HIDDEN __attribute__ ((visibility ("hidden"))) +#endif +#else +#ifdef LIBFFI_ASM +#define FFI_HIDDEN(name) +#else +#define FFI_HIDDEN +#endif +#endif + diff --git a/js/src/ctypes/libffi/include/Makefile.am b/js/src/ctypes/libffi/include/Makefile.am new file mode 100644 index 0000000..fd28024 --- /dev/null +++ b/js/src/ctypes/libffi/include/Makefile.am @@ -0,0 +1,9 @@ +## Process this with automake to create Makefile.in + +AUTOMAKE_OPTIONS=foreign + +DISTCLEANFILES=ffitarget.h +EXTRA_DIST=ffi.h.in ffi_common.h + +includesdir = $(libdir)/@PACKAGE_NAME@-@PACKAGE_VERSION@/include +nodist_includes_HEADERS = ffi.h ffitarget.h diff --git a/js/src/ctypes/libffi/include/Makefile.in b/js/src/ctypes/libffi/include/Makefile.in new file mode 100644 index 0000000..5e00664 --- /dev/null +++ b/js/src/ctypes/libffi/include/Makefile.in @@ -0,0 +1,471 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = include +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/ffi.h.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/fficonfig.h +CONFIG_CLEAN_FILES = ffi.h ffitarget.h +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(includesdir)" +HEADERS = $(nodist_includes_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_LTLDFLAGS = @AM_LTLDFLAGS@ +AM_RUNTESTFLAGS = @AM_RUNTESTFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_LONG_DOUBLE = @HAVE_LONG_DOUBLE@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TARGET = @TARGET@ +TARGETDIR = @TARGETDIR@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +toolexecdir = @toolexecdir@ +toolexeclibdir = @toolexeclibdir@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign +DISTCLEANFILES = ffitarget.h +EXTRA_DIST = ffi.h.in ffi_common.h +includesdir = $(libdir)/@PACKAGE_NAME@-@PACKAGE_VERSION@/include +nodist_includes_HEADERS = ffi.h ffitarget.h +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign include/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +ffi.h: $(top_builddir)/config.status $(srcdir)/ffi.h.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-nodist_includesHEADERS: $(nodist_includes_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includesdir)" || $(MKDIR_P) "$(DESTDIR)$(includesdir)" + @list='$(nodist_includes_HEADERS)'; test -n "$(includesdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includesdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includesdir)" || exit $$?; \ + done + +uninstall-nodist_includesHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nodist_includes_HEADERS)'; test -n "$(includesdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(includesdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(includesdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(includesdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-nodist_includesHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-nodist_includesHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-nodist_includesHEADERS \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-nodist_includesHEADERS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/js/src/ctypes/libffi/include/ffi.h.in b/js/src/ctypes/libffi/include/ffi.h.in new file mode 100644 index 0000000..f4af9c8 --- /dev/null +++ b/js/src/ctypes/libffi/include/ffi.h.in @@ -0,0 +1,416 @@ +/* -----------------------------------------------------------------*-C-*- + libffi @VERSION@ - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------- + The basic API is described in the README file. + + The raw API is designed to bypass some of the argument packing + and unpacking on architectures for which it can be avoided. + + The closure API allows interpreted functions to be packaged up + inside a C function pointer, so that they can be called as C functions, + with no understanding on the client side that they are interpreted. + It can also be used in other cases in which it is necessary to package + up a user specified parameter and a function pointer as a single + function pointer. + + The closure API must be implemented in order to get its functionality, + e.g. for use by gij. Routines are provided to emulate the raw API + if the underlying platform doesn't allow faster implementation. + + More details on the raw and cloure API can be found in: + + http://gcc.gnu.org/ml/java/1999-q3/msg00138.html + + and + + http://gcc.gnu.org/ml/java/1999-q3/msg00174.html + -------------------------------------------------------------------- */ + +#ifndef LIBFFI_H +#define LIBFFI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Specify which architecture libffi is configured for. */ +#ifndef @TARGET@ +#define @TARGET@ +#endif + +/* ---- System configuration information --------------------------------- */ + +#include + +#ifndef LIBFFI_ASM + +#ifdef _MSC_VER +#define __attribute__(X) +#endif + +#include +#include + +/* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). + But we can find it either under the correct ANSI name, or under GNU + C's internal name. */ + +#define FFI_64_BIT_MAX 9223372036854775807 + +#ifdef LONG_LONG_MAX +# define FFI_LONG_LONG_MAX LONG_LONG_MAX +#else +# ifdef LLONG_MAX +# define FFI_LONG_LONG_MAX LLONG_MAX +# else +# ifdef __GNUC__ +# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ +# endif +# ifdef _AIX +# ifndef __PPC64__ +# if defined (__IBMC__) || defined (__IBMCPP__) +# define FFI_LONG_LONG_MAX LONGLONG_MAX +# endif +# endif /* __PPC64__ */ +# undef FFI_64_BIT_MAX +# define FFI_64_BIT_MAX 9223372036854775807LL +# endif +# endif +#endif + +/* The closure code assumes that this works on pointers, i.e. a size_t */ +/* can hold a pointer. */ + +typedef struct _ffi_type +{ + size_t size; + unsigned short alignment; + unsigned short type; + struct _ffi_type **elements; +} ffi_type; + +#ifndef LIBFFI_HIDE_BASIC_TYPES +#if SCHAR_MAX == 127 +# define ffi_type_uchar ffi_type_uint8 +# define ffi_type_schar ffi_type_sint8 +#else + #error "char size not supported" +#endif + +#if SHRT_MAX == 32767 +# define ffi_type_ushort ffi_type_uint16 +# define ffi_type_sshort ffi_type_sint16 +#elif SHRT_MAX == 2147483647 +# define ffi_type_ushort ffi_type_uint32 +# define ffi_type_sshort ffi_type_sint32 +#else + #error "short size not supported" +#endif + +#if INT_MAX == 32767 +# define ffi_type_uint ffi_type_uint16 +# define ffi_type_sint ffi_type_sint16 +#elif INT_MAX == 2147483647 +# define ffi_type_uint ffi_type_uint32 +# define ffi_type_sint ffi_type_sint32 +#elif INT_MAX == 9223372036854775807 +# define ffi_type_uint ffi_type_uint64 +# define ffi_type_sint ffi_type_sint64 +#else + #error "int size not supported" +#endif + +#if LONG_MAX == 2147483647 +# if FFI_LONG_LONG_MAX != FFI_64_BIT_MAX + #error "no 64-bit data type supported" +# endif +#elif LONG_MAX != FFI_64_BIT_MAX + #error "long size not supported" +#endif + +#if LONG_MAX == 2147483647 +# define ffi_type_ulong ffi_type_uint32 +# define ffi_type_slong ffi_type_sint32 +#elif LONG_MAX == FFI_64_BIT_MAX +# define ffi_type_ulong ffi_type_uint64 +# define ffi_type_slong ffi_type_sint64 +#else + #error "long size not supported" +#endif + +/* These are defined in types.c */ +extern ffi_type ffi_type_void; +extern ffi_type ffi_type_uint8; +extern ffi_type ffi_type_sint8; +extern ffi_type ffi_type_uint16; +extern ffi_type ffi_type_sint16; +extern ffi_type ffi_type_uint32; +extern ffi_type ffi_type_sint32; +extern ffi_type ffi_type_uint64; +extern ffi_type ffi_type_sint64; +extern ffi_type ffi_type_float; +extern ffi_type ffi_type_double; +extern ffi_type ffi_type_pointer; + +#if @HAVE_LONG_DOUBLE@ +extern ffi_type ffi_type_longdouble; +#else +#define ffi_type_longdouble ffi_type_double +#endif +#endif /* LIBFFI_HIDE_BASIC_TYPES */ + +typedef enum { + FFI_OK = 0, + FFI_BAD_TYPEDEF, + FFI_BAD_ABI +} ffi_status; + +typedef unsigned FFI_TYPE; + +typedef struct { + ffi_abi abi; + unsigned nargs; + ffi_type **arg_types; + ffi_type *rtype; + unsigned bytes; + unsigned flags; +#ifdef FFI_EXTRA_CIF_FIELDS + FFI_EXTRA_CIF_FIELDS; +#endif +} ffi_cif; + +/* ---- Definitions for the raw API -------------------------------------- */ + +#ifndef FFI_SIZEOF_ARG +# if LONG_MAX == 2147483647 +# define FFI_SIZEOF_ARG 4 +# elif LONG_MAX == FFI_64_BIT_MAX +# define FFI_SIZEOF_ARG 8 +# endif +#endif + +#ifndef FFI_SIZEOF_JAVA_RAW +# define FFI_SIZEOF_JAVA_RAW FFI_SIZEOF_ARG +#endif + +typedef union { + ffi_sarg sint; + ffi_arg uint; + float flt; + char data[FFI_SIZEOF_ARG]; + void* ptr; +} ffi_raw; + +#if FFI_SIZEOF_JAVA_RAW == 4 && FFI_SIZEOF_ARG == 8 +/* This is a special case for mips64/n32 ABI (and perhaps others) where + sizeof(void *) is 4 and FFI_SIZEOF_ARG is 8. */ +typedef union { + signed int sint; + unsigned int uint; + float flt; + char data[FFI_SIZEOF_JAVA_RAW]; + void* ptr; +} ffi_java_raw; +#else +typedef ffi_raw ffi_java_raw; +#endif + + +void ffi_raw_call (ffi_cif *cif, + void (*fn)(void), + void *rvalue, + ffi_raw *avalue); + +void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); +void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); +size_t ffi_raw_size (ffi_cif *cif); + +/* This is analogous to the raw API, except it uses Java parameter */ +/* packing, even on 64-bit machines. I.e. on 64-bit machines */ +/* longs and doubles are followed by an empty 64-bit word. */ + +void ffi_java_raw_call (ffi_cif *cif, + void (*fn)(void), + void *rvalue, + ffi_java_raw *avalue); + +void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw); +void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args); +size_t ffi_java_raw_size (ffi_cif *cif); + +/* ---- Definitions for closures ----------------------------------------- */ + +#if FFI_CLOSURES + +#ifdef _MSC_VER +__declspec(align(8)) +#endif +typedef struct { + char tramp[FFI_TRAMPOLINE_SIZE]; + ffi_cif *cif; + void (*fun)(ffi_cif*,void*,void**,void*); + void *user_data; +#ifdef __GNUC__ +} ffi_closure __attribute__((aligned (8))); +#else +} ffi_closure; +#endif + +void *ffi_closure_alloc (size_t size, void **code); +void ffi_closure_free (void *); + +ffi_status +ffi_prep_closure (ffi_closure*, + ffi_cif *, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data); + +ffi_status +ffi_prep_closure_loc (ffi_closure*, + ffi_cif *, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void*codeloc); + +typedef struct { + char tramp[FFI_TRAMPOLINE_SIZE]; + + ffi_cif *cif; + +#if !FFI_NATIVE_RAW_API + + /* if this is enabled, then a raw closure has the same layout + as a regular closure. We use this to install an intermediate + handler to do the transaltion, void** -> ffi_raw*. */ + + void (*translate_args)(ffi_cif*,void*,void**,void*); + void *this_closure; + +#endif + + void (*fun)(ffi_cif*,void*,ffi_raw*,void*); + void *user_data; + +} ffi_raw_closure; + +typedef struct { + char tramp[FFI_TRAMPOLINE_SIZE]; + + ffi_cif *cif; + +#if !FFI_NATIVE_RAW_API + + /* if this is enabled, then a raw closure has the same layout + as a regular closure. We use this to install an intermediate + handler to do the transaltion, void** -> ffi_raw*. */ + + void (*translate_args)(ffi_cif*,void*,void**,void*); + void *this_closure; + +#endif + + void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*); + void *user_data; + +} ffi_java_raw_closure; + +ffi_status +ffi_prep_raw_closure (ffi_raw_closure*, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data); + +ffi_status +ffi_prep_raw_closure_loc (ffi_raw_closure*, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data, + void *codeloc); + +ffi_status +ffi_prep_java_raw_closure (ffi_java_raw_closure*, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), + void *user_data); + +ffi_status +ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), + void *user_data, + void *codeloc); + +#endif /* FFI_CLOSURES */ + +/* ---- Public interface definition -------------------------------------- */ + +ffi_status ffi_prep_cif(ffi_cif *cif, + ffi_abi abi, + unsigned int nargs, + ffi_type *rtype, + ffi_type **atypes); + +void ffi_call(ffi_cif *cif, + void (*fn)(void), + void *rvalue, + void **avalue); + +/* Useful for eliminating compiler warnings */ +#define FFI_FN(f) ((void (*)(void))f) + +/* ---- Definitions shared with assembly code ---------------------------- */ + +#endif + +/* If these change, update src/mips/ffitarget.h. */ +#define FFI_TYPE_VOID 0 +#define FFI_TYPE_INT 1 +#define FFI_TYPE_FLOAT 2 +#define FFI_TYPE_DOUBLE 3 +#if @HAVE_LONG_DOUBLE@ +#define FFI_TYPE_LONGDOUBLE 4 +#else +#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE +#endif +#define FFI_TYPE_UINT8 5 +#define FFI_TYPE_SINT8 6 +#define FFI_TYPE_UINT16 7 +#define FFI_TYPE_SINT16 8 +#define FFI_TYPE_UINT32 9 +#define FFI_TYPE_SINT32 10 +#define FFI_TYPE_UINT64 11 +#define FFI_TYPE_SINT64 12 +#define FFI_TYPE_STRUCT 13 +#define FFI_TYPE_POINTER 14 + +/* This should always refer to the last type code (for sanity checks) */ +#define FFI_TYPE_LAST FFI_TYPE_POINTER + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/js/src/ctypes/libffi/include/ffi_common.h b/js/src/ctypes/libffi/include/ffi_common.h new file mode 100644 index 0000000..42cace9 --- /dev/null +++ b/js/src/ctypes/libffi/include/ffi_common.h @@ -0,0 +1,122 @@ +/* ----------------------------------------------------------------------- + ffi_common.h - Copyright (c) 1996 Red Hat, Inc. + Copyright (C) 2007 Free Software Foundation, Inc + + Common internal definitions and macros. Only necessary for building + libffi. + ----------------------------------------------------------------------- */ + +#ifndef FFI_COMMON_H +#define FFI_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Do not move this. Some versions of AIX are very picky about where + this is positioned. */ +#ifdef __GNUC__ +/* mingw64 defines this already in malloc.h. */ +#ifndef alloca +# define alloca __builtin_alloca +#endif +# define MAYBE_UNUSED __attribute__((__unused__)) +#else +# define MAYBE_UNUSED +# if HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +# ifdef _MSC_VER +# define alloca _alloca +# else +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +/* Check for the existence of memcpy. */ +#if STDC_HEADERS +# include +#else +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + +#if defined(FFI_DEBUG) +#include +#endif + +#ifdef FFI_DEBUG +void ffi_assert(char *expr, char *file, int line); +void ffi_stop_here(void); +void ffi_type_test(ffi_type *a, char *file, int line); + +#define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) +#define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) +#define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__) +#else +#define FFI_ASSERT(x) +#define FFI_ASSERT_AT(x, f, l) +#define FFI_ASSERT_VALID_TYPE(x) +#endif + +#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) +#define ALIGN_DOWN(v, a) (((size_t) (v)) & -a) + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif); + +/* Extended cif, used in callback from assembly routine */ +typedef struct +{ + ffi_cif *cif; + void *rvalue; + void **avalue; +} extended_cif; + +/* Terse sized type definitions. */ +#if defined(_MSC_VER) || defined(__sgi) +typedef unsigned char UINT8; +typedef signed char SINT8; +typedef unsigned short UINT16; +typedef signed short SINT16; +typedef unsigned int UINT32; +typedef signed int SINT32; +# ifdef _MSC_VER +typedef unsigned __int64 UINT64; +typedef signed __int64 SINT64; +# else +# include +typedef uint64_t UINT64; +typedef int64_t SINT64; +# endif +#else +typedef unsigned int UINT8 __attribute__((__mode__(__QI__))); +typedef signed int SINT8 __attribute__((__mode__(__QI__))); +typedef unsigned int UINT16 __attribute__((__mode__(__HI__))); +typedef signed int SINT16 __attribute__((__mode__(__HI__))); +typedef unsigned int UINT32 __attribute__((__mode__(__SI__))); +typedef signed int SINT32 __attribute__((__mode__(__SI__))); +typedef unsigned int UINT64 __attribute__((__mode__(__DI__))); +typedef signed int SINT64 __attribute__((__mode__(__DI__))); +#endif + +typedef float FLOAT32; + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/js/src/ctypes/libffi/install-sh b/js/src/ctypes/libffi/install-sh new file mode 100755 index 0000000..6ebe46d --- /dev/null +++ b/js/src/ctypes/libffi/install-sh @@ -0,0 +1,323 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2004-12-17.09 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +chmodcmd="$chmodprog 0755" +chowncmd= +chgrpcmd= +stripcmd= +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src= +dst= +dir_arg= +dstarg= +no_target_directory= + +usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: +-c (ignored) +-d create directories instead of installing files. +-g GROUP $chgrpprog installed files to GROUP. +-m MODE $chmodprog installed files to MODE. +-o USER $chownprog installed files to USER. +-s $stripprog installed files. +-t DIRECTORY install into DIRECTORY. +-T report an error if DSTFILE is a directory. +--help display this help and exit. +--version display version info and exit. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG +" + +while test -n "$1"; do + case $1 in + -c) shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + --help) echo "$usage"; exit 0;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t) dstarg=$2 + shift + shift + continue;; + + -T) no_target_directory=true + shift + continue;; + + --version) echo "$0 $scriptversion"; exit 0;; + + *) # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + test -n "$dir_arg$dstarg" && break + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dstarg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dstarg" + shift # fnord + fi + shift # arg + dstarg=$arg + done + break;; + esac +done + +if test -z "$1"; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src ;; + esac + + if test -n "$dir_arg"; then + dst=$src + src= + + if test -d "$dst"; then + mkdircmd=: + chmodcmd= + else + mkdircmd=$mkdirprog + fi + else + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dstarg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dstarg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst ;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dstarg: Is a directory" >&2 + exit 1 + fi + dst=$dst/`basename "$src"` + fi + fi + + # This sed command emulates the dirname command. + dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` + + # Make sure that the destination directory exists. + + # Skip lots of stat calls in the usual case. + if test ! -d "$dstdir"; then + defaultIFS=' + ' + IFS="${IFS-$defaultIFS}" + + oIFS=$IFS + # Some sh's can't handle IFS=/ for some reason. + IFS='%' + set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` + shift + IFS=$oIFS + + pathcomp= + + while test $# -ne 0 ; do + pathcomp=$pathcomp$1 + shift + if test ! -d "$pathcomp"; then + $mkdirprog "$pathcomp" + # mkdir can fail with a `File exist' error in case several + # install-sh are creating the directory concurrently. This + # is OK. + test -d "$pathcomp" || exit + fi + pathcomp=$pathcomp/ + done + fi + + if test -n "$dir_arg"; then + $doit $mkdircmd "$dst" \ + && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } + + else + dstfile=`basename "$dst"` + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + trap '(exit $?); exit' 1 2 13 15 + + # Copy the file name to the temp name. + $doit $cpprog "$src" "$dsttmp" && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && + + # Now rename the file to the real destination. + { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ + || { + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + if test -f "$dstdir/$dstfile"; then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ + || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ + || { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit 1 + } + else + : + fi + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + } + } + fi || { (exit 1); exit 1; } +done + +# The final little trick to "correctly" pass the exit status to the exit trap. +{ + (exit 0); exit 0 +} + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/js/src/ctypes/libffi/libffi.pc.in b/js/src/ctypes/libffi/libffi.pc.in new file mode 100644 index 0000000..c2e1c7b --- /dev/null +++ b/js/src/ctypes/libffi/libffi.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=${libdir}/@PACKAGE_NAME@-@PACKAGE_VERSION@/include + +Name: @PACKAGE_NAME@ +Description: Library supporting Foreign Function Interfaces +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lffi +Cflags: -I${includedir} diff --git a/js/src/ctypes/libffi/libtool-version b/js/src/ctypes/libffi/libtool-version new file mode 100644 index 0000000..b8b80e0 --- /dev/null +++ b/js/src/ctypes/libffi/libtool-version @@ -0,0 +1,29 @@ +# This file is used to maintain libtool version info for libffi. See +# the libtool manual to understand the meaning of the fields. This is +# a separate file so that version updates don't involve re-running +# automake. +# +# Here are a set of rules to help you update your library version +# information: +# +# 1. Start with version information of `0:0:0' for each libtool library. +# +# 2. Update the version information only immediately before a public +# release of your software. More frequent updates are unnecessary, +# and only guarantee that the current interface number gets larger +# faster. +# +# 3. If the library source code has changed at all since the last +# update, then increment revision (`c:r:a' becomes `c:r+1:a'). +# +# 4. If any interfaces have been added, removed, or changed since the +# last update, increment current, and set revision to 0. +# +# 5. If any interfaces have been added since the last public release, +# then increment age. +# +# 6. If any interfaces have been removed since the last public +# release, then set age to 0. +# +# CURRENT:REVISION:AGE +5:10:0 diff --git a/js/src/ctypes/libffi/ltmain.sh b/js/src/ctypes/libffi/ltmain.sh new file mode 100755 index 0000000..a72f2fd --- /dev/null +++ b/js/src/ctypes/libffi/ltmain.sh @@ -0,0 +1,8406 @@ +# Generated from ltmain.m4sh. + +# ltmain.sh (GNU libtool) 2.2.6b +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print informational messages (default) +# --version print version information +# -h, --help print short or long help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.2.6b +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION=2.2.6b +TIMESTAMP="" +package_revision=1.3017 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# NLS nuisances: We save the old values to restore during execute mode. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done + +$lt_unset CDPATH + + + + + +: ${CP="cp -f"} +: ${ECHO="echo"} +: ${EGREP="/bin/grep -E"} +: ${FGREP="/bin/grep -F"} +: ${GREP="/bin/grep"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SED="/bin/sed"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +# Generated shell functions inserted here. + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +# In the unlikely event $progname began with a '-', it would play havoc with +# func_echo (imagine progname=-n), so we prepend ./ in that case: +func_dirname_and_basename "$progpath" +progname=$func_basename_result +case $progname in + -*) progname=./$progname ;; +esac + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=: + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname${mode+: }$mode: $*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"` + done + my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "X$my_tmpdir" | $Xsed +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "X$1" | $Xsed \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + + + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $SED -n '/^# Usage:/,/# -h/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + $ECHO + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help +# Echo long help message to standard output and exit. +func_help () +{ + $SED -n '/^# Usage:/,/# Report bugs to/ { + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ + p + }' < "$progpath" + exit $? +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + func_error "missing argument for $1" + exit_cmd=exit +} + +exit_cmd=: + + + + + +# Check that we have a working $ECHO. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell, and then maybe $ECHO will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# Parse options once, thoroughly. This comes as soon as possible in +# the script to make things like `libtool --version' happen quickly. +{ + + # Shorthand for --mode=foo, only valid as the first argument + case $1 in + clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; + compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; + execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; + finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; + install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; + link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; + uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; + esac + + # Parse non-mode specific arguments: + while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --config) func_config ;; + + --debug) preserve_args="$preserve_args $opt" + func_echo "enabling shell trace mode" + opt_debug='set -x' + $opt_debug + ;; + + -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break + execute_dlfiles="$execute_dlfiles $1" + shift + ;; + + --dry-run | -n) opt_dry_run=: ;; + --features) func_features ;; + --finish) mode="finish" ;; + + --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break + case $1 in + # Valid mode arguments: + clean) ;; + compile) ;; + execute) ;; + finish) ;; + install) ;; + link) ;; + relink) ;; + uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; + esac + + mode="$1" + shift + ;; + + --preserve-dup-deps) + opt_duplicate_deps=: ;; + + --quiet|--silent) preserve_args="$preserve_args $opt" + opt_silent=: + ;; + + --verbose| -v) preserve_args="$preserve_args $opt" + opt_silent=false + ;; + + --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break + preserve_args="$preserve_args $opt $1" + func_enable_tag "$1" # tagname is set here + shift + ;; + + # Separate optargs to long options: + -dlopen=*|--mode=*|--tag=*) + func_opt_split "$opt" + set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} + shift + ;; + + -\?|-h) func_usage ;; + --help) opt_help=: ;; + --version) func_version ;; + + -*) func_fatal_help "unrecognized option \`$opt'" ;; + + *) nonopt="$opt" + break + ;; + esac + done + + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_duplicate_deps + ;; + esac + + # Having warned about all mis-specified options, bail out if + # anything was wrong. + $exit_cmd $EXIT_FAILURE +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +## ----------- ## +## Main. ## +## ----------- ## + +$opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + test -z "$mode" && func_fatal_error "error: you must specify a MODE." + + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$mode' for more information." +} + + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_ltwrapper_scriptname_result="" + if func_ltwrapper_executable_p "$1"; then + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" + fi +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + case "$@ " in + " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T <?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + removelist="$removelist $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + removelist="$removelist $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + command="$command -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { +test "$mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$mode'" + ;; + esac + + $ECHO + $ECHO "Try \`$progname --help' for more information about other modes." + + exit $? +} + + # Now that we've collected a possible --mode arg, show help if necessary + $opt_help && func_mode_help + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_quote_for_eval "$file" + args="$args $func_quote_for_eval_result" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + $ECHO "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + $ECHO "X----------------------------------------------------------------------" | $Xsed + $ECHO "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + $ECHO + $ECHO "If you ever happen to want to link against installed libraries" + $ECHO "in a given directory, LIBDIR, you must either use libtool, and" + $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'" + $ECHO "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $ECHO " - add LIBDIR to the \`$shlibpath_var' environment variable" + $ECHO " during execution" + fi + if test -n "$runpath_var"; then + $ECHO " - add LIBDIR to the \`$runpath_var' environment variable" + $ECHO " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $ECHO " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $ECHO + + $ECHO "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual" + $ECHO "pages." + ;; + *) + $ECHO "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + $ECHO "X----------------------------------------------------------------------" | $Xsed + exit $EXIT_SUCCESS +} + +test "$mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $ECHO "X$nonopt" | $GREP shtool >/dev/null; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + install_prog="$install_prog$func_quote_for_eval_result" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + case " $install_prog " in + *[\\\ /]cp\ *) ;; + *) prev=$arg ;; + esac + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + install_prog="$install_prog $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_verbose "extracting global C symbols from \`$progfile'" + $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + $ECHO >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +" + case $host in + *cygwin* | *mingw* | *cegcc* ) + $ECHO >> "$output_objdir/$my_dlsyms" "\ +/* DATA imports from DLLs on WIN32 con't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs. */" + lt_dlsym_const= ;; + *osf5*) + echo >> "$output_objdir/$my_dlsyms" "\ +/* This system does not cope well with relocations in const data */" + lt_dlsym_const= ;; + *) + lt_dlsym_const=const ;; + esac + + $ECHO >> "$output_objdir/$my_dlsyms" "\ +extern $lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +$lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + $ECHO >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) symtab_cflags="$symtab_cflags $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?' + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + + +# func_emit_wrapper_part1 [arg=no] +# +# Emit the first part of a libtool wrapper script on stdout. +# For more information, see the description associated with +# func_emit_wrapper(), below. +func_emit_wrapper_part1 () +{ + func_emit_wrapper_part1_arg1=no + if test -n "$1" ; then + func_emit_wrapper_part1_arg1=$1 + fi + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + ECHO=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$ECHO works! + : + else + # Restart under the correct shell, and then maybe \$ECHO will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $ECHO "\ + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done +" +} +# end: func_emit_wrapper_part1 + +# func_emit_wrapper_part2 [arg=no] +# +# Emit the second part of a libtool wrapper script on stdout. +# For more information, see the description associated with +# func_emit_wrapper(), below. +func_emit_wrapper_part2 () +{ + func_emit_wrapper_part2_arg1=no + if test -n "$1" ; then + func_emit_wrapper_part2_arg1=$1 + fi + + $ECHO "\ + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} +# end: func_emit_wrapper_part2 + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=no + if test -n "$1" ; then + func_emit_wrapper_arg1=$1 + fi + + # split this up so that func_emit_cwrapperexe_src + # can call each part independently. + func_emit_wrapper_part1 "${func_emit_wrapper_arg1}" + func_emit_wrapper_part2 "${func_emit_wrapper_arg1}" +} + + +# func_to_host_path arg +# +# Convert paths to host format when used with build tools. +# Intended for use with "native" mingw (where libtool itself +# is running under the msys shell), or in the following cross- +# build environments: +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# where wine is equipped with the `winepath' executable. +# In the native mingw case, the (msys) shell automatically +# converts paths for any non-msys applications it launches, +# but that facility isn't available from inside the cwrapper. +# Similar accommodations are necessary for $host mingw and +# $build cygwin. Calling this function does no harm for other +# $host/$build combinations not listed above. +# +# ARG is the path (on $build) that should be converted to +# the proper representation for $host. The result is stored +# in $func_to_host_path_result. +func_to_host_path () +{ + func_to_host_path_result="$1" + if test -n "$1" ; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + case $build in + *mingw* ) # actually, msys + # awkward: cmd appends spaces to result + lt_sed_strip_trailing_spaces="s/[ ]*\$//" + func_to_host_path_tmp1=`( cmd //c echo "$1" |\ + $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_path_tmp1=`cygpath -w "$1"` + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # Unfortunately, winepath does not exit with a non-zero + # error code, so we are forced to check the contents of + # stdout. On the other hand, if the command is not + # found, the shell will set an exit code of 127 and print + # *an error message* to stdout. So we must check for both + # error code of zero AND non-empty stdout, which explains + # the odd construction: + func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` + if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + else + # Allow warning below. + func_to_host_path_result="" + fi + ;; + esac + if test -z "$func_to_host_path_result" ; then + func_error "Could not determine host path corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_path_result="$1" + fi + ;; + esac + fi +} +# end: func_to_host_path + +# func_to_host_pathlist arg +# +# Convert pathlists to host format when used with build tools. +# See func_to_host_path(), above. This function supports the +# following $build/$host combinations (but does no harm for +# combinations not listed here): +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# +# Path separators are also converted from $build format to +# $host format. If ARG begins or ends with a path separator +# character, it is preserved (but converted to $host format) +# on output. +# +# ARG is a pathlist (on $build) that should be converted to +# the proper representation on $host. The result is stored +# in $func_to_host_pathlist_result. +func_to_host_pathlist () +{ + func_to_host_pathlist_result="$1" + if test -n "$1" ; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_to_host_pathlist_tmp2="$1" + # Once set for this call, this variable should not be + # reassigned. It is used in tha fallback case. + func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e 's|^:*||' -e 's|:*$||'` + case $build in + *mingw* ) # Actually, msys. + # Awkward: cmd appends spaces to result. + lt_sed_strip_trailing_spaces="s/[ ]*\$//" + func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"` + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # unfortunately, winepath doesn't convert pathlists + func_to_host_pathlist_result="" + func_to_host_pathlist_oldIFS=$IFS + IFS=: + for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do + IFS=$func_to_host_pathlist_oldIFS + if test -n "$func_to_host_pathlist_f" ; then + func_to_host_path "$func_to_host_pathlist_f" + if test -n "$func_to_host_path_result" ; then + if test -z "$func_to_host_pathlist_result" ; then + func_to_host_pathlist_result="$func_to_host_path_result" + else + func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result" + fi + fi + fi + IFS=: + done + IFS=$func_to_host_pathlist_oldIFS + ;; + esac + if test -z "$func_to_host_pathlist_result" ; then + func_error "Could not determine the host path(s) corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This may break if $1 contains DOS-style drive + # specifications. The fix is not to complicate the expression + # below, but for the user to provide a working wine installation + # with winepath so that path translation in the cross-to-mingw + # case works properly. + lt_replace_pathsep_nix_to_dos="s|:|;|g" + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_replace_pathsep_nix_to_dos"` + fi + # Now, add the leading and trailing path separators back + case "$1" in + :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" + ;; + esac + case "$1" in + *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;" + ;; + esac + ;; + esac + fi +} +# end: func_to_host_pathlist + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +# define setmode _setmode +#else +# include +# include +# ifdef __CYGWIN__ +# include +# define HAVE_SETENV +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +#ifdef _MSC_VER +# define S_IXUSR _S_IEXEC +# define stat _stat +# ifndef _INTPTR_T_DEFINED +# define intptr_t int +# endif +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifdef __CYGWIN__ +# define FOPEN_WB "wb" +#endif + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#undef LTWRAPPER_DEBUGPRINTF +#if defined DEBUGWRAPPER +# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args +static void +ltwrapper_debugprintf (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); +} +#else +# define LTWRAPPER_DEBUGPRINTF(args) +#endif + +const char *program_name = NULL; + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_fatal (const char *message, ...); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_opt_process_env_set (const char *arg); +void lt_opt_process_env_prepend (const char *arg); +void lt_opt_process_env_append (const char *arg); +int lt_split_name_value (const char *arg, char** name, char** value); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); + +static const char *script_text_part1 = +EOF + + func_emit_wrapper_part1 yes | + $SED -e 's/\([\\"]\)/\\\1/g' \ + -e 's/^/ "/' -e 's/$/\\n"/' + echo ";" + cat <"))); + for (i = 0; i < newargc; i++) + { + LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : ""))); + } + +EOF + + case $host_os in + mingw*) + cat <<"EOF" + /* execv doesn't actually work on mingw as expected on unix */ + rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); + if (rval == -1) + { + /* failed to start process */ + LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno)); + return 127; + } + return rval; +EOF + ;; + *) + cat <<"EOF" + execv (lt_argv_zero, newargz); + return rval; /* =127, but avoids unused variable warning */ +EOF + ;; + esac + + cat <<"EOF" +} + +void * +xmalloc (size_t num) +{ + void *p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), + string) : NULL; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char) name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable (const char *path) +{ + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n", + wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!")); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n", + tmp_pathspec)); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + char *errstr = strerror (errno); + lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal ("Could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} + +void +lt_setenv (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n", + (name ? name : ""), + (value ? value : ""))); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +int +lt_split_name_value (const char *arg, char** name, char** value) +{ + const char *p; + int len; + if (!arg || !*arg) + return 1; + + p = strchr (arg, (int)'='); + + if (!p) + return 1; + + *value = xstrdup (++p); + + len = strlen (arg) - strlen (*value); + *name = XMALLOC (char, len); + strncpy (*name, arg, len-1); + (*name)[len - 1] = '\0'; + + return 0; +} + +void +lt_opt_process_env_set (const char *arg) +{ + char *name = NULL; + char *value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg); + } + + lt_setenv (name, value); + XFREE (name); + XFREE (value); +} + +void +lt_opt_process_env_prepend (const char *arg) +{ + char *name = NULL; + char *value = NULL; + char *new_value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg); + } + + new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + XFREE (name); + XFREE (value); +} + +void +lt_opt_process_env_append (const char *arg) +{ + char *name = NULL; + char *value = NULL; + char *new_value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg); + } + + new_value = lt_extend_str (getenv (name), value, 1); + lt_setenv (name, new_value); + XFREE (new_value); + XFREE (name); + XFREE (value); +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + (name ? name : ""), + (value ? value : ""))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + (name ? name : ""), + (value ? value : ""))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + + +EOF +} +# end: func_emit_cwrapperexe_src + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) deplibs="$deplibs $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + weak_libs="$weak_libs $arg" + prev= + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname '-L' '' "$arg" + dir=$func_stripname_result + if test -z "$dir"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" + linker_flags="$linker_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -F/path gives path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC + # @file GCC response files + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_duplicate_deps ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + case $lib in + *.la) func_source "$lib" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"` + case " $weak_libs " in + *" $deplib_base "*) ;; + *) deplibs="$deplibs $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + dir=$func_stripname_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $ECHO + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because the file extensions .$libext of this argument makes me believe" + $ECHO "*** that it is just a static archive that I should not use here." + else + $ECHO + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) temp_rpath="$temp_rpath$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + notinst_deplibs="$notinst_deplibs $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + $ECHO + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $ECHO + $ECHO "*** And there doesn't seem to be a static archive available" + $ECHO "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $ECHO + $ECHO "*** Warning: This system can not link to static lib archive $lib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $ECHO "*** But as you try to build a module library, libtool will still create " + $ECHO "*** a static module, that should work as long as the dlopening application" + $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $ECHO + $ECHO "*** However, this would only work if libtool was able to extract symbol" + $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" + $ECHO "*** not find such a program. So, this module is probably useless." + $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_dirname "$deplib" "" "." + dir="$func_dirname_result" + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + $ECHO + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + libobjs="$libobjs $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"` + # deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"` + # dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $ECHO + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $ECHO + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \ + -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"` + done + fi + if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' | + $GREP . >/dev/null; then + $ECHO + if test "X$deplibs_check_method" = "Xnone"; then + $ECHO "*** Warning: inter-library dependencies are not supported in this platform." + else + $ECHO "*** Warning: inter-library dependencies are not known to be supported." + fi + $ECHO "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $ECHO + $ECHO "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + $ECHO "*** a static module, that should work as long as the dlopening" + $ECHO "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $ECHO + $ECHO "*** However, this would only work if libtool was able to extract symbol" + $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" + $ECHO "*** not find such a program. So, this module is probably useless." + $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $ECHO "*** The inter-library dependencies that have been dropped here will be" + $ECHO "*** automatically added whenever a program is linked with this library" + $ECHO "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $ECHO + $ECHO "*** Since this library must not contain undefined symbols," + $ECHO "*** because either the platform does not support them or" + $ECHO "*** it was explicitly requested with -no-undefined," + $ECHO "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + delfiles="$delfiles $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + func_len " $cmd" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$ECHO "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + $ECHO 'INPUT (' > $output + for obj in $save_libobjs + do + $ECHO "$obj" >> $output + done + $ECHO ')' >> $output + delfiles="$delfiles $output" + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + $ECHO "$obj" >> $output + done + delfiles="$delfiles $output" + output=$firstobj\"$file_list_spec$output\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + delfiles="$delfiles $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *cegcc) + # Disable wrappers for cegcc, we are cross compiling anyway. + wrappers_required=no + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $ECHO for shipping. + if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + oldobjs="$oldobjs $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $ECHO "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlfiles="$newdlfiles $libdir/$name" + ;; + *) newdlfiles="$newdlfiles $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlprefiles="$newdlprefiles $libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$mode" = link || test "$mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) RM="$RM $arg"; rmforce=yes ;; + -*) RM="$RM $arg" ;; + *) files="$files $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + rmfiles="$rmfiles $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$mode" = uninstall || test "$mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/js/src/ctypes/libffi/m4/libtool.m4 b/js/src/ctypes/libffi/m4/libtool.m4 new file mode 100644 index 0000000..671cde1 --- /dev/null +++ b/js/src/ctypes/libffi/m4/libtool.m4 @@ -0,0 +1,7360 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 56 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl +_LT_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + +## ------------------------------------- ## +## Accumulate code for creating libtool. ## +## ------------------------------------- ## + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + +## ------------------------ ## +## FIXME: Eliminate VARNAME ## +## ------------------------ ## + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "X$" | $Xsed -e "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\[$]0 --fallback-echo"')dnl " + lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` + ;; +esac + +_LT_OUTPUT_LIBTOOL_INIT +]) + + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +cat >"$CONFIG_LT" <<_LTEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate a libtool stub with the current configuration. + +lt_cl_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AS_SHELL_SANITIZE +_AS_PREPARE + +exec AS_MESSAGE_FD>&1 +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2008 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +if test "$no_create" != yes; then + lt_cl_success=: + test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" + exec AS_MESSAGE_LOG_FD>/dev/null + $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false + exec AS_MESSAGE_LOG_FD>>config.log + $lt_cl_success || AS_EXIT(1) +fi +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_XSI_SHELLFNS + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES +# -------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX +# ----------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_SHELL_INIT + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[_LT_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +[$]* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(lt_ECHO) +]) +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], + [An echo program that does not interpret backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[AC_CHECK_TOOL(AR, ar, false) +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1]) + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line __oline__ "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[[3-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method == "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC*) + # IBM XL 8.0 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac +AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE(int foo(void) {}, + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + ) + LDFLAGS="$save_LDFLAGS" + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], + [[If ld is used when linking, flag to hardcode $libdir into a binary + during linking. This must work even if $libdir does not exist]]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [fix_srcfile_path], [1], + [Fix the shell variable $srcfile for the compiler]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_PROG_CXX +# ------------ +# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ +# compiler, we have our own version here. +m4_defun([_LT_PROG_CXX], +[ +pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) +AC_PROG_CXX +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_CXX + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_CXX], []) + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[AC_REQUIRE([_LT_PROG_CXX])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + gnu*) + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 will use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + xl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=echo + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +]) +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_PROG_F77 +# ------------ +# Since AC_PROG_F77 is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_F77], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) +AC_PROG_F77 +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_F77 + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_F77], []) + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_REQUIRE([_LT_PROG_F77])dnl +AC_LANG_PUSH(Fortran 77) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${F77-"f77"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_PROG_FC +# ----------- +# Since AC_PROG_FC is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_FC], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) +AC_PROG_FC +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_FC + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_FC], []) + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_REQUIRE([_LT_PROG_FC])dnl +AC_LANG_PUSH(Fortran) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${FC-"f95"} + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC="$lt_save_CC" +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC="$lt_save_CC" +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_XSI_SHELLFNS +# --------------------- +# Bourne and XSI compatible variants of some useful shell functions. +m4_defun([_LT_PROG_XSI_SHELLFNS], +[case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $[*] )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +dnl func_dirname_and_basename +dnl A portable version of this function is already defined in general.m4sh +dnl so there is no need for it here. + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[[^=]]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$[@]"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]+=\$[2]" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]=\$$[1]\$[2]" +} + +_LT_EOF + ;; + esac +]) diff --git a/js/src/ctypes/libffi/m4/ltoptions.m4 b/js/src/ctypes/libffi/m4/ltoptions.m4 new file mode 100644 index 0000000..34151a3 --- /dev/null +++ b/js/src/ctypes/libffi/m4/ltoptions.m4 @@ -0,0 +1,368 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + +## --------------------------------- ## +## Macros to handle LT_INIT options. ## +## --------------------------------- ## + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [0], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + +## ----------------- ## +## LTDL_INIT Options ## +## ----------------- ## + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) diff --git a/js/src/ctypes/libffi/m4/ltsugar.m4 b/js/src/ctypes/libffi/m4/ltsugar.m4 new file mode 100644 index 0000000..9000a05 --- /dev/null +++ b/js/src/ctypes/libffi/m4/ltsugar.m4 @@ -0,0 +1,123 @@ +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) diff --git a/js/src/ctypes/libffi/m4/ltversion.m4 b/js/src/ctypes/libffi/m4/ltversion.m4 new file mode 100644 index 0000000..f3c5309 --- /dev/null +++ b/js/src/ctypes/libffi/m4/ltversion.m4 @@ -0,0 +1,23 @@ +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# Generated from ltversion.in. + +# serial 3017 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.2.6b]) +m4_define([LT_PACKAGE_REVISION], [1.3017]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.2.6b' +macro_revision='1.3017' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) diff --git a/js/src/ctypes/libffi/m4/lt~obsolete.m4 b/js/src/ctypes/libffi/m4/lt~obsolete.m4 new file mode 100644 index 0000000..637bb20 --- /dev/null +++ b/js/src/ctypes/libffi/m4/lt~obsolete.m4 @@ -0,0 +1,92 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 4 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) diff --git a/js/src/ctypes/libffi/man/Makefile.am b/js/src/ctypes/libffi/man/Makefile.am new file mode 100644 index 0000000..2519277 --- /dev/null +++ b/js/src/ctypes/libffi/man/Makefile.am @@ -0,0 +1,8 @@ +## Process this with automake to create Makefile.in + +AUTOMAKE_OPTIONS=foreign + +EXTRA_DIST = ffi.3 ffi_call.3 ffi_prep_cif.3 + +man_MANS = ffi.3 ffi_call.3 ffi_prep_cif.3 + diff --git a/js/src/ctypes/libffi/man/Makefile.in b/js/src/ctypes/libffi/man/Makefile.in new file mode 100644 index 0000000..2903724 --- /dev/null +++ b/js/src/ctypes/libffi/man/Makefile.in @@ -0,0 +1,450 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = man +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/fficonfig.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +man3dir = $(mandir)/man3 +am__installdirs = "$(DESTDIR)$(man3dir)" +NROFF = nroff +MANS = $(man_MANS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_LTLDFLAGS = @AM_LTLDFLAGS@ +AM_RUNTESTFLAGS = @AM_RUNTESTFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_LONG_DOUBLE = @HAVE_LONG_DOUBLE@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TARGET = @TARGET@ +TARGETDIR = @TARGETDIR@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +toolexecdir = @toolexecdir@ +toolexeclibdir = @toolexeclibdir@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign +EXTRA_DIST = ffi.3 ffi_call.3 ffi_prep_cif.3 +man_MANS = ffi.3 ffi_call.3 ffi_prep_cif.3 +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign man/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign man/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man3: $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man3dir)" || $(MKDIR_P) "$(DESTDIR)$(man3dir)" + @list=''; test -n "$(man3dir)" || exit 0; \ + { for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.3[a-z]*$$/p'; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \ + done; } + +uninstall-man3: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man3dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.3[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + test -z "$$files" || { \ + echo " ( cd '$(DESTDIR)$(man3dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(man3dir)" && rm -f $$files; } +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @list='$(MANS)'; if test -n "$$list"; then \ + list=`for p in $$list; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ + if test -n "$$list" && \ + grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ + echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ + grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ + echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ + echo " typically \`make maintainer-clean' will remove them" >&2; \ + exit 1; \ + else :; fi; \ + else :; fi + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(MANS) +installdirs: + for dir in "$(DESTDIR)$(man3dir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-man + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: install-man3 + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-man + +uninstall-man: uninstall-man3 + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-man3 \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + uninstall uninstall-am uninstall-man uninstall-man3 + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/js/src/ctypes/libffi/man/ffi.3 b/js/src/ctypes/libffi/man/ffi.3 new file mode 100644 index 0000000..18b5d5d --- /dev/null +++ b/js/src/ctypes/libffi/man/ffi.3 @@ -0,0 +1,31 @@ +.Dd February 15, 2008 +.Dt FFI 3 +.Sh NAME +.Nm FFI +.Nd Foreign Function Interface +.Sh LIBRARY +libffi, -lffi +.Sh SYNOPSIS +.In ffi.h +.Ft ffi_status +.Fo ffi_prep_cif +.Fa "ffi_cif *cif" +.Fa "ffi_abi abi" +.Fa "unsigned int nargs" +.Fa "ffi_type *rtype" +.Fa "ffi_type **atypes" +.Fc +.Ft void +.Fo ffi_call +.Fa "ffi_cif *cif" +.Fa "void (*fn)(void)" +.Fa "void *rvalue" +.Fa "void **avalue" +.Fc +.Sh DESCRIPTION +The foreign function interface provides a mechanism by which a function can +generate a call to another function at runtime without requiring knowledge of +the called function's interface at compile time. +.Sh SEE ALSO +.Xr ffi_prep_cif 3 , +.Xr ffi_call 3 diff --git a/js/src/ctypes/libffi/man/ffi_call.3 b/js/src/ctypes/libffi/man/ffi_call.3 new file mode 100644 index 0000000..5351513 --- /dev/null +++ b/js/src/ctypes/libffi/man/ffi_call.3 @@ -0,0 +1,103 @@ +.Dd February 15, 2008 +.Dt ffi_call 3 +.Sh NAME +.Nm ffi_call +.Nd Invoke a foreign function. +.Sh SYNOPSIS +.In ffi.h +.Ft void +.Fo ffi_call +.Fa "ffi_cif *cif" +.Fa "void (*fn)(void)" +.Fa "void *rvalue" +.Fa "void **avalue" +.Fc +.Sh DESCRIPTION +The +.Nm ffi_call +function provides a simple mechanism for invoking a function without +requiring knowledge of the function's interface at compile time. +.Fa fn +is called with the values retrieved from the pointers in the +.Fa avalue +array. The return value from +.Fa fn +is placed in storage pointed to by +.Fa rvalue . +.Fa cif +contains information describing the data types, sizes and alignments of the +arguments to and return value from +.Fa fn , +and must be initialized with +.Nm ffi_prep_cif +before it is used with +.Nm ffi_call . +.Pp +.Fa rvalue +must point to storage that is sizeof(ffi_arg) or larger for non-floating point +types. For smaller-sized return value types, the +.Nm ffi_arg +or +.Nm ffi_sarg +integral type must be used to hold +the return value. +.Sh EXAMPLES +.Bd -literal +#include +#include + +unsigned char +foo(unsigned int, float); + +int +main(int argc, const char **argv) +{ + ffi_cif cif; + ffi_type *arg_types[2]; + void *arg_values[2]; + ffi_status status; + + // Because the return value from foo() is smaller than sizeof(long), it + // must be passed as ffi_arg or ffi_sarg. + ffi_arg result; + + // Specify the data type of each argument. Available types are defined + // in . + arg_types[0] = &ffi_type_uint; + arg_types[1] = &ffi_type_float; + + // Prepare the ffi_cif structure. + if ((status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, + 2, &ffi_type_uint8, arg_types)) != FFI_OK) + { + // Handle the ffi_status error. + } + + // Specify the values of each argument. + unsigned int arg1 = 42; + float arg2 = 5.1; + + arg_values[0] = &arg1; + arg_values[1] = &arg2; + + // Invoke the function. + ffi_call(&cif, FFI_FN(foo), &result, arg_values); + + // The ffi_arg 'result' now contains the unsigned char returned from foo(), + // which can be accessed by a typecast. + printf("result is %hhu", (unsigned char)result); + + return 0; +} + +// The target function. +unsigned char +foo(unsigned int x, float y) +{ + unsigned char result = x - y; + return result; +} +.Ed +.Sh SEE ALSO +.Xr ffi 3 , +.Xr ffi_prep_cif 3 diff --git a/js/src/ctypes/libffi/man/ffi_prep_cif.3 b/js/src/ctypes/libffi/man/ffi_prep_cif.3 new file mode 100644 index 0000000..9436b31 --- /dev/null +++ b/js/src/ctypes/libffi/man/ffi_prep_cif.3 @@ -0,0 +1,66 @@ +.Dd February 15, 2008 +.Dt ffi_prep_cif 3 +.Sh NAME +.Nm ffi_prep_cif +.Nd Prepare a +.Nm ffi_cif +structure for use with +.Nm ffi_call +. +.Sh SYNOPSIS +.In ffi.h +.Ft ffi_status +.Fo ffi_prep_cif +.Fa "ffi_cif *cif" +.Fa "ffi_abi abi" +.Fa "unsigned int nargs" +.Fa "ffi_type *rtype" +.Fa "ffi_type **atypes" +.Fc +.Sh DESCRIPTION +The +.Nm ffi_prep_cif +function prepares a +.Nm ffi_cif +structure for use with +.Nm ffi_call +. +.Fa abi +specifies a set of calling conventions to use. +.Fa atypes +is an array of +.Fa nargs +pointers to +.Nm ffi_type +structs that describe the data type, size and alignment of each argument. +.Fa rtype +points to an +.Nm ffi_type +that describes the data type, size and alignment of the +return value. +.Sh RETURN VALUES +Upon successful completion, +.Nm ffi_prep_cif +returns +.Nm FFI_OK . +It will return +.Nm FFI_BAD_TYPEDEF +if +.Fa cif +is +.Nm NULL +or +.Fa atypes +or +.Fa rtype +is malformed. If +.Fa abi +does not refer to a valid ABI, +.Nm FFI_BAD_ABI +will be returned. Available ABIs are +defined in +.Nm +. +.Sh SEE ALSO +.Xr ffi 3 , +.Xr ffi_call 3 diff --git a/js/src/ctypes/libffi/mdate-sh b/js/src/ctypes/libffi/mdate-sh new file mode 100755 index 0000000..cd916c0 --- /dev/null +++ b/js/src/ctypes/libffi/mdate-sh @@ -0,0 +1,201 @@ +#!/bin/sh +# Get modification time of a file or directory and pretty-print it. + +scriptversion=2005-06-29.22 + +# Copyright (C) 1995, 1996, 1997, 2003, 2004, 2005 Free Software +# Foundation, Inc. +# written by Ulrich Drepper , June 1995 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +case $1 in + '') + echo "$0: No file. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: mdate-sh [--help] [--version] FILE + +Pretty-print the modification time of FILE. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "mdate-sh $scriptversion" + exit $? + ;; +esac + +# Prevent date giving response in another language. +LANG=C +export LANG +LC_ALL=C +export LC_ALL +LC_TIME=C +export LC_TIME + +# GNU ls changes its time format in response to the TIME_STYLE +# variable. Since we cannot assume `unset' works, revert this +# variable to its documented default. +if test "${TIME_STYLE+set}" = set; then + TIME_STYLE=posix-long-iso + export TIME_STYLE +fi + +save_arg1=$1 + +# Find out how to get the extended ls output of a file or directory. +if ls -L /dev/null 1>/dev/null 2>&1; then + ls_command='ls -L -l -d' +else + ls_command='ls -l -d' +fi + +# A `ls -l' line looks as follows on OS/2. +# drwxrwx--- 0 Aug 11 2001 foo +# This differs from Unix, which adds ownership information. +# drwxrwx--- 2 root root 4096 Aug 11 2001 foo +# +# To find the date, we split the line on spaces and iterate on words +# until we find a month. This cannot work with files whose owner is a +# user named `Jan', or `Feb', etc. However, it's unlikely that `/' +# will be owned by a user whose name is a month. So we first look at +# the extended ls output of the root directory to decide how many +# words should be skipped to get the date. + +# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below. +set x`ls -l -d /` + +# Find which argument is the month. +month= +command= +until test $month +do + shift + # Add another shift to the command. + command="$command shift;" + case $1 in + Jan) month=January; nummonth=1;; + Feb) month=February; nummonth=2;; + Mar) month=March; nummonth=3;; + Apr) month=April; nummonth=4;; + May) month=May; nummonth=5;; + Jun) month=June; nummonth=6;; + Jul) month=July; nummonth=7;; + Aug) month=August; nummonth=8;; + Sep) month=September; nummonth=9;; + Oct) month=October; nummonth=10;; + Nov) month=November; nummonth=11;; + Dec) month=December; nummonth=12;; + esac +done + +# Get the extended ls output of the file or directory. +set dummy x`eval "$ls_command \"\$save_arg1\""` + +# Remove all preceding arguments +eval $command + +# Because of the dummy argument above, month is in $2. +# +# On a POSIX system, we should have +# +# $# = 5 +# $1 = file size +# $2 = month +# $3 = day +# $4 = year or time +# $5 = filename +# +# On Darwin 7.7.0 and 7.6.0, we have +# +# $# = 4 +# $1 = day +# $2 = month +# $3 = year or time +# $4 = filename + +# Get the month. +case $2 in + Jan) month=January; nummonth=1;; + Feb) month=February; nummonth=2;; + Mar) month=March; nummonth=3;; + Apr) month=April; nummonth=4;; + May) month=May; nummonth=5;; + Jun) month=June; nummonth=6;; + Jul) month=July; nummonth=7;; + Aug) month=August; nummonth=8;; + Sep) month=September; nummonth=9;; + Oct) month=October; nummonth=10;; + Nov) month=November; nummonth=11;; + Dec) month=December; nummonth=12;; +esac + +case $3 in + ???*) day=$1;; + *) day=$3; shift;; +esac + +# Here we have to deal with the problem that the ls output gives either +# the time of day or the year. +case $3 in + *:*) set `date`; eval year=\$$# + case $2 in + Jan) nummonthtod=1;; + Feb) nummonthtod=2;; + Mar) nummonthtod=3;; + Apr) nummonthtod=4;; + May) nummonthtod=5;; + Jun) nummonthtod=6;; + Jul) nummonthtod=7;; + Aug) nummonthtod=8;; + Sep) nummonthtod=9;; + Oct) nummonthtod=10;; + Nov) nummonthtod=11;; + Dec) nummonthtod=12;; + esac + # For the first six month of the year the time notation can also + # be used for files modified in the last year. + if (expr $nummonth \> $nummonthtod) > /dev/null; + then + year=`expr $year - 1` + fi;; + *) year=$3;; +esac + +# The result. +echo $day $month $year + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/js/src/ctypes/libffi/missing b/js/src/ctypes/libffi/missing new file mode 100755 index 0000000..894e786 --- /dev/null +++ b/js/src/ctypes/libffi/missing @@ -0,0 +1,360 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2005-06-08.21 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program 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 General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case "$1" in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/js/src/ctypes/libffi/msvcc.sh b/js/src/ctypes/libffi/msvcc.sh new file mode 100755 index 0000000..dcdbeab --- /dev/null +++ b/js/src/ctypes/libffi/msvcc.sh @@ -0,0 +1,197 @@ +#!/bin/sh + +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the MSVC wrappificator. +# +# The Initial Developer of the Original Code is +# Timothy Wall . +# Portions created by the Initial Developer are Copyright (C) 2009 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Daniel Witte +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# GCC-compatible wrapper for cl.exe and ml.exe. Arguments are given in GCC +# format and translated into something sensible for cl or ml. +# + +args="-nologo -W3" +md=-MD +cl="cl" +ml="ml" +safeseh="-safeseh" +output= + +while [ $# -gt 0 ] +do + case $1 + in + -fexceptions) + # Don't enable exceptions for now. + #args="$args -EHac" + shift 1 + ;; + -m32) + shift 1 + ;; + -m64) + cl="cl" # "$MSVC/x86_amd64/cl" + ml="ml64" # "$MSVC/x86_amd64/ml64" + safeseh= + shift 1 + ;; + -O0) + args="$args -Od" + shift 1 + ;; + -O*) + # If we're optimizing, make sure we explicitly turn on some optimizations + # that are implicitly disabled by debug symbols (-Zi). + args="$args $1 -OPT:REF -OPT:ICF -INCREMENTAL:NO" + shift 1 + ;; + -g) + # Enable debug symbol generation. + args="$args -Zi -DEBUG" + shift 1 + ;; + -DFFI_DEBUG) + # Link against debug CRT and enable runtime error checks. + args="$args -RTC1" + defines="$defines $1" + md=-MDd + shift 1 + ;; + -c) + args="$args -c" + args="$(echo $args | sed 's%/Fe%/Fo%g')" + single="-c" + shift 1 + ;; + -D*=*) + name="$(echo $1|sed 's/-D\([^=][^=]*\)=.*/\1/g')" + value="$(echo $1|sed 's/-D[^=][^=]*=//g')" + args="$args -D${name}='$value'" + defines="$defines -D${name}='$value'" + shift 1 + ;; + -D*) + args="$args $1" + defines="$defines $1" + shift 1 + ;; + -I) + args="$args -I$2" + includes="$includes -I$2" + shift 2 + ;; + -I*) + args="$args $1" + includes="$includes $1" + shift 1 + ;; + -W|-Wextra) + # TODO map extra warnings + shift 1 + ;; + -Wall) + # -Wall on MSVC is overzealous, and we already build with -W3. Nothing + # to do here. + shift 1 + ;; + -Werror) + args="$args -WX" + shift 1 + ;; + -W*) + # TODO map specific warnings + shift 1 + ;; + -S) + args="$args -FAs" + shift 1 + ;; + -o) + outdir="$(dirname $2)" + base="$(basename $2|sed 's/\.[^.]*//g')" + if [ -n "$single" ]; then + output="-Fo$2" + else + output="-Fe$2" + fi + if [ -n "$assembly" ]; then + args="$args $output" + else + args="$args $output -Fd$outdir/$base -Fp$outdir/$base -Fa$outdir/$base" + fi + shift 2 + ;; + *.S) + src=$1 + assembly="true" + shift 1 + ;; + *.c) + args="$args $1" + shift 1 + ;; + *) + # Assume it's an MSVC argument, and pass it through. + args="$args $1" + shift 1 + ;; + esac +done + +if [ -n "$assembly" ]; then + if [ -z "$outdir" ]; then + outdir="." + fi + ppsrc="$outdir/$(basename $src|sed 's/.S$/.asm/g')" + echo "$cl -nologo -EP $includes $defines $src > $ppsrc" + "$cl" -nologo -EP $includes $defines $src > $ppsrc || exit $? + output="$(echo $output | sed 's%/F[dpa][^ ]*%%g')" + args="-nologo $safeseh $single $output $ppsrc" + + echo "$ml $args" + eval "\"$ml\" $args" + result=$? + + # required to fix ml64 broken output? + #mv *.obj $outdir +else + args="$md $args" + echo "$cl $args" + eval "\"$cl\" $args" + result=$? +fi + +exit $result + diff --git a/js/src/ctypes/libffi/src/alpha/ffi.c b/js/src/ctypes/libffi/src/alpha/ffi.c new file mode 100644 index 0000000..8d6b2ba --- /dev/null +++ b/js/src/ctypes/libffi/src/alpha/ffi.c @@ -0,0 +1,284 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc. + + Alpha Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include +#include + +/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE; + all further uses in this file will refer to the 128-bit type. */ +#if defined(__LONG_DOUBLE_128__) +# if FFI_TYPE_LONGDOUBLE != 4 +# error FFI_TYPE_LONGDOUBLE out of date +# endif +#else +# undef FFI_TYPE_LONGDOUBLE +# define FFI_TYPE_LONGDOUBLE 4 +#endif + +extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)(void)) + FFI_HIDDEN; +extern void ffi_closure_osf(void) FFI_HIDDEN; + + +ffi_status +ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* Adjust cif->bytes to represent a minimum 6 words for the temporary + register argument loading area. */ + if (cif->bytes < 6*FFI_SIZEOF_ARG) + cif->bytes = 6*FFI_SIZEOF_ARG; + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_STRUCT: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags = cif->rtype->type; + break; + + case FFI_TYPE_LONGDOUBLE: + /* 128-bit long double is returned in memory, like a struct. */ + cif->flags = FFI_TYPE_STRUCT; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + + +void +ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + unsigned long *stack, *argp; + long i, avn; + ffi_type **arg_types; + + /* If the return value is a struct and we don't have a return + value address then we need to make one. */ + if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT) + rvalue = alloca(cif->rtype->size); + + /* Allocate the space for the arguments, plus 4 words of temp + space for ffi_call_osf. */ + argp = stack = alloca(cif->bytes + 4*FFI_SIZEOF_ARG); + + if (cif->flags == FFI_TYPE_STRUCT) + *(void **) argp++ = rvalue; + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + while (i < avn) + { + size_t size = (*arg_types)->size; + + switch ((*arg_types)->type) + { + case FFI_TYPE_SINT8: + *(SINT64 *) argp = *(SINT8 *)(* avalue); + break; + + case FFI_TYPE_UINT8: + *(SINT64 *) argp = *(UINT8 *)(* avalue); + break; + + case FFI_TYPE_SINT16: + *(SINT64 *) argp = *(SINT16 *)(* avalue); + break; + + case FFI_TYPE_UINT16: + *(SINT64 *) argp = *(UINT16 *)(* avalue); + break; + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + /* Note that unsigned 32-bit quantities are sign extended. */ + *(SINT64 *) argp = *(SINT32 *)(* avalue); + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + *(UINT64 *) argp = *(UINT64 *)(* avalue); + break; + + case FFI_TYPE_FLOAT: + if (argp - stack < 6) + { + /* Note the conversion -- all the fp regs are loaded as + doubles. The in-register format is the same. */ + *(double *) argp = *(float *)(* avalue); + } + else + *(float *) argp = *(float *)(* avalue); + break; + + case FFI_TYPE_DOUBLE: + *(double *) argp = *(double *)(* avalue); + break; + + case FFI_TYPE_LONGDOUBLE: + /* 128-bit long double is passed by reference. */ + *(long double **) argp = (long double *)(* avalue); + size = sizeof (long double *); + break; + + case FFI_TYPE_STRUCT: + memcpy(argp, *avalue, (*arg_types)->size); + break; + + default: + FFI_ASSERT(0); + } + + argp += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + i++, arg_types++, avalue++; + } + + ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn); +} + + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc) +{ + unsigned int *tramp; + + tramp = (unsigned int *) &closure->tramp[0]; + tramp[0] = 0x47fb0401; /* mov $27,$1 */ + tramp[1] = 0xa77b0010; /* ldq $27,16($27) */ + tramp[2] = 0x6bfb0000; /* jmp $31,($27),0 */ + tramp[3] = 0x47ff041f; /* nop */ + *(void **) &tramp[4] = ffi_closure_osf; + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* Flush the Icache. + + Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal + instead, since both Compaq as and gas can handle it. + + 0x86 is PAL_imb in Tru64 UNIX . */ + asm volatile ("call_pal 0x86" : : : "memory"); + + return FFI_OK; +} + + +long FFI_HIDDEN +ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp) +{ + ffi_cif *cif; + void **avalue; + ffi_type **arg_types; + long i, avn, argn; + + cif = closure->cif; + avalue = alloca(cif->nargs * sizeof(void *)); + + argn = 0; + + /* Copy the caller's structure return address to that the closure + returns the data directly to the caller. */ + if (cif->flags == FFI_TYPE_STRUCT) + { + rvalue = (void *) argp[0]; + argn = 1; + } + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + /* Grab the addresses of the arguments from the stack frame. */ + while (i < avn) + { + size_t size = arg_types[i]->size; + + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + case FFI_TYPE_STRUCT: + avalue[i] = &argp[argn]; + break; + + case FFI_TYPE_FLOAT: + if (argn < 6) + { + /* Floats coming from registers need conversion from double + back to float format. */ + *(float *)&argp[argn - 6] = *(double *)&argp[argn - 6]; + avalue[i] = &argp[argn - 6]; + } + else + avalue[i] = &argp[argn]; + break; + + case FFI_TYPE_DOUBLE: + avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)]; + break; + + case FFI_TYPE_LONGDOUBLE: + /* 128-bit long double is passed by reference. */ + avalue[i] = (long double *) argp[argn]; + size = sizeof (long double *); + break; + + default: + abort (); + } + + argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + i++; + } + + /* Invoke the closure. */ + closure->fun (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_osf how to perform return type promotions. */ + return cif->rtype->type; +} diff --git a/js/src/ctypes/libffi/src/alpha/ffitarget.h b/js/src/ctypes/libffi/src/alpha/ffitarget.h new file mode 100644 index 0000000..7d06eb0 --- /dev/null +++ b/js/src/ctypes/libffi/src/alpha/ffitarget.h @@ -0,0 +1,48 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for Alpha. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_OSF, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_OSF +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 24 +#define FFI_NATIVE_RAW_API 0 + +#endif diff --git a/js/src/ctypes/libffi/src/alpha/osf.S b/js/src/ctypes/libffi/src/alpha/osf.S new file mode 100644 index 0000000..d0e7782 --- /dev/null +++ b/js/src/ctypes/libffi/src/alpha/osf.S @@ -0,0 +1,366 @@ +/* ----------------------------------------------------------------------- + osf.S - Copyright (c) 1998, 2001, 2007, 2008 Red Hat + + Alpha/OSF Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include + + .arch ev6 + .text + +/* ffi_call_osf (void *args, unsigned long bytes, unsigned flags, + void *raddr, void (*fnaddr)(void)); + + Bit o trickiness here -- ARGS+BYTES is the base of the stack frame + for this function. This has been allocated by ffi_call. We also + deallocate some of the stack that has been alloca'd. */ + + .align 3 + .globl ffi_call_osf + .ent ffi_call_osf + FFI_HIDDEN(ffi_call_osf) + +ffi_call_osf: + .frame $15, 32, $26, 0 + .mask 0x4008000, -32 +$LFB1: + addq $16,$17,$1 + mov $16, $30 + stq $26, 0($1) + stq $15, 8($1) + stq $18, 16($1) + mov $1, $15 +$LCFI1: + .prologue 0 + + stq $19, 24($1) + mov $20, $27 + + # Load up all of the (potential) argument registers. + ldq $16, 0($30) + ldt $f16, 0($30) + ldt $f17, 8($30) + ldq $17, 8($30) + ldt $f18, 16($30) + ldq $18, 16($30) + ldt $f19, 24($30) + ldq $19, 24($30) + ldt $f20, 32($30) + ldq $20, 32($30) + ldt $f21, 40($30) + ldq $21, 40($30) + + # Deallocate the register argument area. + lda $30, 48($30) + + jsr $26, ($27), 0 + ldgp $29, 0($26) + + # If the return value pointer is NULL, assume no return value. + ldq $19, 24($15) + ldq $18, 16($15) + ldq $26, 0($15) +$LCFI2: + beq $19, $noretval + + # Store the return value out in the proper type. + cmpeq $18, FFI_TYPE_INT, $1 + bne $1, $retint + cmpeq $18, FFI_TYPE_FLOAT, $2 + bne $2, $retfloat + cmpeq $18, FFI_TYPE_DOUBLE, $3 + bne $3, $retdouble + + .align 3 +$noretval: + ldq $15, 8($15) + ret + + .align 4 +$retint: + stq $0, 0($19) + nop + ldq $15, 8($15) + ret + + .align 4 +$retfloat: + sts $f0, 0($19) + nop + ldq $15, 8($15) + ret + + .align 4 +$retdouble: + stt $f0, 0($19) + nop + ldq $15, 8($15) + ret +$LFE1: + + .end ffi_call_osf + +/* ffi_closure_osf(...) + + Receives the closure argument in $1. */ + + .align 3 + .globl ffi_closure_osf + .ent ffi_closure_osf + FFI_HIDDEN(ffi_closure_osf) + +ffi_closure_osf: + .frame $30, 16*8, $26, 0 + .mask 0x4000000, -16*8 +$LFB2: + ldgp $29, 0($27) + subq $30, 16*8, $30 +$LCFI5: + stq $26, 0($30) +$LCFI6: + .prologue 1 + + # Store all of the potential argument registers in va_list format. + stt $f16, 4*8($30) + stt $f17, 5*8($30) + stt $f18, 6*8($30) + stt $f19, 7*8($30) + stt $f20, 8*8($30) + stt $f21, 9*8($30) + stq $16, 10*8($30) + stq $17, 11*8($30) + stq $18, 12*8($30) + stq $19, 13*8($30) + stq $20, 14*8($30) + stq $21, 15*8($30) + + # Call ffi_closure_osf_inner to do the bulk of the work. + mov $1, $16 + lda $17, 2*8($30) + lda $18, 10*8($30) + jsr $26, ffi_closure_osf_inner + ldgp $29, 0($26) + ldq $26, 0($30) + + # Load up the return value in the proper type. + lda $1, $load_table + s4addq $0, $1, $1 + ldl $1, 0($1) + addq $1, $29, $1 + jmp $31, ($1), $load_32 + + .align 4 +$load_none: + addq $30, 16*8, $30 + ret + + .align 4 +$load_float: + lds $f0, 16($30) + nop + addq $30, 16*8, $30 + ret + + .align 4 +$load_double: + ldt $f0, 16($30) + nop + addq $30, 16*8, $30 + ret + + .align 4 +$load_u8: +#ifdef __alpha_bwx__ + ldbu $0, 16($30) + nop +#else + ldq $0, 16($30) + and $0, 255, $0 +#endif + addq $30, 16*8, $30 + ret + + .align 4 +$load_s8: +#ifdef __alpha_bwx__ + ldbu $0, 16($30) + sextb $0, $0 +#else + ldq $0, 16($30) + sll $0, 56, $0 + sra $0, 56, $0 +#endif + addq $30, 16*8, $30 + ret + + .align 4 +$load_u16: +#ifdef __alpha_bwx__ + ldwu $0, 16($30) + nop +#else + ldq $0, 16($30) + zapnot $0, 3, $0 +#endif + addq $30, 16*8, $30 + ret + + .align 4 +$load_s16: +#ifdef __alpha_bwx__ + ldwu $0, 16($30) + sextw $0, $0 +#else + ldq $0, 16($30) + sll $0, 48, $0 + sra $0, 48, $0 +#endif + addq $30, 16*8, $30 + ret + + .align 4 +$load_32: + ldl $0, 16($30) + nop + addq $30, 16*8, $30 + ret + + .align 4 +$load_64: + ldq $0, 16($30) + nop + addq $30, 16*8, $30 + ret +$LFE2: + + .end ffi_closure_osf + +#ifdef __ELF__ +.section .rodata +#else +.rdata +#endif +$load_table: + .gprel32 $load_none # FFI_TYPE_VOID + .gprel32 $load_32 # FFI_TYPE_INT + .gprel32 $load_float # FFI_TYPE_FLOAT + .gprel32 $load_double # FFI_TYPE_DOUBLE + .gprel32 $load_none # FFI_TYPE_LONGDOUBLE + .gprel32 $load_u8 # FFI_TYPE_UINT8 + .gprel32 $load_s8 # FFI_TYPE_SINT8 + .gprel32 $load_u16 # FFI_TYPE_UINT16 + .gprel32 $load_s16 # FFI_TYPE_SINT16 + .gprel32 $load_32 # FFI_TYPE_UINT32 + .gprel32 $load_32 # FFI_TYPE_SINT32 + .gprel32 $load_64 # FFI_TYPE_UINT64 + .gprel32 $load_64 # FFI_TYPE_SINT64 + .gprel32 $load_none # FFI_TYPE_STRUCT + .gprel32 $load_64 # FFI_TYPE_POINTER + +/* Assert that the table above is in sync with ffi.h. */ + +#if FFI_TYPE_FLOAT != 2 \ + || FFI_TYPE_DOUBLE != 3 \ + || FFI_TYPE_UINT8 != 5 \ + || FFI_TYPE_SINT8 != 6 \ + || FFI_TYPE_UINT16 != 7 \ + || FFI_TYPE_SINT16 != 8 \ + || FFI_TYPE_UINT32 != 9 \ + || FFI_TYPE_SINT32 != 10 \ + || FFI_TYPE_UINT64 != 11 \ + || FFI_TYPE_SINT64 != 12 \ + || FFI_TYPE_STRUCT != 13 \ + || FFI_TYPE_POINTER != 14 \ + || FFI_TYPE_LAST != 14 +#error "osf.S out of sync with ffi.h" +#endif + +#ifdef __ELF__ + .section .eh_frame,EH_FRAME_FLAGS,@progbits +__FRAME_BEGIN__: + .4byte $LECIE1-$LSCIE1 # Length of Common Information Entry +$LSCIE1: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version + .ascii "zR\0" # CIE Augmentation + .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor + .byte 0x78 # sleb128 -8; CIE Data Alignment Factor + .byte 26 # CIE RA Column + .byte 0x1 # uleb128 0x1; Augmentation size + .byte 0x1b # FDE Encoding (pcrel sdata4) + .byte 0xc # DW_CFA_def_cfa + .byte 30 # uleb128 column 30 + .byte 0 # uleb128 offset 0 + .align 3 +$LECIE1: +$LSFDE1: + .4byte $LEFDE1-$LASFDE1 # FDE Length +$LASFDE1: + .4byte $LASFDE1-__FRAME_BEGIN__ # FDE CIE offset + .4byte $LFB1-. # FDE initial location + .4byte $LFE1-$LFB1 # FDE address range + .byte 0x0 # uleb128 0x0; Augmentation size + + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI1-$LFB1 + .byte 0x9a # DW_CFA_offset, column 26 + .byte 4 # uleb128 4*-8 + .byte 0x8f # DW_CFA_offset, column 15 + .byte 0x3 # uleb128 3*-8 + .byte 0xc # DW_CFA_def_cfa + .byte 15 # uleb128 column 15 + .byte 32 # uleb128 offset 32 + + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI2-$LCFI1 + .byte 0xda # DW_CFA_restore, column 26 + .align 3 +$LEFDE1: + +$LSFDE3: + .4byte $LEFDE3-$LASFDE3 # FDE Length +$LASFDE3: + .4byte $LASFDE3-__FRAME_BEGIN__ # FDE CIE offset + .4byte $LFB2-. # FDE initial location + .4byte $LFE2-$LFB2 # FDE address range + .byte 0x0 # uleb128 0x0; Augmentation size + + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI5-$LFB2 + .byte 0xe # DW_CFA_def_cfa_offset + .byte 0x80,0x1 # uleb128 128 + + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI6-$LCFI5 + .byte 0x9a # DW_CFA_offset, column 26 + .byte 16 # uleb128 offset 16*-8 + .align 3 +$LEFDE3: + +#ifdef __linux__ + .section .note.GNU-stack,"",@progbits +#endif +#endif diff --git a/js/src/ctypes/libffi/src/arm/ffi.c b/js/src/ctypes/libffi/src/arm/ffi.c new file mode 100644 index 0000000..9a0a53c --- /dev/null +++ b/js/src/ctypes/libffi/src/arm/ffi.c @@ -0,0 +1,500 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1998, 2008 Red Hat, Inc. + + ARM Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include + +/* Forward declares. */ +static int vfp_type_p (ffi_type *); +static void layout_vfp_args (ffi_cif *); + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments + + The vfp_space parameter is the load area for VFP regs, the return + value is cif->vfp_used (word bitset of VFP regs used for passing + arguments). These are only used for the VFP hard-float ABI. +*/ +int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space) +{ + register unsigned int i, vi = 0; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if ( ecif->cif->flags == FFI_TYPE_STRUCT ) { + *(void **) argp = ecif->rvalue; + argp += 4; + } + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + (i != 0); + i--, p_arg++) + { + size_t z; + + /* Allocated in VFP registers. */ + if (ecif->cif->abi == FFI_VFP + && vi < ecif->cif->vfp_nargs && vfp_type_p (*p_arg)) + { + float* vfp_slot = vfp_space + ecif->cif->vfp_args[vi++]; + if ((*p_arg)->type == FFI_TYPE_FLOAT) + *((float*)vfp_slot) = *((float*)*p_argv); + else if ((*p_arg)->type == FFI_TYPE_DOUBLE) + *((double*)vfp_slot) = *((double*)*p_argv); + else + memcpy(vfp_slot, *p_argv, (*p_arg)->size); + p_argv++; + continue; + } + + /* Align if necessary */ + if (((*p_arg)->alignment - 1) & (unsigned) argp) { + argp = (char *) ALIGN(argp, (*p_arg)->alignment); + } + + if ((*p_arg)->type == FFI_TYPE_STRUCT) + argp = (char *) ALIGN(argp, 4); + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + memcpy(argp, *p_argv, (*p_arg)->size); + break; + + default: + FFI_ASSERT(0); + } + } + else if (z == sizeof(int)) + { + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + } + else + { + memcpy(argp, *p_argv, z); + } + p_argv++; + argp += z; + } + + /* Indicate the VFP registers used. */ + return ecif->cif->vfp_used; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + int type_code; + /* Round the stack up to a multiple of 8 bytes. This isn't needed + everywhere, but it is on some platforms, and it doesn't harm anything + when it isn't needed. */ + cif->bytes = (cif->bytes + 7) & ~7; + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags = (unsigned) FFI_TYPE_SINT64; + break; + + case FFI_TYPE_STRUCT: + if (cif->abi == FFI_VFP + && (type_code = vfp_type_p (cif->rtype)) != 0) + { + /* A Composite Type passed in VFP registers, either + FFI_TYPE_STRUCT_VFP_FLOAT or FFI_TYPE_STRUCT_VFP_DOUBLE. */ + cif->flags = (unsigned) type_code; + } + else if (cif->rtype->size <= 4) + /* A Composite Type not larger than 4 bytes is returned in r0. */ + cif->flags = (unsigned)FFI_TYPE_INT; + else + /* A Composite Type larger than 4 bytes, or whose size cannot + be determined statically ... is stored in memory at an + address passed [in r0]. */ + cif->flags = (unsigned)FFI_TYPE_STRUCT; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + /* Map out the register placements of VFP register args. + The VFP hard-float calling conventions are slightly more sophisticated than + the base calling conventions, so we do it here instead of in ffi_prep_args(). */ + if (cif->abi == FFI_VFP) + layout_vfp_args (cif); + + return FFI_OK; +} + +/* Prototypes for assembly functions, in sysv.S */ +extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *); +extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *); + +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + extended_cif ecif; + + int small_struct = (cif->flags == FFI_TYPE_INT + && cif->rtype->type == FFI_TYPE_STRUCT); + int vfp_struct = (cif->flags == FFI_TYPE_STRUCT_VFP_FLOAT + || cif->flags == FFI_TYPE_STRUCT_VFP_DOUBLE); + + ecif.cif = cif; + ecif.avalue = avalue; + + unsigned int temp; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (cif->flags == FFI_TYPE_STRUCT)) + { + ecif.rvalue = alloca(cif->rtype->size); + } + else if (small_struct) + ecif.rvalue = &temp; + else if (vfp_struct) + { + /* Largest case is double x 4. */ + ecif.rvalue = alloca(32); + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: + ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue); + break; + + case FFI_VFP: + ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue); + break; + + default: + FFI_ASSERT(0); + break; + } + if (small_struct) + memcpy (rvalue, &temp, cif->rtype->size); + else if (vfp_struct) + memcpy (rvalue, ecif.rvalue, cif->rtype->size); +} + +/** private members **/ + +static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, + void** args, ffi_cif* cif, float *vfp_stack); + +void ffi_closure_SYSV (ffi_closure *); + +void ffi_closure_VFP (ffi_closure *); + +/* This function is jumped to by the trampoline */ + +unsigned int +ffi_closure_SYSV_inner (closure, respp, args, vfp_args) + ffi_closure *closure; + void **respp; + void *args; + void *vfp_args; +{ + // our various things... + ffi_cif *cif; + void **arg_area; + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void*)); + + /* this call will initialize ARG_AREA, such that each + * element in that array points to the corresponding + * value on the stack; and if the function returns + * a structure, it will re-set RESP to point to the + * structure return address. */ + + ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args); + + (closure->fun) (cif, *respp, arg_area, closure->user_data); + + return cif->flags; +} + +/*@-exportheader@*/ +static void +ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, + void **avalue, ffi_cif *cif, + /* Used only under VFP hard-float ABI. */ + float *vfp_stack) +/*@=exportheader@*/ +{ + register unsigned int i, vi = 0; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if ( cif->flags == FFI_TYPE_STRUCT ) { + *rvalue = *(void **) argp; + argp += 4; + } + + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + { + size_t z; + size_t alignment; + + if (cif->abi == FFI_VFP + && vi < cif->vfp_nargs && vfp_type_p (*p_arg)) + { + *p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]); + continue; + } + + alignment = (*p_arg)->alignment; + if (alignment < 4) + alignment = 4; + /* Align if necessary */ + if ((alignment - 1) & (unsigned) argp) { + argp = (char *) ALIGN(argp, alignment); + } + + z = (*p_arg)->size; + + /* because we're little endian, this is what it turns into. */ + + *p_argv = (void*) argp; + + p_argv++; + argp += z; + } + + return; +} + +/* How to make a trampoline. */ + +#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ +({ unsigned char *__tramp = (unsigned char*)(TRAMP); \ + unsigned int __fun = (unsigned int)(FUN); \ + unsigned int __ctx = (unsigned int)(CTX); \ + *(unsigned int*) &__tramp[0] = 0xe92d000f; /* stmfd sp!, {r0-r3} */ \ + *(unsigned int*) &__tramp[4] = 0xe59f0000; /* ldr r0, [pc] */ \ + *(unsigned int*) &__tramp[8] = 0xe59ff000; /* ldr pc, [pc] */ \ + *(unsigned int*) &__tramp[12] = __ctx; \ + *(unsigned int*) &__tramp[16] = __fun; \ + __clear_cache((&__tramp[0]), (&__tramp[19])); \ + }) + + +/* the cif must already be prep'ed */ + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) +{ + void (*closure_func)(ffi_closure*) = NULL; + + if (cif->abi == FFI_SYSV) + closure_func = &ffi_closure_SYSV; + else if (cif->abi == FFI_VFP) + closure_func = &ffi_closure_VFP; + else + FFI_ASSERT (0); + + FFI_INIT_TRAMPOLINE (&closure->tramp[0], \ + closure_func, \ + codeloc); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + +/* Below are routines for VFP hard-float support. */ + +static int rec_vfp_type_p (ffi_type *t, int *elt, int *elnum) +{ + switch (t->type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + *elt = (int) t->type; + *elnum = 1; + return 1; + + case FFI_TYPE_STRUCT_VFP_FLOAT: + *elt = FFI_TYPE_FLOAT; + *elnum = t->size / sizeof (float); + return 1; + + case FFI_TYPE_STRUCT_VFP_DOUBLE: + *elt = FFI_TYPE_DOUBLE; + *elnum = t->size / sizeof (double); + return 1; + + case FFI_TYPE_STRUCT:; + { + int base_elt = 0, total_elnum = 0; + ffi_type **el = t->elements; + while (*el) + { + int el_elt = 0, el_elnum = 0; + if (! rec_vfp_type_p (*el, &el_elt, &el_elnum) + || (base_elt && base_elt != el_elt) + || total_elnum + el_elnum > 4) + return 0; + base_elt = el_elt; + total_elnum += el_elnum; + el++; + } + *elnum = total_elnum; + *elt = base_elt; + return 1; + } + default: ; + } + return 0; +} + +static int vfp_type_p (ffi_type *t) +{ + int elt, elnum; + if (rec_vfp_type_p (t, &elt, &elnum)) + { + if (t->type == FFI_TYPE_STRUCT) + { + if (elnum == 1) + t->type = elt; + else + t->type = (elt == FFI_TYPE_FLOAT + ? FFI_TYPE_STRUCT_VFP_FLOAT + : FFI_TYPE_STRUCT_VFP_DOUBLE); + } + return (int) t->type; + } + return 0; +} + +static void place_vfp_arg (ffi_cif *cif, ffi_type *t) +{ + int reg = cif->vfp_reg_free; + int nregs = t->size / sizeof (float); + int align = ((t->type == FFI_TYPE_STRUCT_VFP_FLOAT + || t->type == FFI_TYPE_FLOAT) ? 1 : 2); + /* Align register number. */ + if ((reg & 1) && align == 2) + reg++; + while (reg + nregs <= 16) + { + int s, new_used = 0; + for (s = reg; s < reg + nregs; s++) + { + new_used |= (1 << s); + if (cif->vfp_used & (1 << s)) + { + reg += align; + goto next_reg; + } + } + /* Found regs to allocate. */ + cif->vfp_used |= new_used; + cif->vfp_args[cif->vfp_nargs++] = reg; + + /* Update vfp_reg_free. */ + if (cif->vfp_used & (1 << cif->vfp_reg_free)) + { + reg += nregs; + while (cif->vfp_used & (1 << reg)) + reg += 1; + cif->vfp_reg_free = reg; + } + return; + next_reg: ; + } +} + +static void layout_vfp_args (ffi_cif *cif) +{ + int i; + /* Init VFP fields */ + cif->vfp_used = 0; + cif->vfp_nargs = 0; + cif->vfp_reg_free = 0; + memset (cif->vfp_args, -1, 16); /* Init to -1. */ + + for (i = 0; i < cif->nargs; i++) + { + ffi_type *t = cif->arg_types[i]; + if (vfp_type_p (t)) + place_vfp_arg (cif, t); + } +} diff --git a/js/src/ctypes/libffi/src/arm/ffitarget.h b/js/src/ctypes/libffi/src/arm/ffitarget.h new file mode 100644 index 0000000..0814f4e --- /dev/null +++ b/js/src/ctypes/libffi/src/arm/ffitarget.h @@ -0,0 +1,63 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for ARM. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_VFP, + FFI_LAST_ABI, +#ifdef __ARM_PCS_VFP + FFI_DEFAULT_ABI = FFI_VFP +#else + FFI_DEFAULT_ABI = FFI_SYSV +#endif +} ffi_abi; +#endif + +#define FFI_EXTRA_CIF_FIELDS \ + int vfp_used; \ + short vfp_reg_free, vfp_nargs; \ + signed char vfp_args[16] \ + +/* Internally used. */ +#define FFI_TYPE_STRUCT_VFP_FLOAT (FFI_TYPE_LAST + 1) +#define FFI_TYPE_STRUCT_VFP_DOUBLE (FFI_TYPE_LAST + 2) + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 20 +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/js/src/ctypes/libffi/src/arm/sysv.S b/js/src/ctypes/libffi/src/arm/sysv.S new file mode 100644 index 0000000..7bce727 --- /dev/null +++ b/js/src/ctypes/libffi/src/arm/sysv.S @@ -0,0 +1,462 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 1998, 2008 Red Hat, Inc. + + ARM Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include +#ifdef HAVE_MACHINE_ASM_H +#include +#else +#ifdef __USER_LABEL_PREFIX__ +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ +#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) +#else +#define CNAME(x) x +#endif +#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): +#endif + +#ifdef __ELF__ +#define LSYM(x) .x +#else +#define LSYM(x) x +#endif + +/* We need a better way of testing for this, but for now, this is all + we can do. */ +@ This selects the minimum architecture level required. +#define __ARM_ARCH__ 3 + +#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) +# undef __ARM_ARCH__ +# define __ARM_ARCH__ 4 +#endif + +#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ + || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) +# undef __ARM_ARCH__ +# define __ARM_ARCH__ 5 +#endif + +#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \ + || defined(__ARM_ARCH_6M__) +# undef __ARM_ARCH__ +# define __ARM_ARCH__ 6 +#endif + +#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \ + || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \ + || defined(__ARM_ARCH_7EM__) +# undef __ARM_ARCH__ +# define __ARM_ARCH__ 7 +#endif + +#if __ARM_ARCH__ >= 5 +# define call_reg(x) blx x +#elif defined (__ARM_ARCH_4T__) +# define call_reg(x) mov lr, pc ; bx x +# if defined(__thumb__) || defined(__THUMB_INTERWORK__) +# define __INTERWORKING__ +# endif +#else +# define call_reg(x) mov lr, pc ; mov pc, x +#endif + +/* Conditionally compile unwinder directives. */ +#ifdef __ARM_EABI__ +#define UNWIND +#else +#define UNWIND @ +#endif + + +#if defined(__thumb__) && !defined(__THUMB_INTERWORK__) +.macro ARM_FUNC_START name + .text + .align 0 + .thumb + .thumb_func + ENTRY(\name) + bx pc + nop + .arm + UNWIND .fnstart +/* A hook to tell gdb that we've switched to ARM mode. Also used to call + directly from other local arm routines. */ +_L__\name: +.endm +#else +.macro ARM_FUNC_START name + .text + .align 0 + .arm + ENTRY(\name) + UNWIND .fnstart +.endm +#endif + +.macro RETLDM regs=, cond=, dirn=ia +#if defined (__INTERWORKING__) + .ifc "\regs","" + ldr\cond lr, [sp], #4 + .else + ldm\cond\dirn sp!, {\regs, lr} + .endif + bx\cond lr +#else + .ifc "\regs","" + ldr\cond pc, [sp], #4 + .else + ldm\cond\dirn sp!, {\regs, pc} + .endif +#endif +.endm + + + @ r0: fn + @ r1: &ecif + @ r2: cif->bytes + @ r3: fig->flags + @ sp+0: ecif.rvalue + + @ This assumes we are using gas. +ARM_FUNC_START ffi_call_SYSV + @ Save registers + stmfd sp!, {r0-r3, fp, lr} + UNWIND .save {r0-r3, fp, lr} + mov fp, sp + + UNWIND .setfp fp, sp + + @ Make room for all of the new args. + sub sp, fp, r2 + + @ Place all of the ffi_prep_args in position + mov r0, sp + @ r1 already set + + @ Call ffi_prep_args(stack, &ecif) + bl ffi_prep_args + + @ move first 4 parameters in registers + ldmia sp, {r0-r3} + + @ and adjust stack + sub lr, fp, sp @ cif->bytes == fp - sp + ldr ip, [fp] @ load fn() in advance + cmp lr, #16 + movhs lr, #16 + add sp, sp, lr + + @ call (fn) (...) + call_reg(ip) + + @ Remove the space we pushed for the args + mov sp, fp + + @ Load r2 with the pointer to storage for the return value + ldr r2, [sp, #24] + + @ Load r3 with the return type code + ldr r3, [sp, #12] + + @ If the return value pointer is NULL, assume no return value. + cmp r2, #0 + beq LSYM(Lepilogue) + +@ return INT + cmp r3, #FFI_TYPE_INT +#if defined(__SOFTFP__) || defined(__ARM_EABI__) + cmpne r3, #FFI_TYPE_FLOAT +#endif + streq r0, [r2] + beq LSYM(Lepilogue) + + @ return INT64 + cmp r3, #FFI_TYPE_SINT64 +#if defined(__SOFTFP__) || defined(__ARM_EABI__) + cmpne r3, #FFI_TYPE_DOUBLE +#endif + stmeqia r2, {r0, r1} + +#if !defined(__SOFTFP__) && !defined(__ARM_EABI__) + beq LSYM(Lepilogue) + +@ return FLOAT + cmp r3, #FFI_TYPE_FLOAT + stfeqs f0, [r2] + beq LSYM(Lepilogue) + +@ return DOUBLE or LONGDOUBLE + cmp r3, #FFI_TYPE_DOUBLE + stfeqd f0, [r2] +#endif + +LSYM(Lepilogue): + RETLDM "r0-r3,fp" + +.ffi_call_SYSV_end: + UNWIND .fnend + .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) + + + @ r0: fn + @ r1: &ecif + @ r2: cif->bytes + @ r3: fig->flags + @ sp+0: ecif.rvalue + +ARM_FUNC_START ffi_call_VFP + @ Save registers + stmfd sp!, {r0-r3, fp, lr} + UNWIND .save {r0-r3, fp, lr} + mov fp, sp + UNWIND .setfp fp, sp + + @ Make room for all of the new args. + sub sp, sp, r2 + + @ Make room for loading VFP args + sub sp, sp, #64 + + @ Place all of the ffi_prep_args in position + mov r0, sp + @ r1 already set + sub r2, fp, #64 @ VFP scratch space + + @ Call ffi_prep_args(stack, &ecif, vfp_space) + bl ffi_prep_args + + @ Load VFP register args if needed + cmp r0, #0 + beq LSYM(Lbase_args) + + @ Load only d0 if possible + cmp r0, #3 + sub ip, fp, #64 + flddle d0, [ip] + fldmiadgt ip, {d0-d7} + +LSYM(Lbase_args): + @ move first 4 parameters in registers + ldmia sp, {r0-r3} + + @ and adjust stack + sub lr, ip, sp @ cif->bytes == (fp - 64) - sp + ldr ip, [fp] @ load fn() in advance + cmp lr, #16 + movhs lr, #16 + add sp, sp, lr + + @ call (fn) (...) + call_reg(ip) + + @ Remove the space we pushed for the args + mov sp, fp + + @ Load r2 with the pointer to storage for + @ the return value + ldr r2, [sp, #24] + + @ Load r3 with the return type code + ldr r3, [sp, #12] + + @ If the return value pointer is NULL, + @ assume no return value. + cmp r2, #0 + beq LSYM(Lepilogue_vfp) + + cmp r3, #FFI_TYPE_INT + streq r0, [r2] + beq LSYM(Lepilogue_vfp) + + cmp r3, #FFI_TYPE_SINT64 + stmeqia r2, {r0, r1} + beq LSYM(Lepilogue_vfp) + + cmp r3, #FFI_TYPE_FLOAT + fstseq s0, [r2] + beq LSYM(Lepilogue_vfp) + + cmp r3, #FFI_TYPE_DOUBLE + fstdeq d0, [r2] + beq LSYM(Lepilogue_vfp) + + cmp r3, #FFI_TYPE_STRUCT_VFP_FLOAT + cmpne r3, #FFI_TYPE_STRUCT_VFP_DOUBLE + fstmiadeq r2, {d0-d3} + +LSYM(Lepilogue_vfp): + RETLDM "r0-r3,fp" + +.ffi_call_VFP_end: + UNWIND .fnend + .size CNAME(ffi_call_VFP),.ffi_call_VFP_end-CNAME(ffi_call_VFP) + + +/* + unsigned int FFI_HIDDEN + ffi_closure_SYSV_inner (closure, respp, args) + ffi_closure *closure; + void **respp; + void *args; +*/ + +ARM_FUNC_START ffi_closure_SYSV + UNWIND .pad #16 + add ip, sp, #16 + stmfd sp!, {ip, lr} + UNWIND .save {r0, lr} + add r2, sp, #8 + .pad #16 + sub sp, sp, #16 + str sp, [sp, #8] + add r1, sp, #8 + bl ffi_closure_SYSV_inner + cmp r0, #FFI_TYPE_INT + beq .Lretint + + cmp r0, #FFI_TYPE_FLOAT +#if defined(__SOFTFP__) || defined(__ARM_EABI__) + beq .Lretint +#else + beq .Lretfloat +#endif + + cmp r0, #FFI_TYPE_DOUBLE +#if defined(__SOFTFP__) || defined(__ARM_EABI__) + beq .Lretlonglong +#else + beq .Lretdouble +#endif + + cmp r0, #FFI_TYPE_LONGDOUBLE +#if defined(__SOFTFP__) || defined(__ARM_EABI__) + beq .Lretlonglong +#else + beq .Lretlongdouble +#endif + + cmp r0, #FFI_TYPE_SINT64 + beq .Lretlonglong +.Lclosure_epilogue: + add sp, sp, #16 + ldmfd sp, {sp, pc} +.Lretint: + ldr r0, [sp] + b .Lclosure_epilogue +.Lretlonglong: + ldr r0, [sp] + ldr r1, [sp, #4] + b .Lclosure_epilogue + +#if !defined(__SOFTFP__) && !defined(__ARM_EABI__) +.Lretfloat: + ldfs f0, [sp] + b .Lclosure_epilogue +.Lretdouble: + ldfd f0, [sp] + b .Lclosure_epilogue +.Lretlongdouble: + ldfd f0, [sp] + b .Lclosure_epilogue +#endif + +.ffi_closure_SYSV_end: + UNWIND .fnend + .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) + + +ARM_FUNC_START ffi_closure_VFP + fstmfdd sp!, {d0-d7} + @ r0-r3, then d0-d7 + UNWIND .pad #80 + add ip, sp, #80 + stmfd sp!, {ip, lr} + UNWIND .save {r0, lr} + add r2, sp, #72 + add r3, sp, #8 + .pad #72 + sub sp, sp, #72 + str sp, [sp, #64] + add r1, sp, #64 + bl ffi_closure_SYSV_inner + + cmp r0, #FFI_TYPE_INT + beq .Lretint_vfp + + cmp r0, #FFI_TYPE_FLOAT + beq .Lretfloat_vfp + + cmp r0, #FFI_TYPE_DOUBLE + cmpne r0, #FFI_TYPE_LONGDOUBLE + beq .Lretdouble_vfp + + cmp r0, #FFI_TYPE_SINT64 + beq .Lretlonglong_vfp + + cmp r0, #FFI_TYPE_STRUCT_VFP_FLOAT + beq .Lretfloat_struct_vfp + + cmp r0, #FFI_TYPE_STRUCT_VFP_DOUBLE + beq .Lretdouble_struct_vfp + +.Lclosure_epilogue_vfp: + add sp, sp, #72 + ldmfd sp, {sp, pc} + +.Lretfloat_vfp: + flds s0, [sp] + b .Lclosure_epilogue_vfp +.Lretdouble_vfp: + fldd d0, [sp] + b .Lclosure_epilogue_vfp +.Lretint_vfp: + ldr r0, [sp] + b .Lclosure_epilogue_vfp +.Lretlonglong_vfp: + ldmia sp, {r0, r1} + b .Lclosure_epilogue_vfp +.Lretfloat_struct_vfp: + fldmiad sp, {d0-d1} + b .Lclosure_epilogue_vfp +.Lretdouble_struct_vfp: + fldmiad sp, {d0-d3} + b .Lclosure_epilogue_vfp + +.ffi_closure_VFP_end: + UNWIND .fnend + .size CNAME(ffi_closure_VFP),.ffi_closure_VFP_end-CNAME(ffi_closure_VFP) + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",%progbits +#endif diff --git a/js/src/ctypes/libffi/src/avr32/ffi.c b/js/src/ctypes/libffi/src/avr32/ffi.c new file mode 100644 index 0000000..39fba2b --- /dev/null +++ b/js/src/ctypes/libffi/src/avr32/ffi.c @@ -0,0 +1,421 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2009 Bradley Smith + + AVR32 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include +#include +#include +#include + +/* #define DEBUG */ + +extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, + unsigned int, unsigned int, unsigned int*, unsigned int, + void (*fn)(void)); +extern void ffi_closure_SYSV (ffi_closure *); + +unsigned int pass_struct_on_stack(ffi_type *type) +{ + if(type->type != FFI_TYPE_STRUCT) + return 0; + + if(type->alignment < type->size && + !(type->size == 4 || type->size == 8) && + !(type->size == 8 && type->alignment >= 4)) + return 1; + + if(type->size == 3 || type->size == 5 || type->size == 6 || + type->size == 7) + return 1; + + return 0; +} + +/* ffi_prep_args is called by the assembly routine once stack space + * has been allocated for the function's arguments + * + * This is annoyingly complex since we need to keep track of used + * registers. + */ + +void ffi_prep_args(char *stack, extended_cif *ecif) +{ + unsigned int i; + void **p_argv; + ffi_type **p_arg; + char *reg_base = stack; + char *stack_base = stack + 20; + unsigned int stack_offset = 0; + unsigned int reg_mask = 0; + + p_argv = ecif->avalue; + + /* If cif->flags is struct then we know it's not passed in registers */ + if(ecif->cif->flags == FFI_TYPE_STRUCT) + { + *(void**)reg_base = ecif->rvalue; + reg_mask |= 1; + } + + for(i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs; + i++, p_arg++) + { + size_t z = (*p_arg)->size; + int alignment = (*p_arg)->alignment; + int type = (*p_arg)->type; + char *addr = 0; + + if(z % 4 != 0) + z += (4 - z % 4); + + if(reg_mask != 0x1f) + { + if(pass_struct_on_stack(*p_arg)) + { + addr = stack_base + stack_offset; + stack_offset += z; + } + else if(z == sizeof(int)) + { + char index = 0; + + while((reg_mask >> index) & 1) + index++; + + addr = reg_base + (index * 4); + reg_mask |= (1 << index); + } + else if(z == 2 * sizeof(int)) + { + if(!((reg_mask >> 1) & 1)) + { + addr = reg_base + 4; + reg_mask |= (3 << 1); + } + else if(!((reg_mask >> 3) & 1)) + { + addr = reg_base + 12; + reg_mask |= (3 << 3); + } + } + } + + if(!addr) + { + addr = stack_base + stack_offset; + stack_offset += z; + } + + if(type == FFI_TYPE_STRUCT && (*p_arg)->elements[1] == NULL) + type = (*p_arg)->elements[0]->type; + + switch(type) + { + case FFI_TYPE_UINT8: + *(unsigned int *)addr = (unsigned int)*(UINT8 *)(*p_argv); + break; + case FFI_TYPE_SINT8: + *(signed int *)addr = (signed int)*(SINT8 *)(*p_argv); + break; + case FFI_TYPE_UINT16: + *(unsigned int *)addr = (unsigned int)*(UINT16 *)(*p_argv); + break; + case FFI_TYPE_SINT16: + *(signed int *)addr = (signed int)*(SINT16 *)(*p_argv); + break; + default: + memcpy(addr, *p_argv, z); + } + + p_argv++; + } + +#ifdef DEBUG + /* Debugging */ + for(i = 0; i < 5; i++) + { + if((reg_mask & (1 << i)) == 0) + printf("r%d: (unused)\n", 12 - i); + else + printf("r%d: 0x%08x\n", 12 - i, ((unsigned int*)reg_base)[i]); + } + + for(i = 0; i < stack_offset / 4; i++) + { + printf("sp+%d: 0x%08x\n", i*4, ((unsigned int*)stack_base)[i]); + } +#endif +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* Round the stack up to a multiple of 8 bytes. This isn't needed + * everywhere, but it is on some platforms, and it doesn't harm + * anything when it isn't needed. */ + cif->bytes = (cif->bytes + 7) & ~7; + + /* Flag to indicate that he return value is in fact a struct */ + cif->rstruct_flag = 0; + + /* Set the return type flag */ + switch(cif->rtype->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + cif->flags = (unsigned)FFI_TYPE_UINT8; + break; + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + cif->flags = (unsigned)FFI_TYPE_UINT16; + break; + case FFI_TYPE_FLOAT: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + cif->flags = (unsigned)FFI_TYPE_UINT32; + break; + case FFI_TYPE_DOUBLE: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags = (unsigned)FFI_TYPE_UINT64; + break; + case FFI_TYPE_STRUCT: + cif->rstruct_flag = 1; + if(!pass_struct_on_stack(cif->rtype)) + { + if(cif->rtype->size <= 1) + cif->flags = (unsigned)FFI_TYPE_UINT8; + else if(cif->rtype->size <= 2) + cif->flags = (unsigned)FFI_TYPE_UINT16; + else if(cif->rtype->size <= 4) + cif->flags = (unsigned)FFI_TYPE_UINT32; + else if(cif->rtype->size <= 8) + cif->flags = (unsigned)FFI_TYPE_UINT64; + else + cif->flags = (unsigned)cif->rtype->type; + } + else + cif->flags = (unsigned)cif->rtype->type; + break; + default: + cif->flags = (unsigned)cif->rtype->type; + break; + } + + return FFI_OK; +} + +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + extended_cif ecif; + + unsigned int size = 0, i = 0; + ffi_type **p_arg; + + ecif.cif = cif; + ecif.avalue = avalue; + + for(i = 0, p_arg = cif->arg_types; i < cif->nargs; i++, p_arg++) + size += (*p_arg)->size + (4 - (*p_arg)->size % 4); + + /* If the return value is a struct and we don't have a return value + * address then we need to make one */ + + /* If cif->flags is struct then it's not suitable for registers */ + if((rvalue == NULL) && (cif->flags == FFI_TYPE_STRUCT)) + ecif.rvalue = alloca(cif->rtype->size); + else + ecif.rvalue = rvalue; + + switch(cif->abi) + { + case FFI_SYSV: + ffi_call_SYSV(ffi_prep_args, &ecif, size, cif->flags, + ecif.rvalue, cif->rstruct_flag, fn); + break; + default: + FFI_ASSERT(0); + break; + } +} + +static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, + void **avalue, ffi_cif *cif) +{ + register unsigned int i, reg_mask = 0; + register void **p_argv; + register ffi_type **p_arg; + register char *reg_base = stack; + register char *stack_base = stack + 20; + register unsigned int stack_offset = 0; + +#ifdef DEBUG + /* Debugging */ + for(i = 0; i < cif->nargs + 7; i++) + { + printf("sp+%d: 0x%08x\n", i*4, ((unsigned int*)stack)[i]); + } +#endif + + /* If cif->flags is struct then we know it's not passed in registers */ + if(cif->flags == FFI_TYPE_STRUCT) + { + *rvalue = *(void **)reg_base; + reg_mask |= 1; + } + + p_argv = avalue; + + for(i = 0, p_arg = cif->arg_types; i < cif->nargs; i++, p_arg++) + { + size_t z = (*p_arg)->size; + int alignment = (*p_arg)->alignment; + + *p_argv = 0; + + if(z % 4 != 0) + z += (4 - z % 4); + + if(reg_mask != 0x1f) + { + if(pass_struct_on_stack(*p_arg)) + { + *p_argv = (void*)stack_base + stack_offset; + stack_offset += z; + } + else if(z <= sizeof(int)) + { + char index = 0; + + while((reg_mask >> index) & 1) + index++; + + *p_argv = (void*)reg_base + (index * 4); + reg_mask |= (1 << index); + } + else if(z == 2 * sizeof(int)) + { + if(!((reg_mask >> 1) & 1)) + { + *p_argv = (void*)reg_base + 4; + reg_mask |= (3 << 1); + } + else if(!((reg_mask >> 3) & 1)) + { + *p_argv = (void*)reg_base + 12; + reg_mask |= (3 << 3); + } + } + } + + if(!*p_argv) + { + *p_argv = (void*)stack_base + stack_offset; + stack_offset += z; + } + + if((*p_arg)->type != FFI_TYPE_STRUCT || + (*p_arg)->elements[1] == NULL) + { + if(alignment == 1) + **(unsigned int**)p_argv <<= 24; + else if(alignment == 2) + **(unsigned int**)p_argv <<= 16; + } + + p_argv++; + } + +#ifdef DEBUG + /* Debugging */ + for(i = 0; i < cif->nargs; i++) + { + printf("sp+%d: 0x%08x\n", i*4, *(((unsigned int**)avalue)[i])); + } +#endif +} + +/* This function is jumped to by the trampoline */ + +unsigned int ffi_closure_SYSV_inner(ffi_closure *closure, void **respp, + void *args) +{ + ffi_cif *cif; + void **arg_area; + unsigned int i, size = 0; + ffi_type **p_arg; + + cif = closure->cif; + + for(i = 0, p_arg = cif->arg_types; i < cif->nargs; i++, p_arg++) + size += (*p_arg)->size + (4 - (*p_arg)->size % 4); + + arg_area = (void **)alloca(size); + + /* this call will initialize ARG_AREA, such that each element in that + * array points to the corresponding value on the stack; and if the + * function returns a structure, it will re-set RESP to point to the + * structure return address. */ + + ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif); + + (closure->fun)(cif, *respp, arg_area, closure->user_data); + + return cif->flags; +} + +ffi_status ffi_prep_closure_loc(ffi_closure* closure, ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), void *user_data, + void *codeloc) +{ + FFI_ASSERT(cif->abi == FFI_SYSV); + + unsigned char *__tramp = (unsigned char*)(&closure->tramp[0]); + unsigned int __fun = (unsigned int)(&ffi_closure_SYSV); + unsigned int __ctx = (unsigned int)(codeloc); + unsigned int __rstruct_flag = (unsigned int)(cif->rstruct_flag); + unsigned int __inner = (unsigned int)(&ffi_closure_SYSV_inner); + *(unsigned int*) &__tramp[0] = 0xebcd1f00; /* pushm r8-r12 */ + *(unsigned int*) &__tramp[4] = 0xfefc0010; /* ld.w r12, pc[16] */ + *(unsigned int*) &__tramp[8] = 0xfefb0010; /* ld.w r11, pc[16] */ + *(unsigned int*) &__tramp[12] = 0xfefa0010; /* ld.w r10, pc[16] */ + *(unsigned int*) &__tramp[16] = 0xfeff0010; /* ld.w pc, pc[16] */ + *(unsigned int*) &__tramp[20] = __ctx; + *(unsigned int*) &__tramp[24] = __rstruct_flag; + *(unsigned int*) &__tramp[28] = __inner; + *(unsigned int*) &__tramp[32] = __fun; + syscall(__NR_cacheflush, 0, (&__tramp[0]), 36); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + diff --git a/js/src/ctypes/libffi/src/avr32/ffitarget.h b/js/src/ctypes/libffi/src/avr32/ffitarget.h new file mode 100644 index 0000000..b85d062 --- /dev/null +++ b/js/src/ctypes/libffi/src/avr32/ffitarget.h @@ -0,0 +1,50 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 2009 Bradley Smith + Target configuration macros for AVR32. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_SYSV +} ffi_abi; +#endif + +#define FFI_EXTRA_CIF_FIELDS unsigned int rstruct_flag + +/* Definitions for closures */ + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 36 +#define FFI_NATIVE_RAW_API 0 + +#endif diff --git a/js/src/ctypes/libffi/src/avr32/sysv.S b/js/src/ctypes/libffi/src/avr32/sysv.S new file mode 100644 index 0000000..a984b3c --- /dev/null +++ b/js/src/ctypes/libffi/src/avr32/sysv.S @@ -0,0 +1,208 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2009 Bradley Smith + + AVR32 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + --------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include + + /* r12: ffi_prep_args + * r11: &ecif + * r10: size + * r9: cif->flags + * r8: ecif.rvalue + * sp+0: cif->rstruct_flag + * sp+4: fn */ + + .text + .align 1 + .globl ffi_call_SYSV + .type ffi_call_SYSV, @function +ffi_call_SYSV: + stm --sp, r0,r1,lr + stm --sp, r8-r12 + mov r0, sp + + /* Make room for all of the new args. */ + sub sp, r10 + /* Pad to make way for potential skipped registers */ + sub sp, 20 + + /* Call ffi_prep_args(stack, &ecif). */ + /* r11 already set */ + mov r1, r12 + mov r12, sp + icall r1 + + /* Save new argument size */ + mov r1, r12 + + /* Move first 5 parameters in registers. */ + ldm sp++, r8-r12 + + /* call (fn) (...). */ + ld.w r1, r0[36] + icall r1 + + /* Remove the space we pushed for the args. */ + mov sp, r0 + + /* Load r1 with the rstruct flag. */ + ld.w r1, sp[32] + + /* Load r9 with the return type code. */ + ld.w r9, sp[12] + + /* Load r8 with the return value pointer. */ + ld.w r8, sp[16] + + /* If the return value pointer is NULL, assume no return value. */ + cp.w r8, 0 + breq .Lend + + /* Check if return type is actually a struct */ + cp.w r1, 0 + breq 1f + + /* Return 8bit */ + cp.w r9, FFI_TYPE_UINT8 + breq .Lstore8 + + /* Return 16bit */ + cp.w r9, FFI_TYPE_UINT16 + breq .Lstore16 + +1: + /* Return 32bit */ + cp.w r9, FFI_TYPE_UINT32 + breq .Lstore32 + cp.w r9, FFI_TYPE_UINT16 + breq .Lstore32 + cp.w r9, FFI_TYPE_UINT8 + breq .Lstore32 + + /* Return 64bit */ + cp.w r9, FFI_TYPE_UINT64 + breq .Lstore64 + + /* Didn't match anything */ + bral .Lend + +.Lstore64: + st.w r8[0], r11 + st.w r8[4], r10 + bral .Lend + +.Lstore32: + st.w r8[0], r12 + bral .Lend + +.Lstore16: + st.h r8[0], r12 + bral .Lend + +.Lstore8: + st.b r8[0], r12 + bral .Lend + +.Lend: + sub sp, -20 + ldm sp++, r0,r1,pc + + .size ffi_call_SYSV, . - ffi_call_SYSV + + + /* r12: __ctx + * r11: __rstruct_flag + * r10: __inner */ + + .align 1 + .globl ffi_closure_SYSV + .type ffi_closure_SYSV, @function +ffi_closure_SYSV: + stm --sp, r0,lr + mov r0, r11 + mov r8, r10 + sub r10, sp, -8 + sub sp, 12 + st.w sp[8], sp + sub r11, sp, -8 + icall r8 + + /* Check if return type is actually a struct */ + cp.w r0, 0 + breq 1f + + /* Return 8bit */ + cp.w r12, FFI_TYPE_UINT8 + breq .Lget8 + + /* Return 16bit */ + cp.w r12, FFI_TYPE_UINT16 + breq .Lget16 + +1: + /* Return 32bit */ + cp.w r12, FFI_TYPE_UINT32 + breq .Lget32 + cp.w r12, FFI_TYPE_UINT16 + breq .Lget32 + cp.w r12, FFI_TYPE_UINT8 + breq .Lget32 + + /* Return 64bit */ + cp.w r12, FFI_TYPE_UINT64 + breq .Lget64 + + /* Didn't match anything */ + bral .Lclend + +.Lget64: + ld.w r11, sp[0] + ld.w r10, sp[4] + bral .Lclend + +.Lget32: + ld.w r12, sp[0] + bral .Lclend + +.Lget16: + ld.uh r12, sp[0] + bral .Lclend + +.Lget8: + ld.ub r12, sp[0] + bral .Lclend + +.Lclend: + sub sp, -12 + ldm sp++, r0,lr + sub sp, -20 + mov pc, lr + + .size ffi_closure_SYSV, . - ffi_closure_SYSV + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/js/src/ctypes/libffi/src/closures.c b/js/src/ctypes/libffi/src/closures.c new file mode 100644 index 0000000..8f295dd --- /dev/null +++ b/js/src/ctypes/libffi/src/closures.c @@ -0,0 +1,610 @@ +/* ----------------------------------------------------------------------- + closures.c - Copyright (c) 2007 Red Hat, Inc. + Copyright (C) 2007, 2009 Free Software Foundation, Inc + + Code to allocate and deallocate memory for closures. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#if defined __linux__ && !defined _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#include +#include + +#ifndef FFI_MMAP_EXEC_WRIT +# if __gnu_linux__ +/* This macro indicates it may be forbidden to map anonymous memory + with both write and execute permission. Code compiled when this + option is defined will attempt to map such pages once, but if it + fails, it falls back to creating a temporary file in a writable and + executable filesystem and mapping pages from it into separate + locations in the virtual memory space, one location writable and + another executable. */ +# define FFI_MMAP_EXEC_WRIT 1 +# define HAVE_MNTENT 1 +# endif +# if defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__) +/* Windows systems may have Data Execution Protection (DEP) enabled, + which requires the use of VirtualMalloc/VirtualFree to alloc/free + executable memory. */ +# define FFI_MMAP_EXEC_WRIT 1 +# endif +#endif + +#if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX +# ifdef __linux__ +/* When defined to 1 check for SELinux and if SELinux is active, + don't attempt PROT_EXEC|PROT_WRITE mapping at all, as that + might cause audit messages. */ +# define FFI_MMAP_EXEC_SELINUX 1 +# endif +#endif + +#if FFI_CLOSURES + +# if FFI_MMAP_EXEC_WRIT + +#define USE_LOCKS 1 +#define USE_DL_PREFIX 1 +#ifdef __GNUC__ +#ifndef USE_BUILTIN_FFS +#define USE_BUILTIN_FFS 1 +#endif +#endif + +/* We need to use mmap, not sbrk. */ +#define HAVE_MORECORE 0 + +/* We could, in theory, support mremap, but it wouldn't buy us anything. */ +#define HAVE_MREMAP 0 + +/* We have no use for this, so save some code and data. */ +#define NO_MALLINFO 1 + +/* We need all allocations to be in regular segments, otherwise we + lose track of the corresponding code address. */ +#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T + +/* Don't allocate more than a page unless needed. */ +#define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize) + +#if FFI_CLOSURE_TEST +/* Don't release single pages, to avoid a worst-case scenario of + continuously allocating and releasing single pages, but release + pairs of pages, which should do just as well given that allocations + are likely to be small. */ +#define DEFAULT_TRIM_THRESHOLD ((size_t)malloc_getpagesize) +#endif + +#include +#include +#include +#include +#ifndef _MSC_VER +#include +#endif +#include +#include +#if !defined(X86_WIN32) && !defined(X86_WIN64) +#ifdef HAVE_MNTENT +#include +#endif /* HAVE_MNTENT */ +#include +#include + +/* We don't want sys/mman.h to be included after we redefine mmap and + dlmunmap. */ +#include +#define LACKS_SYS_MMAN_H 1 + +#if FFI_MMAP_EXEC_SELINUX +#include +#include + +static int selinux_enabled = -1; + +static int +selinux_enabled_check (void) +{ + struct statfs sfs; + FILE *f; + char *buf = NULL; + size_t len = 0; + + if (statfs ("/selinux", &sfs) >= 0 + && (unsigned int) sfs.f_type == 0xf97cff8cU) + return 1; + f = fopen ("/proc/mounts", "r"); + if (f == NULL) + return 0; + while (getline (&buf, &len, f) >= 0) + { + char *p = strchr (buf, ' '); + if (p == NULL) + break; + p = strchr (p + 1, ' '); + if (p == NULL) + break; + if (strncmp (p + 1, "selinuxfs ", 10) == 0) + { + free (buf); + fclose (f); + return 1; + } + } + free (buf); + fclose (f); + return 0; +} + +#define is_selinux_enabled() (selinux_enabled >= 0 ? selinux_enabled \ + : (selinux_enabled = selinux_enabled_check ())) + +#else + +#define is_selinux_enabled() 0 + +#endif /* !FFI_MMAP_EXEC_SELINUX */ + +#elif defined (__CYGWIN__) + +#include + +/* Cygwin is Linux-like, but not quite that Linux-like. */ +#define is_selinux_enabled() 0 + +#endif /* !defined(X86_WIN32) && !defined(X86_WIN64) */ + +/* Declare all functions defined in dlmalloc.c as static. */ +static void *dlmalloc(size_t); +static void dlfree(void*); +static void *dlcalloc(size_t, size_t) MAYBE_UNUSED; +static void *dlrealloc(void *, size_t) MAYBE_UNUSED; +static void *dlmemalign(size_t, size_t) MAYBE_UNUSED; +static void *dlvalloc(size_t) MAYBE_UNUSED; +static int dlmallopt(int, int) MAYBE_UNUSED; +static size_t dlmalloc_footprint(void) MAYBE_UNUSED; +static size_t dlmalloc_max_footprint(void) MAYBE_UNUSED; +static void** dlindependent_calloc(size_t, size_t, void**) MAYBE_UNUSED; +static void** dlindependent_comalloc(size_t, size_t*, void**) MAYBE_UNUSED; +static void *dlpvalloc(size_t) MAYBE_UNUSED; +static int dlmalloc_trim(size_t) MAYBE_UNUSED; +static size_t dlmalloc_usable_size(void*) MAYBE_UNUSED; +static void dlmalloc_stats(void) MAYBE_UNUSED; + +#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) +/* Use these for mmap and munmap within dlmalloc.c. */ +static void *dlmmap(void *, size_t, int, int, int, off_t); +static int dlmunmap(void *, size_t); +#endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) */ + +#define mmap dlmmap +#define munmap dlmunmap + +#include "dlmalloc.c" + +#undef mmap +#undef munmap + +#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) + +/* A mutex used to synchronize access to *exec* variables in this file. */ +static pthread_mutex_t open_temp_exec_file_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* A file descriptor of a temporary file from which we'll map + executable pages. */ +static int execfd = -1; + +/* The amount of space already allocated from the temporary file. */ +static size_t execsize = 0; + +/* Open a temporary file name, and immediately unlink it. */ +static int +open_temp_exec_file_name (char *name) +{ + int fd = mkstemp (name); + + if (fd != -1) + unlink (name); + + return fd; +} + +/* Open a temporary file in the named directory. */ +static int +open_temp_exec_file_dir (const char *dir) +{ + static const char suffix[] = "/ffiXXXXXX"; + int lendir = strlen (dir); + char *tempname = __builtin_alloca (lendir + sizeof (suffix)); + + if (!tempname) + return -1; + + memcpy (tempname, dir, lendir); + memcpy (tempname + lendir, suffix, sizeof (suffix)); + + return open_temp_exec_file_name (tempname); +} + +/* Open a temporary file in the directory in the named environment + variable. */ +static int +open_temp_exec_file_env (const char *envvar) +{ + const char *value = getenv (envvar); + + if (!value) + return -1; + + return open_temp_exec_file_dir (value); +} + +#ifdef HAVE_MNTENT +/* Open a temporary file in an executable and writable mount point + listed in the mounts file. Subsequent calls with the same mounts + keep searching for mount points in the same file. Providing NULL + as the mounts file closes the file. */ +static int +open_temp_exec_file_mnt (const char *mounts) +{ + static const char *last_mounts; + static FILE *last_mntent; + + if (mounts != last_mounts) + { + if (last_mntent) + endmntent (last_mntent); + + last_mounts = mounts; + + if (mounts) + last_mntent = setmntent (mounts, "r"); + else + last_mntent = NULL; + } + + if (!last_mntent) + return -1; + + for (;;) + { + int fd; + struct mntent mnt; + char buf[MAXPATHLEN * 3]; + + if (getmntent_r (last_mntent, &mnt, buf, sizeof (buf))) + return -1; + + if (hasmntopt (&mnt, "ro") + || hasmntopt (&mnt, "noexec") + || access (mnt.mnt_dir, W_OK)) + continue; + + fd = open_temp_exec_file_dir (mnt.mnt_dir); + + if (fd != -1) + return fd; + } +} +#endif /* HAVE_MNTENT */ + +/* Instructions to look for a location to hold a temporary file that + can be mapped in for execution. */ +static struct +{ + int (*func)(const char *); + const char *arg; + int repeat; +} open_temp_exec_file_opts[] = { + { open_temp_exec_file_env, "TMPDIR", 0 }, + { open_temp_exec_file_dir, "/tmp", 0 }, + { open_temp_exec_file_dir, "/var/tmp", 0 }, + { open_temp_exec_file_dir, "/dev/shm", 0 }, + { open_temp_exec_file_env, "HOME", 0 }, +#ifdef HAVE_MNTENT + { open_temp_exec_file_mnt, "/etc/mtab", 1 }, + { open_temp_exec_file_mnt, "/proc/mounts", 1 }, +#endif /* HAVE_MNTENT */ +}; + +/* Current index into open_temp_exec_file_opts. */ +static int open_temp_exec_file_opts_idx = 0; + +/* Reset a current multi-call func, then advances to the next entry. + If we're at the last, go back to the first and return nonzero, + otherwise return zero. */ +static int +open_temp_exec_file_opts_next (void) +{ + if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat) + open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (NULL); + + open_temp_exec_file_opts_idx++; + if (open_temp_exec_file_opts_idx + == (sizeof (open_temp_exec_file_opts) + / sizeof (*open_temp_exec_file_opts))) + { + open_temp_exec_file_opts_idx = 0; + return 1; + } + + return 0; +} + +/* Return a file descriptor of a temporary zero-sized file in a + writable and exexutable filesystem. */ +static int +open_temp_exec_file (void) +{ + int fd; + + do + { + fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func + (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].arg); + + if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat + || fd == -1) + { + if (open_temp_exec_file_opts_next ()) + break; + } + } + while (fd == -1); + + return fd; +} + +/* Map in a chunk of memory from the temporary exec file into separate + locations in the virtual memory address space, one writable and one + executable. Returns the address of the writable portion, after + storing an offset to the corresponding executable portion at the + last word of the requested chunk. */ +static void * +dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset) +{ + void *ptr; + + if (execfd == -1) + { + open_temp_exec_file_opts_idx = 0; + retry_open: + execfd = open_temp_exec_file (); + if (execfd == -1) + return MFAIL; + } + + offset = execsize; + + if (ftruncate (execfd, offset + length)) + return MFAIL; + + flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS); + flags |= MAP_SHARED; + + ptr = mmap (NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC, + flags, execfd, offset); + if (ptr == MFAIL) + { + if (!offset) + { + close (execfd); + goto retry_open; + } + ftruncate (execfd, offset); + return MFAIL; + } + else if (!offset + && open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat) + open_temp_exec_file_opts_next (); + + start = mmap (start, length, prot, flags, execfd, offset); + + if (start == MFAIL) + { + munmap (ptr, length); + ftruncate (execfd, offset); + return start; + } + + mmap_exec_offset ((char *)start, length) = (char*)ptr - (char*)start; + + execsize += length; + + return start; +} + +/* Map in a writable and executable chunk of memory if possible. + Failing that, fall back to dlmmap_locked. */ +static void * +dlmmap (void *start, size_t length, int prot, + int flags, int fd, off_t offset) +{ + void *ptr; + + assert (start == NULL && length % malloc_getpagesize == 0 + && prot == (PROT_READ | PROT_WRITE) + && flags == (MAP_PRIVATE | MAP_ANONYMOUS) + && fd == -1 && offset == 0); + +#if FFI_CLOSURE_TEST + printf ("mapping in %zi\n", length); +#endif + + if (execfd == -1 && !is_selinux_enabled ()) + { + ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset); + + if (ptr != MFAIL || (errno != EPERM && errno != EACCES)) + /* Cool, no need to mess with separate segments. */ + return ptr; + + /* If MREMAP_DUP is ever introduced and implemented, try mmap + with ((prot & ~PROT_WRITE) | PROT_EXEC) and mremap with + MREMAP_DUP and prot at this point. */ + } + + if (execsize == 0 || execfd == -1) + { + pthread_mutex_lock (&open_temp_exec_file_mutex); + ptr = dlmmap_locked (start, length, prot, flags, offset); + pthread_mutex_unlock (&open_temp_exec_file_mutex); + + return ptr; + } + + return dlmmap_locked (start, length, prot, flags, offset); +} + +/* Release memory at the given address, as well as the corresponding + executable page if it's separate. */ +static int +dlmunmap (void *start, size_t length) +{ + /* We don't bother decreasing execsize or truncating the file, since + we can't quite tell whether we're unmapping the end of the file. + We don't expect frequent deallocation anyway. If we did, we + could locate pages in the file by writing to the pages being + deallocated and checking that the file contents change. + Yuck. */ + msegmentptr seg = segment_holding (gm, start); + void *code; + +#if FFI_CLOSURE_TEST + printf ("unmapping %zi\n", length); +#endif + + if (seg && (code = add_segment_exec_offset (start, seg)) != start) + { + int ret = munmap (code, length); + if (ret) + return ret; + } + + return munmap (start, length); +} + +#if FFI_CLOSURE_FREE_CODE +/* Return segment holding given code address. */ +static msegmentptr +segment_holding_code (mstate m, char* addr) +{ + msegmentptr sp = &m->seg; + for (;;) { + if (addr >= add_segment_exec_offset (sp->base, sp) + && addr < add_segment_exec_offset (sp->base, sp) + sp->size) + return sp; + if ((sp = sp->next) == 0) + return 0; + } +} +#endif + +#endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) */ + +/* Allocate a chunk of memory with the given size. Returns a pointer + to the writable address, and sets *CODE to the executable + corresponding virtual address. */ +void * +ffi_closure_alloc (size_t size, void **code) +{ + void *ptr; + + if (!code) + return NULL; + + ptr = dlmalloc (size); + + if (ptr) + { + msegmentptr seg = segment_holding (gm, ptr); + + *code = add_segment_exec_offset (ptr, seg); + } + + return ptr; +} + +/* Release a chunk of memory allocated with ffi_closure_alloc. If + FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the + writable or the executable address given. Otherwise, only the + writable address can be provided here. */ +void +ffi_closure_free (void *ptr) +{ +#if FFI_CLOSURE_FREE_CODE + msegmentptr seg = segment_holding_code (gm, ptr); + + if (seg) + ptr = sub_segment_exec_offset (ptr, seg); +#endif + + dlfree (ptr); +} + + +#if FFI_CLOSURE_TEST +/* Do some internal sanity testing to make sure allocation and + deallocation of pages are working as intended. */ +int main () +{ + void *p[3]; +#define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0) +#define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0) + GET (0, malloc_getpagesize / 2); + GET (1, 2 * malloc_getpagesize - 64 * sizeof (void*)); + PUT (1); + GET (1, 2 * malloc_getpagesize); + GET (2, malloc_getpagesize / 2); + PUT (1); + PUT (0); + PUT (2); + return 0; +} +#endif /* FFI_CLOSURE_TEST */ +# else /* ! FFI_MMAP_EXEC_WRIT */ + +/* On many systems, memory returned by malloc is writable and + executable, so just use it. */ + +#include + +void * +ffi_closure_alloc (size_t size, void **code) +{ + if (!code) + return NULL; + + return *code = malloc (size); +} + +void +ffi_closure_free (void *ptr) +{ + free (ptr); +} + +# endif /* ! FFI_MMAP_EXEC_WRIT */ +#endif /* FFI_CLOSURES */ diff --git a/js/src/ctypes/libffi/src/cris/ffi.c b/js/src/ctypes/libffi/src/cris/ffi.c new file mode 100644 index 0000000..f25d7b4 --- /dev/null +++ b/js/src/ctypes/libffi/src/cris/ffi.c @@ -0,0 +1,383 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1998 Cygnus Solutions + Copyright (c) 2004 Simon Posnjak + Copyright (c) 2005 Axis Communications AB + Copyright (C) 2007 Free Software Foundation, Inc. + + CRIS Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) + +static ffi_status +initialize_aggregate_packed_struct (ffi_type * arg) +{ + ffi_type **ptr; + + FFI_ASSERT (arg != NULL); + + FFI_ASSERT (arg->elements != NULL); + FFI_ASSERT (arg->size == 0); + FFI_ASSERT (arg->alignment == 0); + + ptr = &(arg->elements[0]); + + while ((*ptr) != NULL) + { + if (((*ptr)->size == 0) + && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + FFI_ASSERT (ffi_type_test ((*ptr))); + + arg->size += (*ptr)->size; + + arg->alignment = (arg->alignment > (*ptr)->alignment) ? + arg->alignment : (*ptr)->alignment; + + ptr++; + } + + if (arg->size == 0) + return FFI_BAD_TYPEDEF; + else + return FFI_OK; +} + +int +ffi_prep_args (char *stack, extended_cif * ecif) +{ + unsigned int i; + unsigned int struct_count = 0; + void **p_argv; + char *argp; + ffi_type **p_arg; + + argp = stack; + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + (i != 0); i--, p_arg++) + { + size_t z; + + switch ((*p_arg)->type) + { + case FFI_TYPE_STRUCT: + { + z = (*p_arg)->size; + if (z <= 4) + { + memcpy (argp, *p_argv, z); + z = 4; + } + else if (z <= 8) + { + memcpy (argp, *p_argv, z); + z = 8; + } + else + { + unsigned int uiLocOnStack; + z = sizeof (void *); + uiLocOnStack = 4 * ecif->cif->nargs + struct_count; + struct_count = struct_count + (*p_arg)->size; + *(unsigned int *) argp = + (unsigned int) (UINT32 *) (stack + uiLocOnStack); + memcpy ((stack + uiLocOnStack), *p_argv, (*p_arg)->size); + } + break; + } + default: + z = (*p_arg)->size; + if (z < sizeof (int)) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = + (unsigned int) *(UINT8 *) (*p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = + (unsigned int) *(UINT16 *) (*p_argv); + break; + + default: + FFI_ASSERT (0); + } + z = sizeof (int); + } + else if (z == sizeof (int)) + *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv); + else + memcpy (argp, *p_argv, z); + break; + } + p_argv++; + argp += z; + } + + return (struct_count); +} + +ffi_status +ffi_prep_cif (ffi_cif * cif, + ffi_abi abi, unsigned int nargs, + ffi_type * rtype, ffi_type ** atypes) +{ + unsigned bytes = 0; + unsigned int i; + ffi_type **ptr; + + FFI_ASSERT (cif != NULL); + FFI_ASSERT (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI); + + cif->abi = abi; + cif->arg_types = atypes; + cif->nargs = nargs; + cif->rtype = rtype; + + cif->flags = 0; + + if ((cif->rtype->size == 0) + && (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + FFI_ASSERT_VALID_TYPE (cif->rtype); + + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + if (((*ptr)->size == 0) + && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + FFI_ASSERT_VALID_TYPE (*ptr); + + if (((*ptr)->alignment - 1) & bytes) + bytes = ALIGN (bytes, (*ptr)->alignment); + if ((*ptr)->type == FFI_TYPE_STRUCT) + { + if ((*ptr)->size > 8) + { + bytes += (*ptr)->size; + bytes += sizeof (void *); + } + else + { + if ((*ptr)->size > 4) + bytes += 8; + else + bytes += 4; + } + } + else + bytes += STACK_ARG_SIZE ((*ptr)->size); + } + + cif->bytes = bytes; + + return ffi_prep_cif_machdep (cif); +} + +ffi_status +ffi_prep_cif_machdep (ffi_cif * cif) +{ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags = (unsigned) cif->rtype->type; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +extern void ffi_call_SYSV (int (*)(char *, extended_cif *), + extended_cif *, + unsigned, unsigned, unsigned *, void (*fn) ()) + __attribute__ ((__visibility__ ("hidden"))); + +void +ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) + { + ecif.rvalue = alloca (cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: + ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; + default: + FFI_ASSERT (0); + break; + } +} + +/* Because the following variables are not exported outside libffi, we + mark them hidden. */ + +/* Assembly code for the jump stub. */ +extern const char ffi_cris_trampoline_template[] + __attribute__ ((__visibility__ ("hidden"))); + +/* Offset into ffi_cris_trampoline_template of where to put the + ffi_prep_closure_inner function. */ +extern const int ffi_cris_trampoline_fn_offset + __attribute__ ((__visibility__ ("hidden"))); + +/* Offset into ffi_cris_trampoline_template of where to put the + closure data. */ +extern const int ffi_cris_trampoline_closure_offset + __attribute__ ((__visibility__ ("hidden"))); + +/* This function is sibling-called (jumped to) by the closure + trampoline. We get R10..R13 at PARAMS[0..3] and a copy of [SP] at + PARAMS[4] to simplify handling of a straddling parameter. A copy + of R9 is at PARAMS[5] and SP at PARAMS[6]. These parameters are + put at the appropriate place in CLOSURE which is then executed and + the return value is passed back to the caller. */ + +static unsigned long long +ffi_prep_closure_inner (void **params, ffi_closure* closure) +{ + char *register_args = (char *) params; + void *struct_ret = params[5]; + char *stack_args = params[6]; + char *ptr = register_args; + ffi_cif *cif = closure->cif; + ffi_type **arg_types = cif->arg_types; + + /* Max room needed is number of arguments as 64-bit values. */ + void **avalue = alloca (closure->cif->nargs * sizeof(void *)); + int i; + int doing_regs; + long long llret = 0; + + /* Find the address of each argument. */ + for (i = 0, doing_regs = 1; i < cif->nargs; i++) + { + /* Types up to and including 8 bytes go by-value. */ + if (arg_types[i]->size <= 4) + { + avalue[i] = ptr; + ptr += 4; + } + else if (arg_types[i]->size <= 8) + { + avalue[i] = ptr; + ptr += 8; + } + else + { + FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT); + + /* Passed by-reference, so copy the pointer. */ + avalue[i] = *(void **) ptr; + ptr += 4; + } + + /* If we've handled more arguments than fit in registers, start + looking at the those passed on the stack. Step over the + first one if we had a straddling parameter. */ + if (doing_regs && ptr >= register_args + 4*4) + { + ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0); + doing_regs = 0; + } + } + + /* Invoke the closure. */ + (closure->fun) (cif, + + cif->rtype->type == FFI_TYPE_STRUCT + /* The caller allocated space for the return + structure, and passed a pointer to this space in + R9. */ + ? struct_ret + + /* We take advantage of being able to ignore that + the high part isn't set if the return value is + not in R10:R11, but in R10 only. */ + : (void *) &llret, + + avalue, closure->user_data); + + return llret; +} + +/* API function: Prepare the trampoline. */ + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif *, void *, void **, void*), + void *user_data, + void *codeloc) +{ + void *innerfn = ffi_prep_closure_inner; + FFI_ASSERT (cif->abi == FFI_SYSV); + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + memcpy (closure->tramp, ffi_cris_trampoline_template, + FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE); + memcpy (closure->tramp + ffi_cris_trampoline_fn_offset, + &innerfn, sizeof (void *)); + memcpy (closure->tramp + ffi_cris_trampoline_closure_offset, + &codeloc, sizeof (void *)); + + return FFI_OK; +} diff --git a/js/src/ctypes/libffi/src/cris/ffitarget.h b/js/src/ctypes/libffi/src/cris/ffitarget.h new file mode 100644 index 0000000..0e3705d --- /dev/null +++ b/js/src/ctypes/libffi/src/cris/ffitarget.h @@ -0,0 +1,51 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for CRIS. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_SYSV +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE 36 +#define FFI_CRIS_TRAMPOLINE_DATA_PART_SIZE (7*4) +#define FFI_TRAMPOLINE_SIZE \ + (FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE + FFI_CRIS_TRAMPOLINE_DATA_PART_SIZE) +#define FFI_NATIVE_RAW_API 0 + +#endif diff --git a/js/src/ctypes/libffi/src/cris/sysv.S b/js/src/ctypes/libffi/src/cris/sysv.S new file mode 100644 index 0000000..79abaee --- /dev/null +++ b/js/src/ctypes/libffi/src/cris/sysv.S @@ -0,0 +1,215 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2004 Simon Posnjak + Copyright (c) 2005 Axis Communications AB + + CRIS Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#define CONCAT(x,y) x ## y +#define XCONCAT(x,y) CONCAT (x, y) +#define L(x) XCONCAT (__USER_LABEL_PREFIX__, x) + + .text + + ;; OK, when we get called we should have this (according to + ;; AXIS ETRAX 100LX Programmer's Manual chapter 6.3). + ;; + ;; R10: ffi_prep_args (func. pointer) + ;; R11: &ecif + ;; R12: cif->bytes + ;; R13: fig->flags + ;; sp+0: ecif.rvalue + ;; sp+4: fn (function pointer to the function that we need to call) + + .globl L(ffi_call_SYSV) + .type L(ffi_call_SYSV),@function + .hidden L(ffi_call_SYSV) + +L(ffi_call_SYSV): + ;; Save the regs to the stack. + push $srp + ;; Used for stack pointer saving. + push $r6 + ;; Used for function address pointer. + push $r7 + ;; Used for stack pointer saving. + push $r8 + ;; We save fig->flags to stack we will need them after we + ;; call The Function. + push $r13 + + ;; Saving current stack pointer. + move.d $sp,$r8 + move.d $sp,$r6 + + ;; Move address of ffi_prep_args to r13. + move.d $r10,$r13 + + ;; Make room on the stack for the args of fn. + sub.d $r12,$sp + + ;; Function void ffi_prep_args(char *stack, extended_cif *ecif) parameters are: + ;; r10 <-- stack pointer + ;; r11 <-- &ecif (already there) + move.d $sp,$r10 + + ;; Call the function. + jsr $r13 + + ;; Save the size of the structures which are passed on stack. + move.d $r10,$r7 + + ;; Move first four args in to r10..r13. + move.d [$sp+0],$r10 + move.d [$sp+4],$r11 + move.d [$sp+8],$r12 + move.d [$sp+12],$r13 + + ;; Adjust the stack and check if any parameters are given on stack. + addq 16,$sp + sub.d $r7,$r6 + cmp.d $sp,$r6 + + bpl go_on + nop + +go_on_no_params_on_stack: + move.d $r6,$sp + +go_on: + ;; Discover if we need to put rval address in to r9. + move.d [$r8+0],$r7 + cmpq FFI_TYPE_STRUCT,$r7 + bne call_now + nop + + ;; Move rval address to $r9. + move.d [$r8+20],$r9 + +call_now: + ;; Move address of The Function in to r7. + move.d [$r8+24],$r7 + + ;; Call The Function. + jsr $r7 + + ;; Reset stack. + move.d $r8,$sp + + ;; Load rval type (fig->flags) in to r13. + pop $r13 + + ;; Detect rval type. + cmpq FFI_TYPE_VOID,$r13 + beq epilogue + + cmpq FFI_TYPE_STRUCT,$r13 + beq epilogue + + cmpq FFI_TYPE_DOUBLE,$r13 + beq return_double_or_longlong + + cmpq FFI_TYPE_UINT64,$r13 + beq return_double_or_longlong + + cmpq FFI_TYPE_SINT64,$r13 + beq return_double_or_longlong + nop + + ;; Just return the 32 bit value. + ba return + nop + +return_double_or_longlong: + ;; Load half of the rval to r10 and the other half to r11. + move.d [$sp+16],$r13 + move.d $r10,[$r13] + addq 4,$r13 + move.d $r11,[$r13] + ba epilogue + nop + +return: + ;; Load the rval to r10. + move.d [$sp+16],$r13 + move.d $r10,[$r13] + +epilogue: + pop $r8 + pop $r7 + pop $r6 + Jump [$sp+] + + .size ffi_call_SYSV,.-ffi_call_SYSV + +/* Save R10..R13 into an array, somewhat like varargs. Copy the next + argument too, to simplify handling of any straddling parameter. + Save R9 and SP after those. Jump to function handling the rest. + Since this is a template, copied and the main function filled in by + the user. */ + + .globl L(ffi_cris_trampoline_template) + .type L(ffi_cris_trampoline_template),@function + .hidden L(ffi_cris_trampoline_template) + +L(ffi_cris_trampoline_template): +0: + /* The value we get for "PC" is right after the prefix instruction, + two bytes from the beginning, i.e. 0b+2. */ + move.d $r10,[$pc+2f-(0b+2)] + move.d $pc,$r10 +1: + addq 2f-1b+4,$r10 + move.d $r11,[$r10+] + move.d $r12,[$r10+] + move.d $r13,[$r10+] + move.d [$sp],$r11 + move.d $r11,[$r10+] + move.d $r9,[$r10+] + move.d $sp,[$r10+] + subq FFI_CRIS_TRAMPOLINE_DATA_PART_SIZE,$r10 + move.d 0,$r11 +3: + jump 0 +2: + .size ffi_cris_trampoline_template,.-0b + +/* This macro create a constant usable as "extern const int \name" in + C from within libffi, when \name has no prefix decoration. */ + + .macro const name,value + .globl \name + .type \name,@object + .hidden \name +\name: + .dword \value + .size \name,4 + .endm + +/* Constants for offsets within the trampoline. We could do this with + just symbols, avoiding memory contents and memory accesses, but the + C usage code would look a bit stranger. */ + + const L(ffi_cris_trampoline_fn_offset),2b-4-0b + const L(ffi_cris_trampoline_closure_offset),3b-4-0b diff --git a/js/src/ctypes/libffi/src/debug.c b/js/src/ctypes/libffi/src/debug.c new file mode 100644 index 0000000..51dcfcf --- /dev/null +++ b/js/src/ctypes/libffi/src/debug.c @@ -0,0 +1,59 @@ +/* ----------------------------------------------------------------------- + debug.c - Copyright (c) 1996 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include +#include +#include + +/* General debugging routines */ + +void ffi_stop_here(void) +{ + /* This function is only useful for debugging purposes. + Place a breakpoint on ffi_stop_here to be notified of + significant events. */ +} + +/* This function should only be called via the FFI_ASSERT() macro */ + +void ffi_assert(char *expr, char *file, int line) +{ + fprintf(stderr, "ASSERTION FAILURE: %s at %s:%d\n", expr, file, line); + ffi_stop_here(); + abort(); +} + +/* Perform a sanity check on an ffi_type structure */ + +void ffi_type_test(ffi_type *a, char *file, int line) +{ + FFI_ASSERT_AT(a != NULL, file, line); + + FFI_ASSERT_AT(a->type <= FFI_TYPE_LAST, file, line); + FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->size > 0, file, line); + FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->alignment > 0, file, line); + FFI_ASSERT_AT(a->type != FFI_TYPE_STRUCT || a->elements != NULL, file, line); + +} diff --git a/js/src/ctypes/libffi/src/dlmalloc.c b/js/src/ctypes/libffi/src/dlmalloc.c new file mode 100644 index 0000000..0fa235a --- /dev/null +++ b/js/src/ctypes/libffi/src/dlmalloc.c @@ -0,0 +1,5158 @@ +/* + This is a version (aka dlmalloc) of malloc/free/realloc written by + Doug Lea and released to the public domain, as explained at + http://creativecommons.org/licenses/publicdomain. Send questions, + comments, complaints, performance data, etc to dl@cs.oswego.edu + +* Version 2.8.3 Thu Sep 22 11:16:15 2005 Doug Lea (dl at gee) + + Note: There may be an updated version of this malloc obtainable at + ftp://gee.cs.oswego.edu/pub/misc/malloc.c + Check before installing! + +* Quickstart + + This library is all in one file to simplify the most common usage: + ftp it, compile it (-O3), and link it into another program. All of + the compile-time options default to reasonable values for use on + most platforms. You might later want to step through various + compile-time and dynamic tuning options. + + For convenience, an include file for code using this malloc is at: + ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.3.h + You don't really need this .h file unless you call functions not + defined in your system include files. The .h file contains only the + excerpts from this file needed for using this malloc on ANSI C/C++ + systems, so long as you haven't changed compile-time options about + naming and tuning parameters. If you do, then you can create your + own malloc.h that does include all settings by cutting at the point + indicated below. Note that you may already by default be using a C + library containing a malloc that is based on some version of this + malloc (for example in linux). You might still want to use the one + in this file to customize settings or to avoid overheads associated + with library versions. + +* Vital statistics: + + Supported pointer/size_t representation: 4 or 8 bytes + size_t MUST be an unsigned type of the same width as + pointers. (If you are using an ancient system that declares + size_t as a signed type, or need it to be a different width + than pointers, you can use a previous release of this malloc + (e.g. 2.7.2) supporting these.) + + Alignment: 8 bytes (default) + This suffices for nearly all current machines and C compilers. + However, you can define MALLOC_ALIGNMENT to be wider than this + if necessary (up to 128bytes), at the expense of using more space. + + Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes) + 8 or 16 bytes (if 8byte sizes) + Each malloced chunk has a hidden word of overhead holding size + and status information, and additional cross-check word + if FOOTERS is defined. + + Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead) + 8-byte ptrs: 32 bytes (including overhead) + + Even a request for zero bytes (i.e., malloc(0)) returns a + pointer to something of the minimum allocatable size. + The maximum overhead wastage (i.e., number of extra bytes + allocated than were requested in malloc) is less than or equal + to the minimum size, except for requests >= mmap_threshold that + are serviced via mmap(), where the worst case wastage is about + 32 bytes plus the remainder from a system page (the minimal + mmap unit); typically 4096 or 8192 bytes. + + Security: static-safe; optionally more or less + The "security" of malloc refers to the ability of malicious + code to accentuate the effects of errors (for example, freeing + space that is not currently malloc'ed or overwriting past the + ends of chunks) in code that calls malloc. This malloc + guarantees not to modify any memory locations below the base of + heap, i.e., static variables, even in the presence of usage + errors. The routines additionally detect most improper frees + and reallocs. All this holds as long as the static bookkeeping + for malloc itself is not corrupted by some other means. This + is only one aspect of security -- these checks do not, and + cannot, detect all possible programming errors. + + If FOOTERS is defined nonzero, then each allocated chunk + carries an additional check word to verify that it was malloced + from its space. These check words are the same within each + execution of a program using malloc, but differ across + executions, so externally crafted fake chunks cannot be + freed. This improves security by rejecting frees/reallocs that + could corrupt heap memory, in addition to the checks preventing + writes to statics that are always on. This may further improve + security at the expense of time and space overhead. (Note that + FOOTERS may also be worth using with MSPACES.) + + By default detected errors cause the program to abort (calling + "abort()"). You can override this to instead proceed past + errors by defining PROCEED_ON_ERROR. In this case, a bad free + has no effect, and a malloc that encounters a bad address + caused by user overwrites will ignore the bad address by + dropping pointers and indices to all known memory. This may + be appropriate for programs that should continue if at all + possible in the face of programming errors, although they may + run out of memory because dropped memory is never reclaimed. + + If you don't like either of these options, you can define + CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything + else. And if if you are sure that your program using malloc has + no errors or vulnerabilities, you can define INSECURE to 1, + which might (or might not) provide a small performance improvement. + + Thread-safety: NOT thread-safe unless USE_LOCKS defined + When USE_LOCKS is defined, each public call to malloc, free, + etc is surrounded with either a pthread mutex or a win32 + spinlock (depending on WIN32). This is not especially fast, and + can be a major bottleneck. It is designed only to provide + minimal protection in concurrent environments, and to provide a + basis for extensions. If you are using malloc in a concurrent + program, consider instead using ptmalloc, which is derived from + a version of this malloc. (See http://www.malloc.de). + + System requirements: Any combination of MORECORE and/or MMAP/MUNMAP + This malloc can use unix sbrk or any emulation (invoked using + the CALL_MORECORE macro) and/or mmap/munmap or any emulation + (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system + memory. On most unix systems, it tends to work best if both + MORECORE and MMAP are enabled. On Win32, it uses emulations + based on VirtualAlloc. It also uses common C library functions + like memset. + + Compliance: I believe it is compliant with the Single Unix Specification + (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably + others as well. + +* Overview of algorithms + + This is not the fastest, most space-conserving, most portable, or + most tunable malloc ever written. However it is among the fastest + while also being among the most space-conserving, portable and + tunable. Consistent balance across these factors results in a good + general-purpose allocator for malloc-intensive programs. + + In most ways, this malloc is a best-fit allocator. Generally, it + chooses the best-fitting existing chunk for a request, with ties + broken in approximately least-recently-used order. (This strategy + normally maintains low fragmentation.) However, for requests less + than 256bytes, it deviates from best-fit when there is not an + exactly fitting available chunk by preferring to use space adjacent + to that used for the previous small request, as well as by breaking + ties in approximately most-recently-used order. (These enhance + locality of series of small allocations.) And for very large requests + (>= 256Kb by default), it relies on system memory mapping + facilities, if supported. (This helps avoid carrying around and + possibly fragmenting memory used only for large chunks.) + + All operations (except malloc_stats and mallinfo) have execution + times that are bounded by a constant factor of the number of bits in + a size_t, not counting any clearing in calloc or copying in realloc, + or actions surrounding MORECORE and MMAP that have times + proportional to the number of non-contiguous regions returned by + system allocation routines, which is often just 1. + + The implementation is not very modular and seriously overuses + macros. Perhaps someday all C compilers will do as good a job + inlining modular code as can now be done by brute-force expansion, + but now, enough of them seem not to. + + Some compilers issue a lot of warnings about code that is + dead/unreachable only on some platforms, and also about intentional + uses of negation on unsigned types. All known cases of each can be + ignored. + + For a longer but out of date high-level description, see + http://gee.cs.oswego.edu/dl/html/malloc.html + +* MSPACES + If MSPACES is defined, then in addition to malloc, free, etc., + this file also defines mspace_malloc, mspace_free, etc. These + are versions of malloc routines that take an "mspace" argument + obtained using create_mspace, to control all internal bookkeeping. + If ONLY_MSPACES is defined, only these versions are compiled. + So if you would like to use this allocator for only some allocations, + and your system malloc for others, you can compile with + ONLY_MSPACES and then do something like... + static mspace mymspace = create_mspace(0,0); // for example + #define mymalloc(bytes) mspace_malloc(mymspace, bytes) + + (Note: If you only need one instance of an mspace, you can instead + use "USE_DL_PREFIX" to relabel the global malloc.) + + You can similarly create thread-local allocators by storing + mspaces as thread-locals. For example: + static __thread mspace tlms = 0; + void* tlmalloc(size_t bytes) { + if (tlms == 0) tlms = create_mspace(0, 0); + return mspace_malloc(tlms, bytes); + } + void tlfree(void* mem) { mspace_free(tlms, mem); } + + Unless FOOTERS is defined, each mspace is completely independent. + You cannot allocate from one and free to another (although + conformance is only weakly checked, so usage errors are not always + caught). If FOOTERS is defined, then each chunk carries around a tag + indicating its originating mspace, and frees are directed to their + originating spaces. + + ------------------------- Compile-time options --------------------------- + +Be careful in setting #define values for numerical constants of type +size_t. On some systems, literal values are not automatically extended +to size_t precision unless they are explicitly casted. + +WIN32 default: defined if _WIN32 defined + Defining WIN32 sets up defaults for MS environment and compilers. + Otherwise defaults are for unix. + +MALLOC_ALIGNMENT default: (size_t)8 + Controls the minimum alignment for malloc'ed chunks. It must be a + power of two and at least 8, even on machines for which smaller + alignments would suffice. It may be defined as larger than this + though. Note however that code and data structures are optimized for + the case of 8-byte alignment. + +MSPACES default: 0 (false) + If true, compile in support for independent allocation spaces. + This is only supported if HAVE_MMAP is true. + +ONLY_MSPACES default: 0 (false) + If true, only compile in mspace versions, not regular versions. + +USE_LOCKS default: 0 (false) + Causes each call to each public routine to be surrounded with + pthread or WIN32 mutex lock/unlock. (If set true, this can be + overridden on a per-mspace basis for mspace versions.) + +FOOTERS default: 0 + If true, provide extra checking and dispatching by placing + information in the footers of allocated chunks. This adds + space and time overhead. + +INSECURE default: 0 + If true, omit checks for usage errors and heap space overwrites. + +USE_DL_PREFIX default: NOT defined + Causes compiler to prefix all public routines with the string 'dl'. + This can be useful when you only want to use this malloc in one part + of a program, using your regular system malloc elsewhere. + +ABORT default: defined as abort() + Defines how to abort on failed checks. On most systems, a failed + check cannot die with an "assert" or even print an informative + message, because the underlying print routines in turn call malloc, + which will fail again. Generally, the best policy is to simply call + abort(). It's not very useful to do more than this because many + errors due to overwriting will show up as address faults (null, odd + addresses etc) rather than malloc-triggered checks, so will also + abort. Also, most compilers know that abort() does not return, so + can better optimize code conditionally calling it. + +PROCEED_ON_ERROR default: defined as 0 (false) + Controls whether detected bad addresses cause them to bypassed + rather than aborting. If set, detected bad arguments to free and + realloc are ignored. And all bookkeeping information is zeroed out + upon a detected overwrite of freed heap space, thus losing the + ability to ever return it from malloc again, but enabling the + application to proceed. If PROCEED_ON_ERROR is defined, the + static variable malloc_corruption_error_count is compiled in + and can be examined to see if errors have occurred. This option + generates slower code than the default abort policy. + +DEBUG default: NOT defined + The DEBUG setting is mainly intended for people trying to modify + this code or diagnose problems when porting to new platforms. + However, it may also be able to better isolate user errors than just + using runtime checks. The assertions in the check routines spell + out in more detail the assumptions and invariants underlying the + algorithms. The checking is fairly extensive, and will slow down + execution noticeably. Calling malloc_stats or mallinfo with DEBUG + set will attempt to check every non-mmapped allocated and free chunk + in the course of computing the summaries. + +ABORT_ON_ASSERT_FAILURE default: defined as 1 (true) + Debugging assertion failures can be nearly impossible if your + version of the assert macro causes malloc to be called, which will + lead to a cascade of further failures, blowing the runtime stack. + ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(), + which will usually make debugging easier. + +MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32 + The action to take before "return 0" when malloc fails to be able to + return memory because there is none available. + +HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES + True if this system supports sbrk or an emulation of it. + +MORECORE default: sbrk + The name of the sbrk-style system routine to call to obtain more + memory. See below for guidance on writing custom MORECORE + functions. The type of the argument to sbrk/MORECORE varies across + systems. It cannot be size_t, because it supports negative + arguments, so it is normally the signed type of the same width as + size_t (sometimes declared as "intptr_t"). It doesn't much matter + though. Internally, we only call it with arguments less than half + the max value of a size_t, which should work across all reasonable + possibilities, although sometimes generating compiler warnings. See + near the end of this file for guidelines for creating a custom + version of MORECORE. + +MORECORE_CONTIGUOUS default: 1 (true) + If true, take advantage of fact that consecutive calls to MORECORE + with positive arguments always return contiguous increasing + addresses. This is true of unix sbrk. It does not hurt too much to + set it true anyway, since malloc copes with non-contiguities. + Setting it false when definitely non-contiguous saves time + and possibly wasted space it would take to discover this though. + +MORECORE_CANNOT_TRIM default: NOT defined + True if MORECORE cannot release space back to the system when given + negative arguments. This is generally necessary only if you are + using a hand-crafted MORECORE function that cannot handle negative + arguments. + +HAVE_MMAP default: 1 (true) + True if this system supports mmap or an emulation of it. If so, and + HAVE_MORECORE is not true, MMAP is used for all system + allocation. If set and HAVE_MORECORE is true as well, MMAP is + primarily used to directly allocate very large blocks. It is also + used as a backup strategy in cases where MORECORE fails to provide + space from system. Note: A single call to MUNMAP is assumed to be + able to unmap memory that may have be allocated using multiple calls + to MMAP, so long as they are adjacent. + +HAVE_MREMAP default: 1 on linux, else 0 + If true realloc() uses mremap() to re-allocate large blocks and + extend or shrink allocation spaces. + +MMAP_CLEARS default: 1 on unix + True if mmap clears memory so calloc doesn't need to. This is true + for standard unix mmap using /dev/zero. + +USE_BUILTIN_FFS default: 0 (i.e., not used) + Causes malloc to use the builtin ffs() function to compute indices. + Some compilers may recognize and intrinsify ffs to be faster than the + supplied C version. Also, the case of x86 using gcc is special-cased + to an asm instruction, so is already as fast as it can be, and so + this setting has no effect. (On most x86s, the asm version is only + slightly faster than the C version.) + +malloc_getpagesize default: derive from system includes, or 4096. + The system page size. To the extent possible, this malloc manages + memory from the system in page-size units. This may be (and + usually is) a function rather than a constant. This is ignored + if WIN32, where page size is determined using getSystemInfo during + initialization. + +USE_DEV_RANDOM default: 0 (i.e., not used) + Causes malloc to use /dev/random to initialize secure magic seed for + stamping footers. Otherwise, the current time is used. + +NO_MALLINFO default: 0 + If defined, don't compile "mallinfo". This can be a simple way + of dealing with mismatches between system declarations and + those in this file. + +MALLINFO_FIELD_TYPE default: size_t + The type of the fields in the mallinfo struct. This was originally + defined as "int" in SVID etc, but is more usefully defined as + size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set + +REALLOC_ZERO_BYTES_FREES default: not defined + This should be set if a call to realloc with zero bytes should + be the same as a call to free. Some people think it should. Otherwise, + since this malloc returns a unique pointer for malloc(0), so does + realloc(p, 0). + +LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H +LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H +LACKS_STDLIB_H default: NOT defined unless on WIN32 + Define these if your system does not have these header files. + You might need to manually insert some of the declarations they provide. + +DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS, + system_info.dwAllocationGranularity in WIN32, + otherwise 64K. + Also settable using mallopt(M_GRANULARITY, x) + The unit for allocating and deallocating memory from the system. On + most systems with contiguous MORECORE, there is no reason to + make this more than a page. However, systems with MMAP tend to + either require or encourage larger granularities. You can increase + this value to prevent system allocation functions to be called so + often, especially if they are slow. The value must be at least one + page and must be a power of two. Setting to 0 causes initialization + to either page size or win32 region size. (Note: In previous + versions of malloc, the equivalent of this option was called + "TOP_PAD") + +DEFAULT_TRIM_THRESHOLD default: 2MB + Also settable using mallopt(M_TRIM_THRESHOLD, x) + The maximum amount of unused top-most memory to keep before + releasing via malloc_trim in free(). Automatic trimming is mainly + useful in long-lived programs using contiguous MORECORE. Because + trimming via sbrk can be slow on some systems, and can sometimes be + wasteful (in cases where programs immediately afterward allocate + more large chunks) the value should be high enough so that your + overall system performance would improve by releasing this much + memory. As a rough guide, you might set to a value close to the + average size of a process (program) running on your system. + Releasing this much memory would allow such a process to run in + memory. Generally, it is worth tuning trim thresholds when a + program undergoes phases where several large chunks are allocated + and released in ways that can reuse each other's storage, perhaps + mixed with phases where there are no such chunks at all. The trim + value must be greater than page size to have any useful effect. To + disable trimming completely, you can set to MAX_SIZE_T. Note that the trick + some people use of mallocing a huge space and then freeing it at + program startup, in an attempt to reserve system memory, doesn't + have the intended effect under automatic trimming, since that memory + will immediately be returned to the system. + +DEFAULT_MMAP_THRESHOLD default: 256K + Also settable using mallopt(M_MMAP_THRESHOLD, x) + The request size threshold for using MMAP to directly service a + request. Requests of at least this size that cannot be allocated + using already-existing space will be serviced via mmap. (If enough + normal freed space already exists it is used instead.) Using mmap + segregates relatively large chunks of memory so that they can be + individually obtained and released from the host system. A request + serviced through mmap is never reused by any other request (at least + not directly; the system may just so happen to remap successive + requests to the same locations). Segregating space in this way has + the benefits that: Mmapped space can always be individually released + back to the system, which helps keep the system level memory demands + of a long-lived program low. Also, mapped memory doesn't become + `locked' between other chunks, as can happen with normally allocated + chunks, which means that even trimming via malloc_trim would not + release them. However, it has the disadvantage that the space + cannot be reclaimed, consolidated, and then used to service later + requests, as happens with normal chunks. The advantages of mmap + nearly always outweigh disadvantages for "large" chunks, but the + value of "large" may vary across systems. The default is an + empirically derived value that works well in most systems. You can + disable mmap by setting to MAX_SIZE_T. + +*/ + +#ifndef WIN32 +#ifdef _WIN32 +#define WIN32 1 +#endif /* _WIN32 */ +#endif /* WIN32 */ +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#define HAVE_MMAP 1 +#define HAVE_MORECORE 0 +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H +#define LACKS_SYS_MMAN_H +#define LACKS_STRING_H +#define LACKS_STRINGS_H +#define LACKS_SYS_TYPES_H +#define LACKS_ERRNO_H +#define MALLOC_FAILURE_ACTION +#define MMAP_CLEARS 0 /* WINCE and some others apparently don't clear */ +#endif /* WIN32 */ + +#ifdef __OS2__ +#define INCL_DOS +#include +#define HAVE_MMAP 1 +#define HAVE_MORECORE 0 +#define LACKS_SYS_MMAN_H +#endif /* __OS2__ */ + +#if defined(DARWIN) || defined(_DARWIN) +/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ +#ifndef HAVE_MORECORE +#define HAVE_MORECORE 0 +#define HAVE_MMAP 1 +#endif /* HAVE_MORECORE */ +#endif /* DARWIN */ + +#ifndef LACKS_SYS_TYPES_H +#include /* For size_t */ +#endif /* LACKS_SYS_TYPES_H */ + +/* The maximum possible size_t value has all bits set */ +#define MAX_SIZE_T (~(size_t)0) + +#ifndef ONLY_MSPACES +#define ONLY_MSPACES 0 +#endif /* ONLY_MSPACES */ +#ifndef MSPACES +#if ONLY_MSPACES +#define MSPACES 1 +#else /* ONLY_MSPACES */ +#define MSPACES 0 +#endif /* ONLY_MSPACES */ +#endif /* MSPACES */ +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT ((size_t)8U) +#endif /* MALLOC_ALIGNMENT */ +#ifndef FOOTERS +#define FOOTERS 0 +#endif /* FOOTERS */ +#ifndef ABORT +#define ABORT abort() +#endif /* ABORT */ +#ifndef ABORT_ON_ASSERT_FAILURE +#define ABORT_ON_ASSERT_FAILURE 1 +#endif /* ABORT_ON_ASSERT_FAILURE */ +#ifndef PROCEED_ON_ERROR +#define PROCEED_ON_ERROR 0 +#endif /* PROCEED_ON_ERROR */ +#ifndef USE_LOCKS +#define USE_LOCKS 0 +#endif /* USE_LOCKS */ +#ifndef INSECURE +#define INSECURE 0 +#endif /* INSECURE */ +#ifndef HAVE_MMAP +#define HAVE_MMAP 1 +#endif /* HAVE_MMAP */ +#ifndef MMAP_CLEARS +#define MMAP_CLEARS 1 +#endif /* MMAP_CLEARS */ +#ifndef HAVE_MREMAP +#ifdef linux +#define HAVE_MREMAP 1 +#else /* linux */ +#define HAVE_MREMAP 0 +#endif /* linux */ +#endif /* HAVE_MREMAP */ +#ifndef MALLOC_FAILURE_ACTION +#define MALLOC_FAILURE_ACTION errno = ENOMEM; +#endif /* MALLOC_FAILURE_ACTION */ +#ifndef HAVE_MORECORE +#if ONLY_MSPACES +#define HAVE_MORECORE 0 +#else /* ONLY_MSPACES */ +#define HAVE_MORECORE 1 +#endif /* ONLY_MSPACES */ +#endif /* HAVE_MORECORE */ +#if !HAVE_MORECORE +#define MORECORE_CONTIGUOUS 0 +#else /* !HAVE_MORECORE */ +#ifndef MORECORE +#define MORECORE sbrk +#endif /* MORECORE */ +#ifndef MORECORE_CONTIGUOUS +#define MORECORE_CONTIGUOUS 1 +#endif /* MORECORE_CONTIGUOUS */ +#endif /* HAVE_MORECORE */ +#ifndef DEFAULT_GRANULARITY +#if MORECORE_CONTIGUOUS +#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ +#else /* MORECORE_CONTIGUOUS */ +#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) +#endif /* MORECORE_CONTIGUOUS */ +#endif /* DEFAULT_GRANULARITY */ +#ifndef DEFAULT_TRIM_THRESHOLD +#ifndef MORECORE_CANNOT_TRIM +#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) +#else /* MORECORE_CANNOT_TRIM */ +#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T +#endif /* MORECORE_CANNOT_TRIM */ +#endif /* DEFAULT_TRIM_THRESHOLD */ +#ifndef DEFAULT_MMAP_THRESHOLD +#if HAVE_MMAP +#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) +#else /* HAVE_MMAP */ +#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* DEFAULT_MMAP_THRESHOLD */ +#ifndef USE_BUILTIN_FFS +#define USE_BUILTIN_FFS 0 +#endif /* USE_BUILTIN_FFS */ +#ifndef USE_DEV_RANDOM +#define USE_DEV_RANDOM 0 +#endif /* USE_DEV_RANDOM */ +#ifndef NO_MALLINFO +#define NO_MALLINFO 0 +#endif /* NO_MALLINFO */ +#ifndef MALLINFO_FIELD_TYPE +#define MALLINFO_FIELD_TYPE size_t +#endif /* MALLINFO_FIELD_TYPE */ + +/* + mallopt tuning options. SVID/XPG defines four standard parameter + numbers for mallopt, normally defined in malloc.h. None of these + are used in this malloc, so setting them has no effect. But this + malloc does support the following options. +*/ + +#define M_TRIM_THRESHOLD (-1) +#define M_GRANULARITY (-2) +#define M_MMAP_THRESHOLD (-3) + +/* ------------------------ Mallinfo declarations ------------------------ */ + +#if !NO_MALLINFO +/* + This version of malloc supports the standard SVID/XPG mallinfo + routine that returns a struct containing usage properties and + statistics. It should work on any system that has a + /usr/include/malloc.h defining struct mallinfo. The main + declaration needed is the mallinfo struct that is returned (by-copy) + by mallinfo(). The malloinfo struct contains a bunch of fields that + are not even meaningful in this version of malloc. These fields are + are instead filled by mallinfo() with other numbers that might be of + interest. + + HAVE_USR_INCLUDE_MALLOC_H should be set if you have a + /usr/include/malloc.h file that includes a declaration of struct + mallinfo. If so, it is included; else a compliant version is + declared below. These must be precisely the same for mallinfo() to + work. The original SVID version of this struct, defined on most + systems with mallinfo, declares all fields as ints. But some others + define as unsigned long. If your system defines the fields using a + type of different width than listed here, you MUST #include your + system version and #define HAVE_USR_INCLUDE_MALLOC_H. +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#ifdef HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else /* HAVE_USR_INCLUDE_MALLOC_H */ + +struct mallinfo { + MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ + MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ + MALLINFO_FIELD_TYPE smblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ + MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ + MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ + MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ + MALLINFO_FIELD_TYPE fordblks; /* total free space */ + MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ +}; + +#endif /* HAVE_USR_INCLUDE_MALLOC_H */ +#endif /* NO_MALLINFO */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if !ONLY_MSPACES + +/* ------------------- Declarations of public routines ------------------- */ + +#ifndef USE_DL_PREFIX +#define dlcalloc calloc +#define dlfree free +#define dlmalloc malloc +#define dlmemalign memalign +#define dlrealloc realloc +#define dlvalloc valloc +#define dlpvalloc pvalloc +#define dlmallinfo mallinfo +#define dlmallopt mallopt +#define dlmalloc_trim malloc_trim +#define dlmalloc_stats malloc_stats +#define dlmalloc_usable_size malloc_usable_size +#define dlmalloc_footprint malloc_footprint +#define dlmalloc_max_footprint malloc_max_footprint +#define dlindependent_calloc independent_calloc +#define dlindependent_comalloc independent_comalloc +#endif /* USE_DL_PREFIX */ + + +/* + malloc(size_t n) + Returns a pointer to a newly allocated chunk of at least n bytes, or + null if no space is available, in which case errno is set to ENOMEM + on ANSI C systems. + + If n is zero, malloc returns a minimum-sized chunk. (The minimum + size is 16 bytes on most 32bit systems, and 32 bytes on 64bit + systems.) Note that size_t is an unsigned type, so calls with + arguments that would be negative if signed are interpreted as + requests for huge amounts of space, which will often fail. The + maximum supported value of n differs across systems, but is in all + cases less than the maximum representable value of a size_t. +*/ +void* dlmalloc(size_t); + +/* + free(void* p) + Releases the chunk of memory pointed to by p, that had been previously + allocated using malloc or a related routine such as realloc. + It has no effect if p is null. If p was not malloced or already + freed, free(p) will by default cause the current program to abort. +*/ +void dlfree(void*); + +/* + calloc(size_t n_elements, size_t element_size); + Returns a pointer to n_elements * element_size bytes, with all locations + set to zero. +*/ +void* dlcalloc(size_t, size_t); + +/* + realloc(void* p, size_t n) + Returns a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. + + The returned pointer may or may not be the same as p. The algorithm + prefers extending p in most cases when possible, otherwise it + employs the equivalent of a malloc-copy-free sequence. + + If p is null, realloc is equivalent to malloc. + + If space is not available, realloc returns null, errno is set (if on + ANSI) and p is NOT freed. + + if n is for fewer bytes than already held by p, the newly unused + space is lopped off and freed if possible. realloc with a size + argument of zero (re)allocates a minimum-sized chunk. + + The old unix realloc convention of allowing the last-free'd chunk + to be used as an argument to realloc is not supported. +*/ + +void* dlrealloc(void*, size_t); + +/* + memalign(size_t alignment, size_t n); + Returns a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument. + + The alignment argument should be a power of two. If the argument is + not a power of two, the nearest greater power is used. + 8-byte alignment is guaranteed by normal malloc calls, so don't + bother calling memalign with an argument of 8 or less. + + Overreliance on memalign is a sure way to fragment space. +*/ +void* dlmemalign(size_t, size_t); + +/* + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system. If the pagesize is unknown, 4096 is used. +*/ +void* dlvalloc(size_t); + +/* + mallopt(int parameter_number, int parameter_value) + Sets tunable parameters The format is to provide a + (parameter-number, parameter-value) pair. mallopt then sets the + corresponding parameter to the argument value if it can (i.e., so + long as the value is meaningful), and returns 1 if successful else + 0. SVID/XPG/ANSI defines four standard param numbers for mallopt, + normally defined in malloc.h. None of these are use in this malloc, + so setting them has no effect. But this malloc also supports other + options in mallopt. See below for details. Briefly, supported + parameters are as follows (listed defaults are for "typical" + configurations). + + Symbol param # default allowed param values + M_TRIM_THRESHOLD -1 2*1024*1024 any (MAX_SIZE_T disables) + M_GRANULARITY -2 page size any power of 2 >= page size + M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) +*/ +int dlmallopt(int, int); + +/* + malloc_footprint(); + Returns the number of bytes obtained from the system. The total + number of bytes allocated by malloc, realloc etc., is less than this + value. Unlike mallinfo, this function returns only a precomputed + result, so can be called frequently to monitor memory consumption. + Even if locks are otherwise defined, this function does not use them, + so results might not be up to date. +*/ +size_t dlmalloc_footprint(void); + +/* + malloc_max_footprint(); + Returns the maximum number of bytes obtained from the system. This + value will be greater than current footprint if deallocated space + has been reclaimed by the system. The peak number of bytes allocated + by malloc, realloc etc., is less than this value. Unlike mallinfo, + this function returns only a precomputed result, so can be called + frequently to monitor memory consumption. Even if locks are + otherwise defined, this function does not use them, so results might + not be up to date. +*/ +size_t dlmalloc_max_footprint(void); + +#if !NO_MALLINFO +/* + mallinfo() + Returns (by copy) a struct containing various summary statistics: + + arena: current total non-mmapped bytes allocated from system + ordblks: the number of free chunks + smblks: always zero. + hblks: current number of mmapped regions + hblkhd: total bytes held in mmapped regions + usmblks: the maximum total allocated space. This will be greater + than current total if trimming has occurred. + fsmblks: always zero + uordblks: current total allocated space (normal or mmapped) + fordblks: total free space + keepcost: the maximum number of bytes that could ideally be released + back to system via malloc_trim. ("ideally" means that + it ignores page restrictions etc.) + + Because these fields are ints, but internal bookkeeping may + be kept as longs, the reported values may wrap around zero and + thus be inaccurate. +*/ +struct mallinfo dlmallinfo(void); +#endif /* NO_MALLINFO */ + +/* + independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); + + independent_calloc is similar to calloc, but instead of returning a + single cleared space, it returns an array of pointers to n_elements + independent elements that can hold contents of size elem_size, each + of which starts out cleared, and can be independently freed, + realloc'ed etc. The elements are guaranteed to be adjacently + allocated (this is not guaranteed to occur with multiple callocs or + mallocs), which may also improve cache locality in some + applications. + + The "chunks" argument is optional (i.e., may be null, which is + probably the most typical usage). If it is null, the returned array + is itself dynamically allocated and should also be freed when it is + no longer needed. Otherwise, the chunks array must be of at least + n_elements in length. It is filled in with the pointers to the + chunks. + + In either case, independent_calloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and "chunks" + is null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be individually freed when it is no longer + needed. If you'd like to instead be able to free all at once, you + should instead use regular calloc and assign pointers into this + space to represent elements. (In this case though, you cannot + independently free elements.) + + independent_calloc simplifies and speeds up implementations of many + kinds of pools. It may also be useful when constructing large data + structures that initially have a fixed number of fixed-sized nodes, + but the number is not known at compile time, and some of the nodes + may later need to be freed. For example: + + struct Node { int item; struct Node* next; }; + + struct Node* build_list() { + struct Node** pool; + int n = read_number_of_nodes_needed(); + if (n <= 0) return 0; + pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); + if (pool == 0) die(); + // organize into a linked list... + struct Node* first = pool[0]; + for (i = 0; i < n-1; ++i) + pool[i]->next = pool[i+1]; + free(pool); // Can now free the array (or not, if it is needed later) + return first; + } +*/ +void** dlindependent_calloc(size_t, size_t, void**); + +/* + independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); + + independent_comalloc allocates, all at once, a set of n_elements + chunks with sizes indicated in the "sizes" array. It returns + an array of pointers to these elements, each of which can be + independently freed, realloc'ed etc. The elements are guaranteed to + be adjacently allocated (this is not guaranteed to occur with + multiple callocs or mallocs), which may also improve cache locality + in some applications. + + The "chunks" argument is optional (i.e., may be null). If it is null + the returned array is itself dynamically allocated and should also + be freed when it is no longer needed. Otherwise, the chunks array + must be of at least n_elements in length. It is filled in with the + pointers to the chunks. + + In either case, independent_comalloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and chunks is + null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be individually freed when it is no longer + needed. If you'd like to instead be able to free all at once, you + should instead use a single regular malloc, and assign pointers at + particular offsets in the aggregate space. (In this case though, you + cannot independently free elements.) + + independent_comallac differs from independent_calloc in that each + element may have a different size, and also that it does not + automatically clear elements. + + independent_comalloc can be used to speed up allocation in cases + where several structs or objects must always be allocated at the + same time. For example: + + struct Head { ... } + struct Foot { ... } + + void send_message(char* msg) { + int msglen = strlen(msg); + size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; + void* chunks[3]; + if (independent_comalloc(3, sizes, chunks) == 0) + die(); + struct Head* head = (struct Head*)(chunks[0]); + char* body = (char*)(chunks[1]); + struct Foot* foot = (struct Foot*)(chunks[2]); + // ... + } + + In general though, independent_comalloc is worth using only for + larger values of n_elements. For small values, you probably won't + detect enough difference from series of malloc calls to bother. + + Overuse of independent_comalloc can increase overall memory usage, + since it cannot reuse existing noncontiguous small chunks that + might be available for some of the elements. +*/ +void** dlindependent_comalloc(size_t, size_t*, void**); + + +/* + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + */ +void* dlpvalloc(size_t); + +/* + malloc_trim(size_t pad); + + If possible, gives memory back to the system (via negative arguments + to sbrk) if there is unused memory at the `high' end of the malloc + pool or in unused MMAP segments. You can call this after freeing + large blocks of memory to potentially reduce the system-level memory + requirements of a program. However, it cannot guarantee to reduce + memory. Under some allocation patterns, some large free blocks of + memory will be locked between two used chunks, so they cannot be + given back to the system. + + The `pad' argument to malloc_trim represents the amount of free + trailing space to leave untrimmed. If this argument is zero, only + the minimum amount of memory to maintain internal data structures + will be left. Non-zero arguments can be supplied to maintain enough + trailing space to service future expected allocations without having + to re-obtain memory from the system. + + Malloc_trim returns 1 if it actually released any memory, else 0. +*/ +int dlmalloc_trim(size_t); + +/* + malloc_usable_size(void* p); + + Returns the number of bytes you can actually use in + an allocated chunk, which may be more than you requested (although + often not) due to alignment and minimum size constraints. + You can use this many bytes without worrying about + overwriting other allocated objects. This is not a particularly great + programming practice. malloc_usable_size can be more useful in + debugging and assertions, for example: + + p = malloc(n); + assert(malloc_usable_size(p) >= 256); +*/ +size_t dlmalloc_usable_size(void*); + +/* + malloc_stats(); + Prints on stderr the amount of space obtained from the system (both + via sbrk and mmap), the maximum amount (which may be more than + current if malloc_trim and/or munmap got called), and the current + number of bytes allocated via malloc (or realloc, etc) but not yet + freed. Note that this is the number of bytes allocated, not the + number requested. It will be larger than the number requested + because of alignment and bookkeeping overhead. Because it includes + alignment wastage as being in use, this figure may be greater than + zero even when no user-level chunks are allocated. + + The reported current and maximum system memory can be inaccurate if + a program makes other calls to system memory allocation functions + (normally sbrk) outside of malloc. + + malloc_stats prints only the most commonly interesting statistics. + More information can be obtained by calling mallinfo. +*/ +void dlmalloc_stats(void); + +#endif /* ONLY_MSPACES */ + +#if MSPACES + +/* + mspace is an opaque type representing an independent + region of space that supports mspace_malloc, etc. +*/ +typedef void* mspace; + +/* + create_mspace creates and returns a new independent space with the + given initial capacity, or, if 0, the default granularity size. It + returns null if there is no system memory available to create the + space. If argument locked is non-zero, the space uses a separate + lock to control access. The capacity of the space will grow + dynamically as needed to service mspace_malloc requests. You can + control the sizes of incremental increases of this space by + compiling with a different DEFAULT_GRANULARITY or dynamically + setting with mallopt(M_GRANULARITY, value). +*/ +mspace create_mspace(size_t capacity, int locked); + +/* + destroy_mspace destroys the given space, and attempts to return all + of its memory back to the system, returning the total number of + bytes freed. After destruction, the results of access to all memory + used by the space become undefined. +*/ +size_t destroy_mspace(mspace msp); + +/* + create_mspace_with_base uses the memory supplied as the initial base + of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this + space is used for bookkeeping, so the capacity must be at least this + large. (Otherwise 0 is returned.) When this initial space is + exhausted, additional memory will be obtained from the system. + Destroying this space will deallocate all additionally allocated + space (if possible) but not the initial base. +*/ +mspace create_mspace_with_base(void* base, size_t capacity, int locked); + +/* + mspace_malloc behaves as malloc, but operates within + the given space. +*/ +void* mspace_malloc(mspace msp, size_t bytes); + +/* + mspace_free behaves as free, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_free is not actually needed. + free may be called instead of mspace_free because freed chunks from + any space are handled by their originating spaces. +*/ +void mspace_free(mspace msp, void* mem); + +/* + mspace_realloc behaves as realloc, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_realloc is not actually + needed. realloc may be called instead of mspace_realloc because + realloced chunks from any space are handled by their originating + spaces. +*/ +void* mspace_realloc(mspace msp, void* mem, size_t newsize); + +/* + mspace_calloc behaves as calloc, but operates within + the given space. +*/ +void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); + +/* + mspace_memalign behaves as memalign, but operates within + the given space. +*/ +void* mspace_memalign(mspace msp, size_t alignment, size_t bytes); + +/* + mspace_independent_calloc behaves as independent_calloc, but + operates within the given space. +*/ +void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]); + +/* + mspace_independent_comalloc behaves as independent_comalloc, but + operates within the given space. +*/ +void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]); + +/* + mspace_footprint() returns the number of bytes obtained from the + system for this space. +*/ +size_t mspace_footprint(mspace msp); + +/* + mspace_max_footprint() returns the peak number of bytes obtained from the + system for this space. +*/ +size_t mspace_max_footprint(mspace msp); + + +#if !NO_MALLINFO +/* + mspace_mallinfo behaves as mallinfo, but reports properties of + the given space. +*/ +struct mallinfo mspace_mallinfo(mspace msp); +#endif /* NO_MALLINFO */ + +/* + mspace_malloc_stats behaves as malloc_stats, but reports + properties of the given space. +*/ +void mspace_malloc_stats(mspace msp); + +/* + mspace_trim behaves as malloc_trim, but + operates within the given space. +*/ +int mspace_trim(mspace msp, size_t pad); + +/* + An alias for mallopt. +*/ +int mspace_mallopt(int, int); + +#endif /* MSPACES */ + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif /* __cplusplus */ + +/* + ======================================================================== + To make a fully customizable malloc.h header file, cut everything + above this line, put into file malloc.h, edit to suit, and #include it + on the next line, as well as in programs that use this malloc. + ======================================================================== +*/ + +/* #include "malloc.h" */ + +/*------------------------------ internal #includes ---------------------- */ + +#ifdef _MSC_VER +#pragma warning( disable : 4146 ) /* no "unsigned" warnings */ +#endif /* _MSC_VER */ + +#include /* for printing in malloc_stats */ + +#ifndef LACKS_ERRNO_H +#include /* for MALLOC_FAILURE_ACTION */ +#endif /* LACKS_ERRNO_H */ +#if FOOTERS +#include /* for magic initialization */ +#endif /* FOOTERS */ +#ifndef LACKS_STDLIB_H +#include /* for abort() */ +#endif /* LACKS_STDLIB_H */ +#ifdef DEBUG +#if ABORT_ON_ASSERT_FAILURE +#define assert(x) if(!(x)) ABORT +#else /* ABORT_ON_ASSERT_FAILURE */ +#include +#endif /* ABORT_ON_ASSERT_FAILURE */ +#else /* DEBUG */ +#define assert(x) +#endif /* DEBUG */ +#ifndef LACKS_STRING_H +#include /* for memset etc */ +#endif /* LACKS_STRING_H */ +#if USE_BUILTIN_FFS +#ifndef LACKS_STRINGS_H +#include /* for ffs */ +#endif /* LACKS_STRINGS_H */ +#endif /* USE_BUILTIN_FFS */ +#if HAVE_MMAP +#ifndef LACKS_SYS_MMAN_H +#include /* for mmap */ +#endif /* LACKS_SYS_MMAN_H */ +#ifndef LACKS_FCNTL_H +#include +#endif /* LACKS_FCNTL_H */ +#endif /* HAVE_MMAP */ +#if HAVE_MORECORE +#ifndef LACKS_UNISTD_H +#include /* for sbrk */ +#else /* LACKS_UNISTD_H */ +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) +extern void* sbrk(ptrdiff_t); +#endif /* FreeBSD etc */ +#endif /* LACKS_UNISTD_H */ +#endif /* HAVE_MMAP */ + +#ifndef WIN32 +#ifndef malloc_getpagesize +# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ +# ifndef _SC_PAGE_SIZE +# define _SC_PAGE_SIZE _SC_PAGESIZE +# endif +# endif +# ifdef _SC_PAGE_SIZE +# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# else +# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) + extern size_t getpagesize(); +# define malloc_getpagesize getpagesize() +# else +# ifdef WIN32 /* use supplied emulation of getpagesize */ +# define malloc_getpagesize getpagesize() +# else +# ifndef LACKS_SYS_PARAM_H +# include +# endif +# ifdef EXEC_PAGESIZE +# define malloc_getpagesize EXEC_PAGESIZE +# else +# ifdef NBPG +# ifndef CLSIZE +# define malloc_getpagesize NBPG +# else +# define malloc_getpagesize (NBPG * CLSIZE) +# endif +# else +# ifdef NBPC +# define malloc_getpagesize NBPC +# else +# ifdef PAGESIZE +# define malloc_getpagesize PAGESIZE +# else /* just guess */ +# define malloc_getpagesize ((size_t)4096U) +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif +#endif + +/* ------------------- size_t and alignment properties -------------------- */ + +/* The byte and bit size of a size_t */ +#define SIZE_T_SIZE (sizeof(size_t)) +#define SIZE_T_BITSIZE (sizeof(size_t) << 3) + +/* Some constants coerced to size_t */ +/* Annoying but necessary to avoid errors on some plaftorms */ +#define SIZE_T_ZERO ((size_t)0) +#define SIZE_T_ONE ((size_t)1) +#define SIZE_T_TWO ((size_t)2) +#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1) +#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2) +#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES) +#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) + +/* The bit mask value corresponding to MALLOC_ALIGNMENT */ +#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) + +/* True if address a has acceptable alignment */ +#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) + +/* the number of bytes to offset an address to align it */ +#define align_offset(A)\ + ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ + ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) + +/* -------------------------- MMAP preliminaries ------------------------- */ + +/* + If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and + checks to fail so compiler optimizer can delete code rather than + using so many "#if"s. +*/ + + +/* MORECORE and MMAP must return MFAIL on failure */ +#define MFAIL ((void*)(MAX_SIZE_T)) +#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */ + +#if !HAVE_MMAP +#define IS_MMAPPED_BIT (SIZE_T_ZERO) +#define USE_MMAP_BIT (SIZE_T_ZERO) +#define CALL_MMAP(s) MFAIL +#define CALL_MUNMAP(a, s) (-1) +#define DIRECT_MMAP(s) MFAIL + +#else /* HAVE_MMAP */ +#define IS_MMAPPED_BIT (SIZE_T_ONE) +#define USE_MMAP_BIT (SIZE_T_ONE) + +#if !defined(WIN32) && !defined (__OS2__) +#define CALL_MUNMAP(a, s) munmap((a), (s)) +#define MMAP_PROT (PROT_READ|PROT_WRITE) +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif /* MAP_ANON */ +#ifdef MAP_ANONYMOUS +#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) +#define CALL_MMAP(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0) +#else /* MAP_ANONYMOUS */ +/* + Nearly all versions of mmap support MAP_ANONYMOUS, so the following + is unlikely to be needed, but is supplied just in case. +*/ +#define MMAP_FLAGS (MAP_PRIVATE) +static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ +#define CALL_MMAP(s) ((dev_zero_fd < 0) ? \ + (dev_zero_fd = open("/dev/zero", O_RDWR), \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) +#endif /* MAP_ANONYMOUS */ + +#define DIRECT_MMAP(s) CALL_MMAP(s) + +#elif defined(__OS2__) + +/* OS/2 MMAP via DosAllocMem */ +static void* os2mmap(size_t size) { + void* ptr; + if (DosAllocMem(&ptr, size, OBJ_ANY|PAG_COMMIT|PAG_READ|PAG_WRITE) && + DosAllocMem(&ptr, size, PAG_COMMIT|PAG_READ|PAG_WRITE)) + return MFAIL; + return ptr; +} + +#define os2direct_mmap(n) os2mmap(n) + +/* This function supports releasing coalesed segments */ +static int os2munmap(void* ptr, size_t size) { + while (size) { + ULONG ulSize = size; + ULONG ulFlags = 0; + if (DosQueryMem(ptr, &ulSize, &ulFlags) != 0) + return -1; + if ((ulFlags & PAG_BASE) == 0 ||(ulFlags & PAG_COMMIT) == 0 || + ulSize > size) + return -1; + if (DosFreeMem(ptr) != 0) + return -1; + ptr = ( void * ) ( ( char * ) ptr + ulSize ); + size -= ulSize; + } + return 0; +} + +#define CALL_MMAP(s) os2mmap(s) +#define CALL_MUNMAP(a, s) os2munmap((a), (s)) +#define DIRECT_MMAP(s) os2direct_mmap(s) + +#else /* WIN32 */ + +/* Win32 MMAP via VirtualAlloc */ +static void* win32mmap(size_t size) { + void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); + return (ptr != 0)? ptr: MFAIL; +} + +/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ +static void* win32direct_mmap(size_t size) { + void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, + PAGE_EXECUTE_READWRITE); + return (ptr != 0)? ptr: MFAIL; +} + +/* This function supports releasing coalesed segments */ +static int win32munmap(void* ptr, size_t size) { + MEMORY_BASIC_INFORMATION minfo; + char* cptr = ptr; + while (size) { + if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) + return -1; + if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr || + minfo.State != MEM_COMMIT || minfo.RegionSize > size) + return -1; + if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) + return -1; + cptr += minfo.RegionSize; + size -= minfo.RegionSize; + } + return 0; +} + +#define CALL_MMAP(s) win32mmap(s) +#define CALL_MUNMAP(a, s) win32munmap((a), (s)) +#define DIRECT_MMAP(s) win32direct_mmap(s) +#endif /* WIN32 */ +#endif /* HAVE_MMAP */ + +#if HAVE_MMAP && HAVE_MREMAP +#define CALL_MREMAP(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv)) +#else /* HAVE_MMAP && HAVE_MREMAP */ +#define CALL_MREMAP(addr, osz, nsz, mv) MFAIL +#endif /* HAVE_MMAP && HAVE_MREMAP */ + +#if HAVE_MORECORE +#define CALL_MORECORE(S) MORECORE(S) +#else /* HAVE_MORECORE */ +#define CALL_MORECORE(S) MFAIL +#endif /* HAVE_MORECORE */ + +/* mstate bit set if continguous morecore disabled or failed */ +#define USE_NONCONTIGUOUS_BIT (4U) + +/* segment bit set in create_mspace_with_base */ +#define EXTERN_BIT (8U) + + +/* --------------------------- Lock preliminaries ------------------------ */ + +#if USE_LOCKS + +/* + When locks are defined, there are up to two global locks: + + * If HAVE_MORECORE, morecore_mutex protects sequences of calls to + MORECORE. In many cases sys_alloc requires two calls, that should + not be interleaved with calls by other threads. This does not + protect against direct calls to MORECORE by other threads not + using this lock, so there is still code to cope the best we can on + interference. + + * magic_init_mutex ensures that mparams.magic and other + unique mparams values are initialized only once. +*/ + +#if !defined(WIN32) && !defined(__OS2__) +/* By default use posix locks */ +#include +#define MLOCK_T pthread_mutex_t +#define INITIAL_LOCK(l) pthread_mutex_init(l, NULL) +#define ACQUIRE_LOCK(l) pthread_mutex_lock(l) +#define RELEASE_LOCK(l) pthread_mutex_unlock(l) + +#if HAVE_MORECORE +static MLOCK_T morecore_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif /* HAVE_MORECORE */ + +static MLOCK_T magic_init_mutex = PTHREAD_MUTEX_INITIALIZER; + +#elif defined(__OS2__) +#define MLOCK_T HMTX +#define INITIAL_LOCK(l) DosCreateMutexSem(0, l, 0, FALSE) +#define ACQUIRE_LOCK(l) DosRequestMutexSem(*l, SEM_INDEFINITE_WAIT) +#define RELEASE_LOCK(l) DosReleaseMutexSem(*l) +#if HAVE_MORECORE +static MLOCK_T morecore_mutex; +#endif /* HAVE_MORECORE */ +static MLOCK_T magic_init_mutex; + +#else /* WIN32 */ +/* + Because lock-protected regions have bounded times, and there + are no recursive lock calls, we can use simple spinlocks. +*/ + +#define MLOCK_T long +static int win32_acquire_lock (MLOCK_T *sl) { + for (;;) { +#ifdef InterlockedCompareExchangePointer + if (!InterlockedCompareExchange(sl, 1, 0)) + return 0; +#else /* Use older void* version */ + if (!InterlockedCompareExchange((void**)sl, (void*)1, (void*)0)) + return 0; +#endif /* InterlockedCompareExchangePointer */ + Sleep (0); + } +} + +static void win32_release_lock (MLOCK_T *sl) { + InterlockedExchange (sl, 0); +} + +#define INITIAL_LOCK(l) *(l)=0 +#define ACQUIRE_LOCK(l) win32_acquire_lock(l) +#define RELEASE_LOCK(l) win32_release_lock(l) +#if HAVE_MORECORE +static MLOCK_T morecore_mutex; +#endif /* HAVE_MORECORE */ +static MLOCK_T magic_init_mutex; +#endif /* WIN32 */ + +#define USE_LOCK_BIT (2U) +#else /* USE_LOCKS */ +#define USE_LOCK_BIT (0U) +#define INITIAL_LOCK(l) +#endif /* USE_LOCKS */ + +#if USE_LOCKS && HAVE_MORECORE +#define ACQUIRE_MORECORE_LOCK() ACQUIRE_LOCK(&morecore_mutex); +#define RELEASE_MORECORE_LOCK() RELEASE_LOCK(&morecore_mutex); +#else /* USE_LOCKS && HAVE_MORECORE */ +#define ACQUIRE_MORECORE_LOCK() +#define RELEASE_MORECORE_LOCK() +#endif /* USE_LOCKS && HAVE_MORECORE */ + +#if USE_LOCKS +#define ACQUIRE_MAGIC_INIT_LOCK() ACQUIRE_LOCK(&magic_init_mutex); +#define RELEASE_MAGIC_INIT_LOCK() RELEASE_LOCK(&magic_init_mutex); +#else /* USE_LOCKS */ +#define ACQUIRE_MAGIC_INIT_LOCK() +#define RELEASE_MAGIC_INIT_LOCK() +#endif /* USE_LOCKS */ + + +/* ----------------------- Chunk representations ------------------------ */ + +/* + (The following includes lightly edited explanations by Colin Plumb.) + + The malloc_chunk declaration below is misleading (but accurate and + necessary). It declares a "view" into memory allowing access to + necessary fields at known offsets from a given base. + + Chunks of memory are maintained using a `boundary tag' method as + originally described by Knuth. (See the paper by Paul Wilson + ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such + techniques.) Sizes of free chunks are stored both in the front of + each chunk and at the end. This makes consolidating fragmented + chunks into bigger chunks fast. The head fields also hold bits + representing whether chunks are free or in use. + + Here are some pictures to make it clearer. They are "exploded" to + show that the state of a chunk can be thought of as extending from + the high 31 bits of the head field of its header through the + prev_foot and PINUSE_BIT bit of the following chunk header. + + A chunk that's in use looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk (if P = 1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 1| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +- -+ + | | + +- -+ + | : + +- size - sizeof(size_t) available payload bytes -+ + : | + chunk-> +- -+ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| + | Size of next chunk (may or may not be in use) | +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + And if it's free, it looks like this: + + chunk-> +- -+ + | User payload (must be in use, or we would have merged!) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 0| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Next pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Prev pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- size - sizeof(struct chunk) unused bytes -+ + : | + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0| + | Size of next chunk (must be in use, or we would have merged)| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- User payload -+ + : | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |0| + +-+ + Note that since we always merge adjacent free chunks, the chunks + adjacent to a free chunk must be in use. + + Given a pointer to a chunk (which can be derived trivially from the + payload pointer) we can, in O(1) time, find out whether the adjacent + chunks are free, and if so, unlink them from the lists that they + are on and merge them with the current chunk. + + Chunks always begin on even word boundaries, so the mem portion + (which is returned to the user) is also on an even word boundary, and + thus at least double-word aligned. + + The P (PINUSE_BIT) bit, stored in the unused low-order bit of the + chunk size (which is always a multiple of two words), is an in-use + bit for the *previous* chunk. If that bit is *clear*, then the + word before the current chunk size contains the previous chunk + size, and can be used to find the front of the previous chunk. + The very first chunk allocated always has this bit set, preventing + access to non-existent (or non-owned) memory. If pinuse is set for + any given chunk, then you CANNOT determine the size of the + previous chunk, and might even get a memory addressing fault when + trying to do so. + + The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of + the chunk size redundantly records whether the current chunk is + inuse. This redundancy enables usage checks within free and realloc, + and reduces indirection when freeing and consolidating chunks. + + Each freshly allocated chunk must have both cinuse and pinuse set. + That is, each allocated chunk borders either a previously allocated + and still in-use chunk, or the base of its memory arena. This is + ensured by making all allocations from the the `lowest' part of any + found chunk. Further, no free chunk physically borders another one, + so each free chunk is known to be preceded and followed by either + inuse chunks or the ends of memory. + + Note that the `foot' of the current chunk is actually represented + as the prev_foot of the NEXT chunk. This makes it easier to + deal with alignments etc but can be very confusing when trying + to extend or adapt this code. + + The exceptions to all this are + + 1. The special chunk `top' is the top-most available chunk (i.e., + the one bordering the end of available memory). It is treated + specially. Top is never included in any bin, is used only if + no other chunk is available, and is released back to the + system if it is very large (see M_TRIM_THRESHOLD). In effect, + the top chunk is treated as larger (and thus less well + fitting) than any other available chunk. The top chunk + doesn't update its trailing size field since there is no next + contiguous chunk that would have to index off it. However, + space is still allocated for it (TOP_FOOT_SIZE) to enable + separation or merging when space is extended. + + 3. Chunks allocated via mmap, which have the lowest-order bit + (IS_MMAPPED_BIT) set in their prev_foot fields, and do not set + PINUSE_BIT in their head fields. Because they are allocated + one-by-one, each must carry its own prev_foot field, which is + also used to hold the offset this chunk has within its mmapped + region, which is needed to preserve alignment. Each mmapped + chunk is trailed by the first two fields of a fake next-chunk + for sake of usage checks. + +*/ + +struct malloc_chunk { + size_t prev_foot; /* Size of previous chunk (if free). */ + size_t head; /* Size and inuse bits. */ + struct malloc_chunk* fd; /* double links -- used only if free. */ + struct malloc_chunk* bk; +}; + +typedef struct malloc_chunk mchunk; +typedef struct malloc_chunk* mchunkptr; +typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ +typedef unsigned int bindex_t; /* Described below */ +typedef unsigned int binmap_t; /* Described below */ +typedef unsigned int flag_t; /* The type of various bit flag sets */ + +/* ------------------- Chunks sizes and alignments ----------------------- */ + +#define MCHUNK_SIZE (sizeof(mchunk)) + +#if FOOTERS +#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +#else /* FOOTERS */ +#define CHUNK_OVERHEAD (SIZE_T_SIZE) +#endif /* FOOTERS */ + +/* MMapped chunks need a second word of overhead ... */ +#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +/* ... and additional padding for fake next-chunk at foot */ +#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) + +/* The smallest size we can malloc is an aligned minimal chunk */ +#define MIN_CHUNK_SIZE\ + ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* conversion from malloc headers to user pointers, and back */ +#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES)) +/* chunk associated with aligned address A */ +#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) + +/* Bounds on request (not chunk) sizes. */ +#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) +#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) + +/* pad request bytes into a usable size */ +#define pad_request(req) \ + (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* pad request, checking for minimum (but not maximum) */ +#define request2size(req) \ + (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req)) + + +/* ------------------ Operations on head and foot fields ----------------- */ + +/* + The head field of a chunk is or'ed with PINUSE_BIT when previous + adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in + use. If the chunk was obtained with mmap, the prev_foot field has + IS_MMAPPED_BIT set, otherwise holding the offset of the base of the + mmapped region to the base of the chunk. +*/ + +#define PINUSE_BIT (SIZE_T_ONE) +#define CINUSE_BIT (SIZE_T_TWO) +#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT) + +/* Head value for fenceposts */ +#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE) + +/* extraction of fields from head words */ +#define cinuse(p) ((p)->head & CINUSE_BIT) +#define pinuse(p) ((p)->head & PINUSE_BIT) +#define chunksize(p) ((p)->head & ~(INUSE_BITS)) + +#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) +#define clear_cinuse(p) ((p)->head &= ~CINUSE_BIT) + +/* Treat space at ptr +/- offset as a chunk */ +#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) +#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s))) + +/* Ptr to next or previous physical malloc_chunk. */ +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~INUSE_BITS))) +#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) )) + +/* extract next chunk's pinuse bit */ +#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) + +/* Get/set size at footer */ +#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot) +#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s)) + +/* Set size, pinuse bit, and foot */ +#define set_size_and_pinuse_of_free_chunk(p, s)\ + ((p)->head = (s|PINUSE_BIT), set_foot(p, s)) + +/* Set size, pinuse bit, foot, and clear next pinuse */ +#define set_free_with_pinuse(p, s, n)\ + (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s)) + +#define is_mmapped(p)\ + (!((p)->head & PINUSE_BIT) && ((p)->prev_foot & IS_MMAPPED_BIT)) + +/* Get the internal overhead associated with chunk p */ +#define overhead_for(p)\ + (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) + +/* Return true if malloced space is not necessarily cleared */ +#if MMAP_CLEARS +#define calloc_must_clear(p) (!is_mmapped(p)) +#else /* MMAP_CLEARS */ +#define calloc_must_clear(p) (1) +#endif /* MMAP_CLEARS */ + +/* ---------------------- Overlaid data structures ----------------------- */ + +/* + When chunks are not in use, they are treated as nodes of either + lists or trees. + + "Small" chunks are stored in circular doubly-linked lists, and look + like this: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space (may be 0 bytes long) . + . . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Larger chunks are kept in a form of bitwise digital trees (aka + tries) keyed on chunksizes. Because malloc_tree_chunks are only for + free chunks greater than 256 bytes, their size doesn't impose any + constraints on user chunk sizes. Each node looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to left child (child[0]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to right child (child[1]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to parent | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | bin index of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Each tree holding treenodes is a tree of unique chunk sizes. Chunks + of the same size are arranged in a circularly-linked list, with only + the oldest chunk (the next to be used, in our FIFO ordering) + actually in the tree. (Tree members are distinguished by a non-null + parent pointer.) If a chunk with the same size an an existing node + is inserted, it is linked off the existing node using pointers that + work in the same way as fd/bk pointers of small chunks. + + Each tree contains a power of 2 sized range of chunk sizes (the + smallest is 0x100 <= x < 0x180), which is is divided in half at each + tree level, with the chunks in the smaller half of the range (0x100 + <= x < 0x140 for the top nose) in the left subtree and the larger + half (0x140 <= x < 0x180) in the right subtree. This is, of course, + done by inspecting individual bits. + + Using these rules, each node's left subtree contains all smaller + sizes than its right subtree. However, the node at the root of each + subtree has no particular ordering relationship to either. (The + dividing line between the subtree sizes is based on trie relation.) + If we remove the last chunk of a given size from the interior of the + tree, we need to replace it with a leaf node. The tree ordering + rules permit a node to be replaced by any leaf below it. + + The smallest chunk in a tree (a common operation in a best-fit + allocator) can be found by walking a path to the leftmost leaf in + the tree. Unlike a usual binary tree, where we follow left child + pointers until we reach a null, here we follow the right child + pointer any time the left one is null, until we reach a leaf with + both child pointers null. The smallest chunk in the tree will be + somewhere along that path. + + The worst case number of steps to add, find, or remove a node is + bounded by the number of bits differentiating chunks within + bins. Under current bin calculations, this ranges from 6 up to 21 + (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case + is of course much better. +*/ + +struct malloc_tree_chunk { + /* The first four fields must be compatible with malloc_chunk */ + size_t prev_foot; + size_t head; + struct malloc_tree_chunk* fd; + struct malloc_tree_chunk* bk; + + struct malloc_tree_chunk* child[2]; + struct malloc_tree_chunk* parent; + bindex_t index; +}; + +typedef struct malloc_tree_chunk tchunk; +typedef struct malloc_tree_chunk* tchunkptr; +typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */ + +/* A little helper macro for trees */ +#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1]) + +/* ----------------------------- Segments -------------------------------- */ + +/* + Each malloc space may include non-contiguous segments, held in a + list headed by an embedded malloc_segment record representing the + top-most space. Segments also include flags holding properties of + the space. Large chunks that are directly allocated by mmap are not + included in this list. They are instead independently created and + destroyed without otherwise keeping track of them. + + Segment management mainly comes into play for spaces allocated by + MMAP. Any call to MMAP might or might not return memory that is + adjacent to an existing segment. MORECORE normally contiguously + extends the current space, so this space is almost always adjacent, + which is simpler and faster to deal with. (This is why MORECORE is + used preferentially to MMAP when both are available -- see + sys_alloc.) When allocating using MMAP, we don't use any of the + hinting mechanisms (inconsistently) supported in various + implementations of unix mmap, or distinguish reserving from + committing memory. Instead, we just ask for space, and exploit + contiguity when we get it. It is probably possible to do + better than this on some systems, but no general scheme seems + to be significantly better. + + Management entails a simpler variant of the consolidation scheme + used for chunks to reduce fragmentation -- new adjacent memory is + normally prepended or appended to an existing segment. However, + there are limitations compared to chunk consolidation that mostly + reflect the fact that segment processing is relatively infrequent + (occurring only when getting memory from system) and that we + don't expect to have huge numbers of segments: + + * Segments are not indexed, so traversal requires linear scans. (It + would be possible to index these, but is not worth the extra + overhead and complexity for most programs on most platforms.) + * New segments are only appended to old ones when holding top-most + memory; if they cannot be prepended to others, they are held in + different segments. + + Except for the top-most segment of an mstate, each segment record + is kept at the tail of its segment. Segments are added by pushing + segment records onto the list headed by &mstate.seg for the + containing mstate. + + Segment flags control allocation/merge/deallocation policies: + * If EXTERN_BIT set, then we did not allocate this segment, + and so should not try to deallocate or merge with others. + (This currently holds only for the initial segment passed + into create_mspace_with_base.) + * If IS_MMAPPED_BIT set, the segment may be merged with + other surrounding mmapped segments and trimmed/de-allocated + using munmap. + * If neither bit is set, then the segment was obtained using + MORECORE so can be merged with surrounding MORECORE'd segments + and deallocated/trimmed using MORECORE with negative arguments. +*/ + +struct malloc_segment { + char* base; /* base address */ + size_t size; /* allocated size */ + struct malloc_segment* next; /* ptr to next segment */ +#if FFI_MMAP_EXEC_WRIT + /* The mmap magic is supposed to store the address of the executable + segment at the very end of the requested block. */ + +# define mmap_exec_offset(b,s) (*(ptrdiff_t*)((b)+(s)-sizeof(ptrdiff_t))) + + /* We can only merge segments if their corresponding executable + segments are at identical offsets. */ +# define check_segment_merge(S,b,s) \ + (mmap_exec_offset((b),(s)) == (S)->exec_offset) + +# define add_segment_exec_offset(p,S) ((char*)(p) + (S)->exec_offset) +# define sub_segment_exec_offset(p,S) ((char*)(p) - (S)->exec_offset) + + /* The removal of sflags only works with HAVE_MORECORE == 0. */ + +# define get_segment_flags(S) (IS_MMAPPED_BIT) +# define set_segment_flags(S,v) \ + (((v) != IS_MMAPPED_BIT) ? (ABORT, (v)) : \ + (((S)->exec_offset = \ + mmap_exec_offset((S)->base, (S)->size)), \ + (mmap_exec_offset((S)->base + (S)->exec_offset, (S)->size) != \ + (S)->exec_offset) ? (ABORT, (v)) : \ + (mmap_exec_offset((S)->base, (S)->size) = 0), (v))) + + /* We use an offset here, instead of a pointer, because then, when + base changes, we don't have to modify this. On architectures + with segmented addresses, this might not work. */ + ptrdiff_t exec_offset; +#else + +# define get_segment_flags(S) ((S)->sflags) +# define set_segment_flags(S,v) ((S)->sflags = (v)) +# define check_segment_merge(S,b,s) (1) + + flag_t sflags; /* mmap and extern flag */ +#endif +}; + +#define is_mmapped_segment(S) (get_segment_flags(S) & IS_MMAPPED_BIT) +#define is_extern_segment(S) (get_segment_flags(S) & EXTERN_BIT) + +typedef struct malloc_segment msegment; +typedef struct malloc_segment* msegmentptr; + +/* ---------------------------- malloc_state ----------------------------- */ + +/* + A malloc_state holds all of the bookkeeping for a space. + The main fields are: + + Top + The topmost chunk of the currently active segment. Its size is + cached in topsize. The actual size of topmost space is + topsize+TOP_FOOT_SIZE, which includes space reserved for adding + fenceposts and segment records if necessary when getting more + space from the system. The size at which to autotrim top is + cached from mparams in trim_check, except that it is disabled if + an autotrim fails. + + Designated victim (dv) + This is the preferred chunk for servicing small requests that + don't have exact fits. It is normally the chunk split off most + recently to service another small request. Its size is cached in + dvsize. The link fields of this chunk are not maintained since it + is not kept in a bin. + + SmallBins + An array of bin headers for free chunks. These bins hold chunks + with sizes less than MIN_LARGE_SIZE bytes. Each bin contains + chunks of all the same size, spaced 8 bytes apart. To simplify + use in double-linked lists, each bin header acts as a malloc_chunk + pointing to the real first node, if it exists (else pointing to + itself). This avoids special-casing for headers. But to avoid + waste, we allocate only the fd/bk pointers of bins, and then use + repositioning tricks to treat these as the fields of a chunk. + + TreeBins + Treebins are pointers to the roots of trees holding a range of + sizes. There are 2 equally spaced treebins for each power of two + from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything + larger. + + Bin maps + There is one bit map for small bins ("smallmap") and one for + treebins ("treemap). Each bin sets its bit when non-empty, and + clears the bit when empty. Bit operations are then used to avoid + bin-by-bin searching -- nearly all "search" is done without ever + looking at bins that won't be selected. The bit maps + conservatively use 32 bits per map word, even if on 64bit system. + For a good description of some of the bit-based techniques used + here, see Henry S. Warren Jr's book "Hacker's Delight" (and + supplement at http://hackersdelight.org/). Many of these are + intended to reduce the branchiness of paths through malloc etc, as + well as to reduce the number of memory locations read or written. + + Segments + A list of segments headed by an embedded malloc_segment record + representing the initial space. + + Address check support + The least_addr field is the least address ever obtained from + MORECORE or MMAP. Attempted frees and reallocs of any address less + than this are trapped (unless INSECURE is defined). + + Magic tag + A cross-check field that should always hold same value as mparams.magic. + + Flags + Bits recording whether to use MMAP, locks, or contiguous MORECORE + + Statistics + Each space keeps track of current and maximum system memory + obtained via MORECORE or MMAP. + + Locking + If USE_LOCKS is defined, the "mutex" lock is acquired and released + around every public call using this mspace. +*/ + +/* Bin types, widths and sizes */ +#define NSMALLBINS (32U) +#define NTREEBINS (32U) +#define SMALLBIN_SHIFT (3U) +#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) +#define TREEBIN_SHIFT (8U) +#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) +#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) +#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) + +struct malloc_state { + binmap_t smallmap; + binmap_t treemap; + size_t dvsize; + size_t topsize; + char* least_addr; + mchunkptr dv; + mchunkptr top; + size_t trim_check; + size_t magic; + mchunkptr smallbins[(NSMALLBINS+1)*2]; + tbinptr treebins[NTREEBINS]; + size_t footprint; + size_t max_footprint; + flag_t mflags; +#if USE_LOCKS + MLOCK_T mutex; /* locate lock among fields that rarely change */ +#endif /* USE_LOCKS */ + msegment seg; +}; + +typedef struct malloc_state* mstate; + +/* ------------- Global malloc_state and malloc_params ------------------- */ + +/* + malloc_params holds global properties, including those that can be + dynamically set using mallopt. There is a single instance, mparams, + initialized in init_mparams. +*/ + +struct malloc_params { + size_t magic; + size_t page_size; + size_t granularity; + size_t mmap_threshold; + size_t trim_threshold; + flag_t default_mflags; +}; + +static struct malloc_params mparams; + +/* The global malloc_state used for all non-"mspace" calls */ +static struct malloc_state _gm_; +#define gm (&_gm_) +#define is_global(M) ((M) == &_gm_) +#define is_initialized(M) ((M)->top != 0) + +/* -------------------------- system alloc setup ------------------------- */ + +/* Operations on mflags */ + +#define use_lock(M) ((M)->mflags & USE_LOCK_BIT) +#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT) +#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT) + +#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT) +#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT) +#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT) + +#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT) +#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT) + +#define set_lock(M,L)\ + ((M)->mflags = (L)?\ + ((M)->mflags | USE_LOCK_BIT) :\ + ((M)->mflags & ~USE_LOCK_BIT)) + +/* page-align a size */ +#define page_align(S)\ + (((S) + (mparams.page_size)) & ~(mparams.page_size - SIZE_T_ONE)) + +/* granularity-align a size */ +#define granularity_align(S)\ + (((S) + (mparams.granularity)) & ~(mparams.granularity - SIZE_T_ONE)) + +#define is_page_aligned(S)\ + (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0) +#define is_granularity_aligned(S)\ + (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0) + +/* True if segment S holds address A */ +#define segment_holds(S, A)\ + ((char*)(A) >= S->base && (char*)(A) < S->base + S->size) + +/* Return segment holding given address */ +static msegmentptr segment_holding(mstate m, char* addr) { + msegmentptr sp = &m->seg; + for (;;) { + if (addr >= sp->base && addr < sp->base + sp->size) + return sp; + if ((sp = sp->next) == 0) + return 0; + } +} + +/* Return true if segment contains a segment link */ +static int has_segment_link(mstate m, msegmentptr ss) { + msegmentptr sp = &m->seg; + for (;;) { + if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size) + return 1; + if ((sp = sp->next) == 0) + return 0; + } +} + +#ifndef MORECORE_CANNOT_TRIM +#define should_trim(M,s) ((s) > (M)->trim_check) +#else /* MORECORE_CANNOT_TRIM */ +#define should_trim(M,s) (0) +#endif /* MORECORE_CANNOT_TRIM */ + +/* + TOP_FOOT_SIZE is padding at the end of a segment, including space + that may be needed to place segment records and fenceposts when new + noncontiguous segments are added. +*/ +#define TOP_FOOT_SIZE\ + (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) + + +/* ------------------------------- Hooks -------------------------------- */ + +/* + PREACTION should be defined to return 0 on success, and nonzero on + failure. If you are not using locking, you can redefine these to do + anything you like. +*/ + +#if USE_LOCKS + +/* Ensure locks are initialized */ +#define GLOBALLY_INITIALIZE() (mparams.page_size == 0 && init_mparams()) + +#define PREACTION(M) ((GLOBALLY_INITIALIZE() || use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0) +#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); } +#else /* USE_LOCKS */ + +#ifndef PREACTION +#define PREACTION(M) (0) +#endif /* PREACTION */ + +#ifndef POSTACTION +#define POSTACTION(M) +#endif /* POSTACTION */ + +#endif /* USE_LOCKS */ + +/* + CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. + USAGE_ERROR_ACTION is triggered on detected bad frees and + reallocs. The argument p is an address that might have triggered the + fault. It is ignored by the two predefined actions, but might be + useful in custom actions that try to help diagnose errors. +*/ + +#if PROCEED_ON_ERROR + +/* A count of the number of corruption errors causing resets */ +int malloc_corruption_error_count; + +/* default corruption action */ +static void reset_on_error(mstate m); + +#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m) +#define USAGE_ERROR_ACTION(m, p) + +#else /* PROCEED_ON_ERROR */ + +#ifndef CORRUPTION_ERROR_ACTION +#define CORRUPTION_ERROR_ACTION(m) ABORT +#endif /* CORRUPTION_ERROR_ACTION */ + +#ifndef USAGE_ERROR_ACTION +#define USAGE_ERROR_ACTION(m,p) ABORT +#endif /* USAGE_ERROR_ACTION */ + +#endif /* PROCEED_ON_ERROR */ + +/* -------------------------- Debugging setup ---------------------------- */ + +#if ! DEBUG + +#define check_free_chunk(M,P) +#define check_inuse_chunk(M,P) +#define check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) +#define check_malloc_state(M) +#define check_top_chunk(M,P) + +#else /* DEBUG */ +#define check_free_chunk(M,P) do_check_free_chunk(M,P) +#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P) +#define check_top_chunk(M,P) do_check_top_chunk(M,P) +#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P) +#define check_malloc_state(M) do_check_malloc_state(M) + +static void do_check_any_chunk(mstate m, mchunkptr p); +static void do_check_top_chunk(mstate m, mchunkptr p); +static void do_check_mmapped_chunk(mstate m, mchunkptr p); +static void do_check_inuse_chunk(mstate m, mchunkptr p); +static void do_check_free_chunk(mstate m, mchunkptr p); +static void do_check_malloced_chunk(mstate m, void* mem, size_t s); +static void do_check_tree(mstate m, tchunkptr t); +static void do_check_treebin(mstate m, bindex_t i); +static void do_check_smallbin(mstate m, bindex_t i); +static void do_check_malloc_state(mstate m); +static int bin_find(mstate m, mchunkptr x); +static size_t traverse_and_check(mstate m); +#endif /* DEBUG */ + +/* ---------------------------- Indexing Bins ---------------------------- */ + +#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) +#define small_index(s) ((s) >> SMALLBIN_SHIFT) +#define small_index2size(i) ((i) << SMALLBIN_SHIFT) +#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) + +/* addressing by index. See above about smallbin repositioning */ +#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1]))) +#define treebin_at(M,i) (&((M)->treebins[i])) + +/* assign tree index for size S to variable I */ +#if defined(__GNUC__) && defined(i386) +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K;\ + __asm__("bsrl %1,%0\n\t" : "=r" (K) : "rm" (X));\ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} +#else /* GNUC */ +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int Y = (unsigned int)X;\ + unsigned int N = ((Y - 0x100) >> 16) & 8;\ + unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\ + N += K;\ + N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\ + K = 14 - N + ((Y <<= K) >> 15);\ + I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\ + }\ +} +#endif /* GNUC */ + +/* Bit representing maximum resolved size in a treebin at i */ +#define bit_for_tree_index(i) \ + (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2) + +/* Shift placing maximum resolved bit in a treebin at i as sign bit */ +#define leftshift_for_tree_index(i) \ + ((i == NTREEBINS-1)? 0 : \ + ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) + +/* The size of the smallest chunk held in bin with index i */ +#define minsize_for_tree_index(i) \ + ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ + (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) + + +/* ------------------------ Operations on bin maps ----------------------- */ + +/* bit corresponding to given index */ +#define idx2bit(i) ((binmap_t)(1) << (i)) + +/* Mark/Clear bits with given index */ +#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i)) +#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i)) +#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i)) + +#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i)) +#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i)) +#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i)) + +/* index corresponding to given bit */ + +#if defined(__GNUC__) && defined(i386) +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + __asm__("bsfl %1,%0\n\t" : "=r" (J) : "rm" (X));\ + I = (bindex_t)J;\ +} + +#else /* GNUC */ +#if USE_BUILTIN_FFS +#define compute_bit2idx(X, I) I = ffs(X)-1 + +#else /* USE_BUILTIN_FFS */ +#define compute_bit2idx(X, I)\ +{\ + unsigned int Y = X - 1;\ + unsigned int K = Y >> (16-4) & 16;\ + unsigned int N = K; Y >>= K;\ + N += K = Y >> (8-3) & 8; Y >>= K;\ + N += K = Y >> (4-2) & 4; Y >>= K;\ + N += K = Y >> (2-1) & 2; Y >>= K;\ + N += K = Y >> (1-0) & 1; Y >>= K;\ + I = (bindex_t)(N + Y);\ +} +#endif /* USE_BUILTIN_FFS */ +#endif /* GNUC */ + +/* isolate the least set bit of a bitmap */ +#define least_bit(x) ((x) & -(x)) + +/* mask with all bits to left of least bit of x on */ +#define left_bits(x) ((x<<1) | -(x<<1)) + +/* mask with all bits to left of or equal to least bit of x on */ +#define same_or_left_bits(x) ((x) | -(x)) + + +/* ----------------------- Runtime Check Support ------------------------- */ + +/* + For security, the main invariant is that malloc/free/etc never + writes to a static address other than malloc_state, unless static + malloc_state itself has been corrupted, which cannot occur via + malloc (because of these checks). In essence this means that we + believe all pointers, sizes, maps etc held in malloc_state, but + check all of those linked or offsetted from other embedded data + structures. These checks are interspersed with main code in a way + that tends to minimize their run-time cost. + + When FOOTERS is defined, in addition to range checking, we also + verify footer fields of inuse chunks, which can be used guarantee + that the mstate controlling malloc/free is intact. This is a + streamlined version of the approach described by William Robertson + et al in "Run-time Detection of Heap-based Overflows" LISA'03 + http://www.usenix.org/events/lisa03/tech/robertson.html The footer + of an inuse chunk holds the xor of its mstate and a random seed, + that is checked upon calls to free() and realloc(). This is + (probablistically) unguessable from outside the program, but can be + computed by any code successfully malloc'ing any chunk, so does not + itself provide protection against code that has already broken + security through some other means. Unlike Robertson et al, we + always dynamically check addresses of all offset chunks (previous, + next, etc). This turns out to be cheaper than relying on hashes. +*/ + +#if !INSECURE +/* Check if address a is at least as high as any from MORECORE or MMAP */ +#define ok_address(M, a) ((char*)(a) >= (M)->least_addr) +/* Check if address of next chunk n is higher than base chunk p */ +#define ok_next(p, n) ((char*)(p) < (char*)(n)) +/* Check if p has its cinuse bit on */ +#define ok_cinuse(p) cinuse(p) +/* Check if p has its pinuse bit on */ +#define ok_pinuse(p) pinuse(p) + +#else /* !INSECURE */ +#define ok_address(M, a) (1) +#define ok_next(b, n) (1) +#define ok_cinuse(p) (1) +#define ok_pinuse(p) (1) +#endif /* !INSECURE */ + +#if (FOOTERS && !INSECURE) +/* Check if (alleged) mstate m has expected magic field */ +#define ok_magic(M) ((M)->magic == mparams.magic) +#else /* (FOOTERS && !INSECURE) */ +#define ok_magic(M) (1) +#endif /* (FOOTERS && !INSECURE) */ + + +/* In gcc, use __builtin_expect to minimize impact of checks */ +#if !INSECURE +#if defined(__GNUC__) && __GNUC__ >= 3 +#define RTCHECK(e) __builtin_expect(e, 1) +#else /* GNUC */ +#define RTCHECK(e) (e) +#endif /* GNUC */ +#else /* !INSECURE */ +#define RTCHECK(e) (1) +#endif /* !INSECURE */ + +/* macros to set up inuse chunks with or without footers */ + +#if !FOOTERS + +#define mark_inuse_foot(M,p,s) + +/* Set cinuse bit and pinuse bit of next chunk */ +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set cinuse and pinuse of this chunk and pinuse of next chunk */ +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set size, cinuse and pinuse bit of this chunk */ +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT)) + +#else /* FOOTERS */ + +/* Set foot of inuse chunk to be xor of mstate and seed */ +#define mark_inuse_foot(M,p,s)\ + (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic)) + +#define get_mstate_for(p)\ + ((mstate)(((mchunkptr)((char*)(p) +\ + (chunksize(p))))->prev_foot ^ mparams.magic)) + +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \ + mark_inuse_foot(M,p,s)) + +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\ + mark_inuse_foot(M,p,s)) + +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + mark_inuse_foot(M, p, s)) + +#endif /* !FOOTERS */ + +/* ---------------------------- setting mparams -------------------------- */ + +/* Initialize mparams */ +static int init_mparams(void) { + if (mparams.page_size == 0) { + size_t s; + + mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; + mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; +#if MORECORE_CONTIGUOUS + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT; +#else /* MORECORE_CONTIGUOUS */ + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT; +#endif /* MORECORE_CONTIGUOUS */ + +#if (FOOTERS && !INSECURE) + { +#if USE_DEV_RANDOM + int fd; + unsigned char buf[sizeof(size_t)]; + /* Try to use /dev/urandom, else fall back on using time */ + if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 && + read(fd, buf, sizeof(buf)) == sizeof(buf)) { + s = *((size_t *) buf); + close(fd); + } + else +#endif /* USE_DEV_RANDOM */ + s = (size_t)(time(0) ^ (size_t)0x55555555U); + + s |= (size_t)8U; /* ensure nonzero */ + s &= ~(size_t)7U; /* improve chances of fault for bad values */ + + } +#else /* (FOOTERS && !INSECURE) */ + s = (size_t)0x58585858U; +#endif /* (FOOTERS && !INSECURE) */ + ACQUIRE_MAGIC_INIT_LOCK(); + if (mparams.magic == 0) { + mparams.magic = s; + /* Set up lock for main malloc area */ + INITIAL_LOCK(&gm->mutex); + gm->mflags = mparams.default_mflags; + } + RELEASE_MAGIC_INIT_LOCK(); + +#if !defined(WIN32) && !defined(__OS2__) + mparams.page_size = malloc_getpagesize; + mparams.granularity = ((DEFAULT_GRANULARITY != 0)? + DEFAULT_GRANULARITY : mparams.page_size); +#elif defined (__OS2__) + /* if low-memory is used, os2munmap() would break + if it were anything other than 64k */ + mparams.page_size = 4096u; + mparams.granularity = 65536u; +#else /* WIN32 */ + { + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + mparams.page_size = system_info.dwPageSize; + mparams.granularity = system_info.dwAllocationGranularity; + } +#endif /* WIN32 */ + + /* Sanity-check configuration: + size_t must be unsigned and as wide as pointer type. + ints must be at least 4 bytes. + alignment must be at least 8. + Alignment, min chunk size, and page size must all be powers of 2. + */ + if ((sizeof(size_t) != sizeof(char*)) || + (MAX_SIZE_T < MIN_CHUNK_SIZE) || + (sizeof(int) < 4) || + (MALLOC_ALIGNMENT < (size_t)8U) || + ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) || + ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) || + ((mparams.granularity & (mparams.granularity-SIZE_T_ONE)) != 0) || + ((mparams.page_size & (mparams.page_size-SIZE_T_ONE)) != 0)) + ABORT; + } + return 0; +} + +/* support for mallopt */ +static int change_mparam(int param_number, int value) { + size_t val = (size_t)value; + init_mparams(); + switch(param_number) { + case M_TRIM_THRESHOLD: + mparams.trim_threshold = val; + return 1; + case M_GRANULARITY: + if (val >= mparams.page_size && ((val & (val-1)) == 0)) { + mparams.granularity = val; + return 1; + } + else + return 0; + case M_MMAP_THRESHOLD: + mparams.mmap_threshold = val; + return 1; + default: + return 0; + } +} + +#if DEBUG +/* ------------------------- Debugging Support --------------------------- */ + +/* Check properties of any chunk, whether free, inuse, mmapped etc */ +static void do_check_any_chunk(mstate m, mchunkptr p) { + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); +} + +/* Check properties of top chunk */ +static void do_check_top_chunk(mstate m, mchunkptr p) { + msegmentptr sp = segment_holding(m, (char*)p); + size_t sz = chunksize(p); + assert(sp != 0); + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); + assert(sz == m->topsize); + assert(sz > 0); + assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE); + assert(pinuse(p)); + assert(!next_pinuse(p)); +} + +/* Check properties of (inuse) mmapped chunks */ +static void do_check_mmapped_chunk(mstate m, mchunkptr p) { + size_t sz = chunksize(p); + size_t len = (sz + (p->prev_foot & ~IS_MMAPPED_BIT) + MMAP_FOOT_PAD); + assert(is_mmapped(p)); + assert(use_mmap(m)); + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); + assert(!is_small(sz)); + assert((len & (mparams.page_size-SIZE_T_ONE)) == 0); + assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD); + assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0); +} + +/* Check properties of inuse chunks */ +static void do_check_inuse_chunk(mstate m, mchunkptr p) { + do_check_any_chunk(m, p); + assert(cinuse(p)); + assert(next_pinuse(p)); + /* If not pinuse and not mmapped, previous chunk has OK offset */ + assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p); + if (is_mmapped(p)) + do_check_mmapped_chunk(m, p); +} + +/* Check properties of free chunks */ +static void do_check_free_chunk(mstate m, mchunkptr p) { + size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT); + mchunkptr next = chunk_plus_offset(p, sz); + do_check_any_chunk(m, p); + assert(!cinuse(p)); + assert(!next_pinuse(p)); + assert (!is_mmapped(p)); + if (p != m->dv && p != m->top) { + if (sz >= MIN_CHUNK_SIZE) { + assert((sz & CHUNK_ALIGN_MASK) == 0); + assert(is_aligned(chunk2mem(p))); + assert(next->prev_foot == sz); + assert(pinuse(p)); + assert (next == m->top || cinuse(next)); + assert(p->fd->bk == p); + assert(p->bk->fd == p); + } + else /* markers are always of size SIZE_T_SIZE */ + assert(sz == SIZE_T_SIZE); + } +} + +/* Check properties of malloced chunks at the point they are malloced */ +static void do_check_malloced_chunk(mstate m, void* mem, size_t s) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT); + do_check_inuse_chunk(m, p); + assert((sz & CHUNK_ALIGN_MASK) == 0); + assert(sz >= MIN_CHUNK_SIZE); + assert(sz >= s); + /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */ + assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE)); + } +} + +/* Check a tree and its subtrees. */ +static void do_check_tree(mstate m, tchunkptr t) { + tchunkptr head = 0; + tchunkptr u = t; + bindex_t tindex = t->index; + size_t tsize = chunksize(t); + bindex_t idx; + compute_tree_index(tsize, idx); + assert(tindex == idx); + assert(tsize >= MIN_LARGE_SIZE); + assert(tsize >= minsize_for_tree_index(idx)); + assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1)))); + + do { /* traverse through chain of same-sized nodes */ + do_check_any_chunk(m, ((mchunkptr)u)); + assert(u->index == tindex); + assert(chunksize(u) == tsize); + assert(!cinuse(u)); + assert(!next_pinuse(u)); + assert(u->fd->bk == u); + assert(u->bk->fd == u); + if (u->parent == 0) { + assert(u->child[0] == 0); + assert(u->child[1] == 0); + } + else { + assert(head == 0); /* only one node on chain has parent */ + head = u; + assert(u->parent != u); + assert (u->parent->child[0] == u || + u->parent->child[1] == u || + *((tbinptr*)(u->parent)) == u); + if (u->child[0] != 0) { + assert(u->child[0]->parent == u); + assert(u->child[0] != u); + do_check_tree(m, u->child[0]); + } + if (u->child[1] != 0) { + assert(u->child[1]->parent == u); + assert(u->child[1] != u); + do_check_tree(m, u->child[1]); + } + if (u->child[0] != 0 && u->child[1] != 0) { + assert(chunksize(u->child[0]) < chunksize(u->child[1])); + } + } + u = u->fd; + } while (u != t); + assert(head != 0); +} + +/* Check all the chunks in a treebin. */ +static void do_check_treebin(mstate m, bindex_t i) { + tbinptr* tb = treebin_at(m, i); + tchunkptr t = *tb; + int empty = (m->treemap & (1U << i)) == 0; + if (t == 0) + assert(empty); + if (!empty) + do_check_tree(m, t); +} + +/* Check all the chunks in a smallbin. */ +static void do_check_smallbin(mstate m, bindex_t i) { + sbinptr b = smallbin_at(m, i); + mchunkptr p = b->bk; + unsigned int empty = (m->smallmap & (1U << i)) == 0; + if (p == b) + assert(empty); + if (!empty) { + for (; p != b; p = p->bk) { + size_t size = chunksize(p); + mchunkptr q; + /* each chunk claims to be free */ + do_check_free_chunk(m, p); + /* chunk belongs in bin */ + assert(small_index(size) == i); + assert(p->bk == b || chunksize(p->bk) == chunksize(p)); + /* chunk is followed by an inuse chunk */ + q = next_chunk(p); + if (q->head != FENCEPOST_HEAD) + do_check_inuse_chunk(m, q); + } + } +} + +/* Find x in a bin. Used in other check functions. */ +static int bin_find(mstate m, mchunkptr x) { + size_t size = chunksize(x); + if (is_small(size)) { + bindex_t sidx = small_index(size); + sbinptr b = smallbin_at(m, sidx); + if (smallmap_is_marked(m, sidx)) { + mchunkptr p = b; + do { + if (p == x) + return 1; + } while ((p = p->fd) != b); + } + } + else { + bindex_t tidx; + compute_tree_index(size, tidx); + if (treemap_is_marked(m, tidx)) { + tchunkptr t = *treebin_at(m, tidx); + size_t sizebits = size << leftshift_for_tree_index(tidx); + while (t != 0 && chunksize(t) != size) { + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + sizebits <<= 1; + } + if (t != 0) { + tchunkptr u = t; + do { + if (u == (tchunkptr)x) + return 1; + } while ((u = u->fd) != t); + } + } + } + return 0; +} + +/* Traverse each chunk and check it; return total */ +static size_t traverse_and_check(mstate m) { + size_t sum = 0; + if (is_initialized(m)) { + msegmentptr s = &m->seg; + sum += m->topsize + TOP_FOOT_SIZE; + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + mchunkptr lastq = 0; + assert(pinuse(q)); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + sum += chunksize(q); + if (cinuse(q)) { + assert(!bin_find(m, q)); + do_check_inuse_chunk(m, q); + } + else { + assert(q == m->dv || bin_find(m, q)); + assert(lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */ + do_check_free_chunk(m, q); + } + lastq = q; + q = next_chunk(q); + } + s = s->next; + } + } + return sum; +} + +/* Check all properties of malloc_state. */ +static void do_check_malloc_state(mstate m) { + bindex_t i; + size_t total; + /* check bins */ + for (i = 0; i < NSMALLBINS; ++i) + do_check_smallbin(m, i); + for (i = 0; i < NTREEBINS; ++i) + do_check_treebin(m, i); + + if (m->dvsize != 0) { /* check dv chunk */ + do_check_any_chunk(m, m->dv); + assert(m->dvsize == chunksize(m->dv)); + assert(m->dvsize >= MIN_CHUNK_SIZE); + assert(bin_find(m, m->dv) == 0); + } + + if (m->top != 0) { /* check top chunk */ + do_check_top_chunk(m, m->top); + assert(m->topsize == chunksize(m->top)); + assert(m->topsize > 0); + assert(bin_find(m, m->top) == 0); + } + + total = traverse_and_check(m); + assert(total <= m->footprint); + assert(m->footprint <= m->max_footprint); +} +#endif /* DEBUG */ + +/* ----------------------------- statistics ------------------------------ */ + +#if !NO_MALLINFO +static struct mallinfo internal_mallinfo(mstate m) { + struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + if (!PREACTION(m)) { + check_malloc_state(m); + if (is_initialized(m)) { + size_t nfree = SIZE_T_ONE; /* top always free */ + size_t mfree = m->topsize + TOP_FOOT_SIZE; + size_t sum = mfree; + msegmentptr s = &m->seg; + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + size_t sz = chunksize(q); + sum += sz; + if (!cinuse(q)) { + mfree += sz; + ++nfree; + } + q = next_chunk(q); + } + s = s->next; + } + + nm.arena = sum; + nm.ordblks = nfree; + nm.hblkhd = m->footprint - sum; + nm.usmblks = m->max_footprint; + nm.uordblks = m->footprint - mfree; + nm.fordblks = mfree; + nm.keepcost = m->topsize; + } + + POSTACTION(m); + } + return nm; +} +#endif /* !NO_MALLINFO */ + +static void internal_malloc_stats(mstate m) { + if (!PREACTION(m)) { + size_t maxfp = 0; + size_t fp = 0; + size_t used = 0; + check_malloc_state(m); + if (is_initialized(m)) { + msegmentptr s = &m->seg; + maxfp = m->max_footprint; + fp = m->footprint; + used = fp - (m->topsize + TOP_FOOT_SIZE); + + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + if (!cinuse(q)) + used -= chunksize(q); + q = next_chunk(q); + } + s = s->next; + } + } + + fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp)); + fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp)); + fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used)); + + POSTACTION(m); + } +} + +/* ----------------------- Operations on smallbins ----------------------- */ + +/* + Various forms of linking and unlinking are defined as macros. Even + the ones for trees, which are very long but have very short typical + paths. This is ugly but reduces reliance on inlining support of + compilers. +*/ + +/* Link a free chunk into a smallbin */ +#define insert_small_chunk(M, P, S) {\ + bindex_t I = small_index(S);\ + mchunkptr B = smallbin_at(M, I);\ + mchunkptr F = B;\ + assert(S >= MIN_CHUNK_SIZE);\ + if (!smallmap_is_marked(M, I))\ + mark_smallmap(M, I);\ + else if (RTCHECK(ok_address(M, B->fd)))\ + F = B->fd;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + B->fd = P;\ + F->bk = P;\ + P->fd = F;\ + P->bk = B;\ +} + +/* Unlink a chunk from a smallbin */ +#define unlink_small_chunk(M, P, S) {\ + mchunkptr F = P->fd;\ + mchunkptr B = P->bk;\ + bindex_t I = small_index(S);\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (F == B)\ + clear_smallmap(M, I);\ + else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\ + (B == smallbin_at(M,I) || ok_address(M, B)))) {\ + F->bk = B;\ + B->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + +/* Unlink the first chunk from a smallbin */ +#define unlink_first_small_chunk(M, B, P, I) {\ + mchunkptr F = P->fd;\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (B == F)\ + clear_smallmap(M, I);\ + else if (RTCHECK(ok_address(M, F))) {\ + B->fd = F;\ + F->bk = B;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + +/* Replace dv node, binning the old one */ +/* Used only when dvsize known to be small */ +#define replace_dv(M, P, S) {\ + size_t DVS = M->dvsize;\ + if (DVS != 0) {\ + mchunkptr DV = M->dv;\ + assert(is_small(DVS));\ + insert_small_chunk(M, DV, DVS);\ + }\ + M->dvsize = S;\ + M->dv = P;\ +} + +/* ------------------------- Operations on trees ------------------------- */ + +/* Insert chunk into tree */ +#define insert_large_chunk(M, X, S) {\ + tbinptr* H;\ + bindex_t I;\ + compute_tree_index(S, I);\ + H = treebin_at(M, I);\ + X->index = I;\ + X->child[0] = X->child[1] = 0;\ + if (!treemap_is_marked(M, I)) {\ + mark_treemap(M, I);\ + *H = X;\ + X->parent = (tchunkptr)H;\ + X->fd = X->bk = X;\ + }\ + else {\ + tchunkptr T = *H;\ + size_t K = S << leftshift_for_tree_index(I);\ + for (;;) {\ + if (chunksize(T) != S) {\ + tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\ + K <<= 1;\ + if (*C != 0)\ + T = *C;\ + else if (RTCHECK(ok_address(M, C))) {\ + *C = X;\ + X->parent = T;\ + X->fd = X->bk = X;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + else {\ + tchunkptr F = T->fd;\ + if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\ + T->fd = F->bk = X;\ + X->fd = F;\ + X->bk = T;\ + X->parent = 0;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + }\ + }\ +} + +/* + Unlink steps: + + 1. If x is a chained node, unlink it from its same-sized fd/bk links + and choose its bk node as its replacement. + 2. If x was the last node of its size, but not a leaf node, it must + be replaced with a leaf node (not merely one with an open left or + right), to make sure that lefts and rights of descendents + correspond properly to bit masks. We use the rightmost descendent + of x. We could use any other leaf, but this is easy to locate and + tends to counteract removal of leftmosts elsewhere, and so keeps + paths shorter than minimally guaranteed. This doesn't loop much + because on average a node in a tree is near the bottom. + 3. If x is the base of a chain (i.e., has parent links) relink + x's parent and children to x's replacement (or null if none). +*/ + +#define unlink_large_chunk(M, X) {\ + tchunkptr XP = X->parent;\ + tchunkptr R;\ + if (X->bk != X) {\ + tchunkptr F = X->fd;\ + R = X->bk;\ + if (RTCHECK(ok_address(M, F))) {\ + F->bk = R;\ + R->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else {\ + tchunkptr* RP;\ + if (((R = *(RP = &(X->child[1]))) != 0) ||\ + ((R = *(RP = &(X->child[0]))) != 0)) {\ + tchunkptr* CP;\ + while ((*(CP = &(R->child[1])) != 0) ||\ + (*(CP = &(R->child[0])) != 0)) {\ + R = *(RP = CP);\ + }\ + if (RTCHECK(ok_address(M, RP)))\ + *RP = 0;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + }\ + if (XP != 0) {\ + tbinptr* H = treebin_at(M, X->index);\ + if (X == *H) {\ + if ((*H = R) == 0) \ + clear_treemap(M, X->index);\ + }\ + else if (RTCHECK(ok_address(M, XP))) {\ + if (XP->child[0] == X) \ + XP->child[0] = R;\ + else \ + XP->child[1] = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + if (R != 0) {\ + if (RTCHECK(ok_address(M, R))) {\ + tchunkptr C0, C1;\ + R->parent = XP;\ + if ((C0 = X->child[0]) != 0) {\ + if (RTCHECK(ok_address(M, C0))) {\ + R->child[0] = C0;\ + C0->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + if ((C1 = X->child[1]) != 0) {\ + if (RTCHECK(ok_address(M, C1))) {\ + R->child[1] = C1;\ + C1->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ +} + +/* Relays to large vs small bin operations */ + +#define insert_chunk(M, P, S)\ + if (is_small(S)) insert_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); } + +#define unlink_chunk(M, P, S)\ + if (is_small(S)) unlink_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); } + + +/* Relays to internal calls to malloc/free from realloc, memalign etc */ + +#if ONLY_MSPACES +#define internal_malloc(m, b) mspace_malloc(m, b) +#define internal_free(m, mem) mspace_free(m,mem); +#else /* ONLY_MSPACES */ +#if MSPACES +#define internal_malloc(m, b)\ + (m == gm)? dlmalloc(b) : mspace_malloc(m, b) +#define internal_free(m, mem)\ + if (m == gm) dlfree(mem); else mspace_free(m,mem); +#else /* MSPACES */ +#define internal_malloc(m, b) dlmalloc(b) +#define internal_free(m, mem) dlfree(mem) +#endif /* MSPACES */ +#endif /* ONLY_MSPACES */ + +/* ----------------------- Direct-mmapping chunks ----------------------- */ + +/* + Directly mmapped chunks are set up with an offset to the start of + the mmapped region stored in the prev_foot field of the chunk. This + allows reconstruction of the required argument to MUNMAP when freed, + and also allows adjustment of the returned chunk to meet alignment + requirements (especially in memalign). There is also enough space + allocated to hold a fake next chunk of size SIZE_T_SIZE to maintain + the PINUSE bit so frees can be checked. +*/ + +/* Malloc using mmap */ +static void* mmap_alloc(mstate m, size_t nb) { + size_t mmsize = granularity_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + if (mmsize > nb) { /* Check for wrap around 0 */ + char* mm = (char*)(DIRECT_MMAP(mmsize)); + if (mm != CMFAIL) { + size_t offset = align_offset(chunk2mem(mm)); + size_t psize = mmsize - offset - MMAP_FOOT_PAD; + mchunkptr p = (mchunkptr)(mm + offset); + p->prev_foot = offset | IS_MMAPPED_BIT; + (p)->head = (psize|CINUSE_BIT); + mark_inuse_foot(m, p, psize); + chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0; + + if (mm < m->least_addr) + m->least_addr = mm; + if ((m->footprint += mmsize) > m->max_footprint) + m->max_footprint = m->footprint; + assert(is_aligned(chunk2mem(p))); + check_mmapped_chunk(m, p); + return chunk2mem(p); + } + } + return 0; +} + +/* Realloc using mmap */ +static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) { + size_t oldsize = chunksize(oldp); + if (is_small(nb)) /* Can't shrink mmap regions below small size */ + return 0; + /* Keep old chunk if big enough but not too big */ + if (oldsize >= nb + SIZE_T_SIZE && + (oldsize - nb) <= (mparams.granularity << 1)) + return oldp; + else { + size_t offset = oldp->prev_foot & ~IS_MMAPPED_BIT; + size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; + size_t newmmsize = granularity_align(nb + SIX_SIZE_T_SIZES + + CHUNK_ALIGN_MASK); + char* cp = (char*)CALL_MREMAP((char*)oldp - offset, + oldmmsize, newmmsize, 1); + if (cp != CMFAIL) { + mchunkptr newp = (mchunkptr)(cp + offset); + size_t psize = newmmsize - offset - MMAP_FOOT_PAD; + newp->head = (psize|CINUSE_BIT); + mark_inuse_foot(m, newp, psize); + chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0; + + if (cp < m->least_addr) + m->least_addr = cp; + if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) + m->max_footprint = m->footprint; + check_mmapped_chunk(m, newp); + return newp; + } + } + return 0; +} + +/* -------------------------- mspace management -------------------------- */ + +/* Initialize top chunk and its size */ +static void init_top(mstate m, mchunkptr p, size_t psize) { + /* Ensure alignment */ + size_t offset = align_offset(chunk2mem(p)); + p = (mchunkptr)((char*)p + offset); + psize -= offset; + + m->top = p; + m->topsize = psize; + p->head = psize | PINUSE_BIT; + /* set size of fake trailing chunk holding overhead space only once */ + chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; + m->trim_check = mparams.trim_threshold; /* reset on each update */ +} + +/* Initialize bins for a new mstate that is otherwise zeroed out */ +static void init_bins(mstate m) { + /* Establish circular links for smallbins */ + bindex_t i; + for (i = 0; i < NSMALLBINS; ++i) { + sbinptr bin = smallbin_at(m,i); + bin->fd = bin->bk = bin; + } +} + +#if PROCEED_ON_ERROR + +/* default corruption action */ +static void reset_on_error(mstate m) { + int i; + ++malloc_corruption_error_count; + /* Reinitialize fields to forget about all memory */ + m->smallbins = m->treebins = 0; + m->dvsize = m->topsize = 0; + m->seg.base = 0; + m->seg.size = 0; + m->seg.next = 0; + m->top = m->dv = 0; + for (i = 0; i < NTREEBINS; ++i) + *treebin_at(m, i) = 0; + init_bins(m); +} +#endif /* PROCEED_ON_ERROR */ + +/* Allocate chunk and prepend remainder with chunk in successor base. */ +static void* prepend_alloc(mstate m, char* newbase, char* oldbase, + size_t nb) { + mchunkptr p = align_as_chunk(newbase); + mchunkptr oldfirst = align_as_chunk(oldbase); + size_t psize = (char*)oldfirst - (char*)p; + mchunkptr q = chunk_plus_offset(p, nb); + size_t qsize = psize - nb; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + + assert((char*)oldfirst > (char*)q); + assert(pinuse(oldfirst)); + assert(qsize >= MIN_CHUNK_SIZE); + + /* consolidate remainder with first chunk of old base */ + if (oldfirst == m->top) { + size_t tsize = m->topsize += qsize; + m->top = q; + q->head = tsize | PINUSE_BIT; + check_top_chunk(m, q); + } + else if (oldfirst == m->dv) { + size_t dsize = m->dvsize += qsize; + m->dv = q; + set_size_and_pinuse_of_free_chunk(q, dsize); + } + else { + if (!cinuse(oldfirst)) { + size_t nsize = chunksize(oldfirst); + unlink_chunk(m, oldfirst, nsize); + oldfirst = chunk_plus_offset(oldfirst, nsize); + qsize += nsize; + } + set_free_with_pinuse(q, qsize, oldfirst); + insert_chunk(m, q, qsize); + check_free_chunk(m, q); + } + + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); +} + + +/* Add a segment to hold a new noncontiguous region */ +static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { + /* Determine locations and sizes of segment, fenceposts, old top */ + char* old_top = (char*)m->top; + msegmentptr oldsp = segment_holding(m, old_top); + char* old_end = oldsp->base + oldsp->size; + size_t ssize = pad_request(sizeof(struct malloc_segment)); + char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + size_t offset = align_offset(chunk2mem(rawsp)); + char* asp = rawsp + offset; + char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp; + mchunkptr sp = (mchunkptr)csp; + msegmentptr ss = (msegmentptr)(chunk2mem(sp)); + mchunkptr tnext = chunk_plus_offset(sp, ssize); + mchunkptr p = tnext; + int nfences = 0; + + /* reset top to new space */ + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + + /* Set up segment record */ + assert(is_aligned(ss)); + set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); + *ss = m->seg; /* Push current record */ + m->seg.base = tbase; + m->seg.size = tsize; + set_segment_flags(&m->seg, mmapped); + m->seg.next = ss; + + /* Insert trailing fenceposts */ + for (;;) { + mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); + p->head = FENCEPOST_HEAD; + ++nfences; + if ((char*)(&(nextp->head)) < old_end) + p = nextp; + else + break; + } + assert(nfences >= 2); + + /* Insert the rest of old top into a bin as an ordinary free chunk */ + if (csp != old_top) { + mchunkptr q = (mchunkptr)old_top; + size_t psize = csp - old_top; + mchunkptr tn = chunk_plus_offset(q, psize); + set_free_with_pinuse(q, psize, tn); + insert_chunk(m, q, psize); + } + + check_top_chunk(m, m->top); +} + +/* -------------------------- System allocation -------------------------- */ + +/* Get memory from system using MORECORE or MMAP */ +static void* sys_alloc(mstate m, size_t nb) { + char* tbase = CMFAIL; + size_t tsize = 0; + flag_t mmap_flag = 0; + + init_mparams(); + + /* Directly map large chunks */ + if (use_mmap(m) && nb >= mparams.mmap_threshold) { + void* mem = mmap_alloc(m, nb); + if (mem != 0) + return mem; + } + + /* + Try getting memory in any of three ways (in most-preferred to + least-preferred order): + 1. A call to MORECORE that can normally contiguously extend memory. + (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or + or main space is mmapped or a previous contiguous call failed) + 2. A call to MMAP new space (disabled if not HAVE_MMAP). + Note that under the default settings, if MORECORE is unable to + fulfill a request, and HAVE_MMAP is true, then mmap is + used as a noncontiguous system allocator. This is a useful backup + strategy for systems with holes in address spaces -- in this case + sbrk cannot contiguously expand the heap, but mmap may be able to + find space. + 3. A call to MORECORE that cannot usually contiguously extend memory. + (disabled if not HAVE_MORECORE) + */ + + if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) { + char* br = CMFAIL; + msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top); + size_t asize = 0; + ACQUIRE_MORECORE_LOCK(); + + if (ss == 0) { /* First time through or recovery */ + char* base = (char*)CALL_MORECORE(0); + if (base != CMFAIL) { + asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE); + /* Adjust to end on a page boundary */ + if (!is_page_aligned(base)) + asize += (page_align((size_t)base) - (size_t)base); + /* Can't call MORECORE if size is negative when treated as signed */ + if (asize < HALF_MAX_SIZE_T && + (br = (char*)(CALL_MORECORE(asize))) == base) { + tbase = base; + tsize = asize; + } + } + } + else { + /* Subtract out existing available top space from MORECORE request. */ + asize = granularity_align(nb - m->topsize + TOP_FOOT_SIZE + SIZE_T_ONE); + /* Use mem here only if it did continuously extend old space */ + if (asize < HALF_MAX_SIZE_T && + (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) { + tbase = br; + tsize = asize; + } + } + + if (tbase == CMFAIL) { /* Cope with partial failure */ + if (br != CMFAIL) { /* Try to use/extend the space we did get */ + if (asize < HALF_MAX_SIZE_T && + asize < nb + TOP_FOOT_SIZE + SIZE_T_ONE) { + size_t esize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE - asize); + if (esize < HALF_MAX_SIZE_T) { + char* end = (char*)CALL_MORECORE(esize); + if (end != CMFAIL) + asize += esize; + else { /* Can't use; try to release */ + (void)CALL_MORECORE(-asize); + br = CMFAIL; + } + } + } + } + if (br != CMFAIL) { /* Use the space we did get */ + tbase = br; + tsize = asize; + } + else + disable_contiguous(m); /* Don't try contiguous path in the future */ + } + + RELEASE_MORECORE_LOCK(); + } + + if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */ + size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE; + size_t rsize = granularity_align(req); + if (rsize > nb) { /* Fail if wraps around zero */ + char* mp = (char*)(CALL_MMAP(rsize)); + if (mp != CMFAIL) { + tbase = mp; + tsize = rsize; + mmap_flag = IS_MMAPPED_BIT; + } + } + } + + if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */ + size_t asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE); + if (asize < HALF_MAX_SIZE_T) { + char* br = CMFAIL; + char* end = CMFAIL; + ACQUIRE_MORECORE_LOCK(); + br = (char*)(CALL_MORECORE(asize)); + end = (char*)(CALL_MORECORE(0)); + RELEASE_MORECORE_LOCK(); + if (br != CMFAIL && end != CMFAIL && br < end) { + size_t ssize = end - br; + if (ssize > nb + TOP_FOOT_SIZE) { + tbase = br; + tsize = ssize; + } + } + } + } + + if (tbase != CMFAIL) { + + if ((m->footprint += tsize) > m->max_footprint) + m->max_footprint = m->footprint; + + if (!is_initialized(m)) { /* first-time initialization */ + m->seg.base = m->least_addr = tbase; + m->seg.size = tsize; + set_segment_flags(&m->seg, mmap_flag); + m->magic = mparams.magic; + init_bins(m); + if (is_global(m)) + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + else { + /* Offset top by embedded malloc_state */ + mchunkptr mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE); + } + } + + else { + /* Try to merge with an existing segment */ + msegmentptr sp = &m->seg; + while (sp != 0 && tbase != sp->base + sp->size) + sp = sp->next; + if (sp != 0 && + !is_extern_segment(sp) && + check_segment_merge(sp, tbase, tsize) && + (get_segment_flags(sp) & IS_MMAPPED_BIT) == mmap_flag && + segment_holds(sp, m->top)) { /* append */ + sp->size += tsize; + init_top(m, m->top, m->topsize + tsize); + } + else { + if (tbase < m->least_addr) + m->least_addr = tbase; + sp = &m->seg; + while (sp != 0 && sp->base != tbase + tsize) + sp = sp->next; + if (sp != 0 && + !is_extern_segment(sp) && + check_segment_merge(sp, tbase, tsize) && + (get_segment_flags(sp) & IS_MMAPPED_BIT) == mmap_flag) { + char* oldbase = sp->base; + sp->base = tbase; + sp->size += tsize; + return prepend_alloc(m, tbase, oldbase, nb); + } + else + add_segment(m, tbase, tsize, mmap_flag); + } + } + + if (nb < m->topsize) { /* Allocate from new or extended top space */ + size_t rsize = m->topsize -= nb; + mchunkptr p = m->top; + mchunkptr r = m->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + check_top_chunk(m, m->top); + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); + } + } + + MALLOC_FAILURE_ACTION; + return 0; +} + +/* ----------------------- system deallocation -------------------------- */ + +/* Unmap and unlink any mmapped segments that don't contain used chunks */ +static size_t release_unused_segments(mstate m) { + size_t released = 0; + msegmentptr pred = &m->seg; + msegmentptr sp = pred->next; + while (sp != 0) { + char* base = sp->base; + size_t size = sp->size; + msegmentptr next = sp->next; + if (is_mmapped_segment(sp) && !is_extern_segment(sp)) { + mchunkptr p = align_as_chunk(base); + size_t psize = chunksize(p); + /* Can unmap if first chunk holds entire segment and not pinned */ + if (!cinuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) { + tchunkptr tp = (tchunkptr)p; + assert(segment_holds(sp, (char*)sp)); + if (p == m->dv) { + m->dv = 0; + m->dvsize = 0; + } + else { + unlink_large_chunk(m, tp); + } + if (CALL_MUNMAP(base, size) == 0) { + released += size; + m->footprint -= size; + /* unlink obsoleted record */ + sp = pred; + sp->next = next; + } + else { /* back out if cannot unmap */ + insert_large_chunk(m, tp, psize); + } + } + } + pred = sp; + sp = next; + } + return released; +} + +static int sys_trim(mstate m, size_t pad) { + size_t released = 0; + if (pad < MAX_REQUEST && is_initialized(m)) { + pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ + + if (m->topsize > pad) { + /* Shrink top space in granularity-size units, keeping at least one */ + size_t unit = mparams.granularity; + size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - + SIZE_T_ONE) * unit; + msegmentptr sp = segment_holding(m, (char*)m->top); + + if (!is_extern_segment(sp)) { + if (is_mmapped_segment(sp)) { + if (HAVE_MMAP && + sp->size >= extra && + !has_segment_link(m, sp)) { /* can't shrink if pinned */ + size_t newsize = sp->size - extra; + /* Prefer mremap, fall back to munmap */ + if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || + (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { + released = extra; + } + } + } + else if (HAVE_MORECORE) { + if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ + extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; + ACQUIRE_MORECORE_LOCK(); + { + /* Make sure end of memory is where we last set it. */ + char* old_br = (char*)(CALL_MORECORE(0)); + if (old_br == sp->base + sp->size) { + char* rel_br = (char*)(CALL_MORECORE(-extra)); + char* new_br = (char*)(CALL_MORECORE(0)); + if (rel_br != CMFAIL && new_br < old_br) + released = old_br - new_br; + } + } + RELEASE_MORECORE_LOCK(); + } + } + + if (released != 0) { + sp->size -= released; + m->footprint -= released; + init_top(m, m->top, m->topsize - released); + check_top_chunk(m, m->top); + } + } + + /* Unmap any unused mmapped segments */ + if (HAVE_MMAP) + released += release_unused_segments(m); + + /* On failure, disable autotrim to avoid repeated failed future calls */ + if (released == 0) + m->trim_check = MAX_SIZE_T; + } + + return (released != 0)? 1 : 0; +} + +/* ---------------------------- malloc support --------------------------- */ + +/* allocate a large request from the best fitting chunk in a treebin */ +static void* tmalloc_large(mstate m, size_t nb) { + tchunkptr v = 0; + size_t rsize = -nb; /* Unsigned negation */ + tchunkptr t; + bindex_t idx; + compute_tree_index(nb, idx); + + if ((t = *treebin_at(m, idx)) != 0) { + /* Traverse tree for this bin looking for node with size == nb */ + size_t sizebits = nb << leftshift_for_tree_index(idx); + tchunkptr rst = 0; /* The deepest untaken right subtree */ + for (;;) { + tchunkptr rt; + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + v = t; + if ((rsize = trem) == 0) + break; + } + rt = t->child[1]; + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + if (rt != 0 && rt != t) + rst = rt; + if (t == 0) { + t = rst; /* set t to least subtree holding sizes > nb */ + break; + } + sizebits <<= 1; + } + } + + if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */ + binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap; + if (leftbits != 0) { + bindex_t i; + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + t = *treebin_at(m, i); + } + } + + while (t != 0) { /* find smallest of tree or subtree */ + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + t = leftmost_child(t); + } + + /* If dv is a better fit, return 0 so malloc will use it */ + if (v != 0 && rsize < (size_t)(m->dvsize - nb)) { + if (RTCHECK(ok_address(m, v))) { /* split */ + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + if (RTCHECK(ok_next(v, r))) { + unlink_large_chunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(m, v, (rsize + nb)); + else { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + insert_chunk(m, r, rsize); + } + return chunk2mem(v); + } + } + CORRUPTION_ERROR_ACTION(m); + } + return 0; +} + +/* allocate a small request from the best fitting chunk in a treebin */ +static void* tmalloc_small(mstate m, size_t nb) { + tchunkptr t, v; + size_t rsize; + bindex_t i; + binmap_t leastbit = least_bit(m->treemap); + compute_bit2idx(leastbit, i); + + v = t = *treebin_at(m, i); + rsize = chunksize(t) - nb; + + while ((t = leftmost_child(t)) != 0) { + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + } + + if (RTCHECK(ok_address(m, v))) { + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + if (RTCHECK(ok_next(v, r))) { + unlink_large_chunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(m, v, (rsize + nb)); + else { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(m, r, rsize); + } + return chunk2mem(v); + } + } + + CORRUPTION_ERROR_ACTION(m); + return 0; +} + +/* --------------------------- realloc support --------------------------- */ + +static void* internal_realloc(mstate m, void* oldmem, size_t bytes) { + if (bytes >= MAX_REQUEST) { + MALLOC_FAILURE_ACTION; + return 0; + } + if (!PREACTION(m)) { + mchunkptr oldp = mem2chunk(oldmem); + size_t oldsize = chunksize(oldp); + mchunkptr next = chunk_plus_offset(oldp, oldsize); + mchunkptr newp = 0; + void* extra = 0; + + /* Try to either shrink or extend into top. Else malloc-copy-free */ + + if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) && + ok_next(oldp, next) && ok_pinuse(next))) { + size_t nb = request2size(bytes); + if (is_mmapped(oldp)) + newp = mmap_resize(m, oldp, nb); + else if (oldsize >= nb) { /* already big enough */ + size_t rsize = oldsize - nb; + newp = oldp; + if (rsize >= MIN_CHUNK_SIZE) { + mchunkptr remainder = chunk_plus_offset(newp, nb); + set_inuse(m, newp, nb); + set_inuse(m, remainder, rsize); + extra = chunk2mem(remainder); + } + } + else if (next == m->top && oldsize + m->topsize > nb) { + /* Expand into top */ + size_t newsize = oldsize + m->topsize; + size_t newtopsize = newsize - nb; + mchunkptr newtop = chunk_plus_offset(oldp, nb); + set_inuse(m, oldp, nb); + newtop->head = newtopsize |PINUSE_BIT; + m->top = newtop; + m->topsize = newtopsize; + newp = oldp; + } + } + else { + USAGE_ERROR_ACTION(m, oldmem); + POSTACTION(m); + return 0; + } + + POSTACTION(m); + + if (newp != 0) { + if (extra != 0) { + internal_free(m, extra); + } + check_inuse_chunk(m, newp); + return chunk2mem(newp); + } + else { + void* newmem = internal_malloc(m, bytes); + if (newmem != 0) { + size_t oc = oldsize - overhead_for(oldp); + memcpy(newmem, oldmem, (oc < bytes)? oc : bytes); + internal_free(m, oldmem); + } + return newmem; + } + } + return 0; +} + +/* --------------------------- memalign support -------------------------- */ + +static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { + if (alignment <= MALLOC_ALIGNMENT) /* Can just use malloc */ + return internal_malloc(m, bytes); + if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ + alignment = MIN_CHUNK_SIZE; + if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */ + size_t a = MALLOC_ALIGNMENT << 1; + while (a < alignment) a <<= 1; + alignment = a; + } + + if (bytes >= MAX_REQUEST - alignment) { + if (m != 0) { /* Test isn't needed but avoids compiler warning */ + MALLOC_FAILURE_ACTION; + } + } + else { + size_t nb = request2size(bytes); + size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; + char* mem = (char*)internal_malloc(m, req); + if (mem != 0) { + void* leader = 0; + void* trailer = 0; + mchunkptr p = mem2chunk(mem); + + if (PREACTION(m)) return 0; + if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */ + /* + Find an aligned spot inside chunk. Since we need to give + back leading space in a chunk of at least MIN_CHUNK_SIZE, if + the first calculation places us at a spot with less than + MIN_CHUNK_SIZE leader, we can move to the next aligned spot. + We've allocated enough total room so that this is always + possible. + */ + char* br = (char*)mem2chunk((size_t)(((size_t)(mem + + alignment - + SIZE_T_ONE)) & + -alignment)); + char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)? + br : br+alignment; + mchunkptr newp = (mchunkptr)pos; + size_t leadsize = pos - (char*)(p); + size_t newsize = chunksize(p) - leadsize; + + if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */ + newp->prev_foot = p->prev_foot + leadsize; + newp->head = (newsize|CINUSE_BIT); + } + else { /* Otherwise, give back leader, use the rest */ + set_inuse(m, newp, newsize); + set_inuse(m, p, leadsize); + leader = chunk2mem(p); + } + p = newp; + } + + /* Give back spare room at the end */ + if (!is_mmapped(p)) { + size_t size = chunksize(p); + if (size > nb + MIN_CHUNK_SIZE) { + size_t remainder_size = size - nb; + mchunkptr remainder = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, remainder, remainder_size); + trailer = chunk2mem(remainder); + } + } + + assert (chunksize(p) >= nb); + assert((((size_t)(chunk2mem(p))) % alignment) == 0); + check_inuse_chunk(m, p); + POSTACTION(m); + if (leader != 0) { + internal_free(m, leader); + } + if (trailer != 0) { + internal_free(m, trailer); + } + return chunk2mem(p); + } + } + return 0; +} + +/* ------------------------ comalloc/coalloc support --------------------- */ + +static void** ialloc(mstate m, + size_t n_elements, + size_t* sizes, + int opts, + void* chunks[]) { + /* + This provides common support for independent_X routines, handling + all of the combinations that can result. + + The opts arg has: + bit 0 set if all elements are same size (using sizes[0]) + bit 1 set if elements should be zeroed + */ + + size_t element_size; /* chunksize of each element, if all same */ + size_t contents_size; /* total size of elements */ + size_t array_size; /* request size of pointer array */ + void* mem; /* malloced aggregate space */ + mchunkptr p; /* corresponding chunk */ + size_t remainder_size; /* remaining bytes while splitting */ + void** marray; /* either "chunks" or malloced ptr array */ + mchunkptr array_chunk; /* chunk for malloced ptr array */ + flag_t was_enabled; /* to disable mmap */ + size_t size; + size_t i; + + /* compute array length, if needed */ + if (chunks != 0) { + if (n_elements == 0) + return chunks; /* nothing to do */ + marray = chunks; + array_size = 0; + } + else { + /* if empty req, must still return chunk representing empty array */ + if (n_elements == 0) + return (void**)internal_malloc(m, 0); + marray = 0; + array_size = request2size(n_elements * (sizeof(void*))); + } + + /* compute total element size */ + if (opts & 0x1) { /* all-same-size */ + element_size = request2size(*sizes); + contents_size = n_elements * element_size; + } + else { /* add up all the sizes */ + element_size = 0; + contents_size = 0; + for (i = 0; i != n_elements; ++i) + contents_size += request2size(sizes[i]); + } + + size = contents_size + array_size; + + /* + Allocate the aggregate chunk. First disable direct-mmapping so + malloc won't use it, since we would not be able to later + free/realloc space internal to a segregated mmap region. + */ + was_enabled = use_mmap(m); + disable_mmap(m); + mem = internal_malloc(m, size - CHUNK_OVERHEAD); + if (was_enabled) + enable_mmap(m); + if (mem == 0) + return 0; + + if (PREACTION(m)) return 0; + p = mem2chunk(mem); + remainder_size = chunksize(p); + + assert(!is_mmapped(p)); + + if (opts & 0x2) { /* optionally clear the elements */ + memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size); + } + + /* If not provided, allocate the pointer array as final part of chunk */ + if (marray == 0) { + size_t array_chunk_size; + array_chunk = chunk_plus_offset(p, contents_size); + array_chunk_size = remainder_size - contents_size; + marray = (void**) (chunk2mem(array_chunk)); + set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size); + remainder_size = contents_size; + } + + /* split out elements */ + for (i = 0; ; ++i) { + marray[i] = chunk2mem(p); + if (i != n_elements-1) { + if (element_size != 0) + size = element_size; + else + size = request2size(sizes[i]); + remainder_size -= size; + set_size_and_pinuse_of_inuse_chunk(m, p, size); + p = chunk_plus_offset(p, size); + } + else { /* the final element absorbs any overallocation slop */ + set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); + break; + } + } + +#if DEBUG + if (marray != chunks) { + /* final element must have exactly exhausted chunk */ + if (element_size != 0) { + assert(remainder_size == element_size); + } + else { + assert(remainder_size == request2size(sizes[i])); + } + check_inuse_chunk(m, mem2chunk(marray)); + } + for (i = 0; i != n_elements; ++i) + check_inuse_chunk(m, mem2chunk(marray[i])); + +#endif /* DEBUG */ + + POSTACTION(m); + return marray; +} + + +/* -------------------------- public routines ---------------------------- */ + +#if !ONLY_MSPACES + +void* dlmalloc(size_t bytes) { + /* + Basic algorithm: + If a small request (< 256 bytes minus per-chunk overhead): + 1. If one exists, use a remainderless chunk in associated smallbin. + (Remainderless means that there are too few excess bytes to + represent as a chunk.) + 2. If it is big enough, use the dv chunk, which is normally the + chunk adjacent to the one used for the most recent small request. + 3. If one exists, split the smallest available chunk in a bin, + saving remainder in dv. + 4. If it is big enough, use the top chunk. + 5. If available, get memory from system and use it + Otherwise, for a large request: + 1. Find the smallest available binned chunk that fits, and use it + if it is better fitting than dv chunk, splitting if necessary. + 2. If better fitting than any binned chunk, use the dv chunk. + 3. If it is big enough, use the top chunk. + 4. If request size >= mmap threshold, try to directly mmap this chunk. + 5. If available, get memory from system and use it + + The ugly goto's here ensure that postaction occurs along all paths. + */ + + if (!PREACTION(gm)) { + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = gm->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(gm, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(gm, b, p, idx); + set_inuse_and_pinuse(gm, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb > gm->dvsize) { + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(gm, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(gm, b, p, i); + rsize = small_index2size(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(gm, p, small_index2size(i)); + else { + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(gm, r, rsize); + } + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else { + nb = pad_request(bytes); + if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + + if (nb <= gm->dvsize) { + size_t rsize = gm->dvsize - nb; + mchunkptr p = gm->dv; + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + mchunkptr r = gm->dv = chunk_plus_offset(p, nb); + gm->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + } + else { /* exhaust dv */ + size_t dvs = gm->dvsize; + gm->dvsize = 0; + gm->dv = 0; + set_inuse_and_pinuse(gm, p, dvs); + } + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb < gm->topsize) { /* Split top */ + size_t rsize = gm->topsize -= nb; + mchunkptr p = gm->top; + mchunkptr r = gm->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + mem = chunk2mem(p); + check_top_chunk(gm, gm->top); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + mem = sys_alloc(gm, nb); + + postaction: + POSTACTION(gm); + return mem; + } + + return 0; +} + +void dlfree(void* mem) { + /* + Consolidate freed chunks with preceding or succeeding bordering + free chunks, if they exist, and then place in a bin. Intermixed + with special cases for top, dv, mmapped chunks, and usage errors. + */ + + if (mem != 0) { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } +#else /* FOOTERS */ +#define fm gm +#endif /* FOOTERS */ + if (!PREACTION(fm)) { + check_inuse_chunk(fm, p); + if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + size_t prevsize = p->prev_foot; + if ((prevsize & IS_MMAPPED_BIT) != 0) { + prevsize &= ~IS_MMAPPED_BIT; + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + fm->footprint -= psize; + goto postaction; + } + else { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (p != fm->dv) { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + goto erroraction; + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == fm->top) { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + if (p == fm->dv) { + fm->dv = 0; + fm->dvsize = 0; + } + if (should_trim(fm, tsize)) + sys_trim(fm, 0); + goto postaction; + } + else if (next == fm->dv) { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == fm->dv) { + fm->dvsize = psize; + goto postaction; + } + } + } + else + set_free_with_pinuse(p, psize, next); + insert_chunk(fm, p, psize); + check_free_chunk(fm, p); + goto postaction; + } + } + erroraction: + USAGE_ERROR_ACTION(fm, p); + postaction: + POSTACTION(fm); + } + } +#if !FOOTERS +#undef fm +#endif /* FOOTERS */ +} + +void* dlcalloc(size_t n_elements, size_t elem_size) { + void* mem; + size_t req = 0; + if (n_elements != 0) { + req = n_elements * elem_size; + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + mem = dlmalloc(req); + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) + memset(mem, 0, req); + return mem; +} + +void* dlrealloc(void* oldmem, size_t bytes) { + if (oldmem == 0) + return dlmalloc(bytes); +#ifdef REALLOC_ZERO_BYTES_FREES + if (bytes == 0) { + dlfree(oldmem); + return 0; + } +#endif /* REALLOC_ZERO_BYTES_FREES */ + else { +#if ! FOOTERS + mstate m = gm; +#else /* FOOTERS */ + mstate m = get_mstate_for(mem2chunk(oldmem)); + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } +#endif /* FOOTERS */ + return internal_realloc(m, oldmem, bytes); + } +} + +void* dlmemalign(size_t alignment, size_t bytes) { + return internal_memalign(gm, alignment, bytes); +} + +void** dlindependent_calloc(size_t n_elements, size_t elem_size, + void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ + return ialloc(gm, n_elements, &sz, 3, chunks); +} + +void** dlindependent_comalloc(size_t n_elements, size_t sizes[], + void* chunks[]) { + return ialloc(gm, n_elements, sizes, 0, chunks); +} + +void* dlvalloc(size_t bytes) { + size_t pagesz; + init_mparams(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, bytes); +} + +void* dlpvalloc(size_t bytes) { + size_t pagesz; + init_mparams(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); +} + +int dlmalloc_trim(size_t pad) { + int result = 0; + if (!PREACTION(gm)) { + result = sys_trim(gm, pad); + POSTACTION(gm); + } + return result; +} + +size_t dlmalloc_footprint(void) { + return gm->footprint; +} + +size_t dlmalloc_max_footprint(void) { + return gm->max_footprint; +} + +#if !NO_MALLINFO +struct mallinfo dlmallinfo(void) { + return internal_mallinfo(gm); +} +#endif /* NO_MALLINFO */ + +void dlmalloc_stats() { + internal_malloc_stats(gm); +} + +size_t dlmalloc_usable_size(void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + if (cinuse(p)) + return chunksize(p) - overhead_for(p); + } + return 0; +} + +int dlmallopt(int param_number, int value) { + return change_mparam(param_number, value); +} + +#endif /* !ONLY_MSPACES */ + +/* ----------------------------- user mspaces ---------------------------- */ + +#if MSPACES + +static mstate init_user_mstate(char* tbase, size_t tsize) { + size_t msize = pad_request(sizeof(struct malloc_state)); + mchunkptr mn; + mchunkptr msp = align_as_chunk(tbase); + mstate m = (mstate)(chunk2mem(msp)); + memset(m, 0, msize); + INITIAL_LOCK(&m->mutex); + msp->head = (msize|PINUSE_BIT|CINUSE_BIT); + m->seg.base = m->least_addr = tbase; + m->seg.size = m->footprint = m->max_footprint = tsize; + m->magic = mparams.magic; + m->mflags = mparams.default_mflags; + disable_contiguous(m); + init_bins(m); + mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE); + check_top_chunk(m, m->top); + return m; +} + +mspace create_mspace(size_t capacity, int locked) { + mstate m = 0; + size_t msize = pad_request(sizeof(struct malloc_state)); + init_mparams(); /* Ensure pagesize etc initialized */ + + if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { + size_t rs = ((capacity == 0)? mparams.granularity : + (capacity + TOP_FOOT_SIZE + msize)); + size_t tsize = granularity_align(rs); + char* tbase = (char*)(CALL_MMAP(tsize)); + if (tbase != CMFAIL) { + m = init_user_mstate(tbase, tsize); + set_segment_flags(&m->seg, IS_MMAPPED_BIT); + set_lock(m, locked); + } + } + return (mspace)m; +} + +mspace create_mspace_with_base(void* base, size_t capacity, int locked) { + mstate m = 0; + size_t msize = pad_request(sizeof(struct malloc_state)); + init_mparams(); /* Ensure pagesize etc initialized */ + + if (capacity > msize + TOP_FOOT_SIZE && + capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { + m = init_user_mstate((char*)base, capacity); + set_segment_flags(&m->seg, EXTERN_BIT); + set_lock(m, locked); + } + return (mspace)m; +} + +size_t destroy_mspace(mspace msp) { + size_t freed = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + msegmentptr sp = &ms->seg; + while (sp != 0) { + char* base = sp->base; + size_t size = sp->size; + flag_t flag = get_segment_flags(sp); + sp = sp->next; + if ((flag & IS_MMAPPED_BIT) && !(flag & EXTERN_BIT) && + CALL_MUNMAP(base, size) == 0) + freed += size; + } + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return freed; +} + +/* + mspace versions of routines are near-clones of the global + versions. This is not so nice but better than the alternatives. +*/ + + +void* mspace_malloc(mspace msp, size_t bytes) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (!PREACTION(ms)) { + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = ms->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(ms, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(ms, b, p, idx); + set_inuse_and_pinuse(ms, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb > ms->dvsize) { + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(ms, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(ms, b, p, i); + rsize = small_index2size(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(ms, p, small_index2size(i)); + else { + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(ms, r, rsize); + } + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else { + nb = pad_request(bytes); + if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + + if (nb <= ms->dvsize) { + size_t rsize = ms->dvsize - nb; + mchunkptr p = ms->dv; + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + mchunkptr r = ms->dv = chunk_plus_offset(p, nb); + ms->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + } + else { /* exhaust dv */ + size_t dvs = ms->dvsize; + ms->dvsize = 0; + ms->dv = 0; + set_inuse_and_pinuse(ms, p, dvs); + } + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb < ms->topsize) { /* Split top */ + size_t rsize = ms->topsize -= nb; + mchunkptr p = ms->top; + mchunkptr r = ms->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + mem = chunk2mem(p); + check_top_chunk(ms, ms->top); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + mem = sys_alloc(ms, nb); + + postaction: + POSTACTION(ms); + return mem; + } + + return 0; +} + +void mspace_free(mspace msp, void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); +#else /* FOOTERS */ + mstate fm = (mstate)msp; +#endif /* FOOTERS */ + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } + if (!PREACTION(fm)) { + check_inuse_chunk(fm, p); + if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + size_t prevsize = p->prev_foot; + if ((prevsize & IS_MMAPPED_BIT) != 0) { + prevsize &= ~IS_MMAPPED_BIT; + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + fm->footprint -= psize; + goto postaction; + } + else { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (p != fm->dv) { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + goto erroraction; + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == fm->top) { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + if (p == fm->dv) { + fm->dv = 0; + fm->dvsize = 0; + } + if (should_trim(fm, tsize)) + sys_trim(fm, 0); + goto postaction; + } + else if (next == fm->dv) { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == fm->dv) { + fm->dvsize = psize; + goto postaction; + } + } + } + else + set_free_with_pinuse(p, psize, next); + insert_chunk(fm, p, psize); + check_free_chunk(fm, p); + goto postaction; + } + } + erroraction: + USAGE_ERROR_ACTION(fm, p); + postaction: + POSTACTION(fm); + } + } +} + +void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) { + void* mem; + size_t req = 0; + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (n_elements != 0) { + req = n_elements * elem_size; + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + mem = internal_malloc(ms, req); + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) + memset(mem, 0, req); + return mem; +} + +void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) { + if (oldmem == 0) + return mspace_malloc(msp, bytes); +#ifdef REALLOC_ZERO_BYTES_FREES + if (bytes == 0) { + mspace_free(msp, oldmem); + return 0; + } +#endif /* REALLOC_ZERO_BYTES_FREES */ + else { +#if FOOTERS + mchunkptr p = mem2chunk(oldmem); + mstate ms = get_mstate_for(p); +#else /* FOOTERS */ + mstate ms = (mstate)msp; +#endif /* FOOTERS */ + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return internal_realloc(ms, oldmem, bytes); + } +} + +void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return internal_memalign(ms, alignment, bytes); +} + +void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return ialloc(ms, n_elements, &sz, 3, chunks); +} + +void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return ialloc(ms, n_elements, sizes, 0, chunks); +} + +int mspace_trim(mspace msp, size_t pad) { + int result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + if (!PREACTION(ms)) { + result = sys_trim(ms, pad); + POSTACTION(ms); + } + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + +void mspace_malloc_stats(mspace msp) { + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + internal_malloc_stats(ms); + } + else { + USAGE_ERROR_ACTION(ms,ms); + } +} + +size_t mspace_footprint(mspace msp) { + size_t result; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + result = ms->footprint; + } + USAGE_ERROR_ACTION(ms,ms); + return result; +} + + +size_t mspace_max_footprint(mspace msp) { + size_t result; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + result = ms->max_footprint; + } + USAGE_ERROR_ACTION(ms,ms); + return result; +} + + +#if !NO_MALLINFO +struct mallinfo mspace_mallinfo(mspace msp) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + } + return internal_mallinfo(ms); +} +#endif /* NO_MALLINFO */ + +int mspace_mallopt(int param_number, int value) { + return change_mparam(param_number, value); +} + +#endif /* MSPACES */ + +/* -------------------- Alternative MORECORE functions ------------------- */ + +/* + Guidelines for creating a custom version of MORECORE: + + * For best performance, MORECORE should allocate in multiples of pagesize. + * MORECORE may allocate more memory than requested. (Or even less, + but this will usually result in a malloc failure.) + * MORECORE must not allocate memory when given argument zero, but + instead return one past the end address of memory from previous + nonzero call. + * For best performance, consecutive calls to MORECORE with positive + arguments should return increasing addresses, indicating that + space has been contiguously extended. + * Even though consecutive calls to MORECORE need not return contiguous + addresses, it must be OK for malloc'ed chunks to span multiple + regions in those cases where they do happen to be contiguous. + * MORECORE need not handle negative arguments -- it may instead + just return MFAIL when given negative arguments. + Negative arguments are always multiples of pagesize. MORECORE + must not misinterpret negative args as large positive unsigned + args. You can suppress all such calls from even occurring by defining + MORECORE_CANNOT_TRIM, + + As an example alternative MORECORE, here is a custom allocator + kindly contributed for pre-OSX macOS. It uses virtually but not + necessarily physically contiguous non-paged memory (locked in, + present and won't get swapped out). You can use it by uncommenting + this section, adding some #includes, and setting up the appropriate + defines above: + + #define MORECORE osMoreCore + + There is also a shutdown routine that should somehow be called for + cleanup upon program exit. + + #define MAX_POOL_ENTRIES 100 + #define MINIMUM_MORECORE_SIZE (64 * 1024U) + static int next_os_pool; + void *our_os_pools[MAX_POOL_ENTRIES]; + + void *osMoreCore(int size) + { + void *ptr = 0; + static void *sbrk_top = 0; + + if (size > 0) + { + if (size < MINIMUM_MORECORE_SIZE) + size = MINIMUM_MORECORE_SIZE; + if (CurrentExecutionLevel() == kTaskLevel) + ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); + if (ptr == 0) + { + return (void *) MFAIL; + } + // save ptrs so they can be freed during cleanup + our_os_pools[next_os_pool] = ptr; + next_os_pool++; + ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); + sbrk_top = (char *) ptr + size; + return ptr; + } + else if (size < 0) + { + // we don't currently support shrink behavior + return (void *) MFAIL; + } + else + { + return sbrk_top; + } + } + + // cleanup any allocated memory pools + // called as last thing before shutting down driver + + void osCleanupMem(void) + { + void **ptr; + + for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) + if (*ptr) + { + PoolDeallocate(*ptr); + *ptr = 0; + } + } + +*/ + + +/* ----------------------------------------------------------------------- +History: + V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee) + * Add max_footprint functions + * Ensure all appropriate literals are size_t + * Fix conditional compilation problem for some #define settings + * Avoid concatenating segments with the one provided + in create_mspace_with_base + * Rename some variables to avoid compiler shadowing warnings + * Use explicit lock initialization. + * Better handling of sbrk interference. + * Simplify and fix segment insertion, trimming and mspace_destroy + * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x + * Thanks especially to Dennis Flanagan for help on these. + + V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee) + * Fix memalign brace error. + + V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee) + * Fix improper #endif nesting in C++ + * Add explicit casts needed for C++ + + V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee) + * Use trees for large bins + * Support mspaces + * Use segments to unify sbrk-based and mmap-based system allocation, + removing need for emulation on most platforms without sbrk. + * Default safety checks + * Optional footer checks. Thanks to William Robertson for the idea. + * Internal code refactoring + * Incorporate suggestions and platform-specific changes. + Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas, + Aaron Bachmann, Emery Berger, and others. + * Speed up non-fastbin processing enough to remove fastbins. + * Remove useless cfree() to avoid conflicts with other apps. + * Remove internal memcpy, memset. Compilers handle builtins better. + * Remove some options that no one ever used and rename others. + + V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) + * Fix malloc_state bitmap array misdeclaration + + V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee) + * Allow tuning of FIRST_SORTED_BIN_SIZE + * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte. + * Better detection and support for non-contiguousness of MORECORE. + Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger + * Bypass most of malloc if no frees. Thanks To Emery Berger. + * Fix freeing of old top non-contiguous chunk im sysmalloc. + * Raised default trim and map thresholds to 256K. + * Fix mmap-related #defines. Thanks to Lubos Lunak. + * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield. + * Branch-free bin calculation + * Default trim and mmap thresholds now 256K. + + V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) + * Introduce independent_comalloc and independent_calloc. + Thanks to Michael Pachos for motivation and help. + * Make optional .h file available + * Allow > 2GB requests on 32bit systems. + * new WIN32 sbrk, mmap, munmap, lock code from . + Thanks also to Andreas Mueller , + and Anonymous. + * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for + helping test this.) + * memalign: check alignment arg + * realloc: don't try to shift chunks backwards, since this + leads to more fragmentation in some programs and doesn't + seem to help in any others. + * Collect all cases in malloc requiring system memory into sysmalloc + * Use mmap as backup to sbrk + * Place all internal state in malloc_state + * Introduce fastbins (although similar to 2.5.1) + * Many minor tunings and cosmetic improvements + * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK + * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS + Thanks to Tony E. Bennett and others. + * Include errno.h to support default failure action. + + V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) + * return null for negative arguments + * Added Several WIN32 cleanups from Martin C. Fong + * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' + (e.g. WIN32 platforms) + * Cleanup header file inclusion for WIN32 platforms + * Cleanup code to avoid Microsoft Visual C++ compiler complaints + * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing + memory allocation routines + * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) + * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to + usage of 'assert' in non-WIN32 code + * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to + avoid infinite loop + * Always call 'fREe()' rather than 'free()' + + V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) + * Fixed ordering problem with boundary-stamping + + V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) + * Added pvalloc, as recommended by H.J. Liu + * Added 64bit pointer support mainly from Wolfram Gloger + * Added anonymously donated WIN32 sbrk emulation + * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen + * malloc_extend_top: fix mask error that caused wastage after + foreign sbrks + * Add linux mremap support code from HJ Liu + + V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) + * Integrated most documentation with the code. + * Add support for mmap, with help from + Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Use last_remainder in more cases. + * Pack bins using idea from colin@nyx10.cs.du.edu + * Use ordered bins instead of best-fit threshhold + * Eliminate block-local decls to simplify tracing and debugging. + * Support another case of realloc via move into top + * Fix error occuring when initial sbrk_base not word-aligned. + * Rely on page size for units instead of SBRK_UNIT to + avoid surprises about sbrk alignment conventions. + * Add mallinfo, mallopt. Thanks to Raymond Nijssen + (raymond@es.ele.tue.nl) for the suggestion. + * Add `pad' argument to malloc_trim and top_pad mallopt parameter. + * More precautions for cases where other routines call sbrk, + courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Added macros etc., allowing use in linux libc from + H.J. Lu (hjl@gnu.ai.mit.edu) + * Inverted this history list + + V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) + * Re-tuned and fixed to behave more nicely with V2.6.0 changes. + * Removed all preallocation code since under current scheme + the work required to undo bad preallocations exceeds + the work saved in good cases for most test programs. + * No longer use return list or unconsolidated bins since + no scheme using them consistently outperforms those that don't + given above changes. + * Use best fit for very large chunks to prevent some worst-cases. + * Added some support for debugging + + V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) + * Removed footers when chunks are in use. Thanks to + Paul Wilson (wilson@cs.texas.edu) for the suggestion. + + V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) + * Added malloc_trim, with help from Wolfram Gloger + (wmglo@Dent.MED.Uni-Muenchen.DE). + + V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) + + V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) + * realloc: try to expand in both directions + * malloc: swap order of clean-bin strategy; + * realloc: only conditionally expand backwards + * Try not to scavenge used bins + * Use bin counts as a guide to preallocation + * Occasionally bin return list chunks in first scan + * Add a few optimizations from colin@nyx10.cs.du.edu + + V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) + * faster bin computation & slightly different binning + * merged all consolidations to one part of malloc proper + (eliminating old malloc_find_space & malloc_clean_bin) + * Scan 2 returns chunks (not just 1) + * Propagate failure in realloc if malloc returns 0 + * Add stuff to allow compilation on non-ANSI compilers + from kpv@research.att.com + + V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) + * removed potential for odd address access in prev_chunk + * removed dependency on getpagesize.h + * misc cosmetics and a bit more internal documentation + * anticosmetics: mangled names in macros to evade debugger strangeness + * tested on sparc, hp-700, dec-mips, rs6000 + with gcc & native cc (hp, dec only) allowing + Detlefs & Zorn comparison study (in SIGPLAN Notices.) + + Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) + * Based loosely on libg++-1.2X malloc. (It retains some of the overall + structure of old version, but most details differ.) + +*/ diff --git a/js/src/ctypes/libffi/src/frv/eabi.S b/js/src/ctypes/libffi/src/frv/eabi.S new file mode 100644 index 0000000..379ea4b --- /dev/null +++ b/js/src/ctypes/libffi/src/frv/eabi.S @@ -0,0 +1,128 @@ +/* ----------------------------------------------------------------------- + eabi.S - Copyright (c) 2004 Anthony Green + + FR-V Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include + + .globl ffi_prep_args_EABI + + .text + .p2align 4 + .globl ffi_call_EABI + .type ffi_call_EABI, @function + + # gr8 : ffi_prep_args + # gr9 : &ecif + # gr10: cif->bytes + # gr11: fig->flags + # gr12: ecif.rvalue + # gr13: fn + +ffi_call_EABI: + addi sp, #-80, sp + sti fp, @(sp, #24) + addi sp, #24, fp + movsg lr, gr5 + + /* Make room for the new arguments. */ + /* subi sp, fp, gr10 */ + + /* Store return address and incoming args on stack. */ + sti gr5, @(fp, #8) + sti gr8, @(fp, #-4) + sti gr9, @(fp, #-8) + sti gr10, @(fp, #-12) + sti gr11, @(fp, #-16) + sti gr12, @(fp, #-20) + sti gr13, @(fp, #-24) + + sub sp, gr10, sp + + /* Call ffi_prep_args. */ + ldi @(fp, #-4), gr4 + addi sp, #0, gr8 + ldi @(fp, #-8), gr9 +#ifdef __FRV_FDPIC__ + ldd @(gr4, gr0), gr14 + calll @(gr14, gr0) +#else + calll @(gr4, gr0) +#endif + + /* ffi_prep_args returns the new stack pointer. */ + mov gr8, gr4 + + ldi @(sp, #0), gr8 + ldi @(sp, #4), gr9 + ldi @(sp, #8), gr10 + ldi @(sp, #12), gr11 + ldi @(sp, #16), gr12 + ldi @(sp, #20), gr13 + + /* Always copy the return value pointer into the hidden + parameter register. This is only strictly necessary + when we're returning an aggregate type, but it doesn't + hurt to do this all the time, and it saves a branch. */ + ldi @(fp, #-20), gr3 + + /* Use the ffi_prep_args return value for the new sp. */ + mov gr4, sp + + /* Call the target function. */ + ldi @(fp, -24), gr4 +#ifdef __FRV_FDPIC__ + ldd @(gr4, gr0), gr14 + calll @(gr14, gr0) +#else + calll @(gr4, gr0) +#endif + + /* Store the result. */ + ldi @(fp, #-16), gr10 /* fig->flags */ + ldi @(fp, #-20), gr4 /* ecif.rvalue */ + + /* Is the return value stored in two registers? */ + cmpi gr10, #8, icc0 + bne icc0, 0, .L2 + /* Yes, save them. */ + sti gr8, @(gr4, #0) + sti gr9, @(gr4, #4) + bra .L3 +.L2: + /* Is the return value a structure? */ + cmpi gr10, #-1, icc0 + beq icc0, 0, .L3 + /* No, save a 4 byte return value. */ + sti gr8, @(gr4, #0) +.L3: + + /* Restore the stack, and return. */ + ldi @(fp, 8), gr5 + ld @(fp, gr0), fp + addi sp,#80,sp + jmpl @(gr5,gr0) + .size ffi_call_EABI, .-ffi_call_EABI + diff --git a/js/src/ctypes/libffi/src/frv/ffi.c b/js/src/ctypes/libffi/src/frv/ffi.c new file mode 100644 index 0000000..5698c89 --- /dev/null +++ b/js/src/ctypes/libffi/src/frv/ffi.c @@ -0,0 +1,292 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (C) 2004 Anthony Green + Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2008 Red Hat, Inc. + + FR-V Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +void *ffi_prep_args(char *stack, extended_cif *ecif) +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + register int count = 0; + + p_argv = ecif->avalue; + argp = stack; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + (i != 0); + i--, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + + if ((*p_arg)->type == FFI_TYPE_STRUCT) + { + z = sizeof(void*); + *(void **) argp = *p_argv; + } + /* if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + if (count > 24) + { + // This is going on the stack. Turn it into a double. + *(double *) argp = (double) *(float*)(* p_argv); + z = sizeof(double); + } + else + *(void **) argp = *(void **)(* p_argv); + } */ + else if (z < sizeof(int)) + { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + } + else if (z == sizeof(int)) + { + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + } + else + { + memcpy(argp, *p_argv, z); + } + p_argv++; + argp += z; + count += z; + } + + return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8))); +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + if (cif->rtype->type == FFI_TYPE_STRUCT) + cif->flags = -1; + else + cif->flags = cif->rtype->size; + + cif->bytes = ALIGN (cif->bytes, 8); + + return FFI_OK; +} + +extern void ffi_call_EABI(void *(*)(char *, extended_cif *), + extended_cif *, + unsigned, unsigned, + unsigned *, + void (*fn)(void)); + +void ffi_call(ffi_cif *cif, + void (*fn)(void), + void *rvalue, + void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + ecif.rvalue = alloca(cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { + case FFI_EABI: + ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; + default: + FFI_ASSERT(0); + break; + } +} + +void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3, + unsigned arg4, unsigned arg5, unsigned arg6) +{ + /* This function is called by a trampoline. The trampoline stows a + pointer to the ffi_closure object in gr7. We must save this + pointer in a place that will persist while we do our work. */ + register ffi_closure *creg __asm__ ("gr7"); + ffi_closure *closure = creg; + + /* Arguments that don't fit in registers are found on the stack + at a fixed offset above the current frame pointer. */ + register char *frame_pointer __asm__ ("fp"); + char *stack_args = frame_pointer + 16; + + /* Lay the register arguments down in a continuous chunk of memory. */ + unsigned register_args[6] = + { arg1, arg2, arg3, arg4, arg5, arg6 }; + + ffi_cif *cif = closure->cif; + ffi_type **arg_types = cif->arg_types; + void **avalue = alloca (cif->nargs * sizeof(void *)); + char *ptr = (char *) register_args; + int i; + + /* Find the address of each argument. */ + for (i = 0; i < cif->nargs; i++) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = ptr + 3; + break; + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = ptr + 2; + break; + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_FLOAT: + avalue[i] = ptr; + break; + case FFI_TYPE_STRUCT: + avalue[i] = *(void**)ptr; + break; + default: + /* This is an 8-byte value. */ + avalue[i] = ptr; + ptr += 4; + break; + } + ptr += 4; + + /* If we've handled more arguments than fit in registers, + start looking at the those passed on the stack. */ + if (ptr == ((char *)register_args + (6*4))) + ptr = stack_args; + } + + /* Invoke the closure. */ + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + /* The caller allocates space for the return structure, and + passes a pointer to this space in gr3. Use this value directly + as the return value. */ + register void *return_struct_ptr __asm__("gr3"); + (closure->fun) (cif, return_struct_ptr, avalue, closure->user_data); + } + else + { + /* Allocate space for the return value and call the function. */ + long long rvalue; + (closure->fun) (cif, &rvalue, avalue, closure->user_data); + + /* Functions return 4-byte or smaller results in gr8. 8-byte + values also use gr9. We fill the both, even for small return + values, just to avoid a branch. */ + asm ("ldi @(%0, #0), gr8" : : "r" (&rvalue)); + asm ("ldi @(%0, #0), gr9" : : "r" (&((int *) &rvalue)[1])); + } +} + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc) +{ + unsigned int *tramp = (unsigned int *) &closure->tramp[0]; + unsigned long fn = (long) ffi_closure_eabi; + unsigned long cls = (long) codeloc; +#ifdef __FRV_FDPIC__ + register void *got __asm__("gr15"); +#endif + int i; + + fn = (unsigned long) ffi_closure_eabi; + +#ifdef __FRV_FDPIC__ + tramp[0] = &((unsigned int *)codeloc)[2]; + tramp[1] = got; + tramp[2] = 0x8cfc0000 + (fn & 0xffff); /* setlos lo(fn), gr6 */ + tramp[3] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7 */ + tramp[4] = 0x8cf80000 + (fn >> 16); /* sethi hi(fn), gr6 */ + tramp[5] = 0x8ef80000 + (cls >> 16); /* sethi hi(cls), gr7 */ + tramp[6] = 0x9cc86000; /* ldi @(gr6, #0), gr14 */ + tramp[7] = 0x8030e000; /* jmpl @(gr14, gr0) */ +#else + tramp[0] = 0x8cfc0000 + (fn & 0xffff); /* setlos lo(fn), gr6 */ + tramp[1] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7 */ + tramp[2] = 0x8cf80000 + (fn >> 16); /* sethi hi(fn), gr6 */ + tramp[3] = 0x8ef80000 + (cls >> 16); /* sethi hi(cls), gr7 */ + tramp[4] = 0x80300006; /* jmpl @(gr0, gr6) */ +#endif + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* Cache flushing. */ + for (i = 0; i < FFI_TRAMPOLINE_SIZE; i++) + __asm__ volatile ("dcf @(%0,%1)\n\tici @(%2,%1)" :: "r" (tramp), "r" (i), + "r" (codeloc)); + + return FFI_OK; +} diff --git a/js/src/ctypes/libffi/src/frv/ffitarget.h b/js/src/ctypes/libffi/src/frv/ffitarget.h new file mode 100644 index 0000000..4839069 --- /dev/null +++ b/js/src/ctypes/libffi/src/frv/ffitarget.h @@ -0,0 +1,57 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2004 Red Hat, Inc. + Target configuration macros for FR-V + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- System specific configurations ----------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_EABI, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_EABI +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 + +#ifdef __FRV_FDPIC__ +/* Trampolines are 8 4-byte instructions long. */ +#define FFI_TRAMPOLINE_SIZE (8*4) +#else +/* Trampolines are 5 4-byte instructions long. */ +#define FFI_TRAMPOLINE_SIZE (5*4) +#endif + +#endif diff --git a/js/src/ctypes/libffi/src/ia64/ffi.c b/js/src/ctypes/libffi/src/ia64/ffi.c new file mode 100644 index 0000000..84b1448 --- /dev/null +++ b/js/src/ctypes/libffi/src/ia64/ffi.c @@ -0,0 +1,580 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1998, 2007, 2008 Red Hat, Inc. + Copyright (c) 2000 Hewlett Packard Company + + IA64 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include +#include +#include + +#include "ia64_flags.h" + +/* A 64-bit pointer value. In LP64 mode, this is effectively a plain + pointer. In ILP32 mode, it's a pointer that's been extended to + 64 bits by "addp4". */ +typedef void *PTR64 __attribute__((mode(DI))); + +/* Memory image of fp register contents. This is the implementation + specific format used by ldf.fill/stf.spill. All we care about is + that it wants a 16 byte aligned slot. */ +typedef struct +{ + UINT64 x[2] __attribute__((aligned(16))); +} fpreg; + + +/* The stack layout given to ffi_call_unix and ffi_closure_unix_inner. */ + +struct ia64_args +{ + fpreg fp_regs[8]; /* Contents of 8 fp arg registers. */ + UINT64 gp_regs[8]; /* Contents of 8 gp arg registers. */ + UINT64 other_args[]; /* Arguments passed on stack, variable size. */ +}; + + +/* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes. */ + +static inline void * +endian_adjust (void *addr, size_t len) +{ +#ifdef __BIG_ENDIAN__ + return addr + (8 - len); +#else + return addr; +#endif +} + +/* Store VALUE to ADDR in the current cpu implementation's fp spill format. + This is a macro instead of a function, so that it works for all 3 floating + point types without type conversions. Type conversion to long double breaks + the denorm support. */ + +#define stf_spill(addr, value) \ + asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value)); + +/* Load a value from ADDR, which is in the current cpu implementation's + fp spill format. As above, this must also be a macro. */ + +#define ldf_fill(result, addr) \ + asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr)); + +/* Return the size of the C type associated with with TYPE. Which will + be one of the FFI_IA64_TYPE_HFA_* values. */ + +static size_t +hfa_type_size (int type) +{ + switch (type) + { + case FFI_IA64_TYPE_HFA_FLOAT: + return sizeof(float); + case FFI_IA64_TYPE_HFA_DOUBLE: + return sizeof(double); + case FFI_IA64_TYPE_HFA_LDOUBLE: + return sizeof(__float80); + default: + abort (); + } +} + +/* Load from ADDR a value indicated by TYPE. Which will be one of + the FFI_IA64_TYPE_HFA_* values. */ + +static void +hfa_type_load (fpreg *fpaddr, int type, void *addr) +{ + switch (type) + { + case FFI_IA64_TYPE_HFA_FLOAT: + stf_spill (fpaddr, *(float *) addr); + return; + case FFI_IA64_TYPE_HFA_DOUBLE: + stf_spill (fpaddr, *(double *) addr); + return; + case FFI_IA64_TYPE_HFA_LDOUBLE: + stf_spill (fpaddr, *(__float80 *) addr); + return; + default: + abort (); + } +} + +/* Load VALUE into ADDR as indicated by TYPE. Which will be one of + the FFI_IA64_TYPE_HFA_* values. */ + +static void +hfa_type_store (int type, void *addr, fpreg *fpaddr) +{ + switch (type) + { + case FFI_IA64_TYPE_HFA_FLOAT: + { + float result; + ldf_fill (result, fpaddr); + *(float *) addr = result; + break; + } + case FFI_IA64_TYPE_HFA_DOUBLE: + { + double result; + ldf_fill (result, fpaddr); + *(double *) addr = result; + break; + } + case FFI_IA64_TYPE_HFA_LDOUBLE: + { + __float80 result; + ldf_fill (result, fpaddr); + *(__float80 *) addr = result; + break; + } + default: + abort (); + } +} + +/* Is TYPE a struct containing floats, doubles, or extended doubles, + all of the same fp type? If so, return the element type. Return + FFI_TYPE_VOID if not. */ + +static int +hfa_element_type (ffi_type *type, int nested) +{ + int element = FFI_TYPE_VOID; + + switch (type->type) + { + case FFI_TYPE_FLOAT: + /* We want to return VOID for raw floating-point types, but the + synthetic HFA type if we're nested within an aggregate. */ + if (nested) + element = FFI_IA64_TYPE_HFA_FLOAT; + break; + + case FFI_TYPE_DOUBLE: + /* Similarly. */ + if (nested) + element = FFI_IA64_TYPE_HFA_DOUBLE; + break; + + case FFI_TYPE_LONGDOUBLE: + /* Similarly, except that that HFA is true for double extended, + but not quad precision. Both have sizeof == 16, so tell the + difference based on the precision. */ + if (LDBL_MANT_DIG == 64 && nested) + element = FFI_IA64_TYPE_HFA_LDOUBLE; + break; + + case FFI_TYPE_STRUCT: + { + ffi_type **ptr = &type->elements[0]; + + for (ptr = &type->elements[0]; *ptr ; ptr++) + { + int sub_element = hfa_element_type (*ptr, 1); + if (sub_element == FFI_TYPE_VOID) + return FFI_TYPE_VOID; + + if (element == FFI_TYPE_VOID) + element = sub_element; + else if (element != sub_element) + return FFI_TYPE_VOID; + } + } + break; + + default: + return FFI_TYPE_VOID; + } + + return element; +} + + +/* Perform machine dependent cif processing. */ + +ffi_status +ffi_prep_cif_machdep(ffi_cif *cif) +{ + int flags; + + /* Adjust cif->bytes to include space for the bits of the ia64_args frame + that precedes the integer register portion. The estimate that the + generic bits did for the argument space required is good enough for the + integer component. */ + cif->bytes += offsetof(struct ia64_args, gp_regs[0]); + if (cif->bytes < sizeof(struct ia64_args)) + cif->bytes = sizeof(struct ia64_args); + + /* Set the return type flag. */ + flags = cif->rtype->type; + switch (cif->rtype->type) + { + case FFI_TYPE_LONGDOUBLE: + /* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision, + and encode quad precision as a two-word integer structure. */ + if (LDBL_MANT_DIG != 64) + flags = FFI_IA64_TYPE_SMALL_STRUCT | (16 << 8); + break; + + case FFI_TYPE_STRUCT: + { + size_t size = cif->rtype->size; + int hfa_type = hfa_element_type (cif->rtype, 0); + + if (hfa_type != FFI_TYPE_VOID) + { + size_t nelts = size / hfa_type_size (hfa_type); + if (nelts <= 8) + flags = hfa_type | (size << 8); + } + else + { + if (size <= 32) + flags = FFI_IA64_TYPE_SMALL_STRUCT | (size << 8); + } + } + break; + + default: + break; + } + cif->flags = flags; + + return FFI_OK; +} + +extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64); + +void +ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + struct ia64_args *stack; + long i, avn, gpcount, fpcount; + ffi_type **p_arg; + + FFI_ASSERT (cif->abi == FFI_UNIX); + + /* If we have no spot for a return value, make one. */ + if (rvalue == NULL && cif->rtype->type != FFI_TYPE_VOID) + rvalue = alloca (cif->rtype->size); + + /* Allocate the stack frame. */ + stack = alloca (cif->bytes); + + gpcount = fpcount = 0; + avn = cif->nargs; + for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + stack->gp_regs[gpcount++] = *(SINT8 *)avalue[i]; + break; + case FFI_TYPE_UINT8: + stack->gp_regs[gpcount++] = *(UINT8 *)avalue[i]; + break; + case FFI_TYPE_SINT16: + stack->gp_regs[gpcount++] = *(SINT16 *)avalue[i]; + break; + case FFI_TYPE_UINT16: + stack->gp_regs[gpcount++] = *(UINT16 *)avalue[i]; + break; + case FFI_TYPE_SINT32: + stack->gp_regs[gpcount++] = *(SINT32 *)avalue[i]; + break; + case FFI_TYPE_UINT32: + stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i]; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i]; + break; + + case FFI_TYPE_POINTER: + stack->gp_regs[gpcount++] = (UINT64)(PTR64) *(void **)avalue[i]; + break; + + case FFI_TYPE_FLOAT: + if (gpcount < 8 && fpcount < 8) + stf_spill (&stack->fp_regs[fpcount++], *(float *)avalue[i]); + stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i]; + break; + + case FFI_TYPE_DOUBLE: + if (gpcount < 8 && fpcount < 8) + stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]); + stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i]; + break; + + case FFI_TYPE_LONGDOUBLE: + if (gpcount & 1) + gpcount++; + if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8) + stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]); + memcpy (&stack->gp_regs[gpcount], avalue[i], 16); + gpcount += 2; + break; + + case FFI_TYPE_STRUCT: + { + size_t size = (*p_arg)->size; + size_t align = (*p_arg)->alignment; + int hfa_type = hfa_element_type (*p_arg, 0); + + FFI_ASSERT (align <= 16); + if (align == 16 && (gpcount & 1)) + gpcount++; + + if (hfa_type != FFI_TYPE_VOID) + { + size_t hfa_size = hfa_type_size (hfa_type); + size_t offset = 0; + size_t gp_offset = gpcount * 8; + + while (fpcount < 8 + && offset < size + && gp_offset < 8 * 8) + { + hfa_type_load (&stack->fp_regs[fpcount], hfa_type, + avalue[i] + offset); + offset += hfa_size; + gp_offset += hfa_size; + fpcount += 1; + } + } + + memcpy (&stack->gp_regs[gpcount], avalue[i], size); + gpcount += (size + 7) / 8; + } + break; + + default: + abort (); + } + } + + ffi_call_unix (stack, rvalue, fn, cif->flags); +} + +/* Closures represent a pair consisting of a function pointer, and + some user data. A closure is invoked by reinterpreting the closure + as a function pointer, and branching to it. Thus we can make an + interpreted function callable as a C function: We turn the + interpreter itself, together with a pointer specifying the + interpreted procedure, into a closure. + + For IA64, function pointer are already pairs consisting of a code + pointer, and a gp pointer. The latter is needed to access global + variables. Here we set up such a pair as the first two words of + the closure (in the "trampoline" area), but we replace the gp + pointer with a pointer to the closure itself. We also add the real + gp pointer to the closure. This allows the function entry code to + both retrieve the user data, and to restire the correct gp pointer. */ + +extern void ffi_closure_unix (); + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) +{ + /* The layout of a function descriptor. A C function pointer really + points to one of these. */ + struct ia64_fd + { + UINT64 code_pointer; + UINT64 gp; + }; + + struct ffi_ia64_trampoline_struct + { + UINT64 code_pointer; /* Pointer to ffi_closure_unix. */ + UINT64 fake_gp; /* Pointer to closure, installed as gp. */ + UINT64 real_gp; /* Real gp value. */ + }; + + struct ffi_ia64_trampoline_struct *tramp; + struct ia64_fd *fd; + + FFI_ASSERT (cif->abi == FFI_UNIX); + + tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp; + fd = (struct ia64_fd *)(void *)ffi_closure_unix; + + tramp->code_pointer = fd->code_pointer; + tramp->real_gp = fd->gp; + tramp->fake_gp = (UINT64)(PTR64)codeloc; + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + + +UINT64 +ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack, + void *rvalue, void *r8) +{ + ffi_cif *cif; + void **avalue; + ffi_type **p_arg; + long i, avn, gpcount, fpcount; + + cif = closure->cif; + avn = cif->nargs; + avalue = alloca (avn * sizeof (void *)); + + /* If the structure return value is passed in memory get that location + from r8 so as to pass the value directly back to the caller. */ + if (cif->flags == FFI_TYPE_STRUCT) + rvalue = r8; + + gpcount = fpcount = 0; + for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1); + break; + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2); + break; + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4); + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + avalue[i] = &stack->gp_regs[gpcount++]; + break; + case FFI_TYPE_POINTER: + avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*)); + break; + + case FFI_TYPE_FLOAT: + if (gpcount < 8 && fpcount < 8) + { + fpreg *addr = &stack->fp_regs[fpcount++]; + float result; + avalue[i] = addr; + ldf_fill (result, addr); + *(float *)addr = result; + } + else + avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4); + gpcount++; + break; + + case FFI_TYPE_DOUBLE: + if (gpcount < 8 && fpcount < 8) + { + fpreg *addr = &stack->fp_regs[fpcount++]; + double result; + avalue[i] = addr; + ldf_fill (result, addr); + *(double *)addr = result; + } + else + avalue[i] = &stack->gp_regs[gpcount]; + gpcount++; + break; + + case FFI_TYPE_LONGDOUBLE: + if (gpcount & 1) + gpcount++; + if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8) + { + fpreg *addr = &stack->fp_regs[fpcount++]; + __float80 result; + avalue[i] = addr; + ldf_fill (result, addr); + *(__float80 *)addr = result; + } + else + avalue[i] = &stack->gp_regs[gpcount]; + gpcount += 2; + break; + + case FFI_TYPE_STRUCT: + { + size_t size = (*p_arg)->size; + size_t align = (*p_arg)->alignment; + int hfa_type = hfa_element_type (*p_arg, 0); + + FFI_ASSERT (align <= 16); + if (align == 16 && (gpcount & 1)) + gpcount++; + + if (hfa_type != FFI_TYPE_VOID) + { + size_t hfa_size = hfa_type_size (hfa_type); + size_t offset = 0; + size_t gp_offset = gpcount * 8; + void *addr = alloca (size); + + avalue[i] = addr; + + while (fpcount < 8 + && offset < size + && gp_offset < 8 * 8) + { + hfa_type_store (hfa_type, addr + offset, + &stack->fp_regs[fpcount]); + offset += hfa_size; + gp_offset += hfa_size; + fpcount += 1; + } + + if (offset < size) + memcpy (addr + offset, (char *)stack->gp_regs + gp_offset, + size - offset); + } + else + avalue[i] = &stack->gp_regs[gpcount]; + + gpcount += (size + 7) / 8; + } + break; + + default: + abort (); + } + } + + closure->fun (cif, rvalue, avalue, closure->user_data); + + return cif->flags; +} diff --git a/js/src/ctypes/libffi/src/ia64/ffitarget.h b/js/src/ctypes/libffi/src/ia64/ffitarget.h new file mode 100644 index 0000000..0d2001d --- /dev/null +++ b/js/src/ctypes/libffi/src/ia64/ffitarget.h @@ -0,0 +1,50 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for IA-64. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_ASM +typedef unsigned long long ffi_arg; +typedef signed long long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_UNIX, /* Linux and all Unix variants use the same conventions */ + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_UNIX +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 24 /* Really the following struct, which */ + /* can be interpreted as a C function */ + /* descriptor: */ + +#endif + diff --git a/js/src/ctypes/libffi/src/ia64/ia64_flags.h b/js/src/ctypes/libffi/src/ia64/ia64_flags.h new file mode 100644 index 0000000..9d652ce --- /dev/null +++ b/js/src/ctypes/libffi/src/ia64/ia64_flags.h @@ -0,0 +1,40 @@ +/* ----------------------------------------------------------------------- + ia64_flags.h - Copyright (c) 2000 Hewlett Packard Company + + IA64/unix Foreign Function Interface + + Original author: Hans Boehm, HP Labs + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +/* "Type" codes used between assembly and C. When used as a part of + a cfi->flags value, the low byte will be these extra type codes, + and bits 8-31 will be the actual size of the type. */ + +/* Small structures containing N words in integer registers. */ +#define FFI_IA64_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 1) + +/* Homogeneous Floating Point Aggregates (HFAs) which are returned + in FP registers. */ +#define FFI_IA64_TYPE_HFA_FLOAT (FFI_TYPE_LAST + 2) +#define FFI_IA64_TYPE_HFA_DOUBLE (FFI_TYPE_LAST + 3) +#define FFI_IA64_TYPE_HFA_LDOUBLE (FFI_TYPE_LAST + 4) diff --git a/js/src/ctypes/libffi/src/ia64/unix.S b/js/src/ctypes/libffi/src/ia64/unix.S new file mode 100644 index 0000000..4d2a86d --- /dev/null +++ b/js/src/ctypes/libffi/src/ia64/unix.S @@ -0,0 +1,560 @@ +/* ----------------------------------------------------------------------- + unix.S - Copyright (c) 1998, 2008 Red Hat, Inc. + Copyright (c) 2000 Hewlett Packard Company + + IA64/unix Foreign Function Interface + + Primary author: Hans Boehm, HP Labs + + Loosely modeled on Cygnus code for other platforms. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include +#include "ia64_flags.h" + + .pred.safe_across_calls p1-p5,p16-p63 +.text + +/* int ffi_call_unix (struct ia64_args *stack, PTR64 rvalue, + void (*fn)(void), int flags); + */ + + .align 16 + .global ffi_call_unix + .proc ffi_call_unix +ffi_call_unix: + .prologue + /* Bit o trickiness. We actually share a stack frame with ffi_call. + Rely on the fact that ffi_call uses a vframe and don't bother + tracking one here at all. */ + .fframe 0 + .save ar.pfs, r36 // loc0 + alloc loc0 = ar.pfs, 4, 3, 8, 0 + .save rp, loc1 + mov loc1 = b0 + .body + add r16 = 16, in0 + mov loc2 = gp + mov r8 = in1 + ;; + + /* Load up all of the argument registers. */ + ldf.fill f8 = [in0], 32 + ldf.fill f9 = [r16], 32 + ;; + ldf.fill f10 = [in0], 32 + ldf.fill f11 = [r16], 32 + ;; + ldf.fill f12 = [in0], 32 + ldf.fill f13 = [r16], 32 + ;; + ldf.fill f14 = [in0], 32 + ldf.fill f15 = [r16], 24 + ;; + ld8 out0 = [in0], 16 + ld8 out1 = [r16], 16 + ;; + ld8 out2 = [in0], 16 + ld8 out3 = [r16], 16 + ;; + ld8 out4 = [in0], 16 + ld8 out5 = [r16], 16 + ;; + ld8 out6 = [in0] + ld8 out7 = [r16] + ;; + + /* Deallocate the register save area from the stack frame. */ + mov sp = in0 + + /* Call the target function. */ + ld8 r16 = [in2], 8 + ;; + ld8 gp = [in2] + mov b6 = r16 + br.call.sptk.many b0 = b6 + ;; + + /* Dispatch to handle return value. */ + mov gp = loc2 + zxt1 r16 = in3 + ;; + mov ar.pfs = loc0 + addl r18 = @ltoffx(.Lst_table), gp + ;; + ld8.mov r18 = [r18], .Lst_table + mov b0 = loc1 + ;; + shladd r18 = r16, 3, r18 + ;; + ld8 r17 = [r18] + shr in3 = in3, 8 + ;; + add r17 = r17, r18 + ;; + mov b6 = r17 + br b6 + ;; + +.Lst_void: + br.ret.sptk.many b0 + ;; +.Lst_uint8: + zxt1 r8 = r8 + ;; + st8 [in1] = r8 + br.ret.sptk.many b0 + ;; +.Lst_sint8: + sxt1 r8 = r8 + ;; + st8 [in1] = r8 + br.ret.sptk.many b0 + ;; +.Lst_uint16: + zxt2 r8 = r8 + ;; + st8 [in1] = r8 + br.ret.sptk.many b0 + ;; +.Lst_sint16: + sxt2 r8 = r8 + ;; + st8 [in1] = r8 + br.ret.sptk.many b0 + ;; +.Lst_uint32: + zxt4 r8 = r8 + ;; + st8 [in1] = r8 + br.ret.sptk.many b0 + ;; +.Lst_sint32: + sxt4 r8 = r8 + ;; + st8 [in1] = r8 + br.ret.sptk.many b0 + ;; +.Lst_int64: + st8 [in1] = r8 + br.ret.sptk.many b0 + ;; +.Lst_float: + stfs [in1] = f8 + br.ret.sptk.many b0 + ;; +.Lst_double: + stfd [in1] = f8 + br.ret.sptk.many b0 + ;; +.Lst_ldouble: + stfe [in1] = f8 + br.ret.sptk.many b0 + ;; + +.Lst_small_struct: + add sp = -16, sp + cmp.lt p6, p0 = 8, in3 + cmp.lt p7, p0 = 16, in3 + cmp.lt p8, p0 = 24, in3 + ;; + add r16 = 8, sp + add r17 = 16, sp + add r18 = 24, sp + ;; + st8 [sp] = r8 +(p6) st8 [r16] = r9 + mov out0 = in1 +(p7) st8 [r17] = r10 +(p8) st8 [r18] = r11 + mov out1 = sp + mov out2 = in3 + br.call.sptk.many b0 = memcpy# + ;; + mov ar.pfs = loc0 + mov b0 = loc1 + mov gp = loc2 + br.ret.sptk.many b0 + +.Lst_hfa_float: + add r16 = 4, in1 + cmp.lt p6, p0 = 4, in3 + ;; + stfs [in1] = f8, 8 +(p6) stfs [r16] = f9, 8 + cmp.lt p7, p0 = 8, in3 + cmp.lt p8, p0 = 12, in3 + ;; +(p7) stfs [in1] = f10, 8 +(p8) stfs [r16] = f11, 8 + cmp.lt p9, p0 = 16, in3 + cmp.lt p10, p0 = 20, in3 + ;; +(p9) stfs [in1] = f12, 8 +(p10) stfs [r16] = f13, 8 + cmp.lt p6, p0 = 24, in3 + cmp.lt p7, p0 = 28, in3 + ;; +(p6) stfs [in1] = f14 +(p7) stfs [r16] = f15 + br.ret.sptk.many b0 + ;; + +.Lst_hfa_double: + add r16 = 8, in1 + cmp.lt p6, p0 = 8, in3 + ;; + stfd [in1] = f8, 16 +(p6) stfd [r16] = f9, 16 + cmp.lt p7, p0 = 16, in3 + cmp.lt p8, p0 = 24, in3 + ;; +(p7) stfd [in1] = f10, 16 +(p8) stfd [r16] = f11, 16 + cmp.lt p9, p0 = 32, in3 + cmp.lt p10, p0 = 40, in3 + ;; +(p9) stfd [in1] = f12, 16 +(p10) stfd [r16] = f13, 16 + cmp.lt p6, p0 = 48, in3 + cmp.lt p7, p0 = 56, in3 + ;; +(p6) stfd [in1] = f14 +(p7) stfd [r16] = f15 + br.ret.sptk.many b0 + ;; + +.Lst_hfa_ldouble: + add r16 = 16, in1 + cmp.lt p6, p0 = 16, in3 + ;; + stfe [in1] = f8, 32 +(p6) stfe [r16] = f9, 32 + cmp.lt p7, p0 = 32, in3 + cmp.lt p8, p0 = 48, in3 + ;; +(p7) stfe [in1] = f10, 32 +(p8) stfe [r16] = f11, 32 + cmp.lt p9, p0 = 64, in3 + cmp.lt p10, p0 = 80, in3 + ;; +(p9) stfe [in1] = f12, 32 +(p10) stfe [r16] = f13, 32 + cmp.lt p6, p0 = 96, in3 + cmp.lt p7, p0 = 112, in3 + ;; +(p6) stfe [in1] = f14 +(p7) stfe [r16] = f15 + br.ret.sptk.many b0 + ;; + + .endp ffi_call_unix + + .align 16 + .global ffi_closure_unix + .proc ffi_closure_unix + +#define FRAME_SIZE (8*16 + 8*8 + 8*16) + +ffi_closure_unix: + .prologue + .save ar.pfs, r40 // loc0 + alloc loc0 = ar.pfs, 8, 4, 4, 0 + .fframe FRAME_SIZE + add r12 = -FRAME_SIZE, r12 + .save rp, loc1 + mov loc1 = b0 + .save ar.unat, loc2 + mov loc2 = ar.unat + .body + + /* Retrieve closure pointer and real gp. */ +#ifdef _ILP32 + addp4 out0 = 0, gp + addp4 gp = 16, gp +#else + mov out0 = gp + add gp = 16, gp +#endif + ;; + ld8 gp = [gp] + + /* Spill all of the possible argument registers. */ + add r16 = 16 + 8*16, sp + add r17 = 16 + 8*16 + 16, sp + ;; + stf.spill [r16] = f8, 32 + stf.spill [r17] = f9, 32 + mov loc3 = gp + ;; + stf.spill [r16] = f10, 32 + stf.spill [r17] = f11, 32 + ;; + stf.spill [r16] = f12, 32 + stf.spill [r17] = f13, 32 + ;; + stf.spill [r16] = f14, 32 + stf.spill [r17] = f15, 24 + ;; + .mem.offset 0, 0 + st8.spill [r16] = in0, 16 + .mem.offset 8, 0 + st8.spill [r17] = in1, 16 + add out1 = 16 + 8*16, sp + ;; + .mem.offset 0, 0 + st8.spill [r16] = in2, 16 + .mem.offset 8, 0 + st8.spill [r17] = in3, 16 + add out2 = 16, sp + ;; + .mem.offset 0, 0 + st8.spill [r16] = in4, 16 + .mem.offset 8, 0 + st8.spill [r17] = in5, 16 + mov out3 = r8 + ;; + .mem.offset 0, 0 + st8.spill [r16] = in6 + .mem.offset 8, 0 + st8.spill [r17] = in7 + + /* Invoke ffi_closure_unix_inner for the hard work. */ + br.call.sptk.many b0 = ffi_closure_unix_inner + ;; + + /* Dispatch to handle return value. */ + mov gp = loc3 + zxt1 r16 = r8 + ;; + addl r18 = @ltoffx(.Lld_table), gp + mov ar.pfs = loc0 + ;; + ld8.mov r18 = [r18], .Lld_table + mov b0 = loc1 + ;; + shladd r18 = r16, 3, r18 + mov ar.unat = loc2 + ;; + ld8 r17 = [r18] + shr r8 = r8, 8 + ;; + add r17 = r17, r18 + add r16 = 16, sp + ;; + mov b6 = r17 + br b6 + ;; + .label_state 1 + +.Lld_void: + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; +.Lld_int: + .body + .copy_state 1 + ld8 r8 = [r16] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; +.Lld_float: + .body + .copy_state 1 + ldfs f8 = [r16] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; +.Lld_double: + .body + .copy_state 1 + ldfd f8 = [r16] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; +.Lld_ldouble: + .body + .copy_state 1 + ldfe f8 = [r16] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; + +.Lld_small_struct: + .body + .copy_state 1 + add r17 = 8, r16 + cmp.lt p6, p0 = 8, r8 + cmp.lt p7, p0 = 16, r8 + cmp.lt p8, p0 = 24, r8 + ;; + ld8 r8 = [r16], 16 +(p6) ld8 r9 = [r17], 16 + ;; +(p7) ld8 r10 = [r16] +(p8) ld8 r11 = [r17] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; + +.Lld_hfa_float: + .body + .copy_state 1 + add r17 = 4, r16 + cmp.lt p6, p0 = 4, r8 + ;; + ldfs f8 = [r16], 8 +(p6) ldfs f9 = [r17], 8 + cmp.lt p7, p0 = 8, r8 + cmp.lt p8, p0 = 12, r8 + ;; +(p7) ldfs f10 = [r16], 8 +(p8) ldfs f11 = [r17], 8 + cmp.lt p9, p0 = 16, r8 + cmp.lt p10, p0 = 20, r8 + ;; +(p9) ldfs f12 = [r16], 8 +(p10) ldfs f13 = [r17], 8 + cmp.lt p6, p0 = 24, r8 + cmp.lt p7, p0 = 28, r8 + ;; +(p6) ldfs f14 = [r16] +(p7) ldfs f15 = [r17] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; + +.Lld_hfa_double: + .body + .copy_state 1 + add r17 = 8, r16 + cmp.lt p6, p0 = 8, r8 + ;; + ldfd f8 = [r16], 16 +(p6) ldfd f9 = [r17], 16 + cmp.lt p7, p0 = 16, r8 + cmp.lt p8, p0 = 24, r8 + ;; +(p7) ldfd f10 = [r16], 16 +(p8) ldfd f11 = [r17], 16 + cmp.lt p9, p0 = 32, r8 + cmp.lt p10, p0 = 40, r8 + ;; +(p9) ldfd f12 = [r16], 16 +(p10) ldfd f13 = [r17], 16 + cmp.lt p6, p0 = 48, r8 + cmp.lt p7, p0 = 56, r8 + ;; +(p6) ldfd f14 = [r16] +(p7) ldfd f15 = [r17] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; + +.Lld_hfa_ldouble: + .body + .copy_state 1 + add r17 = 16, r16 + cmp.lt p6, p0 = 16, r8 + ;; + ldfe f8 = [r16], 32 +(p6) ldfe f9 = [r17], 32 + cmp.lt p7, p0 = 32, r8 + cmp.lt p8, p0 = 48, r8 + ;; +(p7) ldfe f10 = [r16], 32 +(p8) ldfe f11 = [r17], 32 + cmp.lt p9, p0 = 64, r8 + cmp.lt p10, p0 = 80, r8 + ;; +(p9) ldfe f12 = [r16], 32 +(p10) ldfe f13 = [r17], 32 + cmp.lt p6, p0 = 96, r8 + cmp.lt p7, p0 = 112, r8 + ;; +(p6) ldfe f14 = [r16] +(p7) ldfe f15 = [r17] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; + + .endp ffi_closure_unix + + .section .rodata + .align 8 +.Lst_table: + data8 @pcrel(.Lst_void) // FFI_TYPE_VOID + data8 @pcrel(.Lst_sint32) // FFI_TYPE_INT + data8 @pcrel(.Lst_float) // FFI_TYPE_FLOAT + data8 @pcrel(.Lst_double) // FFI_TYPE_DOUBLE + data8 @pcrel(.Lst_ldouble) // FFI_TYPE_LONGDOUBLE + data8 @pcrel(.Lst_uint8) // FFI_TYPE_UINT8 + data8 @pcrel(.Lst_sint8) // FFI_TYPE_SINT8 + data8 @pcrel(.Lst_uint16) // FFI_TYPE_UINT16 + data8 @pcrel(.Lst_sint16) // FFI_TYPE_SINT16 + data8 @pcrel(.Lst_uint32) // FFI_TYPE_UINT32 + data8 @pcrel(.Lst_sint32) // FFI_TYPE_SINT32 + data8 @pcrel(.Lst_int64) // FFI_TYPE_UINT64 + data8 @pcrel(.Lst_int64) // FFI_TYPE_SINT64 + data8 @pcrel(.Lst_void) // FFI_TYPE_STRUCT + data8 @pcrel(.Lst_int64) // FFI_TYPE_POINTER + data8 @pcrel(.Lst_small_struct) // FFI_IA64_TYPE_SMALL_STRUCT + data8 @pcrel(.Lst_hfa_float) // FFI_IA64_TYPE_HFA_FLOAT + data8 @pcrel(.Lst_hfa_double) // FFI_IA64_TYPE_HFA_DOUBLE + data8 @pcrel(.Lst_hfa_ldouble) // FFI_IA64_TYPE_HFA_LDOUBLE + +.Lld_table: + data8 @pcrel(.Lld_void) // FFI_TYPE_VOID + data8 @pcrel(.Lld_int) // FFI_TYPE_INT + data8 @pcrel(.Lld_float) // FFI_TYPE_FLOAT + data8 @pcrel(.Lld_double) // FFI_TYPE_DOUBLE + data8 @pcrel(.Lld_ldouble) // FFI_TYPE_LONGDOUBLE + data8 @pcrel(.Lld_int) // FFI_TYPE_UINT8 + data8 @pcrel(.Lld_int) // FFI_TYPE_SINT8 + data8 @pcrel(.Lld_int) // FFI_TYPE_UINT16 + data8 @pcrel(.Lld_int) // FFI_TYPE_SINT16 + data8 @pcrel(.Lld_int) // FFI_TYPE_UINT32 + data8 @pcrel(.Lld_int) // FFI_TYPE_SINT32 + data8 @pcrel(.Lld_int) // FFI_TYPE_UINT64 + data8 @pcrel(.Lld_int) // FFI_TYPE_SINT64 + data8 @pcrel(.Lld_void) // FFI_TYPE_STRUCT + data8 @pcrel(.Lld_int) // FFI_TYPE_POINTER + data8 @pcrel(.Lld_small_struct) // FFI_IA64_TYPE_SMALL_STRUCT + data8 @pcrel(.Lld_hfa_float) // FFI_IA64_TYPE_HFA_FLOAT + data8 @pcrel(.Lld_hfa_double) // FFI_IA64_TYPE_HFA_DOUBLE + data8 @pcrel(.Lld_hfa_ldouble) // FFI_IA64_TYPE_HFA_LDOUBLE + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/js/src/ctypes/libffi/src/java_raw_api.c b/js/src/ctypes/libffi/src/java_raw_api.c new file mode 100644 index 0000000..9c5383e --- /dev/null +++ b/js/src/ctypes/libffi/src/java_raw_api.c @@ -0,0 +1,356 @@ +/* ----------------------------------------------------------------------- + java_raw_api.c - Copyright (c) 1999, 2007, 2008 Red Hat, Inc. + + Cloned from raw_api.c + + Raw_api.c author: Kresten Krab Thorup + Java_raw_api.c author: Hans-J. Boehm + + $Id $ + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +/* This defines a Java- and 64-bit specific variant of the raw API. */ +/* It assumes that "raw" argument blocks look like Java stacks on a */ +/* 64-bit machine. Arguments that can be stored in a single stack */ +/* stack slots (longs, doubles) occupy 128 bits, but only the first */ +/* 64 bits are actually used. */ + +#include +#include +#include + +#if !defined(NO_JAVA_RAW_API) && !defined(FFI_NO_RAW_API) + +size_t +ffi_java_raw_size (ffi_cif *cif) +{ + size_t result = 0; + int i; + + ffi_type **at = cif->arg_types; + + for (i = cif->nargs-1; i >= 0; i--, at++) + { + switch((*at) -> type) { + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_DOUBLE: + result += 2 * FFI_SIZEOF_JAVA_RAW; + break; + case FFI_TYPE_STRUCT: + /* No structure parameters in Java. */ + abort(); + default: + result += FFI_SIZEOF_JAVA_RAW; + } + } + + return result; +} + + +void +ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args) +{ + unsigned i; + ffi_type **tp = cif->arg_types; + +#if WORDS_BIGENDIAN + + for (i = 0; i < cif->nargs; i++, tp++, args++) + { + switch ((*tp)->type) + { + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + *args = (void*) ((char*)(raw++) + 3); + break; + + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + *args = (void*) ((char*)(raw++) + 2); + break; + +#if FFI_SIZEOF_JAVA_RAW == 8 + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_DOUBLE: + *args = (void *)raw; + raw += 2; + break; +#endif + + case FFI_TYPE_POINTER: + *args = (void*) &(raw++)->ptr; + break; + + default: + *args = raw; + raw += + ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw); + } + } + +#else /* WORDS_BIGENDIAN */ + +#if !PDP + + /* then assume little endian */ + for (i = 0; i < cif->nargs; i++, tp++, args++) + { +#if FFI_SIZEOF_JAVA_RAW == 8 + switch((*tp)->type) { + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_DOUBLE: + *args = (void*) raw; + raw += 2; + break; + default: + *args = (void*) raw++; + } +#else /* FFI_SIZEOF_JAVA_RAW != 8 */ + *args = (void*) raw; + raw += + ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw); +#endif /* FFI_SIZEOF_JAVA_RAW == 8 */ + } + +#else +#error "pdp endian not supported" +#endif /* ! PDP */ + +#endif /* WORDS_BIGENDIAN */ +} + +void +ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw) +{ + unsigned i; + ffi_type **tp = cif->arg_types; + + for (i = 0; i < cif->nargs; i++, tp++, args++) + { + switch ((*tp)->type) + { + case FFI_TYPE_UINT8: +#if WORDS_BIGENDIAN + *(UINT32*)(raw++) = *(UINT8*) (*args); +#else + (raw++)->uint = *(UINT8*) (*args); +#endif + break; + + case FFI_TYPE_SINT8: +#if WORDS_BIGENDIAN + *(SINT32*)(raw++) = *(SINT8*) (*args); +#else + (raw++)->sint = *(SINT8*) (*args); +#endif + break; + + case FFI_TYPE_UINT16: +#if WORDS_BIGENDIAN + *(UINT32*)(raw++) = *(UINT16*) (*args); +#else + (raw++)->uint = *(UINT16*) (*args); +#endif + break; + + case FFI_TYPE_SINT16: +#if WORDS_BIGENDIAN + *(SINT32*)(raw++) = *(SINT16*) (*args); +#else + (raw++)->sint = *(SINT16*) (*args); +#endif + break; + + case FFI_TYPE_UINT32: +#if WORDS_BIGENDIAN + *(UINT32*)(raw++) = *(UINT32*) (*args); +#else + (raw++)->uint = *(UINT32*) (*args); +#endif + break; + + case FFI_TYPE_SINT32: +#if WORDS_BIGENDIAN + *(SINT32*)(raw++) = *(SINT32*) (*args); +#else + (raw++)->sint = *(SINT32*) (*args); +#endif + break; + + case FFI_TYPE_FLOAT: + (raw++)->flt = *(FLOAT32*) (*args); + break; + +#if FFI_SIZEOF_JAVA_RAW == 8 + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_DOUBLE: + raw->uint = *(UINT64*) (*args); + raw += 2; + break; +#endif + + case FFI_TYPE_POINTER: + (raw++)->ptr = **(void***) args; + break; + + default: +#if FFI_SIZEOF_JAVA_RAW == 8 + FFI_ASSERT(0); /* Should have covered all cases */ +#else + memcpy ((void*) raw->data, (void*)*args, (*tp)->size); + raw += + ALIGN ((*tp)->size, sizeof(ffi_java_raw)) / sizeof(ffi_java_raw); +#endif + } + } +} + +#if !FFI_NATIVE_RAW_API + +static void +ffi_java_rvalue_to_raw (ffi_cif *cif, void *rvalue) +{ +#if WORDS_BIGENDIAN && FFI_SIZEOF_ARG == 8 + switch (cif->rtype->type) + { + case FFI_TYPE_UINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_UINT32: + *(UINT64 *)rvalue <<= 32; + break; + + case FFI_TYPE_SINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_INT: +#if FFI_SIZEOF_JAVA_RAW == 4 + case FFI_TYPE_POINTER: +#endif + *(SINT64 *)rvalue <<= 32; + break; + + default: + break; + } +#endif +} + +static void +ffi_java_raw_to_rvalue (ffi_cif *cif, void *rvalue) +{ +#if WORDS_BIGENDIAN && FFI_SIZEOF_ARG == 8 + switch (cif->rtype->type) + { + case FFI_TYPE_UINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_UINT32: + *(UINT64 *)rvalue >>= 32; + break; + + case FFI_TYPE_SINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_INT: + *(SINT64 *)rvalue >>= 32; + break; + + default: + break; + } +#endif +} + +/* This is a generic definition of ffi_raw_call, to be used if the + * native system does not provide a machine-specific implementation. + * Having this, allows code to be written for the raw API, without + * the need for system-specific code to handle input in that format; + * these following couple of functions will handle the translation forth + * and back automatically. */ + +void ffi_java_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, + ffi_java_raw *raw) +{ + void **avalue = (void**) alloca (cif->nargs * sizeof (void*)); + ffi_java_raw_to_ptrarray (cif, raw, avalue); + ffi_call (cif, fn, rvalue, avalue); + ffi_java_rvalue_to_raw (cif, rvalue); +} + +#if FFI_CLOSURES /* base system provides closures */ + +static void +ffi_java_translate_args (ffi_cif *cif, void *rvalue, + void **avalue, void *user_data) +{ + ffi_java_raw *raw = (ffi_java_raw*)alloca (ffi_java_raw_size (cif)); + ffi_raw_closure *cl = (ffi_raw_closure*)user_data; + + ffi_java_ptrarray_to_raw (cif, avalue, raw); + (*cl->fun) (cif, rvalue, raw, cl->user_data); + ffi_java_raw_to_rvalue (cif, rvalue); +} + +ffi_status +ffi_prep_java_raw_closure_loc (ffi_java_raw_closure* cl, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), + void *user_data, + void *codeloc) +{ + ffi_status status; + + status = ffi_prep_closure_loc ((ffi_closure*) cl, + cif, + &ffi_java_translate_args, + codeloc, + codeloc); + if (status == FFI_OK) + { + cl->fun = fun; + cl->user_data = user_data; + } + + return status; +} + +/* Again, here is the generic version of ffi_prep_raw_closure, which + * will install an intermediate "hub" for translation of arguments from + * the pointer-array format, to the raw format */ + +ffi_status +ffi_prep_java_raw_closure (ffi_java_raw_closure* cl, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), + void *user_data) +{ + return ffi_prep_java_raw_closure_loc (cl, cif, fun, user_data, cl); +} + +#endif /* FFI_CLOSURES */ +#endif /* !FFI_NATIVE_RAW_API */ +#endif /* !FFI_NO_RAW_API */ diff --git a/js/src/ctypes/libffi/src/m32r/ffi.c b/js/src/ctypes/libffi/src/m32r/ffi.c new file mode 100644 index 0000000..3000063 --- /dev/null +++ b/js/src/ctypes/libffi/src/m32r/ffi.c @@ -0,0 +1,232 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2004 Renesas Technology + Copyright (c) 2008 Red Hat, Inc. + + M32R Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include + +/* ffi_prep_args is called by the assembly routine once stack + space has been allocated for the function's arguments. */ + +void ffi_prep_args(char *stack, extended_cif *ecif) +{ + unsigned int i; + int tmp; + unsigned int avn; + void **p_argv; + char *argp; + ffi_type **p_arg; + + tmp = 0; + argp = stack; + + if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 8) + { + *(void **) argp = ecif->rvalue; + argp += 4; + } + + avn = ecif->cif->nargs; + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + (i != 0) && (avn != 0); + i--, p_arg++) + { + size_t z; + + /* Align if necessary. */ + if (((*p_arg)->alignment - 1) & (unsigned) argp) + argp = (char *) ALIGN (argp, (*p_arg)->alignment); + + if (avn != 0) + { + avn--; + z = (*p_arg)->size; + if (z < sizeof (int)) + { + z = sizeof (int); + + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + z = (*p_arg)->size; + if ((*p_arg)->alignment != 1) + memcpy (argp, *p_argv, z); + else + memcpy (argp + 4 - z, *p_argv, z); + z = sizeof (int); + break; + + default: + FFI_ASSERT(0); + } + } + else if (z == sizeof (int)) + { + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + } + else + { + if ((*p_arg)->type == FFI_TYPE_STRUCT) + { + if (z > 8) + { + *(unsigned int *) argp = (unsigned int)(void *)(* p_argv); + z = sizeof(void *); + } + else + { + memcpy(argp, *p_argv, z); + z = 8; + } + } + else + { + /* Double or long long 64bit. */ + memcpy (argp, *p_argv, z); + } + } + p_argv++; + argp += z; + } + } + + return; +} + +/* Perform machine dependent cif processing. */ +ffi_status +ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* Set the return type flag. */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_STRUCT: + if (cif->rtype->size <= 4) + cif->flags = FFI_TYPE_INT; + + else if (cif->rtype->size <= 8) + cif->flags = FFI_TYPE_DOUBLE; + + else + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_DOUBLE: + cif->flags = FFI_TYPE_DOUBLE; + break; + + case FFI_TYPE_FLOAT: + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, + unsigned, unsigned, unsigned *, void (*fn)(void)); + +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have + a return value address then we need to make one. */ + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + ecif.rvalue = alloca (cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: + ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + int size = cif->rtype->size; + int align = cif->rtype->alignment; + + if (size < 4) + { + if (align == 1) + *(unsigned long *)(ecif.rvalue) <<= (4 - size) * 8; + } + else if (4 < size && size < 8) + { + if (align == 1) + { + memcpy (ecif.rvalue, ecif.rvalue + 8-size, size); + } + else if (align == 2) + { + if (size & 1) + size += 1; + + if (size != 8) + memcpy (ecif.rvalue, ecif.rvalue + 8-size, size); + } + } + } + break; + + default: + FFI_ASSERT(0); + break; + } +} diff --git a/js/src/ctypes/libffi/src/m32r/ffitarget.h b/js/src/ctypes/libffi/src/m32r/ffitarget.h new file mode 100644 index 0000000..2e2ea48 --- /dev/null +++ b/js/src/ctypes/libffi/src/m32r/ffitarget.h @@ -0,0 +1,48 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 2004 Renesas Technology. + Target configuration macros for M32R. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- Generic type definitions ----------------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi + { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_SYSV + } ffi_abi; +#endif + +#define FFI_CLOSURES 0 +#define FFI_TRAMPOLINE_SIZE 24 +#define FFI_NATIVE_RAW_API 0 + +#endif diff --git a/js/src/ctypes/libffi/src/m32r/sysv.S b/js/src/ctypes/libffi/src/m32r/sysv.S new file mode 100644 index 0000000..06b75c2 --- /dev/null +++ b/js/src/ctypes/libffi/src/m32r/sysv.S @@ -0,0 +1,121 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2004 Renesas Technology + + M32R Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include +#ifdef HAVE_MACHINE_ASM_H +#include +#else +/* XXX these lose for some platforms, I'm sure. */ +#define CNAME(x) x +#define ENTRY(x) .globl CNAME(x)! .type CNAME(x),%function! CNAME(x): +#endif + +.text + + /* R0: ffi_prep_args */ + /* R1: &ecif */ + /* R2: cif->bytes */ + /* R3: fig->flags */ + /* sp+0: ecif.rvalue */ + /* sp+4: fn */ + + /* This assumes we are using gas. */ +ENTRY(ffi_call_SYSV) + /* Save registers. */ + push fp + push lr + push r3 + push r2 + push r1 + push r0 + mv fp, sp + + /* Make room for all of the new args. */ + sub sp, r2 + + /* Place all of the ffi_prep_args in position. */ + mv lr, r0 + mv r0, sp + /* R1 already set. */ + + /* And call. */ + jl lr + + /* Move first 4 parameters in registers... */ + ld r0, @(0,sp) + ld r1, @(4,sp) + ld r2, @(8,sp) + ld r3, @(12,sp) + + /* ...and adjust the stack. */ + ld lr, @(8,fp) + cmpi lr, #16 + bc adjust_stack + ldi lr, #16 +adjust_stack: + add sp, lr + + /* Call the function. */ + ld lr, @(28,fp) + jl lr + + /* Remove the space we pushed for the args. */ + mv sp, fp + + /* Load R2 with the pointer to storage for the return value. */ + ld r2, @(24,sp) + + /* Load R3 with the return type code. */ + ld r3, @(12,sp) + + /* If the return value pointer is NULL, assume no return value. */ + beqz r2, epilogue + + /* Return INT. */ + ldi r4, #FFI_TYPE_INT + bne r3, r4, return_double + st r0, @r2 + bra epilogue + +return_double: + /* Return DOUBLE or LONGDOUBLE. */ + ldi r4, #FFI_TYPE_DOUBLE + bne r3, r4, epilogue + st r0, @r2 + st r1, @(4,r2) + +epilogue: + pop r0 + pop r1 + pop r2 + pop r3 + pop lr + pop fp + jmp lr + +.ffi_call_SYSV_end: + .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) diff --git a/js/src/ctypes/libffi/src/m68k/ffi.c b/js/src/ctypes/libffi/src/m68k/ffi.c new file mode 100644 index 0000000..600cf20 --- /dev/null +++ b/js/src/ctypes/libffi/src/m68k/ffi.c @@ -0,0 +1,278 @@ +/* ----------------------------------------------------------------------- + ffi.c + + m68k Foreign Function Interface + ----------------------------------------------------------------------- */ + +#include +#include + +#include +#include +#include +#include + +void ffi_call_SYSV (extended_cif *, + unsigned, unsigned, + void *, void (*fn) ()); +void *ffi_prep_args (void *stack, extended_cif *ecif); +void ffi_closure_SYSV (ffi_closure *); +void ffi_closure_struct_SYSV (ffi_closure *); +unsigned int ffi_closure_SYSV_inner (ffi_closure *closure, + void *resp, void *args); + +/* ffi_prep_args is called by the assembly routine once stack space has + been allocated for the function's arguments. */ + +void * +ffi_prep_args (void *stack, extended_cif *ecif) +{ + unsigned int i; + void **p_argv; + char *argp; + ffi_type **p_arg; + void *struct_value_ptr; + + argp = stack; + + if (ecif->cif->rtype->type == FFI_TYPE_STRUCT + && !ecif->cif->flags) + struct_value_ptr = ecif->rvalue; + else + struct_value_ptr = NULL; + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + i != 0; + i--, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + if (z < sizeof (int)) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int) *(SINT8 *) *p_argv; + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv; + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int) *(SINT16 *) *p_argv; + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv; + break; + + case FFI_TYPE_STRUCT: + memcpy (argp + sizeof (int) - z, *p_argv, z); + break; + + default: + FFI_ASSERT (0); + } + z = sizeof (int); + } + else + { + memcpy (argp, *p_argv, z); + + /* Align if necessary. */ + if ((sizeof(int) - 1) & z) + z = ALIGN(z, sizeof(int)); + } + + p_argv++; + argp += z; + } + + return struct_value_ptr; +} + +#define CIF_FLAGS_INT 1 +#define CIF_FLAGS_DINT 2 +#define CIF_FLAGS_FLOAT 4 +#define CIF_FLAGS_DOUBLE 8 +#define CIF_FLAGS_LDOUBLE 16 +#define CIF_FLAGS_POINTER 32 +#define CIF_FLAGS_STRUCT1 64 +#define CIF_FLAGS_STRUCT2 128 + +/* Perform machine dependent cif processing */ +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + cif->flags = 0; + break; + + case FFI_TYPE_STRUCT: + switch (cif->rtype->size) + { + case 1: + cif->flags = CIF_FLAGS_STRUCT1; + break; + case 2: + cif->flags = CIF_FLAGS_STRUCT2; + break; + case 4: + cif->flags = CIF_FLAGS_INT; + break; + case 8: + cif->flags = CIF_FLAGS_DINT; + break; + default: + cif->flags = 0; + break; + } + break; + + case FFI_TYPE_FLOAT: + cif->flags = CIF_FLAGS_FLOAT; + break; + + case FFI_TYPE_DOUBLE: + cif->flags = CIF_FLAGS_DOUBLE; + break; + + case FFI_TYPE_LONGDOUBLE: + cif->flags = CIF_FLAGS_LDOUBLE; + break; + + case FFI_TYPE_POINTER: + cif->flags = CIF_FLAGS_POINTER; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags = CIF_FLAGS_DINT; + break; + + default: + cif->flags = CIF_FLAGS_INT; + break; + } + + return FFI_OK; +} + +void +ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return value + address then we need to make one. */ + + if (rvalue == NULL + && cif->rtype->type == FFI_TYPE_STRUCT + && cif->rtype->size > 8) + ecif.rvalue = alloca (cif->rtype->size); + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: + ffi_call_SYSV (&ecif, cif->bytes, cif->flags, + ecif.rvalue, fn); + break; + + default: + FFI_ASSERT (0); + break; + } +} + +static void +ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif) +{ + unsigned int i; + void **p_argv; + char *argp; + ffi_type **p_arg; + + argp = stack; + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + if (z <= 4) + { + *p_argv = (void *) (argp + 4 - z); + + z = 4; + } + else + { + *p_argv = (void *) argp; + + /* Align if necessary */ + if ((sizeof(int) - 1) & z) + z = ALIGN(z, sizeof(int)); + } + + p_argv++; + argp += z; + } +} + +unsigned int +ffi_closure_SYSV_inner (ffi_closure *closure, void *resp, void *args) +{ + ffi_cif *cif; + void **arg_area; + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void *)); + + ffi_prep_incoming_args_SYSV(args, arg_area, cif); + + (closure->fun) (cif, resp, arg_area, closure->user_data); + + return cif->flags; +} + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) +{ + FFI_ASSERT (cif->abi == FFI_SYSV); + + *(unsigned short *)closure->tramp = 0x207c; + *(void **)(closure->tramp + 2) = codeloc; + *(unsigned short *)(closure->tramp + 6) = 0x4ef9; + if (cif->rtype->type == FFI_TYPE_STRUCT + && !cif->flags) + *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV; + else + *(void **)(closure->tramp + 8) = ffi_closure_SYSV; + + syscall(SYS_cacheflush, codeloc, FLUSH_SCOPE_LINE, + FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + diff --git a/js/src/ctypes/libffi/src/m68k/ffitarget.h b/js/src/ctypes/libffi/src/m68k/ffitarget.h new file mode 100644 index 0000000..3b777ed --- /dev/null +++ b/js/src/ctypes/libffi/src/m68k/ffitarget.h @@ -0,0 +1,49 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for Motorola 68K. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_SYSV +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 16 +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/js/src/ctypes/libffi/src/m68k/sysv.S b/js/src/ctypes/libffi/src/m68k/sysv.S new file mode 100644 index 0000000..58822e0 --- /dev/null +++ b/js/src/ctypes/libffi/src/m68k/sysv.S @@ -0,0 +1,234 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 1998 Andreas Schwab + Copyright (c) 2008 Red Hat, Inc. + + m68k Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include + +#ifdef HAVE_AS_CFI_PSEUDO_OP +#define CFI_STARTPROC() .cfi_startproc +#define CFI_OFFSET(reg,off) .cfi_offset reg,off +#define CFI_DEF_CFA(reg,off) .cfi_def_cfa reg,off +#define CFI_ENDPROC() .cfi_endproc +#else +#define CFI_STARTPROC() +#define CFI_OFFSET(reg,off) +#define CFI_DEF_CFA(reg,off) +#define CFI_ENDPROC() +#endif + + .text + + .globl ffi_call_SYSV + .type ffi_call_SYSV,@function + .align 4 + +ffi_call_SYSV: + CFI_STARTPROC() + link %fp,#0 + CFI_OFFSET(14,-8) + CFI_DEF_CFA(14,8) + move.l %d2,-(%sp) + CFI_OFFSET(2,-12) + + | Make room for all of the new args. + sub.l 12(%fp),%sp + + | Call ffi_prep_args + move.l 8(%fp),-(%sp) + pea 4(%sp) +#if !defined __PIC__ + jsr ffi_prep_args +#else + bsr.l ffi_prep_args@PLTPC +#endif + addq.l #8,%sp + + | Pass pointer to struct value, if any + move.l %a0,%a1 + + | Call the function + move.l 24(%fp),%a0 + jsr (%a0) + + | Remove the space we pushed for the args + add.l 12(%fp),%sp + + | Load the pointer to storage for the return value + move.l 20(%fp),%a1 + + | Load the return type code + move.l 16(%fp),%d2 + + | If the return value pointer is NULL, assume no return value. + tst.l %a1 + jbeq noretval + + btst #0,%d2 + jbeq retlongint + move.l %d0,(%a1) + jbra epilogue + +retlongint: + btst #1,%d2 + jbeq retfloat + move.l %d0,(%a1) + move.l %d1,4(%a1) + jbra epilogue + +retfloat: + btst #2,%d2 + jbeq retdouble + fmove.s %fp0,(%a1) + jbra epilogue + +retdouble: + btst #3,%d2 + jbeq retlongdouble + fmove.d %fp0,(%a1) + jbra epilogue + +retlongdouble: + btst #4,%d2 + jbeq retpointer + fmove.x %fp0,(%a1) + jbra epilogue + +retpointer: + btst #5,%d2 + jbeq retstruct1 + move.l %a0,(%a1) + jbra epilogue + +retstruct1: + btst #6,%d2 + jbeq retstruct2 + move.b %d0,(%a1) + jbra epilogue + +retstruct2: + btst #7,%d2 + jbeq noretval + move.w %d0,(%a1) + +noretval: +epilogue: + move.l (%sp)+,%d2 + unlk %fp + rts + CFI_ENDPROC() + .size ffi_call_SYSV,.-ffi_call_SYSV + + .globl ffi_closure_SYSV + .type ffi_closure_SYSV, @function + .align 4 + +ffi_closure_SYSV: + CFI_STARTPROC() + link %fp,#-12 + CFI_OFFSET(14,-8) + CFI_DEF_CFA(14,8) + move.l %sp,-12(%fp) + pea 8(%fp) + pea -12(%fp) + move.l %a0,-(%sp) +#if !defined __PIC__ + jsr ffi_closure_SYSV_inner +#else + bsr.l ffi_closure_SYSV_inner@PLTPC +#endif + + lsr.l #1,%d0 + jne 1f + jcc .Lcls_epilogue + move.l -12(%fp),%d0 +.Lcls_epilogue: + unlk %fp + rts +1: + lea -12(%fp),%a0 + lsr.l #2,%d0 + jne 1f + jcs .Lcls_ret_float + move.l (%a0)+,%d0 + move.l (%a0),%d1 + jra .Lcls_epilogue +.Lcls_ret_float: + fmove.s (%a0),%fp0 + jra .Lcls_epilogue +1: + lsr.l #2,%d0 + jne 1f + jcs .Lcls_ret_ldouble + fmove.d (%a0),%fp0 + jra .Lcls_epilogue +.Lcls_ret_ldouble: + fmove.x (%a0),%fp0 + jra .Lcls_epilogue +1: + lsr.l #2,%d0 + jne .Lcls_ret_struct2 + jcs .Lcls_ret_struct1 + move.l (%a0),%a0 + move.l %a0,%d0 + jra .Lcls_epilogue +.Lcls_ret_struct1: + move.b (%a0),%d0 + jra .Lcls_epilogue +.Lcls_ret_struct2: + move.w (%a0),%d0 + jra .Lcls_epilogue + CFI_ENDPROC() + + .size ffi_closure_SYSV,.-ffi_closure_SYSV + + .globl ffi_closure_struct_SYSV + .type ffi_closure_struct_SYSV, @function + .align 4 + +ffi_closure_struct_SYSV: + CFI_STARTPROC() + link %fp,#0 + CFI_OFFSET(14,-8) + CFI_DEF_CFA(14,8) + move.l %sp,-12(%fp) + pea 8(%fp) + move.l %a1,-(%sp) + move.l %a0,-(%sp) +#if !defined __PIC__ + jsr ffi_closure_SYSV_inner +#else + bsr.l ffi_closure_SYSV_inner@PLTPC +#endif + unlk %fp + rts + CFI_ENDPROC() + .size ffi_closure_struct_SYSV,.-ffi_closure_struct_SYSV + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/js/src/ctypes/libffi/src/mips/ffi.c b/js/src/ctypes/libffi/src/mips/ffi.c new file mode 100644 index 0000000..d714cc9 --- /dev/null +++ b/js/src/ctypes/libffi/src/mips/ffi.c @@ -0,0 +1,1029 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1996, 2007, 2008 Red Hat, Inc. + Copyright (c) 2008 David Daney + + MIPS Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include + +#ifdef __GNUC__ +# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) +# define USE__BUILTIN___CLEAR_CACHE 1 +# endif +#endif + +#ifndef USE__BUILTIN___CLEAR_CACHE +#include +#endif + +#ifdef FFI_DEBUG +# define FFI_MIPS_STOP_HERE() ffi_stop_here() +#else +# define FFI_MIPS_STOP_HERE() do {} while(0) +#endif + +#ifdef FFI_MIPS_N32 +#define FIX_ARGP \ +FFI_ASSERT(argp <= &stack[bytes]); \ +if (argp == &stack[bytes]) \ +{ \ + argp = stack; \ + FFI_MIPS_STOP_HERE(); \ +} +#else +#define FIX_ARGP +#endif + + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +static void ffi_prep_args(char *stack, + extended_cif *ecif, + int bytes, + int flags) +{ + int i; + void **p_argv; + char *argp; + ffi_type **p_arg; + +#ifdef FFI_MIPS_N32 + /* If more than 8 double words are used, the remainder go + on the stack. We reorder stuff on the stack here to + support this easily. */ + if (bytes > 8 * sizeof(ffi_arg)) + argp = &stack[bytes - (8 * sizeof(ffi_arg))]; + else + argp = stack; +#else + argp = stack; +#endif + + memset(stack, 0, bytes); + +#ifdef FFI_MIPS_N32 + if ( ecif->cif->rstruct_flag != 0 ) +#else + if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) +#endif + { + *(ffi_arg *) argp = (ffi_arg) ecif->rvalue; + argp += sizeof(ffi_arg); + FIX_ARGP; + } + + p_argv = ecif->avalue; + + for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs; i++, p_arg++) + { + size_t z; + unsigned int a; + + /* Align if necessary. */ + a = (*p_arg)->alignment; + if (a < sizeof(ffi_arg)) + a = sizeof(ffi_arg); + + if ((a - 1) & (unsigned long) argp) + { + argp = (char *) ALIGN(argp, a); + FIX_ARGP; + } + + z = (*p_arg)->size; + if (z <= sizeof(ffi_arg)) + { + int type = (*p_arg)->type; + z = sizeof(ffi_arg); + + /* The size of a pointer depends on the ABI */ + if (type == FFI_TYPE_POINTER) + type = (ecif->cif->abi == FFI_N64 + || ecif->cif->abi == FFI_N64_SOFT_FLOAT) + ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32; + + if (i < 8 && (ecif->cif->abi == FFI_N32_SOFT_FLOAT + || ecif->cif->abi == FFI_N64_SOFT_FLOAT)) + { + switch (type) + { + case FFI_TYPE_FLOAT: + type = FFI_TYPE_UINT32; + break; + case FFI_TYPE_DOUBLE: + type = FFI_TYPE_UINT64; + break; + default: + break; + } + } + switch (type) + { + case FFI_TYPE_SINT8: + *(ffi_arg *)argp = *(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(ffi_arg *)argp = *(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(ffi_arg *)argp = *(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(ffi_arg *)argp = *(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_SINT32: + *(ffi_arg *)argp = *(SINT32 *)(* p_argv); + break; + + case FFI_TYPE_UINT32: + *(ffi_arg *)argp = *(UINT32 *)(* p_argv); + break; + + /* This can only happen with 64bit slots. */ + case FFI_TYPE_FLOAT: + *(float *) argp = *(float *)(* p_argv); + break; + + /* Handle structures. */ + default: + memcpy(argp, *p_argv, (*p_arg)->size); + break; + } + } + else + { +#ifdef FFI_MIPS_O32 + memcpy(argp, *p_argv, z); +#else + { + unsigned long end = (unsigned long) argp + z; + unsigned long cap = (unsigned long) stack + bytes; + + /* Check if the data will fit within the register space. + Handle it if it doesn't. */ + + if (end <= cap) + memcpy(argp, *p_argv, z); + else + { + unsigned long portion = cap - (unsigned long)argp; + + memcpy(argp, *p_argv, portion); + argp = stack; + z -= portion; + memcpy(argp, (void*)((unsigned long)(*p_argv) + portion), + z); + } + } +#endif + } + p_argv++; + argp += z; + FIX_ARGP; + } +} + +#ifdef FFI_MIPS_N32 + +/* The n32 spec says that if "a chunk consists solely of a double + float field (but not a double, which is part of a union), it + is passed in a floating point register. Any other chunk is + passed in an integer register". This code traverses structure + definitions and generates the appropriate flags. */ + +static unsigned +calc_n32_struct_flags(int soft_float, ffi_type *arg, + unsigned *loc, unsigned *arg_reg) +{ + unsigned flags = 0; + unsigned index = 0; + + ffi_type *e; + + if (soft_float) + return 0; + + while ((e = arg->elements[index])) + { + /* Align this object. */ + *loc = ALIGN(*loc, e->alignment); + if (e->type == FFI_TYPE_DOUBLE) + { + /* Already aligned to FFI_SIZEOF_ARG. */ + *arg_reg = *loc / FFI_SIZEOF_ARG; + if (*arg_reg > 7) + break; + flags += (FFI_TYPE_DOUBLE << (*arg_reg * FFI_FLAG_BITS)); + *loc += e->size; + } + else + *loc += e->size; + index++; + } + /* Next Argument register at alignment of FFI_SIZEOF_ARG. */ + *arg_reg = ALIGN(*loc, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + + return flags; +} + +static unsigned +calc_n32_return_struct_flags(int soft_float, ffi_type *arg) +{ + unsigned flags = 0; + unsigned small = FFI_TYPE_SMALLSTRUCT; + ffi_type *e; + + /* Returning structures under n32 is a tricky thing. + A struct with only one or two floating point fields + is returned in $f0 (and $f2 if necessary). Any other + struct results at most 128 bits are returned in $2 + (the first 64 bits) and $3 (remainder, if necessary). + Larger structs are handled normally. */ + + if (arg->size > 16) + return 0; + + if (arg->size > 8) + small = FFI_TYPE_SMALLSTRUCT2; + + e = arg->elements[0]; + + if (e->type == FFI_TYPE_DOUBLE) + flags = FFI_TYPE_DOUBLE; + else if (e->type == FFI_TYPE_FLOAT) + flags = FFI_TYPE_FLOAT; + + if (flags && (e = arg->elements[1])) + { + if (e->type == FFI_TYPE_DOUBLE) + flags += FFI_TYPE_DOUBLE << FFI_FLAG_BITS; + else if (e->type == FFI_TYPE_FLOAT) + flags += FFI_TYPE_FLOAT << FFI_FLAG_BITS; + else + return small; + + if (flags && (arg->elements[2])) + { + /* There are three arguments and the first two are + floats! This must be passed the old way. */ + return small; + } + if (soft_float) + flags += FFI_TYPE_STRUCT_SOFT; + } + else + if (!flags) + return small; + + return flags; +} + +#endif + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + cif->flags = 0; + +#ifdef FFI_MIPS_O32 + /* Set the flags necessary for O32 processing. FFI_O32_SOFT_FLOAT + * does not have special handling for floating point args. + */ + + if (cif->rtype->type != FFI_TYPE_STRUCT && cif->abi == FFI_O32) + { + if (cif->nargs > 0) + { + switch ((cif->arg_types)[0]->type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags += (cif->arg_types)[0]->type; + break; + + default: + break; + } + + if (cif->nargs > 1) + { + /* Only handle the second argument if the first + is a float or double. */ + if (cif->flags) + { + switch ((cif->arg_types)[1]->type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags += (cif->arg_types)[1]->type << FFI_FLAG_BITS; + break; + + default: + break; + } + } + } + } + } + + /* Set the return type flag */ + + if (cif->abi == FFI_O32_SOFT_FLOAT) + { + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2); + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_DOUBLE: + cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2); + break; + + case FFI_TYPE_FLOAT: + default: + cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2); + break; + } + } + else + { + /* FFI_O32 */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2); + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2); + break; + + default: + cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2); + break; + } + } +#endif + +#ifdef FFI_MIPS_N32 + /* Set the flags necessary for N32 processing */ + { + int type; + unsigned arg_reg = 0; + unsigned loc = 0; + unsigned count = (cif->nargs < 8) ? cif->nargs : 8; + unsigned index = 0; + + unsigned struct_flags = 0; + int soft_float = (cif->abi == FFI_N32_SOFT_FLOAT + || cif->abi == FFI_N64_SOFT_FLOAT); + + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + struct_flags = calc_n32_return_struct_flags(soft_float, cif->rtype); + + if (struct_flags == 0) + { + /* This means that the structure is being passed as + a hidden argument */ + + arg_reg = 1; + count = (cif->nargs < 7) ? cif->nargs : 7; + + cif->rstruct_flag = !0; + } + else + cif->rstruct_flag = 0; + } + else + cif->rstruct_flag = 0; + + while (count-- > 0 && arg_reg < 8) + { + type = (cif->arg_types)[index]->type; + if (soft_float) + { + switch (type) + { + case FFI_TYPE_FLOAT: + type = FFI_TYPE_UINT32; + break; + case FFI_TYPE_DOUBLE: + type = FFI_TYPE_UINT64; + break; + default: + break; + } + } + switch (type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags += + ((cif->arg_types)[index]->type << (arg_reg * FFI_FLAG_BITS)); + arg_reg++; + break; + case FFI_TYPE_LONGDOUBLE: + /* Align it. */ + arg_reg = ALIGN(arg_reg, 2); + /* Treat it as two adjacent doubles. */ + if (soft_float) + { + arg_reg += 2; + } + else + { + cif->flags += + (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS)); + arg_reg++; + cif->flags += + (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS)); + arg_reg++; + } + break; + + case FFI_TYPE_STRUCT: + loc = arg_reg * FFI_SIZEOF_ARG; + cif->flags += calc_n32_struct_flags(soft_float, + (cif->arg_types)[index], + &loc, &arg_reg); + break; + + default: + arg_reg++; + break; + } + + index++; + } + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_STRUCT: + { + if (struct_flags == 0) + { + /* The structure is returned through a hidden + first argument. Do nothing, 'cause FFI_TYPE_VOID + is 0 */ + } + else + { + /* The structure is returned via some tricky + mechanism */ + cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8); + cif->flags += struct_flags << (4 + (FFI_FLAG_BITS * 8)); + } + break; + } + + case FFI_TYPE_VOID: + /* Do nothing, 'cause FFI_TYPE_VOID is 0 */ + break; + + case FFI_TYPE_POINTER: + if (cif->abi == FFI_N32_SOFT_FLOAT || cif->abi == FFI_N32) + cif->flags += FFI_TYPE_SINT32 << (FFI_FLAG_BITS * 8); + else + cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8); + break; + + case FFI_TYPE_FLOAT: + if (soft_float) + { + cif->flags += FFI_TYPE_SINT32 << (FFI_FLAG_BITS * 8); + break; + } + /* else fall through */ + case FFI_TYPE_DOUBLE: + if (soft_float) + cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8); + else + cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8); + break; + + case FFI_TYPE_LONGDOUBLE: + /* Long double is returned as if it were a struct containing + two doubles. */ + if (soft_float) + { + cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8); + cif->flags += FFI_TYPE_SMALLSTRUCT2 << (4 + (FFI_FLAG_BITS * 8)); + } + else + { + cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8); + cif->flags += (FFI_TYPE_DOUBLE + + (FFI_TYPE_DOUBLE << FFI_FLAG_BITS)) + << (4 + (FFI_FLAG_BITS * 8)); + } + break; + default: + cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8); + break; + } + } +#endif + + return FFI_OK; +} + +/* Low level routine for calling O32 functions */ +extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int), + extended_cif *, unsigned, + unsigned, unsigned *, void (*)(void)); + +/* Low level routine for calling N32 functions */ +extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int), + extended_cif *, unsigned, + unsigned, void *, void (*)(void)); + +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + ecif.rvalue = alloca(cif->rtype->size); + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { +#ifdef FFI_MIPS_O32 + case FFI_O32: + case FFI_O32_SOFT_FLOAT: + ffi_call_O32(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; +#endif + +#ifdef FFI_MIPS_N32 + case FFI_N32: + case FFI_N32_SOFT_FLOAT: + case FFI_N64: + case FFI_N64_SOFT_FLOAT: + { + int copy_rvalue = 0; + int copy_offset = 0; + char *rvalue_copy = ecif.rvalue; + if (cif->rtype->type == FFI_TYPE_STRUCT && cif->rtype->size < 16) + { + /* For structures smaller than 16 bytes we clobber memory + in 8 byte increments. Make a copy so we don't clobber + the callers memory outside of the struct bounds. */ + rvalue_copy = alloca(16); + copy_rvalue = 1; + } + else if (cif->rtype->type == FFI_TYPE_FLOAT + && (cif->abi == FFI_N64_SOFT_FLOAT + || cif->abi == FFI_N32_SOFT_FLOAT)) + { + rvalue_copy = alloca (8); + copy_rvalue = 1; +#if defined(__MIPSEB__) || defined(_MIPSEB) + copy_offset = 4; +#endif + } + ffi_call_N32(ffi_prep_args, &ecif, cif->bytes, + cif->flags, rvalue_copy, fn); + if (copy_rvalue) + memcpy(ecif.rvalue, rvalue_copy + copy_offset, cif->rtype->size); + } + break; +#endif + + default: + FFI_ASSERT(0); + break; + } +} + +#if FFI_CLOSURES +#if defined(FFI_MIPS_O32) +extern void ffi_closure_O32(void); +#else +extern void ffi_closure_N32(void); +#endif /* FFI_MIPS_O32 */ + +ffi_status +ffi_prep_closure_loc (ffi_closure *closure, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) +{ + unsigned int *tramp = (unsigned int *) &closure->tramp[0]; + void * fn; + char *clear_location = (char *) codeloc; + +#if defined(FFI_MIPS_O32) + FFI_ASSERT(cif->abi == FFI_O32 || cif->abi == FFI_O32_SOFT_FLOAT); + fn = ffi_closure_O32; +#else /* FFI_MIPS_N32 */ + FFI_ASSERT(cif->abi == FFI_N32 || cif->abi == FFI_N64); + fn = ffi_closure_N32; +#endif /* FFI_MIPS_O32 */ + +#if defined(FFI_MIPS_O32) || (_MIPS_SIM ==_ABIN32) + /* lui $25,high(fn) */ + tramp[0] = 0x3c190000 | ((unsigned)fn >> 16); + /* ori $25,low(fn) */ + tramp[1] = 0x37390000 | ((unsigned)fn & 0xffff); + /* lui $12,high(codeloc) */ + tramp[2] = 0x3c0c0000 | ((unsigned)codeloc >> 16); + /* jr $25 */ + tramp[3] = 0x03200008; + /* ori $12,low(codeloc) */ + tramp[4] = 0x358c0000 | ((unsigned)codeloc & 0xffff); +#else + /* N64 has a somewhat larger trampoline. */ + /* lui $25,high(fn) */ + tramp[0] = 0x3c190000 | ((unsigned long)fn >> 48); + /* lui $12,high(codeloc) */ + tramp[1] = 0x3c0c0000 | ((unsigned long)codeloc >> 48); + /* ori $25,mid-high(fn) */ + tramp[2] = 0x37390000 | (((unsigned long)fn >> 32 ) & 0xffff); + /* ori $12,mid-high(codeloc) */ + tramp[3] = 0x358c0000 | (((unsigned long)codeloc >> 32) & 0xffff); + /* dsll $25,$25,16 */ + tramp[4] = 0x0019cc38; + /* dsll $12,$12,16 */ + tramp[5] = 0x000c6438; + /* ori $25,mid-low(fn) */ + tramp[6] = 0x37390000 | (((unsigned long)fn >> 16 ) & 0xffff); + /* ori $12,mid-low(codeloc) */ + tramp[7] = 0x358c0000 | (((unsigned long)codeloc >> 16) & 0xffff); + /* dsll $25,$25,16 */ + tramp[8] = 0x0019cc38; + /* dsll $12,$12,16 */ + tramp[9] = 0x000c6438; + /* ori $25,low(fn) */ + tramp[10] = 0x37390000 | ((unsigned long)fn & 0xffff); + /* jr $25 */ + tramp[11] = 0x03200008; + /* ori $12,low(codeloc) */ + tramp[12] = 0x358c0000 | ((unsigned long)codeloc & 0xffff); + +#endif + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + +#ifdef USE__BUILTIN___CLEAR_CACHE + __builtin___clear_cache(clear_location, clear_location + FFI_TRAMPOLINE_SIZE); +#else + cacheflush (clear_location, FFI_TRAMPOLINE_SIZE, ICACHE); +#endif + return FFI_OK; +} + +/* + * Decodes the arguments to a function, which will be stored on the + * stack. AR is the pointer to the beginning of the integer arguments + * (and, depending upon the arguments, some floating-point arguments + * as well). FPR is a pointer to the area where floating point + * registers have been saved, if any. + * + * RVALUE is the location where the function return value will be + * stored. CLOSURE is the prepared closure to invoke. + * + * This function should only be called from assembly, which is in + * turn called from a trampoline. + * + * Returns the function return type. + * + * Based on the similar routine for sparc. + */ +int +ffi_closure_mips_inner_O32 (ffi_closure *closure, + void *rvalue, ffi_arg *ar, + double *fpr) +{ + ffi_cif *cif; + void **avaluep; + ffi_arg *avalue; + ffi_type **arg_types; + int i, avn, argn, seen_int; + + cif = closure->cif; + avalue = alloca (cif->nargs * sizeof (ffi_arg)); + avaluep = alloca (cif->nargs * sizeof (ffi_arg)); + + seen_int = (cif->abi == FFI_O32_SOFT_FLOAT); + argn = 0; + + if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_STRUCT) + { + rvalue = (void *)(UINT32)ar[0]; + argn = 1; + } + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + while (i < avn) + { + if (i < 2 && !seen_int && + (arg_types[i]->type == FFI_TYPE_FLOAT || + arg_types[i]->type == FFI_TYPE_DOUBLE || + arg_types[i]->type == FFI_TYPE_LONGDOUBLE)) + { +#if defined(__MIPSEB__) || defined(_MIPSEB) + if (arg_types[i]->type == FFI_TYPE_FLOAT) + avaluep[i] = ((char *) &fpr[i]) + sizeof (float); + else +#endif + avaluep[i] = (char *) &fpr[i]; + } + else + { + if (arg_types[i]->alignment == 8 && (argn & 0x1)) + argn++; + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + avaluep[i] = &avalue[i]; + *(SINT8 *) &avalue[i] = (SINT8) ar[argn]; + break; + + case FFI_TYPE_UINT8: + avaluep[i] = &avalue[i]; + *(UINT8 *) &avalue[i] = (UINT8) ar[argn]; + break; + + case FFI_TYPE_SINT16: + avaluep[i] = &avalue[i]; + *(SINT16 *) &avalue[i] = (SINT16) ar[argn]; + break; + + case FFI_TYPE_UINT16: + avaluep[i] = &avalue[i]; + *(UINT16 *) &avalue[i] = (UINT16) ar[argn]; + break; + + default: + avaluep[i] = (char *) &ar[argn]; + break; + } + seen_int = 1; + } + argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + i++; + } + + /* Invoke the closure. */ + (closure->fun) (cif, rvalue, avaluep, closure->user_data); + + if (cif->abi == FFI_O32_SOFT_FLOAT) + { + switch (cif->rtype->type) + { + case FFI_TYPE_FLOAT: + return FFI_TYPE_INT; + case FFI_TYPE_DOUBLE: + return FFI_TYPE_UINT64; + default: + return cif->rtype->type; + } + } + else + { + return cif->rtype->type; + } +} + +#if defined(FFI_MIPS_N32) + +static void +copy_struct_N32(char *target, unsigned offset, ffi_abi abi, ffi_type *type, + int argn, unsigned arg_offset, ffi_arg *ar, + ffi_arg *fpr, int soft_float) +{ + ffi_type **elt_typep = type->elements; + while(*elt_typep) + { + ffi_type *elt_type = *elt_typep; + unsigned o; + char *tp; + char *argp; + char *fpp; + + o = ALIGN(offset, elt_type->alignment); + arg_offset += o - offset; + offset = o; + argn += arg_offset / sizeof(ffi_arg); + arg_offset = arg_offset % sizeof(ffi_arg); + + argp = (char *)(ar + argn); + fpp = (char *)(argn >= 8 ? ar + argn : fpr + argn); + + tp = target + offset; + + if (elt_type->type == FFI_TYPE_DOUBLE && !soft_float) + *(double *)tp = *(double *)fpp; + else + memcpy(tp, argp + arg_offset, elt_type->size); + + offset += elt_type->size; + arg_offset += elt_type->size; + elt_typep++; + argn += arg_offset / sizeof(ffi_arg); + arg_offset = arg_offset % sizeof(ffi_arg); + } +} + +/* + * Decodes the arguments to a function, which will be stored on the + * stack. AR is the pointer to the beginning of the integer + * arguments. FPR is a pointer to the area where floating point + * registers have been saved. + * + * RVALUE is the location where the function return value will be + * stored. CLOSURE is the prepared closure to invoke. + * + * This function should only be called from assembly, which is in + * turn called from a trampoline. + * + * Returns the function return flags. + * + */ +int +ffi_closure_mips_inner_N32 (ffi_closure *closure, + void *rvalue, ffi_arg *ar, + ffi_arg *fpr) +{ + ffi_cif *cif; + void **avaluep; + ffi_arg *avalue; + ffi_type **arg_types; + int i, avn, argn; + int soft_float; + ffi_arg *argp; + + cif = closure->cif; + soft_float = cif->abi == FFI_N64_SOFT_FLOAT + || cif->abi == FFI_N32_SOFT_FLOAT; + avalue = alloca (cif->nargs * sizeof (ffi_arg)); + avaluep = alloca (cif->nargs * sizeof (ffi_arg)); + + argn = 0; + + if (cif->rstruct_flag) + { +#if _MIPS_SIM==_ABIN32 + rvalue = (void *)(UINT32)ar[0]; +#else /* N64 */ + rvalue = (void *)ar[0]; +#endif + argn = 1; + } + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + while (i < avn) + { + if (arg_types[i]->type == FFI_TYPE_FLOAT + || arg_types[i]->type == FFI_TYPE_DOUBLE + || arg_types[i]->type == FFI_TYPE_LONGDOUBLE) + { + argp = (argn >= 8 || soft_float) ? ar + argn : fpr + argn; + if ((arg_types[i]->type == FFI_TYPE_LONGDOUBLE) && ((unsigned)argp & (arg_types[i]->alignment-1))) + { + argp=(ffi_arg*)ALIGN(argp,arg_types[i]->alignment); + argn++; + } +#if defined(__MIPSEB__) || defined(_MIPSEB) + if (arg_types[i]->type == FFI_TYPE_FLOAT && argn < 8) + avaluep[i] = ((char *) argp) + sizeof (float); + else +#endif + avaluep[i] = (char *) argp; + } + else + { + unsigned type = arg_types[i]->type; + + if (arg_types[i]->alignment > sizeof(ffi_arg)) + argn = ALIGN(argn, arg_types[i]->alignment / sizeof(ffi_arg)); + + argp = ar + argn; + + /* The size of a pointer depends on the ABI */ + if (type == FFI_TYPE_POINTER) + type = (cif->abi == FFI_N64 || cif->abi == FFI_N64_SOFT_FLOAT) + ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32; + + if (soft_float && type == FFI_TYPE_FLOAT) + type = FFI_TYPE_UINT32; + + switch (type) + { + case FFI_TYPE_SINT8: + avaluep[i] = &avalue[i]; + *(SINT8 *) &avalue[i] = (SINT8) *argp; + break; + + case FFI_TYPE_UINT8: + avaluep[i] = &avalue[i]; + *(UINT8 *) &avalue[i] = (UINT8) *argp; + break; + + case FFI_TYPE_SINT16: + avaluep[i] = &avalue[i]; + *(SINT16 *) &avalue[i] = (SINT16) *argp; + break; + + case FFI_TYPE_UINT16: + avaluep[i] = &avalue[i]; + *(UINT16 *) &avalue[i] = (UINT16) *argp; + break; + + case FFI_TYPE_SINT32: + avaluep[i] = &avalue[i]; + *(SINT32 *) &avalue[i] = (SINT32) *argp; + break; + + case FFI_TYPE_UINT32: + avaluep[i] = &avalue[i]; + *(UINT32 *) &avalue[i] = (UINT32) *argp; + break; + + case FFI_TYPE_STRUCT: + if (argn < 8) + { + /* Allocate space for the struct as at least part of + it was passed in registers. */ + avaluep[i] = alloca(arg_types[i]->size); + copy_struct_N32(avaluep[i], 0, cif->abi, arg_types[i], + argn, 0, ar, fpr, soft_float); + + break; + } + /* Else fall through. */ + default: + avaluep[i] = (char *) argp; + break; + } + } + argn += ALIGN(arg_types[i]->size, sizeof(ffi_arg)) / sizeof(ffi_arg); + i++; + } + + /* Invoke the closure. */ + (closure->fun) (cif, rvalue, avaluep, closure->user_data); + + return cif->flags >> (FFI_FLAG_BITS * 8); +} + +#endif /* FFI_MIPS_N32 */ + +#endif /* FFI_CLOSURES */ diff --git a/js/src/ctypes/libffi/src/mips/ffitarget.h b/js/src/ctypes/libffi/src/mips/ffitarget.h new file mode 100644 index 0000000..d70197c --- /dev/null +++ b/js/src/ctypes/libffi/src/mips/ffitarget.h @@ -0,0 +1,234 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for MIPS. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifdef linux +# include +#else +# include +#endif +# ifndef _ABIN32 +# define _ABIN32 _MIPS_SIM_NABI32 +# endif +# ifndef _ABI64 +# define _ABI64 _MIPS_SIM_ABI64 +# endif +# ifndef _ABIO32 +# define _ABIO32 _MIPS_SIM_ABI32 +# endif + +#if !defined(_MIPS_SIM) +-- something is very wrong -- +#else +# if (_MIPS_SIM==_ABIN32 && defined(_ABIN32)) || (_MIPS_SIM==_ABI64 && defined(_ABI64)) +# define FFI_MIPS_N32 +# else +# if (_MIPS_SIM==_ABIO32 && defined(_ABIO32)) +# define FFI_MIPS_O32 +# else +-- this is an unsupported platform -- +# endif +# endif +#endif + +#ifdef FFI_MIPS_O32 +/* O32 stack frames have 32bit integer args */ +# define FFI_SIZEOF_ARG 4 +#else +/* N32 and N64 frames have 64bit integer args */ +# define FFI_SIZEOF_ARG 8 +# if _MIPS_SIM == _ABIN32 +# define FFI_SIZEOF_JAVA_RAW 4 +# endif +#endif + +#define FFI_FLAG_BITS 2 + +/* SGI's strange assembler requires that we multiply by 4 rather + than shift left by FFI_FLAG_BITS */ + +#define FFI_ARGS_D FFI_TYPE_DOUBLE +#define FFI_ARGS_F FFI_TYPE_FLOAT +#define FFI_ARGS_DD FFI_TYPE_DOUBLE * 4 + FFI_TYPE_DOUBLE +#define FFI_ARGS_FF FFI_TYPE_FLOAT * 4 + FFI_TYPE_FLOAT +#define FFI_ARGS_FD FFI_TYPE_DOUBLE * 4 + FFI_TYPE_FLOAT +#define FFI_ARGS_DF FFI_TYPE_FLOAT * 4 + FFI_TYPE_DOUBLE + +/* Needed for N32 structure returns */ +#define FFI_TYPE_SMALLSTRUCT FFI_TYPE_UINT8 +#define FFI_TYPE_SMALLSTRUCT2 FFI_TYPE_SINT8 + +#if 0 +/* The SGI assembler can't handle this.. */ +#define FFI_TYPE_STRUCT_DD (( FFI_ARGS_DD ) << 4) + FFI_TYPE_STRUCT +/* (and so on) */ +#else +/* ...so we calculate these by hand! */ +#define FFI_TYPE_STRUCT_D 61 +#define FFI_TYPE_STRUCT_F 45 +#define FFI_TYPE_STRUCT_DD 253 +#define FFI_TYPE_STRUCT_FF 173 +#define FFI_TYPE_STRUCT_FD 237 +#define FFI_TYPE_STRUCT_DF 189 +#define FFI_TYPE_STRUCT_SMALL 93 +#define FFI_TYPE_STRUCT_SMALL2 109 + +/* and for n32 soft float, add 16 * 2^4 */ +#define FFI_TYPE_STRUCT_D_SOFT 317 +#define FFI_TYPE_STRUCT_F_SOFT 301 +#define FFI_TYPE_STRUCT_DD_SOFT 509 +#define FFI_TYPE_STRUCT_FF_SOFT 429 +#define FFI_TYPE_STRUCT_FD_SOFT 493 +#define FFI_TYPE_STRUCT_DF_SOFT 445 +#define FFI_TYPE_STRUCT_SOFT 16 +#endif + +#ifdef LIBFFI_ASM +#define v0 $2 +#define v1 $3 +#define a0 $4 +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define a4 $8 +#define a5 $9 +#define a6 $10 +#define a7 $11 +#define t0 $8 +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 +#define t8 $24 +#define t9 $25 +#define ra $31 + +#ifdef FFI_MIPS_O32 +# define REG_L lw +# define REG_S sw +# define SUBU subu +# define ADDU addu +# define SRL srl +# define LI li +#else /* !FFI_MIPS_O32 */ +# define REG_L ld +# define REG_S sd +# define SUBU dsubu +# define ADDU daddu +# define SRL dsrl +# define LI dli +# if (_MIPS_SIM==_ABI64) +# define LA dla +# define EH_FRAME_ALIGN 3 +# define FDE_ADDR_BYTES .8byte +# else +# define LA la +# define EH_FRAME_ALIGN 2 +# define FDE_ADDR_BYTES .4byte +# endif /* _MIPS_SIM==_ABI64 */ +#endif /* !FFI_MIPS_O32 */ +#else /* !LIBFFI_ASM */ +# ifdef __GNUC__ +# ifdef FFI_MIPS_O32 +/* O32 stack frames have 32bit integer args */ +typedef unsigned int ffi_arg __attribute__((__mode__(__SI__))); +typedef signed int ffi_sarg __attribute__((__mode__(__SI__))); +#else +/* N32 and N64 frames have 64bit integer args */ +typedef unsigned int ffi_arg __attribute__((__mode__(__DI__))); +typedef signed int ffi_sarg __attribute__((__mode__(__DI__))); +# endif +# else +# ifdef FFI_MIPS_O32 +/* O32 stack frames have 32bit integer args */ +typedef __uint32_t ffi_arg; +typedef __int32_t ffi_sarg; +# else +/* N32 and N64 frames have 64bit integer args */ +typedef __uint64_t ffi_arg; +typedef __int64_t ffi_sarg; +# endif +# endif /* __GNUC__ */ + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_O32, + FFI_N32, + FFI_N64, + FFI_O32_SOFT_FLOAT, + FFI_N32_SOFT_FLOAT, + FFI_N64_SOFT_FLOAT, + FFI_LAST_ABI, + +#ifdef FFI_MIPS_O32 +#ifdef __mips_soft_float + FFI_DEFAULT_ABI = FFI_O32_SOFT_FLOAT +#else + FFI_DEFAULT_ABI = FFI_O32 +#endif +#else +# if _MIPS_SIM==_ABI64 +# ifdef __mips_soft_float + FFI_DEFAULT_ABI = FFI_N64_SOFT_FLOAT +# else + FFI_DEFAULT_ABI = FFI_N64 +# endif +# else +# ifdef __mips_soft_float + FFI_DEFAULT_ABI = FFI_N32_SOFT_FLOAT +# else + FFI_DEFAULT_ABI = FFI_N32 +# endif +# endif +#endif +} ffi_abi; + +#define FFI_EXTRA_CIF_FIELDS unsigned rstruct_flag +#endif /* !LIBFFI_ASM */ + +/* ---- Definitions for closures ----------------------------------------- */ + +#if defined(FFI_MIPS_O32) +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 20 +#else +/* N32/N64. */ +# define FFI_CLOSURES 1 +#if _MIPS_SIM==_ABI64 +#define FFI_TRAMPOLINE_SIZE 52 +#else +#define FFI_TRAMPOLINE_SIZE 20 +#endif +#endif /* FFI_MIPS_O32 */ +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/js/src/ctypes/libffi/src/mips/n32.S b/js/src/ctypes/libffi/src/mips/n32.S new file mode 100644 index 0000000..ae23094 --- /dev/null +++ b/js/src/ctypes/libffi/src/mips/n32.S @@ -0,0 +1,591 @@ +/* ----------------------------------------------------------------------- + n32.S - Copyright (c) 1996, 1998, 2005, 2007, 2009, 2010 Red Hat, Inc. + + MIPS Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include + +/* Only build this code if we are compiling for n32 */ + +#if defined(FFI_MIPS_N32) + +#define callback a0 +#define bytes a2 +#define flags a3 +#define raddr a4 +#define fn a5 + +#define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG ) + +#ifdef __GNUC__ + .abicalls +#endif + .text + .align 2 + .globl ffi_call_N32 + .ent ffi_call_N32 +ffi_call_N32: +.LFB3: + .frame $fp, SIZEOF_FRAME, ra + .mask 0xc0000000,-FFI_SIZEOF_ARG + .fmask 0x00000000,0 + + # Prologue + SUBU $sp, SIZEOF_FRAME # Frame size +.LCFI0: + REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer + REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address +.LCFI1: + move $fp, $sp +.LCFI3: + move t9, callback # callback function pointer + REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes + REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags + REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr + REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn + + # Allocate at least 4 words in the argstack + move v0, bytes + bge bytes, 4 * FFI_SIZEOF_ARG, bigger + LI v0, 4 * FFI_SIZEOF_ARG + b sixteen + + bigger: + ADDU t4, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned + and v0, t4, -2 * FFI_SIZEOF_ARG # to a proper boundry. + +sixteen: + SUBU $sp, $sp, v0 # move the stack pointer to reflect the + # arg space + + move a0, $sp # 4 * FFI_SIZEOF_ARG + ADDU a3, $fp, 3 * FFI_SIZEOF_ARG + + # Call ffi_prep_args + jal t9 + + # Copy the stack pointer to t9 + move t9, $sp + + # Fix the stack if there are more than 8 64bit slots worth + # of arguments. + + # Load the number of bytes + REG_L t6, 2*FFI_SIZEOF_ARG($fp) + + # Is it bigger than 8 * FFI_SIZEOF_ARG? + daddiu t8, t6, -(8 * FFI_SIZEOF_ARG) + bltz t8, loadregs + + ADDU t9, t9, t8 + +loadregs: + + REG_L t6, 3*FFI_SIZEOF_ARG($fp) # load the flags word into t6. + + and t4, t6, ((1< +#include + +/* Only build this code if we are compiling for o32 */ + +#if defined(FFI_MIPS_O32) + +#define callback a0 +#define bytes a2 +#define flags a3 + +#define SIZEOF_FRAME (4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG) +#define A3_OFF (SIZEOF_FRAME + 3 * FFI_SIZEOF_ARG) +#define FP_OFF (SIZEOF_FRAME - 2 * FFI_SIZEOF_ARG) +#define RA_OFF (SIZEOF_FRAME - 1 * FFI_SIZEOF_ARG) + + .abicalls + .text + .align 2 + .globl ffi_call_O32 + .ent ffi_call_O32 +ffi_call_O32: +$LFB0: + # Prologue + SUBU $sp, SIZEOF_FRAME # Frame size +$LCFI0: + REG_S $fp, FP_OFF($sp) # Save frame pointer +$LCFI1: + REG_S ra, RA_OFF($sp) # Save return address +$LCFI2: + move $fp, $sp + +$LCFI3: + move t9, callback # callback function pointer + REG_S flags, A3_OFF($fp) # flags + + # Allocate at least 4 words in the argstack + LI v0, 4 * FFI_SIZEOF_ARG + blt bytes, v0, sixteen + + ADDU v0, bytes, 7 # make sure it is aligned + and v0, -8 # to an 8 byte boundry + +sixteen: + SUBU $sp, v0 # move the stack pointer to reflect the + # arg space + + ADDU a0, $sp, 4 * FFI_SIZEOF_ARG + + jalr t9 + + REG_L t0, A3_OFF($fp) # load the flags word + SRL t2, t0, 4 # shift our arg info + and t0, ((1<<4)-1) # mask out the return type + + ADDU $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args + + bnez t0, pass_d # make it quick for int + REG_L a0, 0*FFI_SIZEOF_ARG($sp) # just go ahead and load the + REG_L a1, 1*FFI_SIZEOF_ARG($sp) # four regs. + REG_L a2, 2*FFI_SIZEOF_ARG($sp) + REG_L a3, 3*FFI_SIZEOF_ARG($sp) + b call_it + +pass_d: + bne t0, FFI_ARGS_D, pass_f + l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args + REG_L a2, 2*FFI_SIZEOF_ARG($sp) # passing a double + REG_L a3, 3*FFI_SIZEOF_ARG($sp) + b call_it + +pass_f: + bne t0, FFI_ARGS_F, pass_d_d + l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args + REG_L a1, 1*FFI_SIZEOF_ARG($sp) # passing a float + REG_L a2, 2*FFI_SIZEOF_ARG($sp) + REG_L a3, 3*FFI_SIZEOF_ARG($sp) + b call_it + +pass_d_d: + bne t0, FFI_ARGS_DD, pass_f_f + l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args + l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing two doubles + b call_it + +pass_f_f: + bne t0, FFI_ARGS_FF, pass_d_f + l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args + l.s $f14, 1*FFI_SIZEOF_ARG($sp) # passing two floats + REG_L a2, 2*FFI_SIZEOF_ARG($sp) + REG_L a3, 3*FFI_SIZEOF_ARG($sp) + b call_it + +pass_d_f: + bne t0, FFI_ARGS_DF, pass_f_d + l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args + l.s $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float + REG_L a3, 3*FFI_SIZEOF_ARG($sp) + b call_it + +pass_f_d: + # assume that the only other combination must be float then double + # bne t0, FFI_ARGS_F_D, call_it + l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args + l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float + +call_it: + # Load the function pointer + REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp) + + # If the return value pointer is NULL, assume no return value. + REG_L t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) + beqz t1, noretval + + bne t2, FFI_TYPE_INT, retlonglong + jalr t9 + REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) + REG_S v0, 0(t0) + b epilogue + +retlonglong: + # Really any 64-bit int, signed or not. + bne t2, FFI_TYPE_UINT64, retfloat + jalr t9 + REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) + REG_S v1, 4(t0) + REG_S v0, 0(t0) + b epilogue + +retfloat: + bne t2, FFI_TYPE_FLOAT, retdouble + jalr t9 + REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) + s.s $f0, 0(t0) + b epilogue + +retdouble: + bne t2, FFI_TYPE_DOUBLE, noretval + jalr t9 + REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) + s.d $f0, 0(t0) + b epilogue + +noretval: + jalr t9 + + # Epilogue +epilogue: + move $sp, $fp + REG_L $fp, FP_OFF($sp) # Restore frame pointer + REG_L ra, RA_OFF($sp) # Restore return address + ADDU $sp, SIZEOF_FRAME # Fix stack pointer + j ra + +$LFE0: + .end ffi_call_O32 + + +/* ffi_closure_O32. Expects address of the passed-in ffi_closure + in t4 ($12). Stores any arguments passed in registers onto the + stack, then calls ffi_closure_mips_inner_O32, which + then decodes them. + + Stack layout: + + 3 - a3 save + 2 - a2 save + 1 - a1 save + 0 - a0 save, original sp + -1 - ra save + -2 - fp save + -3 - $16 (s0) save + -4 - cprestore + -5 - return value high (v1) + -6 - return value low (v0) + -7 - f14 (le high, be low) + -8 - f14 (le low, be high) + -9 - f12 (le high, be low) + -10 - f12 (le low, be high) + -11 - Called function a3 save + -12 - Called function a2 save + -13 - Called function a1 save + -14 - Called function a0 save, our sp and fp point here + */ + +#define SIZEOF_FRAME2 (14 * FFI_SIZEOF_ARG) +#define A3_OFF2 (SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG) +#define A2_OFF2 (SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG) +#define A1_OFF2 (SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG) +#define A0_OFF2 (SIZEOF_FRAME2 + 0 * FFI_SIZEOF_ARG) +#define RA_OFF2 (SIZEOF_FRAME2 - 1 * FFI_SIZEOF_ARG) +#define FP_OFF2 (SIZEOF_FRAME2 - 2 * FFI_SIZEOF_ARG) +#define S0_OFF2 (SIZEOF_FRAME2 - 3 * FFI_SIZEOF_ARG) +#define GP_OFF2 (SIZEOF_FRAME2 - 4 * FFI_SIZEOF_ARG) +#define V1_OFF2 (SIZEOF_FRAME2 - 5 * FFI_SIZEOF_ARG) +#define V0_OFF2 (SIZEOF_FRAME2 - 6 * FFI_SIZEOF_ARG) +#define FA_1_1_OFF2 (SIZEOF_FRAME2 - 7 * FFI_SIZEOF_ARG) +#define FA_1_0_OFF2 (SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG) +#define FA_0_1_OFF2 (SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG) +#define FA_0_0_OFF2 (SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG) + + .text + .align 2 + .globl ffi_closure_O32 + .ent ffi_closure_O32 +ffi_closure_O32: +$LFB1: + # Prologue + .frame $fp, SIZEOF_FRAME2, ra + .set noreorder + .cpload t9 + .set reorder + SUBU $sp, SIZEOF_FRAME2 + .cprestore GP_OFF2 +$LCFI4: + REG_S $16, S0_OFF2($sp) # Save s0 + REG_S $fp, FP_OFF2($sp) # Save frame pointer + REG_S ra, RA_OFF2($sp) # Save return address +$LCFI6: + move $fp, $sp + +$LCFI7: + # Store all possible argument registers. If there are more than + # four arguments, then they are stored above where we put a3. + REG_S a0, A0_OFF2($fp) + REG_S a1, A1_OFF2($fp) + REG_S a2, A2_OFF2($fp) + REG_S a3, A3_OFF2($fp) + + # Load ABI enum to s0 + REG_L $16, 20($12) # cif pointer follows tramp. + REG_L $16, 0($16) # abi is first member. + + li $13, 1 # FFI_O32 + bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT + + # Store all possible float/double registers. + s.d $f12, FA_0_0_OFF2($fp) + s.d $f14, FA_1_0_OFF2($fp) +1: + # Call ffi_closure_mips_inner_O32 to do the work. + la t9, ffi_closure_mips_inner_O32 + move a0, $12 # Pointer to the ffi_closure + addu a1, $fp, V0_OFF2 + addu a2, $fp, A0_OFF2 + addu a3, $fp, FA_0_0_OFF2 + jalr t9 + + # Load the return value into the appropriate register. + move $8, $2 + li $9, FFI_TYPE_VOID + beq $8, $9, closure_done + + li $13, 1 # FFI_O32 + bne $16, $13, 1f # Skip fp restore if FFI_O32_SOFT_FLOAT + + li $9, FFI_TYPE_FLOAT + l.s $f0, V0_OFF2($fp) + beq $8, $9, closure_done + + li $9, FFI_TYPE_DOUBLE + l.d $f0, V0_OFF2($fp) + beq $8, $9, closure_done +1: + REG_L $3, V1_OFF2($fp) + REG_L $2, V0_OFF2($fp) + +closure_done: + # Epilogue + move $sp, $fp + REG_L $16, S0_OFF2($sp) # Restore s0 + REG_L $fp, FP_OFF2($sp) # Restore frame pointer + REG_L ra, RA_OFF2($sp) # Restore return address + ADDU $sp, SIZEOF_FRAME2 + j ra +$LFE1: + .end ffi_closure_O32 + +/* DWARF-2 unwind info. */ + + .section .eh_frame,"a",@progbits +$Lframe0: + .4byte $LECIE0-$LSCIE0 # Length of Common Information Entry +$LSCIE0: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version + .ascii "zR\0" # CIE Augmentation + .uleb128 0x1 # CIE Code Alignment Factor + .sleb128 4 # CIE Data Alignment Factor + .byte 0x1f # CIE RA Column + .uleb128 0x1 # Augmentation size + .byte 0x00 # FDE Encoding (absptr) + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1d + .uleb128 0x0 + .align 2 +$LECIE0: +$LSFDE0: + .4byte $LEFDE0-$LASFDE0 # FDE Length +$LASFDE0: + .4byte $LASFDE0-$Lframe0 # FDE CIE offset + .4byte $LFB0 # FDE initial location + .4byte $LFE0-$LFB0 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI0-$LFB0 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 0x18 + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI2-$LCFI0 + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x1e # $fp + .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x1f # $ra + .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI3-$LCFI2 + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1e + .uleb128 0x18 + .align 2 +$LEFDE0: +$LSFDE1: + .4byte $LEFDE1-$LASFDE1 # FDE Length +$LASFDE1: + .4byte $LASFDE1-$Lframe0 # FDE CIE offset + .4byte $LFB1 # FDE initial location + .4byte $LFE1-$LFB1 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI4-$LFB1 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 0x38 + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI6-$LCFI4 + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x10 # $16 + .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp) + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x1e # $fp + .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x1f # $ra + .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI7-$LCFI6 + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1e + .uleb128 0x38 + .align 2 +$LEFDE1: + +#endif diff --git a/js/src/ctypes/libffi/src/moxie/eabi.S b/js/src/ctypes/libffi/src/moxie/eabi.S new file mode 100644 index 0000000..379ea4b --- /dev/null +++ b/js/src/ctypes/libffi/src/moxie/eabi.S @@ -0,0 +1,128 @@ +/* ----------------------------------------------------------------------- + eabi.S - Copyright (c) 2004 Anthony Green + + FR-V Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include + + .globl ffi_prep_args_EABI + + .text + .p2align 4 + .globl ffi_call_EABI + .type ffi_call_EABI, @function + + # gr8 : ffi_prep_args + # gr9 : &ecif + # gr10: cif->bytes + # gr11: fig->flags + # gr12: ecif.rvalue + # gr13: fn + +ffi_call_EABI: + addi sp, #-80, sp + sti fp, @(sp, #24) + addi sp, #24, fp + movsg lr, gr5 + + /* Make room for the new arguments. */ + /* subi sp, fp, gr10 */ + + /* Store return address and incoming args on stack. */ + sti gr5, @(fp, #8) + sti gr8, @(fp, #-4) + sti gr9, @(fp, #-8) + sti gr10, @(fp, #-12) + sti gr11, @(fp, #-16) + sti gr12, @(fp, #-20) + sti gr13, @(fp, #-24) + + sub sp, gr10, sp + + /* Call ffi_prep_args. */ + ldi @(fp, #-4), gr4 + addi sp, #0, gr8 + ldi @(fp, #-8), gr9 +#ifdef __FRV_FDPIC__ + ldd @(gr4, gr0), gr14 + calll @(gr14, gr0) +#else + calll @(gr4, gr0) +#endif + + /* ffi_prep_args returns the new stack pointer. */ + mov gr8, gr4 + + ldi @(sp, #0), gr8 + ldi @(sp, #4), gr9 + ldi @(sp, #8), gr10 + ldi @(sp, #12), gr11 + ldi @(sp, #16), gr12 + ldi @(sp, #20), gr13 + + /* Always copy the return value pointer into the hidden + parameter register. This is only strictly necessary + when we're returning an aggregate type, but it doesn't + hurt to do this all the time, and it saves a branch. */ + ldi @(fp, #-20), gr3 + + /* Use the ffi_prep_args return value for the new sp. */ + mov gr4, sp + + /* Call the target function. */ + ldi @(fp, -24), gr4 +#ifdef __FRV_FDPIC__ + ldd @(gr4, gr0), gr14 + calll @(gr14, gr0) +#else + calll @(gr4, gr0) +#endif + + /* Store the result. */ + ldi @(fp, #-16), gr10 /* fig->flags */ + ldi @(fp, #-20), gr4 /* ecif.rvalue */ + + /* Is the return value stored in two registers? */ + cmpi gr10, #8, icc0 + bne icc0, 0, .L2 + /* Yes, save them. */ + sti gr8, @(gr4, #0) + sti gr9, @(gr4, #4) + bra .L3 +.L2: + /* Is the return value a structure? */ + cmpi gr10, #-1, icc0 + beq icc0, 0, .L3 + /* No, save a 4 byte return value. */ + sti gr8, @(gr4, #0) +.L3: + + /* Restore the stack, and return. */ + ldi @(fp, 8), gr5 + ld @(fp, gr0), fp + addi sp,#80,sp + jmpl @(gr5,gr0) + .size ffi_call_EABI, .-ffi_call_EABI + diff --git a/js/src/ctypes/libffi/src/moxie/ffi.c b/js/src/ctypes/libffi/src/moxie/ffi.c new file mode 100644 index 0000000..54cbbb9 --- /dev/null +++ b/js/src/ctypes/libffi/src/moxie/ffi.c @@ -0,0 +1,276 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (C) 2009 Anthony Green + + Moxie Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +void *ffi_prep_args(char *stack, extended_cif *ecif) +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + register int count = 0; + + p_argv = ecif->avalue; + argp = stack; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + (i != 0); + i--, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + + if ((*p_arg)->type == FFI_TYPE_STRUCT) + { + z = sizeof(void*); + *(void **) argp = *p_argv; + } + /* if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + if (count > 24) + { + // This is going on the stack. Turn it into a double. + *(double *) argp = (double) *(float*)(* p_argv); + z = sizeof(double); + } + else + *(void **) argp = *(void **)(* p_argv); + } */ + else if (z < sizeof(int)) + { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + } + else if (z == sizeof(int)) + { + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + } + else + { + memcpy(argp, *p_argv, z); + } + p_argv++; + argp += z; + count += z; + } + + return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8))); +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + if (cif->rtype->type == FFI_TYPE_STRUCT) + cif->flags = -1; + else + cif->flags = cif->rtype->size; + + cif->bytes = ALIGN (cif->bytes, 8); + + return FFI_OK; +} + +extern void ffi_call_EABI(void *(*)(char *, extended_cif *), + extended_cif *, + unsigned, unsigned, + unsigned *, + void (*fn)(void)); + +void ffi_call(ffi_cif *cif, + void (*fn)(void), + void *rvalue, + void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + ecif.rvalue = alloca(cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { + case FFI_EABI: + ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; + default: + FFI_ASSERT(0); + break; + } +} + +void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3, + unsigned arg4, unsigned arg5, unsigned arg6) +{ + /* This function is called by a trampoline. The trampoline stows a + pointer to the ffi_closure object in gr7. We must save this + pointer in a place that will persist while we do our work. */ + register ffi_closure *creg __asm__ ("gr7"); + ffi_closure *closure = creg; + + /* Arguments that don't fit in registers are found on the stack + at a fixed offset above the current frame pointer. */ + register char *frame_pointer __asm__ ("fp"); + char *stack_args = frame_pointer + 16; + + /* Lay the register arguments down in a continuous chunk of memory. */ + unsigned register_args[6] = + { arg1, arg2, arg3, arg4, arg5, arg6 }; + + ffi_cif *cif = closure->cif; + ffi_type **arg_types = cif->arg_types; + void **avalue = alloca (cif->nargs * sizeof(void *)); + char *ptr = (char *) register_args; + int i; + + /* Find the address of each argument. */ + for (i = 0; i < cif->nargs; i++) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = ptr + 3; + break; + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = ptr + 2; + break; + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_FLOAT: + avalue[i] = ptr; + break; + case FFI_TYPE_STRUCT: + avalue[i] = *(void**)ptr; + break; + default: + /* This is an 8-byte value. */ + avalue[i] = ptr; + ptr += 4; + break; + } + ptr += 4; + + /* If we've handled more arguments than fit in registers, + start looking at the those passed on the stack. */ + if (ptr == ((char *)register_args + (6*4))) + ptr = stack_args; + } + + /* Invoke the closure. */ + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + /* The caller allocates space for the return structure, and + passes a pointer to this space in gr3. Use this value directly + as the return value. */ + register void *return_struct_ptr __asm__("gr3"); + (closure->fun) (cif, return_struct_ptr, avalue, closure->user_data); + } + else + { + /* Allocate space for the return value and call the function. */ + long long rvalue; + (closure->fun) (cif, &rvalue, avalue, closure->user_data); + + /* Functions return 4-byte or smaller results in gr8. 8-byte + values also use gr9. We fill the both, even for small return + values, just to avoid a branch. */ + asm ("ldi @(%0, #0), gr8" : : "r" (&rvalue)); + asm ("ldi @(%0, #0), gr9" : : "r" (&((int *) &rvalue)[1])); + } +} + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc) +{ + unsigned int *tramp = (unsigned int *) &closure->tramp[0]; + unsigned long fn = (long) ffi_closure_eabi; + unsigned long cls = (long) codeloc; + int i; + + fn = (unsigned long) ffi_closure_eabi; + + tramp[0] = 0x8cfc0000 + (fn & 0xffff); /* setlos lo(fn), gr6 */ + tramp[1] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7 */ + tramp[2] = 0x8cf80000 + (fn >> 16); /* sethi hi(fn), gr6 */ + tramp[3] = 0x8ef80000 + (cls >> 16); /* sethi hi(cls), gr7 */ + tramp[4] = 0x80300006; /* jmpl @(gr0, gr6) */ + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* Cache flushing. */ + for (i = 0; i < FFI_TRAMPOLINE_SIZE; i++) + __asm__ volatile ("dcf @(%0,%1)\n\tici @(%2,%1)" :: "r" (tramp), "r" (i), + "r" (codeloc)); + + return FFI_OK; +} diff --git a/js/src/ctypes/libffi/src/moxie/ffitarget.h b/js/src/ctypes/libffi/src/moxie/ffitarget.h new file mode 100644 index 0000000..2a9d954 --- /dev/null +++ b/js/src/ctypes/libffi/src/moxie/ffitarget.h @@ -0,0 +1,52 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 2009 Anthony Green + Target configuration macros for Moxie + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- System specific configurations ----------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_EABI, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_EABI +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 0 +#define FFI_NATIVE_RAW_API 0 + +/* Trampolines are 5 4-byte instructions long. */ +#define FFI_TRAMPOLINE_SIZE (5*4) + +#endif diff --git a/js/src/ctypes/libffi/src/pa/ffi.c b/js/src/ctypes/libffi/src/pa/ffi.c new file mode 100644 index 0000000..6d7606f --- /dev/null +++ b/js/src/ctypes/libffi/src/pa/ffi.c @@ -0,0 +1,716 @@ +/* ----------------------------------------------------------------------- + ffi.c - (c) 2003-2004 Randolph Chung + (c) 2008 Red Hat, Inc. + + HPPA Foreign Function Interface + HP-UX PA ABI support (c) 2006 Free Software Foundation, Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include +#include + +#define ROUND_UP(v, a) (((size_t)(v) + (a) - 1) & ~((a) - 1)) + +#define MIN_STACK_SIZE 64 +#define FIRST_ARG_SLOT 9 +#define DEBUG_LEVEL 0 + +#define fldw(addr, fpreg) \ + __asm__ volatile ("fldw 0(%0), %%" #fpreg "L" : : "r"(addr) : #fpreg) +#define fstw(fpreg, addr) \ + __asm__ volatile ("fstw %%" #fpreg "L, 0(%0)" : : "r"(addr)) +#define fldd(addr, fpreg) \ + __asm__ volatile ("fldd 0(%0), %%" #fpreg : : "r"(addr) : #fpreg) +#define fstd(fpreg, addr) \ + __asm__ volatile ("fstd %%" #fpreg "L, 0(%0)" : : "r"(addr)) + +#define debug(lvl, x...) do { if (lvl <= DEBUG_LEVEL) { printf(x); } } while (0) + +static inline int ffi_struct_type(ffi_type *t) +{ + size_t sz = t->size; + + /* Small structure results are passed in registers, + larger ones are passed by pointer. Note that + small structures of size 2, 4 and 8 differ from + the corresponding integer types in that they have + different alignment requirements. */ + + if (sz <= 1) + return FFI_TYPE_UINT8; + else if (sz == 2) + return FFI_TYPE_SMALL_STRUCT2; + else if (sz == 3) + return FFI_TYPE_SMALL_STRUCT3; + else if (sz == 4) + return FFI_TYPE_SMALL_STRUCT4; + else if (sz == 5) + return FFI_TYPE_SMALL_STRUCT5; + else if (sz == 6) + return FFI_TYPE_SMALL_STRUCT6; + else if (sz == 7) + return FFI_TYPE_SMALL_STRUCT7; + else if (sz <= 8) + return FFI_TYPE_SMALL_STRUCT8; + else + return FFI_TYPE_STRUCT; /* else, we pass it by pointer. */ +} + +/* PA has a downward growing stack, which looks like this: + + Offset + [ Variable args ] + SP = (4*(n+9)) arg word N + ... + SP-52 arg word 4 + [ Fixed args ] + SP-48 arg word 3 + SP-44 arg word 2 + SP-40 arg word 1 + SP-36 arg word 0 + [ Frame marker ] + ... + SP-20 RP + SP-4 previous SP + + The first four argument words on the stack are reserved for use by + the callee. Instead, the general and floating registers replace + the first four argument slots. Non FP arguments are passed solely + in the general registers. FP arguments are passed in both general + and floating registers when using libffi. + + Non-FP 32-bit args are passed in gr26, gr25, gr24 and gr23. + Non-FP 64-bit args are passed in register pairs, starting + on an odd numbered register (i.e. r25+r26 and r23+r24). + FP 32-bit arguments are passed in fr4L, fr5L, fr6L and fr7L. + FP 64-bit arguments are passed in fr5 and fr7. + + The registers are allocated in the same manner as stack slots. + This allows the callee to save its arguments on the stack if + necessary: + + arg word 3 -> gr23 or fr7L + arg word 2 -> gr24 or fr6L or fr7R + arg word 1 -> gr25 or fr5L + arg word 0 -> gr26 or fr4L or fr5R + + Note that fr4R and fr6R are never used for arguments (i.e., + doubles are not passed in fr4 or fr6). + + The rest of the arguments are passed on the stack starting at SP-52, + but 64-bit arguments need to be aligned to an 8-byte boundary + + This means we can have holes either in the register allocation, + or in the stack. */ + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments + + The following code will put everything into the stack frame + (which was allocated by the asm routine), and on return + the asm routine will load the arguments that should be + passed by register into the appropriate registers + + NOTE: We load floating point args in this function... that means we + assume gcc will not mess with fp regs in here. */ + +void ffi_prep_args_pa32(UINT32 *stack, extended_cif *ecif, unsigned bytes) +{ + register unsigned int i; + register ffi_type **p_arg; + register void **p_argv; + unsigned int slot = FIRST_ARG_SLOT; + char *dest_cpy; + size_t len; + + debug(1, "%s: stack = %p, ecif = %p, bytes = %u\n", __FUNCTION__, stack, + ecif, bytes); + + p_arg = ecif->cif->arg_types; + p_argv = ecif->avalue; + + for (i = 0; i < ecif->cif->nargs; i++) + { + int type = (*p_arg)->type; + + switch (type) + { + case FFI_TYPE_SINT8: + *(SINT32 *)(stack - slot) = *(SINT8 *)(*p_argv); + break; + + case FFI_TYPE_UINT8: + *(UINT32 *)(stack - slot) = *(UINT8 *)(*p_argv); + break; + + case FFI_TYPE_SINT16: + *(SINT32 *)(stack - slot) = *(SINT16 *)(*p_argv); + break; + + case FFI_TYPE_UINT16: + *(UINT32 *)(stack - slot) = *(UINT16 *)(*p_argv); + break; + + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + debug(3, "Storing UINT32 %u in slot %u\n", *(UINT32 *)(*p_argv), + slot); + *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv); + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + /* Align slot for 64-bit type. */ + slot += (slot & 1) ? 1 : 2; + *(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv); + break; + + case FFI_TYPE_FLOAT: + /* First 4 args go in fr4L - fr7L. */ + debug(3, "Storing UINT32(float) in slot %u\n", slot); + *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv); + switch (slot - FIRST_ARG_SLOT) + { + /* First 4 args go in fr4L - fr7L. */ + case 0: fldw(stack - slot, fr4); break; + case 1: fldw(stack - slot, fr5); break; + case 2: fldw(stack - slot, fr6); break; + case 3: fldw(stack - slot, fr7); break; + } + break; + + case FFI_TYPE_DOUBLE: + /* Align slot for 64-bit type. */ + slot += (slot & 1) ? 1 : 2; + debug(3, "Storing UINT64(double) at slot %u\n", slot); + *(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv); + switch (slot - FIRST_ARG_SLOT) + { + /* First 2 args go in fr5, fr7. */ + case 1: fldd(stack - slot, fr5); break; + case 3: fldd(stack - slot, fr7); break; + } + break; + +#ifdef PA_HPUX + case FFI_TYPE_LONGDOUBLE: + /* Long doubles are passed in the same manner as structures + larger than 8 bytes. */ + *(UINT32 *)(stack - slot) = (UINT32)(*p_argv); + break; +#endif + + case FFI_TYPE_STRUCT: + + /* Structs smaller or equal than 4 bytes are passed in one + register. Structs smaller or equal 8 bytes are passed in two + registers. Larger structures are passed by pointer. */ + + len = (*p_arg)->size; + if (len <= 4) + { + dest_cpy = (char *)(stack - slot) + 4 - len; + memcpy(dest_cpy, (char *)*p_argv, len); + } + else if (len <= 8) + { + slot += (slot & 1) ? 1 : 2; + dest_cpy = (char *)(stack - slot) + 8 - len; + memcpy(dest_cpy, (char *)*p_argv, len); + } + else + *(UINT32 *)(stack - slot) = (UINT32)(*p_argv); + break; + + default: + FFI_ASSERT(0); + } + + slot++; + p_arg++; + p_argv++; + } + + /* Make sure we didn't mess up and scribble on the stack. */ + { + unsigned int n; + + debug(5, "Stack setup:\n"); + for (n = 0; n < (bytes + 3) / 4; n++) + { + if ((n%4) == 0) { debug(5, "\n%08x: ", (unsigned int)(stack - n)); } + debug(5, "%08x ", *(stack - n)); + } + debug(5, "\n"); + } + + FFI_ASSERT(slot * 4 <= bytes); + + return; +} + +static void ffi_size_stack_pa32(ffi_cif *cif) +{ + ffi_type **ptr; + int i; + int z = 0; /* # stack slots */ + + for (ptr = cif->arg_types, i = 0; i < cif->nargs; ptr++, i++) + { + int type = (*ptr)->type; + + switch (type) + { + case FFI_TYPE_DOUBLE: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + z += 2 + (z & 1); /* must start on even regs, so we may waste one */ + break; + +#ifdef PA_HPUX + case FFI_TYPE_LONGDOUBLE: +#endif + case FFI_TYPE_STRUCT: + z += 1; /* pass by ptr, callee will copy */ + break; + + default: /* <= 32-bit values */ + z++; + } + } + + /* We can fit up to 6 args in the default 64-byte stack frame, + if we need more, we need more stack. */ + if (z <= 6) + cif->bytes = MIN_STACK_SIZE; /* min stack size */ + else + cif->bytes = 64 + ROUND_UP((z - 6) * sizeof(UINT32), MIN_STACK_SIZE); + + debug(3, "Calculated stack size is %u bytes\n", cif->bytes); +} + +/* Perform machine dependent cif processing. */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags = (unsigned) cif->rtype->type; + break; + +#ifdef PA_HPUX + case FFI_TYPE_LONGDOUBLE: + /* Long doubles are treated like a structure. */ + cif->flags = FFI_TYPE_STRUCT; + break; +#endif + + case FFI_TYPE_STRUCT: + /* For the return type we have to check the size of the structures. + If the size is smaller or equal 4 bytes, the result is given back + in one register. If the size is smaller or equal 8 bytes than we + return the result in two registers. But if the size is bigger than + 8 bytes, we work with pointers. */ + cif->flags = ffi_struct_type(cif->rtype); + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + cif->flags = FFI_TYPE_UINT64; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + /* Lucky us, because of the unique PA ABI we get to do our + own stack sizing. */ + switch (cif->abi) + { + case FFI_PA32: + ffi_size_stack_pa32(cif); + break; + + default: + FFI_ASSERT(0); + break; + } + + return FFI_OK; +} + +extern void ffi_call_pa32(void (*)(UINT32 *, extended_cif *, unsigned), + extended_cif *, unsigned, unsigned, unsigned *, + void (*fn)(void)); + +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return + value address then we need to make one. */ + + if (rvalue == NULL +#ifdef PA_HPUX + && (cif->rtype->type == FFI_TYPE_STRUCT + || cif->rtype->type == FFI_TYPE_LONGDOUBLE)) +#else + && cif->rtype->type == FFI_TYPE_STRUCT) +#endif + { + ecif.rvalue = alloca(cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { + case FFI_PA32: + debug(3, "Calling ffi_call_pa32: ecif=%p, bytes=%u, flags=%u, rvalue=%p, fn=%p\n", &ecif, cif->bytes, cif->flags, ecif.rvalue, (void *)fn); + ffi_call_pa32(ffi_prep_args_pa32, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; + + default: + FFI_ASSERT(0); + break; + } +} + +#if FFI_CLOSURES +/* This is more-or-less an inverse of ffi_call -- we have arguments on + the stack, and we need to fill them into a cif structure and invoke + the user function. This really ought to be in asm to make sure + the compiler doesn't do things we don't expect. */ +ffi_status ffi_closure_inner_pa32(ffi_closure *closure, UINT32 *stack) +{ + ffi_cif *cif; + void **avalue; + void *rvalue; + UINT32 ret[2]; /* function can return up to 64-bits in registers */ + ffi_type **p_arg; + char *tmp; + int i, avn; + unsigned int slot = FIRST_ARG_SLOT; + register UINT32 r28 asm("r28"); + + cif = closure->cif; + + /* If returning via structure, callee will write to our pointer. */ + if (cif->flags == FFI_TYPE_STRUCT) + rvalue = (void *)r28; + else + rvalue = &ret[0]; + + avalue = (void **)alloca(cif->nargs * FFI_SIZEOF_ARG); + avn = cif->nargs; + p_arg = cif->arg_types; + + for (i = 0; i < avn; i++) + { + int type = (*p_arg)->type; + + switch (type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + avalue[i] = (char *)(stack - slot) + sizeof(UINT32) - (*p_arg)->size; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + slot += (slot & 1) ? 1 : 2; + avalue[i] = (void *)(stack - slot); + break; + + case FFI_TYPE_FLOAT: +#ifdef PA_LINUX + /* The closure call is indirect. In Linux, floating point + arguments in indirect calls with a prototype are passed + in the floating point registers instead of the general + registers. So, we need to replace what was previously + stored in the current slot with the value in the + corresponding floating point register. */ + switch (slot - FIRST_ARG_SLOT) + { + case 0: fstw(fr4, (void *)(stack - slot)); break; + case 1: fstw(fr5, (void *)(stack - slot)); break; + case 2: fstw(fr6, (void *)(stack - slot)); break; + case 3: fstw(fr7, (void *)(stack - slot)); break; + } +#endif + avalue[i] = (void *)(stack - slot); + break; + + case FFI_TYPE_DOUBLE: + slot += (slot & 1) ? 1 : 2; +#ifdef PA_LINUX + /* See previous comment for FFI_TYPE_FLOAT. */ + switch (slot - FIRST_ARG_SLOT) + { + case 1: fstd(fr5, (void *)(stack - slot)); break; + case 3: fstd(fr7, (void *)(stack - slot)); break; + } +#endif + avalue[i] = (void *)(stack - slot); + break; + +#ifdef PA_HPUX + case FFI_TYPE_LONGDOUBLE: + /* Long doubles are treated like a big structure. */ + avalue[i] = (void *) *(stack - slot); + break; +#endif + + case FFI_TYPE_STRUCT: + /* Structs smaller or equal than 4 bytes are passed in one + register. Structs smaller or equal 8 bytes are passed in two + registers. Larger structures are passed by pointer. */ + if((*p_arg)->size <= 4) + { + avalue[i] = (void *)(stack - slot) + sizeof(UINT32) - + (*p_arg)->size; + } + else if ((*p_arg)->size <= 8) + { + slot += (slot & 1) ? 1 : 2; + avalue[i] = (void *)(stack - slot) + sizeof(UINT64) - + (*p_arg)->size; + } + else + avalue[i] = (void *) *(stack - slot); + break; + + default: + FFI_ASSERT(0); + } + + slot++; + p_arg++; + } + + /* Invoke the closure. */ + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", ret[0], + ret[1]); + + /* Store the result using the lower 2 bytes of the flags. */ + switch (cif->flags) + { + case FFI_TYPE_UINT8: + *(stack - FIRST_ARG_SLOT) = (UINT8)(ret[0] >> 24); + break; + case FFI_TYPE_SINT8: + *(stack - FIRST_ARG_SLOT) = (SINT8)(ret[0] >> 24); + break; + case FFI_TYPE_UINT16: + *(stack - FIRST_ARG_SLOT) = (UINT16)(ret[0] >> 16); + break; + case FFI_TYPE_SINT16: + *(stack - FIRST_ARG_SLOT) = (SINT16)(ret[0] >> 16); + break; + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + *(stack - FIRST_ARG_SLOT) = ret[0]; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + *(stack - FIRST_ARG_SLOT) = ret[0]; + *(stack - FIRST_ARG_SLOT - 1) = ret[1]; + break; + + case FFI_TYPE_DOUBLE: + fldd(rvalue, fr4); + break; + + case FFI_TYPE_FLOAT: + fldw(rvalue, fr4); + break; + + case FFI_TYPE_STRUCT: + /* Don't need a return value, done by caller. */ + break; + + case FFI_TYPE_SMALL_STRUCT2: + case FFI_TYPE_SMALL_STRUCT3: + case FFI_TYPE_SMALL_STRUCT4: + tmp = (void*)(stack - FIRST_ARG_SLOT); + tmp += 4 - cif->rtype->size; + memcpy((void*)tmp, &ret[0], cif->rtype->size); + break; + + case FFI_TYPE_SMALL_STRUCT5: + case FFI_TYPE_SMALL_STRUCT6: + case FFI_TYPE_SMALL_STRUCT7: + case FFI_TYPE_SMALL_STRUCT8: + { + unsigned int ret2[2]; + int off; + + /* Right justify ret[0] and ret[1] */ + switch (cif->flags) + { + case FFI_TYPE_SMALL_STRUCT5: off = 3; break; + case FFI_TYPE_SMALL_STRUCT6: off = 2; break; + case FFI_TYPE_SMALL_STRUCT7: off = 1; break; + default: off = 0; break; + } + + memset (ret2, 0, sizeof (ret2)); + memcpy ((char *)ret2 + off, ret, 8 - off); + + *(stack - FIRST_ARG_SLOT) = ret2[0]; + *(stack - FIRST_ARG_SLOT - 1) = ret2[1]; + } + break; + + case FFI_TYPE_POINTER: + case FFI_TYPE_VOID: + break; + + default: + debug(0, "assert with cif->flags: %d\n",cif->flags); + FFI_ASSERT(0); + break; + } + return FFI_OK; +} + +/* Fill in a closure to refer to the specified fun and user_data. + cif specifies the argument and result types for fun. + The cif must already be prep'ed. */ + +extern void ffi_closure_pa32(void); + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) +{ + UINT32 *tramp = (UINT32 *)(closure->tramp); +#ifdef PA_HPUX + UINT32 *tmp; +#endif + + FFI_ASSERT (cif->abi == FFI_PA32); + + /* Make a small trampoline that will branch to our + handler function. Use PC-relative addressing. */ + +#ifdef PA_LINUX + tramp[0] = 0xeaa00000; /* b,l .+8,%r21 ; %r21 <- pc+8 */ + tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21 ; mask priv bits */ + tramp[2] = 0x4aa10028; /* ldw 20(%r21),%r1 ; load plabel */ + tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21 ; get closure addr */ + tramp[4] = 0x0c201096; /* ldw 0(%r1),%r22 ; address of handler */ + tramp[5] = 0xeac0c000; /* bv%r0(%r22) ; branch to handler */ + tramp[6] = 0x0c281093; /* ldw 4(%r1),%r19 ; GP of handler */ + tramp[7] = ((UINT32)(ffi_closure_pa32) & ~2); + + /* Flush d/icache -- have to flush up 2 two lines because of + alignment. */ + __asm__ volatile( + "fdc 0(%0)\n\t" + "fdc %1(%0)\n\t" + "fic 0(%%sr4, %0)\n\t" + "fic %1(%%sr4, %0)\n\t" + "sync\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n" + : + : "r"((unsigned long)tramp & ~31), + "r"(32 /* stride */) + : "memory"); +#endif + +#ifdef PA_HPUX + tramp[0] = 0xeaa00000; /* b,l .+8,%r21 ; %r21 <- pc+8 */ + tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21 ; mask priv bits */ + tramp[2] = 0x4aa10038; /* ldw 28(%r21),%r1 ; load plabel */ + tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21 ; get closure addr */ + tramp[4] = 0x0c201096; /* ldw 0(%r1),%r22 ; address of handler */ + tramp[5] = 0x02c010b4; /* ldsid (%r22),%r20 ; load space id */ + tramp[6] = 0x00141820; /* mtsp %r20,%sr0 ; into %sr0 */ + tramp[7] = 0xe2c00000; /* be 0(%sr0,%r22) ; branch to handler */ + tramp[8] = 0x0c281093; /* ldw 4(%r1),%r19 ; GP of handler */ + tramp[9] = ((UINT32)(ffi_closure_pa32) & ~2); + + /* Flush d/icache -- have to flush three lines because of alignment. */ + __asm__ volatile( + "copy %1,%0\n\t" + "fdc,m %2(%0)\n\t" + "fdc,m %2(%0)\n\t" + "fdc,m %2(%0)\n\t" + "ldsid (%1),%0\n\t" + "mtsp %0,%%sr0\n\t" + "copy %1,%0\n\t" + "fic,m %2(%%sr0,%0)\n\t" + "fic,m %2(%%sr0,%0)\n\t" + "fic,m %2(%%sr0,%0)\n\t" + "sync\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n" + : "=&r" ((unsigned long)tmp) + : "r" ((unsigned long)tramp & ~31), + "r" (32/* stride */) + : "memory"); +#endif + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} +#endif diff --git a/js/src/ctypes/libffi/src/pa/ffitarget.h b/js/src/ctypes/libffi/src/pa/ffitarget.h new file mode 100644 index 0000000..efa2f4e --- /dev/null +++ b/js/src/ctypes/libffi/src/pa/ffitarget.h @@ -0,0 +1,78 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for hppa. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- System specific configurations ----------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + +#ifdef PA_LINUX + FFI_PA32, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_PA32 +#endif + +#ifdef PA_HPUX + FFI_PA32, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_PA32 +#endif + +#ifdef PA64_HPUX +#error "PA64_HPUX FFI is not yet implemented" + FFI_PA64, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_PA64 +#endif +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 + +#ifdef PA_LINUX +#define FFI_TRAMPOLINE_SIZE 32 +#else +#define FFI_TRAMPOLINE_SIZE 40 +#endif + +#define FFI_TYPE_SMALL_STRUCT2 -1 +#define FFI_TYPE_SMALL_STRUCT3 -2 +#define FFI_TYPE_SMALL_STRUCT4 -3 +#define FFI_TYPE_SMALL_STRUCT5 -4 +#define FFI_TYPE_SMALL_STRUCT6 -5 +#define FFI_TYPE_SMALL_STRUCT7 -6 +#define FFI_TYPE_SMALL_STRUCT8 -7 +#endif diff --git a/js/src/ctypes/libffi/src/pa/hpux32.S b/js/src/ctypes/libffi/src/pa/hpux32.S new file mode 100644 index 0000000..40528ba --- /dev/null +++ b/js/src/ctypes/libffi/src/pa/hpux32.S @@ -0,0 +1,368 @@ +/* ----------------------------------------------------------------------- + hpux32.S - Copyright (c) 2006 Free Software Foundation, Inc. + (c) 2008 Red Hat, Inc. + based on src/pa/linux.S + + HP-UX PA Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include + + .LEVEL 1.1 + .SPACE $PRIVATE$ + .IMPORT $global$,DATA + .IMPORT $$dyncall,MILLICODE + .SUBSPA $DATA$ + .align 4 + + /* void ffi_call_pa32(void (*)(char *, extended_cif *), + extended_cif *ecif, + unsigned bytes, + unsigned flags, + unsigned *rvalue, + void (*fn)(void)); + */ + + .export ffi_call_pa32,ENTRY,PRIV_LEV=3 + .import ffi_prep_args_pa32,CODE + + .SPACE $TEXT$ + .SUBSPA $CODE$ + .align 4 + +L$FB1 +ffi_call_pa32 + .proc + .callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=4 + .entry + stw %rp, -20(%sp) + copy %r3, %r1 +L$CFI11 + copy %sp, %r3 +L$CFI12 + + /* Setup the stack for calling prep_args... + We want the stack to look like this: + + [ Previous stack ] <- %r3 + + [ 64-bytes register save area ] <- %r4 + + [ Stack space for actual call, passed as ] <- %arg0 + [ arg0 to ffi_prep_args_pa32 ] + + [ Stack for calling prep_args ] <- %sp + */ + + stwm %r1, 64(%sp) + stw %r4, 12(%r3) +L$CFI13 + copy %sp, %r4 + + addl %arg2, %r4, %arg0 ; arg stack + stw %arg3, -48(%r3) ; save flags we need it later + + /* Call prep_args: + %arg0(stack) -- set up above + %arg1(ecif) -- same as incoming param + %arg2(bytes) -- same as incoming param */ + bl ffi_prep_args_pa32,%r2 + ldo 64(%arg0), %sp + ldo -64(%sp), %sp + + /* now %sp should point where %arg0 was pointing. */ + + /* Load the arguments that should be passed in registers + The fp args are loaded by the prep_args function. */ + ldw -36(%sp), %arg0 + ldw -40(%sp), %arg1 + ldw -44(%sp), %arg2 + ldw -48(%sp), %arg3 + + /* in case the function is going to return a structure + we need to give it a place to put the result. */ + ldw -52(%r3), %ret0 ; %ret0 <- rvalue + ldw -56(%r3), %r22 ; %r22 <- function to call + bl $$dyncall, %r31 ; Call the user function + copy %r31, %rp + + /* Prepare to store the result; we need to recover flags and rvalue. */ + ldw -48(%r3), %r21 ; r21 <- flags + ldw -52(%r3), %r20 ; r20 <- rvalue + + /* Store the result according to the return type. The most + likely types should come first. */ + +L$checkint + comib,<>,n FFI_TYPE_INT, %r21, L$checkint8 + b L$done + stw %ret0, 0(%r20) + +L$checkint8 + comib,<>,n FFI_TYPE_UINT8, %r21, L$checkint16 + b L$done + stb %ret0, 0(%r20) + +L$checkint16 + comib,<>,n FFI_TYPE_UINT16, %r21, L$checkdbl + b L$done + sth %ret0, 0(%r20) + +L$checkdbl + comib,<>,n FFI_TYPE_DOUBLE, %r21, L$checkfloat + b L$done + fstd %fr4,0(%r20) + +L$checkfloat + comib,<>,n FFI_TYPE_FLOAT, %r21, L$checkll + b L$done + fstw %fr4L,0(%r20) + +L$checkll + comib,<>,n FFI_TYPE_UINT64, %r21, L$checksmst2 + stw %ret0, 0(%r20) + b L$done + stw %ret1, 4(%r20) + +L$checksmst2 + comib,<>,n FFI_TYPE_SMALL_STRUCT2, %r21, L$checksmst3 + /* 2-byte structs are returned in ret0 as ????xxyy. */ + extru %ret0, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + b L$done + stb %ret0, 0(%r20) + +L$checksmst3 + comib,<>,n FFI_TYPE_SMALL_STRUCT3, %r21, L$checksmst4 + /* 3-byte structs are returned in ret0 as ??xxyyzz. */ + extru %ret0, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret0, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + b L$done + stb %ret0, 0(%r20) + +L$checksmst4 + comib,<>,n FFI_TYPE_SMALL_STRUCT4, %r21, L$checksmst5 + /* 4-byte structs are returned in ret0 as wwxxyyzz. */ + extru %ret0, 7, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret0, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret0, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + b L$done + stb %ret0, 0(%r20) + +L$checksmst5 + comib,<>,n FFI_TYPE_SMALL_STRUCT5, %r21, L$checksmst6 + /* 5 byte values are returned right justified: + ret0 ret1 + 5: ??????aa bbccddee */ + stbs,ma %ret0, 1(%r20) + extru %ret1, 7, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + b L$done + stb %ret1, 0(%r20) + +L$checksmst6 + comib,<>,n FFI_TYPE_SMALL_STRUCT6, %r21, L$checksmst7 + /* 6 byte values are returned right justified: + ret0 ret1 + 6: ????aabb ccddeeff */ + extru %ret0, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + stbs,ma %ret0, 1(%r20) + extru %ret1, 7, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + b L$done + stb %ret1, 0(%r20) + +L$checksmst7 + comib,<>,n FFI_TYPE_SMALL_STRUCT7, %r21, L$checksmst8 + /* 7 byte values are returned right justified: + ret0 ret1 + 7: ??aabbcc ddeeffgg */ + extru %ret0, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret0, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + stbs,ma %ret0, 1(%r20) + extru %ret1, 7, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + b L$done + stb %ret1, 0(%r20) + +L$checksmst8 + comib,<>,n FFI_TYPE_SMALL_STRUCT8, %r21, L$done + /* 8 byte values are returned right justified: + ret0 ret1 + 8: aabbccdd eeffgghh */ + extru %ret0, 7, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret0, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret0, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + stbs,ma %ret0, 1(%r20) + extru %ret1, 7, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + stb %ret1, 0(%r20) + +L$done + /* all done, return */ + copy %r4, %sp ; pop arg stack + ldw 12(%r3), %r4 + ldwm -64(%sp), %r3 ; .. and pop stack + ldw -20(%sp), %rp + bv %r0(%rp) + nop + .exit + .procend +L$FE1 + + /* void ffi_closure_pa32(void); + Called with closure argument in %r21 */ + + .SPACE $TEXT$ + .SUBSPA $CODE$ + .export ffi_closure_pa32,ENTRY,PRIV_LEV=3,RTNVAL=GR + .import ffi_closure_inner_pa32,CODE + .align 4 +L$FB2 +ffi_closure_pa32 + .proc + .callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3 + .entry + + stw %rp, -20(%sp) + copy %r3, %r1 +L$CFI21 + copy %sp, %r3 +L$CFI22 + stwm %r1, 64(%sp) + + /* Put arguments onto the stack and call ffi_closure_inner. */ + stw %arg0, -36(%r3) + stw %arg1, -40(%r3) + stw %arg2, -44(%r3) + stw %arg3, -48(%r3) + + copy %r21, %arg0 + bl ffi_closure_inner_pa32, %r2 + copy %r3, %arg1 + ldwm -64(%sp), %r3 + ldw -20(%sp), %rp + ldw -36(%sp), %ret0 + bv %r0(%rp) + ldw -40(%sp), %ret1 + .exit + .procend +L$FE2: + + .SPACE $PRIVATE$ + .SUBSPA $DATA$ + + .align 4 + .EXPORT _GLOBAL__F_ffi_call_pa32,DATA +_GLOBAL__F_ffi_call_pa32 +L$frame1: + .word L$ECIE1-L$SCIE1 ;# Length of Common Information Entry +L$SCIE1: + .word 0x0 ;# CIE Identifier Tag + .byte 0x1 ;# CIE Version + .ascii "\0" ;# CIE Augmentation + .uleb128 0x1 ;# CIE Code Alignment Factor + .sleb128 4 ;# CIE Data Alignment Factor + .byte 0x2 ;# CIE RA Column + .byte 0xc ;# DW_CFA_def_cfa + .uleb128 0x1e + .uleb128 0x0 + .align 4 +L$ECIE1: +L$SFDE1: + .word L$EFDE1-L$ASFDE1 ;# FDE Length +L$ASFDE1: + .word L$ASFDE1-L$frame1 ;# FDE CIE offset + .word L$FB1 ;# FDE initial location + .word L$FE1-L$FB1 ;# FDE address range + + .byte 0x4 ;# DW_CFA_advance_loc4 + .word L$CFI11-L$FB1 + .byte 0x83 ;# DW_CFA_offset, column 0x3 + .uleb128 0x0 + .byte 0x11 ;# DW_CFA_offset_extended_sf; save r2 at [r30-20] + .uleb128 0x2 + .sleb128 -5 + + .byte 0x4 ;# DW_CFA_advance_loc4 + .word L$CFI12-L$CFI11 + .byte 0xd ;# DW_CFA_def_cfa_register = r3 + .uleb128 0x3 + + .byte 0x4 ;# DW_CFA_advance_loc4 + .word L$CFI13-L$CFI12 + .byte 0x84 ;# DW_CFA_offset, column 0x4 + .uleb128 0x3 + + .align 4 +L$EFDE1: + +L$SFDE2: + .word L$EFDE2-L$ASFDE2 ;# FDE Length +L$ASFDE2: + .word L$ASFDE2-L$frame1 ;# FDE CIE offset + .word L$FB2 ;# FDE initial location + .word L$FE2-L$FB2 ;# FDE address range + .byte 0x4 ;# DW_CFA_advance_loc4 + .word L$CFI21-L$FB2 + .byte 0x83 ;# DW_CFA_offset, column 0x3 + .uleb128 0x0 + .byte 0x11 ;# DW_CFA_offset_extended_sf + .uleb128 0x2 + .sleb128 -5 + + .byte 0x4 ;# DW_CFA_advance_loc4 + .word L$CFI22-L$CFI21 + .byte 0xd ;# DW_CFA_def_cfa_register = r3 + .uleb128 0x3 + + .align 4 +L$EFDE2: diff --git a/js/src/ctypes/libffi/src/pa/linux.S b/js/src/ctypes/libffi/src/pa/linux.S new file mode 100644 index 0000000..f11ae76 --- /dev/null +++ b/js/src/ctypes/libffi/src/pa/linux.S @@ -0,0 +1,357 @@ +/* ----------------------------------------------------------------------- + linux.S - (c) 2003-2004 Randolph Chung + (c) 2008 Red Hat, Inc. + + HPPA Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include + + .text + .level 1.1 + .align 4 + + /* void ffi_call_pa32(void (*)(char *, extended_cif *), + extended_cif *ecif, + unsigned bytes, + unsigned flags, + unsigned *rvalue, + void (*fn)(void)); + */ + + .export ffi_call_pa32,code + .import ffi_prep_args_pa32,code + + .type ffi_call_pa32, @function +.LFB1: +ffi_call_pa32: + .proc + .callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=4 + .entry + stw %rp, -20(%sp) + copy %r3, %r1 +.LCFI11: + + copy %sp, %r3 +.LCFI12: + + /* Setup the stack for calling prep_args... + We want the stack to look like this: + + [ Previous stack ] <- %r3 + + [ 64-bytes register save area ] <- %r4 + + [ Stack space for actual call, passed as ] <- %arg0 + [ arg0 to ffi_prep_args_pa32 ] + + [ Stack for calling prep_args ] <- %sp + */ + + stwm %r1, 64(%sp) + stw %r4, 12(%r3) +.LCFI13: + copy %sp, %r4 + + addl %arg2, %r4, %arg0 /* arg stack */ + stw %arg3, -48(%r3) /* save flags; we need it later */ + + /* Call prep_args: + %arg0(stack) -- set up above + %arg1(ecif) -- same as incoming param + %arg2(bytes) -- same as incoming param */ + bl ffi_prep_args_pa32,%r2 + ldo 64(%arg0), %sp + ldo -64(%sp), %sp + + /* now %sp should point where %arg0 was pointing. */ + + /* Load the arguments that should be passed in registers + The fp args were loaded by the prep_args function. */ + ldw -36(%sp), %arg0 + ldw -40(%sp), %arg1 + ldw -44(%sp), %arg2 + ldw -48(%sp), %arg3 + + /* in case the function is going to return a structure + we need to give it a place to put the result. */ + ldw -52(%r3), %ret0 /* %ret0 <- rvalue */ + ldw -56(%r3), %r22 /* %r22 <- function to call */ + bl $$dyncall, %r31 /* Call the user function */ + copy %r31, %rp + + /* Prepare to store the result; we need to recover flags and rvalue. */ + ldw -48(%r3), %r21 /* r21 <- flags */ + ldw -52(%r3), %r20 /* r20 <- rvalue */ + + /* Store the result according to the return type. */ + +.Lcheckint: + comib,<>,n FFI_TYPE_INT, %r21, .Lcheckint8 + b .Ldone + stw %ret0, 0(%r20) + +.Lcheckint8: + comib,<>,n FFI_TYPE_UINT8, %r21, .Lcheckint16 + b .Ldone + stb %ret0, 0(%r20) + +.Lcheckint16: + comib,<>,n FFI_TYPE_UINT16, %r21, .Lcheckdbl + b .Ldone + sth %ret0, 0(%r20) + +.Lcheckdbl: + comib,<>,n FFI_TYPE_DOUBLE, %r21, .Lcheckfloat + b .Ldone + fstd %fr4,0(%r20) + +.Lcheckfloat: + comib,<>,n FFI_TYPE_FLOAT, %r21, .Lcheckll + b .Ldone + fstw %fr4L,0(%r20) + +.Lcheckll: + comib,<>,n FFI_TYPE_UINT64, %r21, .Lchecksmst2 + stw %ret0, 0(%r20) + b .Ldone + stw %ret1, 4(%r20) + +.Lchecksmst2: + comib,<>,n FFI_TYPE_SMALL_STRUCT2, %r21, .Lchecksmst3 + /* 2-byte structs are returned in ret0 as ????xxyy. */ + extru %ret0, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + b .Ldone + stb %ret0, 0(%r20) + +.Lchecksmst3: + comib,<>,n FFI_TYPE_SMALL_STRUCT3, %r21, .Lchecksmst4 + /* 3-byte structs are returned in ret0 as ??xxyyzz. */ + extru %ret0, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret0, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + b .Ldone + stb %ret0, 0(%r20) + +.Lchecksmst4: + comib,<>,n FFI_TYPE_SMALL_STRUCT4, %r21, .Lchecksmst5 + /* 4-byte structs are returned in ret0 as wwxxyyzz. */ + extru %ret0, 7, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret0, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret0, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + b .Ldone + stb %ret0, 0(%r20) + +.Lchecksmst5: + comib,<>,n FFI_TYPE_SMALL_STRUCT5, %r21, .Lchecksmst6 + /* 5 byte values are returned right justified: + ret0 ret1 + 5: ??????aa bbccddee */ + stbs,ma %ret0, 1(%r20) + extru %ret1, 7, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + b .Ldone + stb %ret1, 0(%r20) + +.Lchecksmst6: + comib,<>,n FFI_TYPE_SMALL_STRUCT6, %r21, .Lchecksmst7 + /* 6 byte values are returned right justified: + ret0 ret1 + 6: ????aabb ccddeeff */ + extru %ret0, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + stbs,ma %ret0, 1(%r20) + extru %ret1, 7, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + b .Ldone + stb %ret1, 0(%r20) + +.Lchecksmst7: + comib,<>,n FFI_TYPE_SMALL_STRUCT7, %r21, .Lchecksmst8 + /* 7 byte values are returned right justified: + ret0 ret1 + 7: ??aabbcc ddeeffgg */ + extru %ret0, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret0, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + stbs,ma %ret0, 1(%r20) + extru %ret1, 7, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + b .Ldone + stb %ret1, 0(%r20) + +.Lchecksmst8: + comib,<>,n FFI_TYPE_SMALL_STRUCT8, %r21, .Ldone + /* 8 byte values are returned right justified: + ret0 ret1 + 8: aabbccdd eeffgghh */ + extru %ret0, 7, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret0, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret0, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + stbs,ma %ret0, 1(%r20) + extru %ret1, 7, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 15, 8, %r22 + stbs,ma %r22, 1(%r20) + extru %ret1, 23, 8, %r22 + stbs,ma %r22, 1(%r20) + stb %ret1, 0(%r20) + +.Ldone: + /* all done, return */ + copy %r4, %sp /* pop arg stack */ + ldw 12(%r3), %r4 + ldwm -64(%sp), %r3 /* .. and pop stack */ + ldw -20(%sp), %rp + bv %r0(%rp) + nop + .exit + .procend +.LFE1: + + /* void ffi_closure_pa32(void); + Called with closure argument in %r21 */ + .export ffi_closure_pa32,code + .import ffi_closure_inner_pa32,code + + .type ffi_closure_pa32, @function +.LFB2: +ffi_closure_pa32: + .proc + .callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3 + .entry + + stw %rp, -20(%sp) +.LCFI20: + copy %r3, %r1 +.LCFI21: + copy %sp, %r3 +.LCFI22: + stwm %r1, 64(%sp) + + /* Put arguments onto the stack and call ffi_closure_inner. */ + stw %arg0, -36(%r3) + stw %arg1, -40(%r3) + stw %arg2, -44(%r3) + stw %arg3, -48(%r3) + + copy %r21, %arg0 + bl ffi_closure_inner_pa32, %r2 + copy %r3, %arg1 + + ldwm -64(%sp), %r3 + ldw -20(%sp), %rp + ldw -36(%sp), %ret0 + bv %r0(%r2) + ldw -40(%sp), %ret1 + + .exit + .procend +.LFE2: + + .section ".eh_frame",EH_FRAME_FLAGS,@progbits +.Lframe1: + .word .LECIE1-.LSCIE1 ;# Length of Common Information Entry +.LSCIE1: + .word 0x0 ;# CIE Identifier Tag + .byte 0x1 ;# CIE Version + .ascii "\0" ;# CIE Augmentation + .uleb128 0x1 ;# CIE Code Alignment Factor + .sleb128 4 ;# CIE Data Alignment Factor + .byte 0x2 ;# CIE RA Column + .byte 0xc ;# DW_CFA_def_cfa + .uleb128 0x1e + .uleb128 0x0 + .align 4 +.LECIE1: +.LSFDE1: + .word .LEFDE1-.LASFDE1 ;# FDE Length +.LASFDE1: + .word .LASFDE1-.Lframe1 ;# FDE CIE offset + .word .LFB1 ;# FDE initial location + .word .LFE1-.LFB1 ;# FDE address range + + .byte 0x4 ;# DW_CFA_advance_loc4 + .word .LCFI11-.LFB1 + .byte 0x83 ;# DW_CFA_offset, column 0x3 + .uleb128 0x0 + .byte 0x11 ;# DW_CFA_offset_extended_sf; save r2 at [r30-20] + .uleb128 0x2 + .sleb128 -5 + + .byte 0x4 ;# DW_CFA_advance_loc4 + .word .LCFI12-.LCFI11 + .byte 0xd ;# DW_CFA_def_cfa_register = r3 + .uleb128 0x3 + + .byte 0x4 ;# DW_CFA_advance_loc4 + .word .LCFI13-.LCFI12 + .byte 0x84 ;# DW_CFA_offset, column 0x4 + .uleb128 0x3 + + .align 4 +.LEFDE1: + +.LSFDE2: + .word .LEFDE2-.LASFDE2 ;# FDE Length +.LASFDE2: + .word .LASFDE2-.Lframe1 ;# FDE CIE offset + .word .LFB2 ;# FDE initial location + .word .LFE2-.LFB2 ;# FDE address range + .byte 0x4 ;# DW_CFA_advance_loc4 + .word .LCFI21-.LFB2 + .byte 0x83 ;# DW_CFA_offset, column 0x3 + .uleb128 0x0 + .byte 0x11 ;# DW_CFA_offset_extended_sf + .uleb128 0x2 + .sleb128 -5 + + .byte 0x4 ;# DW_CFA_advance_loc4 + .word .LCFI22-.LCFI21 + .byte 0xd ;# DW_CFA_def_cfa_register = r3 + .uleb128 0x3 + + .align 4 +.LEFDE2: diff --git a/js/src/ctypes/libffi/src/powerpc/aix.S b/js/src/ctypes/libffi/src/powerpc/aix.S new file mode 100644 index 0000000..c6f8764 --- /dev/null +++ b/js/src/ctypes/libffi/src/powerpc/aix.S @@ -0,0 +1,324 @@ +/* ----------------------------------------------------------------------- + aix.S - Copyright (c) 2002,2009 Free Software Foundation, Inc. + based on darwin.S by John Hornkvist + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + + .set r0,0 + .set r1,1 + .set r2,2 + .set r3,3 + .set r4,4 + .set r5,5 + .set r6,6 + .set r7,7 + .set r8,8 + .set r9,9 + .set r10,10 + .set r11,11 + .set r12,12 + .set r13,13 + .set r14,14 + .set r15,15 + .set r16,16 + .set r17,17 + .set r18,18 + .set r19,19 + .set r20,20 + .set r21,21 + .set r22,22 + .set r23,23 + .set r24,24 + .set r25,25 + .set r26,26 + .set r27,27 + .set r28,28 + .set r29,29 + .set r30,30 + .set r31,31 + .set f0,0 + .set f1,1 + .set f2,2 + .set f3,3 + .set f4,4 + .set f5,5 + .set f6,6 + .set f7,7 + .set f8,8 + .set f9,9 + .set f10,10 + .set f11,11 + .set f12,12 + .set f13,13 + .set f14,14 + .set f15,15 + .set f16,16 + .set f17,17 + .set f18,18 + .set f19,19 + .set f20,20 + .set f21,21 + +#define LIBFFI_ASM +#include +#include +#define JUMPTARGET(name) name +#define L(x) x + .file "aix.S" + .toc + + /* void ffi_call_AIX(extended_cif *ecif, unsigned long bytes, + * unsigned int flags, unsigned int *rvalue, + * void (*fn)(), + * void (*prep_args)(extended_cif*, unsigned *const)); + * r3=ecif, r4=bytes, r5=flags, r6=rvalue, r7=fn, r8=prep_args + */ + +.csect .text[PR] + .align 2 + .globl ffi_call_AIX + .globl .ffi_call_AIX +.csect ffi_call_AIX[DS] +ffi_call_AIX: +#ifdef __64BIT__ + .llong .ffi_call_AIX, TOC[tc0], 0 + .csect .text[PR] +.ffi_call_AIX: + /* Save registers we use. */ + mflr r0 + + std r28,-32(r1) + std r29,-24(r1) + std r30,-16(r1) + std r31, -8(r1) + + std r0, 16(r1) + mr r28, r1 /* our AP. */ + stdux r1, r1, r4 + + /* Save arguments over call... */ + mr r31, r5 /* flags, */ + mr r30, r6 /* rvalue, */ + mr r29, r7 /* function address. */ + std r2, 40(r1) + + /* Call ffi_prep_args. */ + mr r4, r1 + bl .ffi_prep_args + + /* Now do the call. */ + ld r0, 0(r29) + ld r2, 8(r29) + ld r11, 16(r29) + /* Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40, r31 + mtctr r0 + /* Load all those argument registers. */ + // We have set up a nice stack frame, just load it into registers. + ld r3, 40+(1*8)(r1) + ld r4, 40+(2*8)(r1) + ld r5, 40+(3*8)(r1) + ld r6, 40+(4*8)(r1) + nop + ld r7, 40+(5*8)(r1) + ld r8, 40+(6*8)(r1) + ld r9, 40+(7*8)(r1) + ld r10,40+(8*8)(r1) + +L1: + /* Load all the FP registers. */ + bf 6,L2 // 2f + 0x18 + lfd f1,-32-(13*8)(r28) + lfd f2,-32-(12*8)(r28) + lfd f3,-32-(11*8)(r28) + lfd f4,-32-(10*8)(r28) + nop + lfd f5,-32-(9*8)(r28) + lfd f6,-32-(8*8)(r28) + lfd f7,-32-(7*8)(r28) + lfd f8,-32-(6*8)(r28) + nop + lfd f9,-32-(5*8)(r28) + lfd f10,-32-(4*8)(r28) + lfd f11,-32-(3*8)(r28) + lfd f12,-32-(2*8)(r28) + nop + lfd f13,-32-(1*8)(r28) + +L2: + /* Make the call. */ + bctrl + ld r2, 40(r1) + + /* Now, deal with the return value. */ + mtcrf 0x01, r31 + + bt 30, L(done_return_value) + bt 29, L(fp_return_value) + std r3, 0(r30) + + /* Fall through... */ + +L(done_return_value): + /* Restore the registers we used and return. */ + mr r1, r28 + ld r0, 16(r28) + ld r28, -32(r1) + mtlr r0 + ld r29, -24(r1) + ld r30, -16(r1) + ld r31, -8(r1) + blr + +L(fp_return_value): + bf 28, L(float_return_value) + stfd f1, 0(r30) + bf 31, L(done_return_value) + stfd f2, 8(r30) + b L(done_return_value) +L(float_return_value): + stfs f1, 0(r30) + b L(done_return_value) + +#else /* ! __64BIT__ */ + + .long .ffi_call_AIX, TOC[tc0], 0 + .csect .text[PR] +.ffi_call_AIX: + /* Save registers we use. */ + mflr r0 + + stw r28,-16(r1) + stw r29,-12(r1) + stw r30, -8(r1) + stw r31, -4(r1) + + stw r0, 8(r1) + mr r28, r1 /* out AP. */ + stwux r1, r1, r4 + + /* Save arguments over call... */ + mr r31, r5 /* flags, */ + mr r30, r6 /* rvalue, */ + mr r29, r7 /* function address, */ + stw r2, 20(r1) + + /* Call ffi_prep_args. */ + mr r4, r1 + bl .ffi_prep_args + + /* Now do the call. */ + lwz r0, 0(r29) + lwz r2, 4(r29) + lwz r11, 8(r29) + /* Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40, r31 + mtctr r0 + /* Load all those argument registers. */ + // We have set up a nice stack frame, just load it into registers. + lwz r3, 20+(1*4)(r1) + lwz r4, 20+(2*4)(r1) + lwz r5, 20+(3*4)(r1) + lwz r6, 20+(4*4)(r1) + nop + lwz r7, 20+(5*4)(r1) + lwz r8, 20+(6*4)(r1) + lwz r9, 20+(7*4)(r1) + lwz r10,20+(8*4)(r1) + +L1: + /* Load all the FP registers. */ + bf 6,L2 // 2f + 0x18 + lfd f1,-16-(13*8)(r28) + lfd f2,-16-(12*8)(r28) + lfd f3,-16-(11*8)(r28) + lfd f4,-16-(10*8)(r28) + nop + lfd f5,-16-(9*8)(r28) + lfd f6,-16-(8*8)(r28) + lfd f7,-16-(7*8)(r28) + lfd f8,-16-(6*8)(r28) + nop + lfd f9,-16-(5*8)(r28) + lfd f10,-16-(4*8)(r28) + lfd f11,-16-(3*8)(r28) + lfd f12,-16-(2*8)(r28) + nop + lfd f13,-16-(1*8)(r28) + +L2: + /* Make the call. */ + bctrl + lwz r2, 20(r1) + + /* Now, deal with the return value. */ + mtcrf 0x01, r31 + + bt 30, L(done_return_value) + bt 29, L(fp_return_value) + stw r3, 0(r30) + bf 28, L(done_return_value) + stw r4, 4(r30) + + /* Fall through... */ + +L(done_return_value): + /* Restore the registers we used and return. */ + mr r1, r28 + lwz r0, 8(r28) + lwz r28,-16(r1) + mtlr r0 + lwz r29,-12(r1) + lwz r30, -8(r1) + lwz r31, -4(r1) + blr + +L(fp_return_value): + bf 28, L(float_return_value) + stfd f1, 0(r30) + b L(done_return_value) +L(float_return_value): + stfs f1, 0(r30) + b L(done_return_value) +#endif + .long 0 + .byte 0,0,0,1,128,4,0,0 +//END(ffi_call_AIX) + +.csect .text[PR] + .align 2 + .globl ffi_call_DARWIN + .globl .ffi_call_DARWIN +.csect ffi_call_DARWIN[DS] +ffi_call_DARWIN: +#ifdef __64BIT__ + .llong .ffi_call_DARWIN, TOC[tc0], 0 +#else + .long .ffi_call_DARWIN, TOC[tc0], 0 +#endif + .csect .text[PR] +.ffi_call_DARWIN: + blr + .long 0 + .byte 0,0,0,0,0,0,0,0 +//END(ffi_call_DARWIN) diff --git a/js/src/ctypes/libffi/src/powerpc/aix_closure.S b/js/src/ctypes/libffi/src/powerpc/aix_closure.S new file mode 100644 index 0000000..5c74448 --- /dev/null +++ b/js/src/ctypes/libffi/src/powerpc/aix_closure.S @@ -0,0 +1,443 @@ +/* ----------------------------------------------------------------------- + aix_closure.S - Copyright (c) 2002, 2003, 2009 Free Software Foundation, Inc. + based on darwin_closure.S + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + + .set r0,0 + .set r1,1 + .set r2,2 + .set r3,3 + .set r4,4 + .set r5,5 + .set r6,6 + .set r7,7 + .set r8,8 + .set r9,9 + .set r10,10 + .set r11,11 + .set r12,12 + .set r13,13 + .set r14,14 + .set r15,15 + .set r16,16 + .set r17,17 + .set r18,18 + .set r19,19 + .set r20,20 + .set r21,21 + .set r22,22 + .set r23,23 + .set r24,24 + .set r25,25 + .set r26,26 + .set r27,27 + .set r28,28 + .set r29,29 + .set r30,30 + .set r31,31 + .set f0,0 + .set f1,1 + .set f2,2 + .set f3,3 + .set f4,4 + .set f5,5 + .set f6,6 + .set f7,7 + .set f8,8 + .set f9,9 + .set f10,10 + .set f11,11 + .set f12,12 + .set f13,13 + .set f14,14 + .set f15,15 + .set f16,16 + .set f17,17 + .set f18,18 + .set f19,19 + .set f20,20 + .set f21,21 + +#define LIBFFI_ASM +#define JUMPTARGET(name) name +#define L(x) x + .file "aix_closure.S" + .toc +LC..60: + .tc L..60[TC],L..60 + .csect .text[PR] + .align 2 + +.csect .text[PR] + .align 2 + .globl ffi_closure_ASM + .globl .ffi_closure_ASM +.csect ffi_closure_ASM[DS] +ffi_closure_ASM: +#ifdef __64BIT__ + .llong .ffi_closure_ASM, TOC[tc0], 0 + .csect .text[PR] +.ffi_closure_ASM: +/* we want to build up an area for the parameters passed */ +/* in registers (both floating point and integer) */ + + /* we store gpr 3 to gpr 10 (aligned to 4) + in the parents outgoing area */ + std r3, 48+(0*8)(r1) + std r4, 48+(1*8)(r1) + std r5, 48+(2*8)(r1) + std r6, 48+(3*8)(r1) + mflr r0 + + std r7, 48+(4*8)(r1) + std r8, 48+(5*8)(r1) + std r9, 48+(6*8)(r1) + std r10, 48+(7*8)(r1) + std r0, 16(r1) /* save the return address */ + + + /* 48 Bytes (Linkage Area) */ + /* 64 Bytes (params) */ + /* 16 Bytes (result) */ + /* 104 Bytes (13*8 from FPR) */ + /* 8 Bytes (alignment) */ + /* 240 Bytes */ + + stdu r1, -240(r1) /* skip over caller save area + keep stack aligned to 16 */ + + /* next save fpr 1 to fpr 13 (aligned to 8) */ + stfd f1, 128+(0*8)(r1) + stfd f2, 128+(1*8)(r1) + stfd f3, 128+(2*8)(r1) + stfd f4, 128+(3*8)(r1) + stfd f5, 128+(4*8)(r1) + stfd f6, 128+(5*8)(r1) + stfd f7, 128+(6*8)(r1) + stfd f8, 128+(7*8)(r1) + stfd f9, 128+(8*8)(r1) + stfd f10, 128+(9*8)(r1) + stfd f11, 128+(10*8)(r1) + stfd f12, 128+(11*8)(r1) + stfd f13, 128+(12*8)(r1) + + /* set up registers for the routine that actually does the work */ + /* get the context pointer from the trampoline */ + mr r3, r11 + + /* now load up the pointer to the result storage */ + addi r4, r1, 112 + + /* now load up the pointer to the saved gpr registers */ + addi r5, r1, 288 + + /* now load up the pointer to the saved fpr registers */ + addi r6, r1, 128 + + /* make the call */ + bl .ffi_closure_helper_DARWIN + nop + + /* now r3 contains the return type */ + /* so use it to look up in a table */ + /* so we know how to deal with each type */ + + /* look up the proper starting point in table */ + /* by using return type as offset */ + ld r4, LC..60(2) /* get address of jump table */ + sldi r3, r3, 4 /* now multiply return type by 16 */ + ld r0, 240+16(r1) /* load return address */ + add r3, r3, r4 /* add contents of table to table address */ + mtctr r3 + bctr /* jump to it */ + +/* Each fragment must be exactly 16 bytes long (4 instructions). + Align to 16 byte boundary for cache and dispatch efficiency. */ + .align 4 + +L..60: +/* case FFI_TYPE_VOID */ + mtlr r0 + addi r1, r1, 240 + blr + nop + +/* case FFI_TYPE_INT */ + lwa r3, 112+4(r1) + mtlr r0 + addi r1, r1, 240 + blr + +/* case FFI_TYPE_FLOAT */ + lfs f1, 112+0(r1) + mtlr r0 + addi r1, r1, 240 + blr + +/* case FFI_TYPE_DOUBLE */ + lfd f1, 112+0(r1) + mtlr r0 + addi r1, r1, 240 + blr + +/* case FFI_TYPE_LONGDOUBLE */ + lfd f1, 112+0(r1) + mtlr r0 + lfd f2, 112+8(r1) + b L..finish + +/* case FFI_TYPE_UINT8 */ + lbz r3, 112+7(r1) + mtlr r0 + addi r1, r1, 240 + blr + +/* case FFI_TYPE_SINT8 */ + lbz r3, 112+7(r1) + mtlr r0 + extsb r3, r3 + b L..finish + +/* case FFI_TYPE_UINT16 */ + lhz r3, 112+6(r1) + mtlr r0 +L..finish: + addi r1, r1, 240 + blr + +/* case FFI_TYPE_SINT16 */ + lha r3, 112+6(r1) + mtlr r0 + addi r1, r1, 240 + blr + +/* case FFI_TYPE_UINT32 */ + lwz r3, 112+4(r1) + mtlr r0 + addi r1, r1, 240 + blr + +/* case FFI_TYPE_SINT32 */ + lwa r3, 112+4(r1) + mtlr r0 + addi r1, r1, 240 + blr + +/* case FFI_TYPE_UINT64 */ + ld r3, 112+0(r1) + mtlr r0 + addi r1, r1, 240 + blr + +/* case FFI_TYPE_SINT64 */ + ld r3, 112+0(r1) + mtlr r0 + addi r1, r1, 240 + blr + +/* case FFI_TYPE_STRUCT */ + mtlr r0 + addi r1, r1, 240 + blr + nop + +/* case FFI_TYPE_POINTER */ + ld r3, 112+0(r1) + mtlr r0 + addi r1, r1, 240 + blr + +#else /* ! __64BIT__ */ + + .long .ffi_closure_ASM, TOC[tc0], 0 + .csect .text[PR] +.ffi_closure_ASM: +/* we want to build up an area for the parameters passed */ +/* in registers (both floating point and integer) */ + + /* we store gpr 3 to gpr 10 (aligned to 4) + in the parents outgoing area */ + stw r3, 24+(0*4)(r1) + stw r4, 24+(1*4)(r1) + stw r5, 24+(2*4)(r1) + stw r6, 24+(3*4)(r1) + mflr r0 + + stw r7, 24+(4*4)(r1) + stw r8, 24+(5*4)(r1) + stw r9, 24+(6*4)(r1) + stw r10, 24+(7*4)(r1) + stw r0, 8(r1) + + /* 24 Bytes (Linkage Area) */ + /* 32 Bytes (params) */ + /* 16 Bytes (result) */ + /* 104 Bytes (13*8 from FPR) */ + /* 176 Bytes */ + + stwu r1, -176(r1) /* skip over caller save area + keep stack aligned to 16 */ + + /* next save fpr 1 to fpr 13 (aligned to 8) */ + stfd f1, 72+(0*8)(r1) + stfd f2, 72+(1*8)(r1) + stfd f3, 72+(2*8)(r1) + stfd f4, 72+(3*8)(r1) + stfd f5, 72+(4*8)(r1) + stfd f6, 72+(5*8)(r1) + stfd f7, 72+(6*8)(r1) + stfd f8, 72+(7*8)(r1) + stfd f9, 72+(8*8)(r1) + stfd f10, 72+(9*8)(r1) + stfd f11, 72+(10*8)(r1) + stfd f12, 72+(11*8)(r1) + stfd f13, 72+(12*8)(r1) + + /* set up registers for the routine that actually does the work */ + /* get the context pointer from the trampoline */ + mr r3, r11 + + /* now load up the pointer to the result storage */ + addi r4, r1, 56 + + /* now load up the pointer to the saved gpr registers */ + addi r5, r1, 200 + + /* now load up the pointer to the saved fpr registers */ + addi r6, r1, 72 + + /* make the call */ + bl .ffi_closure_helper_DARWIN + nop + + /* now r3 contains the return type */ + /* so use it to look up in a table */ + /* so we know how to deal with each type */ + + /* look up the proper starting point in table */ + /* by using return type as offset */ + lwz r4, LC..60(2) /* get address of jump table */ + slwi r3, r3, 4 /* now multiply return type by 4 */ + lwz r0, 176+8(r1) /* load return address */ + add r3, r3, r4 /* add contents of table to table address */ + mtctr r3 + bctr /* jump to it */ + +/* Each fragment must be exactly 16 bytes long (4 instructions). + Align to 16 byte boundary for cache and dispatch efficiency. */ + .align 4 + +L..60: +/* case FFI_TYPE_VOID */ + mtlr r0 + addi r1, r1, 176 + blr + nop + +/* case FFI_TYPE_INT */ + lwz r3, 56+0(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_FLOAT */ + lfs f1, 56+0(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_DOUBLE */ + lfd f1, 56+0(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_LONGDOUBLE */ + lfd f1, 56+0(r1) + mtlr r0 + lfd f2, 56+8(r1) + b L..finish + +/* case FFI_TYPE_UINT8 */ + lbz r3, 56+3(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_SINT8 */ + lbz r3, 56+3(r1) + mtlr r0 + extsb r3, r3 + b L..finish + +/* case FFI_TYPE_UINT16 */ + lhz r3, 56+2(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_SINT16 */ + lha r3, 56+2(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_UINT32 */ + lwz r3, 56+0(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_SINT32 */ + lwz r3, 56+0(r1) + mtlr r0 + addi r1, r1, 176 + blr + +/* case FFI_TYPE_UINT64 */ + lwz r3, 56+0(r1) + mtlr r0 + lwz r4, 56+4(r1) + b L..finish + +/* case FFI_TYPE_SINT64 */ + lwz r3, 56+0(r1) + mtlr r0 + lwz r4, 56+4(r1) + b L..finish + +/* case FFI_TYPE_STRUCT */ + mtlr r0 + addi r1, r1, 176 + blr + nop + +/* case FFI_TYPE_POINTER */ + lwz r3, 56+0(r1) + mtlr r0 +L..finish: + addi r1, r1, 176 + blr +#endif +/* END(ffi_closure_ASM) */ diff --git a/js/src/ctypes/libffi/src/powerpc/asm.h b/js/src/ctypes/libffi/src/powerpc/asm.h new file mode 100644 index 0000000..e86e6b0 --- /dev/null +++ b/js/src/ctypes/libffi/src/powerpc/asm.h @@ -0,0 +1,125 @@ +/* ----------------------------------------------------------------------- + asm.h - Copyright (c) 1998 Geoffrey Keating + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define ASM_GLOBAL_DIRECTIVE .globl + + +#define C_SYMBOL_NAME(name) name +/* Macro for a label. */ +#ifdef __STDC__ +#define C_LABEL(name) name##: +#else +#define C_LABEL(name) name/**/: +#endif + +/* This seems to always be the case on PPC. */ +#define ALIGNARG(log2) log2 +/* For ELF we need the `.type' directive to make shared libs work right. */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name + +/* If compiled for profiling, call `_mcount' at the start of each function. */ +#ifdef PROF +/* The mcount code relies on a the return address being on the stack + to locate our caller and so it can restore it; so store one just + for its benefit. */ +#ifdef PIC +#define CALL_MCOUNT \ + .pushsection; \ + .section ".data"; \ + .align ALIGNARG(2); \ +0:.long 0; \ + .previous; \ + mflr %r0; \ + stw %r0,4(%r1); \ + bl _GLOBAL_OFFSET_TABLE_@local-4; \ + mflr %r11; \ + lwz %r0,0b@got(%r11); \ + bl JUMPTARGET(_mcount); +#else /* PIC */ +#define CALL_MCOUNT \ + .section ".data"; \ + .align ALIGNARG(2); \ +0:.long 0; \ + .previous; \ + mflr %r0; \ + lis %r11,0b@ha; \ + stw %r0,4(%r1); \ + addi %r0,%r11,0b@l; \ + bl JUMPTARGET(_mcount); +#endif /* PIC */ +#else /* PROF */ +#define CALL_MCOUNT /* Do nothing. */ +#endif /* PROF */ + +#define ENTRY(name) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \ + .align ALIGNARG(2); \ + C_LABEL(name) \ + CALL_MCOUNT + +#define EALIGN_W_0 /* No words to insert. */ +#define EALIGN_W_1 nop +#define EALIGN_W_2 nop;nop +#define EALIGN_W_3 nop;nop;nop +#define EALIGN_W_4 EALIGN_W_3;nop +#define EALIGN_W_5 EALIGN_W_4;nop +#define EALIGN_W_6 EALIGN_W_5;nop +#define EALIGN_W_7 EALIGN_W_6;nop + +/* EALIGN is like ENTRY, but does alignment to 'words'*4 bytes + past a 2^align boundary. */ +#ifdef PROF +#define EALIGN(name, alignt, words) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \ + .align ALIGNARG(2); \ + C_LABEL(name) \ + CALL_MCOUNT \ + b 0f; \ + .align ALIGNARG(alignt); \ + EALIGN_W_##words; \ + 0: +#else /* PROF */ +#define EALIGN(name, alignt, words) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \ + .align ALIGNARG(alignt); \ + EALIGN_W_##words; \ + C_LABEL(name) +#endif + +#define END(name) \ + ASM_SIZE_DIRECTIVE(name) + +#ifdef PIC +#define JUMPTARGET(name) name##@plt +#else +#define JUMPTARGET(name) name +#endif + +/* Local labels stripped out by the linker. */ +#define L(x) .L##x diff --git a/js/src/ctypes/libffi/src/powerpc/darwin.S b/js/src/ctypes/libffi/src/powerpc/darwin.S new file mode 100644 index 0000000..d8a1df5 --- /dev/null +++ b/js/src/ctypes/libffi/src/powerpc/darwin.S @@ -0,0 +1,245 @@ +/* ----------------------------------------------------------------------- + darwin.S - Copyright (c) 2000 John Hornkvist + Copyright (c) 2004 Free Software Foundation, Inc. + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#if defined(__ppc64__) +#define MODE_CHOICE(x, y) y +#else +#define MODE_CHOICE(x, y) x +#endif + +#define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */ + +#define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */ + +#define LIBFFI_ASM +#include +#include +#define JUMPTARGET(name) name +#define L(x) x +.text + .align 2 +.globl _ffi_prep_args + +.text + .align 2 +.globl _ffi_call_DARWIN +.text + .align 2 +_ffi_call_DARWIN: +LFB0: + mr r12,r8 /* We only need r12 until the call, + so it doesn't have to be saved. */ +LFB1: + /* Save the old stack pointer as AP. */ + mr r8,r1 +LCFI0: + /* Allocate the stack space we need. */ + stwux r1,r1,r4 + + /* Save registers we use. */ + mflr r9 + + stw r28,-16(r8) + stw r29,-12(r8) + stw r30,-8(r8) + stw r31,-4(r8) + + stw r9,8(r8) + stw r2,20(r1) +LCFI1: + + /* Save arguments over call. */ + mr r31,r5 /* flags, */ + mr r30,r6 /* rvalue, */ + mr r29,r7 /* function address, */ + mr r28,r8 /* our AP. */ +LCFI2: + /* Call ffi_prep_args. */ + mr r4,r1 + li r9,0 + + mtctr r12 /* r12 holds address of _ffi_prep_args. */ + bctrl + lwz r2,20(r1) + + /* Now do the call. + Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40,r31 + /* Get the address to call into CTR. */ + mtctr r29 + /* Load all those argument registers. + We have set up a nice stack frame, just load it into registers. */ + lwz r3,20+(1*4)(r1) + lwz r4,20+(2*4)(r1) + lwz r5,20+(3*4)(r1) + lwz r6,20+(4*4)(r1) + nop + lwz r7,20+(5*4)(r1) + lwz r8,20+(6*4)(r1) + lwz r9,20+(7*4)(r1) + lwz r10,20+(8*4)(r1) + +L1: + /* Load all the FP registers. */ + bf 6,L2 /* No floats to load. */ + lfd f1,-16-(13*8)(r28) + lfd f2,-16-(12*8)(r28) + lfd f3,-16-(11*8)(r28) + lfd f4,-16-(10*8)(r28) + nop + lfd f5,-16-(9*8)(r28) + lfd f6,-16-(8*8)(r28) + lfd f7,-16-(7*8)(r28) + lfd f8,-16-(6*8)(r28) + nop + lfd f9,-16-(5*8)(r28) + lfd f10,-16-(4*8)(r28) + lfd f11,-16-(3*8)(r28) + lfd f12,-16-(2*8)(r28) + nop + lfd f13,-16-(1*8)(r28) + +L2: + mr r12,r29 /* Put the target address in r12 as specified. */ + mtctr r12 + nop + nop + /* Make the call. */ + bctrl + + /* Now, deal with the return value. */ + mtcrf 0x01,r31 + + bt 30,L(done_return_value) + bt 29,L(fp_return_value) + stw r3,0(r30) + bf 28,L(done_return_value) + stw r4,4(r30) + + /* Fall through. */ + +L(done_return_value): + /* Restore the registers we used and return. */ + lwz r9,8(r28) + lwz r31,-4(r28) + mtlr r9 + lwz r30,-8(r28) + lwz r29,-12(r28) + lwz r28,-16(r28) + lwz r1,0(r1) + blr + +L(fp_return_value): + /* Do we have long double to store? */ + bf 31,L(fd_return_value) + stfd f1,0(r30) + stfd f2,8(r30) + b L(done_return_value) + +L(fd_return_value): + /* Do we have double to store? */ + bf 28,L(float_return_value) + stfd f1,0(r30) + b L(done_return_value) + +L(float_return_value): + /* We only have a float to store. */ + stfs f1,0(r30) + b L(done_return_value) + +LFE1: +/* END(_ffi_call_DARWIN) */ + +/* Provide a null definition of _ffi_call_AIX. */ +.text + .align 2 +.globl _ffi_call_AIX +.text + .align 2 +_ffi_call_AIX: + blr +/* END(_ffi_call_AIX) */ + +.data +.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms +EH_frame1: + .set L$set$0,LECIE1-LSCIE1 + .long L$set$0 ; Length of Common Information Entry +LSCIE1: + .long 0x0 ; CIE Identifier Tag + .byte 0x1 ; CIE Version + .ascii "zR\0" ; CIE Augmentation + .byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor + .byte 0x7c ; sleb128 -4; CIE Data Alignment Factor + .byte 0x41 ; CIE RA Column + .byte 0x1 ; uleb128 0x1; Augmentation size + .byte 0x90 ; FDE Encoding (indirect pcrel) + .byte 0xc ; DW_CFA_def_cfa + .byte 0x1 ; uleb128 0x1 + .byte 0x0 ; uleb128 0x0 + .align LOG2_GPR_BYTES +LECIE1: +.globl _ffi_call_DARWIN.eh +_ffi_call_DARWIN.eh: +LSFDE1: + .set L$set$1,LEFDE1-LASFDE1 + .long L$set$1 ; FDE Length +LASFDE1: + .long LASFDE1-EH_frame1 ; FDE CIE offset + .g_long LLFB0$non_lazy_ptr-. ; FDE initial location + .set L$set$3,LFE1-LFB0 + .g_long L$set$3 ; FDE address range + .byte 0x0 ; uleb128 0x0; Augmentation size + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$4,LCFI0-LFB1 + .long L$set$4 + .byte 0xd ; DW_CFA_def_cfa_register + .byte 0x08 ; uleb128 0x08 + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$5,LCFI1-LCFI0 + .long L$set$5 + .byte 0x11 ; DW_CFA_offset_extended_sf + .byte 0x41 ; uleb128 0x41 + .byte 0x7e ; sleb128 -2 + .byte 0x9f ; DW_CFA_offset, column 0x1f + .byte 0x1 ; uleb128 0x1 + .byte 0x9e ; DW_CFA_offset, column 0x1e + .byte 0x2 ; uleb128 0x2 + .byte 0x9d ; DW_CFA_offset, column 0x1d + .byte 0x3 ; uleb128 0x3 + .byte 0x9c ; DW_CFA_offset, column 0x1c + .byte 0x4 ; uleb128 0x4 + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$6,LCFI2-LCFI1 + .long L$set$6 + .byte 0xd ; DW_CFA_def_cfa_register + .byte 0x1c ; uleb128 0x1c + .align LOG2_GPR_BYTES +LEFDE1: +.data + .align LOG2_GPR_BYTES +LLFB0$non_lazy_ptr: + .g_long LFB0 diff --git a/js/src/ctypes/libffi/src/powerpc/darwin_closure.S b/js/src/ctypes/libffi/src/powerpc/darwin_closure.S new file mode 100644 index 0000000..7959838 --- /dev/null +++ b/js/src/ctypes/libffi/src/powerpc/darwin_closure.S @@ -0,0 +1,317 @@ +/* ----------------------------------------------------------------------- + darwin_closure.S - Copyright (c) 2002, 2003, 2004, Free Software Foundation, + Inc. based on ppc_closure.S + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#define L(x) x + +#if defined(__ppc64__) +#define MODE_CHOICE(x, y) y +#else +#define MODE_CHOICE(x, y) x +#endif + +#define lgu MODE_CHOICE(lwzu, ldu) + +#define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */ + +#define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */ + + .file "darwin_closure.S" +.text + .align LOG2_GPR_BYTES +.globl _ffi_closure_ASM + +.text + .align LOG2_GPR_BYTES +_ffi_closure_ASM: +LFB1: + mflr r0 /* extract return address */ + stw r0,8(r1) /* save the return address */ +LCFI0: + /* 24 Bytes (Linkage Area) + 32 Bytes (outgoing parameter area, always reserved) + 104 Bytes (13*8 from FPR) + 16 Bytes (result) + 176 Bytes */ + + stwu r1,-176(r1) /* skip over caller save area + keep stack aligned to 16. */ +LCFI1: + /* We want to build up an area for the parameters passed + in registers. (both floating point and integer) */ + + /* We store gpr 3 to gpr 10 (aligned to 4) + in the parents outgoing area. */ + stw r3,200(r1) + stw r4,204(r1) + stw r5,208(r1) + stw r6,212(r1) + stw r7,216(r1) + stw r8,220(r1) + stw r9,224(r1) + stw r10,228(r1) + + /* We save fpr 1 to fpr 13. (aligned to 8) */ + stfd f1,56(r1) + stfd f2,64(r1) + stfd f3,72(r1) + stfd f4,80(r1) + stfd f5,88(r1) + stfd f6,96(r1) + stfd f7,104(r1) + stfd f8,112(r1) + stfd f9,120(r1) + stfd f10,128(r1) + stfd f11,136(r1) + stfd f12,144(r1) + stfd f13,152(r1) + + /* Set up registers for the routine that actually does the work + get the context pointer from the trampoline. */ + mr r3,r11 + + /* Now load up the pointer to the result storage. */ + addi r4,r1,160 + + /* Now load up the pointer to the saved gpr registers. */ + addi r5,r1,200 + + /* Now load up the pointer to the saved fpr registers. */ + addi r6,r1,56 + + /* Make the call. */ + bl Lffi_closure_helper_DARWIN$stub + + /* Now r3 contains the return type + so use it to look up in a table + so we know how to deal with each type. */ + + /* Look up the proper starting point in table + by using return type as offset. */ + addi r5,r1,160 /* Get pointer to results area. */ + bl Lget_ret_type0_addr /* Get pointer to Lret_type0 into LR. */ + mflr r4 /* Move to r4. */ + slwi r3,r3,4 /* Now multiply return type by 16. */ + add r3,r3,r4 /* Add contents of table to table address. */ + mtctr r3 + bctr /* Jump to it. */ +LFE1: +/* Each of the ret_typeX code fragments has to be exactly 16 bytes long + (4 instructions). For cache effectiveness we align to a 16 byte boundary + first. */ + + .align 4 + + nop + nop + nop +Lget_ret_type0_addr: + blrl + +/* case FFI_TYPE_VOID */ +Lret_type0: + b Lfinish + nop + nop + nop + +/* case FFI_TYPE_INT */ +Lret_type1: + lwz r3,0(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_FLOAT */ +Lret_type2: + lfs f1,0(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_DOUBLE */ +Lret_type3: + lfd f1,0(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_LONGDOUBLE */ +Lret_type4: + lfd f1,0(r5) + lfd f2,8(r5) + b Lfinish + nop + +/* case FFI_TYPE_UINT8 */ +Lret_type5: + lbz r3,3(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_SINT8 */ +Lret_type6: + lbz r3,3(r5) + extsb r3,r3 + b Lfinish + nop + +/* case FFI_TYPE_UINT16 */ +Lret_type7: + lhz r3,2(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_SINT16 */ +Lret_type8: + lha r3,2(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_UINT32 */ +Lret_type9: + lwz r3,0(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_SINT32 */ +Lret_type10: + lwz r3,0(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_UINT64 */ +Lret_type11: + lwz r3,0(r5) + lwz r4,4(r5) + b Lfinish + nop + +/* case FFI_TYPE_SINT64 */ +Lret_type12: + lwz r3,0(r5) + lwz r4,4(r5) + b Lfinish + nop + +/* case FFI_TYPE_STRUCT */ +Lret_type13: + b Lfinish + nop + nop + nop + +/* case FFI_TYPE_POINTER */ +Lret_type14: + lwz r3,0(r5) + b Lfinish + nop + nop + +/* case done */ +Lfinish: + addi r1,r1,176 /* Restore stack pointer. */ + lwz r0,8(r1) /* Get return address. */ + mtlr r0 /* Reset link register. */ + blr + +/* END(ffi_closure_ASM) */ + +.data +.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support +EH_frame1: + .set L$set$0,LECIE1-LSCIE1 + .long L$set$0 ; Length of Common Information Entry +LSCIE1: + .long 0x0 ; CIE Identifier Tag + .byte 0x1 ; CIE Version + .ascii "zR\0" ; CIE Augmentation + .byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor + .byte 0x7c ; sleb128 -4; CIE Data Alignment Factor + .byte 0x41 ; CIE RA Column + .byte 0x1 ; uleb128 0x1; Augmentation size + .byte 0x90 ; FDE Encoding (indirect pcrel) + .byte 0xc ; DW_CFA_def_cfa + .byte 0x1 ; uleb128 0x1 + .byte 0x0 ; uleb128 0x0 + .align LOG2_GPR_BYTES +LECIE1: +.globl _ffi_closure_ASM.eh +_ffi_closure_ASM.eh: +LSFDE1: + .set L$set$1,LEFDE1-LASFDE1 + .long L$set$1 ; FDE Length + +LASFDE1: + .long LASFDE1-EH_frame1 ; FDE CIE offset + .g_long LLFB1$non_lazy_ptr-. ; FDE initial location + .set L$set$3,LFE1-LFB1 + .g_long L$set$3 ; FDE address range + .byte 0x0 ; uleb128 0x0; Augmentation size + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$3,LCFI1-LCFI0 + .long L$set$3 + .byte 0xe ; DW_CFA_def_cfa_offset + .byte 176,1 ; uleb128 176 + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$4,LCFI0-LFB1 + .long L$set$4 + .byte 0x11 ; DW_CFA_offset_extended_sf + .byte 0x41 ; uleb128 0x41 + .byte 0x7e ; sleb128 -2 + .align LOG2_GPR_BYTES +LEFDE1: +.data + .align LOG2_GPR_BYTES +LDFCM0: +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align LOG2_GPR_BYTES +Lffi_closure_helper_DARWIN$stub: +#if 1 + .indirect_symbol _ffi_closure_helper_DARWIN + mflr r0 + bcl 20,31,LO$ffi_closure_helper_DARWIN +LO$ffi_closure_helper_DARWIN: + mflr r11 + addis r11,r11,ha16(L_ffi_closure_helper_DARWIN$lazy_ptr - LO$ffi_closure_helper_DARWIN) + mtlr r0 + lgu r12,lo16(L_ffi_closure_helper_DARWIN$lazy_ptr - LO$ffi_closure_helper_DARWIN)(r11) + mtctr r12 + bctr +.lazy_symbol_pointer +L_ffi_closure_helper_DARWIN$lazy_ptr: + .indirect_symbol _ffi_closure_helper_DARWIN + .g_long dyld_stub_binding_helper +#endif +.data + .align LOG2_GPR_BYTES +LLFB1$non_lazy_ptr: + .g_long LFB1 diff --git a/js/src/ctypes/libffi/src/powerpc/ffi.c b/js/src/ctypes/libffi/src/powerpc/ffi.c new file mode 100644 index 0000000..75784a9 --- /dev/null +++ b/js/src/ctypes/libffi/src/powerpc/ffi.c @@ -0,0 +1,1442 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1998 Geoffrey Keating + Copyright (C) 2007, 2008 Free Software Foundation, Inc + Copyright (C) 2008 Red Hat, Inc + + PowerPC Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include +#include + + +extern void ffi_closure_SYSV (void); +extern void FFI_HIDDEN ffi_closure_LINUX64 (void); + +enum { + /* The assembly depends on these exact flags. */ + FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */ + FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */ + FLAG_RETURNS_FP = 1 << (31-29), + FLAG_RETURNS_64BITS = 1 << (31-28), + + FLAG_RETURNS_128BITS = 1 << (31-27), /* cr6 */ + FLAG_SYSV_SMST_R4 = 1 << (31-26), /* use r4 for FFI_SYSV 8 byte + structs. */ + FLAG_SYSV_SMST_R3 = 1 << (31-25), /* use r3 for FFI_SYSV 4 byte + structs. */ + /* Bits (31-24) through (31-19) store shift value for SMST */ + + FLAG_ARG_NEEDS_COPY = 1 << (31- 7), + FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */ + FLAG_4_GPR_ARGUMENTS = 1 << (31- 5), + FLAG_RETVAL_REFERENCE = 1 << (31- 4) +}; + +/* About the SYSV ABI. */ +unsigned int NUM_GPR_ARG_REGISTERS = 8; +#ifndef __NO_FPRS__ +unsigned int NUM_FPR_ARG_REGISTERS = 8; +#else +unsigned int NUM_FPR_ARG_REGISTERS = 0; +#endif + +enum { ASM_NEEDS_REGISTERS = 4 }; + +/* ffi_prep_args_SYSV is called by the assembly routine once stack space + has been allocated for the function's arguments. + + The stack layout we want looks like this: + + | Return address from ffi_call_SYSV 4bytes | higher addresses + |--------------------------------------------| + | Previous backchain pointer 4 | stack pointer here + |--------------------------------------------|<+ <<< on entry to + | Saved r28-r31 4*4 | | ffi_call_SYSV + |--------------------------------------------| | + | GPR registers r3-r10 8*4 | | ffi_call_SYSV + |--------------------------------------------| | + | FPR registers f1-f8 (optional) 8*8 | | + |--------------------------------------------| | stack | + | Space for copied structures | | grows | + |--------------------------------------------| | down V + | Parameters that didn't fit in registers | | + |--------------------------------------------| | lower addresses + | Space for callee's LR 4 | | + |--------------------------------------------| | stack pointer here + | Current backchain pointer 4 |-/ during + |--------------------------------------------| <<< ffi_call_SYSV + +*/ + +void +ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack) +{ + const unsigned bytes = ecif->cif->bytes; + const unsigned flags = ecif->cif->flags; + + typedef union { + char *c; + unsigned *u; + long long *ll; + float *f; + double *d; + } valp; + + /* 'stacktop' points at the previous backchain pointer. */ + valp stacktop; + + /* 'gpr_base' points at the space for gpr3, and grows upwards as + we use GPR registers. */ + valp gpr_base; + int intarg_count; + + /* 'fpr_base' points at the space for fpr1, and grows upwards as + we use FPR registers. */ + valp fpr_base; + int fparg_count; + + /* 'copy_space' grows down as we put structures in it. It should + stay 16-byte aligned. */ + valp copy_space; + + /* 'next_arg' grows up as we put parameters in it. */ + valp next_arg; + + int i, ii MAYBE_UNUSED; + ffi_type **ptr; + double double_tmp; + union { + void **v; + char **c; + signed char **sc; + unsigned char **uc; + signed short **ss; + unsigned short **us; + unsigned int **ui; + long long **ll; + float **f; + double **d; + } p_argv; + size_t struct_copy_size; + unsigned gprvalue; + + if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT) + NUM_FPR_ARG_REGISTERS = 0; + + stacktop.c = (char *) stack + bytes; + gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS; + intarg_count = 0; + fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS; + fparg_count = 0; + copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c); + next_arg.u = stack + 2; + + /* Check that everything starts aligned properly. */ + FFI_ASSERT (((unsigned) (char *) stack & 0xF) == 0); + FFI_ASSERT (((unsigned) copy_space.c & 0xF) == 0); + FFI_ASSERT (((unsigned) stacktop.c & 0xF) == 0); + FFI_ASSERT ((bytes & 0xF) == 0); + FFI_ASSERT (copy_space.c >= next_arg.c); + + /* Deal with return values that are actually pass-by-reference. */ + if (flags & FLAG_RETVAL_REFERENCE) + { + *gpr_base.u++ = (unsigned long) (char *) ecif->rvalue; + intarg_count++; + } + + /* Now for the arguments. */ + p_argv.v = ecif->avalue; + for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; + i > 0; + i--, ptr++, p_argv.v++) + { + switch ((*ptr)->type) + { + case FFI_TYPE_FLOAT: + /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */ + if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT) + goto soft_float_prep; + double_tmp = **p_argv.f; + if (fparg_count >= NUM_FPR_ARG_REGISTERS) + { + *next_arg.f = (float) double_tmp; + next_arg.u += 1; + intarg_count++; + } + else + *fpr_base.d++ = double_tmp; + fparg_count++; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; + + case FFI_TYPE_DOUBLE: + /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */ + if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT) + goto soft_double_prep; + double_tmp = **p_argv.d; + + if (fparg_count >= NUM_FPR_ARG_REGISTERS) + { + if (intarg_count >= NUM_GPR_ARG_REGISTERS + && intarg_count % 2 != 0) + { + intarg_count++; + next_arg.u++; + } + *next_arg.d = double_tmp; + next_arg.u += 2; + } + else + *fpr_base.d++ = double_tmp; + fparg_count++; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + if ((ecif->cif->abi != FFI_LINUX) + && (ecif->cif->abi != FFI_LINUX_SOFT_FLOAT)) + goto do_struct; + /* The soft float ABI for long doubles works like this, + a long double is passed in four consecutive gprs if available. + A maximum of 2 long doubles can be passed in gprs. + If we do not have 4 gprs left, the long double is passed on the + stack, 4-byte aligned. */ + if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT) + { + unsigned int int_tmp = (*p_argv.ui)[0]; + if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3) + { + if (intarg_count < NUM_GPR_ARG_REGISTERS) + intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count; + *next_arg.u = int_tmp; + next_arg.u++; + for (ii = 1; ii < 4; ii++) + { + int_tmp = (*p_argv.ui)[ii]; + *next_arg.u = int_tmp; + next_arg.u++; + } + } + else + { + *gpr_base.u++ = int_tmp; + for (ii = 1; ii < 4; ii++) + { + int_tmp = (*p_argv.ui)[ii]; + *gpr_base.u++ = int_tmp; + } + } + intarg_count +=4; + } + else + { + double_tmp = (*p_argv.d)[0]; + + if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1) + { + if (intarg_count >= NUM_GPR_ARG_REGISTERS + && intarg_count % 2 != 0) + { + intarg_count++; + next_arg.u++; + } + *next_arg.d = double_tmp; + next_arg.u += 2; + double_tmp = (*p_argv.d)[1]; + *next_arg.d = double_tmp; + next_arg.u += 2; + } + else + { + *fpr_base.d++ = double_tmp; + double_tmp = (*p_argv.d)[1]; + *fpr_base.d++ = double_tmp; + } + + fparg_count += 2; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + } + break; +#endif + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + soft_double_prep: + if (intarg_count == NUM_GPR_ARG_REGISTERS-1) + intarg_count++; + if (intarg_count >= NUM_GPR_ARG_REGISTERS) + { + if (intarg_count % 2 != 0) + { + intarg_count++; + next_arg.u++; + } + *next_arg.ll = **p_argv.ll; + next_arg.u += 2; + } + else + { + /* whoops: abi states only certain register pairs + * can be used for passing long long int + * specifically (r3,r4), (r5,r6), (r7,r8), + * (r9,r10) and if next arg is long long but + * not correct starting register of pair then skip + * until the proper starting register + */ + if (intarg_count % 2 != 0) + { + intarg_count ++; + gpr_base.u++; + } + *gpr_base.ll++ = **p_argv.ll; + } + intarg_count += 2; + break; + + case FFI_TYPE_STRUCT: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + do_struct: +#endif + struct_copy_size = ((*ptr)->size + 15) & ~0xF; + copy_space.c -= struct_copy_size; + memcpy (copy_space.c, *p_argv.c, (*ptr)->size); + + gprvalue = (unsigned long) copy_space.c; + + FFI_ASSERT (copy_space.c > next_arg.c); + FFI_ASSERT (flags & FLAG_ARG_NEEDS_COPY); + goto putgpr; + + case FFI_TYPE_UINT8: + gprvalue = **p_argv.uc; + goto putgpr; + case FFI_TYPE_SINT8: + gprvalue = **p_argv.sc; + goto putgpr; + case FFI_TYPE_UINT16: + gprvalue = **p_argv.us; + goto putgpr; + case FFI_TYPE_SINT16: + gprvalue = **p_argv.ss; + goto putgpr; + + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + soft_float_prep: + + gprvalue = **p_argv.ui; + + putgpr: + if (intarg_count >= NUM_GPR_ARG_REGISTERS) + *next_arg.u++ = gprvalue; + else + *gpr_base.u++ = gprvalue; + intarg_count++; + break; + } + } + + /* Check that we didn't overrun the stack... */ + FFI_ASSERT (copy_space.c >= next_arg.c); + FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS); + FFI_ASSERT (fpr_base.u + <= stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS); + FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4); +} + +/* About the LINUX64 ABI. */ +enum { + NUM_GPR_ARG_REGISTERS64 = 8, + NUM_FPR_ARG_REGISTERS64 = 13 +}; +enum { ASM_NEEDS_REGISTERS64 = 4 }; + +/* ffi_prep_args64 is called by the assembly routine once stack space + has been allocated for the function's arguments. + + The stack layout we want looks like this: + + | Ret addr from ffi_call_LINUX64 8bytes | higher addresses + |--------------------------------------------| + | CR save area 8bytes | + |--------------------------------------------| + | Previous backchain pointer 8 | stack pointer here + |--------------------------------------------|<+ <<< on entry to + | Saved r28-r31 4*8 | | ffi_call_LINUX64 + |--------------------------------------------| | + | GPR registers r3-r10 8*8 | | + |--------------------------------------------| | + | FPR registers f1-f13 (optional) 13*8 | | + |--------------------------------------------| | + | Parameter save area | | + |--------------------------------------------| | + | TOC save area 8 | | + |--------------------------------------------| | stack | + | Linker doubleword 8 | | grows | + |--------------------------------------------| | down V + | Compiler doubleword 8 | | + |--------------------------------------------| | lower addresses + | Space for callee's LR 8 | | + |--------------------------------------------| | + | CR save area 8 | | + |--------------------------------------------| | stack pointer here + | Current backchain pointer 8 |-/ during + |--------------------------------------------| <<< ffi_call_LINUX64 + +*/ + +void FFI_HIDDEN +ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack) +{ + const unsigned long bytes = ecif->cif->bytes; + const unsigned long flags = ecif->cif->flags; + + typedef union { + char *c; + unsigned long *ul; + float *f; + double *d; + } valp; + + /* 'stacktop' points at the previous backchain pointer. */ + valp stacktop; + + /* 'next_arg' points at the space for gpr3, and grows upwards as + we use GPR registers, then continues at rest. */ + valp gpr_base; + valp gpr_end; + valp rest; + valp next_arg; + + /* 'fpr_base' points at the space for fpr3, and grows upwards as + we use FPR registers. */ + valp fpr_base; + int fparg_count; + + int i, words; + ffi_type **ptr; + double double_tmp; + union { + void **v; + char **c; + signed char **sc; + unsigned char **uc; + signed short **ss; + unsigned short **us; + signed int **si; + unsigned int **ui; + unsigned long **ul; + float **f; + double **d; + } p_argv; + unsigned long gprvalue; + + stacktop.c = (char *) stack + bytes; + gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64; + gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64; + rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64; + fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64; + fparg_count = 0; + next_arg.ul = gpr_base.ul; + + /* Check that everything starts aligned properly. */ + FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0); + FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0); + FFI_ASSERT ((bytes & 0xF) == 0); + + /* Deal with return values that are actually pass-by-reference. */ + if (flags & FLAG_RETVAL_REFERENCE) + *next_arg.ul++ = (unsigned long) (char *) ecif->rvalue; + + /* Now for the arguments. */ + p_argv.v = ecif->avalue; + for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; + i > 0; + i--, ptr++, p_argv.v++) + { + switch ((*ptr)->type) + { + case FFI_TYPE_FLOAT: + double_tmp = **p_argv.f; + *next_arg.f = (float) double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + if (fparg_count < NUM_FPR_ARG_REGISTERS64) + *fpr_base.d++ = double_tmp; + fparg_count++; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; + + case FFI_TYPE_DOUBLE: + double_tmp = **p_argv.d; + *next_arg.d = double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + if (fparg_count < NUM_FPR_ARG_REGISTERS64) + *fpr_base.d++ = double_tmp; + fparg_count++; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + double_tmp = (*p_argv.d)[0]; + *next_arg.d = double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + if (fparg_count < NUM_FPR_ARG_REGISTERS64) + *fpr_base.d++ = double_tmp; + fparg_count++; + double_tmp = (*p_argv.d)[1]; + *next_arg.d = double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + if (fparg_count < NUM_FPR_ARG_REGISTERS64) + *fpr_base.d++ = double_tmp; + fparg_count++; + FFI_ASSERT (__LDBL_MANT_DIG__ == 106); + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; +#endif + + case FFI_TYPE_STRUCT: + words = ((*ptr)->size + 7) / 8; + if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul) + { + size_t first = gpr_end.c - next_arg.c; + memcpy (next_arg.c, *p_argv.c, first); + memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first); + next_arg.c = rest.c + words * 8 - first; + } + else + { + char *where = next_arg.c; + + /* Structures with size less than eight bytes are passed + left-padded. */ + if ((*ptr)->size < 8) + where += 8 - (*ptr)->size; + + memcpy (where, *p_argv.c, (*ptr)->size); + next_arg.ul += words; + if (next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + } + break; + + case FFI_TYPE_UINT8: + gprvalue = **p_argv.uc; + goto putgpr; + case FFI_TYPE_SINT8: + gprvalue = **p_argv.sc; + goto putgpr; + case FFI_TYPE_UINT16: + gprvalue = **p_argv.us; + goto putgpr; + case FFI_TYPE_SINT16: + gprvalue = **p_argv.ss; + goto putgpr; + case FFI_TYPE_UINT32: + gprvalue = **p_argv.ui; + goto putgpr; + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + gprvalue = **p_argv.si; + goto putgpr; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_POINTER: + gprvalue = **p_argv.ul; + putgpr: + *next_arg.ul++ = gprvalue; + if (next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + break; + } + } + + FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS + || (next_arg.ul >= gpr_base.ul + && next_arg.ul <= gpr_base.ul + 4)); +} + + + +/* Perform machine dependent cif processing */ +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + /* All this is for the SYSV and LINUX64 ABI. */ + int i; + ffi_type **ptr; + unsigned bytes; + int fparg_count = 0, intarg_count = 0; + unsigned flags = 0; + unsigned struct_copy_size = 0; + unsigned type = cif->rtype->type; + unsigned size = cif->rtype->size; + + if (cif->abi == FFI_LINUX_SOFT_FLOAT) + NUM_FPR_ARG_REGISTERS = 0; + + if (cif->abi != FFI_LINUX64) + { + /* All the machine-independent calculation of cif->bytes will be wrong. + Redo the calculation for SYSV. */ + + /* Space for the frame pointer, callee's LR, and the asm's temp regs. */ + bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof (int); + + /* Space for the GPR registers. */ + bytes += NUM_GPR_ARG_REGISTERS * sizeof (int); + } + else + { + /* 64-bit ABI. */ + + /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp + regs. */ + bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long); + + /* Space for the mandatory parm save area and general registers. */ + bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long); + } + + /* Return value handling. The rules for SYSV are as follows: + - 32-bit (or less) integer values are returned in gpr3; + - Structures of size <= 4 bytes also returned in gpr3; + - 64-bit integer values and structures between 5 and 8 bytes are returned + in gpr3 and gpr4; + - Single/double FP values are returned in fpr1; + - Larger structures are allocated space and a pointer is passed as + the first argument. + - long doubles (if not equivalent to double) are returned in + fpr1,fpr2 for Linux and as for large structs for SysV. + For LINUX64: + - integer values in gpr3; + - Structures/Unions by reference; + - Single/double FP values in fpr1, long double in fpr1,fpr2. + - soft-float float/doubles are treated as UINT32/UINT64 respectivley. + - soft-float long doubles are returned in gpr3-gpr6. */ + switch (type) + { +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64 + && cif->abi != FFI_LINUX_SOFT_FLOAT) + goto byref; + flags |= FLAG_RETURNS_128BITS; + /* Fall through. */ +#endif + case FFI_TYPE_DOUBLE: + flags |= FLAG_RETURNS_64BITS; + /* Fall through. */ + case FFI_TYPE_FLOAT: + /* With FFI_LINUX_SOFT_FLOAT no fp registers are used. */ + if (cif->abi != FFI_LINUX_SOFT_FLOAT) + flags |= FLAG_RETURNS_FP; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + flags |= FLAG_RETURNS_64BITS; + break; + + case FFI_TYPE_STRUCT: + if (cif->abi == FFI_SYSV) + { + /* The final SYSV ABI says that structures smaller or equal 8 bytes + are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them + in memory. */ + + /* Treat structs with size <= 8 bytes. */ + if (size <= 8) + { + flags |= FLAG_RETURNS_SMST; + /* These structs are returned in r3. We pack the type and the + precalculated shift value (needed in the sysv.S) into flags. + The same applies for the structs returned in r3/r4. */ + if (size <= 4) + { + flags |= FLAG_SYSV_SMST_R3; + flags |= 8 * (4 - size) << 8; + break; + } + /* These structs are returned in r3 and r4. See above. */ + if (size <= 8) + { + flags |= FLAG_SYSV_SMST_R3 | FLAG_SYSV_SMST_R4; + flags |= 8 * (8 - size) << 8; + break; + } + } + } +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + byref: +#endif + intarg_count++; + flags |= FLAG_RETVAL_REFERENCE; + /* Fall through. */ + case FFI_TYPE_VOID: + flags |= FLAG_RETURNS_NOTHING; + break; + + default: + /* Returns 32-bit integer, or similar. Nothing to do here. */ + break; + } + + if (cif->abi != FFI_LINUX64) + /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the + first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest + goes on the stack. Structures and long doubles (if not equivalent + to double) are passed as a pointer to a copy of the structure. + Stuff on the stack needs to keep proper alignment. */ + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + switch ((*ptr)->type) + { + case FFI_TYPE_FLOAT: + /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */ + if (cif->abi == FFI_LINUX_SOFT_FLOAT) + goto soft_float_cif; + fparg_count++; + /* floating singles are not 8-aligned on stack */ + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT) + goto do_struct; + if (cif->abi == FFI_LINUX_SOFT_FLOAT) + { + if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3 + || intarg_count < NUM_GPR_ARG_REGISTERS) + /* A long double in FFI_LINUX_SOFT_FLOAT can use only + a set of four consecutive gprs. If we have not enough, + we have to adjust the intarg_count value. */ + intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count; + intarg_count += 4; + break; + } + else + fparg_count++; + /* Fall thru */ +#endif + case FFI_TYPE_DOUBLE: + /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */ + if (cif->abi == FFI_LINUX_SOFT_FLOAT) + goto soft_double_cif; + fparg_count++; + /* If this FP arg is going on the stack, it must be + 8-byte-aligned. */ + if (fparg_count > NUM_FPR_ARG_REGISTERS + && intarg_count >= NUM_GPR_ARG_REGISTERS + && intarg_count % 2 != 0) + intarg_count++; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + soft_double_cif: + /* 'long long' arguments are passed as two words, but + either both words must fit in registers or both go + on the stack. If they go on the stack, they must + be 8-byte-aligned. + + Also, only certain register pairs can be used for + passing long long int -- specifically (r3,r4), (r5,r6), + (r7,r8), (r9,r10). + */ + if (intarg_count == NUM_GPR_ARG_REGISTERS-1 + || intarg_count % 2 != 0) + intarg_count++; + intarg_count += 2; + break; + + case FFI_TYPE_STRUCT: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + do_struct: +#endif + /* We must allocate space for a copy of these to enforce + pass-by-value. Pad the space up to a multiple of 16 + bytes (the maximum alignment required for anything under + the SYSV ABI). */ + struct_copy_size += ((*ptr)->size + 15) & ~0xF; + /* Fall through (allocate space for the pointer). */ + + default: + soft_float_cif: + /* Everything else is passed as a 4-byte word in a GPR, either + the object itself or a pointer to it. */ + intarg_count++; + break; + } + } + else + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + switch ((*ptr)->type) + { +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + if (cif->abi == FFI_LINUX_SOFT_FLOAT) + intarg_count += 4; + else + { + fparg_count += 2; + intarg_count += 2; + } + break; +#endif + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + fparg_count++; + intarg_count++; + break; + + case FFI_TYPE_STRUCT: + intarg_count += ((*ptr)->size + 7) / 8; + break; + + default: + /* Everything else is passed as a 8-byte word in a GPR, either + the object itself or a pointer to it. */ + intarg_count++; + break; + } + } + + if (fparg_count != 0) + flags |= FLAG_FP_ARGUMENTS; + if (intarg_count > 4) + flags |= FLAG_4_GPR_ARGUMENTS; + if (struct_copy_size != 0) + flags |= FLAG_ARG_NEEDS_COPY; + + if (cif->abi != FFI_LINUX64) + { + /* Space for the FPR registers, if needed. */ + if (fparg_count != 0) + bytes += NUM_FPR_ARG_REGISTERS * sizeof (double); + + /* Stack space. */ + if (intarg_count > NUM_GPR_ARG_REGISTERS) + bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof (int); + if (fparg_count > NUM_FPR_ARG_REGISTERS) + bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof (double); + } + else + { + /* Space for the FPR registers, if needed. */ + if (fparg_count != 0) + bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double); + + /* Stack space. */ + if (intarg_count > NUM_GPR_ARG_REGISTERS64) + bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long); + } + + /* The stack space allocated needs to be a multiple of 16 bytes. */ + bytes = (bytes + 15) & ~0xF; + + /* Add in the space for the copied structures. */ + bytes += struct_copy_size; + + cif->flags = flags; + cif->bytes = bytes; + + return FFI_OK; +} + +extern void ffi_call_SYSV(extended_cif *, unsigned, unsigned, unsigned *, + void (*fn)(void)); +extern void FFI_HIDDEN ffi_call_LINUX64(extended_cif *, unsigned long, + unsigned long, unsigned long *, + void (*fn)(void)); + +void +ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) + { + ecif.rvalue = alloca(cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { +#ifndef POWERPC64 + case FFI_SYSV: + case FFI_GCC_SYSV: + case FFI_LINUX: + case FFI_LINUX_SOFT_FLOAT: + ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn); + break; +#else + case FFI_LINUX64: + ffi_call_LINUX64 (&ecif, -(long) cif->bytes, cif->flags, ecif.rvalue, fn); + break; +#endif + default: + FFI_ASSERT (0); + break; + } +} + + +#ifndef POWERPC64 +#define MIN_CACHE_LINE_SIZE 8 + +static void +flush_icache (char *wraddr, char *xaddr, int size) +{ + int i; + for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) + __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" + : : "r" (xaddr + i), "r" (wraddr + i) : "memory"); + __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;" + : : "r"(xaddr + size - 1), "r"(wraddr + size - 1) + : "memory"); +} +#endif + +ffi_status +ffi_prep_closure_loc (ffi_closure *closure, + ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + void *codeloc) +{ +#ifdef POWERPC64 + void **tramp = (void **) &closure->tramp[0]; + + FFI_ASSERT (cif->abi == FFI_LINUX64); + /* Copy function address and TOC from ffi_closure_LINUX64. */ + memcpy (tramp, (char *) ffi_closure_LINUX64, 16); + tramp[2] = codeloc; +#else + unsigned int *tramp; + + FFI_ASSERT (cif->abi == FFI_GCC_SYSV || cif->abi == FFI_SYSV); + + tramp = (unsigned int *) &closure->tramp[0]; + tramp[0] = 0x7c0802a6; /* mflr r0 */ + tramp[1] = 0x4800000d; /* bl 10 */ + tramp[4] = 0x7d6802a6; /* mflr r11 */ + tramp[5] = 0x7c0803a6; /* mtlr r0 */ + tramp[6] = 0x800b0000; /* lwz r0,0(r11) */ + tramp[7] = 0x816b0004; /* lwz r11,4(r11) */ + tramp[8] = 0x7c0903a6; /* mtctr r0 */ + tramp[9] = 0x4e800420; /* bctr */ + *(void **) &tramp[2] = (void *) ffi_closure_SYSV; /* function */ + *(void **) &tramp[3] = codeloc; /* context */ + + /* Flush the icache. */ + flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE); +#endif + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} + +typedef union +{ + float f; + double d; +} ffi_dblfl; + +int ffi_closure_helper_SYSV (ffi_closure *, void *, unsigned long *, + ffi_dblfl *, unsigned long *); + +/* Basically the trampoline invokes ffi_closure_SYSV, and on + * entry, r11 holds the address of the closure. + * After storing the registers that could possibly contain + * parameters to be passed into the stack frame and setting + * up space for a return value, ffi_closure_SYSV invokes the + * following helper function to do most of the work + */ + +int +ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue, + unsigned long *pgr, ffi_dblfl *pfr, + unsigned long *pst) +{ + /* rvalue is the pointer to space for return value in closure assembly */ + /* pgr is the pointer to where r3-r10 are stored in ffi_closure_SYSV */ + /* pfr is the pointer to where f1-f8 are stored in ffi_closure_SYSV */ + /* pst is the pointer to outgoing parameter stack in original caller */ + + void ** avalue; + ffi_type ** arg_types; + long i, avn; + long nf; /* number of floating registers already used */ + long ng; /* number of general registers already used */ + ffi_cif * cif; + double temp; + unsigned size; + + cif = closure->cif; + avalue = alloca (cif->nargs * sizeof (void *)); + size = cif->rtype->size; + + nf = 0; + ng = 0; + + /* Copy the caller's structure return value address so that the closure + returns the data directly to the caller. + For FFI_SYSV the result is passed in r3/r4 if the struct size is less + or equal 8 bytes. */ + + if ((cif->rtype->type == FFI_TYPE_STRUCT + && !((cif->abi == FFI_SYSV) && (size <= 8))) +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + || (cif->rtype->type == FFI_TYPE_LONGDOUBLE + && cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT) +#endif + ) + { + rvalue = (void *) *pgr; + ng++; + pgr++; + } + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + /* Grab the addresses of the arguments from the stack frame. */ + while (i < avn) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + /* there are 8 gpr registers used to pass values */ + if (ng < 8) + { + avalue[i] = (char *) pgr + 3; + ng++; + pgr++; + } + else + { + avalue[i] = (char *) pst + 3; + pst++; + } + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + /* there are 8 gpr registers used to pass values */ + if (ng < 8) + { + avalue[i] = (char *) pgr + 2; + ng++; + pgr++; + } + else + { + avalue[i] = (char *) pst + 2; + pst++; + } + break; + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + soft_float_closure: + /* there are 8 gpr registers used to pass values */ + if (ng < 8) + { + avalue[i] = pgr; + ng++; + pgr++; + } + else + { + avalue[i] = pst; + pst++; + } + break; + + case FFI_TYPE_STRUCT: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + do_struct: +#endif + /* Structs are passed by reference. The address will appear in a + gpr if it is one of the first 8 arguments. */ + if (ng < 8) + { + avalue[i] = (void *) *pgr; + ng++; + pgr++; + } + else + { + avalue[i] = (void *) *pst; + pst++; + } + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + soft_double_closure: + /* passing long long ints are complex, they must + * be passed in suitable register pairs such as + * (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10) + * and if the entire pair aren't available then the outgoing + * parameter stack is used for both but an alignment of 8 + * must will be kept. So we must either look in pgr + * or pst to find the correct address for this type + * of parameter. + */ + if (ng < 7) + { + if (ng & 0x01) + { + /* skip r4, r6, r8 as starting points */ + ng++; + pgr++; + } + avalue[i] = pgr; + ng += 2; + pgr += 2; + } + else + { + if (((long) pst) & 4) + pst++; + avalue[i] = pst; + pst += 2; + ng = 8; + } + break; + + case FFI_TYPE_FLOAT: + /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */ + if (cif->abi == FFI_LINUX_SOFT_FLOAT) + goto soft_float_closure; + /* unfortunately float values are stored as doubles + * in the ffi_closure_SYSV code (since we don't check + * the type in that routine). + */ + + /* there are 8 64bit floating point registers */ + + if (nf < 8) + { + temp = pfr->d; + pfr->f = (float) temp; + avalue[i] = pfr; + nf++; + pfr++; + } + else + { + /* FIXME? here we are really changing the values + * stored in the original calling routines outgoing + * parameter stack. This is probably a really + * naughty thing to do but... + */ + avalue[i] = pst; + pst += 1; + } + break; + + case FFI_TYPE_DOUBLE: + /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */ + if (cif->abi == FFI_LINUX_SOFT_FLOAT) + goto soft_double_closure; + /* On the outgoing stack all values are aligned to 8 */ + /* there are 8 64bit floating point registers */ + + if (nf < 8) + { + avalue[i] = pfr; + nf++; + pfr++; + } + else + { + if (((long) pst) & 4) + pst++; + avalue[i] = pst; + pst += 2; + } + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT) + goto do_struct; + if (cif->abi == FFI_LINUX_SOFT_FLOAT) + { /* Test if for the whole long double, 4 gprs are available. + otherwise the stuff ends up on the stack. */ + if (ng < 5) + { + avalue[i] = pgr; + pgr += 4; + ng += 4; + } + else + { + avalue[i] = pst; + pst += 4; + ng = 8; + } + break; + } + if (nf < 7) + { + avalue[i] = pfr; + pfr += 2; + nf += 2; + } + else + { + if (((long) pst) & 4) + pst++; + avalue[i] = pst; + pst += 4; + nf = 8; + } + break; +#endif + + default: + FFI_ASSERT (0); + } + + i++; + } + + + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_SYSV how to perform return type promotions. + Because the FFI_SYSV ABI returns the structures <= 8 bytes in r3/r4 + we have to tell ffi_closure_SYSV how to treat them. We combine the base + type FFI_SYSV_TYPE_SMALL_STRUCT - 1 with the size of the struct. + So a one byte struct gets the return type 16. Return type 1 to 15 are + already used and we never have a struct with size zero. That is the reason + for the subtraction of 1. See the comment in ffitarget.h about ordering. + */ + if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT + && size <= 8) + return (FFI_SYSV_TYPE_SMALL_STRUCT - 1) + size; +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + else if (cif->rtype->type == FFI_TYPE_LONGDOUBLE + && cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT) + return FFI_TYPE_STRUCT; +#endif + /* With FFI_LINUX_SOFT_FLOAT floats and doubles are handled like UINT32 + respectivley UINT64. */ + if (cif->abi == FFI_LINUX_SOFT_FLOAT) + { + switch (cif->rtype->type) + { + case FFI_TYPE_FLOAT: + return FFI_TYPE_UINT32; + break; + case FFI_TYPE_DOUBLE: + return FFI_TYPE_UINT64; + break; +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + return FFI_TYPE_UINT128; + break; +#endif + default: + return cif->rtype->type; + } + } + else + { + return cif->rtype->type; + } +} + +int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *, + unsigned long *, ffi_dblfl *); + +int FFI_HIDDEN +ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, + unsigned long *pst, ffi_dblfl *pfr) +{ + /* rvalue is the pointer to space for return value in closure assembly */ + /* pst is the pointer to parameter save area + (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */ + /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */ + + void **avalue; + ffi_type **arg_types; + long i, avn; + ffi_cif *cif; + ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64; + + cif = closure->cif; + avalue = alloca (cif->nargs * sizeof (void *)); + + /* Copy the caller's structure return value address so that the closure + returns the data directly to the caller. */ + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + rvalue = (void *) *pst; + pst++; + } + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + /* Grab the addresses of the arguments from the stack frame. */ + while (i < avn) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = (char *) pst + 7; + pst++; + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = (char *) pst + 6; + pst++; + break; + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + avalue[i] = (char *) pst + 4; + pst++; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + avalue[i] = pst; + pst++; + break; + + case FFI_TYPE_STRUCT: + /* Structures with size less than eight bytes are passed + left-padded. */ + if (arg_types[i]->size < 8) + avalue[i] = (char *) pst + 8 - arg_types[i]->size; + else + avalue[i] = pst; + pst += (arg_types[i]->size + 7) / 8; + break; + + case FFI_TYPE_FLOAT: + /* unfortunately float values are stored as doubles + * in the ffi_closure_LINUX64 code (since we don't check + * the type in that routine). + */ + + /* there are 13 64bit floating point registers */ + + if (pfr < end_pfr) + { + double temp = pfr->d; + pfr->f = (float) temp; + avalue[i] = pfr; + pfr++; + } + else + avalue[i] = pst; + pst++; + break; + + case FFI_TYPE_DOUBLE: + /* On the outgoing stack all values are aligned to 8 */ + /* there are 13 64bit floating point registers */ + + if (pfr < end_pfr) + { + avalue[i] = pfr; + pfr++; + } + else + avalue[i] = pst; + pst++; + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + if (pfr + 1 < end_pfr) + { + avalue[i] = pfr; + pfr += 2; + } + else + { + if (pfr < end_pfr) + { + /* Passed partly in f13 and partly on the stack. + Move it all to the stack. */ + *pst = *(unsigned long *) pfr; + pfr++; + } + avalue[i] = pst; + } + pst += 2; + break; +#endif + + default: + FFI_ASSERT (0); + } + + i++; + } + + + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_LINUX64 how to perform return type promotions. */ + return cif->rtype->type; +} diff --git a/js/src/ctypes/libffi/src/powerpc/ffi_darwin.c b/js/src/ctypes/libffi/src/powerpc/ffi_darwin.c new file mode 100644 index 0000000..82265e8 --- /dev/null +++ b/js/src/ctypes/libffi/src/powerpc/ffi_darwin.c @@ -0,0 +1,928 @@ +/* ----------------------------------------------------------------------- + ffi_darwin.c + + Copyright (C) 1998 Geoffrey Keating + Copyright (C) 2001 John Hornkvist + Copyright (C) 2002, 2006, 2007, 2009 Free Software Foundation, Inc. + + FFI support for Darwin and AIX. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include + +extern void ffi_closure_ASM (void); + +enum { + /* The assembly depends on these exact flags. */ + FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */ + FLAG_RETURNS_FP = 1 << (31-29), + FLAG_RETURNS_64BITS = 1 << (31-28), + FLAG_RETURNS_128BITS = 1 << (31-31), + + FLAG_ARG_NEEDS_COPY = 1 << (31- 7), + FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */ + FLAG_4_GPR_ARGUMENTS = 1 << (31- 5), + FLAG_RETVAL_REFERENCE = 1 << (31- 4) +}; + +/* About the DARWIN ABI. */ +enum { + NUM_GPR_ARG_REGISTERS = 8, + NUM_FPR_ARG_REGISTERS = 13 +}; +enum { ASM_NEEDS_REGISTERS = 4 }; + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments. + + The stack layout we want looks like this: + + | Return address from ffi_call_DARWIN | higher addresses + |--------------------------------------------| + | Previous backchain pointer 4 | stack pointer here + |--------------------------------------------|<+ <<< on entry to + | Saved r28-r31 4*4 | | ffi_call_DARWIN + |--------------------------------------------| | + | Parameters (at least 8*4=32) | | + |--------------------------------------------| | + | Space for GPR2 4 | | + |--------------------------------------------| | stack | + | Reserved 2*4 | | grows | + |--------------------------------------------| | down V + | Space for callee's LR 4 | | + |--------------------------------------------| | lower addresses + | Saved CR 4 | | + |--------------------------------------------| | stack pointer here + | Current backchain pointer 4 |-/ during + |--------------------------------------------| <<< ffi_call_DARWIN + + */ + +void +ffi_prep_args (extended_cif *ecif, unsigned long *const stack) +{ + const unsigned bytes = ecif->cif->bytes; + const unsigned flags = ecif->cif->flags; + const unsigned nargs = ecif->cif->nargs; + const ffi_abi abi = ecif->cif->abi; + + /* 'stacktop' points at the previous backchain pointer. */ + unsigned long *const stacktop = stack + (bytes / sizeof(unsigned long)); + + /* 'fpr_base' points at the space for fpr1, and grows upwards as + we use FPR registers. */ + double *fpr_base = (double *) (stacktop - ASM_NEEDS_REGISTERS) - NUM_FPR_ARG_REGISTERS; + int fparg_count = 0; + + + /* 'next_arg' grows up as we put parameters in it. */ + unsigned long *next_arg = stack + 6; /* 6 reserved positions. */ + + int i; + double double_tmp; + void **p_argv = ecif->avalue; + unsigned long gprvalue; + ffi_type** ptr = ecif->cif->arg_types; + char *dest_cpy; + unsigned size_al = 0; + + /* Check that everything starts aligned properly. */ + FFI_ASSERT(((unsigned) (char *) stack & 0xF) == 0); + FFI_ASSERT(((unsigned) (char *) stacktop & 0xF) == 0); + FFI_ASSERT((bytes & 0xF) == 0); + + /* Deal with return values that are actually pass-by-reference. + Rule: + Return values are referenced by r3, so r4 is the first parameter. */ + + if (flags & FLAG_RETVAL_REFERENCE) + *next_arg++ = (unsigned long) (char *) ecif->rvalue; + + /* Now for the arguments. */ + for (i = nargs; i > 0; i--, ptr++, p_argv++) + { + switch ((*ptr)->type) + { + /* If a floating-point parameter appears before all of the general- + purpose registers are filled, the corresponding GPRs that match + the size of the floating-point parameter are skipped. */ + case FFI_TYPE_FLOAT: + double_tmp = *(float *) *p_argv; + if (fparg_count >= NUM_FPR_ARG_REGISTERS) + *(double *)next_arg = double_tmp; + else + *fpr_base++ = double_tmp; + next_arg++; + fparg_count++; + FFI_ASSERT(flags & FLAG_FP_ARGUMENTS); + break; + + case FFI_TYPE_DOUBLE: + double_tmp = *(double *) *p_argv; + if (fparg_count >= NUM_FPR_ARG_REGISTERS) + *(double *)next_arg = double_tmp; + else + *fpr_base++ = double_tmp; +#ifdef POWERPC64 + next_arg++; +#else + next_arg += 2; +#endif + fparg_count++; + FFI_ASSERT(flags & FLAG_FP_ARGUMENTS); + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + + case FFI_TYPE_LONGDOUBLE: +#ifdef POWERPC64 + if (fparg_count < NUM_FPR_ARG_REGISTERS) + *(long double *) fpr_base++ = *(long double *) *p_argv; + else + *(long double *) next_arg = *(long double *) *p_argv; + next_arg += 2; + fparg_count += 2; +#else + double_tmp = ((double *) *p_argv)[0]; + if (fparg_count < NUM_FPR_ARG_REGISTERS) + *fpr_base++ = double_tmp; + else + *(double *) next_arg = double_tmp; + next_arg += 2; + fparg_count++; + + double_tmp = ((double *) *p_argv)[1]; + if (fparg_count < NUM_FPR_ARG_REGISTERS) + *fpr_base++ = double_tmp; + else + *(double *) next_arg = double_tmp; + next_arg += 2; + fparg_count++; +#endif + FFI_ASSERT(flags & FLAG_FP_ARGUMENTS); + break; +#endif + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: +#ifdef POWERPC64 + gprvalue = *(long long *) *p_argv; + goto putgpr; +#else + *(long long *) next_arg = *(long long *) *p_argv; + next_arg += 2; +#endif + break; + case FFI_TYPE_POINTER: + gprvalue = *(unsigned long *) *p_argv; + goto putgpr; + case FFI_TYPE_UINT8: + gprvalue = *(unsigned char *) *p_argv; + goto putgpr; + case FFI_TYPE_SINT8: + gprvalue = *(signed char *) *p_argv; + goto putgpr; + case FFI_TYPE_UINT16: + gprvalue = *(unsigned short *) *p_argv; + goto putgpr; + case FFI_TYPE_SINT16: + gprvalue = *(signed short *) *p_argv; + goto putgpr; + + case FFI_TYPE_STRUCT: +#ifdef POWERPC64 + dest_cpy = (char *) next_arg; + size_al = (*ptr)->size; + if ((*ptr)->elements[0]->type == 3) + size_al = ALIGN((*ptr)->size, 8); + if (size_al < 3 && abi == FFI_DARWIN) + dest_cpy += 4 - size_al; + + memcpy ((char *) dest_cpy, (char *) *p_argv, size_al); + next_arg += (size_al + 7) / 8; +#else + dest_cpy = (char *) next_arg; + + /* Structures that match the basic modes (QI 1 byte, HI 2 bytes, + SI 4 bytes) are aligned as if they were those modes. + Structures with 3 byte in size are padded upwards. */ + size_al = (*ptr)->size; + /* If the first member of the struct is a double, then align + the struct to double-word. */ + if ((*ptr)->elements[0]->type == FFI_TYPE_DOUBLE) + size_al = ALIGN((*ptr)->size, 8); + if (size_al < 3 && abi == FFI_DARWIN) + dest_cpy += 4 - size_al; + + memcpy((char *) dest_cpy, (char *) *p_argv, size_al); + next_arg += (size_al + 3) / 4; +#endif + break; + + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + gprvalue = *(signed int *) *p_argv; + goto putgpr; + + case FFI_TYPE_UINT32: + gprvalue = *(unsigned int *) *p_argv; + putgpr: + *next_arg++ = gprvalue; + break; + default: + break; + } + } + + /* Check that we didn't overrun the stack... */ + //FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS); + //FFI_ASSERT((unsigned *)fpr_base + // <= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS); + //FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4); +} + +/* Adjust the size of S to be correct for Darwin. + On Darwin, the first field of a structure has natural alignment. */ + +static void +darwin_adjust_aggregate_sizes (ffi_type *s) +{ + int i; + + if (s->type != FFI_TYPE_STRUCT) + return; + + s->size = 0; + for (i = 0; s->elements[i] != NULL; i++) + { + ffi_type *p; + int align; + + p = s->elements[i]; + darwin_adjust_aggregate_sizes (p); + if (i == 0 + && (p->type == FFI_TYPE_UINT64 + || p->type == FFI_TYPE_SINT64 + || p->type == FFI_TYPE_DOUBLE + || p->alignment == 8)) + align = 8; + else if (p->alignment == 16 || p->alignment < 4) + align = p->alignment; + else + align = 4; + s->size = ALIGN(s->size, align) + p->size; + } + + s->size = ALIGN(s->size, s->alignment); + + if (s->elements[0]->type == FFI_TYPE_UINT64 + || s->elements[0]->type == FFI_TYPE_SINT64 + || s->elements[0]->type == FFI_TYPE_DOUBLE + || s->elements[0]->alignment == 8) + s->alignment = s->alignment > 8 ? s->alignment : 8; + /* Do not add additional tail padding. */ +} + +/* Adjust the size of S to be correct for AIX. + Word-align double unless it is the first member of a structure. */ + +static void +aix_adjust_aggregate_sizes (ffi_type *s) +{ + int i; + + if (s->type != FFI_TYPE_STRUCT) + return; + + s->size = 0; + for (i = 0; s->elements[i] != NULL; i++) + { + ffi_type *p; + int align; + + p = s->elements[i]; + aix_adjust_aggregate_sizes (p); + align = p->alignment; + if (i != 0 && p->type == FFI_TYPE_DOUBLE) + align = 4; + s->size = ALIGN(s->size, align) + p->size; + } + + s->size = ALIGN(s->size, s->alignment); + + if (s->elements[0]->type == FFI_TYPE_UINT64 + || s->elements[0]->type == FFI_TYPE_SINT64 + || s->elements[0]->type == FFI_TYPE_DOUBLE + || s->elements[0]->alignment == 8) + s->alignment = s->alignment > 8 ? s->alignment : 8; + /* Do not add additional tail padding. */ +} + +/* Perform machine dependent cif processing. */ +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + /* All this is for the DARWIN ABI. */ + unsigned i; + ffi_type **ptr; + unsigned bytes; + int fparg_count = 0, intarg_count = 0; + unsigned flags = 0; + unsigned size_al = 0; + + /* All the machine-independent calculation of cif->bytes will be wrong. + All the calculation of structure sizes will also be wrong. + Redo the calculation for DARWIN. */ + + if (cif->abi == FFI_DARWIN) + { + darwin_adjust_aggregate_sizes (cif->rtype); + for (i = 0; i < cif->nargs; i++) + darwin_adjust_aggregate_sizes (cif->arg_types[i]); + } + + if (cif->abi == FFI_AIX) + { + aix_adjust_aggregate_sizes (cif->rtype); + for (i = 0; i < cif->nargs; i++) + aix_adjust_aggregate_sizes (cif->arg_types[i]); + } + + /* Space for the frame pointer, callee's LR, CR, etc, and for + the asm's temp regs. */ + + bytes = (6 + ASM_NEEDS_REGISTERS) * sizeof(long); + + /* Return value handling. The rules are as follows: + - 32-bit (or less) integer values are returned in gpr3; + - Structures of size <= 4 bytes also returned in gpr3; + - 64-bit integer values and structures between 5 and 8 bytes are returned + in gpr3 and gpr4; + - Single/double FP values are returned in fpr1; + - Long double FP (if not equivalent to double) values are returned in + fpr1 and fpr2; + - Larger structures values are allocated space and a pointer is passed + as the first argument. */ + switch (cif->rtype->type) + { + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + flags |= FLAG_RETURNS_128BITS; + flags |= FLAG_RETURNS_FP; + break; +#endif + + case FFI_TYPE_DOUBLE: + flags |= FLAG_RETURNS_64BITS; + /* Fall through. */ + case FFI_TYPE_FLOAT: + flags |= FLAG_RETURNS_FP; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: +#ifdef POWERPC64 + case FFI_TYPE_POINTER: +#endif + flags |= FLAG_RETURNS_64BITS; + break; + + case FFI_TYPE_STRUCT: + flags |= FLAG_RETVAL_REFERENCE; + flags |= FLAG_RETURNS_NOTHING; + intarg_count++; + break; + case FFI_TYPE_VOID: + flags |= FLAG_RETURNS_NOTHING; + break; + + default: + /* Returns 32-bit integer, or similar. Nothing to do here. */ + break; + } + + /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the + first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest + goes on the stack. Structures are passed as a pointer to a copy of + the structure. Stuff on the stack needs to keep proper alignment. */ + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + switch ((*ptr)->type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + fparg_count++; + /* If this FP arg is going on the stack, it must be + 8-byte-aligned. */ + if (fparg_count > NUM_FPR_ARG_REGISTERS + && intarg_count%2 != 0) + intarg_count++; + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + + case FFI_TYPE_LONGDOUBLE: + fparg_count += 2; + /* If this FP arg is going on the stack, it must be + 8-byte-aligned. */ + if (fparg_count > NUM_FPR_ARG_REGISTERS + && intarg_count%2 != 0) + intarg_count++; + intarg_count +=2; + break; +#endif + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + /* 'long long' arguments are passed as two words, but + either both words must fit in registers or both go + on the stack. If they go on the stack, they must + be 8-byte-aligned. */ + if (intarg_count == NUM_GPR_ARG_REGISTERS-1 + || (intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0)) + intarg_count++; + intarg_count += 2; + break; + + case FFI_TYPE_STRUCT: + size_al = (*ptr)->size; + /* If the first member of the struct is a double, then align + the struct to double-word. */ + if ((*ptr)->elements[0]->type == FFI_TYPE_DOUBLE) + size_al = ALIGN((*ptr)->size, 8); +#ifdef POWERPC64 + intarg_count += (size_al + 7) / 8; +#else + intarg_count += (size_al + 3) / 4; +#endif + break; + + default: + /* Everything else is passed as a 4-byte word in a GPR, either + the object itself or a pointer to it. */ + intarg_count++; + break; + } + } + + if (fparg_count != 0) + flags |= FLAG_FP_ARGUMENTS; + + /* Space for the FPR registers, if needed. */ + if (fparg_count != 0) + bytes += NUM_FPR_ARG_REGISTERS * sizeof(double); + + /* Stack space. */ +#ifdef POWERPC64 + if ((intarg_count + fparg_count) > NUM_GPR_ARG_REGISTERS) + bytes += (intarg_count + fparg_count) * sizeof(long); +#else + if ((intarg_count + 2 * fparg_count) > NUM_GPR_ARG_REGISTERS) + bytes += (intarg_count + 2 * fparg_count) * sizeof(long); +#endif + else + bytes += NUM_GPR_ARG_REGISTERS * sizeof(long); + + /* The stack space allocated needs to be a multiple of 16 bytes. */ + bytes = (bytes + 15) & ~0xF; + + cif->flags = flags; + cif->bytes = bytes; + + return FFI_OK; +} + +extern void ffi_call_AIX(extended_cif *, long, unsigned, unsigned *, + void (*fn)(void), void (*fn2)(void)); +extern void ffi_call_DARWIN(extended_cif *, long, unsigned, unsigned *, + void (*fn)(void), void (*fn2)(void)); + +void +ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return + value address then we need to make one. */ + + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + ecif.rvalue = alloca (cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_AIX: + ffi_call_AIX(&ecif, -(long)cif->bytes, cif->flags, ecif.rvalue, fn, + FFI_FN(ffi_prep_args)); + break; + case FFI_DARWIN: + ffi_call_DARWIN(&ecif, -(long)cif->bytes, cif->flags, ecif.rvalue, fn, + FFI_FN(ffi_prep_args)); + break; + default: + FFI_ASSERT(0); + break; + } +} + +static void flush_icache(char *); +static void flush_range(char *, int); + +/* The layout of a function descriptor. A C function pointer really + points to one of these. */ + +typedef struct aix_fd_struct { + void *code_pointer; + void *toc; +} aix_fd; + +/* here I'd like to add the stack frame layout we use in darwin_closure.S + and aix_clsoure.S + + SP previous -> +---------------------------------------+ <--- child frame + | back chain to caller 4 | + +---------------------------------------+ 4 + | saved CR 4 | + +---------------------------------------+ 8 + | saved LR 4 | + +---------------------------------------+ 12 + | reserved for compilers 4 | + +---------------------------------------+ 16 + | reserved for binders 4 | + +---------------------------------------+ 20 + | saved TOC pointer 4 | + +---------------------------------------+ 24 + | always reserved 8*4=32 (previous GPRs)| + | according to the linkage convention | + | from AIX | + +---------------------------------------+ 56 + | our FPR area 13*8=104 | + | f1 | + | . | + | f13 | + +---------------------------------------+ 160 + | result area 8 | + +---------------------------------------+ 168 + | alignement to the next multiple of 16 | +SP current --> +---------------------------------------+ 176 <- parent frame + | back chain to caller 4 | + +---------------------------------------+ 180 + | saved CR 4 | + +---------------------------------------+ 184 + | saved LR 4 | + +---------------------------------------+ 188 + | reserved for compilers 4 | + +---------------------------------------+ 192 + | reserved for binders 4 | + +---------------------------------------+ 196 + | saved TOC pointer 4 | + +---------------------------------------+ 200 + | always reserved 8*4=32 we store our | + | GPRs here | + | r3 | + | . | + | r10 | + +---------------------------------------+ 232 + | overflow part | + +---------------------------------------+ xxx + | ???? | + +---------------------------------------+ xxx + +*/ +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc) +{ + unsigned int *tramp; + struct ffi_aix_trampoline_struct *tramp_aix; + aix_fd *fd; + + switch (cif->abi) + { + case FFI_DARWIN: + + FFI_ASSERT (cif->abi == FFI_DARWIN); + + tramp = (unsigned int *) &closure->tramp[0]; + tramp[0] = 0x7c0802a6; /* mflr r0 */ + tramp[1] = 0x429f000d; /* bcl- 20,4*cr7+so,0x10 */ + tramp[4] = 0x7d6802a6; /* mflr r11 */ + tramp[5] = 0x818b0000; /* lwz r12,0(r11) function address */ + tramp[6] = 0x7c0803a6; /* mtlr r0 */ + tramp[7] = 0x7d8903a6; /* mtctr r12 */ + tramp[8] = 0x816b0004; /* lwz r11,4(r11) static chain */ + tramp[9] = 0x4e800420; /* bctr */ + tramp[2] = (unsigned long) ffi_closure_ASM; /* function */ + tramp[3] = (unsigned long) codeloc; /* context */ + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* Flush the icache. Only necessary on Darwin. */ + flush_range(codeloc, FFI_TRAMPOLINE_SIZE); + + break; + + case FFI_AIX: + + tramp_aix = (struct ffi_aix_trampoline_struct *) (closure->tramp); + fd = (aix_fd *)(void *)ffi_closure_ASM; + + FFI_ASSERT (cif->abi == FFI_AIX); + + tramp_aix->code_pointer = fd->code_pointer; + tramp_aix->toc = fd->toc; + tramp_aix->static_chain = codeloc; + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + default: + + FFI_ASSERT(0); + break; + } + return FFI_OK; +} + +static void +flush_icache(char *addr) +{ +#ifndef _AIX + __asm__ volatile ( + "dcbf 0,%0\n" + "\tsync\n" + "\ticbi 0,%0\n" + "\tsync\n" + "\tisync" + : : "r"(addr) : "memory"); +#endif +} + +static void +flush_range(char * addr1, int size) +{ +#define MIN_LINE_SIZE 32 + int i; + for (i = 0; i < size; i += MIN_LINE_SIZE) + flush_icache(addr1+i); + flush_icache(addr1+size-1); +} + +typedef union +{ + float f; + double d; +} ffi_dblfl; + +int +ffi_closure_helper_DARWIN (ffi_closure *, void *, + unsigned long *, ffi_dblfl *); + +/* Basically the trampoline invokes ffi_closure_ASM, and on + entry, r11 holds the address of the closure. + After storing the registers that could possibly contain + parameters to be passed into the stack frame and setting + up space for a return value, ffi_closure_ASM invokes the + following helper function to do most of the work. */ + +int +ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue, + unsigned long *pgr, ffi_dblfl *pfr) +{ + /* rvalue is the pointer to space for return value in closure assembly + pgr is the pointer to where r3-r10 are stored in ffi_closure_ASM + pfr is the pointer to where f1-f13 are stored in ffi_closure_ASM. */ + + typedef double ldbits[2]; + + union ldu + { + ldbits lb; + long double ld; + }; + + void ** avalue; + ffi_type ** arg_types; + long i, avn; + ffi_cif * cif; + ffi_dblfl * end_pfr = pfr + NUM_FPR_ARG_REGISTERS; + unsigned size_al; + + cif = closure->cif; + avalue = alloca (cif->nargs * sizeof(void *)); + + /* Copy the caller's structure return value address so that the closure + returns the data directly to the caller. */ + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + rvalue = (void *) *pgr; + pgr++; + } + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + /* Grab the addresses of the arguments from the stack frame. */ + while (i < avn) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: +#ifdef POWERPC64 + avalue[i] = (char *) pgr + 7; +#else + avalue[i] = (char *) pgr + 3; +#endif + pgr++; + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: +#ifdef POWERPC64 + avalue[i] = (char *) pgr + 6; +#else + avalue[i] = (char *) pgr + 2; +#endif + pgr++; + break; + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: +#ifdef POWERPC64 + avalue[i] = (char *) pgr + 4; +#else + case FFI_TYPE_POINTER: + avalue[i] = pgr; +#endif + pgr++; + break; + + case FFI_TYPE_STRUCT: +#ifdef POWERPC64 + size_al = arg_types[i]->size; + if (arg_types[i]->elements[0]->type == FFI_TYPE_DOUBLE) + size_al = ALIGN (arg_types[i]->size, 8); + if (size_al < 3 && cif->abi == FFI_DARWIN) + avalue[i] = (char *) pgr + 8 - size_al; + else + avalue[i] = pgr; + pgr += (size_al + 7) / 8; +#else + /* Structures that match the basic modes (QI 1 byte, HI 2 bytes, + SI 4 bytes) are aligned as if they were those modes. */ + size_al = arg_types[i]->size; + /* If the first member of the struct is a double, then align + the struct to double-word. */ + if (arg_types[i]->elements[0]->type == FFI_TYPE_DOUBLE) + size_al = ALIGN(arg_types[i]->size, 8); + if (size_al < 3 && cif->abi == FFI_DARWIN) + avalue[i] = (char*) pgr + 4 - size_al; + else + avalue[i] = pgr; + pgr += (size_al + 3) / 4; +#endif + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: +#ifdef POWERPC64 + case FFI_TYPE_POINTER: + avalue[i] = pgr; + pgr++; + break; +#else + /* Long long ints are passed in two gpr's. */ + avalue[i] = pgr; + pgr += 2; + break; +#endif + + case FFI_TYPE_FLOAT: + /* A float value consumes a GPR. + There are 13 64bit floating point registers. */ + if (pfr < end_pfr) + { + double temp = pfr->d; + pfr->f = (float) temp; + avalue[i] = pfr; + pfr++; + } + else + { + avalue[i] = pgr; + } + pgr++; + break; + + case FFI_TYPE_DOUBLE: + /* A double value consumes two GPRs. + There are 13 64bit floating point registers. */ + if (pfr < end_pfr) + { + avalue[i] = pfr; + pfr++; + } + else + { + avalue[i] = pgr; + } +#ifdef POWERPC64 + pgr++; +#else + pgr += 2; +#endif + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + + case FFI_TYPE_LONGDOUBLE: +#ifdef POWERPC64 + if (pfr + 1 < end_pfr) + { + avalue[i] = pfr; + pfr += 2; + } + else + { + if (pfr < end_pfr) + { + *pgr = *(unsigned long *) pfr; + pfr++; + } + avalue[i] = pgr; + } + pgr += 2; +#else /* POWERPC64 */ + /* A long double value consumes four GPRs and two FPRs. + There are 13 64bit floating point registers. */ + if (pfr + 1 < end_pfr) + { + avalue[i] = pfr; + pfr += 2; + } + /* Here we have the situation where one part of the long double + is stored in fpr13 and the other part is already on the stack. + We use a union to pass the long double to avalue[i]. */ + else if (pfr + 1 == end_pfr) + { + union ldu temp_ld; + memcpy (&temp_ld.lb[0], pfr, sizeof(ldbits)); + memcpy (&temp_ld.lb[1], pgr + 2, sizeof(ldbits)); + avalue[i] = &temp_ld.ld; + pfr++; + } + else + { + avalue[i] = pgr; + } + pgr += 4; +#endif /* POWERPC64 */ + break; +#endif + default: + FFI_ASSERT(0); + } + i++; + } + + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_ASM to perform return type promotions. */ + return cif->rtype->type; +} diff --git a/js/src/ctypes/libffi/src/powerpc/ffitarget.h b/js/src/ctypes/libffi/src/powerpc/ffitarget.h new file mode 100644 index 0000000..45529ed --- /dev/null +++ b/js/src/ctypes/libffi/src/powerpc/ffitarget.h @@ -0,0 +1,132 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Copyright (C) 2007, 2008 Free Software Foundation, Inc + Target configuration macros for PowerPC. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- System specific configurations ----------------------------------- */ + +#if defined (POWERPC) && defined (__powerpc64__) /* linux64 */ +#ifndef POWERPC64 +#define POWERPC64 +#endif +#elif defined (POWERPC_DARWIN) && defined (__ppc64__) /* Darwin */ +#ifndef POWERPC64 +#define POWERPC64 +#endif +#elif defined (POWERPC_AIX) && defined (__64BIT__) /* AIX64 */ +#ifndef POWERPC64 +#define POWERPC64 +#endif +#endif + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + +#ifdef POWERPC + FFI_SYSV, + FFI_GCC_SYSV, + FFI_LINUX64, + FFI_LINUX, + FFI_LINUX_SOFT_FLOAT, +# ifdef POWERPC64 + FFI_DEFAULT_ABI = FFI_LINUX64, +# else +# if (!defined(__NO_FPRS__) && (__LDBL_MANT_DIG__ == 106)) + FFI_DEFAULT_ABI = FFI_LINUX, +# else +# ifdef __NO_FPRS__ + FFI_DEFAULT_ABI = FFI_LINUX_SOFT_FLOAT, +# else + FFI_DEFAULT_ABI = FFI_GCC_SYSV, +# endif +# endif +# endif +#endif + +#ifdef POWERPC_AIX + FFI_AIX, + FFI_DARWIN, + FFI_DEFAULT_ABI = FFI_AIX, +#endif + +#ifdef POWERPC_DARWIN + FFI_AIX, + FFI_DARWIN, + FFI_DEFAULT_ABI = FFI_DARWIN, +#endif + +#ifdef POWERPC_FREEBSD + FFI_SYSV, + FFI_GCC_SYSV, + FFI_LINUX64, + FFI_LINUX, + FFI_LINUX_SOFT_FLOAT, + FFI_DEFAULT_ABI = FFI_SYSV, +#endif + + FFI_LAST_ABI +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 + +/* For additional types like the below, take care about the order in + ppc_closures.S. They must follow after the FFI_TYPE_LAST. */ + +/* Needed for soft-float long-double-128 support. */ +#define FFI_TYPE_UINT128 (FFI_TYPE_LAST + 1) + +/* Needed for FFI_SYSV small structure returns. + We use two flag bits, (FLAG_SYSV_SMST_R3, FLAG_SYSV_SMST_R4) which are + defined in ffi.c, to determine the exact return type and its size. */ +#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 2) + +#if defined(POWERPC64) || defined(POWERPC_AIX) +#define FFI_TRAMPOLINE_SIZE 24 +#else /* POWERPC || POWERPC_AIX */ +#define FFI_TRAMPOLINE_SIZE 40 +#endif + +#ifndef LIBFFI_ASM +#if defined(POWERPC_DARWIN) || defined(POWERPC_AIX) +struct ffi_aix_trampoline_struct { + void * code_pointer; /* Pointer to ffi_closure_ASM */ + void * toc; /* TOC */ + void * static_chain; /* Pointer to closure */ +}; +#endif +#endif + +#endif diff --git a/js/src/ctypes/libffi/src/powerpc/linux64.S b/js/src/ctypes/libffi/src/powerpc/linux64.S new file mode 100644 index 0000000..57b56cb --- /dev/null +++ b/js/src/ctypes/libffi/src/powerpc/linux64.S @@ -0,0 +1,187 @@ +/* ----------------------------------------------------------------------- + sysv.h - Copyright (c) 2003 Jakub Jelinek + Copyright (c) 2008 Red Hat, Inc. + + PowerPC64 Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include + +#ifdef __powerpc64__ + .hidden ffi_call_LINUX64, .ffi_call_LINUX64 + .globl ffi_call_LINUX64, .ffi_call_LINUX64 + .section ".opd","aw" + .align 3 +ffi_call_LINUX64: + .quad .ffi_call_LINUX64,.TOC.@tocbase,0 + .size ffi_call_LINUX64,24 + .type .ffi_call_LINUX64,@function + .text +.ffi_call_LINUX64: +.LFB1: + mflr %r0 + std %r28, -32(%r1) + std %r29, -24(%r1) + std %r30, -16(%r1) + std %r31, -8(%r1) + std %r0, 16(%r1) + + mr %r28, %r1 /* our AP. */ +.LCFI0: + stdux %r1, %r1, %r4 + mr %r31, %r5 /* flags, */ + mr %r30, %r6 /* rvalue, */ + mr %r29, %r7 /* function address. */ + std %r2, 40(%r1) + + /* Call ffi_prep_args64. */ + mr %r4, %r1 + bl .ffi_prep_args64 + + ld %r0, 0(%r29) + ld %r2, 8(%r29) + ld %r11, 16(%r29) + + /* Now do the call. */ + /* Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40, %r31 + + /* Get the address to call into CTR. */ + mtctr %r0 + /* Load all those argument registers. */ + ld %r3, -32-(8*8)(%r28) + ld %r4, -32-(7*8)(%r28) + ld %r5, -32-(6*8)(%r28) + ld %r6, -32-(5*8)(%r28) + bf- 5, 1f + ld %r7, -32-(4*8)(%r28) + ld %r8, -32-(3*8)(%r28) + ld %r9, -32-(2*8)(%r28) + ld %r10, -32-(1*8)(%r28) +1: + + /* Load all the FP registers. */ + bf- 6, 2f + lfd %f1, -32-(21*8)(%r28) + lfd %f2, -32-(20*8)(%r28) + lfd %f3, -32-(19*8)(%r28) + lfd %f4, -32-(18*8)(%r28) + lfd %f5, -32-(17*8)(%r28) + lfd %f6, -32-(16*8)(%r28) + lfd %f7, -32-(15*8)(%r28) + lfd %f8, -32-(14*8)(%r28) + lfd %f9, -32-(13*8)(%r28) + lfd %f10, -32-(12*8)(%r28) + lfd %f11, -32-(11*8)(%r28) + lfd %f12, -32-(10*8)(%r28) + lfd %f13, -32-(9*8)(%r28) +2: + + /* Make the call. */ + bctrl + + /* This must follow the call immediately, the unwinder + uses this to find out if r2 has been saved or not. */ + ld %r2, 40(%r1) + + /* Now, deal with the return value. */ + mtcrf 0x01, %r31 + bt- 30, .Ldone_return_value + bt- 29, .Lfp_return_value + std %r3, 0(%r30) + /* Fall through... */ + +.Ldone_return_value: + /* Restore the registers we used and return. */ + mr %r1, %r28 + ld %r0, 16(%r28) + ld %r28, -32(%r1) + mtlr %r0 + ld %r29, -24(%r1) + ld %r30, -16(%r1) + ld %r31, -8(%r1) + blr + +.Lfp_return_value: + bf 28, .Lfloat_return_value + stfd %f1, 0(%r30) + mtcrf 0x02, %r31 /* cr6 */ + bf 27, .Ldone_return_value + stfd %f2, 8(%r30) + b .Ldone_return_value +.Lfloat_return_value: + stfs %f1, 0(%r30) + b .Ldone_return_value +.LFE1: + .long 0 + .byte 0,12,0,1,128,4,0,0 + .size .ffi_call_LINUX64,.-.ffi_call_LINUX64 + + .section .eh_frame,EH_FRAME_FLAGS,@progbits +.Lframe1: + .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry +.LSCIE1: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version + .ascii "zR\0" # CIE Augmentation + .uleb128 0x1 # CIE Code Alignment Factor + .sleb128 -8 # CIE Data Alignment Factor + .byte 0x41 # CIE RA Column + .uleb128 0x1 # Augmentation size + .byte 0x14 # FDE Encoding (pcrel udata8) + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1 + .uleb128 0x0 + .align 3 +.LECIE1: +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 # FDE Length +.LASFDE1: + .4byte .LASFDE1-.Lframe1 # FDE CIE offset + .8byte .LFB1-. # FDE initial location + .8byte .LFE1-.LFB1 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x2 # DW_CFA_advance_loc1 + .byte .LCFI0-.LFB1 + .byte 0xd # DW_CFA_def_cfa_register + .uleb128 0x1c + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x41 + .sleb128 -2 + .byte 0x9f # DW_CFA_offset, column 0x1f + .uleb128 0x1 + .byte 0x9e # DW_CFA_offset, column 0x1e + .uleb128 0x2 + .byte 0x9d # DW_CFA_offset, column 0x1d + .uleb128 0x3 + .byte 0x9c # DW_CFA_offset, column 0x1c + .uleb128 0x4 + .align 3 +.LEFDE1: +#endif + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/js/src/ctypes/libffi/src/powerpc/linux64_closure.S b/js/src/ctypes/libffi/src/powerpc/linux64_closure.S new file mode 100644 index 0000000..f7aa2c9 --- /dev/null +++ b/js/src/ctypes/libffi/src/powerpc/linux64_closure.S @@ -0,0 +1,236 @@ +/* ----------------------------------------------------------------------- + sysv.h - Copyright (c) 2003 Jakub Jelinek + Copyright (c) 2008 Red Hat, Inc. + + PowerPC64 Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ +#define LIBFFI_ASM +#include +#include + + .file "linux64_closure.S" + +#ifdef __powerpc64__ + FFI_HIDDEN (ffi_closure_LINUX64) + FFI_HIDDEN (.ffi_closure_LINUX64) + .globl ffi_closure_LINUX64, .ffi_closure_LINUX64 + .section ".opd","aw" + .align 3 +ffi_closure_LINUX64: + .quad .ffi_closure_LINUX64,.TOC.@tocbase,0 + .size ffi_closure_LINUX64,24 + .type .ffi_closure_LINUX64,@function + .text +.ffi_closure_LINUX64: +.LFB1: + # save general regs into parm save area + std %r3, 48(%r1) + std %r4, 56(%r1) + std %r5, 64(%r1) + std %r6, 72(%r1) + mflr %r0 + + std %r7, 80(%r1) + std %r8, 88(%r1) + std %r9, 96(%r1) + std %r10, 104(%r1) + std %r0, 16(%r1) + + # mandatory 48 bytes special reg save area + 64 bytes parm save area + # + 16 bytes retval area + 13*8 bytes fpr save area + round to 16 + stdu %r1, -240(%r1) +.LCFI0: + + # next save fpr 1 to fpr 13 + stfd %f1, 128+(0*8)(%r1) + stfd %f2, 128+(1*8)(%r1) + stfd %f3, 128+(2*8)(%r1) + stfd %f4, 128+(3*8)(%r1) + stfd %f5, 128+(4*8)(%r1) + stfd %f6, 128+(5*8)(%r1) + stfd %f7, 128+(6*8)(%r1) + stfd %f8, 128+(7*8)(%r1) + stfd %f9, 128+(8*8)(%r1) + stfd %f10, 128+(9*8)(%r1) + stfd %f11, 128+(10*8)(%r1) + stfd %f12, 128+(11*8)(%r1) + stfd %f13, 128+(12*8)(%r1) + + # set up registers for the routine that actually does the work + # get the context pointer from the trampoline + mr %r3, %r11 + + # now load up the pointer to the result storage + addi %r4, %r1, 112 + + # now load up the pointer to the parameter save area + # in the previous frame + addi %r5, %r1, 240 + 48 + + # now load up the pointer to the saved fpr registers */ + addi %r6, %r1, 128 + + # make the call + bl .ffi_closure_helper_LINUX64 +.Lret: + + # now r3 contains the return type + # so use it to look up in a table + # so we know how to deal with each type + + # look up the proper starting point in table + # by using return type as offset + mflr %r4 # move address of .Lret to r4 + sldi %r3, %r3, 4 # now multiply return type by 16 + addi %r4, %r4, .Lret_type0 - .Lret + ld %r0, 240+16(%r1) + add %r3, %r3, %r4 # add contents of table to table address + mtctr %r3 + bctr # jump to it + +# Each of the ret_typeX code fragments has to be exactly 16 bytes long +# (4 instructions). For cache effectiveness we align to a 16 byte boundary +# first. + .align 4 + +.Lret_type0: +# case FFI_TYPE_VOID + mtlr %r0 + addi %r1, %r1, 240 + blr + nop +# case FFI_TYPE_INT + lwa %r3, 112+4(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_FLOAT + lfs %f1, 112+0(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_DOUBLE + lfd %f1, 112+0(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_LONGDOUBLE + lfd %f1, 112+0(%r1) + mtlr %r0 + lfd %f2, 112+8(%r1) + b .Lfinish +# case FFI_TYPE_UINT8 + lbz %r3, 112+7(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_SINT8 + lbz %r3, 112+7(%r1) + extsb %r3,%r3 + mtlr %r0 + b .Lfinish +# case FFI_TYPE_UINT16 + lhz %r3, 112+6(%r1) + mtlr %r0 +.Lfinish: + addi %r1, %r1, 240 + blr +# case FFI_TYPE_SINT16 + lha %r3, 112+6(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_UINT32 + lwz %r3, 112+4(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_SINT32 + lwa %r3, 112+4(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_UINT64 + ld %r3, 112+0(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_SINT64 + ld %r3, 112+0(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_STRUCT + mtlr %r0 + addi %r1, %r1, 240 + blr + nop +# case FFI_TYPE_POINTER + ld %r3, 112+0(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# esac +.LFE1: + .long 0 + .byte 0,12,0,1,128,0,0,0 + .size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64 + + .section .eh_frame,EH_FRAME_FLAGS,@progbits +.Lframe1: + .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry +.LSCIE1: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version + .ascii "zR\0" # CIE Augmentation + .uleb128 0x1 # CIE Code Alignment Factor + .sleb128 -8 # CIE Data Alignment Factor + .byte 0x41 # CIE RA Column + .uleb128 0x1 # Augmentation size + .byte 0x14 # FDE Encoding (pcrel udata8) + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1 + .uleb128 0x0 + .align 3 +.LECIE1: +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 # FDE Length +.LASFDE1: + .4byte .LASFDE1-.Lframe1 # FDE CIE offset + .8byte .LFB1-. # FDE initial location + .8byte .LFE1-.LFB1 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x2 # DW_CFA_advance_loc1 + .byte .LCFI0-.LFB1 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 240 + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x41 + .sleb128 -2 + .align 3 +.LEFDE1: +#endif + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/js/src/ctypes/libffi/src/powerpc/ppc_closure.S b/js/src/ctypes/libffi/src/powerpc/ppc_closure.S new file mode 100644 index 0000000..56f7d1a --- /dev/null +++ b/js/src/ctypes/libffi/src/powerpc/ppc_closure.S @@ -0,0 +1,327 @@ +/* ----------------------------------------------------------------------- + sysv.h - Copyright (c) 2003 Jakub Jelinek + Copyright (c) 2008 Red Hat, Inc. + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ +#define LIBFFI_ASM +#include +#include +#include + + .file "ppc_closure.S" + +#ifndef __powerpc64__ + +ENTRY(ffi_closure_SYSV) +.LFB1: + stwu %r1,-144(%r1) +.LCFI0: + mflr %r0 +.LCFI1: + stw %r0,148(%r1) + +# we want to build up an areas for the parameters passed +# in registers (both floating point and integer) + + # so first save gpr 3 to gpr 10 (aligned to 4) + stw %r3, 16(%r1) + stw %r4, 20(%r1) + stw %r5, 24(%r1) + stw %r6, 28(%r1) + stw %r7, 32(%r1) + stw %r8, 36(%r1) + stw %r9, 40(%r1) + stw %r10,44(%r1) + +#ifndef __NO_FPRS__ + # next save fpr 1 to fpr 8 (aligned to 8) + stfd %f1, 48(%r1) + stfd %f2, 56(%r1) + stfd %f3, 64(%r1) + stfd %f4, 72(%r1) + stfd %f5, 80(%r1) + stfd %f6, 88(%r1) + stfd %f7, 96(%r1) + stfd %f8, 104(%r1) +#endif + + # set up registers for the routine that actually does the work + # get the context pointer from the trampoline + mr %r3,%r11 + + # now load up the pointer to the result storage + addi %r4,%r1,112 + + # now load up the pointer to the saved gpr registers + addi %r5,%r1,16 + + # now load up the pointer to the saved fpr registers */ + addi %r6,%r1,48 + + # now load up the pointer to the outgoing parameter + # stack in the previous frame + # i.e. the previous frame pointer + 8 + addi %r7,%r1,152 + + # make the call + bl ffi_closure_helper_SYSV@local +.Lret: + # now r3 contains the return type + # so use it to look up in a table + # so we know how to deal with each type + + # look up the proper starting point in table + # by using return type as offset + + mflr %r4 # move address of .Lret to r4 + slwi %r3,%r3,4 # now multiply return type by 16 + addi %r4, %r4, .Lret_type0 - .Lret + lwz %r0,148(%r1) + add %r3,%r3,%r4 # add contents of table to table address + mtctr %r3 + bctr # jump to it +.LFE1: + +# Each of the ret_typeX code fragments has to be exactly 16 bytes long +# (4 instructions). For cache effectiveness we align to a 16 byte boundary +# first. + .align 4 +# case FFI_TYPE_VOID +.Lret_type0: + mtlr %r0 + addi %r1,%r1,144 + blr + nop + +# case FFI_TYPE_INT + lwz %r3,112+0(%r1) + mtlr %r0 +.Lfinish: + addi %r1,%r1,144 + blr + +# case FFI_TYPE_FLOAT + lfs %f1,112+0(%r1) + mtlr %r0 + addi %r1,%r1,144 + blr + +# case FFI_TYPE_DOUBLE + lfd %f1,112+0(%r1) + mtlr %r0 + addi %r1,%r1,144 + blr + +# case FFI_TYPE_LONGDOUBLE + lfd %f1,112+0(%r1) + lfd %f2,112+8(%r1) + mtlr %r0 + b .Lfinish + +# case FFI_TYPE_UINT8 + lbz %r3,112+3(%r1) + mtlr %r0 + addi %r1,%r1,144 + blr + +# case FFI_TYPE_SINT8 + lbz %r3,112+3(%r1) + extsb %r3,%r3 + mtlr %r0 + b .Lfinish + +# case FFI_TYPE_UINT16 + lhz %r3,112+2(%r1) + mtlr %r0 + addi %r1,%r1,144 + blr + +# case FFI_TYPE_SINT16 + lha %r3,112+2(%r1) + mtlr %r0 + addi %r1,%r1,144 + blr + +# case FFI_TYPE_UINT32 + lwz %r3,112+0(%r1) + mtlr %r0 + addi %r1,%r1,144 + blr + +# case FFI_TYPE_SINT32 + lwz %r3,112+0(%r1) + mtlr %r0 + addi %r1,%r1,144 + blr + +# case FFI_TYPE_UINT64 + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) + mtlr %r0 + b .Lfinish + +# case FFI_TYPE_SINT64 + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) + mtlr %r0 + b .Lfinish + +# case FFI_TYPE_STRUCT + mtlr %r0 + addi %r1,%r1,144 + blr + nop + +# case FFI_TYPE_POINTER + lwz %r3,112+0(%r1) + mtlr %r0 + addi %r1,%r1,144 + blr + +# case FFI_TYPE_UINT128 + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) + lwz %r5,112+8(%r1) + bl .Luint128 + +# The return types below are only used when the ABI type is FFI_SYSV. +# case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct. + lbz %r3,112+0(%r1) + mtlr %r0 + addi %r1,%r1,144 + blr + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct. + lhz %r3,112+0(%r1) + mtlr %r0 + addi %r1,%r1,144 + blr + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct. + lwz %r3,112+0(%r1) + srwi %r3,%r3,8 + mtlr %r0 + b .Lfinish + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct. + lwz %r3,112+0(%r1) + mtlr %r0 + addi %r1,%r1,144 + blr + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct. + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) + li %r5,24 + b .Lstruct567 + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct. + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) + li %r5,16 + b .Lstruct567 + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct. + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) + li %r5,8 + b .Lstruct567 + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct. + lwz %r3,112+0(%r1) + lwz %r4,112+4(%r1) + mtlr %r0 + b .Lfinish + +.Lstruct567: + subfic %r6,%r5,32 + srw %r4,%r4,%r5 + slw %r6,%r3,%r6 + srw %r3,%r3,%r5 + or %r4,%r6,%r4 + mtlr %r0 + addi %r1,%r1,144 + blr + +.Luint128: + lwz %r6,112+12(%r1) + mtlr %r0 + addi %r1,%r1,144 + blr + +END(ffi_closure_SYSV) + + .section ".eh_frame",EH_FRAME_FLAGS,@progbits +.Lframe1: + .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry +.LSCIE1: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version +#if defined _RELOCATABLE || defined __PIC__ + .ascii "zR\0" # CIE Augmentation +#else + .ascii "\0" # CIE Augmentation +#endif + .uleb128 0x1 # CIE Code Alignment Factor + .sleb128 -4 # CIE Data Alignment Factor + .byte 0x41 # CIE RA Column +#if defined _RELOCATABLE || defined __PIC__ + .uleb128 0x1 # Augmentation size + .byte 0x1b # FDE Encoding (pcrel sdata4) +#endif + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1 + .uleb128 0x0 + .align 2 +.LECIE1: +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 # FDE Length +.LASFDE1: + .4byte .LASFDE1-.Lframe1 # FDE CIE offset +#if defined _RELOCATABLE || defined __PIC__ + .4byte .LFB1-. # FDE initial location +#else + .4byte .LFB1 # FDE initial location +#endif + .4byte .LFE1-.LFB1 # FDE address range +#if defined _RELOCATABLE || defined __PIC__ + .uleb128 0x0 # Augmentation size +#endif + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI0-.LFB1 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 144 + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI1-.LCFI0 + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x41 + .sleb128 -1 + .align 2 +.LEFDE1: + +#endif + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/js/src/ctypes/libffi/src/powerpc/sysv.S b/js/src/ctypes/libffi/src/powerpc/sysv.S new file mode 100644 index 0000000..96ea22b --- /dev/null +++ b/js/src/ctypes/libffi/src/powerpc/sysv.S @@ -0,0 +1,219 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 1998 Geoffrey Keating + Copyright (C) 2007 Free Software Foundation, Inc + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include +#include + +#ifndef __powerpc64__ + .globl ffi_prep_args_SYSV +ENTRY(ffi_call_SYSV) +.LFB1: + /* Save the old stack pointer as AP. */ + mr %r8,%r1 + +.LCFI0: + /* Allocate the stack space we need. */ + stwux %r1,%r1,%r4 + /* Save registers we use. */ + mflr %r9 + stw %r28,-16(%r8) +.LCFI1: + stw %r29,-12(%r8) +.LCFI2: + stw %r30, -8(%r8) +.LCFI3: + stw %r31, -4(%r8) +.LCFI4: + stw %r9, 4(%r8) +.LCFI5: + + /* Save arguments over call... */ + mr %r31,%r5 /* flags, */ + mr %r30,%r6 /* rvalue, */ + mr %r29,%r7 /* function address, */ + mr %r28,%r8 /* our AP. */ +.LCFI6: + + /* Call ffi_prep_args_SYSV. */ + mr %r4,%r1 + bl ffi_prep_args_SYSV@local + + /* Now do the call. */ + /* Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40,%r31 + /* Get the address to call into CTR. */ + mtctr %r29 + /* Load all those argument registers. */ + lwz %r3,-16-(8*4)(%r28) + lwz %r4,-16-(7*4)(%r28) + lwz %r5,-16-(6*4)(%r28) + lwz %r6,-16-(5*4)(%r28) + bf- 5,1f + nop + lwz %r7,-16-(4*4)(%r28) + lwz %r8,-16-(3*4)(%r28) + lwz %r9,-16-(2*4)(%r28) + lwz %r10,-16-(1*4)(%r28) + nop +1: + + /* Load all the FP registers. */ + bf- 6,2f + lfd %f1,-16-(8*4)-(8*8)(%r28) + lfd %f2,-16-(8*4)-(7*8)(%r28) + lfd %f3,-16-(8*4)-(6*8)(%r28) + lfd %f4,-16-(8*4)-(5*8)(%r28) + nop + lfd %f5,-16-(8*4)-(4*8)(%r28) + lfd %f6,-16-(8*4)-(3*8)(%r28) + lfd %f7,-16-(8*4)-(2*8)(%r28) + lfd %f8,-16-(8*4)-(1*8)(%r28) +2: + + /* Make the call. */ + bctrl + + /* Now, deal with the return value. */ + mtcrf 0x01,%r31 /* cr7 */ + bt- 31,L(small_struct_return_value) + bt- 30,L(done_return_value) + bt- 29,L(fp_return_value) + stw %r3,0(%r30) + bf+ 28,L(done_return_value) + stw %r4,4(%r30) + mtcrf 0x02,%r31 /* cr6 */ + bf 27,L(done_return_value) + stw %r5,8(%r30) + stw %r6,12(%r30) + /* Fall through... */ + +L(done_return_value): + /* Restore the registers we used and return. */ + lwz %r9, 4(%r28) + lwz %r31, -4(%r28) + mtlr %r9 + lwz %r30, -8(%r28) + lwz %r29,-12(%r28) + lwz %r28,-16(%r28) + lwz %r1,0(%r1) + blr + +L(fp_return_value): + bf 28,L(float_return_value) + stfd %f1,0(%r30) + mtcrf 0x02,%r31 /* cr6 */ + bf 27,L(done_return_value) + stfd %f2,8(%r30) + b L(done_return_value) +L(float_return_value): + stfs %f1,0(%r30) + b L(done_return_value) + +L(small_struct_return_value): + extrwi %r6,%r31,2,19 /* number of bytes padding = shift/8 */ + mtcrf 0x02,%r31 /* copy flags to cr[24:27] (cr6) */ + extrwi %r5,%r31,5,19 /* r5 <- number of bits of padding */ + subfic %r6,%r6,4 /* r6 <- number of useful bytes in r3 */ + bf- 25,L(done_return_value) /* struct in r3 ? if not, done. */ +/* smst_one_register: */ + slw %r3,%r3,%r5 /* Left-justify value in r3 */ + mtxer %r6 /* move byte count to XER ... */ + stswx %r3,0,%r30 /* ... and store that many bytes */ + bf+ 26,L(done_return_value) /* struct in r3:r4 ? */ + add %r6,%r6,%r30 /* adjust pointer */ + stswi %r4,%r6,4 /* store last four bytes */ + b L(done_return_value) + +.LFE1: +END(ffi_call_SYSV) + + .section ".eh_frame",EH_FRAME_FLAGS,@progbits +.Lframe1: + .4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */ +.LSCIE1: + .4byte 0x0 /* CIE Identifier Tag */ + .byte 0x1 /* CIE Version */ +#if defined _RELOCATABLE || defined __PIC__ + .ascii "zR\0" /* CIE Augmentation */ +#else + .ascii "\0" /* CIE Augmentation */ +#endif + .uleb128 0x1 /* CIE Code Alignment Factor */ + .sleb128 -4 /* CIE Data Alignment Factor */ + .byte 0x41 /* CIE RA Column */ +#if defined _RELOCATABLE || defined __PIC__ + .uleb128 0x1 /* Augmentation size */ + .byte 0x1b /* FDE Encoding (pcrel sdata4) */ +#endif + .byte 0xc /* DW_CFA_def_cfa */ + .uleb128 0x1 + .uleb128 0x0 + .align 2 +.LECIE1: +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 /* FDE Length */ +.LASFDE1: + .4byte .LASFDE1-.Lframe1 /* FDE CIE offset */ +#if defined _RELOCATABLE || defined __PIC__ + .4byte .LFB1-. /* FDE initial location */ +#else + .4byte .LFB1 /* FDE initial location */ +#endif + .4byte .LFE1-.LFB1 /* FDE address range */ +#if defined _RELOCATABLE || defined __PIC__ + .uleb128 0x0 /* Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI0-.LFB1 + .byte 0xd /* DW_CFA_def_cfa_register */ + .uleb128 0x08 + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI5-.LCFI0 + .byte 0x11 /* DW_CFA_offset_extended_sf */ + .uleb128 0x41 + .sleb128 -1 + .byte 0x9f /* DW_CFA_offset, column 0x1f */ + .uleb128 0x1 + .byte 0x9e /* DW_CFA_offset, column 0x1e */ + .uleb128 0x2 + .byte 0x9d /* DW_CFA_offset, column 0x1d */ + .uleb128 0x3 + .byte 0x9c /* DW_CFA_offset, column 0x1c */ + .uleb128 0x4 + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI6-.LCFI5 + .byte 0xd /* DW_CFA_def_cfa_register */ + .uleb128 0x1c + .align 2 +.LEFDE1: +#endif + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/js/src/ctypes/libffi/src/prep_cif.c b/js/src/ctypes/libffi/src/prep_cif.c new file mode 100644 index 0000000..761abdc --- /dev/null +++ b/js/src/ctypes/libffi/src/prep_cif.c @@ -0,0 +1,171 @@ +/* ----------------------------------------------------------------------- + prep_cif.c - Copyright (c) 1996, 1998, 2007 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include +#include + +/* Round up to FFI_SIZEOF_ARG. */ + +#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) + +/* Perform machine independent initialization of aggregate type + specifications. */ + +static ffi_status initialize_aggregate(ffi_type *arg) +{ + ffi_type **ptr; + + FFI_ASSERT(arg != NULL); + + FFI_ASSERT(arg->elements != NULL); + FFI_ASSERT(arg->size == 0); + FFI_ASSERT(arg->alignment == 0); + + ptr = &(arg->elements[0]); + + while ((*ptr) != NULL) + { + if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + /* Perform a sanity check on the argument type */ + FFI_ASSERT_VALID_TYPE(*ptr); + + arg->size = ALIGN(arg->size, (*ptr)->alignment); + arg->size += (*ptr)->size; + + arg->alignment = (arg->alignment > (*ptr)->alignment) ? + arg->alignment : (*ptr)->alignment; + + ptr++; + } + + /* Structure size includes tail padding. This is important for + structures that fit in one register on ABIs like the PowerPC64 + Linux ABI that right justify small structs in a register. + It's also needed for nested structure layout, for example + struct A { long a; char b; }; struct B { struct A x; char y; }; + should find y at an offset of 2*sizeof(long) and result in a + total size of 3*sizeof(long). */ + arg->size = ALIGN (arg->size, arg->alignment); + + if (arg->size == 0) + return FFI_BAD_TYPEDEF; + else + return FFI_OK; +} + +#ifndef __CRIS__ +/* The CRIS ABI specifies structure elements to have byte + alignment only, so it completely overrides this functions, + which assumes "natural" alignment and padding. */ + +/* Perform machine independent ffi_cif preparation, then call + machine dependent routine. */ + +ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs, + ffi_type *rtype, ffi_type **atypes) +{ + unsigned bytes = 0; + unsigned int i; + ffi_type **ptr; + + FFI_ASSERT(cif != NULL); + FFI_ASSERT(abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI); + + cif->abi = abi; + cif->arg_types = atypes; + cif->nargs = nargs; + cif->rtype = rtype; + + cif->flags = 0; + + /* Initialize the return type if necessary */ + if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + /* Perform a sanity check on the return type */ + FFI_ASSERT_VALID_TYPE(cif->rtype); + + /* x86, x86-64 and s390 stack space allocation is handled in prep_machdep. */ +#if !defined M68K && !defined X86_ANY && !defined S390 && !defined PA + /* Make space for the return structure pointer */ + if (cif->rtype->type == FFI_TYPE_STRUCT +#ifdef SPARC + && (cif->abi != FFI_V9 || cif->rtype->size > 32) +#endif + ) + bytes = STACK_ARG_SIZE(sizeof(void*)); +#endif + + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + + /* Initialize any uninitialized aggregate type definitions */ + if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + /* Perform a sanity check on the argument type, do this + check after the initialization. */ + FFI_ASSERT_VALID_TYPE(*ptr); + +#if !defined X86_ANY && !defined S390 && !defined PA +#ifdef SPARC + if (((*ptr)->type == FFI_TYPE_STRUCT + && ((*ptr)->size > 16 || cif->abi != FFI_V9)) + || ((*ptr)->type == FFI_TYPE_LONGDOUBLE + && cif->abi != FFI_V9)) + bytes += sizeof(void*); + else +#endif + { + /* Add any padding if necessary */ + if (((*ptr)->alignment - 1) & bytes) + bytes = ALIGN(bytes, (*ptr)->alignment); + + bytes += STACK_ARG_SIZE((*ptr)->size); + } +#endif + } + + cif->bytes = bytes; + + /* Perform machine dependent cif processing */ + return ffi_prep_cif_machdep(cif); +} +#endif /* not __CRIS__ */ + +#if FFI_CLOSURES + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data) +{ + return ffi_prep_closure_loc (closure, cif, fun, user_data, closure); +} + +#endif diff --git a/js/src/ctypes/libffi/src/raw_api.c b/js/src/ctypes/libffi/src/raw_api.c new file mode 100644 index 0000000..ce21372 --- /dev/null +++ b/js/src/ctypes/libffi/src/raw_api.c @@ -0,0 +1,254 @@ +/* ----------------------------------------------------------------------- + raw_api.c - Copyright (c) 1999, 2008 Red Hat, Inc. + + Author: Kresten Krab Thorup + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +/* This file defines generic functions for use with the raw api. */ + +#include +#include + +#if !FFI_NO_RAW_API + +size_t +ffi_raw_size (ffi_cif *cif) +{ + size_t result = 0; + int i; + + ffi_type **at = cif->arg_types; + + for (i = cif->nargs-1; i >= 0; i--, at++) + { +#if !FFI_NO_STRUCTS + if ((*at)->type == FFI_TYPE_STRUCT) + result += ALIGN (sizeof (void*), FFI_SIZEOF_ARG); + else +#endif + result += ALIGN ((*at)->size, FFI_SIZEOF_ARG); + } + + return result; +} + + +void +ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args) +{ + unsigned i; + ffi_type **tp = cif->arg_types; + +#if WORDS_BIGENDIAN + + for (i = 0; i < cif->nargs; i++, tp++, args++) + { + switch ((*tp)->type) + { + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + *args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 1); + break; + + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + *args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 2); + break; + +#if FFI_SIZEOF_ARG >= 4 + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + *args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 4); + break; +#endif + +#if !FFI_NO_STRUCTS + case FFI_TYPE_STRUCT: + *args = (raw++)->ptr; + break; +#endif + + case FFI_TYPE_POINTER: + *args = (void*) &(raw++)->ptr; + break; + + default: + *args = raw; + raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + } + } + +#else /* WORDS_BIGENDIAN */ + +#if !PDP + + /* then assume little endian */ + for (i = 0; i < cif->nargs; i++, tp++, args++) + { +#if !FFI_NO_STRUCTS + if ((*tp)->type == FFI_TYPE_STRUCT) + { + *args = (raw++)->ptr; + } + else +#endif + { + *args = (void*) raw; + raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*); + } + } + +#else +#error "pdp endian not supported" +#endif /* ! PDP */ + +#endif /* WORDS_BIGENDIAN */ +} + +void +ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw) +{ + unsigned i; + ffi_type **tp = cif->arg_types; + + for (i = 0; i < cif->nargs; i++, tp++, args++) + { + switch ((*tp)->type) + { + case FFI_TYPE_UINT8: + (raw++)->uint = *(UINT8*) (*args); + break; + + case FFI_TYPE_SINT8: + (raw++)->sint = *(SINT8*) (*args); + break; + + case FFI_TYPE_UINT16: + (raw++)->uint = *(UINT16*) (*args); + break; + + case FFI_TYPE_SINT16: + (raw++)->sint = *(SINT16*) (*args); + break; + +#if FFI_SIZEOF_ARG >= 4 + case FFI_TYPE_UINT32: + (raw++)->uint = *(UINT32*) (*args); + break; + + case FFI_TYPE_SINT32: + (raw++)->sint = *(SINT32*) (*args); + break; +#endif + +#if !FFI_NO_STRUCTS + case FFI_TYPE_STRUCT: + (raw++)->ptr = *args; + break; +#endif + + case FFI_TYPE_POINTER: + (raw++)->ptr = **(void***) args; + break; + + default: + memcpy ((void*) raw->data, (void*)*args, (*tp)->size); + raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + } + } +} + +#if !FFI_NATIVE_RAW_API + + +/* This is a generic definition of ffi_raw_call, to be used if the + * native system does not provide a machine-specific implementation. + * Having this, allows code to be written for the raw API, without + * the need for system-specific code to handle input in that format; + * these following couple of functions will handle the translation forth + * and back automatically. */ + +void ffi_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *raw) +{ + void **avalue = (void**) alloca (cif->nargs * sizeof (void*)); + ffi_raw_to_ptrarray (cif, raw, avalue); + ffi_call (cif, fn, rvalue, avalue); +} + +#if FFI_CLOSURES /* base system provides closures */ + +static void +ffi_translate_args (ffi_cif *cif, void *rvalue, + void **avalue, void *user_data) +{ + ffi_raw *raw = (ffi_raw*)alloca (ffi_raw_size (cif)); + ffi_raw_closure *cl = (ffi_raw_closure*)user_data; + + ffi_ptrarray_to_raw (cif, avalue, raw); + (*cl->fun) (cif, rvalue, raw, cl->user_data); +} + +ffi_status +ffi_prep_raw_closure_loc (ffi_raw_closure* cl, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data, + void *codeloc) +{ + ffi_status status; + + status = ffi_prep_closure_loc ((ffi_closure*) cl, + cif, + &ffi_translate_args, + codeloc, + codeloc); + if (status == FFI_OK) + { + cl->fun = fun; + cl->user_data = user_data; + } + + return status; +} + +#endif /* FFI_CLOSURES */ +#endif /* !FFI_NATIVE_RAW_API */ + +#if FFI_CLOSURES + +/* Again, here is the generic version of ffi_prep_raw_closure, which + * will install an intermediate "hub" for translation of arguments from + * the pointer-array format, to the raw format */ + +ffi_status +ffi_prep_raw_closure (ffi_raw_closure* cl, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data) +{ + return ffi_prep_raw_closure_loc (cl, cif, fun, user_data, cl); +} + +#endif /* FFI_CLOSURES */ + +#endif /* !FFI_NO_RAW_API */ diff --git a/js/src/ctypes/libffi/src/s390/ffi.c b/js/src/ctypes/libffi/src/s390/ffi.c new file mode 100644 index 0000000..ca2675b --- /dev/null +++ b/js/src/ctypes/libffi/src/s390/ffi.c @@ -0,0 +1,780 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2000, 2007 Software AG + Copyright (c) 2008 Red Hat, Inc + + S390 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ +/*====================================================================*/ +/* Includes */ +/* -------- */ +/*====================================================================*/ + +#include +#include + +#include +#include + +/*====================== End of Includes =============================*/ + +/*====================================================================*/ +/* Defines */ +/* ------- */ +/*====================================================================*/ + +/* Maximum number of GPRs available for argument passing. */ +#define MAX_GPRARGS 5 + +/* Maximum number of FPRs available for argument passing. */ +#ifdef __s390x__ +#define MAX_FPRARGS 4 +#else +#define MAX_FPRARGS 2 +#endif + +/* Round to multiple of 16. */ +#define ROUND_SIZE(size) (((size) + 15) & ~15) + +/* If these values change, sysv.S must be adapted! */ +#define FFI390_RET_VOID 0 +#define FFI390_RET_STRUCT 1 +#define FFI390_RET_FLOAT 2 +#define FFI390_RET_DOUBLE 3 +#define FFI390_RET_INT32 4 +#define FFI390_RET_INT64 5 + +/*===================== End of Defines ===============================*/ + +/*====================================================================*/ +/* Prototypes */ +/* ---------- */ +/*====================================================================*/ + +static void ffi_prep_args (unsigned char *, extended_cif *); +void +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) +__attribute__ ((visibility ("hidden"))) +#endif +ffi_closure_helper_SYSV (ffi_closure *, unsigned long *, + unsigned long long *, unsigned long *); + +/*====================== End of Prototypes ===========================*/ + +/*====================================================================*/ +/* Externals */ +/* --------- */ +/*====================================================================*/ + +extern void ffi_call_SYSV(unsigned, + extended_cif *, + void (*)(unsigned char *, extended_cif *), + unsigned, + void *, + void (*fn)(void)); + +extern void ffi_closure_SYSV(void); + +/*====================== End of Externals ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_check_struct_type. */ +/* */ +/* Function - Determine if a structure can be passed within a */ +/* general purpose or floating point register. */ +/* */ +/*====================================================================*/ + +static int +ffi_check_struct_type (ffi_type *arg) +{ + size_t size = arg->size; + + /* If the struct has just one element, look at that element + to find out whether to consider the struct as floating point. */ + while (arg->type == FFI_TYPE_STRUCT + && arg->elements[0] && !arg->elements[1]) + arg = arg->elements[0]; + + /* Structs of size 1, 2, 4, and 8 are passed in registers, + just like the corresponding int/float types. */ + switch (size) + { + case 1: + return FFI_TYPE_UINT8; + + case 2: + return FFI_TYPE_UINT16; + + case 4: + if (arg->type == FFI_TYPE_FLOAT) + return FFI_TYPE_FLOAT; + else + return FFI_TYPE_UINT32; + + case 8: + if (arg->type == FFI_TYPE_DOUBLE) + return FFI_TYPE_DOUBLE; + else + return FFI_TYPE_UINT64; + + default: + break; + } + + /* Other structs are passed via a pointer to the data. */ + return FFI_TYPE_POINTER; +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_prep_args. */ +/* */ +/* Function - Prepare parameters for call to function. */ +/* */ +/* ffi_prep_args is called by the assembly routine once stack space */ +/* has been allocated for the function's arguments. */ +/* */ +/*====================================================================*/ + +static void +ffi_prep_args (unsigned char *stack, extended_cif *ecif) +{ + /* The stack space will be filled with those areas: + + FPR argument register save area (highest addresses) + GPR argument register save area + temporary struct copies + overflow argument area (lowest addresses) + + We set up the following pointers: + + p_fpr: bottom of the FPR area (growing upwards) + p_gpr: bottom of the GPR area (growing upwards) + p_ov: bottom of the overflow area (growing upwards) + p_struct: top of the struct copy area (growing downwards) + + All areas are kept aligned to twice the word size. */ + + int gpr_off = ecif->cif->bytes; + int fpr_off = gpr_off + ROUND_SIZE (MAX_GPRARGS * sizeof (long)); + + unsigned long long *p_fpr = (unsigned long long *)(stack + fpr_off); + unsigned long *p_gpr = (unsigned long *)(stack + gpr_off); + unsigned char *p_struct = (unsigned char *)p_gpr; + unsigned long *p_ov = (unsigned long *)stack; + + int n_fpr = 0; + int n_gpr = 0; + int n_ov = 0; + + ffi_type **ptr; + void **p_argv = ecif->avalue; + int i; + + /* If we returning a structure then we set the first parameter register + to the address of where we are returning this structure. */ + + if (ecif->cif->flags == FFI390_RET_STRUCT) + p_gpr[n_gpr++] = (unsigned long) ecif->rvalue; + + /* Now for the arguments. */ + + for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; + i > 0; + i--, ptr++, p_argv++) + { + void *arg = *p_argv; + int type = (*ptr)->type; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + /* 16-byte long double is passed like a struct. */ + if (type == FFI_TYPE_LONGDOUBLE) + type = FFI_TYPE_STRUCT; +#endif + + /* Check how a structure type is passed. */ + if (type == FFI_TYPE_STRUCT) + { + type = ffi_check_struct_type (*ptr); + + /* If we pass the struct via pointer, copy the data. */ + if (type == FFI_TYPE_POINTER) + { + p_struct -= ROUND_SIZE ((*ptr)->size); + memcpy (p_struct, (char *)arg, (*ptr)->size); + arg = &p_struct; + } + } + + /* Now handle all primitive int/pointer/float data types. */ + switch (type) + { + case FFI_TYPE_DOUBLE: + if (n_fpr < MAX_FPRARGS) + p_fpr[n_fpr++] = *(unsigned long long *) arg; + else +#ifdef __s390x__ + p_ov[n_ov++] = *(unsigned long *) arg; +#else + p_ov[n_ov++] = ((unsigned long *) arg)[0], + p_ov[n_ov++] = ((unsigned long *) arg)[1]; +#endif + break; + + case FFI_TYPE_FLOAT: + if (n_fpr < MAX_FPRARGS) + p_fpr[n_fpr++] = (long long) *(unsigned int *) arg << 32; + else + p_ov[n_ov++] = *(unsigned int *) arg; + break; + + case FFI_TYPE_POINTER: + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = (unsigned long)*(unsigned char **) arg; + else + p_ov[n_ov++] = (unsigned long)*(unsigned char **) arg; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: +#ifdef __s390x__ + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = *(unsigned long *) arg; + else + p_ov[n_ov++] = *(unsigned long *) arg; +#else + if (n_gpr == MAX_GPRARGS-1) + n_gpr = MAX_GPRARGS; + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = ((unsigned long *) arg)[0], + p_gpr[n_gpr++] = ((unsigned long *) arg)[1]; + else + p_ov[n_ov++] = ((unsigned long *) arg)[0], + p_ov[n_ov++] = ((unsigned long *) arg)[1]; +#endif + break; + + case FFI_TYPE_UINT32: + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = *(unsigned int *) arg; + else + p_ov[n_ov++] = *(unsigned int *) arg; + break; + + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = *(signed int *) arg; + else + p_ov[n_ov++] = *(signed int *) arg; + break; + + case FFI_TYPE_UINT16: + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = *(unsigned short *) arg; + else + p_ov[n_ov++] = *(unsigned short *) arg; + break; + + case FFI_TYPE_SINT16: + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = *(signed short *) arg; + else + p_ov[n_ov++] = *(signed short *) arg; + break; + + case FFI_TYPE_UINT8: + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = *(unsigned char *) arg; + else + p_ov[n_ov++] = *(unsigned char *) arg; + break; + + case FFI_TYPE_SINT8: + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = *(signed char *) arg; + else + p_ov[n_ov++] = *(signed char *) arg; + break; + + default: + FFI_ASSERT (0); + break; + } + } +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_prep_cif_machdep. */ +/* */ +/* Function - Perform machine dependent CIF processing. */ +/* */ +/*====================================================================*/ + +ffi_status +ffi_prep_cif_machdep(ffi_cif *cif) +{ + size_t struct_size = 0; + int n_gpr = 0; + int n_fpr = 0; + int n_ov = 0; + + ffi_type **ptr; + int i; + + /* Determine return value handling. */ + + switch (cif->rtype->type) + { + /* Void is easy. */ + case FFI_TYPE_VOID: + cif->flags = FFI390_RET_VOID; + break; + + /* Structures are returned via a hidden pointer. */ + case FFI_TYPE_STRUCT: + cif->flags = FFI390_RET_STRUCT; + n_gpr++; /* We need one GPR to pass the pointer. */ + break; + + /* Floating point values are returned in fpr 0. */ + case FFI_TYPE_FLOAT: + cif->flags = FFI390_RET_FLOAT; + break; + + case FFI_TYPE_DOUBLE: + cif->flags = FFI390_RET_DOUBLE; + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + cif->flags = FFI390_RET_STRUCT; + n_gpr++; + break; +#endif + /* Integer values are returned in gpr 2 (and gpr 3 + for 64-bit values on 31-bit machines). */ + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + cif->flags = FFI390_RET_INT64; + break; + + case FFI_TYPE_POINTER: + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + /* These are to be extended to word size. */ +#ifdef __s390x__ + cif->flags = FFI390_RET_INT64; +#else + cif->flags = FFI390_RET_INT32; +#endif + break; + + default: + FFI_ASSERT (0); + break; + } + + /* Now for the arguments. */ + + for (ptr = cif->arg_types, i = cif->nargs; + i > 0; + i--, ptr++) + { + int type = (*ptr)->type; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + /* 16-byte long double is passed like a struct. */ + if (type == FFI_TYPE_LONGDOUBLE) + type = FFI_TYPE_STRUCT; +#endif + + /* Check how a structure type is passed. */ + if (type == FFI_TYPE_STRUCT) + { + type = ffi_check_struct_type (*ptr); + + /* If we pass the struct via pointer, we must reserve space + to copy its data for proper call-by-value semantics. */ + if (type == FFI_TYPE_POINTER) + struct_size += ROUND_SIZE ((*ptr)->size); + } + + /* Now handle all primitive int/float data types. */ + switch (type) + { + /* The first MAX_FPRARGS floating point arguments + go in FPRs, the rest overflow to the stack. */ + + case FFI_TYPE_DOUBLE: + if (n_fpr < MAX_FPRARGS) + n_fpr++; + else + n_ov += sizeof (double) / sizeof (long); + break; + + case FFI_TYPE_FLOAT: + if (n_fpr < MAX_FPRARGS) + n_fpr++; + else + n_ov++; + break; + + /* On 31-bit machines, 64-bit integers are passed in GPR pairs, + if one is still available, or else on the stack. If only one + register is free, skip the register (it won't be used for any + subsequent argument either). */ + +#ifndef __s390x__ + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + if (n_gpr == MAX_GPRARGS-1) + n_gpr = MAX_GPRARGS; + if (n_gpr < MAX_GPRARGS) + n_gpr += 2; + else + n_ov += 2; + break; +#endif + + /* Everything else is passed in GPRs (until MAX_GPRARGS + have been used) or overflows to the stack. */ + + default: + if (n_gpr < MAX_GPRARGS) + n_gpr++; + else + n_ov++; + break; + } + } + + /* Total stack space as required for overflow arguments + and temporary structure copies. */ + + cif->bytes = ROUND_SIZE (n_ov * sizeof (long)) + struct_size; + + return FFI_OK; +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_call. */ +/* */ +/* Function - Call the FFI routine. */ +/* */ +/*====================================================================*/ + +void +ffi_call(ffi_cif *cif, + void (*fn)(void), + void *rvalue, + void **avalue) +{ + int ret_type = cif->flags; + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + ecif.rvalue = rvalue; + + /* If we don't have a return value, we need to fake one. */ + if (rvalue == NULL) + { + if (ret_type == FFI390_RET_STRUCT) + ecif.rvalue = alloca (cif->rtype->size); + else + ret_type = FFI390_RET_VOID; + } + + switch (cif->abi) + { + case FFI_SYSV: + ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args, + ret_type, ecif.rvalue, fn); + break; + + default: + FFI_ASSERT (0); + break; + } +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_closure_helper_SYSV. */ +/* */ +/* Function - Call a FFI closure target function. */ +/* */ +/*====================================================================*/ + +void +ffi_closure_helper_SYSV (ffi_closure *closure, + unsigned long *p_gpr, + unsigned long long *p_fpr, + unsigned long *p_ov) +{ + unsigned long long ret_buffer; + + void *rvalue = &ret_buffer; + void **avalue; + void **p_arg; + + int n_gpr = 0; + int n_fpr = 0; + int n_ov = 0; + + ffi_type **ptr; + int i; + + /* Allocate buffer for argument list pointers. */ + + p_arg = avalue = alloca (closure->cif->nargs * sizeof (void *)); + + /* If we returning a structure, pass the structure address + directly to the target function. Otherwise, have the target + function store the return value to the GPR save area. */ + + if (closure->cif->flags == FFI390_RET_STRUCT) + rvalue = (void *) p_gpr[n_gpr++]; + + /* Now for the arguments. */ + + for (ptr = closure->cif->arg_types, i = closure->cif->nargs; + i > 0; + i--, p_arg++, ptr++) + { + int deref_struct_pointer = 0; + int type = (*ptr)->type; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + /* 16-byte long double is passed like a struct. */ + if (type == FFI_TYPE_LONGDOUBLE) + type = FFI_TYPE_STRUCT; +#endif + + /* Check how a structure type is passed. */ + if (type == FFI_TYPE_STRUCT) + { + type = ffi_check_struct_type (*ptr); + + /* If we pass the struct via pointer, remember to + retrieve the pointer later. */ + if (type == FFI_TYPE_POINTER) + deref_struct_pointer = 1; + } + + /* Pointers are passed like UINTs of the same size. */ + if (type == FFI_TYPE_POINTER) +#ifdef __s390x__ + type = FFI_TYPE_UINT64; +#else + type = FFI_TYPE_UINT32; +#endif + + /* Now handle all primitive int/float data types. */ + switch (type) + { + case FFI_TYPE_DOUBLE: + if (n_fpr < MAX_FPRARGS) + *p_arg = &p_fpr[n_fpr++]; + else + *p_arg = &p_ov[n_ov], + n_ov += sizeof (double) / sizeof (long); + break; + + case FFI_TYPE_FLOAT: + if (n_fpr < MAX_FPRARGS) + *p_arg = &p_fpr[n_fpr++]; + else + *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: +#ifdef __s390x__ + if (n_gpr < MAX_GPRARGS) + *p_arg = &p_gpr[n_gpr++]; + else + *p_arg = &p_ov[n_ov++]; +#else + if (n_gpr == MAX_GPRARGS-1) + n_gpr = MAX_GPRARGS; + if (n_gpr < MAX_GPRARGS) + *p_arg = &p_gpr[n_gpr], n_gpr += 2; + else + *p_arg = &p_ov[n_ov], n_ov += 2; +#endif + break; + + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + if (n_gpr < MAX_GPRARGS) + *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 4; + else + *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4; + break; + + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + if (n_gpr < MAX_GPRARGS) + *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 2; + else + *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 2; + break; + + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + if (n_gpr < MAX_GPRARGS) + *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 1; + else + *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 1; + break; + + default: + FFI_ASSERT (0); + break; + } + + /* If this is a struct passed via pointer, we need to + actually retrieve that pointer. */ + if (deref_struct_pointer) + *p_arg = *(void **)*p_arg; + } + + + /* Call the target function. */ + (closure->fun) (closure->cif, rvalue, avalue, closure->user_data); + + /* Convert the return value. */ + switch (closure->cif->rtype->type) + { + /* Void is easy, and so is struct. */ + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + break; + + /* Floating point values are returned in fpr 0. */ + case FFI_TYPE_FLOAT: + p_fpr[0] = (long long) *(unsigned int *) rvalue << 32; + break; + + case FFI_TYPE_DOUBLE: + p_fpr[0] = *(unsigned long long *) rvalue; + break; + + /* Integer values are returned in gpr 2 (and gpr 3 + for 64-bit values on 31-bit machines). */ + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: +#ifdef __s390x__ + p_gpr[0] = *(unsigned long *) rvalue; +#else + p_gpr[0] = ((unsigned long *) rvalue)[0], + p_gpr[1] = ((unsigned long *) rvalue)[1]; +#endif + break; + + case FFI_TYPE_POINTER: + case FFI_TYPE_UINT32: + case FFI_TYPE_UINT16: + case FFI_TYPE_UINT8: + p_gpr[0] = *(unsigned long *) rvalue; + break; + + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + case FFI_TYPE_SINT16: + case FFI_TYPE_SINT8: + p_gpr[0] = *(signed long *) rvalue; + break; + + default: + FFI_ASSERT (0); + break; + } +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_prep_closure_loc. */ +/* */ +/* Function - Prepare a FFI closure. */ +/* */ +/*====================================================================*/ + +ffi_status +ffi_prep_closure_loc (ffi_closure *closure, + ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + void *codeloc) +{ + FFI_ASSERT (cif->abi == FFI_SYSV); + +#ifndef __s390x__ + *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */ + *(short *)&closure->tramp [2] = 0x9801; /* lm %r0,%r1,6(%r1) */ + *(short *)&closure->tramp [4] = 0x1006; + *(short *)&closure->tramp [6] = 0x07f1; /* br %r1 */ + *(long *)&closure->tramp [8] = (long)codeloc; + *(long *)&closure->tramp[12] = (long)&ffi_closure_SYSV; +#else + *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */ + *(short *)&closure->tramp [2] = 0xeb01; /* lmg %r0,%r1,14(%r1) */ + *(short *)&closure->tramp [4] = 0x100e; + *(short *)&closure->tramp [6] = 0x0004; + *(short *)&closure->tramp [8] = 0x07f1; /* br %r1 */ + *(long *)&closure->tramp[16] = (long)codeloc; + *(long *)&closure->tramp[24] = (long)&ffi_closure_SYSV; +#endif + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + +/*======================== End of Routine ============================*/ + diff --git a/js/src/ctypes/libffi/src/s390/ffitarget.h b/js/src/ctypes/libffi/src/s390/ffitarget.h new file mode 100644 index 0000000..a262691 --- /dev/null +++ b/js/src/ctypes/libffi/src/s390/ffitarget.h @@ -0,0 +1,62 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for S390. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#if defined (__s390x__) +#ifndef S390X +#define S390X +#endif +#endif + +/* ---- System specific configurations ----------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_SYSV +} ffi_abi; +#endif + + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#ifdef S390X +#define FFI_TRAMPOLINE_SIZE 32 +#else +#define FFI_TRAMPOLINE_SIZE 16 +#endif +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/js/src/ctypes/libffi/src/s390/sysv.S b/js/src/ctypes/libffi/src/s390/sysv.S new file mode 100644 index 0000000..4731a31 --- /dev/null +++ b/js/src/ctypes/libffi/src/s390/sysv.S @@ -0,0 +1,434 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2000 Software AG + Copyright (c) 2008 Red Hat, Inc. + + S390 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include + +#ifndef __s390x__ + +.text + + # r2: cif->bytes + # r3: &ecif + # r4: ffi_prep_args + # r5: ret_type + # r6: ecif.rvalue + # ov: fn + + # This assumes we are using gas. + .globl ffi_call_SYSV + .type ffi_call_SYSV,%function +ffi_call_SYSV: +.LFB1: + stm %r6,%r15,24(%r15) # Save registers +.LCFI0: + basr %r13,0 # Set up base register +.Lbase: + lr %r11,%r15 # Set up frame pointer +.LCFI1: + sr %r15,%r2 + ahi %r15,-96-48 # Allocate stack + lr %r8,%r6 # Save ecif.rvalue + sr %r9,%r9 + ic %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address + l %r7,96(%r11) # Load function address + st %r11,0(%r15) # Set up back chain + ahi %r11,-48 # Register save area +.LCFI2: + + la %r2,96(%r15) # Save area + # r3 already holds &ecif + basr %r14,%r4 # Call ffi_prep_args + + lm %r2,%r6,0(%r11) # Load arguments + ld %f0,32(%r11) + ld %f2,40(%r11) + la %r14,0(%r13,%r9) # Set return address + br %r7 # ... and call function + +.LretNone: # Return void + l %r4,48+56(%r11) + lm %r6,%r15,48+24(%r11) + br %r4 + +.LretFloat: + l %r4,48+56(%r11) + ste %f0,0(%r8) # Return float + lm %r6,%r15,48+24(%r11) + br %r4 + +.LretDouble: + l %r4,48+56(%r11) + std %f0,0(%r8) # Return double + lm %r6,%r15,48+24(%r11) + br %r4 + +.LretInt32: + l %r4,48+56(%r11) + st %r2,0(%r8) # Return int + lm %r6,%r15,48+24(%r11) + br %r4 + +.LretInt64: + l %r4,48+56(%r11) + stm %r2,%r3,0(%r8) # Return long long + lm %r6,%r15,48+24(%r11) + br %r4 + +.Ltable: + .byte .LretNone-.Lbase # FFI390_RET_VOID + .byte .LretNone-.Lbase # FFI390_RET_STRUCT + .byte .LretFloat-.Lbase # FFI390_RET_FLOAT + .byte .LretDouble-.Lbase # FFI390_RET_DOUBLE + .byte .LretInt32-.Lbase # FFI390_RET_INT32 + .byte .LretInt64-.Lbase # FFI390_RET_INT64 + +.LFE1: +.ffi_call_SYSV_end: + .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV + + + .globl ffi_closure_SYSV + .type ffi_closure_SYSV,%function +ffi_closure_SYSV: +.LFB2: + stm %r12,%r15,48(%r15) # Save registers +.LCFI10: + basr %r13,0 # Set up base register +.Lcbase: + stm %r2,%r6,8(%r15) # Save arguments + std %f0,64(%r15) + std %f2,72(%r15) + lr %r1,%r15 # Set up stack frame + ahi %r15,-96 +.LCFI11: + l %r12,.Lchelper-.Lcbase(%r13) # Get helper function + lr %r2,%r0 # Closure + la %r3,8(%r1) # GPRs + la %r4,64(%r1) # FPRs + la %r5,96(%r1) # Overflow + st %r1,0(%r15) # Set up back chain + + bas %r14,0(%r12,%r13) # Call helper + + l %r4,96+56(%r15) + ld %f0,96+64(%r15) # Load return registers + lm %r2,%r3,96+8(%r15) + lm %r12,%r15,96+48(%r15) + br %r4 + + .align 4 +.Lchelper: + .long ffi_closure_helper_SYSV-.Lcbase + +.LFE2: + +.ffi_closure_SYSV_end: + .size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV + + + .section .eh_frame,EH_FRAME_FLAGS,@progbits +.Lframe1: + .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry +.LSCIE1: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version + .ascii "zR\0" # CIE Augmentation + .uleb128 0x1 # CIE Code Alignment Factor + .sleb128 -4 # CIE Data Alignment Factor + .byte 0xe # CIE RA Column + .uleb128 0x1 # Augmentation size + .byte 0x1b # FDE Encoding (pcrel sdata4) + .byte 0xc # DW_CFA_def_cfa + .uleb128 0xf + .uleb128 0x60 + .align 4 +.LECIE1: +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 # FDE Length +.LASFDE1: + .4byte .LASFDE1-.Lframe1 # FDE CIE offset + .4byte .LFB1-. # FDE initial location + .4byte .LFE1-.LFB1 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI0-.LFB1 + .byte 0x8f # DW_CFA_offset, column 0xf + .uleb128 0x9 + .byte 0x8e # DW_CFA_offset, column 0xe + .uleb128 0xa + .byte 0x8d # DW_CFA_offset, column 0xd + .uleb128 0xb + .byte 0x8c # DW_CFA_offset, column 0xc + .uleb128 0xc + .byte 0x8b # DW_CFA_offset, column 0xb + .uleb128 0xd + .byte 0x8a # DW_CFA_offset, column 0xa + .uleb128 0xe + .byte 0x89 # DW_CFA_offset, column 0x9 + .uleb128 0xf + .byte 0x88 # DW_CFA_offset, column 0x8 + .uleb128 0x10 + .byte 0x87 # DW_CFA_offset, column 0x7 + .uleb128 0x11 + .byte 0x86 # DW_CFA_offset, column 0x6 + .uleb128 0x12 + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI1-.LCFI0 + .byte 0xd # DW_CFA_def_cfa_register + .uleb128 0xb + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI2-.LCFI1 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 0x90 + .align 4 +.LEFDE1: +.LSFDE2: + .4byte .LEFDE2-.LASFDE2 # FDE Length +.LASFDE2: + .4byte .LASFDE2-.Lframe1 # FDE CIE offset + .4byte .LFB2-. # FDE initial location + .4byte .LFE2-.LFB2 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI10-.LFB2 + .byte 0x8f # DW_CFA_offset, column 0xf + .uleb128 0x9 + .byte 0x8e # DW_CFA_offset, column 0xe + .uleb128 0xa + .byte 0x8d # DW_CFA_offset, column 0xd + .uleb128 0xb + .byte 0x8c # DW_CFA_offset, column 0xc + .uleb128 0xc + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI11-.LCFI10 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 0xc0 + .align 4 +.LEFDE2: + +#else + +.text + + # r2: cif->bytes + # r3: &ecif + # r4: ffi_prep_args + # r5: ret_type + # r6: ecif.rvalue + # ov: fn + + # This assumes we are using gas. + .globl ffi_call_SYSV + .type ffi_call_SYSV,%function +ffi_call_SYSV: +.LFB1: + stmg %r6,%r15,48(%r15) # Save registers +.LCFI0: + larl %r13,.Lbase # Set up base register + lgr %r11,%r15 # Set up frame pointer +.LCFI1: + sgr %r15,%r2 + aghi %r15,-160-80 # Allocate stack + lgr %r8,%r6 # Save ecif.rvalue + llgc %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address + lg %r7,160(%r11) # Load function address + stg %r11,0(%r15) # Set up back chain + aghi %r11,-80 # Register save area +.LCFI2: + + la %r2,160(%r15) # Save area + # r3 already holds &ecif + basr %r14,%r4 # Call ffi_prep_args + + lmg %r2,%r6,0(%r11) # Load arguments + ld %f0,48(%r11) + ld %f2,56(%r11) + ld %f4,64(%r11) + ld %f6,72(%r11) + la %r14,0(%r13,%r9) # Set return address + br %r7 # ... and call function + +.Lbase: +.LretNone: # Return void + lg %r4,80+112(%r11) + lmg %r6,%r15,80+48(%r11) + br %r4 + +.LretFloat: + lg %r4,80+112(%r11) + ste %f0,0(%r8) # Return float + lmg %r6,%r15,80+48(%r11) + br %r4 + +.LretDouble: + lg %r4,80+112(%r11) + std %f0,0(%r8) # Return double + lmg %r6,%r15,80+48(%r11) + br %r4 + +.LretInt32: + lg %r4,80+112(%r11) + st %r2,0(%r8) # Return int + lmg %r6,%r15,80+48(%r11) + br %r4 + +.LretInt64: + lg %r4,80+112(%r11) + stg %r2,0(%r8) # Return long + lmg %r6,%r15,80+48(%r11) + br %r4 + +.Ltable: + .byte .LretNone-.Lbase # FFI390_RET_VOID + .byte .LretNone-.Lbase # FFI390_RET_STRUCT + .byte .LretFloat-.Lbase # FFI390_RET_FLOAT + .byte .LretDouble-.Lbase # FFI390_RET_DOUBLE + .byte .LretInt32-.Lbase # FFI390_RET_INT32 + .byte .LretInt64-.Lbase # FFI390_RET_INT64 + +.LFE1: +.ffi_call_SYSV_end: + .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV + + + .globl ffi_closure_SYSV + .type ffi_closure_SYSV,%function +ffi_closure_SYSV: +.LFB2: + stmg %r14,%r15,112(%r15) # Save registers +.LCFI10: + stmg %r2,%r6,16(%r15) # Save arguments + std %f0,128(%r15) + std %f2,136(%r15) + std %f4,144(%r15) + std %f6,152(%r15) + lgr %r1,%r15 # Set up stack frame + aghi %r15,-160 +.LCFI11: + lgr %r2,%r0 # Closure + la %r3,16(%r1) # GPRs + la %r4,128(%r1) # FPRs + la %r5,160(%r1) # Overflow + stg %r1,0(%r15) # Set up back chain + + brasl %r14,ffi_closure_helper_SYSV # Call helper + + lg %r14,160+112(%r15) + ld %f0,160+128(%r15) # Load return registers + lg %r2,160+16(%r15) + la %r15,160(%r15) + br %r14 +.LFE2: + +.ffi_closure_SYSV_end: + .size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV + + + + .section .eh_frame,EH_FRAME_FLAGS,@progbits +.Lframe1: + .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry +.LSCIE1: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version + .ascii "zR\0" # CIE Augmentation + .uleb128 0x1 # CIE Code Alignment Factor + .sleb128 -8 # CIE Data Alignment Factor + .byte 0xe # CIE RA Column + .uleb128 0x1 # Augmentation size + .byte 0x1b # FDE Encoding (pcrel sdata4) + .byte 0xc # DW_CFA_def_cfa + .uleb128 0xf + .uleb128 0xa0 + .align 8 +.LECIE1: +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 # FDE Length +.LASFDE1: + .4byte .LASFDE1-.Lframe1 # FDE CIE offset + .4byte .LFB1-. # FDE initial location + .4byte .LFE1-.LFB1 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI0-.LFB1 + .byte 0x8f # DW_CFA_offset, column 0xf + .uleb128 0x5 + .byte 0x8e # DW_CFA_offset, column 0xe + .uleb128 0x6 + .byte 0x8d # DW_CFA_offset, column 0xd + .uleb128 0x7 + .byte 0x8c # DW_CFA_offset, column 0xc + .uleb128 0x8 + .byte 0x8b # DW_CFA_offset, column 0xb + .uleb128 0x9 + .byte 0x8a # DW_CFA_offset, column 0xa + .uleb128 0xa + .byte 0x89 # DW_CFA_offset, column 0x9 + .uleb128 0xb + .byte 0x88 # DW_CFA_offset, column 0x8 + .uleb128 0xc + .byte 0x87 # DW_CFA_offset, column 0x7 + .uleb128 0xd + .byte 0x86 # DW_CFA_offset, column 0x6 + .uleb128 0xe + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI1-.LCFI0 + .byte 0xd # DW_CFA_def_cfa_register + .uleb128 0xb + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI2-.LCFI1 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 0xf0 + .align 8 +.LEFDE1: +.LSFDE2: + .4byte .LEFDE2-.LASFDE2 # FDE Length +.LASFDE2: + .4byte .LASFDE2-.Lframe1 # FDE CIE offset + .4byte .LFB2-. # FDE initial location + .4byte .LFE2-.LFB2 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI10-.LFB2 + .byte 0x8f # DW_CFA_offset, column 0xf + .uleb128 0x5 + .byte 0x8e # DW_CFA_offset, column 0xe + .uleb128 0x6 + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI11-.LCFI10 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 0x140 + .align 8 +.LEFDE2: + +#endif + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/js/src/ctypes/libffi/src/sh/ffi.c b/js/src/ctypes/libffi/src/sh/ffi.c new file mode 100644 index 0000000..69bd025 --- /dev/null +++ b/js/src/ctypes/libffi/src/sh/ffi.c @@ -0,0 +1,716 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Kaz Kojima + Copyright (c) 2008 Red Hat, Inc. + + SuperH Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include + +#define NGREGARG 4 +#if defined(__SH4__) +#define NFREGARG 8 +#endif + +#if defined(__HITACHI__) +#define STRUCT_VALUE_ADDRESS_WITH_ARG 1 +#else +#define STRUCT_VALUE_ADDRESS_WITH_ARG 0 +#endif + +/* If the structure has essentialy an unique element, return its type. */ +static int +simple_type (ffi_type *arg) +{ + if (arg->type != FFI_TYPE_STRUCT) + return arg->type; + else if (arg->elements[1]) + return FFI_TYPE_STRUCT; + + return simple_type (arg->elements[0]); +} + +static int +return_type (ffi_type *arg) +{ + unsigned short type; + + if (arg->type != FFI_TYPE_STRUCT) + return arg->type; + + type = simple_type (arg->elements[0]); + if (! arg->elements[1]) + { + switch (type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + return FFI_TYPE_INT; + + default: + return type; + } + } + + /* gcc uses r0/r1 pair for some kind of structures. */ + if (arg->size <= 2 * sizeof (int)) + { + int i = 0; + ffi_type *e; + + while ((e = arg->elements[i++])) + { + type = simple_type (e); + switch (type) + { + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_INT: + case FFI_TYPE_FLOAT: + return FFI_TYPE_UINT64; + + default: + break; + } + } + } + + return FFI_TYPE_STRUCT; +} + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +void ffi_prep_args(char *stack, extended_cif *ecif) +{ + register unsigned int i; + register int tmp; + register unsigned int avn; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + int greg, ireg; +#if defined(__SH4__) + int freg = 0; +#endif + + tmp = 0; + argp = stack; + + if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT) + { + *(void **) argp = ecif->rvalue; + argp += 4; + ireg = STRUCT_VALUE_ADDRESS_WITH_ARG ? 1 : 0; + } + else + ireg = 0; + + /* Set arguments for registers. */ + greg = ireg; + avn = ecif->cif->nargs; + p_argv = ecif->avalue; + + for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++) + { + size_t z; + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + if (greg++ >= NGREGARG) + continue; + + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + argp += z; + } + else if (z == sizeof(int)) + { +#if defined(__SH4__) + if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + if (freg++ >= NFREGARG) + continue; + } + else +#endif + { + if (greg++ >= NGREGARG) + continue; + } + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + argp += z; + } +#if defined(__SH4__) + else if ((*p_arg)->type == FFI_TYPE_DOUBLE) + { + if (freg + 1 >= NFREGARG) + continue; + freg = (freg + 1) & ~1; + freg += 2; + memcpy (argp, *p_argv, z); + argp += z; + } +#endif + else + { + int n = (z + sizeof (int) - 1) / sizeof (int); +#if defined(__SH4__) + if (greg + n - 1 >= NGREGARG) + continue; +#else + if (greg >= NGREGARG) + continue; +#endif + greg += n; + memcpy (argp, *p_argv, z); + argp += n * sizeof (int); + } + } + + /* Set arguments on stack. */ + greg = ireg; +#if defined(__SH4__) + freg = 0; +#endif + p_argv = ecif->avalue; + + for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++) + { + size_t z; + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + if (greg++ < NGREGARG) + continue; + + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + argp += z; + } + else if (z == sizeof(int)) + { +#if defined(__SH4__) + if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + if (freg++ < NFREGARG) + continue; + } + else +#endif + { + if (greg++ < NGREGARG) + continue; + } + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + argp += z; + } +#if defined(__SH4__) + else if ((*p_arg)->type == FFI_TYPE_DOUBLE) + { + if (freg + 1 < NFREGARG) + { + freg = (freg + 1) & ~1; + freg += 2; + continue; + } + memcpy (argp, *p_argv, z); + argp += z; + } +#endif + else + { + int n = (z + sizeof (int) - 1) / sizeof (int); + if (greg + n - 1 < NGREGARG) + { + greg += n; + continue; + } +#if (! defined(__SH4__)) + else if (greg < NGREGARG) + { + greg = NGREGARG; + continue; + } +#endif + memcpy (argp, *p_argv, z); + argp += n * sizeof (int); + } + } + + return; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + int i, j; + int size, type; + int n, m; + int greg; +#if defined(__SH4__) + int freg = 0; +#endif + + cif->flags = 0; + + greg = ((return_type (cif->rtype) == FFI_TYPE_STRUCT) && + STRUCT_VALUE_ADDRESS_WITH_ARG) ? 1 : 0; + +#if defined(__SH4__) + for (i = j = 0; i < cif->nargs && j < 12; i++) + { + type = (cif->arg_types)[i]->type; + switch (type) + { + case FFI_TYPE_FLOAT: + if (freg >= NFREGARG) + continue; + freg++; + cif->flags += ((cif->arg_types)[i]->type) << (2 * j); + j++; + break; + + case FFI_TYPE_DOUBLE: + if ((freg + 1) >= NFREGARG) + continue; + freg = (freg + 1) & ~1; + freg += 2; + cif->flags += ((cif->arg_types)[i]->type) << (2 * j); + j++; + break; + + default: + size = (cif->arg_types)[i]->size; + n = (size + sizeof (int) - 1) / sizeof (int); + if (greg + n - 1 >= NGREGARG) + continue; + greg += n; + for (m = 0; m < n; m++) + cif->flags += FFI_TYPE_INT << (2 * j++); + break; + } + } +#else + for (i = j = 0; i < cif->nargs && j < 4; i++) + { + size = (cif->arg_types)[i]->size; + n = (size + sizeof (int) - 1) / sizeof (int); + if (greg >= NGREGARG) + continue; + else if (greg + n - 1 >= NGREGARG) + n = NGREGARG - greg; + greg += n; + for (m = 0; m < n; m++) + cif->flags += FFI_TYPE_INT << (2 * j++); + } +#endif + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_STRUCT: + cif->flags += (unsigned) (return_type (cif->rtype)) << 24; + break; + + case FFI_TYPE_VOID: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags += (unsigned) cif->rtype->type << 24; + break; + + default: + cif->flags += FFI_TYPE_INT << 24; + break; + } + + return FFI_OK; +} + +extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, + unsigned, unsigned, unsigned *, void (*fn)(void)); + +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + extended_cif ecif; + UINT64 trvalue; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if (cif->rtype->type == FFI_TYPE_STRUCT + && return_type (cif->rtype) != FFI_TYPE_STRUCT) + ecif.rvalue = &trvalue; + else if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + ecif.rvalue = alloca(cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: + ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, + fn); + break; + default: + FFI_ASSERT(0); + break; + } + + if (rvalue + && cif->rtype->type == FFI_TYPE_STRUCT + && return_type (cif->rtype) != FFI_TYPE_STRUCT) + memcpy (rvalue, &trvalue, cif->rtype->size); +} + +extern void ffi_closure_SYSV (void); +#if defined(__SH4__) +extern void __ic_invalidate (void *line); +#endif + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc) +{ + unsigned int *tramp; + unsigned int insn; + + FFI_ASSERT (cif->abi == FFI_GCC_SYSV); + + tramp = (unsigned int *) &closure->tramp[0]; + /* Set T bit if the function returns a struct pointed with R2. */ + insn = (return_type (cif->rtype) == FFI_TYPE_STRUCT + ? 0x0018 /* sett */ + : 0x0008 /* clrt */); + +#ifdef __LITTLE_ENDIAN__ + tramp[0] = 0xd301d102; + tramp[1] = 0x0000412b | (insn << 16); +#else + tramp[0] = 0xd102d301; + tramp[1] = 0x412b0000 | insn; +#endif + *(void **) &tramp[2] = (void *)codeloc; /* ctx */ + *(void **) &tramp[3] = (void *)ffi_closure_SYSV; /* funaddr */ + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + +#if defined(__SH4__) + /* Flush the icache. */ + __ic_invalidate(codeloc); +#endif + + return FFI_OK; +} + +/* Basically the trampoline invokes ffi_closure_SYSV, and on + * entry, r3 holds the address of the closure. + * After storing the registers that could possibly contain + * parameters to be passed into the stack frame and setting + * up space for a return value, ffi_closure_SYSV invokes the + * following helper function to do most of the work. + */ + +#ifdef __LITTLE_ENDIAN__ +#define OFS_INT8 0 +#define OFS_INT16 0 +#else +#define OFS_INT8 3 +#define OFS_INT16 2 +#endif + +int +ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue, + unsigned long *pgr, unsigned long *pfr, + unsigned long *pst) +{ + void **avalue; + ffi_type **p_arg; + int i, avn; + int ireg, greg = 0; +#if defined(__SH4__) + int freg = 0; +#endif + ffi_cif *cif; + + cif = closure->cif; + avalue = alloca(cif->nargs * sizeof(void *)); + + /* Copy the caller's structure return value address so that the closure + returns the data directly to the caller. */ + if (cif->rtype->type == FFI_TYPE_STRUCT && STRUCT_VALUE_ADDRESS_WITH_ARG) + { + rvalue = (void *) *pgr++; + ireg = 1; + } + else + ireg = 0; + + cif = closure->cif; + greg = ireg; + avn = cif->nargs; + + /* Grab the addresses of the arguments from the stack frame. */ + for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + if (greg++ >= NGREGARG) + continue; + + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = (((char *)pgr) + OFS_INT8); + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = (((char *)pgr) + OFS_INT16); + break; + + case FFI_TYPE_STRUCT: + avalue[i] = pgr; + break; + + default: + FFI_ASSERT(0); + } + pgr++; + } + else if (z == sizeof(int)) + { +#if defined(__SH4__) + if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + if (freg++ >= NFREGARG) + continue; + avalue[i] = pfr; + pfr++; + } + else +#endif + { + if (greg++ >= NGREGARG) + continue; + avalue[i] = pgr; + pgr++; + } + } +#if defined(__SH4__) + else if ((*p_arg)->type == FFI_TYPE_DOUBLE) + { + if (freg + 1 >= NFREGARG) + continue; + if (freg & 1) + pfr++; + freg = (freg + 1) & ~1; + freg += 2; + avalue[i] = pfr; + pfr += 2; + } +#endif + else + { + int n = (z + sizeof (int) - 1) / sizeof (int); +#if defined(__SH4__) + if (greg + n - 1 >= NGREGARG) + continue; +#else + if (greg >= NGREGARG) + continue; +#endif + greg += n; + avalue[i] = pgr; + pgr += n; + } + } + + greg = ireg; +#if defined(__SH4__) + freg = 0; +#endif + + for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + if (greg++ < NGREGARG) + continue; + + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = (((char *)pst) + OFS_INT8); + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = (((char *)pst) + OFS_INT16); + break; + + case FFI_TYPE_STRUCT: + avalue[i] = pst; + break; + + default: + FFI_ASSERT(0); + } + pst++; + } + else if (z == sizeof(int)) + { +#if defined(__SH4__) + if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + if (freg++ < NFREGARG) + continue; + } + else +#endif + { + if (greg++ < NGREGARG) + continue; + } + avalue[i] = pst; + pst++; + } +#if defined(__SH4__) + else if ((*p_arg)->type == FFI_TYPE_DOUBLE) + { + if (freg + 1 < NFREGARG) + { + freg = (freg + 1) & ~1; + freg += 2; + continue; + } + avalue[i] = pst; + pst += 2; + } +#endif + else + { + int n = (z + sizeof (int) - 1) / sizeof (int); + if (greg + n - 1 < NGREGARG) + { + greg += n; + continue; + } +#if (! defined(__SH4__)) + else if (greg < NGREGARG) + { + greg += n; + pst += greg - NGREGARG; + continue; + } +#endif + avalue[i] = pst; + pst += n; + } + } + + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_SYSV how to perform return type promotions. */ + return return_type (cif->rtype); +} diff --git a/js/src/ctypes/libffi/src/sh/ffitarget.h b/js/src/ctypes/libffi/src/sh/ffitarget.h new file mode 100644 index 0000000..4f1f639 --- /dev/null +++ b/js/src/ctypes/libffi/src/sh/ffitarget.h @@ -0,0 +1,49 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for SuperH. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- Generic type definitions ----------------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_SYSV +} ffi_abi; +#endif + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 16 +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/js/src/ctypes/libffi/src/sh/sysv.S b/js/src/ctypes/libffi/src/sh/sysv.S new file mode 100644 index 0000000..5be7516 --- /dev/null +++ b/js/src/ctypes/libffi/src/sh/sysv.S @@ -0,0 +1,850 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2002, 2003, 2004, 2006, 2008 Kaz Kojima + + SuperH Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include +#ifdef HAVE_MACHINE_ASM_H +#include +#else +/* XXX these lose for some platforms, I'm sure. */ +#define CNAME(x) x +#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): +#endif + +#if defined(__HITACHI__) +#define STRUCT_VALUE_ADDRESS_WITH_ARG 1 +#else +#define STRUCT_VALUE_ADDRESS_WITH_ARG 0 +#endif + +.text + + # r4: ffi_prep_args + # r5: &ecif + # r6: bytes + # r7: flags + # sp+0: rvalue + # sp+4: fn + + # This assumes we are using gas. +ENTRY(ffi_call_SYSV) + # Save registers +.LFB1: + mov.l r8,@-r15 +.LCFI0: + mov.l r9,@-r15 +.LCFI1: + mov.l r10,@-r15 +.LCFI2: + mov.l r12,@-r15 +.LCFI3: + mov.l r14,@-r15 +.LCFI4: + sts.l pr,@-r15 +.LCFI5: + mov r15,r14 +.LCFI6: +#if defined(__SH4__) + mov r6,r8 + mov r7,r9 + + sub r6,r15 + add #-16,r15 + mov #~7,r0 + and r0,r15 + + mov r4,r0 + jsr @r0 + mov r15,r4 + + mov r9,r1 + shlr8 r9 + shlr8 r9 + shlr8 r9 + + mov #FFI_TYPE_STRUCT,r2 + cmp/eq r2,r9 + bf 1f +#if STRUCT_VALUE_ADDRESS_WITH_ARG + mov.l @r15+,r4 + bra 2f + mov #5,r2 +#else + mov.l @r15+,r10 +#endif +1: + mov #4,r2 +2: + mov #4,r3 + +L_pass: + cmp/pl r8 + bf L_call_it + + mov r1,r0 + and #3,r0 + +L_pass_d: + cmp/eq #FFI_TYPE_DOUBLE,r0 + bf L_pass_f + + mov r3,r0 + and #1,r0 + tst r0,r0 + bt 1f + add #1,r3 +1: + mov #12,r0 + cmp/hs r0,r3 + bt/s 3f + shlr2 r1 + bsr L_pop_d + nop +3: + add #2,r3 + bra L_pass + add #-8,r8 + +L_pop_d: + mov r3,r0 + add r0,r0 + add r3,r0 + add #-12,r0 + braf r0 + nop +#ifdef __LITTLE_ENDIAN__ + fmov.s @r15+,fr5 + rts + fmov.s @r15+,fr4 + fmov.s @r15+,fr7 + rts + fmov.s @r15+,fr6 + fmov.s @r15+,fr9 + rts + fmov.s @r15+,fr8 + fmov.s @r15+,fr11 + rts + fmov.s @r15+,fr10 +#else + fmov.s @r15+,fr4 + rts + fmov.s @r15+,fr5 + fmov.s @r15+,fr6 + rts + fmov.s @r15+,fr7 + fmov.s @r15+,fr8 + rts + fmov.s @r15+,fr9 + fmov.s @r15+,fr10 + rts + fmov.s @r15+,fr11 +#endif + +L_pass_f: + cmp/eq #FFI_TYPE_FLOAT,r0 + bf L_pass_i + + mov #12,r0 + cmp/hs r0,r3 + bt/s 2f + shlr2 r1 + bsr L_pop_f + nop +2: + add #1,r3 + bra L_pass + add #-4,r8 + +L_pop_f: + mov r3,r0 + shll2 r0 + add #-16,r0 + braf r0 + nop +#ifdef __LITTLE_ENDIAN__ + rts + fmov.s @r15+,fr5 + rts + fmov.s @r15+,fr4 + rts + fmov.s @r15+,fr7 + rts + fmov.s @r15+,fr6 + rts + fmov.s @r15+,fr9 + rts + fmov.s @r15+,fr8 + rts + fmov.s @r15+,fr11 + rts + fmov.s @r15+,fr10 +#else + rts + fmov.s @r15+,fr4 + rts + fmov.s @r15+,fr5 + rts + fmov.s @r15+,fr6 + rts + fmov.s @r15+,fr7 + rts + fmov.s @r15+,fr8 + rts + fmov.s @r15+,fr9 + rts + fmov.s @r15+,fr10 + rts + fmov.s @r15+,fr11 +#endif + +L_pass_i: + cmp/eq #FFI_TYPE_INT,r0 + bf L_call_it + + mov #8,r0 + cmp/hs r0,r2 + bt/s 2f + shlr2 r1 + bsr L_pop_i + nop +2: + add #1,r2 + bra L_pass + add #-4,r8 + +L_pop_i: + mov r2,r0 + shll2 r0 + add #-16,r0 + braf r0 + nop + rts + mov.l @r15+,r4 + rts + mov.l @r15+,r5 + rts + mov.l @r15+,r6 + rts + mov.l @r15+,r7 + +L_call_it: + # call function +#if (! STRUCT_VALUE_ADDRESS_WITH_ARG) + mov r10, r2 +#endif + mov.l @(28,r14),r1 + jsr @r1 + nop + +L_ret_d: + mov #FFI_TYPE_DOUBLE,r2 + cmp/eq r2,r9 + bf L_ret_ll + + mov.l @(24,r14),r1 +#ifdef __LITTLE_ENDIAN__ + fmov.s fr1,@r1 + add #4,r1 + bra L_epilogue + fmov.s fr0,@r1 +#else + fmov.s fr0,@r1 + add #4,r1 + bra L_epilogue + fmov.s fr1,@r1 +#endif + +L_ret_ll: + mov #FFI_TYPE_SINT64,r2 + cmp/eq r2,r9 + bt/s 1f + mov #FFI_TYPE_UINT64,r2 + cmp/eq r2,r9 + bf L_ret_f + +1: + mov.l @(24,r14),r2 + mov.l r0,@r2 + bra L_epilogue + mov.l r1,@(4,r2) + +L_ret_f: + mov #FFI_TYPE_FLOAT,r2 + cmp/eq r2,r9 + bf L_ret_i + + mov.l @(24,r14),r1 + bra L_epilogue + fmov.s fr0,@r1 + +L_ret_i: + mov #FFI_TYPE_INT,r2 + cmp/eq r2,r9 + bf L_epilogue + + mov.l @(24,r14),r1 + bra L_epilogue + mov.l r0,@r1 + +L_epilogue: + # Remove the space we pushed for the args + mov r14,r15 + + lds.l @r15+,pr + mov.l @r15+,r14 + mov.l @r15+,r12 + mov.l @r15+,r10 + mov.l @r15+,r9 + rts + mov.l @r15+,r8 +#else + mov r6,r8 + mov r7,r9 + + sub r6,r15 + add #-16,r15 + mov #~7,r0 + and r0,r15 + + mov r4,r0 + jsr @r0 + mov r15,r4 + + mov r9,r3 + shlr8 r9 + shlr8 r9 + shlr8 r9 + + mov #FFI_TYPE_STRUCT,r2 + cmp/eq r2,r9 + bf 1f +#if STRUCT_VALUE_ADDRESS_WITH_ARG + mov.l @r15+,r4 + bra 2f + mov #5,r2 +#else + mov.l @r15+,r10 +#endif +1: + mov #4,r2 +2: + +L_pass: + cmp/pl r8 + bf L_call_it + + mov r3,r0 + and #3,r0 + +L_pass_d: + cmp/eq #FFI_TYPE_DOUBLE,r0 + bf L_pass_i + + mov r15,r0 + and #7,r0 + tst r0,r0 + bt 1f + add #4,r15 +1: + mov #8,r0 + cmp/hs r0,r2 + bt/s 2f + shlr2 r3 + bsr L_pop_d + nop +2: + add #2,r2 + bra L_pass + add #-8,r8 + +L_pop_d: + mov r2,r0 + add r0,r0 + add r2,r0 + add #-12,r0 + add r0,r0 + braf r0 + nop + mov.l @r15+,r4 + rts + mov.l @r15+,r5 + mov.l @r15+,r5 + rts + mov.l @r15+,r6 + mov.l @r15+,r6 + rts + mov.l @r15+,r7 + rts + mov.l @r15+,r7 + +L_pass_i: + cmp/eq #FFI_TYPE_INT,r0 + bf L_call_it + + mov #8,r0 + cmp/hs r0,r2 + bt/s 2f + shlr2 r3 + bsr L_pop_i + nop +2: + add #1,r2 + bra L_pass + add #-4,r8 + +L_pop_i: + mov r2,r0 + shll2 r0 + add #-16,r0 + braf r0 + nop + rts + mov.l @r15+,r4 + rts + mov.l @r15+,r5 + rts + mov.l @r15+,r6 + rts + mov.l @r15+,r7 + +L_call_it: + # call function +#if (! STRUCT_VALUE_ADDRESS_WITH_ARG) + mov r10, r2 +#endif + mov.l @(28,r14),r1 + jsr @r1 + nop + +L_ret_d: + mov #FFI_TYPE_DOUBLE,r2 + cmp/eq r2,r9 + bf L_ret_ll + + mov.l @(24,r14),r2 + mov.l r0,@r2 + bra L_epilogue + mov.l r1,@(4,r2) + +L_ret_ll: + mov #FFI_TYPE_SINT64,r2 + cmp/eq r2,r9 + bt/s 1f + mov #FFI_TYPE_UINT64,r2 + cmp/eq r2,r9 + bf L_ret_i + +1: + mov.l @(24,r14),r2 + mov.l r0,@r2 + bra L_epilogue + mov.l r1,@(4,r2) + +L_ret_i: + mov #FFI_TYPE_FLOAT,r2 + cmp/eq r2,r9 + bt 1f + mov #FFI_TYPE_INT,r2 + cmp/eq r2,r9 + bf L_epilogue +1: + mov.l @(24,r14),r1 + bra L_epilogue + mov.l r0,@r1 + +L_epilogue: + # Remove the space we pushed for the args + mov r14,r15 + + lds.l @r15+,pr + mov.l @r15+,r14 + mov.l @r15+,r12 + mov.l @r15+,r10 + mov.l @r15+,r9 + rts + mov.l @r15+,r8 +#endif +.LFE1: +.ffi_call_SYSV_end: + .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) + +.globl ffi_closure_helper_SYSV + +ENTRY(ffi_closure_SYSV) +.LFB2: + mov.l r7,@-r15 +.LCFI7: + mov.l r6,@-r15 +.LCFI8: + mov.l r5,@-r15 +.LCFI9: + mov.l r4,@-r15 +.LCFIA: + mov.l r14,@-r15 +.LCFIB: + sts.l pr,@-r15 + + /* Stack layout: + xx bytes (on stack parameters) + 16 bytes (register parameters) + 4 bytes (saved frame pointer) + 4 bytes (saved return address) + 32 bytes (floating register parameters, SH-4 only) + 8 bytes (result) + 4 bytes (pad) + 4 bytes (5th arg) + <- new stack pointer + */ +.LCFIC: +#if defined(__SH4__) + add #-48,r15 +#else + add #-16,r15 +#endif +.LCFID: + mov r15,r14 +.LCFIE: + +#if defined(__SH4__) + mov r14,r1 + add #48,r1 +#ifdef __LITTLE_ENDIAN__ + fmov.s fr10,@-r1 + fmov.s fr11,@-r1 + fmov.s fr8,@-r1 + fmov.s fr9,@-r1 + fmov.s fr6,@-r1 + fmov.s fr7,@-r1 + fmov.s fr4,@-r1 + fmov.s fr5,@-r1 +#else + fmov.s fr11,@-r1 + fmov.s fr10,@-r1 + fmov.s fr9,@-r1 + fmov.s fr8,@-r1 + fmov.s fr7,@-r1 + fmov.s fr6,@-r1 + fmov.s fr5,@-r1 + fmov.s fr4,@-r1 +#endif + mov r1,r7 + mov r14,r6 + add #56,r6 +#else + mov r14,r6 + add #24,r6 +#endif + + bt/s 10f + mov r2, r5 + mov r14,r1 + add #8,r1 + mov r1,r5 +10: + + mov r14,r1 +#if defined(__SH4__) + add #72,r1 +#else + add #40,r1 +#endif + mov.l r1,@r14 + +#ifdef PIC + mov.l L_got,r1 + mova L_got,r0 + add r0,r1 + mov.l L_helper,r0 + add r1,r0 +#else + mov.l L_helper,r0 +#endif + jsr @r0 + mov r3,r4 + + shll r0 + mov r0,r1 + mova L_table,r0 + add r1,r0 + mov.w @r0,r0 + mov r14,r2 + braf r0 + add #8,r2 +0: + .align 2 +#ifdef PIC +L_got: + .long _GLOBAL_OFFSET_TABLE_ +L_helper: + .long ffi_closure_helper_SYSV@GOTOFF +#else +L_helper: + .long ffi_closure_helper_SYSV +#endif +L_table: + .short L_case_v - 0b /* FFI_TYPE_VOID */ + .short L_case_i - 0b /* FFI_TYPE_INT */ +#if defined(__SH4__) + .short L_case_f - 0b /* FFI_TYPE_FLOAT */ + .short L_case_d - 0b /* FFI_TYPE_DOUBLE */ + .short L_case_d - 0b /* FFI_TYPE_LONGDOUBLE */ +#else + .short L_case_i - 0b /* FFI_TYPE_FLOAT */ + .short L_case_ll - 0b /* FFI_TYPE_DOUBLE */ + .short L_case_ll - 0b /* FFI_TYPE_LONGDOUBLE */ +#endif + .short L_case_uq - 0b /* FFI_TYPE_UINT8 */ + .short L_case_q - 0b /* FFI_TYPE_SINT8 */ + .short L_case_uh - 0b /* FFI_TYPE_UINT16 */ + .short L_case_h - 0b /* FFI_TYPE_SINT16 */ + .short L_case_i - 0b /* FFI_TYPE_UINT32 */ + .short L_case_i - 0b /* FFI_TYPE_SINT32 */ + .short L_case_ll - 0b /* FFI_TYPE_UINT64 */ + .short L_case_ll - 0b /* FFI_TYPE_SINT64 */ + .short L_case_v - 0b /* FFI_TYPE_STRUCT */ + .short L_case_i - 0b /* FFI_TYPE_POINTER */ + +#if defined(__SH4__) +L_case_d: +#ifdef __LITTLE_ENDIAN__ + fmov.s @r2+,fr1 + bra L_case_v + fmov.s @r2,fr0 +#else + fmov.s @r2+,fr0 + bra L_case_v + fmov.s @r2,fr1 +#endif + +L_case_f: + bra L_case_v + fmov.s @r2,fr0 +#endif + +L_case_ll: + mov.l @r2+,r0 + bra L_case_v + mov.l @r2,r1 + +L_case_i: + bra L_case_v + mov.l @r2,r0 + +L_case_q: +#ifdef __LITTLE_ENDIAN__ +#else + add #3,r2 +#endif + bra L_case_v + mov.b @r2,r0 + +L_case_uq: +#ifdef __LITTLE_ENDIAN__ +#else + add #3,r2 +#endif + mov.b @r2,r0 + bra L_case_v + extu.b r0,r0 + +L_case_h: +#ifdef __LITTLE_ENDIAN__ +#else + add #2,r2 +#endif + bra L_case_v + mov.w @r2,r0 + +L_case_uh: +#ifdef __LITTLE_ENDIAN__ +#else + add #2,r2 +#endif + mov.w @r2,r0 + extu.w r0,r0 + /* fall through */ + +L_case_v: +#if defined(__SH4__) + add #48,r15 +#else + add #16,r15 +#endif + lds.l @r15+,pr + mov.l @r15+,r14 + rts + add #16,r15 +.LFE2: +.ffi_closure_SYSV_end: + .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif + + .section ".eh_frame","aw",@progbits +__FRAME_BEGIN__: + .4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */ +.LSCIE1: + .4byte 0x0 /* CIE Identifier Tag */ + .byte 0x1 /* CIE Version */ +#ifdef PIC + .ascii "zR\0" /* CIE Augmentation */ +#else + .byte 0x0 /* CIE Augmentation */ +#endif + .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */ + .byte 0x7c /* sleb128 -4; CIE Data Alignment Factor */ + .byte 0x11 /* CIE RA Column */ +#ifdef PIC + .uleb128 0x1 /* Augmentation size */ + .byte 0x10 /* FDE Encoding (pcrel) */ +#endif + .byte 0xc /* DW_CFA_def_cfa */ + .byte 0xf /* uleb128 0xf */ + .byte 0x0 /* uleb128 0x0 */ + .align 2 +.LECIE1: +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 /* FDE Length */ +.LASFDE1: + .4byte .LASFDE1-__FRAME_BEGIN__ /* FDE CIE offset */ +#ifdef PIC + .4byte .LFB1-. /* FDE initial location */ +#else + .4byte .LFB1 /* FDE initial location */ +#endif + .4byte .LFE1-.LFB1 /* FDE address range */ +#ifdef PIC + .uleb128 0x0 /* Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI0-.LFB1 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x4 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI1-.LCFI0 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI2-.LCFI1 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0xc /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI3-.LCFI2 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x10 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI4-.LCFI3 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x14 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI5-.LCFI4 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x18 /* uleb128 0x4 */ + .byte 0x91 /* DW_CFA_offset, column 0x11 */ + .byte 0x6 /* uleb128 0x6 */ + .byte 0x8e /* DW_CFA_offset, column 0xe */ + .byte 0x5 /* uleb128 0x5 */ + .byte 0x8c /* DW_CFA_offset, column 0xc */ + .byte 0x4 /* uleb128 0x4 */ + .byte 0x8a /* DW_CFA_offset, column 0xa */ + .byte 0x3 /* uleb128 0x3 */ + .byte 0x89 /* DW_CFA_offset, column 0x9 */ + .byte 0x2 /* uleb128 0x2 */ + .byte 0x88 /* DW_CFA_offset, column 0x8 */ + .byte 0x1 /* uleb128 0x1 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI6-.LCFI5 + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0xe /* uleb128 0xe */ + .align 2 +.LEFDE1: + +.LSFDE3: + .4byte .LEFDE3-.LASFDE3 /* FDE Length */ +.LASFDE3: + .4byte .LASFDE3-__FRAME_BEGIN__ /* FDE CIE offset */ +#ifdef PIC + .4byte .LFB2-. /* FDE initial location */ +#else + .4byte .LFB2 /* FDE initial location */ +#endif + .4byte .LFE2-.LFB2 /* FDE address range */ +#ifdef PIC + .uleb128 0x0 /* Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI7-.LFB2 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x4 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI8-.LCFI7 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI9-.LCFI8 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0xc /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFIA-.LCFI9 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x10 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFIB-.LCFIA + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x14 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFIC-.LCFIB + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x18 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFID-.LCFIC + .byte 0xe /* DW_CFA_def_cfa_offset */ +#if defined(__SH4__) + .byte 24+48 /* uleb128 24+48 */ +#else + .byte 24+16 /* uleb128 24+16 */ +#endif + .byte 0x91 /* DW_CFA_offset, column 0x11 */ + .byte 0x6 /* uleb128 0x6 */ + .byte 0x8e /* DW_CFA_offset, column 0xe */ + .byte 0x5 /* uleb128 0x5 */ + .byte 0x84 /* DW_CFA_offset, column 0x4 */ + .byte 0x4 /* uleb128 0x4 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 */ + .byte 0x3 /* uleb128 0x3 */ + .byte 0x86 /* DW_CFA_offset, column 0x6 */ + .byte 0x2 /* uleb128 0x2 */ + .byte 0x87 /* DW_CFA_offset, column 0x7 */ + .byte 0x1 /* uleb128 0x1 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFIE-.LCFID + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0xe /* uleb128 0xe */ + .align 2 +.LEFDE3: diff --git a/js/src/ctypes/libffi/src/sh64/ffi.c b/js/src/ctypes/libffi/src/sh64/ffi.c new file mode 100644 index 0000000..8fbc05c --- /dev/null +++ b/js/src/ctypes/libffi/src/sh64/ffi.c @@ -0,0 +1,468 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2003, 2004, 2006, 2007 Kaz Kojima + Copyright (c) 2008 Anthony Green + + SuperH SHmedia Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include + +#define NGREGARG 8 +#define NFREGARG 12 + +static int +return_type (ffi_type *arg) +{ + + if (arg->type != FFI_TYPE_STRUCT) + return arg->type; + + /* gcc uses r2 if the result can be packed in on register. */ + if (arg->size <= sizeof (UINT8)) + return FFI_TYPE_UINT8; + else if (arg->size <= sizeof (UINT16)) + return FFI_TYPE_UINT16; + else if (arg->size <= sizeof (UINT32)) + return FFI_TYPE_UINT32; + else if (arg->size <= sizeof (UINT64)) + return FFI_TYPE_UINT64; + + return FFI_TYPE_STRUCT; +} + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +void ffi_prep_args(char *stack, extended_cif *ecif) +{ + register unsigned int i; + register unsigned int avn; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT) + { + *(void **) argp = ecif->rvalue; + argp += sizeof (UINT64); + } + + avn = ecif->cif->nargs; + p_argv = ecif->avalue; + + for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++) + { + size_t z; + int align; + + z = (*p_arg)->size; + align = (*p_arg)->alignment; + if (z < sizeof (UINT32)) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv); + break; + + case FFI_TYPE_UINT8: + *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv); + break; + + case FFI_TYPE_SINT16: + *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv); + break; + + case FFI_TYPE_UINT16: + *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv); + break; + + case FFI_TYPE_STRUCT: + memcpy (argp, *p_argv, z); + break; + + default: + FFI_ASSERT(0); + } + argp += sizeof (UINT64); + } + else if (z == sizeof (UINT32) && align == sizeof (UINT32)) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv); + break; + + case FFI_TYPE_FLOAT: + case FFI_TYPE_POINTER: + case FFI_TYPE_UINT32: + case FFI_TYPE_STRUCT: + *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv); + break; + + default: + FFI_ASSERT(0); + break; + } + argp += sizeof (UINT64); + } + else if (z == sizeof (UINT64) + && align == sizeof (UINT64) + && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0) + { + *(UINT64 *) argp = *(UINT64 *) (*p_argv); + argp += sizeof (UINT64); + } + else + { + int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64); + + memcpy (argp, *p_argv, z); + argp += n * sizeof (UINT64); + } + } + + return; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + int i, j; + int size, type; + int n, m; + int greg; + int freg; + int fpair = -1; + + greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0); + freg = 0; + cif->flags2 = 0; + + for (i = j = 0; i < cif->nargs; i++) + { + type = (cif->arg_types)[i]->type; + switch (type) + { + case FFI_TYPE_FLOAT: + greg++; + cif->bytes += sizeof (UINT64) - sizeof (float); + if (freg >= NFREGARG - 1) + continue; + if (fpair < 0) + { + fpair = freg; + freg += 2; + } + else + fpair = -1; + cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++); + break; + + case FFI_TYPE_DOUBLE: + if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG) + continue; + if ((freg + 1) < NFREGARG) + { + freg += 2; + cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++); + } + else + cif->flags2 += FFI_TYPE_INT << (2 * j++); + break; + + default: + size = (cif->arg_types)[i]->size; + if (size < sizeof (UINT64)) + cif->bytes += sizeof (UINT64) - size; + n = (size + sizeof (UINT64) - 1) / sizeof (UINT64); + if (greg >= NGREGARG) + continue; + else if (greg + n - 1 >= NGREGARG) + greg = NGREGARG; + else + greg += n; + for (m = 0; m < n; m++) + cif->flags2 += FFI_TYPE_INT << (2 * j++); + break; + } + } + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_STRUCT: + cif->flags = return_type (cif->rtype); + break; + + case FFI_TYPE_VOID: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags = cif->rtype->type; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_SYSV(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, long long, + /*@out@*/ unsigned *, + void (*fn)(void)); +/*@=declundef@*/ +/*@=exportheader@*/ + +void ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(void), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + UINT64 trvalue; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if (cif->rtype->type == FFI_TYPE_STRUCT + && return_type (cif->rtype) != FFI_TYPE_STRUCT) + ecif.rvalue = &trvalue; + else if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + ecif.rvalue = alloca(cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: + ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, cif->flags2, + ecif.rvalue, fn); + break; + default: + FFI_ASSERT(0); + break; + } + + if (rvalue + && cif->rtype->type == FFI_TYPE_STRUCT + && return_type (cif->rtype) != FFI_TYPE_STRUCT) + memcpy (rvalue, &trvalue, cif->rtype->size); +} + +extern void ffi_closure_SYSV (void); +extern void __ic_invalidate (void *line); + +ffi_status +ffi_prep_closure_loc (ffi_closure *closure, + ffi_cif *cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc) +{ + unsigned int *tramp; + + FFI_ASSERT (cif->abi == FFI_GCC_SYSV); + + tramp = (unsigned int *) &closure->tramp[0]; + /* Since ffi_closure is an aligned object, the ffi trampoline is + called as an SHcompact code. Sigh. + SHcompact part: + mova @(1,pc),r0; add #1,r0; jmp @r0; nop; + SHmedia part: + movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0 + movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */ +#ifdef __LITTLE_ENDIAN__ + tramp[0] = 0x7001c701; + tramp[1] = 0x0009402b; +#else + tramp[0] = 0xc7017001; + tramp[1] = 0x402b0009; +#endif + tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10; + tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10; + tramp[4] = 0x6bf10600; + tramp[5] = 0xcc000010 | (((UINT32) codeloc) >> 16) << 10; + tramp[6] = 0xc8000010 | (((UINT32) codeloc) & 0xffff) << 10; + tramp[7] = 0x4401fff0; + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* Flush the icache. */ + asm volatile ("ocbwb %0,0; synco; icbi %1,0; synci" : : "r" (tramp), + "r"(codeloc)); + + return FFI_OK; +} + +/* Basically the trampoline invokes ffi_closure_SYSV, and on + * entry, r3 holds the address of the closure. + * After storing the registers that could possibly contain + * parameters to be passed into the stack frame and setting + * up space for a return value, ffi_closure_SYSV invokes the + * following helper function to do most of the work. + */ + +int +ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue, + UINT64 *pgr, UINT64 *pfr, UINT64 *pst) +{ + void **avalue; + ffi_type **p_arg; + int i, avn; + int greg, freg; + ffi_cif *cif; + int fpair = -1; + + cif = closure->cif; + avalue = alloca (cif->nargs * sizeof (void *)); + + /* Copy the caller's structure return value address so that the closure + returns the data directly to the caller. */ + if (return_type (cif->rtype) == FFI_TYPE_STRUCT) + { + rvalue = (UINT64 *) *pgr; + greg = 1; + } + else + greg = 0; + + freg = 0; + cif = closure->cif; + avn = cif->nargs; + + /* Grab the addresses of the arguments from the stack frame. */ + for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) + { + size_t z; + void *p; + + z = (*p_arg)->size; + if (z < sizeof (UINT32)) + { + p = pgr + greg++; + + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_STRUCT: +#ifdef __LITTLE_ENDIAN__ + avalue[i] = p; +#else + avalue[i] = ((char *) p) + sizeof (UINT32) - z; +#endif + break; + + default: + FFI_ASSERT(0); + } + } + else if (z == sizeof (UINT32)) + { + if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + if (freg < NFREGARG - 1) + { + if (fpair >= 0) + { + avalue[i] = (UINT32 *) pfr + fpair; + fpair = -1; + } + else + { +#ifdef __LITTLE_ENDIAN__ + fpair = freg; + avalue[i] = (UINT32 *) pfr + (1 ^ freg); +#else + fpair = 1 ^ freg; + avalue[i] = (UINT32 *) pfr + freg; +#endif + freg += 2; + } + } + else +#ifdef __LITTLE_ENDIAN__ + avalue[i] = pgr + greg; +#else + avalue[i] = (UINT32 *) (pgr + greg) + 1; +#endif + } + else +#ifdef __LITTLE_ENDIAN__ + avalue[i] = pgr + greg; +#else + avalue[i] = (UINT32 *) (pgr + greg) + 1; +#endif + greg++; + } + else if ((*p_arg)->type == FFI_TYPE_DOUBLE) + { + if (freg + 1 >= NFREGARG) + avalue[i] = pgr + greg; + else + { + avalue[i] = pfr + (freg >> 1); + freg += 2; + } + greg++; + } + else + { + int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64); + + avalue[i] = pgr + greg; + greg += n; + } + } + + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_SYSV how to perform return type promotions. */ + return return_type (cif->rtype); +} + diff --git a/js/src/ctypes/libffi/src/sh64/ffitarget.h b/js/src/ctypes/libffi/src/sh64/ffitarget.h new file mode 100644 index 0000000..d935b89 --- /dev/null +++ b/js/src/ctypes/libffi/src/sh64/ffitarget.h @@ -0,0 +1,53 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for SuperH - SHmedia. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- Generic type definitions ----------------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_SYSV +} ffi_abi; + +#define FFI_EXTRA_CIF_FIELDS long long flags2 +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 32 +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/js/src/ctypes/libffi/src/sh64/sysv.S b/js/src/ctypes/libffi/src/sh64/sysv.S new file mode 100644 index 0000000..c4587d5 --- /dev/null +++ b/js/src/ctypes/libffi/src/sh64/sysv.S @@ -0,0 +1,539 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2003, 2004, 2006, 2008 Kaz Kojima + + SuperH SHmedia Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include +#ifdef HAVE_MACHINE_ASM_H +#include +#else +/* XXX these lose for some platforms, I'm sure. */ +#define CNAME(x) x +#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): +#endif + +#ifdef __LITTLE_ENDIAN__ +#define OFS_FLT 0 +#else +#define OFS_FLT 4 +#endif + + .section .text..SHmedia32,"ax" + + # r2: ffi_prep_args + # r3: &ecif + # r4: bytes + # r5: flags + # r6: flags2 + # r7: rvalue + # r8: fn + + # This assumes we are using gas. + .align 5 +ENTRY(ffi_call_SYSV) + # Save registers +.LFB1: + addi.l r15, -48, r15 +.LCFI0: + st.q r15, 40, r32 + st.q r15, 32, r31 + st.q r15, 24, r30 + st.q r15, 16, r29 + st.q r15, 8, r28 + st.l r15, 4, r18 + st.l r15, 0, r14 +.LCFI1: + add.l r15, r63, r14 +.LCFI2: +# add r4, r63, r28 + add r5, r63, r29 + add r6, r63, r30 + add r7, r63, r31 + add r8, r63, r32 + + addi r4, (64 + 7), r4 + andi r4, ~7, r4 + sub.l r15, r4, r15 + + ptabs/l r2, tr0 + add r15, r63, r2 + blink tr0, r18 + + addi r15, 64, r22 + movi 0, r0 + movi 0, r1 + movi -1, r23 + + pt/l 1f, tr1 + bnei/l r29, FFI_TYPE_STRUCT, tr1 + ld.l r15, 0, r19 + addi r15, 8, r15 + addi r0, 1, r0 +1: + +.L_pass: + andi r30, 3, r20 + shlri r30, 2, r30 + + pt/l .L_call_it, tr0 + pt/l .L_pass_i, tr1 + pt/l .L_pass_f, tr2 + + beqi/l r20, FFI_TYPE_VOID, tr0 + beqi/l r20, FFI_TYPE_INT, tr1 + beqi/l r20, FFI_TYPE_FLOAT, tr2 + +.L_pass_d: + addi r0, 1, r0 + pt/l 3f, tr0 + movi 12, r20 + bge/l r1, r20, tr0 + + pt/l .L_pop_d, tr1 + pt/l 2f, tr0 + blink tr1, r63 +2: + addi.l r15, 8, r15 +3: + pt/l .L_pass, tr0 + addi r1, 2, r1 + blink tr0, r63 + +.L_pop_d: + pt/l .L_pop_d_tbl, tr1 + gettr tr1, r20 + shlli r1, 2, r21 + add r20, r21, r20 + ptabs/l r20, tr1 + blink tr1, r63 + +.L_pop_d_tbl: + fld.d r15, 0, dr0 + blink tr0, r63 + fld.d r15, 0, dr2 + blink tr0, r63 + fld.d r15, 0, dr4 + blink tr0, r63 + fld.d r15, 0, dr6 + blink tr0, r63 + fld.d r15, 0, dr8 + blink tr0, r63 + fld.d r15, 0, dr10 + blink tr0, r63 + +.L_pass_f: + addi r0, 1, r0 + pt/l 3f, tr0 + movi 12, r20 + bge/l r1, r20, tr0 + + pt/l .L_pop_f, tr1 + pt/l 2f, tr0 + blink tr1, r63 +2: + addi.l r15, 8, r15 +3: + pt/l .L_pass, tr0 + blink tr0, r63 + +.L_pop_f: + pt/l .L_pop_f_tbl, tr1 + pt/l 5f, tr2 + gettr tr1, r20 + bge/l r23, r63, tr2 + add r1, r63, r23 + shlli r1, 3, r21 + addi r1, 2, r1 + add r20, r21, r20 + ptabs/l r20, tr1 + blink tr1, r63 +5: + addi r23, 1, r21 + movi -1, r23 + shlli r21, 3, r21 + add r20, r21, r20 + ptabs/l r20, tr1 + blink tr1, r63 + +.L_pop_f_tbl: + fld.s r15, OFS_FLT, fr0 + blink tr0, r63 + fld.s r15, OFS_FLT, fr1 + blink tr0, r63 + fld.s r15, OFS_FLT, fr2 + blink tr0, r63 + fld.s r15, OFS_FLT, fr3 + blink tr0, r63 + fld.s r15, OFS_FLT, fr4 + blink tr0, r63 + fld.s r15, OFS_FLT, fr5 + blink tr0, r63 + fld.s r15, OFS_FLT, fr6 + blink tr0, r63 + fld.s r15, OFS_FLT, fr7 + blink tr0, r63 + fld.s r15, OFS_FLT, fr8 + blink tr0, r63 + fld.s r15, OFS_FLT, fr9 + blink tr0, r63 + fld.s r15, OFS_FLT, fr10 + blink tr0, r63 + fld.s r15, OFS_FLT, fr11 + blink tr0, r63 + +.L_pass_i: + pt/l 3f, tr0 + movi 8, r20 + bge/l r0, r20, tr0 + + pt/l .L_pop_i, tr1 + pt/l 2f, tr0 + blink tr1, r63 +2: + addi.l r15, 8, r15 +3: + pt/l .L_pass, tr0 + addi r0, 1, r0 + blink tr0, r63 + +.L_pop_i: + pt/l .L_pop_i_tbl, tr1 + gettr tr1, r20 + shlli r0, 3, r21 + add r20, r21, r20 + ptabs/l r20, tr1 + blink tr1, r63 + +.L_pop_i_tbl: + ld.q r15, 0, r2 + blink tr0, r63 + ld.q r15, 0, r3 + blink tr0, r63 + ld.q r15, 0, r4 + blink tr0, r63 + ld.q r15, 0, r5 + blink tr0, r63 + ld.q r15, 0, r6 + blink tr0, r63 + ld.q r15, 0, r7 + blink tr0, r63 + ld.q r15, 0, r8 + blink tr0, r63 + ld.q r15, 0, r9 + blink tr0, r63 + +.L_call_it: + # call function + pt/l 1f, tr1 + bnei/l r29, FFI_TYPE_STRUCT, tr1 + add r19, r63, r2 +1: + add r22, r63, r15 + ptabs/l r32, tr0 + blink tr0, r18 + + pt/l .L_ret_i, tr0 + pt/l .L_ret_ll, tr1 + pt/l .L_ret_d, tr2 + pt/l .L_ret_f, tr3 + pt/l .L_epilogue, tr4 + + beqi/l r29, FFI_TYPE_INT, tr0 + beqi/l r29, FFI_TYPE_UINT32, tr0 + beqi/l r29, FFI_TYPE_SINT64, tr1 + beqi/l r29, FFI_TYPE_UINT64, tr1 + beqi/l r29, FFI_TYPE_DOUBLE, tr2 + beqi/l r29, FFI_TYPE_FLOAT, tr3 + + pt/l .L_ret_q, tr0 + pt/l .L_ret_h, tr1 + + beqi/l r29, FFI_TYPE_UINT8, tr0 + beqi/l r29, FFI_TYPE_UINT16, tr1 + blink tr4, r63 + +.L_ret_d: + fst.d r31, 0, dr0 + blink tr4, r63 + +.L_ret_ll: + st.q r31, 0, r2 + blink tr4, r63 + +.L_ret_f: + fst.s r31, OFS_FLT, fr0 + blink tr4, r63 + +.L_ret_q: + st.b r31, 0, r2 + blink tr4, r63 + +.L_ret_h: + st.w r31, 0, r2 + blink tr4, r63 + +.L_ret_i: + st.l r31, 0, r2 + # Fall + +.L_epilogue: + # Remove the space we pushed for the args + add r14, r63, r15 + + ld.l r15, 0, r14 + ld.l r15, 4, r18 + ld.q r15, 8, r28 + ld.q r15, 16, r29 + ld.q r15, 24, r30 + ld.q r15, 32, r31 + ld.q r15, 40, r32 + addi.l r15, 48, r15 + ptabs r18, tr0 + blink tr0, r63 + +.LFE1: +.ffi_call_SYSV_end: + .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) + + .align 5 +ENTRY(ffi_closure_SYSV) +.LFB2: + addi.l r15, -136, r15 +.LCFI3: + st.l r15, 12, r18 + st.l r15, 8, r14 + st.l r15, 4, r12 +.LCFI4: + add r15, r63, r14 +.LCFI5: + /* Stack layout: + ... + 64 bytes (register parameters) + 48 bytes (floating register parameters) + 8 bytes (result) + 4 bytes (r18) + 4 bytes (r14) + 4 bytes (r12) + 4 bytes (for align) + <- new stack pointer + */ + fst.d r14, 24, dr0 + fst.d r14, 32, dr2 + fst.d r14, 40, dr4 + fst.d r14, 48, dr6 + fst.d r14, 56, dr8 + fst.d r14, 64, dr10 + st.q r14, 72, r2 + st.q r14, 80, r3 + st.q r14, 88, r4 + st.q r14, 96, r5 + st.q r14, 104, r6 + st.q r14, 112, r7 + st.q r14, 120, r8 + st.q r14, 128, r9 + + add r1, r63, r2 + addi r14, 16, r3 + addi r14, 72, r4 + addi r14, 24, r5 + addi r14, 136, r6 +#ifdef PIC + movi (((datalabel _GLOBAL_OFFSET_TABLE_-(.LPCS0-.)) >> 16) & 65535), r12 + shori ((datalabel _GLOBAL_OFFSET_TABLE_-(.LPCS0-.)) & 65535), r12 +.LPCS0: ptrel/u r12, tr0 + movi ((ffi_closure_helper_SYSV@GOTPLT) & 65535), r1 + gettr tr0, r12 + ldx.l r1, r12, r1 + ptabs r1, tr0 +#else + pt/l ffi_closure_helper_SYSV, tr0 +#endif + blink tr0, r18 + + shlli r2, 1, r1 + movi (((datalabel .L_table) >> 16) & 65535), r2 + shori ((datalabel .L_table) & 65535), r2 + ldx.w r2, r1, r1 + add r1, r2, r1 + pt/l .L_case_v, tr1 + ptabs r1, tr0 + blink tr0, r63 + + .align 2 +.L_table: + .word .L_case_v - datalabel .L_table /* FFI_TYPE_VOID */ + .word .L_case_i - datalabel .L_table /* FFI_TYPE_INT */ + .word .L_case_f - datalabel .L_table /* FFI_TYPE_FLOAT */ + .word .L_case_d - datalabel .L_table /* FFI_TYPE_DOUBLE */ + .word .L_case_d - datalabel .L_table /* FFI_TYPE_LONGDOUBLE */ + .word .L_case_uq - datalabel .L_table /* FFI_TYPE_UINT8 */ + .word .L_case_q - datalabel .L_table /* FFI_TYPE_SINT8 */ + .word .L_case_uh - datalabel .L_table /* FFI_TYPE_UINT16 */ + .word .L_case_h - datalabel .L_table /* FFI_TYPE_SINT16 */ + .word .L_case_i - datalabel .L_table /* FFI_TYPE_UINT32 */ + .word .L_case_i - datalabel .L_table /* FFI_TYPE_SINT32 */ + .word .L_case_ll - datalabel .L_table /* FFI_TYPE_UINT64 */ + .word .L_case_ll - datalabel .L_table /* FFI_TYPE_SINT64 */ + .word .L_case_v - datalabel .L_table /* FFI_TYPE_STRUCT */ + .word .L_case_i - datalabel .L_table /* FFI_TYPE_POINTER */ + + .align 2 +.L_case_d: + fld.d r14, 16, dr0 + blink tr1, r63 +.L_case_f: + fld.s r14, 16, fr0 + blink tr1, r63 +.L_case_ll: + ld.q r14, 16, r2 + blink tr1, r63 +.L_case_i: + ld.l r14, 16, r2 + blink tr1, r63 +.L_case_q: + ld.b r14, 16, r2 + blink tr1, r63 +.L_case_uq: + ld.ub r14, 16, r2 + blink tr1, r63 +.L_case_h: + ld.w r14, 16, r2 + blink tr1, r63 +.L_case_uh: + ld.uw r14, 16, r2 + blink tr1, r63 +.L_case_v: + add.l r14, r63, r15 + ld.l r15, 4, r12 + ld.l r15, 8, r14 + ld.l r15, 12, r18 + addi.l r15, 136, r15 + ptabs r18, tr0 + blink tr0, r63 + +.LFE2: +.ffi_closure_SYSV_end: + .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif + + .section ".eh_frame","aw",@progbits +__FRAME_BEGIN__: + .4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */ +.LSCIE1: + .4byte 0x0 /* CIE Identifier Tag */ + .byte 0x1 /* CIE Version */ +#ifdef PIC + .ascii "zR\0" /* CIE Augmentation */ +#else + .byte 0x0 /* CIE Augmentation */ +#endif + .uleb128 0x1 /* CIE Code Alignment Factor */ + .sleb128 -4 /* CIE Data Alignment Factor */ + .byte 0x12 /* CIE RA Column */ +#ifdef PIC + .uleb128 0x1 /* Augmentation size */ + .byte 0x10 /* FDE Encoding (pcrel) */ +#endif + .byte 0xc /* DW_CFA_def_cfa */ + .uleb128 0xf + .uleb128 0x0 + .align 2 +.LECIE1: +.LSFDE1: + .4byte datalabel .LEFDE1-datalabel .LASFDE1 /* FDE Length */ +.LASFDE1: + .4byte datalabel .LASFDE1-datalabel __FRAME_BEGIN__ +#ifdef PIC + .4byte .LFB1-. /* FDE initial location */ +#else + .4byte .LFB1 /* FDE initial location */ +#endif + .4byte datalabel .LFE1-datalabel .LFB1 /* FDE address range */ +#ifdef PIC + .uleb128 0x0 /* Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte datalabel .LCFI0-datalabel .LFB1 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .uleb128 0x30 + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte datalabel .LCFI1-datalabel .LCFI0 + .byte 0x8e /* DW_CFA_offset, column 0xe */ + .uleb128 0xc + .byte 0x92 /* DW_CFA_offset, column 0x12 */ + .uleb128 0xb + .byte 0x9c /* DW_CFA_offset, column 0x1c */ + .uleb128 0xa + .byte 0x9d /* DW_CFA_offset, column 0x1d */ + .uleb128 0x8 + .byte 0x9e /* DW_CFA_offset, column 0x1e */ + .uleb128 0x6 + .byte 0x9f /* DW_CFA_offset, column 0x1f */ + .uleb128 0x4 + .byte 0xa0 /* DW_CFA_offset, column 0x20 */ + .uleb128 0x2 + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte datalabel .LCFI2-datalabel .LCFI1 + .byte 0xd /* DW_CFA_def_cfa_register */ + .uleb128 0xe + .align 2 +.LEFDE1: + +.LSFDE3: + .4byte datalabel .LEFDE3-datalabel .LASFDE3 /* FDE Length */ +.LASFDE3: + .4byte datalabel .LASFDE3-datalabel __FRAME_BEGIN__ +#ifdef PIC + .4byte .LFB2-. /* FDE initial location */ +#else + .4byte .LFB2 /* FDE initial location */ +#endif + .4byte datalabel .LFE2-datalabel .LFB2 /* FDE address range */ +#ifdef PIC + .uleb128 0x0 /* Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte datalabel .LCFI3-datalabel .LFB2 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .uleb128 0x88 + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte datalabel .LCFI4-datalabel .LCFI3 + .byte 0x8c /* DW_CFA_offset, column 0xc */ + .uleb128 0x21 + .byte 0x8e /* DW_CFA_offset, column 0xe */ + .uleb128 0x20 + .byte 0x92 /* DW_CFA_offset, column 0x12 */ + .uleb128 0x1f + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte datalabel .LCFI5-datalabel .LCFI4 + .byte 0xd /* DW_CFA_def_cfa_register */ + .uleb128 0xe + .align 2 +.LEFDE3: diff --git a/js/src/ctypes/libffi/src/sparc/ffi.c b/js/src/ctypes/libffi/src/sparc/ffi.c new file mode 100644 index 0000000..1d01f59 --- /dev/null +++ b/js/src/ctypes/libffi/src/sparc/ffi.c @@ -0,0 +1,625 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1996, 2003, 2004, 2007, 2008 Red Hat, Inc. + + SPARC Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include + + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +void ffi_prep_args_v8(char *stack, extended_cif *ecif) +{ + int i; + void **p_argv; + char *argp; + ffi_type **p_arg; + + /* Skip 16 words for the window save area */ + argp = stack + 16*sizeof(int); + + /* This should only really be done when we are returning a structure, + however, it's faster just to do it all the time... + + if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */ + *(int *) argp = (long)ecif->rvalue; + + /* And 1 word for the structure return value. */ + argp += sizeof(int); + +#ifdef USING_PURIFY + /* Purify will probably complain in our assembly routine, unless we + zero out this memory. */ + + ((int*)argp)[0] = 0; + ((int*)argp)[1] = 0; + ((int*)argp)[2] = 0; + ((int*)argp)[3] = 0; + ((int*)argp)[4] = 0; + ((int*)argp)[5] = 0; +#endif + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++) + { + size_t z; + + if ((*p_arg)->type == FFI_TYPE_STRUCT +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + || (*p_arg)->type == FFI_TYPE_LONGDOUBLE +#endif + ) + { + *(unsigned int *) argp = (unsigned long)(* p_argv); + z = sizeof(int); + } + else + { + z = (*p_arg)->size; + if (z < sizeof(int)) + { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = *(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = *(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = *(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = *(UINT16 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + } + else + { + memcpy(argp, *p_argv, z); + } + } + p_argv++; + argp += z; + } + + return; +} + +int ffi_prep_args_v9(char *stack, extended_cif *ecif) +{ + int i, ret = 0; + int tmp; + void **p_argv; + char *argp; + ffi_type **p_arg; + + tmp = 0; + + /* Skip 16 words for the window save area */ + argp = stack + 16*sizeof(long long); + +#ifdef USING_PURIFY + /* Purify will probably complain in our assembly routine, unless we + zero out this memory. */ + + ((long long*)argp)[0] = 0; + ((long long*)argp)[1] = 0; + ((long long*)argp)[2] = 0; + ((long long*)argp)[3] = 0; + ((long long*)argp)[4] = 0; + ((long long*)argp)[5] = 0; +#endif + + p_argv = ecif->avalue; + + if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && + ecif->cif->rtype->size > 32) + { + *(unsigned long long *) argp = (unsigned long)ecif->rvalue; + argp += sizeof(long long); + tmp = 1; + } + + for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs; + i++, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + switch ((*p_arg)->type) + { + case FFI_TYPE_STRUCT: + if (z > 16) + { + /* For structures larger than 16 bytes we pass reference. */ + *(unsigned long long *) argp = (unsigned long)* p_argv; + argp += sizeof(long long); + tmp++; + p_argv++; + continue; + } + /* FALLTHROUGH */ + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + ret = 1; /* We should promote into FP regs as well as integer. */ + break; + } + if (z < sizeof(long long)) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed long long *) argp = *(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned long long *) argp = *(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed long long *) argp = *(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned long long *) argp = *(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_SINT32: + *(signed long long *) argp = *(SINT32 *)(* p_argv); + break; + + case FFI_TYPE_UINT32: + *(unsigned long long *) argp = *(UINT32 *)(* p_argv); + break; + + case FFI_TYPE_FLOAT: + *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */ + break; + + case FFI_TYPE_STRUCT: + memcpy(argp, *p_argv, z); + break; + + default: + FFI_ASSERT(0); + } + z = sizeof(long long); + tmp++; + } + else if (z == sizeof(long long)) + { + memcpy(argp, *p_argv, z); + z = sizeof(long long); + tmp++; + } + else + { + if ((tmp & 1) && (*p_arg)->alignment > 8) + { + tmp++; + argp += sizeof(long long); + } + memcpy(argp, *p_argv, z); + z = 2 * sizeof(long long); + tmp += 2; + } + p_argv++; + argp += z; + } + + return ret; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + int wordsize; + + if (cif->abi != FFI_V9) + { + wordsize = 4; + + /* If we are returning a struct, this will already have been added. + Otherwise we need to add it because it's always got to be there! */ + + if (cif->rtype->type != FFI_TYPE_STRUCT) + cif->bytes += wordsize; + + /* sparc call frames require that space is allocated for 6 args, + even if they aren't used. Make that space if necessary. */ + + if (cif->bytes < 4*6+4) + cif->bytes = 4*6+4; + } + else + { + wordsize = 8; + + /* sparc call frames require that space is allocated for 6 args, + even if they aren't used. Make that space if necessary. */ + + if (cif->bytes < 8*6) + cif->bytes = 8*6; + } + + /* Adjust cif->bytes. to include 16 words for the window save area, + and maybe the struct/union return pointer area, */ + + cif->bytes += 16 * wordsize; + + /* The stack must be 2 word aligned, so round bytes up + appropriately. */ + + cif->bytes = ALIGN(cif->bytes, 2 * wordsize); + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + cif->flags = cif->rtype->type; + break; + + case FFI_TYPE_STRUCT: + if (cif->abi == FFI_V9 && cif->rtype->size > 32) + cif->flags = FFI_TYPE_VOID; + else + cif->flags = FFI_TYPE_STRUCT; + break; + + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + if (cif->abi == FFI_V9) + cif->flags = FFI_TYPE_INT; + else + cif->flags = cif->rtype->type; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + if (cif->abi == FFI_V9) + cif->flags = FFI_TYPE_INT; + else + cif->flags = FFI_TYPE_SINT64; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + return FFI_OK; +} + +int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt) +{ + ffi_type **ptr = &arg->elements[0]; + + while (*ptr != NULL) + { + if (off & ((*ptr)->alignment - 1)) + off = ALIGN(off, (*ptr)->alignment); + + switch ((*ptr)->type) + { + case FFI_TYPE_STRUCT: + off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt); + off = ALIGN(off, FFI_SIZEOF_ARG); + break; + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + memmove(ret + off, flt + off, (*ptr)->size); + off += (*ptr)->size; + break; + default: + memmove(ret + off, intg + off, (*ptr)->size); + off += (*ptr)->size; + break; + } + ptr++; + } + return off; +} + + +#ifdef SPARC64 +extern int ffi_call_v9(void *, extended_cif *, unsigned, + unsigned, unsigned *, void (*fn)(void)); +#else +extern int ffi_call_v8(void *, extended_cif *, unsigned, + unsigned, unsigned *, void (*fn)(void)); +#endif + +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + extended_cif ecif; + void *rval = rvalue; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + ecif.rvalue = rvalue; + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + if (cif->rtype->size <= 32) + rval = alloca(64); + else + { + rval = NULL; + if (rvalue == NULL) + ecif.rvalue = alloca(cif->rtype->size); + } + } + + switch (cif->abi) + { + case FFI_V8: +#ifdef SPARC64 + /* We don't yet support calling 32bit code from 64bit */ + FFI_ASSERT(0); +#else + ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes, + cif->flags, rvalue, fn); +#endif + break; + case FFI_V9: +#ifdef SPARC64 + ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes, + cif->flags, rval, fn); + if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT) + ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32); +#else + /* And vice versa */ + FFI_ASSERT(0); +#endif + break; + default: + FFI_ASSERT(0); + break; + } + +} + + +#ifdef SPARC64 +extern void ffi_closure_v9(void); +#else +extern void ffi_closure_v8(void); +#endif + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc) +{ + unsigned int *tramp = (unsigned int *) &closure->tramp[0]; + unsigned long fn; +#ifdef SPARC64 + /* Trampoline address is equal to the closure address. We take advantage + of that to reduce the trampoline size by 8 bytes. */ + FFI_ASSERT (cif->abi == FFI_V9); + fn = (unsigned long) ffi_closure_v9; + tramp[0] = 0x83414000; /* rd %pc, %g1 */ + tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */ + tramp[2] = 0x81c14000; /* jmp %g5 */ + tramp[3] = 0x01000000; /* nop */ + *((unsigned long *) &tramp[4]) = fn; +#else + unsigned long ctx = (unsigned long) codeloc; + FFI_ASSERT (cif->abi == FFI_V8); + fn = (unsigned long) ffi_closure_v8; + tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */ + tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */ + tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */ + tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */ +#endif + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* Flush the Icache. FIXME: alignment isn't certain, assume 8 bytes */ +#ifdef SPARC64 + asm volatile ("flush %0" : : "r" (closure) : "memory"); + asm volatile ("flush %0" : : "r" (((char *) closure) + 8) : "memory"); +#else + asm volatile ("iflush %0" : : "r" (closure) : "memory"); + asm volatile ("iflush %0" : : "r" (((char *) closure) + 8) : "memory"); +#endif + + return FFI_OK; +} + +int +ffi_closure_sparc_inner_v8(ffi_closure *closure, + void *rvalue, unsigned long *gpr, unsigned long *scratch) +{ + ffi_cif *cif; + ffi_type **arg_types; + void **avalue; + int i, argn; + + cif = closure->cif; + arg_types = cif->arg_types; + avalue = alloca(cif->nargs * sizeof(void *)); + + /* Copy the caller's structure return address so that the closure + returns the data directly to the caller. */ + if (cif->flags == FFI_TYPE_STRUCT +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + || cif->flags == FFI_TYPE_LONGDOUBLE +#endif + ) + rvalue = (void *) gpr[0]; + + /* Always skip the structure return address. */ + argn = 1; + + /* Grab the addresses of the arguments from the stack frame. */ + for (i = 0; i < cif->nargs; i++) + { + if (arg_types[i]->type == FFI_TYPE_STRUCT +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + || arg_types[i]->type == FFI_TYPE_LONGDOUBLE +#endif + ) + { + /* Straight copy of invisible reference. */ + avalue[i] = (void *)gpr[argn++]; + } + else if ((arg_types[i]->type == FFI_TYPE_DOUBLE + || arg_types[i]->type == FFI_TYPE_SINT64 + || arg_types[i]->type == FFI_TYPE_UINT64) + /* gpr is 8-byte aligned. */ + && (argn % 2) != 0) + { + /* Align on a 8-byte boundary. */ + scratch[0] = gpr[argn]; + scratch[1] = gpr[argn+1]; + avalue[i] = scratch; + scratch -= 2; + argn += 2; + } + else + { + /* Always right-justify. */ + argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size; + } + } + + /* Invoke the closure. */ + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_sparc how to perform return type promotions. */ + return cif->rtype->type; +} + +int +ffi_closure_sparc_inner_v9(ffi_closure *closure, + void *rvalue, unsigned long *gpr, double *fpr) +{ + ffi_cif *cif; + ffi_type **arg_types; + void **avalue; + int i, argn, fp_slot_max; + + cif = closure->cif; + arg_types = cif->arg_types; + avalue = alloca(cif->nargs * sizeof(void *)); + + /* Copy the caller's structure return address so that the closure + returns the data directly to the caller. */ + if (cif->flags == FFI_TYPE_VOID + && cif->rtype->type == FFI_TYPE_STRUCT) + { + rvalue = (void *) gpr[0]; + /* Skip the structure return address. */ + argn = 1; + } + else + argn = 0; + + fp_slot_max = 16 - argn; + + /* Grab the addresses of the arguments from the stack frame. */ + for (i = 0; i < cif->nargs; i++) + { + if (arg_types[i]->type == FFI_TYPE_STRUCT) + { + if (arg_types[i]->size > 16) + { + /* Straight copy of invisible reference. */ + avalue[i] = (void *)gpr[argn++]; + } + else + { + /* Left-justify. */ + ffi_v9_layout_struct(arg_types[i], + 0, + (char *) &gpr[argn], + (char *) &gpr[argn], + (char *) &fpr[argn]); + avalue[i] = &gpr[argn]; + argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + } + } + else + { + /* Right-justify. */ + argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + + /* Align on a 16-byte boundary. */ +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + if (arg_types[i]->type == FFI_TYPE_LONGDOUBLE && (argn % 2) != 0) + argn++; +#endif + if (i < fp_slot_max + && (arg_types[i]->type == FFI_TYPE_FLOAT + || arg_types[i]->type == FFI_TYPE_DOUBLE +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + || arg_types[i]->type == FFI_TYPE_LONGDOUBLE +#endif + )) + avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size; + else + avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size; + } + } + + /* Invoke the closure. */ + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_sparc how to perform return type promotions. */ + return cif->rtype->type; +} diff --git a/js/src/ctypes/libffi/src/sparc/ffitarget.h b/js/src/ctypes/libffi/src/sparc/ffitarget.h new file mode 100644 index 0000000..51275cb --- /dev/null +++ b/js/src/ctypes/libffi/src/sparc/ffitarget.h @@ -0,0 +1,68 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for SPARC. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- System specific configurations ----------------------------------- */ + +#if defined(__arch64__) || defined(__sparcv9) +#ifndef SPARC64 +#define SPARC64 +#endif +#endif + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_V8, + FFI_V8PLUS, + FFI_V9, + FFI_LAST_ABI, +#ifdef SPARC64 + FFI_DEFAULT_ABI = FFI_V9 +#else + FFI_DEFAULT_ABI = FFI_V8 +#endif +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 + +#ifdef SPARC64 +#define FFI_TRAMPOLINE_SIZE 24 +#else +#define FFI_TRAMPOLINE_SIZE 16 +#endif + +#endif + diff --git a/js/src/ctypes/libffi/src/sparc/v8.S b/js/src/ctypes/libffi/src/sparc/v8.S new file mode 100644 index 0000000..2c4eb60 --- /dev/null +++ b/js/src/ctypes/libffi/src/sparc/v8.S @@ -0,0 +1,313 @@ +/* ----------------------------------------------------------------------- + v8.S - Copyright (c) 1996, 1997, 2003, 2004, 2008 Red Hat, Inc. + + SPARC Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include + +#define STACKFRAME 96 /* Minimum stack framesize for SPARC */ +#define ARGS (64+4) /* Offset of register area in frame */ + +.text + .align 8 +.globl ffi_call_v8 +.globl _ffi_call_v8 + +ffi_call_v8: +_ffi_call_v8: +.LLFB1: + save %sp, -STACKFRAME, %sp +.LLCFI0: + + sub %sp, %i2, %sp ! alloca() space in stack for frame to set up + add %sp, STACKFRAME, %l0 ! %l0 has start of + ! frame to set up + + mov %l0, %o0 ! call routine to set up frame + call %i0 + mov %i1, %o1 ! (delay) + + ld [%l0+ARGS], %o0 ! call foreign function + ld [%l0+ARGS+4], %o1 + ld [%l0+ARGS+8], %o2 + ld [%l0+ARGS+12], %o3 + ld [%l0+ARGS+16], %o4 + ld [%l0+ARGS+20], %o5 + call %i5 + mov %l0, %sp ! (delay) switch to frame + nop ! STRUCT returning functions skip 12 instead of 8 bytes + + ! If the return value pointer is NULL, assume no return value. + tst %i4 + bz done + nop + + cmp %i3, FFI_TYPE_INT + be,a done + st %o0, [%i4] ! (delay) + + cmp %i3, FFI_TYPE_FLOAT + be,a done + st %f0, [%i4+0] ! (delay) + + cmp %i3, FFI_TYPE_DOUBLE + be,a double + st %f0, [%i4+0] ! (delay) + + cmp %i3, FFI_TYPE_SINT8 + be,a sint8 + sll %o0, 24, %o0 ! (delay) + + cmp %i3, FFI_TYPE_UINT8 + be,a uint8 + sll %o0, 24, %o0 ! (delay) + + cmp %i3, FFI_TYPE_SINT16 + be,a sint16 + sll %o0, 16, %o0 ! (delay) + + cmp %i3, FFI_TYPE_UINT16 + be,a uint16 + sll %o0, 16, %o0 ! (delay) + + cmp %i3, FFI_TYPE_SINT64 + be,a longlong + st %o0, [%i4+0] ! (delay) +done: + ret + restore + +double: + st %f1, [%i4+4] + ret + restore + +sint8: + sra %o0, 24, %o0 + st %o0, [%i4+0] + ret + restore + +uint8: + srl %o0, 24, %o0 + st %o0, [%i4+0] + ret + restore + +sint16: + sra %o0, 16, %o0 + st %o0, [%i4+0] + ret + restore + +uint16: + srl %o0, 16, %o0 + st %o0, [%i4+0] + ret + restore + +longlong: + st %o1, [%i4+4] + ret + restore +.LLFE1: + +.ffi_call_v8_end: + .size ffi_call_v8,.ffi_call_v8_end-ffi_call_v8 + + +#undef STACKFRAME +#define STACKFRAME 104 /* 16*4 register window + + 1*4 struct return + + 6*4 args backing store + + 3*4 locals */ + +/* ffi_closure_v8(...) + + Receives the closure argument in %g2. */ + + .text + .align 8 + .globl ffi_closure_v8 + +ffi_closure_v8: +#ifdef HAVE_AS_REGISTER_PSEUDO_OP + .register %g2, #scratch +#endif +.LLFB2: + ! Reserve frame space for all arguments in case + ! we need to align them on a 8-byte boundary. + ld [%g2+FFI_TRAMPOLINE_SIZE], %g1 + ld [%g1+4], %g1 + sll %g1, 3, %g1 + add %g1, STACKFRAME, %g1 + ! %g1 == STACKFRAME + 8*nargs + neg %g1 + save %sp, %g1, %sp +.LLCFI1: + + ! Store all of the potential argument registers in va_list format. + st %i0, [%fp+68+0] + st %i1, [%fp+68+4] + st %i2, [%fp+68+8] + st %i3, [%fp+68+12] + st %i4, [%fp+68+16] + st %i5, [%fp+68+20] + + ! Call ffi_closure_sparc_inner to do the bulk of the work. + mov %g2, %o0 + add %fp, -8, %o1 + add %fp, 64, %o2 + call ffi_closure_sparc_inner_v8 + add %fp, -16, %o3 + + ! Load up the return value in the proper type. + ! See ffi_prep_cif_machdep for the list of cases. + cmp %o0, FFI_TYPE_VOID + be done1 + + cmp %o0, FFI_TYPE_INT + be done1 + ld [%fp-8], %i0 + + cmp %o0, FFI_TYPE_FLOAT + be,a done1 + ld [%fp-8], %f0 + + cmp %o0, FFI_TYPE_DOUBLE + be,a done1 + ldd [%fp-8], %f0 + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + cmp %o0, FFI_TYPE_LONGDOUBLE + be done2 +#endif + + cmp %o0, FFI_TYPE_STRUCT + be done2 + + cmp %o0, FFI_TYPE_SINT64 + be,a done1 + ldd [%fp-8], %i0 + + ld [%fp-8], %i0 +done1: + jmp %i7+8 + restore +done2: + ! Skip 'unimp'. + jmp %i7+12 + restore +.LLFE2: + +.ffi_closure_v8_end: + .size ffi_closure_v8,.ffi_closure_v8_end-ffi_closure_v8 + +#ifdef SPARC64 +#define WS 8 +#define nword xword +#define uanword uaxword +#else +#define WS 4 +#define nword long +#define uanword uaword +#endif + +#ifdef HAVE_RO_EH_FRAME + .section ".eh_frame",#alloc +#else + .section ".eh_frame",#alloc,#write +#endif +.LLframe1: + .uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry +.LLSCIE1: + .uaword 0x0 ! CIE Identifier Tag + .byte 0x1 ! CIE Version + .ascii "zR\0" ! CIE Augmentation + .byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor + .byte 0x80-WS ! sleb128 -WS; CIE Data Alignment Factor + .byte 0xf ! CIE RA Column + .byte 0x1 ! uleb128 0x1; Augmentation size +#ifdef HAVE_AS_SPARC_UA_PCREL + .byte 0x1b ! FDE Encoding (pcrel sdata4) +#else + .byte 0x50 ! FDE Encoding (aligned absolute) +#endif + .byte 0xc ! DW_CFA_def_cfa + .byte 0xe ! uleb128 0xe + .byte 0x0 ! uleb128 0x0 + .align WS +.LLECIE1: +.LLSFDE1: + .uaword .LLEFDE1-.LLASFDE1 ! FDE Length +.LLASFDE1: + .uaword .LLASFDE1-.LLframe1 ! FDE CIE offset +#ifdef HAVE_AS_SPARC_UA_PCREL + .uaword %r_disp32(.LLFB1) + .uaword .LLFE1-.LLFB1 ! FDE address range +#else + .align WS + .nword .LLFB1 + .uanword .LLFE1-.LLFB1 ! FDE address range +#endif + .byte 0x0 ! uleb128 0x0; Augmentation size + .byte 0x4 ! DW_CFA_advance_loc4 + .uaword .LLCFI0-.LLFB1 + .byte 0xd ! DW_CFA_def_cfa_register + .byte 0x1e ! uleb128 0x1e + .byte 0x2d ! DW_CFA_GNU_window_save + .byte 0x9 ! DW_CFA_register + .byte 0xf ! uleb128 0xf + .byte 0x1f ! uleb128 0x1f + .align WS +.LLEFDE1: +.LLSFDE2: + .uaword .LLEFDE2-.LLASFDE2 ! FDE Length +.LLASFDE2: + .uaword .LLASFDE2-.LLframe1 ! FDE CIE offset +#ifdef HAVE_AS_SPARC_UA_PCREL + .uaword %r_disp32(.LLFB2) + .uaword .LLFE2-.LLFB2 ! FDE address range +#else + .align WS + .nword .LLFB2 + .uanword .LLFE2-.LLFB2 ! FDE address range +#endif + .byte 0x0 ! uleb128 0x0; Augmentation size + .byte 0x4 ! DW_CFA_advance_loc4 + .uaword .LLCFI1-.LLFB2 + .byte 0xd ! DW_CFA_def_cfa_register + .byte 0x1e ! uleb128 0x1e + .byte 0x2d ! DW_CFA_GNU_window_save + .byte 0x9 ! DW_CFA_register + .byte 0xf ! uleb128 0xf + .byte 0x1f ! uleb128 0x1f + .align WS +.LLEFDE2: + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/js/src/ctypes/libffi/src/sparc/v9.S b/js/src/ctypes/libffi/src/sparc/v9.S new file mode 100644 index 0000000..489ff02 --- /dev/null +++ b/js/src/ctypes/libffi/src/sparc/v9.S @@ -0,0 +1,307 @@ +/* ----------------------------------------------------------------------- + v9.S - Copyright (c) 2000, 2003, 2004, 2008 Red Hat, Inc. + + SPARC 64-bit Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include +#include + +#ifdef SPARC64 +/* Only compile this in for 64bit builds, because otherwise the object file + will have inproper architecture due to used instructions. */ + +#define STACKFRAME 128 /* Minimum stack framesize for SPARC */ +#define STACK_BIAS 2047 +#define ARGS (128) /* Offset of register area in frame */ + +.text + .align 8 +.globl ffi_call_v9 +.globl _ffi_call_v9 + +ffi_call_v9: +_ffi_call_v9: +.LLFB1: + save %sp, -STACKFRAME, %sp +.LLCFI0: + + sub %sp, %i2, %sp ! alloca() space in stack for frame to set up + add %sp, STACKFRAME+STACK_BIAS, %l0 ! %l0 has start of + ! frame to set up + + mov %l0, %o0 ! call routine to set up frame + call %i0 + mov %i1, %o1 ! (delay) + brz,pt %o0, 1f + ldx [%l0+ARGS], %o0 ! call foreign function + + ldd [%l0+ARGS], %f0 + ldd [%l0+ARGS+8], %f2 + ldd [%l0+ARGS+16], %f4 + ldd [%l0+ARGS+24], %f6 + ldd [%l0+ARGS+32], %f8 + ldd [%l0+ARGS+40], %f10 + ldd [%l0+ARGS+48], %f12 + ldd [%l0+ARGS+56], %f14 + ldd [%l0+ARGS+64], %f16 + ldd [%l0+ARGS+72], %f18 + ldd [%l0+ARGS+80], %f20 + ldd [%l0+ARGS+88], %f22 + ldd [%l0+ARGS+96], %f24 + ldd [%l0+ARGS+104], %f26 + ldd [%l0+ARGS+112], %f28 + ldd [%l0+ARGS+120], %f30 + +1: ldx [%l0+ARGS+8], %o1 + ldx [%l0+ARGS+16], %o2 + ldx [%l0+ARGS+24], %o3 + ldx [%l0+ARGS+32], %o4 + ldx [%l0+ARGS+40], %o5 + call %i5 + sub %l0, STACK_BIAS, %sp ! (delay) switch to frame + + ! If the return value pointer is NULL, assume no return value. + brz,pn %i4, done + nop + + cmp %i3, FFI_TYPE_INT + be,a,pt %icc, done + stx %o0, [%i4+0] ! (delay) + + cmp %i3, FFI_TYPE_FLOAT + be,a,pn %icc, done + st %f0, [%i4+0] ! (delay) + + cmp %i3, FFI_TYPE_DOUBLE + be,a,pn %icc, done + std %f0, [%i4+0] ! (delay) + + cmp %i3, FFI_TYPE_STRUCT + be,pn %icc, dostruct + + cmp %i3, FFI_TYPE_LONGDOUBLE + bne,pt %icc, done + nop + std %f0, [%i4+0] + std %f2, [%i4+8] + +done: ret + restore + +dostruct: + /* This will not work correctly for unions. */ + stx %o0, [%i4+0] + stx %o1, [%i4+8] + stx %o2, [%i4+16] + stx %o3, [%i4+24] + std %f0, [%i4+32] + std %f2, [%i4+40] + std %f4, [%i4+48] + std %f6, [%i4+56] + ret + restore +.LLFE1: + +.ffi_call_v9_end: + .size ffi_call_v9,.ffi_call_v9_end-ffi_call_v9 + + +#undef STACKFRAME +#define STACKFRAME 336 /* 16*8 register window + + 6*8 args backing store + + 20*8 locals */ +#define FP %fp+STACK_BIAS + +/* ffi_closure_v9(...) + + Receives the closure argument in %g1. */ + + .text + .align 8 + .globl ffi_closure_v9 + +ffi_closure_v9: +.LLFB2: + save %sp, -STACKFRAME, %sp +.LLCFI1: + + ! Store all of the potential argument registers in va_list format. + stx %i0, [FP+128+0] + stx %i1, [FP+128+8] + stx %i2, [FP+128+16] + stx %i3, [FP+128+24] + stx %i4, [FP+128+32] + stx %i5, [FP+128+40] + + ! Store possible floating point argument registers too. + std %f0, [FP-128] + std %f2, [FP-120] + std %f4, [FP-112] + std %f6, [FP-104] + std %f8, [FP-96] + std %f10, [FP-88] + std %f12, [FP-80] + std %f14, [FP-72] + std %f16, [FP-64] + std %f18, [FP-56] + std %f20, [FP-48] + std %f22, [FP-40] + std %f24, [FP-32] + std %f26, [FP-24] + std %f28, [FP-16] + std %f30, [FP-8] + + ! Call ffi_closure_sparc_inner to do the bulk of the work. + mov %g1, %o0 + add %fp, STACK_BIAS-160, %o1 + add %fp, STACK_BIAS+128, %o2 + call ffi_closure_sparc_inner_v9 + add %fp, STACK_BIAS-128, %o3 + + ! Load up the return value in the proper type. + ! See ffi_prep_cif_machdep for the list of cases. + cmp %o0, FFI_TYPE_VOID + be,pn %icc, done1 + + cmp %o0, FFI_TYPE_INT + be,pn %icc, integer + + cmp %o0, FFI_TYPE_FLOAT + be,a,pn %icc, done1 + ld [FP-160], %f0 + + cmp %o0, FFI_TYPE_DOUBLE + be,a,pn %icc, done1 + ldd [FP-160], %f0 + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + cmp %o0, FFI_TYPE_LONGDOUBLE + be,a,pn %icc, longdouble1 + ldd [FP-160], %f0 +#endif + + ! FFI_TYPE_STRUCT + ldx [FP-152], %i1 + ldx [FP-144], %i2 + ldx [FP-136], %i3 + ldd [FP-160], %f0 + ldd [FP-152], %f2 + ldd [FP-144], %f4 + ldd [FP-136], %f6 + +integer: + ldx [FP-160], %i0 + +done1: + ret + restore + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +longdouble1: + ldd [FP-152], %f2 + ret + restore +#endif +.LLFE2: + +.ffi_closure_v9_end: + .size ffi_closure_v9,.ffi_closure_v9_end-ffi_closure_v9 + +#ifdef HAVE_RO_EH_FRAME + .section ".eh_frame",#alloc +#else + .section ".eh_frame",#alloc,#write +#endif +.LLframe1: + .uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry +.LLSCIE1: + .uaword 0x0 ! CIE Identifier Tag + .byte 0x1 ! CIE Version + .ascii "zR\0" ! CIE Augmentation + .byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor + .byte 0x78 ! sleb128 -8; CIE Data Alignment Factor + .byte 0xf ! CIE RA Column + .byte 0x1 ! uleb128 0x1; Augmentation size +#ifdef HAVE_AS_SPARC_UA_PCREL + .byte 0x1b ! FDE Encoding (pcrel sdata4) +#else + .byte 0x50 ! FDE Encoding (aligned absolute) +#endif + .byte 0xc ! DW_CFA_def_cfa + .byte 0xe ! uleb128 0xe + .byte 0xff,0xf ! uleb128 0x7ff + .align 8 +.LLECIE1: +.LLSFDE1: + .uaword .LLEFDE1-.LLASFDE1 ! FDE Length +.LLASFDE1: + .uaword .LLASFDE1-.LLframe1 ! FDE CIE offset +#ifdef HAVE_AS_SPARC_UA_PCREL + .uaword %r_disp32(.LLFB1) + .uaword .LLFE1-.LLFB1 ! FDE address range +#else + .align 8 + .xword .LLFB1 + .uaxword .LLFE1-.LLFB1 ! FDE address range +#endif + .byte 0x0 ! uleb128 0x0; Augmentation size + .byte 0x4 ! DW_CFA_advance_loc4 + .uaword .LLCFI0-.LLFB1 + .byte 0xd ! DW_CFA_def_cfa_register + .byte 0x1e ! uleb128 0x1e + .byte 0x2d ! DW_CFA_GNU_window_save + .byte 0x9 ! DW_CFA_register + .byte 0xf ! uleb128 0xf + .byte 0x1f ! uleb128 0x1f + .align 8 +.LLEFDE1: +.LLSFDE2: + .uaword .LLEFDE2-.LLASFDE2 ! FDE Length +.LLASFDE2: + .uaword .LLASFDE2-.LLframe1 ! FDE CIE offset +#ifdef HAVE_AS_SPARC_UA_PCREL + .uaword %r_disp32(.LLFB2) + .uaword .LLFE2-.LLFB2 ! FDE address range +#else + .align 8 + .xword .LLFB2 + .uaxword .LLFE2-.LLFB2 ! FDE address range +#endif + .byte 0x0 ! uleb128 0x0; Augmentation size + .byte 0x4 ! DW_CFA_advance_loc4 + .uaword .LLCFI1-.LLFB2 + .byte 0xd ! DW_CFA_def_cfa_register + .byte 0x1e ! uleb128 0x1e + .byte 0x2d ! DW_CFA_GNU_window_save + .byte 0x9 ! DW_CFA_register + .byte 0xf ! uleb128 0xf + .byte 0x1f ! uleb128 0x1f + .align 8 +.LLEFDE2: +#endif + +#ifdef __linux__ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/js/src/ctypes/libffi/src/types.c b/js/src/ctypes/libffi/src/types.c new file mode 100644 index 0000000..0a11eb0 --- /dev/null +++ b/js/src/ctypes/libffi/src/types.c @@ -0,0 +1,77 @@ +/* ----------------------------------------------------------------------- + types.c - Copyright (c) 1996, 1998 Red Hat, Inc. + + Predefined ffi_types needed by libffi. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +/* Hide the basic type definitions from the header file, so that we + can redefine them here as "const". */ +#define LIBFFI_HIDE_BASIC_TYPES + +#include +#include + +/* Type definitions */ + +#define FFI_TYPEDEF(name, type, id) \ +struct struct_align_##name { \ + char c; \ + type x; \ +}; \ +const ffi_type ffi_type_##name = { \ + sizeof(type), \ + offsetof(struct struct_align_##name, x), \ + id, NULL \ +} + +/* Size and alignment are fake here. They must not be 0. */ +const ffi_type ffi_type_void = { + 1, 1, FFI_TYPE_VOID, NULL +}; + +FFI_TYPEDEF(uint8, UINT8, FFI_TYPE_UINT8); +FFI_TYPEDEF(sint8, SINT8, FFI_TYPE_SINT8); +FFI_TYPEDEF(uint16, UINT16, FFI_TYPE_UINT16); +FFI_TYPEDEF(sint16, SINT16, FFI_TYPE_SINT16); +FFI_TYPEDEF(uint32, UINT32, FFI_TYPE_UINT32); +FFI_TYPEDEF(sint32, SINT32, FFI_TYPE_SINT32); +FFI_TYPEDEF(uint64, UINT64, FFI_TYPE_UINT64); +FFI_TYPEDEF(sint64, SINT64, FFI_TYPE_SINT64); + +FFI_TYPEDEF(pointer, void*, FFI_TYPE_POINTER); + +FFI_TYPEDEF(float, float, FFI_TYPE_FLOAT); +FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE); + +#ifdef __alpha__ +/* Even if we're not configured to default to 128-bit long double, + maintain binary compatibility, as -mlong-double-128 can be used + at any time. */ +/* Validate the hard-coded number below. */ +# if defined(__LONG_DOUBLE_128__) && FFI_TYPE_LONGDOUBLE != 4 +# error FFI_TYPE_LONGDOUBLE out of date +# endif +const ffi_type ffi_type_longdouble = { 16, 16, 4, NULL }; +#elif FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +FFI_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE); +#endif diff --git a/js/src/ctypes/libffi/src/x86/darwin.S b/js/src/ctypes/libffi/src/x86/darwin.S new file mode 100644 index 0000000..8f0f070 --- /dev/null +++ b/js/src/ctypes/libffi/src/x86/darwin.S @@ -0,0 +1,444 @@ +/* ----------------------------------------------------------------------- + darwin.S - Copyright (c) 1996, 1998, 2001, 2002, 2003, 2005 Red Hat, Inc. + Copyright (C) 2008 Free Software Foundation, Inc. + + X86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- + */ + +#ifndef __x86_64__ + +#define LIBFFI_ASM +#include +#include + +.text + +.globl _ffi_prep_args + + .align 4 +.globl _ffi_call_SYSV + +_ffi_call_SYSV: +.LFB1: + pushl %ebp +.LCFI0: + movl %esp,%ebp +.LCFI1: + subl $8,%esp + /* Make room for all of the new args. */ + movl 16(%ebp),%ecx + subl %ecx,%esp + + movl %esp,%eax + + /* Place all of the ffi_prep_args in position */ + subl $8,%esp + pushl 12(%ebp) + pushl %eax + call *8(%ebp) + + /* Return stack to previous state and call the function */ + addl $16,%esp + + call *28(%ebp) + + /* Load %ecx with the return type code */ + movl 20(%ebp),%ecx + + /* Protect %esi. We're going to pop it in the epilogue. */ + pushl %esi + + /* If the return value pointer is NULL, assume no return value. */ + cmpl $0,24(%ebp) + jne 0f + + /* Even if there is no space for the return value, we are + obliged to handle floating-point values. */ + cmpl $FFI_TYPE_FLOAT,%ecx + jne noretval + fstp %st(0) + + jmp epilogue +0: + .align 4 + call 1f +.Lstore_table: + .long noretval-.Lstore_table /* FFI_TYPE_VOID */ + .long retint-.Lstore_table /* FFI_TYPE_INT */ + .long retfloat-.Lstore_table /* FFI_TYPE_FLOAT */ + .long retdouble-.Lstore_table /* FFI_TYPE_DOUBLE */ + .long retlongdouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */ + .long retuint8-.Lstore_table /* FFI_TYPE_UINT8 */ + .long retsint8-.Lstore_table /* FFI_TYPE_SINT8 */ + .long retuint16-.Lstore_table /* FFI_TYPE_UINT16 */ + .long retsint16-.Lstore_table /* FFI_TYPE_SINT16 */ + .long retint-.Lstore_table /* FFI_TYPE_UINT32 */ + .long retint-.Lstore_table /* FFI_TYPE_SINT32 */ + .long retint64-.Lstore_table /* FFI_TYPE_UINT64 */ + .long retint64-.Lstore_table /* FFI_TYPE_SINT64 */ + .long retstruct-.Lstore_table /* FFI_TYPE_STRUCT */ + .long retint-.Lstore_table /* FFI_TYPE_POINTER */ + .long retstruct1b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_1B */ + .long retstruct2b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_2B */ +1: + pop %esi + add (%esi, %ecx, 4), %esi + jmp *%esi + + /* Sign/zero extend as appropriate. */ +retsint8: + movsbl %al, %eax + jmp retint + +retsint16: + movswl %ax, %eax + jmp retint + +retuint8: + movzbl %al, %eax + jmp retint + +retuint16: + movzwl %ax, %eax + jmp retint + +retfloat: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstps (%ecx) + jmp epilogue + +retdouble: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstpl (%ecx) + jmp epilogue + +retlongdouble: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstpt (%ecx) + jmp epilogue + +retint64: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + movl %edx,4(%ecx) + jmp epilogue + +retstruct1b: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movb %al,0(%ecx) + jmp epilogue + +retstruct2b: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movw %ax,0(%ecx) + jmp epilogue + +retint: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + +retstruct: + /* Nothing to do! */ + +noretval: +epilogue: + popl %esi + movl %ebp,%esp + popl %ebp + ret + +.LFE1: +.ffi_call_SYSV_end: + + .align 4 +FFI_HIDDEN (ffi_closure_SYSV) +.globl _ffi_closure_SYSV + +_ffi_closure_SYSV: +.LFB2: + pushl %ebp +.LCFI2: + movl %esp, %ebp +.LCFI3: + subl $40, %esp + leal -24(%ebp), %edx + movl %edx, -12(%ebp) /* resp */ + leal 8(%ebp), %edx + movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */ + leal -12(%ebp), %edx + movl %edx, (%esp) /* &resp */ + movl %ebx, 8(%esp) +.LCFI7: + call L_ffi_closure_SYSV_inner$stub + movl 8(%esp), %ebx + movl -12(%ebp), %ecx + cmpl $FFI_TYPE_INT, %eax + je .Lcls_retint + + /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16, + FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */ + cmpl $FFI_TYPE_UINT64, %eax + jge 0f + cmpl $FFI_TYPE_UINT8, %eax + jge .Lcls_retint + +0: cmpl $FFI_TYPE_FLOAT, %eax + je .Lcls_retfloat + cmpl $FFI_TYPE_DOUBLE, %eax + je .Lcls_retdouble + cmpl $FFI_TYPE_LONGDOUBLE, %eax + je .Lcls_retldouble + cmpl $FFI_TYPE_SINT64, %eax + je .Lcls_retllong + cmpl $FFI_TYPE_SMALL_STRUCT_1B, %eax + je .Lcls_retstruct1b + cmpl $FFI_TYPE_SMALL_STRUCT_2B, %eax + je .Lcls_retstruct2b + cmpl $FFI_TYPE_STRUCT, %eax + je .Lcls_retstruct +.Lcls_epilogue: + movl %ebp, %esp + popl %ebp + ret +.Lcls_retint: + movl (%ecx), %eax + jmp .Lcls_epilogue +.Lcls_retfloat: + flds (%ecx) + jmp .Lcls_epilogue +.Lcls_retdouble: + fldl (%ecx) + jmp .Lcls_epilogue +.Lcls_retldouble: + fldt (%ecx) + jmp .Lcls_epilogue +.Lcls_retllong: + movl (%ecx), %eax + movl 4(%ecx), %edx + jmp .Lcls_epilogue +.Lcls_retstruct1b: + movsbl (%ecx), %eax + jmp .Lcls_epilogue +.Lcls_retstruct2b: + movswl (%ecx), %eax + jmp .Lcls_epilogue +.Lcls_retstruct: + lea -8(%ebp),%esp + movl %ebp, %esp + popl %ebp + ret $4 +.LFE2: + +#if !FFI_NO_RAW_API + +#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3) +#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4) +#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4) +#define CIF_FLAGS_OFFSET 20 + + .align 4 +FFI_HIDDEN (ffi_closure_raw_SYSV) +.globl _ffi_closure_raw_SYSV + +_ffi_closure_raw_SYSV: +.LFB3: + pushl %ebp +.LCFI4: + movl %esp, %ebp +.LCFI5: + pushl %esi +.LCFI6: + subl $36, %esp + movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */ + movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */ + movl %edx, 12(%esp) /* user_data */ + leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */ + movl %edx, 8(%esp) /* raw_args */ + leal -24(%ebp), %edx + movl %edx, 4(%esp) /* &res */ + movl %esi, (%esp) /* cif */ + call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */ + movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */ + cmpl $FFI_TYPE_INT, %eax + je .Lrcls_retint + + /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16, + FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */ + cmpl $FFI_TYPE_UINT64, %eax + jge 0f + cmpl $FFI_TYPE_UINT8, %eax + jge .Lrcls_retint +0: + cmpl $FFI_TYPE_FLOAT, %eax + je .Lrcls_retfloat + cmpl $FFI_TYPE_DOUBLE, %eax + je .Lrcls_retdouble + cmpl $FFI_TYPE_LONGDOUBLE, %eax + je .Lrcls_retldouble + cmpl $FFI_TYPE_SINT64, %eax + je .Lrcls_retllong +.Lrcls_epilogue: + addl $36, %esp + popl %esi + popl %ebp + ret +.Lrcls_retint: + movl -24(%ebp), %eax + jmp .Lrcls_epilogue +.Lrcls_retfloat: + flds -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retdouble: + fldl -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retldouble: + fldt -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retllong: + movl -24(%ebp), %eax + movl -20(%ebp), %edx + jmp .Lrcls_epilogue +.LFE3: +#endif + +.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5 +L_ffi_closure_SYSV_inner$stub: + .indirect_symbol _ffi_closure_SYSV_inner + hlt ; hlt ; hlt ; hlt ; hlt + + +.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support +EH_frame1: + .set L$set$0,LECIE1-LSCIE1 + .long L$set$0 +LSCIE1: + .long 0x0 + .byte 0x1 + .ascii "zR\0" + .byte 0x1 + .byte 0x7c + .byte 0x8 + .byte 0x1 + .byte 0x10 + .byte 0xc + .byte 0x5 + .byte 0x4 + .byte 0x88 + .byte 0x1 + .align 2 +LECIE1: +.globl _ffi_call_SYSV.eh +_ffi_call_SYSV.eh: +LSFDE1: + .set L$set$1,LEFDE1-LASFDE1 + .long L$set$1 +LASFDE1: + .long LASFDE1-EH_frame1 + .long .LFB1-. + .set L$set$2,.LFE1-.LFB1 + .long L$set$2 + .byte 0x0 + .byte 0x4 + .set L$set$3,.LCFI0-.LFB1 + .long L$set$3 + .byte 0xe + .byte 0x8 + .byte 0x84 + .byte 0x2 + .byte 0x4 + .set L$set$4,.LCFI1-.LCFI0 + .long L$set$4 + .byte 0xd + .byte 0x4 + .align 2 +LEFDE1: +.globl _ffi_closure_SYSV.eh +_ffi_closure_SYSV.eh: +LSFDE2: + .set L$set$5,LEFDE2-LASFDE2 + .long L$set$5 +LASFDE2: + .long LASFDE2-EH_frame1 + .long .LFB2-. + .set L$set$6,.LFE2-.LFB2 + .long L$set$6 + .byte 0x0 + .byte 0x4 + .set L$set$7,.LCFI2-.LFB2 + .long L$set$7 + .byte 0xe + .byte 0x8 + .byte 0x84 + .byte 0x2 + .byte 0x4 + .set L$set$8,.LCFI3-.LCFI2 + .long L$set$8 + .byte 0xd + .byte 0x4 + .align 2 +LEFDE2: + +#if !FFI_NO_RAW_API + +.globl _ffi_closure_raw_SYSV.eh +_ffi_closure_raw_SYSV.eh: +LSFDE3: + .set L$set$10,LEFDE3-LASFDE3 + .long L$set$10 +LASFDE3: + .long LASFDE3-EH_frame1 + .long .LFB3-. + .set L$set$11,.LFE3-.LFB3 + .long L$set$11 + .byte 0x0 + .byte 0x4 + .set L$set$12,.LCFI4-.LFB3 + .long L$set$12 + .byte 0xe + .byte 0x8 + .byte 0x84 + .byte 0x2 + .byte 0x4 + .set L$set$13,.LCFI5-.LCFI4 + .long L$set$13 + .byte 0xd + .byte 0x4 + .byte 0x4 + .set L$set$14,.LCFI6-.LCFI5 + .long L$set$14 + .byte 0x85 + .byte 0x3 + .align 2 +LEFDE3: + +#endif + +#endif /* ifndef __x86_64__ */ diff --git a/js/src/ctypes/libffi/src/x86/darwin64.S b/js/src/ctypes/libffi/src/x86/darwin64.S new file mode 100644 index 0000000..2f7394e --- /dev/null +++ b/js/src/ctypes/libffi/src/x86/darwin64.S @@ -0,0 +1,416 @@ +/* ----------------------------------------------------------------------- + darwin64.S - Copyright (c) 2006 Free Software Foundation, Inc. + Copyright (c) 2008 Red Hat, Inc. + derived from unix64.S + + x86-64 Foreign Function Interface for Darwin. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#ifdef __x86_64__ +#define LIBFFI_ASM +#include +#include + + .file "darwin64.S" +.text + +/* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags, + void *raddr, void (*fnaddr)(void)); + + Bit o trickiness here -- ARGS+BYTES is the base of the stack frame + for this function. This has been allocated by ffi_call. We also + deallocate some of the stack that has been alloca'd. */ + + .align 3 + .globl _ffi_call_unix64 + +_ffi_call_unix64: +LUW0: + movq (%rsp), %r10 /* Load return address. */ + leaq (%rdi, %rsi), %rax /* Find local stack base. */ + movq %rdx, (%rax) /* Save flags. */ + movq %rcx, 8(%rax) /* Save raddr. */ + movq %rbp, 16(%rax) /* Save old frame pointer. */ + movq %r10, 24(%rax) /* Relocate return address. */ + movq %rax, %rbp /* Finalize local stack frame. */ +LUW1: + movq %rdi, %r10 /* Save a copy of the register area. */ + movq %r8, %r11 /* Save a copy of the target fn. */ + movl %r9d, %eax /* Set number of SSE registers. */ + + /* Load up all argument registers. */ + movq (%r10), %rdi + movq 8(%r10), %rsi + movq 16(%r10), %rdx + movq 24(%r10), %rcx + movq 32(%r10), %r8 + movq 40(%r10), %r9 + testl %eax, %eax + jnz Lload_sse +Lret_from_load_sse: + + /* Deallocate the reg arg area. */ + leaq 176(%r10), %rsp + + /* Call the user function. */ + call *%r11 + + /* Deallocate stack arg area; local stack frame in redzone. */ + leaq 24(%rbp), %rsp + + movq 0(%rbp), %rcx /* Reload flags. */ + movq 8(%rbp), %rdi /* Reload raddr. */ + movq 16(%rbp), %rbp /* Reload old frame pointer. */ +LUW2: + + /* The first byte of the flags contains the FFI_TYPE. */ + movzbl %cl, %r10d + leaq Lstore_table(%rip), %r11 + movslq (%r11, %r10, 4), %r10 + addq %r11, %r10 + jmp *%r10 + +Lstore_table: + .long Lst_void-Lstore_table /* FFI_TYPE_VOID */ + .long Lst_sint32-Lstore_table /* FFI_TYPE_INT */ + .long Lst_float-Lstore_table /* FFI_TYPE_FLOAT */ + .long Lst_double-Lstore_table /* FFI_TYPE_DOUBLE */ + .long Lst_ldouble-Lstore_table /* FFI_TYPE_LONGDOUBLE */ + .long Lst_uint8-Lstore_table /* FFI_TYPE_UINT8 */ + .long Lst_sint8-Lstore_table /* FFI_TYPE_SINT8 */ + .long Lst_uint16-Lstore_table /* FFI_TYPE_UINT16 */ + .long Lst_sint16-Lstore_table /* FFI_TYPE_SINT16 */ + .long Lst_uint32-Lstore_table /* FFI_TYPE_UINT32 */ + .long Lst_sint32-Lstore_table /* FFI_TYPE_SINT32 */ + .long Lst_int64-Lstore_table /* FFI_TYPE_UINT64 */ + .long Lst_int64-Lstore_table /* FFI_TYPE_SINT64 */ + .long Lst_struct-Lstore_table /* FFI_TYPE_STRUCT */ + .long Lst_int64-Lstore_table /* FFI_TYPE_POINTER */ + + .text + .align 3 +Lst_void: + ret + .align 3 +Lst_uint8: + movzbq %al, %rax + movq %rax, (%rdi) + ret + .align 3 +Lst_sint8: + movsbq %al, %rax + movq %rax, (%rdi) + ret + .align 3 +Lst_uint16: + movzwq %ax, %rax + movq %rax, (%rdi) + .align 3 +Lst_sint16: + movswq %ax, %rax + movq %rax, (%rdi) + ret + .align 3 +Lst_uint32: + movl %eax, %eax + movq %rax, (%rdi) + .align 3 +Lst_sint32: + cltq + movq %rax, (%rdi) + ret + .align 3 +Lst_int64: + movq %rax, (%rdi) + ret + .align 3 +Lst_float: + movss %xmm0, (%rdi) + ret + .align 3 +Lst_double: + movsd %xmm0, (%rdi) + ret +Lst_ldouble: + fstpt (%rdi) + ret + .align 3 +Lst_struct: + leaq -20(%rsp), %rsi /* Scratch area in redzone. */ + + /* We have to locate the values now, and since we don't want to + write too much data into the user's return value, we spill the + value to a 16 byte scratch area first. Bits 8, 9, and 10 + control where the values are located. Only one of the three + bits will be set; see ffi_prep_cif_machdep for the pattern. */ + movd %xmm0, %r10 + movd %xmm1, %r11 + testl $0x100, %ecx + cmovnz %rax, %rdx + cmovnz %r10, %rax + testl $0x200, %ecx + cmovnz %r10, %rdx + testl $0x400, %ecx + cmovnz %r10, %rax + cmovnz %r11, %rdx + movq %rax, (%rsi) + movq %rdx, 8(%rsi) + + /* Bits 12-31 contain the true size of the structure. Copy from + the scratch area to the true destination. */ + shrl $12, %ecx + rep movsb + ret + + /* Many times we can avoid loading any SSE registers at all. + It's not worth an indirect jump to load the exact set of + SSE registers needed; zero or all is a good compromise. */ + .align 3 +LUW3: +Lload_sse: + movdqa 48(%r10), %xmm0 + movdqa 64(%r10), %xmm1 + movdqa 80(%r10), %xmm2 + movdqa 96(%r10), %xmm3 + movdqa 112(%r10), %xmm4 + movdqa 128(%r10), %xmm5 + movdqa 144(%r10), %xmm6 + movdqa 160(%r10), %xmm7 + jmp Lret_from_load_sse + +LUW4: + .align 3 + .globl _ffi_closure_unix64 + +_ffi_closure_unix64: +LUW5: + /* The carry flag is set by the trampoline iff SSE registers + are used. Don't clobber it before the branch instruction. */ + leaq -200(%rsp), %rsp +LUW6: + movq %rdi, (%rsp) + movq %rsi, 8(%rsp) + movq %rdx, 16(%rsp) + movq %rcx, 24(%rsp) + movq %r8, 32(%rsp) + movq %r9, 40(%rsp) + jc Lsave_sse +Lret_from_save_sse: + + movq %r10, %rdi + leaq 176(%rsp), %rsi + movq %rsp, %rdx + leaq 208(%rsp), %rcx + call _ffi_closure_unix64_inner + + /* Deallocate stack frame early; return value is now in redzone. */ + addq $200, %rsp +LUW7: + + /* The first byte of the return value contains the FFI_TYPE. */ + movzbl %al, %r10d + leaq Lload_table(%rip), %r11 + movslq (%r11, %r10, 4), %r10 + addq %r11, %r10 + jmp *%r10 + +Lload_table: + .long Lld_void-Lload_table /* FFI_TYPE_VOID */ + .long Lld_int32-Lload_table /* FFI_TYPE_INT */ + .long Lld_float-Lload_table /* FFI_TYPE_FLOAT */ + .long Lld_double-Lload_table /* FFI_TYPE_DOUBLE */ + .long Lld_ldouble-Lload_table /* FFI_TYPE_LONGDOUBLE */ + .long Lld_int8-Lload_table /* FFI_TYPE_UINT8 */ + .long Lld_int8-Lload_table /* FFI_TYPE_SINT8 */ + .long Lld_int16-Lload_table /* FFI_TYPE_UINT16 */ + .long Lld_int16-Lload_table /* FFI_TYPE_SINT16 */ + .long Lld_int32-Lload_table /* FFI_TYPE_UINT32 */ + .long Lld_int32-Lload_table /* FFI_TYPE_SINT32 */ + .long Lld_int64-Lload_table /* FFI_TYPE_UINT64 */ + .long Lld_int64-Lload_table /* FFI_TYPE_SINT64 */ + .long Lld_struct-Lload_table /* FFI_TYPE_STRUCT */ + .long Lld_int64-Lload_table /* FFI_TYPE_POINTER */ + + .text + .align 3 +Lld_void: + ret + .align 3 +Lld_int8: + movzbl -24(%rsp), %eax + ret + .align 3 +Lld_int16: + movzwl -24(%rsp), %eax + ret + .align 3 +Lld_int32: + movl -24(%rsp), %eax + ret + .align 3 +Lld_int64: + movq -24(%rsp), %rax + ret + .align 3 +Lld_float: + movss -24(%rsp), %xmm0 + ret + .align 3 +Lld_double: + movsd -24(%rsp), %xmm0 + ret + .align 3 +Lld_ldouble: + fldt -24(%rsp) + ret + .align 3 +Lld_struct: + /* There are four possibilities here, %rax/%rdx, %xmm0/%rax, + %rax/%xmm0, %xmm0/%xmm1. We collapse two by always loading + both rdx and xmm1 with the second word. For the remaining, + bit 8 set means xmm0 gets the second word, and bit 9 means + that rax gets the second word. */ + movq -24(%rsp), %rcx + movq -16(%rsp), %rdx + movq -16(%rsp), %xmm1 + testl $0x100, %eax + cmovnz %rdx, %rcx + movd %rcx, %xmm0 + testl $0x200, %eax + movq -24(%rsp), %rax + cmovnz %rdx, %rax + ret + + /* See the comment above Lload_sse; the same logic applies here. */ + .align 3 +LUW8: +Lsave_sse: + movdqa %xmm0, 48(%rsp) + movdqa %xmm1, 64(%rsp) + movdqa %xmm2, 80(%rsp) + movdqa %xmm3, 96(%rsp) + movdqa %xmm4, 112(%rsp) + movdqa %xmm5, 128(%rsp) + movdqa %xmm6, 144(%rsp) + movdqa %xmm7, 160(%rsp) + jmp Lret_from_save_sse + +LUW9: +.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support +EH_frame1: + .set L$set$0,LECIE1-LSCIE1 /* CIE Length */ + .long L$set$0 +LSCIE1: + .long 0x0 /* CIE Identifier Tag */ + .byte 0x1 /* CIE Version */ + .ascii "zR\0" /* CIE Augmentation */ + .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */ + .byte 0x78 /* sleb128 -8; CIE Data Alignment Factor */ + .byte 0x10 /* CIE RA Column */ + .byte 0x1 /* uleb128 0x1; Augmentation size */ + .byte 0x10 /* FDE Encoding (pcrel sdata4) */ + .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */ + .byte 0x7 /* uleb128 0x7 */ + .byte 0x8 /* uleb128 0x8 */ + .byte 0x90 /* DW_CFA_offset, column 0x10 */ + .byte 0x1 + .align 3 +LECIE1: + .globl _ffi_call_unix64.eh +_ffi_call_unix64.eh: +LSFDE1: + .set L$set$1,LEFDE1-LASFDE1 /* FDE Length */ + .long L$set$1 +LASFDE1: + .long LASFDE1-EH_frame1 /* FDE CIE offset */ + .quad LUW0-. /* FDE initial location */ + .set L$set$2,LUW4-LUW0 /* FDE address range */ + .quad L$set$2 + .byte 0x0 /* Augmentation size */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .set L$set$3,LUW1-LUW0 + .long L$set$3 + + /* New stack frame based off rbp. This is a itty bit of unwind + trickery in that the CFA *has* changed. There is no easy way + to describe it correctly on entry to the function. Fortunately, + it doesn't matter too much since at all points we can correctly + unwind back to ffi_call. Note that the location to which we + moved the return address is (the new) CFA-8, so from the + perspective of the unwind info, it hasn't moved. */ + .byte 0xc /* DW_CFA_def_cfa, %rbp offset 32 */ + .byte 0x6 + .byte 0x20 + .byte 0x80+6 /* DW_CFA_offset, %rbp offset 2*-8 */ + .byte 0x2 + .byte 0xa /* DW_CFA_remember_state */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .set L$set$4,LUW2-LUW1 + .long L$set$4 + .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */ + .byte 0x7 + .byte 0x8 + .byte 0xc0+6 /* DW_CFA_restore, %rbp */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .set L$set$5,LUW3-LUW2 + .long L$set$5 + .byte 0xb /* DW_CFA_restore_state */ + + .align 3 +LEFDE1: + .globl _ffi_closure_unix64.eh +_ffi_closure_unix64.eh: +LSFDE3: + .set L$set$6,LEFDE3-LASFDE3 /* FDE Length */ + .long L$set$6 +LASFDE3: + .long LASFDE3-EH_frame1 /* FDE CIE offset */ + .quad LUW5-. /* FDE initial location */ + .set L$set$7,LUW9-LUW5 /* FDE address range */ + .quad L$set$7 + .byte 0x0 /* Augmentation size */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .set L$set$8,LUW6-LUW5 + .long L$set$8 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 208,1 /* uleb128 208 */ + .byte 0xa /* DW_CFA_remember_state */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .set L$set$9,LUW7-LUW6 + .long L$set$9 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .set L$set$10,LUW8-LUW7 + .long L$set$10 + .byte 0xb /* DW_CFA_restore_state */ + + .align 3 +LEFDE3: + .subsections_via_symbols + +#endif /* __x86_64__ */ diff --git a/js/src/ctypes/libffi/src/x86/ffi.c b/js/src/ctypes/libffi/src/x86/ffi.c new file mode 100644 index 0000000..5d053d8 --- /dev/null +++ b/js/src/ctypes/libffi/src/x86/ffi.c @@ -0,0 +1,644 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc. + Copyright (c) 2002 Ranjit Mathew + Copyright (c) 2002 Bo Thorsen + Copyright (c) 2002 Roger Sayle + Copyright (C) 2008 Free Software Foundation, Inc. + + x86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#if !defined(__x86_64__) || defined(_WIN64) + +#ifdef _WIN64 +#include +#endif + +#include +#include + +#include + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +void ffi_prep_args(char *stack, extended_cif *ecif) +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if (ecif->cif->flags == FFI_TYPE_STRUCT +#ifdef X86_WIN64 + && (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2 + && ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8) +#endif + ) + { + *(void **) argp = ecif->rvalue; + argp += sizeof(void*); + } + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + i != 0; + i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if ((sizeof(void*) - 1) & (size_t) argp) + argp = (char *) ALIGN(argp, sizeof(void*)); + + z = (*p_arg)->size; +#ifdef X86_WIN64 + if (z > sizeof(ffi_arg) + || ((*p_arg)->type == FFI_TYPE_STRUCT + && (z != 1 && z != 2 && z != 4 && z != 8)) +#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE + || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE) +#endif + ) + { + z = sizeof(ffi_arg); + *(void **)argp = *p_argv; + } + else if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + memcpy(argp, *p_argv, z); + } + else +#endif + if (z < sizeof(ffi_arg)) + { + z = sizeof(ffi_arg); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_SINT32: + *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv); + break; + + case FFI_TYPE_UINT32: + *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + *(ffi_arg *) argp = *(ffi_arg *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + } + else + { + memcpy(argp, *p_argv, z); + } + p_argv++; +#ifdef X86_WIN64 + argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1); +#else + argp += z; +#endif + } + + return; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + unsigned int i; + ffi_type **ptr; + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_UINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT8: + case FFI_TYPE_SINT16: +#ifdef X86_WIN64 + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: +#endif + case FFI_TYPE_SINT64: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: +#ifndef X86_WIN64 +#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif +#endif + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_UINT64: +#ifdef X86_WIN64 + case FFI_TYPE_POINTER: +#endif + cif->flags = FFI_TYPE_SINT64; + break; + + case FFI_TYPE_STRUCT: +#ifndef X86 + if (cif->rtype->size == 1) + { + cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */ + } + else if (cif->rtype->size == 2) + { + cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */ + } + else if (cif->rtype->size == 4) + { +#ifdef X86_WIN64 + cif->flags = FFI_TYPE_SMALL_STRUCT_4B; +#else + cif->flags = FFI_TYPE_INT; /* same as int type */ +#endif + } + else if (cif->rtype->size == 8) + { + cif->flags = FFI_TYPE_SINT64; /* same as int64 type */ + } + else +#endif + { + cif->flags = FFI_TYPE_STRUCT; + /* allocate space for return value pointer */ + cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG); + } + break; + + default: +#ifdef X86_WIN64 + cif->flags = FFI_TYPE_SINT64; + break; + case FFI_TYPE_INT: + cif->flags = FFI_TYPE_SINT32; +#else + cif->flags = FFI_TYPE_INT; +#endif + break; + } + + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + if (((*ptr)->alignment - 1) & cif->bytes) + cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment); + cif->bytes += ALIGN((*ptr)->size, FFI_SIZEOF_ARG); + } + +#ifdef X86_WIN64 + /* ensure space for storing four registers */ + cif->bytes += 4 * sizeof(ffi_arg); +#endif + +#ifdef X86_DARWIN + cif->bytes = (cif->bytes + 15) & ~0xF; +#endif + + return FFI_OK; +} + +#ifdef X86_WIN64 +extern int +ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *, + unsigned, unsigned, unsigned *, void (*fn)(void)); +#elif defined(X86_WIN32) +extern void +ffi_call_win32(void (*)(char *, extended_cif *), extended_cif *, + unsigned, unsigned, unsigned *, void (*fn)(void)); +#else +extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, + unsigned, unsigned, unsigned *, void (*fn)(void)); +#endif + +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + +#ifdef X86_WIN64 + if (rvalue == NULL + && cif->flags == FFI_TYPE_STRUCT + && cif->rtype->size != 1 && cif->rtype->size != 2 + && cif->rtype->size != 4 && cif->rtype->size != 8) + { + ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF); + } +#else + if (rvalue == NULL + && cif->flags == FFI_TYPE_STRUCT) + { + ecif.rvalue = alloca(cif->rtype->size); + } +#endif + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { +#ifdef X86_WIN64 + case FFI_WIN64: + ffi_call_win64(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; +#elif defined(X86_WIN32) + case FFI_SYSV: + case FFI_STDCALL: + ffi_call_win32(ffi_prep_args, &ecif, cif->bytes, cif->flags, + ecif.rvalue, fn); + break; +#else + case FFI_SYSV: + ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, + fn); + break; +#endif + default: + FFI_ASSERT(0); + break; + } +} + + +/** private members **/ + +/* The following __attribute__((regparm(1))) decorations will have no effect + on MSVC - standard cdecl convention applies. */ +static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, + void** args, ffi_cif* cif); +void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *) + __attribute__ ((regparm(1))); +unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *) + __attribute__ ((regparm(1))); +void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *) + __attribute__ ((regparm(1))); +#ifdef X86_WIN32 +void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *) + __attribute__ ((regparm(1))); +#endif +#ifdef X86_WIN64 +void FFI_HIDDEN ffi_closure_win64 (ffi_closure *); +#endif + +/* This function is jumped to by the trampoline */ + +#ifdef X86_WIN64 +void * FFI_HIDDEN +ffi_closure_win64_inner (ffi_closure *closure, void *args) { + ffi_cif *cif; + void **arg_area; + void *result; + void *resp = &result; + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void*)); + + /* this call will initialize ARG_AREA, such that each + * element in that array points to the corresponding + * value on the stack; and if the function returns + * a structure, it will change RESP to point to the + * structure return address. */ + + ffi_prep_incoming_args_SYSV(args, &resp, arg_area, cif); + + (closure->fun) (cif, resp, arg_area, closure->user_data); + + /* The result is returned in rax. This does the right thing for + result types except for floats; we have to 'mov xmm0, rax' in the + caller to correct this. + TODO: structure sizes of 3 5 6 7 are returned by reference, too!!! + */ + return cif->rtype->size > sizeof(void *) ? resp : *(void **)resp; +} + +#else +unsigned int FFI_HIDDEN __attribute__ ((regparm(1))) +ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args) +{ + /* our various things... */ + ffi_cif *cif; + void **arg_area; + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void*)); + + /* this call will initialize ARG_AREA, such that each + * element in that array points to the corresponding + * value on the stack; and if the function returns + * a structure, it will change RESP to point to the + * structure return address. */ + + ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif); + + (closure->fun) (cif, *respp, arg_area, closure->user_data); + + return cif->flags; +} +#endif /* !X86_WIN64 */ + +static void +ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue, + ffi_cif *cif) +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + +#ifdef X86_WIN64 + if (cif->rtype->size > sizeof(ffi_arg) + || (cif->flags == FFI_TYPE_STRUCT + && (cif->rtype->size != 1 && cif->rtype->size != 2 + && cif->rtype->size != 4 && cif->rtype->size != 8))) { + *rvalue = *(void **) argp; + argp += sizeof(void *); + } +#else + if ( cif->flags == FFI_TYPE_STRUCT ) { + *rvalue = *(void **) argp; + argp += sizeof(void *); + } +#endif + + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if ((sizeof(void*) - 1) & (size_t) argp) { + argp = (char *) ALIGN(argp, sizeof(void*)); + } + +#ifdef X86_WIN64 + if ((*p_arg)->size > sizeof(ffi_arg) + || ((*p_arg)->type == FFI_TYPE_STRUCT + && ((*p_arg)->size != 1 && (*p_arg)->size != 2 + && (*p_arg)->size != 4 && (*p_arg)->size != 8))) + { + z = sizeof(void *); + *p_argv = *(void **)argp; + } + else +#endif + { + z = (*p_arg)->size; + + /* because we're little endian, this is what it turns into. */ + + *p_argv = (void*) argp; + } + + p_argv++; +#ifdef X86_WIN64 + argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1); +#else + argp += z; +#endif + } + + return; +} + +#define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \ +{ unsigned char *__tramp = (unsigned char*)(TRAMP); \ + void* __fun = (void*)(FUN); \ + void* __ctx = (void*)(CTX); \ + *(unsigned char*) &__tramp[0] = 0x41; \ + *(unsigned char*) &__tramp[1] = 0xbb; \ + *(unsigned int*) &__tramp[2] = MASK; /* mov $mask, %r11 */ \ + *(unsigned char*) &__tramp[6] = 0x48; \ + *(unsigned char*) &__tramp[7] = 0xb8; \ + *(void**) &__tramp[8] = __ctx; /* mov __ctx, %rax */ \ + *(unsigned char *) &__tramp[16] = 0x49; \ + *(unsigned char *) &__tramp[17] = 0xba; \ + *(void**) &__tramp[18] = __fun; /* mov __fun, %r10 */ \ + *(unsigned char *) &__tramp[26] = 0x41; \ + *(unsigned char *) &__tramp[27] = 0xff; \ + *(unsigned char *) &__tramp[28] = 0xe2; /* jmp %r10 */ \ + } + +/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */ + +#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ +{ unsigned char *__tramp = (unsigned char*)(TRAMP); \ + unsigned int __fun = (unsigned int)(FUN); \ + unsigned int __ctx = (unsigned int)(CTX); \ + unsigned int __dis = __fun - (__ctx + 10); \ + *(unsigned char*) &__tramp[0] = 0xb8; \ + *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ + *(unsigned char *) &__tramp[5] = 0xe9; \ + *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \ + } + +#define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE) \ +{ unsigned char *__tramp = (unsigned char*)(TRAMP); \ + unsigned int __fun = (unsigned int)(FUN); \ + unsigned int __ctx = (unsigned int)(CTX); \ + unsigned int __dis = __fun - (__ctx + 10); \ + unsigned short __size = (unsigned short)(SIZE); \ + *(unsigned char*) &__tramp[0] = 0xb8; \ + *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ + *(unsigned char *) &__tramp[5] = 0xe8; \ + *(unsigned int*) &__tramp[6] = __dis; /* call __fun */ \ + *(unsigned char *) &__tramp[10] = 0xc2; \ + *(unsigned short*) &__tramp[11] = __size; /* ret __size */ \ + } + +/* the cif must already be prep'ed */ + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) +{ +#ifdef X86_WIN64 +#define ISFLOAT(IDX) (cif->arg_types[IDX]->type == FFI_TYPE_FLOAT || cif->arg_types[IDX]->type == FFI_TYPE_DOUBLE) +#define FLAG(IDX) (cif->nargs>(IDX)&&ISFLOAT(IDX)?(1<<(IDX)):0) + if (cif->abi == FFI_WIN64) + { + int mask = FLAG(0)|FLAG(1)|FLAG(2)|FLAG(3); + FFI_INIT_TRAMPOLINE_WIN64 (&closure->tramp[0], + &ffi_closure_win64, + codeloc, mask); + /* make sure we can execute here */ + } +#else + if (cif->abi == FFI_SYSV) + { + FFI_INIT_TRAMPOLINE (&closure->tramp[0], + &ffi_closure_SYSV, + (void*)codeloc); + } +#ifdef X86_WIN32 + else if (cif->abi == FFI_STDCALL) + { + FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0], + &ffi_closure_STDCALL, + (void*)codeloc, cif->bytes); + } +#endif /* X86_WIN32 */ +#endif /* !X86_WIN64 */ + else + { + return FFI_BAD_ABI; + } + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + +/* ------- Native raw API support -------------------------------- */ + +#if !FFI_NO_RAW_API + +ffi_status +ffi_prep_raw_closure_loc (ffi_raw_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data, + void *codeloc) +{ + int i; + + if (cif->abi != FFI_SYSV) { + return FFI_BAD_ABI; + } + + /* we currently don't support certain kinds of arguments for raw + closures. This should be implemented by a separate assembly + language routine, since it would require argument processing, + something we don't do now for performance. */ + + for (i = cif->nargs-1; i >= 0; i--) + { + FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT); + FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE); + } + + + FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV, + codeloc); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + +static void +ffi_prep_args_raw(char *stack, extended_cif *ecif) +{ + memcpy (stack, ecif->avalue, ecif->cif->bytes); +} + +/* we borrow this routine from libffi (it must be changed, though, to + * actually call the function passed in the first argument. as of + * libffi-1.20, this is not the case.) + */ + +void +ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue) +{ + extended_cif ecif; + void **avalue = (void **)fake_avalue; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + ecif.rvalue = alloca(cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { +#ifdef X86_WIN32 + case FFI_SYSV: + case FFI_STDCALL: + ffi_call_win32(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags, + ecif.rvalue, fn); + break; +#else + case FFI_SYSV: + ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags, + ecif.rvalue, fn); + break; +#endif + default: + FFI_ASSERT(0); + break; + } +} + +#endif + +#endif /* !__x86_64__ || X86_WIN64 */ + diff --git a/js/src/ctypes/libffi/src/x86/ffi64.c b/js/src/ctypes/libffi/src/x86/ffi64.c new file mode 100644 index 0000000..340b8d0 --- /dev/null +++ b/js/src/ctypes/libffi/src/x86/ffi64.c @@ -0,0 +1,627 @@ +/* ----------------------------------------------------------------------- + ffi64.c - Copyright (c) 2002, 2007 Bo Thorsen + Copyright (c) 2008 Red Hat, Inc. + + x86-64 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include +#include + +#include +#include + +#ifdef __x86_64__ + +#define MAX_GPR_REGS 6 +#define MAX_SSE_REGS 8 + +struct register_args +{ + /* Registers for argument passing. */ + UINT64 gpr[MAX_GPR_REGS]; + __int128_t sse[MAX_SSE_REGS]; +}; + +extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags, + void *raddr, void (*fnaddr)(void), unsigned ssecount); + +/* All reference to register classes here is identical to the code in + gcc/config/i386/i386.c. Do *not* change one without the other. */ + +/* Register class used for passing given 64bit part of the argument. + These represent classes as documented by the PS ABI, with the + exception of SSESF, SSEDF classes, that are basically SSE class, + just gcc will use SF or DFmode move instead of DImode to avoid + reformatting penalties. + + Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves + whenever possible (upper half does contain padding). */ +enum x86_64_reg_class + { + X86_64_NO_CLASS, + X86_64_INTEGER_CLASS, + X86_64_INTEGERSI_CLASS, + X86_64_SSE_CLASS, + X86_64_SSESF_CLASS, + X86_64_SSEDF_CLASS, + X86_64_SSEUP_CLASS, + X86_64_X87_CLASS, + X86_64_X87UP_CLASS, + X86_64_COMPLEX_X87_CLASS, + X86_64_MEMORY_CLASS + }; + +#define MAX_CLASSES 4 + +#define SSE_CLASS_P(X) ((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS) + +/* x86-64 register passing implementation. See x86-64 ABI for details. Goal + of this code is to classify each 8bytes of incoming argument by the register + class and assign registers accordingly. */ + +/* Return the union class of CLASS1 and CLASS2. + See the x86-64 PS ABI for details. */ + +static enum x86_64_reg_class +merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) +{ + /* Rule #1: If both classes are equal, this is the resulting class. */ + if (class1 == class2) + return class1; + + /* Rule #2: If one of the classes is NO_CLASS, the resulting class is + the other class. */ + if (class1 == X86_64_NO_CLASS) + return class2; + if (class2 == X86_64_NO_CLASS) + return class1; + + /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */ + if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */ + if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS) + || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS)) + return X86_64_INTEGERSI_CLASS; + if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS + || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) + return X86_64_INTEGER_CLASS; + + /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class, + MEMORY is used. */ + if (class1 == X86_64_X87_CLASS + || class1 == X86_64_X87UP_CLASS + || class1 == X86_64_COMPLEX_X87_CLASS + || class2 == X86_64_X87_CLASS + || class2 == X86_64_X87UP_CLASS + || class2 == X86_64_COMPLEX_X87_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #6: Otherwise class SSE is used. */ + return X86_64_SSE_CLASS; +} + +/* Classify the argument of type TYPE and mode MODE. + CLASSES will be filled by the register class used to pass each word + of the operand. The number of words is returned. In case the parameter + should be passed in memory, 0 is returned. As a special case for zero + sized containers, classes[0] will be NO_CLASS and 1 is returned. + + See the x86-64 PS ABI for details. +*/ +static int +classify_argument (ffi_type *type, enum x86_64_reg_class classes[], + size_t byte_offset) +{ + switch (type->type) + { + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_POINTER: + { + int size = byte_offset + type->size; + + if (size <= 4) + { + classes[0] = X86_64_INTEGERSI_CLASS; + return 1; + } + else if (size <= 8) + { + classes[0] = X86_64_INTEGER_CLASS; + return 1; + } + else if (size <= 12) + { + classes[0] = X86_64_INTEGER_CLASS; + classes[1] = X86_64_INTEGERSI_CLASS; + return 2; + } + else if (size <= 16) + { + classes[0] = classes[1] = X86_64_INTEGERSI_CLASS; + return 2; + } + else + FFI_ASSERT (0); + } + case FFI_TYPE_FLOAT: + if (!(byte_offset % 8)) + classes[0] = X86_64_SSESF_CLASS; + else + classes[0] = X86_64_SSE_CLASS; + return 1; + case FFI_TYPE_DOUBLE: + classes[0] = X86_64_SSEDF_CLASS; + return 1; + case FFI_TYPE_LONGDOUBLE: + classes[0] = X86_64_X87_CLASS; + classes[1] = X86_64_X87UP_CLASS; + return 2; + case FFI_TYPE_STRUCT: + { + const int UNITS_PER_WORD = 8; + int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + ffi_type **ptr; + int i; + enum x86_64_reg_class subclasses[MAX_CLASSES]; + + /* If the struct is larger than 32 bytes, pass it on the stack. */ + if (type->size > 32) + return 0; + + for (i = 0; i < words; i++) + classes[i] = X86_64_NO_CLASS; + + /* Zero sized arrays or structures are NO_CLASS. We return 0 to + signalize memory class, so handle it as special case. */ + if (!words) + { + classes[0] = X86_64_NO_CLASS; + return 1; + } + + /* Merge the fields of structure. */ + for (ptr = type->elements; *ptr != NULL; ptr++) + { + int num; + + byte_offset = ALIGN (byte_offset, (*ptr)->alignment); + + num = classify_argument (*ptr, subclasses, byte_offset % 8); + if (num == 0) + return 0; + for (i = 0; i < num; i++) + { + int pos = byte_offset / 8; + classes[i + pos] = + merge_classes (subclasses[i], classes[i + pos]); + } + + byte_offset += (*ptr)->size; + } + + if (words > 2) + { + /* When size > 16 bytes, if the first one isn't + X86_64_SSE_CLASS or any other ones aren't + X86_64_SSEUP_CLASS, everything should be passed in + memory. */ + if (classes[0] != X86_64_SSE_CLASS) + return 0; + + for (i = 1; i < words; i++) + if (classes[i] != X86_64_SSEUP_CLASS) + return 0; + } + + /* Final merger cleanup. */ + for (i = 0; i < words; i++) + { + /* If one class is MEMORY, everything should be passed in + memory. */ + if (classes[i] == X86_64_MEMORY_CLASS) + return 0; + + /* The X86_64_SSEUP_CLASS should be always preceded by + X86_64_SSE_CLASS or X86_64_SSEUP_CLASS. */ + if (classes[i] == X86_64_SSEUP_CLASS + && classes[i - 1] != X86_64_SSE_CLASS + && classes[i - 1] != X86_64_SSEUP_CLASS) + { + /* The first one should never be X86_64_SSEUP_CLASS. */ + FFI_ASSERT (i != 0); + classes[i] = X86_64_SSE_CLASS; + } + + /* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS, + everything should be passed in memory. */ + if (classes[i] == X86_64_X87UP_CLASS + && (classes[i - 1] != X86_64_X87_CLASS)) + { + /* The first one should never be X86_64_X87UP_CLASS. */ + FFI_ASSERT (i != 0); + return 0; + } + } + return words; + } + + default: + FFI_ASSERT(0); + } + return 0; /* Never reached. */ +} + +/* Examine the argument and return set number of register required in each + class. Return zero iff parameter should be passed in memory, otherwise + the number of registers. */ + +static int +examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES], + _Bool in_return, int *pngpr, int *pnsse) +{ + int i, n, ngpr, nsse; + + n = classify_argument (type, classes, 0); + if (n == 0) + return 0; + + ngpr = nsse = 0; + for (i = 0; i < n; ++i) + switch (classes[i]) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + ngpr++; + break; + case X86_64_SSE_CLASS: + case X86_64_SSESF_CLASS: + case X86_64_SSEDF_CLASS: + nsse++; + break; + case X86_64_NO_CLASS: + case X86_64_SSEUP_CLASS: + break; + case X86_64_X87_CLASS: + case X86_64_X87UP_CLASS: + case X86_64_COMPLEX_X87_CLASS: + return in_return != 0; + default: + abort (); + } + + *pngpr = ngpr; + *pnsse = nsse; + + return n; +} + +/* Perform machine dependent cif processing. */ + +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + int gprcount, ssecount, i, avn, n, ngpr, nsse, flags; + enum x86_64_reg_class classes[MAX_CLASSES]; + size_t bytes; + + gprcount = ssecount = 0; + + flags = cif->rtype->type; + if (flags != FFI_TYPE_VOID) + { + n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); + if (n == 0) + { + /* The return value is passed in memory. A pointer to that + memory is the first argument. Allocate a register for it. */ + gprcount++; + /* We don't have to do anything in asm for the return. */ + flags = FFI_TYPE_VOID; + } + else if (flags == FFI_TYPE_STRUCT) + { + /* Mark which registers the result appears in. */ + _Bool sse0 = SSE_CLASS_P (classes[0]); + _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]); + if (sse0 && !sse1) + flags |= 1 << 8; + else if (!sse0 && sse1) + flags |= 1 << 9; + else if (sse0 && sse1) + flags |= 1 << 10; + /* Mark the true size of the structure. */ + flags |= cif->rtype->size << 12; + } + } + + /* Go over all arguments and determine the way they should be passed. + If it's in a register and there is space for it, let that be so. If + not, add it's size to the stack byte count. */ + for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++) + { + if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0 + || gprcount + ngpr > MAX_GPR_REGS + || ssecount + nsse > MAX_SSE_REGS) + { + long align = cif->arg_types[i]->alignment; + + if (align < 8) + align = 8; + + bytes = ALIGN (bytes, align); + bytes += cif->arg_types[i]->size; + } + else + { + gprcount += ngpr; + ssecount += nsse; + } + } + if (ssecount) + flags |= 1 << 11; + cif->flags = flags; + cif->bytes = ALIGN (bytes, 8); + + return FFI_OK; +} + +void +ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) +{ + enum x86_64_reg_class classes[MAX_CLASSES]; + char *stack, *argp; + ffi_type **arg_types; + int gprcount, ssecount, ngpr, nsse, i, avn; + _Bool ret_in_memory; + struct register_args *reg_args; + + /* Can't call 32-bit mode from 64-bit mode. */ + FFI_ASSERT (cif->abi == FFI_UNIX64); + + /* If the return value is a struct and we don't have a return value + address then we need to make one. Note the setting of flags to + VOID above in ffi_prep_cif_machdep. */ + ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT + && (cif->flags & 0xff) == FFI_TYPE_VOID); + if (rvalue == NULL && ret_in_memory) + rvalue = alloca (cif->rtype->size); + + /* Allocate the space for the arguments, plus 4 words of temp space. */ + stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8); + reg_args = (struct register_args *) stack; + argp = stack + sizeof (struct register_args); + + gprcount = ssecount = 0; + + /* If the return value is passed in memory, add the pointer as the + first integer argument. */ + if (ret_in_memory) + reg_args->gpr[gprcount++] = (long) rvalue; + + avn = cif->nargs; + arg_types = cif->arg_types; + + for (i = 0; i < avn; ++i) + { + size_t size = arg_types[i]->size; + int n; + + n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); + if (n == 0 + || gprcount + ngpr > MAX_GPR_REGS + || ssecount + nsse > MAX_SSE_REGS) + { + long align = arg_types[i]->alignment; + + /* Stack arguments are *always* at least 8 byte aligned. */ + if (align < 8) + align = 8; + + /* Pass this argument in memory. */ + argp = (void *) ALIGN (argp, align); + memcpy (argp, avalue[i], size); + argp += size; + } + else + { + /* The argument is passed entirely in registers. */ + char *a = (char *) avalue[i]; + int j; + + for (j = 0; j < n; j++, a += 8, size -= 8) + { + switch (classes[j]) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + reg_args->gpr[gprcount] = 0; + memcpy (®_args->gpr[gprcount], a, size < 8 ? size : 8); + gprcount++; + break; + case X86_64_SSE_CLASS: + case X86_64_SSEDF_CLASS: + reg_args->sse[ssecount++] = *(UINT64 *) a; + break; + case X86_64_SSESF_CLASS: + reg_args->sse[ssecount++] = *(UINT32 *) a; + break; + default: + abort(); + } + } + } + } + + ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args), + cif->flags, rvalue, fn, ssecount); +} + + +extern void ffi_closure_unix64(void); + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data, + void *codeloc) +{ + volatile unsigned short *tramp; + + tramp = (volatile unsigned short *) &closure->tramp[0]; + + tramp[0] = 0xbb49; /* mov , %r11 */ + *(void * volatile *) &tramp[1] = ffi_closure_unix64; + tramp[5] = 0xba49; /* mov , %r10 */ + *(void * volatile *) &tramp[6] = codeloc; + + /* Set the carry bit iff the function uses any sse registers. + This is clc or stc, together with the first byte of the jmp. */ + tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8; + + tramp[11] = 0xe3ff; /* jmp *%r11 */ + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} + +int +ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue, + struct register_args *reg_args, char *argp) +{ + ffi_cif *cif; + void **avalue; + ffi_type **arg_types; + long i, avn; + int gprcount, ssecount, ngpr, nsse; + int ret; + + cif = closure->cif; + avalue = alloca(cif->nargs * sizeof(void *)); + gprcount = ssecount = 0; + + ret = cif->rtype->type; + if (ret != FFI_TYPE_VOID) + { + enum x86_64_reg_class classes[MAX_CLASSES]; + int n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); + if (n == 0) + { + /* The return value goes in memory. Arrange for the closure + return value to go directly back to the original caller. */ + rvalue = (void *) reg_args->gpr[gprcount++]; + /* We don't have to do anything in asm for the return. */ + ret = FFI_TYPE_VOID; + } + else if (ret == FFI_TYPE_STRUCT && n == 2) + { + /* Mark which register the second word of the structure goes in. */ + _Bool sse0 = SSE_CLASS_P (classes[0]); + _Bool sse1 = SSE_CLASS_P (classes[1]); + if (!sse0 && sse1) + ret |= 1 << 8; + else if (sse0 && !sse1) + ret |= 1 << 9; + } + } + + avn = cif->nargs; + arg_types = cif->arg_types; + + for (i = 0; i < avn; ++i) + { + enum x86_64_reg_class classes[MAX_CLASSES]; + int n; + + n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); + if (n == 0 + || gprcount + ngpr > MAX_GPR_REGS + || ssecount + nsse > MAX_SSE_REGS) + { + long align = arg_types[i]->alignment; + + /* Stack arguments are *always* at least 8 byte aligned. */ + if (align < 8) + align = 8; + + /* Pass this argument in memory. */ + argp = (void *) ALIGN (argp, align); + avalue[i] = argp; + argp += arg_types[i]->size; + } + /* If the argument is in a single register, or two consecutive + integer registers, then we can use that address directly. */ + else if (n == 1 + || (n == 2 && !(SSE_CLASS_P (classes[0]) + || SSE_CLASS_P (classes[1])))) + { + /* The argument is in a single register. */ + if (SSE_CLASS_P (classes[0])) + { + avalue[i] = ®_args->sse[ssecount]; + ssecount += n; + } + else + { + avalue[i] = ®_args->gpr[gprcount]; + gprcount += n; + } + } + /* Otherwise, allocate space to make them consecutive. */ + else + { + char *a = alloca (16); + int j; + + avalue[i] = a; + for (j = 0; j < n; j++, a += 8) + { + if (SSE_CLASS_P (classes[j])) + memcpy (a, ®_args->sse[ssecount++], 8); + else + memcpy (a, ®_args->gpr[gprcount++], 8); + } + } + } + + /* Invoke the closure. */ + closure->fun (cif, rvalue, avalue, closure->user_data); + + /* Tell assembly how to perform return type promotions. */ + return ret; +} + +#endif /* __x86_64__ */ diff --git a/js/src/ctypes/libffi/src/x86/ffitarget.h b/js/src/ctypes/libffi/src/x86/ffitarget.h new file mode 100644 index 0000000..542e6d4 --- /dev/null +++ b/js/src/ctypes/libffi/src/x86/ffitarget.h @@ -0,0 +1,121 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003, 2010 Red Hat, Inc. + Copyright (C) 2008 Free Software Foundation, Inc. + + Target configuration macros for x86 and x86-64. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- System specific configurations ----------------------------------- */ + +/* For code common to all platforms on x86 and x86_64. */ +#define X86_ANY + +#if defined (X86_64) && defined (__i386__) +#undef X86_64 +#define X86 +#endif + +#ifdef X86_WIN64 +#define FFI_SIZEOF_ARG 8 +#define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */ +#endif + +/* ---- Generic type definitions ----------------------------------------- */ + +#ifndef LIBFFI_ASM +#ifdef X86_WIN64 +#ifdef _MSC_VER +typedef unsigned __int64 ffi_arg; +typedef __int64 ffi_sarg; +#else +typedef unsigned long long ffi_arg; +typedef long long ffi_sarg; +#endif +#else +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; +#endif + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + + /* ---- Intel x86 Win32 ---------- */ +#ifdef X86_WIN32 + FFI_SYSV, + FFI_STDCALL, + FFI_LAST_ABI, + /* TODO: Add fastcall support for the sake of completeness */ + FFI_DEFAULT_ABI = FFI_SYSV + +#elif defined(X86_WIN64) + FFI_WIN64, + FFI_LAST_ABI, + FFI_DEFAULT_ABI = FFI_WIN64 + +#else + /* ---- Intel x86 and AMD x86-64 - */ + FFI_SYSV, + FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */ + FFI_LAST_ABI, +#if defined(__i386__) || defined(__i386) + FFI_DEFAULT_ABI = FFI_SYSV +#else + FFI_DEFAULT_ABI = FFI_UNIX64 +#endif +#endif +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) +#define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) +#define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3) + +#if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) +#define FFI_TRAMPOLINE_SIZE 24 +#define FFI_NATIVE_RAW_API 0 +#else +#ifdef X86_WIN32 +#define FFI_TRAMPOLINE_SIZE 13 +#else +#ifdef X86_WIN64 +#define FFI_TRAMPOLINE_SIZE 29 +#define FFI_NATIVE_RAW_API 0 +#define FFI_NO_RAW_API 1 +#else +#define FFI_TRAMPOLINE_SIZE 10 +#endif +#endif +#ifndef X86_WIN64 +#define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ +#endif +#endif + +#endif + diff --git a/js/src/ctypes/libffi/src/x86/freebsd.S b/js/src/ctypes/libffi/src/x86/freebsd.S new file mode 100644 index 0000000..afde513 --- /dev/null +++ b/js/src/ctypes/libffi/src/x86/freebsd.S @@ -0,0 +1,458 @@ +/* ----------------------------------------------------------------------- + freebsd.S - Copyright (c) 1996, 1998, 2001, 2002, 2003, 2005 Red Hat, Inc. + Copyright (c) 2008 Björn König + + X86 Foreign Function Interface for FreeBSD + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +----------------------------------------------------------------------- */ + +#ifndef __x86_64__ + +#define LIBFFI_ASM +#include +#include + +.text + +.globl ffi_prep_args + + .align 4 +.globl ffi_call_SYSV + .type ffi_call_SYSV,@function + +ffi_call_SYSV: +.LFB1: + pushl %ebp +.LCFI0: + movl %esp,%ebp +.LCFI1: + /* Make room for all of the new args. */ + movl 16(%ebp),%ecx + subl %ecx,%esp + + movl %esp,%eax + + /* Place all of the ffi_prep_args in position */ + pushl 12(%ebp) + pushl %eax + call *8(%ebp) + + /* Return stack to previous state and call the function */ + addl $8,%esp + + call *28(%ebp) + + /* Load %ecx with the return type code */ + movl 20(%ebp),%ecx + + /* Protect %esi. We're going to pop it in the epilogue. */ + pushl %esi + + /* If the return value pointer is NULL, assume no return value. */ + cmpl $0,24(%ebp) + jne 0f + + /* Even if there is no space for the return value, we are + obliged to handle floating-point values. */ + cmpl $FFI_TYPE_FLOAT,%ecx + jne noretval + fstp %st(0) + + jmp epilogue + +0: + call 1f + +.Lstore_table: + .long noretval-.Lstore_table /* FFI_TYPE_VOID */ + .long retint-.Lstore_table /* FFI_TYPE_INT */ + .long retfloat-.Lstore_table /* FFI_TYPE_FLOAT */ + .long retdouble-.Lstore_table /* FFI_TYPE_DOUBLE */ + .long retlongdouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */ + .long retuint8-.Lstore_table /* FFI_TYPE_UINT8 */ + .long retsint8-.Lstore_table /* FFI_TYPE_SINT8 */ + .long retuint16-.Lstore_table /* FFI_TYPE_UINT16 */ + .long retsint16-.Lstore_table /* FFI_TYPE_SINT16 */ + .long retint-.Lstore_table /* FFI_TYPE_UINT32 */ + .long retint-.Lstore_table /* FFI_TYPE_SINT32 */ + .long retint64-.Lstore_table /* FFI_TYPE_UINT64 */ + .long retint64-.Lstore_table /* FFI_TYPE_SINT64 */ + .long retstruct-.Lstore_table /* FFI_TYPE_STRUCT */ + .long retint-.Lstore_table /* FFI_TYPE_POINTER */ + .long retstruct1b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_1B */ + .long retstruct2b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_2B */ + +1: + pop %esi + add (%esi, %ecx, 4), %esi + jmp *%esi + + /* Sign/zero extend as appropriate. */ +retsint8: + movsbl %al, %eax + jmp retint + +retsint16: + movswl %ax, %eax + jmp retint + +retuint8: + movzbl %al, %eax + jmp retint + +retuint16: + movzwl %ax, %eax + jmp retint + +retfloat: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstps (%ecx) + jmp epilogue + +retdouble: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstpl (%ecx) + jmp epilogue + +retlongdouble: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstpt (%ecx) + jmp epilogue + +retint64: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + movl %edx,4(%ecx) + jmp epilogue + +retstruct1b: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movb %al,0(%ecx) + jmp epilogue + +retstruct2b: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movw %ax,0(%ecx) + jmp epilogue + +retint: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + +retstruct: + /* Nothing to do! */ + +noretval: +epilogue: + popl %esi + movl %ebp,%esp + popl %ebp + ret +.LFE1: +.ffi_call_SYSV_end: + .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV + + .align 4 +FFI_HIDDEN (ffi_closure_SYSV) +.globl ffi_closure_SYSV + .type ffi_closure_SYSV, @function + +ffi_closure_SYSV: +.LFB2: + pushl %ebp +.LCFI2: + movl %esp, %ebp +.LCFI3: + subl $40, %esp + leal -24(%ebp), %edx + movl %edx, -12(%ebp) /* resp */ + leal 8(%ebp), %edx + movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */ + leal -12(%ebp), %edx + movl %edx, (%esp) /* &resp */ +#if defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE || !defined __PIC__ + call ffi_closure_SYSV_inner +#else + movl %ebx, 8(%esp) +.LCFI7: + call 1f +1: popl %ebx + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx + call ffi_closure_SYSV_inner@PLT + movl 8(%esp), %ebx +#endif + movl -12(%ebp), %ecx + cmpl $FFI_TYPE_INT, %eax + je .Lcls_retint + + /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16, + FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */ + cmpl $FFI_TYPE_UINT64, %eax + jge 0f + cmpl $FFI_TYPE_UINT8, %eax + jge .Lcls_retint + +0: cmpl $FFI_TYPE_FLOAT, %eax + je .Lcls_retfloat + cmpl $FFI_TYPE_DOUBLE, %eax + je .Lcls_retdouble + cmpl $FFI_TYPE_LONGDOUBLE, %eax + je .Lcls_retldouble + cmpl $FFI_TYPE_SINT64, %eax + je .Lcls_retllong + cmpl $FFI_TYPE_SMALL_STRUCT_1B, %eax + je .Lcls_retstruct1b + cmpl $FFI_TYPE_SMALL_STRUCT_2B, %eax + je .Lcls_retstruct2b + cmpl $FFI_TYPE_STRUCT, %eax + je .Lcls_retstruct +.Lcls_epilogue: + movl %ebp, %esp + popl %ebp + ret +.Lcls_retint: + movl (%ecx), %eax + jmp .Lcls_epilogue +.Lcls_retfloat: + flds (%ecx) + jmp .Lcls_epilogue +.Lcls_retdouble: + fldl (%ecx) + jmp .Lcls_epilogue +.Lcls_retldouble: + fldt (%ecx) + jmp .Lcls_epilogue +.Lcls_retllong: + movl (%ecx), %eax + movl 4(%ecx), %edx + jmp .Lcls_epilogue +.Lcls_retstruct1b: + movsbl (%ecx), %eax + jmp .Lcls_epilogue +.Lcls_retstruct2b: + movswl (%ecx), %eax + jmp .Lcls_epilogue +.Lcls_retstruct: + movl %ebp, %esp + popl %ebp + ret $4 +.LFE2: + .size ffi_closure_SYSV, .-ffi_closure_SYSV + +#if !FFI_NO_RAW_API + +#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3) +#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4) +#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4) +#define CIF_FLAGS_OFFSET 20 + + .align 4 +FFI_HIDDEN (ffi_closure_raw_SYSV) +.globl ffi_closure_raw_SYSV + .type ffi_closure_raw_SYSV, @function + +ffi_closure_raw_SYSV: +.LFB3: + pushl %ebp +.LCFI4: + movl %esp, %ebp +.LCFI5: + pushl %esi +.LCFI6: + subl $36, %esp + movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */ + movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */ + movl %edx, 12(%esp) /* user_data */ + leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */ + movl %edx, 8(%esp) /* raw_args */ + leal -24(%ebp), %edx + movl %edx, 4(%esp) /* &res */ + movl %esi, (%esp) /* cif */ + call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */ + movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */ + cmpl $FFI_TYPE_INT, %eax + je .Lrcls_retint + + /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16, + FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */ + cmpl $FFI_TYPE_UINT64, %eax + jge 0f + cmpl $FFI_TYPE_UINT8, %eax + jge .Lrcls_retint +0: + cmpl $FFI_TYPE_FLOAT, %eax + je .Lrcls_retfloat + cmpl $FFI_TYPE_DOUBLE, %eax + je .Lrcls_retdouble + cmpl $FFI_TYPE_LONGDOUBLE, %eax + je .Lrcls_retldouble + cmpl $FFI_TYPE_SINT64, %eax + je .Lrcls_retllong +.Lrcls_epilogue: + addl $36, %esp + popl %esi + popl %ebp + ret +.Lrcls_retint: + movl -24(%ebp), %eax + jmp .Lrcls_epilogue +.Lrcls_retfloat: + flds -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retdouble: + fldl -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retldouble: + fldt -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retllong: + movl -24(%ebp), %eax + movl -20(%ebp), %edx + jmp .Lrcls_epilogue +.LFE3: + .size ffi_closure_raw_SYSV, .-ffi_closure_raw_SYSV +#endif + + .section .eh_frame,EH_FRAME_FLAGS,@progbits +.Lframe1: + .long .LECIE1-.LSCIE1 /* Length of Common Information Entry */ +.LSCIE1: + .long 0x0 /* CIE Identifier Tag */ + .byte 0x1 /* CIE Version */ +#ifdef __PIC__ + .ascii "zR\0" /* CIE Augmentation */ +#else + .ascii "\0" /* CIE Augmentation */ +#endif + .byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */ + .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */ + .byte 0x8 /* CIE RA Column */ +#ifdef __PIC__ + .byte 0x1 /* .uleb128 0x1; Augmentation size */ + .byte 0x1b /* FDE Encoding (pcrel sdata4) */ +#endif + .byte 0xc /* DW_CFA_def_cfa */ + .byte 0x4 /* .uleb128 0x4 */ + .byte 0x4 /* .uleb128 0x4 */ + .byte 0x88 /* DW_CFA_offset, column 0x8 */ + .byte 0x1 /* .uleb128 0x1 */ + .align 4 +.LECIE1: +.LSFDE1: + .long .LEFDE1-.LASFDE1 /* FDE Length */ +.LASFDE1: + .long .LASFDE1-.Lframe1 /* FDE CIE offset */ +#ifdef __PIC__ + .long .LFB1-. /* FDE initial location */ +#else + .long .LFB1 /* FDE initial location */ +#endif + .long .LFE1-.LFB1 /* FDE address range */ +#ifdef __PIC__ + .byte 0x0 /* .uleb128 0x0; Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI0-.LFB1 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 /* .uleb128 0x8 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 */ + .byte 0x2 /* .uleb128 0x2 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI1-.LCFI0 + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0x5 /* .uleb128 0x5 */ + .align 4 +.LEFDE1: +.LSFDE2: + .long .LEFDE2-.LASFDE2 /* FDE Length */ +.LASFDE2: + .long .LASFDE2-.Lframe1 /* FDE CIE offset */ +#ifdef __PIC__ + .long .LFB2-. /* FDE initial location */ +#else + .long .LFB2 +#endif + .long .LFE2-.LFB2 /* FDE address range */ +#ifdef __PIC__ + .byte 0x0 /* .uleb128 0x0; Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI2-.LFB2 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 /* .uleb128 0x8 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 */ + .byte 0x2 /* .uleb128 0x2 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI3-.LCFI2 + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0x5 /* .uleb128 0x5 */ +#if !defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE && defined __PIC__ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI7-.LCFI3 + .byte 0x83 /* DW_CFA_offset, column 0x3 */ + .byte 0xa /* .uleb128 0xa */ +#endif + .align 4 +.LEFDE2: + +#if !FFI_NO_RAW_API + +.LSFDE3: + .long .LEFDE3-.LASFDE3 /* FDE Length */ +.LASFDE3: + .long .LASFDE3-.Lframe1 /* FDE CIE offset */ +#ifdef __PIC__ + .long .LFB3-. /* FDE initial location */ +#else + .long .LFB3 +#endif + .long .LFE3-.LFB3 /* FDE address range */ +#ifdef __PIC__ + .byte 0x0 /* .uleb128 0x0; Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI4-.LFB3 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 /* .uleb128 0x8 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 */ + .byte 0x2 /* .uleb128 0x2 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI5-.LCFI4 + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0x5 /* .uleb128 0x5 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI6-.LCFI5 + .byte 0x86 /* DW_CFA_offset, column 0x6 */ + .byte 0x3 /* .uleb128 0x3 */ + .align 4 +.LEFDE3: + +#endif + +#endif /* ifndef __x86_64__ */ diff --git a/js/src/ctypes/libffi/src/x86/sysv.S b/js/src/ctypes/libffi/src/x86/sysv.S new file mode 100644 index 0000000..f3b0bd5 --- /dev/null +++ b/js/src/ctypes/libffi/src/x86/sysv.S @@ -0,0 +1,467 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 1996, 1998, 2001-2003, 2005, 2008, 2010 Red Hat, Inc. + + X86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#ifndef __x86_64__ + +#define LIBFFI_ASM +#include +#include + +.text + +.globl ffi_prep_args + + .align 4 +.globl ffi_call_SYSV + .type ffi_call_SYSV,@function + +ffi_call_SYSV: +.LFB1: + pushl %ebp +.LCFI0: + movl %esp,%ebp +.LCFI1: + /* Make room for all of the new args. */ + movl 16(%ebp),%ecx + subl %ecx,%esp + + /* Align the stack pointer to 16-bytes */ + andl $0xfffffff0, %esp + + movl %esp,%eax + + /* Place all of the ffi_prep_args in position */ + pushl 12(%ebp) + pushl %eax + call *8(%ebp) + + /* Return stack to previous state and call the function */ + addl $8,%esp + + call *28(%ebp) + + /* Load %ecx with the return type code */ + movl 20(%ebp),%ecx + + /* Protect %esi. We're going to pop it in the epilogue. */ + pushl %esi + + /* If the return value pointer is NULL, assume no return value. */ + cmpl $0,24(%ebp) + jne 0f + + /* Even if there is no space for the return value, we are + obliged to handle floating-point values. */ + cmpl $FFI_TYPE_FLOAT,%ecx + jne noretval + fstp %st(0) + + jmp epilogue + +0: + call 1f + +.Lstore_table: + .long noretval-.Lstore_table /* FFI_TYPE_VOID */ + .long retint-.Lstore_table /* FFI_TYPE_INT */ + .long retfloat-.Lstore_table /* FFI_TYPE_FLOAT */ + .long retdouble-.Lstore_table /* FFI_TYPE_DOUBLE */ + .long retlongdouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */ + .long retuint8-.Lstore_table /* FFI_TYPE_UINT8 */ + .long retsint8-.Lstore_table /* FFI_TYPE_SINT8 */ + .long retuint16-.Lstore_table /* FFI_TYPE_UINT16 */ + .long retsint16-.Lstore_table /* FFI_TYPE_SINT16 */ + .long retint-.Lstore_table /* FFI_TYPE_UINT32 */ + .long retint-.Lstore_table /* FFI_TYPE_SINT32 */ + .long retint64-.Lstore_table /* FFI_TYPE_UINT64 */ + .long retint64-.Lstore_table /* FFI_TYPE_SINT64 */ + .long retstruct-.Lstore_table /* FFI_TYPE_STRUCT */ + .long retint-.Lstore_table /* FFI_TYPE_POINTER */ + +1: + pop %esi + add (%esi, %ecx, 4), %esi + jmp *%esi + + /* Sign/zero extend as appropriate. */ +retsint8: + movsbl %al, %eax + jmp retint + +retsint16: + movswl %ax, %eax + jmp retint + +retuint8: + movzbl %al, %eax + jmp retint + +retuint16: + movzwl %ax, %eax + jmp retint + +retfloat: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstps (%ecx) + jmp epilogue + +retdouble: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstpl (%ecx) + jmp epilogue + +retlongdouble: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstpt (%ecx) + jmp epilogue + +retint64: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + movl %edx,4(%ecx) + jmp epilogue + +retint: + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + +retstruct: + /* Nothing to do! */ + +noretval: +epilogue: + popl %esi + movl %ebp,%esp + popl %ebp + ret +.LFE1: +.ffi_call_SYSV_end: + .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV + + .align 4 +FFI_HIDDEN (ffi_closure_SYSV) +.globl ffi_closure_SYSV + .type ffi_closure_SYSV, @function + +ffi_closure_SYSV: +.LFB2: + pushl %ebp +.LCFI2: + movl %esp, %ebp +.LCFI3: + subl $40, %esp + leal -24(%ebp), %edx + movl %edx, -12(%ebp) /* resp */ + leal 8(%ebp), %edx + movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */ + leal -12(%ebp), %edx + movl %edx, (%esp) /* &resp */ +#if defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE || !defined __PIC__ + call ffi_closure_SYSV_inner +#else + movl %ebx, 8(%esp) +.LCFI7: + call 1f +1: popl %ebx + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx + call ffi_closure_SYSV_inner@PLT + movl 8(%esp), %ebx +#endif + movl -12(%ebp), %ecx + cmpl $FFI_TYPE_INT, %eax + je .Lcls_retint + + /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16, + FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */ + cmpl $FFI_TYPE_UINT64, %eax + jge 0f + cmpl $FFI_TYPE_UINT8, %eax + jge .Lcls_retint + +0: cmpl $FFI_TYPE_FLOAT, %eax + je .Lcls_retfloat + cmpl $FFI_TYPE_DOUBLE, %eax + je .Lcls_retdouble + cmpl $FFI_TYPE_LONGDOUBLE, %eax + je .Lcls_retldouble + cmpl $FFI_TYPE_SINT64, %eax + je .Lcls_retllong + cmpl $FFI_TYPE_STRUCT, %eax + je .Lcls_retstruct +.Lcls_epilogue: + movl %ebp, %esp + popl %ebp + ret +.Lcls_retint: + movl (%ecx), %eax + jmp .Lcls_epilogue +.Lcls_retfloat: + flds (%ecx) + jmp .Lcls_epilogue +.Lcls_retdouble: + fldl (%ecx) + jmp .Lcls_epilogue +.Lcls_retldouble: + fldt (%ecx) + jmp .Lcls_epilogue +.Lcls_retllong: + movl (%ecx), %eax + movl 4(%ecx), %edx + jmp .Lcls_epilogue +.Lcls_retstruct: + movl %ebp, %esp + popl %ebp + ret $4 +.LFE2: + .size ffi_closure_SYSV, .-ffi_closure_SYSV + +#if !FFI_NO_RAW_API + +/* Precalculate for e.g. the Solaris 10/x86 assembler. */ +#if FFI_TRAMPOLINE_SIZE == 10 +#define RAW_CLOSURE_CIF_OFFSET 12 +#define RAW_CLOSURE_FUN_OFFSET 16 +#define RAW_CLOSURE_USER_DATA_OFFSET 20 +#elif FFI_TRAMPOLINE_SIZE == 24 +#define RAW_CLOSURE_CIF_OFFSET 24 +#define RAW_CLOSURE_FUN_OFFSET 28 +#define RAW_CLOSURE_USER_DATA_OFFSET 32 +#else +#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3) +#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4) +#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4) +#endif +#define CIF_FLAGS_OFFSET 20 + + .align 4 +FFI_HIDDEN (ffi_closure_raw_SYSV) +.globl ffi_closure_raw_SYSV + .type ffi_closure_raw_SYSV, @function + +ffi_closure_raw_SYSV: +.LFB3: + pushl %ebp +.LCFI4: + movl %esp, %ebp +.LCFI5: + pushl %esi +.LCFI6: + subl $36, %esp + movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */ + movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */ + movl %edx, 12(%esp) /* user_data */ + leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */ + movl %edx, 8(%esp) /* raw_args */ + leal -24(%ebp), %edx + movl %edx, 4(%esp) /* &res */ + movl %esi, (%esp) /* cif */ + call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */ + movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */ + cmpl $FFI_TYPE_INT, %eax + je .Lrcls_retint + + /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16, + FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */ + cmpl $FFI_TYPE_UINT64, %eax + jge 0f + cmpl $FFI_TYPE_UINT8, %eax + jge .Lrcls_retint +0: + cmpl $FFI_TYPE_FLOAT, %eax + je .Lrcls_retfloat + cmpl $FFI_TYPE_DOUBLE, %eax + je .Lrcls_retdouble + cmpl $FFI_TYPE_LONGDOUBLE, %eax + je .Lrcls_retldouble + cmpl $FFI_TYPE_SINT64, %eax + je .Lrcls_retllong +.Lrcls_epilogue: + addl $36, %esp + popl %esi + popl %ebp + ret +.Lrcls_retint: + movl -24(%ebp), %eax + jmp .Lrcls_epilogue +.Lrcls_retfloat: + flds -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retdouble: + fldl -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retldouble: + fldt -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retllong: + movl -24(%ebp), %eax + movl -20(%ebp), %edx + jmp .Lrcls_epilogue +.LFE3: + .size ffi_closure_raw_SYSV, .-ffi_closure_raw_SYSV +#endif + + .section .eh_frame,EH_FRAME_FLAGS,@progbits +.Lframe1: + .long .LECIE1-.LSCIE1 /* Length of Common Information Entry */ +.LSCIE1: + .long 0x0 /* CIE Identifier Tag */ + .byte 0x1 /* CIE Version */ +#ifdef HAVE_AS_ASCII_PSEUDO_OP +#ifdef __PIC__ + .ascii "zR\0" /* CIE Augmentation */ +#else + .ascii "\0" /* CIE Augmentation */ +#endif +#elif defined HAVE_AS_STRING_PSEUDO_OP +#ifdef __PIC__ + .string "zR" /* CIE Augmentation */ +#else + .string "" /* CIE Augmentation */ +#endif +#else +#error missing .ascii/.string +#endif + .byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */ + .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */ + .byte 0x8 /* CIE RA Column */ +#ifdef __PIC__ + .byte 0x1 /* .uleb128 0x1; Augmentation size */ + .byte 0x1b /* FDE Encoding (pcrel sdata4) */ +#endif + .byte 0xc /* DW_CFA_def_cfa */ + .byte 0x4 /* .uleb128 0x4 */ + .byte 0x4 /* .uleb128 0x4 */ + .byte 0x88 /* DW_CFA_offset, column 0x8 */ + .byte 0x1 /* .uleb128 0x1 */ + .align 4 +.LECIE1: +.LSFDE1: + .long .LEFDE1-.LASFDE1 /* FDE Length */ +.LASFDE1: + .long .LASFDE1-.Lframe1 /* FDE CIE offset */ +#if defined __PIC__ && defined HAVE_AS_X86_PCREL + .long .LFB1-. /* FDE initial location */ +#elif defined __PIC__ + .long .LFB1@rel +#else + .long .LFB1 +#endif + .long .LFE1-.LFB1 /* FDE address range */ +#ifdef __PIC__ + .byte 0x0 /* .uleb128 0x0; Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI0-.LFB1 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 /* .uleb128 0x8 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 */ + .byte 0x2 /* .uleb128 0x2 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI1-.LCFI0 + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0x5 /* .uleb128 0x5 */ + .align 4 +.LEFDE1: +.LSFDE2: + .long .LEFDE2-.LASFDE2 /* FDE Length */ +.LASFDE2: + .long .LASFDE2-.Lframe1 /* FDE CIE offset */ +#if defined __PIC__ && defined HAVE_AS_X86_PCREL + .long .LFB2-. /* FDE initial location */ +#elif defined __PIC__ + .long .LFB2@rel +#else + .long .LFB2 +#endif + .long .LFE2-.LFB2 /* FDE address range */ +#ifdef __PIC__ + .byte 0x0 /* .uleb128 0x0; Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI2-.LFB2 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 /* .uleb128 0x8 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 */ + .byte 0x2 /* .uleb128 0x2 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI3-.LCFI2 + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0x5 /* .uleb128 0x5 */ +#if !defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE && defined __PIC__ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI7-.LCFI3 + .byte 0x83 /* DW_CFA_offset, column 0x3 */ + .byte 0xa /* .uleb128 0xa */ +#endif + .align 4 +.LEFDE2: + +#if !FFI_NO_RAW_API + +.LSFDE3: + .long .LEFDE3-.LASFDE3 /* FDE Length */ +.LASFDE3: + .long .LASFDE3-.Lframe1 /* FDE CIE offset */ +#if defined __PIC__ && defined HAVE_AS_X86_PCREL + .long .LFB3-. /* FDE initial location */ +#elif defined __PIC__ + .long .LFB3@rel +#else + .long .LFB3 +#endif + .long .LFE3-.LFB3 /* FDE address range */ +#ifdef __PIC__ + .byte 0x0 /* .uleb128 0x0; Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI4-.LFB3 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 /* .uleb128 0x8 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 */ + .byte 0x2 /* .uleb128 0x2 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI5-.LCFI4 + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0x5 /* .uleb128 0x5 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI6-.LCFI5 + .byte 0x86 /* DW_CFA_offset, column 0x6 */ + .byte 0x3 /* .uleb128 0x3 */ + .align 4 +.LEFDE3: + +#endif + +#endif /* ifndef __x86_64__ */ + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/js/src/ctypes/libffi/src/x86/unix64.S b/js/src/ctypes/libffi/src/x86/unix64.S new file mode 100644 index 0000000..7a6619a --- /dev/null +++ b/js/src/ctypes/libffi/src/x86/unix64.S @@ -0,0 +1,426 @@ +/* ----------------------------------------------------------------------- + unix64.S - Copyright (c) 2002 Bo Thorsen + Copyright (c) 2008 Red Hat, Inc + + x86-64 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#ifdef __x86_64__ +#define LIBFFI_ASM +#include +#include + +.text + +/* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags, + void *raddr, void (*fnaddr)(void)); + + Bit o trickiness here -- ARGS+BYTES is the base of the stack frame + for this function. This has been allocated by ffi_call. We also + deallocate some of the stack that has been alloca'd. */ + + .align 2 + .globl ffi_call_unix64 + .type ffi_call_unix64,@function + +ffi_call_unix64: +.LUW0: + movq (%rsp), %r10 /* Load return address. */ + leaq (%rdi, %rsi), %rax /* Find local stack base. */ + movq %rdx, (%rax) /* Save flags. */ + movq %rcx, 8(%rax) /* Save raddr. */ + movq %rbp, 16(%rax) /* Save old frame pointer. */ + movq %r10, 24(%rax) /* Relocate return address. */ + movq %rax, %rbp /* Finalize local stack frame. */ +.LUW1: + movq %rdi, %r10 /* Save a copy of the register area. */ + movq %r8, %r11 /* Save a copy of the target fn. */ + movl %r9d, %eax /* Set number of SSE registers. */ + + /* Load up all argument registers. */ + movq (%r10), %rdi + movq 8(%r10), %rsi + movq 16(%r10), %rdx + movq 24(%r10), %rcx + movq 32(%r10), %r8 + movq 40(%r10), %r9 + testl %eax, %eax + jnz .Lload_sse +.Lret_from_load_sse: + + /* Deallocate the reg arg area. */ + leaq 176(%r10), %rsp + + /* Call the user function. */ + call *%r11 + + /* Deallocate stack arg area; local stack frame in redzone. */ + leaq 24(%rbp), %rsp + + movq 0(%rbp), %rcx /* Reload flags. */ + movq 8(%rbp), %rdi /* Reload raddr. */ + movq 16(%rbp), %rbp /* Reload old frame pointer. */ +.LUW2: + + /* The first byte of the flags contains the FFI_TYPE. */ + movzbl %cl, %r10d + leaq .Lstore_table(%rip), %r11 + movslq (%r11, %r10, 4), %r10 + addq %r11, %r10 + jmp *%r10 + +.Lstore_table: + .long .Lst_void-.Lstore_table /* FFI_TYPE_VOID */ + .long .Lst_sint32-.Lstore_table /* FFI_TYPE_INT */ + .long .Lst_float-.Lstore_table /* FFI_TYPE_FLOAT */ + .long .Lst_double-.Lstore_table /* FFI_TYPE_DOUBLE */ + .long .Lst_ldouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */ + .long .Lst_uint8-.Lstore_table /* FFI_TYPE_UINT8 */ + .long .Lst_sint8-.Lstore_table /* FFI_TYPE_SINT8 */ + .long .Lst_uint16-.Lstore_table /* FFI_TYPE_UINT16 */ + .long .Lst_sint16-.Lstore_table /* FFI_TYPE_SINT16 */ + .long .Lst_uint32-.Lstore_table /* FFI_TYPE_UINT32 */ + .long .Lst_sint32-.Lstore_table /* FFI_TYPE_SINT32 */ + .long .Lst_int64-.Lstore_table /* FFI_TYPE_UINT64 */ + .long .Lst_int64-.Lstore_table /* FFI_TYPE_SINT64 */ + .long .Lst_struct-.Lstore_table /* FFI_TYPE_STRUCT */ + .long .Lst_int64-.Lstore_table /* FFI_TYPE_POINTER */ + + .align 2 +.Lst_void: + ret + .align 2 + +.Lst_uint8: + movzbq %al, %rax + movq %rax, (%rdi) + ret + .align 2 +.Lst_sint8: + movsbq %al, %rax + movq %rax, (%rdi) + ret + .align 2 +.Lst_uint16: + movzwq %ax, %rax + movq %rax, (%rdi) + .align 2 +.Lst_sint16: + movswq %ax, %rax + movq %rax, (%rdi) + ret + .align 2 +.Lst_uint32: + movl %eax, %eax + movq %rax, (%rdi) + .align 2 +.Lst_sint32: + cltq + movq %rax, (%rdi) + ret + .align 2 +.Lst_int64: + movq %rax, (%rdi) + ret + + .align 2 +.Lst_float: + movss %xmm0, (%rdi) + ret + .align 2 +.Lst_double: + movsd %xmm0, (%rdi) + ret +.Lst_ldouble: + fstpt (%rdi) + ret + + .align 2 +.Lst_struct: + leaq -20(%rsp), %rsi /* Scratch area in redzone. */ + + /* We have to locate the values now, and since we don't want to + write too much data into the user's return value, we spill the + value to a 16 byte scratch area first. Bits 8, 9, and 10 + control where the values are located. Only one of the three + bits will be set; see ffi_prep_cif_machdep for the pattern. */ + movd %xmm0, %r10 + movd %xmm1, %r11 + testl $0x100, %ecx + cmovnz %rax, %rdx + cmovnz %r10, %rax + testl $0x200, %ecx + cmovnz %r10, %rdx + testl $0x400, %ecx + cmovnz %r10, %rax + cmovnz %r11, %rdx + movq %rax, (%rsi) + movq %rdx, 8(%rsi) + + /* Bits 12-31 contain the true size of the structure. Copy from + the scratch area to the true destination. */ + shrl $12, %ecx + rep movsb + ret + + /* Many times we can avoid loading any SSE registers at all. + It's not worth an indirect jump to load the exact set of + SSE registers needed; zero or all is a good compromise. */ + .align 2 +.LUW3: +.Lload_sse: + movdqa 48(%r10), %xmm0 + movdqa 64(%r10), %xmm1 + movdqa 80(%r10), %xmm2 + movdqa 96(%r10), %xmm3 + movdqa 112(%r10), %xmm4 + movdqa 128(%r10), %xmm5 + movdqa 144(%r10), %xmm6 + movdqa 160(%r10), %xmm7 + jmp .Lret_from_load_sse + +.LUW4: + .size ffi_call_unix64,.-ffi_call_unix64 + + .align 2 + .globl ffi_closure_unix64 + .type ffi_closure_unix64,@function + +ffi_closure_unix64: +.LUW5: + /* The carry flag is set by the trampoline iff SSE registers + are used. Don't clobber it before the branch instruction. */ + leaq -200(%rsp), %rsp +.LUW6: + movq %rdi, (%rsp) + movq %rsi, 8(%rsp) + movq %rdx, 16(%rsp) + movq %rcx, 24(%rsp) + movq %r8, 32(%rsp) + movq %r9, 40(%rsp) + jc .Lsave_sse +.Lret_from_save_sse: + + movq %r10, %rdi + leaq 176(%rsp), %rsi + movq %rsp, %rdx + leaq 208(%rsp), %rcx + call ffi_closure_unix64_inner@PLT + + /* Deallocate stack frame early; return value is now in redzone. */ + addq $200, %rsp +.LUW7: + + /* The first byte of the return value contains the FFI_TYPE. */ + movzbl %al, %r10d + leaq .Lload_table(%rip), %r11 + movslq (%r11, %r10, 4), %r10 + addq %r11, %r10 + jmp *%r10 + +.Lload_table: + .long .Lld_void-.Lload_table /* FFI_TYPE_VOID */ + .long .Lld_int32-.Lload_table /* FFI_TYPE_INT */ + .long .Lld_float-.Lload_table /* FFI_TYPE_FLOAT */ + .long .Lld_double-.Lload_table /* FFI_TYPE_DOUBLE */ + .long .Lld_ldouble-.Lload_table /* FFI_TYPE_LONGDOUBLE */ + .long .Lld_int8-.Lload_table /* FFI_TYPE_UINT8 */ + .long .Lld_int8-.Lload_table /* FFI_TYPE_SINT8 */ + .long .Lld_int16-.Lload_table /* FFI_TYPE_UINT16 */ + .long .Lld_int16-.Lload_table /* FFI_TYPE_SINT16 */ + .long .Lld_int32-.Lload_table /* FFI_TYPE_UINT32 */ + .long .Lld_int32-.Lload_table /* FFI_TYPE_SINT32 */ + .long .Lld_int64-.Lload_table /* FFI_TYPE_UINT64 */ + .long .Lld_int64-.Lload_table /* FFI_TYPE_SINT64 */ + .long .Lld_struct-.Lload_table /* FFI_TYPE_STRUCT */ + .long .Lld_int64-.Lload_table /* FFI_TYPE_POINTER */ + + .align 2 +.Lld_void: + ret + + .align 2 +.Lld_int8: + movzbl -24(%rsp), %eax + ret + .align 2 +.Lld_int16: + movzwl -24(%rsp), %eax + ret + .align 2 +.Lld_int32: + movl -24(%rsp), %eax + ret + .align 2 +.Lld_int64: + movq -24(%rsp), %rax + ret + + .align 2 +.Lld_float: + movss -24(%rsp), %xmm0 + ret + .align 2 +.Lld_double: + movsd -24(%rsp), %xmm0 + ret + .align 2 +.Lld_ldouble: + fldt -24(%rsp) + ret + + .align 2 +.Lld_struct: + /* There are four possibilities here, %rax/%rdx, %xmm0/%rax, + %rax/%xmm0, %xmm0/%xmm1. We collapse two by always loading + both rdx and xmm1 with the second word. For the remaining, + bit 8 set means xmm0 gets the second word, and bit 9 means + that rax gets the second word. */ + movq -24(%rsp), %rcx + movq -16(%rsp), %rdx + movq -16(%rsp), %xmm1 + testl $0x100, %eax + cmovnz %rdx, %rcx + movd %rcx, %xmm0 + testl $0x200, %eax + movq -24(%rsp), %rax + cmovnz %rdx, %rax + ret + + /* See the comment above .Lload_sse; the same logic applies here. */ + .align 2 +.LUW8: +.Lsave_sse: + movdqa %xmm0, 48(%rsp) + movdqa %xmm1, 64(%rsp) + movdqa %xmm2, 80(%rsp) + movdqa %xmm3, 96(%rsp) + movdqa %xmm4, 112(%rsp) + movdqa %xmm5, 128(%rsp) + movdqa %xmm6, 144(%rsp) + movdqa %xmm7, 160(%rsp) + jmp .Lret_from_save_sse + +.LUW9: + .size ffi_closure_unix64,.-ffi_closure_unix64 + +#ifdef HAVE_AS_X86_64_UNWIND_SECTION_TYPE + .section .eh_frame,"a",@unwind +#else + .section .eh_frame,"a",@progbits +#endif +.Lframe1: + .long .LECIE1-.LSCIE1 /* CIE Length */ +.LSCIE1: + .long 0 /* CIE Identifier Tag */ + .byte 1 /* CIE Version */ + .ascii "zR\0" /* CIE Augmentation */ + .uleb128 1 /* CIE Code Alignment Factor */ + .sleb128 -8 /* CIE Data Alignment Factor */ + .byte 0x10 /* CIE RA Column */ + .uleb128 1 /* Augmentation size */ + .byte 0x1b /* FDE Encoding (pcrel sdata4) */ + .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */ + .uleb128 7 + .uleb128 8 + .byte 0x80+16 /* DW_CFA_offset, %rip offset 1*-8 */ + .uleb128 1 + .align 8 +.LECIE1: +.LSFDE1: + .long .LEFDE1-.LASFDE1 /* FDE Length */ +.LASFDE1: + .long .LASFDE1-.Lframe1 /* FDE CIE offset */ +#if HAVE_AS_X86_PCREL + .long .LUW0-. /* FDE initial location */ +#else + .long .LUW0@rel +#endif + .long .LUW4-.LUW0 /* FDE address range */ + .uleb128 0x0 /* Augmentation size */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LUW1-.LUW0 + + /* New stack frame based off rbp. This is a itty bit of unwind + trickery in that the CFA *has* changed. There is no easy way + to describe it correctly on entry to the function. Fortunately, + it doesn't matter too much since at all points we can correctly + unwind back to ffi_call. Note that the location to which we + moved the return address is (the new) CFA-8, so from the + perspective of the unwind info, it hasn't moved. */ + .byte 0xc /* DW_CFA_def_cfa, %rbp offset 32 */ + .uleb128 6 + .uleb128 32 + .byte 0x80+6 /* DW_CFA_offset, %rbp offset 2*-8 */ + .uleb128 2 + .byte 0xa /* DW_CFA_remember_state */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LUW2-.LUW1 + .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */ + .uleb128 7 + .uleb128 8 + .byte 0xc0+6 /* DW_CFA_restore, %rbp */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LUW3-.LUW2 + .byte 0xb /* DW_CFA_restore_state */ + + .align 8 +.LEFDE1: +.LSFDE3: + .long .LEFDE3-.LASFDE3 /* FDE Length */ +.LASFDE3: + .long .LASFDE3-.Lframe1 /* FDE CIE offset */ +#if HAVE_AS_X86_PCREL + .long .LUW5-. /* FDE initial location */ +#else + .long .LUW5@rel +#endif + .long .LUW9-.LUW5 /* FDE address range */ + .uleb128 0x0 /* Augmentation size */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LUW6-.LUW5 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .uleb128 208 + .byte 0xa /* DW_CFA_remember_state */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LUW7-.LUW6 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .uleb128 8 + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LUW8-.LUW7 + .byte 0xb /* DW_CFA_restore_state */ + + .align 8 +.LEFDE3: + +#endif /* __x86_64__ */ + +#if defined __ELF__ && defined __linux__ + .section .note.GNU-stack,"",@progbits +#endif diff --git a/js/src/ctypes/libffi/src/x86/win32.S b/js/src/ctypes/libffi/src/x86/win32.S new file mode 100644 index 0000000..34ec0fd --- /dev/null +++ b/js/src/ctypes/libffi/src/x86/win32.S @@ -0,0 +1,1065 @@ +/* ----------------------------------------------------------------------- + win32.S - Copyright (c) 1996, 1998, 2001, 2002, 2009 Red Hat, Inc. + Copyright (c) 2001 John Beniton + Copyright (c) 2002 Ranjit Mathew + Copyright (c) 2009 Daniel Witte + + + X86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- + */ + +#define LIBFFI_ASM +#include +#include + +#ifdef _MSC_VER + +.386 +.MODEL FLAT, C + +EXTRN ffi_closure_SYSV_inner:NEAR + +_TEXT SEGMENT + +ffi_call_win32 PROC NEAR, + ffi_prep_args : NEAR PTR DWORD, + ecif : NEAR PTR DWORD, + cif_bytes : DWORD, + cif_flags : DWORD, + rvalue : NEAR PTR DWORD, + fn : NEAR PTR DWORD + + ;; Make room for all of the new args. + mov ecx, cif_bytes + sub esp, ecx + + mov eax, esp + + ;; Place all of the ffi_prep_args in position + push ecif + push eax + call ffi_prep_args + + ;; Return stack to previous state and call the function + add esp, 8 + + call fn + + ;; cdecl: we restore esp in the epilogue, so there's no need to + ;; remove the space we pushed for the args. + ;; stdcall: the callee has already cleaned the stack. + + ;; Load ecx with the return type code + mov ecx, cif_flags + + ;; If the return value pointer is NULL, assume no return value. + cmp rvalue, 0 + jne ca_jumptable + + ;; Even if there is no space for the return value, we are + ;; obliged to handle floating-point values. + cmp ecx, FFI_TYPE_FLOAT + jne ca_epilogue + fstp st(0) + + jmp ca_epilogue + +ca_jumptable: + jmp [ca_jumpdata + 4 * ecx] +ca_jumpdata: + ;; Do not insert anything here between label and jump table. + dd offset ca_epilogue ;; FFI_TYPE_VOID + dd offset ca_retint ;; FFI_TYPE_INT + dd offset ca_retfloat ;; FFI_TYPE_FLOAT + dd offset ca_retdouble ;; FFI_TYPE_DOUBLE + dd offset ca_retlongdouble ;; FFI_TYPE_LONGDOUBLE + dd offset ca_retint8 ;; FFI_TYPE_UINT8 + dd offset ca_retint8 ;; FFI_TYPE_SINT8 + dd offset ca_retint16 ;; FFI_TYPE_UINT16 + dd offset ca_retint16 ;; FFI_TYPE_SINT16 + dd offset ca_retint ;; FFI_TYPE_UINT32 + dd offset ca_retint ;; FFI_TYPE_SINT32 + dd offset ca_retint64 ;; FFI_TYPE_UINT64 + dd offset ca_retint64 ;; FFI_TYPE_SINT64 + dd offset ca_epilogue ;; FFI_TYPE_STRUCT + dd offset ca_retint ;; FFI_TYPE_POINTER + dd offset ca_retint8 ;; FFI_TYPE_SMALL_STRUCT_1B + dd offset ca_retint16 ;; FFI_TYPE_SMALL_STRUCT_2B + dd offset ca_retint ;; FFI_TYPE_SMALL_STRUCT_4B + +ca_retint8: + ;; Load %ecx with the pointer to storage for the return value + mov ecx, rvalue + mov [ecx + 0], al + jmp ca_epilogue + +ca_retint16: + ;; Load %ecx with the pointer to storage for the return value + mov ecx, rvalue + mov [ecx + 0], ax + jmp ca_epilogue + +ca_retint: + ;; Load %ecx with the pointer to storage for the return value + mov ecx, rvalue + mov [ecx + 0], eax + jmp ca_epilogue + +ca_retint64: + ;; Load %ecx with the pointer to storage for the return value + mov ecx, rvalue + mov [ecx + 0], eax + mov [ecx + 4], edx + jmp ca_epilogue + +ca_retfloat: + ;; Load %ecx with the pointer to storage for the return value + mov ecx, rvalue + fstp DWORD PTR [ecx] + jmp ca_epilogue + +ca_retdouble: + ;; Load %ecx with the pointer to storage for the return value + mov ecx, rvalue + fstp QWORD PTR [ecx] + jmp ca_epilogue + +ca_retlongdouble: + ;; Load %ecx with the pointer to storage for the return value + mov ecx, rvalue + fstp TBYTE PTR [ecx] + jmp ca_epilogue + +ca_epilogue: + ;; Epilogue code is autogenerated. + ret +ffi_call_win32 ENDP + +ffi_closure_SYSV PROC NEAR FORCEFRAME + ;; the ffi_closure ctx is passed in eax by the trampoline. + + sub esp, 40 + lea edx, [ebp - 24] + mov [ebp - 12], edx ;; resp + lea edx, [ebp + 8] + mov [esp + 8], edx ;; args + lea edx, [ebp - 12] + mov [esp + 4], edx ;; &resp + mov [esp], eax ;; closure + call ffi_closure_SYSV_inner + mov ecx, [ebp - 12] + +cs_jumptable: + jmp [cs_jumpdata + 4 * eax] +cs_jumpdata: + ;; Do not insert anything here between the label and jump table. + dd offset cs_epilogue ;; FFI_TYPE_VOID + dd offset cs_retint ;; FFI_TYPE_INT + dd offset cs_retfloat ;; FFI_TYPE_FLOAT + dd offset cs_retdouble ;; FFI_TYPE_DOUBLE + dd offset cs_retlongdouble ;; FFI_TYPE_LONGDOUBLE + dd offset cs_retint8 ;; FFI_TYPE_UINT8 + dd offset cs_retint8 ;; FFI_TYPE_SINT8 + dd offset cs_retint16 ;; FFI_TYPE_UINT16 + dd offset cs_retint16 ;; FFI_TYPE_SINT16 + dd offset cs_retint ;; FFI_TYPE_UINT32 + dd offset cs_retint ;; FFI_TYPE_SINT32 + dd offset cs_retint64 ;; FFI_TYPE_UINT64 + dd offset cs_retint64 ;; FFI_TYPE_SINT64 + dd offset cs_retstruct ;; FFI_TYPE_STRUCT + dd offset cs_retint ;; FFI_TYPE_POINTER + dd offset cs_retint8 ;; FFI_TYPE_SMALL_STRUCT_1B + dd offset cs_retint16 ;; FFI_TYPE_SMALL_STRUCT_2B + dd offset cs_retint ;; FFI_TYPE_SMALL_STRUCT_4B + +cs_retint8: + mov al, [ecx] + jmp cs_epilogue + +cs_retint16: + mov ax, [ecx] + jmp cs_epilogue + +cs_retint: + mov eax, [ecx] + jmp cs_epilogue + +cs_retint64: + mov eax, [ecx + 0] + mov edx, [ecx + 4] + jmp cs_epilogue + +cs_retfloat: + fld DWORD PTR [ecx] + jmp cs_epilogue + +cs_retdouble: + fld QWORD PTR [ecx] + jmp cs_epilogue + +cs_retlongdouble: + fld TBYTE PTR [ecx] + jmp cs_epilogue + +cs_retstruct: + ;; Caller expects us to pop struct return value pointer hidden arg. + ;; Epilogue code is autogenerated. + ret 4 + +cs_epilogue: + ;; Epilogue code is autogenerated. + ret +ffi_closure_SYSV ENDP + +#if !FFI_NO_RAW_API + +#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) AND NOT 3) +#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4) +#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4) +#define CIF_FLAGS_OFFSET 20 + +ffi_closure_raw_SYSV PROC NEAR USES esi + ;; the ffi_closure ctx is passed in eax by the trampoline. + + sub esp, 40 + mov esi, [eax + RAW_CLOSURE_CIF_OFFSET] ;; closure->cif + mov edx, [eax + RAW_CLOSURE_USER_DATA_OFFSET] ;; closure->user_data + mov [esp + 12], edx ;; user_data + lea edx, [ebp + 8] + mov [esp + 8], edx ;; raw_args + lea edx, [ebp - 24] + mov [esp + 4], edx ;; &res + mov [esp], esi ;; cif + call DWORD PTR [eax + RAW_CLOSURE_FUN_OFFSET] ;; closure->fun + mov eax, [esi + CIF_FLAGS_OFFSET] ;; cif->flags + lea ecx, [ebp - 24] + +cr_jumptable: + jmp [cr_jumpdata + 4 * eax] +cr_jumpdata: + ;; Do not insert anything here between the label and jump table. + dd offset cr_epilogue ;; FFI_TYPE_VOID + dd offset cr_retint ;; FFI_TYPE_INT + dd offset cr_retfloat ;; FFI_TYPE_FLOAT + dd offset cr_retdouble ;; FFI_TYPE_DOUBLE + dd offset cr_retlongdouble ;; FFI_TYPE_LONGDOUBLE + dd offset cr_retint8 ;; FFI_TYPE_UINT8 + dd offset cr_retint8 ;; FFI_TYPE_SINT8 + dd offset cr_retint16 ;; FFI_TYPE_UINT16 + dd offset cr_retint16 ;; FFI_TYPE_SINT16 + dd offset cr_retint ;; FFI_TYPE_UINT32 + dd offset cr_retint ;; FFI_TYPE_SINT32 + dd offset cr_retint64 ;; FFI_TYPE_UINT64 + dd offset cr_retint64 ;; FFI_TYPE_SINT64 + dd offset cr_epilogue ;; FFI_TYPE_STRUCT + dd offset cr_retint ;; FFI_TYPE_POINTER + dd offset cr_retint8 ;; FFI_TYPE_SMALL_STRUCT_1B + dd offset cr_retint16 ;; FFI_TYPE_SMALL_STRUCT_2B + dd offset cr_retint ;; FFI_TYPE_SMALL_STRUCT_4B + +cr_retint8: + mov al, [ecx] + jmp cr_epilogue + +cr_retint16: + mov ax, [ecx] + jmp cr_epilogue + +cr_retint: + mov eax, [ecx] + jmp cr_epilogue + +cr_retint64: + mov eax, [ecx + 0] + mov edx, [ecx + 4] + jmp cr_epilogue + +cr_retfloat: + fld DWORD PTR [ecx] + jmp cr_epilogue + +cr_retdouble: + fld QWORD PTR [ecx] + jmp cr_epilogue + +cr_retlongdouble: + fld TBYTE PTR [ecx] + jmp cr_epilogue + +cr_epilogue: + ;; Epilogue code is autogenerated. + ret +ffi_closure_raw_SYSV ENDP + +#endif /* !FFI_NO_RAW_API */ + +ffi_closure_STDCALL PROC NEAR FORCEFRAME + ;; the ffi_closure ctx is passed in eax by the trampoline. + + sub esp, 40 + lea edx, [ebp - 24] + mov [ebp - 12], edx ;; resp + lea edx, [ebp + 12] ;; account for stub return address on stack + mov [esp + 8], edx ;; args + lea edx, [ebp - 12] + mov [esp + 4], edx ;; &resp + mov [esp], eax ;; closure + call ffi_closure_SYSV_inner + mov ecx, [ebp - 12] + +cd_jumptable: + jmp [cd_jumpdata + 4 * eax] +cd_jumpdata: + ;; Do not insert anything here between the label and jump table. + dd offset cd_epilogue ;; FFI_TYPE_VOID + dd offset cd_retint ;; FFI_TYPE_INT + dd offset cd_retfloat ;; FFI_TYPE_FLOAT + dd offset cd_retdouble ;; FFI_TYPE_DOUBLE + dd offset cd_retlongdouble ;; FFI_TYPE_LONGDOUBLE + dd offset cd_retint8 ;; FFI_TYPE_UINT8 + dd offset cd_retint8 ;; FFI_TYPE_SINT8 + dd offset cd_retint16 ;; FFI_TYPE_UINT16 + dd offset cd_retint16 ;; FFI_TYPE_SINT16 + dd offset cd_retint ;; FFI_TYPE_UINT32 + dd offset cd_retint ;; FFI_TYPE_SINT32 + dd offset cd_retint64 ;; FFI_TYPE_UINT64 + dd offset cd_retint64 ;; FFI_TYPE_SINT64 + dd offset cd_epilogue ;; FFI_TYPE_STRUCT + dd offset cd_retint ;; FFI_TYPE_POINTER + dd offset cd_retint8 ;; FFI_TYPE_SMALL_STRUCT_1B + dd offset cd_retint16 ;; FFI_TYPE_SMALL_STRUCT_2B + dd offset cd_retint ;; FFI_TYPE_SMALL_STRUCT_4B + +cd_retint8: + mov al, [ecx] + jmp cd_epilogue + +cd_retint16: + mov ax, [ecx] + jmp cd_epilogue + +cd_retint: + mov eax, [ecx] + jmp cd_epilogue + +cd_retint64: + mov eax, [ecx + 0] + mov edx, [ecx + 4] + jmp cd_epilogue + +cd_retfloat: + fld DWORD PTR [ecx] + jmp cd_epilogue + +cd_retdouble: + fld QWORD PTR [ecx] + jmp cd_epilogue + +cd_retlongdouble: + fld TBYTE PTR [ecx] + jmp cd_epilogue + +cd_epilogue: + ;; Epilogue code is autogenerated. + ret +ffi_closure_STDCALL ENDP + +_TEXT ENDS +END + +#else + + .text + + # This assumes we are using gas. + .balign 16 + .globl _ffi_call_win32 +#ifndef __OS2__ + .def _ffi_call_win32; .scl 2; .type 32; .endef +#endif +_ffi_call_win32: +.LFB1: + pushl %ebp +.LCFI0: + movl %esp,%ebp +.LCFI1: + # Make room for all of the new args. + movl 16(%ebp),%ecx + subl %ecx,%esp + + movl %esp,%eax + + # Place all of the ffi_prep_args in position + pushl 12(%ebp) + pushl %eax + call *8(%ebp) + + # Return stack to previous state and call the function + addl $8,%esp + + # FIXME: Align the stack to a 128-bit boundary to avoid + # potential performance hits. + + call *28(%ebp) + + # stdcall functions pop arguments off the stack themselves + + # Load %ecx with the return type code + movl 20(%ebp),%ecx + + # If the return value pointer is NULL, assume no return value. + cmpl $0,24(%ebp) + jne 0f + + # Even if there is no space for the return value, we are + # obliged to handle floating-point values. + cmpl $FFI_TYPE_FLOAT,%ecx + jne .Lnoretval + fstp %st(0) + + jmp .Lepilogue + +0: + call 1f + # Do not insert anything here between the call and the jump table. +.Lstore_table: + .long .Lnoretval /* FFI_TYPE_VOID */ + .long .Lretint /* FFI_TYPE_INT */ + .long .Lretfloat /* FFI_TYPE_FLOAT */ + .long .Lretdouble /* FFI_TYPE_DOUBLE */ + .long .Lretlongdouble /* FFI_TYPE_LONGDOUBLE */ + .long .Lretuint8 /* FFI_TYPE_UINT8 */ + .long .Lretsint8 /* FFI_TYPE_SINT8 */ + .long .Lretuint16 /* FFI_TYPE_UINT16 */ + .long .Lretsint16 /* FFI_TYPE_SINT16 */ + .long .Lretint /* FFI_TYPE_UINT32 */ + .long .Lretint /* FFI_TYPE_SINT32 */ + .long .Lretint64 /* FFI_TYPE_UINT64 */ + .long .Lretint64 /* FFI_TYPE_SINT64 */ + .long .Lretstruct /* FFI_TYPE_STRUCT */ + .long .Lretint /* FFI_TYPE_POINTER */ + .long .Lretstruct1b /* FFI_TYPE_SMALL_STRUCT_1B */ + .long .Lretstruct2b /* FFI_TYPE_SMALL_STRUCT_2B */ + .long .Lretstruct4b /* FFI_TYPE_SMALL_STRUCT_4B */ +1: + add %ecx, %ecx + add %ecx, %ecx + add (%esp),%ecx + add $4, %esp + jmp *(%ecx) + + /* Sign/zero extend as appropriate. */ +.Lretsint8: + movsbl %al, %eax + jmp .Lretint + +.Lretsint16: + movswl %ax, %eax + jmp .Lretint + +.Lretuint8: + movzbl %al, %eax + jmp .Lretint + +.Lretuint16: + movzwl %ax, %eax + jmp .Lretint + +.Lretint: + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + jmp .Lepilogue + +.Lretfloat: + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstps (%ecx) + jmp .Lepilogue + +.Lretdouble: + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpl (%ecx) + jmp .Lepilogue + +.Lretlongdouble: + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpt (%ecx) + jmp .Lepilogue + +.Lretint64: + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + movl %edx,4(%ecx) + jmp .Lepilogue + +.Lretstruct1b: + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movb %al,0(%ecx) + jmp .Lepilogue + +.Lretstruct2b: + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movw %ax,0(%ecx) + jmp .Lepilogue + +.Lretstruct4b: + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + jmp .Lepilogue + +.Lretstruct: + # Nothing to do! + +.Lnoretval: +.Lepilogue: + movl %ebp,%esp + popl %ebp + ret +.ffi_call_win32_end: +.LFE1: + + # This assumes we are using gas. + .balign 16 + .globl _ffi_closure_SYSV +#ifndef __OS2__ + .def _ffi_closure_SYSV; .scl 2; .type 32; .endef +#endif +_ffi_closure_SYSV: +.LFB3: + pushl %ebp +.LCFI4: + movl %esp, %ebp +.LCFI5: + subl $40, %esp + leal -24(%ebp), %edx + movl %edx, -12(%ebp) /* resp */ + leal 8(%ebp), %edx + movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */ + leal -12(%ebp), %edx + movl %edx, (%esp) /* &resp */ + call _ffi_closure_SYSV_inner + movl -12(%ebp), %ecx + +0: + call 1f + # Do not insert anything here between the call and the jump table. +.Lcls_store_table: + .long .Lcls_noretval /* FFI_TYPE_VOID */ + .long .Lcls_retint /* FFI_TYPE_INT */ + .long .Lcls_retfloat /* FFI_TYPE_FLOAT */ + .long .Lcls_retdouble /* FFI_TYPE_DOUBLE */ + .long .Lcls_retldouble /* FFI_TYPE_LONGDOUBLE */ + .long .Lcls_retuint8 /* FFI_TYPE_UINT8 */ + .long .Lcls_retsint8 /* FFI_TYPE_SINT8 */ + .long .Lcls_retuint16 /* FFI_TYPE_UINT16 */ + .long .Lcls_retsint16 /* FFI_TYPE_SINT16 */ + .long .Lcls_retint /* FFI_TYPE_UINT32 */ + .long .Lcls_retint /* FFI_TYPE_SINT32 */ + .long .Lcls_retllong /* FFI_TYPE_UINT64 */ + .long .Lcls_retllong /* FFI_TYPE_SINT64 */ + .long .Lcls_retstruct /* FFI_TYPE_STRUCT */ + .long .Lcls_retint /* FFI_TYPE_POINTER */ + .long .Lcls_retstruct1 /* FFI_TYPE_SMALL_STRUCT_1B */ + .long .Lcls_retstruct2 /* FFI_TYPE_SMALL_STRUCT_2B */ + .long .Lcls_retstruct4 /* FFI_TYPE_SMALL_STRUCT_4B */ + +1: + add %eax, %eax + add %eax, %eax + add (%esp),%eax + add $4, %esp + jmp *(%eax) + + /* Sign/zero extend as appropriate. */ +.Lcls_retsint8: + movsbl (%ecx), %eax + jmp .Lcls_epilogue + +.Lcls_retsint16: + movswl (%ecx), %eax + jmp .Lcls_epilogue + +.Lcls_retuint8: + movzbl (%ecx), %eax + jmp .Lcls_epilogue + +.Lcls_retuint16: + movzwl (%ecx), %eax + jmp .Lcls_epilogue + +.Lcls_retint: + movl (%ecx), %eax + jmp .Lcls_epilogue + +.Lcls_retfloat: + flds (%ecx) + jmp .Lcls_epilogue + +.Lcls_retdouble: + fldl (%ecx) + jmp .Lcls_epilogue + +.Lcls_retldouble: + fldt (%ecx) + jmp .Lcls_epilogue + +.Lcls_retllong: + movl (%ecx), %eax + movl 4(%ecx), %edx + jmp .Lcls_epilogue + +.Lcls_retstruct1: + movsbl (%ecx), %eax + jmp .Lcls_epilogue + +.Lcls_retstruct2: + movswl (%ecx), %eax + jmp .Lcls_epilogue + +.Lcls_retstruct4: + movl (%ecx), %eax + jmp .Lcls_epilogue + +.Lcls_retstruct: + # Caller expects us to pop struct return value pointer hidden arg. + movl %ebp, %esp + popl %ebp + ret $0x4 + +.Lcls_noretval: +.Lcls_epilogue: + movl %ebp, %esp + popl %ebp + ret +.ffi_closure_SYSV_end: +.LFE3: + +#if !FFI_NO_RAW_API + +#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3) +#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4) +#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4) +#define CIF_FLAGS_OFFSET 20 + + # This assumes we are using gas. + .balign 16 + .globl _ffi_closure_raw_SYSV +#ifndef __OS2__ + .def _ffi_closure_raw_SYSV; .scl 2; .type 32; .endef +#endif +_ffi_closure_raw_SYSV: +.LFB4: + pushl %ebp +.LCFI6: + movl %esp, %ebp +.LCFI7: + pushl %esi +.LCFI8: + subl $36, %esp + movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */ + movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */ + movl %edx, 12(%esp) /* user_data */ + leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */ + movl %edx, 8(%esp) /* raw_args */ + leal -24(%ebp), %edx + movl %edx, 4(%esp) /* &res */ + movl %esi, (%esp) /* cif */ + call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */ + movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */ +0: + call 1f + # Do not insert anything here between the call and the jump table. +.Lrcls_store_table: + .long .Lrcls_noretval /* FFI_TYPE_VOID */ + .long .Lrcls_retint /* FFI_TYPE_INT */ + .long .Lrcls_retfloat /* FFI_TYPE_FLOAT */ + .long .Lrcls_retdouble /* FFI_TYPE_DOUBLE */ + .long .Lrcls_retldouble /* FFI_TYPE_LONGDOUBLE */ + .long .Lrcls_retuint8 /* FFI_TYPE_UINT8 */ + .long .Lrcls_retsint8 /* FFI_TYPE_SINT8 */ + .long .Lrcls_retuint16 /* FFI_TYPE_UINT16 */ + .long .Lrcls_retsint16 /* FFI_TYPE_SINT16 */ + .long .Lrcls_retint /* FFI_TYPE_UINT32 */ + .long .Lrcls_retint /* FFI_TYPE_SINT32 */ + .long .Lrcls_retllong /* FFI_TYPE_UINT64 */ + .long .Lrcls_retllong /* FFI_TYPE_SINT64 */ + .long .Lrcls_retstruct /* FFI_TYPE_STRUCT */ + .long .Lrcls_retint /* FFI_TYPE_POINTER */ + .long .Lrcls_retstruct1 /* FFI_TYPE_SMALL_STRUCT_1B */ + .long .Lrcls_retstruct2 /* FFI_TYPE_SMALL_STRUCT_2B */ + .long .Lrcls_retstruct4 /* FFI_TYPE_SMALL_STRUCT_4B */ +1: + add %eax, %eax + add %eax, %eax + add (%esp),%eax + add $4, %esp + jmp *(%eax) + + /* Sign/zero extend as appropriate. */ +.Lrcls_retsint8: + movsbl -24(%ebp), %eax + jmp .Lrcls_epilogue + +.Lrcls_retsint16: + movswl -24(%ebp), %eax + jmp .Lrcls_epilogue + +.Lrcls_retuint8: + movzbl -24(%ebp), %eax + jmp .Lrcls_epilogue + +.Lrcls_retuint16: + movzwl -24(%ebp), %eax + jmp .Lrcls_epilogue + +.Lrcls_retint: + movl -24(%ebp), %eax + jmp .Lrcls_epilogue + +.Lrcls_retfloat: + flds -24(%ebp) + jmp .Lrcls_epilogue + +.Lrcls_retdouble: + fldl -24(%ebp) + jmp .Lrcls_epilogue + +.Lrcls_retldouble: + fldt -24(%ebp) + jmp .Lrcls_epilogue + +.Lrcls_retllong: + movl -24(%ebp), %eax + movl -20(%ebp), %edx + jmp .Lrcls_epilogue + +.Lrcls_retstruct1: + movsbl -24(%ebp), %eax + jmp .Lrcls_epilogue + +.Lrcls_retstruct2: + movswl -24(%ebp), %eax + jmp .Lrcls_epilogue + +.Lrcls_retstruct4: + movl -24(%ebp), %eax + jmp .Lrcls_epilogue + +.Lrcls_retstruct: + # Nothing to do! + +.Lrcls_noretval: +.Lrcls_epilogue: + addl $36, %esp + popl %esi + popl %ebp + ret +.ffi_closure_raw_SYSV_end: +.LFE4: + +#endif /* !FFI_NO_RAW_API */ + + # This assumes we are using gas. + .balign 16 + .globl _ffi_closure_STDCALL +#ifndef __OS2__ + .def _ffi_closure_STDCALL; .scl 2; .type 32; .endef +#endif +_ffi_closure_STDCALL: +.LFB5: + pushl %ebp +.LCFI9: + movl %esp, %ebp +.LCFI10: + subl $40, %esp + leal -24(%ebp), %edx + movl %edx, -12(%ebp) /* resp */ + leal 12(%ebp), %edx /* account for stub return address on stack */ + movl %edx, 4(%esp) /* args */ + leal -12(%ebp), %edx + movl %edx, (%esp) /* &resp */ + call _ffi_closure_SYSV_inner + movl -12(%ebp), %ecx +0: + call 1f + # Do not insert anything here between the call and the jump table. +.Lscls_store_table: + .long .Lscls_noretval /* FFI_TYPE_VOID */ + .long .Lscls_retint /* FFI_TYPE_INT */ + .long .Lscls_retfloat /* FFI_TYPE_FLOAT */ + .long .Lscls_retdouble /* FFI_TYPE_DOUBLE */ + .long .Lscls_retldouble /* FFI_TYPE_LONGDOUBLE */ + .long .Lscls_retuint8 /* FFI_TYPE_UINT8 */ + .long .Lscls_retsint8 /* FFI_TYPE_SINT8 */ + .long .Lscls_retuint16 /* FFI_TYPE_UINT16 */ + .long .Lscls_retsint16 /* FFI_TYPE_SINT16 */ + .long .Lscls_retint /* FFI_TYPE_UINT32 */ + .long .Lscls_retint /* FFI_TYPE_SINT32 */ + .long .Lscls_retllong /* FFI_TYPE_UINT64 */ + .long .Lscls_retllong /* FFI_TYPE_SINT64 */ + .long .Lscls_retstruct /* FFI_TYPE_STRUCT */ + .long .Lscls_retint /* FFI_TYPE_POINTER */ + .long .Lscls_retstruct1 /* FFI_TYPE_SMALL_STRUCT_1B */ + .long .Lscls_retstruct2 /* FFI_TYPE_SMALL_STRUCT_2B */ + .long .Lscls_retstruct4 /* FFI_TYPE_SMALL_STRUCT_4B */ +1: + add %eax, %eax + add %eax, %eax + add (%esp),%eax + add $4, %esp + jmp *(%eax) + + /* Sign/zero extend as appropriate. */ +.Lscls_retsint8: + movsbl (%ecx), %eax + jmp .Lscls_epilogue + +.Lscls_retsint16: + movswl (%ecx), %eax + jmp .Lscls_epilogue + +.Lscls_retuint8: + movzbl (%ecx), %eax + jmp .Lscls_epilogue + +.Lscls_retuint16: + movzwl (%ecx), %eax + jmp .Lscls_epilogue + +.Lscls_retint: + movl (%ecx), %eax + jmp .Lscls_epilogue + +.Lscls_retfloat: + flds (%ecx) + jmp .Lscls_epilogue + +.Lscls_retdouble: + fldl (%ecx) + jmp .Lscls_epilogue + +.Lscls_retldouble: + fldt (%ecx) + jmp .Lscls_epilogue + +.Lscls_retllong: + movl (%ecx), %eax + movl 4(%ecx), %edx + jmp .Lscls_epilogue + +.Lscls_retstruct1: + movsbl (%ecx), %eax + jmp .Lscls_epilogue + +.Lscls_retstruct2: + movswl (%ecx), %eax + jmp .Lscls_epilogue + +.Lscls_retstruct4: + movl (%ecx), %eax + jmp .Lscls_epilogue + +.Lscls_retstruct: + # Nothing to do! + +.Lscls_noretval: +.Lscls_epilogue: + movl %ebp, %esp + popl %ebp + ret +.ffi_closure_STDCALL_end: +.LFE5: + +#ifndef __OS2__ + .section .eh_frame,"w" +#endif +.Lframe1: +.LSCIE1: + .long .LECIE1-.LASCIE1 /* Length of Common Information Entry */ +.LASCIE1: + .long 0x0 /* CIE Identifier Tag */ + .byte 0x1 /* CIE Version */ +#ifdef __PIC__ + .ascii "zR\0" /* CIE Augmentation */ +#else + .ascii "\0" /* CIE Augmentation */ +#endif + .byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */ + .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */ + .byte 0x8 /* CIE RA Column */ +#ifdef __PIC__ + .byte 0x1 /* .uleb128 0x1; Augmentation size */ + .byte 0x1b /* FDE Encoding (pcrel sdata4) */ +#endif + .byte 0xc /* DW_CFA_def_cfa CFA = r4 + 4 = 4(%esp) */ + .byte 0x4 /* .uleb128 0x4 */ + .byte 0x4 /* .uleb128 0x4 */ + .byte 0x88 /* DW_CFA_offset, column 0x8 %eip at CFA + 1 * -4 */ + .byte 0x1 /* .uleb128 0x1 */ + .align 4 +.LECIE1: + +.LSFDE1: + .long .LEFDE1-.LASFDE1 /* FDE Length */ +.LASFDE1: + .long .LASFDE1-.Lframe1 /* FDE CIE offset */ +#if defined __PIC__ && defined HAVE_AS_X86_PCREL + .long .LFB1-. /* FDE initial location */ +#else + .long .LFB1 +#endif + .long .LFE1-.LFB1 /* FDE address range */ +#ifdef __PIC__ + .byte 0x0 /* .uleb128 0x0; Augmentation size */ +#endif + /* DW_CFA_xxx CFI instructions go here. */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI0-.LFB1 + .byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */ + .byte 0x8 /* .uleb128 0x8 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */ + .byte 0x2 /* .uleb128 0x2 */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI1-.LCFI0 + .byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */ + .byte 0x5 /* .uleb128 0x5 */ + + /* End of DW_CFA_xxx CFI instructions. */ + .align 4 +.LEFDE1: + + +.LSFDE3: + .long .LEFDE3-.LASFDE3 /* FDE Length */ +.LASFDE3: + .long .LASFDE3-.Lframe1 /* FDE CIE offset */ +#if defined __PIC__ && defined HAVE_AS_X86_PCREL + .long .LFB3-. /* FDE initial location */ +#else + .long .LFB3 +#endif + .long .LFE3-.LFB3 /* FDE address range */ +#ifdef __PIC__ + .byte 0x0 /* .uleb128 0x0; Augmentation size */ +#endif + /* DW_CFA_xxx CFI instructions go here. */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI4-.LFB3 + .byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */ + .byte 0x8 /* .uleb128 0x8 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */ + .byte 0x2 /* .uleb128 0x2 */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI5-.LCFI4 + .byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */ + .byte 0x5 /* .uleb128 0x5 */ + + /* End of DW_CFA_xxx CFI instructions. */ + .align 4 +.LEFDE3: + +#if !FFI_NO_RAW_API + +.LSFDE4: + .long .LEFDE4-.LASFDE4 /* FDE Length */ +.LASFDE4: + .long .LASFDE4-.Lframe1 /* FDE CIE offset */ +#if defined __PIC__ && defined HAVE_AS_X86_PCREL + .long .LFB4-. /* FDE initial location */ +#else + .long .LFB4 +#endif + .long .LFE4-.LFB4 /* FDE address range */ +#ifdef __PIC__ + .byte 0x0 /* .uleb128 0x0; Augmentation size */ +#endif + /* DW_CFA_xxx CFI instructions go here. */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI6-.LFB4 + .byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */ + .byte 0x8 /* .uleb128 0x8 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */ + .byte 0x2 /* .uleb128 0x2 */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI7-.LCFI6 + .byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */ + .byte 0x5 /* .uleb128 0x5 */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI8-.LCFI7 + .byte 0x86 /* DW_CFA_offset, column 0x6 %esi at CFA + 3 * -4 */ + .byte 0x3 /* .uleb128 0x3 */ + + /* End of DW_CFA_xxx CFI instructions. */ + .align 4 +.LEFDE4: + +#endif /* !FFI_NO_RAW_API */ + +.LSFDE5: + .long .LEFDE5-.LASFDE5 /* FDE Length */ +.LASFDE5: + .long .LASFDE5-.Lframe1 /* FDE CIE offset */ +#if defined __PIC__ && defined HAVE_AS_X86_PCREL + .long .LFB5-. /* FDE initial location */ +#else + .long .LFB5 +#endif + .long .LFE5-.LFB5 /* FDE address range */ +#ifdef __PIC__ + .byte 0x0 /* .uleb128 0x0; Augmentation size */ +#endif + /* DW_CFA_xxx CFI instructions go here. */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI9-.LFB5 + .byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */ + .byte 0x8 /* .uleb128 0x8 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */ + .byte 0x2 /* .uleb128 0x2 */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI10-.LCFI9 + .byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */ + .byte 0x5 /* .uleb128 0x5 */ + + /* End of DW_CFA_xxx CFI instructions. */ + .align 4 +.LEFDE5: + +#endif /* !_MSC_VER */ + diff --git a/js/src/ctypes/libffi/src/x86/win64.S b/js/src/ctypes/libffi/src/x86/win64.S new file mode 100644 index 0000000..6e91818 --- /dev/null +++ b/js/src/ctypes/libffi/src/x86/win64.S @@ -0,0 +1,460 @@ +#define LIBFFI_ASM +#include +#include + +/* Constants for ffi_call_win64 */ +#define STACK 0 +#define PREP_ARGS_FN 32 +#define ECIF 40 +#define CIF_BYTES 48 +#define CIF_FLAGS 56 +#define RVALUE 64 +#define FN 72 + +/* ffi_call_win64 (void (*prep_args_fn)(char *, extended_cif *), + extended_cif *ecif, unsigned bytes, unsigned flags, + unsigned *rvalue, void (*fn)()); + */ + +#ifdef _MSC_VER +PUBLIC ffi_call_win64 + +EXTRN __chkstk:NEAR +EXTRN ffi_closure_win64_inner:NEAR + +_TEXT SEGMENT + +;;; ffi_closure_win64 will be called with these registers set: +;;; rax points to 'closure' +;;; r11 contains a bit mask that specifies which of the +;;; first four parameters are float or double +;;; +;;; It must move the parameters passed in registers to their stack location, +;;; call ffi_closure_win64_inner for the actual work, then return the result. +;;; +ffi_closure_win64 PROC FRAME + ;; copy register arguments onto stack + test r11, 1 + jne first_is_float + mov QWORD PTR [rsp+8], rcx + jmp second +first_is_float: + movlpd QWORD PTR [rsp+8], xmm0 + +second: + test r11, 2 + jne second_is_float + mov QWORD PTR [rsp+16], rdx + jmp third +second_is_float: + movlpd QWORD PTR [rsp+16], xmm1 + +third: + test r11, 4 + jne third_is_float + mov QWORD PTR [rsp+24], r8 + jmp fourth +third_is_float: + movlpd QWORD PTR [rsp+24], xmm2 + +fourth: + test r11, 8 + jne fourth_is_float + mov QWORD PTR [rsp+32], r9 + jmp done +fourth_is_float: + movlpd QWORD PTR [rsp+32], xmm3 + +done: + .ALLOCSTACK 40 + sub rsp, 40 + .ENDPROLOG + mov rcx, rax ; context is first parameter + mov rdx, rsp ; stack is second parameter + add rdx, 48 ; point to start of arguments + mov rax, ffi_closure_win64_inner + call rax ; call the real closure function + add rsp, 40 + movd xmm0, rax ; If the closure returned a float, + ; ffi_closure_win64_inner wrote it to rax + ret 0 +ffi_closure_win64 ENDP + +ffi_call_win64 PROC FRAME + ;; copy registers onto stack + mov QWORD PTR [rsp+32], r9 + mov QWORD PTR [rsp+24], r8 + mov QWORD PTR [rsp+16], rdx + mov QWORD PTR [rsp+8], rcx + .PUSHREG rbp + push rbp + .ALLOCSTACK 48 + sub rsp, 48 ; 00000030H + .SETFRAME rbp, 32 + lea rbp, QWORD PTR [rsp+32] + .ENDPROLOG + + mov eax, DWORD PTR CIF_BYTES[rbp] + add rax, 15 + and rax, -16 + call __chkstk + sub rsp, rax + lea rax, QWORD PTR [rsp+32] + mov QWORD PTR STACK[rbp], rax + + mov rdx, QWORD PTR ECIF[rbp] + mov rcx, QWORD PTR STACK[rbp] + call QWORD PTR PREP_ARGS_FN[rbp] + + mov rsp, QWORD PTR STACK[rbp] + + movlpd xmm3, QWORD PTR [rsp+24] + movd r9, xmm3 + + movlpd xmm2, QWORD PTR [rsp+16] + movd r8, xmm2 + + movlpd xmm1, QWORD PTR [rsp+8] + movd rdx, xmm1 + + movlpd xmm0, QWORD PTR [rsp] + movd rcx, xmm0 + + call QWORD PTR FN[rbp] +ret_struct4b$: + cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_4B + jne ret_struct2b$ + + mov rcx, QWORD PTR RVALUE[rbp] + mov DWORD PTR [rcx], eax + jmp ret_void$ + +ret_struct2b$: + cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_2B + jne ret_struct1b$ + + mov rcx, QWORD PTR RVALUE[rbp] + mov WORD PTR [rcx], ax + jmp ret_void$ + +ret_struct1b$: + cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_1B + jne ret_uint8$ + + mov rcx, QWORD PTR RVALUE[rbp] + mov BYTE PTR [rcx], al + jmp ret_void$ + +ret_uint8$: + cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT8 + jne ret_sint8$ + + mov rcx, QWORD PTR RVALUE[rbp] + movzx rax, al + mov QWORD PTR [rcx], rax + jmp ret_void$ + +ret_sint8$: + cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT8 + jne ret_uint16$ + + mov rcx, QWORD PTR RVALUE[rbp] + movsx rax, al + mov QWORD PTR [rcx], rax + jmp ret_void$ + +ret_uint16$: + cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT16 + jne ret_sint16$ + + mov rcx, QWORD PTR RVALUE[rbp] + movzx rax, ax + mov QWORD PTR [rcx], rax + jmp SHORT ret_void$ + +ret_sint16$: + cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT16 + jne ret_uint32$ + + mov rcx, QWORD PTR RVALUE[rbp] + movsx rax, ax + mov QWORD PTR [rcx], rax + jmp SHORT ret_void$ + +ret_uint32$: + cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT32 + jne ret_sint32$ + + mov rcx, QWORD PTR RVALUE[rbp] + mov eax, eax + mov QWORD PTR [rcx], rax + jmp SHORT ret_void$ + +ret_sint32$: + cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT32 + jne ret_float$ + + mov rcx, QWORD PTR RVALUE[rbp] + cdqe + mov QWORD PTR [rcx], rax + jmp SHORT ret_void$ + +ret_float$: + cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_FLOAT + jne SHORT ret_double$ + + mov rax, QWORD PTR RVALUE[rbp] + movss DWORD PTR [rax], xmm0 + jmp SHORT ret_void$ + +ret_double$: + cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_DOUBLE + jne SHORT ret_sint64$ + + mov rax, QWORD PTR RVALUE[rbp] + movlpd QWORD PTR [rax], xmm0 + jmp SHORT ret_void$ + +ret_sint64$: + cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT64 + jne ret_void$ + + mov rcx, QWORD PTR RVALUE[rbp] + mov QWORD PTR [rcx], rax + jmp SHORT ret_void$ + +ret_void$: + xor rax, rax + + lea rsp, QWORD PTR [rbp+16] + pop rbp + ret 0 +ffi_call_win64 ENDP +_TEXT ENDS +END +#else +.text + +.extern _ffi_closure_win64_inner + +# ffi_closure_win64 will be called with these registers set: +# rax points to 'closure' +# r11 contains a bit mask that specifies which of the +# first four parameters are float or double +# +# It must move the parameters passed in registers to their stack location, +# call ffi_closure_win64_inner for the actual work, then return the result. +# + .balign 16 + .globl _ffi_closure_win64 +_ffi_closure_win64: + # copy register arguments onto stack + test $1,%r11 + jne .Lfirst_is_float + mov %rcx, 8(%rsp) + jmp .Lsecond +.Lfirst_is_float: + movlpd %xmm0, 8(%rsp) + +.Lsecond: + test $2, %r11 + jne .Lsecond_is_float + mov %rdx, 16(%rsp) + jmp .Lthird +.Lsecond_is_float: + movlpd %xmm1, 16(%rsp) + +.Lthird: + test $4, %r11 + jne .Lthird_is_float + mov %r8,24(%rsp) + jmp .Lfourth +.Lthird_is_float: + movlpd %xmm2, 24(%rsp) + +.Lfourth: + test $8, %r11 + jne .Lfourth_is_float + mov %r9, 32(%rsp) + jmp .Ldone +.Lfourth_is_float: + movlpd %xmm3, 32(%rsp) + +.Ldone: +#.ALLOCSTACK 40 + sub $40, %rsp +#.ENDPROLOG + mov %rax, %rcx # context is first parameter + mov %rsp, %rdx # stack is second parameter + add $48, %rdx # point to start of arguments + mov $_ffi_closure_win64_inner, %rax + callq *%rax # call the real closure function + add $40, %rsp + movq %rax, %xmm0 # If the closure returned a float, + # ffi_closure_win64_inner wrote it to rax + retq +.ffi_closure_win64_end: + + .balign 16 + .globl _ffi_call_win64 +_ffi_call_win64: + # copy registers onto stack + mov %r9,32(%rsp) + mov %r8,24(%rsp) + mov %rdx,16(%rsp) + mov %rcx,8(%rsp) + #.PUSHREG rbp + push %rbp + #.ALLOCSTACK 48 + sub $48,%rsp + #.SETFRAME rbp, 32 + lea 32(%rsp),%rbp + #.ENDPROLOG + + mov CIF_BYTES(%rbp),%eax + add $15, %rax + and $-16, %rax + cmpq $0x1000, %rax + jb Lch_done +Lch_probe: + subq $0x1000,%rsp + orl $0x0, (%rsp) + subq $0x1000,%rax + cmpq $0x1000,%rax + ja Lch_probe +Lch_done: + subq %rax, %rsp + orl $0x0, (%rsp) + lea 32(%rsp), %rax + mov %rax, STACK(%rbp) + + mov ECIF(%rbp), %rdx + mov STACK(%rbp), %rcx + callq *PREP_ARGS_FN(%rbp) + + mov STACK(%rbp), %rsp + + movlpd 24(%rsp), %xmm3 + movd %xmm3, %r9 + + movlpd 16(%rsp), %xmm2 + movd %xmm2, %r8 + + movlpd 8(%rsp), %xmm1 + movd %xmm1, %rdx + + movlpd (%rsp), %xmm0 + movd %xmm0, %rcx + + callq *FN(%rbp) +.Lret_struct4b: + cmpl $FFI_TYPE_SMALL_STRUCT_4B, CIF_FLAGS(%rbp) + jne .Lret_struct2b + + mov RVALUE(%rbp), %rcx + mov %eax, (%rcx) + jmp .Lret_void + +.Lret_struct2b: + cmpl $FFI_TYPE_SMALL_STRUCT_2B, CIF_FLAGS(%rbp) + jne .Lret_struct1b + + mov RVALUE(%rbp), %rcx + mov %ax, (%rcx) + jmp .Lret_void + +.Lret_struct1b: + cmpl $FFI_TYPE_SMALL_STRUCT_1B, CIF_FLAGS(%rbp) + jne .Lret_uint8 + + mov RVALUE(%rbp), %rcx + mov %al, (%rcx) + jmp .Lret_void + +.Lret_uint8: + cmpl $FFI_TYPE_UINT8, CIF_FLAGS(%rbp) + jne .Lret_sint8 + + mov RVALUE(%rbp), %rcx + movzbq %al, %rax + movq %rax, (%rcx) + jmp .Lret_void + +.Lret_sint8: + cmpl $FFI_TYPE_SINT8, CIF_FLAGS(%rbp) + jne .Lret_uint16 + + mov RVALUE(%rbp), %rcx + movsbq %al, %rax + movq %rax, (%rcx) + jmp .Lret_void + +.Lret_uint16: + cmpl $FFI_TYPE_UINT16, CIF_FLAGS(%rbp) + jne .Lret_sint16 + + mov RVALUE(%rbp), %rcx + movzwq %ax, %rax + movq %rax, (%rcx) + jmp .Lret_void + +.Lret_sint16: + cmpl $FFI_TYPE_SINT16, CIF_FLAGS(%rbp) + jne .Lret_uint32 + + mov RVALUE(%rbp), %rcx + movswq %ax, %rax + movq %rax, (%rcx) + jmp .Lret_void + +.Lret_uint32: + cmpl $FFI_TYPE_UINT32, CIF_FLAGS(%rbp) + jne .Lret_sint32 + + mov RVALUE(%rbp), %rcx + movl %eax, %eax + movq %rax, (%rcx) + jmp .Lret_void + +.Lret_sint32: + cmpl $FFI_TYPE_SINT32, CIF_FLAGS(%rbp) + jne .Lret_float + + mov RVALUE(%rbp), %rcx + cltq + movq %rax, (%rcx) + jmp .Lret_void + +.Lret_float: + cmpl $FFI_TYPE_FLOAT, CIF_FLAGS(%rbp) + jne .Lret_double + + mov RVALUE(%rbp), %rax + movss %xmm0, (%rax) + jmp .Lret_void + +.Lret_double: + cmpl $FFI_TYPE_DOUBLE, CIF_FLAGS(%rbp) + jne .Lret_sint64 + + mov RVALUE(%rbp), %rax + movlpd %xmm0, (%rax) + jmp .Lret_void + +.Lret_sint64: + cmpl $FFI_TYPE_SINT64, CIF_FLAGS(%rbp) + jne .Lret_void + + mov RVALUE(%rbp), %rcx + mov %rax, (%rcx) + jmp .Lret_void + +.Lret_void: + xor %rax, %rax + + lea 16(%rbp), %rsp + pop %rbp + retq +.ffi_call_win64_end: +#endif /* !_MSC_VER */ + diff --git a/js/src/ctypes/libffi/stamp-h.in b/js/src/ctypes/libffi/stamp-h.in new file mode 100644 index 0000000..9788f70 --- /dev/null +++ b/js/src/ctypes/libffi/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/js/src/ctypes/libffi/testsuite/Makefile.am b/js/src/ctypes/libffi/testsuite/Makefile.am new file mode 100644 index 0000000..eae3d74 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/Makefile.am @@ -0,0 +1,80 @@ +## Process this file with automake to produce Makefile.in. + +AUTOMAKE_OPTIONS = foreign dejagnu + +# Setup the testing framework, if you have one +EXPECT = `if [ -f $(top_builddir)/../expect/expect ] ; then \ + echo $(top_builddir)/../expect/expect ; \ + else echo expect ; fi` + +RUNTEST = `if [ -f $(top_srcdir)/../dejagnu/runtest ] ; then \ + echo $(top_srcdir)/../dejagnu/runtest ; \ + else echo runtest; fi` + +AM_RUNTESTFLAGS = + +CLEANFILES = *.exe core* *.log *.sum + +EXTRA_DIST = libffi.special/special.exp \ +libffi.special/unwindtest_ffi_call.cc libffi.special/unwindtest.cc \ +libffi.special/ffitestcxx.h config/default.exp lib/target-libpath.exp \ +lib/libffi-dg.exp lib/wrapper.exp libffi.call/float.c \ +libffi.call/cls_multi_schar.c libffi.call/float3.c \ +libffi.call/cls_3_1byte.c libffi.call/stret_large2.c \ +libffi.call/cls_5_1_byte.c libffi.call/stret_medium.c \ +libffi.call/promotion.c libffi.call/cls_dbls_struct.c \ +libffi.call/nested_struct.c libffi.call/closure_fn1.c \ +libffi.call/cls_4_1byte.c libffi.call/cls_float.c \ +libffi.call/cls_2byte.c libffi.call/closure_fn4.c \ +libffi.call/return_fl2.c libffi.call/nested_struct7.c \ +libffi.call/cls_uint.c libffi.call/cls_align_sint64.c \ +libffi.call/float1.c libffi.call/cls_19byte.c \ +libffi.call/nested_struct1.c libffi.call/cls_4byte.c \ +libffi.call/return_fl1.c libffi.call/cls_align_pointer.c \ +libffi.call/nested_struct4.c libffi.call/nested_struct3.c \ +libffi.call/struct7.c libffi.call/nested_struct9.c \ +libffi.call/cls_sshort.c libffi.call/cls_ulonglong.c \ +libffi.call/cls_pointer_stack.c libffi.call/cls_multi_uchar.c \ +libffi.call/testclosure.c libffi.call/cls_3byte1.c \ +libffi.call/struct6.c libffi.call/return_uc.c libffi.call/return_ll1.c \ +libffi.call/cls_ushort.c libffi.call/stret_medium2.c \ +libffi.call/cls_multi_ushortchar.c libffi.call/return_dbl2.c \ +libffi.call/closure_loc_fn0.c libffi.call/return_sc.c \ +libffi.call/nested_struct8.c libffi.call/cls_7_1_byte.c \ +libffi.call/return_ll.c libffi.call/cls_pointer.c \ +libffi.call/err_bad_abi.c libffi.call/return_dbl1.c \ +libffi.call/call.exp libffi.call/ffitest.h libffi.call/strlen.c \ +libffi.call/return_sl.c libffi.call/cls_1_1byte.c \ +libffi.call/struct1.c libffi.call/cls_64byte.c libffi.call/return_ul.c \ +libffi.call/cls_double.c libffi.call/many_win32.c \ +libffi.call/cls_16byte.c libffi.call/cls_align_double.c \ +libffi.call/cls_align_uint16.c libffi.call/cls_9byte1.c \ +libffi.call/cls_multi_sshortchar.c libffi.call/cls_multi_ushort.c \ +libffi.call/closure_stdcall.c libffi.call/return_fl.c \ +libffi.call/strlen_win32.c libffi.call/return_ldl.c \ +libffi.call/cls_align_float.c libffi.call/struct3.c \ +libffi.call/cls_uchar.c libffi.call/cls_sint.c libffi.call/float2.c \ +libffi.call/cls_align_longdouble_split.c \ +libffi.call/cls_longdouble_va.c libffi.call/cls_multi_sshort.c \ +libffi.call/stret_large.c libffi.call/cls_align_sint16.c \ +libffi.call/nested_struct6.c libffi.call/cls_5byte.c \ +libffi.call/return_dbl.c libffi.call/cls_20byte.c \ +libffi.call/cls_8byte.c libffi.call/pyobjc-tc.c \ +libffi.call/cls_24byte.c libffi.call/cls_align_longdouble_split2.c \ +libffi.call/cls_6_1_byte.c libffi.call/cls_schar.c \ +libffi.call/cls_18byte.c libffi.call/closure_fn3.c \ +libffi.call/err_bad_typedef.c libffi.call/closure_fn2.c \ +libffi.call/struct2.c libffi.call/cls_3byte2.c \ +libffi.call/cls_align_longdouble.c libffi.call/cls_20byte1.c \ +libffi.call/return_fl3.c libffi.call/cls_align_uint32.c \ +libffi.call/problem1.c libffi.call/float4.c \ +libffi.call/cls_align_uint64.c libffi.call/struct9.c \ +libffi.call/closure_fn5.c libffi.call/cls_align_sint32.c \ +libffi.call/closure_fn0.c libffi.call/closure_fn6.c \ +libffi.call/struct4.c libffi.call/nested_struct2.c \ +libffi.call/cls_6byte.c libffi.call/cls_7byte.c libffi.call/many.c \ +libffi.call/struct8.c libffi.call/negint.c libffi.call/struct5.c \ +libffi.call/cls_12byte.c libffi.call/cls_double_va.c \ +libffi.call/cls_longdouble.c libffi.call/cls_9byte2.c \ +libffi.call/nested_struct10.c libffi.call/nested_struct5.c \ +libffi.call/huge_struct.c diff --git a/js/src/ctypes/libffi/testsuite/Makefile.in b/js/src/ctypes/libffi/testsuite/Makefile.in new file mode 100644 index 0000000..5888c56 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/Makefile.in @@ -0,0 +1,484 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = testsuite +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/fficonfig.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +DEJATOOL = $(PACKAGE) +RUNTESTDEFAULTFLAGS = --tool $$tool --srcdir $$srcdir +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_LTLDFLAGS = @AM_LTLDFLAGS@ +AM_RUNTESTFLAGS = +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_LONG_DOUBLE = @HAVE_LONG_DOUBLE@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TARGET = @TARGET@ +TARGETDIR = @TARGETDIR@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +toolexecdir = @toolexecdir@ +toolexeclibdir = @toolexeclibdir@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign dejagnu + +# Setup the testing framework, if you have one +EXPECT = `if [ -f $(top_builddir)/../expect/expect ] ; then \ + echo $(top_builddir)/../expect/expect ; \ + else echo expect ; fi` + +RUNTEST = `if [ -f $(top_srcdir)/../dejagnu/runtest ] ; then \ + echo $(top_srcdir)/../dejagnu/runtest ; \ + else echo runtest; fi` + +CLEANFILES = *.exe core* *.log *.sum +EXTRA_DIST = libffi.special/special.exp \ +libffi.special/unwindtest_ffi_call.cc libffi.special/unwindtest.cc \ +libffi.special/ffitestcxx.h config/default.exp lib/target-libpath.exp \ +lib/libffi-dg.exp lib/wrapper.exp libffi.call/float.c \ +libffi.call/cls_multi_schar.c libffi.call/float3.c \ +libffi.call/cls_3_1byte.c libffi.call/stret_large2.c \ +libffi.call/cls_5_1_byte.c libffi.call/stret_medium.c \ +libffi.call/promotion.c libffi.call/cls_dbls_struct.c \ +libffi.call/nested_struct.c libffi.call/closure_fn1.c \ +libffi.call/cls_4_1byte.c libffi.call/cls_float.c \ +libffi.call/cls_2byte.c libffi.call/closure_fn4.c \ +libffi.call/return_fl2.c libffi.call/nested_struct7.c \ +libffi.call/cls_uint.c libffi.call/cls_align_sint64.c \ +libffi.call/float1.c libffi.call/cls_19byte.c \ +libffi.call/nested_struct1.c libffi.call/cls_4byte.c \ +libffi.call/return_fl1.c libffi.call/cls_align_pointer.c \ +libffi.call/nested_struct4.c libffi.call/nested_struct3.c \ +libffi.call/struct7.c libffi.call/nested_struct9.c \ +libffi.call/cls_sshort.c libffi.call/cls_ulonglong.c \ +libffi.call/cls_pointer_stack.c libffi.call/cls_multi_uchar.c \ +libffi.call/testclosure.c libffi.call/cls_3byte1.c \ +libffi.call/struct6.c libffi.call/return_uc.c libffi.call/return_ll1.c \ +libffi.call/cls_ushort.c libffi.call/stret_medium2.c \ +libffi.call/cls_multi_ushortchar.c libffi.call/return_dbl2.c \ +libffi.call/closure_loc_fn0.c libffi.call/return_sc.c \ +libffi.call/nested_struct8.c libffi.call/cls_7_1_byte.c \ +libffi.call/return_ll.c libffi.call/cls_pointer.c \ +libffi.call/err_bad_abi.c libffi.call/return_dbl1.c \ +libffi.call/call.exp libffi.call/ffitest.h libffi.call/strlen.c \ +libffi.call/return_sl.c libffi.call/cls_1_1byte.c \ +libffi.call/struct1.c libffi.call/cls_64byte.c libffi.call/return_ul.c \ +libffi.call/cls_double.c libffi.call/many_win32.c \ +libffi.call/cls_16byte.c libffi.call/cls_align_double.c \ +libffi.call/cls_align_uint16.c libffi.call/cls_9byte1.c \ +libffi.call/cls_multi_sshortchar.c libffi.call/cls_multi_ushort.c \ +libffi.call/closure_stdcall.c libffi.call/return_fl.c \ +libffi.call/strlen_win32.c libffi.call/return_ldl.c \ +libffi.call/cls_align_float.c libffi.call/struct3.c \ +libffi.call/cls_uchar.c libffi.call/cls_sint.c libffi.call/float2.c \ +libffi.call/cls_align_longdouble_split.c \ +libffi.call/cls_longdouble_va.c libffi.call/cls_multi_sshort.c \ +libffi.call/stret_large.c libffi.call/cls_align_sint16.c \ +libffi.call/nested_struct6.c libffi.call/cls_5byte.c \ +libffi.call/return_dbl.c libffi.call/cls_20byte.c \ +libffi.call/cls_8byte.c libffi.call/pyobjc-tc.c \ +libffi.call/cls_24byte.c libffi.call/cls_align_longdouble_split2.c \ +libffi.call/cls_6_1_byte.c libffi.call/cls_schar.c \ +libffi.call/cls_18byte.c libffi.call/closure_fn3.c \ +libffi.call/err_bad_typedef.c libffi.call/closure_fn2.c \ +libffi.call/struct2.c libffi.call/cls_3byte2.c \ +libffi.call/cls_align_longdouble.c libffi.call/cls_20byte1.c \ +libffi.call/return_fl3.c libffi.call/cls_align_uint32.c \ +libffi.call/problem1.c libffi.call/float4.c \ +libffi.call/cls_align_uint64.c libffi.call/struct9.c \ +libffi.call/closure_fn5.c libffi.call/cls_align_sint32.c \ +libffi.call/closure_fn0.c libffi.call/closure_fn6.c \ +libffi.call/struct4.c libffi.call/nested_struct2.c \ +libffi.call/cls_6byte.c libffi.call/cls_7byte.c libffi.call/many.c \ +libffi.call/struct8.c libffi.call/negint.c libffi.call/struct5.c \ +libffi.call/cls_12byte.c libffi.call/cls_double_va.c \ +libffi.call/cls_longdouble.c libffi.call/cls_9byte2.c \ +libffi.call/nested_struct10.c libffi.call/nested_struct5.c \ +libffi.call/huge_struct.c + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign testsuite/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +check-DEJAGNU: site.exp + srcdir=`$(am__cd) $(srcdir) && pwd`; export srcdir; \ + EXPECT=$(EXPECT); export EXPECT; \ + runtest=$(RUNTEST); \ + if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \ + exit_status=0; l='$(DEJATOOL)'; for tool in $$l; do \ + if $$runtest $(AM_RUNTESTFLAGS) $(RUNTESTDEFAULTFLAGS) $(RUNTESTFLAGS); \ + then :; else exit_status=1; fi; \ + done; \ + else echo "WARNING: could not find \`runtest'" 1>&2; :;\ + fi; \ + exit $$exit_status +site.exp: Makefile + @echo 'Making a new site.exp file...' + @echo '## these variables are automatically generated by make ##' >site.tmp + @echo '# Do not edit here. If you wish to override these values' >>site.tmp + @echo '# edit the last section' >>site.tmp + @echo 'set srcdir $(srcdir)' >>site.tmp + @echo "set objdir `pwd`" >>site.tmp + @echo 'set build_alias "$(build_alias)"' >>site.tmp + @echo 'set build_triplet $(build_triplet)' >>site.tmp + @echo 'set host_alias "$(host_alias)"' >>site.tmp + @echo 'set host_triplet $(host_triplet)' >>site.tmp + @echo 'set target_alias "$(target_alias)"' >>site.tmp + @echo 'set target_triplet $(target_triplet)' >>site.tmp + @echo '## All variables above are generated by configure. Do Not Edit ##' >>site.tmp + @test ! -f site.exp || \ + sed '1,/^## All variables above are.*##/ d' site.exp >> site.tmp + @-rm -f site.bak + @test ! -f site.exp || mv site.exp site.bak + @mv site.tmp site.exp + +distclean-DEJAGNU: + -rm -f site.exp site.bak + -l='$(DEJATOOL)'; for tool in $$l; do \ + rm -f $$tool.sum $$tool.log; \ + done + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-DEJAGNU distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: all all-am check check-DEJAGNU check-am clean clean-generic \ + clean-libtool distclean distclean-DEJAGNU distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/js/src/ctypes/libffi/testsuite/config/default.exp b/js/src/ctypes/libffi/testsuite/config/default.exp new file mode 100644 index 0000000..90967cc --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/config/default.exp @@ -0,0 +1 @@ +load_lib "standard.exp" diff --git a/js/src/ctypes/libffi/testsuite/lib/libffi-dg.exp b/js/src/ctypes/libffi/testsuite/lib/libffi-dg.exp new file mode 100644 index 0000000..ca5f751 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/lib/libffi-dg.exp @@ -0,0 +1,350 @@ +# Copyright (C) 2003, 2005, 2008, 2009, 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +proc load_gcc_lib { filename } { + global srcdir + load_file $srcdir/lib/$filename +} + +load_lib dg.exp +load_lib libgloss.exp +load_gcc_lib target-libpath.exp +load_gcc_lib wrapper.exp + + +# Define libffi callbacks for dg.exp. + +proc libffi-dg-test-1 { target_compile prog do_what extra_tool_flags } { + + # To get all \n in dg-output test strings to match printf output + # in a system that outputs it as \015\012 (i.e. not just \012), we + # need to change all \n into \r?\n. As there is no dejagnu flag + # or hook to do that, we simply change the text being tested. + # Unfortunately, we have to know that the variable is called + # dg-output-text and lives in the caller of libffi-dg-test, which + # is two calls up. Overriding proc dg-output would be longer and + # would necessarily have the same assumption. + upvar 2 dg-output-text output_match + + if { [llength $output_match] > 1 } { + regsub -all "\n" [lindex $output_match 1] "\r?\n" x + set output_match [lreplace $output_match 1 1 $x] + } + + # Set up the compiler flags, based on what we're going to do. + + set options [list] + switch $do_what { + "compile" { + set compile_type "assembly" + set output_file "[file rootname [file tail $prog]].s" + } + "link" { + set compile_type "executable" + set output_file "[file rootname [file tail $prog]].exe" + # The following line is needed for targets like the i960 where + # the default output file is b.out. Sigh. + } + "run" { + set compile_type "executable" + # FIXME: "./" is to cope with "." not being in $PATH. + # Should this be handled elsewhere? + # YES. + set output_file "./[file rootname [file tail $prog]].exe" + # This is the only place where we care if an executable was + # created or not. If it was, dg.exp will try to run it. + remote_file build delete $output_file; + } + default { + perror "$do_what: not a valid dg-do keyword" + return "" + } + } + + if { $extra_tool_flags != "" } { + lappend options "additional_flags=$extra_tool_flags" + } + + set comp_output [libffi_target_compile "$prog" "$output_file" "$compile_type" $options]; + + + return [list $comp_output $output_file] +} + + +proc libffi-dg-test { prog do_what extra_tool_flags } { + return [libffi-dg-test-1 target_compile $prog $do_what $extra_tool_flags] +} + +proc libffi-init { args } { + global gluefile wrap_flags; + global srcdir + global blddirffi + global objdir + global TOOL_OPTIONS + global tool + global libffi_include + global libffi_link_flags + global tool_root_dir + global ld_library_path + + set blddirffi [pwd]/.. + verbose "libffi $blddirffi" + + set gccdir [lookfor_file $tool_root_dir gcc/libgcc.a] + if {$gccdir != ""} { + set gccdir [file dirname $gccdir] + } + verbose "gccdir $gccdir" + + set ld_library_path "." + append ld_library_path ":${gccdir}" + + set compiler "${gccdir}/xgcc" + if { [is_remote host] == 0 && [which $compiler] != 0 } { + foreach i "[exec $compiler --print-multi-lib]" { + set mldir "" + regexp -- "\[a-z0-9=_/\.-\]*;" $i mldir + set mldir [string trimright $mldir "\;@"] + if { "$mldir" == "." } { + continue + } + if { [llength [glob -nocomplain ${gccdir}/${mldir}/libgcc_s*.so.*]] >= 1 } { + append ld_library_path ":${gccdir}/${mldir}" + } + } + } + # add the library path for libffi. + append ld_library_path ":${blddirffi}/.libs" + + verbose "ld_library_path: $ld_library_path" + + # Point to the Libffi headers in libffi. + set libffi_include "${blddirffi}/include" + verbose "libffi_include $libffi_include" + + set libffi_dir "${blddirffi}/.libs" + verbose "libffi_dir $libffi_dir" + if { $libffi_dir != "" } { + set libffi_dir [file dirname ${libffi_dir}] + set libffi_link_flags "-L${libffi_dir}/.libs" + } + + set_ld_library_path_env_vars + libffi_maybe_build_wrapper "${objdir}/testglue.o" +} + +proc libffi_exit { } { + global gluefile; + + if [info exists gluefile] { + file_on_build delete $gluefile; + unset gluefile; + } +} + +proc libffi_target_compile { source dest type options } { + global gluefile wrap_flags; + global srcdir + global blddirffi + global TOOL_OPTIONS + global libffi_link_flags + global libffi_include + global target_triplet + + + if { [target_info needs_status_wrapper]!="" && [info exists gluefile] } { + lappend options "libs=${gluefile}" + lappend options "ldflags=$wrap_flags" + } + + # TOOL_OPTIONS must come first, so that it doesn't override testcase + # specific options. + if [info exists TOOL_OPTIONS] { + lappend options [concat "additional_flags=$TOOL_OPTIONS" $options]; + } + + # search for ffi_mips.h in srcdir, too + lappend options "additional_flags=-I${libffi_include} -I${srcdir}/../include -I${libffi_include}/.." + lappend options "additional_flags=${libffi_link_flags}" + + # Darwin needs a stack execution allowed flag. + + if { [istarget "*-*-darwin9*"] || [istarget "*-*-darwin1*"] + || [istarget "*-*-darwin2*"] } { + lappend options "additional_flags=-Wl,-allow_stack_execute" + } + + # If you're building the compiler with --prefix set to a place + # where it's not yet installed, then the linker won't be able to + # find the libgcc used by libffi.dylib. We could pass the + # -dylib_file option, but that's complicated, and it's much easier + # to just make the linker find libgcc using -L options. + if { [string match "*-*-darwin*" $target_triplet] } { + lappend options "libs= -shared-libgcc" + } + + if { [string match "*-*-openbsd*" $target_triplet] } { + lappend options "libs= -lpthread" + } + + lappend options "libs= -lffi" + + verbose "options: $options" + return [target_compile $source $dest $type $options] +} + +# Utility routines. + +# +# search_for -- looks for a string match in a file +# +proc search_for { file pattern } { + set fd [open $file r] + while { [gets $fd cur_line]>=0 } { + if [string match "*$pattern*" $cur_line] then { + close $fd + return 1 + } + } + close $fd + return 0 +} + +# Modified dg-runtest that can cycle through a list of optimization options +# as c-torture does. +proc libffi-dg-runtest { testcases default-extra-flags } { + global runtests + + foreach test $testcases { + # If we're only testing specific files and this isn't one of + # them, skip it. + if ![runtest_file_p $runtests $test] { + continue + } + + # Look for a loop within the source code - if we don't find one, + # don't pass -funroll[-all]-loops. + global torture_with_loops torture_without_loops + if [expr [search_for $test "for*("]+[search_for $test "while*("]] { + set option_list $torture_with_loops + } else { + set option_list $torture_without_loops + } + + set nshort [file tail [file dirname $test]]/[file tail $test] + + foreach flags $option_list { + verbose "Testing $nshort, $flags" 1 + dg-test $test $flags ${default-extra-flags} + } + } +} + + +# Like check_conditional_xfail, but callable from a dg test. + +proc dg-xfail-if { args } { + set args [lreplace $args 0 0] + set selector "target [join [lindex $args 1]]" + if { [dg-process-target $selector] == "S" } { + global compiler_conditional_xfail_data + set compiler_conditional_xfail_data $args + } +} + +proc check-flags { args } { + + # The args are within another list; pull them out. + set args [lindex $args 0] + + # The next two arguments are optional. If they were not specified, + # use the defaults. + if { [llength $args] == 2 } { + lappend $args [list "*"] + } + if { [llength $args] == 3 } { + lappend $args [list ""] + } + + # If the option strings are the defaults, or the same as the + # defaults, there is no need to call check_conditional_xfail to + # compare them to the actual options. + if { [string compare [lindex $args 2] "*"] == 0 + && [string compare [lindex $args 3] "" ] == 0 } { + set result 1 + } else { + # The target list might be an effective-target keyword, so replace + # the original list with "*-*-*", since we already know it matches. + set result [check_conditional_xfail [lreplace $args 1 1 "*-*-*"]] + } + + return $result +} + +proc dg-skip-if { args } { + # Verify the number of arguments. The last two are optional. + set args [lreplace $args 0 0] + if { [llength $args] < 2 || [llength $args] > 4 } { + error "dg-skip-if 2: need 2, 3, or 4 arguments" + } + + # Don't bother if we're already skipping the test. + upvar dg-do-what dg-do-what + if { [lindex ${dg-do-what} 1] == "N" } { + return + } + + set selector [list target [lindex $args 1]] + if { [dg-process-target $selector] == "S" } { + if [check-flags $args] { + upvar dg-do-what dg-do-what + set dg-do-what [list [lindex ${dg-do-what} 0] "N" "P"] + } + } +} + +# We need to make sure that additional_files and additional_sources +# are both cleared out after every test. It is not enough to clear +# them out *before* the next test run because gcc-target-compile gets +# run directly from some .exp files (outside of any test). (Those +# uses should eventually be eliminated.) + +# Because the DG framework doesn't provide a hook that is run at the +# end of a test, we must replace dg-test with a wrapper. + +if { [info procs saved-dg-test] == [list] } { + rename dg-test saved-dg-test + + proc dg-test { args } { + global additional_files + global additional_sources + global errorInfo + + if { [ catch { eval saved-dg-test $args } errmsg ] } { + set saved_info $errorInfo + set additional_files "" + set additional_sources "" + error $errmsg $saved_info + } + set additional_files "" + set additional_sources "" + } +} + +# Local Variables: +# tcl-indent-level:4 +# End: diff --git a/js/src/ctypes/libffi/testsuite/lib/target-libpath.exp b/js/src/ctypes/libffi/testsuite/lib/target-libpath.exp new file mode 100644 index 0000000..8999aa4 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/lib/target-libpath.exp @@ -0,0 +1,263 @@ +# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# This file was contributed by John David Anglin (dave.anglin@nrc-cnrc.gc.ca) + +set orig_environment_saved 0 +set orig_ld_library_path_saved 0 +set orig_ld_run_path_saved 0 +set orig_shlib_path_saved 0 +set orig_ld_libraryn32_path_saved 0 +set orig_ld_library64_path_saved 0 +set orig_ld_library_path_32_saved 0 +set orig_ld_library_path_64_saved 0 +set orig_dyld_library_path_saved 0 + + +####################################### +# proc set_ld_library_path_env_vars { } +####################################### + +proc set_ld_library_path_env_vars { } { + global ld_library_path + global orig_environment_saved + global orig_ld_library_path_saved + global orig_ld_run_path_saved + global orig_shlib_path_saved + global orig_ld_libraryn32_path_saved + global orig_ld_library64_path_saved + global orig_ld_library_path_32_saved + global orig_ld_library_path_64_saved + global orig_dyld_library_path_saved + global orig_ld_library_path + global orig_ld_run_path + global orig_shlib_path + global orig_ld_libraryn32_path + global orig_ld_library64_path + global orig_ld_library_path_32 + global orig_ld_library_path_64 + global orig_dyld_library_path + global GCC_EXEC_PREFIX + + # Set the relocated compiler prefix, but only if the user hasn't specified one. + if { [info exists GCC_EXEC_PREFIX] && ![info exists env(GCC_EXEC_PREFIX)] } { + setenv GCC_EXEC_PREFIX "$GCC_EXEC_PREFIX" + } + + # Setting the ld library path causes trouble when testing cross-compilers. + if { [is_remote target] } { + return + } + + if { $orig_environment_saved == 0 } { + global env + + set orig_environment_saved 1 + + # Save the original environment. + if [info exists env(LD_LIBRARY_PATH)] { + set orig_ld_library_path "$env(LD_LIBRARY_PATH)" + set orig_ld_library_path_saved 1 + } + if [info exists env(LD_RUN_PATH)] { + set orig_ld_run_path "$env(LD_RUN_PATH)" + set orig_ld_run_path_saved 1 + } + if [info exists env(SHLIB_PATH)] { + set orig_shlib_path "$env(SHLIB_PATH)" + set orig_shlib_path_saved 1 + } + if [info exists env(LD_LIBRARYN32_PATH)] { + set orig_ld_libraryn32_path "$env(LD_LIBRARYN32_PATH)" + set orig_ld_libraryn32_path_saved 1 + } + if [info exists env(LD_LIBRARY64_PATH)] { + set orig_ld_library64_path "$env(LD_LIBRARY64_PATH)" + set orig_ld_library64_path_saved 1 + } + if [info exists env(LD_LIBRARY_PATH_32)] { + set orig_ld_library_path_32 "$env(LD_LIBRARY_PATH_32)" + set orig_ld_library_path_32_saved 1 + } + if [info exists env(LD_LIBRARY_PATH_64)] { + set orig_ld_library_path_64 "$env(LD_LIBRARY_PATH_64)" + set orig_ld_library_path_64_saved 1 + } + if [info exists env(DYLD_LIBRARY_PATH)] { + set orig_dyld_library_path "$env(DYLD_LIBRARY_PATH)" + set orig_dyld_library_path_saved 1 + } + } + + # We need to set ld library path in the environment. Currently, + # unix.exp doesn't set the environment correctly for all systems. + # It only sets SHLIB_PATH and LD_LIBRARY_PATH when it executes a + # program. We also need the environment set for compilations, etc. + # + # On IRIX 6, we have to set variables akin to LD_LIBRARY_PATH, but + # called LD_LIBRARYN32_PATH (for the N32 ABI) and LD_LIBRARY64_PATH + # (for the 64-bit ABI). The same applies to Darwin (DYLD_LIBRARY_PATH), + # Solaris 32 bit (LD_LIBRARY_PATH_32), Solaris 64 bit (LD_LIBRARY_PATH_64), + # and HP-UX (SHLIB_PATH). In some cases, the variables are independent + # of LD_LIBRARY_PATH, and in other cases LD_LIBRARY_PATH is used if the + # variable is not defined. + # + # Doing this is somewhat of a hack as ld_library_path gets repeated in + # SHLIB_PATH and LD_LIBRARY_PATH when unix_load sets these variables. + if { $orig_ld_library_path_saved } { + setenv LD_LIBRARY_PATH "$ld_library_path:$orig_ld_library_path" + } else { + setenv LD_LIBRARY_PATH "$ld_library_path" + } + if { $orig_ld_run_path_saved } { + setenv LD_RUN_PATH "$ld_library_path:$orig_ld_run_path" + } else { + setenv LD_RUN_PATH "$ld_library_path" + } + # The default shared library dynamic path search for 64-bit + # HP-UX executables searches LD_LIBRARY_PATH before SHLIB_PATH. + # LD_LIBRARY_PATH isn't used for 32-bit executables. Thus, we + # set LD_LIBRARY_PATH and SHLIB_PATH as if they were independent. + if { $orig_shlib_path_saved } { + setenv SHLIB_PATH "$ld_library_path:$orig_shlib_path" + } else { + setenv SHLIB_PATH "$ld_library_path" + } + if { $orig_ld_libraryn32_path_saved } { + setenv LD_LIBRARYN32_PATH "$ld_library_path:$orig_ld_libraryn32_path" + } elseif { $orig_ld_library_path_saved } { + setenv LD_LIBRARYN32_PATH "$ld_library_path:$orig_ld_library_path" + } else { + setenv LD_LIBRARYN32_PATH "$ld_library_path" + } + if { $orig_ld_library64_path_saved } { + setenv LD_LIBRARY64_PATH "$ld_library_path:$orig_ld_library64_path" + } elseif { $orig_ld_library_path_saved } { + setenv LD_LIBRARY64_PATH "$ld_library_path:$orig_ld_library_path" + } else { + setenv LD_LIBRARY64_PATH "$ld_library_path" + } + if { $orig_ld_library_path_32_saved } { + setenv LD_LIBRARY_PATH_32 "$ld_library_path:$orig_ld_library_path_32" + } elseif { $orig_ld_library_path_saved } { + setenv LD_LIBRARY_PATH_32 "$ld_library_path:$orig_ld_library_path" + } else { + setenv LD_LIBRARY_PATH_32 "$ld_library_path" + } + if { $orig_ld_library_path_64_saved } { + setenv LD_LIBRARY_PATH_64 "$ld_library_path:$orig_ld_library_path_64" + } elseif { $orig_ld_library_path_saved } { + setenv LD_LIBRARY_PATH_64 "$ld_library_path:$orig_ld_library_path" + } else { + setenv LD_LIBRARY_PATH_64 "$ld_library_path" + } + if { $orig_dyld_library_path_saved } { + setenv DYLD_LIBRARY_PATH "$ld_library_path:$orig_dyld_library_path" + } else { + setenv DYLD_LIBRARY_PATH "$ld_library_path" + } + + verbose -log "set_ld_library_path_env_vars: ld_library_path=$ld_library_path" +} + +####################################### +# proc restore_ld_library_path_env_vars { } +####################################### + +proc restore_ld_library_path_env_vars { } { + global orig_environment_saved + global orig_ld_library_path_saved + global orig_ld_run_path_saved + global orig_shlib_path_saved + global orig_ld_libraryn32_path_saved + global orig_ld_library64_path_saved + global orig_ld_library_path_32_saved + global orig_ld_library_path_64_saved + global orig_dyld_library_path_saved + global orig_ld_library_path + global orig_ld_run_path + global orig_shlib_path + global orig_ld_libraryn32_path + global orig_ld_library64_path + global orig_ld_library_path_32 + global orig_ld_library_path_64 + global orig_dyld_library_path + + if { $orig_environment_saved == 0 } { + return + } + + if { $orig_ld_library_path_saved } { + setenv LD_LIBRARY_PATH "$orig_ld_library_path" + } elseif [info exists env(LD_LIBRARY_PATH)] { + unsetenv LD_LIBRARY_PATH + } + if { $orig_ld_run_path_saved } { + setenv LD_RUN_PATH "$orig_ld_run_path" + } elseif [info exists env(LD_RUN_PATH)] { + unsetenv LD_RUN_PATH + } + if { $orig_shlib_path_saved } { + setenv SHLIB_PATH "$orig_shlib_path" + } elseif [info exists env(SHLIB_PATH)] { + unsetenv SHLIB_PATH + } + if { $orig_ld_libraryn32_path_saved } { + setenv LD_LIBRARYN32_PATH "$orig_ld_libraryn32_path" + } elseif [info exists env(LD_LIBRARYN32_PATH)] { + unsetenv LD_LIBRARYN32_PATH + } + if { $orig_ld_library64_path_saved } { + setenv LD_LIBRARY64_PATH "$orig_ld_library64_path" + } elseif [info exists env(LD_LIBRARY64_PATH)] { + unsetenv LD_LIBRARY64_PATH + } + if { $orig_ld_library_path_32_saved } { + setenv LD_LIBRARY_PATH_32 "$orig_ld_library_path_32" + } elseif [info exists env(LD_LIBRARY_PATH_32)] { + unsetenv LD_LIBRARY_PATH_32 + } + if { $orig_ld_library_path_64_saved } { + setenv LD_LIBRARY_PATH_64 "$orig_ld_library_path_64" + } elseif [info exists env(LD_LIBRARY_PATH_64)] { + unsetenv LD_LIBRARY_PATH_64 + } + if { $orig_dyld_library_path_saved } { + setenv DYLD_LIBRARY_PATH "$orig_dyld_library_path" + } elseif [info exists env(DYLD_LIBRARY_PATH)] { + unsetenv DYLD_LIBRARY_PATH + } +} + +####################################### +# proc get_shlib_extension { } +####################################### + +proc get_shlib_extension { } { + global shlib_ext + + if { [ istarget *-*-darwin* ] } { + set shlib_ext "dylib" + } elseif { [ istarget *-*-cygwin* ] || [ istarget *-*-mingw* ] } { + set shlib_ext "dll" + } elseif { [ istarget hppa*-*-hpux* ] } { + set shlib_ext "sl" + } else { + set shlib_ext "so" + } + return $shlib_ext +} + diff --git a/js/src/ctypes/libffi/testsuite/lib/wrapper.exp b/js/src/ctypes/libffi/testsuite/lib/wrapper.exp new file mode 100644 index 0000000..4e5ae43 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/lib/wrapper.exp @@ -0,0 +1,45 @@ +# Copyright (C) 2004, 2007 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# This file contains GCC-specifics for status wrappers for test programs. + +# ${tool}_maybe_build_wrapper -- Build wrapper object if the target +# needs it. FILENAME is the path to the wrapper file. If there are +# additional arguments, they are command-line options to provide to +# the compiler when compiling FILENAME. + +proc ${tool}_maybe_build_wrapper { filename args } { + global gluefile wrap_flags + + if { [target_info needs_status_wrapper] != "" \ + && [target_info needs_status_wrapper] != "0" \ + && ![info exists gluefile] } { + set saved_wrap_compile_flags [target_info wrap_compile_flags] + set flags [join $args " "] + # The wrapper code may contain code that gcc objects on. This + # became true for dejagnu-1.4.4. The set of warnings and code + # that gcc objects on may change, so just make sure -w is always + # passed to turn off all warnings. + set_currtarget_info wrap_compile_flags \ + "$saved_wrap_compile_flags -w $flags" + set result [build_wrapper $filename] + set_currtarget_info wrap_compile_flags "$saved_wrap_compile_flags" + if { $result != "" } { + set gluefile [lindex $result 0] + set wrap_flags [lindex $result 1] + } + } +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/call.exp b/js/src/ctypes/libffi/testsuite/libffi.call/call.exp new file mode 100644 index 0000000..1e9985e --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/call.exp @@ -0,0 +1,36 @@ +# Copyright (C) 2003, 2006, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING3. If not see +# . + +# libffi testsuite that uses the 'dg.exp' driver. + +load_lib libffi-dg.exp + +dg-init +libffi-init + +global srcdir subdir + +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] "-O0 -W -Wall" "" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] "-O2" "" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] "-O3" "" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] "-Os" "" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] "-O2 -fomit-frame-pointer" "" + +dg-finish + +# Local Variables: +# tcl-indent-level:4 +# End: diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn0.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn0.c new file mode 100644 index 0000000..a579ff6 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn0.c @@ -0,0 +1,89 @@ +/* Area: closure_call + Purpose: Check multiple values passing from different type. + Also, exceed the limit of gpr and fpr registers on PowerPC + Darwin. + Limitations: none. + PR: none. + Originator: 20030828 */ + + + + +/* { dg-do run } */ +#include "ffitest.h" + +static void +closure_test_fn0(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata) +{ + *(ffi_arg*)resp = + (int)*(unsigned long long *)args[0] + (int)(*(int *)args[1]) + + (int)(*(unsigned long long *)args[2]) + (int)*(int *)args[3] + + (int)(*(signed short *)args[4]) + + (int)(*(unsigned long long *)args[5]) + + (int)*(int *)args[6] + (int)(*(int *)args[7]) + + (int)(*(double *)args[8]) + (int)*(int *)args[9] + + (int)(*(int *)args[10]) + (int)(*(float *)args[11]) + + (int)*(int *)args[12] + (int)(*(int *)args[13]) + + (int)(*(int *)args[14]) + *(int *)args[15] + (intptr_t)userdata; + + printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n", + (int)*(unsigned long long *)args[0], (int)(*(int *)args[1]), + (int)(*(unsigned long long *)args[2]), + (int)*(int *)args[3], (int)(*(signed short *)args[4]), + (int)(*(unsigned long long *)args[5]), + (int)*(int *)args[6], (int)(*(int *)args[7]), + (int)(*(double *)args[8]), (int)*(int *)args[9], + (int)(*(int *)args[10]), (int)(*(float *)args[11]), + (int)*(int *)args[12], (int)(*(int *)args[13]), + (int)(*(int *)args[14]),*(int *)args[15], + (int)(intptr_t)userdata, (int)*(ffi_arg *)resp); + +} + +typedef int (*closure_test_type0)(unsigned long long, int, unsigned long long, + int, signed short, unsigned long long, int, + int, double, int, int, float, int, int, + int, int); + +int main (void) +{ + ffi_cif cif; + void * code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[17]; + int res; + + cl_arg_types[0] = &ffi_type_uint64; + cl_arg_types[1] = &ffi_type_sint; + cl_arg_types[2] = &ffi_type_uint64; + cl_arg_types[3] = &ffi_type_sint; + cl_arg_types[4] = &ffi_type_sshort; + cl_arg_types[5] = &ffi_type_uint64; + cl_arg_types[6] = &ffi_type_sint; + cl_arg_types[7] = &ffi_type_sint; + cl_arg_types[8] = &ffi_type_double; + cl_arg_types[9] = &ffi_type_sint; + cl_arg_types[10] = &ffi_type_sint; + cl_arg_types[11] = &ffi_type_float; + cl_arg_types[12] = &ffi_type_sint; + cl_arg_types[13] = &ffi_type_sint; + cl_arg_types[14] = &ffi_type_sint; + cl_arg_types[15] = &ffi_type_sint; + cl_arg_types[16] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16, + &ffi_type_sint, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn0, + (void *) 3 /* userdata */, code) == FFI_OK); + + res = (*((closure_test_type0)code)) + (1LL, 2, 3LL, 4, 127, 429LL, 7, 8, 9.5, 10, 11, 12, 13, + 19, 21, 1); + /* { dg-output "1 2 3 4 127 429 7 8 9 10 11 12 13 19 21 1 3: 680" } */ + printf("res: %d\n",res); + /* { dg-output "\nres: 680" } */ + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn1.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn1.c new file mode 100644 index 0000000..9123173 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn1.c @@ -0,0 +1,81 @@ +/* Area: closure_call. + Purpose: Check multiple values passing from different type. + Also, exceed the limit of gpr and fpr registers on PowerPC + Darwin. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + + +static void closure_test_fn1(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata) +{ + *(ffi_arg*)resp = + (int)*(float *)args[0] +(int)(*(float *)args[1]) + + (int)(*(float *)args[2]) + (int)*(float *)args[3] + + (int)(*(signed short *)args[4]) + (int)(*(float *)args[5]) + + (int)*(float *)args[6] + (int)(*(int *)args[7]) + + (int)(*(double*)args[8]) + (int)*(int *)args[9] + + (int)(*(int *)args[10]) + (int)(*(float *)args[11]) + + (int)*(int *)args[12] + (int)(*(int *)args[13]) + + (int)(*(int *)args[14]) + *(int *)args[15] + (intptr_t)userdata; + + printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n", + (int)*(float *)args[0], (int)(*(float *)args[1]), + (int)(*(float *)args[2]), (int)*(float *)args[3], + (int)(*(signed short *)args[4]), (int)(*(float *)args[5]), + (int)*(float *)args[6], (int)(*(int *)args[7]), + (int)(*(double *)args[8]), (int)*(int *)args[9], + (int)(*(int *)args[10]), (int)(*(float *)args[11]), + (int)*(int *)args[12], (int)(*(int *)args[13]), + (int)(*(int *)args[14]), *(int *)args[15], + (int)(intptr_t)userdata, (int)*(ffi_arg *)resp); +} + +typedef int (*closure_test_type1)(float, float, float, float, signed short, + float, float, int, double, int, int, float, + int, int, int, int); +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[17]; + int res; + + cl_arg_types[0] = &ffi_type_float; + cl_arg_types[1] = &ffi_type_float; + cl_arg_types[2] = &ffi_type_float; + cl_arg_types[3] = &ffi_type_float; + cl_arg_types[4] = &ffi_type_sshort; + cl_arg_types[5] = &ffi_type_float; + cl_arg_types[6] = &ffi_type_float; + cl_arg_types[7] = &ffi_type_sint; + cl_arg_types[8] = &ffi_type_double; + cl_arg_types[9] = &ffi_type_sint; + cl_arg_types[10] = &ffi_type_sint; + cl_arg_types[11] = &ffi_type_float; + cl_arg_types[12] = &ffi_type_sint; + cl_arg_types[13] = &ffi_type_sint; + cl_arg_types[14] = &ffi_type_sint; + cl_arg_types[15] = &ffi_type_sint; + cl_arg_types[16] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16, + &ffi_type_sint, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn1, + (void *) 3 /* userdata */, code) == FFI_OK); + + res = (*((closure_test_type1)code)) + (1.1, 2.2, 3.3, 4.4, 127, 5.5, 6.6, 8, 9, 10, 11, 12.0, 13, + 19, 21, 1); + /* { dg-output "1 2 3 4 127 5 6 8 9 10 11 12 13 19 21 1 3: 255" } */ + printf("res: %d\n",res); + /* { dg-output "\nres: 255" } */ + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn2.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn2.c new file mode 100644 index 0000000..08ff9d9 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn2.c @@ -0,0 +1,81 @@ +/* Area: closure_call + Purpose: Check multiple values passing from different type. + Also, exceed the limit of gpr and fpr registers on PowerPC + Darwin. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static void closure_test_fn2(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata) +{ + *(ffi_arg*)resp = + (int)*(double *)args[0] +(int)(*(double *)args[1]) + + (int)(*(double *)args[2]) + (int)*(double *)args[3] + + (int)(*(signed short *)args[4]) + (int)(*(double *)args[5]) + + (int)*(double *)args[6] + (int)(*(int *)args[7]) + + (int)(*(double *)args[8]) + (int)*(int *)args[9] + + (int)(*(int *)args[10]) + (int)(*(float *)args[11]) + + (int)*(int *)args[12] + (int)(*(float *)args[13]) + + (int)(*(int *)args[14]) + *(int *)args[15] + (intptr_t)userdata; + + printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n", + (int)*(double *)args[0], (int)(*(double *)args[1]), + (int)(*(double *)args[2]), (int)*(double *)args[3], + (int)(*(signed short *)args[4]), (int)(*(double *)args[5]), + (int)*(double *)args[6], (int)(*(int *)args[7]), + (int)(*(double*)args[8]), (int)*(int *)args[9], + (int)(*(int *)args[10]), (int)(*(float *)args[11]), + (int)*(int *)args[12], (int)(*(float *)args[13]), + (int)(*(int *)args[14]), *(int *)args[15], (int)(intptr_t)userdata, + (int)*(ffi_arg *)resp); +} + +typedef int (*closure_test_type2)(double, double, double, double, signed short, + double, double, int, double, int, int, float, + int, float, int, int); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[17]; + int res; + + cl_arg_types[0] = &ffi_type_double; + cl_arg_types[1] = &ffi_type_double; + cl_arg_types[2] = &ffi_type_double; + cl_arg_types[3] = &ffi_type_double; + cl_arg_types[4] = &ffi_type_sshort; + cl_arg_types[5] = &ffi_type_double; + cl_arg_types[6] = &ffi_type_double; + cl_arg_types[7] = &ffi_type_sint; + cl_arg_types[8] = &ffi_type_double; + cl_arg_types[9] = &ffi_type_sint; + cl_arg_types[10] = &ffi_type_sint; + cl_arg_types[11] = &ffi_type_float; + cl_arg_types[12] = &ffi_type_sint; + cl_arg_types[13] = &ffi_type_float; + cl_arg_types[14] = &ffi_type_sint; + cl_arg_types[15] = &ffi_type_sint; + cl_arg_types[16] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16, + &ffi_type_sint, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn2, + (void *) 3 /* userdata */, code) == FFI_OK); + + res = (*((closure_test_type2)code)) + (1, 2, 3, 4, 127, 5, 6, 8, 9, 10, 11, 12.0, 13, + 19.0, 21, 1); + /* { dg-output "1 2 3 4 127 5 6 8 9 10 11 12 13 19 21 1 3: 255" } */ + printf("res: %d\n",res); + /* { dg-output "\nres: 255" } */ + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn3.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn3.c new file mode 100644 index 0000000..9b54d80 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn3.c @@ -0,0 +1,82 @@ +/* Area: closure_call + Purpose: Check multiple values passing from different type. + Also, exceed the limit of gpr and fpr registers on PowerPC + Darwin. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static void closure_test_fn3(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata) + { + *(ffi_arg*)resp = + (int)*(float *)args[0] +(int)(*(float *)args[1]) + + (int)(*(float *)args[2]) + (int)*(float *)args[3] + + (int)(*(float *)args[4]) + (int)(*(float *)args[5]) + + (int)*(float *)args[6] + (int)(*(float *)args[7]) + + (int)(*(double *)args[8]) + (int)*(int *)args[9] + + (int)(*(float *)args[10]) + (int)(*(float *)args[11]) + + (int)*(int *)args[12] + (int)(*(float *)args[13]) + + (int)(*(float *)args[14]) + *(int *)args[15] + (intptr_t)userdata; + + printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n", + (int)*(float *)args[0], (int)(*(float *)args[1]), + (int)(*(float *)args[2]), (int)*(float *)args[3], + (int)(*(float *)args[4]), (int)(*(float *)args[5]), + (int)*(float *)args[6], (int)(*(float *)args[7]), + (int)(*(double *)args[8]), (int)*(int *)args[9], + (int)(*(float *)args[10]), (int)(*(float *)args[11]), + (int)*(int *)args[12], (int)(*(float *)args[13]), + (int)(*(float *)args[14]), *(int *)args[15], (int)(intptr_t)userdata, + (int)*(ffi_arg *)resp); + + } + +typedef int (*closure_test_type3)(float, float, float, float, float, float, + float, float, double, int, float, float, int, + float, float, int); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[17]; + int res; + + cl_arg_types[0] = &ffi_type_float; + cl_arg_types[1] = &ffi_type_float; + cl_arg_types[2] = &ffi_type_float; + cl_arg_types[3] = &ffi_type_float; + cl_arg_types[4] = &ffi_type_float; + cl_arg_types[5] = &ffi_type_float; + cl_arg_types[6] = &ffi_type_float; + cl_arg_types[7] = &ffi_type_float; + cl_arg_types[8] = &ffi_type_double; + cl_arg_types[9] = &ffi_type_sint; + cl_arg_types[10] = &ffi_type_float; + cl_arg_types[11] = &ffi_type_float; + cl_arg_types[12] = &ffi_type_sint; + cl_arg_types[13] = &ffi_type_float; + cl_arg_types[14] = &ffi_type_float; + cl_arg_types[15] = &ffi_type_sint; + cl_arg_types[16] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16, + &ffi_type_sint, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn3, + (void *) 3 /* userdata */, code) == FFI_OK); + + res = (*((closure_test_type3)code)) + (1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9, 10, 11.11, 12.0, 13, + 19.19, 21.21, 1); + /* { dg-output "1 2 3 4 5 6 7 8 9 10 11 12 13 19 21 1 3: 135" } */ + printf("res: %d\n",res); + /* { dg-output "\nres: 135" } */ + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn4.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn4.c new file mode 100644 index 0000000..d4a1530 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn4.c @@ -0,0 +1,89 @@ +/* Area: closure_call + Purpose: Check multiple long long values passing. + Also, exceed the limit of gpr and fpr registers on PowerPC + Darwin. + Limitations: none. + PR: none. + Originator: 20031026 */ + +/* { dg-do run } */ + +#include "ffitest.h" + +static void +closure_test_fn0(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata) +{ + *(ffi_arg*)resp = + (int)*(unsigned long long *)args[0] + (int)*(unsigned long long *)args[1] + + (int)*(unsigned long long *)args[2] + (int)*(unsigned long long *)args[3] + + (int)*(unsigned long long *)args[4] + (int)*(unsigned long long *)args[5] + + (int)*(unsigned long long *)args[6] + (int)*(unsigned long long *)args[7] + + (int)*(unsigned long long *)args[8] + (int)*(unsigned long long *)args[9] + + (int)*(unsigned long long *)args[10] + + (int)*(unsigned long long *)args[11] + + (int)*(unsigned long long *)args[12] + + (int)*(unsigned long long *)args[13] + + (int)*(unsigned long long *)args[14] + + *(int *)args[15] + (intptr_t)userdata; + + printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n", + (int)*(unsigned long long *)args[0], + (int)*(unsigned long long *)args[1], + (int)*(unsigned long long *)args[2], + (int)*(unsigned long long *)args[3], + (int)*(unsigned long long *)args[4], + (int)*(unsigned long long *)args[5], + (int)*(unsigned long long *)args[6], + (int)*(unsigned long long *)args[7], + (int)*(unsigned long long *)args[8], + (int)*(unsigned long long *)args[9], + (int)*(unsigned long long *)args[10], + (int)*(unsigned long long *)args[11], + (int)*(unsigned long long *)args[12], + (int)*(unsigned long long *)args[13], + (int)*(unsigned long long *)args[14], + *(int *)args[15], + (int)(intptr_t)userdata, (int)*(ffi_arg *)resp); + +} + +typedef int (*closure_test_type0)(unsigned long long, unsigned long long, + unsigned long long, unsigned long long, + unsigned long long, unsigned long long, + unsigned long long, unsigned long long, + unsigned long long, unsigned long long, + unsigned long long, unsigned long long, + unsigned long long, unsigned long long, + unsigned long long, int); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[17]; + int i, res; + + for (i = 0; i < 15; i++) { + cl_arg_types[i] = &ffi_type_uint64; + } + cl_arg_types[15] = &ffi_type_sint; + cl_arg_types[16] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16, + &ffi_type_sint, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn0, + (void *) 3 /* userdata */, code) == FFI_OK); + + res = (*((closure_test_type0)code)) + (1LL, 2LL, 3LL, 4LL, 127LL, 429LL, 7LL, 8LL, 9LL, 10LL, 11LL, 12LL, + 13LL, 19LL, 21LL, 1); + /* { dg-output "1 2 3 4 127 429 7 8 9 10 11 12 13 19 21 1 3: 680" } */ + printf("res: %d\n",res); + /* { dg-output "\nres: 680" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn5.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn5.c new file mode 100644 index 0000000..9907442 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn5.c @@ -0,0 +1,92 @@ +/* Area: closure_call + Purpose: Check multiple long long values passing. + Exceed the limit of gpr registers on PowerPC + Darwin. + Limitations: none. + PR: none. + Originator: 20031026 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static void +closure_test_fn5(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata) +{ + *(ffi_arg*)resp = + (int)*(unsigned long long *)args[0] + (int)*(unsigned long long *)args[1] + + (int)*(unsigned long long *)args[2] + (int)*(unsigned long long *)args[3] + + (int)*(unsigned long long *)args[4] + (int)*(unsigned long long *)args[5] + + (int)*(unsigned long long *)args[6] + (int)*(unsigned long long *)args[7] + + (int)*(unsigned long long *)args[8] + (int)*(unsigned long long *)args[9] + + (int)*(int *)args[10] + + (int)*(unsigned long long *)args[11] + + (int)*(unsigned long long *)args[12] + + (int)*(unsigned long long *)args[13] + + (int)*(unsigned long long *)args[14] + + *(int *)args[15] + (intptr_t)userdata; + + printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n", + (int)*(unsigned long long *)args[0], + (int)*(unsigned long long *)args[1], + (int)*(unsigned long long *)args[2], + (int)*(unsigned long long *)args[3], + (int)*(unsigned long long *)args[4], + (int)*(unsigned long long *)args[5], + (int)*(unsigned long long *)args[6], + (int)*(unsigned long long *)args[7], + (int)*(unsigned long long *)args[8], + (int)*(unsigned long long *)args[9], + (int)*(int *)args[10], + (int)*(unsigned long long *)args[11], + (int)*(unsigned long long *)args[12], + (int)*(unsigned long long *)args[13], + (int)*(unsigned long long *)args[14], + *(int *)args[15], + (int)(intptr_t)userdata, (int)*(ffi_arg *)resp); + +} + +typedef int (*closure_test_type0)(unsigned long long, unsigned long long, + unsigned long long, unsigned long long, + unsigned long long, unsigned long long, + unsigned long long, unsigned long long, + unsigned long long, unsigned long long, + int, unsigned long long, + unsigned long long, unsigned long long, + unsigned long long, int); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[17]; + int i, res; + + for (i = 0; i < 10; i++) { + cl_arg_types[i] = &ffi_type_uint64; + } + cl_arg_types[10] = &ffi_type_sint; + for (i = 11; i < 15; i++) { + cl_arg_types[i] = &ffi_type_uint64; + } + cl_arg_types[15] = &ffi_type_sint; + cl_arg_types[16] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16, + &ffi_type_sint, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn5, + (void *) 3 /* userdata */, code) == FFI_OK); + + res = (*((closure_test_type0)code)) + (1LL, 2LL, 3LL, 4LL, 127LL, 429LL, 7LL, 8LL, 9LL, 10LL, 11, 12LL, + 13LL, 19LL, 21LL, 1); + /* { dg-output "1 2 3 4 127 429 7 8 9 10 11 12 13 19 21 1 3: 680" } */ + printf("res: %d\n",res); + /* { dg-output "\nres: 680" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn6.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn6.c new file mode 100644 index 0000000..73c54fd --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/closure_fn6.c @@ -0,0 +1,90 @@ +/* Area: closure_call + Purpose: Check multiple values passing from different type. + Also, exceed the limit of gpr and fpr registers on PowerPC. + Limitations: none. + PR: PR23404 + Originator: 20050830 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static void +closure_test_fn0(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata) +{ + *(ffi_arg*)resp = + (int)*(unsigned long long *)args[0] + + (int)(*(unsigned long long *)args[1]) + + (int)(*(unsigned long long *)args[2]) + + (int)*(unsigned long long *)args[3] + + (int)(*(int *)args[4]) + (int)(*(double *)args[5]) + + (int)*(double *)args[6] + (int)(*(float *)args[7]) + + (int)(*(double *)args[8]) + (int)*(double *)args[9] + + (int)(*(int *)args[10]) + (int)(*(float *)args[11]) + + (int)*(int *)args[12] + (int)(*(int *)args[13]) + + (int)(*(double *)args[14]) + (int)*(double *)args[15] + + (intptr_t)userdata; + + printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n", + (int)*(unsigned long long *)args[0], + (int)(*(unsigned long long *)args[1]), + (int)(*(unsigned long long *)args[2]), + (int)*(unsigned long long *)args[3], + (int)(*(int *)args[4]), (int)(*(double *)args[5]), + (int)*(double *)args[6], (int)(*(float *)args[7]), + (int)(*(double *)args[8]), (int)*(double *)args[9], + (int)(*(int *)args[10]), (int)(*(float *)args[11]), + (int)*(int *)args[12], (int)(*(int *)args[13]), + (int)(*(double *)args[14]), (int)(*(double *)args[15]), + (int)(intptr_t)userdata, (int)*(ffi_arg *)resp); + +} + +typedef int (*closure_test_type0)(unsigned long long, + unsigned long long, + unsigned long long, + unsigned long long, + int, double, double, float, double, double, + int, float, int, int, double, double); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[17]; + int res; + + cl_arg_types[0] = &ffi_type_uint64; + cl_arg_types[1] = &ffi_type_uint64; + cl_arg_types[2] = &ffi_type_uint64; + cl_arg_types[3] = &ffi_type_uint64; + cl_arg_types[4] = &ffi_type_sint; + cl_arg_types[5] = &ffi_type_double; + cl_arg_types[6] = &ffi_type_double; + cl_arg_types[7] = &ffi_type_float; + cl_arg_types[8] = &ffi_type_double; + cl_arg_types[9] = &ffi_type_double; + cl_arg_types[10] = &ffi_type_sint; + cl_arg_types[11] = &ffi_type_float; + cl_arg_types[12] = &ffi_type_sint; + cl_arg_types[13] = &ffi_type_sint; + cl_arg_types[14] = &ffi_type_double; + cl_arg_types[15] = &ffi_type_double; + cl_arg_types[16] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16, + &ffi_type_sint, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn0, + (void *) 3 /* userdata */, code) == FFI_OK); + + res = (*((closure_test_type0)code)) + (1, 2, 3, 4, 127, 429., 7., 8., 9.5, 10., 11, 12., 13, + 19, 21., 1.); + /* { dg-output "1 2 3 4 127 429 7 8 9 10 11 12 13 19 21 1 3: 680" } */ + printf("res: %d\n",res); + /* { dg-output "\nres: 680" } */ + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/closure_loc_fn0.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_loc_fn0.c new file mode 100644 index 0000000..b3afa0b --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/closure_loc_fn0.c @@ -0,0 +1,95 @@ +/* Area: closure_call + Purpose: Check multiple values passing from different type. + Also, exceed the limit of gpr and fpr registers on PowerPC + Darwin. + Limitations: none. + PR: none. + Originator: 20030828 */ + + + + +/* { dg-do run } */ +#include "ffitest.h" + +static void +closure_loc_test_fn0(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata) +{ + *(ffi_arg*)resp = + (int)*(unsigned long long *)args[0] + (int)(*(int *)args[1]) + + (int)(*(unsigned long long *)args[2]) + (int)*(int *)args[3] + + (int)(*(signed short *)args[4]) + + (int)(*(unsigned long long *)args[5]) + + (int)*(int *)args[6] + (int)(*(int *)args[7]) + + (int)(*(double *)args[8]) + (int)*(int *)args[9] + + (int)(*(int *)args[10]) + (int)(*(float *)args[11]) + + (int)*(int *)args[12] + (int)(*(int *)args[13]) + + (int)(*(int *)args[14]) + *(int *)args[15] + (intptr_t)userdata; + + printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n", + (int)*(unsigned long long *)args[0], (int)(*(int *)args[1]), + (int)(*(unsigned long long *)args[2]), + (int)*(int *)args[3], (int)(*(signed short *)args[4]), + (int)(*(unsigned long long *)args[5]), + (int)*(int *)args[6], (int)(*(int *)args[7]), + (int)(*(double *)args[8]), (int)*(int *)args[9], + (int)(*(int *)args[10]), (int)(*(float *)args[11]), + (int)*(int *)args[12], (int)(*(int *)args[13]), + (int)(*(int *)args[14]),*(int *)args[15], + (int)(intptr_t)userdata, (int)*(ffi_arg *)resp); + +} + +typedef int (*closure_loc_test_type0)(unsigned long long, int, unsigned long long, + int, signed short, unsigned long long, int, + int, double, int, int, float, int, int, + int, int); + +int main (void) +{ + ffi_cif cif; + ffi_closure *pcl; + ffi_type * cl_arg_types[17]; + int res; + void *codeloc; + + cl_arg_types[0] = &ffi_type_uint64; + cl_arg_types[1] = &ffi_type_sint; + cl_arg_types[2] = &ffi_type_uint64; + cl_arg_types[3] = &ffi_type_sint; + cl_arg_types[4] = &ffi_type_sshort; + cl_arg_types[5] = &ffi_type_uint64; + cl_arg_types[6] = &ffi_type_sint; + cl_arg_types[7] = &ffi_type_sint; + cl_arg_types[8] = &ffi_type_double; + cl_arg_types[9] = &ffi_type_sint; + cl_arg_types[10] = &ffi_type_sint; + cl_arg_types[11] = &ffi_type_float; + cl_arg_types[12] = &ffi_type_sint; + cl_arg_types[13] = &ffi_type_sint; + cl_arg_types[14] = &ffi_type_sint; + cl_arg_types[15] = &ffi_type_sint; + cl_arg_types[16] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16, + &ffi_type_sint, cl_arg_types) == FFI_OK); + + pcl = ffi_closure_alloc(sizeof(ffi_closure), &codeloc); + CHECK(pcl != NULL); + CHECK(codeloc != NULL); + + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_loc_test_fn0, + (void *) 3 /* userdata */, codeloc) == FFI_OK); + + CHECK(memcmp(pcl, codeloc, sizeof(*pcl)) == 0); + + res = (*((closure_loc_test_type0)codeloc)) + (1LL, 2, 3LL, 4, 127, 429LL, 7, 8, 9.5, 10, 11, 12, 13, + 19, 21, 1); + /* { dg-output "1 2 3 4 127 429 7 8 9 10 11 12 13 19 21 1 3: 680" } */ + printf("res: %d\n",res); + /* { dg-output "\nres: 680" } */ + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/closure_stdcall.c b/js/src/ctypes/libffi/testsuite/libffi.call/closure_stdcall.c new file mode 100644 index 0000000..6bfcc1f --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/closure_stdcall.c @@ -0,0 +1,64 @@ +/* Area: closure_call (stdcall convention) + Purpose: Check handling when caller expects stdcall callee + Limitations: none. + PR: none. + Originator: */ + +/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */ +#include "ffitest.h" + +static void +closure_test_stdcall(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata) +{ + *(ffi_arg*)resp = + (int)*(int *)args[0] + (int)(*(int *)args[1]) + + (int)(*(int *)args[2]) + (int)(*(int *)args[3]) + + (int)(intptr_t)userdata; + + printf("%d %d %d %d: %d\n", + (int)*(int *)args[0], (int)(*(int *)args[1]), + (int)(*(int *)args[2]), (int)(*(int *)args[3]), + (int)*(ffi_arg *)resp); + +} + +typedef int (__stdcall *closure_test_type0)(int, int, int, int); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[17]; + int res; + void* sp_pre; + void* sp_post; + char buf[1024]; + + cl_arg_types[0] = &ffi_type_uint; + cl_arg_types[1] = &ffi_type_uint; + cl_arg_types[2] = &ffi_type_uint; + cl_arg_types[3] = &ffi_type_uint; + cl_arg_types[4] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_STDCALL, 4, + &ffi_type_sint, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_stdcall, + (void *) 3 /* userdata */, code) == FFI_OK); + + asm volatile (" movl %%esp,%0" : "=g" (sp_pre)); + res = (*(closure_test_type0)code)(0, 1, 2, 3); + asm volatile (" movl %%esp,%0" : "=g" (sp_post)); + /* { dg-output "0 1 2 3: 9" } */ + + printf("res: %d\n",res); + /* { dg-output "\nres: 9" } */ + + sprintf(buf, "mismatch: pre=%p vs post=%p", sp_pre, sp_post); + printf("stack pointer %s\n", (sp_pre == sp_post ? "match" : buf)); + /* { dg-output "\nstack pointer match" } */ + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_12byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_12byte.c new file mode 100644 index 0000000..f0a334f --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_12byte.c @@ -0,0 +1,94 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_12byte { + int a; + int b; + int c; +} cls_struct_12byte; + +cls_struct_12byte cls_struct_12byte_fn(struct cls_struct_12byte b1, + struct cls_struct_12byte b2) +{ + struct cls_struct_12byte result; + + result.a = b1.a + b2.a; + result.b = b1.b + b2.b; + result.c = b1.c + b2.c; + + printf("%d %d %d %d %d %d: %d %d %d\n", b1.a, b1.b, b1.c, b2.a, b2.b, b2.c, + result.a, result.b, result.c); + + return result; +} + +static void cls_struct_12byte_gn(ffi_cif* cif __UNUSED__, void* resp, + void** args , void* userdata __UNUSED__) +{ + struct cls_struct_12byte b1, b2; + + b1 = *(struct cls_struct_12byte*)(args[0]); + b2 = *(struct cls_struct_12byte*)(args[1]); + + *(cls_struct_12byte*)resp = cls_struct_12byte_fn(b1, b2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_12byte h_dbl = { 7, 4, 9 }; + struct cls_struct_12byte j_dbl = { 1, 5, 3 }; + struct cls_struct_12byte res_dbl; + + cls_struct_fields[0] = &ffi_type_sint; + cls_struct_fields[1] = &ffi_type_sint; + cls_struct_fields[2] = &ffi_type_sint; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &h_dbl; + args_dbl[1] = &j_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_12byte_fn), &res_dbl, args_dbl); + /* { dg-output "7 4 9 1 5 3: 8 9 12" } */ + printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 8 9 12" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_12byte_gn, NULL, code) == FFI_OK); + + res_dbl.a = 0; + res_dbl.b = 0; + res_dbl.c = 0; + + res_dbl = ((cls_struct_12byte(*)(cls_struct_12byte, cls_struct_12byte))(code))(h_dbl, j_dbl); + /* { dg-output "\n7 4 9 1 5 3: 8 9 12" } */ + printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 8 9 12" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_16byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_16byte.c new file mode 100644 index 0000000..9b9292a --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_16byte.c @@ -0,0 +1,95 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Check overlapping. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_16byte { + int a; + double b; + int c; +} cls_struct_16byte; + +cls_struct_16byte cls_struct_16byte_fn(struct cls_struct_16byte b1, + struct cls_struct_16byte b2) +{ + struct cls_struct_16byte result; + + result.a = b1.a + b2.a; + result.b = b1.b + b2.b; + result.c = b1.c + b2.c; + + printf("%d %g %d %d %g %d: %d %g %d\n", b1.a, b1.b, b1.c, b2.a, b2.b, b2.c, + result.a, result.b, result.c); + + return result; +} + +static void cls_struct_16byte_gn(ffi_cif* cif __UNUSED__, void* resp, + void** args, void* userdata __UNUSED__) +{ + struct cls_struct_16byte b1, b2; + + b1 = *(struct cls_struct_16byte*)(args[0]); + b2 = *(struct cls_struct_16byte*)(args[1]); + + *(cls_struct_16byte*)resp = cls_struct_16byte_fn(b1, b2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_16byte h_dbl = { 7, 8.0, 9 }; + struct cls_struct_16byte j_dbl = { 1, 9.0, 3 }; + struct cls_struct_16byte res_dbl; + + cls_struct_fields[0] = &ffi_type_sint; + cls_struct_fields[1] = &ffi_type_double; + cls_struct_fields[2] = &ffi_type_sint; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &h_dbl; + args_dbl[1] = &j_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_16byte_fn), &res_dbl, args_dbl); + /* { dg-output "7 8 9 1 9 3: 8 17 12" } */ + printf("res: %d %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 8 17 12" } */ + + res_dbl.a = 0; + res_dbl.b = 0.0; + res_dbl.c = 0; + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_16byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_16byte(*)(cls_struct_16byte, cls_struct_16byte))(code))(h_dbl, j_dbl); + /* { dg-output "\n7 8 9 1 9 3: 8 17 12" } */ + printf("res: %d %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 8 17 12" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_18byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_18byte.c new file mode 100644 index 0000000..40c8c6d --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_18byte.c @@ -0,0 +1,96 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Double alignment check on darwin. + Limitations: none. + PR: none. + Originator: 20030915 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_18byte { + double a; + unsigned char b; + unsigned char c; + double d; +} cls_struct_18byte; + +cls_struct_18byte cls_struct_18byte_fn(struct cls_struct_18byte a1, + struct cls_struct_18byte a2) +{ + struct cls_struct_18byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + result.d = a1.d + a2.d; + + + printf("%g %d %d %g %g %d %d %g: %g %d %d %g\n", a1.a, a1.b, a1.c, a1.d, + a2.a, a2.b, a2.c, a2.d, + result.a, result.b, result.c, result.d); + return result; +} + +static void +cls_struct_18byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct cls_struct_18byte a1, a2; + + a1 = *(struct cls_struct_18byte*)(args[0]); + a2 = *(struct cls_struct_18byte*)(args[1]); + + *(cls_struct_18byte*)resp = cls_struct_18byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[3]; + ffi_type* cls_struct_fields[5]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[3]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_18byte g_dbl = { 1.0, 127, 126, 3.0 }; + struct cls_struct_18byte f_dbl = { 4.0, 125, 124, 5.0 }; + struct cls_struct_18byte res_dbl; + + cls_struct_fields[0] = &ffi_type_double; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = &ffi_type_double; + cls_struct_fields[4] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_18byte_fn), &res_dbl, args_dbl); + /* { dg-output "1 127 126 3 4 125 124 5: 5 252 250 8" } */ + printf("res: %g %d %d %g\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d); + /* { dg-output "\nres: 5 252 250 8" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_18byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_18byte(*)(cls_struct_18byte, cls_struct_18byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n1 127 126 3 4 125 124 5: 5 252 250 8" } */ + printf("res: %g %d %d %g\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d); + /* { dg-output "\nres: 5 252 250 8" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_19byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_19byte.c new file mode 100644 index 0000000..aa64248 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_19byte.c @@ -0,0 +1,102 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Double alignment check on darwin. + Limitations: none. + PR: none. + Originator: 20030915 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_19byte { + double a; + unsigned char b; + unsigned char c; + double d; + unsigned char e; +} cls_struct_19byte; + +cls_struct_19byte cls_struct_19byte_fn(struct cls_struct_19byte a1, + struct cls_struct_19byte a2) +{ + struct cls_struct_19byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + result.d = a1.d + a2.d; + result.e = a1.e + a2.e; + + + printf("%g %d %d %g %d %g %d %d %g %d: %g %d %d %g %d\n", + a1.a, a1.b, a1.c, a1.d, a1.e, + a2.a, a2.b, a2.c, a2.d, a2.e, + result.a, result.b, result.c, result.d, result.e); + return result; +} + +static void +cls_struct_19byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct cls_struct_19byte a1, a2; + + a1 = *(struct cls_struct_19byte*)(args[0]); + a2 = *(struct cls_struct_19byte*)(args[1]); + + *(cls_struct_19byte*)resp = cls_struct_19byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[3]; + ffi_type* cls_struct_fields[6]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[3]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_19byte g_dbl = { 1.0, 127, 126, 3.0, 120 }; + struct cls_struct_19byte f_dbl = { 4.0, 125, 124, 5.0, 119 }; + struct cls_struct_19byte res_dbl; + + cls_struct_fields[0] = &ffi_type_double; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = &ffi_type_double; + cls_struct_fields[4] = &ffi_type_uchar; + cls_struct_fields[5] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_19byte_fn), &res_dbl, args_dbl); + /* { dg-output "1 127 126 3 120 4 125 124 5 119: 5 252 250 8 239" } */ + printf("res: %g %d %d %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c, + res_dbl.d, res_dbl.e); + /* { dg-output "\nres: 5 252 250 8 239" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_19byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_19byte(*)(cls_struct_19byte, cls_struct_19byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n1 127 126 3 120 4 125 124 5 119: 5 252 250 8 239" } */ + printf("res: %g %d %d %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c, + res_dbl.d, res_dbl.e); + /* { dg-output "\nres: 5 252 250 8 239" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_1_1byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_1_1byte.c new file mode 100644 index 0000000..b9402d6 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_1_1byte.c @@ -0,0 +1,89 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Especially with small structures which may fit in one + register. Depending on the ABI. + Limitations: none. + PR: none. + Originator: 20030902 */ + + + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_1_1byte { + unsigned char a; +} cls_struct_1_1byte; + +cls_struct_1_1byte cls_struct_1_1byte_fn(struct cls_struct_1_1byte a1, + struct cls_struct_1_1byte a2) +{ + struct cls_struct_1_1byte result; + + result.a = a1.a + a2.a; + + printf("%d %d: %d\n", a1.a, a2.a, result.a); + + return result; +} + +static void +cls_struct_1_1byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_1_1byte a1, a2; + + a1 = *(struct cls_struct_1_1byte*)(args[0]); + a2 = *(struct cls_struct_1_1byte*)(args[1]); + + *(cls_struct_1_1byte*)resp = cls_struct_1_1byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[2]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_1_1byte g_dbl = { 12 }; + struct cls_struct_1_1byte f_dbl = { 178 }; + struct cls_struct_1_1byte res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_1_1byte_fn), &res_dbl, args_dbl); + /* { dg-output "12 178: 190" } */ + printf("res: %d\n", res_dbl.a); + /* { dg-output "\nres: 190" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_1_1byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_1_1byte(*)(cls_struct_1_1byte, cls_struct_1_1byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 178: 190" } */ + printf("res: %d\n", res_dbl.a); + /* { dg-output "\nres: 190" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_20byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_20byte.c new file mode 100644 index 0000000..80dd7ac --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_20byte.c @@ -0,0 +1,91 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Check overlapping. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_20byte { + double a; + double b; + int c; +} cls_struct_20byte; + +cls_struct_20byte cls_struct_20byte_fn(struct cls_struct_20byte a1, + struct cls_struct_20byte a2) +{ + struct cls_struct_20byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + printf("%g %g %d %g %g %d: %g %g %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, + result.a, result.b, result.c); + return result; +} + +static void +cls_struct_20byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct cls_struct_20byte a1, a2; + + a1 = *(struct cls_struct_20byte*)(args[0]); + a2 = *(struct cls_struct_20byte*)(args[1]); + + *(cls_struct_20byte*)resp = cls_struct_20byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_20byte g_dbl = { 1.0, 2.0, 3 }; + struct cls_struct_20byte f_dbl = { 4.0, 5.0, 7 }; + struct cls_struct_20byte res_dbl; + + cls_struct_fields[0] = &ffi_type_double; + cls_struct_fields[1] = &ffi_type_double; + cls_struct_fields[2] = &ffi_type_sint; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_20byte_fn), &res_dbl, args_dbl); + /* { dg-output "1 2 3 4 5 7: 5 7 10" } */ + printf("res: %g %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 5 7 10" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_20byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_20byte(*)(cls_struct_20byte, cls_struct_20byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n1 2 3 4 5 7: 5 7 10" } */ + printf("res: %g %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 5 7 10" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_20byte1.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_20byte1.c new file mode 100644 index 0000000..50bcbbf --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_20byte1.c @@ -0,0 +1,93 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Check overlapping. + Limitations: none. + PR: none. + Originator: 20030828 */ + + + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_20byte { + int a; + double b; + double c; +} cls_struct_20byte; + +cls_struct_20byte cls_struct_20byte_fn(struct cls_struct_20byte a1, + struct cls_struct_20byte a2) +{ + struct cls_struct_20byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + printf("%d %g %g %d %g %g: %d %g %g\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, + result.a, result.b, result.c); + return result; +} + +static void +cls_struct_20byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct cls_struct_20byte a1, a2; + + a1 = *(struct cls_struct_20byte*)(args[0]); + a2 = *(struct cls_struct_20byte*)(args[1]); + + *(cls_struct_20byte*)resp = cls_struct_20byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[3]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[3]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_20byte g_dbl = { 1, 2.0, 3.0 }; + struct cls_struct_20byte f_dbl = { 4, 5.0, 7.0 }; + struct cls_struct_20byte res_dbl; + + cls_struct_fields[0] = &ffi_type_sint; + cls_struct_fields[1] = &ffi_type_double; + cls_struct_fields[2] = &ffi_type_double; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_20byte_fn), &res_dbl, args_dbl); + /* { dg-output "1 2 3 4 5 7: 5 7 10" } */ + printf("res: %d %g %g\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 5 7 10" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_20byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_20byte(*)(cls_struct_20byte, cls_struct_20byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n1 2 3 4 5 7: 5 7 10" } */ + printf("res: %d %g %g\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 5 7 10" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_24byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_24byte.c new file mode 100644 index 0000000..46a6eb4 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_24byte.c @@ -0,0 +1,113 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Check overlapping. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_24byte { + double a; + double b; + int c; + float d; +} cls_struct_24byte; + +cls_struct_24byte cls_struct_24byte_fn(struct cls_struct_24byte b0, + struct cls_struct_24byte b1, + struct cls_struct_24byte b2, + struct cls_struct_24byte b3) +{ + struct cls_struct_24byte result; + + result.a = b0.a + b1.a + b2.a + b3.a; + result.b = b0.b + b1.b + b2.b + b3.b; + result.c = b0.c + b1.c + b2.c + b3.c; + result.d = b0.d + b1.d + b2.d + b3.d; + + printf("%g %g %d %g %g %g %d %g %g %g %d %g %g %g %d %g: %g %g %d %g\n", + b0.a, b0.b, b0.c, b0.d, + b1.a, b1.b, b1.c, b1.d, + b2.a, b2.b, b2.c, b2.d, + b3.a, b3.b, b3.c, b2.d, + result.a, result.b, result.c, result.d); + + return result; +} + +static void +cls_struct_24byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct cls_struct_24byte b0, b1, b2, b3; + + b0 = *(struct cls_struct_24byte*)(args[0]); + b1 = *(struct cls_struct_24byte*)(args[1]); + b2 = *(struct cls_struct_24byte*)(args[2]); + b3 = *(struct cls_struct_24byte*)(args[3]); + + *(cls_struct_24byte*)resp = cls_struct_24byte_fn(b0, b1, b2, b3); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[5]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_24byte e_dbl = { 9.0, 2.0, 6, 5.0 }; + struct cls_struct_24byte f_dbl = { 1.0, 2.0, 3, 7.0 }; + struct cls_struct_24byte g_dbl = { 4.0, 5.0, 7, 9.0 }; + struct cls_struct_24byte h_dbl = { 8.0, 6.0, 1, 4.0 }; + struct cls_struct_24byte res_dbl; + + cls_struct_fields[0] = &ffi_type_double; + cls_struct_fields[1] = &ffi_type_double; + cls_struct_fields[2] = &ffi_type_sint; + cls_struct_fields[3] = &ffi_type_float; + cls_struct_fields[4] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = &cls_struct_type; + dbl_arg_types[3] = &cls_struct_type; + dbl_arg_types[4] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = &g_dbl; + args_dbl[3] = &h_dbl; + args_dbl[4] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_24byte_fn), &res_dbl, args_dbl); + /* { dg-output "9 2 6 5 1 2 3 7 4 5 7 9 8 6 1 9: 22 15 17 25" } */ + printf("res: %g %g %d %g\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d); + /* { dg-output "\nres: 22 15 17 25" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_24byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_24byte(*)(cls_struct_24byte, + cls_struct_24byte, + cls_struct_24byte, + cls_struct_24byte)) + (code))(e_dbl, f_dbl, g_dbl, h_dbl); + /* { dg-output "\n9 2 6 5 1 2 3 7 4 5 7 9 8 6 1 9: 22 15 17 25" } */ + printf("res: %g %g %d %g\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d); + /* { dg-output "\nres: 22 15 17 25" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_2byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_2byte.c new file mode 100644 index 0000000..101e130 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_2byte.c @@ -0,0 +1,90 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Especially with small structures which may fit in one + register. Depending on the ABI. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_2byte { + unsigned char a; + unsigned char b; +} cls_struct_2byte; + +cls_struct_2byte cls_struct_2byte_fn(struct cls_struct_2byte a1, + struct cls_struct_2byte a2) +{ + struct cls_struct_2byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + + printf("%d %d %d %d: %d %d\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b); + + return result; +} + +static void +cls_struct_2byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_2byte a1, a2; + + a1 = *(struct cls_struct_2byte*)(args[0]); + a2 = *(struct cls_struct_2byte*)(args[1]); + + *(cls_struct_2byte*)resp = cls_struct_2byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_2byte g_dbl = { 12, 127 }; + struct cls_struct_2byte f_dbl = { 1, 13 }; + struct cls_struct_2byte res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_2byte_fn), &res_dbl, args_dbl); + /* { dg-output "12 127 1 13: 13 140" } */ + printf("res: %d %d\n", res_dbl.a, res_dbl.b); + /* { dg-output "\nres: 13 140" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_2byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_2byte(*)(cls_struct_2byte, cls_struct_2byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 127 1 13: 13 140" } */ + printf("res: %d %d\n", res_dbl.a, res_dbl.b); + /* { dg-output "\nres: 13 140" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_3_1byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_3_1byte.c new file mode 100644 index 0000000..fc780c3 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_3_1byte.c @@ -0,0 +1,95 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Especially with small structures which may fit in one + register. Depending on the ABI. + Limitations: none. + PR: none. + Originator: 20030902 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_3_1byte { + unsigned char a; + unsigned char b; + unsigned char c; +} cls_struct_3_1byte; + +cls_struct_3_1byte cls_struct_3_1byte_fn(struct cls_struct_3_1byte a1, + struct cls_struct_3_1byte a2) +{ + struct cls_struct_3_1byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + printf("%d %d %d %d %d %d: %d %d %d\n", a1.a, a1.b, a1.c, + a2.a, a2.b, a2.c, + result.a, result.b, result.c); + + return result; +} + +static void +cls_struct_3_1byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_3_1byte a1, a2; + + a1 = *(struct cls_struct_3_1byte*)(args[0]); + a2 = *(struct cls_struct_3_1byte*)(args[1]); + + *(cls_struct_3_1byte*)resp = cls_struct_3_1byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_3_1byte g_dbl = { 12, 13, 14 }; + struct cls_struct_3_1byte f_dbl = { 178, 179, 180 }; + struct cls_struct_3_1byte res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_3_1byte_fn), &res_dbl, args_dbl); + /* { dg-output "12 13 14 178 179 180: 190 192 194" } */ + printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 190 192 194" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_3_1byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_3_1byte(*)(cls_struct_3_1byte, cls_struct_3_1byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 13 14 178 179 180: 190 192 194" } */ + printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 190 192 194" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_3byte1.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_3byte1.c new file mode 100644 index 0000000..5705ce3 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_3byte1.c @@ -0,0 +1,90 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Especially with small structures which may fit in one + register. Depending on the ABI. Check overlapping. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_3byte { + unsigned short a; + unsigned char b; +} cls_struct_3byte; + +cls_struct_3byte cls_struct_3byte_fn(struct cls_struct_3byte a1, + struct cls_struct_3byte a2) +{ + struct cls_struct_3byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + + printf("%d %d %d %d: %d %d\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b); + + return result; +} + +static void +cls_struct_3byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_3byte a1, a2; + + a1 = *(struct cls_struct_3byte*)(args[0]); + a2 = *(struct cls_struct_3byte*)(args[1]); + + *(cls_struct_3byte*)resp = cls_struct_3byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_3byte g_dbl = { 12, 119 }; + struct cls_struct_3byte f_dbl = { 1, 15 }; + struct cls_struct_3byte res_dbl; + + cls_struct_fields[0] = &ffi_type_ushort; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_3byte_fn), &res_dbl, args_dbl); + /* { dg-output "12 119 1 15: 13 134" } */ + printf("res: %d %d\n", res_dbl.a, res_dbl.b); + /* { dg-output "\nres: 13 134" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_3byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_3byte(*)(cls_struct_3byte, cls_struct_3byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 119 1 15: 13 134" } */ + printf("res: %d %d\n", res_dbl.a, res_dbl.b); + /* { dg-output "\nres: 13 134" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_3byte2.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_3byte2.c new file mode 100644 index 0000000..01770a0 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_3byte2.c @@ -0,0 +1,90 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Especially with small structures which may fit in one + register. Depending on the ABI. Check overlapping. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_3byte_1 { + unsigned char a; + unsigned short b; +} cls_struct_3byte_1; + +cls_struct_3byte_1 cls_struct_3byte_fn1(struct cls_struct_3byte_1 a1, + struct cls_struct_3byte_1 a2) +{ + struct cls_struct_3byte_1 result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + + printf("%d %d %d %d: %d %d\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b); + + return result; +} + +static void +cls_struct_3byte_gn1(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_3byte_1 a1, a2; + + a1 = *(struct cls_struct_3byte_1*)(args[0]); + a2 = *(struct cls_struct_3byte_1*)(args[1]); + + *(cls_struct_3byte_1*)resp = cls_struct_3byte_fn1(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_3byte_1 g_dbl = { 15, 125 }; + struct cls_struct_3byte_1 f_dbl = { 9, 19 }; + struct cls_struct_3byte_1 res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_ushort; + cls_struct_fields[2] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_3byte_fn1), &res_dbl, args_dbl); + /* { dg-output "15 125 9 19: 24 144" } */ + printf("res: %d %d\n", res_dbl.a, res_dbl.b); + /* { dg-output "\nres: 24 144" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_3byte_gn1, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_3byte_1(*)(cls_struct_3byte_1, cls_struct_3byte_1))(code))(g_dbl, f_dbl); + /* { dg-output "\n15 125 9 19: 24 144" } */ + printf("res: %d %d\n", res_dbl.a, res_dbl.b); + /* { dg-output "\nres: 24 144" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_4_1byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_4_1byte.c new file mode 100644 index 0000000..f3806d7 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_4_1byte.c @@ -0,0 +1,98 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Especially with small structures which may fit in one + register. Depending on the ABI. + Limitations: none. + PR: none. + Originator: 20030902 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_4_1byte { + unsigned char a; + unsigned char b; + unsigned char c; + unsigned char d; +} cls_struct_4_1byte; + +cls_struct_4_1byte cls_struct_4_1byte_fn(struct cls_struct_4_1byte a1, + struct cls_struct_4_1byte a2) +{ + struct cls_struct_4_1byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + result.d = a1.d + a2.d; + + printf("%d %d %d %d %d %d %d %d: %d %d %d %d\n", a1.a, a1.b, a1.c, a1.d, + a2.a, a2.b, a2.c, a2.d, + result.a, result.b, result.c, result.d); + + return result; +} + +static void +cls_struct_4_1byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_4_1byte a1, a2; + + a1 = *(struct cls_struct_4_1byte*)(args[0]); + a2 = *(struct cls_struct_4_1byte*)(args[1]); + + *(cls_struct_4_1byte*)resp = cls_struct_4_1byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[5]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_4_1byte g_dbl = { 12, 13, 14, 15 }; + struct cls_struct_4_1byte f_dbl = { 178, 179, 180, 181 }; + struct cls_struct_4_1byte res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = &ffi_type_uchar; + cls_struct_fields[4] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_4_1byte_fn), &res_dbl, args_dbl); + /* { dg-output "12 13 14 15 178 179 180 181: 190 192 194 196" } */ + printf("res: %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d); + /* { dg-output "\nres: 190 192 194 196" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_4_1byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_4_1byte(*)(cls_struct_4_1byte, cls_struct_4_1byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 13 14 15 178 179 180 181: 190 192 194 196" } */ + printf("res: %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d); + /* { dg-output "\nres: 190 192 194 196" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_4byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_4byte.c new file mode 100644 index 0000000..a1aba3c --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_4byte.c @@ -0,0 +1,90 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Check overlapping. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ + +#include "ffitest.h" + +typedef struct cls_struct_4byte { + unsigned short a; + unsigned short b; +} cls_struct_4byte; + +cls_struct_4byte cls_struct_4byte_fn(struct cls_struct_4byte a1, + struct cls_struct_4byte a2) +{ + struct cls_struct_4byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + + printf("%d %d %d %d: %d %d\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b); + + return result; +} + +static void +cls_struct_4byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_4byte a1, a2; + + a1 = *(struct cls_struct_4byte*)(args[0]); + a2 = *(struct cls_struct_4byte*)(args[1]); + + *(cls_struct_4byte*)resp = cls_struct_4byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_4byte g_dbl = { 127, 120 }; + struct cls_struct_4byte f_dbl = { 12, 128 }; + struct cls_struct_4byte res_dbl; + + cls_struct_fields[0] = &ffi_type_ushort; + cls_struct_fields[1] = &ffi_type_ushort; + cls_struct_fields[2] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_4byte_fn), &res_dbl, args_dbl); + /* { dg-output "127 120 12 128: 139 248" } */ + printf("res: %d %d\n", res_dbl.a, res_dbl.b); + /* { dg-output "\nres: 139 248" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_4byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_4byte(*)(cls_struct_4byte, cls_struct_4byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n127 120 12 128: 139 248" } */ + printf("res: %d %d\n", res_dbl.a, res_dbl.b); + /* { dg-output "\nres: 139 248" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_5_1_byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_5_1_byte.c new file mode 100644 index 0000000..2ceba3d --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_5_1_byte.c @@ -0,0 +1,109 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Check overlapping. + Limitations: none. + PR: none. + Originator: 20050708 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_5byte { + unsigned char a; + unsigned char b; + unsigned char c; + unsigned char d; + unsigned char e; +} cls_struct_5byte; + +cls_struct_5byte cls_struct_5byte_fn(struct cls_struct_5byte a1, + struct cls_struct_5byte a2) +{ + struct cls_struct_5byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + result.d = a1.d + a2.d; + result.e = a1.e + a2.e; + + printf("%d %d %d %d %d %d %d %d %d %d: %d %d %d %d %d\n", + a1.a, a1.b, a1.c, a1.d, a1.e, + a2.a, a2.b, a2.c, a2.d, a2.e, + result.a, result.b, result.c, result.d, result.e); + + return result; +} + +static void +cls_struct_5byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_5byte a1, a2; + + a1 = *(struct cls_struct_5byte*)(args[0]); + a2 = *(struct cls_struct_5byte*)(args[1]); + + *(cls_struct_5byte*)resp = cls_struct_5byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[6]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_5byte g_dbl = { 127, 120, 1, 3, 4 }; + struct cls_struct_5byte f_dbl = { 12, 128, 9, 3, 4 }; + struct cls_struct_5byte res_dbl = { 0, 0, 0, 0, 0 }; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = &ffi_type_uchar; + cls_struct_fields[4] = &ffi_type_uchar; + cls_struct_fields[5] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_5byte_fn), &res_dbl, args_dbl); + /* { dg-output "127 120 1 3 4 12 128 9 3 4: 139 248 10 6 8" } */ + printf("res: %d %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, + res_dbl.d, res_dbl.e); + /* { dg-output "\nres: 139 248 10 6 8" } */ + + res_dbl.a = 0; + res_dbl.b = 0; + res_dbl.c = 0; + res_dbl.d = 0; + res_dbl.e = 0; + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_5byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_5byte(*)(cls_struct_5byte, cls_struct_5byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n127 120 1 3 4 12 128 9 3 4: 139 248 10 6 8" } */ + printf("res: %d %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, + res_dbl.d, res_dbl.e); + /* { dg-output "\nres: 139 248 10 6 8" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_5byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_5byte.c new file mode 100644 index 0000000..61d595c --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_5byte.c @@ -0,0 +1,98 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Check overlapping. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_5byte { + unsigned short a; + unsigned short b; + unsigned char c; +} cls_struct_5byte; + +cls_struct_5byte cls_struct_5byte_fn(struct cls_struct_5byte a1, + struct cls_struct_5byte a2) +{ + struct cls_struct_5byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + printf("%d %d %d %d %d %d: %d %d %d\n", a1.a, a1.b, a1.c, + a2.a, a2.b, a2.c, + result.a, result.b, result.c); + + return result; +} + +static void +cls_struct_5byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_5byte a1, a2; + + a1 = *(struct cls_struct_5byte*)(args[0]); + a2 = *(struct cls_struct_5byte*)(args[1]); + + *(cls_struct_5byte*)resp = cls_struct_5byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_5byte g_dbl = { 127, 120, 1 }; + struct cls_struct_5byte f_dbl = { 12, 128, 9 }; + struct cls_struct_5byte res_dbl = { 0, 0, 0 }; + + cls_struct_fields[0] = &ffi_type_ushort; + cls_struct_fields[1] = &ffi_type_ushort; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_5byte_fn), &res_dbl, args_dbl); + /* { dg-output "127 120 1 12 128 9: 139 248 10" } */ + printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 139 248 10" } */ + + res_dbl.a = 0; + res_dbl.b = 0; + res_dbl.c = 0; + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_5byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_5byte(*)(cls_struct_5byte, cls_struct_5byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n127 120 1 12 128 9: 139 248 10" } */ + printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 139 248 10" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_64byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_64byte.c new file mode 100644 index 0000000..576ebe0 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_64byte.c @@ -0,0 +1,124 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Check bigger struct which overlaps + the gp and fp register count on Darwin/AIX/ppc64. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_64byte { + double a; + double b; + double c; + double d; + double e; + double f; + double g; + double h; +} cls_struct_64byte; + +cls_struct_64byte cls_struct_64byte_fn(struct cls_struct_64byte b0, + struct cls_struct_64byte b1, + struct cls_struct_64byte b2, + struct cls_struct_64byte b3) +{ + struct cls_struct_64byte result; + + result.a = b0.a + b1.a + b2.a + b3.a; + result.b = b0.b + b1.b + b2.b + b3.b; + result.c = b0.c + b1.c + b2.c + b3.c; + result.d = b0.d + b1.d + b2.d + b3.d; + result.e = b0.e + b1.e + b2.e + b3.e; + result.f = b0.f + b1.f + b2.f + b3.f; + result.g = b0.g + b1.g + b2.g + b3.g; + result.h = b0.h + b1.h + b2.h + b3.h; + + printf("%g %g %g %g %g %g %g %g\n", result.a, result.b, result.c, + result.d, result.e, result.f, result.g, result.h); + + return result; +} + +static void +cls_struct_64byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct cls_struct_64byte b0, b1, b2, b3; + + b0 = *(struct cls_struct_64byte*)(args[0]); + b1 = *(struct cls_struct_64byte*)(args[1]); + b2 = *(struct cls_struct_64byte*)(args[2]); + b3 = *(struct cls_struct_64byte*)(args[3]); + + *(cls_struct_64byte*)resp = cls_struct_64byte_fn(b0, b1, b2, b3); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[9]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_64byte e_dbl = { 9.0, 2.0, 6.0, 5.0, 3.0, 4.0, 8.0, 1.0 }; + struct cls_struct_64byte f_dbl = { 1.0, 2.0, 3.0, 7.0, 2.0, 5.0, 6.0, 7.0 }; + struct cls_struct_64byte g_dbl = { 4.0, 5.0, 7.0, 9.0, 1.0, 1.0, 2.0, 9.0 }; + struct cls_struct_64byte h_dbl = { 8.0, 6.0, 1.0, 4.0, 0.0, 3.0, 3.0, 1.0 }; + struct cls_struct_64byte res_dbl; + + cls_struct_fields[0] = &ffi_type_double; + cls_struct_fields[1] = &ffi_type_double; + cls_struct_fields[2] = &ffi_type_double; + cls_struct_fields[3] = &ffi_type_double; + cls_struct_fields[4] = &ffi_type_double; + cls_struct_fields[5] = &ffi_type_double; + cls_struct_fields[6] = &ffi_type_double; + cls_struct_fields[7] = &ffi_type_double; + cls_struct_fields[8] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = &cls_struct_type; + dbl_arg_types[3] = &cls_struct_type; + dbl_arg_types[4] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = &g_dbl; + args_dbl[3] = &h_dbl; + args_dbl[4] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_64byte_fn), &res_dbl, args_dbl); + /* { dg-output "22 15 17 25 6 13 19 18" } */ + printf("res: %g %g %g %g %g %g %g %g\n", res_dbl.a, res_dbl.b, res_dbl.c, + res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h); + /* { dg-output "\nres: 22 15 17 25 6 13 19 18" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_64byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_64byte(*)(cls_struct_64byte, + cls_struct_64byte, + cls_struct_64byte, + cls_struct_64byte)) + (code))(e_dbl, f_dbl, g_dbl, h_dbl); + /* { dg-output "\n22 15 17 25 6 13 19 18" } */ + printf("res: %g %g %g %g %g %g %g %g\n", res_dbl.a, res_dbl.b, res_dbl.c, + res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h); + /* { dg-output "\nres: 22 15 17 25 6 13 19 18" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_6_1_byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_6_1_byte.c new file mode 100644 index 0000000..9f2eff6 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_6_1_byte.c @@ -0,0 +1,113 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Check overlapping. + Limitations: none. + PR: none. + Originator: 20050708 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_6byte { + unsigned char a; + unsigned char b; + unsigned char c; + unsigned char d; + unsigned char e; + unsigned char f; +} cls_struct_6byte; + +cls_struct_6byte cls_struct_6byte_fn(struct cls_struct_6byte a1, + struct cls_struct_6byte a2) +{ + struct cls_struct_6byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + result.d = a1.d + a2.d; + result.e = a1.e + a2.e; + result.f = a1.f + a2.f; + + printf("%d %d %d %d %d %d %d %d %d %d %d %d: %d %d %d %d %d %d\n", + a1.a, a1.b, a1.c, a1.d, a1.e, a1.f, + a2.a, a2.b, a2.c, a2.d, a2.e, a2.f, + result.a, result.b, result.c, result.d, result.e, result.f); + + return result; +} + +static void +cls_struct_6byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_6byte a1, a2; + + a1 = *(struct cls_struct_6byte*)(args[0]); + a2 = *(struct cls_struct_6byte*)(args[1]); + + *(cls_struct_6byte*)resp = cls_struct_6byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[7]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_6byte g_dbl = { 127, 120, 1, 3, 4, 5 }; + struct cls_struct_6byte f_dbl = { 12, 128, 9, 3, 4, 5 }; + struct cls_struct_6byte res_dbl = { 0, 0, 0, 0, 0, 0 }; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = &ffi_type_uchar; + cls_struct_fields[4] = &ffi_type_uchar; + cls_struct_fields[5] = &ffi_type_uchar; + cls_struct_fields[6] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_6byte_fn), &res_dbl, args_dbl); + /* { dg-output "127 120 1 3 4 5 12 128 9 3 4 5: 139 248 10 6 8 10" } */ + printf("res: %d %d %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, + res_dbl.d, res_dbl.e, res_dbl.f); + /* { dg-output "\nres: 139 248 10 6 8 10" } */ + + res_dbl.a = 0; + res_dbl.b = 0; + res_dbl.c = 0; + res_dbl.d = 0; + res_dbl.e = 0; + res_dbl.f = 0; + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_6byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_6byte(*)(cls_struct_6byte, cls_struct_6byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n127 120 1 3 4 5 12 128 9 3 4 5: 139 248 10 6 8 10" } */ + printf("res: %d %d %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, + res_dbl.d, res_dbl.e, res_dbl.f); + /* { dg-output "\nres: 139 248 10 6 8 10" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_6byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_6byte.c new file mode 100644 index 0000000..73257b0 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_6byte.c @@ -0,0 +1,99 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Check overlapping. + Limitations: none. + PR: none. + Originator: 20030828 */ + + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_6byte { + unsigned short a; + unsigned short b; + unsigned char c; + unsigned char d; +} cls_struct_6byte; + +cls_struct_6byte cls_struct_6byte_fn(struct cls_struct_6byte a1, + struct cls_struct_6byte a2) +{ + struct cls_struct_6byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + result.d = a1.d + a2.d; + + printf("%d %d %d %d %d %d %d %d: %d %d %d %d\n", a1.a, a1.b, a1.c, a1.d, + a2.a, a2.b, a2.c, a2.d, + result.a, result.b, result.c, result.d); + + return result; +} + +static void +cls_struct_6byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_6byte a1, a2; + + a1 = *(struct cls_struct_6byte*)(args[0]); + a2 = *(struct cls_struct_6byte*)(args[1]); + + *(cls_struct_6byte*)resp = cls_struct_6byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[5]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_6byte g_dbl = { 127, 120, 1, 128 }; + struct cls_struct_6byte f_dbl = { 12, 128, 9, 127 }; + struct cls_struct_6byte res_dbl; + + cls_struct_fields[0] = &ffi_type_ushort; + cls_struct_fields[1] = &ffi_type_ushort; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = &ffi_type_uchar; + cls_struct_fields[4] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_6byte_fn), &res_dbl, args_dbl); + /* { dg-output "127 120 1 128 12 128 9 127: 139 248 10 255" } */ + printf("res: %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d); + /* { dg-output "\nres: 139 248 10 255" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_6byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_6byte(*)(cls_struct_6byte, cls_struct_6byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n127 120 1 128 12 128 9 127: 139 248 10 255" } */ + printf("res: %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d); + /* { dg-output "\nres: 139 248 10 255" } */ + + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_7_1_byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_7_1_byte.c new file mode 100644 index 0000000..50d09c9 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_7_1_byte.c @@ -0,0 +1,117 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Check overlapping. + Limitations: none. + PR: none. + Originator: 20050708 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_7byte { + unsigned char a; + unsigned char b; + unsigned char c; + unsigned char d; + unsigned char e; + unsigned char f; + unsigned char g; +} cls_struct_7byte; + +cls_struct_7byte cls_struct_7byte_fn(struct cls_struct_7byte a1, + struct cls_struct_7byte a2) +{ + struct cls_struct_7byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + result.d = a1.d + a2.d; + result.e = a1.e + a2.e; + result.f = a1.f + a2.f; + result.g = a1.g + a2.g; + + printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d %d %d %d %d %d %d\n", + a1.a, a1.b, a1.c, a1.d, a1.e, a1.f, a1.g, + a2.a, a2.b, a2.c, a2.d, a2.e, a2.f, a2.g, + result.a, result.b, result.c, result.d, result.e, result.f, result.g); + + return result; +} + +static void +cls_struct_7byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_7byte a1, a2; + + a1 = *(struct cls_struct_7byte*)(args[0]); + a2 = *(struct cls_struct_7byte*)(args[1]); + + *(cls_struct_7byte*)resp = cls_struct_7byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[8]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_7byte g_dbl = { 127, 120, 1, 3, 4, 5, 6 }; + struct cls_struct_7byte f_dbl = { 12, 128, 9, 3, 4, 5, 6 }; + struct cls_struct_7byte res_dbl = { 0, 0, 0, 0, 0, 0, 0 }; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = &ffi_type_uchar; + cls_struct_fields[4] = &ffi_type_uchar; + cls_struct_fields[5] = &ffi_type_uchar; + cls_struct_fields[6] = &ffi_type_uchar; + cls_struct_fields[7] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_7byte_fn), &res_dbl, args_dbl); + /* { dg-output "127 120 1 3 4 5 6 12 128 9 3 4 5 6: 139 248 10 6 8 10 12" } */ + printf("res: %d %d %d %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, + res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g); + /* { dg-output "\nres: 139 248 10 6 8 10 12" } */ + + res_dbl.a = 0; + res_dbl.b = 0; + res_dbl.c = 0; + res_dbl.d = 0; + res_dbl.e = 0; + res_dbl.f = 0; + res_dbl.g = 0; + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_7byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_7byte(*)(cls_struct_7byte, cls_struct_7byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n127 120 1 3 4 5 6 12 128 9 3 4 5 6: 139 248 10 6 8 10 12" } */ + printf("res: %d %d %d %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, + res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g); + /* { dg-output "\nres: 139 248 10 6 8 10 12" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_7byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_7byte.c new file mode 100644 index 0000000..f5c0000 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_7byte.c @@ -0,0 +1,97 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Check overlapping. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_7byte { + unsigned short a; + unsigned short b; + unsigned char c; + unsigned short d; +} cls_struct_7byte; + +cls_struct_7byte cls_struct_7byte_fn(struct cls_struct_7byte a1, + struct cls_struct_7byte a2) +{ + struct cls_struct_7byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + result.d = a1.d + a2.d; + + printf("%d %d %d %d %d %d %d %d: %d %d %d %d\n", a1.a, a1.b, a1.c, a1.d, + a2.a, a2.b, a2.c, a2.d, + result.a, result.b, result.c, result.d); + + return result; +} + +static void +cls_struct_7byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_7byte a1, a2; + + a1 = *(struct cls_struct_7byte*)(args[0]); + a2 = *(struct cls_struct_7byte*)(args[1]); + + *(cls_struct_7byte*)resp = cls_struct_7byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[5]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_7byte g_dbl = { 127, 120, 1, 254 }; + struct cls_struct_7byte f_dbl = { 12, 128, 9, 255 }; + struct cls_struct_7byte res_dbl; + + cls_struct_fields[0] = &ffi_type_ushort; + cls_struct_fields[1] = &ffi_type_ushort; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = &ffi_type_ushort; + cls_struct_fields[4] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_7byte_fn), &res_dbl, args_dbl); + /* { dg-output "127 120 1 254 12 128 9 255: 139 248 10 509" } */ + printf("res: %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d); + /* { dg-output "\nres: 139 248 10 509" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_7byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_7byte(*)(cls_struct_7byte, cls_struct_7byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n127 120 1 254 12 128 9 255: 139 248 10 509" } */ + printf("res: %d %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c, res_dbl.d); + /* { dg-output "\nres: 139 248 10 509" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_8byte.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_8byte.c new file mode 100644 index 0000000..4aa99d1 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_8byte.c @@ -0,0 +1,88 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Check overlapping. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_8byte { + int a; + float b; +} cls_struct_8byte; + +cls_struct_8byte cls_struct_8byte_fn(struct cls_struct_8byte a1, + struct cls_struct_8byte a2) +{ + struct cls_struct_8byte result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + + printf("%d %g %d %g: %d %g\n", a1.a, a1.b, a2.a, a2.b, result.a, result.b); + + return result; +} + +static void +cls_struct_8byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_8byte a1, a2; + + a1 = *(struct cls_struct_8byte*)(args[0]); + a2 = *(struct cls_struct_8byte*)(args[1]); + + *(cls_struct_8byte*)resp = cls_struct_8byte_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_8byte g_dbl = { 1, 2.0 }; + struct cls_struct_8byte f_dbl = { 4, 5.0 }; + struct cls_struct_8byte res_dbl; + + cls_struct_fields[0] = &ffi_type_sint; + cls_struct_fields[1] = &ffi_type_float; + cls_struct_fields[2] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_8byte_fn), &res_dbl, args_dbl); + /* { dg-output "1 2 4 5: 5 7" } */ + printf("res: %d %g\n", res_dbl.a, res_dbl.b); + /* { dg-output "\nres: 5 7" } */ + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_8byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_8byte(*)(cls_struct_8byte, cls_struct_8byte))(code))(g_dbl, f_dbl); + /* { dg-output "\n1 2 4 5: 5 7" } */ + printf("res: %d %g\n", res_dbl.a, res_dbl.b); + /* { dg-output "\nres: 5 7" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_9byte1.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_9byte1.c new file mode 100644 index 0000000..cc5e9d6 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_9byte1.c @@ -0,0 +1,90 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Darwin/AIX do double-word + alignment of the struct if the first element is a double. + Check that it does not here. + Limitations: none. + PR: none. + Originator: 20030914 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_9byte { + int a; + double b; +} cls_struct_9byte; + +cls_struct_9byte cls_struct_9byte_fn(struct cls_struct_9byte b1, + struct cls_struct_9byte b2) +{ + struct cls_struct_9byte result; + + result.a = b1.a + b2.a; + result.b = b1.b + b2.b; + + printf("%d %g %d %g: %d %g\n", b1.a, b1.b, b2.a, b2.b, + result.a, result.b); + + return result; +} + +static void cls_struct_9byte_gn(ffi_cif* cif __UNUSED__, void* resp, + void** args, void* userdata __UNUSED__) +{ + struct cls_struct_9byte b1, b2; + + b1 = *(struct cls_struct_9byte*)(args[0]); + b2 = *(struct cls_struct_9byte*)(args[1]); + + *(cls_struct_9byte*)resp = cls_struct_9byte_fn(b1, b2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[3]; + ffi_type* cls_struct_fields[3]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[3]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_9byte h_dbl = { 7, 8.0}; + struct cls_struct_9byte j_dbl = { 1, 9.0}; + struct cls_struct_9byte res_dbl; + + cls_struct_fields[0] = &ffi_type_sint; + cls_struct_fields[1] = &ffi_type_double; + cls_struct_fields[2] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &h_dbl; + args_dbl[1] = &j_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_9byte_fn), &res_dbl, args_dbl); + /* { dg-output "7 8 1 9: 8 17" } */ + printf("res: %d %g\n", res_dbl.a, res_dbl.b); + /* { dg-output "\nres: 8 17" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_9byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_9byte(*)(cls_struct_9byte, cls_struct_9byte))(code))(h_dbl, j_dbl); + /* { dg-output "\n7 8 1 9: 8 17" } */ + printf("res: %d %g\n", res_dbl.a, res_dbl.b); + /* { dg-output "\nres: 8 17" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_9byte2.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_9byte2.c new file mode 100644 index 0000000..5c0ba0d --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_9byte2.c @@ -0,0 +1,91 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Depending on the ABI. Darwin/AIX do double-word + alignment of the struct if the first element is a double. + Check that it does here. + Limitations: none. + PR: none. + Originator: 20030914 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_9byte { + double a; + int b; +} cls_struct_9byte; + +cls_struct_9byte cls_struct_9byte_fn(struct cls_struct_9byte b1, + struct cls_struct_9byte b2) +{ + struct cls_struct_9byte result; + + result.a = b1.a + b2.a; + result.b = b1.b + b2.b; + + printf("%g %d %g %d: %g %d\n", b1.a, b1.b, b2.a, b2.b, + result.a, result.b); + + return result; +} + +static void cls_struct_9byte_gn(ffi_cif* cif __UNUSED__, void* resp, + void** args, void* userdata __UNUSED__) +{ + struct cls_struct_9byte b1, b2; + + b1 = *(struct cls_struct_9byte*)(args[0]); + b2 = *(struct cls_struct_9byte*)(args[1]); + + *(cls_struct_9byte*)resp = cls_struct_9byte_fn(b1, b2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[3]; + ffi_type* cls_struct_fields[3]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[3]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_9byte h_dbl = { 7.0, 8}; + struct cls_struct_9byte j_dbl = { 1.0, 9}; + struct cls_struct_9byte res_dbl; + + cls_struct_fields[0] = &ffi_type_double; + cls_struct_fields[1] = &ffi_type_sint; + cls_struct_fields[2] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &h_dbl; + args_dbl[1] = &j_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_9byte_fn), &res_dbl, args_dbl); + /* { dg-output "7 8 1 9: 8 17" } */ + printf("res: %g %d\n", res_dbl.a, res_dbl.b); + /* { dg-output "\nres: 8 17" } */ + + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_9byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_9byte(*)(cls_struct_9byte, cls_struct_9byte))(code))(h_dbl, j_dbl); + /* { dg-output "\n7 8 1 9: 8 17" } */ + printf("res: %g %d\n", res_dbl.a, res_dbl.b); + /* { dg-output "\nres: 8 17" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_double.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_double.c new file mode 100644 index 0000000..22b94d5 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_double.c @@ -0,0 +1,93 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of double. + Limitations: none. + PR: none. + Originator: 20031203 */ + + + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_align { + unsigned char a; + double b; + unsigned char c; +} cls_struct_align; + +cls_struct_align cls_struct_align_fn(struct cls_struct_align a1, + struct cls_struct_align a2) +{ + struct cls_struct_align result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + printf("%d %g %d %d %g %d: %d %g %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c); + + return result; +} + +static void +cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_align a1, a2; + + a1 = *(struct cls_struct_align*)(args[0]); + a2 = *(struct cls_struct_align*)(args[1]); + + *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_align g_dbl = { 12, 4951, 127 }; + struct cls_struct_align f_dbl = { 1, 9320, 13 }; + struct cls_struct_align res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_double; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl); + /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %g %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_float.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_float.c new file mode 100644 index 0000000..62637f2 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_float.c @@ -0,0 +1,91 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of float. + Limitations: none. + PR: none. + Originator: 20031203 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_align { + unsigned char a; + float b; + unsigned char c; +} cls_struct_align; + +cls_struct_align cls_struct_align_fn(struct cls_struct_align a1, + struct cls_struct_align a2) +{ + struct cls_struct_align result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + printf("%d %g %d %d %g %d: %d %g %d\n", a1.a, (double)a1.b, a1.c, a2.a, (double)a2.b, a2.c, result.a, (double)result.b, result.c); + + return result; +} + +static void +cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_align a1, a2; + + a1 = *(struct cls_struct_align*)(args[0]); + a2 = *(struct cls_struct_align*)(args[1]); + + *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_align g_dbl = { 12, 4951, 127 }; + struct cls_struct_align f_dbl = { 1, 9320, 13 }; + struct cls_struct_align res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_float; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl); + /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %g %d\n", res_dbl.a, (double)res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %g %d\n", res_dbl.a, (double)res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble.c new file mode 100644 index 0000000..af38060 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble.c @@ -0,0 +1,92 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of long double. + Limitations: none. + PR: none. + Originator: 20031203 */ + +/* { dg-do run } */ + +#include "ffitest.h" + +typedef struct cls_struct_align { + unsigned char a; + long double b; + unsigned char c; +} cls_struct_align; + +cls_struct_align cls_struct_align_fn(struct cls_struct_align a1, + struct cls_struct_align a2) +{ + struct cls_struct_align result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + printf("%d %g %d %d %g %d: %d %g %d\n", a1.a, (double)a1.b, a1.c, a2.a, (double)a2.b, a2.c, result.a, (double)result.b, result.c); + + return result; +} + +static void +cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_align a1, a2; + + a1 = *(struct cls_struct_align*)(args[0]); + a2 = *(struct cls_struct_align*)(args[1]); + + *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_align g_dbl = { 12, 4951, 127 }; + struct cls_struct_align f_dbl = { 1, 9320, 13 }; + struct cls_struct_align res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_longdouble; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl); + /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %g %d\n", res_dbl.a, (double)res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %g %d\n", res_dbl.a, (double)res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split.c new file mode 100644 index 0000000..4274af1 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split.c @@ -0,0 +1,134 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of long double. + Limitations: none. + PR: none. + Originator: 20031203 */ + +/* { dg-excess-errors "no long double format" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ +/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ +/* { dg-options -mlong-double-128 { target powerpc64*-*-* } } */ +/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ + +#include "ffitest.h" + +typedef struct cls_struct_align { + long double a; + long double b; + long double c; + long double d; + long double e; + long double f; + long double g; +} cls_struct_align; + +cls_struct_align cls_struct_align_fn( + cls_struct_align a1, + cls_struct_align a2) +{ + struct cls_struct_align r; + + r.a = a1.a + a2.a; + r.b = a1.b + a2.b; + r.c = a1.c + a2.c; + r.d = a1.d + a2.d; + r.e = a1.e + a2.e; + r.f = a1.f + a2.f; + r.g = a1.g + a2.g; + + printf("%Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg: " + "%Lg %Lg %Lg %Lg %Lg %Lg %Lg\n", + a1.a, a1.b, a1.c, a1.d, a1.e, a1.f, a1.g, + a2.a, a2.b, a2.c, a2.d, a2.e, a2.f, a2.g, + r.a, r.b, r.c, r.d, r.e, r.f, r.g); + + return r; +} + +cls_struct_align cls_struct_align_fn2( + cls_struct_align a1) +{ + struct cls_struct_align r; + + r.a = a1.a + 1; + r.b = a1.b + 1; + r.c = a1.c + 1; + r.d = a1.d + 1; + r.e = a1.e + 1; + r.f = a1.f + 1; + r.g = a1.g + 1; + + printf("%Lg %Lg %Lg %Lg %Lg %Lg %Lg: " + "%Lg %Lg %Lg %Lg %Lg %Lg %Lg\n", + a1.a, a1.b, a1.c, a1.d, a1.e, a1.f, a1.g, + r.a, r.b, r.c, r.d, r.e, r.f, r.g); + + return r; +} + +static void +cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct cls_struct_align a1, a2; + + a1 = *(struct cls_struct_align*)(args[0]); + a2 = *(struct cls_struct_align*)(args[1]); + + *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[3]; + ffi_type* cls_struct_fields[8]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[3]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_align g_dbl = { 1, 2, 3, 4, 5, 6, 7 }; + struct cls_struct_align f_dbl = { 8, 9, 10, 11, 12, 13, 14 }; + struct cls_struct_align res_dbl; + + cls_struct_fields[0] = &ffi_type_longdouble; + cls_struct_fields[1] = &ffi_type_longdouble; + cls_struct_fields[2] = &ffi_type_longdouble; + cls_struct_fields[3] = &ffi_type_longdouble; + cls_struct_fields[4] = &ffi_type_longdouble; + cls_struct_fields[5] = &ffi_type_longdouble; + cls_struct_fields[6] = &ffi_type_longdouble; + cls_struct_fields[7] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl); + /* { dg-output "1 2 3 4 5 6 7 8 9 10 11 12 13 14: 9 11 13 15 17 19 21" } */ + printf("res: %Lg %Lg %Lg %Lg %Lg %Lg %Lg\n", res_dbl.a, res_dbl.b, + res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g); + /* { dg-output "\nres: 9 11 13 15 17 19 21" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl); + /* { dg-output "\n1 2 3 4 5 6 7 8 9 10 11 12 13 14: 9 11 13 15 17 19 21" } */ + printf("res: %Lg %Lg %Lg %Lg %Lg %Lg %Lg\n", res_dbl.a, res_dbl.b, + res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g); + /* { dg-output "\nres: 9 11 13 15 17 19 21" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c new file mode 100644 index 0000000..088f0d3 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_longdouble_split2.c @@ -0,0 +1,117 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of long double. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/18/2007 +*/ + +/* { dg-excess-errors "no long double format" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ +/* { dg-do run { xfail strongarm*-*-* } } */ +/* { dg-options -mlong-double-128 { target powerpc64*-*-* } } */ +/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ + +#include "ffitest.h" + +typedef struct cls_struct_align { + long double a; + long double b; + long double c; + long double d; + long double e; + double f; + long double g; +} cls_struct_align; + +cls_struct_align cls_struct_align_fn( + cls_struct_align a1, + cls_struct_align a2) +{ + struct cls_struct_align r; + + r.a = a1.a + a2.a; + r.b = a1.b + a2.b; + r.c = a1.c + a2.c; + r.d = a1.d + a2.d; + r.e = a1.e + a2.e; + r.f = a1.f + a2.f; + r.g = a1.g + a2.g; + + printf("%Lg %Lg %Lg %Lg %Lg %g %Lg %Lg %Lg %Lg %Lg %Lg %g %Lg: " + "%Lg %Lg %Lg %Lg %Lg %g %Lg\n", + a1.a, a1.b, a1.c, a1.d, a1.e, a1.f, a1.g, + a2.a, a2.b, a2.c, a2.d, a2.e, a2.f, a2.g, + r.a, r.b, r.c, r.d, r.e, r.f, r.g); + + return r; +} + +static void +cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct cls_struct_align a1, a2; + + a1 = *(struct cls_struct_align*)(args[0]); + a2 = *(struct cls_struct_align*)(args[1]); + + *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[3]; + ffi_type* cls_struct_fields[8]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[3]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_align g_dbl = { 1, 2, 3, 4, 5, 6, 7 }; + struct cls_struct_align f_dbl = { 8, 9, 10, 11, 12, 13, 14 }; + struct cls_struct_align res_dbl; + + cls_struct_fields[0] = &ffi_type_longdouble; + cls_struct_fields[1] = &ffi_type_longdouble; + cls_struct_fields[2] = &ffi_type_longdouble; + cls_struct_fields[3] = &ffi_type_longdouble; + cls_struct_fields[4] = &ffi_type_longdouble; + cls_struct_fields[5] = &ffi_type_double; + cls_struct_fields[6] = &ffi_type_longdouble; + cls_struct_fields[7] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl); + /* { dg-output "1 2 3 4 5 6 7 8 9 10 11 12 13 14: 9 11 13 15 17 19 21" } */ + printf("res: %Lg %Lg %Lg %Lg %Lg %g %Lg\n", res_dbl.a, res_dbl.b, + res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g); + /* { dg-output "\nres: 9 11 13 15 17 19 21" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl); + /* { dg-output "\n1 2 3 4 5 6 7 8 9 10 11 12 13 14: 9 11 13 15 17 19 21" } */ + printf("res: %Lg %Lg %Lg %Lg %Lg %g %Lg\n", res_dbl.a, res_dbl.b, + res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g); + /* { dg-output "\nres: 9 11 13 15 17 19 21" } */ + + exit(0); +} + + + diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_pointer.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_pointer.c new file mode 100644 index 0000000..cbc4f95 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_pointer.c @@ -0,0 +1,95 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of pointer. + Limitations: none. + PR: none. + Originator: 20031203 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_align { + unsigned char a; + void *b; + unsigned char c; +} cls_struct_align; + +cls_struct_align cls_struct_align_fn(struct cls_struct_align a1, + struct cls_struct_align a2) +{ + struct cls_struct_align result; + + result.a = a1.a + a2.a; + result.b = (void *)((uintptr_t)a1.b + (uintptr_t)a2.b); + result.c = a1.c + a2.c; + + printf("%d %" PRIuPTR " %d %d %" PRIuPTR " %d: %d %" PRIuPTR " %d\n", + a1.a, (uintptr_t)a1.b, a1.c, + a2.a, (uintptr_t)a2.b, a2.c, + result.a, (uintptr_t)result.b, + result.c); + + return result; +} + +static void +cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_align a1, a2; + + a1 = *(struct cls_struct_align*)(args[0]); + a2 = *(struct cls_struct_align*)(args[1]); + + *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_align g_dbl = { 12, (void *)4951, 127 }; + struct cls_struct_align f_dbl = { 1, (void *)9320, 13 }; + struct cls_struct_align res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_pointer; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl); + /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %" PRIuPTR " %d\n", res_dbl.a, (uintptr_t)res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %" PRIuPTR " %d\n", res_dbl.a, (uintptr_t)res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint16.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint16.c new file mode 100644 index 0000000..383ea41 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint16.c @@ -0,0 +1,91 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of sint16. + Limitations: none. + PR: none. + Originator: 20031203 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_align { + unsigned char a; + signed short b; + unsigned char c; +} cls_struct_align; + +cls_struct_align cls_struct_align_fn(struct cls_struct_align a1, + struct cls_struct_align a2) +{ + struct cls_struct_align result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + printf("%d %d %d %d %d %d: %d %d %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c); + + return result; +} + +static void +cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_align a1, a2; + + a1 = *(struct cls_struct_align*)(args[0]); + a2 = *(struct cls_struct_align*)(args[1]); + + *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_align g_dbl = { 12, 4951, 127 }; + struct cls_struct_align f_dbl = { 1, 9320, 13 }; + struct cls_struct_align res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_sshort; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl); + /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint32.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint32.c new file mode 100644 index 0000000..705d78c --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint32.c @@ -0,0 +1,91 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of sint32. + Limitations: none. + PR: none. + Originator: 20031203 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_align { + unsigned char a; + signed int b; + unsigned char c; +} cls_struct_align; + +cls_struct_align cls_struct_align_fn(struct cls_struct_align a1, + struct cls_struct_align a2) +{ + struct cls_struct_align result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + printf("%d %d %d %d %d %d: %d %d %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c); + + return result; +} + +static void +cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_align a1, a2; + + a1 = *(struct cls_struct_align*)(args[0]); + a2 = *(struct cls_struct_align*)(args[1]); + + *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_align g_dbl = { 12, 4951, 127 }; + struct cls_struct_align f_dbl = { 1, 9320, 13 }; + struct cls_struct_align res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_sint; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl); + /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint64.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint64.c new file mode 100644 index 0000000..31d53af --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_sint64.c @@ -0,0 +1,92 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of sint64. + Limitations: none. + PR: none. + Originator: 20031203 */ + +/* { dg-do run } */ +/* { dg-options "-Wno-format" { target alpha*-dec-osf* } } */ +#include "ffitest.h" + +typedef struct cls_struct_align { + unsigned char a; + signed long long b; + unsigned char c; +} cls_struct_align; + +cls_struct_align cls_struct_align_fn(struct cls_struct_align a1, + struct cls_struct_align a2) +{ + struct cls_struct_align result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + printf("%d %" PRIdLL " %d %d %" PRIdLL " %d: %d %" PRIdLL " %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c); + + return result; +} + +static void +cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_align a1, a2; + + a1 = *(struct cls_struct_align*)(args[0]); + a2 = *(struct cls_struct_align*)(args[1]); + + *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_align g_dbl = { 12, 4951, 127 }; + struct cls_struct_align f_dbl = { 1, 9320, 13 }; + struct cls_struct_align res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_sint64; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl); + /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %" PRIdLL " %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %" PRIdLL " %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint16.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint16.c new file mode 100644 index 0000000..cb6b748 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint16.c @@ -0,0 +1,91 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of uint16. + Limitations: none. + PR: none. + Originator: 20031203 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_align { + unsigned char a; + unsigned short b; + unsigned char c; +} cls_struct_align; + +cls_struct_align cls_struct_align_fn(struct cls_struct_align a1, + struct cls_struct_align a2) +{ + struct cls_struct_align result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + printf("%d %d %d %d %d %d: %d %d %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c); + + return result; +} + +static void +cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_align a1, a2; + + a1 = *(struct cls_struct_align*)(args[0]); + a2 = *(struct cls_struct_align*)(args[1]); + + *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_align g_dbl = { 12, 4951, 127 }; + struct cls_struct_align f_dbl = { 1, 9320, 13 }; + struct cls_struct_align res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_ushort; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl); + /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint32.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint32.c new file mode 100644 index 0000000..e453d3e --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint32.c @@ -0,0 +1,91 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of uint32. + Limitations: none. + PR: none. + Originator: 20031203 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_align { + unsigned char a; + unsigned int b; + unsigned char c; +} cls_struct_align; + +cls_struct_align cls_struct_align_fn(struct cls_struct_align a1, + struct cls_struct_align a2) +{ + struct cls_struct_align result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + printf("%d %d %d %d %d %d: %d %d %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c); + + return result; +} + +static void +cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_align a1, a2; + + a1 = *(struct cls_struct_align*)(args[0]); + a2 = *(struct cls_struct_align*)(args[1]); + + *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_align g_dbl = { 12, 4951, 127 }; + struct cls_struct_align f_dbl = { 1, 9320, 13 }; + struct cls_struct_align res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_uint; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl); + /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %d %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint64.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint64.c new file mode 100644 index 0000000..495c79f --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_align_uint64.c @@ -0,0 +1,93 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure alignment of uint64. + Limitations: none. + PR: none. + Originator: 20031203 */ + + +/* { dg-do run } */ +/* { dg-options "-Wno-format" { target alpha*-dec-osf* } } */ +#include "ffitest.h" + +typedef struct cls_struct_align { + unsigned char a; + unsigned long long b; + unsigned char c; +} cls_struct_align; + +cls_struct_align cls_struct_align_fn(struct cls_struct_align a1, + struct cls_struct_align a2) +{ + struct cls_struct_align result; + + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + printf("%d %" PRIdLL " %d %d %" PRIdLL " %d: %d %" PRIdLL " %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c); + + return result; +} + +static void +cls_struct_align_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + + struct cls_struct_align a1, a2; + + a1 = *(struct cls_struct_align*)(args[0]); + a2 = *(struct cls_struct_align*)(args[1]); + + *(cls_struct_align*)resp = cls_struct_align_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[4]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct cls_struct_align g_dbl = { 12, 4951, 127 }; + struct cls_struct_align f_dbl = { 1, 9320, 13 }; + struct cls_struct_align res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_uint64; + cls_struct_fields[2] = &ffi_type_uchar; + cls_struct_fields[3] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &g_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl); + /* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %" PRIdLL " %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl); + /* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */ + printf("res: %d %" PRIdLL " %d\n", res_dbl.a, res_dbl.b, res_dbl.c); + /* { dg-output "\nres: 13 14271 140" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_dbls_struct.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_dbls_struct.c new file mode 100644 index 0000000..660dabb --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_dbls_struct.c @@ -0,0 +1,66 @@ +/* Area: ffi_call, closure_call + Purpose: Check double arguments in structs. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/23/2007 */ + +/* { dg-do run } */ + +#include "ffitest.h" + +typedef struct Dbls { + double x; + double y; +} Dbls; + +void +closure_test_fn(Dbls p) +{ + printf("%.1f %.1f\n", p.x, p.y); +} + +void +closure_test_gn(ffi_cif* cif __UNUSED__, void* resp __UNUSED__, + void** args, void* userdata __UNUSED__) +{ + closure_test_fn(*(Dbls*)args[0]); +} + +int main(int argc __UNUSED__, char** argv __UNUSED__) +{ + ffi_cif cif; + + void *code; + ffi_closure* pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type* cl_arg_types[1]; + + ffi_type ts1_type; + ffi_type* ts1_type_elements[4]; + + ts1_type.size = 0; + ts1_type.alignment = 0; + ts1_type.type = FFI_TYPE_STRUCT; + ts1_type.elements = ts1_type_elements; + + ts1_type_elements[0] = &ffi_type_double; + ts1_type_elements[1] = &ffi_type_double; + ts1_type_elements[2] = NULL; + + cl_arg_types[0] = &ts1_type; + + Dbls arg = { 1.0, 2.0 }; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_void, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_gn, NULL, code) == FFI_OK); + + ((void*(*)(Dbls))(code))(arg); + /* { dg-output "1.0 2.0\n" } */ + + closure_test_fn(arg); + /* { dg-output "1.0 2.0\n" } */ + + return 0; +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_double.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_double.c new file mode 100644 index 0000000..84ad4cb --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_double.c @@ -0,0 +1,43 @@ +/* Area: closure_call + Purpose: Check return value double. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static void cls_ret_double_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) + { + *(double *)resp = *(double *)args[0]; + + printf("%f: %f\n",*(double *)args[0], + *(double *)resp); + } +typedef double (*cls_ret_double)(double); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[2]; + double res; + + cl_arg_types[0] = &ffi_type_double; + cl_arg_types[1] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_double, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_double_fn, NULL, code) == FFI_OK); + + res = (*((cls_ret_double)code))(21474.789); + /* { dg-output "21474.789000: 21474.789000" } */ + printf("res: %.6f\n", res); + /* { dg-output "\nres: 21474.789000" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_double_va.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_double_va.c new file mode 100644 index 0000000..62bebbd --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_double_va.c @@ -0,0 +1,59 @@ +/* Area: ffi_call, closure_call + Purpose: Test doubles passed in variable argument lists. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/6/2007 */ + +/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ +/* { dg-output "" { xfail avr32*-*-* } } */ +/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */ + +#include "ffitest.h" + +static void +cls_double_va_fn(ffi_cif* cif __UNUSED__, void* resp, + void** args, void* userdata __UNUSED__) +{ + char* format = *(char**)args[0]; + double doubleValue = *(double*)args[1]; + + *(ffi_arg*)resp = printf(format, doubleValue); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args[3]; + ffi_type* arg_types[3]; + + char* format = "%.1f\n"; + double doubleArg = 7; + ffi_arg res = 0; + + arg_types[0] = &ffi_type_pointer; + arg_types[1] = &ffi_type_double; + arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, + arg_types) == FFI_OK); + + args[0] = &format; + args[1] = &doubleArg; + args[2] = NULL; + + ffi_call(&cif, FFI_FN(printf), &res, args); + // { dg-output "7.0" } + printf("res: %d\n", (int) res); + // { dg-output "\nres: 4" } + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_double_va_fn, NULL, code) == FFI_OK); + + res = ((int(*)(char*, double))(code))(format, doubleArg); + // { dg-output "\n7.0" } + printf("res: %d\n", (int) res); + // { dg-output "\nres: 4" } + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_float.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_float.c new file mode 100644 index 0000000..0090fed --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_float.c @@ -0,0 +1,42 @@ +/* Area: closure_call + Purpose: Check return value float. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static void cls_ret_float_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) + { + *(float *)resp = *(float *)args[0]; + + printf("%g: %g\n",*(float *)args[0], + *(float *)resp); + } + +typedef float (*cls_ret_float)(float); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[2]; + float res; + + cl_arg_types[0] = &ffi_type_float; + cl_arg_types[1] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_float, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_float_fn, NULL, code) == FFI_OK); + res = ((((cls_ret_float)code)(-2122.12))); + /* { dg-output "\\-2122.12: \\-2122.12" } */ + printf("res: %.6f\n", res); + /* { dg-output "\nres: \-2122.120117" } */ + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble.c new file mode 100644 index 0000000..52af6cf --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble.c @@ -0,0 +1,105 @@ +/* Area: ffi_call, closure_call + Purpose: Check long double arguments. + Limitations: none. + PR: none. + Originator: Blake Chaffin */ + +/* { dg-excess-errors "no long double format" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ +/* { dg-do run { xfail arm*-*-* strongarm*-*-* xscale*-*-* } } */ +/* { dg-options -mlong-double-128 { target powerpc64*-*-* } } */ +/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ + +#include "ffitest.h" + +long double cls_ldouble_fn( + long double a1, + long double a2, + long double a3, + long double a4, + long double a5, + long double a6, + long double a7, + long double a8) +{ + long double r = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8; + + printf("%Lg %Lg %Lg %Lg %Lg %Lg %Lg %Lg: %Lg\n", + a1, a2, a3, a4, a5, a6, a7, a8, r); + + return r; +} + +static void +cls_ldouble_gn(ffi_cif* cif __UNUSED__, void* resp, + void** args, void* userdata __UNUSED__) +{ + long double a1 = *(long double*)args[0]; + long double a2 = *(long double*)args[1]; + long double a3 = *(long double*)args[2]; + long double a4 = *(long double*)args[3]; + long double a5 = *(long double*)args[4]; + long double a6 = *(long double*)args[5]; + long double a7 = *(long double*)args[6]; + long double a8 = *(long double*)args[7]; + + *(long double*)resp = cls_ldouble_fn( + a1, a2, a3, a4, a5, a6, a7, a8); +} + +int main(void) +{ + ffi_cif cif; + void* code; + ffi_closure* pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args[9]; + ffi_type* arg_types[9]; + long double res = 0; + + long double arg1 = 1; + long double arg2 = 2; + long double arg3 = 3; + long double arg4 = 4; + long double arg5 = 5; + long double arg6 = 6; + long double arg7 = 7; + long double arg8 = 8; + + arg_types[0] = &ffi_type_longdouble; + arg_types[1] = &ffi_type_longdouble; + arg_types[2] = &ffi_type_longdouble; + arg_types[3] = &ffi_type_longdouble; + arg_types[4] = &ffi_type_longdouble; + arg_types[5] = &ffi_type_longdouble; + arg_types[6] = &ffi_type_longdouble; + arg_types[7] = &ffi_type_longdouble; + arg_types[8] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 8, &ffi_type_longdouble, + arg_types) == FFI_OK); + + args[0] = &arg1; + args[1] = &arg2; + args[2] = &arg3; + args[3] = &arg4; + args[4] = &arg5; + args[5] = &arg6; + args[6] = &arg7; + args[7] = &arg8; + args[8] = NULL; + + ffi_call(&cif, FFI_FN(cls_ldouble_fn), &res, args); + /* { dg-output "1 2 3 4 5 6 7 8: 36" } */ + printf("res: %Lg\n", res); + /* { dg-output "\nres: 36" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ldouble_gn, NULL, code) == FFI_OK); + + res = ((long double(*)(long double, long double, long double, long double, + long double, long double, long double, long double))(code))(arg1, arg2, + arg3, arg4, arg5, arg6, arg7, arg8); + /* { dg-output "\n1 2 3 4 5 6 7 8: 36" } */ + printf("res: %Lg\n", res); + /* { dg-output "\nres: 36" } */ + + return 0; +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c new file mode 100644 index 0000000..b33b2b7 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_longdouble_va.c @@ -0,0 +1,59 @@ +/* Area: ffi_call, closure_call + Purpose: Test long doubles passed in variable argument lists. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/6/2007 */ + +/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ +/* { dg-output "" { xfail avr32*-*-* x86_64-*-mingw* } } */ +/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */ + +#include "ffitest.h" + +static void +cls_longdouble_va_fn(ffi_cif* cif __UNUSED__, void* resp, + void** args, void* userdata __UNUSED__) +{ + char* format = *(char**)args[0]; + long double ldValue = *(long double*)args[1]; + + *(ffi_arg*)resp = printf(format, ldValue); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args[3]; + ffi_type* arg_types[3]; + + char* format = "%.1Lf\n"; + long double ldArg = 7; + ffi_arg res = 0; + + arg_types[0] = &ffi_type_pointer; + arg_types[1] = &ffi_type_longdouble; + arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, + arg_types) == FFI_OK); + + args[0] = &format; + args[1] = &ldArg; + args[2] = NULL; + + ffi_call(&cif, FFI_FN(printf), &res, args); + // { dg-output "7.0" } + printf("res: %d\n", (int) res); + // { dg-output "\nres: 4" } + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL, code) == FFI_OK); + + res = ((int(*)(char*, long double))(code))(format, ldArg); + // { dg-output "\n7.0" } + printf("res: %d\n", (int) res); + // { dg-output "\nres: 4" } + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_schar.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_schar.c new file mode 100644 index 0000000..71df7b6 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_schar.c @@ -0,0 +1,74 @@ +/* Area: ffi_call, closure_call + Purpose: Check passing of multiple signed char values. + Limitations: none. + PR: PR13221. + Originator: 20031129 */ + +/* { dg-do run } */ +#include "ffitest.h" + +signed char test_func_fn(signed char a1, signed char a2) +{ + signed char result; + + result = a1 + a2; + + printf("%d %d: %d\n", a1, a2, result); + + return result; + +} + +static void test_func_gn(ffi_cif *cif __UNUSED__, void *rval, void **avals, + void *data __UNUSED__) +{ + signed char a1, a2; + + a1 = *(signed char *)avals[0]; + a2 = *(signed char *)avals[1]; + + *(ffi_arg *)rval = test_func_fn(a1, a2); + +} + +typedef signed char (*test_type)(signed char, signed char); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void * args_dbl[3]; + ffi_type * cl_arg_types[3]; + ffi_arg res_call; + signed char a, b, res_closure; + + a = 2; + b = 125; + + args_dbl[0] = &a; + args_dbl[1] = &b; + args_dbl[2] = NULL; + + cl_arg_types[0] = &ffi_type_schar; + cl_arg_types[1] = &ffi_type_schar; + cl_arg_types[2] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, + &ffi_type_schar, cl_arg_types) == FFI_OK); + + ffi_call(&cif, FFI_FN(test_func_fn), &res_call, args_dbl); + /* { dg-output "2 125: 127" } */ + printf("res: %d\n", (signed char)res_call); + /* { dg-output "\nres: 127" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code) == FFI_OK); + + res_closure = (*((test_type)code))(2, 125); + /* { dg-output "\n2 125: 127" } */ + printf("res: %d\n", res_closure); + /* { dg-output "\nres: 127" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_sshort.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_sshort.c new file mode 100644 index 0000000..4c39153 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_sshort.c @@ -0,0 +1,74 @@ +/* Area: ffi_call, closure_call + Purpose: Check passing of multiple signed short values. + Limitations: none. + PR: PR13221. + Originator: 20031129 */ + +/* { dg-do run } */ +#include "ffitest.h" + +signed short test_func_fn(signed short a1, signed short a2) +{ + signed short result; + + result = a1 + a2; + + printf("%d %d: %d\n", a1, a2, result); + + return result; + +} + +static void test_func_gn(ffi_cif *cif __UNUSED__, void *rval, void **avals, + void *data __UNUSED__) +{ + signed short a1, a2; + + a1 = *(signed short *)avals[0]; + a2 = *(signed short *)avals[1]; + + *(ffi_arg *)rval = test_func_fn(a1, a2); + +} + +typedef signed short (*test_type)(signed short, signed short); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void * args_dbl[3]; + ffi_type * cl_arg_types[3]; + ffi_arg res_call; + unsigned short a, b, res_closure; + + a = 2; + b = 32765; + + args_dbl[0] = &a; + args_dbl[1] = &b; + args_dbl[2] = NULL; + + cl_arg_types[0] = &ffi_type_sshort; + cl_arg_types[1] = &ffi_type_sshort; + cl_arg_types[2] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, + &ffi_type_sshort, cl_arg_types) == FFI_OK); + + ffi_call(&cif, FFI_FN(test_func_fn), &res_call, args_dbl); + /* { dg-output "2 32765: 32767" } */ + printf("res: %d\n", (unsigned short)res_call); + /* { dg-output "\nres: 32767" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code) == FFI_OK); + + res_closure = (*((test_type)code))(2, 32765); + /* { dg-output "\n2 32765: 32767" } */ + printf("res: %d\n", res_closure); + /* { dg-output "\nres: 32767" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_sshortchar.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_sshortchar.c new file mode 100644 index 0000000..1c3aeb5 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_sshortchar.c @@ -0,0 +1,86 @@ +/* Area: ffi_call, closure_call + Purpose: Check passing of multiple signed short/char values. + Limitations: none. + PR: PR13221. + Originator: 20031129 */ + +/* { dg-do run } */ +#include "ffitest.h" + +signed short test_func_fn(signed char a1, signed short a2, + signed char a3, signed short a4) +{ + signed short result; + + result = a1 + a2 + a3 + a4; + + printf("%d %d %d %d: %d\n", a1, a2, a3, a4, result); + + return result; + +} + +static void test_func_gn(ffi_cif *cif __UNUSED__, void *rval, void **avals, + void *data __UNUSED__) +{ + signed char a1, a3; + signed short a2, a4; + + a1 = *(signed char *)avals[0]; + a2 = *(signed short *)avals[1]; + a3 = *(signed char *)avals[2]; + a4 = *(signed short *)avals[3]; + + *(ffi_arg *)rval = test_func_fn(a1, a2, a3, a4); + +} + +typedef signed short (*test_type)(signed char, signed short, + signed char, signed short); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void * args_dbl[5]; + ffi_type * cl_arg_types[5]; + ffi_arg res_call; + signed char a, c; + signed short b, d, res_closure; + + a = 1; + b = 32765; + c = 127; + d = -128; + + args_dbl[0] = &a; + args_dbl[1] = &b; + args_dbl[2] = &c; + args_dbl[3] = &d; + args_dbl[4] = NULL; + + cl_arg_types[0] = &ffi_type_schar; + cl_arg_types[1] = &ffi_type_sshort; + cl_arg_types[2] = &ffi_type_schar; + cl_arg_types[3] = &ffi_type_sshort; + cl_arg_types[4] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, + &ffi_type_sshort, cl_arg_types) == FFI_OK); + + ffi_call(&cif, FFI_FN(test_func_fn), &res_call, args_dbl); + /* { dg-output "1 32765 127 -128: 32765" } */ + printf("res: %d\n", (signed short)res_call); + /* { dg-output "\nres: 32765" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code) == FFI_OK); + + res_closure = (*((test_type)code))(1, 32765, 127, -128); + /* { dg-output "\n1 32765 127 -128: 32765" } */ + printf("res: %d\n", res_closure); + /* { dg-output "\nres: 32765" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_uchar.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_uchar.c new file mode 100644 index 0000000..009c02c --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_uchar.c @@ -0,0 +1,91 @@ +/* Area: ffi_call, closure_call + Purpose: Check passing of multiple unsigned char values. + Limitations: none. + PR: PR13221. + Originator: 20031129 */ + +/* { dg-do run } */ +#include "ffitest.h" + +unsigned char test_func_fn(unsigned char a1, unsigned char a2, + unsigned char a3, unsigned char a4) +{ + unsigned char result; + + result = a1 + a2 + a3 + a4; + + printf("%d %d %d %d: %d\n", a1, a2, a3, a4, result); + + return result; + +} + +static void test_func_gn(ffi_cif *cif __UNUSED__, void *rval, void **avals, + void *data __UNUSED__) +{ + unsigned char a1, a2, a3, a4; + + a1 = *(unsigned char *)avals[0]; + a2 = *(unsigned char *)avals[1]; + a3 = *(unsigned char *)avals[2]; + a4 = *(unsigned char *)avals[3]; + + *(ffi_arg *)rval = test_func_fn(a1, a2, a3, a4); + +} + +typedef unsigned char (*test_type)(unsigned char, unsigned char, + unsigned char, unsigned char); + +void test_func(ffi_cif *cif __UNUSED__, void *rval __UNUSED__, void **avals, + void *data __UNUSED__) +{ + printf("%d %d %d %d\n", *(unsigned char *)avals[0], + *(unsigned char *)avals[1], *(unsigned char *)avals[2], + *(unsigned char *)avals[3]); +} +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void * args_dbl[5]; + ffi_type * cl_arg_types[5]; + ffi_arg res_call; + unsigned char a, b, c, d, res_closure; + + a = 1; + b = 2; + c = 127; + d = 125; + + args_dbl[0] = &a; + args_dbl[1] = &b; + args_dbl[2] = &c; + args_dbl[3] = &d; + args_dbl[4] = NULL; + + cl_arg_types[0] = &ffi_type_uchar; + cl_arg_types[1] = &ffi_type_uchar; + cl_arg_types[2] = &ffi_type_uchar; + cl_arg_types[3] = &ffi_type_uchar; + cl_arg_types[4] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, + &ffi_type_uchar, cl_arg_types) == FFI_OK); + + ffi_call(&cif, FFI_FN(test_func_fn), &res_call, args_dbl); + /* { dg-output "1 2 127 125: 255" } */ + printf("res: %d\n", (unsigned char)res_call); + /* { dg-output "\nres: 255" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code) == FFI_OK); + + res_closure = (*((test_type)code))(1, 2, 127, 125); + /* { dg-output "\n1 2 127 125: 255" } */ + printf("res: %d\n", res_closure); + /* { dg-output "\nres: 255" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_ushort.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_ushort.c new file mode 100644 index 0000000..dd10ca7 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_ushort.c @@ -0,0 +1,74 @@ +/* Area: ffi_call, closure_call + Purpose: Check passing of multiple unsigned short values. + Limitations: none. + PR: PR13221. + Originator: 20031129 */ + +/* { dg-do run } */ +#include "ffitest.h" + +unsigned short test_func_fn(unsigned short a1, unsigned short a2) +{ + unsigned short result; + + result = a1 + a2; + + printf("%d %d: %d\n", a1, a2, result); + + return result; + +} + +static void test_func_gn(ffi_cif *cif __UNUSED__, void *rval, void **avals, + void *data __UNUSED__) +{ + unsigned short a1, a2; + + a1 = *(unsigned short *)avals[0]; + a2 = *(unsigned short *)avals[1]; + + *(ffi_arg *)rval = test_func_fn(a1, a2); + +} + +typedef unsigned short (*test_type)(unsigned short, unsigned short); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void * args_dbl[3]; + ffi_type * cl_arg_types[3]; + ffi_arg res_call; + unsigned short a, b, res_closure; + + a = 2; + b = 32765; + + args_dbl[0] = &a; + args_dbl[1] = &b; + args_dbl[2] = NULL; + + cl_arg_types[0] = &ffi_type_ushort; + cl_arg_types[1] = &ffi_type_ushort; + cl_arg_types[2] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, + &ffi_type_ushort, cl_arg_types) == FFI_OK); + + ffi_call(&cif, FFI_FN(test_func_fn), &res_call, args_dbl); + /* { dg-output "2 32765: 32767" } */ + printf("res: %d\n", (unsigned short)res_call); + /* { dg-output "\nres: 32767" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code) == FFI_OK); + + res_closure = (*((test_type)code))(2, 32765); + /* { dg-output "\n2 32765: 32767" } */ + printf("res: %d\n", res_closure); + /* { dg-output "\nres: 32767" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_ushortchar.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_ushortchar.c new file mode 100644 index 0000000..2588e97 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_multi_ushortchar.c @@ -0,0 +1,86 @@ +/* Area: ffi_call, closure_call + Purpose: Check passing of multiple unsigned short/char values. + Limitations: none. + PR: PR13221. + Originator: 20031129 */ + +/* { dg-do run } */ +#include "ffitest.h" + +unsigned short test_func_fn(unsigned char a1, unsigned short a2, + unsigned char a3, unsigned short a4) +{ + unsigned short result; + + result = a1 + a2 + a3 + a4; + + printf("%d %d %d %d: %d\n", a1, a2, a3, a4, result); + + return result; + +} + +static void test_func_gn(ffi_cif *cif __UNUSED__, void *rval, void **avals, + void *data __UNUSED__) +{ + unsigned char a1, a3; + unsigned short a2, a4; + + a1 = *(unsigned char *)avals[0]; + a2 = *(unsigned short *)avals[1]; + a3 = *(unsigned char *)avals[2]; + a4 = *(unsigned short *)avals[3]; + + *(ffi_arg *)rval = test_func_fn(a1, a2, a3, a4); + +} + +typedef unsigned short (*test_type)(unsigned char, unsigned short, + unsigned char, unsigned short); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void * args_dbl[5]; + ffi_type * cl_arg_types[5]; + ffi_arg res_call; + unsigned char a, c; + unsigned short b, d, res_closure; + + a = 1; + b = 2; + c = 127; + d = 128; + + args_dbl[0] = &a; + args_dbl[1] = &b; + args_dbl[2] = &c; + args_dbl[3] = &d; + args_dbl[4] = NULL; + + cl_arg_types[0] = &ffi_type_uchar; + cl_arg_types[1] = &ffi_type_ushort; + cl_arg_types[2] = &ffi_type_uchar; + cl_arg_types[3] = &ffi_type_ushort; + cl_arg_types[4] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, + &ffi_type_ushort, cl_arg_types) == FFI_OK); + + ffi_call(&cif, FFI_FN(test_func_fn), &res_call, args_dbl); + /* { dg-output "1 2 127 128: 258" } */ + printf("res: %d\n", (unsigned short)res_call); + /* { dg-output "\nres: 258" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, test_func_gn, NULL, code) == FFI_OK); + + res_closure = (*((test_type)code))(1, 2, 127, 128); + /* { dg-output "\n1 2 127 128: 258" } */ + printf("res: %d\n", res_closure); + /* { dg-output "\nres: 258" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_pointer.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_pointer.c new file mode 100644 index 0000000..fadd353 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_pointer.c @@ -0,0 +1,74 @@ +/* Area: ffi_call, closure_call + Purpose: Check pointer arguments. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/6/2007 */ + +/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ +#include "ffitest.h" + +void* cls_pointer_fn(void* a1, void* a2) +{ + void* result = (void*)((intptr_t)a1 + (intptr_t)a2); + + printf("0x%08x 0x%08x: 0x%08x\n", + (unsigned int)(uintptr_t) a1, + (unsigned int)(uintptr_t) a2, + (unsigned int)(uintptr_t) result); + + return result; +} + +static void +cls_pointer_gn(ffi_cif* cif __UNUSED__, void* resp, + void** args, void* userdata __UNUSED__) +{ + void* a1 = *(void**)(args[0]); + void* a2 = *(void**)(args[1]); + + *(void**)resp = cls_pointer_fn(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure* pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args[3]; +// ffi_type cls_pointer_type; + ffi_type* arg_types[3]; + +/* cls_pointer_type.size = sizeof(void*); + cls_pointer_type.alignment = 0; + cls_pointer_type.type = FFI_TYPE_POINTER; + cls_pointer_type.elements = NULL;*/ + + void* arg1 = (void*)0x12345678; + void* arg2 = (void*)0x89abcdef; + ffi_arg res = 0; + + arg_types[0] = &ffi_type_pointer; + arg_types[1] = &ffi_type_pointer; + arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_pointer, + arg_types) == FFI_OK); + + args[0] = &arg1; + args[1] = &arg2; + args[2] = NULL; + + ffi_call(&cif, FFI_FN(cls_pointer_fn), &res, args); + /* { dg-output "0x12345678 0x89abcdef: 0x9be02467" } */ + printf("res: 0x%08x\n", (unsigned int) res); + /* { dg-output "\nres: 0x9be02467" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_pointer_gn, NULL, code) == FFI_OK); + + res = (ffi_arg)((void*(*)(void*, void*))(code))(arg1, arg2); + /* { dg-output "\n0x12345678 0x89abcdef: 0x9be02467" } */ + printf("res: 0x%08x\n", (unsigned int) res); + /* { dg-output "\nres: 0x9be02467" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_pointer_stack.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_pointer_stack.c new file mode 100644 index 0000000..697f271 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_pointer_stack.c @@ -0,0 +1,140 @@ +/* Area: ffi_call, closure_call + Purpose: Check pointer arguments across multiple hideous stack frames. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/7/2007 */ + +/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ +#include "ffitest.h" + +static long dummyVar; + +long dummy_func( + long double a1, char b1, + long double a2, char b2, + long double a3, char b3, + long double a4, char b4) +{ + return a1 + b1 + a2 + b2 + a3 + b3 + a4 + b4; +} + +void* cls_pointer_fn2(void* a1, void* a2) +{ + long double trample1 = (intptr_t)a1 + (intptr_t)a2; + char trample2 = ((char*)&a1)[0] + ((char*)&a2)[0]; + long double trample3 = (intptr_t)trample1 + (intptr_t)a1; + char trample4 = trample2 + ((char*)&a1)[1]; + long double trample5 = (intptr_t)trample3 + (intptr_t)a2; + char trample6 = trample4 + ((char*)&a2)[1]; + long double trample7 = (intptr_t)trample5 + (intptr_t)trample1; + char trample8 = trample6 + trample2; + + dummyVar = dummy_func(trample1, trample2, trample3, trample4, + trample5, trample6, trample7, trample8); + + void* result = (void*)((intptr_t)a1 + (intptr_t)a2); + + printf("0x%08x 0x%08x: 0x%08x\n", + (unsigned int)(uintptr_t) a1, + (unsigned int)(uintptr_t) a2, + (unsigned int)(uintptr_t) result); + + return result; +} + +void* cls_pointer_fn1(void* a1, void* a2) +{ + long double trample1 = (intptr_t)a1 + (intptr_t)a2; + char trample2 = ((char*)&a1)[0] + ((char*)&a2)[0]; + long double trample3 = (intptr_t)trample1 + (intptr_t)a1; + char trample4 = trample2 + ((char*)&a1)[1]; + long double trample5 = (intptr_t)trample3 + (intptr_t)a2; + char trample6 = trample4 + ((char*)&a2)[1]; + long double trample7 = (intptr_t)trample5 + (intptr_t)trample1; + char trample8 = trample6 + trample2; + + dummyVar = dummy_func(trample1, trample2, trample3, trample4, + trample5, trample6, trample7, trample8); + + void* result = (void*)((intptr_t)a1 + (intptr_t)a2); + + printf("0x%08x 0x%08x: 0x%08x\n", + (unsigned int)(intptr_t) a1, + (unsigned int)(intptr_t) a2, + (unsigned int)(intptr_t) result); + + result = cls_pointer_fn2(result, a1); + + return result; +} + +static void +cls_pointer_gn(ffi_cif* cif __UNUSED__, void* resp, + void** args, void* userdata __UNUSED__) +{ + void* a1 = *(void**)(args[0]); + void* a2 = *(void**)(args[1]); + + long double trample1 = (intptr_t)a1 + (intptr_t)a2; + char trample2 = ((char*)&a1)[0] + ((char*)&a2)[0]; + long double trample3 = (intptr_t)trample1 + (intptr_t)a1; + char trample4 = trample2 + ((char*)&a1)[1]; + long double trample5 = (intptr_t)trample3 + (intptr_t)a2; + char trample6 = trample4 + ((char*)&a2)[1]; + long double trample7 = (intptr_t)trample5 + (intptr_t)trample1; + char trample8 = trample6 + trample2; + + dummyVar = dummy_func(trample1, trample2, trample3, trample4, + trample5, trample6, trample7, trample8); + + *(void**)resp = cls_pointer_fn1(a1, a2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure* pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args[3]; +// ffi_type cls_pointer_type; + ffi_type* arg_types[3]; + +/* cls_pointer_type.size = sizeof(void*); + cls_pointer_type.alignment = 0; + cls_pointer_type.type = FFI_TYPE_POINTER; + cls_pointer_type.elements = NULL;*/ + + void* arg1 = (void*)0x01234567; + void* arg2 = (void*)0x89abcdef; + ffi_arg res = 0; + + arg_types[0] = &ffi_type_pointer; + arg_types[1] = &ffi_type_pointer; + arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_pointer, + arg_types) == FFI_OK); + + args[0] = &arg1; + args[1] = &arg2; + args[2] = NULL; + + printf("\n"); + ffi_call(&cif, FFI_FN(cls_pointer_fn1), &res, args); + + printf("res: 0x%08x\n", (unsigned int) res); + // { dg-output "\n0x01234567 0x89abcdef: 0x8acf1356" } + // { dg-output "\n0x8acf1356 0x01234567: 0x8bf258bd" } + // { dg-output "\nres: 0x8bf258bd" } + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_pointer_gn, NULL, code) == FFI_OK); + + res = (ffi_arg)((void*(*)(void*, void*))(code))(arg1, arg2); + + printf("res: 0x%08x\n", (unsigned int) res); + // { dg-output "\n0x01234567 0x89abcdef: 0x8acf1356" } + // { dg-output "\n0x8acf1356 0x01234567: 0x8bf258bd" } + // { dg-output "\nres: 0x8bf258bd" } + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_schar.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_schar.c new file mode 100644 index 0000000..82986b1 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_schar.c @@ -0,0 +1,44 @@ +/* Area: closure_call + Purpose: Check return value schar. + Limitations: none. + PR: none. + Originator: 20031108 */ + + + +/* { dg-do run } */ +#include "ffitest.h" + +static void cls_ret_schar_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + *(ffi_arg*)resp = *(signed char *)args[0]; + printf("%d: %d\n",*(signed char *)args[0], + (int)*(ffi_arg *)(resp)); +} +typedef signed char (*cls_ret_schar)(signed char); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[2]; + signed char res; + + cl_arg_types[0] = &ffi_type_schar; + cl_arg_types[1] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_schar, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_schar_fn, NULL, code) == FFI_OK); + + res = (*((cls_ret_schar)code))(127); + /* { dg-output "127: 127" } */ + printf("res: %d\n", res); + /* { dg-output "\nres: 127" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_sint.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_sint.c new file mode 100644 index 0000000..c7e13b7 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_sint.c @@ -0,0 +1,42 @@ +/* Area: closure_call + Purpose: Check return value sint32. + Limitations: none. + PR: none. + Originator: 20031108 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static void cls_ret_sint_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + *(ffi_arg*)resp = *(signed int *)args[0]; + printf("%d: %d\n",*(signed int *)args[0], + (int)*(ffi_arg *)(resp)); +} +typedef signed int (*cls_ret_sint)(signed int); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[2]; + signed int res; + + cl_arg_types[0] = &ffi_type_sint; + cl_arg_types[1] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_sint, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_sint_fn, NULL, code) == FFI_OK); + + res = (*((cls_ret_sint)code))(65534); + /* { dg-output "65534: 65534" } */ + printf("res: %d\n",res); + /* { dg-output "\nres: 65534" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_sshort.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_sshort.c new file mode 100644 index 0000000..846d57e --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_sshort.c @@ -0,0 +1,42 @@ +/* Area: closure_call + Purpose: Check return value sshort. + Limitations: none. + PR: none. + Originator: 20031108 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static void cls_ret_sshort_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + *(ffi_arg*)resp = *(signed short *)args[0]; + printf("%d: %d\n",*(signed short *)args[0], + (int)*(ffi_arg *)(resp)); +} +typedef signed short (*cls_ret_sshort)(signed short); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[2]; + signed short res; + + cl_arg_types[0] = &ffi_type_sshort; + cl_arg_types[1] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_sshort, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_sshort_fn, NULL, code) == FFI_OK); + + res = (*((cls_ret_sshort)code))(255); + /* { dg-output "255: 255" } */ + printf("res: %d\n",res); + /* { dg-output "\nres: 255" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_uchar.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_uchar.c new file mode 100644 index 0000000..c1317e7 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_uchar.c @@ -0,0 +1,42 @@ +/* Area: closure_call + Purpose: Check return value uchar. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static void cls_ret_uchar_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + *(ffi_arg*)resp = *(unsigned char *)args[0]; + printf("%d: %d\n",*(unsigned char *)args[0], + (int)*(ffi_arg *)(resp)); +} +typedef unsigned char (*cls_ret_uchar)(unsigned char); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[2]; + unsigned char res; + + cl_arg_types[0] = &ffi_type_uchar; + cl_arg_types[1] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_uchar, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_uchar_fn, NULL, code) == FFI_OK); + + res = (*((cls_ret_uchar)code))(127); + /* { dg-output "127: 127" } */ + printf("res: %d\n",res); + /* { dg-output "\nres: 127" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_uint.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_uint.c new file mode 100644 index 0000000..885cff5 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_uint.c @@ -0,0 +1,43 @@ +/* Area: closure_call + Purpose: Check return value uint. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static void cls_ret_uint_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + *(ffi_arg *)resp = *(unsigned int *)args[0]; + + printf("%d: %d\n",*(unsigned int *)args[0], + (int)*(ffi_arg *)(resp)); +} +typedef unsigned int (*cls_ret_uint)(unsigned int); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[2]; + unsigned int res; + + cl_arg_types[0] = &ffi_type_uint; + cl_arg_types[1] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_uint, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_uint_fn, NULL, code) == FFI_OK); + + res = (*((cls_ret_uint)code))(2147483647); + /* { dg-output "2147483647: 2147483647" } */ + printf("res: %d\n",res); + /* { dg-output "\nres: 2147483647" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_ulonglong.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_ulonglong.c new file mode 100644 index 0000000..235ab44 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_ulonglong.c @@ -0,0 +1,47 @@ +/* Area: closure_call + Purpose: Check return value long long. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +/* { dg-options "-Wno-format" { target alpha*-dec-osf* } } */ +#include "ffitest.h" + +static void cls_ret_ulonglong_fn(ffi_cif* cif __UNUSED__, void* resp, + void** args, void* userdata __UNUSED__) +{ + *(unsigned long long *)resp= *(unsigned long long *)args[0]; + + printf("%" PRIuLL ": %" PRIuLL "\n",*(unsigned long long *)args[0], + *(unsigned long long *)(resp)); +} +typedef unsigned long long (*cls_ret_ulonglong)(unsigned long long); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[2]; + unsigned long long res; + + cl_arg_types[0] = &ffi_type_uint64; + cl_arg_types[1] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_uint64, cl_arg_types) == FFI_OK); + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_ulonglong_fn, NULL, code) == FFI_OK); + res = (*((cls_ret_ulonglong)code))(214LL); + /* { dg-output "214: 214" } */ + printf("res: %" PRIdLL "\n", res); + /* { dg-output "\nres: 214" } */ + + res = (*((cls_ret_ulonglong)code))(9223372035854775808LL); + /* { dg-output "\n9223372035854775808: 9223372035854775808" } */ + printf("res: %" PRIdLL "\n", res); + /* { dg-output "\nres: 9223372035854775808" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/cls_ushort.c b/js/src/ctypes/libffi/testsuite/libffi.call/cls_ushort.c new file mode 100644 index 0000000..a00100e --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/cls_ushort.c @@ -0,0 +1,43 @@ +/* Area: closure_call + Purpose: Check return value ushort. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static void cls_ret_ushort_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + *(ffi_arg*)resp = *(unsigned short *)args[0]; + + printf("%d: %d\n",*(unsigned short *)args[0], + (int)*(ffi_arg *)(resp)); +} +typedef unsigned short (*cls_ret_ushort)(unsigned short); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[2]; + unsigned short res; + + cl_arg_types[0] = &ffi_type_ushort; + cl_arg_types[1] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_ushort, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_ushort_fn, NULL, code) == FFI_OK); + + res = (*((cls_ret_ushort)code))(65535); + /* { dg-output "65535: 65535" } */ + printf("res: %d\n",res); + /* { dg-output "\nres: 65535" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/err_bad_abi.c b/js/src/ctypes/libffi/testsuite/libffi.call/err_bad_abi.c new file mode 100644 index 0000000..ce0f3bb --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/err_bad_abi.c @@ -0,0 +1,35 @@ +/* Area: ffi_prep_cif, ffi_prep_closure + Purpose: Test error return for bad ABIs. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/6/2007 */ + +/* { dg-do run { xfail *-*-* } } */ +#include "ffitest.h" + +static void +dummy_fn(ffi_cif* cif __UNUSED__, void* resp __UNUSED__, + void** args __UNUSED__, void* userdata __UNUSED__) +{} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type* arg_types[1]; + + arg_types[0] = NULL; + + CHECK(ffi_prep_cif(&cif, 255, 0, &ffi_type_void, + arg_types) == FFI_BAD_ABI); + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, &ffi_type_void, + arg_types) == FFI_OK); + + cif.abi= 255; + + CHECK(ffi_prep_closure_loc(pcl, &cif, dummy_fn, NULL, code) == FFI_BAD_ABI); + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/err_bad_typedef.c b/js/src/ctypes/libffi/testsuite/libffi.call/err_bad_typedef.c new file mode 100644 index 0000000..bd2fc54 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/err_bad_typedef.c @@ -0,0 +1,25 @@ +/* Area: ffi_prep_cif + Purpose: Test error return for bad typedefs. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/6/2007 */ + +/* { dg-do run { xfail *-*-* } } */ +#include "ffitest.h" + +int main (void) +{ + ffi_cif cif; + ffi_type* arg_types[1]; + + arg_types[0] = NULL; + + ffi_type badType = ffi_type_void; + + badType.size = 0; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, &badType, + arg_types) == FFI_BAD_TYPEDEF); + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/ffitest.h b/js/src/ctypes/libffi/testsuite/libffi.call/ffitest.h new file mode 100644 index 0000000..2cb9849 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/ffitest.h @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include "fficonfig.h" + +#if defined HAVE_STDINT_H +#include +#endif + +#if defined HAVE_INTTYPES_H +#include +#endif + +#define MAX_ARGS 256 + +#define CHECK(x) !(x) ? abort() : 0 + +/* Define __UNUSED__ that also other compilers than gcc can run the tests. */ +#undef __UNUSED__ +#if defined(__GNUC__) +#define __UNUSED__ __attribute__((__unused__)) +#else +#define __UNUSED__ +#endif + +/* Prefer MAP_ANON(YMOUS) to /dev/zero, since we don't need to keep a + file open. */ +#ifdef HAVE_MMAP_ANON +# undef HAVE_MMAP_DEV_ZERO + +# include +# ifndef MAP_FAILED +# define MAP_FAILED -1 +# endif +# if !defined (MAP_ANONYMOUS) && defined (MAP_ANON) +# define MAP_ANONYMOUS MAP_ANON +# endif +# define USING_MMAP + +#endif + +#ifdef HAVE_MMAP_DEV_ZERO + +# include +# ifndef MAP_FAILED +# define MAP_FAILED -1 +# endif +# define USING_MMAP + +#endif + +/* MinGW kludge. */ +#ifdef _WIN64 +#define PRIdLL "I64d" +#define PRIuLL "I64u" +#else +#define PRIdLL "lld" +#define PRIuLL "llu" +#endif + +/* Tru64 UNIX kludge. */ +#if defined(__alpha__) && defined(__osf__) +/* Tru64 UNIX V4.0 doesn't support %lld/%lld, but long is 64-bit. */ +#undef PRIdLL +#define PRIdLL "ld" +#undef PRIuLL +#define PRIuLL "lu" +#define PRId64 "ld" +#define PRIu64 "lu" +#define PRIuPTR "lu" +#endif + +/* PA HP-UX kludge. */ +#if defined(__hppa__) && defined(__hpux__) && !defined(PRIuPTR) +#define PRIuPTR "lu" +#endif + +/* Solaris < 10 kludge. */ +#if defined(__sun__) && defined(__svr4__) && !defined(PRIuPTR) +#if defined(__arch64__) || defined (__x86_64__) +#define PRIuPTR "lu" +#else +#define PRIuPTR "u" +#endif +#endif + +#ifdef USING_MMAP +static inline void * +allocate_mmap (size_t size) +{ + void *page; +#if defined (HAVE_MMAP_DEV_ZERO) + static int dev_zero_fd = -1; +#endif + +#ifdef HAVE_MMAP_DEV_ZERO + if (dev_zero_fd == -1) + { + dev_zero_fd = open ("/dev/zero", O_RDONLY); + if (dev_zero_fd == -1) + { + perror ("open /dev/zero: %m"); + exit (1); + } + } +#endif + + +#ifdef HAVE_MMAP_ANON + page = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +#endif +#ifdef HAVE_MMAP_DEV_ZERO + page = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE, dev_zero_fd, 0); +#endif + + if (page == (void *) MAP_FAILED) + { + perror ("virtual memory exhausted"); + exit (1); + } + + return page; +} + +#endif diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/float.c b/js/src/ctypes/libffi/testsuite/libffi.call/float.c new file mode 100644 index 0000000..fbc272d --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/float.c @@ -0,0 +1,59 @@ +/* Area: ffi_call + Purpose: Check return value float. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ + +#include "ffitest.h" + +static int floating(int a, float b, double c, long double d) +{ + int i; + + i = (int) ((float)a/b + ((float)c/(float)d)); + + return i; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_arg rint; + + float f; + signed int si1; + double d; + long double ld; + + args[0] = &ffi_type_sint; + values[0] = &si1; + args[1] = &ffi_type_float; + values[1] = &f; + args[2] = &ffi_type_double; + values[2] = &d; + args[3] = &ffi_type_longdouble; + values[3] = &ld; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, + &ffi_type_sint, args) == FFI_OK); + + si1 = 6; + f = 3.14159; + d = (double)1.0/(double)3.0; + ld = 2.71828182846L; + + floating (si1, f, d, ld); + + ffi_call(&cif, FFI_FN(floating), &rint, values); + + printf ("%d vs %d\n", (int)rint, floating (si1, f, d, ld)); + + CHECK((int)rint == floating(si1, f, d, ld)); + + exit (0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/float1.c b/js/src/ctypes/libffi/testsuite/libffi.call/float1.c new file mode 100644 index 0000000..991d059 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/float1.c @@ -0,0 +1,58 @@ +/* Area: ffi_call + Purpose: Check return value double. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" +#include "float.h" + +typedef union +{ + double d; + unsigned char c[sizeof (double)]; +} value_type; + +#define CANARY 0xba + +static double dblit(float f) +{ + return f/3.0; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + float f; + value_type result[2]; + unsigned int i; + + args[0] = &ffi_type_float; + values[0] = &f; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_double, args) == FFI_OK); + + f = 3.14159; + + /* Put a canary in the return array. This is a regression test for + a buffer overrun. */ + memset(result[1].c, CANARY, sizeof (double)); + + ffi_call(&cif, FFI_FN(dblit), &result[0].d, values); + + /* These are not always the same!! Check for a reasonable delta */ + + CHECK(result[0].d - dblit(f) < DBL_EPSILON); + + /* Check the canary. */ + for (i = 0; i < sizeof (double); ++i) + CHECK(result[1].c[i] == CANARY); + + exit(0); + +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/float2.c b/js/src/ctypes/libffi/testsuite/libffi.call/float2.c new file mode 100644 index 0000000..a0b296c --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/float2.c @@ -0,0 +1,58 @@ +/* Area: ffi_call + Purpose: Check return value long double. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-excess-errors "fails" { target x86_64-*-mingw* x86_64-*-cygwin* } } */ +/* { dg-do run { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ + +#include "ffitest.h" +#include "float.h" + +static long double ldblit(float f) +{ + return (long double) (((long double) f)/ (long double) 3.0); +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + float f; + long double ld; + + args[0] = &ffi_type_float; + values[0] = &f; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_longdouble, args) == FFI_OK); + + f = 3.14159; + +#if 1 + /* This is ifdef'd out for now. long double support under SunOS/gcc + is pretty much non-existent. You'll get the odd bus error in library + routines like printf(). */ + printf ("%Lf\n", ldblit(f)); +#endif + ld = 666; + ffi_call(&cif, FFI_FN(ldblit), &ld, values); + +#if 1 + /* This is ifdef'd out for now. long double support under SunOS/gcc + is pretty much non-existent. You'll get the odd bus error in library + routines like printf(). */ + printf ("%Lf, %Lf, %Lf, %Lf\n", ld, ldblit(f), ld - ldblit(f), LDBL_EPSILON); +#endif + + /* These are not always the same!! Check for a reasonable delta */ + if (ld - ldblit(f) < LDBL_EPSILON) + puts("long double return value tests ok!"); + else + CHECK(0); + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/float3.c b/js/src/ctypes/libffi/testsuite/libffi.call/float3.c new file mode 100644 index 0000000..76bd5f2 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/float3.c @@ -0,0 +1,72 @@ +/* Area: ffi_call + Purpose: Check float arguments with different orders. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ + +#include "ffitest.h" +#include "float.h" + +static double floating_1(float a, double b, long double c) +{ + return (double) a + b + (double) c; +} + +static double floating_2(long double a, double b, float c) +{ + return (double) a + b + (double) c; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + double rd; + + float f; + double d; + long double ld; + + args[0] = &ffi_type_float; + values[0] = &f; + args[1] = &ffi_type_double; + values[1] = &d; + args[2] = &ffi_type_longdouble; + values[2] = &ld; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, + &ffi_type_double, args) == FFI_OK); + + f = 3.14159; + d = (double)1.0/(double)3.0; + ld = 2.71828182846L; + + floating_1 (f, d, ld); + + ffi_call(&cif, FFI_FN(floating_1), &rd, values); + + CHECK(rd - floating_1(f, d, ld) < DBL_EPSILON); + + args[0] = &ffi_type_longdouble; + values[0] = &ld; + args[1] = &ffi_type_double; + values[1] = &d; + args[2] = &ffi_type_float; + values[2] = &f; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, + &ffi_type_double, args) == FFI_OK); + + floating_2 (ld, d, f); + + ffi_call(&cif, FFI_FN(floating_2), &rd, values); + + CHECK(rd - floating_2(ld, d, f) < DBL_EPSILON); + + exit (0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/float4.c b/js/src/ctypes/libffi/testsuite/libffi.call/float4.c new file mode 100644 index 0000000..0dd6d85 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/float4.c @@ -0,0 +1,62 @@ +/* Area: ffi_call + Purpose: Check denorm double value. + Limitations: none. + PR: PR26483. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +/* { dg-options "-mieee" { target alpha*-*-* } } */ + +#include "ffitest.h" +#include "float.h" + +typedef union +{ + double d; + unsigned char c[sizeof (double)]; +} value_type; + +#define CANARY 0xba + +static double dblit(double d) +{ + return d; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + double d; + value_type result[2]; + unsigned int i; + + args[0] = &ffi_type_double; + values[0] = &d; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_double, args) == FFI_OK); + + d = DBL_MIN / 2; + + /* Put a canary in the return array. This is a regression test for + a buffer overrun. */ + memset(result[1].c, CANARY, sizeof (double)); + + ffi_call(&cif, FFI_FN(dblit), &result[0].d, values); + + /* The standard delta check doesn't work for denorms. Since we didn't do + any arithmetic, we should get the original result back, and hence an + exact check should be OK here. */ + + CHECK(result[0].d == dblit(d)); + + /* Check the canary. */ + for (i = 0; i < sizeof (double); ++i) + CHECK(result[1].c[i] == CANARY); + + exit(0); + +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/huge_struct.c b/js/src/ctypes/libffi/testsuite/libffi.call/huge_struct.c new file mode 100644 index 0000000..9cffb71 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/huge_struct.c @@ -0,0 +1,342 @@ +/* Area: ffi_call, closure_call + Purpose: Check large structure returns. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/18/2007 +*/ + +/* { dg-excess-errors "" { target x86_64-*-mingw* x86_64-*-cygwin* } } */ +/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ +/* { dg-options -mlong-double-128 { target powerpc64*-*-* } } */ +/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ + +#include "ffitest.h" + +typedef struct BigStruct{ + uint8_t a; + int8_t b; + uint16_t c; + int16_t d; + uint32_t e; + int32_t f; + uint64_t g; + int64_t h; + float i; + double j; + long double k; + char* l; + uint8_t m; + int8_t n; + uint16_t o; + int16_t p; + uint32_t q; + int32_t r; + uint64_t s; + int64_t t; + float u; + double v; + long double w; + char* x; + uint8_t y; + int8_t z; + uint16_t aa; + int16_t bb; + uint32_t cc; + int32_t dd; + uint64_t ee; + int64_t ff; + float gg; + double hh; + long double ii; + char* jj; + uint8_t kk; + int8_t ll; + uint16_t mm; + int16_t nn; + uint32_t oo; + int32_t pp; + uint64_t qq; + int64_t rr; + float ss; + double tt; + long double uu; + char* vv; + uint8_t ww; + int8_t xx; +} BigStruct; + +BigStruct +test_large_fn( + uint8_t ui8_1, + int8_t si8_1, + uint16_t ui16_1, + int16_t si16_1, + uint32_t ui32_1, + int32_t si32_1, + uint64_t ui64_1, + int64_t si64_1, + float f_1, + double d_1, + long double ld_1, + char* p_1, + uint8_t ui8_2, + int8_t si8_2, + uint16_t ui16_2, + int16_t si16_2, + uint32_t ui32_2, + int32_t si32_2, + uint64_t ui64_2, + int64_t si64_2, + float f_2, + double d_2, + long double ld_2, + char* p_2, + uint8_t ui8_3, + int8_t si8_3, + uint16_t ui16_3, + int16_t si16_3, + uint32_t ui32_3, + int32_t si32_3, + uint64_t ui64_3, + int64_t si64_3, + float f_3, + double d_3, + long double ld_3, + char* p_3, + uint8_t ui8_4, + int8_t si8_4, + uint16_t ui16_4, + int16_t si16_4, + uint32_t ui32_4, + int32_t si32_4, + uint64_t ui64_4, + int64_t si64_4, + float f_4, + double d_4, + long double ld_4, + char* p_4, + uint8_t ui8_5, + int8_t si8_5) +{ + BigStruct retVal = { + ui8_1 + 1, si8_1 + 1, ui16_1 + 1, si16_1 + 1, ui32_1 + 1, si32_1 + 1, + ui64_1 + 1, si64_1 + 1, f_1 + 1, d_1 + 1, ld_1 + 1, (char*)((intptr_t)p_1 + 1), + ui8_2 + 2, si8_2 + 2, ui16_2 + 2, si16_2 + 2, ui32_2 + 2, si32_2 + 2, + ui64_2 + 2, si64_2 + 2, f_2 + 2, d_2 + 2, ld_2 + 2, (char*)((intptr_t)p_2 + 2), + ui8_3 + 3, si8_3 + 3, ui16_3 + 3, si16_3 + 3, ui32_3 + 3, si32_3 + 3, + ui64_3 + 3, si64_3 + 3, f_3 + 3, d_3 + 3, ld_3 + 3, (char*)((intptr_t)p_3 + 3), + ui8_4 + 4, si8_4 + 4, ui16_4 + 4, si16_4 + 4, ui32_4 + 4, si32_4 + 4, + ui64_4 + 4, si64_4 + 4, f_4 + 4, d_4 + 4, ld_4 + 4, (char*)((intptr_t)p_4 + 4), + ui8_5 + 5, si8_5 + 5}; + + printf("%hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " + "%hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " + "%hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " + "%hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx %hhu %hhd: " + "%hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " + "%hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " + "%hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " + "%hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx %hhu %hhd\n", + ui8_1, si8_1, ui16_1, si16_1, ui32_1, si32_1, ui64_1, si64_1, f_1, d_1, ld_1, (unsigned long)p_1, + ui8_2, si8_2, ui16_2, si16_2, ui32_2, si32_2, ui64_2, si64_2, f_2, d_2, ld_2, (unsigned long)p_2, + ui8_3, si8_3, ui16_3, si16_3, ui32_3, si32_3, ui64_3, si64_3, f_3, d_3, ld_3, (unsigned long)p_3, + ui8_4, si8_4, ui16_4, si16_4, ui32_4, si32_4, ui64_4, si64_4, f_4, d_4, ld_4, (unsigned long)p_4, ui8_5, si8_5, + retVal.a, retVal.b, retVal.c, retVal.d, retVal.e, retVal.f, + retVal.g, retVal.h, retVal.i, retVal.j, retVal.k, (unsigned long)retVal.l, + retVal.m, retVal.n, retVal.o, retVal.p, retVal.q, retVal.r, + retVal.s, retVal.t, retVal.u, retVal.v, retVal.w, (unsigned long)retVal.x, + retVal.y, retVal.z, retVal.aa, retVal.bb, retVal.cc, retVal.dd, + retVal.ee, retVal.ff, retVal.gg, retVal.hh, retVal.ii, (unsigned long)retVal.jj, + retVal.kk, retVal.ll, retVal.mm, retVal.nn, retVal.oo, retVal.pp, + retVal.qq, retVal.rr, retVal.ss, retVal.tt, retVal.uu, (unsigned long)retVal.vv, retVal.ww, retVal.xx); + + return retVal; +} + +static void +cls_large_fn(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata __UNUSED__) +{ + uint8_t ui8_1 = *(uint8_t*)args[0]; + int8_t si8_1 = *(int8_t*)args[1]; + uint16_t ui16_1 = *(uint16_t*)args[2]; + int16_t si16_1 = *(int16_t*)args[3]; + uint32_t ui32_1 = *(uint32_t*)args[4]; + int32_t si32_1 = *(int32_t*)args[5]; + uint64_t ui64_1 = *(uint64_t*)args[6]; + int64_t si64_1 = *(int64_t*)args[7]; + float f_1 = *(float*)args[8]; + double d_1 = *(double*)args[9]; + long double ld_1 = *(long double*)args[10]; + char* p_1 = *(char**)args[11]; + uint8_t ui8_2 = *(uint8_t*)args[12]; + int8_t si8_2 = *(int8_t*)args[13]; + uint16_t ui16_2 = *(uint16_t*)args[14]; + int16_t si16_2 = *(int16_t*)args[15]; + uint32_t ui32_2 = *(uint32_t*)args[16]; + int32_t si32_2 = *(int32_t*)args[17]; + uint64_t ui64_2 = *(uint64_t*)args[18]; + int64_t si64_2 = *(int64_t*)args[19]; + float f_2 = *(float*)args[20]; + double d_2 = *(double*)args[21]; + long double ld_2 = *(long double*)args[22]; + char* p_2 = *(char**)args[23]; + uint8_t ui8_3 = *(uint8_t*)args[24]; + int8_t si8_3 = *(int8_t*)args[25]; + uint16_t ui16_3 = *(uint16_t*)args[26]; + int16_t si16_3 = *(int16_t*)args[27]; + uint32_t ui32_3 = *(uint32_t*)args[28]; + int32_t si32_3 = *(int32_t*)args[29]; + uint64_t ui64_3 = *(uint64_t*)args[30]; + int64_t si64_3 = *(int64_t*)args[31]; + float f_3 = *(float*)args[32]; + double d_3 = *(double*)args[33]; + long double ld_3 = *(long double*)args[34]; + char* p_3 = *(char**)args[35]; + uint8_t ui8_4 = *(uint8_t*)args[36]; + int8_t si8_4 = *(int8_t*)args[37]; + uint16_t ui16_4 = *(uint16_t*)args[38]; + int16_t si16_4 = *(int16_t*)args[39]; + uint32_t ui32_4 = *(uint32_t*)args[40]; + int32_t si32_4 = *(int32_t*)args[41]; + uint64_t ui64_4 = *(uint64_t*)args[42]; + int64_t si64_4 = *(int64_t*)args[43]; + float f_4 = *(float*)args[44]; + double d_4 = *(double*)args[45]; + long double ld_4 = *(long double*)args[46]; + char* p_4 = *(char**)args[47]; + uint8_t ui8_5 = *(uint8_t*)args[48]; + int8_t si8_5 = *(int8_t*)args[49]; + + *(BigStruct*)resp = test_large_fn( + ui8_1, si8_1, ui16_1, si16_1, ui32_1, si32_1, ui64_1, si64_1, f_1, d_1, ld_1, p_1, + ui8_2, si8_2, ui16_2, si16_2, ui32_2, si32_2, ui64_2, si64_2, f_2, d_2, ld_2, p_2, + ui8_3, si8_3, ui16_3, si16_3, ui32_3, si32_3, ui64_3, si64_3, f_3, d_3, ld_3, p_3, + ui8_4, si8_4, ui16_4, si16_4, ui32_4, si32_4, ui64_4, si64_4, f_4, d_4, ld_4, p_4, + ui8_5, si8_5); +} + +int +main(int argc __UNUSED__, const char** argv __UNUSED__) +{ + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + + ffi_cif cif; + ffi_type* argTypes[51]; + void* argValues[51]; + + ffi_type ret_struct_type; + ffi_type* st_fields[51]; + BigStruct retVal; + + memset (&retVal, 0, sizeof(retVal)); + + ret_struct_type.size = 0; + ret_struct_type.alignment = 0; + ret_struct_type.type = FFI_TYPE_STRUCT; + ret_struct_type.elements = st_fields; + + st_fields[0] = st_fields[12] = st_fields[24] = st_fields[36] = st_fields[48] = &ffi_type_uint8; + st_fields[1] = st_fields[13] = st_fields[25] = st_fields[37] = st_fields[49] = &ffi_type_sint8; + st_fields[2] = st_fields[14] = st_fields[26] = st_fields[38] = &ffi_type_uint16; + st_fields[3] = st_fields[15] = st_fields[27] = st_fields[39] = &ffi_type_sint16; + st_fields[4] = st_fields[16] = st_fields[28] = st_fields[40] = &ffi_type_uint32; + st_fields[5] = st_fields[17] = st_fields[29] = st_fields[41] = &ffi_type_sint32; + st_fields[6] = st_fields[18] = st_fields[30] = st_fields[42] = &ffi_type_uint64; + st_fields[7] = st_fields[19] = st_fields[31] = st_fields[43] = &ffi_type_sint64; + st_fields[8] = st_fields[20] = st_fields[32] = st_fields[44] = &ffi_type_float; + st_fields[9] = st_fields[21] = st_fields[33] = st_fields[45] = &ffi_type_double; + st_fields[10] = st_fields[22] = st_fields[34] = st_fields[46] = &ffi_type_longdouble; + st_fields[11] = st_fields[23] = st_fields[35] = st_fields[47] = &ffi_type_pointer; + + st_fields[50] = NULL; + + uint8_t ui8 = 1; + int8_t si8 = 2; + uint16_t ui16 = 3; + int16_t si16 = 4; + uint32_t ui32 = 5; + int32_t si32 = 6; + uint64_t ui64 = 7; + int64_t si64 = 8; + float f = 9; + double d = 10; + long double ld = 11; + char* p = (char*)0x12345678; + + argTypes[0] = argTypes[12] = argTypes[24] = argTypes[36] = argTypes[48] = &ffi_type_uint8; + argValues[0] = argValues[12] = argValues[24] = argValues[36] = argValues[48] = &ui8; + argTypes[1] = argTypes[13] = argTypes[25] = argTypes[37] = argTypes[49] = &ffi_type_sint8; + argValues[1] = argValues[13] = argValues[25] = argValues[37] = argValues[49] = &si8; + argTypes[2] = argTypes[14] = argTypes[26] = argTypes[38] = &ffi_type_uint16; + argValues[2] = argValues[14] = argValues[26] = argValues[38] = &ui16; + argTypes[3] = argTypes[15] = argTypes[27] = argTypes[39] = &ffi_type_sint16; + argValues[3] = argValues[15] = argValues[27] = argValues[39] = &si16; + argTypes[4] = argTypes[16] = argTypes[28] = argTypes[40] = &ffi_type_uint32; + argValues[4] = argValues[16] = argValues[28] = argValues[40] = &ui32; + argTypes[5] = argTypes[17] = argTypes[29] = argTypes[41] = &ffi_type_sint32; + argValues[5] = argValues[17] = argValues[29] = argValues[41] = &si32; + argTypes[6] = argTypes[18] = argTypes[30] = argTypes[42] = &ffi_type_uint64; + argValues[6] = argValues[18] = argValues[30] = argValues[42] = &ui64; + argTypes[7] = argTypes[19] = argTypes[31] = argTypes[43] = &ffi_type_sint64; + argValues[7] = argValues[19] = argValues[31] = argValues[43] = &si64; + argTypes[8] = argTypes[20] = argTypes[32] = argTypes[44] = &ffi_type_float; + argValues[8] = argValues[20] = argValues[32] = argValues[44] = &f; + argTypes[9] = argTypes[21] = argTypes[33] = argTypes[45] = &ffi_type_double; + argValues[9] = argValues[21] = argValues[33] = argValues[45] = &d; + argTypes[10] = argTypes[22] = argTypes[34] = argTypes[46] = &ffi_type_longdouble; + argValues[10] = argValues[22] = argValues[34] = argValues[46] = &ld; + argTypes[11] = argTypes[23] = argTypes[35] = argTypes[47] = &ffi_type_pointer; + argValues[11] = argValues[23] = argValues[35] = argValues[47] = &p; + + argTypes[50] = NULL; + argValues[50] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 50, &ret_struct_type, argTypes) == FFI_OK); + + ffi_call(&cif, FFI_FN(test_large_fn), &retVal, argValues); + // { dg-output "1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } + printf("res: %hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " + "%hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " + "%hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " + "%hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx %hhu %hhd\n", + retVal.a, retVal.b, retVal.c, retVal.d, retVal.e, retVal.f, + retVal.g, retVal.h, retVal.i, retVal.j, retVal.k, (unsigned long)retVal.l, + retVal.m, retVal.n, retVal.o, retVal.p, retVal.q, retVal.r, + retVal.s, retVal.t, retVal.u, retVal.v, retVal.w, (unsigned long)retVal.x, + retVal.y, retVal.z, retVal.aa, retVal.bb, retVal.cc, retVal.dd, + retVal.ee, retVal.ff, retVal.gg, retVal.hh, retVal.ii, (unsigned long)retVal.jj, + retVal.kk, retVal.ll, retVal.mm, retVal.nn, retVal.oo, retVal.pp, + retVal.qq, retVal.rr, retVal.ss, retVal.tt, retVal.uu, (unsigned long)retVal.vv, retVal.ww, retVal.xx); + // { dg-output "\nres: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_large_fn, NULL, code) == FFI_OK); + + retVal = ((BigStruct(*)( + uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double, long double, char*, + uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double, long double, char*, + uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double, long double, char*, + uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double, long double, char*, + uint8_t, int8_t))(code))( + ui8, si8, ui16, si16, ui32, si32, ui64, si64, f, d, ld, p, + ui8, si8, ui16, si16, ui32, si32, ui64, si64, f, d, ld, p, + ui8, si8, ui16, si16, ui32, si32, ui64, si64, f, d, ld, p, + ui8, si8, ui16, si16, ui32, si32, ui64, si64, f, d, ld, p, + ui8, si8); + // { dg-output "\n1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2 3 4 5 6 7 8 9 10 11 0x12345678 1 2: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } + printf("res: %hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " + "%hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " + "%hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx " + "%hhu %hhd %hu %hd %u %d %" PRIu64 " %" PRId64 " %.0f %.0f %.0Lf %#lx %hhu %hhd\n", + retVal.a, retVal.b, retVal.c, retVal.d, retVal.e, retVal.f, + retVal.g, retVal.h, retVal.i, retVal.j, retVal.k, (unsigned long)retVal.l, + retVal.m, retVal.n, retVal.o, retVal.p, retVal.q, retVal.r, + retVal.s, retVal.t, retVal.u, retVal.v, retVal.w, (unsigned long)retVal.x, + retVal.y, retVal.z, retVal.aa, retVal.bb, retVal.cc, retVal.dd, + retVal.ee, retVal.ff, retVal.gg, retVal.hh, retVal.ii, (unsigned long)retVal.jj, + retVal.kk, retVal.ll, retVal.mm, retVal.nn, retVal.oo, retVal.pp, + retVal.qq, retVal.rr, retVal.ss, retVal.tt, retVal.uu, (unsigned long)retVal.vv, retVal.ww, retVal.xx); + // { dg-output "\nres: 2 3 4 5 6 7 8 9 10 11 12 0x12345679 3 4 5 6 7 8 9 10 11 12 13 0x1234567a 4 5 6 7 8 9 10 11 12 13 14 0x1234567b 5 6 7 8 9 10 11 12 13 14 15 0x1234567c 6 7" } + + return 0; +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/many.c b/js/src/ctypes/libffi/testsuite/libffi.call/many.c new file mode 100644 index 0000000..4869ba9 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/many.c @@ -0,0 +1,69 @@ +/* Area: ffi_call + Purpose: Check return value float, with many arguments + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" + +#include + +static float many(float f1, + float f2, + float f3, + float f4, + float f5, + float f6, + float f7, + float f8, + float f9, + float f10, + float f11, + float f12, + float f13) +{ +#if 0 + printf("%f %f %f %f %f %f %f %f %f %f %f %f %f\n", + (double) f1, (double) f2, (double) f3, (double) f4, (double) f5, + (double) f6, (double) f7, (double) f8, (double) f9, (double) f10, + (double) f11, (double) f12, (double) f13); +#endif + + return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13); +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[13]; + void *values[13]; + float fa[13]; + float f, ff; + int i; + + for (i = 0; i < 13; i++) + { + args[i] = &ffi_type_float; + values[i] = &fa[i]; + fa[i] = (float) i; + } + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 13, + &ffi_type_float, args) == FFI_OK); + + ffi_call(&cif, FFI_FN(many), &f, values); + + ff = many(fa[0], fa[1], + fa[2], fa[3], + fa[4], fa[5], + fa[6], fa[7], + fa[8], fa[9], + fa[10],fa[11],fa[12]); + + if (f - ff < FLT_EPSILON) + exit(0); + else + abort(); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/many_win32.c b/js/src/ctypes/libffi/testsuite/libffi.call/many_win32.c new file mode 100644 index 0000000..1b26332 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/many_win32.c @@ -0,0 +1,63 @@ +/* Area: ffi_call + Purpose: Check stdcall many call on X86_WIN32 systems. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */ + +#include "ffitest.h" +#include + +static float __attribute__((stdcall)) stdcall_many(float f1, + float f2, + float f3, + float f4, + float f5, + float f6, + float f7, + float f8, + float f9, + float f10, + float f11, + float f12, + float f13) +{ + return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12) * f13); +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[13]; + void *values[13]; + float fa[13]; + float f, ff; + unsigned long ul; + + for (ul = 0; ul < 13; ul++) + { + args[ul] = &ffi_type_float; + values[ul] = &fa[ul]; + fa[ul] = (float) ul; + } + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_STDCALL, 13, + &ffi_type_float, args) == FFI_OK); + + ff = stdcall_many(fa[0], fa[1], + fa[2], fa[3], + fa[4], fa[5], + fa[6], fa[7], + fa[8], fa[9], + fa[10], fa[11], fa[12]); + + ffi_call(&cif, FFI_FN(stdcall_many), &f, values); + + if (f - ff < FLT_EPSILON) + printf("stdcall many arg tests ok!\n"); + else + CHECK(0); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/negint.c b/js/src/ctypes/libffi/testsuite/libffi.call/negint.c new file mode 100644 index 0000000..3168113 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/negint.c @@ -0,0 +1,53 @@ +/* Area: ffi_call + Purpose: Check that negative integers are passed correctly. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +/* { dg-options -O2 } */ + +#include "ffitest.h" + +static int checking(int a, short b, signed char c) +{ + + return (a < 0 && b < 0 && c < 0); +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_arg rint; + + signed int si; + signed short ss; + signed char sc; + + args[0] = &ffi_type_sint; + values[0] = &si; + args[1] = &ffi_type_sshort; + values[1] = &ss; + args[2] = &ffi_type_schar; + values[2] = ≻ + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, + &ffi_type_sint, args) == FFI_OK); + + si = -6; + ss = -12; + sc = -1; + + checking (si, ss, sc); + + ffi_call(&cif, FFI_FN(checking), &rint, values); + + printf ("%d vs %d\n", (int)rint, checking (si, ss, sc)); + + CHECK(rint != 0); + + exit (0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct.c new file mode 100644 index 0000000..8aa527e --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct.c @@ -0,0 +1,152 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Contains structs as parameter of the struct itself. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_16byte1 { + double a; + float b; + int c; +} cls_struct_16byte1; + +typedef struct cls_struct_16byte2 { + int ii; + double dd; + float ff; +} cls_struct_16byte2; + +typedef struct cls_struct_combined { + cls_struct_16byte1 d; + cls_struct_16byte2 e; +} cls_struct_combined; + +cls_struct_combined cls_struct_combined_fn(struct cls_struct_16byte1 b0, + struct cls_struct_16byte2 b1, + struct cls_struct_combined b2) +{ + struct cls_struct_combined result; + + result.d.a = b0.a + b1.dd + b2.d.a; + result.d.b = b0.b + b1.ff + b2.d.b; + result.d.c = b0.c + b1.ii + b2.d.c; + result.e.ii = b0.c + b1.ii + b2.e.ii; + result.e.dd = b0.a + b1.dd + b2.e.dd; + result.e.ff = b0.b + b1.ff + b2.e.ff; + + printf("%g %g %d %d %g %g %g %g %d %d %g %g: %g %g %d %d %g %g\n", + b0.a, b0.b, b0.c, + b1.ii, b1.dd, b1.ff, + b2.d.a, b2.d.b, b2.d.c, + b2.e.ii, b2.e.dd, b2.e.ff, + result.d.a, result.d.b, result.d.c, + result.e.ii, result.e.dd, result.e.ff); + + return result; +} + +static void +cls_struct_combined_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct cls_struct_16byte1 b0; + struct cls_struct_16byte2 b1; + struct cls_struct_combined b2; + + b0 = *(struct cls_struct_16byte1*)(args[0]); + b1 = *(struct cls_struct_16byte2*)(args[1]); + b2 = *(struct cls_struct_combined*)(args[2]); + + + *(cls_struct_combined*)resp = cls_struct_combined_fn(b0, b1, b2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[5]; + ffi_type* cls_struct_fields1[5]; + ffi_type* cls_struct_fields2[5]; + ffi_type cls_struct_type, cls_struct_type1, cls_struct_type2; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + cls_struct_type1.size = 0; + cls_struct_type1.alignment = 0; + cls_struct_type1.type = FFI_TYPE_STRUCT; + cls_struct_type1.elements = cls_struct_fields1; + + cls_struct_type2.size = 0; + cls_struct_type2.alignment = 0; + cls_struct_type2.type = FFI_TYPE_STRUCT; + cls_struct_type2.elements = cls_struct_fields2; + + struct cls_struct_16byte1 e_dbl = { 9.0, 2.0, 6}; + struct cls_struct_16byte2 f_dbl = { 1, 2.0, 3.0}; + struct cls_struct_combined g_dbl = {{4.0, 5.0, 6}, + {3, 1.0, 8.0}}; + struct cls_struct_combined res_dbl; + + cls_struct_fields[0] = &ffi_type_double; + cls_struct_fields[1] = &ffi_type_float; + cls_struct_fields[2] = &ffi_type_sint; + cls_struct_fields[3] = NULL; + + cls_struct_fields1[0] = &ffi_type_sint; + cls_struct_fields1[1] = &ffi_type_double; + cls_struct_fields1[2] = &ffi_type_float; + cls_struct_fields1[3] = NULL; + + cls_struct_fields2[0] = &cls_struct_type; + cls_struct_fields2[1] = &cls_struct_type1; + cls_struct_fields2[2] = NULL; + + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type1; + dbl_arg_types[2] = &cls_struct_type2; + dbl_arg_types[3] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, &cls_struct_type2, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = &g_dbl; + args_dbl[3] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_combined_fn), &res_dbl, args_dbl); + /* { dg-output "9 2 6 1 2 3 4 5 6 3 1 8: 15 10 13 10 12 13" } */ + CHECK( res_dbl.d.a == (e_dbl.a + f_dbl.dd + g_dbl.d.a)); + CHECK( res_dbl.d.b == (e_dbl.b + f_dbl.ff + g_dbl.d.b)); + CHECK( res_dbl.d.c == (e_dbl.c + f_dbl.ii + g_dbl.d.c)); + CHECK( res_dbl.e.ii == (e_dbl.c + f_dbl.ii + g_dbl.e.ii)); + CHECK( res_dbl.e.dd == (e_dbl.a + f_dbl.dd + g_dbl.e.dd)); + CHECK( res_dbl.e.ff == (e_dbl.b + f_dbl.ff + g_dbl.e.ff)); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_combined_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_combined(*)(cls_struct_16byte1, + cls_struct_16byte2, + cls_struct_combined)) + (code))(e_dbl, f_dbl, g_dbl); + /* { dg-output "\n9 2 6 1 2 3 4 5 6 3 1 8: 15 10 13 10 12 13" } */ + CHECK( res_dbl.d.a == (e_dbl.a + f_dbl.dd + g_dbl.d.a)); + CHECK( res_dbl.d.b == (e_dbl.b + f_dbl.ff + g_dbl.d.b)); + CHECK( res_dbl.d.c == (e_dbl.c + f_dbl.ii + g_dbl.d.c)); + CHECK( res_dbl.e.ii == (e_dbl.c + f_dbl.ii + g_dbl.e.ii)); + CHECK( res_dbl.e.dd == (e_dbl.a + f_dbl.dd + g_dbl.e.dd)); + CHECK( res_dbl.e.ff == (e_dbl.b + f_dbl.ff + g_dbl.e.ff)); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct1.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct1.c new file mode 100644 index 0000000..2a9f515 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct1.c @@ -0,0 +1,161 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Contains structs as parameter of the struct itself. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_16byte1 { + double a; + float b; + int c; +} cls_struct_16byte1; + +typedef struct cls_struct_16byte2 { + int ii; + double dd; + float ff; +} cls_struct_16byte2; + +typedef struct cls_struct_combined { + cls_struct_16byte1 d; + cls_struct_16byte2 e; +} cls_struct_combined; + +cls_struct_combined cls_struct_combined_fn(struct cls_struct_16byte1 b0, + struct cls_struct_16byte2 b1, + struct cls_struct_combined b2, + struct cls_struct_16byte1 b3) +{ + struct cls_struct_combined result; + + result.d.a = b0.a + b1.dd + b2.d.a; + result.d.b = b0.b + b1.ff + b2.d.b; + result.d.c = b0.c + b1.ii + b2.d.c; + result.e.ii = b0.c + b1.ii + b2.e.ii; + result.e.dd = b0.a + b1.dd + b2.e.dd; + result.e.ff = b0.b + b1.ff + b2.e.ff; + + printf("%g %g %d %d %g %g %g %g %d %d %g %g %g %g %d: %g %g %d %d %g %g\n", + b0.a, b0.b, b0.c, + b1.ii, b1.dd, b1.ff, + b2.d.a, b2.d.b, b2.d.c, + b2.e.ii, b2.e.dd, b2.e.ff, + b3.a, b3.b, b3.c, + result.d.a, result.d.b, result.d.c, + result.e.ii, result.e.dd, result.e.ff); + + return result; +} + +static void +cls_struct_combined_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct cls_struct_16byte1 b0; + struct cls_struct_16byte2 b1; + struct cls_struct_combined b2; + struct cls_struct_16byte1 b3; + + b0 = *(struct cls_struct_16byte1*)(args[0]); + b1 = *(struct cls_struct_16byte2*)(args[1]); + b2 = *(struct cls_struct_combined*)(args[2]); + b3 = *(struct cls_struct_16byte1*)(args[3]); + + + *(cls_struct_combined*)resp = cls_struct_combined_fn(b0, b1, b2, b3); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[5]; + ffi_type* cls_struct_fields1[5]; + ffi_type* cls_struct_fields2[5]; + ffi_type cls_struct_type, cls_struct_type1, cls_struct_type2; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + cls_struct_type1.size = 0; + cls_struct_type1.alignment = 0; + cls_struct_type1.type = FFI_TYPE_STRUCT; + cls_struct_type1.elements = cls_struct_fields1; + + cls_struct_type2.size = 0; + cls_struct_type2.alignment = 0; + cls_struct_type2.type = FFI_TYPE_STRUCT; + cls_struct_type2.elements = cls_struct_fields2; + + struct cls_struct_16byte1 e_dbl = { 9.0, 2.0, 6}; + struct cls_struct_16byte2 f_dbl = { 1, 2.0, 3.0}; + struct cls_struct_combined g_dbl = {{4.0, 5.0, 6}, + {3, 1.0, 8.0}}; + struct cls_struct_16byte1 h_dbl = { 3.0, 2.0, 4}; + struct cls_struct_combined res_dbl; + + cls_struct_fields[0] = &ffi_type_double; + cls_struct_fields[1] = &ffi_type_float; + cls_struct_fields[2] = &ffi_type_sint; + cls_struct_fields[3] = NULL; + + cls_struct_fields1[0] = &ffi_type_sint; + cls_struct_fields1[1] = &ffi_type_double; + cls_struct_fields1[2] = &ffi_type_float; + cls_struct_fields1[3] = NULL; + + cls_struct_fields2[0] = &cls_struct_type; + cls_struct_fields2[1] = &cls_struct_type1; + cls_struct_fields2[2] = NULL; + + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type1; + dbl_arg_types[2] = &cls_struct_type2; + dbl_arg_types[3] = &cls_struct_type; + dbl_arg_types[4] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &cls_struct_type2, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = &g_dbl; + args_dbl[3] = &h_dbl; + args_dbl[4] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_combined_fn), &res_dbl, args_dbl); + /* { dg-output "9 2 6 1 2 3 4 5 6 3 1 8 3 2 4: 15 10 13 10 12 13" } */ + CHECK( res_dbl.d.a == (e_dbl.a + f_dbl.dd + g_dbl.d.a)); + CHECK( res_dbl.d.b == (e_dbl.b + f_dbl.ff + g_dbl.d.b)); + CHECK( res_dbl.d.c == (e_dbl.c + f_dbl.ii + g_dbl.d.c)); + CHECK( res_dbl.e.ii == (e_dbl.c + f_dbl.ii + g_dbl.e.ii)); + CHECK( res_dbl.e.dd == (e_dbl.a + f_dbl.dd + g_dbl.e.dd)); + CHECK( res_dbl.e.ff == (e_dbl.b + f_dbl.ff + g_dbl.e.ff)); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_combined_gn, NULL, code) == FFI_OK); + + res_dbl = ((cls_struct_combined(*)(cls_struct_16byte1, + cls_struct_16byte2, + cls_struct_combined, + cls_struct_16byte1)) + (code))(e_dbl, f_dbl, g_dbl, h_dbl); + /* { dg-output "\n9 2 6 1 2 3 4 5 6 3 1 8 3 2 4: 15 10 13 10 12 13" } */ + CHECK( res_dbl.d.a == (e_dbl.a + f_dbl.dd + g_dbl.d.a)); + CHECK( res_dbl.d.b == (e_dbl.b + f_dbl.ff + g_dbl.d.b)); + CHECK( res_dbl.d.c == (e_dbl.c + f_dbl.ii + g_dbl.d.c)); + CHECK( res_dbl.e.ii == (e_dbl.c + f_dbl.ii + g_dbl.e.ii)); + CHECK( res_dbl.e.dd == (e_dbl.a + f_dbl.dd + g_dbl.e.dd)); + CHECK( res_dbl.e.ff == (e_dbl.b + f_dbl.ff + g_dbl.e.ff)); + // CHECK( 1 == 0); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct10.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct10.c new file mode 100644 index 0000000..d6a718b --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct10.c @@ -0,0 +1,133 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Contains structs as parameter of the struct itself. + Sample taken from Alan Modras patch to src/prep_cif.c. + Limitations: none. + PR: none. + Originator: 20051010 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct A { + unsigned long long a; + unsigned char b; +} A; + +typedef struct B { + unsigned char y; + struct A x; + unsigned int z; +} B; + +typedef struct C { + unsigned long long d; + unsigned char e; +} C; + +static B B_fn(struct A b2, struct B b3, struct C b4) +{ + struct B result; + + result.x.a = b2.a + b3.x.a + b3.z + b4.d; + result.x.b = b2.b + b3.x.b + b3.y + b4.e; + result.y = b2.b + b3.x.b + b4.e; + + printf("%d %d %d %d %d %d %d %d: %d %d %d\n", (int)b2.a, b2.b, + (int)b3.x.a, b3.x.b, b3.y, b3.z, (int)b4.d, b4.e, + (int)result.x.a, result.x.b, result.y); + + return result; +} + +static void +B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct A b0; + struct B b1; + struct C b2; + + b0 = *(struct A*)(args[0]); + b1 = *(struct B*)(args[1]); + b2 = *(struct C*)(args[2]); + + *(B*)resp = B_fn(b0, b1, b2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[4]; + ffi_type* cls_struct_fields[3]; + ffi_type* cls_struct_fields1[4]; + ffi_type* cls_struct_fields2[3]; + ffi_type cls_struct_type, cls_struct_type1, cls_struct_type2; + ffi_type* dbl_arg_types[4]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + cls_struct_type1.size = 0; + cls_struct_type1.alignment = 0; + cls_struct_type1.type = FFI_TYPE_STRUCT; + cls_struct_type1.elements = cls_struct_fields1; + + cls_struct_type2.size = 0; + cls_struct_type2.alignment = 0; + cls_struct_type2.type = FFI_TYPE_STRUCT; + cls_struct_type2.elements = cls_struct_fields2; + + struct A e_dbl = { 1LL, 7}; + struct B f_dbl = { 99, {12LL , 127}, 255}; + struct C g_dbl = { 2LL, 9}; + + struct B res_dbl; + + cls_struct_fields[0] = &ffi_type_uint64; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = NULL; + + cls_struct_fields1[0] = &ffi_type_uchar; + cls_struct_fields1[1] = &cls_struct_type; + cls_struct_fields1[2] = &ffi_type_uint; + cls_struct_fields1[3] = NULL; + + cls_struct_fields2[0] = &ffi_type_uint64; + cls_struct_fields2[1] = &ffi_type_uchar; + cls_struct_fields2[2] = NULL; + + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type1; + dbl_arg_types[2] = &cls_struct_type2; + dbl_arg_types[3] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, &cls_struct_type1, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = &g_dbl; + args_dbl[3] = NULL; + + ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl); + /* { dg-output "1 7 12 127 99 255 2 9: 270 242 143" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + f_dbl.z + g_dbl.d)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e)); + + CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK); + + res_dbl = ((B(*)(A, B, C))(code))(e_dbl, f_dbl, g_dbl); + /* { dg-output "\n1 7 12 127 99 255 2 9: 270 242 143" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + f_dbl.z + g_dbl.d)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e)); + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct2.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct2.c new file mode 100644 index 0000000..de1584c --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct2.c @@ -0,0 +1,110 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Contains structs as parameter of the struct itself. + Sample taken from Alan Modras patch to src/prep_cif.c. + Limitations: none. + PR: none. + Originator: 20030911 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct A { + unsigned long a; + unsigned char b; +} A; + +typedef struct B { + struct A x; + unsigned char y; +} B; + +B B_fn(struct A b0, struct B b1) +{ + struct B result; + + result.x.a = b0.a + b1.x.a; + result.x.b = b0.b + b1.x.b + b1.y; + result.y = b0.b + b1.x.b; + + printf("%lu %d %lu %d %d: %lu %d %d\n", b0.a, b0.b, b1.x.a, b1.x.b, b1.y, + result.x.a, result.x.b, result.y); + + return result; +} + +static void +B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct A b0; + struct B b1; + + b0 = *(struct A*)(args[0]); + b1 = *(struct B*)(args[1]); + + *(B*)resp = B_fn(b0, b1); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[3]; + ffi_type* cls_struct_fields[3]; + ffi_type* cls_struct_fields1[3]; + ffi_type cls_struct_type, cls_struct_type1; + ffi_type* dbl_arg_types[3]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + cls_struct_type1.size = 0; + cls_struct_type1.alignment = 0; + cls_struct_type1.type = FFI_TYPE_STRUCT; + cls_struct_type1.elements = cls_struct_fields1; + + struct A e_dbl = { 1, 7}; + struct B f_dbl = {{12 , 127}, 99}; + + struct B res_dbl; + + cls_struct_fields[0] = &ffi_type_ulong; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = NULL; + + cls_struct_fields1[0] = &cls_struct_type; + cls_struct_fields1[1] = &ffi_type_uchar; + cls_struct_fields1[2] = NULL; + + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type1; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type1, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl); + /* { dg-output "1 7 12 127 99: 13 233 134" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b)); + + CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK); + + res_dbl = ((B(*)(A, B))(code))(e_dbl, f_dbl); + /* { dg-output "\n1 7 12 127 99: 13 233 134" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b)); + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct3.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct3.c new file mode 100644 index 0000000..58aa853 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct3.c @@ -0,0 +1,111 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Contains structs as parameter of the struct itself. + Sample taken from Alan Modras patch to src/prep_cif.c. + Limitations: none. + PR: none. + Originator: 20030911 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct A { + unsigned long long a; + unsigned char b; +} A; + +typedef struct B { + struct A x; + unsigned char y; +} B; + +B B_fn(struct A b0, struct B b1) +{ + struct B result; + + result.x.a = b0.a + b1.x.a; + result.x.b = b0.b + b1.x.b + b1.y; + result.y = b0.b + b1.x.b; + + printf("%d %d %d %d %d: %d %d %d\n", (int)b0.a, b0.b, + (int)b1.x.a, b1.x.b, b1.y, + (int)result.x.a, result.x.b, result.y); + + return result; +} + +static void +B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct A b0; + struct B b1; + + b0 = *(struct A*)(args[0]); + b1 = *(struct B*)(args[1]); + + *(B*)resp = B_fn(b0, b1); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[3]; + ffi_type* cls_struct_fields[3]; + ffi_type* cls_struct_fields1[3]; + ffi_type cls_struct_type, cls_struct_type1; + ffi_type* dbl_arg_types[3]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + cls_struct_type1.size = 0; + cls_struct_type1.alignment = 0; + cls_struct_type1.type = FFI_TYPE_STRUCT; + cls_struct_type1.elements = cls_struct_fields1; + + struct A e_dbl = { 1LL, 7}; + struct B f_dbl = {{12LL , 127}, 99}; + + struct B res_dbl; + + cls_struct_fields[0] = &ffi_type_uint64; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = NULL; + + cls_struct_fields1[0] = &cls_struct_type; + cls_struct_fields1[1] = &ffi_type_uchar; + cls_struct_fields1[2] = NULL; + + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type1; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type1, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl); + /* { dg-output "1 7 12 127 99: 13 233 134" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b)); + + + CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK); + + res_dbl = ((B(*)(A, B))(code))(e_dbl, f_dbl); + /* { dg-output "\n1 7 12 127 99: 13 233 134" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b)); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct4.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct4.c new file mode 100644 index 0000000..98e491e --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct4.c @@ -0,0 +1,111 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Contains structs as parameter of the struct itself. + Sample taken from Alan Modras patch to src/prep_cif.c. + Limitations: none. + PR: PR 25630. + Originator: 20051010 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct A { + double a; + unsigned char b; +} A; + +typedef struct B { + struct A x; + unsigned char y; +} B; + +static B B_fn(struct A b2, struct B b3) +{ + struct B result; + + result.x.a = b2.a + b3.x.a; + result.x.b = b2.b + b3.x.b + b3.y; + result.y = b2.b + b3.x.b; + + printf("%d %d %d %d %d: %d %d %d\n", (int)b2.a, b2.b, + (int)b3.x.a, b3.x.b, b3.y, + (int)result.x.a, result.x.b, result.y); + + return result; +} + +static void +B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct A b0; + struct B b1; + + b0 = *(struct A*)(args[0]); + b1 = *(struct B*)(args[1]); + + *(B*)resp = B_fn(b0, b1); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[3]; + ffi_type* cls_struct_fields[3]; + ffi_type* cls_struct_fields1[3]; + ffi_type cls_struct_type, cls_struct_type1; + ffi_type* dbl_arg_types[3]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + cls_struct_type1.size = 0; + cls_struct_type1.alignment = 0; + cls_struct_type1.type = FFI_TYPE_STRUCT; + cls_struct_type1.elements = cls_struct_fields1; + + struct A e_dbl = { 1.0, 7}; + struct B f_dbl = {{12.0 , 127}, 99}; + + struct B res_dbl; + + cls_struct_fields[0] = &ffi_type_double; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = NULL; + + cls_struct_fields1[0] = &cls_struct_type; + cls_struct_fields1[1] = &ffi_type_uchar; + cls_struct_fields1[2] = NULL; + + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type1; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type1, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl); + /* { dg-output "1 7 12 127 99: 13 233 134" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b)); + + CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK); + + res_dbl = ((B(*)(A, B))(code))(e_dbl, f_dbl); + /* { dg-output "\n1 7 12 127 99: 13 233 134" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b)); + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct5.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct5.c new file mode 100644 index 0000000..d8e3537 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct5.c @@ -0,0 +1,112 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Contains structs as parameter of the struct itself. + Sample taken from Alan Modras patch to src/prep_cif.c. + Limitations: none. + PR: none. + Originator: 20051010 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct A { + long double a; + unsigned char b; +} A; + +typedef struct B { + struct A x; + unsigned char y; +} B; + +static B B_fn(struct A b2, struct B b3) +{ + struct B result; + + result.x.a = b2.a + b3.x.a; + result.x.b = b2.b + b3.x.b + b3.y; + result.y = b2.b + b3.x.b; + + printf("%d %d %d %d %d: %d %d %d\n", (int)b2.a, b2.b, + (int)b3.x.a, b3.x.b, b3.y, + (int)result.x.a, result.x.b, result.y); + + return result; +} + +static void +B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct A b0; + struct B b1; + + b0 = *(struct A*)(args[0]); + b1 = *(struct B*)(args[1]); + + *(B*)resp = B_fn(b0, b1); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[3]; + ffi_type* cls_struct_fields[3]; + ffi_type* cls_struct_fields1[3]; + ffi_type cls_struct_type, cls_struct_type1; + ffi_type* dbl_arg_types[3]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + cls_struct_type1.size = 0; + cls_struct_type1.alignment = 0; + cls_struct_type1.type = FFI_TYPE_STRUCT; + cls_struct_type1.elements = cls_struct_fields1; + + struct A e_dbl = { 1.0, 7}; + struct B f_dbl = {{12.0 , 127}, 99}; + + struct B res_dbl; + + cls_struct_fields[0] = &ffi_type_longdouble; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = NULL; + + cls_struct_fields1[0] = &cls_struct_type; + cls_struct_fields1[1] = &ffi_type_uchar; + cls_struct_fields1[2] = NULL; + + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type1; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type1, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl); + /* { dg-output "1 7 12 127 99: 13 233 134" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b)); + + + CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK); + + res_dbl = ((B(*)(A, B))(code))(e_dbl, f_dbl); + /* { dg-output "\n1 7 12 127 99: 13 233 134" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b)); + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct6.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct6.c new file mode 100644 index 0000000..2f2b25a --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct6.c @@ -0,0 +1,131 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Contains structs as parameter of the struct itself. + Sample taken from Alan Modras patch to src/prep_cif.c. + Limitations: none. + PR: PR 25630. + Originator: 20051010 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct A { + double a; + unsigned char b; +} A; + +typedef struct B { + struct A x; + unsigned char y; +} B; + +typedef struct C { + long d; + unsigned char e; +} C; + +static B B_fn(struct A b2, struct B b3, struct C b4) +{ + struct B result; + + result.x.a = b2.a + b3.x.a + b4.d; + result.x.b = b2.b + b3.x.b + b3.y + b4.e; + result.y = b2.b + b3.x.b + b4.e; + + printf("%d %d %d %d %d %d %d: %d %d %d\n", (int)b2.a, b2.b, + (int)b3.x.a, b3.x.b, b3.y, (int)b4.d, b4.e, + (int)result.x.a, result.x.b, result.y); + + return result; +} + +static void +B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct A b0; + struct B b1; + struct C b2; + + b0 = *(struct A*)(args[0]); + b1 = *(struct B*)(args[1]); + b2 = *(struct C*)(args[2]); + + *(B*)resp = B_fn(b0, b1, b2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[4]; + ffi_type* cls_struct_fields[3]; + ffi_type* cls_struct_fields1[3]; + ffi_type* cls_struct_fields2[3]; + ffi_type cls_struct_type, cls_struct_type1, cls_struct_type2; + ffi_type* dbl_arg_types[4]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + cls_struct_type1.size = 0; + cls_struct_type1.alignment = 0; + cls_struct_type1.type = FFI_TYPE_STRUCT; + cls_struct_type1.elements = cls_struct_fields1; + + cls_struct_type2.size = 0; + cls_struct_type2.alignment = 0; + cls_struct_type2.type = FFI_TYPE_STRUCT; + cls_struct_type2.elements = cls_struct_fields2; + + struct A e_dbl = { 1.0, 7}; + struct B f_dbl = {{12.0 , 127}, 99}; + struct C g_dbl = { 2, 9}; + + struct B res_dbl; + + cls_struct_fields[0] = &ffi_type_double; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = NULL; + + cls_struct_fields1[0] = &cls_struct_type; + cls_struct_fields1[1] = &ffi_type_uchar; + cls_struct_fields1[2] = NULL; + + cls_struct_fields2[0] = &ffi_type_slong; + cls_struct_fields2[1] = &ffi_type_uchar; + cls_struct_fields2[2] = NULL; + + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type1; + dbl_arg_types[2] = &cls_struct_type2; + dbl_arg_types[3] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, &cls_struct_type1, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = &g_dbl; + args_dbl[3] = NULL; + + ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl); + /* { dg-output "1 7 12 127 99 2 9: 15 242 143" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + g_dbl.d)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e)); + + CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK); + + res_dbl = ((B(*)(A, B, C))(code))(e_dbl, f_dbl, g_dbl); + /* { dg-output "\n1 7 12 127 99 2 9: 15 242 143" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + g_dbl.d)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e)); + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct7.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct7.c new file mode 100644 index 0000000..14c7023 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct7.c @@ -0,0 +1,111 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Contains structs as parameter of the struct itself. + Sample taken from Alan Modras patch to src/prep_cif.c. + Limitations: none. + PR: none. + Originator: 20051010 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct A { + unsigned long long a; + unsigned char b; +} A; + +typedef struct B { + struct A x; + unsigned char y; +} B; + +static B B_fn(struct A b2, struct B b3) +{ + struct B result; + + result.x.a = b2.a + b3.x.a; + result.x.b = b2.b + b3.x.b + b3.y; + result.y = b2.b + b3.x.b; + + printf("%d %d %d %d %d: %d %d %d\n", (int)b2.a, b2.b, + (int)b3.x.a, b3.x.b, b3.y, + (int)result.x.a, result.x.b, result.y); + + return result; +} + +static void +B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct A b0; + struct B b1; + + b0 = *(struct A*)(args[0]); + b1 = *(struct B*)(args[1]); + + *(B*)resp = B_fn(b0, b1); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[3]; + ffi_type* cls_struct_fields[3]; + ffi_type* cls_struct_fields1[3]; + ffi_type cls_struct_type, cls_struct_type1; + ffi_type* dbl_arg_types[3]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + cls_struct_type1.size = 0; + cls_struct_type1.alignment = 0; + cls_struct_type1.type = FFI_TYPE_STRUCT; + cls_struct_type1.elements = cls_struct_fields1; + + struct A e_dbl = { 1LL, 7}; + struct B f_dbl = {{12.0 , 127}, 99}; + + struct B res_dbl; + + cls_struct_fields[0] = &ffi_type_uint64; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = NULL; + + cls_struct_fields1[0] = &cls_struct_type; + cls_struct_fields1[1] = &ffi_type_uchar; + cls_struct_fields1[2] = NULL; + + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type1; + dbl_arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &cls_struct_type1, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = NULL; + + ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl); + /* { dg-output "1 7 12 127 99: 13 233 134" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b)); + + CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK); + + res_dbl = ((B(*)(A, B))(code))(e_dbl, f_dbl); + /* { dg-output "\n1 7 12 127 99: 13 233 134" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b)); + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct8.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct8.c new file mode 100644 index 0000000..bb77ead --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct8.c @@ -0,0 +1,131 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Contains structs as parameter of the struct itself. + Sample taken from Alan Modras patch to src/prep_cif.c. + Limitations: none. + PR: none. + Originator: 20051010 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct A { + unsigned long long a; + unsigned char b; +} A; + +typedef struct B { + struct A x; + unsigned char y; +} B; + +typedef struct C { + unsigned long long d; + unsigned char e; +} C; + +static B B_fn(struct A b2, struct B b3, struct C b4) +{ + struct B result; + + result.x.a = b2.a + b3.x.a + b4.d; + result.x.b = b2.b + b3.x.b + b3.y + b4.e; + result.y = b2.b + b3.x.b + b4.e; + + printf("%d %d %d %d %d %d %d: %d %d %d\n", (int)b2.a, b2.b, + (int)b3.x.a, b3.x.b, b3.y, (int)b4.d, b4.e, + (int)result.x.a, result.x.b, result.y); + + return result; +} + +static void +B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct A b0; + struct B b1; + struct C b2; + + b0 = *(struct A*)(args[0]); + b1 = *(struct B*)(args[1]); + b2 = *(struct C*)(args[2]); + + *(B*)resp = B_fn(b0, b1, b2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[4]; + ffi_type* cls_struct_fields[3]; + ffi_type* cls_struct_fields1[3]; + ffi_type* cls_struct_fields2[3]; + ffi_type cls_struct_type, cls_struct_type1, cls_struct_type2; + ffi_type* dbl_arg_types[4]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + cls_struct_type1.size = 0; + cls_struct_type1.alignment = 0; + cls_struct_type1.type = FFI_TYPE_STRUCT; + cls_struct_type1.elements = cls_struct_fields1; + + cls_struct_type2.size = 0; + cls_struct_type2.alignment = 0; + cls_struct_type2.type = FFI_TYPE_STRUCT; + cls_struct_type2.elements = cls_struct_fields2; + + struct A e_dbl = { 1LL, 7}; + struct B f_dbl = {{12LL , 127}, 99}; + struct C g_dbl = { 2LL, 9}; + + struct B res_dbl; + + cls_struct_fields[0] = &ffi_type_uint64; + cls_struct_fields[1] = &ffi_type_uchar; + cls_struct_fields[2] = NULL; + + cls_struct_fields1[0] = &cls_struct_type; + cls_struct_fields1[1] = &ffi_type_uchar; + cls_struct_fields1[2] = NULL; + + cls_struct_fields2[0] = &ffi_type_uint64; + cls_struct_fields2[1] = &ffi_type_uchar; + cls_struct_fields2[2] = NULL; + + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type1; + dbl_arg_types[2] = &cls_struct_type2; + dbl_arg_types[3] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, &cls_struct_type1, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = &g_dbl; + args_dbl[3] = NULL; + + ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl); + /* { dg-output "1 7 12 127 99 2 9: 15 242 143" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + g_dbl.d)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e)); + + CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK); + + res_dbl = ((B(*)(A, B, C))(code))(e_dbl, f_dbl, g_dbl); + /* { dg-output "\n1 7 12 127 99 2 9: 15 242 143" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + g_dbl.d)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e)); + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct9.c b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct9.c new file mode 100644 index 0000000..e9f541c --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/nested_struct9.c @@ -0,0 +1,131 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Contains structs as parameter of the struct itself. + Sample taken from Alan Modras patch to src/prep_cif.c. + Limitations: none. + PR: none. + Originator: 20051010 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct A { + unsigned char a; + unsigned long long b; +} A; + +typedef struct B { + struct A x; + unsigned char y; +} B; + +typedef struct C { + unsigned long d; + unsigned char e; +} C; + +static B B_fn(struct A b2, struct B b3, struct C b4) +{ + struct B result; + + result.x.a = b2.a + b3.x.a + b4.d; + result.x.b = b2.b + b3.x.b + b3.y + b4.e; + result.y = b2.b + b3.x.b + b4.e; + + printf("%d %d %d %d %d %d %d: %d %d %d\n", b2.a, (int)b2.b, + b3.x.a, (int)b3.x.b, b3.y, (int)b4.d, b4.e, + result.x.a, (int)result.x.b, result.y); + + return result; +} + +static void +B_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct A b0; + struct B b1; + struct C b2; + + b0 = *(struct A*)(args[0]); + b1 = *(struct B*)(args[1]); + b2 = *(struct C*)(args[2]); + + *(B*)resp = B_fn(b0, b1, b2); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[4]; + ffi_type* cls_struct_fields[3]; + ffi_type* cls_struct_fields1[3]; + ffi_type* cls_struct_fields2[3]; + ffi_type cls_struct_type, cls_struct_type1, cls_struct_type2; + ffi_type* dbl_arg_types[4]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + cls_struct_type1.size = 0; + cls_struct_type1.alignment = 0; + cls_struct_type1.type = FFI_TYPE_STRUCT; + cls_struct_type1.elements = cls_struct_fields1; + + cls_struct_type2.size = 0; + cls_struct_type2.alignment = 0; + cls_struct_type2.type = FFI_TYPE_STRUCT; + cls_struct_type2.elements = cls_struct_fields2; + + struct A e_dbl = { 1, 7LL}; + struct B f_dbl = {{12.0 , 127}, 99}; + struct C g_dbl = { 2, 9}; + + struct B res_dbl; + + cls_struct_fields[0] = &ffi_type_uchar; + cls_struct_fields[1] = &ffi_type_uint64; + cls_struct_fields[2] = NULL; + + cls_struct_fields1[0] = &cls_struct_type; + cls_struct_fields1[1] = &ffi_type_uchar; + cls_struct_fields1[2] = NULL; + + cls_struct_fields2[0] = &ffi_type_ulong; + cls_struct_fields2[1] = &ffi_type_uchar; + cls_struct_fields2[2] = NULL; + + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type1; + dbl_arg_types[2] = &cls_struct_type2; + dbl_arg_types[3] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, &cls_struct_type1, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = &g_dbl; + args_dbl[3] = NULL; + + ffi_call(&cif, FFI_FN(B_fn), &res_dbl, args_dbl); + /* { dg-output "1 7 12 127 99 2 9: 15 242 143" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + g_dbl.d)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e)); + + CHECK(ffi_prep_closure_loc(pcl, &cif, B_gn, NULL, code) == FFI_OK); + + res_dbl = ((B(*)(A, B, C))(code))(e_dbl, f_dbl, g_dbl); + /* { dg-output "\n1 7 12 127 99 2 9: 15 242 143" } */ + CHECK( res_dbl.x.a == (e_dbl.a + f_dbl.x.a + g_dbl.d)); + CHECK( res_dbl.x.b == (e_dbl.b + f_dbl.x.b + f_dbl.y + g_dbl.e)); + CHECK( res_dbl.y == (e_dbl.b + f_dbl.x.b + g_dbl.e)); + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/problem1.c b/js/src/ctypes/libffi/testsuite/libffi.call/problem1.c new file mode 100644 index 0000000..6a91555 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/problem1.c @@ -0,0 +1,90 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure passing with different structure size. + Limitations: none. + PR: none. + Originator: 20030828 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct my_ffi_struct { + double a; + double b; + double c; +} my_ffi_struct; + +my_ffi_struct callee(struct my_ffi_struct a1, struct my_ffi_struct a2) +{ + struct my_ffi_struct result; + result.a = a1.a + a2.a; + result.b = a1.b + a2.b; + result.c = a1.c + a2.c; + + + printf("%g %g %g %g %g %g: %g %g %g\n", a1.a, a1.b, a1.c, + a2.a, a2.b, a2.c, result.a, result.b, result.c); + + return result; +} + +void stub(ffi_cif* cif __UNUSED__, void* resp, void** args, + void* userdata __UNUSED__) +{ + struct my_ffi_struct a1; + struct my_ffi_struct a2; + + a1 = *(struct my_ffi_struct*)(args[0]); + a2 = *(struct my_ffi_struct*)(args[1]); + + *(my_ffi_struct *)resp = callee(a1, a2); +} + + +int main(void) +{ + ffi_type* my_ffi_struct_fields[4]; + ffi_type my_ffi_struct_type; + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args[4]; + ffi_type* arg_types[3]; + + struct my_ffi_struct g = { 1.0, 2.0, 3.0 }; + struct my_ffi_struct f = { 1.0, 2.0, 3.0 }; + struct my_ffi_struct res; + + my_ffi_struct_type.size = 0; + my_ffi_struct_type.alignment = 0; + my_ffi_struct_type.type = FFI_TYPE_STRUCT; + my_ffi_struct_type.elements = my_ffi_struct_fields; + + my_ffi_struct_fields[0] = &ffi_type_double; + my_ffi_struct_fields[1] = &ffi_type_double; + my_ffi_struct_fields[2] = &ffi_type_double; + my_ffi_struct_fields[3] = NULL; + + arg_types[0] = &my_ffi_struct_type; + arg_types[1] = &my_ffi_struct_type; + arg_types[2] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &my_ffi_struct_type, + arg_types) == FFI_OK); + + args[0] = &g; + args[1] = &f; + args[2] = NULL; + ffi_call(&cif, FFI_FN(callee), &res, args); + /* { dg-output "1 2 3 1 2 3: 2 4 6" } */ + printf("res: %g %g %g\n", res.a, res.b, res.c); + /* { dg-output "\nres: 2 4 6" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, stub, NULL, code) == FFI_OK); + + res = ((my_ffi_struct(*)(struct my_ffi_struct, struct my_ffi_struct))(code))(g, f); + /* { dg-output "\n1 2 3 1 2 3: 2 4 6" } */ + printf("res: %g %g %g\n", res.a, res.b, res.c); + /* { dg-output "\nres: 2 4 6" } */ + + exit(0);; +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/promotion.c b/js/src/ctypes/libffi/testsuite/libffi.call/promotion.c new file mode 100644 index 0000000..4456161 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/promotion.c @@ -0,0 +1,59 @@ +/* Area: ffi_call + Purpose: Promotion test. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" +static int promotion(signed char sc, signed short ss, + unsigned char uc, unsigned short us) +{ + int r = (int) sc + (int) ss + (int) uc + (int) us; + + return r; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_arg rint; + signed char sc; + unsigned char uc; + signed short ss; + unsigned short us; + unsigned long ul; + + args[0] = &ffi_type_schar; + args[1] = &ffi_type_sshort; + args[2] = &ffi_type_uchar; + args[3] = &ffi_type_ushort; + values[0] = ≻ + values[1] = &ss; + values[2] = &uc; + values[3] = &us; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, + &ffi_type_sint, args) == FFI_OK); + + us = 0; + ul = 0; + + for (sc = (signed char) -127; + sc <= (signed char) 120; sc += 1) + for (ss = -30000; ss <= 30000; ss += 10000) + for (uc = (unsigned char) 0; + uc <= (unsigned char) 200; uc += 20) + for (us = 0; us <= 60000; us += 10000) + { + ul++; + ffi_call(&cif, FFI_FN(promotion), &rint, values); + CHECK((int)rint == (signed char) sc + (signed short) ss + + (unsigned char) uc + (unsigned short) us); + } + printf("%lu promotion tests run\n", ul); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/pyobjc-tc.c b/js/src/ctypes/libffi/testsuite/libffi.call/pyobjc-tc.c new file mode 100644 index 0000000..e29bd6c --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/pyobjc-tc.c @@ -0,0 +1,114 @@ +/* Area: ffi_call + Purpose: Check different structures. + Limitations: none. + PR: none. + Originator: Ronald Oussoren 20030824 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct Point { + float x; + float y; +} Point; + +typedef struct Size { + float h; + float w; +} Size; + +typedef struct Rect { + Point o; + Size s; +} Rect; + +int doit(int o, char* s, Point p, Rect r, int last) +{ + printf("CALLED WITH %d %s {%f %f} {{%f %f} {%f %f}} %d\n", + o, s, p.x, p.y, r.o.x, r.o.y, r.s.h, r.s.w, last); + return 42; +} + + +int main(void) +{ + ffi_type point_type; + ffi_type size_type; + ffi_type rect_type; + ffi_cif cif; + ffi_type* arglist[6]; + void* values[6]; + int r; + + /* + * First set up FFI types for the 3 struct types + */ + + point_type.size = 0; /*sizeof(Point);*/ + point_type.alignment = 0; /*__alignof__(Point);*/ + point_type.type = FFI_TYPE_STRUCT; + point_type.elements = malloc(3 * sizeof(ffi_type*)); + point_type.elements[0] = &ffi_type_float; + point_type.elements[1] = &ffi_type_float; + point_type.elements[2] = NULL; + + size_type.size = 0;/* sizeof(Size);*/ + size_type.alignment = 0;/* __alignof__(Size);*/ + size_type.type = FFI_TYPE_STRUCT; + size_type.elements = malloc(3 * sizeof(ffi_type*)); + size_type.elements[0] = &ffi_type_float; + size_type.elements[1] = &ffi_type_float; + size_type.elements[2] = NULL; + + rect_type.size = 0;/*sizeof(Rect);*/ + rect_type.alignment =0;/* __alignof__(Rect);*/ + rect_type.type = FFI_TYPE_STRUCT; + rect_type.elements = malloc(3 * sizeof(ffi_type*)); + rect_type.elements[0] = &point_type; + rect_type.elements[1] = &size_type; + rect_type.elements[2] = NULL; + + /* + * Create a CIF + */ + arglist[0] = &ffi_type_sint; + arglist[1] = &ffi_type_pointer; + arglist[2] = &point_type; + arglist[3] = &rect_type; + arglist[4] = &ffi_type_sint; + arglist[5] = NULL; + + r = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, + 5, &ffi_type_sint, arglist); + if (r != FFI_OK) { + abort(); + } + + + /* And call the function through the CIF */ + + { + Point p = { 1.0, 2.0 }; + Rect r = { { 9.0, 10.0}, { -1.0, -2.0 } }; + int o = 0; + int l = 42; + char* m = "myMethod"; + ffi_arg result; + + values[0] = &o; + values[1] = &m; + values[2] = &p; + values[3] = &r; + values[4] = &l; + values[5] = NULL; + + printf("CALLING WITH %d %s {%f %f} {{%f %f} {%f %f}} %d\n", + o, m, p.x, p.y, r.o.x, r.o.y, r.s.h, r.s.w, l); + + ffi_call(&cif, FFI_FN(doit), &result, values); + + printf ("The result is %d\n", (int)result); + + } + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/return_dbl.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_dbl.c new file mode 100644 index 0000000..1aab403 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/return_dbl.c @@ -0,0 +1,35 @@ +/* Area: ffi_call + Purpose: Check return value double. + Limitations: none. + PR: none. + Originator: 20050212 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static double return_dbl(double dbl) +{ + return 2 * dbl; +} +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + double dbl, rdbl; + + args[0] = &ffi_type_double; + values[0] = &dbl; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_double, args) == FFI_OK); + + for (dbl = -127.3; dbl < 127; dbl++) + { + ffi_call(&cif, FFI_FN(return_dbl), &rdbl, values); + printf ("%f vs %f\n", rdbl, return_dbl(dbl)); + CHECK(rdbl == 2 * dbl); + } + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/return_dbl1.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_dbl1.c new file mode 100644 index 0000000..0ea5d50 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/return_dbl1.c @@ -0,0 +1,43 @@ +/* Area: ffi_call + Purpose: Check return value double. + Limitations: none. + PR: none. + Originator: 20050212 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static double return_dbl(double dbl1, float fl2, unsigned int in3, double dbl4) +{ + return dbl1 + fl2 + in3 + dbl4; +} +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + double dbl1, dbl4, rdbl; + float fl2; + unsigned int in3; + args[0] = &ffi_type_double; + args[1] = &ffi_type_float; + args[2] = &ffi_type_uint; + args[3] = &ffi_type_double; + values[0] = &dbl1; + values[1] = &fl2; + values[2] = &in3; + values[3] = &dbl4; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, + &ffi_type_double, args) == FFI_OK); + dbl1 = 127.0; + fl2 = 128.0; + in3 = 255; + dbl4 = 512.7; + + ffi_call(&cif, FFI_FN(return_dbl), &rdbl, values); + printf ("%f vs %f\n", rdbl, return_dbl(dbl1, fl2, in3, dbl4)); + CHECK(rdbl == dbl1 + fl2 + in3 + dbl4); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/return_dbl2.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_dbl2.c new file mode 100644 index 0000000..b3818f8 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/return_dbl2.c @@ -0,0 +1,42 @@ +/* Area: ffi_call + Purpose: Check return value double. + Limitations: none. + PR: none. + Originator: 20050212 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static double return_dbl(double dbl1, double dbl2, unsigned int in3, double dbl4) +{ + return dbl1 + dbl2 + in3 + dbl4; +} +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + double dbl1, dbl2, dbl4, rdbl; + unsigned int in3; + args[0] = &ffi_type_double; + args[1] = &ffi_type_double; + args[2] = &ffi_type_uint; + args[3] = &ffi_type_double; + values[0] = &dbl1; + values[1] = &dbl2; + values[2] = &in3; + values[3] = &dbl4; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, + &ffi_type_double, args) == FFI_OK); + dbl1 = 127.0; + dbl2 = 128.0; + in3 = 255; + dbl4 = 512.7; + + ffi_call(&cif, FFI_FN(return_dbl), &rdbl, values); + printf ("%f vs %f\n", rdbl, return_dbl(dbl1, dbl2, in3, dbl4)); + CHECK(rdbl == dbl1 + dbl2 + in3 + dbl4); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/return_fl.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_fl.c new file mode 100644 index 0000000..fb8a09e --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/return_fl.c @@ -0,0 +1,35 @@ +/* Area: ffi_call + Purpose: Check return value float. + Limitations: none. + PR: none. + Originator: 20050212 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static float return_fl(float fl) +{ + return 2 * fl; +} +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + float fl, rfl; + + args[0] = &ffi_type_float; + values[0] = &fl; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_float, args) == FFI_OK); + + for (fl = -127.0; fl < 127; fl++) + { + ffi_call(&cif, FFI_FN(return_fl), &rfl, values); + printf ("%f vs %f\n", rfl, return_fl(fl)); + CHECK(rfl == 2 * fl); + } + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/return_fl1.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_fl1.c new file mode 100644 index 0000000..c3d92c2 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/return_fl1.c @@ -0,0 +1,36 @@ +/* Area: ffi_call + Purpose: Check return value float. + Limitations: none. + PR: none. + Originator: 20050212 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static float return_fl(float fl1, float fl2) +{ + return fl1 + fl2; +} +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + float fl1, fl2, rfl; + + args[0] = &ffi_type_float; + args[1] = &ffi_type_float; + values[0] = &fl1; + values[1] = &fl2; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, + &ffi_type_float, args) == FFI_OK); + fl1 = 127.0; + fl2 = 128.0; + + ffi_call(&cif, FFI_FN(return_fl), &rfl, values); + printf ("%f vs %f\n", rfl, return_fl(fl1, fl2)); + CHECK(rfl == fl1 + fl2); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/return_fl2.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_fl2.c new file mode 100644 index 0000000..ddb976c --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/return_fl2.c @@ -0,0 +1,49 @@ +/* Area: ffi_call + Purpose: Check return value float. + Limitations: none. + PR: none. + Originator: 20050212 */ + +/* { dg-do run } */ +#include "ffitest.h" + +/* Use volatile float to avoid false negative on ix86. See PR target/323. */ +static float return_fl(float fl1, float fl2, float fl3, float fl4) +{ + volatile float sum; + + sum = fl1 + fl2 + fl3 + fl4; + return sum; +} +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + float fl1, fl2, fl3, fl4, rfl; + volatile float sum; + + args[0] = &ffi_type_float; + args[1] = &ffi_type_float; + args[2] = &ffi_type_float; + args[3] = &ffi_type_float; + values[0] = &fl1; + values[1] = &fl2; + values[2] = &fl3; + values[3] = &fl4; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, + &ffi_type_float, args) == FFI_OK); + fl1 = 127.0; + fl2 = 128.0; + fl3 = 255.1; + fl4 = 512.7; + + ffi_call(&cif, FFI_FN(return_fl), &rfl, values); + printf ("%f vs %f\n", rfl, return_fl(fl1, fl2, fl3, fl4)); + + sum = fl1 + fl2 + fl3 + fl4; + CHECK(rfl == sum); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/return_fl3.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_fl3.c new file mode 100644 index 0000000..c37877b --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/return_fl3.c @@ -0,0 +1,42 @@ +/* Area: ffi_call + Purpose: Check return value float. + Limitations: none. + PR: none. + Originator: 20050212 */ + +/* { dg-do run } */ +#include "ffitest.h" + +static float return_fl(float fl1, float fl2, unsigned int in3, float fl4) +{ + return fl1 + fl2 + in3 + fl4; +} +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + float fl1, fl2, fl4, rfl; + unsigned int in3; + args[0] = &ffi_type_float; + args[1] = &ffi_type_float; + args[2] = &ffi_type_uint; + args[3] = &ffi_type_float; + values[0] = &fl1; + values[1] = &fl2; + values[2] = &in3; + values[3] = &fl4; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, + &ffi_type_float, args) == FFI_OK); + fl1 = 127.0; + fl2 = 128.0; + in3 = 255; + fl4 = 512.7; + + ffi_call(&cif, FFI_FN(return_fl), &rfl, values); + printf ("%f vs %f\n", rfl, return_fl(fl1, fl2, in3, fl4)); + CHECK(rfl == fl1 + fl2 + in3 + fl4); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/return_ldl.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_ldl.c new file mode 100644 index 0000000..5c2fe65 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/return_ldl.c @@ -0,0 +1,34 @@ +/* Area: ffi_call + Purpose: Check return value long double. + Limitations: none. + PR: none. + Originator: 20071113 */ + +/* { dg-do run { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */ +#include "ffitest.h" + +static long double return_ldl(long double ldl) +{ + return 2*ldl; +} +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + long double ldl, rldl; + + args[0] = &ffi_type_longdouble; + values[0] = &ldl; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_longdouble, args) == FFI_OK); + + for (ldl = -127.0; ldl < 127.0; ldl++) + { + ffi_call(&cif, FFI_FN(return_ldl), &rldl, values); + CHECK(rldl == 2 * ldl); + } + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/return_ll.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_ll.c new file mode 100644 index 0000000..ea4a1e4 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/return_ll.c @@ -0,0 +1,41 @@ +/* Area: ffi_call + Purpose: Check return value long long. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" +static long long return_ll(long long ll) +{ + return ll; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + long long rlonglong; + long long ll; + + args[0] = &ffi_type_sint64; + values[0] = ≪ + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_sint64, args) == FFI_OK); + + for (ll = 0LL; ll < 100LL; ll++) + { + ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values); + CHECK(rlonglong == ll); + } + + for (ll = 55555555555000LL; ll < 55555555555100LL; ll++) + { + ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values); + CHECK(rlonglong == ll); + } + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/return_ll1.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_ll1.c new file mode 100644 index 0000000..593e8a3 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/return_ll1.c @@ -0,0 +1,43 @@ +/* Area: ffi_call + Purpose: Check if long long are passed in the corresponding regs on ppc. + Limitations: none. + PR: 20104. + Originator: 20050222 */ + +/* { dg-do run } */ +/* { dg-options "-Wno-format" { target alpha*-dec-osf* } } */ +#include "ffitest.h" +static long long return_ll(int ll0, long long ll1, int ll2) +{ + return ll0 + ll1 + ll2; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + long long rlonglong; + long long ll1; + unsigned ll0, ll2; + + args[0] = &ffi_type_sint; + args[1] = &ffi_type_sint64; + args[2] = &ffi_type_sint; + values[0] = &ll0; + values[1] = &ll1; + values[2] = &ll2; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, + &ffi_type_sint64, args) == FFI_OK); + + ll0 = 11111111; + ll1 = 11111111111000LL; + ll2 = 11111111; + + ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values); + printf("res: %" PRIdLL ", %" PRIdLL "\n", rlonglong, ll0 + ll1 + ll2); + /* { dg-output "res: 11111133333222, 11111133333222" } */ + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/return_sc.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_sc.c new file mode 100644 index 0000000..19608ee --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/return_sc.c @@ -0,0 +1,36 @@ +/* Area: ffi_call + Purpose: Check return value signed char. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" + +static signed char return_sc(signed char sc) +{ + return sc; +} +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_arg rint; + signed char sc; + + args[0] = &ffi_type_schar; + values[0] = ≻ + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_schar, args) == FFI_OK); + + for (sc = (signed char) -127; + sc < (signed char) 127; sc++) + { + ffi_call(&cif, FFI_FN(return_sc), &rint, values); + CHECK(rint == (ffi_arg) sc); + } + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/return_sl.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_sl.c new file mode 100644 index 0000000..f0fd345 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/return_sl.c @@ -0,0 +1,38 @@ +/* Area: ffi_call + Purpose: Check if long as return type is handled correctly. + Limitations: none. + PR: none. + */ + +/* { dg-do run } */ +#include "ffitest.h" +static long return_sl(long l1, long l2) +{ + return l1 - l2; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_arg res; + unsigned long l1, l2; + + args[0] = &ffi_type_slong; + args[1] = &ffi_type_slong; + values[0] = &l1; + values[1] = &l2; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, + &ffi_type_slong, args) == FFI_OK); + + l1 = 1073741823L; + l2 = 1073741824L; + + ffi_call(&cif, FFI_FN(return_sl), &res, values); + printf("res: %ld, %ld\n", (long)res, l1 - l2); + /* { dg-output "res: -1, -1" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/return_uc.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_uc.c new file mode 100644 index 0000000..07c45de --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/return_uc.c @@ -0,0 +1,38 @@ +/* Area: ffi_call + Purpose: Check return value unsigned char. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" + +static unsigned char return_uc(unsigned char uc) +{ + return uc; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_arg rint; + + unsigned char uc; + + args[0] = &ffi_type_uchar; + values[0] = &uc; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_uchar, args) == FFI_OK); + + for (uc = (unsigned char) '\x00'; + uc < (unsigned char) '\xff'; uc++) + { + ffi_call(&cif, FFI_FN(return_uc), &rint, values); + CHECK(rint == (signed int) uc); + } + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/return_ul.c b/js/src/ctypes/libffi/testsuite/libffi.call/return_ul.c new file mode 100644 index 0000000..12b266f --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/return_ul.c @@ -0,0 +1,38 @@ +/* Area: ffi_call + Purpose: Check if unsigned long as return type is handled correctly. + Limitations: none. + PR: none. + Originator: 20060724 */ + +/* { dg-do run } */ +#include "ffitest.h" +static unsigned long return_ul(unsigned long ul1, unsigned long ul2) +{ + return ul1 + ul2; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_arg res; + unsigned long ul1, ul2; + + args[0] = &ffi_type_ulong; + args[1] = &ffi_type_ulong; + values[0] = &ul1; + values[1] = &ul2; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, + &ffi_type_ulong, args) == FFI_OK); + + ul1 = 1073741823L; + ul2 = 1073741824L; + + ffi_call(&cif, FFI_FN(return_ul), &res, values); + printf("res: %lu, %lu\n", (unsigned long)res, ul1 + ul2); + /* { dg-output "res: 2147483647, 2147483647" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/stret_large.c b/js/src/ctypes/libffi/testsuite/libffi.call/stret_large.c new file mode 100644 index 0000000..23a93b9 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/stret_large.c @@ -0,0 +1,145 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure returning with different structure size. + Depending on the ABI. Check bigger struct which overlaps + the gp and fp register count on Darwin/AIX/ppc64. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/21/2007 */ + +/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ +#include "ffitest.h" + +// 13 FPRs: 104 bytes +// 14 FPRs: 112 bytes + +typedef struct struct_108byte { + double a; + double b; + double c; + double d; + double e; + double f; + double g; + double h; + double i; + double j; + double k; + double l; + double m; + int n; +} struct_108byte; + +struct_108byte cls_struct_108byte_fn( + struct_108byte b0, + struct_108byte b1, + struct_108byte b2, + struct_108byte b3) +{ + struct_108byte result; + + result.a = b0.a + b1.a + b2.a + b3.a; + result.b = b0.b + b1.b + b2.b + b3.b; + result.c = b0.c + b1.c + b2.c + b3.c; + result.d = b0.d + b1.d + b2.d + b3.d; + result.e = b0.e + b1.e + b2.e + b3.e; + result.f = b0.f + b1.f + b2.f + b3.f; + result.g = b0.g + b1.g + b2.g + b3.g; + result.h = b0.h + b1.h + b2.h + b3.h; + result.i = b0.i + b1.i + b2.i + b3.i; + result.j = b0.j + b1.j + b2.j + b3.j; + result.k = b0.k + b1.k + b2.k + b3.k; + result.l = b0.l + b1.l + b2.l + b3.l; + result.m = b0.m + b1.m + b2.m + b3.m; + result.n = b0.n + b1.n + b2.n + b3.n; + + printf("%g %g %g %g %g %g %g %g %g %g %g %g %g %d\n", result.a, result.b, result.c, + result.d, result.e, result.f, result.g, result.h, result.i, + result.j, result.k, result.l, result.m, result.n); + + return result; +} + +static void +cls_struct_108byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata __UNUSED__) +{ + struct_108byte b0, b1, b2, b3; + + b0 = *(struct_108byte*)(args[0]); + b1 = *(struct_108byte*)(args[1]); + b2 = *(struct_108byte*)(args[2]); + b3 = *(struct_108byte*)(args[3]); + + *(struct_108byte*)resp = cls_struct_108byte_fn(b0, b1, b2, b3); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[15]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct_108byte e_dbl = { 9.0, 2.0, 6.0, 5.0, 3.0, 4.0, 8.0, 1.0, 1.0, 2.0, 3.0, 7.0, 2.0, 7 }; + struct_108byte f_dbl = { 1.0, 2.0, 3.0, 7.0, 2.0, 5.0, 6.0, 7.0, 4.0, 5.0, 7.0, 9.0, 1.0, 4 }; + struct_108byte g_dbl = { 4.0, 5.0, 7.0, 9.0, 1.0, 1.0, 2.0, 9.0, 8.0, 6.0, 1.0, 4.0, 0.0, 3 }; + struct_108byte h_dbl = { 8.0, 6.0, 1.0, 4.0, 0.0, 3.0, 3.0, 1.0, 9.0, 2.0, 6.0, 5.0, 3.0, 2 }; + struct_108byte res_dbl; + + cls_struct_fields[0] = &ffi_type_double; + cls_struct_fields[1] = &ffi_type_double; + cls_struct_fields[2] = &ffi_type_double; + cls_struct_fields[3] = &ffi_type_double; + cls_struct_fields[4] = &ffi_type_double; + cls_struct_fields[5] = &ffi_type_double; + cls_struct_fields[6] = &ffi_type_double; + cls_struct_fields[7] = &ffi_type_double; + cls_struct_fields[8] = &ffi_type_double; + cls_struct_fields[9] = &ffi_type_double; + cls_struct_fields[10] = &ffi_type_double; + cls_struct_fields[11] = &ffi_type_double; + cls_struct_fields[12] = &ffi_type_double; + cls_struct_fields[13] = &ffi_type_sint32; + cls_struct_fields[14] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = &cls_struct_type; + dbl_arg_types[3] = &cls_struct_type; + dbl_arg_types[4] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = &g_dbl; + args_dbl[3] = &h_dbl; + args_dbl[4] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_108byte_fn), &res_dbl, args_dbl); + /* { dg-output "22 15 17 25 6 13 19 18 22 15 17 25 6 16" } */ + printf("res: %g %g %g %g %g %g %g %g %g %g %g %g %g %d\n", res_dbl.a, res_dbl.b, + res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i, + res_dbl.j, res_dbl.k, res_dbl.l, res_dbl.m, res_dbl.n); + /* { dg-output "\nres: 22 15 17 25 6 13 19 18 22 15 17 25 6 16" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_108byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((struct_108byte(*)(struct_108byte, struct_108byte, + struct_108byte, struct_108byte))(code))(e_dbl, f_dbl, g_dbl, h_dbl); + /* { dg-output "\n22 15 17 25 6 13 19 18 22 15 17 25 6 16" } */ + printf("res: %g %g %g %g %g %g %g %g %g %g %g %g %g %d\n", res_dbl.a, res_dbl.b, + res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i, + res_dbl.j, res_dbl.k, res_dbl.l, res_dbl.m, res_dbl.n); + /* { dg-output "\nres: 22 15 17 25 6 13 19 18 22 15 17 25 6 16" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/stret_large2.c b/js/src/ctypes/libffi/testsuite/libffi.call/stret_large2.c new file mode 100644 index 0000000..e2599d2 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/stret_large2.c @@ -0,0 +1,148 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure returning with different structure size. + Depending on the ABI. Check bigger struct which overlaps + the gp and fp register count on Darwin/AIX/ppc64. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/21/2007 */ + +/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ +#include "ffitest.h" + +// 13 FPRs: 104 bytes +// 14 FPRs: 112 bytes + +typedef struct struct_116byte { + double a; + double b; + double c; + double d; + double e; + double f; + double g; + double h; + double i; + double j; + double k; + double l; + double m; + double n; + int o; +} struct_116byte; + +struct_116byte cls_struct_116byte_fn( + struct_116byte b0, + struct_116byte b1, + struct_116byte b2, + struct_116byte b3) +{ + struct_116byte result; + + result.a = b0.a + b1.a + b2.a + b3.a; + result.b = b0.b + b1.b + b2.b + b3.b; + result.c = b0.c + b1.c + b2.c + b3.c; + result.d = b0.d + b1.d + b2.d + b3.d; + result.e = b0.e + b1.e + b2.e + b3.e; + result.f = b0.f + b1.f + b2.f + b3.f; + result.g = b0.g + b1.g + b2.g + b3.g; + result.h = b0.h + b1.h + b2.h + b3.h; + result.i = b0.i + b1.i + b2.i + b3.i; + result.j = b0.j + b1.j + b2.j + b3.j; + result.k = b0.k + b1.k + b2.k + b3.k; + result.l = b0.l + b1.l + b2.l + b3.l; + result.m = b0.m + b1.m + b2.m + b3.m; + result.n = b0.n + b1.n + b2.n + b3.n; + result.o = b0.o + b1.o + b2.o + b3.o; + + printf("%g %g %g %g %g %g %g %g %g %g %g %g %g %g %d\n", result.a, result.b, result.c, + result.d, result.e, result.f, result.g, result.h, result.i, + result.j, result.k, result.l, result.m, result.n, result.o); + + return result; +} + +static void +cls_struct_116byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata __UNUSED__) +{ + struct_116byte b0, b1, b2, b3; + + b0 = *(struct_116byte*)(args[0]); + b1 = *(struct_116byte*)(args[1]); + b2 = *(struct_116byte*)(args[2]); + b3 = *(struct_116byte*)(args[3]); + + *(struct_116byte*)resp = cls_struct_116byte_fn(b0, b1, b2, b3); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[16]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct_116byte e_dbl = { 9.0, 2.0, 6.0, 5.0, 3.0, 4.0, 8.0, 1.0, 1.0, 2.0, 3.0, 7.0, 2.0, 5.0, 7 }; + struct_116byte f_dbl = { 1.0, 2.0, 3.0, 7.0, 2.0, 5.0, 6.0, 7.0, 4.0, 5.0, 7.0, 9.0, 1.0, 6.0, 4 }; + struct_116byte g_dbl = { 4.0, 5.0, 7.0, 9.0, 1.0, 1.0, 2.0, 9.0, 8.0, 6.0, 1.0, 4.0, 0.0, 7.0, 3 }; + struct_116byte h_dbl = { 8.0, 6.0, 1.0, 4.0, 0.0, 3.0, 3.0, 1.0, 9.0, 2.0, 6.0, 5.0, 3.0, 8.0, 2 }; + struct_116byte res_dbl; + + cls_struct_fields[0] = &ffi_type_double; + cls_struct_fields[1] = &ffi_type_double; + cls_struct_fields[2] = &ffi_type_double; + cls_struct_fields[3] = &ffi_type_double; + cls_struct_fields[4] = &ffi_type_double; + cls_struct_fields[5] = &ffi_type_double; + cls_struct_fields[6] = &ffi_type_double; + cls_struct_fields[7] = &ffi_type_double; + cls_struct_fields[8] = &ffi_type_double; + cls_struct_fields[9] = &ffi_type_double; + cls_struct_fields[10] = &ffi_type_double; + cls_struct_fields[11] = &ffi_type_double; + cls_struct_fields[12] = &ffi_type_double; + cls_struct_fields[13] = &ffi_type_double; + cls_struct_fields[14] = &ffi_type_sint32; + cls_struct_fields[15] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = &cls_struct_type; + dbl_arg_types[3] = &cls_struct_type; + dbl_arg_types[4] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = &g_dbl; + args_dbl[3] = &h_dbl; + args_dbl[4] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_116byte_fn), &res_dbl, args_dbl); + /* { dg-output "22 15 17 25 6 13 19 18 22 15 17 25 6 26 16" } */ + printf("res: %g %g %g %g %g %g %g %g %g %g %g %g %g %g %d\n", res_dbl.a, res_dbl.b, + res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i, + res_dbl.j, res_dbl.k, res_dbl.l, res_dbl.m, res_dbl.n, res_dbl.o); + /* { dg-output "\nres: 22 15 17 25 6 13 19 18 22 15 17 25 6 26 16" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_116byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((struct_116byte(*)(struct_116byte, struct_116byte, + struct_116byte, struct_116byte))(code))(e_dbl, f_dbl, g_dbl, h_dbl); + /* { dg-output "\n22 15 17 25 6 13 19 18 22 15 17 25 6 26 16" } */ + printf("res: %g %g %g %g %g %g %g %g %g %g %g %g %g %g %d\n", res_dbl.a, res_dbl.b, + res_dbl.c, res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i, + res_dbl.j, res_dbl.k, res_dbl.l, res_dbl.m, res_dbl.n, res_dbl.o); + /* { dg-output "\nres: 22 15 17 25 6 13 19 18 22 15 17 25 6 26 16" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/stret_medium.c b/js/src/ctypes/libffi/testsuite/libffi.call/stret_medium.c new file mode 100644 index 0000000..1fc6a9e --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/stret_medium.c @@ -0,0 +1,124 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure returning with different structure size. + Depending on the ABI. Check bigger struct which overlaps + the gp and fp register count on Darwin/AIX/ppc64. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/21/2007 */ + +/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ +#include "ffitest.h" + +typedef struct struct_72byte { + double a; + double b; + double c; + double d; + double e; + double f; + double g; + double h; + double i; +} struct_72byte; + +struct_72byte cls_struct_72byte_fn( + struct_72byte b0, + struct_72byte b1, + struct_72byte b2, + struct_72byte b3) +{ + struct_72byte result; + + result.a = b0.a + b1.a + b2.a + b3.a; + result.b = b0.b + b1.b + b2.b + b3.b; + result.c = b0.c + b1.c + b2.c + b3.c; + result.d = b0.d + b1.d + b2.d + b3.d; + result.e = b0.e + b1.e + b2.e + b3.e; + result.f = b0.f + b1.f + b2.f + b3.f; + result.g = b0.g + b1.g + b2.g + b3.g; + result.h = b0.h + b1.h + b2.h + b3.h; + result.i = b0.i + b1.i + b2.i + b3.i; + + printf("%g %g %g %g %g %g %g %g %g\n", result.a, result.b, result.c, + result.d, result.e, result.f, result.g, result.h, result.i); + + return result; +} + +static void +cls_struct_72byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata __UNUSED__) +{ + struct_72byte b0, b1, b2, b3; + + b0 = *(struct_72byte*)(args[0]); + b1 = *(struct_72byte*)(args[1]); + b2 = *(struct_72byte*)(args[2]); + b3 = *(struct_72byte*)(args[3]); + + *(struct_72byte*)resp = cls_struct_72byte_fn(b0, b1, b2, b3); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[10]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct_72byte e_dbl = { 9.0, 2.0, 6.0, 5.0, 3.0, 4.0, 8.0, 1.0, 7.0 }; + struct_72byte f_dbl = { 1.0, 2.0, 3.0, 7.0, 2.0, 5.0, 6.0, 7.0, 4.0 }; + struct_72byte g_dbl = { 4.0, 5.0, 7.0, 9.0, 1.0, 1.0, 2.0, 9.0, 3.0 }; + struct_72byte h_dbl = { 8.0, 6.0, 1.0, 4.0, 0.0, 3.0, 3.0, 1.0, 2.0 }; + struct_72byte res_dbl; + + cls_struct_fields[0] = &ffi_type_double; + cls_struct_fields[1] = &ffi_type_double; + cls_struct_fields[2] = &ffi_type_double; + cls_struct_fields[3] = &ffi_type_double; + cls_struct_fields[4] = &ffi_type_double; + cls_struct_fields[5] = &ffi_type_double; + cls_struct_fields[6] = &ffi_type_double; + cls_struct_fields[7] = &ffi_type_double; + cls_struct_fields[8] = &ffi_type_double; + cls_struct_fields[9] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = &cls_struct_type; + dbl_arg_types[3] = &cls_struct_type; + dbl_arg_types[4] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = &g_dbl; + args_dbl[3] = &h_dbl; + args_dbl[4] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_72byte_fn), &res_dbl, args_dbl); + /* { dg-output "22 15 17 25 6 13 19 18 16" } */ + printf("res: %g %g %g %g %g %g %g %g %g\n", res_dbl.a, res_dbl.b, res_dbl.c, + res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i); + /* { dg-output "\nres: 22 15 17 25 6 13 19 18 16" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_72byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((struct_72byte(*)(struct_72byte, struct_72byte, + struct_72byte, struct_72byte))(code))(e_dbl, f_dbl, g_dbl, h_dbl); + /* { dg-output "\n22 15 17 25 6 13 19 18 16" } */ + printf("res: %g %g %g %g %g %g %g %g %g\n", res_dbl.a, res_dbl.b, res_dbl.c, + res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i); + /* { dg-output "\nres: 22 15 17 25 6 13 19 18 16" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/stret_medium2.c b/js/src/ctypes/libffi/testsuite/libffi.call/stret_medium2.c new file mode 100644 index 0000000..cb2f2fb --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/stret_medium2.c @@ -0,0 +1,125 @@ +/* Area: ffi_call, closure_call + Purpose: Check structure returning with different structure size. + Depending on the ABI. Check bigger struct which overlaps + the gp and fp register count on Darwin/AIX/ppc64. + Limitations: none. + PR: none. + Originator: Blake Chaffin 6/21/2007 */ + +/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */ +/* { dg-options "-Wno-format" { target alpha*-dec-osf* } } */ +#include "ffitest.h" + +typedef struct struct_72byte { + double a; + double b; + double c; + double d; + double e; + double f; + double g; + double h; + long long i; +} struct_72byte; + +struct_72byte cls_struct_72byte_fn( + struct_72byte b0, + struct_72byte b1, + struct_72byte b2, + struct_72byte b3) +{ + struct_72byte result; + + result.a = b0.a + b1.a + b2.a + b3.a; + result.b = b0.b + b1.b + b2.b + b3.b; + result.c = b0.c + b1.c + b2.c + b3.c; + result.d = b0.d + b1.d + b2.d + b3.d; + result.e = b0.e + b1.e + b2.e + b3.e; + result.f = b0.f + b1.f + b2.f + b3.f; + result.g = b0.g + b1.g + b2.g + b3.g; + result.h = b0.h + b1.h + b2.h + b3.h; + result.i = b0.i + b1.i + b2.i + b3.i; + + printf("%g %g %g %g %g %g %g %g %" PRIdLL "\n", result.a, result.b, result.c, + result.d, result.e, result.f, result.g, result.h, result.i); + + return result; +} + +static void +cls_struct_72byte_gn(ffi_cif* cif __UNUSED__, void* resp, void** args, void* userdata __UNUSED__) +{ + struct_72byte b0, b1, b2, b3; + + b0 = *(struct_72byte*)(args[0]); + b1 = *(struct_72byte*)(args[1]); + b2 = *(struct_72byte*)(args[2]); + b3 = *(struct_72byte*)(args[3]); + + *(struct_72byte*)resp = cls_struct_72byte_fn(b0, b1, b2, b3); +} + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + void* args_dbl[5]; + ffi_type* cls_struct_fields[10]; + ffi_type cls_struct_type; + ffi_type* dbl_arg_types[5]; + + cls_struct_type.size = 0; + cls_struct_type.alignment = 0; + cls_struct_type.type = FFI_TYPE_STRUCT; + cls_struct_type.elements = cls_struct_fields; + + struct_72byte e_dbl = { 9.0, 2.0, 6.0, 5.0, 3.0, 4.0, 8.0, 1.0, 7 }; + struct_72byte f_dbl = { 1.0, 2.0, 3.0, 7.0, 2.0, 5.0, 6.0, 7.0, 4 }; + struct_72byte g_dbl = { 4.0, 5.0, 7.0, 9.0, 1.0, 1.0, 2.0, 9.0, 3 }; + struct_72byte h_dbl = { 8.0, 6.0, 1.0, 4.0, 0.0, 3.0, 3.0, 1.0, 2 }; + struct_72byte res_dbl; + + cls_struct_fields[0] = &ffi_type_double; + cls_struct_fields[1] = &ffi_type_double; + cls_struct_fields[2] = &ffi_type_double; + cls_struct_fields[3] = &ffi_type_double; + cls_struct_fields[4] = &ffi_type_double; + cls_struct_fields[5] = &ffi_type_double; + cls_struct_fields[6] = &ffi_type_double; + cls_struct_fields[7] = &ffi_type_double; + cls_struct_fields[8] = &ffi_type_sint64; + cls_struct_fields[9] = NULL; + + dbl_arg_types[0] = &cls_struct_type; + dbl_arg_types[1] = &cls_struct_type; + dbl_arg_types[2] = &cls_struct_type; + dbl_arg_types[3] = &cls_struct_type; + dbl_arg_types[4] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &cls_struct_type, + dbl_arg_types) == FFI_OK); + + args_dbl[0] = &e_dbl; + args_dbl[1] = &f_dbl; + args_dbl[2] = &g_dbl; + args_dbl[3] = &h_dbl; + args_dbl[4] = NULL; + + ffi_call(&cif, FFI_FN(cls_struct_72byte_fn), &res_dbl, args_dbl); + /* { dg-output "22 15 17 25 6 13 19 18 16" } */ + printf("res: %g %g %g %g %g %g %g %g %" PRIdLL "\n", res_dbl.a, res_dbl.b, res_dbl.c, + res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i); + /* { dg-output "\nres: 22 15 17 25 6 13 19 18 16" } */ + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_72byte_gn, NULL, code) == FFI_OK); + + res_dbl = ((struct_72byte(*)(struct_72byte, struct_72byte, + struct_72byte, struct_72byte))(code))(e_dbl, f_dbl, g_dbl, h_dbl); + /* { dg-output "\n22 15 17 25 6 13 19 18 16" } */ + printf("res: %g %g %g %g %g %g %g %g %" PRIdLL "\n", res_dbl.a, res_dbl.b, res_dbl.c, + res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i); + /* { dg-output "\nres: 22 15 17 25 6 13 19 18 16" } */ + + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/strlen.c b/js/src/ctypes/libffi/testsuite/libffi.call/strlen.c new file mode 100644 index 0000000..3de45de --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/strlen.c @@ -0,0 +1,44 @@ +/* Area: ffi_call + Purpose: Check strlen function call. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" + +static size_t my_strlen(char *s) +{ + return (strlen(s)); +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_arg rint; + char *s; + + args[0] = &ffi_type_pointer; + values[0] = (void*) &s; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_sint, args) == FFI_OK); + + s = "a"; + ffi_call(&cif, FFI_FN(my_strlen), &rint, values); + CHECK(rint == 1); + + s = "1234567"; + ffi_call(&cif, FFI_FN(my_strlen), &rint, values); + CHECK(rint == 7); + + s = "1234567890123456789012345"; + ffi_call(&cif, FFI_FN(my_strlen), &rint, values); + CHECK(rint == 25); + + exit (0); +} + diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/strlen_win32.c b/js/src/ctypes/libffi/testsuite/libffi.call/strlen_win32.c new file mode 100644 index 0000000..6fbcc87 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/strlen_win32.c @@ -0,0 +1,44 @@ +/* Area: ffi_call + Purpose: Check stdcall strlen call on X86_WIN32 systems. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run { target i?86-*-cygwin* i?86-*-mingw* } } */ + +#include "ffitest.h" + +static size_t __attribute__((stdcall)) my_stdcall_strlen(char *s) +{ + return (strlen(s)); +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_arg rint; + char *s; + args[0] = &ffi_type_pointer; + values[0] = (void*) &s; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_STDCALL, 1, + &ffi_type_sint, args) == FFI_OK); + + s = "a"; + ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values); + CHECK(rint == 1); + + s = "1234567"; + ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values); + CHECK(rint == 7); + + s = "1234567890123456789012345"; + ffi_call(&cif, FFI_FN(my_stdcall_strlen), &rint, values); + CHECK(rint == 25); + + printf("stdcall strlen tests passed\n"); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/struct1.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct1.c new file mode 100644 index 0000000..ea76c85 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/struct1.c @@ -0,0 +1,65 @@ +/* Area: ffi_call + Purpose: Check structures. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct +{ + unsigned char uc; + double d; + unsigned int ui; +} test_structure_1; + +static test_structure_1 struct1(test_structure_1 ts) +{ + ts.uc++; + ts.d--; + ts.ui++; + + return ts; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_type ts1_type; + ffi_type *ts1_type_elements[4]; + ts1_type.size = 0; + ts1_type.alignment = 0; + ts1_type.type = FFI_TYPE_STRUCT; + ts1_type.elements = ts1_type_elements; + ts1_type_elements[0] = &ffi_type_uchar; + ts1_type_elements[1] = &ffi_type_double; + ts1_type_elements[2] = &ffi_type_uint; + ts1_type_elements[3] = NULL; + + test_structure_1 ts1_arg; + /* This is a hack to get a properly aligned result buffer */ + test_structure_1 *ts1_result = + (test_structure_1 *) malloc (sizeof(test_structure_1)); + + args[0] = &ts1_type; + values[0] = &ts1_arg; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ts1_type, args) == FFI_OK); + + ts1_arg.uc = '\x01'; + ts1_arg.d = 3.14159; + ts1_arg.ui = 555; + + ffi_call(&cif, FFI_FN(struct1), ts1_result, values); + + CHECK(ts1_result->ui == 556); + CHECK(ts1_result->d == 3.14159 - 1); + + free (ts1_result); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/struct2.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct2.c new file mode 100644 index 0000000..14bc9fd --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/struct2.c @@ -0,0 +1,67 @@ +/* Area: ffi_call + Purpose: Check structures. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct +{ + double d1; + double d2; +} test_structure_2; + +static test_structure_2 struct2(test_structure_2 ts) +{ + ts.d1--; + ts.d2--; + + return ts; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + test_structure_2 ts2_arg; + ffi_type ts2_type; + ffi_type *ts2_type_elements[3]; + ts2_type.size = 0; + ts2_type.alignment = 0; + ts2_type.type = FFI_TYPE_STRUCT; + ts2_type.elements = ts2_type_elements; + ts2_type_elements[0] = &ffi_type_double; + ts2_type_elements[1] = &ffi_type_double; + ts2_type_elements[2] = NULL; + + + /* This is a hack to get a properly aligned result buffer */ + test_structure_2 *ts2_result = + (test_structure_2 *) malloc (sizeof(test_structure_2)); + + args[0] = &ts2_type; + values[0] = &ts2_arg; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts2_type, args) == FFI_OK); + + ts2_arg.d1 = 5.55; + ts2_arg.d2 = 6.66; + + printf ("%g\n", ts2_arg.d1); + printf ("%g\n", ts2_arg.d2); + + ffi_call(&cif, FFI_FN(struct2), ts2_result, values); + + printf ("%g\n", ts2_result->d1); + printf ("%g\n", ts2_result->d2); + + CHECK(ts2_result->d1 == 5.55 - 1); + CHECK(ts2_result->d2 == 6.66 - 1); + + free (ts2_result); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/struct3.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct3.c new file mode 100644 index 0000000..e0bb09b --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/struct3.c @@ -0,0 +1,59 @@ +/* Area: ffi_call + Purpose: Check structures. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct +{ + int si; +} test_structure_3; + +static test_structure_3 struct3(test_structure_3 ts) +{ + ts.si = -(ts.si*2); + + return ts; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + int compare_value; + ffi_type ts3_type; + ffi_type *ts3_type_elements[2]; + ts3_type.size = 0; + ts3_type.alignment = 0; + ts3_type.type = FFI_TYPE_STRUCT; + ts3_type.elements = ts3_type_elements; + ts3_type_elements[0] = &ffi_type_sint; + ts3_type_elements[1] = NULL; + + test_structure_3 ts3_arg; + test_structure_3 *ts3_result = + (test_structure_3 *) malloc (sizeof(test_structure_3)); + + args[0] = &ts3_type; + values[0] = &ts3_arg; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ts3_type, args) == FFI_OK); + + ts3_arg.si = -123; + compare_value = ts3_arg.si; + + ffi_call(&cif, FFI_FN(struct3), ts3_result, values); + + printf ("%d %d\n", ts3_result->si, -(compare_value*2)); + + CHECK(ts3_result->si == -(compare_value*2)); + + free (ts3_result); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/struct4.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct4.c new file mode 100644 index 0000000..0ad0a83 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/struct4.c @@ -0,0 +1,63 @@ +/* Area: ffi_call + Purpose: Check structures. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct +{ + unsigned ui1; + unsigned ui2; + unsigned ui3; +} test_structure_4; + +static test_structure_4 struct4(test_structure_4 ts) +{ + ts.ui3 = ts.ui1 * ts.ui2 * ts.ui3; + + return ts; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_type ts4_type; + ffi_type *ts4_type_elements[4]; + ts4_type.size = 0; + ts4_type.alignment = 0; + ts4_type.type = FFI_TYPE_STRUCT; + test_structure_4 ts4_arg; + ts4_type.elements = ts4_type_elements; + ts4_type_elements[0] = &ffi_type_uint; + ts4_type_elements[1] = &ffi_type_uint; + ts4_type_elements[2] = &ffi_type_uint; + ts4_type_elements[3] = NULL; + + + /* This is a hack to get a properly aligned result buffer */ + test_structure_4 *ts4_result = + (test_structure_4 *) malloc (sizeof(test_structure_4)); + + args[0] = &ts4_type; + values[0] = &ts4_arg; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts4_type, args) == FFI_OK); + + ts4_arg.ui1 = 2; + ts4_arg.ui2 = 3; + ts4_arg.ui3 = 4; + + ffi_call (&cif, FFI_FN(struct4), ts4_result, values); + + CHECK(ts4_result->ui3 == 2U * 3U * 4U); + + + free (ts4_result); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/struct5.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct5.c new file mode 100644 index 0000000..c03cc97 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/struct5.c @@ -0,0 +1,65 @@ +/* Area: ffi_call + Purpose: Check structures. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" +typedef struct +{ + char c1; + char c2; +} test_structure_5; + +static test_structure_5 struct5(test_structure_5 ts1, test_structure_5 ts2) +{ + ts1.c1 += ts2.c1; + ts1.c2 -= ts2.c2; + + return ts1; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_type ts5_type; + ffi_type *ts5_type_elements[3]; + ts5_type.size = 0; + ts5_type.alignment = 0; + ts5_type.type = FFI_TYPE_STRUCT; + ts5_type.elements = ts5_type_elements; + ts5_type_elements[0] = &ffi_type_schar; + ts5_type_elements[1] = &ffi_type_schar; + ts5_type_elements[2] = NULL; + + test_structure_5 ts5_arg1, ts5_arg2; + + /* This is a hack to get a properly aligned result buffer */ + test_structure_5 *ts5_result = + (test_structure_5 *) malloc (sizeof(test_structure_5)); + + args[0] = &ts5_type; + args[1] = &ts5_type; + values[0] = &ts5_arg1; + values[1] = &ts5_arg2; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ts5_type, args) == FFI_OK); + + ts5_arg1.c1 = 2; + ts5_arg1.c2 = 6; + ts5_arg2.c1 = 5; + ts5_arg2.c2 = 3; + + ffi_call (&cif, FFI_FN(struct5), ts5_result, values); + + CHECK(ts5_result->c1 == 7); + CHECK(ts5_result->c2 == 3); + + + free (ts5_result); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/struct6.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct6.c new file mode 100644 index 0000000..83db9af --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/struct6.c @@ -0,0 +1,64 @@ +/* Area: ffi_call + Purpose: Check structures. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" +typedef struct +{ + float f; + double d; +} test_structure_6; + +static test_structure_6 struct6 (test_structure_6 ts) +{ + ts.f += 1; + ts.d += 1; + + return ts; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_type ts6_type; + ffi_type *ts6_type_elements[3]; + ts6_type.size = 0; + ts6_type.alignment = 0; + ts6_type.type = FFI_TYPE_STRUCT; + ts6_type.elements = ts6_type_elements; + ts6_type_elements[0] = &ffi_type_float; + ts6_type_elements[1] = &ffi_type_double; + ts6_type_elements[2] = NULL; + + + test_structure_6 ts6_arg; + + /* This is a hack to get a properly aligned result buffer */ + test_structure_6 *ts6_result = + (test_structure_6 *) malloc (sizeof(test_structure_6)); + + args[0] = &ts6_type; + values[0] = &ts6_arg; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts6_type, args) == FFI_OK); + + ts6_arg.f = 5.55f; + ts6_arg.d = 6.66; + + printf ("%g\n", ts6_arg.f); + printf ("%g\n", ts6_arg.d); + + ffi_call(&cif, FFI_FN(struct6), ts6_result, values); + + CHECK(ts6_result->f == 5.55f + 1); + CHECK(ts6_result->d == 6.66 + 1); + + free (ts6_result); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/struct7.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct7.c new file mode 100644 index 0000000..58aac4c --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/struct7.c @@ -0,0 +1,74 @@ +/* Area: ffi_call + Purpose: Check structures. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" +typedef struct +{ + float f1; + float f2; + double d; +} test_structure_7; + +static test_structure_7 struct7 (test_structure_7 ts) +{ + ts.f1 += 1; + ts.f2 += 1; + ts.d += 1; + + return ts; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_type ts7_type; + ffi_type *ts7_type_elements[4]; + ts7_type.size = 0; + ts7_type.alignment = 0; + ts7_type.type = FFI_TYPE_STRUCT; + ts7_type.elements = ts7_type_elements; + ts7_type_elements[0] = &ffi_type_float; + ts7_type_elements[1] = &ffi_type_float; + ts7_type_elements[2] = &ffi_type_double; + ts7_type_elements[3] = NULL; + + + test_structure_7 ts7_arg; + + /* This is a hack to get a properly aligned result buffer */ + test_structure_7 *ts7_result = + (test_structure_7 *) malloc (sizeof(test_structure_7)); + + args[0] = &ts7_type; + values[0] = &ts7_arg; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts7_type, args) == FFI_OK); + + ts7_arg.f1 = 5.55f; + ts7_arg.f2 = 55.5f; + ts7_arg.d = 6.66; + + printf ("%g\n", ts7_arg.f1); + printf ("%g\n", ts7_arg.f2); + printf ("%g\n", ts7_arg.d); + + ffi_call(&cif, FFI_FN(struct7), ts7_result, values); + + printf ("%g\n", ts7_result->f1); + printf ("%g\n", ts7_result->f2); + printf ("%g\n", ts7_result->d); + + CHECK(ts7_result->f1 == 5.55f + 1); + CHECK(ts7_result->f2 == 55.5f + 1); + CHECK(ts7_result->d == 6.66 + 1); + + free (ts7_result); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/struct8.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct8.c new file mode 100644 index 0000000..c773ac7 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/struct8.c @@ -0,0 +1,80 @@ +/* Area: ffi_call + Purpose: Check structures. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" +typedef struct +{ + float f1; + float f2; + float f3; + float f4; +} test_structure_8; + +static test_structure_8 struct8 (test_structure_8 ts) +{ + ts.f1 += 1; + ts.f2 += 1; + ts.f3 += 1; + ts.f4 += 1; + + return ts; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_type ts8_type; + ffi_type *ts8_type_elements[5]; + ts8_type.size = 0; + ts8_type.alignment = 0; + ts8_type.type = FFI_TYPE_STRUCT; + ts8_type.elements = ts8_type_elements; + ts8_type_elements[0] = &ffi_type_float; + ts8_type_elements[1] = &ffi_type_float; + ts8_type_elements[2] = &ffi_type_float; + ts8_type_elements[3] = &ffi_type_float; + ts8_type_elements[4] = NULL; + + test_structure_8 ts8_arg; + + /* This is a hack to get a properly aligned result buffer */ + test_structure_8 *ts8_result = + (test_structure_8 *) malloc (sizeof(test_structure_8)); + + args[0] = &ts8_type; + values[0] = &ts8_arg; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts8_type, args) == FFI_OK); + + ts8_arg.f1 = 5.55f; + ts8_arg.f2 = 55.5f; + ts8_arg.f3 = -5.55f; + ts8_arg.f4 = -55.5f; + + printf ("%g\n", ts8_arg.f1); + printf ("%g\n", ts8_arg.f2); + printf ("%g\n", ts8_arg.f3); + printf ("%g\n", ts8_arg.f4); + + ffi_call(&cif, FFI_FN(struct8), ts8_result, values); + + printf ("%g\n", ts8_result->f1); + printf ("%g\n", ts8_result->f2); + printf ("%g\n", ts8_result->f3); + printf ("%g\n", ts8_result->f4); + + CHECK(ts8_result->f1 == 5.55f + 1); + CHECK(ts8_result->f2 == 55.5f + 1); + CHECK(ts8_result->f3 == -5.55f + 1); + CHECK(ts8_result->f4 == -55.5f + 1); + + free (ts8_result); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/struct9.c b/js/src/ctypes/libffi/testsuite/libffi.call/struct9.c new file mode 100644 index 0000000..f30091f --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/struct9.c @@ -0,0 +1,67 @@ +/* Area: ffi_call + Purpose: Check structures. + Limitations: none. + PR: none. + Originator: From the original ffitest.c */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct +{ + float f; + int i; +} test_structure_9; + +static test_structure_9 struct9 (test_structure_9 ts) +{ + ts.f += 1; + ts.i += 1; + + return ts; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_type ts9_type; + ffi_type *ts9_type_elements[3]; + ts9_type.size = 0; + ts9_type.alignment = 0; + ts9_type.type = FFI_TYPE_STRUCT; + ts9_type.elements = ts9_type_elements; + ts9_type_elements[0] = &ffi_type_float; + ts9_type_elements[1] = &ffi_type_sint; + ts9_type_elements[2] = NULL; + + test_structure_9 ts9_arg; + + /* This is a hack to get a properly aligned result buffer */ + test_structure_9 *ts9_result = + (test_structure_9 *) malloc (sizeof(test_structure_9)); + + args[0] = &ts9_type; + values[0] = &ts9_arg; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ts9_type, args) == FFI_OK); + + ts9_arg.f = 5.55f; + ts9_arg.i = 5; + + printf ("%g\n", ts9_arg.f); + printf ("%d\n", ts9_arg.i); + + ffi_call(&cif, FFI_FN(struct9), ts9_result, values); + + printf ("%g\n", ts9_result->f); + printf ("%d\n", ts9_result->i); + + CHECK(ts9_result->f == 5.55f + 1); + CHECK(ts9_result->i == 5 + 1); + + free (ts9_result); + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.call/testclosure.c b/js/src/ctypes/libffi/testsuite/libffi.call/testclosure.c new file mode 100644 index 0000000..161cc89 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.call/testclosure.c @@ -0,0 +1,70 @@ +/* Area: closure_call + Purpose: Check return value float. + Limitations: none. + PR: 41908. + Originator: 20091102 */ + +/* { dg-do run } */ +#include "ffitest.h" + +typedef struct cls_struct_combined { + float a; + float b; + float c; + float d; +} cls_struct_combined; + +void cls_struct_combined_fn(struct cls_struct_combined arg) +{ + printf("%g %g %g %g\n", + arg.a, arg.b, + arg.c, arg.d); + fflush(stdout); +} + +static void +cls_struct_combined_gn(ffi_cif* cif __UNUSED__, void* resp __UNUSED__, + void** args, void* userdata __UNUSED__) +{ + struct cls_struct_combined a0; + + a0 = *(struct cls_struct_combined*)(args[0]); + + cls_struct_combined_fn(a0); +} + + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type* cls_struct_fields0[5]; + ffi_type cls_struct_type0; + ffi_type* dbl_arg_types[5]; + + cls_struct_type0.size = 0; + cls_struct_type0.alignment = 0; + cls_struct_type0.type = FFI_TYPE_STRUCT; + cls_struct_type0.elements = cls_struct_fields0; + + struct cls_struct_combined g_dbl = {4.0, 5.0, 1.0, 8.0}; + + cls_struct_fields0[0] = &ffi_type_float; + cls_struct_fields0[1] = &ffi_type_float; + cls_struct_fields0[2] = &ffi_type_float; + cls_struct_fields0[3] = &ffi_type_float; + cls_struct_fields0[4] = NULL; + + dbl_arg_types[0] = &cls_struct_type0; + dbl_arg_types[1] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_void, + dbl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_combined_gn, NULL, code) == FFI_OK); + + ((void(*)(cls_struct_combined)) (code))(g_dbl); + /* { dg-output "4 5 1 8" } */ + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.special/ffitestcxx.h b/js/src/ctypes/libffi/testsuite/libffi.special/ffitestcxx.h new file mode 100644 index 0000000..83f5442 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.special/ffitestcxx.h @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include "fficonfig.h" + +#define MAX_ARGS 256 + + +/* Define __UNUSED__ that also other compilers than gcc can run the tests. */ +#undef __UNUSED__ +#if defined(__GNUC__) +#define __UNUSED__ __attribute__((__unused__)) +#else +#define __UNUSED__ +#endif + +#define CHECK(x) (!(x) ? abort() : (void)0) + +/* Prefer MAP_ANON(YMOUS) to /dev/zero, since we don't need to keep a + file open. */ +#ifdef HAVE_MMAP_ANON +# undef HAVE_MMAP_DEV_ZERO + +# include +# ifndef MAP_FAILED +# define MAP_FAILED -1 +# endif +# if !defined (MAP_ANONYMOUS) && defined (MAP_ANON) +# define MAP_ANONYMOUS MAP_ANON +# endif +# define USING_MMAP + +#endif + +#ifdef HAVE_MMAP_DEV_ZERO + +# include +# ifndef MAP_FAILED +# define MAP_FAILED -1 +# endif +# define USING_MMAP + +#endif + + +/* MinGW kludge. */ +#ifdef _WIN64 +#define PRIdLL "I64d" +#define PRIuLL "I64u" +#else +#define PRIdLL "lld" +#define PRIuLL "llu" +#endif + +#ifdef USING_MMAP +static inline void * +allocate_mmap (size_t size) +{ + void *page; +#if defined (HAVE_MMAP_DEV_ZERO) + static int dev_zero_fd = -1; +#endif + +#ifdef HAVE_MMAP_DEV_ZERO + if (dev_zero_fd == -1) + { + dev_zero_fd = open ("/dev/zero", O_RDONLY); + if (dev_zero_fd == -1) + { + perror ("open /dev/zero: %m"); + exit (1); + } + } +#endif + + +#ifdef HAVE_MMAP_ANON + page = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +#endif +#ifdef HAVE_MMAP_DEV_ZERO + page = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE, dev_zero_fd, 0); +#endif + + if (page == (char *) MAP_FAILED) + { + perror ("virtual memory exhausted"); + exit (1); + } + + return page; +} + +#endif diff --git a/js/src/ctypes/libffi/testsuite/libffi.special/special.exp b/js/src/ctypes/libffi/testsuite/libffi.special/special.exp new file mode 100644 index 0000000..e167e86 --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.special/special.exp @@ -0,0 +1,37 @@ +# Copyright (C) 2003, 2006, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING3. If not see +# . + +load_lib libffi-dg.exp + +dg-init +libffi-init + +global srcdir subdir + +global cxx_options + +set cxx_options " -shared-libgcc -lstdc++" + +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.cc]] $cxx_options "-O0 -W -Wall" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.cc]] $cxx_options "-O2" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.cc]] $cxx_options "-O3" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.cc]] $cxx_options "-Os" + +dg-finish + +# Local Variables: +# tcl-indent-level:4 +# End: diff --git a/js/src/ctypes/libffi/testsuite/libffi.special/unwindtest.cc b/js/src/ctypes/libffi/testsuite/libffi.special/unwindtest.cc new file mode 100644 index 0000000..d7ffd4a --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.special/unwindtest.cc @@ -0,0 +1,124 @@ +/* Area: ffi_closure, unwind info + Purpose: Check if the unwind information is passed correctly. + Limitations: none. + PR: none. + Originator: Jeff Sturm */ + +/* { dg-do run } */ +#include "ffitestcxx.h" + +#if defined HAVE_STDINT_H +#include +#endif + +#if defined HAVE_INTTYPES_H +#include +#endif + +void +closure_test_fn(ffi_cif* cif __UNUSED__, void* resp __UNUSED__, + void** args __UNUSED__, void* userdata __UNUSED__) +{ + throw 9; +} + +typedef void (*closure_test_type)(); + +void closure_test_fn1(ffi_cif* cif __UNUSED__, void* resp, + void** args, void* userdata __UNUSED__) + { + *(ffi_arg*)resp = + (int)*(float *)args[0] +(int)(*(float *)args[1]) + + (int)(*(float *)args[2]) + (int)*(float *)args[3] + + (int)(*(signed short *)args[4]) + (int)(*(float *)args[5]) + + (int)*(float *)args[6] + (int)(*(int *)args[7]) + + (int)(*(double*)args[8]) + (int)*(int *)args[9] + + (int)(*(int *)args[10]) + (int)(*(float *)args[11]) + + (int)*(int *)args[12] + (int)(*(int *)args[13]) + + (int)(*(int *)args[14]) + *(int *)args[15] + (int)(intptr_t)userdata; + + printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d: %d\n", + (int)*(float *)args[0], (int)(*(float *)args[1]), + (int)(*(float *)args[2]), (int)*(float *)args[3], + (int)(*(signed short *)args[4]), (int)(*(float *)args[5]), + (int)*(float *)args[6], (int)(*(int *)args[7]), + (int)(*(double *)args[8]), (int)*(int *)args[9], + (int)(*(int *)args[10]), (int)(*(float *)args[11]), + (int)*(int *)args[12], (int)(*(int *)args[13]), + (int)(*(int *)args[14]), *(int *)args[15], + (int)(intptr_t)userdata, (int)*(ffi_arg*)resp); + + throw (int)*(ffi_arg*)resp; +} + +typedef int (*closure_test_type1)(float, float, float, float, signed short, + float, float, int, double, int, int, float, + int, int, int, int); + +int main (void) +{ + ffi_cif cif; + void *code; + ffi_closure *pcl = (ffi_closure *)ffi_closure_alloc(sizeof(ffi_closure), &code); + ffi_type * cl_arg_types[17]; + + { + cl_arg_types[1] = NULL; + + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, + &ffi_type_void, cl_arg_types) == FFI_OK); + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn, NULL, code) == FFI_OK); + + try + { + (*((closure_test_type)(code)))(); + } catch (int exception_code) + { + CHECK(exception_code == 9); + } + + printf("part one OK\n"); + /* { dg-output "part one OK" } */ + } + + { + + cl_arg_types[0] = &ffi_type_float; + cl_arg_types[1] = &ffi_type_float; + cl_arg_types[2] = &ffi_type_float; + cl_arg_types[3] = &ffi_type_float; + cl_arg_types[4] = &ffi_type_sshort; + cl_arg_types[5] = &ffi_type_float; + cl_arg_types[6] = &ffi_type_float; + cl_arg_types[7] = &ffi_type_uint; + cl_arg_types[8] = &ffi_type_double; + cl_arg_types[9] = &ffi_type_uint; + cl_arg_types[10] = &ffi_type_uint; + cl_arg_types[11] = &ffi_type_float; + cl_arg_types[12] = &ffi_type_uint; + cl_arg_types[13] = &ffi_type_uint; + cl_arg_types[14] = &ffi_type_uint; + cl_arg_types[15] = &ffi_type_uint; + cl_arg_types[16] = NULL; + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 16, + &ffi_type_sint, cl_arg_types) == FFI_OK); + + CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_fn1, + (void *) 3 /* userdata */, code) == FFI_OK); + try + { + (*((closure_test_type1)code)) + (1.1, 2.2, 3.3, 4.4, 127, 5.5, 6.6, 8, 9, 10, 11, 12.0, 13, + 19, 21, 1); + /* { dg-output "\n1 2 3 4 127 5 6 8 9 10 11 12 13 19 21 1 3: 255" } */ + } catch (int exception_code) + { + CHECK(exception_code == 255); + } + printf("part two OK\n"); + /* { dg-output "\npart two OK" } */ + } + exit(0); +} diff --git a/js/src/ctypes/libffi/testsuite/libffi.special/unwindtest_ffi_call.cc b/js/src/ctypes/libffi/testsuite/libffi.special/unwindtest_ffi_call.cc new file mode 100644 index 0000000..29739cd --- /dev/null +++ b/js/src/ctypes/libffi/testsuite/libffi.special/unwindtest_ffi_call.cc @@ -0,0 +1,53 @@ +/* Area: ffi_call, unwind info + Purpose: Check if the unwind information is passed correctly. + Limitations: none. + PR: none. + Originator: Andreas Tobler 20061213 */ + +/* { dg-do run } */ +#include "ffitestcxx.h" + +static int checking(int a __UNUSED__, short b __UNUSED__, + signed char c __UNUSED__) +{ + throw 9; +} + +int main (void) +{ + ffi_cif cif; + ffi_type *args[MAX_ARGS]; + void *values[MAX_ARGS]; + ffi_arg rint; + + signed int si; + signed short ss; + signed char sc; + + args[0] = &ffi_type_sint; + values[0] = &si; + args[1] = &ffi_type_sshort; + values[1] = &ss; + args[2] = &ffi_type_schar; + values[2] = ≻ + + /* Initialize the cif */ + CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, + &ffi_type_sint, args) == FFI_OK); + + si = -6; + ss = -12; + sc = -1; + { + try + { + ffi_call(&cif, FFI_FN(checking), &rint, values); + } catch (int exception_code) + { + CHECK(exception_code == 9); + } + printf("part one OK\n"); + /* { dg-output "part one OK" } */ + } + exit(0); +} diff --git a/js/src/ctypes/libffi/texinfo.tex b/js/src/ctypes/libffi/texinfo.tex new file mode 100644 index 0000000..ff2c406 --- /dev/null +++ b/js/src/ctypes/libffi/texinfo.tex @@ -0,0 +1,7210 @@ +% texinfo.tex -- TeX macros to handle Texinfo files. +% +% Load plain if necessary, i.e., if running under initex. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi +% +\def\texinfoversion{2005-07-05.19} +% +% Copyright (C) 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, +% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software +% Foundation, Inc. +% +% This texinfo.tex file is free software; you can redistribute it and/or +% modify it under the terms of the GNU General Public License as +% published by the Free Software Foundation; either version 2, or (at +% your option) any later version. +% +% This texinfo.tex file 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 +% General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this texinfo.tex file; see the file COPYING. If not, write +% to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +% Boston, MA 02110-1301, USA. +% +% As a special exception, when this file is read by TeX when processing +% a Texinfo source document, you may use the result without +% restriction. (This has been our intent since Texinfo was invented.) +% +% Please try the latest version of texinfo.tex before submitting bug +% reports; you can get the latest version from: +% http://www.gnu.org/software/texinfo/ (the Texinfo home page), or +% ftp://tug.org/tex/texinfo.tex +% (and all CTAN mirrors, see http://www.ctan.org). +% The texinfo.tex in any given distribution could well be out +% of date, so if that's what you're using, please check. +% +% Send bug reports to bug-texinfo@gnu.org. Please include including a +% complete document in each bug report with which we can reproduce the +% problem. Patches are, of course, greatly appreciated. +% +% To process a Texinfo manual with TeX, it's most reliable to use the +% texi2dvi shell script that comes with the distribution. For a simple +% manual foo.texi, however, you can get away with this: +% tex foo.texi +% texindex foo.?? +% tex foo.texi +% tex foo.texi +% dvips foo.dvi -o # or whatever; this makes foo.ps. +% The extra TeX runs get the cross-reference information correct. +% Sometimes one run after texindex suffices, and sometimes you need more +% than two; texi2dvi does it as many times as necessary. +% +% It is possible to adapt texinfo.tex for other languages, to some +% extent. You can get the existing language-specific files from the +% full Texinfo distribution. +% +% The GNU Texinfo home page is http://www.gnu.org/software/texinfo. + + +\message{Loading texinfo [version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}% + \catcode`+=\active \catcode`\_=\active} + +\message{Basics,} +\chardef\other=12 + +% We never want plain's \outer definition of \+ in Texinfo. +% For @tex, we can use \tabalign. +\let\+ = \relax + +% Save some plain tex macros whose names we will redefine. +\let\ptexb=\b +\let\ptexbullet=\bullet +\let\ptexc=\c +\let\ptexcomma=\, +\let\ptexdot=\. +\let\ptexdots=\dots +\let\ptexend=\end +\let\ptexequiv=\equiv +\let\ptexexclam=\! +\let\ptexfootnote=\footnote +\let\ptexgtr=> +\let\ptexhat=^ +\let\ptexi=\i +\let\ptexindent=\indent +\let\ptexinsert=\insert +\let\ptexlbrace=\{ +\let\ptexless=< +\let\ptexnewwrite\newwrite +\let\ptexnoindent=\noindent +\let\ptexplus=+ +\let\ptexrbrace=\} +\let\ptexslash=\/ +\let\ptexstar=\* +\let\ptext=\t + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Pre-3.0. +\else + \def\linenumber{l.\the\inputlineno:\space} +\fi + +% Set up fixed words for English if not already set. +\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi +\ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi +\ifx\putwordfile\undefined \gdef\putwordfile{file}\fi +\ifx\putwordin\undefined \gdef\putwordin{in}\fi +\ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi +\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi +\ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi +\ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi +\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi +\ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi +\ifx\putwordof\undefined \gdef\putwordof{of}\fi +\ifx\putwordon\undefined \gdef\putwordon{on}\fi +\ifx\putwordpage\undefined \gdef\putwordpage{page}\fi +\ifx\putwordsection\undefined \gdef\putwordsection{section}\fi +\ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi +\ifx\putwordsee\undefined \gdef\putwordsee{see}\fi +\ifx\putwordSee\undefined \gdef\putwordSee{See}\fi +\ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi +\ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi +% +\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi +\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi +\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi +\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi +\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi +\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi +\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi +\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi +\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi +\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi +\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi +\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi +% +\ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi +\ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi +\ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi +\ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi +\ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi + +% In some macros, we cannot use the `\? notation---the left quote is +% in some cases the escape char. +\chardef\backChar = `\\ +\chardef\colonChar = `\: +\chardef\commaChar = `\, +\chardef\dotChar = `\. +\chardef\exclamChar= `\! +\chardef\plusChar = `\+ +\chardef\questChar = `\? +\chardef\semiChar = `\; +\chardef\underChar = `\_ + +\chardef\spaceChar = `\ % +\chardef\spacecat = 10 +\def\spaceisspace{\catcode\spaceChar=\spacecat} + +{% for help with debugging. + % example usage: \expandafter\show\activebackslash + \catcode`\! = 0 \catcode`\\ = \active + !global!def!activebackslash{\} +} + +% Ignore a token. +% +\def\gobble#1{} + +% The following is used inside several \edef's. +\def\makecsname#1{\expandafter\noexpand\csname#1\endcsname} + +% Hyphenation fixes. +\hyphenation{ + Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script + ap-pen-dix bit-map bit-maps + data-base data-bases eshell fall-ing half-way long-est man-u-script + man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm + par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces + spell-ing spell-ings + stand-alone strong-est time-stamp time-stamps which-ever white-space + wide-spread wrap-around +} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen\bindingoffset +\newdimen\normaloffset +\newdimen\pagewidth \newdimen\pageheight + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. We also make +% some effort to order the tracing commands to reduce output in the log +% file; cf. trace.sty in LaTeX. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\def\loggingall{% + \tracingstats2 + \tracingpages1 + \tracinglostchars2 % 2 gives us more in etex + \tracingparagraphs1 + \tracingoutput1 + \tracingmacros2 + \tracingrestores1 + \showboxbreadth\maxdimen \showboxdepth\maxdimen + \ifx\eTeXversion\undefined\else % etex gives us more logging + \tracingscantokens1 + \tracingifs1 + \tracinggroups1 + \tracingnesting2 + \tracingassigns1 + \fi + \tracingcommands3 % 3 gives us more in etex + \errorcontextlines16 +}% + +% add check for \lastpenalty to plain's definitions. If the last thing +% we did was a \nobreak, we don't want to insert more space. +% +\def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount + \removelastskip\penalty-50\smallskip\fi\fi} +\def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount + \removelastskip\penalty-100\medskip\fi\fi} +\def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount + \removelastskip\penalty-200\bigskip\fi\fi} + +% For @cropmarks command. +% Do @cropmarks to get crop marks. +% +\newif\ifcropmarks +\let\cropmarks = \cropmarkstrue +% +% Dimensions to add cropmarks at corners. +% Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines +\newdimen\cornerlong \cornerlong=1pc +\newdimen\cornerthick \cornerthick=.3pt +\newdimen\topandbottommargin \topandbottommargin=.75in + +% Main output routine. +\chardef\PAGE = 255 +\output = {\onepageout{\pagecontents\PAGE}} + +\newbox\headlinebox +\newbox\footlinebox + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions, but you have to call it yourself. +\def\onepageout#1{% + \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi + % + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + % + % Do this outside of the \shipout so @code etc. will be expanded in + % the headline as they should be, not taken literally (outputting ''code). + \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% + \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% + % + {% + % Have to do this stuff outside the \shipout because we want it to + % take effect in \write's, yet the group defined by the \vbox ends + % before the \shipout runs. + % + \indexdummies % don't expand commands in the output. + \shipout\vbox{% + % Do this early so pdf references go to the beginning of the page. + \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi + % + \ifcropmarks \vbox to \outervsize\bgroup + \hsize = \outerhsize + \vskip-\topandbottommargin + \vtop to0pt{% + \line{\ewtop\hfil\ewtop}% + \nointerlineskip + \line{% + \vbox{\moveleft\cornerthick\nstop}% + \hfill + \vbox{\moveright\cornerthick\nstop}% + }% + \vss}% + \vskip\topandbottommargin + \line\bgroup + \hfil % center the page within the outer (page) hsize. + \ifodd\pageno\hskip\bindingoffset\fi + \vbox\bgroup + \fi + % + \unvbox\headlinebox + \pagebody{#1}% + \ifdim\ht\footlinebox > 0pt + % Only leave this space if the footline is nonempty. + % (We lessened \vsize for it in \oddfootingxxx.) + % The \baselineskip=24pt in plain's \makefootline has no effect. + \vskip 2\baselineskip + \unvbox\footlinebox + \fi + % + \ifcropmarks + \egroup % end of \vbox\bgroup + \hfil\egroup % end of (centering) \line\bgroup + \vskip\topandbottommargin plus1fill minus1fill + \boxmaxdepth = \cornerthick + \vbox to0pt{\vss + \line{% + \vbox{\moveleft\cornerthick\nsbot}% + \hfill + \vbox{\moveright\cornerthick\nsbot}% + }% + \nointerlineskip + \line{\ewbot\hfil\ewbot}% + }% + \egroup % \vbox from first cropmarks clause + \fi + }% end of \shipout\vbox + }% end of group with \indexdummies + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi +} + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg{\parseargusing{}} +\def\parseargusing#1#2{% + \def\next{#2}% + \begingroup + \obeylines + \spaceisspace + #1% + \parseargline\empty% Insert the \empty token, see \finishparsearg below. +} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + \argremovecomment #1\comment\ArgTerm% + }% +} + +% First remove any @comment, then any @c comment. +\def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm} +\def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm} + +% Each occurence of `\^^M' or `\^^M' is replaced by a single space. +% +% \argremovec might leave us with trailing space, e.g., +% @end itemize @c foo +% This space token undergoes the same procedure and is eventually removed +% by \finishparsearg. +% +\def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M} +\def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M} +\def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{% + \def\temp{#3}% + \ifx\temp\empty + % We cannot use \next here, as it holds the macro to run; + % thus we reuse \temp. + \let\temp\finishparsearg + \else + \let\temp\argcheckspaces + \fi + % Put the space token in: + \temp#1 #3\ArgTerm +} + +% If a _delimited_ argument is enclosed in braces, they get stripped; so +% to get _exactly_ the rest of the line, we had to prevent such situation. +% We prepended an \empty token at the very beginning and we expand it now, +% just before passing the control to \next. +% (Similarily, we have to think about #3 of \argcheckspacesY above: it is +% either the null string, or it ends with \^^M---thus there is no danger +% that a pair of braces would be stripped. +% +% But first, we have to remove the trailing space token. +% +\def\finishparsearg#1 \ArgTerm{\expandafter\next\expandafter{#1}} + +% \parseargdef\foo{...} +% is roughly equivalent to +% \def\foo{\parsearg\Xfoo} +% \def\Xfoo#1{...} +% +% Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my +% favourite TeX trick. --kasal, 16nov03 + +\def\parseargdef#1{% + \expandafter \doparseargdef \csname\string#1\endcsname #1% +} +\def\doparseargdef#1#2{% + \def#2{\parsearg#1}% + \def#1##1% +} + +% Several utility definitions with active space: +{ + \obeyspaces + \gdef\obeyedspace{ } + + % Make each space character in the input produce a normal interword + % space in the output. Don't allow a line break at this space, as this + % is used only in environments like @example, where each line of input + % should produce a line of output anyway. + % + \gdef\sepspaces{\obeyspaces\let =\tie} + + % If an index command is used in an @example environment, any spaces + % therein should become regular spaces in the raw index file, not the + % expansion of \tie (\leavevmode \penalty \@M \ ). + \gdef\unsepspaces{\let =\space} +} + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +% Define the framework for environments in texinfo.tex. It's used like this: +% +% \envdef\foo{...} +% \def\Efoo{...} +% +% It's the responsibility of \envdef to insert \begingroup before the +% actual body; @end closes the group after calling \Efoo. \envdef also +% defines \thisenv, so the current environment is known; @end checks +% whether the environment name matches. The \checkenv macro can also be +% used to check whether the current environment is the one expected. +% +% Non-false conditionals (@iftex, @ifset) don't fit into this, so they +% are not treated as enviroments; they don't open a group. (The +% implementation of @end takes care not to call \endgroup in this +% special case.) + + +% At runtime, environments start with this: +\def\startenvironment#1{\begingroup\def\thisenv{#1}} +% initialize +\let\thisenv\empty + +% ... but they get defined via ``\envdef\foo{...}'': +\long\def\envdef#1#2{\def#1{\startenvironment#1#2}} +\def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} + +% Check whether we're in the right environment: +\def\checkenv#1{% + \def\temp{#1}% + \ifx\thisenv\temp + \else + \badenverr + \fi +} + +% Evironment mismatch, #1 expected: +\def\badenverr{% + \errhelp = \EMsimple + \errmessage{This command can appear only \inenvironment\temp, + not \inenvironment\thisenv}% +} +\def\inenvironment#1{% + \ifx#1\empty + out of any environment% + \else + in environment \expandafter\string#1% + \fi +} + +% @end foo executes the definition of \Efoo. +% But first, it executes a specialized version of \checkenv +% +\parseargdef\end{% + \if 1\csname iscond.#1\endcsname + \else + % The general wording of \badenverr may not be ideal, but... --kasal, 06nov03 + \expandafter\checkenv\csname#1\endcsname + \csname E#1\endcsname + \endgroup + \fi +} + +\newhelp\EMsimple{Press RETURN to continue.} + + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt\char64}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. +\def\mylbrace {{\tt\char123}} +\def\myrbrace {{\tt\char125}} +\let\{=\mylbrace +\let\}=\myrbrace +\begingroup + % Definitions to produce \{ and \} commands for indices, + % and @{ and @} for the aux/toc files. + \catcode`\{ = \other \catcode`\} = \other + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\! = 0 \catcode`\\ = \other + !gdef!lbracecmd[\{]% + !gdef!rbracecmd[\}]% + !gdef!lbraceatcmd[@{]% + !gdef!rbraceatcmd[@}]% +!endgroup + +% @comma{} to avoid , parsing problems. +\let\comma = , + +% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent +% Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H. +\let\, = \c +\let\dotaccent = \. +\def\ringaccent#1{{\accent23 #1}} +\let\tieaccent = \t +\let\ubaraccent = \b +\let\udotaccent = \d + +% Other special characters: @questiondown @exclamdown @ordf @ordm +% Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss. +\def\questiondown{?`} +\def\exclamdown{!`} +\def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}} +\def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}} + +% Dotless i and dotless j, used for accents. +\def\imacro{i} +\def\jmacro{j} +\def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ptexi + \else\ifx\temp\jmacro \j + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi +} + +% The \TeX{} logo, as in plain, but resetting the spacing so that a +% period following counts as ending a sentence. (Idea found in latex.) +% +\edef\TeX{\TeX \spacefactor=1000 } + +% @LaTeX{} logo. Not quite the same results as the definition in +% latex.ltx, since we use a different font for the raised A; it's most +% convenient for us to use an explicitly smaller font, rather than using +% the \scriptstyle font (since we don't reset \scriptstyle and +% \scriptscriptstyle). +% +\def\LaTeX{% + L\kern-.36em + {\setbox0=\hbox{T}% + \vbox to \ht0{\hbox{\selectfonts\lllsize A}\vss}}% + \kern-.15em + \TeX +} + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @/ allows a line break. +\let\/=\allowbreak + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=\endofsentencespacefactor\space} + +% @! is an end-of-sentence bang. +\def\!{!\spacefactor=\endofsentencespacefactor\space} + +% @? is an end-of-sentence query. +\def\?{?\spacefactor=\endofsentencespacefactor\space} + +% @frenchspacing on|off says whether to put extra space after punctuation. +% +\def\onword{on} +\def\offword{off} +% +\parseargdef\frenchspacing{% + \def\temp{#1}% + \ifx\temp\onword \plainfrenchspacing + \else\ifx\temp\offword \plainnonfrenchspacing + \else + \errhelp = \EMsimple + \errmessage{Unknown @frenchspacing option `\temp', must be on/off}% + \fi\fi +} + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +% Another complication is that the group might be very large. This can +% cause the glue on the previous page to be unduly stretched, because it +% does not have much material. In this case, it's better to add an +% explicit \vfill so that the extra space is at the bottom. The +% threshold for doing this is if the group is more than \vfilllimit +% percent of a page (\vfilllimit can be changed inside of @tex). +% +\newbox\groupbox +\def\vfilllimit{0.7} +% +\envdef\group{% + \ifnum\catcode`\^^M=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + \startsavinginserts + % + \setbox\groupbox = \vtop\bgroup + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% The \vtop produces a box with normal height and large depth; thus, TeX puts +% \baselineskip glue before it, and (when the next line of text is done) +% \lineskip glue after it. Thus, space below is not quite equal to space +% above. But it's pretty close. +\def\Egroup{% + % To get correct interline space between the last line of the group + % and the first line afterwards, we have to propagate \prevdepth. + \endgraf % Not \par, as it may have been set to \lisppar. + \global\dimen1 = \prevdepth + \egroup % End the \vtop. + % \dimen0 is the vertical size of the group's box. + \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox + % \dimen2 is how much space is left on the page (more or less). + \dimen2 = \pageheight \advance\dimen2 by -\pagetotal + % if the group doesn't fit on the current page, and it's a big big + % group, force a page break. + \ifdim \dimen0 > \dimen2 + \ifdim \pagetotal < \vfilllimit\pageheight + \page + \fi + \fi + \box\groupbox + \prevdepth = \dimen1 + \checkinserts +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +% Old definition--didn't work. +%\parseargdef\need{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak +%\prevdepth=-1000pt +%}} + +\parseargdef\need{% + % Ensure vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % If the @need value is less than one line space, it's useless. + \dimen0 = #1\mil + \dimen2 = \ht\strutbox + \advance\dimen2 by \dp\strutbox + \ifdim\dimen0 > \dimen2 + % + % Do a \strut just to make the height of this box be normal, so the + % normal leading is inserted relative to the preceding line. + % And a page break here is fine. + \vtop to #1\mil{\strut\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak + \fi +} + +% @br forces paragraph break (and is undocumented). + +\let\br = \par + +% @page forces the start of a new page. +% +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break} + +% This defn is used inside nofill environments such as @example. +\parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount + \leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current +% paragraph. For more general purposes, use the \margin insertion +% class. WHICH is `l' or `r'. +% +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} +% +\def\doinmargin#1#2{\strut\vadjust{% + \nobreak + \kern-\strutdepth + \vtop to \strutdepth{% + \baselineskip=\strutdepth + \vss + % if you have multiple lines of stuff to put here, you'll need to + % make the vbox yourself of the appropriate size. + \ifx#1l% + \llap{\ignorespaces #2\hskip\inmarginspacing}% + \else + \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}% + \fi + \null + }% +}} +\def\inleftmargin{\doinmargin l} +\def\inrightmargin{\doinmargin r} +% +% @inmargin{TEXT [, RIGHT-TEXT]} +% (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right; +% else use TEXT for both). +% +\def\inmargin#1{\parseinmargin #1,,\finish} +\def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing. + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \def\lefttext{#1}% have both texts + \def\righttext{#2}% + \else + \def\lefttext{#1}% have only one text + \def\righttext{#1}% + \fi + % + \ifodd\pageno + \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin + \else + \def\temp{\inleftmargin\lefttext}% + \fi + \temp +} + +% @include file insert text of that file as input. +% +\def\include{\parseargusing\filenamecatcodes\includezzz} +\def\includezzz#1{% + \pushthisfilestack + \def\thisfile{#1}% + {% + \makevalueexpandable + \def\temp{\input #1 }% + \expandafter + }\temp + \popthisfilestack +} +\def\filenamecatcodes{% + \catcode`\\=\other + \catcode`~=\other + \catcode`^=\other + \catcode`_=\other + \catcode`|=\other + \catcode`<=\other + \catcode`>=\other + \catcode`+=\other + \catcode`-=\other +} + +\def\pushthisfilestack{% + \expandafter\pushthisfilestackX\popthisfilestack\StackTerm +} +\def\pushthisfilestackX{% + \expandafter\pushthisfilestackY\thisfile\StackTerm +} +\def\pushthisfilestackY #1\StackTerm #2\StackTerm {% + \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}% +} + +\def\popthisfilestack{\errthisfilestackempty} +\def\errthisfilestackempty{\errmessage{Internal error: + the stack of filenames is empty.}} + +\def\thisfile{} + +% @center line +% outputs that line, centered. +% +\parseargdef\center{% + \ifhmode + \let\next\centerH + \else + \let\next\centerV + \fi + \next{\hfil \ignorespaces#1\unskip \hfil}% +} +\def\centerH#1{% + {% + \hfil\break + \advance\hsize by -\leftskip + \advance\hsize by -\rightskip + \line{#1}% + \break + }% +} +\def\centerV#1{\line{\kern\leftskip #1\kern\rightskip}} + +% @sp n outputs n lines of vertical space + +\parseargdef\sp{\vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\begingroup \catcode`\^^M=\other% +\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% +\commentxxx} +{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} + +\let\c=\comment + +% @paragraphindent NCHARS +% We'll use ems for NCHARS, close enough. +% NCHARS can also be the word `asis' or `none'. +% We cannot feasibly implement @paragraphindent asis, though. +% +\def\asisword{asis} % no translation, these are keywords +\def\noneword{none} +% +\parseargdef\paragraphindent{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \defaultparindent = 0pt + \else + \defaultparindent = #1em + \fi + \fi + \parindent = \defaultparindent +} + +% @exampleindent NCHARS +% We'll use ems for NCHARS like @paragraphindent. +% It seems @exampleindent asis isn't necessary, but +% I preserve it to make it similar to @paragraphindent. +\parseargdef\exampleindent{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \lispnarrowing = 0pt + \else + \lispnarrowing = #1em + \fi + \fi +} + +% @firstparagraphindent WORD +% If WORD is `none', then suppress indentation of the first paragraph +% after a section heading. If WORD is `insert', then do indent at such +% paragraphs. +% +% The paragraph indentation is suppressed or not by calling +% \suppressfirstparagraphindent, which the sectioning commands do. +% We switch the definition of this back and forth according to WORD. +% By default, we suppress indentation. +% +\def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent} +\def\insertword{insert} +% +\parseargdef\firstparagraphindent{% + \def\temp{#1}% + \ifx\temp\noneword + \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent + \else\ifx\temp\insertword + \let\suppressfirstparagraphindent = \relax + \else + \errhelp = \EMsimple + \errmessage{Unknown @firstparagraphindent option `\temp'}% + \fi\fi +} + +% Here is how we actually suppress indentation. Redefine \everypar to +% \kern backwards by \parindent, and then reset itself to empty. +% +% We also make \indent itself not actually do anything until the next +% paragraph. +% +\gdef\dosuppressfirstparagraphindent{% + \gdef\indent{% + \restorefirstparagraphindent + \indent + }% + \gdef\noindent{% + \restorefirstparagraphindent + \noindent + }% + \global\everypar = {% + \kern -\parindent + \restorefirstparagraphindent + }% +} + +\gdef\restorefirstparagraphindent{% + \global \let \indent = \ptexindent + \global \let \noindent = \ptexnoindent + \global \everypar = {}% +} + + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math outputs its argument in math mode. +% +% One complication: _ usually means subscripts, but it could also mean +% an actual _ character, as in @math{@var{some_variable} + 1}. So make +% _ active, and distinguish by seeing if the current family is \slfam, +% which is what @var uses. +{ + \catcode\underChar = \active + \gdef\mathunderscore{% + \catcode\underChar=\active + \def_{\ifnum\fam=\slfam \_\else\sb\fi}% + } +} +% Another complication: we want \\ (and @\) to output a \ character. +% FYI, plain.tex uses \\ as a temporary control sequence (why?), but +% this is not advertised and we don't care. Texinfo does not +% otherwise define @\. +% +% The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\. +\def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi} +% +\def\math{% + \tex + \mathunderscore + \let\\ = \mathbackslash + \mathactive + $\finishmath +} +\def\finishmath#1{#1$\endgroup} % Close the group opened by \tex. + +% Some active characters (such as <) are spaced differently in math. +% We have to reset their definitions in case the @math was an argument +% to a command which sets the catcodes (such as @item or @section). +% +{ + \catcode`^ = \active + \catcode`< = \active + \catcode`> = \active + \catcode`+ = \active + \gdef\mathactive{% + \let^ = \ptexhat + \let< = \ptexless + \let> = \ptexgtr + \let+ = \ptexplus + } +} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{$\ptexbullet$} +\def\minus{$-$} + +% @dots{} outputs an ellipsis using the current font. +% We do .5em per period so that it has the same spacing in a typewriter +% font as three actual period characters. +% +\def\dots{% + \leavevmode + \hbox to 1.5em{% + \hskip 0pt plus 0.25fil + .\hfil.\hfil.% + \hskip 0pt plus 0.5fil + }% +} + +% @enddots{} is an end-of-sentence ellipsis. +% +\def\enddots{% + \dots + \spacefactor=\endofsentencespacefactor +} + +% @comma{} is so commas can be inserted into text without messing up +% Texinfo's parsing. +% +\let\comma = , + +% @refill is a no-op. +\let\refill=\relax + +% If working on a large document in chapters, it is convenient to +% be able to disable indexing, cross-referencing, and contents, for test runs. +% This is done with @novalidate (before @setfilename). +% +\newif\iflinks \linkstrue % by default we want the aux files. +\let\novalidate = \linksfalse + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \iflinks + \tryauxfile + % Open the new aux file. TeX will close it automatically at exit. + \immediate\openout\auxfile=\jobname.aux + \fi % \openindices needs to do some work in any case. + \openindices + \let\setfilename=\comment % Ignore extra @setfilename cmds. + % + % If texinfo.cnf is present on the system, read it. + % Useful for site-wide @afourpaper, etc. + \openin 1 texinfo.cnf + \ifeof 1 \else \input texinfo.cnf \fi + \closein 1 + % + \comment % Ignore the actual filename. +} + +% Called from \setfilename. +% +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% @bye. +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + + +\message{pdf,} +% adobe `portable' document format +\newcount\tempnum +\newcount\lnkcount +\newtoks\filename +\newcount\filenamelength +\newcount\pgn +\newtoks\toksA +\newtoks\toksB +\newtoks\toksC +\newtoks\toksD +\newbox\boxA +\newcount\countA +\newif\ifpdf +\newif\ifpdfmakepagedest + +% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1 +% can be set). So we test for \relax and 0 as well as \undefined, +% borrowed from ifpdf.sty. +\ifx\pdfoutput\undefined +\else + \ifx\pdfoutput\relax + \else + \ifcase\pdfoutput + \else + \pdftrue + \fi + \fi +\fi + +% PDF uses PostScript string constants for the names of xref targets, to +% for display in the outlines, and in other places. Thus, we have to +% double any backslashes. Otherwise, a name like "\node" will be +% interpreted as a newline (\n), followed by o, d, e. Not good. +% http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html +% (and related messages, the final outcome is that it is up to the TeX +% user to double the backslashes and otherwise make the string valid, so +% that's we do). + +% double active backslashes. +% +{\catcode`\@=0 \catcode`\\=\active + @gdef@activebackslash{@catcode`@\=@active @otherbackslash} + @gdef@activebackslashdouble{% + @catcode@backChar=@active + @let\=@doublebackslash} +} + +% To handle parens, we must adopt a different approach, since parens are +% not active characters. hyperref.dtx (which has the same problem as +% us) handles it with this amazing macro to replace tokens. I've +% tinkered with it a little for texinfo, but it's definitely from there. +% +% #1 is the tokens to replace. +% #2 is the replacement. +% #3 is the control sequence with the string. +% +\def\HyPsdSubst#1#2#3{% + \def\HyPsdReplace##1#1##2\END{% + ##1% + \ifx\\##2\\% + \else + #2% + \HyReturnAfterFi{% + \HyPsdReplace##2\END + }% + \fi + }% + \xdef#3{\expandafter\HyPsdReplace#3#1\END}% +} +\long\def\HyReturnAfterFi#1\fi{\fi#1} + +% #1 is a control sequence in which to do the replacements. +\def\backslashparens#1{% + \xdef#1{#1}% redefine it as its expansion; the definition is simply + % \lastnode when called from \setref -> \pdfmkdest. + \HyPsdSubst{(}{\backslashlparen}{#1}% + \HyPsdSubst{)}{\backslashrparen}{#1}% +} + +{\catcode\exclamChar = 0 \catcode\backChar = \other + !gdef!backslashlparen{\(}% + !gdef!backslashrparen{\)}% +} + +\ifpdf + \input pdfcolor + \pdfcatalog{/PageMode /UseOutlines}% + \def\dopdfimage#1#2#3{% + \def\imagewidth{#2}% + \def\imageheight{#3}% + % without \immediate, pdftex seg faults when the same image is + % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.) + \ifnum\pdftexversion < 14 + \immediate\pdfimage + \else + \immediate\pdfximage + \fi + \ifx\empty\imagewidth\else width \imagewidth \fi + \ifx\empty\imageheight\else height \imageheight \fi + \ifnum\pdftexversion<13 + #1.pdf% + \else + {#1.pdf}% + \fi + \ifnum\pdftexversion < 14 \else + \pdfrefximage \pdflastximage + \fi} + \def\pdfmkdest#1{{% + % We have to set dummies so commands such as @code, and characters + % such as \, aren't expanded when present in a section title. + \atdummies + \activebackslashdouble + \def\pdfdestname{#1}% + \backslashparens\pdfdestname + \pdfdest name{\pdfdestname} xyz% + }}% + % + % used to mark target names; must be expandable. + \def\pdfmkpgn#1{#1}% + % + \let\linkcolor = \Blue % was Cyan, but that seems light? + \def\endlink{\Black\pdfendlink} + % Adding outlines to PDF; macros for calculating structure of outlines + % come from Petr Olsak + \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% + \else \csname#1\endcsname \fi} + \def\advancenumber#1{\tempnum=\expnumber{#1}\relax + \advance\tempnum by 1 + \expandafter\xdef\csname#1\endcsname{\the\tempnum}} + % + % #1 is the section text, which is what will be displayed in the + % outline by the pdf viewer. #2 is the pdf expression for the number + % of subentries (or empty, for subsubsections). #3 is the node text, + % which might be empty if this toc entry had no corresponding node. + % #4 is the page number + % + \def\dopdfoutline#1#2#3#4{% + % Generate a link to the node text if that exists; else, use the + % page number. We could generate a destination for the section + % text in the case where a section has no node, but it doesn't + % seem worth the trouble, since most documents are normally structured. + \def\pdfoutlinedest{#3}% + \ifx\pdfoutlinedest\empty + \def\pdfoutlinedest{#4}% + \else + % Doubled backslashes in the name. + {\activebackslashdouble \xdef\pdfoutlinedest{#3}% + \backslashparens\pdfoutlinedest}% + \fi + % + % Also double the backslashes in the display string. + {\activebackslashdouble \xdef\pdfoutlinetext{#1}% + \backslashparens\pdfoutlinetext}% + % + \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}% + } + % + \def\pdfmakeoutlines{% + \begingroup + % Thanh's hack / proper braces in bookmarks + \edef\mylbrace{\iftrue \string{\else}\fi}\let\{=\mylbrace + \edef\myrbrace{\iffalse{\else\string}\fi}\let\}=\myrbrace + % + % Read toc silently, to get counts of subentries for \pdfoutline. + \def\numchapentry##1##2##3##4{% + \def\thischapnum{##2}% + \def\thissecnum{0}% + \def\thissubsecnum{0}% + }% + \def\numsecentry##1##2##3##4{% + \advancenumber{chap\thischapnum}% + \def\thissecnum{##2}% + \def\thissubsecnum{0}% + }% + \def\numsubsecentry##1##2##3##4{% + \advancenumber{sec\thissecnum}% + \def\thissubsecnum{##2}% + }% + \def\numsubsubsecentry##1##2##3##4{% + \advancenumber{subsec\thissubsecnum}% + }% + \def\thischapnum{0}% + \def\thissecnum{0}% + \def\thissubsecnum{0}% + % + % use \def rather than \let here because we redefine \chapentry et + % al. a second time, below. + \def\appentry{\numchapentry}% + \def\appsecentry{\numsecentry}% + \def\appsubsecentry{\numsubsecentry}% + \def\appsubsubsecentry{\numsubsubsecentry}% + \def\unnchapentry{\numchapentry}% + \def\unnsecentry{\numsecentry}% + \def\unnsubsecentry{\numsubsecentry}% + \def\unnsubsubsecentry{\numsubsubsecentry}% + \readdatafile{toc}% + % + % Read toc second time, this time actually producing the outlines. + % The `-' means take the \expnumber as the absolute number of + % subentries, which we calculated on our first read of the .toc above. + % + % We use the node names as the destinations. + \def\numchapentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}% + \def\numsecentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}% + \def\numsubsecentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}% + \def\numsubsubsecentry##1##2##3##4{% count is always zero + \dopdfoutline{##1}{}{##3}{##4}}% + % + % PDF outlines are displayed using system fonts, instead of + % document fonts. Therefore we cannot use special characters, + % since the encoding is unknown. For example, the eogonek from + % Latin 2 (0xea) gets translated to a | character. Info from + % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100. + % + % xx to do this right, we have to translate 8-bit characters to + % their "best" equivalent, based on the @documentencoding. Right + % now, I guess we'll just let the pdf reader have its way. + \indexnofonts + \setupdatafile + \activebackslash + \input \jobname.toc + \endgroup + } + % + \def\skipspaces#1{\def\PP{#1}\def\D{|}% + \ifx\PP\D\let\nextsp\relax + \else\let\nextsp\skipspaces + \ifx\p\space\else\addtokens{\filename}{\PP}% + \advance\filenamelength by 1 + \fi + \fi + \nextsp} + \def\getfilename#1{\filenamelength=0\expandafter\skipspaces#1|\relax} + \ifnum\pdftexversion < 14 + \let \startlink \pdfannotlink + \else + \let \startlink \pdfstartlink + \fi + \def\pdfurl#1{% + \begingroup + \normalturnoffactive\def\@{@}% + \makevalueexpandable + \leavevmode\Red + \startlink attr{/Border [0 0 0]}% + user{/Subtype /Link /A << /S /URI /URI (#1) >>}% + \endgroup} + \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} + \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} + \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} + \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} + \def\maketoks{% + \expandafter\poptoks\the\toksA|ENDTOKS|\relax + \ifx\first0\adn0 + \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 + \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 + \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 + \else + \ifnum0=\countA\else\makelink\fi + \ifx\first.\let\next=\done\else + \let\next=\maketoks + \addtokens{\toksB}{\the\toksD} + \ifx\first,\addtokens{\toksB}{\space}\fi + \fi + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \next} + \def\makelink{\addtokens{\toksB}% + {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} + \def\pdflink#1{% + \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}} + \linkcolor #1\endlink} + \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} +\else + \let\pdfmkdest = \gobble + \let\pdfurl = \gobble + \let\endlink = \relax + \let\linkcolor = \relax + \let\pdfmakeoutlines = \relax +\fi % \ifx\pdfoutput + + +\message{fonts,} + +% Change the current font style to #1, remembering it in \curfontstyle. +% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in +% italics, not bold italics. +% +\def\setfontstyle#1{% + \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. + \csname ten#1\endcsname % change the current font +} + +% Select #1 fonts with the current style. +% +\def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname} + +\def\rm{\fam=0 \setfontstyle{rm}} +\def\it{\fam=\itfam \setfontstyle{it}} +\def\sl{\fam=\slfam \setfontstyle{sl}} +\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf} +\def\tt{\fam=\ttfam \setfontstyle{tt}} + +% Texinfo sort of supports the sans serif font style, which plain TeX does not. +% So we set up a \sf. +\newfam\sffam +\def\sf{\fam=\sffam \setfontstyle{sf}} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this font style. +\def\ttsl{\setfontstyle{ttsl}} + +% Default leading. +\newdimen\textleading \textleading = 13.2pt + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +% #3 is the font's design size, #4 is a scale factor +\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4} + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} %where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +% Text fonts (11.2pt, magstep1). +\def\textnominalsize{11pt} +\edef\mainmagstep{\magstephalf} +\setfont\textrm\rmshape{10}{\mainmagstep} +\setfont\texttt\ttshape{10}{\mainmagstep} +\setfont\textbf\bfshape{10}{\mainmagstep} +\setfont\textit\itshape{10}{\mainmagstep} +\setfont\textsl\slshape{10}{\mainmagstep} +\setfont\textsf\sfshape{10}{\mainmagstep} +\setfont\textsc\scshape{10}{\mainmagstep} +\setfont\textttsl\ttslshape{10}{\mainmagstep} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun names and args. +\setfont\defbf\bfshape{10}{\magstep1} +\setfont\deftt\ttshape{10}{\magstep1} +\setfont\defttsl\ttslshape{10}{\magstep1} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} + +% Fonts for indices, footnotes, small examples (9pt). +\def\smallnominalsize{9pt} +\setfont\smallrm\rmshape{9}{1000} +\setfont\smalltt\ttshape{9}{1000} +\setfont\smallbf\bfshape{10}{900} +\setfont\smallit\itshape{9}{1000} +\setfont\smallsl\slshape{9}{1000} +\setfont\smallsf\sfshape{9}{1000} +\setfont\smallsc\scshape{10}{900} +\setfont\smallttsl\ttslshape{10}{900} +\font\smalli=cmmi9 +\font\smallsy=cmsy9 + +% Fonts for small examples (8pt). +\def\smallernominalsize{8pt} +\setfont\smallerrm\rmshape{8}{1000} +\setfont\smallertt\ttshape{8}{1000} +\setfont\smallerbf\bfshape{10}{800} +\setfont\smallerit\itshape{8}{1000} +\setfont\smallersl\slshape{8}{1000} +\setfont\smallersf\sfshape{8}{1000} +\setfont\smallersc\scshape{10}{800} +\setfont\smallerttsl\ttslshape{10}{800} +\font\smalleri=cmmi8 +\font\smallersy=cmsy8 + +% Fonts for title page (20.4pt): +\def\titlenominalsize{20pt} +\setfont\titlerm\rmbshape{12}{\magstep3} +\setfont\titleit\itbshape{10}{\magstep4} +\setfont\titlesl\slbshape{10}{\magstep4} +\setfont\titlett\ttbshape{12}{\magstep3} +\setfont\titlettsl\ttslshape{10}{\magstep4} +\setfont\titlesf\sfbshape{17}{\magstep1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\authorrm{\secrm} +\def\authortt{\sectt} + +% Chapter (and unnumbered) fonts (17.28pt). +\def\chapnominalsize{17pt} +\setfont\chaprm\rmbshape{12}{\magstep2} +\setfont\chapit\itbshape{10}{\magstep3} +\setfont\chapsl\slbshape{10}{\magstep3} +\setfont\chaptt\ttbshape{12}{\magstep2} +\setfont\chapttsl\ttslshape{10}{\magstep3} +\setfont\chapsf\sfbshape{17}{1000} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 + +% Section fonts (14.4pt). +\def\secnominalsize{14pt} +\setfont\secrm\rmbshape{12}{\magstep1} +\setfont\secit\itbshape{10}{\magstep2} +\setfont\secsl\slbshape{10}{\magstep2} +\setfont\sectt\ttbshape{12}{\magstep1} +\setfont\secttsl\ttslshape{10}{\magstep2} +\setfont\secsf\sfbshape{12}{\magstep1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 + +% Subsection fonts (13.15pt). +\def\ssecnominalsize{13pt} +\setfont\ssecrm\rmbshape{12}{\magstephalf} +\setfont\ssecit\itbshape{10}{1315} +\setfont\ssecsl\slbshape{10}{1315} +\setfont\ssectt\ttbshape{12}{\magstephalf} +\setfont\ssecttsl\ttslshape{10}{1315} +\setfont\ssecsf\sfbshape{12}{\magstephalf} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{1315} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled 1315 + +% Reduced fonts for @acro in text (10pt). +\def\reducednominalsize{10pt} +\setfont\reducedrm\rmshape{10}{1000} +\setfont\reducedtt\ttshape{10}{1000} +\setfont\reducedbf\bfshape{10}{1000} +\setfont\reducedit\itshape{10}{1000} +\setfont\reducedsl\slshape{10}{1000} +\setfont\reducedsf\sfshape{10}{1000} +\setfont\reducedsc\scshape{10}{1000} +\setfont\reducedttsl\ttslshape{10}{1000} +\font\reducedi=cmmi10 +\font\reducedsy=cmsy10 + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts except +% in the main text, we don't bother to reset \scriptfont and +% \scriptscriptfont (which would also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy + \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf + \textfont\ttfam=\tentt \textfont\sffam=\tensf +} + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this because \STYLE needs to also set the +% current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire +% \tenSTYLE to set the current font. +% +% Each font-changing command also sets the names \lsize (one size lower) +% and \lllsize (three sizes lower). These relative commands are used in +% the LaTeX logo and acronyms. +% +% This all needs generalizing, badly. +% +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy + \let\tenttsl=\textttsl + \def\curfontsize{text}% + \def\lsize{reduced}\def\lllsize{smaller}% + \resetmathfonts \setleading{\textleading}} +\def\titlefonts{% + \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl + \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc + \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy + \let\tenttsl=\titlettsl + \def\curfontsize{title}% + \def\lsize{chap}\def\lllsize{subsec}% + \resetmathfonts \setleading{25pt}} +\def\titlefont#1{{\titlefonts\rm #1}} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy + \let\tenttsl=\chapttsl + \def\curfontsize{chap}% + \def\lsize{sec}\def\lllsize{text}% + \resetmathfonts \setleading{19pt}} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy + \let\tenttsl=\secttsl + \def\curfontsize{sec}% + \def\lsize{subsec}\def\lllsize{reduced}% + \resetmathfonts \setleading{16pt}} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy + \let\tenttsl=\ssecttsl + \def\curfontsize{ssec}% + \def\lsize{text}\def\lllsize{small}% + \resetmathfonts \setleading{15pt}} +\let\subsubsecfonts = \subsecfonts +\def\reducedfonts{% + \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl + \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc + \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy + \let\tenttsl=\reducedttsl + \def\curfontsize{reduced}% + \def\lsize{small}\def\lllsize{smaller}% + \resetmathfonts \setleading{10.5pt}} +\def\smallfonts{% + \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl + \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc + \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy + \let\tenttsl=\smallttsl + \def\curfontsize{small}% + \def\lsize{smaller}\def\lllsize{smaller}% + \resetmathfonts \setleading{10.5pt}} +\def\smallerfonts{% + \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl + \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc + \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy + \let\tenttsl=\smallerttsl + \def\curfontsize{smaller}% + \def\lsize{smaller}\def\lllsize{smaller}% + \resetmathfonts \setleading{9.5pt}} + +% Set the fonts to use with the @small... environments. +\let\smallexamplefonts = \smallfonts + +% About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample +% can fit this many characters: +% 8.5x11=86 smallbook=72 a4=90 a5=69 +% If we use \scriptfonts (8pt), then we can fit this many characters: +% 8.5x11=90+ smallbook=80 a4=90+ a5=77 +% For me, subjectively, the few extra characters that fit aren't worth +% the additional smallness of 8pt. So I'm making the default 9pt. +% +% By the way, for comparison, here's what fits with @example (10pt): +% 8.5x11=71 smallbook=60 a4=75 a5=58 +% +% I wish the USA used A4 paper. +% --karl, 24jan03. + + +% Set up the default fonts, so we can use them for creating boxes. +% +\textfonts \rm + +% Define these so they can be easily changed for other fonts. +\def\angleleft{$\langle$} +\def\angleright{$\rangle$} + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000} +\setfont\shortcontbf\bfshape{10}{\magstep1} % no cmb12 +\setfont\shortcontsl\slshape{12}{1000} +\setfont\shortconttt\ttshape{12}{1000} + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else + \ptexslash\fi\fi\fi} +\def\smartslanted#1{{\ifusingtt\ttsl\sl #1}\futurelet\next\smartitalicx} +\def\smartitalic#1{{\ifusingtt\ttsl\it #1}\futurelet\next\smartitalicx} + +% like \smartslanted except unconditionally uses \ttsl. +% @var is set to this for defun arguments. +\def\ttslanted#1{{\ttsl #1}\futurelet\next\smartitalicx} + +% like \smartslanted except unconditionally use \sl. We never want +% ttsl for book titles, do we? +\def\cite#1{{\sl #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\slanted=\smartslanted +\let\var=\smartslanted +\let\dfn=\smartslanted +\let\emph=\smartitalic + +% @b, explicit bold. +\def\b#1{{\bf #1}} +\let\strong=\b + +% @sansserif, explicit sans. +\def\sansserif#1{{\sf #1}} + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +% Set sfcode to normal for the chars that usually have another value. +% Can't use plain's \frenchspacing because it uses the `\x notation, and +% sometimes \x has an active definition that messes things up. +% +\catcode`@=11 + \def\plainfrenchspacing{% + \sfcode\dotChar =\@m \sfcode\questChar=\@m \sfcode\exclamChar=\@m + \sfcode\colonChar=\@m \sfcode\semiChar =\@m \sfcode\commaChar =\@m + \def\endofsentencespacefactor{1000}% for @. and friends + } + \def\plainnonfrenchspacing{% + \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000 + \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250 + \def\endofsentencespacefactor{3000}% for @. and friends + } +\catcode`@=\other +\def\endofsentencespacefactor{3000}% default + +\def\t#1{% + {\tt \rawbackslash \plainfrenchspacing #1}% + \null +} +\def\samp#1{`\tclose{#1}'\null} +\setfont\keyrm\rmshape{8}{1000} +\font\keysy=cmsy9 +\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{% + \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% + \vbox{\hrule\kern-0.4pt + \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% + \kern-0.4pt\hrule}% + \kern-.06em\raise0.4pt\hbox{\angleright}}}} +% The old definition, with no lozenge: +%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +% @file, @option are the same as @samp. +\let\file=\samp +\let\option=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \plainfrenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in @code. +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate at a dash. +% -- rms. +{ + \catcode`\-=\active + \catcode`\_=\active + % + \global\def\code{\begingroup + \catcode`\-=\active \catcode`\_=\active + \ifallowcodebreaks + \let-\codedash + \let_\codeunder + \else + \let-\realdash + \let_\realunder + \fi + \codex + } +} + +\def\realdash{-} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{% + % this is all so @math{@code{var_name}+1} can work. In math mode, _ + % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.) + % will therefore expand the active definition of _, which is us + % (inside @code that is), therefore an endless loop. + \ifusingtt{\ifmmode + \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_. + \else\normalunderscore \fi + \discretionary{}{}{}}% + {\_}% +} +\def\codex #1{\tclose{#1}\endgroup} + +% An additional complication: the above will allow breaks after, e.g., +% each of the four underscores in __typeof__. This is undesirable in +% some manuals, especially if they don't have long identifiers in +% general. @allowcodebreaks provides a way to control this. +% +\newif\ifallowcodebreaks \allowcodebreakstrue + +\def\keywordtrue{true} +\def\keywordfalse{false} + +\parseargdef\allowcodebreaks{% + \def\txiarg{#1}% + \ifx\txiarg\keywordtrue + \allowcodebreakstrue + \else\ifx\txiarg\keywordfalse + \allowcodebreaksfalse + \else + \errhelp = \EMsimple + \errmessage{Unknown @allowcodebreaks option `\txiarg'}% + \fi\fi +} + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. + +% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), +% `example' (@kbd uses ttsl only inside of @example and friends), +% or `code' (@kbd uses normal tty font always). +\parseargdef\kbdinputstyle{% + \def\txiarg{#1}% + \ifx\txiarg\worddistinct + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% + \else\ifx\txiarg\wordexample + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% + \else\ifx\txiarg\wordcode + \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% + \else + \errhelp = \EMsimple + \errmessage{Unknown @kbdinputstyle option `\txiarg'}% + \fi\fi\fi +} +\def\worddistinct{distinct} +\def\wordexample{example} +\def\wordcode{code} + +% Default is `distinct.' +\kbdinputstyle distinct + +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else{\tclose{\kbdfont\look}}\fi +\else{\tclose{\kbdfont\look}}\fi} + +% For @indicateurl, @env, @command quotes seem unnecessary, so use \code. +\let\indicateurl=\code +\let\env=\code +\let\command=\code + +% @uref (abbreviation for `urlref') takes an optional (comma-separated) +% second argument specifying the text to display and an optional third +% arg as text to display instead of (rather than in addition to) the url +% itself. First (mandatory) arg is the url. Perhaps eventually put in +% a hypertex \special here. +% +\def\uref#1{\douref #1,,,\finish} +\def\douref#1,#2,#3,#4\finish{\begingroup + \unsepspaces + \pdfurl{#1}% + \setbox0 = \hbox{\ignorespaces #3}% + \ifdim\wd0 > 0pt + \unhbox0 % third arg given, show only that + \else + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \ifpdf + \unhbox0 % PDF: 2nd arg given, show only it + \else + \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url + \fi + \else + \code{#1}% only url given, so show it + \fi + \fi + \endlink +\endgroup} + +% @url synonym for @uref, since that's how everyone uses it. +% +\let\url=\uref + +% rms does not like angle brackets --karl, 17may97. +% So now @email is just like @uref, unless we are pdf. +% +%\def\email#1{\angleleft{\tt #1}\angleright} +\ifpdf + \def\email#1{\doemail#1,,\finish} + \def\doemail#1,#2,#3\finish{\begingroup + \unsepspaces + \pdfurl{mailto:#1}% + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi + \endlink + \endgroup} +\else + \let\email=\uref +\fi + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + +% @l was never documented to mean ``switch to the Lisp font'', +% and it is not used as such in any manual I can find. We need it for +% Polish suppressed-l. --karl, 22sep96. +%\def\l#1{{\li #1}\null} + +% Explicit font changes: @r, @sc, undocumented @ii. +\def\r#1{{\rm #1}} % roman font +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +% @acronym for "FBI", "NATO", and the like. +% We print this one point size smaller, since it's intended for +% all-uppercase. +% +\def\acronym#1{\doacronym #1,,\finish} +\def\doacronym#1,#2,#3\finish{% + {\selectfonts\lsize #1}% + \def\temp{#2}% + \ifx\temp\empty \else + \space ({\unsepspaces \ignorespaces \temp \unskip})% + \fi +} + +% @abbr for "Comput. J." and the like. +% No font change, but don't do end-of-sentence spacing. +% +\def\abbr#1{\doabbr #1,,\finish} +\def\doabbr#1,#2,#3\finish{% + {\plainfrenchspacing #1}% + \def\temp{#2}% + \ifx\temp\empty \else + \space ({\unsepspaces \ignorespaces \temp \unskip})% + \fi +} + +% @pounds{} is a sterling sign, which Knuth put in the CM italic font. +% +\def\pounds{{\it\$}} + +% @euro{} comes from a separate font, depending on the current style. +% We use the free feym* fonts from the eurosym package by Henrik +% Theiling, which support regular, slanted, bold and bold slanted (and +% "outlined" (blackboard board, sort of) versions, which we don't need). +% It is available from http://www.ctan.org/tex-archive/fonts/eurosym. +% +% Although only regular is the truly official Euro symbol, we ignore +% that. The Euro is designed to be slightly taller than the regular +% font height. +% +% feymr - regular +% feymo - slanted +% feybr - bold +% feybo - bold slanted +% +% There is no good (free) typewriter version, to my knowledge. +% A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide. +% Hmm. +% +% Also doesn't work in math. Do we need to do math with euro symbols? +% Hope not. +% +% +\def\euro{{\eurofont e}} +\def\eurofont{% + % We set the font at each command, rather than predefining it in + % \textfonts and the other font-switching commands, so that + % installations which never need the symbol don't have to have the + % font installed. + % + % There is only one designed size (nominal 10pt), so we always scale + % that to the current nominal size. + % + % By the way, simply using "at 1em" works for cmr10 and the like, but + % does not work for cmbx10 and other extended/shrunken fonts. + % + \def\eurosize{\csname\curfontsize nominalsize\endcsname}% + % + \ifx\curfontstyle\bfstylename + % bold: + \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize + \else + % regular: + \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize + \fi + \thiseurofont +} + +% @registeredsymbol - R in a circle. The font for the R should really +% be smaller yet, but lllsize is the best we can do for now. +% Adapted from the plain.tex definition of \copyright. +% +\def\registeredsymbol{% + $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}% + \hfil\crcr\Orb}}% + }$% +} + +% Laurent Siebenmann reports \Orb undefined with: +% Textures 1.7.7 (preloaded format=plain 93.10.14) (68K) 16 APR 2004 02:38 +% so we'll define it if necessary. +% +\ifx\Orb\undefined +\def\Orb{\mathhexbox20D} +\fi + + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\newif\ifseenauthor +\newif\iffinishedtitlepage + +% Do an implicit @contents or @shortcontents after @end titlepage if the +% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. +% +\newif\ifsetcontentsaftertitlepage + \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue +\newif\ifsetshortcontentsaftertitlepage + \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue + +\parseargdef\shorttitlepage{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\envdef\titlepage{% + % Open one extra group, as we want to close it in the middle of \Etitlepage. + \begingroup + \parindent=0pt \textfonts + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \let\page = \oldpage + \page + \null + }% +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + % + % Need this before the \...aftertitlepage checks so that if they are + % in effect the toc pages will come out with page numbers. + \HEADINGSon + % + % If they want short, they certainly want long too. + \ifsetshortcontentsaftertitlepage + \shortcontents + \contents + \global\let\shortcontents = \relax + \global\let\contents = \relax + \fi + % + \ifsetcontentsaftertitlepage + \contents + \global\let\contents = \relax + \global\let\shortcontents = \relax + \fi +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Macros to be used within @titlepage: + +\let\subtitlerm=\tenrm +\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines} + +\def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines + \let\tt=\authortt} + +\parseargdef\title{% + \checkenv\titlepage + \leftline{\titlefonts\rm #1} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt +} + +\parseargdef\subtitle{% + \checkenv\titlepage + {\subtitlefont \rightline{#1}}% +} + +% @author should come last, but may come many times. +% It can also be used inside @quotation. +% +\parseargdef\author{% + \def\temp{\quotation}% + \ifx\thisenv\temp + \def\quotationauthor{#1}% printed in \Equotation. + \else + \checkenv\titlepage + \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi + {\authorfont \leftline{#1}}% + \fi +} + + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks\evenheadline % headline on even pages +\newtoks\oddheadline % headline on odd pages +\newtoks\evenfootline % footline on even pages +\newtoks\oddfootline % footline on odd pages + +% Now make TeX use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + + +\def\evenheading{\parsearg\evenheadingxxx} +\def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish} +\def\evenheadingyyy #1\|#2\|#3\|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\def\oddheading{\parsearg\oddheadingxxx} +\def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish} +\def\oddheadingyyy #1\|#2\|#3\|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}% + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish} +\def\evenfootingyyy #1\|#2\|#3\|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\def\oddfooting{\parsearg\oddfootingxxx} +\def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish} +\def\oddfootingyyy #1\|#2\|#3\|#4\finish{% + \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% + % + % Leave some space for the footline. Hopefully ok to assume + % @evenfooting will not be used by itself. + \global\advance\pageheight by -\baselineskip + \global\advance\vsize by -\baselineskip +} + +\parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}} + + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off at the start of a document, +% and turned `on' after @end titlepage. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{% +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{% +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} +\let\contentsalignmacro = \chappager + +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{% +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} + +% Subroutines used in generating headings +% This produces Day Month Year style of output. +% Only define if not already defined, in case a txi-??.tex file has set +% up a different format (e.g., txi-cs.tex does this). +\ifx\today\undefined +\def\today{% + \number\day\space + \ifcase\month + \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr + \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug + \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec + \fi + \space\number\year} +\fi + +% @settitle line... specifies the title of the document, for headings. +% It generates no output of its own. +\def\thistitle{\putwordNoTitle} +\def\settitle{\parsearg{\gdef\thistitle}} + + +\message{tables,} +% Tables -- @table, @ftable, @vtable, @item(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @ftable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemindicate{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. However, if + % what follows is an environment such as @example, there will be no + % \parskip glue; then the negative vskip we just inserted would + % cause the example and the item to crash together. So we use this + % bizarre value of 10001 as a signal to \aboveenvbreak to insert + % \parskip glue after all. Section titles are handled this way also. + % + \penalty 10001 + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. + \noindent + % Do this with kerns and \unhbox so that if there is a footnote in + % the item text, it can migrate to the main vertical list and + % eventually be printed. + \nobreak\kern-\tableindent + \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 + \unhbox0 + \nobreak\kern\dimen0 + \endgroup + \itemxneedsnegativevskiptrue + \fi +} + +\def\item{\errmessage{@item while not in a list environment}} +\def\itemx{\errmessage{@itemx while not in a list environment}} + +% @table, @ftable, @vtable. +\envdef\table{% + \let\itemindex\gobble + \tablecheck{table}% +} +\envdef\ftable{% + \def\itemindex ##1{\doind {fn}{\code{##1}}}% + \tablecheck{ftable}% +} +\envdef\vtable{% + \def\itemindex ##1{\doind {vr}{\code{##1}}}% + \tablecheck{vtable}% +} +\def\tablecheck#1{% + \ifnum \the\catcode`\^^M=\active + \endgroup + \errmessage{This command won't work in this context; perhaps the problem is + that we are \inenvironment\thisenv}% + \def\next{\doignore{#1}}% + \else + \let\next\tablex + \fi + \next +} +\def\tablex#1{% + \def\itemindicate{#1}% + \parsearg\tabley +} +\def\tabley#1{% + {% + \makevalueexpandable + \edef\temp{\noexpand\tablez #1\space\space\space}% + \expandafter + }\temp \endtablez +} +\def\tablez #1 #2 #3 #4\endtablez{% + \aboveenvbreak + \ifnum 0#1>0 \advance \leftskip by #1\mil \fi + \ifnum 0#2>0 \tableindent=#2\mil \fi + \ifnum 0#3>0 \advance \rightskip by #3\mil \fi + \itemmax=\tableindent + \advance \itemmax by -\itemmargin + \advance \leftskip by \tableindent + \exdentamount=\tableindent + \parindent = 0pt + \parskip = \smallskipamount + \ifdim \parskip=0pt \parskip=2pt \fi + \let\item = \internalBitem + \let\itemx = \internalBitemx +} +\def\Etable{\endgraf\afterenvbreak} +\let\Eftable\Etable +\let\Evtable\Etable +\let\Eitemize\Etable +\let\Eenumerate\Etable + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\envdef\itemize{\parsearg\doitemize} + +\def\doitemize#1{% + \aboveenvbreak + \itemmax=\itemindent + \advance\itemmax by -\itemmargin + \advance\leftskip by \itemindent + \exdentamount=\itemindent + \parindent=0pt + \parskip=\smallskipamount + \ifdim\parskip=0pt \parskip=2pt \fi + \def\itemcontents{#1}% + % @itemize with no arg is equivalent to @itemize @bullet. + \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi + \let\item=\itemizeitem +} + +% Definition of @item while inside @itemize and @enumerate. +% +\def\itemizeitem{% + \advance\itemno by 1 % for enumerations + {\let\par=\endgraf \smallbreak}% reasonable place to break + {% + % If the document has an @itemize directly after a section title, a + % \nobreak will be last on the list, and \sectionheading will have + % done a \vskip-\parskip. In that case, we don't want to zero + % parskip, or the item text will crash with the heading. On the + % other hand, when there is normal text preceding the item (as there + % usually is), we do want to zero parskip, or there would be too much + % space. In that case, we won't have a \nobreak before. At least + % that's the theory. + \ifnum\lastpenalty<10000 \parskip=0in \fi + \noindent + \hbox to 0pt{\hss \itemcontents \kern\itemmargin}% + \vadjust{\penalty 1200}}% not good to break after first line of item. + \flushcr +} + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\envparseargdef\enumerate{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a . + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call \doitemize, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \doitemize{#1.}\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + + +% @multitable macros +% Amy Hendrickson, 8/18/94, 3/6/96 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab do not need to be on their own lines, but it will not hurt +% if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip is vertical space between paragraphs in table. +% @multitableparindent is paragraph indent in table. +% @multitablecolmargin is horizontal space to be left between columns. +% @multitablelinespace is space to leave between table items, baseline +% to baseline. +% 0pt means it depends on current normal line spacing. +% +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=0pt + +% Macros used to set up halign preamble: +% +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +% #1 is the @columnfraction, usually a decimal number like .5, but might +% be just 1. We just use it, whatever it is. +% +\def\pickupwholefraction#1 {% + \global\advance\colcount by 1 + \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}% + \setuptable +} + +\newcount\colcount +\def\setuptable#1{% + \def\firstarg{#1}% + \ifx\firstarg\xendsetuptable + \let\go = \relax + \else + \ifx\firstarg\xcolumnfractions + \global\setpercenttrue + \else + \ifsetpercent + \let\go\pickupwholefraction + \else + \global\advance\colcount by 1 + \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a + % separator; typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi + \fi + \ifx\go\pickupwholefraction + % Put the argument back for the \pickupwholefraction call, so + % we'll always have a period there to be parsed. + \def\go{\pickupwholefraction#1}% + \else + \let\go = \setuptable + \fi% + \fi + \go +} + +% multitable-only commands. +% +% @headitem starts a heading row, which we typeset in bold. +% Assignments have to be global since we are inside the implicit group +% of an alignment entry. Note that \everycr resets \everytab. +\def\headitem{\checkenv\multitable \crcr \global\everytab={\bf}\the\everytab}% +% +% A \tab used to include \hskip1sp. But then the space in a template +% line is not enough. That is bad. So let's go back to just `&' until +% we encounter the problem it was intended to solve again. +% --karl, nathan@acm.org, 20apr99. +\def\tab{\checkenv\multitable &\the\everytab}% + +% @multitable ... @end multitable definitions: +% +\newtoks\everytab % insert after every tab. +% +\envdef\multitable{% + \vskip\parskip + \startsavinginserts + % + % @item within a multitable starts a normal row. + % We use \def instead of \let so that if one of the multitable entries + % contains an @itemize, we don't choke on the \item (seen as \crcr aka + % \endtemplate) expanding \doitemize. + \def\item{\crcr}% + % + \tolerance=9500 + \hbadness=9500 + \setmultitablespacing + \parskip=\multitableparskip + \parindent=\multitableparindent + \overfullrule=0pt + \global\colcount=0 + % + \everycr = {% + \noalign{% + \global\everytab={}% + \global\colcount=0 % Reset the column counter. + % Check for saved footnotes, etc. + \checkinserts + % Keeps underfull box messages off when table breaks over pages. + %\filbreak + % Maybe so, but it also creates really weird page breaks when the + % table breaks over pages. Wouldn't \vfil be better? Wait until the + % problem manifests itself, so it can be fixed for real --karl. + }% + }% + % + \parsearg\domultitable +} +\def\domultitable#1{% + % To parse everything between @multitable and @item: + \setuptable#1 \endsetuptable + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. + \halign\bgroup &% + \global\advance\colcount by 1 + \multistrut + \vtop{% + % Use the current \colcount to find the correct column width: + \hsize=\expandafter\csname col\the\colcount\endcsname + % + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % + % If the user has set preamble in terms of percent of \hsize we will + % use that dimension as the width of the column, and the \leftskip + % will keep entries from bumping into each other. Table will start at + % left margin and final column will justify at right margin. + % + % Make sure we don't inherit \rightskip from the outer environment. + \rightskip=0pt + \ifnum\colcount=1 + % The first column will be indented with the surrounding text. + \advance\hsize by\leftskip + \else + \ifsetpercent \else + % If user has not set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace. + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: + \leftskip=\multitablecolspace + \fi + % Ignoring space at the beginning and end avoids an occasional spurious + % blank line, when TeX decides to break the line at the space before the + % box from the multistrut, so the strut ends up on a line by itself. + % For example: + % @multitable @columnfractions .11 .89 + % @item @code{#} + % @tab Legal holiday which is valid in major parts of the whole country. + % Is automatically provided with highlighting sequences respectively + % marking characters. + \noindent\ignorespaces##\unskip\multistrut + }\cr +} +\def\Emultitable{% + \crcr + \egroup % end the \halign + \global\setpercentfalse +} + +\def\setmultitablespacing{% + \def\multistrut{\strut}% just use the standard line spacing + % + % Compute \multitablelinespace (if not defined by user) for use in + % \multitableparskip calculation. We used define \multistrut based on + % this, but (ironically) that caused the spacing to be off. + % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100. +\ifdim\multitablelinespace=0pt +\setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip +\global\advance\multitablelinespace by-\ht0 +\fi +%% Test to see if parskip is larger than space between lines of +%% table. If not, do nothing. +%% If so, set to same dimension as multitablelinespace. +\ifdim\multitableparskip>\multitablelinespace +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi% +\ifdim\multitableparskip=0pt +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi} + + +\message{conditionals,} + +% @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext, +% @ifnotxml always succeed. They currently do nothing; we don't +% attempt to check whether the conditionals are properly nested. But we +% have to remember that they are conditionals, so that @end doesn't +% attempt to close an environment group. +% +\def\makecond#1{% + \expandafter\let\csname #1\endcsname = \relax + \expandafter\let\csname iscond.#1\endcsname = 1 +} +\makecond{iftex} +\makecond{ifnotdocbook} +\makecond{ifnothtml} +\makecond{ifnotinfo} +\makecond{ifnotplaintext} +\makecond{ifnotxml} + +% Ignore @ignore, @ifhtml, @ifinfo, and the like. +% +\def\direntry{\doignore{direntry}} +\def\documentdescription{\doignore{documentdescription}} +\def\docbook{\doignore{docbook}} +\def\html{\doignore{html}} +\def\ifdocbook{\doignore{ifdocbook}} +\def\ifhtml{\doignore{ifhtml}} +\def\ifinfo{\doignore{ifinfo}} +\def\ifnottex{\doignore{ifnottex}} +\def\ifplaintext{\doignore{ifplaintext}} +\def\ifxml{\doignore{ifxml}} +\def\ignore{\doignore{ignore}} +\def\menu{\doignore{menu}} +\def\xml{\doignore{xml}} + +% Ignore text until a line `@end #1', keeping track of nested conditionals. +% +% A count to remember the depth of nesting. +\newcount\doignorecount + +\def\doignore#1{\begingroup + % Scan in ``verbatim'' mode: + \catcode`\@ = \other + \catcode`\{ = \other + \catcode`\} = \other + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \spaceisspace + % + % Count number of #1's that we've seen. + \doignorecount = 0 + % + % Swallow text until we reach the matching `@end #1'. + \dodoignore{#1}% +} + +{ \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source. + \obeylines % + % + \gdef\dodoignore#1{% + % #1 contains the command name as a string, e.g., `ifinfo'. + % + % Define a command to find the next `@end #1', which must be on a line + % by itself. + \long\def\doignoretext##1^^M@end #1{\doignoretextyyy##1^^M@#1\_STOP_}% + % And this command to find another #1 command, at the beginning of a + % line. (Otherwise, we would consider a line `@c @ifset', for + % example, to count as an @ifset for nesting.) + \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}% + % + % And now expand that command. + \obeylines % + \doignoretext ^^M% + }% +} + +\def\doignoreyyy#1{% + \def\temp{#1}% + \ifx\temp\empty % Nothing found. + \let\next\doignoretextzzz + \else % Found a nested condition, ... + \advance\doignorecount by 1 + \let\next\doignoretextyyy % ..., look for another. + % If we're here, #1 ends with ^^M\ifinfo (for example). + \fi + \next #1% the token \_STOP_ is present just after this macro. +} + +% We have to swallow the remaining "\_STOP_". +% +\def\doignoretextzzz#1{% + \ifnum\doignorecount = 0 % We have just found the outermost @end. + \let\next\enddoignore + \else % Still inside a nested condition. + \advance\doignorecount by -1 + \let\next\doignoretext % Look for the next @end. + \fi + \next +} + +% Finish off ignored text. +\def\enddoignore{\endgroup\ignorespaces} + + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. +% We rely on the fact that \parsearg sets \catcode`\ =10. +% +\parseargdef\set{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + {% + \makevalueexpandable + \def\temp{#2}% + \edef\next{\gdef\makecsname{SET#1}}% + \ifx\temp\empty + \next{}% + \else + \setzzz#2\endsetzzz + \fi + }% +} +% Remove the trailing space \setxxx inserted. +\def\setzzz#1 \endsetzzz{\next{#1}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\parseargdef\clear{% + {% + \makevalueexpandable + \global\expandafter\let\csname SET#1\endcsname=\relax + }% +} + +% @value{foo} gets the text saved in variable foo. +\def\value{\begingroup\makevalueexpandable\valuexxx} +\def\valuexxx#1{\expandablevalue{#1}\endgroup} +{ + \catcode`\- = \active \catcode`\_ = \active + % + \gdef\makevalueexpandable{% + \let\value = \expandablevalue + % We don't want these characters active, ... + \catcode`\-=\other \catcode`\_=\other + % ..., but we might end up with active ones in the argument if + % we're called from @code, as @code{@value{foo-bar_}}, though. + % So \let them to their normal equivalents. + \let-\realdash \let_\normalunderscore + } +} + +% We have this subroutine so that we can handle at least some @value's +% properly in indexes (we call \makevalueexpandable in \indexdummies). +% The command has to be fully expandable (if the variable is set), since +% the result winds up in the index file. This means that if the +% variable's value contains other Texinfo commands, it's almost certain +% it will fail (although perhaps we could fix that with sufficient work +% to do a one-level expansion on the result, instead of complete). +% +\def\expandablevalue#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + {[No value for ``#1'']}% + \message{Variable `#1', used in @value, is not set.}% + \else + \csname SET#1\endcsname + \fi +} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +% To get special treatment of `@end ifset,' call \makeond and the redefine. +% +\makecond{ifset} +\def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}} +\def\doifset#1#2{% + {% + \makevalueexpandable + \let\next=\empty + \expandafter\ifx\csname SET#2\endcsname\relax + #1% If not set, redefine \next. + \fi + \expandafter + }\next +} +\def\ifsetfail{\doignore{ifset}} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +% The `\else' inside the `\doifset' parameter is a trick to reuse the +% above code: if the variable is not set, do nothing, if it is set, +% then redefine \next to \ifclearfail. +% +\makecond{ifclear} +\def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}} +\def\ifclearfail{\doignore{ifclear}} + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. +\let\dircategory=\comment + +% @defininfoenclose. +\let\definfoenclose=\comment + + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within macros and \if's. +\edef\newwrite{\makecsname{ptexnewwrite}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. +% +\def\newindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 % Open the file + \fi + \expandafter\xdef\csname#1index\endcsname{% % Define @#1index + \noexpand\doindex{#1}} +} + +% @defindex foo == \newindex{foo} +% +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. +% +\def\defcodeindex{\parsearg\newcodeindex} +% +\def\newcodeindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 + \fi + \expandafter\xdef\csname#1index\endcsname{% + \noexpand\docodeindex{#1}}% +} + + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +% +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +% +\def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}} +\def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}} + +% #1 is \doindex or \docodeindex, #2 the index getting redefined (foo), +% #3 the target index (bar). +\def\dosynindex#1#2#3{% + % Only do \closeout if we haven't already done it, else we'll end up + % closing the target index. + \expandafter \ifx\csname donesynindex#2\endcsname \undefined + % The \closeout helps reduce unnecessary open files; the limit on the + % Acorn RISC OS is a mere 16 files. + \expandafter\closeout\csname#2indfile\endcsname + \expandafter\let\csname\donesynindex#2\endcsname = 1 + \fi + % redefine \fooindfile: + \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname + \expandafter\let\csname#2indfile\endcsname=\temp + % redefine \fooindex: + \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +% Take care of Texinfo commands that can appear in an index entry. +% Since there are some commands we want to expand, and others we don't, +% we have to laboriously prevent expansion for those that we don't. +% +\def\indexdummies{% + \escapechar = `\\ % use backslash in output files. + \def\@{@}% change to @@ when we switch to @ as escape char in index files. + \def\ {\realbackslash\space }% + % Need these in case \tex is in effect and \{ is a \delimiter again. + % But can't use \lbracecmd and \rbracecmd because texindex assumes + % braces and backslashes are used only as delimiters. + \let\{ = \mylbrace + \let\} = \myrbrace + % + % Do the redefinitions. + \commondummies +} + +% For the aux and toc files, @ is the escape character. So we want to +% redefine everything using @ as the escape character (instead of +% \realbackslash, still used for index files). When everything uses @, +% this will be simpler. +% +\def\atdummies{% + \def\@{@@}% + \def\ {@ }% + \let\{ = \lbraceatcmd + \let\} = \rbraceatcmd + % + % Do the redefinitions. + \commondummies +} + +% Called from \indexdummies and \atdummies. +% +\def\commondummies{% + % + % \definedummyword defines \#1 as \string\#1\space, thus effectively + % preventing its expansion. This is used only for control% words, + % not control letters, because the \space would be incorrect for + % control characters, but is needed to separate the control word + % from whatever follows. + % + % For control letters, we have \definedummyletter, which omits the + % space. + % + % These can be used both for control words that take an argument and + % those that do not. If it is followed by {arg} in the input, then + % that will dutifully get written to the index (or wherever). + % + \def\definedummyword ##1{\def##1{\string##1\space}}% + \def\definedummyletter##1{\def##1{\string##1}}% + \let\definedummyaccent\definedummyletter + % + \commondummiesnofonts + % + \definedummyletter\_% + % + % Non-English letters. + \definedummyword\AA + \definedummyword\AE + \definedummyword\L + \definedummyword\OE + \definedummyword\O + \definedummyword\aa + \definedummyword\ae + \definedummyword\l + \definedummyword\oe + \definedummyword\o + \definedummyword\ss + \definedummyword\exclamdown + \definedummyword\questiondown + \definedummyword\ordf + \definedummyword\ordm + % + % Although these internal commands shouldn't show up, sometimes they do. + \definedummyword\bf + \definedummyword\gtr + \definedummyword\hat + \definedummyword\less + \definedummyword\sf + \definedummyword\sl + \definedummyword\tclose + \definedummyword\tt + % + \definedummyword\LaTeX + \definedummyword\TeX + % + % Assorted special characters. + \definedummyword\bullet + \definedummyword\comma + \definedummyword\copyright + \definedummyword\registeredsymbol + \definedummyword\dots + \definedummyword\enddots + \definedummyword\equiv + \definedummyword\error + \definedummyword\euro + \definedummyword\expansion + \definedummyword\minus + \definedummyword\pounds + \definedummyword\point + \definedummyword\print + \definedummyword\result + % + % We want to disable all macros so that they are not expanded by \write. + \macrolist + % + \normalturnoffactive + % + % Handle some cases of @value -- where it does not contain any + % (non-fully-expandable) commands. + \makevalueexpandable +} + +% \commondummiesnofonts: common to \commondummies and \indexnofonts. +% +% Better have this without active chars. +{ + \catcode`\~=\other + \gdef\commondummiesnofonts{% + % Control letters and accents. + \definedummyletter\!% + \definedummyaccent\"% + \definedummyaccent\'% + \definedummyletter\*% + \definedummyaccent\,% + \definedummyletter\.% + \definedummyletter\/% + \definedummyletter\:% + \definedummyaccent\=% + \definedummyletter\?% + \definedummyaccent\^% + \definedummyaccent\`% + \definedummyaccent\~% + \definedummyword\u + \definedummyword\v + \definedummyword\H + \definedummyword\dotaccent + \definedummyword\ringaccent + \definedummyword\tieaccent + \definedummyword\ubaraccent + \definedummyword\udotaccent + \definedummyword\dotless + % + % Texinfo font commands. + \definedummyword\b + \definedummyword\i + \definedummyword\r + \definedummyword\sc + \definedummyword\t + % + % Commands that take arguments. + \definedummyword\acronym + \definedummyword\cite + \definedummyword\code + \definedummyword\command + \definedummyword\dfn + \definedummyword\emph + \definedummyword\env + \definedummyword\file + \definedummyword\kbd + \definedummyword\key + \definedummyword\math + \definedummyword\option + \definedummyword\samp + \definedummyword\strong + \definedummyword\tie + \definedummyword\uref + \definedummyword\url + \definedummyword\var + \definedummyword\verb + \definedummyword\w + } +} + +% \indexnofonts is used when outputting the strings to sort the index +% by, and when constructing control sequence names. It eliminates all +% control sequences and just writes whatever the best ASCII sort string +% would be for a given command (usually its argument). +% +\def\indexnofonts{% + % Accent commands should become @asis. + \def\definedummyaccent##1{\let##1\asis}% + % We can just ignore other control letters. + \def\definedummyletter##1{\let##1\empty}% + % Hopefully, all control words can become @asis. + \let\definedummyword\definedummyaccent + % + \commondummiesnofonts + % + % Don't no-op \tt, since it isn't a user-level command + % and is used in the definitions of the active chars like <, >, |, etc. + % Likewise with the other plain tex font commands. + %\let\tt=\asis + % + \def\ { }% + \def\@{@}% + % how to handle braces? + \def\_{\normalunderscore}% + % + % Non-English letters. + \def\AA{AA}% + \def\AE{AE}% + \def\L{L}% + \def\OE{OE}% + \def\O{O}% + \def\aa{aa}% + \def\ae{ae}% + \def\l{l}% + \def\oe{oe}% + \def\o{o}% + \def\ss{ss}% + \def\exclamdown{!}% + \def\questiondown{?}% + \def\ordf{a}% + \def\ordm{o}% + % + \def\LaTeX{LaTeX}% + \def\TeX{TeX}% + % + % Assorted special characters. + % (The following {} will end up in the sort string, but that's ok.) + \def\bullet{bullet}% + \def\comma{,}% + \def\copyright{copyright}% + \def\registeredsymbol{R}% + \def\dots{...}% + \def\enddots{...}% + \def\equiv{==}% + \def\error{error}% + \def\euro{euro}% + \def\expansion{==>}% + \def\minus{-}% + \def\pounds{pounds}% + \def\point{.}% + \def\print{-|}% + \def\result{=>}% + % + % We need to get rid of all macros, leaving only the arguments (if present). + % Of course this is not nearly correct, but it is the best we can do for now. + % makeinfo does not expand macros in the argument to @deffn, which ends up + % writing an index entry, and texindex isn't prepared for an index sort entry + % that starts with \. + % + % Since macro invocations are followed by braces, we can just redefine them + % to take a single TeX argument. The case of a macro invocation that + % goes to end-of-line is not handled. + % + \macrolist +} + +\let\indexbackslash=0 %overridden during \printindex. +\let\SETmarginindex=\relax % put index entries in margin (undocumented)? + +% Most index entries go through here, but \dosubind is the general case. +% #1 is the index name, #2 is the entry text. +\def\doind#1#2{\dosubind{#1}{#2}{}} + +% Workhorse for all \fooindexes. +% #1 is name of index, #2 is stuff to put there, #3 is subentry -- +% empty if called from \doind, as we usually are (the main exception +% is with most defuns, which call us directly). +% +\def\dosubind#1#2#3{% + \iflinks + {% + % Store the main index entry text (including the third arg). + \toks0 = {#2}% + % If third arg is present, precede it with a space. + \def\thirdarg{#3}% + \ifx\thirdarg\empty \else + \toks0 = \expandafter{\the\toks0 \space #3}% + \fi + % + \edef\writeto{\csname#1indfile\endcsname}% + % + \ifvmode + \dosubindsanitize + \else + \dosubindwrite + \fi + }% + \fi +} + +% Write the entry in \toks0 to the index file: +% +\def\dosubindwrite{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}% + \fi + % + % Remember, we are within a group. + \indexdummies % Must do this here, since \bf, etc expand at this stage + \def\backslashcurfont{\indexbackslash}% \indexbackslash isn't defined now + % so it will be output as is; and it will print as backslash. + % + % Process the index entry with all font commands turned off, to + % get the string to sort by. + {\indexnofonts + \edef\temp{\the\toks0}% need full expansion + \xdef\indexsorttmp{\temp}% + }% + % + % Set up the complete index entry, with both the sort key and + % the original text, including any font commands. We write + % three arguments to \entry to the .?? file (four in the + % subentry case), texindex reduces to two when writing the .??s + % sorted result. + \edef\temp{% + \write\writeto{% + \string\entry{\indexsorttmp}{\noexpand\folio}{\the\toks0}}% + }% + \temp +} + +% Take care of unwanted page breaks: +% +% If a skip is the last thing on the list now, preserve it +% by backing up by \lastskip, doing the \write, then inserting +% the skip again. Otherwise, the whatsit generated by the +% \write will make \lastskip zero. The result is that sequences +% like this: +% @end defun +% @tindex whatever +% @defun ... +% will have extra space inserted, because the \medbreak in the +% start of the @defun won't see the skip inserted by the @end of +% the previous defun. +% +% But don't do any of this if we're not in vertical mode. We +% don't want to do a \vskip and prematurely end a paragraph. +% +% Avoid page breaks due to these extra skips, too. +% +% But wait, there is a catch there: +% We'll have to check whether \lastskip is zero skip. \ifdim is not +% sufficient for this purpose, as it ignores stretch and shrink parts +% of the skip. The only way seems to be to check the textual +% representation of the skip. +% +% The following is almost like \def\zeroskipmacro{0.0pt} except that +% the ``p'' and ``t'' characters have catcode \other, not 11 (letter). +% +\edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname} +% +% ..., ready, GO: +% +\def\dosubindsanitize{% + % \lastskip and \lastpenalty cannot both be nonzero simultaneously. + \skip0 = \lastskip + \edef\lastskipmacro{\the\lastskip}% + \count255 = \lastpenalty + % + % If \lastskip is nonzero, that means the last item was a + % skip. And since a skip is discardable, that means this + % -\skip0 glue we're inserting is preceded by a + % non-discardable item, therefore it is not a potential + % breakpoint, therefore no \nobreak needed. + \ifx\lastskipmacro\zeroskipmacro + \else + \vskip-\skip0 + \fi + % + \dosubindwrite + % + \ifx\lastskipmacro\zeroskipmacro + % If \lastskip was zero, perhaps the last item was a penalty, and + % perhaps it was >=10000, e.g., a \nobreak. In that case, we want + % to re-insert the same penalty (values >10000 are used for various + % signals); since we just inserted a non-discardable item, any + % following glue (such as a \parskip) would be a breakpoint. For example: + % + % @deffn deffn-whatever + % @vindex index-whatever + % Description. + % would allow a break between the index-whatever whatsit + % and the "Description." paragraph. + \ifnum\count255>9999 \penalty\count255 \fi + \else + % On the other hand, if we had a nonzero \lastskip, + % this make-up glue would be preceded by a non-discardable item + % (the whatsit from the \write), so we must insert a \nobreak. + \nobreak\vskip\skip0 + \fi +} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% @printindex causes a particular index (the ??s file) to get printed. +% It does not print any chapter heading (usually an @unnumbered). +% +\parseargdef\printindex{\begingroup + \dobreak \chapheadingskip{10000}% + % + \smallfonts \rm + \tolerance = 9500 + \everypar = {}% don't want the \kern\-parindent from indentation suppression. + % + % See if the index file exists and is nonempty. + % Change catcode of @ here so that if the index file contains + % \initial {@} + % as its first line, TeX doesn't complain about mismatched braces + % (because it thinks @} is a control sequence). + \catcode`\@ = 11 + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + \putwordIndexNonexistent + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + \putwordIndexIsEmpty + \else + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \def\indexbackslash{\backslashcurfont}% + \catcode`\\ = 0 + \escapechar = `\\ + \begindoublecolumns + \input \jobname.#1s + \enddoublecolumns + \fi + \fi + \closein 1 +\endgroup} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +\def\initial#1{{% + % Some minor font changes for the special characters. + \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt + % + % Remove any glue we may have, we'll be inserting our own. + \removelastskip + % + % We like breaks before the index initials, so insert a bonus. + \nobreak + \vskip 0pt plus 3\baselineskip + \penalty 0 + \vskip 0pt plus -3\baselineskip + % + % Typeset the initial. Making this add up to a whole number of + % baselineskips increases the chance of the dots lining up from column + % to column. It still won't often be perfect, because of the stretch + % we need before each entry, but it's better. + % + % No shrink because it confuses \balancecolumns. + \vskip 1.67\baselineskip plus .5\baselineskip + \leftline{\secbf #1}% + % Do our best not to break after the initial. + \nobreak + \vskip .33\baselineskip plus .1\baselineskip +}} + +% \entry typesets a paragraph consisting of the text (#1), dot leaders, and +% then page number (#2) flushed to the right margin. It is used for index +% and table of contents entries. The paragraph is indented by \leftskip. +% +% A straightforward implementation would start like this: +% \def\entry#1#2{... +% But this frozes the catcodes in the argument, and can cause problems to +% @code, which sets - active. This problem was fixed by a kludge--- +% ``-'' was active throughout whole index, but this isn't really right. +% +% The right solution is to prevent \entry from swallowing the whole text. +% --kasal, 21nov03 +\def\entry{% + \begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent = 2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % A bit of stretch before each entry for the benefit of balancing + % columns. + \vskip 0pt plus1pt + % + % Swallow the left brace of the text (first parameter): + \afterassignment\doentry + \let\temp = +} +\def\doentry{% + \bgroup % Instead of the swallowed brace. + \noindent + \aftergroup\finishentry + % And now comes the text of the entry. +} +\def\finishentry#1{% + % #1 is the page number. + % + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#1}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd + \ % + \else + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ifpdf + \pdfgettoks#1.% + \ \the\toksA + \else + \ #1% + \fi + \fi + \par + \endgroup +} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm +\def\secondary#1#2{{% + \parfillskip=0in + \parskip=0in + \hangindent=1in + \hangafter=1 + \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill + \ifpdf + \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. + \else + #2 + \fi + \par +}} + +% Define two-column mode, which we use to typeset indexes. +% Adapted from the TeXbook, page 416, which is to say, +% the manmac.tex format used to print the TeXbook itself. +\catcode`\@=11 + +\newbox\partialpage +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % Grab any single-column material above us. + \output = {% + % + % Here is a possibility not foreseen in manmac: if we accumulate a + % whole lot of material, we might end up calling this \output + % routine twice in a row (see the doublecol-lose test, which is + % essentially a couple of indexes with @setchapternewpage off). In + % that case we just ship out what is in \partialpage with the normal + % output routine. Generally, \partialpage will be empty when this + % runs and this will be a no-op. See the indexspread.tex test case. + \ifvoid\partialpage \else + \onepageout{\pagecontents\partialpage}% + \fi + % + \global\setbox\partialpage = \vbox{% + % Unvbox the main output page. + \unvbox\PAGE + \kern-\topskip \kern\baselineskip + }% + }% + \eject % run that output routine to set \partialpage + % + % Use the double-column output routine for subsequent pages. + \output = {\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it in one place. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +-<1pt) + % as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \vsize = 2\vsize +} + +% The double-column output routine for all double-column pages except +% the last. +% +\def\doublecolumnout{% + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@ = \vsize + \divide\dimen@ by 2 + \advance\dimen@ by -\ht\partialpage + % + % box0 will be the left-hand column, box2 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 + \penalty\outputpenalty +} +% +% Re-output the contents of the output page -- any previous material, +% followed by the two boxes we just split, in box0 and box2. +\def\pagesofar{% + \unvbox\partialpage + % + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize + \hbox to\pagewidth{\box0\hfil\box2}% +} +% +% All done with double columns. +\def\enddoublecolumns{% + \output = {% + % Split the last of the double-column material. Leave it on the + % current page, no automatic page break. + \balancecolumns + % + % If we end up splitting too much material for the current page, + % though, there will be another page break right after this \output + % invocation ends. Having called \balancecolumns once, we do not + % want to call it again. Therefore, reset \output to its normal + % definition right away. (We hope \balancecolumns will never be + % called on to balance too much material, but if it is, this makes + % the output somewhat more palatable.) + \global\output = {\onepageout{\pagecontents\PAGE}}% + }% + \eject + \endgroup % started in \begindoublecolumns + % + % \pagegoal was set to the doubled \vsize above, since we restarted + % the current page. We're now back to normal single-column + % typesetting, so reset \pagegoal to the normal \vsize (after the + % \endgroup where \vsize got restored). + \pagegoal = \vsize +} +% +% Called at the end of the double column material. +\def\balancecolumns{% + \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \divide\dimen@ by 2 % target to split to + %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% + \splittopskip = \topskip + % Loop until we get a decent breakpoint. + {% + \vbadness = 10000 + \loop + \global\setbox3 = \copy0 + \global\setbox1 = \vsplit3 to \dimen@ + \ifdim\ht3>\dimen@ + \global\advance\dimen@ by 1pt + \repeat + }% + %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + % + \pagesofar +} +\catcode`\@ = \other + + +\message{sectioning,} +% Chapters, sections, etc. + +% \unnumberedno is an oxymoron, of course. But we count the unnumbered +% sections so that we can refer to them unambiguously in the pdf +% outlines by their "section number". We avoid collisions with chapter +% numbers by starting them at 10000. (If a document ever has 10000 +% chapters, we're in trouble anyway, I'm sure.) +\newcount\unnumberedno \unnumberedno = 10000 +\newcount\chapno +\newcount\secno \secno=0 +\newcount\subsecno \subsecno=0 +\newcount\subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount\appendixno \appendixno = `\@ +% +% \def\appendixletter{\char\the\appendixno} +% We do the following ugly conditional instead of the above simple +% construct for the sake of pdftex, which needs the actual +% letter in the expansion, not just typeset. +% +\def\appendixletter{% + \ifnum\appendixno=`A A% + \else\ifnum\appendixno=`B B% + \else\ifnum\appendixno=`C C% + \else\ifnum\appendixno=`D D% + \else\ifnum\appendixno=`E E% + \else\ifnum\appendixno=`F F% + \else\ifnum\appendixno=`G G% + \else\ifnum\appendixno=`H H% + \else\ifnum\appendixno=`I I% + \else\ifnum\appendixno=`J J% + \else\ifnum\appendixno=`K K% + \else\ifnum\appendixno=`L L% + \else\ifnum\appendixno=`M M% + \else\ifnum\appendixno=`N N% + \else\ifnum\appendixno=`O O% + \else\ifnum\appendixno=`P P% + \else\ifnum\appendixno=`Q Q% + \else\ifnum\appendixno=`R R% + \else\ifnum\appendixno=`S S% + \else\ifnum\appendixno=`T T% + \else\ifnum\appendixno=`U U% + \else\ifnum\appendixno=`V V% + \else\ifnum\appendixno=`W W% + \else\ifnum\appendixno=`X X% + \else\ifnum\appendixno=`Y Y% + \else\ifnum\appendixno=`Z Z% + % The \the is necessary, despite appearances, because \appendixletter is + % expanded while writing the .toc file. \char\appendixno is not + % expandable, thus it is written literally, thus all appendixes come out + % with the same letter (or @) in the toc without it. + \else\char\the\appendixno + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise. +% However, they are not reliable, because we don't use marks. +\def\thischapter{} +\def\thissection{} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% we only have subsub. +\chardef\maxseclevel = 3 +% +% A numbered section within an unnumbered changes to unnumbered too. +% To achive this, remember the "biggest" unnum. sec. we are currently in: +\chardef\unmlevel = \maxseclevel +% +% Trace whether the current chapter is an appendix or not: +% \chapheadtype is "N" or "A", unnumbered chapters are ignored. +\def\chapheadtype{N} + +% Choose a heading macro +% #1 is heading type +% #2 is heading level +% #3 is text for heading +\def\genhead#1#2#3{% + % Compute the abs. sec. level: + \absseclevel=#2 + \advance\absseclevel by \secbase + % Make sure \absseclevel doesn't fall outside the range: + \ifnum \absseclevel < 0 + \absseclevel = 0 + \else + \ifnum \absseclevel > 3 + \absseclevel = 3 + \fi + \fi + % The heading type: + \def\headtype{#1}% + \if \headtype U% + \ifnum \absseclevel < \unmlevel + \chardef\unmlevel = \absseclevel + \fi + \else + % Check for appendix sections: + \ifnum \absseclevel = 0 + \edef\chapheadtype{\headtype}% + \else + \if \headtype A\if \chapheadtype N% + \errmessage{@appendix... within a non-appendix chapter}% + \fi\fi + \fi + % Check for numbered within unnumbered: + \ifnum \absseclevel > \unmlevel + \def\headtype{U}% + \else + \chardef\unmlevel = 3 + \fi + \fi + % Now print the heading: + \if \headtype U% + \ifcase\absseclevel + \unnumberedzzz{#3}% + \or \unnumberedseczzz{#3}% + \or \unnumberedsubseczzz{#3}% + \or \unnumberedsubsubseczzz{#3}% + \fi + \else + \if \headtype A% + \ifcase\absseclevel + \appendixzzz{#3}% + \or \appendixsectionzzz{#3}% + \or \appendixsubseczzz{#3}% + \or \appendixsubsubseczzz{#3}% + \fi + \else + \ifcase\absseclevel + \chapterzzz{#3}% + \or \seczzz{#3}% + \or \numberedsubseczzz{#3}% + \or \numberedsubsubseczzz{#3}% + \fi + \fi + \fi + \suppressfirstparagraphindent +} + +% an interface: +\def\numhead{\genhead N} +\def\apphead{\genhead A} +\def\unnmhead{\genhead U} + +% @chapter, @appendix, @unnumbered. Increment top-level counter, reset +% all lower-level sectioning counters to zero. +% +% Also set \chaplevelprefix, which we prepend to @float sequence numbers +% (e.g., figures), q.v. By default (before any chapter), that is empty. +\let\chaplevelprefix = \empty +% +\outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz#1{% + % section resetting is \global in case the chapter is in a group, such + % as an @include file. + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\chapno by 1 + % + % Used for \float. + \gdef\chaplevelprefix{\the\chapno.}% + \resetallfloatnos + % + \message{\putwordChapter\space \the\chapno}% + % + % Write the actual heading. + \chapmacro{#1}{Ynumbered}{\the\chapno}% + % + % So @section and the like are numbered underneath this chapter. + \global\let\section = \numberedsec + \global\let\subsection = \numberedsubsec + \global\let\subsubsection = \numberedsubsubsec +} + +\outer\parseargdef\appendix{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz#1{% + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\appendixno by 1 + \gdef\chaplevelprefix{\appendixletter.}% + \resetallfloatnos + % + \def\appendixnum{\putwordAppendix\space \appendixletter}% + \message{\appendixnum}% + % + \chapmacro{#1}{Yappendix}{\appendixletter}% + % + \global\let\section = \appendixsec + \global\let\subsection = \appendixsubsec + \global\let\subsubsection = \appendixsubsubsec +} + +\outer\parseargdef\unnumbered{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz#1{% + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\unnumberedno by 1 + % + % Since an unnumbered has no number, no prefix for figures. + \global\let\chaplevelprefix = \empty + \resetallfloatnos + % + % This used to be simply \message{#1}, but TeX fully expands the + % argument to \message. Therefore, if #1 contained @-commands, TeX + % expanded them. For example, in `@unnumbered The @cite{Book}', TeX + % expanded @cite (which turns out to cause errors because \cite is meant + % to be executed, not expanded). + % + % Anyway, we don't want the fully-expanded definition of @cite to appear + % as a result of the \message, we just want `@cite' itself. We use + % \the to achieve this: TeX expands \the only once, + % simply yielding the contents of . (We also do this for + % the toc entries.) + \toks0 = {#1}% + \message{(\the\toks0)}% + % + \chapmacro{#1}{Ynothing}{\the\unnumberedno}% + % + \global\let\section = \unnumberedsec + \global\let\subsection = \unnumberedsubsec + \global\let\subsubsection = \unnumberedsubsubsec +} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\parseargdef\centerchap{% + % Well, we could do the following in a group, but that would break + % an assumption that \chapmacro is called at the outermost level. + % Thus we are safer this way: --kasal, 24feb04 + \let\centerparametersmaybe = \centerparameters + \unnmhead0{#1}% + \let\centerparametersmaybe = \relax +} + +% @top is like @unnumbered. +\let\top\unnumbered + +% Sections. +\outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz +\def\seczzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}% +} + +\outer\parseargdef\appendixsection{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}% +} +\let\appendixsec\appendixsection + +\outer\parseargdef\unnumberedsec{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}% +} + +% Subsections. +\outer\parseargdef\numberedsubsec{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}% +} + +\outer\parseargdef\appendixsubsec{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Yappendix}% + {\appendixletter.\the\secno.\the\subsecno}% +} + +\outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Ynothing}% + {\the\unnumberedno.\the\secno.\the\subsecno}% +} + +% Subsubsections. +\outer\parseargdef\numberedsubsubsec{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Ynumbered}% + {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +\outer\parseargdef\appendixsubsubsec{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Yappendix}% + {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +\outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Ynothing}% + {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\let\section = \numberedsec +\let\subsection = \numberedsubsec +\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{% + {\advance\chapheadingskip by 10pt \chapbreak }% + \parsearg\chapheadingzzz +} + +\def\chapheading{\chapbreak \parsearg\chapheadingzzz} +\def\chapheadingzzz#1{% + {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% + \bigskip \par\penalty 200\relax + \suppressfirstparagraphindent +} + +% @heading, @subheading, @subsubheading. +\parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} +\parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} +\parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip\chapheadingskip + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{% +\global\let\contentsalignmacro = \chapoddpage +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +% Chapter opening. +% +% #1 is the text, #2 is the section type (Ynumbered, Ynothing, +% Yappendix, Yomitfromtoc), #3 the chapter number. +% +% To test against our argument. +\def\Ynothingkeyword{Ynothing} +\def\Yomitfromtockeyword{Yomitfromtoc} +\def\Yappendixkeyword{Yappendix} +% +\def\chapmacro#1#2#3{% + \pchapsepmacro + {% + \chapfonts \rm + % + % Have to define \thissection before calling \donoderef, because the + % xref code eventually uses it. On the other hand, it has to be called + % after \pchapsepmacro, or the headline will change too soon. + \gdef\thissection{#1}% + \gdef\thischaptername{#1}% + % + % Only insert the separating space if we have a chapter/appendix + % number, and don't print the unnumbered ``number''. + \def\temptype{#2}% + \ifx\temptype\Ynothingkeyword + \setbox0 = \hbox{}% + \def\toctype{unnchap}% + \gdef\thischapter{#1}% + \else\ifx\temptype\Yomitfromtockeyword + \setbox0 = \hbox{}% contents like unnumbered, but no toc entry + \def\toctype{omit}% + \gdef\thischapter{}% + \else\ifx\temptype\Yappendixkeyword + \setbox0 = \hbox{\putwordAppendix{} #3\enspace}% + \def\toctype{app}% + % We don't substitute the actual chapter name into \thischapter + % because we don't want its macros evaluated now. And we don't + % use \thissection because that changes with each section. + % + \xdef\thischapter{\putwordAppendix{} \appendixletter: + \noexpand\thischaptername}% + \else + \setbox0 = \hbox{#3\enspace}% + \def\toctype{numchap}% + \xdef\thischapter{\putwordChapter{} \the\chapno: + \noexpand\thischaptername}% + \fi\fi\fi + % + % Write the toc entry for this chapter. Must come before the + % \donoderef, because we include the current node name in the toc + % entry, and \donoderef resets it to empty. + \writetocentry{\toctype}{#1}{#3}% + % + % For pdftex, we have to write out the node definition (aka, make + % the pdfdest) after any page break, but before the actual text has + % been typeset. If the destination for the pdf outline is after the + % text, then jumping from the outline may wind up with the text not + % being visible, for instance under high magnification. + \donoderef{#2}% + % + % Typeset the actual heading. + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent=\wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak +} + +% @centerchap -- centered and unnumbered. +\let\centerparametersmaybe = \relax +\def\centerparameters{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt +} + + +% I don't think this chapter style is supported any more, so I'm not +% updating it with the new noderef stuff. We'll see. --karl, 11aug03. +% +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} +% +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\nobreak +} +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} +\def\centerchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt + \hfill {\rm #1}\hfill}}\bigskip \par\nobreak +} +\def\CHAPFopen{% + \global\let\chapmacro=\chfopen + \global\let\centerchapmacro=\centerchfopen} + + +% Section titles. These macros combine the section number parts and +% call the generic \sectionheading to do the printing. +% +\newskip\secheadingskip +\def\secheadingbreak{\dobreak \secheadingskip{-1000}} + +% Subsection titles. +\newskip\subsecheadingskip +\def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}} + +% Subsubsection titles. +\def\subsubsecheadingskip{\subsecheadingskip} +\def\subsubsecheadingbreak{\subsecheadingbreak} + + +% Print any size, any type, section title. +% +% #1 is the text, #2 is the section level (sec/subsec/subsubsec), #3 is +% the section type for xrefs (Ynumbered, Ynothing, Yappendix), #4 is the +% section number. +% +\def\sectionheading#1#2#3#4{% + {% + % Switch to the right set of fonts. + \csname #2fonts\endcsname \rm + % + % Insert space above the heading. + \csname #2headingbreak\endcsname + % + % Only insert the space after the number if we have a section number. + \def\sectionlevel{#2}% + \def\temptype{#3}% + % + \ifx\temptype\Ynothingkeyword + \setbox0 = \hbox{}% + \def\toctype{unn}% + \gdef\thissection{#1}% + \else\ifx\temptype\Yomitfromtockeyword + % for @headings -- no section number, don't include in toc, + % and don't redefine \thissection. + \setbox0 = \hbox{}% + \def\toctype{omit}% + \let\sectionlevel=\empty + \else\ifx\temptype\Yappendixkeyword + \setbox0 = \hbox{#4\enspace}% + \def\toctype{app}% + \gdef\thissection{#1}% + \else + \setbox0 = \hbox{#4\enspace}% + \def\toctype{num}% + \gdef\thissection{#1}% + \fi\fi\fi + % + % Write the toc entry (before \donoderef). See comments in \chfplain. + \writetocentry{\toctype\sectionlevel}{#1}{#4}% + % + % Write the node reference (= pdf destination for pdftex). + % Again, see comments in \chfplain. + \donoderef{#3}% + % + % Output the actual section heading. + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent=\wd0 % zero if no section number + \unhbox0 #1}% + }% + % Add extra space after the heading -- half of whatever came above it. + % Don't allow stretch, though. + \kern .5 \csname #2headingskip\endcsname + % + % Do not let the kern be a potential breakpoint, as it would be if it + % was followed by glue. + \nobreak + % + % We'll almost certainly start a paragraph next, so don't let that + % glue accumulate. (Not a breakpoint because it's preceded by a + % discardable item.) + \vskip-\parskip + % + % This is purely so the last item on the list is a known \penalty > + % 10000. This is so \startdefun can avoid allowing breakpoints after + % section headings. Otherwise, it would insert a valid breakpoint between: + % + % @section sec-whatever + % @deffn def-whatever + \penalty 10001 +} + + +\message{toc,} +% Table of contents. +\newwrite\tocfile + +% Write an entry to the toc file, opening it if necessary. +% Called from @chapter, etc. +% +% Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno} +% We append the current node name (if any) and page number as additional +% arguments for the \{chap,sec,...}entry macros which will eventually +% read this. The node name is used in the pdf outlines as the +% destination to jump to. +% +% We open the .toc file for writing here instead of at @setfilename (or +% any other fixed time) so that @contents can be anywhere in the document. +% But if #1 is `omit', then we don't do anything. This is used for the +% table of contents chapter openings themselves. +% +\newif\iftocfileopened +\def\omitkeyword{omit}% +% +\def\writetocentry#1#2#3{% + \edef\writetoctype{#1}% + \ifx\writetoctype\omitkeyword \else + \iftocfileopened\else + \immediate\openout\tocfile = \jobname.toc + \global\tocfileopenedtrue + \fi + % + \iflinks + {\atdummies + \edef\temp{% + \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}% + \temp + } + \fi + \fi + % + % Tell \shipout to create a pdf destination on each page, if we're + % writing pdf. These are used in the table of contents. We can't + % just write one on every page because the title pages are numbered + % 1 and 2 (the page numbers aren't printed), and so are the first + % two pages of the document. Thus, we'd have two destinations named + % `1', and two named `2'. + \ifpdf \global\pdfmakepagedesttrue \fi +} + + +% These characters do not print properly in the Computer Modern roman +% fonts, so we must take special care. This is more or less redundant +% with the Texinfo input format setup at the end of this file. +% +\def\activecatcodes{% + \catcode`\"=\active + \catcode`\$=\active + \catcode`\<=\active + \catcode`\>=\active + \catcode`\\=\active + \catcode`\^=\active + \catcode`\_=\active + \catcode`\|=\active + \catcode`\~=\active +} + + +% Read the toc file, which is essentially Texinfo input. +\def\readtocfile{% + \setupdatafile + \activecatcodes + \input \jobname.toc +} + +\newskip\contentsrightmargin \contentsrightmargin=1in +\newcount\savepageno +\newcount\lastnegativepageno \lastnegativepageno = -1 + +% Prepare to read what we've written to \tocfile. +% +\def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund + \contentsalignmacro + \immediate\closeout\tocfile + % + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \def\thischapter{}% + \chapmacro{#1}{Yomitfromtoc}{}% + % + \savepageno = \pageno + \begingroup % Set up to handle contents files properly. + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. + % + % Roman numerals for page numbers. + \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi +} + + +% Normal (long) toc. +\def\contents{% + \startcontents{\putwordTOC}% + \openin 1 \jobname.toc + \ifeof 1 \else + \readtocfile + \fi + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \ifeof 1 \else + \pdfmakeoutlines + \fi + \closein 1 + \endgroup + \lastnegativepageno = \pageno + \global\pageno = \savepageno +} + +% And just the chapters. +\def\summarycontents{% + \startcontents{\putwordShortTOC}% + % + \let\numchapentry = \shortchapentry + \let\appentry = \shortchapentry + \let\unnchapentry = \shortunnchapentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf + \let\sl=\shortcontsl \let\tt=\shortconttt + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\numsecentry##1##2##3##4{} + \let\appsecentry = \numsecentry + \let\unnsecentry = \numsecentry + \let\numsubsecentry = \numsecentry + \let\appsubsecentry = \numsecentry + \let\unnsubsecentry = \numsecentry + \let\numsubsubsecentry = \numsecentry + \let\appsubsubsecentry = \numsecentry + \let\unnsubsubsecentry = \numsecentry + \openin 1 \jobname.toc + \ifeof 1 \else + \readtocfile + \fi + \closein 1 + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \endgroup + \lastnegativepageno = \pageno + \global\pageno = \savepageno +} +\let\shortcontents = \summarycontents + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g., `A' for an appendix, or `3' for a chapter. +% +\def\shortchaplabel#1{% + % This space should be enough, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % But use \hss just in case. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + % + % We'd like to right-justify chapter numbers, but that looks strange + % with appendix letters. And right-justifying numbers and + % left-justifying letters looks strange when there is less than 10 + % chapters. Have to read the whole toc once to know how many chapters + % there are before deciding ... + \hbox to 1em{#1\hss}% +} + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapters, in the main contents. +\def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}} +% +% Chapters, in the short toc. +% See comments in \dochapentry re vbox and related settings. +\def\shortchapentry#1#2#3#4{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}% +} + +% Appendices, in the main contents. +% Need the word Appendix, and a fixed-size box. +% +\def\appendixbox#1{% + % We use M since it's probably the widest letter. + \setbox0 = \hbox{\putwordAppendix{} M}% + \hbox to \wd0{\putwordAppendix{} #1\hss}} +% +\def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\labelspace#1}{#4}} + +% Unnumbered chapters. +\def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}} +\def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}} + +% Sections. +\def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}} +\let\appsecentry=\numsecentry +\def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}} + +% Subsections. +\def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}} +\let\appsubsecentry=\numsubsecentry +\def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}} + +% And subsubsections. +\def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}} +\let\appsubsubsecentry=\numsubsubsecentry +\def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}} + +% This parameter controls the indentation of the various levels. +% Same as \defaultparindent. +\newdimen\tocindent \tocindent = 15pt + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we want it to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno\bgroup#2\egroup}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +% We use the same \entry macro as for the index entries. +\let\tocentry = \entry + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\def\subsecentryfonts{\textfonts} +\def\subsubsecentryfonts{\textfonts} + + +\message{environments,} +% @foo ... @end foo. + +% @point{}, @result{}, @expansion{}, @print{}, @equiv{}. +% +% Since these characters are used in examples, it should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% +\def\point{$\star$} +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% The @error{} command. +% Adapted from the TeXbook's \boxit. +% +\newbox\errorbox +% +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} +% +\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{% + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} +% +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\envdef\tex{% + \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 + \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 + \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie + \catcode `\%=14 + \catcode `\+=\other + \catcode `\"=\other + \catcode `\|=\other + \catcode `\<=\other + \catcode `\>=\other + \escapechar=`\\ + % + \let\b=\ptexb + \let\bullet=\ptexbullet + \let\c=\ptexc + \let\,=\ptexcomma + \let\.=\ptexdot + \let\dots=\ptexdots + \let\equiv=\ptexequiv + \let\!=\ptexexclam + \let\i=\ptexi + \let\indent=\ptexindent + \let\noindent=\ptexnoindent + \let\{=\ptexlbrace + \let\+=\tabalign + \let\}=\ptexrbrace + \let\/=\ptexslash + \let\*=\ptexstar + \let\t=\ptext + \let\frenchspacing=\plainfrenchspacing + % + \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% + \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% + \def\@{@}% +} +% There is no need to define \Etex. + +% Define @lisp ... @end lisp. +% @lisp environment forms a group so it can rebind things, +% including the definition of @end lisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip. +% +\def\aboveenvbreak{{% + % =10000 instead of <10000 because of a special case in \itemzzz and + % \sectionheading, q.v. + \ifnum \lastpenalty=10000 \else + \advance\envskipamount by \parskip + \endgraf + \ifdim\lastskip<\envskipamount + \removelastskip + % it's not a good place to break if the last penalty was \nobreak + % or better ... + \ifnum\lastpenalty<10000 \penalty-50 \fi + \vskip\envskipamount + \fi + \fi +}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins; it will +% also clear it, so that its embedded environments do the narrowing again. +\let\nonarrowing=\relax + +% @cartouche ... @end cartouche: draw rectangle w/rounded corners around +% environment contents. +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\envdef\cartouche{% + \ifhmode\par\fi % can't be in the midst of a paragraph. + \startsavinginserts + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt % we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18.4pt % allow for 3pt kerns on either + % side, and for 6pt waste from + % each corner char, and rule thickness + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing = t% + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \kern3pt + \hsize=\cartinner + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip + \comment % For explanation, see the end of \def\group. +} +\def\Ecartouche{% + \ifhmode\par\fi + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup + \checkinserts +} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \else + \let\nonarrowing = \relax + \fi + \let\exdent=\nofillexdent +} + +% If you want all examples etc. small: @set dispenvsize small. +% If you want even small examples the full size: @set dispenvsize nosmall. +% This affects the following displayed environments: +% @example, @display, @format, @lisp +% +\def\smallword{small} +\def\nosmallword{nosmall} +\let\SETdispenvsize\relax +\def\setnormaldispenv{% + \ifx\SETdispenvsize\smallword + \smallexamplefonts \rm + \fi +} +\def\setsmalldispenv{% + \ifx\SETdispenvsize\nosmallword + \else + \smallexamplefonts \rm + \fi +} + +% We often define two environments, @foo and @smallfoo. +% Let's do it by one command: +\def\makedispenv #1#2{ + \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2} + \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2} + \expandafter\let\csname E#1\endcsname \afterenvbreak + \expandafter\let\csname Esmall#1\endcsname \afterenvbreak +} + +% Define two synonyms: +\def\maketwodispenvs #1#2#3{ + \makedispenv{#1}{#3} + \makedispenv{#2}{#3} +} + +% @lisp: indented, narrowed, typewriter font; @example: same as @lisp. +% +% @smallexample and @smalllisp: use smaller fonts. +% Originally contributed by Pavel@xerox. +% +\maketwodispenvs {lisp}{example}{% + \nonfillstart + \tt + \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. + \gobble % eat return +} + +% @display/@smalldisplay: same as @lisp except keep current font. +% +\makedispenv {display}{% + \nonfillstart + \gobble +} + +% @format/@smallformat: same as @display except don't narrow margins. +% +\makedispenv{format}{% + \let\nonarrowing = t% + \nonfillstart + \gobble +} + +% @flushleft: same as @format, but doesn't obey \SETdispenvsize. +\envdef\flushleft{% + \let\nonarrowing = t% + \nonfillstart + \gobble +} +\let\Eflushleft = \afterenvbreak + +% @flushright. +% +\envdef\flushright{% + \let\nonarrowing = t% + \nonfillstart + \advance\leftskip by 0pt plus 1fill + \gobble +} +\let\Eflushright = \afterenvbreak + + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. We keep \parskip nonzero in general, since +% we're doing normal filling. So, when using \aboveenvbreak and +% \afterenvbreak, temporarily make \parskip 0. +% +\envdef\quotation{% + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \parindent=0pt + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \else + \let\nonarrowing = \relax + \fi + \parsearg\quotationlabel +} + +% We have retained a nonzero parskip for the environment, since we're +% doing normal filling. +% +\def\Equotation{% + \par + \ifx\quotationauthor\undefined\else + % indent a bit. + \leftline{\kern 2\leftskip \sl ---\quotationauthor}% + \fi + {\parskip=0pt \afterenvbreak}% +} + +% If we're given an argument, typeset it in bold with a colon after. +\def\quotationlabel#1{% + \def\temp{#1}% + \ifx\temp\empty \else + {\bf #1: }% + \fi +} + + +% LaTeX-like @verbatim...@end verbatim and @verb{...} +% If we want to allow any as delimiter, +% we need the curly braces so that makeinfo sees the @verb command, eg: +% `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org +% +% [Knuth]: Donald Ervin Knuth, 1996. The TeXbook. +% +% [Knuth] p.344; only we need to do the other characters Texinfo sets +% active too. Otherwise, they get lost as the first character on a +% verbatim line. +\def\dospecials{% + \do\ \do\\\do\{\do\}\do\$\do\&% + \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~% + \do\<\do\>\do\|\do\@\do+\do\"% +} +% +% [Knuth] p. 380 +\def\uncatcodespecials{% + \def\do##1{\catcode`##1=\other}\dospecials} +% +% [Knuth] pp. 380,381,391 +% Disable Spanish ligatures ?` and !` of \tt font +\begingroup + \catcode`\`=\active\gdef`{\relax\lq} +\endgroup +% +% Setup for the @verb command. +% +% Eight spaces for a tab +\begingroup + \catcode`\^^I=\active + \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }} +\endgroup +% +\def\setupverb{% + \tt % easiest (and conventionally used) font for verbatim + \def\par{\leavevmode\endgraf}% + \catcode`\`=\active + \tabeightspaces + % Respect line breaks, + % print special symbols as themselves, and + % make each space count + % must do in this order: + \obeylines \uncatcodespecials \sepspaces +} + +% Setup for the @verbatim environment +% +% Real tab expansion +\newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount +% +\def\starttabbox{\setbox0=\hbox\bgroup} +\begingroup + \catcode`\^^I=\active + \gdef\tabexpand{% + \catcode`\^^I=\active + \def^^I{\leavevmode\egroup + \dimen0=\wd0 % the width so far, or since the previous tab + \divide\dimen0 by\tabw + \multiply\dimen0 by\tabw % compute previous multiple of \tabw + \advance\dimen0 by\tabw % advance to next multiple of \tabw + \wd0=\dimen0 \box0 \starttabbox + }% + } +\endgroup +\def\setupverbatim{% + \let\nonarrowing = t% + \nonfillstart + % Easiest (and conventionally used) font for verbatim + \tt + \def\par{\leavevmode\egroup\box0\endgraf}% + \catcode`\`=\active + \tabexpand + % Respect line breaks, + % print special symbols as themselves, and + % make each space count + % must do in this order: + \obeylines \uncatcodespecials \sepspaces + \everypar{\starttabbox}% +} + +% Do the @verb magic: verbatim text is quoted by unique +% delimiter characters. Before first delimiter expect a +% right brace, after last delimiter expect closing brace: +% +% \def\doverb'{'#1'}'{#1} +% +% [Knuth] p. 382; only eat outer {} +\begingroup + \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other + \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next] +\endgroup +% +\def\verb{\begingroup\setupverb\doverb} +% +% +% Do the @verbatim magic: define the macro \doverbatim so that +% the (first) argument ends when '@end verbatim' is reached, ie: +% +% \def\doverbatim#1@end verbatim{#1} +% +% For Texinfo it's a lot easier than for LaTeX, +% because texinfo's \verbatim doesn't stop at '\end{verbatim}': +% we need not redefine '\', '{' and '}'. +% +% Inspired by LaTeX's verbatim command set [latex.ltx] +% +\begingroup + \catcode`\ =\active + \obeylines % + % ignore everything up to the first ^^M, that's the newline at the end + % of the @verbatim input line itself. Otherwise we get an extra blank + % line in the output. + \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}% + % We really want {...\end verbatim} in the body of the macro, but + % without the active space; thus we have to use \xdef and \gobble. +\endgroup +% +\envdef\verbatim{% + \setupverbatim\doverbatim +} +\let\Everbatim = \afterenvbreak + + +% @verbatiminclude FILE - insert text of file in verbatim environment. +% +\def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude} +% +\def\doverbatiminclude#1{% + {% + \makevalueexpandable + \setupverbatim + \input #1 + \afterenvbreak + }% +} + +% @copying ... @end copying. +% Save the text away for @insertcopying later. +% +% We save the uninterpreted tokens, rather than creating a box. +% Saving the text in a box would be much easier, but then all the +% typesetting commands (@smallbook, font changes, etc.) have to be done +% beforehand -- and a) we want @copying to be done first in the source +% file; b) letting users define the frontmatter in as flexible order as +% possible is very desirable. +% +\def\copying{\checkenv{}\begingroup\scanargctxt\docopying} +\def\docopying#1@end copying{\endgroup\def\copyingtext{#1}} +% +\def\insertcopying{% + \begingroup + \parindent = 0pt % paragraph indentation looks wrong on title page + \scanexp\copyingtext + \endgroup +} + +\message{defuns,} +% @defun etc. + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deflastargmargin \deflastargmargin=18pt + +% Start the processing of @deffn: +\def\startdefun{% + \ifnum\lastpenalty<10000 + \medbreak + \else + % If there are two @def commands in a row, we'll have a \nobreak, + % which is there to keep the function description together with its + % header. But if there's nothing but headers, we need to allow a + % break somewhere. Check specifically for penalty 10002, inserted + % by \defargscommonending, instead of 10000, since the sectioning + % commands also insert a nobreak penalty, and we don't want to allow + % a break between a section heading and a defun. + % + \ifnum\lastpenalty=10002 \penalty2000 \fi + % + % Similarly, after a section heading, do not allow a break. + % But do insert the glue. + \medskip % preceded by discardable penalty, so not a breakpoint + \fi + % + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent +} + +\def\dodefunx#1{% + % First, check whether we are in the right environment: + \checkenv#1% + % + % As above, allow line break if we have multiple x headers in a row. + % It's not a great place, though. + \ifnum\lastpenalty=10002 \penalty3000 \fi + % + % And now, it's time to reuse the body of the original defun: + \expandafter\gobbledefun#1% +} +\def\gobbledefun#1\startdefun{} + +% \printdefunline \deffnheader{text} +% +\def\printdefunline#1#2{% + \begingroup + % call \deffnheader: + #1#2 \endheader + % common ending: + \interlinepenalty = 10000 + \advance\rightskip by 0pt plus 1fil + \endgraf + \nobreak\vskip -\parskip + \penalty 10002 % signal to \startdefun and \dodefunx + % Some of the @defun-type tags do not enable magic parentheses, + % rendering the following check redundant. But we don't optimize. + \checkparencounts + \endgroup +} + +\def\Edefun{\endgraf\medbreak} + +% \makedefun{deffn} creates \deffn, \deffnx and \Edeffn; +% the only thing remainnig is to define \deffnheader. +% +\def\makedefun#1{% + \expandafter\let\csname E#1\endcsname = \Edefun + \edef\temp{\noexpand\domakedefun + \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}% + \temp +} + +% \domakedefun \deffn \deffnx \deffnheader +% +% Define \deffn and \deffnx, without parameters. +% \deffnheader has to be defined explicitly. +% +\def\domakedefun#1#2#3{% + \envdef#1{% + \startdefun + \parseargusing\activeparens{\printdefunline#3}% + }% + \def#2{\dodefunx#1}% + \def#3% +} + +%%% Untyped functions: + +% @deffn category name args +\makedefun{deffn}{\deffngeneral{}} + +% @deffn category class name args +\makedefun{defop}#1 {\defopon{#1\ \putwordon}} + +% \defopon {category on}class name args +\def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } + +% \deffngeneral {subind}category name args +% +\def\deffngeneral#1#2 #3 #4\endheader{% + % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}. + \dosubind{fn}{\code{#3}}{#1}% + \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}% +} + +%%% Typed functions: + +% @deftypefn category type name args +\makedefun{deftypefn}{\deftypefngeneral{}} + +% @deftypeop category class type name args +\makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}} + +% \deftypeopon {category on}class type name args +\def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } + +% \deftypefngeneral {subind}category type name args +% +\def\deftypefngeneral#1#2 #3 #4 #5\endheader{% + \dosubind{fn}{\code{#4}}{#1}% + \defname{#2}{#3}{#4}\defunargs{#5\unskip}% +} + +%%% Typed variables: + +% @deftypevr category type var args +\makedefun{deftypevr}{\deftypecvgeneral{}} + +% @deftypecv category class type var args +\makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}} + +% \deftypecvof {category of}class type var args +\def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} } + +% \deftypecvgeneral {subind}category type var args +% +\def\deftypecvgeneral#1#2 #3 #4 #5\endheader{% + \dosubind{vr}{\code{#4}}{#1}% + \defname{#2}{#3}{#4}\defunargs{#5\unskip}% +} + +%%% Untyped variables: + +% @defvr category var args +\makedefun{defvr}#1 {\deftypevrheader{#1} {} } + +% @defcv category class var args +\makedefun{defcv}#1 {\defcvof{#1\ \putwordof}} + +% \defcvof {category of}class var args +\def\defcvof#1#2 {\deftypecvof{#1}#2 {} } + +%%% Type: +% @deftp category name args +\makedefun{deftp}#1 #2 #3\endheader{% + \doind{tp}{\code{#2}}% + \defname{#1}{}{#2}\defunargs{#3\unskip}% +} + +% Remaining @defun-like shortcuts: +\makedefun{defun}{\deffnheader{\putwordDeffunc} } +\makedefun{defmac}{\deffnheader{\putwordDefmac} } +\makedefun{defspec}{\deffnheader{\putwordDefspec} } +\makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} } +\makedefun{defvar}{\defvrheader{\putwordDefvar} } +\makedefun{defopt}{\defvrheader{\putwordDefopt} } +\makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} } +\makedefun{defmethod}{\defopon\putwordMethodon} +\makedefun{deftypemethod}{\deftypeopon\putwordMethodon} +\makedefun{defivar}{\defcvof\putwordInstanceVariableof} +\makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof} + +% \defname, which formats the name of the @def (not the args). +% #1 is the category, such as "Function". +% #2 is the return type, if any. +% #3 is the function name. +% +% We are followed by (but not passed) the arguments, if any. +% +\def\defname#1#2#3{% + % Get the values of \leftskip and \rightskip as they were outside the @def... + \advance\leftskip by -\defbodyindent + % + % How we'll format the type name. Putting it in brackets helps + % distinguish it from the body text that may end up on the next line + % just below it. + \def\temp{#1}% + \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi} + % + % Figure out line sizes for the paragraph shape. + % The first line needs space for \box0; but if \rightskip is nonzero, + % we need only space for the part of \box0 which exceeds it: + \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip + % The continuations: + \dimen2=\hsize \advance\dimen2 by -\defargsindent + % (plain.tex says that \dimen1 should be used only as global.) + \parshape 2 0in \dimen0 \defargsindent \dimen2 + % + % Put the type name to the right margin. + \noindent + \hbox to 0pt{% + \hfil\box0 \kern-\hsize + % \hsize has to be shortened this way: + \kern\leftskip + % Intentionally do not respect \rightskip, since we need the space. + }% + % + % Allow all lines to be underfull without complaint: + \tolerance=10000 \hbadness=10000 + \exdentamount=\defbodyindent + {% + % defun fonts. We use typewriter by default (used to be bold) because: + % . we're printing identifiers, they should be in tt in principle. + % . in languages with many accents, such as Czech or French, it's + % common to leave accents off identifiers. The result looks ok in + % tt, but exceedingly strange in rm. + % . we don't want -- and --- to be treated as ligatures. + % . this still does not fix the ?` and !` ligatures, but so far no + % one has made identifiers using them :). + \df \tt + \def\temp{#2}% return value type + \ifx\temp\empty\else \tclose{\temp} \fi + #3% output function name + }% + {\rm\enskip}% hskip 0.5 em of \tenrm + % + \boldbrax + % arguments will be output next, if any. +} + +% Print arguments in slanted roman (not ttsl), inconsistently with using +% tt for the name. This is because literal text is sometimes needed in +% the argument list (groff manual), and ttsl and tt are not very +% distinguishable. Prevent hyphenation at `-' chars. +% +\def\defunargs#1{% + % use sl by default (not ttsl), + % tt for the names. + \df \sl \hyphenchar\font=0 + % + % On the other hand, if an argument has two dashes (for instance), we + % want a way to get ttsl. Let's try @var for that. + \let\var=\ttslanted + #1% + \sl\hyphenchar\font=45 +} + +% We want ()&[] to print specially on the defun line. +% +\def\activeparens{% + \catcode`\(=\active \catcode`\)=\active + \catcode`\[=\active \catcode`\]=\active + \catcode`\&=\active +} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +{ + \activeparens + \global\let(=\lparen \global\let)=\rparen + \global\let[=\lbrack \global\let]=\rbrack + \global\let& = \& + + \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} + \gdef\magicamp{\let&=\amprm} +} + +\newcount\parencount + +% If we encounter &foo, then turn on ()-hacking afterwards +\newif\ifampseen +\def\amprm#1 {\ampseentrue{\bf\ }} + +\def\parenfont{% + \ifampseen + % At the first level, print parens in roman, + % otherwise use the default font. + \ifnum \parencount=1 \rm \fi + \else + % The \sf parens (in \boldbrax) actually are a little bolder than + % the contained text. This is especially needed for [ and ] . + \sf + \fi +} +\def\infirstlevel#1{% + \ifampseen + \ifnum\parencount=1 + #1% + \fi + \fi +} +\def\bfafterword#1 {#1 \bf} + +\def\opnr{% + \global\advance\parencount by 1 + {\parenfont(}% + \infirstlevel \bfafterword +} +\def\clnr{% + {\parenfont)}% + \infirstlevel \sl + \global\advance\parencount by -1 +} + +\newcount\brackcount +\def\lbrb{% + \global\advance\brackcount by 1 + {\bf[}% +} +\def\rbrb{% + {\bf]}% + \global\advance\brackcount by -1 +} + +\def\checkparencounts{% + \ifnum\parencount=0 \else \badparencount \fi + \ifnum\brackcount=0 \else \badbrackcount \fi +} +\def\badparencount{% + \errmessage{Unbalanced parentheses in @def}% + \global\parencount=0 +} +\def\badbrackcount{% + \errmessage{Unbalanced square braces in @def}% + \global\brackcount=0 +} + + +\message{macros,} +% @macro. + +% To do this right we need a feature of e-TeX, \scantokens, +% which we arrange to emulate with a temporary file in ordinary TeX. +\ifx\eTeXversion\undefined + \newwrite\macscribble + \def\scantokens#1{% + \toks0={#1}% + \immediate\openout\macscribble=\jobname.tmp + \immediate\write\macscribble{\the\toks0}% + \immediate\closeout\macscribble + \input \jobname.tmp + } +\fi + +\def\scanmacro#1{% + \begingroup + \newlinechar`\^^M + \let\xeatspaces\eatspaces + % Undo catcode changes of \startcontents and \doprintindex + % When called from @insertcopying or (short)caption, we need active + % backslash to get it printed correctly. Previously, we had + % \catcode`\\=\other instead. We'll see whether a problem appears + % with macro expansion. --kasal, 19aug04 + \catcode`\@=0 \catcode`\\=\active \escapechar=`\@ + % ... and \example + \spaceisspace + % + % Append \endinput to make sure that TeX does not see the ending newline. + % + % I've verified that it is necessary both for e-TeX and for ordinary TeX + % --kasal, 29nov03 + \scantokens{#1\endinput}% + \endgroup +} + +\def\scanexp#1{% + \edef\temp{\noexpand\scanmacro{#1}}% + \temp +} + +\newcount\paramno % Count of parameters +\newtoks\macname % Macro name +\newif\ifrecursive % Is it recursive? + +% List of all defined macros in the form +% \definedummyword\macro1\definedummyword\macro2... +% Currently is also contains all @aliases; the list can be split +% if there is a need. +\def\macrolist{} + +% Add the macro to \macrolist +\def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname} +\def\addtomacrolistxxx#1{% + \toks0 = \expandafter{\macrolist\definedummyword#1}% + \xdef\macrolist{\the\toks0}% +} + +% Utility routines. +% This does \let #1 = #2, with \csnames; that is, +% \let \csname#1\endcsname = \csname#2\endcsname +% (except of course we have to play expansion games). +% +\def\cslet#1#2{% + \expandafter\let + \csname#1\expandafter\endcsname + \csname#2\endcsname +} + +% Trim leading and trailing spaces off a string. +% Concepts from aro-bend problem 15 (see CTAN). +{\catcode`\@=11 +\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} +\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} +\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} +\def\unbrace#1{#1} +\unbrace{\gdef\trim@@@ #1 } #2@{#1} +} + +% Trim a single trailing ^^M off a string. +{\catcode`\^^M=\other \catcode`\Q=3% +\gdef\eatcr #1{\eatcra #1Q^^MQ}% +\gdef\eatcra#1^^MQ{\eatcrb#1Q}% +\gdef\eatcrb#1Q#2Q{#1}% +} + +% Macro bodies are absorbed as an argument in a context where +% all characters are catcode 10, 11 or 12, except \ which is active +% (as in normal texinfo). It is necessary to change the definition of \. + +% It's necessary to have hard CRs when the macro is executed. This is +% done by making ^^M (\endlinechar) catcode 12 when reading the macro +% body, and then making it the \newlinechar in \scanmacro. + +\def\scanctxt{% + \catcode`\"=\other + \catcode`\+=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\@=\other + \catcode`\^=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\~=\other +} + +\def\scanargctxt{% + \scanctxt + \catcode`\\=\other + \catcode`\^^M=\other +} + +\def\macrobodyctxt{% + \scanctxt + \catcode`\{=\other + \catcode`\}=\other + \catcode`\^^M=\other + \usembodybackslash +} + +\def\macroargctxt{% + \scanctxt + \catcode`\\=\other +} + +% \mbodybackslash is the definition of \ in @macro bodies. +% It maps \foo\ => \csname macarg.foo\endcsname => #N +% where N is the macro parameter number. +% We define \csname macarg.\endcsname to be \realbackslash, so +% \\ in macro replacement text gets you a backslash. + +{\catcode`@=0 @catcode`@\=@active + @gdef@usembodybackslash{@let\=@mbodybackslash} + @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} +} +\expandafter\def\csname macarg.\endcsname{\realbackslash} + +\def\macro{\recursivefalse\parsearg\macroxxx} +\def\rmacro{\recursivetrue\parsearg\macroxxx} + +\def\macroxxx#1{% + \getargs{#1}% now \macname is the macname and \argl the arglist + \ifx\argl\empty % no arguments + \paramno=0% + \else + \expandafter\parsemargdef \argl;% + \fi + \if1\csname ismacro.\the\macname\endcsname + \message{Warning: redefining \the\macname}% + \else + \expandafter\ifx\csname \the\macname\endcsname \relax + \else \errmessage{Macro name \the\macname\space already defined}\fi + \global\cslet{macsave.\the\macname}{\the\macname}% + \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% + \addtomacrolist{\the\macname}% + \fi + \begingroup \macrobodyctxt + \ifrecursive \expandafter\parsermacbody + \else \expandafter\parsemacbody + \fi} + +\parseargdef\unmacro{% + \if1\csname ismacro.#1\endcsname + \global\cslet{#1}{macsave.#1}% + \global\expandafter\let \csname ismacro.#1\endcsname=0% + % Remove the macro name from \macrolist: + \begingroup + \expandafter\let\csname#1\endcsname \relax + \let\definedummyword\unmacrodo + \xdef\macrolist{\macrolist}% + \endgroup + \else + \errmessage{Macro #1 not defined}% + \fi +} + +% Called by \do from \dounmacro on each macro. The idea is to omit any +% macro definitions that have been changed to \relax. +% +\def\unmacrodo#1{% + \ifx #1\relax + % remove this + \else + \noexpand\definedummyword \noexpand#1% + \fi +} + +% This makes use of the obscure feature that if the last token of a +% is #, then the preceding argument is delimited by +% an opening brace, and that opening brace is not consumed. +\def\getargs#1{\getargsxxx#1{}} +\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} +\def\getmacname #1 #2\relax{\macname={#1}} +\def\getmacargs#1{\def\argl{#1}} + +% Parse the optional {params} list. Set up \paramno and \paramlist +% so \defmacro knows what to do. Define \macarg.blah for each blah +% in the params list, to be ##N where N is the position in that list. +% That gets used by \mbodybackslash (above). + +% We need to get `macro parameter char #' into several definitions. +% The technique used is stolen from LaTeX: let \hash be something +% unexpandable, insert that wherever you need a #, and then redefine +% it to # just before using the token list produced. +% +% The same technique is used to protect \eatspaces till just before +% the macro is used. + +\def\parsemargdef#1;{\paramno=0\def\paramlist{}% + \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,} +\def\parsemargdefxxx#1,{% + \if#1;\let\next=\relax + \else \let\next=\parsemargdefxxx + \advance\paramno by 1% + \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname + {\xeatspaces{\hash\the\paramno}}% + \edef\paramlist{\paramlist\hash\the\paramno,}% + \fi\next} + +% These two commands read recursive and nonrecursive macro bodies. +% (They're different since rec and nonrec macros end differently.) + +\long\def\parsemacbody#1@end macro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% +\long\def\parsermacbody#1@end rmacro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% + +% This defines the macro itself. There are six cases: recursive and +% nonrecursive macros of zero, one, and many arguments. +% Much magic with \expandafter here. +% \xdef is used so that macro definitions will survive the file +% they're defined in; @include reads the file inside a group. +\def\defmacro{% + \let\hash=##% convert placeholders to macro parameter chars + \ifrecursive + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\scanmacro{\temp}}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup\noexpand\scanmacro{\temp}}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{\egroup\noexpand\scanmacro{\temp}}% + \fi + \else + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \expandafter\noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \fi + \fi} + +\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} + +% \braceorline decides whether the next nonwhitespace character is a +% {. If so it reads up to the closing }, if not, it reads the whole +% line. Whatever was read is then fed to the next control sequence +% as an argument (by \parsebrace or \parsearg) +\def\braceorline#1{\let\next=#1\futurelet\nchar\braceorlinexxx} +\def\braceorlinexxx{% + \ifx\nchar\bgroup\else + \expandafter\parsearg + \fi \next} + + +% @alias. +% We need some trickery to remove the optional spaces around the equal +% sign. Just make them active and then expand them all to nothing. +\def\alias{\parseargusing\obeyspaces\aliasxxx} +\def\aliasxxx #1{\aliasyyy#1\relax} +\def\aliasyyy #1=#2\relax{% + {% + \expandafter\let\obeyedspace=\empty + \addtomacrolist{#1}% + \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}% + }% + \next +} + + +\message{cross references,} + +\newwrite\auxfile + +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% @inforef is relatively simple. +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +% @node's only job in TeX is to define \lastnode, which is used in +% cross-references. The @node line might or might not have commas, and +% might or might not have spaces before the first comma, like: +% @node foo , bar , ... +% We don't want such trailing spaces in the node name. +% +\parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse} +% +% also remove a trailing comma, in case of something like this: +% @node Help-Cross, , , Cross-refs +\def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse} +\def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}} + +\let\nwnode=\node +\let\lastnode=\empty + +% Write a cross-reference definition for the current node. #1 is the +% type (Ynumbered, Yappendix, Ynothing). +% +\def\donoderef#1{% + \ifx\lastnode\empty\else + \setref{\lastnode}{#1}% + \global\let\lastnode=\empty + \fi +} + +% @anchor{NAME} -- define xref target at arbitrary point. +% +\newcount\savesfregister +% +\def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi} +\def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi} +\def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces} + +% \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an +% anchor), which consists of three parts: +% 1) NAME-title - the current sectioning name taken from \thissection, +% or the anchor name. +% 2) NAME-snt - section number and type, passed as the SNT arg, or +% empty for anchors. +% 3) NAME-pg - the page number. +% +% This is called from \donoderef, \anchor, and \dofloat. In the case of +% floats, there is an additional part, which is not written here: +% 4) NAME-lof - the text as it should appear in a @listoffloats. +% +\def\setref#1#2{% + \pdfmkdest{#1}% + \iflinks + {% + \atdummies % preserve commands, but don't expand them + \edef\writexrdef##1##2{% + \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef + ##1}{##2}}% these are parameters of \writexrdef + }% + \toks0 = \expandafter{\thissection}% + \immediate \writexrdef{title}{\the\toks0 }% + \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc. + \writexrdef{pg}{\folio}% will be written later, during \shipout + }% + \fi +} + +% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is +% the node name, #2 the name of the Info cross-reference, #3 the printed +% node name, #4 the name of the Info file, #5 the name of the printed +% manual. All but the node name can be omitted. +% +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \unsepspaces + \def\printedmanual{\ignorespaces #5}% + \def\printedrefname{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual\unskip}% + \setbox0=\hbox{\printedrefname\unskip}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printedrefname{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1 > 0pt + % It is in another manual, so we don't have it. + \def\printedrefname{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printedrefname{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printedrefname{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % Make link in pdf output. + \ifpdf + \leavevmode + \getfilename{#4}% + {\turnoffactive + % See comments at \activebackslashdouble. + {\activebackslashdouble \xdef\pdfxrefdest{#1}% + \backslashparens\pdfxrefdest}% + % + \ifnum\filenamelength>0 + \startlink attr{/Border [0 0 0]}% + goto file{\the\filename.pdf} name{\pdfxrefdest}% + \else + \startlink attr{/Border [0 0 0]}% + goto name{\pdfmkpgn{\pdfxrefdest}}% + \fi + }% + \linkcolor + \fi + % + % Float references are printed completely differently: "Figure 1.2" + % instead of "[somenode], p.3". We distinguish them by the + % LABEL-title being set to a magic string. + {% + % Have to otherify everything special to allow the \csname to + % include an _ in the xref name, etc. + \indexnofonts + \turnoffactive + \expandafter\global\expandafter\let\expandafter\Xthisreftitle + \csname XR#1-title\endcsname + }% + \iffloat\Xthisreftitle + % If the user specified the print name (third arg) to the ref, + % print it instead of our usual "Figure 1.2". + \ifdim\wd0 = 0pt + \refx{#1-snt}% + \else + \printedrefname + \fi + % + % if the user also gave the printed manual name (fifth arg), append + % "in MANUALNAME". + \ifdim \wd1 > 0pt + \space \putwordin{} \cite{\printedmanual}% + \fi + \else + % node/anchor (non-float) references. + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordsection{} ``\printedrefname'' \putwordin{} \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\turnoffactive + % Only output a following space if the -snt ref is nonempty; for + % @unnumbered and @anchor, it won't be. + \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% + \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi + }% + % output the `[mynode]' via a macro so it can be overridden. + \xrefprintnodename\printedrefname + % + % But we always want a comma and a space: + ,\space + % + % output the `page 3'. + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi + \fi + \endlink +\endgroup} + +% This macro is called from \xrefX for the `[nodename]' part of xref +% output. It's a separate macro only so it can be changed more easily, +% since square brackets don't work well in some documents. Particularly +% one that Bob is working on :). +% +\def\xrefprintnodename#1{[#1]} + +% Things referred to by \setref. +% +\def\Ynothing{} +\def\Yomitfromtoc{} +\def\Ynumbered{% + \ifnum\secno=0 + \putwordChapter@tie \the\chapno + \else \ifnum\subsecno=0 + \putwordSection@tie \the\chapno.\the\secno + \else \ifnum\subsubsecno=0 + \putwordSection@tie \the\chapno.\the\secno.\the\subsecno + \else + \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno + \fi\fi\fi +} +\def\Yappendix{% + \ifnum\secno=0 + \putwordAppendix@tie @char\the\appendixno{}% + \else \ifnum\subsecno=0 + \putwordSection@tie @char\the\appendixno.\the\secno + \else \ifnum\subsubsecno=0 + \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno + \else + \putwordSection@tie + @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno + \fi\fi\fi +} + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. +% +\def\refx#1#2{% + {% + \indexnofonts + \otherbackslash + \expandafter\global\expandafter\let\expandafter\thisrefX + \csname XR#1\endcsname + }% + \ifx\thisrefX\relax + % If not defined, say something at least. + \angleleft un\-de\-fined\angleright + \iflinks + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \fi + \else + % It's defined, so just use it. + \thisrefX + \fi + #2% Output the suffix in any case. +} + +% This is the macro invoked by entries in the aux file. Usually it's +% just a \def (we prepend XR to the control sequence name to avoid +% collisions). But if this is a float type, we have more work to do. +% +\def\xrdef#1#2{% + \expandafter\gdef\csname XR#1\endcsname{#2}% remember this xref value. + % + % Was that xref control sequence that we just defined for a float? + \expandafter\iffloat\csname XR#1\endcsname + % it was a float, and we have the (safe) float type in \iffloattype. + \expandafter\let\expandafter\floatlist + \csname floatlist\iffloattype\endcsname + % + % Is this the first time we've seen this float type? + \expandafter\ifx\floatlist\relax + \toks0 = {\do}% yes, so just \do + \else + % had it before, so preserve previous elements in list. + \toks0 = \expandafter{\floatlist\do}% + \fi + % + % Remember this xref in the control sequence \floatlistFLOATTYPE, + % for later use in \listoffloats. + \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0{#1}}% + \fi +} + +% Read the last existing aux file, if any. No error if none exists. +% +\def\tryauxfile{% + \openin 1 \jobname.aux + \ifeof 1 \else + \readdatafile{aux}% + \global\havexrefstrue + \fi + \closein 1 +} + +\def\setupdatafile{% + \catcode`\^^@=\other + \catcode`\^^A=\other + \catcode`\^^B=\other + \catcode`\^^C=\other + \catcode`\^^D=\other + \catcode`\^^E=\other + \catcode`\^^F=\other + \catcode`\^^G=\other + \catcode`\^^H=\other + \catcode`\^^K=\other + \catcode`\^^L=\other + \catcode`\^^N=\other + \catcode`\^^P=\other + \catcode`\^^Q=\other + \catcode`\^^R=\other + \catcode`\^^S=\other + \catcode`\^^T=\other + \catcode`\^^U=\other + \catcode`\^^V=\other + \catcode`\^^W=\other + \catcode`\^^X=\other + \catcode`\^^Z=\other + \catcode`\^^[=\other + \catcode`\^^\=\other + \catcode`\^^]=\other + \catcode`\^^^=\other + \catcode`\^^_=\other + % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc. + % in xref tags, i.e., node names. But since ^^e4 notation isn't + % supported in the main text, it doesn't seem desirable. Furthermore, + % that is not enough: for node names that actually contain a ^ + % character, we would end up writing a line like this: 'xrdef {'hat + % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first + % argument, and \hat is not an expandable control sequence. It could + % all be worked out, but why? Either we support ^^ or we don't. + % + % The other change necessary for this was to define \auxhat: + % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter + % and then to call \auxhat in \setq. + % + \catcode`\^=\other + % + % Special characters. Should be turned off anyway, but... + \catcode`\~=\other + \catcode`\[=\other + \catcode`\]=\other + \catcode`\"=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\$=\other + \catcode`\#=\other + \catcode`\&=\other + \catcode`\%=\other + \catcode`+=\other % avoid \+ for paranoia even though we've turned it off + % + % This is to support \ in node names and titles, since the \ + % characters end up in a \csname. It's easier than + % leaving it active and making its active definition an actual \ + % character. What I don't understand is why it works in the *value* + % of the xrdef. Seems like it should be a catcode12 \, and that + % should not typeset properly. But it works, so I'm moving on for + % now. --karl, 15jan04. + \catcode`\\=\other + % + % Make the characters 128-255 be printing characters. + {% + \count1=128 + \def\loop{% + \catcode\count1=\other + \advance\count1 by 1 + \ifnum \count1<256 \loop \fi + }% + }% + % + % @ is our escape character in .aux files, and we need braces. + \catcode`\{=1 + \catcode`\}=2 + \catcode`\@=0 +} + +\def\readdatafile#1{% +\begingroup + \setupdatafile + \input\jobname.#1 +\endgroup} + +\message{insertions,} +% including footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. (Generally, numeric constants should always be followed by a +% space to prevent strange expansion errors.) +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only. +\let\footnotestyle=\comment + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \let\indent=\ptexindent + \let\noindent=\ptexnoindent + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \dofootnote +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +% Oh yes, they do; otherwise, @ifset (and anything else that uses +% \parseargline) fails inside footnotes because the tokens are fixed when +% the footnote is read. --karl, 16nov96. +% +\gdef\dofootnote{% + \insert\footins\bgroup + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \hsize=\pagewidth + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + \smallfonts \rm + % + % Because we use hanging indentation in footnotes, a @noindent appears + % to exdent this text, so make it be a no-op. makeinfo does not use + % hanging indentation so @noindent can still be needed within footnote + % text after an @example or the like (not that this is good style). + \let\noindent = \relax + % + % Hang the footnote text off the number. Use \everypar in case the + % footnote extends for more than one paragraph. + \everypar = {\hang}% + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + \futurelet\next\fo@t +} +}%end \catcode `\@=11 + +% In case a @footnote appears in a vbox, save the footnote text and create +% the real \insert just after the vbox finished. Otherwise, the insertion +% would be lost. +% Similarily, if a @footnote appears inside an alignment, save the footnote +% text to a box and make the \insert when a row of the table is finished. +% And the same can be done for other insert classes. --kasal, 16nov03. + +% Replace the \insert primitive by a cheating macro. +% Deeper inside, just make sure that the saved insertions are not spilled +% out prematurely. +% +\def\startsavinginserts{% + \ifx \insert\ptexinsert + \let\insert\saveinsert + \else + \let\checkinserts\relax + \fi +} + +% This \insert replacement works for both \insert\footins{foo} and +% \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}. +% +\def\saveinsert#1{% + \edef\next{\noexpand\savetobox \makeSAVEname#1}% + \afterassignment\next + % swallow the left brace + \let\temp = +} +\def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}} +\def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1} + +\def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi} + +\def\placesaveins#1{% + \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname + {\box#1}% +} + +% eat @SAVE -- beware, all of them have catcode \other: +{ + \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-) + \gdef\gobblesave @SAVE{} +} + +% initialization: +\def\newsaveins #1{% + \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}% + \next +} +\def\newsaveinsX #1{% + \csname newbox\endcsname #1% + \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts + \checksaveins #1}% +} + +% initialize: +\let\checkinserts\empty +\newsaveins\footins +\newsaveins\margin + + +% @image. We use the macros from epsf.tex to support this. +% If epsf.tex is not installed and @image is used, we complain. +% +% Check for and read epsf.tex up front. If we read it only at @image +% time, we might be inside a group, and then its definitions would get +% undone and the next image would fail. +\openin 1 = epsf.tex +\ifeof 1 \else + % Do not bother showing banner with epsf.tex v2.7k (available in + % doc/epsf.tex and on ctan). + \def\epsfannounce{\toks0 = }% + \input epsf.tex +\fi +\closein 1 +% +% We will only complain once about lack of epsf.tex. +\newif\ifwarnednoepsf +\newhelp\noepsfhelp{epsf.tex must be installed for images to + work. It is also included in the Texinfo distribution, or you can get + it from ftp://tug.org/tex/epsf.tex.} +% +\def\image#1{% + \ifx\epsfbox\undefined + \ifwarnednoepsf \else + \errhelp = \noepsfhelp + \errmessage{epsf.tex not found, images will be ignored}% + \global\warnednoepsftrue + \fi + \else + \imagexxx #1,,,,,\finish + \fi +} +% +% Arguments to @image: +% #1 is (mandatory) image filename; we tack on .eps extension. +% #2 is (optional) width, #3 is (optional) height. +% #4 is (ignored optional) html alt text. +% #5 is (ignored optional) extension. +% #6 is just the usual extra ignored arg for parsing this stuff. +\newif\ifimagevmode +\def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup + \catcode`\^^M = 5 % in case we're inside an example + \normalturnoffactive % allow _ et al. in names + % If the image is by itself, center it. + \ifvmode + \imagevmodetrue + \nobreak\bigskip + % Usually we'll have text after the image which will insert + % \parskip glue, so insert it here too to equalize the space + % above and below. + \nobreak\vskip\parskip + \nobreak + \line\bgroup\hss + \fi + % + % Output the image. + \ifpdf + \dopdfimage{#1}{#2}{#3}% + \else + % \epsfbox itself resets \epsf?size at each figure. + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi + \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi + \epsfbox{#1.eps}% + \fi + % + \ifimagevmode \hss \egroup \bigbreak \fi % space after the image +\endgroup} + + +% @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables, +% etc. We don't actually implement floating yet, we always include the +% float "here". But it seemed the best name for the future. +% +\envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish} + +% There may be a space before second and/or third parameter; delete it. +\def\eatcommaspace#1, {#1,} + +% #1 is the optional FLOATTYPE, the text label for this float, typically +% "Figure", "Table", "Example", etc. Can't contain commas. If omitted, +% this float will not be numbered and cannot be referred to. +% +% #2 is the optional xref label. Also must be present for the float to +% be referable. +% +% #3 is the optional positioning argument; for now, it is ignored. It +% will somehow specify the positions allowed to float to (here, top, bottom). +% +% We keep a separate counter for each FLOATTYPE, which we reset at each +% chapter-level command. +\let\resetallfloatnos=\empty +% +\def\dofloat#1,#2,#3,#4\finish{% + \let\thiscaption=\empty + \let\thisshortcaption=\empty + % + % don't lose footnotes inside @float. + % + % BEWARE: when the floats start float, we have to issue warning whenever an + % insert appears inside a float which could possibly float. --kasal, 26may04 + % + \startsavinginserts + % + % We can't be used inside a paragraph. + \par + % + \vtop\bgroup + \def\floattype{#1}% + \def\floatlabel{#2}% + \def\floatloc{#3}% we do nothing with this yet. + % + \ifx\floattype\empty + \let\safefloattype=\empty + \else + {% + % the floattype might have accents or other special characters, + % but we need to use it in a control sequence name. + \indexnofonts + \turnoffactive + \xdef\safefloattype{\floattype}% + }% + \fi + % + % If label is given but no type, we handle that as the empty type. + \ifx\floatlabel\empty \else + % We want each FLOATTYPE to be numbered separately (Figure 1, + % Table 1, Figure 2, ...). (And if no label, no number.) + % + \expandafter\getfloatno\csname\safefloattype floatno\endcsname + \global\advance\floatno by 1 + % + {% + % This magic value for \thissection is output by \setref as the + % XREFLABEL-title value. \xrefX uses it to distinguish float + % labels (which have a completely different output format) from + % node and anchor labels. And \xrdef uses it to construct the + % lists of floats. + % + \edef\thissection{\floatmagic=\safefloattype}% + \setref{\floatlabel}{Yfloat}% + }% + \fi + % + % start with \parskip glue, I guess. + \vskip\parskip + % + % Don't suppress indentation if a float happens to start a section. + \restorefirstparagraphindent +} + +% we have these possibilities: +% @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap +% @float Foo,lbl & no caption: Foo 1.1 +% @float Foo & @caption{Cap}: Foo: Cap +% @float Foo & no caption: Foo +% @float ,lbl & Caption{Cap}: 1.1: Cap +% @float ,lbl & no caption: 1.1 +% @float & @caption{Cap}: Cap +% @float & no caption: +% +\def\Efloat{% + \let\floatident = \empty + % + % In all cases, if we have a float type, it comes first. + \ifx\floattype\empty \else \def\floatident{\floattype}\fi + % + % If we have an xref label, the number comes next. + \ifx\floatlabel\empty \else + \ifx\floattype\empty \else % if also had float type, need tie first. + \appendtomacro\floatident{\tie}% + \fi + % the number. + \appendtomacro\floatident{\chaplevelprefix\the\floatno}% + \fi + % + % Start the printed caption with what we've constructed in + % \floatident, but keep it separate; we need \floatident again. + \let\captionline = \floatident + % + \ifx\thiscaption\empty \else + \ifx\floatident\empty \else + \appendtomacro\captionline{: }% had ident, so need a colon between + \fi + % + % caption text. + \appendtomacro\captionline{\scanexp\thiscaption}% + \fi + % + % If we have anything to print, print it, with space before. + % Eventually this needs to become an \insert. + \ifx\captionline\empty \else + \vskip.5\parskip + \captionline + % + % Space below caption. + \vskip\parskip + \fi + % + % If have an xref label, write the list of floats info. Do this + % after the caption, to avoid chance of it being a breakpoint. + \ifx\floatlabel\empty \else + % Write the text that goes in the lof to the aux file as + % \floatlabel-lof. Besides \floatident, we include the short + % caption if specified, else the full caption if specified, else nothing. + {% + \atdummies + % since we read the caption text in the macro world, where ^^M + % is turned into a normal character, we have to scan it back, so + % we don't write the literal three characters "^^M" into the aux file. + \scanexp{% + \xdef\noexpand\gtemp{% + \ifx\thisshortcaption\empty + \thiscaption + \else + \thisshortcaption + \fi + }% + }% + \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident + \ifx\gtemp\empty \else : \gtemp \fi}}% + }% + \fi + \egroup % end of \vtop + % + % place the captured inserts + % + % BEWARE: when the floats start float, we have to issue warning whenever an + % insert appears inside a float which could possibly float. --kasal, 26may04 + % + \checkinserts +} + +% Append the tokens #2 to the definition of macro #1, not expanding either. +% +\def\appendtomacro#1#2{% + \expandafter\def\expandafter#1\expandafter{#1#2}% +} + +% @caption, @shortcaption +% +\def\caption{\docaption\thiscaption} +\def\shortcaption{\docaption\thisshortcaption} +\def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption} +\def\defcaption#1#2{\egroup \def#1{#2}} + +% The parameter is the control sequence identifying the counter we are +% going to use. Create it if it doesn't exist and assign it to \floatno. +\def\getfloatno#1{% + \ifx#1\relax + % Haven't seen this figure type before. + \csname newcount\endcsname #1% + % + % Remember to reset this floatno at the next chap. + \expandafter\gdef\expandafter\resetallfloatnos + \expandafter{\resetallfloatnos #1=0 }% + \fi + \let\floatno#1% +} + +% \setref calls this to get the XREFLABEL-snt value. We want an @xref +% to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we +% first read the @float command. +% +\def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}% + +% Magic string used for the XREFLABEL-title value, so \xrefX can +% distinguish floats from other xref types. +\def\floatmagic{!!float!!} + +% #1 is the control sequence we are passed; we expand into a conditional +% which is true if #1 represents a float ref. That is, the magic +% \thissection value which we \setref above. +% +\def\iffloat#1{\expandafter\doiffloat#1==\finish} +% +% #1 is (maybe) the \floatmagic string. If so, #2 will be the +% (safe) float type for this float. We set \iffloattype to #2. +% +\def\doiffloat#1=#2=#3\finish{% + \def\temp{#1}% + \def\iffloattype{#2}% + \ifx\temp\floatmagic +} + +% @listoffloats FLOATTYPE - print a list of floats like a table of contents. +% +\parseargdef\listoffloats{% + \def\floattype{#1}% floattype + {% + % the floattype might have accents or other special characters, + % but we need to use it in a control sequence name. + \indexnofonts + \turnoffactive + \xdef\safefloattype{\floattype}% + }% + % + % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE. + \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax + \ifhavexrefs + % if the user said @listoffloats foo but never @float foo. + \message{\linenumber No `\safefloattype' floats to list.}% + \fi + \else + \begingroup + \leftskip=\tocindent % indent these entries like a toc + \let\do=\listoffloatsdo + \csname floatlist\safefloattype\endcsname + \endgroup + \fi +} + +% This is called on each entry in a list of floats. We're passed the +% xref label, in the form LABEL-title, which is how we save it in the +% aux file. We strip off the -title and look up \XRLABEL-lof, which +% has the text we're supposed to typeset here. +% +% Figures without xref labels will not be included in the list (since +% they won't appear in the aux file). +% +\def\listoffloatsdo#1{\listoffloatsdoentry#1\finish} +\def\listoffloatsdoentry#1-title\finish{{% + % Can't fully expand XR#1-lof because it can contain anything. Just + % pass the control sequence. On the other hand, XR#1-pg is just the + % page number, and we want to fully expand that so we can get a link + % in pdf output. + \toksA = \expandafter{\csname XR#1-lof\endcsname}% + % + % use the same \entry macro we use to generate the TOC and index. + \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}% + \writeentry +}} + +\message{localization,} +% and i18n. + +% @documentlanguage is usually given very early, just after +% @setfilename. If done too late, it may not override everything +% properly. Single argument is the language abbreviation. +% It would be nice if we could set up a hyphenation file here. +% +\parseargdef\documentlanguage{% + \tex % read txi-??.tex file in plain TeX. + % Read the file if it exists. + \openin 1 txi-#1.tex + \ifeof 1 + \errhelp = \nolanghelp + \errmessage{Cannot read language file txi-#1.tex}% + \else + \input txi-#1.tex + \fi + \closein 1 + \endgroup +} +\newhelp\nolanghelp{The given language definition file cannot be found or +is empty. Maybe you need to install it? In the current directory +should work if nowhere else does.} + + +% @documentencoding should change something in TeX eventually, most +% likely, but for now just recognize it. +\let\documentencoding = \comment + + +% Page size parameters. +% +\newdimen\defaultparindent \defaultparindent = 15pt + +\chapheadingskip = 15pt plus 4pt minus 2pt +\secheadingskip = 12pt plus 3pt minus 2pt +\subsecheadingskip = 9pt plus 2pt minus 2pt + +% Prevent underfull vbox error messages. +\vbadness = 10000 + +% Don't be so finicky about underfull hboxes, either. +\hbadness = 2000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. We call this whenever the paper size is set. +% +\def\setemergencystretch{% + \ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% + \else + \emergencystretch = .15\hsize + \fi +} + +% Parameters in order: 1) textheight; 2) textwidth; +% 3) voffset; 4) hoffset; 5) binding offset; 6) topskip; +% 7) physical page height; 8) physical page width. +% +% We also call \setleading{\textleading}, so the caller should define +% \textleading. The caller should also set \parskip. +% +\def\internalpagesizes#1#2#3#4#5#6#7#8{% + \voffset = #3\relax + \topskip = #6\relax + \splittopskip = \topskip + % + \vsize = #1\relax + \advance\vsize by \topskip + \outervsize = \vsize + \advance\outervsize by 2\topandbottommargin + \pageheight = \vsize + % + \hsize = #2\relax + \outerhsize = \hsize + \advance\outerhsize by 0.5in + \pagewidth = \hsize + % + \normaloffset = #4\relax + \bindingoffset = #5\relax + % + \ifpdf + \pdfpageheight #7\relax + \pdfpagewidth #8\relax + \fi + % + \setleading{\textleading} + % + \parindent = \defaultparindent + \setemergencystretch +} + +% @letterpaper (the default). +\def\letterpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \textleading = 13.2pt + % + % If page is nothing but text, make it come out even. + \internalpagesizes{46\baselineskip}{6in}% + {\voffset}{.25in}% + {\bindingoffset}{36pt}% + {11in}{8.5in}% +}} + +% Use @smallbook to reset parameters for 7x9.25 trim size. +\def\smallbook{{\globaldefs = 1 + \parskip = 2pt plus 1pt + \textleading = 12pt + % + \internalpagesizes{7.5in}{5in}% + {\voffset}{.25in}% + {\bindingoffset}{16pt}% + {9.25in}{7in}% + % + \lispnarrowing = 0.3in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = .5cm +}} + +% Use @smallerbook to reset parameters for 6x9 trim size. +% (Just testing, parameters still in flux.) +\def\smallerbook{{\globaldefs = 1 + \parskip = 1.5pt plus 1pt + \textleading = 12pt + % + \internalpagesizes{7.4in}{4.8in}% + {-.2in}{-.4in}% + {0pt}{14pt}% + {9in}{6in}% + % + \lispnarrowing = 0.25in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = .4cm +}} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \textleading = 13.2pt + % + % Double-side printing via postscript on Laserjet 4050 + % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm. + % To change the settings for a different printer or situation, adjust + % \normaloffset until the front-side and back-side texts align. Then + % do the same for \bindingoffset. You can set these for testing in + % your texinfo source file like this: + % @tex + % \global\normaloffset = -6mm + % \global\bindingoffset = 10mm + % @end tex + \internalpagesizes{51\baselineskip}{160mm} + {\voffset}{\hoffset}% + {\bindingoffset}{44pt}% + {297mm}{210mm}% + % + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = 5mm +}} + +% Use @afivepaper to print on European A5 paper. +% From romildo@urano.iceb.ufop.br, 2 July 2000. +% He also recommends making @example and @lisp be small. +\def\afivepaper{{\globaldefs = 1 + \parskip = 2pt plus 1pt minus 0.1pt + \textleading = 12.5pt + % + \internalpagesizes{160mm}{120mm}% + {\voffset}{\hoffset}% + {\bindingoffset}{8pt}% + {210mm}{148mm}% + % + \lispnarrowing = 0.2in + \tolerance = 800 + \hfuzz = 1.2pt + \contentsrightmargin = 0pt + \defbodyindent = 2mm + \tableindent = 12mm +}} + +% A specific text layout, 24x15cm overall, intended for A4 paper. +\def\afourlatex{{\globaldefs = 1 + \afourpaper + \internalpagesizes{237mm}{150mm}% + {\voffset}{4.6mm}% + {\bindingoffset}{7mm}% + {297mm}{210mm}% + % + % Must explicitly reset to 0 because we call \afourpaper. + \globaldefs = 0 +}} + +% Use @afourwide to print on A4 paper in landscape format. +\def\afourwide{{\globaldefs = 1 + \afourpaper + \internalpagesizes{241mm}{165mm}% + {\voffset}{-2.95mm}% + {\bindingoffset}{7mm}% + {297mm}{210mm}% + \globaldefs = 0 +}} + +% @pagesizes TEXTHEIGHT[,TEXTWIDTH] +% Perhaps we should allow setting the margins, \topskip, \parskip, +% and/or leading, also. Or perhaps we should compute them somehow. +% +\parseargdef\pagesizes{\pagesizesyyy #1,,\finish} +\def\pagesizesyyy#1,#2,#3\finish{{% + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi + \globaldefs = 1 + % + \parskip = 3pt plus 2pt minus 1pt + \setleading{\textleading}% + % + \dimen0 = #1 + \advance\dimen0 by \voffset + % + \dimen2 = \hsize + \advance\dimen2 by \normaloffset + % + \internalpagesizes{#1}{\hsize}% + {\voffset}{\normaloffset}% + {\bindingoffset}{44pt}% + {\dimen0}{\dimen2}% +}} + +% Set default to letter. +% +\letterpaper + + +\message{and turning on texinfo input format.} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\catcode`\$=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} +\def\normaldollar{$}%$ font-lock fix + +% This macro is used to make a character print one way in \tt +% (where it can probably be output as-is), and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi} + +% Same as above, but check for italic font. Actually this also catches +% non-italic slanted fonts since it is impossible to distinguish them from +% italic fonts. But since this is only used by $ and it uses \sl anyway +% this is not a problem. +\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt\char34}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt\char126}} +\chardef\hat=`\^ +\catcode`\^=\active +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +\let\realunder=_ +% Subroutine for the previous macro. +\def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em } + +\catcode`\|=\active +\def|{{\tt\char124}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +\catcode`\$=\active +\def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + +\catcode`\@=0 + +% \backslashcurfont outputs one backslash character in current font, +% as in \char`\\. +\global\chardef\backslashcurfont=`\\ +\global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work + +% \rawbackslash defines an active \ to do \backslashcurfont. +% \otherbackslash defines an active \ to be a literal `\' character with +% catcode other. +{\catcode`\\=\active + @gdef@rawbackslash{@let\=@backslashcurfont} + @gdef@otherbackslash{@let\=@realbackslash} +} + +% \realbackslash is an actual character `\' with catcode other, and +% \doublebackslash is two of them (for the pdf outlines). +{\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}} + +% \normalbackslash outputs one backslash in fixed width font. +\def\normalbackslash{{\tt\backslashcurfont}} + +\catcode`\\=\active + +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +@def@turnoffactive{% + @let"=@normaldoublequote + @let\=@realbackslash + @let~=@normaltilde + @let^=@normalcaret + @let_=@normalunderscore + @let|=@normalverticalbar + @let<=@normalless + @let>=@normalgreater + @let+=@normalplus + @let$=@normaldollar %$ font-lock fix + @unsepspaces +} + +% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of +% the literal character `\'. (Thus, \ is not expandable when this is in +% effect.) +% +@def@normalturnoffactive{@turnoffactive @let\=@normalbackslash} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\{ in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% Also turn back on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{% + @ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active + @catcode`@_=@active +} + +% Say @foo, not \foo, in error messages. +@escapechar = `@@ + +% These look ok in all fonts, so just make them not special. +@catcode`@& = @other +@catcode`@# = @other +@catcode`@% = @other + + +@c Local variables: +@c eval: (add-hook 'write-file-hooks 'time-stamp) +@c page-delimiter: "^\\\\message" +@c time-stamp-start: "def\\\\texinfoversion{" +@c time-stamp-format: "%:y-%02m-%02d.%02H" +@c time-stamp-end: "}" +@c End: + +@c vim:sw=2: + +@ignore + arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115 +@end ignore diff --git a/js/src/ctypes/typedefs.h b/js/src/ctypes/typedefs.h new file mode 100644 index 0000000..7e27b8a --- /dev/null +++ b/js/src/ctypes/typedefs.h @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is js-ctypes. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation . + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Witte + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * This header contains the builtin types available for arguments and return + * values, representing their C counterparts. They are listed inside macros + * that the #includer is expected to #define. Format is: + * + * DEFINE_X_TYPE(typename, ctype, ffitype) + * + * where 'typename' is the name of the type constructor (accessible as + * ctypes.typename), 'ctype' is the corresponding C type declaration (from + * which sizeof(ctype) and templated type conversions will be derived), and + * 'ffitype' is the ffi_type to use. (Special types, such as 'void' and the + * pointer, array, and struct types are handled separately.) + */ + +// If we're not breaking the types out, combine them together under one +// DEFINE_TYPE macro. Otherwise, turn off whichever ones we're not using. +#if defined(DEFINE_TYPE) +# define DEFINE_CHAR_TYPE(x, y, z) DEFINE_TYPE(x, y, z) +# define DEFINE_JSCHAR_TYPE(x, y, z) DEFINE_TYPE(x, y, z) +# define DEFINE_BOOL_TYPE(x, y, z) DEFINE_TYPE(x, y, z) +# define DEFINE_INT_TYPE(x, y, z) DEFINE_TYPE(x, y, z) +# define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_TYPE(x, y, z) +# define DEFINE_FLOAT_TYPE(x, y, z) DEFINE_TYPE(x, y, z) +#else +# ifndef DEFINE_BOOL_TYPE +# define DEFINE_BOOL_TYPE(x, y, z) +# endif +# ifndef DEFINE_CHAR_TYPE +# define DEFINE_CHAR_TYPE(x, y, z) +# endif +# ifndef DEFINE_JSCHAR_TYPE +# define DEFINE_JSCHAR_TYPE(x, y, z) +# endif +# ifndef DEFINE_INT_TYPE +# define DEFINE_INT_TYPE(x, y, z) +# endif +# ifndef DEFINE_WRAPPED_INT_TYPE +# define DEFINE_WRAPPED_INT_TYPE(x, y, z) +# endif +# ifndef DEFINE_FLOAT_TYPE +# define DEFINE_FLOAT_TYPE(x, y, z) +# endif +#endif + +// MSVC doesn't have ssize_t. Help it along a little. +#ifdef HAVE_SSIZE_T +#define CTYPES_SSIZE_T ssize_t +#else +#define CTYPES_SSIZE_T intptr_t +#endif + +// Some #defines to make handling of types whose length varies by platform +// easier. These could be implemented as configure tests, but the expressions +// are all statically resolvable so there's no need. (See CTypes.cpp for the +// appropriate PR_STATIC_ASSERTs; they can't go here since this header is +// used in places where such asserts are illegal.) +#define CTYPES_FFI_BOOL (sizeof(bool) == 1 ? ffi_type_uint8 : ffi_type_uint32) +#define CTYPES_FFI_LONG (sizeof(long) == 4 ? ffi_type_sint32 : ffi_type_sint64) +#define CTYPES_FFI_ULONG (sizeof(long) == 4 ? ffi_type_uint32 : ffi_type_uint64) +#define CTYPES_FFI_SIZE_T (sizeof(size_t) == 4 ? ffi_type_uint32 : ffi_type_uint64) +#define CTYPES_FFI_SSIZE_T (sizeof(size_t) == 4 ? ffi_type_sint32 : ffi_type_sint64) +#define CTYPES_FFI_INTPTR_T (sizeof(uintptr_t) == 4 ? ffi_type_sint32 : ffi_type_sint64) +#define CTYPES_FFI_UINTPTR_T (sizeof(uintptr_t) == 4 ? ffi_type_uint32 : ffi_type_uint64) + +// The meat. +DEFINE_BOOL_TYPE (bool, bool, CTYPES_FFI_BOOL) +DEFINE_INT_TYPE (int8_t, JSInt8, ffi_type_sint8) +DEFINE_INT_TYPE (int16_t, JSInt16, ffi_type_sint16) +DEFINE_INT_TYPE (int32_t, JSInt32, ffi_type_sint32) +DEFINE_INT_TYPE (uint8_t, JSUint8, ffi_type_uint8) +DEFINE_INT_TYPE (uint16_t, JSUint16, ffi_type_uint16) +DEFINE_INT_TYPE (uint32_t, JSUint32, ffi_type_uint32) +DEFINE_INT_TYPE (short, short, ffi_type_sint16) +DEFINE_INT_TYPE (unsigned_short, unsigned short, ffi_type_uint16) +DEFINE_INT_TYPE (int, int, ffi_type_sint32) +DEFINE_INT_TYPE (unsigned_int, unsigned int, ffi_type_uint32) +DEFINE_WRAPPED_INT_TYPE(int64_t, JSInt64, ffi_type_sint64) +DEFINE_WRAPPED_INT_TYPE(uint64_t, JSUint64, ffi_type_uint64) +DEFINE_WRAPPED_INT_TYPE(long, long, CTYPES_FFI_LONG) +DEFINE_WRAPPED_INT_TYPE(unsigned_long, unsigned long, CTYPES_FFI_ULONG) +DEFINE_WRAPPED_INT_TYPE(long_long, long long, ffi_type_sint64) +DEFINE_WRAPPED_INT_TYPE(unsigned_long_long, unsigned long long, ffi_type_uint64) +DEFINE_WRAPPED_INT_TYPE(size_t, size_t, CTYPES_FFI_SIZE_T) +DEFINE_WRAPPED_INT_TYPE(ssize_t, CTYPES_SSIZE_T, CTYPES_FFI_SSIZE_T) +DEFINE_WRAPPED_INT_TYPE(intptr_t, intptr_t, CTYPES_FFI_INTPTR_T) +DEFINE_WRAPPED_INT_TYPE(uintptr_t, uintptr_t, CTYPES_FFI_UINTPTR_T) +DEFINE_FLOAT_TYPE (float32_t, float, ffi_type_float) +DEFINE_FLOAT_TYPE (float64_t, double, ffi_type_double) +DEFINE_FLOAT_TYPE (float, float, ffi_type_float) +DEFINE_FLOAT_TYPE (double, double, ffi_type_double) +DEFINE_CHAR_TYPE (char, char, ffi_type_uint8) +DEFINE_CHAR_TYPE (signed_char, signed char, ffi_type_sint8) +DEFINE_CHAR_TYPE (unsigned_char, unsigned char, ffi_type_uint8) +DEFINE_JSCHAR_TYPE (jschar, jschar, ffi_type_uint16) + +#undef CTYPES_SSIZE_T +#undef CTYPES_FFI_BOOL +#undef CTYPES_FFI_LONG +#undef CTYPES_FFI_ULONG +#undef CTYPES_FFI_SIZE_T +#undef CTYPES_FFI_SSIZE_T +#undef CTYPES_FFI_INTPTR_T +#undef CTYPES_FFI_UINTPTR_T + +#undef DEFINE_TYPE +#undef DEFINE_CHAR_TYPE +#undef DEFINE_JSCHAR_TYPE +#undef DEFINE_BOOL_TYPE +#undef DEFINE_INT_TYPE +#undef DEFINE_WRAPPED_INT_TYPE +#undef DEFINE_FLOAT_TYPE + diff --git a/js/src/dtoa.c b/js/src/dtoa.c new file mode 100644 index 0000000..3940ccf --- /dev/null +++ b/js/src/dtoa.c @@ -0,0 +1,3255 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* Please send bug reports to David M. Gay (dmg at acm dot org, + * with " at " changed at "@" and " dot " changed to "."). */ + +/* On a machine with IEEE extended-precision registers, it is + * necessary to specify double-precision (53-bit) rounding precision + * before invoking strtod or dtoa. If the machine uses (the equivalent + * of) Intel 80x87 arithmetic, the call + * _control87(PC_53, MCW_PC); + * does this with many compilers. Whether this or another call is + * appropriate depends on the compiler; for this to work, it may be + * necessary to #include "float.h" or another system-dependent header + * file. + */ + +/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. + * + * This strtod returns a nearest machine number to the input decimal + * string (or sets errno to ERANGE). With IEEE arithmetic, ties are + * broken by the IEEE round-even rule. Otherwise ties are broken by + * biased rounding (add half and chop). + * + * Inspired loosely by William D. Clinger's paper "How to Read Floating + * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * + * 1. We only require IEEE, IBM, or VAX double-precision + * arithmetic (not IEEE double-extended). + * 2. We get by with floating-point arithmetic in a case that + * Clinger missed -- when we're computing d * 10^n + * for a small integer d and the integer n is not too + * much larger than 22 (the maximum integer k for which + * we can represent 10^k exactly), we may be able to + * compute (d*10^k) * 10^(e-k) with just one roundoff. + * 3. Rather than a bit-at-a-time adjustment of the binary + * result in the hard case, we use floating-point + * arithmetic to determine the adjustment to within + * one bit; only in really hard cases do we need to + * compute a second residual. + * 4. Because of 3., we don't need a large table of powers of 10 + * for ten-to-e (just some small tables, e.g. of 10^k + * for 0 <= k <= 22). + */ + +/* + * #define IEEE_8087 for IEEE-arithmetic machines where the least + * significant byte has the lowest address. + * #define IEEE_MC68k for IEEE-arithmetic machines where the most + * significant byte has the lowest address. + * #define Long int on machines with 32-bit ints and 64-bit longs. + * #define IBM for IBM mainframe-style floating-point arithmetic. + * #define VAX for VAX-style floating-point arithmetic (D_floating). + * #define No_leftright to omit left-right logic in fast floating-point + * computation of dtoa. + * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and strtod and dtoa should round accordingly. + * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and Honor_FLT_ROUNDS is not #defined. + * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines + * that use extended-precision instructions to compute rounded + * products and quotients) with IBM. + * #define ROUND_BIASED for IEEE-format with biased rounding. + * #define Inaccurate_Divide for IEEE-format with correctly rounded + * products but inaccurate quotients, e.g., for Intel i860. + * #define NO_LONG_LONG on machines that do not have a "long long" + * integer type (of >= 64 bits). On such machines, you can + * #define Just_16 to store 16 bits per 32-bit Long when doing + * high-precision integer arithmetic. Whether this speeds things + * up or slows things down depends on the machine and the number + * being converted. If long long is available and the name is + * something other than "long long", #define Llong to be the name, + * and if "unsigned Llong" does not work as an unsigned version of + * Llong, #define #ULLong to be the corresponding unsigned type. + * #define KR_headers for old-style C function headers. + * #define Bad_float_h if your system lacks a float.h or if it does not + * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, + * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. + * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) + * if memory is available and otherwise does something you deem + * appropriate. If MALLOC is undefined, malloc will be invoked + * directly -- and assumed always to succeed. Similarly, if you + * want something other than the system's free() to be called to + * recycle memory acquired from MALLOC, #define FREE to be the + * name of the alternate routine. (Unless you #define + * NO_GLOBAL_STATE and call destroydtoa, FREE or free is only + * called in pathological cases, e.g., in a dtoa call after a dtoa + * return in mode 3 with thousands of digits requested.) + * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making + * memory allocations from a private pool of memory when possible. + * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, + * unless #defined to be a different length. This default length + * suffices to get rid of MALLOC calls except for unusual cases, + * such as decimal-to-binary conversion of a very long string of + * digits. The longest string dtoa can return is about 751 bytes + * long. For conversions by strtod of strings of 800 digits and + * all dtoa conversions in single-threaded executions with 8-byte + * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte + * pointers, PRIVATE_MEM >= 7112 appears adequate. + * #define MULTIPLE_THREADS if the system offers preemptively scheduled + * multiple threads. In this case, you must provide (or suitably + * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed + * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed + * in pow5mult, ensures lazy evaluation of only one copy of high + * powers of 5; omitting this lock would introduce a small + * probability of wasting memory, but would otherwise be harmless.) + * You must also invoke freedtoa(s) to free the value s returned by + * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. + * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that + * avoids underflows on inputs whose result does not underflow. + * If you #define NO_IEEE_Scale on a machine that uses IEEE-format + * floating-point numbers and flushes underflows to zero rather + * than implementing gradual underflow, then you must also #define + * Sudden_Underflow. + * #define USE_LOCALE to use the current locale's decimal_point value. + * #define SET_INEXACT if IEEE arithmetic is being used and extra + * computation should be done to set the inexact flag when the + * result is inexact and avoid setting inexact when the result + * is exact. In this case, dtoa.c must be compiled in + * an environment, perhaps provided by #include "dtoa.c" in a + * suitable wrapper, that defines two functions, + * int get_inexact(void); + * void clear_inexact(void); + * such that get_inexact() returns a nonzero value if the + * inexact bit is already set, and clear_inexact() sets the + * inexact bit to 0. When SET_INEXACT is #defined, strtod + * also does extra computations to set the underflow and overflow + * flags when appropriate (i.e., when the result is tiny and + * inexact or when it is a numeric value rounded to +-infinity). + * #define NO_ERRNO if strtod should not assign errno = ERANGE when + * the result overflows to +-Infinity or underflows to 0. + * #define NO_GLOBAL_STATE to avoid defining any non-const global or + * static variables. Instead the necessary state is stored in an + * opaque struct, DtoaState, a pointer to which must be passed to + * every entry point. Two new functions are added to the API: + * DtoaState *newdtoa(void); + * void destroydtoa(DtoaState *); + */ + +#ifndef Long +#define Long long +#endif +#ifndef ULong +typedef unsigned Long ULong; +#endif + +#ifdef DEBUG +#include "stdio.h" +#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} +#endif + +#include "stdlib.h" +#include "string.h" + +#ifdef USE_LOCALE +#include "locale.h" +#endif + +#ifdef MALLOC +#ifdef KR_headers +extern char *MALLOC(); +#else +extern void *MALLOC(size_t); +#endif +#else +#define MALLOC malloc +#endif + +#ifndef FREE +#define FREE free +#endif + +#ifndef Omit_Private_Memory +#ifndef PRIVATE_MEM +#define PRIVATE_MEM 2304 +#endif +#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) +#endif + +#undef IEEE_Arith +#undef Avoid_Underflow +#ifdef IEEE_MC68k +#define IEEE_Arith +#endif +#ifdef IEEE_8087 +#define IEEE_Arith +#endif + +#include "errno.h" + +#ifdef Bad_float_h + +#ifdef IEEE_Arith +#define DBL_DIG 15 +#define DBL_MAX_10_EXP 308 +#define DBL_MAX_EXP 1024 +#define FLT_RADIX 2 +#endif /*IEEE_Arith*/ + +#ifdef IBM +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 75 +#define DBL_MAX_EXP 63 +#define FLT_RADIX 16 +#define DBL_MAX 7.2370055773322621e+75 +#endif + +#ifdef VAX +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 38 +#define DBL_MAX_EXP 127 +#define FLT_RADIX 2 +#define DBL_MAX 1.7014118346046923e+38 +#endif + +#ifndef LONG_MAX +#define LONG_MAX 2147483647 +#endif + +#else /* ifndef Bad_float_h */ +#include "float.h" +#endif /* Bad_float_h */ + +#ifndef __MATH_H__ +#include "math.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef CONST +#ifdef KR_headers +#define CONST /* blank */ +#else +#define CONST const +#endif +#endif + +#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 +Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. +#endif + +typedef union { double d; ULong L[2]; } U; + +#define dval(x) ((x).d) +#ifdef IEEE_8087 +#define word0(x) ((x).L[1]) +#define word1(x) ((x).L[0]) +#else +#define word0(x) ((x).L[0]) +#define word1(x) ((x).L[1]) +#endif + +/* The following definition of Storeinc is appropriate for MIPS processors. + * An alternative that might be better on some machines is + * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) + */ +#if defined(IEEE_8087) + defined(VAX) +#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ +((unsigned short *)a)[0] = (unsigned short)c, a++) +#else +#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ +((unsigned short *)a)[1] = (unsigned short)c, a++) +#endif + +/* #define P DBL_MANT_DIG */ +/* Ten_pmax = floor(P*log(2)/log(5)) */ +/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ +/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ +/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ + +#ifdef IEEE_Arith +#define Exp_shift 20 +#define Exp_shift1 20 +#define Exp_msk1 0x100000 +#define Exp_msk11 0x100000 +#define Exp_mask 0x7ff00000 +#define P 53 +#define Bias 1023 +#define Emin (-1022) +#define Exp_1 0x3ff00000 +#define Exp_11 0x3ff00000 +#define Ebits 11 +#define Frac_mask 0xfffff +#define Frac_mask1 0xfffff +#define Ten_pmax 22 +#define Bletch 0x10 +#define Bndry_mask 0xfffff +#define Bndry_mask1 0xfffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 1 +#define Tiny0 0 +#define Tiny1 1 +#define Quick_max 14 +#define Int_max 14 +#ifndef NO_IEEE_Scale +#define Avoid_Underflow +#ifdef Flush_Denorm /* debugging option */ +#undef Sudden_Underflow +#endif +#endif + +#ifndef Flt_Rounds +#ifdef FLT_ROUNDS +#define Flt_Rounds FLT_ROUNDS +#else +#define Flt_Rounds 1 +#endif +#endif /*Flt_Rounds*/ + +#ifdef Honor_FLT_ROUNDS +#define Rounding rounding +#undef Check_FLT_ROUNDS +#define Check_FLT_ROUNDS +#else +#define Rounding Flt_Rounds +#endif + +#else /* ifndef IEEE_Arith */ +#undef Check_FLT_ROUNDS +#undef Honor_FLT_ROUNDS +#undef SET_INEXACT +#undef Sudden_Underflow +#define Sudden_Underflow +#ifdef IBM +#undef Flt_Rounds +#define Flt_Rounds 0 +#define Exp_shift 24 +#define Exp_shift1 24 +#define Exp_msk1 0x1000000 +#define Exp_msk11 0x1000000 +#define Exp_mask 0x7f000000 +#define P 14 +#define Bias 65 +#define Exp_1 0x41000000 +#define Exp_11 0x41000000 +#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ +#define Frac_mask 0xffffff +#define Frac_mask1 0xffffff +#define Bletch 4 +#define Ten_pmax 22 +#define Bndry_mask 0xefffff +#define Bndry_mask1 0xffffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 4 +#define Tiny0 0x100000 +#define Tiny1 0 +#define Quick_max 14 +#define Int_max 15 +#else /* VAX */ +#undef Flt_Rounds +#define Flt_Rounds 1 +#define Exp_shift 23 +#define Exp_shift1 7 +#define Exp_msk1 0x80 +#define Exp_msk11 0x800000 +#define Exp_mask 0x7f80 +#define P 56 +#define Bias 129 +#define Exp_1 0x40800000 +#define Exp_11 0x4080 +#define Ebits 8 +#define Frac_mask 0x7fffff +#define Frac_mask1 0xffff007f +#define Ten_pmax 24 +#define Bletch 2 +#define Bndry_mask 0xffff007f +#define Bndry_mask1 0xffff007f +#define LSB 0x10000 +#define Sign_bit 0x8000 +#define Log2P 1 +#define Tiny0 0x80 +#define Tiny1 0 +#define Quick_max 15 +#define Int_max 15 +#endif /* IBM, VAX */ +#endif /* IEEE_Arith */ + +#ifndef IEEE_Arith +#define ROUND_BIASED +#endif + +#ifdef RND_PRODQUOT +#define rounded_product(a,b) a = rnd_prod(a, b) +#define rounded_quotient(a,b) a = rnd_quot(a, b) +#ifdef KR_headers +extern double rnd_prod(), rnd_quot(); +#else +extern double rnd_prod(double, double), rnd_quot(double, double); +#endif +#else +#define rounded_product(a,b) a *= b +#define rounded_quotient(a,b) a /= b +#endif + +#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) +#define Big1 0xffffffff + +#ifndef Pack_32 +#define Pack_32 +#endif + +#ifdef KR_headers +#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff) +#else +#define FFFFFFFF 0xffffffffUL +#endif + +#ifdef NO_LONG_LONG +#undef ULLong +#ifdef Just_16 +#undef Pack_32 +/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. + * This makes some inner loops simpler and sometimes saves work + * during multiplications, but it often seems to make things slightly + * slower. Hence the default is now to store 32 bits per Long. + */ +#endif +#else /* long long available */ +#ifndef Llong +#define Llong long long +#endif +#ifndef ULLong +#define ULLong unsigned Llong +#endif +#endif /* NO_LONG_LONG */ + +#ifndef MULTIPLE_THREADS +#define ACQUIRE_DTOA_LOCK(n) /*nothing*/ +#define FREE_DTOA_LOCK(n) /*nothing*/ +#endif + +#define Kmax 7 + + struct +Bigint { + struct Bigint *next; + int k, maxwds, sign, wds; + ULong x[1]; + }; + + typedef struct Bigint Bigint; + +#ifdef NO_GLOBAL_STATE +#ifdef MULTIPLE_THREADS +#error "cannot have both NO_GLOBAL_STATE and MULTIPLE_THREADS" +#endif + struct +DtoaState { +#define DECLARE_GLOBAL_STATE /* nothing */ +#else +#define DECLARE_GLOBAL_STATE static +#endif + + DECLARE_GLOBAL_STATE Bigint *freelist[Kmax+1]; + DECLARE_GLOBAL_STATE Bigint *p5s; +#ifndef Omit_Private_Memory + DECLARE_GLOBAL_STATE double private_mem[PRIVATE_mem]; + DECLARE_GLOBAL_STATE double *pmem_next +#ifndef NO_GLOBAL_STATE + = private_mem +#endif + ; +#endif +#ifdef NO_GLOBAL_STATE + }; + typedef struct DtoaState DtoaState; +#ifdef KR_headers +#define STATE_PARAM state, +#define STATE_PARAM_DECL DtoaState *state; +#else +#define STATE_PARAM DtoaState *state, +#endif +#define PASS_STATE state, +#define GET_STATE(field) (state->field) + + static DtoaState * +newdtoa(void) +{ + DtoaState *state = (DtoaState *) MALLOC(sizeof(DtoaState)); + if (state) { + memset(state, 0, sizeof(DtoaState)); +#ifndef Omit_Private_Memory + state->pmem_next = state->private_mem; +#endif + } + return state; +} + + static void +destroydtoa +#ifdef KR_headers + (state) STATE_PARAM_DECL +#else + (DtoaState *state) +#endif +{ + int i; + Bigint *v, *next; + + for (i = 0; i <= Kmax; i++) { + for (v = GET_STATE(freelist)[i]; v; v = next) { + next = v->next; +#ifndef Omit_Private_Memory + if ((double*)v < GET_STATE(private_mem) || + (double*)v >= GET_STATE(private_mem) + PRIVATE_mem) +#endif + FREE((void*)v); + } + } + FREE((void *)state); +} + +#else +#define STATE_PARAM /* nothing */ +#define STATE_PARAM_DECL /* nothing */ +#define PASS_STATE /* nothing */ +#define GET_STATE(name) name +#endif + + static Bigint * +Balloc +#ifdef KR_headers + (STATE_PARAM k) STATE_PARAM_DECL int k; +#else + (STATE_PARAM int k) +#endif +{ + int x; + Bigint *rv; +#ifndef Omit_Private_Memory + size_t len; +#endif + + ACQUIRE_DTOA_LOCK(0); + /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */ + /* but this case seems very unlikely. */ + if (k <= Kmax && (rv = GET_STATE(freelist)[k])) + GET_STATE(freelist)[k] = rv->next; + else { + x = 1 << k; +#ifdef Omit_Private_Memory + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); +#else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) + /sizeof(double); + if (k <= Kmax && GET_STATE(pmem_next) - GET_STATE(private_mem) + len <= PRIVATE_mem) { + rv = (Bigint*)GET_STATE(pmem_next); + GET_STATE(pmem_next) += len; + } + else + rv = (Bigint*)MALLOC(len*sizeof(double)); +#endif + rv->k = k; + rv->maxwds = x; + } + FREE_DTOA_LOCK(0); + rv->sign = rv->wds = 0; + return rv; + } + + static void +Bfree +#ifdef KR_headers + (STATE_PARAM v) STATE_PARAM_DECL Bigint *v; +#else + (STATE_PARAM Bigint *v) +#endif +{ + if (v) { + if (v->k > Kmax) + FREE((void*)v); + else { + ACQUIRE_DTOA_LOCK(0); + v->next = GET_STATE(freelist)[v->k]; + GET_STATE(freelist)[v->k] = v; + FREE_DTOA_LOCK(0); + } + } + } + +#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ +y->wds*sizeof(Long) + 2*sizeof(int)) + + static Bigint * +multadd +#ifdef KR_headers + (STATE_PARAM b, m, a) STATE_PARAM_DECL Bigint *b; int m, a; +#else + (STATE_PARAM Bigint *b, int m, int a) /* multiply by m and add a */ +#endif +{ + int i, wds; +#ifdef ULLong + ULong *x; + ULLong carry, y; +#else + ULong carry, *x, y; +#ifdef Pack_32 + ULong xi, z; +#endif +#endif + Bigint *b1; + + wds = b->wds; + x = b->x; + i = 0; + carry = a; + do { +#ifdef ULLong + y = *x * (ULLong)m + carry; + carry = y >> 32; + *x++ = (ULong) y & FFFFFFFF; +#else +#ifdef Pack_32 + xi = *x; + y = (xi & 0xffff) * m + carry; + z = (xi >> 16) * m + (y >> 16); + carry = z >> 16; + *x++ = (z << 16) + (y & 0xffff); +#else + y = *x * m + carry; + carry = y >> 16; + *x++ = y & 0xffff; +#endif +#endif + } + while(++i < wds); + if (carry) { + if (wds >= b->maxwds) { + b1 = Balloc(PASS_STATE b->k+1); + Bcopy(b1, b); + Bfree(PASS_STATE b); + b = b1; + } + b->x[wds++] = (ULong) carry; + b->wds = wds; + } + return b; + } + + static Bigint * +s2b +#ifdef KR_headers + (STATE_PARAM s, nd0, nd, y9) STATE_PARAM_DECL CONST char *s; int nd0, nd; ULong y9; +#else + (STATE_PARAM CONST char *s, int nd0, int nd, ULong y9) +#endif +{ + Bigint *b; + int i, k; + Long x, y; + + x = (nd + 8) / 9; + for(k = 0, y = 1; x > y; y <<= 1, k++) ; +#ifdef Pack_32 + b = Balloc(PASS_STATE k); + b->x[0] = y9; + b->wds = 1; +#else + b = Balloc(PASS_STATE k+1); + b->x[0] = y9 & 0xffff; + b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; +#endif + + i = 9; + if (9 < nd0) { + s += 9; + do b = multadd(PASS_STATE b, 10, *s++ - '0'); + while(++i < nd0); + s++; + } + else + s += 10; + for(; i < nd; i++) + b = multadd(PASS_STATE b, 10, *s++ - '0'); + return b; + } + + static int +hi0bits +#ifdef KR_headers + (x) register ULong x; +#else + (register ULong x) +#endif +{ + register int k = 0; + + if (!(x & 0xffff0000)) { + k = 16; + x <<= 16; + } + if (!(x & 0xff000000)) { + k += 8; + x <<= 8; + } + if (!(x & 0xf0000000)) { + k += 4; + x <<= 4; + } + if (!(x & 0xc0000000)) { + k += 2; + x <<= 2; + } + if (!(x & 0x80000000)) { + k++; + if (!(x & 0x40000000)) + return 32; + } + return k; + } + + static int +lo0bits +#ifdef KR_headers + (y) ULong *y; +#else + (ULong *y) +#endif +{ + register int k; + register ULong x = *y; + + if (x & 7) { + if (x & 1) + return 0; + if (x & 2) { + *y = x >> 1; + return 1; + } + *y = x >> 2; + return 2; + } + k = 0; + if (!(x & 0xffff)) { + k = 16; + x >>= 16; + } + if (!(x & 0xff)) { + k += 8; + x >>= 8; + } + if (!(x & 0xf)) { + k += 4; + x >>= 4; + } + if (!(x & 0x3)) { + k += 2; + x >>= 2; + } + if (!(x & 1)) { + k++; + x >>= 1; + if (!x) + return 32; + } + *y = x; + return k; + } + + static Bigint * +i2b +#ifdef KR_headers + (STATE_PARAM i) STATE_PARAM_DECL int i; +#else + (STATE_PARAM int i) +#endif +{ + Bigint *b; + + b = Balloc(PASS_STATE 1); + b->x[0] = i; + b->wds = 1; + return b; + } + + static Bigint * +mult +#ifdef KR_headers + (STATE_PARAM a, b) STATE_PARAM_DECL Bigint *a, *b; +#else + (STATE_PARAM Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int k, wa, wb, wc; + ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; + ULong y; +#ifdef ULLong + ULLong carry, z; +#else + ULong carry, z; +#ifdef Pack_32 + ULong z2; +#endif +#endif + + if (a->wds < b->wds) { + c = a; + a = b; + b = c; + } + k = a->k; + wa = a->wds; + wb = b->wds; + wc = wa + wb; + if (wc > a->maxwds) + k++; + c = Balloc(PASS_STATE k); + for(x = c->x, xa = x + wc; x < xa; x++) + *x = 0; + xa = a->x; + xae = xa + wa; + xb = b->x; + xbe = xb + wb; + xc0 = c->x; +#ifdef ULLong + for(; xb < xbe; xc0++) { + if ((y = *xb++)) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * (ULLong)y + *xc + carry; + carry = z >> 32; + *xc++ = (ULong) z & FFFFFFFF; + } + while(x < xae); + *xc = (ULong) carry; + } + } +#else +#ifdef Pack_32 + for(; xb < xbe; xb++, xc0++) { + if (y = *xb & 0xffff) { + x = xa; + xc = xc0; + carry = 0; + do { + z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; + carry = z >> 16; + z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; + carry = z2 >> 16; + Storeinc(xc, z2, z); + } + while(x < xae); + *xc = carry; + } + if (y = *xb >> 16) { + x = xa; + xc = xc0; + carry = 0; + z2 = *xc; + do { + z = (*x & 0xffff) * y + (*xc >> 16) + carry; + carry = z >> 16; + Storeinc(xc, z, z2); + z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; + carry = z2 >> 16; + } + while(x < xae); + *xc = z2; + } + } +#else + for(; xb < xbe; xc0++) { + if (y = *xb++) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * y + *xc + carry; + carry = z >> 16; + *xc++ = z & 0xffff; + } + while(x < xae); + *xc = carry; + } + } +#endif +#endif + for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; + c->wds = wc; + return c; + } + + static Bigint * +pow5mult +#ifdef KR_headers + (STATE_PARAM b, k) STATE_PARAM_DECL Bigint *b; int k; +#else + (STATE_PARAM Bigint *b, int k) +#endif +{ + Bigint *b1, *p5, *p51; + int i; + static CONST int p05[3] = { 5, 25, 125 }; + + if ((i = k & 3)) + b = multadd(PASS_STATE b, p05[i-1], 0); + + if (!(k >>= 2)) + return b; + if (!(p5 = GET_STATE(p5s))) { + /* first time */ +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + if (!(p5 = p5s)) { + p5 = p5s = i2b(625); + p5->next = 0; + } + FREE_DTOA_LOCK(1); +#else + p5 = GET_STATE(p5s) = i2b(PASS_STATE 625); + p5->next = 0; +#endif + } + for(;;) { + if (k & 1) { + b1 = mult(PASS_STATE b, p5); + Bfree(PASS_STATE b); + b = b1; + } + if (!(k >>= 1)) + break; + if (!(p51 = p5->next)) { +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + if (!(p51 = p5->next)) { + p51 = p5->next = mult(p5,p5); + p51->next = 0; + } + FREE_DTOA_LOCK(1); +#else + p51 = p5->next = mult(PASS_STATE p5,p5); + p51->next = 0; +#endif + } + p5 = p51; + } + return b; + } + + static Bigint * +lshift +#ifdef KR_headers + (STATE_PARAM b, k) STATE_PARAM_DECL Bigint *b; int k; +#else + (STATE_PARAM Bigint *b, int k) +#endif +{ + int i, k1, n, n1; + Bigint *b1; + ULong *x, *x1, *xe, z; + +#ifdef Pack_32 + n = k >> 5; +#else + n = k >> 4; +#endif + k1 = b->k; + n1 = n + b->wds + 1; + for(i = b->maxwds; n1 > i; i <<= 1) + k1++; + b1 = Balloc(PASS_STATE k1); + x1 = b1->x; + for(i = 0; i < n; i++) + *x1++ = 0; + x = b->x; + xe = x + b->wds; +#ifdef Pack_32 + if (k &= 0x1f) { + k1 = 32 - k; + z = 0; + do { + *x1++ = *x << k | z; + z = *x++ >> k1; + } + while(x < xe); + if ((*x1 = z)) + ++n1; + } +#else + if (k &= 0xf) { + k1 = 16 - k; + z = 0; + do { + *x1++ = *x << k & 0xffff | z; + z = *x++ >> k1; + } + while(x < xe); + if (*x1 = z) + ++n1; + } +#endif + else do + *x1++ = *x++; + while(x < xe); + b1->wds = n1 - 1; + Bfree(PASS_STATE b); + return b1; + } + + static int +cmp +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + ULong *xa, *xa0, *xb, *xb0; + int i, j; + + i = a->wds; + j = b->wds; +#ifdef DEBUG + if (i > 1 && !a->x[i-1]) + Bug("cmp called with a->x[a->wds-1] == 0"); + if (j > 1 && !b->x[j-1]) + Bug("cmp called with b->x[b->wds-1] == 0"); +#endif + if (i -= j) + return i; + xa0 = a->x; + xa = xa0 + j; + xb0 = b->x; + xb = xb0 + j; + for(;;) { + if (*--xa != *--xb) + return *xa < *xb ? -1 : 1; + if (xa <= xa0) + break; + } + return 0; + } + + static Bigint * +diff +#ifdef KR_headers + (STATE_PARAM a, b) STATE_PARAM_DECL Bigint *a, *b; +#else + (STATE_PARAM Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int i, wa, wb; + ULong *xa, *xae, *xb, *xbe, *xc; +#ifdef ULLong + ULLong borrow, y; +#else + ULong borrow, y; +#ifdef Pack_32 + ULong z; +#endif +#endif + + i = cmp(a,b); + if (!i) { + c = Balloc(PASS_STATE 0); + c->wds = 1; + c->x[0] = 0; + return c; + } + if (i < 0) { + c = a; + a = b; + b = c; + i = 1; + } + else + i = 0; + c = Balloc(PASS_STATE a->k); + c->sign = i; + wa = a->wds; + xa = a->x; + xae = xa + wa; + wb = b->wds; + xb = b->x; + xbe = xb + wb; + xc = c->x; + borrow = 0; +#ifdef ULLong + do { + y = (ULLong)*xa++ - *xb++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = (ULong) y & FFFFFFFF; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = (ULong) y & FFFFFFFF; + } +#else +#ifdef Pack_32 + do { + y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } + while(xb < xbe); + while(xa < xae) { + y = (*xa & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } +#else + do { + y = *xa++ - *xb++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } +#endif +#endif + while(!*--xc) + wa--; + c->wds = wa; + return c; + } + + static double +ulp +#ifdef KR_headers + (x) U x; +#else + (U x) +#endif +{ + register Long L; + U a; + + L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + if (L > 0) { +#endif +#endif +#ifdef IBM + L |= Exp_msk1 >> 4; +#endif + word0(a) = L; + word1(a) = 0; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + } + else { + L = -L >> Exp_shift; + if (L < Exp_shift) { + word0(a) = 0x80000 >> L; + word1(a) = 0; + } + else { + word0(a) = 0; + L -= Exp_shift; + word1(a) = L >= 31 ? 1 : 1 << 31 - L; + } + } +#endif +#endif + return dval(a); + } + + static double +b2d +#ifdef KR_headers + (a, e) Bigint *a; int *e; +#else + (Bigint *a, int *e) +#endif +{ + ULong *xa, *xa0, w, y, z; + int k; + U d; +#ifdef VAX + ULong d0, d1; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + + xa0 = a->x; + xa = xa0 + a->wds; + y = *--xa; +#ifdef DEBUG + if (!y) Bug("zero y in b2d"); +#endif + k = hi0bits(y); + *e = 32 - k; +#ifdef Pack_32 + if (k < Ebits) { + d0 = Exp_1 | y >> (Ebits - k); + w = xa > xa0 ? *--xa : 0; + d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + if (k -= Ebits) { + d0 = Exp_1 | y << k | z >> (32 - k); + y = xa > xa0 ? *--xa : 0; + d1 = z << k | y >> (32 - k); + } + else { + d0 = Exp_1 | y; + d1 = z; + } +#else + if (k < Ebits + 16) { + z = xa > xa0 ? *--xa : 0; + d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; + w = xa > xa0 ? *--xa : 0; + y = xa > xa0 ? *--xa : 0; + d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + w = xa > xa0 ? *--xa : 0; + k -= Ebits + 16; + d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; + y = xa > xa0 ? *--xa : 0; + d1 = w << k + 16 | y << k; +#endif + ret_d: +#ifdef VAX + word0(d) = d0 >> 16 | d0 << 16; + word1(d) = d1 >> 16 | d1 << 16; +#else +#undef d0 +#undef d1 +#endif + return dval(d); + } + + static Bigint * +d2b +#ifdef KR_headers + (STATE_PARAM d, e, bits) STATE_PARAM_DECL U d; int *e, *bits; +#else + (STATE_PARAM U d, int *e, int *bits) +#endif +{ + Bigint *b; + int de, k; + ULong *x, y, z; +#ifndef Sudden_Underflow + int i; +#endif +#ifdef VAX + ULong d0, d1; + d0 = word0(d) >> 16 | word0(d) << 16; + d1 = word1(d) >> 16 | word1(d) << 16; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + +#ifdef Pack_32 + b = Balloc(PASS_STATE 1); +#else + b = Balloc(PASS_STATE 2); +#endif + x = b->x; + + z = d0 & Frac_mask; + d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ +#ifdef Sudden_Underflow + de = (int)(d0 >> Exp_shift); +#ifndef IBM + z |= Exp_msk11; +#endif +#else + if ((de = (int)(d0 >> Exp_shift))) + z |= Exp_msk1; +#endif +#ifdef Pack_32 + if ((y = d1)) { + if ((k = lo0bits(&y))) { + x[0] = y | z << (32 - k); + z >>= k; + } + else + x[0] = y; +#ifndef Sudden_Underflow + i = +#endif + b->wds = (x[1] = z) ? 2 : 1; + } + else { + k = lo0bits(&z); + x[0] = z; +#ifndef Sudden_Underflow + i = +#endif + b->wds = 1; + k += 32; + } +#else + if (y = d1) { + if (k = lo0bits(&y)) + if (k >= 16) { + x[0] = y | z << 32 - k & 0xffff; + x[1] = z >> k - 16 & 0xffff; + x[2] = z >> k; + i = 2; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16 | z << 16 - k & 0xffff; + x[2] = z >> k & 0xffff; + x[3] = z >> k+16; + i = 3; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16; + x[2] = z & 0xffff; + x[3] = z >> 16; + i = 3; + } + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + if (k >= 16) { + x[0] = z; + i = 0; + } + else { + x[0] = z & 0xffff; + x[1] = z >> 16; + i = 1; + } + k += 32; + } + while(!x[i]) + --i; + b->wds = i + 1; +#endif +#ifndef Sudden_Underflow + if (de) { +#endif +#ifdef IBM + *e = (de - Bias - (P-1) << 2) + k; + *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); +#else + *e = de - Bias - (P-1) + k; + *bits = P - k; +#endif +#ifndef Sudden_Underflow + } + else { + *e = de - Bias - (P-1) + 1 + k; +#ifdef Pack_32 + *bits = 32*i - hi0bits(x[i-1]); +#else + *bits = (i+2)*16 - hi0bits(x[i]); +#endif + } +#endif + return b; + } +#undef d0 +#undef d1 + + static double +ratio +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + U da, db; + int k, ka, kb; + + dval(da) = b2d(a, &ka); + dval(db) = b2d(b, &kb); +#ifdef Pack_32 + k = ka - kb + 32*(a->wds - b->wds); +#else + k = ka - kb + 16*(a->wds - b->wds); +#endif +#ifdef IBM + if (k > 0) { + word0(da) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(da) *= 1 << k; + } + else { + k = -k; + word0(db) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(db) *= 1 << k; + } +#else + if (k > 0) + word0(da) += k*Exp_msk1; + else { + k = -k; + word0(db) += k*Exp_msk1; + } +#endif + return dval(da) / dval(db); + } + + static CONST double +tens[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 +#ifdef VAX + , 1e23, 1e24 +#endif + }; + + static CONST double +#ifdef IEEE_Arith +bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, +#ifdef Avoid_Underflow + 9007199254740992.*9007199254740992.e-256 + /* = 2^106 * 1e-53 */ +#else + 1e-256 +#endif + }; +/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ +/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ +#define Scale_Bit 0x10 +#define n_bigtens 5 +#else +#ifdef IBM +bigtens[] = { 1e16, 1e32, 1e64 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; +#define n_bigtens 3 +#else +bigtens[] = { 1e16, 1e32 }; +static CONST double tinytens[] = { 1e-16, 1e-32 }; +#define n_bigtens 2 +#endif +#endif + + static double +_strtod +#ifdef KR_headers + (STATE_PARAM s00, se) STATE_PARAM_DECL CONST char *s00; char **se; +#else + (STATE_PARAM CONST char *s00, char **se) +#endif +{ +#ifdef Avoid_Underflow + int scale; +#endif + int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, + e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; + CONST char *s, *s0, *s1; + double aadj, adj; + U aadj1, rv, rv0; + Long L; + ULong y, z; + Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif +#ifdef Honor_FLT_ROUNDS + int rounding; +#endif +#ifdef USE_LOCALE + CONST char *s2; +#endif + +#ifdef __GNUC__ + delta = bb = bd = bs = 0; +#endif + + sign = nz0 = nz = 0; + dval(rv) = 0.; + for(s = s00;;s++) switch(*s) { + case '-': + sign = 1; + /* no break */ + case '+': + if (*++s) + goto break2; + /* no break */ + case 0: + goto ret0; + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + continue; + default: + goto break2; + } + break2: + if (*s == '0') { + nz0 = 1; + while(*++s == '0') ; + if (!*s) + goto ret; + } + s0 = s; + y = z = 0; + for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) + if (nd < 9) + y = 10*y + c - '0'; + else if (nd < 16) + z = 10*z + c - '0'; + nd0 = nd; +#ifdef USE_LOCALE + s1 = localeconv()->decimal_point; + if (c == *s1) { + c = '.'; + if (*++s1) { + s2 = s; + for(;;) { + if (*++s2 != *s1) { + c = 0; + break; + } + if (!*++s1) { + s = s2; + break; + } + } + } + } +#endif + if (c == '.') { + c = *++s; + if (!nd) { + for(; c == '0'; c = *++s) + nz++; + if (c > '0' && c <= '9') { + s0 = s; + nf += nz; + nz = 0; + goto have_dig; + } + goto dig_done; + } + for(; c >= '0' && c <= '9'; c = *++s) { + have_dig: + nz++; + if (c -= '0') { + nf += nz; + for(i = 1; i < nz; i++) + if (nd++ < 9) + y *= 10; + else if (nd <= DBL_DIG + 1) + z *= 10; + if (nd++ < 9) + y = 10*y + c; + else if (nd <= DBL_DIG + 1) + z = 10*z + c; + nz = 0; + } + } + } + dig_done: + e = 0; + if (c == 'e' || c == 'E') { + if (!nd && !nz && !nz0) { + goto ret0; + } + s00 = s; + esign = 0; + switch(c = *++s) { + case '-': + esign = 1; + case '+': + c = *++s; + } + if (c >= '0' && c <= '9') { + while(c == '0') + c = *++s; + if (c > '0' && c <= '9') { + L = c - '0'; + s1 = s; + while((c = *++s) >= '0' && c <= '9') + L = 10*L + c - '0'; + if (s - s1 > 8 || L > 19999) + /* Avoid confusion from exponents + * so large that e might overflow. + */ + e = 19999; /* safe for 16 bit ints */ + else + e = (int)L; + if (esign) + e = -e; + } + else + e = 0; + } + else + s = s00; + } + if (!nd) { + if (!nz && !nz0) { + ret0: + s = s00; + sign = 0; + } + goto ret; + } + e1 = e -= nf; + + /* Now we have nd0 digits, starting at s0, followed by a + * decimal point, followed by nd-nd0 digits. The number we're + * after is the integer represented by those digits times + * 10**e */ + + if (!nd0) + nd0 = nd; + k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; + dval(rv) = y; + if (k > 9) { +#ifdef SET_INEXACT + if (k > DBL_DIG) + oldinexact = get_inexact(); +#endif + dval(rv) = tens[k - 9] * dval(rv) + z; + } + bd0 = 0; + if (nd <= DBL_DIG +#ifndef RND_PRODQUOT +#ifndef Honor_FLT_ROUNDS + && Flt_Rounds == 1 +#endif +#endif + ) { + if (!e) + goto ret; + if (e > 0) { + if (e <= Ten_pmax) { +#ifdef VAX + goto vax_ovfl_check; +#else +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif + /* rv = */ rounded_product(dval(rv), tens[e]); + goto ret; +#endif + } + i = DBL_DIG - nd; + if (e <= Ten_pmax + i) { + /* A fancier test would sometimes let us do + * this for larger i values. + */ +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif + e -= i; + dval(rv) *= tens[i]; +#ifdef VAX + /* VAX exponent range is so narrow we must + * worry about overflow here... + */ + vax_ovfl_check: + word0(rv) -= P*Exp_msk1; + /* rv = */ rounded_product(dval(rv), tens[e]); + if ((word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) + goto ovfl; + word0(rv) += P*Exp_msk1; +#else + /* rv = */ rounded_product(dval(rv), tens[e]); +#endif + goto ret; + } + } +#ifndef Inaccurate_Divide + else if (e >= -Ten_pmax) { +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif + /* rv = */ rounded_quotient(dval(rv), tens[-e]); + goto ret; + } +#endif + } + e1 += nd - k; + +#ifdef IEEE_Arith +#ifdef SET_INEXACT + inexact = 1; + if (k <= DBL_DIG) + oldinexact = get_inexact(); +#endif +#ifdef Avoid_Underflow + scale = 0; +#endif +#ifdef Honor_FLT_ROUNDS + if ((rounding = Flt_Rounds) >= 2) { + if (sign) + rounding = rounding == 2 ? 0 : 2; + else + if (rounding != 2) + rounding = 0; + } +#endif +#endif /*IEEE_Arith*/ + + /* Get starting approximation = rv * 10**e1 */ + + if (e1 > 0) { + if ((i = e1 & 15)) + dval(rv) *= tens[i]; + if (e1 &= ~15) { + if (e1 > DBL_MAX_10_EXP) { + ovfl: +#ifndef NO_ERRNO + errno = ERANGE; +#endif + /* Can't trust HUGE_VAL */ +#ifdef IEEE_Arith +#ifdef Honor_FLT_ROUNDS + switch(rounding) { + case 0: /* toward 0 */ + case 3: /* toward -infinity */ + word0(rv) = Big0; + word1(rv) = Big1; + break; + default: + word0(rv) = Exp_mask; + word1(rv) = 0; + } +#else /*Honor_FLT_ROUNDS*/ + word0(rv) = Exp_mask; + word1(rv) = 0; +#endif /*Honor_FLT_ROUNDS*/ +#ifdef SET_INEXACT + /* set overflow bit */ + dval(rv0) = 1e300; + dval(rv0) *= dval(rv0); +#endif +#else /*IEEE_Arith*/ + word0(rv) = Big0; + word1(rv) = Big1; +#endif /*IEEE_Arith*/ + if (bd0) + goto retfree; + goto ret; + } + e1 >>= 4; + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= bigtens[j]; + /* The last multiplication could overflow. */ + word0(rv) -= P*Exp_msk1; + dval(rv) *= bigtens[j]; + if ((z = word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-P)) + goto ovfl; + if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { + /* set to largest number */ + /* (Can't trust DBL_MAX) */ + word0(rv) = Big0; + word1(rv) = Big1; + } + else + word0(rv) += P*Exp_msk1; + } + } + else if (e1 < 0) { + e1 = -e1; + if ((i = e1 & 15)) + dval(rv) /= tens[i]; + if (e1 >>= 4) { + if (e1 >= 1 << n_bigtens) + goto undfl; +#ifdef Avoid_Underflow + if (e1 & Scale_Bit) + scale = 2*P; + for(j = 0; e1 > 0; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= tinytens[j]; + if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask) + >> Exp_shift)) > 0) { + /* scaled rv is denormal; zap j low bits */ + if (j >= 32) { + word1(rv) = 0; + if (j >= 53) + word0(rv) = (P+2)*Exp_msk1; + else + word0(rv) &= 0xffffffff << (j-32); + } + else + word1(rv) &= 0xffffffff << j; + } +#else + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= tinytens[j]; + /* The last multiplication could underflow. */ + dval(rv0) = dval(rv); + dval(rv) *= tinytens[j]; + if (!dval(rv)) { + dval(rv) = 2.*dval(rv0); + dval(rv) *= tinytens[j]; +#endif + if (!dval(rv)) { + undfl: + dval(rv) = 0.; +#ifndef NO_ERRNO + errno = ERANGE; +#endif + if (bd0) + goto retfree; + goto ret; + } +#ifndef Avoid_Underflow + word0(rv) = Tiny0; + word1(rv) = Tiny1; + /* The refinement below will clean + * this approximation up. + */ + } +#endif + } + } + + /* Now the hard part -- adjusting rv to the correct value.*/ + + /* Put digits into bd: true value = bd * 10^e */ + + bd0 = s2b(PASS_STATE s0, nd0, nd, y); + + for(;;) { + bd = Balloc(PASS_STATE bd0->k); + Bcopy(bd, bd0); + bb = d2b(PASS_STATE rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ + bs = i2b(PASS_STATE 1); + + if (e >= 0) { + bb2 = bb5 = 0; + bd2 = bd5 = e; + } + else { + bb2 = bb5 = -e; + bd2 = bd5 = 0; + } + if (bbe >= 0) + bb2 += bbe; + else + bd2 -= bbe; + bs2 = bb2; +#ifdef Honor_FLT_ROUNDS + if (rounding != 1) + bs2++; +#endif +#ifdef Avoid_Underflow + j = bbe - scale; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#else /*Avoid_Underflow*/ +#ifdef Sudden_Underflow +#ifdef IBM + j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); +#else + j = P + 1 - bbbits; +#endif +#else /*Sudden_Underflow*/ + j = bbe; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + bb2 += j; + bd2 += j; +#ifdef Avoid_Underflow + bd2 += scale; +#endif + i = bb2 < bd2 ? bb2 : bd2; + if (i > bs2) + i = bs2; + if (i > 0) { + bb2 -= i; + bd2 -= i; + bs2 -= i; + } + if (bb5 > 0) { + bs = pow5mult(PASS_STATE bs, bb5); + bb1 = mult(PASS_STATE bs, bb); + Bfree(PASS_STATE bb); + bb = bb1; + } + if (bb2 > 0) + bb = lshift(PASS_STATE bb, bb2); + if (bd5 > 0) + bd = pow5mult(PASS_STATE bd, bd5); + if (bd2 > 0) + bd = lshift(PASS_STATE bd, bd2); + if (bs2 > 0) + bs = lshift(PASS_STATE bs, bs2); + delta = diff(PASS_STATE bb, bd); + dsign = delta->sign; + delta->sign = 0; + i = cmp(delta, bs); +#ifdef Honor_FLT_ROUNDS + if (rounding != 1) { + if (i < 0) { + /* Error is less than an ulp */ + if (!delta->x[0] && delta->wds <= 1) { + /* exact */ +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (rounding) { + if (dsign) { + adj = 1.; + goto apply_adj; + } + } + else if (!dsign) { + adj = -1.; + if (!word1(rv) + && !(word0(rv) & Frac_mask)) { + y = word0(rv) & Exp_mask; +#ifdef Avoid_Underflow + if (!scale || y > 2*P*Exp_msk1) +#else + if (y) +#endif + { + delta = lshift(PASS_STATE delta,Log2P); + if (cmp(delta, bs) <= 0) + adj = -0.5; + } + } + apply_adj: +#ifdef Avoid_Underflow + if (scale && (y = word0(rv) & Exp_mask) + <= 2*P*Exp_msk1) + word0(adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= + P*Exp_msk1) { + word0(rv) += P*Exp_msk1; + dval(rv) += adj*ulp(rv); + word0(rv) -= P*Exp_msk1; + } + else +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + dval(rv) += adj*ulp(rv); + } + break; + } + adj = ratio(delta, bs); + if (adj < 1.) + adj = 1.; + if (adj <= 0x7ffffffe) { + /* adj = rounding ? ceil(adj) : floor(adj); */ + y = adj; + if (y != adj) { + if (!((rounding>>1) ^ dsign)) + y++; + adj = y; + } + } +#ifdef Avoid_Underflow + if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) + word0(adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + word0(rv) += P*Exp_msk1; + adj *= ulp(rv); + if (dsign) + dval(rv) += adj; + else + dval(rv) -= adj; + word0(rv) -= P*Exp_msk1; + goto cont; + } +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + adj *= ulp(rv); + if (dsign) + dval(rv) += adj; + else + dval(rv) -= adj; + goto cont; + } +#endif /*Honor_FLT_ROUNDS*/ + + if (i < 0) { + /* Error is less than half an ulp -- check for + * special case of mantissa a power of two. + */ + if (dsign || word1(rv) || word0(rv) & Bndry_mask +#ifdef IEEE_Arith +#ifdef Avoid_Underflow + || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1 +#else + || (word0(rv) & Exp_mask) <= Exp_msk1 +#endif +#endif + ) { +#ifdef SET_INEXACT + if (!delta->x[0] && delta->wds <= 1) + inexact = 0; +#endif + break; + } + if (!delta->x[0] && delta->wds <= 1) { + /* exact result */ +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + delta = lshift(PASS_STATE delta,Log2P); + if (cmp(delta, bs) > 0) + goto drop_down; + break; + } + if (i == 0) { + /* exactly half-way between */ + if (dsign) { + if ((word0(rv) & Bndry_mask1) == Bndry_mask1 + && word1(rv) == ( +#ifdef Avoid_Underflow + (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) + ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : +#endif + 0xffffffff)) { + /*boundary case -- increment exponent*/ + word0(rv) = (word0(rv) & Exp_mask) + + Exp_msk1 +#ifdef IBM + | Exp_msk1 >> 4 +#endif + ; + word1(rv) = 0; +#ifdef Avoid_Underflow + dsign = 0; +#endif + break; + } + } + else if (!(word0(rv) & Bndry_mask) && !word1(rv)) { + drop_down: + /* boundary case -- decrement exponent */ +#ifdef Sudden_Underflow /*{{*/ + L = word0(rv) & Exp_mask; +#ifdef IBM + if (L < Exp_msk1) +#else +#ifdef Avoid_Underflow + if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) +#else + if (L <= Exp_msk1) +#endif /*Avoid_Underflow*/ +#endif /*IBM*/ + goto undfl; + L -= Exp_msk1; +#else /*Sudden_Underflow}{*/ +#ifdef Avoid_Underflow + if (scale) { + L = word0(rv) & Exp_mask; + if (L <= (2*P+1)*Exp_msk1) { + if (L > (P+2)*Exp_msk1) + /* round even ==> */ + /* accept rv */ + break; + /* rv = smallest denormal */ + goto undfl; + } + } +#endif /*Avoid_Underflow*/ + L = (word0(rv) & Exp_mask) - Exp_msk1; +#endif /*Sudden_Underflow}}*/ + word0(rv) = L | Bndry_mask1; + word1(rv) = 0xffffffff; +#ifdef IBM + goto cont; +#else + break; +#endif + } +#ifndef ROUND_BIASED + if (!(word1(rv) & LSB)) + break; +#endif + if (dsign) + dval(rv) += ulp(rv); +#ifndef ROUND_BIASED + else { + dval(rv) -= ulp(rv); +#ifndef Sudden_Underflow + if (!dval(rv)) + goto undfl; +#endif + } +#ifdef Avoid_Underflow + dsign = 1 - dsign; +#endif +#endif + break; + } + if ((aadj = ratio(delta, bs)) <= 2.) { + if (dsign) + aadj = dval(aadj1) = 1.; + else if (word1(rv) || word0(rv) & Bndry_mask) { +#ifndef Sudden_Underflow + if (word1(rv) == Tiny1 && !word0(rv)) + goto undfl; +#endif + aadj = 1.; + dval(aadj1) = -1.; + } + else { + /* special case -- power of FLT_RADIX to be */ + /* rounded down... */ + + if (aadj < 2./FLT_RADIX) + aadj = 1./FLT_RADIX; + else + aadj *= 0.5; + dval(aadj1) = -aadj; + } + } + else { + aadj *= 0.5; + dval(aadj1) = dsign ? aadj : -aadj; +#ifdef Check_FLT_ROUNDS + switch(Rounding) { + case 2: /* towards +infinity */ + dval(aadj1) -= 0.5; + break; + case 0: /* towards 0 */ + case 3: /* towards -infinity */ + dval(aadj1) += 0.5; + } +#else + if (Flt_Rounds == 0) + dval(aadj1) += 0.5; +#endif /*Check_FLT_ROUNDS*/ + } + y = word0(rv) & Exp_mask; + + /* Check for overflow */ + + if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { + dval(rv0) = dval(rv); + word0(rv) -= P*Exp_msk1; + adj = dval(aadj1) * ulp(rv); + dval(rv) += adj; + if ((word0(rv) & Exp_mask) >= + Exp_msk1*(DBL_MAX_EXP+Bias-P)) { + if (word0(rv0) == Big0 && word1(rv0) == Big1) + goto ovfl; + word0(rv) = Big0; + word1(rv) = Big1; + goto cont; + } + else + word0(rv) += P*Exp_msk1; + } + else { +#ifdef Avoid_Underflow + if (scale && y <= 2*P*Exp_msk1) { + if (aadj <= 0x7fffffff) { + if ((z = (ULong) aadj) <= 0) + z = 1; + aadj = z; + dval(aadj1) = dsign ? aadj : -aadj; + } + word0(aadj1) += (2*P+1)*Exp_msk1 - y; + } + adj = dval(aadj1) * ulp(rv); + dval(rv) += adj; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + dval(rv0) = dval(rv); + word0(rv) += P*Exp_msk1; + adj = dval(aadj1) * ulp(rv); + dval(rv) += adj; +#ifdef IBM + if ((word0(rv) & Exp_mask) < P*Exp_msk1) +#else + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) +#endif + { + if (word0(rv0) == Tiny0 + && word1(rv0) == Tiny1) + goto undfl; + word0(rv) = Tiny0; + word1(rv) = Tiny1; + goto cont; + } + else + word0(rv) -= P*Exp_msk1; + } + else { + adj = dval(aadj1) * ulp(rv); + dval(rv) += adj; + } +#else /*Sudden_Underflow*/ + /* Compute adj so that the IEEE rounding rules will + * correctly round rv + adj in some half-way cases. + * If rv * ulp(rv) is denormalized (i.e., + * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid + * trouble from bits lost to denormalization; + * example: 1.2e-307 . + */ + if (y <= (P-1)*Exp_msk1 && aadj > 1.) { + dval(aadj1) = (double)(int)(aadj + 0.5); + if (!dsign) + dval(aadj1) = -dval(aadj1); + } + adj = dval(aadj1) * ulp(rv); + dval(rv) += adj; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + } + z = word0(rv) & Exp_mask; +#ifndef SET_INEXACT +#ifdef Avoid_Underflow + if (!scale) +#endif + if (y == z) { + /* Can we stop now? */ + L = (Long)aadj; + aadj -= L; + /* The tolerances below are conservative. */ + if (dsign || word1(rv) || word0(rv) & Bndry_mask) { + if (aadj < .4999999 || aadj > .5000001) + break; + } + else if (aadj < .4999999/FLT_RADIX) + break; + } +#endif + cont: + Bfree(PASS_STATE bb); + Bfree(PASS_STATE bd); + Bfree(PASS_STATE bs); + Bfree(PASS_STATE delta); + } +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(rv0) = Exp_1 + (70 << Exp_shift); + word1(rv0) = 0; + dval(rv0) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif +#ifdef Avoid_Underflow + if (scale) { + word0(rv0) = Exp_1 - 2*P*Exp_msk1; + word1(rv0) = 0; + dval(rv) *= dval(rv0); +#ifndef NO_ERRNO + /* try to avoid the bug of testing an 8087 register value */ + if (word0(rv) == 0 && word1(rv) == 0) + errno = ERANGE; +#endif + } +#endif /* Avoid_Underflow */ +#ifdef SET_INEXACT + if (inexact && !(word0(rv) & Exp_mask)) { + /* set underflow bit */ + dval(rv0) = 1e-300; + dval(rv0) *= dval(rv0); + } +#endif + retfree: + Bfree(PASS_STATE bb); + Bfree(PASS_STATE bd); + Bfree(PASS_STATE bs); + Bfree(PASS_STATE bd0); + Bfree(PASS_STATE delta); + ret: + if (se) + *se = (char *)s; + return sign ? -dval(rv) : dval(rv); + } + + static int +quorem +#ifdef KR_headers + (b, S) Bigint *b, *S; +#else + (Bigint *b, Bigint *S) +#endif +{ + int n; + ULong *bx, *bxe, q, *sx, *sxe; +#ifdef ULLong + ULLong borrow, carry, y, ys; +#else + ULong borrow, carry, y, ys; +#ifdef Pack_32 + ULong si, z, zs; +#endif +#endif + + n = S->wds; +#ifdef DEBUG + /*debug*/ if (b->wds > n) + /*debug*/ Bug("oversize b in quorem"); +#endif + if (b->wds < n) + return 0; + sx = S->x; + sxe = sx + --n; + bx = b->x; + bxe = bx + n; + q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ +#ifdef DEBUG + /*debug*/ if (q > 9) + /*debug*/ Bug("oversized quotient in quorem"); +#endif + if (q) { + borrow = 0; + carry = 0; + do { +#ifdef ULLong + ys = *sx++ * (ULLong)q + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = (ULong) y & FFFFFFFF; +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) * q + carry; + zs = (si >> 16) * q + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ * q + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } + while(sx <= sxe); + if (!*bxe) { + bx = b->x; + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + if (cmp(b, S) >= 0) { + q++; + borrow = 0; + carry = 0; + bx = b->x; + sx = S->x; + do { +#ifdef ULLong + ys = *sx++ + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = (ULong) y & FFFFFFFF; +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) + carry; + zs = (si >> 16) + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } + while(sx <= sxe); + bx = b->x; + bxe = bx + n; + if (!*bxe) { + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + return q; + } + +#if !defined(MULTIPLE_THREADS) && !defined(NO_GLOBAL_STATE) +#define USE_DTOA_RESULT 1 + static char *dtoa_result; +#endif + + static char * +#ifdef KR_headers +rv_alloc(STATE_PARAM i) STATE_PARAM_DECL int i; +#else +rv_alloc(STATE_PARAM int i) +#endif +{ + int j, k, *r; + + j = sizeof(ULong); + for(k = 0; + sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (unsigned) i; + j <<= 1) + k++; + r = (int*)Balloc(PASS_STATE k); + *r = k; + return +#ifdef USE_DTOA_RESULT + dtoa_result = +#endif + (char *)(r+1); + } + + static char * +#ifdef KR_headers +nrv_alloc(STATE_PARAM s, rve, n) STATE_PARAM_DECL char *s, **rve; int n; +#else +nrv_alloc(STATE_PARAM CONST char *s, char **rve, int n) +#endif +{ + char *rv, *t; + + t = rv = rv_alloc(PASS_STATE n); + while((*t = *s++)) t++; + if (rve) + *rve = t; + return rv; + } + +/* freedtoa(s) must be used to free values s returned by dtoa + * when MULTIPLE_THREADS is #defined. It should be used in all cases, + * but for consistency with earlier versions of dtoa, it is optional + * when MULTIPLE_THREADS is not defined. + */ + + static void +#ifdef KR_headers +freedtoa(STATE_PARAM s) STATE_PARAM_DECL char *s; +#else +freedtoa(STATE_PARAM char *s) +#endif +{ + Bigint *b = (Bigint *)((int *)s - 1); + b->maxwds = 1 << (b->k = *(int*)b); + Bfree(PASS_STATE b); +#ifdef USE_DTOA_RESULT + if (s == dtoa_result) + dtoa_result = 0; +#endif + } + +/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. + * + * Inspired by "How to Print Floating-Point Numbers Accurately" by + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. + * + * Modifications: + * 1. Rather than iterating, we use a simple numeric overestimate + * to determine k = floor(log10(d)). We scale relevant + * quantities using O(log2(k)) rather than O(k) multiplications. + * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't + * try to generate digits strictly left to right. Instead, we + * compute with fewer bits and propagate the carry if necessary + * when rounding the final digit up. This is often faster. + * 3. Under the assumption that input will be rounded nearest, + * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. + * That is, we allow equality in stopping tests when the + * round-nearest rule will give the same floating-point value + * as would satisfaction of the stopping test with strict + * inequality. + * 4. We remove common factors of powers of 2 from relevant + * quantities. + * 5. When converting floating-point integers less than 1e16, + * we use floating-point arithmetic rather than resorting + * to multiple-precision integers. + * 6. When asked to produce fewer than 15 digits, we first try + * to get by with floating-point arithmetic; we resort to + * multiple-precision integer arithmetic only if we cannot + * guarantee that the floating-point calculation has given + * the correctly rounded result. For k requested digits and + * "uniformly" distributed input, the probability is + * something like 10^(k-15) that we must resort to the Long + * calculation. + */ + + static char * +dtoa +#ifdef KR_headers + (STATE_PARAM d, mode, ndigits, decpt, sign, rve) + STATE_PARAM_DECL U d; int mode, ndigits, *decpt, *sign; char **rve; +#else + (STATE_PARAM U d, int mode, int ndigits, int *decpt, int *sign, char **rve) +#endif +{ + /* Arguments ndigits, decpt, sign are similar to those + of ecvt and fcvt; trailing zeros are suppressed from + the returned string. If not null, *rve is set to point + to the end of the return value. If d is +-Infinity or NaN, + then *decpt is set to 9999. + + mode: + 0 ==> shortest string that yields d when read in + and rounded to nearest. + 1 ==> like 0, but with Steele & White stopping rule; + e.g. with IEEE P754 arithmetic , mode 0 gives + 1e23 whereas mode 1 gives 9.999999999999999e22. + 2 ==> max(1,ndigits) significant digits. This gives a + return value similar to that of ecvt, except + that trailing zeros are suppressed. + 3 ==> through ndigits past the decimal point. This + gives a return value similar to that from fcvt, + except that trailing zeros are suppressed, and + ndigits can be negative. + 4,5 ==> similar to 2 and 3, respectively, but (in + round-nearest mode) with the tests of mode 0 to + possibly return a shorter string that rounds to d. + With IEEE arithmetic and compilation with + -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same + as modes 2 and 3 when FLT_ROUNDS != 1. + 6-9 ==> Debugging modes similar to mode - 4: don't try + fast floating-point estimate (if applicable). + + Values of mode other than 0-9 are treated as mode 0. + + Sufficient space is allocated to the return value + to hold the suppressed trailing zeros. + */ + + int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, + j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, + spec_case, try_quick; + Long L; +#ifndef Sudden_Underflow + int denorm; + ULong x; +#endif + Bigint *b, *b1, *delta, *mlo, *mhi, *S; + U d2, eps; + double ds; + char *s, *s0; +#ifdef Honor_FLT_ROUNDS + int rounding; +#endif +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif + +#ifdef __GNUC__ + ilim = ilim1 = 0; + mlo = NULL; +#endif + +#ifdef USE_DTOA_RESULT + if (dtoa_result) { + freedtoa(PASS_STATE dtoa_result); + dtoa_result = 0; + } +#endif + + if (word0(d) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + word0(d) &= ~Sign_bit; /* clear sign bit */ + } + else + *sign = 0; + +#if defined(IEEE_Arith) + defined(VAX) +#ifdef IEEE_Arith + if ((word0(d) & Exp_mask) == Exp_mask) +#else + if (word0(d) == 0x8000) +#endif + { + /* Infinity or NaN */ + *decpt = 9999; +#ifdef IEEE_Arith + if (!word1(d) && !(word0(d) & 0xfffff)) + return nrv_alloc(PASS_STATE "Infinity", rve, 8); +#endif + return nrv_alloc(PASS_STATE "NaN", rve, 3); + } +#endif +#ifdef IBM + dval(d) += 0; /* normalize */ +#endif + if (!dval(d)) { + *decpt = 1; + return nrv_alloc(PASS_STATE "0", rve, 1); + } + +#ifdef SET_INEXACT + try_quick = oldinexact = get_inexact(); + inexact = 1; +#endif +#ifdef Honor_FLT_ROUNDS + if ((rounding = Flt_Rounds) >= 2) { + if (*sign) + rounding = rounding == 2 ? 0 : 2; + else + if (rounding != 2) + rounding = 0; + } +#endif + + b = d2b(PASS_STATE d, &be, &bbits); +#ifdef Sudden_Underflow + i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); +#else + if ((i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) { +#endif + dval(d2) = dval(d); + word0(d2) &= Frac_mask1; + word0(d2) |= Exp_11; +#ifdef IBM + if (j = 11 - hi0bits(word0(d2) & Frac_mask)) + dval(d2) /= 1 << j; +#endif + + /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 + * log10(x) = log(x) / log(10) + * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) + * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) + * + * This suggests computing an approximation k to log10(d) by + * + * k = (i - Bias)*0.301029995663981 + * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); + * + * We want k to be too large rather than too small. + * The error in the first-order Taylor series approximation + * is in our favor, so we just round up the constant enough + * to compensate for any error in the multiplication of + * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, + * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, + * adding 1e-13 to the constant term more than suffices. + * Hence we adjust the constant term to 0.1760912590558. + * (We could get a more accurate k by invoking log10, + * but this is probably not worthwhile.) + */ + + i -= Bias; +#ifdef IBM + i <<= 2; + i += j; +#endif +#ifndef Sudden_Underflow + denorm = 0; + } + else { + /* d is denormalized */ + + i = bbits + be + (Bias + (P-1) - 1); + x = i > 32 ? word0(d) << (64 - i) | word1(d) >> (i - 32) + : word1(d) << (32 - i); + dval(d2) = x; + word0(d2) -= 31*Exp_msk1; /* adjust exponent */ + i -= (Bias + (P-1) - 1) + 1; + denorm = 1; + } +#endif + ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; + k = (int)ds; + if (ds < 0. && ds != k) + k--; /* want k = floor(ds) */ + k_check = 1; + if (k >= 0 && k <= Ten_pmax) { + if (dval(d) < tens[k]) + k--; + k_check = 0; + } + j = bbits - i - 1; + if (j >= 0) { + b2 = 0; + s2 = j; + } + else { + b2 = -j; + s2 = 0; + } + if (k >= 0) { + b5 = 0; + s5 = k; + s2 += k; + } + else { + b2 -= k; + b5 = -k; + s5 = 0; + } + if (mode < 0 || mode > 9) + mode = 0; + +#ifndef SET_INEXACT +#ifdef Check_FLT_ROUNDS + try_quick = Rounding == 1; +#else + try_quick = 1; +#endif +#endif /*SET_INEXACT*/ + + if (mode > 5) { + mode -= 4; + try_quick = 0; + } + leftright = 1; + switch(mode) { + case 0: + case 1: + ilim = ilim1 = -1; + i = 18; + ndigits = 0; + break; + case 2: + leftright = 0; + /* no break */ + case 4: + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + break; + case 3: + leftright = 0; + /* no break */ + case 5: + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } + s = s0 = rv_alloc(PASS_STATE i); + +#ifdef Honor_FLT_ROUNDS + if (mode > 1 && rounding != 1) + leftright = 0; +#endif + + if (ilim >= 0 && ilim <= Quick_max && try_quick) { + + /* Try to get by with floating-point arithmetic. */ + + i = 0; + dval(d2) = dval(d); + k0 = k; + ilim0 = ilim; + ieps = 2; /* conservative */ + if (k > 0) { + ds = tens[k&0xf]; + j = k >> 4; + if (j & Bletch) { + /* prevent overflows */ + j &= Bletch - 1; + dval(d) /= bigtens[n_bigtens-1]; + ieps++; + } + for(; j; j >>= 1, i++) + if (j & 1) { + ieps++; + ds *= bigtens[i]; + } + dval(d) /= ds; + } + else if ((j1 = -k)) { + dval(d) *= tens[j1 & 0xf]; + for(j = j1 >> 4; j; j >>= 1, i++) + if (j & 1) { + ieps++; + dval(d) *= bigtens[i]; + } + } + if (k_check && dval(d) < 1. && ilim > 0) { + if (ilim1 <= 0) + goto fast_failed; + ilim = ilim1; + k--; + dval(d) *= 10.; + ieps++; + } + dval(eps) = ieps*dval(d) + 7.; + word0(eps) -= (P-1)*Exp_msk1; + if (ilim == 0) { + S = mhi = 0; + dval(d) -= 5.; + if (dval(d) > dval(eps)) + goto one_digit; + if (dval(d) < -dval(eps)) + goto no_digits; + goto fast_failed; + } +#ifndef No_leftright + if (leftright) { + /* Use Steele & White method of only + * generating digits needed. + */ + dval(eps) = 0.5/tens[ilim-1] - dval(eps); + for(i = 0;;) { + L = (ULong) dval(d); + dval(d) -= L; + *s++ = '0' + (int)L; + if (dval(d) < dval(eps)) + goto ret1; + if (1. - dval(d) < dval(eps)) + goto bump_up; + if (++i >= ilim) + break; + dval(eps) *= 10.; + dval(d) *= 10.; + } + } + else { +#endif + /* Generate ilim digits, then fix them up. */ + dval(eps) *= tens[ilim-1]; + for(i = 1;; i++, dval(d) *= 10.) { + L = (Long)(dval(d)); + if (!(dval(d) -= L)) + ilim = i; + *s++ = '0' + (int)L; + if (i == ilim) { + if (dval(d) > 0.5 + dval(eps)) + goto bump_up; + else if (dval(d) < 0.5 - dval(eps)) { + while(*--s == '0'); + s++; + goto ret1; + } + break; + } + } +#ifndef No_leftright + } +#endif + fast_failed: + s = s0; + dval(d) = dval(d2); + k = k0; + ilim = ilim0; + } + + /* Do we have a "small" integer? */ + + if (be >= 0 && k <= Int_max) { + /* Yes. */ + ds = tens[k]; + if (ndigits < 0 && ilim <= 0) { + S = mhi = 0; + if (ilim < 0 || dval(d) < 5*ds) + goto no_digits; + goto one_digit; + } + for(i = 1;; i++, dval(d) *= 10.) { + L = (Long)(dval(d) / ds); + dval(d) -= L*ds; +#ifdef Check_FLT_ROUNDS + /* If FLT_ROUNDS == 2, L will usually be high by 1 */ + if (dval(d) < 0) { + L--; + dval(d) += ds; + } +#endif + *s++ = '0' + (int)L; + if (!dval(d)) { +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (i == ilim) { +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(rounding) { + case 0: goto ret1; + case 2: goto bump_up; + } +#endif + dval(d) += dval(d); + if (dval(d) > ds || (dval(d) == ds && L & 1)) { + bump_up: + while(*--s == '9') + if (s == s0) { + k++; + *s = '0'; + break; + } + ++*s++; + } + break; + } + } + goto ret1; + } + + m2 = b2; + m5 = b5; + mhi = mlo = 0; + if (leftright) { + i = +#ifndef Sudden_Underflow + denorm ? be + (Bias + (P-1) - 1 + 1) : +#endif +#ifdef IBM + 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); +#else + 1 + P - bbits; +#endif + b2 += i; + s2 += i; + mhi = i2b(PASS_STATE 1); + } + if (m2 > 0 && s2 > 0) { + i = m2 < s2 ? m2 : s2; + b2 -= i; + m2 -= i; + s2 -= i; + } + if (b5 > 0) { + if (leftright) { + if (m5 > 0) { + mhi = pow5mult(PASS_STATE mhi, m5); + b1 = mult(PASS_STATE mhi, b); + Bfree(PASS_STATE b); + b = b1; + } + if ((j = b5 - m5)) + b = pow5mult(PASS_STATE b, j); + } + else + b = pow5mult(PASS_STATE b, b5); + } + S = i2b(PASS_STATE 1); + if (s5 > 0) + S = pow5mult(PASS_STATE S, s5); + + /* Check for special case that d is a normalized power of 2. */ + + spec_case = 0; + if ((mode < 2 || leftright) +#ifdef Honor_FLT_ROUNDS + && rounding == 1 +#endif + ) { + if (!word1(d) && !(word0(d) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(d) & (Exp_mask & ~Exp_msk1) +#endif + ) { + /* The special case */ + b2 += Log2P; + s2 += Log2P; + spec_case = 1; + } + } + + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + * + * Perhaps we should just compute leading 28 bits of S once + * and for all and pass them and a shift to quorem, so it + * can do shifts and ors to compute the numerator for q. + */ +#ifdef Pack_32 + if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f)) + i = 32 - i; +#else + if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) + i = 16 - i; +#endif + if (i > 4) { + i -= 4; + b2 += i; + m2 += i; + s2 += i; + } + else if (i < 4) { + i += 28; + b2 += i; + m2 += i; + s2 += i; + } + if (b2 > 0) + b = lshift(PASS_STATE b, b2); + if (s2 > 0) + S = lshift(PASS_STATE S, s2); + if (k_check) { + if (cmp(b,S) < 0) { + k--; + b = multadd(PASS_STATE b, 10, 0); /* we botched the k estimate */ + if (leftright) + mhi = multadd(PASS_STATE mhi, 10, 0); + ilim = ilim1; + } + } + if (ilim <= 0 && (mode == 3 || mode == 5)) { + if (ilim < 0 || cmp(b,S = multadd(PASS_STATE S,5,0)) < 0) { + /* no digits, fcvt style */ + no_digits: + /* MOZILLA CHANGE: Always return a non-empty string. */ + *s++ = '0'; + k = 0; + goto ret; + } + one_digit: + *s++ = '1'; + k++; + goto ret; + } + if (leftright) { + if (m2 > 0) + mhi = lshift(PASS_STATE mhi, m2); + + /* Compute mlo -- check for special case + * that d is a normalized power of 2. + */ + + mlo = mhi; + if (spec_case) { + mhi = Balloc(PASS_STATE mhi->k); + Bcopy(mhi, mlo); + mhi = lshift(PASS_STATE mhi, Log2P); + } + + for(i = 1;;i++) { + dig = quorem(b,S) + '0'; + /* Do we yet have the shortest decimal string + * that will round to d? + */ + j = cmp(b, mlo); + delta = diff(PASS_STATE S, mhi); + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(PASS_STATE delta); +#ifndef ROUND_BIASED + if (j1 == 0 && mode != 1 && !(word1(d) & 1) +#ifdef Honor_FLT_ROUNDS + && rounding >= 1 +#endif + ) { + if (dig == '9') + goto round_9_up; + if (j > 0) + dig++; +#ifdef SET_INEXACT + else if (!b->x[0] && b->wds <= 1) + inexact = 0; +#endif + *s++ = dig; + goto ret; + } +#endif + if (j < 0 || (j == 0 && mode != 1 +#ifndef ROUND_BIASED + && !(word1(d) & 1) +#endif + )) { + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto accept_dig; + } +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(rounding) { + case 0: goto accept_dig; + case 2: goto keep_dig; + } +#endif /*Honor_FLT_ROUNDS*/ + if (j1 > 0) { + b = lshift(PASS_STATE b, 1); + j1 = cmp(b, S); + if ((j1 > 0 || (j1 == 0 && dig & 1)) + && dig++ == '9') + goto round_9_up; + } + accept_dig: + *s++ = dig; + goto ret; + } + if (j1 > 0) { +#ifdef Honor_FLT_ROUNDS + if (!rounding) + goto accept_dig; +#endif + if (dig == '9') { /* possible if i == 1 */ + round_9_up: + *s++ = '9'; + goto roundoff; + } + *s++ = dig + 1; + goto ret; + } +#ifdef Honor_FLT_ROUNDS + keep_dig: +#endif + *s++ = dig; + if (i == ilim) + break; + b = multadd(PASS_STATE b, 10, 0); + if (mlo == mhi) + mlo = mhi = multadd(PASS_STATE mhi, 10, 0); + else { + mlo = multadd(PASS_STATE mlo, 10, 0); + mhi = multadd(PASS_STATE mhi, 10, 0); + } + } + } + else + for(i = 1;; i++) { + *s++ = dig = quorem(b,S) + '0'; + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto ret; + } + if (i >= ilim) + break; + b = multadd(PASS_STATE b, 10, 0); + } + + /* Round off last digit */ + +#ifdef Honor_FLT_ROUNDS + switch(rounding) { + case 0: goto trimzeros; + case 2: goto roundoff; + } +#endif + b = lshift(PASS_STATE b, 1); + j = cmp(b, S); + if (j >= 0) { /* ECMA compatible rounding needed by Spidermonkey */ + roundoff: + while(*--s == '9') + if (s == s0) { + k++; + *s++ = '1'; + goto ret; + } + ++*s++; + } + else { +#ifdef Honor_FLT_ROUNDS + trimzeros: +#endif + while(*--s == '0'); + s++; + } + ret: + Bfree(PASS_STATE S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(PASS_STATE mlo); + Bfree(PASS_STATE mhi); + } + ret1: +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(d) = Exp_1 + (70 << Exp_shift); + word1(d) = 0; + dval(d) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif + Bfree(PASS_STATE b); + *s = 0; + *decpt = k + 1; + if (rve) + *rve = s; + return s0; + } +#ifdef __cplusplus +} +#endif diff --git a/js/src/editline/Makefile.in b/js/src/editline/Makefile.in new file mode 100644 index 0000000..acf5a6d --- /dev/null +++ b/js/src/editline/Makefile.in @@ -0,0 +1,55 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Spidermonkey build system. +# +# The Initial Developer of the Original Code is +# The Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Ted Mielczarek +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +LIBRARY_NAME = editline +FORCE_STATIC_LIB = 1 + +CSRCS = editline.c sysunix.c + +DEFINES += -DANSI_ARROWS -DHAVE_TCGETATTR -DHIDE -DUSE_DIRENT -DSYS_UNIX \ + -DHAVE_STDLIB -DUNIQUE_HISTORY + +include $(topsrcdir)/config/rules.mk diff --git a/js/src/editline/Makefile.ref b/js/src/editline/Makefile.ref new file mode 100644 index 0000000..c902c88 --- /dev/null +++ b/js/src/editline/Makefile.ref @@ -0,0 +1,143 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Simmule Turner and Rich Salz. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. +# +# This software is not subject to any license of the American Telephone +# and Telegraph Company or of the Regents of the University of California. +# +# Permission is granted to anyone to use this software for any purpose on +# any computer system, and to alter it and redistribute it freely, subject +# to the following restrictions: +# 1. The authors are not responsible for the consequences of use of this +# software, no matter how awful, even if they arise from flaws in it. +# 2. The origin of this software must not be misrepresented, either by +# explicit claim or by omission. Since few users ever read sources, +# credits must appear in the documentation. +# 3. Altered versions must be plainly marked as such, and must not be +# misrepresented as being the original software. Since few users +# ever read sources, credits must appear in the documentation. +# 4. This notice may not be removed or altered. +# + +# +# Unix makefile for editline library. +# + +## Set your options: +## -DANSI_ARROWS ANSI arrows keys work like emacs. +## -DHAVE_STDLIB Have . +## -DHAVE_TCGETATTR Have tcgetattr(), tcsetattr(). +## -DHAVE_TERMIO Have "struct termio" and +## (If neither of above two, we use and BSD ioctl's) +## -DHIDE Make static functions static (non debug). +## -DHIST_SIZE=n History size. +## -DNEED_STRDUP Don't have strdup(). +## -DUNIQUE_HISTORY Don't save command if same as last one. +## -DUSE_DIRENT Use , not ? +## -DUSE_TERMCAP Use the termcap library for terminal size +## see LDFLAGS, below, if you set this. +## -DNEED_PERROR Don't have perror() (used in testit) + +## If you have -DUSE_TERMCAP, set this as appropriate: +#LDFLAGS = -ltermlib +#LDFLAGS = -ltermcap + +DEFS = -DANSI_ARROWS -DHAVE_TCGETATTR -DHIDE -DUSE_DIRENT -DSYS_UNIX \ + -DHAVE_STDLIB -DUNIQUE_HISTORY + +DEPTH = .. + +include $(DEPTH)/config.mk + +LOCAL_OBJDIR = $(OBJDIR)/editline + +# +# Default IEEE libm +# +CFLAGS += -DXP_UNIX $(OPTIMIZER) $(OS_CFLAGS) $(DEFINES) $(INCLUDES) \ + -DJSFILE $(XCFLAGS) $(DEFS) + +INCFILES = editline.h +.INIT: $(INCFILES) +.KEEP_STATE: +EDITLINE_CFILES = editline.c sysunix.c + +EDITLINE_OBJS = $(addprefix $(LOCAL_OBJDIR)/, $(EDITLINE_CFILES:.c=.o)) + +LIBRARY = $(LOCAL_OBJDIR)/libedit.a + +all: $(LIBRARY) + +export: + +# make objects to depen on $(LOCAL_OBJDIR) only when it exists +$(EDITLINE_OBJS) : $(filter-out $(wildcard $(LOCAL_OBJDIR)), $(LOCAL_OBJDIR)) + +$(LOCAL_OBJDIR) : + mkdir -p $@ + +$(LOCAL_OBJDIR)/%: %.c + $(CC) -o $@ $(CFLAGS) $*.c $(LDFLAGS) + +$(LOCAL_OBJDIR)/%.o: %.c + $(CC) -o $@ -c $(CFLAGS) $*.c + +$(LOCAL_OBJDIR)/%.o: %.s + $(AS) -o $@ $(ASFLAGS) $*.s + +$(LIBRARY): $(EDITLINE_OBJS) + $(AR) rv $@ $? + $(RANLIB) $@ + +#libedit.a : $(EDITLINE_OBJS) +# $(AR) cru $(LOCAL_OBJDIR)/libedit.a $(EDITLINE_OBJS) +# $(RANLIB) $(LOCAL_OBJDIR)/libedit.a + +clean: + rm -rf $(EDITLINE_OBJS) $(EDITLINE_OBJS:.o=.d) + +clobber: clean + rm -rf $(LIBRARY) $(DEPENDENCIES) + if test -d $(LOCAL_OBJDIR); then rmdir $(LOCAL_OBJDIR); fi + +SUFFIXES: .i +%.i: %.c + $(CC) -C -E $(CFLAGS) $< > $*.i diff --git a/js/src/editline/README b/js/src/editline/README new file mode 100644 index 0000000..bbec0ff --- /dev/null +++ b/js/src/editline/README @@ -0,0 +1,83 @@ +The files in this directory provide simple line-editing and history +support for the standalone javascript engine, through the 'editline' +library. + +editline has only been enabled for those platforms on which it is +known to build; to try it on a different platform, define JS_EDITLINE +before building. Line editing (and js.c) is not a supported feature +of the javascript library, so your mileage my vary. + +The editline API is a compatible subset of the FSF readline API; if +you have readline installed and would like to link to that instead, +define JS_READLINE. Note that the readline library is distributed +under the GPL, so any resulting binaries are not legally +distributable. + +The editline files used here have been modified to work with the js +build system and to quiet some compiler warnings, and also to remove +filename-completion support. + +If anyone knows of a more recent version of these files, or a site on +which they are being maintained, please let me know! + +Mike McCabe, mccabe@netscape.com + + +The original README file distributed with the editline library follows. + + + +This is a line-editing library. It can be linked into almost any +program to provide command-line editing and recall. + +It is call-compatible with the FSF readline library, but it is a +fraction of the size (and offers fewer features). It does not use +standard I/O. It is distributed under a "C News-like" copyright. + +Configuration is done in the Makefile. Type "make testit" to get +a small slow shell for testing. + +An earlier version was distributed with Byron's rc. Principal +changes over that version include: + Faster. + Is eight-bit clean (thanks to brendan@cs.widener.edu) + Written in K&R C, but ANSI compliant (gcc all warnings) + Propagates EOF properly; rc trip test now passes + Doesn't need or use or provide memmove. + More robust + Calling sequence changed to be compatible with readline. + Test program, new manpage, better configuration + More system-independent; includes Unix and OS-9 support. + +This contains some changes since the posting to comp.sources.misc: + Bugfix for completion on absolute pathnames. + Better handling of M-n versus showing raw 8bit chars. + Better signal handling. + Now supports termios/termio/sgttyb ioctl's. + Add M-m command to toggle how 8bit data is displayed. + +There is one known bug: + History-searching redraws the line wrong if the text + retrieved is shorter then the prompt. + +Enjoy, + Rich $alz + + + Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. + + This software is not subject to any license of the American Telephone + and Telegraph Company or of the Regents of the University of California. + + Permission is granted to anyone to use this software for any purpose on + any computer system, and to alter it and redistribute it freely, subject + to the following restrictions: + 1. The authors are not responsible for the consequences of use of this + software, no matter how awful, even if they arise from flaws in it. + 2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. Since few users ever read sources, + credits must appear in the documentation. + 3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. Since few users + ever read sources, credits must appear in the documentation. + 4. This notice may not be removed or altered. diff --git a/js/src/editline/editline.3 b/js/src/editline/editline.3 new file mode 100644 index 0000000..21a72ca --- /dev/null +++ b/js/src/editline/editline.3 @@ -0,0 +1,175 @@ +.TH EDITLINE 3 +.SH NAME +editline \- command-line editing library with history +.SH SYNOPSIS +.nf +.B "char *" +.B "readline(prompt)" +.B " char *prompt;" + +.B "void" +.B "add_history(line)" +.B " char *line;" +.fi +.SH DESCRIPTION +.I Editline +is a library that provides an line-editing interface with text recall. +It is intended to be compatible with the +.I readline +library provided by the Free Software Foundation, but much smaller. +The bulk of this manual page describes the user interface. +.PP +The +.I readline +routine returns a line of text with the trailing newline removed. +The data is returned in a buffer allocated with +.IR malloc (3), +so the space should be released with +.IR free (3) +when the calling program is done with it. +Before accepting input from the user, the specified +.I prompt +is displayed on the terminal. +.PP +The +.I add_history +routine makes a copy of the specified +.I line +and adds it to the internal history list. +.SS "User Interface" +A program that uses this library provides a simple emacs-like editing +interface to its users. +A line may be edited before it is sent to the calling program by typing either +control characters or escape sequences. +A control character, shown as a caret followed by a letter, is typed by +holding down the ``control'' key while the letter is typed. +For example, ``^A'' is a control-A. +An escape sequence is entered by typing the ``escape'' key followed by one or +more characters. +The escape key is abbreviated as ``ESC.'' +Note that unlike control keys, case matters in escape sequences; ``ESC\ F'' +is not the same as ``ESC\ f''. +.PP +An editing command may be typed anywhere on the line, not just at the +beginning. +In addition, a return may also be typed anywhere on the line, not just at +the end. +.PP +Most editing commands may be given a repeat count, +.IR n , +where +.I n +is a number. +To enter a repeat count, type the escape key, the number, and then +the command to execute. +For example, ``ESC\ 4\ ^f'' moves forward four characters. +If a command may be given a repeat count then the text ``[n]'' is given at the +end of its description. +.PP +The following control characters are accepted: +.RS +.nf +.ta \w'ESC DEL 'u +^A Move to the beginning of the line +^B Move left (backwards) [n] +^D Delete character [n] +^E Move to end of line +^F Move right (forwards) [n] +^G Ring the bell +^H Delete character before cursor (backspace key) [n] +^I Complete filename (tab key); see below +^J Done with line (return key) +^K Kill to end of line (or column [n]) +^L Redisplay line +^M Done with line (alternate return key) +^N Get next line from history [n] +^P Get previous line from history [n] +^R Search backward (forward if [n]) through history for text; +\& must start line if text begins with an uparrow +^T Transpose characters +^V Insert next character, even if it is an edit command +^W Wipe to the mark +^X^X Exchange current location and mark +^Y Yank back last killed text +^[ Start an escape sequence (escape key) +^]c Move forward to next character ``c'' +^? Delete character before cursor (delete key) [n] +.fi +.RE +.PP +The following escape sequences are provided. +.RS +.nf +.ta \w'ESC DEL 'u +ESC\ ^H Delete previous word (backspace key) [n] +ESC\ DEL Delete previous word (delete key) [n] +ESC\ SP Set the mark (space key); see ^X^X and ^Y above +ESC\ \. Get the last (or [n]'th) word from previous line +ESC\ \? Show possible completions; see below +ESC\ < Move to start of history +ESC\ > Move to end of history +ESC\ b Move backward a word [n] +ESC\ d Delete word under cursor [n] +ESC\ f Move forward a word [n] +ESC\ l Make word lowercase [n] +ESC\ m Toggle if 8bit chars display normally or with ``M\-'' prefix +ESC\ u Make word uppercase [n] +ESC\ y Yank back last killed text +ESC\ v Show library version +ESC\ w Make area up to mark yankable +ESC\ nn Set repeat count to the number nn +ESC\ C Read from environment variable ``_C_'', where C is +\& an uppercase letter +.fi +.RE +.PP +The +.I editline +library has a small macro facility. +If you type the escape key followed by an uppercase letter, +.IR C , +then the contents of the environment variable +.I _C_ +are read in as if you had typed them at the keyboard. +For example, if the variable +.I _L_ +contains the following: +.RS +^A^Kecho '^V^[[H^V^[[2J'^M +.RE +Then typing ``ESC L'' will move to the beginning of the line, kill the +entire line, enter the echo command needed to clear the terminal (if your +terminal is like a VT-100), and send the line back to the shell. +.PP +The +.I editline +library also does filename completion. +Suppose the root directory has the following files in it: +.RS +.nf +.ta \w'core 'u +bin vmunix +core vmunix.old +.fi +.RE +If you type ``rm\ /v'' and then the tab key. +.I Editline +will then finish off as much of the name as possible by adding ``munix''. +Because the name is not unique, it will then beep. +If you type the escape key and a question mark, it will display the +two choices. +If you then type a period and a tab, the library will finish off the filename +for you: +.RS +.nf +.RI "rm /v[TAB]" munix .TAB old +.fi +.RE +The tab key is shown by ``[TAB]'' and the automatically-entered text +is shown in italics. +.SH "BUGS AND LIMITATIONS" +Cannot handle lines more than 80 columns. +.SH AUTHORS +Simmule R. Turner +and Rich $alz . +Original manual page by DaviD W. Sanderson . diff --git a/js/src/editline/editline.c b/js/src/editline/editline.c new file mode 100644 index 0000000..07d4819 --- /dev/null +++ b/js/src/editline/editline.c @@ -0,0 +1,1374 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Simmule Turner and Rich Salz. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or of the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * 1. The authors are not responsible for the consequences of use of this + * software, no matter how awful, even if they arise from flaws in it. + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Since few users ever read sources, + * credits must appear in the documentation. + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. Since few users + * ever read sources, credits must appear in the documentation. + * 4. This notice may not be removed or altered. + */ + + +/* +** Main editing routines for editline library. +*/ +#include "editline.h" +#include +#include +#include + +/* +** Manifest constants. +*/ +#define SCREEN_WIDTH 80 +#define SCREEN_ROWS 24 +#define NO_ARG (-1) +#define DEL 127 +#define CTL(x) ((x) & 0x1F) +#define ISCTL(x) ((x) && (x) < ' ') +#define UNCTL(x) ((x) + 64) +#define META(x) ((x) | 0x80) +#define ISMETA(x) ((x) & 0x80) +#define UNMETA(x) ((x) & 0x7F) +#if !defined(HIST_SIZE) +#define HIST_SIZE 20 +#endif /* !defined(HIST_SIZE) */ + +/* +** Command status codes. +*/ +typedef enum _STATUS { + CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal +} STATUS; + +/* +** The type of case-changing to perform. +*/ +typedef enum _CASE { + TOupper, TOlower +} CASE; + +/* +** Key to command mapping. +*/ +typedef struct _KEYMAP { + CHAR Key; + STATUS (*Function)(); +} KEYMAP; + +/* +** Command history structure. +*/ +typedef struct _HISTORY { + int Size; + int Pos; + CHAR *Lines[HIST_SIZE]; +} HISTORY; + +/* +** Globals. +*/ +unsigned rl_eof; +unsigned rl_erase; +unsigned rl_intr; +unsigned rl_kill; +unsigned rl_quit; + +STATIC CHAR NIL[] = ""; +STATIC CONST CHAR *Input = NIL; +STATIC CHAR *Line; +STATIC CONST char *Prompt; +STATIC CHAR *Yanked; +STATIC char *Screen; +STATIC char NEWLINE[]= CRLF; +STATIC HISTORY H; +STATIC int Repeat; +STATIC int End; +STATIC int Mark; +STATIC int OldPoint; +STATIC int Point; +STATIC int PushBack; +STATIC int Pushed; +STATIC int Signal; +FORWARD KEYMAP Map[32]; +FORWARD KEYMAP MetaMap[16]; +STATIC SIZE_T Length; +STATIC SIZE_T ScreenCount; +STATIC SIZE_T ScreenSize; +STATIC char *backspace; +STATIC int TTYwidth; +STATIC int TTYrows; + +/* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */ +int rl_meta_chars = 0; + +/* +** Declarations. +*/ +STATIC CHAR *editinput(); +#if defined(USE_TERMCAP) +#include +#include +#include +#endif /* defined(USE_TERMCAP) */ + +/* +** TTY input/output functions. +*/ + +STATIC void +TTYflush() +{ + if (ScreenCount) { + /* Dummy assignment avoids GCC warning on + * "attribute warn_unused_result" */ + ssize_t dummy = write(1, Screen, ScreenCount); + (void)dummy; + ScreenCount = 0; + } +} + +STATIC void +TTYput(c) + CHAR c; +{ + Screen[ScreenCount] = c; + if (++ScreenCount >= ScreenSize - 1) { + ScreenSize += SCREEN_INC; + RENEW(Screen, char, ScreenSize); + } +} + +STATIC void +TTYputs(p) + CHAR *p; +{ + while (*p) + TTYput(*p++); +} + +STATIC void +TTYshow(c) + CHAR c; +{ + if (c == DEL) { + TTYput('^'); + TTYput('?'); + } + else if (ISCTL(c)) { + TTYput('^'); + TTYput(UNCTL(c)); + } + else if (rl_meta_chars && ISMETA(c)) { + TTYput('M'); + TTYput('-'); + TTYput(UNMETA(c)); + } + else + TTYput(c); +} + +STATIC void +TTYstring(p) + CHAR *p; +{ + while (*p) + TTYshow(*p++); +} + +STATIC unsigned int +TTYget() +{ + CHAR c; + + TTYflush(); + if (Pushed) { + Pushed = 0; + return PushBack; + } + if (*Input) + return *Input++; + return read(0, &c, (SIZE_T)1) == 1 ? c : EOF; +} + +#define TTYback() (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b')) + +STATIC void +TTYbackn(n) + int n; +{ + while (--n >= 0) + TTYback(); +} + +STATIC void +TTYinfo() +{ + static int init; +#if defined(USE_TERMCAP) + char *term; + char buff[2048]; + char *bp, *p; +#endif /* defined(USE_TERMCAP) */ +#if defined(TIOCGWINSZ) + struct winsize W; +#endif /* defined(TIOCGWINSZ) */ + + if (init) { +#if defined(TIOCGWINSZ) + /* Perhaps we got resized. */ + if (ioctl(0, TIOCGWINSZ, &W) >= 0 + && W.ws_col > 0 && W.ws_row > 0) { + TTYwidth = (int)W.ws_col; + TTYrows = (int)W.ws_row; + } +#endif /* defined(TIOCGWINSZ) */ + return; + } + init++; + + TTYwidth = TTYrows = 0; +#if defined(USE_TERMCAP) + bp = &buff[0]; + if ((term = getenv("TERM")) == NULL) + term = "dumb"; + if (tgetent(buff, term) < 0) { + TTYwidth = SCREEN_WIDTH; + TTYrows = SCREEN_ROWS; + return; + } + p = tgetstr("le", &bp); + backspace = p ? strdup(p) : NULL; + TTYwidth = tgetnum("co"); + TTYrows = tgetnum("li"); +#endif /* defined(USE_TERMCAP) */ + +#if defined(TIOCGWINSZ) + if (ioctl(0, TIOCGWINSZ, &W) >= 0) { + TTYwidth = (int)W.ws_col; + TTYrows = (int)W.ws_row; + } +#endif /* defined(TIOCGWINSZ) */ + + if (TTYwidth <= 0 || TTYrows <= 0) { + TTYwidth = SCREEN_WIDTH; + TTYrows = SCREEN_ROWS; + } +} + + +STATIC void +reposition() +{ + int i; + CHAR *p; + + TTYput('\r'); + TTYputs((CONST CHAR *)Prompt); + for (i = Point, p = Line; --i >= 0; p++) + TTYshow(*p); +} + +STATIC void +left(Change) + STATUS Change; +{ + TTYback(); + if (Point) { + if (ISCTL(Line[Point - 1])) + TTYback(); + else if (rl_meta_chars && ISMETA(Line[Point - 1])) { + TTYback(); + TTYback(); + } + } + if (Change == CSmove) + Point--; +} + +STATIC void +right(Change) + STATUS Change; +{ + TTYshow(Line[Point]); + if (Change == CSmove) + Point++; +} + +STATIC STATUS +ring_bell() +{ + TTYput('\07'); + TTYflush(); + return CSstay; +} + +STATIC STATUS +do_macro(c) + unsigned int c; +{ + CHAR name[4]; + + name[0] = '_'; + name[1] = c; + name[2] = '_'; + name[3] = '\0'; + + if ((Input = (CHAR *)getenv((char *)name)) == NULL) { + Input = NIL; + return ring_bell(); + } + return CSstay; +} + +STATIC STATUS +do_forward(move) + STATUS move; +{ + int i; + CHAR *p; + + i = 0; + do { + p = &Line[Point]; + for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++) + if (move == CSmove) + right(CSstay); + + for (; Point < End && isalnum(*p); Point++, p++) + if (move == CSmove) + right(CSstay); + + if (Point == End) + break; + } while (++i < Repeat); + + return CSstay; +} + +STATIC STATUS +do_case(type) + CASE type; +{ + int i; + int end; + int count; + CHAR *p; + + (void)do_forward(CSstay); + if (OldPoint != Point) { + if ((count = Point - OldPoint) < 0) + count = -count; + Point = OldPoint; + if ((end = Point + count) > End) + end = End; + for (i = Point, p = &Line[i]; i < end; i++, p++) { + if (type == TOupper) { + if (islower(*p)) + *p = toupper(*p); + } + else if (isupper(*p)) + *p = tolower(*p); + right(CSmove); + } + } + return CSstay; +} + +STATIC STATUS +case_down_word() +{ + return do_case(TOlower); +} + +STATIC STATUS +case_up_word() +{ + return do_case(TOupper); +} + +STATIC void +ceol() +{ + int extras; + int i; + CHAR *p; + + for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) { + TTYput(' '); + if (ISCTL(*p)) { + TTYput(' '); + extras++; + } + else if (rl_meta_chars && ISMETA(*p)) { + TTYput(' '); + TTYput(' '); + extras += 2; + } + } + + for (i += extras; i > Point; i--) + TTYback(); +} + +STATIC void +clear_line() +{ + Point = -strlen(Prompt); + TTYput('\r'); + ceol(); + Point = 0; + End = 0; + Line[0] = '\0'; +} + +STATIC STATUS +insert_string(p) + CHAR *p; +{ + SIZE_T len; + int i; + CHAR *new; + CHAR *q; + + len = strlen((char *)p); + if (End + len >= Length) { + if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL) + return CSstay; + if (Length) { + COPYFROMTO(new, Line, Length); + DISPOSE(Line); + } + Line = new; + Length += len + MEM_INC; + } + + for (q = &Line[Point], i = End - Point; --i >= 0; ) + q[len + i] = q[i]; + COPYFROMTO(&Line[Point], p, len); + End += len; + Line[End] = '\0'; + TTYstring(&Line[Point]); + Point += len; + + return Point == End ? CSstay : CSmove; +} + +STATIC STATUS +redisplay() +{ + TTYputs((CONST CHAR *)NEWLINE); + TTYputs((CONST CHAR *)Prompt); + TTYstring(Line); + return CSmove; +} + +STATIC STATUS +toggle_meta_mode() +{ + rl_meta_chars = ! rl_meta_chars; + return redisplay(); +} + + +STATIC CHAR * +next_hist() +{ + return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos]; +} + +STATIC CHAR * +prev_hist() +{ + return H.Pos == 0 ? NULL : H.Lines[--H.Pos]; +} + +STATIC STATUS +do_insert_hist(p) + CHAR *p; +{ + if (p == NULL) + return ring_bell(); + Point = 0; + reposition(); + ceol(); + End = 0; + return insert_string(p); +} + +STATIC STATUS +do_hist(move) + CHAR *(*move)(); +{ + CHAR *p; + int i; + + i = 0; + do { + if ((p = (*move)()) == NULL) + return ring_bell(); + } while (++i < Repeat); + return do_insert_hist(p); +} + +STATIC STATUS +h_next() +{ + return do_hist(next_hist); +} + +STATIC STATUS +h_prev() +{ + return do_hist(prev_hist); +} + +STATIC STATUS +h_first() +{ + return do_insert_hist(H.Lines[H.Pos = 0]); +} + +STATIC STATUS +h_last() +{ + return do_insert_hist(H.Lines[H.Pos = H.Size - 1]); +} + +/* +** Return zero if pat appears as a substring in text. +*/ +STATIC int +substrcmp(text, pat, len) + char *text; + char *pat; + int len; +{ + char c; + + if ((c = *pat) == '\0') + return *text == '\0'; + for ( ; *text; text++) + if (*text == c && strncmp(text, pat, len) == 0) + return 0; + return 1; +} + +STATIC CHAR * +search_hist(search, move) + CHAR *search; + CHAR *(*move)(); +{ + static CHAR *old_search; + int len; + int pos; + int (*match)(); + char *pat; + + /* Save or get remembered search pattern. */ + if (search && *search) { + if (old_search) + DISPOSE(old_search); + old_search = (CHAR *)strdup((char *)search); + } + else { + if (old_search == NULL || *old_search == '\0') + return NULL; + search = old_search; + } + + /* Set up pattern-finder. */ + if (*search == '^') { + match = strncmp; + pat = (char *)(search + 1); + } + else { + match = substrcmp; + pat = (char *)search; + } + len = strlen(pat); + + for (pos = H.Pos; (*move)() != NULL; ) + if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0) + return H.Lines[H.Pos]; + H.Pos = pos; + return NULL; +} + +STATIC STATUS +h_search() +{ + static int Searching; + CONST char *old_prompt; + CHAR *(*move)(); + CHAR *p; + + if (Searching) + return ring_bell(); + Searching = 1; + + clear_line(); + old_prompt = Prompt; + Prompt = "Search: "; + TTYputs((CONST CHAR *)Prompt); + move = Repeat == NO_ARG ? prev_hist : next_hist; + p = editinput(); + Prompt = old_prompt; + Searching = 0; + TTYputs((CONST CHAR *)Prompt); + if (p == NULL && Signal > 0) { + Signal = 0; + clear_line(); + return redisplay(); + } + p = search_hist(p, move); + clear_line(); + if (p == NULL) { + (void)ring_bell(); + return redisplay(); + } + return do_insert_hist(p); +} + +STATIC STATUS +fd_char() +{ + int i; + + i = 0; + do { + if (Point >= End) + break; + right(CSmove); + } while (++i < Repeat); + return CSstay; +} + +STATIC void +save_yank(begin, i) + int begin; + int i; +{ + if (Yanked) { + DISPOSE(Yanked); + Yanked = NULL; + } + + if (i < 1) + return; + + if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) { + COPYFROMTO(Yanked, &Line[begin], i); + Yanked[i] = '\0'; + } +} + +STATIC STATUS +delete_string(count) + int count; +{ + int i; + CHAR *p; + + if (count <= 0 || End == Point) + return ring_bell(); + + if (count == 1 && Point == End - 1) { + /* Optimize common case of delete at end of line. */ + End--; + p = &Line[Point]; + i = 1; + TTYput(' '); + if (ISCTL(*p)) { + i = 2; + TTYput(' '); + } + else if (rl_meta_chars && ISMETA(*p)) { + i = 3; + TTYput(' '); + TTYput(' '); + } + TTYbackn(i); + *p = '\0'; + return CSmove; + } + if (Point + count > End && (count = End - Point) <= 0) + return CSstay; + + if (count > 1) + save_yank(Point, count); + + for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++) + p[0] = p[count]; + ceol(); + End -= count; + TTYstring(&Line[Point]); + return CSmove; +} + +STATIC STATUS +bk_char() +{ + int i; + + i = 0; + do { + if (Point == 0) + break; + left(CSmove); + } while (++i < Repeat); + + return CSstay; +} + +STATIC STATUS +bk_del_char() +{ + int i; + + i = 0; + do { + if (Point == 0) + break; + left(CSmove); + } while (++i < Repeat); + + return delete_string(i); +} + +STATIC STATUS +kill_line() +{ + int i; + + if (Repeat != NO_ARG) { + if (Repeat < Point) { + i = Point; + Point = Repeat; + reposition(); + (void)delete_string(i - Point); + } + else if (Repeat > Point) { + right(CSmove); + (void)delete_string(Repeat - Point - 1); + } + return CSmove; + } + + save_yank(Point, End - Point); + Line[Point] = '\0'; + ceol(); + End = Point; + return CSstay; +} + +STATIC STATUS +insert_char(c) + int c; +{ + STATUS s; + CHAR buff[2]; + CHAR *p; + CHAR *q; + int i; + + if (Repeat == NO_ARG || Repeat < 2) { + buff[0] = c; + buff[1] = '\0'; + return insert_string(buff); + } + + if ((p = NEW(CHAR, Repeat + 1)) == NULL) + return CSstay; + for (i = Repeat, q = p; --i >= 0; ) + *q++ = c; + *q = '\0'; + Repeat = 0; + s = insert_string(p); + DISPOSE(p); + return s; +} + +STATIC STATUS +meta() +{ + unsigned int c; + KEYMAP *kp; + + if ((int)(c = TTYget()) == EOF) + return CSeof; +#if defined(ANSI_ARROWS) + /* Also include VT-100 arrows. */ + if (c == '[' || c == 'O') + switch (c = TTYget()) { + default: return ring_bell(); + case EOF: return CSeof; + case 'A': return h_prev(); + case 'B': return h_next(); + case 'C': return fd_char(); + case 'D': return bk_char(); + } +#endif /* defined(ANSI_ARROWS) */ + + if (isdigit(c)) { + for (Repeat = c - '0'; (int)(c = TTYget()) != EOF && isdigit(c); ) + Repeat = Repeat * 10 + c - '0'; + Pushed = 1; + PushBack = c; + return CSstay; + } + + if (isupper(c)) + return do_macro(c); + for (OldPoint = Point, kp = MetaMap; kp->Function; kp++) + if (kp->Key == c) + return (*kp->Function)(); + + return ring_bell(); +} + +STATIC STATUS +emacs(c) + unsigned int c; +{ + STATUS s; + KEYMAP *kp; + + if (rl_meta_chars && ISMETA(c)) { + Pushed = 1; + PushBack = UNMETA(c); + return meta(); + } + for (kp = Map; kp->Function; kp++) + if (kp->Key == c) + break; + s = kp->Function ? (*kp->Function)() : insert_char((int)c); + if (!Pushed) + /* No pushback means no repeat count; hacky, but true. */ + Repeat = NO_ARG; + return s; +} + +STATIC STATUS +TTYspecial(c) + unsigned int c; +{ + if (ISMETA(c)) + return CSdispatch; + + if (c == rl_erase || (int)c == DEL) + return bk_del_char(); + if (c == rl_kill) { + if (Point != 0) { + Point = 0; + reposition(); + } + Repeat = NO_ARG; + return kill_line(); + } + if (c == rl_eof && Point == 0 && End == 0) + return CSeof; + if (c == rl_intr) { + Signal = SIGINT; + return CSsignal; + } + if (c == rl_quit) { + Signal = SIGQUIT; + return CSeof; + } + + return CSdispatch; +} + +STATIC CHAR * +editinput() +{ + unsigned int c; + + Repeat = NO_ARG; + OldPoint = Point = Mark = End = 0; + Line[0] = '\0'; + + Signal = -1; + while ((int)(c = TTYget()) != EOF) + switch (TTYspecial(c)) { + case CSdone: + return Line; + case CSeof: + return NULL; + case CSsignal: + return (CHAR *)""; + case CSmove: + reposition(); + break; + case CSdispatch: + switch (emacs(c)) { + case CSdone: + return Line; + case CSeof: + return NULL; + case CSsignal: + return (CHAR *)""; + case CSmove: + reposition(); + break; + case CSdispatch: + case CSstay: + break; + } + break; + case CSstay: + break; + } + if (strlen((char *)Line)) + return Line; + free(Line); + return NULL; +} + +STATIC void +hist_add(p) + CHAR *p; +{ + int i; + + if ((p = (CHAR *)strdup((char *)p)) == NULL) + return; + if (H.Size < HIST_SIZE) + H.Lines[H.Size++] = p; + else { + DISPOSE(H.Lines[0]); + for (i = 0; i < HIST_SIZE - 1; i++) + H.Lines[i] = H.Lines[i + 1]; + H.Lines[i] = p; + } + H.Pos = H.Size - 1; +} + +/* +** For compatibility with FSF readline. +*/ +/* ARGSUSED0 */ +void +rl_reset_terminal(p) + char *p; +{ +} + +void +rl_initialize() +{ +} + +char * +readline(prompt) + CONST char *prompt; +{ + CHAR *line; + int s; + + if (Line == NULL) { + Length = MEM_INC; + if ((Line = NEW(CHAR, Length)) == NULL) + return NULL; + } + + TTYinfo(); + rl_ttyset(0); + hist_add(NIL); + ScreenSize = SCREEN_INC; + Screen = NEW(char, ScreenSize); + Prompt = prompt ? prompt : (char *)NIL; + TTYputs((CONST CHAR *)Prompt); + if ((line = editinput()) != NULL) { + line = (CHAR *)strdup((char *)line); + TTYputs((CHAR *)NEWLINE); + TTYflush(); + } + rl_ttyset(1); + DISPOSE(Screen); + DISPOSE(H.Lines[--H.Size]); + if (Signal > 0) { + s = Signal; + Signal = 0; + (void)kill(getpid(), s); + } + return (char *)line; +} + +void +add_history(p) + char *p; +{ + if (p == NULL || *p == '\0') + return; + +#if defined(UNIQUE_HISTORY) + if (H.Size && strcmp(p, (char *)H.Lines[H.Size - 1]) == 0) + return; +#endif /* defined(UNIQUE_HISTORY) */ + hist_add((CHAR *)p); +} + + +STATIC STATUS +beg_line() +{ + if (Point) { + Point = 0; + return CSmove; + } + return CSstay; +} + +STATIC STATUS +del_char() +{ + return delete_string(Repeat == NO_ARG ? 1 : Repeat); +} + +STATIC STATUS +end_line() +{ + if (Point != End) { + Point = End; + return CSmove; + } + return CSstay; +} + +STATIC STATUS +accept_line() +{ + Line[End] = '\0'; + return CSdone; +} + +STATIC STATUS +transpose() +{ + CHAR c; + + if (Point) { + if (Point == End) + left(CSmove); + c = Line[Point - 1]; + left(CSstay); + Line[Point - 1] = Line[Point]; + TTYshow(Line[Point - 1]); + Line[Point++] = c; + TTYshow(c); + } + return CSstay; +} + +STATIC STATUS +quote() +{ + unsigned int c; + + return (int)(c = TTYget()) == EOF ? CSeof : insert_char((int)c); +} + +STATIC STATUS +wipe() +{ + int i; + + if (Mark > End) + return ring_bell(); + + if (Point > Mark) { + i = Point; + Point = Mark; + Mark = i; + reposition(); + } + + return delete_string(Mark - Point); +} + +STATIC STATUS +mk_set() +{ + Mark = Point; + return CSstay; +} + +STATIC STATUS +exchange() +{ + unsigned int c; + + if ((c = TTYget()) != CTL('X')) + return (int)c == EOF ? CSeof : ring_bell(); + + if ((int)(c = Mark) <= End) { + Mark = Point; + Point = c; + return CSmove; + } + return CSstay; +} + +STATIC STATUS +yank() +{ + if (Yanked && *Yanked) + return insert_string(Yanked); + return CSstay; +} + +STATIC STATUS +copy_region() +{ + if (Mark > End) + return ring_bell(); + + if (Point > Mark) + save_yank(Mark, Point - Mark); + else + save_yank(Point, Mark - Point); + + return CSstay; +} + +STATIC STATUS +move_to_char() +{ + unsigned int c; + int i; + CHAR *p; + + if ((int)(c = TTYget()) == EOF) + return CSeof; + for (i = Point + 1, p = &Line[i]; i < End; i++, p++) + if (*p == c) { + Point = i; + return CSmove; + } + return CSstay; +} + +STATIC STATUS +fd_word() +{ + return do_forward(CSmove); +} + +STATIC STATUS +fd_kill_word() +{ + int i; + + (void)do_forward(CSstay); + if (OldPoint != Point) { + i = Point - OldPoint; + Point = OldPoint; + return delete_string(i); + } + return CSstay; +} + +STATIC STATUS +bk_word() +{ + int i; + CHAR *p; + + i = 0; + do { + for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--) + left(CSmove); + + for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--) + left(CSmove); + + if (Point == 0) + break; + } while (++i < Repeat); + + return CSstay; +} + +STATIC STATUS +bk_kill_word() +{ + (void)bk_word(); + if (OldPoint != Point) + return delete_string(OldPoint - Point); + return CSstay; +} + +STATIC int +argify(line, avp) + CHAR *line; + CHAR ***avp; +{ + CHAR *c; + CHAR **p; + CHAR **new; + int ac; + int i; + + i = MEM_INC; + if ((*avp = p = NEW(CHAR*, i))== NULL) + return 0; + + for (c = line; isspace(*c); c++) + continue; + if (*c == '\n' || *c == '\0') + return 0; + + for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) { + if (isspace(*c)) { + *c++ = '\0'; + if (*c && *c != '\n') { + if (ac + 1 == i) { + new = NEW(CHAR*, i + MEM_INC); + if (new == NULL) { + p[ac] = NULL; + return ac; + } + COPYFROMTO(new, p, i * sizeof (char **)); + i += MEM_INC; + DISPOSE(p); + *avp = p = new; + } + p[ac++] = c; + } + } + else + c++; + } + *c = '\0'; + p[ac] = NULL; + return ac; +} + +STATIC STATUS +last_argument() +{ + CHAR **av; + CHAR *p; + STATUS s; + int ac; + + if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL) + return ring_bell(); + + if ((p = (CHAR *)strdup((char *)p)) == NULL) + return CSstay; + ac = argify(p, &av); + + if (Repeat != NO_ARG) + s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell(); + else + s = ac ? insert_string(av[ac - 1]) : CSstay; + + if (ac) + DISPOSE(av); + DISPOSE(p); + return s; +} + +STATIC KEYMAP Map[32] = { + { CTL('@'), ring_bell }, + { CTL('A'), beg_line }, + { CTL('B'), bk_char }, + { CTL('D'), del_char }, + { CTL('E'), end_line }, + { CTL('F'), fd_char }, + { CTL('G'), ring_bell }, + { CTL('H'), bk_del_char }, + { CTL('J'), accept_line }, + { CTL('K'), kill_line }, + { CTL('L'), redisplay }, + { CTL('M'), accept_line }, + { CTL('N'), h_next }, + { CTL('O'), ring_bell }, + { CTL('P'), h_prev }, + { CTL('Q'), ring_bell }, + { CTL('R'), h_search }, + { CTL('S'), ring_bell }, + { CTL('T'), transpose }, + { CTL('U'), ring_bell }, + { CTL('V'), quote }, + { CTL('W'), wipe }, + { CTL('X'), exchange }, + { CTL('Y'), yank }, + { CTL('Z'), ring_bell }, + { CTL('['), meta }, + { CTL(']'), move_to_char }, + { CTL('^'), ring_bell }, + { CTL('_'), ring_bell }, + { 0, NULL } +}; + +STATIC KEYMAP MetaMap[16]= { + { CTL('H'), bk_kill_word }, + { DEL, bk_kill_word }, + { ' ', mk_set }, + { '.', last_argument }, + { '<', h_first }, + { '>', h_last }, + { 'b', bk_word }, + { 'd', fd_kill_word }, + { 'f', fd_word }, + { 'l', case_down_word }, + { 'm', toggle_meta_mode }, + { 'u', case_up_word }, + { 'y', yank }, + { 'w', copy_region }, + { 0, NULL } +}; + diff --git a/js/src/editline/editline.h b/js/src/editline/editline.h new file mode 100644 index 0000000..41f8f3d --- /dev/null +++ b/js/src/editline/editline.h @@ -0,0 +1,135 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Simmule Turner and Rich Salz. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or of the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * 1. The authors are not responsible for the consequences of use of this + * software, no matter how awful, even if they arise from flaws in it. + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Since few users ever read sources, + * credits must appear in the documentation. + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. Since few users + * ever read sources, credits must appear in the documentation. + * 4. This notice may not be removed or altered. + */ + +/* +** Internal header file for editline library. +*/ +#include +#if defined(HAVE_STDLIB) +#include +#include +#endif /* defined(HAVE_STDLIB) */ +#if defined(SYS_UNIX) +#include "unix.h" +#endif /* defined(SYS_UNIX) */ +#if defined(SYS_OS9) +#include "os9.h" +#endif /* defined(SYS_OS9) */ + +#if !defined(SIZE_T) +#define SIZE_T unsigned int +#endif /* !defined(SIZE_T) */ + +typedef unsigned char CHAR; + +#if defined(HIDE) +#define STATIC static +#else +#define STATIC /* NULL */ +#endif /* !defined(HIDE) */ + +#if !defined(CONST) +#if defined(__STDC__) +#define CONST const +#else +#define CONST +#endif /* defined(__STDC__) */ +#endif /* !defined(CONST) */ + + +#define MEM_INC 64 +#define SCREEN_INC 256 + +#define DISPOSE(p) free((char *)(p)) +#define NEW(T, c) \ + ((T *)malloc((unsigned int)(sizeof (T) * (c)))) +#define RENEW(p, T, c) \ + (p = (T *)realloc((char *)(p), (unsigned int)(sizeof (T) * (c)))) +#define COPYFROMTO(new, p, len) \ + (void)memcpy((char *)(new), (char *)(p), (int)(len)) + + +/* +** Variables and routines internal to this package. +*/ +extern unsigned rl_eof; +extern unsigned rl_erase; +extern unsigned rl_intr; +extern unsigned rl_kill; +extern unsigned rl_quit; +extern char *rl_complete(); +extern int rl_list_possib(); +extern void rl_ttyset(); +extern void rl_add_slash(); + +#if !defined(HAVE_STDLIB) +extern char *getenv(); +extern char *malloc(); +extern char *realloc(); +extern char *memcpy(); +extern char *strcat(); +extern char *strchr(); +extern char *strrchr(); +extern char *strcpy(); +extern char *strdup(); +extern int strcmp(); +extern int strlen(); +extern int strncmp(); +#endif /* !defined(HAVE_STDLIB) */ + diff --git a/js/src/editline/sysunix.c b/js/src/editline/sysunix.c new file mode 100644 index 0000000..17227ea --- /dev/null +++ b/js/src/editline/sysunix.c @@ -0,0 +1,182 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Simmule Turner and Rich Salz. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or of the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * 1. The authors are not responsible for the consequences of use of this + * software, no matter how awful, even if they arise from flaws in it. + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Since few users ever read sources, + * credits must appear in the documentation. + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. Since few users + * ever read sources, credits must appear in the documentation. + * 4. This notice may not be removed or altered. + */ + + +/* +** Unix system-dependant routines for editline library. +*/ +#include "editline.h" + +#if defined(HAVE_TCGETATTR) +#include + +void +rl_ttyset(Reset) + int Reset; +{ + static struct termios old; + struct termios new; + + if (Reset == 0) { + (void)tcgetattr(0, &old); + rl_erase = old.c_cc[VERASE]; + rl_kill = old.c_cc[VKILL]; + rl_eof = old.c_cc[VEOF]; + rl_intr = old.c_cc[VINTR]; + rl_quit = old.c_cc[VQUIT]; + + new = old; + new.c_cc[VINTR] = -1; + new.c_cc[VQUIT] = -1; + new.c_lflag &= ~(ECHO | ICANON); + new.c_iflag &= ~(ISTRIP | INPCK); + new.c_cc[VMIN] = 1; + new.c_cc[VTIME] = 0; + (void)tcsetattr(0, TCSADRAIN, &new); + } + else + (void)tcsetattr(0, TCSADRAIN, &old); +} + +#else +#if defined(HAVE_TERMIO) +#include + +void +rl_ttyset(Reset) + int Reset; +{ + static struct termio old; + struct termio new; + + if (Reset == 0) { + (void)ioctl(0, TCGETA, &old); + rl_erase = old.c_cc[VERASE]; + rl_kill = old.c_cc[VKILL]; + rl_eof = old.c_cc[VEOF]; + rl_intr = old.c_cc[VINTR]; + rl_quit = old.c_cc[VQUIT]; + + new = old; + new.c_cc[VINTR] = -1; + new.c_cc[VQUIT] = -1; + new.c_lflag &= ~(ECHO | ICANON); + new.c_iflag &= ~(ISTRIP | INPCK); + new.c_cc[VMIN] = 1; + new.c_cc[VTIME] = 0; + (void)ioctl(0, TCSETAW, &new); + } + else + (void)ioctl(0, TCSETAW, &old); +} + +#else +#include + +void +rl_ttyset(Reset) + int Reset; +{ + static struct sgttyb old_sgttyb; + static struct tchars old_tchars; + struct sgttyb new_sgttyb; + struct tchars new_tchars; + + if (Reset == 0) { + (void)ioctl(0, TIOCGETP, &old_sgttyb); + rl_erase = old_sgttyb.sg_erase; + rl_kill = old_sgttyb.sg_kill; + + (void)ioctl(0, TIOCGETC, &old_tchars); + rl_eof = old_tchars.t_eofc; + rl_intr = old_tchars.t_intrc; + rl_quit = old_tchars.t_quitc; + + new_sgttyb = old_sgttyb; + new_sgttyb.sg_flags &= ~ECHO; + new_sgttyb.sg_flags |= RAW; +#if defined(PASS8) + new_sgttyb.sg_flags |= PASS8; +#endif /* defined(PASS8) */ + (void)ioctl(0, TIOCSETP, &new_sgttyb); + + new_tchars = old_tchars; + new_tchars.t_intrc = -1; + new_tchars.t_quitc = -1; + (void)ioctl(0, TIOCSETC, &new_tchars); + } + else { + (void)ioctl(0, TIOCSETP, &old_sgttyb); + (void)ioctl(0, TIOCSETC, &old_tchars); + } +} +#endif /* defined(HAVE_TERMIO) */ +#endif /* defined(HAVE_TCGETATTR) */ + +void +rl_add_slash(path, p) + char *path; + char *p; +{ + struct stat Sb; + + if (stat(path, &Sb) >= 0) + (void)strcat(p, S_ISDIR(Sb.st_mode) ? "/" : " "); +} + diff --git a/js/src/editline/unix.h b/js/src/editline/unix.h new file mode 100644 index 0000000..c99b729 --- /dev/null +++ b/js/src/editline/unix.h @@ -0,0 +1,82 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Simmule Turner and Rich Salz. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or of the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * 1. The authors are not responsible for the consequences of use of this + * software, no matter how awful, even if they arise from flaws in it. + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Since few users ever read sources, + * credits must appear in the documentation. + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. Since few users + * ever read sources, credits must appear in the documentation. + * 4. This notice may not be removed or altered. + */ + + +/* +** Editline system header file for Unix. +*/ + +#define CRLF "\r\n" +#define FORWARD STATIC + +#include +#include + +#if defined(USE_DIRENT) +#include +typedef struct dirent DIRENTRY; +#else +#include +typedef struct direct DIRENTRY; +#endif /* defined(USE_DIRENT) */ + +#if !defined(S_ISDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif /* !defined(S_ISDIR) */ + diff --git a/js/src/find-child.py b/js/src/find-child.py new file mode 100644 index 0000000..4980767 --- /dev/null +++ b/js/src/find-child.py @@ -0,0 +1,69 @@ +#!/usr/bin/python +# +# The output of this script is a splicemap. +# +# A splicemap is used by the mercurial 'convert' extension to direct its +# splicing operation. +# +# The script assumes you already have a destination repository +# containing a conversion somewhere in its history, but that you've +# possibly mixed some new commits on top of that conversion. It outputs +# a splicemap that picks up the conversion where it left off (with the +# first descendant, in the source repo, of the src rev given by --start, +# if or rather the first descendant that would be included by the +# conversion's filemap) and connects them to the current tip of the +# destination repo. +# + +from mercurial import ui, hg +from hgext.convert.filemap import filemapper +from optparse import OptionParser + +import sys + +parser = OptionParser() + +parser.add_option("-s", "--src", dest="src", + help="source repository", metavar="REPO") + +parser.add_option("-d", "--dst", dest="dst", + help="destination repository", metavar="REPO") + +parser.add_option("-t", "--start", dest="start", + help="starting revid in source repository", metavar="REV") + +parser.add_option("-f", "--filemap", dest="filemap", + help="filemap used in conversion", metavar="PATH") + +(options, args) = parser.parse_args() + +if not (options.src and options.dst and options.start): + parser.print_help() + exit(1) + +u = ui.ui() + +src_repo = hg.repository(u, options.src) +dst_repo = hg.repository(u, options.dst) + +fm = None +if options.filemap: + fm = filemapper(u, options.filemap) + +last_converted_src = src_repo[options.start] + +dst_tip = dst_repo.changectx(dst_repo.changelog.tip()).hex() +revs = last_converted_src.children() + +while len(revs) != 0: + tmp = revs + revs = [] + for child in tmp: + for f in child.files(): + if (not fm) or fm(f): + u.write("%s %s\n" % (child.hex(), dst_tip)) + exit(0); + revs.extend(child.children()) + +sys.stderr.write("No candidate child found in source repository\n") +exit(1) diff --git a/js/src/gnuplot/gcTimer.gnu b/js/src/gnuplot/gcTimer.gnu new file mode 100644 index 0000000..9766afa --- /dev/null +++ b/js/src/gnuplot/gcTimer.gnu @@ -0,0 +1,24 @@ +# gnuplot script to visualize GCMETER results. +# usage: "gnuplot gcTimer.gnu >outputfile.png" + +set terminal png +# set Title +set title "Title goes here!" +set datafile missing "-" +set noxtics +set ytics nomirror +set ylabel "Cycles [1E6]" +set y2tics nomirror +set y2label "Chunk count" +set key below +set style data linespoints + +#set data file +plot 'gcTimer.dat' using 2 title columnheader(2), \ +'' u 3 title columnheader(3), \ +'' u 4 title columnheader(4), \ +'' u 5 title columnheader(5) with points, \ +'' u 6 title columnheader(6) with points, \ +'' u 7 title columnheader(7) with points, \ +'' u 8 title columnheader(8) with points axis x1y2, \ +'' u 9 title columnheader(9) with points axis x1y2 diff --git a/js/src/imacro_asm.py b/js/src/imacro_asm.py new file mode 100644 index 0000000..2e85e55 --- /dev/null +++ b/js/src/imacro_asm.py @@ -0,0 +1,467 @@ +#!/usr/bin/env python +# -*- Mode: Python; tab-width: 4; indent-tabs-mode: nil -*- +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the TraceMonkey IMacro Assembler. +# +# The Initial Developer of the Original Code is +# Brendan Eich . +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# An imacro (interpreter-macro) assembler in Python. +# +# Filename suffix conventions, used by Makefile.in rules: +# .jsasm SpiderMonkey JS assembly source, which could be input to other +# assemblers than imacro_asm.js, hence the generic suffix! +# .c.out C source output by imacro_asm.js + +import re +import os + +class Op: + def __init__(self, jsop, opcode, opname, opsrc, oplen, pops, pushes, precedence, flags): + self.jsop = jsop + self.opcode = opcode + self.opname = opname + self.opsrc = opsrc + self.oplen = oplen + self.pops = pops + self.pushes = pushes + self.precedence = precedence + self.flags = flags + +def readFileLines(filename): + f = open(filename) + try: + return f.readlines() + finally: + f.close() + +def load_ops(filename): + opdef_regexp = re.compile(r'''(?x) + ^ OPDEF \( (JSOP_\w+), \s* # op + ([0-9]+), \s* # val + ("[^"]+" | [\w_]+), \s* # name + ("[^"]+" | [\w_]+), \s* # image + (-1|[0-9]+), \s* # len + (-1|[0-9]+), \s* # uses + (-1|[0-9]+), \s* # defs + ([0-9]+), \s* # prec + ([\w_| ]+) \s* # format + \) \s* $''') + + def decode_string_expr(expr): + if expr == 'NULL': + return None + if expr[0] == '"': + assert expr[-1] == '"' + return expr[1:-1] + assert expr.startswith('js_') and expr.endswith('_str') + return expr[3:-4] + + opinfo = [] + for lineno, line in enumerate(readFileLines(filename)): + if line.startswith('OPDEF'): + m = opdef_regexp.match(line) + if m is None: + raise ValueError("OPDEF line of wrong format in jsopcode.tbl at line %d" % (lineno + 1)) + jsop, opcode, opname, opsrc, oplen, pops, pushes, precedence, flags = m.groups() + assert int(opcode) == len(opinfo) + opinfo.append(Op(jsop, int(opcode), decode_string_expr(opname), + decode_string_expr(opsrc), int(oplen), int(pops), int(pushes), + int(precedence), flags.replace(' ', '').split('|'))) + return opinfo + +opinfo = load_ops(os.path.join(os.path.dirname(__file__), "jsopcode.tbl")) +opname2info = dict((info.opname, info) for info in opinfo) +jsop2opcode = dict((info.jsop, info.opcode) for info in opinfo) + +def to_uint8(s): + try: + n = int(s) + except ValueError: + n = -1 + if 0 <= n < (1<<8): + return n + raise ValueError("invalid 8-bit operand: " + s) + +def to_uint16(s): + try: + n = int(s) + except ValueError: + n = -1 + if 0 <= n < (1<<16): + return n + raise ValueError("invalid 16-bit operand: " + s) + +def immediate(op): + info = op.info + imm1Expr = op.imm1.startswith('(') + if 'JOF_ATOM' in info.flags: + if op.imm1 in ('void', 'object', 'function', 'string', 'number', 'boolean'): + return "0, COMMON_TYPE_ATOM_INDEX(JSTYPE_%s)" % op.imm1.upper() + return "0, COMMON_ATOM_INDEX(%s)" % op.imm1 + if 'JOF_JUMP' in info.flags: + assert not imm1Expr + return "%d, %d" % ((op.target >> 8) & 0xff, op.target & 0xff) + if 'JOF_UINT8' in info.flags or 'JOF_INT8' in info.flags: + if imm1Expr: + return op.imm1 + return str(to_uint8(op.imm1)) + if 'JOF_UINT16' in info.flags: + if imm1Expr: + return '(%s & 0xff00) >> 8, (%s & 0xff)' % (op.imm1, op.imm1) + v = to_uint16(op.imm1) + return "%d, %d" % ((v & 0xff00) >> 8, v & 0xff) + raise NotImplementedError(info.jsop + " format not yet implemented") + +def simulate_cfg(igroup, imacro, depth, i): + any_group_opcode = None + expected_depth = None + for opcode in igroup.ops: + opi = opinfo[opcode] + if any_group_opcode is None: + any_group_opcode = opcode + if opi.pops < 0: + expected_depth = None + else: + expected_depth = opi.pushes - opi.pops + elif expected_depth is None: + if opi.pops >= 0: + raise ValueError("imacro shared by constant- and variable-stack-defs/uses instructions") + else: + if opi.pops < 0: + raise ValueError("imacro shared by constant- and variable-stack-defs/uses instructions") + if opi.pushes - opi.pops != expected_depth: + raise ValueError("imacro shared by instructions with different stack depths") + + for i in range(i, len(imacro.code)): + op = imacro.code[i] + opi = op.info + if opi.opname == 'imacop': + opi = opinfo[any_group_opcode] + + if opi.pops < 0: + depth -= 2 + int(op.imm1) + else: + depth -= opi.pops + depth += opi.pushes + + if i in imacro.depths and imacro.depths[i] != depth: + raise ValueError("Mismatched depth at %s:%d" % (imacro.filename, op.line)) + + # Underflowing depth isn't necessarily fatal; most of the imacros + # assume they are called with N>0 args so some assume it's ok to go + # to some depth imacro.maxdepth: + imacro.maxdepth = depth + imacro.depths[i] = depth + + if hasattr(op, "target_index"): + if op.target_index <= i: + raise ValueError("Backward jump at %s:%d" % (imacro.filename, op.line)) + simulate_cfg(igroup, imacro, depth, op.target_index) + if op.info.opname in ('goto', 'gotox'): + return + + if expected_depth is not None and depth != expected_depth: + raise ValueError("Expected depth %d, got %d" % (expected_depth, depth)) + + +# Syntax (spaces are significant only to delimit tokens): +# +# Assembly ::= (Directive? '\n')* +# Directive ::= (name ':')? Operation +# Operation ::= opname Operands? +# Operands ::= Operand (',' Operand)* +# Operand ::= name | number | '(' Expr ')' +# Expr ::= a constant-expression in the C++ language +# containing no parentheses +# +# We simplify given line structure and the maximum of one immediate operand, +# by parsing using split and regexps. For ease of parsing, parentheses are +# banned in an Expr for now, even in quotes or a C++ comment. +# +# Pseudo-ops start with . and include .igroup and .imacro, terminated by .end. +# .imacro must nest in .igroup, neither nests in itself. See imacros.jsasm for +# examples. +# +line_regexp = re.compile(r'''(?x) + ^ + (?: (\w+): )? # optional label at start of line + \s* (\.?\w+) # optional spaces, (pseudo-)opcode + (?: \s+ ([+-]?\w+ | \([^)]*\)) )? # optional first immediate operand + (?: \s+ ([\w,-]+ | \([^)]*\)) )? # optional second immediate operand + (?: \s* (?:\#.*) )? # optional spaces and comment + $''') + +oprange_regexp = re.compile(r'^\w+(?:-\w+)?(?:,\w+(?:-\w+)?)*$') + +class IGroup(object): + def __init__(self, name, ops): + self.name = name + self.ops = ops + self.imacros = [] + +class IMacro(object): + def __init__(self, name, filename): + self.name = name + self.offset = 0 + self.code = [] + self.labeldefs = {} + self.labeldef_indexes = {} + self.labelrefs = {} + self.filename = filename + self.depths = {} + self.initdepth = 0 + +class Instruction(object): + def __init__(self, offset, info, imm1, imm2, lineno): + self.offset = offset + self.info = info + self.imm1 = imm1 + self.imm2 = imm2 + self.lineno = lineno + +def assemble(filename, outfile): + write = outfile.write + igroup = None + imacro = None + opcode2extra = {} + igroups = [] + + write("/* GENERATED BY imacro_asm.js -- DO NOT EDIT!!! */\n") + + def fail(msg, *args): + raise ValueError("%s at %s:%d" % (msg % args, filename, lineno + 1)) + + for lineno, line in enumerate(readFileLines(filename)): + # strip comments + line = re.sub(r'#.*', '', line).rstrip() + if line == "": + continue + m = line_regexp.match(line) + if m is None: + fail(line) + + label, opname, imm1, imm2 = m.groups() + + if opname.startswith('.'): + if label is not None: + fail("invalid label %s before %s" % (label, opname)) + + if opname == '.igroup': + if imm1 is None: + fail("missing .igroup name") + if igroup is not None: + fail("nested .igroup " + imm1) + if oprange_regexp.match(imm2) is None: + fail("invalid igroup operator range " + imm2) + + ops = set() + for current in imm2.split(","): + split = current.split('-') + opcode = jsop2opcode[split[0]] + if len(split) == 1: + lastopcode = opcode + else: + assert len(split) == 2 + lastopcode = jsop2opcode[split[1]] + if opcode >= lastopcode: + fail("invalid opcode range: " + current) + + for opcode in range(opcode, lastopcode + 1): + if opcode in ops: + fail("repeated opcode " + opinfo[opcode].jsop) + ops.add(opcode) + + igroup = IGroup(imm1, ops) + + elif opname == '.imacro': + if igroup is None: + fail(".imacro outside of .igroup") + if imm1 is None: + fail("missing .imacro name") + if imacro: + fail("nested .imacro " + imm1) + imacro = IMacro(imm1, filename) + + elif opname == '.fixup': + if imacro is None: + fail(".fixup outside of .imacro") + if len(imacro.code) != 0: + fail(".fixup must be first item in .imacro") + if imm1 is None: + fail("missing .fixup argument") + try: + fixup = int(imm1) + except ValueError: + fail(".fixup argument must be a nonzero integer") + if fixup == 0: + fail(".fixup argument must be a nonzero integer") + if imacro.initdepth != 0: + fail("more than one .fixup in .imacro") + imacro.initdepth = fixup + + elif opname == '.end': + if imacro is None: + if igroup is None: + fail(".end without prior .igroup or .imacro") + if imm1 is not None and (imm1 != igroup.name or imm2 is not None): + fail(".igroup/.end name mismatch") + + maxdepth = 0 + + write("static struct {\n") + for imacro in igroup.imacros: + write(" jsbytecode %s[%d];\n" % (imacro.name, imacro.offset)) + write("} %s_imacros = {\n" % igroup.name) + + for imacro in igroup.imacros: + depth = 0 + write(" {\n") + for op in imacro.code: + operand = "" + if op.imm1 is not None: + operand = ", " + immediate(op) + write("/*%2d*/ %s%s,\n" % (op.offset, op.info.jsop, operand)) + + imacro.maxdepth = imacro.initdepth + simulate_cfg(igroup, imacro, imacro.initdepth, 0) + if imacro.maxdepth > maxdepth: + maxdepth = imacro.maxdepth + + write(" },\n") + write("};\n") + + for opcode in igroup.ops: + opcode2extra[opcode] = maxdepth + igroups.append(igroup) + igroup = None + else: + assert igroup is not None + + if imm1 is not None and imm1 != imacro.name: + fail(".imacro/.end name mismatch") + + # Backpatch the forward references to labels that must now be defined. + for label in imacro.labelrefs: + if label not in imacro.labeldefs: + fail("label " + label + " used but not defined") + link = imacro.labelrefs[label] + assert link >= 0 + while True: + op = imacro.code[link] + next = op.target + op.target = imacro.labeldefs[label] - op.offset + op.target_index = imacro.labeldef_indexes[label] + if next < 0: + break + link = next + + igroup.imacros.append(imacro) + imacro = None + + else: + fail("unknown pseudo-op " + opname) + continue + + if opname not in opname2info: + fail("unknown opcode " + opname) + + info = opname2info[opname] + if info.oplen == -1: + fail("unimplemented opcode " + opname) + + if imacro is None: + fail("opcode %s outside of .imacro", opname) + + # Blacklist ops that may or must use an atomized double immediate. + if info.opname in ('double', 'lookupswitch', 'lookupswitchx'): + fail(op.opname + " opcode not yet supported") + + if label: + imacro.labeldefs[label] = imacro.offset + imacro.labeldef_indexes[label] = len(imacro.code) + + op = Instruction(imacro.offset, info, imm1, imm2, lineno + 1) + if 'JOF_JUMP' in info.flags: + if imm1 in imacro.labeldefs: + # Backward reference can be resolved right away, no backpatching needed. + op.target = imacro.labeldefs[imm1] - op.offset + op.target_index = imacro.labeldef_indexes[imm1] + else: + # Link op into the .target-linked backpatch chain at labelrefs[imm1]. + # The linked list terminates with a -1 sentinel. + if imm1 in imacro.labelrefs: + op.target = imacro.labelrefs[imm1] + else: + op.target = -1 + imacro.labelrefs[imm1] = len(imacro.code) + + imacro.code.append(op) + imacro.offset += info.oplen + + write("uint8 js_opcode2extra[JSOP_LIMIT] = {\n") + for i in range(len(opinfo)): + write(" %d, /* %s */\n" % (opcode2extra.get(i, 0), opinfo[i].jsop)) + write("};\n") + + write("#define JSOP_IS_IMACOP(x) (0 \\\n") + for i in sorted(opcode2extra): + write(" || x == %s \\\n" % opinfo[i].jsop) + write(")\n") + + write("jsbytecode*\njs_GetImacroStart(jsbytecode* pc) {\n") + for g in igroups: + for m in g.imacros: + start = g.name + "_imacros." + m.name + write(" if (size_t(pc - %s) < %d) return %s;\n" % (start, m.offset, start)) + + write(" return NULL;\n") + write("}\n") + +if __name__ == '__main__': + import sys + if len(sys.argv) != 3: + print "usage: python imacro_asm.py infile.jsasm outfile.c.out" + sys.exit(1) + + f = open(sys.argv[2], 'w') + try: + assemble(sys.argv[1], f) + finally: + f.close() + diff --git a/js/src/imacros.jsasm b/js/src/imacros.jsasm new file mode 100644 index 0000000..798adac --- /dev/null +++ b/js/src/imacros.jsasm @@ -0,0 +1,718 @@ +# -*- indent-tabs-mode: nil; -*- +# vim: set sw=4 ts=8 et tw=78 ft=asm: +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the TraceMonkey IMacro Assembler. +# +# The Initial Developer of the Original Code is +# Brendan Eich . +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +.igroup equality JSOP_EQ-JSOP_NE + + .imacro any_obj # any obj + dup # any obj obj + dup # any obj obj obj + getprop valueOf # any obj obj valueOf + ifprimtop 1 # any obj obj valueOf + swap # any obj valueOf obj + string void # any obj valueOf obj "void" + call 1 # any obj rval + ifprimtop 3 # any obj rval + pop # any obj + dup # any obj obj + goto 2 +1: pop # any obj obj +2: callprop toString # any obj toString obj + call 0 # any obj rval + primtop (JSTYPE_NUMBER) # any obj rval +3: swap # any rval obj + pop # any rval + imacop # eqval + stop + .end + + .imacro obj_any # obj any + swap # any obj + dup # any obj obj + dup # any obj obj obj + getprop valueOf # any obj obj valueOf + ifprimtop 1 # any obj obj valueOf + swap # any obj valueOf obj + string void # any obj valueOf obj "void" + call 1 # any obj lval + ifprimtop 3 # any obj lval + pop # any obj + dup # any obj obj + goto 2 +1: pop # any obj obj +2: callprop toString # any obj toString obj + call 0 # any obj lval + primtop (JSTYPE_NUMBER) # any obj rval +3: swap # any lval obj + pop # any lval + swap # lval any + imacop # eqval + stop + .end + +.end equality + +# A single range, split up like so to test groups over multiple ranges of ops +.igroup binary JSOP_BITOR-JSOP_BITAND,JSOP_EQ-JSOP_DIV,JSOP_MOD + + .imacro any_obj # any obj + dup # any obj obj + dup # any obj obj obj + getprop valueOf # any obj obj valueOf + ifprimtop 1 # any obj obj valueOf + swap # any obj valueOf obj + string number # any obj valueOf obj "number" + call 1 # any obj rval + ifprimtop 3 # any obj rval + pop # any obj + dup # any obj obj + goto 2 +1: pop # any obj obj +2: callprop toString # any obj toString obj + call 0 # any obj rval + primtop (JSTYPE_NUMBER) # any obj rval +3: swap # any rval obj + pop # any rval + imacop # bval + stop + .end + + .imacro obj_any # obj any + swap # any obj + dup # any obj obj + dup # any obj obj obj + getprop valueOf # any obj obj valueOf + ifprimtop 1 # any obj obj valueOf + swap # any obj valueOf obj + string number # any obj valueOf obj "number" + call 1 # any obj lval + ifprimtop 3 # any obj lval + pop # any obj + dup # any obj obj + goto 2 +1: pop # any obj obj +2: callprop toString # any obj toString obj + call 0 # any obj lval + primtop (JSTYPE_NUMBER) # any obj lval +3: swap # any lval obj + pop # any lval + swap # lval any + imacop # bval + stop + .end + + .imacro obj_obj # obj1 obj2 + swap # obj2 obj1 + dup # obj2 obj1 obj1 + dup # obj2 obj1 obj1 obj1 + getprop valueOf # obj2 obj1 obj1 valueOf + ifprimtop 1 # obj2 obj1 obj1 valueOf + swap # obj2 obj1 valueOf obj1 + string number # obj2 obj1 valueOf obj1 "number" + call 1 # obj2 obj1 lval + ifprimtop 3 # obj2 obj1 lval + pop # obj2 obj1 + dup # obj2 obj1 obj1 + goto 2 +1: pop # obj2 obj1 obj1 +2: callprop toString # obj2 obj1 toString obj1 + call 0 # obj2 obj1 lval + primtop (JSTYPE_NUMBER) # obj2 obj1 lval +3: swap # obj2 lval obj1 + pop # obj2 lval + swap # lval obj2 + dup # lval obj1 obj1 + dup # lval obj obj obj + getprop valueOf # lval obj obj valueOf + ifprimtop 4 # lval obj obj valueOf + swap # lval obj valueOf obj + string number # lval obj valueOf obj "number" + call 1 # lval obj rval + ifprimtop 6 # lval obj rval + pop # lval obj + dup # lval obj obj + goto 5 +4: pop # lval obj obj +5: callprop toString # lval obj toString obj + call 0 # lval obj rval + primtop (JSTYPE_NUMBER) # lval obj rval +6: swap # lval rval obj + pop # lval rval + imacop # bval + stop + .end + +.end binary + +.igroup add JSOP_ADD + + .imacro any_obj # any obj + dup # any obj obj + dup # any obj obj obj + getprop valueOf # any obj obj valueOf + ifprimtop 1 # any obj obj valueOf + swap # any obj valueOf obj + string void # any obj valueOf obj "void" + call 1 # any obj rval + ifprimtop 3 # any obj rval + pop # any obj + dup # any obj obj + goto 2 +1: pop # any obj obj +2: callprop toString # any obj toString obj + call 0 # any obj rval + primtop (JSTYPE_VOID) # any obj rval +3: swap # any rval obj + pop # any rval + add # aval + stop + .end + + .imacro obj_any # obj any + swap # any obj + dup # any obj obj + dup # any obj obj obj + getprop valueOf # any obj obj valueOf + ifprimtop 1 # any obj obj valueOf + swap # any obj valueOf obj + string void # any obj valueOf obj "void" + call 1 # any obj lval + ifprimtop 3 # any obj lval + pop # any obj + dup # any obj obj + goto 2 +1: pop # any obj obj +2: callprop toString # any obj toString obj + call 0 # any obj lval + primtop (JSTYPE_VOID) # any obj lval +3: swap # any lval obj + pop # any lval + swap # lval any + add # aval + stop + .end + + .imacro obj_obj # obj1 obj2 + swap # obj2 obj1 + dup # obj2 obj1 obj1 + dup # obj2 obj1 obj1 obj1 + getprop valueOf # obj2 obj1 obj1 valueOf + ifprimtop 1 # obj2 obj1 obj1 valueOf + swap # obj2 obj1 valueOf obj1 + string void # obj2 obj1 valueOf obj1 "void" + call 1 # obj2 obj1 lval + ifprimtop 3 # obj2 obj1 lval + pop # obj2 obj1 + dup # obj2 obj1 obj1 + goto 2 +1: pop # obj2 obj1 obj1 +2: callprop toString # obj2 obj1 toString obj1 + call 0 # obj2 obj1 lval + primtop (JSTYPE_VOID) # obj2 obj1 lval +3: swap # obj2 lval obj1 + pop # obj2 lval + swap # lval obj2 + dup # lval obj obj + dup # lval obj obj obj + getprop valueOf # lval obj obj valueOf + ifprimtop 4 # lval obj obj valueOf + swap # lval obj valueOf obj + string void # lval obj valueOf obj "void" + call 1 # lval obj rval + ifprimtop 6 # lval obj rval + pop # lval obj + dup # lval obj obj + goto 5 +4: pop # lval obj obj +5: callprop toString # lval obj toString obj + call 0 # lval obj rval + primtop (JSTYPE_VOID) # lval obj rval +6: swap # lval rval obj + pop # lval rval + add # aval + stop + .end + +.end add + +.igroup unary JSOP_NEG-JSOP_POS + + .imacro sign # obj + dup # obj obj + dup # obj obj obj + getprop valueOf # obj obj valueOf + ifprimtop 2 # obj obj valueOf + swap # obj valueOf obj + string number # obj valueOf obj "number" + call 1 # obj lval + ifprimtop 1 # obj lval + pop # obj + dup # obj obj + goto 3 +1: swap # lval obj + pop # lval + goto 4 +2: pop # obj obj +3: callprop toString # obj toString obj + call 0 # obj lval + primtop (JSTYPE_NUMBER) # obj lval + swap # lval obj + pop # lval +4: imacop # aval + stop + .end + +.end unary + +.igroup incelem JSOP_INCELEM,JSOP_ELEMINC + .imacro incelem # obj id + dup2 # obj id obj id + getelem # obj id val + pos # obj id n + one # obj id n 1 + add # obj id m + setelem # m + stop + .end + + .imacro eleminc # obj id + dup2 # obj id obj id + getelem # obj id val + pos # obj id n + dup # obj id n n + one # obj id n n 1 + add # obj id n m + pick 3 # id n m obj + pick 3 # n m obj id + pick 2 # n obj id m + setelem # n m + pop # n + stop + .end +.end incelem + +.igroup decelem JSOP_DECELEM,JSOP_ELEMDEC + .imacro decelem # obj id + dup2 # obj id obj id + getelem # obj id val + pos # obj id n + one # obj id n 1 + sub # obj id m + setelem # m + stop + .end + + .imacro elemdec # obj id + dup2 # obj id obj id + getelem # obj id val + pos # obj id n + dup # obj id n n + one # obj id n n 1 + sub # obj id n m + pick 3 # id n m obj + pick 3 # n m obj id + pick 2 # n obj id m + setelem # n m + pop # n + stop + .end +.end decelem + +.igroup call JSOP_CALL + + .imacro String # String this obj + dup # String this obj obj + dup # String this obj obj obj + getprop toString # String this obj obj toString + ifprimtop 1 # String this obj obj toString + swap # String this obj toString obj + call 0 # String this obj rval + ifprimtop 3 # String this obj rval + pop # String this obj + dup # String this obj obj + goto 2 +1: pop # String this obj obj +2: callprop valueOf # String this obj valueOf obj + string string # String this obj valueOf obj "string" + call 1 # String this obj rval + primtop (JSTYPE_STRING) # String this obj rval +3: swap # String this rval obj + pop # String this rval + call 1 # str + stop # str + .end + +.end call + +.igroup new JSOP_NEW + + .imacro String # String this obj + dup # String this obj obj + dup # String this obj obj obj + getprop toString # String this obj obj toString + ifprimtop 1 # String this obj obj toString + swap # String this obj toString obj + call 0 # String this obj rval + ifprimtop 3 # String this obj rval + pop # String this obj + dup # String this obj obj + goto 2 +1: pop # String this obj obj +2: callprop valueOf # String this obj valueOf obj + string string # String this obj valueOf obj "string" + call 1 # String this obj rval + primtop (JSTYPE_STRING) # String this obj rval +3: swap # String this rval obj + pop # String this rval + new 1 # strobj + stop # strobj + .end + +.end new + +.igroup funapply JSOP_FUNAPPLY + + .imacro apply0 # apply fun this arr + pick 3 # fun this arr apply + pop # fun this arr + pop # fun this + call 0 # + stop # + .end # + + .imacro apply1 # apply fun this arr + pick 3 # fun this arr apply + pop # fun this arr + dup # fun this arr arr + zero # fun this arr arr 0 + getelem # fun this arr arg0 + swap # fun this arg0 arr + pop # fun this arg0 + call 1 # + stop # + .end # + + .imacro apply2 # apply fun this arr + pick 3 # fun this arr apply + pop # fun this arr + dup # fun this arr arr + zero # fun this arr arr 0 + getelem # fun this arr arg0 + swap # fun this arg0 arr + dup # fun this arg0 arr arr + one # fun this arg0 arr arr 1 + getelem # fun this arg0 arr arg1 + swap # fun this arg0 arg1 arr + pop # fun this arg0 arg1 + call 2 # + stop # + .end # + + .imacro apply3 # apply fun this arr + pick 3 # fun this arr apply + pop # fun this arr + dup # fun this arr arr + zero # fun this arr arr 0 + getelem # fun this arr arg0 + swap # fun this arg0 arr + dup # fun this arg0 arr arr + one # fun this arg0 arr arr 1 + getelem # fun this arg0 arr arg1 + swap # fun this arg0 arg1 arr + dup # fun this arg0 arg1 arr arr + int8 2 # fun this arg0 arg1 arr arr 2 + getelem # fun this arg0 arg1 arr arg2 + swap # fun this arg0 arg1 arg2 arr + pop # fun this arg0 arg1 arg2 + call 3 # + stop # + .end # + + .imacro apply4 # apply fun this arr + pick 3 # fun this arr apply + pop # fun this arr + dup # fun this arr arr + zero # fun this arr arr 0 + getelem # fun this arr arg0 + swap # fun this arg0 arr + dup # fun this arg0 arr arr + one # fun this arg0 arr arr 1 + getelem # fun this arg0 arr arg1 + swap # fun this arg0 arg1 arr + dup # fun this arg0 arg1 arr arr + int8 2 # fun this arg0 arg1 arr arr 2 + getelem # fun this arg0 arg1 arr arg2 + swap # fun this arg0 arg1 arg2 arr + dup # fun this arg0 arg1 arg2 arr arr + int8 3 # fun this arg0 arg1 arg2 arr arr 3 + getelem # fun this arg0 arg1 arg2 arr arg3 + swap # fun this arg0 arg1 arg2 arg3 arr + pop # fun this arg0 arg1 arg2 arg3 + call 4 # + stop # + .end # + + .imacro apply5 # apply fun this arr + pick 3 # fun this arr apply + pop # fun this arr + dup # fun this arr arr + zero # fun this arr arr 0 + getelem # fun this arr arg0 + swap # fun this arg0 arr + dup # fun this arg0 arr arr + one # fun this arg0 arr arr 1 + getelem # fun this arg0 arr arg1 + swap # fun this arg0 arg1 arr + dup # fun this arg0 arg1 arr arr + int8 2 # fun this arg0 arg1 arr arr 2 + getelem # fun this arg0 arg1 arr arg2 + swap # fun this arg0 arg1 arg2 arr + dup # fun this arg0 arg1 arg2 arr arr + int8 3 # fun this arg0 arg1 arg2 arr arr 3 + getelem # fun this arg0 arg1 arg2 arr arg3 + swap # fun this arg0 arg1 arg2 arg3 arr + dup # fun this arg0 arg1 arg2 arg3 arr arr + int8 4 # fun this arg0 arg1 arg2 arg3 arr arr 4 + getelem # fun this arg0 arg1 arg2 arg3 arr arg4 + swap # fun this arg0 arg1 arg2 arg3 arg4 arr + pop # fun this arg0 arg1 arg2 arg3 arg4 + call 5 # + stop # + .end # + + .imacro apply6 # apply fun this arr + pick 3 # fun this arr apply + pop # fun this arr + dup # fun this arr arr + zero # fun this arr arr 0 + getelem # fun this arr arg0 + swap # fun this arg0 arr + dup # fun this arg0 arr arr + one # fun this arg0 arr arr 1 + getelem # fun this arg0 arr arg1 + swap # fun this arg0 arg1 arr + dup # fun this arg0 arg1 arr arr + int8 2 # fun this arg0 arg1 arr arr 2 + getelem # fun this arg0 arg1 arr arg2 + swap # fun this arg0 arg1 arg2 arr + dup # fun this arg0 arg1 arg2 arr arr + int8 3 # fun this arg0 arg1 arg2 arr arr 3 + getelem # fun this arg0 arg1 arg2 arr arg3 + swap # fun this arg0 arg1 arg2 arg3 arr + dup # fun this arg0 arg1 arg2 arg3 arr arr + int8 4 # fun this arg0 arg1 arg2 arg3 arr arr 4 + getelem # fun this arg0 arg1 arg2 arg3 arr arg4 + swap # fun this arg0 arg1 arg2 arg3 arg4 arr + dup # fun this arg0 arg1 arg2 arg3 arg4 arr arr + int8 5 # fun this arg0 arg1 arg2 arg3 arg4 arr arr 5 + getelem # fun this arg0 arg1 arg2 arg3 arg4 arr arg5 + swap # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr + pop # fun this arg0 arg1 arg2 arg3 arg4 arg5 + call 6 # + stop # + .end # + + .imacro apply7 # apply fun this arr + pick 3 # fun this arr apply + pop # fun this arr + dup # fun this arr arr + zero # fun this arr arr 0 + getelem # fun this arr arg0 + swap # fun this arg0 arr + dup # fun this arg0 arr arr + one # fun this arg0 arr arr 1 + getelem # fun this arg0 arr arg1 + swap # fun this arg0 arg1 arr + dup # fun this arg0 arg1 arr arr + int8 2 # fun this arg0 arg1 arr arr 2 + getelem # fun this arg0 arg1 arr arg2 + swap # fun this arg0 arg1 arg2 arr + dup # fun this arg0 arg1 arg2 arr arr + int8 3 # fun this arg0 arg1 arg2 arr arr 3 + getelem # fun this arg0 arg1 arg2 arr arg3 + swap # fun this arg0 arg1 arg2 arg3 arr + dup # fun this arg0 arg1 arg2 arg3 arr arr + int8 4 # fun this arg0 arg1 arg2 arg3 arr arr 4 + getelem # fun this arg0 arg1 arg2 arg3 arr arg4 + swap # fun this arg0 arg1 arg2 arg3 arg4 arr + dup # fun this arg0 arg1 arg2 arg3 arg4 arr arr + int8 5 # fun this arg0 arg1 arg2 arg3 arg4 arr arr 5 + getelem # fun this arg0 arg1 arg2 arg3 arg4 arr arg5 + swap # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr + dup # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr arr + int8 6 # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr arr 6 + getelem # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr arg6 + swap # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 arr + pop # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 + call 7 # + stop # + .end # + + .imacro apply8 # apply fun this arr + pick 3 # fun this arr apply + pop # fun this arr + dup # fun this arr arr + zero # fun this arr arr 0 + getelem # fun this arr arg0 + swap # fun this arg0 arr + dup # fun this arg0 arr arr + one # fun this arg0 arr arr 1 + getelem # fun this arg0 arr arg1 + swap # fun this arg0 arg1 arr + dup # fun this arg0 arg1 arr arr + int8 2 # fun this arg0 arg1 arr arr 2 + getelem # fun this arg0 arg1 arr arg2 + swap # fun this arg0 arg1 arg2 arr + dup # fun this arg0 arg1 arg2 arr arr + int8 3 # fun this arg0 arg1 arg2 arr arr 3 + getelem # fun this arg0 arg1 arg2 arr arg3 + swap # fun this arg0 arg1 arg2 arg3 arr + dup # fun this arg0 arg1 arg2 arg3 arr arr + int8 4 # fun this arg0 arg1 arg2 arg3 arr arr 4 + getelem # fun this arg0 arg1 arg2 arg3 arr arg4 + swap # fun this arg0 arg1 arg2 arg3 arg4 arr + dup # fun this arg0 arg1 arg2 arg3 arg4 arr arr + int8 5 # fun this arg0 arg1 arg2 arg3 arg4 arr arr 5 + getelem # fun this arg0 arg1 arg2 arg3 arg4 arr arg5 + swap # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr + dup # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr arr + int8 6 # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr arr 6 + getelem # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr arg6 + swap # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 arr + dup # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 arr arr + int8 7 # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 arr arr 7 + getelem # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 arr arg7 + swap # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 arg7 arr + pop # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 arg7 + call 8 # + stop # + .end # + +.end funapply + +.igroup funcall JSOP_FUNCALL + + .imacro call0 # call fun + swap # fun call + pop # fun + null # fun this + call 0 # + stop # + .end # + + .imacro call1 # call fun this + pick 2 # fun this call + pop # fun this + call 0 # + stop # + .end # + + .imacro call2 # call fun this arg0 + pick 3 # fun this arg0 call + pop # fun this arg0 + call 1 # + stop # + .end # + + .imacro call3 # call fun this arg0 arg1 + pick 4 # fun this arg0 arg1 call + pop # fun this arg0 arg1 + call 2 # + stop # + .end # + + .imacro call4 # call fun this arg0 arg1 arg2 + pick 5 # fun this arg0 arg1 arg2 call + pop # fun this arg0 arg1 arg2 + call 3 # + stop # + .end # + + .imacro call5 # call fun this arg0 arg1 arg2 arg3 + pick 6 # fun this arg0 arg1 arg2 arg3 call + pop # fun this arg0 arg1 arg2 arg3 + call 4 # + stop # + .end # + + .imacro call6 # call fun this arg0 arg1 arg2 arg3 arg4 + pick 7 # fun this arg0 arg1 arg2 arg3 arg4 call + pop # fun this arg0 arg1 arg2 arg3 arg4 + call 5 # + stop # + .end # + + .imacro call7 # call fun this arg0 arg1 arg2 arg3 arg4 arg5 + pick 8 # fun this arg0 arg1 arg2 arg3 arg4 arg5 call + pop # fun this arg0 arg1 arg2 arg3 arg4 arg5 + call 6 # + stop # + .end # + + .imacro call8 # call fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 + pick 9 # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 call + pop # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 + call 7 # + stop # + .end # + +.end funcall + +.igroup getprop JSOP_GETPROP + .imacro scriptgetter # obj + .fixup +1 # getter obj + call 0 # val + stop + .end +.end getprop + +.igroup callprop JSOP_CALLPROP + .imacro scriptgetter # obj + .fixup +2 # obj getter obj + call 0 # obj method + swap # method obj + stop + .end +.end callprop + +.igroup getthisprop JSOP_GETTHISPROP,JSOP_GETARGPROP,JSOP_GETLOCALPROP + .imacro scriptgetter # + .fixup +2 # getter obj + call 0 # val + stop + .end +.end getthisprop diff --git a/js/src/javascript-trace.d b/js/src/javascript-trace.d new file mode 100644 index 0000000..9ac12ed --- /dev/null +++ b/js/src/javascript-trace.d @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * Copyright (C) 2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * javascript provider probes + * + * function-entry (filename, classname, funcname) + * function-return (filename, classname, funcname) + * object-create (classname, *object) + * object-finalize (NULL, classname, *object) + * execute-start (filename, lineno) + * execute-done (filename, lineno) + */ + +provider javascript { + probe function__entry(const char *, const char *, const char *); + probe function__return(const char *, const char *, const char *); + /* XXX must use unsigned longs here instead of uintptr_t for OS X + (Apple radar: 5194316 & 5565198) */ + probe object__create(const char *, unsigned long); + probe object__finalize(const char *, const char *, unsigned long); + probe execute__start(const char *, int); + probe execute__done(const char *, int); +}; + +/* +#pragma D attributes Unstable/Unstable/Common provider mozilla provider +#pragma D attributes Private/Private/Unknown provider mozilla module +#pragma D attributes Private/Private/Unknown provider mozilla function +#pragma D attributes Unstable/Unstable/Common provider mozilla name +*/ + diff --git a/js/src/jit-test/README b/js/src/jit-test/README new file mode 100644 index 0000000..ddde38d --- /dev/null +++ b/js/src/jit-test/README @@ -0,0 +1,74 @@ +JS Trace Test Suite + +* PURPOSE + +This is a test suite for testing TraceMonkey. All tests are run in the JS shell +with tracing enabled (-j). + +* REQUIREMENTS + +Python 2.5. This is already a standard requirement for building our tree. + +* RUNNING THE TESTS + +Basic usage: + + python jit_test.py + +The progress bar shows [#tests passed, #tests failed, #tests run] at the left. +If all tests pass, the output is 'PASSED ALL'. The test suite can be interrupted +at any time with Ctrl+C and partial results will be printed. + +To run only the basic tests, not including the slow tests: + + python jit_test.py basic + +For more options: + + python jit_test.py -h + +* CREATING NEW TESTS + +Simply create a JS file under the 'tests/' directory. Most tests should go in +'tests/basic/'. + +All tests are run with 'lib/prolog.js' included first on the command line. The +command line also creates a global variable 'libdir' that is set to the path +of the 'lib' directory. To include a file 'foo.js' from the lib directory in a +test case: + + load(libdir + 'foo.js') + +* TEST METALINES + +The first line of a test case can contain a special comment controlling how the +test is run. For example: + + // |jit-test| allow-oom; + +The general format in EBNF is: + + metaline ::= cookie { item ";" } + cookie ::= "|jit-test|" + item ::= flag | attribute + + flag ::= "slow" | "allow-oom" + + attribute ::= name ":" value + name ::= "TMFLAGS" | "error" + value ::= + +The metaline may appear anywhere in the first line of the file: this allows it +to be placed inside any kind of comment. + +The meaning of the items: + + slow Test runs slowly. Do not run if the --no-slow option is given. + allow-oom If the test runs out of memory, it counts as passing. + valgrind Run test under valgrind. + + error The test should be considered to pass iff it throws the + given JS exception. + TMFLAGS Set the environment variable TMFLAGS to the given value. + +* END diff --git a/js/src/jit-test/jit_test.py b/js/src/jit-test/jit_test.py new file mode 100755 index 0000000..fc27a23 --- /dev/null +++ b/js/src/jit-test/jit_test.py @@ -0,0 +1,463 @@ +#!/usr/bin/env python + +# jit_test.py -- Python harness for JavaScript trace tests. + +import datetime, os, re, sys, tempfile, traceback +import subprocess +from subprocess import * + +DEBUGGER_INFO = { + "gdb": { + "interactive": True, + "args": "-q --args" + }, + + "valgrind": { + "interactive": False, + "args": "--leak-check=full" + } +} + +# Backported from Python 3.1 posixpath.py +def _relpath(path, start=None): + """Return a relative version of a path""" + + if not path: + raise ValueError("no path specified") + + if start is None: + start = os.curdir + + start_list = os.path.abspath(start).split(os.sep) + path_list = os.path.abspath(path).split(os.sep) + + # Work out how much of the filepath is shared by start and path. + i = len(os.path.commonprefix([start_list, path_list])) + + rel_list = [os.pardir] * (len(start_list)-i) + path_list[i:] + if not rel_list: + return os.curdir + return os.path.join(*rel_list) + +os.path.relpath = _relpath + +class Test: + def __init__(self, path): + self.path = path # path to test file + + self.jitflags = [] # jit flags to enable + self.slow = False # True means the test is slow-running + self.allow_oom = False # True means that OOM is not considered a failure + self.valgrind = False # True means run under valgrind + self.tmflags = '' # Value of TMFLAGS env var to pass + self.error = '' # Errors to expect and consider passing + + def copy(self): + t = Test(self.path) + t.jitflags = self.jitflags[:] + t.slow = self.slow + t.allow_oom = self.allow_oom + t.valgrind = self.valgrind + t.tmflags = self.tmflags + t.error = self.error + return t + + COOKIE = '|jit-test|' + + @classmethod + def from_file(cls, path, options): + test = cls(path) + + line = open(path).readline() + i = line.find(cls.COOKIE) + if i != -1: + meta = line[i + len(cls.COOKIE):].strip('\n') + parts = meta.split(';') + for part in parts: + part = part.strip() + if not part: + continue + name, _, value = part.partition(':') + if value: + value = value.strip() + if name == 'TMFLAGS': + test.tmflags = value + elif name == 'error': + test.error = value + else: + print('warning: unrecognized |jit-test| attribute %s'%part) + else: + if name == 'slow': + test.slow = True + elif name == 'allow-oom': + test.allow_oom = True + elif name == 'valgrind': + test.valgrind = options.valgrind + elif name == 'mjitalways': + test.jitflags.append('-a') + elif name == 'debug': + test.jitflags.append('-d') + else: + print('warning: unrecognized |jit-test| attribute %s'%part) + + if options.valgrind_all: + test.valgrind = True + + return test + +def find_tests(dir, substring = None): + ans = [] + for dirpath, dirnames, filenames in os.walk(dir): + dirnames.sort() + filenames.sort() + if dirpath == '.': + continue + for filename in filenames: + if not filename.endswith('.js'): + continue + if filename in ('shell.js', 'browser.js', 'jsref.js'): + continue + test = os.path.join(dirpath, filename) + if substring is None or substring in os.path.relpath(test, dir): + ans.append(test) + return ans + +def get_test_cmd(path, jitflags, lib_dir): + libdir_var = lib_dir + if not libdir_var.endswith('/'): + libdir_var += '/' + expr = "const platform=%r; const libdir=%r;"%(sys.platform, libdir_var) + # We may have specified '-a' or '-d' twice: once via --jitflags, once + # via the "|jit-test|" line. Remove dups because they are toggles. + return [ JS ] + list(set(jitflags)) + [ '-e', expr, '-f', os.path.join(lib_dir, 'prolog.js'), + '-f', path ] + +def run_cmd(cmdline, env): + # close_fds is not supported on Windows and will cause a ValueError. + close_fds = sys.platform != 'win32' + p = Popen(cmdline, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=close_fds, env=env) + out, err = p.communicate() + return out.decode(), err.decode(), p.returncode + +def tmppath(token): + fd, path = tempfile.mkstemp(prefix=token) + os.close(fd) + return path + +def read_and_unlink(path): + f = open(path) + d = f.read() + f.close() + os.unlink(path) + return d + +def run_cmd_avoid_stdio(cmdline, env): + stdoutPath, stderrPath = tmppath('jsstdout'), tmppath('jsstderr') + env['JS_STDOUT'] = stdoutPath + env['JS_STDERR'] = stderrPath + # close_fds is not supported on Windows and will cause a ValueError. + close_fds = sys.platform != 'win32' + p = Popen(cmdline, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=close_fds, env=env) + _, __ = p.communicate() + return read_and_unlink(stdoutPath), read_and_unlink(stderrPath), p.returncode + +def run_test(test, lib_dir): + env = os.environ.copy() + if test.tmflags: + env['TMFLAGS'] = test.tmflags + cmd = get_test_cmd(test.path, test.jitflags, lib_dir) + + if (test.valgrind and + any([os.path.exists(os.path.join(d, 'valgrind')) + for d in os.environ['PATH'].split(os.pathsep)])): + valgrind_prefix = [ 'valgrind', + '-q', + '--smc-check=all', + '--error-exitcode=1', + '--leak-check=full'] + if os.uname()[0] == 'Darwin': + valgrind_prefix += ['--dsymutil=yes'] + cmd = valgrind_prefix + cmd + + if OPTIONS.show_cmd: + print(subprocess.list2cmdline(cmd)) + + if OPTIONS.avoid_stdio: + out, err, code = run_cmd_avoid_stdio(cmd, env) + else: + out, err, code = run_cmd(cmd, env) + + if OPTIONS.show_output: + sys.stdout.write(out) + sys.stdout.write(err) + sys.stdout.write('Exit code: %s\n' % code) + if test.valgrind: + sys.stdout.write(err) + return (check_output(out, err, code, test.allow_oom, test.error), + out, err, code) + +def check_output(out, err, rc, allow_oom, expectedError): + if expectedError: + return expectedError in err + + for line in out.split('\n'): + if line.startswith('Trace stats check failed'): + return False + + for line in err.split('\n'): + if 'Assertion failed:' in line: + return False + + if rc != 0: + # Allow a non-zero exit code if we want to allow OOM, but only if we + # actually got OOM. + return allow_oom and ': out of memory' in err + + return True + +def run_tests(tests, test_dir, lib_dir): + pb = None + if not OPTIONS.hide_progress and not OPTIONS.show_cmd: + try: + from progressbar import ProgressBar + pb = ProgressBar('', len(tests), 16) + except ImportError: + pass + + failures = [] + complete = False + doing = 'before starting' + try: + for i, test in enumerate(tests): + doing = 'on %s'%test.path + ok, out, err, code = run_test(test, lib_dir) + doing = 'after %s'%test.path + + if not ok: + failures.append([ test, out, err, code ]) + + if OPTIONS.tinderbox: + if ok: + print('TEST-PASS | jit_test.py | %s'%test.path) + else: + lines = [ _ for _ in out.split('\n') + err.split('\n') + if _ != '' ] + if len(lines) >= 1: + msg = lines[-1] + else: + msg = '' + print('TEST-UNEXPECTED-FAIL | jit_test.py | %s: %s'% + (test.path, msg)) + + n = i + 1 + if pb: + pb.label = '[%4d|%4d|%4d]'%(n - len(failures), len(failures), n) + pb.update(n) + complete = True + except KeyboardInterrupt: + print('TEST-UNEXPECTED_FAIL | jit_test.py | %s'%test.path) + + if pb: + pb.finish() + + if failures: + if OPTIONS.write_failures: + try: + out = open(OPTIONS.write_failures, 'w') + # Don't write duplicate entries when we are doing multiple failures per job. + written = set() + for test, fout, ferr, fcode in failures: + if test.path not in written: + out.write(os.path.relpath(test.path, test_dir) + '\n') + if OPTIONS.write_failure_output: + out.write(fout) + out.write(ferr) + out.write('Exit code: ' + str(fcode) + "\n") + written.add(test.path) + out.close() + except IOError: + sys.stderr.write("Exception thrown trying to write failure file '%s'\n"% + OPTIONS.write_failures) + traceback.print_exc() + sys.stderr.write('---\n') + + print('FAILURES:') + for test, _, __, ___ in failures: + if OPTIONS.show_failed: + print(' ' + subprocess.list2cmdline(get_test_cmd(test.path, test.jitflags, lib_dir))) + else: + print(' ' + ' '.join(test.jitflags + [ test.path ])) + return False + else: + print('PASSED ALL' + ('' if complete else ' (partial run -- interrupted by user %s)'%doing)) + return True + +def parse_jitflags(): + jitflags = [ [ '-' + flag for flag in flags ] + for flags in OPTIONS.jitflags.split(',') ] + for flags in jitflags: + for flag in flags: + if flag not in ('-j', '-m', '-a', '-p', '-d'): + print('Invalid jit flag: "%s"'%flag) + sys.exit(1) + return jitflags + +def platform_might_be_android(): + try: + # The python package for SL4A provides an |android| module. + # If that module is present, we're likely in SL4A-python on + # device. False positives and negatives are possible, + # however. + import android + return True + except ImportError: + return False + +def stdio_might_be_broken(): + return platform_might_be_android() + +JS = None +OPTIONS = None +def main(argv): + global JS, OPTIONS + + script_path = os.path.abspath(__file__) + script_dir = os.path.dirname(script_path) + test_dir = os.path.join(script_dir, 'tests') + lib_dir = os.path.join(script_dir, 'lib') + + # The [TESTS] optional arguments are paths of test files relative + # to the jit-test/tests directory. + + from optparse import OptionParser + op = OptionParser(usage='%prog [options] JS_SHELL [TESTS]') + op.add_option('-s', '--show-cmd', dest='show_cmd', action='store_true', + help='show js shell command run') + op.add_option('-f', '--show-failed-cmd', dest='show_failed', + action='store_true', help='show command lines of failed tests') + op.add_option('-o', '--show-output', dest='show_output', action='store_true', + help='show output from js shell') + op.add_option('-x', '--exclude', dest='exclude', action='append', + help='exclude given test dir or path') + op.add_option('--no-slow', dest='run_slow', action='store_false', + help='do not run tests marked as slow') + op.add_option('--no-progress', dest='hide_progress', action='store_true', + help='hide progress bar') + op.add_option('--tinderbox', dest='tinderbox', action='store_true', + help='Tinderbox-parseable output format') + op.add_option('-w', '--write-failures', dest='write_failures', metavar='FILE', + help='Write a list of failed tests to [FILE]') + op.add_option('-r', '--read-tests', dest='read_tests', metavar='FILE', + help='Run test files listed in [FILE]') + op.add_option('-R', '--retest', dest='retest', metavar='FILE', + help='Retest using test list file [FILE]') + op.add_option('-g', '--debug', dest='debug', action='store_true', + help='Run test in gdb') + op.add_option('--valgrind', dest='valgrind', action='store_true', + help='Enable the |valgrind| flag, if valgrind is in $PATH.') + op.add_option('--valgrind-all', dest='valgrind_all', action='store_true', + help='Run all tests with valgrind, if valgrind is in $PATH.') + op.add_option('--jitflags', dest='jitflags', default='mjp', + help='Example: --jitflags=j,mj,mjp to run each test with -j, -m -j, -m -j -p [default=%default]') + op.add_option('--avoid-stdio', dest='avoid_stdio', action='store_true', + help='Use js-shell file indirection instead of piping stdio.') + op.add_option('--write-failure-output', dest='write_failure_output', action='store_true', + help='With --write-failures=FILE, additionally write the output of failed tests to [FILE]') + (OPTIONS, args) = op.parse_args(argv) + if len(args) < 1: + op.error('missing JS_SHELL argument') + # We need to make sure we are using backslashes on Windows. + JS, test_args = os.path.normpath(args[0]), args[1:] + JS = os.path.realpath(JS) # Burst through the symlinks! + + if stdio_might_be_broken(): + # Prefer erring on the side of caution and not using stdio if + # it might be broken on this platform. The file-redirect + # fallback should work on any platform, so at worst by + # guessing wrong we might have slowed down the tests a bit. + # + # XXX technically we could check for broken stdio, but it + # really seems like overkill. + OPTIONS.avoid_stdio = True + + if OPTIONS.retest: + OPTIONS.read_tests = OPTIONS.retest + OPTIONS.write_failures = OPTIONS.retest + + test_list = [] + read_all = True + + if test_args: + read_all = False + for arg in test_args: + test_list += find_tests(test_dir, arg) + + if OPTIONS.read_tests: + read_all = False + try: + f = open(OPTIONS.read_tests) + for line in f: + test_list.append(os.path.join(test_dir, line.strip('\n'))) + f.close() + except IOError: + if OPTIONS.retest: + read_all = True + else: + sys.stderr.write("Exception thrown trying to read test file '%s'\n"% + OPTIONS.read_tests) + traceback.print_exc() + sys.stderr.write('---\n') + + if read_all: + test_list = find_tests(test_dir) + + if OPTIONS.exclude: + exclude_list = [] + for exclude in OPTIONS.exclude: + exclude_list += find_tests(test_dir, exclude) + test_list = [ test for test in test_list if test not in set(exclude_list) ] + + if not test_list: + print >> sys.stderr, "No tests found matching command line arguments." + sys.exit(0) + + test_list = [ Test.from_file(_, OPTIONS) for _ in test_list ] + + if not OPTIONS.run_slow: + test_list = [ _ for _ in test_list if not _.slow ] + + # The full test list is ready. Now create copies for each JIT configuration. + job_list = [] + jitflags_list = parse_jitflags() + for test in test_list: + for jitflags in jitflags_list: + new_test = test.copy() + new_test.jitflags.extend(jitflags) + job_list.append(new_test) + + + if OPTIONS.debug: + if len(job_list) > 1: + print('Multiple tests match command line arguments, debugger can only run one') + for tc in job_list: + print(' %s'%tc.path) + sys.exit(1) + + tc = job_list[0] + cmd = [ 'gdb', '--args' ] + get_test_cmd(tc.path, tc.jitflags, lib_dir) + call(cmd) + sys.exit() + + try: + ok = run_tests(job_list, test_dir, lib_dir) + if not ok: + sys.exit(2) + except OSError: + if not os.path.exists(JS): + print >> sys.stderr, "JS shell argument: file does not exist: '%s'"%JS + sys.exit(1) + else: + raise + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/js/src/jit-test/lib/andTestHelper.js b/js/src/jit-test/lib/andTestHelper.js new file mode 100644 index 0000000..e8a29af --- /dev/null +++ b/js/src/jit-test/lib/andTestHelper.js @@ -0,0 +1,9 @@ +function andTestHelper(a, b, n) +{ + var k = 0; + for (var i = 0; i < n; i++) { + if (a && b) + k += i; + } + return k; +} diff --git a/js/src/jit-test/lib/array-compare.js b/js/src/jit-test/lib/array-compare.js new file mode 100644 index 0000000..b72dea0 --- /dev/null +++ b/js/src/jit-test/lib/array-compare.js @@ -0,0 +1,24 @@ +// Library file for tests to load. + +function SameValue(v1, v2) +{ + if (v1 === 0 && v2 === 0) + return 1 / v1 === 1 / v2; + if (v1 !== v1 && v2 !== v2) + return true; + return v1 === v2; +} + +function arraysEqual(a1, a2) +{ + var len1 = a1.length, len2 = a2.length; + if (len1 !== len2) + return false; + for (var i = 0; i < len1; i++) + { + if (!SameValue(a1[i], a2[i])) + return false; + } + return true; +} + diff --git a/js/src/jit-test/lib/eqArrayHelper.js b/js/src/jit-test/lib/eqArrayHelper.js new file mode 100644 index 0000000..3fa521f --- /dev/null +++ b/js/src/jit-test/lib/eqArrayHelper.js @@ -0,0 +1,17 @@ +function assertEqArray(actual, expected) { + if (actual.length != expected.length) { + throw new Error( + "array lengths not equal: got " + + uneval(actual) + ", expected " + uneval(expected)); + } + + for (var i = 0; i < actual.length; ++i) { + if (actual[i] != expected[i]) { + throw new Error( + "arrays not equal at element " + i + ": got " + + uneval(actual) + ", expected " + uneval(expected)); + } + } +} + + diff --git a/js/src/jit-test/lib/mandelbrot-results.js b/js/src/jit-test/lib/mandelbrot-results.js new file mode 100644 index 0000000..8c4e133 --- /dev/null +++ b/js/src/jit-test/lib/mandelbrot-results.js @@ -0,0 +1,3 @@ +var mandelbrotNoImageDataResult = "[[[60, 300, 1, 1], [61, 300, 1, 1], [62, 300, 1, 1], [63, 300, 1, 1], [64, 300, 1, 1], [65, 298, 1, 5], [66, 297, 1, 7], [67, 298, 1, 5], [68, 299, 1, 1], [68, 301, 1, 1], [78, 300, 1, 1], [91, 300, 1, 1], [92, 300, 1, 1], [107, 300, 1, 1], [110, 300, 1, 1], [111, 300, 1, 1], [112, 300, 1, 1], [113, 300, 1, 1], [114, 300, 1, 1], [115, 300, 1, 1], [116, 300, 1, 1], [117, 300, 1, 1], [118, 300, 1, 1], [119, 300, 1, 1], [120, 300, 1, 1], [121, 300, 1, 1], [122, 300, 1, 1], [123, 300, 1, 1], [124, 300, 1, 1], [125, 300, 1, 1], [126, 300, 1, 1], [127, 300, 1, 1], [128, 300, 1, 1], [129, 300, 1, 1], [130, 300, 1, 1], [131, 300, 1, 1], [132, 300, 1, 1], [133, 300, 1, 1], [134, 300, 1, 1], [135, 300, 1, 1], [136, 300, 1, 1], [137, 299, 1, 3], [138, 298, 1, 5], [139, 297, 1, 7], [140, 298, 1, 5], [141, 298, 1, 5], [142, 295, 1, 11], [143, 293, 1, 15], [144, 293, 1, 15], [145, 289, 1, 1], [145, 291, 1, 19], [145, 311, 1, 1], [146, 288, 1, 25], [147, 288, 1, 25], [148, 290, 1, 21], [149, 289, 1, 23], [150, 288, 1, 25], [151, 289, 1, 23], [152, 287, 1, 27], [153, 287, 1, 27], [154, 288, 1, 25], [155, 288, 1, 25], [156, 288, 1, 25], [157, 288, 1, 25], [158, 289, 1, 23], [159, 290, 1, 21], [160, 290, 1, 21], [161, 291, 1, 19], [162, 293, 1, 15], [163, 224, 1, 1], [163, 294, 1, 13], [163, 376, 1, 1], [164, 296, 1, 9], [165, 286, 1, 1], [165, 288, 1, 1], [165, 291, 1, 19], [165, 312, 1, 1], [165, 314, 1, 1], [166, 282, 1, 2], [166, 285, 1, 31], [166, 317, 1, 2], [167, 268, 1, 1], [167, 277, 1, 2], [167, 282, 1, 37], [167, 322, 1, 2], [167, 332, 1, 1], [168, 276, 1, 49], [169, 267, 1, 1], [169, 269, 1, 1], [169, 271, 1, 1], [169, 277, 1, 47], [169, 329, 1, 1], [169, 331, 1, 1], [169, 333, 1, 1], [170, 268, 1, 3], [170, 274, 1, 53], [170, 330, 1, 3], [171, 268, 1, 4], [171, 273, 1, 1], [171, 275, 1, 51], [171, 327, 1, 1], [171, 329, 1, 4], [172, 268, 1, 4], [172, 273, 1, 55], [172, 329, 1, 4], [173, 266, 1, 1], [173, 268, 1, 65], [173, 334, 1, 1], [174, 268, 1, 65], [175, 268, 1, 65], [176, 263, 1, 1], [176, 267, 1, 67], [176, 337, 1, 1], [177, 239, 1, 1], [177, 261, 1, 1], [177, 267, 1, 67], [177, 339, 1, 1], [177, 361, 1, 1], [178, 263, 1, 75], [179, 251, 1, 1], [179, 263, 1, 75], [179, 349, 1, 1], [180, 246, 1, 1], [180, 251, 1, 2], [180, 262, 1, 77], [180, 348, 1, 2], [180, 354, 1, 1], [181, 250, 1, 6], [181, 261, 1, 79], [181, 345, 1, 6], [182, 246, 1, 1], [182, 249, 1, 8], [182, 260, 1, 1], [182, 262, 1, 77], [182, 340, 1, 1], [182, 344, 1, 8], [182, 354, 1, 1], [183, 245, 1, 13], [183, 261, 1, 79], [183, 343, 1, 13], [184, 245, 1, 13], [184, 259, 1, 83], [184, 343, 1, 13], [185, 246, 1, 12], [185, 259, 1, 83], [185, 343, 1, 12], [186, 247, 1, 11], [186, 259, 1, 83], [186, 343, 1, 11], [187, 246, 1, 109], [188, 247, 1, 107], [189, 247, 1, 107], [190, 247, 1, 1], [190, 249, 1, 103], [190, 353, 1, 1], [191, 249, 1, 6], [191, 256, 1, 89], [191, 346, 1, 6], [192, 250, 1, 1], [192, 255, 1, 91], [192, 350, 1, 1], [193, 255, 1, 91], [194, 253, 1, 95], [195, 252, 1, 1], [195, 254, 1, 93], [195, 348, 1, 1], [196, 253, 1, 95], [197, 253, 1, 95], [198, 252, 1, 97], [199, 252, 1, 97], [200, 248, 1, 1], [200, 250, 1, 1], [200, 252, 1, 97], [200, 350, 1, 1], [200, 352, 1, 1], [201, 247, 1, 1], [201, 250, 1, 101], [201, 353, 1, 1], [202, 247, 1, 107], [203, 249, 1, 103], [204, 250, 1, 101], [205, 249, 1, 1], [205, 251, 1, 99], [205, 351, 1, 1], [206, 249, 1, 103], [207, 250, 1, 101], [208, 250, 1, 101], [209, 250, 1, 101], [210, 243, 1, 1], [210, 245, 1, 4], [210, 250, 1, 101], [210, 352, 1, 4], [210, 357, 1, 1], [211, 245, 1, 111], [212, 243, 1, 115], [213, 243, 1, 115], [214, 243, 1, 115], [215, 242, 1, 1], [215, 245, 1, 111], [215, 358, 1, 1], [216, 247, 1, 2], [216, 250, 1, 101], [216, 352, 1, 2], [217, 247, 1, 1], [217, 250, 1, 101], [217, 353, 1, 1], [218, 250, 1, 101], [219, 249, 1, 103], [220, 248, 1, 1], [220, 250, 1, 101], [220, 352, 1, 1], [221, 247, 1, 1], [221, 250, 1, 101], [221, 353, 1, 1], [222, 249, 1, 103], [223, 251, 1, 99], [224, 250, 1, 101], [225, 251, 1, 99], [226, 250, 1, 1], [226, 252, 1, 97], [226, 350, 1, 1], [227, 248, 1, 1], [227, 250, 1, 101], [227, 352, 1, 1], [228, 249, 1, 103], [229, 248, 1, 105], [230, 248, 1, 1], [230, 250, 1, 101], [230, 352, 1, 1], [231, 254, 1, 93], [232, 254, 1, 93], [233, 251, 1, 1], [233, 254, 1, 93], [233, 349, 1, 1], [234, 253, 1, 95], [235, 256, 1, 89], [236, 255, 1, 91], [237, 254, 1, 93], [238, 254, 1, 3], [238, 258, 1, 85], [238, 344, 1, 3], [239, 254, 1, 3], [239, 258, 1, 85], [239, 344, 1, 3], [240, 253, 1, 1], [240, 259, 1, 83], [240, 347, 1, 1], [241, 258, 1, 85], [242, 260, 1, 81], [243, 258, 1, 1], [243, 260, 1, 81], [243, 342, 1, 1], [244, 259, 1, 83], [245, 259, 1, 1], [245, 263, 1, 75], [245, 341, 1, 1], [246, 262, 1, 77], [247, 264, 1, 73], [248, 262, 1, 1], [248, 264, 1, 1], [248, 266, 1, 69], [248, 336, 1, 1], [248, 338, 1, 1], [249, 266, 1, 69], [250, 266, 1, 69], [251, 266, 1, 69], [252, 270, 1, 61], [253, 270, 1, 1], [253, 272, 1, 57], [253, 330, 1, 1], [254, 272, 1, 57], [255, 274, 1, 53], [256, 274, 1, 1], [256, 276, 1, 49], [256, 326, 1, 1], [257, 276, 1, 1], [257, 278, 1, 45], [257, 324, 1, 1], [258, 279, 1, 1], [258, 281, 1, 39], [258, 321, 1, 1], [259, 283, 1, 35], [260, 287, 1, 27], [261, 294, 1, 13], [262, 263, 1, 1], [262, 275, 1, 1], [262, 277, 1, 1], [262, 280, 1, 41], [262, 323, 1, 1], [262, 325, 1, 1], [262, 337, 1, 1], [263, 264, 1, 1], [263, 266, 1, 2], [263, 269, 1, 1], [263, 273, 1, 1], [263, 275, 1, 51], [263, 327, 1, 1], [263, 331, 1, 1], [263, 333, 1, 2], [263, 336, 1, 1], [264, 258, 1, 1], [264, 266, 1, 3], [264, 270, 1, 1], [264, 272, 1, 57], [264, 330, 1, 1], [264, 332, 1, 3], [264, 342, 1, 1], [265, 251, 1, 1], [265, 262, 1, 3], [265, 267, 1, 67], [265, 336, 1, 3], [265, 349, 1, 1], [266, 251, 1, 2], [266, 257, 1, 3], [266, 261, 1, 1], [266, 263, 1, 75], [266, 339, 1, 1], [266, 341, 1, 3], [266, 348, 1, 2], [267, 243, 1, 2], [267, 251, 1, 4], [267, 258, 1, 85], [267, 346, 1, 4], [267, 356, 1, 2], [268, 243, 1, 2], [268, 250, 1, 5], [268, 256, 1, 89], [268, 346, 1, 5], [268, 356, 1, 2], [269, 238, 1, 1], [269, 243, 1, 2], [269, 246, 1, 1], [269, 251, 1, 99], [269, 354, 1, 1], [269, 356, 1, 2], [269, 362, 1, 1], [270, 241, 1, 1], [270, 243, 1, 3], [270, 249, 1, 103], [270, 355, 1, 3], [270, 359, 1, 1], [271, 230, 1, 1], [271, 242, 1, 4], [271, 248, 1, 105], [271, 355, 1, 4], [271, 370, 1, 1], [272, 225, 1, 1], [272, 232, 1, 1], [272, 242, 1, 4], [272, 247, 1, 107], [272, 355, 1, 4], [272, 368, 1, 1], [272, 375, 1, 1], [273, 231, 1, 3], [273, 238, 1, 2], [273, 244, 1, 113], [273, 361, 1, 2], [273, 367, 1, 3], [274, 230, 1, 5], [274, 239, 1, 123], [274, 366, 1, 5], [275, 212, 1, 1], [275, 230, 1, 6], [275, 237, 1, 1], [275, 239, 1, 123], [275, 363, 1, 1], [275, 365, 1, 6], [275, 388, 1, 1], [276, 228, 1, 1], [276, 230, 1, 6], [276, 238, 1, 125], [276, 365, 1, 6], [276, 372, 1, 1], [277, 230, 1, 141], [278, 209, 1, 1], [278, 231, 1, 139], [278, 391, 1, 1], [279, 210, 1, 1], [279, 233, 1, 135], [279, 390, 1, 1], [280, 213, 1, 1], [280, 225, 1, 1], [280, 228, 1, 145], [280, 375, 1, 1], [280, 387, 1, 1], [281, 209, 1, 1], [281, 211, 1, 3], [281, 215, 1, 2], [281, 225, 1, 2], [281, 228, 1, 145], [281, 374, 1, 2], [281, 384, 1, 2], [281, 387, 1, 3], [281, 391, 1, 1], [282, 209, 1, 1], [282, 211, 1, 7], [282, 225, 1, 151], [282, 383, 1, 7], [282, 391, 1, 1], [283, 212, 1, 9], [283, 225, 1, 151], [283, 380, 1, 9], [284, 211, 1, 9], [284, 223, 1, 1], [284, 225, 1, 151], [284, 377, 1, 1], [284, 381, 1, 9], [285, 207, 1, 2], [285, 211, 1, 9], [285, 222, 1, 157], [285, 381, 1, 9], [285, 392, 1, 2], [286, 210, 1, 10], [286, 221, 1, 159], [286, 381, 1, 10], [287, 210, 1, 10], [287, 221, 1, 159], [287, 381, 1, 10], [288, 211, 1, 179], [289, 211, 1, 179], [290, 213, 1, 3], [290, 217, 1, 167], [290, 385, 1, 3], [291, 214, 1, 173], [292, 212, 1, 177], [293, 209, 1, 183], [294, 210, 1, 1], [294, 212, 1, 177], [294, 390, 1, 1], [295, 210, 1, 181], [296, 204, 1, 193], [297, 204, 1, 193], [298, 203, 1, 195], [299, 189, 1, 1], [299, 205, 1, 191], [299, 411, 1, 1], [300, 188, 1, 3], [300, 204, 1, 193], [300, 410, 1, 3], [301, 180, 1, 1], [301, 183, 1, 1], [301, 185, 1, 2], [301, 188, 1, 3], [301, 200, 1, 2], [301, 204, 1, 193], [301, 399, 1, 2], [301, 410, 1, 3], [301, 414, 1, 2], [301, 417, 1, 1], [301, 420, 1, 1], [302, 177, 1, 5], [302, 184, 1, 10], [302, 200, 1, 1], [302, 202, 1, 197], [302, 400, 1, 1], [302, 407, 1, 10], [302, 419, 1, 5], [303, 178, 1, 15], [303, 203, 1, 195], [303, 408, 1, 15], [304, 178, 1, 17], [304, 199, 1, 2], [304, 202, 1, 197], [304, 400, 1, 2], [304, 406, 1, 17], [305, 179, 1, 16], [305, 200, 1, 201], [305, 406, 1, 16], [306, 180, 1, 16], [306, 198, 1, 205], [306, 405, 1, 16], [307, 179, 1, 17], [307, 198, 1, 205], [307, 405, 1, 17], [308, 180, 1, 16], [308, 197, 1, 207], [308, 405, 1, 16], [309, 179, 1, 17], [309, 197, 1, 207], [309, 405, 1, 17], [310, 180, 1, 241], [311, 180, 1, 15], [311, 196, 1, 209], [311, 406, 1, 15], [312, 179, 1, 243], [313, 177, 1, 1], [313, 179, 1, 243], [313, 423, 1, 1], [314, 181, 1, 239], [315, 182, 1, 237], [316, 180, 1, 1], [316, 183, 1, 8], [316, 192, 1, 217], [316, 410, 1, 8], [316, 420, 1, 1], [317, 185, 1, 1], [317, 188, 1, 1], [317, 191, 1, 219], [317, 412, 1, 1], [317, 415, 1, 1], [318, 189, 1, 223], [319, 189, 1, 223], [320, 186, 1, 2], [320, 189, 1, 223], [320, 413, 1, 2], [321, 187, 1, 1], [321, 189, 1, 223], [321, 413, 1, 1], [322, 185, 1, 1], [322, 188, 1, 225], [322, 415, 1, 1], [323, 185, 1, 231], [324, 185, 1, 231], [325, 180, 1, 1], [325, 183, 1, 1], [325, 185, 1, 231], [325, 417, 1, 1], [325, 420, 1, 1], [326, 180, 1, 1], [326, 182, 1, 2], [326, 185, 1, 231], [326, 417, 1, 2], [326, 420, 1, 1], [327, 182, 1, 237], [328, 182, 1, 237], [329, 183, 1, 235], [330, 182, 1, 237], [331, 176, 1, 1], [331, 180, 1, 1], [331, 183, 1, 235], [331, 420, 1, 1], [331, 424, 1, 1], [332, 174, 1, 1], [332, 181, 1, 239], [332, 426, 1, 1], [333, 176, 1, 1], [333, 180, 1, 241], [333, 424, 1, 1], [334, 175, 1, 4], [334, 181, 1, 239], [334, 422, 1, 4], [335, 171, 1, 259], [336, 172, 1, 257], [337, 171, 1, 1], [337, 174, 1, 253], [337, 429, 1, 1], [338, 173, 1, 255], [339, 174, 1, 253], [340, 172, 1, 1], [340, 175, 1, 3], [340, 179, 1, 243], [340, 423, 1, 3], [340, 428, 1, 1], [341, 178, 1, 245], [342, 176, 1, 1], [342, 178, 1, 245], [342, 424, 1, 1], [343, 176, 1, 249], [344, 174, 1, 1], [344, 176, 1, 249], [344, 426, 1, 1], [345, 176, 1, 249], [346, 176, 1, 249], [347, 172, 1, 1], [347, 175, 1, 251], [347, 428, 1, 1], [348, 172, 1, 3], [348, 176, 1, 249], [348, 426, 1, 3], [349, 169, 1, 263], [350, 169, 1, 1], [350, 172, 1, 257], [350, 431, 1, 1], [351, 172, 1, 257], [352, 174, 1, 253], [353, 173, 1, 255], [354, 172, 1, 1], [354, 174, 1, 253], [354, 428, 1, 1], [355, 169, 1, 1], [355, 173, 1, 255], [355, 431, 1, 1], [356, 169, 1, 1], [356, 172, 1, 257], [356, 431, 1, 1], [357, 169, 1, 1], [357, 171, 1, 259], [357, 431, 1, 1], [358, 148, 1, 1], [358, 169, 1, 263], [358, 452, 1, 1], [359, 173, 1, 255], [360, 171, 1, 259], [361, 150, 1, 1], [361, 171, 1, 259], [361, 450, 1, 1], [362, 137, 1, 1], [362, 149, 1, 3], [362, 170, 1, 261], [362, 449, 1, 3], [362, 463, 1, 1], [363, 138, 1, 2], [363, 149, 1, 4], [363, 156, 1, 2], [363, 160, 1, 1], [363, 170, 1, 261], [363, 440, 1, 1], [363, 443, 1, 2], [363, 448, 1, 4], [363, 461, 1, 2], [364, 138, 1, 3], [364, 145, 1, 1], [364, 147, 1, 1], [364, 149, 1, 6], [364, 156, 1, 2], [364, 171, 1, 259], [364, 443, 1, 2], [364, 446, 1, 6], [364, 453, 1, 1], [364, 455, 1, 1], [364, 460, 1, 3], [365, 137, 1, 5], [365, 144, 1, 15], [365, 160, 1, 2], [365, 163, 1, 1], [365, 171, 1, 259], [365, 437, 1, 1], [365, 439, 1, 2], [365, 442, 1, 15], [365, 459, 1, 5], [366, 137, 1, 24], [366, 171, 1, 259], [366, 440, 1, 24], [367, 137, 1, 25], [367, 163, 1, 1], [367, 171, 1, 259], [367, 437, 1, 1], [367, 439, 1, 25], [368, 80, 1, 1], [368, 137, 1, 1], [368, 140, 1, 25], [368, 170, 1, 261], [368, 436, 1, 25], [368, 463, 1, 1], [368, 520, 1, 1], [369, 138, 1, 28], [369, 170, 1, 261], [369, 435, 1, 28], [370, 136, 1, 31], [370, 170, 1, 261], [370, 434, 1, 31], [371, 133, 1, 1], [371, 137, 1, 30], [371, 170, 1, 261], [371, 434, 1, 30], [371, 467, 1, 1], [372, 133, 1, 2], [372, 136, 1, 32], [372, 170, 1, 261], [372, 433, 1, 32], [372, 466, 1, 2], [373, 134, 1, 34], [373, 170, 1, 261], [373, 433, 1, 34], [374, 135, 1, 34], [374, 170, 1, 261], [374, 432, 1, 34], [375, 94, 1, 1], [375, 134, 1, 35], [375, 170, 1, 261], [375, 432, 1, 35], [375, 506, 1, 1], [376, 93, 1, 2], [376, 132, 1, 337], [376, 506, 1, 2], [377, 93, 1, 1], [377, 133, 1, 37], [377, 171, 1, 259], [377, 431, 1, 37], [377, 507, 1, 1], [378, 133, 1, 37], [378, 171, 1, 259], [378, 431, 1, 37], [379, 132, 1, 337], [380, 126, 1, 5], [380, 133, 1, 335], [380, 470, 1, 5], [381, 125, 1, 7], [381, 133, 1, 335], [381, 469, 1, 7], [382, 125, 1, 7], [382, 133, 1, 335], [382, 469, 1, 7], [383, 123, 1, 355], [384, 122, 1, 1], [384, 124, 1, 353], [384, 478, 1, 1], [385, 121, 1, 359], [386, 115, 1, 1], [386, 122, 1, 48], [386, 171, 1, 259], [386, 431, 1, 48], [386, 485, 1, 1], [387, 125, 1, 7], [387, 133, 1, 335], [387, 469, 1, 7], [388, 125, 1, 6], [388, 134, 1, 36], [388, 171, 1, 259], [388, 431, 1, 36], [388, 470, 1, 6], [389, 126, 1, 1], [389, 128, 1, 1], [389, 130, 1, 1], [389, 133, 1, 335], [389, 470, 1, 1], [389, 472, 1, 1], [389, 474, 1, 1], [390, 125, 1, 1], [390, 133, 1, 36], [390, 170, 1, 261], [390, 432, 1, 36], [390, 475, 1, 1], [391, 135, 1, 34], [391, 170, 1, 261], [391, 432, 1, 34], [392, 106, 1, 1], [392, 134, 1, 35], [392, 171, 1, 259], [392, 432, 1, 35], [392, 494, 1, 1], [393, 136, 1, 31], [393, 170, 1, 261], [393, 434, 1, 31], [394, 135, 1, 33], [394, 171, 1, 259], [394, 433, 1, 33], [395, 135, 1, 30], [395, 170, 1, 261], [395, 436, 1, 30], [396, 136, 1, 1], [396, 139, 1, 26], [396, 170, 1, 261], [396, 436, 1, 26], [396, 464, 1, 1], [397, 138, 1, 1], [397, 140, 1, 25], [397, 171, 1, 259], [397, 436, 1, 25], [397, 462, 1, 1], [398, 103, 1, 1], [398, 142, 1, 20], [398, 164, 1, 1], [398, 170, 1, 261], [398, 436, 1, 1], [398, 439, 1, 20], [398, 497, 1, 1], [399, 140, 1, 20], [399, 161, 1, 1], [399, 171, 1, 259], [399, 439, 1, 1], [399, 441, 1, 20], [400, 140, 1, 5], [400, 146, 1, 13], [400, 169, 1, 1], [400, 171, 1, 259], [400, 431, 1, 1], [400, 442, 1, 13], [400, 456, 1, 5], [401, 140, 1, 4], [401, 148, 1, 2], [401, 151, 1, 2], [401, 155, 1, 1], [401, 157, 1, 2], [401, 161, 1, 1], [401, 170, 1, 261], [401, 439, 1, 1], [401, 442, 1, 2], [401, 445, 1, 1], [401, 448, 1, 2], [401, 451, 1, 2], [401, 457, 1, 4], [402, 141, 1, 3], [402, 151, 1, 3], [402, 170, 1, 1], [402, 172, 1, 257], [402, 430, 1, 1], [402, 447, 1, 3], [402, 457, 1, 3], [403, 141, 1, 1], [403, 152, 1, 1], [403, 171, 1, 259], [403, 448, 1, 1], [403, 459, 1, 1], [404, 169, 1, 263], [405, 170, 1, 261], [406, 172, 1, 257], [407, 172, 1, 257], [408, 172, 1, 257], [409, 169, 1, 263], [410, 170, 1, 261], [411, 174, 1, 253], [412, 173, 1, 255], [413, 174, 1, 253], [414, 173, 1, 255], [415, 169, 1, 1], [415, 171, 1, 259], [415, 431, 1, 1], [416, 172, 1, 257], [417, 171, 1, 259], [418, 174, 1, 253], [419, 170, 1, 1], [419, 173, 1, 1], [419, 176, 1, 249], [419, 427, 1, 1], [419, 430, 1, 1], [420, 176, 1, 249], [421, 175, 1, 251], [422, 175, 1, 251], [423, 177, 1, 247], [424, 177, 1, 247], [425, 179, 1, 243], [426, 177, 1, 1], [426, 180, 1, 241], [426, 423, 1, 1], [427, 173, 1, 1], [427, 177, 1, 247], [427, 427, 1, 1], [428, 175, 1, 251], [429, 174, 1, 253], [430, 174, 1, 253], [431, 173, 1, 255], [432, 173, 1, 9], [432, 183, 1, 235], [432, 419, 1, 9], [433, 174, 1, 1], [433, 176, 1, 5], [433, 184, 1, 233], [433, 420, 1, 5], [433, 426, 1, 1], [434, 170, 1, 1], [434, 177, 1, 3], [434, 182, 1, 237], [434, 421, 1, 3], [434, 430, 1, 1], [435, 184, 1, 233], [436, 183, 1, 235], [437, 185, 1, 231], [438, 184, 1, 233], [439, 184, 1, 233], [440, 184, 1, 233], [441, 184, 1, 3], [441, 188, 1, 225], [441, 414, 1, 3], [442, 183, 1, 1], [442, 186, 1, 1], [442, 189, 1, 223], [442, 414, 1, 1], [442, 417, 1, 1], [443, 184, 1, 1], [443, 190, 1, 221], [443, 416, 1, 1], [444, 183, 1, 1], [444, 189, 1, 223], [444, 417, 1, 1], [445, 187, 1, 1], [445, 189, 1, 1], [445, 191, 1, 219], [445, 411, 1, 1], [445, 413, 1, 1], [446, 188, 1, 1], [446, 191, 1, 219], [446, 412, 1, 1], [447, 192, 1, 217], [448, 192, 1, 217], [449, 193, 1, 215], [450, 195, 1, 211], [451, 196, 1, 209], [452, 189, 1, 1], [452, 191, 1, 2], [452, 195, 1, 1], [452, 197, 1, 207], [452, 405, 1, 1], [452, 408, 1, 2], [452, 411, 1, 1], [453, 189, 1, 223], [454, 185, 1, 2], [454, 188, 1, 225], [454, 414, 1, 2], [455, 186, 1, 229], [456, 187, 1, 113], [456, 301, 1, 113], [457, 186, 1, 16], [457, 203, 1, 97], [457, 301, 1, 97], [457, 399, 1, 16], [458, 186, 1, 114], [458, 301, 1, 114], [459, 182, 1, 21], [459, 204, 1, 96], [459, 301, 1, 96], [459, 398, 1, 21], [460, 184, 1, 19], [460, 205, 1, 94], [460, 302, 1, 94], [460, 398, 1, 19], [461, 185, 1, 18], [461, 206, 1, 93], [461, 302, 1, 93], [461, 398, 1, 18], [462, 185, 1, 18], [462, 207, 1, 1], [462, 209, 1, 88], [462, 304, 1, 88], [462, 393, 1, 1], [462, 398, 1, 18], [463, 185, 1, 19], [463, 209, 1, 88], [463, 304, 1, 88], [463, 397, 1, 19], [464, 186, 1, 17], [464, 209, 1, 88], [464, 304, 1, 88], [464, 398, 1, 17], [465, 186, 1, 17], [465, 208, 1, 1], [465, 212, 1, 84], [465, 305, 1, 84], [465, 392, 1, 1], [465, 398, 1, 17], [466, 187, 1, 15], [466, 212, 1, 82], [466, 307, 1, 82], [466, 399, 1, 15], [467, 188, 1, 15], [467, 209, 1, 1], [467, 211, 1, 1], [467, 213, 1, 1], [467, 215, 1, 78], [467, 308, 1, 78], [467, 387, 1, 1], [467, 389, 1, 1], [467, 391, 1, 1], [467, 398, 1, 15], [468, 185, 1, 15], [468, 212, 1, 1], [468, 215, 1, 78], [468, 308, 1, 78], [468, 388, 1, 1], [468, 401, 1, 15], [469, 185, 1, 14], [469, 211, 1, 1], [469, 217, 1, 74], [469, 310, 1, 74], [469, 389, 1, 1], [469, 402, 1, 14], [470, 185, 1, 5], [470, 193, 1, 1], [470, 197, 1, 2], [470, 215, 1, 5], [470, 221, 1, 69], [470, 311, 1, 69], [470, 381, 1, 5], [470, 402, 1, 2], [470, 407, 1, 1], [470, 411, 1, 5], [471, 186, 1, 3], [471, 193, 1, 1], [471, 198, 1, 1], [471, 215, 1, 5], [471, 222, 1, 66], [471, 289, 1, 1], [471, 311, 1, 1], [471, 313, 1, 66], [471, 381, 1, 5], [471, 402, 1, 1], [471, 407, 1, 1], [471, 412, 1, 3], [472, 186, 1, 1], [472, 198, 1, 1], [472, 216, 1, 3], [472, 224, 1, 62], [472, 315, 1, 62], [472, 382, 1, 3], [472, 402, 1, 1], [472, 414, 1, 1], [473, 223, 1, 1], [473, 226, 1, 61], [473, 314, 1, 61], [473, 377, 1, 1], [474, 216, 1, 1], [474, 223, 1, 2], [474, 227, 1, 1], [474, 230, 1, 53], [474, 285, 1, 1], [474, 287, 1, 1], [474, 313, 1, 1], [474, 315, 1, 1], [474, 318, 1, 53], [474, 373, 1, 1], [474, 376, 1, 2], [474, 384, 1, 1], [475, 233, 1, 48], [475, 320, 1, 48], [476, 171, 1, 1], [476, 230, 1, 48], [476, 279, 1, 3], [476, 319, 1, 3], [476, 323, 1, 48], [476, 429, 1, 1], [477, 228, 1, 9], [477, 238, 1, 37], [477, 276, 1, 1], [477, 279, 1, 3], [477, 319, 1, 3], [477, 324, 1, 1], [477, 326, 1, 37], [477, 364, 1, 9], [478, 227, 1, 1], [478, 229, 1, 9], [478, 243, 1, 30], [478, 279, 1, 3], [478, 319, 1, 3], [478, 328, 1, 30], [478, 363, 1, 9], [478, 373, 1, 1], [479, 228, 1, 10], [479, 242, 1, 2], [479, 246, 1, 2], [479, 249, 1, 17], [479, 267, 1, 1], [479, 270, 1, 3], [479, 328, 1, 3], [479, 333, 1, 1], [479, 335, 1, 17], [479, 353, 1, 2], [479, 357, 1, 2], [479, 363, 1, 10], [480, 228, 1, 10], [480, 245, 1, 4], [480, 252, 1, 1], [480, 254, 1, 6], [480, 265, 1, 1], [480, 268, 1, 5], [480, 274, 1, 1], [480, 326, 1, 1], [480, 328, 1, 5], [480, 335, 1, 1], [480, 341, 1, 6], [480, 348, 1, 1], [480, 352, 1, 4], [480, 363, 1, 10], [481, 227, 1, 12], [481, 246, 1, 1], [481, 254, 1, 7], [481, 265, 1, 1], [481, 271, 1, 2], [481, 328, 1, 2], [481, 335, 1, 1], [481, 340, 1, 7], [481, 354, 1, 1], [481, 362, 1, 12], [482, 227, 1, 11], [482, 254, 1, 6], [482, 269, 1, 2], [482, 330, 1, 2], [482, 341, 1, 6], [482, 363, 1, 11], [483, 230, 1, 8], [483, 254, 1, 7], [483, 340, 1, 7], [483, 363, 1, 8], [484, 230, 1, 6], [484, 237, 1, 1], [484, 254, 1, 5], [484, 342, 1, 5], [484, 363, 1, 1], [484, 365, 1, 6], [485, 231, 1, 3], [485, 257, 1, 2], [485, 342, 1, 2], [485, 367, 1, 3], [486, 231, 1, 3], [486, 367, 1, 3], [487, 232, 1, 1], [487, 368, 1, 1], [491, 230, 1, 1], [491, 235, 1, 1], [491, 365, 1, 1], [491, 370, 1, 1]], [[0, 0, 1, 600], [1, 0, 1, 600], [2, 0, 1, 600], [3, 0, 1, 600], [4, 0, 1, 600], [5, 0, 1, 600], [6, 0, 1, 600], [7, 0, 1, 600], [8, 0, 1, 600], [9, 0, 1, 600], [10, 0, 1, 600], [11, 0, 1, 600], [12, 0, 1, 600], [13, 0, 1, 600], [14, 0, 1, 600], [15, 0, 1, 600], [16, 0, 1, 600], [17, 0, 1, 600], [18, 0, 1, 600], [19, 0, 1, 600], [20, 0, 1, 298], [20, 303, 1, 297], [21, 0, 1, 297], [21, 304, 1, 296], [22, 0, 1, 297], [22, 304, 1, 296], [23, 0, 1, 297], [23, 304, 1, 296], [24, 0, 1, 297], [24, 304, 1, 296], [25, 0, 1, 297], [25, 304, 1, 296], [26, 0, 1, 297], [26, 304, 1, 296], [27, 0, 1, 297], [27, 304, 1, 296], [28, 0, 1, 298], [28, 303, 1, 297], [29, 0, 1, 298], [29, 303, 1, 297], [30, 0, 1, 299], [30, 302, 1, 298], [31, 0, 1, 299], [31, 302, 1, 298], [32, 0, 1, 298], [32, 303, 1, 297], [33, 0, 1, 297], [33, 304, 1, 296], [34, 0, 1, 296], [34, 305, 1, 295], [35, 0, 1, 295], [35, 306, 1, 294], [36, 0, 1, 294], [36, 307, 1, 293], [37, 0, 1, 293], [37, 308, 1, 292], [38, 0, 1, 292], [38, 309, 1, 291], [39, 0, 1, 292], [39, 309, 1, 291], [40, 0, 1, 291], [40, 310, 1, 290], [41, 0, 1, 290], [41, 311, 1, 289], [42, 0, 1, 290], [42, 311, 1, 289], [43, 0, 1, 289], [43, 312, 1, 288], [44, 0, 1, 289], [44, 312, 1, 288], [45, 0, 1, 289], [45, 312, 1, 288], [46, 0, 1, 288], [46, 313, 1, 287], [47, 0, 1, 288], [47, 313, 1, 287], [48, 0, 1, 288], [48, 313, 1, 287], [49, 0, 1, 288], [49, 313, 1, 287], [50, 0, 1, 288], [50, 313, 1, 287], [51, 0, 1, 287], [51, 314, 1, 286], [52, 0, 1, 287], [52, 314, 1, 286], [53, 0, 1, 287], [53, 314, 1, 286], [54, 0, 1, 287], [54, 314, 1, 286], [55, 0, 1, 287], [55, 314, 1, 286], [56, 0, 1, 287], [56, 314, 1, 286], [57, 0, 1, 287], [57, 314, 1, 286], [58, 0, 1, 287], [58, 314, 1, 286], [59, 0, 1, 287], [59, 314, 1, 286], [60, 0, 1, 287], [60, 314, 1, 286], [61, 0, 1, 287], [61, 314, 1, 286], [62, 0, 1, 287], [62, 314, 1, 286], [63, 0, 1, 287], [63, 314, 1, 286], [64, 0, 1, 286], [64, 315, 1, 285], [65, 0, 1, 286], [65, 315, 1, 285], [66, 0, 1, 286], [66, 315, 1, 285], [67, 0, 1, 285], [67, 316, 1, 284], [68, 0, 1, 285], [68, 316, 1, 284], [69, 0, 1, 284], [69, 317, 1, 283], [70, 0, 1, 284], [70, 317, 1, 283], [71, 0, 1, 283], [71, 318, 1, 282], [72, 0, 1, 283], [72, 318, 1, 282], [73, 0, 1, 282], [73, 319, 1, 281], [74, 0, 1, 282], [74, 319, 1, 281], [75, 0, 1, 281], [75, 320, 1, 280], [76, 0, 1, 281], [76, 320, 1, 280], [77, 0, 1, 280], [77, 321, 1, 279], [78, 0, 1, 280], [78, 321, 1, 279], [79, 0, 1, 279], [79, 322, 1, 278], [80, 0, 1, 279], [80, 322, 1, 278], [81, 0, 1, 278], [81, 323, 1, 277], [82, 0, 1, 278], [82, 323, 1, 277], [83, 0, 1, 277], [83, 324, 1, 276], [84, 0, 1, 277], [84, 324, 1, 276], [85, 0, 1, 277], [85, 324, 1, 276], [86, 0, 1, 276], [86, 325, 1, 275], [87, 0, 1, 276], [87, 325, 1, 275], [88, 0, 1, 276], [88, 325, 1, 275], [89, 0, 1, 275], [89, 326, 1, 274], [90, 0, 1, 275], [90, 326, 1, 274], [91, 0, 1, 275], [91, 326, 1, 274], [92, 0, 1, 274], [92, 327, 1, 273], [93, 0, 1, 274], [93, 327, 1, 273], [94, 0, 1, 274], [94, 327, 1, 273], [95, 0, 1, 274], [95, 327, 1, 273], [96, 0, 1, 273], [96, 328, 1, 272], [97, 0, 1, 273], [97, 328, 1, 272], [98, 0, 1, 273], [98, 328, 1, 272], [99, 0, 1, 273], [99, 328, 1, 272], [100, 0, 1, 273], [100, 328, 1, 272], [101, 0, 1, 272], [101, 329, 1, 271], [102, 0, 1, 272], [102, 329, 1, 271], [103, 0, 1, 272], [103, 329, 1, 271], [104, 0, 1, 272], [104, 329, 1, 271], [105, 0, 1, 272], [105, 329, 1, 271], [106, 0, 1, 272], [106, 329, 1, 271], [107, 0, 1, 271], [107, 330, 1, 270], [108, 0, 1, 271], [108, 330, 1, 270], [109, 0, 1, 271], [109, 330, 1, 270], [110, 0, 1, 271], [110, 330, 1, 270], [111, 0, 1, 271], [111, 330, 1, 270], [112, 0, 1, 270], [112, 331, 1, 269], [113, 0, 1, 270], [113, 331, 1, 269], [114, 0, 1, 270], [114, 331, 1, 269], [115, 0, 1, 270], [115, 331, 1, 269], [116, 0, 1, 269], [116, 332, 1, 268], [117, 0, 1, 269], [117, 332, 1, 268], [118, 0, 1, 269], [118, 332, 1, 268], [119, 0, 1, 268], [119, 333, 1, 267], [120, 0, 1, 268], [120, 333, 1, 267], [121, 0, 1, 268], [121, 333, 1, 267], [122, 0, 1, 267], [122, 334, 1, 266], [123, 0, 1, 267], [123, 334, 1, 266], [124, 0, 1, 266], [124, 335, 1, 265], [125, 0, 1, 265], [125, 336, 1, 264], [126, 0, 1, 265], [126, 336, 1, 264], [127, 0, 1, 264], [127, 337, 1, 263], [128, 0, 1, 263], [128, 338, 1, 262], [129, 0, 1, 262], [129, 339, 1, 261], [130, 0, 1, 261], [130, 340, 1, 260], [131, 0, 1, 260], [131, 341, 1, 259], [132, 0, 1, 259], [132, 342, 1, 258], [133, 0, 1, 257], [133, 344, 1, 256], [134, 0, 1, 256], [134, 345, 1, 255], [135, 0, 1, 254], [135, 347, 1, 253], [136, 0, 1, 252], [136, 349, 1, 251], [137, 0, 1, 249], [137, 352, 1, 248], [138, 0, 1, 246], [138, 355, 1, 245], [139, 0, 1, 243], [139, 358, 1, 242], [140, 0, 1, 239], [140, 362, 1, 238], [141, 0, 1, 235], [141, 366, 1, 234], [142, 0, 1, 231], [142, 370, 1, 230], [143, 0, 1, 228], [143, 373, 1, 227], [144, 0, 1, 225], [144, 376, 1, 224], [145, 0, 1, 223], [145, 378, 1, 222], [146, 0, 1, 221], [146, 380, 1, 220], [147, 0, 1, 219], [147, 382, 1, 218], [148, 0, 1, 218], [148, 383, 1, 217], [149, 0, 1, 216], [149, 385, 1, 215], [150, 0, 1, 215], [150, 386, 1, 214], [151, 0, 1, 214], [151, 387, 1, 213], [152, 0, 1, 213], [152, 388, 1, 212], [153, 0, 1, 212], [153, 389, 1, 211], [154, 0, 1, 212], [154, 389, 1, 211], [155, 0, 1, 211], [155, 390, 1, 210], [156, 0, 1, 210], [156, 391, 1, 209], [157, 0, 1, 210], [157, 391, 1, 209], [158, 0, 1, 209], [158, 392, 1, 208], [159, 0, 1, 209], [159, 392, 1, 208], [160, 0, 1, 208], [160, 393, 1, 207], [161, 0, 1, 208], [161, 393, 1, 207], [162, 0, 1, 208], [162, 393, 1, 207], [163, 0, 1, 208], [163, 393, 1, 207], [164, 0, 1, 207], [164, 394, 1, 206], [165, 0, 1, 207], [165, 394, 1, 206], [166, 0, 1, 207], [166, 394, 1, 206], [167, 0, 1, 207], [167, 394, 1, 206], [168, 0, 1, 207], [168, 394, 1, 206], [169, 0, 1, 207], [169, 394, 1, 206], [170, 0, 1, 207], [170, 394, 1, 206], [171, 0, 1, 207], [171, 394, 1, 206], [172, 0, 1, 207], [172, 394, 1, 206], [173, 0, 1, 207], [173, 394, 1, 206], [174, 0, 1, 207], [174, 394, 1, 206], [175, 0, 1, 207], [175, 394, 1, 206], [176, 0, 1, 207], [176, 394, 1, 206], [177, 0, 1, 208], [177, 393, 1, 207], [178, 0, 1, 208], [178, 393, 1, 207], [179, 0, 1, 208], [179, 393, 1, 207], [180, 0, 1, 208], [180, 393, 1, 207], [181, 0, 1, 209], [181, 392, 1, 208], [182, 0, 1, 209], [182, 392, 1, 208], [183, 0, 1, 209], [183, 392, 1, 208], [184, 0, 1, 209], [184, 392, 1, 208], [185, 0, 1, 210], [185, 391, 1, 209], [186, 0, 1, 210], [186, 391, 1, 209], [187, 0, 1, 210], [187, 391, 1, 209], [188, 0, 1, 210], [188, 391, 1, 209], [189, 0, 1, 211], [189, 390, 1, 210], [190, 0, 1, 211], [190, 390, 1, 210], [191, 0, 1, 211], [191, 390, 1, 210], [192, 0, 1, 211], [192, 390, 1, 210], [193, 0, 1, 212], [193, 389, 1, 211], [194, 0, 1, 212], [194, 389, 1, 211], [195, 0, 1, 212], [195, 389, 1, 211], [196, 0, 1, 212], [196, 389, 1, 211], [197, 0, 1, 212], [197, 389, 1, 211], [198, 0, 1, 213], [198, 388, 1, 212], [199, 0, 1, 213], [199, 388, 1, 212], [200, 0, 1, 213], [200, 388, 1, 212], [201, 0, 1, 213], [201, 388, 1, 212], [202, 0, 1, 213], [202, 388, 1, 212], [203, 0, 1, 213], [203, 388, 1, 212], [204, 0, 1, 213], [204, 388, 1, 212], [205, 0, 1, 213], [205, 388, 1, 212], [206, 0, 1, 213], [206, 388, 1, 212], [207, 0, 1, 213], [207, 388, 1, 212], [208, 0, 1, 213], [208, 388, 1, 212], [209, 0, 1, 213], [209, 388, 1, 212], [210, 0, 1, 213], [210, 388, 1, 212], [211, 0, 1, 213], [211, 388, 1, 212], [212, 0, 1, 213], [212, 388, 1, 212], [213, 0, 1, 213], [213, 388, 1, 212], [214, 0, 1, 212], [214, 389, 1, 211], [215, 0, 1, 212], [215, 389, 1, 211], [216, 0, 1, 212], [216, 389, 1, 211], [217, 0, 1, 212], [217, 389, 1, 211], [218, 0, 1, 211], [218, 390, 1, 210], [219, 0, 1, 211], [219, 390, 1, 210], [220, 0, 1, 211], [220, 390, 1, 210], [221, 0, 1, 210], [221, 391, 1, 209], [222, 0, 1, 210], [222, 391, 1, 209], [223, 0, 1, 210], [223, 391, 1, 209], [224, 0, 1, 209], [224, 392, 1, 208], [225, 0, 1, 209], [225, 392, 1, 208], [226, 0, 1, 208], [226, 393, 1, 207], [227, 0, 1, 208], [227, 393, 1, 207], [228, 0, 1, 207], [228, 394, 1, 206], [229, 0, 1, 207], [229, 394, 1, 206], [230, 0, 1, 206], [230, 395, 1, 205], [231, 0, 1, 206], [231, 395, 1, 205], [232, 0, 1, 205], [232, 396, 1, 204], [233, 0, 1, 204], [233, 397, 1, 203], [234, 0, 1, 204], [234, 397, 1, 203], [235, 0, 1, 203], [235, 398, 1, 202], [236, 0, 1, 202], [236, 399, 1, 201], [237, 0, 1, 201], [237, 400, 1, 200], [238, 0, 1, 201], [238, 400, 1, 200], [239, 0, 1, 200], [239, 401, 1, 199], [240, 0, 1, 199], [240, 402, 1, 198], [241, 0, 1, 198], [241, 403, 1, 197], [242, 0, 1, 197], [242, 404, 1, 196], [243, 0, 1, 196], [243, 405, 1, 195], [244, 0, 1, 196], [244, 405, 1, 195], [245, 0, 1, 195], [245, 406, 1, 194], [246, 0, 1, 194], [246, 407, 1, 193], [247, 0, 1, 193], [247, 408, 1, 192], [248, 0, 1, 192], [248, 409, 1, 191], [249, 0, 1, 191], [249, 410, 1, 190], [250, 0, 1, 190], [250, 411, 1, 189], [251, 0, 1, 189], [251, 412, 1, 188], [252, 0, 1, 188], [252, 413, 1, 187], [253, 0, 1, 187], [253, 414, 1, 186], [254, 0, 1, 186], [254, 415, 1, 185], [255, 0, 1, 185], [255, 416, 1, 184], [256, 0, 1, 184], [256, 417, 1, 183], [257, 0, 1, 183], [257, 418, 1, 182], [258, 0, 1, 181], [258, 420, 1, 180], [259, 0, 1, 180], [259, 421, 1, 179], [260, 0, 1, 179], [260, 422, 1, 178], [261, 0, 1, 178], [261, 423, 1, 177], [262, 0, 1, 177], [262, 424, 1, 176], [263, 0, 1, 176], [263, 425, 1, 175], [264, 0, 1, 175], [264, 426, 1, 174], [265, 0, 1, 174], [265, 427, 1, 173], [266, 0, 1, 173], [266, 428, 1, 172], [267, 0, 1, 172], [267, 429, 1, 171], [268, 0, 1, 171], [268, 430, 1, 170], [269, 0, 1, 170], [269, 431, 1, 169], [270, 0, 1, 169], [270, 432, 1, 168], [271, 0, 1, 168], [271, 433, 1, 167], [272, 0, 1, 167], [272, 434, 1, 166], [273, 0, 1, 166], [273, 435, 1, 165], [274, 0, 1, 165], [274, 436, 1, 164], [275, 0, 1, 164], [275, 437, 1, 163], [276, 0, 1, 163], [276, 438, 1, 162], [277, 0, 1, 162], [277, 439, 1, 161], [278, 0, 1, 161], [278, 440, 1, 160], [279, 0, 1, 161], [279, 440, 1, 160], [280, 0, 1, 160], [280, 441, 1, 159], [281, 0, 1, 159], [281, 442, 1, 158], [282, 0, 1, 158], [282, 443, 1, 157], [283, 0, 1, 157], [283, 444, 1, 156], [284, 0, 1, 157], [284, 444, 1, 156], [285, 0, 1, 156], [285, 445, 1, 155], [286, 0, 1, 155], [286, 446, 1, 154], [287, 0, 1, 155], [287, 446, 1, 154], [288, 0, 1, 154], [288, 447, 1, 153], [289, 0, 1, 153], [289, 448, 1, 152], [290, 0, 1, 153], [290, 448, 1, 152], [291, 0, 1, 152], [291, 449, 1, 151], [292, 0, 1, 151], [292, 450, 1, 150], [293, 0, 1, 151], [293, 450, 1, 150], [294, 0, 1, 150], [294, 451, 1, 149], [295, 0, 1, 149], [295, 452, 1, 148], [296, 0, 1, 149], [296, 452, 1, 148], [297, 0, 1, 148], [297, 453, 1, 147], [298, 0, 1, 148], [298, 453, 1, 147], [299, 0, 1, 147], [299, 454, 1, 146], [300, 0, 1, 147], [300, 454, 1, 146], [301, 0, 1, 146], [301, 455, 1, 145], [302, 0, 1, 146], [302, 455, 1, 145], [303, 0, 1, 145], [303, 456, 1, 144], [304, 0, 1, 145], [304, 456, 1, 144], [305, 0, 1, 144], [305, 457, 1, 143], [306, 0, 1, 144], [306, 457, 1, 143], [307, 0, 1, 143], [307, 458, 1, 142], [308, 0, 1, 143], [308, 458, 1, 142], [309, 0, 1, 142], [309, 459, 1, 141], [310, 0, 1, 142], [310, 459, 1, 141], [311, 0, 1, 141], [311, 460, 1, 140], [312, 0, 1, 141], [312, 460, 1, 140], [313, 0, 1, 140], [313, 461, 1, 139], [314, 0, 1, 140], [314, 461, 1, 139], [315, 0, 1, 139], [315, 462, 1, 138], [316, 0, 1, 139], [316, 462, 1, 138], [317, 0, 1, 138], [317, 463, 1, 137], [318, 0, 1, 138], [318, 463, 1, 137], [319, 0, 1, 138], [319, 463, 1, 137], [320, 0, 1, 137], [320, 464, 1, 136], [321, 0, 1, 137], [321, 464, 1, 136], [322, 0, 1, 136], [322, 465, 1, 135], [323, 0, 1, 136], [323, 465, 1, 135], [324, 0, 1, 135], [324, 466, 1, 134], [325, 0, 1, 135], [325, 466, 1, 134], [326, 0, 1, 134], [326, 467, 1, 133], [327, 0, 1, 133], [327, 468, 1, 132], [328, 0, 1, 133], [328, 468, 1, 132], [329, 0, 1, 132], [329, 469, 1, 131], [330, 0, 1, 132], [330, 469, 1, 131], [331, 0, 1, 131], [331, 470, 1, 130], [332, 0, 1, 131], [332, 470, 1, 130], [333, 0, 1, 130], [333, 471, 1, 129], [334, 0, 1, 129], [334, 472, 1, 128], [335, 0, 1, 129], [335, 472, 1, 128], [336, 0, 1, 128], [336, 473, 1, 127], [337, 0, 1, 127], [337, 474, 1, 126], [338, 0, 1, 126], [338, 475, 1, 125], [339, 0, 1, 126], [339, 475, 1, 125], [340, 0, 1, 125], [340, 476, 1, 124], [341, 0, 1, 124], [341, 477, 1, 123], [342, 0, 1, 123], [342, 478, 1, 122], [343, 0, 1, 122], [343, 479, 1, 121], [344, 0, 1, 121], [344, 480, 1, 120], [345, 0, 1, 120], [345, 481, 1, 119], [346, 0, 1, 119], [346, 482, 1, 118], [347, 0, 1, 117], [347, 484, 1, 116], [348, 0, 1, 116], [348, 485, 1, 115], [349, 0, 1, 115], [349, 486, 1, 114], [350, 0, 1, 113], [350, 488, 1, 112], [351, 0, 1, 111], [351, 490, 1, 110], [352, 0, 1, 109], [352, 492, 1, 108], [353, 0, 1, 107], [353, 494, 1, 106], [354, 0, 1, 104], [354, 497, 1, 103], [355, 0, 1, 101], [355, 500, 1, 100], [356, 0, 1, 96], [356, 505, 1, 95], [357, 0, 1, 88], [357, 513, 1, 87], [358, 0, 1, 83], [358, 518, 1, 82], [359, 0, 1, 80], [359, 521, 1, 79], [360, 0, 1, 78], [360, 523, 1, 77], [361, 0, 1, 77], [361, 524, 1, 76], [362, 0, 1, 76], [362, 525, 1, 75], [363, 0, 1, 75], [363, 526, 1, 74], [364, 0, 1, 74], [364, 527, 1, 73], [365, 0, 1, 74], [365, 527, 1, 73], [366, 0, 1, 73], [366, 528, 1, 72], [367, 0, 1, 73], [367, 528, 1, 72], [368, 0, 1, 73], [368, 528, 1, 72], [369, 0, 1, 73], [369, 528, 1, 72], [370, 0, 1, 73], [370, 528, 1, 72], [371, 0, 1, 73], [371, 528, 1, 72], [372, 0, 1, 74], [372, 527, 1, 73], [373, 0, 1, 74], [373, 527, 1, 73], [374, 0, 1, 74], [374, 527, 1, 73], [375, 0, 1, 75], [375, 526, 1, 74], [376, 0, 1, 76], [376, 525, 1, 75], [377, 0, 1, 76], [377, 525, 1, 75], [378, 0, 1, 77], [378, 524, 1, 76], [379, 0, 1, 78], [379, 523, 1, 77], [380, 0, 1, 79], [380, 522, 1, 78], [381, 0, 1, 80], [381, 521, 1, 79], [382, 0, 1, 80], [382, 521, 1, 79], [383, 0, 1, 81], [383, 520, 1, 80], [384, 0, 1, 82], [384, 519, 1, 81], [385, 0, 1, 82], [385, 519, 1, 81], [386, 0, 1, 83], [386, 518, 1, 82], [387, 0, 1, 84], [387, 517, 1, 83], [388, 0, 1, 84], [388, 517, 1, 83], [389, 0, 1, 84], [389, 517, 1, 83], [390, 0, 1, 85], [390, 516, 1, 84], [391, 0, 1, 85], [391, 516, 1, 84], [392, 0, 1, 85], [392, 516, 1, 84], [393, 0, 1, 86], [393, 515, 1, 85], [394, 0, 1, 86], [394, 515, 1, 85], [395, 0, 1, 86], [395, 515, 1, 85], [396, 0, 1, 87], [396, 514, 1, 86], [397, 0, 1, 87], [397, 514, 1, 86], [398, 0, 1, 88], [398, 513, 1, 87], [399, 0, 1, 88], [399, 513, 1, 87], [400, 0, 1, 88], [400, 513, 1, 87], [401, 0, 1, 89], [401, 512, 1, 88], [402, 0, 1, 89], [402, 512, 1, 88], [403, 0, 1, 90], [403, 511, 1, 89], [404, 0, 1, 91], [404, 510, 1, 90], [405, 0, 1, 91], [405, 510, 1, 90], [406, 0, 1, 92], [406, 509, 1, 91], [407, 0, 1, 93], [407, 508, 1, 92], [408, 0, 1, 94], [408, 507, 1, 93], [409, 0, 1, 95], [409, 506, 1, 94], [410, 0, 1, 96], [410, 505, 1, 95], [411, 0, 1, 97], [411, 504, 1, 96], [412, 0, 1, 99], [412, 502, 1, 98], [413, 0, 1, 101], [413, 500, 1, 100], [414, 0, 1, 103], [414, 498, 1, 102], [415, 0, 1, 106], [415, 495, 1, 105], [416, 0, 1, 109], [416, 492, 1, 108], [417, 0, 1, 112], [417, 489, 1, 111], [418, 0, 1, 116], [418, 485, 1, 115], [419, 0, 1, 120], [419, 481, 1, 119], [420, 0, 1, 123], [420, 478, 1, 122], [421, 0, 1, 125], [421, 476, 1, 124], [422, 0, 1, 128], [422, 473, 1, 127], [423, 0, 1, 130], [423, 471, 1, 129], [424, 0, 1, 131], [424, 470, 1, 130], [425, 0, 1, 133], [425, 468, 1, 132], [426, 0, 1, 134], [426, 467, 1, 133], [427, 0, 1, 136], [427, 465, 1, 135], [428, 0, 1, 137], [428, 464, 1, 136], [429, 0, 1, 138], [429, 463, 1, 137], [430, 0, 1, 139], [430, 462, 1, 138], [431, 0, 1, 140], [431, 461, 1, 139], [432, 0, 1, 141], [432, 460, 1, 140], [433, 0, 1, 142], [433, 459, 1, 141], [434, 0, 1, 142], [434, 459, 1, 141], [435, 0, 1, 143], [435, 458, 1, 142], [436, 0, 1, 144], [436, 457, 1, 143], [437, 0, 1, 144], [437, 457, 1, 143], [438, 0, 1, 145], [438, 456, 1, 144], [439, 0, 1, 146], [439, 455, 1, 145], [440, 0, 1, 146], [440, 455, 1, 145], [441, 0, 1, 147], [441, 454, 1, 146], [442, 0, 1, 147], [442, 454, 1, 146], [443, 0, 1, 148], [443, 453, 1, 147], [444, 0, 1, 148], [444, 453, 1, 147], [445, 0, 1, 149], [445, 452, 1, 148], [446, 0, 1, 149], [446, 452, 1, 148], [447, 0, 1, 149], [447, 452, 1, 148], [448, 0, 1, 150], [448, 451, 1, 149], [449, 0, 1, 150], [449, 451, 1, 149], [450, 0, 1, 150], [450, 451, 1, 149], [451, 0, 1, 151], [451, 450, 1, 150], [452, 0, 1, 151], [452, 450, 1, 150], [453, 0, 1, 151], [453, 450, 1, 150], [454, 0, 1, 152], [454, 449, 1, 151], [455, 0, 1, 152], [455, 449, 1, 151], [456, 0, 1, 152], [456, 449, 1, 151], [457, 0, 1, 152], [457, 449, 1, 151], [458, 0, 1, 152], [458, 449, 1, 151], [459, 0, 1, 153], [459, 448, 1, 152], [460, 0, 1, 153], [460, 448, 1, 152], [461, 0, 1, 153], [461, 448, 1, 152], [462, 0, 1, 153], [462, 448, 1, 152], [463, 0, 1, 153], [463, 448, 1, 152], [464, 0, 1, 153], [464, 448, 1, 152], [465, 0, 1, 154], [465, 447, 1, 153], [466, 0, 1, 154], [466, 447, 1, 153], [467, 0, 1, 154], [467, 447, 1, 153], [468, 0, 1, 154], [468, 447, 1, 153], [469, 0, 1, 154], [469, 447, 1, 153], [470, 0, 1, 155], [470, 446, 1, 154], [471, 0, 1, 155], [471, 446, 1, 154], [472, 0, 1, 155], [472, 446, 1, 154], [473, 0, 1, 155], [473, 446, 1, 154], [474, 0, 1, 156], [474, 445, 1, 155], [475, 0, 1, 156], [475, 445, 1, 155], [476, 0, 1, 156], [476, 445, 1, 155], [477, 0, 1, 157], [477, 444, 1, 156], [478, 0, 1, 157], [478, 444, 1, 156], [479, 0, 1, 158], [479, 443, 1, 157], [480, 0, 1, 158], [480, 443, 1, 157], [481, 0, 1, 159], [481, 442, 1, 158], [482, 0, 1, 160], [482, 441, 1, 159], [483, 0, 1, 161], [483, 440, 1, 160], [484, 0, 1, 162], [484, 439, 1, 161], [485, 0, 1, 163], [485, 438, 1, 162], [486, 0, 1, 164], [486, 437, 1, 163], [487, 0, 1, 165], [487, 436, 1, 164], [488, 0, 1, 167], [488, 434, 1, 166], [489, 0, 1, 169], [489, 432, 1, 168], [490, 0, 1, 171], [490, 430, 1, 170], [491, 0, 1, 175], [491, 426, 1, 174], [492, 0, 1, 183], [492, 418, 1, 182], [493, 0, 1, 192], [493, 409, 1, 191], [494, 0, 1, 197], [494, 404, 1, 196], [495, 0, 1, 201], [495, 286, 1, 29], [495, 400, 1, 200], [496, 0, 1, 204], [496, 279, 1, 43], [496, 397, 1, 203], [497, 0, 1, 207], [497, 273, 1, 55], [497, 394, 1, 206], [498, 0, 1, 210], [498, 269, 1, 63], [498, 391, 1, 209], [499, 0, 1, 213], [499, 264, 1, 73], [499, 388, 1, 212], [500, 0, 1, 216], [500, 260, 1, 81], [500, 385, 1, 215], [501, 0, 1, 219], [501, 256, 1, 89], [501, 382, 1, 218], [502, 0, 1, 223], [502, 251, 1, 99], [502, 378, 1, 222], [503, 0, 1, 229], [503, 245, 1, 111], [503, 372, 1, 228], [504, 0, 1, 600], [505, 0, 1, 600], [506, 0, 1, 600], [507, 0, 1, 600], [508, 0, 1, 600], [509, 0, 1, 600], [510, 0, 1, 600], [511, 0, 1, 600], [512, 0, 1, 600], [513, 0, 1, 600], [514, 0, 1, 600], [515, 0, 1, 600], [516, 0, 1, 600], [517, 0, 1, 600], [518, 0, 1, 600], [519, 0, 1, 600], [520, 0, 1, 600], [521, 0, 1, 600], [522, 0, 1, 600], [523, 0, 1, 600], [524, 0, 1, 600], [525, 0, 1, 600], [526, 0, 1, 600], [527, 0, 1, 600], [528, 0, 1, 600], [529, 0, 1, 600], [530, 0, 1, 600], [531, 0, 1, 600], [532, 0, 1, 600], [533, 0, 1, 600], [534, 0, 1, 600], [535, 0, 1, 600], [536, 0, 1, 600], [537, 0, 1, 600], [538, 0, 1, 600], [539, 0, 1, 600], [540, 0, 1, 600], [541, 0, 1, 600], [542, 0, 1, 600], [543, 0, 1, 600], [544, 0, 1, 600], [545, 0, 1, 600], [546, 0, 1, 600], [547, 0, 1, 600], [548, 0, 1, 600], [549, 0, 1, 600], [550, 0, 1, 600], [551, 0, 1, 600], [552, 0, 1, 600], [553, 0, 1, 600], [554, 0, 1, 600], [555, 0, 1, 600], [556, 0, 1, 600], [557, 0, 1, 600], [558, 0, 1, 600], [559, 0, 1, 600], [560, 0, 1, 600], [561, 0, 1, 600], [562, 0, 1, 600], [563, 0, 1, 600], [564, 0, 1, 600], [565, 0, 1, 600], [566, 0, 1, 600], [567, 0, 1, 600], [568, 0, 1, 600], [569, 0, 1, 600], [570, 0, 1, 600], [571, 0, 1, 600], [572, 0, 1, 600], [573, 0, 1, 600], [574, 0, 1, 600], [575, 0, 1, 600], [576, 0, 1, 600], [577, 0, 1, 600], [578, 0, 1, 600], [579, 0, 1, 600], [580, 0, 1, 600], [581, 0, 1, 600], [582, 0, 1, 600], [583, 0, 1, 600], [584, 0, 1, 600], [585, 0, 1, 600], [586, 0, 1, 600], [587, 0, 1, 600], [588, 0, 1, 600], [589, 0, 1, 600], [590, 0, 1, 600], [591, 0, 1, 600], [592, 0, 1, 600], [593, 0, 1, 600], [594, 0, 1, 600], [595, 0, 1, 600], [596, 0, 1, 600], [597, 0, 1, 600], [598, 0, 1, 600], [599, 0, 1, 600]], [[20, 298, 1, 2], [20, 301, 1, 2], [21, 297, 1, 3], [21, 301, 1, 3], [22, 297, 1, 3], [22, 301, 1, 3], [23, 297, 1, 3], [23, 301, 1, 3], [24, 297, 1, 3], [24, 301, 1, 3], [25, 297, 1, 3], [25, 301, 1, 3], [26, 297, 1, 3], [26, 301, 1, 3], [27, 297, 1, 3], [27, 301, 1, 3], [28, 298, 1, 2], [28, 301, 1, 2], [29, 298, 1, 2], [29, 301, 1, 2], [30, 299, 1, 1], [30, 301, 1, 1], [31, 299, 1, 1], [31, 301, 1, 1], [32, 298, 1, 2], [32, 301, 1, 2], [33, 297, 1, 3], [33, 301, 1, 3], [34, 296, 1, 4], [34, 301, 1, 4], [35, 295, 1, 5], [35, 301, 1, 5], [36, 294, 1, 6], [36, 301, 1, 6], [37, 293, 1, 7], [37, 301, 1, 7], [38, 292, 1, 8], [38, 301, 1, 8], [39, 292, 1, 8], [39, 301, 1, 8], [40, 291, 1, 9], [40, 301, 1, 9], [41, 290, 1, 10], [41, 301, 1, 10], [42, 290, 1, 10], [42, 301, 1, 10], [43, 289, 1, 11], [43, 301, 1, 11], [44, 289, 1, 11], [44, 301, 1, 11], [45, 289, 1, 11], [45, 301, 1, 11], [46, 288, 1, 10], [46, 303, 1, 10], [47, 288, 1, 11], [47, 302, 1, 11], [48, 288, 1, 12], [48, 301, 1, 12], [49, 288, 1, 12], [49, 301, 1, 12], [50, 288, 1, 12], [50, 301, 1, 12], [51, 287, 1, 13], [51, 301, 1, 13], [52, 287, 1, 13], [52, 301, 1, 13], [53, 287, 1, 13], [53, 301, 1, 13], [54, 287, 1, 13], [54, 301, 1, 13], [55, 287, 1, 13], [55, 301, 1, 13], [56, 287, 1, 13], [56, 301, 1, 13], [57, 287, 1, 12], [57, 302, 1, 12], [58, 287, 1, 12], [58, 302, 1, 12], [59, 287, 1, 12], [59, 302, 1, 12], [60, 287, 1, 12], [60, 302, 1, 12], [61, 287, 1, 9], [61, 305, 1, 9], [62, 287, 1, 9], [62, 305, 1, 9], [63, 287, 1, 10], [63, 304, 1, 10], [64, 286, 1, 2], [64, 313, 1, 2], [65, 286, 1, 5], [65, 310, 1, 5], [66, 286, 1, 7], [66, 308, 1, 7], [67, 285, 1, 10], [67, 306, 1, 10], [68, 285, 1, 10], [68, 306, 1, 10], [69, 284, 1, 11], [69, 306, 1, 11], [70, 284, 1, 11], [70, 296, 1, 2], [70, 303, 1, 2], [70, 306, 1, 11], [71, 283, 1, 15], [71, 303, 1, 15], [72, 283, 1, 16], [72, 302, 1, 16], [73, 282, 1, 17], [73, 302, 1, 17], [74, 282, 1, 17], [74, 302, 1, 17], [75, 281, 1, 18], [75, 302, 1, 18], [76, 281, 1, 18], [76, 302, 1, 18], [77, 280, 1, 19], [77, 302, 1, 19], [78, 280, 1, 19], [78, 302, 1, 19], [79, 279, 1, 21], [79, 301, 1, 21], [80, 279, 1, 20], [80, 302, 1, 20], [81, 278, 1, 21], [81, 302, 1, 21], [82, 278, 1, 20], [82, 303, 1, 20], [83, 277, 1, 21], [83, 303, 1, 21], [84, 277, 1, 22], [84, 302, 1, 22], [85, 277, 1, 22], [85, 302, 1, 22], [86, 276, 1, 23], [86, 302, 1, 23], [87, 276, 1, 23], [87, 302, 1, 23], [88, 276, 1, 22], [88, 303, 1, 22], [89, 275, 1, 22], [89, 304, 1, 22], [90, 275, 1, 20], [90, 306, 1, 20], [91, 275, 1, 18], [91, 308, 1, 18], [92, 274, 1, 20], [92, 307, 1, 20], [93, 274, 1, 22], [93, 305, 1, 22], [94, 274, 1, 23], [94, 304, 1, 23], [95, 274, 1, 23], [95, 304, 1, 23], [96, 273, 1, 25], [96, 303, 1, 25], [97, 273, 1, 26], [97, 302, 1, 26], [98, 273, 1, 26], [98, 302, 1, 26], [99, 273, 1, 25], [99, 303, 1, 25], [100, 273, 1, 25], [100, 303, 1, 25], [101, 272, 1, 25], [101, 304, 1, 25], [102, 272, 1, 25], [102, 304, 1, 25], [103, 272, 1, 25], [103, 304, 1, 25], [104, 272, 1, 26], [104, 303, 1, 26], [105, 272, 1, 27], [105, 302, 1, 27], [106, 272, 1, 27], [106, 302, 1, 27], [107, 271, 1, 27], [107, 303, 1, 27], [108, 271, 1, 27], [108, 303, 1, 27], [109, 271, 1, 27], [109, 303, 1, 27], [110, 271, 1, 27], [110, 303, 1, 27], [111, 271, 1, 26], [111, 304, 1, 26], [112, 270, 1, 27], [112, 304, 1, 27], [113, 270, 1, 27], [113, 304, 1, 27], [114, 270, 1, 26], [114, 305, 1, 26], [115, 270, 1, 26], [115, 305, 1, 26], [116, 269, 1, 26], [116, 306, 1, 26], [117, 269, 1, 25], [117, 307, 1, 25], [118, 269, 1, 21], [118, 311, 1, 21], [119, 268, 1, 23], [119, 310, 1, 23], [120, 268, 1, 24], [120, 309, 1, 24], [121, 268, 1, 24], [121, 309, 1, 24], [122, 267, 1, 25], [122, 309, 1, 25], [123, 267, 1, 25], [123, 309, 1, 25], [124, 266, 1, 26], [124, 309, 1, 26], [125, 265, 1, 27], [125, 309, 1, 27], [126, 265, 1, 27], [126, 309, 1, 27], [127, 264, 1, 27], [127, 310, 1, 27], [128, 263, 1, 28], [128, 310, 1, 28], [129, 262, 1, 28], [129, 311, 1, 28], [130, 261, 1, 28], [130, 312, 1, 28], [131, 260, 1, 8], [131, 271, 1, 3], [131, 276, 1, 12], [131, 313, 1, 12], [131, 327, 1, 3], [131, 333, 1, 8], [132, 259, 1, 10], [132, 277, 1, 9], [132, 315, 1, 9], [132, 332, 1, 10], [133, 257, 1, 13], [133, 278, 1, 6], [133, 317, 1, 6], [133, 331, 1, 13], [134, 256, 1, 14], [134, 331, 1, 14], [135, 254, 1, 16], [135, 331, 1, 16], [136, 252, 1, 18], [136, 331, 1, 18], [137, 249, 1, 24], [137, 328, 1, 24], [138, 246, 1, 29], [138, 326, 1, 29], [139, 243, 1, 32], [139, 326, 1, 32], [140, 239, 1, 36], [140, 326, 1, 36], [141, 235, 1, 41], [141, 325, 1, 41], [142, 231, 1, 45], [142, 325, 1, 45], [143, 228, 1, 48], [143, 325, 1, 48], [144, 225, 1, 51], [144, 325, 1, 51], [145, 223, 1, 53], [145, 325, 1, 53], [146, 221, 1, 55], [146, 325, 1, 55], [147, 219, 1, 57], [147, 325, 1, 57], [148, 218, 1, 58], [148, 325, 1, 58], [149, 216, 1, 60], [149, 325, 1, 60], [150, 215, 1, 60], [150, 326, 1, 60], [151, 214, 1, 61], [151, 326, 1, 61], [152, 213, 1, 61], [152, 327, 1, 61], [153, 212, 1, 62], [153, 327, 1, 62], [154, 212, 1, 61], [154, 328, 1, 61], [155, 211, 1, 60], [155, 330, 1, 60], [156, 210, 1, 2], [156, 213, 1, 57], [156, 331, 1, 57], [156, 389, 1, 2], [157, 210, 1, 3], [157, 214, 1, 2], [157, 217, 1, 12], [157, 231, 1, 29], [157, 264, 1, 4], [157, 333, 1, 4], [157, 341, 1, 29], [157, 372, 1, 12], [157, 385, 1, 2], [157, 388, 1, 3], [158, 209, 1, 4], [158, 218, 1, 11], [158, 231, 1, 29], [158, 341, 1, 29], [158, 372, 1, 11], [158, 388, 1, 4], [159, 209, 1, 7], [159, 219, 1, 9], [159, 232, 1, 28], [159, 341, 1, 28], [159, 373, 1, 9], [159, 385, 1, 7], [160, 208, 1, 8], [160, 219, 1, 9], [160, 232, 1, 28], [160, 341, 1, 28], [160, 373, 1, 9], [160, 385, 1, 8], [161, 208, 1, 9], [161, 220, 1, 2], [161, 232, 1, 28], [161, 341, 1, 28], [161, 379, 1, 2], [161, 384, 1, 9], [162, 208, 1, 8], [162, 238, 1, 22], [162, 341, 1, 22], [162, 385, 1, 8], [163, 208, 1, 10], [163, 238, 1, 21], [163, 342, 1, 21], [163, 383, 1, 10], [164, 207, 1, 11], [164, 238, 1, 20], [164, 343, 1, 20], [164, 383, 1, 11], [165, 207, 1, 10], [165, 239, 1, 18], [165, 344, 1, 18], [165, 384, 1, 10], [166, 207, 1, 10], [166, 219, 1, 3], [166, 240, 1, 16], [166, 345, 1, 16], [166, 379, 1, 3], [166, 384, 1, 10], [167, 207, 1, 23], [167, 241, 1, 14], [167, 346, 1, 14], [167, 371, 1, 23], [168, 207, 1, 24], [168, 243, 1, 10], [168, 348, 1, 10], [168, 370, 1, 24], [169, 207, 1, 25], [169, 369, 1, 25], [170, 207, 1, 25], [170, 369, 1, 25], [171, 207, 1, 25], [171, 369, 1, 25], [172, 207, 1, 26], [172, 368, 1, 26], [173, 207, 1, 26], [173, 368, 1, 26], [174, 207, 1, 26], [174, 368, 1, 26], [175, 207, 1, 26], [175, 368, 1, 26], [176, 207, 1, 26], [176, 368, 1, 26], [177, 208, 1, 26], [177, 367, 1, 26], [178, 208, 1, 26], [178, 367, 1, 26], [179, 208, 1, 26], [179, 367, 1, 26], [180, 208, 1, 25], [180, 368, 1, 25], [181, 209, 1, 24], [181, 368, 1, 24], [182, 209, 1, 24], [182, 368, 1, 24], [183, 209, 1, 22], [183, 370, 1, 22], [184, 209, 1, 22], [184, 370, 1, 22], [185, 210, 1, 22], [185, 369, 1, 22], [186, 210, 1, 24], [186, 367, 1, 24], [187, 210, 1, 25], [187, 366, 1, 25], [188, 210, 1, 25], [188, 366, 1, 25], [189, 211, 1, 25], [189, 365, 1, 25], [190, 211, 1, 26], [190, 364, 1, 26], [191, 211, 1, 26], [191, 364, 1, 26], [192, 211, 1, 26], [192, 364, 1, 26], [193, 212, 1, 26], [193, 363, 1, 26], [194, 212, 1, 26], [194, 363, 1, 26], [195, 212, 1, 26], [195, 363, 1, 26], [196, 212, 1, 25], [196, 364, 1, 25], [197, 212, 1, 25], [197, 364, 1, 25], [198, 213, 1, 24], [198, 364, 1, 24], [199, 213, 1, 23], [199, 365, 1, 23], [200, 213, 1, 22], [200, 366, 1, 22], [201, 213, 1, 21], [201, 367, 1, 21], [202, 213, 1, 15], [202, 373, 1, 15], [203, 213, 1, 14], [203, 374, 1, 14], [204, 213, 1, 14], [204, 374, 1, 14], [205, 213, 1, 14], [205, 374, 1, 14], [206, 213, 1, 10], [206, 378, 1, 10], [207, 213, 1, 8], [207, 380, 1, 8], [208, 213, 1, 9], [208, 379, 1, 9], [209, 213, 1, 11], [209, 377, 1, 11], [210, 213, 1, 12], [210, 376, 1, 12], [211, 213, 1, 12], [211, 228, 1, 1], [211, 372, 1, 1], [211, 376, 1, 12], [212, 213, 1, 18], [212, 370, 1, 18], [213, 213, 1, 19], [213, 369, 1, 19], [214, 212, 1, 21], [214, 368, 1, 21], [215, 212, 1, 21], [215, 368, 1, 21], [216, 212, 1, 22], [216, 367, 1, 22], [217, 212, 1, 23], [217, 366, 1, 23], [218, 211, 1, 24], [218, 366, 1, 24], [219, 211, 1, 25], [219, 365, 1, 25], [220, 211, 1, 25], [220, 365, 1, 25], [221, 210, 1, 26], [221, 365, 1, 26], [222, 210, 1, 27], [222, 364, 1, 27], [223, 210, 1, 27], [223, 364, 1, 27], [224, 209, 1, 28], [224, 364, 1, 28], [225, 209, 1, 27], [225, 365, 1, 27], [226, 208, 1, 28], [226, 365, 1, 28], [227, 208, 1, 27], [227, 366, 1, 27], [228, 207, 1, 27], [228, 367, 1, 27], [229, 207, 1, 27], [229, 367, 1, 27], [230, 206, 1, 29], [230, 366, 1, 29], [231, 206, 1, 31], [231, 364, 1, 31], [232, 205, 1, 34], [232, 362, 1, 34], [233, 204, 1, 36], [233, 361, 1, 36], [234, 204, 1, 36], [234, 361, 1, 36], [235, 203, 1, 38], [235, 360, 1, 38], [236, 202, 1, 40], [236, 359, 1, 40], [237, 201, 1, 41], [237, 359, 1, 41], [238, 201, 1, 42], [238, 358, 1, 42], [239, 200, 1, 43], [239, 358, 1, 43], [240, 199, 1, 45], [240, 357, 1, 45], [241, 198, 1, 46], [241, 357, 1, 46], [242, 197, 1, 48], [242, 356, 1, 48], [243, 196, 1, 49], [243, 356, 1, 49], [244, 196, 1, 49], [244, 356, 1, 49], [245, 195, 1, 51], [245, 355, 1, 51], [246, 194, 1, 52], [246, 355, 1, 52], [247, 193, 1, 53], [247, 355, 1, 53], [248, 192, 1, 54], [248, 355, 1, 54], [249, 191, 1, 55], [249, 355, 1, 55], [250, 190, 1, 56], [250, 355, 1, 56], [251, 189, 1, 57], [251, 355, 1, 57], [252, 188, 1, 58], [252, 355, 1, 58], [253, 187, 1, 59], [253, 355, 1, 59], [254, 186, 1, 59], [254, 356, 1, 59], [255, 185, 1, 60], [255, 356, 1, 60], [256, 184, 1, 61], [256, 356, 1, 61], [257, 183, 1, 61], [257, 357, 1, 61], [258, 181, 1, 62], [258, 358, 1, 62], [259, 180, 1, 63], [259, 358, 1, 63], [260, 179, 1, 62], [260, 360, 1, 62], [261, 178, 1, 62], [261, 361, 1, 62], [262, 177, 1, 61], [262, 363, 1, 61], [263, 176, 1, 55], [263, 370, 1, 55], [264, 175, 1, 53], [264, 373, 1, 53], [265, 174, 1, 52], [265, 375, 1, 52], [266, 173, 1, 52], [266, 376, 1, 52], [267, 172, 1, 53], [267, 376, 1, 53], [268, 171, 1, 53], [268, 377, 1, 53], [269, 170, 1, 35], [269, 208, 1, 15], [269, 378, 1, 15], [269, 396, 1, 35], [270, 169, 1, 36], [270, 213, 1, 9], [270, 379, 1, 9], [270, 396, 1, 36], [271, 168, 1, 36], [271, 397, 1, 36], [272, 167, 1, 37], [272, 397, 1, 37], [273, 166, 1, 38], [273, 397, 1, 38], [274, 165, 1, 39], [274, 397, 1, 39], [275, 164, 1, 40], [275, 397, 1, 40], [276, 163, 1, 40], [276, 398, 1, 40], [277, 162, 1, 40], [277, 399, 1, 40], [278, 161, 1, 39], [278, 401, 1, 39], [279, 161, 1, 39], [279, 401, 1, 39], [280, 160, 1, 39], [280, 402, 1, 39], [281, 159, 1, 40], [281, 402, 1, 40], [282, 158, 1, 41], [282, 402, 1, 41], [283, 157, 1, 42], [283, 402, 1, 42], [284, 157, 1, 6], [284, 165, 1, 34], [284, 402, 1, 34], [284, 438, 1, 6], [285, 156, 1, 7], [285, 165, 1, 34], [285, 402, 1, 34], [285, 438, 1, 7], [286, 155, 1, 8], [286, 168, 1, 9], [286, 180, 1, 19], [286, 402, 1, 19], [286, 424, 1, 9], [286, 438, 1, 8], [287, 155, 1, 8], [287, 169, 1, 5], [287, 180, 1, 18], [287, 403, 1, 18], [287, 427, 1, 5], [287, 438, 1, 8], [288, 154, 1, 9], [288, 169, 1, 4], [288, 181, 1, 16], [288, 404, 1, 16], [288, 428, 1, 4], [288, 438, 1, 9], [289, 153, 1, 9], [289, 182, 1, 14], [289, 405, 1, 14], [289, 439, 1, 9], [290, 153, 1, 9], [290, 183, 1, 11], [290, 407, 1, 11], [290, 439, 1, 9], [291, 152, 1, 11], [291, 438, 1, 11], [292, 151, 1, 14], [292, 436, 1, 14], [293, 151, 1, 15], [293, 435, 1, 15], [294, 150, 1, 15], [294, 436, 1, 15], [295, 149, 1, 16], [295, 436, 1, 16], [296, 149, 1, 15], [296, 437, 1, 15], [297, 148, 1, 16], [297, 437, 1, 16], [298, 148, 1, 16], [298, 437, 1, 16], [299, 147, 1, 17], [299, 437, 1, 17], [300, 147, 1, 17], [300, 437, 1, 17], [301, 146, 1, 18], [301, 437, 1, 18], [302, 146, 1, 16], [302, 439, 1, 16], [303, 145, 1, 16], [303, 440, 1, 16], [304, 145, 1, 14], [304, 442, 1, 14], [305, 144, 1, 15], [305, 442, 1, 15], [306, 144, 1, 17], [306, 440, 1, 17], [307, 143, 1, 18], [307, 440, 1, 18], [308, 143, 1, 18], [308, 440, 1, 18], [309, 142, 1, 20], [309, 439, 1, 20], [310, 142, 1, 25], [310, 434, 1, 25], [311, 141, 1, 27], [311, 433, 1, 27], [312, 141, 1, 28], [312, 432, 1, 28], [313, 140, 1, 30], [313, 431, 1, 30], [314, 140, 1, 30], [314, 431, 1, 30], [315, 139, 1, 32], [315, 430, 1, 32], [316, 139, 1, 32], [316, 430, 1, 32], [317, 138, 1, 33], [317, 430, 1, 33], [318, 138, 1, 34], [318, 429, 1, 34], [319, 138, 1, 34], [319, 429, 1, 34], [320, 137, 1, 35], [320, 429, 1, 35], [321, 137, 1, 35], [321, 429, 1, 35], [322, 136, 1, 36], [322, 429, 1, 36], [323, 136, 1, 35], [323, 430, 1, 35], [324, 135, 1, 36], [324, 430, 1, 36], [325, 135, 1, 35], [325, 431, 1, 35], [326, 134, 1, 36], [326, 431, 1, 36], [327, 133, 1, 35], [327, 433, 1, 35], [328, 133, 1, 32], [328, 436, 1, 32], [329, 132, 1, 32], [329, 437, 1, 32], [330, 132, 1, 31], [330, 438, 1, 31], [331, 131, 1, 32], [331, 438, 1, 32], [332, 131, 1, 32], [332, 438, 1, 32], [333, 130, 1, 33], [333, 438, 1, 33], [334, 129, 1, 34], [334, 438, 1, 34], [335, 129, 1, 34], [335, 438, 1, 34], [336, 128, 1, 35], [336, 438, 1, 35], [337, 127, 1, 36], [337, 438, 1, 36], [338, 126, 1, 37], [338, 438, 1, 37], [339, 126, 1, 37], [339, 438, 1, 37], [340, 125, 1, 38], [340, 438, 1, 38], [341, 124, 1, 39], [341, 438, 1, 39], [342, 123, 1, 41], [342, 437, 1, 41], [343, 122, 1, 42], [343, 437, 1, 42], [344, 121, 1, 43], [344, 437, 1, 43], [345, 120, 1, 44], [345, 437, 1, 44], [346, 119, 1, 45], [346, 437, 1, 45], [347, 117, 1, 46], [347, 438, 1, 46], [348, 116, 1, 15], [348, 132, 1, 31], [348, 438, 1, 31], [348, 470, 1, 15], [349, 115, 1, 15], [349, 133, 1, 29], [349, 439, 1, 29], [349, 471, 1, 15], [350, 113, 1, 16], [350, 134, 1, 27], [350, 440, 1, 27], [350, 472, 1, 16], [351, 111, 1, 18], [351, 135, 1, 25], [351, 441, 1, 25], [351, 472, 1, 18], [352, 109, 1, 20], [352, 136, 1, 12], [352, 153, 1, 4], [352, 444, 1, 4], [352, 453, 1, 12], [352, 472, 1, 20], [353, 107, 1, 22], [353, 137, 1, 9], [353, 455, 1, 9], [353, 472, 1, 22], [354, 104, 1, 25], [354, 139, 1, 4], [354, 458, 1, 4], [354, 472, 1, 25], [355, 101, 1, 27], [355, 473, 1, 27], [356, 96, 1, 31], [356, 474, 1, 31], [357, 88, 1, 39], [357, 474, 1, 39], [358, 83, 1, 40], [358, 478, 1, 40], [359, 80, 1, 43], [359, 478, 1, 43], [360, 78, 1, 45], [360, 478, 1, 45], [361, 77, 1, 46], [361, 478, 1, 46], [362, 76, 1, 48], [362, 477, 1, 48], [363, 75, 1, 50], [363, 476, 1, 50], [364, 74, 1, 3], [364, 78, 1, 47], [364, 476, 1, 47], [364, 524, 1, 3], [365, 74, 1, 3], [365, 78, 1, 47], [365, 476, 1, 47], [365, 524, 1, 3], [366, 73, 1, 4], [366, 80, 1, 45], [366, 476, 1, 45], [366, 524, 1, 4], [367, 73, 1, 6], [367, 81, 1, 44], [367, 476, 1, 44], [367, 522, 1, 6], [368, 73, 1, 6], [368, 82, 1, 42], [368, 477, 1, 42], [368, 522, 1, 6], [369, 73, 1, 7], [369, 82, 1, 41], [369, 478, 1, 41], [369, 521, 1, 7], [370, 73, 1, 7], [370, 82, 1, 39], [370, 480, 1, 39], [370, 521, 1, 7], [371, 73, 1, 8], [371, 85, 1, 3], [371, 91, 1, 3], [371, 98, 1, 22], [371, 481, 1, 22], [371, 507, 1, 3], [371, 513, 1, 3], [371, 520, 1, 8], [372, 74, 1, 8], [372, 98, 1, 21], [372, 482, 1, 21], [372, 519, 1, 8], [373, 74, 1, 7], [373, 98, 1, 20], [373, 483, 1, 20], [373, 520, 1, 7], [374, 74, 1, 7], [374, 85, 1, 1], [374, 98, 1, 19], [374, 484, 1, 19], [374, 515, 1, 1], [374, 520, 1, 7], [375, 75, 1, 5], [375, 82, 1, 6], [375, 99, 1, 18], [375, 484, 1, 18], [375, 513, 1, 6], [375, 521, 1, 5], [376, 76, 1, 2], [376, 80, 1, 10], [376, 100, 1, 16], [376, 485, 1, 16], [376, 511, 1, 10], [376, 523, 1, 2], [377, 76, 1, 3], [377, 80, 1, 10], [377, 103, 1, 12], [377, 486, 1, 12], [377, 511, 1, 10], [377, 522, 1, 3], [378, 77, 1, 13], [378, 105, 1, 8], [378, 488, 1, 8], [378, 511, 1, 13], [379, 78, 1, 11], [379, 512, 1, 11], [380, 79, 1, 16], [380, 506, 1, 16], [381, 80, 1, 15], [381, 506, 1, 15], [382, 80, 1, 15], [382, 506, 1, 15], [383, 81, 1, 17], [383, 503, 1, 17], [384, 82, 1, 18], [384, 501, 1, 18], [385, 82, 1, 19], [385, 500, 1, 19], [386, 83, 1, 19], [386, 499, 1, 19], [387, 84, 1, 19], [387, 498, 1, 19], [388, 84, 1, 19], [388, 498, 1, 19], [389, 84, 1, 19], [389, 498, 1, 19], [390, 85, 1, 18], [390, 498, 1, 18], [391, 85, 1, 18], [391, 498, 1, 18], [392, 85, 1, 17], [392, 499, 1, 17], [393, 86, 1, 14], [393, 501, 1, 14], [394, 86, 1, 14], [394, 110, 1, 4], [394, 487, 1, 4], [394, 501, 1, 14], [395, 86, 1, 14], [395, 109, 1, 7], [395, 485, 1, 7], [395, 501, 1, 14], [396, 87, 1, 14], [396, 108, 1, 10], [396, 483, 1, 10], [396, 500, 1, 14], [397, 87, 1, 13], [397, 108, 1, 11], [397, 482, 1, 11], [397, 501, 1, 13], [398, 88, 1, 12], [398, 107, 1, 16], [398, 478, 1, 16], [398, 501, 1, 12], [399, 88, 1, 12], [399, 107, 1, 19], [399, 475, 1, 19], [399, 501, 1, 12], [400, 88, 1, 12], [400, 106, 1, 21], [400, 474, 1, 21], [400, 501, 1, 12], [401, 89, 1, 11], [401, 105, 1, 23], [401, 473, 1, 23], [401, 501, 1, 11], [402, 89, 1, 8], [402, 105, 1, 23], [402, 473, 1, 23], [402, 504, 1, 8], [403, 90, 1, 6], [403, 102, 1, 26], [403, 473, 1, 26], [403, 505, 1, 6], [404, 91, 1, 3], [404, 97, 1, 1], [404, 101, 1, 27], [404, 473, 1, 27], [404, 503, 1, 1], [404, 507, 1, 3], [405, 91, 1, 3], [405, 95, 1, 4], [405, 101, 1, 27], [405, 473, 1, 27], [405, 502, 1, 4], [405, 507, 1, 3], [406, 92, 1, 7], [406, 101, 1, 27], [406, 473, 1, 27], [406, 502, 1, 7], [407, 93, 1, 6], [407, 100, 1, 28], [407, 473, 1, 28], [407, 502, 1, 6], [408, 94, 1, 34], [408, 473, 1, 34], [409, 95, 1, 33], [409, 473, 1, 33], [410, 96, 1, 31], [410, 474, 1, 31], [411, 97, 1, 29], [411, 142, 1, 5], [411, 152, 1, 7], [411, 442, 1, 7], [411, 454, 1, 5], [411, 475, 1, 29], [412, 99, 1, 27], [412, 132, 1, 3], [412, 141, 1, 19], [412, 441, 1, 19], [412, 466, 1, 3], [412, 475, 1, 27], [413, 101, 1, 35], [413, 140, 1, 21], [413, 440, 1, 21], [413, 465, 1, 35], [414, 103, 1, 33], [414, 139, 1, 23], [414, 439, 1, 23], [414, 465, 1, 33], [415, 106, 1, 57], [415, 438, 1, 57], [416, 109, 1, 54], [416, 438, 1, 54], [417, 112, 1, 52], [417, 437, 1, 52], [418, 116, 1, 48], [418, 437, 1, 48], [419, 120, 1, 45], [419, 436, 1, 45], [420, 123, 1, 42], [420, 436, 1, 42], [421, 125, 1, 40], [421, 436, 1, 40], [422, 128, 1, 38], [422, 435, 1, 38], [423, 130, 1, 36], [423, 435, 1, 36], [424, 131, 1, 35], [424, 435, 1, 35], [425, 133, 1, 33], [425, 435, 1, 33], [426, 134, 1, 32], [426, 435, 1, 32], [427, 136, 1, 30], [427, 435, 1, 30], [428, 137, 1, 28], [428, 436, 1, 28], [429, 138, 1, 27], [429, 436, 1, 27], [430, 139, 1, 24], [430, 438, 1, 24], [431, 140, 1, 22], [431, 439, 1, 22], [432, 141, 1, 21], [432, 439, 1, 21], [433, 142, 1, 20], [433, 439, 1, 20], [434, 142, 1, 21], [434, 438, 1, 21], [435, 143, 1, 22], [435, 436, 1, 22], [436, 144, 1, 22], [436, 435, 1, 22], [437, 144, 1, 22], [437, 435, 1, 22], [438, 145, 1, 21], [438, 435, 1, 21], [439, 146, 1, 23], [439, 432, 1, 23], [440, 146, 1, 25], [440, 430, 1, 25], [441, 147, 1, 26], [441, 428, 1, 26], [442, 147, 1, 28], [442, 426, 1, 28], [443, 148, 1, 29], [443, 424, 1, 29], [444, 148, 1, 30], [444, 423, 1, 30], [445, 149, 1, 30], [445, 422, 1, 30], [446, 149, 1, 30], [446, 422, 1, 30], [447, 149, 1, 31], [447, 421, 1, 31], [448, 150, 1, 30], [448, 421, 1, 30], [449, 150, 1, 30], [449, 421, 1, 30], [450, 150, 1, 29], [450, 422, 1, 29], [451, 151, 1, 28], [451, 422, 1, 28], [452, 151, 1, 27], [452, 423, 1, 27], [453, 151, 1, 26], [453, 424, 1, 26], [454, 152, 1, 23], [454, 426, 1, 23], [455, 152, 1, 23], [455, 426, 1, 23], [456, 152, 1, 23], [456, 426, 1, 23], [457, 152, 1, 23], [457, 426, 1, 23], [458, 152, 1, 23], [458, 426, 1, 23], [459, 153, 1, 22], [459, 426, 1, 22], [460, 153, 1, 22], [460, 426, 1, 22], [461, 153, 1, 22], [461, 426, 1, 22], [462, 153, 1, 22], [462, 426, 1, 22], [463, 153, 1, 23], [463, 425, 1, 23], [464, 153, 1, 23], [464, 425, 1, 23], [465, 154, 1, 23], [465, 424, 1, 23], [466, 154, 1, 23], [466, 424, 1, 23], [467, 154, 1, 23], [467, 424, 1, 23], [468, 154, 1, 23], [468, 299, 1, 3], [468, 424, 1, 23], [469, 154, 1, 22], [469, 296, 1, 9], [469, 425, 1, 22], [470, 155, 1, 20], [470, 295, 1, 11], [470, 426, 1, 20], [471, 155, 1, 18], [471, 294, 1, 13], [471, 428, 1, 18], [472, 155, 1, 16], [472, 293, 1, 15], [472, 430, 1, 16], [473, 155, 1, 14], [473, 292, 1, 17], [473, 432, 1, 14], [474, 156, 1, 4], [474, 161, 1, 6], [474, 204, 1, 4], [474, 291, 1, 19], [474, 393, 1, 4], [474, 434, 1, 6], [474, 441, 1, 4], [475, 156, 1, 4], [475, 202, 1, 8], [475, 289, 1, 23], [475, 391, 1, 8], [475, 441, 1, 4], [476, 156, 1, 4], [476, 202, 1, 9], [476, 289, 1, 23], [476, 390, 1, 9], [476, 441, 1, 4], [477, 157, 1, 6], [477, 200, 1, 13], [477, 287, 1, 27], [477, 388, 1, 13], [477, 438, 1, 6], [478, 157, 1, 7], [478, 198, 1, 18], [478, 285, 1, 31], [478, 385, 1, 18], [478, 437, 1, 7], [479, 158, 1, 6], [479, 169, 1, 5], [479, 190, 1, 5], [479, 196, 1, 23], [479, 284, 1, 33], [479, 382, 1, 23], [479, 406, 1, 5], [479, 427, 1, 5], [479, 437, 1, 6], [480, 158, 1, 5], [480, 165, 1, 1], [480, 168, 1, 8], [480, 190, 1, 30], [480, 284, 1, 33], [480, 381, 1, 30], [480, 425, 1, 8], [480, 435, 1, 1], [480, 438, 1, 5], [481, 159, 1, 18], [481, 190, 1, 31], [481, 282, 1, 37], [481, 380, 1, 31], [481, 424, 1, 18], [482, 160, 1, 17], [482, 190, 1, 31], [482, 280, 1, 41], [482, 380, 1, 31], [482, 424, 1, 17], [483, 161, 1, 17], [483, 190, 1, 32], [483, 276, 1, 49], [483, 379, 1, 32], [483, 423, 1, 17], [484, 162, 1, 16], [484, 182, 1, 4], [484, 190, 1, 32], [484, 276, 1, 49], [484, 379, 1, 32], [484, 415, 1, 4], [484, 423, 1, 16], [485, 163, 1, 14], [485, 181, 1, 5], [485, 188, 1, 35], [485, 275, 1, 51], [485, 378, 1, 35], [485, 415, 1, 5], [485, 424, 1, 14], [486, 164, 1, 13], [486, 181, 1, 42], [486, 243, 1, 5], [486, 264, 1, 3], [486, 274, 1, 53], [486, 334, 1, 3], [486, 353, 1, 5], [486, 378, 1, 42], [486, 424, 1, 13], [487, 165, 1, 11], [487, 180, 1, 43], [487, 241, 1, 8], [487, 263, 1, 5], [487, 272, 1, 57], [487, 333, 1, 5], [487, 352, 1, 8], [487, 378, 1, 43], [487, 425, 1, 11], [488, 167, 1, 56], [488, 240, 1, 10], [488, 263, 1, 75], [488, 351, 1, 10], [488, 378, 1, 56], [489, 169, 1, 54], [489, 239, 1, 11], [489, 262, 1, 77], [489, 351, 1, 11], [489, 378, 1, 54], [490, 171, 1, 52], [490, 238, 1, 12], [490, 262, 1, 77], [490, 351, 1, 12], [490, 378, 1, 52], [491, 175, 1, 47], [491, 238, 1, 12], [491, 261, 1, 79], [491, 351, 1, 12], [491, 379, 1, 47], [492, 183, 1, 38], [492, 238, 1, 12], [492, 260, 1, 81], [492, 351, 1, 12], [492, 380, 1, 38], [493, 192, 1, 26], [493, 237, 1, 14], [493, 255, 1, 2], [493, 258, 1, 85], [493, 344, 1, 2], [493, 350, 1, 14], [493, 383, 1, 26], [494, 197, 1, 21], [494, 236, 1, 129], [494, 383, 1, 21], [495, 201, 1, 18], [495, 226, 1, 2], [495, 236, 1, 50], [495, 315, 1, 50], [495, 373, 1, 2], [495, 382, 1, 18], [496, 204, 1, 17], [496, 225, 1, 4], [496, 232, 1, 47], [496, 322, 1, 47], [496, 372, 1, 4], [496, 380, 1, 17], [497, 207, 1, 22], [497, 232, 1, 41], [497, 328, 1, 41], [497, 372, 1, 22], [498, 210, 1, 59], [498, 332, 1, 59], [499, 213, 1, 51], [499, 337, 1, 51], [500, 216, 1, 44], [500, 341, 1, 44], [501, 219, 1, 37], [501, 345, 1, 37], [502, 223, 1, 28], [502, 350, 1, 28], [503, 229, 1, 16], [503, 356, 1, 16]], [[46, 298, 1, 2], [46, 301, 1, 2], [47, 299, 1, 1], [47, 301, 1, 1], [57, 299, 1, 1], [57, 301, 1, 1], [58, 299, 1, 1], [58, 301, 1, 1], [59, 299, 1, 1], [59, 301, 1, 1], [60, 299, 1, 1], [60, 301, 1, 1], [61, 296, 1, 3], [61, 302, 1, 3], [62, 296, 1, 2], [62, 303, 1, 2], [63, 297, 1, 1], [63, 303, 1, 1], [64, 288, 1, 1], [64, 290, 1, 7], [64, 304, 1, 7], [64, 312, 1, 1], [65, 291, 1, 3], [65, 295, 1, 2], [65, 304, 1, 2], [65, 307, 1, 3], [66, 293, 1, 3], [66, 305, 1, 3], [67, 295, 1, 1], [67, 305, 1, 1], [68, 295, 1, 2], [68, 304, 1, 2], [69, 295, 1, 3], [69, 303, 1, 3], [70, 295, 1, 1], [70, 298, 1, 2], [70, 301, 1, 2], [70, 305, 1, 1], [71, 298, 1, 2], [71, 301, 1, 2], [72, 299, 1, 1], [72, 301, 1, 1], [73, 299, 1, 1], [73, 301, 1, 1], [74, 299, 1, 1], [74, 301, 1, 1], [75, 299, 1, 1], [75, 301, 1, 1], [76, 299, 1, 1], [76, 301, 1, 1], [77, 299, 1, 1], [77, 301, 1, 1], [78, 299, 1, 1], [78, 301, 1, 1], [80, 299, 1, 1], [80, 301, 1, 1], [81, 299, 1, 1], [81, 301, 1, 1], [82, 298, 1, 2], [82, 301, 1, 2], [83, 298, 1, 2], [83, 301, 1, 2], [84, 299, 1, 1], [84, 301, 1, 1], [85, 299, 1, 1], [85, 301, 1, 1], [86, 299, 1, 1], [86, 301, 1, 1], [87, 299, 1, 1], [87, 301, 1, 1], [88, 298, 1, 2], [88, 301, 1, 2], [89, 297, 1, 3], [89, 301, 1, 3], [90, 295, 1, 4], [90, 302, 1, 4], [91, 294, 1, 2], [91, 297, 1, 2], [91, 302, 1, 2], [91, 305, 1, 2], [92, 294, 1, 5], [92, 302, 1, 5], [93, 296, 1, 3], [93, 302, 1, 3], [94, 297, 1, 3], [94, 301, 1, 3], [95, 297, 1, 3], [95, 301, 1, 3], [96, 298, 1, 2], [96, 301, 1, 2], [97, 299, 1, 1], [97, 301, 1, 1], [98, 299, 1, 1], [98, 301, 1, 1], [99, 298, 1, 2], [99, 301, 1, 2], [100, 298, 1, 2], [100, 301, 1, 2], [101, 297, 1, 3], [101, 301, 1, 3], [102, 297, 1, 2], [102, 302, 1, 2], [103, 297, 1, 3], [103, 301, 1, 3], [104, 298, 1, 2], [104, 301, 1, 2], [105, 299, 1, 1], [105, 301, 1, 1], [106, 299, 1, 1], [106, 301, 1, 1], [107, 298, 1, 2], [107, 301, 1, 2], [108, 298, 1, 2], [108, 301, 1, 2], [109, 298, 1, 2], [109, 301, 1, 2], [110, 298, 1, 2], [110, 301, 1, 2], [111, 297, 1, 3], [111, 301, 1, 3], [112, 297, 1, 1], [112, 303, 1, 1], [113, 297, 1, 3], [113, 301, 1, 3], [114, 296, 1, 4], [114, 301, 1, 4], [115, 296, 1, 4], [115, 301, 1, 4], [116, 295, 1, 4], [116, 302, 1, 4], [117, 294, 1, 6], [117, 301, 1, 6], [118, 290, 1, 3], [118, 294, 1, 5], [118, 302, 1, 5], [118, 308, 1, 3], [119, 291, 1, 1], [119, 296, 1, 2], [119, 303, 1, 2], [119, 309, 1, 1], [120, 292, 1, 2], [120, 307, 1, 2], [121, 292, 1, 5], [121, 304, 1, 5], [122, 292, 1, 6], [122, 303, 1, 6], [123, 292, 1, 6], [123, 303, 1, 6], [124, 292, 1, 7], [124, 302, 1, 7], [125, 292, 1, 6], [125, 303, 1, 6], [126, 292, 1, 4], [126, 305, 1, 4], [127, 291, 1, 6], [127, 304, 1, 6], [128, 291, 1, 7], [128, 303, 1, 7], [129, 290, 1, 8], [129, 303, 1, 8], [130, 289, 1, 8], [130, 304, 1, 8], [131, 268, 1, 1], [131, 270, 1, 1], [131, 274, 1, 2], [131, 288, 1, 2], [131, 292, 1, 4], [131, 305, 1, 4], [131, 311, 1, 2], [131, 325, 1, 2], [131, 330, 1, 1], [131, 332, 1, 1], [132, 269, 1, 1], [132, 271, 1, 6], [132, 286, 1, 4], [132, 293, 1, 3], [132, 305, 1, 3], [132, 311, 1, 4], [132, 324, 1, 6], [132, 331, 1, 1], [133, 270, 1, 1], [133, 272, 1, 2], [133, 275, 1, 3], [133, 284, 1, 7], [133, 310, 1, 7], [133, 323, 1, 3], [133, 327, 1, 2], [133, 330, 1, 1], [134, 270, 1, 1], [134, 276, 1, 16], [134, 309, 1, 16], [134, 330, 1, 1], [135, 270, 1, 5], [135, 278, 1, 14], [135, 309, 1, 14], [135, 326, 1, 5], [136, 270, 1, 5], [136, 280, 1, 12], [136, 309, 1, 12], [136, 326, 1, 5], [137, 273, 1, 4], [137, 280, 1, 11], [137, 310, 1, 11], [137, 324, 1, 4], [138, 275, 1, 4], [138, 282, 1, 2], [138, 286, 1, 3], [138, 312, 1, 3], [138, 317, 1, 2], [138, 322, 1, 4], [139, 275, 1, 5], [139, 287, 1, 2], [139, 312, 1, 2], [139, 321, 1, 5], [140, 275, 1, 5], [140, 321, 1, 5], [141, 276, 1, 5], [141, 320, 1, 5], [142, 276, 1, 4], [142, 321, 1, 4], [143, 276, 1, 7], [143, 318, 1, 7], [144, 276, 1, 7], [144, 318, 1, 7], [145, 276, 1, 7], [145, 318, 1, 7], [146, 276, 1, 7], [146, 318, 1, 7], [147, 276, 1, 7], [147, 318, 1, 7], [148, 276, 1, 7], [148, 318, 1, 7], [149, 276, 1, 2], [149, 279, 1, 1], [149, 321, 1, 1], [149, 323, 1, 2], [150, 275, 1, 2], [150, 324, 1, 2], [151, 275, 1, 2], [151, 324, 1, 2], [152, 274, 1, 7], [152, 320, 1, 7], [153, 274, 1, 8], [153, 319, 1, 8], [154, 273, 1, 9], [154, 319, 1, 9], [155, 271, 1, 11], [155, 319, 1, 11], [156, 212, 1, 1], [156, 270, 1, 11], [156, 320, 1, 11], [156, 388, 1, 1], [157, 213, 1, 1], [157, 216, 1, 1], [157, 229, 1, 2], [157, 260, 1, 4], [157, 268, 1, 14], [157, 319, 1, 14], [157, 337, 1, 4], [157, 370, 1, 2], [157, 384, 1, 1], [157, 387, 1, 1], [158, 213, 1, 2], [158, 217, 1, 1], [158, 229, 1, 1], [158, 260, 1, 1], [158, 262, 1, 20], [158, 319, 1, 20], [158, 340, 1, 1], [158, 371, 1, 1], [158, 383, 1, 1], [158, 386, 1, 2], [159, 216, 1, 1], [159, 218, 1, 1], [159, 228, 1, 2], [159, 231, 1, 1], [159, 260, 1, 1], [159, 265, 1, 17], [159, 319, 1, 17], [159, 340, 1, 1], [159, 369, 1, 1], [159, 371, 1, 2], [159, 382, 1, 1], [159, 384, 1, 1], [160, 216, 1, 3], [160, 228, 1, 1], [160, 230, 1, 2], [160, 260, 1, 1], [160, 265, 1, 17], [160, 319, 1, 17], [160, 340, 1, 1], [160, 369, 1, 2], [160, 372, 1, 1], [160, 382, 1, 3], [161, 218, 1, 2], [161, 222, 1, 7], [161, 230, 1, 2], [161, 260, 1, 2], [161, 266, 1, 9], [161, 278, 1, 3], [161, 320, 1, 3], [161, 326, 1, 9], [161, 339, 1, 2], [161, 369, 1, 2], [161, 372, 1, 7], [161, 381, 1, 2], [162, 216, 1, 2], [162, 219, 1, 4], [162, 224, 1, 5], [162, 230, 1, 6], [162, 237, 1, 1], [162, 260, 1, 4], [162, 267, 1, 8], [162, 326, 1, 8], [162, 337, 1, 4], [162, 363, 1, 1], [162, 365, 1, 6], [162, 372, 1, 5], [162, 378, 1, 4], [162, 383, 1, 2], [163, 218, 1, 1], [163, 220, 1, 3], [163, 233, 1, 3], [163, 237, 1, 1], [163, 259, 1, 5], [163, 267, 1, 7], [163, 327, 1, 7], [163, 337, 1, 5], [163, 363, 1, 1], [163, 365, 1, 3], [163, 378, 1, 3], [163, 382, 1, 1], [164, 218, 1, 1], [164, 220, 1, 2], [164, 226, 1, 5], [164, 236, 1, 2], [164, 258, 1, 7], [164, 268, 1, 1], [164, 271, 1, 3], [164, 327, 1, 3], [164, 332, 1, 1], [164, 336, 1, 7], [164, 363, 1, 2], [164, 370, 1, 5], [164, 379, 1, 2], [164, 382, 1, 1], [165, 217, 1, 1], [165, 220, 1, 4], [165, 225, 1, 6], [165, 236, 1, 3], [165, 257, 1, 7], [165, 337, 1, 7], [165, 362, 1, 3], [165, 370, 1, 6], [165, 377, 1, 4], [165, 383, 1, 1], [166, 217, 1, 2], [166, 222, 1, 12], [166, 237, 1, 1], [166, 239, 1, 1], [166, 256, 1, 8], [166, 337, 1, 8], [166, 361, 1, 1], [166, 363, 1, 1], [166, 367, 1, 12], [166, 382, 1, 2], [167, 230, 1, 5], [167, 238, 1, 3], [167, 255, 1, 9], [167, 337, 1, 9], [167, 360, 1, 3], [167, 366, 1, 5], [168, 231, 1, 5], [168, 238, 1, 5], [168, 253, 1, 8], [168, 340, 1, 8], [168, 358, 1, 5], [168, 365, 1, 5], [169, 232, 1, 5], [169, 238, 1, 24], [169, 339, 1, 24], [169, 364, 1, 5], [170, 232, 1, 4], [170, 238, 1, 13], [170, 252, 1, 10], [170, 339, 1, 10], [170, 350, 1, 13], [170, 365, 1, 4], [171, 232, 1, 4], [171, 238, 1, 13], [171, 254, 1, 8], [171, 339, 1, 8], [171, 350, 1, 13], [171, 365, 1, 4], [172, 233, 1, 2], [172, 239, 1, 12], [172, 254, 1, 7], [172, 340, 1, 7], [172, 350, 1, 12], [172, 366, 1, 2], [173, 233, 1, 3], [173, 239, 1, 12], [173, 254, 1, 6], [173, 341, 1, 6], [173, 350, 1, 12], [173, 365, 1, 3], [174, 233, 1, 3], [174, 240, 1, 1], [174, 244, 1, 7], [174, 255, 1, 4], [174, 342, 1, 4], [174, 350, 1, 7], [174, 360, 1, 1], [174, 365, 1, 3], [175, 233, 1, 1], [175, 244, 1, 6], [175, 256, 1, 2], [175, 343, 1, 2], [175, 351, 1, 6], [175, 367, 1, 1], [176, 233, 1, 4], [176, 244, 1, 3], [176, 354, 1, 3], [176, 364, 1, 4], [177, 234, 1, 3], [177, 364, 1, 3], [178, 234, 1, 2], [178, 365, 1, 2], [179, 234, 1, 4], [179, 363, 1, 4], [180, 233, 1, 5], [180, 363, 1, 5], [181, 233, 1, 5], [181, 363, 1, 5], [182, 233, 1, 4], [182, 364, 1, 4], [183, 231, 1, 2], [183, 368, 1, 2], [184, 234, 1, 2], [184, 365, 1, 2], [185, 232, 1, 5], [185, 364, 1, 5], [186, 234, 1, 7], [186, 360, 1, 7], [187, 235, 1, 6], [187, 360, 1, 6], [188, 235, 1, 6], [188, 360, 1, 6], [189, 236, 1, 4], [189, 361, 1, 4], [190, 237, 1, 2], [190, 362, 1, 2], [191, 237, 1, 1], [191, 241, 1, 1], [191, 359, 1, 1], [191, 363, 1, 1], [192, 237, 1, 6], [192, 358, 1, 6], [193, 238, 1, 6], [193, 357, 1, 6], [194, 238, 1, 8], [194, 355, 1, 8], [195, 238, 1, 8], [195, 355, 1, 8], [196, 237, 1, 8], [196, 356, 1, 8], [197, 237, 1, 7], [197, 357, 1, 7], [198, 237, 1, 6], [198, 358, 1, 6], [199, 236, 1, 7], [199, 358, 1, 7], [200, 235, 1, 9], [200, 357, 1, 9], [201, 234, 1, 11], [201, 356, 1, 11], [202, 228, 1, 17], [202, 356, 1, 17], [203, 227, 1, 1], [203, 229, 1, 3], [203, 233, 1, 11], [203, 357, 1, 11], [203, 369, 1, 3], [203, 373, 1, 1], [204, 227, 1, 1], [204, 230, 1, 1], [204, 235, 1, 8], [204, 358, 1, 8], [204, 370, 1, 1], [204, 373, 1, 1], [205, 236, 1, 6], [205, 359, 1, 6], [206, 223, 1, 5], [206, 237, 1, 4], [206, 360, 1, 4], [206, 373, 1, 5], [207, 221, 1, 2], [207, 225, 1, 2], [207, 230, 1, 3], [207, 238, 1, 3], [207, 360, 1, 3], [207, 368, 1, 3], [207, 374, 1, 2], [207, 378, 1, 2], [208, 222, 1, 2], [208, 226, 1, 1], [208, 229, 1, 5], [208, 367, 1, 5], [208, 374, 1, 1], [208, 377, 1, 2], [209, 228, 1, 6], [209, 367, 1, 6], [210, 225, 1, 1], [210, 228, 1, 6], [210, 367, 1, 6], [210, 375, 1, 1], [211, 226, 1, 2], [211, 229, 1, 5], [211, 367, 1, 5], [211, 373, 1, 2], [212, 231, 1, 4], [212, 366, 1, 4], [213, 232, 1, 5], [213, 364, 1, 5], [214, 233, 1, 3], [214, 365, 1, 3], [215, 233, 1, 2], [215, 366, 1, 2], [216, 234, 1, 1], [216, 236, 1, 1], [216, 364, 1, 1], [216, 366, 1, 1], [217, 235, 1, 4], [217, 362, 1, 4], [218, 235, 1, 6], [218, 360, 1, 6], [219, 236, 1, 6], [219, 359, 1, 6], [220, 236, 1, 7], [220, 358, 1, 7], [221, 236, 1, 8], [221, 357, 1, 8], [222, 237, 1, 7], [222, 357, 1, 7], [223, 237, 1, 7], [223, 357, 1, 7], [224, 237, 1, 2], [224, 362, 1, 2], [225, 236, 1, 1], [225, 238, 1, 1], [225, 362, 1, 1], [225, 364, 1, 1], [226, 236, 1, 1], [226, 364, 1, 1], [227, 235, 1, 2], [227, 364, 1, 2], [228, 234, 1, 2], [228, 365, 1, 2], [229, 234, 1, 1], [229, 239, 1, 3], [229, 359, 1, 3], [229, 366, 1, 1], [230, 235, 1, 2], [230, 238, 1, 5], [230, 358, 1, 5], [230, 364, 1, 2], [231, 237, 1, 6], [231, 358, 1, 6], [232, 239, 1, 4], [232, 358, 1, 4], [233, 240, 1, 6], [233, 355, 1, 6], [234, 240, 1, 8], [234, 353, 1, 8], [235, 241, 1, 7], [235, 353, 1, 7], [236, 242, 1, 5], [236, 354, 1, 5], [237, 242, 1, 4], [237, 355, 1, 4], [238, 243, 1, 3], [238, 355, 1, 3], [239, 243, 1, 2], [239, 356, 1, 2], [240, 244, 1, 2], [240, 248, 1, 2], [240, 351, 1, 2], [240, 355, 1, 2], [241, 244, 1, 7], [241, 350, 1, 7], [242, 245, 1, 8], [242, 348, 1, 8], [243, 245, 1, 8], [243, 348, 1, 8], [244, 245, 1, 8], [244, 348, 1, 8], [245, 246, 1, 7], [245, 348, 1, 7], [246, 246, 1, 7], [246, 348, 1, 7], [247, 246, 1, 11], [247, 344, 1, 11], [248, 246, 1, 12], [248, 343, 1, 12], [249, 246, 1, 12], [249, 343, 1, 12], [250, 246, 1, 13], [250, 342, 1, 13], [251, 246, 1, 14], [251, 341, 1, 14], [252, 246, 1, 15], [252, 340, 1, 15], [253, 246, 1, 16], [253, 339, 1, 16], [254, 245, 1, 18], [254, 338, 1, 18], [255, 245, 1, 18], [255, 338, 1, 18], [256, 245, 1, 18], [256, 338, 1, 18], [257, 244, 1, 19], [257, 338, 1, 19], [258, 243, 1, 19], [258, 339, 1, 19], [259, 243, 1, 19], [259, 339, 1, 19], [260, 241, 1, 19], [260, 341, 1, 19], [261, 240, 1, 19], [261, 342, 1, 19], [262, 238, 1, 18], [262, 345, 1, 18], [263, 231, 1, 11], [263, 243, 1, 8], [263, 350, 1, 8], [263, 359, 1, 11], [264, 228, 1, 13], [264, 245, 1, 4], [264, 352, 1, 4], [264, 360, 1, 13], [265, 226, 1, 2], [265, 230, 1, 11], [265, 360, 1, 11], [265, 373, 1, 2], [266, 225, 1, 3], [266, 232, 1, 8], [266, 361, 1, 8], [266, 373, 1, 3], [267, 225, 1, 3], [267, 233, 1, 5], [267, 363, 1, 5], [267, 373, 1, 3], [268, 224, 1, 4], [268, 234, 1, 4], [268, 363, 1, 4], [268, 373, 1, 4], [269, 205, 1, 3], [269, 223, 1, 3], [269, 235, 1, 2], [269, 364, 1, 2], [269, 375, 1, 3], [269, 393, 1, 3], [270, 205, 1, 1], [270, 207, 1, 6], [270, 222, 1, 4], [270, 375, 1, 4], [270, 388, 1, 6], [270, 395, 1, 1], [271, 204, 1, 1], [271, 208, 1, 2], [271, 213, 1, 11], [271, 377, 1, 11], [271, 391, 1, 2], [271, 396, 1, 1], [272, 208, 1, 2], [272, 213, 1, 11], [272, 377, 1, 11], [272, 391, 1, 2], [273, 204, 1, 2], [273, 213, 1, 10], [273, 378, 1, 10], [273, 395, 1, 2], [274, 204, 1, 2], [274, 216, 1, 7], [274, 378, 1, 7], [274, 395, 1, 2], [275, 204, 1, 2], [275, 216, 1, 8], [275, 377, 1, 8], [275, 395, 1, 2], [276, 203, 1, 1], [276, 216, 1, 8], [276, 377, 1, 8], [276, 397, 1, 1], [277, 202, 1, 2], [277, 217, 1, 7], [277, 377, 1, 7], [277, 397, 1, 2], [278, 200, 1, 4], [278, 221, 1, 2], [278, 378, 1, 2], [278, 397, 1, 4], [280, 199, 1, 1], [280, 401, 1, 1], [281, 199, 1, 2], [281, 400, 1, 2], [282, 199, 1, 2], [282, 400, 1, 2], [283, 199, 1, 1], [283, 401, 1, 1], [284, 164, 1, 1], [284, 199, 1, 6], [284, 396, 1, 6], [284, 436, 1, 1], [285, 164, 1, 1], [285, 199, 1, 6], [285, 396, 1, 6], [285, 436, 1, 1], [286, 163, 1, 1], [286, 165, 1, 1], [286, 167, 1, 1], [286, 177, 1, 1], [286, 179, 1, 1], [286, 199, 1, 6], [286, 396, 1, 6], [286, 421, 1, 1], [286, 423, 1, 1], [286, 433, 1, 1], [286, 435, 1, 1], [286, 437, 1, 1], [287, 163, 1, 1], [287, 167, 1, 2], [287, 174, 1, 3], [287, 179, 1, 1], [287, 198, 1, 8], [287, 395, 1, 8], [287, 421, 1, 1], [287, 424, 1, 3], [287, 432, 1, 2], [287, 437, 1, 1], [288, 163, 1, 1], [288, 166, 1, 3], [288, 173, 1, 1], [288, 179, 1, 2], [288, 197, 1, 9], [288, 395, 1, 9], [288, 420, 1, 2], [288, 427, 1, 1], [288, 432, 1, 3], [288, 437, 1, 1], [289, 168, 1, 7], [289, 180, 1, 2], [289, 196, 1, 10], [289, 395, 1, 10], [289, 419, 1, 2], [289, 426, 1, 7], [290, 162, 1, 4], [290, 169, 1, 7], [290, 179, 1, 4], [290, 194, 1, 12], [290, 395, 1, 12], [290, 418, 1, 4], [290, 425, 1, 7], [290, 435, 1, 4], [291, 163, 1, 3], [291, 170, 1, 4], [291, 179, 1, 26], [291, 396, 1, 26], [291, 427, 1, 4], [291, 435, 1, 3], [292, 165, 1, 2], [292, 171, 1, 2], [292, 179, 1, 22], [292, 400, 1, 22], [292, 428, 1, 2], [292, 434, 1, 2], [293, 166, 1, 2], [293, 171, 1, 1], [293, 178, 1, 10], [293, 190, 1, 11], [293, 400, 1, 11], [293, 413, 1, 10], [293, 429, 1, 1], [293, 433, 1, 2], [294, 165, 1, 3], [294, 178, 1, 6], [294, 186, 1, 1], [294, 190, 1, 11], [294, 400, 1, 11], [294, 414, 1, 1], [294, 417, 1, 6], [294, 433, 1, 3], [295, 165, 1, 4], [295, 179, 1, 5], [295, 193, 1, 6], [295, 402, 1, 6], [295, 417, 1, 5], [295, 432, 1, 4], [296, 164, 1, 1], [296, 166, 1, 1], [296, 180, 1, 2], [296, 193, 1, 6], [296, 402, 1, 6], [296, 419, 1, 2], [296, 434, 1, 1], [296, 436, 1, 1], [297, 164, 1, 1], [297, 193, 1, 6], [297, 402, 1, 6], [297, 436, 1, 1], [298, 164, 1, 2], [298, 195, 1, 3], [298, 403, 1, 3], [298, 435, 1, 2], [299, 164, 1, 4], [299, 433, 1, 4], [300, 164, 1, 4], [300, 433, 1, 4], [301, 164, 1, 2], [301, 435, 1, 2], [302, 162, 1, 4], [302, 435, 1, 4], [303, 161, 1, 1], [303, 163, 1, 2], [303, 436, 1, 2], [303, 439, 1, 1], [304, 161, 1, 1], [304, 439, 1, 1], [305, 159, 1, 2], [305, 169, 1, 3], [305, 429, 1, 3], [305, 440, 1, 2], [306, 167, 1, 6], [306, 428, 1, 6], [307, 161, 1, 2], [307, 164, 1, 10], [307, 427, 1, 10], [307, 438, 1, 2], [308, 161, 1, 1], [308, 164, 1, 10], [308, 427, 1, 10], [308, 439, 1, 1], [309, 162, 1, 11], [309, 428, 1, 11], [310, 167, 1, 5], [310, 429, 1, 5], [311, 168, 1, 4], [311, 429, 1, 4], [312, 169, 1, 4], [312, 428, 1, 4], [313, 170, 1, 2], [313, 429, 1, 2], [314, 170, 1, 2], [314, 429, 1, 2], [315, 171, 1, 3], [315, 427, 1, 3], [316, 171, 1, 4], [316, 426, 1, 4], [317, 171, 1, 3], [317, 427, 1, 3], [318, 172, 1, 7], [318, 422, 1, 7], [319, 172, 1, 8], [319, 421, 1, 8], [320, 172, 1, 9], [320, 420, 1, 9], [321, 172, 1, 9], [321, 420, 1, 9], [322, 172, 1, 8], [322, 421, 1, 8], [323, 171, 1, 9], [323, 421, 1, 9], [324, 171, 1, 7], [324, 423, 1, 7], [325, 170, 1, 8], [325, 423, 1, 8], [326, 170, 1, 8], [326, 423, 1, 8], [327, 168, 1, 9], [327, 424, 1, 9], [328, 165, 1, 5], [328, 173, 1, 4], [328, 424, 1, 4], [328, 431, 1, 5], [329, 164, 1, 5], [329, 174, 1, 2], [329, 425, 1, 2], [329, 432, 1, 5], [330, 163, 1, 1], [330, 167, 1, 2], [330, 432, 1, 2], [330, 437, 1, 1], [331, 163, 1, 1], [331, 437, 1, 1], [332, 163, 1, 2], [332, 436, 1, 2], [333, 163, 1, 2], [333, 436, 1, 2], [334, 163, 1, 2], [334, 436, 1, 2], [335, 163, 1, 3], [335, 435, 1, 3], [336, 163, 1, 2], [336, 436, 1, 2], [337, 163, 1, 1], [337, 437, 1, 1], [338, 163, 1, 1], [338, 437, 1, 1], [339, 163, 1, 4], [339, 434, 1, 4], [340, 163, 1, 5], [340, 433, 1, 5], [341, 163, 1, 7], [341, 431, 1, 7], [342, 164, 1, 7], [342, 430, 1, 7], [343, 164, 1, 7], [343, 430, 1, 7], [344, 164, 1, 6], [344, 431, 1, 6], [345, 164, 1, 5], [345, 432, 1, 5], [346, 164, 1, 4], [346, 433, 1, 4], [347, 163, 1, 3], [347, 435, 1, 3], [348, 163, 1, 4], [348, 434, 1, 4], [349, 130, 1, 1], [349, 132, 1, 1], [349, 162, 1, 5], [349, 434, 1, 5], [349, 468, 1, 1], [349, 470, 1, 1], [350, 129, 1, 1], [350, 132, 1, 2], [350, 161, 1, 5], [350, 435, 1, 5], [350, 467, 1, 2], [350, 471, 1, 1], [351, 129, 1, 1], [351, 134, 1, 1], [351, 160, 1, 7], [351, 434, 1, 7], [351, 466, 1, 1], [351, 471, 1, 1], [352, 129, 1, 3], [352, 135, 1, 1], [352, 148, 1, 5], [352, 157, 1, 11], [352, 433, 1, 11], [352, 448, 1, 5], [352, 465, 1, 1], [352, 469, 1, 3], [353, 129, 1, 2], [353, 134, 1, 3], [353, 146, 1, 3], [353, 150, 1, 18], [353, 433, 1, 18], [353, 452, 1, 3], [353, 464, 1, 3], [353, 470, 1, 2], [354, 129, 1, 2], [354, 133, 1, 6], [354, 143, 1, 5], [354, 150, 1, 18], [354, 433, 1, 18], [354, 453, 1, 5], [354, 462, 1, 6], [354, 470, 1, 2], [355, 128, 1, 1], [355, 133, 1, 11], [355, 145, 1, 2], [355, 151, 1, 16], [355, 434, 1, 16], [355, 454, 1, 2], [355, 457, 1, 11], [355, 472, 1, 1], [356, 127, 1, 3], [356, 132, 1, 12], [356, 151, 1, 16], [356, 434, 1, 16], [356, 457, 1, 12], [356, 471, 1, 3], [357, 127, 1, 2], [357, 133, 1, 11], [357, 151, 1, 16], [357, 434, 1, 16], [357, 457, 1, 11], [357, 472, 1, 2], [358, 124, 1, 5], [358, 134, 1, 3], [358, 140, 1, 4], [358, 152, 1, 2], [358, 159, 1, 8], [358, 434, 1, 8], [358, 447, 1, 2], [358, 457, 1, 4], [358, 464, 1, 3], [358, 472, 1, 5], [359, 123, 1, 1], [359, 126, 1, 3], [359, 140, 1, 3], [359, 159, 1, 8], [359, 434, 1, 8], [359, 458, 1, 3], [359, 472, 1, 3], [359, 477, 1, 1], [360, 124, 1, 1], [360, 160, 1, 6], [360, 435, 1, 6], [360, 476, 1, 1], [361, 123, 1, 3], [361, 475, 1, 3], [362, 124, 1, 1], [362, 476, 1, 1], [363, 125, 1, 4], [363, 472, 1, 4], [364, 77, 1, 1], [364, 125, 1, 7], [364, 469, 1, 7], [364, 523, 1, 1], [365, 77, 1, 1], [365, 125, 1, 7], [365, 469, 1, 7], [365, 523, 1, 1], [366, 77, 1, 1], [366, 79, 1, 1], [366, 125, 1, 7], [366, 469, 1, 7], [366, 521, 1, 1], [366, 523, 1, 1], [367, 79, 1, 1], [367, 125, 1, 7], [367, 469, 1, 7], [367, 521, 1, 1], [368, 79, 1, 1], [368, 81, 1, 1], [368, 124, 1, 7], [368, 470, 1, 7], [368, 519, 1, 1], [368, 521, 1, 1], [369, 81, 1, 1], [369, 123, 1, 6], [369, 472, 1, 6], [369, 519, 1, 1], [370, 80, 1, 2], [370, 121, 1, 8], [370, 472, 1, 8], [370, 519, 1, 2], [371, 81, 1, 1], [371, 83, 1, 2], [371, 88, 1, 3], [371, 94, 1, 2], [371, 97, 1, 1], [371, 120, 1, 9], [371, 472, 1, 9], [371, 503, 1, 1], [371, 505, 1, 2], [371, 510, 1, 3], [371, 516, 1, 2], [371, 519, 1, 1], [372, 82, 1, 4], [372, 87, 1, 2], [372, 90, 1, 5], [372, 96, 1, 2], [372, 119, 1, 1], [372, 121, 1, 7], [372, 473, 1, 7], [372, 481, 1, 1], [372, 503, 1, 2], [372, 506, 1, 5], [372, 512, 1, 2], [372, 515, 1, 4], [373, 81, 1, 5], [373, 89, 1, 1], [373, 92, 1, 3], [373, 96, 1, 2], [373, 118, 1, 2], [373, 123, 1, 5], [373, 473, 1, 5], [373, 481, 1, 2], [373, 503, 1, 2], [373, 506, 1, 3], [373, 511, 1, 1], [373, 515, 1, 5], [374, 81, 1, 4], [374, 86, 1, 5], [374, 96, 1, 2], [374, 117, 1, 3], [374, 123, 1, 5], [374, 473, 1, 5], [374, 481, 1, 3], [374, 503, 1, 2], [374, 510, 1, 5], [374, 516, 1, 4], [375, 80, 1, 2], [375, 88, 1, 3], [375, 97, 1, 2], [375, 117, 1, 3], [375, 124, 1, 3], [375, 474, 1, 3], [375, 481, 1, 3], [375, 502, 1, 2], [375, 510, 1, 3], [375, 519, 1, 2], [376, 90, 1, 2], [376, 96, 1, 4], [376, 116, 1, 1], [376, 118, 1, 1], [376, 482, 1, 1], [376, 484, 1, 1], [376, 501, 1, 4], [376, 509, 1, 2], [377, 79, 1, 1], [377, 90, 1, 1], [377, 96, 1, 7], [377, 115, 1, 3], [377, 483, 1, 3], [377, 498, 1, 7], [377, 510, 1, 1], [377, 521, 1, 1], [378, 90, 1, 1], [378, 92, 1, 1], [378, 94, 1, 1], [378, 97, 1, 8], [378, 113, 1, 5], [378, 483, 1, 5], [378, 496, 1, 8], [378, 506, 1, 1], [378, 508, 1, 1], [378, 510, 1, 1], [379, 89, 1, 7], [379, 98, 1, 7], [379, 106, 1, 13], [379, 482, 1, 13], [379, 496, 1, 7], [379, 505, 1, 7], [380, 95, 1, 2], [380, 105, 1, 14], [380, 482, 1, 14], [380, 504, 1, 2], [381, 95, 1, 1], [381, 97, 1, 4], [381, 105, 1, 14], [381, 482, 1, 14], [381, 500, 1, 4], [381, 505, 1, 1], [382, 95, 1, 6], [382, 105, 1, 10], [382, 116, 1, 2], [382, 483, 1, 2], [382, 486, 1, 10], [382, 500, 1, 6], [383, 98, 1, 3], [383, 107, 1, 6], [383, 488, 1, 6], [383, 500, 1, 3], [384, 100, 1, 3], [384, 108, 1, 5], [384, 488, 1, 5], [384, 498, 1, 3], [385, 101, 1, 4], [385, 109, 1, 2], [385, 490, 1, 2], [385, 496, 1, 4], [386, 102, 1, 5], [386, 494, 1, 5], [387, 103, 1, 5], [387, 493, 1, 5], [388, 103, 1, 4], [388, 494, 1, 4], [389, 103, 1, 4], [389, 110, 1, 4], [389, 487, 1, 4], [389, 494, 1, 4], [390, 103, 1, 2], [390, 109, 1, 5], [390, 115, 1, 5], [390, 481, 1, 5], [390, 487, 1, 5], [390, 496, 1, 2], [391, 103, 1, 2], [391, 108, 1, 13], [391, 480, 1, 13], [391, 496, 1, 2], [392, 102, 1, 3], [392, 108, 1, 13], [392, 480, 1, 13], [392, 496, 1, 3], [393, 100, 1, 5], [393, 108, 1, 12], [393, 481, 1, 12], [393, 496, 1, 5], [394, 102, 1, 2], [394, 108, 1, 2], [394, 114, 1, 6], [394, 127, 1, 2], [394, 472, 1, 2], [394, 481, 1, 6], [394, 491, 1, 2], [394, 497, 1, 2], [395, 100, 1, 2], [395, 105, 1, 4], [395, 116, 1, 4], [395, 122, 1, 1], [395, 126, 1, 4], [395, 471, 1, 4], [395, 478, 1, 1], [395, 481, 1, 4], [395, 492, 1, 4], [395, 499, 1, 2], [396, 101, 1, 2], [396, 104, 1, 4], [396, 118, 1, 1], [396, 120, 1, 4], [396, 125, 1, 5], [396, 471, 1, 5], [396, 477, 1, 4], [396, 482, 1, 1], [396, 493, 1, 4], [396, 498, 1, 2], [397, 100, 1, 2], [397, 104, 1, 4], [397, 119, 1, 11], [397, 471, 1, 11], [397, 493, 1, 4], [397, 499, 1, 2], [398, 100, 1, 1], [398, 105, 1, 2], [398, 123, 1, 9], [398, 469, 1, 9], [398, 494, 1, 2], [398, 500, 1, 1], [399, 100, 1, 2], [399, 106, 1, 1], [399, 126, 1, 7], [399, 468, 1, 7], [399, 494, 1, 1], [399, 499, 1, 2], [400, 100, 1, 2], [400, 104, 1, 2], [400, 127, 1, 8], [400, 466, 1, 8], [400, 495, 1, 2], [400, 499, 1, 2], [401, 100, 1, 1], [401, 103, 1, 2], [401, 128, 1, 7], [401, 466, 1, 7], [401, 496, 1, 2], [401, 500, 1, 1], [402, 97, 1, 3], [402, 101, 1, 4], [402, 128, 1, 8], [402, 465, 1, 8], [402, 496, 1, 4], [402, 501, 1, 3], [403, 96, 1, 1], [403, 100, 1, 2], [403, 128, 1, 7], [403, 162, 1, 4], [403, 435, 1, 4], [403, 466, 1, 7], [403, 499, 1, 2], [403, 504, 1, 1], [404, 94, 1, 3], [404, 98, 1, 1], [404, 100, 1, 1], [404, 128, 1, 7], [404, 160, 1, 7], [404, 434, 1, 7], [404, 466, 1, 7], [404, 500, 1, 1], [404, 502, 1, 1], [404, 504, 1, 3], [405, 94, 1, 1], [405, 100, 1, 1], [405, 128, 1, 4], [405, 160, 1, 8], [405, 433, 1, 8], [405, 469, 1, 4], [405, 500, 1, 1], [405, 506, 1, 1], [406, 99, 1, 2], [406, 128, 1, 3], [406, 144, 1, 3], [406, 154, 1, 2], [406, 158, 1, 10], [406, 433, 1, 10], [406, 445, 1, 2], [406, 454, 1, 3], [406, 470, 1, 3], [406, 500, 1, 2], [407, 99, 1, 1], [407, 128, 1, 1], [407, 143, 1, 4], [407, 153, 1, 14], [407, 434, 1, 14], [407, 454, 1, 4], [407, 472, 1, 1], [407, 501, 1, 1], [408, 128, 1, 2], [408, 133, 1, 1], [408, 139, 1, 2], [408, 142, 1, 5], [408, 153, 1, 14], [408, 434, 1, 14], [408, 454, 1, 5], [408, 460, 1, 2], [408, 467, 1, 1], [408, 471, 1, 2], [409, 128, 1, 2], [409, 132, 1, 3], [409, 138, 1, 10], [409, 150, 1, 2], [409, 153, 1, 14], [409, 434, 1, 14], [409, 449, 1, 2], [409, 453, 1, 10], [409, 466, 1, 3], [409, 471, 1, 2], [410, 127, 1, 3], [410, 132, 1, 3], [410, 138, 1, 10], [410, 149, 1, 19], [410, 433, 1, 19], [410, 453, 1, 10], [410, 466, 1, 3], [410, 471, 1, 3], [411, 126, 1, 2], [411, 131, 1, 4], [411, 139, 1, 3], [411, 147, 1, 5], [411, 159, 1, 10], [411, 432, 1, 10], [411, 449, 1, 5], [411, 459, 1, 3], [411, 466, 1, 4], [411, 473, 1, 2], [412, 126, 1, 1], [412, 128, 1, 4], [412, 135, 1, 3], [412, 140, 1, 1], [412, 160, 1, 9], [412, 432, 1, 9], [412, 460, 1, 1], [412, 463, 1, 3], [412, 469, 1, 4], [412, 474, 1, 1], [413, 136, 1, 1], [413, 139, 1, 1], [413, 161, 1, 8], [413, 432, 1, 8], [413, 461, 1, 1], [413, 464, 1, 1], [414, 136, 1, 1], [414, 138, 1, 1], [414, 162, 1, 6], [414, 433, 1, 6], [414, 462, 1, 1], [414, 464, 1, 1], [415, 163, 1, 4], [415, 434, 1, 4], [416, 163, 1, 2], [416, 436, 1, 2], [417, 164, 1, 2], [417, 435, 1, 2], [418, 164, 1, 3], [418, 434, 1, 3], [419, 165, 1, 2], [419, 434, 1, 2], [420, 165, 1, 4], [420, 432, 1, 4], [421, 165, 1, 4], [421, 432, 1, 4], [422, 166, 1, 6], [422, 429, 1, 6], [423, 166, 1, 7], [423, 428, 1, 7], [424, 166, 1, 7], [424, 428, 1, 7], [425, 166, 1, 6], [425, 429, 1, 6], [426, 166, 1, 6], [426, 429, 1, 6], [427, 166, 1, 5], [427, 430, 1, 5], [428, 165, 1, 2], [428, 434, 1, 2], [429, 165, 1, 2], [429, 434, 1, 2], [430, 163, 1, 4], [430, 434, 1, 4], [431, 162, 1, 2], [431, 165, 1, 2], [431, 434, 1, 2], [431, 437, 1, 2], [433, 162, 1, 1], [433, 438, 1, 1], [434, 163, 1, 1], [434, 165, 1, 2], [434, 434, 1, 2], [434, 437, 1, 1], [435, 165, 1, 1], [435, 435, 1, 1], [436, 166, 1, 2], [436, 433, 1, 2], [437, 166, 1, 1], [437, 434, 1, 1], [438, 166, 1, 1], [438, 169, 1, 2], [438, 175, 1, 5], [438, 421, 1, 5], [438, 430, 1, 2], [438, 434, 1, 1], [439, 169, 1, 3], [439, 175, 1, 6], [439, 420, 1, 6], [439, 429, 1, 3], [440, 171, 1, 10], [440, 420, 1, 10], [441, 173, 1, 7], [441, 421, 1, 7], [442, 175, 1, 5], [442, 421, 1, 5], [443, 177, 1, 4], [443, 420, 1, 4], [444, 178, 1, 3], [444, 420, 1, 3], [445, 179, 1, 6], [445, 416, 1, 6], [446, 179, 1, 7], [446, 415, 1, 7], [447, 180, 1, 7], [447, 414, 1, 7], [448, 180, 1, 7], [448, 414, 1, 7], [449, 180, 1, 7], [449, 414, 1, 7], [450, 179, 1, 8], [450, 414, 1, 8], [451, 179, 1, 5], [451, 417, 1, 5], [452, 178, 1, 5], [452, 418, 1, 5], [453, 177, 1, 6], [453, 418, 1, 6], [454, 175, 1, 7], [454, 419, 1, 7], [455, 175, 1, 1], [455, 177, 1, 5], [455, 419, 1, 5], [455, 425, 1, 1], [456, 175, 1, 1], [456, 179, 1, 2], [456, 420, 1, 2], [456, 425, 1, 1], [457, 175, 1, 1], [457, 425, 1, 1], [458, 175, 1, 2], [458, 424, 1, 2], [459, 175, 1, 2], [459, 424, 1, 2], [460, 175, 1, 1], [460, 425, 1, 1], [461, 175, 1, 1], [461, 425, 1, 1], [462, 175, 1, 3], [462, 299, 1, 3], [462, 423, 1, 3], [463, 176, 1, 1], [463, 298, 1, 5], [463, 424, 1, 1], [464, 176, 1, 1], [464, 179, 1, 2], [464, 297, 1, 7], [464, 420, 1, 2], [464, 424, 1, 1], [465, 177, 1, 5], [465, 297, 1, 7], [465, 419, 1, 5], [466, 177, 1, 5], [466, 296, 1, 9], [466, 419, 1, 5], [467, 177, 1, 3], [467, 205, 1, 3], [467, 295, 1, 11], [467, 393, 1, 3], [467, 421, 1, 3], [468, 177, 1, 4], [468, 205, 1, 3], [468, 295, 1, 4], [468, 302, 1, 4], [468, 393, 1, 3], [468, 420, 1, 4], [469, 176, 1, 5], [469, 204, 1, 6], [469, 294, 1, 2], [469, 305, 1, 2], [469, 391, 1, 6], [469, 420, 1, 5], [470, 175, 1, 6], [470, 204, 1, 8], [470, 293, 1, 2], [470, 306, 1, 2], [470, 389, 1, 8], [470, 420, 1, 6], [471, 173, 1, 8], [471, 203, 1, 10], [471, 292, 1, 2], [471, 307, 1, 2], [471, 388, 1, 10], [471, 420, 1, 8], [472, 171, 1, 10], [472, 201, 1, 12], [472, 292, 1, 1], [472, 308, 1, 1], [472, 388, 1, 12], [472, 420, 1, 10], [473, 169, 1, 2], [473, 172, 1, 9], [473, 201, 1, 12], [473, 291, 1, 1], [473, 309, 1, 1], [473, 388, 1, 12], [473, 420, 1, 9], [473, 430, 1, 2], [474, 160, 1, 1], [474, 167, 1, 1], [474, 169, 1, 2], [474, 173, 1, 5], [474, 179, 1, 2], [474, 192, 1, 2], [474, 202, 1, 2], [474, 208, 1, 4], [474, 288, 1, 3], [474, 310, 1, 3], [474, 389, 1, 4], [474, 397, 1, 2], [474, 407, 1, 2], [474, 420, 1, 2], [474, 423, 1, 5], [474, 430, 1, 2], [474, 433, 1, 1], [474, 440, 1, 1], [475, 160, 1, 8], [475, 174, 1, 2], [475, 191, 1, 3], [475, 200, 1, 2], [475, 210, 1, 1], [475, 220, 1, 2], [475, 288, 1, 1], [475, 312, 1, 1], [475, 379, 1, 2], [475, 390, 1, 1], [475, 399, 1, 2], [475, 407, 1, 3], [475, 425, 1, 2], [475, 433, 1, 8], [476, 162, 1, 1], [476, 164, 1, 4], [476, 189, 1, 6], [476, 200, 1, 2], [476, 211, 1, 4], [476, 218, 1, 6], [476, 284, 1, 1], [476, 288, 1, 1], [476, 312, 1, 1], [476, 316, 1, 1], [476, 377, 1, 6], [476, 386, 1, 4], [476, 399, 1, 2], [476, 406, 1, 6], [476, 433, 1, 4], [476, 438, 1, 1], [477, 163, 1, 1], [477, 165, 1, 1], [477, 168, 1, 3], [477, 186, 1, 10], [477, 197, 1, 2], [477, 213, 1, 12], [477, 283, 1, 2], [477, 286, 1, 1], [477, 314, 1, 1], [477, 316, 1, 2], [477, 376, 1, 12], [477, 402, 1, 2], [477, 405, 1, 10], [477, 430, 1, 3], [477, 435, 1, 1], [477, 437, 1, 1], [478, 164, 1, 1], [478, 167, 1, 4], [478, 172, 1, 3], [478, 176, 1, 3], [478, 186, 1, 9], [478, 197, 1, 1], [478, 216, 1, 9], [478, 283, 1, 2], [478, 316, 1, 2], [478, 376, 1, 9], [478, 403, 1, 1], [478, 406, 1, 9], [478, 422, 1, 3], [478, 426, 1, 3], [478, 430, 1, 4], [478, 436, 1, 1], [479, 164, 1, 1], [479, 166, 1, 3], [479, 174, 1, 6], [479, 186, 1, 4], [479, 195, 1, 1], [479, 219, 1, 6], [479, 276, 1, 3], [479, 322, 1, 3], [479, 376, 1, 6], [479, 405, 1, 1], [479, 411, 1, 4], [479, 421, 1, 6], [479, 432, 1, 3], [479, 436, 1, 1], [480, 163, 1, 2], [480, 166, 1, 2], [480, 176, 1, 4], [480, 182, 1, 1], [480, 187, 1, 3], [480, 220, 1, 4], [480, 275, 1, 4], [480, 283, 1, 1], [480, 317, 1, 1], [480, 322, 1, 4], [480, 377, 1, 4], [480, 411, 1, 3], [480, 418, 1, 1], [480, 421, 1, 4], [480, 433, 1, 2], [480, 436, 1, 2], [481, 177, 1, 2], [481, 181, 1, 3], [481, 188, 1, 2], [481, 221, 1, 1], [481, 275, 1, 3], [481, 281, 1, 1], [481, 319, 1, 1], [481, 323, 1, 3], [481, 379, 1, 1], [481, 411, 1, 2], [481, 417, 1, 3], [481, 422, 1, 2], [482, 177, 1, 1], [482, 181, 1, 4], [482, 188, 1, 2], [482, 221, 1, 2], [482, 241, 1, 3], [482, 266, 1, 2], [482, 275, 1, 5], [482, 321, 1, 5], [482, 333, 1, 2], [482, 357, 1, 3], [482, 378, 1, 2], [482, 411, 1, 2], [482, 416, 1, 4], [482, 423, 1, 1], [483, 178, 1, 1], [483, 180, 1, 7], [483, 222, 1, 2], [483, 240, 1, 4], [483, 248, 1, 3], [483, 262, 1, 7], [483, 332, 1, 7], [483, 350, 1, 3], [483, 357, 1, 4], [483, 377, 1, 2], [483, 414, 1, 7], [483, 422, 1, 1], [484, 178, 1, 1], [484, 180, 1, 2], [484, 186, 1, 1], [484, 189, 1, 1], [484, 222, 1, 2], [484, 240, 1, 11], [484, 262, 1, 8], [484, 275, 1, 1], [484, 325, 1, 1], [484, 331, 1, 8], [484, 350, 1, 11], [484, 377, 1, 2], [484, 411, 1, 1], [484, 414, 1, 1], [484, 419, 1, 2], [484, 422, 1, 1], [485, 177, 1, 2], [485, 186, 1, 1], [485, 223, 1, 2], [485, 240, 1, 12], [485, 262, 1, 8], [485, 331, 1, 8], [485, 349, 1, 12], [485, 376, 1, 2], [485, 414, 1, 1], [485, 422, 1, 2], [486, 177, 1, 1], [486, 180, 1, 1], [486, 223, 1, 4], [486, 240, 1, 3], [486, 248, 1, 5], [486, 261, 1, 3], [486, 267, 1, 2], [486, 272, 1, 1], [486, 328, 1, 1], [486, 332, 1, 2], [486, 337, 1, 3], [486, 348, 1, 5], [486, 358, 1, 3], [486, 374, 1, 4], [486, 420, 1, 1], [486, 423, 1, 1], [487, 176, 1, 4], [487, 223, 1, 5], [487, 239, 1, 2], [487, 249, 1, 5], [487, 262, 1, 1], [487, 271, 1, 1], [487, 329, 1, 1], [487, 338, 1, 1], [487, 347, 1, 5], [487, 360, 1, 2], [487, 373, 1, 5], [487, 421, 1, 4], [488, 223, 1, 5], [488, 236, 1, 2], [488, 239, 1, 1], [488, 250, 1, 4], [488, 262, 1, 1], [488, 338, 1, 1], [488, 347, 1, 4], [488, 361, 1, 1], [488, 363, 1, 2], [488, 373, 1, 5], [489, 223, 1, 5], [489, 235, 1, 4], [489, 250, 1, 4], [489, 347, 1, 4], [489, 362, 1, 4], [489, 373, 1, 5], [490, 223, 1, 2], [490, 226, 1, 1], [490, 236, 1, 2], [490, 250, 1, 3], [490, 261, 1, 1], [490, 339, 1, 1], [490, 348, 1, 3], [490, 363, 1, 2], [490, 374, 1, 1], [490, 376, 1, 2], [491, 222, 1, 2], [491, 237, 1, 1], [491, 250, 1, 3], [491, 256, 1, 2], [491, 259, 1, 1], [491, 341, 1, 1], [491, 343, 1, 2], [491, 348, 1, 3], [491, 363, 1, 1], [491, 377, 1, 2], [492, 221, 1, 2], [492, 235, 1, 1], [492, 237, 1, 1], [492, 255, 1, 3], [492, 259, 1, 1], [492, 341, 1, 1], [492, 343, 1, 3], [492, 363, 1, 1], [492, 365, 1, 1], [492, 378, 1, 2], [493, 219, 1, 4], [493, 228, 1, 2], [493, 234, 1, 3], [493, 251, 1, 2], [493, 257, 1, 1], [493, 343, 1, 1], [493, 348, 1, 2], [493, 364, 1, 3], [493, 371, 1, 2], [493, 378, 1, 4], [494, 218, 1, 1], [494, 224, 1, 6], [494, 232, 1, 1], [494, 235, 1, 1], [494, 365, 1, 1], [494, 368, 1, 1], [494, 371, 1, 6], [494, 382, 1, 1], [495, 219, 1, 3], [495, 225, 1, 1], [495, 228, 1, 2], [495, 232, 1, 2], [495, 235, 1, 1], [495, 365, 1, 1], [495, 367, 1, 2], [495, 371, 1, 2], [495, 375, 1, 1], [495, 379, 1, 3], [496, 221, 1, 1], [496, 223, 1, 2], [496, 229, 1, 3], [496, 369, 1, 3], [496, 376, 1, 2], [496, 379, 1, 1], [497, 229, 1, 3], [497, 369, 1, 3]], [[61, 299, 1, 1], [61, 301, 1, 1], [62, 298, 1, 2], [62, 301, 1, 2], [63, 298, 1, 1], [63, 302, 1, 1], [64, 289, 1, 1], [64, 297, 1, 1], [64, 303, 1, 1], [64, 311, 1, 1], [65, 294, 1, 1], [65, 297, 1, 1], [65, 303, 1, 1], [65, 306, 1, 1], [67, 296, 1, 1], [67, 304, 1, 1], [68, 297, 1, 1], [68, 303, 1, 1], [69, 298, 1, 2], [69, 301, 1, 2], [90, 299, 1, 1], [90, 301, 1, 1], [93, 299, 1, 1], [93, 301, 1, 1], [102, 299, 1, 1], [102, 301, 1, 1], [112, 298, 1, 2], [112, 301, 1, 2], [116, 299, 1, 1], [116, 301, 1, 1], [118, 293, 1, 1], [118, 299, 1, 1], [118, 301, 1, 1], [118, 307, 1, 1], [119, 292, 1, 1], [119, 294, 1, 2], [119, 298, 1, 1], [119, 302, 1, 1], [119, 305, 1, 2], [119, 308, 1, 1], [120, 295, 1, 2], [120, 304, 1, 2], [121, 297, 1, 2], [121, 302, 1, 2], [122, 299, 1, 1], [122, 301, 1, 1], [123, 298, 1, 2], [123, 301, 1, 2], [124, 299, 1, 1], [124, 301, 1, 1], [125, 298, 1, 2], [125, 301, 1, 2], [126, 298, 1, 1], [126, 302, 1, 1], [127, 297, 1, 2], [127, 302, 1, 2], [128, 298, 1, 2], [128, 301, 1, 2], [129, 298, 1, 2], [129, 301, 1, 2], [130, 297, 1, 2], [130, 302, 1, 2], [131, 269, 1, 1], [131, 290, 1, 1], [131, 296, 1, 1], [131, 298, 1, 1], [131, 302, 1, 1], [131, 304, 1, 1], [131, 310, 1, 1], [131, 331, 1, 1], [132, 270, 1, 1], [132, 296, 1, 2], [132, 303, 1, 2], [132, 330, 1, 1], [133, 271, 1, 1], [133, 274, 1, 1], [133, 293, 1, 5], [133, 303, 1, 5], [133, 326, 1, 1], [133, 329, 1, 1], [134, 271, 1, 2], [134, 274, 1, 1], [134, 292, 1, 1], [134, 296, 1, 1], [134, 304, 1, 1], [134, 308, 1, 1], [134, 326, 1, 1], [134, 328, 1, 2], [135, 277, 1, 1], [135, 292, 1, 2], [135, 307, 1, 2], [135, 323, 1, 1], [136, 277, 1, 2], [136, 292, 1, 2], [136, 307, 1, 2], [136, 322, 1, 2], [137, 277, 1, 1], [137, 279, 1, 1], [137, 291, 1, 4], [137, 306, 1, 4], [137, 321, 1, 1], [137, 323, 1, 1], [138, 279, 1, 3], [138, 284, 1, 2], [138, 289, 1, 1], [138, 291, 1, 3], [138, 307, 1, 3], [138, 311, 1, 1], [138, 315, 1, 2], [138, 319, 1, 3], [139, 282, 1, 5], [139, 289, 1, 2], [139, 292, 1, 2], [139, 307, 1, 2], [139, 310, 1, 2], [139, 314, 1, 5], [140, 280, 1, 1], [140, 286, 1, 5], [140, 310, 1, 5], [140, 320, 1, 1], [141, 287, 1, 4], [141, 310, 1, 4], [142, 281, 1, 2], [142, 318, 1, 2], [143, 283, 1, 2], [143, 316, 1, 2], [144, 283, 1, 2], [144, 316, 1, 2], [145, 283, 1, 2], [145, 316, 1, 2], [146, 283, 1, 2], [146, 316, 1, 2], [147, 283, 1, 2], [147, 316, 1, 2], [148, 283, 1, 2], [148, 316, 1, 2], [149, 280, 1, 3], [149, 284, 1, 1], [149, 316, 1, 1], [149, 318, 1, 3], [150, 281, 1, 2], [150, 318, 1, 2], [151, 277, 1, 5], [151, 319, 1, 5], [152, 281, 1, 1], [152, 319, 1, 1], [153, 282, 1, 2], [153, 317, 1, 2], [154, 282, 1, 3], [154, 316, 1, 3], [155, 282, 1, 3], [155, 316, 1, 3], [156, 281, 1, 1], [156, 319, 1, 1], [157, 282, 1, 3], [157, 316, 1, 3], [158, 215, 1, 1], [158, 261, 1, 1], [158, 282, 1, 4], [158, 315, 1, 4], [158, 339, 1, 1], [158, 385, 1, 1], [159, 230, 1, 1], [159, 261, 1, 1], [159, 263, 1, 2], [159, 282, 1, 3], [159, 316, 1, 3], [159, 336, 1, 2], [159, 339, 1, 1], [159, 370, 1, 1], [160, 229, 1, 1], [160, 261, 1, 2], [160, 282, 1, 4], [160, 315, 1, 4], [160, 338, 1, 2], [160, 371, 1, 1], [161, 217, 1, 1], [161, 262, 1, 1], [161, 276, 1, 2], [161, 281, 1, 5], [161, 315, 1, 5], [161, 323, 1, 2], [161, 338, 1, 1], [161, 383, 1, 1], [162, 218, 1, 1], [162, 223, 1, 1], [162, 229, 1, 1], [162, 236, 1, 1], [162, 264, 1, 1], [162, 266, 1, 1], [162, 277, 1, 5], [162, 283, 1, 3], [162, 315, 1, 3], [162, 319, 1, 5], [162, 334, 1, 1], [162, 336, 1, 1], [162, 364, 1, 1], [162, 371, 1, 1], [162, 377, 1, 1], [162, 382, 1, 1], [163, 219, 1, 1], [163, 223, 1, 1], [163, 226, 1, 2], [163, 229, 1, 1], [163, 231, 1, 2], [163, 236, 1, 1], [163, 264, 1, 3], [163, 274, 1, 2], [163, 277, 1, 5], [163, 319, 1, 5], [163, 325, 1, 2], [163, 334, 1, 3], [163, 364, 1, 1], [163, 368, 1, 2], [163, 371, 1, 1], [163, 373, 1, 2], [163, 377, 1, 1], [163, 381, 1, 1], [164, 219, 1, 1], [164, 225, 1, 1], [164, 233, 1, 2], [164, 266, 1, 2], [164, 269, 1, 2], [164, 274, 1, 2], [164, 279, 1, 2], [164, 320, 1, 2], [164, 325, 1, 2], [164, 330, 1, 2], [164, 333, 1, 2], [164, 366, 1, 2], [164, 375, 1, 1], [164, 381, 1, 1], [165, 232, 1, 1], [165, 264, 1, 1], [165, 267, 1, 7], [165, 275, 1, 1], [165, 325, 1, 1], [165, 327, 1, 7], [165, 336, 1, 1], [165, 368, 1, 1], [166, 234, 1, 1], [166, 236, 1, 1], [166, 238, 1, 1], [166, 264, 1, 1], [166, 270, 1, 4], [166, 327, 1, 4], [166, 336, 1, 1], [166, 362, 1, 1], [166, 364, 1, 1], [166, 366, 1, 1], [167, 235, 1, 1], [167, 237, 1, 1], [167, 271, 1, 3], [167, 327, 1, 3], [167, 363, 1, 1], [167, 365, 1, 1], [168, 236, 1, 2], [168, 262, 1, 3], [168, 336, 1, 3], [168, 363, 1, 2], [169, 262, 1, 1], [169, 338, 1, 1], [170, 236, 1, 2], [170, 251, 1, 1], [170, 262, 1, 1], [170, 338, 1, 1], [170, 349, 1, 1], [170, 363, 1, 2], [171, 237, 1, 1], [171, 252, 1, 1], [171, 262, 1, 2], [171, 337, 1, 2], [171, 348, 1, 1], [171, 363, 1, 1], [172, 235, 1, 1], [172, 237, 1, 2], [172, 253, 1, 1], [172, 261, 1, 3], [172, 337, 1, 3], [172, 347, 1, 1], [172, 362, 1, 2], [172, 365, 1, 1], [173, 238, 1, 1], [173, 251, 1, 1], [173, 260, 1, 4], [173, 337, 1, 4], [173, 349, 1, 1], [173, 362, 1, 1], [174, 236, 1, 1], [174, 238, 1, 2], [174, 241, 1, 1], [174, 243, 1, 1], [174, 251, 1, 4], [174, 259, 1, 2], [174, 262, 1, 2], [174, 337, 1, 2], [174, 340, 1, 2], [174, 346, 1, 4], [174, 357, 1, 1], [174, 359, 1, 1], [174, 361, 1, 2], [174, 364, 1, 1], [175, 234, 1, 2], [175, 240, 1, 2], [175, 243, 1, 1], [175, 250, 1, 2], [175, 253, 1, 3], [175, 258, 1, 3], [175, 340, 1, 3], [175, 345, 1, 3], [175, 349, 1, 2], [175, 357, 1, 1], [175, 359, 1, 2], [175, 365, 1, 2], [176, 237, 1, 1], [176, 242, 1, 2], [176, 247, 1, 1], [176, 249, 1, 1], [176, 253, 1, 8], [176, 340, 1, 8], [176, 351, 1, 1], [176, 353, 1, 1], [176, 357, 1, 2], [176, 363, 1, 1], [177, 237, 1, 1], [177, 242, 1, 6], [177, 254, 1, 2], [177, 257, 1, 3], [177, 341, 1, 3], [177, 345, 1, 2], [177, 353, 1, 6], [177, 363, 1, 1], [178, 237, 1, 2], [178, 242, 1, 4], [178, 247, 1, 1], [178, 258, 1, 2], [178, 341, 1, 2], [178, 353, 1, 1], [178, 355, 1, 4], [178, 362, 1, 2], [179, 238, 1, 1], [179, 244, 1, 2], [179, 355, 1, 2], [179, 362, 1, 1], [180, 238, 1, 2], [180, 361, 1, 2], [181, 239, 1, 1], [181, 361, 1, 1], [182, 237, 1, 2], [182, 362, 1, 2], [183, 234, 1, 1], [183, 236, 1, 2], [183, 363, 1, 2], [183, 366, 1, 1], [184, 231, 1, 3], [184, 240, 1, 1], [184, 360, 1, 1], [184, 367, 1, 3], [185, 239, 1, 3], [185, 359, 1, 3], [186, 241, 1, 2], [186, 358, 1, 2], [187, 241, 1, 3], [187, 357, 1, 3], [188, 241, 1, 2], [188, 358, 1, 2], [189, 241, 1, 1], [189, 359, 1, 1], [190, 240, 1, 2], [190, 359, 1, 2], [191, 238, 1, 1], [191, 240, 1, 1], [191, 242, 1, 2], [191, 357, 1, 2], [191, 360, 1, 1], [191, 362, 1, 1], [192, 244, 1, 2], [192, 355, 1, 2], [193, 244, 1, 2], [193, 355, 1, 2], [194, 246, 1, 3], [194, 352, 1, 3], [195, 246, 1, 3], [195, 352, 1, 3], [196, 245, 1, 3], [196, 353, 1, 3], [197, 244, 1, 5], [197, 352, 1, 5], [198, 243, 1, 1], [198, 246, 1, 2], [198, 353, 1, 2], [198, 357, 1, 1], [200, 244, 1, 2], [200, 355, 1, 2], [201, 245, 1, 1], [201, 355, 1, 1], [202, 245, 1, 1], [202, 355, 1, 1], [203, 228, 1, 1], [203, 232, 1, 1], [203, 244, 1, 2], [203, 355, 1, 2], [203, 368, 1, 1], [203, 372, 1, 1], [204, 228, 1, 2], [204, 233, 1, 2], [204, 243, 1, 4], [204, 354, 1, 4], [204, 366, 1, 2], [204, 371, 1, 2], [205, 228, 1, 1], [205, 235, 1, 1], [205, 243, 1, 4], [205, 354, 1, 4], [205, 365, 1, 1], [205, 372, 1, 1], [206, 228, 1, 1], [206, 230, 1, 1], [206, 232, 1, 2], [206, 236, 1, 1], [206, 241, 1, 2], [206, 358, 1, 2], [206, 364, 1, 1], [206, 367, 1, 2], [206, 370, 1, 1], [206, 372, 1, 1], [207, 229, 1, 1], [207, 233, 1, 2], [207, 236, 1, 2], [207, 241, 1, 2], [207, 358, 1, 2], [207, 363, 1, 2], [207, 366, 1, 2], [207, 371, 1, 1], [208, 224, 1, 2], [208, 227, 1, 2], [208, 235, 1, 8], [208, 358, 1, 8], [208, 372, 1, 2], [208, 375, 1, 2], [209, 225, 1, 1], [209, 227, 1, 1], [209, 237, 1, 2], [209, 240, 1, 2], [209, 359, 1, 2], [209, 362, 1, 2], [209, 373, 1, 1], [209, 375, 1, 1], [210, 227, 1, 1], [210, 234, 1, 1], [210, 366, 1, 1], [210, 373, 1, 1], [211, 225, 1, 1], [211, 375, 1, 1], [212, 235, 1, 2], [212, 364, 1, 2], [213, 237, 1, 1], [213, 363, 1, 1], [214, 236, 1, 2], [214, 363, 1, 2], [216, 235, 1, 1], [216, 238, 1, 2], [216, 361, 1, 2], [216, 365, 1, 1], [217, 241, 1, 1], [217, 359, 1, 1], [218, 241, 1, 1], [218, 359, 1, 1], [219, 242, 1, 4], [219, 355, 1, 4], [220, 243, 1, 3], [220, 355, 1, 3], [221, 244, 1, 1], [221, 356, 1, 1], [222, 244, 1, 3], [222, 354, 1, 3], [223, 244, 1, 3], [223, 354, 1, 3], [224, 240, 1, 7], [224, 354, 1, 7], [225, 237, 1, 1], [225, 243, 1, 3], [225, 355, 1, 3], [225, 363, 1, 1], [226, 237, 1, 1], [226, 243, 1, 3], [226, 355, 1, 3], [226, 363, 1, 1], [227, 239, 1, 2], [227, 360, 1, 2], [228, 236, 1, 2], [228, 239, 1, 3], [228, 359, 1, 3], [228, 363, 1, 2], [230, 243, 1, 1], [230, 357, 1, 1], [231, 243, 1, 1], [231, 357, 1, 1], [232, 244, 1, 2], [232, 355, 1, 2], [233, 246, 1, 4], [233, 351, 1, 4], [234, 248, 1, 3], [234, 350, 1, 3], [235, 248, 1, 3], [235, 350, 1, 3], [236, 247, 1, 1], [236, 353, 1, 1], [237, 246, 1, 1], [237, 354, 1, 1], [239, 246, 1, 1], [239, 248, 1, 2], [239, 351, 1, 2], [239, 354, 1, 1], [240, 246, 1, 1], [240, 250, 1, 1], [240, 350, 1, 1], [240, 354, 1, 1], [241, 251, 1, 1], [241, 349, 1, 1], [242, 253, 1, 2], [242, 346, 1, 2], [243, 253, 1, 1], [243, 347, 1, 1], [245, 253, 1, 1], [245, 347, 1, 1], [246, 253, 1, 1], [246, 255, 1, 2], [246, 344, 1, 2], [246, 347, 1, 1], [247, 257, 1, 2], [247, 342, 1, 2], [248, 258, 1, 1], [248, 342, 1, 1], [249, 258, 1, 1], [249, 342, 1, 1], [250, 259, 1, 3], [250, 339, 1, 3], [251, 260, 1, 4], [251, 337, 1, 4], [252, 261, 1, 3], [252, 337, 1, 3], [253, 262, 1, 5], [253, 334, 1, 5], [254, 263, 1, 4], [254, 334, 1, 4], [255, 263, 1, 6], [255, 332, 1, 6], [256, 263, 1, 7], [256, 331, 1, 7], [257, 263, 1, 8], [257, 330, 1, 8], [258, 262, 1, 9], [258, 330, 1, 9], [259, 262, 1, 10], [259, 329, 1, 10], [260, 260, 1, 11], [260, 330, 1, 11], [261, 259, 1, 11], [261, 331, 1, 11], [262, 256, 1, 2], [262, 259, 1, 4], [262, 265, 1, 2], [262, 334, 1, 2], [262, 338, 1, 4], [262, 343, 1, 2], [263, 253, 1, 5], [263, 260, 1, 2], [263, 339, 1, 2], [263, 343, 1, 5], [264, 241, 1, 1], [264, 249, 1, 2], [264, 254, 1, 2], [264, 345, 1, 2], [264, 350, 1, 2], [264, 359, 1, 1], [265, 229, 1, 1], [265, 241, 1, 1], [265, 246, 1, 3], [265, 352, 1, 3], [265, 359, 1, 1], [265, 371, 1, 1], [266, 230, 1, 1], [266, 240, 1, 1], [266, 246, 1, 2], [266, 353, 1, 2], [266, 360, 1, 1], [266, 370, 1, 1], [267, 228, 1, 1], [267, 232, 1, 1], [267, 238, 1, 1], [267, 246, 1, 2], [267, 353, 1, 2], [267, 362, 1, 1], [267, 368, 1, 1], [267, 372, 1, 1], [269, 226, 1, 2], [269, 234, 1, 1], [269, 237, 1, 1], [269, 363, 1, 1], [269, 366, 1, 1], [269, 373, 1, 2], [270, 206, 1, 1], [270, 235, 1, 4], [270, 362, 1, 4], [270, 394, 1, 1], [271, 205, 1, 1], [271, 207, 1, 1], [271, 211, 1, 2], [271, 235, 1, 4], [271, 362, 1, 4], [271, 388, 1, 2], [271, 393, 1, 1], [271, 395, 1, 1], [272, 204, 1, 4], [272, 210, 1, 1], [272, 236, 1, 2], [272, 363, 1, 2], [272, 390, 1, 1], [272, 393, 1, 4], [273, 206, 1, 1], [273, 208, 1, 2], [273, 212, 1, 1], [273, 388, 1, 1], [273, 391, 1, 2], [273, 394, 1, 1], [274, 206, 1, 1], [274, 211, 1, 2], [274, 223, 1, 1], [274, 225, 1, 2], [274, 374, 1, 2], [274, 377, 1, 1], [274, 388, 1, 2], [274, 394, 1, 1], [275, 224, 1, 3], [275, 374, 1, 3], [276, 205, 1, 1], [276, 215, 1, 1], [276, 224, 1, 3], [276, 374, 1, 3], [276, 385, 1, 1], [276, 395, 1, 1], [277, 214, 1, 3], [277, 224, 1, 3], [277, 374, 1, 3], [277, 384, 1, 3], [278, 204, 1, 2], [278, 214, 1, 1], [278, 217, 1, 1], [278, 219, 1, 2], [278, 223, 1, 4], [278, 374, 1, 4], [278, 380, 1, 2], [278, 383, 1, 1], [278, 386, 1, 1], [278, 395, 1, 2], [279, 202, 1, 3], [279, 220, 1, 4], [279, 377, 1, 4], [279, 396, 1, 3], [280, 200, 1, 1], [280, 220, 1, 3], [280, 378, 1, 3], [280, 400, 1, 1], [281, 220, 1, 2], [281, 379, 1, 2], [282, 202, 1, 1], [282, 206, 1, 2], [282, 393, 1, 2], [282, 398, 1, 1], [283, 202, 1, 6], [283, 393, 1, 6], [284, 163, 1, 1], [284, 205, 1, 2], [284, 394, 1, 2], [284, 437, 1, 1], [285, 205, 1, 1], [285, 395, 1, 1], [286, 166, 1, 1], [286, 205, 1, 1], [286, 395, 1, 1], [286, 434, 1, 1], [287, 164, 1, 3], [287, 177, 1, 1], [287, 206, 1, 1], [287, 394, 1, 1], [287, 423, 1, 1], [287, 434, 1, 3], [288, 164, 1, 1], [288, 176, 1, 1], [288, 178, 1, 1], [288, 206, 1, 1], [288, 394, 1, 1], [288, 422, 1, 1], [288, 424, 1, 1], [288, 436, 1, 1], [289, 163, 1, 1], [289, 165, 1, 1], [289, 167, 1, 1], [289, 175, 1, 2], [289, 178, 1, 2], [289, 206, 1, 1], [289, 394, 1, 1], [289, 421, 1, 2], [289, 424, 1, 2], [289, 433, 1, 1], [289, 435, 1, 1], [289, 437, 1, 1], [290, 166, 1, 1], [290, 176, 1, 1], [290, 178, 1, 1], [290, 206, 1, 3], [290, 392, 1, 3], [290, 422, 1, 1], [290, 424, 1, 1], [290, 434, 1, 1], [291, 169, 1, 1], [291, 178, 1, 1], [291, 205, 1, 4], [291, 392, 1, 4], [291, 422, 1, 1], [291, 431, 1, 1], [292, 167, 1, 1], [292, 170, 1, 1], [292, 173, 1, 1], [292, 178, 1, 1], [292, 202, 1, 1], [292, 204, 1, 4], [292, 393, 1, 4], [292, 398, 1, 1], [292, 422, 1, 1], [292, 427, 1, 1], [292, 430, 1, 1], [292, 433, 1, 1], [293, 170, 1, 1], [293, 172, 1, 2], [293, 427, 1, 2], [293, 430, 1, 1], [294, 168, 1, 1], [294, 171, 1, 2], [294, 176, 1, 2], [294, 184, 1, 1], [294, 187, 1, 1], [294, 413, 1, 1], [294, 416, 1, 1], [294, 423, 1, 2], [294, 428, 1, 2], [294, 432, 1, 1], [295, 169, 1, 1], [295, 176, 1, 3], [295, 184, 1, 1], [295, 190, 1, 1], [295, 199, 1, 1], [295, 401, 1, 1], [295, 410, 1, 1], [295, 416, 1, 1], [295, 422, 1, 3], [295, 431, 1, 1], [296, 165, 1, 1], [296, 167, 1, 3], [296, 175, 1, 5], [296, 182, 1, 2], [296, 192, 1, 1], [296, 199, 1, 1], [296, 401, 1, 1], [296, 408, 1, 1], [296, 417, 1, 2], [296, 421, 1, 5], [296, 431, 1, 3], [296, 435, 1, 1], [297, 176, 1, 2], [297, 179, 1, 1], [297, 181, 1, 4], [297, 191, 1, 2], [297, 199, 1, 2], [297, 400, 1, 2], [297, 408, 1, 2], [297, 416, 1, 4], [297, 421, 1, 1], [297, 423, 1, 2], [298, 183, 1, 2], [298, 191, 1, 4], [298, 198, 1, 4], [298, 399, 1, 4], [298, 406, 1, 4], [298, 416, 1, 2], [299, 168, 1, 2], [299, 195, 1, 6], [299, 400, 1, 6], [299, 431, 1, 2], [300, 168, 1, 1], [300, 195, 1, 5], [300, 401, 1, 5], [300, 432, 1, 1], [301, 166, 1, 1], [301, 196, 1, 3], [301, 402, 1, 3], [301, 434, 1, 1], [302, 166, 1, 1], [302, 171, 1, 3], [302, 196, 1, 2], [302, 403, 1, 2], [302, 427, 1, 3], [302, 434, 1, 1], [303, 165, 1, 1], [303, 168, 1, 6], [303, 427, 1, 6], [303, 435, 1, 1], [304, 160, 1, 1], [304, 162, 1, 1], [304, 164, 1, 2], [304, 168, 1, 6], [304, 427, 1, 6], [304, 435, 1, 2], [304, 438, 1, 1], [304, 440, 1, 1], [305, 161, 1, 1], [305, 168, 1, 1], [305, 172, 1, 1], [305, 428, 1, 1], [305, 432, 1, 1], [305, 439, 1, 1], [306, 162, 1, 3], [306, 166, 1, 1], [306, 173, 1, 2], [306, 426, 1, 2], [306, 434, 1, 1], [306, 436, 1, 3], [307, 163, 1, 1], [307, 174, 1, 1], [307, 426, 1, 1], [307, 437, 1, 1], [308, 163, 1, 1], [308, 174, 1, 3], [308, 424, 1, 3], [308, 437, 1, 1], [309, 173, 1, 3], [309, 425, 1, 3], [311, 172, 1, 1], [311, 428, 1, 1], [314, 172, 1, 2], [314, 427, 1, 2], [315, 174, 1, 1], [315, 426, 1, 1], [316, 177, 1, 2], [316, 422, 1, 2], [317, 176, 1, 4], [317, 421, 1, 4], [318, 179, 1, 2], [318, 420, 1, 2], [319, 180, 1, 4], [319, 417, 1, 4], [320, 181, 1, 4], [320, 416, 1, 4], [321, 181, 1, 3], [321, 417, 1, 3], [322, 180, 1, 4], [322, 417, 1, 4], [323, 180, 1, 3], [323, 418, 1, 3], [324, 179, 1, 1], [324, 421, 1, 1], [325, 178, 1, 1], [325, 422, 1, 1], [326, 178, 1, 1], [326, 422, 1, 1], [327, 177, 1, 1], [327, 423, 1, 1], [328, 170, 1, 1], [328, 172, 1, 1], [328, 177, 1, 2], [328, 422, 1, 2], [328, 428, 1, 1], [328, 430, 1, 1], [329, 169, 1, 1], [329, 173, 1, 1], [329, 176, 1, 3], [329, 422, 1, 3], [329, 427, 1, 1], [329, 431, 1, 1], [330, 165, 1, 2], [330, 169, 1, 1], [330, 173, 1, 7], [330, 421, 1, 7], [330, 431, 1, 1], [330, 434, 1, 2], [331, 166, 1, 2], [331, 169, 1, 1], [331, 173, 1, 1], [331, 427, 1, 1], [331, 431, 1, 1], [331, 433, 1, 2], [332, 165, 1, 1], [332, 435, 1, 1], [336, 165, 1, 1], [336, 435, 1, 1], [338, 166, 1, 1], [338, 434, 1, 1], [339, 167, 1, 1], [339, 170, 1, 1], [339, 430, 1, 1], [339, 433, 1, 1], [340, 169, 1, 2], [340, 430, 1, 2], [341, 170, 1, 2], [341, 429, 1, 2], [342, 171, 1, 3], [342, 427, 1, 3], [343, 171, 1, 3], [343, 427, 1, 3], [344, 170, 1, 3], [344, 428, 1, 3], [345, 172, 1, 1], [345, 428, 1, 1], [346, 168, 1, 1], [346, 432, 1, 1], [348, 131, 1, 1], [348, 469, 1, 1], [350, 130, 1, 2], [350, 469, 1, 2], [351, 131, 1, 3], [351, 167, 1, 1], [351, 433, 1, 1], [351, 467, 1, 3], [352, 134, 1, 1], [352, 168, 1, 2], [352, 431, 1, 2], [352, 466, 1, 1], [353, 131, 1, 1], [353, 149, 1, 1], [353, 168, 1, 2], [353, 431, 1, 2], [353, 451, 1, 1], [353, 469, 1, 1], [354, 148, 1, 1], [354, 168, 1, 1], [354, 432, 1, 1], [354, 452, 1, 1], [355, 132, 1, 1], [355, 167, 1, 1], [355, 433, 1, 1], [355, 468, 1, 1], [356, 144, 1, 1], [356, 146, 1, 1], [356, 149, 1, 2], [356, 167, 1, 1], [356, 433, 1, 1], [356, 450, 1, 2], [356, 454, 1, 1], [356, 456, 1, 1], [357, 129, 1, 1], [357, 132, 1, 1], [357, 149, 1, 2], [357, 167, 1, 1], [357, 433, 1, 1], [357, 450, 1, 2], [357, 468, 1, 1], [357, 471, 1, 1], [358, 129, 1, 1], [358, 131, 1, 3], [358, 137, 1, 3], [358, 144, 1, 1], [358, 150, 1, 2], [358, 154, 1, 3], [358, 158, 1, 1], [358, 167, 1, 1], [358, 433, 1, 1], [358, 442, 1, 1], [358, 444, 1, 3], [358, 449, 1, 2], [358, 456, 1, 1], [358, 461, 1, 3], [358, 467, 1, 3], [358, 471, 1, 1], [359, 129, 1, 1], [359, 133, 1, 1], [359, 135, 1, 2], [359, 139, 1, 1], [359, 143, 1, 3], [359, 152, 1, 2], [359, 158, 1, 1], [359, 167, 1, 2], [359, 432, 1, 2], [359, 442, 1, 1], [359, 447, 1, 2], [359, 455, 1, 3], [359, 461, 1, 1], [359, 464, 1, 2], [359, 467, 1, 1], [359, 471, 1, 1], [360, 123, 1, 1], [360, 125, 1, 1], [360, 128, 1, 2], [360, 139, 1, 7], [360, 152, 1, 2], [360, 158, 1, 2], [360, 166, 1, 3], [360, 432, 1, 3], [360, 441, 1, 2], [360, 447, 1, 2], [360, 455, 1, 7], [360, 471, 1, 2], [360, 475, 1, 1], [360, 477, 1, 1], [361, 126, 1, 1], [361, 142, 1, 4], [361, 158, 1, 11], [361, 432, 1, 11], [361, 455, 1, 4], [361, 474, 1, 1], [362, 127, 1, 2], [362, 131, 1, 2], [362, 162, 1, 6], [362, 433, 1, 6], [362, 468, 1, 2], [362, 472, 1, 2], [363, 129, 1, 5], [363, 162, 1, 7], [363, 432, 1, 7], [363, 467, 1, 5], [364, 132, 1, 3], [364, 163, 1, 6], [364, 432, 1, 6], [364, 466, 1, 3], [365, 132, 1, 1], [365, 165, 1, 3], [365, 433, 1, 3], [365, 468, 1, 1], [366, 78, 1, 1], [366, 132, 1, 1], [366, 468, 1, 1], [366, 522, 1, 1], [367, 80, 1, 1], [367, 132, 1, 1], [367, 468, 1, 1], [367, 520, 1, 1], [368, 131, 1, 3], [368, 467, 1, 3], [369, 80, 1, 1], [369, 129, 1, 5], [369, 467, 1, 5], [369, 520, 1, 1], [370, 131, 1, 1], [370, 469, 1, 1], [371, 82, 1, 1], [371, 96, 1, 1], [371, 129, 1, 1], [371, 471, 1, 1], [371, 504, 1, 1], [371, 518, 1, 1], [372, 95, 1, 1], [372, 505, 1, 1], [373, 86, 1, 2], [373, 120, 1, 1], [373, 128, 1, 3], [373, 470, 1, 3], [373, 480, 1, 1], [373, 513, 1, 2], [374, 91, 1, 1], [374, 94, 1, 2], [374, 122, 1, 1], [374, 128, 1, 3], [374, 470, 1, 3], [374, 478, 1, 1], [374, 505, 1, 2], [374, 509, 1, 1], [375, 91, 1, 1], [375, 96, 1, 1], [375, 120, 1, 1], [375, 123, 1, 1], [375, 127, 1, 3], [375, 471, 1, 3], [375, 477, 1, 1], [375, 480, 1, 1], [375, 504, 1, 1], [375, 509, 1, 1], [376, 78, 1, 2], [376, 119, 1, 2], [376, 122, 1, 5], [376, 128, 1, 2], [376, 471, 1, 2], [376, 474, 1, 5], [376, 480, 1, 2], [376, 521, 1, 2], [377, 91, 1, 1], [377, 95, 1, 1], [377, 122, 1, 3], [377, 476, 1, 3], [377, 505, 1, 1], [377, 509, 1, 1], [378, 91, 1, 1], [378, 93, 1, 1], [378, 96, 1, 1], [378, 118, 1, 1], [378, 120, 1, 1], [378, 480, 1, 1], [378, 482, 1, 1], [378, 504, 1, 1], [378, 507, 1, 1], [378, 509, 1, 1], [379, 96, 1, 2], [379, 105, 1, 1], [379, 119, 1, 2], [379, 480, 1, 2], [379, 495, 1, 1], [379, 503, 1, 2], [380, 100, 1, 4], [380, 119, 1, 3], [380, 479, 1, 3], [380, 497, 1, 4], [381, 96, 1, 1], [381, 101, 1, 1], [381, 104, 1, 1], [381, 119, 1, 3], [381, 479, 1, 3], [381, 496, 1, 1], [381, 499, 1, 1], [381, 504, 1, 1], [382, 101, 1, 1], [382, 104, 1, 1], [382, 115, 1, 1], [382, 118, 1, 2], [382, 481, 1, 2], [382, 485, 1, 1], [382, 496, 1, 1], [382, 499, 1, 1], [383, 102, 1, 2], [383, 106, 1, 1], [383, 113, 1, 2], [383, 116, 1, 3], [383, 482, 1, 3], [383, 486, 1, 2], [383, 494, 1, 1], [383, 497, 1, 2], [384, 104, 1, 2], [384, 113, 1, 1], [384, 116, 1, 3], [384, 482, 1, 3], [384, 487, 1, 1], [384, 495, 1, 2], [385, 105, 1, 1], [385, 108, 1, 1], [385, 111, 1, 3], [385, 487, 1, 3], [385, 492, 1, 1], [385, 495, 1, 1], [386, 109, 1, 2], [386, 490, 1, 2], [387, 108, 1, 1], [387, 492, 1, 1], [388, 107, 1, 1], [388, 109, 1, 5], [388, 117, 1, 3], [388, 481, 1, 3], [388, 487, 1, 5], [388, 493, 1, 1], [389, 109, 1, 1], [389, 115, 1, 1], [389, 117, 1, 2], [389, 120, 1, 1], [389, 480, 1, 1], [389, 482, 1, 2], [389, 485, 1, 1], [389, 491, 1, 1], [390, 105, 1, 2], [390, 120, 1, 3], [390, 478, 1, 3], [390, 494, 1, 2], [391, 105, 1, 1], [391, 107, 1, 1], [391, 121, 1, 2], [391, 478, 1, 2], [391, 493, 1, 1], [391, 495, 1, 1], [392, 107, 1, 1], [392, 121, 1, 2], [392, 126, 1, 1], [392, 130, 1, 1], [392, 470, 1, 1], [392, 474, 1, 1], [392, 478, 1, 2], [392, 493, 1, 1], [393, 105, 1, 1], [393, 107, 1, 1], [393, 120, 1, 1], [393, 124, 1, 3], [393, 128, 1, 4], [393, 469, 1, 4], [393, 474, 1, 3], [393, 480, 1, 1], [393, 493, 1, 1], [393, 495, 1, 1], [394, 100, 1, 2], [394, 104, 1, 4], [394, 122, 1, 1], [394, 124, 1, 3], [394, 129, 1, 4], [394, 468, 1, 4], [394, 474, 1, 3], [394, 478, 1, 1], [394, 493, 1, 4], [394, 499, 1, 2], [395, 102, 1, 3], [395, 121, 1, 1], [395, 123, 1, 1], [395, 125, 1, 1], [395, 130, 1, 3], [395, 468, 1, 3], [395, 475, 1, 1], [395, 477, 1, 1], [395, 479, 1, 1], [395, 496, 1, 3], [396, 119, 1, 1], [396, 130, 1, 1], [396, 470, 1, 1], [396, 481, 1, 1], [397, 102, 1, 2], [397, 497, 1, 2], [398, 104, 1, 1], [398, 132, 1, 1], [398, 134, 1, 3], [398, 166, 1, 1], [398, 434, 1, 1], [398, 464, 1, 3], [398, 468, 1, 1], [398, 496, 1, 1], [399, 104, 1, 2], [399, 133, 1, 4], [399, 165, 1, 3], [399, 433, 1, 3], [399, 464, 1, 4], [399, 495, 1, 2], [400, 102, 1, 2], [400, 135, 1, 1], [400, 163, 1, 6], [400, 432, 1, 6], [400, 465, 1, 1], [400, 497, 1, 2], [401, 101, 1, 2], [401, 135, 1, 2], [401, 163, 1, 6], [401, 432, 1, 6], [401, 464, 1, 2], [401, 498, 1, 2], [402, 100, 1, 1], [402, 136, 1, 2], [402, 162, 1, 7], [402, 432, 1, 7], [402, 463, 1, 2], [402, 500, 1, 1], [403, 97, 1, 3], [403, 135, 1, 3], [403, 160, 1, 2], [403, 166, 1, 2], [403, 433, 1, 2], [403, 439, 1, 2], [403, 463, 1, 3], [403, 501, 1, 3], [404, 99, 1, 1], [404, 135, 1, 3], [404, 145, 1, 4], [404, 155, 1, 1], [404, 159, 1, 1], [404, 167, 1, 2], [404, 432, 1, 2], [404, 441, 1, 1], [404, 445, 1, 1], [404, 452, 1, 4], [404, 463, 1, 3], [404, 501, 1, 1], [405, 99, 1, 1], [405, 133, 1, 1], [405, 135, 1, 2], [405, 144, 1, 5], [405, 154, 1, 2], [405, 158, 1, 2], [405, 168, 1, 1], [405, 432, 1, 1], [405, 441, 1, 2], [405, 445, 1, 2], [405, 452, 1, 5], [405, 464, 1, 2], [405, 467, 1, 1], [405, 501, 1, 1], [406, 131, 1, 1], [406, 140, 1, 1], [406, 143, 1, 1], [406, 147, 1, 1], [406, 152, 1, 1], [406, 156, 1, 2], [406, 168, 1, 2], [406, 431, 1, 2], [406, 443, 1, 2], [406, 448, 1, 1], [406, 453, 1, 1], [406, 457, 1, 1], [406, 460, 1, 1], [406, 469, 1, 1], [407, 129, 1, 2], [407, 133, 1, 2], [407, 139, 1, 2], [407, 142, 1, 1], [407, 147, 1, 1], [407, 152, 1, 1], [407, 167, 1, 1], [407, 433, 1, 1], [407, 448, 1, 1], [407, 453, 1, 1], [407, 458, 1, 1], [407, 460, 1, 2], [407, 466, 1, 2], [407, 470, 1, 2], [408, 130, 1, 1], [408, 132, 1, 1], [408, 134, 1, 1], [408, 136, 1, 3], [408, 141, 1, 1], [408, 149, 1, 1], [408, 451, 1, 1], [408, 459, 1, 1], [408, 462, 1, 3], [408, 466, 1, 1], [408, 468, 1, 1], [408, 470, 1, 1], [409, 130, 1, 2], [409, 137, 1, 1], [409, 148, 1, 2], [409, 167, 1, 1], [409, 433, 1, 1], [409, 451, 1, 2], [409, 463, 1, 1], [409, 469, 1, 2], [410, 131, 1, 1], [410, 135, 1, 1], [410, 137, 1, 1], [410, 463, 1, 1], [410, 465, 1, 1], [410, 469, 1, 1], [411, 129, 1, 2], [411, 135, 1, 2], [411, 169, 1, 1], [411, 431, 1, 1], [411, 464, 1, 2], [411, 470, 1, 2], [412, 169, 1, 1], [412, 431, 1, 1], [413, 138, 1, 1], [413, 169, 1, 2], [413, 430, 1, 2], [413, 462, 1, 1], [414, 137, 1, 1], [414, 168, 1, 3], [414, 430, 1, 3], [414, 463, 1, 1], [420, 169, 1, 1], [420, 431, 1, 1], [421, 169, 1, 1], [421, 172, 1, 2], [421, 427, 1, 2], [421, 431, 1, 1], [422, 172, 1, 2], [422, 427, 1, 2], [423, 173, 1, 2], [423, 426, 1, 2], [424, 173, 1, 3], [424, 425, 1, 3], [425, 172, 1, 3], [425, 426, 1, 3], [427, 171, 1, 1], [427, 429, 1, 1], [428, 169, 1, 3], [428, 429, 1, 3], [429, 169, 1, 3], [429, 429, 1, 3], [431, 167, 1, 1], [431, 433, 1, 1], [432, 163, 1, 1], [432, 167, 1, 1], [432, 433, 1, 1], [432, 437, 1, 1], [434, 167, 1, 1], [434, 433, 1, 1], [435, 166, 1, 1], [435, 434, 1, 1], [436, 174, 1, 1], [436, 180, 1, 1], [436, 420, 1, 1], [436, 426, 1, 1], [437, 169, 1, 1], [437, 171, 1, 1], [437, 174, 1, 2], [437, 177, 1, 5], [437, 419, 1, 5], [437, 425, 1, 2], [437, 429, 1, 1], [437, 431, 1, 1], [438, 167, 1, 1], [438, 171, 1, 1], [438, 174, 1, 1], [438, 180, 1, 3], [438, 418, 1, 3], [438, 426, 1, 1], [438, 429, 1, 1], [438, 433, 1, 1], [439, 174, 1, 1], [439, 426, 1, 1], [441, 180, 1, 1], [441, 420, 1, 1], [443, 181, 1, 1], [443, 419, 1, 1], [444, 181, 1, 2], [444, 185, 1, 2], [444, 414, 1, 2], [444, 418, 1, 2], [445, 185, 1, 2], [445, 414, 1, 2], [446, 186, 1, 1], [446, 414, 1, 1], [447, 187, 1, 1], [447, 413, 1, 1], [448, 187, 1, 3], [448, 411, 1, 3], [449, 187, 1, 4], [449, 410, 1, 4], [450, 187, 1, 4], [450, 410, 1, 4], [451, 184, 1, 4], [451, 413, 1, 4], [452, 183, 1, 1], [452, 185, 1, 2], [452, 414, 1, 2], [452, 417, 1, 1], [454, 182, 1, 1], [454, 418, 1, 1], [456, 178, 1, 1], [456, 181, 1, 2], [456, 418, 1, 2], [456, 422, 1, 1], [457, 179, 1, 4], [457, 418, 1, 4], [458, 177, 1, 1], [458, 179, 1, 2], [458, 420, 1, 2], [458, 423, 1, 1], [459, 177, 1, 1], [459, 300, 1, 1], [459, 423, 1, 1], [460, 176, 1, 2], [460, 299, 1, 3], [460, 423, 1, 2], [461, 176, 1, 1], [461, 299, 1, 3], [461, 424, 1, 1], [462, 178, 1, 1], [462, 181, 1, 1], [462, 298, 1, 1], [462, 302, 1, 1], [462, 419, 1, 1], [462, 422, 1, 1], [463, 177, 1, 1], [463, 180, 1, 3], [463, 418, 1, 3], [463, 423, 1, 1], [464, 177, 1, 2], [464, 181, 1, 1], [464, 205, 1, 2], [464, 394, 1, 2], [464, 419, 1, 1], [464, 422, 1, 2], [465, 182, 1, 1], [465, 205, 1, 2], [465, 296, 1, 1], [465, 304, 1, 1], [465, 394, 1, 2], [465, 418, 1, 1], [466, 182, 1, 2], [466, 205, 1, 5], [466, 391, 1, 5], [466, 417, 1, 2], [467, 181, 1, 3], [467, 204, 1, 1], [467, 208, 1, 1], [467, 392, 1, 1], [467, 396, 1, 1], [467, 417, 1, 3], [468, 203, 1, 2], [468, 208, 1, 1], [468, 293, 1, 1], [468, 307, 1, 1], [468, 392, 1, 1], [468, 396, 1, 2], [469, 213, 1, 1], [469, 387, 1, 1], [470, 181, 1, 1], [470, 212, 1, 2], [470, 291, 1, 1], [470, 309, 1, 1], [470, 387, 1, 2], [470, 419, 1, 1], [471, 182, 1, 1], [471, 200, 1, 2], [471, 213, 1, 2], [471, 386, 1, 2], [471, 399, 1, 2], [471, 418, 1, 1], [472, 181, 1, 2], [472, 200, 1, 1], [472, 288, 1, 1], [472, 312, 1, 1], [472, 400, 1, 1], [472, 418, 1, 2], [473, 171, 1, 1], [473, 181, 1, 1], [473, 191, 1, 5], [473, 200, 1, 1], [473, 220, 1, 1], [473, 288, 1, 1], [473, 312, 1, 1], [473, 380, 1, 1], [473, 400, 1, 1], [473, 405, 1, 5], [473, 419, 1, 1], [473, 429, 1, 1], [474, 168, 1, 1], [474, 172, 1, 1], [474, 178, 1, 1], [474, 181, 1, 1], [474, 191, 1, 1], [474, 194, 1, 1], [474, 201, 1, 1], [474, 213, 1, 1], [474, 219, 1, 3], [474, 379, 1, 3], [474, 387, 1, 1], [474, 399, 1, 1], [474, 406, 1, 1], [474, 409, 1, 1], [474, 419, 1, 1], [474, 422, 1, 1], [474, 428, 1, 1], [474, 432, 1, 1], [475, 168, 1, 2], [475, 178, 1, 4], [475, 186, 1, 2], [475, 189, 1, 1], [475, 194, 1, 2], [475, 199, 1, 1], [475, 219, 1, 1], [475, 222, 1, 1], [475, 225, 1, 2], [475, 284, 1, 2], [475, 315, 1, 2], [475, 374, 1, 2], [475, 378, 1, 1], [475, 381, 1, 1], [475, 401, 1, 1], [475, 405, 1, 2], [475, 411, 1, 1], [475, 413, 1, 2], [475, 419, 1, 4], [475, 431, 1, 2], [476, 160, 1, 1], [476, 169, 1, 1], [476, 173, 1, 2], [476, 181, 1, 1], [476, 185, 1, 4], [476, 197, 1, 1], [476, 216, 1, 2], [476, 224, 1, 3], [476, 283, 1, 1], [476, 285, 1, 1], [476, 315, 1, 1], [476, 317, 1, 1], [476, 374, 1, 3], [476, 383, 1, 2], [476, 403, 1, 1], [476, 412, 1, 4], [476, 419, 1, 1], [476, 426, 1, 2], [476, 431, 1, 1], [476, 440, 1, 1], [477, 164, 1, 1], [477, 172, 1, 2], [477, 175, 1, 3], [477, 184, 1, 2], [477, 225, 1, 2], [477, 374, 1, 2], [477, 415, 1, 2], [477, 423, 1, 3], [477, 427, 1, 2], [477, 436, 1, 1], [478, 165, 1, 2], [478, 171, 1, 1], [478, 175, 1, 1], [478, 179, 1, 2], [478, 184, 1, 2], [478, 195, 1, 1], [478, 225, 1, 1], [478, 277, 1, 1], [478, 323, 1, 1], [478, 375, 1, 1], [478, 405, 1, 1], [478, 415, 1, 2], [478, 420, 1, 2], [478, 425, 1, 1], [478, 429, 1, 1], [478, 434, 1, 2], [479, 180, 1, 1], [479, 182, 1, 1], [479, 225, 1, 1], [479, 275, 1, 1], [479, 279, 1, 1], [479, 283, 1, 1], [479, 317, 1, 1], [479, 321, 1, 1], [479, 325, 1, 1], [479, 375, 1, 1], [479, 418, 1, 1], [479, 420, 1, 1], [480, 183, 1, 1], [480, 186, 1, 1], [480, 224, 1, 2], [480, 240, 1, 2], [480, 267, 1, 1], [480, 279, 1, 1], [480, 281, 1, 1], [480, 319, 1, 1], [480, 321, 1, 1], [480, 333, 1, 1], [480, 359, 1, 2], [480, 375, 1, 2], [480, 414, 1, 1], [480, 417, 1, 1], [481, 179, 1, 1], [481, 184, 1, 1], [481, 187, 1, 1], [481, 223, 1, 1], [481, 225, 1, 1], [481, 240, 1, 4], [481, 249, 1, 1], [481, 251, 1, 1], [481, 262, 1, 2], [481, 266, 1, 2], [481, 279, 1, 1], [481, 321, 1, 1], [481, 333, 1, 2], [481, 337, 1, 2], [481, 349, 1, 1], [481, 351, 1, 1], [481, 357, 1, 4], [481, 375, 1, 1], [481, 377, 1, 1], [481, 413, 1, 1], [481, 416, 1, 1], [481, 421, 1, 1], [482, 178, 1, 1], [482, 240, 1, 1], [482, 244, 1, 1], [482, 249, 1, 3], [482, 262, 1, 2], [482, 265, 1, 1], [482, 335, 1, 1], [482, 337, 1, 2], [482, 349, 1, 3], [482, 356, 1, 1], [482, 360, 1, 1], [482, 422, 1, 1], [483, 187, 1, 3], [483, 224, 1, 1], [483, 239, 1, 1], [483, 251, 1, 2], [483, 269, 1, 2], [483, 275, 1, 1], [483, 325, 1, 1], [483, 330, 1, 2], [483, 348, 1, 2], [483, 361, 1, 1], [483, 376, 1, 1], [483, 411, 1, 3], [484, 224, 1, 1], [484, 376, 1, 1], [485, 179, 1, 2], [485, 187, 1, 1], [485, 225, 1, 1], [485, 227, 1, 2], [485, 272, 1, 1], [485, 274, 1, 1], [485, 326, 1, 1], [485, 328, 1, 1], [485, 372, 1, 2], [485, 375, 1, 1], [485, 413, 1, 1], [485, 420, 1, 2], [486, 179, 1, 1], [486, 227, 1, 1], [486, 236, 1, 1], [486, 260, 1, 1], [486, 269, 1, 1], [486, 331, 1, 1], [486, 340, 1, 1], [486, 364, 1, 1], [486, 373, 1, 1], [486, 421, 1, 1], [487, 228, 1, 1], [487, 235, 1, 2], [487, 254, 1, 2], [487, 270, 1, 1], [487, 330, 1, 1], [487, 345, 1, 2], [487, 364, 1, 2], [487, 372, 1, 1], [488, 228, 1, 2], [488, 235, 1, 1], [488, 254, 1, 3], [488, 261, 1, 1], [488, 339, 1, 1], [488, 344, 1, 3], [488, 365, 1, 1], [488, 371, 1, 2], [489, 228, 1, 3], [489, 234, 1, 1], [489, 255, 1, 1], [489, 345, 1, 1], [489, 366, 1, 1], [489, 370, 1, 3], [490, 225, 1, 1], [490, 227, 1, 3], [490, 234, 1, 2], [490, 253, 1, 1], [490, 257, 1, 1], [490, 260, 1, 1], [490, 340, 1, 1], [490, 343, 1, 1], [490, 347, 1, 1], [490, 365, 1, 2], [490, 371, 1, 3], [490, 375, 1, 1], [491, 224, 1, 1], [491, 226, 1, 2], [491, 253, 1, 1], [491, 347, 1, 1], [491, 373, 1, 2], [491, 376, 1, 1], [492, 223, 1, 1], [492, 229, 1, 2], [492, 233, 1, 2], [492, 236, 1, 1], [492, 251, 1, 1], [492, 349, 1, 1], [492, 364, 1, 1], [492, 366, 1, 2], [492, 370, 1, 2], [492, 377, 1, 1], [493, 218, 1, 1], [493, 223, 1, 2], [493, 226, 1, 2], [493, 230, 1, 1], [493, 232, 1, 1], [493, 368, 1, 1], [493, 370, 1, 1], [493, 373, 1, 2], [493, 376, 1, 2], [493, 382, 1, 1], [494, 219, 1, 2], [494, 222, 1, 1], [494, 233, 1, 1], [494, 367, 1, 1], [494, 378, 1, 1], [494, 380, 1, 2], [495, 222, 1, 1], [495, 231, 1, 1], [495, 234, 1, 1], [495, 366, 1, 1], [495, 369, 1, 1], [495, 378, 1, 1]], [[64, 298, 1, 1], [64, 302, 1, 1], [67, 297, 1, 1], [67, 303, 1, 1], [91, 293, 1, 1], [91, 307, 1, 1], [92, 299, 1, 1], [92, 301, 1, 1], [119, 293, 1, 1], [119, 307, 1, 1], [120, 294, 1, 1], [120, 298, 1, 1], [120, 302, 1, 1], [120, 306, 1, 1], [122, 298, 1, 1], [122, 302, 1, 1], [126, 296, 1, 2], [126, 303, 1, 2], [127, 299, 1, 1], [127, 301, 1, 1], [130, 299, 1, 1], [130, 301, 1, 1], [131, 291, 1, 1], [131, 299, 1, 1], [131, 301, 1, 1], [131, 309, 1, 1], [132, 290, 1, 1], [132, 292, 1, 1], [132, 298, 1, 1], [132, 302, 1, 1], [132, 308, 1, 1], [132, 310, 1, 1], [133, 291, 1, 1], [133, 298, 1, 1], [133, 302, 1, 1], [133, 309, 1, 1], [134, 273, 1, 1], [134, 294, 1, 2], [134, 297, 1, 1], [134, 303, 1, 1], [134, 305, 1, 2], [134, 327, 1, 1], [135, 275, 1, 2], [135, 296, 1, 2], [135, 303, 1, 2], [135, 324, 1, 2], [136, 275, 1, 2], [136, 324, 1, 2], [137, 295, 1, 1], [137, 305, 1, 1], [138, 290, 1, 1], [138, 310, 1, 1], [139, 280, 1, 1], [139, 291, 1, 1], [139, 294, 1, 1], [139, 306, 1, 1], [139, 309, 1, 1], [139, 320, 1, 1], [140, 281, 1, 2], [140, 284, 1, 2], [140, 291, 1, 1], [140, 293, 1, 1], [140, 307, 1, 1], [140, 309, 1, 1], [140, 315, 1, 2], [140, 318, 1, 2], [141, 291, 1, 1], [141, 309, 1, 1], [142, 283, 1, 3], [142, 287, 1, 2], [142, 290, 1, 1], [142, 310, 1, 1], [142, 312, 1, 2], [142, 315, 1, 3], [143, 285, 1, 1], [143, 288, 1, 1], [143, 312, 1, 1], [143, 315, 1, 1], [144, 285, 1, 1], [144, 315, 1, 1], [146, 285, 1, 1], [146, 315, 1, 1], [147, 285, 1, 1], [147, 315, 1, 1], [148, 285, 1, 2], [148, 314, 1, 2], [149, 283, 1, 1], [149, 285, 1, 1], [149, 315, 1, 1], [149, 317, 1, 1], [150, 280, 1, 1], [150, 320, 1, 1], [154, 285, 1, 1], [154, 315, 1, 1], [156, 282, 1, 1], [156, 318, 1, 1], [157, 285, 1, 1], [157, 315, 1, 1], [158, 216, 1, 1], [158, 230, 1, 1], [158, 286, 1, 1], [158, 314, 1, 1], [158, 370, 1, 1], [158, 384, 1, 1], [159, 217, 1, 1], [159, 262, 1, 1], [159, 285, 1, 1], [159, 315, 1, 1], [159, 338, 1, 1], [159, 383, 1, 1], [160, 264, 1, 1], [160, 286, 1, 2], [160, 313, 1, 2], [160, 336, 1, 1], [161, 263, 1, 1], [161, 265, 1, 1], [161, 286, 1, 2], [161, 313, 1, 2], [161, 335, 1, 1], [161, 337, 1, 1], [162, 275, 1, 1], [162, 282, 1, 1], [162, 286, 1, 3], [162, 312, 1, 3], [162, 318, 1, 1], [162, 325, 1, 1], [163, 225, 1, 1], [163, 228, 1, 1], [163, 230, 1, 1], [163, 276, 1, 1], [163, 283, 1, 2], [163, 286, 1, 2], [163, 313, 1, 2], [163, 316, 1, 2], [163, 324, 1, 1], [163, 370, 1, 1], [163, 372, 1, 1], [163, 375, 1, 1], [164, 222, 1, 3], [164, 232, 1, 1], [164, 235, 1, 1], [164, 278, 1, 1], [164, 281, 1, 1], [164, 284, 1, 1], [164, 316, 1, 1], [164, 319, 1, 1], [164, 322, 1, 1], [164, 365, 1, 1], [164, 368, 1, 1], [164, 376, 1, 3], [165, 219, 1, 1], [165, 224, 1, 1], [165, 231, 1, 1], [165, 235, 1, 1], [165, 280, 1, 1], [165, 320, 1, 1], [165, 365, 1, 1], [165, 369, 1, 1], [165, 376, 1, 1], [165, 381, 1, 1], [166, 265, 1, 1], [166, 267, 1, 1], [166, 274, 1, 1], [166, 326, 1, 1], [166, 333, 1, 1], [166, 335, 1, 1], [167, 236, 1, 1], [167, 264, 1, 2], [167, 270, 1, 1], [167, 274, 1, 1], [167, 326, 1, 1], [167, 330, 1, 1], [167, 335, 1, 2], [167, 364, 1, 1], [168, 261, 1, 1], [168, 272, 1, 3], [168, 326, 1, 3], [168, 339, 1, 1], [169, 273, 1, 1], [169, 327, 1, 1], [170, 263, 1, 1], [170, 337, 1, 1], [171, 264, 1, 1], [171, 336, 1, 1], [172, 236, 1, 1], [172, 364, 1, 1], [173, 236, 1, 1], [173, 252, 1, 2], [173, 264, 1, 2], [173, 335, 1, 2], [173, 347, 1, 2], [173, 364, 1, 1], [174, 242, 1, 1], [174, 264, 1, 2], [174, 335, 1, 2], [174, 358, 1, 1], [175, 237, 1, 1], [175, 261, 1, 1], [175, 263, 1, 1], [175, 337, 1, 1], [175, 339, 1, 1], [175, 363, 1, 1], [176, 238, 1, 1], [176, 248, 1, 1], [176, 250, 1, 1], [176, 261, 1, 1], [176, 339, 1, 1], [176, 350, 1, 1], [176, 352, 1, 1], [176, 362, 1, 1], [177, 241, 1, 1], [177, 248, 1, 1], [177, 253, 1, 1], [177, 260, 1, 1], [177, 340, 1, 1], [177, 347, 1, 1], [177, 352, 1, 1], [177, 359, 1, 1], [178, 236, 1, 1], [178, 239, 1, 1], [178, 241, 1, 1], [178, 248, 1, 1], [178, 253, 1, 5], [178, 260, 1, 1], [178, 340, 1, 1], [178, 343, 1, 5], [178, 352, 1, 1], [178, 359, 1, 1], [178, 361, 1, 1], [178, 364, 1, 1], [179, 239, 1, 1], [179, 243, 1, 1], [179, 246, 1, 3], [179, 257, 1, 3], [179, 341, 1, 3], [179, 352, 1, 3], [179, 357, 1, 1], [179, 361, 1, 1], [180, 240, 1, 1], [180, 243, 1, 2], [180, 257, 1, 3], [180, 341, 1, 3], [180, 356, 1, 2], [180, 360, 1, 1], [181, 238, 1, 1], [181, 240, 1, 1], [181, 360, 1, 1], [181, 362, 1, 1], [183, 233, 1, 1], [183, 235, 1, 1], [183, 241, 1, 1], [183, 359, 1, 1], [183, 365, 1, 1], [183, 367, 1, 1], [184, 241, 1, 2], [184, 358, 1, 2], [185, 238, 1, 1], [185, 362, 1, 1], [187, 244, 1, 1], [187, 356, 1, 1], [188, 244, 1, 1], [188, 356, 1, 1], [189, 240, 1, 1], [189, 242, 1, 1], [189, 358, 1, 1], [189, 360, 1, 1], [191, 244, 1, 1], [191, 356, 1, 1], [192, 246, 1, 1], [192, 354, 1, 1], [193, 247, 1, 1], [193, 249, 1, 1], [193, 351, 1, 1], [193, 353, 1, 1], [194, 249, 1, 2], [194, 350, 1, 2], [195, 249, 1, 2], [195, 350, 1, 2], [196, 248, 1, 1], [196, 352, 1, 1], [197, 249, 1, 1], [197, 351, 1, 1], [198, 248, 1, 2], [198, 351, 1, 2], [199, 245, 1, 3], [199, 353, 1, 3], [203, 246, 1, 1], [203, 354, 1, 1], [204, 232, 1, 1], [204, 247, 1, 1], [204, 353, 1, 1], [204, 368, 1, 1], [205, 227, 1, 1], [205, 229, 1, 1], [205, 232, 1, 1], [205, 368, 1, 1], [205, 371, 1, 1], [205, 373, 1, 1], [206, 229, 1, 1], [206, 231, 1, 1], [206, 234, 1, 1], [206, 243, 1, 1], [206, 245, 1, 3], [206, 353, 1, 3], [206, 357, 1, 1], [206, 366, 1, 1], [206, 369, 1, 1], [206, 371, 1, 1], [207, 223, 1, 2], [207, 228, 1, 1], [207, 243, 1, 1], [207, 245, 1, 3], [207, 353, 1, 3], [207, 357, 1, 1], [207, 372, 1, 1], [207, 376, 1, 2], [208, 243, 1, 1], [208, 357, 1, 1], [209, 224, 1, 1], [209, 226, 1, 1], [209, 234, 1, 1], [209, 242, 1, 1], [209, 358, 1, 1], [209, 366, 1, 1], [209, 374, 1, 1], [209, 376, 1, 1], [210, 235, 1, 4], [210, 240, 1, 3], [210, 358, 1, 3], [210, 362, 1, 4], [211, 234, 1, 1], [211, 240, 1, 2], [211, 359, 1, 2], [211, 366, 1, 1], [213, 238, 1, 1], [213, 362, 1, 1], [215, 236, 1, 2], [215, 239, 1, 1], [215, 361, 1, 1], [215, 363, 1, 2], [216, 237, 1, 1], [216, 241, 1, 2], [216, 358, 1, 2], [216, 363, 1, 1], [217, 242, 1, 1], [217, 358, 1, 1], [218, 243, 1, 1], [218, 247, 1, 1], [218, 353, 1, 1], [218, 357, 1, 1], [219, 246, 1, 2], [219, 353, 1, 2], [221, 246, 1, 1], [221, 354, 1, 1], [223, 247, 1, 2], [223, 352, 1, 2], [224, 239, 1, 1], [224, 247, 1, 2], [224, 352, 1, 2], [224, 361, 1, 1], [225, 242, 1, 1], [225, 246, 1, 1], [225, 354, 1, 1], [225, 358, 1, 1], [226, 238, 1, 1], [226, 240, 1, 2], [226, 246, 1, 1], [226, 354, 1, 1], [226, 359, 1, 2], [226, 362, 1, 1], [227, 242, 1, 5], [227, 354, 1, 5], [228, 244, 1, 1], [228, 356, 1, 1], [229, 235, 1, 2], [229, 242, 1, 1], [229, 358, 1, 1], [229, 364, 1, 2], [231, 244, 1, 1], [231, 356, 1, 1], [232, 248, 1, 1], [232, 352, 1, 1], [233, 250, 1, 1], [233, 350, 1, 1], [234, 251, 1, 1], [234, 349, 1, 1], [235, 251, 1, 2], [235, 348, 1, 2], [236, 248, 1, 4], [236, 349, 1, 4], [237, 250, 1, 3], [237, 348, 1, 3], [238, 247, 1, 2], [238, 352, 1, 2], [240, 251, 1, 1], [240, 349, 1, 1], [241, 252, 1, 1], [241, 255, 1, 1], [241, 345, 1, 1], [241, 348, 1, 1], [242, 255, 1, 2], [242, 344, 1, 2], [244, 253, 1, 1], [244, 347, 1, 1], [245, 255, 1, 1], [245, 345, 1, 1], [247, 259, 1, 2], [247, 340, 1, 2], [249, 260, 1, 1], [249, 340, 1, 1], [250, 262, 1, 1], [250, 338, 1, 1], [252, 265, 1, 1], [252, 335, 1, 1], [254, 268, 1, 1], [254, 332, 1, 1], [255, 269, 1, 1], [255, 331, 1, 1], [256, 270, 1, 3], [256, 328, 1, 3], [257, 271, 1, 4], [257, 326, 1, 4], [258, 271, 1, 6], [258, 324, 1, 6], [259, 272, 1, 5], [259, 324, 1, 5], [260, 271, 1, 6], [260, 324, 1, 6], [261, 270, 1, 6], [261, 325, 1, 6], [262, 264, 1, 1], [262, 268, 1, 2], [262, 331, 1, 2], [262, 336, 1, 1], [263, 262, 1, 1], [263, 265, 1, 1], [263, 335, 1, 1], [263, 338, 1, 1], [264, 243, 1, 1], [264, 251, 1, 1], [264, 260, 1, 1], [264, 340, 1, 1], [264, 349, 1, 1], [264, 357, 1, 1], [265, 228, 1, 1], [265, 242, 1, 1], [265, 254, 1, 1], [265, 346, 1, 1], [265, 358, 1, 1], [265, 372, 1, 1], [267, 230, 1, 1], [267, 240, 1, 1], [267, 360, 1, 1], [267, 370, 1, 1], [268, 246, 1, 4], [268, 351, 1, 4], [269, 239, 1, 1], [269, 361, 1, 1], [270, 239, 1, 2], [270, 360, 1, 2], [271, 210, 1, 1], [271, 226, 1, 1], [271, 233, 1, 2], [271, 239, 1, 2], [271, 360, 1, 2], [271, 366, 1, 2], [271, 374, 1, 1], [271, 390, 1, 1], [272, 212, 1, 1], [272, 238, 1, 3], [272, 360, 1, 3], [272, 388, 1, 1], [273, 210, 1, 1], [273, 226, 1, 1], [273, 236, 1, 2], [273, 363, 1, 2], [273, 374, 1, 1], [273, 390, 1, 1], [274, 208, 1, 2], [274, 213, 1, 1], [274, 227, 1, 1], [274, 373, 1, 1], [274, 387, 1, 1], [274, 391, 1, 2], [275, 207, 1, 1], [275, 213, 1, 1], [275, 387, 1, 1], [275, 393, 1, 1], [276, 204, 1, 1], [276, 206, 1, 1], [276, 214, 1, 1], [276, 386, 1, 1], [276, 394, 1, 1], [276, 396, 1, 1], [277, 204, 1, 1], [277, 212, 1, 2], [277, 387, 1, 2], [277, 396, 1, 1], [278, 206, 1, 1], [278, 213, 1, 1], [278, 215, 1, 1], [278, 227, 1, 1], [278, 373, 1, 1], [278, 385, 1, 1], [278, 387, 1, 1], [278, 394, 1, 1], [279, 201, 1, 1], [279, 215, 1, 1], [279, 226, 1, 2], [279, 373, 1, 2], [279, 385, 1, 1], [279, 399, 1, 1], [280, 203, 1, 1], [280, 397, 1, 1], [281, 201, 1, 1], [281, 206, 1, 3], [281, 219, 1, 1], [281, 222, 1, 1], [281, 378, 1, 1], [281, 381, 1, 1], [281, 392, 1, 3], [281, 399, 1, 1], [282, 201, 1, 1], [282, 204, 1, 1], [282, 221, 1, 2], [282, 378, 1, 2], [282, 396, 1, 1], [282, 399, 1, 1], [283, 208, 1, 1], [283, 221, 1, 1], [283, 379, 1, 1], [283, 392, 1, 1], [284, 208, 1, 1], [284, 392, 1, 1], [285, 163, 1, 1], [285, 206, 1, 1], [285, 394, 1, 1], [285, 437, 1, 1], [286, 164, 1, 1], [286, 436, 1, 1], [287, 178, 1, 1], [287, 422, 1, 1], [288, 165, 1, 1], [288, 174, 1, 2], [288, 177, 1, 1], [288, 423, 1, 1], [288, 425, 1, 2], [288, 435, 1, 1], [289, 164, 1, 1], [289, 207, 1, 3], [289, 391, 1, 3], [289, 436, 1, 1], [290, 168, 1, 1], [290, 177, 1, 1], [290, 209, 1, 1], [290, 391, 1, 1], [290, 423, 1, 1], [290, 432, 1, 1], [291, 174, 1, 1], [291, 209, 1, 2], [291, 390, 1, 2], [291, 426, 1, 1], [292, 174, 1, 1], [292, 177, 1, 1], [292, 208, 1, 1], [292, 392, 1, 1], [292, 423, 1, 1], [292, 426, 1, 1], [293, 169, 1, 1], [293, 174, 1, 3], [293, 201, 1, 1], [293, 206, 1, 2], [293, 393, 1, 2], [293, 399, 1, 1], [293, 424, 1, 3], [293, 431, 1, 1], [294, 169, 1, 1], [294, 206, 1, 2], [294, 393, 1, 2], [294, 431, 1, 1], [295, 171, 1, 2], [295, 186, 1, 1], [295, 189, 1, 1], [295, 192, 1, 1], [295, 200, 1, 1], [295, 400, 1, 1], [295, 408, 1, 1], [295, 411, 1, 1], [295, 414, 1, 1], [295, 428, 1, 2], [296, 170, 1, 1], [296, 172, 1, 1], [296, 174, 1, 1], [296, 184, 1, 1], [296, 416, 1, 1], [296, 426, 1, 1], [296, 428, 1, 1], [296, 430, 1, 1], [297, 165, 1, 1], [297, 168, 1, 1], [297, 170, 1, 1], [297, 174, 1, 2], [297, 178, 1, 1], [297, 180, 1, 1], [297, 185, 1, 1], [297, 190, 1, 1], [297, 410, 1, 1], [297, 415, 1, 1], [297, 420, 1, 1], [297, 422, 1, 1], [297, 425, 1, 2], [297, 430, 1, 1], [297, 432, 1, 1], [297, 435, 1, 1], [298, 166, 1, 3], [298, 174, 1, 2], [298, 177, 1, 1], [298, 182, 1, 1], [298, 185, 1, 2], [298, 202, 1, 1], [298, 398, 1, 1], [298, 414, 1, 2], [298, 418, 1, 1], [298, 423, 1, 1], [298, 425, 1, 2], [298, 432, 1, 3], [299, 177, 1, 1], [299, 182, 1, 2], [299, 191, 1, 1], [299, 201, 1, 2], [299, 398, 1, 2], [299, 409, 1, 1], [299, 417, 1, 2], [299, 423, 1, 1], [300, 171, 1, 2], [300, 428, 1, 2], [301, 167, 1, 1], [301, 171, 1, 2], [301, 195, 1, 1], [301, 405, 1, 1], [301, 428, 1, 2], [301, 433, 1, 1], [302, 170, 1, 1], [302, 174, 1, 1], [302, 195, 1, 1], [302, 198, 1, 1], [302, 402, 1, 1], [302, 405, 1, 1], [302, 426, 1, 1], [302, 430, 1, 1], [303, 166, 1, 2], [303, 174, 1, 1], [303, 196, 1, 3], [303, 402, 1, 3], [303, 426, 1, 1], [303, 433, 1, 2], [304, 159, 1, 1], [304, 163, 1, 1], [304, 196, 1, 2], [304, 403, 1, 2], [304, 437, 1, 1], [304, 441, 1, 1], [305, 162, 1, 2], [305, 167, 1, 1], [305, 173, 1, 1], [305, 427, 1, 1], [305, 433, 1, 1], [305, 437, 1, 2], [306, 161, 1, 1], [306, 165, 1, 1], [306, 435, 1, 1], [306, 439, 1, 1], [307, 176, 1, 2], [307, 423, 1, 2], [308, 162, 1, 1], [308, 438, 1, 1], [309, 176, 1, 1], [309, 424, 1, 1], [310, 174, 1, 4], [310, 423, 1, 4], [312, 173, 1, 1], [312, 427, 1, 1], [313, 172, 1, 1], [313, 428, 1, 1], [315, 176, 1, 4], [315, 421, 1, 4], [316, 175, 1, 1], [316, 425, 1, 1], [317, 175, 1, 1], [317, 425, 1, 1], [318, 182, 1, 2], [318, 417, 1, 2], [319, 184, 1, 3], [319, 414, 1, 3], [320, 185, 1, 1], [320, 415, 1, 1], [321, 184, 1, 2], [321, 415, 1, 2], [324, 181, 1, 3], [324, 417, 1, 3], [329, 172, 1, 1], [329, 428, 1, 1], [330, 170, 1, 1], [330, 172, 1, 1], [330, 180, 1, 1], [330, 420, 1, 1], [330, 428, 1, 1], [330, 430, 1, 1], [331, 172, 1, 1], [331, 178, 1, 2], [331, 421, 1, 2], [331, 428, 1, 1], [332, 167, 1, 1], [332, 172, 1, 2], [332, 178, 1, 2], [332, 421, 1, 2], [332, 427, 1, 2], [332, 433, 1, 1], [333, 165, 1, 2], [333, 434, 1, 2], [334, 165, 1, 2], [334, 434, 1, 2], [337, 167, 1, 1], [337, 433, 1, 1], [338, 167, 1, 1], [338, 170, 1, 2], [338, 429, 1, 2], [338, 433, 1, 1], [339, 169, 1, 1], [339, 431, 1, 1], [340, 171, 1, 1], [340, 429, 1, 1], [342, 174, 1, 2], [342, 425, 1, 2], [343, 174, 1, 1], [343, 426, 1, 1], [344, 173, 1, 1], [344, 427, 1, 1], [345, 173, 1, 1], [345, 427, 1, 1], [346, 169, 1, 1], [346, 171, 1, 3], [346, 427, 1, 3], [346, 431, 1, 1], [347, 167, 1, 2], [347, 432, 1, 2], [349, 131, 1, 1], [349, 469, 1, 1], [350, 166, 1, 1], [350, 434, 1, 1], [352, 170, 1, 2], [352, 429, 1, 2], [353, 132, 1, 2], [353, 170, 1, 2], [353, 429, 1, 2], [353, 467, 1, 2], [355, 129, 1, 1], [355, 144, 1, 1], [355, 148, 1, 1], [355, 150, 1, 1], [355, 168, 1, 1], [355, 432, 1, 1], [355, 450, 1, 1], [355, 452, 1, 1], [355, 456, 1, 1], [355, 471, 1, 1], [356, 130, 1, 2], [356, 145, 1, 1], [356, 148, 1, 1], [356, 452, 1, 1], [356, 455, 1, 1], [356, 469, 1, 2], [357, 145, 1, 1], [357, 148, 1, 1], [357, 452, 1, 1], [357, 455, 1, 1], [358, 123, 1, 1], [358, 168, 1, 1], [358, 432, 1, 1], [358, 477, 1, 1], [359, 124, 1, 2], [359, 131, 1, 2], [359, 138, 1, 1], [359, 146, 1, 2], [359, 151, 1, 1], [359, 155, 1, 1], [359, 169, 1, 1], [359, 431, 1, 1], [359, 445, 1, 1], [359, 449, 1, 1], [359, 453, 1, 2], [359, 462, 1, 1], [359, 468, 1, 2], [359, 475, 1, 2], [360, 127, 1, 1], [360, 130, 1, 1], [360, 136, 1, 2], [360, 146, 1, 2], [360, 157, 1, 1], [360, 169, 1, 1], [360, 431, 1, 1], [360, 443, 1, 1], [360, 453, 1, 2], [360, 463, 1, 2], [360, 470, 1, 1], [360, 473, 1, 1], [361, 129, 1, 1], [361, 132, 1, 2], [361, 139, 1, 1], [361, 146, 1, 1], [361, 153, 1, 2], [361, 446, 1, 2], [361, 454, 1, 1], [361, 461, 1, 1], [361, 467, 1, 2], [361, 471, 1, 1], [362, 129, 1, 1], [362, 133, 1, 1], [362, 142, 1, 1], [362, 145, 1, 2], [362, 160, 1, 1], [362, 168, 1, 1], [362, 432, 1, 1], [362, 440, 1, 1], [362, 454, 1, 2], [362, 458, 1, 1], [362, 467, 1, 1], [362, 471, 1, 1], [363, 134, 1, 2], [363, 142, 1, 1], [363, 161, 1, 1], [363, 169, 1, 1], [363, 431, 1, 1], [363, 439, 1, 1], [363, 458, 1, 1], [363, 465, 1, 2], [364, 135, 1, 1], [364, 162, 1, 1], [364, 438, 1, 1], [364, 465, 1, 1], [365, 133, 1, 2], [365, 168, 1, 1], [365, 432, 1, 1], [365, 466, 1, 2], [366, 133, 1, 1], [366, 164, 1, 6], [366, 431, 1, 6], [366, 467, 1, 1], [367, 166, 1, 3], [367, 432, 1, 3], [368, 134, 1, 2], [368, 166, 1, 3], [368, 432, 1, 3], [368, 465, 1, 2], [369, 134, 1, 1], [369, 466, 1, 1], [370, 129, 1, 1], [370, 133, 1, 2], [370, 466, 1, 2], [370, 471, 1, 1], [372, 89, 1, 1], [372, 120, 1, 1], [372, 128, 1, 1], [372, 472, 1, 1], [372, 480, 1, 1], [372, 511, 1, 1], [373, 88, 1, 1], [373, 121, 1, 2], [373, 478, 1, 2], [373, 512, 1, 1], [374, 93, 1, 1], [374, 120, 1, 2], [374, 131, 1, 1], [374, 469, 1, 1], [374, 479, 1, 2], [374, 507, 1, 1], [375, 122, 1, 1], [375, 130, 1, 1], [375, 470, 1, 1], [375, 478, 1, 1], [376, 117, 1, 1], [376, 483, 1, 1], [377, 94, 1, 1], [377, 118, 1, 1], [377, 125, 1, 1], [377, 127, 1, 4], [377, 470, 1, 4], [377, 475, 1, 1], [377, 482, 1, 1], [377, 506, 1, 1], [378, 95, 1, 1], [378, 119, 1, 1], [378, 121, 1, 1], [378, 124, 1, 2], [378, 130, 1, 1], [378, 470, 1, 1], [378, 475, 1, 2], [378, 479, 1, 1], [378, 481, 1, 1], [378, 505, 1, 1], [379, 121, 1, 1], [379, 479, 1, 1], [380, 97, 1, 1], [380, 104, 1, 1], [380, 122, 1, 1], [380, 478, 1, 1], [380, 496, 1, 1], [380, 503, 1, 1], [381, 103, 1, 1], [381, 497, 1, 1], [382, 121, 1, 1], [382, 479, 1, 1], [383, 101, 1, 1], [383, 119, 1, 1], [383, 481, 1, 1], [383, 499, 1, 1], [384, 103, 1, 1], [384, 107, 1, 1], [384, 114, 1, 1], [384, 119, 1, 1], [384, 481, 1, 1], [384, 486, 1, 1], [384, 493, 1, 1], [384, 497, 1, 1], [385, 106, 1, 1], [385, 114, 1, 1], [385, 486, 1, 1], [385, 494, 1, 1], [386, 111, 1, 2], [386, 488, 1, 2], [387, 109, 1, 2], [387, 112, 1, 3], [387, 116, 1, 2], [387, 119, 1, 2], [387, 480, 1, 2], [387, 483, 1, 2], [387, 486, 1, 3], [387, 490, 1, 2], [388, 114, 1, 1], [388, 116, 1, 1], [388, 120, 1, 1], [388, 480, 1, 1], [388, 484, 1, 1], [388, 486, 1, 1], [389, 107, 1, 2], [389, 121, 1, 2], [389, 478, 1, 2], [389, 492, 1, 2], [390, 114, 1, 1], [390, 123, 1, 1], [390, 477, 1, 1], [390, 486, 1, 1], [391, 129, 1, 4], [391, 468, 1, 4], [392, 123, 1, 1], [392, 127, 1, 1], [392, 129, 1, 1], [392, 131, 1, 1], [392, 469, 1, 1], [392, 471, 1, 1], [392, 473, 1, 1], [392, 477, 1, 1], [393, 106, 1, 1], [393, 127, 1, 1], [393, 132, 1, 1], [393, 468, 1, 1], [393, 473, 1, 1], [393, 494, 1, 1], [394, 120, 1, 1], [394, 123, 1, 1], [394, 133, 1, 1], [394, 467, 1, 1], [394, 477, 1, 1], [394, 480, 1, 1], [395, 120, 1, 1], [395, 124, 1, 1], [395, 133, 1, 1], [395, 467, 1, 1], [395, 476, 1, 1], [395, 480, 1, 1], [396, 131, 1, 1], [396, 167, 1, 2], [396, 432, 1, 2], [396, 469, 1, 1], [397, 132, 1, 3], [397, 166, 1, 4], [397, 431, 1, 4], [397, 466, 1, 3], [398, 133, 1, 1], [398, 137, 1, 1], [398, 165, 1, 1], [398, 167, 1, 2], [398, 432, 1, 2], [398, 435, 1, 1], [398, 463, 1, 1], [398, 467, 1, 1], [399, 102, 1, 1], [399, 137, 1, 1], [399, 168, 1, 2], [399, 431, 1, 2], [399, 463, 1, 1], [399, 498, 1, 1], [402, 160, 1, 1], [402, 169, 1, 1], [402, 431, 1, 1], [402, 440, 1, 1], [403, 138, 1, 1], [403, 145, 1, 1], [403, 148, 1, 1], [403, 155, 1, 1], [403, 159, 1, 1], [403, 168, 1, 1], [403, 432, 1, 1], [403, 441, 1, 1], [403, 445, 1, 1], [403, 452, 1, 1], [403, 455, 1, 1], [403, 462, 1, 1], [404, 144, 1, 1], [404, 149, 1, 2], [404, 154, 1, 1], [404, 446, 1, 1], [404, 450, 1, 2], [404, 456, 1, 1], [405, 132, 1, 1], [405, 134, 1, 1], [405, 137, 1, 1], [405, 142, 1, 1], [405, 149, 1, 2], [405, 157, 1, 1], [405, 169, 1, 1], [405, 431, 1, 1], [405, 443, 1, 1], [405, 450, 1, 2], [405, 458, 1, 1], [405, 463, 1, 1], [405, 466, 1, 1], [405, 468, 1, 1], [406, 132, 1, 1], [406, 136, 1, 1], [406, 141, 1, 2], [406, 458, 1, 2], [406, 464, 1, 1], [406, 468, 1, 1], [407, 138, 1, 1], [407, 149, 1, 1], [407, 151, 1, 1], [407, 168, 1, 1], [407, 432, 1, 1], [407, 449, 1, 1], [407, 451, 1, 1], [407, 462, 1, 1], [409, 136, 1, 1], [409, 464, 1, 1], [410, 130, 1, 1], [410, 470, 1, 1], [412, 127, 1, 1], [412, 139, 1, 1], [412, 170, 1, 2], [412, 429, 1, 2], [412, 461, 1, 1], [412, 473, 1, 1], [413, 137, 1, 1], [413, 171, 1, 2], [413, 428, 1, 2], [413, 463, 1, 1], [415, 167, 1, 2], [415, 432, 1, 2], [416, 167, 1, 1], [416, 433, 1, 1], [419, 168, 1, 1], [419, 432, 1, 1], [420, 172, 1, 3], [420, 426, 1, 3], [421, 174, 1, 1], [421, 426, 1, 1], [423, 175, 1, 1], [423, 425, 1, 1], [424, 176, 1, 1], [424, 424, 1, 1], [425, 175, 1, 2], [425, 424, 1, 2], [429, 172, 1, 1], [429, 428, 1, 1], [430, 167, 1, 1], [430, 170, 1, 2], [430, 429, 1, 2], [430, 433, 1, 1], [431, 170, 1, 1], [431, 430, 1, 1], [432, 164, 1, 2], [432, 168, 1, 1], [432, 432, 1, 1], [432, 435, 1, 2], [433, 163, 1, 1], [433, 437, 1, 1], [434, 181, 1, 1], [434, 419, 1, 1], [435, 173, 1, 3], [435, 179, 1, 3], [435, 419, 1, 3], [435, 425, 1, 3], [436, 169, 1, 1], [436, 173, 1, 1], [436, 175, 1, 2], [436, 181, 1, 1], [436, 419, 1, 1], [436, 424, 1, 2], [436, 427, 1, 1], [436, 431, 1, 1], [437, 167, 1, 1], [437, 182, 1, 1], [437, 418, 1, 1], [437, 433, 1, 1], [438, 183, 1, 1], [438, 417, 1, 1], [439, 172, 1, 1], [439, 181, 1, 1], [439, 419, 1, 1], [439, 428, 1, 1], [443, 186, 1, 2], [443, 413, 1, 2], [444, 184, 1, 1], [444, 416, 1, 1], [447, 188, 1, 3], [447, 410, 1, 3], [448, 190, 1, 1], [448, 410, 1, 1], [449, 191, 1, 1], [449, 409, 1, 1], [450, 191, 1, 2], [450, 408, 1, 2], [451, 189, 1, 1], [451, 191, 1, 1], [451, 409, 1, 1], [451, 411, 1, 1], [453, 183, 1, 1], [453, 185, 1, 2], [453, 414, 1, 2], [453, 417, 1, 1], [456, 176, 1, 2], [456, 183, 1, 2], [456, 416, 1, 2], [456, 423, 1, 2], [457, 177, 1, 2], [457, 422, 1, 2], [458, 178, 1, 1], [458, 300, 1, 1], [458, 422, 1, 1], [459, 179, 1, 1], [459, 421, 1, 1], [461, 180, 1, 2], [461, 419, 1, 2], [462, 180, 1, 1], [462, 182, 1, 1], [462, 205, 1, 1], [462, 395, 1, 1], [462, 418, 1, 1], [462, 420, 1, 1], [463, 183, 1, 1], [463, 204, 1, 3], [463, 394, 1, 3], [463, 417, 1, 1], [464, 204, 1, 1], [464, 207, 1, 1], [464, 393, 1, 1], [464, 396, 1, 1], [465, 204, 1, 1], [465, 207, 1, 1], [465, 393, 1, 1], [465, 396, 1, 1], [466, 184, 1, 1], [466, 295, 1, 1], [466, 305, 1, 1], [466, 416, 1, 1], [467, 203, 1, 1], [467, 397, 1, 1], [468, 183, 1, 1], [468, 213, 1, 1], [468, 387, 1, 1], [468, 417, 1, 1], [469, 181, 1, 1], [469, 214, 1, 1], [469, 386, 1, 1], [469, 419, 1, 1], [470, 200, 1, 1], [470, 202, 1, 1], [470, 214, 1, 1], [470, 292, 1, 1], [470, 308, 1, 1], [470, 386, 1, 1], [470, 398, 1, 1], [470, 400, 1, 1], [471, 183, 1, 1], [471, 191, 1, 1], [471, 409, 1, 1], [471, 417, 1, 1], [472, 183, 1, 1], [472, 191, 1, 1], [472, 194, 1, 3], [472, 214, 1, 1], [472, 221, 1, 1], [472, 289, 1, 1], [472, 291, 1, 1], [472, 309, 1, 1], [472, 311, 1, 1], [472, 379, 1, 1], [472, 386, 1, 1], [472, 404, 1, 3], [472, 409, 1, 1], [472, 417, 1, 1], [473, 183, 1, 1], [473, 190, 1, 1], [473, 196, 1, 2], [473, 199, 1, 1], [473, 221, 1, 1], [473, 289, 1, 2], [473, 310, 1, 2], [473, 379, 1, 1], [473, 401, 1, 1], [473, 403, 1, 2], [473, 410, 1, 1], [473, 417, 1, 1], [474, 171, 1, 1], [474, 182, 1, 1], [474, 186, 1, 3], [474, 200, 1, 1], [474, 225, 1, 1], [474, 375, 1, 1], [474, 400, 1, 1], [474, 412, 1, 3], [474, 418, 1, 1], [474, 429, 1, 1], [475, 170, 1, 1], [475, 173, 1, 1], [475, 176, 1, 2], [475, 182, 1, 1], [475, 190, 1, 1], [475, 197, 1, 2], [475, 213, 1, 2], [475, 224, 1, 1], [475, 227, 1, 2], [475, 282, 1, 2], [475, 317, 1, 2], [475, 372, 1, 2], [475, 376, 1, 1], [475, 386, 1, 2], [475, 402, 1, 2], [475, 410, 1, 1], [475, 418, 1, 1], [475, 423, 1, 2], [475, 427, 1, 1], [475, 430, 1, 1], [476, 175, 1, 1], [476, 178, 1, 1], [476, 182, 1, 1], [476, 184, 1, 1], [476, 227, 1, 2], [476, 287, 1, 1], [476, 313, 1, 1], [476, 372, 1, 2], [476, 416, 1, 1], [476, 418, 1, 1], [476, 422, 1, 1], [476, 425, 1, 1], [477, 166, 1, 2], [477, 171, 1, 1], [477, 180, 1, 1], [477, 183, 1, 1], [477, 227, 1, 1], [477, 277, 1, 1], [477, 282, 1, 1], [477, 318, 1, 1], [477, 323, 1, 1], [477, 373, 1, 1], [477, 417, 1, 1], [477, 420, 1, 1], [477, 429, 1, 1], [477, 433, 1, 2], [478, 196, 1, 1], [478, 274, 1, 2], [478, 325, 1, 2], [478, 404, 1, 1], [479, 183, 1, 1], [479, 185, 1, 1], [479, 239, 1, 3], [479, 274, 1, 1], [479, 280, 1, 1], [479, 320, 1, 1], [479, 326, 1, 1], [479, 359, 1, 3], [479, 415, 1, 1], [479, 417, 1, 1], [480, 181, 1, 1], [480, 185, 1, 1], [480, 244, 1, 1], [480, 263, 1, 1], [480, 266, 1, 1], [480, 334, 1, 1], [480, 337, 1, 1], [480, 356, 1, 1], [480, 415, 1, 1], [480, 419, 1, 1], [481, 180, 1, 1], [481, 250, 1, 1], [481, 252, 1, 1], [481, 261, 1, 1], [481, 268, 1, 1], [481, 274, 1, 1], [481, 280, 1, 1], [481, 320, 1, 1], [481, 326, 1, 1], [481, 332, 1, 1], [481, 339, 1, 1], [481, 348, 1, 1], [481, 350, 1, 1], [481, 420, 1, 1], [482, 179, 1, 2], [482, 187, 1, 1], [482, 225, 1, 1], [482, 248, 1, 1], [482, 261, 1, 1], [482, 339, 1, 1], [482, 352, 1, 1], [482, 375, 1, 1], [482, 413, 1, 1], [482, 420, 1, 2], [483, 246, 1, 1], [483, 271, 1, 1], [483, 329, 1, 1], [483, 354, 1, 1], [484, 179, 1, 1], [484, 187, 1, 1], [484, 227, 1, 1], [484, 239, 1, 1], [484, 271, 1, 1], [484, 274, 1, 1], [484, 326, 1, 1], [484, 329, 1, 1], [484, 361, 1, 1], [484, 373, 1, 1], [484, 413, 1, 1], [484, 421, 1, 1], [485, 229, 1, 1], [485, 260, 1, 1], [485, 270, 1, 1], [485, 330, 1, 1], [485, 340, 1, 1], [485, 371, 1, 1], [486, 178, 1, 1], [486, 228, 1, 1], [486, 235, 1, 1], [486, 239, 1, 1], [486, 253, 1, 1], [486, 255, 1, 1], [486, 270, 1, 1], [486, 330, 1, 1], [486, 345, 1, 1], [486, 347, 1, 1], [486, 361, 1, 1], [486, 365, 1, 1], [486, 372, 1, 1], [486, 422, 1, 1], [487, 256, 1, 1], [487, 259, 1, 3], [487, 339, 1, 3], [487, 344, 1, 1], [488, 230, 1, 1], [488, 233, 1, 1], [488, 238, 1, 1], [488, 257, 1, 1], [488, 343, 1, 1], [488, 362, 1, 1], [488, 367, 1, 1], [488, 370, 1, 1], [489, 233, 1, 1], [489, 367, 1, 1], [490, 230, 1, 2], [490, 233, 1, 1], [490, 259, 1, 1], [490, 341, 1, 1], [490, 367, 1, 1], [490, 369, 1, 2], [491, 254, 1, 1], [491, 346, 1, 1], [492, 227, 1, 2], [492, 250, 1, 1], [492, 253, 1, 1], [492, 258, 1, 1], [492, 342, 1, 1], [492, 347, 1, 1], [492, 350, 1, 1], [492, 372, 1, 2], [493, 225, 1, 1], [493, 253, 1, 1], [493, 347, 1, 1], [493, 375, 1, 1], [494, 221, 1, 1], [494, 379, 1, 1]], [[91, 299, 1, 1], [91, 301, 1, 1], [119, 299, 1, 1], [119, 301, 1, 1], [120, 299, 1, 1], [120, 301, 1, 1], [133, 299, 1, 1], [133, 301, 1, 1], [134, 298, 1, 1], [134, 302, 1, 1], [135, 298, 1, 1], [135, 302, 1, 1], [136, 279, 1, 1], [136, 294, 1, 2], [136, 305, 1, 2], [136, 321, 1, 1], [137, 296, 1, 1], [137, 304, 1, 1], [138, 295, 1, 1], [138, 305, 1, 1], [139, 281, 1, 1], [139, 295, 1, 1], [139, 305, 1, 1], [139, 319, 1, 1], [140, 283, 1, 1], [140, 292, 1, 1], [140, 295, 1, 1], [140, 305, 1, 1], [140, 308, 1, 1], [140, 317, 1, 1], [141, 282, 1, 1], [141, 284, 1, 1], [141, 286, 1, 1], [141, 293, 1, 2], [141, 306, 1, 2], [141, 314, 1, 1], [141, 316, 1, 1], [141, 318, 1, 1], [142, 280, 1, 1], [142, 320, 1, 1], [143, 287, 1, 1], [143, 290, 1, 2], [143, 309, 1, 2], [143, 313, 1, 1], [145, 285, 1, 1], [145, 315, 1, 1], [148, 287, 1, 1], [148, 313, 1, 1], [149, 286, 1, 1], [149, 314, 1, 1], [150, 278, 1, 2], [150, 283, 1, 1], [150, 317, 1, 1], [150, 321, 1, 2], [151, 282, 1, 1], [151, 284, 1, 1], [151, 316, 1, 1], [151, 318, 1, 1], [152, 282, 1, 1], [152, 284, 1, 1], [152, 316, 1, 1], [152, 318, 1, 1], [154, 286, 1, 1], [154, 314, 1, 1], [160, 288, 1, 1], [160, 312, 1, 1], [161, 229, 1, 1], [161, 264, 1, 1], [161, 288, 1, 2], [161, 311, 1, 2], [161, 336, 1, 1], [161, 371, 1, 1], [162, 289, 1, 1], [162, 311, 1, 1], [163, 288, 1, 3], [163, 310, 1, 3], [164, 231, 1, 1], [164, 276, 1, 2], [164, 283, 1, 1], [164, 285, 1, 1], [164, 287, 1, 1], [164, 313, 1, 1], [164, 315, 1, 1], [164, 317, 1, 1], [164, 323, 1, 2], [164, 369, 1, 1], [165, 234, 1, 1], [165, 366, 1, 1], [166, 279, 1, 2], [166, 320, 1, 2], [167, 269, 1, 1], [167, 331, 1, 1], [168, 269, 1, 1], [168, 271, 1, 1], [168, 329, 1, 1], [168, 331, 1, 1], [169, 237, 1, 1], [169, 363, 1, 1], [170, 264, 1, 1], [170, 336, 1, 1], [171, 253, 1, 1], [171, 265, 1, 1], [171, 335, 1, 1], [171, 347, 1, 1], [172, 251, 1, 1], [172, 349, 1, 1], [173, 237, 1, 1], [173, 363, 1, 1], [174, 266, 1, 1], [174, 334, 1, 1], [175, 238, 1, 2], [175, 242, 1, 1], [175, 252, 1, 1], [175, 264, 1, 2], [175, 335, 1, 2], [175, 348, 1, 1], [175, 358, 1, 1], [175, 361, 1, 2], [176, 240, 1, 2], [176, 251, 1, 1], [176, 349, 1, 1], [176, 359, 1, 2], [177, 238, 1, 1], [177, 250, 1, 1], [177, 252, 1, 1], [177, 348, 1, 1], [177, 350, 1, 1], [177, 362, 1, 1], [178, 252, 1, 1], [178, 261, 1, 1], [178, 339, 1, 1], [178, 348, 1, 1], [179, 240, 1, 1], [179, 242, 1, 1], [179, 249, 1, 1], [179, 253, 1, 1], [179, 256, 1, 1], [179, 260, 1, 2], [179, 339, 1, 2], [179, 344, 1, 1], [179, 347, 1, 1], [179, 351, 1, 1], [179, 358, 1, 1], [179, 360, 1, 1], [180, 242, 1, 1], [180, 245, 1, 1], [180, 247, 1, 2], [180, 256, 1, 1], [180, 260, 1, 1], [180, 340, 1, 1], [180, 344, 1, 1], [180, 352, 1, 2], [180, 355, 1, 1], [180, 358, 1, 1], [181, 241, 1, 4], [181, 258, 1, 2], [181, 341, 1, 2], [181, 356, 1, 4], [182, 259, 1, 1], [182, 341, 1, 1], [183, 238, 1, 1], [183, 240, 1, 1], [183, 242, 1, 1], [183, 358, 1, 1], [183, 360, 1, 1], [183, 362, 1, 1], [184, 236, 1, 1], [184, 238, 1, 2], [184, 243, 1, 1], [184, 357, 1, 1], [184, 361, 1, 2], [184, 364, 1, 1], [185, 237, 1, 1], [185, 242, 1, 1], [185, 358, 1, 1], [185, 363, 1, 1], [186, 244, 1, 1], [186, 356, 1, 1], [188, 243, 1, 1], [188, 245, 1, 1], [188, 355, 1, 1], [188, 357, 1, 1], [191, 239, 1, 1], [191, 245, 1, 3], [191, 353, 1, 3], [191, 361, 1, 1], [193, 248, 1, 1], [193, 250, 1, 2], [193, 349, 1, 2], [193, 352, 1, 1], [194, 251, 1, 1], [194, 349, 1, 1], [195, 251, 1, 1], [195, 349, 1, 1], [196, 249, 1, 2], [196, 350, 1, 2], [199, 243, 1, 1], [199, 248, 1, 3], [199, 350, 1, 3], [199, 357, 1, 1], [204, 248, 1, 1], [204, 352, 1, 1], [205, 230, 1, 2], [205, 369, 1, 2], [207, 244, 1, 1], [207, 248, 1, 1], [207, 352, 1, 1], [207, 356, 1, 1], [208, 234, 1, 1], [208, 245, 1, 2], [208, 248, 1, 1], [208, 352, 1, 1], [208, 354, 1, 2], [208, 366, 1, 1], [209, 235, 1, 1], [209, 239, 1, 1], [209, 361, 1, 1], [209, 365, 1, 1], [210, 239, 1, 1], [210, 361, 1, 1], [211, 239, 1, 1], [211, 361, 1, 1], [212, 241, 1, 1], [212, 359, 1, 1], [215, 241, 1, 1], [215, 359, 1, 1], [216, 243, 1, 1], [216, 357, 1, 1], [217, 243, 1, 1], [217, 357, 1, 1], [218, 242, 1, 1], [218, 245, 1, 1], [218, 355, 1, 1], [218, 358, 1, 1], [219, 248, 1, 1], [219, 352, 1, 1], [220, 247, 1, 1], [220, 353, 1, 1], [221, 245, 1, 1], [221, 355, 1, 1], [224, 249, 1, 1], [224, 351, 1, 1], [225, 240, 1, 2], [225, 247, 1, 2], [225, 352, 1, 2], [225, 359, 1, 2], [226, 239, 1, 1], [226, 247, 1, 1], [226, 353, 1, 1], [226, 361, 1, 1], [227, 237, 1, 1], [227, 363, 1, 1], [228, 246, 1, 1], [228, 354, 1, 1], [232, 243, 1, 1], [232, 247, 1, 1], [232, 251, 1, 1], [232, 349, 1, 1], [232, 353, 1, 1], [232, 357, 1, 1], [234, 252, 1, 1], [234, 348, 1, 1], [235, 253, 1, 1], [235, 347, 1, 1], [236, 252, 1, 1], [236, 348, 1, 1], [237, 248, 1, 1], [237, 352, 1, 1], [238, 246, 1, 1], [238, 250, 1, 2], [238, 349, 1, 2], [238, 354, 1, 1], [239, 245, 1, 1], [239, 355, 1, 1], [241, 253, 1, 2], [241, 256, 1, 1], [241, 344, 1, 1], [241, 346, 1, 2], [242, 257, 1, 1], [242, 343, 1, 1], [243, 256, 1, 2], [243, 343, 1, 2], [244, 254, 1, 1], [244, 256, 1, 2], [244, 343, 1, 2], [244, 346, 1, 1], [245, 254, 1, 1], [245, 346, 1, 1], [246, 254, 1, 1], [246, 346, 1, 1], [247, 261, 1, 1], [247, 339, 1, 1], [250, 264, 1, 1], [250, 336, 1, 1], [253, 267, 1, 1], [253, 333, 1, 1], [255, 271, 1, 1], [255, 329, 1, 1], [258, 277, 1, 1], [258, 323, 1, 1], [259, 277, 1, 3], [259, 321, 1, 3], [260, 277, 1, 4], [260, 320, 1, 4], [261, 276, 1, 4], [261, 321, 1, 4], [262, 271, 1, 2], [262, 274, 1, 1], [262, 326, 1, 1], [262, 328, 1, 2], [263, 251, 1, 1], [263, 258, 1, 1], [263, 342, 1, 1], [263, 349, 1, 1], [265, 244, 1, 1], [265, 250, 1, 1], [265, 260, 1, 1], [265, 340, 1, 1], [265, 350, 1, 1], [265, 356, 1, 1], [266, 228, 1, 1], [266, 231, 1, 1], [266, 241, 1, 1], [266, 254, 1, 3], [266, 344, 1, 3], [266, 359, 1, 1], [266, 369, 1, 1], [266, 372, 1, 1], [267, 249, 1, 1], [267, 255, 1, 1], [267, 345, 1, 1], [267, 351, 1, 1], [268, 232, 1, 1], [268, 238, 1, 1], [268, 362, 1, 1], [268, 368, 1, 1], [269, 232, 1, 1], [269, 240, 1, 1], [269, 247, 1, 2], [269, 352, 1, 2], [269, 360, 1, 1], [269, 368, 1, 1], [270, 227, 1, 1], [270, 234, 1, 1], [270, 366, 1, 1], [270, 373, 1, 1], [271, 225, 1, 1], [271, 232, 1, 1], [271, 368, 1, 1], [271, 375, 1, 1], [272, 211, 1, 1], [272, 233, 1, 1], [272, 367, 1, 1], [272, 389, 1, 1], [273, 223, 1, 1], [273, 228, 1, 1], [273, 372, 1, 1], [273, 377, 1, 1], [274, 207, 1, 1], [274, 228, 1, 1], [274, 236, 1, 2], [274, 363, 1, 2], [274, 372, 1, 1], [274, 393, 1, 1], [275, 210, 1, 2], [275, 389, 1, 2], [277, 211, 1, 1], [277, 389, 1, 1], [278, 211, 1, 2], [278, 218, 1, 1], [278, 228, 1, 1], [278, 372, 1, 1], [278, 382, 1, 1], [278, 388, 1, 2], [279, 208, 1, 1], [279, 214, 1, 1], [279, 228, 1, 1], [279, 372, 1, 1], [279, 386, 1, 1], [279, 392, 1, 1], [280, 201, 1, 2], [280, 204, 1, 1], [280, 207, 1, 3], [280, 215, 1, 1], [280, 223, 1, 1], [280, 227, 1, 1], [280, 373, 1, 1], [280, 377, 1, 1], [280, 385, 1, 1], [280, 391, 1, 3], [280, 396, 1, 1], [280, 398, 1, 2], [281, 223, 1, 1], [281, 377, 1, 1], [282, 205, 1, 1], [282, 208, 1, 1], [282, 223, 1, 1], [282, 377, 1, 1], [282, 392, 1, 1], [282, 395, 1, 1], [283, 201, 1, 1], [283, 399, 1, 1], [284, 207, 1, 1], [284, 209, 1, 1], [284, 221, 1, 1], [284, 379, 1, 1], [284, 391, 1, 1], [284, 393, 1, 1], [286, 206, 1, 1], [286, 394, 1, 1], [288, 209, 1, 1], [288, 391, 1, 1], [289, 177, 1, 1], [289, 423, 1, 1], [290, 167, 1, 1], [290, 210, 1, 1], [290, 390, 1, 1], [290, 433, 1, 1], [291, 168, 1, 1], [291, 176, 1, 1], [291, 211, 1, 2], [291, 388, 1, 2], [291, 424, 1, 1], [291, 432, 1, 1], [292, 211, 1, 1], [292, 389, 1, 1], [293, 168, 1, 1], [293, 204, 1, 1], [293, 208, 1, 1], [293, 392, 1, 1], [293, 396, 1, 1], [293, 432, 1, 1], [294, 170, 1, 1], [294, 174, 1, 1], [294, 201, 1, 1], [294, 399, 1, 1], [294, 426, 1, 1], [294, 430, 1, 1], [295, 187, 1, 2], [295, 191, 1, 1], [295, 409, 1, 1], [295, 412, 1, 2], [296, 171, 1, 1], [296, 191, 1, 1], [296, 201, 1, 1], [296, 399, 1, 1], [296, 409, 1, 1], [296, 429, 1, 1], [297, 166, 1, 2], [297, 169, 1, 1], [297, 173, 1, 1], [297, 427, 1, 1], [297, 431, 1, 1], [297, 433, 1, 2], [298, 170, 1, 1], [298, 179, 1, 1], [298, 187, 1, 1], [298, 413, 1, 1], [298, 421, 1, 1], [298, 430, 1, 1], [299, 170, 1, 1], [299, 172, 1, 1], [299, 178, 1, 1], [299, 181, 1, 1], [299, 186, 1, 1], [299, 414, 1, 1], [299, 419, 1, 1], [299, 422, 1, 1], [299, 428, 1, 1], [299, 430, 1, 1], [300, 169, 1, 1], [300, 173, 1, 1], [300, 182, 1, 1], [300, 191, 1, 1], [300, 409, 1, 1], [300, 418, 1, 1], [300, 427, 1, 1], [300, 431, 1, 1], [301, 168, 1, 1], [301, 170, 1, 1], [301, 194, 1, 1], [301, 406, 1, 1], [301, 430, 1, 1], [301, 432, 1, 1], [302, 175, 1, 1], [302, 194, 1, 1], [302, 199, 1, 1], [302, 401, 1, 1], [302, 406, 1, 1], [302, 425, 1, 1], [303, 162, 1, 1], [303, 175, 1, 1], [303, 199, 1, 1], [303, 401, 1, 1], [303, 425, 1, 1], [303, 438, 1, 1], [305, 164, 1, 1], [305, 197, 1, 2], [305, 402, 1, 2], [305, 436, 1, 1], [306, 176, 1, 1], [306, 197, 1, 1], [306, 403, 1, 1], [306, 424, 1, 1], [307, 175, 1, 1], [307, 178, 1, 1], [307, 422, 1, 1], [307, 425, 1, 1], [308, 177, 1, 1], [308, 423, 1, 1], [311, 176, 1, 2], [311, 423, 1, 2], [314, 177, 1, 1], [314, 423, 1, 1], [315, 180, 1, 1], [315, 420, 1, 1], [316, 179, 1, 1], [316, 421, 1, 1], [317, 174, 1, 1], [317, 426, 1, 1], [318, 184, 1, 4], [318, 413, 1, 4], [319, 187, 1, 1], [319, 413, 1, 1], [324, 178, 1, 1], [324, 422, 1, 1], [329, 179, 1, 2], [329, 420, 1, 2], [331, 164, 1, 1], [331, 436, 1, 1], [332, 169, 1, 1], [332, 171, 1, 1], [332, 429, 1, 1], [332, 431, 1, 1], [333, 171, 1, 3], [333, 179, 1, 1], [333, 421, 1, 1], [333, 427, 1, 3], [336, 167, 1, 1], [336, 433, 1, 1], [337, 169, 1, 2], [337, 430, 1, 2], [338, 164, 1, 2], [338, 168, 1, 1], [338, 432, 1, 1], [338, 435, 1, 2], [340, 168, 1, 1], [340, 432, 1, 1], [341, 174, 1, 1], [341, 426, 1, 1], [345, 170, 1, 1], [345, 430, 1, 1], [346, 174, 1, 1], [346, 426, 1, 1], [347, 171, 1, 1], [347, 429, 1, 1], [348, 167, 1, 1], [348, 433, 1, 1], [351, 130, 1, 1], [351, 170, 1, 1], [351, 430, 1, 1], [351, 470, 1, 1], [352, 132, 1, 2], [352, 467, 1, 2], [353, 172, 1, 1], [353, 428, 1, 1], [354, 131, 1, 2], [354, 149, 1, 1], [354, 171, 1, 1], [354, 429, 1, 1], [354, 451, 1, 1], [354, 468, 1, 2], [355, 131, 1, 1], [355, 147, 1, 1], [355, 149, 1, 1], [355, 451, 1, 1], [355, 453, 1, 1], [355, 469, 1, 1], [357, 131, 1, 1], [357, 147, 1, 1], [357, 168, 1, 1], [357, 432, 1, 1], [357, 453, 1, 1], [357, 469, 1, 1], [358, 146, 1, 1], [358, 157, 1, 1], [358, 443, 1, 1], [358, 454, 1, 1], [359, 134, 1, 1], [359, 148, 1, 1], [359, 150, 1, 1], [359, 450, 1, 1], [359, 452, 1, 1], [359, 466, 1, 1], [360, 134, 1, 1], [360, 466, 1, 1], [361, 130, 1, 2], [361, 136, 1, 1], [361, 138, 1, 1], [361, 141, 1, 1], [361, 155, 1, 1], [361, 157, 1, 1], [361, 443, 1, 1], [361, 445, 1, 1], [361, 459, 1, 1], [361, 462, 1, 1], [361, 464, 1, 1], [361, 469, 1, 2], [362, 125, 1, 1], [362, 135, 1, 1], [362, 139, 1, 1], [362, 141, 1, 1], [362, 143, 1, 1], [362, 152, 1, 1], [362, 154, 1, 1], [362, 158, 1, 2], [362, 161, 1, 1], [362, 439, 1, 1], [362, 441, 1, 2], [362, 446, 1, 1], [362, 448, 1, 1], [362, 457, 1, 1], [362, 459, 1, 1], [362, 461, 1, 1], [362, 465, 1, 1], [362, 475, 1, 1], [363, 136, 1, 1], [363, 143, 1, 1], [363, 457, 1, 1], [363, 464, 1, 1], [366, 134, 1, 1], [366, 466, 1, 1], [367, 135, 1, 1], [367, 169, 1, 1], [367, 431, 1, 1], [367, 465, 1, 1], [368, 169, 1, 1], [368, 431, 1, 1], [369, 135, 1, 1], [369, 167, 1, 3], [369, 431, 1, 3], [369, 465, 1, 1], [370, 130, 1, 1], [370, 168, 1, 2], [370, 431, 1, 2], [370, 470, 1, 1], [371, 131, 1, 1], [371, 469, 1, 1], [372, 130, 1, 1], [372, 470, 1, 1], [373, 90, 1, 2], [373, 95, 1, 1], [373, 505, 1, 1], [373, 509, 1, 2], [374, 92, 1, 1], [374, 132, 1, 1], [374, 468, 1, 1], [374, 508, 1, 1], [375, 95, 1, 1], [375, 131, 1, 1], [375, 469, 1, 1], [375, 505, 1, 1], [376, 95, 1, 1], [376, 130, 1, 2], [376, 469, 1, 2], [376, 505, 1, 1], [377, 92, 1, 1], [377, 119, 1, 1], [377, 121, 1, 1], [377, 126, 1, 1], [377, 131, 1, 1], [377, 469, 1, 1], [377, 474, 1, 1], [377, 479, 1, 1], [377, 481, 1, 1], [377, 508, 1, 1], [378, 123, 1, 1], [378, 126, 1, 1], [378, 128, 1, 1], [378, 472, 1, 1], [378, 474, 1, 1], [378, 477, 1, 1], [379, 122, 1, 1], [379, 124, 1, 1], [379, 476, 1, 1], [379, 478, 1, 1], [380, 98, 1, 1], [380, 502, 1, 1], [381, 102, 1, 1], [381, 498, 1, 1], [382, 102, 1, 2], [382, 120, 1, 1], [382, 122, 1, 1], [382, 478, 1, 1], [382, 480, 1, 1], [382, 497, 1, 2], [383, 104, 1, 2], [383, 115, 1, 1], [383, 120, 1, 1], [383, 480, 1, 1], [383, 485, 1, 1], [383, 495, 1, 2], [384, 120, 1, 1], [384, 480, 1, 1], [385, 107, 1, 1], [385, 115, 1, 5], [385, 481, 1, 5], [385, 493, 1, 1], [386, 113, 1, 1], [386, 118, 1, 2], [386, 481, 1, 2], [386, 487, 1, 1], [387, 111, 1, 1], [387, 489, 1, 1], [388, 108, 1, 1], [388, 115, 1, 1], [388, 122, 1, 1], [388, 478, 1, 1], [388, 485, 1, 1], [388, 492, 1, 1], [389, 119, 1, 1], [389, 481, 1, 1], [390, 107, 1, 1], [390, 131, 1, 2], [390, 468, 1, 2], [390, 493, 1, 1], [391, 106, 1, 1], [391, 123, 1, 1], [391, 125, 1, 1], [391, 127, 1, 1], [391, 473, 1, 1], [391, 475, 1, 1], [391, 477, 1, 1], [391, 494, 1, 1], [392, 105, 1, 1], [392, 132, 1, 1], [392, 468, 1, 1], [392, 495, 1, 1], [393, 133, 1, 1], [393, 467, 1, 1], [394, 134, 1, 1], [394, 168, 1, 2], [394, 431, 1, 2], [394, 466, 1, 1], [395, 167, 1, 3], [395, 431, 1, 3], [396, 103, 1, 1], [396, 132, 1, 2], [396, 166, 1, 1], [396, 169, 1, 1], [396, 431, 1, 1], [396, 434, 1, 1], [396, 467, 1, 2], [396, 497, 1, 1], [397, 135, 1, 3], [397, 463, 1, 3], [398, 101, 1, 2], [398, 138, 1, 1], [398, 169, 1, 1], [398, 431, 1, 1], [398, 462, 1, 1], [398, 498, 1, 2], [399, 138, 1, 1], [399, 462, 1, 1], [400, 138, 1, 1], [400, 462, 1, 1], [401, 137, 1, 1], [401, 160, 1, 1], [401, 169, 1, 1], [401, 431, 1, 1], [401, 440, 1, 1], [401, 463, 1, 1], [402, 138, 1, 1], [402, 145, 1, 2], [402, 156, 1, 1], [402, 444, 1, 1], [402, 454, 1, 2], [402, 462, 1, 1], [403, 139, 1, 1], [403, 156, 1, 1], [403, 444, 1, 1], [403, 461, 1, 1], [404, 139, 1, 1], [404, 143, 1, 1], [404, 158, 1, 1], [404, 442, 1, 1], [404, 457, 1, 1], [404, 461, 1, 1], [405, 138, 1, 1], [405, 140, 1, 1], [405, 152, 1, 1], [405, 448, 1, 1], [405, 460, 1, 1], [405, 462, 1, 1], [406, 148, 1, 1], [406, 150, 1, 1], [406, 153, 1, 1], [406, 171, 1, 1], [406, 429, 1, 1], [406, 447, 1, 1], [406, 450, 1, 1], [406, 452, 1, 1], [407, 131, 1, 1], [407, 150, 1, 1], [407, 170, 1, 1], [407, 430, 1, 1], [407, 450, 1, 1], [407, 469, 1, 1], [408, 148, 1, 1], [408, 168, 1, 1], [408, 432, 1, 1], [408, 452, 1, 1], [410, 148, 1, 1], [410, 452, 1, 1], [411, 128, 1, 1], [411, 137, 1, 2], [411, 171, 1, 2], [411, 428, 1, 2], [411, 462, 1, 2], [411, 472, 1, 1], [412, 172, 1, 1], [412, 428, 1, 1], [415, 170, 1, 1], [415, 430, 1, 1], [418, 167, 1, 1], [418, 433, 1, 1], [420, 170, 1, 1], [420, 175, 1, 1], [420, 425, 1, 1], [420, 430, 1, 1], [425, 177, 1, 1], [425, 423, 1, 1], [428, 167, 1, 1], [428, 433, 1, 1], [430, 168, 1, 1], [430, 432, 1, 1], [431, 164, 1, 1], [431, 169, 1, 1], [431, 171, 1, 1], [431, 429, 1, 1], [431, 431, 1, 1], [431, 436, 1, 1], [432, 162, 1, 1], [432, 166, 1, 1], [432, 170, 1, 2], [432, 429, 1, 2], [432, 434, 1, 1], [432, 438, 1, 1], [433, 166, 1, 1], [433, 434, 1, 1], [434, 168, 1, 1], [434, 175, 1, 1], [434, 425, 1, 1], [434, 432, 1, 1], [435, 168, 1, 1], [435, 172, 1, 1], [435, 428, 1, 1], [435, 432, 1, 1], [436, 170, 1, 2], [436, 178, 1, 1], [436, 422, 1, 1], [436, 429, 1, 2], [437, 168, 1, 1], [437, 170, 1, 1], [437, 172, 1, 2], [437, 183, 1, 1], [437, 417, 1, 1], [437, 427, 1, 2], [437, 430, 1, 1], [437, 432, 1, 1], [438, 173, 1, 1], [438, 427, 1, 1], [439, 183, 1, 1], [439, 417, 1, 1], [442, 187, 1, 1], [442, 413, 1, 1], [446, 190, 1, 1], [446, 410, 1, 1], [449, 192, 1, 1], [449, 408, 1, 1], [450, 193, 1, 1], [450, 407, 1, 1], [451, 190, 1, 1], [451, 193, 1, 1], [451, 407, 1, 1], [451, 410, 1, 1], [453, 184, 1, 1], [453, 416, 1, 1], [457, 184, 1, 1], [457, 300, 1, 1], [457, 416, 1, 1], [461, 179, 1, 1], [461, 182, 1, 1], [461, 204, 1, 2], [461, 395, 1, 2], [461, 418, 1, 1], [461, 421, 1, 1], [462, 204, 1, 1], [462, 206, 1, 1], [462, 394, 1, 1], [462, 396, 1, 1], [463, 207, 1, 1], [463, 393, 1, 1], [464, 182, 1, 1], [464, 418, 1, 1], [465, 183, 1, 2], [465, 210, 1, 1], [465, 390, 1, 1], [465, 416, 1, 2], [466, 204, 1, 1], [466, 210, 1, 1], [466, 390, 1, 1], [466, 396, 1, 1], [469, 200, 1, 1], [469, 203, 1, 1], [469, 215, 1, 1], [469, 291, 1, 1], [469, 309, 1, 1], [469, 385, 1, 1], [469, 397, 1, 1], [469, 400, 1, 1], [471, 192, 1, 1], [471, 195, 1, 1], [471, 199, 1, 1], [471, 288, 1, 1], [471, 291, 1, 1], [471, 309, 1, 1], [471, 312, 1, 1], [471, 401, 1, 1], [471, 405, 1, 1], [471, 408, 1, 1], [472, 184, 1, 1], [472, 213, 1, 1], [472, 215, 1, 1], [472, 222, 1, 1], [472, 287, 1, 1], [472, 313, 1, 1], [472, 378, 1, 1], [472, 385, 1, 1], [472, 387, 1, 1], [472, 416, 1, 1], [473, 187, 1, 1], [473, 218, 1, 1], [473, 382, 1, 1], [473, 413, 1, 1], [474, 185, 1, 1], [474, 195, 1, 2], [474, 214, 1, 1], [474, 218, 1, 1], [474, 284, 1, 1], [474, 316, 1, 1], [474, 382, 1, 1], [474, 386, 1, 1], [474, 404, 1, 2], [474, 415, 1, 1], [475, 171, 1, 1], [475, 185, 1, 1], [475, 188, 1, 1], [475, 212, 1, 1], [475, 217, 1, 1], [475, 229, 1, 1], [475, 286, 1, 1], [475, 314, 1, 1], [475, 371, 1, 1], [475, 383, 1, 1], [475, 388, 1, 1], [475, 412, 1, 1], [475, 415, 1, 1], [475, 429, 1, 1], [476, 161, 1, 1], [476, 168, 1, 1], [476, 170, 1, 1], [476, 176, 1, 1], [476, 183, 1, 1], [476, 417, 1, 1], [476, 424, 1, 1], [476, 430, 1, 1], [476, 432, 1, 1], [476, 439, 1, 1], [477, 179, 1, 1], [477, 196, 1, 1], [477, 199, 1, 1], [477, 401, 1, 1], [477, 404, 1, 1], [477, 421, 1, 1], [479, 165, 1, 1], [479, 181, 1, 1], [479, 184, 1, 1], [479, 244, 1, 1], [479, 268, 1, 1], [479, 332, 1, 1], [479, 356, 1, 1], [479, 416, 1, 1], [479, 419, 1, 1], [479, 435, 1, 1], [480, 180, 1, 1], [480, 184, 1, 1], [480, 226, 1, 1], [480, 249, 1, 1], [480, 253, 1, 1], [480, 260, 1, 2], [480, 282, 1, 1], [480, 318, 1, 1], [480, 339, 1, 2], [480, 347, 1, 1], [480, 351, 1, 1], [480, 374, 1, 1], [480, 416, 1, 1], [480, 420, 1, 1], [481, 224, 1, 1], [481, 239, 1, 1], [481, 245, 1, 1], [481, 248, 1, 1], [481, 352, 1, 1], [481, 355, 1, 1], [481, 361, 1, 1], [481, 376, 1, 1], [482, 185, 1, 2], [482, 245, 1, 1], [482, 355, 1, 1], [482, 414, 1, 2], [483, 244, 1, 1], [483, 272, 1, 1], [483, 274, 1, 1], [483, 326, 1, 1], [483, 328, 1, 1], [483, 356, 1, 1], [484, 225, 1, 1], [484, 252, 1, 1], [484, 260, 1, 1], [484, 340, 1, 1], [484, 348, 1, 1], [484, 375, 1, 1], [485, 236, 1, 2], [485, 259, 1, 1], [485, 261, 1, 1], [485, 339, 1, 1], [485, 341, 1, 1], [485, 363, 1, 2], [486, 229, 1, 1], [486, 238, 1, 1], [486, 273, 1, 1], [486, 327, 1, 1], [486, 362, 1, 1], [486, 371, 1, 1], [487, 237, 1, 1], [487, 257, 1, 1], [487, 268, 1, 1], [487, 332, 1, 1], [487, 343, 1, 1], [487, 363, 1, 1], [488, 231, 1, 1], [488, 369, 1, 1], [491, 228, 1, 2], [491, 258, 1, 1], [491, 342, 1, 1], [491, 371, 1, 2], [493, 233, 1, 1], [493, 367, 1, 1], [494, 231, 1, 1], [494, 234, 1, 1], [494, 366, 1, 1], [494, 369, 1, 1], [496, 222, 1, 1], [496, 378, 1, 1]], [[64, 299, 1, 1], [64, 301, 1, 1], [66, 296, 1, 1], [66, 304, 1, 1], [120, 297, 1, 1], [120, 303, 1, 1], [121, 299, 1, 1], [121, 301, 1, 1], [126, 299, 1, 1], [126, 301, 1, 1], [132, 291, 1, 1], [132, 309, 1, 1], [134, 275, 1, 1], [134, 299, 1, 1], [134, 301, 1, 1], [134, 325, 1, 1], [135, 294, 1, 2], [135, 305, 1, 2], [136, 297, 1, 1], [136, 303, 1, 1], [137, 278, 1, 1], [137, 322, 1, 1], [138, 296, 1, 1], [138, 304, 1, 1], [141, 281, 1, 1], [141, 295, 1, 1], [141, 305, 1, 1], [141, 319, 1, 1], [142, 289, 1, 1], [142, 291, 1, 1], [142, 309, 1, 1], [142, 311, 1, 1], [144, 288, 1, 1], [144, 312, 1, 1], [146, 286, 1, 1], [146, 314, 1, 1], [150, 285, 1, 3], [150, 313, 1, 3], [151, 286, 1, 1], [151, 314, 1, 1], [153, 285, 1, 1], [153, 315, 1, 1], [155, 285, 1, 1], [155, 315, 1, 1], [156, 283, 1, 1], [156, 317, 1, 1], [157, 286, 1, 1], [157, 314, 1, 1], [162, 265, 1, 1], [162, 290, 1, 1], [162, 310, 1, 1], [162, 335, 1, 1], [163, 285, 1, 1], [163, 291, 1, 1], [163, 309, 1, 1], [163, 315, 1, 1], [164, 265, 1, 1], [164, 286, 1, 1], [164, 289, 1, 2], [164, 310, 1, 2], [164, 314, 1, 1], [164, 335, 1, 1], [165, 218, 1, 1], [165, 266, 1, 1], [165, 276, 1, 1], [165, 278, 1, 1], [165, 284, 1, 1], [165, 316, 1, 1], [165, 322, 1, 1], [165, 324, 1, 1], [165, 334, 1, 1], [165, 382, 1, 1], [166, 235, 1, 1], [166, 365, 1, 1], [167, 267, 1, 1], [167, 275, 1, 1], [167, 280, 1, 1], [167, 320, 1, 1], [167, 325, 1, 1], [167, 333, 1, 1], [168, 265, 1, 1], [168, 268, 1, 1], [168, 270, 1, 1], [168, 275, 1, 1], [168, 325, 1, 1], [168, 330, 1, 1], [168, 332, 1, 1], [168, 335, 1, 1], [169, 263, 1, 1], [169, 275, 1, 1], [169, 325, 1, 1], [169, 337, 1, 1], [170, 265, 1, 2], [170, 272, 1, 2], [170, 327, 1, 2], [170, 334, 1, 2], [171, 266, 1, 1], [171, 334, 1, 1], [174, 237, 1, 1], [174, 363, 1, 1], [175, 266, 1, 1], [175, 334, 1, 1], [176, 252, 1, 1], [176, 264, 1, 2], [176, 335, 1, 2], [176, 348, 1, 1], [178, 246, 1, 1], [178, 251, 1, 1], [178, 349, 1, 1], [178, 354, 1, 1], [179, 241, 1, 1], [179, 250, 1, 1], [179, 262, 1, 1], [179, 338, 1, 1], [179, 350, 1, 1], [179, 359, 1, 1], [180, 249, 1, 1], [180, 351, 1, 1], [181, 245, 1, 1], [181, 247, 1, 1], [181, 260, 1, 1], [181, 340, 1, 1], [181, 353, 1, 1], [181, 355, 1, 1], [182, 239, 1, 1], [182, 361, 1, 1], [183, 239, 1, 1], [183, 243, 1, 1], [183, 357, 1, 1], [183, 361, 1, 1], [184, 237, 1, 1], [184, 363, 1, 1], [186, 243, 1, 1], [186, 245, 1, 1], [186, 355, 1, 1], [186, 357, 1, 1], [187, 245, 1, 1], [187, 355, 1, 1], [189, 245, 1, 1], [189, 355, 1, 1], [190, 239, 1, 1], [190, 242, 1, 3], [190, 356, 1, 3], [190, 361, 1, 1], [192, 247, 1, 1], [192, 353, 1, 1], [193, 252, 1, 1], [193, 348, 1, 1], [194, 252, 1, 1], [194, 348, 1, 1], [196, 251, 1, 1], [196, 349, 1, 1], [198, 244, 1, 1], [198, 356, 1, 1], [200, 249, 1, 1], [200, 351, 1, 1], [203, 248, 1, 1], [203, 352, 1, 1], [204, 231, 1, 1], [204, 249, 1, 1], [204, 351, 1, 1], [204, 369, 1, 1], [205, 234, 1, 1], [205, 248, 1, 1], [205, 352, 1, 1], [205, 366, 1, 1], [207, 227, 1, 1], [207, 235, 1, 1], [207, 365, 1, 1], [207, 373, 1, 1], [208, 247, 1, 1], [208, 353, 1, 1], [210, 226, 1, 1], [210, 374, 1, 1], [211, 235, 1, 3], [211, 242, 1, 2], [211, 357, 1, 2], [211, 363, 1, 3], [212, 239, 1, 2], [212, 360, 1, 2], [213, 241, 1, 1], [213, 359, 1, 1], [215, 235, 1, 1], [215, 365, 1, 1], [217, 240, 1, 1], [217, 248, 1, 1], [217, 352, 1, 1], [217, 360, 1, 1], [220, 246, 1, 1], [220, 354, 1, 1], [222, 247, 1, 1], [222, 353, 1, 1], [223, 249, 1, 1], [223, 351, 1, 1], [225, 249, 1, 2], [225, 350, 1, 2], [227, 241, 1, 1], [227, 359, 1, 1], [228, 242, 1, 1], [228, 245, 1, 1], [228, 247, 1, 1], [228, 353, 1, 1], [228, 355, 1, 1], [228, 358, 1, 1], [229, 246, 1, 1], [229, 354, 1, 1], [231, 245, 1, 1], [231, 355, 1, 1], [232, 246, 1, 1], [232, 250, 1, 1], [232, 252, 1, 1], [232, 348, 1, 1], [232, 350, 1, 1], [232, 354, 1, 1], [233, 252, 1, 1], [233, 348, 1, 1], [235, 254, 1, 1], [235, 346, 1, 1], [237, 247, 1, 1], [237, 249, 1, 1], [237, 351, 1, 1], [237, 353, 1, 1], [238, 249, 1, 1], [238, 351, 1, 1], [239, 250, 1, 1], [239, 350, 1, 1], [243, 255, 1, 1], [243, 345, 1, 1], [248, 259, 1, 1], [248, 261, 1, 1], [248, 339, 1, 1], [248, 341, 1, 1], [250, 263, 1, 1], [250, 265, 1, 1], [250, 335, 1, 1], [250, 337, 1, 1], [252, 268, 1, 1], [252, 332, 1, 1], [258, 278, 1, 1], [258, 322, 1, 1], [259, 280, 1, 1], [259, 320, 1, 1], [260, 281, 1, 2], [260, 318, 1, 2], [261, 280, 1, 3], [261, 318, 1, 3], [262, 276, 1, 1], [262, 324, 1, 1], [263, 268, 1, 1], [263, 332, 1, 1], [264, 253, 1, 1], [264, 257, 1, 1], [264, 265, 1, 1], [264, 335, 1, 1], [264, 343, 1, 1], [264, 347, 1, 1], [265, 245, 1, 1], [265, 256, 1, 1], [265, 261, 1, 1], [265, 339, 1, 1], [265, 344, 1, 1], [265, 355, 1, 1], [266, 229, 1, 1], [266, 371, 1, 1], [267, 229, 1, 1], [267, 241, 1, 1], [267, 250, 1, 1], [267, 350, 1, 1], [267, 359, 1, 1], [267, 371, 1, 1], [268, 229, 1, 1], [268, 231, 1, 1], [268, 239, 1, 1], [268, 245, 1, 1], [268, 355, 1, 1], [268, 361, 1, 1], [268, 369, 1, 1], [268, 371, 1, 1], [269, 233, 1, 1], [269, 241, 1, 1], [269, 249, 1, 1], [269, 351, 1, 1], [269, 359, 1, 1], [269, 367, 1, 1], [270, 247, 1, 1], [270, 353, 1, 1], [271, 224, 1, 1], [271, 376, 1, 1], [272, 227, 1, 3], [272, 241, 1, 1], [272, 359, 1, 1], [272, 371, 1, 3], [273, 211, 1, 1], [273, 241, 1, 1], [273, 359, 1, 1], [273, 389, 1, 1], [274, 210, 1, 1], [274, 214, 1, 2], [274, 385, 1, 2], [274, 390, 1, 1], [275, 236, 1, 1], [275, 364, 1, 1], [276, 210, 1, 1], [276, 212, 1, 1], [276, 388, 1, 1], [276, 390, 1, 1], [277, 210, 1, 1], [277, 390, 1, 1], [278, 207, 1, 1], [278, 393, 1, 1], [279, 205, 1, 1], [279, 229, 1, 1], [279, 371, 1, 1], [279, 395, 1, 1], [280, 205, 1, 1], [280, 214, 1, 1], [280, 386, 1, 1], [280, 395, 1, 1], [282, 203, 1, 1], [282, 397, 1, 1], [283, 222, 1, 1], [283, 378, 1, 1], [285, 209, 1, 1], [285, 391, 1, 1], [286, 178, 1, 1], [286, 422, 1, 1], [289, 162, 1, 1], [289, 166, 1, 1], [289, 434, 1, 1], [289, 438, 1, 1], [290, 211, 1, 1], [290, 389, 1, 1], [291, 177, 1, 1], [291, 423, 1, 1], [292, 175, 1, 1], [292, 201, 1, 1], [292, 399, 1, 1], [292, 425, 1, 1], [293, 202, 1, 1], [293, 398, 1, 1], [294, 188, 1, 1], [294, 412, 1, 1], [295, 201, 1, 1], [295, 208, 1, 1], [295, 392, 1, 1], [295, 399, 1, 1], [296, 186, 1, 1], [296, 189, 1, 1], [296, 411, 1, 1], [296, 414, 1, 1], [297, 186, 1, 1], [297, 414, 1, 1], [298, 171, 1, 1], [298, 173, 1, 1], [298, 427, 1, 1], [298, 429, 1, 1], [299, 179, 1, 1], [299, 185, 1, 1], [299, 190, 1, 1], [299, 193, 1, 1], [299, 203, 1, 1], [299, 397, 1, 1], [299, 407, 1, 1], [299, 410, 1, 1], [299, 415, 1, 1], [299, 421, 1, 1], [300, 186, 1, 1], [300, 203, 1, 1], [300, 397, 1, 1], [300, 414, 1, 1], [301, 174, 1, 2], [301, 182, 1, 1], [301, 418, 1, 1], [301, 425, 1, 2], [302, 168, 1, 1], [302, 432, 1, 1], [304, 174, 1, 2], [304, 425, 1, 2], [305, 166, 1, 1], [305, 196, 1, 1], [305, 404, 1, 1], [305, 434, 1, 1], [306, 175, 1, 1], [306, 196, 1, 1], [306, 404, 1, 1], [306, 425, 1, 1], [309, 177, 1, 1], [309, 423, 1, 1], [310, 172, 1, 1], [310, 178, 1, 1], [310, 422, 1, 1], [310, 428, 1, 1], [312, 174, 1, 1], [312, 176, 1, 2], [312, 423, 1, 2], [312, 426, 1, 1], [314, 174, 1, 1], [314, 176, 1, 1], [314, 424, 1, 1], [314, 426, 1, 1], [316, 176, 1, 1], [316, 424, 1, 1], [317, 183, 1, 1], [317, 417, 1, 1], [318, 188, 1, 1], [318, 412, 1, 1], [321, 186, 1, 1], [321, 414, 1, 1], [322, 186, 1, 1], [322, 414, 1, 1], [325, 182, 1, 1], [325, 184, 1, 1], [325, 416, 1, 1], [325, 418, 1, 1], [329, 171, 1, 1], [329, 429, 1, 1], [330, 164, 1, 1], [330, 436, 1, 1], [331, 174, 1, 1], [331, 426, 1, 1], [333, 174, 1, 1], [333, 426, 1, 1], [335, 166, 1, 2], [335, 433, 1, 2], [336, 169, 1, 2], [336, 430, 1, 2], [337, 164, 1, 3], [337, 434, 1, 3], [338, 172, 1, 1], [338, 428, 1, 1], [341, 172, 1, 1], [341, 176, 1, 1], [341, 424, 1, 1], [341, 428, 1, 1], [343, 175, 1, 1], [343, 425, 1, 1], [347, 166, 1, 1], [347, 169, 1, 1], [347, 431, 1, 1], [347, 434, 1, 1], [350, 167, 1, 1], [350, 433, 1, 1], [355, 130, 1, 1], [355, 470, 1, 1], [358, 130, 1, 1], [358, 147, 1, 1], [358, 453, 1, 1], [358, 470, 1, 1], [359, 130, 1, 1], [359, 137, 1, 1], [359, 170, 1, 2], [359, 429, 1, 2], [359, 463, 1, 1], [359, 470, 1, 1], [360, 131, 1, 1], [360, 135, 1, 1], [360, 148, 1, 1], [360, 452, 1, 1], [360, 465, 1, 1], [360, 469, 1, 1], [361, 127, 1, 2], [361, 140, 1, 1], [361, 147, 1, 2], [361, 452, 1, 2], [361, 460, 1, 1], [361, 472, 1, 2], [362, 134, 1, 1], [362, 155, 1, 1], [362, 445, 1, 1], [362, 466, 1, 1], [363, 141, 1, 1], [363, 144, 1, 1], [363, 146, 1, 2], [363, 158, 1, 1], [363, 442, 1, 1], [363, 453, 1, 2], [363, 456, 1, 1], [363, 459, 1, 1], [364, 136, 1, 1], [364, 142, 1, 1], [364, 159, 1, 1], [364, 441, 1, 1], [364, 458, 1, 1], [364, 464, 1, 1], [365, 135, 1, 1], [365, 162, 1, 1], [365, 438, 1, 1], [365, 465, 1, 1], [367, 134, 1, 1], [367, 466, 1, 1], [369, 136, 1, 1], [369, 464, 1, 1], [371, 168, 1, 2], [371, 431, 1, 2], [372, 86, 1, 1], [372, 169, 1, 1], [372, 431, 1, 1], [372, 514, 1, 1], [373, 131, 1, 1], [373, 469, 1, 1], [375, 121, 1, 1], [375, 479, 1, 1], [376, 92, 1, 1], [376, 127, 1, 1], [376, 473, 1, 1], [376, 508, 1, 1], [377, 120, 1, 1], [377, 480, 1, 1], [378, 127, 1, 1], [378, 131, 1, 1], [378, 469, 1, 1], [378, 473, 1, 1], [379, 123, 1, 1], [379, 125, 1, 1], [379, 129, 1, 1], [379, 131, 1, 1], [379, 469, 1, 1], [379, 471, 1, 1], [379, 475, 1, 1], [379, 477, 1, 1], [383, 121, 1, 1], [383, 479, 1, 1], [386, 108, 1, 1], [386, 114, 1, 1], [386, 120, 1, 1], [386, 480, 1, 1], [386, 486, 1, 1], [386, 492, 1, 1], [388, 121, 1, 1], [388, 123, 1, 1], [388, 477, 1, 1], [388, 479, 1, 1], [389, 132, 1, 1], [389, 468, 1, 1], [390, 124, 1, 1], [390, 127, 1, 1], [390, 129, 1, 1], [390, 471, 1, 1], [390, 473, 1, 1], [390, 476, 1, 1], [391, 133, 1, 1], [391, 467, 1, 1], [392, 169, 1, 1], [392, 431, 1, 1], [393, 121, 1, 1], [393, 168, 1, 2], [393, 431, 1, 2], [393, 479, 1, 1], [396, 124, 1, 1], [396, 476, 1, 1], [397, 131, 1, 1], [397, 469, 1, 1], [398, 139, 1, 1], [398, 461, 1, 1], [399, 103, 1, 1], [399, 497, 1, 1], [400, 160, 1, 1], [400, 440, 1, 1], [401, 145, 1, 1], [401, 455, 1, 1], [402, 139, 1, 1], [402, 148, 1, 2], [402, 154, 1, 1], [402, 157, 1, 1], [402, 443, 1, 1], [402, 446, 1, 1], [402, 451, 1, 2], [402, 461, 1, 1], [403, 149, 1, 1], [403, 157, 1, 1], [403, 443, 1, 1], [403, 451, 1, 1], [404, 142, 1, 1], [404, 151, 1, 1], [404, 449, 1, 1], [404, 458, 1, 1], [406, 133, 1, 1], [406, 137, 1, 1], [406, 139, 1, 1], [406, 170, 1, 1], [406, 430, 1, 1], [406, 461, 1, 1], [406, 463, 1, 1], [406, 467, 1, 1], [407, 132, 1, 1], [407, 135, 1, 1], [407, 148, 1, 1], [407, 452, 1, 1], [407, 465, 1, 1], [407, 468, 1, 1], [408, 147, 1, 1], [408, 150, 1, 2], [408, 449, 1, 2], [408, 453, 1, 1], [410, 136, 1, 1], [410, 464, 1, 1], [412, 138, 1, 1], [412, 462, 1, 1], [413, 173, 1, 1], [413, 427, 1, 1], [416, 170, 1, 1], [416, 430, 1, 1], [417, 166, 1, 1], [417, 434, 1, 1], [419, 171, 1, 1], [419, 175, 1, 1], [419, 425, 1, 1], [419, 429, 1, 1], [426, 172, 1, 1], [426, 174, 1, 1], [426, 426, 1, 1], [426, 428, 1, 1], [428, 172, 1, 1], [428, 428, 1, 1], [429, 167, 1, 1], [429, 173, 1, 1], [429, 427, 1, 1], [429, 433, 1, 1], [430, 173, 1, 1], [430, 427, 1, 1], [433, 165, 1, 1], [433, 167, 1, 1], [433, 169, 1, 2], [433, 181, 1, 2], [433, 418, 1, 2], [433, 430, 1, 2], [433, 433, 1, 1], [433, 435, 1, 1], [435, 182, 1, 1], [435, 418, 1, 1], [437, 184, 1, 1], [437, 416, 1, 1], [438, 172, 1, 1], [438, 428, 1, 1], [439, 182, 1, 1], [439, 418, 1, 1], [440, 183, 1, 1], [440, 417, 1, 1], [443, 188, 1, 1], [443, 412, 1, 1], [450, 194, 1, 1], [450, 406, 1, 1], [451, 194, 1, 1], [451, 406, 1, 1], [452, 184, 1, 1], [452, 416, 1, 1], [453, 187, 1, 1], [453, 413, 1, 1], [454, 183, 1, 1], [454, 417, 1, 1], [455, 176, 1, 1], [455, 184, 1, 2], [455, 415, 1, 2], [455, 424, 1, 1], [456, 185, 1, 1], [456, 415, 1, 1], [459, 178, 1, 1], [459, 422, 1, 1], [460, 178, 1, 1], [460, 182, 1, 1], [460, 204, 1, 1], [460, 396, 1, 1], [460, 418, 1, 1], [460, 422, 1, 1], [463, 208, 1, 1], [463, 392, 1, 1], [464, 183, 1, 1], [464, 417, 1, 1], [466, 202, 1, 1], [466, 398, 1, 1], [467, 293, 1, 1], [467, 307, 1, 1], [468, 181, 1, 1], [468, 184, 1, 1], [468, 416, 1, 1], [468, 419, 1, 1], [469, 201, 1, 1], [469, 292, 1, 1], [469, 308, 1, 1], [469, 399, 1, 1], [470, 184, 1, 1], [470, 191, 1, 1], [470, 409, 1, 1], [470, 416, 1, 1], [471, 184, 1, 1], [471, 190, 1, 1], [471, 202, 1, 1], [471, 398, 1, 1], [471, 410, 1, 1], [471, 416, 1, 1], [473, 185, 1, 2], [473, 189, 1, 1], [473, 213, 1, 1], [473, 215, 1, 1], [473, 385, 1, 1], [473, 387, 1, 1], [473, 411, 1, 1], [473, 414, 1, 2], [474, 197, 1, 1], [474, 199, 1, 1], [474, 217, 1, 1], [474, 383, 1, 1], [474, 401, 1, 1], [474, 403, 1, 1], [475, 183, 1, 2], [475, 230, 1, 1], [475, 370, 1, 1], [475, 416, 1, 2], [478, 182, 1, 2], [478, 238, 1, 1], [478, 273, 1, 1], [478, 327, 1, 1], [478, 362, 1, 1], [478, 417, 1, 2], [479, 245, 1, 1], [479, 266, 1, 1], [479, 334, 1, 1], [479, 355, 1, 1], [480, 227, 1, 1], [480, 242, 1, 1], [480, 358, 1, 1], [480, 373, 1, 1], [481, 186, 1, 1], [481, 226, 1, 1], [481, 264, 1, 1], [481, 278, 1, 1], [481, 322, 1, 1], [481, 336, 1, 1], [481, 374, 1, 1], [481, 414, 1, 1], [482, 223, 1, 1], [482, 238, 1, 1], [482, 273, 1, 1], [482, 327, 1, 1], [482, 362, 1, 1], [482, 377, 1, 1], [483, 179, 1, 1], [483, 226, 1, 1], [483, 374, 1, 1], [483, 421, 1, 1], [484, 251, 1, 1], [484, 349, 1, 1], [485, 254, 1, 1], [485, 346, 1, 1], [486, 230, 1, 1], [486, 370, 1, 1], [487, 230, 1, 1], [487, 269, 1, 1], [487, 331, 1, 1], [487, 370, 1, 1], [488, 258, 1, 1], [488, 342, 1, 1], [489, 258, 1, 2], [489, 341, 1, 2], [490, 255, 1, 2], [490, 344, 1, 2], [491, 232, 1, 2], [491, 255, 1, 1], [491, 345, 1, 1], [491, 367, 1, 2], [492, 252, 1, 1], [492, 254, 1, 1], [492, 346, 1, 1], [492, 348, 1, 1], [494, 223, 1, 1], [494, 377, 1, 1], [495, 230, 1, 1], [495, 370, 1, 1]], [[132, 299, 1, 1], [132, 301, 1, 1], [134, 293, 1, 1], [134, 307, 1, 1], [139, 296, 1, 1], [139, 304, 1, 1], [140, 294, 1, 1], [140, 296, 1, 1], [140, 304, 1, 1], [140, 306, 1, 1], [141, 292, 1, 1], [141, 308, 1, 1], [142, 292, 1, 1], [142, 308, 1, 1], [144, 287, 1, 1], [144, 290, 1, 2], [144, 309, 1, 2], [144, 313, 1, 1], [149, 278, 1, 1], [149, 322, 1, 1], [150, 277, 1, 1], [150, 323, 1, 1], [151, 285, 1, 1], [151, 315, 1, 1], [155, 286, 1, 1], [155, 314, 1, 1], [156, 284, 1, 1], [156, 316, 1, 1], [158, 287, 1, 1], [158, 313, 1, 1], [160, 263, 1, 1], [160, 337, 1, 1], [163, 292, 1, 1], [163, 308, 1, 1], [164, 291, 1, 2], [164, 308, 1, 2], [165, 233, 1, 1], [165, 279, 1, 1], [165, 281, 1, 1], [165, 319, 1, 1], [165, 321, 1, 1], [165, 367, 1, 1], [166, 269, 1, 1], [166, 275, 1, 1], [166, 281, 1, 1], [166, 319, 1, 1], [166, 325, 1, 1], [166, 331, 1, 1], [167, 276, 1, 1], [167, 324, 1, 1], [169, 264, 1, 1], [169, 336, 1, 1], [175, 236, 1, 1], [175, 262, 1, 1], [175, 267, 1, 1], [175, 333, 1, 1], [175, 338, 1, 1], [175, 364, 1, 1], [177, 251, 1, 1], [177, 349, 1, 1], [178, 240, 1, 1], [178, 360, 1, 1], [181, 246, 1, 1], [181, 248, 1, 1], [181, 352, 1, 1], [181, 354, 1, 1], [182, 241, 1, 1], [182, 257, 1, 1], [182, 343, 1, 1], [182, 359, 1, 1], [183, 258, 1, 2], [183, 341, 1, 2], [185, 243, 1, 1], [185, 357, 1, 1], [189, 243, 1, 1], [189, 357, 1, 1], [193, 253, 1, 1], [193, 347, 1, 1], [198, 245, 1, 1], [198, 250, 1, 1], [198, 350, 1, 1], [198, 355, 1, 1], [206, 235, 1, 1], [206, 365, 1, 1], [207, 249, 1, 1], [207, 351, 1, 1], [209, 244, 1, 1], [209, 249, 1, 1], [209, 351, 1, 1], [209, 356, 1, 1], [212, 238, 1, 1], [212, 362, 1, 1], [213, 239, 1, 1], [213, 361, 1, 1], [216, 244, 1, 1], [216, 356, 1, 1], [218, 244, 1, 1], [218, 356, 1, 1], [226, 242, 1, 1], [226, 358, 1, 1], [227, 247, 1, 1], [227, 353, 1, 1], [229, 238, 1, 1], [229, 362, 1, 1], [230, 244, 1, 1], [230, 356, 1, 1], [231, 249, 1, 1], [231, 252, 1, 1], [231, 348, 1, 1], [231, 351, 1, 1], [238, 253, 1, 1], [238, 347, 1, 1], [240, 247, 1, 1], [240, 252, 1, 1], [240, 257, 1, 1], [240, 343, 1, 1], [240, 348, 1, 1], [240, 353, 1, 1], [242, 258, 1, 1], [242, 342, 1, 1], [243, 254, 1, 1], [243, 346, 1, 1], [244, 258, 1, 1], [244, 342, 1, 1], [246, 261, 1, 1], [246, 339, 1, 1], [251, 264, 1, 2], [251, 335, 1, 2], [252, 266, 1, 1], [252, 334, 1, 1], [254, 269, 1, 1], [254, 271, 1, 1], [254, 329, 1, 1], [254, 331, 1, 1], [259, 281, 1, 1], [259, 319, 1, 1], [260, 283, 1, 2], [260, 316, 1, 2], [261, 283, 1, 2], [261, 316, 1, 2], [262, 258, 1, 1], [262, 342, 1, 1], [263, 242, 1, 1], [263, 271, 1, 1], [263, 329, 1, 1], [263, 358, 1, 1], [264, 242, 1, 1], [264, 261, 1, 1], [264, 339, 1, 1], [264, 358, 1, 1], [265, 243, 1, 1], [265, 255, 1, 1], [265, 345, 1, 1], [265, 357, 1, 1], [269, 231, 1, 1], [269, 250, 1, 1], [269, 350, 1, 1], [269, 369, 1, 1], [271, 206, 1, 1], [271, 394, 1, 1], [272, 224, 1, 1], [272, 376, 1, 1], [273, 240, 1, 1], [273, 360, 1, 1], [275, 208, 1, 1], [275, 227, 1, 1], [275, 373, 1, 1], [275, 392, 1, 1], [276, 236, 1, 1], [276, 364, 1, 1], [277, 227, 1, 1], [277, 373, 1, 1], [278, 210, 1, 1], [278, 390, 1, 1], [279, 207, 1, 1], [279, 212, 1, 1], [279, 230, 1, 1], [279, 370, 1, 1], [279, 388, 1, 1], [279, 393, 1, 1], [282, 224, 1, 1], [282, 376, 1, 1], [283, 210, 1, 1], [283, 224, 1, 1], [283, 376, 1, 1], [283, 390, 1, 1], [285, 220, 1, 1], [285, 380, 1, 1], [288, 210, 1, 1], [288, 390, 1, 1], [291, 166, 1, 1], [291, 175, 1, 1], [291, 213, 1, 1], [291, 387, 1, 1], [291, 425, 1, 1], [291, 434, 1, 1], [293, 188, 1, 1], [293, 412, 1, 1], [294, 173, 1, 1], [294, 427, 1, 1], [295, 175, 1, 1], [295, 207, 1, 1], [295, 393, 1, 1], [295, 425, 1, 1], [296, 185, 1, 1], [296, 200, 1, 1], [296, 400, 1, 1], [296, 415, 1, 1], [297, 171, 1, 1], [297, 187, 1, 2], [297, 202, 1, 2], [297, 397, 1, 2], [297, 412, 1, 2], [297, 429, 1, 1], [298, 169, 1, 1], [298, 176, 1, 1], [298, 424, 1, 1], [298, 431, 1, 1], [301, 192, 1, 1], [301, 408, 1, 1], [302, 167, 1, 1], [302, 433, 1, 1], [303, 176, 1, 1], [303, 424, 1, 1], [304, 167, 1, 1], [304, 433, 1, 1], [305, 165, 1, 1], [305, 435, 1, 1], [306, 178, 1, 1], [306, 422, 1, 1], [307, 196, 1, 2], [307, 403, 1, 2], [308, 178, 1, 1], [308, 422, 1, 1], [311, 173, 1, 1], [311, 175, 1, 1], [311, 425, 1, 1], [311, 427, 1, 1], [313, 173, 1, 1], [313, 176, 1, 1], [313, 424, 1, 1], [313, 427, 1, 1], [314, 180, 1, 1], [314, 420, 1, 1], [315, 181, 1, 1], [315, 419, 1, 1], [316, 181, 1, 1], [316, 419, 1, 1], [317, 189, 1, 1], [317, 411, 1, 1], [324, 180, 1, 1], [324, 420, 1, 1], [328, 180, 1, 1], [328, 420, 1, 1], [332, 166, 1, 1], [332, 434, 1, 1], [333, 167, 1, 1], [333, 170, 1, 1], [333, 430, 1, 1], [333, 433, 1, 1], [334, 167, 1, 1], [334, 171, 1, 1], [334, 180, 1, 1], [334, 420, 1, 1], [334, 429, 1, 1], [334, 433, 1, 1], [335, 169, 1, 1], [335, 431, 1, 1], [339, 171, 1, 1], [339, 429, 1, 1], [345, 174, 1, 1], [345, 426, 1, 1], [347, 170, 1, 1], [347, 174, 1, 1], [347, 426, 1, 1], [347, 430, 1, 1], [352, 173, 1, 1], [352, 427, 1, 1], [356, 147, 1, 1], [356, 168, 1, 1], [356, 432, 1, 1], [356, 453, 1, 1], [357, 130, 1, 1], [357, 144, 1, 1], [357, 146, 1, 1], [357, 454, 1, 1], [357, 456, 1, 1], [357, 470, 1, 1], [358, 145, 1, 1], [358, 455, 1, 1], [359, 157, 1, 1], [359, 443, 1, 1], [360, 132, 1, 1], [360, 149, 1, 1], [360, 451, 1, 1], [360, 468, 1, 1], [361, 151, 1, 1], [361, 449, 1, 1], [362, 126, 1, 1], [362, 138, 1, 1], [362, 140, 1, 1], [362, 153, 1, 1], [362, 447, 1, 1], [362, 460, 1, 1], [362, 462, 1, 1], [362, 474, 1, 1], [363, 154, 1, 1], [363, 446, 1, 1], [364, 144, 1, 1], [364, 160, 1, 2], [364, 439, 1, 2], [364, 456, 1, 1], [365, 142, 1, 1], [365, 458, 1, 1], [366, 162, 1, 1], [366, 438, 1, 1], [367, 136, 1, 1], [367, 164, 1, 1], [367, 436, 1, 1], [367, 464, 1, 1], [370, 132, 1, 1], [370, 468, 1, 1], [373, 169, 1, 1], [373, 431, 1, 1], [374, 133, 1, 1], [374, 467, 1, 1], [376, 121, 1, 1], [376, 479, 1, 1], [379, 126, 1, 1], [379, 128, 1, 1], [379, 472, 1, 1], [379, 474, 1, 1], [380, 131, 1, 1], [380, 469, 1, 1], [381, 122, 1, 1], [381, 478, 1, 1], [383, 122, 1, 1], [383, 478, 1, 1], [384, 106, 1, 1], [384, 115, 1, 1], [384, 485, 1, 1], [384, 494, 1, 1], [385, 120, 1, 1], [385, 480, 1, 1], [386, 107, 1, 1], [386, 116, 1, 1], [386, 484, 1, 1], [386, 493, 1, 1], [387, 122, 1, 2], [387, 477, 1, 2], [389, 114, 1, 1], [389, 131, 1, 1], [389, 469, 1, 1], [389, 486, 1, 1], [390, 130, 1, 1], [390, 470, 1, 1], [391, 126, 1, 1], [391, 169, 1, 1], [391, 431, 1, 1], [391, 474, 1, 1], [392, 124, 1, 1], [392, 476, 1, 1], [394, 121, 1, 1], [394, 479, 1, 1], [396, 137, 1, 1], [396, 463, 1, 1], [398, 163, 1, 1], [398, 437, 1, 1], [399, 139, 1, 1], [399, 461, 1, 1], [400, 136, 1, 1], [400, 161, 1, 2], [400, 438, 1, 2], [400, 464, 1, 1], [401, 138, 1, 1], [401, 156, 1, 1], [401, 444, 1, 1], [401, 462, 1, 1], [402, 159, 1, 1], [402, 441, 1, 1], [403, 144, 1, 1], [403, 154, 1, 1], [403, 446, 1, 1], [403, 456, 1, 1], [404, 138, 1, 1], [404, 462, 1, 1], [405, 151, 1, 1], [405, 449, 1, 1], [406, 134, 1, 1], [406, 466, 1, 1], [407, 137, 1, 1], [407, 141, 1, 1], [407, 459, 1, 1], [407, 463, 1, 1], [408, 135, 1, 1], [408, 465, 1, 1], [410, 169, 1, 1], [410, 431, 1, 1], [417, 167, 1, 1], [417, 433, 1, 1], [427, 172, 1, 1], [427, 428, 1, 1], [428, 168, 1, 1], [428, 432, 1, 1], [431, 168, 1, 1], [431, 432, 1, 1], [434, 164, 1, 1], [434, 171, 1, 2], [434, 176, 1, 1], [434, 424, 1, 1], [434, 428, 1, 2], [434, 436, 1, 1], [435, 170, 1, 1], [435, 176, 1, 1], [435, 424, 1, 1], [435, 430, 1, 1], [436, 168, 1, 1], [436, 432, 1, 1], [441, 181, 1, 2], [441, 418, 1, 2], [442, 185, 1, 1], [442, 415, 1, 1], [451, 188, 1, 1], [451, 195, 1, 1], [451, 405, 1, 1], [451, 412, 1, 1], [456, 300, 1, 1], [457, 183, 1, 1], [457, 417, 1, 1], [458, 181, 1, 1], [458, 419, 1, 1], [462, 184, 1, 1], [462, 416, 1, 1], [463, 178, 1, 1], [463, 422, 1, 1], [465, 211, 1, 1], [465, 389, 1, 1], [467, 185, 1, 1], [467, 294, 1, 1], [467, 306, 1, 1], [467, 415, 1, 1], [468, 182, 1, 1], [468, 200, 1, 2], [468, 209, 1, 1], [468, 214, 1, 1], [468, 294, 1, 1], [468, 306, 1, 1], [468, 386, 1, 1], [468, 391, 1, 1], [468, 399, 1, 2], [468, 418, 1, 1], [469, 199, 1, 1], [469, 401, 1, 1], [470, 183, 1, 1], [470, 203, 1, 1], [470, 397, 1, 1], [470, 417, 1, 1], [471, 221, 1, 1], [471, 379, 1, 1], [472, 220, 1, 1], [472, 380, 1, 1], [473, 222, 1, 1], [473, 225, 1, 1], [473, 287, 1, 1], [473, 313, 1, 1], [473, 375, 1, 1], [473, 378, 1, 1], [474, 198, 1, 1], [474, 402, 1, 1], [475, 172, 1, 1], [475, 196, 1, 1], [475, 211, 1, 1], [475, 389, 1, 1], [475, 404, 1, 1], [475, 428, 1, 1], [476, 195, 1, 1], [476, 198, 1, 1], [476, 229, 1, 1], [476, 278, 1, 1], [476, 322, 1, 1], [476, 371, 1, 1], [476, 402, 1, 1], [476, 405, 1, 1], [477, 285, 1, 1], [477, 315, 1, 1], [478, 240, 1, 1], [478, 360, 1, 1], [479, 282, 1, 1], [479, 318, 1, 1], [480, 280, 1, 1], [480, 320, 1, 1], [481, 244, 1, 1], [481, 356, 1, 1], [482, 264, 1, 1], [482, 336, 1, 1], [483, 225, 1, 1], [483, 375, 1, 1], [484, 226, 1, 1], [484, 270, 1, 1], [484, 272, 1, 1], [484, 328, 1, 1], [484, 330, 1, 1], [484, 374, 1, 1], [485, 226, 1, 1], [485, 230, 1, 1], [485, 235, 1, 1], [485, 256, 1, 1], [485, 344, 1, 1], [485, 365, 1, 1], [485, 370, 1, 1], [485, 374, 1, 1], [486, 256, 1, 1], [486, 271, 1, 1], [486, 329, 1, 1], [486, 344, 1, 1], [487, 233, 1, 1], [487, 238, 1, 1], [487, 362, 1, 1], [487, 367, 1, 1], [488, 232, 1, 1], [488, 368, 1, 1], [489, 256, 1, 2], [489, 343, 1, 2], [490, 232, 1, 1], [490, 368, 1, 1], [492, 231, 1, 1], [492, 369, 1, 1], [493, 231, 1, 1], [493, 254, 1, 1], [493, 346, 1, 1], [493, 369, 1, 1], [494, 230, 1, 1], [494, 370, 1, 1]], [[20, 300, 1, 1], [63, 299, 1, 1], [63, 301, 1, 1], [91, 296, 1, 1], [91, 304, 1, 1], [131, 297, 1, 1], [131, 303, 1, 1], [133, 292, 1, 1], [133, 308, 1, 1], [135, 299, 1, 1], [135, 301, 1, 1], [138, 294, 1, 1], [138, 306, 1, 1], [141, 283, 1, 1], [141, 285, 1, 1], [141, 297, 1, 1], [141, 303, 1, 1], [141, 315, 1, 1], [141, 317, 1, 1], [143, 289, 1, 1], [143, 311, 1, 1], [148, 288, 1, 1], [148, 312, 1, 1], [152, 283, 1, 1], [152, 285, 1, 1], [152, 315, 1, 1], [152, 317, 1, 1], [154, 287, 1, 1], [154, 313, 1, 1], [158, 288, 1, 1], [158, 312, 1, 1], [159, 286, 1, 1], [159, 314, 1, 1], [162, 276, 1, 1], [162, 324, 1, 1], [164, 293, 1, 1], [164, 307, 1, 1], [165, 277, 1, 1], [165, 323, 1, 1], [166, 268, 1, 1], [166, 284, 1, 1], [166, 316, 1, 1], [166, 332, 1, 1], [167, 266, 1, 1], [167, 281, 1, 1], [167, 319, 1, 1], [167, 334, 1, 1], [169, 266, 1, 1], [169, 276, 1, 1], [169, 324, 1, 1], [169, 334, 1, 1], [171, 251, 1, 1], [171, 272, 1, 1], [171, 328, 1, 1], [171, 349, 1, 1], [174, 261, 1, 1], [174, 339, 1, 1], [176, 239, 1, 1], [176, 361, 1, 1], [177, 240, 1, 1], [177, 360, 1, 1], [178, 250, 1, 1], [178, 350, 1, 1], [180, 253, 1, 2], [180, 346, 1, 2], [181, 257, 1, 1], [181, 343, 1, 1], [182, 242, 1, 1], [182, 244, 1, 1], [182, 356, 1, 1], [182, 358, 1, 1], [184, 244, 1, 1], [184, 258, 1, 1], [184, 342, 1, 1], [184, 356, 1, 1], [185, 244, 1, 1], [185, 356, 1, 1], [188, 246, 1, 1], [188, 354, 1, 1], [191, 248, 1, 1], [191, 352, 1, 1], [192, 249, 1, 1], [192, 253, 1, 1], [192, 347, 1, 1], [192, 351, 1, 1], [193, 246, 1, 1], [193, 354, 1, 1], [199, 251, 1, 1], [199, 349, 1, 1], [200, 247, 1, 1], [200, 353, 1, 1], [205, 233, 1, 1], [205, 242, 1, 1], [205, 358, 1, 1], [205, 367, 1, 1], [206, 248, 1, 1], [206, 352, 1, 1], [212, 237, 1, 1], [212, 363, 1, 1], [213, 240, 1, 1], [213, 360, 1, 1], [215, 243, 1, 1], [215, 357, 1, 1], [216, 249, 1, 1], [216, 351, 1, 1], [217, 244, 1, 1], [217, 246, 1, 1], [217, 249, 1, 1], [217, 351, 1, 1], [217, 354, 1, 1], [217, 356, 1, 1], [223, 250, 1, 1], [223, 350, 1, 1], [226, 248, 1, 1], [226, 352, 1, 1], [227, 238, 1, 1], [227, 362, 1, 1], [229, 237, 1, 1], [229, 244, 1, 1], [229, 356, 1, 1], [229, 363, 1, 1], [231, 246, 1, 1], [231, 354, 1, 1], [232, 249, 1, 1], [232, 351, 1, 1], [236, 253, 1, 2], [236, 346, 1, 2], [238, 252, 1, 1], [238, 348, 1, 1], [239, 247, 1, 1], [239, 253, 1, 1], [239, 347, 1, 1], [239, 353, 1, 1], [242, 259, 1, 1], [242, 341, 1, 1], [244, 255, 1, 1], [244, 345, 1, 1], [245, 261, 1, 1], [245, 339, 1, 1], [246, 257, 1, 2], [246, 342, 1, 2], [254, 267, 1, 1], [254, 333, 1, 1], [255, 273, 1, 1], [255, 327, 1, 1], [256, 273, 1, 1], [256, 275, 1, 1], [256, 325, 1, 1], [256, 327, 1, 1], [260, 285, 1, 1], [260, 315, 1, 1], [261, 285, 1, 2], [261, 314, 1, 2], [263, 259, 1, 1], [263, 341, 1, 1], [266, 253, 1, 1], [266, 347, 1, 1], [269, 245, 1, 1], [269, 355, 1, 1], [270, 226, 1, 1], [270, 232, 1, 1], [270, 368, 1, 1], [270, 374, 1, 1], [271, 229, 1, 1], [271, 371, 1, 1], [272, 234, 1, 1], [272, 366, 1, 1], [273, 224, 1, 1], [273, 242, 1, 1], [273, 358, 1, 1], [273, 376, 1, 1], [274, 229, 1, 1], [274, 235, 1, 1], [274, 365, 1, 1], [274, 371, 1, 1], [275, 214, 1, 1], [275, 238, 1, 1], [275, 362, 1, 1], [275, 386, 1, 1], [276, 208, 1, 2], [276, 391, 1, 2], [277, 209, 1, 1], [277, 228, 1, 1], [277, 372, 1, 1], [277, 391, 1, 1], [278, 208, 1, 1], [278, 392, 1, 1], [279, 209, 1, 1], [279, 391, 1, 1], [280, 206, 1, 1], [280, 210, 1, 1], [280, 216, 1, 1], [280, 219, 1, 1], [280, 381, 1, 1], [280, 384, 1, 1], [280, 390, 1, 1], [280, 394, 1, 1], [281, 214, 1, 1], [281, 386, 1, 1], [286, 209, 1, 1], [286, 220, 1, 1], [286, 380, 1, 1], [286, 391, 1, 1], [287, 208, 1, 1], [287, 392, 1, 1], [294, 205, 1, 1], [294, 395, 1, 1], [295, 170, 1, 1], [295, 173, 1, 2], [295, 205, 1, 1], [295, 395, 1, 1], [295, 426, 1, 2], [295, 430, 1, 1], [296, 173, 1, 1], [296, 427, 1, 1], [297, 172, 1, 1], [297, 428, 1, 1], [298, 178, 1, 1], [298, 189, 1, 1], [298, 411, 1, 1], [298, 422, 1, 1], [299, 173, 1, 3], [299, 180, 1, 1], [299, 187, 1, 1], [299, 413, 1, 1], [299, 420, 1, 1], [299, 425, 1, 3], [300, 174, 1, 1], [300, 178, 1, 3], [300, 184, 1, 1], [300, 201, 1, 1], [300, 399, 1, 1], [300, 416, 1, 1], [300, 420, 1, 3], [300, 426, 1, 1], [301, 173, 1, 1], [301, 191, 1, 1], [301, 203, 1, 1], [301, 397, 1, 1], [301, 409, 1, 1], [301, 427, 1, 1], [302, 169, 1, 1], [302, 176, 1, 1], [302, 182, 1, 1], [302, 418, 1, 1], [302, 424, 1, 1], [302, 431, 1, 1], [303, 194, 1, 1], [303, 201, 1, 1], [303, 399, 1, 1], [303, 406, 1, 1], [304, 195, 1, 1], [304, 405, 1, 1], [305, 199, 1, 1], [305, 401, 1, 1], [306, 179, 1, 1], [306, 421, 1, 1], [308, 196, 1, 1], [308, 404, 1, 1], [309, 178, 1, 1], [309, 422, 1, 1], [310, 173, 1, 1], [310, 427, 1, 1], [317, 190, 1, 1], [317, 410, 1, 1], [326, 184, 1, 1], [326, 416, 1, 1], [329, 170, 1, 1], [329, 430, 1, 1], [331, 170, 1, 2], [331, 429, 1, 2], [333, 168, 1, 1], [333, 175, 1, 1], [333, 177, 1, 1], [333, 423, 1, 1], [333, 425, 1, 1], [333, 432, 1, 1], [334, 169, 1, 2], [334, 430, 1, 2], [338, 169, 1, 1], [338, 431, 1, 1], [345, 169, 1, 1], [345, 171, 1, 1], [345, 429, 1, 1], [345, 431, 1, 1], [348, 170, 1, 1], [348, 430, 1, 1], [350, 168, 1, 1], [350, 432, 1, 1], [352, 172, 1, 1], [352, 428, 1, 1], [360, 126, 1, 1], [360, 138, 1, 1], [360, 462, 1, 1], [360, 474, 1, 1], [361, 137, 1, 1], [361, 463, 1, 1], [365, 136, 1, 1], [365, 464, 1, 1], [367, 165, 1, 1], [367, 435, 1, 1], [368, 136, 1, 1], [368, 464, 1, 1], [370, 135, 1, 1], [370, 465, 1, 1], [371, 135, 1, 1], [371, 465, 1, 1], [372, 132, 1, 1], [372, 468, 1, 1], [374, 169, 1, 1], [374, 431, 1, 1], [377, 132, 1, 1], [377, 468, 1, 1], [380, 123, 1, 1], [380, 477, 1, 1], [387, 115, 1, 1], [387, 485, 1, 1], [388, 132, 1, 1], [388, 468, 1, 1], [389, 124, 1, 1], [389, 476, 1, 1], [390, 108, 1, 1], [390, 126, 1, 1], [390, 169, 1, 1], [390, 431, 1, 1], [390, 474, 1, 1], [390, 492, 1, 1], [398, 140, 1, 1], [398, 460, 1, 1], [399, 164, 1, 1], [399, 436, 1, 1], [400, 139, 1, 1], [400, 159, 1, 1], [400, 441, 1, 1], [400, 461, 1, 1], [402, 150, 1, 1], [402, 450, 1, 1], [403, 142, 1, 1], [403, 153, 1, 1], [403, 158, 1, 1], [403, 442, 1, 1], [403, 447, 1, 1], [403, 458, 1, 1], [404, 141, 1, 1], [404, 157, 1, 1], [404, 443, 1, 1], [404, 459, 1, 1], [405, 143, 1, 1], [405, 457, 1, 1], [406, 149, 1, 1], [406, 451, 1, 1], [407, 136, 1, 1], [407, 464, 1, 1], [408, 131, 1, 1], [408, 167, 1, 1], [408, 170, 1, 1], [408, 430, 1, 1], [408, 433, 1, 1], [408, 469, 1, 1], [409, 168, 1, 1], [409, 432, 1, 1], [411, 173, 1, 1], [411, 427, 1, 1], [416, 165, 1, 2], [416, 434, 1, 2], [417, 168, 1, 1], [417, 432, 1, 1], [418, 170, 1, 1], [418, 430, 1, 1], [426, 175, 1, 1], [426, 425, 1, 1], [428, 173, 1, 1], [428, 427, 1, 1], [433, 164, 1, 1], [433, 436, 1, 1], [435, 167, 1, 1], [435, 178, 1, 1], [435, 422, 1, 1], [435, 433, 1, 1], [436, 172, 1, 1], [436, 428, 1, 1], [438, 168, 1, 1], [438, 432, 1, 1], [439, 173, 1, 1], [439, 427, 1, 1], [441, 183, 1, 1], [441, 417, 1, 1], [452, 187, 1, 1], [452, 196, 1, 1], [452, 404, 1, 1], [452, 413, 1, 1], [454, 184, 1, 1], [454, 416, 1, 1], [455, 182, 1, 1], [455, 418, 1, 1], [457, 176, 1, 1], [457, 424, 1, 1], [459, 180, 1, 1], [459, 203, 1, 1], [459, 397, 1, 1], [459, 420, 1, 1], [460, 179, 1, 1], [460, 181, 1, 1], [460, 419, 1, 1], [460, 421, 1, 1], [462, 183, 1, 1], [462, 417, 1, 1], [464, 203, 1, 1], [464, 397, 1, 1], [465, 185, 1, 1], [465, 415, 1, 1], [469, 182, 1, 1], [469, 184, 1, 1], [469, 416, 1, 1], [469, 418, 1, 1], [470, 190, 1, 1], [470, 199, 1, 1], [470, 401, 1, 1], [470, 410, 1, 1], [471, 181, 1, 1], [471, 196, 1, 2], [471, 403, 1, 2], [471, 419, 1, 1], [472, 189, 1, 2], [472, 286, 1, 1], [472, 314, 1, 1], [472, 410, 1, 2], [474, 183, 1, 1], [474, 189, 1, 2], [474, 410, 1, 2], [474, 417, 1, 1], [475, 231, 1, 1], [475, 369, 1, 1], [476, 179, 1, 1], [476, 196, 1, 1], [476, 199, 1, 1], [476, 215, 1, 1], [476, 385, 1, 1], [476, 401, 1, 1], [476, 404, 1, 1], [476, 421, 1, 1], [477, 178, 1, 1], [477, 181, 1, 2], [477, 418, 1, 2], [477, 422, 1, 1], [478, 242, 1, 1], [478, 358, 1, 1], [479, 227, 1, 1], [479, 248, 1, 1], [479, 352, 1, 1], [479, 373, 1, 1], [480, 239, 1, 1], [480, 361, 1, 1], [481, 269, 1, 1], [481, 331, 1, 1], [482, 260, 1, 1], [482, 271, 1, 1], [482, 329, 1, 1], [482, 340, 1, 1], [483, 228, 1, 1], [483, 253, 1, 1], [483, 347, 1, 1], [483, 372, 1, 1], [484, 229, 1, 1], [484, 236, 1, 1], [484, 364, 1, 1], [484, 371, 1, 1], [485, 234, 1, 1], [485, 238, 1, 2], [485, 361, 1, 2], [485, 366, 1, 1], [486, 234, 1, 1], [486, 366, 1, 1], [487, 231, 1, 1], [487, 369, 1, 1], [488, 259, 1, 1], [488, 341, 1, 1], [489, 231, 1, 1], [489, 369, 1, 1], [490, 254, 1, 1], [490, 346, 1, 1], [491, 234, 1, 1], [491, 366, 1, 1], [492, 226, 1, 1], [492, 374, 1, 1], [495, 223, 1, 2], [495, 376, 1, 2]], [[21, 300, 1, 1], [22, 300, 1, 1], [23, 300, 1, 1], [24, 300, 1, 1], [25, 300, 1, 1], [27, 300, 1, 1], [136, 296, 1, 1], [136, 304, 1, 1], [141, 296, 1, 1], [141, 304, 1, 1], [143, 286, 1, 1], [143, 292, 1, 1], [143, 308, 1, 1], [143, 314, 1, 1], [150, 284, 1, 1], [150, 316, 1, 1], [159, 287, 1, 1], [159, 313, 1, 1], [161, 275, 1, 1], [161, 325, 1, 1], [163, 282, 1, 1], [163, 293, 1, 1], [163, 307, 1, 1], [163, 318, 1, 1], [165, 274, 1, 1], [165, 283, 1, 1], [165, 317, 1, 1], [165, 326, 1, 1], [166, 276, 1, 1], [166, 324, 1, 1], [171, 236, 1, 1], [171, 364, 1, 1], [177, 256, 1, 1], [177, 265, 1, 1], [177, 335, 1, 1], [177, 344, 1, 1], [182, 240, 1, 1], [182, 245, 1, 1], [182, 258, 1, 1], [182, 342, 1, 1], [182, 355, 1, 1], [182, 360, 1, 1], [183, 244, 1, 1], [183, 356, 1, 1], [185, 245, 1, 1], [185, 355, 1, 1], [192, 254, 1, 1], [192, 346, 1, 1], [200, 251, 1, 1], [200, 349, 1, 1], [201, 246, 1, 1], [201, 354, 1, 1], [209, 243, 1, 1], [209, 248, 1, 1], [209, 352, 1, 1], [209, 357, 1, 1], [211, 238, 1, 1], [211, 362, 1, 1], [212, 242, 1, 1], [212, 358, 1, 1], [214, 238, 1, 1], [214, 362, 1, 1], [216, 240, 1, 1], [216, 360, 1, 1], [217, 239, 1, 1], [217, 361, 1, 1], [218, 249, 1, 1], [218, 351, 1, 1], [221, 248, 1, 1], [221, 352, 1, 1], [225, 239, 1, 1], [225, 361, 1, 1], [228, 238, 1, 1], [228, 362, 1, 1], [229, 243, 1, 1], [229, 357, 1, 1], [230, 237, 1, 1], [230, 363, 1, 1], [231, 247, 1, 1], [231, 353, 1, 1], [239, 251, 1, 1], [239, 349, 1, 1], [240, 254, 1, 1], [240, 256, 1, 1], [240, 344, 1, 1], [240, 346, 1, 1], [241, 257, 1, 1], [241, 343, 1, 1], [245, 256, 1, 1], [245, 344, 1, 1], [246, 259, 1, 1], [246, 341, 1, 1], [253, 269, 1, 1], [253, 331, 1, 1], [261, 287, 1, 1], [261, 313, 1, 1], [263, 274, 1, 1], [263, 326, 1, 1], [264, 244, 1, 1], [264, 269, 1, 1], [264, 331, 1, 1], [264, 356, 1, 1], [265, 253, 1, 1], [265, 257, 1, 1], [265, 343, 1, 1], [265, 347, 1, 1], [266, 249, 1, 1], [266, 260, 1, 1], [266, 340, 1, 1], [266, 351, 1, 1], [267, 231, 1, 1], [267, 369, 1, 1], [268, 255, 1, 1], [268, 345, 1, 1], [269, 230, 1, 1], [269, 370, 1, 1], [270, 242, 1, 1], [270, 358, 1, 1], [271, 227, 1, 1], [271, 373, 1, 1], [274, 224, 1, 1], [274, 376, 1, 1], [275, 206, 1, 1], [275, 229, 1, 1], [275, 371, 1, 1], [275, 394, 1, 1], [277, 206, 1, 1], [277, 208, 1, 1], [277, 229, 1, 1], [277, 371, 1, 1], [277, 392, 1, 1], [277, 394, 1, 1], [279, 200, 1, 1], [279, 217, 1, 1], [279, 383, 1, 1], [279, 400, 1, 1], [281, 203, 1, 1], [281, 397, 1, 1], [283, 200, 1, 1], [283, 400, 1, 1], [288, 207, 1, 1], [288, 393, 1, 1], [292, 169, 1, 1], [292, 431, 1, 1], [293, 203, 1, 1], [293, 397, 1, 1], [294, 175, 1, 1], [294, 425, 1, 1], [295, 209, 1, 1], [295, 391, 1, 1], [299, 184, 1, 1], [299, 416, 1, 1], [300, 170, 1, 1], [300, 194, 1, 1], [300, 202, 1, 1], [300, 398, 1, 1], [300, 406, 1, 1], [300, 430, 1, 1], [301, 184, 1, 1], [301, 416, 1, 1], [309, 196, 1, 1], [309, 404, 1, 1], [317, 187, 1, 1], [317, 413, 1, 1], [324, 184, 1, 1], [324, 416, 1, 1], [328, 179, 1, 1], [328, 421, 1, 1], [334, 172, 1, 1], [334, 428, 1, 1], [340, 174, 1, 1], [340, 426, 1, 1], [341, 175, 1, 1], [341, 425, 1, 1], [348, 168, 1, 1], [348, 432, 1, 1], [351, 168, 1, 1], [351, 432, 1, 1], [354, 170, 1, 1], [354, 430, 1, 1], [358, 149, 1, 1], [358, 451, 1, 1], [359, 149, 1, 1], [359, 451, 1, 1], [361, 134, 1, 1], [361, 466, 1, 1], [362, 130, 1, 1], [362, 136, 1, 1], [362, 169, 1, 1], [362, 431, 1, 1], [362, 464, 1, 1], [362, 470, 1, 1], [363, 155, 1, 1], [363, 445, 1, 1], [365, 143, 1, 1], [365, 169, 1, 1], [365, 431, 1, 1], [365, 457, 1, 1], [366, 163, 1, 1], [366, 437, 1, 1], [375, 132, 1, 2], [375, 467, 1, 2], [378, 129, 1, 1], [378, 471, 1, 1], [382, 123, 1, 1], [382, 477, 1, 1], [386, 121, 1, 1], [386, 479, 1, 1], [387, 121, 1, 1], [387, 479, 1, 1], [388, 124, 1, 1], [388, 476, 1, 1], [389, 116, 1, 1], [389, 484, 1, 1], [391, 128, 1, 1], [391, 472, 1, 1], [392, 125, 1, 1], [392, 128, 1, 1], [392, 472, 1, 1], [392, 475, 1, 1], [393, 134, 1, 1], [393, 466, 1, 1], [397, 130, 1, 1], [397, 470, 1, 1], [401, 162, 1, 1], [401, 438, 1, 1], [402, 140, 1, 1], [402, 147, 1, 1], [402, 161, 1, 1], [402, 439, 1, 1], [402, 453, 1, 1], [402, 460, 1, 1], [404, 140, 1, 1], [404, 460, 1, 1], [406, 138, 1, 1], [406, 462, 1, 1], [408, 152, 1, 1], [408, 448, 1, 1], [409, 152, 1, 1], [409, 448, 1, 1], [416, 168, 1, 2], [416, 431, 1, 2], [418, 172, 1, 1], [418, 428, 1, 1], [421, 171, 1, 1], [421, 429, 1, 1], [426, 179, 1, 1], [426, 421, 1, 1], [427, 175, 1, 1], [427, 425, 1, 1], [430, 172, 1, 1], [430, 428, 1, 1], [432, 182, 1, 1], [432, 418, 1, 1], [433, 168, 1, 1], [433, 171, 1, 1], [433, 429, 1, 1], [433, 432, 1, 1], [436, 177, 1, 1], [436, 179, 1, 1], [436, 421, 1, 1], [436, 423, 1, 1], [440, 181, 1, 1], [440, 419, 1, 1], [442, 184, 1, 1], [442, 416, 1, 1], [443, 189, 1, 1], [443, 411, 1, 1], [446, 189, 1, 1], [446, 411, 1, 1], [455, 183, 1, 1], [455, 417, 1, 1], [458, 182, 1, 2], [458, 417, 1, 2], [459, 181, 1, 1], [459, 419, 1, 1], [460, 180, 1, 1], [460, 420, 1, 1], [461, 184, 1, 1], [461, 416, 1, 1], [462, 179, 1, 1], [462, 297, 1, 1], [462, 303, 1, 1], [462, 421, 1, 1], [466, 294, 1, 1], [466, 306, 1, 1], [467, 214, 1, 1], [467, 386, 1, 1], [469, 202, 1, 1], [469, 210, 1, 1], [469, 390, 1, 1], [469, 398, 1, 1], [470, 195, 1, 1], [470, 220, 1, 1], [470, 380, 1, 1], [470, 405, 1, 1], [472, 188, 1, 1], [472, 197, 1, 1], [472, 403, 1, 1], [472, 412, 1, 1], [473, 198, 1, 1], [473, 217, 1, 1], [473, 383, 1, 1], [473, 402, 1, 1], [474, 215, 1, 1], [474, 385, 1, 1], [475, 216, 1, 1], [475, 384, 1, 1], [476, 180, 1, 1], [476, 420, 1, 1], [477, 174, 1, 1], [477, 237, 1, 1], [477, 363, 1, 1], [477, 426, 1, 1], [481, 222, 1, 1], [481, 378, 1, 1], [482, 224, 1, 1], [482, 246, 1, 1], [482, 252, 1, 1], [482, 268, 1, 1], [482, 332, 1, 1], [482, 348, 1, 1], [482, 354, 1, 1], [482, 376, 1, 1], [483, 273, 1, 1], [483, 327, 1, 1], [484, 228, 1, 1], [484, 238, 1, 1], [484, 362, 1, 1], [484, 372, 1, 1], [485, 253, 1, 1], [485, 347, 1, 1], [487, 229, 1, 1], [487, 371, 1, 1], [489, 260, 1, 1], [489, 340, 1, 1], [491, 231, 1, 1], [491, 236, 1, 1], [491, 260, 1, 1], [491, 340, 1, 1], [491, 364, 1, 1], [491, 369, 1, 1]], [[28, 300, 1, 1], [29, 300, 1, 1], [31, 300, 1, 1], [32, 300, 1, 1], [33, 300, 1, 1], [34, 300, 1, 1], [35, 300, 1, 1], [37, 300, 1, 1], [38, 300, 1, 1], [39, 300, 1, 1], [40, 300, 1, 1], [43, 300, 1, 1], [138, 297, 1, 1], [138, 303, 1, 1], [149, 288, 1, 1], [149, 312, 1, 1], [151, 283, 1, 1], [151, 287, 1, 1], [151, 313, 1, 1], [151, 317, 1, 1], [152, 286, 1, 1], [152, 314, 1, 1], [164, 294, 1, 1], [164, 306, 1, 1], [170, 271, 1, 1], [170, 329, 1, 1], [172, 252, 1, 1], [172, 265, 1, 1], [172, 335, 1, 1], [172, 348, 1, 1], [178, 249, 1, 1], [178, 351, 1, 1], [180, 255, 1, 1], [180, 345, 1, 1], [182, 248, 1, 1], [182, 352, 1, 1], [185, 258, 1, 1], [185, 342, 1, 1], [190, 245, 1, 1], [190, 355, 1, 1], [192, 248, 1, 1], [192, 352, 1, 1], [201, 248, 1, 1], [201, 352, 1, 1], [202, 246, 1, 1], [202, 354, 1, 1], [206, 244, 1, 1], [206, 356, 1, 1], [210, 244, 1, 1], [210, 356, 1, 1], [215, 244, 1, 1], [215, 356, 1, 1], [239, 257, 1, 1], [239, 343, 1, 1], [247, 263, 1, 1], [247, 337, 1, 1], [252, 264, 1, 1], [252, 336, 1, 1], [254, 270, 1, 1], [254, 330, 1, 1], [257, 275, 1, 1], [257, 325, 1, 1], [261, 288, 1, 1], [261, 312, 1, 1], [263, 272, 1, 1], [263, 328, 1, 1], [265, 249, 1, 1], [265, 259, 1, 1], [265, 266, 1, 1], [265, 334, 1, 1], [265, 341, 1, 1], [265, 351, 1, 1], [266, 242, 1, 1], [266, 262, 1, 1], [266, 338, 1, 1], [266, 358, 1, 1], [267, 257, 1, 1], [267, 343, 1, 1], [268, 230, 1, 1], [268, 241, 1, 1], [268, 359, 1, 1], [268, 370, 1, 1], [269, 228, 1, 1], [269, 372, 1, 1], [270, 229, 1, 3], [270, 246, 1, 1], [270, 354, 1, 1], [270, 369, 1, 3], [272, 226, 1, 1], [272, 230, 1, 1], [272, 370, 1, 1], [272, 374, 1, 1], [273, 227, 1, 1], [273, 373, 1, 1], [275, 228, 1, 1], [275, 372, 1, 1], [276, 211, 1, 1], [276, 389, 1, 1], [280, 212, 1, 1], [280, 388, 1, 1], [281, 202, 1, 1], [281, 210, 1, 1], [281, 390, 1, 1], [281, 398, 1, 1], [282, 219, 1, 1], [282, 381, 1, 1], [284, 222, 1, 1], [284, 378, 1, 1], [285, 210, 1, 1], [285, 390, 1, 1], [287, 207, 1, 1], [287, 393, 1, 1], [293, 189, 1, 1], [293, 411, 1, 1], [294, 185, 1, 1], [294, 415, 1, 1], [295, 202, 1, 1], [295, 204, 1, 1], [295, 396, 1, 1], [295, 398, 1, 1], [298, 180, 1, 1], [298, 420, 1, 1], [299, 176, 1, 1], [299, 424, 1, 1], [300, 185, 1, 1], [300, 187, 1, 1], [300, 413, 1, 1], [300, 415, 1, 1], [308, 179, 1, 1], [308, 421, 1, 1], [311, 174, 1, 1], [311, 426, 1, 1], [317, 181, 1, 2], [317, 418, 1, 2], [318, 181, 1, 1], [318, 419, 1, 1], [322, 187, 1, 1], [322, 413, 1, 1], [327, 180, 1, 1], [327, 420, 1, 1], [328, 181, 1, 1], [328, 419, 1, 1], [331, 165, 1, 1], [331, 175, 1, 1], [331, 425, 1, 1], [331, 435, 1, 1], [332, 170, 1, 1], [332, 430, 1, 1], [336, 166, 1, 1], [336, 171, 1, 1], [336, 429, 1, 1], [336, 434, 1, 1], [337, 168, 1, 1], [337, 432, 1, 1], [342, 177, 1, 1], [342, 423, 1, 1], [348, 175, 1, 1], [348, 425, 1, 1], [356, 170, 1, 1], [356, 430, 1, 1], [360, 151, 1, 1], [360, 155, 1, 1], [360, 445, 1, 1], [360, 449, 1, 1], [361, 135, 1, 1], [361, 465, 1, 1], [362, 148, 1, 1], [362, 452, 1, 1], [363, 140, 1, 1], [363, 460, 1, 1], [365, 159, 1, 1], [365, 441, 1, 1], [371, 167, 1, 1], [371, 433, 1, 1], [373, 132, 1, 1], [373, 468, 1, 1], [378, 122, 1, 1], [378, 478, 1, 1], [380, 99, 1, 1], [380, 501, 1, 1], [384, 121, 1, 1], [384, 479, 1, 1], [387, 118, 1, 1], [387, 482, 1, 1], [391, 124, 1, 1], [391, 134, 1, 1], [391, 466, 1, 1], [391, 476, 1, 1], [393, 122, 1, 1], [393, 478, 1, 1], [395, 166, 1, 1], [395, 434, 1, 1], [398, 162, 1, 1], [398, 438, 1, 1], [399, 170, 1, 1], [399, 430, 1, 1], [404, 152, 1, 1], [404, 448, 1, 1], [405, 141, 1, 1], [405, 153, 1, 1], [405, 156, 1, 1], [405, 444, 1, 1], [405, 447, 1, 1], [405, 459, 1, 1], [406, 151, 1, 1], [406, 449, 1, 1], [409, 135, 1, 1], [409, 465, 1, 1], [410, 168, 1, 1], [410, 432, 1, 1], [418, 171, 1, 1], [418, 429, 1, 1], [427, 174, 1, 1], [427, 426, 1, 1], [432, 169, 1, 1], [432, 431, 1, 1], [433, 175, 1, 1], [433, 425, 1, 1], [435, 177, 1, 1], [435, 423, 1, 1], [442, 182, 1, 1], [442, 418, 1, 1], [448, 191, 1, 1], [448, 409, 1, 1], [453, 188, 1, 1], [453, 412, 1, 1], [458, 184, 1, 2], [458, 415, 1, 2], [461, 177, 1, 1], [461, 183, 1, 1], [461, 417, 1, 1], [461, 423, 1, 1], [464, 184, 1, 1], [464, 416, 1, 1], [465, 203, 1, 1], [465, 397, 1, 1], [466, 186, 1, 1], [466, 414, 1, 1], [467, 180, 1, 1], [467, 420, 1, 1], [468, 202, 1, 1], [468, 210, 1, 1], [468, 390, 1, 1], [468, 398, 1, 1], [469, 183, 1, 1], [469, 293, 1, 1], [469, 307, 1, 1], [469, 417, 1, 1], [472, 185, 1, 1], [472, 187, 1, 1], [472, 199, 1, 1], [472, 290, 1, 1], [472, 310, 1, 1], [472, 401, 1, 1], [472, 413, 1, 1], [472, 415, 1, 1], [473, 188, 1, 1], [473, 412, 1, 1], [474, 184, 1, 1], [474, 283, 1, 1], [474, 317, 1, 1], [474, 416, 1, 1], [477, 278, 1, 1], [477, 322, 1, 1], [478, 226, 1, 1], [478, 374, 1, 1], [482, 226, 1, 1], [482, 239, 1, 1], [482, 247, 1, 1], [482, 274, 1, 1], [482, 326, 1, 1], [482, 353, 1, 1], [482, 361, 1, 1], [482, 374, 1, 1], [484, 188, 1, 1], [484, 273, 1, 1], [484, 327, 1, 1], [484, 412, 1, 1], [489, 232, 1, 1], [489, 368, 1, 1], [492, 224, 1, 1], [492, 376, 1, 1]], [[26, 300, 1, 1], [30, 300, 1, 1], [36, 300, 1, 1], [42, 300, 1, 1], [47, 300, 1, 1], [49, 300, 1, 1], [53, 300, 1, 1], [56, 300, 1, 1], [136, 298, 1, 1], [136, 302, 1, 1], [140, 297, 1, 1], [140, 303, 1, 1], [142, 286, 1, 1], [142, 314, 1, 1], [144, 286, 1, 1], [144, 292, 1, 1], [144, 308, 1, 1], [144, 314, 1, 1], [145, 287, 1, 1], [145, 313, 1, 1], [146, 287, 1, 1], [146, 313, 1, 1], [153, 286, 1, 1], [153, 314, 1, 1], [155, 287, 1, 1], [155, 313, 1, 1], [156, 286, 1, 1], [156, 314, 1, 1], [166, 266, 1, 1], [166, 334, 1, 1], [169, 268, 1, 1], [169, 332, 1, 1], [171, 267, 1, 1], [171, 333, 1, 1], [172, 272, 1, 1], [172, 328, 1, 1], [174, 267, 1, 1], [174, 333, 1, 1], [179, 255, 1, 1], [179, 345, 1, 1], [186, 246, 1, 1], [186, 354, 1, 1], [189, 244, 1, 1], [189, 356, 1, 1], [190, 246, 1, 1], [190, 354, 1, 1], [199, 244, 1, 1], [199, 356, 1, 1], [209, 236, 1, 1], [209, 364, 1, 1], [215, 240, 1, 1], [215, 360, 1, 1], [221, 249, 1, 1], [221, 351, 1, 1], [233, 253, 1, 1], [233, 347, 1, 1], [237, 253, 1, 1], [237, 347, 1, 1], [245, 258, 1, 1], [245, 342, 1, 1], [246, 260, 1, 1], [246, 340, 1, 1], [253, 271, 1, 1], [253, 329, 1, 1], [261, 289, 1, 1], [261, 311, 1, 1], [263, 252, 1, 1], [263, 348, 1, 1], [266, 248, 1, 1], [266, 352, 1, 1], [268, 242, 1, 1], [268, 358, 1, 1], [271, 228, 1, 1], [271, 372, 1, 1], [273, 207, 1, 1], [273, 225, 1, 1], [273, 375, 1, 1], [273, 393, 1, 1], [275, 209, 1, 1], [275, 391, 1, 1], [276, 237, 1, 1], [276, 363, 1, 1], [277, 207, 1, 1], [277, 393, 1, 1], [279, 206, 1, 1], [279, 219, 1, 1], [279, 231, 1, 1], [279, 369, 1, 1], [279, 381, 1, 1], [279, 394, 1, 1], [280, 218, 1, 1], [280, 382, 1, 1], [281, 204, 1, 1], [281, 217, 1, 1], [281, 383, 1, 1], [281, 396, 1, 1], [282, 210, 1, 1], [282, 218, 1, 1], [282, 382, 1, 1], [282, 390, 1, 1], [286, 207, 1, 1], [286, 393, 1, 1], [291, 167, 1, 1], [291, 433, 1, 1], [292, 168, 1, 1], [292, 432, 1, 1], [293, 177, 1, 1], [293, 423, 1, 1], [294, 189, 1, 1], [294, 411, 1, 1], [296, 190, 1, 1], [296, 202, 1, 1], [296, 398, 1, 1], [296, 410, 1, 1], [300, 176, 1, 1], [300, 424, 1, 1], [303, 177, 1, 1], [303, 423, 1, 1], [305, 195, 1, 1], [305, 405, 1, 1], [312, 175, 1, 1], [312, 425, 1, 1], [316, 191, 1, 1], [316, 409, 1, 1], [317, 186, 1, 1], [317, 414, 1, 1], [326, 181, 1, 1], [326, 419, 1, 1], [327, 178, 1, 1], [327, 422, 1, 1], [331, 177, 1, 1], [331, 423, 1, 1], [332, 168, 1, 1], [332, 175, 1, 1], [332, 425, 1, 1], [332, 432, 1, 1], [334, 174, 1, 1], [334, 426, 1, 1], [340, 178, 1, 1], [340, 422, 1, 1], [345, 175, 1, 1], [345, 425, 1, 1], [347, 173, 1, 1], [347, 427, 1, 1], [349, 167, 1, 1], [349, 433, 1, 1], [357, 170, 1, 1], [357, 430, 1, 1], [360, 154, 1, 1], [360, 156, 1, 1], [360, 170, 1, 1], [360, 430, 1, 1], [360, 444, 1, 1], [360, 446, 1, 1], [362, 144, 1, 1], [362, 456, 1, 1], [363, 148, 1, 1], [363, 452, 1, 1], [365, 164, 1, 1], [365, 436, 1, 1], [366, 161, 1, 1], [366, 439, 1, 1], [368, 138, 1, 1], [368, 165, 1, 1], [368, 435, 1, 1], [368, 462, 1, 1], [371, 130, 1, 1], [371, 470, 1, 1], [372, 131, 1, 1], [372, 469, 1, 1], [379, 130, 1, 1], [379, 470, 1, 1], [386, 117, 1, 1], [386, 483, 1, 1], [389, 123, 1, 1], [389, 477, 1, 1], [399, 160, 1, 1], [399, 440, 1, 1], [401, 159, 1, 1], [401, 441, 1, 1], [402, 144, 1, 1], [402, 158, 1, 1], [402, 442, 1, 1], [402, 456, 1, 1], [403, 151, 1, 1], [403, 449, 1, 1], [414, 172, 1, 1], [414, 428, 1, 1], [434, 169, 1, 1], [434, 431, 1, 1], [440, 182, 1, 1], [440, 418, 1, 1], [441, 187, 1, 1], [441, 413, 1, 1], [462, 203, 1, 1], [462, 397, 1, 1], [466, 203, 1, 1], [466, 211, 1, 1], [466, 389, 1, 1], [466, 397, 1, 1], [467, 184, 1, 1], [467, 416, 1, 1], [469, 212, 1, 1], [469, 388, 1, 1], [471, 194, 1, 1], [471, 406, 1, 1], [472, 192, 1, 1], [472, 408, 1, 1], [473, 182, 1, 1], [473, 184, 1, 1], [473, 216, 1, 1], [473, 384, 1, 1], [473, 416, 1, 1], [473, 418, 1, 1], [474, 226, 1, 1], [474, 374, 1, 1], [475, 215, 1, 1], [475, 223, 1, 1], [475, 377, 1, 1], [475, 385, 1, 1], [476, 163, 1, 1], [476, 437, 1, 1], [478, 181, 1, 1], [478, 282, 1, 1], [478, 318, 1, 1], [478, 419, 1, 1], [480, 250, 1, 1], [480, 350, 1, 1], [482, 253, 1, 1], [482, 347, 1, 1], [484, 253, 1, 1], [484, 347, 1, 1], [485, 252, 1, 1], [485, 348, 1, 1], [490, 258, 1, 1], [490, 342, 1, 1], [491, 225, 1, 1], [491, 375, 1, 1], [492, 232, 1, 1], [492, 368, 1, 1]], [[41, 300, 1, 1], [44, 300, 1, 1], [45, 300, 1, 1], [48, 300, 1, 1], [51, 300, 1, 1], [54, 300, 1, 1], [72, 300, 1, 1], [144, 289, 1, 1], [144, 311, 1, 1], [145, 290, 1, 1], [145, 310, 1, 1], [147, 286, 1, 2], [147, 313, 1, 2], [156, 285, 1, 1], [156, 287, 1, 1], [156, 313, 1, 1], [156, 315, 1, 1], [164, 282, 1, 1], [164, 295, 1, 1], [164, 305, 1, 1], [164, 318, 1, 1], [165, 287, 1, 1], [165, 289, 1, 1], [165, 311, 1, 1], [165, 313, 1, 1], [169, 265, 1, 1], [169, 272, 1, 1], [169, 328, 1, 1], [169, 335, 1, 1], [171, 274, 1, 1], [171, 326, 1, 1], [173, 267, 1, 1], [173, 333, 1, 1], [176, 262, 1, 1], [176, 338, 1, 1], [178, 262, 1, 1], [178, 338, 1, 1], [180, 250, 1, 1], [180, 350, 1, 1], [181, 256, 1, 1], [181, 344, 1, 1], [182, 247, 1, 1], [182, 353, 1, 1], [183, 260, 1, 1], [183, 340, 1, 1], [192, 243, 1, 1], [192, 252, 1, 1], [192, 348, 1, 1], [192, 357, 1, 1], [208, 244, 1, 1], [208, 356, 1, 1], [211, 244, 1, 1], [211, 356, 1, 1], [214, 241, 1, 2], [214, 358, 1, 2], [217, 245, 1, 1], [217, 355, 1, 1], [230, 247, 1, 1], [230, 353, 1, 1], [231, 250, 1, 1], [231, 253, 1, 1], [231, 347, 1, 1], [231, 350, 1, 1], [239, 252, 1, 1], [239, 348, 1, 1], [240, 258, 1, 1], [240, 342, 1, 1], [245, 257, 1, 1], [245, 260, 1, 1], [245, 340, 1, 1], [245, 343, 1, 1], [249, 259, 1, 1], [249, 341, 1, 1], [252, 269, 1, 1], [252, 331, 1, 1], [253, 268, 1, 1], [253, 332, 1, 1], [258, 280, 1, 1], [258, 320, 1, 1], [261, 290, 1, 1], [261, 310, 1, 1], [262, 278, 1, 1], [262, 322, 1, 1], [264, 252, 1, 1], [264, 348, 1, 1], [268, 233, 1, 1], [268, 240, 1, 1], [268, 360, 1, 1], [268, 367, 1, 1], [271, 241, 1, 1], [271, 247, 1, 1], [271, 353, 1, 1], [271, 359, 1, 1], [273, 234, 1, 1], [273, 366, 1, 1], [275, 215, 1, 1], [275, 385, 1, 1], [277, 205, 1, 1], [277, 395, 1, 1], [279, 216, 1, 1], [279, 224, 1, 1], [279, 376, 1, 1], [279, 384, 1, 1], [282, 220, 1, 1], [282, 380, 1, 1], [284, 220, 1, 1], [284, 380, 1, 1], [287, 209, 1, 1], [287, 391, 1, 1], [294, 203, 1, 1], [294, 397, 1, 1], [295, 185, 1, 1], [295, 415, 1, 1], [296, 187, 1, 2], [296, 412, 1, 2], [297, 189, 1, 1], [297, 411, 1, 1], [298, 172, 1, 1], [298, 188, 1, 1], [298, 190, 1, 1], [298, 410, 1, 1], [298, 412, 1, 1], [298, 428, 1, 1], [299, 171, 1, 1], [299, 429, 1, 1], [300, 175, 1, 1], [300, 177, 1, 1], [300, 200, 1, 1], [300, 400, 1, 1], [300, 423, 1, 1], [300, 425, 1, 1], [301, 176, 1, 1], [301, 424, 1, 1], [304, 176, 1, 1], [304, 424, 1, 1], [305, 174, 1, 2], [305, 177, 1, 1], [305, 423, 1, 1], [305, 425, 1, 2], [313, 174, 1, 2], [313, 425, 1, 2], [316, 182, 1, 1], [316, 418, 1, 1], [320, 188, 1, 1], [320, 412, 1, 1], [325, 179, 1, 1], [325, 421, 1, 1], [328, 171, 1, 1], [328, 429, 1, 1], [330, 181, 1, 1], [330, 419, 1, 1], [331, 182, 1, 1], [331, 418, 1, 1], [334, 173, 1, 1], [334, 427, 1, 1], [350, 171, 1, 1], [350, 429, 1, 1], [359, 154, 1, 1], [359, 446, 1, 1], [361, 149, 1, 1], [361, 152, 1, 1], [361, 448, 1, 1], [361, 451, 1, 1], [362, 157, 1, 1], [362, 443, 1, 1], [363, 145, 1, 1], [363, 455, 1, 1], [369, 137, 1, 1], [369, 166, 1, 1], [369, 434, 1, 1], [369, 463, 1, 1], [370, 167, 1, 1], [370, 433, 1, 1], [371, 132, 1, 1], [371, 468, 1, 1], [372, 135, 1, 1], [372, 465, 1, 1], [380, 124, 1, 1], [380, 132, 1, 1], [380, 468, 1, 1], [380, 476, 1, 1], [381, 124, 1, 1], [381, 132, 1, 1], [381, 468, 1, 1], [381, 476, 1, 1], [393, 167, 1, 1], [393, 433, 1, 1], [397, 139, 1, 1], [397, 170, 1, 1], [397, 430, 1, 1], [397, 461, 1, 1], [401, 144, 1, 1], [401, 146, 1, 1], [401, 150, 1, 1], [401, 450, 1, 1], [401, 454, 1, 1], [401, 456, 1, 1], [402, 155, 1, 1], [402, 445, 1, 1], [403, 140, 1, 1], [403, 143, 1, 1], [403, 457, 1, 1], [403, 460, 1, 1], [406, 135, 1, 1], [406, 465, 1, 1], [434, 180, 1, 1], [434, 420, 1, 1], [437, 176, 1, 1], [437, 424, 1, 1], [445, 188, 1, 1], [445, 190, 1, 1], [445, 410, 1, 1], [445, 412, 1, 1], [451, 192, 1, 1], [451, 408, 1, 1], [452, 193, 1, 1], [452, 407, 1, 1], [461, 203, 1, 1], [461, 397, 1, 1], [463, 179, 1, 1], [463, 297, 1, 1], [463, 303, 1, 1], [463, 421, 1, 1], [475, 218, 1, 1], [475, 232, 1, 1], [475, 368, 1, 1], [475, 382, 1, 1], [476, 172, 1, 1], [476, 428, 1, 1], [478, 276, 1, 1], [478, 324, 1, 1], [480, 273, 1, 1], [480, 327, 1, 1], [481, 247, 1, 1], [481, 273, 1, 1], [481, 327, 1, 1], [481, 353, 1, 1], [483, 245, 1, 1], [483, 247, 1, 1], [483, 353, 1, 1], [483, 355, 1, 1], [486, 258, 1, 2], [486, 341, 1, 2], [487, 234, 1, 1], [487, 366, 1, 1], [488, 234, 1, 1], [488, 366, 1, 1], [489, 261, 1, 1], [489, 339, 1, 1]], [[46, 300, 1, 1], [50, 300, 1, 1], [52, 300, 1, 1], [55, 300, 1, 1], [57, 300, 1, 1], [58, 300, 1, 1], [68, 298, 1, 1], [68, 302, 1, 1], [76, 300, 1, 1], [77, 300, 1, 1], [80, 300, 1, 1], [137, 298, 1, 1], [137, 302, 1, 1], [145, 286, 1, 1], [145, 314, 1, 1], [153, 284, 1, 1], [153, 316, 1, 1], [162, 291, 1, 1], [162, 309, 1, 1], [165, 290, 1, 1], [165, 310, 1, 1], [166, 278, 1, 1], [166, 322, 1, 1], [177, 262, 1, 1], [177, 338, 1, 1], [182, 261, 1, 1], [182, 339, 1, 1], [186, 258, 1, 1], [186, 342, 1, 1], [190, 248, 1, 1], [190, 352, 1, 1], [196, 252, 1, 1], [196, 348, 1, 1], [198, 251, 1, 1], [198, 349, 1, 1], [201, 249, 1, 1], [201, 351, 1, 1], [205, 250, 1, 1], [205, 350, 1, 1], [226, 251, 1, 1], [226, 349, 1, 1], [228, 243, 1, 1], [228, 357, 1, 1], [231, 248, 1, 1], [231, 251, 1, 1], [231, 349, 1, 1], [231, 352, 1, 1], [235, 255, 1, 1], [235, 345, 1, 1], [248, 263, 1, 1], [248, 337, 1, 1], [249, 261, 1, 2], [249, 265, 1, 1], [249, 335, 1, 1], [249, 338, 1, 2], [259, 282, 1, 1], [259, 318, 1, 1], [261, 291, 1, 1], [261, 309, 1, 1], [262, 267, 1, 1], [262, 333, 1, 1], [265, 258, 1, 1], [265, 342, 1, 1], [267, 239, 1, 1], [267, 361, 1, 1], [270, 248, 1, 1], [270, 352, 1, 1], [274, 238, 1, 1], [274, 362, 1, 1], [276, 213, 1, 1], [276, 387, 1, 1], [279, 225, 1, 1], [279, 375, 1, 1], [281, 224, 1, 1], [281, 376, 1, 1], [285, 221, 1, 1], [285, 379, 1, 1], [294, 211, 1, 1], [294, 389, 1, 1], [301, 177, 1, 1], [301, 423, 1, 1], [303, 200, 1, 1], [303, 400, 1, 1], [304, 177, 1, 1], [304, 423, 1, 1], [314, 175, 1, 1], [314, 179, 1, 1], [314, 421, 1, 1], [314, 425, 1, 1], [323, 184, 1, 1], [323, 416, 1, 1], [325, 181, 1, 1], [325, 419, 1, 1], [332, 180, 1, 1], [332, 420, 1, 1], [333, 169, 1, 1], [333, 431, 1, 1], [335, 168, 1, 1], [335, 432, 1, 1], [337, 173, 1, 1], [337, 427, 1, 1], [346, 170, 1, 1], [346, 430, 1, 1], [350, 170, 1, 1], [350, 430, 1, 1], [351, 169, 1, 1], [351, 431, 1, 1], [354, 169, 1, 1], [354, 431, 1, 1], [360, 150, 1, 1], [360, 450, 1, 1], [363, 153, 1, 1], [363, 447, 1, 1], [364, 137, 1, 1], [364, 141, 1, 1], [364, 155, 1, 1], [364, 158, 1, 1], [364, 170, 1, 1], [364, 430, 1, 1], [364, 442, 1, 1], [364, 445, 1, 1], [364, 459, 1, 1], [364, 463, 1, 1], [366, 170, 1, 1], [366, 430, 1, 1], [372, 129, 1, 1], [372, 471, 1, 1], [375, 93, 1, 1], [375, 507, 1, 1], [381, 123, 1, 1], [381, 477, 1, 1], [388, 170, 1, 1], [388, 430, 1, 1], [390, 128, 1, 1], [390, 472, 1, 1], [394, 170, 1, 1], [394, 430, 1, 1], [396, 138, 1, 1], [396, 462, 1, 1], [399, 162, 1, 1], [399, 438, 1, 1], [400, 137, 1, 1], [400, 463, 1, 1], [401, 153, 1, 1], [401, 447, 1, 1], [402, 171, 1, 1], [402, 429, 1, 1], [403, 147, 1, 1], [403, 453, 1, 1], [408, 169, 1, 1], [408, 431, 1, 1], [411, 170, 1, 1], [411, 430, 1, 1], [414, 171, 1, 1], [414, 429, 1, 1], [419, 174, 1, 1], [419, 426, 1, 1], [431, 172, 1, 1], [431, 428, 1, 1], [434, 173, 1, 1], [434, 427, 1, 1], [435, 169, 1, 1], [435, 431, 1, 1], [452, 188, 1, 1], [452, 194, 1, 1], [452, 406, 1, 1], [452, 412, 1, 1], [461, 178, 1, 1], [461, 422, 1, 1], [463, 184, 1, 1], [463, 416, 1, 1], [468, 211, 1, 1], [468, 389, 1, 1], [470, 182, 1, 1], [470, 192, 1, 1], [470, 196, 1, 1], [470, 290, 1, 1], [470, 310, 1, 1], [470, 404, 1, 1], [470, 408, 1, 1], [470, 418, 1, 1], [472, 193, 1, 1], [472, 407, 1, 1], [475, 287, 1, 1], [475, 313, 1, 1], [478, 278, 1, 1], [478, 322, 1, 1], [479, 238, 1, 1], [479, 362, 1, 1], [481, 185, 1, 1], [481, 415, 1, 1], [482, 272, 1, 1], [482, 328, 1, 1], [483, 229, 1, 1], [483, 261, 1, 1], [483, 339, 1, 1], [483, 371, 1, 1], [488, 260, 1, 1], [488, 340, 1, 1]], [[59, 300, 1, 1], [69, 300, 1, 1], [70, 300, 1, 1], [71, 300, 1, 1], [74, 300, 1, 1], [89, 300, 1, 1], [136, 299, 1, 1], [136, 301, 1, 1], [148, 289, 1, 1], [148, 311, 1, 1], [151, 288, 1, 1], [151, 312, 1, 1], [165, 265, 1, 1], [165, 335, 1, 1], [172, 264, 1, 1], [172, 266, 1, 1], [172, 334, 1, 1], [172, 336, 1, 1], [180, 241, 1, 1], [180, 359, 1, 1], [189, 246, 1, 1], [189, 354, 1, 1], [191, 255, 1, 1], [191, 345, 1, 1], [192, 251, 1, 1], [192, 349, 1, 1], [193, 254, 1, 1], [193, 346, 1, 1], [195, 253, 1, 1], [195, 347, 1, 1], [203, 247, 1, 1], [203, 353, 1, 1], [213, 242, 1, 1], [213, 358, 1, 1], [214, 239, 1, 1], [214, 361, 1, 1], [218, 248, 1, 1], [218, 352, 1, 1], [220, 249, 1, 1], [220, 351, 1, 1], [248, 260, 1, 1], [248, 340, 1, 1], [255, 270, 1, 1], [255, 272, 1, 1], [255, 328, 1, 1], [255, 330, 1, 1], [262, 279, 1, 1], [262, 321, 1, 1], [264, 263, 1, 1], [264, 271, 1, 1], [264, 329, 1, 1], [264, 337, 1, 1], [266, 243, 1, 1], [266, 250, 1, 1], [266, 350, 1, 1], [266, 357, 1, 1], [267, 256, 1, 1], [267, 344, 1, 1], [272, 235, 1, 1], [272, 246, 1, 1], [272, 354, 1, 1], [272, 365, 1, 1], [273, 235, 1, 1], [273, 365, 1, 1], [280, 211, 1, 1], [280, 389, 1, 1], [281, 205, 1, 1], [281, 395, 1, 1], [283, 211, 1, 1], [283, 223, 1, 1], [283, 377, 1, 1], [283, 389, 1, 1], [284, 224, 1, 1], [284, 376, 1, 1], [288, 208, 1, 1], [288, 392, 1, 1], [299, 204, 1, 1], [299, 396, 1, 1], [300, 181, 1, 1], [300, 193, 1, 1], [300, 407, 1, 1], [300, 419, 1, 1], [301, 169, 1, 1], [301, 179, 1, 1], [301, 181, 1, 1], [301, 187, 1, 1], [301, 413, 1, 1], [301, 419, 1, 1], [301, 421, 1, 1], [301, 431, 1, 1], [302, 201, 1, 1], [302, 399, 1, 1], [303, 193, 1, 1], [303, 195, 1, 1], [303, 405, 1, 1], [303, 407, 1, 1], [306, 177, 1, 1], [306, 423, 1, 1], [310, 179, 1, 1], [310, 421, 1, 1], [311, 178, 1, 2], [311, 421, 1, 2], [332, 177, 1, 1], [332, 423, 1, 1], [336, 168, 1, 1], [336, 432, 1, 1], [337, 172, 1, 1], [337, 428, 1, 1], [359, 156, 1, 1], [359, 444, 1, 1], [361, 170, 1, 1], [361, 430, 1, 1], [364, 146, 1, 1], [364, 169, 1, 1], [364, 431, 1, 1], [364, 454, 1, 1], [365, 170, 1, 1], [365, 430, 1, 1], [366, 135, 1, 2], [366, 464, 1, 2], [367, 133, 1, 1], [367, 467, 1, 1], [372, 168, 1, 1], [372, 432, 1, 1], [377, 170, 1, 1], [377, 430, 1, 1], [379, 127, 1, 1], [379, 473, 1, 1], [387, 132, 1, 1], [387, 468, 1, 1], [395, 134, 1, 1], [395, 466, 1, 1], [397, 165, 1, 1], [397, 435, 1, 1], [401, 154, 1, 1], [401, 446, 1, 1], [404, 153, 1, 1], [404, 156, 1, 1], [404, 444, 1, 1], [404, 447, 1, 1], [430, 169, 1, 1], [430, 431, 1, 1], [436, 182, 1, 1], [436, 418, 1, 1], [442, 180, 1, 1], [442, 420, 1, 1], [443, 185, 1, 1], [443, 415, 1, 1], [446, 187, 1, 1], [446, 413, 1, 1], [457, 202, 1, 1], [457, 398, 1, 1], [460, 203, 1, 1], [460, 397, 1, 1], [464, 208, 1, 1], [464, 392, 1, 1], [467, 212, 1, 1], [467, 388, 1, 1], [470, 194, 1, 1], [470, 406, 1, 1], [471, 185, 1, 1], [471, 415, 1, 1], [472, 219, 1, 1], [472, 381, 1, 1], [473, 214, 1, 1], [473, 386, 1, 1], [478, 241, 1, 1], [478, 359, 1, 1], [479, 269, 1, 1], [479, 331, 1, 1], [480, 238, 1, 1], [480, 362, 1, 1], [484, 261, 1, 1], [484, 339, 1, 1], [486, 237, 1, 1], [486, 254, 1, 1], [486, 346, 1, 1], [486, 363, 1, 1]], [[73, 300, 1, 1], [75, 300, 1, 1], [81, 300, 1, 1], [82, 300, 1, 1], [83, 300, 1, 1], [84, 300, 1, 1], [88, 300, 1, 1], [99, 300, 1, 1], [100, 300, 1, 1], [142, 293, 1, 1], [142, 307, 1, 1], [145, 288, 1, 1], [145, 312, 1, 1], [160, 289, 1, 1], [160, 311, 1, 1], [164, 288, 1, 1], [164, 312, 1, 1], [165, 285, 1, 1], [165, 315, 1, 1], [170, 267, 1, 1], [170, 333, 1, 1], [177, 249, 1, 1], [177, 351, 1, 1], [179, 254, 1, 1], [179, 346, 1, 1], [197, 252, 1, 1], [197, 348, 1, 1], [209, 245, 1, 1], [209, 355, 1, 1], [215, 238, 1, 1], [215, 362, 1, 1], [216, 246, 1, 1], [216, 354, 1, 1], [222, 248, 1, 1], [222, 352, 1, 1], [230, 249, 1, 1], [230, 351, 1, 1], [249, 264, 1, 1], [249, 336, 1, 1], [261, 292, 1, 1], [261, 308, 1, 1], [262, 270, 1, 1], [262, 330, 1, 1], [267, 242, 1, 1], [267, 358, 1, 1], [269, 242, 1, 1], [269, 358, 1, 1], [273, 230, 1, 1], [273, 243, 1, 1], [273, 357, 1, 1], [273, 370, 1, 1], [279, 211, 1, 1], [279, 389, 1, 1], [283, 209, 1, 1], [283, 391, 1, 1], [284, 210, 1, 1], [284, 390, 1, 1], [292, 203, 1, 1], [292, 209, 1, 1], [292, 391, 1, 1], [292, 397, 1, 1], [294, 202, 1, 1], [294, 209, 1, 1], [294, 391, 1, 1], [294, 398, 1, 1], [302, 183, 1, 1], [302, 417, 1, 1], [317, 184, 1, 1], [317, 416, 1, 1], [330, 171, 1, 1], [330, 429, 1, 1], [331, 168, 1, 1], [331, 181, 1, 1], [331, 419, 1, 1], [331, 432, 1, 1], [346, 175, 1, 1], [346, 425, 1, 1], [349, 168, 1, 1], [349, 432, 1, 1], [355, 170, 1, 1], [355, 430, 1, 1], [363, 159, 1, 1], [363, 441, 1, 1], [371, 136, 1, 1], [371, 464, 1, 1], [373, 168, 1, 1], [373, 432, 1, 1], [374, 134, 1, 1], [374, 466, 1, 1], [382, 132, 1, 1], [382, 468, 1, 1], [384, 123, 1, 1], [384, 477, 1, 1], [389, 125, 1, 1], [389, 127, 1, 1], [389, 473, 1, 1], [389, 475, 1, 1], [393, 123, 1, 1], [393, 477, 1, 1], [398, 141, 1, 1], [398, 459, 1, 1], [403, 169, 1, 1], [403, 431, 1, 1], [417, 170, 1, 1], [417, 430, 1, 1], [418, 173, 1, 1], [418, 427, 1, 1], [429, 168, 1, 1], [429, 432, 1, 1], [432, 172, 1, 1], [432, 428, 1, 1], [433, 172, 1, 2], [433, 427, 1, 2], [434, 174, 1, 1], [434, 426, 1, 1], [435, 171, 1, 1], [435, 429, 1, 1], [444, 188, 1, 1], [444, 412, 1, 1], [464, 185, 1, 1], [464, 415, 1, 1], [467, 187, 1, 1], [467, 413, 1, 1], [472, 223, 1, 1], [472, 377, 1, 1], [474, 228, 1, 1], [474, 372, 1, 1], [476, 177, 1, 1], [476, 286, 1, 1], [476, 314, 1, 1], [476, 423, 1, 1], [477, 275, 1, 1], [477, 325, 1, 1], [483, 238, 1, 1], [483, 362, 1, 1], [486, 257, 1, 1], [486, 343, 1, 1], [489, 254, 1, 1], [489, 346, 1, 1]], [[68, 300, 1, 1], [79, 300, 1, 1], [85, 300, 1, 1], [86, 300, 1, 1], [87, 300, 1, 1], [93, 300, 1, 1], [94, 300, 1, 1], [95, 300, 1, 1], [96, 300, 1, 1], [98, 300, 1, 1], [106, 300, 1, 1], [159, 288, 1, 2], [159, 311, 1, 2], [168, 266, 1, 1], [168, 334, 1, 1], [169, 274, 1, 1], [169, 326, 1, 1], [177, 264, 1, 1], [177, 266, 1, 1], [177, 334, 1, 1], [177, 336, 1, 1], [197, 250, 1, 2], [197, 349, 1, 2], [209, 247, 1, 1], [209, 353, 1, 1], [229, 247, 1, 1], [229, 353, 1, 1], [232, 253, 1, 1], [232, 347, 1, 1], [248, 265, 1, 1], [248, 335, 1, 1], [249, 263, 1, 1], [249, 337, 1, 1], [263, 270, 1, 1], [263, 330, 1, 1], [264, 264, 1, 1], [264, 336, 1, 1], [266, 245, 1, 1], [266, 355, 1, 1], [267, 248, 1, 1], [267, 352, 1, 1], [272, 231, 1, 1], [272, 369, 1, 1], [276, 227, 1, 1], [276, 373, 1, 1], [278, 216, 1, 1], [278, 384, 1, 1], [279, 213, 1, 1], [279, 232, 1, 1], [279, 368, 1, 1], [279, 387, 1, 1], [280, 224, 1, 1], [280, 376, 1, 1], [281, 227, 1, 1], [281, 373, 1, 1], [290, 212, 1, 1], [290, 388, 1, 1], [293, 205, 1, 1], [293, 395, 1, 1], [295, 206, 1, 1], [295, 394, 1, 1], [298, 181, 1, 1], [298, 419, 1, 1], [299, 188, 1, 1], [299, 412, 1, 1], [301, 178, 1, 1], [301, 199, 1, 1], [301, 401, 1, 1], [301, 422, 1, 1], [304, 198, 1, 1], [304, 402, 1, 1], [313, 178, 1, 1], [313, 422, 1, 1], [329, 181, 1, 1], [329, 419, 1, 1], [334, 168, 1, 1], [334, 432, 1, 1], [340, 173, 1, 1], [340, 427, 1, 1], [373, 133, 1, 1], [373, 467, 1, 1], [378, 170, 1, 1], [378, 430, 1, 1], [388, 131, 1, 1], [388, 133, 1, 1], [388, 467, 1, 1], [388, 469, 1, 1], [399, 163, 1, 1], [399, 437, 1, 1], [403, 146, 1, 1], [403, 454, 1, 1], [405, 139, 1, 1], [405, 461, 1, 1], [416, 171, 1, 1], [416, 429, 1, 1], [419, 169, 1, 1], [419, 431, 1, 1], [426, 173, 1, 1], [426, 427, 1, 1], [435, 183, 1, 1], [435, 417, 1, 1], [442, 188, 1, 1], [442, 412, 1, 1], [443, 182, 1, 1], [443, 418, 1, 1], [447, 191, 1, 1], [447, 409, 1, 1], [456, 186, 1, 1], [456, 414, 1, 1], [467, 186, 1, 1], [467, 414, 1, 1], [470, 201, 1, 1], [470, 399, 1, 1], [471, 189, 1, 1], [471, 411, 1, 1], [474, 229, 1, 1], [474, 371, 1, 1], [478, 239, 1, 1], [478, 361, 1, 1], [479, 273, 1, 1], [479, 281, 1, 1], [479, 319, 1, 1], [479, 327, 1, 1], [487, 258, 1, 1], [487, 342, 1, 1]], [[90, 300, 1, 1], [104, 300, 1, 1], [105, 300, 1, 1], [108, 300, 1, 1], [137, 297, 1, 1], [137, 303, 1, 1], [142, 294, 1, 1], [142, 306, 1, 1], [161, 290, 1, 1], [161, 310, 1, 1], [165, 282, 1, 1], [165, 318, 1, 1], [168, 267, 1, 1], [168, 333, 1, 1], [172, 267, 1, 1], [172, 333, 1, 1], [179, 252, 1, 1], [179, 348, 1, 1], [182, 243, 1, 1], [182, 357, 1, 1], [205, 247, 1, 1], [205, 353, 1, 1], [214, 240, 1, 1], [214, 360, 1, 1], [229, 245, 1, 1], [229, 355, 1, 1], [230, 245, 1, 1], [230, 355, 1, 1], [240, 255, 1, 1], [240, 345, 1, 1], [247, 262, 1, 1], [247, 338, 1, 1], [261, 293, 1, 1], [261, 307, 1, 1], [264, 259, 1, 1], [264, 262, 1, 1], [264, 338, 1, 1], [264, 341, 1, 1], [265, 252, 1, 1], [265, 348, 1, 1], [266, 244, 1, 1], [266, 356, 1, 1], [270, 228, 1, 1], [270, 233, 1, 1], [270, 367, 1, 1], [270, 372, 1, 1], [271, 231, 1, 1], [271, 246, 1, 1], [271, 354, 1, 1], [271, 369, 1, 1], [273, 229, 1, 1], [273, 371, 1, 1], [280, 226, 1, 1], [280, 374, 1, 1], [281, 218, 1, 1], [281, 382, 1, 1], [286, 208, 1, 1], [286, 392, 1, 1], [294, 204, 1, 1], [294, 396, 1, 1], [296, 203, 1, 1], [296, 397, 1, 1], [300, 183, 1, 1], [300, 417, 1, 1], [301, 202, 1, 1], [301, 398, 1, 1], [304, 166, 1, 1], [304, 201, 1, 1], [304, 399, 1, 1], [304, 434, 1, 1], [311, 195, 1, 1], [311, 405, 1, 1], [332, 176, 1, 1], [332, 424, 1, 1], [339, 168, 1, 1], [339, 432, 1, 1], [341, 173, 1, 1], [341, 177, 1, 1], [341, 423, 1, 1], [341, 427, 1, 1], [344, 175, 1, 1], [344, 425, 1, 1], [348, 169, 1, 1], [348, 431, 1, 1], [351, 171, 1, 1], [351, 429, 1, 1], [355, 171, 1, 1], [355, 429, 1, 1], [359, 172, 1, 1], [359, 428, 1, 1], [363, 137, 1, 1], [363, 463, 1, 1], [368, 139, 1, 1], [368, 461, 1, 1], [382, 124, 1, 1], [382, 476, 1, 1], [392, 170, 1, 1], [392, 430, 1, 1], [396, 135, 1, 1], [396, 165, 1, 1], [396, 435, 1, 1], [396, 465, 1, 1], [400, 145, 1, 1], [400, 455, 1, 1], [401, 139, 1, 1], [401, 147, 1, 1], [401, 453, 1, 1], [401, 461, 1, 1], [419, 172, 1, 1], [419, 428, 1, 1], [426, 176, 1, 1], [426, 178, 1, 1], [426, 422, 1, 1], [426, 424, 1, 1], [433, 183, 1, 1], [433, 417, 1, 1], [443, 183, 1, 1], [443, 417, 1, 1], [462, 208, 1, 1], [462, 392, 1, 1], [465, 209, 1, 1], [465, 391, 1, 1], [466, 185, 1, 1], [466, 415, 1, 1], [469, 216, 1, 1], [469, 384, 1, 1], [473, 219, 1, 1], [473, 381, 1, 1], [480, 243, 1, 1], [480, 262, 1, 1], [480, 338, 1, 1], [480, 357, 1, 1], [484, 259, 1, 1], [484, 341, 1, 1], [492, 225, 1, 1], [492, 375, 1, 1]], [[97, 300, 1, 1], [101, 300, 1, 1], [109, 300, 1, 1], [177, 263, 1, 1], [177, 337, 1, 1], [208, 249, 1, 1], [208, 351, 1, 1], [209, 246, 1, 1], [209, 354, 1, 1], [228, 248, 1, 1], [228, 352, 1, 1], [243, 259, 1, 1], [243, 341, 1, 1], [245, 262, 1, 1], [245, 338, 1, 1], [252, 267, 1, 1], [252, 333, 1, 1], [257, 277, 1, 1], [257, 323, 1, 1], [260, 286, 1, 1], [260, 314, 1, 1], [262, 273, 1, 1], [262, 327, 1, 1], [264, 256, 1, 1], [264, 344, 1, 1], [265, 265, 1, 1], [265, 335, 1, 1], [267, 245, 1, 1], [267, 355, 1, 1], [268, 228, 1, 1], [268, 372, 1, 1], [278, 229, 1, 2], [278, 370, 1, 2], [292, 176, 1, 1], [292, 424, 1, 1], [294, 208, 1, 1], [294, 392, 1, 1], [295, 203, 1, 1], [295, 397, 1, 1], [299, 192, 1, 1], [299, 194, 1, 1], [299, 406, 1, 1], [299, 408, 1, 1], [305, 178, 1, 1], [305, 422, 1, 1], [312, 178, 1, 1], [312, 422, 1, 1], [314, 178, 1, 1], [314, 422, 1, 1], [315, 175, 1, 1], [315, 425, 1, 1], [321, 188, 1, 1], [321, 412, 1, 1], [327, 179, 1, 1], [327, 181, 1, 1], [327, 419, 1, 1], [327, 421, 1, 1], [333, 178, 1, 1], [333, 422, 1, 1], [339, 173, 1, 1], [339, 427, 1, 1], [354, 173, 1, 1], [354, 427, 1, 1], [362, 147, 1, 1], [362, 453, 1, 1], [364, 143, 1, 1], [364, 457, 1, 1], [367, 162, 1, 1], [367, 438, 1, 1], [371, 134, 1, 1], [371, 466, 1, 1], [375, 92, 1, 1], [375, 508, 1, 1], [378, 132, 1, 1], [378, 468, 1, 1], [380, 125, 1, 1], [380, 475, 1, 1], [386, 170, 1, 1], [386, 430, 1, 1], [392, 133, 1, 1], [392, 467, 1, 1], [393, 135, 1, 1], [393, 465, 1, 1], [400, 170, 1, 1], [400, 430, 1, 1], [403, 150, 1, 1], [403, 170, 1, 1], [403, 430, 1, 1], [403, 450, 1, 1], [407, 169, 1, 1], [407, 431, 1, 1], [418, 169, 1, 1], [418, 431, 1, 1], [420, 171, 1, 1], [420, 429, 1, 1], [421, 170, 1, 1], [421, 430, 1, 1], [423, 176, 1, 1], [423, 424, 1, 1], [425, 178, 1, 1], [425, 422, 1, 1], [428, 174, 1, 1], [428, 426, 1, 1], [442, 181, 1, 1], [442, 419, 1, 1], [444, 187, 1, 1], [444, 413, 1, 1], [452, 190, 1, 1], [452, 410, 1, 1], [457, 185, 1, 1], [457, 415, 1, 1], [467, 210, 1, 1], [467, 390, 1, 1], [473, 224, 1, 1], [473, 376, 1, 1], [476, 282, 1, 1], [476, 318, 1, 1], [479, 226, 1, 1], [479, 374, 1, 1], [481, 270, 1, 1], [481, 330, 1, 1], [485, 255, 1, 1], [485, 345, 1, 1]], [[102, 300, 1, 1], [103, 300, 1, 1], [157, 287, 1, 1], [157, 313, 1, 1], [167, 279, 1, 1], [167, 321, 1, 1], [169, 270, 1, 1], [169, 330, 1, 1], [180, 261, 1, 1], [180, 339, 1, 1], [200, 246, 1, 1], [200, 354, 1, 1], [216, 245, 1, 1], [216, 355, 1, 1], [226, 249, 1, 1], [226, 351, 1, 1], [227, 249, 1, 1], [227, 351, 1, 1], [276, 207, 1, 1], [276, 393, 1, 1], [290, 216, 1, 1], [290, 384, 1, 1], [300, 192, 1, 1], [300, 408, 1, 1], [301, 193, 1, 1], [301, 407, 1, 1], [305, 176, 1, 1], [305, 424, 1, 1], [322, 184, 1, 1], [322, 416, 1, 1], [323, 183, 1, 1], [323, 417, 1, 1], [329, 182, 1, 1], [329, 418, 1, 1], [339, 172, 1, 1], [339, 428, 1, 1], [362, 156, 1, 1], [362, 444, 1, 1], [408, 171, 1, 1], [408, 429, 1, 1], [417, 169, 1, 1], [417, 431, 1, 1], [418, 168, 1, 1], [418, 432, 1, 1], [419, 167, 1, 1], [419, 433, 1, 1], [427, 176, 1, 1], [427, 424, 1, 1], [454, 187, 1, 1], [454, 413, 1, 1], [460, 183, 1, 1], [460, 417, 1, 1], [471, 290, 1, 1], [471, 310, 1, 1], [474, 286, 1, 1], [474, 314, 1, 1], [478, 228, 1, 1], [478, 372, 1, 1], [483, 227, 1, 1], [483, 373, 1, 1], [485, 271, 1, 1], [485, 273, 1, 1], [485, 327, 1, 1], [485, 329, 1, 1]], [[149, 287, 1, 1], [149, 313, 1, 1], [162, 292, 1, 1], [162, 308, 1, 1], [166, 277, 1, 1], [166, 323, 1, 1], [176, 266, 1, 1], [176, 334, 1, 1], [181, 249, 1, 1], [181, 351, 1, 1], [210, 249, 1, 1], [210, 351, 1, 1], [218, 246, 1, 1], [218, 354, 1, 1], [230, 246, 1, 1], [230, 354, 1, 1], [238, 257, 1, 1], [238, 343, 1, 1], [263, 263, 1, 1], [263, 337, 1, 1], [269, 229, 1, 1], [269, 371, 1, 1], [276, 229, 1, 1], [276, 371, 1, 1], [279, 218, 1, 1], [279, 382, 1, 1], [280, 217, 1, 1], [280, 383, 1, 1], [287, 220, 1, 1], [287, 380, 1, 1], [289, 210, 1, 1], [289, 390, 1, 1], [292, 210, 1, 1], [292, 390, 1, 1], [297, 201, 1, 1], [297, 399, 1, 1], [303, 202, 1, 1], [303, 398, 1, 1], [317, 180, 1, 1], [317, 420, 1, 1], [319, 188, 1, 1], [319, 412, 1, 1], [326, 179, 1, 1], [326, 421, 1, 1], [334, 179, 1, 1], [334, 421, 1, 1], [335, 170, 1, 1], [335, 430, 1, 1], [348, 171, 1, 1], [348, 429, 1, 1], [355, 172, 1, 1], [355, 428, 1, 1], [356, 171, 1, 1], [356, 429, 1, 1], [360, 133, 1, 1], [360, 467, 1, 1], [361, 156, 1, 1], [361, 169, 1, 1], [361, 431, 1, 1], [361, 444, 1, 1], [364, 148, 1, 1], [364, 452, 1, 1], [367, 170, 1, 1], [367, 430, 1, 1], [375, 169, 1, 1], [375, 431, 1, 1], [387, 124, 1, 1], [387, 476, 1, 1], [389, 129, 1, 1], [389, 471, 1, 1], [395, 165, 1, 1], [395, 435, 1, 1], [396, 134, 1, 1], [396, 466, 1, 1], [407, 171, 1, 1], [407, 429, 1, 1], [422, 174, 1, 1], [422, 426, 1, 1], [471, 220, 1, 1], [471, 380, 1, 1], [474, 212, 1, 1], [474, 222, 1, 1], [474, 378, 1, 1], [474, 388, 1, 1], [475, 281, 1, 1], [475, 319, 1, 1], [480, 251, 1, 1], [480, 264, 1, 1], [480, 336, 1, 1], [480, 349, 1, 1], [481, 253, 1, 1], [481, 347, 1, 1]]]"; +var mandelbrotImageDataFuzzyResult = "[1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 0, 0, 0, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 7, 7, 7, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 6, 6, 6, 0, 19, 19, 19, 0, 7, 7, 7, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 11, 11, 11, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 0, 0, 0, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 12, 12, 12, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 10, 10, 10, 0, 10, 10, 10, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 6, 6, 6, 0, 5, 5, 5, 0, 8, 8, 8, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 9, 9, 9, 0, 14, 14, 14, 0, 10, 10, 10, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 7, 7, 7, 0, 11, 11, 11, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 16, 16, 16, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 12, 12, 12, 0, 12, 12, 12, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 11, 11, 11, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 5, 5, 5, 0, 10, 10, 10, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 9, 9, 9, 0, 4, 4, 4, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 5, 5, 5, 0, 7, 7, 7, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 10, 10, 10, 0, 10, 10, 10, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 5, 5, 5, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 12, 12, 12, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 12, 12, 12, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 13, 13, 13, 0, 9, 9, 9, 0, 11, 11, 11, 0, 6, 6, 6, 0, 10, 10, 10, 0, 0, 0, 0, 0, 9, 9, 9, 0, 19, 19, 19, 0, 0, 0, 0, 0, 13, 13, 13, 0, 12, 12, 12, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 21, 21, 21, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 19, 19, 19, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 6, 6, 6, 0, 10, 10, 10, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 10, 10, 10, 0, 6, 6, 6, 0, 15, 15, 15, 0, 21, 21, 21, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 11, 11, 11, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 15, 15, 15, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 13, 13, 13, 0, 7, 7, 7, 0, 8, 8, 8, 0, 10, 10, 10, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 10, 10, 10, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 15, 15, 15, 0, 8, 8, 8, 0, 9, 9, 9, 0, 7, 7, 7, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 5, 5, 5, 0, 8, 8, 8, 0, 0, 0, 0, 0, 18, 18, 18, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 14, 14, 14, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 17, 17, 17, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 16, 16, 16, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 8, 8, 8, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 13, 13, 13, 0, 10, 10, 10, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 7, 7, 7, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 11, 11, 11, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 19, 19, 19, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 6, 6, 6, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 5, 5, 5, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 12, 12, 12, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 11, 11, 11, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 6, 6, 6, 0, 17, 17, 17, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 8, 8, 8, 0, 6, 6, 6, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 19, 19, 19, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 10, 10, 10, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 21, 21, 21, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 11, 11, 11, 0, 12, 12, 12, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 7, 7, 7, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 9, 9, 9, 0, 19, 19, 19, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 7, 7, 7, 0, 8, 8, 8, 0, 11, 11, 11, 0, 5, 5, 5, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 13, 13, 13, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 10, 10, 10, 0, 10, 10, 10, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 9, 9, 9, 0, 14, 14, 14, 0, 11, 11, 11, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 13, 13, 13, 0, 12, 12, 12, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 7, 7, 7, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 10, 10, 10, 0, 6, 6, 6, 0, 6, 6, 6, 0, 10, 10, 10, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 15, 15, 15, 0, 12, 12, 12, 0, 21, 21, 21, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 15, 15, 15, 0, 11, 11, 11, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 16, 16, 16, 0, 7, 7, 7, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 12, 12, 12, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 5, 5, 5, 0, 8, 8, 8, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 6, 6, 6, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 13, 13, 13, 0, 8, 8, 8, 0, 10, 10, 10, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 17, 17, 17, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 12, 12, 12, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 6, 6, 6, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 12, 12, 12, 0, 5, 5, 5, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 6, 6, 6, 0, 5, 5, 5, 0, 9, 9, 9, 0, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 11, 11, 11, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 18, 18, 18, 0, 15, 15, 15, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 7, 7, 7, 0, 4, 4, 4, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 18, 18, 18, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 11, 11, 11, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 9, 9, 9, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 6, 6, 6, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 12, 12, 12, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 7, 7, 7, 0, 5, 5, 5, 0, 8, 8, 8, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 11, 11, 11, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 12, 12, 12, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 8, 8, 8, 0, 5, 5, 5, 0, 19, 19, 19, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 9, 9, 9, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 12, 12, 12, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 16, 16, 16, 0, 12, 12, 12, 0, 9, 9, 9, 0, 17, 17, 17, 0, 14, 14, 14, 0, 15, 15, 15, 0, 11, 11, 11, 0, 6, 6, 6, 0, 17, 17, 17, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 10, 10, 10, 0, 16, 16, 16, 0, 9, 9, 9, 0, 9, 9, 9, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 14, 14, 14, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 11, 11, 11, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 10, 10, 10, 0, 9, 9, 9, 0, 20, 20, 20, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 16, 16, 16, 0, 5, 5, 5, 0, 8, 8, 8, 0, 5, 5, 5, 0, 10, 10, 10, 0, 6, 6, 6, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 9, 9, 9, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 8, 8, 8, 0, 4, 4, 4, 0, 6, 6, 6, 0, 14, 14, 14, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 14, 14, 14, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 9, 9, 9, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 9, 9, 9, 0, 5, 5, 5, 0, 6, 6, 6, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 5, 5, 5, 0, 21, 21, 21, 0, 10, 10, 10, 0, 5, 5, 5, 0, 14, 14, 14, 0, 9, 9, 9, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 16, 16, 16, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 19, 19, 19, 0, 14, 14, 14, 0, 0, 0, 0, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 0, 0, 0, 0, 9, 9, 9, 0, 20, 20, 20, 0, 19, 19, 19, 0, 17, 17, 17, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 15, 15, 15, 0, 6, 6, 6, 0, 11, 11, 11, 0, 7, 7, 7, 0, 11, 11, 11, 0, 14, 14, 14, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 5, 5, 5, 0, 9, 9, 9, 0, 11, 11, 11, 0, 8, 8, 8, 0, 9, 9, 9, 0, 21, 21, 21, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 14, 14, 14, 0, 8, 8, 8, 0, 9, 9, 9, 0, 0, 0, 0, 0, 14, 14, 14, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 10, 10, 10, 0, 16, 16, 16, 0, 11, 11, 11, 0, 12, 12, 12, 0, 0, 0, 0, 0, 7, 7, 7, 0, 12, 12, 12, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 11, 11, 11, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 15, 15, 15, 0, 9, 9, 9, 0, 0, 0, 0, 0, 6, 6, 6, 0, 19, 19, 19, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 13, 13, 13, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 13, 13, 13, 0, 6, 6, 6, 0, 16, 16, 16, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 5, 5, 5, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 5, 5, 5, 0, 6, 6, 6, 0, 21, 21, 21, 0, 0, 0, 0, 0, 12, 12, 12, 0, 18, 18, 18, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 18, 18, 18, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 21, 21, 21, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 14, 14, 14, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 11, 11, 11, 0, 6, 6, 6, 0, 19, 19, 19, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 7, 7, 7, 0, 16, 16, 16, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 13, 13, 13, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 7, 7, 7, 0, 20, 20, 20, 0, 0, 0, 0, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 6, 6, 6, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 18, 18, 18, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 10, 10, 10, 0, 14, 14, 14, 0, 16, 16, 16, 0, 16, 16, 16, 0, 8, 8, 8, 0, 6, 6, 6, 0, 9, 9, 9, 0, 6, 6, 6, 0, 7, 7, 7, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 13, 13, 13, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 6, 6, 6, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 9, 9, 9, 0, 8, 8, 8, 0, 4, 4, 4, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 19, 19, 19, 0, 17, 17, 17, 0, 18, 18, 18, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 17, 17, 17, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 14, 14, 14, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 8, 8, 8, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 13, 13, 13, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 11, 11, 11, 0, 6, 6, 6, 0, 12, 12, 12, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 0, 0, 0, 0, 7, 7, 7, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 8, 8, 8, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 5, 5, 5, 0, 4, 4, 4, 0, 20, 20, 20, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 11, 11, 11, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 10, 10, 10, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 10, 10, 10, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 13, 13, 13, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 12, 12, 12, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 19, 19, 19, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 11, 11, 11, 0, 12, 12, 12, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 5, 5, 5, 0, 7, 7, 7, 0, 18, 18, 18, 0, 12, 12, 12, 0, 16, 16, 16, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 19, 19, 19, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 8, 8, 8, 0, 7, 7, 7, 0, 12, 12, 12, 0, 20, 20, 20, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 5, 5, 5, 0, 5, 5, 5, 0, 18, 18, 18, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 5, 5, 5, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 7, 7, 7, 0, 5, 5, 5, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 12, 12, 12, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 13, 13, 13, 0, 13, 13, 13, 0, 0, 0, 0, 0, 12, 12, 12, 0, 14, 14, 14, 0, 13, 13, 13, 0, 14, 14, 14, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 12, 12, 12, 0, 14, 14, 14, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 10, 10, 10, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 16, 16, 16, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 6, 6, 6, 0, 9, 9, 9, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 8, 8, 8, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 7, 7, 7, 0, 15, 15, 15, 0, 19, 19, 19, 0, 17, 17, 17, 0, 19, 19, 19, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 14, 14, 14, 0, 4, 4, 4, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 15, 15, 15, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 12, 12, 12, 0, 21, 21, 21, 0, 19, 19, 19, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 6, 6, 6, 0, 9, 9, 9, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 6, 6, 6, 0, 0, 0, 0, 0, 21, 21, 21, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 15, 15, 15, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 11, 11, 11, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 16, 16, 16, 0, 6, 6, 6, 0, 15, 15, 15, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 11, 11, 11, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 14, 14, 14, 0, 12, 12, 12, 0, 18, 18, 18, 0, 11, 11, 11, 0, 17, 17, 17, 0, 13, 13, 13, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 10, 10, 10, 0, 8, 8, 8, 0, 19, 19, 19, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 10, 10, 10, 0, 9, 9, 9, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 12, 12, 12, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 7, 7, 7, 0, 0, 0, 0, 0, 7, 7, 7, 0, 15, 15, 15, 0, 5, 5, 5, 0, 4, 4, 4, 0, 7, 7, 7, 0, 12, 12, 12, 0, 8, 8, 8, 0, 11, 11, 11, 0, 16, 16, 16, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 9, 9, 9, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 18, 18, 18, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 20, 20, 20, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 10, 10, 10, 0, 5, 5, 5, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 20, 20, 20, 0, 11, 11, 11, 0, 9, 9, 9, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 11, 11, 11, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 19, 19, 19, 0, 13, 13, 13, 0, 10, 10, 10, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 8, 8, 8, 0, 14, 14, 14, 0, 11, 11, 11, 0, 6, 6, 6, 0, 5, 5, 5, 0, 12, 12, 12, 0, 6, 6, 6, 0, 9, 9, 9, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 12, 12, 12, 0, 11, 11, 11, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 11, 11, 11, 0, 13, 13, 13, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 15, 15, 15, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 18, 18, 18, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 8, 8, 8, 0, 18, 18, 18, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 11, 11, 11, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 14, 14, 14, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 0, 0, 0, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 13, 13, 13, 0, 8, 8, 8, 0, 6, 6, 6, 0, 8, 8, 8, 0, 11, 11, 11, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 19, 19, 19, 0, 0, 0, 0, 0, 15, 15, 15, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 6, 6, 6, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 13, 13, 13, 0, 8, 8, 8, 0, 13, 13, 13, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 21, 21, 21, 0, 13, 13, 13, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 7, 7, 7, 0, 16, 16, 16, 0, 13, 13, 13, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 14, 14, 14, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 11, 11, 11, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 11, 11, 11, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 10, 10, 10, 0, 12, 12, 12, 0, 5, 5, 5, 0, 6, 6, 6, 0, 12, 12, 12, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 9, 9, 9, 0, 7, 7, 7, 0, 9, 9, 9, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 11, 11, 11, 0, 5, 5, 5, 0, 13, 13, 13, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 7, 7, 7, 0, 9, 9, 9, 0, 5, 5, 5, 0, 9, 9, 9, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 19, 19, 19, 0, 20, 20, 20, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 5, 5, 5, 0, 12, 12, 12, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 15, 15, 15, 0, 20, 20, 20, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 6, 6, 6, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 19, 19, 19, 0, 10, 10, 10, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 12, 12, 12, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 15, 15, 15, 0, 9, 9, 9, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 6, 6, 6, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 10, 10, 10, 0, 5, 5, 5, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 17, 17, 17, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 8, 8, 8, 0, 5, 5, 5, 0, 8, 8, 8, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 17, 17, 17, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 9, 9, 9, 0, 6, 6, 6, 0, 11, 11, 11, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 9, 9, 9, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 10, 10, 10, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 3, 3, 3, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 21, 21, 21, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 0, 0, 0, 0, 15, 15, 15, 0, 9, 9, 9, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 17, 17, 17, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 10, 10, 10, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 16, 16, 16, 0, 11, 11, 11, 0, 12, 12, 12, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 9, 9, 9, 0, 18, 18, 18, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 10, 10, 10, 0, 10, 10, 10, 0, 5, 5, 5, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 10, 10, 10, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 16, 16, 16, 0, 9, 9, 9, 0, 13, 13, 13, 0, 19, 19, 19, 0, 17, 17, 17, 0, 8, 8, 8, 0, 0, 0, 0, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 0, 0, 0, 0, 8, 8, 8, 0, 11, 11, 11, 0, 12, 12, 12, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 12, 12, 12, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 18, 18, 18, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 12, 12, 12, 0, 4, 4, 4, 0, 7, 7, 7, 0, 7, 7, 7, 0, 15, 15, 15, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 17, 17, 17, 0, 9, 9, 9, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 5, 5, 5, 0, 10, 10, 10, 0, 5, 5, 5, 0, 12, 12, 12, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 20, 20, 20, 0, 12, 12, 12, 0, 6, 6, 6, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 18, 18, 18, 0, 9, 9, 9, 0, 15, 15, 15, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 19, 19, 19, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 7, 7, 7, 0, 15, 15, 15, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 16, 16, 16, 0, 0, 0, 0, 0, 16, 16, 16, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 4, 4, 4, 0, 0, 0, 0, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 8, 8, 8, 0, 15, 15, 15, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 20, 20, 20, 0, 6, 6, 6, 0, 5, 5, 5, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 6, 6, 6, 0, 19, 19, 19, 0, 11, 11, 11, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 6, 6, 6, 0, 7, 7, 7, 0, 4, 4, 4, 0, 6, 6, 6, 0, 11, 11, 11, 0, 6, 6, 6, 0, 6, 6, 6, 0, 16, 16, 16, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 12, 12, 12, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 12, 12, 12, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 21, 21, 21, 0, 6, 6, 6, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 14, 14, 14, 0, 5, 5, 5, 0, 5, 5, 5, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 7, 7, 7, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 15, 15, 15, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 13, 13, 13, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 21, 21, 21, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 11, 11, 11, 0, 9, 9, 9, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 17, 17, 17, 0, 13, 13, 13, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 10, 10, 10, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 10, 10, 10, 0, 21, 21, 21, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 3, 3, 3, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 21, 21, 21, 0, 12, 12, 12, 0, 17, 17, 17, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 12, 12, 12, 0, 9, 9, 9, 0, 5, 5, 5, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 18, 18, 18, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 13, 13, 13, 0, 0, 0, 0, 0, 13, 13, 13, 0, 8, 8, 8, 0, 9, 9, 9, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 21, 21, 21, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 8, 8, 8, 0, 20, 20, 20, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 9, 9, 9, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 9, 9, 9, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 13, 13, 13, 0, 16, 16, 16, 0, 14, 14, 14, 0, 8, 8, 8, 0, 8, 8, 8, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 10, 10, 10, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 11, 11, 11, 0, 4, 4, 4, 0, 3, 3, 3, 0, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 0, 0, 0, 0, 11, 11, 11, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 12, 12, 12, 0, 18, 18, 18, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 4, 4, 4, 0, 11, 11, 11, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 18, 18, 18, 0, 6, 6, 6, 0, 7, 7, 7, 0, 10, 10, 10, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 9, 9, 9, 0, 7, 7, 7, 0, 11, 11, 11, 0, 5, 5, 5, 0, 8, 8, 8, 0, 17, 17, 17, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 21, 21, 21, 0, 9, 9, 9, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 19, 19, 19, 0, 11, 11, 11, 0, 18, 18, 18, 0, 12, 12, 12, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 11, 11, 11, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 10, 10, 10, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 7, 7, 7, 0, 21, 21, 21, 0, 11, 11, 11, 0, 9, 9, 9, 0, 7, 7, 7, 0, 18, 18, 18, 0, 9, 9, 9, 0, 10, 10, 10, 0, 21, 21, 21, 0, 10, 10, 10, 0, 19, 19, 19, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 9, 9, 9, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 10, 10, 10, 0, 11, 11, 11, 0, 0, 0, 0, 0, 11, 11, 11, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 10, 10, 10, 0, 7, 7, 7, 0, 8, 8, 8, 0, 11, 11, 11, 0, 18, 18, 18, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 9, 9, 9, 0, 5, 5, 5, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 11, 11, 11, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 12, 12, 12, 0, 7, 7, 7, 0, 17, 17, 17, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 9, 9, 9, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 9, 9, 9, 0, 13, 13, 13, 0, 13, 13, 13, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 4, 4, 4, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 7, 7, 7, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 15, 15, 15, 0, 15, 15, 15, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 12, 12, 12, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 8, 8, 8, 0, 10, 10, 10, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 14, 14, 14, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 10, 10, 10, 0, 7, 7, 7, 0, 5, 5, 5, 0, 10, 10, 10, 0, 15, 15, 15, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 9, 9, 9, 0, 10, 10, 10, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 0, 0, 14, 14, 14, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 14, 14, 14, 0, 15, 15, 15, 0, 0, 0, 0, 0, 7, 7, 7, 0, 16, 16, 16, 0, 10, 10, 10, 0, 9, 9, 9, 0, 5, 5, 5, 0, 8, 8, 8, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 15, 15, 15, 0, 5, 5, 5, 0, 4, 4, 4, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 10, 10, 10, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 13, 13, 13, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 5, 5, 5, 0, 9, 9, 9, 0, 5, 5, 5, 0, 11, 11, 11, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 9, 9, 9, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 10, 10, 10, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 9, 9, 9, 0, 17, 17, 17, 0, 12, 12, 12, 0, 9, 9, 9, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 13, 13, 13, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 15, 15, 15, 0, 6, 6, 6, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 3, 3, 3, 0, 6, 6, 6, 0, 7, 7, 7, 0, 11, 11, 11, 0, 6, 6, 6, 0, 0, 0, 0, 0, 13, 13, 13, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 10, 10, 10, 0, 15, 15, 15, 0, 13, 13, 13, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 11, 11, 11, 0, 16, 16, 16, 0, 12, 12, 12, 0, 16, 16, 16, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 18, 18, 18, 0, 7, 7, 7, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 4, 4, 4, 0, 6, 6, 6, 0, 8, 8, 8, 0, 6, 6, 6, 0, 4, 4, 4, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 10, 10, 10, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 14, 14, 14, 0, 10, 10, 10, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 8, 8, 8, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 11, 11, 11, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 12, 12, 12, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 6, 6, 6, 0, 13, 13, 13, 0, 8, 8, 8, 0, 11, 11, 11, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 8, 8, 8, 0, 9, 9, 9, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 6, 6, 6, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 7, 7, 7, 0, 11, 11, 11, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 13, 13, 13, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 18, 18, 18, 0, 18, 18, 18, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 17, 17, 17, 0, 19, 19, 19, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 21, 21, 21, 0, 6, 6, 6, 0, 5, 5, 5, 0, 13, 13, 13, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 5, 5, 5, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 9, 9, 9, 0, 15, 15, 15, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 20, 20, 20, 0, 10, 10, 10, 0, 11, 11, 11, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 9, 9, 9, 0, 21, 21, 21, 0, 5, 5, 5, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 21, 21, 21, 0, 9, 9, 9, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 11, 11, 11, 0, 18, 18, 18, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 5, 5, 5, 0, 18, 18, 18, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 7, 7, 7, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 8, 8, 8, 0, 7, 7, 7, 0, 17, 17, 17, 0, 13, 13, 13, 0, 9, 9, 9, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 5, 5, 5, 0, 9, 9, 9, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 11, 11, 11, 0, 13, 13, 13, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 9, 9, 9, 0, 11, 11, 11, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 7, 7, 7, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 15, 15, 15, 0, 6, 6, 6, 0, 0, 0, 0, 0, 9, 9, 9, 0, 16, 16, 16, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 11, 11, 11, 0, 16, 16, 16, 0, 5, 5, 5, 0, 6, 6, 6, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 16, 16, 16, 0, 11, 11, 11, 0, 6, 6, 6, 0, 7, 7, 7, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 19, 19, 19, 0, 8, 8, 8, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 0, 0, 0, 0, 15, 15, 15, 0, 12, 12, 12, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 20, 20, 20, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 8, 8, 8, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 11, 11, 11, 0, 10, 10, 10, 0, 6, 6, 6, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 7, 7, 7, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 17, 17, 17, 0, 8, 8, 8, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 15, 15, 15, 0, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 9, 9, 9, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 17, 17, 17, 0, 13, 13, 13, 0, 9, 9, 9, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 6, 6, 6, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 13, 13, 13, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 9, 9, 9, 0, 13, 13, 13, 0, 8, 8, 8, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 12, 12, 12, 0, 13, 13, 13, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 9, 9, 9, 0, 4, 4, 4, 0, 6, 6, 6, 0, 12, 12, 12, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 8, 8, 8, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 17, 17, 17, 0, 12, 12, 12, 0, 0, 0, 0, 0, 6, 6, 6, 0, 9, 9, 9, 0, 12, 12, 12, 0, 8, 8, 8, 0, 9, 9, 9, 0, 0, 0, 0, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 10, 10, 10, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 20, 20, 20, 0, 11, 11, 11, 0, 9, 9, 9, 0, 12, 12, 12, 0, 10, 10, 10, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 16, 16, 16, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 15, 15, 15, 0, 3, 3, 3, 0, 3, 3, 3, 0, 16, 16, 16, 0, 9, 9, 9, 0, 4, 4, 4, 0, 6, 6, 6, 0, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 12, 12, 12, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 19, 19, 19, 0, 7, 7, 7, 0, 6, 6, 6, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 9, 9, 9, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 11, 11, 11, 0, 8, 8, 8, 0, 10, 10, 10, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 13, 13, 13, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 6, 6, 6, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8, 8, 0, 12, 12, 12, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 6, 6, 6, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 17, 17, 17, 0, 7, 7, 7, 0, 7, 7, 7, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 4, 4, 4, 0, 7, 7, 7, 0, 13, 13, 13, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 17, 17, 17, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 6, 6, 6, 0, 12, 12, 12, 0, 5, 5, 5, 0, 9, 9, 9, 0, 7, 7, 7, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 12, 12, 12, 0, 5, 5, 5, 0, 15, 15, 15, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 14, 14, 14, 0, 9, 9, 9, 0, 3, 3, 3, 0, 10, 10, 10, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 6, 6, 6, 0, 6, 6, 6, 0, 20, 20, 20, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 7, 7, 7, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 14, 14, 14, 0, 14, 14, 14, 0, 6, 6, 6, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 12, 12, 12, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 14, 14, 14, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 18, 18, 18, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 14, 14, 14, 0, 17, 17, 17, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 0, 0, 21, 21, 21, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 15, 15, 15, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 6, 6, 6, 0, 8, 8, 8, 0, 11, 11, 11, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 7, 7, 7, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 7, 7, 7, 0, 15, 15, 15, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 13, 13, 13, 0, 6, 6, 6, 0, 6, 6, 6, 0, 11, 11, 11, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 13, 13, 13, 0, 7, 7, 7, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 12, 12, 12, 0, 9, 9, 9, 0, 17, 17, 17, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 15, 15, 15, 0, 0, 0, 0, 0, 6, 6, 6, 0, 7, 7, 7, 0, 21, 21, 21, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 18, 18, 18, 0, 0, 0, 0, 0, 16, 16, 16, 0, 12, 12, 12, 0, 18, 18, 18, 0, 13, 13, 13, 0, 12, 12, 12, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 6, 6, 6, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 0, 0, 0, 0, 7, 7, 7, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 13, 13, 13, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 4, 4, 4, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 15, 15, 15, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 16, 16, 16, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 4, 4, 4, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 4, 4, 4, 0, 5, 5, 5, 0, 19, 19, 19, 0, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 13, 13, 13, 0, 7, 7, 7, 0, 9, 9, 9, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 6, 6, 6, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 7, 7, 7, 0, 10, 10, 10, 0, 10, 10, 10, 0, 20, 20, 20, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 17, 17, 17, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 0, 0, 0, 0, 4, 4, 4, 0, 11, 11, 11, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 11, 11, 11, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 10, 10, 10, 0, 8, 8, 8, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 9, 9, 9, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 10, 10, 10, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 6, 6, 6, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 5, 5, 5, 0, 7, 7, 7, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 10, 10, 10, 0, 13, 13, 13, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 19, 19, 19, 0, 5, 5, 5, 0, 12, 12, 12, 0, 8, 8, 8, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 11, 11, 11, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 10, 10, 10, 0, 6, 6, 6, 0, 6, 6, 6, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 7, 7, 7, 0, 5, 5, 5, 0, 7, 7, 7, 0, 13, 13, 13, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 5, 5, 5, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 12, 12, 12, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 7, 7, 7, 0, 13, 13, 13, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 11, 11, 11, 0, 11, 11, 11, 0, 6, 6, 6, 0, 8, 8, 8, 0, 12, 12, 12, 0, 7, 7, 7, 0, 5, 5, 5, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 19, 19, 19, 0, 6, 6, 6, 0, 16, 16, 16, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 6, 6, 6, 0, 20, 20, 20, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 12, 12, 12, 0, 13, 13, 13, 0, 20, 20, 20, 0, 8, 8, 8, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 14, 14, 14, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 11, 11, 11, 0, 21, 21, 21, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 17, 17, 17, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 9, 9, 9, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 16, 16, 16, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 7, 7, 7, 0, 6, 6, 6, 0, 7, 7, 7, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 20, 20, 20, 0, 11, 11, 11, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 4, 4, 4, 0, 10, 10, 10, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 9, 9, 9, 0, 5, 5, 5, 0, 8, 8, 8, 0, 6, 6, 6, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 7, 7, 7, 0, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 10, 10, 10, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 18, 18, 18, 0, 11, 11, 11, 0, 0, 0, 0, 0, 12, 12, 12, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 12, 12, 12, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 12, 12, 12, 0, 13, 13, 13, 0, 12, 12, 12, 0, 14, 14, 14, 0, 13, 13, 13, 0, 14, 14, 14, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 16, 16, 16, 0, 15, 15, 15, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 0, 0, 0, 0, 17, 17, 17, 0, 14, 14, 14, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 19, 19, 19, 0, 20, 20, 20, 0, 20, 20, 20, 0, 18, 18, 18, 0, 18, 18, 18, 0, 17, 17, 17, 0, 0, 0, 0, 0, 17, 17, 17, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 12, 12, 12, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 18, 18, 18, 0, 11, 11, 11, 0, 0, 0, 0, 0, 12, 12, 12, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 10, 10, 10, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 9, 9, 9, 0, 5, 5, 5, 0, 8, 8, 8, 0, 6, 6, 6, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 7, 7, 7, 0, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 4, 4, 4, 0, 10, 10, 10, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 7, 7, 7, 0, 6, 6, 6, 0, 7, 7, 7, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 20, 20, 20, 0, 11, 11, 11, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 9, 9, 9, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 16, 16, 16, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 11, 11, 11, 0, 21, 21, 21, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 17, 17, 17, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 6, 6, 6, 0, 20, 20, 20, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 12, 12, 12, 0, 13, 13, 13, 0, 20, 20, 20, 0, 8, 8, 8, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 14, 14, 14, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 12, 12, 12, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 7, 7, 7, 0, 13, 13, 13, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 11, 11, 11, 0, 11, 11, 11, 0, 6, 6, 6, 0, 8, 8, 8, 0, 12, 12, 12, 0, 7, 7, 7, 0, 5, 5, 5, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 19, 19, 19, 0, 6, 6, 6, 0, 16, 16, 16, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 7, 7, 7, 0, 5, 5, 5, 0, 7, 7, 7, 0, 13, 13, 13, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 5, 5, 5, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 10, 10, 10, 0, 6, 6, 6, 0, 6, 6, 6, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 11, 11, 11, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 10, 10, 10, 0, 13, 13, 13, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 19, 19, 19, 0, 5, 5, 5, 0, 12, 12, 12, 0, 8, 8, 8, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 5, 5, 5, 0, 7, 7, 7, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 6, 6, 6, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 10, 10, 10, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 9, 9, 9, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 10, 10, 10, 0, 8, 8, 8, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 11, 11, 11, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 17, 17, 17, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 0, 0, 0, 0, 4, 4, 4, 0, 11, 11, 11, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 7, 7, 7, 0, 10, 10, 10, 0, 10, 10, 10, 0, 20, 20, 20, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 13, 13, 13, 0, 7, 7, 7, 0, 9, 9, 9, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 6, 6, 6, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 4, 4, 4, 0, 5, 5, 5, 0, 19, 19, 19, 0, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 15, 15, 15, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 16, 16, 16, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 4, 4, 4, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 0, 0, 0, 0, 7, 7, 7, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 13, 13, 13, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 4, 4, 4, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 18, 18, 18, 0, 0, 0, 0, 0, 16, 16, 16, 0, 12, 12, 12, 0, 18, 18, 18, 0, 13, 13, 13, 0, 12, 12, 12, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 6, 6, 6, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 12, 12, 12, 0, 9, 9, 9, 0, 17, 17, 17, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 15, 15, 15, 0, 0, 0, 0, 0, 6, 6, 6, 0, 7, 7, 7, 0, 21, 21, 21, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 7, 7, 7, 0, 15, 15, 15, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 13, 13, 13, 0, 6, 6, 6, 0, 6, 6, 6, 0, 11, 11, 11, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 13, 13, 13, 0, 7, 7, 7, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 15, 15, 15, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 6, 6, 6, 0, 8, 8, 8, 0, 11, 11, 11, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 7, 7, 7, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 14, 14, 14, 0, 17, 17, 17, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 0, 0, 21, 21, 21, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 14, 14, 14, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 18, 18, 18, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 6, 6, 6, 0, 6, 6, 6, 0, 20, 20, 20, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 7, 7, 7, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 14, 14, 14, 0, 14, 14, 14, 0, 6, 6, 6, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 12, 12, 12, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 12, 12, 12, 0, 5, 5, 5, 0, 15, 15, 15, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 14, 14, 14, 0, 9, 9, 9, 0, 3, 3, 3, 0, 10, 10, 10, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 4, 4, 4, 0, 7, 7, 7, 0, 13, 13, 13, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 17, 17, 17, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 6, 6, 6, 0, 12, 12, 12, 0, 5, 5, 5, 0, 9, 9, 9, 0, 7, 7, 7, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8, 8, 0, 12, 12, 12, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 6, 6, 6, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 17, 17, 17, 0, 7, 7, 7, 0, 7, 7, 7, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 9, 9, 9, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 11, 11, 11, 0, 8, 8, 8, 0, 10, 10, 10, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 13, 13, 13, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 6, 6, 6, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 19, 19, 19, 0, 7, 7, 7, 0, 6, 6, 6, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 12, 12, 12, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 16, 16, 16, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 15, 15, 15, 0, 3, 3, 3, 0, 3, 3, 3, 0, 16, 16, 16, 0, 9, 9, 9, 0, 4, 4, 4, 0, 6, 6, 6, 0, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 8, 8, 8, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 17, 17, 17, 0, 12, 12, 12, 0, 0, 0, 0, 0, 6, 6, 6, 0, 9, 9, 9, 0, 12, 12, 12, 0, 8, 8, 8, 0, 9, 9, 9, 0, 0, 0, 0, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 10, 10, 10, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 20, 20, 20, 0, 11, 11, 11, 0, 9, 9, 9, 0, 12, 12, 12, 0, 10, 10, 10, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 13, 13, 13, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 9, 9, 9, 0, 13, 13, 13, 0, 8, 8, 8, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 12, 12, 12, 0, 13, 13, 13, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 9, 9, 9, 0, 4, 4, 4, 0, 6, 6, 6, 0, 12, 12, 12, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 9, 9, 9, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 17, 17, 17, 0, 13, 13, 13, 0, 9, 9, 9, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 6, 6, 6, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 7, 7, 7, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 17, 17, 17, 0, 8, 8, 8, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 15, 15, 15, 0, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 16, 16, 16, 0, 11, 11, 11, 0, 6, 6, 6, 0, 7, 7, 7, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 19, 19, 19, 0, 8, 8, 8, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 0, 0, 0, 0, 15, 15, 15, 0, 12, 12, 12, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 20, 20, 20, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 8, 8, 8, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 11, 11, 11, 0, 10, 10, 10, 0, 6, 6, 6, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 9, 9, 9, 0, 11, 11, 11, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 7, 7, 7, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 15, 15, 15, 0, 6, 6, 6, 0, 0, 0, 0, 0, 9, 9, 9, 0, 16, 16, 16, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 11, 11, 11, 0, 16, 16, 16, 0, 5, 5, 5, 0, 6, 6, 6, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 5, 5, 5, 0, 18, 18, 18, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 7, 7, 7, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 8, 8, 8, 0, 7, 7, 7, 0, 17, 17, 17, 0, 13, 13, 13, 0, 9, 9, 9, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 5, 5, 5, 0, 9, 9, 9, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 11, 11, 11, 0, 13, 13, 13, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 5, 5, 5, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 9, 9, 9, 0, 15, 15, 15, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 20, 20, 20, 0, 10, 10, 10, 0, 11, 11, 11, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 9, 9, 9, 0, 21, 21, 21, 0, 5, 5, 5, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 21, 21, 21, 0, 9, 9, 9, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 11, 11, 11, 0, 18, 18, 18, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 7, 7, 7, 0, 11, 11, 11, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 13, 13, 13, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 18, 18, 18, 0, 18, 18, 18, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 17, 17, 17, 0, 19, 19, 19, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 21, 21, 21, 0, 6, 6, 6, 0, 5, 5, 5, 0, 13, 13, 13, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 11, 11, 11, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 12, 12, 12, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 6, 6, 6, 0, 13, 13, 13, 0, 8, 8, 8, 0, 11, 11, 11, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 8, 8, 8, 0, 9, 9, 9, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 6, 6, 6, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 18, 18, 18, 0, 7, 7, 7, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 4, 4, 4, 0, 6, 6, 6, 0, 8, 8, 8, 0, 6, 6, 6, 0, 4, 4, 4, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 10, 10, 10, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 14, 14, 14, 0, 10, 10, 10, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 8, 8, 8, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 10, 10, 10, 0, 15, 15, 15, 0, 13, 13, 13, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 11, 11, 11, 0, 16, 16, 16, 0, 12, 12, 12, 0, 16, 16, 16, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 15, 15, 15, 0, 6, 6, 6, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 3, 3, 3, 0, 6, 6, 6, 0, 7, 7, 7, 0, 11, 11, 11, 0, 6, 6, 6, 0, 0, 0, 0, 0, 13, 13, 13, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 9, 9, 9, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 10, 10, 10, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 9, 9, 9, 0, 17, 17, 17, 0, 12, 12, 12, 0, 9, 9, 9, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 13, 13, 13, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 15, 15, 15, 0, 5, 5, 5, 0, 4, 4, 4, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 10, 10, 10, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 13, 13, 13, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 5, 5, 5, 0, 9, 9, 9, 0, 5, 5, 5, 0, 11, 11, 11, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 10, 10, 10, 0, 7, 7, 7, 0, 5, 5, 5, 0, 10, 10, 10, 0, 15, 15, 15, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 9, 9, 9, 0, 10, 10, 10, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 0, 0, 14, 14, 14, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 14, 14, 14, 0, 15, 15, 15, 0, 0, 0, 0, 0, 7, 7, 7, 0, 16, 16, 16, 0, 10, 10, 10, 0, 9, 9, 9, 0, 5, 5, 5, 0, 8, 8, 8, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 8, 8, 8, 0, 10, 10, 10, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 14, 14, 14, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 12, 12, 12, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 7, 7, 7, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 15, 15, 15, 0, 15, 15, 15, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 9, 9, 9, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 9, 9, 9, 0, 13, 13, 13, 0, 13, 13, 13, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 4, 4, 4, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 12, 12, 12, 0, 7, 7, 7, 0, 17, 17, 17, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 11, 11, 11, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 10, 10, 10, 0, 7, 7, 7, 0, 8, 8, 8, 0, 11, 11, 11, 0, 18, 18, 18, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 9, 9, 9, 0, 5, 5, 5, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 10, 10, 10, 0, 11, 11, 11, 0, 0, 0, 0, 0, 11, 11, 11, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 7, 7, 7, 0, 21, 21, 21, 0, 11, 11, 11, 0, 9, 9, 9, 0, 7, 7, 7, 0, 18, 18, 18, 0, 9, 9, 9, 0, 10, 10, 10, 0, 21, 21, 21, 0, 10, 10, 10, 0, 19, 19, 19, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 9, 9, 9, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 19, 19, 19, 0, 11, 11, 11, 0, 18, 18, 18, 0, 12, 12, 12, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 11, 11, 11, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 10, 10, 10, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 9, 9, 9, 0, 7, 7, 7, 0, 11, 11, 11, 0, 5, 5, 5, 0, 8, 8, 8, 0, 17, 17, 17, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 21, 21, 21, 0, 9, 9, 9, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 4, 4, 4, 0, 11, 11, 11, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 18, 18, 18, 0, 6, 6, 6, 0, 7, 7, 7, 0, 10, 10, 10, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 0, 0, 0, 0, 11, 11, 11, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 12, 12, 12, 0, 18, 18, 18, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 13, 13, 13, 0, 16, 16, 16, 0, 14, 14, 14, 0, 8, 8, 8, 0, 8, 8, 8, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 10, 10, 10, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 11, 11, 11, 0, 4, 4, 4, 0, 3, 3, 3, 0, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 9, 9, 9, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 8, 8, 8, 0, 20, 20, 20, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 9, 9, 9, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 13, 13, 13, 0, 0, 0, 0, 0, 13, 13, 13, 0, 8, 8, 8, 0, 9, 9, 9, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 21, 21, 21, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 12, 12, 12, 0, 9, 9, 9, 0, 5, 5, 5, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 18, 18, 18, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 3, 3, 3, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 21, 21, 21, 0, 12, 12, 12, 0, 17, 17, 17, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 10, 10, 10, 0, 21, 21, 21, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 17, 17, 17, 0, 13, 13, 13, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 10, 10, 10, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 13, 13, 13, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 21, 21, 21, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 11, 11, 11, 0, 9, 9, 9, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 7, 7, 7, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 15, 15, 15, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 14, 14, 14, 0, 5, 5, 5, 0, 5, 5, 5, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 12, 12, 12, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 21, 21, 21, 0, 6, 6, 6, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 6, 6, 6, 0, 7, 7, 7, 0, 4, 4, 4, 0, 6, 6, 6, 0, 11, 11, 11, 0, 6, 6, 6, 0, 6, 6, 6, 0, 16, 16, 16, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 12, 12, 12, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 8, 8, 8, 0, 15, 15, 15, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 20, 20, 20, 0, 6, 6, 6, 0, 5, 5, 5, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 6, 6, 6, 0, 19, 19, 19, 0, 11, 11, 11, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 16, 16, 16, 0, 0, 0, 0, 0, 16, 16, 16, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 4, 4, 4, 0, 0, 0, 0, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 18, 18, 18, 0, 9, 9, 9, 0, 15, 15, 15, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 19, 19, 19, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 7, 7, 7, 0, 15, 15, 15, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 20, 20, 20, 0, 12, 12, 12, 0, 6, 6, 6, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 5, 5, 5, 0, 10, 10, 10, 0, 5, 5, 5, 0, 12, 12, 12, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 12, 12, 12, 0, 4, 4, 4, 0, 7, 7, 7, 0, 7, 7, 7, 0, 15, 15, 15, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 17, 17, 17, 0, 9, 9, 9, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 12, 12, 12, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 18, 18, 18, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 10, 10, 10, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 16, 16, 16, 0, 9, 9, 9, 0, 13, 13, 13, 0, 19, 19, 19, 0, 17, 17, 17, 0, 8, 8, 8, 0, 0, 0, 0, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 0, 0, 0, 0, 8, 8, 8, 0, 11, 11, 11, 0, 12, 12, 12, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 10, 10, 10, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 16, 16, 16, 0, 11, 11, 11, 0, 12, 12, 12, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 9, 9, 9, 0, 18, 18, 18, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 10, 10, 10, 0, 10, 10, 10, 0, 5, 5, 5, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 21, 21, 21, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 0, 0, 0, 0, 15, 15, 15, 0, 9, 9, 9, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 17, 17, 17, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 10, 10, 10, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 3, 3, 3, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 17, 17, 17, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 9, 9, 9, 0, 6, 6, 6, 0, 11, 11, 11, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 9, 9, 9, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 17, 17, 17, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 8, 8, 8, 0, 5, 5, 5, 0, 8, 8, 8, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 10, 10, 10, 0, 5, 5, 5, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 6, 6, 6, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 15, 15, 15, 0, 9, 9, 9, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 19, 19, 19, 0, 10, 10, 10, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 12, 12, 12, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 15, 15, 15, 0, 20, 20, 20, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 6, 6, 6, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 19, 19, 19, 0, 20, 20, 20, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 5, 5, 5, 0, 12, 12, 12, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 11, 11, 11, 0, 5, 5, 5, 0, 13, 13, 13, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 7, 7, 7, 0, 9, 9, 9, 0, 5, 5, 5, 0, 9, 9, 9, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 10, 10, 10, 0, 12, 12, 12, 0, 5, 5, 5, 0, 6, 6, 6, 0, 12, 12, 12, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 9, 9, 9, 0, 7, 7, 7, 0, 9, 9, 9, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 13, 13, 13, 0, 8, 8, 8, 0, 13, 13, 13, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 21, 21, 21, 0, 13, 13, 13, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 7, 7, 7, 0, 16, 16, 16, 0, 13, 13, 13, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 14, 14, 14, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 11, 11, 11, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 11, 11, 11, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 13, 13, 13, 0, 8, 8, 8, 0, 6, 6, 6, 0, 8, 8, 8, 0, 11, 11, 11, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 19, 19, 19, 0, 0, 0, 0, 0, 15, 15, 15, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 6, 6, 6, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 0, 0, 0, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 11, 11, 11, 0, 13, 13, 13, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 15, 15, 15, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 18, 18, 18, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 8, 8, 8, 0, 18, 18, 18, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 11, 11, 11, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 14, 14, 14, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 19, 19, 19, 0, 13, 13, 13, 0, 10, 10, 10, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 8, 8, 8, 0, 14, 14, 14, 0, 11, 11, 11, 0, 6, 6, 6, 0, 5, 5, 5, 0, 12, 12, 12, 0, 6, 6, 6, 0, 9, 9, 9, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 12, 12, 12, 0, 11, 11, 11, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 18, 18, 18, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 20, 20, 20, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 10, 10, 10, 0, 5, 5, 5, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 20, 20, 20, 0, 11, 11, 11, 0, 9, 9, 9, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 11, 11, 11, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 7, 7, 7, 0, 0, 0, 0, 0, 7, 7, 7, 0, 15, 15, 15, 0, 5, 5, 5, 0, 4, 4, 4, 0, 7, 7, 7, 0, 12, 12, 12, 0, 8, 8, 8, 0, 11, 11, 11, 0, 16, 16, 16, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 9, 9, 9, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 16, 16, 16, 0, 6, 6, 6, 0, 15, 15, 15, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 11, 11, 11, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 14, 14, 14, 0, 12, 12, 12, 0, 18, 18, 18, 0, 11, 11, 11, 0, 17, 17, 17, 0, 13, 13, 13, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 10, 10, 10, 0, 8, 8, 8, 0, 19, 19, 19, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 10, 10, 10, 0, 9, 9, 9, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 12, 12, 12, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 6, 6, 6, 0, 0, 0, 0, 0, 21, 21, 21, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 15, 15, 15, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 11, 11, 11, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 15, 15, 15, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 12, 12, 12, 0, 21, 21, 21, 0, 19, 19, 19, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 6, 6, 6, 0, 9, 9, 9, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 6, 6, 6, 0, 9, 9, 9, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 8, 8, 8, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 7, 7, 7, 0, 15, 15, 15, 0, 19, 19, 19, 0, 17, 17, 17, 0, 19, 19, 19, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 14, 14, 14, 0, 4, 4, 4, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 12, 12, 12, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 13, 13, 13, 0, 13, 13, 13, 0, 0, 0, 0, 0, 12, 12, 12, 0, 14, 14, 14, 0, 13, 13, 13, 0, 14, 14, 14, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 12, 12, 12, 0, 14, 14, 14, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 10, 10, 10, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 16, 16, 16, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 19, 19, 19, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 8, 8, 8, 0, 7, 7, 7, 0, 12, 12, 12, 0, 20, 20, 20, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 5, 5, 5, 0, 5, 5, 5, 0, 18, 18, 18, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 5, 5, 5, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 7, 7, 7, 0, 5, 5, 5, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 10, 10, 10, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 13, 13, 13, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 12, 12, 12, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 19, 19, 19, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 11, 11, 11, 0, 12, 12, 12, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 5, 5, 5, 0, 7, 7, 7, 0, 18, 18, 18, 0, 12, 12, 12, 0, 16, 16, 16, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 13, 13, 13, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 11, 11, 11, 0, 6, 6, 6, 0, 12, 12, 12, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 0, 0, 0, 0, 7, 7, 7, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 8, 8, 8, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 5, 5, 5, 0, 4, 4, 4, 0, 20, 20, 20, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 11, 11, 11, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 10, 10, 10, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 6, 6, 6, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 9, 9, 9, 0, 8, 8, 8, 0, 4, 4, 4, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 19, 19, 19, 0, 17, 17, 17, 0, 18, 18, 18, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 17, 17, 17, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 14, 14, 14, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 8, 8, 8, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 13, 13, 13, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 7, 7, 7, 0, 20, 20, 20, 0, 0, 0, 0, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 6, 6, 6, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 18, 18, 18, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 10, 10, 10, 0, 14, 14, 14, 0, 16, 16, 16, 0, 16, 16, 16, 0, 8, 8, 8, 0, 6, 6, 6, 0, 9, 9, 9, 0, 6, 6, 6, 0, 7, 7, 7, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 13, 13, 13, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 13, 13, 13, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 13, 13, 13, 0, 6, 6, 6, 0, 16, 16, 16, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 5, 5, 5, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 5, 5, 5, 0, 6, 6, 6, 0, 21, 21, 21, 0, 0, 0, 0, 0, 12, 12, 12, 0, 18, 18, 18, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 18, 18, 18, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 21, 21, 21, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 14, 14, 14, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 11, 11, 11, 0, 6, 6, 6, 0, 19, 19, 19, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 7, 7, 7, 0, 16, 16, 16, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 9, 9, 9, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 5, 5, 5, 0, 9, 9, 9, 0, 11, 11, 11, 0, 8, 8, 8, 0, 9, 9, 9, 0, 21, 21, 21, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 14, 14, 14, 0, 8, 8, 8, 0, 9, 9, 9, 0, 0, 0, 0, 0, 14, 14, 14, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 10, 10, 10, 0, 16, 16, 16, 0, 11, 11, 11, 0, 12, 12, 12, 0, 0, 0, 0, 0, 7, 7, 7, 0, 12, 12, 12, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 11, 11, 11, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 15, 15, 15, 0, 9, 9, 9, 0, 0, 0, 0, 0, 6, 6, 6, 0, 19, 19, 19, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 8, 8, 8, 0, 4, 4, 4, 0, 6, 6, 6, 0, 14, 14, 14, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 14, 14, 14, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 9, 9, 9, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 9, 9, 9, 0, 5, 5, 5, 0, 6, 6, 6, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 5, 5, 5, 0, 21, 21, 21, 0, 10, 10, 10, 0, 5, 5, 5, 0, 14, 14, 14, 0, 9, 9, 9, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 16, 16, 16, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 19, 19, 19, 0, 14, 14, 14, 0, 0, 0, 0, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 0, 0, 0, 0, 9, 9, 9, 0, 20, 20, 20, 0, 19, 19, 19, 0, 17, 17, 17, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 15, 15, 15, 0, 6, 6, 6, 0, 11, 11, 11, 0, 7, 7, 7, 0, 11, 11, 11, 0, 14, 14, 14, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 12, 12, 12, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 16, 16, 16, 0, 12, 12, 12, 0, 9, 9, 9, 0, 17, 17, 17, 0, 14, 14, 14, 0, 15, 15, 15, 0, 11, 11, 11, 0, 6, 6, 6, 0, 17, 17, 17, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 10, 10, 10, 0, 16, 16, 16, 0, 9, 9, 9, 0, 9, 9, 9, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 14, 14, 14, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 11, 11, 11, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 10, 10, 10, 0, 9, 9, 9, 0, 20, 20, 20, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 16, 16, 16, 0, 5, 5, 5, 0, 8, 8, 8, 0, 5, 5, 5, 0, 10, 10, 10, 0, 6, 6, 6, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 9, 9, 9, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 12, 12, 12, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 7, 7, 7, 0, 5, 5, 5, 0, 8, 8, 8, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 11, 11, 11, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 12, 12, 12, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 8, 8, 8, 0, 5, 5, 5, 0, 19, 19, 19, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 9, 9, 9, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 7, 7, 7, 0, 4, 4, 4, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 18, 18, 18, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 11, 11, 11, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 9, 9, 9, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 6, 6, 6, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 11, 11, 11, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 18, 18, 18, 0, 15, 15, 15, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 6, 6, 6, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 12, 12, 12, 0, 5, 5, 5, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 6, 6, 6, 0, 5, 5, 5, 0, 9, 9, 9, 0, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 17, 17, 17, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 12, 12, 12, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 6, 6, 6, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 13, 13, 13, 0, 8, 8, 8, 0, 10, 10, 10, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 5, 5, 5, 0, 8, 8, 8, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 16, 16, 16, 0, 7, 7, 7, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 12, 12, 12, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 15, 15, 15, 0, 12, 12, 12, 0, 21, 21, 21, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 15, 15, 15, 0, 11, 11, 11, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 10, 10, 10, 0, 6, 6, 6, 0, 6, 6, 6, 0, 10, 10, 10, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 13, 13, 13, 0, 12, 12, 12, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 7, 7, 7, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 9, 9, 9, 0, 14, 14, 14, 0, 11, 11, 11, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 13, 13, 13, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 10, 10, 10, 0, 10, 10, 10, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 7, 7, 7, 0, 8, 8, 8, 0, 11, 11, 11, 0, 5, 5, 5, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 9, 9, 9, 0, 19, 19, 19, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 7, 7, 7, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 21, 21, 21, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 11, 11, 11, 0, 12, 12, 12, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 8, 8, 8, 0, 6, 6, 6, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 19, 19, 19, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 10, 10, 10, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 6, 6, 6, 0, 17, 17, 17, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 5, 5, 5, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 12, 12, 12, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 11, 11, 11, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 19, 19, 19, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 6, 6, 6, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 7, 7, 7, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 11, 11, 11, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 8, 8, 8, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 13, 13, 13, 0, 10, 10, 10, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 17, 17, 17, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 16, 16, 16, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 10, 10, 10, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 5, 5, 5, 0, 8, 8, 8, 0, 0, 0, 0, 0, 18, 18, 18, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 14, 14, 14, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 10, 10, 10, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 15, 15, 15, 0, 8, 8, 8, 0, 9, 9, 9, 0, 7, 7, 7, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 11, 11, 11, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 15, 15, 15, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 13, 13, 13, 0, 7, 7, 7, 0, 8, 8, 8, 0, 10, 10, 10, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 6, 6, 6, 0, 10, 10, 10, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 10, 10, 10, 0, 6, 6, 6, 0, 15, 15, 15, 0, 21, 21, 21, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 21, 21, 21, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 19, 19, 19, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 8, 8, 8, 0, 13, 13, 13, 0, 9, 9, 9, 0, 11, 11, 11, 0, 6, 6, 6, 0, 10, 10, 10, 0, 0, 0, 0, 0, 9, 9, 9, 0, 19, 19, 19, 0, 0, 0, 0, 0, 13, 13, 13, 0, 12, 12, 12, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 12, 12, 12, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 9, 9, 9, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 7, 7, 7, 0, 5, 5, 5, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 12, 12, 12, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 9, 9, 9, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 10, 10, 10, 0, 10, 10, 10, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 5, 5, 5, 0, 7, 7, 7, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 9, 9, 9, 0, 4, 4, 4, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 5, 5, 5, 0, 10, 10, 10, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 12, 12, 12, 0, 12, 12, 12, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 11, 11, 11, 0, 8, 8, 8, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 9, 9, 9, 0, 14, 14, 14, 0, 10, 10, 10, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 7, 7, 7, 0, 11, 11, 11, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 16, 16, 16, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 6, 6, 6, 0, 5, 5, 5, 0, 8, 8, 8, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 11, 11, 11, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 10, 10, 10, 0, 0, 0, 0, 0, 10, 10, 10, 0, 10, 10, 10, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 8, 8, 8, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 12, 12, 12, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 5, 5, 5, 0, 4, 4, 4, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 9, 9, 9, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 0, 0, 0, 0, 7, 7, 7, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 5, 5, 5, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 11, 11, 11, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 6, 6, 6, 0, 19, 19, 19, 0, 7, 7, 7, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 7, 7, 7, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 0, 0, 0, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0]"; +var mandelbrotImageDataModdedResult = "[1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 12, 12, 12, 0, 14, 14, 14, 0, 12, 12, 12, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 16, 16, 16, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 14, 14, 14, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 17, 17, 17, 0, 13, 13, 13, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 15, 15, 15, 0, 0, 0, 0, 0, 18, 18, 18, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 14, 14, 14, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 13, 13, 13, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 16, 16, 16, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 17, 17, 17, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 4, 4, 4, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 13, 13, 13, 0, 21, 21, 21, 0, 15, 15, 15, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 7, 7, 7, 0, 13, 13, 13, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 7, 7, 7, 0, 17, 17, 17, 0, 20, 20, 20, 0, 15, 15, 15, 0, 16, 16, 16, 0, 19, 19, 19, 0, 12, 12, 12, 0, 9, 9, 9, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 6, 6, 6, 0, 7, 7, 7, 0, 10, 10, 10, 0, 4, 4, 4, 0, 13, 13, 13, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 15, 15, 15, 0, 21, 21, 21, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 14, 14, 14, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 14, 14, 14, 0, 10, 10, 10, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 12, 12, 12, 0, 16, 16, 16, 0, 8, 8, 8, 0, 19, 19, 19, 0, 5, 5, 5, 0, 5, 5, 5, 0, 17, 17, 17, 0, 4, 4, 4, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 12, 12, 12, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 14, 14, 14, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 17, 17, 17, 0, 17, 17, 17, 0, 13, 13, 13, 0, 18, 18, 18, 0, 14, 14, 14, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 3, 3, 3, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 20, 20, 20, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 5, 5, 5, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 17, 17, 17, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 16, 16, 16, 0, 18, 18, 18, 0, 15, 15, 15, 0, 11, 11, 11, 0, 10, 10, 10, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 15, 15, 15, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 18, 18, 18, 0, 14, 14, 14, 0, 11, 11, 11, 0, 9, 9, 9, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 17, 17, 17, 0, 17, 17, 17, 0, 16, 16, 16, 0, 2, 2, 2, 0, 12, 12, 12, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 17, 17, 17, 0, 13, 13, 13, 0, 11, 11, 11, 0, 12, 12, 12, 0, 6, 6, 6, 0, 12, 12, 12, 0, 12, 12, 12, 0, 17, 17, 17, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 14, 14, 14, 0, 16, 16, 16, 0, 5, 5, 5, 0, 7, 7, 7, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 14, 14, 14, 0, 16, 16, 16, 0, 14, 14, 14, 0, 16, 16, 16, 0, 8, 8, 8, 0, 3, 3, 3, 0, 15, 15, 15, 0, 16, 16, 16, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 15, 15, 15, 0, 3, 3, 3, 0, 5, 5, 5, 0, 19, 19, 19, 0, 21, 21, 21, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 20, 20, 20, 0, 7, 7, 7, 0, 19, 19, 19, 0, 0, 0, 0, 0, 10, 10, 10, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 20, 20, 20, 0, 17, 17, 17, 0, 16, 16, 16, 0, 7, 7, 7, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 18, 18, 18, 0, 18, 18, 18, 0, 14, 14, 14, 0, 14, 14, 14, 0, 19, 19, 19, 0, 15, 15, 15, 0, 12, 12, 12, 0, 11, 11, 11, 0, 12, 12, 12, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 19, 19, 19, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 4, 4, 4, 0, 18, 18, 18, 0, 19, 19, 19, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 6, 6, 6, 0, 18, 18, 18, 0, 18, 18, 18, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 18, 18, 18, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 17, 17, 17, 0, 14, 14, 14, 0, 20, 20, 20, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 5, 5, 5, 0, 0, 0, 0, 0, 21, 21, 21, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 1, 1, 1, 0, 7, 7, 7, 0, 16, 16, 16, 0, 15, 15, 15, 0, 16, 16, 16, 0, 20, 20, 20, 0, 5, 5, 5, 0, 17, 17, 17, 0, 20, 20, 20, 0, 15, 15, 15, 0, 16, 16, 16, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 17, 17, 17, 0, 10, 10, 10, 0, 18, 18, 18, 0, 5, 5, 5, 0, 21, 21, 21, 0, 21, 21, 21, 0, 15, 15, 15, 0, 14, 14, 14, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 2, 2, 2, 0, 16, 16, 16, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 17, 17, 17, 0, 2, 2, 2, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 3, 3, 3, 0, 5, 5, 5, 0, 17, 17, 17, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 20, 20, 20, 0, 20, 20, 20, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 15, 15, 15, 0, 19, 19, 19, 0, 18, 18, 18, 0, 9, 9, 9, 0, 1, 1, 1, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 15, 15, 15, 0, 3, 3, 3, 0, 1, 1, 1, 0, 9, 9, 9, 0, 3, 3, 3, 0, 20, 20, 20, 0, 14, 14, 14, 0, 20, 20, 20, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 17, 17, 17, 0, 7, 7, 7, 0, 14, 14, 14, 0, 5, 5, 5, 0, 0, 0, 0, 0, 1, 1, 1, 0, 5, 5, 5, 0, 17, 17, 17, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 19, 19, 19, 0, 3, 3, 3, 0, 18, 18, 18, 0, 3, 3, 3, 0, 19, 19, 19, 0, 4, 4, 4, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 2, 2, 2, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 4, 4, 4, 0, 17, 17, 17, 0, 1, 1, 1, 0, 17, 17, 17, 0, 16, 16, 16, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 15, 15, 15, 0, 21, 21, 21, 0, 15, 15, 15, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 4, 4, 4, 0, 8, 8, 8, 0, 7, 7, 7, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 5, 5, 5, 0, 21, 21, 21, 0, 15, 15, 15, 0, 15, 15, 15, 0, 19, 19, 19, 0, 19, 19, 19, 0, 21, 21, 21, 0, 21, 21, 21, 0, 6, 6, 6, 0, 5, 5, 5, 0, 20, 20, 20, 0, 19, 19, 19, 0, 6, 6, 6, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 3, 3, 3, 0, 17, 17, 17, 0, 1, 1, 1, 0, 16, 16, 16, 0, 17, 17, 17, 0, 14, 14, 14, 0, 19, 19, 19, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 5, 5, 5, 0, 7, 7, 7, 0, 5, 5, 5, 0, 17, 17, 17, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 19, 19, 19, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 2, 2, 2, 0, 2, 2, 2, 0, 14, 14, 14, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 21, 21, 21, 0, 3, 3, 3, 0, 9, 9, 9, 0, 17, 17, 17, 0, 6, 6, 6, 0, 1, 1, 1, 0, 21, 21, 21, 0, 19, 19, 19, 0, 20, 20, 20, 0, 1, 1, 1, 0, 10, 10, 10, 0, 7, 7, 7, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 9, 9, 9, 0, 3, 3, 3, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 10, 10, 10, 0, 15, 15, 15, 0, 16, 16, 16, 0, 12, 12, 12, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 3, 3, 3, 0, 15, 15, 15, 0, 21, 21, 21, 0, 18, 18, 18, 0, 20, 20, 20, 0, 12, 12, 12, 0, 8, 8, 8, 0, 3, 3, 3, 0, 18, 18, 18, 0, 9, 9, 9, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 4, 4, 4, 0, 20, 20, 20, 0, 19, 19, 19, 0, 17, 17, 17, 0, 18, 18, 18, 0, 12, 12, 12, 0, 18, 18, 18, 0, 15, 15, 15, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 20, 20, 20, 0, 15, 15, 15, 0, 15, 15, 15, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 17, 17, 17, 0, 4, 4, 4, 0, 10, 10, 10, 0, 20, 20, 20, 0, 3, 3, 3, 0, 4, 4, 4, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 10, 10, 10, 0, 13, 13, 13, 0, 2, 2, 2, 0, 6, 6, 6, 0, 3, 3, 3, 0, 15, 15, 15, 0, 2, 2, 2, 0, 18, 18, 18, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 19, 19, 19, 0, 14, 14, 14, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 18, 18, 18, 0, 20, 20, 20, 0, 8, 8, 8, 0, 18, 18, 18, 0, 18, 18, 18, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 5, 5, 5, 0, 20, 20, 20, 0, 13, 13, 13, 0, 9, 9, 9, 0, 18, 18, 18, 0, 20, 20, 20, 0, 20, 20, 20, 0, 1, 1, 1, 0, 12, 12, 12, 0, 14, 14, 14, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 21, 21, 21, 0, 19, 19, 19, 0, 13, 13, 13, 0, 5, 5, 5, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 21, 21, 21, 0, 1, 1, 1, 0, 9, 9, 9, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 4, 4, 4, 0, 6, 6, 6, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 13, 13, 13, 0, 15, 15, 15, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 18, 18, 18, 0, 4, 4, 4, 0, 7, 7, 7, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 17, 17, 17, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 21, 21, 21, 0, 12, 12, 12, 0, 17, 17, 17, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 10, 10, 10, 0, 3, 3, 3, 0, 12, 12, 12, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 11, 11, 11, 0, 3, 3, 3, 0, 3, 3, 3, 0, 21, 21, 21, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 15, 15, 15, 0, 20, 20, 20, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 16, 16, 16, 0, 14, 14, 14, 0, 18, 18, 18, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 15, 15, 15, 0, 2, 2, 2, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 20, 20, 20, 0, 4, 4, 4, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 18, 18, 18, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 5, 5, 5, 0, 14, 14, 14, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 1, 1, 1, 0, 14, 14, 14, 0, 18, 18, 18, 0, 16, 16, 16, 0, 15, 15, 15, 0, 17, 17, 17, 0, 3, 3, 3, 0, 1, 1, 1, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 18, 18, 18, 0, 21, 21, 21, 0, 18, 18, 18, 0, 3, 3, 3, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 20, 20, 20, 0, 3, 3, 3, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 11, 11, 11, 0, 2, 2, 2, 0, 21, 21, 21, 0, 18, 18, 18, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 15, 15, 15, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 14, 14, 14, 0, 17, 17, 17, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 10, 10, 10, 0, 15, 15, 15, 0, 3, 3, 3, 0, 13, 13, 13, 0, 12, 12, 12, 0, 14, 14, 14, 0, 12, 12, 12, 0, 1, 1, 1, 0, 15, 15, 15, 0, 13, 13, 13, 0, 10, 10, 10, 0, 21, 21, 21, 0, 6, 6, 6, 0, 7, 7, 7, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 19, 19, 19, 0, 5, 5, 5, 0, 15, 15, 15, 0, 9, 9, 9, 0, 19, 19, 19, 0, 19, 19, 19, 0, 1, 1, 1, 0, 7, 7, 7, 0, 1, 1, 1, 0, 4, 4, 4, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 2, 2, 2, 0, 19, 19, 19, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 4, 4, 4, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 18, 18, 18, 0, 17, 17, 17, 0, 19, 19, 19, 0, 1, 1, 1, 0, 17, 17, 17, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 19, 19, 19, 0, 21, 21, 21, 0, 15, 15, 15, 0, 18, 18, 18, 0, 15, 15, 15, 0, 16, 16, 16, 0, 5, 5, 5, 0, 8, 8, 8, 0, 3, 3, 3, 0, 5, 5, 5, 0, 18, 18, 18, 0, 20, 20, 20, 0, 11, 11, 11, 0, 9, 9, 9, 0, 18, 18, 18, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 19, 19, 19, 0, 4, 4, 4, 0, 17, 17, 17, 0, 12, 12, 12, 0, 1, 1, 1, 0, 5, 5, 5, 0, 8, 8, 8, 0, 6, 6, 6, 0, 10, 10, 10, 0, 10, 10, 10, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 17, 17, 17, 0, 5, 5, 5, 0, 1, 1, 1, 0, 20, 20, 20, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 21, 21, 21, 0, 14, 14, 14, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 9, 9, 9, 0, 20, 20, 20, 0, 19, 19, 19, 0, 18, 18, 18, 0, 14, 14, 14, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 9, 9, 9, 0, 21, 21, 21, 0, 5, 5, 5, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 21, 21, 21, 0, 15, 15, 15, 0, 20, 20, 20, 0, 18, 18, 18, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 2, 2, 2, 0, 11, 11, 11, 0, 5, 5, 5, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 2, 2, 0, 8, 8, 8, 0, 0, 0, 0, 0, 1, 1, 1, 0, 17, 17, 17, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 19, 19, 19, 0, 12, 12, 12, 0, 8, 8, 8, 0, 4, 4, 4, 0, 7, 7, 7, 0, 2, 2, 2, 0, 19, 19, 19, 0, 19, 19, 19, 0, 9, 9, 9, 0, 20, 20, 20, 0, 16, 16, 16, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 2, 2, 2, 0, 1, 1, 1, 0, 11, 11, 11, 0, 17, 17, 17, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 18, 18, 18, 0, 6, 6, 6, 0, 3, 3, 3, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 19, 19, 19, 0, 17, 17, 17, 0, 1, 1, 1, 0, 2, 2, 2, 0, 17, 17, 17, 0, 17, 17, 17, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 19, 19, 19, 0, 19, 19, 19, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 14, 14, 14, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 11, 11, 11, 0, 5, 5, 5, 0, 1, 1, 1, 0, 1, 1, 1, 0, 4, 4, 4, 0, 3, 3, 3, 0, 1, 1, 1, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 17, 17, 17, 0, 11, 11, 11, 0, 19, 19, 19, 0, 15, 15, 15, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 17, 17, 17, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 10, 10, 10, 0, 3, 3, 3, 0, 20, 20, 20, 0, 1, 1, 1, 0, 7, 7, 7, 0, 10, 10, 10, 0, 21, 21, 21, 0, 20, 20, 20, 0, 4, 4, 4, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 18, 18, 18, 0, 1, 1, 1, 0, 17, 17, 17, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 3, 3, 3, 0, 18, 18, 18, 0, 18, 18, 18, 0, 16, 16, 16, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 12, 12, 12, 0, 11, 11, 11, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 11, 11, 11, 0, 5, 5, 5, 0, 2, 2, 2, 0, 5, 5, 5, 0, 1, 1, 1, 0, 21, 21, 21, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 8, 8, 8, 0, 17, 17, 17, 0, 17, 17, 17, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 18, 18, 18, 0, 21, 21, 21, 0, 10, 10, 10, 0, 15, 15, 15, 0, 8, 8, 8, 0, 15, 15, 15, 0, 17, 17, 17, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 20, 20, 20, 0, 8, 8, 8, 0, 7, 7, 7, 0, 8, 8, 8, 0, 13, 13, 13, 0, 2, 2, 2, 0, 8, 8, 8, 0, 15, 15, 15, 0, 21, 21, 21, 0, 10, 10, 10, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 20, 20, 20, 0, 19, 19, 19, 0, 16, 16, 16, 0, 18, 18, 18, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 1, 1, 1, 0, 1, 1, 1, 0, 19, 19, 19, 0, 21, 21, 21, 0, 10, 10, 10, 0, 16, 16, 16, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 17, 17, 17, 0, 13, 13, 13, 0, 3, 3, 3, 0, 19, 19, 19, 0, 0, 0, 0, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 8, 8, 8, 0, 3, 3, 3, 0, 1, 1, 1, 0, 5, 5, 5, 0, 7, 7, 7, 0, 19, 19, 19, 0, 18, 18, 18, 0, 19, 19, 19, 0, 20, 20, 20, 0, 10, 10, 10, 0, 14, 14, 14, 0, 17, 17, 17, 0, 16, 16, 16, 0, 18, 18, 18, 0, 5, 5, 5, 0, 14, 14, 14, 0, 21, 21, 21, 0, 17, 17, 17, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 17, 17, 17, 0, 20, 20, 20, 0, 1, 1, 1, 0, 5, 5, 5, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 18, 18, 18, 0, 6, 6, 6, 0, 1, 1, 1, 0, 14, 14, 14, 0, 7, 7, 7, 0, 7, 7, 7, 0, 1, 1, 1, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 3, 3, 3, 0, 12, 12, 12, 0, 18, 18, 18, 0, 11, 11, 11, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 15, 15, 15, 0, 16, 16, 16, 0, 18, 18, 18, 0, 1, 1, 1, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 12, 12, 12, 0, 16, 16, 16, 0, 20, 20, 20, 0, 1, 1, 1, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 17, 17, 17, 0, 10, 10, 10, 0, 18, 18, 18, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 21, 21, 21, 0, 11, 11, 11, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 9, 9, 9, 0, 16, 16, 16, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 2, 2, 2, 0, 5, 5, 5, 0, 5, 5, 5, 0, 19, 19, 19, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 5, 5, 5, 0, 4, 4, 4, 0, 13, 13, 13, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 10, 10, 10, 0, 2, 2, 2, 0, 15, 15, 15, 0, 17, 17, 17, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 18, 18, 18, 0, 20, 20, 20, 0, 2, 2, 2, 0, 8, 8, 8, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 11, 11, 11, 0, 3, 3, 3, 0, 20, 20, 20, 0, 18, 18, 18, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 8, 8, 8, 0, 4, 4, 4, 0, 11, 11, 11, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 7, 7, 7, 0, 3, 3, 3, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 1, 1, 1, 0, 18, 18, 18, 0, 14, 14, 14, 0, 18, 18, 18, 0, 16, 16, 16, 0, 17, 17, 17, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 13, 13, 13, 0, 15, 15, 15, 0, 3, 3, 3, 0, 18, 18, 18, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 17, 17, 17, 0, 19, 19, 19, 0, 19, 19, 19, 0, 20, 20, 20, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 13, 13, 13, 0, 4, 4, 4, 0, 21, 21, 21, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 17, 17, 17, 0, 16, 16, 16, 0, 7, 7, 7, 0, 2, 2, 2, 0, 20, 20, 20, 0, 20, 20, 20, 0, 4, 4, 4, 0, 10, 10, 10, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 7, 7, 7, 0, 20, 20, 20, 0, 17, 17, 17, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 12, 12, 12, 0, 8, 8, 8, 0, 15, 15, 15, 0, 5, 5, 5, 0, 10, 10, 10, 0, 3, 3, 3, 0, 2, 2, 2, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 7, 7, 7, 0, 6, 6, 6, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 12, 12, 12, 0, 16, 16, 16, 0, 20, 20, 20, 0, 21, 21, 21, 0, 20, 20, 20, 0, 20, 20, 20, 0, 7, 7, 7, 0, 13, 13, 13, 0, 10, 10, 10, 0, 9, 9, 9, 0, 15, 15, 15, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 1, 1, 1, 0, 19, 19, 19, 0, 19, 19, 19, 0, 6, 6, 6, 0, 11, 11, 11, 0, 6, 6, 6, 0, 18, 18, 18, 0, 7, 7, 7, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 16, 16, 16, 0, 5, 5, 5, 0, 5, 5, 5, 0, 18, 18, 18, 0, 17, 17, 17, 0, 8, 8, 8, 0, 5, 5, 5, 0, 18, 18, 18, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 12, 12, 12, 0, 20, 20, 20, 0, 21, 21, 21, 0, 3, 3, 3, 0, 4, 4, 4, 0, 18, 18, 18, 0, 19, 19, 19, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 13, 13, 13, 0, 14, 14, 14, 0, 2, 2, 2, 0, 15, 15, 15, 0, 16, 16, 16, 0, 19, 19, 19, 0, 5, 5, 5, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 20, 20, 20, 0, 9, 9, 9, 0, 4, 4, 4, 0, 2, 2, 2, 0, 8, 8, 8, 0, 8, 8, 8, 0, 13, 13, 13, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 17, 17, 17, 0, 20, 20, 20, 0, 9, 9, 9, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 12, 12, 12, 0, 15, 15, 15, 0, 9, 9, 9, 0, 21, 21, 21, 0, 9, 9, 9, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 20, 20, 20, 0, 21, 21, 21, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 8, 8, 8, 0, 19, 19, 19, 0, 16, 16, 16, 0, 6, 6, 6, 0, 4, 4, 4, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 19, 19, 19, 0, 1, 1, 1, 0, 18, 18, 18, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 21, 21, 21, 0, 7, 7, 7, 0, 11, 11, 11, 0, 7, 7, 7, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 17, 17, 17, 0, 19, 19, 19, 0, 16, 16, 16, 0, 3, 3, 3, 0, 5, 5, 5, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 10, 10, 10, 0, 16, 16, 16, 0, 20, 20, 20, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 15, 15, 15, 0, 21, 21, 21, 0, 8, 8, 8, 0, 7, 7, 7, 0, 9, 9, 9, 0, 6, 6, 6, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 1, 1, 1, 0, 20, 20, 20, 0, 17, 17, 17, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 15, 15, 15, 0, 11, 11, 11, 0, 17, 17, 17, 0, 17, 17, 17, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 5, 5, 5, 0, 5, 5, 5, 0, 12, 12, 12, 0, 9, 9, 9, 0, 16, 16, 16, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 4, 4, 4, 0, 16, 16, 16, 0, 20, 20, 20, 0, 5, 5, 5, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 10, 10, 10, 0, 21, 21, 21, 0, 21, 21, 21, 0, 17, 17, 17, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 18, 18, 18, 0, 4, 4, 4, 0, 10, 10, 10, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 19, 19, 19, 0, 4, 4, 4, 0, 16, 16, 16, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 1, 1, 1, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 5, 5, 5, 0, 15, 15, 15, 0, 11, 11, 11, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 17, 17, 17, 0, 15, 15, 15, 0, 19, 19, 19, 0, 18, 18, 18, 0, 16, 16, 16, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 15, 15, 15, 0, 15, 15, 15, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 3, 3, 3, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 10, 10, 10, 0, 6, 6, 6, 0, 20, 20, 20, 0, 16, 16, 16, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 13, 13, 13, 0, 10, 10, 10, 0, 19, 19, 19, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 16, 16, 16, 0, 1, 1, 1, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 6, 6, 6, 0, 4, 4, 4, 0, 18, 18, 18, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 5, 5, 5, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 12, 12, 12, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 13, 13, 13, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 6, 6, 6, 0, 16, 16, 16, 0, 3, 3, 3, 0, 18, 18, 18, 0, 13, 13, 13, 0, 19, 19, 19, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 11, 11, 11, 0, 17, 17, 17, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 2, 2, 2, 0, 16, 16, 16, 0, 7, 7, 7, 0, 17, 17, 17, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 6, 6, 6, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 14, 14, 14, 0, 13, 13, 13, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 16, 16, 16, 0, 20, 20, 20, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 16, 16, 16, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 14, 14, 14, 0, 3, 3, 3, 0, 1, 1, 1, 0, 18, 18, 18, 0, 18, 18, 18, 0, 15, 15, 15, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 20, 20, 20, 0, 20, 20, 20, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 18, 18, 18, 0, 20, 20, 20, 0, 12, 12, 12, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 15, 15, 15, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 2, 2, 2, 0, 16, 16, 16, 0, 19, 19, 19, 0, 3, 3, 3, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 16, 16, 16, 0, 6, 6, 6, 0, 16, 16, 16, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 9, 9, 9, 0, 5, 5, 5, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 11, 11, 11, 0, 6, 6, 6, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 17, 17, 17, 0, 14, 14, 14, 0, 2, 2, 2, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 1, 1, 1, 0, 1, 1, 1, 0, 18, 18, 18, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 13, 13, 13, 0, 17, 17, 17, 0, 12, 12, 12, 0, 11, 11, 11, 0, 13, 13, 13, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 13, 13, 13, 0, 19, 19, 19, 0, 4, 4, 4, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 19, 19, 19, 0, 2, 2, 2, 0, 15, 15, 15, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 19, 19, 19, 0, 18, 18, 18, 0, 17, 17, 17, 0, 2, 2, 2, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 19, 19, 19, 0, 9, 9, 9, 0, 16, 16, 16, 0, 2, 2, 2, 0, 21, 21, 21, 0, 14, 14, 14, 0, 18, 18, 18, 0, 11, 11, 11, 0, 6, 6, 6, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 20, 20, 20, 0, 2, 2, 2, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 4, 4, 4, 0, 9, 9, 9, 0, 1, 1, 1, 0, 19, 19, 19, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 19, 19, 19, 0, 13, 13, 13, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 2, 2, 2, 0, 10, 10, 10, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 16, 16, 16, 0, 3, 3, 3, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 15, 15, 15, 0, 16, 16, 16, 0, 15, 15, 15, 0, 10, 10, 10, 0, 18, 18, 18, 0, 14, 14, 14, 0, 13, 13, 13, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 6, 6, 6, 0, 2, 2, 2, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 20, 20, 20, 0, 20, 20, 20, 0, 3, 3, 3, 0, 11, 11, 11, 0, 19, 19, 19, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 18, 18, 18, 0, 19, 19, 19, 0, 15, 15, 15, 0, 21, 21, 21, 0, 2, 2, 2, 0, 12, 12, 12, 0, 9, 9, 9, 0, 10, 10, 10, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 9, 9, 9, 0, 15, 15, 15, 0, 14, 14, 14, 0, 2, 2, 2, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 20, 20, 20, 0, 2, 2, 2, 0, 4, 4, 4, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 6, 6, 6, 0, 1, 1, 1, 0, 20, 20, 20, 0, 19, 19, 19, 0, 17, 17, 17, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 1, 1, 1, 0, 12, 12, 12, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 5, 5, 5, 0, 6, 6, 6, 0, 14, 14, 14, 0, 20, 20, 20, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 19, 19, 19, 0, 19, 19, 19, 0, 14, 14, 14, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 18, 18, 18, 0, 6, 6, 6, 0, 15, 15, 15, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 15, 15, 15, 0, 5, 5, 5, 0, 20, 20, 20, 0, 15, 15, 15, 0, 15, 15, 15, 0, 21, 21, 21, 0, 13, 13, 13, 0, 3, 3, 3, 0, 16, 16, 16, 0, 21, 21, 21, 0, 15, 15, 15, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 18, 18, 18, 0, 3, 3, 3, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 8, 8, 8, 0, 21, 21, 21, 0, 21, 21, 21, 0, 18, 18, 18, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 3, 3, 3, 0, 4, 4, 4, 0, 13, 13, 13, 0, 13, 13, 13, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 18, 18, 18, 0, 18, 18, 18, 0, 19, 19, 19, 0, 20, 20, 20, 0, 1, 1, 1, 0, 2, 2, 2, 0, 5, 5, 5, 0, 18, 18, 18, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 6, 6, 6, 0, 2, 2, 2, 0, 1, 1, 1, 0, 20, 20, 20, 0, 19, 19, 19, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 20, 20, 20, 0, 15, 15, 15, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 2, 2, 2, 0, 21, 21, 21, 0, 18, 18, 18, 0, 4, 4, 4, 0, 11, 11, 11, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 4, 4, 4, 0, 12, 12, 12, 0, 2, 2, 2, 0, 16, 16, 16, 0, 18, 18, 18, 0, 13, 13, 13, 0, 19, 19, 19, 0, 2, 2, 2, 0, 14, 14, 14, 0, 19, 19, 19, 0, 19, 19, 19, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 14, 14, 14, 0, 2, 2, 2, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 20, 20, 20, 0, 4, 4, 4, 0, 15, 15, 15, 0, 9, 9, 9, 0, 16, 16, 16, 0, 15, 15, 15, 0, 16, 16, 16, 0, 1, 1, 1, 0, 21, 21, 21, 0, 17, 17, 17, 0, 16, 16, 16, 0, 5, 5, 5, 0, 10, 10, 10, 0, 20, 20, 20, 0, 18, 18, 18, 0, 20, 20, 20, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 15, 15, 15, 0, 14, 14, 14, 0, 21, 21, 21, 0, 20, 20, 20, 0, 6, 6, 6, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 1, 1, 1, 0, 4, 4, 4, 0, 13, 13, 13, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 3, 3, 3, 0, 6, 6, 6, 0, 14, 14, 14, 0, 20, 20, 20, 0, 3, 3, 3, 0, 17, 17, 17, 0, 15, 15, 15, 0, 16, 16, 16, 0, 20, 20, 20, 0, 14, 14, 14, 0, 7, 7, 7, 0, 20, 20, 20, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 21, 21, 21, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 21, 21, 21, 0, 1, 1, 1, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 7, 7, 7, 0, 4, 4, 4, 0, 2, 2, 2, 0, 1, 1, 1, 0, 21, 21, 21, 0, 20, 20, 20, 0, 19, 19, 19, 0, 18, 18, 18, 0, 18, 18, 18, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 16, 16, 16, 0, 2, 2, 2, 0, 8, 8, 8, 0, 3, 3, 3, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 2, 2, 2, 0, 5, 5, 5, 0, 21, 21, 21, 0, 13, 13, 13, 0, 2, 2, 2, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 4, 4, 4, 0, 15, 15, 15, 0, 1, 1, 1, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 14, 14, 14, 0, 7, 7, 7, 0, 3, 3, 3, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 16, 16, 16, 0, 17, 17, 17, 0, 6, 6, 6, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 14, 14, 14, 0, 15, 15, 15, 0, 5, 5, 5, 0, 2, 2, 2, 0, 3, 3, 3, 0, 19, 19, 19, 0, 18, 18, 18, 0, 6, 6, 6, 0, 19, 19, 19, 0, 19, 19, 19, 0, 7, 7, 7, 0, 7, 7, 7, 0, 19, 19, 19, 0, 19, 19, 19, 0, 16, 16, 16, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 16, 16, 16, 0, 16, 16, 16, 0, 20, 20, 20, 0, 5, 5, 5, 0, 4, 4, 4, 0, 2, 2, 2, 0, 18, 18, 18, 0, 13, 13, 13, 0, 8, 8, 8, 0, 3, 3, 3, 0, 21, 21, 21, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 14, 14, 14, 0, 20, 20, 20, 0, 3, 3, 3, 0, 9, 9, 9, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 18, 18, 18, 0, 17, 17, 17, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 1, 1, 1, 0, 20, 20, 20, 0, 5, 5, 5, 0, 1, 1, 1, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 12, 12, 12, 0, 16, 16, 16, 0, 20, 20, 20, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 17, 17, 17, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 0, 0, 0, 0, 7, 7, 7, 0, 21, 21, 21, 0, 13, 13, 13, 0, 0, 0, 0, 0, 20, 20, 20, 0, 18, 18, 18, 0, 7, 7, 7, 0, 5, 5, 5, 0, 0, 0, 0, 0, 15, 15, 15, 0, 19, 19, 19, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 0, 0, 0, 0, 3, 3, 3, 0, 13, 13, 13, 0, 8, 8, 8, 0, 20, 20, 20, 0, 16, 16, 16, 0, 18, 18, 18, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 16, 16, 16, 0, 19, 19, 19, 0, 8, 8, 8, 0, 9, 9, 9, 0, 12, 12, 12, 0, 10, 10, 10, 0, 13, 13, 13, 0, 4, 4, 4, 0, 1, 1, 1, 0, 16, 16, 16, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 12, 12, 12, 0, 17, 17, 17, 0, 16, 16, 16, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 7, 7, 7, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 21, 21, 21, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 20, 20, 20, 0, 2, 2, 2, 0, 1, 1, 1, 0, 2, 2, 2, 0, 10, 10, 10, 0, 16, 16, 16, 0, 1, 1, 1, 0, 21, 21, 21, 0, 10, 10, 10, 0, 5, 5, 5, 0, 1, 1, 1, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 7, 7, 7, 0, 6, 6, 6, 0, 19, 19, 19, 0, 20, 20, 20, 0, 0, 0, 0, 0, 4, 4, 4, 0, 7, 7, 7, 0, 20, 20, 20, 0, 20, 20, 20, 0, 5, 5, 5, 0, 14, 14, 14, 0, 11, 11, 11, 0, 16, 16, 16, 0, 0, 0, 0, 0, 10, 10, 10, 0, 16, 16, 16, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 7, 7, 7, 0, 3, 3, 3, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 10, 10, 10, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 5, 5, 5, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 19, 19, 19, 0, 18, 18, 18, 0, 19, 19, 19, 0, 5, 5, 5, 0, 13, 13, 13, 0, 12, 12, 12, 0, 21, 21, 21, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 20, 20, 20, 0, 2, 2, 2, 0, 7, 7, 7, 0, 13, 13, 13, 0, 0, 0, 0, 0, 14, 14, 14, 0, 8, 8, 8, 0, 4, 4, 4, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 13, 13, 13, 0, 3, 3, 3, 0, 7, 7, 7, 0, 14, 14, 14, 0, 13, 13, 13, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 20, 20, 20, 0, 7, 7, 7, 0, 14, 14, 14, 0, 12, 12, 12, 0, 21, 21, 21, 0, 4, 4, 4, 0, 21, 21, 21, 0, 18, 18, 18, 0, 16, 16, 16, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 13, 13, 13, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 2, 2, 2, 0, 9, 9, 9, 0, 16, 16, 16, 0, 1, 1, 1, 0, 5, 5, 5, 0, 7, 7, 7, 0, 18, 18, 18, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 4, 4, 4, 0, 16, 16, 16, 0, 2, 2, 2, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 20, 20, 20, 0, 3, 3, 3, 0, 8, 8, 8, 0, 21, 21, 21, 0, 0, 0, 0, 0, 18, 18, 18, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 5, 5, 5, 0, 4, 4, 4, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 19, 19, 19, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 21, 21, 21, 0, 20, 20, 20, 0, 5, 5, 5, 0, 0, 0, 0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 5, 5, 5, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 19, 19, 19, 0, 19, 19, 19, 0, 20, 20, 20, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 13, 13, 13, 0, 14, 14, 14, 0, 4, 4, 4, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 18, 18, 18, 0, 20, 20, 20, 0, 9, 9, 9, 0, 0, 0, 0, 0, 1, 1, 1, 0, 18, 18, 18, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 3, 3, 3, 0, 21, 21, 21, 0, 20, 20, 20, 0, 6, 6, 6, 0, 2, 2, 2, 0, 20, 20, 20, 0, 18, 18, 18, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 10, 10, 10, 0, 14, 14, 14, 0, 15, 15, 15, 0, 21, 21, 21, 0, 17, 17, 17, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 17, 17, 17, 0, 2, 2, 2, 0, 20, 20, 20, 0, 21, 21, 21, 0, 2, 2, 2, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 10, 10, 10, 0, 15, 15, 15, 0, 0, 0, 0, 0, 9, 9, 9, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 20, 20, 20, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 7, 7, 7, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 6, 6, 6, 0, 2, 2, 2, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 4, 4, 4, 0, 21, 21, 21, 0, 18, 18, 18, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 10, 10, 10, 0, 18, 18, 18, 0, 13, 13, 13, 0, 2, 2, 2, 0, 4, 4, 4, 0, 3, 3, 3, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 5, 5, 5, 0, 2, 2, 2, 0, 7, 7, 7, 0, 14, 14, 14, 0, 3, 3, 3, 0, 12, 12, 12, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 15, 15, 15, 0, 14, 14, 14, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 16, 16, 16, 0, 12, 12, 12, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 16, 16, 16, 0, 19, 19, 19, 0, 18, 18, 18, 0, 21, 21, 21, 0, 21, 21, 21, 0, 6, 6, 6, 0, 12, 12, 12, 0, 21, 21, 21, 0, 6, 6, 6, 0, 21, 21, 21, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 1, 1, 1, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 21, 21, 21, 0, 18, 18, 18, 0, 20, 20, 20, 0, 16, 16, 16, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 1, 1, 1, 0, 7, 7, 7, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 8, 8, 8, 0, 19, 19, 19, 0, 3, 3, 3, 0, 19, 19, 19, 0, 18, 18, 18, 0, 20, 20, 20, 0, 1, 1, 1, 0, 3, 3, 3, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 21, 21, 21, 0, 18, 18, 18, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 0, 0, 0, 0, 20, 20, 20, 0, 8, 8, 8, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 4, 4, 4, 0, 2, 2, 2, 0, 21, 21, 21, 0, 9, 9, 9, 0, 4, 4, 4, 0, 19, 19, 19, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 1, 1, 1, 0, 19, 19, 19, 0, 16, 16, 16, 0, 14, 14, 14, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 21, 21, 21, 0, 13, 13, 13, 0, 13, 13, 13, 0, 21, 21, 21, 0, 2, 2, 2, 0, 3, 3, 3, 0, 7, 7, 7, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 4, 4, 4, 0, 21, 21, 21, 0, 20, 20, 20, 0, 14, 14, 14, 0, 2, 2, 2, 0, 1, 1, 1, 0, 11, 11, 11, 0, 2, 2, 2, 0, 18, 18, 18, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 3, 3, 3, 0, 9, 9, 9, 0, 9, 9, 9, 0, 17, 17, 17, 0, 13, 13, 13, 0, 16, 16, 16, 0, 14, 14, 14, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 10, 10, 10, 0, 0, 0, 0, 0, 10, 10, 10, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 4, 4, 4, 0, 1, 1, 1, 0, 2, 2, 2, 0, 0, 0, 0, 0, 17, 17, 17, 0, 6, 6, 6, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 1, 1, 1, 0, 20, 20, 20, 0, 16, 16, 16, 0, 18, 18, 18, 0, 17, 17, 17, 0, 20, 20, 20, 0, 8, 8, 8, 0, 11, 11, 11, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 20, 20, 20, 0, 18, 18, 18, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 16, 16, 16, 0, 4, 4, 4, 0, 14, 14, 14, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 11, 11, 11, 0, 3, 3, 3, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 14, 14, 14, 0, 1, 1, 1, 0, 7, 7, 7, 0, 17, 17, 17, 0, 20, 20, 20, 0, 20, 20, 20, 0, 3, 3, 3, 0, 1, 1, 1, 0, 20, 20, 20, 0, 11, 11, 11, 0, 5, 5, 5, 0, 5, 5, 5, 0, 11, 11, 11, 0, 18, 18, 18, 0, 13, 13, 13, 0, 6, 6, 6, 0, 18, 18, 18, 0, 18, 18, 18, 0, 2, 2, 2, 0, 14, 14, 14, 0, 14, 14, 14, 0, 20, 20, 20, 0, 5, 5, 5, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 9, 9, 9, 0, 18, 18, 18, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 4, 4, 4, 0, 11, 11, 11, 0, 2, 2, 2, 0, 16, 16, 16, 0, 13, 13, 13, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 19, 19, 19, 0, 20, 20, 20, 0, 20, 20, 20, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 9, 9, 9, 0, 2, 2, 2, 0, 21, 21, 21, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 14, 14, 14, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 4, 4, 4, 0, 17, 17, 17, 0, 14, 14, 14, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 10, 10, 10, 0, 11, 11, 11, 0, 20, 20, 20, 0, 19, 19, 19, 0, 17, 17, 17, 0, 5, 5, 5, 0, 8, 8, 8, 0, 20, 20, 20, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 16, 16, 16, 0, 12, 12, 12, 0, 16, 16, 16, 0, 18, 18, 18, 0, 19, 19, 19, 0, 14, 14, 14, 0, 18, 18, 18, 0, 12, 12, 12, 0, 5, 5, 5, 0, 21, 21, 21, 0, 19, 19, 19, 0, 19, 19, 19, 0, 21, 21, 21, 0, 4, 4, 4, 0, 9, 9, 9, 0, 16, 16, 16, 0, 11, 11, 11, 0, 4, 4, 4, 0, 12, 12, 12, 0, 18, 18, 18, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 1, 1, 1, 0, 2, 2, 2, 0, 5, 5, 5, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 19, 19, 19, 0, 3, 3, 3, 0, 21, 21, 21, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 2, 2, 2, 0, 19, 19, 19, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 18, 18, 18, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 1, 1, 1, 0, 3, 3, 3, 0, 17, 17, 17, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 13, 13, 13, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 10, 10, 10, 0, 13, 13, 13, 0, 2, 2, 2, 0, 6, 6, 6, 0, 1, 1, 1, 0, 9, 9, 9, 0, 20, 20, 20, 0, 14, 14, 14, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 18, 18, 18, 0, 21, 21, 21, 0, 3, 3, 3, 0, 21, 21, 21, 0, 2, 2, 2, 0, 0, 0, 0, 0, 17, 17, 17, 0, 4, 4, 4, 0, 21, 21, 21, 0, 7, 7, 7, 0, 3, 3, 3, 0, 8, 8, 8, 0, 10, 10, 10, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 0, 0, 0, 0, 8, 8, 8, 0, 1, 1, 1, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 15, 15, 15, 0, 7, 7, 7, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 16, 16, 16, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 21, 21, 21, 0, 20, 20, 20, 0, 19, 19, 19, 0, 18, 18, 18, 0, 16, 16, 16, 0, 9, 9, 9, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 3, 3, 3, 0, 16, 16, 16, 0, 19, 19, 19, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 11, 11, 11, 0, 20, 20, 20, 0, 15, 15, 15, 0, 18, 18, 18, 0, 16, 16, 16, 0, 16, 16, 16, 0, 19, 19, 19, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 21, 21, 21, 0, 3, 3, 3, 0, 5, 5, 5, 0, 1, 1, 1, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 15, 15, 15, 0, 8, 8, 8, 0, 13, 13, 13, 0, 2, 2, 2, 0, 10, 10, 10, 0, 11, 11, 11, 0, 9, 9, 9, 0, 18, 18, 18, 0, 9, 9, 9, 0, 2, 2, 2, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 7, 7, 7, 0, 18, 18, 18, 0, 19, 19, 19, 0, 13, 13, 13, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 20, 20, 20, 0, 2, 2, 2, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 7, 7, 7, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 19, 19, 19, 0, 2, 2, 2, 0, 1, 1, 1, 0, 9, 9, 9, 0, 14, 14, 14, 0, 3, 3, 3, 0, 18, 18, 18, 0, 18, 18, 18, 0, 16, 16, 16, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 20, 20, 20, 0, 20, 20, 20, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 11, 11, 11, 0, 12, 12, 12, 0, 1, 1, 1, 0, 10, 10, 10, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 10, 10, 10, 0, 11, 11, 11, 0, 15, 15, 15, 0, 19, 19, 19, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 18, 18, 18, 0, 6, 6, 6, 0, 10, 10, 10, 0, 20, 20, 20, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 10, 10, 10, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 3, 3, 3, 0, 6, 6, 6, 0, 20, 20, 20, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 20, 20, 20, 0, 20, 20, 20, 0, 3, 3, 3, 0, 8, 8, 8, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 7, 7, 7, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 19, 19, 19, 0, 1, 1, 1, 0, 20, 20, 20, 0, 8, 8, 8, 0, 3, 3, 3, 0, 2, 2, 2, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 21, 21, 21, 0, 5, 5, 5, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 16, 16, 16, 0, 20, 20, 20, 0, 12, 12, 12, 0, 1, 1, 1, 0, 16, 16, 16, 0, 15, 15, 15, 0, 11, 11, 11, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 19, 19, 19, 0, 10, 10, 10, 0, 1, 1, 1, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 8, 8, 8, 0, 0, 0, 0, 0, 18, 18, 18, 0, 18, 18, 18, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 17, 17, 17, 0, 4, 4, 4, 0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 20, 20, 20, 0, 18, 18, 18, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 9, 9, 9, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 18, 18, 18, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 17, 17, 17, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 4, 4, 4, 0, 2, 2, 2, 0, 17, 17, 17, 0, 19, 19, 19, 0, 5, 5, 5, 0, 21, 21, 21, 0, 19, 19, 19, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 18, 18, 18, 0, 17, 17, 17, 0, 6, 6, 6, 0, 9, 9, 9, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 18, 18, 18, 0, 9, 9, 9, 0, 12, 12, 12, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 18, 18, 18, 0, 4, 4, 4, 0, 4, 4, 4, 0, 14, 14, 14, 0, 6, 6, 6, 0, 12, 12, 12, 0, 18, 18, 18, 0, 1, 1, 1, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 2, 2, 2, 0, 20, 20, 20, 0, 19, 19, 19, 0, 17, 17, 17, 0, 17, 17, 17, 0, 21, 21, 21, 0, 6, 6, 6, 0, 15, 15, 15, 0, 7, 7, 7, 0, 17, 17, 17, 0, 15, 15, 15, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 19, 19, 19, 0, 17, 17, 17, 0, 6, 6, 6, 0, 3, 3, 3, 0, 2, 2, 2, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 12, 12, 12, 0, 20, 20, 20, 0, 17, 17, 17, 0, 20, 20, 20, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 19, 19, 19, 0, 1, 1, 1, 0, 16, 16, 16, 0, 5, 5, 5, 0, 20, 20, 20, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 1, 1, 1, 0, 1, 1, 1, 0, 5, 5, 5, 0, 13, 13, 13, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 8, 8, 8, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 3, 3, 3, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 11, 11, 11, 0, 9, 9, 9, 0, 21, 21, 21, 0, 19, 19, 19, 0, 10, 10, 10, 0, 16, 16, 16, 0, 18, 18, 18, 0, 12, 12, 12, 0, 17, 17, 17, 0, 16, 16, 16, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 16, 16, 16, 0, 19, 19, 19, 0, 17, 17, 17, 0, 19, 19, 19, 0, 3, 3, 3, 0, 0, 0, 0, 0, 13, 13, 13, 0, 7, 7, 7, 0, 1, 1, 1, 0, 19, 19, 19, 0, 6, 6, 6, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 16, 16, 16, 0, 20, 20, 20, 0, 3, 3, 3, 0, 18, 18, 18, 0, 17, 17, 17, 0, 13, 13, 13, 0, 21, 21, 21, 0, 20, 20, 20, 0, 4, 4, 4, 0, 2, 2, 2, 0, 8, 8, 8, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 21, 21, 21, 0, 2, 2, 2, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 1, 1, 1, 0, 19, 19, 19, 0, 18, 18, 18, 0, 17, 17, 17, 0, 20, 20, 20, 0, 14, 14, 14, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 8, 8, 8, 0, 1, 1, 1, 0, 8, 8, 8, 0, 10, 10, 10, 0, 20, 20, 20, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 19, 19, 19, 0, 2, 2, 2, 0, 10, 10, 10, 0, 4, 4, 4, 0, 21, 21, 21, 0, 14, 14, 14, 0, 7, 7, 7, 0, 0, 0, 0, 0, 15, 15, 15, 0, 11, 11, 11, 0, 20, 20, 20, 0, 2, 2, 2, 0, 10, 10, 10, 0, 5, 5, 5, 0, 18, 18, 18, 0, 19, 19, 19, 0, 1, 1, 1, 0, 9, 9, 9, 0, 15, 15, 15, 0, 3, 3, 3, 0, 19, 19, 19, 0, 2, 2, 2, 0, 19, 19, 19, 0, 11, 11, 11, 0, 8, 8, 8, 0, 21, 21, 21, 0, 9, 9, 9, 0, 21, 21, 21, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 19, 19, 19, 0, 18, 18, 18, 0, 21, 21, 21, 0, 18, 18, 18, 0, 19, 19, 19, 0, 6, 6, 6, 0, 2, 2, 2, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 9, 9, 9, 0, 19, 19, 19, 0, 19, 19, 19, 0, 20, 20, 20, 0, 11, 11, 11, 0, 2, 2, 2, 0, 6, 6, 6, 0, 9, 9, 9, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 1, 1, 1, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 9, 9, 9, 0, 5, 5, 5, 0, 19, 19, 19, 0, 11, 11, 11, 0, 3, 3, 3, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 18, 18, 18, 0, 6, 6, 6, 0, 11, 11, 11, 0, 5, 5, 5, 0, 1, 1, 1, 0, 14, 14, 14, 0, 9, 9, 9, 0, 1, 1, 1, 0, 12, 12, 12, 0, 9, 9, 9, 0, 8, 8, 8, 0, 14, 14, 14, 0, 9, 9, 9, 0, 9, 9, 9, 0, 2, 2, 2, 0, 18, 18, 18, 0, 17, 17, 17, 0, 5, 5, 5, 0, 6, 6, 6, 0, 17, 17, 17, 0, 15, 15, 15, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 11, 11, 11, 0, 2, 2, 2, 0, 14, 14, 14, 0, 2, 2, 2, 0, 21, 21, 21, 0, 11, 11, 11, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 21, 21, 21, 0, 21, 21, 21, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 9, 9, 9, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 1, 1, 1, 0, 0, 0, 0, 0, 13, 13, 13, 0, 11, 11, 11, 0, 6, 6, 6, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 19, 19, 19, 0, 3, 3, 3, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 12, 12, 12, 0, 13, 13, 13, 0, 3, 3, 3, 0, 5, 5, 5, 0, 18, 18, 18, 0, 15, 15, 15, 0, 15, 15, 15, 0, 21, 21, 21, 0, 21, 21, 21, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 15, 15, 15, 0, 20, 20, 20, 0, 13, 13, 13, 0, 10, 10, 10, 0, 3, 3, 3, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 6, 6, 6, 0, 3, 3, 3, 0, 0, 0, 0, 0, 9, 9, 9, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 21, 21, 21, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 12, 12, 12, 0, 7, 7, 7, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 19, 19, 19, 0, 7, 7, 7, 0, 20, 20, 20, 0, 16, 16, 16, 0, 7, 7, 7, 0, 19, 19, 19, 0, 9, 9, 9, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 7, 7, 7, 0, 3, 3, 3, 0, 9, 9, 9, 0, 0, 0, 0, 0, 8, 8, 8, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 20, 20, 20, 0, 8, 8, 8, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 5, 5, 5, 0, 19, 19, 19, 0, 18, 18, 18, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 17, 17, 17, 0, 3, 3, 3, 0, 14, 14, 14, 0, 1, 1, 1, 0, 15, 15, 15, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 16, 16, 16, 0, 13, 13, 13, 0, 9, 9, 9, 0, 1, 1, 1, 0, 18, 18, 18, 0, 19, 19, 19, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 17, 17, 17, 0, 20, 20, 20, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 10, 10, 10, 0, 15, 15, 15, 0, 21, 21, 21, 0, 0, 0, 0, 0, 2, 2, 2, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 14, 14, 14, 0, 3, 3, 3, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 10, 10, 10, 0, 3, 3, 3, 0, 8, 8, 8, 0, 18, 18, 18, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 10, 10, 10, 0, 10, 10, 10, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 8, 8, 8, 0, 16, 16, 16, 0, 1, 1, 1, 0, 9, 9, 9, 0, 18, 18, 18, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 20, 20, 20, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 20, 20, 20, 0, 13, 13, 13, 0, 20, 20, 20, 0, 19, 19, 19, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 15, 15, 15, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 20, 20, 20, 0, 13, 13, 13, 0, 1, 1, 1, 0, 21, 21, 21, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 8, 8, 8, 0, 4, 4, 4, 0, 21, 21, 21, 0, 18, 18, 18, 0, 19, 19, 19, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 10, 10, 10, 0, 21, 21, 21, 0, 21, 21, 21, 0, 21, 21, 21, 0, 1, 1, 1, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 4, 4, 4, 0, 9, 9, 9, 0, 19, 19, 19, 0, 19, 19, 19, 0, 2, 2, 2, 0, 7, 7, 7, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 8, 8, 8, 0, 21, 21, 21, 0, 21, 21, 21, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 3, 3, 3, 0, 19, 19, 19, 0, 17, 17, 17, 0, 16, 16, 16, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 3, 3, 3, 0, 17, 17, 17, 0, 16, 16, 16, 0, 18, 18, 18, 0, 8, 8, 8, 0, 12, 12, 12, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 1, 1, 1, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 17, 17, 17, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 12, 12, 12, 0, 9, 9, 9, 0, 15, 15, 15, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 6, 6, 6, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 10, 10, 10, 0, 6, 6, 6, 0, 5, 5, 5, 0, 8, 8, 8, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 9, 9, 9, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 16, 16, 16, 0, 2, 2, 2, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 17, 17, 17, 0, 20, 20, 20, 0, 20, 20, 20, 0, 2, 2, 2, 0, 9, 9, 9, 0, 21, 21, 21, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 6, 6, 6, 0, 19, 19, 19, 0, 18, 18, 18, 0, 7, 7, 7, 0, 19, 19, 19, 0, 18, 18, 18, 0, 14, 14, 14, 0, 15, 15, 15, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 1, 1, 1, 0, 3, 3, 3, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 18, 18, 18, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 1, 1, 1, 0, 4, 4, 4, 0, 21, 21, 21, 0, 6, 6, 6, 0, 18, 18, 18, 0, 21, 21, 21, 0, 6, 6, 6, 0, 1, 1, 1, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 2, 2, 2, 0, 5, 5, 5, 0, 8, 8, 8, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 5, 5, 5, 0, 4, 4, 4, 0, 10, 10, 10, 0, 3, 3, 3, 0, 16, 16, 16, 0, 12, 12, 12, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 18, 18, 18, 0, 20, 20, 20, 0, 21, 21, 21, 0, 19, 19, 19, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 15, 15, 15, 0, 2, 2, 2, 0, 16, 16, 16, 0, 12, 12, 12, 0, 10, 10, 10, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 16, 16, 16, 0, 16, 16, 16, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 19, 19, 19, 0, 20, 20, 20, 0, 3, 3, 3, 0, 6, 6, 6, 0, 0, 0, 0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 2, 2, 2, 0, 6, 6, 6, 0, 10, 10, 10, 0, 19, 19, 19, 0, 9, 9, 9, 0, 17, 17, 17, 0, 3, 3, 3, 0, 5, 5, 5, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 4, 4, 4, 0, 16, 16, 16, 0, 12, 12, 12, 0, 13, 13, 13, 0, 6, 6, 6, 0, 11, 11, 11, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 15, 15, 15, 0, 2, 2, 2, 0, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 19, 19, 19, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 4, 4, 4, 0, 21, 21, 21, 0, 18, 18, 18, 0, 15, 15, 15, 0, 16, 16, 16, 0, 1, 1, 1, 0, 13, 13, 13, 0, 11, 11, 11, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 19, 19, 19, 0, 5, 5, 5, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 20, 20, 20, 0, 6, 6, 6, 0, 11, 11, 11, 0, 7, 7, 7, 0, 20, 20, 20, 0, 20, 20, 20, 0, 21, 21, 21, 0, 2, 2, 2, 0, 0, 0, 0, 0, 9, 9, 9, 0, 3, 3, 3, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 12, 12, 12, 0, 21, 21, 21, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 16, 16, 16, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 15, 15, 15, 0, 8, 8, 8, 0, 8, 8, 8, 0, 19, 19, 19, 0, 17, 17, 17, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 11, 11, 11, 0, 14, 14, 14, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 20, 20, 20, 0, 5, 5, 5, 0, 14, 14, 14, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 13, 13, 13, 0, 3, 3, 3, 0, 19, 19, 19, 0, 11, 11, 11, 0, 1, 1, 1, 0, 17, 17, 17, 0, 0, 0, 0, 0, 8, 8, 8, 0, 14, 14, 14, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 8, 8, 8, 0, 20, 20, 20, 0, 14, 14, 14, 0, 0, 0, 0, 0, 19, 19, 19, 0, 13, 13, 13, 0, 15, 15, 15, 0, 2, 2, 2, 0, 18, 18, 18, 0, 4, 4, 4, 0, 16, 16, 16, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 10, 10, 10, 0, 11, 11, 11, 0, 15, 15, 15, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 3, 3, 3, 0, 3, 3, 3, 0, 15, 15, 15, 0, 15, 15, 15, 0, 8, 8, 8, 0, 15, 15, 15, 0, 2, 2, 2, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 4, 4, 4, 0, 4, 4, 4, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 20, 20, 20, 0, 4, 4, 4, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 15, 15, 15, 0, 13, 13, 13, 0, 18, 18, 18, 0, 16, 16, 16, 0, 13, 13, 13, 0, 12, 12, 12, 0, 14, 14, 14, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 5, 5, 5, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 19, 19, 19, 0, 21, 21, 21, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 2, 2, 2, 0, 21, 21, 21, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 12, 12, 12, 0, 19, 19, 19, 0, 15, 15, 15, 0, 19, 19, 19, 0, 14, 14, 14, 0, 15, 15, 15, 0, 6, 6, 6, 0, 21, 21, 21, 0, 4, 4, 4, 0, 2, 2, 2, 0, 14, 14, 14, 0, 19, 19, 19, 0, 1, 1, 1, 0, 19, 19, 19, 0, 17, 17, 17, 0, 17, 17, 17, 0, 1, 1, 1, 0, 6, 6, 6, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 18, 18, 18, 0, 21, 21, 21, 0, 4, 4, 4, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 21, 21, 21, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 15, 15, 15, 0, 19, 19, 19, 0, 20, 20, 20, 0, 15, 15, 15, 0, 5, 5, 5, 0, 2, 2, 2, 0, 13, 13, 13, 0, 17, 17, 17, 0, 8, 8, 8, 0, 15, 15, 15, 0, 5, 5, 5, 0, 1, 1, 1, 0, 20, 20, 20, 0, 19, 19, 19, 0, 4, 4, 4, 0, 0, 0, 0, 0, 14, 14, 14, 0, 8, 8, 8, 0, 6, 6, 6, 0, 20, 20, 20, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 20, 20, 20, 0, 2, 2, 2, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 3, 3, 3, 0, 20, 20, 20, 0, 15, 15, 15, 0, 15, 15, 15, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 18, 18, 18, 0, 21, 21, 21, 0, 16, 16, 16, 0, 20, 20, 20, 0, 7, 7, 7, 0, 1, 1, 1, 0, 8, 8, 8, 0, 5, 5, 5, 0, 3, 3, 3, 0, 6, 6, 6, 0, 1, 1, 1, 0, 4, 4, 4, 0, 0, 0, 0, 0, 4, 4, 4, 0, 21, 21, 21, 0, 10, 10, 10, 0, 1, 1, 1, 0, 19, 19, 19, 0, 18, 18, 18, 0, 21, 21, 21, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 13, 13, 13, 0, 8, 8, 8, 0, 0, 0, 0, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 2, 2, 2, 0, 12, 12, 12, 0, 1, 1, 1, 0, 3, 3, 3, 0, 0, 0, 0, 0, 20, 20, 20, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 6, 6, 6, 0, 12, 12, 12, 0, 1, 1, 1, 0, 18, 18, 18, 0, 6, 6, 6, 0, 2, 2, 2, 0, 20, 20, 20, 0, 20, 20, 20, 0, 13, 13, 13, 0, 0, 0, 0, 0, 15, 15, 15, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 19, 19, 19, 0, 0, 0, 0, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 1, 1, 1, 0, 18, 18, 18, 0, 3, 3, 3, 0, 9, 9, 9, 0, 5, 5, 5, 0, 13, 13, 13, 0, 14, 14, 14, 0, 19, 19, 19, 0, 0, 0, 0, 0, 20, 20, 20, 0, 9, 9, 9, 0, 15, 15, 15, 0, 16, 16, 16, 0, 12, 12, 12, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 16, 16, 16, 0, 6, 6, 6, 0, 1, 1, 1, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 10, 10, 10, 0, 12, 12, 12, 0, 3, 3, 3, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 15, 15, 15, 0, 8, 8, 8, 0, 10, 10, 10, 0, 20, 20, 20, 0, 9, 9, 9, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 15, 15, 15, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 4, 4, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 16, 16, 16, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 14, 14, 14, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 15, 15, 15, 0, 1, 1, 1, 0, 16, 16, 16, 0, 17, 17, 17, 0, 0, 0, 0, 0, 11, 11, 11, 0, 4, 4, 4, 0, 7, 7, 7, 0, 15, 15, 15, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 17, 17, 17, 0, 8, 8, 8, 0, 13, 13, 13, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 10, 10, 10, 0, 13, 13, 13, 0, 12, 12, 12, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 1, 1, 1, 0, 2, 2, 2, 0, 5, 5, 5, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 18, 18, 18, 0, 16, 16, 16, 0, 17, 17, 17, 0, 8, 8, 8, 0, 13, 13, 13, 0, 19, 19, 19, 0, 1, 1, 1, 0, 12, 12, 12, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 14, 14, 14, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 1, 1, 1, 0, 20, 20, 20, 0, 18, 18, 18, 0, 20, 20, 20, 0, 5, 5, 5, 0, 11, 11, 11, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 14, 14, 14, 0, 20, 20, 20, 0, 3, 3, 3, 0, 19, 19, 19, 0, 1, 1, 1, 0, 8, 8, 8, 0, 5, 5, 5, 0, 1, 1, 1, 0, 14, 14, 14, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 17, 17, 17, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 19, 19, 19, 0, 16, 16, 16, 0, 17, 17, 17, 0, 21, 21, 21, 0, 3, 3, 3, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 21, 21, 21, 0, 5, 5, 5, 0, 11, 11, 11, 0, 3, 3, 3, 0, 13, 13, 13, 0, 20, 20, 20, 0, 12, 12, 12, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 12, 12, 12, 0, 4, 4, 4, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 5, 5, 5, 0, 19, 19, 19, 0, 12, 12, 12, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 11, 11, 11, 0, 2, 2, 2, 0, 14, 14, 14, 0, 15, 15, 15, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 6, 6, 6, 0, 18, 18, 18, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 12, 12, 12, 0, 4, 4, 4, 0, 17, 17, 17, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 17, 17, 17, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 9, 9, 9, 0, 18, 18, 18, 0, 16, 16, 16, 0, 1, 1, 1, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 4, 4, 4, 0, 1, 1, 1, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 17, 17, 17, 0, 10, 10, 10, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 1, 1, 1, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 16, 16, 16, 0, 1, 1, 1, 0, 3, 3, 3, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 3, 3, 3, 0, 19, 19, 19, 0, 19, 19, 19, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 16, 16, 16, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 18, 18, 18, 0, 20, 20, 20, 0, 21, 21, 21, 0, 0, 0, 0, 0, 20, 20, 20, 0, 15, 15, 15, 0, 21, 21, 21, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 18, 18, 18, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 15, 15, 15, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 14, 14, 14, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 21, 21, 21, 0, 3, 3, 3, 0, 7, 7, 7, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 1, 1, 1, 0, 20, 20, 20, 0, 17, 17, 17, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 19, 19, 19, 0, 11, 11, 11, 0, 11, 11, 11, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 3, 3, 3, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 14, 14, 14, 0, 14, 14, 14, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 21, 21, 21, 0, 1, 1, 1, 0, 10, 10, 10, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 3, 3, 3, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 20, 20, 20, 0, 19, 19, 19, 0, 2, 2, 2, 0, 13, 13, 13, 0, 12, 12, 12, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 2, 2, 2, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 14, 14, 14, 0, 7, 7, 7, 0, 18, 18, 18, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 4, 4, 4, 0, 9, 9, 9, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 19, 19, 19, 0, 8, 8, 8, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 16, 16, 16, 0, 18, 18, 18, 0, 9, 9, 9, 0, 1, 1, 1, 0, 13, 13, 13, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 12, 12, 12, 0, 13, 13, 13, 0, 0, 0, 0, 0, 2, 2, 2, 0, 1, 1, 1, 0, 12, 12, 12, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 3, 3, 3, 0, 18, 18, 18, 0, 2, 2, 2, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 11, 11, 11, 0, 17, 17, 17, 0, 20, 20, 20, 0, 8, 8, 8, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 20, 20, 20, 0, 17, 17, 17, 0, 5, 5, 5, 0, 15, 15, 15, 0, 16, 16, 16, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 20, 20, 20, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 18, 18, 18, 0, 19, 19, 19, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 16, 16, 16, 0, 9, 9, 9, 0, 19, 19, 19, 0, 14, 14, 14, 0, 19, 19, 19, 0, 10, 10, 10, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 14, 14, 14, 0, 4, 4, 4, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 19, 19, 19, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 7, 7, 7, 0, 0, 0, 0, 0, 13, 13, 13, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 1, 1, 1, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 2, 2, 2, 0, 14, 14, 14, 0, 5, 5, 5, 0, 16, 16, 16, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 17, 17, 17, 0, 16, 16, 16, 0, 3, 3, 3, 0, 3, 3, 3, 0, 13, 13, 13, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 18, 18, 18, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 15, 15, 15, 0, 2, 2, 2, 0, 10, 10, 10, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 17, 17, 17, 0, 21, 21, 21, 0, 20, 20, 20, 0, 11, 11, 11, 0, 2, 2, 2, 0, 19, 19, 19, 0, 18, 18, 18, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 12, 12, 12, 0, 5, 5, 5, 0, 9, 9, 9, 0, 12, 12, 12, 0, 8, 8, 8, 0, 12, 12, 12, 0, 17, 17, 17, 0, 16, 16, 16, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 1, 1, 1, 0, 15, 15, 15, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 20, 20, 20, 0, 13, 13, 13, 0, 8, 8, 8, 0, 18, 18, 18, 0, 19, 19, 19, 0, 20, 20, 20, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 14, 14, 14, 0, 13, 13, 13, 0, 14, 14, 14, 0, 19, 19, 19, 0, 6, 6, 6, 0, 3, 3, 3, 0, 13, 13, 13, 0, 11, 11, 11, 0, 1, 1, 1, 0, 17, 17, 17, 0, 19, 19, 19, 0, 17, 17, 17, 0, 21, 21, 21, 0, 2, 2, 2, 0, 7, 7, 7, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 20, 20, 20, 0, 2, 2, 2, 0, 20, 20, 20, 0, 21, 21, 21, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 1, 1, 1, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 2, 2, 2, 0, 17, 17, 17, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 15, 15, 15, 0, 12, 12, 12, 0, 14, 14, 14, 0, 2, 2, 2, 0, 15, 15, 15, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 18, 18, 18, 0, 18, 18, 18, 0, 17, 17, 17, 0, 18, 18, 18, 0, 1, 1, 1, 0, 19, 19, 19, 0, 14, 14, 14, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 19, 19, 19, 0, 8, 8, 8, 0, 18, 18, 18, 0, 9, 9, 9, 0, 9, 9, 9, 0, 2, 2, 2, 0, 16, 16, 16, 0, 10, 10, 10, 0, 5, 5, 5, 0, 8, 8, 8, 0, 9, 9, 9, 0, 0, 0, 0, 0, 1, 1, 1, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 2, 2, 2, 0, 3, 3, 3, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 5, 5, 5, 0, 19, 19, 19, 0, 1, 1, 1, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 7, 7, 7, 0, 20, 20, 20, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 10, 10, 10, 0, 13, 13, 13, 0, 11, 11, 11, 0, 13, 13, 13, 0, 19, 19, 19, 0, 7, 7, 7, 0, 18, 18, 18, 0, 18, 18, 18, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 13, 13, 13, 0, 16, 16, 16, 0, 20, 20, 20, 0, 1, 1, 1, 0, 16, 16, 16, 0, 15, 15, 15, 0, 12, 12, 12, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 16, 16, 16, 0, 12, 12, 12, 0, 9, 9, 9, 0, 14, 14, 14, 0, 18, 18, 18, 0, 10, 10, 10, 0, 21, 21, 21, 0, 12, 12, 12, 0, 2, 2, 2, 0, 20, 20, 20, 0, 6, 6, 6, 0, 20, 20, 20, 0, 4, 4, 4, 0, 9, 9, 9, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 6, 6, 6, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 1, 1, 1, 0, 2, 2, 2, 0, 7, 7, 7, 0, 3, 3, 3, 0, 17, 17, 17, 0, 17, 17, 17, 0, 20, 20, 20, 0, 4, 4, 4, 0, 20, 20, 20, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 11, 11, 11, 0, 21, 21, 21, 0, 15, 15, 15, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 20, 20, 20, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 6, 6, 6, 0, 18, 18, 18, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 18, 18, 18, 0, 20, 20, 20, 0, 11, 11, 11, 0, 7, 7, 7, 0, 11, 11, 11, 0, 0, 0, 0, 0, 11, 11, 11, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 1, 1, 1, 0, 18, 18, 18, 0, 20, 20, 20, 0, 0, 0, 0, 0, 19, 19, 19, 0, 16, 16, 16, 0, 15, 15, 15, 0, 12, 12, 12, 0, 14, 14, 14, 0, 12, 12, 12, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 17, 17, 17, 0, 9, 9, 9, 0, 21, 21, 21, 0, 15, 15, 15, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 19, 19, 19, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 10, 10, 10, 0, 5, 5, 5, 0, 1, 1, 1, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 5, 5, 5, 0, 4, 4, 4, 0, 12, 12, 12, 0, 15, 15, 15, 0, 10, 10, 10, 0, 4, 4, 4, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 17, 17, 17, 0, 15, 15, 15, 0, 4, 4, 4, 0, 19, 19, 19, 0, 14, 14, 14, 0, 14, 14, 14, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 14, 14, 14, 0, 19, 19, 19, 0, 1, 1, 1, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 18, 18, 18, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 15, 15, 15, 0, 2, 2, 2, 0, 1, 1, 1, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 17, 17, 17, 0, 6, 6, 6, 0, 5, 5, 5, 0, 1, 1, 1, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 12, 12, 12, 0, 15, 15, 15, 0, 11, 11, 11, 0, 13, 13, 13, 0, 17, 17, 17, 0, 14, 14, 14, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 20, 20, 20, 0, 18, 18, 18, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 16, 16, 16, 0, 21, 21, 21, 0, 16, 16, 16, 0, 16, 16, 16, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 18, 18, 18, 0, 10, 10, 10, 0, 1, 1, 1, 0, 3, 3, 3, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 3, 3, 3, 0, 21, 21, 21, 0, 21, 21, 21, 0, 10, 10, 10, 0, 19, 19, 19, 0, 5, 5, 5, 0, 15, 15, 15, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 17, 17, 17, 0, 8, 8, 8, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 20, 20, 20, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 20, 20, 20, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 16, 16, 16, 0, 11, 11, 11, 0, 20, 20, 20, 0, 19, 19, 19, 0, 7, 7, 7, 0, 3, 3, 3, 0, 15, 15, 15, 0, 4, 4, 4, 0, 13, 13, 13, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 6, 6, 6, 0, 19, 19, 19, 0, 21, 21, 21, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 1, 1, 1, 0, 21, 21, 21, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 21, 21, 21, 0, 18, 18, 18, 0, 14, 14, 14, 0, 5, 5, 5, 0, 18, 18, 18, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 14, 14, 14, 0, 2, 2, 2, 0, 4, 4, 4, 0, 10, 10, 10, 0, 17, 17, 17, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 13, 13, 13, 0, 14, 14, 14, 0, 19, 19, 19, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 3, 3, 3, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 15, 15, 15, 0, 16, 16, 16, 0, 18, 18, 18, 0, 10, 10, 10, 0, 19, 19, 19, 0, 7, 7, 7, 0, 2, 2, 2, 0, 13, 13, 13, 0, 16, 16, 16, 0, 13, 13, 13, 0, 14, 14, 14, 0, 10, 10, 10, 0, 17, 17, 17, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 15, 15, 15, 0, 21, 21, 21, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 10, 10, 10, 0, 10, 10, 10, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 1, 1, 1, 0, 19, 19, 19, 0, 15, 15, 15, 0, 14, 14, 14, 0, 16, 16, 16, 0, 0, 0, 0, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 17, 17, 17, 0, 17, 17, 17, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 4, 4, 4, 0, 17, 17, 17, 0, 15, 15, 15, 0, 18, 18, 18, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 17, 17, 17, 0, 18, 18, 18, 0, 15, 15, 15, 0, 14, 14, 14, 0, 21, 21, 21, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 7, 7, 7, 0, 15, 15, 15, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 17, 17, 17, 0, 4, 4, 4, 0, 10, 10, 10, 0, 19, 19, 19, 0, 15, 15, 15, 0, 16, 16, 16, 0, 21, 21, 21, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 19, 19, 19, 0, 3, 3, 3, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 3, 3, 3, 0, 5, 5, 5, 0, 11, 11, 11, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 4, 4, 4, 0, 19, 19, 19, 0, 16, 16, 16, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 5, 5, 5, 0, 16, 16, 16, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 19, 19, 19, 0, 20, 20, 20, 0, 5, 5, 5, 0, 16, 16, 16, 0, 15, 15, 15, 0, 17, 17, 17, 0, 6, 6, 6, 0, 14, 14, 14, 0, 2, 2, 2, 0, 17, 17, 17, 0, 20, 20, 20, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 18, 18, 18, 0, 13, 13, 13, 0, 5, 5, 5, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 18, 18, 18, 0, 1, 1, 1, 0, 12, 12, 12, 0, 2, 2, 2, 0, 18, 18, 18, 0, 17, 17, 17, 0, 3, 3, 3, 0, 1, 1, 1, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 20, 20, 20, 0, 19, 19, 19, 0, 5, 5, 5, 0, 16, 16, 16, 0, 19, 19, 19, 0, 4, 4, 4, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 7, 7, 7, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 13, 13, 13, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 15, 15, 15, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 16, 16, 16, 0, 18, 18, 18, 0, 17, 17, 17, 0, 7, 7, 7, 0, 1, 1, 1, 0, 5, 5, 5, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 20, 20, 20, 0, 19, 19, 19, 0, 5, 5, 5, 0, 6, 6, 6, 0, 20, 20, 20, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 19, 19, 19, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 21, 21, 21, 0, 7, 7, 7, 0, 14, 14, 14, 0, 21, 21, 21, 0, 4, 4, 4, 0, 12, 12, 12, 0, 17, 17, 17, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 21, 21, 21, 0, 1, 1, 1, 0, 4, 4, 4, 0, 17, 17, 17, 0, 15, 15, 15, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 4, 4, 4, 0, 0, 0, 0, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 0, 0, 0, 0, 5, 5, 5, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 3, 3, 3, 0, 8, 8, 8, 0, 0, 0, 0, 0, 12, 12, 12, 0, 15, 15, 15, 0, 5, 5, 5, 0, 2, 2, 2, 0, 4, 4, 4, 0, 15, 15, 15, 0, 21, 21, 21, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 8, 8, 8, 0, 20, 20, 20, 0, 0, 0, 0, 0, 2, 2, 2, 0, 1, 1, 1, 0, 17, 17, 17, 0, 19, 19, 19, 0, 9, 9, 9, 0, 13, 13, 13, 0, 5, 5, 5, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 10, 10, 10, 0, 9, 9, 9, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 11, 11, 11, 0, 14, 14, 14, 0, 8, 8, 8, 0, 4, 4, 4, 0, 19, 19, 19, 0, 6, 6, 6, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 1, 1, 1, 0, 7, 7, 7, 0, 5, 5, 5, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 2, 2, 2, 0, 13, 13, 13, 0, 2, 2, 2, 0, 21, 21, 21, 0, 21, 21, 21, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 2, 2, 2, 0, 21, 21, 21, 0, 4, 4, 4, 0, 10, 10, 10, 0, 19, 19, 19, 0, 2, 2, 2, 0, 19, 19, 19, 0, 1, 1, 1, 0, 13, 13, 13, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 6, 6, 6, 0, 2, 2, 2, 0, 14, 14, 14, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 8, 8, 8, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 2, 2, 2, 0, 18, 18, 18, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 18, 18, 18, 0, 1, 1, 1, 0, 2, 2, 2, 0, 10, 10, 10, 0, 20, 20, 20, 0, 1, 1, 1, 0, 15, 15, 15, 0, 3, 3, 3, 0, 10, 10, 10, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 7, 7, 7, 0, 20, 20, 20, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 16, 16, 16, 0, 21, 21, 21, 0, 20, 20, 20, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 4, 4, 4, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 16, 16, 16, 0, 18, 18, 18, 0, 6, 6, 6, 0, 1, 1, 1, 0, 1, 1, 1, 0, 12, 12, 12, 0, 8, 8, 8, 0, 8, 8, 8, 0, 18, 18, 18, 0, 2, 2, 2, 0, 20, 20, 20, 0, 20, 20, 20, 0, 18, 18, 18, 0, 15, 15, 15, 0, 17, 17, 17, 0, 20, 20, 20, 0, 19, 19, 19, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 21, 21, 21, 0, 2, 2, 2, 0, 6, 6, 6, 0, 14, 14, 14, 0, 18, 18, 18, 0, 8, 8, 8, 0, 2, 2, 2, 0, 19, 19, 19, 0, 16, 16, 16, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 8, 8, 8, 0, 1, 1, 1, 0, 10, 10, 10, 0, 18, 18, 18, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 20, 20, 20, 0, 15, 15, 15, 0, 5, 5, 5, 0, 12, 12, 12, 0, 9, 9, 9, 0, 9, 9, 9, 0, 0, 0, 0, 0, 1, 1, 1, 0, 13, 13, 13, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 1, 1, 1, 0, 20, 20, 20, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 1, 1, 1, 0, 4, 4, 4, 0, 20, 20, 20, 0, 19, 19, 19, 0, 20, 20, 20, 0, 5, 5, 5, 0, 5, 5, 5, 0, 8, 8, 8, 0, 2, 2, 2, 0, 8, 8, 8, 0, 2, 2, 2, 0, 6, 6, 6, 0, 19, 19, 19, 0, 17, 17, 17, 0, 17, 17, 17, 0, 21, 21, 21, 0, 10, 10, 10, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 20, 20, 20, 0, 19, 19, 19, 0, 17, 17, 17, 0, 20, 20, 20, 0, 21, 21, 21, 0, 2, 2, 2, 0, 14, 14, 14, 0, 5, 5, 5, 0, 11, 11, 11, 0, 1, 1, 1, 0, 0, 0, 0, 0, 3, 3, 3, 0, 1, 1, 1, 0, 5, 5, 5, 0, 16, 16, 16, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 20, 20, 20, 0, 15, 15, 15, 0, 2, 2, 2, 0, 10, 10, 10, 0, 20, 20, 20, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 16, 16, 16, 0, 14, 14, 14, 0, 2, 2, 2, 0, 11, 11, 11, 0, 15, 15, 15, 0, 15, 15, 15, 0, 14, 14, 14, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 9, 9, 9, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 17, 17, 17, 0, 20, 20, 20, 0, 1, 1, 1, 0, 7, 7, 7, 0, 6, 6, 6, 0, 14, 14, 14, 0, 8, 8, 8, 0, 16, 16, 16, 0, 11, 11, 11, 0, 20, 20, 20, 0, 7, 7, 7, 0, 15, 15, 15, 0, 9, 9, 9, 0, 19, 19, 19, 0, 21, 21, 21, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 5, 5, 5, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 19, 19, 19, 0, 3, 3, 3, 0, 21, 21, 21, 0, 2, 2, 2, 0, 6, 6, 6, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 7, 7, 7, 0, 8, 8, 8, 0, 21, 21, 21, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 21, 21, 21, 0, 3, 3, 3, 0, 6, 6, 6, 0, 18, 18, 18, 0, 16, 16, 16, 0, 8, 8, 8, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 14, 14, 14, 0, 21, 21, 21, 0, 15, 15, 15, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 21, 21, 21, 0, 7, 7, 7, 0, 19, 19, 19, 0, 7, 7, 7, 0, 20, 20, 20, 0, 19, 19, 19, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 13, 13, 13, 0, 12, 12, 12, 0, 4, 4, 4, 0, 19, 19, 19, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 9, 9, 9, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 18, 18, 18, 0, 9, 9, 9, 0, 6, 6, 6, 0, 19, 19, 19, 0, 19, 19, 19, 0, 12, 12, 12, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 16, 16, 16, 0, 2, 2, 2, 0, 15, 15, 15, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 19, 19, 19, 0, 2, 2, 2, 0, 21, 21, 21, 0, 17, 17, 17, 0, 1, 1, 1, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 20, 20, 20, 0, 13, 13, 13, 0, 16, 16, 16, 0, 8, 8, 8, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 19, 19, 19, 0, 5, 5, 5, 0, 13, 13, 13, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 10, 10, 10, 0, 12, 12, 12, 0, 6, 6, 6, 0, 13, 13, 13, 0, 12, 12, 12, 0, 7, 7, 7, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 21, 21, 21, 0, 19, 19, 19, 0, 18, 18, 18, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 20, 20, 20, 0, 2, 2, 2, 0, 6, 6, 6, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 21, 21, 21, 0, 6, 6, 6, 0, 19, 19, 19, 0, 18, 18, 18, 0, 6, 6, 6, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 2, 2, 2, 0, 9, 9, 9, 0, 3, 3, 3, 0, 2, 2, 2, 0, 12, 12, 12, 0, 19, 19, 19, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 7, 7, 7, 0, 13, 13, 13, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 9, 9, 9, 0, 1, 1, 1, 0, 10, 10, 10, 0, 9, 9, 9, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 20, 20, 20, 0, 6, 6, 6, 0, 4, 4, 4, 0, 1, 1, 1, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 14, 14, 14, 0, 3, 3, 3, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 20, 20, 20, 0, 11, 11, 11, 0, 14, 14, 14, 0, 6, 6, 6, 0, 1, 1, 1, 0, 1, 1, 1, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 2, 2, 2, 0, 13, 13, 13, 0, 7, 7, 7, 0, 11, 11, 11, 0, 1, 1, 1, 0, 19, 19, 19, 0, 19, 19, 19, 0, 21, 21, 21, 0, 21, 21, 21, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 21, 21, 21, 0, 17, 17, 17, 0, 21, 21, 21, 0, 11, 11, 11, 0, 2, 2, 2, 0, 19, 19, 19, 0, 18, 18, 18, 0, 18, 18, 18, 0, 20, 20, 20, 0, 21, 21, 21, 0, 1, 1, 1, 0, 6, 6, 6, 0, 11, 11, 11, 0, 19, 19, 19, 0, 21, 21, 21, 0, 10, 10, 10, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 14, 14, 14, 0, 19, 19, 19, 0, 8, 8, 8, 0, 20, 20, 20, 0, 17, 17, 17, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 19, 19, 19, 0, 1, 1, 1, 0, 0, 0, 0, 0, 9, 9, 9, 0, 2, 2, 2, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 3, 3, 3, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 19, 19, 19, 0, 1, 1, 1, 0, 5, 5, 5, 0, 12, 12, 12, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 10, 10, 10, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 21, 21, 21, 0, 5, 5, 5, 0, 1, 1, 1, 0, 3, 3, 3, 0, 12, 12, 12, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 2, 2, 2, 0, 5, 5, 5, 0, 0, 0, 0, 0, 11, 11, 11, 0, 20, 20, 20, 0, 1, 1, 1, 0, 5, 5, 5, 0, 4, 4, 4, 0, 17, 17, 17, 0, 11, 11, 11, 0, 19, 19, 19, 0, 19, 19, 19, 0, 3, 3, 3, 0, 8, 8, 8, 0, 19, 19, 19, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 13, 13, 13, 0, 3, 3, 3, 0, 1, 1, 1, 0, 15, 15, 15, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 19, 19, 19, 0, 21, 21, 21, 0, 4, 4, 4, 0, 10, 10, 10, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 11, 11, 11, 0, 1, 1, 1, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 3, 3, 3, 0, 1, 1, 1, 0, 1, 1, 1, 0, 21, 21, 21, 0, 6, 6, 6, 0, 14, 14, 14, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 20, 20, 20, 0, 11, 11, 11, 0, 5, 5, 5, 0, 19, 19, 19, 0, 19, 19, 19, 0, 21, 21, 21, 0, 19, 19, 19, 0, 21, 21, 21, 0, 9, 9, 9, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 0, 4, 4, 4, 0, 12, 12, 12, 0, 1, 1, 1, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 12, 12, 12, 0, 6, 6, 6, 0, 0, 0, 0, 0, 3, 3, 3, 0, 14, 14, 14, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 2, 2, 2, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 4, 4, 4, 0, 17, 17, 17, 0, 17, 17, 17, 0, 16, 16, 16, 0, 1, 1, 1, 0, 4, 4, 4, 0, 21, 21, 21, 0, 18, 18, 18, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 13, 13, 13, 0, 17, 17, 17, 0, 2, 2, 2, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 4, 4, 4, 0, 2, 2, 2, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 16, 16, 16, 0, 10, 10, 10, 0, 6, 6, 6, 0, 13, 13, 13, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 3, 3, 3, 0, 21, 21, 21, 0, 1, 1, 1, 0, 5, 5, 5, 0, 21, 21, 21, 0, 2, 2, 2, 0, 4, 4, 4, 0, 14, 14, 14, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 11, 11, 11, 0, 18, 18, 18, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 0, 0, 0, 0, 9, 9, 9, 0, 17, 17, 17, 0, 0, 0, 0, 0, 13, 13, 13, 0, 7, 7, 7, 0, 9, 9, 9, 0, 14, 14, 14, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 16, 16, 16, 0, 1, 1, 1, 0, 20, 20, 20, 0, 17, 17, 17, 0, 18, 18, 18, 0, 1, 1, 1, 0, 11, 11, 11, 0, 11, 11, 11, 0, 20, 20, 20, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 10, 10, 10, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 19, 19, 19, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 2, 2, 2, 0, 7, 7, 7, 0, 20, 20, 20, 0, 12, 12, 12, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 6, 6, 6, 0, 20, 20, 20, 0, 17, 17, 17, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 13, 13, 13, 0, 21, 21, 21, 0, 19, 19, 19, 0, 19, 19, 19, 0, 21, 21, 21, 0, 2, 2, 2, 0, 4, 4, 4, 0, 13, 13, 13, 0, 17, 17, 17, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 16, 16, 16, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 21, 21, 21, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 1, 1, 1, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 17, 17, 17, 0, 21, 21, 21, 0, 8, 8, 8, 0, 16, 16, 16, 0, 16, 16, 16, 0, 19, 19, 19, 0, 6, 6, 6, 0, 17, 17, 17, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 10, 10, 10, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 1, 1, 1, 0, 21, 21, 21, 0, 21, 21, 21, 0, 2, 2, 2, 0, 5, 5, 5, 0, 6, 6, 6, 0, 2, 2, 2, 0, 19, 19, 19, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 7, 7, 7, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 19, 19, 19, 0, 16, 16, 16, 0, 16, 16, 16, 0, 11, 11, 11, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 16, 16, 16, 0, 13, 13, 13, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 13, 13, 13, 0, 17, 17, 17, 0, 8, 8, 8, 0, 2, 2, 2, 0, 19, 19, 19, 0, 7, 7, 7, 0, 14, 14, 14, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 10, 10, 10, 0, 10, 10, 10, 0, 0, 0, 0, 0, 2, 2, 2, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 8, 8, 8, 0, 14, 14, 14, 0, 5, 5, 5, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 21, 21, 21, 0, 20, 20, 20, 0, 18, 18, 18, 0, 2, 2, 2, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 14, 14, 14, 0, 21, 21, 21, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 2, 2, 2, 0, 19, 19, 19, 0, 5, 5, 5, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 11, 11, 11, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 8, 8, 8, 0, 16, 16, 16, 0, 1, 1, 1, 0, 20, 20, 20, 0, 18, 18, 18, 0, 20, 20, 20, 0, 21, 21, 21, 0, 3, 3, 3, 0, 6, 6, 6, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 16, 16, 16, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 19, 19, 19, 0, 15, 15, 15, 0, 0, 0, 0, 0, 8, 8, 8, 0, 20, 20, 20, 0, 17, 17, 17, 0, 17, 17, 17, 0, 2, 2, 2, 0, 0, 0, 0, 0, 8, 8, 8, 0, 17, 17, 17, 0, 16, 16, 16, 0, 3, 3, 3, 0, 18, 18, 18, 0, 17, 17, 17, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 19, 19, 19, 0, 11, 11, 11, 0, 6, 6, 6, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 16, 16, 16, 0, 13, 13, 13, 0, 1, 1, 1, 0, 17, 17, 17, 0, 5, 5, 5, 0, 1, 1, 1, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 20, 20, 20, 0, 20, 20, 20, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 2, 2, 2, 0, 14, 14, 14, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 19, 19, 19, 0, 16, 16, 16, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 18, 18, 18, 0, 21, 21, 21, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 8, 8, 8, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 2, 2, 2, 0, 20, 20, 20, 0, 8, 8, 8, 0, 16, 16, 16, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 18, 18, 18, 0, 21, 21, 21, 0, 14, 14, 14, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 3, 3, 3, 0, 21, 21, 21, 0, 13, 13, 13, 0, 19, 19, 19, 0, 21, 21, 21, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 18, 18, 18, 0, 16, 16, 16, 0, 4, 4, 4, 0, 8, 8, 8, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 2, 2, 2, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 11, 11, 11, 0, 8, 8, 8, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 4, 4, 4, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 2, 2, 2, 0, 4, 4, 4, 0, 8, 8, 8, 0, 3, 3, 3, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 9, 9, 9, 0, 13, 13, 13, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 14, 14, 14, 0, 20, 20, 20, 0, 19, 19, 19, 0, 15, 15, 15, 0, 11, 11, 11, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 20, 20, 20, 0, 1, 1, 1, 0, 3, 3, 3, 0, 20, 20, 20, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 12, 12, 12, 0, 16, 16, 16, 0, 7, 7, 7, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 19, 19, 19, 0, 20, 20, 20, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 18, 18, 18, 0, 12, 12, 12, 0, 6, 6, 6, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 8, 8, 8, 0, 2, 2, 2, 0, 17, 17, 17, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 9, 9, 9, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 15, 15, 15, 0, 3, 3, 3, 0, 9, 9, 9, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 16, 16, 16, 0, 17, 17, 17, 0, 21, 21, 21, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 7, 7, 7, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 18, 18, 18, 0, 10, 10, 10, 0, 10, 10, 10, 0, 15, 15, 15, 0, 7, 7, 7, 0, 21, 21, 21, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 1, 1, 1, 0, 2, 2, 2, 0, 4, 4, 4, 0, 8, 8, 8, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 20, 20, 20, 0, 10, 10, 10, 0, 20, 20, 20, 0, 18, 18, 18, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 17, 17, 17, 0, 19, 19, 19, 0, 1, 1, 1, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 6, 6, 6, 0, 18, 18, 18, 0, 1, 1, 1, 0, 21, 21, 21, 0, 12, 12, 12, 0, 1, 1, 1, 0, 13, 13, 13, 0, 10, 10, 10, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 12, 12, 12, 0, 11, 11, 11, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 18, 18, 18, 0, 20, 20, 20, 0, 18, 18, 18, 0, 18, 18, 18, 0, 20, 20, 20, 0, 21, 21, 21, 0, 9, 9, 9, 0, 8, 8, 8, 0, 10, 10, 10, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 16, 16, 16, 0, 4, 4, 4, 0, 10, 10, 10, 0, 3, 3, 3, 0, 18, 18, 18, 0, 15, 15, 15, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 3, 3, 3, 0, 8, 8, 8, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 8, 8, 8, 0, 2, 2, 2, 0, 16, 16, 16, 0, 20, 20, 20, 0, 5, 5, 5, 0, 3, 3, 3, 0, 14, 14, 14, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 11, 11, 11, 0, 20, 20, 20, 0, 17, 17, 17, 0, 16, 16, 16, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 20, 20, 20, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 20, 20, 20, 0, 21, 21, 21, 0, 21, 21, 21, 0, 0, 0, 0, 0, 6, 6, 6, 0, 7, 7, 7, 0, 12, 12, 12, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 17, 17, 17, 0, 7, 7, 7, 0, 11, 11, 11, 0, 7, 7, 7, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 19, 19, 19, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 20, 20, 20, 0, 21, 21, 21, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 14, 14, 14, 0, 3, 3, 3, 0, 16, 16, 16, 0, 18, 18, 18, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 21, 21, 21, 0, 16, 16, 16, 0, 15, 15, 15, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 20, 20, 20, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 15, 15, 15, 0, 21, 21, 21, 0, 2, 2, 2, 0, 21, 21, 21, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 5, 5, 5, 0, 21, 21, 21, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 18, 18, 18, 0, 1, 1, 1, 0, 5, 5, 5, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 17, 17, 17, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 17, 17, 17, 0, 15, 15, 15, 0, 2, 2, 2, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 14, 14, 14, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 2, 2, 2, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 5, 5, 5, 0, 20, 20, 20, 0, 11, 11, 11, 0, 20, 20, 20, 0, 19, 19, 19, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 0, 0, 0, 0, 17, 17, 17, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 18, 18, 18, 0, 16, 16, 16, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 14, 14, 14, 0, 17, 17, 17, 0, 3, 3, 3, 0, 4, 4, 4, 0, 19, 19, 19, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 17, 17, 17, 0, 3, 3, 3, 0, 19, 19, 19, 0, 15, 15, 15, 0, 9, 9, 9, 0, 21, 21, 21, 0, 8, 8, 8, 0, 20, 20, 20, 0, 1, 1, 1, 0, 5, 5, 5, 0, 14, 14, 14, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 6, 6, 6, 0, 17, 17, 17, 0, 12, 12, 12, 0, 18, 18, 18, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 2, 2, 2, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 10, 10, 10, 0, 15, 15, 15, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 1, 1, 1, 0, 10, 10, 10, 0, 20, 20, 20, 0, 10, 10, 10, 0, 10, 10, 10, 0, 2, 2, 2, 0, 3, 3, 3, 0, 10, 10, 10, 0, 19, 19, 19, 0, 9, 9, 9, 0, 6, 6, 6, 0, 11, 11, 11, 0, 3, 3, 3, 0, 2, 2, 2, 0, 6, 6, 6, 0, 11, 11, 11, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 2, 2, 2, 0, 10, 10, 10, 0, 16, 16, 16, 0, 1, 1, 1, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 3, 3, 3, 0, 13, 13, 13, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 16, 16, 16, 0, 16, 16, 16, 0, 19, 19, 19, 0, 10, 10, 10, 0, 18, 18, 18, 0, 3, 3, 3, 0, 18, 18, 18, 0, 1, 1, 1, 0, 14, 14, 14, 0, 12, 12, 12, 0, 8, 8, 8, 0, 0, 0, 0, 0, 6, 6, 6, 0, 13, 13, 13, 0, 18, 18, 18, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 19, 19, 19, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 18, 18, 18, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 2, 2, 2, 0, 16, 16, 16, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 19, 19, 19, 0, 2, 2, 2, 0, 10, 10, 10, 0, 5, 5, 5, 0, 0, 0, 0, 0, 17, 17, 17, 0, 15, 15, 15, 0, 3, 3, 3, 0, 20, 20, 20, 0, 18, 18, 18, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 17, 17, 17, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 10, 10, 10, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 2, 2, 2, 0, 0, 0, 0, 0, 12, 12, 12, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 20, 20, 20, 0, 2, 2, 2, 0, 19, 19, 19, 0, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 19, 19, 19, 0, 2, 2, 2, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 20, 20, 20, 0, 6, 6, 6, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 5, 5, 5, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 19, 19, 19, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 19, 19, 19, 0, 18, 18, 18, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 6, 6, 6, 0, 17, 17, 17, 0, 20, 20, 20, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 20, 20, 20, 0, 1, 1, 1, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 16, 16, 16, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 19, 19, 19, 0, 19, 19, 19, 0, 21, 21, 21, 0, 11, 11, 11, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 20, 20, 20, 0, 20, 20, 20, 0, 15, 15, 15, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 17, 17, 17, 0, 15, 15, 15, 0, 2, 2, 2, 0, 20, 20, 20, 0, 16, 16, 16, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 13, 13, 13, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 5, 5, 5, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 19, 19, 19, 0, 9, 9, 9, 0, 21, 21, 21, 0, 20, 20, 20, 0, 20, 20, 20, 0, 20, 20, 20, 0, 20, 20, 20, 0, 21, 21, 21, 0, 7, 7, 7, 0, 17, 17, 17, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 20, 20, 20, 0, 21, 21, 21, 0, 11, 11, 11, 0, 16, 16, 16, 0, 10, 10, 10, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 20, 20, 20, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 20, 20, 20, 0, 2, 2, 2, 0, 20, 20, 20, 0, 13, 13, 13, 0, 20, 20, 20, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 2, 2, 2, 0, 21, 21, 21, 0, 21, 21, 21, 0, 21, 21, 21, 0, 21, 21, 21, 0, 1, 1, 1, 0, 4, 4, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 5, 5, 5, 0, 18, 18, 18, 0, 16, 16, 16, 0, 12, 12, 12, 0, 9, 9, 9, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 2, 2, 2, 0, 12, 12, 12, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 4, 4, 4, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 21, 21, 21, 0, 1, 1, 1, 0, 21, 21, 21, 0, 21, 21, 21, 0, 1, 1, 1, 0, 1, 1, 1, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 21, 21, 21, 0, 20, 20, 20, 0, 18, 18, 18, 0, 10, 10, 10, 0, 5, 5, 5, 0, 8, 8, 8, 0, 12, 12, 12, 0, 3, 3, 3, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 13, 13, 13, 0, 18, 18, 18, 0, 19, 19, 19, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 5, 5, 5, 0, 21, 21, 21, 0, 3, 3, 3, 0, 3, 3, 3, 0, 18, 18, 18, 0, 0, 0, 0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 19, 19, 19, 0, 0, 0, 0, 0, 20, 20, 20, 0, 11, 11, 11, 0, 6, 6, 6, 0, 1, 1, 1, 0, 15, 15, 15, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 11, 11, 11, 0, 3, 3, 3, 0, 20, 20, 20, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 15, 15, 15, 0, 5, 5, 5, 0, 3, 3, 3, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 17, 17, 17, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 9, 9, 9, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 3, 3, 3, 0, 16, 16, 16, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 14, 14, 14, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 21, 21, 21, 0, 21, 21, 21, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 20, 20, 20, 0, 2, 2, 2, 0, 21, 21, 21, 0, 7, 7, 7, 0, 10, 10, 10, 0, 5, 5, 5, 0, 18, 18, 18, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 20, 20, 20, 0, 18, 18, 18, 0, 17, 17, 17, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 16, 16, 16, 0, 15, 15, 15, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 18, 18, 18, 0, 19, 19, 19, 0, 8, 8, 8, 0, 1, 1, 1, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 12, 12, 12, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 17, 17, 17, 0, 6, 6, 6, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 2, 2, 2, 0, 10, 10, 10, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 8, 8, 8, 0, 1, 1, 1, 0, 14, 14, 14, 0, 14, 14, 14, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 8, 8, 8, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 6, 6, 6, 0, 17, 17, 17, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 16, 16, 16, 0, 7, 7, 7, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 7, 7, 7, 0, 8, 8, 8, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 17, 17, 17, 0, 15, 15, 15, 0, 19, 19, 19, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 17, 17, 17, 0, 21, 21, 21, 0, 15, 15, 15, 0, 15, 15, 15, 0, 7, 7, 7, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 4, 4, 4, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 2, 2, 2, 0, 6, 6, 6, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 10, 10, 10, 0, 8, 8, 8, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 2, 2, 2, 0, 14, 14, 14, 0, 3, 3, 3, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 9, 9, 9, 0, 2, 2, 2, 0, 10, 10, 10, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 19, 19, 19, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 20, 20, 20, 0, 20, 20, 20, 0, 21, 21, 21, 0, 16, 16, 16, 0, 19, 19, 19, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 10, 10, 10, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 15, 15, 15, 0, 11, 11, 11, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 3, 3, 3, 0, 5, 5, 5, 0, 18, 18, 18, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 20, 20, 20, 0, 8, 8, 8, 0, 8, 8, 8, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 1, 1, 1, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 21, 21, 21, 0, 8, 8, 8, 0, 2, 2, 2, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 12, 12, 12, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 8, 8, 8, 0, 21, 21, 21, 0, 15, 15, 15, 0, 15, 15, 15, 0, 3, 3, 3, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 6, 6, 6, 0, 21, 21, 21, 0, 20, 20, 20, 0, 17, 17, 17, 0, 16, 16, 16, 0, 18, 18, 18, 0, 18, 18, 18, 0, 16, 16, 16, 0, 17, 17, 17, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 20, 20, 20, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 13, 13, 13, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 8, 8, 8, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 1, 1, 1, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 18, 18, 18, 0, 9, 9, 9, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 4, 4, 4, 0, 8, 8, 8, 0, 1, 1, 1, 0, 19, 19, 19, 0, 17, 17, 17, 0, 20, 20, 20, 0, 19, 19, 19, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 2, 2, 2, 0, 10, 10, 10, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 18, 18, 18, 0, 19, 19, 19, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 9, 9, 9, 0, 2, 2, 2, 0, 1, 1, 1, 0, 21, 21, 21, 0, 21, 21, 21, 0, 9, 9, 9, 0, 15, 15, 15, 0, 1, 1, 1, 0, 10, 10, 10, 0, 2, 2, 2, 0, 12, 12, 12, 0, 19, 19, 19, 0, 1, 1, 1, 0, 20, 20, 20, 0, 1, 1, 1, 0, 20, 20, 20, 0, 19, 19, 19, 0, 19, 19, 19, 0, 13, 13, 13, 0, 4, 4, 4, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 20, 20, 20, 0, 8, 8, 8, 0, 18, 18, 18, 0, 4, 4, 4, 0, 14, 14, 14, 0, 4, 4, 4, 0, 10, 10, 10, 0, 20, 20, 20, 0, 3, 3, 3, 0, 5, 5, 5, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 13, 13, 13, 0, 9, 9, 9, 0, 16, 16, 16, 0, 16, 16, 16, 0, 10, 10, 10, 0, 2, 2, 2, 0, 3, 3, 3, 0, 21, 21, 21, 0, 21, 21, 21, 0, 21, 21, 21, 0, 3, 3, 3, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0, 11, 11, 11, 0, 5, 5, 5, 0, 16, 16, 16, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 19, 19, 19, 0, 1, 1, 1, 0, 7, 7, 7, 0, 16, 16, 16, 0, 17, 17, 17, 0, 16, 16, 16, 0, 1, 1, 1, 0, 8, 8, 8, 0, 16, 16, 16, 0, 12, 12, 12, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 18, 18, 18, 0, 19, 19, 19, 0, 15, 15, 15, 0, 18, 18, 18, 0, 7, 7, 7, 0, 2, 2, 2, 0, 21, 21, 21, 0, 2, 2, 2, 0, 2, 2, 2, 0, 6, 6, 6, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 15, 15, 15, 0, 0, 0, 0, 0, 3, 3, 3, 0, 20, 20, 20, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 12, 12, 12, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 18, 18, 18, 0, 21, 21, 21, 0, 4, 4, 4, 0, 12, 12, 12, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 11, 11, 11, 0, 21, 21, 21, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 18, 18, 18, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 18, 18, 18, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 15, 15, 15, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 12, 12, 12, 0, 21, 21, 21, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 14, 14, 14, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 10, 10, 10, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 20, 20, 20, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 16, 16, 16, 0, 2, 2, 2, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 21, 21, 21, 0, 18, 18, 18, 0, 19, 19, 19, 0, 20, 20, 20, 0, 2, 2, 2, 0, 6, 6, 6, 0, 15, 15, 15, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 10, 10, 10, 0, 8, 8, 8, 0, 12, 12, 12, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 14, 14, 14, 0, 10, 10, 10, 0, 20, 20, 20, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 1, 1, 1, 0, 9, 9, 9, 0, 1, 1, 1, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 10, 10, 10, 0, 9, 9, 9, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 12, 12, 12, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 18, 18, 18, 0, 6, 6, 6, 0, 1, 1, 1, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 12, 12, 12, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 16, 16, 16, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 4, 4, 4, 0, 19, 19, 19, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 9, 9, 9, 0, 16, 16, 16, 0, 18, 18, 18, 0, 3, 3, 3, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 17, 17, 17, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 1, 1, 1, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 1, 1, 1, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 16, 16, 16, 0, 21, 21, 21, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 14, 14, 14, 0, 20, 20, 20, 0, 18, 18, 18, 0, 17, 17, 17, 0, 18, 18, 18, 0, 20, 20, 20, 0, 2, 2, 2, 0, 7, 7, 7, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 19, 19, 19, 0, 8, 8, 8, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 17, 17, 17, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 16, 16, 16, 0, 2, 2, 2, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 20, 20, 20, 0, 10, 10, 10, 0, 5, 5, 5, 0, 20, 20, 20, 0, 20, 20, 20, 0, 1, 1, 1, 0, 15, 15, 15, 0, 9, 9, 9, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 13, 13, 13, 0, 15, 15, 15, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 13, 13, 13, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 14, 14, 14, 0, 14, 14, 14, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 16, 16, 16, 0, 17, 17, 17, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 21, 21, 21, 0, 11, 11, 11, 0, 5, 5, 5, 0, 3, 3, 3, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 13, 13, 13, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 13, 13, 13, 0, 15, 15, 15, 0, 13, 13, 13, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 20, 20, 20, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 18, 18, 18, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 2, 2, 2, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 2, 2, 2, 0, 4, 4, 4, 0, 8, 8, 8, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 19, 19, 19, 0, 19, 19, 19, 0, 0, 0, 0, 0, 1, 1, 1, 0, 19, 19, 19, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 10, 10, 10, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 21, 21, 21, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 2, 2, 2, 0, 18, 18, 18, 0, 18, 18, 18, 0, 1, 1, 1, 0, 3, 3, 3, 0, 12, 12, 12, 0, 3, 3, 3, 0, 12, 12, 12, 0, 0, 0, 0, 0, 14, 14, 14, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 20, 20, 20, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 20, 20, 20, 0, 19, 19, 19, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 17, 17, 17, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 15, 15, 15, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 17, 17, 17, 0, 2, 2, 2, 0, 19, 19, 19, 0, 2, 2, 2, 0, 16, 16, 16, 0, 15, 15, 15, 0, 16, 16, 16, 0, 20, 20, 20, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 19, 19, 19, 0, 2, 2, 2, 0, 21, 21, 21, 0, 4, 4, 4, 0, 9, 9, 9, 0, 14, 14, 14, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 16, 16, 16, 0, 19, 19, 19, 0, 1, 1, 1, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 17, 17, 17, 0, 8, 8, 8, 0, 2, 2, 2, 0, 16, 16, 16, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 13, 13, 13, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 18, 18, 18, 0, 14, 14, 14, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 15, 15, 15, 0, 17, 17, 17, 0, 5, 5, 5, 0, 8, 8, 8, 0, 10, 10, 10, 0, 19, 19, 19, 0, 17, 17, 17, 0, 20, 20, 20, 0, 19, 19, 19, 0, 10, 10, 10, 0, 21, 21, 21, 0, 20, 20, 20, 0, 19, 19, 19, 0, 20, 20, 20, 0, 21, 21, 21, 0, 18, 18, 18, 0, 6, 6, 6, 0, 10, 10, 10, 0, 20, 20, 20, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 4, 4, 4, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 14, 14, 14, 0, 7, 7, 7, 0, 10, 10, 10, 0, 13, 13, 13, 0, 14, 14, 14, 0, 12, 12, 12, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 10, 10, 10, 0, 16, 16, 16, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 12, 12, 12, 0, 1, 1, 1, 0, 16, 16, 16, 0, 11, 11, 11, 0, 1, 1, 1, 0, 20, 20, 20, 0, 6, 6, 6, 0, 15, 15, 15, 0, 2, 2, 2, 0, 16, 16, 16, 0, 3, 3, 3, 0, 20, 20, 20, 0, 3, 3, 3, 0, 15, 15, 15, 0, 2, 2, 2, 0, 6, 6, 6, 0, 17, 17, 17, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 8, 8, 8, 0, 6, 6, 6, 0, 7, 7, 7, 0, 20, 20, 20, 0, 13, 13, 13, 0, 10, 10, 10, 0, 13, 13, 13, 0, 7, 7, 7, 0, 4, 4, 4, 0, 0, 0, 0, 0, 19, 19, 19, 0, 7, 7, 7, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 1, 1, 1, 0, 13, 13, 13, 0, 8, 8, 8, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 20, 20, 20, 0, 19, 19, 19, 0, 21, 21, 21, 0, 11, 11, 11, 0, 20, 20, 20, 0, 14, 14, 14, 0, 16, 16, 16, 0, 9, 9, 9, 0, 16, 16, 16, 0, 13, 13, 13, 0, 4, 4, 4, 0, 2, 2, 2, 0, 21, 21, 21, 0, 0, 0, 0, 0, 1, 1, 1, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 6, 6, 6, 0, 21, 21, 21, 0, 18, 18, 18, 0, 16, 16, 16, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 16, 16, 16, 0, 19, 19, 19, 0, 1, 1, 1, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 17, 17, 17, 0, 8, 8, 8, 0, 2, 2, 2, 0, 16, 16, 16, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 13, 13, 13, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 18, 18, 18, 0, 14, 14, 14, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 15, 15, 15, 0, 17, 17, 17, 0, 5, 5, 5, 0, 8, 8, 8, 0, 10, 10, 10, 0, 19, 19, 19, 0, 17, 17, 17, 0, 20, 20, 20, 0, 19, 19, 19, 0, 10, 10, 10, 0, 21, 21, 21, 0, 20, 20, 20, 0, 19, 19, 19, 0, 20, 20, 20, 0, 21, 21, 21, 0, 18, 18, 18, 0, 6, 6, 6, 0, 10, 10, 10, 0, 20, 20, 20, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 20, 20, 20, 0, 19, 19, 19, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 17, 17, 17, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 15, 15, 15, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 17, 17, 17, 0, 2, 2, 2, 0, 19, 19, 19, 0, 2, 2, 2, 0, 16, 16, 16, 0, 15, 15, 15, 0, 16, 16, 16, 0, 20, 20, 20, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 19, 19, 19, 0, 2, 2, 2, 0, 21, 21, 21, 0, 4, 4, 4, 0, 9, 9, 9, 0, 14, 14, 14, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 19, 19, 19, 0, 19, 19, 19, 0, 0, 0, 0, 0, 1, 1, 1, 0, 19, 19, 19, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 10, 10, 10, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 21, 21, 21, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 2, 2, 2, 0, 18, 18, 18, 0, 18, 18, 18, 0, 1, 1, 1, 0, 3, 3, 3, 0, 12, 12, 12, 0, 3, 3, 3, 0, 12, 12, 12, 0, 0, 0, 0, 0, 14, 14, 14, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 20, 20, 20, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 13, 13, 13, 0, 15, 15, 15, 0, 13, 13, 13, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 20, 20, 20, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 18, 18, 18, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 2, 2, 2, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 2, 2, 2, 0, 4, 4, 4, 0, 8, 8, 8, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 13, 13, 13, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 14, 14, 14, 0, 14, 14, 14, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 16, 16, 16, 0, 17, 17, 17, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 21, 21, 21, 0, 11, 11, 11, 0, 5, 5, 5, 0, 3, 3, 3, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 13, 13, 13, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 17, 17, 17, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 16, 16, 16, 0, 2, 2, 2, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 20, 20, 20, 0, 10, 10, 10, 0, 5, 5, 5, 0, 20, 20, 20, 0, 20, 20, 20, 0, 1, 1, 1, 0, 15, 15, 15, 0, 9, 9, 9, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 13, 13, 13, 0, 15, 15, 15, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 1, 1, 1, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 16, 16, 16, 0, 21, 21, 21, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 14, 14, 14, 0, 20, 20, 20, 0, 18, 18, 18, 0, 17, 17, 17, 0, 18, 18, 18, 0, 20, 20, 20, 0, 2, 2, 2, 0, 7, 7, 7, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 19, 19, 19, 0, 8, 8, 8, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 12, 12, 12, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 16, 16, 16, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 4, 4, 4, 0, 19, 19, 19, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 9, 9, 9, 0, 16, 16, 16, 0, 18, 18, 18, 0, 3, 3, 3, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 17, 17, 17, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 1, 1, 1, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 1, 1, 1, 0, 9, 9, 9, 0, 1, 1, 1, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 2, 2, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 10, 10, 10, 0, 9, 9, 9, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 12, 12, 12, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 18, 18, 18, 0, 6, 6, 6, 0, 1, 1, 1, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 16, 16, 16, 0, 2, 2, 2, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 21, 21, 21, 0, 18, 18, 18, 0, 19, 19, 19, 0, 20, 20, 20, 0, 2, 2, 2, 0, 6, 6, 6, 0, 15, 15, 15, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 10, 10, 10, 0, 8, 8, 8, 0, 12, 12, 12, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 14, 14, 14, 0, 10, 10, 10, 0, 20, 20, 20, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 15, 15, 15, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 12, 12, 12, 0, 21, 21, 21, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 14, 14, 14, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 10, 10, 10, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 20, 20, 20, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 12, 12, 12, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 18, 18, 18, 0, 21, 21, 21, 0, 4, 4, 4, 0, 12, 12, 12, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 11, 11, 11, 0, 21, 21, 21, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 18, 18, 18, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 18, 18, 18, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 19, 19, 19, 0, 1, 1, 1, 0, 7, 7, 7, 0, 16, 16, 16, 0, 17, 17, 17, 0, 16, 16, 16, 0, 1, 1, 1, 0, 8, 8, 8, 0, 16, 16, 16, 0, 12, 12, 12, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 18, 18, 18, 0, 19, 19, 19, 0, 15, 15, 15, 0, 18, 18, 18, 0, 7, 7, 7, 0, 2, 2, 2, 0, 21, 21, 21, 0, 2, 2, 2, 0, 2, 2, 2, 0, 6, 6, 6, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 15, 15, 15, 0, 0, 0, 0, 0, 3, 3, 3, 0, 20, 20, 20, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 20, 20, 20, 0, 8, 8, 8, 0, 18, 18, 18, 0, 4, 4, 4, 0, 14, 14, 14, 0, 4, 4, 4, 0, 10, 10, 10, 0, 20, 20, 20, 0, 3, 3, 3, 0, 5, 5, 5, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 13, 13, 13, 0, 9, 9, 9, 0, 16, 16, 16, 0, 16, 16, 16, 0, 10, 10, 10, 0, 2, 2, 2, 0, 3, 3, 3, 0, 21, 21, 21, 0, 21, 21, 21, 0, 21, 21, 21, 0, 3, 3, 3, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0, 11, 11, 11, 0, 5, 5, 5, 0, 16, 16, 16, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 18, 18, 18, 0, 19, 19, 19, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 9, 9, 9, 0, 2, 2, 2, 0, 1, 1, 1, 0, 21, 21, 21, 0, 21, 21, 21, 0, 9, 9, 9, 0, 15, 15, 15, 0, 1, 1, 1, 0, 10, 10, 10, 0, 2, 2, 2, 0, 12, 12, 12, 0, 19, 19, 19, 0, 1, 1, 1, 0, 20, 20, 20, 0, 1, 1, 1, 0, 20, 20, 20, 0, 19, 19, 19, 0, 19, 19, 19, 0, 13, 13, 13, 0, 4, 4, 4, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 4, 4, 4, 0, 8, 8, 8, 0, 1, 1, 1, 0, 19, 19, 19, 0, 17, 17, 17, 0, 20, 20, 20, 0, 19, 19, 19, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 2, 2, 2, 0, 10, 10, 10, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 6, 6, 6, 0, 21, 21, 21, 0, 20, 20, 20, 0, 17, 17, 17, 0, 16, 16, 16, 0, 18, 18, 18, 0, 18, 18, 18, 0, 16, 16, 16, 0, 17, 17, 17, 0, 3, 3, 3, 0, 4, 4, 4, 0, 9, 9, 9, 0, 20, 20, 20, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 13, 13, 13, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 8, 8, 8, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 1, 1, 1, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 18, 18, 18, 0, 9, 9, 9, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 3, 3, 3, 0, 5, 5, 5, 0, 18, 18, 18, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 20, 20, 20, 0, 8, 8, 8, 0, 8, 8, 8, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 1, 1, 1, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 21, 21, 21, 0, 8, 8, 8, 0, 2, 2, 2, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 12, 12, 12, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 8, 8, 8, 0, 21, 21, 21, 0, 15, 15, 15, 0, 15, 15, 15, 0, 3, 3, 3, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 9, 9, 9, 0, 2, 2, 2, 0, 10, 10, 10, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 19, 19, 19, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 20, 20, 20, 0, 20, 20, 20, 0, 21, 21, 21, 0, 16, 16, 16, 0, 19, 19, 19, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 10, 10, 10, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 15, 15, 15, 0, 11, 11, 11, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 17, 17, 17, 0, 21, 21, 21, 0, 15, 15, 15, 0, 15, 15, 15, 0, 7, 7, 7, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 4, 4, 4, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 2, 2, 2, 0, 6, 6, 6, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 10, 10, 10, 0, 8, 8, 8, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 2, 2, 2, 0, 14, 14, 14, 0, 3, 3, 3, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 8, 8, 8, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 6, 6, 6, 0, 17, 17, 17, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 16, 16, 16, 0, 7, 7, 7, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 7, 7, 7, 0, 8, 8, 8, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 17, 17, 17, 0, 15, 15, 15, 0, 19, 19, 19, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 12, 12, 12, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 17, 17, 17, 0, 6, 6, 6, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 2, 2, 2, 0, 10, 10, 10, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 8, 8, 8, 0, 1, 1, 1, 0, 14, 14, 14, 0, 14, 14, 14, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 20, 20, 20, 0, 18, 18, 18, 0, 17, 17, 17, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 16, 16, 16, 0, 15, 15, 15, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 18, 18, 18, 0, 19, 19, 19, 0, 8, 8, 8, 0, 1, 1, 1, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 21, 21, 21, 0, 21, 21, 21, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 20, 20, 20, 0, 2, 2, 2, 0, 21, 21, 21, 0, 7, 7, 7, 0, 10, 10, 10, 0, 5, 5, 5, 0, 18, 18, 18, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 11, 11, 11, 0, 3, 3, 3, 0, 20, 20, 20, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 15, 15, 15, 0, 5, 5, 5, 0, 3, 3, 3, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 17, 17, 17, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 9, 9, 9, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 3, 3, 3, 0, 16, 16, 16, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 14, 14, 14, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 13, 13, 13, 0, 18, 18, 18, 0, 19, 19, 19, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 5, 5, 5, 0, 21, 21, 21, 0, 3, 3, 3, 0, 3, 3, 3, 0, 18, 18, 18, 0, 0, 0, 0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 19, 19, 19, 0, 0, 0, 0, 0, 20, 20, 20, 0, 11, 11, 11, 0, 6, 6, 6, 0, 1, 1, 1, 0, 15, 15, 15, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 2, 2, 2, 0, 12, 12, 12, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 4, 4, 4, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 21, 21, 21, 0, 1, 1, 1, 0, 21, 21, 21, 0, 21, 21, 21, 0, 1, 1, 1, 0, 1, 1, 1, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 21, 21, 21, 0, 20, 20, 20, 0, 18, 18, 18, 0, 10, 10, 10, 0, 5, 5, 5, 0, 8, 8, 8, 0, 12, 12, 12, 0, 3, 3, 3, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 20, 20, 20, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 20, 20, 20, 0, 2, 2, 2, 0, 20, 20, 20, 0, 13, 13, 13, 0, 20, 20, 20, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 2, 2, 2, 0, 21, 21, 21, 0, 21, 21, 21, 0, 21, 21, 21, 0, 21, 21, 21, 0, 1, 1, 1, 0, 4, 4, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 5, 5, 5, 0, 18, 18, 18, 0, 16, 16, 16, 0, 12, 12, 12, 0, 9, 9, 9, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 13, 13, 13, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 5, 5, 5, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 19, 19, 19, 0, 9, 9, 9, 0, 21, 21, 21, 0, 20, 20, 20, 0, 20, 20, 20, 0, 20, 20, 20, 0, 20, 20, 20, 0, 21, 21, 21, 0, 7, 7, 7, 0, 17, 17, 17, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 20, 20, 20, 0, 21, 21, 21, 0, 11, 11, 11, 0, 16, 16, 16, 0, 10, 10, 10, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 16, 16, 16, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 19, 19, 19, 0, 19, 19, 19, 0, 21, 21, 21, 0, 11, 11, 11, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 20, 20, 20, 0, 20, 20, 20, 0, 15, 15, 15, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 17, 17, 17, 0, 15, 15, 15, 0, 2, 2, 2, 0, 20, 20, 20, 0, 16, 16, 16, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 19, 19, 19, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 19, 19, 19, 0, 18, 18, 18, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 6, 6, 6, 0, 17, 17, 17, 0, 20, 20, 20, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 20, 20, 20, 0, 1, 1, 1, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 10, 10, 10, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 2, 2, 2, 0, 0, 0, 0, 0, 12, 12, 12, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 20, 20, 20, 0, 2, 2, 2, 0, 19, 19, 19, 0, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 19, 19, 19, 0, 2, 2, 2, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 20, 20, 20, 0, 6, 6, 6, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 5, 5, 5, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 19, 19, 19, 0, 2, 2, 2, 0, 10, 10, 10, 0, 5, 5, 5, 0, 0, 0, 0, 0, 17, 17, 17, 0, 15, 15, 15, 0, 3, 3, 3, 0, 20, 20, 20, 0, 18, 18, 18, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 17, 17, 17, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 16, 16, 16, 0, 16, 16, 16, 0, 19, 19, 19, 0, 10, 10, 10, 0, 18, 18, 18, 0, 3, 3, 3, 0, 18, 18, 18, 0, 1, 1, 1, 0, 14, 14, 14, 0, 12, 12, 12, 0, 8, 8, 8, 0, 0, 0, 0, 0, 6, 6, 6, 0, 13, 13, 13, 0, 18, 18, 18, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 19, 19, 19, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 18, 18, 18, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 2, 2, 2, 0, 16, 16, 16, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 1, 1, 1, 0, 10, 10, 10, 0, 20, 20, 20, 0, 10, 10, 10, 0, 10, 10, 10, 0, 2, 2, 2, 0, 3, 3, 3, 0, 10, 10, 10, 0, 19, 19, 19, 0, 9, 9, 9, 0, 6, 6, 6, 0, 11, 11, 11, 0, 3, 3, 3, 0, 2, 2, 2, 0, 6, 6, 6, 0, 11, 11, 11, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 2, 2, 2, 0, 10, 10, 10, 0, 16, 16, 16, 0, 1, 1, 1, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 3, 3, 3, 0, 13, 13, 13, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 14, 14, 14, 0, 17, 17, 17, 0, 3, 3, 3, 0, 4, 4, 4, 0, 19, 19, 19, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 17, 17, 17, 0, 3, 3, 3, 0, 19, 19, 19, 0, 15, 15, 15, 0, 9, 9, 9, 0, 21, 21, 21, 0, 8, 8, 8, 0, 20, 20, 20, 0, 1, 1, 1, 0, 5, 5, 5, 0, 14, 14, 14, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 6, 6, 6, 0, 17, 17, 17, 0, 12, 12, 12, 0, 18, 18, 18, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 2, 2, 2, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 10, 10, 10, 0, 15, 15, 15, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 17, 17, 17, 0, 15, 15, 15, 0, 2, 2, 2, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 14, 14, 14, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 2, 2, 2, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 5, 5, 5, 0, 20, 20, 20, 0, 11, 11, 11, 0, 20, 20, 20, 0, 19, 19, 19, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 0, 0, 0, 0, 17, 17, 17, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 18, 18, 18, 0, 16, 16, 16, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 21, 21, 21, 0, 16, 16, 16, 0, 15, 15, 15, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 20, 20, 20, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 15, 15, 15, 0, 21, 21, 21, 0, 2, 2, 2, 0, 21, 21, 21, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 5, 5, 5, 0, 21, 21, 21, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 18, 18, 18, 0, 1, 1, 1, 0, 5, 5, 5, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 17, 17, 17, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 11, 11, 11, 0, 20, 20, 20, 0, 17, 17, 17, 0, 16, 16, 16, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 20, 20, 20, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 20, 20, 20, 0, 21, 21, 21, 0, 21, 21, 21, 0, 0, 0, 0, 0, 6, 6, 6, 0, 7, 7, 7, 0, 12, 12, 12, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 17, 17, 17, 0, 7, 7, 7, 0, 11, 11, 11, 0, 7, 7, 7, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 19, 19, 19, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 20, 20, 20, 0, 21, 21, 21, 0, 5, 5, 5, 0, 7, 7, 7, 0, 6, 6, 6, 0, 14, 14, 14, 0, 3, 3, 3, 0, 16, 16, 16, 0, 18, 18, 18, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 12, 12, 12, 0, 11, 11, 11, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 18, 18, 18, 0, 20, 20, 20, 0, 18, 18, 18, 0, 18, 18, 18, 0, 20, 20, 20, 0, 21, 21, 21, 0, 9, 9, 9, 0, 8, 8, 8, 0, 10, 10, 10, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 16, 16, 16, 0, 4, 4, 4, 0, 10, 10, 10, 0, 3, 3, 3, 0, 18, 18, 18, 0, 15, 15, 15, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 3, 3, 3, 0, 8, 8, 8, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 8, 8, 8, 0, 2, 2, 2, 0, 16, 16, 16, 0, 20, 20, 20, 0, 5, 5, 5, 0, 3, 3, 3, 0, 14, 14, 14, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 1, 1, 1, 0, 2, 2, 2, 0, 4, 4, 4, 0, 8, 8, 8, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 20, 20, 20, 0, 10, 10, 10, 0, 20, 20, 20, 0, 18, 18, 18, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 17, 17, 17, 0, 19, 19, 19, 0, 1, 1, 1, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 6, 6, 6, 0, 18, 18, 18, 0, 1, 1, 1, 0, 21, 21, 21, 0, 12, 12, 12, 0, 1, 1, 1, 0, 13, 13, 13, 0, 10, 10, 10, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 15, 15, 15, 0, 3, 3, 3, 0, 9, 9, 9, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 16, 16, 16, 0, 17, 17, 17, 0, 21, 21, 21, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 7, 7, 7, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 18, 18, 18, 0, 10, 10, 10, 0, 10, 10, 10, 0, 15, 15, 15, 0, 7, 7, 7, 0, 21, 21, 21, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 20, 20, 20, 0, 1, 1, 1, 0, 3, 3, 3, 0, 20, 20, 20, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 12, 12, 12, 0, 16, 16, 16, 0, 7, 7, 7, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 19, 19, 19, 0, 20, 20, 20, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 18, 18, 18, 0, 12, 12, 12, 0, 6, 6, 6, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 8, 8, 8, 0, 2, 2, 2, 0, 17, 17, 17, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 9, 9, 9, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 4, 4, 4, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 2, 2, 2, 0, 4, 4, 4, 0, 8, 8, 8, 0, 3, 3, 3, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 9, 9, 9, 0, 13, 13, 13, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 14, 14, 14, 0, 20, 20, 20, 0, 19, 19, 19, 0, 15, 15, 15, 0, 11, 11, 11, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 18, 18, 18, 0, 21, 21, 21, 0, 14, 14, 14, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 3, 3, 3, 0, 21, 21, 21, 0, 13, 13, 13, 0, 19, 19, 19, 0, 21, 21, 21, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 18, 18, 18, 0, 16, 16, 16, 0, 4, 4, 4, 0, 8, 8, 8, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 2, 2, 2, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 11, 11, 11, 0, 8, 8, 8, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 2, 2, 2, 0, 14, 14, 14, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 19, 19, 19, 0, 16, 16, 16, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 18, 18, 18, 0, 21, 21, 21, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 8, 8, 8, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 2, 2, 2, 0, 20, 20, 20, 0, 8, 8, 8, 0, 16, 16, 16, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 8, 8, 8, 0, 16, 16, 16, 0, 1, 1, 1, 0, 20, 20, 20, 0, 18, 18, 18, 0, 20, 20, 20, 0, 21, 21, 21, 0, 3, 3, 3, 0, 6, 6, 6, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 16, 16, 16, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 19, 19, 19, 0, 15, 15, 15, 0, 0, 0, 0, 0, 8, 8, 8, 0, 20, 20, 20, 0, 17, 17, 17, 0, 17, 17, 17, 0, 2, 2, 2, 0, 0, 0, 0, 0, 8, 8, 8, 0, 17, 17, 17, 0, 16, 16, 16, 0, 3, 3, 3, 0, 18, 18, 18, 0, 17, 17, 17, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 19, 19, 19, 0, 11, 11, 11, 0, 6, 6, 6, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 16, 16, 16, 0, 13, 13, 13, 0, 1, 1, 1, 0, 17, 17, 17, 0, 5, 5, 5, 0, 1, 1, 1, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 20, 20, 20, 0, 20, 20, 20, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 13, 13, 13, 0, 17, 17, 17, 0, 8, 8, 8, 0, 2, 2, 2, 0, 19, 19, 19, 0, 7, 7, 7, 0, 14, 14, 14, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 10, 10, 10, 0, 10, 10, 10, 0, 0, 0, 0, 0, 2, 2, 2, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 8, 8, 8, 0, 14, 14, 14, 0, 5, 5, 5, 0, 2, 2, 2, 0, 3, 3, 3, 0, 4, 4, 4, 0, 21, 21, 21, 0, 20, 20, 20, 0, 18, 18, 18, 0, 2, 2, 2, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 14, 14, 14, 0, 21, 21, 21, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 2, 2, 2, 0, 19, 19, 19, 0, 5, 5, 5, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 11, 11, 11, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 17, 17, 17, 0, 21, 21, 21, 0, 8, 8, 8, 0, 16, 16, 16, 0, 16, 16, 16, 0, 19, 19, 19, 0, 6, 6, 6, 0, 17, 17, 17, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 10, 10, 10, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 1, 1, 1, 0, 21, 21, 21, 0, 21, 21, 21, 0, 2, 2, 2, 0, 5, 5, 5, 0, 6, 6, 6, 0, 2, 2, 2, 0, 19, 19, 19, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 7, 7, 7, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 19, 19, 19, 0, 16, 16, 16, 0, 16, 16, 16, 0, 11, 11, 11, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 16, 16, 16, 0, 13, 13, 13, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 2, 2, 2, 0, 7, 7, 7, 0, 20, 20, 20, 0, 12, 12, 12, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 6, 6, 6, 0, 20, 20, 20, 0, 17, 17, 17, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 13, 13, 13, 0, 21, 21, 21, 0, 19, 19, 19, 0, 19, 19, 19, 0, 21, 21, 21, 0, 2, 2, 2, 0, 4, 4, 4, 0, 13, 13, 13, 0, 17, 17, 17, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 16, 16, 16, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 21, 21, 21, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 1, 1, 1, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 16, 16, 16, 0, 10, 10, 10, 0, 6, 6, 6, 0, 13, 13, 13, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 3, 3, 3, 0, 21, 21, 21, 0, 1, 1, 1, 0, 5, 5, 5, 0, 21, 21, 21, 0, 2, 2, 2, 0, 4, 4, 4, 0, 14, 14, 14, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 11, 11, 11, 0, 18, 18, 18, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 0, 0, 0, 0, 9, 9, 9, 0, 17, 17, 17, 0, 0, 0, 0, 0, 13, 13, 13, 0, 7, 7, 7, 0, 9, 9, 9, 0, 14, 14, 14, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 16, 16, 16, 0, 1, 1, 1, 0, 20, 20, 20, 0, 17, 17, 17, 0, 18, 18, 18, 0, 1, 1, 1, 0, 11, 11, 11, 0, 11, 11, 11, 0, 20, 20, 20, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 10, 10, 10, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 19, 19, 19, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 3, 3, 3, 0, 1, 1, 1, 0, 1, 1, 1, 0, 21, 21, 21, 0, 6, 6, 6, 0, 14, 14, 14, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 20, 20, 20, 0, 11, 11, 11, 0, 5, 5, 5, 0, 19, 19, 19, 0, 19, 19, 19, 0, 21, 21, 21, 0, 19, 19, 19, 0, 21, 21, 21, 0, 9, 9, 9, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 0, 4, 4, 4, 0, 12, 12, 12, 0, 1, 1, 1, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 12, 12, 12, 0, 6, 6, 6, 0, 0, 0, 0, 0, 3, 3, 3, 0, 14, 14, 14, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 2, 2, 2, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 4, 4, 4, 0, 17, 17, 17, 0, 17, 17, 17, 0, 16, 16, 16, 0, 1, 1, 1, 0, 4, 4, 4, 0, 21, 21, 21, 0, 18, 18, 18, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 13, 13, 13, 0, 17, 17, 17, 0, 2, 2, 2, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 4, 4, 4, 0, 2, 2, 2, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 19, 19, 19, 0, 1, 1, 1, 0, 5, 5, 5, 0, 12, 12, 12, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 10, 10, 10, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 21, 21, 21, 0, 5, 5, 5, 0, 1, 1, 1, 0, 3, 3, 3, 0, 12, 12, 12, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 2, 2, 2, 0, 5, 5, 5, 0, 0, 0, 0, 0, 11, 11, 11, 0, 20, 20, 20, 0, 1, 1, 1, 0, 5, 5, 5, 0, 4, 4, 4, 0, 17, 17, 17, 0, 11, 11, 11, 0, 19, 19, 19, 0, 19, 19, 19, 0, 3, 3, 3, 0, 8, 8, 8, 0, 19, 19, 19, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 13, 13, 13, 0, 3, 3, 3, 0, 1, 1, 1, 0, 15, 15, 15, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 19, 19, 19, 0, 21, 21, 21, 0, 4, 4, 4, 0, 10, 10, 10, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 11, 11, 11, 0, 1, 1, 1, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 14, 14, 14, 0, 3, 3, 3, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 20, 20, 20, 0, 11, 11, 11, 0, 14, 14, 14, 0, 6, 6, 6, 0, 1, 1, 1, 0, 1, 1, 1, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 2, 2, 2, 0, 13, 13, 13, 0, 7, 7, 7, 0, 11, 11, 11, 0, 1, 1, 1, 0, 19, 19, 19, 0, 19, 19, 19, 0, 21, 21, 21, 0, 21, 21, 21, 0, 6, 6, 6, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 21, 21, 21, 0, 17, 17, 17, 0, 21, 21, 21, 0, 11, 11, 11, 0, 2, 2, 2, 0, 19, 19, 19, 0, 18, 18, 18, 0, 18, 18, 18, 0, 20, 20, 20, 0, 21, 21, 21, 0, 1, 1, 1, 0, 6, 6, 6, 0, 11, 11, 11, 0, 19, 19, 19, 0, 21, 21, 21, 0, 10, 10, 10, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 14, 14, 14, 0, 19, 19, 19, 0, 8, 8, 8, 0, 20, 20, 20, 0, 17, 17, 17, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 19, 19, 19, 0, 1, 1, 1, 0, 0, 0, 0, 0, 9, 9, 9, 0, 2, 2, 2, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 3, 3, 3, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 19, 19, 19, 0, 5, 5, 5, 0, 13, 13, 13, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 10, 10, 10, 0, 12, 12, 12, 0, 6, 6, 6, 0, 13, 13, 13, 0, 12, 12, 12, 0, 7, 7, 7, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 21, 21, 21, 0, 19, 19, 19, 0, 18, 18, 18, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 20, 20, 20, 0, 2, 2, 2, 0, 6, 6, 6, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 21, 21, 21, 0, 6, 6, 6, 0, 19, 19, 19, 0, 18, 18, 18, 0, 6, 6, 6, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 2, 2, 2, 0, 9, 9, 9, 0, 3, 3, 3, 0, 2, 2, 2, 0, 12, 12, 12, 0, 19, 19, 19, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 7, 7, 7, 0, 13, 13, 13, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 9, 9, 9, 0, 1, 1, 1, 0, 10, 10, 10, 0, 9, 9, 9, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 20, 20, 20, 0, 6, 6, 6, 0, 4, 4, 4, 0, 1, 1, 1, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 21, 21, 21, 0, 7, 7, 7, 0, 19, 19, 19, 0, 7, 7, 7, 0, 20, 20, 20, 0, 19, 19, 19, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 13, 13, 13, 0, 12, 12, 12, 0, 4, 4, 4, 0, 19, 19, 19, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 9, 9, 9, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 18, 18, 18, 0, 9, 9, 9, 0, 6, 6, 6, 0, 19, 19, 19, 0, 19, 19, 19, 0, 12, 12, 12, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 16, 16, 16, 0, 2, 2, 2, 0, 15, 15, 15, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 19, 19, 19, 0, 2, 2, 2, 0, 21, 21, 21, 0, 17, 17, 17, 0, 1, 1, 1, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 7, 7, 7, 0, 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 20, 20, 20, 0, 13, 13, 13, 0, 16, 16, 16, 0, 8, 8, 8, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 17, 17, 17, 0, 20, 20, 20, 0, 1, 1, 1, 0, 7, 7, 7, 0, 6, 6, 6, 0, 14, 14, 14, 0, 8, 8, 8, 0, 16, 16, 16, 0, 11, 11, 11, 0, 20, 20, 20, 0, 7, 7, 7, 0, 15, 15, 15, 0, 9, 9, 9, 0, 19, 19, 19, 0, 21, 21, 21, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 5, 5, 5, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 19, 19, 19, 0, 3, 3, 3, 0, 21, 21, 21, 0, 2, 2, 2, 0, 6, 6, 6, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 7, 7, 7, 0, 8, 8, 8, 0, 21, 21, 21, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 21, 21, 21, 0, 3, 3, 3, 0, 6, 6, 6, 0, 18, 18, 18, 0, 16, 16, 16, 0, 8, 8, 8, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 14, 14, 14, 0, 21, 21, 21, 0, 15, 15, 15, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 1, 1, 1, 0, 4, 4, 4, 0, 20, 20, 20, 0, 19, 19, 19, 0, 20, 20, 20, 0, 5, 5, 5, 0, 5, 5, 5, 0, 8, 8, 8, 0, 2, 2, 2, 0, 8, 8, 8, 0, 2, 2, 2, 0, 6, 6, 6, 0, 19, 19, 19, 0, 17, 17, 17, 0, 17, 17, 17, 0, 21, 21, 21, 0, 10, 10, 10, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 20, 20, 20, 0, 19, 19, 19, 0, 17, 17, 17, 0, 20, 20, 20, 0, 21, 21, 21, 0, 2, 2, 2, 0, 14, 14, 14, 0, 5, 5, 5, 0, 11, 11, 11, 0, 1, 1, 1, 0, 0, 0, 0, 0, 3, 3, 3, 0, 1, 1, 1, 0, 5, 5, 5, 0, 16, 16, 16, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 20, 20, 20, 0, 15, 15, 15, 0, 2, 2, 2, 0, 10, 10, 10, 0, 20, 20, 20, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 16, 16, 16, 0, 14, 14, 14, 0, 2, 2, 2, 0, 11, 11, 11, 0, 15, 15, 15, 0, 15, 15, 15, 0, 14, 14, 14, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 9, 9, 9, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 16, 16, 16, 0, 18, 18, 18, 0, 6, 6, 6, 0, 1, 1, 1, 0, 1, 1, 1, 0, 12, 12, 12, 0, 8, 8, 8, 0, 8, 8, 8, 0, 18, 18, 18, 0, 2, 2, 2, 0, 20, 20, 20, 0, 20, 20, 20, 0, 18, 18, 18, 0, 15, 15, 15, 0, 17, 17, 17, 0, 20, 20, 20, 0, 19, 19, 19, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 21, 21, 21, 0, 2, 2, 2, 0, 6, 6, 6, 0, 14, 14, 14, 0, 18, 18, 18, 0, 8, 8, 8, 0, 2, 2, 2, 0, 19, 19, 19, 0, 16, 16, 16, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 8, 8, 8, 0, 1, 1, 1, 0, 10, 10, 10, 0, 18, 18, 18, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 20, 20, 20, 0, 15, 15, 15, 0, 5, 5, 5, 0, 12, 12, 12, 0, 9, 9, 9, 0, 9, 9, 9, 0, 0, 0, 0, 0, 1, 1, 1, 0, 13, 13, 13, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 1, 1, 1, 0, 20, 20, 20, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 6, 6, 6, 0, 2, 2, 2, 0, 14, 14, 14, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 8, 8, 8, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 2, 2, 2, 0, 18, 18, 18, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 18, 18, 18, 0, 1, 1, 1, 0, 2, 2, 2, 0, 10, 10, 10, 0, 20, 20, 20, 0, 1, 1, 1, 0, 15, 15, 15, 0, 3, 3, 3, 0, 10, 10, 10, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 7, 7, 7, 0, 20, 20, 20, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 16, 16, 16, 0, 21, 21, 21, 0, 20, 20, 20, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 4, 4, 4, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 8, 8, 8, 0, 20, 20, 20, 0, 0, 0, 0, 0, 2, 2, 2, 0, 1, 1, 1, 0, 17, 17, 17, 0, 19, 19, 19, 0, 9, 9, 9, 0, 13, 13, 13, 0, 5, 5, 5, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 10, 10, 10, 0, 9, 9, 9, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 11, 11, 11, 0, 14, 14, 14, 0, 8, 8, 8, 0, 4, 4, 4, 0, 19, 19, 19, 0, 6, 6, 6, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 1, 1, 1, 0, 7, 7, 7, 0, 5, 5, 5, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 2, 2, 2, 0, 13, 13, 13, 0, 2, 2, 2, 0, 21, 21, 21, 0, 21, 21, 21, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 2, 2, 2, 0, 21, 21, 21, 0, 4, 4, 4, 0, 10, 10, 10, 0, 19, 19, 19, 0, 2, 2, 2, 0, 19, 19, 19, 0, 1, 1, 1, 0, 13, 13, 13, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 15, 15, 15, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 16, 16, 16, 0, 18, 18, 18, 0, 17, 17, 17, 0, 7, 7, 7, 0, 1, 1, 1, 0, 5, 5, 5, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 20, 20, 20, 0, 19, 19, 19, 0, 5, 5, 5, 0, 6, 6, 6, 0, 20, 20, 20, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 19, 19, 19, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 21, 21, 21, 0, 7, 7, 7, 0, 14, 14, 14, 0, 21, 21, 21, 0, 4, 4, 4, 0, 12, 12, 12, 0, 17, 17, 17, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 21, 21, 21, 0, 1, 1, 1, 0, 4, 4, 4, 0, 17, 17, 17, 0, 15, 15, 15, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 4, 4, 4, 0, 0, 0, 0, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 0, 0, 0, 0, 5, 5, 5, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 3, 3, 3, 0, 8, 8, 8, 0, 0, 0, 0, 0, 12, 12, 12, 0, 15, 15, 15, 0, 5, 5, 5, 0, 2, 2, 2, 0, 4, 4, 4, 0, 15, 15, 15, 0, 21, 21, 21, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 19, 19, 19, 0, 20, 20, 20, 0, 5, 5, 5, 0, 16, 16, 16, 0, 15, 15, 15, 0, 17, 17, 17, 0, 6, 6, 6, 0, 14, 14, 14, 0, 2, 2, 2, 0, 17, 17, 17, 0, 20, 20, 20, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 18, 18, 18, 0, 13, 13, 13, 0, 5, 5, 5, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 18, 18, 18, 0, 1, 1, 1, 0, 12, 12, 12, 0, 2, 2, 2, 0, 18, 18, 18, 0, 17, 17, 17, 0, 3, 3, 3, 0, 1, 1, 1, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 20, 20, 20, 0, 19, 19, 19, 0, 5, 5, 5, 0, 16, 16, 16, 0, 19, 19, 19, 0, 4, 4, 4, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 7, 7, 7, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 7, 7, 7, 0, 4, 4, 4, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 13, 13, 13, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 17, 17, 17, 0, 17, 17, 17, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 4, 4, 4, 0, 17, 17, 17, 0, 15, 15, 15, 0, 18, 18, 18, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 17, 17, 17, 0, 18, 18, 18, 0, 15, 15, 15, 0, 14, 14, 14, 0, 21, 21, 21, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 7, 7, 7, 0, 15, 15, 15, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 17, 17, 17, 0, 4, 4, 4, 0, 10, 10, 10, 0, 19, 19, 19, 0, 15, 15, 15, 0, 16, 16, 16, 0, 21, 21, 21, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 19, 19, 19, 0, 3, 3, 3, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 3, 3, 3, 0, 5, 5, 5, 0, 11, 11, 11, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 4, 4, 4, 0, 19, 19, 19, 0, 16, 16, 16, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 5, 5, 5, 0, 16, 16, 16, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 14, 14, 14, 0, 2, 2, 2, 0, 4, 4, 4, 0, 10, 10, 10, 0, 17, 17, 17, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 13, 13, 13, 0, 14, 14, 14, 0, 19, 19, 19, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 3, 3, 3, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 15, 15, 15, 0, 16, 16, 16, 0, 18, 18, 18, 0, 10, 10, 10, 0, 19, 19, 19, 0, 7, 7, 7, 0, 2, 2, 2, 0, 13, 13, 13, 0, 16, 16, 16, 0, 13, 13, 13, 0, 14, 14, 14, 0, 10, 10, 10, 0, 17, 17, 17, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 15, 15, 15, 0, 21, 21, 21, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 10, 10, 10, 0, 10, 10, 10, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 1, 1, 1, 0, 19, 19, 19, 0, 15, 15, 15, 0, 14, 14, 14, 0, 16, 16, 16, 0, 0, 0, 0, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 17, 17, 17, 0, 8, 8, 8, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 20, 20, 20, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 20, 20, 20, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 16, 16, 16, 0, 11, 11, 11, 0, 20, 20, 20, 0, 19, 19, 19, 0, 7, 7, 7, 0, 3, 3, 3, 0, 15, 15, 15, 0, 4, 4, 4, 0, 13, 13, 13, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 6, 6, 6, 0, 19, 19, 19, 0, 21, 21, 21, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 1, 1, 1, 0, 21, 21, 21, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 21, 21, 21, 0, 18, 18, 18, 0, 14, 14, 14, 0, 5, 5, 5, 0, 18, 18, 18, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 20, 20, 20, 0, 18, 18, 18, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 16, 16, 16, 0, 21, 21, 21, 0, 16, 16, 16, 0, 16, 16, 16, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 18, 18, 18, 0, 10, 10, 10, 0, 1, 1, 1, 0, 3, 3, 3, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 3, 3, 3, 0, 21, 21, 21, 0, 21, 21, 21, 0, 10, 10, 10, 0, 19, 19, 19, 0, 5, 5, 5, 0, 15, 15, 15, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 14, 14, 14, 0, 19, 19, 19, 0, 1, 1, 1, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 18, 18, 18, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 15, 15, 15, 0, 2, 2, 2, 0, 1, 1, 1, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 17, 17, 17, 0, 6, 6, 6, 0, 5, 5, 5, 0, 1, 1, 1, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 12, 12, 12, 0, 15, 15, 15, 0, 11, 11, 11, 0, 13, 13, 13, 0, 17, 17, 17, 0, 14, 14, 14, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 17, 17, 17, 0, 9, 9, 9, 0, 21, 21, 21, 0, 15, 15, 15, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 19, 19, 19, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 10, 10, 10, 0, 5, 5, 5, 0, 1, 1, 1, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 5, 5, 5, 0, 4, 4, 4, 0, 12, 12, 12, 0, 15, 15, 15, 0, 10, 10, 10, 0, 4, 4, 4, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 6, 6, 6, 0, 2, 2, 2, 0, 2, 2, 2, 0, 4, 4, 4, 0, 17, 17, 17, 0, 15, 15, 15, 0, 4, 4, 4, 0, 19, 19, 19, 0, 14, 14, 14, 0, 14, 14, 14, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 11, 11, 11, 0, 21, 21, 21, 0, 15, 15, 15, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 20, 20, 20, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 6, 6, 6, 0, 18, 18, 18, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 18, 18, 18, 0, 20, 20, 20, 0, 11, 11, 11, 0, 7, 7, 7, 0, 11, 11, 11, 0, 0, 0, 0, 0, 11, 11, 11, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 1, 1, 1, 0, 18, 18, 18, 0, 20, 20, 20, 0, 0, 0, 0, 0, 19, 19, 19, 0, 16, 16, 16, 0, 15, 15, 15, 0, 12, 12, 12, 0, 14, 14, 14, 0, 12, 12, 12, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 10, 10, 10, 0, 13, 13, 13, 0, 11, 11, 11, 0, 13, 13, 13, 0, 19, 19, 19, 0, 7, 7, 7, 0, 18, 18, 18, 0, 18, 18, 18, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 13, 13, 13, 0, 16, 16, 16, 0, 20, 20, 20, 0, 1, 1, 1, 0, 16, 16, 16, 0, 15, 15, 15, 0, 12, 12, 12, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 16, 16, 16, 0, 12, 12, 12, 0, 9, 9, 9, 0, 14, 14, 14, 0, 18, 18, 18, 0, 10, 10, 10, 0, 21, 21, 21, 0, 12, 12, 12, 0, 2, 2, 2, 0, 20, 20, 20, 0, 6, 6, 6, 0, 20, 20, 20, 0, 4, 4, 4, 0, 9, 9, 9, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 6, 6, 6, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 1, 1, 1, 0, 2, 2, 2, 0, 7, 7, 7, 0, 3, 3, 3, 0, 17, 17, 17, 0, 17, 17, 17, 0, 20, 20, 20, 0, 4, 4, 4, 0, 20, 20, 20, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 15, 15, 15, 0, 12, 12, 12, 0, 14, 14, 14, 0, 2, 2, 2, 0, 15, 15, 15, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 18, 18, 18, 0, 18, 18, 18, 0, 17, 17, 17, 0, 18, 18, 18, 0, 1, 1, 1, 0, 19, 19, 19, 0, 14, 14, 14, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 19, 19, 19, 0, 8, 8, 8, 0, 18, 18, 18, 0, 9, 9, 9, 0, 9, 9, 9, 0, 2, 2, 2, 0, 16, 16, 16, 0, 10, 10, 10, 0, 5, 5, 5, 0, 8, 8, 8, 0, 9, 9, 9, 0, 0, 0, 0, 0, 1, 1, 1, 0, 5, 5, 5, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 2, 2, 2, 0, 3, 3, 3, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 5, 5, 5, 0, 19, 19, 19, 0, 1, 1, 1, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 7, 7, 7, 0, 20, 20, 20, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 20, 20, 20, 0, 13, 13, 13, 0, 8, 8, 8, 0, 18, 18, 18, 0, 19, 19, 19, 0, 20, 20, 20, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 14, 14, 14, 0, 13, 13, 13, 0, 14, 14, 14, 0, 19, 19, 19, 0, 6, 6, 6, 0, 3, 3, 3, 0, 13, 13, 13, 0, 11, 11, 11, 0, 1, 1, 1, 0, 17, 17, 17, 0, 19, 19, 19, 0, 17, 17, 17, 0, 21, 21, 21, 0, 2, 2, 2, 0, 7, 7, 7, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 20, 20, 20, 0, 2, 2, 2, 0, 20, 20, 20, 0, 21, 21, 21, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 1, 1, 1, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 2, 2, 2, 0, 17, 17, 17, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 18, 18, 18, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 15, 15, 15, 0, 2, 2, 2, 0, 10, 10, 10, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 17, 17, 17, 0, 21, 21, 21, 0, 20, 20, 20, 0, 11, 11, 11, 0, 2, 2, 2, 0, 19, 19, 19, 0, 18, 18, 18, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 12, 12, 12, 0, 5, 5, 5, 0, 9, 9, 9, 0, 12, 12, 12, 0, 8, 8, 8, 0, 12, 12, 12, 0, 17, 17, 17, 0, 16, 16, 16, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 1, 1, 1, 0, 15, 15, 15, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 14, 14, 14, 0, 4, 4, 4, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 19, 19, 19, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 7, 7, 7, 0, 0, 0, 0, 0, 13, 13, 13, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 1, 1, 1, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 2, 2, 2, 0, 14, 14, 14, 0, 5, 5, 5, 0, 16, 16, 16, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 17, 17, 17, 0, 16, 16, 16, 0, 3, 3, 3, 0, 3, 3, 3, 0, 13, 13, 13, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 12, 12, 12, 0, 13, 13, 13, 0, 0, 0, 0, 0, 2, 2, 2, 0, 1, 1, 1, 0, 12, 12, 12, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 3, 3, 3, 0, 18, 18, 18, 0, 2, 2, 2, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 11, 11, 11, 0, 17, 17, 17, 0, 20, 20, 20, 0, 8, 8, 8, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 20, 20, 20, 0, 17, 17, 17, 0, 5, 5, 5, 0, 15, 15, 15, 0, 16, 16, 16, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 20, 20, 20, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 4, 4, 4, 0, 4, 4, 4, 0, 18, 18, 18, 0, 19, 19, 19, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 16, 16, 16, 0, 9, 9, 9, 0, 19, 19, 19, 0, 14, 14, 14, 0, 19, 19, 19, 0, 10, 10, 10, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 20, 20, 20, 0, 19, 19, 19, 0, 2, 2, 2, 0, 13, 13, 13, 0, 12, 12, 12, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 2, 2, 2, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 14, 14, 14, 0, 7, 7, 7, 0, 18, 18, 18, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 4, 4, 4, 0, 9, 9, 9, 0, 5, 5, 5, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 19, 19, 19, 0, 8, 8, 8, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 16, 16, 16, 0, 18, 18, 18, 0, 9, 9, 9, 0, 1, 1, 1, 0, 13, 13, 13, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 3, 3, 3, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 14, 14, 14, 0, 14, 14, 14, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 21, 21, 21, 0, 1, 1, 1, 0, 10, 10, 10, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 3, 3, 3, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 15, 15, 15, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 14, 14, 14, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 21, 21, 21, 0, 3, 3, 3, 0, 7, 7, 7, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 1, 1, 1, 0, 20, 20, 20, 0, 17, 17, 17, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 19, 19, 19, 0, 11, 11, 11, 0, 11, 11, 11, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 18, 18, 18, 0, 20, 20, 20, 0, 21, 21, 21, 0, 0, 0, 0, 0, 20, 20, 20, 0, 15, 15, 15, 0, 21, 21, 21, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 18, 18, 18, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 1, 1, 1, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 16, 16, 16, 0, 1, 1, 1, 0, 3, 3, 3, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 3, 3, 3, 0, 19, 19, 19, 0, 19, 19, 19, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 16, 16, 16, 0, 12, 12, 12, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 17, 17, 17, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 9, 9, 9, 0, 18, 18, 18, 0, 16, 16, 16, 0, 1, 1, 1, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 4, 4, 4, 0, 1, 1, 1, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 17, 17, 17, 0, 10, 10, 10, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 11, 11, 11, 0, 2, 2, 2, 0, 14, 14, 14, 0, 15, 15, 15, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 6, 6, 6, 0, 18, 18, 18, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 12, 12, 12, 0, 4, 4, 4, 0, 17, 17, 17, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 12, 12, 12, 0, 4, 4, 4, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 5, 5, 5, 0, 19, 19, 19, 0, 12, 12, 12, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 17, 17, 17, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 19, 19, 19, 0, 16, 16, 16, 0, 17, 17, 17, 0, 21, 21, 21, 0, 3, 3, 3, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 21, 21, 21, 0, 5, 5, 5, 0, 11, 11, 11, 0, 3, 3, 3, 0, 13, 13, 13, 0, 20, 20, 20, 0, 12, 12, 12, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 14, 14, 14, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 1, 1, 1, 0, 20, 20, 20, 0, 18, 18, 18, 0, 20, 20, 20, 0, 5, 5, 5, 0, 11, 11, 11, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 14, 14, 14, 0, 20, 20, 20, 0, 3, 3, 3, 0, 19, 19, 19, 0, 1, 1, 1, 0, 8, 8, 8, 0, 5, 5, 5, 0, 1, 1, 1, 0, 14, 14, 14, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 10, 10, 10, 0, 13, 13, 13, 0, 12, 12, 12, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 1, 1, 1, 0, 2, 2, 2, 0, 5, 5, 5, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 18, 18, 18, 0, 16, 16, 16, 0, 17, 17, 17, 0, 8, 8, 8, 0, 13, 13, 13, 0, 19, 19, 19, 0, 1, 1, 1, 0, 12, 12, 12, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 14, 14, 14, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 15, 15, 15, 0, 1, 1, 1, 0, 16, 16, 16, 0, 17, 17, 17, 0, 0, 0, 0, 0, 11, 11, 11, 0, 4, 4, 4, 0, 7, 7, 7, 0, 15, 15, 15, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 17, 17, 17, 0, 8, 8, 8, 0, 13, 13, 13, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 15, 15, 15, 0, 8, 8, 8, 0, 10, 10, 10, 0, 20, 20, 20, 0, 9, 9, 9, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 15, 15, 15, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 4, 4, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 16, 16, 16, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 1, 1, 1, 0, 18, 18, 18, 0, 3, 3, 3, 0, 9, 9, 9, 0, 5, 5, 5, 0, 13, 13, 13, 0, 14, 14, 14, 0, 19, 19, 19, 0, 0, 0, 0, 0, 20, 20, 20, 0, 9, 9, 9, 0, 15, 15, 15, 0, 16, 16, 16, 0, 12, 12, 12, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 16, 16, 16, 0, 6, 6, 6, 0, 1, 1, 1, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 5, 5, 5, 0, 10, 10, 10, 0, 12, 12, 12, 0, 3, 3, 3, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 2, 2, 2, 0, 12, 12, 12, 0, 1, 1, 1, 0, 3, 3, 3, 0, 0, 0, 0, 0, 20, 20, 20, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 6, 6, 6, 0, 12, 12, 12, 0, 1, 1, 1, 0, 18, 18, 18, 0, 6, 6, 6, 0, 2, 2, 2, 0, 20, 20, 20, 0, 20, 20, 20, 0, 13, 13, 13, 0, 0, 0, 0, 0, 15, 15, 15, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 19, 19, 19, 0, 0, 0, 0, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 18, 18, 18, 0, 21, 21, 21, 0, 16, 16, 16, 0, 20, 20, 20, 0, 7, 7, 7, 0, 1, 1, 1, 0, 8, 8, 8, 0, 5, 5, 5, 0, 3, 3, 3, 0, 6, 6, 6, 0, 1, 1, 1, 0, 4, 4, 4, 0, 0, 0, 0, 0, 4, 4, 4, 0, 21, 21, 21, 0, 10, 10, 10, 0, 1, 1, 1, 0, 19, 19, 19, 0, 18, 18, 18, 0, 21, 21, 21, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 13, 13, 13, 0, 8, 8, 8, 0, 0, 0, 0, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 15, 15, 15, 0, 19, 19, 19, 0, 20, 20, 20, 0, 15, 15, 15, 0, 5, 5, 5, 0, 2, 2, 2, 0, 13, 13, 13, 0, 17, 17, 17, 0, 8, 8, 8, 0, 15, 15, 15, 0, 5, 5, 5, 0, 1, 1, 1, 0, 20, 20, 20, 0, 19, 19, 19, 0, 4, 4, 4, 0, 0, 0, 0, 0, 14, 14, 14, 0, 8, 8, 8, 0, 6, 6, 6, 0, 20, 20, 20, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 20, 20, 20, 0, 2, 2, 2, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 3, 3, 3, 0, 20, 20, 20, 0, 15, 15, 15, 0, 15, 15, 15, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 12, 12, 12, 0, 19, 19, 19, 0, 15, 15, 15, 0, 19, 19, 19, 0, 14, 14, 14, 0, 15, 15, 15, 0, 6, 6, 6, 0, 21, 21, 21, 0, 4, 4, 4, 0, 2, 2, 2, 0, 14, 14, 14, 0, 19, 19, 19, 0, 1, 1, 1, 0, 19, 19, 19, 0, 17, 17, 17, 0, 17, 17, 17, 0, 1, 1, 1, 0, 6, 6, 6, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 18, 18, 18, 0, 21, 21, 21, 0, 4, 4, 4, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 21, 21, 21, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 15, 15, 15, 0, 13, 13, 13, 0, 18, 18, 18, 0, 16, 16, 16, 0, 13, 13, 13, 0, 12, 12, 12, 0, 14, 14, 14, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 5, 5, 5, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 19, 19, 19, 0, 21, 21, 21, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 2, 2, 2, 0, 21, 21, 21, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 10, 10, 10, 0, 11, 11, 11, 0, 15, 15, 15, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 3, 3, 3, 0, 3, 3, 3, 0, 15, 15, 15, 0, 15, 15, 15, 0, 8, 8, 8, 0, 15, 15, 15, 0, 2, 2, 2, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 4, 4, 4, 0, 4, 4, 4, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 6, 6, 6, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 20, 20, 20, 0, 4, 4, 4, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 20, 20, 20, 0, 5, 5, 5, 0, 14, 14, 14, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 13, 13, 13, 0, 3, 3, 3, 0, 19, 19, 19, 0, 11, 11, 11, 0, 1, 1, 1, 0, 17, 17, 17, 0, 0, 0, 0, 0, 8, 8, 8, 0, 14, 14, 14, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 8, 8, 8, 0, 20, 20, 20, 0, 14, 14, 14, 0, 0, 0, 0, 0, 19, 19, 19, 0, 13, 13, 13, 0, 15, 15, 15, 0, 2, 2, 2, 0, 18, 18, 18, 0, 4, 4, 4, 0, 16, 16, 16, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 15, 15, 15, 0, 8, 8, 8, 0, 8, 8, 8, 0, 19, 19, 19, 0, 17, 17, 17, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 11, 11, 11, 0, 14, 14, 14, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 5, 5, 5, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 3, 3, 3, 0, 6, 6, 6, 0, 3, 3, 3, 0, 19, 19, 19, 0, 5, 5, 5, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 20, 20, 20, 0, 6, 6, 6, 0, 11, 11, 11, 0, 7, 7, 7, 0, 20, 20, 20, 0, 20, 20, 20, 0, 21, 21, 21, 0, 2, 2, 2, 0, 0, 0, 0, 0, 9, 9, 9, 0, 3, 3, 3, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 12, 12, 12, 0, 21, 21, 21, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 16, 16, 16, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 4, 4, 4, 0, 16, 16, 16, 0, 12, 12, 12, 0, 13, 13, 13, 0, 6, 6, 6, 0, 11, 11, 11, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 15, 15, 15, 0, 2, 2, 2, 0, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 19, 19, 19, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 4, 4, 4, 0, 21, 21, 21, 0, 18, 18, 18, 0, 15, 15, 15, 0, 16, 16, 16, 0, 1, 1, 1, 0, 13, 13, 13, 0, 11, 11, 11, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 16, 16, 16, 0, 16, 16, 16, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 19, 19, 19, 0, 20, 20, 20, 0, 3, 3, 3, 0, 6, 6, 6, 0, 0, 0, 0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 2, 2, 2, 0, 6, 6, 6, 0, 10, 10, 10, 0, 19, 19, 19, 0, 9, 9, 9, 0, 17, 17, 17, 0, 3, 3, 3, 0, 5, 5, 5, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 18, 18, 18, 0, 20, 20, 20, 0, 21, 21, 21, 0, 19, 19, 19, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 15, 15, 15, 0, 2, 2, 2, 0, 16, 16, 16, 0, 12, 12, 12, 0, 10, 10, 10, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 2, 2, 2, 0, 5, 5, 5, 0, 8, 8, 8, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 5, 5, 5, 0, 4, 4, 4, 0, 10, 10, 10, 0, 3, 3, 3, 0, 16, 16, 16, 0, 12, 12, 12, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 1, 1, 1, 0, 3, 3, 3, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 18, 18, 18, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 1, 1, 1, 0, 4, 4, 4, 0, 21, 21, 21, 0, 6, 6, 6, 0, 18, 18, 18, 0, 21, 21, 21, 0, 6, 6, 6, 0, 1, 1, 1, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 17, 17, 17, 0, 20, 20, 20, 0, 20, 20, 20, 0, 2, 2, 2, 0, 9, 9, 9, 0, 21, 21, 21, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 6, 6, 6, 0, 19, 19, 19, 0, 18, 18, 18, 0, 7, 7, 7, 0, 19, 19, 19, 0, 18, 18, 18, 0, 14, 14, 14, 0, 15, 15, 15, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 10, 10, 10, 0, 6, 6, 6, 0, 5, 5, 5, 0, 8, 8, 8, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 9, 9, 9, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 16, 16, 16, 0, 2, 2, 2, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 12, 12, 12, 0, 9, 9, 9, 0, 15, 15, 15, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 6, 6, 6, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 3, 3, 3, 0, 17, 17, 17, 0, 16, 16, 16, 0, 18, 18, 18, 0, 8, 8, 8, 0, 12, 12, 12, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 1, 1, 1, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 17, 17, 17, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 4, 4, 4, 0, 9, 9, 9, 0, 19, 19, 19, 0, 19, 19, 19, 0, 2, 2, 2, 0, 7, 7, 7, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 8, 8, 8, 0, 21, 21, 21, 0, 21, 21, 21, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 3, 3, 3, 0, 19, 19, 19, 0, 17, 17, 17, 0, 16, 16, 16, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 20, 20, 20, 0, 13, 13, 13, 0, 1, 1, 1, 0, 21, 21, 21, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 8, 8, 8, 0, 4, 4, 4, 0, 21, 21, 21, 0, 18, 18, 18, 0, 19, 19, 19, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 10, 10, 10, 0, 21, 21, 21, 0, 21, 21, 21, 0, 21, 21, 21, 0, 1, 1, 1, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 8, 8, 8, 0, 16, 16, 16, 0, 1, 1, 1, 0, 9, 9, 9, 0, 18, 18, 18, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 20, 20, 20, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 20, 20, 20, 0, 13, 13, 13, 0, 20, 20, 20, 0, 19, 19, 19, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 15, 15, 15, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 16, 16, 16, 0, 13, 13, 13, 0, 9, 9, 9, 0, 1, 1, 1, 0, 18, 18, 18, 0, 19, 19, 19, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 17, 17, 17, 0, 20, 20, 20, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 10, 10, 10, 0, 15, 15, 15, 0, 21, 21, 21, 0, 0, 0, 0, 0, 2, 2, 2, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 14, 14, 14, 0, 3, 3, 3, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 10, 10, 10, 0, 3, 3, 3, 0, 8, 8, 8, 0, 18, 18, 18, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 10, 10, 10, 0, 10, 10, 10, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 19, 19, 19, 0, 7, 7, 7, 0, 20, 20, 20, 0, 16, 16, 16, 0, 7, 7, 7, 0, 19, 19, 19, 0, 9, 9, 9, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 7, 7, 7, 0, 3, 3, 3, 0, 9, 9, 9, 0, 0, 0, 0, 0, 8, 8, 8, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 20, 20, 20, 0, 8, 8, 8, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 5, 5, 5, 0, 19, 19, 19, 0, 18, 18, 18, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 17, 17, 17, 0, 3, 3, 3, 0, 14, 14, 14, 0, 1, 1, 1, 0, 15, 15, 15, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 15, 15, 15, 0, 20, 20, 20, 0, 13, 13, 13, 0, 10, 10, 10, 0, 3, 3, 3, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 6, 6, 6, 0, 3, 3, 3, 0, 0, 0, 0, 0, 9, 9, 9, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 21, 21, 21, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 12, 12, 12, 0, 7, 7, 7, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 11, 11, 11, 0, 2, 2, 2, 0, 14, 14, 14, 0, 2, 2, 2, 0, 21, 21, 21, 0, 11, 11, 11, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 21, 21, 21, 0, 21, 21, 21, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 9, 9, 9, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 1, 1, 1, 0, 0, 0, 0, 0, 13, 13, 13, 0, 11, 11, 11, 0, 6, 6, 6, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 19, 19, 19, 0, 3, 3, 3, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 12, 12, 12, 0, 13, 13, 13, 0, 3, 3, 3, 0, 5, 5, 5, 0, 18, 18, 18, 0, 15, 15, 15, 0, 15, 15, 15, 0, 21, 21, 21, 0, 21, 21, 21, 0, 5, 5, 5, 0, 6, 6, 6, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 19, 19, 19, 0, 18, 18, 18, 0, 21, 21, 21, 0, 18, 18, 18, 0, 19, 19, 19, 0, 6, 6, 6, 0, 2, 2, 2, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 9, 9, 9, 0, 19, 19, 19, 0, 19, 19, 19, 0, 20, 20, 20, 0, 11, 11, 11, 0, 2, 2, 2, 0, 6, 6, 6, 0, 9, 9, 9, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 1, 1, 1, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 9, 9, 9, 0, 5, 5, 5, 0, 19, 19, 19, 0, 11, 11, 11, 0, 3, 3, 3, 0, 6, 6, 6, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 18, 18, 18, 0, 6, 6, 6, 0, 11, 11, 11, 0, 5, 5, 5, 0, 1, 1, 1, 0, 14, 14, 14, 0, 9, 9, 9, 0, 1, 1, 1, 0, 12, 12, 12, 0, 9, 9, 9, 0, 8, 8, 8, 0, 14, 14, 14, 0, 9, 9, 9, 0, 9, 9, 9, 0, 2, 2, 2, 0, 18, 18, 18, 0, 17, 17, 17, 0, 5, 5, 5, 0, 6, 6, 6, 0, 17, 17, 17, 0, 15, 15, 15, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 21, 21, 21, 0, 2, 2, 2, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 1, 1, 1, 0, 19, 19, 19, 0, 18, 18, 18, 0, 17, 17, 17, 0, 20, 20, 20, 0, 14, 14, 14, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 8, 8, 8, 0, 1, 1, 1, 0, 8, 8, 8, 0, 10, 10, 10, 0, 20, 20, 20, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 19, 19, 19, 0, 2, 2, 2, 0, 10, 10, 10, 0, 4, 4, 4, 0, 21, 21, 21, 0, 14, 14, 14, 0, 7, 7, 7, 0, 0, 0, 0, 0, 15, 15, 15, 0, 11, 11, 11, 0, 20, 20, 20, 0, 2, 2, 2, 0, 10, 10, 10, 0, 5, 5, 5, 0, 18, 18, 18, 0, 19, 19, 19, 0, 1, 1, 1, 0, 9, 9, 9, 0, 15, 15, 15, 0, 3, 3, 3, 0, 19, 19, 19, 0, 2, 2, 2, 0, 19, 19, 19, 0, 11, 11, 11, 0, 8, 8, 8, 0, 21, 21, 21, 0, 9, 9, 9, 0, 21, 21, 21, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 1, 1, 1, 0, 1, 1, 1, 0, 5, 5, 5, 0, 13, 13, 13, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 8, 8, 8, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 3, 3, 3, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 13, 13, 13, 0, 0, 0, 0, 0, 11, 11, 11, 0, 9, 9, 9, 0, 21, 21, 21, 0, 19, 19, 19, 0, 10, 10, 10, 0, 16, 16, 16, 0, 18, 18, 18, 0, 12, 12, 12, 0, 17, 17, 17, 0, 16, 16, 16, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 16, 16, 16, 0, 19, 19, 19, 0, 17, 17, 17, 0, 19, 19, 19, 0, 3, 3, 3, 0, 0, 0, 0, 0, 13, 13, 13, 0, 7, 7, 7, 0, 1, 1, 1, 0, 19, 19, 19, 0, 6, 6, 6, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 16, 16, 16, 0, 20, 20, 20, 0, 3, 3, 3, 0, 18, 18, 18, 0, 17, 17, 17, 0, 13, 13, 13, 0, 21, 21, 21, 0, 20, 20, 20, 0, 4, 4, 4, 0, 2, 2, 2, 0, 8, 8, 8, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 18, 18, 18, 0, 17, 17, 17, 0, 6, 6, 6, 0, 9, 9, 9, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 18, 18, 18, 0, 9, 9, 9, 0, 12, 12, 12, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 18, 18, 18, 0, 4, 4, 4, 0, 4, 4, 4, 0, 14, 14, 14, 0, 6, 6, 6, 0, 12, 12, 12, 0, 18, 18, 18, 0, 1, 1, 1, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 2, 2, 2, 0, 20, 20, 20, 0, 19, 19, 19, 0, 17, 17, 17, 0, 17, 17, 17, 0, 21, 21, 21, 0, 6, 6, 6, 0, 15, 15, 15, 0, 7, 7, 7, 0, 17, 17, 17, 0, 15, 15, 15, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 19, 19, 19, 0, 17, 17, 17, 0, 6, 6, 6, 0, 3, 3, 3, 0, 2, 2, 2, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 18, 18, 18, 0, 12, 12, 12, 0, 20, 20, 20, 0, 17, 17, 17, 0, 20, 20, 20, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 19, 19, 19, 0, 1, 1, 1, 0, 16, 16, 16, 0, 5, 5, 5, 0, 20, 20, 20, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 19, 19, 19, 0, 10, 10, 10, 0, 1, 1, 1, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 8, 8, 8, 0, 0, 0, 0, 0, 18, 18, 18, 0, 18, 18, 18, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 17, 17, 17, 0, 4, 4, 4, 0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 20, 20, 20, 0, 18, 18, 18, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 9, 9, 9, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 18, 18, 18, 0, 7, 7, 7, 0, 4, 4, 4, 0, 4, 4, 4, 0, 17, 17, 17, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 4, 4, 4, 0, 2, 2, 2, 0, 17, 17, 17, 0, 19, 19, 19, 0, 5, 5, 5, 0, 21, 21, 21, 0, 19, 19, 19, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 10, 10, 10, 0, 11, 11, 11, 0, 15, 15, 15, 0, 19, 19, 19, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 18, 18, 18, 0, 6, 6, 6, 0, 10, 10, 10, 0, 20, 20, 20, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 10, 10, 10, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 3, 3, 3, 0, 6, 6, 6, 0, 20, 20, 20, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 18, 18, 18, 0, 18, 18, 18, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 20, 20, 20, 0, 20, 20, 20, 0, 3, 3, 3, 0, 8, 8, 8, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 7, 7, 7, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 19, 19, 19, 0, 1, 1, 1, 0, 20, 20, 20, 0, 8, 8, 8, 0, 3, 3, 3, 0, 2, 2, 2, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 21, 21, 21, 0, 5, 5, 5, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 16, 16, 16, 0, 20, 20, 20, 0, 12, 12, 12, 0, 1, 1, 1, 0, 16, 16, 16, 0, 15, 15, 15, 0, 11, 11, 11, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 11, 11, 11, 0, 20, 20, 20, 0, 15, 15, 15, 0, 18, 18, 18, 0, 16, 16, 16, 0, 16, 16, 16, 0, 19, 19, 19, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 21, 21, 21, 0, 3, 3, 3, 0, 5, 5, 5, 0, 1, 1, 1, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 15, 15, 15, 0, 8, 8, 8, 0, 13, 13, 13, 0, 2, 2, 2, 0, 10, 10, 10, 0, 11, 11, 11, 0, 9, 9, 9, 0, 18, 18, 18, 0, 9, 9, 9, 0, 2, 2, 2, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 7, 7, 7, 0, 18, 18, 18, 0, 19, 19, 19, 0, 13, 13, 13, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 20, 20, 20, 0, 2, 2, 2, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 7, 7, 7, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 19, 19, 19, 0, 2, 2, 2, 0, 1, 1, 1, 0, 9, 9, 9, 0, 14, 14, 14, 0, 3, 3, 3, 0, 18, 18, 18, 0, 18, 18, 18, 0, 16, 16, 16, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 20, 20, 20, 0, 20, 20, 20, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 11, 11, 11, 0, 12, 12, 12, 0, 1, 1, 1, 0, 10, 10, 10, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 10, 10, 10, 0, 13, 13, 13, 0, 2, 2, 2, 0, 6, 6, 6, 0, 1, 1, 1, 0, 9, 9, 9, 0, 20, 20, 20, 0, 14, 14, 14, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 18, 18, 18, 0, 21, 21, 21, 0, 3, 3, 3, 0, 21, 21, 21, 0, 2, 2, 2, 0, 0, 0, 0, 0, 17, 17, 17, 0, 4, 4, 4, 0, 21, 21, 21, 0, 7, 7, 7, 0, 3, 3, 3, 0, 8, 8, 8, 0, 10, 10, 10, 0, 4, 4, 4, 0, 5, 5, 5, 0, 9, 9, 9, 0, 0, 0, 0, 0, 8, 8, 8, 0, 1, 1, 1, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 15, 15, 15, 0, 7, 7, 7, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 6, 6, 6, 0, 16, 16, 16, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 21, 21, 21, 0, 20, 20, 20, 0, 19, 19, 19, 0, 18, 18, 18, 0, 16, 16, 16, 0, 9, 9, 9, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 3, 3, 3, 0, 16, 16, 16, 0, 19, 19, 19, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 10, 10, 10, 0, 11, 11, 11, 0, 20, 20, 20, 0, 19, 19, 19, 0, 17, 17, 17, 0, 5, 5, 5, 0, 8, 8, 8, 0, 20, 20, 20, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 16, 16, 16, 0, 12, 12, 12, 0, 16, 16, 16, 0, 18, 18, 18, 0, 19, 19, 19, 0, 14, 14, 14, 0, 18, 18, 18, 0, 12, 12, 12, 0, 5, 5, 5, 0, 21, 21, 21, 0, 19, 19, 19, 0, 19, 19, 19, 0, 21, 21, 21, 0, 4, 4, 4, 0, 9, 9, 9, 0, 16, 16, 16, 0, 11, 11, 11, 0, 4, 4, 4, 0, 12, 12, 12, 0, 18, 18, 18, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 1, 1, 1, 0, 2, 2, 2, 0, 5, 5, 5, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 19, 19, 19, 0, 3, 3, 3, 0, 21, 21, 21, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 2, 2, 2, 0, 19, 19, 19, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 18, 18, 18, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 1, 1, 1, 0, 3, 3, 3, 0, 17, 17, 17, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 13, 13, 13, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 11, 11, 11, 0, 3, 3, 3, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 14, 14, 14, 0, 1, 1, 1, 0, 7, 7, 7, 0, 17, 17, 17, 0, 20, 20, 20, 0, 20, 20, 20, 0, 3, 3, 3, 0, 1, 1, 1, 0, 20, 20, 20, 0, 11, 11, 11, 0, 5, 5, 5, 0, 5, 5, 5, 0, 11, 11, 11, 0, 18, 18, 18, 0, 13, 13, 13, 0, 6, 6, 6, 0, 18, 18, 18, 0, 18, 18, 18, 0, 2, 2, 2, 0, 14, 14, 14, 0, 14, 14, 14, 0, 20, 20, 20, 0, 5, 5, 5, 0, 10, 10, 10, 0, 3, 3, 3, 0, 3, 3, 3, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 9, 9, 9, 0, 18, 18, 18, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 4, 4, 4, 0, 11, 11, 11, 0, 2, 2, 2, 0, 16, 16, 16, 0, 13, 13, 13, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 19, 19, 19, 0, 20, 20, 20, 0, 20, 20, 20, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 9, 9, 9, 0, 2, 2, 2, 0, 21, 21, 21, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 14, 14, 14, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 4, 4, 4, 0, 17, 17, 17, 0, 14, 14, 14, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 21, 21, 21, 0, 13, 13, 13, 0, 13, 13, 13, 0, 21, 21, 21, 0, 2, 2, 2, 0, 3, 3, 3, 0, 7, 7, 7, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 4, 4, 4, 0, 21, 21, 21, 0, 20, 20, 20, 0, 14, 14, 14, 0, 2, 2, 2, 0, 1, 1, 1, 0, 11, 11, 11, 0, 2, 2, 2, 0, 18, 18, 18, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 3, 3, 3, 0, 9, 9, 9, 0, 9, 9, 9, 0, 17, 17, 17, 0, 13, 13, 13, 0, 16, 16, 16, 0, 14, 14, 14, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 10, 10, 10, 0, 0, 0, 0, 0, 10, 10, 10, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 4, 4, 4, 0, 1, 1, 1, 0, 2, 2, 2, 0, 0, 0, 0, 0, 17, 17, 17, 0, 6, 6, 6, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 1, 1, 1, 0, 20, 20, 20, 0, 16, 16, 16, 0, 18, 18, 18, 0, 17, 17, 17, 0, 20, 20, 20, 0, 8, 8, 8, 0, 11, 11, 11, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 20, 20, 20, 0, 18, 18, 18, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 16, 16, 16, 0, 4, 4, 4, 0, 14, 14, 14, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 16, 16, 16, 0, 19, 19, 19, 0, 18, 18, 18, 0, 21, 21, 21, 0, 21, 21, 21, 0, 6, 6, 6, 0, 12, 12, 12, 0, 21, 21, 21, 0, 6, 6, 6, 0, 21, 21, 21, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 1, 1, 1, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 21, 21, 21, 0, 18, 18, 18, 0, 20, 20, 20, 0, 16, 16, 16, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 1, 1, 1, 0, 7, 7, 7, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 8, 8, 8, 0, 19, 19, 19, 0, 3, 3, 3, 0, 19, 19, 19, 0, 18, 18, 18, 0, 20, 20, 20, 0, 1, 1, 1, 0, 3, 3, 3, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 21, 21, 21, 0, 18, 18, 18, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 0, 0, 0, 0, 20, 20, 20, 0, 8, 8, 8, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 4, 4, 4, 0, 2, 2, 2, 0, 21, 21, 21, 0, 9, 9, 9, 0, 4, 4, 4, 0, 19, 19, 19, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 1, 1, 1, 0, 19, 19, 19, 0, 16, 16, 16, 0, 14, 14, 14, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 3, 3, 3, 0, 21, 21, 21, 0, 20, 20, 20, 0, 6, 6, 6, 0, 2, 2, 2, 0, 20, 20, 20, 0, 18, 18, 18, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 10, 10, 10, 0, 14, 14, 14, 0, 15, 15, 15, 0, 21, 21, 21, 0, 17, 17, 17, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 17, 17, 17, 0, 2, 2, 2, 0, 20, 20, 20, 0, 21, 21, 21, 0, 2, 2, 2, 0, 7, 7, 7, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 10, 10, 10, 0, 15, 15, 15, 0, 0, 0, 0, 0, 9, 9, 9, 0, 17, 17, 17, 0, 17, 17, 17, 0, 18, 18, 18, 0, 20, 20, 20, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 7, 7, 7, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 6, 6, 6, 0, 2, 2, 2, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 4, 4, 4, 0, 21, 21, 21, 0, 18, 18, 18, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 10, 10, 10, 0, 18, 18, 18, 0, 13, 13, 13, 0, 2, 2, 2, 0, 4, 4, 4, 0, 3, 3, 3, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 5, 5, 5, 0, 2, 2, 2, 0, 7, 7, 7, 0, 14, 14, 14, 0, 3, 3, 3, 0, 12, 12, 12, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 15, 15, 15, 0, 14, 14, 14, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 16, 16, 16, 0, 12, 12, 12, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 15, 15, 15, 0, 18, 18, 18, 0, 20, 20, 20, 0, 7, 7, 7, 0, 14, 14, 14, 0, 12, 12, 12, 0, 21, 21, 21, 0, 4, 4, 4, 0, 21, 21, 21, 0, 18, 18, 18, 0, 16, 16, 16, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 13, 13, 13, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 2, 2, 2, 0, 9, 9, 9, 0, 16, 16, 16, 0, 1, 1, 1, 0, 5, 5, 5, 0, 7, 7, 7, 0, 18, 18, 18, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 4, 4, 4, 0, 16, 16, 16, 0, 2, 2, 2, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 20, 20, 20, 0, 3, 3, 3, 0, 8, 8, 8, 0, 21, 21, 21, 0, 0, 0, 0, 0, 18, 18, 18, 0, 3, 3, 3, 0, 4, 4, 4, 0, 2, 2, 2, 0, 5, 5, 5, 0, 4, 4, 4, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 19, 19, 19, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 21, 21, 21, 0, 20, 20, 20, 0, 5, 5, 5, 0, 0, 0, 0, 0, 20, 20, 20, 0, 0, 0, 0, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 5, 5, 5, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 19, 19, 19, 0, 19, 19, 19, 0, 20, 20, 20, 0, 3, 3, 3, 0, 6, 6, 6, 0, 4, 4, 4, 0, 13, 13, 13, 0, 14, 14, 14, 0, 4, 4, 4, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 18, 18, 18, 0, 20, 20, 20, 0, 9, 9, 9, 0, 0, 0, 0, 0, 1, 1, 1, 0, 18, 18, 18, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 7, 7, 7, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 21, 21, 21, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 20, 20, 20, 0, 2, 2, 2, 0, 1, 1, 1, 0, 2, 2, 2, 0, 10, 10, 10, 0, 16, 16, 16, 0, 1, 1, 1, 0, 21, 21, 21, 0, 10, 10, 10, 0, 5, 5, 5, 0, 1, 1, 1, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 7, 7, 7, 0, 6, 6, 6, 0, 19, 19, 19, 0, 20, 20, 20, 0, 0, 0, 0, 0, 4, 4, 4, 0, 7, 7, 7, 0, 20, 20, 20, 0, 20, 20, 20, 0, 5, 5, 5, 0, 14, 14, 14, 0, 11, 11, 11, 0, 16, 16, 16, 0, 0, 0, 0, 0, 10, 10, 10, 0, 16, 16, 16, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 7, 7, 7, 0, 3, 3, 3, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 0, 0, 0, 0, 10, 10, 10, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 5, 5, 5, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 19, 19, 19, 0, 18, 18, 18, 0, 19, 19, 19, 0, 5, 5, 5, 0, 13, 13, 13, 0, 12, 12, 12, 0, 21, 21, 21, 0, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 20, 20, 20, 0, 2, 2, 2, 0, 7, 7, 7, 0, 13, 13, 13, 0, 0, 0, 0, 0, 14, 14, 14, 0, 8, 8, 8, 0, 4, 4, 4, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 13, 13, 13, 0, 3, 3, 3, 0, 7, 7, 7, 0, 14, 14, 14, 0, 13, 13, 13, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 14, 14, 14, 0, 15, 15, 15, 0, 5, 5, 5, 0, 2, 2, 2, 0, 3, 3, 3, 0, 19, 19, 19, 0, 18, 18, 18, 0, 6, 6, 6, 0, 19, 19, 19, 0, 19, 19, 19, 0, 7, 7, 7, 0, 7, 7, 7, 0, 19, 19, 19, 0, 19, 19, 19, 0, 16, 16, 16, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 16, 16, 16, 0, 16, 16, 16, 0, 20, 20, 20, 0, 5, 5, 5, 0, 4, 4, 4, 0, 2, 2, 2, 0, 18, 18, 18, 0, 13, 13, 13, 0, 8, 8, 8, 0, 3, 3, 3, 0, 21, 21, 21, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 14, 14, 14, 0, 20, 20, 20, 0, 3, 3, 3, 0, 9, 9, 9, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 18, 18, 18, 0, 17, 17, 17, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 1, 1, 1, 0, 20, 20, 20, 0, 5, 5, 5, 0, 1, 1, 1, 0, 7, 7, 7, 0, 3, 3, 3, 0, 3, 3, 3, 0, 5, 5, 5, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 9, 9, 9, 0, 12, 12, 12, 0, 16, 16, 16, 0, 20, 20, 20, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 17, 17, 17, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 0, 0, 0, 0, 7, 7, 7, 0, 21, 21, 21, 0, 13, 13, 13, 0, 0, 0, 0, 0, 20, 20, 20, 0, 18, 18, 18, 0, 7, 7, 7, 0, 5, 5, 5, 0, 0, 0, 0, 0, 15, 15, 15, 0, 19, 19, 19, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 0, 0, 0, 0, 3, 3, 3, 0, 13, 13, 13, 0, 8, 8, 8, 0, 20, 20, 20, 0, 16, 16, 16, 0, 18, 18, 18, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 16, 16, 16, 0, 19, 19, 19, 0, 8, 8, 8, 0, 9, 9, 9, 0, 12, 12, 12, 0, 10, 10, 10, 0, 13, 13, 13, 0, 4, 4, 4, 0, 1, 1, 1, 0, 16, 16, 16, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 12, 12, 12, 0, 17, 17, 17, 0, 16, 16, 16, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 20, 20, 20, 0, 4, 4, 4, 0, 15, 15, 15, 0, 9, 9, 9, 0, 16, 16, 16, 0, 15, 15, 15, 0, 16, 16, 16, 0, 1, 1, 1, 0, 21, 21, 21, 0, 17, 17, 17, 0, 16, 16, 16, 0, 5, 5, 5, 0, 10, 10, 10, 0, 20, 20, 20, 0, 18, 18, 18, 0, 20, 20, 20, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 15, 15, 15, 0, 14, 14, 14, 0, 21, 21, 21, 0, 20, 20, 20, 0, 6, 6, 6, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 1, 1, 1, 0, 4, 4, 4, 0, 13, 13, 13, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 3, 3, 3, 0, 6, 6, 6, 0, 14, 14, 14, 0, 20, 20, 20, 0, 3, 3, 3, 0, 17, 17, 17, 0, 15, 15, 15, 0, 16, 16, 16, 0, 20, 20, 20, 0, 14, 14, 14, 0, 7, 7, 7, 0, 20, 20, 20, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 21, 21, 21, 0, 19, 19, 19, 0, 19, 19, 19, 0, 19, 19, 19, 0, 21, 21, 21, 0, 1, 1, 1, 0, 3, 3, 3, 0, 4, 4, 4, 0, 6, 6, 6, 0, 8, 8, 8, 0, 7, 7, 7, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 0, 7, 7, 7, 0, 4, 4, 4, 0, 2, 2, 2, 0, 1, 1, 1, 0, 21, 21, 21, 0, 20, 20, 20, 0, 19, 19, 19, 0, 18, 18, 18, 0, 18, 18, 18, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 16, 16, 16, 0, 2, 2, 2, 0, 8, 8, 8, 0, 3, 3, 3, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 2, 2, 2, 0, 5, 5, 5, 0, 21, 21, 21, 0, 13, 13, 13, 0, 2, 2, 2, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 4, 4, 4, 0, 15, 15, 15, 0, 1, 1, 1, 0, 4, 4, 4, 0, 5, 5, 5, 0, 4, 4, 4, 0, 14, 14, 14, 0, 7, 7, 7, 0, 3, 3, 3, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 16, 16, 16, 0, 17, 17, 17, 0, 6, 6, 6, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 18, 18, 18, 0, 6, 6, 6, 0, 15, 15, 15, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 15, 15, 15, 0, 5, 5, 5, 0, 20, 20, 20, 0, 15, 15, 15, 0, 15, 15, 15, 0, 21, 21, 21, 0, 13, 13, 13, 0, 3, 3, 3, 0, 16, 16, 16, 0, 21, 21, 21, 0, 15, 15, 15, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 18, 18, 18, 0, 3, 3, 3, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 8, 8, 8, 0, 21, 21, 21, 0, 21, 21, 21, 0, 18, 18, 18, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 3, 3, 3, 0, 4, 4, 4, 0, 13, 13, 13, 0, 13, 13, 13, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 16, 16, 16, 0, 18, 18, 18, 0, 18, 18, 18, 0, 19, 19, 19, 0, 20, 20, 20, 0, 1, 1, 1, 0, 2, 2, 2, 0, 5, 5, 5, 0, 18, 18, 18, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 6, 6, 6, 0, 2, 2, 2, 0, 1, 1, 1, 0, 20, 20, 20, 0, 19, 19, 19, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 20, 20, 20, 0, 15, 15, 15, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 2, 2, 2, 0, 21, 21, 21, 0, 18, 18, 18, 0, 4, 4, 4, 0, 11, 11, 11, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 4, 4, 4, 0, 12, 12, 12, 0, 2, 2, 2, 0, 16, 16, 16, 0, 18, 18, 18, 0, 13, 13, 13, 0, 19, 19, 19, 0, 2, 2, 2, 0, 14, 14, 14, 0, 19, 19, 19, 0, 19, 19, 19, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 14, 14, 14, 0, 2, 2, 2, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 15, 15, 15, 0, 16, 16, 16, 0, 15, 15, 15, 0, 10, 10, 10, 0, 18, 18, 18, 0, 14, 14, 14, 0, 13, 13, 13, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 6, 6, 6, 0, 2, 2, 2, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 20, 20, 20, 0, 20, 20, 20, 0, 3, 3, 3, 0, 11, 11, 11, 0, 19, 19, 19, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 18, 18, 18, 0, 19, 19, 19, 0, 15, 15, 15, 0, 21, 21, 21, 0, 2, 2, 2, 0, 12, 12, 12, 0, 9, 9, 9, 0, 10, 10, 10, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 9, 9, 9, 0, 15, 15, 15, 0, 14, 14, 14, 0, 2, 2, 2, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 20, 20, 20, 0, 2, 2, 2, 0, 4, 4, 4, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 6, 6, 6, 0, 1, 1, 1, 0, 20, 20, 20, 0, 19, 19, 19, 0, 17, 17, 17, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 1, 1, 1, 0, 12, 12, 12, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 5, 5, 5, 0, 6, 6, 6, 0, 14, 14, 14, 0, 20, 20, 20, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 19, 19, 19, 0, 19, 19, 19, 0, 14, 14, 14, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 13, 13, 13, 0, 19, 19, 19, 0, 4, 4, 4, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 19, 19, 19, 0, 2, 2, 2, 0, 15, 15, 15, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 19, 19, 19, 0, 18, 18, 18, 0, 17, 17, 17, 0, 2, 2, 2, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 19, 19, 19, 0, 9, 9, 9, 0, 16, 16, 16, 0, 2, 2, 2, 0, 21, 21, 21, 0, 14, 14, 14, 0, 18, 18, 18, 0, 11, 11, 11, 0, 6, 6, 6, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 20, 20, 20, 0, 2, 2, 2, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 4, 4, 4, 0, 9, 9, 9, 0, 1, 1, 1, 0, 19, 19, 19, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 19, 19, 19, 0, 13, 13, 13, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 2, 2, 2, 0, 10, 10, 10, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 16, 16, 16, 0, 3, 3, 3, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 2, 2, 2, 0, 16, 16, 16, 0, 19, 19, 19, 0, 3, 3, 3, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 16, 16, 16, 0, 6, 6, 6, 0, 16, 16, 16, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 9, 9, 9, 0, 5, 5, 5, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 11, 11, 11, 0, 6, 6, 6, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 17, 17, 17, 0, 14, 14, 14, 0, 2, 2, 2, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 1, 1, 1, 0, 1, 1, 1, 0, 18, 18, 18, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 13, 13, 13, 0, 17, 17, 17, 0, 12, 12, 12, 0, 11, 11, 11, 0, 13, 13, 13, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 16, 16, 16, 0, 20, 20, 20, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 16, 16, 16, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 14, 14, 14, 0, 3, 3, 3, 0, 1, 1, 1, 0, 18, 18, 18, 0, 18, 18, 18, 0, 15, 15, 15, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 19, 19, 19, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 20, 20, 20, 0, 20, 20, 20, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 18, 18, 18, 0, 20, 20, 20, 0, 12, 12, 12, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 15, 15, 15, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 13, 13, 13, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 6, 6, 6, 0, 16, 16, 16, 0, 3, 3, 3, 0, 18, 18, 18, 0, 13, 13, 13, 0, 19, 19, 19, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 18, 18, 18, 0, 19, 19, 19, 0, 21, 21, 21, 0, 11, 11, 11, 0, 17, 17, 17, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 2, 2, 2, 0, 16, 16, 16, 0, 7, 7, 7, 0, 17, 17, 17, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 6, 6, 6, 0, 10, 10, 10, 0, 9, 9, 9, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 14, 14, 14, 0, 13, 13, 13, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 16, 16, 16, 0, 1, 1, 1, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 6, 6, 6, 0, 4, 4, 4, 0, 18, 18, 18, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 5, 5, 5, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 12, 12, 12, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 15, 15, 15, 0, 15, 15, 15, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 3, 3, 3, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 10, 10, 10, 0, 6, 6, 6, 0, 20, 20, 20, 0, 16, 16, 16, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 13, 13, 13, 0, 10, 10, 10, 0, 19, 19, 19, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 1, 1, 1, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 5, 5, 5, 0, 15, 15, 15, 0, 11, 11, 11, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 17, 17, 17, 0, 15, 15, 15, 0, 19, 19, 19, 0, 18, 18, 18, 0, 16, 16, 16, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 18, 18, 18, 0, 4, 4, 4, 0, 10, 10, 10, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 19, 19, 19, 0, 4, 4, 4, 0, 16, 16, 16, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 4, 4, 4, 0, 16, 16, 16, 0, 20, 20, 20, 0, 5, 5, 5, 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 10, 10, 10, 0, 21, 21, 21, 0, 21, 21, 21, 0, 17, 17, 17, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 15, 15, 15, 0, 11, 11, 11, 0, 17, 17, 17, 0, 17, 17, 17, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 5, 5, 5, 0, 5, 5, 5, 0, 12, 12, 12, 0, 9, 9, 9, 0, 16, 16, 16, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 15, 15, 15, 0, 21, 21, 21, 0, 8, 8, 8, 0, 7, 7, 7, 0, 9, 9, 9, 0, 6, 6, 6, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 1, 1, 1, 0, 20, 20, 20, 0, 17, 17, 17, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 17, 17, 17, 0, 19, 19, 19, 0, 16, 16, 16, 0, 3, 3, 3, 0, 5, 5, 5, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 10, 10, 10, 0, 16, 16, 16, 0, 20, 20, 20, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 19, 19, 19, 0, 1, 1, 1, 0, 18, 18, 18, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 21, 21, 21, 0, 7, 7, 7, 0, 11, 11, 11, 0, 7, 7, 7, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 20, 20, 20, 0, 21, 21, 21, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 8, 8, 8, 0, 19, 19, 19, 0, 16, 16, 16, 0, 6, 6, 6, 0, 4, 4, 4, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 14, 14, 14, 0, 17, 17, 17, 0, 20, 20, 20, 0, 9, 9, 9, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 12, 12, 12, 0, 15, 15, 15, 0, 9, 9, 9, 0, 21, 21, 21, 0, 9, 9, 9, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 13, 13, 13, 0, 14, 14, 14, 0, 2, 2, 2, 0, 15, 15, 15, 0, 16, 16, 16, 0, 19, 19, 19, 0, 5, 5, 5, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 20, 20, 20, 0, 9, 9, 9, 0, 4, 4, 4, 0, 2, 2, 2, 0, 8, 8, 8, 0, 8, 8, 8, 0, 13, 13, 13, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 16, 16, 16, 0, 5, 5, 5, 0, 5, 5, 5, 0, 18, 18, 18, 0, 17, 17, 17, 0, 8, 8, 8, 0, 5, 5, 5, 0, 18, 18, 18, 0, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 12, 12, 12, 0, 20, 20, 20, 0, 21, 21, 21, 0, 3, 3, 3, 0, 4, 4, 4, 0, 18, 18, 18, 0, 19, 19, 19, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 12, 12, 12, 0, 16, 16, 16, 0, 20, 20, 20, 0, 21, 21, 21, 0, 20, 20, 20, 0, 20, 20, 20, 0, 7, 7, 7, 0, 13, 13, 13, 0, 10, 10, 10, 0, 9, 9, 9, 0, 15, 15, 15, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 1, 1, 1, 0, 19, 19, 19, 0, 19, 19, 19, 0, 6, 6, 6, 0, 11, 11, 11, 0, 6, 6, 6, 0, 18, 18, 18, 0, 7, 7, 7, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 12, 12, 12, 0, 8, 8, 8, 0, 15, 15, 15, 0, 5, 5, 5, 0, 10, 10, 10, 0, 3, 3, 3, 0, 2, 2, 2, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 7, 7, 7, 0, 6, 6, 6, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 17, 17, 17, 0, 16, 16, 16, 0, 7, 7, 7, 0, 2, 2, 2, 0, 20, 20, 20, 0, 20, 20, 20, 0, 4, 4, 4, 0, 10, 10, 10, 0, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 7, 7, 7, 0, 20, 20, 20, 0, 17, 17, 17, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 17, 17, 17, 0, 19, 19, 19, 0, 19, 19, 19, 0, 20, 20, 20, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 13, 13, 13, 0, 4, 4, 4, 0, 21, 21, 21, 0, 18, 18, 18, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 1, 1, 1, 0, 18, 18, 18, 0, 14, 14, 14, 0, 18, 18, 18, 0, 16, 16, 16, 0, 17, 17, 17, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 13, 13, 13, 0, 15, 15, 15, 0, 3, 3, 3, 0, 18, 18, 18, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 15, 15, 15, 0, 16, 16, 16, 0, 17, 17, 17, 0, 8, 8, 8, 0, 4, 4, 4, 0, 11, 11, 11, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 7, 7, 7, 0, 3, 3, 3, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 18, 18, 18, 0, 20, 20, 20, 0, 2, 2, 2, 0, 8, 8, 8, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 11, 11, 11, 0, 3, 3, 3, 0, 20, 20, 20, 0, 18, 18, 18, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 5, 5, 5, 0, 4, 4, 4, 0, 13, 13, 13, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 10, 10, 10, 0, 2, 2, 2, 0, 15, 15, 15, 0, 17, 17, 17, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 9, 9, 9, 0, 16, 16, 16, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 2, 2, 2, 0, 5, 5, 5, 0, 5, 5, 5, 0, 19, 19, 19, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 15, 15, 15, 0, 16, 16, 16, 0, 18, 18, 18, 0, 1, 1, 1, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 12, 12, 12, 0, 16, 16, 16, 0, 20, 20, 20, 0, 1, 1, 1, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 17, 17, 17, 0, 10, 10, 10, 0, 18, 18, 18, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 21, 21, 21, 0, 11, 11, 11, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 17, 17, 17, 0, 20, 20, 20, 0, 1, 1, 1, 0, 5, 5, 5, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 5, 5, 5, 0, 18, 18, 18, 0, 6, 6, 6, 0, 1, 1, 1, 0, 14, 14, 14, 0, 7, 7, 7, 0, 7, 7, 7, 0, 1, 1, 1, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 3, 3, 3, 0, 12, 12, 12, 0, 18, 18, 18, 0, 11, 11, 11, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 17, 17, 17, 0, 13, 13, 13, 0, 3, 3, 3, 0, 19, 19, 19, 0, 0, 0, 0, 0, 4, 4, 4, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 8, 8, 8, 0, 3, 3, 3, 0, 1, 1, 1, 0, 5, 5, 5, 0, 7, 7, 7, 0, 19, 19, 19, 0, 18, 18, 18, 0, 19, 19, 19, 0, 20, 20, 20, 0, 10, 10, 10, 0, 14, 14, 14, 0, 17, 17, 17, 0, 16, 16, 16, 0, 18, 18, 18, 0, 5, 5, 5, 0, 14, 14, 14, 0, 21, 21, 21, 0, 17, 17, 17, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 20, 20, 20, 0, 8, 8, 8, 0, 7, 7, 7, 0, 8, 8, 8, 0, 13, 13, 13, 0, 2, 2, 2, 0, 8, 8, 8, 0, 15, 15, 15, 0, 21, 21, 21, 0, 10, 10, 10, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 20, 20, 20, 0, 19, 19, 19, 0, 16, 16, 16, 0, 18, 18, 18, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 1, 1, 1, 0, 1, 1, 1, 0, 19, 19, 19, 0, 21, 21, 21, 0, 10, 10, 10, 0, 16, 16, 16, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 12, 12, 12, 0, 11, 11, 11, 0, 8, 8, 8, 0, 3, 3, 3, 0, 3, 3, 3, 0, 8, 8, 8, 0, 11, 11, 11, 0, 5, 5, 5, 0, 2, 2, 2, 0, 5, 5, 5, 0, 1, 1, 1, 0, 21, 21, 21, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 8, 8, 8, 0, 17, 17, 17, 0, 17, 17, 17, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 16, 16, 16, 0, 18, 18, 18, 0, 21, 21, 21, 0, 10, 10, 10, 0, 15, 15, 15, 0, 8, 8, 8, 0, 15, 15, 15, 0, 17, 17, 17, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 17, 17, 17, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 10, 10, 10, 0, 3, 3, 3, 0, 20, 20, 20, 0, 1, 1, 1, 0, 7, 7, 7, 0, 10, 10, 10, 0, 21, 21, 21, 0, 20, 20, 20, 0, 4, 4, 4, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 0, 0, 0, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 18, 18, 18, 0, 1, 1, 1, 0, 17, 17, 17, 0, 16, 16, 16, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 3, 3, 3, 0, 18, 18, 18, 0, 18, 18, 18, 0, 16, 16, 16, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 18, 18, 18, 0, 6, 6, 6, 0, 3, 3, 3, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 19, 19, 19, 0, 17, 17, 17, 0, 1, 1, 1, 0, 2, 2, 2, 0, 17, 17, 17, 0, 17, 17, 17, 0, 4, 4, 4, 0, 4, 4, 4, 0, 7, 7, 7, 0, 19, 19, 19, 0, 19, 19, 19, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 14, 14, 14, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 11, 11, 11, 0, 5, 5, 5, 0, 1, 1, 1, 0, 1, 1, 1, 0, 4, 4, 4, 0, 3, 3, 3, 0, 1, 1, 1, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 17, 17, 17, 0, 11, 11, 11, 0, 19, 19, 19, 0, 15, 15, 15, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 9, 9, 9, 0, 21, 21, 21, 0, 5, 5, 5, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 17, 17, 17, 0, 21, 21, 21, 0, 15, 15, 15, 0, 20, 20, 20, 0, 18, 18, 18, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 15, 15, 15, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 19, 19, 19, 0, 2, 2, 2, 0, 11, 11, 11, 0, 5, 5, 5, 0, 8, 8, 8, 0, 0, 0, 0, 0, 2, 2, 2, 0, 8, 8, 8, 0, 0, 0, 0, 0, 1, 1, 1, 0, 17, 17, 17, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 0, 19, 19, 19, 0, 12, 12, 12, 0, 8, 8, 8, 0, 4, 4, 4, 0, 7, 7, 7, 0, 2, 2, 2, 0, 19, 19, 19, 0, 19, 19, 19, 0, 9, 9, 9, 0, 20, 20, 20, 0, 16, 16, 16, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 2, 2, 2, 0, 1, 1, 1, 0, 11, 11, 11, 0, 17, 17, 17, 0, 14, 14, 14, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 19, 19, 19, 0, 21, 21, 21, 0, 15, 15, 15, 0, 18, 18, 18, 0, 15, 15, 15, 0, 16, 16, 16, 0, 5, 5, 5, 0, 8, 8, 8, 0, 3, 3, 3, 0, 5, 5, 5, 0, 18, 18, 18, 0, 20, 20, 20, 0, 11, 11, 11, 0, 9, 9, 9, 0, 18, 18, 18, 0, 16, 16, 16, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 19, 19, 19, 0, 4, 4, 4, 0, 17, 17, 17, 0, 12, 12, 12, 0, 1, 1, 1, 0, 5, 5, 5, 0, 8, 8, 8, 0, 6, 6, 6, 0, 10, 10, 10, 0, 10, 10, 10, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 17, 17, 17, 0, 5, 5, 5, 0, 1, 1, 1, 0, 20, 20, 20, 0, 17, 17, 17, 0, 17, 17, 17, 0, 17, 17, 17, 0, 21, 21, 21, 0, 14, 14, 14, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 9, 9, 9, 0, 20, 20, 20, 0, 19, 19, 19, 0, 18, 18, 18, 0, 14, 14, 14, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 10, 10, 10, 0, 15, 15, 15, 0, 3, 3, 3, 0, 13, 13, 13, 0, 12, 12, 12, 0, 14, 14, 14, 0, 12, 12, 12, 0, 1, 1, 1, 0, 15, 15, 15, 0, 13, 13, 13, 0, 10, 10, 10, 0, 21, 21, 21, 0, 6, 6, 6, 0, 7, 7, 7, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 19, 19, 19, 0, 5, 5, 5, 0, 15, 15, 15, 0, 9, 9, 9, 0, 19, 19, 19, 0, 19, 19, 19, 0, 1, 1, 1, 0, 7, 7, 7, 0, 1, 1, 1, 0, 4, 4, 4, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 2, 2, 2, 0, 19, 19, 19, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 15, 15, 15, 0, 4, 4, 4, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 14, 14, 14, 0, 18, 18, 18, 0, 17, 17, 17, 0, 19, 19, 19, 0, 1, 1, 1, 0, 17, 17, 17, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 1, 1, 1, 0, 14, 14, 14, 0, 18, 18, 18, 0, 16, 16, 16, 0, 15, 15, 15, 0, 17, 17, 17, 0, 3, 3, 3, 0, 1, 1, 1, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 18, 18, 18, 0, 21, 21, 21, 0, 18, 18, 18, 0, 3, 3, 3, 0, 18, 18, 18, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 20, 20, 20, 0, 3, 3, 3, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 11, 11, 11, 0, 2, 2, 2, 0, 21, 21, 21, 0, 18, 18, 18, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 15, 15, 15, 0, 16, 16, 16, 0, 14, 14, 14, 0, 12, 12, 12, 0, 14, 14, 14, 0, 17, 17, 17, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 16, 16, 16, 0, 14, 14, 14, 0, 18, 18, 18, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 15, 15, 15, 0, 2, 2, 2, 0, 16, 16, 16, 0, 16, 16, 16, 0, 17, 17, 17, 0, 18, 18, 18, 0, 20, 20, 20, 0, 4, 4, 4, 0, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 18, 18, 18, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 5, 5, 5, 0, 14, 14, 14, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 21, 21, 21, 0, 12, 12, 12, 0, 17, 17, 17, 0, 14, 14, 14, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 10, 10, 10, 0, 3, 3, 3, 0, 12, 12, 12, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 11, 11, 11, 0, 3, 3, 3, 0, 3, 3, 3, 0, 21, 21, 21, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 15, 15, 15, 0, 20, 20, 20, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 13, 13, 13, 0, 15, 15, 15, 0, 21, 21, 21, 0, 18, 18, 18, 0, 17, 17, 17, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 18, 18, 18, 0, 4, 4, 4, 0, 7, 7, 7, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0, 17, 17, 17, 0, 19, 19, 19, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 21, 21, 21, 0, 19, 19, 19, 0, 13, 13, 13, 0, 5, 5, 5, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 21, 21, 21, 0, 1, 1, 1, 0, 9, 9, 9, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 4, 4, 4, 0, 6, 6, 6, 0, 17, 17, 17, 0, 16, 16, 16, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 19, 19, 19, 0, 14, 14, 14, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 18, 18, 18, 0, 20, 20, 20, 0, 8, 8, 8, 0, 18, 18, 18, 0, 18, 18, 18, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 0, 5, 5, 5, 0, 20, 20, 20, 0, 13, 13, 13, 0, 9, 9, 9, 0, 18, 18, 18, 0, 20, 20, 20, 0, 20, 20, 20, 0, 1, 1, 1, 0, 12, 12, 12, 0, 14, 14, 14, 0, 10, 10, 10, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 20, 20, 20, 0, 15, 15, 15, 0, 15, 15, 15, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 17, 17, 17, 0, 4, 4, 4, 0, 10, 10, 10, 0, 20, 20, 20, 0, 3, 3, 3, 0, 4, 4, 4, 0, 0, 0, 0, 0, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 10, 10, 10, 0, 13, 13, 13, 0, 2, 2, 2, 0, 6, 6, 6, 0, 3, 3, 3, 0, 15, 15, 15, 0, 2, 2, 2, 0, 18, 18, 18, 0, 13, 13, 13, 0, 12, 12, 12, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 3, 3, 3, 0, 15, 15, 15, 0, 21, 21, 21, 0, 18, 18, 18, 0, 20, 20, 20, 0, 12, 12, 12, 0, 8, 8, 8, 0, 3, 3, 3, 0, 18, 18, 18, 0, 9, 9, 9, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 4, 4, 4, 0, 20, 20, 20, 0, 19, 19, 19, 0, 17, 17, 17, 0, 18, 18, 18, 0, 12, 12, 12, 0, 18, 18, 18, 0, 15, 15, 15, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 21, 21, 21, 0, 3, 3, 3, 0, 9, 9, 9, 0, 17, 17, 17, 0, 6, 6, 6, 0, 1, 1, 1, 0, 21, 21, 21, 0, 19, 19, 19, 0, 20, 20, 20, 0, 1, 1, 1, 0, 10, 10, 10, 0, 7, 7, 7, 0, 0, 0, 0, 0, 5, 5, 5, 0, 4, 4, 4, 0, 9, 9, 9, 0, 3, 3, 3, 0, 17, 17, 17, 0, 16, 16, 16, 0, 16, 16, 16, 0, 10, 10, 10, 0, 15, 15, 15, 0, 16, 16, 16, 0, 12, 12, 12, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 3, 3, 3, 0, 17, 17, 17, 0, 1, 1, 1, 0, 16, 16, 16, 0, 17, 17, 17, 0, 14, 14, 14, 0, 19, 19, 19, 0, 17, 17, 17, 0, 17, 17, 17, 0, 19, 19, 19, 0, 5, 5, 5, 0, 7, 7, 7, 0, 5, 5, 5, 0, 17, 17, 17, 0, 13, 13, 13, 0, 3, 3, 3, 0, 3, 3, 3, 0, 19, 19, 19, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 15, 15, 15, 0, 2, 2, 2, 0, 2, 2, 2, 0, 14, 14, 14, 0, 11, 11, 11, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 5, 5, 5, 0, 21, 21, 21, 0, 15, 15, 15, 0, 15, 15, 15, 0, 19, 19, 19, 0, 19, 19, 19, 0, 21, 21, 21, 0, 21, 21, 21, 0, 6, 6, 6, 0, 5, 5, 5, 0, 20, 20, 20, 0, 19, 19, 19, 0, 6, 6, 6, 0, 14, 14, 14, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 17, 17, 17, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 15, 15, 15, 0, 21, 21, 21, 0, 15, 15, 15, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 20, 20, 20, 0, 4, 4, 4, 0, 8, 8, 8, 0, 7, 7, 7, 0, 17, 17, 17, 0, 15, 15, 15, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 2, 2, 2, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 16, 16, 16, 0, 17, 17, 17, 0, 4, 4, 4, 0, 17, 17, 17, 0, 1, 1, 1, 0, 17, 17, 17, 0, 16, 16, 16, 0, 13, 13, 13, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 17, 17, 17, 0, 19, 19, 19, 0, 3, 3, 3, 0, 18, 18, 18, 0, 3, 3, 3, 0, 19, 19, 19, 0, 4, 4, 4, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 17, 17, 17, 0, 7, 7, 7, 0, 14, 14, 14, 0, 5, 5, 5, 0, 0, 0, 0, 0, 1, 1, 1, 0, 5, 5, 5, 0, 17, 17, 17, 0, 14, 14, 14, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 15, 15, 15, 0, 3, 3, 3, 0, 1, 1, 1, 0, 9, 9, 9, 0, 3, 3, 3, 0, 20, 20, 20, 0, 14, 14, 14, 0, 20, 20, 20, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 15, 15, 15, 0, 19, 19, 19, 0, 18, 18, 18, 0, 9, 9, 9, 0, 1, 1, 1, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 15, 15, 15, 0, 16, 16, 16, 0, 20, 20, 20, 0, 20, 20, 20, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 13, 13, 13, 0, 14, 14, 14, 0, 3, 3, 3, 0, 5, 5, 5, 0, 17, 17, 17, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 14, 14, 14, 0, 14, 14, 14, 0, 17, 17, 17, 0, 2, 2, 2, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 15, 15, 15, 0, 17, 17, 17, 0, 2, 2, 2, 0, 16, 16, 16, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 17, 17, 17, 0, 10, 10, 10, 0, 18, 18, 18, 0, 5, 5, 5, 0, 21, 21, 21, 0, 21, 21, 21, 0, 15, 15, 15, 0, 14, 14, 14, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 15, 15, 15, 0, 1, 1, 1, 0, 7, 7, 7, 0, 16, 16, 16, 0, 15, 15, 15, 0, 16, 16, 16, 0, 20, 20, 20, 0, 5, 5, 5, 0, 17, 17, 17, 0, 20, 20, 20, 0, 15, 15, 15, 0, 16, 16, 16, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 17, 17, 17, 0, 14, 14, 14, 0, 20, 20, 20, 0, 14, 14, 14, 0, 13, 13, 13, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 5, 5, 5, 0, 0, 0, 0, 0, 21, 21, 21, 0, 17, 17, 17, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 19, 19, 19, 0, 13, 13, 13, 0, 13, 13, 13, 0, 15, 15, 15, 0, 4, 4, 4, 0, 18, 18, 18, 0, 19, 19, 19, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 14, 14, 14, 0, 16, 16, 16, 0, 6, 6, 6, 0, 18, 18, 18, 0, 18, 18, 18, 0, 13, 13, 13, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 18, 18, 18, 0, 11, 11, 11, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 20, 20, 20, 0, 17, 17, 17, 0, 16, 16, 16, 0, 7, 7, 7, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 18, 18, 18, 0, 18, 18, 18, 0, 14, 14, 14, 0, 14, 14, 14, 0, 19, 19, 19, 0, 15, 15, 15, 0, 12, 12, 12, 0, 11, 11, 11, 0, 12, 12, 12, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 12, 12, 12, 0, 15, 15, 15, 0, 3, 3, 3, 0, 5, 5, 5, 0, 19, 19, 19, 0, 21, 21, 21, 0, 13, 13, 13, 0, 11, 11, 11, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 20, 20, 20, 0, 7, 7, 7, 0, 19, 19, 19, 0, 0, 0, 0, 0, 10, 10, 10, 0, 16, 16, 16, 0, 14, 14, 14, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 14, 14, 14, 0, 16, 16, 16, 0, 5, 5, 5, 0, 7, 7, 7, 0, 15, 15, 15, 0, 13, 13, 13, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 14, 14, 14, 0, 16, 16, 16, 0, 14, 14, 14, 0, 16, 16, 16, 0, 8, 8, 8, 0, 3, 3, 3, 0, 15, 15, 15, 0, 16, 16, 16, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 17, 17, 17, 0, 17, 17, 17, 0, 16, 16, 16, 0, 2, 2, 2, 0, 12, 12, 12, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 17, 17, 17, 0, 13, 13, 13, 0, 11, 11, 11, 0, 12, 12, 12, 0, 6, 6, 6, 0, 12, 12, 12, 0, 12, 12, 12, 0, 17, 17, 17, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 17, 17, 17, 0, 15, 15, 15, 0, 13, 13, 13, 0, 13, 13, 13, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 15, 15, 15, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 11, 11, 11, 0, 14, 14, 14, 0, 18, 18, 18, 0, 14, 14, 14, 0, 11, 11, 11, 0, 9, 9, 9, 0, 10, 10, 10, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 12, 12, 12, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 16, 16, 16, 0, 18, 18, 18, 0, 15, 15, 15, 0, 11, 11, 11, 0, 10, 10, 10, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 11, 11, 11, 0, 12, 12, 12, 0, 12, 12, 12, 0, 14, 14, 14, 0, 5, 5, 5, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 11, 11, 11, 0, 17, 17, 17, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 13, 13, 13, 0, 13, 13, 13, 0, 16, 16, 16, 0, 3, 3, 3, 0, 14, 14, 14, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 11, 11, 11, 0, 20, 20, 20, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 15, 15, 15, 0, 13, 13, 13, 0, 12, 12, 12, 0, 13, 13, 13, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 17, 17, 17, 0, 17, 17, 17, 0, 13, 13, 13, 0, 18, 18, 18, 0, 14, 14, 14, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 12, 12, 12, 0, 16, 16, 16, 0, 8, 8, 8, 0, 19, 19, 19, 0, 5, 5, 5, 0, 5, 5, 5, 0, 17, 17, 17, 0, 4, 4, 4, 0, 13, 13, 13, 0, 12, 12, 12, 0, 11, 11, 11, 0, 12, 12, 12, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 14, 14, 14, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 11, 11, 11, 0, 12, 12, 12, 0, 13, 13, 13, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 14, 14, 14, 0, 12, 12, 12, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 14, 14, 14, 0, 10, 10, 10, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 15, 15, 15, 0, 21, 21, 21, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 10, 10, 10, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 9, 9, 9, 0, 7, 7, 7, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 13, 13, 13, 0, 6, 6, 6, 0, 7, 7, 7, 0, 10, 10, 10, 0, 4, 4, 4, 0, 13, 13, 13, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 7, 7, 7, 0, 17, 17, 17, 0, 20, 20, 20, 0, 15, 15, 15, 0, 16, 16, 16, 0, 19, 19, 19, 0, 12, 12, 12, 0, 9, 9, 9, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 10, 10, 10, 0, 11, 11, 11, 0, 13, 13, 13, 0, 7, 7, 7, 0, 13, 13, 13, 0, 13, 13, 13, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 11, 11, 11, 0, 9, 9, 9, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 13, 13, 13, 0, 21, 21, 21, 0, 15, 15, 15, 0, 12, 12, 12, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 4, 4, 4, 0, 11, 11, 11, 0, 10, 10, 10, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 10, 10, 10, 0, 12, 12, 12, 0, 17, 17, 17, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 10, 10, 10, 0, 16, 16, 16, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 13, 13, 13, 0, 9, 9, 9, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 14, 14, 14, 0, 12, 12, 12, 0, 10, 10, 10, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 9, 9, 9, 0, 11, 11, 11, 0, 14, 14, 14, 0, 13, 13, 13, 0, 11, 11, 11, 0, 9, 9, 9, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 10, 10, 10, 0, 10, 10, 10, 0, 15, 15, 15, 0, 14, 14, 14, 0, 14, 14, 14, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 11, 11, 11, 0, 11, 11, 11, 0, 13, 13, 13, 0, 11, 11, 11, 0, 10, 10, 10, 0, 10, 10, 10, 0, 12, 12, 12, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 15, 15, 15, 0, 0, 0, 0, 0, 18, 18, 18, 0, 11, 11, 11, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 9, 9, 9, 0, 13, 13, 13, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 6, 6, 6, 0, 7, 7, 7, 0, 7, 7, 7, 0, 9, 9, 9, 0, 11, 11, 11, 0, 11, 11, 11, 0, 11, 11, 11, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 17, 17, 17, 0, 13, 13, 13, 0, 7, 7, 7, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 8, 8, 8, 0, 8, 8, 8, 0, 10, 10, 10, 0, 16, 16, 16, 0, 10, 10, 10, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 8, 8, 8, 0, 14, 14, 14, 0, 8, 8, 8, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 6, 6, 6, 0, 9, 9, 9, 0, 12, 12, 12, 0, 14, 14, 14, 0, 12, 12, 12, 0, 9, 9, 9, 0, 8, 8, 8, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 7, 7, 7, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 8, 8, 8, 0, 7, 7, 7, 0, 8, 8, 8, 0, 9, 9, 9, 0, 8, 8, 8, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 7, 7, 7, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 4, 4, 4, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0]"; diff --git a/js/src/jit-test/lib/orTestHelper.js b/js/src/jit-test/lib/orTestHelper.js new file mode 100644 index 0000000..855aef8 --- /dev/null +++ b/js/src/jit-test/lib/orTestHelper.js @@ -0,0 +1,9 @@ +function orTestHelper(a, b, n) +{ + var k = 0; + for (var i = 0; i < n; i++) { + if (a || b) + k += i; + } + return k; +} diff --git a/js/src/jit-test/lib/prolog.js b/js/src/jit-test/lib/prolog.js new file mode 100644 index 0000000..5d577b3 --- /dev/null +++ b/js/src/jit-test/lib/prolog.js @@ -0,0 +1,48 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +const HAVE_TM = 'tracemonkey' in this; + +const HOTLOOP = HAVE_TM ? tracemonkey.HOTLOOP : 8; +const RECORDLOOP = HOTLOOP; +const RUNLOOP = HOTLOOP + 1; + +var checkStats; +if (HAVE_TM) { + checkStats = function(stats) + { + // Temporarily disabled while we work on heuristics. + return; + function jit(on) + { + if (on && !options().match(/tracejit/)) + { + options('tracejit'); + } + else if (!on && options().match(/tracejit/)) + { + options('tracejit'); + } + } + + jit(false); + for (var name in stats) { + var expected = stats[name]; + var actual = tracemonkey[name]; + if (expected != actual) { + print('Trace stats check failed: got ' + actual + ', expected ' + expected + ' for ' + name); + } + } + jit(true); + }; +} else { + checkStats = function() {}; +} + +var appendToActual = function(s) { + actual += s + ','; +} + +if (!("gczeal" in this)) { + gczeal = function() { } +} + diff --git a/js/src/jit-test/lib/range.js b/js/src/jit-test/lib/range.js new file mode 100644 index 0000000..067575b --- /dev/null +++ b/js/src/jit-test/lib/range.js @@ -0,0 +1,18 @@ +// Library file for tests to load. + +function Range(start, stop) { + this.i = start; + this.stop = stop; +} +Range.prototype = { + __iterator__: function() this, + next: function() { + if (this.i >= this.stop) + throw StopIteration; + return this.i++; + } +}; + +function range(start, stop) { + return new Range(start, stop); +} diff --git a/js/src/jit-test/progressbar.py b/js/src/jit-test/progressbar.py new file mode 100644 index 0000000..12aa000 --- /dev/null +++ b/js/src/jit-test/progressbar.py @@ -0,0 +1,35 @@ +# Text progress bar library, like curl or scp. + +import sys, datetime + +class ProgressBar: + def __init__(self, label, limit, label_width=12): + self.label = label + self.limit = limit + self.label_width = label_width + self.cur = 0 + self.t0 = datetime.datetime.now() + + self.barlen = 64 - self.label_width + self.fmt = '\r%-' + str(label_width) + 's %3d%% %-' + str(self.barlen) + 's| %6.1fs' + + def update(self, value): + self.cur = value + pct = int(100.0 * self.cur / self.limit) + barlen = int(1.0 * self.barlen * self.cur / self.limit) - 1 + bar = '='*barlen + '>' + dt = datetime.datetime.now() - self.t0 + dt = dt.seconds + dt.microseconds * 1e-6 + sys.stdout.write(self.fmt%(self.label[:self.label_width], pct, bar, dt)) + sys.stdout.flush() + + def finish(self): + self.update(self.limit) + sys.stdout.write('\n') + +if __name__ == '__main__': + pb = ProgressBar('test', 12) + for i in range(12): + pb.update(i) + time.sleep(0.5) + pb.finish() diff --git a/js/src/jit-test/tests/arguments/args-createontrace.js b/js/src/jit-test/tests/arguments/args-createontrace.js new file mode 100644 index 0000000..9f9f0a4 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args-createontrace.js @@ -0,0 +1,18 @@ +actual = ''; +expected = '5,4,3,2,1,X,5,4,3,2,1,Y,5,4,3,2,1,'; + +function f() { + for (var i = 0; i < 5; ++i) { + var args = arguments; + appendToActual(args[i]); + } +} + +f(5, 4, 3, 2, 1); +appendToActual("X"); +f(5, 4, 3, 2, 1); +appendToActual("Y"); +f(5, 4, 3, 2, 1); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args-mochi-2.js b/js/src/jit-test/tests/arguments/args-mochi-2.js new file mode 100644 index 0000000..4fec2dd --- /dev/null +++ b/js/src/jit-test/tests/arguments/args-mochi-2.js @@ -0,0 +1,23 @@ +actual = ''; +expected = 'true,'; + +var isNotEmpty = function (args, i) { + var o = args[i]; + if (!(o && o.length)) { + return false; + } + return true; +}; + +var f = function(obj) { + for (var i = 0; i < arguments.length; i++) { + if (!isNotEmpty(arguments, i)) + return false; + } + return true; +} + +appendToActual(f([1], [1], [1], "asdf", [1])); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args-mochi-2a.js b/js/src/jit-test/tests/arguments/args-mochi-2a.js new file mode 100644 index 0000000..5c8895b --- /dev/null +++ b/js/src/jit-test/tests/arguments/args-mochi-2a.js @@ -0,0 +1,23 @@ +actual = ''; +expected = 'true,'; + +function isNotEmpty(args, i) { + var o = args[i]; + if (!(o && o.length)) { + return false; + } + return true; +}; + +function f(obj) { + for (var i = 0; i < arguments.length; i++) { + if (!isNotEmpty(arguments, i)) + return false; + } + return true; +} + +appendToActual(f([1], [1], [1], "asdf", [1])); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args-mochi.js b/js/src/jit-test/tests/arguments/args-mochi.js new file mode 100644 index 0000000..c477ef0 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args-mochi.js @@ -0,0 +1,17 @@ +actual = ''; +expected = 'true,'; + +var isNotEmpty = function (obj) { + for (var i = 0; i < arguments.length; i++) { + var o = arguments[i]; + if (!(o && o.length)) { + return false; + } + } + return true; +}; + +appendToActual(isNotEmpty([1], [1], [1], "asdf", [1])); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args-mutate-length-1.js b/js/src/jit-test/tests/arguments/args-mutate-length-1.js new file mode 100644 index 0000000..cea55bc --- /dev/null +++ b/js/src/jit-test/tests/arguments/args-mutate-length-1.js @@ -0,0 +1,16 @@ +actual = ''; +expected = '0,0,0,'; + +function f() { + arguments.length--; + for (var i = 0; i < arguments.length; ++i) { + appendToActual(i); + } +} + +f(1, 2); +f(1, 2); +f(2, 2); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args-mutate-length-2.js b/js/src/jit-test/tests/arguments/args-mutate-length-2.js new file mode 100644 index 0000000..1db881b --- /dev/null +++ b/js/src/jit-test/tests/arguments/args-mutate-length-2.js @@ -0,0 +1,15 @@ +actual = ''; +expected = '0,1,0,1,0,1,'; + +function f() { + for (var i = 0; i < arguments.length; ++i) { + appendToActual(i); + } +} + +f(1, 2); +f(1, 2); +f(2, 2); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args-range-2.js b/js/src/jit-test/tests/arguments/args-range-2.js new file mode 100644 index 0000000..393d574 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args-range-2.js @@ -0,0 +1,37 @@ +actual = ''; +expected = "undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,"; + +var index; + +function h() { + for (var i = 0; i < 5; ++i) { + var a = arguments; + appendToActual(a[index]); + } +} + +index = 0; +h(); +index = -1; +h(); +index = 1; +h(); + +index = -9999999; +h(1, 2, 3); +index = -1; +h(1, 2, 3); +index = 0; +h(1, 2, 3); +index = 1; +h(1, 2, 3); +index = 2; +h(1, 2, 3); +index = 3; +h(1, 2, 3); +index = 4; +h(1, 2, 3); +index = 9999999; +h(1, 2, 3); + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args-range-const.js b/js/src/jit-test/tests/arguments/args-range-const.js new file mode 100644 index 0000000..d4a9193 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args-range-const.js @@ -0,0 +1,14 @@ +actual = ''; +expected = 'undefined,undefined,undefined,undefined,undefined,'; + +function h() { + for (var i = 0; i < 5; ++i) { + var a = arguments; + appendToActual(a[100]); + } +} + +h(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args-range.js b/js/src/jit-test/tests/arguments/args-range.js new file mode 100644 index 0000000..a5e40ac --- /dev/null +++ b/js/src/jit-test/tests/arguments/args-range.js @@ -0,0 +1,18 @@ +actual = ''; +expected = '0,0,0,0,0,88,88,88,88,88,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,'; + +function h(k) { + for (var i = 0; i < 5; ++i) { + var a = arguments; + appendToActual(a[k]); + } +} + +h(0); +h(2, 99, 88, 77); +h(-5); +h(46); +h('adf'); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args-redefine-length-1.js b/js/src/jit-test/tests/arguments/args-redefine-length-1.js new file mode 100644 index 0000000..c71c97b --- /dev/null +++ b/js/src/jit-test/tests/arguments/args-redefine-length-1.js @@ -0,0 +1,7 @@ +function t() +{ + Object.defineProperty(arguments, "length", { value: 17 }); + for (var i = 0; i < 5; i++) + assertEq(arguments.length, 17); +} +t(); diff --git a/js/src/jit-test/tests/arguments/args-redefine-length-2.js b/js/src/jit-test/tests/arguments/args-redefine-length-2.js new file mode 100644 index 0000000..fe1c9cf --- /dev/null +++ b/js/src/jit-test/tests/arguments/args-redefine-length-2.js @@ -0,0 +1,8 @@ +function t() +{ + var a = arguments; + Object.defineProperty(a, "length", { value: 17 }); + for (var i = 0; i < 5; i++) + assertEq(a.length, 17); +} +t(); diff --git a/js/src/jit-test/tests/arguments/args-sum.js b/js/src/jit-test/tests/arguments/args-sum.js new file mode 100644 index 0000000..04946e0 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args-sum.js @@ -0,0 +1,16 @@ +actual = ''; +expected = '666,'; + +function h() { + var ans = 0; + for (var i = 0; i < arguments.length; ++i) { + ans += arguments[i]; + } + return ans; +} + +var q = h(600, 60, 6); +appendToActual(q); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args-vargc.js b/js/src/jit-test/tests/arguments/args-vargc.js new file mode 100644 index 0000000..615323c --- /dev/null +++ b/js/src/jit-test/tests/arguments/args-vargc.js @@ -0,0 +1,18 @@ +actual = ''; +expected = '1 2,1 2,1 2,1 2,1 2,1 2,1 2,1 2,1 undefined,1 undefined,1 undefined,1 undefined,1 undefined,1 undefined,1 undefined,1 undefined,'; + +function g(a, b) { + appendToActual(a + ' ' + b); +} + +function f() { + for (var i = 0; i < 8; ++i) { + g.apply(this, arguments); + } +} + +f(1, 2); +f(1); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args1.js b/js/src/jit-test/tests/arguments/args1.js new file mode 100644 index 0000000..3efc299 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args1.js @@ -0,0 +1,15 @@ +actual = ''; +expected = 'a,'; + +function f() { + arguments; +} + +for (var i = 0; i < 1000; ++i) { + f(1, 2); +} + +appendToActual('a') + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args10.js b/js/src/jit-test/tests/arguments/args10.js new file mode 100644 index 0000000..8c9e6fb --- /dev/null +++ b/js/src/jit-test/tests/arguments/args10.js @@ -0,0 +1,16 @@ +actual = ''; +expected = 'function h(x, y) {\n return arguments;\n},2,4,8,'; + +function h(x, y) { return arguments; } + +var p; +for (var i = 0; i < 5; ++i) { + p = h(i, i*2); +} +appendToActual(p.callee); +appendToActual(p.length); +appendToActual(p[0]); +appendToActual(p[1]); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args11.js b/js/src/jit-test/tests/arguments/args11.js new file mode 100644 index 0000000..13e5893 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args11.js @@ -0,0 +1,14 @@ +actual = ''; +expected = 'true,true,true,true,true,'; + +function h() { + var a = arguments; + for (var i = 0; i < 5; ++i) { + appendToActual(a == arguments); + } +} + +h(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args2.js b/js/src/jit-test/tests/arguments/args2.js new file mode 100644 index 0000000..2c19c31 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args2.js @@ -0,0 +1,20 @@ +actual = ''; +expected = '151,'; + +var g = 0; + +function add(a, b) { + g = a + b; +} + +function f() { + add.apply(this, arguments); +} + +for (var i = 0; i < 5; ++i) { + f(100, 51); +} +appendToActual(g); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args2a.js b/js/src/jit-test/tests/arguments/args2a.js new file mode 100644 index 0000000..627aef0 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args2a.js @@ -0,0 +1,17 @@ +actual = ''; +expected = 'g,g,g,g,g,'; + +function g() { + appendToActual('g'); +} + +function f() { + g.apply(this, arguments); +} + +for (var i = 0; i < 5; ++i) { + f(); +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args2b.js b/js/src/jit-test/tests/arguments/args2b.js new file mode 100644 index 0000000..aa47786 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args2b.js @@ -0,0 +1,17 @@ +actual = ''; +expected = 'g 0,g 1,g 2,g 3,g 4,'; + +function g(x) { + appendToActual('g ' + x); +} + +function f() { + g.apply(this, arguments); +} + +for (var i = 0; i < 5; ++i) { + f(i); +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args2c.js b/js/src/jit-test/tests/arguments/args2c.js new file mode 100644 index 0000000..9e83a42 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args2c.js @@ -0,0 +1,19 @@ +actual = ''; +expected = 'g 0 0,g 1 2,g 2 4,g 3 6,g 4 8,'; + +function g(x, y) { + appendToActual('g ' + x + ' ' + y); + //appendToActual('g ' + x + ' ' + y); + //appendToActual('g ' + y); +} + +function f() { + g.apply(this, arguments); +} + +for (var i = 0; i < 5; ++i) { + f(i, i*2); +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args2d.js b/js/src/jit-test/tests/arguments/args2d.js new file mode 100644 index 0000000..a95c821 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args2d.js @@ -0,0 +1,17 @@ +actual = ''; +expected = 'g 0 0 0,g 1 2 1,g 2 4 4,g 3 6 9,g 4 8 16,'; + +function g(x, y, z) { + appendToActual('g ' + x + ' ' + y + ' ' + z); +} + +function f() { + g.apply(this, arguments); +} + +for (var i = 0; i < 5; ++i) { + f(i, i*2, i*i); +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args3.js b/js/src/jit-test/tests/arguments/args3.js new file mode 100644 index 0000000..7098521 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args3.js @@ -0,0 +1,20 @@ +actual = ''; +expected = '51,'; + +var g = 0; + +function add(a, b) { + g = a + b; +} + +function f() { + g = arguments[1]; +} + +for (var i = 0; i < 10000; ++i) { + f(100, 51); +} +appendToActual(g); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args4.js b/js/src/jit-test/tests/arguments/args4.js new file mode 100644 index 0000000..bd13c88 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args4.js @@ -0,0 +1,21 @@ +actual = ''; +expected = '51,'; + +var g = 0; + +function h(args) { + g = args[1]; +} + +function f() { + h(arguments); +} + +for (var i = 0; i < 10000; ++i) { + f(100, 51); +} + +appendToActual(g); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args5.js b/js/src/jit-test/tests/arguments/args5.js new file mode 100644 index 0000000..8bd1c1c --- /dev/null +++ b/js/src/jit-test/tests/arguments/args5.js @@ -0,0 +1,24 @@ +actual = ''; +expected = '150,'; + +var g = 0; + +function h(args) { + var ans = 0; + for (var i = 0; i < 5; ++i) { + ans += args[i]; + } + g = ans; +} + +function f() { + h(arguments); +} + +for (var i = 0; i < 5; ++i) { + f(10, 20, 30, 40, 50); +} +appendToActual(g); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args6.js b/js/src/jit-test/tests/arguments/args6.js new file mode 100644 index 0000000..a2fc60d --- /dev/null +++ b/js/src/jit-test/tests/arguments/args6.js @@ -0,0 +1,22 @@ +actual = ''; +expected = '6,'; + +// tracing length + +var g = 0; + +function h(args) { + g = args.length; +} + +function f() { + h(arguments); +} + +for (var i = 0; i < 5; ++i) { + f(10, 20, 30, 40, 50, 60); +} +appendToActual(g); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args6a.js b/js/src/jit-test/tests/arguments/args6a.js new file mode 100644 index 0000000..ce5206d --- /dev/null +++ b/js/src/jit-test/tests/arguments/args6a.js @@ -0,0 +1,23 @@ +actual = ''; +expected = '5,'; + +// tracing length + +var g = 0; + +function h(args) { + for (var i = 0; i < 6; ++i) + g = args.length; +} + +function f() { + h(arguments); +} + +for (var i = 0; i < 5; ++i) { + f(10, 20, 30, 40, 50); +} +appendToActual(g); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args7.js b/js/src/jit-test/tests/arguments/args7.js new file mode 100644 index 0000000..5d713e8 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args7.js @@ -0,0 +1,14 @@ +actual = ''; +expected = '5,4,3,2,1,'; + +function f() { + while (arguments.length > 0) { + appendToActual(arguments[arguments.length-1]); + arguments.length--; + } +} + +f(1, 2, 3, 4, 5); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args8.js b/js/src/jit-test/tests/arguments/args8.js new file mode 100644 index 0000000..57938d9 --- /dev/null +++ b/js/src/jit-test/tests/arguments/args8.js @@ -0,0 +1,14 @@ +actual = ''; +expected = '[object Arguments],[object Arguments],[object Arguments],[object Arguments],[object Arguments],'; + +function h() { + return arguments; +} + +for (var i = 0; i < 5; ++i) { + var p = h(i, i*2); + appendToActual(p); +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/args9.js b/js/src/jit-test/tests/arguments/args9.js new file mode 100644 index 0000000..79a54df --- /dev/null +++ b/js/src/jit-test/tests/arguments/args9.js @@ -0,0 +1,16 @@ +actual = ''; +expected = '10,20,'; + +function h() { + var p; + for (var i = 0; i < 5; ++i) { + p = arguments; + } + appendToActual(p[0]); + appendToActual(p[1]); +} + +h(10, 20); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/argsub.js b/js/src/jit-test/tests/arguments/argsub.js new file mode 100644 index 0000000..e52992c --- /dev/null +++ b/js/src/jit-test/tests/arguments/argsub.js @@ -0,0 +1,13 @@ +actual = ''; +expected = 'undefined,undefined,undefined,undefined,undefined,'; + +function h() { + for (var i = 0; i < 5; ++i) { + appendToActual(arguments[100]); + } +} + +h(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/argsx-1.js b/js/src/jit-test/tests/arguments/argsx-1.js new file mode 100644 index 0000000..9b33373 --- /dev/null +++ b/js/src/jit-test/tests/arguments/argsx-1.js @@ -0,0 +1,22 @@ +actual = ''; +expected = 'function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,1,2,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,1,2,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,1,2,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,1,2,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,1,2,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,1,2,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,1,2,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,1,2,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,1,2,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,1,2,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,[object Object],a,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,[object Object],a,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,[object Object],a,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,[object Object],a,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,[object Object],a,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,[object Object],a,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,[object Object],a,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,[object Object],a,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,[object Object],a,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,[object Object],a,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,abc,def,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,abc,def,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,abc,def,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,abc,def,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,abc,def,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,abc,def,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,abc,def,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,abc,def,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,abc,def,function f() {\n var a = arguments;\n for (var i = 0; i < 10; ++i) {\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},2,abc,def,'; + +// args object created by interpreter + +function f() { + var a = arguments; + + for (var i = 0; i < 10; ++i) { + appendToActual(a.callee); + appendToActual(a.length); + appendToActual(a[0]); + appendToActual(a[1]); + } +} + +f(1, 2, 3); +f({}, 'a'); +f('abc', 'def'); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/argsx-2.js b/js/src/jit-test/tests/arguments/argsx-2.js new file mode 100644 index 0000000..3014702 --- /dev/null +++ b/js/src/jit-test/tests/arguments/argsx-2.js @@ -0,0 +1,23 @@ +actual = ''; +expected = 'function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},3,1,2,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},3,1,2,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},3,1,2,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},3,1,2,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},3,1,2,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},3,1,2,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},3,1,2,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},3,1,2,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},3,1,2,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},3,1,2,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,[object Object],a,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,[object Object],a,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,[object Object],a,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,[object Object],a,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,[object Object],a,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,[object Object],a,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,[object Object],a,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,[object Object],a,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,[object Object],a,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,[object Object],a,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,abc,def,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,abc,def,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,abc,def,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,abc,def,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,abc,def,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,abc,def,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,abc,def,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,abc,def,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,abc,def,function f() {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n},2,abc,def,'; + +// args object created on trace + +function f() { + var a = arguments; + + appendToActual(a.callee); + appendToActual(a.length); + appendToActual(a[0]); + appendToActual(a[1]); +} + +for (var i = 0; i < 10; ++i) + f(1, 2, 3); +for (var i = 0; i < 10; ++i) + f({}, 'a'); +for (var i = 0; i < 10; ++i) + f('abc', 'def'); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/argsx-3.js b/js/src/jit-test/tests/arguments/argsx-3.js new file mode 100644 index 0000000..ce3ea5c --- /dev/null +++ b/js/src/jit-test/tests/arguments/argsx-3.js @@ -0,0 +1,27 @@ +actual = ''; +expected = 'true,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,false,abc,'; + +// args object created by interpreter at record time, but not always at run time. + +function f(t) { + if (t) { + var b = arguments; + appendToActual(b[0]); + } + + for (var i = 0; i < 10; ++i) { + var a = arguments; + appendToActual(a.callee); + appendToActual(a.length); + appendToActual(a[0]); + appendToActual(a[1]); + } +} + +f(true, 1, 2, 3); +f(false, 1, 2, 3); +f(false, {}, 'a'); +f(false, 'abc', 'def'); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/argsx-3a.js b/js/src/jit-test/tests/arguments/argsx-3a.js new file mode 100644 index 0000000..c9b0f49 --- /dev/null +++ b/js/src/jit-test/tests/arguments/argsx-3a.js @@ -0,0 +1,27 @@ +actual = ''; +expected = 'function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,false,1,true,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},4,true,1,true,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,[object Object],function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,[object Object],true,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,abc,function f(t) {\n if (t) {\n var b = arguments;\n appendToActual(b[0]);\n }\n for (var i = 0; i < 10; ++i) {\n var a = arguments;\n appendToActual(a.callee);\n appendToActual(a.length);\n appendToActual(a[0]);\n appendToActual(a[1]);\n }\n},3,true,abc,'; + +// args object not created by interpreter at record time, but maybe at run time + +function f(t) { + if (t) { + var b = arguments; + appendToActual(b[0]); + } + + for (var i = 0; i < 10; ++i) { + var a = arguments; + appendToActual(a.callee); + appendToActual(a.length); + appendToActual(a[0]); + appendToActual(a[1]); + } +} + +f(false, 1, 2, 3); +f(true, 1, 2, 3); +f(true, {}, 'a'); +f(true, 'abc', 'def'); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/argsx-4.js b/js/src/jit-test/tests/arguments/argsx-4.js new file mode 100644 index 0000000..b52b148 --- /dev/null +++ b/js/src/jit-test/tests/arguments/argsx-4.js @@ -0,0 +1,23 @@ +actual = ''; +expected = '[object Arguments] undefined undefined,[object Arguments] undefined undefined,'; + +function f() { + g(arguments); +} + +function g(a, b, c) { + h(arguments); + a = 1; + b = 2; + c = 3; + h(arguments); +} + +function h(a, b, c) { + appendToActual(a + ' ' + b + ' ' + c); +} + +f(4, 5, 6); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/bug503772.js b/js/src/jit-test/tests/arguments/bug503772.js new file mode 100644 index 0000000..6ef8e1f --- /dev/null +++ b/js/src/jit-test/tests/arguments/bug503772.js @@ -0,0 +1,16 @@ +function f(a) { + // Create arguments on trace + var z = arguments; + // Make f need a call object + if (false) { + var p = function() { ++a; } + } +} + +function g() { + for (var i = 0; i < 5; ++i) { + f(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); + } +} + +g(); diff --git a/js/src/jit-test/tests/arguments/bug508178.js b/js/src/jit-test/tests/arguments/bug508178.js new file mode 100644 index 0000000..c779c82 --- /dev/null +++ b/js/src/jit-test/tests/arguments/bug508178.js @@ -0,0 +1,18 @@ +actual = ''; +expected = 'g,g,g,g,f,'; + +function test() { + var testargs = arguments; + var f = function (name, which) { + var args = [testargs, arguments]; + return args[which][0]; + }; + var arr = [0, 0, 0, 0, 1]; + for (var i = 0; i < arr.length; i++) + arr[i] = f("f", arr[i]); + appendToActual(arr); +} +test('g'); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/arguments/bug554670-1.js b/js/src/jit-test/tests/arguments/bug554670-1.js new file mode 100644 index 0000000..75606c3 --- /dev/null +++ b/js/src/jit-test/tests/arguments/bug554670-1.js @@ -0,0 +1,8 @@ +x = true; +(function() { + for each(let c in [0, x]) { + (arguments)[4] *= c + } +})() + +// don't assert diff --git a/js/src/jit-test/tests/arguments/bug554670-2.js b/js/src/jit-test/tests/arguments/bug554670-2.js new file mode 100644 index 0000000..6aeba78 --- /dev/null +++ b/js/src/jit-test/tests/arguments/bug554670-2.js @@ -0,0 +1,8 @@ +var c; +(function() { + for each(e in [0, 0]) { + (arguments)[1] *= c + } +})() + +// don't assert diff --git a/js/src/jit-test/tests/arguments/bug633020.js b/js/src/jit-test/tests/arguments/bug633020.js new file mode 100644 index 0000000..5f9c18c --- /dev/null +++ b/js/src/jit-test/tests/arguments/bug633020.js @@ -0,0 +1,11 @@ +var N = HOTLOOP + 2; +function f(b) { + var a = []; + for (var i = 0; i < N; i++) + a[i] = {}; + a[N-1] = arguments; + for (var i = 0; i < N; i++) + a[i][0] = i; + assertEq(b, N - 1); +} +f(null); diff --git a/js/src/jit-test/tests/arguments/nonstrict-args.js b/js/src/jit-test/tests/arguments/nonstrict-args.js new file mode 100644 index 0000000..750bcc1 --- /dev/null +++ b/js/src/jit-test/tests/arguments/nonstrict-args.js @@ -0,0 +1,24 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function args(a) { return arguments; } + +var a1, a2, a3, a4; + +for (var i = 0; i < 5; i++) +{ + a1 = args(); + a2 = args(1); + a3 = args(1, obj); + a4 = args("foopy"); +} + +assertEq(arraysEqual(a1, []), true); +assertEq(arraysEqual(a2, [1]), true); +assertEq(arraysEqual(a3, [1, obj]), true); +assertEq(arraysEqual(a4, ["foopy"]), true); diff --git a/js/src/jit-test/tests/arguments/nonstrict-assign-element-get-parameter.js b/js/src/jit-test/tests/arguments/nonstrict-assign-element-get-parameter.js new file mode 100644 index 0000000..c55588d --- /dev/null +++ b/js/src/jit-test/tests/arguments/nonstrict-assign-element-get-parameter.js @@ -0,0 +1,13 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +function assignElementGetParameter(a) +{ + arguments[0] = 17; + return a; +} + +for (var i = 0; i < 5; i++) + assertEq(assignElementGetParameter(42), 17); diff --git a/js/src/jit-test/tests/arguments/nonstrict-assign-parameter-get-element.js b/js/src/jit-test/tests/arguments/nonstrict-assign-parameter-get-element.js new file mode 100644 index 0000000..747abba --- /dev/null +++ b/js/src/jit-test/tests/arguments/nonstrict-assign-parameter-get-element.js @@ -0,0 +1,13 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +function assignParameterGetElement(a) +{ + a = 17; + return arguments[0]; +} + +for (var i = 0; i < 5; i++) + assertEq(assignParameterGetElement(42), 17); diff --git a/js/src/jit-test/tests/arguments/nonstrict-assign.js b/js/src/jit-test/tests/arguments/nonstrict-assign.js new file mode 100644 index 0000000..8dd75e7 --- /dev/null +++ b/js/src/jit-test/tests/arguments/nonstrict-assign.js @@ -0,0 +1,17 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +function assign(a) +{ + a = 17; + return arguments; +} + +var a1; +for (var i = 0; i < 5; i++) + a1 = assign(1); + +assertEq(arraysEqual(a1, [17]), true); diff --git a/js/src/jit-test/tests/arguments/nonstrict-later-assign.js b/js/src/jit-test/tests/arguments/nonstrict-later-assign.js new file mode 100644 index 0000000..fbf72ab --- /dev/null +++ b/js/src/jit-test/tests/arguments/nonstrict-later-assign.js @@ -0,0 +1,18 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +function getLaterAssign(a) +{ + var o = arguments; + a = 17; + return o; +} + +var a1, a2; +for (var i = 0; i < 5; i++) + a1 = getLaterAssign(1); + +assertEq(arraysEqual(a1, [17]), true); diff --git a/js/src/jit-test/tests/arguments/nonstrict-noargs.js b/js/src/jit-test/tests/arguments/nonstrict-noargs.js new file mode 100644 index 0000000..ef1bca7 --- /dev/null +++ b/js/src/jit-test/tests/arguments/nonstrict-noargs.js @@ -0,0 +1,21 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function noargs() { return arguments; } + +var a1, a2, a3; +for (var i = 0; i < 5; i++) +{ + a1 = noargs(); + a2 = noargs(1); + a3 = noargs(2, obj, 8); +} + +assertEq(arraysEqual(a1, []), true); +assertEq(arraysEqual(a2, [1]), true); +assertEq(arraysEqual(a3, [2, obj, 8]), true); diff --git a/js/src/jit-test/tests/arguments/strict-args-flushstack.js b/js/src/jit-test/tests/arguments/strict-args-flushstack.js new file mode 100644 index 0000000..b6094d4 --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-args-flushstack.js @@ -0,0 +1,27 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +var args; + +function test() +{ + "use strict"; + eval("args = arguments;"); + var a = []; + for (var i = 0; i < RUNLOOP; i++) + a.push(arguments); + return a; +} + +var a = test(); + +assertEq(Array.isArray(a), true); +assertEq(a.length, RUNLOOP); + +var count = 0; +a.forEach(function(v, i) { count++; assertEq(v, args); }); +assertEq(count, RUNLOOP); + +assertEq(Object.prototype.toString.call(args), "[object Arguments]"); +assertEq(args.length, 0); diff --git a/js/src/jit-test/tests/arguments/strict-args-generator-flushstack.js b/js/src/jit-test/tests/arguments/strict-args-generator-flushstack.js new file mode 100644 index 0000000..ea75467 --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-args-generator-flushstack.js @@ -0,0 +1,27 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +var args; + +function upToTen() +{ + "use strict"; + eval("args = arguments;"); + for (var i = 0; i < RUNLOOP; i++) + yield i; +} + +var gen = upToTen(); + +var i = 0; +for (var v in gen) +{ + assertEq(v, i); + i++; +} + +assertEq(i, RUNLOOP); + +assertEq(Object.prototype.toString.call(args), "[object Arguments]"); +assertEq(args.length, 0); diff --git a/js/src/jit-test/tests/arguments/strict-args.js b/js/src/jit-test/tests/arguments/strict-args.js new file mode 100644 index 0000000..82682ff --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-args.js @@ -0,0 +1,25 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function strictArgs(a) +{ + "use strict"; + return arguments; +} + +var a1, a2, a3; +for (var i = 0; i < HOTLOOP+1; i++) +{ + a1 = strictArgs(); + a2 = strictArgs(1); + a3 = strictArgs(1, obj); +} + +assertEq(arraysEqual(a1, []), true); +assertEq(arraysEqual(a2, [1]), true); +assertEq(arraysEqual(a3, [1, obj]), true); diff --git a/js/src/jit-test/tests/arguments/strict-assign-after.js b/js/src/jit-test/tests/arguments/strict-assign-after.js new file mode 100644 index 0000000..b295321 --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-assign-after.js @@ -0,0 +1,28 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +var upper; +function strictAssignAfter(a) +{ + "use strict"; + upper = arguments; + a = 42; + return upper; +} + +var a1, a2, a3; +for (var i = 0; i < 5; i++) +{ + a1 = strictAssignAfter(); + a2 = strictAssignAfter(17); + a3 = strictAssignAfter(obj); +} + +assertEq(arraysEqual(a1, []), true); +assertEq(arraysEqual(a2, [17]), true); +assertEq(arraysEqual(a3, [obj]), true); diff --git a/js/src/jit-test/tests/arguments/strict-assign-arguments-element.js b/js/src/jit-test/tests/arguments/strict-assign-arguments-element.js new file mode 100644 index 0000000..d2f4f1e --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-assign-arguments-element.js @@ -0,0 +1,21 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function strictAssignArgumentsElement(a) +{ + "use strict"; + arguments[0] = 42; + return a; +} + +for (var i = 0; i < 5; i++) +{ + assertEq(strictAssignArgumentsElement(), undefined); + assertEq(strictAssignArgumentsElement(obj), obj); + assertEq(strictAssignArgumentsElement(17), 17); +} diff --git a/js/src/jit-test/tests/arguments/strict-assign-outer-param-psych.js b/js/src/jit-test/tests/arguments/strict-assign-outer-param-psych.js new file mode 100644 index 0000000..6b8fb68 --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-assign-outer-param-psych.js @@ -0,0 +1,27 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function strictAssignOuterParamPSYCH(p) +{ + "use strict"; + function inner(p) { p = 17; } + inner(); + return arguments; +} + +var a1, a2, a3; +for (var i = 0; i < 5; i++) +{ + a1 = strictAssignOuterParamPSYCH(); + a2 = strictAssignOuterParamPSYCH(17); + a3 = strictAssignOuterParamPSYCH(obj); +} + +assertEq(arraysEqual(a1, []), true); +assertEq(arraysEqual(a2, [17]), true); +assertEq(arraysEqual(a3, [obj]), true); diff --git a/js/src/jit-test/tests/arguments/strict-assign-outer-param.js b/js/src/jit-test/tests/arguments/strict-assign-outer-param.js new file mode 100644 index 0000000..f6e4f47 --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-assign-outer-param.js @@ -0,0 +1,27 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function strictAssignOuterParam(p) +{ + "use strict"; + function inner() { p = 17; } + inner(); + return arguments; +} + +var a1, a2, a3; +for (var i = 0; i < 5; i++) +{ + a1 = strictAssignOuterParam(); + a2 = strictAssignOuterParam(42); + a3 = strictAssignOuterParam(obj); +} + +assertEq(arraysEqual(a1, []), true); +assertEq(arraysEqual(a2, [42]), true); +assertEq(arraysEqual(a3, [obj]), true); diff --git a/js/src/jit-test/tests/arguments/strict-assign-parameter-get-element.js b/js/src/jit-test/tests/arguments/strict-assign-parameter-get-element.js new file mode 100644 index 0000000..ca283fb --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-assign-parameter-get-element.js @@ -0,0 +1,14 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +function strictAssignParameterGetElement(a) +{ + "use strict"; + a = 17; + return arguments[0]; +} + +for (var i = 0; i < 5; i++) + assertEq(strictAssignParameterGetElement(42), 42); diff --git a/js/src/jit-test/tests/arguments/strict-assign.js b/js/src/jit-test/tests/arguments/strict-assign.js new file mode 100644 index 0000000..6666dec --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-assign.js @@ -0,0 +1,26 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function strictAssign(a) +{ + "use strict"; + a = 17; + return arguments; +} + +var a1, a2, a3; +for (var i = 0; i < 5; i++) +{ + a1 = strictAssign(); + a2 = strictAssign(1); + a3 = strictAssign(1, obj); +} + +assertEq(arraysEqual(a1, []), true); +assertEq(arraysEqual(a2, [1]), true); +assertEq(arraysEqual(a3, [1, obj]), true); diff --git a/js/src/jit-test/tests/arguments/strict-eval-mutation.js b/js/src/jit-test/tests/arguments/strict-eval-mutation.js new file mode 100644 index 0000000..d33a05c --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-eval-mutation.js @@ -0,0 +1,24 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function strictEvalMutation(code) +{ + "use strict"; + return eval(code); +} + +var a1, a2; +for (var i = 0; i < 5; i++) +{ + a1 = strictEvalMutation("code = 17; arguments"); + a2 = strictEvalMutation("arguments[0] = 17; arguments"); + assertEq(strictEvalMutation("arguments[0] = 17; code"), "arguments[0] = 17; code"); +} + +assertEq(arraysEqual(a1, ["code = 17; arguments"]), true); +assertEq(arraysEqual(a2, [17]), true); diff --git a/js/src/jit-test/tests/arguments/strict-eval.js b/js/src/jit-test/tests/arguments/strict-eval.js new file mode 100644 index 0000000..22ffb7f --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-eval.js @@ -0,0 +1,30 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +function strictEval(code, p) +{ + "use strict"; + eval(code); + return arguments; +} + +var a1, a2, a3, a4, a5, a6; +for (var i = 0; i < 5; i++) +{ + a1 = strictEval("1", 2); + a2 = strictEval("arguments"); + a3 = strictEval("p = 2"); + a4 = strictEval("p = 2", 17); + a5 = strictEval("arguments[0] = 17"); + a6 = strictEval("arguments[0] = 17", 42); +} + +assertEq(arraysEqual(a1, ["1", 2]), true); +assertEq(arraysEqual(a2, ["arguments"]), true); +assertEq(arraysEqual(a3, ["p = 2"]), true); +assertEq(arraysEqual(a4, ["p = 2", 17]), true); +assertEq(arraysEqual(a5, [17]), true); +assertEq(arraysEqual(a6, [17, 42]), true); diff --git a/js/src/jit-test/tests/arguments/strict-maybe-assign-outer.js b/js/src/jit-test/tests/arguments/strict-maybe-assign-outer.js new file mode 100644 index 0000000..63f9f69 --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-maybe-assign-outer.js @@ -0,0 +1,26 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function strictMaybeAssignOuterParam(p) +{ + "use strict"; + function inner() { p = 17; } + return arguments; +} + +var a1, a2, a3; +for (var i = 0; i < 5; i++) +{ + a1 = strictMaybeAssignOuterParam(); + a2 = strictMaybeAssignOuterParam(17); + a3 = strictMaybeAssignOuterParam(obj); +} + +assertEq(arraysEqual(a1, []), true); +assertEq(arraysEqual(a2, [17]), true); +assertEq(arraysEqual(a3, [obj]), true); diff --git a/js/src/jit-test/tests/arguments/strict-maybe-nested-eval.js b/js/src/jit-test/tests/arguments/strict-maybe-nested-eval.js new file mode 100644 index 0000000..a1fe88f --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-maybe-nested-eval.js @@ -0,0 +1,26 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +function strictMaybeNestedEval(code, p) +{ + "use strict"; + function inner() { eval(code); } + return arguments; +} + +var a1, a2, a3, a4; +for (var i = 0; i < 5; i++) +{ + a1 = strictMaybeNestedEval("1", 2); + a2 = strictMaybeNestedEval("arguments"); + a3 = strictMaybeNestedEval("p = 2"); + a4 = strictMaybeNestedEval("p = 2", 17); +} + +assertEq(arraysEqual(a1, ["1", 2]), true); +assertEq(arraysEqual(a2, ["arguments"]), true); +assertEq(arraysEqual(a3, ["p = 2"]), true); +assertEq(arraysEqual(a4, ["p = 2", 17]), true); diff --git a/js/src/jit-test/tests/arguments/strict-nested-assign-shadow-function-call.js b/js/src/jit-test/tests/arguments/strict-nested-assign-shadow-function-call.js new file mode 100644 index 0000000..a9430e3 --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-nested-assign-shadow-function-call.js @@ -0,0 +1,33 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function strictNestedAssignShadowFunctionCall(p) +{ + "use strict"; + function inner() + { + function p() { } + p = 1776; + } + inner(); + return arguments; +} + +var a1, a2, a3, a4; +for (var i = 0; i < 5; i++) +{ + a1 = strictNestedAssignShadowFunctionCall(); + a2 = strictNestedAssignShadowFunctionCall(99); + a3 = strictNestedAssignShadowFunctionCall(""); + a4 = strictNestedAssignShadowFunctionCall(obj); +} + +assertEq(arraysEqual(a1, []), true); +assertEq(arraysEqual(a2, [99]), true); +assertEq(arraysEqual(a3, [""]), true); +assertEq(arraysEqual(a4, [obj]), true); diff --git a/js/src/jit-test/tests/arguments/strict-nested-assign-shadow-function-name.js b/js/src/jit-test/tests/arguments/strict-nested-assign-shadow-function-name.js new file mode 100644 index 0000000..e8ae317 --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-nested-assign-shadow-function-name.js @@ -0,0 +1,33 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function strictNestedAssignShadowFunctionName(p) +{ + "use strict"; + function inner() + { + function p() { p = 1776; } + p(); + } + inner(); + return arguments; +} + +var a1, a2, a3, a4, a5; +for (var i = 0; i < 5; i++) +{ + a1 = strictNestedAssignShadowFunctionName(); + a2 = strictNestedAssignShadowFunctionName(99); + a3 = strictNestedAssignShadowFunctionName(""); + a4 = strictNestedAssignShadowFunctionName(obj); +} + +assertEq(arraysEqual(a1, []), true); +assertEq(arraysEqual(a2, [99]), true); +assertEq(arraysEqual(a3, [""]), true); +assertEq(arraysEqual(a4, [obj]), true); diff --git a/js/src/jit-test/tests/arguments/strict-nested-assign-shadow-function.js b/js/src/jit-test/tests/arguments/strict-nested-assign-shadow-function.js new file mode 100644 index 0000000..46e0acf --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-nested-assign-shadow-function.js @@ -0,0 +1,32 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function strictNestedAssignShadowFunction(p) +{ + "use strict"; + function inner() + { + function p() { } + p = 1776; + } + return arguments; +} + +var a1, a2, a3, a4; +for (var i = 0; i < 5; i++) +{ + a1 = strictNestedAssignShadowFunction(); + a2 = strictNestedAssignShadowFunction(99); + a3 = strictNestedAssignShadowFunction(""); + a4 = strictNestedAssignShadowFunction(obj); +} + +assertEq(arraysEqual(a1, []), true); +assertEq(arraysEqual(a2, [99]), true); +assertEq(arraysEqual(a3, [""]), true); +assertEq(arraysEqual(a4, [obj]), true); diff --git a/js/src/jit-test/tests/arguments/strict-nested-assign-shadowed-catch-call.js b/js/src/jit-test/tests/arguments/strict-nested-assign-shadowed-catch-call.js new file mode 100644 index 0000000..03c5e02 --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-nested-assign-shadowed-catch-call.js @@ -0,0 +1,39 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function strictNestedAssignShadowCatchCall(p) +{ + "use strict"; + function inner() + { + try + { + } + catch (p) + { + var f = function innermost() { p = 1776; return 12; }; + f(); + } + } + inner(); + return arguments; +} + +var a1, a2, a3, a4; +for (var i = 0; i < 5; i++) +{ + a1 = strictNestedAssignShadowCatchCall(); + a2 = strictNestedAssignShadowCatchCall(99); + a3 = strictNestedAssignShadowCatchCall(""); + a4 = strictNestedAssignShadowCatchCall(obj); +} + +assertEq(arraysEqual(a1, []), true); +assertEq(arraysEqual(a2, [99]), true); +assertEq(arraysEqual(a3, [""]), true); +assertEq(arraysEqual(a4, [obj]), true); diff --git a/js/src/jit-test/tests/arguments/strict-nested-assign-shadowed-catch.js b/js/src/jit-test/tests/arguments/strict-nested-assign-shadowed-catch.js new file mode 100644 index 0000000..06df3f9 --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-nested-assign-shadowed-catch.js @@ -0,0 +1,39 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function strictNestedAssignShadowCatch(p) +{ + "use strict"; + function inner() + { + try + { + } + catch (p) + { + var f = function innermost() { p = 1776; return 12; }; + f(); + } + } + return arguments; +} + +var a1, a2, a3, a4; +for (var i = 0; i < 5; i++) +{ + a1 = strictNestedAssignShadowCatch(); + a2 = strictNestedAssignShadowCatch(99); + a3 = strictNestedAssignShadowCatch(""); + a4 = strictNestedAssignShadowCatch(obj); +} + +assertEq(arraysEqual(a1, []), true); +assertEq(arraysEqual(a2, [99]), true); +assertEq(arraysEqual(a3, [""]), true); +assertEq(arraysEqual(a4, [obj]), true); + diff --git a/js/src/jit-test/tests/arguments/strict-nested-assign-shadowed-var.js b/js/src/jit-test/tests/arguments/strict-nested-assign-shadowed-var.js new file mode 100644 index 0000000..8248bed --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-nested-assign-shadowed-var.js @@ -0,0 +1,29 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +/******************** + * STRICT ARGUMENTS * + ********************/ + +function strictNestedAssignShadowVar(p) +{ + "use strict"; + function inner() + { + var p = 12; + function innermost() { p = 1776; return 12; } + return innermost(); + } + return arguments; +} + +assertEq(arraysEqual(strictNestedAssignShadowVar(), []), true); +assertEq(arraysEqual(strictNestedAssignShadowVar(99), [99]), true); +assertEq(arraysEqual(strictNestedAssignShadowVar(""), [""]), true); +assertEq(arraysEqual(strictNestedAssignShadowVar(obj), [obj]), true); + diff --git a/js/src/jit-test/tests/arguments/strict-nested-eval.js b/js/src/jit-test/tests/arguments/strict-nested-eval.js new file mode 100644 index 0000000..1f6eab5 --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-nested-eval.js @@ -0,0 +1,31 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +function strictNestedEval(code, p) +{ + "use strict"; + function inner() { eval(code); } + inner(); + return arguments; +} + +var a1, a2, a3, a4, a5, a6; +for (var i = 0; i < 5; i++) +{ + a1 = strictNestedEval("1", 2); + a2 = strictNestedEval("arguments"); + a3 = strictNestedEval("p = 2"); + a4 = strictNestedEval("p = 2", 17); + a5 = strictNestedEval("arguments[0] = 17"); + a6 = strictNestedEval("arguments[0] = 17", 42); +} + +assertEq(arraysEqual(a1, ["1", 2]), true); +assertEq(arraysEqual(a2, ["arguments"]), true); +assertEq(arraysEqual(a3, ["p = 2"]), true); +assertEq(arraysEqual(a4, ["p = 2", 17]), true); +assertEq(arraysEqual(a5, ["arguments[0] = 17"]), true); +assertEq(arraysEqual(a6, ["arguments[0] = 17", 42]), true); diff --git a/js/src/jit-test/tests/arguments/strict-nested-shadow-eval.js b/js/src/jit-test/tests/arguments/strict-nested-shadow-eval.js new file mode 100644 index 0000000..d80b7be --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-nested-shadow-eval.js @@ -0,0 +1,30 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +function strictNestedShadowEval(code, p) +{ + "use strict"; + function inner(p) { eval(code); } + return arguments; +} + +var a1, a2, a3, a4, a5, a6; +for (var i = 0; i < 5; i++) +{ + a1 = strictNestedShadowEval("1", 2); + a2 = strictNestedShadowEval("arguments"); + a3 = strictNestedShadowEval("p = 2"); + a4 = strictNestedShadowEval("p = 2", 17); + a5 = strictNestedShadowEval("arguments[0] = 17"); + a6 = strictNestedShadowEval("arguments[0] = 17", 42); +} + +assertEq(arraysEqual(a1, ["1", 2]), true); +assertEq(arraysEqual(a2, ["arguments"]), true); +assertEq(arraysEqual(a3, ["p = 2"]), true); +assertEq(arraysEqual(a4, ["p = 2", 17]), true); +assertEq(arraysEqual(a5, ["arguments[0] = 17"]), true); +assertEq(arraysEqual(a6, ["arguments[0] = 17", 42]), true); diff --git a/js/src/jit-test/tests/arguments/strict-nested-shadow-maybe-eval.js b/js/src/jit-test/tests/arguments/strict-nested-shadow-maybe-eval.js new file mode 100644 index 0000000..cf9edea --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-nested-shadow-maybe-eval.js @@ -0,0 +1,30 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +function strictNestedShadowMaybeEval(code, p) +{ + "use strict"; + function inner(p) { eval(code); } + return arguments; +} + +var a1, a2, a3, a4, a5, a6; +for (var i = 0; i < 5; i++) +{ + a1 = strictNestedShadowMaybeEval("1", 2); + a2 = strictNestedShadowMaybeEval("arguments"); + a3 = strictNestedShadowMaybeEval("p = 2"); + a4 = strictNestedShadowMaybeEval("p = 2", 17); + a5 = strictNestedShadowMaybeEval("arguments[0] = 17"); + a6 = strictNestedShadowMaybeEval("arguments[0] = 17", 42); +} + +assertEq(arraysEqual(a1, ["1", 2]), true); +assertEq(arraysEqual(a2, ["arguments"]), true); +assertEq(arraysEqual(a3, ["p = 2"]), true); +assertEq(arraysEqual(a4, ["p = 2", 17]), true); +assertEq(arraysEqual(a5, ["arguments[0] = 17"]), true); +assertEq(arraysEqual(a6, ["arguments[0] = 17", 42]), true); diff --git a/js/src/jit-test/tests/arguments/strict-noargs.js b/js/src/jit-test/tests/arguments/strict-noargs.js new file mode 100644 index 0000000..dfee3c8 --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-noargs.js @@ -0,0 +1,25 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +load(libdir + 'array-compare.js'); + +var obj = {}; + +function strictNoargs() +{ + "use strict"; + return arguments; +} + +var a1, a2, a3; +for (var i = 0; i < 5; i++) +{ + a1 = strictNoargs(); + a2 = strictNoargs(1); + a3 = strictNoargs(1, obj); +} + +assertEq(arraysEqual(a1, []), true); +assertEq(arraysEqual(a2, [1]), true); +assertEq(arraysEqual(a3, [1, obj]), true); diff --git a/js/src/jit-test/tests/arguments/testDelArg1.js b/js/src/jit-test/tests/arguments/testDelArg1.js new file mode 100644 index 0000000..3603dd4 --- /dev/null +++ b/js/src/jit-test/tests/arguments/testDelArg1.js @@ -0,0 +1,13 @@ +function f(x,y,z) { + z = 9; + delete arguments[2]; + assertEq(arguments[2], undefined); + o = arguments; + assertEq(o[2], undefined); + assertEq(o[2] == undefined, true); +} + +for (var i = 0; i < HOTLOOP+2; ++i) { + print(i); + f(1,2,3) +} diff --git a/js/src/jit-test/tests/arguments/testDelArg2.js b/js/src/jit-test/tests/arguments/testDelArg2.js new file mode 100644 index 0000000..7b4bce8 --- /dev/null +++ b/js/src/jit-test/tests/arguments/testDelArg2.js @@ -0,0 +1,13 @@ +function f(del) { + o = arguments; + if (del) + delete o[2]; + for (var i = 0; i < HOTLOOP+2; ++i) + assertEq(o[2] == undefined, del); +} + +// record without arg deleted +f(false, 1,2,3,4); + +// run with arg deleted +f(true, 1,2,3,4); diff --git a/js/src/jit-test/tests/basic/FPQuadCmp.js b/js/src/jit-test/tests/basic/FPQuadCmp.js new file mode 100644 index 0000000..010228d --- /dev/null +++ b/js/src/jit-test/tests/basic/FPQuadCmp.js @@ -0,0 +1,6 @@ +function FPQuadCmp() +{ + for (let j = 0; j < 3; ++j) { true == 0; } + return "ok"; +} +assertEq(FPQuadCmp(), "ok"); diff --git a/js/src/jit-test/tests/basic/argumentsPassedToBuiltin.js b/js/src/jit-test/tests/basic/argumentsPassedToBuiltin.js new file mode 100644 index 0000000..d8edfff --- /dev/null +++ b/js/src/jit-test/tests/basic/argumentsPassedToBuiltin.js @@ -0,0 +1,14 @@ +// bug 504797 + +function f() { + g(arguments, 1); +} + +function g(a, b) { + var s = Array.prototype.slice.call(a, b); + assertEq(s[0] == undefined, false); +} + +for (var i = 0; i < 10; ++i) { + f(1, 2, 3, 4); +} diff --git a/js/src/jit-test/tests/basic/arith.js b/js/src/jit-test/tests/basic/arith.js new file mode 100644 index 0000000..b7f551d --- /dev/null +++ b/js/src/jit-test/tests/basic/arith.js @@ -0,0 +1,11 @@ +// |jit-test| TMFLAGS: full,fragprofile,treevis + +function arith() +{ + var accum = 0; + for (var i = 0; i < 100; i++) { + accum += (i * 2) - 1; + } + return accum; +} +assertEq(arith(), 9800); diff --git a/js/src/jit-test/tests/basic/arityMismatchExtraArg.js b/js/src/jit-test/tests/basic/arityMismatchExtraArg.js new file mode 100644 index 0000000..6803368 --- /dev/null +++ b/js/src/jit-test/tests/basic/arityMismatchExtraArg.js @@ -0,0 +1,13 @@ +function arityMismatchMissingArg(arg) +{ + for (var a = 0, i = 1; i < 10000; i *= 2) { + a += i; + } + return a; +} + +function arityMismatchExtraArg() +{ + return arityMismatchMissingArg(1, 2); +} +assertEq(arityMismatchExtraArg(), 16383); diff --git a/js/src/jit-test/tests/basic/arityMismatchMissingArg.js b/js/src/jit-test/tests/basic/arityMismatchMissingArg.js new file mode 100644 index 0000000..79284e9 --- /dev/null +++ b/js/src/jit-test/tests/basic/arityMismatchMissingArg.js @@ -0,0 +1,8 @@ +function arityMismatchMissingArg(arg) +{ + for (var a = 0, i = 1; i < 10000; i *= 2) { + a += i; + } + return a; +} +assertEq(arityMismatchMissingArg(), 16383); diff --git a/js/src/jit-test/tests/basic/bigLoadStoreDisp.js b/js/src/jit-test/tests/basic/bigLoadStoreDisp.js new file mode 100644 index 0000000..528ba25 --- /dev/null +++ b/js/src/jit-test/tests/basic/bigLoadStoreDisp.js @@ -0,0 +1,25 @@ +// In Nanojit, loads and stores have a maximum displacement of 16-bits. Any +// displacements larger than that should be split off into a separate +// instruction that adds the displacement to the base pointer. This +// program tests if this is done correctly. +// +// x.y ends up having a dslot offset of 79988, because of the 20000 array +// elements before it. If Nanojit incorrectly stores this offset into a +// 16-bit value it will truncate to 14452 (because 79988 - 65536 == 14452). +// This means that the increments in the second loop will be done to one of +// the array elements instead of x.y. And so x.y's final value will be +// (99 + HOTLOOP) instead of 1099. +// +// Note that setting x.y to 99 and checking its value at the end will +// access the correct location because those lines are interpreted. Phew. + +var x = {} +for (var i = 0; i < 20000; i++) + x[i] = 0; +x.y = 99; // not traced, correctly accessed + +for (var i = 0; i < 1000; ++i) { + x.y++; // traced, will access an array elem if disp was truncated +} +assertEq(x.y, 1099); // not traced, correctly accessed + diff --git a/js/src/jit-test/tests/basic/bindname-in-strict-eval.js b/js/src/jit-test/tests/basic/bindname-in-strict-eval.js new file mode 100644 index 0000000..fa23102 --- /dev/null +++ b/js/src/jit-test/tests/basic/bindname-in-strict-eval.js @@ -0,0 +1,3 @@ +'use strict'; +eval("var i = 0; var end = RUNLOOP; for(var j = 0; j < end; i++, j++) { i = 0; }"); +print("done"); diff --git a/js/src/jit-test/tests/basic/bitwiseAnd.js b/js/src/jit-test/tests/basic/bitwiseAnd.js new file mode 100644 index 0000000..dc9fafa --- /dev/null +++ b/js/src/jit-test/tests/basic/bitwiseAnd.js @@ -0,0 +1,10 @@ +function bitwiseAnd_inner(bitwiseAndValue) { + for (var i = 0; i < 60000; i++) + bitwiseAndValue = bitwiseAndValue & i; + return bitwiseAndValue; +} +function bitwiseAnd() +{ + return bitwiseAnd_inner(12341234); +} +assertEq(bitwiseAnd(), 0); diff --git a/js/src/jit-test/tests/basic/bitwiseGlobal.js b/js/src/jit-test/tests/basic/bitwiseGlobal.js new file mode 100644 index 0000000..e8967c1 --- /dev/null +++ b/js/src/jit-test/tests/basic/bitwiseGlobal.js @@ -0,0 +1,8 @@ +bitwiseAndValue = Math.pow(2,32); +for (var i = 0; i < 60000; i++) + bitwiseAndValue = bitwiseAndValue & i; + +assertEq(bitwiseAndValue, 0); + + + diff --git a/js/src/jit-test/tests/basic/bug464403.js b/js/src/jit-test/tests/basic/bug464403.js new file mode 100644 index 0000000..a0d4b4c --- /dev/null +++ b/js/src/jit-test/tests/basic/bug464403.js @@ -0,0 +1,7 @@ +function bug464403() { + print(8); + var u = [print, print, function(){}] + for each (x in u) for (u.e in [1,1,1,1]); + return "ok"; +} +assertEq(bug464403(), "ok"); diff --git a/js/src/jit-test/tests/basic/bug465902.js b/js/src/jit-test/tests/basic/bug465902.js new file mode 100644 index 0000000..c490d45 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug465902.js @@ -0,0 +1,13 @@ +var a = []; +for (let j = 0; j < 6; ++j) { + e = 3; + for each (let c in [10, 20, 30]) { + a.push(e); + e = c; + } +} +for (let j = 0; j < 6; ++j) { + assertEq(a[j*3 + 0], 3); + assertEq(a[j*3 + 1], 10); + assertEq(a[j*3 + 2], 20); +} diff --git a/js/src/jit-test/tests/basic/bug489098.js b/js/src/jit-test/tests/basic/bug489098.js new file mode 100644 index 0000000..6767ba6 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug489098.js @@ -0,0 +1,18 @@ +// Check that the loop is trace-compiled even though it's run in an eval. + +code = "\ +j = 0;\ +for (i = 0; i < 10; i++)\ +{\ + j += 5;\ +}\ +"; + +eval(code); +print (j); + +checkStats({ +recorderStarted: 1, +recorderAborted: 0, +traceCompleted: 1, +}); diff --git a/js/src/jit-test/tests/basic/bug504587-1.js b/js/src/jit-test/tests/basic/bug504587-1.js new file mode 100644 index 0000000..a489f99 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug504587-1.js @@ -0,0 +1,13 @@ +// This test case failed a WIP patch. See https://bugzilla.mozilla.org/show_bug.cgi?id=504587#c68 + +function B() {} +B.prototype.x = 1; +var d = new B; + +var names = ['z', 'z', 'z', 'z', 'z', 'z', 'z', 'x']; +for (var i = 0; i < names.length; i++) { + x = d.x; // guard on shapeOf(d) + d[names[i]] = 2; // unpredicted shape change + y = d.x; // guard here is elided +} +assertEq(y, 2); // Assertion failed: got 1, expected 2 diff --git a/js/src/jit-test/tests/basic/bug507180.js b/js/src/jit-test/tests/basic/bug507180.js new file mode 100644 index 0000000..9d8fb19 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug507180.js @@ -0,0 +1,69 @@ +var o = { + valueOf : function() { + return { + toString : function() { return "fail" } + } + }, + toString : function() { return "good" } +}; + +var p = { + valueOf : function() { + return { + toString : function() { return "0" } + } + }, + toString : function() { return "7" } +}; + +var q = { + toString : function() { + return { + valueOf : function() { return "0" } + } + }, + valueOf : function() { return "7" } +}; + +function assert(b, s) { + if (b) + return; + assertEq("imacro produces incorrect result for " + s, "fail"); +} + +function run() { + for (var i = 0; i < 5; ++i) { + // equality / inequality + assert(!(o == "fail"), "obj == any"); + assert(!("fail" == o), "any == obj"); + assert(!(o != "good"), "obj != any"); + assert(!("good" != o), "any != obj"); + + // binary + assert(!((p | 3) != 7), "obj | any"); + assert(!((3 | p) != 7), "any | obj"); + assert(!((p | p) != 7), "obj | obj"); + assert(!((p & 3) != 3), "obj & any"); + assert(!((3 & p) != 3), "any & obj"); + assert(!((p & p) != 7), "obj & obj"); + assert(!((p * 3) != 21), "obj * any"); + assert(!((3 * p) != 21), "any * obj"); + assert(!((p * p) != 49), "obj * obj"); + + // addition + assert(!(o + "" != "good"), "obj + any"); + assert(!("" + o != "good"), "any + obj"); + assert(!(o + o != "goodgood"), "any + any"); + + // sign + assert(!(-p != -7), "-obj"); + assert(!(+p != 7), "+obj"); + + // String + assert(!(String(q) != "7"), "String(obj)"); + assert(!(new String(q) != "7"), "new String(obj)"); + } + return true; +} + +run(); diff --git a/js/src/jit-test/tests/basic/bug509639.js b/js/src/jit-test/tests/basic/bug509639.js new file mode 100644 index 0000000..7c5b0c7 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug509639.js @@ -0,0 +1,3 @@ +// don't crash + +(function(){ var c; eval("for(c in [1,2,3,4]) {}") })(); diff --git a/js/src/jit-test/tests/basic/bug509982.js b/js/src/jit-test/tests/basic/bug509982.js new file mode 100644 index 0000000..36b9364 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug509982.js @@ -0,0 +1,15 @@ +function g() { + const e = 0; + return function () { + switch (7) { + case e: + } + }; +} + +for (var i = 0; i < 2; i++) { + let f = g; + f(); +} + +// Just test that we don't crash. diff --git a/js/src/jit-test/tests/basic/bug510434.js b/js/src/jit-test/tests/basic/bug510434.js new file mode 100644 index 0000000..253352e --- /dev/null +++ b/js/src/jit-test/tests/basic/bug510434.js @@ -0,0 +1,2 @@ +var f = function(){ var arguments = 3; for (var j=0;j<4;++j) print(arguments); }; +f(); diff --git a/js/src/jit-test/tests/basic/bug510437-2.js b/js/src/jit-test/tests/basic/bug510437-2.js new file mode 100644 index 0000000..1fca206 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug510437-2.js @@ -0,0 +1,13 @@ +function f() { + eval("g=function() { \ + for (let x=0; x < 2; ++x) { \ + d=x \ + } \ + }") + g(); + eval("var d") + g(); +} + +f(); +assertEq(d, 1); diff --git a/js/src/jit-test/tests/basic/bug510437.js b/js/src/jit-test/tests/basic/bug510437.js new file mode 100644 index 0000000..00f5d8d --- /dev/null +++ b/js/src/jit-test/tests/basic/bug510437.js @@ -0,0 +1,12 @@ +// Don't crash or assert. + +this.watch("d", eval); +(function () { + (eval("\ + (function () {\ + for (let x = 0; x < 2; ++x) {\ + d = x\ + }\ + })\ +"))() +})() diff --git a/js/src/jit-test/tests/basic/bug510642.js b/js/src/jit-test/tests/basic/bug510642.js new file mode 100644 index 0000000..c225d15 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug510642.js @@ -0,0 +1,14 @@ +// Don't crash or assert. + +(function () { + var x; + (eval("\ + (function () {\ + for (y in [0, 0]) let(a)((function () {\ + for (w in [0, 0])\ + x = 0\ + })());\ + with({}) {}\ + })\ + "))() +})() diff --git a/js/src/jit-test/tests/basic/bug510655.js b/js/src/jit-test/tests/basic/bug510655.js new file mode 100644 index 0000000..3ae8bbe --- /dev/null +++ b/js/src/jit-test/tests/basic/bug510655.js @@ -0,0 +1,15 @@ +// This should not crash (or assert in debug builds). + +(function () { + for (b in [0, 0]) { + (eval("\ + [this\ + for (b in [\ + [undefined],\ + arguments,\ + [undefined]\ + ])\ + ]\ + ")) + } +})() diff --git a/js/src/jit-test/tests/basic/bug511214.js b/js/src/jit-test/tests/basic/bug511214.js new file mode 100644 index 0000000..611d86e --- /dev/null +++ b/js/src/jit-test/tests/basic/bug511214.js @@ -0,0 +1,18 @@ +eval(1); // avoid global shape change when we call eval below +function q() { + var x = 1; + function f() { + function g() { + var t=0; + for (var i=0; i<3; i++) + x = i; + }; + g(); + eval("var x = 3"); + g(); + assertEq(x, 2); + } + f(); + assertEq(x, 2); +} +q(); diff --git a/js/src/jit-test/tests/basic/bug511241.js b/js/src/jit-test/tests/basic/bug511241.js new file mode 100644 index 0000000..fe28feb --- /dev/null +++ b/js/src/jit-test/tests/basic/bug511241.js @@ -0,0 +1,15 @@ +var d = 1; +function heavy(x) { + eval(x); + return function lite() { + var s = 0; + for (var i = 0; i < 9; i++) + s += d; + return s; + }; +} + +var f1 = heavy("1"); +var f2 = heavy("var d = 100;"); +assertEq(f1(), 9); +assertEq(f2(), 900); diff --git a/js/src/jit-test/tests/basic/bug513038.js b/js/src/jit-test/tests/basic/bug513038.js new file mode 100644 index 0000000..21cf1c3 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug513038.js @@ -0,0 +1,16 @@ +// Just don't assert or crash. + +function f() { + let c + try { + (eval("\ + (function(){\ + with(\ + this.__defineGetter__(\"x\", function(){for(a = 0; a < 3; a++){c=a}})\ + ){}\ + })\ + "))() + } catch(e) {} +} +f() +print(x) diff --git a/js/src/jit-test/tests/basic/bug513898-regexp.js b/js/src/jit-test/tests/basic/bug513898-regexp.js new file mode 100644 index 0000000..6b76abf --- /dev/null +++ b/js/src/jit-test/tests/basic/bug513898-regexp.js @@ -0,0 +1,51 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: haytjes + */ + +/* Check the undefined pattern is equivalent to empty string. */ + +assertEq(RegExp(undefined).source, ''); +assertEq(RegExp(undefined).global, false); +assertEq("test".replace(RegExp(undefined), "*"), '*test'); +assertEq(new RegExp(undefined).source, ''); +assertEq(new RegExp(undefined).global, false); +assertEq('test'.replace(new RegExp(undefined), "*"), '*test'); + +/* Global flags. */ + +assertEq(new RegExp(undefined, "g").global, true); +assertEq("test".replace(new RegExp(undefined, "g"), "*"), "*t*e*s*t*"); +assertEq(RegExp(undefined, "g").global, true); +assertEq("test".replace(RegExp(undefined, "g"), "*"), "*t*e*s*t*"); + +/* Undefined flags. */ + +var re = new RegExp(undefined, undefined); +assertEq(re.multiline, false); +assertEq(re.global, false); +assertEq(re.ignoreCase, false); + +var re = new RegExp("test", undefined); +assertEq(re.multiline, false); +assertEq(re.global, false); +assertEq(re.ignoreCase, false); + +/* Flags argument that requires toString. */ + +function Flags() {}; + +Flags.prototype.toString = function dogToString() { return ""; } + +var re = new RegExp(undefined, new Flags()); +assertEq(re.multiline, false); +assertEq(re.global, false); +assertEq(re.ignoreCase, false); + +Flags.prototype.toString = function dogToString() { return "gim"; } + +var re = new RegExp(undefined, new Flags()); +assertEq(re.multiline, true); +assertEq(re.global, true); +assertEq(re.ignoreCase, true); diff --git a/js/src/jit-test/tests/basic/bug516009.js b/js/src/jit-test/tests/basic/bug516009.js new file mode 100644 index 0000000..db3a359 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug516009.js @@ -0,0 +1,20 @@ +var gFutureCalls = []; + +function add_future_call(index, func) +{ + if (!(index in gFutureCalls)) { + gFutureCalls[index] = []; + } +} + +function check_reset_test(time) +{ +} + +check_reset_test(0); + +for (var i = 1; i <= 8; ++i) { + (function(j) { + add_future_call(j, function() { check_reset_test(j); }); + })(i); +} diff --git a/js/src/jit-test/tests/basic/bug517721.js b/js/src/jit-test/tests/basic/bug517721.js new file mode 100644 index 0000000..77a2c94 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug517721.js @@ -0,0 +1,8 @@ +try { + for (var j = 0; j < 2; ++j) { + if (j == 1) { + ++(null[2]); + } + } +} catch(e) { +} diff --git a/js/src/jit-test/tests/basic/bug519129.js b/js/src/jit-test/tests/basic/bug519129.js new file mode 100644 index 0000000..89ba1f9 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug519129.js @@ -0,0 +1 @@ +(function(){eval("for(l in[0,0,0]){}",0)})() diff --git a/js/src/jit-test/tests/basic/bug520498.js b/js/src/jit-test/tests/basic/bug520498.js new file mode 100644 index 0000000..55324f6 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug520498.js @@ -0,0 +1,9 @@ +var Q = 0; +try { + (function f(i) { Q = i; if (i == 100000) return; f(i+1); })(1) +} catch (e) { +} + +if (Q == 100000) + assertEq(Q, "fail"); + diff --git a/js/src/jit-test/tests/basic/bug522136.js b/js/src/jit-test/tests/basic/bug522136.js new file mode 100644 index 0000000..9267c99 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug522136.js @@ -0,0 +1,10 @@ +var Q = 0; +try { + (function f(i) { Q = i; if (i == 100000) return; f(i+1); })(1) +} catch (e) { +} + +// Exact behavior of recursion check depends on which JIT we use. +var ok = (Q == 3000 || Q == 3001); +assertEq(ok, true); + diff --git a/js/src/jit-test/tests/basic/bug522817.js b/js/src/jit-test/tests/basic/bug522817.js new file mode 100644 index 0000000..25b5b99 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug522817.js @@ -0,0 +1,17 @@ +// This test should not assert in a debug build. + +var q1={}; +var $native = function () { + for (var i = 0, l = arguments.length; i < l; i++) { + arguments[i].extend = function (props) {}; + } +}; +$native(q1, Array, String, Number); +Array.extend({}); +Number.extend({}); +Object.Native = function () { + for (var i = 0; i < arguments.length; i++) { + arguments[i].eeeeee = (function(){}); + } +}; +new Object.Native(q1, Array, String, Number); diff --git a/js/src/jit-test/tests/basic/bug524826-2.js b/js/src/jit-test/tests/basic/bug524826-2.js new file mode 100644 index 0000000..38e3c27 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug524826-2.js @@ -0,0 +1,11 @@ +var x = 42; + +function f() { + var a = [{}, {}, {}, {}, {}]; + for (var i = 0; i < 5; i++) + a[i].m = function () {return x}; + for (i = 0; i < 4; i++) + if (a[i].m == a[i+1].m) + throw "FAIL!"; +} +f(); diff --git a/js/src/jit-test/tests/basic/bug524826.js b/js/src/jit-test/tests/basic/bug524826.js new file mode 100644 index 0000000..225c359 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug524826.js @@ -0,0 +1,10 @@ +var x = 42; +function f() { + var a = [new Date, new Date, new Date, new Date, new Date]; + for (var i = 0; i < 5; i++) + a[i].m = function () {return x}; + for (i = 0; i < 4; i++) + if (a[i].m == a[i+1].m) + throw "FAIL!"; +} +f(); diff --git a/js/src/jit-test/tests/basic/bug525028.js b/js/src/jit-test/tests/basic/bug525028.js new file mode 100644 index 0000000..90200b6 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug525028.js @@ -0,0 +1,16 @@ +// don't crash + +function f() { + var _L1 = arguments; + for (var i = 0; i < _L1.length; i++) { + if (typeof _L1[i] == "string") + _L1[i] = new Object(); + } + print(arguments[2]); +} + +f(1, 2, "3", 4, 5); +f(1, 2, "3", 4, 5); +f(1, 2, "3", 4, 5); +f(1, 2, "3", 4, 5); + diff --git a/js/src/jit-test/tests/basic/bug527288.js b/js/src/jit-test/tests/basic/bug527288.js new file mode 100644 index 0000000..de227a7 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug527288.js @@ -0,0 +1,7 @@ +(function () { + for (a = 0; a < 3; a++) { + for each(b in [0, -0]) {} + } +})() + +// Just test we don't assert. diff --git a/js/src/jit-test/tests/basic/bug528116.js b/js/src/jit-test/tests/basic/bug528116.js new file mode 100644 index 0000000..8a47778 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug528116.js @@ -0,0 +1,8 @@ +(function() { + var x = [null, [], null]; + for (var i = 0; i != x.length; ++i) { + eval("for (var b = 0; b < 2; ++b);", x[i]); + } +})(); + +// Just test that we don't crash. diff --git a/js/src/jit-test/tests/basic/bug528644.js b/js/src/jit-test/tests/basic/bug528644.js new file mode 100644 index 0000000..260e0d9 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug528644.js @@ -0,0 +1,16 @@ +// Don't crash + +function g(foo) { + for (a in foo) { + } +} + +var makegen = eval("\n\ + (function(b) {\n\ + var h = \n\ + eval(\"new function() { yield print(b) }\" ); \n\ + return h\n\ + })\n\ +"); + +g(makegen()); diff --git a/js/src/jit-test/tests/basic/bug529130.js b/js/src/jit-test/tests/basic/bug529130.js new file mode 100644 index 0000000..aefc91c --- /dev/null +++ b/js/src/jit-test/tests/basic/bug529130.js @@ -0,0 +1,19 @@ +// don't crash + +var q = 30; + +function var_iter(v) { + q--; + yield v; + if (q > 0) { + for each (let ret in var_iter(v)) { + var_iter(v); + yield ret; + } + } +} + +for (x in var_iter([1, 2, 3, 4, 5, 6, 7, 8, 9])) + print(x); + + diff --git a/js/src/jit-test/tests/basic/bug532568-2.js b/js/src/jit-test/tests/basic/bug532568-2.js new file mode 100644 index 0000000..47f7058 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug532568-2.js @@ -0,0 +1,20 @@ +var before = ''; +var after = ''; + +function g(b) { + for (var i = 0; i < 10; ++i) { + } +} + +function f(xa_arg) { + var xa = xa_arg; + for (var i = 0; i < 5; ++i) { + var j = i + xa[i]; + before += j + ','; + g(); + after += j + ','; + } +} + +f([ 0, 1, 2, 3, 4 ]); +assertEq(before, after); diff --git a/js/src/jit-test/tests/basic/bug532568.js b/js/src/jit-test/tests/basic/bug532568.js new file mode 100644 index 0000000..b1cf86c --- /dev/null +++ b/js/src/jit-test/tests/basic/bug532568.js @@ -0,0 +1,19 @@ +var actual = ""; + +function f() { + var x = 10; + + var g = function(p) { + for (var i = 0; i < 10; ++i) + x = p + i; + } + + for (var i = 0; i < 10; ++i) { + g(100 * i + x); + actual += x + ','; + } +} + +f(); + +assertEq(actual, "19,128,337,646,1055,1564,2173,2882,3691,4600,"); diff --git a/js/src/jit-test/tests/basic/bug532823.js b/js/src/jit-test/tests/basic/bug532823.js new file mode 100644 index 0000000..c2b2dc6 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug532823.js @@ -0,0 +1,23 @@ +function loop(f) { + var p; + for (var i = 0; i < 10; ++i) { + p = f(); + } + return p; +} + +function f(j, k) { + var g = function() { return k; } + + var ans = ''; + + for (k = 0; k < 5; ++k) { + ans += loop(g); + } + return ans; +} + +var t0 = new Date; +var actual = f(1); + +assertEq(actual, '01234'); diff --git a/js/src/jit-test/tests/basic/bug535474.js b/js/src/jit-test/tests/basic/bug535474.js new file mode 100644 index 0000000..6e34298 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug535474.js @@ -0,0 +1,27 @@ +function f() { + var _76 = {}; + for (var i = 0; i < arguments.length; i++) { + var typ = arguments[i]; + _76[typ] = typ; + } + return function () { + for (var i = 0; i < arguments.length; i++) { + if (!(typeof (arguments[i]) in _76)) { + return false; + } + } + return true; + } +} + +g = f("number", "boolean", "object"); + +g("a", "b", "c", "d", "e", "f", 2); +g(2, "a", "b", "c", "d", "e", "f", 2); + +/* + * Don't assert -- + * Assertion failed: frame entry -4 wasn't freed + * : _activation.entry[i] == 0 (../nanojit/Assembler.cpp:786) + */ + diff --git a/js/src/jit-test/tests/basic/bug535760.js b/js/src/jit-test/tests/basic/bug535760.js new file mode 100644 index 0000000..e7e1fce --- /dev/null +++ b/js/src/jit-test/tests/basic/bug535760.js @@ -0,0 +1,13 @@ +/* vim: set ts=4 sw=4 tw=99 et: */ +function foundit(items, n) { + for (var i = 0; i < 10; i++) + arguments[2](items, this); +} + +function dostuff() { + print(this); +} +foundit('crab', 'crab', dostuff); + +/* Don't crash or assert */ + diff --git a/js/src/jit-test/tests/basic/bug535930.js b/js/src/jit-test/tests/basic/bug535930.js new file mode 100644 index 0000000..ac985d1 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug535930.js @@ -0,0 +1,19 @@ +(function () { + p = function () { + Set() + }; + var Set = function () {}; + for (var x = 0; x < 5; x++) { + Set = function (z) { + return function () { + [z] + } + } (x) + } +})() + +/* + * bug 535930, mistakenly generated code to GetUpvar and crashed inside the call. + * so don't crash. + */ + diff --git a/js/src/jit-test/tests/basic/bug536445.js b/js/src/jit-test/tests/basic/bug536445.js new file mode 100644 index 0000000..16808bb --- /dev/null +++ b/js/src/jit-test/tests/basic/bug536445.js @@ -0,0 +1,10 @@ +var x; +var str = "a"; +assertEq(str.charCodeAt(Infinity) | 0, 0); +for (var i = 0; i < 10; ++i) + x = str.charCodeAt(Infinity) | 0; +assertEq(x, 0); +for (var i = 0; i < 10; ++i) + x = str.charCodeAt(Infinity); +assertEq(x | 0, 0); + diff --git a/js/src/jit-test/tests/basic/bug536748.js b/js/src/jit-test/tests/basic/bug536748.js new file mode 100644 index 0000000..42d8200 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug536748.js @@ -0,0 +1,8 @@ +// Do not assert. + +var s = "a"; +var b = 32767; + +for (var i = 0; i < 10; ++i) { + b = b & s.charCodeAt(); +} diff --git a/js/src/jit-test/tests/basic/bug539379.js b/js/src/jit-test/tests/basic/bug539379.js new file mode 100644 index 0000000..dab57f5 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug539379.js @@ -0,0 +1,9 @@ +try { + // On X64 this was crashing rather than causing a "too much recursion" exception. + x = /x/; + (function f() { + x.r = x; + return f() + })(); +} catch (e) {} + diff --git a/js/src/jit-test/tests/basic/bug539553-2.js b/js/src/jit-test/tests/basic/bug539553-2.js new file mode 100644 index 0000000..b8fbeb1 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug539553-2.js @@ -0,0 +1,7 @@ +function f() { + var x = arguments; + arguments.length = {}; + for (var i = 0; i < 9; i++) + x.length.toSource(); +} +f(); diff --git a/js/src/jit-test/tests/basic/bug539553-3.js b/js/src/jit-test/tests/basic/bug539553-3.js new file mode 100644 index 0000000..44b7d41 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug539553-3.js @@ -0,0 +1,11 @@ +function g(x) { + assertEq(arguments.length, 1); + assertEq(x.length, 4); +} + +function f() { + for (var i = 0; i < 9; i++) + g(arguments); +} + +f(1, 2, 3, 4); diff --git a/js/src/jit-test/tests/basic/bug539553.js b/js/src/jit-test/tests/basic/bug539553.js new file mode 100644 index 0000000..41f12c7 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug539553.js @@ -0,0 +1,11 @@ +function g(x) { + assertEq(x.length, 1); +} + +function f() { + arguments.length = 1; + for (var i = 0; i < 9; i++) + g(arguments); +} + +f(); diff --git a/js/src/jit-test/tests/basic/bug541191-1.js b/js/src/jit-test/tests/basic/bug541191-1.js new file mode 100644 index 0000000..78f0caf --- /dev/null +++ b/js/src/jit-test/tests/basic/bug541191-1.js @@ -0,0 +1,23 @@ +/* vim: set ts=4 sw=4 tw=99 et: */ + +function g(a, b, c, d) { + return "" + a + b + c + d; +} + +var x = 1; +function f(a, b, c) { + arguments[1] = 2; + arguments[2] = 3; + arguments[3] = 4; + if (!x) + arguments.length = 4; + var k; + for (var i = 0; i < 10; i++) + k = g.apply(this, arguments); + return k; +} + +assertEq(f(1), "1undefinedundefinedundefined"); +x = 0; +assertEq(f(1), "1234"); + diff --git a/js/src/jit-test/tests/basic/bug541191-2.js b/js/src/jit-test/tests/basic/bug541191-2.js new file mode 100644 index 0000000..5be269a --- /dev/null +++ b/js/src/jit-test/tests/basic/bug541191-2.js @@ -0,0 +1,23 @@ +/* vim: set ts=4 sw=4 tw=99 et: */ + +function g(a, b, c, d) { + return "" + a + b + c + d; +} + +var x = 1; +function f(a, b, c) { + arguments[1] = 2; + arguments[2] = 3; + arguments[3] = 4; + if (x) + arguments.length = 4; + var k; + for (var i = 0; i < RUNLOOP; i++) + k = g.apply(this, arguments); + return k; +} + +assertEq(f(1), "1234"); +x = 0; +assertEq(f(1), "1undefinedundefinedundefined"); + diff --git a/js/src/jit-test/tests/basic/bug541191-3.js b/js/src/jit-test/tests/basic/bug541191-3.js new file mode 100644 index 0000000..f4e01b9 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug541191-3.js @@ -0,0 +1,23 @@ +/* vim: set ts=4 sw=4 tw=99 et: */ + +function g(a, b, c, d) { + return "" + a + b + c + d; +} + +var x = 1; +function f(a, b, c) { + arguments[1] = 2; + arguments[2] = 3; + arguments[3] = 4; + if (x) + arguments.length = 1; + var k; + for (var i = 0; i < 10; i++) + k = g.apply(this, arguments); + return k; +} + +assertEq(f(1), "1undefinedundefinedundefined"); +x = 0; +assertEq(f(1), "1undefinedundefinedundefined"); + diff --git a/js/src/jit-test/tests/basic/bug541191-4.js b/js/src/jit-test/tests/basic/bug541191-4.js new file mode 100644 index 0000000..0ecbb91 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug541191-4.js @@ -0,0 +1,27 @@ +/* vim: set ts=4 sw=4 tw=99 et: */ + +function g(a, b, c, d) { + return "" + a + b + c + d; +} + +var x = 1; +function f(a, b, c) { + arguments[1] = 2; + arguments[2] = 3; + arguments[3] = 4; + if (x) { + arguments.length = 1; + delete arguments.length; + arguments.__defineGetter__('length', function () { return eval('1'); }); + } + var k; + for (var i = 0; i < 10; i++) + k = g.apply(this, arguments); + return k; +} + +assertEq(f(1), "1undefinedundefinedundefined"); +x = 0; +assertEq(f(1), "1undefinedundefinedundefined"); + + diff --git a/js/src/jit-test/tests/basic/bug541191-5.js b/js/src/jit-test/tests/basic/bug541191-5.js new file mode 100644 index 0000000..a2f9e57 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug541191-5.js @@ -0,0 +1,24 @@ +/* vim: set ts=4 sw=4 tw=99 et: */ + +function g(a, b, c, d) { + return "" + a + b + c + d; +} + +var x = 1; +function f(a, b, c) { + arguments[1] = 2; + arguments[2] = 3; + arguments[3] = 4; + if (x) + arguments.length = 1; + var k; + for (var i = 0; i < 10; i++) + k = g.apply(this, arguments); + return k; +} + +assertEq(f(1), "1undefinedundefinedundefined"); +x = 0; +assertEq(f(1), "1undefinedundefinedundefined"); + + diff --git a/js/src/jit-test/tests/basic/bug547911-1.js b/js/src/jit-test/tests/basic/bug547911-1.js new file mode 100644 index 0000000..e15c335 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug547911-1.js @@ -0,0 +1,7 @@ +a = b = c = d = 0; +this.__defineGetter__("e", function () { throw StopIteration; }) +try { + for each(f in this) {} +} catch (exc) { + assertEq(exc, StopIteration); +} diff --git a/js/src/jit-test/tests/basic/bug547911-2.js b/js/src/jit-test/tests/basic/bug547911-2.js new file mode 100644 index 0000000..d29d330 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug547911-2.js @@ -0,0 +1,7 @@ +var obj = {a: 0, b: 0, c: 0, d: 0, get e() { throw StopIteration; }}; +try { + for each (x in obj) {} + FAIL; +} catch (exc) { + assertEq(exc, StopIteration); +} diff --git a/js/src/jit-test/tests/basic/bug551705.js b/js/src/jit-test/tests/basic/bug551705.js new file mode 100644 index 0000000..a97d988 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug551705.js @@ -0,0 +1,39 @@ +(Function("\ + for each(let x in [\n\ + true,\n\ + (1),\n\ + (1),\n\ + (1),\n\ + (1),\n\ + true,\n\ + true,\n\ + true,\n\ + (1),\n\ + true,\n\ + true,\n\ + (1),\n\ + true,\n\ + true,\n\ + (1),\n\ + (1),\n\ + true,\n\ + true,\n\ + true,\n\ + true\n\ + ]) { \n\ + ((function f(aaaaaa) {\n\ + return aaaaaa.length == 0 ? 0 : aaaaaa[0] + f(aaaaaa.slice(1))\n\ + })([\n\ + x,\n\ + Math.I,\n\ + '',\n\ + null,\n\ + Math.I,\n\ + null,\n\ + new String(),\n\ + new String()\n\ + ]))\n\ +}"))() + +/* Don't assert/crash. */ + diff --git a/js/src/jit-test/tests/basic/bug552196.js b/js/src/jit-test/tests/basic/bug552196.js new file mode 100644 index 0000000..d526234 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug552196.js @@ -0,0 +1,12 @@ +(Function("\ + for (a = 0; a < 5; a++)\n\ + (function f(b) {\n\ + if (b > 0) {\n\ + f(b - 1)\n\ + }\n\ + })\n\ + (3)\n\ +"))() + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/basic/bug557168-1.js b/js/src/jit-test/tests/basic/bug557168-1.js new file mode 100644 index 0000000..fedcafb --- /dev/null +++ b/js/src/jit-test/tests/basic/bug557168-1.js @@ -0,0 +1,11 @@ +x = +try { + Function("\ + (function f() {\ + ({x:{b}}=x);\ + f()\ + })()\ + ")() +} catch (e) { + assertEq(e.message, "too much recursion"); +} diff --git a/js/src/jit-test/tests/basic/bug557168-2.js b/js/src/jit-test/tests/basic/bug557168-2.js new file mode 100644 index 0000000..8221f91 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug557168-2.js @@ -0,0 +1,11 @@ +x = +try { + Function("\ + (function f() {\ + ({x}=x);\ + f()\ + })()\ + ")() +} catch (e) { + assertEq(e.message, "too much recursion"); +} diff --git a/js/src/jit-test/tests/basic/bug557168-3.js b/js/src/jit-test/tests/basic/bug557168-3.js new file mode 100644 index 0000000..31cd262 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug557168-3.js @@ -0,0 +1,10 @@ +x = +try { + Function("\ + for(var a = 0; a < 6; a++) {\ + Number(x.u)\ + }\ + ")() +} catch (e) { + assertEq(e.message, "too much recursion"); +} diff --git a/js/src/jit-test/tests/basic/bug557168.js b/js/src/jit-test/tests/basic/bug557168.js new file mode 100644 index 0000000..737052f --- /dev/null +++ b/js/src/jit-test/tests/basic/bug557168.js @@ -0,0 +1,4 @@ +x = +for (var z = 0; z < 4; z++) { + print(x.z) +} diff --git a/js/src/jit-test/tests/basic/bug557841.js b/js/src/jit-test/tests/basic/bug557841.js new file mode 100644 index 0000000..903490e --- /dev/null +++ b/js/src/jit-test/tests/basic/bug557841.js @@ -0,0 +1 @@ +eval("for(a = 0; a < 4; a++) x = 1;", []); diff --git a/js/src/jit-test/tests/basic/bug558530.js b/js/src/jit-test/tests/basic/bug558530.js new file mode 100644 index 0000000..31fa78e --- /dev/null +++ b/js/src/jit-test/tests/basic/bug558530.js @@ -0,0 +1,14 @@ +// There's no assertEq() here; the test is just that it doesn't crash. +(function () { + new function () {} +}()); +[function () {}] +gc() +for (z = 0; z < 6; ++z) { + x = [] +} +for (w in [0]) { + x._ = w +} +gc() + diff --git a/js/src/jit-test/tests/basic/bug558814.js b/js/src/jit-test/tests/basic/bug558814.js new file mode 100644 index 0000000..63a9f87 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug558814.js @@ -0,0 +1,10 @@ +function f() +{ + var a = []; + a.length = 10; + for (var i = 0; i < 100; i++) { + var y = a[a.length]; + } +} +f(); +// No assertEq() call, the test is just that it shouldn't assert or crash. diff --git a/js/src/jit-test/tests/basic/bug559912.js b/js/src/jit-test/tests/basic/bug559912.js new file mode 100644 index 0000000..8f05ff5 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug559912.js @@ -0,0 +1,12 @@ + +function s(f) { this._m = f; } +function C() { + Object.defineProperty(this, "m", {set: s}); + this.m = function () {}; +} +var last = {}; +for (var i = 0; i < 20; i++) { + var a = new C; + assertEq(a._m === last._m, false); + last = a; +} diff --git a/js/src/jit-test/tests/basic/bug560234.js b/js/src/jit-test/tests/basic/bug560234.js new file mode 100644 index 0000000..dc2956a --- /dev/null +++ b/js/src/jit-test/tests/basic/bug560234.js @@ -0,0 +1,10 @@ +function test() { + var a = ['x', '', '', '', '', '', '', 'x']; + var b = ''; + for (var i = 0; i < a.length; i++) { + (function() { + a[i].replace(/x/, function() { return b; }); + }()); + } +} +test(); // should NOT get a ReferenceError for b on trace diff --git a/js/src/jit-test/tests/basic/bug560234b.js b/js/src/jit-test/tests/basic/bug560234b.js new file mode 100644 index 0000000..b130d75 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug560234b.js @@ -0,0 +1,12 @@ +function f(a) { + function g() { + yield function () a; + } + if (a == 8) + return g(); + a = 3; +} +var x; +for (var i = 0; i < 9; i++) + x = f(i); +x.next()(); // ReferenceError: a is not defined. diff --git a/js/src/jit-test/tests/basic/bug561279.js b/js/src/jit-test/tests/basic/bug561279.js new file mode 100644 index 0000000..2160be5 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug561279.js @@ -0,0 +1,4 @@ +{ + let y; + eval('eval("for (z = 0; z < 6; z++) a = z;")'); +} diff --git a/js/src/jit-test/tests/basic/bug563125.js b/js/src/jit-test/tests/basic/bug563125.js new file mode 100644 index 0000000..d5da052 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug563125.js @@ -0,0 +1,5 @@ +var array = new Array(4294967295); +for (var j = 0; j < RUNLOOP; ++j) { '' + array.length; } + +// Don't assert. + diff --git a/js/src/jit-test/tests/basic/bug566637.js b/js/src/jit-test/tests/basic/bug566637.js new file mode 100644 index 0000000..6623dba --- /dev/null +++ b/js/src/jit-test/tests/basic/bug566637.js @@ -0,0 +1,5 @@ +for (var j = 0; j < 9; j++) { + var a = j; + var b = this.a; +} +assertEq(b, 8); diff --git a/js/src/jit-test/tests/basic/bug568276.js b/js/src/jit-test/tests/basic/bug568276.js new file mode 100644 index 0000000..4f3f6e7 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug568276.js @@ -0,0 +1 @@ +function outer(a) { var b, c, d, e, f, g, h, i; function a() {} } diff --git a/js/src/jit-test/tests/basic/bug569651.js b/js/src/jit-test/tests/basic/bug569651.js new file mode 100644 index 0000000..58f9c13 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug569651.js @@ -0,0 +1,3 @@ +// don't crash or assert + ++Function("switch(\"\"){case 1:case 8:}"); \ No newline at end of file diff --git a/js/src/jit-test/tests/basic/bug569843.js b/js/src/jit-test/tests/basic/bug569843.js new file mode 100644 index 0000000..ff70ad6 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug569843.js @@ -0,0 +1,4 @@ +x = ; +for each(l in [0, 0, 0, 0]) { + delete x.d; +} diff --git a/js/src/jit-test/tests/basic/bug569849.js b/js/src/jit-test/tests/basic/bug569849.js new file mode 100644 index 0000000..18598ba --- /dev/null +++ b/js/src/jit-test/tests/basic/bug569849.js @@ -0,0 +1,9 @@ +function g() { + function f(a) { + delete a.x; + } + for each(let w in [Infinity, String()]) { + let i = f(w); + } +} +g(); diff --git a/js/src/jit-test/tests/basic/bug570385-1.js b/js/src/jit-test/tests/basic/bug570385-1.js new file mode 100644 index 0000000..ec9007c --- /dev/null +++ b/js/src/jit-test/tests/basic/bug570385-1.js @@ -0,0 +1,9 @@ +var actual = ''; + +var a = [0, 1]; +for (var i in a) { + appendToActual(i); + a.pop(); +} + +assertEq(actual, "0,"); diff --git a/js/src/jit-test/tests/basic/bug570385-2.js b/js/src/jit-test/tests/basic/bug570385-2.js new file mode 100644 index 0000000..dc189dd --- /dev/null +++ b/js/src/jit-test/tests/basic/bug570385-2.js @@ -0,0 +1,9 @@ +var actual = ''; + +var a = [0, 1]; +for (var i in a) { + appendToActual(i); + delete a[1]; +} + +assertEq(actual, "0,"); diff --git a/js/src/jit-test/tests/basic/bug570385-3.js b/js/src/jit-test/tests/basic/bug570385-3.js new file mode 100644 index 0000000..f65fabc --- /dev/null +++ b/js/src/jit-test/tests/basic/bug570385-3.js @@ -0,0 +1,11 @@ +var actual = ''; + +var a = [0, 1]; +a.x = 10; +delete a.x; +for (var i in a) { + appendToActual(i); + a.pop(); +} + +assertEq(actual, "0,"); diff --git a/js/src/jit-test/tests/basic/bug570663-1.js b/js/src/jit-test/tests/basic/bug570663-1.js new file mode 100644 index 0000000..08f14ec --- /dev/null +++ b/js/src/jit-test/tests/basic/bug570663-1.js @@ -0,0 +1,4 @@ +// don't crash +for (var a = 0; a < 4; a++) { + switch (NaN) {} +} diff --git a/js/src/jit-test/tests/basic/bug570663-2.js b/js/src/jit-test/tests/basic/bug570663-2.js new file mode 100644 index 0000000..bc4b088 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug570663-2.js @@ -0,0 +1,12 @@ +function f() { + var x; + for (var a = 0; a < 4; a++) { + switch (NaN) { + default: + x = a; + } + } + assertEq(x, 3); +} + +f(); diff --git a/js/src/jit-test/tests/basic/bug572229.js b/js/src/jit-test/tests/basic/bug572229.js new file mode 100644 index 0000000..c45cea0 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug572229.js @@ -0,0 +1,12 @@ +// Don't crash + +function f(o, s) { + var k = s.substr(0, 1); + var c; + for (var i = 0; i < 10; ++i) { + c = k in o; + } + return c; +} + +assertEq(f({ a: 66 }, 'abc'), true); diff --git a/js/src/jit-test/tests/basic/bug574280.js b/js/src/jit-test/tests/basic/bug574280.js new file mode 100644 index 0000000..bcd3469 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug574280.js @@ -0,0 +1,4 @@ +for (p = 0; p < 4; p++) { + a = 0 + new XMLList +} diff --git a/js/src/jit-test/tests/basic/bug576823-regexp.js b/js/src/jit-test/tests/basic/bug576823-regexp.js new file mode 100644 index 0000000..175ecb2 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug576823-regexp.js @@ -0,0 +1,3 @@ +// Sticky should work across disjunctions. + +assertEq(/A|B/y.exec("CB"), null); diff --git a/js/src/jit-test/tests/basic/bug576837-regexp.js b/js/src/jit-test/tests/basic/bug576837-regexp.js new file mode 100644 index 0000000..99d161c --- /dev/null +++ b/js/src/jit-test/tests/basic/bug576837-regexp.js @@ -0,0 +1,45 @@ +/* + * Check that builtin character classes within ranges produce syntax + * errors. + * + * Note that, per the extension in bug 351463, SpiderMonkey permits hyphens + * adjacent to character class escapes in character classes, treating them as a + * hyphen pattern character. Therefore /[\d-\s]/ is okay + * + * Note: /\b/ is the backspace escape, which is a single pattern character, + * though it looks deceptively like a character class. + */ + +function isRegExpSyntaxError(pattern) { + try { + var re = new RegExp(pattern); + } catch (e) { + if (e instanceof SyntaxError) + return true; + } + return false; +} + +assertEq(isRegExpSyntaxError('[C-\\s]'), true); +assertEq(isRegExpSyntaxError('[C-\\d]'), true); +assertEq(isRegExpSyntaxError('[C-\\W]'), true); +assertEq(isRegExpSyntaxError('[C-]'), false); +assertEq(isRegExpSyntaxError('[-C]'), false); +assertEq(isRegExpSyntaxError('[C-C]'), false); +assertEq(isRegExpSyntaxError('[C-C]'), false); +assertEq(isRegExpSyntaxError('[\\b-\\b]'), false); +assertEq(isRegExpSyntaxError('[\\B-\\B]'), false); +assertEq(isRegExpSyntaxError('[\\b-\\B]'), false); +assertEq(isRegExpSyntaxError('[\\B-\\b]'), true); +assertEq(isRegExpSyntaxError('[\\b-\\w]'), true); +assertEq(isRegExpSyntaxError('[\\B-\\w]'), true); + +/* Extension. */ +assertEq(isRegExpSyntaxError('[\\s-\\s]'), false); +assertEq(isRegExpSyntaxError('[\\W-\\s]'), false); +assertEq(isRegExpSyntaxError('[\\s-\\W]'), false); +assertEq(isRegExpSyntaxError('[\\W-C]'), false); +assertEq(isRegExpSyntaxError('[\\d-C]'), false); +assertEq(isRegExpSyntaxError('[\\s-C]'), false); +assertEq(isRegExpSyntaxError('[\\w-\\b]'), false); +assertEq(isRegExpSyntaxError('[\\w-\\B]'), false); diff --git a/js/src/jit-test/tests/basic/bug578041.js b/js/src/jit-test/tests/basic/bug578041.js new file mode 100644 index 0000000..0ab8878 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug578041.js @@ -0,0 +1,3 @@ +this.__defineGetter__('x', Float32Array); +with(this) + x; diff --git a/js/src/jit-test/tests/basic/bug579740.js b/js/src/jit-test/tests/basic/bug579740.js new file mode 100644 index 0000000..83ee967 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug579740.js @@ -0,0 +1,7 @@ + +for (a = 0; a < 4; a++) { + new Math.round(0).t +} + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/basic/bug582161.js b/js/src/jit-test/tests/basic/bug582161.js new file mode 100644 index 0000000..09f9a89 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug582161.js @@ -0,0 +1,3 @@ +// |jit-test| error: RangeError; +var vs = [1, 1, 1, 1, 3.5, 1]; +for (var i = 0, sz = vs.length; i < sz; i++) new Array(vs[i]); diff --git a/js/src/jit-test/tests/basic/bug582479.js b/js/src/jit-test/tests/basic/bug582479.js new file mode 100644 index 0000000..4029dcf --- /dev/null +++ b/js/src/jit-test/tests/basic/bug582479.js @@ -0,0 +1,5 @@ +for (b = 0; b < 2; b++) { + / / + (function(){}) +} + diff --git a/js/src/jit-test/tests/basic/bug583615.js b/js/src/jit-test/tests/basic/bug583615.js new file mode 100644 index 0000000..10ba603 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug583615.js @@ -0,0 +1,12 @@ +// |jit-test| slow; + +try { + x = + x += /x / +} catch (e) {} +for each(a in [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0]) { + x += x; +} +default xml namespace = x; + diff --git a/js/src/jit-test/tests/basic/bug583757.js b/js/src/jit-test/tests/basic/bug583757.js new file mode 100644 index 0000000..3a7f910 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug583757.js @@ -0,0 +1,24 @@ +var arr = []; + +function f() {} + +function g(n, h) { + var a = f; + if (n <= 0) + return f; + + var t = g(n - 1, h); + var r = function(x) { + if (x) + return a; + return a(h(function() { return t(); })); + }; + arr.push(r); + return r; +} + +g(80, f); +g(80, f); +g(80, f); +for (var i = 0; i < arr.length; i++) + assertEq(arr[i](1), f); diff --git a/js/src/jit-test/tests/basic/bug584499-1.js b/js/src/jit-test/tests/basic/bug584499-1.js new file mode 100644 index 0000000..bc98953 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug584499-1.js @@ -0,0 +1,6 @@ +// |jit-test| error: TypeError +var s = "12345"; +for(var i=0; i<7; i++) { + print(s[i].length); +} + diff --git a/js/src/jit-test/tests/basic/bug584499-2.js b/js/src/jit-test/tests/basic/bug584499-2.js new file mode 100644 index 0000000..bd8b0ab --- /dev/null +++ b/js/src/jit-test/tests/basic/bug584499-2.js @@ -0,0 +1,12 @@ +function f(x) { + var s = "a"; + var last = ""; + for (var i = 0; i < HOTLOOP + 2; i++) { + last = s[x]; + } + return last; +} + +f(0); + +assertEq(f(1), undefined); diff --git a/js/src/jit-test/tests/basic/bug584565.js b/js/src/jit-test/tests/basic/bug584565.js new file mode 100644 index 0000000..ad7d4b4 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug584565.js @@ -0,0 +1,10 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ +// Contributor: Luke Wagner + +var x, f; +for (var i = 0; i < 100; i++) { + f = function() {}; + f.foo; + x = f.length; +} diff --git a/js/src/jit-test/tests/basic/bug584603.js b/js/src/jit-test/tests/basic/bug584603.js new file mode 100644 index 0000000..4e76079 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug584603.js @@ -0,0 +1,13 @@ +var f = 99; + +function g(a) { + if (a) { + var e = 55; + function f() { + print("f"); + } + assertEq(f == 99, false); + } +} + +g(true); diff --git a/js/src/jit-test/tests/basic/bug585542.js b/js/src/jit-test/tests/basic/bug585542.js new file mode 100644 index 0000000..9ea3de6 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug585542.js @@ -0,0 +1,11 @@ +function f() { return 2; } +function g(o) { + with (o) { + var f = function() { return 4; } + } + return f(); +} + +assertEq(g({}), 4); + + diff --git a/js/src/jit-test/tests/basic/bug586499-regexp.js b/js/src/jit-test/tests/basic/bug586499-regexp.js new file mode 100644 index 0000000..3f7f451 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug586499-regexp.js @@ -0,0 +1,2 @@ +// Don't crash. +var re = /^(?:\s*.){0,16}/; diff --git a/js/src/jit-test/tests/basic/bug586917.js b/js/src/jit-test/tests/basic/bug586917.js new file mode 100644 index 0000000..5cefe71 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug586917.js @@ -0,0 +1,1834 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +/* The tracer should properly parse JSOP_TABLESWITCHX instructions. */ +var x = 1; +for (i = 0; i < HOTLOOP; i++) { + switch (x) { + case 2: + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + try {} catch (e) {} + } +} diff --git a/js/src/jit-test/tests/basic/bug587346-regexp-01.js b/js/src/jit-test/tests/basic/bug587346-regexp-01.js new file mode 100644 index 0000000..cf341a4 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug587346-regexp-01.js @@ -0,0 +1 @@ +var re = /(?:){1,60}/ diff --git a/js/src/jit-test/tests/basic/bug587366.js b/js/src/jit-test/tests/basic/bug587366.js new file mode 100644 index 0000000..9934d98 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug587366.js @@ -0,0 +1,3 @@ +// Test flat string replacement, per ECMAScriptv5 15.5.4.11. +assertEq("1+2".replace("1+2", "$&+3"), "1+2+3"); +assertEq(")".replace(")","*$&*"), "*)*"); diff --git a/js/src/jit-test/tests/basic/bug589318.js b/js/src/jit-test/tests/basic/bug589318.js new file mode 100644 index 0000000..98902b0 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug589318.js @@ -0,0 +1,10 @@ +// Use arguments in an eval. +code = " \ +function f(a) { var x = a; } \ +for (var i = 0; i < 10; i++) { f(5); } \ +"; + +eval(code); + + +// Test it doesn't assert. diff --git a/js/src/jit-test/tests/basic/bug590006.js b/js/src/jit-test/tests/basic/bug590006.js new file mode 100644 index 0000000..9654663 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug590006.js @@ -0,0 +1,11 @@ +function f() { + var ret; + for (var i = 0; i < 10; ++i) { + let (local = 3) { + ret = function() { print(local++); } + } + } + return ret; +} +f()(); // test.js:5: ReferenceError: local is not defined + diff --git a/js/src/jit-test/tests/basic/bug592927.js b/js/src/jit-test/tests/basic/bug592927.js new file mode 100644 index 0000000..b6412c6 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug592927.js @@ -0,0 +1,27 @@ +// vim: set ts=4 sw=4 tw=99 et: +function f(x, y) { + x(f); + assertEq(y, "hello"); +} + +function g(x) { + assertEq(x.arguments[1], "hello"); + x.arguments[1] = "bye"; + assertEq(x.arguments[1], "hello"); +} + +function f2(x, y) { + arguments; + x(f2); + assertEq(y, "bye"); +} + +function g2(x) { + assertEq(x.arguments[1], "hello"); + x.arguments[1] = "bye"; + assertEq(x.arguments[1], "bye"); +} + +f(g, "hello"); +f2(g2, "hello"); + diff --git a/js/src/jit-test/tests/basic/bug593663-regexp.js b/js/src/jit-test/tests/basic/bug593663-regexp.js new file mode 100644 index 0000000..3fe404c --- /dev/null +++ b/js/src/jit-test/tests/basic/bug593663-regexp.js @@ -0,0 +1,109 @@ +/* + * Ensure that flat matches with metachars in them don't have their metachars + * interpreted as special. + */ + +function isPatternSyntaxError(pattern) { + try { + new RegExp(pattern); + return false; + } catch (e if e instanceof SyntaxError) { + return true; + } +} + +// Bug example. +assertEq("1+2".replace("1+2", "$&+3", "g"), "1+2+3"); +assertEq("1112".replace("1+2", "", "g"), "1112"); + +// ^ +assertEq("leading text^my hat".replace("^my hat", "", "g"), "leading text"); +assertEq("my hat".replace("^my hat", "", "g"), "my hat"); + +// $ +assertEq("leading text$my money".replace("leading text$", "", "g"), "my money"); +assertEq("leading text".replace("leading text$", "", "g"), "leading text"); + +// \ +var BSL = '\\'; +assertEq(("dir C:" + BSL + "Windoze").replace("C:" + BSL, "", "g"), + "dir Windoze"); +assertEq(isPatternSyntaxError("C:" + BSL), true); + +// . +assertEq("This is a sentence. It has words.".replace(".", "!", "g"), + "This is a sentence! It has words!"); +assertEq("This is an unterminated sentence".replace(".", "", "g"), + "This is an unterminated sentence"); + +// * +assertEq("Video killed the radio *".replace(" *", "", "g"), "Video killed the radio"); +assertEq("aaa".replace("a*", "", "g"), "aaa"); + +// + +assertEq("On the + side".replace(" +", "", "g"), "On the side"); +assertEq("1111111111111".replace("1+", "", "g"), "1111111111111"); + +// \+ +assertEq(("Inverse cone head: " + BSL + "++/").replace(BSL + "+", "", "g"), + "Inverse cone head: +/"); +assertEq((BSL + BSL + BSL).replace(BSL + "+", "", "g"), + BSL + BSL + BSL); + +// \\+ +assertEq((BSL + BSL + "+").replace(BSL + BSL + "+", "", "g"), ""); +assertEq((BSL + BSL + BSL).replace(BSL + BSL + "+", "", "g"), (BSL + BSL + BSL)); + +// \\\ +assertEq((BSL + BSL + BSL + BSL).replace(BSL + BSL + BSL, "", "g"), BSL); +assertEq(isPatternSyntaxError(BSL + BSL + BSL), true); + +// \\\\ +assertEq((BSL + BSL + BSL + BSL).replace(BSL + BSL + BSL + BSL, "", "i"), ""); +assertEq((BSL + BSL).replace(BSL + BSL + BSL + BSL, "", "g"), BSL + BSL); + + +// ? +assertEq("Pressing question?".replace("?", ".", "g"), "Pressing question."); +assertEq("a".replace("a?", "", "g"), "a"); + +// ( +assertEq("(a".replace("(", "", "g"), "a"); + +// ) +assertEq("a)".replace(")", "", "g"), "a"); + +// ( and ) +assertEq("(foo)".replace("(foo)", "", "g"), ""); +assertEq("a".replace("(a)", "", "g"), "a"); + +// [ +assertEq("[a".replace("[", "", "g"), "a"); + +// ] +assertEq("a]".replace("]", "", "g"), "a"); + +// [ and ] +assertEq("a".replace("[a-z]", "", "g"), "a"); +assertEq("You would write your regexp as [a-z]".replace("[a-z]", "", "g"), + "You would write your regexp as "); + +// { +assertEq("Numbers may be specified in the interval {1,100}".replace("{1,", "", "g"), + "Numbers may be specified in the interval 100}"); + +// } +assertEq("Numbers may be specified in the interval {1,100}".replace(",100}", "", "g"), + "Numbers may be specified in the interval {1"); + +// { and } +assertEq("Numbers may be specified in the interval {1,100}".replace(" {1,100}", "", "g"), + "Numbers may be specified in the interval"); +assertEq("aaa".replace("a{1,10}", "", "g"), "aaa"); + +// | +assertEq("Mr. Gorbachev|Tear down this wall!".replace("|Tear down this wall!", "", "g"), + "Mr. Gorbachev"); +assertEq("foobar".replace("foo|bar", "", "g"), "foobar"); + +print("PASS"); diff --git a/js/src/jit-test/tests/basic/bug594108.js b/js/src/jit-test/tests/basic/bug594108.js new file mode 100644 index 0000000..3a250db --- /dev/null +++ b/js/src/jit-test/tests/basic/bug594108.js @@ -0,0 +1,8 @@ +var res; +for (var i = 0; i < 10; i++) { + var re = /a(b)c/; + var b = (re.exec(""), v = re.exec("abc")) !== null; + assertEq(v[0], "abc"); + assertEq(v[1], "b"); +} + diff --git a/js/src/jit-test/tests/basic/bug594205.js b/js/src/jit-test/tests/basic/bug594205.js new file mode 100644 index 0000000..beaeaa1 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug594205.js @@ -0,0 +1,16 @@ +var re = /a(b)c/; + +for (var i = 0; i < 10; i++) { + // These two are of a form where we can convert exec() to test(). + if (!re.exec("abc")) print("huh?"); + re.exec("abc"); +} + +RegExp.prototype.test = 1; + +for (var i = 0; i < 10; i++) { + // These two are the same form, but we've replaced test(), so we must + // not convert. + if (!re.exec("abc")) print("huh?"); // don't crash/assert + re.exec("abc"); // don't crash/assert +} diff --git a/js/src/jit-test/tests/basic/bug595963-1.js b/js/src/jit-test/tests/basic/bug595963-1.js new file mode 100644 index 0000000..2cccfac --- /dev/null +++ b/js/src/jit-test/tests/basic/bug595963-1.js @@ -0,0 +1,19 @@ +function remove(k, L) { + for (var i in k) { + if (i == L) + k.splice(L, 1); + } +} +function f(k) { + var L = 0; + for (var i in k) { + if (L == 1) + remove(k, L); + L++; + assertEq(k[i], 3); + } + assertEq(L, 6); +} + +var a = [3, 3, 3, 3, 3, 3, 3]; +f(a); diff --git a/js/src/jit-test/tests/basic/bug595963-2.js b/js/src/jit-test/tests/basic/bug595963-2.js new file mode 100644 index 0000000..651a380 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug595963-2.js @@ -0,0 +1,19 @@ +function remove(k, L) { + for (var i in k) { + if (i == L) + k.splice(L, 3); + } +} +function f(k) { + var L = 0; + for (var i in k) { + if (L == 1) + remove(k, L); + L++; + assertEq(k[i], 3); + } + assertEq(L, 4); +} + +var a = [3, 3, 3, 3, 3, 3, 3]; +f(a); diff --git a/js/src/jit-test/tests/basic/bug596502-version.js b/js/src/jit-test/tests/basic/bug596502-version.js new file mode 100644 index 0000000..dbc4344 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug596502-version.js @@ -0,0 +1,23 @@ +/* All versions >= 1.6. */ + +function syntaxErrorFromXML() { + try { + var f = new Function('var text = .toString();'); + return false; + } catch (e if e instanceof SyntaxError) { + return true; + } +} + +version(150); +assertEq(syntaxErrorFromXML(), true); +revertVersion(); + +for (vno in {160: null, 170: null, 180: null}) { + print('Setting version to: ' + vno); + version(vno); + assertEq(syntaxErrorFromXML(), false); + revertVersion(); +} + +print('PASS!') diff --git a/js/src/jit-test/tests/basic/bug599854.js b/js/src/jit-test/tests/basic/bug599854.js new file mode 100644 index 0000000..19e3f7c --- /dev/null +++ b/js/src/jit-test/tests/basic/bug599854.js @@ -0,0 +1,4 @@ +load(libdir + 'eqArrayHelper.js'); +assertEqArray(/(?:(?:(")(c)")?)*/.exec('"c"'), [ '"c"', '"', "c" ]); +assertEqArray(/(?:(?:a*?(")(c)")?)*/.exec('"c"'), [ '"c"', '"', "c" ]); +assertEqArray(/]*type=['"]?(?:dojo\/|text\/html\b))(?:[^>]*?(?:src=(['"]?)([^>]*?)\1[^>]*)?)*>([\s\S]*?)<\/script>/gi.exec(''), ['', '"', "...", ""]); diff --git a/js/src/jit-test/tests/basic/bug601046.js b/js/src/jit-test/tests/basic/bug601046.js new file mode 100644 index 0000000..45f3bf8 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug601046.js @@ -0,0 +1,8 @@ +// don't assert +var f = function(){}; +for (var p in f); +Object.defineProperty(f, "j", ({configurable: true, value: "a"})); +Object.defineProperty(f, "k", ({configurable: true, value: "b"})); +Object.defineProperty(f, "j", ({configurable: true, get: function() {}})); +delete f.k; +Object.defineProperty(f, "j", ({configurable: false})); diff --git a/js/src/jit-test/tests/basic/bug601395.js b/js/src/jit-test/tests/basic/bug601395.js new file mode 100644 index 0000000..cdf61a3 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug601395.js @@ -0,0 +1,2 @@ +// |jit-test| error: SyntaxError; +let(y = let(d = []) u, x diff --git a/js/src/jit-test/tests/basic/bug601398.js b/js/src/jit-test/tests/basic/bug601398.js new file mode 100644 index 0000000..e6276ee --- /dev/null +++ b/js/src/jit-test/tests/basic/bug601398.js @@ -0,0 +1,7 @@ +(function () { + try {} finally { + let(z) { + return; + } + } +})() diff --git a/js/src/jit-test/tests/basic/bug601401.js b/js/src/jit-test/tests/basic/bug601401.js new file mode 100644 index 0000000..0ee7dda --- /dev/null +++ b/js/src/jit-test/tests/basic/bug601401.js @@ -0,0 +1,5 @@ +let(e) { + with({}) try {} catch (x) {} finally { + let(y) {} + } +} diff --git a/js/src/jit-test/tests/basic/bug601402.js b/js/src/jit-test/tests/basic/bug601402.js new file mode 100644 index 0000000..33bda5a --- /dev/null +++ b/js/src/jit-test/tests/basic/bug601402.js @@ -0,0 +1,2 @@ +// |jit-test| error: SyntaxError; +for (let d in [(0)]) let(b = (let(e) {}), d diff --git a/js/src/jit-test/tests/basic/bug601428.js b/js/src/jit-test/tests/basic/bug601428.js new file mode 100644 index 0000000..b9419f8 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug601428.js @@ -0,0 +1,2 @@ +// |jit-test| error: SyntaxError; +let({}=[c for(x in[])]){let diff --git a/js/src/jit-test/tests/basic/bug602088.js b/js/src/jit-test/tests/basic/bug602088.js new file mode 100644 index 0000000..283b546 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug602088.js @@ -0,0 +1,6 @@ +// |jit-test| error: TypeError +/* vim: set ts=4 sw=4 tw=99 et: */ + +var p = Proxy.createFunction({}, function(x, y) { undefined.x(); }); +print(new p(1, 2)); + diff --git a/js/src/jit-test/tests/basic/bug605015.js b/js/src/jit-test/tests/basic/bug605015.js new file mode 100644 index 0000000..a35f7b6 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug605015.js @@ -0,0 +1,9 @@ +// |jit-test| error: TypeError +// don't assert + +print(this.watch("x", +function() { + Object.defineProperty(this, "x", ({ + get: (Int8Array) + })) +}))(x = /x/) diff --git a/js/src/jit-test/tests/basic/bug605754-regexp.js b/js/src/jit-test/tests/basic/bug605754-regexp.js new file mode 100644 index 0000000..9acd314 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug605754-regexp.js @@ -0,0 +1,2 @@ +var result = "foobarbaz".replace(/foo(bar)?bar/, "$1"); +assertEq(result, "baz"); diff --git a/js/src/jit-test/tests/basic/bug606083.js b/js/src/jit-test/tests/basic/bug606083.js new file mode 100644 index 0000000..fc2594b --- /dev/null +++ b/js/src/jit-test/tests/basic/bug606083.js @@ -0,0 +1,32 @@ +// vim: set ts=4 sw=4 tw=99 et: +function f(L) { + do { + L: for (var i = 0; i < L; i++) { + break L; + } + } while (0); +} +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); +f(1); diff --git a/js/src/jit-test/tests/basic/bug606882-1.js b/js/src/jit-test/tests/basic/bug606882-1.js new file mode 100644 index 0000000..3d8bdf4 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug606882-1.js @@ -0,0 +1,3 @@ +// don't crash + +"ABC".match("A+(?:X?(?:|(?:))(?:(?:B)?C+w?w?)?)*"); diff --git a/js/src/jit-test/tests/basic/bug606882-2.js b/js/src/jit-test/tests/basic/bug606882-2.js new file mode 100644 index 0000000..b754217 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug606882-2.js @@ -0,0 +1,16 @@ +// don't crash +var book = 'Ps'; +var pattern = "(?:" ++ "(?:" ++ "(?:" ++ "(?:-|)" ++ "\\s?" ++ ")" ++ "|" ++ ")" ++ " ?" ++ "\\d+" ++ "\\w?" ++ ")*"; +var re = new RegExp(pattern); +'8:5-8'.match(re); diff --git a/js/src/jit-test/tests/basic/bug608313.js b/js/src/jit-test/tests/basic/bug608313.js new file mode 100644 index 0000000..1bd20df --- /dev/null +++ b/js/src/jit-test/tests/basic/bug608313.js @@ -0,0 +1,11 @@ + +function testInt8Array(L) { + var f = new Int8Array(8); + f[0] = 0; // Don't assert. +} + +for (var i = 0; i < 10; i++) { + testInt8Array(0); +} + + diff --git a/js/src/jit-test/tests/basic/bug608980.js b/js/src/jit-test/tests/basic/bug608980.js new file mode 100644 index 0000000..53ad2cb --- /dev/null +++ b/js/src/jit-test/tests/basic/bug608980.js @@ -0,0 +1,11 @@ + +/* Don't trip bogus assert. */ + +function foo() +{ + var x; + while (x = 0) { + x = 1; + } +} +foo(); diff --git a/js/src/jit-test/tests/basic/bug609502-1.js b/js/src/jit-test/tests/basic/bug609502-1.js new file mode 100644 index 0000000..72cf965 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug609502-1.js @@ -0,0 +1,9 @@ +for(var i = 0; i < RUNLOOP; i++) { + x = ''.charCodeAt(NaN); +} + +for(var i = 0; i < RUNLOOP; i++) { + x = ''.charAt(NaN); +} + +// Don't assert diff --git a/js/src/jit-test/tests/basic/bug609502-2.js b/js/src/jit-test/tests/basic/bug609502-2.js new file mode 100644 index 0000000..7998d84 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug609502-2.js @@ -0,0 +1,5 @@ +for (var i = 0; i < RUNLOOP; i++) { + Math.abs(-2147483648) +} + +// Don't assert diff --git a/js/src/jit-test/tests/basic/bug609502-3.js b/js/src/jit-test/tests/basic/bug609502-3.js new file mode 100644 index 0000000..7c9436d --- /dev/null +++ b/js/src/jit-test/tests/basic/bug609502-3.js @@ -0,0 +1,11 @@ +{ + function a() {} +} +Math.floor(Math.d) + function c() {} + c() + for each(let b in [0, 0, 0, 0, 0, 0, 0, -2147483648]) { + print(Math.abs(b)) + } + +// Don't assert diff --git a/js/src/jit-test/tests/basic/bug610592.js b/js/src/jit-test/tests/basic/bug610592.js new file mode 100644 index 0000000..da825d2 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug610592.js @@ -0,0 +1,29 @@ + +/* Don't confuse JIT code by making slow arrays that use inline slots inconsistently. */ + +function foo(a) +{ + assertEq(a.x, 5); +} + +function bar() +{ + for (var i = 0; i < 50; i++) { + var a = []; + a[i] = 0; + delete a[i]; + a.x = 5; + foo(a); + } + + var b = [1,,2,,3,,4,,5]; + assertEq(b.toString(), "1,,2,,3,,4,,5"); + b.x = 0; + assertEq(b.toString(), "1,,2,,3,,4,,5"); + delete b.x; + delete b[8]; + delete b[6]; + delete b[4]; + assertEq(b.toString(), "1,,2,,,,,,"); +} +bar(); diff --git a/js/src/jit-test/tests/basic/bug613122.js b/js/src/jit-test/tests/basic/bug613122.js new file mode 100644 index 0000000..a28b40f --- /dev/null +++ b/js/src/jit-test/tests/basic/bug613122.js @@ -0,0 +1,4 @@ +var a = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +a.push(1); +a.splice(0); +a.d = ""; diff --git a/js/src/jit-test/tests/basic/bug613151.js b/js/src/jit-test/tests/basic/bug613151.js new file mode 100644 index 0000000..cc2f1fa --- /dev/null +++ b/js/src/jit-test/tests/basic/bug613151.js @@ -0,0 +1,18 @@ +// Iterating over a property with an XML id. +function n() {} +function g() {} +eval("\ + function a() {}\ + function b() {\ + for (w in this) {}\ + Object.defineProperty(\ + this, \ + new QName, \ + ({enumerable: true})\ + )\ + }\ + for (z in [0, 0, 0]) b()\ +") + +// Test it doesn't assert. + diff --git a/js/src/jit-test/tests/basic/bug613399.js b/js/src/jit-test/tests/basic/bug613399.js new file mode 100644 index 0000000..b2431c9 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug613399.js @@ -0,0 +1,3 @@ +// don't assert +/((?=()+))?/.exec(""); + diff --git a/js/src/jit-test/tests/basic/bug614915.js b/js/src/jit-test/tests/basic/bug614915.js new file mode 100644 index 0000000..b4ab949 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug614915.js @@ -0,0 +1,2 @@ +var s = [undefined, undefined].sort(); +assertEq(s.length, 2); diff --git a/js/src/jit-test/tests/basic/bug616762.js b/js/src/jit-test/tests/basic/bug616762.js new file mode 100644 index 0000000..89b8ddd --- /dev/null +++ b/js/src/jit-test/tests/basic/bug616762.js @@ -0,0 +1,26 @@ +// vim: set ts=4 sw=4 tw=99 et: +document = { + ready: function (x) { + this.exec = x; + } +}; + +var $ = function (x) { + return document; +}; + +(function ($) { + eval("(function(){\n" + + " var Private={};\n" + + " $(document).ready(function(){\n" + + " init()\n" + + " });\n" + + " function init(){\n" + + " $(Private)\n" + + " };\n" + + "})();"); +})($); +document.exec(); + +// Don't crash or assert. + diff --git a/js/src/jit-test/tests/basic/bug617139.js b/js/src/jit-test/tests/basic/bug617139.js new file mode 100644 index 0000000..d53456e --- /dev/null +++ b/js/src/jit-test/tests/basic/bug617139.js @@ -0,0 +1,9 @@ +// |jit-test| error: InternalError +// don't assert + +gczeal(2) +function x() { + [null].some(x) +} +x(); + diff --git a/js/src/jit-test/tests/basic/bug617171.js b/js/src/jit-test/tests/basic/bug617171.js new file mode 100644 index 0000000..c4305f9 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug617171.js @@ -0,0 +1,4 @@ +var a = 6; +Object.defineProperty(this, "a", {writable: false}); +a = 7; +assertEq(a, 6); diff --git a/js/src/jit-test/tests/basic/bug618350.js b/js/src/jit-test/tests/basic/bug618350.js new file mode 100644 index 0000000..61e72d0 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug618350.js @@ -0,0 +1,24 @@ + +var global = 0; + +Object.defineProperty(Object.prototype, 0, {set: function() { global++; }}); + +for (var x = 0; x < 20; ++x) + [1,2]; +assertEq(global, 0); + +Object.defineProperty(Object.prototype, 1, {set: function() { global++; }}); + +for (var x = 0; x < 20; ++x) + [1,2]; +assertEq(global, 0); + +Object.defineProperty(Object.prototype, "b", {set: function() { global++; }}); + +for (var x = 0; x < 20; ++x) { + var s = { a:0, b:1, 0: 2, 1: 3 }; +} +assertEq(global, 0); + +assertEq([42][0], 42); +assertEq([42].length, 1); diff --git a/js/src/jit-test/tests/basic/bug618577.js b/js/src/jit-test/tests/basic/bug618577.js new file mode 100644 index 0000000..37c78f5 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug618577.js @@ -0,0 +1,5 @@ +var x = Uint32Array(); +for (var i = 0; i < 100; i++) + x[77] = x[77]; + +// Don't assert. diff --git a/js/src/jit-test/tests/basic/bug619004.js b/js/src/jit-test/tests/basic/bug619004.js new file mode 100644 index 0000000..8c7cec4 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug619004.js @@ -0,0 +1,4 @@ +// don't crash +gczeal(2) +evalcx('split') + diff --git a/js/src/jit-test/tests/basic/bug620532.js b/js/src/jit-test/tests/basic/bug620532.js new file mode 100644 index 0000000..4a2f6f6 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug620532.js @@ -0,0 +1,15 @@ +for (var i = 0; i < 20; i++) { + m = Math.min(0xffffffff, 0); +} +assertEq(m == 0, true); + +var buffer = new ArrayBuffer(4); +var int32View = new Int32Array(buffer); +var uint32View = new Uint32Array(buffer); +int32View[0] = -1; +var m; +for (var i = 0; i < 20; i++) { + m = Math.min(uint32View[0], 0); // uint32View[0] == 0xffffffff +} +assertEq(m == 0, true); + diff --git a/js/src/jit-test/tests/basic/bug620838.js b/js/src/jit-test/tests/basic/bug620838.js new file mode 100644 index 0000000..c82933a --- /dev/null +++ b/js/src/jit-test/tests/basic/bug620838.js @@ -0,0 +1,22 @@ +function g() { + return "global"; +} + +function q(fun) { + return fun(); +} + +function f(x) { + if (x) { + function g() { + return "local"; + } + var ans = q(function() { + return g(); + }); + } + g = null; + return ans; +} + +assertEq(f(true), "local"); diff --git a/js/src/jit-test/tests/basic/bug621022-1.js b/js/src/jit-test/tests/basic/bug621022-1.js new file mode 100644 index 0000000..aab5bf9 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug621022-1.js @@ -0,0 +1,14 @@ +function f(x) { + delete arguments[0]; + undefined != arguments[0]; + undefined == arguments[0]; + undefined != arguments[0]; + undefined === arguments[0]; +} + +for(var i=0; i<20; i++) { + f(1); +} + +// Don't assert. + diff --git a/js/src/jit-test/tests/basic/bug621022-2.js b/js/src/jit-test/tests/basic/bug621022-2.js new file mode 100644 index 0000000..0f3549c --- /dev/null +++ b/js/src/jit-test/tests/basic/bug621022-2.js @@ -0,0 +1,13 @@ +function f(j) { + var a = [[1],[1],[1],[1],[1],[1],[1],[1],[1],arguments]; + var b; + for (var i = 0; i < a.length; i++) { + delete a[i][0]; + b = arguments[0]; + } + assertEq(b === undefined, true); +} + +f(1); + + diff --git a/js/src/jit-test/tests/basic/bug623859.js b/js/src/jit-test/tests/basic/bug623859.js new file mode 100644 index 0000000..1831869 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug623859.js @@ -0,0 +1,16 @@ +// |jit-test| allow-oom + +(function() { + Iterator((function() { + switch ((7)) { + default: + return (Float32Array).call([], 4300018) + case Proxy.create((function() { + return { + e: + function() {} + } + })): + } + })()) + })() diff --git a/js/src/jit-test/tests/basic/bug623863.js b/js/src/jit-test/tests/basic/bug623863.js new file mode 100644 index 0000000..d9ba4f7 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug623863.js @@ -0,0 +1,5 @@ +// Contributor: Christian Holler +if (typeof gczeal === 'function') gczeal(2); +Function.prototype.prototype = function() { return 42; }; +try { foo(Function); } catch (e) { } +Function.prototype.prototype = function() { return 42; }; diff --git a/js/src/jit-test/tests/basic/bug624041-1.js b/js/src/jit-test/tests/basic/bug624041-1.js new file mode 100644 index 0000000..4eef9e9 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug624041-1.js @@ -0,0 +1,8 @@ +var count = 0; + +var a = [0, 1]; +for (var i in a) { + assertEq(++count <= 1, true); + a.shift(); +} + diff --git a/js/src/jit-test/tests/basic/bug624041-2.js b/js/src/jit-test/tests/basic/bug624041-2.js new file mode 100644 index 0000000..6eb1b78 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug624041-2.js @@ -0,0 +1,11 @@ +var s = ''; + +var a = [, 0, 1]; +for (var i in a) { + a.reverse(); + s += i + ','; +} + +// Index of the element with value '0'. +assertEq(s, '1,'); + diff --git a/js/src/jit-test/tests/basic/bug625141-1.js b/js/src/jit-test/tests/basic/bug625141-1.js new file mode 100644 index 0000000..9f79cf7 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug625141-1.js @@ -0,0 +1,13 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +function f() { + var arr = new Int32Array(10); + x = function () { return arr.length; } + for (var i = 0; i < arr.length; i++) { + arr[i] = i; + } + assertEq(arr[5], 5); +} +f(); diff --git a/js/src/jit-test/tests/basic/bug625141-2.js b/js/src/jit-test/tests/basic/bug625141-2.js new file mode 100644 index 0000000..d97cdf4 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug625141-2.js @@ -0,0 +1,13 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +function f() { + var arr = new Int8Array(10); + x = function () { return arr.length; } + for (var i = 0; i < arr.length; i++) { + arr[i] = i; + } + assertEq(arr[5], 5); +} +f(); diff --git a/js/src/jit-test/tests/basic/bug625399.js b/js/src/jit-test/tests/basic/bug625399.js new file mode 100644 index 0000000..e45cf21 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug625399.js @@ -0,0 +1,7 @@ +function a(bb) { + "use strict"; + return; + this.d = function() { bb; }; +} +for (var i = 0; i <= RUNLOOP; i++) + a(); diff --git a/js/src/jit-test/tests/basic/bug627609.js b/js/src/jit-test/tests/basic/bug627609.js new file mode 100644 index 0000000..c36a995 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug627609.js @@ -0,0 +1,2 @@ +load(libdir + 'eqArrayHelper.js'); +assertEqArray(/((a|)+b)+/.exec('bb'), [ "bb", "b", "" ]); diff --git a/js/src/jit-test/tests/basic/bug627692-1.js b/js/src/jit-test/tests/basic/bug627692-1.js new file mode 100644 index 0000000..a895288 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug627692-1.js @@ -0,0 +1,19 @@ +var loop1 = '', loop2 = '', actual = ''; + +var obj = {}; +for (var i = 0; i < HOTLOOP + 2; i++) { + obj['a' + i] = i; + loop1 += i; + loop2 += 'a' + i; +} + +Object.defineProperty(obj, 'z', {enumerable: true, get: function () { + for (var y in obj) + actual += y; + }}); +(function() { + for each (var e in obj) + actual += e; + })(); + +assertEq(actual, loop1 + loop2 + "z" + "undefined"); diff --git a/js/src/jit-test/tests/basic/bug627692-2.js b/js/src/jit-test/tests/basic/bug627692-2.js new file mode 100644 index 0000000..3c60331 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug627692-2.js @@ -0,0 +1,28 @@ +N = 0; +function n() {} +s = n; +function f(foo) { + gc(); + try { + (Function(foo))(); + } catch(r) {} + delete this.Math; +} +function g() {} +var c; +function y() {} +t = b = eval; +f("\ + __defineGetter__(\"\",\ + function(p){\ + for(var s in this) {}\ + }\ + )[\"\"]\ +"); +f("\ + do;\ + while(([\ + \"\" for each(z in this)\ + ])&0)\ +"); +f(); diff --git a/js/src/jit-test/tests/basic/bug630377.js b/js/src/jit-test/tests/basic/bug630377.js new file mode 100644 index 0000000..8fe97e2 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug630377.js @@ -0,0 +1,7 @@ +var a = []; +for (var i = 0; i < RUNLOOP; i++) + a[i] = 0; +var b = #1=[x === "0" && (#1#.slow = 1) for (x in a)]; +assertEq(b[0], 1); +for (var i = 1; i < RUNLOOP; i++) + assertEq(b[i], false); diff --git a/js/src/jit-test/tests/basic/bug630865-1.js b/js/src/jit-test/tests/basic/bug630865-1.js new file mode 100644 index 0000000..5203d13 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug630865-1.js @@ -0,0 +1,6 @@ +Object.defineProperty(Function.prototype, "prototype", {set:function(){}}); +var x; +for (var i = 0; i < HOTLOOP + 2; i++) + x = new Function.prototype; +assertEq(toString.call(x), "[object Object]"); +assertEq(Object.getPrototypeOf(x), Object.prototype); diff --git a/js/src/jit-test/tests/basic/bug630865-2.js b/js/src/jit-test/tests/basic/bug630865-2.js new file mode 100644 index 0000000..4616891 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug630865-2.js @@ -0,0 +1,6 @@ +Function.prototype.prototype = function () {}; +var x; +for (var i = 0; i < HOTLOOP + 2; i++) + x = new Function.prototype; +assertEq(toString.call(x), "[object Object]"); +assertEq(Object.getPrototypeOf(x), Function.prototype.prototype); diff --git a/js/src/jit-test/tests/basic/bug630865-3.js b/js/src/jit-test/tests/basic/bug630865-3.js new file mode 100644 index 0000000..5933b2c --- /dev/null +++ b/js/src/jit-test/tests/basic/bug630865-3.js @@ -0,0 +1,12 @@ +var a = []; +function next() { + var x = {}; + a.push(x); + return x; +} +Object.defineProperty(Function.prototype, 'prototype', {get: next}); +var b = []; +for (var i = 0; i < HOTLOOP + 2; i++) + b[i] = new Function.prototype; +for (var i = 0; i < HOTLOOP + 2; i++) + assertEq(Object.getPrototypeOf(b[i]), a[i]); diff --git a/js/src/jit-test/tests/basic/bug630865-4.js b/js/src/jit-test/tests/basic/bug630865-4.js new file mode 100644 index 0000000..fd9f8b5 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug630865-4.js @@ -0,0 +1,10 @@ +Object.defineProperty(Function.prototype, 'prototype', + {get: function () { if (i == HOTLOOP + 1) throw "X"; }}); +var x; +try { + for (var i = 0; i < HOTLOOP + 2; i++) + x = new Function.prototype; +} catch (exc) { + assertEq(i, HOTLOOP + 1); + assertEq(exc, "X"); +} diff --git a/js/src/jit-test/tests/basic/bug630865-5.js b/js/src/jit-test/tests/basic/bug630865-5.js new file mode 100644 index 0000000..7057ab2 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug630865-5.js @@ -0,0 +1,13 @@ +function C(a, b) { + this.a = a; + this.b = b; +} +var f = C.bind(null, 2); +Object.defineProperty(f, "prototype", {get: function () { throw "FAIL"; }}); +var x; +for (var i = 0; i < HOTLOOP + 2; i++) + x = new f(i); +assertEq(toString.call(x), "[object Object]"); +assertEq(Object.getPrototypeOf(x), C.prototype); +assertEq(x.a, 2); +assertEq(x.b, HOTLOOP + 1); diff --git a/js/src/jit-test/tests/basic/bug630865-6.js b/js/src/jit-test/tests/basic/bug630865-6.js new file mode 100644 index 0000000..2080726 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug630865-6.js @@ -0,0 +1,11 @@ +var a = []; +var x, i; +for (i = 0; i < HOTLOOP + 10; i++) { + a[i] = function (b) { this.b = b; }; + if (i != HOTLOOP + 9) + x = a[i].prototype; +} +for (i = 0; i < HOTLOOP + 10; i++) + x = new a[i]; +assertEq(toString.call(x), "[object Object]"); +assertEq(Object.getPrototypeOf(x), a[HOTLOOP + 9].prototype); diff --git a/js/src/jit-test/tests/basic/bug631082.js b/js/src/jit-test/tests/basic/bug631082.js new file mode 100644 index 0000000..61db35a --- /dev/null +++ b/js/src/jit-test/tests/basic/bug631082.js @@ -0,0 +1,13 @@ +var t; +(function () { + t = (function() { + yield k(); + })(); + function h() { + } + function k() { + return function() { h(); }; + } +})(); +t.next(); + diff --git a/js/src/jit-test/tests/basic/bug631219.js b/js/src/jit-test/tests/basic/bug631219.js new file mode 100644 index 0000000..5b33919 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug631219.js @@ -0,0 +1,10 @@ +// don't assert or crash +function g(o) { + o.__proto__ = arguments; + o.length = 123; +} +function f() { + g(arguments); +} +f(); + diff --git a/js/src/jit-test/tests/basic/bug631305.js b/js/src/jit-test/tests/basic/bug631305.js new file mode 100644 index 0000000..b0cbbbb --- /dev/null +++ b/js/src/jit-test/tests/basic/bug631305.js @@ -0,0 +1,9 @@ +var n = 0; +var a = []; +for (var i = 0; i < 20; i++) + a[i] = {}; +a[18].watch("p", function () { n++; }); +delete a[18].p; +for (var i = 0; i < 20; i++) + a[i].p = 0; +assertEq(n, 1); diff --git a/js/src/jit-test/tests/basic/bug631788.js b/js/src/jit-test/tests/basic/bug631788.js new file mode 100644 index 0000000..503d32f --- /dev/null +++ b/js/src/jit-test/tests/basic/bug631788.js @@ -0,0 +1 @@ +for (var j = 1; j < 10; ++j) { switch(0/j) { } } // don't assert diff --git a/js/src/jit-test/tests/basic/bug632206.js b/js/src/jit-test/tests/basic/bug632206.js new file mode 100644 index 0000000..d98c88b --- /dev/null +++ b/js/src/jit-test/tests/basic/bug632206.js @@ -0,0 +1,6 @@ +// don't crash +x = +for (a = 0; a < 9; a++) { + x.elements() +} + diff --git a/js/src/jit-test/tests/basic/bug632901.js b/js/src/jit-test/tests/basic/bug632901.js new file mode 100644 index 0000000..c0d5a4d --- /dev/null +++ b/js/src/jit-test/tests/basic/bug632901.js @@ -0,0 +1,9 @@ +// don't crash when tracing +function f(o) { + var prop = "arguments"; + f[prop] = f[prop]; +} +for(var i=0; i<10; i++) { + f(); +} + diff --git a/js/src/jit-test/tests/basic/bug632964-regexp.js b/js/src/jit-test/tests/basic/bug632964-regexp.js new file mode 100644 index 0000000..7151d37 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug632964-regexp.js @@ -0,0 +1,17 @@ +// |jit-test| error: InternalError: regular expression too complex + +var sText = "s"; + +for (var i = 0; i < 250000; ++i) + sText += 'a\n'; + +sText += 'e'; + +var start = new Date(); +var match = sText.match(/s(\s|.)*?e/gi); +//var match = sText.match(/s([\s\S]*?)e/gi); +//var match = sText.match(/s(?:[\s\S]*?)e/gi); +var end = new Date(); +print(end - start); + +assertEq(match.length, 1); diff --git a/js/src/jit-test/tests/basic/bug633409-1.js b/js/src/jit-test/tests/basic/bug633409-1.js new file mode 100644 index 0000000..1f65ccc --- /dev/null +++ b/js/src/jit-test/tests/basic/bug633409-1.js @@ -0,0 +1,13 @@ +// vim: set ts=4 sw=4 tw=99 et: +x = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 }; + +for (i in x) + delete x.d; + +x = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 }; +y = []; +for (i in x) + y.push(i) + +assertEq(y[3], "d"); + diff --git a/js/src/jit-test/tests/basic/bug633409-2.js b/js/src/jit-test/tests/basic/bug633409-2.js new file mode 100644 index 0000000..349af46 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug633409-2.js @@ -0,0 +1,13 @@ +// vim: set ts=4 sw=4 tw=99 et: + +var o1 = {p1: 1}; +var o2 = {p1: 1, p2: 2}; + +for(var x in o1) { + for(var y in o2) { + delete o2.p2; + } +} + +/* Don't fail cx->enumerators == obj assert, see bug comment #31 */ + diff --git a/js/src/jit-test/tests/basic/bug633752.js b/js/src/jit-test/tests/basic/bug633752.js new file mode 100644 index 0000000..522f642 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug633752.js @@ -0,0 +1,11 @@ +function f(o) { + var p = "arguments"; + for(var i=0; i<10; i++) { + f[p]; + } +} +f({}); +f({}); +f({}); +f({}); + diff --git a/js/src/jit-test/tests/basic/bug633890.js b/js/src/jit-test/tests/basic/bug633890.js new file mode 100644 index 0000000..11b60a8 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug633890.js @@ -0,0 +1,9 @@ +// |jit-test| error:Error +var p = /./, x = resolver({}, p), y = resolver({lastIndex: 2}, p), v; +var a = []; +for (var i = 0; i < HOTLOOP; i++) + a[i] = x; +a[HOTLOOP] = y; +for (i = 0; i < a.length; i++) + v = a[i].lastIndex; +assertEq(v, 2); // fails due to bug 458271 diff --git a/js/src/jit-test/tests/basic/bug634593.js b/js/src/jit-test/tests/basic/bug634593.js new file mode 100644 index 0000000..b4241a8 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug634593.js @@ -0,0 +1,4 @@ +this.__defineGetter__("x3", Function); +parseInt = x3; +parseInt.prototype = []; +for (var z = 0; z < 10; ++z) { new parseInt() } \ No newline at end of file diff --git a/js/src/jit-test/tests/basic/bug635417.js b/js/src/jit-test/tests/basic/bug635417.js new file mode 100644 index 0000000..94dd101 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug635417.js @@ -0,0 +1,2 @@ +assertEq(/^@(A*)x(B)*/.test("@xB"), true); + diff --git a/js/src/jit-test/tests/basic/call.js b/js/src/jit-test/tests/basic/call.js new file mode 100644 index 0000000..8e6b647 --- /dev/null +++ b/js/src/jit-test/tests/basic/call.js @@ -0,0 +1,28 @@ +function glob_f1() { + return 1; +} +function glob_f2() { + return glob_f1(); +} +function call() +{ + var q1 = 0, q2 = 0, q3 = 0, q4 = 0, q5 = 0; + var o = {}; + function f1() { + return 1; + } + function f2(f) { + return f(); + } + o.f = f1; + for (var i = 0; i < 100; ++i) { + q1 += f1(); + q2 += f2(f1); + q3 += glob_f1(); + q4 += o.f(); + q5 += glob_f2(); + } + var ret = String([q1, q2, q3, q4, q5]); + return ret; +} +assertEq(call(), "100,100,100,100,100"); diff --git a/js/src/jit-test/tests/basic/call2.js b/js/src/jit-test/tests/basic/call2.js new file mode 100644 index 0000000..9e68bb2 --- /dev/null +++ b/js/src/jit-test/tests/basic/call2.js @@ -0,0 +1,13 @@ +function g(x) { + if ((x & 1) == 1) return 1; + return 2; +} + +function f(n) { + var q = 0; + for (var i = 0; i < n; i++) + q += g(i); + return q; +} + +assertEq(f(1000), 1500); diff --git a/js/src/jit-test/tests/basic/createMandelSet.js b/js/src/jit-test/tests/basic/createMandelSet.js new file mode 100644 index 0000000..9898b5d --- /dev/null +++ b/js/src/jit-test/tests/basic/createMandelSet.js @@ -0,0 +1,242 @@ +// |jit-test| slow; + +// XXXbz I would dearly like to wrap it up into a function to avoid polluting +// the global scope, but the function ends up heavyweight, and then we lose on +// the jit. +load(libdir + "mandelbrot-results.js"); +//function testMandelbrotAll() { + // Configuration options that affect which codepaths we follow. + var doImageData = true; + var avoidSparseArray = true; + + // Control of iteration numbers and sizing. We'll do + // scaler * colorNames.length iterations or so before deciding that we + // don't escape. + const scaler = 5; + const numRows = 600; + const numCols = 600; + + const colorNames = [ + "black", + "green", + "blue", + "red", + "purple", + "orange", + "cyan", + "yellow", + "magenta", + "brown", + "pink", + "chartreuse", + "darkorange", + "crimson", + "gray", + "deeppink", + "firebrick", + "lavender", + "lawngreen", + "lightsalmon", + "lime", + "goldenrod" + ]; + const threshold = (colorNames.length - 1) * scaler; + + // Now set up our colors + var colors = []; + // 3-part for loop (iterators buggy, we will add a separate test for them) + for (var colorNameIdx = 0; colorNameIdx < colorNames.length; ++colorNameIdx) { + //for (var colorNameIdx in colorNames) { + colorNameIdx = parseInt(colorNameIdx); + colors.push([colorNameIdx, colorNameIdx, colorNameIdx, 0]); + } + + // Storage for our point data + var points; + + var scratch = {}; + var scratchZ = {}; + function complexMult(a, b) { + var newr = a.r * b.r - a.i * b.i; + var newi = a.r * b.i + a.i * b.r; + scratch.r = newr; + scratch.i = newi; + return scratch; + } + function complexAdd(a, b) { + scratch.r = a.r + b.r; + scratch.i = a.i + b.i; + return scratch; + } + function abs(a) { + return Math.sqrt(a.r * a.r + a.i * a.i); + } + + function escapeAbsDiff(normZ, absC) { + var absZ = Math.sqrt(normZ); + return normZ > absZ + absC; + } + + function escapeNorm2(normZ) { + return normZ > 4; + } + + function fuzzyColors(i) { + return Math.floor(i / scaler) + 1; + } + + function moddedColors(i) { + return (i % (colorNames.length - 1)) + 1; + } + + function computeEscapeSpeedObjects(real, imag) { + var c = { r: real, i: imag } + scratchZ.r = scratchZ.i = 0; + var absC = abs(c); + for (var i = 0; i < threshold; ++i) { + scratchZ = complexAdd(c, complexMult(scratchZ, scratchZ)); + if (escape(scratchZ.r * scratchZ.r + scratchZ.i * scratchZ.i, + absC)) { + return colorMap(i); + } + } + return 0; + } + + function computeEscapeSpeedOneObject(real, imag) { + // fold in the fact that we start with 0 + var r = real; + var i = imag; + var absC = abs({r: real, i: imag}); + for (var j = 0; j < threshold; ++j) { + var r2 = r * r; + var i2 = i * i; + if (escape(r2 + i2, absC)) { + return colorMap(j); + } + i = 2 * r * i + imag; + r = r2 - i2 + real; + } + return 0; + } + + function computeEscapeSpeedDoubles(real, imag) { + // fold in the fact that we start with 0 + var r = real; + var i = imag; + var absC = Math.sqrt(real * real + imag * imag); + for (var j = 0; j < threshold; ++j) { + var r2 = r * r; + var i2 = i * i; + if (escape(r2 + i2, absC)) { + return colorMap(j); + } + i = 2 * r * i + imag; + r = r2 - i2 + real; + } + return 0; + } + + var computeEscapeSpeed = computeEscapeSpeedDoubles; + var escape = escapeNorm2; + var colorMap = fuzzyColors; + + function addPointOrig(pointArray, n, i, j) { + if (!points[n]) { + points[n] = []; + points[n].push([i, j, 1, 1]); + } else { + var point = points[n][points[n].length-1]; + if (point[0] == i && point[1] == j - point[3]) { + ++point[3]; + } else { + points[n].push([i, j, 1, 1]); + } + } + } + + function addPointImagedata(pointArray, n, col, row) { + var slotIdx = ((row * numCols) + col) * 4; + pointArray[slotIdx] = colors[n][0]; + pointArray[slotIdx+1] = colors[n][1]; + pointArray[slotIdx+2] = colors[n][2]; + pointArray[slotIdx+3] = colors[n][3]; + } + + function createMandelSet() { + var realRange = { min: -2.1, max: 1 }; + var imagRange = { min: -1.5, max: 1.5 }; + + var addPoint; + if (doImageData) { + addPoint = addPointImagedata; + points = new Array(4*numCols*numRows); + if (avoidSparseArray) { + for (var idx = 0; idx < 4*numCols*numRows; ++idx) { + points[idx] = 0; + } + } + } else { + addPoint = addPointOrig; + points = []; + } + var realStep = (realRange.max - realRange.min)/numCols; + var imagStep = (imagRange.min - imagRange.max)/numRows; + for (var i = 0, curReal = realRange.min; + i < numCols; + ++i, curReal += realStep) { + for (var j = 0, curImag = imagRange.max; + j < numRows; + ++j, curImag += imagStep) { + var n = computeEscapeSpeed(curReal, curImag); + addPoint(points, n, i, j) + } + } + var result; + if (doImageData) { + if (colorMap == fuzzyColors) { + result = mandelbrotImageDataFuzzyResult; + } else { + result = mandelbrotImageDataModdedResult; + } + } else { + result = mandelbrotNoImageDataResult; + } + return points.toSource() == result; + } + + const escapeTests = [ escapeAbsDiff ]; + const colorMaps = [ fuzzyColors, moddedColors ]; + const escapeComputations = [ computeEscapeSpeedObjects, + computeEscapeSpeedOneObject, + computeEscapeSpeedDoubles ]; + // Test all possible escape-speed generation codepaths, using the + // imageData + sparse array avoidance storage. + doImageData = true; + avoidSparseArray = true; + for (var escapeIdx in escapeTests) { + escape = escapeTests[escapeIdx]; + for (var colorMapIdx in colorMaps) { + colorMap = colorMaps[colorMapIdx]; + for (var escapeComputationIdx in escapeComputations) { + computeEscapeSpeed = escapeComputations[escapeComputationIdx]; + assertEq(createMandelSet(), true); + } + } + } + + // Test all possible storage strategies. Note that we already tested + // doImageData == true with avoidSparseArray == true. + escape = escapeAbsDiff; + colorMap = fuzzyColors; // This part doesn't really matter too much here + computeEscapeSpeed = computeEscapeSpeedDoubles; + + doImageData = true; + avoidSparseArray = false; + assertEq(createMandelSet(), true); + + escape = escapeNorm2; + doImageData = false; // avoidSparseArray doesn't matter here + assertEq(createMandelSet(), true); +//} +//testMandelbrotAll(); diff --git a/js/src/jit-test/tests/basic/deep2.js b/js/src/jit-test/tests/basic/deep2.js new file mode 100644 index 0000000..2cf30b8 --- /dev/null +++ b/js/src/jit-test/tests/basic/deep2.js @@ -0,0 +1,11 @@ +function deep1(x) { + if (x > 90) + return 1; + return 2; +} +function deep2() { + for (var i = 0; i < 100; ++i) + deep1(i); + return "ok"; +} +assertEq(deep2(), "ok"); diff --git a/js/src/jit-test/tests/basic/deepForInLoop.js b/js/src/jit-test/tests/basic/deepForInLoop.js new file mode 100644 index 0000000..0e58b06 --- /dev/null +++ b/js/src/jit-test/tests/basic/deepForInLoop.js @@ -0,0 +1,12 @@ +function deepForInLoop() { + // NB: the number of props set in C is arefully tuned to match HOTLOOP = 2. + function C(){this.p = 1, this.q = 2} + C.prototype = {p:1, q:2, r:3, s:4, t:5}; + var o = new C; + var j = 0; + var a = []; + for (var i in o) + a[j++] = i; + return a.join(""); +} +assertEq(deepForInLoop(), "pqrst"); diff --git a/js/src/jit-test/tests/basic/delete-array-elements.js b/js/src/jit-test/tests/basic/delete-array-elements.js new file mode 100644 index 0000000..09dd6dd --- /dev/null +++ b/js/src/jit-test/tests/basic/delete-array-elements.js @@ -0,0 +1,12 @@ +var a = [0,1,2,3,4,5,6,7,8,9,10]; +for (var i = 0; i < 10; i++) + delete a[9 - i]; +assertEq(a.length, 11); +for (i = 0; i < 10; i++) + assertEq(a.hasOwnProperty(i), false); + +checkStats({ + recorderAborted:0, + traceCompleted:2, + sideExitIntoInterpreter:2 +}); diff --git a/js/src/jit-test/tests/basic/delete-indexed-names.js b/js/src/jit-test/tests/basic/delete-indexed-names.js new file mode 100644 index 0000000..1585fca --- /dev/null +++ b/js/src/jit-test/tests/basic/delete-indexed-names.js @@ -0,0 +1,12 @@ +var a = ['p', 'q', 'r', 's', 't']; +var o = {p:1, q:2, r:3, s:4, t:5}; +for (var i in o) + delete o[i]; +for each (var i in a) + assertEq(o.hasOwnProperty(i), false); + +checkStats({ + recorderAborted:0, + traceCompleted:2, + sideExitIntoInterpreter:2 +}); diff --git a/js/src/jit-test/tests/basic/delete-integer-nonid.js b/js/src/jit-test/tests/basic/delete-integer-nonid.js new file mode 100644 index 0000000..e016227 --- /dev/null +++ b/js/src/jit-test/tests/basic/delete-integer-nonid.js @@ -0,0 +1,24 @@ +var JSID_INT_MIN = -(1 << 30); +var JSID_INT_MAX = (1 << 30) - 1; + +var o = {}; + + +for (var i = 0; i < 10; i++) + delete o[JSID_INT_MIN - 1]; + +for (var i = 0; i < 10; i++) + delete o[JSID_INT_MIN]; + +for (var i = 0; i < 10; i++) + delete o[JSID_INT_MIN + 1]; + + +for (var i = 0; i < 10; i++) + delete o[JSID_INT_MAX - 1]; + +for (var i = 0; i < 10; i++) + delete o[JSID_INT_MAX]; + +for (var i = 0; i < 10; i++) + delete o[JSID_INT_MAX + 1]; diff --git a/js/src/jit-test/tests/basic/delete-named-names.js b/js/src/jit-test/tests/basic/delete-named-names.js new file mode 100644 index 0000000..1e0ac40 --- /dev/null +++ b/js/src/jit-test/tests/basic/delete-named-names.js @@ -0,0 +1,17 @@ +var a = ['p', 'q', 'r', 's', 't']; +var o = {p:1, q:2, r:3, s:4, t:5}; +for (var i in o) { + delete o.p; + delete o.q; + delete o.r; + delete o.s; + delete o.t; +} +for each (var i in a) + assertEq(o.hasOwnProperty(i), false); + +checkStats({ + recorderAborted:0, + traceCompleted:1, + sideExitIntoInterpreter:1 +}); diff --git a/js/src/jit-test/tests/basic/delete-non-config.js b/js/src/jit-test/tests/basic/delete-non-config.js new file mode 100644 index 0000000..f65b695 --- /dev/null +++ b/js/src/jit-test/tests/basic/delete-non-config.js @@ -0,0 +1,10 @@ +var a = [0,1,2,3,4,5,6,7,8,9,10]; +for (var i = 0; i < 10; i++) + delete a.length; +assertEq(delete a.length, false); + +checkStats({ + recorderAborted:0, + traceCompleted:1, + sideExitIntoInterpreter:1 +}); diff --git a/js/src/jit-test/tests/basic/dependentStrings.js b/js/src/jit-test/tests/basic/dependentStrings.js new file mode 100644 index 0000000..1dd38bb --- /dev/null +++ b/js/src/jit-test/tests/basic/dependentStrings.js @@ -0,0 +1,11 @@ +function dependentStrings() +{ + var a = []; + var t = "abcdefghijklmnopqrst"; + for (var i = 0; i < 10; i++) { + var s = t.substring(2*i, 2*i + 2); + a[i] = s + s.length; + } + return a.join(""); +} +assertEq(dependentStrings(), "ab2cd2ef2gh2ij2kl2mn2op2qr2st2"); diff --git a/js/src/jit-test/tests/basic/doMath.js b/js/src/jit-test/tests/basic/doMath.js new file mode 100644 index 0000000..8129a46 --- /dev/null +++ b/js/src/jit-test/tests/basic/doMath.js @@ -0,0 +1,60 @@ +function map_test(t, cases) +{ + for (var i = 0; i < cases.length; i++) { + function c() { return t(cases[i].input); } + var expected = cases[i].expected; + assertEq(c(), expected); + } +} + +function lsh_inner(n) +{ + var r; + for (var i = 0; i < 35; i++) + r = 0x1 << n; + return r; +} +map_test (lsh_inner, + [{input: 15, expected: 32768}, + {input: 55, expected: 8388608}, + {input: 1, expected: 2}, + {input: 0, expected: 1}]); + +function rsh_inner(n) +{ + var r; + for (var i = 0; i < 35; i++) + r = 0x11010101 >> n; + return r; +} +map_test (rsh_inner, + [{input: 8, expected: 1114369}, + {input: 5, expected: 8914952}, + {input: 35, expected: 35659808}, + {input: -1, expected: 0}]); + +function ursh_inner(n) +{ + var r; + for (var i = 0; i < 35; i++) + r = -55 >>> n; + return r; +} +map_test (ursh_inner, + [{input: 8, expected: 16777215}, + {input: 33, expected: 2147483620}, + {input: 0, expected: 4294967241}, + {input: 1, expected: 2147483620}]); + +function doMath_inner(cos) +{ + var s = 0; + var sin = Math.sin; + for (var i = 0; i < 200; i++) + s = -Math.pow(sin(i) + cos(i * 0.75), 4); + return s; +} +function doMath() { + return doMath_inner(Math.cos); +} +assertEq(doMath(), -0.5405549555611059); diff --git a/js/src/jit-test/tests/basic/equalInt.js b/js/src/jit-test/tests/basic/equalInt.js new file mode 100644 index 0000000..d63c881 --- /dev/null +++ b/js/src/jit-test/tests/basic/equalInt.js @@ -0,0 +1,29 @@ +function equalInt() +{ + var i1 = 55, one = 1, zero = 0, undef; + var o1 = { }, o2 = { }; + var s = "5"; + var hits = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + for (var i = 0; i < 5000; i++) { + if (i1 == 55) hits[0]++; + if (i1 != 56) hits[1]++; + if (i1 < 56) hits[2]++; + if (i1 > 50) hits[3]++; + if (i1 <= 60) hits[4]++; + if (i1 >= 30) hits[5]++; + if (i1 == 7) hits[6]++; + if (i1 != 55) hits[7]++; + if (i1 < 30) hits[8]++; + if (i1 > 90) hits[9]++; + if (i1 <= 40) hits[10]++; + if (i1 >= 70) hits[11]++; + if (o1 == o2) hits[12]++; + if (o2 != null) hits[13]++; + if (s < 10) hits[14]++; + if (true < zero) hits[15]++; + if (undef > one) hits[16]++; + if (undef < zero) hits[17]++; + } + return hits.toString(); +} +assertEq(equalInt(), "5000,5000,5000,5000,5000,5000,0,0,0,0,0,0,0,5000,5000,0,0,0"); diff --git a/js/src/jit-test/tests/basic/fannkuch.js b/js/src/jit-test/tests/basic/fannkuch.js new file mode 100644 index 0000000..a6154f2 --- /dev/null +++ b/js/src/jit-test/tests/basic/fannkuch.js @@ -0,0 +1,17 @@ +function fannkuch() { + var count = Array(8); + var r = 8; + var done = 0; + while (done < 40) { + // write-out the first 30 permutations + done += r; + while (r != 1) { count[r - 1] = r; r--; } + while (true) { + count[r] = count[r] - 1; + if (count[r] > 0) break; + r++; + } + } + return done; +} +assertEq(fannkuch(), 41); diff --git a/js/src/jit-test/tests/basic/firstSlotConflict.js b/js/src/jit-test/tests/basic/firstSlotConflict.js new file mode 100644 index 0000000..fa39469 --- /dev/null +++ b/js/src/jit-test/tests/basic/firstSlotConflict.js @@ -0,0 +1,10 @@ +(function(x) { + function f1() { return 1; } + function f2() { return 2; } + function f3() { return 3; } + function f4() { return 4; } + var g = function () { return x; } + var a = [f1, f2, f3, f4, g]; + for each (var v in a) + v.adhoc = 42; // Don't assertbotch in jsbuiltins.cpp setting g.adhoc +})(33); diff --git a/js/src/jit-test/tests/basic/forVarInWith.js b/js/src/jit-test/tests/basic/forVarInWith.js new file mode 100644 index 0000000..6dbf07b --- /dev/null +++ b/js/src/jit-test/tests/basic/forVarInWith.js @@ -0,0 +1,12 @@ +function forVarInWith() { + function foo() ({notk:42}); + function bar() ({p:1, q:2, r:3, s:4, t:5}); + var o = foo(); + var a = []; + with (o) { + for (var k in bar()) + a[a.length] = k; + } + return a.join(""); +} +assertEq(forVarInWith(), "pqrst"); diff --git a/js/src/jit-test/tests/basic/function-bind.js b/js/src/jit-test/tests/basic/function-bind.js new file mode 100644 index 0000000..7831ef0 --- /dev/null +++ b/js/src/jit-test/tests/basic/function-bind.js @@ -0,0 +1,21 @@ +var A = Array.bind(1, 1, 2); + +var a1; +for (var i = 0; i < 5; i++) + a1 = A(3, 4); + +assertEq(a1.length, 4); +assertEq(a1[0], 1); +assertEq(a1[1], 2); +assertEq(a1[2], 3); +assertEq(a1[3], 4); + +var a2; +for (var i = 0; i < 5; i++) + a2 = new A(3, 4); + +assertEq(a2.length, 4); +assertEq(a2[0], 1); +assertEq(a2[1], 2); +assertEq(a2[2], 3); +assertEq(a2[3], 4); diff --git a/js/src/jit-test/tests/basic/getelem.js b/js/src/jit-test/tests/basic/getelem.js new file mode 100644 index 0000000..cfc2a70 --- /dev/null +++ b/js/src/jit-test/tests/basic/getelem.js @@ -0,0 +1,30 @@ +var a; +function setelem() +{ + a = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + a = a.concat(a, a, a); + var l = a.length; + for (var i = 0; i < l; i++) { + a[i] = i; + } + return a.toString(); +} + +setelem(); + +function getelem_inner(a) +{ + var accum = 0; + var l = a.length; + for (var i = 0; i < l; i++) { + accum += a[i]; + } + return accum; +} + +function getelem() +{ + return getelem_inner(a); +} + +assertEq(getelem(), 3486); diff --git a/js/src/jit-test/tests/basic/getprop.js b/js/src/jit-test/tests/basic/getprop.js new file mode 100644 index 0000000..126af69 --- /dev/null +++ b/js/src/jit-test/tests/basic/getprop.js @@ -0,0 +1,16 @@ +var a = 2; +function getprop_inner(o2) +{ + var o = {a:5}; + var t = this; + var x = 0; + for (var i = 0; i < 20; i++) { + t = this; + x += o.a + o2.a + this.a + t.a; + } + return x; +} +function getprop() { + return getprop_inner({a:9}); +} +assertEq(getprop(), 360); diff --git a/js/src/jit-test/tests/basic/globalGet.js b/js/src/jit-test/tests/basic/globalGet.js new file mode 100644 index 0000000..53d73a6 --- /dev/null +++ b/js/src/jit-test/tests/basic/globalGet.js @@ -0,0 +1,6 @@ +globalName = 907; +var globalInt = 0; +for (var i = 0; i < 500; i++) + globalInt = globalName + i; + +assertEq(globalInt, globalName + 499); diff --git a/js/src/jit-test/tests/basic/globalOptimize-1.js b/js/src/jit-test/tests/basic/globalOptimize-1.js new file mode 100644 index 0000000..f90114c --- /dev/null +++ b/js/src/jit-test/tests/basic/globalOptimize-1.js @@ -0,0 +1,5 @@ +/* Test that NaN does not trigger js_InitMathClass & constants while parsing. */ +var NaN + +var x = 2; + diff --git a/js/src/jit-test/tests/basic/globalSet.js b/js/src/jit-test/tests/basic/globalSet.js new file mode 100644 index 0000000..ceb2852 --- /dev/null +++ b/js/src/jit-test/tests/basic/globalSet.js @@ -0,0 +1,4 @@ +for (var i = 0; i < 500; i++) + globalInt = i; + +assertEq(globalInt, 499); diff --git a/js/src/jit-test/tests/basic/ifInsideLoop.js b/js/src/jit-test/tests/basic/ifInsideLoop.js new file mode 100644 index 0000000..296e3f8 --- /dev/null +++ b/js/src/jit-test/tests/basic/ifInsideLoop.js @@ -0,0 +1,12 @@ +function ifInsideLoop() +{ + var cond = true, intCond = 5, count = 0; + for (var i = 0; i < 100; i++) { + if (cond) + count++; + if (intCond) + count++; + } + return count; +} +assertEq(ifInsideLoop(), 200); diff --git a/js/src/jit-test/tests/basic/inArrayTest.js b/js/src/jit-test/tests/basic/inArrayTest.js new file mode 100644 index 0000000..d57f013 --- /dev/null +++ b/js/src/jit-test/tests/basic/inArrayTest.js @@ -0,0 +1,9 @@ +function inArrayTest() { + var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + for (var i = 0; i < a.length; i++) { + if (!(i in a)) + break; + } + return i; +} +assertEq(inArrayTest(), 10); diff --git a/js/src/jit-test/tests/basic/inObjectTest.js b/js/src/jit-test/tests/basic/inObjectTest.js new file mode 100644 index 0000000..f19fdbe --- /dev/null +++ b/js/src/jit-test/tests/basic/inObjectTest.js @@ -0,0 +1,13 @@ +function inObjectTest() { + var o = {p: 1, q: 2, r: 3, s: 4, t: 5}; + var r = 0; + for (var i in o) { + if (!(i in o)) + break; + if ((i + i) in o) + break; + ++r; + } + return r; +} +assertEq(inObjectTest(), 5); diff --git a/js/src/jit-test/tests/basic/innerLoopIntOuterDouble.js b/js/src/jit-test/tests/basic/innerLoopIntOuterDouble.js new file mode 100644 index 0000000..723f26c --- /dev/null +++ b/js/src/jit-test/tests/basic/innerLoopIntOuterDouble.js @@ -0,0 +1,11 @@ +function innerLoopIntOuterDouble() { + var n = 10000, i=0, j=0, count=0, limit=0; + for (i = 1; i <= n; ++i) { + limit = i * 1; + for (j = 0; j < limit; ++j) { + ++count; + } + } + return "" + count; +} +assertEq(innerLoopIntOuterDouble(), "50005000"); diff --git a/js/src/jit-test/tests/basic/inner_double_outer_int.js b/js/src/jit-test/tests/basic/inner_double_outer_int.js new file mode 100644 index 0000000..4051aa2 --- /dev/null +++ b/js/src/jit-test/tests/basic/inner_double_outer_int.js @@ -0,0 +1,10 @@ +function inner_double_outer_int() { + function f(i) { + for (var m = 0; m < 20; ++m) + for (var n = 0; n < 100; n += i) + ; + return n; + } + return f(.5); +} +assertEq(inner_double_outer_int(), 100); diff --git a/js/src/jit-test/tests/basic/jitstatsArchFlags.js b/js/src/jit-test/tests/basic/jitstatsArchFlags.js new file mode 100644 index 0000000..a4ec0c4 --- /dev/null +++ b/js/src/jit-test/tests/basic/jitstatsArchFlags.js @@ -0,0 +1,14 @@ +// Make sure the arch flags are valid on startup, even if nothing has +// been traced yet. We don't know what arch the user is building on, +// but presumably we want at least 1 flag to be set on all supported +// platforms. + +if (HAVE_TM) { + assertEq(jitstats.archIsIA32 || + jitstats.archIs64BIT || + jitstats.archIsARM || + jitstats.archIsSPARC || + jitstats.archIsPPC || + jitstats.archIsAMD64, + 1); + } diff --git a/js/src/jit-test/tests/basic/joinTest.js b/js/src/jit-test/tests/basic/joinTest.js new file mode 100644 index 0000000..1988da4 --- /dev/null +++ b/js/src/jit-test/tests/basic/joinTest.js @@ -0,0 +1,15 @@ +function joinTest() +{ + var s = ""; + var a = []; + for (var i = 0; i < 8; i++) + a[i] = [String.fromCharCode(97 + i)]; + for (i = 0; i < 8; i++) { + for (var j = 0; j < 8; j++) + a[i][1 + j] = j; + } + for (i = 0; i < 8; i++) + s += a[i].join(","); + return s; +} +assertEq(joinTest(), "a,0,1,2,3,4,5,6,7b,0,1,2,3,4,5,6,7c,0,1,2,3,4,5,6,7d,0,1,2,3,4,5,6,7e,0,1,2,3,4,5,6,7f,0,1,2,3,4,5,6,7g,0,1,2,3,4,5,6,7h,0,1,2,3,4,5,6,7"); diff --git a/js/src/jit-test/tests/basic/matchInLoop.js b/js/src/jit-test/tests/basic/matchInLoop.js new file mode 100644 index 0000000..89f40ac --- /dev/null +++ b/js/src/jit-test/tests/basic/matchInLoop.js @@ -0,0 +1,8 @@ +function matchInLoop() { + var k = "hi"; + for (var i = 0; i < 10; i++) { + var result = k.match(/hi/) != null; + } + return result; +} +assertEq(matchInLoop(), true); diff --git a/js/src/jit-test/tests/basic/math-jit-tests.js b/js/src/jit-test/tests/basic/math-jit-tests.js new file mode 100644 index 0000000..418210f --- /dev/null +++ b/js/src/jit-test/tests/basic/math-jit-tests.js @@ -0,0 +1,520 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +// Apply FUNCNAME to ARGS, and check against EXPECTED. +// Expect a loop containing such a call to be traced. +// FUNCNAME and ARGS are both strings. +// ARGS has the form of an argument list: a comma-separated list of expressions. +// Certain Tracemonkey limitations require us to pass FUNCNAME as a string. +// Passing ARGS as a string allows us to assign better test names: +// expressions like Math.PI/4 haven't been evaluated to big hairy numbers. +function testmath(funcname, args, expected) { + var i, j; + + var arg_value_list = eval("[" + args + "]"); + var arity = arg_value_list.length; + + // Build the string "a[i][0],...,a[i][ARITY-1]". + var actuals = [] + for (i = 0; i < arity; i++) + actuals.push("a[i][" + i + "]"); + actuals = actuals.join(","); + + // Create a function that maps FUNCNAME across an array of input values. + // Unless we eval here, the call to funcname won't get traced. + // FUNCNAME="Infinity/Math.abs" and cases like that happen to + // parse, too, in a twisted way. + var mapfunc = eval("(function(a) {\n" + + " for (var i = 0; i < a.length; i++)\n" + + " a[i] = " + funcname + "(" + actuals +");\n" + + " })\n"); + + // To prevent the compiler from doing constant folding, produce an + // array to pass to mapfunc that contains enough dummy + // values at the front to get the loop body jitted, and then our + // actual test value. + var dummies_and_input = []; + for (i = 0; i < RUNLOOP; i++) { + var dummy_list = []; + for (j = 0; j < arity; j++) + dummy_list[j] = .0078125 * ((i + j) % 128); + dummies_and_input[i] = dummy_list; + } + dummies_and_input[RUNLOOP] = arg_value_list; + + function testfunc() { + // Map the function across the dummy values and the test input. + mapfunc(dummies_and_input); + return dummies_and_input[RUNLOOP]; + } + + assertEq(close_enough(testfunc(), expected), true); +} + +function close_enough(expected, actual) +{ + if (typeof expected != typeof actual) + return false; + if (typeof expected != 'number') + return actual == expected; + + // Distinguish NaN from other values. Using x != x comparisons here + // works even if tests redefine isNaN. + if (actual != actual) + return expected != expected + if (expected != expected) + return false; + + // Tolerate a certain degree of error. + if (actual != expected) + return Math.abs(actual - expected) <= 1E-10; + + // Distinguish 0 and -0. + if (actual == 0) + return (1 / actual > 0) == (1 / expected > 0); + + return true; +} + +testmath("Math.abs", "void 0", Number.NaN) +testmath("Math.abs", "null", 0) +testmath("Math.abs", "true", 1) +testmath("Math.abs", "false", 0) +testmath("Math.abs", "\"a string primitive\"", Number.NaN) +testmath("Math.abs", "new String( 'a String object' )", Number.NaN) +testmath("Math.abs", "Number.NaN", Number.NaN) +testmath("Math.abs", "0", 0) +testmath("Math.abs", "-0", 0) +testmath("Infinity/Math.abs", "-0", Infinity) +testmath("Math.abs", "Number.NEGATIVE_INFINITY", Number.POSITIVE_INFINITY) +testmath("Math.abs", "Number.POSITIVE_INFINITY", Number.POSITIVE_INFINITY) +testmath("Math.abs", "- Number.MAX_VALUE", Number.MAX_VALUE) +testmath("Math.abs", "-Number.MIN_VALUE", Number.MIN_VALUE) +testmath("Math.abs", "Number.MAX_VALUE", Number.MAX_VALUE) +testmath("Math.abs", "Number.MIN_VALUE", Number.MIN_VALUE) +testmath("Math.abs", "-1", 1) +testmath("Math.abs", "new Number(-1)", 1) +testmath("Math.abs", "1", 1) +testmath("Math.abs", "Math.PI", Math.PI) +testmath("Math.abs", "-Math.PI", Math.PI) +testmath("Math.abs", "-1/100000000", 1/100000000) +testmath("Math.abs", "-Math.pow(2,32)", Math.pow(2,32)) +testmath("Math.abs", "Math.pow(2,32)", Math.pow(2,32)) +testmath("Math.abs", "-0xfff", 4095) +testmath("Math.abs", "-0777", 511) +testmath("Math.abs", "'-1e-1'", 0.1) +testmath("Math.abs", "'0xff'", 255) +testmath("Math.abs", "'077'", 77) +testmath("Math.abs", "'Infinity'", Infinity) +testmath("Math.abs", "'-Infinity'", Infinity) + +testmath("Math.acos", "void 0", Number.NaN) +testmath("Math.acos", "null", Math.PI/2) +testmath("Math.acos", "Number.NaN", Number.NaN) +testmath("Math.acos", "\"a string\"", Number.NaN) +testmath("Math.acos", "'0'", Math.PI/2) +testmath("Math.acos", "'1'", 0) +testmath("Math.acos", "'-1'", Math.PI) +testmath("Math.acos", "1.00000001", Number.NaN) +testmath("Math.acos", "-1.00000001", Number.NaN) +testmath("Math.acos", "1", 0) +testmath("Math.acos", "-1", Math.PI) +testmath("Math.acos", "0", Math.PI/2) +testmath("Math.acos", "-0", Math.PI/2) +testmath("Math.acos", "Math.SQRT1_2", Math.PI/4) +testmath("Math.acos", "-Math.SQRT1_2", Math.PI/4*3) +testmath("Math.acos", "0.9999619230642", Math.PI/360) +testmath("Math.acos", "-3.0", Number.NaN) + +testmath("Math.asin", "void 0", Number.NaN) +testmath("Math.asin", "null", 0) +testmath("Math.asin", "Number.NaN", Number.NaN) +testmath("Math.asin", "\"string\"", Number.NaN) +testmath("Math.asin", "\"0\"", 0) +testmath("Math.asin", "\"1\"", Math.PI/2) +testmath("Math.asin", "\"-1\"", -Math.PI/2) +testmath("Math.asin", "Math.SQRT1_2+''", Math.PI/4) +testmath("Math.asin", "-Math.SQRT1_2+''", -Math.PI/4) +testmath("Math.asin", "1.000001", Number.NaN) +testmath("Math.asin", "-1.000001", Number.NaN) +testmath("Math.asin", "0", 0) +testmath("Math.asin", "-0", -0) +testmath("Infinity/Math.asin", "-0", -Infinity) +testmath("Math.asin", "1", Math.PI/2) +testmath("Math.asin", "-1", -Math.PI/2) +testmath("Math.asin", "Math.SQRT1_2", Math.PI/4) +testmath("Math.asin", "-Math.SQRT1_2", -Math.PI/4) + +testmath("Math.atan", "void 0", Number.NaN) +testmath("Math.atan", "null", 0) +testmath("Math.atan", "Number.NaN", Number.NaN) +testmath("Math.atan", "\"a string\"", Number.NaN) +testmath("Math.atan", "'0'", 0) +testmath("Math.atan", "'1'", Math.PI/4) +testmath("Math.atan", "'-1'", -Math.PI/4) +testmath("Math.atan", "'Infinity'", Math.PI/2) +testmath("Math.atan", "'-Infinity'", -Math.PI/2) +testmath("Math.atan", "0", 0) +testmath("Math.atan", "-0", -0) +testmath("Infinity/Math.atan", "-0", -Infinity) +testmath("Math.atan", "Number.POSITIVE_INFINITY", Math.PI/2) +testmath("Math.atan", "Number.NEGATIVE_INFINITY", -Math.PI/2) +testmath("Math.atan", "1", Math.PI/4) +testmath("Math.atan", "-1", -Math.PI/4) + +testmath("Math.atan2", "Number.NaN,0", Number.NaN) +testmath("Math.atan2", "null, null", 0) +testmath("Math.atan2", "void 0, void 0", Number.NaN) +testmath("Math.atan2", "0,Number.NaN", Number.NaN) +testmath("Math.atan2", "1,0", Math.PI/2) +testmath("Math.atan2", "1,-0", Math.PI/2) +testmath("Math.atan2", "0,0.001", 0) +testmath("Math.atan2", "0,0", 0) +testmath("Math.atan2", "0,-0", Math.PI) +testmath("Math.atan2", "0, -1", Math.PI) +testmath("Math.atan2", "-0, 1", -0) +testmath("Infinity/Math.atan2", "-0,1", -Infinity) +testmath("Math.atan2", "-0,0", -0) +testmath("Math.atan2", "-0, -0", -Math.PI) +testmath("Math.atan2", "-0, -1", -Math.PI) +testmath("Math.atan2", "-1, 0", -Math.PI/2) +testmath("Math.atan2", "-1, -0", -Math.PI/2) +testmath("Math.atan2", "1, Number.POSITIVE_INFINITY", 0) +testmath("Math.atan2", "1, Number.NEGATIVE_INFINITY", Math.PI) +testmath("Math.atan2", "-1,Number.POSITIVE_INFINITY", -0) +testmath("Infinity/Math.atan2", "-1,Infinity", -Infinity) +testmath("Math.atan2", "-1,Number.NEGATIVE_INFINITY", -Math.PI) +testmath("Math.atan2", "Number.POSITIVE_INFINITY, 0", Math.PI/2) +testmath("Math.atan2", "Number.POSITIVE_INFINITY, 1", Math.PI/2) +testmath("Math.atan2", "Number.POSITIVE_INFINITY,-1", Math.PI/2) +testmath("Math.atan2", "Number.POSITIVE_INFINITY,-0", Math.PI/2) +testmath("Math.atan2", "Number.NEGATIVE_INFINITY, 0", -Math.PI/2) +testmath("Math.atan2", "Number.NEGATIVE_INFINITY,-0", -Math.PI/2) +testmath("Math.atan2", "Number.NEGATIVE_INFINITY, 1", -Math.PI/2) +testmath("Math.atan2", "Number.NEGATIVE_INFINITY,-1", -Math.PI/2) +testmath("Math.atan2", "Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY", Math.PI/4) +testmath("Math.atan2", "Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY", 3*Math.PI/4) +testmath("Math.atan2", "Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY", -Math.PI/4) +testmath("Math.atan2", "Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY", -3*Math.PI/4) +testmath("Math.atan2", "-1, 1", -Math.PI/4) + +testmath("Math.ceil", "Number.NaN", Number.NaN) +testmath("Math.ceil", "null", 0) +testmath("Math.ceil", "void 0", Number.NaN) +testmath("Math.ceil", "'0'", 0) +testmath("Math.ceil", "'-0'", -0) +testmath("Infinity/Math.ceil", "'0'", Infinity) +testmath("Infinity/Math.ceil", "'-0'", -Infinity) +testmath("Math.ceil", "0", 0) +testmath("Math.ceil", "-0", -0) +testmath("Infinity/Math.ceil", "0", Infinity) +testmath("Infinity/Math.ceil", "-0", -Infinity) +testmath("Math.ceil", "Number.POSITIVE_INFINITY", Number.POSITIVE_INFINITY) +testmath("Math.ceil", "Number.NEGATIVE_INFINITY", Number.NEGATIVE_INFINITY) +testmath("Math.ceil", "-Number.MIN_VALUE", -0) +testmath("Infinity/Math.ceil", "-Number.MIN_VALUE", -Infinity) +testmath("Math.ceil", "1", 1) +testmath("Math.ceil", "-1", -1) +testmath("Math.ceil", "-0.9", -0) +testmath("Infinity/Math.ceil", "-0.9", -Infinity) +testmath("Math.ceil", "0.9", 1) +testmath("Math.ceil", "-1.1", -1) +testmath("Math.ceil", "1.1", 2) +testmath("Math.ceil", "Number.POSITIVE_INFINITY", -Math.floor(-Infinity)) +testmath("Math.ceil", "Number.NEGATIVE_INFINITY", -Math.floor(Infinity)) +testmath("Math.ceil", "-Number.MIN_VALUE", -Math.floor(Number.MIN_VALUE)) +testmath("Math.ceil", "1", -Math.floor(-1)) +testmath("Math.ceil", "-1", -Math.floor(1)) +testmath("Math.ceil", "-0.9", -Math.floor(0.9)) +testmath("Math.ceil", "0.9", -Math.floor(-0.9)) +testmath("Math.ceil", "-1.1", -Math.floor(1.1)) +testmath("Math.ceil", "1.1", -Math.floor(-1.1)) + +testmath("Math.cos", "void 0", Number.NaN) +testmath("Math.cos", "false", 1) +testmath("Math.cos", "null", 1) +testmath("Math.cos", "'0'", 1) +testmath("Math.cos", "\"Infinity\"", Number.NaN) +testmath("Math.cos", "'3.14159265359'", -1) +testmath("Math.cos", "Number.NaN", Number.NaN) +testmath("Math.cos", "0", 1) +testmath("Math.cos", "-0", 1) +testmath("Math.cos", "Number.POSITIVE_INFINITY", Number.NaN) +testmath("Math.cos", "Number.NEGATIVE_INFINITY", Number.NaN) +testmath("Math.cos", "0.7853981633974", 0.7071067811865) +testmath("Math.cos", "1.570796326795", 0) +testmath("Math.cos", "2.356194490192", -0.7071067811865) +testmath("Math.cos", "3.14159265359", -1) +testmath("Math.cos", "3.926990816987", -0.7071067811865) +testmath("Math.cos", "4.712388980385", 0) +testmath("Math.cos", "5.497787143782", 0.7071067811865) +testmath("Math.cos", "Math.PI*2", 1) +testmath("Math.cos", "Math.PI/4", Math.SQRT2/2) +testmath("Math.cos", "Math.PI/2", 0) +testmath("Math.cos", "3*Math.PI/4", -Math.SQRT2/2) +testmath("Math.cos", "Math.PI", -1) +testmath("Math.cos", "5*Math.PI/4", -Math.SQRT2/2) +testmath("Math.cos", "3*Math.PI/2", 0) +testmath("Math.cos", "7*Math.PI/4", Math.SQRT2/2) +testmath("Math.cos", "2*Math.PI", 1) +testmath("Math.cos", "-0.7853981633974", 0.7071067811865) +testmath("Math.cos", "-1.570796326795", 0) +testmath("Math.cos", "2.3561944901920", -.7071067811865) +testmath("Math.cos", "3.14159265359", -1) +testmath("Math.cos", "3.926990816987", -0.7071067811865) +testmath("Math.cos", "4.712388980385", 0) +testmath("Math.cos", "5.497787143782", 0.7071067811865) +testmath("Math.cos", "6.28318530718", 1) +testmath("Math.cos", "-Math.PI/4", Math.SQRT2/2) +testmath("Math.cos", "-Math.PI/2", 0) +testmath("Math.cos", "-3*Math.PI/4", -Math.SQRT2/2) +testmath("Math.cos", "-Math.PI", -1) +testmath("Math.cos", "-5*Math.PI/4", -Math.SQRT2/2) +testmath("Math.cos", "-3*Math.PI/2", 0) +testmath("Math.cos", "-7*Math.PI/4", Math.SQRT2/2) +testmath("Math.cos", "-Math.PI*2", 1) + +testmath("Math.exp", "null", 1) +testmath("Math.exp", "void 0", Number.NaN) +testmath("Math.exp", "1", Math.E) +testmath("Math.exp", "true", Math.E) +testmath("Math.exp", "false", 1) +testmath("Math.exp", "'1'", Math.E) +testmath("Math.exp", "'0'", 1) +testmath("Math.exp", "Number.NaN", Number.NaN) +testmath("Math.exp", "0", 1) +testmath("Math.exp", "-0", 1) +testmath("Math.exp", "Number.POSITIVE_INFINITY", Number.POSITIVE_INFINITY) +testmath("Math.exp", "Number.NEGATIVE_INFINITY", 0) + +testmath("Math.floor", "void 0", Number.NaN) +testmath("Math.floor", "null", 0) +testmath("Math.floor", "true", 1) +testmath("Math.floor", "false", 0) +testmath("Math.floor", "\"1.1\"", 1) +testmath("Math.floor", "\"-1.1\"", -2) +testmath("Math.floor", "\"0.1\"", 0) +testmath("Math.floor", "\"-0.1\"", -1) +testmath("Math.floor", "Number.NaN", Number.NaN) +testmath("Math.floor(Number.NaN) == -Math.ceil", "-Number.NaN", false) +testmath("Math.floor", "0", 0) +testmath("Math.floor(0) == -Math.ceil", "-0", true) +testmath("Math.floor", "-0", -0) +testmath("Infinity/Math.floor", "-0", -Infinity) +testmath("Math.floor(-0)== -Math.ceil", "0", true) +testmath("Math.floor", "Number.POSITIVE_INFINITY", Number.POSITIVE_INFINITY) +testmath("Math.floor(Number.POSITIVE_INFINITY) == -Math.ceil", "Number.NEGATIVE_INFINITY", true) +testmath("Math.floor", "Number.NEGATIVE_INFINITY", Number.NEGATIVE_INFINITY) +testmath("Math.floor(Number.NEGATIVE_INFINITY) == -Math.ceil", "Number.POSITIVE_INFINITY", true) +testmath("Math.floor", "0.0000001", 0) +testmath("Math.floor(0.0000001)==-Math.ceil", "-0.0000001", true) +testmath("Math.floor", "-0.0000001", -1) +testmath("Math.floor(-0.0000001)==-Math.ceil", "0.0000001", true) + +testmath("Math.log", "void 0", Number.NaN) +testmath("Math.log", "null", Number.NEGATIVE_INFINITY) +testmath("Math.log", "true", 0) +testmath("Math.log", "false", -Infinity) +testmath("Math.log", "'0'", -Infinity) +testmath("Math.log", "'1'", 0) +testmath("Math.log", "\"Infinity\"", Infinity) +testmath("Math.log", "Number.NaN", Number.NaN) +testmath("Math.log", "-0.000001", Number.NaN) +testmath("Math.log", "-1", Number.NaN) +testmath("Math.log", "0", Number.NEGATIVE_INFINITY) +testmath("Math.log", "-0", Number.NEGATIVE_INFINITY) +testmath("Math.log", "1", 0) +testmath("Math.log", "Number.POSITIVE_INFINITY", Number.POSITIVE_INFINITY) +testmath("Math.log", "Number.NEGATIVE_INFINITY", Number.NaN) + +testmath("Math.max", "void 0, 1", Number.NaN) +testmath("Math.max", "void 0, void 0", Number.NaN) +testmath("Math.max", "null, 1", 1) +testmath("Math.max", "-1, null", 0) +testmath("Math.max", "true,false", 1) +testmath("Math.max", "\"-99\",\"99\"", 99) +testmath("Math.max", "Number.NaN,Number.POSITIVE_INFINITY", Number.NaN) +testmath("Math.max", "Number.NaN, 0", Number.NaN) +testmath("Math.max", "\"a string\", 0", Number.NaN) +testmath("Math.max", "Number.NaN,1", Number.NaN) +testmath("Math.max", "\"a string\", Number.POSITIVE_INFINITY", Number.NaN) +testmath("Math.max", "Number.POSITIVE_INFINITY, Number.NaN", Number.NaN) +testmath("Math.max", "Number.NaN, Number.NaN", Number.NaN) +testmath("Math.max", "0,Number.NaN", Number.NaN) +testmath("Math.max", "1, Number.NaN", Number.NaN) +testmath("Math.max", "0,0", 0) +testmath("Math.max", "0,-0", 0) +testmath("Math.max", "-0,0", 0) +testmath("Math.max", "-0,-0", -0) +testmath("Infinity/Math.max", "-0,-0", -Infinity) +testmath("Math.max", "Number.POSITIVE_INFINITY, Number.MAX_VALUE", Number.POSITIVE_INFINITY) +testmath("Math.max", "Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY", Number.POSITIVE_INFINITY) +testmath("Math.max", "Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY", Number.NEGATIVE_INFINITY) +testmath("Math.max", "1,.99999999999999", 1) +testmath("Math.max", "-1,-.99999999999999", -.99999999999999) + +testmath("Math.min", "void 0, 1", Number.NaN) +testmath("Math.min", "void 0, void 0", Number.NaN) +testmath("Math.min", "null, 1", 0) +testmath("Math.min", "-1, null", -1) +testmath("Math.min", "true,false", 0) +testmath("Math.min", "\"-99\",\"99\"", -99) +testmath("Math.min", "Number.NaN,0", Number.NaN) +testmath("Math.min", "Number.NaN,1", Number.NaN) +testmath("Math.min", "Number.NaN,-1", Number.NaN) +testmath("Math.min", "0,Number.NaN", Number.NaN) +testmath("Math.min", "1,Number.NaN", Number.NaN) +testmath("Math.min", "-1,Number.NaN", Number.NaN) +testmath("Math.min", "Number.NaN,Number.NaN", Number.NaN) +testmath("Math.min", "1,1.0000000001", 1) +testmath("Math.min", "1.0000000001,1", 1) +testmath("Math.min", "0,0", 0) +testmath("Math.min", "0,-0", -0) +testmath("Math.min", "-0,-0", -0) +testmath("Infinity/Math.min", "0,-0", -Infinity) +testmath("Infinity/Math.min", "-0,-0", -Infinity) + +testmath("Math.pow", "null,null", 1) +testmath("Math.pow", "void 0, void 0", Number.NaN) +testmath("Math.pow", "true, false", 1) +testmath("Math.pow", "false,true", 0) +testmath("Math.pow", "'2','32'", 4294967296) +testmath("Math.pow", "1,Number.NaN", Number.NaN) +testmath("Math.pow", "0,Number.NaN", Number.NaN) +testmath("Math.pow", "Number.NaN,0", 1) +testmath("Math.pow", "Number.NaN,-0", 1) +testmath("Math.pow", "Number.NaN, 1", Number.NaN) +testmath("Math.pow", "Number.NaN, .5", Number.NaN) +testmath("Math.pow", "1.00000001, Number.POSITIVE_INFINITY", Number.POSITIVE_INFINITY) +testmath("Math.pow", "1.00000001, Number.NEGATIVE_INFINITY", 0) +testmath("Math.pow", "-1.00000001,Number.POSITIVE_INFINITY", Number.POSITIVE_INFINITY) +testmath("Math.pow", "-1.00000001,Number.NEGATIVE_INFINITY", 0) +testmath("Math.pow", "1, Number.POSITIVE_INFINITY", Number.NaN) +testmath("Math.pow", "1, Number.NEGATIVE_INFINITY", Number.NaN) +testmath("Math.pow", "-1, Number.POSITIVE_INFINITY", Number.NaN) +testmath("Math.pow", "-1, Number.NEGATIVE_INFINITY", Number.NaN) +testmath("Math.pow", ".0000000009, Number.POSITIVE_INFINITY", 0) +testmath("Math.pow", "-.0000000009, Number.POSITIVE_INFINITY", 0) +testmath("Math.pow", "-.0000000009, Number.NEGATIVE_INFINITY", Number.POSITIVE_INFINITY) +testmath("Math.pow", "Number.POSITIVE_INFINITY,.00000000001", Number.POSITIVE_INFINITY) +testmath("Math.pow", "Number.POSITIVE_INFINITY, 1", Number.POSITIVE_INFINITY) +testmath("Math.pow", "Number.POSITIVE_INFINITY, -.00000000001", 0) +testmath("Math.pow", "Number.POSITIVE_INFINITY, -1", 0) +testmath("Math.pow", "Number.NEGATIVE_INFINITY, 1", Number.NEGATIVE_INFINITY) +testmath("Math.pow", "Number.NEGATIVE_INFINITY, 333", Number.NEGATIVE_INFINITY) +testmath("Math.pow", "Number.POSITIVE_INFINITY, 2", Number.POSITIVE_INFINITY) +testmath("Math.pow", "Number.NEGATIVE_INFINITY, 666", Number.POSITIVE_INFINITY) +testmath("Math.pow", "Number.NEGATIVE_INFINITY, 0.5", Number.POSITIVE_INFINITY) +testmath("Math.pow", "Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY", Number.POSITIVE_INFINITY) +testmath("Math.pow", "Number.NEGATIVE_INFINITY, -1", -0) +testmath("Infinity/Math.pow", "Number.NEGATIVE_INFINITY, -1", -Infinity) +testmath("Math.pow", "Number.NEGATIVE_INFINITY, -3", -0) +testmath("Math.pow", "Number.NEGATIVE_INFINITY, -2", 0) +testmath("Math.pow", "Number.NEGATIVE_INFINITY,-0.5", 0) +testmath("Math.pow", "Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY", 0) +testmath("Math.pow", "0,1", 0) +testmath("Math.pow", "0,0", 1) +testmath("Math.pow", "1,0", 1) +testmath("Math.pow", "-1,0", 1) +testmath("Math.pow", "0,0.5", 0) +testmath("Math.pow", "0,1000", 0) +testmath("Math.pow", "0, Number.POSITIVE_INFINITY", 0) +testmath("Math.pow", "0, -1", Number.POSITIVE_INFINITY) +testmath("Math.pow", "0, -0.5", Number.POSITIVE_INFINITY) +testmath("Math.pow", "0, -1000", Number.POSITIVE_INFINITY) +testmath("Math.pow", "0, Number.NEGATIVE_INFINITY", Number.POSITIVE_INFINITY) +testmath("Math.pow", "-0, 1", -0) +testmath("Math.pow", "-0,3", -0) +testmath("Infinity/Math.pow", "-0, 1", -Infinity) +testmath("Infinity/Math.pow", "-0,3", -Infinity) +testmath("Math.pow", "-0,2", 0) +testmath("Math.pow", "-0, Number.POSITIVE_INFINITY", 0) +testmath("Math.pow", "-0, -1", Number.NEGATIVE_INFINITY) +testmath("Math.pow", "-0, -10001", Number.NEGATIVE_INFINITY) +testmath("Math.pow", "-0, -2", Number.POSITIVE_INFINITY) +testmath("Math.pow", "-0, 0.5", 0) +testmath("Math.pow", "-0, Number.POSITIVE_INFINITY", 0) +testmath("Math.pow", "-1, 0.5", Number.NaN) +testmath("Math.pow", "-1, Number.NaN", Number.NaN) +testmath("Math.pow", "-1, -0.5", Number.NaN) + +testmath("Math.round", "0", 0) +testmath("Math.round", "void 0", Number.NaN) +testmath("Math.round", "true", 1) +testmath("Math.round", "false", 0) +testmath("Math.round", "'.99999'", 1) +testmath("Math.round", "'12345e-2'", 123) +testmath("Math.round", "Number.NaN", Number.NaN) +testmath("Math.round", "0", 0) +testmath("Math.round", "-0", -0) +testmath("Infinity/Math.round", "-0", -Infinity) +testmath("Math.round", "Number.POSITIVE_INFINITY", Number.POSITIVE_INFINITY) +testmath("Math.round", "Number.NEGATIVE_INFINITY", Number.NEGATIVE_INFINITY) +testmath("Math.round", "0.49", 0) +testmath("Math.round", "0.5", 1) +testmath("Math.round", "0.51", 1) +testmath("Math.round", "-0.49", -0) +testmath("Math.round", "-0.5", -0) +testmath("Infinity/Math.round", "-0.49", -Infinity) +testmath("Infinity/Math.round", "-0.5", -Infinity) +testmath("Math.round", "-0.51", -1) +testmath("Math.round", "3.5", 4) +testmath("Math.round", "-3", -3) + +testmath("Math.sin", "null", 0) +testmath("Math.sin", "void 0", Number.NaN) +testmath("Math.sin", "false", 0) +testmath("Math.sin", "'2.356194490192'", 0.7071067811865) +testmath("Math.sin", "Number.NaN", Number.NaN) +testmath("Math.sin", "0", 0) +testmath("Math.sin", "-0", -0) +testmath("Math.sin", "Number.POSITIVE_INFINITY", Number.NaN) +testmath("Math.sin", "Number.NEGATIVE_INFINITY", Number.NaN) +testmath("Math.sin", "0.7853981633974", 0.7071067811865) +testmath("Math.sin", "1.570796326795", 1) +testmath("Math.sin", "2.356194490192", 0.7071067811865) +testmath("Math.sin", "3.14159265359", 0) + +testmath("Math.sqrt", "void 0", Number.NaN) +testmath("Math.sqrt", "null", 0) +testmath("Math.sqrt", "1", 1) +testmath("Math.sqrt", "false", 0) +testmath("Math.sqrt", "'225'", 15) +testmath("Math.sqrt", "Number.NaN", Number.NaN) +testmath("Math.sqrt", "Number.NEGATIVE_INFINITY", Number.NaN) +testmath("Math.sqrt", "-1", Number.NaN) +testmath("Math.sqrt", "-0.5", Number.NaN) +testmath("Math.sqrt", "0", 0) +testmath("Math.sqrt", "-0", -0) +testmath("Infinity/Math.sqrt", "-0", -Infinity) +testmath("Math.sqrt", "Number.POSITIVE_INFINITY", Number.POSITIVE_INFINITY) +testmath("Math.sqrt", "1", 1) +testmath("Math.sqrt", "2", Math.SQRT2) +testmath("Math.sqrt", "0.5", Math.SQRT1_2) +testmath("Math.sqrt", "4", 2) +testmath("Math.sqrt", "9", 3) +testmath("Math.sqrt", "16", 4) +testmath("Math.sqrt", "25", 5) +testmath("Math.sqrt", "36", 6) +testmath("Math.sqrt", "49", 7) +testmath("Math.sqrt", "64", 8) +testmath("Math.sqrt", "256", 16) +testmath("Math.sqrt", "10000", 100) +testmath("Math.sqrt", "65536", 256) +testmath("Math.sqrt", "0.09", 0.3) +testmath("Math.sqrt", "0.01", 0.1) +testmath("Math.sqrt", "0.00000001", 0.0001) + +testmath("Math.tan", "void 0", Number.NaN) +testmath("Math.tan", "null", 0) +testmath("Math.tan", "false", 0) +testmath("Math.tan", "Number.NaN", Number.NaN) +testmath("Math.tan", "0", 0) +testmath("Math.tan", "-0", -0) +testmath("Math.tan", "Number.POSITIVE_INFINITY", Number.NaN) +testmath("Math.tan", "Number.NEGATIVE_INFINITY", Number.NaN) +testmath("Math.tan", "Math.PI/4", 1) +testmath("Math.tan", "3*Math.PI/4", -1) +testmath("Math.tan", "Math.PI", -0) +testmath("Math.tan", "5*Math.PI/4", 1) +testmath("Math.tan", "7*Math.PI/4", -1) +testmath("Infinity/Math.tan", "-0", -Infinity) diff --git a/js/src/jit-test/tests/basic/merge_type_maps.js b/js/src/jit-test/tests/basic/merge_type_maps.js new file mode 100644 index 0000000..1be4b9d --- /dev/null +++ b/js/src/jit-test/tests/basic/merge_type_maps.js @@ -0,0 +1,9 @@ +var merge_type_maps_x = 0, merge_type_maps_y = 0; +function merge_type_maps() { + for (merge_type_maps_x = 0; merge_type_maps_x < 50; ++merge_type_maps_x) + if ((merge_type_maps_x & 1) == 1) + ++merge_type_maps_y; + return [merge_type_maps_x,merge_type_maps_y].join(","); +} +merge_type_maps(); + diff --git a/js/src/jit-test/tests/basic/missingArgTest.js b/js/src/jit-test/tests/basic/missingArgTest.js new file mode 100644 index 0000000..28fe790 --- /dev/null +++ b/js/src/jit-test/tests/basic/missingArgTest.js @@ -0,0 +1,12 @@ +function arity1(x) +{ + return (x == undefined) ? 1 : 0; +} +function missingArgTest() { + var q; + for (var i = 0; i < 10; i++) { + q = arity1(); + } + return q; +} +assertEq(missingArgTest(), 1); diff --git a/js/src/jit-test/tests/basic/missingArgTest2.js b/js/src/jit-test/tests/basic/missingArgTest2.js new file mode 100644 index 0000000..3d48a36 --- /dev/null +++ b/js/src/jit-test/tests/basic/missingArgTest2.js @@ -0,0 +1,26 @@ +JSON = function () { + return { + stringify: function stringify(value, whitelist) { + switch (typeof(value)) { + case "object": + return value.constructor.name; + } + } + }; +}(); + +function missingArgTest2() { + var testPairs = [ + ["{}", {}], + ["[]", []], + ['{"foo":"bar"}', {"foo":"bar"}], + ] + + var a = []; + for (var i=0; i < testPairs.length; i++) { + var s = JSON.stringify(testPairs[i][1]) + a[i] = s; + } + return a.join(","); +} +assertEq(missingArgTest2(), "Object,Array,Object"); diff --git a/js/src/jit-test/tests/basic/mod.js b/js/src/jit-test/tests/basic/mod.js new file mode 100644 index 0000000..cd8f6f6 --- /dev/null +++ b/js/src/jit-test/tests/basic/mod.js @@ -0,0 +1,14 @@ +function mod() +{ + var mods = [-1,-1,-1,-1]; + var a = 9.5, b = -5, c = 42, d = (1/0); + for (var i = 0; i < 20; i++) { + mods[0] = a % b; + mods[1] = b % 1; + mods[2] = c % d; + mods[3] = c % a; + mods[4] = b % 0; + } + return mods.toString(); +} +assertEq(mod(), "4.5,0,42,4,NaN"); diff --git a/js/src/jit-test/tests/basic/name-inactive-del.js b/js/src/jit-test/tests/basic/name-inactive-del.js new file mode 100644 index 0000000..ba2f69f --- /dev/null +++ b/js/src/jit-test/tests/basic/name-inactive-del.js @@ -0,0 +1,28 @@ +function mp(g) { + var ans = ''; + for (var i = 0; i < 5; ++i) { + ans += g(); + } + + return ans; +} + +function f() { + var k = 5; + + function g() { + return k; + } + + ans = ''; + + k = 6; + ans += mp(g); + + delete k; + ans += mp(g); + + return ans; +} + +assertEq(f(), '6666666666'); diff --git a/js/src/jit-test/tests/basic/name-inactive-eval-del.js b/js/src/jit-test/tests/basic/name-inactive-eval-del.js new file mode 100644 index 0000000..593ab39 --- /dev/null +++ b/js/src/jit-test/tests/basic/name-inactive-eval-del.js @@ -0,0 +1,10 @@ +function mp(g) { + ans = '' + for (var i = 0; i < 5; ++i) { + ans += g(); + } + return ans; +} + +var f = eval("(function() { var k = 5; function g() { return k; } k = 6; mp(g); delete k; return mp(g); })"); +assertEq(f(), "66666"); diff --git a/js/src/jit-test/tests/basic/name-inactive-inferflags.js b/js/src/jit-test/tests/basic/name-inactive-inferflags.js new file mode 100644 index 0000000..0bbd3fb --- /dev/null +++ b/js/src/jit-test/tests/basic/name-inactive-inferflags.js @@ -0,0 +1,18 @@ +function addAccumulations(f) { + var a = f(); + var b = f(); + return a() + b(); +} + +function loopingAccumulator() { + var x = 0; + return function () { + for (var i = 0; i < 10; ++i) { + ++x; + } + return x; + } +} + +var x = addAccumulations(loopingAccumulator); +assertEq(x, 20); diff --git a/js/src/jit-test/tests/basic/name-inactive.js b/js/src/jit-test/tests/basic/name-inactive.js new file mode 100644 index 0000000..d9475b4 --- /dev/null +++ b/js/src/jit-test/tests/basic/name-inactive.js @@ -0,0 +1,20 @@ +function f(k) { + function g(j) { + return j + k; + } + return g; +} + +g = f(10); +var ans = ''; +for (var i = 0; i < 5; ++i) { + ans += g(i) + ','; +} + +assertEq(ans, '10,11,12,13,14,'); + +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceTriggered: 1 +}); diff --git a/js/src/jit-test/tests/basic/name.js b/js/src/jit-test/tests/basic/name.js new file mode 100644 index 0000000..92b76d0 --- /dev/null +++ b/js/src/jit-test/tests/basic/name.js @@ -0,0 +1,9 @@ +globalName = 907; +function name() +{ + var a = 0; + for (var i = 0; i < 100; i++) + a = globalName; + return a; +} +assertEq(name(), 907); diff --git a/js/src/jit-test/tests/basic/nestedExit2.js b/js/src/jit-test/tests/basic/nestedExit2.js new file mode 100644 index 0000000..a868954 --- /dev/null +++ b/js/src/jit-test/tests/basic/nestedExit2.js @@ -0,0 +1,17 @@ +function bitsinbyte(b) { + var m = 1, c = 0; + while(m<0x100) { + if(b & m) c++; + m <<= 1; + } + return 1; +} +function TimeFunc(func) { + var x,y; + for(var y=0; y<256; y++) func(y); +} +function nestedExit2() { + TimeFunc(bitsinbyte); + return "ok"; +} +assertEq(nestedExit2(), "ok"); diff --git a/js/src/jit-test/tests/basic/nestedExitLoop.js b/js/src/jit-test/tests/basic/nestedExitLoop.js new file mode 100644 index 0000000..fffc857 --- /dev/null +++ b/js/src/jit-test/tests/basic/nestedExitLoop.js @@ -0,0 +1,14 @@ +function nestedExit(x) { + var q = 0; + for (var i = 0; i < 10; ++i) + { + if (x) + ++q; + } +} +function nestedExitLoop() { + for (var j = 0; j < 10; ++j) + nestedExit(j < 7); + return "ok"; +} +assertEq(nestedExitLoop(), "ok"); diff --git a/js/src/jit-test/tests/basic/new-Function-prototype.js b/js/src/jit-test/tests/basic/new-Function-prototype.js new file mode 100644 index 0000000..72bc5f7 --- /dev/null +++ b/js/src/jit-test/tests/basic/new-Function-prototype.js @@ -0,0 +1,22 @@ +var funProto = Function.prototype; +assertEq(Object.getOwnPropertyDescriptor(funProto, "prototype"), undefined); + +assertEq(parseInt.prototype, undefined); + +var oldObj; +for (var i = 0, sz = RUNLOOP; i < sz; oldObj = obj, i++) +{ + var obj = new funProto; + assertEq(obj === oldObj, false); + assertEq(Object.prototype.toString.call(obj), "[object Object]"); + assertEq(Object.getOwnPropertyDescriptor(funProto, "prototype"), undefined); + assertEq(Object.getOwnPropertyDescriptor(parseInt, "prototype"), undefined); + assertEq(parseInt.prototype, undefined); +} + +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceTriggered: 1, + traceCompleted: 1, +}); diff --git a/js/src/jit-test/tests/basic/new-bound-function.js b/js/src/jit-test/tests/basic/new-bound-function.js new file mode 100644 index 0000000..db531a7 --- /dev/null +++ b/js/src/jit-test/tests/basic/new-bound-function.js @@ -0,0 +1,26 @@ +var funProto = Function.prototype; +assertEq(Object.getOwnPropertyDescriptor(funProto, "prototype"), undefined); + +function Point(x, y) { this.x = x; this.y = y; } + +var YAxisPoint = Point.bind(null, 0); + +assertEq(YAxisPoint.prototype, undefined); + +var oldPoint; +for (var i = 0, sz = RUNLOOP; i < sz; oldPoint = point, i++) +{ + var point = new YAxisPoint(5); + assertEq(point === oldPoint, false); + assertEq(point.x, 0); + assertEq(point.y, 5); + assertEq(Object.getOwnPropertyDescriptor(funProto, "prototype"), undefined); + assertEq(Object.getOwnPropertyDescriptor(YAxisPoint, "prototype"), undefined); +} + +checkStats({ + recorderStarted: 1, + recorderAborted: 1, + traceTriggered: 0, + traceCompleted: 0, +}); diff --git a/js/src/jit-test/tests/basic/newArrayTest.js b/js/src/jit-test/tests/basic/newArrayTest.js new file mode 100644 index 0000000..e6bd817 --- /dev/null +++ b/js/src/jit-test/tests/basic/newArrayTest.js @@ -0,0 +1,8 @@ +function newArrayTest() +{ + var a = []; + for (var i = 0; i < 10; i++) + a[i] = new Array(); + return a.map(function(x) x.length).toString(); +} +assertEq(newArrayTest(), "0,0,0,0,0,0,0,0,0,0"); diff --git a/js/src/jit-test/tests/basic/newTest.js b/js/src/jit-test/tests/basic/newTest.js new file mode 100644 index 0000000..5defbe9 --- /dev/null +++ b/js/src/jit-test/tests/basic/newTest.js @@ -0,0 +1,14 @@ +function MyConstructor(i) +{ + this.i = i; +} +MyConstructor.prototype.toString = function() {return this.i + ""}; + +function newTest() +{ + var a = []; + for (var i = 0; i < 10; i++) + a[i] = new MyConstructor(i); + return a.join(""); +} +assertEq(newTest(), "0123456789"); diff --git a/js/src/jit-test/tests/basic/nonEmptyStack1.js b/js/src/jit-test/tests/basic/nonEmptyStack1.js new file mode 100644 index 0000000..b3b2603 --- /dev/null +++ b/js/src/jit-test/tests/basic/nonEmptyStack1.js @@ -0,0 +1,13 @@ +function nonEmptyStack1Helper(o, farble) { + var a = []; + var j = 0; + for (var i in o) + a[j++] = i; + return a.join(""); +} + +function nonEmptyStack1() { + return nonEmptyStack1Helper({a:1,b:2,c:3,d:4,e:5,f:6,g:7,h:8}, "hi"); +} + +assertEq(nonEmptyStack1(), "abcdefgh"); diff --git a/js/src/jit-test/tests/basic/nonEmptyStack2.js b/js/src/jit-test/tests/basic/nonEmptyStack2.js new file mode 100644 index 0000000..fb83942 --- /dev/null +++ b/js/src/jit-test/tests/basic/nonEmptyStack2.js @@ -0,0 +1,10 @@ +function nonEmptyStack2() +{ + var a = 0; + for (var c in {a:1, b:2, c:3}) { + for (var i = 0; i < 10; i++) + a += i; + } + return String(a); +} +assertEq(nonEmptyStack2(), "135"); diff --git a/js/src/jit-test/tests/basic/orNaNTest1.js b/js/src/jit-test/tests/basic/orNaNTest1.js new file mode 100644 index 0000000..0b713b2 --- /dev/null +++ b/js/src/jit-test/tests/basic/orNaNTest1.js @@ -0,0 +1,3 @@ +load(libdir + 'orTestHelper.js'); +var orNaNTest1 = new Function("return orTestHelper(NaN, NaN, 10);"); +assertEq(orNaNTest1(), 0); diff --git a/js/src/jit-test/tests/basic/orNaNTest2.js b/js/src/jit-test/tests/basic/orNaNTest2.js new file mode 100644 index 0000000..113fe03 --- /dev/null +++ b/js/src/jit-test/tests/basic/orNaNTest2.js @@ -0,0 +1,3 @@ +load(libdir + 'orTestHelper.js'); +var orNaNTest2 = new Function("return orTestHelper(NaN, 1, 10);"); +assertEq(orNaNTest2(), 45); diff --git a/js/src/jit-test/tests/basic/outerline.js b/js/src/jit-test/tests/basic/outerline.js new file mode 100644 index 0000000..8056864 --- /dev/null +++ b/js/src/jit-test/tests/basic/outerline.js @@ -0,0 +1,15 @@ +function outerline(){ + var i=0; + var j=0; + + for (i = 3; i<= 100000; i+=2) + { + for (j = 3; j < 1000; j+=2) + { + if ((i & 1) == 1) + break; + } + } + return "ok"; +} +assertEq(outerline(), "ok"); diff --git a/js/src/jit-test/tests/basic/parseIntTests.js b/js/src/jit-test/tests/basic/parseIntTests.js new file mode 100644 index 0000000..c8ecb36 --- /dev/null +++ b/js/src/jit-test/tests/basic/parseIntTests.js @@ -0,0 +1,23 @@ +function parseIntHelper(n) { + var a; + for (var i = 0; i < 5; i++) + a = parseInt(n); + return a; +} +function doParseIntTests() { + var inputs = [0, -0, .1, -.1, .7, -.7, 1.3, -1.3]; + var outputs = new Array(8); + //avoid jit, unrolled + outputs[0] = outputs[1] = outputs[2] = outputs[4] = 0; + outputs[3] = outputs[5] = -0; + outputs[6] = 1; + outputs[7] = -1; + for (var i = 0; i < 8; i++) { + var testfn = new Function('return parseIntHelper(' + uneval(inputs[i]) + ');'); + assertEq(testfn(), outputs[i]); + } +} +doParseIntTests(); + +assertEq(parseInt("08"), 0); +assertEq(parseInt("09"), 0); diff --git a/js/src/jit-test/tests/basic/parsingNumbers.js b/js/src/jit-test/tests/basic/parsingNumbers.js new file mode 100644 index 0000000..1630612 --- /dev/null +++ b/js/src/jit-test/tests/basic/parsingNumbers.js @@ -0,0 +1,23 @@ +function parsingNumbers() { + var s1 = "123"; + var s1z = "123zzz"; + var s2 = "123.456"; + var s2z = "123.456zzz"; + + var e1 = 123; + var e2 = 123.456; + + var r1, r1z, r2, r2z; + + for (var i = 0; i < 10; i++) { + r1 = parseInt(s1); + r1z = parseInt(s1z); + r2 = parseFloat(s2); + r2z = parseFloat(s2z); + } + + if (r1 == e1 && r1z == e1 && r2 == e2 && r2z == e2) + return "ok"; + return "fail"; +} +assertEq(parsingNumbers(), "ok"); diff --git a/js/src/jit-test/tests/basic/perf-smoketest.js b/js/src/jit-test/tests/basic/perf-smoketest.js new file mode 100644 index 0000000..7c442ca --- /dev/null +++ b/js/src/jit-test/tests/basic/perf-smoketest.js @@ -0,0 +1,34 @@ +function spin_loop() +{ + for (let i = 0; i < 10000; i++) ; +} + +function check_timing(label, count) { + if (count == -1) { + print("TEST-UNEXPECTED-FAIL | TestPerf | " + label); + throwError(); + } else { + print("TEST-PASS | TestPerf | " + label + " = " + count); + } +} + +var pm = new PerfMeasurement(PerfMeasurement.ALL); +if (pm.eventsMeasured == 0) { + print("TEST-KNOWN-FAIL | perf-smoketest | stub, skipping test"); +} else { + pm.start(); + spin_loop(); + pm.stop(); + + check_timing("cpu_cycles", pm.cpu_cycles); + check_timing("instructions", pm.instructions); + check_timing("cache_references", pm.cache_references); + check_timing("cache_misses", pm.cache_misses); + check_timing("branch_instructions", pm.branch_instructions); + check_timing("branch_misses", pm.branch_misses); + check_timing("bus_cycles", pm.bus_cycles); + check_timing("page_faults", pm.page_faults); + check_timing("major_page_faults", pm.major_page_faults); + check_timing("context_switches", pm.context_switches); + check_timing("cpu_migrations", pm.cpu_migrations); +} diff --git a/js/src/jit-test/tests/basic/putargsNoReturn.js b/js/src/jit-test/tests/basic/putargsNoReturn.js new file mode 100644 index 0000000..73df78b --- /dev/null +++ b/js/src/jit-test/tests/basic/putargsNoReturn.js @@ -0,0 +1,6 @@ +function f(a) { + x = arguments; +} +for (var i = 0; i < 9; i++) + f(123); +assertEq(x[0], 123); diff --git a/js/src/jit-test/tests/basic/putargsReturn.js b/js/src/jit-test/tests/basic/putargsReturn.js new file mode 100644 index 0000000..1a6f3c3 --- /dev/null +++ b/js/src/jit-test/tests/basic/putargsReturn.js @@ -0,0 +1,7 @@ +function f(a) { + x = arguments; + return 99; +} +for (var i = 0; i < 9; i++) + f(123); +assertEq(x[0], 123); diff --git a/js/src/jit-test/tests/basic/regexp-reset-input.js b/js/src/jit-test/tests/basic/regexp-reset-input.js new file mode 100644 index 0000000..77cdd69 --- /dev/null +++ b/js/src/jit-test/tests/basic/regexp-reset-input.js @@ -0,0 +1,8 @@ +var re = /(pattern)/g; +var input = "patternpatternpattern"; +re.exec(input) +RegExp.input = "satturn"; +assertEq(RegExp.$1, "pattern"); +assertEq(RegExp.lastMatch, "pattern"); +assertEq(RegExp.lastParen, "pattern"); +assertEq(RegExp.rightContext, "patternpattern"); diff --git a/js/src/jit-test/tests/basic/regexp-sticky-undef-capture.js b/js/src/jit-test/tests/basic/regexp-sticky-undef-capture.js new file mode 100644 index 0000000..3d96d4e --- /dev/null +++ b/js/src/jit-test/tests/basic/regexp-sticky-undef-capture.js @@ -0,0 +1,8 @@ +var re = /abc(WHOO!)?def/y; +var input = 'abcdefabcdefabcdef'; +var count = 0; +while ((match = re.exec(input)) !== null) { + print(count++); + assertEq(match[0], 'abcdef'); + assertEq(match[1], undefined); +} diff --git a/js/src/jit-test/tests/basic/regexpLastIndex.js b/js/src/jit-test/tests/basic/regexpLastIndex.js new file mode 100644 index 0000000..80991fa --- /dev/null +++ b/js/src/jit-test/tests/basic/regexpLastIndex.js @@ -0,0 +1,13 @@ +function regexpLastIndex() +{ + var n = 0; + var re = /hi/g; + var ss = " hi hi hi hi hi hi hi hi hi hi"; + for (var i = 0; i < 10; i++) { + // re.exec(ss); + n += (re.lastIndex > 0) ? 3 : 0; + re.lastIndex = 0; + } + return n; +} +assertEq(regexpLastIndex(), 0); diff --git a/js/src/jit-test/tests/basic/setArgumentsLength.js b/js/src/jit-test/tests/basic/setArgumentsLength.js new file mode 100644 index 0000000..775d3ef --- /dev/null +++ b/js/src/jit-test/tests/basic/setArgumentsLength.js @@ -0,0 +1,14 @@ +var count = 0; + +function f() { + arguments.length--; + for (var i = 0; i < arguments.length; ++i) { + ++count; + } +} + +f(1, 2); +f(1, 2); +f(2, 2); + +assertEq(count, 3); diff --git a/js/src/jit-test/tests/basic/setArgumentsLength2.js b/js/src/jit-test/tests/basic/setArgumentsLength2.js new file mode 100644 index 0000000..2dcb174 --- /dev/null +++ b/js/src/jit-test/tests/basic/setArgumentsLength2.js @@ -0,0 +1,12 @@ +// don't crash + +var q; + +function f() { + while (arguments.length > 0) { + q = arguments[arguments.length-1]; + arguments.length--; + } +} + +f(1, 2, 3, 4, 5); diff --git a/js/src/jit-test/tests/basic/setCall.js b/js/src/jit-test/tests/basic/setCall.js new file mode 100644 index 0000000..fa9e95d --- /dev/null +++ b/js/src/jit-test/tests/basic/setCall.js @@ -0,0 +1,26 @@ +function f() { + var x = 11; + + function g() { + var y = 12; + + function h() { + for (var i = 0; i < 5; ++i) { + y = 4; + x = i * 2; + } + } + h(); + + assertEq(y, 4); + } + g(); + + assertEq(x, 8); +} + +f(); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, +}); diff --git a/js/src/jit-test/tests/basic/setCallEvalMiddle.js b/js/src/jit-test/tests/basic/setCallEvalMiddle.js new file mode 100644 index 0000000..71de2ac --- /dev/null +++ b/js/src/jit-test/tests/basic/setCallEvalMiddle.js @@ -0,0 +1,17 @@ +eval(1); // avoid global shape change when we call eval below +function q() { + var x = 1; + function f() { + function g() { + var t=0; + for (var i=0; i<3; i++) + x = i; + }; + g(); + eval("var x = 3"); + g(); + assertEq(x, 2); + } + f(); +} +q(); diff --git a/js/src/jit-test/tests/basic/setCallEvalMiddle2.js b/js/src/jit-test/tests/basic/setCallEvalMiddle2.js new file mode 100644 index 0000000..b93622f --- /dev/null +++ b/js/src/jit-test/tests/basic/setCallEvalMiddle2.js @@ -0,0 +1,18 @@ +eval(1); // avoid global shape change when we call eval below +function q() { + var x = 1; + function f() { + function g() { + var t=0; + for (var i=0; i<3; i++) + x = i; + assertEq(x, 2); + eval("var x = 3"); + }; + g(); + g(); + assertEq(x, 2); + } + f(); +} +q(); diff --git a/js/src/jit-test/tests/basic/setCallGlobal.js b/js/src/jit-test/tests/basic/setCallGlobal.js new file mode 100644 index 0000000..a4ba54b --- /dev/null +++ b/js/src/jit-test/tests/basic/setCallGlobal.js @@ -0,0 +1,14 @@ +var x = 1; +function f() { + function g() { + var t=0; + for (var i=0; i<3; i++) + x = i; + }; + g(); + eval("var x = 2"); + g(); + assertEq(x, 2); +} +f(); +assertEq(x, 2); diff --git a/js/src/jit-test/tests/basic/setelem.js b/js/src/jit-test/tests/basic/setelem.js new file mode 100644 index 0000000..cdbe035 --- /dev/null +++ b/js/src/jit-test/tests/basic/setelem.js @@ -0,0 +1,12 @@ +var a; +function setelem() +{ + a = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + a = a.concat(a, a, a); + var l = a.length; + for (var i = 0; i < l; i++) { + a[i] = i; + } + return a.toString(); +} +assertEq(setelem(), "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83"); diff --git a/js/src/jit-test/tests/basic/setprop.js b/js/src/jit-test/tests/basic/setprop.js new file mode 100644 index 0000000..bb93e1e --- /dev/null +++ b/js/src/jit-test/tests/basic/setprop.js @@ -0,0 +1,10 @@ +function setprop() +{ + var obj = { a:-1 }; + var obj2 = { b:-1, a:-1 }; + for (var i = 0; i < 20; i++) { + obj2.b = obj.a = i; + } + return [obj.a, obj2.a, obj2.b].toString(); +} +assertEq(setprop(), "19,-1,19"); diff --git a/js/src/jit-test/tests/basic/shapelessCalleeTest.js b/js/src/jit-test/tests/basic/shapelessCalleeTest.js new file mode 100644 index 0000000..78c42ad --- /dev/null +++ b/js/src/jit-test/tests/basic/shapelessCalleeTest.js @@ -0,0 +1,67 @@ +// The following functions use a delay line of length 2 to change the value +// of the callee without exiting the traced loop. This is obviously tuned to +// match the current HOTLOOP setting of 2. +function shapelessArgCalleeLoop(f, g, h, a) +{ + for (var i = 0; i < 10; i++) { + f(i, a); + f = g; + g = h; + } +} + +function shapelessVarCalleeLoop(f0, g, h, a) +{ + var f = f0; + for (var i = 0; i < 10; i++) { + f(i, a); + f = g; + g = h; + } +} + +function shapelessLetCalleeLoop(f0, g, h, a) +{ + for (var i = 0; i < 10; i++) { + let f = f0; + f(i, a); + f = g; + g = h; + } +} + +function shapelessUnknownCalleeLoop(n, f, g, h, a) +{ + for (var i = 0; i < 10; i++) { + (n || f)(i, a); + f = g; + g = h; + } +} + +function shapelessCalleeTest() +{ + var a = []; + + var helper = function (i, a) a[i] = i; + shapelessArgCalleeLoop(helper, helper, function (i, a) a[i] = -i, a); + + helper = function (i, a) a[10 + i] = i; + shapelessVarCalleeLoop(helper, helper, function (i, a) a[10 + i] = -i, a); + + helper = function (i, a) a[20 + i] = i; + shapelessLetCalleeLoop(helper, helper, function (i, a) a[20 + i] = -i, a); + + helper = function (i, a) a[30 + i] = i; + shapelessUnknownCalleeLoop(null, helper, helper, function (i, a) a[30 + i] = -i, a); + + try { + helper = {hack: 42}; + shapelessUnknownCalleeLoop(null, helper, helper, helper, a); + } catch (e) { + if (e + "" != "TypeError: f is not a function") + print("shapelessUnknownCalleeLoop: unexpected exception " + e); + } + return a.join(""); +} +assertEq(shapelessCalleeTest(), "01-2-3-4-5-6-7-8-901-2-3-4-5-6-7-8-9012345678901-2-3-4-5-6-7-8-9"); diff --git a/js/src/jit-test/tests/basic/strict-eval-loop-error.js b/js/src/jit-test/tests/basic/strict-eval-loop-error.js new file mode 100644 index 0000000..f284677 --- /dev/null +++ b/js/src/jit-test/tests/basic/strict-eval-loop-error.js @@ -0,0 +1,3 @@ +var COUNT = RUNLOOP; +eval("'use strict'; for (let j = 0; j < COUNT; j++); try { x; throw new Error(); } catch (e) { if (!(e instanceof ReferenceError)) throw e; }"); +assertEq(typeof j, "undefined"); diff --git a/js/src/jit-test/tests/basic/strictParseIntOctal.js b/js/src/jit-test/tests/basic/strictParseIntOctal.js new file mode 100644 index 0000000..536d2d7 --- /dev/null +++ b/js/src/jit-test/tests/basic/strictParseIntOctal.js @@ -0,0 +1,16 @@ +"use strict"; + +assertEq(parseInt("08"), 0); +assertEq(parseInt("09"), 0); +assertEq(parseInt("014"), 12); +assertEq(parseInt("0xA"), 10); +assertEq(parseInt("00123"), 83); + +for (var i = 0; i < 5; i++) +{ + assertEq(parseInt("08"), 0); + assertEq(parseInt("09"), 0); + assertEq(parseInt("014"), 12); + assertEq(parseInt("0xA"), 10); + assertEq(parseInt("00123"), 83); +} diff --git a/js/src/jit-test/tests/basic/stringConvert.js b/js/src/jit-test/tests/basic/stringConvert.js new file mode 100644 index 0000000..5318189 --- /dev/null +++ b/js/src/jit-test/tests/basic/stringConvert.js @@ -0,0 +1,18 @@ +function stringConvert() +{ + var a = []; + var s1 = "F", s2 = "1.3", s3 = "5"; + for (var i = 0; i < 10; i++) { + a[0] = 1 >> s1; + a[1] = 10 - s2; + a[2] = 15 * s3; + a[3] = s3 | 32; + a[4] = s2 + 60; + // a[5] = 9 + s3; + // a[6] = -s3; + a[7] = s3 & "7"; + // a[8] = ~s3; + } + return a.toString(); +} +assertEq(stringConvert(), "1,8.7,75,37,1.360,,,5"); diff --git a/js/src/jit-test/tests/basic/stringSplitIntoArrayTest.js b/js/src/jit-test/tests/basic/stringSplitIntoArrayTest.js new file mode 100644 index 0000000..e7fdb09 --- /dev/null +++ b/js/src/jit-test/tests/basic/stringSplitIntoArrayTest.js @@ -0,0 +1,9 @@ +function stringSplitIntoArrayTest() +{ + var s = "a,b" + var a = []; + for (var i = 0; i < 10; ++i) + a[i] = s.split(","); + return a.join(); +} +assertEq(stringSplitIntoArrayTest(), "a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b"); diff --git a/js/src/jit-test/tests/basic/stringSplitTest.js b/js/src/jit-test/tests/basic/stringSplitTest.js new file mode 100644 index 0000000..942c7e7 --- /dev/null +++ b/js/src/jit-test/tests/basic/stringSplitTest.js @@ -0,0 +1,9 @@ +function stringSplitTest() +{ + var s = "a,b" + var a = null; + for (var i = 0; i < 10; ++i) + a = s.split(","); + return a.join(); +} +assertEq(stringSplitTest(), "a,b"); diff --git a/js/src/jit-test/tests/basic/strings.js b/js/src/jit-test/tests/basic/strings.js new file mode 100644 index 0000000..19139b9 --- /dev/null +++ b/js/src/jit-test/tests/basic/strings.js @@ -0,0 +1,21 @@ +function strings() +{ + var a = [], b = -1; + var s = "abcdefghij", s2 = "a"; + var f = "f"; + var c = 0, d = 0, e = 0, g = 0; + for (var i = 0; i < 10; i++) { + a[i] = (s.substring(i, i+1) + s[i] + String.fromCharCode(s2.charCodeAt(0) + i)).concat(i) + i; + if (s[i] == f) + c++; + if (s[i] != 'b') + d++; + if ("B" > s2) + g++; // f already used + if (s2 < "b") + e++; + b = s.length; + } + return a.toString() + b + c + d + e + g; +} +assertEq(strings(), "aaa00,bbb11,ccc22,ddd33,eee44,fff55,ggg66,hhh77,iii88,jjj991019100"); diff --git a/js/src/jit-test/tests/basic/test586387.js b/js/src/jit-test/tests/basic/test586387.js new file mode 100644 index 0000000..5ddc2d7 --- /dev/null +++ b/js/src/jit-test/tests/basic/test586387.js @@ -0,0 +1,14 @@ +function testFloatArray() { + var v = new Float32Array(32); + + for (var i = 0; i < v.length; ++i) + v[i] = i; + + var t = 0; + for (var i = 0; i < v.length; ++i) + t += v[i]; + + return t; +} + +assertEq(testFloatArray(), 496); diff --git a/js/src/jit-test/tests/basic/testAbortedImacroDecompilation.js b/js/src/jit-test/tests/basic/testAbortedImacroDecompilation.js new file mode 100644 index 0000000..b1cfdb9 --- /dev/null +++ b/js/src/jit-test/tests/basic/testAbortedImacroDecompilation.js @@ -0,0 +1,7 @@ +function f() { + for (var i=0; i<9; i++) + assertEq("" + f, expected); +} + +var expected = "" + f; +f(); diff --git a/js/src/jit-test/tests/basic/testAccessCanonicalArgInGetElem.js b/js/src/jit-test/tests/basic/testAccessCanonicalArgInGetElem.js new file mode 100644 index 0000000..6440724 --- /dev/null +++ b/js/src/jit-test/tests/basic/testAccessCanonicalArgInGetElem.js @@ -0,0 +1,12 @@ +var o = {x:42}; + +function f(index,param) { + arguments[1] = 0; + var ret = 0; + for (var i = 0; i < 5; ++i) + ret = arguments[index].x; + return ret; +} + +assertEq(f(2,o,o), 42); +assertEq(f(1,o,o), undefined); diff --git a/js/src/jit-test/tests/basic/testAddAnyInconvertibleObject.js b/js/src/jit-test/tests/basic/testAddAnyInconvertibleObject.js new file mode 100644 index 0000000..9995471 --- /dev/null +++ b/js/src/jit-test/tests/basic/testAddAnyInconvertibleObject.js @@ -0,0 +1,33 @@ +function testAddAnyInconvertibleObject() +{ + var count = 0; + function toString() { ++count; if (count == 95) return {}; return "" + count; } + var o = {valueOf: undefined, toString: toString}; + + var threw = false; + try + { + for (var i = 0; i < 100; i++) + var q = 5 + o; + } + catch (e) + { + threw = true; + if (i !== 94) + return "expected i === 94, got " + i; + if (q !== "594") + return "expected q === '594', got " + q + " (type " + typeof q + ")"; + if (count !== 95) + return "expected count === 95, got " + count; + } + if (!threw) + return "expected throw with 5 + o"; // hey, a rhyme! + + return "pass"; +} +assertEq(testAddAnyInconvertibleObject(), "pass"); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + sideExitIntoInterpreter: 3 +}); diff --git a/js/src/jit-test/tests/basic/testAddInconvertibleObjectAny.js b/js/src/jit-test/tests/basic/testAddInconvertibleObjectAny.js new file mode 100644 index 0000000..76c072e --- /dev/null +++ b/js/src/jit-test/tests/basic/testAddInconvertibleObjectAny.js @@ -0,0 +1,39 @@ +function testAddInconvertibleObjectAny() +{ + var count = 0; + function toString() + { + ++count; + if (count == 95) + return {}; + return "" + count; + } + var o = {valueOf: undefined, toString: toString}; + + var threw = false; + try + { + for (var i = 0; i < 100; i++) + var q = o + 5; + } + catch (e) + { + threw = true; + if (i !== 94) + return "expected i === 94, got " + i; + if (q !== "945") + return "expected q === '945', got " + q + " (type " + typeof q + ")"; + if (count !== 95) + return "expected count === 95, got " + count; + } + if (!threw) + return "expected throw with o + 5"; + + return "pass"; +} +assertEq(testAddInconvertibleObjectAny(), "pass"); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + sideExitIntoInterpreter: 3 +}); diff --git a/js/src/jit-test/tests/basic/testAddInconvertibleObjectInconvertibleObject.js b/js/src/jit-test/tests/basic/testAddInconvertibleObjectInconvertibleObject.js new file mode 100644 index 0000000..eabc757 --- /dev/null +++ b/js/src/jit-test/tests/basic/testAddInconvertibleObjectInconvertibleObject.js @@ -0,0 +1,38 @@ +function testAddInconvertibleObjectInconvertibleObject() +{ + var count1 = 0; + function toString1() { ++count1; if (count1 == 95) return {}; return "" + count1; } + var o1 = {valueOf: undefined, toString: toString1}; + var count2 = 0; + function toString2() { ++count2; if (count2 == 95) return {}; return "" + count2; } + var o2 = {valueOf: undefined, toString: toString2}; + + var threw = false; + try + { + for (var i = 0; i < 100; i++) + var q = o1 + o2; + } + catch (e) + { + threw = true; + if (i !== 94) + return "expected i === 94, got " + i; + if (q !== "9494") + return "expected q === '9494', got " + q + " (type " + typeof q + ")"; + if (count1 !== 95) + return "expected count1 === 95, got " + count1; + if (count2 !== 94) + return "expected count2 === 94, got " + count2; + } + if (!threw) + return "expected throw with o1 + o2"; + + return "pass"; +} +assertEq(testAddInconvertibleObjectInconvertibleObject(), "pass"); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + sideExitIntoInterpreter: 3 +}); diff --git a/js/src/jit-test/tests/basic/testAddNull.js b/js/src/jit-test/tests/basic/testAddNull.js new file mode 100644 index 0000000..c5aa863 --- /dev/null +++ b/js/src/jit-test/tests/basic/testAddNull.js @@ -0,0 +1,13 @@ +function testAddNull() +{ + var rv; + for (var x = 0; x < HOTLOOP + 1; ++x) + rv = null + [,,]; + return rv; +} +assertEq(testAddNull(), "null,"); +checkStats({ + recorderStarted: 1, + sideExitIntoInterpreter: 1, + recorderAborted: 0 +}); diff --git a/js/src/jit-test/tests/basic/testAddUndefined.js b/js/src/jit-test/tests/basic/testAddUndefined.js new file mode 100644 index 0000000..9a21e2f --- /dev/null +++ b/js/src/jit-test/tests/basic/testAddUndefined.js @@ -0,0 +1,5 @@ +function testAddUndefined() { + for (var j = 0; j < 3; ++j) + (0 + void 0) && 0; +} +testAddUndefined(); diff --git a/js/src/jit-test/tests/basic/testApply.js b/js/src/jit-test/tests/basic/testApply.js new file mode 100644 index 0000000..73e3592 --- /dev/null +++ b/js/src/jit-test/tests/basic/testApply.js @@ -0,0 +1,7 @@ +function testApply() { + var q = []; + for (var i = 0; i < 10; ++i) + Array.prototype.push.apply(q, [5]); + return q.join(","); +} +assertEq(testApply(), "5,5,5,5,5,5,5,5,5,5"); diff --git a/js/src/jit-test/tests/basic/testApplyAtJoinPoint.js b/js/src/jit-test/tests/basic/testApplyAtJoinPoint.js new file mode 100644 index 0000000..0ed3f58 --- /dev/null +++ b/js/src/jit-test/tests/basic/testApplyAtJoinPoint.js @@ -0,0 +1,12 @@ +var isTrue = true; + +function g(x) { + return x; +} + +function f() { + return g.apply(null, isTrue ? ["happy"] : arguments); +} + +for (var i = 0; i < HOTLOOP + 10; ++i) + assertEq(f("sad"), "happy"); diff --git a/js/src/jit-test/tests/basic/testApplyCall.js b/js/src/jit-test/tests/basic/testApplyCall.js new file mode 100644 index 0000000..0afe2ff --- /dev/null +++ b/js/src/jit-test/tests/basic/testApplyCall.js @@ -0,0 +1,42 @@ +function testApplyCallHelper(f) { + var r = []; + for (var i = 0; i < 10; ++i) f.call(); + r.push(x); + for (var i = 0; i < 10; ++i) f.call(this); + r.push(x); + for (var i = 0; i < 10; ++i) f.apply(this); + r.push(x); + for (var i = 0; i < 10; ++i) f.call(this,0); + r.push(x); + for (var i = 0; i < 10; ++i) f.apply(this,[0]); + r.push(x); + for (var i = 0; i < 10; ++i) f.call(this,0,1); + r.push(x); + for (var i = 0; i < 10; ++i) f.apply(this,[0,1]); + r.push(x); + for (var i = 0; i < 10; ++i) f.call(this,0,1,2); + r.push(x); + for (var i = 0; i < 10; ++i) f.apply(this,[0,1,2]); + r.push(x); + for (var i = 0; i < 10; ++i) f.call(this,0,1,2,3); + r.push(x); + for (var i = 0; i < 10; ++i) f.apply(this,[0,1,2,3]); + r.push(x); + for (var i = 0; i < 10; ++i) f.call(this,0,1,2,3,4); + r.push(x); + for (var i = 0; i < 10; ++i) f.apply(this,[0,1,2,3,4]); + r.push(x); + for (var i = 0; i < 10; ++i) f.call(this,0,1,2,3,4,5); + r.push(x); + for (var i = 0; i < 10; ++i) f.apply(this,[0,1,2,3,4,5]) + r.push(x); + return(r.join(",")); +} +function testApplyCall() { + var r = testApplyCallHelper(function (a0,a1,a2,a3,a4,a5,a6,a7) { x = [a0,a1,a2,a3,a4,a5,a6,a7]; }); + r += testApplyCallHelper(function (a0,a1,a2,a3,a4,a5,a6,a7) { x = [a0,a1,a2,a3,a4,a5,a6,a7]; }); + return r; +} + +assertEq(testApplyCall(), ",,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,0,,,,,,,,0,1,,,,,,,0,1,,,,,,,0,1,2,,,,,,0,1,2,,,,,,0,1,2,3,,,,,0,1,2,3,,,,,0,1,2,3,4,,,,0,1,2,3,4,,,,0,1,2,3,4,5,,,0,1,2,3,4,5,," + +",,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,0,,,,,,,,0,1,,,,,,,0,1,,,,,,,0,1,2,,,,,,0,1,2,,,,,,0,1,2,3,,,,,0,1,2,3,,,,,0,1,2,3,4,,,,0,1,2,3,4,,,,0,1,2,3,4,5,,,0,1,2,3,4,5,,"); diff --git a/js/src/jit-test/tests/basic/testApplyUnbox.js b/js/src/jit-test/tests/basic/testApplyUnbox.js new file mode 100644 index 0000000..5336ace --- /dev/null +++ b/js/src/jit-test/tests/basic/testApplyUnbox.js @@ -0,0 +1,11 @@ +function testApplyUnboxHelper(f,a) { + var q; + for (var i = 0; i < 10; ++i) + q = f.apply(f,a); + return q; +} +function testApplyUnbox() { + var f = function(x) { return x; } + return [testApplyUnboxHelper(f,[1]), testApplyUnboxHelper(f,[true])].join(","); +} +assertEq(testApplyUnbox(), "1,true"); diff --git a/js/src/jit-test/tests/basic/testArrayComp1.js b/js/src/jit-test/tests/basic/testArrayComp1.js new file mode 100644 index 0000000..95e2c6c --- /dev/null +++ b/js/src/jit-test/tests/basic/testArrayComp1.js @@ -0,0 +1,6 @@ +load(libdir + 'range.js'); + +function testArrayComp1() { + return [a for (a in range(0, 10))].join(''); +} +assertEq(testArrayComp1(), '0123456789'); diff --git a/js/src/jit-test/tests/basic/testArrayComp2.js b/js/src/jit-test/tests/basic/testArrayComp2.js new file mode 100644 index 0000000..acf65b6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testArrayComp2.js @@ -0,0 +1,7 @@ +load(libdir + 'range.js'); + +function testArrayComp2() { + return [a + b for (a in range(0, 5)) for (b in range(0, 5))].join(''); +} + +assertEq(testArrayComp2(), '0123412345234563456745678'); diff --git a/js/src/jit-test/tests/basic/testArrayDensityChange.js b/js/src/jit-test/tests/basic/testArrayDensityChange.js new file mode 100644 index 0000000..b9dfaba --- /dev/null +++ b/js/src/jit-test/tests/basic/testArrayDensityChange.js @@ -0,0 +1,17 @@ +function testArrayDensityChange() { + var x = []; + var count = 0; + for (var i=0; i < 100; ++i) { + x[i] = "asdf"; + } + for (var i=0; i < x.length; ++i) { + if (i == 51) + { + x[199] = "asdf"; + } + if (x[i]) + count += x[i].length; + } + return count; +} +assertEq(testArrayDensityChange(), 404); diff --git a/js/src/jit-test/tests/basic/testArrayIn.js b/js/src/jit-test/tests/basic/testArrayIn.js new file mode 100644 index 0000000..47b7cf6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testArrayIn.js @@ -0,0 +1,54 @@ +// Give us enough room to work with some holes too +const array_size = RUNLOOP + 20; + +function testArrayIn() +{ + var arr = new Array(array_size); + var i; + for (i = 0; i < array_size; ++i) { + arr[i] = i; + } + + // Sanity check here + checkStats({ + traceCompleted: 1, + traceTriggered: 1, + sideExitIntoInterpreter: 1 + }); + + delete arr[RUNLOOP + 5]; + delete arr[RUNLOOP + 10]; + + var ret = []; + for (i = 0; i < array_size; ++i) { + ret.push(i in arr); + } + + checkStats({ + traceCompleted: 2, + traceTriggered: 2, + sideExitIntoInterpreter: 2 + }); + + + var ret2; + for (i = 0; i < RUNLOOP; ++i) { + ret2 = array_size in arr; + } + + checkStats({ + traceCompleted: 3, + traceTriggered: 3, + sideExitIntoInterpreter: 3 + }); + + return [ret, ret2]; +} + +var [ret, ret2] = testArrayIn(); + +assertEq(ret2, false); + +for (var i = 0; i < array_size; ++i) { + assertEq(ret[i], i != RUNLOOP + 5 && i != RUNLOOP + 10); +} diff --git a/js/src/jit-test/tests/basic/testArrayInWithIndexedProto.js b/js/src/jit-test/tests/basic/testArrayInWithIndexedProto.js new file mode 100644 index 0000000..8bfc8a6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testArrayInWithIndexedProto.js @@ -0,0 +1,31 @@ +function testArrayInWithIndexedProto() +{ + Array.prototype[0] = "Got me"; + var zeroPresent, zeroPresent2; + // Need to go to 2*RUNLOOP because in the failure mode this is + // testing we have various side-exits in there due to interp and + // tracer not agreeing that confuse the issue and cause us to not + // hit the bad case within RUNLOOP iterations. + for (var j = 0; j < 2*RUNLOOP; ++j) { + zeroPresent = 0 in []; + } + + var arr = [1, 2]; + delete arr[0]; + for (var j = 0; j < 2*RUNLOOP; ++j) { + zeroPresent2 = 0 in arr; + } + return [zeroPresent, zeroPresent2]; +} + +var [ret, ret2] = testArrayInWithIndexedProto(); +assertEq(ret, true); +assertEq(ret2, true); + +checkStats({ + traceCompleted: 0, + traceTriggered: 0, + sideExitIntoInterpreter: 0, + recorderStarted: 2, + recorderAborted: 2 +}); diff --git a/js/src/jit-test/tests/basic/testArrayNaNIndex.js b/js/src/jit-test/tests/basic/testArrayNaNIndex.js new file mode 100644 index 0000000..671f6ff --- /dev/null +++ b/js/src/jit-test/tests/basic/testArrayNaNIndex.js @@ -0,0 +1,7 @@ +function testArrayNaNIndex() +{ + for (var j = 0; j < 4; ++j) { [this[NaN]]; } + for (var j = 0; j < 5; ++j) { if([1][-0]) { } } + return "ok"; +} +assertEq(testArrayNaNIndex(), "ok"); diff --git a/js/src/jit-test/tests/basic/testArrayNamedProp.js b/js/src/jit-test/tests/basic/testArrayNamedProp.js new file mode 100644 index 0000000..7357412 --- /dev/null +++ b/js/src/jit-test/tests/basic/testArrayNamedProp.js @@ -0,0 +1,5 @@ +function testArrayNamedProp() { + for (var x = 0; x < 10; ++x) { [4].sort-- } + return "ok"; +} +assertEq(testArrayNamedProp(), "ok"); diff --git a/js/src/jit-test/tests/basic/testArrayPushPop.js b/js/src/jit-test/tests/basic/testArrayPushPop.js new file mode 100644 index 0000000..8e00dad --- /dev/null +++ b/js/src/jit-test/tests/basic/testArrayPushPop.js @@ -0,0 +1,11 @@ +function testArrayPushPop() { + var a = [], sum1 = 0, sum2 = 0; + for (var i = 0; i < 10; ++i) + sum1 += a.push(i); + for (var i = 0; i < 10; ++i) + sum2 += a.pop(); + a.push(sum1); + a.push(sum2); + return a.join(","); +} +assertEq(testArrayPushPop(), "55,45"); diff --git a/js/src/jit-test/tests/basic/testAssigningWatchedDeletedProperty.js b/js/src/jit-test/tests/basic/testAssigningWatchedDeletedProperty.js new file mode 100644 index 0000000..62fa710 --- /dev/null +++ b/js/src/jit-test/tests/basic/testAssigningWatchedDeletedProperty.js @@ -0,0 +1,7 @@ +var o = {}; +o.watch("p", function() { }); + +for (var i = 0; i < HOTLOOP + 2; i++) { + o.p = 123; + delete o.p; +} diff --git a/js/src/jit-test/tests/basic/testAssignmentThatIgnoresSetterRetval.js b/js/src/jit-test/tests/basic/testAssignmentThatIgnoresSetterRetval.js new file mode 100644 index 0000000..1c59113 --- /dev/null +++ b/js/src/jit-test/tests/basic/testAssignmentThatIgnoresSetterRetval.js @@ -0,0 +1,10 @@ +var o = { + set x(v) { + return 42; + } +}; + +for (var i = 0; i < 10; ++i) { + var z = o.x = "choose me"; + assertEq(z, "choose me"); +} diff --git a/js/src/jit-test/tests/basic/testAtomize.js b/js/src/jit-test/tests/basic/testAtomize.js new file mode 100644 index 0000000..16076eb --- /dev/null +++ b/js/src/jit-test/tests/basic/testAtomize.js @@ -0,0 +1,10 @@ +function testAtomize() { + x = {}; + for (var i = 0; i < 65536; ++i) + x[String.fromCharCode(i)] = 1; + var z = 0; + for (var p in x) + ++z; + return z; +} +assertEq(testAtomize(), 65536) diff --git a/js/src/jit-test/tests/basic/testBitOrAnyInconvertibleObject.js b/js/src/jit-test/tests/basic/testBitOrAnyInconvertibleObject.js new file mode 100644 index 0000000..f0d1db3 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBitOrAnyInconvertibleObject.js @@ -0,0 +1,33 @@ +function testBitOrAnyInconvertibleObject() +{ + var count = 0; + function toString() { ++count; if (count == 95) return {}; return count; } + var o = {valueOf: undefined, toString: toString}; + + var threw = false; + try + { + for (var i = 0; i < 100; i++) + var q = 1 | o; + } + catch (e) + { + threw = true; + if (i !== 94) + return "expected i === 94, got " + i; + if (q !== 95) + return "expected q === 95, got " + q; + if (count !== 95) + return "expected count === 95, got " + count; + } + if (!threw) + return "expected throw with 2 | o"; // hey, a rhyme! + + return "pass"; +} +assertEq(testBitOrAnyInconvertibleObject(), "pass"); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + sideExitIntoInterpreter: 3 +}); diff --git a/js/src/jit-test/tests/basic/testBitOrInconvertibleObjectAny.js b/js/src/jit-test/tests/basic/testBitOrInconvertibleObjectAny.js new file mode 100644 index 0000000..2ccb0d1 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBitOrInconvertibleObjectAny.js @@ -0,0 +1,33 @@ +function testBitOrInconvertibleObjectAny() +{ + var count = 0; + function toString() { ++count; if (count == 95) return {}; return count; } + var o = {valueOf: undefined, toString: toString}; + + var threw = false; + try + { + for (var i = 0; i < 100; i++) + var q = o | 1; + } + catch (e) + { + threw = true; + if (i !== 94) + return "expected i === 94, got " + i; + if (q !== 95) + return "expected q === 95, got " + q; + if (count !== 95) + return "expected count === 95, got " + count; + } + if (!threw) + return "expected throw with o | 2"; + + return "pass"; +} +assertEq(testBitOrInconvertibleObjectAny(), "pass"); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + sideExitIntoInterpreter: 3 +}); diff --git a/js/src/jit-test/tests/basic/testBitOrInconvertibleObjectInconvertibleObject.js b/js/src/jit-test/tests/basic/testBitOrInconvertibleObjectInconvertibleObject.js new file mode 100644 index 0000000..fd4242f --- /dev/null +++ b/js/src/jit-test/tests/basic/testBitOrInconvertibleObjectInconvertibleObject.js @@ -0,0 +1,38 @@ +function testBitOrInconvertibleObjectInconvertibleObject() +{ + var count1 = 0; + function toString1() { ++count1; if (count1 == 95) return {}; return count1; } + var o1 = {valueOf: undefined, toString: toString1}; + var count2 = 0; + function toString2() { ++count2; if (count2 == 95) return {}; return count2; } + var o2 = {valueOf: undefined, toString: toString2}; + + var threw = false; + try + { + for (var i = 0; i < 100; i++) + var q = o1 | o2; + } + catch (e) + { + threw = true; + if (i !== 94) + return "expected i === 94, got " + i; + if (q !== 94) + return "expected q === 94, got " + q; + if (count1 !== 95) + return "expected count1 === 95, got " + count1; + if (count2 !== 94) + return "expected count2 === 94, got " + count2; + } + if (!threw) + return "expected throw with o1 | o2"; + + return "pass"; +} +assertEq(testBitOrInconvertibleObjectInconvertibleObject(), "pass"); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + sideExitIntoInterpreter: 3 +}); diff --git a/js/src/jit-test/tests/basic/testBitwise.js b/js/src/jit-test/tests/basic/testBitwise.js new file mode 100644 index 0000000..5d940a5 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBitwise.js @@ -0,0 +1,12 @@ +function testBitwise() { + var x = 10000; + var y = 123456; + var z = 987234; + for (var i = 0; i < 50; i++) { + x = x ^ y; + y = y | z; + z = ~x; + } + return x + y + z; +} +assertEq(testBitwise(), -1298); diff --git a/js/src/jit-test/tests/basic/testBoolToString.js b/js/src/jit-test/tests/basic/testBoolToString.js new file mode 100644 index 0000000..9eeb40c --- /dev/null +++ b/js/src/jit-test/tests/basic/testBoolToString.js @@ -0,0 +1,3 @@ +// |jit-test| error: TypeError; +var bts = true.toString; +bts(); diff --git a/js/src/jit-test/tests/basic/testBoxDoubleWithDoubleSizedInt.js b/js/src/jit-test/tests/basic/testBoxDoubleWithDoubleSizedInt.js new file mode 100644 index 0000000..5327e56 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBoxDoubleWithDoubleSizedInt.js @@ -0,0 +1,10 @@ +function testBoxDoubleWithDoubleSizedInt() +{ + var i = 0; + var a = new Array(3); + + while (i < a.length) + a[i++] = 0x5a827999; + return a.join(","); +} +assertEq(testBoxDoubleWithDoubleSizedInt(), "1518500249,1518500249,1518500249"); diff --git a/js/src/jit-test/tests/basic/testBranchCse.js b/js/src/jit-test/tests/basic/testBranchCse.js new file mode 100644 index 0000000..1c99658 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBranchCse.js @@ -0,0 +1,7 @@ +function testBranchCse() { + empty = []; + out = []; + for (var j=0;j<10;++j) { empty[42]; out.push((1 * (1)) | ""); } + return out.join(","); +} +assertEq(testBranchCse(), "1,1,1,1,1,1,1,1,1,1"); diff --git a/js/src/jit-test/tests/basic/testBranchingLoop.js b/js/src/jit-test/tests/basic/testBranchingLoop.js new file mode 100644 index 0000000..5c30242 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBranchingLoop.js @@ -0,0 +1,11 @@ +function testBranchingLoop() { + var x = 0; + for (var i=0; i < 100; ++i) { + if (i == 51) { + x += 10; + } + x++; + } + return x; +} +assertEq(testBranchingLoop(), 110); diff --git a/js/src/jit-test/tests/basic/testBranchingUnstableLoop.js b/js/src/jit-test/tests/basic/testBranchingUnstableLoop.js new file mode 100644 index 0000000..f8333ec --- /dev/null +++ b/js/src/jit-test/tests/basic/testBranchingUnstableLoop.js @@ -0,0 +1,11 @@ +function testBranchingUnstableLoop() { + var x = 0; + for (var i=0; i < 100; ++i) { + if (i == 51) { + x += 10.1; + } + x++; + } + return x; +} +assertEq(testBranchingUnstableLoop(), 110.1); diff --git a/js/src/jit-test/tests/basic/testBranchingUnstableLoopCounter.js b/js/src/jit-test/tests/basic/testBranchingUnstableLoopCounter.js new file mode 100644 index 0000000..53fff9e --- /dev/null +++ b/js/src/jit-test/tests/basic/testBranchingUnstableLoopCounter.js @@ -0,0 +1,11 @@ +function testBranchingUnstableLoopCounter() { + var x = 0; + for (var i=0; i < 100; ++i) { + if (i == 51) { + i += 1.1; + } + x++; + } + return x; +} +assertEq(testBranchingUnstableLoopCounter(), 99); diff --git a/js/src/jit-test/tests/basic/testBranchingUnstableObject.js b/js/src/jit-test/tests/basic/testBranchingUnstableObject.js new file mode 100644 index 0000000..338ae73 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBranchingUnstableObject.js @@ -0,0 +1,13 @@ +function testBranchingUnstableObject() { + var x = {s: "a"}; + var t = ""; + for (var i=0; i < 100; ++i) { + if (i == 51) + { + x.s = 5; + } + t += x.s; + } + return t.length; +} +assertEq(testBranchingUnstableObject(), 100); diff --git a/js/src/jit-test/tests/basic/testBrandedVsGeneric.js b/js/src/jit-test/tests/basic/testBrandedVsGeneric.js new file mode 100644 index 0000000..f0a244b --- /dev/null +++ b/js/src/jit-test/tests/basic/testBrandedVsGeneric.js @@ -0,0 +1,17 @@ +const C = function (a, b, c) { + return function C() { + this.m1 = function () a; + this.m2 = function () b; + this.m3 = function () c; + } +}(2,3,4); +var c = new C(); +var d = function (e) {return {m0: function () e}}(5); +for (var i = 0; i < 5; i++) + d.m0(); +C.call(d); +d.__iterator__ = function() {yield 55}; +for (i = 0; i < 5; i++) { + for (j in d) + print(j); +} diff --git a/js/src/jit-test/tests/basic/testBreak.js b/js/src/jit-test/tests/basic/testBreak.js new file mode 100644 index 0000000..3ef7621 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBreak.js @@ -0,0 +1,6 @@ +for (var i = 10; i < 19; i++) + for (var j = 0; j < 9; j++) + if (j < i) + break; + +checkStats({recorderStarted: 3, recorderAborted: 1, traceCompleted: 2}); diff --git a/js/src/jit-test/tests/basic/testBug458838.js b/js/src/jit-test/tests/basic/testBug458838.js new file mode 100644 index 0000000..cd1e05c --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug458838.js @@ -0,0 +1,19 @@ +var escape; +function testBug458838() { + var a = 1; + function g() { + var b = 0 + for (var i = 0; i < 10; ++i) { + b += a; + } + return b; + } + + return g(); +} +assertEq(testBug458838(), 10); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceCompleted: 1 +}); diff --git a/js/src/jit-test/tests/basic/testBug462388.js b/js/src/jit-test/tests/basic/testBug462388.js new file mode 100644 index 0000000..7af29cb --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug462388.js @@ -0,0 +1,6 @@ +//test no multitrees assert +function testBug462388() { + var c = 0, v; for each (let x in ["",v,v,v]) { for (c=0;c<4;++c) { } } + return true; +} +assertEq(testBug462388(), true); diff --git a/js/src/jit-test/tests/basic/testBug462407.js b/js/src/jit-test/tests/basic/testBug462407.js new file mode 100644 index 0000000..82f7340 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug462407.js @@ -0,0 +1,6 @@ +//test no multitrees assert +function testBug462407() { + for each (let i in [0, {}, 0, 1.5, {}, 0, 1.5, 0, 0]) { } + return true; +} +assertEq(testBug462407(), true); diff --git a/js/src/jit-test/tests/basic/testBug463490.js b/js/src/jit-test/tests/basic/testBug463490.js new file mode 100644 index 0000000..730879e --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug463490.js @@ -0,0 +1,18 @@ +//test no multitrees assert +function testBug463490() { + function f(a, b, d) { + for (var i = 0; i < 10; i++) { + if (d) + b /= 2; + } + return a + b; + } + //integer stable loop + f(2, 2, false); + //double stable loop + f(3, 4.5, false); + //integer unstable branch + f(2, 2, true); + return true; +}; +assertEq(testBug463490(), true); diff --git a/js/src/jit-test/tests/basic/testBug465261.js b/js/src/jit-test/tests/basic/testBug465261.js new file mode 100644 index 0000000..be40905 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug465261.js @@ -0,0 +1,7 @@ +// Test no assert or crash +function testBug465261() { + for (let z = 0; z < 2; ++z) { for each (let x in [0, true, (void 0), 0, (void + 0)]) { if(x){} } }; + return true; +} +assertEq(testBug465261(), true); diff --git a/js/src/jit-test/tests/basic/testBug465272.js b/js/src/jit-test/tests/basic/testBug465272.js new file mode 100644 index 0000000..88a8f06 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug465272.js @@ -0,0 +1,6 @@ +function testBug465272() { + var a = new Array(5); + for (j=0;j<5;++j) a[j] = "" + ((5) - 2); + return a.join(","); +} +assertEq(testBug465272(), "3,3,3,3,3"); diff --git a/js/src/jit-test/tests/basic/testBug465483.js b/js/src/jit-test/tests/basic/testBug465483.js new file mode 100644 index 0000000..a2b3da6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug465483.js @@ -0,0 +1,7 @@ +function testBug465483() { + var a = new Array(4); + var c = 0; + for each (i in [4, 'a', 'b', (void 0)]) a[c++] = '' + (i + i); + return a.join(','); +} +assertEq(testBug465483(), '8,aa,bb,NaN'); diff --git a/js/src/jit-test/tests/basic/testBug465688.js b/js/src/jit-test/tests/basic/testBug465688.js new file mode 100644 index 0000000..3eb1bd7 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug465688.js @@ -0,0 +1,6 @@ +//test no assert +function testBug465688() { + for each (let d in [-0x80000000, -0x80000000]) - -d; + return true; +} +assertEq(testBug465688(), true); diff --git a/js/src/jit-test/tests/basic/testBug466128.js b/js/src/jit-test/tests/basic/testBug466128.js new file mode 100644 index 0000000..c4f1918 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug466128.js @@ -0,0 +1,9 @@ +//test no multitrees assert +function testBug466128() { + for (let a = 0; a < 3; ++a) { + for each (let b in [1, 2, "three", 4, 5, 6, 7, 8]) { + } + } + return true; +} +assertEq(testBug466128(), true); diff --git a/js/src/jit-test/tests/basic/testBug466262.js b/js/src/jit-test/tests/basic/testBug466262.js new file mode 100644 index 0000000..450d095 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug466262.js @@ -0,0 +1,11 @@ +//test no assert +function testBug466262() { + var e = 1; + for (var d = 0; d < 3; ++d) { + if (d == 2) { + e = ""; + } + } + return true; +} +assertEq(testBug466262(), true); diff --git a/js/src/jit-test/tests/basic/testBug474769.js b/js/src/jit-test/tests/basic/testBug474769.js new file mode 100644 index 0000000..54dc1f4 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug474769.js @@ -0,0 +1,10 @@ +delete b; +delete q; + +for each (testBug474769_b in [1, 1, 1, 1.5, 1, 1]) { + (function() { for each (let testBug474769_h in [0, 0, 1.4, ""]) {} })() +} +function testBug474769() { + return testBug474769_b; +} +assertEq(testBug474769(), 1); diff --git a/js/src/jit-test/tests/basic/testBug501690.js b/js/src/jit-test/tests/basic/testBug501690.js new file mode 100644 index 0000000..9fa65b6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug501690.js @@ -0,0 +1,14 @@ +function testBug501690() { + // Property cache assertion when 3 objects along a prototype chain have the same shape. + function B(){} + B.prototype = {x: 123}; + + function D(){} + D.prototype = new B; + D.prototype.x = 1; // [1] shapeOf(B.prototype) == shapeOf(D.prototype) + + arr = [new D, new D, new D, D.prototype]; // [2] all the same shape + for (var i = 0; i < 4; i++) + assertEq(arr[i].x, 1); // same kshape [2], same vshape [1] +} +testBug501690(); diff --git a/js/src/jit-test/tests/basic/testBug502914.js b/js/src/jit-test/tests/basic/testBug502914.js new file mode 100644 index 0000000..d01ee97 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug502914.js @@ -0,0 +1,19 @@ +function testBug502914() { + // Assigning a non-function to a function-valued property on trace should + // bump the shape. + function f1() {} + function C() {} + var x = C.prototype = {m: f1}; + x.m(); // brand scope + var arr = [new C, new C, new C, x]; + try { + for (var i = 0; i < 4; i++) { + arr[i].m = 12; + x.m(); // should throw last time through + } + } catch (exc) { + return exc.constructor.name; + } + return "no exception"; +} +assertEq(testBug502914(), "TypeError"); diff --git a/js/src/jit-test/tests/basic/testBug504520.js b/js/src/jit-test/tests/basic/testBug504520.js new file mode 100644 index 0000000..73e2e30 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug504520.js @@ -0,0 +1,11 @@ +function testBug504520() { + // A bug involving comparisons. + var arr = [1/0, 1/0, 1/0, 1/0, 1/0, 1/0, 1/0, 1/0, 1/0, 0]; + assertEq(arr.length > RUNLOOP, true); + + var s = ''; + for (var i = 0; i < arr.length; i++) + arr[i] >= 1/0 ? null : (s += i); + assertEq(s, '9'); +} +testBug504520(); diff --git a/js/src/jit-test/tests/basic/testBug504520Harder.js b/js/src/jit-test/tests/basic/testBug504520Harder.js new file mode 100644 index 0000000..0a63ebf --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug504520Harder.js @@ -0,0 +1,33 @@ +function testBug504520Harder() { + // test 1024 similar cases + var vals = [1/0, -1/0, 0, 0/0]; + var ops = ["===", "!==", "==", "!=", "<", ">", "<=", ">="]; + for each (var x in vals) { + for each (var y in vals) { + for each (var op in ops) { + for each (var z in vals) { + // Assume eval is correct. This depends on the global + // Infinity property not having been reassigned. + var xz = eval(x + op + z); + var yz = eval(y + op + z); + + var arr = [x, x, x, x, x, x, x, x, x, y]; + assertEq(arr.length > RUNLOOP, true); + var expected = [xz, xz, xz, xz, xz, xz, xz, xz, xz, yz]; + + // ?: looks superfluous but that's what we're testing here + var fun = eval( + '(function (arr, results) {\n' + + ' for (let i = 0; i < arr.length; i++)\n' + + ' results.push(arr[i]' + op + z + ' ? "true" : "false");\n' + + '});\n'); + var actual = []; + fun(arr, actual); + print(x, y, op, z); + assertEq("" + actual, "" + expected); + } + } + } + } +} +testBug504520Harder(); diff --git a/js/src/jit-test/tests/basic/testBug507425.js b/js/src/jit-test/tests/basic/testBug507425.js new file mode 100644 index 0000000..616baba --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug507425.js @@ -0,0 +1,14 @@ +// |jit-test| allow-oom; +function testBug507425() { + var r = /x/; + for (var i = 0; i < 3; i++) + r.lastIndex = 0; // call a setter + var s = ';'; + try { + for (i = 0; i < 80; i++) + s += s; // call js_CanLeaveTrace + } catch (exc) { + return "ok"; + } +} +assertEq(testBug507425(), "ok"); diff --git a/js/src/jit-test/tests/basic/testBug520503-1.js b/js/src/jit-test/tests/basic/testBug520503-1.js new file mode 100644 index 0000000..a3730e5 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug520503-1.js @@ -0,0 +1,3 @@ +(new Function("for (var j=0; j<9; ++j) { (function sum_indexing(array,start){return array.length==start ? 0 : array[start]+ sum_indexing(array,start+1)})([true,true,undefined],0)}"))() + +/* Should not have crashed. */ diff --git a/js/src/jit-test/tests/basic/testBug520503-2.js b/js/src/jit-test/tests/basic/testBug520503-2.js new file mode 100644 index 0000000..2f6699d --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug520503-2.js @@ -0,0 +1,18 @@ +for each(let a in [new Boolean(false)]) {} +for (var b = 0; b < 13; ++b) { + if (b % 3 == 1) { + (function f(c) { + if (c <= 1) { + return 1; + } + return f(c - 1) + f(c - 2); + })(3) + } else { + (function g(d, e) {; + return d.length == e ? 0 : d[e] + g(d, e + 1); + })([false, new Boolean(true), false], 0) + } +} + +/* Should not have crashed. */ + diff --git a/js/src/jit-test/tests/basic/testBug520503-3.js b/js/src/jit-test/tests/basic/testBug520503-3.js new file mode 100644 index 0000000..1385af0 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug520503-3.js @@ -0,0 +1,6 @@ +(Function("for (var a = 0; a < 6; a++) {\ + (function sum_indexing(b, c) {\ + return b.length == c ? 0 : b[c] + sum_indexing(b, c + 1)\ + })([(void 0), Infinity, Infinity], 0)\ +}"))() + diff --git a/js/src/jit-test/tests/basic/testBug529147.js b/js/src/jit-test/tests/basic/testBug529147.js new file mode 100644 index 0000000..8b70087 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug529147.js @@ -0,0 +1,22 @@ +var magicNumbers = [1, -1, 0, 0]; +var magicIndex = 0; + +var sum = 0; + +function foo(n) { + for (var i = 0; i < n; ++i) { + sum += 10; + bar(); + } +} + +function bar() { + var q = magicNumbers[magicIndex++]; + if (q != -1) { + sum += 1; + foo(q); + } +} + +foo(3); +assertEq(sum, 43); diff --git a/js/src/jit-test/tests/basic/testBug547791.js b/js/src/jit-test/tests/basic/testBug547791.js new file mode 100644 index 0000000..2d4482e --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug547791.js @@ -0,0 +1,21 @@ + +function Bext(k) { + if (k > 0) { + let i = k + 1; + if (k == 10) { + function x () { i = 2; } + } + Bext(i - 2); + Bext(i - 2); + } + return 0; +} + +function f() { + Bext(12); +} + +f(); + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/basic/testBug550210.js b/js/src/jit-test/tests/basic/testBug550210.js new file mode 100644 index 0000000..d4fa9d1 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug550210.js @@ -0,0 +1,16 @@ +function g(e) { + return ("" + e); +} + +function blah() { + do { + yield; + } while ({}(p = arguments)); +} +rv = blah(); +try { + for (a in rv) ; +} catch (e) { + print("" + g(e)); +} +gc(); diff --git a/js/src/jit-test/tests/basic/testBug552248.js b/js/src/jit-test/tests/basic/testBug552248.js new file mode 100644 index 0000000..94aef6a --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug552248.js @@ -0,0 +1,37 @@ +// |jit-test| debug +setDebug(true); +var a = new Array(); + +function i(save) { + var x = 9; + evalInFrame(0, "a.push(x)", save); + evalInFrame(1, "a.push(z)", save); + evalInFrame(2, "a.push(z)", save); + evalInFrame(3, "a.push(y)", save); + evalInFrame(4, "a.push(x)", save); +} + +function h() { + var z = 5; + evalInFrame(0, "a.push(z)"); + evalInFrame(1, "a.push(y)"); + evalInFrame(2, "a.push(x)"); + evalInFrame(0, "i(false)"); + evalInFrame(0, "a.push(z)", true); + evalInFrame(1, "a.push(y)", true); + evalInFrame(2, "a.push(x)", true); + evalInFrame(0, "i(true)", true); +} + +function g() { + var y = 4; + h(); +} + +function f() { + var x = 3; + g(); +} + +f(); +assertEq(a+'', [5, 4, 3, 9, 5, 5, 4, 3, 5, 4, 3, 9, 5, 5, 4, 3]+''); diff --git a/js/src/jit-test/tests/basic/testBug554043.js b/js/src/jit-test/tests/basic/testBug554043.js new file mode 100644 index 0000000..a0071ae --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug554043.js @@ -0,0 +1,6 @@ +(function () { + for (var a = 0; a < 5; a++) { + print(-false) + assertEq(-false, -0.0); + } +})() diff --git a/js/src/jit-test/tests/basic/testBug555484.js b/js/src/jit-test/tests/basic/testBug555484.js new file mode 100644 index 0000000..f15f2b2 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug555484.js @@ -0,0 +1,8 @@ +var result = ""; +o = { valueOf:function(){ throw "cow" } }; +try { + String.fromCharCode(o); +} catch (e) { + result = e.toString(); +} +assertEq(result, "cow"); diff --git a/js/src/jit-test/tests/basic/testBug558446.js b/js/src/jit-test/tests/basic/testBug558446.js new file mode 100644 index 0000000..91c0187 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug558446.js @@ -0,0 +1,11 @@ +function f(a, b) { return a + " " + b; } + +for (var i = 0; i < 10; ++i) { + var s = ''; + var a = {toString: function () { s += 'a'; return 'a'; }}; + var b = {toString: function () { s += 'b'; return 'b'; }}; + f(a, b); + assertEq(s, 'ab'); +} + +checkStats({ traceTriggered:1 }); diff --git a/js/src/jit-test/tests/basic/testBug560098.js b/js/src/jit-test/tests/basic/testBug560098.js new file mode 100644 index 0000000..18b5e76 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug560098.js @@ -0,0 +1,16 @@ +Function("\ + for each(let w in [(5), false, Number, false]) {\ + (function f(zzzzzz) {\ + return zzzzzz.length == 0 ? 0 : zzzzzz[0] + f(zzzzzz.slice(1))\ + })([, [], [], w, , ])\ + }\ +")() + +Function("\ + for each(let w in [(void 0), (void 0), false, false, false, false, false, \ + undefined, undefined, false, (void 0), undefined]) {\ + (function f(zzzzzz) {\ + return zzzzzz.length == 0 ? 0 : zzzzzz[0] + f(zzzzzz.slice(1))\ + })([w, , w, w, [], []])\ + }\ +")() diff --git a/js/src/jit-test/tests/basic/testBug566556.js b/js/src/jit-test/tests/basic/testBug566556.js new file mode 100644 index 0000000..71f0ba6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug566556.js @@ -0,0 +1,9 @@ +var msg = ""; +try { + this.__defineSetter__('x', Object.create); + this.watch('x', function() {}); + x = 3; +} catch (e) { + msg = e.toString(); +} +assertEq(msg, "TypeError: (void 0) is not an object or null"); diff --git a/js/src/jit-test/tests/basic/testBug578044.js b/js/src/jit-test/tests/basic/testBug578044.js new file mode 100644 index 0000000..c5b811d --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug578044.js @@ -0,0 +1,13 @@ +this.watch("x", Object.create) +try { + (function() { + this.__defineGetter__("x", + function() { + return this + }) + })() +} catch(e) {} +Object.defineProperty(x, "x", ({ + set: Uint16Array +})) + diff --git a/js/src/jit-test/tests/basic/testBug579602.js b/js/src/jit-test/tests/basic/testBug579602.js new file mode 100644 index 0000000..5871c24 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug579602.js @@ -0,0 +1,21 @@ +// don't panic + +f = function() { + x = yield +} +rv = f() +for (a in rv) (function() {}) +x = Proxy.create((function() { + return { + defineProperty: gc + } +})(), x) +with({ + d: (({ + x: Object.defineProperty(x, "", ({ + set: Array.e + })) + })) +}) {} + +// don't crash diff --git a/js/src/jit-test/tests/basic/testBug579646.js b/js/src/jit-test/tests/basic/testBug579646.js new file mode 100644 index 0000000..d034410 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug579646.js @@ -0,0 +1,22 @@ +if (typeof gczeal != "function") + gczeal = function() {} + +for (a = 0; a < 9; a++) + for (b = 0; b < 1; b++) + for (c = 0; c < 2; c++) + gczeal(); + +for each(e in [NaN]) + for (d = 0; d < 1; d++) + z = 0; + +for (w in [0, 0]) + {} + +x = 0; + +for (e = 0; e < 3; e++) + for (f = 0; f < 4; f++) + x = -x + +// don't crash diff --git a/js/src/jit-test/tests/basic/testBug579647.js b/js/src/jit-test/tests/basic/testBug579647.js new file mode 100644 index 0000000..92f76c6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug579647.js @@ -0,0 +1,13 @@ +expected = "TypeError: NaN is not a function"; +actual = ""; + +try { + a = "" + for each(x in [0, 0, 0, 0]) { + a %= x + } ( - a)() +} catch (e) { + actual = '' + e; +} + +assertEq(expected, actual); diff --git a/js/src/jit-test/tests/basic/testBug582766.js b/js/src/jit-test/tests/basic/testBug582766.js new file mode 100644 index 0000000..cfcafbe --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug582766.js @@ -0,0 +1,18 @@ +expected = 4; + +var fourth = { nextSibling: null }; +var third = { nextSibling: fourth }; +var second = { nextSibling: third }; +var first = { nextSibling: second }; + +function f() { + let loopcount = 0; + for (let node = first; node; node = node.nextSibling) { + loopcount++; + } + return loopcount; +} + +actual = f(); + +assertEq(actual, expected); diff --git a/js/src/jit-test/tests/basic/testBug584650.js b/js/src/jit-test/tests/basic/testBug584650.js new file mode 100644 index 0000000..b6c9d8a --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug584650.js @@ -0,0 +1,9 @@ +if (typeof gczeal != "function") + gczeal = function() {} + +// don't crash +x = (evalcx('lazy')) +x.watch("", function () {}) +gczeal(1) +for (w in x) {} + diff --git a/js/src/jit-test/tests/basic/testBug586866.js b/js/src/jit-test/tests/basic/testBug586866.js new file mode 100644 index 0000000..c9ccd45 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug586866.js @@ -0,0 +1,16 @@ +var magic = HOTLOOP; + +var obj = {}; +for (var i = 1; i <= magic; ++i) + obj[i] = "a"; + +function func() { + var i = 1; + while (i in obj) { + ++i; + } + return i - 1; +} +assertEq(func(), magic); +assertEq(func(), magic); +assertEq(func(), magic); diff --git a/js/src/jit-test/tests/basic/testBug593559.js b/js/src/jit-test/tests/basic/testBug593559.js new file mode 100644 index 0000000..c49e536 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug593559.js @@ -0,0 +1,10 @@ +var gen = (function () {yield})(); +var t = gen.throw; + +try { + new t; +} catch (e) { + actual = "" + e; +} +assertEq(actual, "TypeError: Generator.prototype.throw called on incompatible Object"); + diff --git a/js/src/jit-test/tests/basic/testBug595916.js b/js/src/jit-test/tests/basic/testBug595916.js new file mode 100644 index 0000000..eada406 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug595916.js @@ -0,0 +1,10 @@ +(function () { + try { + eval("\ + for each(let d in[0,0,0,0,0,0,0,0]) {\ + for(let b in[0,0]) {}\ + }\ + ") + } catch (e) {} +})() + diff --git a/js/src/jit-test/tests/basic/testBug597736.js b/js/src/jit-test/tests/basic/testBug597736.js new file mode 100644 index 0000000..ded3384 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug597736.js @@ -0,0 +1,32 @@ +function leak_test() { + // Create a reference loop function->script->traceFragment->object->function + // that GC must be able to break. To embedd object into the fragment the + // code use prototype chain of depth 2 which caches obj.__proto__.__proto__ + // into the fragment. + + // To make sure that we have no references to the function f after this + // function returns due via the conservative scan of the native stack we + // loop here multiple times overwriting the stack and registers with new garabge. + for (var j = 0; j != 8; ++j) { + var f = Function("a", "var s = 0; for (var i = 0; i != 100; ++i) s += a.b; return s;"); + var c = {b: 1, f: f, leakDetection: makeFinalizeObserver()}; + f({ __proto__: { __proto__: c}}); + f = c = a = null; + gc(); + } +} + +function test() +{ + if (typeof finalizeCount != "function") + return; + + var base = finalizeCount(); + leak_test(); + gc(); + gc(); + var n = finalizeCount(); + assertEq(base + 4 < finalizeCount(), true, "Some finalizations must happen"); +} + +test(); diff --git a/js/src/jit-test/tests/basic/testBug602413.js b/js/src/jit-test/tests/basic/testBug602413.js new file mode 100644 index 0000000..eeef15c --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug602413.js @@ -0,0 +1,45 @@ +var so = []; + +function U(unusedV) +{ + for (var i = 0; i < so.length; ++i) + return false; + so.push(0); +} + +function C(v) +{ + if (typeof v == "object" || typeof v == "function") { + for (var i = 0; i < 10; ++i) {} + U(v); + } +} + +function exploreProperties(obj) +{ + var props = []; + for (var o = obj; o; o = Object.getPrototypeOf(o)) { + props = props.concat(Object.getOwnPropertyNames(o)); + } + for (var i = 0; i < props.length; ++i) { + var p = props[i]; + try { + var v = obj[p]; + C(v); + } catch(e) { } + } +} + +function boom() +{ + var a = []; + var b = function(){}; + var c = [{}]; + exploreProperties(a); + exploreProperties(b); + exploreProperties(c); + exploreProperties(c); +} + +boom(); + diff --git a/js/src/jit-test/tests/basic/testBug603193.js b/js/src/jit-test/tests/basic/testBug603193.js new file mode 100644 index 0000000..8bebb5f --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug603193.js @@ -0,0 +1,12 @@ +function g(code) { + f = Function(code); + for (a in f()) {} +} + +/* Get call ic in a state to call CompileFunction for new functions. */ +g() +g("(function(){})") +g() + +/* Call generator with frame created by call ic + CompileFunction. */ +g("yield") diff --git a/js/src/jit-test/tests/basic/testBug604210.js b/js/src/jit-test/tests/basic/testBug604210.js new file mode 100644 index 0000000..3f333ec --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug604210.js @@ -0,0 +1,11 @@ +function f() { + var msg = ''; + try { + var x = undefined; + print(x.foo); + } catch (e) { + msg = '' + e; + } + assertEq(msg, "TypeError: x is undefined"); +} +f(); diff --git a/js/src/jit-test/tests/basic/testBug606138.js b/js/src/jit-test/tests/basic/testBug606138.js new file mode 100644 index 0000000..155a19f --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug606138.js @@ -0,0 +1,3 @@ +// The proxy is going to mutate thisv in place. InvokeSessionGuard should be +// cool with that +with(evalcx(''))[7, 8].map(Int16Array, []) diff --git a/js/src/jit-test/tests/basic/testBug607659.js b/js/src/jit-test/tests/basic/testBug607659.js new file mode 100644 index 0000000..edfda93 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug607659.js @@ -0,0 +1,8 @@ +var g = 0; +Object.defineProperty(RegExp.prototype, 'test', { get:function() { ++g } }); +function f() { + for (var i = 0; i < 100; ++i) + /a/.exec('a'); +} +f(); +assertEq(g, 0); diff --git a/js/src/jit-test/tests/basic/testBug614653.js b/js/src/jit-test/tests/basic/testBug614653.js new file mode 100644 index 0000000..2b86e97 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug614653.js @@ -0,0 +1,10 @@ +/* Bug 614653 - This test .2 seconds with the fix, 20 minutes without. */ +for (var i = 0; i < 100; ++i) { + var arr = []; + var s = "abcdefghijklmnop"; + for (var i = 0; i < 50000; ++i) { + s = "<" + s + ">"; + arr.push(s); + } + gc(); +} diff --git a/js/src/jit-test/tests/basic/testBug614752.js b/js/src/jit-test/tests/basic/testBug614752.js new file mode 100644 index 0000000..d34392d --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug614752.js @@ -0,0 +1,3 @@ +// |jit-test| error: TypeError +Object.prototype.apply = Function.prototype.apply; +({}).apply(null, null); // don't assert diff --git a/js/src/jit-test/tests/basic/testBug616119.js b/js/src/jit-test/tests/basic/testBug616119.js new file mode 100644 index 0000000..c41ab54 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug616119.js @@ -0,0 +1,6 @@ +// don't assert +for (a = 0; a < 9; ++a) { + M: for (let c in >) { + break M + } +} diff --git a/js/src/jit-test/tests/basic/testBug616454.js b/js/src/jit-test/tests/basic/testBug616454.js new file mode 100644 index 0000000..34ca440 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug616454.js @@ -0,0 +1,2 @@ +function isnan(x) { return x !== x } +assertEq(isnan(deserialize(serialize(-'test'))), true); diff --git a/js/src/jit-test/tests/basic/testBug621202.js b/js/src/jit-test/tests/basic/testBug621202.js new file mode 100644 index 0000000..5bf8269 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug621202.js @@ -0,0 +1,16 @@ +const MAX = 10000; + +var arr = []; +var str = ""; +for (var i = 0; i < MAX; ++i) { + /x/.test(str); + str = str + 'xxxxxxxxxxxxxx'; + arr.push(str); +} + +arr.length = Math.floor(MAX/3); +gc(); + +for (var i = 0; i < MAX; ++i) { + /x/.test(arr[i]); +} diff --git a/js/src/jit-test/tests/basic/testBug628564.js b/js/src/jit-test/tests/basic/testBug628564.js new file mode 100644 index 0000000..2c217d0 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug628564.js @@ -0,0 +1,8 @@ +x = 0 +for (a = 0; a < HOTLOOP+5; ++a) { + if (a == HOTLOOP-1) { + if (!x) { + __defineSetter__("x", Object.defineProperties) + } + } +} diff --git a/js/src/jit-test/tests/basic/testBug629974.js b/js/src/jit-test/tests/basic/testBug629974.js new file mode 100644 index 0000000..50e7247 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug629974.js @@ -0,0 +1,7 @@ +foo = {} +foo.y = 3; +foo.y = function () {} +Object.defineProperty(foo, "y", { set:function(){} }) +gc() +delete foo.y +gc(); diff --git a/js/src/jit-test/tests/basic/testBug630064.js b/js/src/jit-test/tests/basic/testBug630064.js new file mode 100644 index 0000000..aab4885 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug630064.js @@ -0,0 +1,48 @@ +var BUGNUMBER = ''; +function printBugNumber (num) +{ + return "foo"; +} +function optionsClear() { + var x = printBugNumber().split(','); +} +function optionsReset() { + optionsClear(); +} +var code = new Array(); +code.push("evaluate"); +var x0 = "\ + printBugNumber(BUGNUMBER);\n\ + function gen()\n\ + {\n\ + try {\n\ + yield 0;\n\ + } finally {\n\ + }\n\ + }\n\ + var iter1 = gen( iter1=\"NaN\", new gen(gen)) ;\n\ + gc();\n\ +"; +code.push(x0); +code.push("evaluate"); +var files = new Array(); +while (true) { + var file = code.shift(); + if (file == "evaluate") { + loadFiles(files); + } else if (file == undefined) { + break; + } else { + files.push(file); + } +} +function loadFiles(x) { + for (i in x) { + try { + eval(x[i]); + } catch (e) { + } + } + optionsReset(); +} + diff --git a/js/src/jit-test/tests/basic/testBug634590.js b/js/src/jit-test/tests/basic/testBug634590.js new file mode 100644 index 0000000..5787c61 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug634590.js @@ -0,0 +1,12 @@ +this.name = "outer"; +var sb = evalcx(''); +sb.name = "inner"; +sb.parent = this; +function f() { return this.name; } +assertEq(evalcx('this.f = parent.f;\n' + + 'var s = "";\n' + + 'for (i = 0; i < 10; ++i)\n' + + ' s += f();\n' + + 's', + sb), + "innerinnerinnerinnerinnerinnerinnerinnerinnerinner"); diff --git a/js/src/jit-test/tests/basic/testBug634590b.js b/js/src/jit-test/tests/basic/testBug634590b.js new file mode 100644 index 0000000..42531a8 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug634590b.js @@ -0,0 +1,19 @@ +this.name = "outer"; +var sb = evalcx(''); +sb.name = "inner"; +sb.parent = this; +function f() { return this.name; } +f.notMuchTodo = '42'; +assertEq(evalcx('{\n' + + ' let f = parent.f;\n' + + ' let name = "block";\n' + + ' (function () {\n' + + ' eval(f.notMuchTodo);\n' + // reify Block + ' var s = "";\n' + + ' for (i = 0; i < 10; ++i)\n' + + ' s += f();\n' + + ' return s;\n' + + ' })();\n' + + '}', + sb), + "outerouterouterouterouterouterouterouterouterouter"); diff --git a/js/src/jit-test/tests/basic/testBug634590c.js b/js/src/jit-test/tests/basic/testBug634590c.js new file mode 100644 index 0000000..1ae2542 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug634590c.js @@ -0,0 +1,20 @@ +this.name = "outer"; +var sb = evalcx(''); +sb.name = "inner"; +sb.parent = this; +function f() { return this.name; } +f.notMuchTodo = '42'; +assertEq(evalcx('(function () {\n' + + ' arguments = null;\n' + // force heavyweight + ' var f = parent.f;\n' + + ' var name = "call";\n' + + ' return (function () {\n' + + ' eval(f.notMuchTodo);\n' + // reify Call, make f() compile to JSOP_CALLNAME + ' var s = "";\n' + + ' for (i = 0; i < 10; ++i)\n' + + ' s += f();\n' + + ' return s;\n' + + ' })();\n' + + '})()', + sb), + "outerouterouterouterouterouterouterouterouterouter"); diff --git a/js/src/jit-test/tests/basic/testBug634590d.js b/js/src/jit-test/tests/basic/testBug634590d.js new file mode 100644 index 0000000..d2e47b5 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug634590d.js @@ -0,0 +1,19 @@ +this.name = "outer"; +var sb = evalcx(''); +sb.name = "inner"; +sb.parent = this; +this.f = function name(outer) { + if (outer) { + return function () { + return name(false); + }(); + } + return this.name; +} +assertEq(evalcx('this.f = parent.f;\n' + + 'var s = "";\n' + + 'for (i = 0; i < 10; ++i)\n' + + ' s += f(true);\n' + + 's', + sb), + "outerouterouterouterouterouterouterouterouterouter"); diff --git a/js/src/jit-test/tests/basic/testBug634590ma.js b/js/src/jit-test/tests/basic/testBug634590ma.js new file mode 100644 index 0000000..413f3a2 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug634590ma.js @@ -0,0 +1,14 @@ +// |jit-test| mjitalways; + +this.name = "outer"; +var sb = evalcx(''); +sb.name = "inner"; +sb.parent = this; +function f() { return this.name; } +assertEq(evalcx('this.f = parent.f;\n' + + 'var s = "";\n' + + 'for (i = 0; i < 10; ++i)\n' + + ' s += f();\n' + + 's', + sb), + "innerinnerinnerinnerinnerinnerinnerinnerinnerinner"); diff --git a/js/src/jit-test/tests/basic/testCallApply.js b/js/src/jit-test/tests/basic/testCallApply.js new file mode 100644 index 0000000..46eee91 --- /dev/null +++ b/js/src/jit-test/tests/basic/testCallApply.js @@ -0,0 +1,168 @@ +function script1() { return arguments.length; } +function script2(x) { return x; } +function script3(x) { var o = arguments; return o[0]; } +function genClosure() { var x = 3; eval("x = 4"); return function(y) { return x + y } }; +var closed1 = genClosure(); +var closed2 = genClosure(); +var closed3 = genClosure(); +var native1 = String.prototype.search; +var native2 = String.prototype.match; +var tricky1 = { call:function(x,y) { return y }, apply:function(x,y) { return y } }; + +test0(); +test1(); +test2(); +test3(); + +function test0() { + assertEq(script1.call(null), 0); + assertEq(script1.call(null, 1), 1); + assertEq(script1.call(null, 1,2), 2); + assertEq(native1.call("aabc", /b/), 2); + assertEq(native1.call("abc"), -1); + assertEq(tricky1.call(null, 9), 9); + assertEq(script1.apply(null), 0); + assertEq(script1.apply(null, [1]), 1); + assertEq(script1.apply(null, [1,2]), 2); + assertEq(native1.apply("aabc", [/b/]), 2); + assertEq(native1.apply("abc"), -1); + assertEq(tricky1.apply(null, 1), 1); +} +test0(); + +function test1() { + function f(arr) { + for (var i = 0; i < 10; ++i) { + for (var j = 0; j < arr.length; ++j) { + arr[j].call('a'); + arr[j].apply('a', []); + var arg0 = []; + arr[j].apply('a', arg0); + (function() { arr[j].apply('a', arguments); })(); + + arr[j].call('a', 1); + arr[j].apply('a', [1]); + var arg0 = [1]; + arr[j].apply('a', arg0); + (function() { arr[j].apply('a', arguments); })(1); + + arr[j].call('a', 1,'g'); + arr[j].apply('a', [1,'g']); + var arg0 = [1,'g']; + arr[j].apply('a', arg0); + (function() { arr[j].apply('a', arguments); })(1,'g'); + + arr[j].call('a', 1,'g',3,4,5,6,7,8,9); + arr[j].apply('a', [1,'g',3,4,5,6,7,8,9]); + var arg0 = [1,'g',3,4,5,6,7,8,9]; + arr[j].apply('a', arg0); + (function() { arr[j].apply('a', arguments); })(1,'g',3,4,5,6,7,8,9); + } + } + } + + f([script1, script1, script1, script1, script2, script2, script1, script2]); + f([script1, script2, script3, script1, script2, script3, script3, script3]); + f([script1, script2, script2, script2, script2, script3, script1, script2]); + f([script1, script1, script1, native1, native1, native1, native1, script1]); + f([native1, native1, native1, native2, native2, native2, native2, native1]); + f([native1, native2, native1, native2, native1, native2, native1, native2]); + f([native1, native1, native1, script1, script2, script2, native1, script3]); + f([closed1, closed1, closed1, closed2, closed2, closed2, script3, script3]); + f([closed1, closed2, closed1, closed2, closed1, closed2, closed1, closed2]); + f([closed1, closed2, closed3, closed1, closed2, closed3, script1, script2]); + f([closed1, closed1, closed1, closed2, closed2, closed2, native1, native2]); + f([closed1, closed1, closed1, closed2, closed2, closed2, native1, native2]); + f([native1, native1, native1, closed1, closed2, script1, script2, native2]); +} + +// test things that break our speculation +function test2() { + var threw = false; + try { + (3).call(null, 1,2); + } catch (e) { + threw = true; + } + assertEq(threw, true); + + var threw = false; + try { + (3).apply(null, [1,2]); + } catch (e) { + threw = true; + } + assertEq(threw, true); + + var threw = false; + try { + var arr = [1,2]; + (3).apply(null, arr); + } catch (e) { + threw = true; + } + assertEq(threw, true); + + function tryAndFail(o) { + var threw = false; + try { + o.call(null, 1,2); + } catch(e) { + threw = true; + } + assertEq(threw, true); + threw = false; + try { + o.apply(null, [1,2]); + } catch(e) { + threw = true; + } + assertEq(threw, true); + } + + tryAndFail(1); + tryAndFail({}); + tryAndFail({call:{}, apply:{}}); + tryAndFail({call:function() { throw "not js_fun_call"}, apply:function(){ throw "not js_fun_apply" }}); +} + +// hit the stubs::CompileFunction path +function test3() { + function genFreshFunction(s) { return new Function(s, "return " + s); } + + function callIt(f) { + assertEq(f.call(null, 1,2), 1); + } + callIt(script2); callIt(script2); callIt(script2); callIt(script2); + callIt(genFreshFunction("x")); + callIt(genFreshFunction("y")); + callIt(genFreshFunction("z")); + + function applyIt(f) { + var arr = [1,2]; + assertEq(f.apply(null, arr), 1); + } + applyIt(script2); applyIt(script2); applyIt(script2); applyIt(script2); + applyIt(genFreshFunction("x")); + applyIt(genFreshFunction("y")); + applyIt(genFreshFunction("z")); + + function applyIt1(f) { + function g() { + assertEq(f.apply(null, arguments), 1); + } + g(1,2); + } + applyIt1(script2); applyIt1(script2); applyIt1(script2); applyIt1(script2); + applyIt1(genFreshFunction("x")); + applyIt1(genFreshFunction("y")); + applyIt1(genFreshFunction("z")); + + function applyIt2(f) { + assertEq(f.apply(null, [1,2]), 1); + } + applyIt2(script2); applyIt2(script2); applyIt2(script2); applyIt2(script2); + applyIt2(genFreshFunction("x")); + applyIt2(genFreshFunction("y")); + applyIt2(genFreshFunction("z")); +} diff --git a/js/src/jit-test/tests/basic/testCallElem.js b/js/src/jit-test/tests/basic/testCallElem.js new file mode 100644 index 0000000..b40553e --- /dev/null +++ b/js/src/jit-test/tests/basic/testCallElem.js @@ -0,0 +1,17 @@ +function testCALLELEM() +{ + function f() { + return 5; + } + + function g() { + return 7; + } + + var x = [f,f,f,f,g]; + var y = 0; + for (var i = 0; i < 5; ++i) + y = x[i](); + return y; +} +assertEq(testCALLELEM(), 7); diff --git a/js/src/jit-test/tests/basic/testCallNull.js b/js/src/jit-test/tests/basic/testCallNull.js new file mode 100644 index 0000000..53f11cd --- /dev/null +++ b/js/src/jit-test/tests/basic/testCallNull.js @@ -0,0 +1,9 @@ +function f() {} +for (var i = 0; i < HOTLOOP; ++i) { + f.call(null); +} + +checkStats({ + recorderStarted: 1, + recorderAborted: 0 +}); diff --git a/js/src/jit-test/tests/basic/testCallPick.js b/js/src/jit-test/tests/basic/testCallPick.js new file mode 100644 index 0000000..7f1d9ad --- /dev/null +++ b/js/src/jit-test/tests/basic/testCallPick.js @@ -0,0 +1,18 @@ +function testCallPick() { + function g(x,a) { + x.f(); + } + + var x = []; + x.f = function() { } + + var y = []; + y.f = function() { } + + var z = [x,x,x,x,x,y,y,y,y,y]; + + for (var i = 0; i < 10; ++i) + g.call(this, z[i], ""); + return true; +} +assertEq(testCallPick(), true); diff --git a/js/src/jit-test/tests/basic/testCallProtoMethod.js b/js/src/jit-test/tests/basic/testCallProtoMethod.js new file mode 100644 index 0000000..cd0be83 --- /dev/null +++ b/js/src/jit-test/tests/basic/testCallProtoMethod.js @@ -0,0 +1,14 @@ +function testCallProtoMethod() { + function X() { this.x = 1; } + X.prototype.getName = function () { return "X"; } + + function Y() { this.x = 2; } + Y.prototype.getName = function() "Y"; + + var a = [new X, new X, new X, new X, new Y]; + var s = ''; + for (var i = 0; i < a.length; i++) + s += a[i].getName(); + return s; +} +assertEq(testCallProtoMethod(), 'XXXXY'); diff --git a/js/src/jit-test/tests/basic/testCaseAbort.js b/js/src/jit-test/tests/basic/testCaseAbort.js new file mode 100644 index 0000000..e4b8049 --- /dev/null +++ b/js/src/jit-test/tests/basic/testCaseAbort.js @@ -0,0 +1,19 @@ +function testCaseAbort() +{ + var four = "4"; + var r = 0; + for (var i = 0; i < 5; i++) + { + switch (i) + { + case four: r += 1; break; + default: r += 2; break; + } + } + + return "" + r; +} +assertEq(testCaseAbort(), "10"); +checkStats({ + recorderAborted: 0 +}); diff --git a/js/src/jit-test/tests/basic/testCaseTypeMismatchBadness.js b/js/src/jit-test/tests/basic/testCaseTypeMismatchBadness.js new file mode 100644 index 0000000..3512255 --- /dev/null +++ b/js/src/jit-test/tests/basic/testCaseTypeMismatchBadness.js @@ -0,0 +1,22 @@ +function testCaseTypeMismatchBadness() +{ + for (var z = 0; z < 3; ++z) + { + switch ("") + { + default: + case 9: + break; + + case "": + case : + break; + } + } + + return "no crash"; +} +assertEq(testCaseTypeMismatchBadness(), "no crash"); +checkStats({ + recorderAborted: 0 +}); diff --git a/js/src/jit-test/tests/basic/testChangingObjectWithLength.js b/js/src/jit-test/tests/basic/testChangingObjectWithLength.js new file mode 100644 index 0000000..5521ce6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testChangingObjectWithLength.js @@ -0,0 +1,37 @@ +function testChangingObjectWithLength() +{ + var obj = { length: 10 }; + var dense = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + var slow = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; slow.slow = 5; + + /* + * The elements of objs constitute a De Bruijn sequence repeated 4x to trace + * and run native code for every object and transition. + */ + var objs = [obj, obj, obj, obj, + obj, obj, obj, obj, + dense, dense, dense, dense, + obj, obj, obj, obj, + slow, slow, slow, slow, + dense, dense, dense, dense, + dense, dense, dense, dense, + slow, slow, slow, slow, + slow, slow, slow, slow, + obj, obj, obj, obj]; + + var counter = 0; + + for (var i = 0, sz = objs.length; i < sz; i++) + { + var o = objs[i]; + for (var j = 0; j < o.length; j++) + counter++; + } + + return counter; +} +assertEq(testChangingObjectWithLength(), 400); +checkStats({ + recorderAborted: 0, + sideExitIntoInterpreter: 15 // empirically determined +}); diff --git a/js/src/jit-test/tests/basic/testChangingTypeDuringRecording.js b/js/src/jit-test/tests/basic/testChangingTypeDuringRecording.js new file mode 100644 index 0000000..5c6a576 --- /dev/null +++ b/js/src/jit-test/tests/basic/testChangingTypeDuringRecording.js @@ -0,0 +1,6 @@ +X = { value: "" } +z = 0; +for (var i = 0; i < 20; i++) { + Object.defineProperty(this, "z", X); + z = 1; +} diff --git a/js/src/jit-test/tests/basic/testClosingRecursion.js b/js/src/jit-test/tests/basic/testClosingRecursion.js new file mode 100644 index 0000000..5b76d2a --- /dev/null +++ b/js/src/jit-test/tests/basic/testClosingRecursion.js @@ -0,0 +1,13 @@ +// Test no assert (bug 464089) +function shortRecursiveLoop(b, c) { + for (var i = 0; i < c; i++) { + if (b) + shortRecursiveLoop(c - 1); + } +} +function testClosingRecursion() { + shortRecursiveLoop(false, 1); + shortRecursiveLoop(true, 3); + return true; +} +assertEq(testClosingRecursion(), true); diff --git a/js/src/jit-test/tests/basic/testClosureIncrSideExit.js b/js/src/jit-test/tests/basic/testClosureIncrSideExit.js new file mode 100644 index 0000000..14e8527 --- /dev/null +++ b/js/src/jit-test/tests/basic/testClosureIncrSideExit.js @@ -0,0 +1,17 @@ +function testClosureIncrSideExit() { + let(f = function (y) { + let(ff = function (g) { + for each(let h in g) { + if (++y > 5) { + return 'ddd'; + } + } + return 'qqq'; + }) { + return ff(['', null, '', false, '', '', null]); + } + }) { + return f(-1); + } +} +assertEq(testClosureIncrSideExit(), "ddd"); diff --git a/js/src/jit-test/tests/basic/testClosures.js b/js/src/jit-test/tests/basic/testClosures.js new file mode 100644 index 0000000..a8152c2 --- /dev/null +++ b/js/src/jit-test/tests/basic/testClosures.js @@ -0,0 +1,18 @@ +function testClosures() +{ + function MyObject(id) { + var thisObject = this; + this.id = id; + this.toString = str; + + function str() { + return "" + this.id + thisObject.id; + } + } + + var a = []; + for (var i = 0; i < 5; i++) + a.push(new MyObject(i)); + return a.toString(); +} +assertEq(testClosures(), "00,11,22,33,44"); diff --git a/js/src/jit-test/tests/basic/testComparisons.js b/js/src/jit-test/tests/basic/testComparisons.js new file mode 100644 index 0000000..b4ae997 --- /dev/null +++ b/js/src/jit-test/tests/basic/testComparisons.js @@ -0,0 +1,988 @@ +function testComparisons() +{ + // All the special values from each of the types in + // ECMA-262, 3rd ed. section 8 + var undefinedType, nullType, booleanType, stringType, numberType, objectType; + + var types = []; + types[undefinedType = 0] = "Undefined"; + types[nullType = 1] = "Null"; + types[booleanType = 2] = "Boolean"; + types[stringType = 3] = "String"; + types[numberType = 4] = "Number"; + types[objectType = 5] = "Object"; + + var JSVAL_INT_MIN = -Math.pow(2, 30); + var JSVAL_INT_MAX = Math.pow(2, 30) - 1; + + // Values from every ES3 type, hitting all the edge-case and special values + // that can be dreamed up + var values = + { + "undefined": + { + value: function() { return undefined; }, + type: undefinedType + }, + "null": + { + value: function() { return null; }, + type: nullType + }, + "true": + { + value: function() { return true; }, + type: booleanType + }, + "false": + { + value: function() { return false; }, + type: booleanType + }, + '""': + { + value: function() { return ""; }, + type: stringType + }, + '"a"': + { + // a > [, for string-object comparisons + value: function() { return "a"; }, + type: stringType + }, + '"Z"': + { + // Z < [, for string-object comparisons + value: function() { return "Z"; }, + type: stringType + }, + "0": + { + value: function() { return 0; }, + type: numberType + }, + "-0": + { + value: function() { return -0; }, + type: numberType + }, + "1": + { + value: function() { return 1; }, + type: numberType + }, + "Math.E": + { + value: function() { return Math.E; }, + type: numberType + }, + "JSVAL_INT_MIN - 1": + { + value: function() { return JSVAL_INT_MIN - 1; }, + type: numberType + }, + "JSVAL_INT_MIN": + { + value: function() { return JSVAL_INT_MIN; }, + type: numberType + }, + "JSVAL_INT_MIN + 1": + { + value: function() { return JSVAL_INT_MIN + 1; }, + type: numberType + }, + "JSVAL_INT_MAX - 1": + { + value: function() { return JSVAL_INT_MAX - 1; }, + type: numberType + }, + "JSVAL_INT_MAX": + { + value: function() { return JSVAL_INT_MAX; }, + type: numberType + }, + "JSVAL_INT_MAX + 1": + { + value: function() { return JSVAL_INT_MAX + 1; }, + type: numberType + }, + "Infinity": + { + value: function() { return Infinity; }, + type: numberType + }, + "-Infinity": + { + value: function() { return -Infinity; }, + type: numberType + }, + "NaN": + { + value: function() { return NaN; }, + type: numberType + }, + "{}": + { + value: function() { return {}; }, + type: objectType + }, + "{ valueOf: undefined }": + { + value: function() { return { valueOf: undefined }; }, + type: objectType + }, + "[]": + { + value: function() { return []; }, + type: objectType + }, + '[""]': + { + value: function() { return [""]; }, + type: objectType + }, + '["a"]': + { + value: function() { return ["a"]; }, + type: objectType + }, + "[0]": + { + value: function() { return [0]; }, + type: objectType + } + }; + + var orderOps = + { + "<": function(a, b) { return a < b; }, + ">": function(a, b) { return a > b; }, + "<=": function(a, b) { return a <= b; }, + ">=": function(a, b) { return a >= b; } + }; + var eqOps = + { + "==": function(a, b) { return a == b; }, + "!=": function(a, b) { return a != b; }, + "===": function(a, b) { return a === b; }, + "!==": function(a, b) { return a !== b; } + }; + + + var notEqualIncomparable = + { + eq: { "==": false, "!=": true, "===": false, "!==": true }, + order: { "<": false, ">": false, "<=": false, ">=": false } + }; + var notEqualLessThan = + { + eq: { "==": false, "!=": true, "===": false, "!==": true }, + order: { "<": true, ">": false, "<=": true, ">=": false } + }; + var notEqualGreaterThan = + { + eq: { "==": false, "!=": true, "===": false, "!==": true }, + order: { "<": false, ">": true, "<=": false, ">=": true } + }; + var notEqualNorDifferent = + { + eq: { "==": false, "!=": true, "===": false, "!==": true }, + order: { "<": false, ">": false, "<=": true, ">=": true } + }; + var strictlyEqual = + { + eq: { "==": true, "!=": false, "===": true, "!==": false }, + order: { "<": false, ">": false, "<=": true, ">=": true } + }; + var looselyEqual = + { + eq: { "==": true, "!=": false, "===": false, "!==": true }, + order: { "<": false, ">": false, "<=": true, ">=": true } + }; + var looselyEqualNotDifferent = + { + eq: { "==": true, "!=": false, "===": false, "!==": true }, + order: { "<": false, ">": false, "<=": true, ">=": true } + }; + var looselyEqualIncomparable = + { + eq: { "==": true, "!=": false, "===": false, "!==": true }, + order: { "<": false, ">": false, "<=": false, ">=": false } + }; + var strictlyEqualNotDifferent = + { + eq: { "==": true, "!=": false, "===": true, "!==": false }, + order: { "<": false, ">": false, "<=": true, ">=": true } + }; + var strictlyEqualIncomparable = + { + eq: { "==": true, "!=": false, "===": true, "!==": false }, + order: { "<": false, ">": false, "<=": false, ">=": false } + }; + + var comparingZeroToSomething = + { + "undefined": notEqualIncomparable, + "null": notEqualNorDifferent, + "true": notEqualLessThan, + "false": looselyEqual, + '""': looselyEqualNotDifferent, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": strictlyEqual, + "-0": strictlyEqual, + "1": notEqualLessThan, + "Math.E": notEqualLessThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": notEqualGreaterThan, + "JSVAL_INT_MAX - 1": notEqualLessThan, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": looselyEqual, + '[""]': looselyEqual, + '["a"]': notEqualIncomparable, + "[0]": looselyEqual + }; + + var comparingObjectOrObjectWithValueUndefined = + { + "undefined": notEqualIncomparable, + "null": notEqualIncomparable, + "true": notEqualIncomparable, + "false": notEqualIncomparable, + '""': notEqualGreaterThan, + '"a"': notEqualLessThan, + '"Z"': notEqualGreaterThan, + "0": notEqualIncomparable, + "-0": notEqualIncomparable, + "1": notEqualIncomparable, + "Math.E": notEqualIncomparable, + "JSVAL_INT_MIN - 1": notEqualIncomparable, + "JSVAL_INT_MIN": notEqualIncomparable, + "JSVAL_INT_MIN + 1": notEqualIncomparable, + "JSVAL_INT_MAX - 1": notEqualIncomparable, + "JSVAL_INT_MAX": notEqualIncomparable, + "JSVAL_INT_MAX + 1": notEqualIncomparable, + "Infinity": notEqualIncomparable, + "-Infinity": notEqualIncomparable, + "NaN": notEqualIncomparable, + "{}": notEqualNorDifferent, + "{ valueOf: undefined }": notEqualNorDifferent, + "[]": notEqualGreaterThan, + '[""]': notEqualGreaterThan, + '["a"]': notEqualLessThan, + "[0]": notEqualGreaterThan + }; + + // Constructed expected-value matrix + var expected = + { + "undefined": + { + "undefined": strictlyEqualIncomparable, + "null": looselyEqualIncomparable, + "true": notEqualIncomparable, + "false": notEqualIncomparable, + '""': notEqualIncomparable, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": notEqualIncomparable, + "-0": notEqualIncomparable, + "1": notEqualIncomparable, + "Math.E": notEqualIncomparable, + "JSVAL_INT_MIN - 1": notEqualIncomparable, + "JSVAL_INT_MIN": notEqualIncomparable, + "JSVAL_INT_MIN + 1": notEqualIncomparable, + "JSVAL_INT_MAX - 1": notEqualIncomparable, + "JSVAL_INT_MAX": notEqualIncomparable, + "JSVAL_INT_MAX + 1": notEqualIncomparable, + "Infinity": notEqualIncomparable, + "-Infinity": notEqualIncomparable, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": notEqualIncomparable, + '[""]': notEqualIncomparable, + '["a"]': notEqualIncomparable, + "[0]": notEqualIncomparable + }, + "null": + { + "undefined": looselyEqualIncomparable, + "null": strictlyEqualNotDifferent, + "true": notEqualLessThan, + "false": notEqualNorDifferent, + '""': notEqualNorDifferent, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": notEqualNorDifferent, + "-0": notEqualNorDifferent, + "1": notEqualLessThan, + "Math.E": notEqualLessThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": notEqualGreaterThan, + "JSVAL_INT_MAX - 1": notEqualLessThan, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": notEqualNorDifferent, + '[""]': notEqualNorDifferent, + '["a"]': notEqualIncomparable, + "[0]": notEqualNorDifferent + }, + "true": + { + "undefined": notEqualIncomparable, + "null": notEqualGreaterThan, + "true": strictlyEqual, + "false": notEqualGreaterThan, + '""': notEqualGreaterThan, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": notEqualGreaterThan, + "-0": notEqualGreaterThan, + "1": looselyEqual, + "Math.E": notEqualLessThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": notEqualGreaterThan, + "JSVAL_INT_MAX - 1": notEqualLessThan, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": notEqualGreaterThan, + '[""]': notEqualGreaterThan, + '["a"]': notEqualIncomparable, + "[0]": notEqualGreaterThan + }, + "false": + { + "undefined": notEqualIncomparable, + "null": notEqualNorDifferent, + "true": notEqualLessThan, + "false": strictlyEqual, + '""': looselyEqualNotDifferent, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": looselyEqual, + "-0": looselyEqual, + "1": notEqualLessThan, + "Math.E": notEqualLessThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": notEqualGreaterThan, + "JSVAL_INT_MAX - 1": notEqualLessThan, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": looselyEqual, + '[""]': looselyEqual, + '["a"]': notEqualIncomparable, + "[0]": looselyEqual + }, + '""': + { + "undefined": notEqualIncomparable, + "null": notEqualNorDifferent, + "true": notEqualLessThan, + "false": looselyEqual, + '""': strictlyEqual, + '"a"': notEqualLessThan, + '"Z"': notEqualLessThan, + "0": looselyEqual, + "-0": looselyEqual, + "1": notEqualLessThan, + "Math.E": notEqualLessThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": notEqualGreaterThan, + "JSVAL_INT_MAX - 1": notEqualLessThan, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualLessThan, + "{ valueOf: undefined }": notEqualLessThan, + "[]": looselyEqual, + '[""]': looselyEqual, + '["a"]': notEqualLessThan, + "[0]": notEqualLessThan + }, + '"a"': + { + "undefined": notEqualIncomparable, + "null": notEqualIncomparable, + "true": notEqualIncomparable, + "false": notEqualIncomparable, + '""': notEqualGreaterThan, + '"a"': strictlyEqual, + '"Z"': notEqualGreaterThan, + "0": notEqualIncomparable, + "-0": notEqualIncomparable, + "1": notEqualIncomparable, + "Math.E": notEqualIncomparable, + "JSVAL_INT_MIN - 1": notEqualIncomparable, + "JSVAL_INT_MIN": notEqualIncomparable, + "JSVAL_INT_MIN + 1": notEqualIncomparable, + "JSVAL_INT_MAX - 1": notEqualIncomparable, + "JSVAL_INT_MAX": notEqualIncomparable, + "JSVAL_INT_MAX + 1": notEqualIncomparable, + "Infinity": notEqualIncomparable, + "-Infinity": notEqualIncomparable, + "NaN": notEqualIncomparable, + "{}": notEqualGreaterThan, + "{ valueOf: undefined }": notEqualGreaterThan, + "[]": notEqualGreaterThan, + '[""]': notEqualGreaterThan, + '["a"]': looselyEqualNotDifferent, + "[0]": notEqualGreaterThan + }, + '"Z"': + { + "undefined": notEqualIncomparable, + "null": notEqualIncomparable, + "true": notEqualIncomparable, + "false": notEqualIncomparable, + '""': notEqualGreaterThan, + '"a"': notEqualLessThan, + '"Z"': strictlyEqual, + "0": notEqualIncomparable, + "-0": notEqualIncomparable, + "1": notEqualIncomparable, + "Math.E": notEqualIncomparable, + "JSVAL_INT_MIN - 1": notEqualIncomparable, + "JSVAL_INT_MIN": notEqualIncomparable, + "JSVAL_INT_MIN + 1": notEqualIncomparable, + "JSVAL_INT_MAX - 1": notEqualIncomparable, + "JSVAL_INT_MAX": notEqualIncomparable, + "JSVAL_INT_MAX + 1": notEqualIncomparable, + "Infinity": notEqualIncomparable, + "-Infinity": notEqualIncomparable, + "NaN": notEqualIncomparable, + "{}": notEqualLessThan, + "{ valueOf: undefined }": notEqualLessThan, + "[]": notEqualGreaterThan, + '[""]': notEqualGreaterThan, + '["a"]': notEqualLessThan, + "[0]": notEqualGreaterThan + }, + "0": comparingZeroToSomething, + "-0": comparingZeroToSomething, + "1": + { + "undefined": notEqualIncomparable, + "null": notEqualGreaterThan, + "true": looselyEqual, + "false": notEqualGreaterThan, + '""': notEqualGreaterThan, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": notEqualGreaterThan, + "-0": notEqualGreaterThan, + "1": strictlyEqual, + "Math.E": notEqualLessThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": notEqualGreaterThan, + "JSVAL_INT_MAX - 1": notEqualLessThan, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": notEqualGreaterThan, + '[""]': notEqualGreaterThan, + '["a"]': notEqualIncomparable, + "[0]": notEqualGreaterThan + }, + "Math.E": + { + "undefined": notEqualIncomparable, + "null": notEqualGreaterThan, + "true": notEqualGreaterThan, + "false": notEqualGreaterThan, + '""': notEqualGreaterThan, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": notEqualGreaterThan, + "-0": notEqualGreaterThan, + "1": notEqualGreaterThan, + "Math.E": strictlyEqual, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": notEqualGreaterThan, + "JSVAL_INT_MAX - 1": notEqualLessThan, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": notEqualGreaterThan, + '[""]': notEqualGreaterThan, + '["a"]': notEqualIncomparable, + "[0]": notEqualGreaterThan + }, + "JSVAL_INT_MIN - 1": + { + "undefined": notEqualIncomparable, + "null": notEqualLessThan, + "true": notEqualLessThan, + "false": notEqualLessThan, + '""': notEqualLessThan, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": notEqualLessThan, + "-0": notEqualLessThan, + "1": notEqualLessThan, + "Math.E": notEqualLessThan, + "JSVAL_INT_MIN - 1": strictlyEqual, + "JSVAL_INT_MIN": notEqualLessThan, + "JSVAL_INT_MIN + 1": notEqualLessThan, + "JSVAL_INT_MAX - 1": notEqualLessThan, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": notEqualLessThan, + '[""]': notEqualLessThan, + '["a"]': notEqualIncomparable, + "[0]": notEqualLessThan + }, + "JSVAL_INT_MIN": + { + "undefined": notEqualIncomparable, + "null": notEqualLessThan, + "true": notEqualLessThan, + "false": notEqualLessThan, + '""': notEqualLessThan, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": notEqualLessThan, + "-0": notEqualLessThan, + "1": notEqualLessThan, + "Math.E": notEqualLessThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": strictlyEqual, + "JSVAL_INT_MIN + 1": notEqualLessThan, + "JSVAL_INT_MAX - 1": notEqualLessThan, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": notEqualLessThan, + '[""]': notEqualLessThan, + '["a"]': notEqualIncomparable, + "[0]": notEqualLessThan + }, + "JSVAL_INT_MIN + 1": + { + "undefined": notEqualIncomparable, + "null": notEqualLessThan, + "true": notEqualLessThan, + "false": notEqualLessThan, + '""': notEqualLessThan, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": notEqualLessThan, + "-0": notEqualLessThan, + "1": notEqualLessThan, + "Math.E": notEqualLessThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": strictlyEqual, + "JSVAL_INT_MAX - 1": notEqualLessThan, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": notEqualLessThan, + '[""]': notEqualLessThan, + '["a"]': notEqualIncomparable, + "[0]": notEqualLessThan + }, + "JSVAL_INT_MAX - 1": + { + "undefined": notEqualIncomparable, + "null": notEqualGreaterThan, + "true": notEqualGreaterThan, + "false": notEqualGreaterThan, + '""': notEqualGreaterThan, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": notEqualGreaterThan, + "-0": notEqualGreaterThan, + "1": notEqualGreaterThan, + "Math.E": notEqualGreaterThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": notEqualGreaterThan, + "JSVAL_INT_MAX - 1": strictlyEqual, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": notEqualGreaterThan, + '[""]': notEqualGreaterThan, + '["a"]': notEqualIncomparable, + "[0]": notEqualGreaterThan + }, + "JSVAL_INT_MAX": + { + "undefined": notEqualIncomparable, + "null": notEqualGreaterThan, + "true": notEqualGreaterThan, + "false": notEqualGreaterThan, + '""': notEqualGreaterThan, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": notEqualGreaterThan, + "-0": notEqualGreaterThan, + "1": notEqualGreaterThan, + "Math.E": notEqualGreaterThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": notEqualGreaterThan, + "JSVAL_INT_MAX - 1": notEqualGreaterThan, + "JSVAL_INT_MAX": strictlyEqual, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": notEqualGreaterThan, + '[""]': notEqualGreaterThan, + '["a"]': notEqualIncomparable, + "[0]": notEqualGreaterThan + }, + "JSVAL_INT_MAX + 1": + { + "undefined": notEqualIncomparable, + "null": notEqualGreaterThan, + "true": notEqualGreaterThan, + "false": notEqualGreaterThan, + '""': notEqualGreaterThan, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": notEqualGreaterThan, + "-0": notEqualGreaterThan, + "1": notEqualGreaterThan, + "Math.E": notEqualGreaterThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": notEqualGreaterThan, + "JSVAL_INT_MAX - 1": notEqualGreaterThan, + "JSVAL_INT_MAX": notEqualGreaterThan, + "JSVAL_INT_MAX + 1": strictlyEqual, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": notEqualGreaterThan, + '[""]': notEqualGreaterThan, + '["a"]': notEqualIncomparable, + "[0]": notEqualGreaterThan + }, + "Infinity": + { + "undefined": notEqualIncomparable, + "null": notEqualGreaterThan, + "true": notEqualGreaterThan, + "false": notEqualGreaterThan, + '""': notEqualGreaterThan, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": notEqualGreaterThan, + "-0": notEqualGreaterThan, + "1": notEqualGreaterThan, + "Math.E": notEqualGreaterThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": notEqualGreaterThan, + "JSVAL_INT_MAX - 1": notEqualGreaterThan, + "JSVAL_INT_MAX": notEqualGreaterThan, + "JSVAL_INT_MAX + 1": notEqualGreaterThan, + "Infinity": strictlyEqual, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": notEqualGreaterThan, + '[""]': notEqualGreaterThan, + '["a"]': notEqualIncomparable, + "[0]": notEqualGreaterThan + }, + "-Infinity": + { + "undefined": notEqualIncomparable, + "null": notEqualLessThan, + "true": notEqualLessThan, + "false": notEqualLessThan, + '""': notEqualLessThan, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": notEqualLessThan, + "-0": notEqualLessThan, + "1": notEqualLessThan, + "Math.E": notEqualLessThan, + "JSVAL_INT_MIN - 1": notEqualLessThan, + "JSVAL_INT_MIN": notEqualLessThan, + "JSVAL_INT_MIN + 1": notEqualLessThan, + "JSVAL_INT_MAX - 1": notEqualLessThan, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": strictlyEqual, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": notEqualLessThan, + '[""]': notEqualLessThan, + '["a"]': notEqualIncomparable, + "[0]": notEqualLessThan + }, + "NaN": + { + "undefined": notEqualIncomparable, + "null": notEqualIncomparable, + "true": notEqualIncomparable, + "false": notEqualIncomparable, + '""': notEqualIncomparable, + '"a"': notEqualIncomparable, + '"Z"': notEqualIncomparable, + "0": notEqualIncomparable, + "-0": notEqualIncomparable, + "1": notEqualIncomparable, + "Math.E": notEqualIncomparable, + "JSVAL_INT_MIN - 1": notEqualIncomparable, + "JSVAL_INT_MIN": notEqualIncomparable, + "JSVAL_INT_MIN + 1": notEqualIncomparable, + "JSVAL_INT_MAX - 1": notEqualIncomparable, + "JSVAL_INT_MAX": notEqualIncomparable, + "JSVAL_INT_MAX + 1": notEqualIncomparable, + "Infinity": notEqualIncomparable, + "-Infinity": notEqualIncomparable, + "NaN": notEqualIncomparable, + "{}": notEqualIncomparable, + "{ valueOf: undefined }": notEqualIncomparable, + "[]": notEqualIncomparable, + '[""]': notEqualIncomparable, + '["a"]': notEqualIncomparable, + "[0]": notEqualIncomparable + }, + "{}": comparingObjectOrObjectWithValueUndefined, + "{ valueOf: undefined }": comparingObjectOrObjectWithValueUndefined, + "[]": + { + "undefined": notEqualIncomparable, + "null": notEqualNorDifferent, + "true": notEqualLessThan, + "false": looselyEqual, + '""': looselyEqual, + '"a"': notEqualLessThan, + '"Z"': notEqualLessThan, + "0": looselyEqual, + "-0": looselyEqual, + "1": notEqualLessThan, + "Math.E": notEqualLessThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": notEqualGreaterThan, + "JSVAL_INT_MAX - 1": notEqualLessThan, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualLessThan, + "{ valueOf: undefined }": notEqualLessThan, + "[]": notEqualNorDifferent, + '[""]': notEqualNorDifferent, + '["a"]': notEqualLessThan, + "[0]": notEqualLessThan + }, + '[""]': + { + "undefined": notEqualIncomparable, + "null": notEqualNorDifferent, + "true": notEqualLessThan, + "false": looselyEqual, + '""': looselyEqual, + '"a"': notEqualLessThan, + '"Z"': notEqualLessThan, + "0": looselyEqual, + "-0": looselyEqual, + "1": notEqualLessThan, + "Math.E": notEqualLessThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": notEqualGreaterThan, + "JSVAL_INT_MAX - 1": notEqualLessThan, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualLessThan, + "{ valueOf: undefined }": notEqualLessThan, + "[]": notEqualNorDifferent, + '[""]': notEqualNorDifferent, + '["a"]': notEqualLessThan, + "[0]": notEqualLessThan + }, + '["a"]': + { + "undefined": notEqualIncomparable, + "null": notEqualIncomparable, + "true": notEqualIncomparable, + "false": notEqualIncomparable, + '""': notEqualGreaterThan, + '"a"': looselyEqual, + '"Z"': notEqualGreaterThan, + "0": notEqualIncomparable, + "-0": notEqualIncomparable, + "1": notEqualIncomparable, + "Math.E": notEqualIncomparable, + "JSVAL_INT_MIN - 1": notEqualIncomparable, + "JSVAL_INT_MIN": notEqualIncomparable, + "JSVAL_INT_MIN + 1": notEqualIncomparable, + "JSVAL_INT_MAX - 1": notEqualIncomparable, + "JSVAL_INT_MAX": notEqualIncomparable, + "JSVAL_INT_MAX + 1": notEqualIncomparable, + "Infinity": notEqualIncomparable, + "-Infinity": notEqualIncomparable, + "NaN": notEqualIncomparable, + "{}": notEqualGreaterThan, + "{ valueOf: undefined }": notEqualGreaterThan, + "[]": notEqualGreaterThan, + '[""]': notEqualGreaterThan, + '["a"]': notEqualNorDifferent, + "[0]": notEqualGreaterThan + }, + "[0]": + { + "undefined": notEqualIncomparable, + "null": notEqualNorDifferent, + "true": notEqualLessThan, + "false": looselyEqual, + '""': notEqualGreaterThan, + '"a"': notEqualLessThan, + '"Z"': notEqualLessThan, + "0": looselyEqual, + "-0": looselyEqual, + "1": notEqualLessThan, + "Math.E": notEqualLessThan, + "JSVAL_INT_MIN - 1": notEqualGreaterThan, + "JSVAL_INT_MIN": notEqualGreaterThan, + "JSVAL_INT_MIN + 1": notEqualGreaterThan, + "JSVAL_INT_MAX - 1": notEqualLessThan, + "JSVAL_INT_MAX": notEqualLessThan, + "JSVAL_INT_MAX + 1": notEqualLessThan, + "Infinity": notEqualLessThan, + "-Infinity": notEqualGreaterThan, + "NaN": notEqualIncomparable, + "{}": notEqualLessThan, + "{ valueOf: undefined }": notEqualLessThan, + "[]": notEqualGreaterThan, + '[""]': notEqualGreaterThan, + '["a"]': notEqualLessThan, + "[0]": notEqualNorDifferent + } + }; + + + + var failures = []; + function fail(a, ta, b, tb, ex, ac, op) + { + failures.push("(" + a + " " + op + " " + b + ") wrong: " + + "expected " + ex + ", got " + ac + + " (types " + types[ta] + ", " + types[tb] + ")"); + } + + var result = false; + for (var i in values) + { + for (var j in values) + { + // Constants, so hoist to help JIT know that + var vala = values[i], valb = values[j]; + var a = vala.value(), b = valb.value(); + + for (var opname in orderOps) + { + var op = orderOps[opname]; + var expect = expected[i][j].order[opname]; + var failed = false; + + for (var iter = 0; iter < 5; iter++) + { + result = op(a, b); + failed = failed || result !== expect; + } + + if (failed) + fail(i, vala.type, j, valb.type, expect, result, opname); + } + + for (var opname in eqOps) + { + var op = eqOps[opname]; + var expect = expected[i][j].eq[opname]; + var failed = false; + + for (var iter = 0; iter < 5; iter++) + { + result = op(a, b); + failed = failed || result !== expect; + } + + if (failed) + fail(i, vala.type, j, valb.type, expect, result, opname); + } + } + } + + if (failures.length == 0) + return "no failures reported!"; + + return "\n" + failures.join(",\n"); +} +assertEq(testComparisons(), "no failures reported!"); diff --git a/js/src/jit-test/tests/basic/testConcatNWithSideEffects.js b/js/src/jit-test/tests/basic/testConcatNWithSideEffects.js new file mode 100644 index 0000000..6272d54 --- /dev/null +++ b/js/src/jit-test/tests/basic/testConcatNWithSideEffects.js @@ -0,0 +1,13 @@ +var log; +function b(x) { log += 'b'; return 'B'; } +function g() { + log = ''; + var a = {toString: function () { log += 'a'; return 'A'; }}; + assertEq("[" + a + b() + "]", "[AB]"); + assertEq(log, "ab"); +} + +for (var i = 0; i < 1000; ++i) + g(); + +checkStats({recorderStarted:1, recorderAborted:0, traceCompleted:1}); diff --git a/js/src/jit-test/tests/basic/testConstIf.js b/js/src/jit-test/tests/basic/testConstIf.js new file mode 100644 index 0000000..2fcde1c --- /dev/null +++ b/js/src/jit-test/tests/basic/testConstIf.js @@ -0,0 +1,6 @@ +function testConstIf() { + var x; + for (var j=0;j<5;++j) { if (1.1 || 5) { } x = 2;} + return x; +} +assertEq(testConstIf(), 2); diff --git a/js/src/jit-test/tests/basic/testConstSwitch.js b/js/src/jit-test/tests/basic/testConstSwitch.js new file mode 100644 index 0000000..f98959a --- /dev/null +++ b/js/src/jit-test/tests/basic/testConstSwitch.js @@ -0,0 +1,13 @@ +// No test case, just make sure this doesn't assert. +function testNegZero2() { + var z = 0; + for (let j = 0; j < 5; ++j) { ({p: (-z)}); } +} +testNegZero2(); + +function testConstSwitch() { + var x; + for (var j=0;j<5;++j) { switch(1.1) { case NaN: case 2: } x = 2; } + return x; +} +assertEq(testConstSwitch(), 2); diff --git a/js/src/jit-test/tests/basic/testConstSwitch2.js b/js/src/jit-test/tests/basic/testConstSwitch2.js new file mode 100644 index 0000000..48d5f2c --- /dev/null +++ b/js/src/jit-test/tests/basic/testConstSwitch2.js @@ -0,0 +1,6 @@ +function testConstSwitch2() { + var x; + for (var j = 0; j < 4; ++j) { switch(0/0) { } } + return "ok"; +} +assertEq(testConstSwitch2(), "ok"); diff --git a/js/src/jit-test/tests/basic/testConstantBooleanExpr.js b/js/src/jit-test/tests/basic/testConstantBooleanExpr.js new file mode 100644 index 0000000..8cc5f34 --- /dev/null +++ b/js/src/jit-test/tests/basic/testConstantBooleanExpr.js @@ -0,0 +1,6 @@ +function testConstantBooleanExpr() +{ + for (var j = 0; j < 3; ++j) { if(true <= true) { } } + return "ok"; +} +assertEq(testConstantBooleanExpr(), "ok"); diff --git a/js/src/jit-test/tests/basic/testConstructorArgs-1.js b/js/src/jit-test/tests/basic/testConstructorArgs-1.js new file mode 100644 index 0000000..81630f0 --- /dev/null +++ b/js/src/jit-test/tests/basic/testConstructorArgs-1.js @@ -0,0 +1,11 @@ +function f(a, b) { + this.a = a; + assertEq(b, 'x'); +} + +for (var x = 0; x < RUNLOOP; ++x) { + f.prototype = {}; + var obj = new f(x, 'x'); + assertEq(obj.a, x); + assertEq(Object.getPrototypeOf(obj), f.prototype); +} diff --git a/js/src/jit-test/tests/basic/testConstructorArgs-2.js b/js/src/jit-test/tests/basic/testConstructorArgs-2.js new file mode 100644 index 0000000..5a85470 --- /dev/null +++ b/js/src/jit-test/tests/basic/testConstructorArgs-2.js @@ -0,0 +1,12 @@ +function f(a, b, c) { + this.a = a; + assertEq(b, 'x'); + assertEq(c, void 0); +} + +for (var x = 0; x < RUNLOOP; ++x) { + f.prototype = {}; + var obj = new f(x, 'x'); // fewer than f.length arguments + assertEq(obj.a, x); + assertEq(Object.getPrototypeOf(obj), f.prototype); +} diff --git a/js/src/jit-test/tests/basic/testConstructorArgs-3.js b/js/src/jit-test/tests/basic/testConstructorArgs-3.js new file mode 100644 index 0000000..4b1eb55 --- /dev/null +++ b/js/src/jit-test/tests/basic/testConstructorArgs-3.js @@ -0,0 +1,11 @@ +function f(a) { + this.a = a; + assertEq(arguments[1], 'x'); +} + +for (var x = 0; x < RUNLOOP; ++x) { + f.prototype = {}; + var obj = new f(x, 'x'); // more than f.length arguments + assertEq(obj.a, x); + assertEq(Object.getPrototypeOf(obj), f.prototype); +} diff --git a/js/src/jit-test/tests/basic/testConstructorBail.js b/js/src/jit-test/tests/basic/testConstructorBail.js new file mode 100644 index 0000000..0cd3397 --- /dev/null +++ b/js/src/jit-test/tests/basic/testConstructorBail.js @@ -0,0 +1,4 @@ +function testConstructorBail() { + for (let i = 0; i < 5; ++i) new Number(/x/); +} +testConstructorBail(); diff --git a/js/src/jit-test/tests/basic/testContinue.js b/js/src/jit-test/tests/basic/testContinue.js new file mode 100644 index 0000000..a878bbb --- /dev/null +++ b/js/src/jit-test/tests/basic/testContinue.js @@ -0,0 +1,11 @@ +function testContinue() { + var i; + var total = 0; + for (i = 0; i < 20; ++i) { + if (i == 11) + continue; + total++; + } + return total; +} +assertEq(testContinue(), 19); diff --git a/js/src/jit-test/tests/basic/testContinueWithLabel.js b/js/src/jit-test/tests/basic/testContinueWithLabel.js new file mode 100644 index 0000000..b851b41 --- /dev/null +++ b/js/src/jit-test/tests/basic/testContinueWithLabel.js @@ -0,0 +1,16 @@ +function testContinueWithLabel() { + var i = 0; + var j = 20; + checkiandj : + while (i < 10) { + i += 1; + checkj : + while (j > 10) { + j -= 1; + if ((j % 2) == 0) + continue checkj; + } + } + return i + j; +} +assertEq(testContinueWithLabel(), 20); diff --git a/js/src/jit-test/tests/basic/testContinueWithLabel2.js b/js/src/jit-test/tests/basic/testContinueWithLabel2.js new file mode 100644 index 0000000..fdc8db0 --- /dev/null +++ b/js/src/jit-test/tests/basic/testContinueWithLabel2.js @@ -0,0 +1,7 @@ +outer: +for (var i = 10; i < 19; i++) + for (var j = 0; j < 9; j++) + if (j < i) + continue outer; + +checkStats({recorderStarted: 3, recorderAborted: 1, traceCompleted: 2}); \ No newline at end of file diff --git a/js/src/jit-test/tests/basic/testContinueWithLabel3.js b/js/src/jit-test/tests/basic/testContinueWithLabel3.js new file mode 100644 index 0000000..14ef74b --- /dev/null +++ b/js/src/jit-test/tests/basic/testContinueWithLabel3.js @@ -0,0 +1,6 @@ +// bug 511575 comment 3 +outer: +for (var j = 0; j < 10; j++) + for (var p in {x:1}) + if (p > "q") + continue outer; diff --git a/js/src/jit-test/tests/basic/testContinueWithLabel4.js b/js/src/jit-test/tests/basic/testContinueWithLabel4.js new file mode 100644 index 0000000..739726c --- /dev/null +++ b/js/src/jit-test/tests/basic/testContinueWithLabel4.js @@ -0,0 +1,25 @@ +// bug 511575 + +Function.prototype.X = 42; + +function ownProperties() { + var props = {}; + var r = function () {}; + + outer: + for (var a in r) { + for (var b in r) { + if (a == b) { + continue outer; + } + } + print("SHOULD NOT BE REACHED"); + props[a] = true; + } + return props; +} + +for (var i = 0; i < 12; ++i) { + print(i); + ownProperties(); +} diff --git a/js/src/jit-test/tests/basic/testConvertibleObjectEqUndefined.js b/js/src/jit-test/tests/basic/testConvertibleObjectEqUndefined.js new file mode 100644 index 0000000..788c789 --- /dev/null +++ b/js/src/jit-test/tests/basic/testConvertibleObjectEqUndefined.js @@ -0,0 +1,33 @@ +function x4(v) { return "" + v + v + v + v; } +function testConvertibleObjectEqUndefined() +{ + var compares = + [ + false, false, false, false, + undefined, undefined, undefined, undefined, + false, false, false, false, + undefined, undefined, undefined, undefined, + false, false, false, false, + undefined, undefined, undefined, undefined, + false, false, false, false, + undefined, undefined, undefined, undefined, + false, false, false, false, + undefined, undefined, undefined, undefined, + ]; + var count = 0; + var obj = { valueOf: function() { count++; return 1; } }; + var results = compares.map(function(v) { return "unwritten"; }); + + for (var i = 0, sz = compares.length; i < sz; i++) + results[i] = compares[i] == obj; + + return results.join("") + count; +} + +assertEq(testConvertibleObjectEqUndefined(), + x4(false) + x4(false) + x4(false) + x4(false) + x4(false) + x4(false) + + x4(false) + x4(false) + x4(false) + x4(false) + "20"); + +checkStats({ + sideExitIntoInterpreter: 3 +}); diff --git a/js/src/jit-test/tests/basic/testCustomIterator.js b/js/src/jit-test/tests/basic/testCustomIterator.js new file mode 100644 index 0000000..24f915d --- /dev/null +++ b/js/src/jit-test/tests/basic/testCustomIterator.js @@ -0,0 +1,26 @@ +function my_iterator_next() { + if (this.i == 10) { + this.i = 0; + throw this.StopIteration; + } + return this.i++; +} +function testCustomIterator() { + var o = { + __iterator__: function () { + return { + i: 0, + next: my_iterator_next, + StopIteration: StopIteration + }; + } + }; + var a=[]; + for (var k = 0; k < 100; k += 10) { + for(var j in o) { + a[k + (j >> 0)] = j*k; + } + } + return a.join(); +} +assertEq(testCustomIterator(), "0,0,0,0,0,0,0,0,0,0,0,10,20,30,40,50,60,70,80,90,0,20,40,60,80,100,120,140,160,180,0,30,60,90,120,150,180,210,240,270,0,40,80,120,160,200,240,280,320,360,0,50,100,150,200,250,300,350,400,450,0,60,120,180,240,300,360,420,480,540,0,70,140,210,280,350,420,490,560,630,0,80,160,240,320,400,480,560,640,720,0,90,180,270,360,450,540,630,720,810"); diff --git a/js/src/jit-test/tests/basic/testDateNow.js b/js/src/jit-test/tests/basic/testDateNow.js new file mode 100644 index 0000000..4fdb6b5 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDateNow.js @@ -0,0 +1,15 @@ +function testDateNow() { + // Accessing global.Date for the first time will change the global shape, + // so do it before the loop starts; otherwise we have to loop an extra time + // to pick things up. + var time = Date.now(); + for (var j = 0; j < RUNLOOP; ++j) + time = Date.now(); + return "ok"; +} +assertEq(testDateNow(), "ok"); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceTriggered: 1 +}); diff --git a/js/src/jit-test/tests/basic/testDecElem1.js b/js/src/jit-test/tests/basic/testDecElem1.js new file mode 100644 index 0000000..e954030 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDecElem1.js @@ -0,0 +1,10 @@ +var obj = {p: 100}; +var name = "p"; +var a = []; +for (var i = 0; i < 10; i++) + a[i] = --obj[name]; +assertEq(a.join(','), '99,98,97,96,95,94,93,92,91,90'); +assertEq(obj.p, 90); + +checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1}); + diff --git a/js/src/jit-test/tests/basic/testDecElem2.js b/js/src/jit-test/tests/basic/testDecElem2.js new file mode 100644 index 0000000..5327f40 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDecElem2.js @@ -0,0 +1,11 @@ +var obj = {s: ""}; +var name = "s"; +var a = []; +for (var i = 0; i <= RECORDLOOP + 5; i++) { + a[i] = 'x'; + if (i > RECORDLOOP) + a[i] = --obj[name]; // first recording changes obj.s from string to number +} +assertEq(a.join(','), Array(RECORDLOOP + 2).join('x,') + '-1,-2,-3,-4,-5'); +assertEq(obj.s, -5); + diff --git a/js/src/jit-test/tests/basic/testDecayingInnerLoop.js b/js/src/jit-test/tests/basic/testDecayingInnerLoop.js new file mode 100644 index 0000000..92e985c --- /dev/null +++ b/js/src/jit-test/tests/basic/testDecayingInnerLoop.js @@ -0,0 +1,9 @@ +function testDecayingInnerLoop() { + var i, j, k = 10; + for (i = 0; i < 5000; ++i) { + for (j = 0; j < k; ++j); + --k; + } + return i; +} +assertEq(testDecayingInnerLoop(), 5000); diff --git a/js/src/jit-test/tests/basic/testDeepBail1.js b/js/src/jit-test/tests/basic/testDeepBail1.js new file mode 100644 index 0000000..f359077 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDeepBail1.js @@ -0,0 +1,6 @@ +function testDeepBail1() { + var y = ; + for (var i = 0; i < RUNLOOP; i++) + "" in y; +} +testDeepBail1(); diff --git a/js/src/jit-test/tests/basic/testDeepBailFromHasInstance.js b/js/src/jit-test/tests/basic/testDeepBailFromHasInstance.js new file mode 100644 index 0000000..33646da --- /dev/null +++ b/js/src/jit-test/tests/basic/testDeepBailFromHasInstance.js @@ -0,0 +1,12 @@ +var arr = [StopIteration, StopIteration, StopIteration, StopIteration, {}]; +var obj = {}; +var x; +var result = 'no error'; +try { + for (var i = 0; i < arr.length; i++) + x = (obj instanceof arr[i]); // last iteration throws, triggering deep bail +} catch (exc) { + result = exc.constructor.name; +} +assertEq(result, 'TypeError'); + diff --git a/js/src/jit-test/tests/basic/testDeepBailInMoreIter.js b/js/src/jit-test/tests/basic/testDeepBailInMoreIter.js new file mode 100644 index 0000000..3e6b680 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDeepBailInMoreIter.js @@ -0,0 +1,5 @@ +w = (function() { yield })(); +w.next(); +for (var i = 0; i < 100; ++i) { + for (v in w) {} +} diff --git a/js/src/jit-test/tests/basic/testDeepBailWhileRecording.js b/js/src/jit-test/tests/basic/testDeepBailWhileRecording.js new file mode 100644 index 0000000..7ee4218 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDeepBailWhileRecording.js @@ -0,0 +1,20 @@ +var o = {}; +var arr = [o,o,o,o,o,o,o,o,o,o,o,o,o]; +var out = []; + +const OUTER = 10; + +for (var i = 0; i < 10; ++i) { + for (var j = 0; j < arr.length; ++j) { + out.push(String.prototype.indexOf.call(arr[i], 'object')); + } +} + +assertEq(out.length, 10 * arr.length); +for (var i = 0; i < out.length; ++i) + assertEq(out[i], 1); + +checkStats({ + traceCompleted:2, + recorderAborted:1 +}); diff --git a/js/src/jit-test/tests/basic/testDeepPropertyShadowing.js b/js/src/jit-test/tests/basic/testDeepPropertyShadowing.js new file mode 100644 index 0000000..65dbf8d --- /dev/null +++ b/js/src/jit-test/tests/basic/testDeepPropertyShadowing.js @@ -0,0 +1,17 @@ +function testDeepPropertyShadowing() +{ + function h(node) { + var x = 0; + while (node) { + x++; + node = node.parent; + } + return x; + } + var tree = {__proto__: {__proto__: {parent: null}}}; + h(tree); + h(tree); + tree.parent = {}; + assertEq(h(tree), 2); +} +testDeepPropertyShadowing(); diff --git a/js/src/jit-test/tests/basic/testDefinePropertyAcrossCompartment.js b/js/src/jit-test/tests/basic/testDefinePropertyAcrossCompartment.js new file mode 100644 index 0000000..b997089 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDefinePropertyAcrossCompartment.js @@ -0,0 +1,7 @@ +var a = evalcx(''); +Object.defineProperty(a, "", ({ + get: function() {}, +})) +gc() + +// don't crash diff --git a/js/src/jit-test/tests/basic/testDenseArrayProp.js b/js/src/jit-test/tests/basic/testDenseArrayProp.js new file mode 100644 index 0000000..1ccb2e8 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDenseArrayProp.js @@ -0,0 +1,12 @@ +function testDenseArrayProp() +{ + [].__proto__.x = 1; + ({}).__proto__.x = 2; + var a = [[],[],[],({}).__proto__]; + for (var i = 0; i < a.length; ++i) + uneval(a[i].x); + delete [].__proto__.x; + delete ({}).__proto__.x; + return "ok"; +} +assertEq(testDenseArrayProp(), "ok"); diff --git a/js/src/jit-test/tests/basic/testDenseToSlowArray.js b/js/src/jit-test/tests/basic/testDenseToSlowArray.js new file mode 100644 index 0000000..e4b6b5d --- /dev/null +++ b/js/src/jit-test/tests/basic/testDenseToSlowArray.js @@ -0,0 +1,185 @@ +// test dense -> slow array transitions during the recording and on trace +// for various array functions and property accessors + +function test_set_elem() { + + function f() { + var bag = []; + for (var i = 0; i != 100; ++i) { + var a = [0]; + a[100*100] = i; + bag.push(a); + } + + for (var i = 0; i != 100; ++i) { + var a = [0]; + a[200 + i] = i; + bag.push(a); + } + return bag; + } + + var bag = f(); + + for (var i = 0; i != 100; ++i) { + var a = bag[i]; + assertEq(a.length, 100 * 100 + 1); + assertEq(a[100*100], i); + assertEq(a[0], 0); + assertEq(1 + i in a, false); + } + + for (var i = 0; i != 100; ++i) { + var a = bag[100 + i]; + assertEq(a.length, 200 + i + 1); + assertEq(a[200 + i], i); + assertEq(a[0], 0); + assertEq(1 + i in a, false); + } +} + +function test_reverse() { + + function prepare_arays() { + var bag = []; + var base_index = 245; + for (var i = 0; i != 50; ++i) { + var a = [1, 2, 3, 4, 5]; + a.length = i + base_index; + bag.push(a); + } + return bag; + } + + function test(bag) { + for (var i = 0; i != bag.length; ++i) { + var a = bag[i]; + a.reverse(); + a[0] = 1; + } + } + + var bag = prepare_arays(); + test(bag); + for (var i = 0; i != bag.length; ++i) { + var a = bag[i]; + assertEq(a[0], 1); + for (var j = 1; j <= 5; ++j) { + assertEq(a[a.length - j], j); + } + for (var j = 1; j < a.length - 5; ++j) { + assertEq(j in a, false); + } + } + +} + +function test_push() { + + function prepare_arays() { + var bag = []; + var base_index = 245; + for (var i = 0; i != 50; ++i) { + var a = [0]; + a.length = i + base_index; + bag.push(a); + } + return bag; + } + + function test(bag) { + for (var i = 0; i != bag.length; ++i) { + var a = bag[i]; + a.push(2); + a[0] = 1; + } + } + + var bag = prepare_arays(); + test(bag); + for (var i = 0; i != bag.length; ++i) { + var a = bag[i]; + assertEq(a[0], 1); + assertEq(a[a.length - 1], 2); + for (var j = 1; j < a.length - 1; ++j) { + assertEq(j in a, false); + } + } +} + +function test_unshift() { + + function prepare_arays() { + var bag = []; + var base_index = 245; + for (var i = 0; i != 50; ++i) { + var a = [0]; + a.length = i + base_index; + bag.push(a); + } + return bag; + } + + function test(bag) { + for (var i = 0; i != bag.length; ++i) { + var a = bag[i]; + a.unshift(1); + a[2] = 2; + } + } + + var bag = prepare_arays(); + test(bag); + for (var i = 0; i != bag.length; ++i) { + var a = bag[i]; + assertEq(a[0], 1); + assertEq(a[1], 0); + assertEq(a[2], 2); + for (var j = 3; j < a.length; ++j) { + assertEq(j in a, false); + } + } +} + +function test_splice() { + + function prepare_arays() { + var bag = []; + var base_index = 245; + for (var i = 0; i != 50; ++i) { + var a = [1, 2]; + a.length = i + base_index; + bag.push(a); + } + return bag; + } + + function test(bag) { + for (var i = 0; i != bag.length; ++i) { + var a = bag[i]; + a.splice(1, 0, "a", "b", "c"); + a[2] = 100; + } + } + + var bag = prepare_arays(); + test(bag); + for (var i = 0; i != bag.length; ++i) { + var a = bag[i]; + assertEq(a[0], 1); + assertEq(a[1], "a"); + assertEq(a[2], 100); + assertEq(a[3], "c"); + assertEq(a[4], 2); + for (var j = 5; j < a.length; ++j) { + assertEq(j in a, false); + } + } +} + +test_set_elem(); +test_reverse(); +test_push(); +test_unshift(); +test_splice(); + diff --git a/js/src/jit-test/tests/basic/testDestructuring.js b/js/src/jit-test/tests/basic/testDestructuring.js new file mode 100644 index 0000000..3e6cfdb --- /dev/null +++ b/js/src/jit-test/tests/basic/testDestructuring.js @@ -0,0 +1,9 @@ +function testDestructuring() { + var t = 0; + for (var i = 0; i < HOTLOOP + 1; ++i) { + var [r, g, b] = [1, 1, 1]; + t += r + g + b; + } + return t +} +assertEq(testDestructuring(), (HOTLOOP + 1) * 3); diff --git a/js/src/jit-test/tests/basic/testDifferingArgc.js b/js/src/jit-test/tests/basic/testDifferingArgc.js new file mode 100644 index 0000000..0cac569 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDifferingArgc.js @@ -0,0 +1,18 @@ +function doTestDifferingArgc(a, b) +{ + var k = 0; + for (var i = 0; i < 10; i++) + { + k += i; + } + return k; +} +function testDifferingArgc() +{ + var x = 0; + x += doTestDifferingArgc(1, 2); + x += doTestDifferingArgc(1); + x += doTestDifferingArgc(1, 2, 3); + return x; +} +assertEq(testDifferingArgc(), 45*3); diff --git a/js/src/jit-test/tests/basic/testDivOverflow.js b/js/src/jit-test/tests/basic/testDivOverflow.js new file mode 100644 index 0000000..f2af92b --- /dev/null +++ b/js/src/jit-test/tests/basic/testDivOverflow.js @@ -0,0 +1,6 @@ +for (d in [0, 0]) { + const a = (d -= (++d).toString()) + for each(b in [Number(1) << d, 0, 0xC]) { + b / a + } +} diff --git a/js/src/jit-test/tests/basic/testDivision.js b/js/src/jit-test/tests/basic/testDivision.js new file mode 100644 index 0000000..52f3d95 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDivision.js @@ -0,0 +1,10 @@ +function testDivision() { + var a = 32768; + var b; + while (b !== 1) { + b = a / 2; + a = b; + } + return a; +} +assertEq(testDivision(), 1); diff --git a/js/src/jit-test/tests/basic/testDivisionFloat.js b/js/src/jit-test/tests/basic/testDivisionFloat.js new file mode 100644 index 0000000..44f6765 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDivisionFloat.js @@ -0,0 +1,10 @@ +function testDivisionFloat() { + var a = 32768.0; + var b; + while (b !== 1) { + b = a / 2.0; + a = b; + } + return a === 1.0; +} +assertEq(testDivisionFloat(), true); diff --git a/js/src/jit-test/tests/basic/testDivisionWithNegative1.js b/js/src/jit-test/tests/basic/testDivisionWithNegative1.js new file mode 100644 index 0000000..18a3b26 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDivisionWithNegative1.js @@ -0,0 +1,6 @@ +function testDivisionWithNegative1() { + for (var i = 3; i >= 0; --i) + c = i / -1; + return 1/c; +} +assertEq(testDivisionWithNegative1(), -Infinity); diff --git a/js/src/jit-test/tests/basic/testDoubleComparison.js b/js/src/jit-test/tests/basic/testDoubleComparison.js new file mode 100644 index 0000000..e102e42 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDoubleComparison.js @@ -0,0 +1,16 @@ +function testDoubleComparison() +{ + for (var i = 0; i < 500000; ++i) + { + switch (1 / 0) + { + case Infinity: + } + } + + return "finished"; +} +assertEq(testDoubleComparison(), "finished"); +checkStats({ + sideExitIntoInterpreter: 1 +}); diff --git a/js/src/jit-test/tests/basic/testDoubleToStr.js b/js/src/jit-test/tests/basic/testDoubleToStr.js new file mode 100644 index 0000000..9eea240 --- /dev/null +++ b/js/src/jit-test/tests/basic/testDoubleToStr.js @@ -0,0 +1,9 @@ +function testDoubleToStr() { + var x = 0.0; + var y = 5.5; + for (var i = 0; i < 200; i++) { + x += parseFloat(y.toString()); + } + return x; +} +assertEq(testDoubleToStr(), 5.5*200); diff --git a/js/src/jit-test/tests/basic/testDoubleZeroInSwitch1.js b/js/src/jit-test/tests/basic/testDoubleZeroInSwitch1.js new file mode 100644 index 0000000..2b147aa --- /dev/null +++ b/js/src/jit-test/tests/basic/testDoubleZeroInSwitch1.js @@ -0,0 +1,7 @@ +var a = Math.sin(Math.PI/2); // spec does not specify precise answer here... +if (a === 1) { // ...but if a === 1 here... + switch (a) { + case 1: break; // ...then it must also match here + default: throw "FAIL"; + } +} diff --git a/js/src/jit-test/tests/basic/testDoubleZeroInSwitch2.js b/js/src/jit-test/tests/basic/testDoubleZeroInSwitch2.js new file mode 100644 index 0000000..86707aa --- /dev/null +++ b/js/src/jit-test/tests/basic/testDoubleZeroInSwitch2.js @@ -0,0 +1,9 @@ +var arr = Float32Array(1); +arr[0] = 15; +var a = arr[0]; +assertEq(a, 15); +switch (a) { + case 15: break; + default: throw "FAIL"; +} + diff --git a/js/src/jit-test/tests/basic/testElemDec1.js b/js/src/jit-test/tests/basic/testElemDec1.js new file mode 100644 index 0000000..5c5f7a7 --- /dev/null +++ b/js/src/jit-test/tests/basic/testElemDec1.js @@ -0,0 +1,10 @@ +var obj = {p: 100}; +var name = "p"; +var a = []; +for (var i = 0; i < 10; i++) + a[i] = obj[name]--; +assertEq(a.join(','), '100,99,98,97,96,95,94,93,92,91'); +assertEq(obj.p, 90); + +checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1}); + diff --git a/js/src/jit-test/tests/basic/testElemDec2.js b/js/src/jit-test/tests/basic/testElemDec2.js new file mode 100644 index 0000000..1388d39 --- /dev/null +++ b/js/src/jit-test/tests/basic/testElemDec2.js @@ -0,0 +1,7 @@ +var obj = {s: ""}; +var name = "s"; +for (var i = 0; i <= RECORDLOOP + 5; i++) + if (i > RECORDLOOP) + obj[name]--; // first recording changes obj.s from string to number +assertEq(obj.s, -5); + diff --git a/js/src/jit-test/tests/basic/testElemInc1.js b/js/src/jit-test/tests/basic/testElemInc1.js new file mode 100644 index 0000000..84a0c74 --- /dev/null +++ b/js/src/jit-test/tests/basic/testElemInc1.js @@ -0,0 +1,10 @@ +var obj = {p: 100}; +var name = "p"; +var a = []; +for (var i = 0; i < 10; i++) + a[i] = obj[name]++; +assertEq(a.join(','), '100,101,102,103,104,105,106,107,108,109'); +assertEq(obj.p, 110); + +checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1}); + diff --git a/js/src/jit-test/tests/basic/testElemInc2.js b/js/src/jit-test/tests/basic/testElemInc2.js new file mode 100644 index 0000000..9a1712d --- /dev/null +++ b/js/src/jit-test/tests/basic/testElemInc2.js @@ -0,0 +1,7 @@ +var obj = {s: ""}; +var name = "s"; +for (var i = 0; i <= RECORDLOOP + 5; i++) + if (i > RECORDLOOP) + obj[name]++; // first recording changes obj.s from string to number +assertEq(obj.s, 5); + diff --git a/js/src/jit-test/tests/basic/testEliminatedGuardWithinAnchor.js b/js/src/jit-test/tests/basic/testEliminatedGuardWithinAnchor.js new file mode 100644 index 0000000..cc80e77 --- /dev/null +++ b/js/src/jit-test/tests/basic/testEliminatedGuardWithinAnchor.js @@ -0,0 +1,12 @@ +function testEliminatedGuardWithinAnchor() { + for (let i = 0; i < 5; ++i) { i / (i * i); } + return "ok"; +} + +assertEq(testEliminatedGuardWithinAnchor(), "ok"); + +if (HAVE_TM) { + checkStats({ + sideExitIntoInterpreter: (jitstats.archIsARM ? 1 : 3) + }); +} diff --git a/js/src/jit-test/tests/basic/testEqFalseEmptyString.js b/js/src/jit-test/tests/basic/testEqFalseEmptyString.js new file mode 100644 index 0000000..6fd70f1 --- /dev/null +++ b/js/src/jit-test/tests/basic/testEqFalseEmptyString.js @@ -0,0 +1,6 @@ +function testEqFalseEmptyString() { + var x = []; + for (var i=0;i<5;++i) x.push(false == ""); + return x.join(","); +} +assertEq(testEqFalseEmptyString(), "true,true,true,true,true"); diff --git a/js/src/jit-test/tests/basic/testErrorReportIn_getPrototypeOf.js b/js/src/jit-test/tests/basic/testErrorReportIn_getPrototypeOf.js new file mode 100644 index 0000000..e557119 --- /dev/null +++ b/js/src/jit-test/tests/basic/testErrorReportIn_getPrototypeOf.js @@ -0,0 +1,9 @@ +actual = ""; +expect = "TypeError: \"kittens\" is not an object"; +try { + Object.getPrototypeOf.apply(null, ["kittens",4,3]) +} catch (e) { + actual = "" + e; +} + +assertEq(actual, expect); diff --git a/js/src/jit-test/tests/basic/testEvalCalledFromWatchOverSetter.js b/js/src/jit-test/tests/basic/testEvalCalledFromWatchOverSetter.js new file mode 100644 index 0000000..bcd60fd --- /dev/null +++ b/js/src/jit-test/tests/basic/testEvalCalledFromWatchOverSetter.js @@ -0,0 +1,3 @@ +this.__defineSetter__("x", function(){}); +this.watch("x", eval); +x = 0; diff --git a/js/src/jit-test/tests/basic/testEvalInFunctionCallee.js b/js/src/jit-test/tests/basic/testEvalInFunctionCallee.js new file mode 100644 index 0000000..81f757f --- /dev/null +++ b/js/src/jit-test/tests/basic/testEvalInFunctionCallee.js @@ -0,0 +1,4 @@ +function f(x,y) { + eval("assertEq(arguments.callee, f)"); +} +f(1,2); diff --git a/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-2.js b/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-2.js new file mode 100644 index 0000000..b6bc067 --- /dev/null +++ b/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-2.js @@ -0,0 +1,8 @@ +function f() { + var a = [], i, N = HOTLOOP + 2; + for (i = 0; i < N; i++) + a[i] = {m: i, m: function() { return 0; }}; + assertEq(a[N - 2].m === a[N - 1].m, false); +} +f(); +f(); diff --git a/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-3.js b/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-3.js new file mode 100644 index 0000000..8566d1c --- /dev/null +++ b/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-3.js @@ -0,0 +1,15 @@ +function f() { + var a = [], i, N = HOTLOOP + 2; + for (i = 0; i < N; i++) { + a[i] = {}; + a[i].m = function() { return 0; }; + a[i].m = function() { return 1; }; + } + assertEq(a[N - 2].m === a[N - 1].m, false); + for (i = 0; i < N; i++) { + var f = a[i].m; + assertEq(f(), 1); + } +} +f(); +f(); diff --git a/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-4.js b/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-4.js new file mode 100644 index 0000000..1d87487 --- /dev/null +++ b/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt-4.js @@ -0,0 +1,12 @@ +function f() { + var a = [], i, N = HOTLOOP + 2; + for (i = 0; i < N; i++) + a[i] = {m: function() { return 0; }, m: function() { return 1; }}; + assertEq(a[N - 2].m === a[N - 1].m, false); + for (i = 0; i < N; i++) { + var f = a[i].m; + assertEq(f(), 1); + } +} +f(); +f(); diff --git a/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt.js b/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt.js new file mode 100644 index 0000000..fd59398 --- /dev/null +++ b/js/src/jit-test/tests/basic/testExistingPropToJoinedMethodAttempt.js @@ -0,0 +1,10 @@ +function f() { + var a = [], i, N = HOTLOOP + 2; + for (i = 0; i < N; i++) + a[i] = {m: i}; + for (i = 0; i < N; i++) + a[i].m = function() { return 0; }; + assertEq(a[N - 2].m === a[N - 1].m, false); +} +f(); +f(); diff --git a/js/src/jit-test/tests/basic/testFewerGlobalsInInnerTree.js b/js/src/jit-test/tests/basic/testFewerGlobalsInInnerTree.js new file mode 100644 index 0000000..25a4a52 --- /dev/null +++ b/js/src/jit-test/tests/basic/testFewerGlobalsInInnerTree.js @@ -0,0 +1,14 @@ +function testFewerGlobalsInInnerTree() { + for each (a in [new Number(1), new Number(1), {}, {}, new Number(1)]) { + for each (b in [2, "", 2, "", "", ""]) { + for each (c in [{}, {}, 3, 3, 3, 3, {}, {}]) { + 4 + a; + } + } + } + delete a; + delete b; + delete c; + return "ok"; +} +assertEq(testFewerGlobalsInInnerTree(), "ok"); diff --git a/js/src/jit-test/tests/basic/testFloatArrayIndex.js b/js/src/jit-test/tests/basic/testFloatArrayIndex.js new file mode 100644 index 0000000..5648247 --- /dev/null +++ b/js/src/jit-test/tests/basic/testFloatArrayIndex.js @@ -0,0 +1,9 @@ +function testFloatArrayIndex() { + var a = []; + for (var i = 0; i < 10; ++i) { + a[3] = 5; + a[3.5] = 7; + } + return a[3] + "," + a[3.5]; +} +assertEq(testFloatArrayIndex(), "5,7"); diff --git a/js/src/jit-test/tests/basic/testForEach.js b/js/src/jit-test/tests/basic/testForEach.js new file mode 100644 index 0000000..7646355 --- /dev/null +++ b/js/src/jit-test/tests/basic/testForEach.js @@ -0,0 +1,11 @@ +function testForEach() { + var r; + var a = ["zero", "one", "two", "three"]; + for (var i = 0; i < RUNLOOP; i++) { + r = ""; + for each (var s in a) + r += s + " "; + } + return r; +} +assertEq(testForEach(), "zero one two three "); diff --git a/js/src/jit-test/tests/basic/testForInLoopChangeIteratorType.js b/js/src/jit-test/tests/basic/testForInLoopChangeIteratorType.js new file mode 100644 index 0000000..0efce83 --- /dev/null +++ b/js/src/jit-test/tests/basic/testForInLoopChangeIteratorType.js @@ -0,0 +1,11 @@ +function testForInLoopChangeIteratorType() { + for(y in [0,1,2]) y = NaN; + (function(){ + [].__proto__.u = void 0; + for (let y in [5,6,7,8]) + y = NaN; + delete [].__proto__.u; + })() + return "ok"; +} +assertEq(testForInLoopChangeIteratorType(), "ok"); diff --git a/js/src/jit-test/tests/basic/testFunctionIdentityChange.js b/js/src/jit-test/tests/basic/testFunctionIdentityChange.js new file mode 100644 index 0000000..bb0830c --- /dev/null +++ b/js/src/jit-test/tests/basic/testFunctionIdentityChange.js @@ -0,0 +1,21 @@ +function testFunctionIdentityChange() +{ + function a() {} + function b() {} + + var o = { a: a, b: b }; + + for (var prop in o) + { + for (var i = 0; i < 1000; i++) + o[prop](); + } + + return true; +} +assertEq(testFunctionIdentityChange(), true); +checkStats({ + recorderStarted: 2, + traceCompleted: 2, + sideExitIntoInterpreter: 3 +}); diff --git a/js/src/jit-test/tests/basic/testGCWhileRecording.js b/js/src/jit-test/tests/basic/testGCWhileRecording.js new file mode 100644 index 0000000..2dffbb2 --- /dev/null +++ b/js/src/jit-test/tests/basic/testGCWhileRecording.js @@ -0,0 +1,12 @@ +function test() { + for (let z = 0; z < 4; ++z) { + uneval({ x: 9 }); + gc() + } + return "pass"; +} +assertEq(test(), "pass"); +checkStats({ + recorderStarted: 1, + recorderAborted: 0 +}); diff --git a/js/src/jit-test/tests/basic/testGeneratorDeepBail.js b/js/src/jit-test/tests/basic/testGeneratorDeepBail.js new file mode 100644 index 0000000..50c62b0 --- /dev/null +++ b/js/src/jit-test/tests/basic/testGeneratorDeepBail.js @@ -0,0 +1,11 @@ +function testGeneratorDeepBail() { + function g() { yield 2; } + var iterables = [[1], [], [], [], g()]; + + var total = 0; + for (let i = 0; i < iterables.length; i++) + for each (let j in iterables[i]) + total += j; + return total; +} +assertEq(testGeneratorDeepBail(), 3); diff --git a/js/src/jit-test/tests/basic/testGetCallObj.js b/js/src/jit-test/tests/basic/testGetCallObj.js new file mode 100644 index 0000000..6c0902a --- /dev/null +++ b/js/src/jit-test/tests/basic/testGetCallObj.js @@ -0,0 +1,11 @@ +function testGetCallObjInlined(i) { + if (i > 7) eval("1"); + return 1; +} + +function testGetCallObj() { + for (var i = 0; i < 10; ++i) + testGetCallObjInlined(i); + return "ok"; +} +assertEq(testGetCallObj(), "ok"); diff --git a/js/src/jit-test/tests/basic/testGetThis.js b/js/src/jit-test/tests/basic/testGetThis.js new file mode 100644 index 0000000..3c2546a --- /dev/null +++ b/js/src/jit-test/tests/basic/testGetThis.js @@ -0,0 +1,7 @@ +function testGetThis() { + for (var i = 0; i < 3; ++i) { + (function() { return this; })(); + } + return "ok"; +} +assertEq(testGetThis(), "ok"); diff --git a/js/src/jit-test/tests/basic/testGlobalAsProto.js b/js/src/jit-test/tests/basic/testGlobalAsProto.js new file mode 100644 index 0000000..1ba2455 --- /dev/null +++ b/js/src/jit-test/tests/basic/testGlobalAsProto.js @@ -0,0 +1,3 @@ +var b = Object.create(this); +for (var i = 0; i < 9; i++) + assertEq(b.i, i); diff --git a/js/src/jit-test/tests/basic/testGlobalMultitrees1.js b/js/src/jit-test/tests/basic/testGlobalMultitrees1.js new file mode 100644 index 0000000..108134d --- /dev/null +++ b/js/src/jit-test/tests/basic/testGlobalMultitrees1.js @@ -0,0 +1,11 @@ +//test no multitrees assert +function testGlobalMultitrees1() { + (function() { + for (var j = 0; j < 4; ++j) { + for each (e in ['A', 1, 'A']) { + } + } + })(); + return true; +} +assertEq(testGlobalMultitrees1(), true); diff --git a/js/src/jit-test/tests/basic/testGlobalOptimize-2.js b/js/src/jit-test/tests/basic/testGlobalOptimize-2.js new file mode 100644 index 0000000..53b3bff --- /dev/null +++ b/js/src/jit-test/tests/basic/testGlobalOptimize-2.js @@ -0,0 +1,9 @@ +var test; +{ + let (a = 5) { + with ({a: 2}) { + test = (function () { return a; })(); + } + } +} +assertEq(test, 2); diff --git a/js/src/jit-test/tests/basic/testGlobalOptimize-3.js b/js/src/jit-test/tests/basic/testGlobalOptimize-3.js new file mode 100644 index 0000000..020138b --- /dev/null +++ b/js/src/jit-test/tests/basic/testGlobalOptimize-3.js @@ -0,0 +1,9 @@ +var test; +{ + with ({a: 2}) { + let (a = 5) { + test = (function () { return a; })(); + } + } +} +assertEq(test, 5); diff --git a/js/src/jit-test/tests/basic/testGlobalOptimize-4.js b/js/src/jit-test/tests/basic/testGlobalOptimize-4.js new file mode 100644 index 0000000..3075421 --- /dev/null +++ b/js/src/jit-test/tests/basic/testGlobalOptimize-4.js @@ -0,0 +1,8 @@ +var test; +{ + with ({a: 2}) { + test = (function () { return a; })(); + } + let a = 5; +} +assertEq(test, 2); diff --git a/js/src/jit-test/tests/basic/testGlobalOptimize-5.js b/js/src/jit-test/tests/basic/testGlobalOptimize-5.js new file mode 100644 index 0000000..20c3bab --- /dev/null +++ b/js/src/jit-test/tests/basic/testGlobalOptimize-5.js @@ -0,0 +1,10 @@ +var test; +function f() { + let (a = 5) { + with ({a: 2}) { + test = (function () { return a;} )(); + } + } +} +f(); +assertEq(test, 2); diff --git a/js/src/jit-test/tests/basic/testGlobalOptimize-6.js b/js/src/jit-test/tests/basic/testGlobalOptimize-6.js new file mode 100644 index 0000000..fe3174a --- /dev/null +++ b/js/src/jit-test/tests/basic/testGlobalOptimize-6.js @@ -0,0 +1,10 @@ +var test; +function f() { + with ({a: 2}) { + let (a = 5) { + test = (function () { return a; })(); + } + } +} +f(); +assertEq(test, 5); diff --git a/js/src/jit-test/tests/basic/testGlobalProtoAccess.js b/js/src/jit-test/tests/basic/testGlobalProtoAccess.js new file mode 100644 index 0000000..97f1612 --- /dev/null +++ b/js/src/jit-test/tests/basic/testGlobalProtoAccess.js @@ -0,0 +1,5 @@ +function testGlobalProtoAccess() { + return "ok"; +} +this.__proto__.a = 3; for (var j = 0; j < 4; ++j) { [a]; } +assertEq(testGlobalProtoAccess(), "ok"); diff --git a/js/src/jit-test/tests/basic/testGlobalShapeChangeAfterDeepBail.js b/js/src/jit-test/tests/basic/testGlobalShapeChangeAfterDeepBail.js new file mode 100644 index 0000000..0839b37 --- /dev/null +++ b/js/src/jit-test/tests/basic/testGlobalShapeChangeAfterDeepBail.js @@ -0,0 +1,15 @@ +// Complicated whitebox test for bug 487845. +function testGlobalShapeChangeAfterDeepBail() { + function f(name) { + this[name] = 1; // may change global shape + for (var i = 0; i < 4; i++) + ; // MonitorLoopEdge eventually triggers assertion + } + + // When i==3, deep-bail, then change global shape enough times to exhaust + // the array of GlobalStates. + var arr = [[], [], [], ["bug0", "bug1", "bug2", "bug3", "bug4"]]; + for (var i = 0; i < arr.length; i++) + arr[i].forEach(f); +} +testGlobalShapeChangeAfterDeepBail(); diff --git a/js/src/jit-test/tests/basic/testGroupAssignment.js b/js/src/jit-test/tests/basic/testGroupAssignment.js new file mode 100644 index 0000000..11ef77a --- /dev/null +++ b/js/src/jit-test/tests/basic/testGroupAssignment.js @@ -0,0 +1,22 @@ +assertEq( + (function () { + var arr = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 ]; + + for (var i = 0; i < 4; ++i) { + var src = i * 8; + var dst = i * 8 + 7; + for (var j = 0; j < 4; ++j) { + [arr[dst--], arr[src++]] = [arr[src], arr[dst]]; + } + } + return arr; + })().toSource(), + "[7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 32]"); + +checkStats({ + recorderStarted: 2, + traceCompleted: 2, + sideExitIntoInterpreter: 3, + traceTriggered: 3 +}); diff --git a/js/src/jit-test/tests/basic/testGrowDenseArray.js b/js/src/jit-test/tests/basic/testGrowDenseArray.js new file mode 100644 index 0000000..810c12f --- /dev/null +++ b/js/src/jit-test/tests/basic/testGrowDenseArray.js @@ -0,0 +1,7 @@ +function testGrowDenseArray() { + var a = new Array(); + for (var i = 0; i < 10; ++i) + a[i] |= 5; + return a.join(","); +} +assertEq(testGrowDenseArray(), "5,5,5,5,5,5,5,5,5,5"); diff --git a/js/src/jit-test/tests/basic/testGuardCalleeSneakAttack.js b/js/src/jit-test/tests/basic/testGuardCalleeSneakAttack.js new file mode 100644 index 0000000..37af1a2 --- /dev/null +++ b/js/src/jit-test/tests/basic/testGuardCalleeSneakAttack.js @@ -0,0 +1,38 @@ +function loop(f, expected) { + // This is the loop that breaks us. + // At record time, f's parent is a Call object with no fp. + // At second execute time, it is a Call object with fp, + // and all the Call object's dslots are still JSVAL_VOID. + for (var i = 0; i < 9; i++) + assertEq(f(), expected); +} + +function C(bad) { + var x = bad; + function f() { + return x; // We trick TR::callProp() into emitting code that gets + // JSVAL_VOID (from the Call object's dslots) + // rather than the actual value (true or false). + } + this.m = f; + return f; +} + +var obj = { + set m(f) { + if (f()) // Call once to resolve x on the Call object, + // for shape consistency. Otherwise loop gets + // recorded twice. + loop(f, true); + } +}; + +loop(C.call(obj, false), false); +C.call(obj, true); + +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceCompleted: 2, + traceTriggered: 4 +}); diff --git a/js/src/jit-test/tests/basic/testGuardCalleeSneakAttack2.js b/js/src/jit-test/tests/basic/testGuardCalleeSneakAttack2.js new file mode 100644 index 0000000..6281fc6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testGuardCalleeSneakAttack2.js @@ -0,0 +1,39 @@ +function loop(f, expected) { + // This is the loop that breaks us. + // At record time, f's parent is a Call object with no fp. + // At second execute time, it is a Call object with fp, + // and all the Call object's dslots are still JSVAL_VOID. + for (var i = 0; i < 9; i++) + assertEq(f(), expected); +} + +function C(bad) { + var x = bad; + function f() { + return x; // We trick TR::callProp() into emitting code that gets + // JSVAL_VOID (from the Call object's dslots) + // rather than the actual value (true or false). + } + if (bad) + void (f + "a!"); + return f; +} + +var obj = { +}; + +// Warm up and trace with C's Call object entrained but its stack frame gone. +loop(C.call(obj, false), false); + +// Sneaky access to f via a prototype method called implicitly by operator +. +Function.prototype.toString = function () { loop(this, true); return "hah"; }; + +// Fail hard if we don't handle the implicit call out of C to F.p.toString. +C.call(obj, true); + +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceCompleted: 2, + traceTriggered: 4 +}); diff --git a/js/src/jit-test/tests/basic/testHOTLOOPCorrectness.js b/js/src/jit-test/tests/basic/testHOTLOOPCorrectness.js new file mode 100644 index 0000000..b295c69 --- /dev/null +++ b/js/src/jit-test/tests/basic/testHOTLOOPCorrectness.js @@ -0,0 +1,14 @@ +function testHOTLOOPCorrectness() { + var b = 0; + for (var i = 0; i < HOTLOOP; ++i) + ++b; + return b; +} +// Change the global shape right before doing the test +this.testHOTLOOPCorrectnessVar = 1; +assertEq(testHOTLOOPCorrectness(), HOTLOOP); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceTriggered: 0 +}); diff --git a/js/src/jit-test/tests/basic/testHOTLOOPSize.js b/js/src/jit-test/tests/basic/testHOTLOOPSize.js new file mode 100644 index 0000000..d498592 --- /dev/null +++ b/js/src/jit-test/tests/basic/testHOTLOOPSize.js @@ -0,0 +1,4 @@ +function testHOTLOOPSize() { + return HOTLOOP > 1; +} +assertEq(testHOTLOOPSize(), true); diff --git a/js/src/jit-test/tests/basic/testHeavy.js b/js/src/jit-test/tests/basic/testHeavy.js new file mode 100644 index 0000000..2ef1ce6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testHeavy.js @@ -0,0 +1,14 @@ +function heavyFn1(i) { + if (i == 3) { + var x = 3; + return [0, i].map(function (i) i + x); + } + return []; +} + +function testHeavy() { + for (var i = 0; i <= 3; i++) + heavyFn1(i); +} + +testHeavy(); diff --git a/js/src/jit-test/tests/basic/testHeavy2.js b/js/src/jit-test/tests/basic/testHeavy2.js new file mode 100644 index 0000000..d7abbb0 --- /dev/null +++ b/js/src/jit-test/tests/basic/testHeavy2.js @@ -0,0 +1,20 @@ +function heavyFn1(i) { + if (i == 3) { + var x = 3; + return [0, i].map(function (i) i + x); + } + return []; +} + +function heavyFn2(i) { + if (i < 1000) + return heavyFn1(i); + return function () i; +} + +function testHeavy2() { + for (var i = 0; i <= 3; i++) + heavyFn2(i); +} + +testHeavy2(); diff --git a/js/src/jit-test/tests/basic/testHoleInDenseArray.js b/js/src/jit-test/tests/basic/testHoleInDenseArray.js new file mode 100644 index 0000000..ba7a2c0 --- /dev/null +++ b/js/src/jit-test/tests/basic/testHoleInDenseArray.js @@ -0,0 +1,18 @@ +var s; + +function f(i) { + if (i > 4) /* side exit when arr[i] changes from bool to undefined (via a hole) */ + assertEq(s, undefined); + else + assertEq(s, false); + return 1; +} + +/* trailing 'true' ensures array has capacity >= 10 */ +var arr = [ false, false, false, false, false, , , , , , true ]; + +for (var i = 0; i < 10; ++i) { + (s = arr[i]) + f(i); +} + +checkStats({ traceTriggered: 2, sideExitIntoInterpreter: 2 }) diff --git a/js/src/jit-test/tests/basic/testHolePushing.js b/js/src/jit-test/tests/basic/testHolePushing.js new file mode 100644 index 0000000..a231613 --- /dev/null +++ b/js/src/jit-test/tests/basic/testHolePushing.js @@ -0,0 +1,13 @@ +function testHolePushing() { + var a = ["foobar", "baz"]; + for (var i = 0; i < 5; i++) + a = [, "overwritten", "new"]; + var s = "["; + for (i = 0; i < a.length; i++) { + s += (i in a) ? a[i] : ""; + if (i != a.length - 1) + s += ","; + } + return s + "], " + (0 in a); +} +assertEq(testHolePushing(), "[,overwritten,new], false"); diff --git a/js/src/jit-test/tests/basic/testHolesAndIndexPropertiesOnThePrototype.js b/js/src/jit-test/tests/basic/testHolesAndIndexPropertiesOnThePrototype.js new file mode 100644 index 0000000..1af2506 --- /dev/null +++ b/js/src/jit-test/tests/basic/testHolesAndIndexPropertiesOnThePrototype.js @@ -0,0 +1,29 @@ +function f(x,y,z) { + return x + y + z; +} + +Array.prototype[1] = 10; + +function g() { + var arr = [1, ,3,4,5,6]; + + for (var i = 0; i < 10; ++i) { + assertEq(f.apply(null, arr), 14); + } +} +g(); + +Object.prototype[1] = 20; + +function h() { + delete arguments[1]; + return f.apply(null, arguments); +} +assertEq(h(1,2,3), 24); + +function i() { + o = arguments; + delete o[1]; + return f.apply(null, o); +} +assertEq(i(1,2,3), 24); diff --git a/js/src/jit-test/tests/basic/testINITELEM.js b/js/src/jit-test/tests/basic/testINITELEM.js new file mode 100644 index 0000000..2d7567a --- /dev/null +++ b/js/src/jit-test/tests/basic/testINITELEM.js @@ -0,0 +1,8 @@ +function testINITELEM() +{ + var x; + for (var i = 0; i < 10; ++i) + x = { 0: 5, 1: 5 }; + return x[0] + x[1]; +} +assertEq(testINITELEM(), 10); diff --git a/js/src/jit-test/tests/basic/testIn.js b/js/src/jit-test/tests/basic/testIn.js new file mode 100644 index 0000000..aeadab3 --- /dev/null +++ b/js/src/jit-test/tests/basic/testIn.js @@ -0,0 +1,19 @@ +function testIn() { + var array = [3]; + var obj = { "-1": 5, "1.7": 3, "foo": 5, "1": 7 }; + var a = []; + for (let j = 0; j < 5; ++j) { + a.push("0" in array); + a.push(-1 in obj); + a.push(1.7 in obj); + a.push("foo" in obj); + a.push(1 in obj); + a.push("1" in array); + a.push(-2 in obj); + a.push(2.7 in obj); + a.push("bar" in obj); + a.push(2 in obj); + } + return a.join(","); +} +assertEq(testIn(), "true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false"); diff --git a/js/src/jit-test/tests/basic/testIncDec.js b/js/src/jit-test/tests/basic/testIncDec.js new file mode 100644 index 0000000..89b5335 --- /dev/null +++ b/js/src/jit-test/tests/basic/testIncDec.js @@ -0,0 +1,19 @@ +function testIncDec2(ii) { + var x = []; + for (let j=0;j<5;++j) { + ii=j; + jj=j; + var kk=j; + x.push(ii--); + x.push(jj--); + x.push(kk--); + x.push(++ii); + x.push(++jj); + x.push(++kk); + } + return x.join(","); +} +function testIncDec() { + return testIncDec2(0); +} +assertEq(testIncDec(), "0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4"); diff --git a/js/src/jit-test/tests/basic/testIncDecReadOnly.js b/js/src/jit-test/tests/basic/testIncDecReadOnly.js new file mode 100644 index 0000000..5ff23b2 --- /dev/null +++ b/js/src/jit-test/tests/basic/testIncDecReadOnly.js @@ -0,0 +1,22 @@ +var r; +Object.defineProperty(this, "x", {value: 0, writable: false}); + +for (var a = 0; a < 10; ++a) + r = ++x; +assertEq(x, 0); +assertEq(r, 1); + +for (var a = 0; a < 10; ++a) + r = --x; +assertEq(x, 0); +assertEq(r, -1); + +for (var a = 0; a < 10; ++a) + r = x++; +assertEq(x, 0); +assertEq(r, 0); + +for (var a = 0; a < 10; ++a) + r = x--; +assertEq(x, 0); +assertEq(r, 0); diff --git a/js/src/jit-test/tests/basic/testIncElem1.js b/js/src/jit-test/tests/basic/testIncElem1.js new file mode 100644 index 0000000..2f8ddf6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testIncElem1.js @@ -0,0 +1,10 @@ +var obj = {p: 100}; +var name = "p"; +var a = []; +for (var i = 0; i < 10; i++) + a[i] = ++obj[name]; +assertEq(a.join(','), '101,102,103,104,105,106,107,108,109,110'); +assertEq(obj.p, 110); + +checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1}); + diff --git a/js/src/jit-test/tests/basic/testIncElem2.js b/js/src/jit-test/tests/basic/testIncElem2.js new file mode 100644 index 0000000..93ae189 --- /dev/null +++ b/js/src/jit-test/tests/basic/testIncElem2.js @@ -0,0 +1,11 @@ +var obj = {s: ""}; +var name = "s"; +var a = []; +for (var i = 0; i <= RECORDLOOP + 5; i++) { + a[i] = 'x'; + if (i > RECORDLOOP) + a[i] = ++obj[name]; // first recording changes obj.s from string to number +} +assertEq(a.join(','), Array(RECORDLOOP + 2).join('x,') + '1,2,3,4,5'); +assertEq(obj.s, 5); + diff --git a/js/src/jit-test/tests/basic/testIncElem3.js b/js/src/jit-test/tests/basic/testIncElem3.js new file mode 100644 index 0000000..308fd68 --- /dev/null +++ b/js/src/jit-test/tests/basic/testIncElem3.js @@ -0,0 +1,6 @@ +var arr; +for (var j = 0; j < 2 * RUNLOOP; ++j ) { + arr = [,]; + ++arr[0]; +} +assertEq(isNaN(arr[0]), true); diff --git a/js/src/jit-test/tests/basic/testInitDictionary.js b/js/src/jit-test/tests/basic/testInitDictionary.js new file mode 100644 index 0000000..d83ea8d --- /dev/null +++ b/js/src/jit-test/tests/basic/testInitDictionary.js @@ -0,0 +1,51 @@ + +var shapes = {}; + +function stringify(a) { + assertEq(shapes[shapeOf(a)], undefined); + shapes[shapeOf(a)] = 1; + var b = ""; + for (var c in a) { + b += c + ":"; + if (typeof a[c] == "function") + b += "function,"; + else + b += a[c] + ","; + } + return b; +} + +function test1() { + return stringify({a: 0, b: 1, a: function() {} }); +} +for (var i = 0; i < 3; i++) + assertEq(test1(), "a:function,b:1,"); + +// This does not cause the object to go to dictionary mode, unlike the above. +function test2() { + return stringify({a: 0, b: 1, a: 2, b: 3}); +} +assertEq(test2(), "a:2,b:3,"); + +function test3() { + return stringify({ + aa:0,ab:1,ac:2,ad:3,ae:4,af:5,ag:6,ah:7,ai:8,aj:9, + ba:0,bb:1,bc:2,bd:3,be:4,bf:5,bg:6,bh:7,bi:8,bj:9, + ca:0,cb:1,cc:2,cd:3,ce:4,cf:5,cg:6,ch:7,ci:8,cj:9, + da:0,db:1,dc:2,dd:3,de:4,df:5,dg:6,dh:7,di:8,dj:9, + ea:0,eb:1,ec:2,ed:3,ee:4,ef:5,eg:6,eh:7,ei:8,ej:9, + fa:0,fb:1,fc:2,fd:3,fe:4,ff:5,fg:6,fh:7,fi:8,fj:9, + ga:0,gb:1,gc:2,gd:3,ge:4,gf:5,gg:6,gh:7,gi:8,gj:9, + ha:0,hb:1,hc:2,hd:3,he:4,hf:5,hg:6,hh:7,hi:8,hj:9, + ia:0,ib:1,ic:2,id:3,ie:4,if:5,ig:6,ih:7,ii:8,ij:9, + ja:0,jb:1,jc:2,jd:3,je:4,jf:5,jg:6,jh:7,ji:8,jj:9, + ka:0,kb:1,kc:2,kd:3,ke:4,kf:5,kg:6,kh:7,ki:8,kj:9, + la:0,lb:1,lc:2,ld:3,le:4,lf:5,lg:6,lh:7,li:8,lj:9, + ma:0,mb:1,mc:2,md:3,me:4,mf:5,mg:6,mh:7,mi:8,mj:9, + na:0,nb:1,nc:2,nd:3,ne:4,nf:5,ng:6,nh:7,ni:8,nj:9, + oa:0,ob:1,oc:2,od:3,oe:4,of:5,og:6,oh:7,oi:8,oj:9, + pa:0,pb:1,pc:2,pd:3,pe:4,pf:5,pg:6,ph:7,pi:8,pj:9, + }); +} +for (var i = 0; i < HOTLOOP + 2; i++) + assertEq(test3(), "aa:0,ab:1,ac:2,ad:3,ae:4,af:5,ag:6,ah:7,ai:8,aj:9,ba:0,bb:1,bc:2,bd:3,be:4,bf:5,bg:6,bh:7,bi:8,bj:9,ca:0,cb:1,cc:2,cd:3,ce:4,cf:5,cg:6,ch:7,ci:8,cj:9,da:0,db:1,dc:2,dd:3,de:4,df:5,dg:6,dh:7,di:8,dj:9,ea:0,eb:1,ec:2,ed:3,ee:4,ef:5,eg:6,eh:7,ei:8,ej:9,fa:0,fb:1,fc:2,fd:3,fe:4,ff:5,fg:6,fh:7,fi:8,fj:9,ga:0,gb:1,gc:2,gd:3,ge:4,gf:5,gg:6,gh:7,gi:8,gj:9,ha:0,hb:1,hc:2,hd:3,he:4,hf:5,hg:6,hh:7,hi:8,hj:9,ia:0,ib:1,ic:2,id:3,ie:4,if:5,ig:6,ih:7,ii:8,ij:9,ja:0,jb:1,jc:2,jd:3,je:4,jf:5,jg:6,jh:7,ji:8,jj:9,ka:0,kb:1,kc:2,kd:3,ke:4,kf:5,kg:6,kh:7,ki:8,kj:9,la:0,lb:1,lc:2,ld:3,le:4,lf:5,lg:6,lh:7,li:8,lj:9,ma:0,mb:1,mc:2,md:3,me:4,mf:5,mg:6,mh:7,mi:8,mj:9,na:0,nb:1,nc:2,nd:3,ne:4,nf:5,ng:6,nh:7,ni:8,nj:9,oa:0,ob:1,oc:2,od:3,oe:4,of:5,og:6,oh:7,oi:8,oj:9,pa:0,pb:1,pc:2,pd:3,pe:4,pf:5,pg:6,ph:7,pi:8,pj:9,"); diff --git a/js/src/jit-test/tests/basic/testInitMethod.js b/js/src/jit-test/tests/basic/testInitMethod.js new file mode 100644 index 0000000..abd3f3e --- /dev/null +++ b/js/src/jit-test/tests/basic/testInitMethod.js @@ -0,0 +1,9 @@ +for (var i = 0; i < 9; i++) + x = {a: function() {}, b: function() {}}; + +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceCompleted: 1, + sideExitIntoInterpreter: 1 +}); diff --git a/js/src/jit-test/tests/basic/testInitPropOverMethod.js b/js/src/jit-test/tests/basic/testInitPropOverMethod.js new file mode 100644 index 0000000..8f808c4 --- /dev/null +++ b/js/src/jit-test/tests/basic/testInitPropOverMethod.js @@ -0,0 +1,9 @@ +for (var i = 0; i < HOTLOOP + 2; i++) + x = {a: function () { return 33; }, a: 4}; + +try { + result = x.a(); +} catch (exc) { + result = "threw " + exc.name; +} +assertEq(result, "threw TypeError"); diff --git a/js/src/jit-test/tests/basic/testInitPropWithIntName.js b/js/src/jit-test/tests/basic/testInitPropWithIntName.js new file mode 100644 index 0000000..7bfa4ce --- /dev/null +++ b/js/src/jit-test/tests/basic/testInitPropWithIntName.js @@ -0,0 +1,2 @@ +for (var j=0; j -2147483648); +} +assertEq(testIntUnderflow(), false); +checkStats({ + recorderStarted: 2, + recorderAborted: 0, + traceCompleted: 2, + traceTriggered: 2, +}); diff --git a/js/src/jit-test/tests/basic/testInterpreterReentery8.js b/js/src/jit-test/tests/basic/testInterpreterReentery8.js new file mode 100644 index 0000000..3996af4 --- /dev/null +++ b/js/src/jit-test/tests/basic/testInterpreterReentery8.js @@ -0,0 +1,6 @@ +// Bug 462027 comment 54. +function testInterpreterReentery8() { + var e = ; + for (var j = 0; j < 4; ++j) { +[e]; } +} +testInterpreterReentery8(); diff --git a/js/src/jit-test/tests/basic/testInterpreterReentry.js b/js/src/jit-test/tests/basic/testInterpreterReentry.js new file mode 100644 index 0000000..d820b23 --- /dev/null +++ b/js/src/jit-test/tests/basic/testInterpreterReentry.js @@ -0,0 +1,6 @@ +function testInterpreterReentry() { + this.__defineSetter__('x', function(){}) + for (var j = 0; j < 5; ++j) { x = 3; } + return 1; +} +assertEq(testInterpreterReentry(), 1); diff --git a/js/src/jit-test/tests/basic/testInterpreterReentry2.js b/js/src/jit-test/tests/basic/testInterpreterReentry2.js new file mode 100644 index 0000000..e8dd672 --- /dev/null +++ b/js/src/jit-test/tests/basic/testInterpreterReentry2.js @@ -0,0 +1,11 @@ +function testInterpreterReentry2() { + var a = false; + var b = {}; + var c = false; + var d = {}; + this.__defineGetter__('e', function(){}); + for (let f in this) print(f); + [1 for each (g in this) for each (h in [])] + return 1; +} +assertEq(testInterpreterReentry2(), 1); diff --git a/js/src/jit-test/tests/basic/testInterpreterReentry3.js b/js/src/jit-test/tests/basic/testInterpreterReentry3.js new file mode 100644 index 0000000..1728272 --- /dev/null +++ b/js/src/jit-test/tests/basic/testInterpreterReentry3.js @@ -0,0 +1,7 @@ +function testInterpreterReentry3() { + for (let i=0;i<5;++i) this["y" + i] = function(){}; + this.__defineGetter__('e', function (x2) { yield; }); + [1 for each (a in this) for (b in {})]; + return 1; +} +assertEq(testInterpreterReentry3(), 1); diff --git a/js/src/jit-test/tests/basic/testInterpreterReentry4.js b/js/src/jit-test/tests/basic/testInterpreterReentry4.js new file mode 100644 index 0000000..52339e3 --- /dev/null +++ b/js/src/jit-test/tests/basic/testInterpreterReentry4.js @@ -0,0 +1,6 @@ +function testInterpreterReentry4() { + var obj = {a:1, b:1, c:1, d:1, get e() 1000 }; + for (var p in obj) + obj[p]; +} +testInterpreterReentry4(); diff --git a/js/src/jit-test/tests/basic/testInterpreterReentry5.js b/js/src/jit-test/tests/basic/testInterpreterReentry5.js new file mode 100644 index 0000000..1652d09 --- /dev/null +++ b/js/src/jit-test/tests/basic/testInterpreterReentry5.js @@ -0,0 +1,9 @@ +function testInterpreterReentry5() { + var arr = [0, 1, 2, 3, 4]; + arr.__defineGetter__("4", function() 1000); + for (var i = 0; i < 5; i++) + arr[i]; + for (var p in arr) + arr[p]; +} +testInterpreterReentry5(); diff --git a/js/src/jit-test/tests/basic/testInterpreterReentry6.js b/js/src/jit-test/tests/basic/testInterpreterReentry6.js new file mode 100644 index 0000000..c5a6b28 --- /dev/null +++ b/js/src/jit-test/tests/basic/testInterpreterReentry6.js @@ -0,0 +1,7 @@ +function testInterpreterReentry6() { + var obj = {a:1, b:1, c:1, d:1, set e(x) { this._e = x; }}; + for (var p in obj) + obj[p] = "grue"; + return obj._e; +} +assertEq(testInterpreterReentry6(), "grue"); diff --git a/js/src/jit-test/tests/basic/testInterpreterReentry7.js b/js/src/jit-test/tests/basic/testInterpreterReentry7.js new file mode 100644 index 0000000..36b34c6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testInterpreterReentry7.js @@ -0,0 +1,11 @@ +function testInterpreterReentry7() { + var arr = [0, 1, 2, 3, 4]; + arr.__defineSetter__("4", function(x) { this._4 = x; }); + for (var i = 0; i < 5; i++) + arr[i] = "grue"; + var tmp = arr._4; + for (var p in arr) + arr[p] = "bleen"; + return tmp + " " + arr._4; +} +assertEq(testInterpreterReentry7(), "grue bleen"); diff --git a/js/src/jit-test/tests/basic/testInvalidCharCodeAt.js b/js/src/jit-test/tests/basic/testInvalidCharCodeAt.js new file mode 100644 index 0000000..748220f --- /dev/null +++ b/js/src/jit-test/tests/basic/testInvalidCharCodeAt.js @@ -0,0 +1,12 @@ +function doTestInvalidCharCodeAt(input) +{ + var q = ""; + for (var i = 0; i < 10; i++) + q += input.charCodeAt(i); + return q; +} +function testInvalidCharCodeAt() +{ + return doTestInvalidCharCodeAt(""); +} +assertEq(testInvalidCharCodeAt(), "NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN"); diff --git a/js/src/jit-test/tests/basic/testInvertNullAfterNegateNull.js b/js/src/jit-test/tests/basic/testInvertNullAfterNegateNull.js new file mode 100644 index 0000000..7e6a12b --- /dev/null +++ b/js/src/jit-test/tests/basic/testInvertNullAfterNegateNull.js @@ -0,0 +1,7 @@ +function testInvertNullAfterNegateNull() +{ + for (var i = 0; i < 5; i++) !null; + for (var i = 0; i < 5; i++) -null; + return "no assertion"; +} +assertEq(testInvertNullAfterNegateNull(), "no assertion"); diff --git a/js/src/jit-test/tests/basic/testIteratorReification.js b/js/src/jit-test/tests/basic/testIteratorReification.js new file mode 100644 index 0000000..8f89672 --- /dev/null +++ b/js/src/jit-test/tests/basic/testIteratorReification.js @@ -0,0 +1 @@ +for (b in evalcx('')) {} diff --git a/js/src/jit-test/tests/basic/testLambdaCtor.js b/js/src/jit-test/tests/basic/testLambdaCtor.js new file mode 100644 index 0000000..2284de9 --- /dev/null +++ b/js/src/jit-test/tests/basic/testLambdaCtor.js @@ -0,0 +1,14 @@ +function testLambdaCtor() { + var a = []; + for (var x = 0; x < RUNLOOP; ++x) { + var f = function(){}; + a[a.length] = new f; + } + + // This prints false until the upvar2 bug is fixed: + // print(a[HOTLOOP].__proto__ !== a[HOTLOOP-1].__proto__); + + // Assert that the last f was properly constructed. + return a[RUNLOOP-1].__proto__ === f.prototype; +} +assertEq(testLambdaCtor(), true); diff --git a/js/src/jit-test/tests/basic/testLambdaInitedVar.js b/js/src/jit-test/tests/basic/testLambdaInitedVar.js new file mode 100644 index 0000000..e37b4f9 --- /dev/null +++ b/js/src/jit-test/tests/basic/testLambdaInitedVar.js @@ -0,0 +1,8 @@ +function testLambdaInitedVar() { + var jQuery = function (a, b) { + return jQuery && jQuery.length; + } + return jQuery(); +} + +assertEq(testLambdaInitedVar(), 2); diff --git a/js/src/jit-test/tests/basic/testLengthInString.js b/js/src/jit-test/tests/basic/testLengthInString.js new file mode 100644 index 0000000..5950b50 --- /dev/null +++ b/js/src/jit-test/tests/basic/testLengthInString.js @@ -0,0 +1,12 @@ +function testLengthInString() +{ + var s = new String(); + var res = "length" in s; + for (var i = 0; i < 5; i++) + res = res && ("length" in s); + res = res && s.hasOwnProperty("length"); + for (var i = 0; i < 5; i++) + res = res && s.hasOwnProperty("length"); + return res; +} +assertEq(testLengthInString(), true); diff --git a/js/src/jit-test/tests/basic/testLengthOnNonNativeProto.js b/js/src/jit-test/tests/basic/testLengthOnNonNativeProto.js new file mode 100644 index 0000000..80d388f --- /dev/null +++ b/js/src/jit-test/tests/basic/testLengthOnNonNativeProto.js @@ -0,0 +1,20 @@ +function testLengthOnNonNativeProto() +{ + var o = {}; + o.__proto__ = [3]; + for (var j = 0; j < 5; j++) + o[0]; + + var o2 = {}; + o2.__proto__ = []; + for (var j = 0; j < 5; j++) + o2.length; + + function foo() { } + foo.__proto__ = []; + for (var j = 0; j < 5; j++) + foo.length; + + return "no assertion"; +} +assertEq(testLengthOnNonNativeProto(), "no assertion"); diff --git a/js/src/jit-test/tests/basic/testLetWithUnstableGlobal.js b/js/src/jit-test/tests/basic/testLetWithUnstableGlobal.js new file mode 100644 index 0000000..fb7984c --- /dev/null +++ b/js/src/jit-test/tests/basic/testLetWithUnstableGlobal.js @@ -0,0 +1,11 @@ +var q = []; +for each (b in [0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF]) { + for each (let e in [{}, {}, {}, "", {}]) { + b = (b | 0x40000000) + 1; + q.push(b); + } +} +function testLetWithUnstableGlobal() { + return q.join(","); +} +assertEq(testLetWithUnstableGlobal(), "2147483648,-1073741823,-1073741822,-1073741821,-1073741820,2147483648,-1073741823,-1073741822,-1073741821,-1073741820,2147483648,-1073741823,-1073741822,-1073741821,-1073741820"); diff --git a/js/src/jit-test/tests/basic/testLirBufOOM.js b/js/src/jit-test/tests/basic/testLirBufOOM.js new file mode 100644 index 0000000..f9d4e1d --- /dev/null +++ b/js/src/jit-test/tests/basic/testLirBufOOM.js @@ -0,0 +1,34 @@ +function testLirBufOOM() +{ + var a = [ + "12345678901234", + "123456789012", + "1234567890123456789012345678", + "12345678901234567890123456789012345678901234567890123456", + "f", + "$", + "", + "f()", + "(\\*)", + "b()", + "()", + "(#)", + "ABCDEFGHIJK", + "ABCDEFGHIJKLM", + "ABCDEFGHIJKLMNOPQ", + "ABCDEFGH", + "(.)", + "(|)", + "()$", + "/()", + "(.)$" + ]; + + for (var j = 0; j < 200; ++j) { + var js = "" + j; + for (var i = 0; i < a.length; i++) + "".match(a[i] + js) + } + return "ok"; +} +assertEq(testLirBufOOM(), "ok"); diff --git a/js/src/jit-test/tests/basic/testLogicalNotNaN.js b/js/src/jit-test/tests/basic/testLogicalNotNaN.js new file mode 100644 index 0000000..6bb0251 --- /dev/null +++ b/js/src/jit-test/tests/basic/testLogicalNotNaN.js @@ -0,0 +1,8 @@ +function testLogicalNotNaN() { + var i = 0; + var a = new Array(5); + while (i < a.length) + a[i++] = !NaN; + return a.join(); +} +assertEq(testLogicalNotNaN(), "true,true,true,true,true"); diff --git a/js/src/jit-test/tests/basic/testLongNumToString.js b/js/src/jit-test/tests/basic/testLongNumToString.js new file mode 100644 index 0000000..def2b47 --- /dev/null +++ b/js/src/jit-test/tests/basic/testLongNumToString.js @@ -0,0 +1,7 @@ +function testLongNumToString() { + var s; + for (var i = 0; i < 5; i++) + s = (0x08000000).toString(2); + return s; +} +assertEq(testLongNumToString(), '1000000000000000000000000000'); diff --git a/js/src/jit-test/tests/basic/testLoopWithUndefined1.js b/js/src/jit-test/tests/basic/testLoopWithUndefined1.js new file mode 100644 index 0000000..63c4b97 --- /dev/null +++ b/js/src/jit-test/tests/basic/testLoopWithUndefined1.js @@ -0,0 +1,12 @@ +function loopWithUndefined1(t, val) { + var a = new Array(6); + for (var i = 0; i < 6; i++) + a[i] = (t > val); + return a; +} +loopWithUndefined1(5.0, 2); //compile version with val=int + +function testLoopWithUndefined1() { + return loopWithUndefined1(5.0).join(","); //val=undefined +}; +assertEq(testLoopWithUndefined1(), "false,false,false,false,false,false"); diff --git a/js/src/jit-test/tests/basic/testLoopWithUndefined2.js b/js/src/jit-test/tests/basic/testLoopWithUndefined2.js new file mode 100644 index 0000000..a6ba9db --- /dev/null +++ b/js/src/jit-test/tests/basic/testLoopWithUndefined2.js @@ -0,0 +1,20 @@ +function loopWithUndefined2(t, dostuff, val) { + var a = new Array(6); + for (var i = 0; i < 6; i++) { + if (dostuff) { + val = 1; + a[i] = (t > val); + } else { + a[i] = (val == undefined); + } + } + return a; +} +function testLoopWithUndefined2() { + var a = loopWithUndefined2(5.0, true, 2); + var b = loopWithUndefined2(5.0, true); + var c = loopWithUndefined2(5.0, false, 8); + var d = loopWithUndefined2(5.0, false); + return [a[0], b[0], c[0], d[0]].join(","); +} +assertEq(testLoopWithUndefined2(), "true,true,false,true"); diff --git a/js/src/jit-test/tests/basic/testLoopingAccumulator.js b/js/src/jit-test/tests/basic/testLoopingAccumulator.js new file mode 100644 index 0000000..bacb29b --- /dev/null +++ b/js/src/jit-test/tests/basic/testLoopingAccumulator.js @@ -0,0 +1,21 @@ +function addAccumulations(f) { + var a = f(); + var b = f(); + return a() + b(); +} + +function loopingAccumulator() { + var x = 0; + return function () { + for (var i = 0; i < 10; ++i) { + ++x; + } + return x; + } +} + +function testLoopingAccumulator() { + var x = addAccumulations(loopingAccumulator); + return x; +} +assertEq(testLoopingAccumulator(), 20); diff --git a/js/src/jit-test/tests/basic/testMatchAsCondition.js b/js/src/jit-test/tests/basic/testMatchAsCondition.js new file mode 100644 index 0000000..8cb429f --- /dev/null +++ b/js/src/jit-test/tests/basic/testMatchAsCondition.js @@ -0,0 +1,8 @@ +function testMatchAsCondition() { + var a = ['0', '0', '0', '0']; + var r = /0/; + "x".q; + for (var z = 0; z < 4; z++) + a[z].match(r) ? 1 : 2; +} +testMatchAsCondition(); diff --git a/js/src/jit-test/tests/basic/testMatchStringObject.js b/js/src/jit-test/tests/basic/testMatchStringObject.js new file mode 100644 index 0000000..cde2da1 --- /dev/null +++ b/js/src/jit-test/tests/basic/testMatchStringObject.js @@ -0,0 +1,8 @@ +function testMatchStringObject() { + var a = new String("foo"); + var b; + for (i = 0; i < 300; i++) + b = a.match(/bar/); + return b; +} +assertEq(testMatchStringObject(), null); diff --git a/js/src/jit-test/tests/basic/testMethodInc.js b/js/src/jit-test/tests/basic/testMethodInc.js new file mode 100644 index 0000000..d965adf --- /dev/null +++ b/js/src/jit-test/tests/basic/testMethodInc.js @@ -0,0 +1,12 @@ +for (var i = 0; i < 9; i++) { + var x = {f: function() {}}; + x.f++; + assertEq(""+x.f, "NaN"); +} + +checkStats({ + recorderStarted: 1, + recorderAborted: 1, + traceCompleted: 0, + sideExitIntoInterpreter: 0 +}); diff --git a/js/src/jit-test/tests/basic/testMethodInit.js b/js/src/jit-test/tests/basic/testMethodInit.js new file mode 100644 index 0000000..bd74a81 --- /dev/null +++ b/js/src/jit-test/tests/basic/testMethodInit.js @@ -0,0 +1,15 @@ +function testMethodInit() { // bug 503198 + function o() { return 'o'; } + function k() { return 'k'; } + + var x; + for (var i = 0; i < 10; i++) + x = {o: o, k: k}; + return x.o() + x.k(); +} +assertEq(testMethodInit(), "ok"); +checkStats({ + recorderStarted: 1, + traceCompleted: 1, + sideExitIntoInterpreter: 1 +}); diff --git a/js/src/jit-test/tests/basic/testMethodInitDeref.js b/js/src/jit-test/tests/basic/testMethodInitDeref.js new file mode 100644 index 0000000..620f6e3 --- /dev/null +++ b/js/src/jit-test/tests/basic/testMethodInitDeref.js @@ -0,0 +1,9 @@ +for (var j = 0; j < 7; ++j) + ({x: function () {}}).x; + +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceCompleted: 1, + sideExitIntoInterpreter: 1 +}); diff --git a/js/src/jit-test/tests/basic/testMethodInitSafety.js b/js/src/jit-test/tests/basic/testMethodInitSafety.js new file mode 100644 index 0000000..ebd6309 --- /dev/null +++ b/js/src/jit-test/tests/basic/testMethodInitSafety.js @@ -0,0 +1,14 @@ +function testMethodInitSafety() { + function f() { return 'fail'; } + function g() { return 'ok'; } + + var s; + var arr = [f, f, f, f, g]; + //assertEq(arr.length > RUNLOOP, true); + for (var i = 0; i < arr.length; i++) { + var x = {m: arr[i]}; + s = x.m(); + } + return s; +} +assertEq(testMethodInitSafety(), "ok"); diff --git a/js/src/jit-test/tests/basic/testMethodInitUneval.js b/js/src/jit-test/tests/basic/testMethodInitUneval.js new file mode 100644 index 0000000..5ca7570 --- /dev/null +++ b/js/src/jit-test/tests/basic/testMethodInitUneval.js @@ -0,0 +1,9 @@ +for (var j = 0; j < 7; ++j) + uneval({x: function () {}}); + +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceCompleted: 1, + sideExitIntoInterpreter: 4 +}); diff --git a/js/src/jit-test/tests/basic/testMethodOverride.js b/js/src/jit-test/tests/basic/testMethodOverride.js new file mode 100644 index 0000000..bd19dd6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testMethodOverride.js @@ -0,0 +1,20 @@ +function Q() { + this.m = function () {}; +} +function callm(q) { + q.m(); +} +var a = []; +for (var i = 0; i < 5; i++) { + var q = new Q; + callm(q); + q.m = function () { return 42; }; + a[i] = q; +} +for (var i = 0; i < 5; i++) + callm(a[i]); +checkStats({ + recorderStarted: 2, + traceCompleted: 3, + sideExitIntoInterpreter: 4 +}); diff --git a/js/src/jit-test/tests/basic/testMethodSet.js b/js/src/jit-test/tests/basic/testMethodSet.js new file mode 100644 index 0000000..1549c1b --- /dev/null +++ b/js/src/jit-test/tests/basic/testMethodSet.js @@ -0,0 +1,18 @@ +function testMethodSet() { // bug 503198 + function o() { return 'o'; } + function k() { return 'k'; } + + var x; + for (var i = 0; i < 10; i++) { + x = {}; + x.o = o; + x.k = k; + } + return x.o() + x.k(); +} +assertEq(testMethodSet(), "ok"); +checkStats({ + recorderStarted: 1, + traceCompleted: 1, + sideExitIntoInterpreter: 1 +}); diff --git a/js/src/jit-test/tests/basic/testMethodWriteBarrier.js b/js/src/jit-test/tests/basic/testMethodWriteBarrier.js new file mode 100644 index 0000000..86f2b17 --- /dev/null +++ b/js/src/jit-test/tests/basic/testMethodWriteBarrier.js @@ -0,0 +1,4 @@ +var x = {p: 0.1, m: function(){}}; +x.m(); // the interpreter brands x +for (var i = 0; i < 9; i++) + x.p = 0.1; diff --git a/js/src/jit-test/tests/basic/testMethodWriteBarrier2.js b/js/src/jit-test/tests/basic/testMethodWriteBarrier2.js new file mode 100644 index 0000000..19b3871 --- /dev/null +++ b/js/src/jit-test/tests/basic/testMethodWriteBarrier2.js @@ -0,0 +1,17 @@ +function C() { + this.m = function () {}; // JSOP_SETMETHOD +} + +var a = [new C, new C, new C, new C, new C, new C, new C, new C, new C]; +var b = [new C, new C, new C, new C, new C, new C, a[8], new C, new C]; + +var thrown = 'none'; +try { + for (var i = 0; i < 9; i++) { + a[i].m(); + b[i].m = 0.7; // MethodWriteBarrier required here + } +} catch (exc) { + thrown = exc.name; +} +assertEq(thrown, 'TypeError'); diff --git a/js/src/jit-test/tests/basic/testMethodWriteBarrier3.js b/js/src/jit-test/tests/basic/testMethodWriteBarrier3.js new file mode 100644 index 0000000..9ae20fe --- /dev/null +++ b/js/src/jit-test/tests/basic/testMethodWriteBarrier3.js @@ -0,0 +1,27 @@ +function g() {} + +function h() { + for (var i = 0; i < 9; i++) + x.f = i; +} + +function j() { + x.f(); +} + +var x = {f: 0.7, g: g}; +x.g(); // interpreter brands x +h(); +print(shapeOf(x)); +x.f = function (){}; // does not change x's shape +j(); +print(shapeOf(x)); +h(); // should change x's shape + +var thrown = 'none'; +try { + j(); // should throw since x.f === 8 +} catch (exc) { + thrown = exc.name; +} +assertEq(thrown, 'TypeError'); \ No newline at end of file diff --git a/js/src/jit-test/tests/basic/testMethodWriteBarrier4.js b/js/src/jit-test/tests/basic/testMethodWriteBarrier4.js new file mode 100644 index 0000000..686df37 --- /dev/null +++ b/js/src/jit-test/tests/basic/testMethodWriteBarrier4.js @@ -0,0 +1,12 @@ +var z = 0; +function f() { + this.b = function() {}; + this.b = undefined; + if (z++ > HOTLOOP) + this.b(); +} + +try { + for (var i = 0; i < HOTLOOP + 2; i++) + new f(); +} catch (exc) {} diff --git a/js/src/jit-test/tests/basic/testMissingMethod.js b/js/src/jit-test/tests/basic/testMissingMethod.js new file mode 100644 index 0000000..20917f3 --- /dev/null +++ b/js/src/jit-test/tests/basic/testMissingMethod.js @@ -0,0 +1,9 @@ +var o = {y: function () {}}; +var a = [o, o, o, o, o, o, o, o, o]; +a[RECORDLOOP - 1] = {}; +try { + for (var i = 0; i < 9; i++) + a[i].y(); +} catch (exc) { + assertEq(exc.name, "TypeError"); // should happen when i == RECORDLOOP - 1 +} diff --git a/js/src/jit-test/tests/basic/testMissingMethod2.js b/js/src/jit-test/tests/basic/testMissingMethod2.js new file mode 100644 index 0000000..2c5c381 --- /dev/null +++ b/js/src/jit-test/tests/basic/testMissingMethod2.js @@ -0,0 +1,10 @@ +var o = {y: function() {}}; +var a = [o, o, o, o, o, o, o, o, o]; +Number.prototype.y = 0; +a[RECORDLOOP - 1] = 0; +try { + for (var i = 0; i < 9; i++) + a[i].y(); +} catch (exc) { + assertEq(exc.name, "TypeError"); // should happen when i == RECORDLOOP - 1 +} diff --git a/js/src/jit-test/tests/basic/testModuloWithNegative1.js b/js/src/jit-test/tests/basic/testModuloWithNegative1.js new file mode 100644 index 0000000..ed767a7 --- /dev/null +++ b/js/src/jit-test/tests/basic/testModuloWithNegative1.js @@ -0,0 +1,11 @@ +function testModuloWithNegative1() { + var v = 0; + for (var i = 0; i < 2; ++i) { + c = v; + v -= 1; + for (var j = 0; j < 2; ++j) + c %= -1; + } + return 1/c; +} +assertEq(testModuloWithNegative1(), -Infinity); diff --git a/js/src/jit-test/tests/basic/testModuloWithNegative2.js b/js/src/jit-test/tests/basic/testModuloWithNegative2.js new file mode 100644 index 0000000..dfd1e3d --- /dev/null +++ b/js/src/jit-test/tests/basic/testModuloWithNegative2.js @@ -0,0 +1,7 @@ +function f(v, e) { + for (var i = 0; i < 9; i++) + v %= e; + return v; +} +f(0, 1); +assertEq(f(-2, 2), -0); diff --git a/js/src/jit-test/tests/basic/testMoreArgcThanNargs.js b/js/src/jit-test/tests/basic/testMoreArgcThanNargs.js new file mode 100644 index 0000000..9fcda77 --- /dev/null +++ b/js/src/jit-test/tests/basic/testMoreArgcThanNargs.js @@ -0,0 +1,14 @@ +function doTestMoreArgcThanNargs() +{ + var x = 0; + for (var i = 0; i < 10; i++) + { + x = x + arguments[3]; + } + return x; +} +function testMoreArgcThanNargs() +{ + return doTestMoreArgcThanNargs(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); +} +assertEq(testMoreArgcThanNargs(), 4*10); diff --git a/js/src/jit-test/tests/basic/testMoreClosures.js b/js/src/jit-test/tests/basic/testMoreClosures.js new file mode 100644 index 0000000..5592bcb --- /dev/null +++ b/js/src/jit-test/tests/basic/testMoreClosures.js @@ -0,0 +1,14 @@ +function testMoreClosures() { + var f = {}, max = 3; + + var hello = function(n) { + function howdy() { return n * n } + f.test = howdy; + }; + + for (var i = 0; i <= max; i++) + hello(i); + + return f.test(); +} +assertEq(testMoreClosures(), 9); diff --git a/js/src/jit-test/tests/basic/testMulOverflow.js b/js/src/jit-test/tests/basic/testMulOverflow.js new file mode 100644 index 0000000..5d7a133 --- /dev/null +++ b/js/src/jit-test/tests/basic/testMulOverflow.js @@ -0,0 +1,6 @@ +function testMulOverflow() { + var a = []; + for (let j=0;j<5;++j) a.push(0 | ((0x60000009) * 0x60000009)); + return a.join(","); +} +assertEq(testMulOverflow(), "-1073741824,-1073741824,-1073741824,-1073741824,-1073741824"); diff --git a/js/src/jit-test/tests/basic/testMultipleArgumentsObjects.js b/js/src/jit-test/tests/basic/testMultipleArgumentsObjects.js new file mode 100644 index 0000000..dd8285d --- /dev/null +++ b/js/src/jit-test/tests/basic/testMultipleArgumentsObjects.js @@ -0,0 +1,12 @@ +function testMultipleArgumentsObjects() { + var testargs = arguments; + var f = function (name, which) { + var args = [testargs, arguments]; + return args[which][0]; + }; + var arr = [0, 0, 0, 0, 1]; + for (var i = 0; i < arr.length; i++) + arr[i] = f("f", arr[i]); + return arr + ''; +} +assertEq(testMultipleArgumentsObjects(), ",,,,f"); diff --git a/js/src/jit-test/tests/basic/testMultiplePendingGlobalWrites.js b/js/src/jit-test/tests/basic/testMultiplePendingGlobalWrites.js new file mode 100644 index 0000000..06d54df --- /dev/null +++ b/js/src/jit-test/tests/basic/testMultiplePendingGlobalWrites.js @@ -0,0 +1,11 @@ +var a, b; +function g(x) { + var y = x++; + return [x, y]; +} +function f() { + for(var i=0; i<20; i++) { + [a,b] = g("10"); + } +} +f(); diff --git a/js/src/jit-test/tests/basic/testNEWINIT.js b/js/src/jit-test/tests/basic/testNEWINIT.js new file mode 100644 index 0000000..28fd227 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNEWINIT.js @@ -0,0 +1,8 @@ +function testNEWINIT() +{ + var a; + for (var i = 0; i < 10; ++i) + a = [{}]; + return uneval(a); +} +assertEq(testNEWINIT(), "[{}]"); diff --git a/js/src/jit-test/tests/basic/testNEWINIT_DOUBLE.js b/js/src/jit-test/tests/basic/testNEWINIT_DOUBLE.js new file mode 100644 index 0000000..238e5de --- /dev/null +++ b/js/src/jit-test/tests/basic/testNEWINIT_DOUBLE.js @@ -0,0 +1,6 @@ +function testNEWINIT_DOUBLE() +{ + for (var z = 0; z < 2; ++z) { ({ 0.1: null })} + return "ok"; +} +assertEq(testNEWINIT_DOUBLE(), "ok"); diff --git a/js/src/jit-test/tests/basic/testNativeArgsRooting.js b/js/src/jit-test/tests/basic/testNativeArgsRooting.js new file mode 100644 index 0000000..1ce8259 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNativeArgsRooting.js @@ -0,0 +1,14 @@ +if ('gczeal' in this) +(function () { + (eval("\ + (function () {\ + for (var y = 0; y < 16; ++y) {\ + if (y % 3 == 2) {\ + gczeal(1);\ + } else {\ + print(0 / 0);\ + }\ + }\ + });\ + "))() +})(); diff --git a/js/src/jit-test/tests/basic/testNativeLog.js b/js/src/jit-test/tests/basic/testNativeLog.js new file mode 100644 index 0000000..5a81c79 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNativeLog.js @@ -0,0 +1,8 @@ +function testNativeLog() { + var a = new Array(5); + for (var i = 0; i < 5; i++) { + a[i] = Math.log(Math.pow(Math.E, 10)); + } + return a.join(","); +} +assertEq(testNativeLog(), "10,10,10,10,10"); diff --git a/js/src/jit-test/tests/basic/testNativeMax.js b/js/src/jit-test/tests/basic/testNativeMax.js new file mode 100644 index 0000000..ef36dbe --- /dev/null +++ b/js/src/jit-test/tests/basic/testNativeMax.js @@ -0,0 +1,20 @@ +function testNativeMax() { + var out = [], k; + for (var i = 0; i < 5; ++i) { + k = Math.max(k, i); + } + out.push(k); + + k = 0; + for (var i = 0; i < 5; ++i) { + k = Math.max(k, i); + } + out.push(k); + + for (var i = 0; i < 5; ++i) { + k = Math.max(0, -0); + } + out.push((1 / k) < 0); + return out.join(","); +} +assertEq(testNativeMax(), "NaN,4,false"); diff --git a/js/src/jit-test/tests/basic/testNativeSetter.js b/js/src/jit-test/tests/basic/testNativeSetter.js new file mode 100644 index 0000000..b2c7d75 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNativeSetter.js @@ -0,0 +1,14 @@ +function testNativeSetter() { + var re = /foo/; + var N = RUNLOOP + 10; + for (var i = 0; i < N; i++) + re.lastIndex = i; + assertEq(re.lastIndex, N - 1); +} +testNativeSetter(); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceTriggered: 1, + sideExitIntoInterpreter: 1 +}); diff --git a/js/src/jit-test/tests/basic/testNegZero1.js b/js/src/jit-test/tests/basic/testNegZero1.js new file mode 100644 index 0000000..fe9aabd --- /dev/null +++ b/js/src/jit-test/tests/basic/testNegZero1.js @@ -0,0 +1,9 @@ +function testNegZero1Helper(z) { + for (let j = 0; j < 5; ++j) { z = -z; } + return Math.atan2(0, -0) == Math.atan2(0, z); +} + +var testNegZero1 = function() { return testNegZero1Helper(0); } +testNegZero1.name = 'testNegZero1'; +testNegZero1Helper(1); +assertEq(testNegZero1(), true); diff --git a/js/src/jit-test/tests/basic/testNegativeArrayLength.js b/js/src/jit-test/tests/basic/testNegativeArrayLength.js new file mode 100644 index 0000000..77f1335 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNegativeArrayLength.js @@ -0,0 +1,10 @@ +function f() { + try { + for ( var i = HOTLOOP-1; i > -2; i-- ) + new Array(i).join('*'); + } catch (e) { + return e instanceof RangeError; + } + return false; +} +assertEq(f(), true); diff --git a/js/src/jit-test/tests/basic/testNegativeGETELEMIndex.js b/js/src/jit-test/tests/basic/testNegativeGETELEMIndex.js new file mode 100644 index 0000000..da7b748 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNegativeGETELEMIndex.js @@ -0,0 +1,6 @@ +function testNegativeGETELEMIndex() +{ + for (let i=0;i<3;++i) /x/[-4]; + return "ok"; +} +assertEq(testNegativeGETELEMIndex(), "ok"); diff --git a/js/src/jit-test/tests/basic/testNestedClosures.js b/js/src/jit-test/tests/basic/testNestedClosures.js new file mode 100644 index 0000000..445ea6e --- /dev/null +++ b/js/src/jit-test/tests/basic/testNestedClosures.js @@ -0,0 +1,23 @@ +function testNestedClosures() { + function f(a, b) { + function g(x, y) { + function h(m, n) { + function k(u, v) { + var s = ''; + for (var i = 0; i < 5; ++i) + s = a + ',' + b + ',' + x + ',' + y + ',' + m + ',' + n + ',' + u + ',' + v; + return s; + } + return k(m+1, n+1); + } + return h(x+1, y+1); + } + return g(a+1, b+1); + } + + var s1; + for (var i = 0; i < 5; ++i) + s1 = f(i, i+i); + return s1; +} +assertEq(testNestedClosures(), '4,8,5,9,6,10,7,11'); diff --git a/js/src/jit-test/tests/basic/testNestedDeepBail.js b/js/src/jit-test/tests/basic/testNestedDeepBail.js new file mode 100644 index 0000000..8e59b04 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNestedDeepBail.js @@ -0,0 +1,20 @@ +var _quit; +function testNestedDeepBail() +{ + _quit = false; + function loop() { + for (var i = 0; i < 4; i++) + ; + } + loop(); + + function f() { + loop(); + _quit = true; + } + + var stk = [[1], [], [], [], []]; + while (!_quit) + stk.pop().forEach(f); +} +testNestedDeepBail(); diff --git a/js/src/jit-test/tests/basic/testNestedEscapingLambdas.js b/js/src/jit-test/tests/basic/testNestedEscapingLambdas.js new file mode 100644 index 0000000..8b896f1 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNestedEscapingLambdas.js @@ -0,0 +1,31 @@ +function testNestedEscapingLambdas() +{ + try { + return (function() { + var a = [], r = []; + function setTimeout(f, t) { + a.push(f); + } + + function runTimeouts() { + for (var i = 0; i < a.length; i++) + a[i](); + } + + var $foo = "#nothiddendiv"; + setTimeout(function(){ + r.push($foo); + setTimeout(function(){ + r.push($foo); + }, 100); + }, 100); + + runTimeouts(); + + return r.join(""); + })(); + } catch (e) { + return e; + } +} +assertEq(testNestedEscapingLambdas(), "#nothiddendiv#nothiddendiv"); diff --git a/js/src/jit-test/tests/basic/testNestedExitStackOuter.js b/js/src/jit-test/tests/basic/testNestedExitStackOuter.js new file mode 100644 index 0000000..88b795e --- /dev/null +++ b/js/src/jit-test/tests/basic/testNestedExitStackOuter.js @@ -0,0 +1,29 @@ +// Test stack reconstruction after a nested exit +function testNestedExitStackInner(j, counter) { + ++counter; + var b = 0; + for (var i = 1; i <= RUNLOOP; i++) { + ++b; + var a; + // Make sure that once everything has been traced we suddenly switch to + // a different control flow the first time we run the outermost tree, + // triggering a side exit. + if (j < RUNLOOP) + a = 1; + else + a = 0; + ++b; + b += a; + } + return counter + b; +} +function testNestedExitStackOuter() { + var counter = 0; + for (var j = 1; j <= RUNLOOP; ++j) { + for (var k = 1; k <= RUNLOOP; ++k) { + counter = testNestedExitStackInner(j, counter); + } + } + return counter; +} +//assertEq(testNestedExitStackOuter(), 81); diff --git a/js/src/jit-test/tests/basic/testNestedForIn.js b/js/src/jit-test/tests/basic/testNestedForIn.js new file mode 100644 index 0000000..1541775 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNestedForIn.js @@ -0,0 +1,9 @@ +function testNestedForIn() { + var a = {x: 1, y: 2, z: 3}; + var s = ''; + for (var p1 in a) + for (var p2 in a) + s += p1 + p2 + ' '; + return s; +} +assertEq(testNestedForIn(), 'xx xy xz yx yy yz zx zy zz '); diff --git a/js/src/jit-test/tests/basic/testNewArrayCount.js b/js/src/jit-test/tests/basic/testNewArrayCount.js new file mode 100644 index 0000000..cb7e6d9 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNewArrayCount.js @@ -0,0 +1,12 @@ +function testNewArrayCount() +{ + function count(a) { var n = 0; for (var p in a) n++; return n; } + var a = []; + for (var i = 0; i < 5; i++) + a = [0]; + assertEq(count(a), 1); + for (var i = 0; i < 5; i++) + a = [0, , 2]; + assertEq(count(a), 2); +} +testNewArrayCount(); diff --git a/js/src/jit-test/tests/basic/testNewArrayCount2.js b/js/src/jit-test/tests/basic/testNewArrayCount2.js new file mode 100644 index 0000000..6318e4c --- /dev/null +++ b/js/src/jit-test/tests/basic/testNewArrayCount2.js @@ -0,0 +1,8 @@ +function testNewArrayCount2() { + function count(a) { var n = 0; for (var p in a) n++; return n; } + var x = 0; + for (var i = 0; i < 10; ++i) + x = count(new Array(1,2,3)); + return x; +} +assertEq(testNewArrayCount2(), 3); diff --git a/js/src/jit-test/tests/basic/testNewDate.js b/js/src/jit-test/tests/basic/testNewDate.js new file mode 100644 index 0000000..2775451 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNewDate.js @@ -0,0 +1,17 @@ +function testNewDate() +{ + // Accessing global.Date for the first time will change the global shape, + // so do it before the loop starts; otherwise we have to loop an extra time + // to pick things up. + var start = new Date(); + var time = new Date(); + for (var j = 0; j < RUNLOOP; ++j) + time = new Date(); + return time > 0 && time >= start; +} +assertEq(testNewDate(), true); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceTriggered: 1 +}); diff --git a/js/src/jit-test/tests/basic/testNewObject.js b/js/src/jit-test/tests/basic/testNewObject.js new file mode 100644 index 0000000..028523c --- /dev/null +++ b/js/src/jit-test/tests/basic/testNewObject.js @@ -0,0 +1,8 @@ +function testNewObject() +{ + var a = {}; + for (var i = 0; i < 10; ++i) + a = new Object(); + return a; +} +assertEq(testNewObject().__proto__, {}.__proto__); diff --git a/js/src/jit-test/tests/basic/testNewString.js b/js/src/jit-test/tests/basic/testNewString.js new file mode 100644 index 0000000..81e1c21 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNewString.js @@ -0,0 +1,27 @@ +function testNewString() +{ + var o = { toString: function() { return "string"; } }; + var r = []; + for (var i = 0; i < 5; i++) + r.push(typeof new String(o)); + for (var i = 0; i < 5; i++) + r.push(typeof new String(3)); + for (var i = 0; i < 5; i++) + r.push(typeof new String(2.5)); + for (var i = 0; i < 5; i++) + r.push(typeof new String("string")); + for (var i = 0; i < 5; i++) + r.push(typeof new String(null)); + for (var i = 0; i < 5; i++) + r.push(typeof new String(true)); + for (var i = 0; i < 5; i++) + r.push(typeof new String(undefined)); + return r.length === 35 && r.every(function(v) { return v === "object"; }); +} +assertEq(testNewString(), true); +checkStats({ + recorderStarted: 7, + recorderAborted: 0, + traceCompleted: 7, + sideExitIntoInterpreter: 7 +}); diff --git a/js/src/jit-test/tests/basic/testNewWithNonNativeProto.js b/js/src/jit-test/tests/basic/testNewWithNonNativeProto.js new file mode 100644 index 0000000..11066ba --- /dev/null +++ b/js/src/jit-test/tests/basic/testNewWithNonNativeProto.js @@ -0,0 +1,14 @@ +function testNewWithNonNativeProto() +{ + function f() { } + var a = f.prototype = []; + for (var i = 0; i < 5; i++) + var o = new f(); + return Object.getPrototypeOf(o) === a && o.splice === Array.prototype.splice; +} +assertEq(testNewWithNonNativeProto(), true); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + sideExitIntoInterpreter: 1 +}); diff --git a/js/src/jit-test/tests/basic/testNonStubGetter.js b/js/src/jit-test/tests/basic/testNonStubGetter.js new file mode 100644 index 0000000..da0b78e --- /dev/null +++ b/js/src/jit-test/tests/basic/testNonStubGetter.js @@ -0,0 +1,7 @@ +function testNonStubGetter() { + let ([] = false) { (this.watch("x", /a/g)); }; + (function () { (eval("(function(){for each (x in [1, 2, 2]);});"))(); })(); + this.unwatch("x"); + return "ok"; +} +assertEq(testNonStubGetter(), "ok"); diff --git a/js/src/jit-test/tests/basic/testNot.js b/js/src/jit-test/tests/basic/testNot.js new file mode 100644 index 0000000..746ca57 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNot.js @@ -0,0 +1,8 @@ +function testNot() { + var a = new Object(), b = null, c = "foo", d = "", e = 5, f = 0, g = 5.5, h = -0, i = true, j = false, k = undefined; + var r; + for (var i = 0; i < 10; ++i) + r = [!a, !b, !c, !d, !e, !f, !g, !h, !i, !j, !k]; + return r.join(","); +} +assertEq(testNot(), "false,true,false,true,false,true,false,true,false,true,true"); diff --git a/js/src/jit-test/tests/basic/testNullCallee.js b/js/src/jit-test/tests/basic/testNullCallee.js new file mode 100644 index 0000000..7eab7d5 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNullCallee.js @@ -0,0 +1,16 @@ +function testNullCallee() { + try { + function f() { + var x = new Array(5); + for (var i = 0; i < 5; i++) + x[i] = a[i].toString(); + return x.join(','); + } + f([[1],[2],[3],[4],[5]]); + f([null, null, null, null, null]); + } catch (e) { + return true; + } + return false; +} +assertEq(testNullCallee(), true); diff --git a/js/src/jit-test/tests/basic/testNullIncrement.js b/js/src/jit-test/tests/basic/testNullIncrement.js new file mode 100644 index 0000000..71e49b7 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNullIncrement.js @@ -0,0 +1,21 @@ +function f() { + var n; + var k; + for (var i = 0; i < 2*RUNLOOP; ++i) { + n = null; + k = n++; + if (k) { } + } + return [k, n]; +} + +var [a, b] = f(); +assertEq(a, 0); +assertEq(b, 1); + +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceCompleted: 1, + traceTriggered: 1 +}); diff --git a/js/src/jit-test/tests/basic/testNullRelCmp.js b/js/src/jit-test/tests/basic/testNullRelCmp.js new file mode 100644 index 0000000..4531ea2 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNullRelCmp.js @@ -0,0 +1,6 @@ +function testNullRelCmp() { + var out = []; + for(j=0;j<3;++j) { out.push(3 > null); out.push(3 < null); out.push(0 == null); out.push(3 == null); } + return out.join(","); +} +assertEq(testNullRelCmp(), "true,false,false,false,true,false,false,false,true,false,false,false"); diff --git a/js/src/jit-test/tests/basic/testNullToString.js b/js/src/jit-test/tests/basic/testNullToString.js new file mode 100644 index 0000000..a422ce9 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNullToString.js @@ -0,0 +1,18 @@ +function testNullToString() +{ + var a = []; + for (var i = 0; i < 10; i++) + a.push(String(null)); + for (i = 0; i < 10; i++) { + var t = typeof a[i]; + if (t != "string") + a.push(t); + } + return a.join(","); +} +assertEq(testNullToString(), "null,null,null,null,null,null,null,null,null,null"); +checkStats({ + recorderStarted: 2, + sideExitIntoInterpreter: 2, + recorderAborted: 0 +}); diff --git a/js/src/jit-test/tests/basic/testNumToString.js b/js/src/jit-test/tests/basic/testNumToString.js new file mode 100644 index 0000000..96f3cc7 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNumToString.js @@ -0,0 +1,18 @@ +function testNumToString() { + var r = []; + var d = 123456789; + for (var i = 0; i < 10; ++i) { + r = [ + d.toString(), + (-d).toString(), + d.toString(10), + (-d).toString(10), + d.toString(16), + (-d).toString(16), + d.toString(36), + (-d).toString(36) + ]; + } + return r.join(","); +} +assertEq(testNumToString(), "123456789,-123456789,123456789,-123456789,75bcd15,-75bcd15,21i3v9,-21i3v9"); diff --git a/js/src/jit-test/tests/basic/testNumberToString.js b/js/src/jit-test/tests/basic/testNumberToString.js new file mode 100644 index 0000000..5b79616 --- /dev/null +++ b/js/src/jit-test/tests/basic/testNumberToString.js @@ -0,0 +1,6 @@ +function testNumberToString() { + var x = new Number(0); + for (var i = 0; i < 4; i++) + x.toString(); +} +testNumberToString(); diff --git a/js/src/jit-test/tests/basic/testObjectConstructorReturningObject.js b/js/src/jit-test/tests/basic/testObjectConstructorReturningObject.js new file mode 100644 index 0000000..21d8a08 --- /dev/null +++ b/js/src/jit-test/tests/basic/testObjectConstructorReturningObject.js @@ -0,0 +1,12 @@ +for (var i = 0; i < HOTLOOP+4; ++i) { + var o; + + o = new Object(Object); + assertEq(o, Object); + + (function () { + x = constructor + })(); + o = new(x)(x); + assertEq(o, Object); +} diff --git a/js/src/jit-test/tests/basic/testObjectLength.js b/js/src/jit-test/tests/basic/testObjectLength.js new file mode 100644 index 0000000..c19c1b2 --- /dev/null +++ b/js/src/jit-test/tests/basic/testObjectLength.js @@ -0,0 +1,15 @@ +function testObjectLength() +{ + var counter = 0; + var a = {}; + a.length = 10000000; + for (var i = 0; i < a.length; i++) + counter++; + return counter; +} +assertEq(testObjectLength(), 10000000); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + sideExitIntoInterpreter: 1 +}); diff --git a/js/src/jit-test/tests/basic/testObjectOrderedCmp.js b/js/src/jit-test/tests/basic/testObjectOrderedCmp.js new file mode 100644 index 0000000..7065ad8 --- /dev/null +++ b/js/src/jit-test/tests/basic/testObjectOrderedCmp.js @@ -0,0 +1,7 @@ +function testObjectOrderedCmp() +{ + var a = new Array(5); + for(var i=0;i<5;++i) a[i] = ({} < {}); + return a.join(","); +} +assertEq(testObjectOrderedCmp(), "false,false,false,false,false"); diff --git a/js/src/jit-test/tests/basic/testObjectOrderedCmp2.js b/js/src/jit-test/tests/basic/testObjectOrderedCmp2.js new file mode 100644 index 0000000..6790799 --- /dev/null +++ b/js/src/jit-test/tests/basic/testObjectOrderedCmp2.js @@ -0,0 +1,7 @@ +function testObjectOrderedCmp2() +{ + var a = new Array(5); + for(var i=0;i<5;++i) a[i] = ("" <= null); + return a.join(","); +} +assertEq(testObjectOrderedCmp2(), "true,true,true,true,true"); diff --git a/js/src/jit-test/tests/basic/testObjectToNumber.js b/js/src/jit-test/tests/basic/testObjectToNumber.js new file mode 100644 index 0000000..137b050 --- /dev/null +++ b/js/src/jit-test/tests/basic/testObjectToNumber.js @@ -0,0 +1,8 @@ +function testObjectToNumber() { + var o = {valueOf: function()-3}; + var x = 0; + for (var i = 0; i < 10; i++) + x -= o; + return x; +} +assertEq(testObjectToNumber(), 30); diff --git a/js/src/jit-test/tests/basic/testObjectToString.js b/js/src/jit-test/tests/basic/testObjectToString.js new file mode 100644 index 0000000..20157b2 --- /dev/null +++ b/js/src/jit-test/tests/basic/testObjectToString.js @@ -0,0 +1,8 @@ +function testObjectToString() { + var o = {toString: function()"foo"}; + var s = ""; + for (var i = 0; i < 10; i++) + s += o; + return s; +} +assertEq(testObjectToString(), "foofoofoofoofoofoofoofoofoofoo"); diff --git a/js/src/jit-test/tests/basic/testObjectVsPrototype.js b/js/src/jit-test/tests/basic/testObjectVsPrototype.js new file mode 100644 index 0000000..194b05f --- /dev/null +++ b/js/src/jit-test/tests/basic/testObjectVsPrototype.js @@ -0,0 +1,12 @@ +function testObjectVsPrototype() { + function D() {} + var b = D.prototype = {x: 1}; + var d = new D; + var arr = [b, b, b, d]; + for (var i = 0; i < 4; i++) + arr[i].x = i; + + d.y = 12; + assertEq(d.x, 3); +} +testObjectVsPrototype(); diff --git a/js/src/jit-test/tests/basic/testOwnPropertyWithInOperator.js b/js/src/jit-test/tests/basic/testOwnPropertyWithInOperator.js new file mode 100644 index 0000000..7c9501f --- /dev/null +++ b/js/src/jit-test/tests/basic/testOwnPropertyWithInOperator.js @@ -0,0 +1,12 @@ +function testOwnPropertyWithInOperator() +{ + var o = { 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6 }; + var a = []; + for (var i = 0; i < 7; i++) + a.push(i in o); + return a.join(","); +} +assertEq(testOwnPropertyWithInOperator(), "true,true,true,true,true,true,true"); +checkStats({ + sideExitIntoInterpreter: 1 +}); diff --git a/js/src/jit-test/tests/basic/testPartialFlatClosure.js b/js/src/jit-test/tests/basic/testPartialFlatClosure.js new file mode 100644 index 0000000..da022fb --- /dev/null +++ b/js/src/jit-test/tests/basic/testPartialFlatClosure.js @@ -0,0 +1,16 @@ +assertEq((('-r', function (s) { + function C(i) { + this.m = function () { return i * t; } + } + var t = s; + var a = []; + for (var i = 0; i < 5; i++) + a[a.length] = new C(i); + return a; +})(42))[4].m(), 168); + +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceCompleted: 1, +}); diff --git a/js/src/jit-test/tests/basic/testPrimitiveConstructorPrototype.js b/js/src/jit-test/tests/basic/testPrimitiveConstructorPrototype.js new file mode 100644 index 0000000..f015408 --- /dev/null +++ b/js/src/jit-test/tests/basic/testPrimitiveConstructorPrototype.js @@ -0,0 +1,7 @@ +function testPrimitiveConstructorPrototype() { + var f = function(){}; + f.prototype = false; + for (let j=0;j<5;++j) { new f; } + return "ok"; +} +assertEq(testPrimitiveConstructorPrototype(), "ok"); diff --git a/js/src/jit-test/tests/basic/testPropagatedFunArgs.js b/js/src/jit-test/tests/basic/testPropagatedFunArgs.js new file mode 100644 index 0000000..19052d1 --- /dev/null +++ b/js/src/jit-test/tests/basic/testPropagatedFunArgs.js @@ -0,0 +1,34 @@ +function testPropagatedFunArgs() +{ + var win = this; + var res = [], q = []; + function addEventListener(name, func, flag) { + q.push(func); + } + + var pageInfo, obs; + addEventListener("load", handleLoad, true); + + var observer = { + observe: function(win, topic, data) { + // obs.removeObserver(observer, "page-info-dialog-loaded"); + handlePageInfo(); + } + }; + + function handleLoad() { + pageInfo = { toString: function() { return "pageInfo"; } }; + obs = { addObserver: function (obs, topic, data) { obs.observe(win, topic, data); } }; + obs.addObserver(observer, "page-info-dialog-loaded", false); + } + + function handlePageInfo() { + res.push(pageInfo); + function $(aId) { res.push(pageInfo); }; + var feedTab = $("feedTab"); + } + + q[0](); + return res.join(','); +} +assertEq(testPropagatedFunArgs(), "pageInfo,pageInfo"); diff --git a/js/src/jit-test/tests/basic/testProxyConstructors.js b/js/src/jit-test/tests/basic/testProxyConstructors.js new file mode 100644 index 0000000..04665a7 --- /dev/null +++ b/js/src/jit-test/tests/basic/testProxyConstructors.js @@ -0,0 +1,16 @@ +// |jit-test| error: ExitCleanly + +// proxies can return primitives +assertEq(new (Proxy.createFunction({}, function(){}, function(){})), undefined); + +x = Proxy.createFunction((function () {}), Uint16Array, wrap) +new(wrap(x)) + +// proxies can return the callee +var x = Proxy.createFunction({}, function (q) { return q; }); +new x(x); + +// not an error +new (Proxy.createFunction({}, "".indexOf)); + +throw "ExitCleanly" diff --git a/js/src/jit-test/tests/basic/testProxyDefinePropertyWithMissingSetter.js b/js/src/jit-test/tests/basic/testProxyDefinePropertyWithMissingSetter.js new file mode 100644 index 0000000..fa52756 --- /dev/null +++ b/js/src/jit-test/tests/basic/testProxyDefinePropertyWithMissingSetter.js @@ -0,0 +1,23 @@ +// throw, don't crash + +var expect = "TypeError: property descriptor's setter field is neither undefined nor a function"; +var actual = ""; + +try { + +(x = Proxy.createFunction((function() { + return { + defineProperty: function(name, desc) { + Object.defineProperty(x, name, desc) + }, + } +})(), (eval))); +Object.defineProperty(x, "", ({ + get: function() {} +})) + +} catch (e) { + actual = '' + e; +} + +assertEq(expect, actual); diff --git a/js/src/jit-test/tests/basic/testPutOnEmptyArgsObject.js b/js/src/jit-test/tests/basic/testPutOnEmptyArgsObject.js new file mode 100644 index 0000000..b230897 --- /dev/null +++ b/js/src/jit-test/tests/basic/testPutOnEmptyArgsObject.js @@ -0,0 +1,16 @@ +var g; + +function h() { + return arguments.length; +} + +function f() { + var args = arguments; + g = function() { return h.apply(this, args); } +} + +for (var i = 0; i < 10; ++i) { + f(); +} + +assertEq(g(), 0); diff --git a/js/src/jit-test/tests/basic/testRUNLOOPCorrectness.js b/js/src/jit-test/tests/basic/testRUNLOOPCorrectness.js new file mode 100644 index 0000000..5ec5529 --- /dev/null +++ b/js/src/jit-test/tests/basic/testRUNLOOPCorrectness.js @@ -0,0 +1,15 @@ +function testRUNLOOPCorrectness() { + var b = 0; + for (var i = 0; i < RUNLOOP; ++i) { + ++b; + } + return b; +} +// Change the global shape right before doing the test +this.testRUNLOOPCorrectnessVar = 1; +assertEq(testRUNLOOPCorrectness(), RUNLOOP); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceTriggered: 1 +}); diff --git a/js/src/jit-test/tests/basic/testReallyDeepNestedExit.js b/js/src/jit-test/tests/basic/testReallyDeepNestedExit.js new file mode 100644 index 0000000..f27c731 --- /dev/null +++ b/js/src/jit-test/tests/basic/testReallyDeepNestedExit.js @@ -0,0 +1,38 @@ +function reallyDeepNestedExit(schedule) +{ + var c = 0, j = 0; + for (var i = 0; i < 5; i++) { + for (j = 0; j < 4; j++) { + c += (schedule[i*4 + j] == 1) ? 1 : 2; + } + } + return c; +} +function testReallyDeepNestedExit() +{ + var c = 0; + var schedule1 = new Array(5*4); + var schedule2 = new Array(5*4); + for (var i = 0; i < 5*4; i++) { + schedule1[i] = 0; + schedule2[i] = 0; + } + /** + * First innermost compile: true branch runs through. + * Second '': false branch compiles new loop edge. + * First outer compile: expect true branch. + * Second '': hit false branch. + */ + schedule1[0*4 + 3] = 1; + var schedules = [schedule1, + schedule2, + schedule1, + schedule2, + schedule2]; + + for (var i = 0; i < 5; i++) { + c += reallyDeepNestedExit(schedules[i]); + } + return c; +} +assertEq(testReallyDeepNestedExit(), 198); diff --git a/js/src/jit-test/tests/basic/testRebranding.js b/js/src/jit-test/tests/basic/testRebranding.js new file mode 100644 index 0000000..f21fc5c --- /dev/null +++ b/js/src/jit-test/tests/basic/testRebranding.js @@ -0,0 +1,10 @@ +q = ""; +function g() { q += "g"; } +function h() { q += "h"; } +a = [g, g, g, g, h]; +for (i=0; i<5; i++) { f = a[i]; f(); } + +function testRebranding() { + return q; +} +assertEq(testRebranding(), "ggggh"); diff --git a/js/src/jit-test/tests/basic/testRebranding2.js b/js/src/jit-test/tests/basic/testRebranding2.js new file mode 100644 index 0000000..2bf26ee --- /dev/null +++ b/js/src/jit-test/tests/basic/testRebranding2.js @@ -0,0 +1,21 @@ +delete q; +delete g; +delete h; +delete a; +delete f; + +function testRebranding2() { + // Same as testRebranding, but the object to be rebranded isn't the global. + var x = "FAIL"; + function g(){} + function h(){ x = "ok"; } + var obj = {m: g}; + var arr = [g, g, g, g, h]; + //assertEq(arr.length > RUNLOOP, true); + for (var i = 0; i < 5; i++) { + obj.m = arr[i]; + obj.m(); + } + return x; +} +assertEq(testRebranding2(), "ok"); diff --git a/js/src/jit-test/tests/basic/testReconstructImacroPCStack.js b/js/src/jit-test/tests/basic/testReconstructImacroPCStack.js new file mode 100644 index 0000000..2dc5150 --- /dev/null +++ b/js/src/jit-test/tests/basic/testReconstructImacroPCStack.js @@ -0,0 +1,28 @@ +x = Proxy.create((function () { + return { + get: function () {} + } +}()), Object.e) + +var hit = false; + +try { + Function("\ + for(var a = 0; a < 2; ++a) {\ + if (a == 0) {}\ + else {\ + x > x\ + }\ + }\ + ")() +} catch (e) { + hit = true; + + var str = String(e); + var match = (str == "TypeError: x is not a function" || + str == "TypeError: can't convert x to number"); + + assertEq(match, true); +} + +assertEq(hit, true); diff --git a/js/src/jit-test/tests/basic/testRegExpLiteral.js b/js/src/jit-test/tests/basic/testRegExpLiteral.js new file mode 100644 index 0000000..8e0c7fe --- /dev/null +++ b/js/src/jit-test/tests/basic/testRegExpLiteral.js @@ -0,0 +1,17 @@ +function testRegExpLiteral() +{ + var a; + for (var i = 0; i < 15; i++) + a = /foobar/; +} + +testRegExpLiteral(); + +checkStats({ + recorderStarted: 1, + sideExitIntoInterpreter: 1, + recorderAborted: 0, + traceTriggered: 1, + traceCompleted: 1 + }); + diff --git a/js/src/jit-test/tests/basic/testRegExpTest.js b/js/src/jit-test/tests/basic/testRegExpTest.js new file mode 100644 index 0000000..78917ba --- /dev/null +++ b/js/src/jit-test/tests/basic/testRegExpTest.js @@ -0,0 +1,10 @@ +// |jit-test| TMFLAGS: full,fragprofile,treevis; valgrind + +function testRegExpTest() { + var r = /abc/; + var flag = false; + for (var i = 0; i < 10; ++i) + flag = r.test("abc"); + return flag; +} +assertEq(testRegExpTest(), true); diff --git a/js/src/jit-test/tests/basic/testRegexpGet.js b/js/src/jit-test/tests/basic/testRegexpGet.js new file mode 100644 index 0000000..c890009 --- /dev/null +++ b/js/src/jit-test/tests/basic/testRegexpGet.js @@ -0,0 +1,8 @@ +function testRegexpGet() { + var re = /hi/; + var a = []; + for (let i = 0; i < 5; ++i) + a.push(re.source); + return a.toString(); +} +assertEq(testRegexpGet(), "hi,hi,hi,hi,hi"); diff --git a/js/src/jit-test/tests/basic/testReplace2.js b/js/src/jit-test/tests/basic/testReplace2.js new file mode 100644 index 0000000..20685ad --- /dev/null +++ b/js/src/jit-test/tests/basic/testReplace2.js @@ -0,0 +1,7 @@ +function testReplace2() { + var s = "H e l l o", s1; + for (i = 0; i < 100; ++i) + s1 = s.replace(" ", ""); + return s1; +} +assertEq(testReplace2(), "He l l o"); diff --git a/js/src/jit-test/tests/basic/testReplaceMap.js b/js/src/jit-test/tests/basic/testReplaceMap.js new file mode 100644 index 0000000..929f52c --- /dev/null +++ b/js/src/jit-test/tests/basic/testReplaceMap.js @@ -0,0 +1,27 @@ + +// String.replace on functions returning hashmap elements. + +function first() { + var arr = {a: "hello", b: "there"}; + var s = 'a|b'; + return s.replace(/[a-z]/g, function(a) { return arr[a]; }, 'g'); +} +assertEq(first(), "hello|there"); + +function second() { + var arr = {a: "hello", c: "there"}; + var s = 'a|b|c'; + return s.replace(/[a-z]/g, function(a) { return arr[a]; }, 'g'); +} +assertEq(second(), "hello|undefined|there"); + +Object.defineProperty(Object.prototype, "b", {get: function() { return "what"; }}); + +assertEq(second(), "hello|what|there"); + +function third() { + var arr = {a: "hello", b: {toString: function() { arr = {}; return "three"; }}, c: "there"}; + var s = 'a|b|c'; + return s.replace(/[a-z]/g, function(a) { return arr[a]; }, 'g'); +} +assertEq(third(), "hello|three|undefined"); diff --git a/js/src/jit-test/tests/basic/testResumeOp.js b/js/src/jit-test/tests/basic/testResumeOp.js new file mode 100644 index 0000000..2acb18f --- /dev/null +++ b/js/src/jit-test/tests/basic/testResumeOp.js @@ -0,0 +1,8 @@ +function testResumeOp() { + var a = [1,"2",3,"4",5,"6",7,"8",9,"10",11,"12",13,"14",15,"16"]; + var x = ""; + while (a.length > 0) + x += a.pop(); + return x; +} +assertEq(testResumeOp(), "16151413121110987654321"); diff --git a/js/src/jit-test/tests/basic/testReverseArgTypes.js b/js/src/jit-test/tests/basic/testReverseArgTypes.js new file mode 100644 index 0000000..f36fed3 --- /dev/null +++ b/js/src/jit-test/tests/basic/testReverseArgTypes.js @@ -0,0 +1,5 @@ +function testReverseArgTypes() { + for (var j = 0; j < 4; ++j) ''.replace('', /x/); + return 1; +} +assertEq(testReverseArgTypes(), 1); diff --git a/js/src/jit-test/tests/basic/testScriptGetter_JSOP_CALLPROP-2.js b/js/src/jit-test/tests/basic/testScriptGetter_JSOP_CALLPROP-2.js new file mode 100644 index 0000000..f9899b1 --- /dev/null +++ b/js/src/jit-test/tests/basic/testScriptGetter_JSOP_CALLPROP-2.js @@ -0,0 +1,13 @@ +// Test that the tracer is not confused by a.m() when a is the same shape each +// time through the loop but a.m is a scripted getter that returns different +// functions. + +function f() { return 'f'; } +function g() { return 'g'; } +var arr = [f, f, f, f, f, f, f, f, g]; +var a = {get m() { return arr[i]; }}; + +var s = ''; +for (var i = 0; i < 9; i++) + s += a.m(); +assertEq(s, 'ffffffffg'); diff --git a/js/src/jit-test/tests/basic/testScriptGetter_JSOP_CALLPROP.js b/js/src/jit-test/tests/basic/testScriptGetter_JSOP_CALLPROP.js new file mode 100644 index 0000000..14574b1 --- /dev/null +++ b/js/src/jit-test/tests/basic/testScriptGetter_JSOP_CALLPROP.js @@ -0,0 +1,11 @@ +var a = {_val: 'q', + get p() { return f; }}; + +function f() { return this._val; } + +var g = ''; +for (var i = 0; i < 9; i++) + g += a.p(); +assertEq(g, 'qqqqqqqqq'); + +checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1}); diff --git a/js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETARGPROP.js b/js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETARGPROP.js new file mode 100644 index 0000000..5483781 --- /dev/null +++ b/js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETARGPROP.js @@ -0,0 +1,9 @@ +function test(a) { + var s = ''; + for (var i = 0; i < 9; i++) + s += a.p; + assertEq(s, 'qqqqqqqqq'); +} +test({get p() { return 'q'; }}); + +checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1}); diff --git a/js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETLOCALPROP.js b/js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETLOCALPROP.js new file mode 100644 index 0000000..c00e07e --- /dev/null +++ b/js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETLOCALPROP.js @@ -0,0 +1,10 @@ +function test() { + var a = {get p() { return 'q'; }}; + var s = ''; + for (var i = 0; i < 9; i++) + s += a.p; + assertEq(s, 'qqqqqqqqq'); +} +test(); + +checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1}); diff --git a/js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETPROP.js b/js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETPROP.js new file mode 100644 index 0000000..59e545d --- /dev/null +++ b/js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETPROP.js @@ -0,0 +1,10 @@ +var a = {get p() { return 11; }}; + +function f() { return a; } + +var g = 0; +for (var i = 0; i < 9; i++) + g += f().p; +assertEq(g, 99); + +checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1}); diff --git a/js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETTHISPROP.js b/js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETTHISPROP.js new file mode 100644 index 0000000..9c4b958 --- /dev/null +++ b/js/src/jit-test/tests/basic/testScriptGetter_JSOP_GETTHISPROP.js @@ -0,0 +1,11 @@ +var a = { + get p() { return 11; }, + test: function () { + var s = 0; + for (var i = 0; i < 9; i++) + s += this.p; + assertEq(s, 99); + }}; +a.test(); + +checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1}); diff --git a/js/src/jit-test/tests/basic/testSetGetterOnlyProperty.js b/js/src/jit-test/tests/basic/testSetGetterOnlyProperty.js new file mode 100644 index 0000000..d08ea7a --- /dev/null +++ b/js/src/jit-test/tests/basic/testSetGetterOnlyProperty.js @@ -0,0 +1,5 @@ +var o = { get x() { return 17; } }; +for (var j = 0; j < 5; ++j) + o.x = 42; + +assertEq(true, true); diff --git a/js/src/jit-test/tests/basic/testSetMethod.js b/js/src/jit-test/tests/basic/testSetMethod.js new file mode 100644 index 0000000..45e9404 --- /dev/null +++ b/js/src/jit-test/tests/basic/testSetMethod.js @@ -0,0 +1,13 @@ +function C() { + this.a = function() {}; + this.b = function() {}; +} +for (var i = 0; i < 9; i++) + new C; + +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceCompleted: 1, + sideExitIntoInterpreter: 1 +}); diff --git a/js/src/jit-test/tests/basic/testSetPropNeitherMissNorHit.js b/js/src/jit-test/tests/basic/testSetPropNeitherMissNorHit.js new file mode 100644 index 0000000..906a2c1 --- /dev/null +++ b/js/src/jit-test/tests/basic/testSetPropNeitherMissNorHit.js @@ -0,0 +1,5 @@ +function testSetPropNeitherMissNorHit() { + for (var j = 0; j < 5; ++j) { if (({}).__proto__ = 1) { } } + return "ok"; +} +assertEq(testSetPropNeitherMissNorHit(), "ok"); diff --git a/js/src/jit-test/tests/basic/testSetPropertyFail.js b/js/src/jit-test/tests/basic/testSetPropertyFail.js new file mode 100644 index 0000000..0ca6257 --- /dev/null +++ b/js/src/jit-test/tests/basic/testSetPropertyFail.js @@ -0,0 +1,22 @@ +function test(name, fn, val) { + gc(); + var ok = {}, bad = {}; + bad.__defineSetter__(name, fn); + var arr = [ok, ok, ok, ok, ok, bad]; + + var log = ''; + try { + for (var i = 0; i < arr.length; i++) { + arr[i][name] = val; + log += '.'; + } + } catch (exc) { + log += 'E'; + } + assertEq(log, '.....E'); +} + +test("x", Function.prototype.call, null); // TypeError: Function.prototype.call called on incompatible [object Object] +test("y", Array, 0.1); // RangeError: invalid array length +test(1, Function.prototype.call, null); // TypeError: Function.prototype.call called on incompatible [object Object] +test(1, Array, 0.1); // RangeError: invalid array length diff --git a/js/src/jit-test/tests/basic/testSetProtoRegeneratesObjectShape.js b/js/src/jit-test/tests/basic/testSetProtoRegeneratesObjectShape.js new file mode 100644 index 0000000..1c6e0da --- /dev/null +++ b/js/src/jit-test/tests/basic/testSetProtoRegeneratesObjectShape.js @@ -0,0 +1,24 @@ +function testSetProtoRegeneratesObjectShape() +{ + var f = function() {}; + var g = function() {}; + g.prototype.__proto__ = {}; + + function iq(obj) + { + for (var i = 0; i < 10; ++i) + "" + obj.prototype; + } + + iq(f); + iq(f); + iq(f); + iq(f); + iq(g); + + if (shapeOf(f.prototype) === shapeOf(g.prototype)) + return "object shapes same after proto of one is changed"; + + return true; +} +assertEq(testSetProtoRegeneratesObjectShape(), true); diff --git a/js/src/jit-test/tests/basic/testSetelemWithFloatIndex.js b/js/src/jit-test/tests/basic/testSetelemWithFloatIndex.js new file mode 100644 index 0000000..20ec897 --- /dev/null +++ b/js/src/jit-test/tests/basic/testSetelemWithFloatIndex.js @@ -0,0 +1,4 @@ +var x, a = {}; +for (var i = 0; i < 9; i++) + x = a[-3.5] = "ok"; +assertEq(x, "ok"); diff --git a/js/src/jit-test/tests/basic/testSettingWatchPointOnReadOnlyProp.js b/js/src/jit-test/tests/basic/testSettingWatchPointOnReadOnlyProp.js new file mode 100644 index 0000000..78c281f --- /dev/null +++ b/js/src/jit-test/tests/basic/testSettingWatchPointOnReadOnlyProp.js @@ -0,0 +1,7 @@ +for (var i = 0; i < 5; ++i) { + var o = {} + Object.defineProperty(o, 'x', { value:"cow", writable:false }); + var r = o.watch('x', function() {}); + assertEq(r, undefined); + o.x = 4; +} diff --git a/js/src/jit-test/tests/basic/testShiftLeft.js b/js/src/jit-test/tests/basic/testShiftLeft.js new file mode 100644 index 0000000..4a7f5d9 --- /dev/null +++ b/js/src/jit-test/tests/basic/testShiftLeft.js @@ -0,0 +1,38 @@ +// |jit-test| TMFLAGS: full,fragprofile,treevis; valgrind + +/* Test the proper operation of the left shift operator. This is especially + * important on ARM as an explicit mask is required at the native instruction + * level. */ + +load(libdir + 'range.js'); + +function testShiftLeft() +{ + var r = []; + var i = 0; + var j = 0; + + var shifts = [0,1,7,8,15,16,23,24,31]; + + /* Samples from the simple shift range. */ + for (i = 0; i < shifts.length; i++) + r[j++] = 1 << shifts[i]; + + /* Samples outside the normal shift range. */ + for (i = 0; i < shifts.length; i++) + r[j++] = 1 << (shifts[i] + 32); + + /* Samples far outside the normal shift range. */ + for (i = 0; i < shifts.length; i++) + r[j++] = 1 << (shifts[i] + 224); + for (i = 0; i < shifts.length; i++) + r[j++] = 1 << (shifts[i] + 256); + + return r.join(","); +} + +assertEq(testShiftLeft(), + "1,2,128,256,32768,65536,8388608,16777216,-2147483648,"+ + "1,2,128,256,32768,65536,8388608,16777216,-2147483648,"+ + "1,2,128,256,32768,65536,8388608,16777216,-2147483648,"+ + "1,2,128,256,32768,65536,8388608,16777216,-2147483648"); diff --git a/js/src/jit-test/tests/basic/testShiftRightArithmetic.js b/js/src/jit-test/tests/basic/testShiftRightArithmetic.js new file mode 100644 index 0000000..7268dc0 --- /dev/null +++ b/js/src/jit-test/tests/basic/testShiftRightArithmetic.js @@ -0,0 +1,44 @@ +/* Test the proper operation of the arithmetic right shift operator. This is + * especially important on ARM as an explicit mask is required at the native + * instruction level. */ + +load(libdir + 'range.js'); + +/* Test different combinations of literals/variables. */ +var s = 4; +var t = 100; +assertEq(42 >> s, 2); +assertEq(s >> 1, 2); +assertEq(23 >> 3, 2); +assertEq(t >> s, 6); + + +function testShiftRightArithmetic() +{ + var r = []; + var i = 0; + var j = 0; + + var shifts = [0,1,7,8,15,16,23,24,31]; + + /* Samples from the simple shift range. */ + for (i = 0; i < shifts.length; i++) + r[j++] = -2147483648 >> shifts[i]; + + /* Samples outside the normal shift range. */ + for (i = 0; i < shifts.length; i++) + r[j++] = -2147483648 >> (shifts[i] + 32); + + /* Samples far outside the normal shift range. */ + for (i = 0; i < shifts.length; i++) + r[j++] = -2147483648 >> (shifts[i] + 224); + for (i = 0; i < shifts.length; i++) + r[j++] = -2147483648 >> (shifts[i] + 256); + + return r.join(","); +} +assertEq(testShiftRightArithmetic(), + "-2147483648,-1073741824,-16777216,-8388608,-65536,-32768,-256,-128,-1,"+ + "-2147483648,-1073741824,-16777216,-8388608,-65536,-32768,-256,-128,-1,"+ + "-2147483648,-1073741824,-16777216,-8388608,-65536,-32768,-256,-128,-1,"+ + "-2147483648,-1073741824,-16777216,-8388608,-65536,-32768,-256,-128,-1"); diff --git a/js/src/jit-test/tests/basic/testShiftRightLogical.js b/js/src/jit-test/tests/basic/testShiftRightLogical.js new file mode 100644 index 0000000..de2dda6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testShiftRightLogical.js @@ -0,0 +1,38 @@ +/* Test the proper operation of the logical right shift operator. This is + * especially important on ARM as an explicit mask is required at the native + * instruction level. */ + +load(libdir + 'range.js'); + +function testShiftRightLogical() +{ + var r = []; + var i = 0; + var j = 0; + + var shifts = [0,1,7,8,15,16,23,24,31]; + + /* Samples from the simple shift range. */ + for (i = 0; i < shifts.length; i++) + r[j++] = -2147483648 >>> shifts[i]; + + /* Samples outside the normal shift range. */ + for (i = 0; i < shifts.length; i++) + r[j++] = -2147483648 >>> (shifts[i] + 32); + + /* Samples far outside the normal shift range. */ + for (i = 0; i < shifts.length; i++) + r[j++] = -2147483648 >>> (shifts[i] + 224); + for (i = 0; i < shifts.length; i++) + r[j++] = -2147483648 >>> (shifts[i] + 256); + + return r.join(","); +} +/* Note: Arguments to the ">>>" operator are converted to unsigned 32-bit + * integers during evaluation. As a result, -2147483648 >>> 0 evaluates to the + * unsigned interpretation of the same value, which is 2147483648. */ +assertEq(testShiftRightLogical(), + "2147483648,1073741824,16777216,8388608,65536,32768,256,128,1,"+ + "2147483648,1073741824,16777216,8388608,65536,32768,256,128,1,"+ + "2147483648,1073741824,16777216,8388608,65536,32768,256,128,1,"+ + "2147483648,1073741824,16777216,8388608,65536,32768,256,128,1"); diff --git a/js/src/jit-test/tests/basic/testSideExitInConstructor.js b/js/src/jit-test/tests/basic/testSideExitInConstructor.js new file mode 100644 index 0000000..d46543e --- /dev/null +++ b/js/src/jit-test/tests/basic/testSideExitInConstructor.js @@ -0,0 +1,39 @@ +// |jit-test| TMFLAGS: full,fragprofile,treevis; valgrind + +function testSideExitInConstructor() { + var FCKConfig = {}; + FCKConfig.CoreStyles = + { + 'Bold': { }, + 'Italic': { }, + 'FontFace': { }, + 'Size' : + { + Overrides: [ ] + }, + + 'Color' : + { + Element: '', + Styles: { }, + Overrides: [ ] + }, + 'BackColor': { + Element : '', + Styles : { 'background-color' : '' } + }, + + }; + var FCKStyle = function(A) { + A.Element; + }; + + var pass = true; + for (var s in FCKConfig.CoreStyles) { + var x = new FCKStyle(FCKConfig.CoreStyles[s]); + if (!x) + pass = false; + } + return pass; +} +assertEq(testSideExitInConstructor(), true); diff --git a/js/src/jit-test/tests/basic/testSlowArrayLength.js b/js/src/jit-test/tests/basic/testSlowArrayLength.js new file mode 100644 index 0000000..1e8fc3b --- /dev/null +++ b/js/src/jit-test/tests/basic/testSlowArrayLength.js @@ -0,0 +1,15 @@ +function testSlowArrayLength() +{ + var counter = 0; + var a = []; + a[10000000 - 1] = 0; + for (var i = 0; i < a.length; i++) + counter++; + return counter; +} +assertEq(testSlowArrayLength(), 10000000); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + sideExitIntoInterpreter: 1 +}); diff --git a/js/src/jit-test/tests/basic/testSlowArrayPop.js b/js/src/jit-test/tests/basic/testSlowArrayPop.js new file mode 100644 index 0000000..6c55a0c --- /dev/null +++ b/js/src/jit-test/tests/basic/testSlowArrayPop.js @@ -0,0 +1,12 @@ +function testSlowArrayPop() { + var a = []; + for (var i = 0; i < RUNLOOP; i++) + a[i] = [0]; + a[RUNLOOP-1].__defineGetter__("0", function () { return 'xyzzy'; }); + + var last; + for (var i = 0; i < RUNLOOP; i++) + last = a[i].pop(); // reenters interpreter in getter + return last; +} +assertEq(testSlowArrayPop(), 'xyzzy'); diff --git a/js/src/jit-test/tests/basic/testSlowArrayPopMultiFrame.js b/js/src/jit-test/tests/basic/testSlowArrayPopMultiFrame.js new file mode 100644 index 0000000..3a5fb8d --- /dev/null +++ b/js/src/jit-test/tests/basic/testSlowArrayPopMultiFrame.js @@ -0,0 +1,24 @@ +// Same thing but it needs to reconstruct multiple stack frames (so, +// multiple functions called inside the loop) +function testSlowArrayPopMultiFrame() { + var a = []; + for (var i = 0; i < RUNLOOP; i++) + a[i] = [0]; + a[RUNLOOP-1].__defineGetter__("0", function () { return 23; }); + + function child(a, i) { + return a[i].pop(); // reenters interpreter in getter + } + function parent(a, i) { + return child(a, i); + } + function gramps(a, i) { + return parent(a, i); + } + + var last; + for (var i = 0; i < RUNLOOP; i++) + last = gramps(a, i); + return last; +} +assertEq(testSlowArrayPopMultiFrame(), 23); diff --git a/js/src/jit-test/tests/basic/testSlowArrayPopNestedTrees.js b/js/src/jit-test/tests/basic/testSlowArrayPopNestedTrees.js new file mode 100644 index 0000000..ae137c3 --- /dev/null +++ b/js/src/jit-test/tests/basic/testSlowArrayPopNestedTrees.js @@ -0,0 +1,36 @@ +// Same thing but nested trees, each reconstructing one or more stack frames +// (so, several functions with loops, such that the loops end up being +// nested though they are not lexically nested) + +function testSlowArrayPopNestedTrees() { + var a = []; + for (var i = 0; i < RUNLOOP; i++) + a[i] = [0]; + a[RUNLOOP-1].__defineGetter__("0", function () { return 3.14159 }); + + function child(a, i, j, k) { + var last = 2.71828; + for (var l = 0; l < RUNLOOP; l++) + if (i == RUNLOOP-1 && j == RUNLOOP-1 && k == RUNLOOP-1) + last = a[l].pop(); // reenters interpreter in getter + return last; + } + function parent(a, i, j) { + var last; + for (var k = 0; k < RUNLOOP; k++) + last = child(a, i, j, k); + return last; + } + function gramps(a, i) { + var last; + for (var j = 0; j < RUNLOOP; j++) + last = parent(a, i, j); + return last; + } + + var last; + for (var i = 0; i < RUNLOOP; i++) + last = gramps(a, i); + return last; +} +assertEq(testSlowArrayPopNestedTrees(), 3.14159); diff --git a/js/src/jit-test/tests/basic/testSlowNativeBail.js b/js/src/jit-test/tests/basic/testSlowNativeBail.js new file mode 100644 index 0000000..f7a1443 --- /dev/null +++ b/js/src/jit-test/tests/basic/testSlowNativeBail.js @@ -0,0 +1,10 @@ +function testSlowNativeBail() { + var a = ['0', '1', '2', '3', '+']; + try { + for (var i = 0; i < a.length; i++) + new RegExp(a[i]); + } catch (exc) { + assertEq(""+exc, "SyntaxError: invalid quantifier"); + } +} +testSlowNativeBail(); diff --git a/js/src/jit-test/tests/basic/testSlowNativeCtor.js b/js/src/jit-test/tests/basic/testSlowNativeCtor.js new file mode 100644 index 0000000..345546a --- /dev/null +++ b/js/src/jit-test/tests/basic/testSlowNativeCtor.js @@ -0,0 +1,7 @@ +delete _quit; + +function testSlowNativeCtor() { + for (var i = 0; i < 4; i++) + new Date().valueOf(); +} +testSlowNativeCtor(); diff --git a/js/src/jit-test/tests/basic/testSlowNativeWithNullThis.js b/js/src/jit-test/tests/basic/testSlowNativeWithNullThis.js new file mode 100644 index 0000000..0d300f2 --- /dev/null +++ b/js/src/jit-test/tests/basic/testSlowNativeWithNullThis.js @@ -0,0 +1,6 @@ +x = 0 +for (a = 0; a < 3; a++) { + (function () { + return Float64Array + })()(x, 1) +} diff --git a/js/src/jit-test/tests/basic/testStackQuotaExhausted.js b/js/src/jit-test/tests/basic/testStackQuotaExhausted.js new file mode 100644 index 0000000..f65957a --- /dev/null +++ b/js/src/jit-test/tests/basic/testStackQuotaExhausted.js @@ -0,0 +1,29 @@ +const numFatArgs = Math.pow(2,19) - 1024; + +function fun(x) { + if (x <= 0) + return 0; + return fun(x-1); +} + +function fatStack() { + return fun(10000); +} + +function assertRightFailure(e) { + assertEq(e.toString() == "InternalError: script stack space quota is exhausted" || + e.toString() == "InternalError: too much recursion", + true); +} + +exception = false; +try { + fatStack.apply(null, new Array(numFatArgs)); +} catch (e) { + assertRightFailure(e); + exception = true; +} +assertEq(exception, true); + +// No more trace recursion w/ JM +checkStats({traceCompleted:0}); diff --git a/js/src/jit-test/tests/basic/testStaticsInRegExp.js b/js/src/jit-test/tests/basic/testStaticsInRegExp.js new file mode 100644 index 0000000..cef69cd --- /dev/null +++ b/js/src/jit-test/tests/basic/testStaticsInRegExp.js @@ -0,0 +1,9 @@ +'abcdef'.replace(/a(\w+)c/, function() { + assertEq(RegExp.lastMatch, 'abc'); + '123456'.replace(/1(\d+)3/, function() { + assertEq(RegExp.lastMatch, '123'); + }); + assertEq(RegExp.lastMatch, '123'); +}); +assertEq(RegExp.lastMatch, 'abc'); + diff --git a/js/src/jit-test/tests/basic/testStrict.js b/js/src/jit-test/tests/basic/testStrict.js new file mode 100644 index 0000000..583a2b0 --- /dev/null +++ b/js/src/jit-test/tests/basic/testStrict.js @@ -0,0 +1,11 @@ +function testStrict() { + var n = 10, a = []; + for (var i = 0; i < 10; ++i) { + a[0] = (n === 10); + a[1] = (n !== 10); + a[2] = (n === null); + a[3] = (n == null); + } + return a.join(","); +} +assertEq(testStrict(), "true,false,false,false"); diff --git a/js/src/jit-test/tests/basic/testString.js b/js/src/jit-test/tests/basic/testString.js new file mode 100644 index 0000000..b8a5021 --- /dev/null +++ b/js/src/jit-test/tests/basic/testString.js @@ -0,0 +1,18 @@ +function testString() { + var q; + for (var i = 0; i <= RUNLOOP; ++i) { + q = []; + q.push(String(void 0)); + q.push(String(true)); + q.push(String(5)); + q.push(String(5.5)); + q.push(String("5")); + q.push(String([5])); + } + return q.join(","); +} +assertEq(testString(), "undefined,true,5,5.5,5,5"); +checkStats({ + recorderStarted: 1, + sideExitIntoInterpreter: 1 +}); diff --git a/js/src/jit-test/tests/basic/testStringConstructorWithExtraArg.js b/js/src/jit-test/tests/basic/testStringConstructorWithExtraArg.js new file mode 100644 index 0000000..b4986c5 --- /dev/null +++ b/js/src/jit-test/tests/basic/testStringConstructorWithExtraArg.js @@ -0,0 +1,6 @@ +function testStringConstructorWithExtraArg() { + for (let i = 0; i < 5; ++i) + new String(new String(), 2); + return "ok"; +} +assertEq(testStringConstructorWithExtraArg(), "ok"); diff --git a/js/src/jit-test/tests/basic/testStringIncrement.js b/js/src/jit-test/tests/basic/testStringIncrement.js new file mode 100644 index 0000000..65f7de5 --- /dev/null +++ b/js/src/jit-test/tests/basic/testStringIncrement.js @@ -0,0 +1,27 @@ +var a, b; + +function f(str) { + var n; + var k; + for (var i = 0; i < 2*RUNLOOP; ++i) { + n = str; + k = n++; + if (k) { } + } + return [k, n]; +} + +[a, b] = f("10"); +assertEq(a, 10); +assertEq(b, 11); + +[a, b] = f("5"); +assertEq(a, 5); +assertEq(b, 6); + +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceCompleted: 1, + traceTriggered: 2 +}); diff --git a/js/src/jit-test/tests/basic/testStringLengthNoTinyId.js b/js/src/jit-test/tests/basic/testStringLengthNoTinyId.js new file mode 100644 index 0000000..e08f5a6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testStringLengthNoTinyId.js @@ -0,0 +1,64 @@ +// Second testPropagatedFunArgs test -- this is a crash-test. +(function () { + var escapee; + + function testPropagatedFunArgs() + { + const magic = 42; + + var win = this; + var res = [], q = []; + function addEventListener(name, func, flag) { + q.push(func); + } + + var pageInfo = "pageInfo", obs; + addEventListener("load", handleLoad, true); + + var observer = { + observe: function(win, topic, data) { + // obs.removeObserver(observer, "page-info-dialog-loaded"); + handlePageInfo(); + } + }; + + function handleLoad() { + //pageInfo = { toString: function() { return "pageInfo"; } }; + obs = { addObserver: function (obs, topic, data) { obs.observe(win, topic, data); } }; + obs.addObserver(observer, "page-info-dialog-loaded", false); + } + + function handlePageInfo() { + res.push(pageInfo); + function $(aId) { + function notSafe() { + return magic; + } + notSafe(); + res.push(pageInfo); + }; + var feedTab = $("feedTab"); + } + + escapee = q[0]; + return res.join(','); + } + + testPropagatedFunArgs(); + + escapee(); +})(); + +function testStringLengthNoTinyId() +{ + var x = "unset"; + var t = new String(""); + for (var i = 0; i < 5; i++) + x = t["-1"]; + + var r = "t['-1'] is " + x; + t["-1"] = "foo"; + r += " when unset, '" + t["-1"] + "' when set"; + return r; +} +assertEq(testStringLengthNoTinyId(), "t['-1'] is undefined when unset, 'foo' when set"); diff --git a/js/src/jit-test/tests/basic/testStringObjectLength.js b/js/src/jit-test/tests/basic/testStringObjectLength.js new file mode 100644 index 0000000..d908ff6 --- /dev/null +++ b/js/src/jit-test/tests/basic/testStringObjectLength.js @@ -0,0 +1,7 @@ +function testStringObjectLength() { + var x = new String("foo"), y = 0; + for (var i = 0; i < 10; ++i) + y = x.length; + return y; +} +assertEq(testStringObjectLength(), 3); diff --git a/js/src/jit-test/tests/basic/testStringPropIncrement.js b/js/src/jit-test/tests/basic/testStringPropIncrement.js new file mode 100644 index 0000000..4832d90 --- /dev/null +++ b/js/src/jit-test/tests/basic/testStringPropIncrement.js @@ -0,0 +1,16 @@ +function f() { + var o = { n: "" }; + for (var i = 0; i < 2*RUNLOOP; ++i) { + o.n = ""; + if (o.n++) { } + } +} + +f(); + +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceCompleted: 1, + traceTriggered: 1 +}); \ No newline at end of file diff --git a/js/src/jit-test/tests/basic/testStringResolve.js b/js/src/jit-test/tests/basic/testStringResolve.js new file mode 100644 index 0000000..348087b --- /dev/null +++ b/js/src/jit-test/tests/basic/testStringResolve.js @@ -0,0 +1,9 @@ +function testStringResolve() { + var x = 0; + for each (let d in [new String('q'), new String('q'), new String('q')]) { + if (("" + (0 in d)) === "true") + x++; + } + return x; +} +assertEq(testStringResolve(), 3); diff --git a/js/src/jit-test/tests/basic/testStringToInt32.js b/js/src/jit-test/tests/basic/testStringToInt32.js new file mode 100644 index 0000000..ca1ca34 --- /dev/null +++ b/js/src/jit-test/tests/basic/testStringToInt32.js @@ -0,0 +1,6 @@ +function testStringToInt32() { + var s = ""; + for (let j = 0; j < 5; ++j) s += ("1e+81" ^ 3); + return s; +} +assertEq(testStringToInt32(), "33333"); diff --git a/js/src/jit-test/tests/basic/testStringToNumber.js b/js/src/jit-test/tests/basic/testStringToNumber.js new file mode 100644 index 0000000..e3e2fe7 --- /dev/null +++ b/js/src/jit-test/tests/basic/testStringToNumber.js @@ -0,0 +1,47 @@ +function convertToInt(str) { + return str | 0; +} + +function convertToIntOnTrace(str) { + var z; + for (var i = 0; i < RUNLOOP; ++i) { + z = str | 0; + } + return z; +} + +function convertToDouble(str) { + return str * 1.5; +} + +function convertToDoubleOnTrace(str) { + var z; + for (var i = 0; i < RUNLOOP; ++i) { + z = str * 1.5; + } + return z; +} + +assertEq(convertToInt("0x10"), 16); +assertEq(convertToInt("-0x10"), 0); + +assertEq(convertToIntOnTrace("0x10"), 16); +checkStats({ + traceTriggered: 1 +}); +assertEq(convertToIntOnTrace("-0x10"), 0); +checkStats({ + traceTriggered: 2 +}); + +assertEq(convertToDouble("0x10"), 24); +assertEq(convertToDouble("-0x10"), NaN); + +assertEq(convertToDoubleOnTrace("0x10"), 24); +checkStats({ + traceTriggered: 3 +}); +assertEq(convertToDoubleOnTrace("-0x10"), NaN); +checkStats({ + traceTriggered: 4 +}); diff --git a/js/src/jit-test/tests/basic/testStringify.js b/js/src/jit-test/tests/basic/testStringify.js new file mode 100644 index 0000000..003e4fd --- /dev/null +++ b/js/src/jit-test/tests/basic/testStringify.js @@ -0,0 +1,20 @@ +function testStringify() { + var t = true, f = false, u = undefined, n = 5, d = 5.5, s = "x"; + var a = []; + for (var i = 0; i < 10; ++i) { + a[0] = "" + t; + a[1] = t + ""; + a[2] = "" + f; + a[3] = f + ""; + a[4] = "" + u; + a[5] = u + ""; + a[6] = "" + n; + a[7] = n + ""; + a[8] = "" + d; + a[9] = d + ""; + a[10] = "" + s; + a[11] = s + ""; + } + return a.join(","); +} +assertEq(testStringify(), "true,true,false,false,undefined,undefined,5,5,5.5,5.5,x,x"); diff --git a/js/src/jit-test/tests/basic/testSubstring.js b/js/src/jit-test/tests/basic/testSubstring.js new file mode 100644 index 0000000..5916c23 --- /dev/null +++ b/js/src/jit-test/tests/basic/testSubstring.js @@ -0,0 +1,7 @@ +function testSubstring() { + for (var i = 0; i < 5; ++i) { + actual = "".substring(5); + } + return actual; +} +assertEq(testSubstring(), ""); diff --git a/js/src/jit-test/tests/basic/testSuppressDeletedProperty.js b/js/src/jit-test/tests/basic/testSuppressDeletedProperty.js new file mode 100644 index 0000000..a867b35 --- /dev/null +++ b/js/src/jit-test/tests/basic/testSuppressDeletedProperty.js @@ -0,0 +1,8 @@ +var obj = { a:1, b:1, c:1, d:1, e:1, f:1, g:1 }; +var sum = 0; +for each (var i in obj) { + sum += i; + delete obj.f; +} + +// this isn't even implemented to work yet; just don't crash or iloop diff --git a/js/src/jit-test/tests/basic/testSwitch.js b/js/src/jit-test/tests/basic/testSwitch.js new file mode 100644 index 0000000..c2127d4 --- /dev/null +++ b/js/src/jit-test/tests/basic/testSwitch.js @@ -0,0 +1,25 @@ +function testSwitch() { + var x = 0; + var ret = 0; + for (var i = 0; i < 100; ++i) { + switch (x) { + case 0: + ret += 1; + break; + case 1: + ret += 2; + break; + case 2: + ret += 3; + break; + case 3: + ret += 4; + break; + default: + x = 0; + } + x++; + } + return ret; +} +assertEq(testSwitch(), 226); diff --git a/js/src/jit-test/tests/basic/testSwitchString.js b/js/src/jit-test/tests/basic/testSwitchString.js new file mode 100644 index 0000000..323763a --- /dev/null +++ b/js/src/jit-test/tests/basic/testSwitchString.js @@ -0,0 +1,28 @@ +function testSwitchString() { + var x = "asdf"; + var ret = 0; + for (var i = 0; i < 100; ++i) { + switch (x) { + case "asdf": + x = "asd"; + ret += 1; + break; + case "asd": + x = "as"; + ret += 2; + break; + case "as": + x = "a"; + ret += 3; + break; + case "a": + x = "foo"; + ret += 4; + break; + default: + x = "asdf"; + } + } + return ret; +} +assertEq(testSwitchString(), 200); diff --git a/js/src/jit-test/tests/basic/testSwitchUndefined.js b/js/src/jit-test/tests/basic/testSwitchUndefined.js new file mode 100644 index 0000000..44d27ca --- /dev/null +++ b/js/src/jit-test/tests/basic/testSwitchUndefined.js @@ -0,0 +1,15 @@ +function testSwitchUndefined() +{ + var x = undefined; + var y = 0; + for (var i = 0; i < 5; i++) + { + switch (x) + { + default: + y++; + } + } + return y; +} +assertEq(testSwitchUndefined(), 5); diff --git a/js/src/jit-test/tests/basic/testTableSwitch1.js b/js/src/jit-test/tests/basic/testTableSwitch1.js new file mode 100644 index 0000000..fa394a4 --- /dev/null +++ b/js/src/jit-test/tests/basic/testTableSwitch1.js @@ -0,0 +1,22 @@ +function testTableSwitch1() { + var x = 'miss'; + var i, j = 0; + for (i = 0; i < RUNLOOP + 10; i++) { + switch (x) { + case 1: case 2: case 3: case 4: case 5: throw "FAIL"; + default: j++; + } + } + assertEq(i, j); +} + +testTableSwitch1(); + +if (HAVE_TM && jitstats.archIsIA32) { + checkStats({ + recorderStarted: 1, + sideExitIntoInterpreter: 1, + recorderAborted: 0, + traceCompleted: 1 + }); +} diff --git a/js/src/jit-test/tests/basic/testTableSwitch2.js b/js/src/jit-test/tests/basic/testTableSwitch2.js new file mode 100644 index 0000000..9a350fd --- /dev/null +++ b/js/src/jit-test/tests/basic/testTableSwitch2.js @@ -0,0 +1,27 @@ +function testTableSwitch2() { + var arr = [2, 2, 2, 2, 2, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5]; + var s = ''; + for (var i = 0; i < arr.length; i++) { + switch (arr[i]) { + case 0: case 1: case 3: case 4: + throw "FAIL"; + case 2: + s += '2'; + break; + case 5: + s += '5'; + } + } + assertEq(s, arr.join("")); +} + +testTableSwitch2(); + +if (HAVE_TM && jitstats.archIsIA32) { + checkStats({ + recorderStarted: 1, + sideExitIntoInterpreter: 4, + recorderAborted: 0, + traceCompleted: 3 + }); +} diff --git a/js/src/jit-test/tests/basic/testThinForEach.js b/js/src/jit-test/tests/basic/testThinForEach.js new file mode 100644 index 0000000..85e5ca2 --- /dev/null +++ b/js/src/jit-test/tests/basic/testThinForEach.js @@ -0,0 +1,10 @@ +function testThinForEach() { + var a = ["red"]; + var n = 0; + for (var i = 0; i < 10; i++) + for each (var v in a) + if (v) + n++; + return n; +} +assertEq(testThinForEach(), 10); diff --git a/js/src/jit-test/tests/basic/testThinLoopDemote.js b/js/src/jit-test/tests/basic/testThinLoopDemote.js new file mode 100644 index 0000000..6feb063 --- /dev/null +++ b/js/src/jit-test/tests/basic/testThinLoopDemote.js @@ -0,0 +1,20 @@ +function testThinLoopDemote() { + function f() + { + var k = 1; + for (var n = 0; n < 4; n++) { + k = (k * 10); + } + return k; + } + f(); + return f(); +} +assertEq(testThinLoopDemote(), 10000); +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceCompleted: 1, + traceTriggered: 2, + unstableLoopVariable: 0 +}); diff --git a/js/src/jit-test/tests/basic/testThrowingObjectEqUndefined.js b/js/src/jit-test/tests/basic/testThrowingObjectEqUndefined.js new file mode 100644 index 0000000..af20161 --- /dev/null +++ b/js/src/jit-test/tests/basic/testThrowingObjectEqUndefined.js @@ -0,0 +1,18 @@ +function testThrowingObjectEqUndefined() +{ + try + { + var obj = { toString: function() { throw 0; } }; + for (var i = 0; i < 5; i++) + "" + (obj == undefined); + return i === 5; + } + catch (e) + { + return "" + e; + } +} +assertEq(testThrowingObjectEqUndefined(), true); +checkStats({ + sideExitIntoInterpreter: 1 +}); diff --git a/js/src/jit-test/tests/basic/testToLocaleString.js b/js/src/jit-test/tests/basic/testToLocaleString.js new file mode 100644 index 0000000..158e08b --- /dev/null +++ b/js/src/jit-test/tests/basic/testToLocaleString.js @@ -0,0 +1,2 @@ +var str = (3.14).toLocaleString(); +assertEq(str[str.length-1], "4"); \ No newline at end of file diff --git a/js/src/jit-test/tests/basic/testToStringBeforeValueOf.js b/js/src/jit-test/tests/basic/testToStringBeforeValueOf.js new file mode 100644 index 0000000..ac35541 --- /dev/null +++ b/js/src/jit-test/tests/basic/testToStringBeforeValueOf.js @@ -0,0 +1,13 @@ +function testToStringBeforeValueOf() +{ + var o = {toString: function() { return "s"; }, valueOf: function() { return "v"; } }; + var a = []; + for (var i = 0; i < 10; i++) + a.push(String(o)); + return a.join(","); +} +assertEq(testToStringBeforeValueOf(), "s,s,s,s,s,s,s,s,s,s"); +checkStats({ + recorderStarted: 1, + sideExitIntoInterpreter: 1 +}); diff --git a/js/src/jit-test/tests/basic/testToUpperToLower.js b/js/src/jit-test/tests/basic/testToUpperToLower.js new file mode 100644 index 0000000..4bd78f3 --- /dev/null +++ b/js/src/jit-test/tests/basic/testToUpperToLower.js @@ -0,0 +1,9 @@ +function testToUpperToLower() { + var s = "Hello", s1, s2; + for (i = 0; i < 100; ++i) { + s1 = s.toLowerCase(); + s2 = s.toUpperCase(); + } + return s1 + s2; +} +assertEq(testToUpperToLower(), "helloHELLO"); diff --git a/js/src/jit-test/tests/basic/testTrueShiftTrue.js b/js/src/jit-test/tests/basic/testTrueShiftTrue.js new file mode 100644 index 0000000..44c1290 --- /dev/null +++ b/js/src/jit-test/tests/basic/testTrueShiftTrue.js @@ -0,0 +1,16 @@ +// Test no assert or crash from outer recorders (bug 465145) +function testBug465145() { + this.__defineSetter__("x", function(){}); + this.watch("x", function(){}); + y = this; + for (var z = 0; z < 2; ++z) { x = y }; + this.__defineSetter__("x", function(){}); + for (var z = 0; z < 2; ++z) { x = y }; +} + +function testTrueShiftTrue() { + var a = new Array(5); + for (var i=0;i<5;++i) a[i] = "" + (true << true); + return a.join(","); +} +assertEq(testTrueShiftTrue(), "2,2,2,2,2"); diff --git a/js/src/jit-test/tests/basic/testTypeUnstableForIn.js b/js/src/jit-test/tests/basic/testTypeUnstableForIn.js new file mode 100644 index 0000000..0f6b10b --- /dev/null +++ b/js/src/jit-test/tests/basic/testTypeUnstableForIn.js @@ -0,0 +1,10 @@ +function testTypeUnstableForIn() { + var a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; + var x = 0; + for (var i in a) { + i = parseInt(i); + x++; + } + return x; +} +assertEq(testTypeUnstableForIn(), 16); diff --git a/js/src/jit-test/tests/basic/testTypedArrayPunning.js b/js/src/jit-test/tests/basic/testTypedArrayPunning.js new file mode 100644 index 0000000..59f6b74 --- /dev/null +++ b/js/src/jit-test/tests/basic/testTypedArrayPunning.js @@ -0,0 +1,42 @@ +function testNonCanonicalNan() +{ + const bytes = 128; + var buf = new ArrayBuffer(bytes); + + /* create an array of non-canonical double nans */ + var ui8arr = new Uint8Array(buf); + for (var i = 0; i < ui8arr.length; ++i) + ui8arr[i] = 0xff; + + var dblarr = new Float64Array(buf); + assertEq(dblarr.length, bytes / 8); + + /* ensure they are canonicalized */ + for (var i = 0; i < dblarr.length; ++i) { + var asstr = dblarr[i] + ""; + var asnum = dblarr[i] + 0.0; + assertEq(asstr, "NaN"); + assertEq(asnum, NaN); + } + + /* create an array of non-canonical float nans */ + for (var i = 0; i < ui8arr.length; i += 4) { + ui8arr[i+0] = 0xffff; + ui8arr[i+1] = 0xffff; + ui8arr[i+2] = 0xffff; + ui8arr[i+3] = 0xffff; + } + + var fltarr = new Float32Array(buf); + assertEq(fltarr.length, bytes / 4); + + /* ensure they are canonicalized */ + for (var i = 0; i < fltarr.length; ++i) { + var asstr = fltarr[i] + ""; + var asnum = fltarr[i] + 0.0; + assertEq(asstr, "NaN"); + assertEq(asnum, NaN); + } +} + +testNonCanonicalNan(); diff --git a/js/src/jit-test/tests/basic/testTypedArrays.js b/js/src/jit-test/tests/basic/testTypedArrays.js new file mode 100644 index 0000000..485d113 --- /dev/null +++ b/js/src/jit-test/tests/basic/testTypedArrays.js @@ -0,0 +1,104 @@ +function testBasicTypedArrays() +{ + var ar, aridx, idx; + + var a = new Uint8Array(16); + var b = new Uint16Array(16); + var c = new Uint32Array(16); + var d = new Int8Array(16); + var e = new Int16Array(16); + var f = new Int32Array(16); + + var g = new Float32Array(16); + var h = new Float64Array(16); + + var iarrays = [ a, b, c, d, e, f ]; + for (aridx = 0; aridx < iarrays.length; ++aridx) { + ar = iarrays[aridx]; + + for (idx = 0; idx < ar.length-4; ++idx) { + ar[idx] = 22; + ar[idx+1] = 12.7; + ar[idx+2] = "99"; + ar[idx+3] = { k: "thing" }; + ar[idx+4] = Infinity; + } + + assertEq(ar[ar.length-5], 22); + assertEq(ar[ar.length-4], 12); + assertEq(ar[ar.length-3], 99); + assertEq(ar[ar.length-2], 0); + assertEq(ar[ar.length-1], 0); + } + + var farrays = [ g, h ]; + for (aridx = 0; aridx < farrays.length; ++aridx) { + ar = farrays[aridx]; + + for (idx = 0; idx < ar.length-4; ++idx) { + ar[idx] = 22; + ar[idx+1] = 12.25; + ar[idx+2] = "99"; + ar[idx+3] = { k: "thing" }; + ar[idx+4] = Infinity; + } + + assertEq(ar[ar.length-5], 22); + assertEq(ar[ar.length-4], 12.25); + assertEq(ar[ar.length-3], 99); + assertEq(!(ar[ar.length-2] == ar[ar.length-2]), true); + assertEq(ar[ar.length-1], Infinity); + } +} + +function testSpecialTypedArrays() +{ + var ar, aridx, idx; + + ar = new Uint8ClampedArray(16); + for (idx = 0; idx < ar.length-4; ++idx) { + ar[idx] = -200; + ar[idx+1] = 127.5; + ar[idx+2] = 987; + ar[idx+3] = Infinity; + ar[idx+4] = "hello world"; + } + + assertEq(ar[ar.length-5], 0); + assertEq(ar[ar.length-4], 128); + assertEq(ar[ar.length-3], 255); + assertEq(ar[ar.length-2], 255); + assertEq(ar[ar.length-1], 0); +} + +function testTypedArrayOther() +{ + var ar = new Int32Array(16); + for (var i = 0; i < ar.length; ++i) { + ar[i] = i; + } + + for (var i = 0; i < ar.length; ++i) { + // deliberate out of bounds access + ar[i-2] = ar[i+2]; + } + + var t = 0; + for (var i = 0; i < ar.length; ++i) { + t += ar[i]; + } + + assertEq(t, 143); +} + +testBasicTypedArrays(); +testSpecialTypedArrays(); +testTypedArrayOther(); + +checkStats({ + // Note! These are all inner tree growing aborts, because we change + // the array type in the inner loop of the tests. This isn't ideal, + // and if we ever fix these to not report as aborts, this should go + // back to 0. + recorderAborted: 5 +}); diff --git a/js/src/jit-test/tests/basic/testTypeofHole.js b/js/src/jit-test/tests/basic/testTypeofHole.js new file mode 100644 index 0000000..9538dd7 --- /dev/null +++ b/js/src/jit-test/tests/basic/testTypeofHole.js @@ -0,0 +1,8 @@ +function testTypeofHole() { + var a = new Array(6); + a[5] = 3; + for (var i = 0; i < 6; ++i) + a[i] = typeof a[i]; + return a.join(","); +} +assertEq(testTypeofHole(), "undefined,undefined,undefined,undefined,undefined,number"); diff --git a/js/src/jit-test/tests/basic/testUnaryImacros.js b/js/src/jit-test/tests/basic/testUnaryImacros.js new file mode 100644 index 0000000..884d856 --- /dev/null +++ b/js/src/jit-test/tests/basic/testUnaryImacros.js @@ -0,0 +1,26 @@ +function testUnaryImacros() +{ + function checkArg(x) + { + return 1; + } + + var o = { valueOf: checkArg, toString: null }; + var count = 0; + var v = 0; + for (var i = 0; i < 5; i++) + v += +o + -(-o); + + var results = [v === 10 ? "valueOf passed" : "valueOf failed"]; + + o.valueOf = null; + o.toString = checkArg; + + for (var i = 0; i < 5; i++) + v += +o + -(-o); + + results.push(v === 20 ? "toString passed" : "toString failed"); + + return results.join(", "); +} +assertEq(testUnaryImacros(), "valueOf passed, toString passed"); diff --git a/js/src/jit-test/tests/basic/testUndefinedBooleanCmp.js b/js/src/jit-test/tests/basic/testUndefinedBooleanCmp.js new file mode 100644 index 0000000..cd21469 --- /dev/null +++ b/js/src/jit-test/tests/basic/testUndefinedBooleanCmp.js @@ -0,0 +1,24 @@ +function testUndefinedBooleanCmp() +{ + var t = true, f = false, x = []; + for (var i = 0; i < 10; ++i) { + x[0] = t == undefined; + x[1] = t != undefined; + x[2] = t === undefined; + x[3] = t !== undefined; + x[4] = t < undefined; + x[5] = t > undefined; + x[6] = t <= undefined; + x[7] = t >= undefined; + x[8] = f == undefined; + x[9] = f != undefined; + x[10] = f === undefined; + x[11] = f !== undefined; + x[12] = f < undefined; + x[13] = f > undefined; + x[14] = f <= undefined; + x[15] = f >= undefined; + } + return x.join(","); +} +assertEq(testUndefinedBooleanCmp(), "false,true,false,true,false,false,false,false,false,true,false,true,false,false,false,false"); diff --git a/js/src/jit-test/tests/basic/testUndefinedCmp.js b/js/src/jit-test/tests/basic/testUndefinedCmp.js new file mode 100644 index 0000000..48a0dd5 --- /dev/null +++ b/js/src/jit-test/tests/basic/testUndefinedCmp.js @@ -0,0 +1,6 @@ +function testUndefinedCmp() { + var a = false; + for (var j = 0; j < 4; ++j) { if (undefined < false) { a = true; } } + return a; +} +assertEq(testUndefinedCmp(), false); diff --git a/js/src/jit-test/tests/basic/testUndefinedIncrement.js b/js/src/jit-test/tests/basic/testUndefinedIncrement.js new file mode 100644 index 0000000..885b13a --- /dev/null +++ b/js/src/jit-test/tests/basic/testUndefinedIncrement.js @@ -0,0 +1,22 @@ +function f() { + var n; + var k; + for (var i = 0; i < 2*RUNLOOP; ++i) { + n = undefined; + k = n++; + if (k) { } + } + return [k, n]; +} + +var [a, b] = f(); + +assertEq(isNaN(a), true); +assertEq(isNaN(b), true); + +checkStats({ + recorderStarted: 1, + recorderAborted: 0, + traceCompleted: 1, + traceTriggered: 1 +}); diff --git a/js/src/jit-test/tests/basic/testUndefinedPropertyAccess.js b/js/src/jit-test/tests/basic/testUndefinedPropertyAccess.js new file mode 100644 index 0000000..49699eb --- /dev/null +++ b/js/src/jit-test/tests/basic/testUndefinedPropertyAccess.js @@ -0,0 +1,15 @@ +function testUndefinedPropertyAccess() { + var x = [1,2,3]; + var y = {}; + var a = { foo: 1 }; + y.__proto__ = x; + var z = [x, x, x, y, y, y, y, a, a, a]; + var s = ""; + for (var i = 0; i < z.length; ++i) + s += z[i].foo; + return s; +} +assertEq(testUndefinedPropertyAccess(), "undefinedundefinedundefinedundefinedundefinedundefinedundefined111"); +checkStats({ + traceCompleted: 3 +}); diff --git a/js/src/jit-test/tests/basic/testUndemotableBinaryOp.js b/js/src/jit-test/tests/basic/testUndemotableBinaryOp.js new file mode 100644 index 0000000..6fd79cd --- /dev/null +++ b/js/src/jit-test/tests/basic/testUndemotableBinaryOp.js @@ -0,0 +1,6 @@ +function testUndemotableBinaryOp() { + var out = []; + for (let j = 0; j < 5; ++j) { out.push(6 - ((void 0) ^ 0x80000005)); } + return out.join(","); +} +assertEq(testUndemotableBinaryOp(), "2147483649,2147483649,2147483649,2147483649,2147483649"); diff --git a/js/src/jit-test/tests/basic/testUndemoteLateGlobalSlots.js b/js/src/jit-test/tests/basic/testUndemoteLateGlobalSlots.js new file mode 100644 index 0000000..27d98a3 --- /dev/null +++ b/js/src/jit-test/tests/basic/testUndemoteLateGlobalSlots.js @@ -0,0 +1,11 @@ +function testUndemoteLateGlobalSlots() { + for each (aaa in ["", "", 0/0, ""]) { + ++aaa; + for each (bbb in [0, "", aaa, "", 0, "", 0/0]) { + } + } + delete aaa; + delete bbb; + return "ok"; +} +assertEq(testUndemoteLateGlobalSlots(), "ok"); diff --git a/js/src/jit-test/tests/basic/testWeirdDateParse.js b/js/src/jit-test/tests/basic/testWeirdDateParse.js new file mode 100644 index 0000000..85c2a44 --- /dev/null +++ b/js/src/jit-test/tests/basic/testWeirdDateParse.js @@ -0,0 +1,46 @@ +var global = this; +function testWeirdDateParseOuter() +{ + var vDateParts = ["11", "17", "2008"]; + var out = []; + for (var vI = 0; vI < vDateParts.length; vI++) + out.push(testWeirdDateParseInner(vDateParts[vI])); + /* Mutate the global shape so we fall off trace; this causes + * additional oddity */ + global.x = Math.random(); + return out; +} +function testWeirdDateParseInner(pVal) +{ + var vR = 0; + for (var vI = 0; vI < pVal.length; vI++) { + var vC = pVal.charAt(vI); + if ((vC >= '0') && (vC <= '9')) + vR = (vR * 10) + parseInt(vC); + } + return vR; +} +function testWeirdDateParse() { + var result = []; + result.push(testWeirdDateParseInner("11")); + result.push(testWeirdDateParseInner("17")); + result.push(testWeirdDateParseInner("2008")); + result.push(testWeirdDateParseInner("11")); + result.push(testWeirdDateParseInner("17")); + result.push(testWeirdDateParseInner("2008")); + result = result.concat(testWeirdDateParseOuter()); + result = result.concat(testWeirdDateParseOuter()); + result.push(testWeirdDateParseInner("11")); + result.push(testWeirdDateParseInner("17")); + result.push(testWeirdDateParseInner("2008")); + return result.join(","); +} +assertEq(testWeirdDateParse(), "11,17,2008,11,17,2008,11,17,2008,11,17,2008,11,17,2008"); +checkStats({ + recorderStarted: 8, + recorderAborted: 1, + traceCompleted: 7, + traceTriggered: 13, + unstableLoopVariable: 3, + noCompatInnerTrees: 1 +}); diff --git a/js/src/jit-test/tests/basic/testWhileObjectOrNull.js b/js/src/jit-test/tests/basic/testWhileObjectOrNull.js new file mode 100644 index 0000000..51316ae --- /dev/null +++ b/js/src/jit-test/tests/basic/testWhileObjectOrNull.js @@ -0,0 +1,18 @@ +function testWhileObjectOrNull() +{ + try + { + for (var i = 0; i < 3; i++) + { + var o = { p: { p: null } }; + while (o.p) + o = o.p; + } + return "pass"; + } + catch (e) + { + return "threw exception: " + e; + } +} +assertEq(testWhileObjectOrNull(), "pass"); diff --git a/js/src/jit-test/tests/basic/testWhileWithContinue.js b/js/src/jit-test/tests/basic/testWhileWithContinue.js new file mode 100644 index 0000000..6a8e5b5 --- /dev/null +++ b/js/src/jit-test/tests/basic/testWhileWithContinue.js @@ -0,0 +1,10 @@ +// Test using 'while' with 'continue' -- the most ancient, the most powerful, +// the most rare of all coding incantations. + +var i = 0; +while (i < HOTLOOP+4) { + ++i; + continue; +} +assertEq(i, HOTLOOP+4); + diff --git a/js/src/jit-test/tests/basic/testWithAndShadowing.js b/js/src/jit-test/tests/basic/testWithAndShadowing.js new file mode 100644 index 0000000..07922c8 --- /dev/null +++ b/js/src/jit-test/tests/basic/testWithAndShadowing.js @@ -0,0 +1,14 @@ +// see bug 470795 +var o = [{},{},{i:42}] +var i; +var s = []; +for (var j = 0; j < 3; ++j) { + with (o[j]) { + for (i = 0; i < 2; ++i) { + s.push(j); + s.push(i); + } + } +} +assertEq(s.join(), '0,0,0,1,1,0,1,1,2,0,2,1'); + diff --git a/js/src/jit-test/tests/basic/testXMLPropertyNames.js b/js/src/jit-test/tests/basic/testXMLPropertyNames.js new file mode 100644 index 0000000..36b0b31 --- /dev/null +++ b/js/src/jit-test/tests/basic/testXMLPropertyNames.js @@ -0,0 +1,11 @@ +var o = {}; + +o.__defineGetter__(,function(){}); +.(o.__defineGetter__(new QName("foo"), function(){})); + +var i = 0; +for (w in o) { + ++i; +} + +assertEq(i, 2); diff --git a/js/src/jit-test/tests/basic/test_JSOP_ARGCNT.js b/js/src/jit-test/tests/basic/test_JSOP_ARGCNT.js new file mode 100644 index 0000000..6e558a0 --- /dev/null +++ b/js/src/jit-test/tests/basic/test_JSOP_ARGCNT.js @@ -0,0 +1,27 @@ +function test_JSOP_ARGCNT() { + function f0() { return arguments.length; } + function f1() { return arguments.length; } + function f2() { return arguments.length; } + function f3() { return arguments.length; } + function f4() { return arguments.length; } + function f5() { return arguments.length; } + function f6() { return arguments.length; } + function f7() { return arguments.length; } + function f8() { return arguments.length; } + function f9() { return arguments.length; } + var a = []; + for (var i = 0; i < 10; i++) { + a[0] = f0('a'); + a[1] = f1('a','b'); + a[2] = f2('a','b','c'); + a[3] = f3('a','b','c','d'); + a[4] = f4('a','b','c','d','e'); + a[5] = f5('a','b','c','d','e','f'); + a[6] = f6('a','b','c','d','e','f','g'); + a[7] = f7('a','b','c','d','e','f','g','h'); + a[8] = f8('a','b','c','d','e','f','g','h','i'); + a[9] = f9('a','b','c','d','e','f','g','h','i','j'); + } + return a.join(","); +} +assertEq(test_JSOP_ARGCNT(), "1,2,3,4,5,6,7,8,9,10"); diff --git a/js/src/jit-test/tests/basic/test_JSOP_ARGSUB.js b/js/src/jit-test/tests/basic/test_JSOP_ARGSUB.js new file mode 100644 index 0000000..1a4d27c --- /dev/null +++ b/js/src/jit-test/tests/basic/test_JSOP_ARGSUB.js @@ -0,0 +1,27 @@ +function test_JSOP_ARGSUB() { + function f0() { return arguments[0]; } + function f1() { return arguments[1]; } + function f2() { return arguments[2]; } + function f3() { return arguments[3]; } + function f4() { return arguments[4]; } + function f5() { return arguments[5]; } + function f6() { return arguments[6]; } + function f7() { return arguments[7]; } + function f8() { return arguments[8]; } + function f9() { return arguments[9]; } + var a = []; + for (var i = 0; i < 10; i++) { + a[0] = f0('a'); + a[1] = f1('a','b'); + a[2] = f2('a','b','c'); + a[3] = f3('a','b','c','d'); + a[4] = f4('a','b','c','d','e'); + a[5] = f5('a','b','c','d','e','f'); + a[6] = f6('a','b','c','d','e','f','g'); + a[7] = f7('a','b','c','d','e','f','g','h'); + a[8] = f8('a','b','c','d','e','f','g','h','i'); + a[9] = f9('a','b','c','d','e','f','g','h','i','j'); + } + return a.join(""); +} +assertEq(test_JSOP_ARGSUB(), "abcdefghij"); diff --git a/js/src/jit-test/tests/basic/testif.js b/js/src/jit-test/tests/basic/testif.js new file mode 100644 index 0000000..f7b2864 --- /dev/null +++ b/js/src/jit-test/tests/basic/testif.js @@ -0,0 +1,11 @@ +function testif() { + var q = 0; + for (var i = 0; i < 100; i++) { + if ((i & 1) == 0) + q++; + else + q--; + } + return q; +} +assertEq(testif(), 0); diff --git a/js/src/jit-test/tests/basic/testincops.js b/js/src/jit-test/tests/basic/testincops.js new file mode 100644 index 0000000..85e36ab --- /dev/null +++ b/js/src/jit-test/tests/basic/testincops.js @@ -0,0 +1,24 @@ +var globalinc = 0; +function testincops(n) { + var i = 0, o = {p:0}, a = [0]; + n = 100; + + for (i = 0; i < n; i++); + while (i-- > 0); + for (i = 0; i < n; ++i); + while (--i >= 0); + + for (o.p = 0; o.p < n; o.p++) globalinc++; + while (o.p-- > 0) --globalinc; + for (o.p = 0; o.p < n; ++o.p) ++globalinc; + while (--o.p >= 0) globalinc--; + + ++i; // set to 0 + for (a[i] = 0; a[i] < n; a[i]++); + while (a[i]-- > 0); + for (a[i] = 0; a[i] < n; ++a[i]); + while (--a[i] >= 0); + + return [++o.p, ++a[i], globalinc].toString(); +} +assertEq(testincops(), "0,0,0"); diff --git a/js/src/jit-test/tests/basic/trees.js b/js/src/jit-test/tests/basic/trees.js new file mode 100644 index 0000000..7638f08 --- /dev/null +++ b/js/src/jit-test/tests/basic/trees.js @@ -0,0 +1,10 @@ +function trees() { + var i = 0, o = [0,0,0]; + for (i = 0; i < 100; ++i) { + if ((i & 1) == 0) o[0]++; + else if ((i & 2) == 0) o[1]++; + else o[2]++; + } + return String(o); +} +assertEq(trees(), "50,25,25"); diff --git a/js/src/jit-test/tests/basic/truthies.js b/js/src/jit-test/tests/basic/truthies.js new file mode 100644 index 0000000..3006ee7 --- /dev/null +++ b/js/src/jit-test/tests/basic/truthies.js @@ -0,0 +1,29 @@ +load(libdir + 'andTestHelper.js'); +load(libdir + 'orTestHelper.js'); + +(function () { + var opsies = ["||", "&&"]; + var falsies = [null, undefined, false, NaN, 0, ""]; + var truthies = [{}, true, 1, 42, 1/0, -1/0, "blah"]; + var boolies = [falsies, truthies]; + + // The for each here should abort tracing, so that this test framework + // relies only on the interpreter while the orTestHelper and andTestHelper + // functions get trace-JITed. + for each (var op in opsies) { + for (var i in boolies) { + for (var j in boolies[i]) { + var x = uneval(boolies[i][j]); + for (var k in boolies) { + for (var l in boolies[k]) { + var y = uneval(boolies[k][l]); + var prefix = (op == "||") ? "or" : "and"; + var f = new Function("return " + prefix + "TestHelper(" + x + "," + y + ",10)"); + var expected = eval(x + op + y) ? 45 : 0; + assertEq(f(), expected); + } + } + } + } + } + })(); diff --git a/js/src/jit-test/tests/basic/typeofTest.js b/js/src/jit-test/tests/basic/typeofTest.js new file mode 100644 index 0000000..90dadbb --- /dev/null +++ b/js/src/jit-test/tests/basic/typeofTest.js @@ -0,0 +1,8 @@ +function typeofTest() +{ + var values = ["hi", "hi", "hi", null, 5, 5.1, true, undefined, /foo/, typeofTest, [], {}], types = []; + for (var i = 0; i < values.length; i++) + types[i] = typeof values[i]; + return types.toString(); +} +assertEq(typeofTest(), "string,string,string,object,number,number,boolean,undefined,object,function,object,object"); diff --git a/js/src/jit-test/tests/basic/unboxint.js b/js/src/jit-test/tests/basic/unboxint.js new file mode 100644 index 0000000..1aa4312 --- /dev/null +++ b/js/src/jit-test/tests/basic/unboxint.js @@ -0,0 +1,8 @@ +function unboxint() { + var q = 0; + var o = [4]; + for (var i = 0; i < 100; ++i) + q = o[0] << 1; + return q; +} +assertEq(unboxint(), 8); diff --git a/js/src/jit-test/tests/basic/wrap-primitive-this.js b/js/src/jit-test/tests/basic/wrap-primitive-this.js new file mode 100644 index 0000000..5c9db80 --- /dev/null +++ b/js/src/jit-test/tests/basic/wrap-primitive-this.js @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +/* + * If the tracer fails to notice that computeThis() will produce a wrapped + * primitive, then we may get: + * + * Assertion failure: thisObj == globalObj + */ + +var HOTLOOP = this.tracemonkey ? tracemonkey.HOTLOOP : 8; +var a; +function f(n) { + for (var i = 0; i < HOTLOOP; i++) + if (i == HOTLOOP - 2) + a = this; +} + +/* + * Various sorts of events can cause the global to be reshaped, which + * resets our loop counts. Furthermore, we don't record a branch off a + * trace until it has been taken HOTEXIT times. So simply calling the + * function twice may not be enough to ensure that the 'a = this' branch + * gets recorded. This is probably excessive, but it'll work. + */ +f.call("s", 1); +f.call("s", 1); +f.call("s", 1); +f.call("s", 1); +f.call("s", 1); +f.call("s", 1); +f.call("s", 1); +f.call("s", 1); +assertEq(typeof a, "object"); +assertEq("" + a, "s"); diff --git a/js/src/jit-test/tests/basic/xprop.js b/js/src/jit-test/tests/basic/xprop.js new file mode 100644 index 0000000..9fdbb66 --- /dev/null +++ b/js/src/jit-test/tests/basic/xprop.js @@ -0,0 +1,8 @@ +function xprop() +{ + a = 0; + for (var i = 0; i < 20; i++) + a += 7; + return a; +} +assertEq(xprop(), 140); diff --git a/js/src/jit-test/tests/closures/bug496922.js b/js/src/jit-test/tests/closures/bug496922.js new file mode 100644 index 0000000..7b351b1 --- /dev/null +++ b/js/src/jit-test/tests/closures/bug496922.js @@ -0,0 +1,20 @@ +actual = ''; +expected = '0,0,1,1,2,2,3,3,'; + +v = 0 +let( +f = function() { + for (let x = 0; x < 4; ++x) { + v >> x; + (function() { + for (let y = 0; y < 2; ++y) { + appendToActual(x) + } + })() + } +}) { (function() {})() + f(v) +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/bug496987.js b/js/src/jit-test/tests/closures/bug496987.js new file mode 100644 index 0000000..2c4c10e --- /dev/null +++ b/js/src/jit-test/tests/closures/bug496987.js @@ -0,0 +1,17 @@ +actual = ''; +expected = '0,undefined,0,undefined,1,undefined,0,undefined,1,undefined,0,undefined,1,undefined,nocrash,'; + +// bug 496987 + +for each(let a in ["", "", true, "", true, "", true]) { + appendToActual((function() { + for (var e in [0]) { + appendToActual( + a) + } + })()) +} + +appendToActual('nocrash') + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/bug497015-1.js b/js/src/jit-test/tests/closures/bug497015-1.js new file mode 100644 index 0000000..ac0511a --- /dev/null +++ b/js/src/jit-test/tests/closures/bug497015-1.js @@ -0,0 +1,19 @@ +actual = ''; +expected = ',0,0,8888,0,0,8888,0,0,/x/,0,0,'; + +for each(let a in ['', 8888, 8888, /x/]) { + ''; + for each(e in ['', false, '']) { + (function(e) { + for each(let c in ['']) { + appendToActual(a); + } + })(); + for (let aa = 0; aa < 1; ++aa) { + a = aa; + } + } +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/bug497015-2.js b/js/src/jit-test/tests/closures/bug497015-2.js new file mode 100644 index 0000000..0395a18 --- /dev/null +++ b/js/src/jit-test/tests/closures/bug497015-2.js @@ -0,0 +1,22 @@ +actual = ''; +expected = 'zzz ,zzz 100,zzz 100,zzz 7777,zzz 100,zzz 100,zzz 8888,zzz 100,zzz 100,zzz /x/,zzz 100,zzz 100,'; + +//function f() { +for each(let a in ['', 7777, 8888, /x/]) { + for each(e in ['', false, '']) { + (function(e) { + for each(let c in ['']) { + appendToActual('zzz ' + a); + } + })(); + for (let aa = 100; aa < 101; ++aa) { + a = aa; + } + } +} +//} + +//f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/bug540131-2.js b/js/src/jit-test/tests/closures/bug540131-2.js new file mode 100644 index 0000000..ebd3e02 --- /dev/null +++ b/js/src/jit-test/tests/closures/bug540131-2.js @@ -0,0 +1,13 @@ +// |jit-test| error: TypeError +(function() { + for (let z in [true]) { + (new(eval("for(l in[0,0,0,0]){}")) + (((function f(a, b) { + if (a.length == b) { + return (z) + } + f(a, b + 1) + })([,,], 0)), [])) + } +})() + diff --git a/js/src/jit-test/tests/closures/bug540131-3.js b/js/src/jit-test/tests/closures/bug540131-3.js new file mode 100644 index 0000000..8d47d79 --- /dev/null +++ b/js/src/jit-test/tests/closures/bug540131-3.js @@ -0,0 +1,13 @@ +(function() { + (eval("\ + (function() {\ + let(e = eval(\"\ + for(z=0;z<5;z++){}\ + \"))\ + (function(){\ + x = e\ + })()\ + })\ + "))() +})(); +print(x) diff --git a/js/src/jit-test/tests/closures/bug540131.js b/js/src/jit-test/tests/closures/bug540131.js new file mode 100644 index 0000000..2a46ae8 --- /dev/null +++ b/js/src/jit-test/tests/closures/bug540131.js @@ -0,0 +1,5 @@ +try { + (function() { + let(x = (eval("for(y in[0,0,0,0]){}"))) {} + })() +} catch(e) {} diff --git a/js/src/jit-test/tests/closures/bug540133.js b/js/src/jit-test/tests/closures/bug540133.js new file mode 100644 index 0000000..495f7b0 --- /dev/null +++ b/js/src/jit-test/tests/closures/bug540133.js @@ -0,0 +1,4 @@ +(function() { + var x; + eval("for (x in (gc)()) for each(e in [0]) { print }") +})() diff --git a/js/src/jit-test/tests/closures/bug540136.js b/js/src/jit-test/tests/closures/bug540136.js new file mode 100644 index 0000000..54b5771 --- /dev/null +++ b/js/src/jit-test/tests/closures/bug540136.js @@ -0,0 +1,17 @@ +// |jit-test| error: TypeError + +(eval("\ + (function () {\ + for (var[x] = function(){} in \ + (function m(a) {\ + if (a < 1) {\ + x;\ + return\ + }\ + return m(a - 1) + m(a - 2)\ + })(7)\ + (eval(\"\"))\ + )\ + ([])\ + })\ +"))() diff --git a/js/src/jit-test/tests/closures/bug540242.js b/js/src/jit-test/tests/closures/bug540242.js new file mode 100644 index 0000000..56c1a5a --- /dev/null +++ b/js/src/jit-test/tests/closures/bug540242.js @@ -0,0 +1,17 @@ +for (j = 0; j < 1; j++) { + var f = eval("\ + (function() {\ + for (var a = 0; a < 8; ++a) {\ + if (a % 3 == 2) {\ + eval(\"\ + for(b in[0,0,0,0]) {\ + print()\ + }\ + \")\ + }\ + gc()\ + }\ + })\ + "); + f() +} diff --git a/js/src/jit-test/tests/closures/bug540243.js b/js/src/jit-test/tests/closures/bug540243.js new file mode 100644 index 0000000..07faa26 --- /dev/null +++ b/js/src/jit-test/tests/closures/bug540243.js @@ -0,0 +1,10 @@ +for (a in (eval("\ + (function() {\ + return function() {\ + yield ((function() {\ + return d\ + })())\ + } ();\ + var d = []\ + })\ +"))()); diff --git a/js/src/jit-test/tests/closures/bug540348.js b/js/src/jit-test/tests/closures/bug540348.js new file mode 100644 index 0000000..ba4729c --- /dev/null +++ b/js/src/jit-test/tests/closures/bug540348.js @@ -0,0 +1,3 @@ +(function() { + for (var [e] = 1 in (eval("for (b = 0; b < 6; ++b) gc()"))) {} +})() diff --git a/js/src/jit-test/tests/closures/bug540528.js b/js/src/jit-test/tests/closures/bug540528.js new file mode 100644 index 0000000..419d33e --- /dev/null +++ b/js/src/jit-test/tests/closures/bug540528.js @@ -0,0 +1,4 @@ +(function() { + var a + eval("for(b in[0,0,0,0]){}[a=0]") +})() diff --git a/js/src/jit-test/tests/closures/bug541239.js b/js/src/jit-test/tests/closures/bug541239.js new file mode 100644 index 0000000..32e3af1 --- /dev/null +++ b/js/src/jit-test/tests/closures/bug541239.js @@ -0,0 +1,16 @@ +function m() { + var d = 73; + + return (eval("\n\ + (function() {\n\ + return function() {\n\ + yield ((function() {\n\ + print(d);\n\ + return d\n\ + })())\n\ + } ();\n\ + })\n\ + "))(); +} + +m().next(); diff --git a/js/src/jit-test/tests/closures/bug543565.js b/js/src/jit-test/tests/closures/bug543565.js new file mode 100644 index 0000000..828688b --- /dev/null +++ b/js/src/jit-test/tests/closures/bug543565.js @@ -0,0 +1,7 @@ +function C() { + var k = 3; + this.x = function () { return k; }; + for (var i = 0; i < 9; i++) + ; +} +new C; diff --git a/js/src/jit-test/tests/closures/closure-pluseq.js b/js/src/jit-test/tests/closures/closure-pluseq.js new file mode 100644 index 0000000..ccf5c82 --- /dev/null +++ b/js/src/jit-test/tests/closures/closure-pluseq.js @@ -0,0 +1,31 @@ +actual = ''; +expected = '3,6,9,12,15,18,'; + +function slice(a, b) +{ + //return { x: a + ':' + b }; + return b; +} + +function f() +{ + var length = 20; + var index = 0; + + function get3() { + //appendToActual("get3 " + index); + if (length - index < 3) + return null; + return slice(index, index += 3); + } + + var bytes = null; + while (bytes = get3()) { + appendToActual(bytes); + } +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/closure-pluseq2.js b/js/src/jit-test/tests/closures/closure-pluseq2.js new file mode 100644 index 0000000..bab2df6 --- /dev/null +++ b/js/src/jit-test/tests/closures/closure-pluseq2.js @@ -0,0 +1,30 @@ +actual = ''; +expected = '3,6,9,12,15,18,'; + +function slice(a, b) +{ + //return { x: a + ':' + b }; + return b; +} + +function f(index) +{ + var length = 20; + + function get3() { + //appendToActual("get3 " + index); + if (length - index < 3) + return null; + return slice(index, index += 3); + } + + var bytes = null; + while (bytes = get3()) { + appendToActual(bytes); + } +} + +f(0); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/closure-plusplus.js b/js/src/jit-test/tests/closures/closure-plusplus.js new file mode 100644 index 0000000..c6f3535 --- /dev/null +++ b/js/src/jit-test/tests/closures/closure-plusplus.js @@ -0,0 +1,31 @@ +actual = ''; +expected = '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,'; + +function slice(a, b) +{ + //return { x: a + ':' + b }; + return b; +} + +function f() +{ + var length = 20; + var index = 0; + + function get3() { + //appendToActual("get3 " + index); + if (length - index < 3) + return null; + return slice(index, ++index); + } + + var bytes = null; + while (bytes = get3()) { + appendToActual(bytes); + } +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/closure-tests.js b/js/src/jit-test/tests/closures/closure-tests.js new file mode 100644 index 0000000..4ec09e9 --- /dev/null +++ b/js/src/jit-test/tests/closures/closure-tests.js @@ -0,0 +1,6 @@ +actual = ''; +expected = ''; + + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/flat-closure-1.js b/js/src/jit-test/tests/closures/flat-closure-1.js new file mode 100644 index 0000000..3ac9b5a --- /dev/null +++ b/js/src/jit-test/tests/closures/flat-closure-1.js @@ -0,0 +1,18 @@ +actual = ''; +expected = '0,1,2,3,4,'; + +function g(a) { +} + +function f(y) { + var q; + q = function() { appendToActual(y); }; + q(); +} + +for (var i = 0; i < 5; ++i) { + f(i); + } + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/flat-closure-2.js b/js/src/jit-test/tests/closures/flat-closure-2.js new file mode 100644 index 0000000..41514d9 --- /dev/null +++ b/js/src/jit-test/tests/closures/flat-closure-2.js @@ -0,0 +1,15 @@ +actual = ''; +expected = 'nocrash,'; + +let (z = {}) { + for (var i = 0; i < 4; ++i) { + for each (var e in [{}, 1, {}]) { + +(function () z)(); + } + } +} + +appendToActual('nocrash') + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/flat-closure-3.js b/js/src/jit-test/tests/closures/flat-closure-3.js new file mode 100644 index 0000000..018880a --- /dev/null +++ b/js/src/jit-test/tests/closures/flat-closure-3.js @@ -0,0 +1,9 @@ +actual = ''; +expected = 'nocrash,'; + ++[(e = {}, (function () e)()) for each (e in ["", {}, "", {}, ""])]; + +appendToActual('nocrash') + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/flat-closure-4.js b/js/src/jit-test/tests/closures/flat-closure-4.js new file mode 100644 index 0000000..4d4613e --- /dev/null +++ b/js/src/jit-test/tests/closures/flat-closure-4.js @@ -0,0 +1,15 @@ +actual = ''; +expected = ',,,,,[object Object],[object Object],[object Object],[object Object],[object Object],,,,,,[object Object],[object Object],[object Object],[object Object],[object Object],,,,,,[object Object],[object Object],[object Object],[object Object],[object Object],,,,,,[object Object],[object Object],[object Object],[object Object],[object Object],,,,,,'; + +function f() { + var e; + for each (e in ["", {}, "", {}, "", {}, "", {}, ""]) { + var g = function() { for (var i = 0; i < 5; ++i) appendToActual(e); } + g(); + } +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/flat-closure-5.js b/js/src/jit-test/tests/closures/flat-closure-5.js new file mode 100644 index 0000000..f9bd10a --- /dev/null +++ b/js/src/jit-test/tests/closures/flat-closure-5.js @@ -0,0 +1,19 @@ +actual = ''; +expected = 'undefined,[object Object],undefined,[object Object],undefined,[object Object],undefined,[object Object],undefined,[object Object],undefined,[object Object],undefined,[object Object],undefined,[object Object],undefined,[object Object],undefined,[object Object],'; + +function f() { +for (var q = 0; q < 10; ++q) { + for each(let b in [(void 0), {}]) { + (function() { + for (var i = 0; i < 1; ++i) { + appendToActual('' + b) + } + }()) + } +} +} + +f() + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/flat-closure-6.js b/js/src/jit-test/tests/closures/flat-closure-6.js new file mode 100644 index 0000000..18a0bcb --- /dev/null +++ b/js/src/jit-test/tests/closures/flat-closure-6.js @@ -0,0 +1,17 @@ +actual = ''; +expected = 'bundefined,aundefined,b[object Object],aundefined,bundefined,aundefined,b[object Object],aundefined,bundefined,aundefined,b[object Object],aundefined,bundefined,aundefined,b[object Object],aundefined,bundefined,aundefined,b[object Object],aundefined,bundefined,aundefined,b[object Object],aundefined,bundefined,aundefined,b[object Object],aundefined,bundefined,aundefined,b[object Object],aundefined,bundefined,aundefined,b[object Object],aundefined,bundefined,aundefined,b[object Object],aundefined,'; + +// tests nfixed case of getting slot with let. + +for (var q = 0; q < 10; ++q) { + for each(let b in [(void 0), {}]) { + appendToActual('a' + ((function() { + for (var e in ['']) { + appendToActual('b' + b) + } + })())) + } +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/flat-closure-7.js b/js/src/jit-test/tests/closures/flat-closure-7.js new file mode 100644 index 0000000..0cf873a --- /dev/null +++ b/js/src/jit-test/tests/closures/flat-closure-7.js @@ -0,0 +1,16 @@ +actual = ''; +expected = '0 0 0 0 0 0 0 0 0,'; + + var o = []; + for (var a = 0; a < 9; ++a) { + var unused = 0; + let (zero = 0) { + for (var ee = 0; ee < 1; ++ee) { + o.push((function () zero)()); + } + } + } + appendToActual(o.join(" ")); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/flat-closure-8.js b/js/src/jit-test/tests/closures/flat-closure-8.js new file mode 100644 index 0000000..fb719b0 --- /dev/null +++ b/js/src/jit-test/tests/closures/flat-closure-8.js @@ -0,0 +1,19 @@ +actual = ''; +expected = 'nocrash,'; + +function b(a) { +} + +function f(y) { + function q() { b(y); }; + q(); +} + +for (var i = 0; i < 1000; ++i) { + f(i); + } + +appendToActual('nocrash') + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/incr-exit-2.js b/js/src/jit-test/tests/closures/incr-exit-2.js new file mode 100644 index 0000000..d87ab96 --- /dev/null +++ b/js/src/jit-test/tests/closures/incr-exit-2.js @@ -0,0 +1,20 @@ +actual = ''; +expected = '-3,'; + +v = 0 +let(f = function (y) { + let(f = function (g) { + for each(let h in g) { + if (++y > 2) { + appendToActual(h) + } + } + }) { + f([(--y), false, true, (--y), false, (--y)]) + } +}) { + f(v) +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/incr-exit-3.js b/js/src/jit-test/tests/closures/incr-exit-3.js new file mode 100644 index 0000000..e15212d --- /dev/null +++ b/js/src/jit-test/tests/closures/incr-exit-3.js @@ -0,0 +1,28 @@ +actual = ''; +expected = 'foo4,foo4,'; + +v = 0 +let(f = function (y) { + let(f = function (y) { + let(f = function (g) { + for (h in g) { + if (++y > 3) { + appendToActual('foo' + y) + } + } + }) { + f([y + for (b in [1, []])]); + f(['', false]) + } + v = String + }) { + f(y) + f(y) + } +}) { + f(v) +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/incr-exit.js b/js/src/jit-test/tests/closures/incr-exit.js new file mode 100644 index 0000000..6eb303a --- /dev/null +++ b/js/src/jit-test/tests/closures/incr-exit.js @@ -0,0 +1,20 @@ +actual = ''; +expected = 'ddd,'; + +// Bug 508187 +let(f = function (y) { + let(ff = function (g) { + for each(let h in g) { + if (++y > 5) { + appendToActual('ddd') + } + } + }) { + ff(['', null, '', false, '', '', null]) + } +}) { + f(-1) +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/lambda-inner-heavy.js b/js/src/jit-test/tests/closures/lambda-inner-heavy.js new file mode 100644 index 0000000..eba73cb --- /dev/null +++ b/js/src/jit-test/tests/closures/lambda-inner-heavy.js @@ -0,0 +1,32 @@ +actual = ''; +expected = '0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,3,3,3,4,4,4,4,4,4,4,'; + +function g(a) { + a(); +} + +function n() { +} + +function f(y) { + for (var i = 0; i < 7; ++i) { + var q; + q = function() { + appendToActual(y); + + var m = 1; + var z = function() { + appendToActual(m); + } + m = 2; + }; + g(q); + } +} + +for (var i = 0; i < 5; ++i) { + f(i); + } + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/lambda-light-returned.js b/js/src/jit-test/tests/closures/lambda-light-returned.js new file mode 100644 index 0000000..75541ba --- /dev/null +++ b/js/src/jit-test/tests/closures/lambda-light-returned.js @@ -0,0 +1,25 @@ +actual = ''; +expected = '1,'; + +function createCounter() { + var i = 0; + + var counter = function() { + return ++i; + } + + return counter; +} + +function f() { + var counter; + for (var i = 0; i < 100; ++i) { + counter = createCounter(); + } + appendToActual(counter()); +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/lambda-light.js b/js/src/jit-test/tests/closures/lambda-light.js new file mode 100644 index 0000000..b56893b --- /dev/null +++ b/js/src/jit-test/tests/closures/lambda-light.js @@ -0,0 +1,18 @@ +actual = ''; +expected = '10,'; + +function f(x) { + let (x = 10) { + for (var i = 0; i < 5; ++i) { + var g = function () { + appendToActual(x); + }; + } + g(); + } +} + +f(1); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/lambda.js b/js/src/jit-test/tests/closures/lambda.js new file mode 100644 index 0000000..fd7cbd1 --- /dev/null +++ b/js/src/jit-test/tests/closures/lambda.js @@ -0,0 +1,27 @@ +function f() { + var k = 0; + + var g = function() { + return ++k; + } + + return g; +} + +function h() { + for (var i = 0; i < 10; ++i) { + var vf = f(); + assertEq(vf(), 1); + assertEq(vf(), 2); + for (var j = 0; j < 10; ++j) { + assertEq(vf(), j + 3); + } + } +} + +h(); + +checkStats({ + recorderAborted: 8, // Inner tree is trying to grow +}); + diff --git a/js/src/jit-test/tests/closures/lambdafc.js b/js/src/jit-test/tests/closures/lambdafc.js new file mode 100644 index 0000000..03fc5ed --- /dev/null +++ b/js/src/jit-test/tests/closures/lambdafc.js @@ -0,0 +1,25 @@ +actual = ''; +expected = '99,'; + +function g(p) { + appendToActual(p()); +} + +function d(k) { + return function() { return k; } +} + +function f(k) { + var p; + + for (var i = 0; i < 1000; ++i) { + p = d(k); + } + + g(p); +} + +f(99); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/name-both-hvy.js b/js/src/jit-test/tests/closures/name-both-hvy.js new file mode 100644 index 0000000..6943e64 --- /dev/null +++ b/js/src/jit-test/tests/closures/name-both-hvy.js @@ -0,0 +1,28 @@ +actual = ''; +expected = ''; + +// do not crash + +function q() { +} + +function f() { + var j = 12; + + function g() { + eval(""); // makes |g| heavyweight + for (var i = 0; i < 3; ++i) { + j; + } + } + + j = 13; + q(g); // escaping |g| makes |f| heavyweight + g(); + j = 14; +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/name-inactive-missing.js b/js/src/jit-test/tests/closures/name-inactive-missing.js new file mode 100644 index 0000000..a0f6848 --- /dev/null +++ b/js/src/jit-test/tests/closures/name-inactive-missing.js @@ -0,0 +1,14 @@ +// |jit-test| error: ReferenceError + +function f(k) { + function g(j) { + return j + q; + } + return g; +} + +g = f(10); +var ans = ''; +for (var i = 0; i < 5; ++i) { + ans += g(i) + ','; +} diff --git a/js/src/jit-test/tests/closures/name.js b/js/src/jit-test/tests/closures/name.js new file mode 100644 index 0000000..498083f --- /dev/null +++ b/js/src/jit-test/tests/closures/name.js @@ -0,0 +1,25 @@ +actual = ''; +expected = '2,5,'; + +function loop(f) { + var p; + for (var i = 0; i < 10; ++i) { + p = f(); + } + return p; +} + +function f(i, k) { + var g = function() { return k; } + + k = 2; + appendToActual(loop(g)); + k = 5; + appendToActual(loop(g)); +} + +f(0, 0); + + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/name2.js b/js/src/jit-test/tests/closures/name2.js new file mode 100644 index 0000000..127b097 --- /dev/null +++ b/js/src/jit-test/tests/closures/name2.js @@ -0,0 +1,23 @@ +actual = ''; +expected = '0,1,2,3,4,'; + +function loop(f) { + var p; + for (var i = 0; i < 10; ++i) { + p = f(); + } + return p; +} + +function f(j, k) { + var g = function() { return k; } + + for (k = 0; k < 5; ++k) { + appendToActual(loop(g)); + } +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/name2a.js b/js/src/jit-test/tests/closures/name2a.js new file mode 100644 index 0000000..34f1d0e --- /dev/null +++ b/js/src/jit-test/tests/closures/name2a.js @@ -0,0 +1,23 @@ +actual = ''; +expected = '0,1,2,3,4,'; + +function loop(f) { + var p; + for (var i = 0; i < 10; ++i) { + p = f(1, 2, 3); + } + return p; +} + +function f(j, k) { + var g = function(a, b, c) { return k; } + + for (k = 0; k < 5; ++k) { + appendToActual(loop(g)); + } +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/name2b.js b/js/src/jit-test/tests/closures/name2b.js new file mode 100644 index 0000000..b07b02b --- /dev/null +++ b/js/src/jit-test/tests/closures/name2b.js @@ -0,0 +1,23 @@ +actual = ''; +expected = '0,1,2,3,4,'; + +function loop(f) { + var p; + for (var i = 0; i < 10; ++i) { + p = f(1, 2, 3); + } + return p; +} + +function f(j, k) { + var g = function(a, b, c) { return k; } + + for (k = 0; k < 5; ++k) { + appendToActual(loop(g)); + } +} + +f(1); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/name3.js b/js/src/jit-test/tests/closures/name3.js new file mode 100644 index 0000000..228dfaa --- /dev/null +++ b/js/src/jit-test/tests/closures/name3.js @@ -0,0 +1,24 @@ +actual = ''; +expected = '0,1,2,3,4,'; + +function loop(f) { + var p; + for (var i = 0; i < 10; ++i) { + p = f(); + } + return p; +} + +function f(j, k) { + var g = function() { return k; } + + k = j; + appendToActual(loop(g)); +} + +for (var i = 0; i < 5; ++i) { + f(i); +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/name4.js b/js/src/jit-test/tests/closures/name4.js new file mode 100644 index 0000000..596028e --- /dev/null +++ b/js/src/jit-test/tests/closures/name4.js @@ -0,0 +1,22 @@ +actual = ''; +expected = 'undefined,'; + +function loop(f) { + var p; + for (var i = 0; i < 10; ++i) { + p = f(); + } + return p; +} + +function make(k, j) { + var g = function() { return k; } + k = j; + return g; +} + +var f = make(); +appendToActual(loop(f)); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/namedLambda.js b/js/src/jit-test/tests/closures/namedLambda.js new file mode 100644 index 0000000..4be0c44 --- /dev/null +++ b/js/src/jit-test/tests/closures/namedLambda.js @@ -0,0 +1,17 @@ +// This just tests that named lambdas don't crash in the tracer. + +var f = function ff() { + var k = 0; + var counter = function q() { + return ++k; + } + return counter; +} + +function g() { + for (var i = 0; i < 10; ++i) { + f(); + } +} + +g(); diff --git a/js/src/jit-test/tests/closures/nameinc-loop-2.js b/js/src/jit-test/tests/closures/nameinc-loop-2.js new file mode 100644 index 0000000..1753f26 --- /dev/null +++ b/js/src/jit-test/tests/closures/nameinc-loop-2.js @@ -0,0 +1,26 @@ +actual = ''; +expected = '1,2,3,4,5,5,undefined,1,2,3,4,5,5,undefined,1,2,3,4,5,5,undefined,1,2,3,4,5,5,undefined,1,2,3,4,5,5,undefined,'; + +var f = function() { + var p = 0; + + function g() { + for (var i = 0; i < 5; ++i) { + p++; + appendToActual(p); + } + } + + g(); + + appendToActual(p); +} + +for (var i = 0; i < 5; ++i) { + f(); + appendToActual(); +} + + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/nameinc-loop-3.js b/js/src/jit-test/tests/closures/nameinc-loop-3.js new file mode 100644 index 0000000..08a7d56 --- /dev/null +++ b/js/src/jit-test/tests/closures/nameinc-loop-3.js @@ -0,0 +1,33 @@ +actual = ''; +expected = 'g 1 0,g 2 -1,g 3 -2,g 4 -3,g 5 -4,h 5 -5,f 5,undefined,g 1 0,g 2 -1,g 3 -2,g 4 -3,g 5 -4,h 5 -5,f 5,undefined,g 1 0,g 2 -1,g 3 -2,g 4 -3,g 5 -4,h 5 -5,f 5,undefined,g 1 0,g 2 -1,g 3 -2,g 4 -3,g 5 -4,h 5 -5,f 5,undefined,g 1 0,g 2 -1,g 3 -2,g 4 -3,g 5 -4,h 5 -5,f 5,undefined,'; + +var f = function() { + var p = 0; + + function h() { + var q = 0; + + function g() { + for (var i = 0; i < 5; ++i) { + p++; + appendToActual('g ' + p + ' ' + q); + q--; + } + } + g(); + appendToActual('h ' + p + ' ' + q); + } + + h(); + + appendToActual('f ' + p); +} + +for (var i = 0; i < 5; ++i) { + f(); + appendToActual(); +} + + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/nameinc-loop-missing-2.js b/js/src/jit-test/tests/closures/nameinc-loop-missing-2.js new file mode 100644 index 0000000..c37b3cc --- /dev/null +++ b/js/src/jit-test/tests/closures/nameinc-loop-missing-2.js @@ -0,0 +1,19 @@ +// |jit-test| error: ReferenceError + +for (var i = 0; i < 10; ++i) { + var f = function() { + var p = 0; + + function g() { + for (var i = 0; i < 5; ++i) { + x += 5; + } + } + + g(); + + print(p); + } + f(); +} + diff --git a/js/src/jit-test/tests/closures/nameinc-loop-missing.js b/js/src/jit-test/tests/closures/nameinc-loop-missing.js new file mode 100644 index 0000000..72eae0e --- /dev/null +++ b/js/src/jit-test/tests/closures/nameinc-loop-missing.js @@ -0,0 +1,21 @@ +// |jit-test| error: ReferenceError + +for (var i = 0; i < 10; ++i) { + var f = function() { + var p = 0; + + function g() { + for (var i = 0; i < 5; ++i) { + p++; + x++; + print(p); + } + } + + g(); + + print(p); + } + f(); +} + diff --git a/js/src/jit-test/tests/closures/nameinc-loop.js b/js/src/jit-test/tests/closures/nameinc-loop.js new file mode 100644 index 0000000..33c89d1 --- /dev/null +++ b/js/src/jit-test/tests/closures/nameinc-loop.js @@ -0,0 +1,24 @@ +actual = ''; +expected = '1,2,3,4,5,5,1,2,3,4,5,5,1,2,3,4,5,5,1,2,3,4,5,5,1,2,3,4,5,5,1,2,3,4,5,5,1,2,3,4,5,5,1,2,3,4,5,5,1,2,3,4,5,5,1,2,3,4,5,5,'; + +for (var i = 0; i < 10; ++i) { + var f = function() { + var p = 0; + + function g() { + for (var i = 0; i < 5; ++i) { + p++; + appendToActual(p); + } + } + + g(); + + appendToActual(p); + } + f(); +} + + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/nameinc.js b/js/src/jit-test/tests/closures/nameinc.js new file mode 100644 index 0000000..6909908 --- /dev/null +++ b/js/src/jit-test/tests/closures/nameinc.js @@ -0,0 +1,21 @@ +actual = ''; +expected = '5,'; + +function f() { + var p = 0; + + function g() { + for (var i = 0; i < 5; ++i) { + p++; + } + } + + g(); + + appendToActual(p); +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/set-outer-trace-1.js b/js/src/jit-test/tests/closures/set-outer-trace-1.js new file mode 100644 index 0000000..034a0e1 --- /dev/null +++ b/js/src/jit-test/tests/closures/set-outer-trace-1.js @@ -0,0 +1,24 @@ +actual = ''; +expected = '10,19,128,337,646,1055,1564,2173,2882,3691,4600,'; + +function f() { + var x = 10; + + var g = function(p) { + for (var i = 0; i < 10; ++i) { + x = p + i; + } + } + + for (var i = 0; i < 10; ++i) { + appendToActual(x); + g(100 * i + x); + } + + appendToActual(x); +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/set-outer-trace-2.js b/js/src/jit-test/tests/closures/set-outer-trace-2.js new file mode 100644 index 0000000..49b98aa --- /dev/null +++ b/js/src/jit-test/tests/closures/set-outer-trace-2.js @@ -0,0 +1,23 @@ +actual = ''; +expected = '10,19,100199,2001001999,30020010019999,400300200100199999,5004003002001001999999,60050040030020010019999999,700600500400300200100199999999,8007006005004003002001001999999999,90080070060050040030020010019999999999,'; + +function f() { + var x = 10; + + var g = function(p) { + for (var i = 0; i < 10; ++i) + x = p + i + ''; + } + + for (var i = 0; i < 10; ++i) { + appendToActual(x); + g(100 * i + x); + } + + appendToActual(x); +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/set-outer-trace-3.js b/js/src/jit-test/tests/closures/set-outer-trace-3.js new file mode 100644 index 0000000..458968f --- /dev/null +++ b/js/src/jit-test/tests/closures/set-outer-trace-3.js @@ -0,0 +1,23 @@ +actual = ''; +expected = '10.5,19.5,128.5,337.5,646.5,1055.5,1564.5,2173.5,2882.5,3691.5,4600.5,'; + +function f() { + var x = 10.5; + + var g = function(p) { + for (var i = 0; i < 10; ++i) + x = p + i; + } + + for (var i = 0; i < 10; ++i) { + appendToActual(x); + g(100 * i + x); + } + + appendToActual(x); +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/set-outer-trace-4.js b/js/src/jit-test/tests/closures/set-outer-trace-4.js new file mode 100644 index 0000000..c15f3c2 --- /dev/null +++ b/js/src/jit-test/tests/closures/set-outer-trace-4.js @@ -0,0 +1,23 @@ +actual = ''; +expected = '10,19,1000028,3000037,6000046,10000055,15000064,21000073,28000082,36000091,45000100,'; + +function f() { + var x = 10; + + var g = function(p) { + for (var i = 0; i < 10; ++i) + x = p + i; + } + + for (var i = 0; i < 10; ++i) { + appendToActual(x); + g(1000000 * i + x); + } + + appendToActual(x); +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/set-outer-trace.js b/js/src/jit-test/tests/closures/set-outer-trace.js new file mode 100644 index 0000000..f3eb8b8 --- /dev/null +++ b/js/src/jit-test/tests/closures/set-outer-trace.js @@ -0,0 +1,23 @@ +actual = ''; +expected = '10,20,30,40,50,60,70,80,90,100,110,'; + +function f() { + var x = 10; + + var g = function(p) { + for (var i = 0; i < 10; ++i) + x++; + } + + for (var i = 0; i < 10; ++i) { + appendToActual(x); + g(100 * i + x); + } + + appendToActual(x); +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/setname-1.js b/js/src/jit-test/tests/closures/setname-1.js new file mode 100644 index 0000000..63e3be3 --- /dev/null +++ b/js/src/jit-test/tests/closures/setname-1.js @@ -0,0 +1,26 @@ +actual = ''; +expected = '4,4,4,4,4,'; + +function f() { + var k = 0; + + function g() { + for (var i = 0; i < 5; ++i) { + k = i; + } + } + + function h() { + for (var i = 0; i < 5; ++i) { + appendToActual(k); + } + } + + g(); + h(); +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/setname-closure-2.js b/js/src/jit-test/tests/closures/setname-closure-2.js new file mode 100644 index 0000000..b5e30ab --- /dev/null +++ b/js/src/jit-test/tests/closures/setname-closure-2.js @@ -0,0 +1,27 @@ +actual = ''; +expected = '16,'; + +var f = function() { + var p = 1; + + function g() { + for (var i = 0; i < 5; ++i) { + p = i * i; + } + } + + function h() { + appendToActual(p); + } + + return [g, h]; +}; + +var [ g,h ] = f(); +for (var i = 0; i < 5; ++i) { + g(); +} +h(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/setname-closure.js b/js/src/jit-test/tests/closures/setname-closure.js new file mode 100644 index 0000000..fd450dd --- /dev/null +++ b/js/src/jit-test/tests/closures/setname-closure.js @@ -0,0 +1,25 @@ +actual = ''; +expected = '2,4,8,16,32,undefined,64,128,256,512,1024,undefined,2048,4096,8192,16384,32768,undefined,65536,131072,262144,524288,1048576,undefined,2097152,4194304,8388608,16777216,33554432,undefined,'; + +var f = function() { + var p = 1; + + function g() { + for (var i = 0; i < 5; ++i) { + p = p * 2; + appendToActual(p); + } + } + + return g; +} + +var g = f(); +for (var i = 0; i < 5; ++i) { + g(); + appendToActual(); +} + + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/setname-inner-heavy.js b/js/src/jit-test/tests/closures/setname-inner-heavy.js new file mode 100644 index 0000000..cf66c61 --- /dev/null +++ b/js/src/jit-test/tests/closures/setname-inner-heavy.js @@ -0,0 +1,18 @@ +actual = ''; +expected = 'undefined,'; + +function f() { + (eval("\ + (function () {\ + for (var z = 0; z < 2; ++z) {\ + x = ''\ + }\ + })\ + "))(); +} +this.__defineSetter__("x", eval) +f() +appendToActual(x); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/setname-loop-2.js b/js/src/jit-test/tests/closures/setname-loop-2.js new file mode 100644 index 0000000..82adb07 --- /dev/null +++ b/js/src/jit-test/tests/closures/setname-loop-2.js @@ -0,0 +1,29 @@ +actual = ''; +expected = '2,4,8,16,32,32,undefined,2,4,8,16,32,32,undefined,2,4,8,16,32,32,undefined,2,4,8,16,32,32,undefined,2,4,8,16,32,32,undefined,'; + +var f = function() { + var p = 1; + + function h() { + function g() { + for (var i = 0; i < 5; ++i) { + p = p * 2; + appendToActual(p); + } + } + g(); + } + + h(); + + appendToActual(p); +} + +for (var i = 0; i < 5; ++i) { + f(); + appendToActual(); +} + + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/setname-loop.js b/js/src/jit-test/tests/closures/setname-loop.js new file mode 100644 index 0000000..5aa3b17 --- /dev/null +++ b/js/src/jit-test/tests/closures/setname-loop.js @@ -0,0 +1,26 @@ +actual = ''; +expected = '2,4,8,16,32,32,undefined,2,4,8,16,32,32,undefined,2,4,8,16,32,32,undefined,2,4,8,16,32,32,undefined,2,4,8,16,32,32,undefined,'; + +var f = function() { + var p = 1; + + function g() { + for (var i = 0; i < 5; ++i) { + p = p * 2; + appendToActual(p); + } + } + + g(); + + appendToActual(p); +} + +for (var i = 0; i < 5; ++i) { + f(); + appendToActual(); +} + + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/setname-no-pop.js b/js/src/jit-test/tests/closures/setname-no-pop.js new file mode 100644 index 0000000..c07d81b --- /dev/null +++ b/js/src/jit-test/tests/closures/setname-no-pop.js @@ -0,0 +1,16 @@ +actual = ''; +expected = ''; + +(function () { + var y; + (eval("(function () {\ + for (var x = 0; x < 3; ++x) {\ + ''.replace(/a/, (y = 3))\ + }\ + });\ + "))() +})() + + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t001.js b/js/src/jit-test/tests/closures/t001.js new file mode 100644 index 0000000..3353004 --- /dev/null +++ b/js/src/jit-test/tests/closures/t001.js @@ -0,0 +1,21 @@ +actual = ''; +expected = '4,4,4,'; + +function k(f_arg) { + for (var i = 0; i < 5; ++i) { + f_arg(i); + } +} + +function t() { + var x = 1; + k(function (i) { x = i; }); + appendToActual(x); +} + +t(); +t(); +t(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t002.js b/js/src/jit-test/tests/closures/t002.js new file mode 100644 index 0000000..77e8178 --- /dev/null +++ b/js/src/jit-test/tests/closures/t002.js @@ -0,0 +1,21 @@ +actual = ''; +expected = '54,54,54,'; + +function k(a, f_arg, b, c) { + for (var i = 0; i < 5; ++i) { + f_arg(i + a); + } +} + +function t() { + var x = 1; + k(50, function (i) { x = i; }, 100, 200); + appendToActual(x); +} + +t(); +t(); +t(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t003.js b/js/src/jit-test/tests/closures/t003.js new file mode 100644 index 0000000..4cbf6cf --- /dev/null +++ b/js/src/jit-test/tests/closures/t003.js @@ -0,0 +1,21 @@ +actual = ''; +expected = '54,54,54,'; + +function k(a, b, f_arg, c) { + for (var i = 0; i < 5; ++i) { + f_arg(i + a); + } +} + +function t(a, b) { + var x = 1; + k(50, 100, function (i) { x = i; }, 200); + appendToActual(x); +} + +t(1); +t(2, 3); +t(4, 5, 6); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t004.js b/js/src/jit-test/tests/closures/t004.js new file mode 100644 index 0000000..de430eb --- /dev/null +++ b/js/src/jit-test/tests/closures/t004.js @@ -0,0 +1,21 @@ +actual = ''; +expected = 'NaN,60,74,'; + +function k(a, b, f_arg, c) { + for (var i = 0; i < 5; ++i) { + f_arg(i + a); + } +} + +function t(a, b) { + var x = 1; + k(50, 100, function (i) { x = i + a * b; }, 100, 200); + appendToActual(x); +} + +t(1); +t(2, 3); +t(4, 5, 6); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t005.js b/js/src/jit-test/tests/closures/t005.js new file mode 100644 index 0000000..a5be41f --- /dev/null +++ b/js/src/jit-test/tests/closures/t005.js @@ -0,0 +1,24 @@ +actual = ''; +expected = '4,'; + +function k(f_arg) { + for (var i = 0; i < 5; ++i) { + f_arg(i); + } +} + +function t() { + var x = 1; + + function u() { + k(function (i) { x = i; }); + appendToActual(x); + } + + u(); +} + +t(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t006.js b/js/src/jit-test/tests/closures/t006.js new file mode 100644 index 0000000..6705274 --- /dev/null +++ b/js/src/jit-test/tests/closures/t006.js @@ -0,0 +1,22 @@ +actual = ''; +expected = '2,'; + +function k(f_arg) { + (function() { + for (var i = 0; i < 10; ++i) { + f_arg(); + } + })(); +} + +function t() { + var x = 1; + k(function () { x = 2; }); + appendToActual(x); +} + +t(); + + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t007.js b/js/src/jit-test/tests/closures/t007.js new file mode 100644 index 0000000..1d745a3 --- /dev/null +++ b/js/src/jit-test/tests/closures/t007.js @@ -0,0 +1,23 @@ +actual = ''; +expected = '0,1,2,3,4,5,6,7,8,9,'; + +function k(f_arg) { + for (var i = 0; i < 10; ++i) { + f_arg(i); + } +} + +function t() { + var x = 1; + k(function (i) { x = i; }); + appendToActual(i); +} + +for (var i = 0; i < 10; ++i) { + t(); +} + + + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t008.js b/js/src/jit-test/tests/closures/t008.js new file mode 100644 index 0000000..2e5f833 --- /dev/null +++ b/js/src/jit-test/tests/closures/t008.js @@ -0,0 +1,26 @@ +actual = ''; +expected = '900,'; + +function k(f_arg) { + for (var i = 0; i < 10; ++i) { + f_arg(i); + } +} + +function t() { + var x = 1; + k(function (i) { x = i; }); + return x; +} + +var ans = 0; +for (var j = 0; j < 10; ++j) { + for (var i = 0; i < 10; ++i) { + ans += t(); + } +} +appendToActual(ans); + + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t009.js b/js/src/jit-test/tests/closures/t009.js new file mode 100644 index 0000000..02acc9a --- /dev/null +++ b/js/src/jit-test/tests/closures/t009.js @@ -0,0 +1,18 @@ +actual = ''; +expected = '4,'; + +function k(f_arg) { + for (var i = 0; i < 5; ++i) { + f_arg(i); + } +} + +function t(x) { + k(function (i) { x = i; }); + appendToActual(x); +} + +t(1); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t010.js b/js/src/jit-test/tests/closures/t010.js new file mode 100644 index 0000000..be45e78 --- /dev/null +++ b/js/src/jit-test/tests/closures/t010.js @@ -0,0 +1,21 @@ +actual = ''; +expected = '101,'; + +function looper(f) { + for (var i = 0; i < 10; ++i) { + for (var j = 0; j < 10; ++j) { + f(); + } + } +} + +function tester() { + var x = 1; + looper(function() { ++x; }); + return x; +} + +appendToActual(tester()); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t011.js b/js/src/jit-test/tests/closures/t011.js new file mode 100644 index 0000000..3ac9b5a --- /dev/null +++ b/js/src/jit-test/tests/closures/t011.js @@ -0,0 +1,18 @@ +actual = ''; +expected = '0,1,2,3,4,'; + +function g(a) { +} + +function f(y) { + var q; + q = function() { appendToActual(y); }; + q(); +} + +for (var i = 0; i < 5; ++i) { + f(i); + } + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t012.js b/js/src/jit-test/tests/closures/t012.js new file mode 100644 index 0000000..95936a7 --- /dev/null +++ b/js/src/jit-test/tests/closures/t012.js @@ -0,0 +1,19 @@ +actual = ''; +expected = '0,1,2,3,4,'; + +function g(a) { + a(); +} + +function f(y) { + var q; + q = function() { appendToActual(y); }; + g(q); +} + +for (var i = 0; i < 5; ++i) { + f(i); + } + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t013.js b/js/src/jit-test/tests/closures/t013.js new file mode 100644 index 0000000..6a06af8 --- /dev/null +++ b/js/src/jit-test/tests/closures/t013.js @@ -0,0 +1,21 @@ +actual = ''; +expected = '0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,3,3,3,4,4,4,4,4,4,4,'; + +function g(a) { + a(); +} + +function f(y) { + for (var i = 0; i < 7; ++i) { + var q; + q = function() { appendToActual(y); }; + g(q); + } +} + +for (var i = 0; i < 5; ++i) { + f(i); + } + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t014.js b/js/src/jit-test/tests/closures/t014.js new file mode 100644 index 0000000..9e2b96b --- /dev/null +++ b/js/src/jit-test/tests/closures/t014.js @@ -0,0 +1,21 @@ +actual = ''; +expected = '0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,3,3,3,4,4,4,4,4,4,4,'; + +function g(a) { + a(); +} + +function f(y) { + var q; + q = function() { appendToActual(y); }; + for (var i = 0; i < 7; ++i) { + g(q); + } +} + +for (var i = 0; i < 5; ++i) { + f(i); + } + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t015.js b/js/src/jit-test/tests/closures/t015.js new file mode 100644 index 0000000..2d5005c --- /dev/null +++ b/js/src/jit-test/tests/closures/t015.js @@ -0,0 +1,21 @@ +actual = ''; +expected = '0,1,2,3,4,'; + +function g(a) { + a(); +} + +function f(y) { + var q; + for (var i = 0; i < 7; ++i) { + q = function() { appendToActual(y); }; + } + g(q); +} + +for (var i = 0; i < 5; ++i) { + f(i); + } + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t016.js b/js/src/jit-test/tests/closures/t016.js new file mode 100644 index 0000000..1eac8c1 --- /dev/null +++ b/js/src/jit-test/tests/closures/t016.js @@ -0,0 +1,23 @@ +actual = ''; +expected = '0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,'; + +function g(a) { + for (var i = 0; i < 3; ++i) { + a(); + } +} + +function f(y) { + var q; + for (var i = 0; i < 7; ++i) { + q = function() { appendToActual(y); }; + } + g(q); +} + +for (var i = 0; i < 5; ++i) { + f(i); + } + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t017.js b/js/src/jit-test/tests/closures/t017.js new file mode 100644 index 0000000..92acf01 --- /dev/null +++ b/js/src/jit-test/tests/closures/t017.js @@ -0,0 +1,23 @@ +actual = ''; +expected = '0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,'; + +function g(a) { + for (var i = 0; i < 3; ++i) { + a(); + } +} + +function f(y) { + var q; + for (var i = 0; i < 7; ++i) { + q = function() { appendToActual(y); }; + g(q); + } +} + +for (var i = 0; i < 5; ++i) { + f(i); + } + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t018.js b/js/src/jit-test/tests/closures/t018.js new file mode 100644 index 0000000..846394e --- /dev/null +++ b/js/src/jit-test/tests/closures/t018.js @@ -0,0 +1,16 @@ +actual = ''; +expected = 'undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,'; + +for (x = 0; x < 10; ++x) { + for each(let a in ['', NaN]) { + appendToActual((function() { + for (let y = 0; y < 1; ++y) { + '' + a + } + })()) + } +} + + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t019.js b/js/src/jit-test/tests/closures/t019.js new file mode 100644 index 0000000..bbd0ade --- /dev/null +++ b/js/src/jit-test/tests/closures/t019.js @@ -0,0 +1,16 @@ +actual = ''; +expected = 'undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,'; + +for (x = 0; x < 10; ++x) { + for each(let a in ['', NaN, 3, 5.5, {}]) { + appendToActual((function() { + for (let y = 0; y < 1; ++y) { + '' + a + } + })()) + } +} + + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t020.js b/js/src/jit-test/tests/closures/t020.js new file mode 100644 index 0000000..a1b8f03 --- /dev/null +++ b/js/src/jit-test/tests/closures/t020.js @@ -0,0 +1,17 @@ +actual = ''; +expected = '0,0,1,1,2,2,3,3,'; + +let(f = function() { + for (let x = 0; x < 4; ++x) { + (function() { + for (let y = 0; y < 2; ++y) { + appendToActual(x); + } + })() + } +}) { + f(0) +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t021.js b/js/src/jit-test/tests/closures/t021.js new file mode 100644 index 0000000..6205238 --- /dev/null +++ b/js/src/jit-test/tests/closures/t021.js @@ -0,0 +1,18 @@ +actual = ''; +expected = 'nocrash,'; + +var v = {}; + +function a() { + var o = 3; + v.f = function() { return o; }; +} + +for (i = 0; i < 6; i++) + new a; + + +appendToActual('nocrash') + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t022.js b/js/src/jit-test/tests/closures/t022.js new file mode 100644 index 0000000..20d73ba --- /dev/null +++ b/js/src/jit-test/tests/closures/t022.js @@ -0,0 +1,24 @@ +actual = ''; +expected = 'nocrash,'; + +function jQuery(a, c) { +} +jQuery.fn = {}; +(function() { + var e = +["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"]; + for (var i = 0; i < e.length; i++) { + new function() { + var o = e[i]; + jQuery.fn[o] = function(f) { + return this.bind(o, f); + } + }; + } +})(); + + +appendToActual('nocrash') + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t023.js b/js/src/jit-test/tests/closures/t023.js new file mode 100644 index 0000000..0cddac3 --- /dev/null +++ b/js/src/jit-test/tests/closures/t023.js @@ -0,0 +1,17 @@ +actual = ''; +expected = '0,1,2,0,1,2,'; + +for (var a = 0; a < 2; ++a) { + for (var b = 0; b < 3; ++b) { + (function (x) { + (function () { + for (var c = 0; c < 1; ++c) { + appendToActual(x); + } + })(); + })(b); + } +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t024.js b/js/src/jit-test/tests/closures/t024.js new file mode 100644 index 0000000..fc874c6 --- /dev/null +++ b/js/src/jit-test/tests/closures/t024.js @@ -0,0 +1,19 @@ +actual = ''; +expected = '787878,'; + +var q = []; +for (var a = 0; a < 3; ++a) { + (function () { + for (var b = 7; b < 9; ++b) { + (function () { + for (var c = 0; c < 1; ++c) { + q.push(b); + } + })(); + } + })(); +} +appendToActual(q.join("")); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t025.js b/js/src/jit-test/tests/closures/t025.js new file mode 100644 index 0000000..5adb253 --- /dev/null +++ b/js/src/jit-test/tests/closures/t025.js @@ -0,0 +1,26 @@ +actual = ''; +expected = '2,5,'; + +function loop(f) { + var p; + for (var i = 0; i < 1000; ++i) { + p = f(); + } + return p; +} + +function f(k) { + function g() { + return k; + } + + k = 2; + appendToActual(loop(g)); + k = 5; + appendToActual(loop(g)); +} + +f(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t026.js b/js/src/jit-test/tests/closures/t026.js new file mode 100644 index 0000000..12063a7 --- /dev/null +++ b/js/src/jit-test/tests/closures/t026.js @@ -0,0 +1,22 @@ +actual = ''; +expected = '101,nocrash,'; + +function looper(f) { + for (var i = 0; i < 10; ++i) { + for (var j = 0; j < 10; ++j) { + f(); + } + } +} + +function tester() { + var x = 1; + looper(function() { ++x; }); + return x; +} + +appendToActual(tester()); +appendToActual("nocrash"); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t027.js b/js/src/jit-test/tests/closures/t027.js new file mode 100644 index 0000000..423fb52 --- /dev/null +++ b/js/src/jit-test/tests/closures/t027.js @@ -0,0 +1,21 @@ +actual = ''; +expected = '99,'; + +function looper(f) { + for (var i = 0; i < 10; ++i) { + for (var j = 0; j < 10; ++j) { + f(10*i + j); + } + } +} + +function tester() { + var x = 1; + looper(function(y) { x = y; }); + return x; +} + +appendToActual(tester()); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t028.js b/js/src/jit-test/tests/closures/t028.js new file mode 100644 index 0000000..b1a6d3a --- /dev/null +++ b/js/src/jit-test/tests/closures/t028.js @@ -0,0 +1,23 @@ +actual = ''; +expected = 'undefined,'; + +function looper(f) { + for (var i = 0; i < 10; ++i) { + for (var j = 0; j < 10; ++j) { + f(); + } + } +} + +function tester() { + var x = 1; + function f() { + return x; + } + looper(f); +} + +appendToActual(tester()); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t029.js b/js/src/jit-test/tests/closures/t029.js new file mode 100644 index 0000000..be45e78 --- /dev/null +++ b/js/src/jit-test/tests/closures/t029.js @@ -0,0 +1,21 @@ +actual = ''; +expected = '101,'; + +function looper(f) { + for (var i = 0; i < 10; ++i) { + for (var j = 0; j < 10; ++j) { + f(); + } + } +} + +function tester() { + var x = 1; + looper(function() { ++x; }); + return x; +} + +appendToActual(tester()); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t030.js b/js/src/jit-test/tests/closures/t030.js new file mode 100644 index 0000000..e0b2b64 --- /dev/null +++ b/js/src/jit-test/tests/closures/t030.js @@ -0,0 +1,21 @@ +actual = ''; +expected = '2,'; + +function looper(f) { + for (var i = 0; i < 10; ++i) { + for (var j = 0; j < 10; ++j) { + f(); + } + } +} + +function tester() { + var x = 1; + looper(function() { x = 2; }); + return x; +} + +appendToActual(tester()); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t031.js b/js/src/jit-test/tests/closures/t031.js new file mode 100644 index 0000000..3353004 --- /dev/null +++ b/js/src/jit-test/tests/closures/t031.js @@ -0,0 +1,21 @@ +actual = ''; +expected = '4,4,4,'; + +function k(f_arg) { + for (var i = 0; i < 5; ++i) { + f_arg(i); + } +} + +function t() { + var x = 1; + k(function (i) { x = i; }); + appendToActual(x); +} + +t(); +t(); +t(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t032.js b/js/src/jit-test/tests/closures/t032.js new file mode 100644 index 0000000..a5be41f --- /dev/null +++ b/js/src/jit-test/tests/closures/t032.js @@ -0,0 +1,24 @@ +actual = ''; +expected = '4,'; + +function k(f_arg) { + for (var i = 0; i < 5; ++i) { + f_arg(i); + } +} + +function t() { + var x = 1; + + function u() { + k(function (i) { x = i; }); + appendToActual(x); + } + + u(); +} + +t(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t033.js b/js/src/jit-test/tests/closures/t033.js new file mode 100644 index 0000000..e030fbf --- /dev/null +++ b/js/src/jit-test/tests/closures/t033.js @@ -0,0 +1,19 @@ +actual = ''; +expected = '2,'; + +function k(f_arg) { + for (var i = 0; i < 100; ++i) { + f_arg(); + } +} + +function t() { + var x = 1; + k(function () { x = 2; }); + appendToActual(x); +} + +t(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t034.js b/js/src/jit-test/tests/closures/t034.js new file mode 100644 index 0000000..060101e --- /dev/null +++ b/js/src/jit-test/tests/closures/t034.js @@ -0,0 +1,20 @@ +actual = ''; +expected = ''; + +function k(f_arg) { + for (var i = 0; i < 10; ++i) { + f_arg(i); + } +} + +function t() { + var x = 1; + k(function (i) { x = i; }); +} + +for (var i = 0; i < 100; ++i) { + t(); +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t035.js b/js/src/jit-test/tests/closures/t035.js new file mode 100644 index 0000000..02acc9a --- /dev/null +++ b/js/src/jit-test/tests/closures/t035.js @@ -0,0 +1,18 @@ +actual = ''; +expected = '4,'; + +function k(f_arg) { + for (var i = 0; i < 5; ++i) { + f_arg(i); + } +} + +function t(x) { + k(function (i) { x = i; }); + appendToActual(x); +} + +t(1); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t036.js b/js/src/jit-test/tests/closures/t036.js new file mode 100644 index 0000000..9e26baf --- /dev/null +++ b/js/src/jit-test/tests/closures/t036.js @@ -0,0 +1,24 @@ +actual = ''; +expected = '77,77,'; + +var o = { + x: 11, + y: 13 +}; + +function g() { + with (o) { + var x = 77; + for (var i = 0; i < 5; ++i) { + var f = function() { appendToActual(x); } + } + f(); + } + + f(); +} + +g(); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/t037.js b/js/src/jit-test/tests/closures/t037.js new file mode 100644 index 0000000..0350c51 --- /dev/null +++ b/js/src/jit-test/tests/closures/t037.js @@ -0,0 +1,14 @@ +actual = ''; +expected = '7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,'; + +function heavy(s, t, u) {return eval(s)} + +for (var i = 0; i < 5; ++i) { + var flat = heavy("(function () {var x = t * t; return function(){return x + u}})()", 2, 3); + for (var j = 0; j < 5; ++j) { + appendToActual(flat()); + } + } + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/test-inner-imports.js b/js/src/jit-test/tests/closures/test-inner-imports.js new file mode 100644 index 0000000..8e7e8d0 --- /dev/null +++ b/js/src/jit-test/tests/closures/test-inner-imports.js @@ -0,0 +1,22 @@ +actual = ''; +expected = '0,0,2,2,4,4,6,6,8,8,'; + +function g(b) { + for (var i = 0; i < 10; ++i) { + } +} + +function f(xa_arg) { + var xa = xa_arg; + for (var i = 0; i < 5; ++i) { + var j = i + xa[i]; + appendToActual(j); + g(); + appendToActual(j); + } +} + +f([ 0, 1, 2, 3, 4 ]); + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/closures/upvar-nest.js b/js/src/jit-test/tests/closures/upvar-nest.js new file mode 100644 index 0000000..1380011 --- /dev/null +++ b/js/src/jit-test/tests/closures/upvar-nest.js @@ -0,0 +1,24 @@ +actual = ''; +expected = '0 0 1 1 2 2 3 3,0 0 1 1 2 2 3 3,0 0 1 1 2 2 3 3,0 0 1 1 2 2 3 3,0 0 1 1 2 2 3 3,1 2 2 3 3 4 4 5,1 2 2 3 3 4 4 5,1 2 2 3 3 4 4 5,1 2 2 3 3 4 4 5,1 2 2 3 3 4 4 5,2 4 3 5 4 6 5 7,2 4 3 5 4 6 5 7,2 4 3 5 4 6 5 7,2 4 3 5 4 6 5 7,2 4 3 5 4 6 5 7,3 6 4 7 5 8 6 9,3 6 4 7 5 8 6 9,3 6 4 7 5 8 6 9,3 6 4 7 5 8 6 9,3 6 4 7 5 8 6 9,4 8 5 9 6 10 7 11,4 8 5 9 6 10 7 11,4 8 5 9 6 10 7 11,4 8 5 9 6 10 7 11,4 8 5 9 6 10 7 11,'; + +function f(a, b) { + function g(x, y) { + function h(m, n) { + function k(u, v) { + for (var i = 0; i < 5; ++i) { + appendToActual(a + ' ' + b + ' ' + x + ' ' + y + ' ' + m + ' ' + n + ' ' + u + ' ' + v); + } + } + k(m+1, n+1); + } + h(x+1, y+1); + } + g(a+1, b+1); +} + +for (var i = 0; i < 5; ++i) { + f(i, i+i); +} + + +assertEq(actual, expected) diff --git a/js/src/jit-test/tests/jaeger/bug549393-1.js b/js/src/jit-test/tests/jaeger/bug549393-1.js new file mode 100644 index 0000000..d98cc0b --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug549393-1.js @@ -0,0 +1,43 @@ +// |jit-test| error: TypeError +function start() { + MAX_TOTAL_TIME = startTime = new Date + do { + if (rnd(0)) return (a[rnd()])() + lastTime = new Date + } while ( lastTime - startTime < MAX_TOTAL_TIME ) +} +function MersenneTwister19937() { + this.init_genrand = function() { + for (mti = 1; mti < 4; mti++) { + Array[mti] = 1 + } + }; + this.genrand_int32 = function() { + if (mti > 4) { + mti = 0 + } + return Array[mti++]; + } +} (function() { + fuzzMT = new MersenneTwister19937; + fuzzMT.init_genrand() + rnd = function() { + return Math.floor(fuzzMT.genrand_int32()) + } +} ()) +function weighted(wa) { + a = [] + for (i = 0; i < wa.length; ++i) { + for (var j = 0; j < 8; ++j) { + a.push(wa[i].fun) + } + } +} +statementMakers = weighted([{ + fun: function makeMixedTypeArray() { [[, , , , , , , , , , , , , , , , , , , +, , , , , ""][(a[rnd()])()]]} +}]) +start() + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug549393-2.js b/js/src/jit-test/tests/jaeger/bug549393-2.js new file mode 100644 index 0000000..6c902ca --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug549393-2.js @@ -0,0 +1,10 @@ +(function () { + for (var q = 0; q < 6; ++q) { + x: (function () { + var m = (function () {})() + })([0, , 0, 0, 0, , 0, 0, 0, , 0, 0, 0, , 0, 0, 0, 0, 0, 0, Number(1)]) + } +})() + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug549396.js b/js/src/jit-test/tests/jaeger/bug549396.js new file mode 100644 index 0000000..9fbefe4 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug549396.js @@ -0,0 +1 @@ +x = this.__defineSetter__("x", function(z) function() { z }) diff --git a/js/src/jit-test/tests/jaeger/bug549398.js b/js/src/jit-test/tests/jaeger/bug549398.js new file mode 100644 index 0000000..32d9e4c --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug549398.js @@ -0,0 +1,10 @@ +(function () { + eval("\ + for(var z = 0 ; z < 2 ; ++z) {\ + this\ + }\ + ", ()) +})() + +/* Don't crash. */ + diff --git a/js/src/jit-test/tests/jaeger/bug549521.js b/js/src/jit-test/tests/jaeger/bug549521.js new file mode 100644 index 0000000..c92b440 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug549521.js @@ -0,0 +1,12 @@ +function f(y) { + if (y) + return; + let(x) { + for (;;) {} + } +} + + +/* Don't assert. */ +f(1); + diff --git a/js/src/jit-test/tests/jaeger/bug549602.js b/js/src/jit-test/tests/jaeger/bug549602.js new file mode 100644 index 0000000..7a71f81 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug549602.js @@ -0,0 +1,31 @@ +version(180) +function f1(code) { + var c + var t = code.replace(/s/, "") + var f = new Function(code) + var o + e = v = f2(f, c) +} +function f2(f, e) { + try { + a = f() + } catch(r) { + var r = g() + } +} +g1 = [{ + text: "(function sum_slicing(array){return array==0?0:a+sum_slicing(array.slice(1))})", + test: function (f) { + f([, 2]) == "" + } +}]; +(function () { + for (var i = 0; i < g1.length; ++i) { + var a = g1[i] + var text = a.text + var f = eval(text.replace(/@/, "")) + if (a.test(f)) {} + } +}()) +f1("for(let a=0;a<6;a++){print([\"\"].some(function(){false>\"\"}))}") + diff --git a/js/src/jit-test/tests/jaeger/bug549603.js b/js/src/jit-test/tests/jaeger/bug549603.js new file mode 100644 index 0000000..5d5dea6 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug549603.js @@ -0,0 +1,3 @@ +// |jit-test| error: ReferenceError +x ? o : [] && x + diff --git a/js/src/jit-test/tests/jaeger/bug550490.js b/js/src/jit-test/tests/jaeger/bug550490.js new file mode 100644 index 0000000..f434806 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug550490.js @@ -0,0 +1,14 @@ + +function a() { + function f() {} + this.d = function() { + f + } +} (function() { + var a2, x + a2 = new a; + d = (function(){x * 1})(); +})() + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug550665.js b/js/src/jit-test/tests/jaeger/bug550665.js new file mode 100644 index 0000000..6cfe99e --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug550665.js @@ -0,0 +1,8 @@ +(function () { + var a; + eval("for(w in ((function(x,y){b:0})())) ;"); +})(); + +this.__defineSetter__("l", function() { gc() }); +this.watch("l", function(x) { yield #1={} }); +l = true; diff --git a/js/src/jit-test/tests/jaeger/bug551603.js b/js/src/jit-test/tests/jaeger/bug551603.js new file mode 100644 index 0000000..019408e --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug551603.js @@ -0,0 +1,8 @@ +(function() { + ((function f(a) { + if (a > 0) { + f(a - 1) + } + })(6)) +})() + diff --git a/js/src/jit-test/tests/jaeger/bug552644.js b/js/src/jit-test/tests/jaeger/bug552644.js new file mode 100644 index 0000000..20babe1 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug552644.js @@ -0,0 +1,6 @@ +(function() { + for (e in ((function() { + yield + })())) return +})() +/* Don't assert. */ diff --git a/js/src/jit-test/tests/jaeger/bug553781-2.js b/js/src/jit-test/tests/jaeger/bug553781-2.js new file mode 100644 index 0000000..b10c5c8 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug553781-2.js @@ -0,0 +1,13 @@ +(function() { + do { + try { + return + } + catch(x if (c)) { + return + } (x) + } while (x) +})() + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug553781.js b/js/src/jit-test/tests/jaeger/bug553781.js new file mode 100644 index 0000000..4c9b674 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug553781.js @@ -0,0 +1,11 @@ +(function () { + try { + return + } catch (x if i) { + return + } + for (z in []); +})() + +/* Don't assert */ + diff --git a/js/src/jit-test/tests/jaeger/bug553784.js b/js/src/jit-test/tests/jaeger/bug553784.js new file mode 100644 index 0000000..6bd60f7 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug553784.js @@ -0,0 +1,18 @@ +// |jit-test| allow-oom +(function(){ + (x)=> +})() +try{ + (function(){ + ((function a(aaaaaa,bbbbbb){ + if(aaaaaa.length==bbbbbb){ + return eval%bbbbbb.valueOf() + } + cccccc=a(aaaaaa,bbbbbb+1) + return cccccc._=x + })([,,,,,,,,,,,,,,,,,,0],0)) + })() +}catch(e){} + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug554580-1.js b/js/src/jit-test/tests/jaeger/bug554580-1.js new file mode 100644 index 0000000..0e8daad --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug554580-1.js @@ -0,0 +1,7 @@ +// |jit-test| error: TypeError +for (var a = 0; a < 7; ++a) { + if (a == 1) { + Iterator() + } +} + diff --git a/js/src/jit-test/tests/jaeger/bug554580-2.js b/js/src/jit-test/tests/jaeger/bug554580-2.js new file mode 100644 index 0000000..d297f3a --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug554580-2.js @@ -0,0 +1,9 @@ +// |jit-test| error: RangeError +(function() { + for each(let a in [function() {}, Infinity]) { + new Array(a) + } +})() + +/* Don't assert/crash. */ + diff --git a/js/src/jit-test/tests/jaeger/bug554580-3.js b/js/src/jit-test/tests/jaeger/bug554580-3.js new file mode 100644 index 0000000..9ebde6d --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug554580-3.js @@ -0,0 +1,11 @@ +// |jit-test| error: SyntaxError +Function("\n\ + for (a = 0; a < 3; a++) {\n\ + if (a == 0) {} else {\n\ + this.__defineSetter__(\"\",1)\n\ + }\n\ + }\n\ +")() + +/* Don't crash/assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug554580-4.js b/js/src/jit-test/tests/jaeger/bug554580-4.js new file mode 100644 index 0000000..f9a25ad --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug554580-4.js @@ -0,0 +1,18 @@ +(function() { + try { + (eval("\ + function() {\ + for each(let y in [0]) {\ + for (var a = 0; a < 9; ++a) {\ + if (a) {\ + this.__defineGetter__(\"\",this)\ + }\ + }\ + }\ + }\ + "))() + } catch(e) {} +})() + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug554580-5.js b/js/src/jit-test/tests/jaeger/bug554580-5.js new file mode 100644 index 0000000..1d3ee52 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug554580-5.js @@ -0,0 +1,20 @@ +(function() { + (function g(m, n) { + if (m = n) { + return eval("x=this") + } + g(m, 1)[[]] + })() +})() +Function("\ + for (let b in [0]) {\ + for (var k = 0; k < 6; ++k) {\ + if (k == 1) {\ + print(x)\ + }\ + }\ + }\ +")() + +/* Don't crash/assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug554651.js b/js/src/jit-test/tests/jaeger/bug554651.js new file mode 100644 index 0000000..23be34d --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug554651.js @@ -0,0 +1,15 @@ +// |jit-test| error: InternalError +(function() { + try { + (Function("this.__defineGetter__(\"x\",(Function(\"for(z=0;z<6;z++)(x)\")))"))() + } catch(e) {} +})() +((function f(d, aaaaaa) { + if (bbbbbb = aaaaaa) { + x + } + f(bbbbbb, aaaaaa + 1) +})([], 0)) + +/* Don't assert (32-bit mac only, relies on very specific stack usage). */ + diff --git a/js/src/jit-test/tests/jaeger/bug554675-1.js b/js/src/jit-test/tests/jaeger/bug554675-1.js new file mode 100644 index 0000000..2dcbae8 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug554675-1.js @@ -0,0 +1,8 @@ +(function() { + for (e in [0, 0]) { + if (/x/ < this) {} + } +})() + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug554675-2.js b/js/src/jit-test/tests/jaeger/bug554675-2.js new file mode 100644 index 0000000..d3b6988 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug554675-2.js @@ -0,0 +1,11 @@ +function a(code) { + var f = new Function("for each(let x in[false,'',/x/,'',{}]){if(x; + this.x = x; +} +function f() { + var a = new K(1); + var b = new K(2); + return (a == b); +} +assertEq(f(), false); diff --git a/js/src/jit-test/tests/jaeger/bug577580.js b/js/src/jit-test/tests/jaeger/bug577580.js new file mode 100644 index 0000000..6812a7d --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug577580.js @@ -0,0 +1,7 @@ +// |jit-test| error: ReferenceError +(function() { + for (; i;) { + eval(/@/, "") + } +})() + diff --git a/js/src/jit-test/tests/jaeger/bug577646.js b/js/src/jit-test/tests/jaeger/bug577646.js new file mode 100644 index 0000000..659354c --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug577646.js @@ -0,0 +1,5 @@ +try { + [](); +} catch(e) {} + +/* Don't crash. */ diff --git a/js/src/jit-test/tests/jaeger/bug577705.js b/js/src/jit-test/tests/jaeger/bug577705.js new file mode 100644 index 0000000..e9e3381 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug577705.js @@ -0,0 +1,65 @@ +// |jit-test| error: ReferenceError +function f1() { + N = 62; + mt = Array + function g1(n1) { + return n1 < 0 ? (1 ^ 21) + 21: n1 + } + function g2(n1, n2) { + return g1(n1 + n2 & 4294967295); + } + function g3(n1, n2) { + sum = 0; + for (var i = 0; i < 32; ++i) { + if (n1 >> i) { + sum = g2(sum, g1(n2)) + } + } + return sum + } + this.h1 = function() { + for (mti = 1; mti < N; mti++) { + mt[mti] = g2(g3(3, g1(mt[mti - 1] ^ 0)), mti) + } + }; + this.i2 = function() { + if (mti > N) { + mti = 0; + } + y = mt[mti++]; + return y + }; + this.i1 = function() { + return (this.i2() + 5) * 2e-10 + }; +} (function() { + fuzzMT = new f1; + fuzzMT.h1(9); + rnd = function(n) { + return Math.floor(fuzzMT.i1() * n) + }; +} ()); +function f5(a) { + return a[rnd(a.length)] +} +function f2(d, b) { + f3(d, b); + return "" + f2(2, b) + ""; +} +function f3(d, b) { + if (rnd(4) == 1) { + f5(f4)(d, b) + } +} +var f4 = [function() { ["", f6(), ""] +}]; +function f6(db) { + return f5(foo)(); +} +var foo = [function() { + t(["", "", "", "", "", "", "", "", "", "", "", "" + h.I, ""]); +}]; +f2() + +/* Don't assert or crash. */ + diff --git a/js/src/jit-test/tests/jaeger/bug577996.js b/js/src/jit-test/tests/jaeger/bug577996.js new file mode 100644 index 0000000..1c7fa6a --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug577996.js @@ -0,0 +1,6 @@ +Function("\n\ + for each(y in[0,0,0]) {\n\ + for(x in[0,0,0,0,0,0,0,0,0,new Boolean(true),0,0,0,new Boolean(true)]) {}\n\ + }\n\ +")() + diff --git a/js/src/jit-test/tests/jaeger/bug580703.js b/js/src/jit-test/tests/jaeger/bug580703.js new file mode 100644 index 0000000..78d85df --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug580703.js @@ -0,0 +1,9 @@ + + +let(w)(function () { + w +}) +let(e)(function () { + e +}) + diff --git a/js/src/jit-test/tests/jaeger/bug580712.js b/js/src/jit-test/tests/jaeger/bug580712.js new file mode 100644 index 0000000..aabb5f5 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug580712.js @@ -0,0 +1 @@ +--''.trimLeft diff --git a/js/src/jit-test/tests/jaeger/bug580883.js b/js/src/jit-test/tests/jaeger/bug580883.js new file mode 100644 index 0000000..90d8cb3 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug580883.js @@ -0,0 +1,6 @@ +// |jit-test| error: invalid sharp variable use #1# +[] = #1# +with(7) { + var c +} + diff --git a/js/src/jit-test/tests/jaeger/bug580884-2.js b/js/src/jit-test/tests/jaeger/bug580884-2.js new file mode 100644 index 0000000..fdc4f53 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug580884-2.js @@ -0,0 +1,23 @@ +assertEq( + (function () { + eval(); + var arr = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 ]; + + for (var i = 0; i < 4; ++i) { + var src = i * 8; + var dst = i * 8 + 7; + for (var j = 0; j < 4; ++j) { + [arr[dst--], arr[src++]] = [arr[src], arr[dst]]; + } + } + return arr; + })().toSource(), + "[7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 32]"); + +checkStats({ + recorderStarted: 2, + traceCompleted: 2, + sideExitIntoInterpreter: 3, + traceTriggered: 3 +}); diff --git a/js/src/jit-test/tests/jaeger/bug580884-3.js b/js/src/jit-test/tests/jaeger/bug580884-3.js new file mode 100644 index 0000000..485f306 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug580884-3.js @@ -0,0 +1,10 @@ +function testDestructuring() { + eval(); + var t = 0; + for (var i = 0; i < HOTLOOP + 1; ++i) { + var [r, g, b] = [1, 1, 1]; + t += r + g + b; + } + return t +} +assertEq(testDestructuring(), (HOTLOOP + 1) * 3); diff --git a/js/src/jit-test/tests/jaeger/bug580884.js b/js/src/jit-test/tests/jaeger/bug580884.js new file mode 100644 index 0000000..b7a26f7 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug580884.js @@ -0,0 +1,8 @@ +// |jit-test| error: ReferenceError +for (let a in [0]) +a = e +for (let a in [0]) +(function () { + a +}) + diff --git a/js/src/jit-test/tests/jaeger/bug580931-2.js b/js/src/jit-test/tests/jaeger/bug580931-2.js new file mode 100644 index 0000000..9f18f57 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug580931-2.js @@ -0,0 +1,4 @@ +// |jit-test| error: TypeError +x = 0 +'a'.replace(/a/, x.toLocaleString) + diff --git a/js/src/jit-test/tests/jaeger/bug581871.js b/js/src/jit-test/tests/jaeger/bug581871.js new file mode 100644 index 0000000..6b22dd5 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug581871.js @@ -0,0 +1,10 @@ +function test(p) { + var alwaysFalse = p && !p; + var k = []; + var g; + if (!alwaysFalse) { + k[0] = g = alwaysFalse ? "failure" : "success"; + return g; + } +} +assertEq(test("anything"), "success"); diff --git a/js/src/jit-test/tests/jaeger/bug581936.js b/js/src/jit-test/tests/jaeger/bug581936.js new file mode 100644 index 0000000..5b4e4f1 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug581936.js @@ -0,0 +1,12 @@ +function returnZero() { return 0; } +function test() { + var a = "a"; + var b = "b"; + if (returnZero()) { + return a + b; + } else { + return b + a; + } +} +assertEq(test(), "ba"); + diff --git a/js/src/jit-test/tests/jaeger/bug582185.js b/js/src/jit-test/tests/jaeger/bug582185.js new file mode 100644 index 0000000..38d1c42 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug582185.js @@ -0,0 +1,3 @@ +let c = (this != 4.2); + +/* Don't assert. */ diff --git a/js/src/jit-test/tests/jaeger/bug582286.js b/js/src/jit-test/tests/jaeger/bug582286.js new file mode 100644 index 0000000..094366a --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug582286.js @@ -0,0 +1,3 @@ +evalcx("function s(){}",evalcx('lazy')) + + diff --git a/js/src/jit-test/tests/jaeger/bug582392.js b/js/src/jit-test/tests/jaeger/bug582392.js new file mode 100644 index 0000000..ad60d3f --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug582392.js @@ -0,0 +1,8 @@ +function cmp(x, y) { + if (x < y) + return -1; + if (x > y) + return 1; + return 0; +} +assertEq(cmp('true', 'false'), 1); diff --git a/js/src/jit-test/tests/jaeger/bug582880.js b/js/src/jit-test/tests/jaeger/bug582880.js new file mode 100644 index 0000000..0a8e5d0 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug582880.js @@ -0,0 +1,9 @@ +x = +default xml namespace = []; +(function () { + function a() {} + a([7].some(gc)) +}()) + +/* Don't crash or assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug582882.js b/js/src/jit-test/tests/jaeger/bug582882.js new file mode 100644 index 0000000..2fafca5 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug582882.js @@ -0,0 +1,11 @@ +// |jit-test| error: ReferenceError +function f1(code) { + f = Function(code) + f2() +} +function f2() { + f() +} +f1("d=this.__defineGetter__(\"x\",gc)") +f1("b(x&=w);function b(){}") + diff --git a/js/src/jit-test/tests/jaeger/bug582884.js b/js/src/jit-test/tests/jaeger/bug582884.js new file mode 100644 index 0000000..3d5d995 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug582884.js @@ -0,0 +1,7 @@ +(function () { + x ^ x++ + var x +})() + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug582894.js b/js/src/jit-test/tests/jaeger/bug582894.js new file mode 100644 index 0000000..1343da0 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug582894.js @@ -0,0 +1,6 @@ +for each(let e in [0x40000000]) { + (0)[e] +} + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug582897.js b/js/src/jit-test/tests/jaeger/bug582897.js new file mode 100644 index 0000000..ef846ce --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug582897.js @@ -0,0 +1,6 @@ +let(x) { + x + x-- +} + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug582898.js b/js/src/jit-test/tests/jaeger/bug582898.js new file mode 100644 index 0000000..38080ef --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug582898.js @@ -0,0 +1,6 @@ +let(x = "") { + x++ + assertEq(x, 1); +} + +/* Test no assert. */ diff --git a/js/src/jit-test/tests/jaeger/bug582900.js b/js/src/jit-test/tests/jaeger/bug582900.js new file mode 100644 index 0000000..1da5539 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug582900.js @@ -0,0 +1,3 @@ +// |jit-test| error: ReferenceError + +[].x >>= a | 0 diff --git a/js/src/jit-test/tests/jaeger/bug583158.js b/js/src/jit-test/tests/jaeger/bug583158.js new file mode 100644 index 0000000..6d8c124 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug583158.js @@ -0,0 +1,9 @@ +// |jit-test| error: ReferenceError +function g() { + var rv = (function() { + this << 1 + })() + if (a) (function() {}) +} +g() + diff --git a/js/src/jit-test/tests/jaeger/bug583160.js b/js/src/jit-test/tests/jaeger/bug583160.js new file mode 100644 index 0000000..928f588 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug583160.js @@ -0,0 +1,10 @@ +(function() { + for (a in []) { + (function() {}) + ([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +h.I]) + } +})() + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug583672.js b/js/src/jit-test/tests/jaeger/bug583672.js new file mode 100644 index 0000000..79335ec --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug583672.js @@ -0,0 +1,30 @@ +(function () { + function f() + { + this.y = w + this.y = (void 0) + Object + } + for (a in [0, 0, 0, 0]) + { + new f + } + let w = {} +})() + +/* Make sure that MICs don't have the same bug. */ +x = Object(); +(function () { + function f() + { + x = w + x = (void 0) + Object + } + for (a in [0, 0, 0, 0]) + { + new f + } + let w = {} +})() +/* Don't assert. */ diff --git a/js/src/jit-test/tests/jaeger/bug583684.js b/js/src/jit-test/tests/jaeger/bug583684.js new file mode 100644 index 0000000..c034362 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug583684.js @@ -0,0 +1,8 @@ +// |jit-test| error: TypeError +(function () { + var b = e + for (var [e] = b in w) c +})() + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug583688.js b/js/src/jit-test/tests/jaeger/bug583688.js new file mode 100644 index 0000000..c13f616 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug583688.js @@ -0,0 +1,10 @@ +// |jit-test| error: ReferenceError +this.__defineSetter__("x", function () {}) +try { + this.__defineGetter__("d", (Function("x"))) +} catch (e) {} +d +print(delete x) +throw d + + diff --git a/js/src/jit-test/tests/jaeger/bug583689.js b/js/src/jit-test/tests/jaeger/bug583689.js new file mode 100644 index 0000000..edb3248 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug583689.js @@ -0,0 +1,7 @@ +function f() { + if (-[]) delete y +} +for (c in [0, 0, 0, 0]) { + new f +} + diff --git a/js/src/jit-test/tests/jaeger/bug584644-2.js b/js/src/jit-test/tests/jaeger/bug584644-2.js new file mode 100644 index 0000000..dfee51a --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug584644-2.js @@ -0,0 +1,7 @@ +this.__defineSetter__("x",/a/) +Function("\ + for each(w in[0,0,0]) {\ + for each(y in[0,0,0,0,0,0,0,0,x,0,0,0,0,0,0,0,0,0,x,0,0,0,0,0,0,0,x]) {}\ + }\ +")() + diff --git a/js/src/jit-test/tests/jaeger/bug584646.js b/js/src/jit-test/tests/jaeger/bug584646.js new file mode 100644 index 0000000..5667392 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug584646.js @@ -0,0 +1,7 @@ +switch (0) { + case 2: + k; + case (-1): + case 2: +} +/* Don't assert. */ diff --git a/js/src/jit-test/tests/jaeger/bug584647.js b/js/src/jit-test/tests/jaeger/bug584647.js new file mode 100644 index 0000000..7f0e659 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug584647.js @@ -0,0 +1,2 @@ +(function(){for(j=0;j<3;++j)NaN=42})(); +assertEq(NaN != NaN, true); diff --git a/js/src/jit-test/tests/jaeger/bug585310.js b/js/src/jit-test/tests/jaeger/bug585310.js new file mode 100644 index 0000000..0f65c91 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug585310.js @@ -0,0 +1,19 @@ +gczeal(2) +try { + (function () { + for each(l in [0, 0, 0]) { + print(''.replace(function () {})) + } + })() +} catch (e) {} + +x = gczeal(2) +try { + (function () { + for each(d in [x, x, x]) { + 'a'.replace(/a/, function () {}) + } + })() +} catch (e) {} + +/* Don't assert or segfault. Tests PIC resetting. */ diff --git a/js/src/jit-test/tests/jaeger/bug585341.js b/js/src/jit-test/tests/jaeger/bug585341.js new file mode 100644 index 0000000..1a4933c --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug585341.js @@ -0,0 +1,6 @@ +this.__defineGetter__("x", Float64Array) +Function("\ + with(this) {\ + eval(\"x\")\ + }\ +")() diff --git a/js/src/jit-test/tests/jaeger/bug585391.js b/js/src/jit-test/tests/jaeger/bug585391.js new file mode 100644 index 0000000..28f969c --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug585391.js @@ -0,0 +1,11 @@ +var x = (function () { + return [, , ] +}()); +(function () { + while (x > 7 & 0) { + return + } +}()) + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug585408-2.js b/js/src/jit-test/tests/jaeger/bug585408-2.js new file mode 100644 index 0000000..b77f1a9 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug585408-2.js @@ -0,0 +1,6 @@ +for (let c in []) { + c << c++ +} + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug585408-3.js b/js/src/jit-test/tests/jaeger/bug585408-3.js new file mode 100644 index 0000000..9359aba --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug585408-3.js @@ -0,0 +1,7 @@ +(function() { + function a() {} + a > a-- +})() + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug585408.js b/js/src/jit-test/tests/jaeger/bug585408.js new file mode 100644 index 0000000..118f219 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug585408.js @@ -0,0 +1,7 @@ +(function() { + function a() {} + a.e = a++ +})() + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug585540.js b/js/src/jit-test/tests/jaeger/bug585540.js new file mode 100644 index 0000000..0fae459 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug585540.js @@ -0,0 +1,13 @@ +try { + (function () { + gczeal(2)() + })() +} catch (e) {} +(function () { + for (y in [/x/, Boolean, Boolean, 0, Boolean]) { + [Math.floor(this)].some(function () {}) + } +})() + +/* Don't crash. */ + diff --git a/js/src/jit-test/tests/jaeger/bug587431.js b/js/src/jit-test/tests/jaeger/bug587431.js new file mode 100644 index 0000000..bfad857 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug587431.js @@ -0,0 +1,29 @@ +function g() { + var UPPER_MASK = 2147483648 + var mt = new Array + function f1(n1) { + return n1 < 0 ? (n1 ^ UPPER_MASK) + UPPER_MASK: n1 + } + function f2(n1, n2) { + return f1(n1 + n2 & 4294967295) + } + function f3(n1, n2) { + var sum + for (var i = 0; i < 32; ++i) { + sum = f2(sum, f1(n2 << i)) + } + return sum + } + this.init_genrand = function(s) { + mt[0] = f1(s & 96295) + for (mti = 1; mti < 6; mti++) { + mt[mti] = f2(f3(3, f1(mt[mti - 1] ^ mt[1] > 0)), mti) + } + } +} (function() { + var fuzzMT = new g; + fuzzMT.init_genrand(54) +} ()) + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug588338.js b/js/src/jit-test/tests/jaeger/bug588338.js new file mode 100644 index 0000000..65c3095 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug588338.js @@ -0,0 +1,14 @@ +// |jit-test| error: is not a function +function f() { (e) +} (x = Proxy.createFunction((function(x) { + return { + get: function(r, b) { + return x[b] + } + } +})(/x/), wrap)) +for (z = 0; z < 100; x.unwatch(), z++) +for (e in [0]) { + gczeal(2) +} ( )("") + diff --git a/js/src/jit-test/tests/jaeger/bug588362-1.js b/js/src/jit-test/tests/jaeger/bug588362-1.js new file mode 100644 index 0000000..9afcbdb --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug588362-1.js @@ -0,0 +1,8 @@ +for (a = 0; a < HOTLOOP + 5; a++) { + (function e() { + yield eval() + }()) +} + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug588362-2.js b/js/src/jit-test/tests/jaeger/bug588362-2.js new file mode 100644 index 0000000..3acdbe3 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug588362-2.js @@ -0,0 +1,10 @@ +for (a = 0; a < HOTLOOP + 5; a++) { + (function n() { + with({}) { + yield + } + } ()) +} + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug588362-3.js b/js/src/jit-test/tests/jaeger/bug588362-3.js new file mode 100644 index 0000000..7f6c622 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug588362-3.js @@ -0,0 +1,10 @@ +for (a = 0; a < HOTLOOP + 5; a++) { + (function n() { { + function s() {} + } + yield[]; + }()); +} + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug588363-1.js b/js/src/jit-test/tests/jaeger/bug588363-1.js new file mode 100644 index 0000000..da3d346 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug588363-1.js @@ -0,0 +1,5 @@ +({eval} = Object.defineProperty(evalcx("lazy"), "", {})) +eval("eval(/x/)", []) + +/* Don't assert or crash. */ + diff --git a/js/src/jit-test/tests/jaeger/bug588363-2.js b/js/src/jit-test/tests/jaeger/bug588363-2.js new file mode 100644 index 0000000..5550be3 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug588363-2.js @@ -0,0 +1,7 @@ +with(evalcx('')) { + delete eval; + eval("x", this.__defineGetter__("x", Function)); +} + +/* Don't assert or crash. */ + diff --git a/js/src/jit-test/tests/jaeger/bug589108.js b/js/src/jit-test/tests/jaeger/bug589108.js new file mode 100644 index 0000000..ecf369a --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug589108.js @@ -0,0 +1,10 @@ +try { + var x + for (x in >) + gczeal(2) + new NaN +} catch(e) {} +(function() { + for (a in [Boolean(), x.t]) {} +} (function() {})) + diff --git a/js/src/jit-test/tests/jaeger/bug589115.js b/js/src/jit-test/tests/jaeger/bug589115.js new file mode 100644 index 0000000..32a6beb --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug589115.js @@ -0,0 +1,6 @@ +for each(y in ['', 0, '']) { + y.lastIndexOf-- +} + +/* Don't assert/crash. */ + diff --git a/js/src/jit-test/tests/jaeger/bug589461.js b/js/src/jit-test/tests/jaeger/bug589461.js new file mode 100644 index 0000000..89fc7ac --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug589461.js @@ -0,0 +1,7 @@ +function f(h, i, Q) { + var L = Q; + var H = h; + + return h[i] * L ^ L * 0x1010100; +} +assertEq(f([6], 0, 12345), 1768429654); diff --git a/js/src/jit-test/tests/jaeger/bug590083.js b/js/src/jit-test/tests/jaeger/bug590083.js new file mode 100644 index 0000000..c11c7a1 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug590083.js @@ -0,0 +1,11 @@ +eval("\ + (function(){\ + for(var w in [0]) {\ + function w(){}\ + print(w)\ + }\ + })\ +")() + +/* Don't crash. */ + diff --git a/js/src/jit-test/tests/jaeger/bug591602.js b/js/src/jit-test/tests/jaeger/bug591602.js new file mode 100644 index 0000000..a6ba464 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug591602.js @@ -0,0 +1,40 @@ +try { + for (x in ['']) { + gczeal(2) + } +} catch(e) {} +try { + var x, e + p() +} catch(e) {} +try { (function() { + let(x)((function() { + let(y)((function() { + try { + let(c) o + } finally { (f, *::*) + } + })) + })) + })() +} catch(e) {} +try { (function() { + if (x.w("", (function() { + t + })())) {} + })() +} catch(e) {} +try { + gczeal() +} catch(e) {} +try { (function() { + for (let w in [0, 0]) let(b)((function() { + let(x = w = [])((function() { + for (let a in []); + })) + })()) + })() +} catch(e) {} + +/* Don't assert with -m only. */ + diff --git a/js/src/jit-test/tests/jaeger/bug591606.js b/js/src/jit-test/tests/jaeger/bug591606.js new file mode 100644 index 0000000..cb711f0 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug591606.js @@ -0,0 +1,5 @@ +var c = [] +function c() {} + +/* Don't assert. */ + diff --git a/js/src/jit-test/tests/jaeger/bug592973-1.js b/js/src/jit-test/tests/jaeger/bug592973-1.js new file mode 100644 index 0000000..470f84e --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug592973-1.js @@ -0,0 +1,12 @@ +// vim: set ts=4 sw=4 tw=99 et: +function f(x) { + if (x) { + let y; + y = 12; + (function () { + assertEq(y, 12); + })(); + } +} +f(1); + diff --git a/js/src/jit-test/tests/jaeger/bug592973-2.js b/js/src/jit-test/tests/jaeger/bug592973-2.js new file mode 100644 index 0000000..052c622 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug592973-2.js @@ -0,0 +1,7 @@ +function f(a) { + function a() { + } +} + +/* Don't assert on JOF_NAME test in BindNameToSlot(). */ + diff --git a/js/src/jit-test/tests/jaeger/bug592973-3.js b/js/src/jit-test/tests/jaeger/bug592973-3.js new file mode 100644 index 0000000..ae46949 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug592973-3.js @@ -0,0 +1,8 @@ +// vim: set ts=4 sw=4 tw=99 et: +function f([a, b, c, d]) { + a = b; + return function () { return a + b + c + d; }; +} + +var F = f(["a", "b", "c", "d"]); +assertEq(F(), "bbcd"); diff --git a/js/src/jit-test/tests/jaeger/bug593554.js b/js/src/jit-test/tests/jaeger/bug593554.js new file mode 100644 index 0000000..20143da --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug593554.js @@ -0,0 +1,8 @@ +/* Don't assert. */ +var b = 7; +var a = []; +for (var j = 0; j < 7; ++j) { + var d = {}; + a.push(b >> d); +} +assertEq(a.toString(), '7,7,7,7,7,7,7'); diff --git a/js/src/jit-test/tests/jaeger/bug595917.js b/js/src/jit-test/tests/jaeger/bug595917.js new file mode 100644 index 0000000..1b3e132 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug595917.js @@ -0,0 +1,4 @@ +if (!this.parseInt) { + var parseInt = function () { return 5; } +} +assertEq(parseInt(10), 10); diff --git a/js/src/jit-test/tests/jaeger/bug595921.js b/js/src/jit-test/tests/jaeger/bug595921.js new file mode 100644 index 0000000..a5113ad --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug595921.js @@ -0,0 +1,9 @@ +/* Don't assert. */ +x = +function f(aaa) { + aaa.e = x +} +for each(let c in [x, x, x]) { + f(c) +} +assertEq(0,0); diff --git a/js/src/jit-test/tests/jaeger/bug597378.js b/js/src/jit-test/tests/jaeger/bug597378.js new file mode 100644 index 0000000..454935b --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug597378.js @@ -0,0 +1,12 @@ +// vim: set ts=4 sw=4 tw=99 et: +function f(a, b) { + var o = a; + var q = b; + var p; + do { } while (0); + p = o; + q = p + 1 < q ? p + 1 : 0; + assertEq(q, 0); +} +f(3, 4); + diff --git a/js/src/jit-test/tests/jaeger/bug597871.js b/js/src/jit-test/tests/jaeger/bug597871.js new file mode 100644 index 0000000..a0bb261 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug597871.js @@ -0,0 +1,8 @@ +for (a in [0, 0, 0, 0, 0, 0, 0, 0, 0]) { + try { (function() { + for each(l in [false, 0, 0, 0]) {} + h + })() + } catch(e) {} +} + diff --git a/js/src/jit-test/tests/jaeger/bug598696.js b/js/src/jit-test/tests/jaeger/bug598696.js new file mode 100644 index 0000000..129275d --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug598696.js @@ -0,0 +1,6 @@ +function f() { + eval(); + var i = 0; + assertEq(++i, 1); +} +f(); diff --git a/js/src/jit-test/tests/jaeger/bug599488.js b/js/src/jit-test/tests/jaeger/bug599488.js new file mode 100644 index 0000000..f2cf952 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug599488.js @@ -0,0 +1,9 @@ +/* Don't crash. */ +function foo(y) { + var x = y; + if (x != x) + return true; + return false; +} +assertEq(foo("three"), false); +assertEq(foo(NaN), true); diff --git a/js/src/jit-test/tests/jaeger/bug600139.js b/js/src/jit-test/tests/jaeger/bug600139.js new file mode 100644 index 0000000..0328479 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug600139.js @@ -0,0 +1,11 @@ +// |jit-test| error: ReferenceError +// vim: set ts=4 sw=4 tw=99 et: +function f(a, b, c) { + if (!a.__SSi) { + throw Components.returnCode = Cr.NS_ERROR_INVALID_ARG; + } + this.restoreWindow(a, b, c); + eval(); +} +dis(f); +f(1, 2, 3); diff --git a/js/src/jit-test/tests/jaeger/bug600419.js b/js/src/jit-test/tests/jaeger/bug600419.js new file mode 100644 index 0000000..981a6a1 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug600419.js @@ -0,0 +1,5 @@ +/* Don't assert. */ +(function() { + var x; + [1].map(function(){}, x << x); +})() diff --git a/js/src/jit-test/tests/jaeger/bug600424.js b/js/src/jit-test/tests/jaeger/bug600424.js new file mode 100644 index 0000000..44bb4e7 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug600424.js @@ -0,0 +1,14 @@ +// vim: set ts=4 sw=4 tw=99 et: +function f(a) { + var x = { + g: function () { + return this.a; + } + }; + x.g.prototype.a = a; + assertEq(x.g.prototype.a, a); + return x; +} +f(1); +f(2); +f(3); diff --git a/js/src/jit-test/tests/jaeger/bug601400.js b/js/src/jit-test/tests/jaeger/bug601400.js new file mode 100644 index 0000000..cb9ae27 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug601400.js @@ -0,0 +1,8 @@ +// |jit-test| error: TypeError + +eval("\ + function NaN() {}\ + for(w in s) {}\ +") + +// Don't assert. diff --git a/js/src/jit-test/tests/jaeger/bug601982.js b/js/src/jit-test/tests/jaeger/bug601982.js new file mode 100644 index 0000000..b874444 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug601982.js @@ -0,0 +1,33 @@ +/* vim: set ts=4 sw=4 tw=99 et: */ + +function J(i) { + /* Cause a branch to build. */ + if (i % 3) + +} + +function h(i) { + J(i); + + /* Generate a safe point in the method JIT. */ + if (1 == 14) { eval(); } + + return J(i); +} + +function g(i) { + /* Method JIT will try to remove this frame. */ + if (i == 14) { } + return h(i); +} + +function f() { + for (var i = 0; i < RUNLOOP * 2; i++) { + g(i); + } +} + +f(); + +/* Don't crash. */ + diff --git a/js/src/jit-test/tests/jaeger/bug604381.js b/js/src/jit-test/tests/jaeger/bug604381.js new file mode 100644 index 0000000..365c9e3 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug604381.js @@ -0,0 +1,14 @@ +// vim: set ts=4 sw=4 tw=99 et: + +function F() { + var T = { }; + try { + throw 12; + } catch (e) { + T.x = 5; + return T; + } +} + +assertEq((new F()).x, 5); + diff --git a/js/src/jit-test/tests/jaeger/bug604427.js b/js/src/jit-test/tests/jaeger/bug604427.js new file mode 100644 index 0000000..1e37df8 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug604427.js @@ -0,0 +1,6 @@ + +function testInt(x) { + var a = x|0; + return (a !== a); +} +assertEq(testInt(10), false); diff --git a/js/src/jit-test/tests/jaeger/bug606662-1.js b/js/src/jit-test/tests/jaeger/bug606662-1.js new file mode 100644 index 0000000..63ec9d0 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug606662-1.js @@ -0,0 +1,5 @@ +// don't assert +new(function() { + #1# +}) + diff --git a/js/src/jit-test/tests/jaeger/bug606662-2.js b/js/src/jit-test/tests/jaeger/bug606662-2.js new file mode 100644 index 0000000..b4fae0d --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug606662-2.js @@ -0,0 +1,5 @@ +// don't crash +try{a()}catch(e){} +try{for(e in((JSON.e)(x=/x/)))throw []}catch(e){} +try{(function(){c()})()}catch(e){} +try{new function(){#1#}}catch(e){} diff --git a/js/src/jit-test/tests/jaeger/bug606829.js b/js/src/jit-test/tests/jaeger/bug606829.js new file mode 100644 index 0000000..1839c93 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug606829.js @@ -0,0 +1,8 @@ +/* Don't assert. */ +function f(x) +{ + if ("hi" == (x & 3)) { + return 1; + } +} +f(12); diff --git a/js/src/jit-test/tests/jaeger/bug610652.js b/js/src/jit-test/tests/jaeger/bug610652.js new file mode 100644 index 0000000..b5c64d1 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug610652.js @@ -0,0 +1,5 @@ +function a1(a2) { + return 10 - a2; +} +a3 = a1(-2147483648); +assertEq(a3, 2147483658); diff --git a/js/src/jit-test/tests/jaeger/bug615440.js b/js/src/jit-test/tests/jaeger/bug615440.js new file mode 100644 index 0000000..1ed4cd1 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug615440.js @@ -0,0 +1,5 @@ +Array.prototype.__proto__ = null; +for (var r = 0; r < 3; ++r) [][0] = 1; + +// Don't crash. + diff --git a/js/src/jit-test/tests/jaeger/bug616508.js b/js/src/jit-test/tests/jaeger/bug616508.js new file mode 100644 index 0000000..8548ce4 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug616508.js @@ -0,0 +1,9 @@ +// |jit-test| error: ReferenceError +// vim: set ts=4 sw=4 tw=99 et: +try { + (function () { + __proto__ = Uint32Array() + }()) +} catch (e) {}(function () { + length, ([eval()] ? x : 7) +})() diff --git a/js/src/jit-test/tests/jaeger/bug618007.js b/js/src/jit-test/tests/jaeger/bug618007.js new file mode 100644 index 0000000..daa43e5 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug618007.js @@ -0,0 +1,31 @@ +var appendToActual = function(s) { + actual += s + ','; +} + +for(var z=0; z < 3; z++) { + function ff() { + } + ff(); + + // jit-test/tests/closures/setname-closure.js + actual = ''; + expected = '2,4,8,16,32,undefined,64,128,256,512,1024,undefined,2048,4096,8192,16384,32768,undefined,65536,131072,262144,524288,1048576,undefined,2097152,4194304,8388608,16777216,33554432,undefined,'; + + var f = function() { + var p = 1; + function g() { + for (var i = 0; i < 5; ++i) { + p = p * 2; + appendToActual(p); + } + } + return g; + } + var g = f(); + for (var i = 0; i < 5; ++i) { + g(); + appendToActual(); + } + assertEq(actual, expected); +} + diff --git a/js/src/jit-test/tests/jaeger/bug620643.js b/js/src/jit-test/tests/jaeger/bug620643.js new file mode 100644 index 0000000..fcb096e --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug620643.js @@ -0,0 +1 @@ +var a = new Int32Array(); +(a[0]={}); diff --git a/js/src/jit-test/tests/jaeger/bug623474.js b/js/src/jit-test/tests/jaeger/bug623474.js new file mode 100644 index 0000000..bda9088 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug623474.js @@ -0,0 +1,10 @@ +for (var j=0;j<2;++j) { (function(o){o.length})(String.prototype); } + +for each(let y in [Number, Number]) { + try { + "".length() + } catch(e) {} +} + +/* Don't crash. */ + diff --git a/js/src/jit-test/tests/jaeger/bug624100.js b/js/src/jit-test/tests/jaeger/bug624100.js new file mode 100644 index 0000000..744ca01 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug624100.js @@ -0,0 +1,2 @@ +// |jit-test| error: ReferenceError +eval("'use strict'; for(let j=0;j<9;++j) {} x;"); diff --git a/js/src/jit-test/tests/jaeger/bug624483.js b/js/src/jit-test/tests/jaeger/bug624483.js new file mode 100644 index 0000000..480e539 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug624483.js @@ -0,0 +1,5 @@ +var arr = new Uint8ClampedArray(16); +for (var i = 0; i < 16; i++) { + arr[i] = "Infinity"; +} +assertEq(arr[14], 255); diff --git a/js/src/jit-test/tests/jaeger/bug625157.js b/js/src/jit-test/tests/jaeger/bug625157.js new file mode 100644 index 0000000..53bed4e --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug625157.js @@ -0,0 +1,16 @@ +function f() { + { + function g() { + var a = []; + for (var i = 0; i < 10; i++) + a.push({}); + for (var i = 0; i < 10; i++) + a[i].m = function() { return 0; } + assertEq(a[8].m !== a[9].m, true); + } + g(); + } +} +f() + + diff --git a/js/src/jit-test/tests/jaeger/bug625377.js b/js/src/jit-test/tests/jaeger/bug625377.js new file mode 100644 index 0000000..4c78939 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug625377.js @@ -0,0 +1,13 @@ +x = [] +for(var i=0; i<3; i++) { + var obj = { first: "first", second: "second" }; + var count = 0; + for (var elem in obj) { + delete obj.second; + count++; + } + x.push(count); +} +assertEq(x[0], 1); +assertEq(x[1], 1); +assertEq(x[2], 1); diff --git a/js/src/jit-test/tests/jaeger/bug625438.js b/js/src/jit-test/tests/jaeger/bug625438.js new file mode 100644 index 0000000..494bfd1 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug625438.js @@ -0,0 +1,10 @@ +// vim: set ts=4 sw=4 tw=99 et: + +var count = 0; +this.watch("x", function() { + count++; +}); +for(var i=0; i<10; i++) { + x = 2; +} +assertEq(count, 10); diff --git a/js/src/jit-test/tests/jaeger/bug625718-1.js b/js/src/jit-test/tests/jaeger/bug625718-1.js new file mode 100644 index 0000000..601c2a8 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug625718-1.js @@ -0,0 +1,12 @@ +function f3() { return 2; }; +function f4(o) { o.g4 = function() {}; }; + +var f = function() {}; +f.x = undefined; +f4(new String("x")); +f3(); +f4(f); + +for(var i=0; i<20; i++) { + f4(Math); +} diff --git a/js/src/jit-test/tests/jaeger/bug625718-2.js b/js/src/jit-test/tests/jaeger/bug625718-2.js new file mode 100644 index 0000000..0298195 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug625718-2.js @@ -0,0 +1,14 @@ +var o3 = new String("foobarbaz"); +var o10 = Math; +var o11 = function() {}; + +function f3(o) { return o; }; +function f4(o) { o.g4 = function() {}; }; + +for(var i=0; i<20; i++) { + o11[3] = undefined; + f4(o3); + f3(o3); + f4(o11); + f4(o10); +} diff --git a/js/src/jit-test/tests/jaeger/bug625718-3.js b/js/src/jit-test/tests/jaeger/bug625718-3.js new file mode 100644 index 0000000..81e7881 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug625718-3.js @@ -0,0 +1,52 @@ +var o0 = []; +var o1 = new String("foobarbaz"); +var o2 = {}; +var o3 = new String("foobarbaz"); +var o4 = {}; +var o5 = Math; +var o6 = {}; +var o7 = new String("foobarbaz"); +var o8 = new String("foobarbaz"); +var o9 = Math; +var o10 = Math; +var o11 = function() {}; +var o12 = {}; +var o13 = new String("foobarbaz"); +var o14 = {}; + +function f1(o) { return o.length;}; +function f2(o) { o.g2 = function() {};}; +function f3(o) { return o.g10;}; +function f4(o) { o.g4 = function() {};}; +function f5(o) { return o == o14;}; +function f6(o) { o[3] = o;}; +function f7(o) { o[3] = undefined;}; +function f8(o) { o[3] = undefined;}; +function f9(o) { return o.length;}; +function f10(o) { return o.__proto__; }; + +for(var i=0; i<20; i++) { + f9(o11); + f6(o0); + f2(o1); + f2(o6); + f7(o6); + f8(o11); + f2(o5); + f7(o9); + f7(o12); + f6(o4); + f5(o1); + f4(o1); + f8(o8); + f6(o5); + f2(o0); + f10(o7); + f3(o3); + f4(o1); + f9(o3); + f4(o11); + f4(o0); + f2(o4); + f4(o10); +} diff --git a/js/src/jit-test/tests/jaeger/bug625757.js b/js/src/jit-test/tests/jaeger/bug625757.js new file mode 100644 index 0000000..458c160 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug625757.js @@ -0,0 +1,4 @@ +for(var i=0; i<20; i++) { + var x = 5e-324; +} +/* Don't crash. */ diff --git a/js/src/jit-test/tests/jaeger/bug627486.js b/js/src/jit-test/tests/jaeger/bug627486.js new file mode 100644 index 0000000..f87d27e --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug627486.js @@ -0,0 +1,23 @@ +// |jit-test| error: TypeError +// vim: set ts=4 sw=4 tw=99 et: +g = undefined; +function L() { } + +function h() { + with (h) { } + for (var i = 0; i < 10; i++) + g(); +} + +function f(x) { + g = x; +} + +f(L); +h(); +f(L); +f(2); +h(); + +/* Don't assert/crash. */ + diff --git a/js/src/jit-test/tests/jaeger/bug630366.js b/js/src/jit-test/tests/jaeger/bug630366.js new file mode 100644 index 0000000..acac8d3 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/bug630366.js @@ -0,0 +1,7 @@ +var o = {}; +for(var i=0; i<5; i++) { + o.p = 2; + o.watch("p", function() { }); + o.p = 2; + delete o.p; +} diff --git a/js/src/jit-test/tests/jaeger/compare-wrong-1.js b/js/src/jit-test/tests/jaeger/compare-wrong-1.js new file mode 100644 index 0000000..dec3ada --- /dev/null +++ b/js/src/jit-test/tests/jaeger/compare-wrong-1.js @@ -0,0 +1,4 @@ +function f(a) { return a; } +assertEq(print < f, false); +assertEq(print > f, true); + diff --git a/js/src/jit-test/tests/jaeger/crash-on-compare.js b/js/src/jit-test/tests/jaeger/crash-on-compare.js new file mode 100644 index 0000000..5abd7aa --- /dev/null +++ b/js/src/jit-test/tests/jaeger/crash-on-compare.js @@ -0,0 +1 @@ +assertEq(Infinity >= Infinity ? true : false, true); diff --git a/js/src/jit-test/tests/jaeger/deepBailAfterRunTracer.js b/js/src/jit-test/tests/jaeger/deepBailAfterRunTracer.js new file mode 100644 index 0000000..63399a4 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/deepBailAfterRunTracer.js @@ -0,0 +1,25 @@ +var o = { }; +for (var i = 0; i <= 50; i++) + o[i] = i; + +Object.defineProperty(o, "51", { get: assertEq }); + +var threw = 0; +function g(o, i) { + try { + assertEq(o[i], i); + } catch (e) { + threw++; + } +} + +function f() { + for (var i = 0; i <= 51; i++) + g(o, i); +} + +f(); +f(); +f(); +assertEq(threw, 3); + diff --git a/js/src/jit-test/tests/jaeger/floatTypedArrays.js b/js/src/jit-test/tests/jaeger/floatTypedArrays.js new file mode 100644 index 0000000..da1abe0 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/floatTypedArrays.js @@ -0,0 +1,64 @@ +// vim: set ts=4 sw=4 tw=99 et: + +function testFloat32Array(L) { + var f = new Float32Array(8); + assertEq(f[0], 0); + assertEq(f[L], 0); + assertEq(f[L+8], undefined); + assertEq(f[8], undefined); + f[0] = 12; + f[L+1] = 13.5; + f[2] = f[1]; + f[L+3] = 4294967295; + f[L+4] = true; + f[L+5] = L; + assertEq(f[0], 12); + assertEq(f[1], 13.5); + assertEq(f[2], 13.5); + assertEq(f[3], 4294967296); + assertEq(f[4], 1); + assertEq(f[5], 0); +} + +function testFloat64Array(L) { + var f = new Float64Array(8); + assertEq(f[0], 0); + assertEq(f[L], 0); + assertEq(f[L+8], undefined); + assertEq(f[8], undefined); + f[0] = 12; + f[L+1] = 13.5; + f[2] = f[1]; + f[L+3] = 4294967295; + f[L+4] = true; + f[L+5] = L; + assertEq(f[0], 12); + assertEq(f[1], 13.5); + assertEq(f[2], 13.5); + assertEq(f[3], 4294967295); + assertEq(f[4], 1); + assertEq(f[5], 0); +} + +function testNaNCanonicalization() { + var buf = new ArrayBuffer(128); + + var u8 = new Uint8Array(buf); + for (var i = 0; i < 128; i++) + u8[i] = 0xFF; + + var dblarr = new Float64Array(buf); + var asstr = dblarr[0] + ""; + var asnum = dblarr[0] + 0.0; + assertEq(asstr, "NaN"); + assertEq(asnum, NaN); +} + +for (var i = 0; i < 10; i++) { + //testFloat32Array(0); + //testFloat64Array(0); + testNaNCanonicalization(); + if (i == 5) + gc(); +} + diff --git a/js/src/jit-test/tests/jaeger/fused-eq-ifeq.js b/js/src/jit-test/tests/jaeger/fused-eq-ifeq.js new file mode 100644 index 0000000..b5d2bf2 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/fused-eq-ifeq.js @@ -0,0 +1,6 @@ +function ack(m,n){ + if (m==0) { return n+1; } + if (n==0) { return ack(m-1,1); } + return ack(m-1, ack(m,n-1) ); +} +assertEq(ack(3, 3), 61); diff --git a/js/src/jit-test/tests/jaeger/getelem-sanity-1.js b/js/src/jit-test/tests/jaeger/getelem-sanity-1.js new file mode 100644 index 0000000..4bad91e --- /dev/null +++ b/js/src/jit-test/tests/jaeger/getelem-sanity-1.js @@ -0,0 +1,9 @@ +var obj = {attr: 'value'}; + +(function() { + var name = 'attr'; + for (var i = 0; i < 10; ++i) + assertEq(obj[name], 'value'); +})(); + +/* Look up a string id. */ diff --git a/js/src/jit-test/tests/jaeger/getelem-sanity-2.js b/js/src/jit-test/tests/jaeger/getelem-sanity-2.js new file mode 100644 index 0000000..399219b --- /dev/null +++ b/js/src/jit-test/tests/jaeger/getelem-sanity-2.js @@ -0,0 +1,22 @@ +var obj = {firstAttr: 'value', secondAttr: 'another value'}; + +(function() { + for (var i = 0; i < 12; ++i) { + var name; + if (i < 4) + name = 'firstAttr'; + else if (i < 8) + name = 'secondAttr'; + else + name = 'firstAttr'; + + var result = obj[name]; + + switch (name) { + case 'firstAttr': assertEq(result, 'value'); break; + case 'secondAttr': assertEq(result, 'another value'); break; + } + } +})(); + +/* Toggle lookup between two ids. */ diff --git a/js/src/jit-test/tests/jaeger/getelem-sanity-3.js b/js/src/jit-test/tests/jaeger/getelem-sanity-3.js new file mode 100644 index 0000000..4b5b879 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/getelem-sanity-3.js @@ -0,0 +1,22 @@ +var obj = {firstAttr: 'value', secondAttr: 'another value', thirdAttr: 'the last value'}; + +(function() { + for (var i = 0; i < 64; ++i) { + var name; + switch (~~(i / 4) % 3) { + case 0: name = 'firstAttr'; break; + case 1: name = 'secondAttr'; break; + case 2: name = 'thirdAttr'; break; + } + + var result = obj[name]; + + switch (name) { + case 'firstAttr': assertEq(result, 'value'); break; + case 'secondAttr': assertEq(result, 'another value'); break; + case 'thirdAttr': assertEq(result, 'the last value'); break; + } + } +})(); + +/* Rotate lookup between three ids. */ diff --git a/js/src/jit-test/tests/jaeger/getelem-sanity-4.js b/js/src/jit-test/tests/jaeger/getelem-sanity-4.js new file mode 100644 index 0000000..9837133 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/getelem-sanity-4.js @@ -0,0 +1,51 @@ +var obj = { + attr0: 'val0', + attr1: 'val1', + attr2: 'val2', + attr3: 'val3', + attr4: 'val4', + attr5: 'val5', + attr6: 'val6', + attr7: 'val7', + attr8: 'val8', + attr9: 'val9', + attr10: 'val10', + attr11: 'val11', + attr12: 'val12', + attr13: 'val13', + attr14: 'val14', + attr15: 'val15', + attr16: 'val16', + attr17: 'val17', +} + +var baseName = 'attr'; + +(function() { + for (var i = 0; i < 128; ++i) { + var name = baseName + (i % 18); + var result = obj[name]; + switch (i) { + case 0: assertEq('val0', result); break; + case 1: assertEq('val1', result); break; + case 2: assertEq('val2', result); break; + case 3: assertEq('val3', result); break; + case 4: assertEq('val4', result); break; + case 5: assertEq('val5', result); break; + case 6: assertEq('val6', result); break; + case 7: assertEq('val7', result); break; + case 8: assertEq('val8', result); break; + case 9: assertEq('val9', result); break; + case 10: assertEq('val10', result); break; + case 11: assertEq('val11', result); break; + case 12: assertEq('val12', result); break; + case 13: assertEq('val13', result); break; + case 14: assertEq('val14', result); break; + case 15: assertEq('val15', result); break; + case 16: assertEq('val16', result); break; + case 17: assertEq('val17', result); break; + } + } +})(); + +/* Megamorphic index atom. */ diff --git a/js/src/jit-test/tests/jaeger/getelem-sanity-5.js b/js/src/jit-test/tests/jaeger/getelem-sanity-5.js new file mode 100644 index 0000000..9d3811c --- /dev/null +++ b/js/src/jit-test/tests/jaeger/getelem-sanity-5.js @@ -0,0 +1,4 @@ +var x = { 0: 5, 1: 5 }; +assertEq(x[0] + x[1], 10); + +/* int32 getelem on object. */ diff --git a/js/src/jit-test/tests/jaeger/getelem-sanity-6.js b/js/src/jit-test/tests/jaeger/getelem-sanity-6.js new file mode 100644 index 0000000..693453d --- /dev/null +++ b/js/src/jit-test/tests/jaeger/getelem-sanity-6.js @@ -0,0 +1,4 @@ +var x = {1: 2, 3: 4}; +assertEq(x[1], 2); + +/* getelem with non-dense array and known type int32. */ diff --git a/js/src/jit-test/tests/jaeger/getelem-sanity-7.js b/js/src/jit-test/tests/jaeger/getelem-sanity-7.js new file mode 100644 index 0000000..483d8b5 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/getelem-sanity-7.js @@ -0,0 +1,10 @@ +var obj = {count: 24}; +var key = 'count'; + +for (var i = 0; i < 1024; ++i) { + var result = obj[key]; + if (i === 2) + obj.newAttr = 42; +} + +/* Perform getelem across shape change. */ diff --git a/js/src/jit-test/tests/jaeger/getelem-sanity-int-1.js b/js/src/jit-test/tests/jaeger/getelem-sanity-int-1.js new file mode 100644 index 0000000..8876455 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/getelem-sanity-int-1.js @@ -0,0 +1,7 @@ +var arr = ['this', 'works', 'for', 'me']; +assertEq('this', arr[0]); +assertEq('works', arr[1]); +assertEq('for', arr[2]); +assertEq('me', arr[3]); + +/* Multiple int32 getelem for dense array. */ diff --git a/js/src/jit-test/tests/jaeger/getelem-sanity-int-2.js b/js/src/jit-test/tests/jaeger/getelem-sanity-int-2.js new file mode 100644 index 0000000..3df39d3 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/getelem-sanity-int-2.js @@ -0,0 +1,12 @@ +var arr = ['this', 'works', 'for', 'me']; +for (var i = 0; i < arr.length; ++i) { + var result = arr[i]; + switch (i) { + case 0: assertEq('this', result); break; + case 1: assertEq('works', result); break; + case 2: assertEq('for', result); break; + case 3: assertEq('me', result); break; + } +} + +/* int32 getelem for dense array. */ diff --git a/js/src/jit-test/tests/jaeger/getelem-sanity-int-3.js b/js/src/jit-test/tests/jaeger/getelem-sanity-int-3.js new file mode 100644 index 0000000..f0eaacd --- /dev/null +++ b/js/src/jit-test/tests/jaeger/getelem-sanity-int-3.js @@ -0,0 +1,19 @@ +var a = [1, 2]; +a[3.1415926535] = 'value'; + +for (var i = 0; i < 3; i++) { + var attr; + switch (i) { + case 0: attr = 0; break; + case 1: attr = 1; break; + case 2: attr = 3.1415926535; break; + } + var result = a[attr]; + switch (i) { + case 0: assertEq(result, 1); break; + case 1: assertEq(result, 2); break; + case 2: assertEq(result, 'value'); break; + } +} + +/* int32 and string getelem for non-dense array. */ diff --git a/js/src/jit-test/tests/jaeger/globalOptimize-1.js b/js/src/jit-test/tests/jaeger/globalOptimize-1.js new file mode 100644 index 0000000..f90114c --- /dev/null +++ b/js/src/jit-test/tests/jaeger/globalOptimize-1.js @@ -0,0 +1,5 @@ +/* Test that NaN does not trigger js_InitMathClass & constants while parsing. */ +var NaN + +var x = 2; + diff --git a/js/src/jit-test/tests/jaeger/instanceOfWithKnownTypes.js b/js/src/jit-test/tests/jaeger/instanceOfWithKnownTypes.js new file mode 100644 index 0000000..0ca3dc8 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/instanceOfWithKnownTypes.js @@ -0,0 +1,13 @@ +// |jit-test| error: TypeError + +// Verify that the compiler doesn't assert. + +function f() { + var o = {}, p = {}; + z = o instanceof p; + z = 3 instanceof p; + z = p instanceof 3; + z = 3 instanceof 4; +} + +f(); diff --git a/js/src/jit-test/tests/jaeger/invokeSessionGuard.js b/js/src/jit-test/tests/jaeger/invokeSessionGuard.js new file mode 100644 index 0000000..61b564e --- /dev/null +++ b/js/src/jit-test/tests/jaeger/invokeSessionGuard.js @@ -0,0 +1,8 @@ +// |jit-test| mjitalways;debug + +[1,2,3,4,5,6,7,8].forEach( + function(x) { + // evalInFrame means lightweight gets call obj + assertEq(evalInFrame(0, "x"), x); + } +); diff --git a/js/src/jit-test/tests/jaeger/modConstDoubles.js b/js/src/jit-test/tests/jaeger/modConstDoubles.js new file mode 100644 index 0000000..807782c --- /dev/null +++ b/js/src/jit-test/tests/jaeger/modConstDoubles.js @@ -0,0 +1,8 @@ + +function f() { + var x = 2.6; + var y = 2.1; + return x % y; +} +assertEq(f(), 0.5); + diff --git a/js/src/jit-test/tests/jaeger/modConstInt.js b/js/src/jit-test/tests/jaeger/modConstInt.js new file mode 100644 index 0000000..cdb0711 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/modConstInt.js @@ -0,0 +1,8 @@ + +function f() { + var i = 1000; + var rest = i % 3; + var div = (i - rest) / 3; + assertEq(div, 333); +} +f(); \ No newline at end of file diff --git a/js/src/jit-test/tests/jaeger/modConstZeroRhs.js b/js/src/jit-test/tests/jaeger/modConstZeroRhs.js new file mode 100644 index 0000000..75ef884 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/modConstZeroRhs.js @@ -0,0 +1,8 @@ + +function f() { + var x = 5; + var y = 0; + return x % y; +} +assertEq(f(), NaN); + diff --git a/js/src/jit-test/tests/jaeger/modWithConstLhs.js b/js/src/jit-test/tests/jaeger/modWithConstLhs.js new file mode 100644 index 0000000..67bf398 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/modWithConstLhs.js @@ -0,0 +1,2 @@ +// |jit-test| error: ReferenceError; +7%s; diff --git a/js/src/jit-test/tests/jaeger/mulNegZero.js b/js/src/jit-test/tests/jaeger/mulNegZero.js new file mode 100644 index 0000000..6758dab --- /dev/null +++ b/js/src/jit-test/tests/jaeger/mulNegZero.js @@ -0,0 +1,31 @@ + +function mul(x, y) { return x * y; }; +function mulConst0(x) { return x * 0; }; +function mulConst1(x) { return -5 * x; }; +function mulConst2(x) { return x * -5; }; + +function f() { + assertEq(mulConst0(7), 0); + assertEq(mulConst0(-5), -0); + assertEq(mulConst0(0), 0); + assertEq(mulConst0(-0), -0); + + assertEq(mulConst1(7), -35); + assertEq(mulConst1(-8), 40); + assertEq(mulConst1(0), -0); + assertEq(mulConst1(-0), 0); + + assertEq(mulConst2(7), -35); + assertEq(mulConst2(-8), 40); + assertEq(mulConst2(0), -0); + assertEq(mulConst2(-0), 0); + + assertEq(mul(55, 2), 110); + assertEq(mul(0, -10), -0); + assertEq(mul(-5, 0), -0); + assertEq(mul(-0, 0), -0); + assertEq(mul(0, -0), -0); + assertEq(mul(0, 0), 0); + assertEq(mul(-0, -0), 0); +} +f(); diff --git a/js/src/jit-test/tests/jaeger/negation.js b/js/src/jit-test/tests/jaeger/negation.js new file mode 100644 index 0000000..f0f3e51 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/negation.js @@ -0,0 +1,2 @@ +var n = -2147483648; +assertEq(-n, 2147483648); diff --git a/js/src/jit-test/tests/jaeger/normalIntTypedArrays.js b/js/src/jit-test/tests/jaeger/normalIntTypedArrays.js new file mode 100644 index 0000000..dc5ed7b --- /dev/null +++ b/js/src/jit-test/tests/jaeger/normalIntTypedArrays.js @@ -0,0 +1,49 @@ +// vim: set ts=4 sw=4 tw=99 et: + +function testInt32Array(L) { + var f = new Int32Array(8); + assertEq(f[0], 0); + assertEq(f[L], 0); + assertEq(f[L+8], undefined); + assertEq(f[8], undefined); + f[0] = 12; + f[L+1] = 13; + f[2] = f[1]; + f[L+3] = 4294967295; + f[L+4] = true; + f[L+5] = L; + assertEq(f[0], 12); + assertEq(f[1], 13); + assertEq(f[2], 13); + assertEq(f[3], -1); + assertEq(f[4], 1); + assertEq(f[5], 0); +} + +function testUint32Array(L) { + var f = new Uint32Array(8); + assertEq(f[0], 0); + assertEq(f[L], 0); + assertEq(f[L+8], undefined); + assertEq(f[8], undefined); + f[0] = 12; + f[L+1] = 13; + f[2] = f[1]; + f[L+3] = 4294967295; + f[L+4] = true; + f[L+5] = L; + assertEq(f[0], 12); + assertEq(f[1], 13); + assertEq(f[2], 13); + assertEq(f[3], 4294967295); + assertEq(f[4], 1); + assertEq(f[5], 0); +} + +for (var i = 0; i < 10; i++) { + //testInt32Array(0); + testUint32Array(0); + if (i == 5) + gc(); +} + diff --git a/js/src/jit-test/tests/jaeger/optimize-globals-1.js b/js/src/jit-test/tests/jaeger/optimize-globals-1.js new file mode 100644 index 0000000..4197a27 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/optimize-globals-1.js @@ -0,0 +1,9 @@ + +function testLocalNames() { + var NaN = 4; + var undefined = 5; + var Infinity = 6; + return NaN + undefined + Infinity; +} +assertEq(testLocalNames(), 15); + diff --git a/js/src/jit-test/tests/jaeger/optimize-globals-2.js b/js/src/jit-test/tests/jaeger/optimize-globals-2.js new file mode 100644 index 0000000..2e01cdc --- /dev/null +++ b/js/src/jit-test/tests/jaeger/optimize-globals-2.js @@ -0,0 +1,20 @@ + +function testNaN(x) { + var x = NaN; + assertEq(isNaN(x), true); +} +testNaN(); + +function testInfinity(x) { + return (x === Infinity); +} +assertEq(testInfinity(Infinity), true); +assertEq(testInfinity(6), false); +assertEq(testInfinity(-Infinity), false); + +function testUndefined(x) { + return (x === undefined); +} +assertEq(testUndefined(undefined), true); +assertEq(testUndefined(), true); +assertEq(testUndefined(5), false); diff --git a/js/src/jit-test/tests/jaeger/optimize-globals-3.js b/js/src/jit-test/tests/jaeger/optimize-globals-3.js new file mode 100644 index 0000000..eb2474c --- /dev/null +++ b/js/src/jit-test/tests/jaeger/optimize-globals-3.js @@ -0,0 +1,9 @@ + +NaN = 4; +undefined = 5; +Infinity = 6; + +assertEq(isNaN(NaN), true); +assertEq(Infinity > 100, true); +assertEq(undefined != 5, true); + diff --git a/js/src/jit-test/tests/jaeger/regalloc-1.js b/js/src/jit-test/tests/jaeger/regalloc-1.js new file mode 100644 index 0000000..c4b854b --- /dev/null +++ b/js/src/jit-test/tests/jaeger/regalloc-1.js @@ -0,0 +1,15 @@ +// |jit-test| error: TypeError + +x = 2; + +function tryItOut(c) { + return eval("(function(){" + c + "})"); +} + +function doit() { + var f = tryItOut("((( \"\" \n for each (eval in [null, this, null, this, (1/0), new String('q'), new String('q'), null, null, null, new String('q'), new String('q'), new String('q'), null]) if (this)).eval(x = x)));"); + f(); +} + +doit(); + diff --git a/js/src/jit-test/tests/jaeger/regress-bug625701.js b/js/src/jit-test/tests/jaeger/regress-bug625701.js new file mode 100644 index 0000000..a6f24d9 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/regress-bug625701.js @@ -0,0 +1,10 @@ +gczeal(2); + +for(var i=0; i<20; i++) { + function f() { + for (var j = 0; j < 3; j++) { + (function() {})(); + } + } + f(); +} diff --git a/js/src/jit-test/tests/jaeger/rsh-sanity-1.js b/js/src/jit-test/tests/jaeger/rsh-sanity-1.js new file mode 100644 index 0000000..3127a32 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/rsh-sanity-1.js @@ -0,0 +1,17 @@ +/* Unknown types. */ +function rsh(lhs, rhs) { return lhs >> rhs; } +assertEq(rsh(1024, 2), 256) +assertEq(rsh(1024.5, 2), 256) +assertEq(rsh(1024.5, 2.0), 256) + +/* Constant rhs. */ +var lhs = 1024; +assertEq(lhs >> 2, 256); +lhs = 1024.5; +assertEq(lhs >> 2, 256); + +/* Constant lhs. */ +var rhs = 2; +assertEq(256, 1024 >> rhs); +var rhs = 2.0; +assertEq(256, 1024 >> rhs); diff --git a/js/src/jit-test/tests/jaeger/scriptedICs-1.js b/js/src/jit-test/tests/jaeger/scriptedICs-1.js new file mode 100644 index 0000000..b0fd505 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/scriptedICs-1.js @@ -0,0 +1,39 @@ +T = 12; + +function arity2(q, w, r, t, y) { + var Q1; + var Q2; + var Q3; + var Q4; + var Q5; + var Q6; + var Q7; + var Q8; + var Q9; + T; + return arguments; +} + +function arity(q, w, r) { + var Q1; + var Q2; + var Q3; + var Q4; + var Q5; + var Q6; + var Q7; + var Q8; + var Q9; + T; + return Q9; +} + +for (var i = 0; i < 10; i++) { + arity(); + if (i == 6) + arity = arity2; +} + +/* Don't assert - stubs::CompileFunction must correct |regs.sp| */ + + diff --git a/js/src/jit-test/tests/jaeger/smallIntTypedArrays.js b/js/src/jit-test/tests/jaeger/smallIntTypedArrays.js new file mode 100644 index 0000000..3ed2f2b --- /dev/null +++ b/js/src/jit-test/tests/jaeger/smallIntTypedArrays.js @@ -0,0 +1,112 @@ +// vim: set ts=4 sw=4 tw=99 et: + +function testInt8Array(L) { + var f = new Int8Array(8); + assertEq(f[0], 0); + assertEq(f[L], 0); + assertEq(f[L+8], undefined); + assertEq(f[8], undefined); + f[0] = 12; + f[L+1] = 13; + f[2] = f[1]; + f[L+3] = 500; + f[L+4] = true; + f[L+5] = L; + assertEq(f[0], 12); + assertEq(f[1], 13); + assertEq(f[2], 13); + assertEq(f[3], -12); + assertEq(f[4], 1); + assertEq(f[5], 0); +} + +function testUint8Array(L) { + var f = new Uint8Array(8); + assertEq(f[0], 0); + assertEq(f[L], 0); + assertEq(f[L+8], undefined); + assertEq(f[8], undefined); + f[0] = 12; + f[L+1] = 13; + f[2] = f[1]; + f[L+3] = 500; + f[L+4] = true; + f[L+5] = L; + assertEq(f[0], 12); + assertEq(f[1], 13); + assertEq(f[2], 13); + assertEq(f[3], 244); + assertEq(f[4], 1); + assertEq(f[5], 0); +} + +function testUint8ClampedArray(L) { + var f = new Uint8ClampedArray(8); + assertEq(f[0], 0); + assertEq(f[L], 0); + assertEq(f[L+8], undefined); + assertEq(f[8], undefined); + f[0] = 12; + f[L+1] = 13; + f[2] = f[1]; + f[L+3] = 500; + f[L+4] = true; + f[L+5] = L; + assertEq(f[0], 12); + assertEq(f[1], 13); + assertEq(f[2], 13); + assertEq(f[3], 255); + assertEq(f[4], 1); + assertEq(f[5], 0); +} + +function testInt16Array(L) { + var f = new Int16Array(8); + assertEq(f[0], 0); + assertEq(f[L], 0); + assertEq(f[L+8], undefined); + assertEq(f[8], undefined); + f[0] = 12; + f[L+1] = 13; + f[2] = f[1]; + f[L+3] = 190000; + f[L+4] = true; + f[L+5] = L; + assertEq(f[0], 12); + assertEq(f[1], 13); + assertEq(f[2], 13); + assertEq(f[3], -6608); + assertEq(f[4], 1); + assertEq(f[5], 0); +} + +function testUint16Array(L) { + var f = new Uint16Array(8); + assertEq(f[0], 0); + assertEq(f[L], 0); + assertEq(f[L+8], undefined); + assertEq(f[8], undefined); + f[0] = 12; + f[L+1] = 13; + f[2] = f[1]; + f[L+3] = 190000; + f[L+4] = true; + f[L+5] = L; + assertEq(f[0], 12); + assertEq(f[1], 13); + assertEq(f[2], 13); + assertEq(f[3], 58928); + assertEq(f[4], 1); + assertEq(f[5], 0); +} + +for (var i = 0; i < 10; i++) { + testInt8Array(0); + testUint8Array(0); + testUint8ClampedArray(0); + testInt16Array(0); + testUint16Array(0); + if (i == 5) + gc(); +} + diff --git a/js/src/jit-test/tests/jaeger/strictModeSetUndefinedVar.js b/js/src/jit-test/tests/jaeger/strictModeSetUndefinedVar.js new file mode 100644 index 0000000..99b846c --- /dev/null +++ b/js/src/jit-test/tests/jaeger/strictModeSetUndefinedVar.js @@ -0,0 +1,8 @@ +// |jit-test| error: ReferenceError; + +function f() { + "use strict"; + foo = 1; +} + +f(); diff --git a/js/src/jit-test/tests/jaeger/subCommutativity.js b/js/src/jit-test/tests/jaeger/subCommutativity.js new file mode 100644 index 0000000..89885c2 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/subCommutativity.js @@ -0,0 +1,4 @@ +assertEq(6 - ((void 0) ^ 0x80000005), 2147483649); + +var x = ((void 0) ^ 0x80000005); +assertEq(6 - x, 2147483649); diff --git a/js/src/jit-test/tests/jaeger/tableSwitchConst.js b/js/src/jit-test/tests/jaeger/tableSwitchConst.js new file mode 100644 index 0000000..6422af3 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/tableSwitchConst.js @@ -0,0 +1,18 @@ +function f() { + switch(2) { + case 1: return 1; + case 2: return 2; + default: return -1; + } +} +assertEq(f(), 2); + +function g() { + switch(3.14) { + case 3: return 3; + case 4: return 4; + default: return -1; + } +} +assertEq(g(), -1); + diff --git a/js/src/jit-test/tests/jaeger/tableSwitchDouble.js b/js/src/jit-test/tests/jaeger/tableSwitchDouble.js new file mode 100644 index 0000000..df9fe2a --- /dev/null +++ b/js/src/jit-test/tests/jaeger/tableSwitchDouble.js @@ -0,0 +1,13 @@ + +function f(a) { + switch(a) { + case 3: return 3; + case 4: return 4; + default: return -1; + } +} + +assertEq(f(-0.0), -1); +assertEq(f(3.14), -1); +assertEq(f(12.34), -1); + diff --git a/js/src/jit-test/tests/jaeger/tableSwitchEmpty.js b/js/src/jit-test/tests/jaeger/tableSwitchEmpty.js new file mode 100644 index 0000000..42a050d --- /dev/null +++ b/js/src/jit-test/tests/jaeger/tableSwitchEmpty.js @@ -0,0 +1,14 @@ + +function f(a) { + switch(a) { + } + switch(a) { + default: return 0; + } + assertEq(0, 1); +} + +assertEq(f(), 0); +assertEq(f(0), 0); +assertEq(f(1.1), 0); + diff --git a/js/src/jit-test/tests/jaeger/tableSwitchFloat.js b/js/src/jit-test/tests/jaeger/tableSwitchFloat.js new file mode 100644 index 0000000..6422af3 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/tableSwitchFloat.js @@ -0,0 +1,18 @@ +function f() { + switch(2) { + case 1: return 1; + case 2: return 2; + default: return -1; + } +} +assertEq(f(), 2); + +function g() { + switch(3.14) { + case 3: return 3; + case 4: return 4; + default: return -1; + } +} +assertEq(g(), -1); + diff --git a/js/src/jit-test/tests/jaeger/tableSwitchNeg.js b/js/src/jit-test/tests/jaeger/tableSwitchNeg.js new file mode 100644 index 0000000..ae37026 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/tableSwitchNeg.js @@ -0,0 +1,27 @@ + +function f(a) { + switch(a) { + case -1: return 1; + case -2: return 2; + case -5: return 5; + default: return 10; + } +} + +assertEq(f(-1), 1); +assertEq(f(-2), 2); +assertEq(f(-5), 5); + +assertEq(f(-3), 10); +assertEq(f(-6), 10); +assertEq(f(0), 10); +assertEq(f(1), 10); + +assertEq(f(-2147483647), 10); +assertEq(f(-2147483648), 10); +assertEq(f(-2147483649), 10); + +assertEq(f(2147483647), 10); +assertEq(f(2147483648), 10); +assertEq(f(2147483649), 10); + diff --git a/js/src/jit-test/tests/jaeger/testAddStringObject.js b/js/src/jit-test/tests/jaeger/testAddStringObject.js new file mode 100644 index 0000000..0ed0288 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/testAddStringObject.js @@ -0,0 +1,17 @@ +String.prototype.m = function(s) { + return this.indexOf('a'); +}; + +var g = function(s) { + return (s + 'asdf').m(); +}; + +var h = function(s) { + return ('asdf' + s).m(); +}; + +var ix = g(new String('abc')); +assertEq(ix, 0); + +var ix = h(new String('abc')); +assertEq(ix, 0); diff --git a/js/src/jit-test/tests/jaeger/testBug550743.js b/js/src/jit-test/tests/jaeger/testBug550743.js new file mode 100644 index 0000000..50349d6 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/testBug550743.js @@ -0,0 +1,21 @@ +expected = ''; + +function g(code) { + f = Function(code); + gen = f(); + gen.next(); + try { gen.next(); } catch (ex) { expected = ex.toString() } +} + +g("\ + yield this.__defineGetter__('x', function(){ return z }); \ + let z = new String('hi'); \ + "); + +eval(); +gc(); + +str = x; + +assertEq(expected, "[object StopIteration]"); +assertEq(str.toString(), "hi"); diff --git a/js/src/jit-test/tests/jaeger/testCallElemAfterGC.js b/js/src/jit-test/tests/jaeger/testCallElemAfterGC.js new file mode 100644 index 0000000..f9e7825 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/testCallElemAfterGC.js @@ -0,0 +1,20 @@ +// vim: ts=4 sw=4 tw=99 et: + +function A() { + this.x = 12; + this.y = function () { return this.x; }; + this[1] = function () { return this.x; }; +} + +function f(obj, key){ + assertEq(obj[key](), 12); +} + +a = new A(); +f(a, "y"); +f(a, "y"); +f(a, 1); +gc(); +f(a, "y"); +f(a, "y"); + diff --git a/js/src/jit-test/tests/jaeger/testDenseCallElem.js b/js/src/jit-test/tests/jaeger/testDenseCallElem.js new file mode 100644 index 0000000..eadb77f --- /dev/null +++ b/js/src/jit-test/tests/jaeger/testDenseCallElem.js @@ -0,0 +1,89 @@ +// vim: set ts=4 sw=4 tw=99 et: + +function fillDense(a) { +} + +function testDenseUKeyUArray(a, key) { + a.push(function () { return this[3]; }); + a.push(function () { return this[4]; }); + a.push(function() { return this[5]; }); + a.push(20); + a.push("hi"); + a.push(500); + assertEq(a[key](), 20); + assertEq(a[key + 1](), "hi"); + assertEq(a[key + 2](), 500); +} + +function testDenseVKeyUArray(a) { + a.push(function () { return this[3]; }); + a.push(function () { return this[4]; }); + a.push(function() { return this[5]; }); + a.push(20); + a.push("hi"); + a.push(500); + var key = a.length & 1; + assertEq(a[key](), 20); + assertEq(a[(key + 1) & 3](), "hi"); + assertEq(a[(key + 2) & 3](), 500); +} + +function testDenseKKeyUArray(a, key) { + a.push(function () { return this[3]; }); + a.push(function () { return this[4]; }); + a.push(function() { return this[5]; }); + a.push(20); + a.push("hi"); + a.push(500); + assertEq(a[0](), 20); + assertEq(a[1](), "hi"); + assertEq(a[2](), 500); +} + +function testDenseUKeyVArray(key) { + var a = [function () { return this[3]; }, + function () { return this[4]; }, + function() { return this[5]; }, + 20, + "hi", + 500]; + assertEq(a[key](), 20); + assertEq(a[key + 1](), "hi"); + assertEq(a[key + 2](), 500); +} + +function testDenseVKeyVArray() { + var a = [function () { return this[3]; }, + function () { return this[4]; }, + function() { return this[5]; }, + 20, + "hi", + 500]; + var key = a.length & 1; + assertEq(a[key](), 20); + assertEq(a[(key + 1) & 3](), "hi"); + assertEq(a[(key + 2) & 3](), 500); +} + +function testDenseKKeyVArray() { + var a = [function () { return this[3]; }, + function () { return this[4]; }, + function() { return this[5]; }, + 20, + "hi", + 500]; + assertEq(a[0](), 20); + assertEq(a[1](), "hi"); + assertEq(a[2](), 500); +} + +for (var i = 0; i < 5; i++) { + testDenseUKeyUArray([], 0); + testDenseVKeyUArray([]); + testDenseKKeyUArray([]); + testDenseUKeyVArray(0); + testDenseVKeyVArray(); + testDenseKKeyVArray(); +} + + diff --git a/js/src/jit-test/tests/jaeger/testForOps.js b/js/src/jit-test/tests/jaeger/testForOps.js new file mode 100644 index 0000000..cb7d583 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/testForOps.js @@ -0,0 +1,73 @@ +// |jit-test| mjitalways +// vim: set ts=4 sw=4 tw=99 et: + +function assertObjectsEqual(obj1, obj2) { + assertEq(obj1.a, obj2.a); + assertEq(obj1.b, obj2.b); + assertEq(obj1.c, obj2.c); + assertEq(obj1.d, obj2.d); + assertEq(obj2.a, 1); + assertEq(obj2.b, "bee"); + assertEq(obj2.c, "crab"); + assertEq(obj2.d, 12); +} + +function forName(obj) { + assertJit(); + eval(''); + var r = { }; + for (x in obj) + r[x] = obj[x]; + return r; +} + +function forGlobalName(obj) { + assertJit(); + var r = { }; + for (x in obj) + r[x] = obj[x]; + return r; +} + +function forProp(obj) { + assertJit(); + var r = { }; + var c = { }; + for (c.x in obj) + r[c.x] = obj[c.x]; + return r; +} + +function forElem(obj, x) { + assertJit(); + var r = { }; + var c = { }; + for (c[x] in obj) + r[c[x]] = obj[c[x]]; + return r; +} + +function forLocal(obj) { + assertJit(); + var r = { }; + for (var x in obj) + r[x] = obj[x]; + return r; +} + +function forArg(obj, x) { + assertJit(); + var r = { }; + for (x in obj) + r[x] = obj[x]; + return r; +} + +var obj = { a: 1, b: "bee", c: "crab", d: 12 }; +assertObjectsEqual(obj, forName(obj)); +assertObjectsEqual(obj, forGlobalName(obj)); +assertObjectsEqual(obj, forProp(obj)); +assertObjectsEqual(obj, forElem(obj, "v")); +assertObjectsEqual(obj, forLocal(obj)); +assertObjectsEqual(obj, forArg(obj)); + diff --git a/js/src/jit-test/tests/jaeger/testPropCallElem.js b/js/src/jit-test/tests/jaeger/testPropCallElem.js new file mode 100644 index 0000000..fd067bb --- /dev/null +++ b/js/src/jit-test/tests/jaeger/testPropCallElem.js @@ -0,0 +1,93 @@ +// vim: set ts=4 sw=4 tw=99 et: + +function testUKeyUObject(a, key1, key2, key3) { + a.a = function () { return this.d; } + a.b = function () { return this.e; } + a.c = function() { return this.f; } + a.d = 20; + a.e = "hi"; + a.f = 500; + assertEq(a[key1](), 20); + assertEq(a[key2](), "hi"); + assertEq(a[key3](), 500); +} + +function testVKeyUObject(a, key1, key2, key3) { + a.a = function () { return this.d; } + a.b = function () { return this.e; } + a.c = function() { return this.f; } + a.d = 20; + a.e = "hi"; + a.f = 500; + assertEq(a["" + key1](), 20); + assertEq(a["" + key2](), "hi"); + assertEq(a["" + key3](), 500); +} + +function testKKeyUObject(a) { + a.a = function () { return this.d; } + a.b = function () { return this.e; } + a.c = function() { return this.f; } + a.d = 20; + a.e = "hi"; + a.f = 500; + var key1 = "a"; + var key2 = "b"; + var key3 = "c"; + assertEq(a[key1](), 20); + assertEq(a[key2](), "hi"); + assertEq(a[key3](), 500); +} + +function testUKeyVObject(key1, key2, key3) { + a = { a: function () { return this.d; }, + b: function () { return this.e; }, + c: function () { return this.f; }, + d: 20, + e: "hi", + f: 500 + }; + assertEq(a[key1](), 20); + assertEq(a[key2](), "hi"); + assertEq(a[key3](), 500); +} + +function testVKeyVObject(key1, key2, key3) { + a = { a: function () { return this.d; }, + b: function () { return this.e; }, + c: function () { return this.f; }, + d: 20, + e: "hi", + f: 500 + }; + assertEq(a["" + key1](), 20); + assertEq(a["" + key2](), "hi"); + assertEq(a["" + key3](), 500); +} + +function testKKeyVObject(a) { + a = { a: function () { return this.d; }, + b: function () { return this.e; }, + c: function () { return this.f; }, + d: 20, + e: "hi", + f: 500 + }; + var key1 = "a"; + var key2 = "b"; + var key3 = "c"; + assertEq(a[key1](), 20); + assertEq(a[key2](), "hi"); + assertEq(a[key3](), 500); +} + +for (var i = 0; i < 5; i++) { + testUKeyUObject({}, "a", "b", "c"); + testVKeyUObject({}, "a", "b", "c"); + testKKeyUObject({}); + testUKeyVObject("a", "b", "c"); + testVKeyVObject("a", "b", "c"); + testKKeyVObject(); +} + + diff --git a/js/src/jit-test/tests/jaeger/testPropCallElem2.js b/js/src/jit-test/tests/jaeger/testPropCallElem2.js new file mode 100644 index 0000000..328193a --- /dev/null +++ b/js/src/jit-test/tests/jaeger/testPropCallElem2.js @@ -0,0 +1,20 @@ +// vim: set ts=4 sw=4 tw=99 et: + +function testUKeyUObject(a, key1, key2, key3) { + a.a = function () { return this.d; } + a.b = function () { return this.e; } + a.c = function() { return this.f; } + a.d = 20; + a.e = "hi"; + a.f = 500; + delete a["b"]; + Object.defineProperty(a, "b", { get: function () { return function () { return this.e; } } }); + assertEq(a[key1](), 20); + assertEq(a[key2](), "hi"); + assertEq(a[key3](), 500); +} + +for (var i = 0; i < 5; i++) + testUKeyUObject({}, "a", "b", "c"); + + diff --git a/js/src/jit-test/tests/jaeger/testSetElem-Easy.js b/js/src/jit-test/tests/jaeger/testSetElem-Easy.js new file mode 100644 index 0000000..9eb9d06 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/testSetElem-Easy.js @@ -0,0 +1,41 @@ +// vim: set ts=4 sw=4 tw=99 et: + +function testBadSetElems(obj, key) { + obj[key] = 5; + obj[-1] = 5; + var L = obj; + L[L] = L; + obj = []; + obj.K = 5; + obj[2] = 5; + var T = "a"; + obj[T] = 12; + obj = []; + obj[Object] = key; +} + +function testDenseSets(L) { + var obj = [,,,,,,,,,,]; + obj[2] = 2; + assertEq(obj[2], 2); + var T = L; + assertEq(obj[T], 2); + assertEq(obj.length, 10); + obj[10] = T; + assertEq(obj[10], T); + assertEq(obj.length, 11); + var K = T + 9; + obj[K] = K; + assertEq(obj[K], K); + assertEq(obj.length, 12); + obj[K + 1] = obj; + assertEq(obj[K + 1], obj); + assertEq(obj.length, 13); +} + +for (var i = 0; i < 10; i++) { + testBadSetElems([], -1); + testDenseSets(2); +} + + diff --git a/js/src/jit-test/tests/jaeger/testSetElem-Indexed.js b/js/src/jit-test/tests/jaeger/testSetElem-Indexed.js new file mode 100644 index 0000000..146092f --- /dev/null +++ b/js/src/jit-test/tests/jaeger/testSetElem-Indexed.js @@ -0,0 +1,36 @@ +// vim: set ts=4 sw=4 tw=99 et: + +function f() { + return [[], [], [], []]; +} + +function setelem(obj, key, val) { + obj[key] = val; +} + +// Generate IC +setelem([], 0, "hi"); +setelem([], 0, "hi"); + +// Get some arrays pre-indexing. +var arrays = f(); + +// Do bad stuff. +Object.defineProperty(Object.prototype, "1", { set: function (v) { this.kettle = v; } }); + +var k = arrays[0]; +setelem(k, 1, 13); +assertEq(k.kettle, 13); +assertEq(k.hasOwnProperty("1"), false); + +Object.defineProperty(Array.prototype, "2", { set: function (v) { this.pot = v; } }); +k = arrays[1]; +setelem(k, 2, "yam"); +assertEq(k.pot, "yam"); + +gc(); + +// make sure this reset okay. +setelem([], 0, "hi"); +setelem([], 0, "hi"); + diff --git a/js/src/jit-test/tests/jaeger/testSetElem-NewProto.js b/js/src/jit-test/tests/jaeger/testSetElem-NewProto.js new file mode 100644 index 0000000..91d7140 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/testSetElem-NewProto.js @@ -0,0 +1,24 @@ +// vim: set ts=4 sw=4 tw=99 et: + +function f() { + return [[], [], [], []]; +} + +function setelem(obj, key, val) { + obj[key] = val; +} + +// Generate IC +setelem([], 0, "hi"); +setelem([], 0, "hi"); + +var arrays = f(); + +var evil = { }; +Object.defineProperty(evil, "1", { set: function (v) { this.ham = v; } }); +Array.prototype.__proto__ = evil; + +var k = arrays[0]; +setelem(k, 1, "yam"); +assertEq(k.ham, "yam"); + diff --git a/js/src/jit-test/tests/jaeger/testSetTypedFloatArray.js b/js/src/jit-test/tests/jaeger/testSetTypedFloatArray.js new file mode 100644 index 0000000..49ea74a --- /dev/null +++ b/js/src/jit-test/tests/jaeger/testSetTypedFloatArray.js @@ -0,0 +1,61 @@ +// vim: set ts=4 sw=4 tw=99 et: + +function testSetTypedFloat32Array(k) { + var ar = new Float32Array(8); + ar[k+5] = { }; + ar[k+6] = ar; + ar[k+4] = (k + 800) * 897 * 800 * 800 * 810 * 1923437; + var t = k + 555; + var L = ar[k+7] = t & 5; + ar[0] = 12.3; + ar[8] = 500; + ar[k+8] = 1200; + ar[k+1] = 500; + ar[k+2] = "3" + k; + ar[k+3] = true; + assertEq(ar[0] - 12.3 >= 0 && + ar[0] - 12.3 <= 0.0001, true); + assertEq(ar[1], 500); + assertEq(ar[2], 30); + assertEq(ar[3], 1); + assertEq(ar[4], 715525927453369300000); + assertEq(ar[5], NaN); + assertEq(ar[6], NaN); + assertEq(ar[7], 1); + assertEq(ar[8], undefined); + assertEq(ar[k+8], undefined); +} + +function testSetTypedFloat64Array(k) { + var ar = new Float64Array(8); + ar[k+5] = { }; + ar[k+6] = ar; + ar[k+4] = (k + 800) * 897 * 800 * 800 * 810 * 1923437; + var t = k + 555; + var L = ar[k+7] = t & 5; + ar[0] = 12.3; + ar[8] = 500; + ar[k+8] = 1200; + ar[k+1] = 500; + ar[k+2] = "3" + k; + ar[k+3] = true; + assertEq(ar[0] - 12.3 >= 0 && + ar[0] - 12.3 <= 0.0001, true); + assertEq(ar[1], 500); + assertEq(ar[2], 30); + assertEq(ar[3], 1); + assertEq(ar[4], 715525949998080000000); + assertEq(ar[5], NaN); + assertEq(ar[6], NaN); + assertEq(ar[7], 1); + assertEq(ar[8], undefined); + assertEq(ar[k+8], undefined); +} + +for (var i = 0; i <= 10; i++) { + testSetTypedFloat32Array(0); + testSetTypedFloat64Array(0); + if (i == 5) + gc(); +} + diff --git a/js/src/jit-test/tests/jaeger/testSetTypedIntArray.js b/js/src/jit-test/tests/jaeger/testSetTypedIntArray.js new file mode 100644 index 0000000..bf3099c --- /dev/null +++ b/js/src/jit-test/tests/jaeger/testSetTypedIntArray.js @@ -0,0 +1,190 @@ +// vim: set ts=4 sw=4 tw=99 et: + +function testSetTypedInt8Array(k) { + var ar = new Int8Array(8); + ar[k+5] = { }; + ar[k+6] = ar; + ar[k+4] = k + 800; + var t = k + 555; + var t = ar[k+7] = t & 5; + ar[0] = 12; + ar[8] = 500; + ar[k+8] = 1200; + ar[k+1] = 500; + ar[k+2] = "3"; + ar[k+3] = true; + assertEq(ar[0], 12); + assertEq(ar[1], -12); + assertEq(ar[2], 3); + assertEq(ar[3], 1); + assertEq(ar[4], 32); + assertEq(ar[5], 0); + assertEq(ar[6], 0); + assertEq(ar[7], 1); + assertEq(ar[8], undefined); + assertEq(ar[k+8], undefined); +} + +function testSetTypedUint8ClampedArray(k) { + var ar = new Uint8ClampedArray(8); + ar[k+5] = { }; + ar[k+6] = ar; + ar[k+4] = k + 800; + var t = k + 555; + var L = ar[k+7] = t & 5; + var Q = ar[k+7] = t + 5; + ar[0] = 12; + ar[8] = 500; + ar[k+8] = 1200; + ar[k+1] = -500; + ar[k+2] = "3"; + ar[k+3] = true; + assertEq(ar[0], 12); + assertEq(ar[1], 0); + assertEq(ar[2], 3); + assertEq(ar[3], 1); + assertEq(ar[4], 255); + assertEq(ar[5], 0); + assertEq(ar[6], 0); + assertEq(ar[7], 255); + assertEq(ar[8], undefined); + assertEq(ar[k+8], undefined); +} + +function testSetTypedUint8Array(k) { + var ar = new Uint8Array(8); + ar[k+5] = { }; + ar[k+6] = ar; + ar[k+4] = k + 800; + var t = k + 555; + var L = ar[k+7] = t + 5; + ar[0] = 12.3; + ar[8] = 500; + ar[k+8] = 1200; + ar[k+1] = 500; + ar[k+2] = "3"; + ar[k+3] = true; + assertEq(ar[0], 12); + assertEq(ar[1], 244); + assertEq(ar[2], 3); + assertEq(ar[3], 1); + assertEq(ar[4], 32); + assertEq(ar[5], 0); + assertEq(ar[6], 0); + assertEq(ar[7], 48); + assertEq(ar[8], undefined); + assertEq(ar[k+8], undefined); +} + +function testSetTypedInt16Array(k) { + var ar = new Int16Array(8); + ar[k+5] = { }; + ar[k+6] = ar; + ar[k+4] = (k + 800) * 800 * 800 * 913; + var t = k + 555; + var L = ar[k+7] = t + 5; + ar[0] = 12.3; + ar[8] = 500; + ar[k+8] = 1200; + ar[k+1] = 500000; + ar[k+2] = "3"; + ar[k+3] = true; + assertEq(ar[0], 12); + assertEq(ar[1], -24288); + assertEq(ar[2], 3); + assertEq(ar[3], 1); + assertEq(ar[4], -32768); + assertEq(ar[5], 0); + assertEq(ar[6], 0); + assertEq(ar[7], 560); + assertEq(ar[8], undefined); + assertEq(ar[k+8], undefined); +} + +function testSetTypedUint16Array(k) { + var ar = new Uint16Array(8); + ar[k+5] = { }; + ar[k+6] = ar; + ar[k+4] = (k + 800) * 800 * 800 * 913; + var t = k + 555; + var L = ar[k+7] = t + 5; + ar[0] = 12.3; + ar[8] = 500; + ar[k+8] = 1200; + ar[k+1] = 500000; + ar[k+2] = "3"; + ar[k+3] = true; + assertEq(ar[0], 12); + assertEq(ar[1], 41248); + assertEq(ar[2], 3); + assertEq(ar[3], 1); + assertEq(ar[4], 32768); + assertEq(ar[5], 0); + assertEq(ar[6], 0); + assertEq(ar[7], 560); + assertEq(ar[8], undefined); + assertEq(ar[k+8], undefined); +} + +function testSetTypedInt32Array(k) { + var ar = new Int32Array(8); + ar[k+5] = { }; + ar[k+6] = ar; + ar[k+4] = (k + 800) * 800 * 800 * 800 * 800; + var t = k + 555; + var L = ar[k+7] = t + 5; + ar[0] = 12.3; + ar[8] = 500; + ar[k+8] = 1200; + ar[k+1] = 500; + ar[k+2] = "3"; + ar[k+3] = true; + assertEq(ar[0], 12); + assertEq(ar[1], 500); + assertEq(ar[2], 3); + assertEq(ar[3], 1); + assertEq(ar[4], -234881024); + assertEq(ar[5], 0); + assertEq(ar[6], 0); + assertEq(ar[7], 560); + assertEq(ar[8], undefined); + assertEq(ar[k+8], undefined); +} + +function testSetTypedUint32Array(k) { + var ar = new Uint32Array(8); + ar[k+5] = { }; + ar[k+6] = ar; + ar[k+4] = (k + 800) * 800 * 800 * 800 * 800; + var t = k + 555; + var L = ar[k+7] = t + 5; + ar[0] = 12.3; + ar[8] = 500; + ar[k+8] = 1200; + ar[k+1] = 500; + ar[k+2] = "3"; + ar[k+3] = true; + assertEq(ar[0], 12); + assertEq(ar[1], 500); + assertEq(ar[2], 3); + assertEq(ar[3], 1); + assertEq(ar[4], 4060086272); + assertEq(ar[5], 0); + assertEq(ar[6], 0); + assertEq(ar[7], 560); + assertEq(ar[8], undefined); + assertEq(ar[k+8], undefined); +} + +for (var i = 0; i <= 10; i++) { + testSetTypedInt8Array(0); + testSetTypedUint8Array(0); + testSetTypedUint8ClampedArray(0); + testSetTypedInt16Array(0); + testSetTypedUint16Array(0); + testSetTypedInt32Array(0); + testSetTypedUint32Array(0); + if (i == 5) + gc(); +} + diff --git a/js/src/jit-test/tests/jaeger/testShiftSameBacking.js b/js/src/jit-test/tests/jaeger/testShiftSameBacking.js new file mode 100644 index 0000000..cb2ce00 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/testShiftSameBacking.js @@ -0,0 +1,12 @@ +// vim: set ts=4 sw=4 tw=99 et: + +function f(a) { + var x = a; + var y = x; + + assertEq((x << y), (a << a)); + assertEq((y << x), (a << a)); +} + +f(2); + diff --git a/js/src/jit-test/tests/jaeger/unsignedShiftZero.js b/js/src/jit-test/tests/jaeger/unsignedShiftZero.js new file mode 100644 index 0000000..e199677 --- /dev/null +++ b/js/src/jit-test/tests/jaeger/unsignedShiftZero.js @@ -0,0 +1,8 @@ + +function f(a) { + return a >>> 0; +}; + +assertEq(f(-2147483647), 2147483649); +assertEq(f(-2147483648), 2147483648); +assertEq(f(-2147483649), 2147483647); diff --git a/js/src/jit-test/tests/jaeger/xor-sanity.js b/js/src/jit-test/tests/jaeger/xor-sanity.js new file mode 100644 index 0000000..4f41e0f --- /dev/null +++ b/js/src/jit-test/tests/jaeger/xor-sanity.js @@ -0,0 +1 @@ +assertEq(-2^31, -31); diff --git a/js/src/jit-test/tests/pic/bug558099.js b/js/src/jit-test/tests/pic/bug558099.js new file mode 100644 index 0000000..5d8c68f --- /dev/null +++ b/js/src/jit-test/tests/pic/bug558099.js @@ -0,0 +1,60 @@ +(function()[function() function() function() function() function() function() {}]); +foo = [{ + text: "(function(){if(d){(1)}})", + s: function() {}, + test: function() { + try { + f + } catch(e) {} + } +}, +{ + text: "(function(){t})", + s: function() {}, + test: function() {} +}, +{ + text: "(function(){if(0){}})", + s: function() {}, + test: function() {} +}, +{ + text: "(function(){if(1){}(2)})", + s: function() {}, + test: function() {} +}, +{ + text: "(function(){g})", + b: function() {}, + test: function() {} +}, +{ + text: "(function(){})", + s: function() {}, + test: function() {} +}, +{ + text: "(function(){1})", + s: function() {}, + test: function() {} +}]; (function() { + for (i = 0; i < foo.length; ++i) { + a = foo[i] + text = a.text + eval(text.replace(/@/, "")); + if (a.test()) {} + } +} ()); +s = [function() function() function() function() function() function() {}] +[function() function() function() function() {}]; +(function() { [function() function() {}] }); +(function() {}); +(eval("\ + (function(){\ + for each(d in[\ + 0,0,0,0,0,0,0,0,0,0,0,0,0,null,NaN,1,Boolean(false),Boolean(false)\ + ]){\ + [].filter(new Function,gczeal(2))\ + }\ + })\ +"))(); diff --git a/js/src/jit-test/tests/pic/bug558616.js b/js/src/jit-test/tests/pic/bug558616.js new file mode 100644 index 0000000..c86f012 --- /dev/null +++ b/js/src/jit-test/tests/pic/bug558616.js @@ -0,0 +1,9 @@ +(function() { + for each(let d in [{}, {}, 0]) { + for each(e in [0, 0, 0, 0, 0, 0, 0, 0, 0]) { + d.__defineSetter__("", function() {}) + } + } +})() + +// don't assert diff --git a/js/src/jit-test/tests/pic/bug582899.js b/js/src/jit-test/tests/pic/bug582899.js new file mode 100644 index 0000000..1db4be3 --- /dev/null +++ b/js/src/jit-test/tests/pic/bug582899.js @@ -0,0 +1,8 @@ +try { + (function () { + __proto__ = []; + for each(y in [0, 0]) { + this.__defineGetter__("", function () {}) + } + })() +} catch (e) {} diff --git a/js/src/jit-test/tests/pic/bug584642.js b/js/src/jit-test/tests/pic/bug584642.js new file mode 100644 index 0000000..ebf4d78 --- /dev/null +++ b/js/src/jit-test/tests/pic/bug584642.js @@ -0,0 +1,3 @@ +// |jit-test| error: ReferenceError +Function("x=[(x)=s]")(); +/* Don't assert. */ diff --git a/js/src/jit-test/tests/pic/bug595706.js b/js/src/jit-test/tests/pic/bug595706.js new file mode 100644 index 0000000..63c031a --- /dev/null +++ b/js/src/jit-test/tests/pic/bug595706.js @@ -0,0 +1,19 @@ +function f(useArg2, arg2, expect) { + var args = arguments; + if (useArg2) + args = arg2; + + print(args) + assertEq(args.length, expect); +} + +// Generate a PIC for arguments. +f(false, 0, 3); +f(false, 0, 3); +f(false, 0, 3); + +// Now call it with a slow array. +var a = [1, 2, 3]; +a.x = 9; + +f(true, a, 3); diff --git a/js/src/jit-test/tests/pic/call_self.js b/js/src/jit-test/tests/pic/call_self.js new file mode 100644 index 0000000..0709b23 --- /dev/null +++ b/js/src/jit-test/tests/pic/call_self.js @@ -0,0 +1,15 @@ +var o = { + g: function(a) { + return a; + } +}; + +function f() { + var z; + for (var i = 0; i < 10; ++i) { + z = o.g(i); + assertEq(z, i); + } +} + +f(); diff --git a/js/src/jit-test/tests/pic/densearray.js b/js/src/jit-test/tests/pic/densearray.js new file mode 100644 index 0000000..1d0e8fa --- /dev/null +++ b/js/src/jit-test/tests/pic/densearray.js @@ -0,0 +1,12 @@ +function f() { + var o = [ 1, 2, 3, 4, 5 ]; + + for (var i = 6; i < 10; ++i) + o.push(i); + + return o; +} + +var o = f(); + +assertEq(o.join(','), [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ].join(',')); \ No newline at end of file diff --git a/js/src/jit-test/tests/pic/fuzz1.js b/js/src/jit-test/tests/pic/fuzz1.js new file mode 100644 index 0000000..2481a13 --- /dev/null +++ b/js/src/jit-test/tests/pic/fuzz1.js @@ -0,0 +1,4 @@ +(function() { + for (a = 0; a < 2; a++) + ''.watch("", function() {}) +})() diff --git a/js/src/jit-test/tests/pic/fuzz2.js b/js/src/jit-test/tests/pic/fuzz2.js new file mode 100644 index 0000000..45145c7 --- /dev/null +++ b/js/src/jit-test/tests/pic/fuzz2.js @@ -0,0 +1,3 @@ +for each(let x in [0, {}, 0, {}]) { + x.valueOf +} \ No newline at end of file diff --git a/js/src/jit-test/tests/pic/fuzz3.js b/js/src/jit-test/tests/pic/fuzz3.js new file mode 100644 index 0000000..17613b6 --- /dev/null +++ b/js/src/jit-test/tests/pic/fuzz3.js @@ -0,0 +1,3 @@ +for each(let w in [[], 0, [], 0]) { + w.unwatch() +} diff --git a/js/src/jit-test/tests/pic/grandproto.js b/js/src/jit-test/tests/pic/grandproto.js new file mode 100644 index 0000000..0dd65fc --- /dev/null +++ b/js/src/jit-test/tests/pic/grandproto.js @@ -0,0 +1,28 @@ +function A() +{ + this.a = 77; + this.b = 88; +} + +function B() +{ +} + +B.prototype = new A; + +function C() +{ +} + +C.prototype = new B; + +function f() { + var o = new C; + var z; + for (var i = 0; i < 5; ++i) { + z = o.a; + assertEq(z, 77); + } +} + +f(); \ No newline at end of file diff --git a/js/src/jit-test/tests/pic/length_array.js b/js/src/jit-test/tests/pic/length_array.js new file mode 100644 index 0000000..ab77749 --- /dev/null +++ b/js/src/jit-test/tests/pic/length_array.js @@ -0,0 +1,16 @@ +// length, string + +var expected = "3,6,4,3,6,4,3,6,4,3,6,4,"; +var actual = ''; + +function f() { + var ss = [ [1, 2, 3], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4] ]; + + for (var i = 0; i < 12; ++i) { + actual += ss[i%3].length + ','; + } +} + +f(); + +assertEq(actual, expected); diff --git a/js/src/jit-test/tests/pic/length_mix.js b/js/src/jit-test/tests/pic/length_mix.js new file mode 100644 index 0000000..094762f --- /dev/null +++ b/js/src/jit-test/tests/pic/length_mix.js @@ -0,0 +1,22 @@ +// length, various types + +var expected = "4,5,44,5,44,4,44,4,5,4,5,44,5,44,4,44,4,5,"; +var actual = ''; + +function f() { + var a = [ "abcd", [1, 2, 3, 4, 5], { length: 44 } ]; + + for (var i = 0; i < 6; ++i) { + // Use 3 PICs so we start out with each type in one PIC. + var i1 = i % 3; + var i2 = (i+1) % 3; + var i3 = (i+2) % 3; + actual += a[i1].length + ','; + actual += a[i2].length + ','; + actual += a[i3].length + ','; + } +} + +f(); + +assertEq(actual, expected); diff --git a/js/src/jit-test/tests/pic/length_object.js b/js/src/jit-test/tests/pic/length_object.js new file mode 100644 index 0000000..5f01d57 --- /dev/null +++ b/js/src/jit-test/tests/pic/length_object.js @@ -0,0 +1,16 @@ +// length, object + +var expected = "777,777,777,777,777,"; +var actual = ''; + +function f() { + var o = { a: 11, length: 777, b: 22 }; + + for (var i = 0; i < 5; ++i) { + actual += o.length + ','; + } +} + +f(); + +assertEq(actual, expected); diff --git a/js/src/jit-test/tests/pic/length_string.js b/js/src/jit-test/tests/pic/length_string.js new file mode 100644 index 0000000..abdf62c --- /dev/null +++ b/js/src/jit-test/tests/pic/length_string.js @@ -0,0 +1,16 @@ +// length, string + +var expected = "3,6,4,3,6,4,3,6,4,3,6,4,"; +var actual = ''; + +function f() { + var ss = [ "abc", "foobar", "quux" ]; + + for (var i = 0; i < 12; ++i) { + actual += ss[i%3].length + ','; + } +} + +f(); + +assertEq(actual, expected); diff --git a/js/src/jit-test/tests/pic/length_string_object.js b/js/src/jit-test/tests/pic/length_string_object.js new file mode 100644 index 0000000..534c6b4 --- /dev/null +++ b/js/src/jit-test/tests/pic/length_string_object.js @@ -0,0 +1,36 @@ +//length, string, object + +var expected = "3,6,4,3,6,4,3,6,4,3,6,4,"; +var actual = ''; + +function f() { + var ss = [new String("abc"), new String("foobar"), new String("quux")]; + + for (var i = 0; i < 12; ++i) { + actual += ss[i%3].length + ','; + } +} + +f(); + +assertEq(actual, expected); + + +function g(s) { + return new String(s).length; +} + +assertEq(g("x"), 1); // Warm-up +assertEq(g("x"), 1); // Create IC +assertEq(g("x"), 1); // Test IC + +function h(s) { + var x = new String(s); + for (var i = 0; i < 100; i++) + x[i] = i; + return x.length; +} + +assertEq(h("x"), 1); +assertEq(h("x"), 1); +assertEq(h("x"), 1); diff --git a/js/src/jit-test/tests/pic/proto1.js b/js/src/jit-test/tests/pic/proto1.js new file mode 100644 index 0000000..4c98dd7 --- /dev/null +++ b/js/src/jit-test/tests/pic/proto1.js @@ -0,0 +1,24 @@ +// getprop, proto, 1 shape + +var expected = "11,22,33,11,22,33,11,22,33,11,22,33,11,22,33,"; +var actual = ''; + +var proto = { a: 11, b: 22, c: 33 }; + +function B() { +} +B.prototype = proto; + +function f() { + var o = new B(); + + for (var i = 0; i < 5; ++i) { + actual += o.a + ','; + actual += o.b + ','; + actual += o.c + ','; + } +} + +f(); + +assertEq(actual, expected); diff --git a/js/src/jit-test/tests/pic/proto3.js b/js/src/jit-test/tests/pic/proto3.js new file mode 100644 index 0000000..48800eb --- /dev/null +++ b/js/src/jit-test/tests/pic/proto3.js @@ -0,0 +1,32 @@ +// getprop, proto, 3 shapes + +var expected = "22,202,202,22,202,202,22,202,202,"; +var actual = ''; + +var protoB = { a: 11, b: 22, c: 33 }; + +function B() { +} +B.prototype = protoB; + +var protoC = { a: 101, b: 202, c: 303 }; + +function C() { +} +C.prototype = protoC; + +function f() { + var o1 = new B(); + var o2 = new C(); + var o3 = new C(); + o3.q = 99; + var oa = [ o1, o2, o3 ]; + + for (var i = 0; i < 9; ++i) { + actual += oa[i%3].b + ','; + } +} + +f(); + +assertEq(actual, expected); diff --git a/js/src/jit-test/tests/pic/proto_self.js b/js/src/jit-test/tests/pic/proto_self.js new file mode 100644 index 0000000..faa3e4a --- /dev/null +++ b/js/src/jit-test/tests/pic/proto_self.js @@ -0,0 +1,39 @@ +// getprop, proto and self, 3 shapes + +var expected = "22,202,99;202,99,22;99,22,202;22,202,99;202,99,22;99,22,202;22,202,99;202,99,22;99,22,202;"; +var actual = ''; + +var protoB = { a: 11, b: 22, c: 33 }; + +function B() { +} +B.prototype = protoB; + +var protoC = { a: 101, b: 202, c: 303 }; + +function C() { +} +C.prototype = protoC; + +function f() { + var o1 = new B(); + var o2 = new C(); + var o3 = new C(); + o3.b = 99; + var oa = [ o1, o2, o3 ]; + + for (var i = 0; i < 9; ++i) { + // Use 3 PICs so we start out with each type in one PIC. + var i1 = i % 3; + var i2 = (i+1) % 3; + var i3 = (i+2) % 3; + + actual += oa[i1].b + ','; + actual += oa[i2].b + ','; + actual += oa[i3].b + ';'; + } +} + +f(); + +assertEq(actual, expected); diff --git a/js/src/jit-test/tests/pic/self1.js b/js/src/jit-test/tests/pic/self1.js new file mode 100644 index 0000000..3a8d45e --- /dev/null +++ b/js/src/jit-test/tests/pic/self1.js @@ -0,0 +1,18 @@ +// getprop, self, 1 shape + +var expected = "11,22,33,11,22,33,11,22,33,11,22,33,11,22,33,"; +var actual = ''; + +function f() { + var o = { a: 11, b: 22, c: 33 }; + + for (var i = 0; i < 5; ++i) { + actual += o.a + ','; + actual += o.b + ','; + actual += o.c + ','; + } +} + +f(); + +assertEq(actual, expected); diff --git a/js/src/jit-test/tests/pic/self2.js b/js/src/jit-test/tests/pic/self2.js new file mode 100644 index 0000000..146771c --- /dev/null +++ b/js/src/jit-test/tests/pic/self2.js @@ -0,0 +1,18 @@ +// getprop, self, 2 shapes + +var expected = "22,303,22,303,22,303,22,303,"; +var actual = ''; + +function f() { + var o1 = { a: 11, b: 22, c: 33 }; + var o2 = { x: 101, y: 202, b: 303 }; + var oa = [ o1, o2 ]; + + for (var i = 0; i < 8; ++i) { + actual += oa[i%2].b + ','; + } +} + +f(); + +assertEq(actual, expected); diff --git a/js/src/jit-test/tests/pic/self3.js b/js/src/jit-test/tests/pic/self3.js new file mode 100644 index 0000000..b865a22 --- /dev/null +++ b/js/src/jit-test/tests/pic/self3.js @@ -0,0 +1,19 @@ +// getprop, self, 3 shapes + +var expected = "22,303,1001,22,303,1001,22,303,"; +var actual = ''; + +function f() { + var o1 = { a: 11, b: 22, c: 33 }; + var o2 = { x: 101, y: 202, b: 303 }; + var o3 = { b: 1001, x: 2002, y: 3003 }; + var oa = [ o1, o2, o3 ]; + + for (var i = 0; i < 8; ++i) { + actual += oa[i%3].b + ','; + } +} + +f(); + +assertEq(actual, expected); diff --git a/js/src/jit-test/tests/pic/self8.js b/js/src/jit-test/tests/pic/self8.js new file mode 100644 index 0000000..3c0523c --- /dev/null +++ b/js/src/jit-test/tests/pic/self8.js @@ -0,0 +1,32 @@ +// getprop, self, 8 shapes + +var expected = "0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,"; +var actual = ''; + +function letter(i) { + return String.fromCharCode(97 + i); +} + +function f() { + // Build 8 objects with different shapes and x in different slots. + var oa = []; + for (var i = 0; i < 8; ++i) { + var o = {}; + for (var j = 0; j < 8; ++j) { + if (j != i) { + o[letter(j)] = 1000 + i * 10 + j; + } else { + o.x = i; + } + } + oa[i] = o; + } + + for (var i = 0; i < 24; ++i) { + actual += oa[i%8].x + ','; + } +} + +f(); + +assertEq(actual, expected); diff --git a/js/src/jit-test/tests/pic/set-assign.js b/js/src/jit-test/tests/pic/set-assign.js new file mode 100644 index 0000000..227d92a --- /dev/null +++ b/js/src/jit-test/tests/pic/set-assign.js @@ -0,0 +1,10 @@ +function f() { + var o = { a: 555 }; + + for (var j = 0; j < 10; ++j) { + var i = o.a = 100 + j; + assertEq(i, 100 + j); + } +} + +f() \ No newline at end of file diff --git a/js/src/jit-test/tests/pic/set1.js b/js/src/jit-test/tests/pic/set1.js new file mode 100644 index 0000000..58db0a3 --- /dev/null +++ b/js/src/jit-test/tests/pic/set1.js @@ -0,0 +1,11 @@ +function f() { + var o = { a: 5 }; + + for (var i = 0; i < 5; ++i) { + o.a = i; + } + + assertEq(o.a, 4); +} + +f(); \ No newline at end of file diff --git a/js/src/jit-test/tests/pic/set2.js b/js/src/jit-test/tests/pic/set2.js new file mode 100644 index 0000000..8713642 --- /dev/null +++ b/js/src/jit-test/tests/pic/set2.js @@ -0,0 +1,14 @@ +function f(k) { + var o1 = { a: 5 }; + var o2 = { b : 7, a : 9 }; + + for (var i = 0; i < k; ++i) { + var o = i % 2 ? o2 : o1; + o.a = i; + } + + return o1.a + ',' + o2.a; +} + +assertEq(f(5), '4,3') +assertEq(f(6), '4,5') diff --git a/js/src/jit-test/tests/pic/shape_regen.js b/js/src/jit-test/tests/pic/shape_regen.js new file mode 100644 index 0000000..55b3ff1 --- /dev/null +++ b/js/src/jit-test/tests/pic/shape_regen.js @@ -0,0 +1,33 @@ +// Try to test that we handle shape regeneration correctly. +// This is a fragile test, but as of this writing, on dmandelin's +// windows box, we have the same shape number with different +// logical shapes in the two assertEq lines. + +var o; +var p; +var zz; +var o2; + +function f(x) { + return x.a; +} + +gczeal(1); +gc(); + +zz = { q: 11 }; +o = { a: 77, b: 88 }; +o2 = { c: 11 }; +p = { b: 99, a: 11 }; + +//print('s ' + shapeOf(zz) + ' ' + shapeOf(o) + ' ' + shapeOf(o2) + ' ' + shapeOf(p)); + +assertEq(f(o), 77); + +o = undefined; + +gczeal(1); +gc(); +//print('s ' + 'x' + ' ' + shapeOf(p)); + +assertEq(f(p), 11); diff --git a/js/src/jit-test/tests/pic/thisprop.js b/js/src/jit-test/tests/pic/thisprop.js new file mode 100644 index 0000000..e20d699 --- /dev/null +++ b/js/src/jit-test/tests/pic/thisprop.js @@ -0,0 +1,30 @@ +// test getthisprop + +var expected = "22,22,22,;33,33,33,;"; +var actual = ''; + +function f() { + for (var i = 0; i < 3; ++i) { + actual += this.b + ','; + } + actual += ';'; +} + +function A() { + this.a = 11; + this.b = 22; +}; + +A.prototype.f = f; + +function B() { + this.b = 33; + this.c = 44; +}; + +B.prototype.f = f; + +new A().f(); +new B().f(); + +assertEq(actual, expected); diff --git a/js/src/jit-test/tests/pic/to-dictionary.js b/js/src/jit-test/tests/pic/to-dictionary.js new file mode 100644 index 0000000..6f54647 --- /dev/null +++ b/js/src/jit-test/tests/pic/to-dictionary.js @@ -0,0 +1,9 @@ +function f() { + var MAX_HEIGHT = 64; + var obj = {}; + for (var i = 0; i < MAX_HEIGHT; i++) + obj['a' + i] = i; + obj.m = function () { return 0; }; +} +f(); +f(); diff --git a/js/src/jit-test/tests/sunspider/check-3d-cube.js b/js/src/jit-test/tests/sunspider/check-3d-cube.js new file mode 100644 index 0000000..036a4f6 --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-3d-cube.js @@ -0,0 +1,345 @@ +// 3D Cube Rotation +// http://www.speich.net/computer/moztesting/3d.htm +// Created by Simon Speich + +var Q = new Array(); +var MTrans = new Array(); // transformation matrix +var MQube = new Array(); // position information of qube +var I = new Array(); // entity matrix +var Origin = new Object(); +var Testing = new Object(); +var LoopTimer; + +var DisplArea = new Object(); +DisplArea.Width = 300; +DisplArea.Height = 300; + +function DrawLine(From, To) { + var x1 = From.V[0]; + var x2 = To.V[0]; + var y1 = From.V[1]; + var y2 = To.V[1]; + var dx = Math.abs(x2 - x1); + var dy = Math.abs(y2 - y1); + var x = x1; + var y = y1; + var IncX1, IncY1; + var IncX2, IncY2; + var Den; + var Num; + var NumAdd; + var NumPix; + + if (x2 >= x1) { IncX1 = 1; IncX2 = 1; } + else { IncX1 = -1; IncX2 = -1; } + if (y2 >= y1) { IncY1 = 1; IncY2 = 1; } + else { IncY1 = -1; IncY2 = -1; } + if (dx >= dy) { + IncX1 = 0; + IncY2 = 0; + Den = dx; + Num = dx / 2; + NumAdd = dy; + NumPix = dx; + } + else { + IncX2 = 0; + IncY1 = 0; + Den = dy; + Num = dy / 2; + NumAdd = dx; + NumPix = dy; + } + + NumPix = Math.round(Q.LastPx + NumPix); + + var i = Q.LastPx; + for (; i < NumPix; i++) { + Num += NumAdd; + if (Num >= Den) { + Num -= Den; + x += IncX1; + y += IncY1; + } + x += IncX2; + y += IncY2; + } + Q.LastPx = NumPix; +} + +function CalcCross(V0, V1) { + var Cross = new Array(); + Cross[0] = V0[1]*V1[2] - V0[2]*V1[1]; + Cross[1] = V0[2]*V1[0] - V0[0]*V1[2]; + Cross[2] = V0[0]*V1[1] - V0[1]*V1[0]; + return Cross; +} + +function CalcNormal(V0, V1, V2) { + var A = new Array(); var B = new Array(); + for (var i = 0; i < 3; i++) { + A[i] = V0[i] - V1[i]; + B[i] = V2[i] - V1[i]; + } + A = CalcCross(A, B); + var Length = Math.sqrt(A[0]*A[0] + A[1]*A[1] + A[2]*A[2]); + for (var i = 0; i < 3; i++) A[i] = A[i] / Length; + A[3] = 1; + return A; +} + +function CreateP(X,Y,Z) { + this.V = [X,Y,Z,1]; +} + +// multiplies two matrices +function MMulti(M1, M2) { + var M = [[],[],[],[]]; + var i = 0; + var j = 0; + for (; i < 4; i++) { + j = 0; + for (; j < 4; j++) M[i][j] = M1[i][0] * M2[0][j] + M1[i][1] * M2[1][j] + M1[i][2] * M2[2][j] + M1[i][3] * M2[3][j]; + } + return M; +} + +//multiplies matrix with vector +function VMulti(M, V) { + var Vect = new Array(); + var i = 0; + for (;i < 4; i++) Vect[i] = M[i][0] * V[0] + M[i][1] * V[1] + M[i][2] * V[2] + M[i][3] * V[3]; + return Vect; +} + +function VMulti2(M, V) { + var Vect = new Array(); + var i = 0; + for (;i < 3; i++) Vect[i] = M[i][0] * V[0] + M[i][1] * V[1] + M[i][2] * V[2]; + return Vect; +} + +// add to matrices +function MAdd(M1, M2) { + var M = [[],[],[],[]]; + var i = 0; + var j = 0; + for (; i < 4; i++) { + j = 0; + for (; j < 4; j++) M[i][j] = M1[i][j] + M2[i][j]; + } + return M; +} + +function Translate(M, Dx, Dy, Dz) { + var T = [ + [1,0,0,Dx], + [0,1,0,Dy], + [0,0,1,Dz], + [0,0,0,1] + ]; + return MMulti(T, M); +} + +function RotateX(M, Phi) { + var a = Phi; + a *= Math.PI / 180; + var Cos = Math.cos(a); + var Sin = Math.sin(a); + var R = [ + [1,0,0,0], + [0,Cos,-Sin,0], + [0,Sin,Cos,0], + [0,0,0,1] + ]; + return MMulti(R, M); +} + +function RotateY(M, Phi) { + var a = Phi; + a *= Math.PI / 180; + var Cos = Math.cos(a); + var Sin = Math.sin(a); + var R = [ + [Cos,0,Sin,0], + [0,1,0,0], + [-Sin,0,Cos,0], + [0,0,0,1] + ]; + return MMulti(R, M); +} + +function RotateZ(M, Phi) { + var a = Phi; + a *= Math.PI / 180; + var Cos = Math.cos(a); + var Sin = Math.sin(a); + var R = [ + [Cos,-Sin,0,0], + [Sin,Cos,0,0], + [0,0,1,0], + [0,0,0,1] + ]; + return MMulti(R, M); +} + +function DrawQube() { + // calc current normals + var CurN = new Array(); + var i = 5; + Q.LastPx = 0; + for (; i > -1; i--) CurN[i] = VMulti2(MQube, Q.Normal[i]); + if (CurN[0][2] < 0) { + if (!Q.Line[0]) { DrawLine(Q[0], Q[1]); Q.Line[0] = true; }; + if (!Q.Line[1]) { DrawLine(Q[1], Q[2]); Q.Line[1] = true; }; + if (!Q.Line[2]) { DrawLine(Q[2], Q[3]); Q.Line[2] = true; }; + if (!Q.Line[3]) { DrawLine(Q[3], Q[0]); Q.Line[3] = true; }; + } + if (CurN[1][2] < 0) { + if (!Q.Line[2]) { DrawLine(Q[3], Q[2]); Q.Line[2] = true; }; + if (!Q.Line[9]) { DrawLine(Q[2], Q[6]); Q.Line[9] = true; }; + if (!Q.Line[6]) { DrawLine(Q[6], Q[7]); Q.Line[6] = true; }; + if (!Q.Line[10]) { DrawLine(Q[7], Q[3]); Q.Line[10] = true; }; + } + if (CurN[2][2] < 0) { + if (!Q.Line[4]) { DrawLine(Q[4], Q[5]); Q.Line[4] = true; }; + if (!Q.Line[5]) { DrawLine(Q[5], Q[6]); Q.Line[5] = true; }; + if (!Q.Line[6]) { DrawLine(Q[6], Q[7]); Q.Line[6] = true; }; + if (!Q.Line[7]) { DrawLine(Q[7], Q[4]); Q.Line[7] = true; }; + } + if (CurN[3][2] < 0) { + if (!Q.Line[4]) { DrawLine(Q[4], Q[5]); Q.Line[4] = true; }; + if (!Q.Line[8]) { DrawLine(Q[5], Q[1]); Q.Line[8] = true; }; + if (!Q.Line[0]) { DrawLine(Q[1], Q[0]); Q.Line[0] = true; }; + if (!Q.Line[11]) { DrawLine(Q[0], Q[4]); Q.Line[11] = true; }; + } + if (CurN[4][2] < 0) { + if (!Q.Line[11]) { DrawLine(Q[4], Q[0]); Q.Line[11] = true; }; + if (!Q.Line[3]) { DrawLine(Q[0], Q[3]); Q.Line[3] = true; }; + if (!Q.Line[10]) { DrawLine(Q[3], Q[7]); Q.Line[10] = true; }; + if (!Q.Line[7]) { DrawLine(Q[7], Q[4]); Q.Line[7] = true; }; + } + if (CurN[5][2] < 0) { + if (!Q.Line[8]) { DrawLine(Q[1], Q[5]); Q.Line[8] = true; }; + if (!Q.Line[5]) { DrawLine(Q[5], Q[6]); Q.Line[5] = true; }; + if (!Q.Line[9]) { DrawLine(Q[6], Q[2]); Q.Line[9] = true; }; + if (!Q.Line[1]) { DrawLine(Q[2], Q[1]); Q.Line[1] = true; }; + } + Q.Line = [false,false,false,false,false,false,false,false,false,false,false,false]; + Q.LastPx = 0; +} + +function Loop() { + if (Testing.LoopCount > Testing.LoopMax) return; + var TestingStr = String(Testing.LoopCount); + while (TestingStr.length < 3) TestingStr = "0" + TestingStr; + MTrans = Translate(I, -Q[8].V[0], -Q[8].V[1], -Q[8].V[2]); + MTrans = RotateX(MTrans, 1); + MTrans = RotateY(MTrans, 3); + MTrans = RotateZ(MTrans, 5); + MTrans = Translate(MTrans, Q[8].V[0], Q[8].V[1], Q[8].V[2]); + MQube = MMulti(MTrans, MQube); + var i = 8; + for (; i > -1; i--) { + Q[i].V = VMulti(MTrans, Q[i].V); + } + DrawQube(); + Testing.LoopCount++; + Loop(); +} + +function Init(CubeSize) { + // init/reset vars + Origin.V = [150,150,20,1]; + Testing.LoopCount = 0; + Testing.LoopMax = 50; + Testing.TimeMax = 0; + Testing.TimeAvg = 0; + Testing.TimeMin = 0; + Testing.TimeTemp = 0; + Testing.TimeTotal = 0; + Testing.Init = false; + + // transformation matrix + MTrans = [ + [1,0,0,0], + [0,1,0,0], + [0,0,1,0], + [0,0,0,1] + ]; + + // position information of qube + MQube = [ + [1,0,0,0], + [0,1,0,0], + [0,0,1,0], + [0,0,0,1] + ]; + + // entity matrix + I = [ + [1,0,0,0], + [0,1,0,0], + [0,0,1,0], + [0,0,0,1] + ]; + + // create qube + Q[0] = new CreateP(-CubeSize,-CubeSize, CubeSize); + Q[1] = new CreateP(-CubeSize, CubeSize, CubeSize); + Q[2] = new CreateP( CubeSize, CubeSize, CubeSize); + Q[3] = new CreateP( CubeSize,-CubeSize, CubeSize); + Q[4] = new CreateP(-CubeSize,-CubeSize,-CubeSize); + Q[5] = new CreateP(-CubeSize, CubeSize,-CubeSize); + Q[6] = new CreateP( CubeSize, CubeSize,-CubeSize); + Q[7] = new CreateP( CubeSize,-CubeSize,-CubeSize); + + // center of gravity + Q[8] = new CreateP(0, 0, 0); + + // anti-clockwise edge check + Q.Edge = [[0,1,2],[3,2,6],[7,6,5],[4,5,1],[4,0,3],[1,5,6]]; + + // calculate squad normals + Q.Normal = new Array(); + for (var i = 0; i < Q.Edge.length; i++) Q.Normal[i] = CalcNormal(Q[Q.Edge[i][0]].V, Q[Q.Edge[i][1]].V, Q[Q.Edge[i][2]].V); + + // line drawn ? + Q.Line = [false,false,false,false,false,false,false,false,false,false,false,false]; + + // create line pixels + Q.NumPx = 9 * 2 * CubeSize; + for (var i = 0; i < Q.NumPx; i++) CreateP(0,0,0); + + MTrans = Translate(MTrans, Origin.V[0], Origin.V[1], Origin.V[2]); + MQube = MMulti(MTrans, MQube); + + var i = 0; + for (; i < 9; i++) { + Q[i].V = VMulti(MTrans, Q[i].V); + } + DrawQube(); + Testing.Init = true; + Loop(); +} + +for ( var i = 20; i <= 160; i *= 2 ) { + Init(i); +} + +var actual = ''; +for (var i = 0; i < Q.length; ++i) { + actual += Q[i].V + ';'; +} +var expected = "-116.618229186398,212.51135212951073,62.5094191967962,1;127.83701023614447,417.11611179082263,90.41153816299942,1;293.9570894432935,196.58093046570656,252.17789153139591,1;49.501850020750915,-8.02382919560505,224.275772565193,1;6.042910556709444,103.41906953429206,-212.1778915313964,1;250.49814997925202,308.02382919560387,-184.27577256519325,1;416.61822918640064,87.48864787048812,-22.509419196796493,1;172.1629897638581,-117.1161117908236,-50.41153816299975,1;150.0000000000007,149.99999999999952,20,1;"; +assertEq(actual, expected); + +Q = null; +MTrans = null; +MQube = null; +I = null; +Origin = null; +Testing = null; +LoopTime = null; +DisplArea = null; + diff --git a/js/src/jit-test/tests/sunspider/check-3d-morph.js b/js/src/jit-test/tests/sunspider/check-3d-morph.js new file mode 100644 index 0000000..3fabdc7 --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-3d-morph.js @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +var loops = 15 +var nx = 120 +var nz = 120 + +function morph(a, f) { + var PI2nx = Math.PI * 8/nx + var sin = Math.sin + var f30 = -(50 * sin(f*Math.PI*2)) + + for (var i = 0; i < nz; ++i) { + for (var j = 0; j < nx; ++j) { + a[3*(i*nx+j)+1] = sin((j-1) * PI2nx ) * -f30 + } + } +} + + +var a = Array() +for (var i=0; i < nx*nz*3; ++i) + a[i] = 0 + +for (var i = 0; i < loops; ++i) { + morph(a, i/loops) +} + +testOutput = 0; +for (var i = 0; i < nx; i++) + testOutput += a[3*(i*nx+i)+1]; +a = null; + +/* not based on any mathematical error calculation.*/ +acceptableDelta = 4e-15 + +assertEq((testOutput - 6.394884621840902e-14) < acceptableDelta, true); diff --git a/js/src/jit-test/tests/sunspider/check-3d-raytrace.js b/js/src/jit-test/tests/sunspider/check-3d-raytrace.js new file mode 100644 index 0000000..5e02060 --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-3d-raytrace.js @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function createVector(x,y,z) { + return new Array(x,y,z); +} + +function sqrLengthVector(self) { + return self[0] * self[0] + self[1] * self[1] + self[2] * self[2]; +} + +function lengthVector(self) { + return Math.sqrt(self[0] * self[0] + self[1] * self[1] + self[2] * self[2]); +} + +function addVector(self, v) { + self[0] += v[0]; + self[1] += v[1]; + self[2] += v[2]; + return self; +} + +function subVector(self, v) { + self[0] -= v[0]; + self[1] -= v[1]; + self[2] -= v[2]; + return self; +} + +function scaleVector(self, scale) { + self[0] *= scale; + self[1] *= scale; + self[2] *= scale; + return self; +} + +function normaliseVector(self) { + var len = Math.sqrt(self[0] * self[0] + self[1] * self[1] + self[2] * self[2]); + self[0] /= len; + self[1] /= len; + self[2] /= len; + return self; +} + +function add(v1, v2) { + return new Array(v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]); +} + +function sub(v1, v2) { + return new Array(v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]); +} + +function scalev(v1, v2) { + return new Array(v1[0] * v2[0], v1[1] * v2[1], v1[2] * v2[2]); +} + +function dot(v1, v2) { + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; +} + +function scale(v, scale) { + return [v[0] * scale, v[1] * scale, v[2] * scale]; +} + +function cross(v1, v2) { + return [v1[1] * v2[2] - v1[2] * v2[1], + v1[2] * v2[0] - v1[0] * v2[2], + v1[0] * v2[1] - v1[1] * v2[0]]; + +} + +function normalise(v) { + var len = lengthVector(v); + return [v[0] / len, v[1] / len, v[2] / len]; +} + +function transformMatrix(self, v) { + var vals = self; + var x = vals[0] * v[0] + vals[1] * v[1] + vals[2] * v[2] + vals[3]; + var y = vals[4] * v[0] + vals[5] * v[1] + vals[6] * v[2] + vals[7]; + var z = vals[8] * v[0] + vals[9] * v[1] + vals[10] * v[2] + vals[11]; + return [x, y, z]; +} + +function invertMatrix(self) { + var temp = new Array(16); + var tx = -self[3]; + var ty = -self[7]; + var tz = -self[11]; + for (h = 0; h < 3; h++) + for (v = 0; v < 3; v++) + temp[h + v * 4] = self[v + h * 4]; + for (i = 0; i < 11; i++) + self[i] = temp[i]; + self[3] = tx * self[0] + ty * self[1] + tz * self[2]; + self[7] = tx * self[4] + ty * self[5] + tz * self[6]; + self[11] = tx * self[8] + ty * self[9] + tz * self[10]; + return self; +} + + +// Triangle intersection using barycentric coord method +function Triangle(p1, p2, p3) { + var edge1 = sub(p3, p1); + var edge2 = sub(p2, p1); + var normal = cross(edge1, edge2); + if (Math.abs(normal[0]) > Math.abs(normal[1])) + if (Math.abs(normal[0]) > Math.abs(normal[2])) + this.axis = 0; + else + this.axis = 2; + else + if (Math.abs(normal[1]) > Math.abs(normal[2])) + this.axis = 1; + else + this.axis = 2; + var u = (this.axis + 1) % 3; + var v = (this.axis + 2) % 3; + var u1 = edge1[u]; + var v1 = edge1[v]; + + var u2 = edge2[u]; + var v2 = edge2[v]; + this.normal = normalise(normal); + this.nu = normal[u] / normal[this.axis]; + this.nv = normal[v] / normal[this.axis]; + this.nd = dot(normal, p1) / normal[this.axis]; + var det = u1 * v2 - v1 * u2; + this.eu = p1[u]; + this.ev = p1[v]; + this.nu1 = u1 / det; + this.nv1 = -v1 / det; + this.nu2 = v2 / det; + this.nv2 = -u2 / det; + this.material = [0.7, 0.7, 0.7]; +} + +Triangle.prototype.intersect = function(orig, dir, near, far) { + var u = (this.axis + 1) % 3; + var v = (this.axis + 2) % 3; + var d = dir[this.axis] + this.nu * dir[u] + this.nv * dir[v]; + var t = (this.nd - orig[this.axis] - this.nu * orig[u] - this.nv * orig[v]) / d; + if (t < near || t > far) + return null; + var Pu = orig[u] + t * dir[u] - this.eu; + var Pv = orig[v] + t * dir[v] - this.ev; + var a2 = Pv * this.nu1 + Pu * this.nv1; + if (a2 < 0) + return null; + var a3 = Pu * this.nu2 + Pv * this.nv2; + if (a3 < 0) + return null; + + if ((a2 + a3) > 1) + return null; + return t; +} + +function Scene(a_triangles) { + this.triangles = a_triangles; + this.lights = []; + this.ambient = [0,0,0]; + this.background = [0.8,0.8,1]; +} +var zero = new Array(0,0,0); + +Scene.prototype.intersect = function(origin, dir, near, far) { + var closest = null; + for (i = 0; i < this.triangles.length; i++) { + var triangle = this.triangles[i]; + var d = triangle.intersect(origin, dir, near, far); + if (d == null || d > far || d < near) + continue; + far = d; + closest = triangle; + } + + if (!closest) + return [this.background[0],this.background[1],this.background[2]]; + + var normal = closest.normal; + var hit = add(origin, scale(dir, far)); + if (dot(dir, normal) > 0) + normal = [-normal[0], -normal[1], -normal[2]]; + + var colour = null; + if (closest.shader) { + colour = closest.shader(closest, hit, dir); + } else { + colour = closest.material; + } + + // do reflection + var reflected = null; + if (colour.reflection > 0.001) { + var reflection = addVector(scale(normal, -2*dot(dir, normal)), dir); + reflected = this.intersect(hit, reflection, 0.0001, 1000000); + if (colour.reflection >= 0.999999) + return reflected; + } + + var l = [this.ambient[0], this.ambient[1], this.ambient[2]]; + for (var i = 0; i < this.lights.length; i++) { + var light = this.lights[i]; + var toLight = sub(light, hit); + var distance = lengthVector(toLight); + scaleVector(toLight, 1.0/distance); + distance -= 0.0001; + if (this.blocked(hit, toLight, distance)) + continue; + var nl = dot(normal, toLight); + if (nl > 0) + addVector(l, scale(light.colour, nl)); + } + l = scalev(l, colour); + if (reflected) { + l = addVector(scaleVector(l, 1 - colour.reflection), scaleVector(reflected, colour.reflection)); + } + return l; +} + +Scene.prototype.blocked = function(O, D, far) { + var near = 0.0001; + var closest = null; + for (i = 0; i < this.triangles.length; i++) { + var triangle = this.triangles[i]; + var d = triangle.intersect(O, D, near, far); + if (d == null || d > far || d < near) + continue; + return true; + } + + return false; +} + + +// this camera code is from notes i made ages ago, it is from *somewhere* -- i cannot remember where +// that somewhere is +function Camera(origin, lookat, up) { + var zaxis = normaliseVector(subVector(lookat, origin)); + var xaxis = normaliseVector(cross(up, zaxis)); + var yaxis = normaliseVector(cross(xaxis, subVector([0,0,0], zaxis))); + var m = new Array(16); + m[0] = xaxis[0]; m[1] = xaxis[1]; m[2] = xaxis[2]; + m[4] = yaxis[0]; m[5] = yaxis[1]; m[6] = yaxis[2]; + m[8] = zaxis[0]; m[9] = zaxis[1]; m[10] = zaxis[2]; + invertMatrix(m); + m[3] = 0; m[7] = 0; m[11] = 0; + this.origin = origin; + this.directions = new Array(4); + this.directions[0] = normalise([-0.7, 0.7, 1]); + this.directions[1] = normalise([ 0.7, 0.7, 1]); + this.directions[2] = normalise([ 0.7, -0.7, 1]); + this.directions[3] = normalise([-0.7, -0.7, 1]); + this.directions[0] = transformMatrix(m, this.directions[0]); + this.directions[1] = transformMatrix(m, this.directions[1]); + this.directions[2] = transformMatrix(m, this.directions[2]); + this.directions[3] = transformMatrix(m, this.directions[3]); +} + +Camera.prototype.generateRayPair = function(y) { + rays = new Array(new Object(), new Object()); + rays[0].origin = this.origin; + rays[1].origin = this.origin; + rays[0].dir = addVector(scale(this.directions[0], y), scale(this.directions[3], 1 - y)); + rays[1].dir = addVector(scale(this.directions[1], y), scale(this.directions[2], 1 - y)); + return rays; +} + +function renderRows(camera, scene, pixels, width, height, starty, stopy) { + for (var y = starty; y < stopy; y++) { + var rays = camera.generateRayPair(y / height); + for (var x = 0; x < width; x++) { + var xp = x / width; + var origin = addVector(scale(rays[0].origin, xp), scale(rays[1].origin, 1 - xp)); + var dir = normaliseVector(addVector(scale(rays[0].dir, xp), scale(rays[1].dir, 1 - xp))); + var l = scene.intersect(origin, dir); + pixels[y][x] = l; + } + } +} + +Camera.prototype.render = function(scene, pixels, width, height) { + var cam = this; + var row = 0; + renderRows(cam, scene, pixels, width, height, 0, height); +} + + + +function raytraceScene() +{ + var startDate = new Date().getTime(); + var numTriangles = 2 * 6; + var triangles = new Array();//numTriangles); + var tfl = createVector(-10, 10, -10); + var tfr = createVector( 10, 10, -10); + var tbl = createVector(-10, 10, 10); + var tbr = createVector( 10, 10, 10); + var bfl = createVector(-10, -10, -10); + var bfr = createVector( 10, -10, -10); + var bbl = createVector(-10, -10, 10); + var bbr = createVector( 10, -10, 10); + + // cube!!! + // front + var i = 0; + + triangles[i++] = new Triangle(tfl, tfr, bfr); + triangles[i++] = new Triangle(tfl, bfr, bfl); + // back + triangles[i++] = new Triangle(tbl, tbr, bbr); + triangles[i++] = new Triangle(tbl, bbr, bbl); + // triangles[i-1].material = [0.7,0.2,0.2]; + // triangles[i-1].material.reflection = 0.8; + // left + triangles[i++] = new Triangle(tbl, tfl, bbl); + // triangles[i-1].reflection = 0.6; + triangles[i++] = new Triangle(tfl, bfl, bbl); + // triangles[i-1].reflection = 0.6; + // right + triangles[i++] = new Triangle(tbr, tfr, bbr); + triangles[i++] = new Triangle(tfr, bfr, bbr); + // top + triangles[i++] = new Triangle(tbl, tbr, tfr); + triangles[i++] = new Triangle(tbl, tfr, tfl); + // bottom + triangles[i++] = new Triangle(bbl, bbr, bfr); + triangles[i++] = new Triangle(bbl, bfr, bfl); + + //Floor!!!! + var green = createVector(0.0, 0.4, 0.0); + var grey = createVector(0.4, 0.4, 0.4); + grey.reflection = 1.0; + var floorShader = function(tri, pos, view) { + var x = ((pos[0]/32) % 2 + 2) % 2; + var z = ((pos[2]/32 + 0.3) % 2 + 2) % 2; + if (x < 1 != z < 1) { + //in the real world we use the fresnel term... + // var angle = 1-dot(view, tri.normal); + // angle *= angle; + // angle *= angle; + // angle *= angle; + //grey.reflection = angle; + return grey; + } else + return green; + } + var ffl = createVector(-1000, -30, -1000); + var ffr = createVector( 1000, -30, -1000); + var fbl = createVector(-1000, -30, 1000); + var fbr = createVector( 1000, -30, 1000); + triangles[i++] = new Triangle(fbl, fbr, ffr); + triangles[i-1].shader = floorShader; + triangles[i++] = new Triangle(fbl, ffr, ffl); + triangles[i-1].shader = floorShader; + + var _scene = new Scene(triangles); + _scene.lights[0] = createVector(20, 38, -22); + _scene.lights[0].colour = createVector(0.7, 0.3, 0.3); + _scene.lights[1] = createVector(-23, 40, 17); + _scene.lights[1].colour = createVector(0.7, 0.3, 0.3); + _scene.lights[2] = createVector(23, 20, 17); + _scene.lights[2].colour = createVector(0.7, 0.7, 0.7); + _scene.ambient = createVector(0.1, 0.1, 0.1); + // _scene.background = createVector(0.7, 0.7, 1.0); + + var size = 30; + var pixels = new Array(); + for (var y = 0; y < size; y++) { + pixels[y] = new Array(); + for (var x = 0; x < size; x++) { + pixels[y][x] = 0; + } + } + + var _camera = new Camera(createVector(-40, 40, 40), createVector(0, 0, 0), createVector(0, 1, 0)); + _camera.render(_scene, pixels, size, size); + + return pixels; +} + +function arrayToCanvasCommands(pixels) +{ + var s = '\nvar pixels = ['; + var size = 30; + for (var y = 0; y < size; y++) { + s += "["; + for (var x = 0; x < size; x++) { + s += "[" + pixels[y][x] + "],"; + } + s+= "],"; + } + s += '];\n var canvas = document.getElementById("renderCanvas").getContext("2d");\n\ +\n\ +\n\ + var size = 30;\n\ + canvas.fillStyle = "red";\n\ + canvas.fillRect(0, 0, size, size);\n\ + canvas.scale(1, -1);\n\ + canvas.translate(0, -size);\n\ +\n\ + if (!canvas.setFillColor)\n\ + canvas.setFillColor = function(r, g, b, a) {\n\ + this.fillStyle = "rgb("+[Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)]+")";\n\ + }\n\ +\n\ +for (var y = 0; y < size; y++) {\n\ + for (var x = 0; x < size; x++) {\n\ + var l = pixels[y][x];\n\ + canvas.setFillColor(l[0], l[1], l[2], 1);\n\ + canvas.fillRect(x, y, 1, 1);\n\ + }\n\ +}'; + + return s; +} + +testOutput = arrayToCanvasCommands(raytraceScene()); +expected = ''; +assertEq(testOutput, expected) diff --git a/js/src/jit-test/tests/sunspider/check-access-binary-trees.js b/js/src/jit-test/tests/sunspider/check-access-binary-trees.js new file mode 100644 index 0000000..e10961a --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-access-binary-trees.js @@ -0,0 +1,52 @@ +/* The Great Computer Language Shootout + http://shootout.alioth.debian.org/ + contributed by Isaac Gouy */ + +function TreeNode(left,right,item){ + this.left = left; + this.right = right; + this.item = item; +} + +TreeNode.prototype.itemCheck = function(){ + if (this.left==null) return this.item; + else return this.item + this.left.itemCheck() - this.right.itemCheck(); +} + +function bottomUpTree(item,depth){ + if (depth>0){ + return new TreeNode( + bottomUpTree(2*item-1, depth-1) + ,bottomUpTree(2*item, depth-1) + ,item + ); + } + else { + return new TreeNode(null,null,item); + } +} + +var ret; + +for ( var n = 4; n <= 7; n += 1 ) { + var minDepth = 4; + var maxDepth = Math.max(minDepth + 2, n); + var stretchDepth = maxDepth + 1; + + var check = bottomUpTree(0,stretchDepth).itemCheck(); + + var longLivedTree = bottomUpTree(0,maxDepth); + for (var depth=minDepth; depth<=maxDepth; depth+=2){ + var iterations = 1 << (maxDepth - depth + minDepth); + + check = 0; + for (var i=1; i<=iterations; i++){ + check += bottomUpTree(i,depth).itemCheck(); + check += bottomUpTree(-i,depth).itemCheck(); + } + } + + ret = longLivedTree.itemCheck(); +} + +assertEq(ret, -1) diff --git a/js/src/jit-test/tests/sunspider/check-access-fannkuch.js b/js/src/jit-test/tests/sunspider/check-access-fannkuch.js new file mode 100644 index 0000000..d2bb98d --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-access-fannkuch.js @@ -0,0 +1,66 @@ +/* The Great Computer Language Shootout + http://shootout.alioth.debian.org/ + contributed by Isaac Gouy */ + +function fannkuch(n) { + var check = 0; + var perm = Array(n); + var perm1 = Array(n); + var count = Array(n); + var maxPerm = Array(n); + var maxFlipsCount = 0; + var m = n - 1; + + for (var i = 0; i < n; i++) perm1[i] = i; + var r = n; + + while (true) { + // write-out the first 30 permutations + if (check < 30){ + var s = ""; + for(var i=0; i> 1; + for (var i = 0; i < k2; i++) { + var temp = perm[i]; perm[i] = perm[k - i]; perm[k - i] = temp; + } + flipsCount++; + } + + if (flipsCount > maxFlipsCount) { + maxFlipsCount = flipsCount; + for (var i = 0; i < n; i++) maxPerm[i] = perm1[i]; + } + } + + while (true) { + if (r == n) return maxFlipsCount; + var perm0 = perm1[0]; + var i = 0; + while (i < r) { + var j = i + 1; + perm1[i] = perm1[j]; + i = j; + } + perm1[r] = perm0; + + count[r] = count[r] - 1; + if (count[r] > 0) break; + r++; + } + } +} + +var n = 8; +var ret = fannkuch(n); +assertEq(ret, 22) diff --git a/js/src/jit-test/tests/sunspider/check-access-nbody.js b/js/src/jit-test/tests/sunspider/check-access-nbody.js new file mode 100644 index 0000000..5bcfd59 --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-access-nbody.js @@ -0,0 +1,171 @@ +/* The Great Computer Language Shootout + http://shootout.alioth.debian.org/ + contributed by Isaac Gouy */ + +var PI = 3.141592653589793; +var SOLAR_MASS = 4 * PI * PI; +var DAYS_PER_YEAR = 365.24; + +function Body(x,y,z,vx,vy,vz,mass){ + this.x = x; + this.y = y; + this.z = z; + this.vx = vx; + this.vy = vy; + this.vz = vz; + this.mass = mass; +} + +Body.prototype.offsetMomentum = function(px,py,pz) { + this.vx = -px / SOLAR_MASS; + this.vy = -py / SOLAR_MASS; + this.vz = -pz / SOLAR_MASS; + return this; +} + +function Jupiter(){ + return new Body( + 4.84143144246472090e+00, + -1.16032004402742839e+00, + -1.03622044471123109e-01, + 1.66007664274403694e-03 * DAYS_PER_YEAR, + 7.69901118419740425e-03 * DAYS_PER_YEAR, + -6.90460016972063023e-05 * DAYS_PER_YEAR, + 9.54791938424326609e-04 * SOLAR_MASS + ); +} + +function Saturn(){ + return new Body( + 8.34336671824457987e+00, + 4.12479856412430479e+00, + -4.03523417114321381e-01, + -2.76742510726862411e-03 * DAYS_PER_YEAR, + 4.99852801234917238e-03 * DAYS_PER_YEAR, + 2.30417297573763929e-05 * DAYS_PER_YEAR, + 2.85885980666130812e-04 * SOLAR_MASS + ); +} + +function Uranus(){ + return new Body( + 1.28943695621391310e+01, + -1.51111514016986312e+01, + -2.23307578892655734e-01, + 2.96460137564761618e-03 * DAYS_PER_YEAR, + 2.37847173959480950e-03 * DAYS_PER_YEAR, + -2.96589568540237556e-05 * DAYS_PER_YEAR, + 4.36624404335156298e-05 * SOLAR_MASS + ); +} + +function Neptune(){ + return new Body( + 1.53796971148509165e+01, + -2.59193146099879641e+01, + 1.79258772950371181e-01, + 2.68067772490389322e-03 * DAYS_PER_YEAR, + 1.62824170038242295e-03 * DAYS_PER_YEAR, + -9.51592254519715870e-05 * DAYS_PER_YEAR, + 5.15138902046611451e-05 * SOLAR_MASS + ); +} + +function Sun(){ + return new Body(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, SOLAR_MASS); +} + + +function NBodySystem(bodies){ + this.bodies = bodies; + var px = 0.0; + var py = 0.0; + var pz = 0.0; + var size = this.bodies.length; + for (var i=0; i0){ + for (var i=1; i<=prefixWidth; i++) s = " " + s; + } + return s; +} + +function nsieve(m, isPrime){ + var i, k, count; + + for (i=2; i<=m; i++) { isPrime[i] = true; } + count = 0; + + for (i=2; i<=m; i++){ + if (isPrime[i]) { + for (k=i+i; k<=m; k+=i) isPrime[k] = false; + count++; + } + } + return count; +} + +var ret = 0; +function sieve() { + for (var i = 1; i <= 3; i++ ) { + var m = (1<> ((b << 1) & 14)); +c += 3 & (bi3b >> ((b >> 2) & 14)); +c += 3 & (bi3b >> ((b >> 5) & 6)); +return c; + +/* +lir4,0xE994; 9 instructions, no memory access, minimal register dependence, 6 shifts, 2 adds, 1 inline assign +rlwinmr5,r3,1,28,30 +rlwinmr6,r3,30,28,30 +rlwinmr7,r3,27,29,30 +rlwnmr8,r4,r5,30,31 +rlwnmr9,r4,r6,30,31 +rlwnmr10,r4,r7,30,31 +addr3,r8,r9 +addr3,r3,r10 +*/ +} + +var ret = 0; +function TimeFunc(func) { + var x, y, t; + for(var x=0; x<500; x++) + for(var y=0; y<256; y++) { + ret += func(y); + } +} + +TimeFunc(fast3bitlookup); +assertEq(ret, 512000) diff --git a/js/src/jit-test/tests/sunspider/check-bitops-bits-in-byte.js b/js/src/jit-test/tests/sunspider/check-bitops-bits-in-byte.js new file mode 100644 index 0000000..8a0efda --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-bitops-bits-in-byte.js @@ -0,0 +1,24 @@ +// Copyright (c) 2004 by Arthur Langereis (arthur_ext at domain xfinitegames, tld com) + + +// 1 op = 2 assigns, 16 compare/branches, 8 ANDs, (0-8) ADDs, 8 SHLs +// O(n) +function bitsinbyte(b) { +var m = 1, c = 0; +while(m<0x100) { +if(b & m) c++; +m <<= 1; +} +return c; +} + +var ret = 0; +function TimeFunc(func) { +var x, y, t; +for(var x=0; x<350; x++) +for(var y=0; y<256; y++) + ret += func(y); +} + +TimeFunc(bitsinbyte); +assertEq(ret, 358400) diff --git a/js/src/jit-test/tests/sunspider/check-bitops-bitwise-and.js b/js/src/jit-test/tests/sunspider/check-bitops-bitwise-and.js new file mode 100644 index 0000000..5971de7 --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-bitops-bitwise-and.js @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +bitwiseAndValue = 4294967296; +for (var i = 0; i < 60; i++) + bitwiseAndValue = bitwiseAndValue & i; +assertEq(bitwiseAndValue, 0) diff --git a/js/src/jit-test/tests/sunspider/check-bitops-nsieve-bits.js b/js/src/jit-test/tests/sunspider/check-bitops-nsieve-bits.js new file mode 100644 index 0000000..1db6ff2 --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-bitops-nsieve-bits.js @@ -0,0 +1,40 @@ +// The Great Computer Language Shootout +// http://shootout.alioth.debian.org +// +// Contributed by Ian Osgood + +var result = []; + +function pad(n,width) { + var s = n.toString(); + while (s.length < width) s = ' ' + s; + return s; +} + +function primes(isPrime, n) { + var i, count = 0, m = 10000<>5; + + for (i=0; i>5] & 1<<(i&31)) { + for (var j=i+i; j>5] &= ~(1<<(j&31))); + count++; + } +} + +function sieve() { + for (var i = 4; i <= 4; i++) { + var isPrime = new Array((10000<>5); + primes(isPrime, i); + } +} + +sieve(); + +var ret = 0; +for (var i = 0; i < result.length; ++i) + ret += result[i]; + +assertEq(ret, -211235557404919) diff --git a/js/src/jit-test/tests/sunspider/check-controlflow-recursive.js b/js/src/jit-test/tests/sunspider/check-controlflow-recursive.js new file mode 100644 index 0000000..8ee010e --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-controlflow-recursive.js @@ -0,0 +1,27 @@ +// The Computer Language Shootout +// http://shootout.alioth.debian.org/ +// contributed by Isaac Gouy + +function ack(m,n){ + if (m==0) { return n+1; } + if (n==0) { return ack(m-1,1); } + return ack(m-1, ack(m,n-1) ); +} + +function fib(n) { + if (n < 2){ return 1; } + return fib(n-2) + fib(n-1); +} + +function tak(x,y,z) { + if (y >= x) return z; + return tak(tak(x-1,y,z), tak(y-1,z,x), tak(z-1,x,y)); +} + +var ret = 0; +for ( var i = 3; i <= 5; i++ ) { + ret += ack(3,i); + ret += fib(17.0+i); + ret += tak(3*i+3,2*i+2,i+1); +} +assertEq(ret, 57775); diff --git a/js/src/jit-test/tests/sunspider/check-crypto-aes.js b/js/src/jit-test/tests/sunspider/check-crypto-aes.js new file mode 100644 index 0000000..6bcdb54 --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-crypto-aes.js @@ -0,0 +1,424 @@ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* + * AES Cipher function: encrypt 'input' with Rijndael algorithm + * + * takes byte-array 'input' (16 bytes) + * 2D byte-array key schedule 'w' (Nr+1 x Nb bytes) + * + * applies Nr rounds (10/12/14) using key schedule w for 'add round key' stage + * + * returns byte-array encrypted value (16 bytes) + */ +function Cipher(input, w) { // main Cipher function [§5.1] + var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES) + var Nr = w.length/Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys + + var state = [[],[],[],[]]; // initialise 4xNb byte-array 'state' with input [§3.4] + for (var i=0; i<4*Nb; i++) state[i%4][Math.floor(i/4)] = input[i]; + + state = AddRoundKey(state, w, 0, Nb); + + for (var round=1; round 6 && i%Nk == 4) { + temp = SubWord(temp); + } + for (var t=0; t<4; t++) w[i][t] = w[i-Nk][t] ^ temp[t]; + } + + return w; +} + +function SubWord(w) { // apply SBox to 4-byte word w + for (var i=0; i<4; i++) w[i] = Sbox[w[i]]; + return w; +} + +function RotWord(w) { // rotate 4-byte word w left by one byte + w[4] = w[0]; + for (var i=0; i<4; i++) w[i] = w[i+1]; + return w; +} + + +// Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [§5.1.1] +var Sbox = [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, + 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, + 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, + 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, + 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, + 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, + 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, + 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, + 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, + 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, + 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, + 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, + 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, + 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, + 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, + 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16]; + +// Rcon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [§5.2] +var Rcon = [ [0x00, 0x00, 0x00, 0x00], + [0x01, 0x00, 0x00, 0x00], + [0x02, 0x00, 0x00, 0x00], + [0x04, 0x00, 0x00, 0x00], + [0x08, 0x00, 0x00, 0x00], + [0x10, 0x00, 0x00, 0x00], + [0x20, 0x00, 0x00, 0x00], + [0x40, 0x00, 0x00, 0x00], + [0x80, 0x00, 0x00, 0x00], + [0x1b, 0x00, 0x00, 0x00], + [0x36, 0x00, 0x00, 0x00] ]; + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* + * Use AES to encrypt 'plaintext' with 'password' using 'nBits' key, in 'Counter' mode of operation + * - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + * for each block + * - outputblock = cipher(counter, key) + * - cipherblock = plaintext xor outputblock + */ +function AESEncryptCtr(plaintext, password, nBits) { + if (!(nBits==128 || nBits==192 || nBits==256)) return ''; // standard allows 128/192/256 bit keys + + // for this example script, generate the key by applying Cipher to 1st 16/24/32 chars of password; + // for real-world applications, a more secure approach would be to hash the password e.g. with SHA-1 + var nBytes = nBits/8; // no bytes in key + var pwBytes = new Array(nBytes); + for (var i=0; i>> i*8) & 0xff; + for (var i=0; i<4; i++) counterBlock[i+4] = (nonce/0x100000000 >>> i*8) & 0xff; + + // generate key schedule - an expansion of the key into distinct Key Rounds for each round + var keySchedule = KeyExpansion(key); + + var blockCount = Math.ceil(plaintext.length/blockSize); + var ciphertext = new Array(blockCount); // ciphertext as array of strings + + for (var b=0; b>> c*8) & 0xff; + for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8) + + var cipherCntr = Cipher(counterBlock, keySchedule); // -- encrypt counter block -- + + // calculate length of final block: + var blockLength = b>> c*8) & 0xff; + for (var c=0; c<4; c++) counterBlock[15-c-4] = ((b/0x100000000-1) >>> c*8) & 0xff; + + var cipherCntr = Cipher(counterBlock, keySchedule); // encrypt counter block + + ciphertext[b] = unescCtrlChars(ciphertext[b]); + + var pt = ''; + for (var i=0; i>18 & 0x3f; + h2 = bits>>12 & 0x3f; + h3 = bits>>6 & 0x3f; + h4 = bits & 0x3f; + + // end of string? index to '=' in b64 + if (isNaN(o3)) h4 = 64; + if (isNaN(o2)) h3 = 64; + + // use hexets to index into b64, and append result to encoded string + enc += b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); + } while (i < str.length); + + return enc; +} + +function decodeBase64(str) { + var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc=''; + + do { // unpack four hexets into three octets using index points in b64 + h1 = b64.indexOf(str.charAt(i++)); + h2 = b64.indexOf(str.charAt(i++)); + h3 = b64.indexOf(str.charAt(i++)); + h4 = b64.indexOf(str.charAt(i++)); + + bits = h1<<18 | h2<<12 | h3<<6 | h4; + + o1 = bits>>16 & 0xff; + o2 = bits>>8 & 0xff; + o3 = bits & 0xff; + + if (h3 == 64) enc += String.fromCharCode(o1); + else if (h4 == 64) enc += String.fromCharCode(o1, o2); + else enc += String.fromCharCode(o1, o2, o3); + } while (i < str.length); + + return decodeUTF8(enc); // decode UTF-8 byte-array back to Unicode +} + +function encodeUTF8(str) { // encode multi-byte string into utf-8 multiple single-byte characters + str = str.replace( + /[\u0080-\u07ff]/g, // U+0080 - U+07FF = 2-byte chars + function(c) { + var cc = c.charCodeAt(0); + return String.fromCharCode(0xc0 | cc>>6, 0x80 | cc&0x3f); } + ); + str = str.replace( + /[\u0800-\uffff]/g, // U+0800 - U+FFFF = 3-byte chars + function(c) { + var cc = c.charCodeAt(0); + return String.fromCharCode(0xe0 | cc>>12, 0x80 | cc>>6&0x3F, 0x80 | cc&0x3f); } + ); + return str; +} + +function decodeUTF8(str) { // decode utf-8 encoded string back into multi-byte characters + str = str.replace( + /[\u00c0-\u00df][\u0080-\u00bf]/g, // 2-byte chars + function(c) { + var cc = (c.charCodeAt(0)&0x1f)<<6 | c.charCodeAt(1)&0x3f; + return String.fromCharCode(cc); } + ); + str = str.replace( + /[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, // 3-byte chars + function(c) { + var cc = (c.charCodeAt(0)&0x0f)<<12 | (c.charCodeAt(1)&0x3f<<6) | c.charCodeAt(2)&0x3f; + return String.fromCharCode(cc); } + ); + return str; +} + + +function byteArrayToHexStr(b) { // convert byte array to hex string for displaying test vectors + var s = ''; + for (var i=0; i> 5] |= 0x80 << ((len) % 32); + x[(((len + 64) >>> 9) << 4) + 14] = len; + + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + + for(var i = 0; i < x.length; i += 16) + { + var olda = a; + var oldb = b; + var oldc = c; + var oldd = d; + + a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); + d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); + c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); + b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); + a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); + d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); + c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); + b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); + a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); + d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); + c = md5_ff(c, d, a, b, x[i+10], 17, -42063); + b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); + a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); + d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); + c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); + b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); + + a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); + d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); + c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); + b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); + a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); + d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); + c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); + b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); + a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); + d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); + c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); + b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); + a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); + d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); + c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); + b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); + + a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); + d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); + c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); + b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); + a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); + d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); + c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); + b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); + a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); + d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); + c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); + b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); + a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); + d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); + c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); + b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); + + a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); + d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); + c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); + b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); + a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); + d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); + c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); + b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); + a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); + d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); + c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); + b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); + a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); + d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); + c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); + b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + } + return Array(a, b, c, d); + +} + +/* + * These functions implement the four basic operations the algorithm uses. + */ +function md5_cmn(q, a, b, x, s, t) +{ + return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); +} +function md5_ff(a, b, c, d, x, s, t) +{ + return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); +} +function md5_gg(a, b, c, d, x, s, t) +{ + return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); +} +function md5_hh(a, b, c, d, x, s, t) +{ + return md5_cmn(b ^ c ^ d, a, b, x, s, t); +} +function md5_ii(a, b, c, d, x, s, t) +{ + return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); +} + +/* + * Calculate the HMAC-MD5, of a key and some data + */ +function core_hmac_md5(key, data) +{ + var bkey = str2binl(key); + if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz); + + var ipad = Array(16), opad = Array(16); + for(var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); + return core_md5(opad.concat(hash), 512 + 128); +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function bit_rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +} + +/* + * Convert a string to an array of little-endian words + * If chrsz is ASCII, characters >255 have their hi-byte silently ignored. + */ +function str2binl(str) +{ + var bin = Array(); + var mask = (1 << chrsz) - 1; + for(var i = 0; i < str.length * chrsz; i += chrsz) + bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); + return bin; +} + +/* + * Convert an array of little-endian words to a string + */ +function binl2str(bin) +{ + var str = ""; + var mask = (1 << chrsz) - 1; + for(var i = 0; i < bin.length * 32; i += chrsz) + str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); + return str; +} + +/* + * Convert an array of little-endian words to a hex string. + */ +function binl2hex(binarray) +{ + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var str = ""; + for(var i = 0; i < binarray.length * 4; i++) + { + str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + + hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF); + } + return str; +} + +/* + * Convert an array of little-endian words to a base-64 string + */ +function binl2b64(binarray) +{ + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var str = ""; + for(var i = 0; i < binarray.length * 4; i += 3) + { + var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16) + | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) + | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF); + for(var j = 0; j < 4; j++) + { + if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; + else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); + } + } + return str; +} + +var plainText = "Rebellious subjects, enemies to peace,\n\ +Profaners of this neighbour-stained steel,--\n\ +Will they not hear? What, ho! you men, you beasts,\n\ +That quench the fire of your pernicious rage\n\ +With purple fountains issuing from your veins,\n\ +On pain of torture, from those bloody hands\n\ +Throw your mistemper'd weapons to the ground,\n\ +And hear the sentence of your moved prince.\n\ +Three civil brawls, bred of an airy word,\n\ +By thee, old Capulet, and Montague,\n\ +Have thrice disturb'd the quiet of our streets,\n\ +And made Verona's ancient citizens\n\ +Cast by their grave beseeming ornaments,\n\ +To wield old partisans, in hands as old,\n\ +Canker'd with peace, to part your canker'd hate:\n\ +If ever you disturb our streets again,\n\ +Your lives shall pay the forfeit of the peace.\n\ +For this time, all the rest depart away:\n\ +You Capulet; shall go along with me:\n\ +And, Montague, come you this afternoon,\n\ +To know our further pleasure in this case,\n\ +To old Free-town, our common judgment-place.\n\ +Once more, on pain of death, all men depart." + +for (var i = 0; i <4; i++) { + plainText += plainText; +} + +var md5Output = hex_md5(plainText); +assertEq(md5Output, "a831e91e0f70eddcb70dc61c6f82f6cd") diff --git a/js/src/jit-test/tests/sunspider/check-crypto-sha1.js b/js/src/jit-test/tests/sunspider/check-crypto-sha1.js new file mode 100644 index 0000000..d25d5ad --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-crypto-sha1.js @@ -0,0 +1,225 @@ +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined + * in FIPS PUB 180-1 + * Version 2.1a Copyright Paul Johnston 2000 - 2002. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for details. + */ + +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ +var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ + +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));} +function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));} +function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));} +function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));} +function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));} +function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));} + +/* + * Perform a simple self-test to see if the VM is working + */ +function sha1_vm_test() +{ + return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; +} + +/* + * Calculate the SHA-1 of an array of big-endian words, and a bit length + */ +function core_sha1(x, len) +{ + /* append padding */ + x[len >> 5] |= 0x80 << (24 - len % 32); + x[((len + 64 >> 9) << 4) + 15] = len; + + var w = Array(80); + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + var e = -1009589776; + + for(var i = 0; i < x.length; i += 16) + { + var olda = a; + var oldb = b; + var oldc = c; + var oldd = d; + var olde = e; + + for(var j = 0; j < 80; j++) + { + if(j < 16) w[j] = x[i + j]; + else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); + var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), + safe_add(safe_add(e, w[j]), sha1_kt(j))); + e = d; + d = c; + c = rol(b, 30); + b = a; + a = t; + } + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + e = safe_add(e, olde); + } + return Array(a, b, c, d, e); + +} + +/* + * Perform the appropriate triplet combination function for the current + * iteration + */ +function sha1_ft(t, b, c, d) +{ + if(t < 20) return (b & c) | ((~b) & d); + if(t < 40) return b ^ c ^ d; + if(t < 60) return (b & c) | (b & d) | (c & d); + return b ^ c ^ d; +} + +/* + * Determine the appropriate additive constant for the current iteration + */ +function sha1_kt(t) +{ + return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : + (t < 60) ? -1894007588 : -899497514; +} + +/* + * Calculate the HMAC-SHA1 of a key and some data + */ +function core_hmac_sha1(key, data) +{ + var bkey = str2binb(key); + if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz); + + var ipad = Array(16), opad = Array(16); + for(var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); + return core_sha1(opad.concat(hash), 512 + 160); +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +} + +/* + * Convert an 8-bit or 16-bit string to an array of big-endian words + * In 8-bit function, characters >255 have their hi-byte silently ignored. + */ +function str2binb(str) +{ + var bin = Array(); + var mask = (1 << chrsz) - 1; + for(var i = 0; i < str.length * chrsz; i += chrsz) + bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32); + return bin; +} + +/* + * Convert an array of big-endian words to a string + */ +function binb2str(bin) +{ + var str = ""; + var mask = (1 << chrsz) - 1; + for(var i = 0; i < bin.length * 32; i += chrsz) + str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask); + return str; +} + +/* + * Convert an array of big-endian words to a hex string. + */ +function binb2hex(binarray) +{ + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var str = ""; + for(var i = 0; i < binarray.length * 4; i++) + { + str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + + hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); + } + return str; +} + +/* + * Convert an array of big-endian words to a base-64 string + */ +function binb2b64(binarray) +{ + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var str = ""; + for(var i = 0; i < binarray.length * 4; i += 3) + { + var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16) + | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) + | ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF); + for(var j = 0; j < 4; j++) + { + if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; + else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); + } + } + return str; +} + + +var plainText = "Two households, both alike in dignity,\n\ +In fair Verona, where we lay our scene,\n\ +From ancient grudge break to new mutiny,\n\ +Where civil blood makes civil hands unclean.\n\ +From forth the fatal loins of these two foes\n\ +A pair of star-cross'd lovers take their life;\n\ +Whole misadventured piteous overthrows\n\ +Do with their death bury their parents' strife.\n\ +The fearful passage of their death-mark'd love,\n\ +And the continuance of their parents' rage,\n\ +Which, but their children's end, nought could remove,\n\ +Is now the two hours' traffic of our stage;\n\ +The which if you with patient ears attend,\n\ +What here shall miss, our toil shall strive to mend."; + +for (var i = 0; i <4; i++) { + plainText += plainText; +} + +var sha1Output = hex_sha1(plainText); +assertEq(sha1Output, "2524d264def74cce2498bf112bedf00e6c0b796d") diff --git a/js/src/jit-test/tests/sunspider/check-date-format-tofte.js b/js/src/jit-test/tests/sunspider/check-date-format-tofte.js new file mode 100644 index 0000000..1a8bcd1 --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-date-format-tofte.js @@ -0,0 +1,302 @@ +function arrayExists(array, x) { + for (var i = 0; i < array.length; i++) { + if (array[i] == x) return true; + } + return false; +} + +Date.prototype.formatDate = function (input,time) { + // formatDate : + // a PHP date like function, for formatting date strings + // See: http://www.php.net/date + // + // input : format string + // time : epoch time (seconds, and optional) + // + // if time is not passed, formatting is based on + // the current "this" date object's set time. + // + // supported: + // a, A, B, d, D, F, g, G, h, H, i, j, l (lowercase L), L, + // m, M, n, O, r, s, S, t, U, w, W, y, Y, z + // + // unsupported: + // I (capital i), T, Z + + var switches = ["a", "A", "B", "d", "D", "F", "g", "G", "h", "H", + "i", "j", "l", "L", "m", "M", "n", "O", "r", "s", + "S", "t", "U", "w", "W", "y", "Y", "z"]; + var daysLong = ["Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday"]; + var daysShort = ["Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat"]; + var monthsShort = ["Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", "Sep", + "Oct", "Nov", "Dec"]; + var monthsLong = ["January", "February", "March", "April", + "May", "June", "July", "August", "September", + "October", "November", "December"]; + var daysSuffix = ["st", "nd", "rd", "th", "th", "th", "th", // 1st - 7th + "th", "th", "th", "th", "th", "th", "th", // 8th - 14th + "th", "th", "th", "th", "th", "th", "st", // 15th - 21st + "nd", "rd", "th", "th", "th", "th", "th", // 22nd - 28th + "th", "th", "st"]; // 29th - 31st + + function a() { + // Lowercase Ante meridiem and Post meridiem + return self.getHours() > 11? "pm" : "am"; + } + function A() { + // Uppercase Ante meridiem and Post meridiem + return self.getHours() > 11? "PM" : "AM"; + } + + function B(){ + // Swatch internet time. code simply grabbed from ppk, + // since I was feeling lazy: + // http://www.xs4all.nl/~ppk/js/beat.html + var off = (self.getTimezoneOffset() + 60)*60; + var theSeconds = (self.getHours() * 3600) + + (self.getMinutes() * 60) + + self.getSeconds() + off; + var beat = Math.floor(theSeconds/86.4); + if (beat > 1000) beat -= 1000; + if (beat < 0) beat += 1000; + if ((""+beat).length == 1) beat = "00"+beat; + if ((""+beat).length == 2) beat = "0"+beat; + return beat; + } + + function d() { + // Day of the month, 2 digits with leading zeros + return new String(self.getDate()).length == 1? + "0"+self.getDate() : self.getDate(); + } + function D() { + // A textual representation of a day, three letters + return daysShort[self.getDay()]; + } + function F() { + // A full textual representation of a month + return monthsLong[self.getMonth()]; + } + function g() { + // 12-hour format of an hour without leading zeros + return self.getHours() > 12? self.getHours()-12 : self.getHours(); + } + function G() { + // 24-hour format of an hour without leading zeros + return self.getHours(); + } + function h() { + // 12-hour format of an hour with leading zeros + if (self.getHours() > 12) { + var s = new String(self.getHours()-12); + return s.length == 1? + "0"+ (self.getHours()-12) : self.getHours()-12; + } else { + var s = new String(self.getHours()); + return s.length == 1? + "0"+self.getHours() : self.getHours(); + } + } + function H() { + // 24-hour format of an hour with leading zeros + return new String(self.getHours()).length == 1? + "0"+self.getHours() : self.getHours(); + } + function i() { + // Minutes with leading zeros + return new String(self.getMinutes()).length == 1? + "0"+self.getMinutes() : self.getMinutes(); + } + function j() { + // Day of the month without leading zeros + return self.getDate(); + } + function l() { + // A full textual representation of the day of the week + return daysLong[self.getDay()]; + } + function L() { + // leap year or not. 1 if leap year, 0 if not. + // the logic should match iso's 8601 standard. + var y_ = Y(); + if ( + (y_ % 4 == 0 && y_ % 100 != 0) || + (y_ % 4 == 0 && y_ % 100 == 0 && y_ % 400 == 0) + ) { + return 1; + } else { + return 0; + } + } + function m() { + // Numeric representation of a month, with leading zeros + return self.getMonth() < 9? + "0"+(self.getMonth()+1) : + self.getMonth()+1; + } + function M() { + // A short textual representation of a month, three letters + return monthsShort[self.getMonth()]; + } + function n() { + // Numeric representation of a month, without leading zeros + return self.getMonth()+1; + } + function O() { + // Difference to Greenwich time (GMT) in hours + var os = Math.abs(self.getTimezoneOffset()); + var h = ""+Math.floor(os/60); + var m = ""+(os%60); + h.length == 1? h = "0"+h:1; + m.length == 1? m = "0"+m:1; + return self.getTimezoneOffset() < 0 ? "+"+h+m : "-"+h+m; + } + function r() { + // RFC 822 formatted date + var r; // result + // Thu , 21 Dec 2000 + r = D() + ", " + j() + " " + M() + " " + Y() + + // 16 : 01 : 07 +0200 + " " + H() + ":" + i() + ":" + s() + " " + O(); + return r; + } + function S() { + // English ordinal suffix for the day of the month, 2 characters + return daysSuffix[self.getDate()-1]; + } + function s() { + // Seconds, with leading zeros + return new String(self.getSeconds()).length == 1? + "0"+self.getSeconds() : self.getSeconds(); + } + function t() { + + // thanks to Matt Bannon for some much needed code-fixes here! + var daysinmonths = [null,31,28,31,30,31,30,31,31,30,31,30,31]; + if (L()==1 && n()==2) return 29; // leap day + return daysinmonths[n()]; + } + function U() { + // Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) + return Math.round(self.getTime()/1000); + } + function W() { + // Weeknumber, as per ISO specification: + // http://www.cl.cam.ac.uk/~mgk25/iso-time.html + + // if the day is three days before newyears eve, + // there's a chance it's "week 1" of next year. + // here we check for that. + var beforeNY = 364+L() - z(); + var afterNY = z(); + var weekday = w()!=0?w()-1:6; // makes sunday (0), into 6. + if (beforeNY <= 2 && weekday <= 2-beforeNY) { + return 1; + } + // similarly, if the day is within threedays of newyears + // there's a chance it belongs in the old year. + var ny = new Date("January 1 " + Y() + " 00:00:00"); + var nyDay = ny.getDay()!=0?ny.getDay()-1:6; + if ( + (afterNY <= 2) && + (nyDay >=4) && + (afterNY >= (6-nyDay)) + ) { + // Since I'm not sure we can just always return 53, + // i call the function here again, using the last day + // of the previous year, as the date, and then just + // return that week. + var prevNY = new Date("December 31 " + (Y()-1) + " 00:00:00"); + return prevNY.formatDate("W"); + } + + // week 1, is the week that has the first thursday in it. + // note that this value is not zero index. + if (nyDay <= 3) { + // first day of the year fell on a thursday, or earlier. + return 1 + Math.floor( ( z() + nyDay ) / 7 ); + } else { + // first day of the year fell on a friday, or later. + return 1 + Math.floor( ( z() - ( 7 - nyDay ) ) / 7 ); + } + } + function w() { + // Numeric representation of the day of the week + return self.getDay(); + } + + function Y() { + // A full numeric representation of a year, 4 digits + + // we first check, if getFullYear is supported. if it + // is, we just use that. ppks code is nice, but wont + // work with dates outside 1900-2038, or something like that + if (self.getFullYear) { + var newDate = new Date("January 1 2001 00:00:00 +0000"); + var x = newDate .getFullYear(); + if (x == 2001) { + // i trust the method now + return self.getFullYear(); + } + } + // else, do this: + // codes thanks to ppk: + // http://www.xs4all.nl/~ppk/js/introdate.html + var x = self.getYear(); + var y = x % 100; + y += (y < 38) ? 2000 : 1900; + return y; + } + function y() { + // A two-digit representation of a year + var y = Y()+""; + return y.substring(y.length-2,y.length); + } + function z() { + // The day of the year, zero indexed! 0 through 366 + var t = new Date("January 1 " + Y() + " 00:00:00"); + var diff = self.getTime() - t.getTime(); + return Math.floor(diff/1000/60/60/24); + } + + var self = this; + if (time) { + // save time + var prevTime = self.getTime(); + self.setTime(time); + } + + var ia = input.split(""); + var ij = 0; + while (ia[ij]) { + if (ia[ij] == "\\") { + // this is our way of allowing users to escape stuff + ia.splice(ij,1); + } else { + if (arrayExists(switches,ia[ij])) { + ia[ij] = eval(ia[ij] + "()"); + } + } + ij++; + } + // reset time, back to what it was + if (prevTime) { + self.setTime(prevTime); + } + return ia.join(""); +} + +var date = new Date("1/1/2007 1:11:11"); + +var ret = ""; +for (i = 0; i < 500; ++i) { + var shortFormat = date.formatDate("Y-m-d"); + var longFormat = date.formatDate("l, F d, Y g:i:s A"); + ret += shortFormat + longFormat; + date.setTime(date.getTime() + 84266956); +} +var expected = "2007-01-01Monday, January 01, 2007 1:11:11 AM2007-01-02Tuesday, January 02, 2007 0:35:37 AM2007-01-03Wednesday, January 03, 2007 0:00:04 AM2007-01-03Wednesday, January 03, 2007 11:24:31 PM2007-01-04Thursday, January 04, 2007 10:48:58 PM2007-01-05Friday, January 05, 2007 10:13:25 PM2007-01-06Saturday, January 06, 2007 9:37:52 PM2007-01-07Sunday, January 07, 2007 9:02:19 PM2007-01-08Monday, January 08, 2007 8:26:46 PM2007-01-09Tuesday, January 09, 2007 7:51:13 PM2007-01-10Wednesday, January 10, 2007 7:15:40 PM2007-01-11Thursday, January 11, 2007 6:40:07 PM2007-01-12Friday, January 12, 2007 6:04:34 PM2007-01-13Saturday, January 13, 2007 5:29:01 PM2007-01-14Sunday, January 14, 2007 4:53:28 PM2007-01-15Monday, January 15, 2007 4:17:55 PM2007-01-16Tuesday, January 16, 2007 3:42:22 PM2007-01-17Wednesday, January 17, 2007 3:06:49 PM2007-01-18Thursday, January 18, 2007 2:31:16 PM2007-01-19Friday, January 19, 2007 1:55:43 PM2007-01-20Saturday, January 20, 2007 1:20:10 PM2007-01-21Sunday, January 21, 2007 12:44:37 PM2007-01-22Monday, January 22, 2007 12:09:04 PM2007-01-23Tuesday, January 23, 2007 11:33:30 AM2007-01-24Wednesday, January 24, 2007 10:57:57 AM2007-01-25Thursday, January 25, 2007 10:22:24 AM2007-01-26Friday, January 26, 2007 9:46:51 AM2007-01-27Saturday, January 27, 2007 9:11:18 AM2007-01-28Sunday, January 28, 2007 8:35:45 AM2007-01-29Monday, January 29, 2007 8:00:12 AM2007-01-30Tuesday, January 30, 2007 7:24:39 AM2007-01-31Wednesday, January 31, 2007 6:49:06 AM2007-02-01Thursday, February 01, 2007 6:13:33 AM2007-02-02Friday, February 02, 2007 5:38:00 AM2007-02-03Saturday, February 03, 2007 5:02:27 AM2007-02-04Sunday, February 04, 2007 4:26:54 AM2007-02-05Monday, February 05, 2007 3:51:21 AM2007-02-06Tuesday, February 06, 2007 3:15:48 AM2007-02-07Wednesday, February 07, 2007 2:40:15 AM2007-02-08Thursday, February 08, 2007 2:04:42 AM2007-02-09Friday, February 09, 2007 1:29:09 AM2007-02-10Saturday, February 10, 2007 0:53:36 AM2007-02-11Sunday, February 11, 2007 0:18:03 AM2007-02-11Sunday, February 11, 2007 11:42:30 PM2007-02-12Monday, February 12, 2007 11:06:57 PM2007-02-13Tuesday, February 13, 2007 10:31:24 PM2007-02-14Wednesday, February 14, 2007 9:55:50 PM2007-02-15Thursday, February 15, 2007 9:20:17 PM2007-02-16Friday, February 16, 2007 8:44:44 PM2007-02-17Saturday, February 17, 2007 8:09:11 PM2007-02-18Sunday, February 18, 2007 7:33:38 PM2007-02-19Monday, February 19, 2007 6:58:05 PM2007-02-20Tuesday, February 20, 2007 6:22:32 PM2007-02-21Wednesday, February 21, 2007 5:46:59 PM2007-02-22Thursday, February 22, 2007 5:11:26 PM2007-02-23Friday, February 23, 2007 4:35:53 PM2007-02-24Saturday, February 24, 2007 4:00:20 PM2007-02-25Sunday, February 25, 2007 3:24:47 PM2007-02-26Monday, February 26, 2007 2:49:14 PM2007-02-27Tuesday, February 27, 2007 2:13:41 PM2007-02-28Wednesday, February 28, 2007 1:38:08 PM2007-03-01Thursday, March 01, 2007 1:02:35 PM2007-03-02Friday, March 02, 2007 12:27:02 PM2007-03-03Saturday, March 03, 2007 11:51:29 AM2007-03-04Sunday, March 04, 2007 11:15:56 AM2007-03-05Monday, March 05, 2007 10:40:23 AM2007-03-06Tuesday, March 06, 2007 10:04:50 AM2007-03-07Wednesday, March 07, 2007 9:29:17 AM2007-03-08Thursday, March 08, 2007 8:53:44 AM2007-03-09Friday, March 09, 2007 8:18:10 AM2007-03-10Saturday, March 10, 2007 7:42:37 AM2007-03-11Sunday, March 11, 2007 8:07:04 AM2007-03-12Monday, March 12, 2007 7:31:31 AM2007-03-13Tuesday, March 13, 2007 6:55:58 AM2007-03-14Wednesday, March 14, 2007 6:20:25 AM2007-03-15Thursday, March 15, 2007 5:44:52 AM2007-03-16Friday, March 16, 2007 5:09:19 AM2007-03-17Saturday, March 17, 2007 4:33:46 AM2007-03-18Sunday, March 18, 2007 3:58:13 AM2007-03-19Monday, March 19, 2007 3:22:40 AM2007-03-20Tuesday, March 20, 2007 2:47:07 AM2007-03-21Wednesday, March 21, 2007 2:11:34 AM2007-03-22Thursday, March 22, 2007 1:36:01 AM2007-03-23Friday, March 23, 2007 1:00:28 AM2007-03-24Saturday, March 24, 2007 0:24:55 AM2007-03-24Saturday, March 24, 2007 11:49:22 PM2007-03-25Sunday, March 25, 2007 11:13:49 PM2007-03-26Monday, March 26, 2007 10:38:16 PM2007-03-27Tuesday, March 27, 2007 10:02:43 PM2007-03-28Wednesday, March 28, 2007 9:27:10 PM2007-03-29Thursday, March 29, 2007 8:51:37 PM2007-03-30Friday, March 30, 2007 8:16:03 PM2007-03-31Saturday, March 31, 2007 7:40:30 PM2007-04-01Sunday, April 01, 2007 7:04:57 PM2007-04-02Monday, April 02, 2007 6:29:24 PM2007-04-03Tuesday, April 03, 2007 5:53:51 PM2007-04-04Wednesday, April 04, 2007 5:18:18 PM2007-04-05Thursday, April 05, 2007 4:42:45 PM2007-04-06Friday, April 06, 2007 4:07:12 PM2007-04-07Saturday, April 07, 2007 3:31:39 PM2007-04-08Sunday, April 08, 2007 2:56:06 PM2007-04-09Monday, April 09, 2007 2:20:33 PM2007-04-10Tuesday, April 10, 2007 1:45:00 PM2007-04-11Wednesday, April 11, 2007 1:09:27 PM2007-04-12Thursday, April 12, 2007 12:33:54 PM2007-04-13Friday, April 13, 2007 11:58:21 AM2007-04-14Saturday, April 14, 2007 11:22:48 AM2007-04-15Sunday, April 15, 2007 10:47:15 AM2007-04-16Monday, April 16, 2007 10:11:42 AM2007-04-17Tuesday, April 17, 2007 9:36:09 AM2007-04-18Wednesday, April 18, 2007 9:00:36 AM2007-04-19Thursday, April 19, 2007 8:25:03 AM2007-04-20Friday, April 20, 2007 7:49:30 AM2007-04-21Saturday, April 21, 2007 7:13:57 AM2007-04-22Sunday, April 22, 2007 6:38:23 AM2007-04-23Monday, April 23, 2007 6:02:50 AM2007-04-24Tuesday, April 24, 2007 5:27:17 AM2007-04-25Wednesday, April 25, 2007 4:51:44 AM2007-04-26Thursday, April 26, 2007 4:16:11 AM2007-04-27Friday, April 27, 2007 3:40:38 AM2007-04-28Saturday, April 28, 2007 3:05:05 AM2007-04-29Sunday, April 29, 2007 2:29:32 AM2007-04-30Monday, April 30, 2007 1:53:59 AM2007-05-01Tuesday, May 01, 2007 1:18:26 AM2007-05-02Wednesday, May 02, 2007 0:42:53 AM2007-05-03Thursday, May 03, 2007 0:07:20 AM2007-05-03Thursday, May 03, 2007 11:31:47 PM2007-05-04Friday, May 04, 2007 10:56:14 PM2007-05-05Saturday, May 05, 2007 10:20:41 PM2007-05-06Sunday, May 06, 2007 9:45:08 PM2007-05-07Monday, May 07, 2007 9:09:35 PM2007-05-08Tuesday, May 08, 2007 8:34:02 PM2007-05-09Wednesday, May 09, 2007 7:58:29 PM2007-05-10Thursday, May 10, 2007 7:22:56 PM2007-05-11Friday, May 11, 2007 6:47:23 PM2007-05-12Saturday, May 12, 2007 6:11:50 PM2007-05-13Sunday, May 13, 2007 5:36:17 PM2007-05-14Monday, May 14, 2007 5:00:43 PM2007-05-15Tuesday, May 15, 2007 4:25:10 PM2007-05-16Wednesday, May 16, 2007 3:49:37 PM2007-05-17Thursday, May 17, 2007 3:14:04 PM2007-05-18Friday, May 18, 2007 2:38:31 PM2007-05-19Saturday, May 19, 2007 2:02:58 PM2007-05-20Sunday, May 20, 2007 1:27:25 PM2007-05-21Monday, May 21, 2007 12:51:52 PM2007-05-22Tuesday, May 22, 2007 12:16:19 PM2007-05-23Wednesday, May 23, 2007 11:40:46 AM2007-05-24Thursday, May 24, 2007 11:05:13 AM2007-05-25Friday, May 25, 2007 10:29:40 AM2007-05-26Saturday, May 26, 2007 9:54:07 AM2007-05-27Sunday, May 27, 2007 9:18:34 AM2007-05-28Monday, May 28, 2007 8:43:01 AM2007-05-29Tuesday, May 29, 2007 8:07:28 AM2007-05-30Wednesday, May 30, 2007 7:31:55 AM2007-05-31Thursday, May 31, 2007 6:56:22 AM2007-06-01Friday, June 01, 2007 6:20:49 AM2007-06-02Saturday, June 02, 2007 5:45:16 AM2007-06-03Sunday, June 03, 2007 5:09:43 AM2007-06-04Monday, June 04, 2007 4:34:10 AM2007-06-05Tuesday, June 05, 2007 3:58:37 AM2007-06-06Wednesday, June 06, 2007 3:23:03 AM2007-06-07Thursday, June 07, 2007 2:47:30 AM2007-06-08Friday, June 08, 2007 2:11:57 AM2007-06-09Saturday, June 09, 2007 1:36:24 AM2007-06-10Sunday, June 10, 2007 1:00:51 AM2007-06-11Monday, June 11, 2007 0:25:18 AM2007-06-11Monday, June 11, 2007 11:49:45 PM2007-06-12Tuesday, June 12, 2007 11:14:12 PM2007-06-13Wednesday, June 13, 2007 10:38:39 PM2007-06-14Thursday, June 14, 2007 10:03:06 PM2007-06-15Friday, June 15, 2007 9:27:33 PM2007-06-16Saturday, June 16, 2007 8:52:00 PM2007-06-17Sunday, June 17, 2007 8:16:27 PM2007-06-18Monday, June 18, 2007 7:40:54 PM2007-06-19Tuesday, June 19, 2007 7:05:21 PM2007-06-20Wednesday, June 20, 2007 6:29:48 PM2007-06-21Thursday, June 21, 2007 5:54:15 PM2007-06-22Friday, June 22, 2007 5:18:42 PM2007-06-23Saturday, June 23, 2007 4:43:09 PM2007-06-24Sunday, June 24, 2007 4:07:36 PM2007-06-25Monday, June 25, 2007 3:32:03 PM2007-06-26Tuesday, June 26, 2007 2:56:30 PM2007-06-27Wednesday, June 27, 2007 2:20:56 PM2007-06-28Thursday, June 28, 2007 1:45:23 PM2007-06-29Friday, June 29, 2007 1:09:50 PM2007-06-30Saturday, June 30, 2007 12:34:17 PM2007-07-01Sunday, July 01, 2007 11:58:44 AM2007-07-02Monday, July 02, 2007 11:23:11 AM2007-07-03Tuesday, July 03, 2007 10:47:38 AM2007-07-04Wednesday, July 04, 2007 10:12:05 AM2007-07-05Thursday, July 05, 2007 9:36:32 AM2007-07-06Friday, July 06, 2007 9:00:59 AM2007-07-07Saturday, July 07, 2007 8:25:26 AM2007-07-08Sunday, July 08, 2007 7:49:53 AM2007-07-09Monday, July 09, 2007 7:14:20 AM2007-07-10Tuesday, July 10, 2007 6:38:47 AM2007-07-11Wednesday, July 11, 2007 6:03:14 AM2007-07-12Thursday, July 12, 2007 5:27:41 AM2007-07-13Friday, July 13, 2007 4:52:08 AM2007-07-14Saturday, July 14, 2007 4:16:35 AM2007-07-15Sunday, July 15, 2007 3:41:02 AM2007-07-16Monday, July 16, 2007 3:05:29 AM2007-07-17Tuesday, July 17, 2007 2:29:56 AM2007-07-18Wednesday, July 18, 2007 1:54:23 AM2007-07-19Thursday, July 19, 2007 1:18:50 AM2007-07-20Friday, July 20, 2007 0:43:16 AM2007-07-21Saturday, July 21, 2007 0:07:43 AM2007-07-21Saturday, July 21, 2007 11:32:10 PM2007-07-22Sunday, July 22, 2007 10:56:37 PM2007-07-23Monday, July 23, 2007 10:21:04 PM2007-07-24Tuesday, July 24, 2007 9:45:31 PM2007-07-25Wednesday, July 25, 2007 9:09:58 PM2007-07-26Thursday, July 26, 2007 8:34:25 PM2007-07-27Friday, July 27, 2007 7:58:52 PM2007-07-28Saturday, July 28, 2007 7:23:19 PM2007-07-29Sunday, July 29, 2007 6:47:46 PM2007-07-30Monday, July 30, 2007 6:12:13 PM2007-07-31Tuesday, July 31, 2007 5:36:40 PM2007-08-01Wednesday, August 01, 2007 5:01:07 PM2007-08-02Thursday, August 02, 2007 4:25:34 PM2007-08-03Friday, August 03, 2007 3:50:01 PM2007-08-04Saturday, August 04, 2007 3:14:28 PM2007-08-05Sunday, August 05, 2007 2:38:55 PM2007-08-06Monday, August 06, 2007 2:03:22 PM2007-08-07Tuesday, August 07, 2007 1:27:49 PM2007-08-08Wednesday, August 08, 2007 12:52:16 PM2007-08-09Thursday, August 09, 2007 12:16:43 PM2007-08-10Friday, August 10, 2007 11:41:10 AM2007-08-11Saturday, August 11, 2007 11:05:36 AM2007-08-12Sunday, August 12, 2007 10:30:03 AM2007-08-13Monday, August 13, 2007 9:54:30 AM2007-08-14Tuesday, August 14, 2007 9:18:57 AM2007-08-15Wednesday, August 15, 2007 8:43:24 AM2007-08-16Thursday, August 16, 2007 8:07:51 AM2007-08-17Friday, August 17, 2007 7:32:18 AM2007-08-18Saturday, August 18, 2007 6:56:45 AM2007-08-19Sunday, August 19, 2007 6:21:12 AM2007-08-20Monday, August 20, 2007 5:45:39 AM2007-08-21Tuesday, August 21, 2007 5:10:06 AM2007-08-22Wednesday, August 22, 2007 4:34:33 AM2007-08-23Thursday, August 23, 2007 3:59:00 AM2007-08-24Friday, August 24, 2007 3:23:27 AM2007-08-25Saturday, August 25, 2007 2:47:54 AM2007-08-26Sunday, August 26, 2007 2:12:21 AM2007-08-27Monday, August 27, 2007 1:36:48 AM2007-08-28Tuesday, August 28, 2007 1:01:15 AM2007-08-29Wednesday, August 29, 2007 0:25:42 AM2007-08-29Wednesday, August 29, 2007 11:50:09 PM2007-08-30Thursday, August 30, 2007 11:14:36 PM2007-08-31Friday, August 31, 2007 10:39:03 PM2007-09-01Saturday, September 01, 2007 10:03:30 PM2007-09-02Sunday, September 02, 2007 9:27:56 PM2007-09-03Monday, September 03, 2007 8:52:23 PM2007-09-04Tuesday, September 04, 2007 8:16:50 PM2007-09-05Wednesday, September 05, 2007 7:41:17 PM2007-09-06Thursday, September 06, 2007 7:05:44 PM2007-09-07Friday, September 07, 2007 6:30:11 PM2007-09-08Saturday, September 08, 2007 5:54:38 PM2007-09-09Sunday, September 09, 2007 5:19:05 PM2007-09-10Monday, September 10, 2007 4:43:32 PM2007-09-11Tuesday, September 11, 2007 4:07:59 PM2007-09-12Wednesday, September 12, 2007 3:32:26 PM2007-09-13Thursday, September 13, 2007 2:56:53 PM2007-09-14Friday, September 14, 2007 2:21:20 PM2007-09-15Saturday, September 15, 2007 1:45:47 PM2007-09-16Sunday, September 16, 2007 1:10:14 PM2007-09-17Monday, September 17, 2007 12:34:41 PM2007-09-18Tuesday, September 18, 2007 11:59:08 AM2007-09-19Wednesday, September 19, 2007 11:23:35 AM2007-09-20Thursday, September 20, 2007 10:48:02 AM2007-09-21Friday, September 21, 2007 10:12:29 AM2007-09-22Saturday, September 22, 2007 9:36:56 AM2007-09-23Sunday, September 23, 2007 9:01:23 AM2007-09-24Monday, September 24, 2007 8:25:49 AM2007-09-25Tuesday, September 25, 2007 7:50:16 AM2007-09-26Wednesday, September 26, 2007 7:14:43 AM2007-09-27Thursday, September 27, 2007 6:39:10 AM2007-09-28Friday, September 28, 2007 6:03:37 AM2007-09-29Saturday, September 29, 2007 5:28:04 AM2007-09-30Sunday, September 30, 2007 4:52:31 AM2007-10-01Monday, October 01, 2007 4:16:58 AM2007-10-02Tuesday, October 02, 2007 3:41:25 AM2007-10-03Wednesday, October 03, 2007 3:05:52 AM2007-10-04Thursday, October 04, 2007 2:30:19 AM2007-10-05Friday, October 05, 2007 1:54:46 AM2007-10-06Saturday, October 06, 2007 1:19:13 AM2007-10-07Sunday, October 07, 2007 0:43:40 AM2007-10-08Monday, October 08, 2007 0:08:07 AM2007-10-08Monday, October 08, 2007 11:32:34 PM2007-10-09Tuesday, October 09, 2007 10:57:01 PM2007-10-10Wednesday, October 10, 2007 10:21:28 PM2007-10-11Thursday, October 11, 2007 9:45:55 PM2007-10-12Friday, October 12, 2007 9:10:22 PM2007-10-13Saturday, October 13, 2007 8:34:49 PM2007-10-14Sunday, October 14, 2007 7:59:16 PM2007-10-15Monday, October 15, 2007 7:23:43 PM2007-10-16Tuesday, October 16, 2007 6:48:09 PM2007-10-17Wednesday, October 17, 2007 6:12:36 PM2007-10-18Thursday, October 18, 2007 5:37:03 PM2007-10-19Friday, October 19, 2007 5:01:30 PM2007-10-20Saturday, October 20, 2007 4:25:57 PM2007-10-21Sunday, October 21, 2007 3:50:24 PM2007-10-22Monday, October 22, 2007 3:14:51 PM2007-10-23Tuesday, October 23, 2007 2:39:18 PM2007-10-24Wednesday, October 24, 2007 2:03:45 PM2007-10-25Thursday, October 25, 2007 1:28:12 PM2007-10-26Friday, October 26, 2007 12:52:39 PM2007-10-27Saturday, October 27, 2007 12:17:06 PM2007-10-28Sunday, October 28, 2007 11:41:33 AM2007-10-29Monday, October 29, 2007 11:06:00 AM2007-10-30Tuesday, October 30, 2007 10:30:27 AM2007-10-31Wednesday, October 31, 2007 9:54:54 AM2007-11-01Thursday, November 01, 2007 9:19:21 AM2007-11-02Friday, November 02, 2007 8:43:48 AM2007-11-03Saturday, November 03, 2007 8:08:15 AM2007-11-04Sunday, November 04, 2007 6:32:42 AM2007-11-05Monday, November 05, 2007 5:57:09 AM2007-11-06Tuesday, November 06, 2007 5:21:36 AM2007-11-07Wednesday, November 07, 2007 4:46:03 AM2007-11-08Thursday, November 08, 2007 4:10:29 AM2007-11-09Friday, November 09, 2007 3:34:56 AM2007-11-10Saturday, November 10, 2007 2:59:23 AM2007-11-11Sunday, November 11, 2007 2:23:50 AM2007-11-12Monday, November 12, 2007 1:48:17 AM2007-11-13Tuesday, November 13, 2007 1:12:44 AM2007-11-14Wednesday, November 14, 2007 0:37:11 AM2007-11-15Thursday, November 15, 2007 0:01:38 AM2007-11-15Thursday, November 15, 2007 11:26:05 PM2007-11-16Friday, November 16, 2007 10:50:32 PM2007-11-17Saturday, November 17, 2007 10:14:59 PM2007-11-18Sunday, November 18, 2007 9:39:26 PM2007-11-19Monday, November 19, 2007 9:03:53 PM2007-11-20Tuesday, November 20, 2007 8:28:20 PM2007-11-21Wednesday, November 21, 2007 7:52:47 PM2007-11-22Thursday, November 22, 2007 7:17:14 PM2007-11-23Friday, November 23, 2007 6:41:41 PM2007-11-24Saturday, November 24, 2007 6:06:08 PM2007-11-25Sunday, November 25, 2007 5:30:35 PM2007-11-26Monday, November 26, 2007 4:55:02 PM2007-11-27Tuesday, November 27, 2007 4:19:29 PM2007-11-28Wednesday, November 28, 2007 3:43:56 PM2007-11-29Thursday, November 29, 2007 3:08:22 PM2007-11-30Friday, November 30, 2007 2:32:49 PM2007-12-01Saturday, December 01, 2007 1:57:16 PM2007-12-02Sunday, December 02, 2007 1:21:43 PM2007-12-03Monday, December 03, 2007 12:46:10 PM2007-12-04Tuesday, December 04, 2007 12:10:37 PM2007-12-05Wednesday, December 05, 2007 11:35:04 AM2007-12-06Thursday, December 06, 2007 10:59:31 AM2007-12-07Friday, December 07, 2007 10:23:58 AM2007-12-08Saturday, December 08, 2007 9:48:25 AM2007-12-09Sunday, December 09, 2007 9:12:52 AM2007-12-10Monday, December 10, 2007 8:37:19 AM2007-12-11Tuesday, December 11, 2007 8:01:46 AM2007-12-12Wednesday, December 12, 2007 7:26:13 AM2007-12-13Thursday, December 13, 2007 6:50:40 AM2007-12-14Friday, December 14, 2007 6:15:07 AM2007-12-15Saturday, December 15, 2007 5:39:34 AM2007-12-16Sunday, December 16, 2007 5:04:01 AM2007-12-17Monday, December 17, 2007 4:28:28 AM2007-12-18Tuesday, December 18, 2007 3:52:55 AM2007-12-19Wednesday, December 19, 2007 3:17:22 AM2007-12-20Thursday, December 20, 2007 2:41:49 AM2007-12-21Friday, December 21, 2007 2:06:16 AM2007-12-22Saturday, December 22, 2007 1:30:42 AM2007-12-23Sunday, December 23, 2007 0:55:09 AM2007-12-24Monday, December 24, 2007 0:19:36 AM2007-12-24Monday, December 24, 2007 11:44:03 PM2007-12-25Tuesday, December 25, 2007 11:08:30 PM2007-12-26Wednesday, December 26, 2007 10:32:57 PM2007-12-27Thursday, December 27, 2007 9:57:24 PM2007-12-28Friday, December 28, 2007 9:21:51 PM2007-12-29Saturday, December 29, 2007 8:46:18 PM2007-12-30Sunday, December 30, 2007 8:10:45 PM2007-12-31Monday, December 31, 2007 7:35:12 PM2008-01-01Tuesday, January 01, 2008 6:59:39 PM2008-01-02Wednesday, January 02, 2008 6:24:06 PM2008-01-03Thursday, January 03, 2008 5:48:33 PM2008-01-04Friday, January 04, 2008 5:13:00 PM2008-01-05Saturday, January 05, 2008 4:37:27 PM2008-01-06Sunday, January 06, 2008 4:01:54 PM2008-01-07Monday, January 07, 2008 3:26:21 PM2008-01-08Tuesday, January 08, 2008 2:50:48 PM2008-01-09Wednesday, January 09, 2008 2:15:15 PM2008-01-10Thursday, January 10, 2008 1:39:42 PM2008-01-11Friday, January 11, 2008 1:04:09 PM2008-01-12Saturday, January 12, 2008 12:28:36 PM2008-01-13Sunday, January 13, 2008 11:53:02 AM2008-01-14Monday, January 14, 2008 11:17:29 AM2008-01-15Tuesday, January 15, 2008 10:41:56 AM2008-01-16Wednesday, January 16, 2008 10:06:23 AM2008-01-17Thursday, January 17, 2008 9:30:50 AM2008-01-18Friday, January 18, 2008 8:55:17 AM2008-01-19Saturday, January 19, 2008 8:19:44 AM2008-01-20Sunday, January 20, 2008 7:44:11 AM2008-01-21Monday, January 21, 2008 7:08:38 AM2008-01-22Tuesday, January 22, 2008 6:33:05 AM2008-01-23Wednesday, January 23, 2008 5:57:32 AM2008-01-24Thursday, January 24, 2008 5:21:59 AM2008-01-25Friday, January 25, 2008 4:46:26 AM2008-01-26Saturday, January 26, 2008 4:10:53 AM2008-01-27Sunday, January 27, 2008 3:35:20 AM2008-01-28Monday, January 28, 2008 2:59:47 AM2008-01-29Tuesday, January 29, 2008 2:24:14 AM2008-01-30Wednesday, January 30, 2008 1:48:41 AM2008-01-31Thursday, January 31, 2008 1:13:08 AM2008-02-01Friday, February 01, 2008 0:37:35 AM2008-02-02Saturday, February 02, 2008 0:02:02 AM2008-02-02Saturday, February 02, 2008 11:26:29 PM2008-02-03Sunday, February 03, 2008 10:50:56 PM2008-02-04Monday, February 04, 2008 10:15:22 PM2008-02-05Tuesday, February 05, 2008 9:39:49 PM2008-02-06Wednesday, February 06, 2008 9:04:16 PM2008-02-07Thursday, February 07, 2008 8:28:43 PM2008-02-08Friday, February 08, 2008 7:53:10 PM2008-02-09Saturday, February 09, 2008 7:17:37 PM2008-02-10Sunday, February 10, 2008 6:42:04 PM2008-02-11Monday, February 11, 2008 6:06:31 PM2008-02-12Tuesday, February 12, 2008 5:30:58 PM2008-02-13Wednesday, February 13, 2008 4:55:25 PM2008-02-14Thursday, February 14, 2008 4:19:52 PM2008-02-15Friday, February 15, 2008 3:44:19 PM2008-02-16Saturday, February 16, 2008 3:08:46 PM2008-02-17Sunday, February 17, 2008 2:33:13 PM2008-02-18Monday, February 18, 2008 1:57:40 PM2008-02-19Tuesday, February 19, 2008 1:22:07 PM2008-02-20Wednesday, February 20, 2008 12:46:34 PM2008-02-21Thursday, February 21, 2008 12:11:01 PM2008-02-22Friday, February 22, 2008 11:35:28 AM2008-02-23Saturday, February 23, 2008 10:59:55 AM2008-02-24Sunday, February 24, 2008 10:24:22 AM2008-02-25Monday, February 25, 2008 9:48:49 AM2008-02-26Tuesday, February 26, 2008 9:13:15 AM2008-02-27Wednesday, February 27, 2008 8:37:42 AM2008-02-28Thursday, February 28, 2008 8:02:09 AM2008-02-29Friday, February 29, 2008 7:26:36 AM2008-03-01Saturday, March 01, 2008 6:51:03 AM2008-03-02Sunday, March 02, 2008 6:15:30 AM2008-03-03Monday, March 03, 2008 5:39:57 AM2008-03-04Tuesday, March 04, 2008 5:04:24 AM2008-03-05Wednesday, March 05, 2008 4:28:51 AM2008-03-06Thursday, March 06, 2008 3:53:18 AM2008-03-07Friday, March 07, 2008 3:17:45 AM2008-03-08Saturday, March 08, 2008 2:42:12 AM2008-03-09Sunday, March 09, 2008 3:06:39 AM2008-03-10Monday, March 10, 2008 2:31:06 AM2008-03-11Tuesday, March 11, 2008 1:55:33 AM2008-03-12Wednesday, March 12, 2008 1:20:00 AM2008-03-13Thursday, March 13, 2008 0:44:27 AM2008-03-14Friday, March 14, 2008 0:08:54 AM2008-03-14Friday, March 14, 2008 11:33:21 PM2008-03-15Saturday, March 15, 2008 10:57:48 PM2008-03-16Sunday, March 16, 2008 10:22:15 PM2008-03-17Monday, March 17, 2008 9:46:42 PM2008-03-18Tuesday, March 18, 2008 9:11:09 PM2008-03-19Wednesday, March 19, 2008 8:35:35 PM2008-03-20Thursday, March 20, 2008 8:00:02 PM2008-03-21Friday, March 21, 2008 7:24:29 PM2008-03-22Saturday, March 22, 2008 6:48:56 PM2008-03-23Sunday, March 23, 2008 6:13:23 PM2008-03-24Monday, March 24, 2008 5:37:50 PM2008-03-25Tuesday, March 25, 2008 5:02:17 PM2008-03-26Wednesday, March 26, 2008 4:26:44 PM2008-03-27Thursday, March 27, 2008 3:51:11 PM2008-03-28Friday, March 28, 2008 3:15:38 PM2008-03-29Saturday, March 29, 2008 2:40:05 PM2008-03-30Sunday, March 30, 2008 2:04:32 PM2008-03-31Monday, March 31, 2008 1:28:59 PM2008-04-01Tuesday, April 01, 2008 12:53:26 PM2008-04-02Wednesday, April 02, 2008 12:17:53 PM2008-04-03Thursday, April 03, 2008 11:42:20 AM2008-04-04Friday, April 04, 2008 11:06:47 AM2008-04-05Saturday, April 05, 2008 10:31:14 AM2008-04-06Sunday, April 06, 2008 9:55:41 AM2008-04-07Monday, April 07, 2008 9:20:08 AM2008-04-08Tuesday, April 08, 2008 8:44:35 AM2008-04-09Wednesday, April 09, 2008 8:09:02 AM2008-04-10Thursday, April 10, 2008 7:33:29 AM2008-04-11Friday, April 11, 2008 6:57:55 AM2008-04-12Saturday, April 12, 2008 6:22:22 AM2008-04-13Sunday, April 13, 2008 5:46:49 AM2008-04-14Monday, April 14, 2008 5:11:16 AM2008-04-15Tuesday, April 15, 2008 4:35:43 AM2008-04-16Wednesday, April 16, 2008 4:00:10 AM2008-04-17Thursday, April 17, 2008 3:24:37 AM2008-04-18Friday, April 18, 2008 2:49:04 AM2008-04-19Saturday, April 19, 2008 2:13:31 AM2008-04-20Sunday, April 20, 2008 1:37:58 AM2008-04-21Monday, April 21, 2008 1:02:25 AM2008-04-22Tuesday, April 22, 2008 0:26:52 AM2008-04-22Tuesday, April 22, 2008 11:51:19 PM2008-04-23Wednesday, April 23, 2008 11:15:46 PM2008-04-24Thursday, April 24, 2008 10:40:13 PM2008-04-25Friday, April 25, 2008 10:04:40 PM2008-04-26Saturday, April 26, 2008 9:29:07 PM2008-04-27Sunday, April 27, 2008 8:53:34 PM2008-04-28Monday, April 28, 2008 8:18:01 PM2008-04-29Tuesday, April 29, 2008 7:42:28 PM2008-04-30Wednesday, April 30, 2008 7:06:55 PM2008-05-01Thursday, May 01, 2008 6:31:22 PM" +assertEq(ret, expected); diff --git a/js/src/jit-test/tests/sunspider/check-date-format-xparb.js b/js/src/jit-test/tests/sunspider/check-date-format-xparb.js new file mode 100644 index 0000000..41f44fe --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-date-format-xparb.js @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2004 Baron Schwartz + * + * This program 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, version 2.1. + * + * This program 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. + */ + +Date.parseFunctions = {count:0}; +Date.parseRegexes = []; +Date.formatFunctions = {count:0}; + +Date.prototype.dateFormat = function(format) { + if (Date.formatFunctions[format] == null) { + Date.createNewFormat(format); + } + var func = Date.formatFunctions[format]; + return this[func](); +} + +Date.createNewFormat = function(format) { + var funcName = "format" + Date.formatFunctions.count++; + Date.formatFunctions[format] = funcName; + var code = "Date.prototype." + funcName + " = function(){return "; + var special = false; + var ch = ''; + for (var i = 0; i < format.length; ++i) { + ch = format.charAt(i); + if (!special && ch == "\\") { + special = true; + } + else if (special) { + special = false; + code += "'" + String.escape(ch) + "' + "; + } + else { + code += Date.getFormatCode(ch); + } + } + eval(code.substring(0, code.length - 3) + ";}"); +} + +Date.getFormatCode = function(character) { + switch (character) { + case "d": + return "String.leftPad(this.getDate(), 2, '0') + "; + case "D": + return "Date.dayNames[this.getDay()].substring(0, 3) + "; + case "j": + return "this.getDate() + "; + case "l": + return "Date.dayNames[this.getDay()] + "; + case "S": + return "this.getSuffix() + "; + case "w": + return "this.getDay() + "; + case "z": + return "this.getDayOfYear() + "; + case "W": + return "this.getWeekOfYear() + "; + case "F": + return "Date.monthNames[this.getMonth()] + "; + case "m": + return "String.leftPad(this.getMonth() + 1, 2, '0') + "; + case "M": + return "Date.monthNames[this.getMonth()].substring(0, 3) + "; + case "n": + return "(this.getMonth() + 1) + "; + case "t": + return "this.getDaysInMonth() + "; + case "L": + return "(this.isLeapYear() ? 1 : 0) + "; + case "Y": + return "this.getFullYear() + "; + case "y": + return "('' + this.getFullYear()).substring(2, 4) + "; + case "a": + return "(this.getHours() < 12 ? 'am' : 'pm') + "; + case "A": + return "(this.getHours() < 12 ? 'AM' : 'PM') + "; + case "g": + return "((this.getHours() %12) ? this.getHours() % 12 : 12) + "; + case "G": + return "this.getHours() + "; + case "h": + return "String.leftPad((this.getHours() %12) ? this.getHours() % 12 : 12, 2, '0') + "; + case "H": + return "String.leftPad(this.getHours(), 2, '0') + "; + case "i": + return "String.leftPad(this.getMinutes(), 2, '0') + "; + case "s": + return "String.leftPad(this.getSeconds(), 2, '0') + "; + case "O": + return "this.getGMTOffset() + "; + case "T": + return "this.getTimezone() + "; + case "Z": + return "(this.getTimezoneOffset() * -60) + "; + default: + return "'" + String.escape(character) + "' + "; + } +} + +Date.parseDate = function(input, format) { + if (Date.parseFunctions[format] == null) { + Date.createParser(format); + } + var func = Date.parseFunctions[format]; + return Date[func](input); +} + +Date.createParser = function(format) { + var funcName = "parse" + Date.parseFunctions.count++; + var regexNum = Date.parseRegexes.length; + var currentGroup = 1; + Date.parseFunctions[format] = funcName; + + var code = "Date." + funcName + " = function(input){\n" + + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1;\n" + + "var d = new Date();\n" + + "y = d.getFullYear();\n" + + "m = d.getMonth();\n" + + "d = d.getDate();\n" + + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n" + + "if (results && results.length > 0) {" + var regex = ""; + + var special = false; + var ch = ''; + for (var i = 0; i < format.length; ++i) { + ch = format.charAt(i); + if (!special && ch == "\\") { + special = true; + } + else if (special) { + special = false; + regex += String.escape(ch); + } + else { + obj = Date.formatCodeToRegex(ch, currentGroup); + currentGroup += obj.g; + regex += obj.s; + if (obj.g && obj.c) { + code += obj.c; + } + } + } + + code += "if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n" + + "{return new Date(y, m, d, h, i, s);}\n" + + "else if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n" + + "{return new Date(y, m, d, h, i);}\n" + + "else if (y > 0 && m >= 0 && d > 0 && h >= 0)\n" + + "{return new Date(y, m, d, h);}\n" + + "else if (y > 0 && m >= 0 && d > 0)\n" + + "{return new Date(y, m, d);}\n" + + "else if (y > 0 && m >= 0)\n" + + "{return new Date(y, m);}\n" + + "else if (y > 0)\n" + + "{return new Date(y);}\n" + + "}return null;}"; + + Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$"); + eval(code); +} + +Date.formatCodeToRegex = function(character, currentGroup) { + switch (character) { + case "D": + return {g:0, + c:null, + s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"}; + case "j": + case "d": + return {g:1, + c:"d = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{1,2})"}; + case "l": + return {g:0, + c:null, + s:"(?:" + Date.dayNames.join("|") + ")"}; + case "S": + return {g:0, + c:null, + s:"(?:st|nd|rd|th)"}; + case "w": + return {g:0, + c:null, + s:"\\d"}; + case "z": + return {g:0, + c:null, + s:"(?:\\d{1,3})"}; + case "W": + return {g:0, + c:null, + s:"(?:\\d{2})"}; + case "F": + return {g:1, + c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n", + s:"(" + Date.monthNames.join("|") + ")"}; + case "M": + return {g:1, + c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n", + s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"}; + case "n": + case "m": + return {g:1, + c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n", + s:"(\\d{1,2})"}; + case "t": + return {g:0, + c:null, + s:"\\d{1,2}"}; + case "L": + return {g:0, + c:null, + s:"(?:1|0)"}; + case "Y": + return {g:1, + c:"y = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{4})"}; + case "y": + return {g:1, + c:"var ty = parseInt(results[" + currentGroup + "], 10);\n" + + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n", + s:"(\\d{1,2})"}; + case "a": + return {g:1, + c:"if (results[" + currentGroup + "] == 'am') {\n" + + "if (h == 12) { h = 0; }\n" + + "} else { if (h < 12) { h += 12; }}", + s:"(am|pm)"}; + case "A": + return {g:1, + c:"if (results[" + currentGroup + "] == 'AM') {\n" + + "if (h == 12) { h = 0; }\n" + + "} else { if (h < 12) { h += 12; }}", + s:"(AM|PM)"}; + case "g": + case "G": + case "h": + case "H": + return {g:1, + c:"h = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{1,2})"}; + case "i": + return {g:1, + c:"i = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{2})"}; + case "s": + return {g:1, + c:"s = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{2})"}; + case "O": + return {g:0, + c:null, + s:"[+-]\\d{4}"}; + case "T": + return {g:0, + c:null, + s:"[A-Z]{3}"}; + case "Z": + return {g:0, + c:null, + s:"[+-]\\d{1,5}"}; + default: + return {g:0, + c:null, + s:String.escape(character)}; + } +} + +Date.prototype.getTimezone = function() { + return this.toString().replace( + /^.*? ([A-Z]{3}) [0-9]{4}.*$/, "$1").replace( + /^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, "$1$2$3"); +} + +Date.prototype.getGMTOffset = function() { + return (this.getTimezoneOffset() > 0 ? "-" : "+") + + String.leftPad(Math.floor(this.getTimezoneOffset() / 60), 2, "0") + + String.leftPad(this.getTimezoneOffset() % 60, 2, "0"); +} + +Date.prototype.getDayOfYear = function() { + var num = 0; + Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28; + for (var i = 0; i < this.getMonth(); ++i) { + num += Date.daysInMonth[i]; + } + return num + this.getDate() - 1; +} + +Date.prototype.getWeekOfYear = function() { + // Skip to Thursday of this week + var now = this.getDayOfYear() + (4 - this.getDay()); + // Find the first Thursday of the year + var jan1 = new Date(this.getFullYear(), 0, 1); + var then = (7 - jan1.getDay() + 4); + document.write(then); + return String.leftPad(((now - then) / 7) + 1, 2, "0"); +} + +Date.prototype.isLeapYear = function() { + var year = this.getFullYear(); + return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year))); +} + +Date.prototype.getFirstDayOfMonth = function() { + var day = (this.getDay() - (this.getDate() - 1)) % 7; + return (day < 0) ? (day + 7) : day; +} + +Date.prototype.getLastDayOfMonth = function() { + var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7; + return (day < 0) ? (day + 7) : day; +} + +Date.prototype.getDaysInMonth = function() { + Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28; + return Date.daysInMonth[this.getMonth()]; +} + +Date.prototype.getSuffix = function() { + switch (this.getDate()) { + case 1: + case 21: + case 31: + return "st"; + case 2: + case 22: + return "nd"; + case 3: + case 23: + return "rd"; + default: + return "th"; + } +} + +String.escape = function(string) { + return string.replace(/('|\\)/g, "\\$1"); +} + +String.leftPad = function (val, size, ch) { + var result = new String(val); + if (ch == null) { + ch = " "; + } + while (result.length < size) { + result = ch + result; + } + return result; +} + +Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31]; +Date.monthNames = + ["January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December"]; +Date.dayNames = + ["Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday"]; +Date.y2kYear = 50; +Date.monthNumbers = { + Jan:0, + Feb:1, + Mar:2, + Apr:3, + May:4, + Jun:5, + Jul:6, + Aug:7, + Sep:8, + Oct:9, + Nov:10, + Dec:11}; +Date.patterns = { + ISO8601LongPattern:"Y-m-d H:i:s", + ISO8601ShortPattern:"Y-m-d", + ShortDatePattern: "n/j/Y", + LongDatePattern: "l, F d, Y", + FullDateTimePattern: "l, F d, Y g:i:s A", + MonthDayPattern: "F d", + ShortTimePattern: "g:i A", + LongTimePattern: "g:i:s A", + SortableDateTimePattern: "Y-m-d\\TH:i:s", + UniversalSortableDateTimePattern: "Y-m-d H:i:sO", + YearMonthPattern: "F, Y"}; + +var date = new Date("1/1/2007 1:11:11"); + +var ret; +for (i = 0; i < 4000; ++i) { + var shortFormat = date.dateFormat("Y-m-d"); + var longFormat = date.dateFormat("l, F d, Y g:i:s A"); + ret = shortFormat + longFormat; + date.setTime(date.getTime() + 84266956); +} + +// No exact match because the output depends on the locale's time zone. See bug 524490. +assertEq(/^2017-09-05Tuesday, September 05, 2017 [0-9:]* AM$/.exec(ret) != null, true); diff --git a/js/src/jit-test/tests/sunspider/check-math-cordic.js b/js/src/jit-test/tests/sunspider/check-math-cordic.js new file mode 100644 index 0000000..f1ade3a --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-math-cordic.js @@ -0,0 +1,100 @@ +/* + * Copyright (C) Rich Moore. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/////. Start CORDIC + +var AG_CONST = 0.6072529350; + +function FIXED(X) +{ + return X * 65536.0; +} + +function FLOAT(X) +{ + return X / 65536.0; +} + +function DEG2RAD(X) +{ + return 0.017453 * (X); +} + +var Angles = [ + FIXED(45.0), FIXED(26.565), FIXED(14.0362), FIXED(7.12502), + FIXED(3.57633), FIXED(1.78991), FIXED(0.895174), FIXED(0.447614), + FIXED(0.223811), FIXED(0.111906), FIXED(0.055953), + FIXED(0.027977) + ]; + + +function cordicsincos() { + var X; + var Y; + var TargetAngle; + var CurrAngle; + var Step; + + X = FIXED(AG_CONST); /* AG_CONST * cos(0) */ + Y = 0; /* AG_CONST * sin(0) */ + + TargetAngle = FIXED(28.027); + CurrAngle = 0; + for (Step = 0; Step < 12; Step++) { + var NewX; + if (TargetAngle > CurrAngle) { + NewX = X - (Y >> Step); + Y = (X >> Step) + Y; + X = NewX; + CurrAngle += Angles[Step]; + } else { + NewX = X + (Y >> Step); + Y = -(X >> Step) + Y; + X = NewX; + CurrAngle -= Angles[Step]; + } + } + return CurrAngle; +} + +///// End CORDIC + +function cordic( runs ) { + var actual; + + var start = new Date(); + + for ( var i = 0 ; i < runs ; i++ ) { + actual = cordicsincos(); + } + + var end = new Date(); + + assertEq(actual, 1834995.3515519998) + + return end.getTime() - start.getTime(); +} + +cordic(25000); diff --git a/js/src/jit-test/tests/sunspider/check-math-partial-sums.js b/js/src/jit-test/tests/sunspider/check-math-partial-sums.js new file mode 100644 index 0000000..a908270 --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-math-partial-sums.js @@ -0,0 +1,41 @@ +// The Computer Language Shootout +// http://shootout.alioth.debian.org/ +// contributed by Isaac Gouy + +function partial(n){ + var a1 = a2 = a3 = a4 = a5 = a6 = a7 = a8 = a9 = 0.0; + var twothirds = 2.0/3.0; + var alt = -1.0; + var k2 = k3 = sk = ck = 0.0; + + for (var k = 1; k <= n; k++){ + k2 = k*k; + k3 = k2*k; + sk = Math.sin(k); + ck = Math.cos(k); + alt = -alt; + + a1 += Math.pow(twothirds,k-1); + a2 += Math.pow(k,-0.5); + a3 += 1.0/(k*(k+1.0)); + a4 += 1.0/(k3 * sk*sk); + a5 += 1.0/(k3 * ck*ck); + a6 += 1.0/k; + a7 += 1.0/k2; + a8 += alt/k; + a9 += alt/(2*k -1); + } + + return [ a1, a2, a3, a4, a5, a6, a7, a8, a9 ]; +} + +var actual = []; +for (var i = 1024; i <= 16384; i *= 2) + Array.prototype.push.apply(actual, partial(i)); + +var eps = 1e-12; +var expect = [2.9999999999999987,62.555269219624684,0.9990243902439033,30.174793391263677,42.99468748637077,7.509175672278132,1.6439579810301654,0.6926591377284127,0.785154022830656,2.9999999999999987,89.06036157695789,0.9995119570522216,30.30796333494624,42.99485339033617,8.202078771817716,1.6444459047881168,0.6929030995395857,0.7852760930922243,2.9999999999999987,126.54745783224483,0.999755918965097,30.314167756318135,42.994888939123,8.89510389696629,1.6446899560231332,0.6930251251486118,0.7853371282421086,2.9999999999999987,179.56450569047874,0.9998779445868421,30.314499725429847,42.99489723774016,9.588190046095265,1.644812003986005,0.693086149128997,0.785367645819433,2.9999999999999987,254.54355172132264,0.9999389685688135,30.31451920492601,42.99489939769195,10.281306710008463,1.6448730335545856,0.6931166639131536,0.7853829046083998]; + +assertEq(actual.length, expect.length); +for (var i = 0; i < expect.length; ++i) + assertEq(Math.abs(actual[i] - expect[i]) < eps, true); diff --git a/js/src/jit-test/tests/sunspider/check-math-spectral-norm.js b/js/src/jit-test/tests/sunspider/check-math-spectral-norm.js new file mode 100644 index 0000000..824863c --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-math-spectral-norm.js @@ -0,0 +1,53 @@ +// The Great Computer Language Shootout +// http://shootout.alioth.debian.org/ +// +// contributed by Ian Osgood + +function A(i,j) { + return 1/((i+j)*(i+j+1)/2+i+1); +} + +function Au(u,v) { + for (var i=0; i (1<>=1; //bpe=number of bits in one element of the array representing the bigInt +mask=(1<>=bpe; + } +} + +//is x > y? (x and y both nonnegative) +function greater(x,y) { + var i; + var k=(x.length=0;i--) + if (x[i]>y[i]) + return 1; + else if (x[i]0 && n[kn-1]==0;kn--); //ignore leading zeros of n + for (;ky>0 && y[ky-1]==0;ky--); //ignore leading zeros of y + + copyInt_(sa,0); + + //the following loop consumes 95% of the runtime for randTruePrime_() and powMod_() for large keys + for (i=0; i> bpe; + t=x[i]; + + //do sa=(sa+x[i]*y+ui*n)/b where b=2**bpe + for (j=1;j>=bpe; + } + for (;j>=bpe; + } + sa[j-1]=c & mask; + } + + if (!greater(n,sa)) + sub_(sa,n); + copy_(x,sa); +} + +mont_(x, x, n, np); + +var passed = expected.length == x.length; +for (var i = 0; i < expected.length; i++) { + if (passed) + passed = expected[i] == x[i]; +} +assertEq(passed, true); diff --git a/js/src/jit-test/tests/sunspider/check-regexp-dna.js b/js/src/jit-test/tests/sunspider/check-regexp-dna.js new file mode 100644 index 0000000..08b5421 --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-regexp-dna.js @@ -0,0 +1,1714 @@ +// The Computer Language Shootout +// http://shootout.alioth.debian.org/ +// +// contributed by Jesse Millikan +// Base on the Ruby version by jose fco. gonzalez + +var l; +var dnaInput = ">ONE Homo sapiens alu\n\ +GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA\n\ +TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT\n\ +AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG\n\ +GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG\n\ +CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT\n\ +GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA\n\ +GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA\n\ +TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG\n\ +AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA\n\ +GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT\n\ +AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC\n\ +AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG\n\ +GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC\n\ +CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG\n\ +AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT\n\ +TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA\n\ +TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT\n\ +GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG\n\ +TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT\n\ +CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG\n\ +CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG\n\ +TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA\n\ +CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG\n\ +AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG\n\ +GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC\n\ +TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA\n\ +TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA\n\ +GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT\n\ +GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC\n\ +ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT\n\ +TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC\n\ +CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG\n\ +CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG\n\ +GGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCC\n\ +CAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCT\n\ +GGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGC\n\ +GCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGA\n\ +GGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGA\n\ +GACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGA\n\ +GGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTG\n\ +AAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT\n\ +CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCA\n\ +GTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAA\n\ +AAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGC\n\ +GGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCT\n\ +ACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGG\n\ +GAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATC\n\ +GCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGC\n\ +GGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGG\n\ +TCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAA\n\ +AAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAG\n\ +GAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACT\n\ +CCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCC\n\ +TGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAG\n\ +ACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGC\n\ +GTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGA\n\ +ACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGA\n\ +CAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCA\n\ +CTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCA\n\ +ACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCG\n\ +CCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGG\n\ +AGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTC\n\ +CGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCG\n\ +AGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACC\n\ +CCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAG\n\ +CTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAG\n\ +CCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGG\n\ +CCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATC\n\ +ACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAA\n\ +AAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGC\n\ +TGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCC\n\ +ACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGG\n\ +CTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGG\n\ +AGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATT\n\ +AGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAA\n\ +TCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGC\n\ +CTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAA\n\ +TCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAG\n\ +CCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGT\n\ +GGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCG\n\ +GGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAG\n\ +CGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTG\n\ +GGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATG\n\ +GTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGT\n\ +AATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTT\n\ +GCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCT\n\ +CAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCG\n\ +GGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTC\n\ +TCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACT\n\ +CGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAG\n\ +ATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGG\n\ +CGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTG\n\ +AGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATA\n\ +CAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGG\n\ +CAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGC\n\ +ACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCAC\n\ +GCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTC\n\ +GAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCG\n\ +GGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCT\n\ +TGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGG\n\ +CGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCA\n\ +GCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGG\n\ +CCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGC\n\ +GCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGG\n\ +CGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGA\n\ +CTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGG\n\ +CCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAA\n\ +ACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCC\n\ +CAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGT\n\ +GAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAA\n\ +AGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGG\n\ +ATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTAC\n\ +TAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGA\n\ +GGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGC\n\ +GCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGG\n\ +TGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTC\n\ +AGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAA\n\ +ATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGA\n\ +GAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC\n\ +AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTG\n\ +TAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGAC\n\ +CAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGT\n\ +GGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAAC\n\ +CCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACA\n\ +GAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACT\n\ +TTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAAC\n\ +ATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCC\n\ +TGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAG\n\ +GTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCG\n\ +TCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAG\n\ +GCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCC\n\ +GTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCT\n\ +ACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCC\n\ +GAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCC\n\ +GGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCAC\n\ +CTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAA\n\ +ATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTG\n\ +AGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCAC\n\ +TGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCT\n\ +CACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAG\n\ +TTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAG\n\ +CCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATC\n\ +GCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCT\n\ +GGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATC\n\ +CCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCC\n\ +TGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGG\n\ +CGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG\n\ +AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCG\n\ +AGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGG\n\ +AGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGT\n\ +GAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAA\n\ +TCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGC\n\ +AGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCA\n\ +AAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGG\n\ +CGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTC\n\ +TACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCG\n\ +GGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGAT\n\ +CGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCG\n\ +CGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAG\n\ +GTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACA\n\ +AAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCA\n\ +GGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCAC\n\ +TCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGC\n\ +CTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGA\n\ +GACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGG\n\ +CGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTG\n\ +AACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCG\n\ +ACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGC\n\ +ACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCC\n\ +AACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGC\n\ +GCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCG\n\ +GAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACT\n\ +CCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCC\n\ +GAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAAC\n\ +CCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA\n\ +GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGA\n\ +GCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAG\n\ +GCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGAT\n\ +CACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTA\n\ +AAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGG\n\ +CTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGC\n\ +CACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTG\n\ +GCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAG\n\ +GAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAAT\n\ +TAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGA\n\ +ATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAG\n\ +CCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTA\n\ +ATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCA\n\ +GCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGG\n\ +TGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCC\n\ +GGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGA\n\ +GCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTT\n\ +GGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACAT\n\ +GGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTG\n\ +TAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGT\n\ +TGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTC\n\ +TCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGC\n\ +GGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGT\n\ +CTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTAC\n\ +TCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGA\n\ +GATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGG\n\ +GCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCT\n\ +GAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT\n\ +ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAG\n\ +GCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTG\n\ +CACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCA\n\ +CGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTT\n\ +CGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCC\n\ +GGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGC\n\ +TTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGG\n\ +GCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCC\n\ +AGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTG\n\ +GCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCG\n\ +CGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAG\n\ +GCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAG\n\ +ACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAG\n\ +GCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGA\n\ +AACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATC\n\ +CCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAG\n\ +TGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAA\n\ +AAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCG\n\ +GATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTA\n\ +CTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGG\n\ +AGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCG\n\ +CGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCG\n\ +GTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGT\n\ +CAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAA\n\ +AATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGG\n\ +AGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTC\n\ +CAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCT\n\ +GTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA\n\ +CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCG\n\ +TGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAA\n\ +CCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGAC\n\ +AGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCAC\n\ +TTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAA\n\ +CATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGC\n\ +CTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGA\n\ +GGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCC\n\ +GTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGA\n\ +GGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCC\n\ +CGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGC\n\ +TACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGC\n\ +CGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGC\n\ +CGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCA\n\ +CCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAA\n\ +AATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCT\n\ +GAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCA\n\ +CTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGC\n\ +TCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGA\n\ +GTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTA\n\ +GCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAAT\n\ +CGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCC\n\ +TGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAAT\n\ +CCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGC\n\ +CTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTG\n\ +GCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGG\n\ +GAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGC\n\ +GAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG\n\ +GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGG\n\ +TGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTA\n\ +ATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTG\n\ +CAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTC\n\ +AAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGG\n\ +GCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCT\n\ +CTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTC\n\ +GGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGA\n\ +TCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGC\n\ +GCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGA\n\ +GGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATAC\n\ +AAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGC\n\ +AGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCA\n\ +CTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACG\n\ +CCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCG\n\ +AGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGG\n\ +GCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTT\n\ +GAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGC\n\ +GACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAG\n\ +CACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGC\n\ +CAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCG\n\ +CGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGC\n\ +GGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGAC\n\ +TCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGC\n\ +CGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAA\n\ +CCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCC\n\ +AGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTG\n\ +AGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA\n\ +GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA\n\ +TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT\n\ +AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG\n\ +GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG\n\ +CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT\n\ +GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA\n\ +GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA\n\ +TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG\n\ +AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA\n\ +GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT\n\ +AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC\n\ +AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG\n\ +GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC\n\ +CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG\n\ +AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT\n\ +TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA\n\ +TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT\n\ +GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG\n\ +TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT\n\ +CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG\n\ +CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG\n\ +TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA\n\ +CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG\n\ +AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG\n\ +GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC\n\ +TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA\n\ +TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA\n\ +GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT\n\ +GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC\n\ +ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT\n\ +TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC\n\ +CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG\n\ +CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG\n\ +GGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCC\n\ +CAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCT\n\ +GGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGC\n\ +GCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGA\n\ +GGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGA\n\ +GACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGA\n\ +GGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTG\n\ +AAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT\n\ +CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCA\n\ +GTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAA\n\ +AAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGC\n\ +GGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCT\n\ +ACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGG\n\ +GAGGCTGAGGCAGGAGAATC\n\ +>TWO IUB ambiguity codes\n\ +cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg\n\ +tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa\n\ +NtactMcSMtYtcMgRtacttctWBacgaaatatagScDtttgaagacacatagtVgYgt\n\ +cattHWtMMWcStgttaggKtSgaYaaccWStcgBttgcgaMttBYatcWtgacaYcaga\n\ +gtaBDtRacttttcWatMttDBcatWtatcttactaBgaYtcttgttttttttYaaScYa\n\ +HgtgttNtSatcMtcVaaaStccRcctDaataataStcYtRDSaMtDttgttSagtRRca\n\ +tttHatSttMtWgtcgtatSSagactYaaattcaMtWatttaSgYttaRgKaRtccactt\n\ +tattRggaMcDaWaWagttttgacatgttctacaaaRaatataataaMttcgDacgaSSt\n\ +acaStYRctVaNMtMgtaggcKatcttttattaaaaagVWaHKYagtttttatttaacct\n\ +tacgtVtcVaattVMBcttaMtttaStgacttagattWWacVtgWYagWVRctDattBYt\n\ +gtttaagaagattattgacVatMaacattVctgtBSgaVtgWWggaKHaatKWcBScSWa\n\ +accRVacacaaactaccScattRatatKVtactatatttHttaagtttSKtRtacaaagt\n\ +RDttcaaaaWgcacatWaDgtDKacgaacaattacaRNWaatHtttStgttattaaMtgt\n\ +tgDcgtMgcatBtgcttcgcgaDWgagctgcgaggggVtaaScNatttacttaatgacag\n\ +cccccacatYScaMgtaggtYaNgttctgaMaacNaMRaacaaacaKctacatagYWctg\n\ +ttWaaataaaataRattagHacacaagcgKatacBttRttaagtatttccgatctHSaat\n\ +actcNttMaagtattMtgRtgaMgcataatHcMtaBSaRattagttgatHtMttaaKagg\n\ +YtaaBataSaVatactWtataVWgKgttaaaacagtgcgRatatacatVtHRtVYataSa\n\ +KtWaStVcNKHKttactatccctcatgWHatWaRcttactaggatctataDtDHBttata\n\ +aaaHgtacVtagaYttYaKcctattcttcttaataNDaaggaaaDYgcggctaaWSctBa\n\ +aNtgctggMBaKctaMVKagBaactaWaDaMaccYVtNtaHtVWtKgRtcaaNtYaNacg\n\ +gtttNattgVtttctgtBaWgtaattcaagtcaVWtactNggattctttaYtaaagccgc\n\ +tcttagHVggaYtgtNcDaVagctctctKgacgtatagYcctRYHDtgBattDaaDgccK\n\ +tcHaaStttMcctagtattgcRgWBaVatHaaaataYtgtttagMDMRtaataaggatMt\n\ +ttctWgtNtgtgaaaaMaatatRtttMtDgHHtgtcattttcWattRSHcVagaagtacg\n\ +ggtaKVattKYagactNaatgtttgKMMgYNtcccgSKttctaStatatNVataYHgtNa\n\ +BKRgNacaactgatttcctttaNcgatttctctataScaHtataRagtcRVttacDSDtt\n\ +aRtSatacHgtSKacYagttMHtWataggatgactNtatSaNctataVtttRNKtgRacc\n\ +tttYtatgttactttttcctttaaacatacaHactMacacggtWataMtBVacRaSaatc\n\ +cgtaBVttccagccBcttaRKtgtgcctttttRtgtcagcRttKtaaacKtaaatctcac\n\ +aattgcaNtSBaaccgggttattaaBcKatDagttactcttcattVtttHaaggctKKga\n\ +tacatcBggScagtVcacattttgaHaDSgHatRMaHWggtatatRgccDttcgtatcga\n\ +aacaHtaagttaRatgaVacttagattVKtaaYttaaatcaNatccRttRRaMScNaaaD\n\ +gttVHWgtcHaaHgacVaWtgttScactaagSgttatcttagggDtaccagWattWtRtg\n\ +ttHWHacgattBtgVcaYatcggttgagKcWtKKcaVtgaYgWctgYggVctgtHgaNcV\n\ +taBtWaaYatcDRaaRtSctgaHaYRttagatMatgcatttNattaDttaattgttctaa\n\ +ccctcccctagaWBtttHtBccttagaVaatMcBHagaVcWcagBVttcBtaYMccagat\n\ +gaaaaHctctaacgttagNWRtcggattNatcRaNHttcagtKttttgWatWttcSaNgg\n\ +gaWtactKKMaacatKatacNattgctWtatctaVgagctatgtRaHtYcWcttagccaa\n\ +tYttWttaWSSttaHcaaaaagVacVgtaVaRMgattaVcDactttcHHggHRtgNcctt\n\ +tYatcatKgctcctctatVcaaaaKaaaagtatatctgMtWtaaaacaStttMtcgactt\n\ +taSatcgDataaactaaacaagtaaVctaggaSccaatMVtaaSKNVattttgHccatca\n\ +cBVctgcaVatVttRtactgtVcaattHgtaaattaaattttYtatattaaRSgYtgBag\n\ +aHSBDgtagcacRHtYcBgtcacttacactaYcgctWtattgSHtSatcataaatataHt\n\ +cgtYaaMNgBaatttaRgaMaatatttBtttaaaHHKaatctgatWatYaacttMctctt\n\ +ttVctagctDaaagtaVaKaKRtaacBgtatccaaccactHHaagaagaaggaNaaatBW\n\ +attccgStaMSaMatBttgcatgRSacgttVVtaaDMtcSgVatWcaSatcttttVatag\n\ +ttactttacgatcaccNtaDVgSRcgVcgtgaacgaNtaNatatagtHtMgtHcMtagaa\n\ +attBgtataRaaaacaYKgtRccYtatgaagtaataKgtaaMttgaaRVatgcagaKStc\n\ +tHNaaatctBBtcttaYaBWHgtVtgacagcaRcataWctcaBcYacYgatDgtDHccta\n\ +aagacYRcaggattHaYgtKtaatgcVcaataMYacccatatcacgWDBtgaatcBaata\n\ +cKcttRaRtgatgaBDacggtaattaaYtataStgVHDtDctgactcaaatKtacaatgc\n\ +gYatBtRaDatHaactgtttatatDttttaaaKVccYcaaccNcBcgHaaVcattHctcg\n\ +attaaatBtatgcaaaaatYMctSactHatacgaWacattacMBgHttcgaatVaaaaca\n\ +BatatVtctgaaaaWtctRacgBMaatSgRgtgtcgactatcRtattaScctaStagKga\n\ +DcWgtYtDDWKRgRtHatRtggtcgaHgggcgtattaMgtcagccaBggWVcWctVaaat\n\ +tcgNaatcKWagcNaHtgaaaSaaagctcYctttRVtaaaatNtataaccKtaRgtttaM\n\ +tgtKaBtRtNaggaSattHatatWactcagtgtactaKctatttgRYYatKatgtccgtR\n\ +tttttatttaatatVgKtttgtatgtNtataRatWYNgtRtHggtaaKaYtKSDcatcKg\n\ +taaYatcSRctaVtSMWtVtRWHatttagataDtVggacagVcgKWagBgatBtaaagNc\n\ +aRtagcataBggactaacacRctKgttaatcctHgDgttKHHagttgttaatgHBtatHc\n\ +DaagtVaBaRccctVgtgDtacRHSctaagagcggWYaBtSaKtHBtaaactYacgNKBa\n\ +VYgtaacttagtVttcttaatgtBtatMtMtttaattaatBWccatRtttcatagVgMMt\n\ +agctStKctaMactacDNYgKYHgaWcgaHgagattacVgtttgtRaSttaWaVgataat\n\ +gtgtYtaStattattMtNgWtgttKaccaatagNYttattcgtatHcWtctaaaNVYKKt\n\ +tWtggcDtcgaagtNcagatacgcattaagaccWctgcagcttggNSgaNcHggatgtVt\n\ +catNtRaaBNcHVagagaaBtaaSggDaatWaatRccaVgggStctDaacataKttKatt\n\ +tggacYtattcSatcttagcaatgaVBMcttDattctYaaRgatgcattttNgVHtKcYR\n\ +aatRKctgtaaacRatVSagctgtWacBtKVatctgttttKcgtctaaDcaagtatcSat\n\ +aWVgcKKataWaYttcccSaatgaaaacccWgcRctWatNcWtBRttYaattataaNgac\n\ +acaatagtttVNtataNaYtaatRaVWKtBatKagtaatataDaNaaaaataMtaagaaS\n\ +tccBcaatNgaataWtHaNactgtcDtRcYaaVaaaaaDgtttRatctatgHtgttKtga\n\ +aNSgatactttcgagWaaatctKaaDaRttgtggKKagcDgataaattgSaacWaVtaNM\n\ +acKtcaDaaatttctRaaVcagNacaScRBatatctRatcctaNatWgRtcDcSaWSgtt\n\ +RtKaRtMtKaatgttBHcYaaBtgatSgaSWaScMgatNtctcctatttctYtatMatMt\n\ +RRtSaattaMtagaaaaStcgVgRttSVaScagtgDtttatcatcatacRcatatDctta\n\ +tcatVRtttataaHtattcYtcaaaatactttgVctagtaaYttagatagtSYacKaaac\n\ +gaaKtaaatagataatSatatgaaatSgKtaatVtttatcctgKHaatHattagaaccgt\n\ +YaaHactRcggSBNgtgctaaBagBttgtRttaaattYtVRaaaattgtaatVatttctc\n\ +ttcatgBcVgtgKgaHaaatattYatagWacNctgaaMcgaattStagWaSgtaaKagtt\n\ +ttaagaDgatKcctgtaHtcatggKttVDatcaaggtYcgccagNgtgcVttttagagat\n\ +gctaccacggggtNttttaSHaNtatNcctcatSaaVgtactgBHtagcaYggYVKNgta\n\ +KBcRttgaWatgaatVtagtcgattYgatgtaatttacDacSctgctaaaStttaWMagD\n\ +aaatcaVYctccgggcgaVtaaWtStaKMgDtttcaaMtVgBaatccagNaaatcYRMBg\n\ +gttWtaaScKttMWtYataRaDBMaDataatHBcacDaaKDactaMgagttDattaHatH\n\ +taYatDtattDcRNStgaatattSDttggtattaaNSYacttcDMgYgBatWtaMagact\n\ +VWttctttgYMaYaacRgHWaattgRtaagcattctMKVStatactacHVtatgatcBtV\n\ +NataaBttYtSttacKgggWgYDtgaVtYgatDaacattYgatggtRDaVDttNactaSa\n\ +MtgNttaacaaSaBStcDctaccacagacgcaHatMataWKYtaYattMcaMtgSttDag\n\ +cHacgatcaHttYaKHggagttccgatYcaatgatRaVRcaagatcagtatggScctata\n\ +ttaNtagcgacgtgKaaWaactSgagtMYtcttccaKtStaacggMtaagNttattatcg\n\ +tctaRcactctctDtaacWYtgaYaSaagaWtNtatttRacatgNaatgttattgWDDcN\n\ +aHcctgaaHacSgaataaRaataMHttatMtgaSDSKatatHHaNtacagtccaYatWtc\n\ +actaactatKDacSaStcggataHgYatagKtaatKagStaNgtatactatggRHacttg\n\ +tattatgtDVagDVaRctacMYattDgtttYgtctatggtKaRSttRccRtaaccttaga\n\ +gRatagSaaMaacgcaNtatgaaatcaRaagataatagatactcHaaYKBctccaagaRa\n\ +BaStNagataggcgaatgaMtagaatgtcaKttaaatgtaWcaBttaatRcggtgNcaca\n\ +aKtttScRtWtgcatagtttWYaagBttDKgcctttatMggNttattBtctagVtacata\n\ +aaYttacacaaRttcYtWttgHcaYYtaMgBaBatctNgcDtNttacgacDcgataaSat\n\ +YaSttWtcctatKaatgcagHaVaacgctgcatDtgttaSataaaaYSNttatagtaNYt\n\ +aDaaaNtggggacttaBggcHgcgtNtaaMcctggtVtaKcgNacNtatVaSWctWtgaW\n\ +cggNaBagctctgaYataMgaagatBSttctatacttgtgtKtaattttRagtDtacata\n\ +tatatgatNHVgBMtKtaKaNttDHaagatactHaccHtcatttaaagttVaMcNgHata\n\ +tKtaNtgYMccttatcaaNagctggacStttcNtggcaVtattactHaSttatgNMVatt\n\ +MMDtMactattattgWMSgtHBttStStgatatRaDaagattttctatMtaaaaaggtac\n\ +taaVttaSacNaatactgMttgacHaHRttgMacaaaatagttaatatWKRgacDgaRta\n\ +tatttattatcYttaWtgtBRtWatgHaaattHataagtVaDtWaVaWtgStcgtMSgaS\n\ +RgMKtaaataVacataatgtaSaatttagtcgaaHtaKaatgcacatcggRaggSKctDc\n\ +agtcSttcccStYtccRtctctYtcaaKcgagtaMttttcRaYDttgttatctaatcata\n\ +NctctgctatcaMatactataggDaHaaSttMtaDtcNatataattctMcStaaBYtaNa\n\ +gatgtaatHagagSttgWHVcttatKaYgDctcttggtgttMcRaVgSgggtagacaata\n\ +aDtaattSaDaNaHaBctattgNtaccaaRgaVtKNtaaYggHtaKKgHcatctWtctDt\n\ +ttctttggSDtNtaStagttataaacaattgcaBaBWggHgcaaaBtYgctaatgaaatW\n\ +cDcttHtcMtWWattBHatcatcaaatctKMagtDNatttWaBtHaaaNgMttaaStagt\n\ +tctctaatDtcRVaYttgttMtRtgtcaSaaYVgSWDRtaatagctcagDgcWWaaaBaa\n\ +RaBctgVgggNgDWStNaNBKcBctaaKtttDcttBaaggBttgaccatgaaaNgttttt\n\ +tttatctatgttataccaaDRaaSagtaVtDtcaWatBtacattaWacttaSgtattggD\n\ +gKaaatScaattacgWcagKHaaccaYcRcaRttaDttRtttHgaHVggcttBaRgtccc\n\ +tDatKaVtKtcRgYtaKttacgtatBtStaagcaattaagaRgBagSaattccSWYttta\n\ +ttVaataNctgHgttaaNBgcVYgtRtcccagWNaaaacaDNaBcaaaaRVtcWMgBagM\n\ +tttattacgDacttBtactatcattggaaatVccggttRttcatagttVYcatYaSHaHc\n\ +ttaaagcNWaHataaaRWtctVtRYtagHtaaaYMataHYtNBctNtKaatattStgaMc\n\ +BtRgctaKtgcScSttDgYatcVtggaaKtaagatWccHccgKYctaNNctacaWctttt\n\ +gcRtgtVcgaKttcMRHgctaHtVaataaDtatgKDcttatBtDttggNtacttttMtga\n\ +acRattaaNagaactcaaaBBVtcDtcgaStaDctgaaaSgttMaDtcgttcaccaaaag\n\ +gWtcKcgSMtcDtatgtttStaaBtatagDcatYatWtaaaBacaKgcaDatgRggaaYc\n\ +taRtccagattDaWtttggacBaVcHtHtaacDacYgtaatataMagaatgHMatcttat\n\ +acgtatttttatattacHactgttataMgStYaattYaccaattgagtcaaattaYtgta\n\ +tcatgMcaDcgggtcttDtKgcatgWRtataatatRacacNRBttcHtBgcRttgtgcgt\n\ +catacMtttBctatctBaatcattMttMYgattaaVYatgDaatVagtattDacaacDMa\n\ +tcMtHcccataagatgBggaccattVWtRtSacatgctcaaggggYtttDtaaNgNtaaB\n\ +atggaatgtctRtaBgBtcNYatatNRtagaacMgagSaSDDSaDcctRagtVWSHtVSR\n\ +ggaacaBVaccgtttaStagaacaMtactccagtttVctaaRaaHttNcttagcaattta\n\ +ttaatRtaaaatctaacDaBttggSagagctacHtaaRWgattcaaBtctRtSHaNtgta\n\ +cattVcaHaNaagtataccacaWtaRtaaVKgMYaWgttaKggKMtKcgWatcaDatYtK\n\ +SttgtacgaccNctSaattcDcatcttcaaaDKttacHtggttHggRRaRcaWacaMtBW\n\ +VHSHgaaMcKattgtaRWttScNattBBatYtaNRgcggaagacHSaattRtttcYgacc\n\ +BRccMacccKgatgaacttcgDgHcaaaaaRtatatDtatYVtttttHgSHaSaatagct\n\ +NYtaHYaVYttattNtttgaaaYtaKttWtctaNtgagaaaNctNDctaaHgttagDcRt\n\ +tatagccBaacgcaRBtRctRtggtaMYYttWtgataatcgaataattattataVaaaaa\n\ +ttacNRVYcaaMacNatRttcKatMctgaagactaattataaYgcKcaSYaatMNctcaa\n\ +cgtgatttttBacNtgatDccaattattKWWcattttatatatgatBcDtaaaagttgaa\n\ +VtaHtaHHtBtataRBgtgDtaataMttRtDgDcttattNtggtctatctaaBcatctaR\n\ +atgNacWtaatgaagtcMNaacNgHttatactaWgcNtaStaRgttaaHacccgaYStac\n\ +aaaatWggaYaWgaattattcMaactcBKaaaRVNcaNRDcYcgaBctKaacaaaaaSgc\n\ +tccYBBHYaVagaatagaaaacagYtctVccaMtcgtttVatcaatttDRtgWctagtac\n\ +RttMctgtDctttcKtWttttataaatgVttgBKtgtKWDaWagMtaaagaaattDVtag\n\ +gttacatcatttatgtcgMHaVcttaBtVRtcgtaYgBRHatttHgaBcKaYWaatcNSc\n\ +tagtaaaaatttacaatcactSWacgtaatgKttWattagttttNaggtctcaagtcact\n\ +attcttctaagKggaataMgtttcataagataaaaatagattatDgcBVHWgaBKttDgc\n\ +atRHaagcaYcRaattattatgtMatatattgHDtcaDtcaaaHctStattaatHaccga\n\ +cNattgatatattttgtgtDtRatagSacaMtcRtcattcccgacacSattgttKaWatt\n\ +NHcaacttccgtttSRtgtctgDcgctcaaMagVtBctBMcMcWtgtaacgactctcttR\n\ +ggRKSttgYtYatDccagttDgaKccacgVatWcataVaaagaataMgtgataaKYaaat\n\ +cHDaacgataYctRtcYatcgcaMgtNttaBttttgatttaRtStgcaacaaaataccVg\n\ +aaDgtVgDcStctatatttattaaaaRKDatagaaagaKaaYYcaYSgKStctccSttac\n\ +agtcNactttDVttagaaagMHttRaNcSaRaMgBttattggtttaRMggatggcKDgWR\n\ +tNaataataWKKacttcKWaaagNaBttaBatMHtccattaacttccccYtcBcYRtaga\n\ +ttaagctaaYBDttaNtgaaaccHcaRMtKtaaHMcNBttaNaNcVcgVttWNtDaBatg\n\ +ataaVtcWKcttRggWatcattgaRagHgaattNtatttctctattaattaatgaDaaMa\n\ +tacgttgggcHaYVaaNaDDttHtcaaHtcVVDgBVagcMacgtgttaaBRNtatRtcag\n\ +taagaggtttaagacaVaaggttaWatctccgtVtaDtcDatttccVatgtacNtttccg\n\ +tHttatKgScBatgtVgHtYcWagcaKtaMYaaHgtaattaSaHcgcagtWNaatNccNN\n\ +YcacgVaagaRacttctcattcccRtgtgtaattagcSttaaStWaMtctNNcSMacatt\n\ +ataaactaDgtatWgtagtttaagaaaattgtagtNagtcaataaatttgatMMYactaa\n\ +tatcggBWDtVcYttcDHtVttatacYaRgaMaacaStaatcRttttVtagaDtcacWat\n\ +ttWtgaaaagaaagNRacDtttStVatBaDNtaactatatcBSMcccaSttccggaMatg\n\ +attaaWatKMaBaBatttgataNctgttKtVaagtcagScgaaaDggaWgtgttttKtWt\n\ +atttHaatgtagttcactaaKMagttSYBtKtaYgaactcagagRtatagtVtatcaaaW\n\ +YagcgNtaDagtacNSaaYDgatBgtcgataacYDtaaactacagWDcYKaagtttatta\n\ +gcatcgagttKcatDaattgattatDtcagRtWSKtcgNtMaaaaacaMttKcaWcaaSV\n\ +MaaaccagMVtaMaDtMaHaBgaacataBBVtaatVYaNSWcSgNtDNaaKacacBttta\n\ +tKtgtttcaaHaMctcagtaacgtcgYtactDcgcctaNgagagcYgatattttaaattt\n\ +ccattttacatttDaaRctattttWctttacgtDatYtttcagacgcaaVttagtaaKaa\n\ +aRtgVtccataBggacttatttgtttaWNtgttVWtaWNVDaattgtatttBaagcBtaa\n\ +BttaaVatcHcaVgacattccNggtcgacKttaaaRtagRtctWagaYggtgMtataatM\n\ +tgaaRttattttgWcttNtDRRgMDKacagaaaaggaaaRStcccagtYccVattaNaaK\n\ +StNWtgacaVtagaagcttSaaDtcacaacgDYacWDYtgtttKatcVtgcMaDaSKStV\n\ +cgtagaaWaKaagtttcHaHgMgMtctataagBtKaaaKKcactggagRRttaagaBaaN\n\ +atVVcgRcKSttDaactagtSttSattgttgaaRYatggttVttaataaHttccaagDtg\n\ +atNWtaagHtgcYtaactRgcaatgMgtgtRaatRaNaacHKtagactactggaatttcg\n\ +ccataacgMctRgatgttaccctaHgtgWaYcactcacYaattcttaBtgacttaaacct\n\ +gYgaWatgBttcttVttcgttWttMcNYgtaaaatctYgMgaaattacNgaHgaacDVVM\n\ +tttggtHtctaaRgtacagacgHtVtaBMNBgattagcttaRcttacaHcRctgttcaaD\n\ +BggttKaacatgKtttYataVaNattccgMcgcgtagtRaVVaattaKaatggttRgaMc\n\ +agtatcWBttNtHagctaatctagaaNaaacaYBctatcgcVctBtgcaaagDgttVtga\n\ +HtactSNYtaaNccatgtgDacgaVtDcgKaRtacDcttgctaagggcagMDagggtBWR\n\ +tttSgccttttttaacgtcHctaVtVDtagatcaNMaVtcVacatHctDWNaataRgcgt\n\ +aVHaggtaaaaSgtttMtattDgBtctgatSgtRagagYtctSaKWaataMgattRKtaa\n\ +catttYcgtaacacattRWtBtcggtaaatMtaaacBatttctKagtcDtttgcBtKYYB\n\ +aKttctVttgttaDtgattttcttccacttgSaaacggaaaNDaattcYNNaWcgaaYat\n\ +tttMgcBtcatRtgtaaagatgaWtgaccaYBHgaatagataVVtHtttVgYBtMctaMt\n\ +cctgaDcYttgtccaaaRNtacagcMctKaaaggatttacatgtttaaWSaYaKttBtag\n\ +DacactagctMtttNaKtctttcNcSattNacttggaacaatDagtattRtgSHaataat\n\ +gccVgacccgatactatccctgtRctttgagaSgatcatatcgDcagWaaHSgctYYWta\n\ +tHttggttctttatVattatcgactaagtgtagcatVgtgHMtttgtttcgttaKattcM\n\ +atttgtttWcaaStNatgtHcaaaDtaagBaKBtRgaBgDtSagtatMtaacYaatYtVc\n\ +KatgtgcaacVaaaatactKcRgtaYtgtNgBBNcKtcttaccttKgaRaYcaNKtactt\n\ +tgagSBtgtRagaNgcaaaNcacagtVtttHWatgttaNatBgtttaatNgVtctgaata\n\ +tcaRtattcttttttttRaaKcRStctcggDgKagattaMaaaKtcaHacttaataataK\n\ +taRgDtKVBttttcgtKaggHHcatgttagHggttNctcgtatKKagVagRaaaggaaBt\n\ +NatttVKcRttaHctaHtcaaatgtaggHccaBataNaNaggttgcWaatctgatYcaaa\n\ +HaatWtaVgaaBttagtaagaKKtaaaKtRHatMaDBtBctagcatWtatttgWttVaaa\n\ +ScMNattRactttgtYtttaaaagtaagtMtaMaSttMBtatgaBtttaKtgaatgagYg\n\ +tNNacMtcNRacMMHcttWtgtRtctttaacaacattattcYaMagBaacYttMatcttK\n\ +cRMtgMNccattaRttNatHaHNaSaaHMacacaVaatacaKaSttHatattMtVatWga\n\ +ttttttaYctttKttHgScWaacgHtttcaVaaMgaacagNatcgttaacaaaaagtaca\n\ +HBNaattgttKtcttVttaaBtctgctacgBgcWtttcaggacacatMgacatcccagcg\n\ +gMgaVKaBattgacttaatgacacacaaaaaatRKaaBctacgtRaDcgtagcVBaacDS\n\ +BHaaaaSacatatacagacRNatcttNaaVtaaaataHattagtaaaaSWccgtatWatg\n\ +gDttaactattgcccatcttHaSgYataBttBaactattBtcHtgatcaataSttaBtat\n\ +KSHYttWggtcYtttBttaataccRgVatStaHaKagaatNtagRMNgtcttYaaSaact\n\ +cagDSgagaaYtMttDtMRVgWKWtgMaKtKaDttttgactatacataatcNtatNaHat\n\ +tVagacgYgatatatttttgtStWaaatctWaMgagaRttRatacgStgattcttaagaD\n\ +taWccaaatRcagcagaaNKagtaaDggcgccBtYtagSBMtactaaataMataBSacRM\n\ +gDgattMMgtcHtcaYDtRaDaacggttDaggcMtttatgttaNctaattaVacgaaMMt\n\ +aatDccSgtattgaRtWWaccaccgagtactMcgVNgctDctaMScatagcgtcaactat\n\ +acRacgHRttgctatttaatgaattataYKttgtaagWgtYttgcHgMtaMattWaWVta\n\ +RgcttgYgttBHtYataSccStBtgtagMgtDtggcVaaSBaatagDttgBgtctttctc\n\ +attttaNagtHKtaMWcYactVcgcgtatMVtttRacVagDaatcttgctBBcRDgcaac\n\ +KttgatSKtYtagBMagaRtcgBattHcBWcaactgatttaatttWDccatttatcgagS\n\ +KaWttataHactaHMttaatHtggaHtHagaatgtKtaaRactgtttMatacgatcaagD\n\ +gatKaDctataMggtHDtggHacctttRtatcttYattttgacttgaaSaataaatYcgB\n\ +aaaaccgNatVBttMacHaKaataagtatKgtcaagactcttaHttcggaattgttDtct\n\ +aaccHttttWaaatgaaatataaaWattccYDtKtaaaacggtgaggWVtctattagtga\n\ +ctattaagtMgtttaagcatttgSgaaatatccHaaggMaaaattttcWtatKctagDtY\n\ +tMcctagagHcactttactatacaaacattaacttaHatcVMYattYgVgtMttaaRtga\n\ +aataaDatcaHgtHHatKcDYaatcttMtNcgatYatgSaMaNtcttKcWataScKggta\n\ +tcttacgcttWaaagNatgMgHtctttNtaacVtgttcMaaRatccggggactcMtttaY\n\ +MtcWRgNctgNccKatcttgYDcMgattNYaRagatHaaHgKctcataRDttacatBatc\n\ +cattgDWttatttaWgtcggagaaaaatacaatacSNtgggtttccttacSMaagBatta\n\ +caMaNcactMttatgaRBacYcYtcaaaWtagctSaacttWgDMHgaggatgBVgcHaDt\n\ +ggaactttggtcNatNgtaKaBcccaNtaagttBaacagtatacDYttcctNgWgcgSMc\n\ +acatStctHatgRcNcgtacacaatRttMggaNKKggataaaSaYcMVcMgtaMaHtgat\n\ +tYMatYcggtcttcctHtcDccgtgRatcattgcgccgatatMaaYaataaYSggatagc\n\ +gcBtNtaaaScaKgttBgagVagttaKagagtatVaactaSacWactSaKatWccaKaaa\n\ +atBKgaaKtDMattttgtaaatcRctMatcaaMagMttDgVatggMaaWgttcgaWatga\n\ +aatttgRtYtattaWHKcRgctacatKttctaccaaHttRatctaYattaaWatVNccat\n\ +NgagtcKttKataStRaatatattcctRWatDctVagttYDgSBaatYgttttgtVaatt\n\ +taatagcagMatRaacttBctattgtMagagattaaactaMatVtHtaaatctRgaaaaa\n\ +aaatttWacaacaYccYDSaattMatgaccKtaBKWBattgtcaagcHKaagttMMtaat\n\ +ttcKcMagNaaKagattggMagaggtaatttYacatcWaaDgatMgKHacMacgcVaaca\n\ +DtaDatatYggttBcgtatgWgaSatttgtagaHYRVacaRtctHaaRtatgaactaata\n\ +tctSSBgggaaHMWtcaagatKgagtDaSatagttgattVRatNtctMtcSaagaSHaat\n\ +aNataataRaaRgattctttaataaagWaRHcYgcatgtWRcttgaaggaMcaataBRaa\n\ +ccagStaaacNtttcaatataYtaatatgHaDgcStcWttaacctaRgtYaRtataKtgM\n\ +ttttatgactaaaatttacYatcccRWtttHRtattaaatgtttatatttgttYaatMca\n\ +RcSVaaDatcgtaYMcatgtagacatgaaattgRtcaaYaaYtRBatKacttataccaNa\n\ +aattVaBtctggacaagKaaYaaatatWtMtatcYaaVNtcgHaactBaagKcHgtctac\n\ +aatWtaDtSgtaHcataHtactgataNctRgttMtDcDttatHtcgtacatcccaggStt\n\ +aBgtcacacWtccNMcNatMVaVgtccDYStatMaccDatggYaRKaaagataRatttHK\n\ +tSaaatDgataaacttaHgttgVBtcttVttHgDacgaKatgtatatNYataactctSat\n\ +atatattgcHRRYttStggaactHgttttYtttaWtatMcttttctatctDtagVHYgMR\n\ +BgtHttcctaatYRttKtaagatggaVRataKDctaMtKBNtMtHNtWtttYcVtattMc\n\ +gRaacMcctNSctcatttaaagDcaHtYccSgatgcaatYaaaaDcttcgtaWtaattct\n\ +cgttttScttggtaatctttYgtctaactKataHacctMctcttacHtKataacacagcN\n\ +RatgKatttttSaaatRYcgDttaMRcgaaattactMtgcgtaagcgttatBtttttaat\n\ +taagtNacatHgttcRgacKcBBtVgatKttcgaBaatactDRgtRtgaNacWtcacYtt\n\ +aaKcgttctHaKttaNaMgWgWaggtctRgaKgWttSttBtDcNtgtttacaaatYcDRt\n\ +gVtgcctattcNtctaaaDMNttttNtggctgagaVctDaacVtWccaagtaacacaNct\n\ +gaScattccDHcVBatcgatgtMtaatBgHaatDctMYgagaatgYWKcctaatNaStHa\n\ +aaKccgHgcgtYaaYtattgtStgtgcaaRtattaKatattagaWVtcaMtBagttatta\n\ +gNaWHcVgcaattttDcMtgtaRHVYtHtctgtaaaaHVtMKacatcgNaatttMatatg\n\ +ttgttactagWYtaRacgataKagYNKcattataNaRtgaacKaYgcaaYYacaNccHat\n\ +MatDcNgtHttRaWttagaaDcaaaaaatagggtKDtStaDaRtaVtHWKNtgtattVct\n\ +SVgRgataDaRaWataBgaagaaKtaataaYgDcaStaNgtaDaaggtattHaRaWMYaY\n\ +aWtggttHYgagVtgtgcttttcaaDKcagVcgttagacNaaWtagtaataDttctggtt\n\ +VcatcataaagtgKaaaNaMtaBBaattaatWaattgctHaVKaSgDaaVKaHtatatat\n\ +HatcatSBagNgHtatcHYMHgttDgtaHtBttWatcgtttaRaattgStKgSKNWKatc\n\ +agDtctcagatttctRtYtBatBgHHtKaWtgYBgacVVWaKtacKcDttKMaKaVcggt\n\ +gttataagaataaHaatattagtataatMHgttYgaRttagtaRtcaaVatacggtcMcg\n\ +agtaaRttacWgactKRYataaaagSattYaWgagatYagKagatgSaagKgttaatMgg\n\ +tataatgttWYttatgagaaacctNVataatHcccKtDctcctaatactggctHggaSag\n\ +gRtKHaWaattcgSatMatttagaggcYtctaMcgctcataSatatgRagacNaaDagga\n\ +VBagaYttKtacNaKgtSYtagttggaWcatcWttaatctatgaVtcgtgtMtatcaYcg\n\ +tRccaaYgDctgcMgtgtWgacWtgataacacgcgctBtgttaKtYDtatDcatcagKaV\n\ +MctaatcttgVcaaRgcRMtDcgattaHttcaNatgaatMtactacVgtRgatggaWttt\n\ +actaaKatgagSaaKggtaNtactVaYtaaKRagaacccacaMtaaMtKtatBcttgtaa\n\ +WBtMctaataaVcDaaYtcRHBtcgttNtaaHatttBNgRStVDattBatVtaagttaYa\n\ +tVattaagaBcacggtSgtVtatttaRattgatgtaHDKgcaatattKtggcctatgaWD\n\ +KRYcggattgRctatNgatacaatMNttctgtcRBYRaaaHctNYattcHtaWcaattct\n\ +BtMKtVgYataatMgYtcagcttMDataVtggRtKtgaatgccNcRttcaMtRgattaac\n\ +attRcagcctHtWMtgtDRagaKaBtgDttYaaaaKatKgatctVaaYaacWcgcatagB\n\ +VtaNtRtYRaggBaaBtgKgttacataagagcatgtRattccacttaccatRaaatgWgD\n\ +aMHaYVgVtaSctatcgKaatatattaDgacccYagtgtaYNaaatKcagtBRgagtcca\n\ +tgKgaaaccBgaagBtgSttWtacgatWHaYatcgatttRaaNRgcaNaKVacaNtDgat\n\ +tgHVaatcDaagcgtatgcNttaDataatcSataaKcaataaHWataBtttatBtcaKtK\n\ +tatagttaDgSaYctacaRatNtaWctSaatatttYaKaKtaccWtatcRagacttaYtt\n\ +VcKgSDcgagaagatccHtaattctSttatggtKYgtMaHagVaBRatttctgtRgtcta\n\ +tgggtaHKgtHacHtSYacgtacacHatacKaaBaVaccaDtatcSaataaHaagagaat\n\ +ScagactataaRttagcaaVcaHataKgDacatWccccaagcaBgagWatctaYttgaaa\n\ +tctVNcYtttWagHcgcgcDcVaaatgttKcHtNtcaatagtgtNRaactttttcaatgg\n\ +WgBcgDtgVgtttctacMtaaataaaRggaaacWaHttaRtNtgctaaRRtVBctYtVta\n\ +tDcattDtgaccYatagatYRKatNYKttNgcctagtaWtgaactaMVaacctgaStttc\n\ +tgaKVtaaVaRKDttVtVctaDNtataaaDtccccaagtWtcgatcactDgYaBcatcct\n\ +MtVtacDaaBtYtMaKNatNtcaNacgDatYcatcgcaRatWBgaacWttKttagYtaat\n\ +tcggttgSWttttDWctttacYtatatWtcatDtMgtBttgRtVDggttaacYtacgtac\n\ +atgaattgaaWcttMStaDgtatattgaDtcRBcattSgaaVBRgagccaaKtttcDgcg\n\ +aSMtatgWattaKttWtgDBMaggBBttBaatWttRtgcNtHcgttttHtKtcWtagHSt\n\ +aacagttgatatBtaWSaWggtaataaMttaKacDaatactcBttcaatatHttcBaaSa\n\ +aatYggtaRtatNtHcaatcaHtagVtgtattataNggaMtcttHtNagctaaaggtaga\n\ +YctMattNaMVNtcKtactBKcaHHcBttaSagaKacataYgctaKaYgttYcgacWVtt\n\ +WtSagcaacatcccHaccKtcttaacgaKttcacKtNtacHtatatRtaaatacactaBt\n\ +ttgaHaRttggttWtatYagcatYDatcggagagcWBataagRtacctataRKgtBgatg\n\ +aDatataSttagBaHtaatNtaDWcWtgtaattacagKttcNtMagtattaNgtctcgtc\n\ +ctcttBaHaKcKccgtRcaaYagSattaagtKataDatatatagtcDtaacaWHcaKttD\n\ +gaaRcgtgYttgtcatatNtatttttatggccHtgDtYHtWgttatYaacaattcaWtat\n\ +NgctcaaaSttRgctaatcaaatNatcgtttaBtNNVtgttataagcaaagattBacgtD\n\ +atttNatttaaaDcBgtaSKgacgtagataatttcHMVNttgttBtDtgtaWKaaRMcKM\n\ +tHtaVtagataWctccNNaSWtVaHatctcMgggDgtNHtDaDttatatVWttgttattt\n\ +aacctttcacaaggaSaDcggttttttatatVtctgVtaacaStDVaKactaMtttaSNa\n\ +gtgaaattaNacttSKctattcctctaSagKcaVttaagNaVcttaVaaRNaHaaHttat\n\ +gtHttgtgatMccaggtaDcgaccgtWgtWMtttaHcRtattgScctatttKtaaccaag\n\ +tYagaHgtWcHaatgccKNRtttagtMYSgaDatctgtgaWDtccMNcgHgcaaacNDaa\n\ +aRaStDWtcaaaaHKtaNBctagBtgtattaactaattttVctagaatggcWSatMaccc\n\ +ttHttaSgSgtgMRcatRVKtatctgaaaccDNatYgaaVHNgatMgHRtacttaaaRta\n\ +tStRtDtatDttYatattHggaBcttHgcgattgaKcKtttcRataMtcgaVttWacatN\n\ +catacctRataDDatVaWNcggttgaHtgtMacVtttaBHtgagVttMaataattatgtt\n\ +cttagtttgtgcDtSatttgBtcaacHattaaBagVWcgcaSYttMgcttacYKtVtatc\n\ +aYaKctgBatgcgggcYcaaaaacgNtctagKBtattatctttKtaVttatagtaYtRag\n\ +NtaYataaVtgaatatcHgcaaRataHtacacatgtaNtgtcgYatWMatttgaactacR\n\ +ctaWtWtatacaatctBatatgYtaagtatgtgtatSttactVatcttYtaBcKgRaSgg\n\ +RaaaaatgcagtaaaWgtaRgcgataatcBaataccgtatttttccatcNHtatWYgatH\n\ +SaaaDHttgctgtccHtggggcctaataatttttctatattYWtcattBtgBRcVttaVM\n\ +RSgctaatMagtYtttaaaaatBRtcBttcaaVtaacagctccSaaSttKNtHtKYcagc\n\ +agaaaccccRtttttaaDcDtaStatccaagcgctHtatcttaDRYgatDHtWcaaaBcW\n\ +gKWHttHataagHacgMNKttMKHccaYcatMVaacgttaKgYcaVaaBtacgcaacttt\n\ +MctaaHaatgtBatgagaSatgtatgSRgHgWaVWgataaatatttccKagVgataattW\n\ +aHNcYggaaatgctHtKtaDtctaaagtMaatVDVactWtSaaWaaMtaHtaSKtcBRaN\n\ +cttStggtBttacNagcatagRgtKtgcgaacaacBcgKaatgataagatgaaaattgta\n\ +ctgcgggtccHHWHaaNacaBttNKtKtcaaBatatgctaHNgtKcDWgtttatNgVDHg\n\ +accaacWctKaaggHttgaRgYaatHcaBacaatgagcaaattactgtaVaaYaDtagat\n\ +tgagNKggtggtgKtWKaatacagDRtatRaMRtgattDggtcaaYRtatttNtagaDtc\n\ +acaaSDctDtataatcgtactaHttatacaatYaacaaHttHatHtgcgatRRttNgcat\n\ +SVtacWWgaaggagtatVMaVaaattScDDKNcaYBYaDatHgtctatBagcaacaagaa\n\ +tgagaaRcataaKNaRtBDatcaaacgcattttttaaBtcSgtacaRggatgtMNaattg\n\ +gatatWtgagtattaaaVctgcaYMtatgatttttYgaHtgtcttaagWBttHttgtctt\n\ +attDtcgtatWtataataSgctaHagcDVcNtaatcaagtaBDaWaDgtttagYctaNcc\n\ +DtaKtaHcttaataacccaRKtacaVaatNgcWRaMgaattatgaBaaagattVYaHMDc\n\ +aDHtcRcgYtcttaaaWaaaVKgatacRtttRRKYgaatacaWVacVcRtatMacaBtac\n\ +tggMataaattttHggNagSctacHgtBagcgtcgtgattNtttgatSaaggMttctttc\n\ +ttNtYNagBtaaacaaatttMgaccttacataattgYtcgacBtVMctgStgMDtagtaR\n\ +ctHtatgttcatatVRNWataDKatWcgaaaaagttaaaagcacgHNacgtaatctttMR\n\ +tgacttttDacctataaacgaaatatgattagaactccSYtaBctttaataacWgaaaYa\n\ +tagatgWttcatKtNgatttttcaagHtaYgaaRaDaagtaggagcttatVtagtctttc\n\ +attaaaatcgKtattaRttacagVaDatgcatVgattgggtctttHVtagKaaRBtaHta\n\ +aggccccaaaaKatggtttaMWgtBtaaacttcactttKHtcgatctccctaYaBacMgt\n\ +cttBaBaNgcgaaacaatctagtHccHtKttcRtRVttccVctttcatacYagMVtMcag\n\ +aMaaacaataBctgYtaatRaaagattaaccatVRatHtaRagcgcaBcgDttStttttc\n\ +VtttaDtKgcaaWaaaaatSccMcVatgtKgtaKgcgatatgtagtSaaaDttatacaaa\n\ +catYaRRcVRHctKtcgacKttaaVctaDaatgttMggRcWaacttttHaDaKaDaBctg\n\ +taggcgtttaHBccatccattcNHtDaYtaataMttacggctNVaacDattgatatttta\n\ +cVttSaattacaaRtataNDgacVtgaacataVRttttaDtcaaacataYDBtttaatBa\n\ +DtttYDaDaMccMttNBttatatgagaaMgaNtattHccNataattcaHagtgaaggDga\n\ +tgtatatatgYatgaStcataaBStWacgtcccataRMaaDattggttaaattcMKtctM\n\ +acaBSactcggaatDDgatDgcWctaacaccgggaVcacWKVacggtaNatatacctMta\n\ +tgatagtgcaKagggVaDtgtaacttggagtcKatatcgMcttRaMagcattaBRaStct\n\ +YSggaHYtacaactMBaagDcaBDRaaacMYacaHaattagcattaaaHgcgctaaggSc\n\ +cKtgaaKtNaBtatDDcKBSaVtgatVYaagVtctSgMctacgttaacWaaattctSgtD\n\ +actaaStaaattgcagBBRVctaatatacctNttMcRggctttMttagacRaHcaBaacV\n\ +KgaataHttttMgYgattcYaNRgttMgcVaaacaVVcDHaatttgKtMYgtatBtVVct\n\ +WgVtatHtacaaHttcacgatagcagtaaNattBatatatttcVgaDagcggttMaagtc\n\ +ScHagaaatgcYNggcgtttttMtStggtRatctacttaaatVVtBacttHNttttaRca\n\ +aatcacagHgagagtMgatcSWaNRacagDtatactaaDKaSRtgattctccatSaaRtt\n\ +aaYctacacNtaRtaactggatgaccYtacactttaattaattgattYgttcagDtNKtt\n\ +agDttaaaaaaaBtttaaNaYWKMBaaaacVcBMtatWtgBatatgaacVtattMtYatM\n\ +NYDKNcKgDttDaVtaaaatgggatttctgtaaatWtctcWgtVVagtcgRgacttcccc\n\ +taDcacagcRcagagtgtWSatgtacatgttaaSttgtaaHcgatgggMagtgaacttat\n\ +RtttaVcaccaWaMgtactaatSSaHtcMgaaYtatcgaaggYgggcgtgaNDtgttMNg\n\ +aNDMtaattcgVttttaacatgVatgtWVMatatcaKgaaattcaBcctccWcttgaaWH\n\ +tWgHtcgNWgaRgctcBgSgaattgcaaHtgattgtgNagtDttHHgBttaaWcaaWagc\n\ +aSaHHtaaaVctRaaMagtaDaatHtDMtcVaWMtagSagcttHSattaacaaagtRacM\n\ +tRtctgttagcMtcaBatVKtKtKacgagaSNatSactgtatatcBctgagVtYactgta\n\ +aattaaaggcYgDHgtaacatSRDatMMccHatKgttaacgactKtgKagtcttcaaHRV\n\ +tccttKgtSataatttacaactggatDNgaacttcaRtVaagDcaWatcBctctHYatHa\n\ +DaaatttagYatSatccaWtttagaaatVaacBatHcatcgtacaatatcgcNYRcaata\n\ +YaRaYtgattVttgaatgaVaactcRcaNStgtgtattMtgaggtNttBaDRcgaaaagc\n\ +tNgBcWaWgtSaDcVtgVaatMKBtttcgtttctaaHctaaagYactgMtatBDtcStga\n\ +ccgtSDattYaataHctgggaYYttcggttaWaatctggtRagWMaDagtaacBccacta\n\ +cgHWMKaatgatWatcctgHcaBaSctVtcMtgtDttacctaVgatYcWaDRaaaaRtag\n\ +atcgaMagtggaRaWctctgMgcWttaagKBRtaaDaaWtctgtaagYMttactaHtaat\n\ +cttcataacggcacBtSgcgttNHtgtHccatgttttaaagtatcgaKtMttVcataYBB\n\ +aKtaMVaVgtattNDSataHcagtWMtaggtaSaaKgttgBtVtttgttatcatKcgHac\n\ +acRtctHatNVagSBgatgHtgaRaSgttRcctaacaaattDNttgacctaaYtBgaaaa\n\ +tagttattactcttttgatgtNNtVtgtatMgtcttRttcatttgatgacacttcHSaaa\n\ +ccaWWDtWagtaRDDVNacVaRatgttBccttaatHtgtaaacStcVNtcacaSRttcYa\n\ +gacagaMMttttgMcNttBcgWBtactgVtaRttctccaaYHBtaaagaBattaYacgat\n\ +ttacatctgtaaMKaRYtttttactaaVatWgctBtttDVttctggcDaHaggDaagtcg\n\ +aWcaagtagtWttHtgKtVataStccaMcWcaagataagatcactctHatgtcYgaKcat\n\ +cagatactaagNSStHcctRRNtattgtccttagttagMVgtatagactaactctVcaat\n\ +MctgtttgtgttgccttatWgtaBVtttctggMcaaKgDWtcgtaaYStgSactatttHg\n\ +atctgKagtagBtVacRaagRtMctatgggcaaaKaaaatacttcHctaRtgtDcttDat\n\ +taggaaatttcYHaRaaBttaatggcacKtgctHVcaDcaaaVDaaaVcgMttgtNagcg\n\ +taDWgtcgttaatDgKgagcSatatcSHtagtagttggtgtHaWtaHKtatagctgtVga\n\ +ttaBVaatgaataagtaatVatSttaHctttKtttgtagttaccttaatcgtagtcctgB\n\ +cgactatttVcMacHaaaggaatgDatggKtaHtgStatattaaSagctWcctccRtata\n\ +BaDYcgttgcNaagaggatRaaaYtaWgNtSMcaatttactaacatttaaWttHtatBat\n\ +tgtcgacaatNgattgcNgtMaaaKaBDattHacttggtRtttaYaacgVactBtaBaKt\n\ +gBttatgVttgtVttcaatcWcNctDBaaBgaDHacBttattNtgtDtatttVSaaacag\n\ +gatgcRatSgtaSaNtgBatagttcHBgcBBaaattaHgtDattatDaKaatBaaYaaMa\n\ +ataaataKtttYtagtBgMatNcatgtttgaNagtgttgtgKaNaSagtttgaSMaYBca\n\ +aaacDStagttVacaaaaactaaWttBaagtctgtgcgtMgtaattctcctacctcaNtt\n\ +taaccaaaaVtBcacataacaccccBcWMtatVtggaatgaWtcaaWaaaaaaaaWtDta\n\ +atatRcctDWtcctaccMtVVatKttaWaaKaaatataaagScHBagaggBaSMtaWaVt\n\ +atattactSaaaKNaactatNatccttgaYctattcaaaVgatttYHcRagattttaSat\n\ +aggttattcVtaaagaKgtattattKtRttNcggcRgtgtgtWYtaacHgKatKgatYta\n\ +cYagDtWcHBDctctgRaYKaYagcactKcacSaRtBttttBHKcMtNtcBatttatttt\n\ +tgSatVgaaagaWtcDtagDatatgMacaacRgatatatgtttgtKtNRaatatNatgYc\n\ +aHtgHataacKtgagtagtaacYttaNccaaatHcacaacaVDtagtaYtccagcattNt\n\ +acKtBtactaaagaBatVtKaaHBctgStgtBgtatgaSNtgDataaccctgtagcaBgt\n\ +gatcttaDataStgaMaccaSBBgWagtacKcgattgaDgNNaaaacacagtSatBacKD\n\ +gcgtataBKcatacactaSaatYtYcDaactHttcatRtttaatcaattataRtttgtaa\n\ +gMcgNttcatcBtYBagtNWNMtSHcattcRctttttRWgaKacKttgggagBcgttcgc\n\ +MaWHtaatactgtctctatttataVgtttaBScttttaBMaNaatMacactYtBMggtHa\n\ +cMagtaRtctgcatttaHtcaaaatttgagKtgNtactBacaHtcgtatttctMaSRagc\n\ +agttaatgtNtaaattgagagWcKtaNttagVtacgatttgaatttcgRtgtWcVatcgt\n\ +taaDVctgtttBWgaccagaaagtcSgtVtatagaBccttttcctaaattgHtatcggRa\n\ +ttttcaaggcYSKaagWaWtRactaaaacccBatMtttBaatYtaagaactSttcgaaSc\n\ +aatagtattgaccaagtgttttctaacatgtttNVaatcaaagagaaaNattaaRtttta\n\ +VaaaccgcaggNMtatattVctcaagaggaacgBgtttaacaagttcKcYaatatactaa\n\ +ccBaaaSggttcNtattctagttRtBacgScVctcaatttaatYtaaaaaaatgSaatga\n\ +tagaMBRatgRcMcgttgaWHtcaVYgaatYtaatctttYttatRaWtctgBtDcgatNa\n\ +tcKaBaDgatgtaNatWKctccgatattaacattNaaacDatgBgttctgtDtaaaMggt\n\ +gaBaSHataacgccSctaBtttaRBtcNHcDatcDcctagagtcRtaBgWttDRVHagat\n\ +tYatgtatcWtaHtttYcattWtaaagtctNgtStggRNcgcggagSSaaagaaaatYcH\n\ +DtcgctttaatgYcKBVSgtattRaYBaDaaatBgtatgaHtaaRaRgcaSWNtagatHa\n\ +acttNctBtcaccatctMcatattccaSatttgcgaDagDgtatYtaaaVDtaagtttWV\n\ +aagtagYatRttaagDcNgacKBcScagHtattatcDaDactaaaaaYgHttBcgaDttg\n\ +gataaaKSRcBMaBcgaBSttcWtgNBatRaccgattcatttataacggHVtaattcaca\n\ +agagVttaaRaatVVRKcgWtVgacctgDgYaaHaWtctttcacMagggatVgactagMa\n\ +aataKaaNWagKatagNaaWtaaaatttgaattttatttgctaaVgaHatBatcaaBWcB\n\ +gttcMatcgBaaNgttcgSNaggSaRtttgHtRtattaNttcDcatSaVttttcgaaaaa\n\ +ttgHatctaRaggSaNatMDaaatDcacgattttagaHgHaWtYgattaatHNSttatMS\n\ +gggNtcKtYatRggtttgtMWVtttaYtagcagBagHaYagttatatggtBacYcattaR\n\ +SataBatMtttaaatctHcaaaSaaaagttNSaaWcWRccRtKaagtBWtcaaattSttM\n\ +tattggaaaccttaacgttBtWatttatatWcDaatagattcctScacctaagggRaaYt\n\ +aNaatgVtBcttaaBaacaMVaaattatStYgRcctgtactatcMcVKatttcgSgatRH\n\ +MaaaHtagtaaHtVgcaaataatatcgKKtgccaatBNgaaWcVttgagttaKatagttc\n\ +aggKDatDtattgaKaVcaKtaataDataataHSaHcattagttaatRVYcNaHtaRcaa\n\ +ggtNHcgtcaaccaBaaagYtHWaaaRcKgaYaaDttgcWYtataRgaatatgtYtgcKt\n\ +aNttWacatYHctRaDtYtattcBttttatcSataYaYgttWaRagcacHMgtttHtYtt\n\ +YaatcggtatStttcgtRSattaaDaKMaatatactaNBaWgctacacYtgaYVgtgHta\n\ +aaRaaRgHtagtWattataaaSDaaWtgMattatcgaaaagtaYRSaWtSgNtBgagcRY\n\ +aMDtactaacttaWgtatctagacaagNtattHggataatYttYatcataDcgHgttBtt\n\ +ctttVttgccgaaWtaaaacgKgtatctaaaaaNtccDtaDatBMaMggaatNKtatBaa\n\ +atVtccRaHtaSacataHattgtttKVYattcataVaattWtcgtgMttcttKtgtctaa\n\ +cVtatctatatBRataactcgKatStatattcatHHRttKtccaacgtgggtgRgtgaMt\n\ +attattggctatcgtgacMtRcBDtcttgtactaatRHttttaagatcgVMDStattatY\n\ +BtttDttgtBtNttgRcMtYtgBacHaWaBaatDKctaagtgaaactaatgRaaKgatcc\n\ +aagNaaaatattaggWNtaagtatacttttKcgtcggSYtcttgRctataYcttatataa\n\ +agtatattaatttataVaacacaDHatctatttttKYVatHRactttaBHccaWagtact\n\ +BtcacgaVgcgttRtttttttSVgtSagtBaaattctgaHgactcttgMcattttagVta\n\ +agaattHctHtcaDaaNtaacRggWatagttcgtSttgaDatcNgNagctagDgatcNtt\n\ +KgttgtaDtctttRaaYStRatDtgMggactSttaDtagSaVtBDttgtDgccatcacaM\n\ +attaaaMtNacaVcgSWcVaaDatcaHaatgaattaMtatccVtctBtaattgtWattat\n\ +BRcWcaatgNNtactWYtDaKttaaatcactcagtRaaRgatggtKgcgccaaHgaggat\n\ +StattYcaNMtcaBttacttatgagDaNtaMgaaWtgtttcttctaHtMNgttatctaWW\n\ +atMtBtaaatagDVatgtBYtatcggcttaagacMRtaHScgatatYgRDtcattatSDa\n\ +HggaaataNgaWSRRaaaBaatagBattaDctttgHWNttacaataaaaaaatacggttt\n\ +gHgVtaHtWMttNtBtctagtMcgKMgHgYtataHaNagWtcaacYattaataYRgtaWK\n\ +gaBctataaccgatttaHaNBRaRaMtccggtNgacMtctcatttgcaattcWgMactta\n\ +caaDaaNtactWatVtttagccttMaatcagVaagtctVaaDaBtattaattaYtNaYtg\n\ +gattaKtaKctYaMtattYgatattataatKtVgDcttatatNBtcgttgtStttttMag\n\ +aggttaHYSttcKgtcKtDNtataagttataagSgttatDtRttattgttttSNggRtca\n\ +aKMNatgaatattgtBWtaMacctgggYgaSgaagYataagattacgagaatBtggtRcV\n\ +HtgYggaDgaYaKagWagctatagacgaaHgtWaNgacttHRatVaWacKYtgRVNgVcS\n\ +gRWctacatcKSactctgWYtBggtataagcttNRttVtgRcaWaaatDMatYattaact\n\ +ttcgaagRatSctgccttgcRKaccHtttSNVagtagHagBagttagaccaRtataBcca\n\ +taatSHatRtcHagacBWatagcaMtacaRtgtgaaBatctKRtScttccaNaatcNgta\n\ +atatWtcaMgactctBtWtaaNactHaaaaRctcgcatggctMcaaNtcagaaaaacaca\n\ +gtggggWttRttagtaagaVctVMtcgaatcttcMaaaHcaHBttcgattatgtcaDagc\n\ +YRtBtYcgacMgtDcagcgaNgttaataatagcagKYYtcgtaBtYctMaRtaRtDagaa\n\ +aacacatgYaBttgattattcgaaNttBctSataaMataWRgaHtttccgtDgaYtatgg\n\ +tDgHKgMtatttVtMtVagttaRatMattRagataaccctKctMtSttgaHagtcStcta\n\ +tttccSagatgttccacgaggYNttHRacgattcDatatDcataaaatBBttatcgaHtN\n\ +HaaatatDNaggctgaNcaaggagttBttMgRagVatBcRtaWgatgBtSgaKtcgHttt\n\ +gaatcaaDaHttcSBgHcagtVaaSttDcagccgttNBtgttHagYtattctttRWaaVt\n\ +SttcatatKaaRaaaNacaVtVctMtSDtDtRHRcgtaatgctcttaaatSacacaatcg\n\ +HattcaWcttaaaatHaaatcNctWttaNMcMtaKctVtcctaagYgatgatcYaaaRac\n\ +tctaRDaYagtaacgtDgaggaaatctcaaacatcaScttcKttNtaccatNtaNataca\n\ +tttHaaDHgcaDatMWaaBttcRggctMaagctVYcacgatcaDttatYtaatcKatWat\n\ +caatVYtNagatttgattgaYttttYgacttVtcKaRagaaaHVgDtaMatKYagagttN\n\ +atWttaccNtYtcDWgSatgaRgtMatgKtcgacaagWtacttaagtcgKtgatccttNc\n\ +ttatagMatHVggtagcgHctatagccctYttggtaattKNaacgaaYatatVctaataM\n\ +aaaYtgVtcKaYtaataacagaatHcacVagatYWHttagaaSMaatWtYtgtaaagNaa\n\ +acaVgaWtcacNWgataNttcaSagctMDaRttgNactaccgataMaaatgtttattDtc\n\ +aagacgctDHYYatggttcaagccNctccttcMctttagacBtaaWtaWVHggaaaaNat\n\ +ttaDtDtgctaaHHtMtatNtMtagtcatttgcaaaRatacagRHtatDNtgtDgaatVg\n\ +tVNtcaaatYBMaaaagcaKgtgatgatMgWWMaHttttMgMagatDtataaattaacca\n\ +actMtacataaattgRataatacgBtKtaataattRgtatDagDtcRDacctatRcagag\n\ +cSHatNtcaScNtttggacNtaaggaccgtgKNttgttNcttgaaRgYgRtNtcagttBc\n\ +ttttcHtKtgcttYaaNgYagtaaatgaatggWaMattBHtatctatSgtcYtgcHtaat\n\ +tHgaaMtHcagaaSatggtatgccaHBtYtcNattWtgtNgctttaggtttgtWatNtgH\n\ +tgcDttactttttttgcNtactKtWRaVcttcatagtgSNKaNccgaataaBttataata\n\ +YtSagctttaaatSttggctaaKSaatRccgWHgagDttaaatcatgagMtcgagtVtaD\n\ +ggaBtatttgDacataaacgtagYRagBWtgDStKDgatgaagttcattatttaKWcata\n\ +aatWRgatataRgttRacaaNKttNtKagaaYaStaactScattattaacgatttaaatg\n\ +DtaattagatHgaYataaactatggggatVHtgccgtNgatNYcaStRtagaccacWcaM\n\ +tatRagHgVactYtWHtcttcatgatWgagaKggagtatgaWtDtVtNaNtcgYYgtaaa\n\ +ctttaDtBactagtaDctatagtaatatttatatataacgHaaaRagKattSagttYtSt\n\ +>THREE Homo sapiens frequency\n\ +agagagacgatgaaaattaatcgtcaatacgctggcgaacactgagggggacccaatgct\n\ +cttctcggtctaaaaaggaatgtgtcagaaattggtcagttcaaaagtagaccggatctt\n\ +tgcggagaacaattcacggaacgtagcgttgggaaatatcctttctaccacacatcggat\n\ +tttcgccctctcccattatttattgtgttctcacatagaattattgtttagacatccctc\n\ +gttgtatggagagttgcccgagcgtaaaggcataatccatataccgccgggtgagtgacc\n\ +tgaaattgtttttagttgggatttcgctatggattagcttacacgaagagattctaatgg\n\ +tactataggataattataatgctgcgtggcgcagtacaccgttacaaacgtcgttcgcat\n\ +atgtggctaacacggtgaaaatacctacatcgtatttgcaatttcggtcgtttcatagag\n\ +cgcattgaattactcaaaaattatatatgttgattatttgattagactgcgtggaaagaa\n\ +ggggtactcaagccatttgtaaaagctgcatctcgcttaagtttgagagcttacattagt\n\ +ctatttcagtcttctaggaaatgtctgtgtgagtggttgtcgtccataggtcactggcat\n\ +atgcgattcatgacatgctaaactaagaaagtagattactattaccggcatgcctaatgc\n\ +gattgcactgctatgaaggtgcggacgtcgcgcccatgtagccctgataataccaatact\n\ +tacatttggtcagcaattctgacattatacctagcacccataaatttactcagacttgag\n\ +gacaggctcttggagtcgatcttctgtttgtatgcatgtgatcatatagatgaataagcg\n\ +atgcgactagttagggcatagtatagatctgtgtatacagttcagctgaacgtccgcgag\n\ +tggaagtacagctgagatctatcctaaaatgcaaccatatcgttcacacatgatatgaac\n\ +ccagggggaaacattgagttcagttaaattggcagcgaatcccccaagaagaaggcggag\n\ +tgacgttgaacgggcttatggtttttcagtacttcctccgtataagttgagcgaaatgta\n\ +aacagaataatcgttgtgttaacaacattaaaatcgcggaatatgatgagaatacacagt\n\ +gtgagcatttcacttgtaaaatatctttggtagaacttactttgctttaaatatgttaaa\n\ +ccgatctaataatctacaaaacggtagattttgcctagcacattgcgtccttctctattc\n\ +agatagaggcaatactcagaaggttttatccaaagcactgtgttgactaacctaagtttt\n\ +agtctaataatcatgattgattataggtgccgtggactacatgactcgtccacaaataat\n\ +acttagcagatcagcaattggccaagcacccgacttttatttaatggttgtgcaatagtc\n\ +cagattcgtattcgggactctttcaaataatagtttcctggcatctaagtaagaaaagct\n\ +cataaggaagcgatattatgacacgctcttccgccgctgttttgaaacttgagtattgct\n\ +cgtccgaaattgagggtcacttcaaaatttactgagaagacgaagatcgactaaagttaa\n\ +aatgctagtccacagttggtcaagttgaattcatccacgagttatatagctattttaatt\n\ +tatagtcgagtgtacaaaaaacatccacaataagatttatcttagaataacaacccccgt\n\ +atcatcgaaatcctccgttatggcctgactcctcgagcttatagcatttgtgctggcgct\n\ +cttgccaggaacttgctcgcgaggtggtgacgagtgagatgatcagtttcattatgatga\n\ +tacgattttatcgcgactagttaatcatcatagcaagtaaaatttgaattatgtcattat\n\ +catgctccattaacaggttatttaattgatactgacgaaattttttcacaatgggttttc\n\ +tagaatttaatatcagtaattgaagccttcataggggtcctactagtatcctacacgacg\n\ +caggtccgcagtatcctggagggacgtgttactgattaaaagggtcaaaggaatgaaggc\n\ +tcacaatgttacctgcttcaccatagtgagccgatgagttttacattagtactaaatccc\n\ +aaatcatactttacgatgaggcttgctagcgctaaagagaatacatacaccaccacatag\n\ +aattgttagcgatgatatcaaatagactcctggaagtgtcagggggaaactgttcaatat\n\ +ttcgtccacaggactgaccaggcatggaaaagactgacgttggaaactataccatctcac\n\ +gcccgacgcttcactaattgatgatccaaaaaatatagcccggattcctgattagcaaag\n\ +ggttcacagagaaagatattatcgacgtatatcccaaaaaacagacgtaatgtgcatctt\n\ +cgaatcgggatgaatacttgtatcataaaaatgtgacctctagtatacaggttaatgtta\n\ +gtgatacacaatactcgtgggccatgggttctcaaataaaatgtaatattgcgtcgatca\n\ +ctcacccacgtatttggtctaattatgttttatttagtgacaatccaatagataaccggt\n\ +cctattaagggctatatttttagcgaccacgcgtttaaacaaaggattgtatgtagatgg\n\ +taccagtttaattgccagtgggcaatcctaagcaaaatgagattctatcctaaagtttgg\n\ +gcttgatataagatttcggatgtatgggttttataatcgttggagagctcaatcatgagc\n\ +taatacatggatttcgctacctcaccgagagaccttgcatgaagaattctaaccaaaagt\n\ +ttaataggccggattggattgagttaattaagaccttgttcagtcatagtaaaaaccctt\n\ +aaattttaccgattgacaaagtgagcagtcgcaataccctatgcgaaacgcctcgatagt\n\ +gactaggtatacaaggtttttgagttcctttgaaatagttaactaatttaaaattaatta\n\ +acgacatggaaatcacagaacctaatgctttgtaggagttatttatgctgtttactgcct\n\ +ctacaaccctaataaagcagtcctaagaatgaaacgcatcttttagttcagaaagtggta\n\ +tccagggtggtcaatttaataaattcaacatcgggtctcaggatattcggtcatataatt\n\ +tattaagggctcttcgagtcttactctgagtgaaattggaaacagtcatccttttcgttg\n\ +tgaggcatcttacaccgctatcgatatacaatgcattccaccgcggtgtcccgtacacaa\n\ +ggaaacttgttaccttggggatataagaaaactcacacgtctcattattaaactgagtac\n\ +aatttttgcacgagaaagtaatgcaatacaatatgatgaaagccagctaatgaaaaggga\n\ +tggaacgcacctcggatctgttgcactggattaaaatccgattatttttaaaaatattca\n\ +gtgctagagcatatcaggtctacttttttatctggtatgtaaagcccacggagcgatagt\n\ +gagatccttacgactcaacgaaaagttataacataactcccgttagccaaagcccaatcc\n\ +cgattactgccctaccctaacgtctgccatctaaatatcgaacttgttatgatcaatgtg\n\ +actacctcccaccctttccccttcatttgttccactggggataagctagcgttttcagaa\n\ +tcaatgcaataagaatagccaattgtctcacttcatcagagctcttggcaattccaggcg\n\ +ctacgtggttctggaatatattcatttttcaaatagtaatacgtttagtgttgctattgt\n\ +ctacacgtttggatattacgttatgtgagcggacatcaatagttgtctaactctttagta\n\ +agccagagatagcactcttagcgaatggataccatcttccataagtttagttaatagtcc\n\ +gaaacaactgcttcgagcatatttgaacctccttgtaggcaaatagcctcttcaaagcaa\n\ +tcttactaatagatagagtttgttttaagggactactagaaatgggacaatcttaatagt\n\ +atgacctaaactgacatttaaagatatatccaggtggcaagcataaagatcattgcgcca\n\ +cctccaccgtgggattacttatcagtcgatatcctatatgctaagtttgcgacggcagaa\n\ +tacaaactaagctgagttgatgctaaccttacctatgataccccattggaccggttaaca\n\ +gccctacttattccaaataaaagaacttttatgctgtagaagctattatagtgatgcctg\n\ +gtaacttcagtatattaaaatgacacacatacgccatatagagctcctggaactttgaat\n\ +aatgagcgaacttcgaagttgaagagcaagaaaccatatgtcacggttgcctaaagcccg\n\ +gtaaccagacatgtgctatcattgatcattatcgaggttttcataaccttgacccattat\n\ +cggctgtgcgcggacaagtacttaaatcactagtttcttcacctgcttatcggtaagaaa\n\ +taaggttggcaaagaatcgcataagacggacgtagagccgcagcgttgtgcgagtccagg\n\ +tgcatgcgcagcaataggattttaaattttgttccatttttaatttagccgtaaggatgt\n\ +ccgtaaatgattgaaaattggattcaatctttgggcctatgctactggaacctgatcgac\n\ +aaaatttcaaacatacgttaactccgaaagaccgtatttttgcggctagaatagtcagtc\n\ +gcttggagccatataccttaccacttaaacgacgtgctcctgtagttgaaatataaacag\n\ +aacacaaagactaccgatcatatcaactgaagatctttgtaactttgaggcgaagcaccc\n\ +tcttcgagacaactaagagtaaagtaccgggcgccgcaaggagtcgattgggaccctaaa\n\ +tcttgacgaattgctaagaggctcagagctaccactgtaatttctctagagcccataata\n\ +aatgaacgatacatccgtaggtagcacctaagggattataatggaagccaaatgcagtta\n\ +ataatattatatactggcgtacacgattcgacggatctctcacatagtgattcacgaccc\n\ +ccccctttgattgacacagcgtcagcattttgcaagaacgatcttctgcatagggtgcgc\n\ +caccgtaaggatgacgtcgaagctacaactgggtataatttaccatgcttccctgatgct\n\ +gagtgcaatacactaagaatgagtttttaccccatatcaccagtatttgttctgttattg\n\ +cgaagaaatggctatgctgagttggcgactaaagtcacccatcctttttattaggtaacc\n\ +ccctcccttaaactaactgatttgctggagctgccctgcatacatatactttatcattta\n\ +tggacgtccgtgacgcttattatccaccatagtcgatatgctacacggattcattaatgg\n\ +atcgtaggagtttaagttatatttactaagatcggtctcggctactatcccgccttaccc\n\ +ggcgctatttacggccatttttaatatattgacggtaattattcctatggtttcgaccgc\n\ +acgtccttggacaagaaagaatggcaaaaaaaatgtaaaagaaaaaaaatattgagtccc\n\ +taccatcatataaaaaatatgtgatgagtaacttgacgaaatgttagtggttattaaaga\n\ +ctatctattacaccttttgttttctgtcgtagtatattaaagtctagaagccttacagga\n\ +aaatcagggttatacagccgatactccgcagcatgaatcatcgaggaggtgtcctaccat\n\ +cgcgccttgtaatcttgtctgtgtatactgtatttagaccttttatacaaagtaaatatc\n\ +tcggctttatgtgattgggaggggcctactcaaacatgatgacttgacctaataatcact\n\ +gtgcgggcgtcttatgactagctattccttgaaatccaccaccaaatggttaatatgtaa\n\ +aaactttgacgatgaaacaaggtgaatgtgtagttactttgtgtaattagctgcgtcgag\n\ +cattgcttgtaaaaccgtcaatcgcacacgttacttccataaaatttctacgaatacacc\n\ +cttcttaaaaaaaacgtaggaattcacgagtttaacaaacgataactgtataaagtggaa\n\ +gtccgaagaaagcagatgcccgaactactcgaagatgtttcgttttcttaaccatagggg\n\ +cttcttaatggcccactacgcacattttgttcaagcccgagagggacatccccattacgg\n\ +gagtattactaaaactgttccgtaatacgttcagcaagggatgaaaaaggccactgctca\n\ +agttattgacgtgggagtattacatcggaagcctgaatcccacactatgatggtctgtac\n\ +aggcctagggactgcgtctagacggtattaccggcttctaatcatacgatcgtgagtctt\n\ +aacgggaagtaaggctcacacctaccccaaaccatttatctatgtaagtataaaattgtg\n\ +cgtaagtgttcaaagtggacaataaagacgtggcaaaaacccccgcacataagccgcttt\n\ +agatttcacaaataccaatgcggttaaaaacatccttgagtcgtacatacaccatactcg\n\ +cgttaaacggatataacagaagataataaatccggatgtggagtcggtgtaactatagaa\n\ +agccaagtgaaataatgcttaccagtcatttagctatacggctttcatttcatgtcaaga\n\ +gggtggagtttgacctgtacagttgatatatcaccgatacttagaactcacctaaagcta\n\ +aaattgctcgcagcgtgtaatccgcatattacaaacaatagatgggattcattatacata\n\ +agacacgatgatctgctttttcaggttgcgagatgttgcctatcgtcaatcgagtcctgc\n\ +cttacaccacttaaacaaaagtattgacagggaacctattttcgaggtattatatagtcc\n\ +agcttgaatatcaatttgacagttaacctagtgaaaatcagtaagaggaaatacgccaca\n\ +ttctccagtgaaattctacgggttatcgtctagtccaactatcaattataactcacgaga\n\ +tataagtaaattctcgtacttggcctgatttttattatactttggatccttagtaaacag\n\ +gaagggagaaaccttcaacgaaaaacactggattttgttttactctcaaagctcttatat\n\ +gacggaaataccctgtcaagtcttaactttattactagactaatgaaatgggcttggggt\n\ +ggccagaatcatagtacaatttagcggatacactattcggactttcctatcggctgtctg\n\ +gttggataagtatggggactaataggctagacatacctatacttaaactatacaggcgtc\n\ +atctatctctgcaactttggagttccctgatgttctcccgccctttgggttcacatcttc\n\ +tataccgacacccctaataacgattagtttgtgggttagagtaaattaatacggttaata\n\ +ttaatgtatcgttgaaaagctggtgtcgccaataaggtaaccggctaggcagagtatatg\n\ +tcacgaagtataactaccctaatgataagctgtaggaataaaattaatgctgtctctaag\n\ +cgaagagatatttccgactctgttttaatgacgaatctcattacttctgacttgcaaatg\n\ +ttcaatatggcacggtttcacggcacctttgtgacgcatataatgaacttagaagattat\n\ +aacgacggaactttatatgataatccgttacgattaaagaatctgttaaatatcataatg\n\ +gcattcagttctagaccgtgcatcatggtaaacttactttctctgcatggcgacatacat\n\ +ttcgctattcaaattcgcgtgtggttacacccactcgcacctttggaatattaagagaag\n\ +atgatcagaaaatccattcgctcaatttttctgacgtacgtctaatttatcctaggagac\n\ +aaatcgttttatgtctctcacatttttgaagaaaggttcgagagacaatactcaggtcct\n\ +gaactgctagaagatactcggtggagcgtggcaacaatgaaaaactcgtgacataaatga\n\ +atgatacttttccaagttcagttaagtgaatatgtttaacatacccggcttttcgatctt\n\ +aagctgacgctggacgtgcgagtaatgtcagtctcttacatacactagtgactccaagtt\n\ +tcgtcaaaaacgccccctcccttctcgagcccactcacgctatgtattgacgcgaacttg\n\ +ttcgggatcagacttttcaggagttcggtcgcgtgtccctatgtgctaatatataagtta\n\ +gatcgcattagatgctaatctgaatacttatagacgaccttcaacgagaacgggtaccac\n\ +cttgaggctagagttaggtgtgaaacgacaggtagggacatataaaatttgagtgcggct\n\ +ttagttaagggtttaattacctactcaaacatcacgctcgcgcccttcgtacgtaatcga\n\ +ccatctagaggctaaggggactgtactaggtagtgattaatgatatcctagacgcacgtg\n\ +ccttagatcttcagactctgatggtccgcgatcaccgtaattgtagtcctccaactcgat\n\ +cactttgttggcgtcaaagaaattacgatatctaaatacttataatacaataaccaagga\n\ +tgagaatgactcatcgcgttggagttatattgcttgaagttctatggaatgaaagcacgt\n\ +tatctgccgtcccaatatctccagtgagctaattcattggacggtccactttgatcaatc\n\ +cccgaggagatgttcggacactttagtctgtaacacttagcgttgagaccacgaacaatt\n\ +gattactcagtcttgaaggtgttttccaaagttcattttaaataagactacgataggcct\n\ +ttcctattgatataaactacccggctctgttgttcgtgtgagtcgtacttctctgtgttt\n\ +ttctgattatagcaagattcgattcttagtgtaaacagcgatttttatttgacccgtcaa\n\ +tgagaagcgcataggatctaagcaaaattatcaagttgtgccacaaggtaagatctttcc\n\ +agttattgcaggtaggatgtatcccacgttgatagtatgaggtctgacgtcaactgtcta\n\ +ggagagttgaccgcgtgcgggtacaccggatttgcatcgatgttgagaacgcagaactcc\n\ +cactgtcgtggcggcgttcctgatatttagcaagaggcgttgataaagccctcatcatct\n\ +agatctcgacctcatctgccctcttgctccatcattttctacacagactactttcctatc\n\ +tacgttagtataattgctttctatcttagtatcatttagagcttctccgtcaacaggttc\n\ +gtgctattaaagttagtacgaaagggacaacttgtagcaacgcatttaatcggttttcga\n\ +ctacttcgcacaaaatcagataaagaagtttgtcattctattagacattgaattgcgcaa\n\ +ttgacttgtaccacttatgatcgaacactgaatcaagactgtgattaactaaaatagaca\n\ +agccactatatcaactaataaaaacgcccctggtggtcgaacatagttgactacaggata\n\ +attaattggactggagccattacattctctacaatcgtatcacttcccaagtagacaact\n\ +ttgaccttgtagtttcatgtacaaaaaaatgctttcgcaggagcacattggtagttcaat\n\ +agtttcatgggaacctcttgagccgtcttctgtgggtgtgttcggatagtaggtactgat\n\ +aaagtcgtgtcgctttcgatgagagggaattcaccggaaaacaccttggttaacaggata\n\ +gtctatgtaaacttcgagacatgtttaagagttaccagcttaatccacggtgctctacta\n\ +gtatcatcagctgtcttgcctcgcctagaaatatgcattctatcgttatcctatcaacgg\n\ +ttgccgtactgagcagccttattgtggaagagtaatatataaatgtagtcttgtctttac\n\ +gaagcagacgtaagtaataatgacttggaataccaaaactaaacatagtggattatcata\n\ +ctcaagaactctccagataaataacagtttttacgatacgtcaccaatgagcttaaagat\n\ +taggatcctcaaaactgatacaaacgctaattcatttgttattggatccagtatcagtta\n\ +aactgaatggagtgaagattgtagaatgttgttctggcctcgcatggggtctaggtgata\n\ +tacaatttctcatacttacacggtagtggaaatctgattctagcttcgtagctgactata\n\ +ctcaaggaaccactgctcaaggtaggagactagttccgaccctacagtcaaagtggccga\n\ +agcttaaactatagactagttgttaaatgctgatttcaagatatcatctatatacagttt\n\ +ggacaattatgtgtgcgaaactaaaattcatgctattcagatggatttcacttatgcctt\n\ +agaaacagatattgcccgagctcaatcaacagttttagccggaaacaatcgaagcatagg\n\ +gacaatgtatcttttcctaaattgccatgtgcagatttctgagtgtcacgaagcgcataa\n\ +tagaatcttgtgttgcctcaactcgttgaaaagtttaaaacaatcgcagcagtctttttg\n\ +gggtctactgtgtgtttgcaaaataactgaaagaaacgcttgaacaactctgaagtagct\n\ +cgagtactcattaaagtgtaacacattagtgaatatcggccaatgaaccaaacgcttccc\n\ +ggtacgctatctctctcatcgggaggcgatgtgcaggttatctacgaaagcatcccttta\n\ +cgttgagagtgtcgatgcatgaacctcattgtaacaatagcccagcaaattctcatacgt\n\ +gcctcagggtccgggcgtactcctccatggaagggcgcgcatctagtgttataccaactc\n\ +gctttttaactactatgctgtagttctacaggcatagtggccagtattttctaacttctc\n\ +tggatagatgctctcactcctcatccatcacggcttcagtttacgtcttacttgcttgtt\n\ +cagcaacggatggaggcattaagtatcttcactgttccctaaaattgctgttcaatatca\n\ +aagtaaggacgatacagggaaagctcaagcacactcattgaatactgccccagttgcaac\n\ +ctcacttaatctgacaaaaataatgactactctaagtgttgcggaagcagtctcttccac\n\ +gagcttgtctgtatcacttcgtataggcatgtaactcgatagacacgaacaccgagtgag\n\ +aaactatattcttgcttccgtgtgtgtgacaccaggtaattgatgcggatataagctgga\n\ +gatcactcacgcccacacaaggcgctgctacctctttattccaatgtgtaagaatttgct\n\ +aacttcatttctagaccgcagctttgcggtcataatttcacggtacggacccttgggtta\n\ +gagacttgataacacacttcgcagtttccaccgcgcacatgttttagtggcttctaacat\n\ +agaatttttgttgtgacataaagagtgcgtgggagacttgcccgaccgttaagccataat\n\ +caattgaaagccccgtgagtcacatctaattggttgtactgcgcatttagctatccttta\n\ +gctgactcgaagagattcgattcctaatataggttaattagatggctgccgcgcgaagta\n\ +aaacgtgaaaaacgtagtgcgcagatctgcataactcgcgcttaattacttatgagtagt\n\ +tccaagttcgctacgttatgagagagattggaattaagcaaatatgttttatggtgattt\n\ +tgggatgagaaggactgctaagtacggctactaaacaaatttctaaaaccgccatctacc\n\ +ttatcttggagacatttaagttgtatatgtcactagtctagcttttgtctgtgggacgcg\n\ +ttctcggaatgagggaaatgcaagagccgattcatcaaatgcttatctaagaaagtagtg\n\ +gactattacaccaagcacgaatgccagggaactgctttcttgctcaggacctcgcgacaa\n\ +ggtaccccgcataagtcctagaattacatttggtcagcaatgctgacatttgaccgtgaa\n\ +aacataattttaatcagaaggcagctcacccgcttgctctagatcttatctttgtatgaa\n\ +tgtcagaatttactgcaatatccgttccgaatagtgagggcttagtatagttctctgtat\n\ +acaggtcacatcaaactccccctgtcctagtacagctctgagctttaattaattgcatac\n\ +atttccttcaatcatcagatgaaaacaccgcgaatcatgctcttctcgtatagggcaaga\n\ +gaagcaacaaacaactagcccgactcacgttcatccgccgtatccttgttcagttcttac\n\ +tccgtattaggtcagcgaaatctaatcagaataatcggtcgcgtatcaaaattaaaatcc\n\ +cgcttgaggttgacaattaaaacgctgagcagttatcggctattagatagtggggtgaaa\n\ +gtaattggctggaattatgttaaaacgtgatattaagctaaaatacgctacttgttgccg\n\ +acctaattcagtcattcgatattcagttagagccaagaataacaagcttgtataaattga\n\ +acggggtgcactaaacgatgtgttactctaatattcagcttggagtatacctgaaggcga\n\ +attcatgtatcggccaataataagacgttgaagatcacaatttggactagcaaaagaagg\n\ +tgatttatgcgtggggattgagtccactgtacgagtacggtctctggaaaattataggtt\n\ +cagggaatataaggaagtaaagataattaccaagagatttttggtatcgctatgacccag\n\ +aggtgttctaacgtctgttttgatccgcagaatttctgcctcaatgcatatttgacggac\n\ +ttgaactagagcctctaaagttaaatggcgacgcaactgttcctaaacttcaattattac\n\ +tactctttttttcctagggtattgtagaggccagtggacaaaataaatcaaatttaagat\n\ +gtttcggacattaacatcccccgtagcatagaaatcatcagttatccaatctctcatcga\n\ +gcttttacaatttctgctggcgctatggacagcatatgccgcgagacctccgcaagactc\n\ +acttgatcactgtaagtatcttcattagaggttagagcctatagttaagctgctgaccta\n\ +gtaaaattggtattttctaattttattgctcaagttaaaggttagtgaagggataatgac\n\ +gttatttttgaacaatgggttgtattcaattttatatcacgaatggaacccttcattccc\n\ +ggcataatactagacgacacgaacaagctccgatctatcagccaggcacgtgttaaggtt\n\ +taattccggcaaaccaatgaagcatcaaaaggtgacctgatgcaacttagggtcacgatg\n\ +agtttttcaggactacttattacctattaataagttaacatgagccttcataccccgtaa\n\ +gacaatacatactccaccaattagaattctgagccatcttatctttttgtatcatcgaag\n\ +ggtatggccgaataggttaattagttactcctaacgtctctacaggcatgcatttgacgc\n\ +accttcgaaaatagtcaatctctcgccacacgcgtctagtatgcagcatcaaaaatatag\n\ +tccacggtttccggattaccaaacgcggcaaagagaaacattgtatcgacggagataact\n\ +taatacagaaggaaggggcatcttcgaatacggatgaataattctatctgtttattctga\n\ +catcttgttttcaggttaatcttacgcattcaaatgacgcctgccccatgcgtgcgcaat\n\ +tattttctaatattgacgagagcaatctcactccttttgggtctatttatgttttattga\n\ +ggcacaagcctatacagaacaggtactattaaggccgtgagtgtgagactcaaaccgtgg\n\ +aaacaaaggatgggttgttcttggtacaagttttagtgcatgtgggcaatccttaccaaa\n\ +atcagatgctatccttaactttgggctgcatttaagatggcggttggaggcctgtgagaa\n\ +tcctgcgtgtcatctttaatgaccgaattcatccatgtagattcagatcacacactcatt\n\ +ccttgatgttgtctaaacaaaagttgttgtggacgcattggagggagttaagtaacaact\n\ +tgggatcgcatacttataaaaattatatgttaaactttcacaaacgctgaagtccaaagt\n\ +aactagcccaaacgcctcgagagtcactaggtattaatggtgtttgagttcctgtgaaat\n\ +agtgttcgaaggtaaaatttatgtaccaaatcgaaagaacacttaataaggcttgcttgc\n\ +acggaggtatgatgtttactgactctacaaccctaattttccagtacgtacattcattcc\n\ +aataggttagttctcaaagtgctatacaggctcctcaattgatgatatgcttcagccgct\n\ +ctatggatattagctcattttatttaggaagcccgcttagaggcttactatgagggaaat\n\ +gccaaaatgtcatacttttcggtgtgtcccatatgacaccgctttacatagaatttgaat\n\ +taaaacgcgctctcccgttcactaccatacttggtaccgtgcgcatattacatatagata\n\ +taggatcattttttaaagctgtactaggtttgatcgacaatcttatgctatactatatga\n\ +tgtaaccctcataatcaataccgatcgtacgatcctagcataggtggcaagcgattttat\n\ +gccgattattgtgttaaatagtctgtgagtgtgattatcagggctacgttggtagagggg\n\ +ttgtatagacctcgcacacattgtgacatacttaacaatatacgaaaactgatataataa\n\ +atccccttacccaaacaccaatcccgttgaatcaactaccataacgtctcccatataaat\n\ +tgcctacttgtttgcataaatctgaatacataacaccattgcaccttcttgtgttccaat\n\ +cccgttaagattgccttgtcagatgatatgcaagaacaatagcatttgctagcaattatt\n\ +aacagctcttcgaattgcctccacataacgcgggagggtatattttaatttggcaaatac\n\ +taagtactgttggcgtcatatgctattaacggttggatattaagttatgtcagccgtaag\n\ +caagagtgggcgaaatattttgttacccagtgagagcactcttagagtttggatacaata\n\ +ggccatatgttgacttaagaggacgtaactacgccgtacaccattgttcaaccgacttct\n\ +tggcaaatagaatcgtattagcaatcttaagaatagagacacgttcgtgttagggtatac\n\ +tacaaatccgaaaatcttaagaggatcacctaaactgaaatttatacatatttcaacgtg\n\ +gatagatttaacataattcagccacctccaacctgggagtaattttcagtagatttacta\n\ +gatgattagtggcccaacgcacttgactatataagatctggggatcctaacctgacctat\n\ +gagacaaaattggaaacgttaacagcccttatgtgtacaaagaaaagtaagttgttgctg\n\ +ttcaacagatgatagtcatgacgcgtaacttcactatagtaaattgaaacaaatacgcaa\n\ +tttagacagaatggtacggtcatgaatgacagtaattcgaagtgctagaccaacttaaaa\n\ +taggtaaacgtgcccgaaaccccccttaacagaaagctgctatcatggtgcagtatcgac\n\ +gtgttcagaaacttgtaacttttgagcaggtccgagcacatggaagtatatcacgtgttt\n\ +ctgaaccggcttatccctaagatatatccgtcgcaaactttcgatttagtcccacgtaga\n\ +gcccaagcgttgtgcgactccacgtgcatgcccagaaatacgagtttaaatttggttaca\n\ +tggttaattttgaccgaagcatcgcactttatgattgataattggattcaatatgtcgcc\n\ +ctatgcgaatgcaacatgatccacaatttggctataagacgtttaatccgtatcacactt\n\ +tgtttgcggctagtatagtaacgcccgtgcaccaagagtcagtaacaattataagtactc\n\ +cgcaggtacttcaaatataaaaactaatcaaacacgacccatatgatcatctgaagatat\n\ +ttggaactttctcgacaaccaccctcgtactcaatacttacactaatcgacaggcacacg\n\ +caacgtgtacagtcgcaccatattgagtcaagatttgcttagtggcgatgagcgtacacg\n\ +cttatttctctagtcacaattagttatctacgagacatcacgagggagcaaataagcgat\n\ +gttatggctacacataggcacgtatgaatatgatataagccagttaaacagtcgaaccat\n\ +cgagcaaattctcatgcaccaacccacacgttgaggcacaaagagtaagctgtttgaatg\n\ +taacttcttctgctgagcgggccccaacgtaaggatcaactagaagagaaaactcggtat\n\ +tagtttaaatgcgtcacggagcatgagtgcatttcactaagaatgtctgtgtaaccaata\n\ +taacatctatttgttatctgattgcctacttatggctttgcggtcgtggcgactaatgtc\n\ +tccaatccttttgaggtcggtaccaactccctttaaattacgctgtgcaggctcatgcac\n\ +tgcatacatatacggtagcaggtagggacctcacgcacccttattataatcaatagtagt\n\ +tatcagtcaacgaggcaggaatgctgaggtcgaggtgttggtatattttctatgtgccgt\n\ +ctaggcgactatcacgcattaccaggcgagatttaagccaattttgaatatagtcaacgt\n\ +aatttttactatgggttccaccgaaacgccttgcacaactaagaatcccataaaatatcg\n\ +atatcaaataaaagattgtgtcaataccttcatatatattttttcggttgactaacgtga\n\ +actaaggttaggggttttgtatgtctatataggaaacagtttcttttctgtcctacttta\n\ +gtaaagtcttcaagccttactccaaaatcacggtgattaagccgttactcagcagcatga\n\ +ttctgcctgctcgggtcctaaaatccagccttgtaagagtcgctgtgtattagctaggga\n\ +gacctttgttaaaaaggatatatcgcggcgggatgtgagtgcgtggcgcatactcaatct\n\ +tcagctcgtgtcattataatatctctcccccacgcttttcactagatatgccgtgtaagc\n\ +aaacaccttatgcttaatttcgaaaatattggtacttgaaaaaagctgtaggggtactta\n\ +atgtctggtaggagatcaggagagaattgagtgtaaaaccgtaaagccctcacctgactt\n\ +catgtaaatggcttagaagactccatgatttaataaatactacgaaggaaagactggatc\n\ +taaagataactctagtaaggccaactcccttcaatgctgttgccagttataatccaagag\n\ +ctgtccttttctgaaccatagcggcttctgaagcgaactagaagcaaagttggttctagc\n\ +cagacagccacataccctgtacgggtgtattactaaaactggtccggtattagttcacca\n\ +agggaggaattaggcaaaggatctaggtatgcaagtcggagtattacatccctaccctga\n\ +atccatcaataggttcctctgtactggccttcgcaatgagtattcaaggttgtacagccg\n\ +tataataataagatagtgactatgaacgggaagtaacccgctcaccttccccaaaacatt\n\ +gttatatctaagtattaaagtctgccgtagtgttaatactcgaaaataaacaactggcaa\n\ +attacaccgcacttaagccgcttttgatttatatttttccaatgcgcttttaaaaataat\n\ +tcagtcctacatactaattaagacccttaaacggagatatcacaagttaagttttaacca\n\ +tctcgactaggtggaactatagatacccaactcaatttatcattacctgtaatgttccta\n\ +gaaggattgcatttcatgtcaagacggtggagtttcacagcgaaacttcagtgtgaacag\n\ +attctgagaaatcacctaaacctattagtcagagcacccggttagaaccagttgtcaaaa\n\ +aatagagcggttgcatgagacagaagtaacgatgagatccgttgtaacgttgagacatct\n\ +ggcctatcgtcaatacagtcctcccttaaaaatatttttaaatactaggcaaacccaaca\n\ +taggttagtcctatgtgatacgccacatggtatatcattttgtaacgttacctagggata\n\ +atcaggaagtggaattacgcaaaagtagacagtgaaatgcttagggttatagtctagtcc\n\ +aaagataaaggataaagcacgtcagagaactatattagccgaatgggaatcattgttagg\n\ +agactgtggatcatgtctaaaaagcaacgcagaaacagtcatcgaaaaaatctcgttttt\n\ +gtttgaatctaaaagagctttgatgaccgatagtacctgtatactagttactgtattacg\n\ +tgtctaatgatttcggattggggtccccagaatcagacgtcattgtagacgattcaagtt\n\ +taccaatttaatttcccagctctccttggagaactatcgccaataattgcagtcactttc\n\ +cttttctgaaacgataaagccgtcagagttctctgcaacgttggacttacctgaggttct\n\ +aacccactttcggttctaatagtagttaacgacacaacgaataacctttactgtggggct\n\ +ttcacgatattttttcgcttattattaatggttacgtcataagctggtgtccaaattaag\n\ +gttaccggcttcgcagagtagttgtatccaagtataacttccctaatcataagatcgagg\n\ +tagaaaattaatgctgtctctaaccgaacagatatgtcccactatgtggtatggacgttg\n\ +ctaattacttctgaagggaaattggtcattatggatacgtgtctaccatcaggtcggacg\n\ +cagatatggttctgtcttcagttgatccaccgttctttataggataataactgacgatta\n\ +aagattatggtaaatagattaagccaattctcttcttgtcagtgaagcatccttaactga\n\ +cttgctctgcagcccctcatacatttagctattcaaagtaccggctcgtttcaaactctc\n\ +ccacctttggaagaggttgtcaacttgataagtatatcatttacagcattttttcggacg\n\ +tacctctaatgtttcattgcagaaaattagttttttctatcgcacattttgcaagtaacg\n\ +ttagagacacaattatctgcgaatgaactgctagatctgacgaccgggagcctcgcaaat\n\ +atcaaaaaagactgacatatatcaaggagtcgttgacaagtgctggtaagtcaattggtt\n\ +tatctgtcccggcgtttcgatcttaagctgaccatgcacggcagagtaatgtcactctcg\n\ +ttcttacaagtctgtctccaagggtcggcaaaaaagacccctccattctcgagcccactc\n\ +acgatatgtagggacgacaacttgtgcggcttatgaattgtctggactgcgggcgagggt\n\ +ccatatctccgaagttagaagggacatacctttagatgataagatcaattcttattgacg\n\ +aaattcatccacaacggggaacaacttcaccctagacttacgtctgaaaagacacctagc\n\ +gtcttataaaaggtcagtgccccgtttcgtaaggctggaattacctacgcaaacttaaac\n\ +ctcgcgcccttccttacgtatcgacaagatagaggctatcgcgaatgtactacggaggca\n\ +tgaatcatatactagaaccaagtgcctgtgatattaacaagatgatccgacgcgagcacc\n\ +gtaattctaggcataaaactccagcaatttgggggccgaaaacaaatgacgttagctaat\n\ +taattatatgacatgatcaaaggaggtcaatcacgcatcgagttcgacgtatattcattg\n\ +aacttcgtgcgtttgaaagaaacttttatgaaggcaaaattgatcctgtctcctatttca\n\ +tgcgtacctcctagttgataattccccgagcagtggttaggacacttttgtcggtatcaa\n\ +gttccggtctcaaaacgtaaaattctgtaatctgtatggatggtctgtgaattagttaat\n\ +ttttatgaagtcgtcgagacgcagttcctattgatttattctaaacggagatgtgcttcg\n\ +tgggactcggaagtagatctgtgtttatgattattgctactttagatgctgactgttaac\n\ +tccgtgttgtttttcaaccgtatatcacaaccgaattggatagaacctatagtttcaagt\n\ +tctgccacaaggtatcatatttacagttagtgctggttgcttctttcaaacgtggtgagt\n\ +ttgtgctatcacgtcaacggtagagctcagtggaccgagtgcgcgttcaaccctgttcca\n\ +gagagggtgtgatagcacatataccacgctcgtcgaggcgttcatgatagtttgcaagag\n\ +ccggtgttaaacacatattattattgttatccaactaatcggacctatgcataaagcatt\n\ +gtctaaacagaataattgcctatatacggtagttttagtgatttatatcttagtatcagt\n\ +tagagcttcgaactcttcaggttcctcatatttaacgttcttcgaaagcgaaaacttcta\n\ +caaacgaatgtaagcggttttccaagtagtacctataaatcacagaaagatctgtctcag\n\ +tatagttgaaatggtattcagctagtgacgtgtaccaattatcatagttcactcaagcaa\n\ +gacgctcattaacgaatatagacaagacactatatcatataataaaaaagaacatggtgc\n\ +tcgaacatagttgaattcaccatattgaaggggaatgctgacatgtaattcgctactaga\n\ +cgatcaattccctacttgtcaaagttgaactggtacgttcttggaattaaatatgattgc\n\ +gctggaccaaattgcgacttcttgagtttcagggcaaacgattgagccggaggatgtccg\n\ +tctcttacctttcttgcttatgataaacgacggtccctgtacatcactgggaattctcag\n\ +caaaaataattgggtaaatcgagactcgatgtattcggccacaaaggtgttagacgttaa\n\ +agattattcaacggggcgataataggatcataaccggtatgcaagcgcattgaaagagcc\n\ +atgagatccttatccgataaacgctgcacggtatgtgcagccttattgtcgatcacgaat\n\ +ttataaatgtagtctgggctgtaagttgaagacctaagttataatgaagtgcaataccaa\n\ +atcgattcatagtggattatcagactcaagatatctcctgataaattacagttgttaaga\n\ +tacggataaaatgagatttaagattagcagcctctaatctgtttcaatcccgttggaatg\n\ +tggtatgcgatcaaggttaagttaaaatcaagcctgtcttcagtcttgattcttgttctg\n\ +ccatcgcatgcggtctacgtgagttaatatgtagcttacgttctagcttgtgctaatctg\n\ +agtatagattcgtagaggaatattatcaagcttccacgcctcaacgtacgtgtattggtc\n\ +acacaagacactaaaagtggaagtagcgtaaactatagtctagttgttaaatgctcagtt\n\ +cttgttatattcgatatactcttggctaatttatgtctgagtatataaaattaatgatat\n\ +taacttgcatttcacggatcccttagaaaaagattttgaccgagcgcattataaacggtt\n\ +acaccgaatcaatagaagcatacccaatagctttctttgaatttattgcctgcgcaactt\n\ +ggctgactctctagatccgaataattctatatggtcgtgacgaaactagttcattactgt\n\ +ttaaaatgccaacatgtcttttgggccgataatggctctttgcaaaattactcaatgata\n\ +cgattgatcaaagcggtagttgctagtggtagcatgtaagtctatcaaatgtctgattat\n\ +ccgaaaatcttccaaaagagtccacgtaccatatctatctcatagcgacgcgaggggaac\n\ +cttatctaactatcattccatttaccgggtgactctcgatgcaggatccgattgggataa\n\ +attgcccagaaatggctcattcctgactaagggtaaggccgttctcagcaagggaacccc\n\ +gcgaatctaggcttataccatctagattgttaactacttgcctgtagttctacagccata\n\ +ctggacagttgtttctaaatgatcgggattcatgctagcactcctctgaatgcaccgcgt\n\ +aagtttaactattacgtccgtgggcagataaggatggaggctgtatgtatcttaactgtt\n\ +acctaatatggctggtaattatcaaagtaaggaccttaatgccatagcgctagcaatcgc\n\ +tttgtatactgaccatgtgccaacctctcttaatctgtaaaatataatgtcttagctaac\n\ +tgtggacgatcatgtctctgcctagagcttcgctgtatcaattcctatagccagcgtact\n\ +agtgacacaacaacaccgtgtgagaaaagatattagtccttacgtctgtctctctacagc\n\ +ttattgatgaggattgaacatggacatatagctccccctcaaaagcagatgctacctctt\n\ +tattccattctcgaacatttgccgaacttaatttcgacaaacctgaggtcacgtcttaat\n\ +ttatcggtaacgtcacgtccctttgagactggataaatatattaccaggggccaacgagc\n\ +aattgttggaggcgcttctataatacaaggtgtcttgtcaaagaaagacggcgtgcgtct\n\ +cgtgcaactcacttaaccaatattaatgtgaaacccccctctctcacatcttatgcggtg\n\ +tactgccctggtacatttcctgtacaggactccaacagtgtagattcctaagatagctgt\n\ +tggagttgcctcacgccagatcgaaaaactgaataaactagtgagctgagctgcagaaat\n\ +accgcttaattacttatgactagttcaaagggacctacgtgatgtcagacattgcaagga\n\ +agaaattaggtttgtgcgtcattttggctggactagcactccttacttcccctactattc\n\ +aaatgtcgtaaacagcatgagacaggatcgtgctgacatttaaggtctattgggaacgag\n\ +gctacctttggtcgcgcgctcgcgttctccgaatgaccgaaatgcatgagcacagtatgc\n\ +aattgcttatagatctaaggtctggtcgttgaaaccaagcacgtaggcctgggaaatcag\n\ +ttcttcctcagcaactacacaaaagcgtccaagcattagtacttgtagtaaatgtccgaa\n\ +cctatgcgctcatttgaaagtcaaaaaatatttttaagcagtaggcacctaacccgattc\n\ +ctctacttagtagctttctttgattctcagaattgactgcaatatcactgcacaattctg\n\ +tgccattactagacttctctgtattaacgtctcatcttactaacactcgcctaggacaca\n\ +tctgagagtgaagtatttcaatacatttactgaaatcttcagttctaaaatccccgaata\n\ +aggctcttatcggtttggccaacacaagaaaaaaacttcttgcaccactcaccttcatac\n\ +gcaggagcctggggaacttagtaataactatttcggcagacaaagcttataacaagttgc\n\ +cggcgcgtataatatttaaaagaccccttgagctgctcaattaaaacgctcacctggtat\n\ +aggctattagatagtgccgtcttagtaaggggcgggaattatcggataaactgatatttt\n\ +gataaaataaccgacttgttcacgacataagtcactaaggagattttatctttctccaaa\n\ +gtatatcttccttggataatttcaaagcgctgcaatttaagttctgttactagtttatgc\n\ +tgctgggaggtgaccggaaggcgtagtaatctagaggcaaattataagaagttcatcata\n\ +tcattttcgactacaaaaacaaggtgttgtatgccggcgcattgtgtaaactggacgagt\n\ +accctagatggaaaattatacgttaagccaagatttcgatgtaatgataattacctacac\n\ +atttttgctatccataggaacaagagctgttctataggctcgtggcatacgaacatttgc\n\ +tgccgctatgaatattggaagctcttcaactacagactctattcttaattgccgtcgaaa\n\ +atgggccgaatcggctattattaatactcggtttttccgaggggattgttgtcgacagtc\n\ +gtaattattattaatattgatgttggtgaggtcatttaaatacaaccttgcagacaatga\n\ +ataagggatccaatctctcatactccttttacaattgctcatgcccctatgcaaacctta\n\ +tgccgccacacctccgcaactctctcttctgaactgtaagtagcttcattactggtttga\n\ +gactatactgaagctgatgacattctaaaatggctattttcgaatgtgattcataatgtt\n\ +tatcgtttgggatggcagaatcacgttatttttgatatagcccgggtattctattgtata\n\ +gaacgtatgctacaagtcattccccgaagaagactagaagtaaacaacatgcgaccatcg\n\ +ttaagccacgcaaggctgtagctttatttcccgataacctatcttccataaatagcggac\n\ +agcaggatactgacgctcaacatcagtggttatggtctaatttttaacttttaataaggt\n\ +aacttcagcaggcatacacagtaactctttaatttataatcaaattagaagtctgacact\n\ +tcttatatttttctatcatccaacgcgatcgcccattagcttattgtgttactaataacg\n\ +tatctaaaccaatccttttcaagctactgcctatattgtcaatatatacaaacaacagga\n\ +tagtaggctgcttaaaaaatattgtcaaccgtgtacgctttacaatacccggaaatcaca\n\ +aactttgtagacaacgagtgaaatttatacactacgaagggccagcgtacaagacccatg\n\ +aattaggcgatatgtttattctgacatattggtttatccttaatctgtcgctgtaaaatg\n\ +aagccgcccccatccctgcgaattttttttcgaagattcacgactgaaatataaatacgt\n\ +ttggctatatttatgttggagggaggcaatagcctttactgttaaccgaagatttagcca\n\ +gtgagtgtgacactaaaacactggaataaatgcaggcgttcttctgggtaaaaggtttag\n\ +tcaatctcgcctataagttcatatagctctggatataattatctggcccatgcatttatc\n\ +atggcgcttggtgccctgtgtgaagccggcctctcatattgaaggtccgaagtattccat\n\ +gtacattaagatcactctctcattcatgcatcttggcttaacaaatctggttgtccaagc\n\ +tttccaggcacgtatggtacaaattcggatcgaatacttataaaaatgatatgttaaact\n\ +gtctaaaacgctcatctacaaagtaaagtgcactaaccaatagagtctcaagaccgtgta\n\ +atgctggtgcactgaatgtgtaatacggttagaagggattagttatgttacaaatccatt\n\ +gaaaacttaagaagcattgcgtgctcggagggtgcatcttttatcaagagactaacatta\n\ +ttttcaacgacgtacatgctttacaatagggtacttatcaaacgccgagaaacgcgccta\n\ +tagtgatgttatgattatgacccgatatccattggaccgaattttatgtaggttcccagc\n\ +gtactcgcgtaatatctcggtattgccataatgtaatacttgtcggtctctcccagatga\n\ +aaaagcgttacagagtatttcaatgaaaaacagcgcgcaacgtcaatacctttaggggta\n\ +acggccgctgatttcatatagatatacgataagttggtatagctctactaggtggcatcc\n\ +acaatcgttgcatttactatagctggttacaatcataatctataccgttccttacatact\n\ +accatagcgggatagcgtttttttgccgttgattgggtttaagaggatgtcagtctcatt\n\ +atatccgattcggtgggagagccgttgttttcaaatcgcacactttgtgacataatgtac\n\ +aagataacaaaactgatataagatataaactgtcaatatcaccttgacacttgaatcaaa\n\ +gtaaattaactcgcaaatataatttgactaattgggtgcagatttctcaattaataaaaa\n\ +aatggcaccggatgggcttacaagccccttatcattcacttgtatcatgatttccaagaa\n\ +caatagaatttgctagcaagtatgaacagagattcgaattgcatccacagtacgccggag\n\ +cgtttattttaatgtggatatgacgatgtactgttggcggcatttgctagtaaccggtcc\n\ +ttatttacgtagcgcacacgtaagcatgtctgggagaaatatggtggtacaatctcagag\n\ +aaagattacagtttggtttaaataggacttatcgggtcggaagtggaacttaataagcag\n\ +tacacaattgggcaacagacgtcttgcctattacaataggattacaatgcgttagatttc\n\ +agacacgttcgtgtttggctattcgtcaattccctaaatagttagacgatcaactattat\n\ +caaagtgattctttgttcatcctccattcatgtaacagatggcacactacgcataacgcc\n\ +gaggaattttaacgagatttaagagagcagttcgggcacaacccacttgactttataaca\n\ +gctcggcagcataaacggtaatatgtgacaaatttccaaacgttataagaacgtatgtgt\n\ +acttagaaaactaagtggttcatgttcaacagatgtgacgcagcaagcctaacttatcta\n\ +ttggttttgctataaaagaacaaagttacacagaatcctaagggcttgtttcacacttat\n\ +gcctagtgcttcaccatcttaaaatagcgaaaccggcacgaatcaaaccttaaaacaatg\n\ +cgcagatattggtgatggtgactccgggtatgataatggtaactgttgaccagcgcccac\n\ +ctcatcgaagtatagaaagtggttaggataaggatgagaccgaacttatttccggccata\n\ +actttagattttctacctagtacacaacatcagggcggacacgaaaccgccatcacatca\n\ +tataccaggtttaatttgcttaatgggggaagtgtcaacgaaccttcgaactttagcagg\n\ +catatggccattatatatggccccagagcagaatgctacagcagacaaaatttggattta\n\ +tgtagtttaatacctatcaaacttggtgtgaccatacttgtctaacgacagtgcacaaag\n\ +tgtaagttacaattattactactcagcagcttctgcaatgataaaatcttatcatacacg\n\ +tcacatatgataatatctacttagggggaacgggctccacaacctacatagtactcaata\n\ +cttacactattcgacaggcacaccaaacctgtacagtcccaaaagattgagtcaactttg\n\ +cagtactgcagatcacagtaatagcttagttagcgagtcaaaattagttttctacgagac\n\ +tgcacgaccgtgcaaatttccgatgtgttggctacaaatagcaacgtatgaatttgtttg\n\ +aagccacgtaaactgtacaaccttagagataagtctcaggctactaaaaacacgttgtgg\n\ +cactaacaggatcatggttgattcttacttattcggctgaccggcccaataagtaacctt\n\ +caactagaacagaataatcgggagtagtttaattcagtcaaggtgcaggtctcattgtaa\n\ +ctaacaagctctgtgtaaccaagttaaaatcgttttcttagcggattccctacttatgga\n\ +tttgagctcgtccacaatattcgatacaagaagtttgtggtccgtaacaacgaaatttta\n\ +attacgctgtgcagcctcatccaaggaattaatagaaggttgatggtaggctccgaacgc\n\ +tccatgattataatcaagtggactgtgcagtaaacgaggaaggtatcctgacgtcgtggt\n\ +gttcgtttttgttatttgtgccctatacgagtagataaaccatgaacagcacagtgtgaa\n\ +cccatggttgattttaggctaccttatttttaatttccgttacacagaaacgaattccac\n\ +aactaacatgccattaatttttcgatatcttataaaagatggtcgaaattcattcattta\n\ +ttttttttcggttctcgaaagtcaactaagctgtcgcgttttgtttctctttagaggtaa\n\ +aagtggctttgatctcctacgtttggatactagtcaaccattactccatttgatccgtga\n\ +gtatcacctgtctaacatccagcattatgactcctcggcgaagaaaagacacacttctta\n\ +gagtcgatgtgtattagctagggacacagttgtttaatacgatagtgagcccagggaggg\n\ +cagtgcgtcccccagtagatttattcagctagtgtaagtataagatatctcacccacgag\n\ +gttcaagtgatatgcagtcttagaataatacttatcctgaatttcgatattatgggtact\n\ +tcaataatccgctagcgctactttatgtctcgttggacagcaggacacatggcagtctta\n\ +aacactaaagacatcacctgaatgaatgtaatgggattacaagaatcaatgaggtattat\n\ +atacgacgtaggaaactctggatatatacagtaatctagttacgccatcgcacttcattc\n\ +ctctggaaacttagaagacatcagctgtacgtggaggaaccagacccccgtatgtagcca\n\ +aatagaaccaaagttgcttatacaaacacacccaatgacaatggaccgctggagttcgta\n\ +aactcggaacgtagtactgcacaaacccagcatttagcaataggagctacgtatgcaact\n\ +cccacgtggtaataccttcaagctatcaatatataggtgcctagctaatcgcattcgcaa\n\ +gcagtattcaagcttgtaaaccagtataataattacagaggctctatgaaacccaacttt\n\ +ccagctaaaagtcccaattaaatggttatttcgtacttttaaagtcgcccgttctgttat\n\ +tacgcgaattgattctactccaaaattaaacacaaattatcaaccgtttcatttatattt\n\ +gtcaatgcagctgtttaaaataaggctctactaaattataattaagacacttattaccag\n\ +atttctctagttaagtttgaaccagctcgactaccgcgaaagatacattcccttctctat\n\ +ttttcagttcatctatgggtcagagaagcattgaatttattctattcaccctcgtcgttc\n\ +acagcgaatcgtcagtgtgatcagtgtatgagaaatatcctaaaccgtttagtcagacca\n\ +cacgcttagaacaagtggtctaaaaagactgccctggaaggagtaagaagtatacagctg\n\ +atccggtgtatccttcagtcatctgccctatactaattacacgacgcaaggaaaaatagg\n\ +tttattttctaggcaaacccttcataggtgactccgatgtgttacgaatcatgcttgaga\n\ +atgtgctatcgttaccgacggataataacgatctccaatgaaccaaatgtagaatgtcta\n\ +ttgattacccttttactattcgacttagagataggagatagaacctcagtgtactttttt\n\ +agccgaatgggaatctttgggaggtgaatggccataaggtcgtaaatccaaccctcttaa\n\ +agtcttccatattatatcgttgttcgtggaatcgataacagatttgttgacccatagtaa\n\ +atgtatactagtttatgttgtaagtgtagattgttttccgattgccgtccaaactttatg\n\ +tcgtaattgtagaccagtaaagttgaccaaggtaagtgcccagcgatcctgcgagatcga\n\ +tcgccaatttttccagtcactgtaagtgtaggtttagataaagccgtatgagttatatca\n\ +taagggcctcggaaagcagcttcgaaccaaagttcccttataatagtagtttaactataa\n\ +aagtatatactggtctgtcgccctttcacgatttgttttaccggtttatgaagcgttacg\n\ +tcattagagcggctccaatttaaggttaacggcttccatgtgtagttgtatacaaggata\n\ +acttaaagtatctgttcagcgagctagttaagttatcctcgatagaacacaactcagagg\n\ +tcccaagatcgggtttgcaacttgctaatttattctcaaggcaaattgggaattatcgat\n\ +acctgtataccataaggtcgctcgatgtgatgcttatgtcttctggtgatcctaccttag\n\ +ttagtgctgattaacggaacattaatgtttatcgttttgagatttagccaattctctgat\n\ +tctaactcaagatgccttatctgacgtgctatgcagcccctaagtattttacattgtaat\n\ +aggacacgctcctttaaaactcgccaaaaggtcgttgtggttctctactggttaactata\n\ +taatttacagctttgttgagctagttcctctttggtttaagtcctcaatattagttggtt\n\ +cgagcgataagttggctagttaccttagtcactatattagatccgaatgttatgcttcat\n\ +ctgaagaccgccaccctccaaaatttcttttaagactcacttattgcaaggtgtaggtga\n\ +attcggctcgtttctcaagtggtgtatctgtacacgagtttccatattttcatcaacagc\n\ +caccgcacacttatgtcactctaggtattaaaagtcgctctacaaggggacgcaattaag\n\ +aaacagacatgctagtcaaaaataaacatagcgaggcaccactaattcggccgcttatca\n\ +atgggatgctctgcgcgagacgcgccagagctcagtagttagttcggacatacatttact\n\ +tcagatgatcaattagttttctacaaatgcttactctaccccgaaaaaagtcaccagact\n\ +cttacgtctctttagtatccttccgtcttatataaggtcagtcccccgtttcggtaccct\n\ +ggaatttactaagaataatgaaacagcccccaaggacgtacgtttacaaatgatagacca\n\ +gatcgcctagcttattccgacgcatgttgcatagaattgaaccaacggaatgtgagagta\n\ +actagatgagccgaccacagcacccgtttgcgtcgcagaatacgcctgatagttcggcca\n\ +cgaaatcatatgtcctttgagtattaagtatttgtaatgatcaatcgagctcaagcaagc\n\ +ttacacttcctcggatattcagggaacttagtgcctttgaaagatacgttgatcaacgaa\n\ +aaattgataatggctcatatggaatgcctacctcatagtgctgaattaacacagcactgc\n\ +ggacctaacttttcgaggtttcaagttcacgtctcaaaacctaataggctggaatatgta\n\ +gggatcctcggtgaatttgtgattgggtttgttgtagtactgaccaagtgaatattcttt\n\ +ttttctaaaagcagatctgctgccgggcactacgaaggagatctctgtgtatcattattg\n\ +cttcttgacatgatgactcttaaatcactgtgggtgtgcaaaacgatagcacaacccaat\n\ +tcgatagtacatattgttgatacttcgcactaaaccgttcatatttaaaggttgtgctcc\n\ +ttccttcgttaaatactggtgacttggtcctatctactattagctagacctctggggaac\n\ +cacgcccccgtaaaacctgtgcaagagagggggtcatacatcttagacatcgcgcctcca\n\ +ccagggaagcattgggtgattgaccaggtgtgtaacaaatatgattattcttatactaat\n\ +attagcaaagatgcataatgatttgtattaaatgtataattgaattgataagggtctttt\n\ +agtcagtgatagagtagtataaggtagacattagaactcttaaccggacgcagatttttc\n\ +ggtcttagtaagccaattagtcgacaaaacaaggtaagagcggttactagtagtacctat\n\ +aatgcactgaatcttcggtcgaagtatagttctaatgctatgcagattgtgacggcgaca\n\ +aatgttcagacttatatcatgaaacaagctcttgtaagtattgacaaatgaaaagattga\n\ +atatttttaaatacaaaatgcgcctacttattaggggaattaaccagattgaaggccaat\n\ +cctcacatgtaatgagataatagacgataaatgaaattcttgtaatagttgaactgctac\n\ +gtgatgggtattatatatgattgagatcctccaattgccgacgtcttgtcttgatgccca\n\ +aaagattgtcaacgaggagctccctcgcgtacctgtcgtccgtatcataaacgacgcgac\n\ +atgtacagcactccgaagtataagcaataataatgcgggtaatccagactagatcttttc\n\ +ggactcaatgcggtttcacggtaaacatgattaataccggagagtagtcgagcttatcag\n\ +cgatgcaagcgaattcattgtgccaggagatacgttgcagataaaaccggcaacgtatgt\n\ +caacaagttttggcgatctcgttgtttgtattcgacgaggcgcgggaacttcaagaacta\n\ +tcgtatattcaagtccattaccttttagtttcagactggtggagctgactaaagttatat\n\ +catcattttgtacactggtttagttaacgataatttcagatttaacatgaccagacgata\n\ +atcgctgtatatccagttggaatgtggtttgccagaaaggttaacttataatcaagcctc\n\ +tcttcagtcttgattcgtcgtatcccatccattgcgctatacctcagtgtatttggagct\n\ +gtagttataccgtgtgctaagatcagtagacatgacgagagcaatattatctaccttaca\n\ +agcatcaacggacgtctagtcggaacaaaagactctaaaactcgaacttcaggttaatat\n\ +actatagttctgtattcagcagttattcttatattcgatattatcttgcctattggatgt\n\ +ctgactttagtatattaatcatagtatctgccatgtaaaggtgccagtactaaatctgtt\n\ +tcacagtgcgaattataaacggttacaaccattaaagacaacaagaccctatagctttat\n\ +ttgaattttgtcaatgcgcaacttggagctcgcgatacatcccaattagtctatagggtc\n\ +gggacgattctacggcatttctggttataatgacaacatggattgtggcccgagaatcgc\n\ +tctttcattaattaagcaatcattacagtcttataagcgctacttccgagtggtagcagg\n\ +taactcgatataaggtcgcatgagccgaatagcttaaaaaacaggccaccgaacattgat\n\ +agagaataccgaccacagcgcaacctttgattactttcattaaattgtacggctcactcg\n\ +acatcaagcttaagattgcgataatgtgaactcaaatggatcagtactgaagaaccgtaa\n\ +cccacttcgcagaaagcgtacccagagaagatacgctgttacaatatacagggtgaaatt\n\ +attgcctgttcttcgtaaccatttcgccaaacttggttagaaatgatagccattcatgat\n\ +agaaataagctgaatgataccagtatctttaactatgtagtcagggggaagataacgatg\n\ +gtccatgtatgtttctgatatgtgacagtattggccgcgtaatttgctaacgaagctact\n\ +taatgcctttgagcttcatatagatttctttaatcaaaatcggcaaaaagatagtatgag\n\ +ctataatatatgctagtagagaactctggaccatcatctatatgaatactgattcgagcg\n\ +tgcaattactttagcctgcgtactactgactctacaaaacactctgagataagtttgtag\n\ +tcagtaagtcgctctctataaaccttttggatgaccattgtacagccacttatagatccc\n\ +aataaatagcacaggagacagagtttttcaatgctcgatcatttgccgatagtattttcg\n\ +tctaacctcagggcacctattatttgatacctaacctaacggccctttcacaatggagaa\n\ +atatatgacatcgggacaaacacaaatggtgggtggccaggagatatgacatggtggcgt\n\ +ctctaagaaacacggactccctctaggcaaactcacgtaaccaattttaatgtcaaacaa\n\ +aacgctcgaaaagattttgccgtgtaatgacctggtacattgactggtcaggaatacatc\n\ +actgtagttgccgtagtgtcctgttggtgttccatcaagacacatcgtataacgcaattt\n\ +acgacggacatcagatcaagttatacagattatttaagtatcacgtgtgcattgggacat\n\ +aagggatctcacacatgccttggaacatttttgctttgtgccgctttttcgctgcactac\n\ +caatccttacttaccagtatattcaaaggtcgttaacagaatgagaaaggttagggctct\n\ +aagttatcgtcgattgggatagacgagacatttgcgagcgccctccacggatacgaatct\n\ +cccatatcaatgtgaactggatgctatgcagtttagttcttacgtctcctagtggtaaaa\n\ +atcaaagtagcactcgcatagcagttattcagaacctaatacacaaaaccgtcaaacatt\n\ +ttctaattctaggtatgggccgatcataggagctaaggtgaaactcataaatgttttgtt\n\ +agatctagcatcctaaaaagatgcatatactgagtagctggcgtgcattctctcaattgt\n\ +atcctttttaactgaactagtcggtcccatttcgtgactgagatctattaaccgataaga\n\ +ttaataacactcgcattcgtatcagctcagagtgaagtttttcaataatttgactgatat\n\ +attaacttctaaaataaccctttaagcctcggatccgtttcccaatcacatcaaaaattc\n\ +ttattccaactatctacggattaacaacgtgcatggggatcgtagtaagaacttgttccg\n\ +atcactttgagtatatcaagttgacggcccggttattattgaatagaaacattcacctgc\n\ +taaattaaataccgcacatcggatacccgatttcagagggccgtcttactaagggcaggc\n\ +tttgttcggtttaactgagatgttcattattttacagtatgcttcaactaatatgtaacg\n\ +aaggacagtggatctgtctccatagtagatcttcagtcgtgaatttcataccgctcctat\n\ +ttaagttcgcgttcgagttgttgatcatggcacgtgaaagcaacccctagtattctagac\n\ +gaaaattttttctagttcatctgataatttgccaattcaaaaacaaccgctggtttcccg\n\ +gcgcattctctaaaatggaagtcgaacctagagccattatttgtcggtaacccatgagtt\n\ +ccttcttttcagaagttaatacactgtggtcctatacagaggaaaaacagcggttatata\n\ +cgatcgtggcataacaacattggatcaagatagcaatttggctacctattctaattctca\n\ +ctagattcggtattccactacaatatcggcagattaggattggatgaataatcggtgttt\n\ +aagtccggttgcgtctccaatctcctaatttttattaatattgatcttggtgacctattg\n\ +taaataaaaacttcaagactttgaataacggtgaaaagatagaagactcatttgaaaatg\n\ +gatcatccacagatccaaacattagcaagacactaatccccaactagctattctgatcgc\n\ +gatcgtgctgcagtactcctgtcacaatagtctgttcatgatctaattctttttgggctt\n\ +tgttcgatggtgattcagaatctttatccggtcgcttccctgtagctactttgtggggat\n\ +attgcccggggattatagggttgagatcgtttcctaaaagtatttaaaccaagtagactt\n\ +caactaaactacatcagaacatcgtgaagacaccatacgcggtacctttatttaccgata\n\ +acatttcttcaagaaataccggtaagcagcataatgaccctaaacagctcggggtatcgt\n\ +cgtagttttaaattttatttaggttactgctcaaggaataaaaactaactatttaattta\n\ +taataatattacaaggctcacactgattagatttgtctataagacttcgcgatcccccat\n\ +taccggattgtcttaagaataaactagataaaccatgcattttctagataaggcctttag\n\ +tctaattagatacaaaaaacacgatagttgcatccttaatttattgtgtcaaacctggaa\n\ +ccttttaattacccgcaaatcactttatgtcgagactacctctgaaatttattatctacc\n\ +taccgcatgaggacttgaaccatcttgtaggagttatgtttattagctaagattcgttta\n\ +tcctgtagcggtccatgtatattcaacaagcaaaaagcactcagaattgtttttagttga\n\ +gtcaagactgatatataaataagtttccctagttttttcgtggtgggacgatattgaatt\n\ +gaatcttaaccgaagagtttcccactctgtcgcacaataatacacgccaatatttccagc\n\ +cctgcttatgccttaatcggttactcaatctcccattgaagttcattttgatctgcatag\n\ +aagtttcgggcccagccttttttctgccaccttcctccaagctctgtagacgcactctaa\n\ +gattgatgctcacatgtattaattctacattaacataaatatataagtcatgcatcttcg\n\ +agtaaaatatctggttctccaacatgtcctggcacgtatcgttataatgcccatacatgt\n\ +agtattaaaatgattgggttaactggatattaagatcatcgaaattgtaaagtcaaatta\n\ +acaatactgtctcaagaccgtgtattcctcgtgctcggaagggctattacgcttacttcc\n\ +gttttggtatcttaatatgactttcaaaaattaagttgcagtgagtcctacctgcgtgca\n\ +tcggttagcaagagtataaaagttgtttaaacgaactacttgctttacaataccggtcgt\n\ +atatatcgccgtgaatccagaagattgtcttctttggattatcaaccgagatcctgtgga\n\ +ccgatgttttgggaccttcacagaggactccaggtagagctcgcttttgcattaatctaa\n\ +gaattgtacctctctaaaagatctaaaacagtgaatgtgtatttcatggaaaaacacaga\n\ +gaaacgtaaattactttaggccgaaaggcacatgagttattatacatatacgagatggtg\n\ +gtatacatcgaattcggggcatacactatagttgcattgtatttagctgctttaaataat\n\ +atgatattaccttccttacataagacattaccggcataccctggttttcaacttgtgggg\n\ +ctttttgacgatcgcactctcatttgatccgagtagggcggtgacccctgcttttcaaat\n\ +acaaaaatttcgctatgaaggtaatagattacttttcgctgttatgatagaaacggtaaa\n\ +tttaaaattgaaacttctagaaaagtaaagtaacgagaaatgattttgtgaataatgcgg\n\ +tcatgattgcgcaagtaagaaaaaaaggcaaaaggatgcgcggaatagaaacttatcagt\n\ +cacgggtatcttgatttcattcttcttgtcaattgccgacataggatgaaatcagattcc\n\ +aatgcaatacacagtaacccccacccttgattgtaatgtcgatttgaagttgtacgcgtc\n\ +gacgaagtggatagtatacgggccttttgtacggtgcgatcaactatgaatctcggcgag\n\ +ttagatggtcgtacaatctcacacatagaggtcacttgcctgtaatgacgaattttcggc\n\ +taggtactcgaactttattagaagtaaaaatgtgggcaaaagaaggattccattttacaa\n\ +gacgattacaatgagttacatgtctctcaacgtagtctttccctagtagtctttgaacta\n\ +tttaggtactccagaaaattttagcaaagggtttctgtgtgaatccgccattcatgttta\n\ +tgatggaacaataagaataacgccctcgtatgttatcgacagtgaagtcagcagttcggc\n\ +caaaaacatattcaatttagtacagatccccagaagttaagctaagtgctctaaaatggc\n\ +ctaaacggttatcaaagtaggtctaattactatactaacgggtgcatcgtaataactgct\n\ +gtcgatgcaacactatatgatagtgtcgttttgctatatatgtacaatgtgacaaagaag\n\ +ccttagcgattcttgcaaacttaggacttcggattctcaatcttaaatgtccgaaaacgc\n\ +aaagattcaaaaatttaatctatgagcagatatgcctgatggtgactacgcgtatgttaa\n\ +ggctaaatgttgacaaccgcacacataatcgaactattgatagtcgggagcataaccagg\n\ +tgaacgtactttgttcacgacatttattgacatgttctaaatacgtctcaaaatcacggc\n\ +gcactagaaaacgcaatcaaatcattgtcctggtttaagggccgtaatgccggtagtgtc\n\ +aaacttcatgagaactttagctggcttttggccagtatttagggaccaagagcactagcc\n\ +ttaagctgaatattttgccatttatctactgttataactttaaaacttggtggcaccaga\n\ +cttgtcgatacacacgcatcaatctgtaacgtaaaaggtttactaagaacaagcgtagga\n\ +attgagtttatattatatttaaactaaaagatgatattagcttctgagggcgatagggct\n\ +ccaaatcataaagaggaatatattattacacgattagaaacccacaacatacctcgaatc\n\ +gcccaaaagtttgacgaaacttggcagtactccacatctcagtaatacagttgggagagt\n\ +ctcaaatgttgttttattactcaatgaaccaccctcataatttcactgctgttccattaa\n\ +atttgcaaacgatcatttgctttgaagaaacgtaaaatcgacaaaattacagataagtag\n\ +atgcataataaaaaaaactgctcgctataacacgatcatcgtgcattcttacttaggagc\n\ +atcacccgcacaataacgtaccttaaactacaacactattagaccgagtactgtaattca\n\ +cgaaagctcaagctcgcattgtaaagaacttgctctctcgtaaaatgtgataatagtttg\n\ +cggagaggattcaattattttccattgcacctactccactagattcgataaaagaaggtg\n\ +gtcctcccttaaaaagaaatgttaagtaacatcggaaccataagcaaagcatgtaagtga\n\ +accgtcatccttccctaagaaacataaaggtttttaataatgtcgactgtgaactataac\n\ +tgcatcctttcctgacctactccggttccttgttgttatttctgaacgagaccagtagat\n\ +aaacaatgtaaaccacagtgggtaccaatggtgcatgtgacgctaccgttgttttaagtg\n\ +cccgtacaaacataagaagtcataatcttacttgaaattaattttgccttttattttttt\n\ +tcaggctcgaaattaatgatttgttttttttgaccttctagttacgctaatatgcggtcg\n\ +cctgtggtttctattgagtcctataacgggatgggatctaatacgtttggttactagtaa\n\ +acaaggtataaatttgataccggagtatcaactgtataacatcaagctttatgactcata\n\ +cgcgaagtaatgacacaaggctttcaggagatcgcgagtacagagccactaaggggtgta\n\ +ttacgatagtgacaccaccgagcgcactcactccccaagtagatttatgatcctacgcta\n\ +agtattagatatataaccaaagaggttctagtcagtgcaactcttagaataataattagc\n\ +cggttttgcctttttaggcctaatgcaatattcagctagcccttatgtatctcgcgttcc\n\ +acagcaccactcatggcacgcgtttaaactaatcaaatataatctatgaatgttatgcca\n\ +gtacttgaataaatcaggttttttataagtccttgcatactctcgttatatactgttaga\n\ +gtcttaccccatagaaattctttcatctgcaaacttagaagaattctcagctacggggag\n\ +cataaagtccccaggatgttgacaaatacaacaaatgtggcttatacaaacactccatat\n\ +gaaaatcgaaccctcgtggtagttttagccgaaccttgtacggataaatccctccatttt\n\ +ccaatagcagatacctatcctactacctcgtggtattaaattaaagcttgaaatatagag\n\ +ctgcatagcttatccaattcccaagcacgagtctaccgtcgtaaccacgatttgatttac\n\ +agacgctagagcaaacccatctttaaacatataagtaaaaattaaagggtgagtgcgtac\n\ +gtgtttactagcaacttcgcttattaagacaattgtttataagccataattaaaaacata\n\ +tgttcaacaggttcattgatatttgtaattgcacaggtttttaataaggatctacgtaag\n\ +tataatgaacaaactttttaccagagttatattctgtactttgaaaatgctcctctaccg\n\ +ccttagagactttcaattagattttttgcagttaatctatgcgtaagtgaaccatgcaag\n\ +ggatgcgattcaaccgcctcgtgctaaccctatcgtctgtctcataactgtaggtctaat\n\ +ataattttcagttttcgaacacataaccctttgaaaatctgctatttaatgtctcacctg\n\ +catgcactatcttctatactgctcagaacggctatacgtcactatgctccaagtgacgat\n\ +ttaaacgaagcaaggaataataggtttattttagtgcaaaacaattaagtgcggactacg\n\ +tgctctttacaataagccttgtgattgggctataggttaagtcccatattaacgatctcc\n\ +aatgtacaaaatcgacaatcgctttgcattacccggttactagtcgaattacagatagct\n\ +gttagatactcactctaattttggacaacaatcccaatcttggggtcgtctatcgcctga\n\ +agctcgtaaatccttccatcttaaacgattacatattatagacttgttcggggtagagat\n\ +atcacagttgtgcaaacattgtaaatcgatactagtttatgttggtagtctagttgcttt\n\ +taccattccccgaaaaacttgatctactatttcgacaacagtaaacttgaactaggtaag\n\ +tgaaaacagagaatgcctcatagtgccactatttgtccactatatgtaagtgtagcttta\n\ +cataatccactatgactgagatcattacggcctaggaaagcagcgtagaaaaaaagggcc\n\ +cggatattacgactgtaactataaaactagttactggtagcgcgccatgtatagatttgt\n\ +tttaccggttgtggttgcgttaacgaatttcagccgcgaaaattgatccgttaaccagtc\n\ +catctcgacttctataaaacgataaagtaaagttgatgttcagcctccttcttatggttg\n\ +catcgagagtacactactcagtgggaaatagatcggggttcctacttcagattgtattat\n\ +ctaggcaattgccgattgtgccatacctggataaaataagctacctacatgtgatgctta\n\ +tctattatcgtcatactaccttagggtgtcctgttgaacgctacattaatctttagccgt\n\ +ttgagatgttccaatggataggagtctaacgcatgatgaagtttaggaaggcagagcatc\n\ +ccactaagtatgtgacagtgtatttcgaaacgagacgttataaatagaaaaaaggtcctt\n\ +ctggttctattctgctgaactattgaatggaaagattggttgacctacgtactatttgct\n\ +tgaagtcatcaatttgacggggtgagagacatatggtgcatactttacggactctatatt\n\ +ttagatcagaagcttagcagtcttctctacaccccctcacgacataattgcttttaagaa\n\ +tctatgtttgattcctctacgggaattcggatccgttcgcatgtgcggtttatctaaacc\n\ +aggggacatatgttcagctaaagcatacgaacactttgctaactagacgtatgtatagta\n\ +gctataaatcccgacgatatttacaaaaagaaatgagactcaaatatatacatagcgacc\n\ +ctacacttattcgcaccctgatctaggcgatcctagcacccacacccgaaagtgagcact\n\ +agtgtcttccgtattaaatttactgcagttgagattttagttgtctactaaggattactc\n\ +taacccgtaataaggatcaagactcggtactagctttactatcattccctatgtgttttc\n\ +ctaactcacaagggtacgtaccagcctatgtaattacaataatgataaagacacaaagga\n\ +agtaactttacaaatgagtctccagttacactagcttagtccctcccatcttgctttgaa\n\ +gtctaaatacgcaatctctgaggatatacagcagaagaacactcataacgttggagtcca\n\ +agaattagactcatagggcccccaacatttaatatgtactgtgagtttgaaggtgttcta\n\ +ttgttaattcctgctcttgatacatgacacgtactccgtgtttaaggcttcggactgact\n\ +ttctttcataagttgagcaacgaaaatttcagaatcgataagttggattcactaactaat\n\ +acggctgattgaaaactccactccggacctatatggtcgacctttatacgtaaccgatat\n\ +aaaacttataggctggtatatcgagccttcctagcgcaatttcggatggggtttcttcta\n\ +ctactcaacaacggaatagtctttgtttagtaaaccagagctcaggacgcccaatacgta\n\ +ggagagcgctgtggagcatgtgtcattatggactggagcactcttaaatcactctgcgtg\n\ +tgctaaacgatagatcataacatgtcctgagtaaattttcttgatacgtcgcaatatacc\n\ +gttattagttaaacgttctcatccgtcatgcgtgaaatacggctgtcgtgctcagatata\n\ +ctattagcgactcatctcgcctaacacgcacacgtataaactcggaatgactgccgctct\n\ +tacatattagaaatacagactacaccacggaagcattgggtcattctcaaccgctgtata\n\ +aaagatgattagtcttataataagattaccaaagaggcagaatcatgggtagtaaatcta\n\ +ttattcaagtgattaccgtcgtgtaggcagggagtgaggacgagatggtactcaggacaa\n\ +atattaaccggacgaagtggtttacgtcgtactttcactattagtagtaaatacaaggta\n\ +acaccggggaatagtactaaatataatgatatctatcttcgggagaacgagtcgtctatt\n\ +gctttgaacattctcaaggcgtaaaatgtgctgacttatagcatgatacaaccgattgtt\n\ +acttttgtctattcaaaagattgaatagttttttatacaaaagccgcatacttatgacgg\n\ +ctagtatacagtttcatcccctagcatcaatgctatggacagtattgaacttataggaaa\n\ +ttcttctaatagggcaaatccgtcgtgatgcctattttttttcagtcacatcctcaaatg\n\ +gcactagtattgtcgggatcccattaacaggctcaaccacgagctcacgcgaggacatgt\n\ +agtccgtatctttaacgaagcgacagcgacagaactcccatggataaccaattataaggc\n\ +ccgtaatcctctagacatcgtttaccaataaatccgctttctccgtaatcatgttgaata\n\ +ccccagagtagtccagatgataaccgatgaaacacaagtctttctcaatgcacttacggt\n\ +gaacttattaccgccaacgtagctcatcaaggttgcgacatctagttgtgtgtttgcgac\n\ +gagcccagcgaacttcatcaactttcgtatattcaacgccttgtaattttactttaagac\n\ +gcctggtgatgtagattcttagataatcagtttgttatcggctgtactttaccataattt\n\ +cacaggtttcaggtcaagaagattatagctgtatatacagttccatgctcggtgcacaga\n\ +aacgtgatcggataataatcaatcgcttatgtcgtctttaggcgtatccaatacatgccc\n\ +cgataccgcagtgtatttcgacatgtaggtataccgtcgcatttgagctcgagtcaggac\n\ +gtcagctagattagattccttaatagaatataccgacctctagtccgaactaaactatag\n\ +ataacgccaacttcaggttaattgtctagtcgtctgtttgcagatgggattcttagatga\n\ +gtgagtatcggccatattggttcgagcactttagtttttgatgcataggatatgcaatgt\n\ +atagctgaaagtactttatctgtttcaaactcacattgattaaaccggtaaacctttaaa\n\ +gactacaagaaaatattcagtgagggcaattttgtcaatcacaatcttccagctagagat\n\ +acttcacaatttgtcttgaggctacgcaacattagacggattttcgcgttttattgaaat\n\ +aatcgaggggcccaagagtatccatagttcattttgtaagatttctttacaggcttatta\n\ +cagcttcttcagactcctacatgcttacgagttatatgctagcatgtgaacaatagatta\n\ +atatacaggaaaacgtacattgagagagatgaccctacacagcgcaaccgttgagtactt\n\ +tcattaaagggtaacgctctcgagacagcatccttaagatggccttattgtcaaatcatt\n\ +tgcagaagtacgcaagatccctaaccaacgtagaagaatccctacaaacacatgagacgc\n\ +ggtgaaaatagacagggtgttagtattcaatcttcggagtatcaatttcgccaatcttgg\n\ +tgagaaagcataccctttcttcagagaaagaagatcaatcataacactatctttaacgag\n\ +gtacgcacgcgcatcattacctgcctccatggatctttaggatagcggaaagtattggca\n\ +gcgtattgtgatttcgttcctactttatcaatttcacattcatatacatgtcttttatca\n\ +aaatcgccaataagataggatgagctatattagatgctagtagagttcgcgccaacatca\n\ +tcgataggaatactcaggacagcgtgataggacttttcaatccctaatactctctataat\n\ +tataactctctcttaagtttggaggcagtaacgcgctctatataatcagtttgctgcacc\n\ +attcttcagcctctgatacatacaaataaattccacagcagtaagagggtttaattgaga\n\ +catcttgggaacttaggattttactctaacatcaccgaaacgattattggataccgtacc\n\ +taaacgaactttctcaaggcagtaatataggacatccgcaataacacaaatgctgcctcc\n\ +ccaggagttatgtcttcctggaggctatatcttacacccactcactataggcaaactaaa\n\ +gtttaaatgttgattgtctaaaaaaaagatagataagagttggccggcgtagcacatgcg\n\ +aaagtgaatcgtaagctataattctctggacttgaagttctgtcctgttcctctgcaaga\n\ +aacaaacttcctttaaagctatttacgacgcacatctcagcaagttataaacatgttgga\n\ +agtttctagtcggaattcccaaagaacggatctatctaatgcattcctacatttttcctg\n\ +tctgccgatggtgccatcctattcaaagaatttcttaaaagtagattaaatgggactttt\n\ +aacaatgagtaaccttacgcctctaagggttcctcgagtgccatacaccagtcaggtccg\n\ +agccacatacacggagaacattctaacatagcattctcaactcgatcatttgcaggttac\n\ +ttctttcctatcctagtgctaaaaatcatacttgcaatcccatagcacggattaagaacc\n\ +taagaaacaattcagtaaaacatgttcgaattcttggtatgggaacatcattgcagctat\n\ +ggtctaacgcattaatgtttgggtacatcttccatcatataaacaggaagagtctgacga\n\ +cagggagtgcttgcgatcatgtctatcattgtgaaatcaaattgtagctcacatgtcgtc\n\ +tatgagagcgtgtatccgataagatttagaaaaatagaagtcgtataagatctcactgaa\n\ +cttttgaatgaatgtgaagcatatatgatctgctttaataaaactttatccataggatac\n\ +gtttccaaatcaattcaataattattagtcaaaatagataaggatgaacaacctgaaggc\n\ +cgatcggacgtagaaagtggtcccatcactttgagttgatattgttgaaccacacgttat\n\ +tatggttttcaaacagtctcaggatattgtatatacagataatccgataccagttgtctg\n\ +acgcccctcttacgtaccccaccctttgtgacgtttaaagcagttgttcagtattttaaa\n\ +ctaggcggcaactaatttggaaagaagcacagtggatatgtctaaattcttgttattcag\n\ +gcctgaatttaatacaccgcatagttaacttcgcggtagagttgttcatcatgcctcctc\n\ +taagctaccacttctatgatacaccaatagttgttctacggaatctgataattggccaag\n\ +tcataaacttccgctgcgttcaacccccttgctcgaatatccaactcgaaaagacagcct\n\ +tttggtgtccggaacaaatcagttacttcttttctgatgttaattctctgtggtcagata\n\ +cagaccaaaaactccgcggatttaccatcctccaagaacaaatttgcatcaacatagcat\n\ +tttggctacatattctaagtctcaatagtttaggttttcaactacattatcccaacatta\n\ +ggattggaggaataatagctgggtaagtccccttgcgtctacaatcgactattttttatg\n\ +aatatgcttctgccgcacctatggttattaaaaaagtcatgactttgaagaaccctgaaa\n\ +agatagatgaatcaggtgtaatggcagcagccaaagagcatataattagcaacactctaa\n\ +gaacattatagatatgatgatagcgatcgtcatgatgttatccggtcacaatagtagctt\n\ +catcagctaattcgttttgccagtggtgacttgcgctggaagaatcgttatacggtccct\n\ +tccctcttgatacggtgggggcttattcaaccgcgtggattgggttgtcatacttgcatt\n\ +aaacgatgtaaaccatctagtagtcaactatactaaatcacaaaatagtgatcaatacat\n\ +acccgcttcatggttttaaccatttaattgattaaagatattccgctaagaaccattatc\n\ +tacctaaactgatcgccgtatcctagtagtttgaaatttgatgtaccgtaatgatcaacg\n\ +aagtaaaacgttatattgtatgtagaataataggtcttggagctaaatgatgtgattggt\n\ +agtgaagacttacccttacaactttaccggtttctcggaagaatatactagagaatcaat\n\ +gcatgggctacataagcactttagtctaatgagataaaaaatacacgagtcttccatcat\n\ +gaattttttgtcgaaaaactcgaacctggtaatttaaaccatatatctttatgtcgtcaa\n\ +taactctcatatgttttatataacttcccaatcacgacttgtaactgcttgttcgactga\n\ +gctgtttgagctatgaggccgggatccggttgagctacatctatttgctacaagaaaaat\n\ +gaaagcacatttgttgggagttctggctacactcatagagaaataagtggcccgagtggg\n\ +tgcggcctgcctccatattcaagtgtatcttaaaccaagtggttccaacgctcgcgctaa\n\ +agaattaaagcctttatttcctccacggagtagcccgtaatccggttcgaaagagaccat\n\ +tgaagttaattttcatatccagtgaagtttaggcacaagcatgtgttctgccacatgcct\n\ +caaagcgctcttcaaccaagatatgattcatcctaacttcgatgaatgcgtctgtaacat\n\ +aaatatagaaggaatgattcggcgagttaattttcgccttctccaacatggcatccctac\n\ +gttcgttataaggaccatacatgtaggttttaaaggtttgcggttaatcgatatttacat\n\ +catagaaattctatagtcaaatttacaagactctagatactcactcgttgcagccggcta\n\ +ggaagcgctttgtaccttacttcccttttcgttgcgtaatatgaatttcatatagtaagt\n\ +tcaaggcactcatacctccgtgaagagggtagatagactattaaagttgtttaatagtac\n\ +gtattgatggaaatgacccgtaggagatttaccactcaatccacaagattcgctgctgtg\n\ +cattatcaaaacagtgcatgtcgaaacatgggttgggtccttcaaacacgaatccaggta\n\ +gagatacctttgcaattttt\n"; + +dnaInput = dnaInput + dnaInput + dnaInput; + +var ilen, clen, + seqs = [ + /agggtaaa|tttaccct/ig, + /[cgt]gggtaaa|tttaccc[acg]/ig, + /a[act]ggtaaa|tttacc[agt]t/ig, + /ag[act]gtaaa|tttac[agt]ct/ig, + /agg[act]taaa|ttta[agt]cct/ig, + /aggg[acg]aaa|ttt[cgt]ccct/ig, + /agggt[cgt]aa|tt[acg]accct/ig, + /agggta[cgt]a|t[acg]taccct/ig, + /agggtaa[cgt]|[acg]ttaccct/ig], + subs = { + B: '(c|g|t)', D: '(a|g|t)', H: '(a|c|t)', K: '(g|t)', + M: '(a|c)', N: '(a|c|g|t)', R: '(a|g)', S: '(c|t)', + V: '(a|c|g)', W: '(a|t)', Y: '(c|t)' } + +ilen = dnaInput.length; + +// There is no in-place substitution +dnaInput = dnaInput.replace(/>.*\n|\n/g,"") +clen = dnaInput.length + +var dnaOutputString = ''; + +for(i in seqs) + dnaOutputString += seqs[i].source + " " + (dnaInput.match(seqs[i]) || []).length + "\n"; + // match returns null if no matches, so replace with empty + +for(k in subs) + dnaInput = dnaInput.replace(k, subs[k], "g") + // search string, replacement string, flags + +assertEq(dnaOutputString, "agggtaaa|tttaccct 0\n[cgt]gggtaaa|tttaccc[acg] 9\na[act]ggtaaa|tttacc[agt]t 27\nag[act]gtaaa|tttac[agt]ct 24\nagg[act]taaa|ttta[agt]cct 30\naggg[acg]aaa|ttt[cgt]ccct 9\nagggt[cgt]aa|tt[acg]accct 12\nagggta[cgt]a|t[acg]taccct 9\nagggtaa[cgt]|[acg]ttaccct 15\n") diff --git a/js/src/jit-test/tests/sunspider/check-string-fasta.js b/js/src/jit-test/tests/sunspider/check-string-fasta.js new file mode 100644 index 0000000..ed5ecef --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-string-fasta.js @@ -0,0 +1,90 @@ +// The Great Computer Language Shootout +// http://shootout.alioth.debian.org +// +// Contributed by Ian Osgood + +var last = 42, A = 3877, C = 29573, M = 139968; + +function rand(max) { + last = (last * A + C) % M; + return max * last / M; +} + +var ALU = + "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG" + + "GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA" + + "CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT" + + "ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA" + + "GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG" + + "AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC" + + "AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA"; + +var IUB = { + a:0.27, c:0.12, g:0.12, t:0.27, + B:0.02, D:0.02, H:0.02, K:0.02, + M:0.02, N:0.02, R:0.02, S:0.02, + V:0.02, W:0.02, Y:0.02 +} + +var HomoSap = { + a: 0.3029549426680, + c: 0.1979883004921, + g: 0.1975473066391, + t: 0.3015094502008 +} + +function makeCumulative(table) { + var last = null; + for (var c in table) { + if (last) table[c] += table[last]; + last = c; + } +} + +function fastaRepeat(n, seq) { + var seqi = 0, lenOut = 60; + while (n>0) { + if (n0) { + if (n= 0x7f) { + validates = false; + break; + } + } + + if (!validates) + continue; + + var url = "http://example.com/tag/" + tag.replace(" ", "").toLowerCase(); + var popularity = tagInfo[i].popularity; + var color = 'rgb(' + Math.floor(255 * (popularity - 12) / 20) + ', 0, 255)'; + output += ' ' + tag + ' \n'; + } + + output += ''; + output.replace(" ", " "); + + return output; +} + +var tagcloud = makeTagCloud(tagInfo); +tagInfo = null; + +// The result string embeds floating-point numbers, which can vary a bit on different platforms, +// so we truncate them a bit before comparing. +var tagcloud_norm = tagcloud.replace(/([0-9.]+)px/g, function(str, p1) { return p1.substr(0, 10) + 'px' }) +assertEq(tagcloud_norm.length, 295906) diff --git a/js/src/jit-test/tests/sunspider/check-string-unpack-code.js b/js/src/jit-test/tests/sunspider/check-string-unpack-code.js new file mode 100644 index 0000000..a7013ec --- /dev/null +++ b/js/src/jit-test/tests/sunspider/check-string-unpack-code.js @@ -0,0 +1,73 @@ +// This test case unpacks the compressed code for the MochiKit, +// jQuery, Dojo and Prototype JavaScript libraries. + +/*** + MochiKit.MochiKit 1.3.1 : PACKED VERSION + THIS FILE IS AUTOMATICALLY GENERATED. If creating patches, please + diff against the source tree, not this file. + + See for documentation, downloads, license, etc. + + (c) 2005 Bob Ippolito. All rights Reserved. +***/ + +for (var i = 0; i < 2; i++) { + +var decompressedMochiKit = function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('if(H(1q)!="L"){1q.2X("B.J")}if(H(B)=="L"){B={}}if(H(B.J)=="L"){B.J={}}B.J.1Y="1.3.1";B.J.1r="B.J";B.J.2l=G(7V,vR){if(7V===O){7V={}}R(u i=1;i=0;i--){aw.e9(o[i])}}N{X.1c(o)}}F X},1R:G(7U,1i,av){if(!av){av=0}if(1i){u l=1i.K;if(H(l)!="2y"){if(H(B.15)!="L"){1i=B.15.2G(1i);l=1i.K}N{14 Y 3p("au 2E an at-as 3W B.15 2E ar")}}if(!7U){7U=[]}R(u i=av;i>b},vG:G(a,b){F a>>>b},eq:G(a,b){F a==b},ne:G(a,b){F a!=b},gt:G(a,b){F a>b},ge:G(a,b){F a>=b},lt:G(a,b){F al){7T=l}}69=[];R(i=0;i<7T;i++){u fa=[];R(u j=1;j0){ap=m.2o(me.am,ap)}u 4o=me.f7;if(!4o){4o=D}F me.f5.1w(4o,ap)};7Q.f7=f6;7Q.f5=ao;7Q.am=5f;F 7Q},lF:G(7P){u mp=B.J.1O;R(u k in 7P){u f4=7P[k];if(H(f4)=="G"){7P[k]=mp(f4,7P)}}},5u:G(mo,mn,ml,mk){B.J.ae.5M(mo,mn,ml,mk)},mj:{"5L":1h,"1n":1h,"2y":1h},2f:G(a,b){if(a==b){F 0}u f3=(H(a)=="L"||a===O);u f2=(H(b)=="L"||b===O);if(f3&&f2){F 0}N{if(f3){F-1}N{if(f2){F 1}}}u m=B.J;u f1=m.mj;if(!(H(a)in f1&&H(b)in f1)){1f{F m.ae.3C(a,b)}1e(e){if(e!=m.4d){14 e}}}if(ab){F 1}}u f0=m.U;14 Y 3p(f0(a)+" 3W "+f0(b)+" 9v 2E be vv")},eM:G(a,b){F B.J.2f(a.9P(),b.9P())},eL:G(a,b){u mi=B.J.2f;u 7O=a.K;u al=0;if(7O>b.K){al=1;7O=b.K}N{if(7O0))){u kv=B.S.d5(3s);3s=kv[0];68=kv[1]}N{if(M.K==1){u o=3s;3s=[];68=[];R(u k in o){u v=o[k];if(H(v)!="G"){3s.1c(k);68.1c(v)}}}}u W=[];u lT=28.2a(3s.K,68.K);u eT=B.J.af;R(u i=0;i=2J){14 I.25}5c+=3a;F W}}},4c:G(aa,p,q){u m=B.J;u I=B.15;u lb=m.2r(I.1Q,m.1R(O,M,1));u 2r=m.2r;u 1a=I.1a;F{U:G(){F"4c(...)"},1l:m.24("U"),1a:G(){F aa.1w(D,2r(1a,lb))}}},ep:G(aa,1V,I){1V=B.15.1Q(1V);u m=B.J;F{U:G(){F"ep(...)"},1l:m.24("U"),1a:G(){F aa.1w(I,1V.1a())}}},55:G(p,q){u I=B.15;u m=B.J;if(M.K==1){F I.1Q(M[0])}u 64=m.2r(I.1Q,M);F{U:G(){F"55(...)"},1l:m.24("U"),1a:G(){1M(64.K>1){1f{F 64[0].1a()}1e(e){if(e!=I.25){14 e}64.2P()}}if(64.K==1){u a9=64.2P();D.1a=m.1O("1a",a9);F D.1a()}14 I.25}}},9Z:G(3b,1V){u I=B.15;1V=I.1Q(1V);F{U:G(){F"9Z(...)"},1l:B.J.24("U"),1a:G(){u W=1V.1a();if(!3b(W)){D.1a=G(){14 I.25};D.1a()}F W}}},eo:G(3b,1V){1V=B.15.1Q(1V);u m=B.J;u 1O=m.1O;F{"U":G(){F"eo(...)"},"1l":m.24("U"),"1a":G(){1M(1h){u W=1V.1a();if(!3b(W)){2K}}D.1a=1O("1a",1V);F W}}},a7:G(63,2u,la){2u.62[63]=-1;u m=B.J;u l9=m.eI;F{U:G(){F"en("+63+", ...)"},1l:m.24("U"),1a:G(){u W;u i=2u.62[63];if(i==2u.29){W=la.1a();2u.a8.1c(W);2u.29+=1;2u.62[63]+=1}N{W=2u.a8[i-2u.2a];2u.62[63]+=1;if(i==2u.2a&&l9(2u.62)!=2u.2a){2u.2a+=1;2u.a8.2P()}}F W}}},en:G(a6,n){u W=[];u 2u={"62":[],"a8":[],"29":-1,"2a":-1};if(M.K==1){n=2}u I=B.15;a6=I.1Q(a6);u a7=I.a7;R(u i=0;i0&&4k>=2J)||(3a<0&&4k<=2J)){14 B.15.25}u W=4k;4k+=3a;F W},U:G(){F"7I("+[4k,2J,3a].2b(", ")+")"},1l:B.J.24("U")}},l0:G(a5,l7){u x=l7||0;u I=B.15;a5=I.1Q(a5);1f{1M(1h){x+=a5.1a()}}1e(e){if(e!=I.25){14 e}}F x},em:G(a4){u I=B.15;a4=I.1Q(a4);1f{1M(1h){a4.1a()}}1e(e){if(e!=I.25){14 e}}},9a:G(7J,1A,I){u m=B.J;if(M.K>2){1A=m.1O(1A,I)}if(m.3A(7J)){1f{R(u i=0;i<7J.K;i++){1A(7J[i])}}1e(e){if(e!=B.15.25){14 e}}}N{I=B.15;I.em(I.4c(1A,7J))}},kZ:G(l6,1A){u I=B.15;1f{I.a0(1A,l6).1a();F 1m}1e(e){if(e!=I.25){14 e}F 1h}},kY:G(l5,4j){u W=B.15.2G(l5);if(M.K==1){4j=B.J.2f}W.iz(4j);F W},kX:G(l4){u W=B.15.2G(l4);W.vg();F W},kW:G(l3,1A){u I=B.15;1f{I.a1(1A,l3).1a();F 1h}1e(e){if(e!=I.25){14 e}F 1m}},kV:G(1g,5b){if(B.J.3A(5b)){R(u i=0;i<5b.K;i++){1g.1c(5b[i])}}N{u I=B.15;5b=I.1Q(5b);1f{1M(1h){1g.1c(5b.1a())}}1e(e){if(e!=I.25){14 e}}}F 1g},ek:G(a3,eH){u m=B.J;u I=B.15;if(M.K<2){eH=m.4i.eE}a3=I.1Q(a3);u pk=L;u k=L;u v;G eF(){v=a3.1a();k=eH(v)}G l2(){u 7j=v;v=L;F 7j}u eG=1h;F{U:G(){F"ek(...)"},1a:G(){1M(k==pk){eF();if(eG){eG=1m;2K}}pk=k;F[k,{1a:G(){if(v==L){eF()}if(k!=pk){14 I.25}F l2()}}]}}},kU:G(a2,eD){u m=B.J;u I=B.15;if(M.K<2){eD=m.4i.eE}a2=I.1Q(a2);u ey=[];u eA=1h;u ez;1M(1h){1f{u eB=a2.1a();u 2h=eD(eB)}1e(e){if(e==I.25){2K}14 e}if(eA||2h!=ez){u eC=[];ey.1c([2h,eC])}eC.1c(eB);eA=1m;ez=2h}F ey},9X:G(ex){u i=0;F{U:G(){F"9X(...)"},1l:B.J.24("U"),1a:G(){if(i>=ex.K){14 B.15.25}F ex[i++]}}},eh:G(ew){F(ew&&H(ew.ei)=="G")},9V:G(l1){F{U:G(){F"9V(...)"},1l:B.J.24("U"),1a:G(){u W=l1.ei();if(W===O||W===L){14 B.15.25}F W}}}});B.15.1W=["9Y","9X","eh","9V",];B.15.1z=["25","9W","1Q","eu","et","7b","1a","es","a1","a0","er","4c","ep","55","9Z","eo","en","2G","7H","7I","l0","em","9a","kZ","kY","kX","kW","kV","ek","kU"];B.15.2d=G(){u m=B.J;D.25=Y m.5a("25");D.9Y=Y m.4a();D.9W("ej",m.3A,D.9X);D.9W("ei",D.eh,D.9V);D.2k={":3e":D.1z,":1p":m.2o(D.1z,D.1W)};m.3f(D)};B.15.2d();if(!B.3d){7H=B.15.7H}B.J.2Y(D,B.15);if(H(1q)!="L"){1q.2X("B.1H");1q.2M("B.J")}if(H(1x)!="L"){1x.26("B.J",[])}1f{if(H(B.J)=="L"){14""}}1e(e){14"B.1H 3F on B.J!"}if(H(B.1H)=="L"){B.1H={}}B.1H.1r="B.1H";B.1H.1Y="1.3.1";B.1H.1K=G(){F"["+D.1r+" "+D.1Y+"]"};B.1H.1l=G(){F D.1K()};B.1H.1z=["5C","49","7A","kR","2L","5Z","kG","ch","kE","kC"];B.1H.1W=["ef","e8","e7"];B.1H.49=G(1P,kT,3z){D.1P=1P;D.3N=kT;D.3z=3z;D.vf=Y 3Q()};B.1H.49.1U={U:G(){u m=B.J;F"49("+m.2r(m.U,[D.1P,D.3N,D.3z]).2b(", ")+")"},1l:B.J.24("U")};B.J.2l(B.1H,{ef:G(7F){u I=B.1H;if(H(7F)=="1n"){7F=I.5C[7F]}F G(1t){u 7G=1t.3N;if(H(7G)=="1n"){7G=I.5C[7G]}F 7G>=7F}},e8:G(){u kS=B.1H.49;R(u i=0;i=0&&D.4h.K>D.ec){D.4h.2P()}},c8:G(9U){u ea=0;if(!(H(9U)=="L"||9U===O)){ea=28.29(0,D.4h.K-9U)}F D.4h.9T(ea)},kJ:G(7B){if(H(7B)=="L"||7B===O){7B=30}u 9S=D.c8(7B);if(9S.K){u 1g=2r(G(m){F"\\n ["+m.1P+"] "+m.3N+": "+m.3z.2b(" ")},9S);1g.e9("va "+9S.K+" v9:");F 1g.2b("")}F""},v8:G(kI){if(H(B.1I)=="L"){cq(D.kJ())}N{B.1I.bY(kI||1m)}}};B.1H.2d=G(){D.5C={8M:40,8L:50,8K:30,8J:20,8I:10};u m=B.J;m.5u("49",D.e8,D.e7);u 61=m.2z;u e6=D.7A;u 60=e6.1U.kH;m.2l(D.7A.1U,{kF:61(60,"8I"),5Z:61(60,"8J"),dE:61(60,"8M"),kD:61(60,"8L"),kB:61(60,"8K")});u I=D;u 5Y=G(1b){F G(){I.2L[1b].1w(I.2L,M)}};D.5Z=5Y("5Z");D.kG=5Y("dE");D.ch=5Y("kF");D.kE=5Y("kD");D.kC=5Y("kB");D.2L=Y e6();D.2L.e5=1h;D.2k={":3e":D.1z,":1p":m.2o(D.1z,D.1W)};m.3f(D)};if(H(5X)=="L"&&H(2v)!="L"&&2v.kA&&H(kz)!="L"){5X=G(){5X.3G=M;u ev=2v.kA("v7");ev.v6("5X",1m,1h);kz(ev)}}B.1H.2d();B.J.2Y(D,B.1H);if(H(1q)!="L"){1q.2X("B.1D")}if(H(B)=="L"){B={}}if(H(B.1D)=="L"){B.1D={}}B.1D.1r="B.1D";B.1D.1Y="1.3.1";B.1D.1K=G(){F"["+D.1r+" "+D.1Y+"]"};B.1D.1l=G(){F D.1K()};B.1D.ks=G(1y){1y=1y+"";if(H(1y)!="1n"||1y.K===0){F O}u 7z=1y.2R("-");if(7z.K===0){F O}F Y 3Q(7z[0],7z[1]-1,7z[2])};B.1D.ky=/(\\d{4,})(?:-(\\d{1,2})(?:-(\\d{1,2})(?:[T ](\\d{1,2}):(\\d{1,2})(?::(\\d{1,2})(?:\\.(\\d+))?)?(?:(Z)|([+-])(\\d{1,2})(?::(\\d{1,2}))?)?)?)?)?/;B.1D.kr=G(1y){1y=1y+"";if(H(1y)!="1n"||1y.K===0){F O}u X=1y.3C(B.1D.ky);if(H(X)=="L"||X===O){F O}u 5W,7y,7x,9R,2a,9Q,7w;5W=3w(X[1],10);if(H(X[2])=="L"||X[2]===""){F Y 3Q(5W)}7y=3w(X[2],10)-1;7x=3w(X[3],10);if(H(X[4])=="L"||X[4]===""){F Y 3Q(5W,7y,7x)}9R=3w(X[4],10);2a=3w(X[5],10);9Q=(H(X[6])!="L"&&X[6]!=="")?3w(X[6],10):0;if(H(X[7])!="L"&&X[7]!==""){7w=28.ha(c5*4M("0."+X[7]))}N{7w=0}if((H(X[8])=="L"||X[8]==="")&&(H(X[9])=="L"||X[9]==="")){F Y 3Q(5W,7y,7x,9R,2a,9Q,7w)}u 58;if(H(X[9])!="L"&&X[9]!==""){58=3w(X[10],10)*v5;if(H(X[11])!="L"&&X[11]!==""){58+=3w(X[11],10)*kw}if(X[9]=="-"){58=-58}}N{58=0}F Y 3Q(3Q.v4(5W,7y,7x,9R,2a,9Q,7w)-58)};B.1D.dY=G(2g,kx){if(H(2g)=="L"||2g===O){F O}u hh=2g.v3();u mm=2g.v2();u ss=2g.v1();u 1g=[((kx&&(hh<10))?"0"+hh:hh),((mm<10)?"0"+mm:mm),((ss<10)?"0"+ss:ss)];F 1g.2b(":")};B.1D.kq=G(2g,7v){if(H(2g)=="L"||2g===O){F O}u ku=7v?"T":" ";u kt=7v?"Z":"";if(7v){2g=Y 3Q(2g.9P()+(2g.v0()*kw))}F B.1D.dX(2g)+ku+B.1D.dY(2g,7v)+kt};B.1D.dX=G(2g){if(H(2g)=="L"||2g===O){F O}u e4=B.1D.e3;F[2g.dZ(),e4(2g.e1()+1),e4(2g.e0())].2b("-")};B.1D.kp=G(d){d=d+"";if(H(d)!="1n"||d.K===0){F O}u a=d.2R("/");F Y 3Q(a[2],a[0]-1,a[1])};B.1D.e3=G(n){F(n>9)?n:"0"+n};B.1D.ko=G(d){if(H(d)=="L"||d===O){F O}u e2=B.1D.e3;F[e2(d.e1()+1),e2(d.e0()),d.dZ()].2b("/")};B.1D.kn=G(d){if(H(d)=="L"||d===O){F O}F[d.e1()+1,d.e0(),d.dZ()].2b("/")};B.1D.1z=["ks","kr","dY","kq","dX","kp","ko","kn"];B.1D.1W=[];B.1D.2k={":3e":B.1D.1z,":1p":B.1D.1z};B.1D.2d=G(){u 2w=D.1r+".";R(u k in D){u o=D[k];if(H(o)=="G"&&H(o.1r)=="L"){1f{o.1r=2w+k}1e(e){}}}};B.1D.2d();if(H(B.J)!="L"){B.J.2Y(D,B.1D)}N{(G(km,dW){if((H(1x)=="L"&&H(1q)=="L")||(H(B.3d)=="5L"&&B.3d)){u 1p=dW.2k[":1p"];R(u i=0;i<1p.K;i++){km[1p[i]]=dW[1p[i]]}}})(D,B.1D)}if(H(1q)!="L"){1q.2X("B.1s")}if(H(B)=="L"){B={}}if(H(B.1s)=="L"){B.1s={}}B.1s.1r="B.1s";B.1s.1Y="1.3.1";B.1s.1K=G(){F"["+D.1r+" "+D.1Y+"]"};B.1s.1l=G(){F D.1K()};B.1s.ke=G(kl,kk,kj,ki,kh,dV,kg,9N,kf){F G(1P){1P=4M(1P);if(H(1P)=="L"||1P===O||k8(1P)){F kl}u 9L=kk;u 9K=kj;if(1P<0){1P=-1P}N{9L=9L.23(/-/,"")}u me=M.2U;u 9M=B.1s.dJ(ki);if(kh){1P=1P*3k;9K=9M.9y+9K}1P=B.1s.dK(1P,dV);u 9O=1P.2R(/\\./);u 3r=9O[0];u 3P=(9O.K==1)?"":9O[1];u X="";1M(3r.K9N){u i=3r.K-9N;X=9M.9A+3r.2W(i,3r.K)+X;3r=3r.2W(0,i)}}X=3r+X;if(dV>0){1M(3P.K=0)){D.9u()}},jR:G(X){D.9x(X);D.jX()},9x:G(X){D.2H=((X 2C 2x)?1:0);D.53[D.2H]=X;D.9u()},dD:G(){if(D.2H!=-1){if(!D.7l){14 Y B.1k.dj(D)}D.7l=1m;F}},3o:G(X){D.dD();if(X 2C B.1k.2t){14 Y 2x("2t jW 9v aB be 7r if jV jU jT jS of a 3o")}D.9x(X)},52:G(X){D.dD();u I=B.1k;if(X 2C I.2t){14 Y 2x("2t jW 9v aB be 7r if jV jU jT jS of a 3o")}if(!(X 2C 2x)){X=Y I.9p(X)}D.9x(X)},jP:G(fn){if(M.K>1){fn=B.J.2z.1w(O,M)}F D.9w(fn,fn)},5Q:G(fn){if(M.K>1){fn=B.J.2z.1w(O,M)}F D.9w(fn,O)},jA:G(fn){if(M.K>1){fn=B.J.2z.1w(O,M)}F D.9w(O,fn)},9w:G(cb,eb){if(D.7r){14 Y 2x("uQ uP 9v 2E be re-uO")}D.55.1c([cb,eb]);if(D.2H>=0){D.9u()}F D},9u:G(){u dC=D.55;u 56=D.2H;u X=D.53[56];u I=D;u cb=O;1M(dC.K>0&&D.54===0){u 2n=dC.2P();u f=2n[56];if(f===O){2V}1f{X=f(X);56=((X 2C 2x)?1:0);if(X 2C B.1k.2t){cb=G(X){I.jR(X)};D.jQ()}}1e(3O){56=1;if(!(3O 2C 2x)){3O=Y B.1k.9p(3O)}X=3O}}D.2H=56;D.53[56]=X;if(cb&&D.54){X.jP(cb);X.7r=1h}}};B.J.2l(B.1k,{dk:G(){F dB("("+M[0].jN+")")},dp:G(uN){u d=Y B.1k.2t();d.3o.1w(d,M);F d},9q:G(uM){u d=Y B.1k.2t();d.52.1w(d,M);F d},do:G(){u I=M.2U;if(!I.7q){u dy=[G(){F Y 7q()},G(){F Y dA("jO.dz")},G(){F Y dA("uL.dz")},G(){F Y dA("jO.dz.4.0")},G(){14 Y B.1k.dh("uK uJ 2E uI 7q")}];R(u i=0;i1){u m=B.J;u qs=m.dw.1w(O,m.1R(O,M,1));if(qs){5F+="?"+qs}}2s.cp("uB",5F,1h);F I.dl(2s)},jv:G(5F){u I=B.1k;u d=I.dn.1w(I,M);d=d.5Q(I.dk);F d},dm:G(jJ,dv){u d=Y B.1k.2t();u m=B.J;if(H(dv)!="L"){d.5Q(G(){F dv})}u jI=uA(m.1O("3o",d),28.8B(jJ*c5));d.7m=G(){1f{uz(jI)}1e(e){}};F d},ju:G(jH,1A){u m=B.J;u jG=m.2z.1w(m,m.1R(O,M,1));F B.1k.dm(jH).5Q(G(X){F jG()})}});B.1k.5O=G(){D.5S=[];D.4e=1m;D.id=D.7n()};B.1k.5O.1U={bX:B.1k.5O,uy:G(){d=Y B.1k.2t();if(D.4e){D.5S.1c(d)}N{D.4e=1h;d.3o(D)}F d},jF:G(){if(!D.4e){14 3p("ux to jF an jE 5O")}D.4e=1m;if(D.5S.K>0){D.4e=1h;D.5S.2P().3o(D)}},7n:B.J.4f(),U:G(){u 9t;if(D.4e){9t="4e, "+D.5S.K+" 5S"}N{9t="jE"}F"5O("+D.id+", "+9t+")"},1l:B.J.24("U")};B.1k.7i=G(2G,du,jC,jB,jD){D.2G=2G;D.9r=Y 7o(D.2G.K);D.55=[];D.id=D.7n();D.2H=-1;D.54=0;D.53=[O,O];D.7m=jD;D.7l=1m;if(D.2G.K===0&&!du){D.3o(D.9r)}D.dr=0;D.jz=du;D.jy=jC;D.jx=jB;u 9s=0;B.J.2r(B.J.1O(G(d){d.5Q(B.J.1O(D.dt,D),9s,1h);d.jA(B.J.1O(D.dt,D),9s,1m);9s+=1},D),D.2G)};B.J.2l(B.1k.7i.1U,B.1k.2t.1U);B.J.2l(B.1k.7i.1U,{dt:G(ds,7k,5R){D.9r[ds]=[7k,5R];D.dr+=1;if(D.2H!==0){if(7k&&D.jz){D.3o([ds,5R])}N{if(!7k&&D.jy){D.52(5R)}N{if(D.dr==D.2G.K){D.3o(D.9r)}}}}if(!7k&&D.jx){5R=O}F 5R}});B.1k.jt=G(jw){u d=Y B.1k.7i(jw,1m,1h,1m);d.5Q(G(dq){u 7j=[];R(u i=0;i=0){u 9m=Q.1S[Q.j4];7d.1c(1b);7c.1c((9m.3m)?9m.3m:9m.7X);F O}7d.1c(1b);7c.1c("");F O}if(4Y=="cu"||4Y=="P"||4Y=="8d"||4Y=="6m"){F Q.5h}7d.1c(1b);7c.1c(Q.3m||"");F O}F Q.5h});F[7d,7c]},94:G(1N,1A){u I=B.S;u d3=I.1Z;u W;1f{I.1Z=1N;W=1A()}1e(e){I.1Z=d3;14 e}I.1Z=d3;F W},j3:G(1b,j2,3y,j1){B.S.9b.5M(1b,j2,3y,j1)},9k:G(1j,7a){u im=B.15;u I=B.S;u 1Q=im.1Q;u iY=im.7b;u 4c=im.4c;u iX=I.9b;u iZ=I.9k;u iW=B.J.4d;1M(1h){if(H(1j)=="L"||1j===O){F O}if(H(1j.3T)!="L"&&1j.3T>0){F 1j}if(H(1j)=="2y"||H(1j)=="5L"){1j=1j.1l()}if(H(1j)=="1n"){F I.1Z.4S(1j)}if(H(1j.j0)=="G"){1j=1j.j0(7a);2V}if(H(1j)=="G"){1j=1j(7a);2V}u 9l=O;1f{9l=1Q(1j)}1e(e){}if(9l){F 4c(iZ,9l,iY(7a))}1f{1j=iX.3C(1j,7a);2V}1e(e){if(e!=iW){14 e}}F I.1Z.4S(1j.1l())}F L},iV:G(1j,79,iU){u o={};o[79]=iU;1f{F B.S.4X(1j,o)}1e(e){}F O},iT:G(1j,79){u I=B.S;u d2=I.4U.99[79];1j=I.1E(1j);1f{if(d2){F 1j[d2]}F 1j.fm(79)}1e(e){}F O},4X:G(1j,5K){u Q=1j;u I=B.S;if(H(1j)=="1n"){Q=I.1E(1j)}if(5K){u d0=B.J.8Z;if(I.4U.6X){R(u k in 5K){u v=5K[k];if(H(v)=="3n"&&H(Q[k])=="3n"){d0(Q[k],v)}N{if(k.2W(0,2)=="on"){if(H(v)=="1n"){v=Y cZ(v)}Q[k]=v}N{Q.4p(k,v)}}}}N{u iS=I.4U.99;R(k in 5K){v=5K[k];u d1=iS[k];if(k=="1T"&&H(v)=="1n"){Q.1T.3x=v}N{if(H(d1)=="1n"){Q[d1]=v}N{if(H(Q[k])=="3n"&&H(v)=="3n"){d0(Q[k],v)}N{if(k.2W(0,2)=="on"){if(H(v)=="1n"){v=Y cZ(v)}Q[k]=v}N{Q.4p(k,v)}}}}}}}F Q},9j:G(1j){u Q=1j;u I=B.S;if(H(1j)=="1n"){Q=I.1E(1j)}u 78=[I.9k(B.J.1R(O,M,1),Q)];u iR=B.J.2o;1M(78.K){u n=78.2P();if(H(n)=="L"||n===O){}N{if(H(n.3T)=="2y"){Q.2c(n)}N{78=iR(n,78)}}}F Q},iQ:G(1j){u Q=1j;u I=B.S;if(H(1j)=="1n"){Q=I.1E(1j);M[0]=Q}u cY;1M((cY=Q.6n)){Q.6S(cY)}if(M.K<2){F Q}N{F I.9j.1w(D,M)}},cX:G(1b,4b){u Q;u I=B.S;u m=B.J;if(H(4b)=="1n"||H(4b)=="2y"){u 3G=m.1R([1b,O],M,1);F M.2U.1w(D,3G)}if(H(1b)=="1n"){if(4b&&"1b"in 4b&&!I.4U.6X){1b=("<"+1b+" 1b=\\""+I.9c(4b.1b)+"\\">")}Q=I.1Z.2S(1b)}N{Q=1b}if(4b){I.4X(Q,4b)}if(M.K<=2){F Q}N{u 3G=m.1R([Q],M,2);F I.9j.1w(D,3G)}},cw:G(){u m=B.J;F m.2z.1w(D,m.1R([B.S.cX],M))},cs:G(5J,1d){u I=B.S;5J=I.1E(5J);u cW=5J.3t;if(1d){1d=I.1E(1d);cW.uj(1d,5J)}N{cW.6S(5J)}F 1d},1E:G(id){u I=B.S;if(M.K==1){F((H(id)=="1n")?I.1Z.hN(id):id)}N{F B.J.2r(I.1E,M)}},4q:G(iP,cV,cU){if(M.K==2){cU=cV}u I=B.S;u el=I.1E(iP);u 77=I.1Z;if(!el||el==77){F L}if(el.iO){F el.iO[cV]}if(H(77.5k)=="L"){F L}if(77.5k===O){F L}u 9i=77.5k.g4(el,O);if(H(9i)=="L"||9i===O){F L}F 9i.6q(cU)},aH:G(76,9g,4W){u I=B.S;if(H(76)=="L"||76===O){76="*"}if(H(4W)=="L"||4W===O){4W=I.1Z}4W=I.1E(4W);u 9h=(4W.fr(76)||I.1Z.1p);if(H(9g)=="L"||9g===O){F B.J.1R(O,9h)}u cR=[];R(u i=0;i<9h.K;i++){u cS=9h[i];u cT=cS.3M.2R(" ");R(u j=0;j/g,">")},iB:G(2q){F B.S.cG(2q).2b("")},cG:G(2q,1g){if(H(1g)=="L"||1g===O){1g=[]}u 70=[2q];u I=B.S;u cB=I.9c;u iA=I.4U;1M(70.K){2q=70.hP();if(H(2q)=="1n"){1g.1c(2q)}N{if(2q.3T==1){1g.1c("<"+2q.cD.8G());u 71=[];u cF=iA(2q);R(u i=0;i");70.1c("");u cC=2q.5h;R(i=cC.K-1;i>=0;i--){70.1c(cC[i])}}N{1g.1c("/>")}}N{if(2q.3T==3){1g.1c(cB(2q.iv))}}}}F 1g},97:G(ix,cA){u m=B.J;u iy=m.1R(O,M,1);B.15.9a(m.47(O,m.2r(B.S.1E,iy)),G(cA){cA.1T.3u=ix})},iw:G(1j,iu){u W=[];(G(1j){u cn=1j.5h;if(cn){R(u i=0;i0){u it=m.47;2T=G(1j){F it(2T.ir,1j.6Y)};2T.cx={};B.15.9a(6Z.6Y,G(a){2T.cx[a.1b]=a.3m});2T.ir=G(a){F(2T.cx[a.1b]!=a.3m)};2T.6X=1m;2T.99={"iq":"3M","ip":"ud","uc":"ub","R":"u9"}}N{2T=G(1j){F 1j.6Y};2T.6X=1h;2T.99={}}D.4U=2T;u 1C=D.cw;D.io=1C("ul");D.il=1C("ol");D.ik=1C("li");D.ij=1C("td");D.cm=1C("tr");D.ii=1C("u8");D.ih=1C("u7");D.ig=1C("u6");D.ie=1C("u5");D.ic=1C("th");D.cv=1C("ck");D.8d=1C("cj");D.A=1C("a");D.6m=1C("4u");D.ib=1C("u4");D.ia=1C("2e");D.i9=1C("tt");D.i8=1C("4O");D.i7=1C("h1");D.i6=1C("h2");D.i5=1C("h3");D.i4=1C("br");D.i3=1C("hr");D.i2=1C("u3");D.i1=1C("u2");D.cu=1C("u1");D.P=1C("p");D.ct=1C("u0");D.i0=1C("hJ");D.hZ=1C("tZ");D.hY=1C("tY");D.hX=1C("tX");D.hW=1C("tW");D.hV=1C("tV");D.hU=m.2z(D.97,"98");D.hT=m.2z(D.97,"8c");D.hS=D.cs;D.$=D.1E;D.2k={":3e":D.1z,":1p":m.2o(D.1z,D.1W)};m.3f(D)}});B.S.2d(((H(2O)=="L")?D:2O));if(!B.3d){95=B.S.95;94=B.S.94}B.J.2Y(D,B.S);if(H(1q)!="L"){1q.2X("B.1I");1q.2M("B.1H");1q.2M("B.J")}if(H(1x)!="L"){1x.26("B.1H",[]);1x.26("B.J",[])}1f{if(H(B.J)=="L"||H(B.1H)=="L"){14""}}1e(e){14"B.1I 3F on B.J 3W B.1H!"}if(H(B.1I)=="L"){B.1I={}}B.1I.1r="B.1I";B.1I.1Y="1.3.1";B.1I.1K=G(){F"["+D.1r+" "+D.1Y+"]"};B.1I.1l=G(){F D.1K()};B.1I.bY=G(6W){u m=B.1I;6W=!(!6W);if(m.3l&&m.3l.8Q!=6W){m.3l.hA();m.3l=O}if(!m.3l||m.3l.8P){m.3l=Y m.1I(6W,B.1H.2L)}F m.3l};B.1I.1I=G(4R,6V){if(H(6V)=="L"||6V===O){6V=B.1H.2L}D.2L=6V;u tU=B.J.2l;u c3=B.J.8Z;u 1O=B.J.1O;u hM=B.J.4L;u 2m=2O;u 6U="tT";if(H(B.S)!="L"){2m=B.S.cr()}if(!4R){u 5F=2m.tS.tR.2R("?")[0].23(/[:\\/.><&]/g,"hR");u 1b=6U+"hR"+5F;u 5D=2m.cp("",1b,"tQ,tP,3V=hQ");if(!5D){cq("tO tN to cp tM 2O tL to hP-up tK.");F L}5D.2v.fl(""+"<5E><8Y>[B.1I]"+"<5s>");5D.2v.hG();5D.2v.8Y+=" "+2m.2v.8Y;2m=5D}u 1N=2m.2v;D.1N=1N;u 21=1N.hN(6U);u c4=!!21;if(21&&H(21.5B)!="L"){21.5B.2L=D.2L;21.5B.6K();F 21.5B}if(c4){u cl;1M((cl=21.6n)){21.6S(cl)}}N{21=1N.2S("4u");21.id=6U}21.5B=D;u 8T=1N.2S("ck");u 8S=1N.2S("ck");u 6O=1N.2S("2e");u 6N=1N.2S("2e");u 6M=1N.2S("2e");u 6L=1N.2S("2e");u 3L=1N.2S("4u");u 42=1N.2S("4u");u 8U=6U+"tz";D.8N=hM(D.8N);u 4T=[];u 6R=O;u cf=G(1t){u 6T=1t.3N;if(H(6T)=="2y"){6T=B.1H.5C[6T]}F 6T};u cd=G(1t){F 1t.3z.2b(" ")};u ca=1O(G(1t){u 8W=cf(1t);u 7X=cd(1t);u c=D.8N[8W];u p=1N.2S("cj");p.3M="B-49 B-5C-"+8W;p.1T.3x="ty: 2N; 4F-8X: -hL-4O-3y; 4F-8X: -o-4O-3y; 4F-8X: 4O-3y; 4F-8X: 4O-tx; hK-3y: 2K-hK; 3y-hJ: tw; 3U: "+c;p.2c(1N.4S(8W+": "+7X));42.2c(p);42.2c(1N.2S("br"));if(3L.ci>3L.hI){3L.4C=0}N{3L.4C=3L.hI}},D);u hD=G(1t){4T[4T.K]=1t;ca(1t)};u hF=G(){u cg,ce;1f{cg=Y 8V(8T.3m);ce=Y 8V(8S.3m)}1e(e){ch("2x in 47 tv: "+e.43);F O}F G(1t){F(cg.hH(cf(1t))&&ce.hH(cd(1t)))}};u cc=G(){1M(42.6n){42.6S(42.6n)}};u hB=G(){4T=[];cc()};u bZ=1O(G(){if(D.8P){F}D.8P=1h;if(B.1I.3l==D){B.1I.3l=O}D.2L.c9(8U);21.5B=O;if(4R){21.3t.6S(21)}N{D.2m.hG()}},D);u c7=G(){cc();R(u i=0;i<4T.K;i++){u 1t=4T[i];if(6R===O||6R(1t)){ca(1t)}}};D.6K=G(){6R=hF();c7();D.2L.c9(8U);D.2L.hE(8U,6R,hD)};u c0=1O(G(){4T=D.2L.c8();c7()},D);u c2=1O(G(6Q){6Q=6Q||2O.6D;2h=6Q.6w||6Q.8t;if(2h==13){D.6K()}},D);u 31="3u: 8c; z-c6: c5; 2I: 2N; 6f: 2N; 6P: tu; 5A: 3k%; he-3U: 4F; c1: "+D.8O;if(4R){31+="; 3V: ts; 3E-3D: fO 8a 8y"}N{31+="; 3V: 3k%;"}21.1T.3x=31;if(!c4){1N.5s.2c(21)}31={"3x":"5A: 33%; 3u: 8Q; c1: "+D.8O};c3(8T,{"3m":"8L|8M|8K|8J|8I","hC":c2,"1T":31});21.2c(8T);c3(8S,{"3m":".*","hC":c2,"1T":31});21.2c(8S);31="5A: 8%; 3u:8Q; c1: "+D.8O;6O.2c(1N.4S("tq"));6O.8R=1O("6K",D);6O.1T.3x=31;21.2c(6O);6N.2c(1N.4S("tp"));6N.8R=c0;6N.1T.3x=31;21.2c(6N);6M.2c(1N.4S("tn"));6M.8R=hB;6M.1T.3x=31;21.2c(6M);6L.2c(1N.4S("tm"));6L.8R=bZ;6L.1T.3x=31;21.2c(6L);3L.1T.3x="fS: tk; 5A: 3k%";42.1T.3x="5A: 3k%; 3V: "+(4R?"tj":"3k%");3L.2c(42);21.2c(3L);D.6K();c0();if(4R){D.2m=L}N{D.2m=2m}D.8Q=4R;D.hA=bZ;D.8P=1m;F D};B.1I.1I.1U={"8O":"ti tg,tf-te","8N":{"8M":"1v","8L":"gU","8K":"1F","8J":"8y","8I":"bx"}};B.1I.1W=["1I"];B.1I.1z=["bY"];B.1I.2d=G(){D.2k={":3e":D.1z,":1p":B.J.2o(D.1z,D.1W)};B.J.3f(D);B.1I.3l=O};B.1I.2d();B.J.2Y(D,B.1I);if(H(1q)!="L"){1q.2X("B.V");1q.2M("B.J")}if(H(1x)!="L"){1x.26("B.J",[])}1f{if(H(B.J)=="L"){14""}}1e(e){14"B.V 3F on B.J"}if(H(B.V)=="L"){B.V={}}B.V.1r="B.V";B.V.1Y="1.3.1";B.V.1K=G(){F"["+D.1r+" "+D.1Y+"]"};B.V.1l=G(){F D.1K()};B.V.V=G(1v,hz,1F,6J){if(H(6J)=="L"||6J===O){6J=1}D.1B={r:1v,g:hz,b:1F,a:6J}};B.V.V.1U={bX:B.V.V,tc:G(hy){u 1B=D.1B;u m=B.V;F m.V.3Y(1B.r,1B.g,1B.b,hy)},tb:G(1o){u 1G=D.41();1G.h=1o;u m=B.V;F m.V.4H(1G)},ta:G(hx){u 1G=D.41();1G.s=hx;u m=B.V;F m.V.4H(1G)},t9:G(hw){u 1G=D.41();1G.l=hw;u m=B.V;F m.V.4H(1G)},t8:G(hv){u 1G=D.41();1G.l=28.29(1G.l-hv,0);u m=B.V;F m.V.4H(1G)},t7:G(hu){u 1G=D.41();1G.l=28.2a(1G.l+hu,1);u m=B.V;F m.V.4H(1G)},fJ:G(ht,5z){if(H(5z)=="L"||5z===O){5z=0.5}u sf=1-5z;u s=D.1B;u d=ht.1B;u df=5z;F B.V.V.3Y((s.r*sf)+(d.r*df),(s.g*sf)+(d.g*df),(s.b*sf)+(d.b*df),(s.a*sf)+(d.a*df))},h4:G(hs){u a=D.6r();u b=hs.6r();F B.J.2f([a.r,a.g,a.b,a.a],[b.r,b.g,b.b,b.a])},hq:G(){F D.41().b>0.5},t6:G(){F(!D.hq())},t5:G(){u c=D.41();u 2Z=B.V.6F;u W=D.ho;if(!W){u 5y=(2Z(c.h,bF).6I(0)+","+2Z(c.s,3k).hp(4)+"%"+","+2Z(c.l,3k).hp(4)+"%");u a=c.a;if(a>=1){a=1;W="1G("+5y+")"}N{if(a<=0){a=0}W="t4("+5y+","+a+")"}D.ho=W}F W},hl:G(){u c=D.1B;u 2Z=B.V.6F;u W=D.hn;if(!W){u 5y=(2Z(c.r,3h).6I(0)+","+2Z(c.g,3h).6I(0)+","+2Z(c.b,3h).6I(0));if(c.a!=1){W="t3("+5y+","+c.a+")"}N{W="1B("+5y+")"}D.hn=W}F W},6r:G(){F B.J.4L(D.1B)},t2:G(){u m=B.V;u c=D.1B;u 2Z=B.V.6F;u W=D.hm;if(!W){W=("#"+m.6E(2Z(c.r,3h))+m.6E(2Z(c.g,3h))+m.6E(2Z(c.b,3h)));D.hm=W}F W},t1:G(){u 2Q=D.2Q;u c=D.1B;if(H(2Q)=="L"||2Q===O){2Q=B.V.bA(D.1B);D.2Q=2Q}F B.J.4L(2Q)},41:G(){u 1G=D.1G;u c=D.1B;if(H(1G)=="L"||1G===O){1G=B.V.bC(D.1B);D.1G=1G}F B.J.4L(1G)},1l:G(){F D.hl()},U:G(){u c=D.1B;u hk=[c.r,c.g,c.b,c.a];F D.bX.1r+"("+hk.2b(", ")+")"}};B.J.2l(B.V.V,{3Y:G(1v,bW,1F,8H){u hj=B.V.V;if(M.K==1){u 1B=1v;1v=1B.r;bW=1B.g;1F=1B.b;if(H(1B.a)=="L"){8H=L}N{8H=1B.a}}F Y hj(1v,bW,1F,8H)},4H:G(1o,t0,sZ,sY){u m=B.V;F m.V.3Y(m.bB.1w(m,M))},sX:G(1o,sW,sV,sU){u m=B.V;F m.V.3Y(m.bz.1w(m,M))},hi:G(1b){u 8F=B.V.V;if(1b.3Z(0)=="\\""){1b=1b.3H(1,1b.K-2)}u bV=8F.by[1b.8G()];if(H(bV)=="1n"){F 8F.bT(bV)}N{if(1b=="aP"){F 8F.sT()}}F O},8f:G(4Q){u I=B.V.V;u bU=4Q.3H(0,3);if(bU=="1B"){F I.h9(4Q)}N{if(bU=="1G"){F I.h8(4Q)}N{if(4Q.3Z(0)=="#"){F I.bT(4Q)}}}F I.hi(4Q)},bT:G(4P){if(4P.3Z(0)=="#"){4P=4P.2W(1)}u 8E=[];u i,5x;if(4P.K==3){R(i=0;i<3;i++){5x=4P.3H(i,1);8E.1c(3w(5x+5x,16)/3h)}}N{R(i=0;i<6;i+=2){5x=4P.3H(i,2);8E.1c(3w(5x,16)/3h)}}u bS=B.V.V;F bS.3Y.1w(bS,8E)},bG:G(4O,hf,hg,4N){if(4N.2A(4O)===0){4N=4N.2W(4N.2A("(",3)+1,4N.K-1)}u bR=4N.2R(/\\s*,\\s*/);u bP=[];R(u i=0;i0){F 8D}}F O},ba:G(Q){u 2F=B.V.V;F 2F.bN(Q,"aZ","he-3U")||2F.sN()},sM:G(Q){u 2F=B.V.V;F 2F.bN(Q,"3U","3U")||2F.sL()},sK:G(){F B.J.4L(B.V.V.by)}});B.J.2l(B.V,{6F:G(v,8C){v*=8C;if(v<0){F 0}N{if(v>8C){F 8C}N{F v}}},hc:G(n1,n2,1o){if(1o>6){1o-=6}N{if(1o<0){1o+=6}}u 2i;if(1o<1){2i=n1+(n2-n1)*1o}N{if(1o<3){2i=n2}N{if(1o<4){2i=n1+(n2-n1)*(4-1o)}N{2i=n1}}}F 2i},bz:G(1o,5w,3i,bM){if(M.K==1){u 2Q=1o;1o=2Q.h;5w=2Q.s;3i=2Q.v;bM=2Q.a}u 1v;u 3K;u 1F;if(5w===0){1v=0;3K=0;1F=0}N{u i=28.8B(1o*6);u f=(1o*6)-i;u p=3i*(1-5w);u q=3i*(1-(5w*f));u t=3i*(1-(5w*(1-f)));hd(i){3j 1:1v=q;3K=3i;1F=p;2K;3j 2:1v=p;3K=3i;1F=t;2K;3j 3:1v=p;3K=q;1F=3i;2K;3j 4:1v=t;3K=p;1F=3i;2K;3j 5:1v=3i;3K=p;1F=q;2K;3j 6:3j 0:1v=3i;3K=t;1F=p;2K}}F{r:1v,g:3K,b:1F,a:bM}},bB:G(1o,5v,3v,bL){if(M.K==1){u 1G=1o;1o=1G.h;5v=1G.s;3v=1G.l;bL=1G.a}u 1v;u 8A;u 1F;if(5v===0){1v=3v;8A=3v;1F=3v}N{u m2;if(3v<=0.5){m2=3v*(1+5v)}N{m2=3v+5v-(3v*5v)}u m1=(2*3v)-m2;u f=B.V.hc;u h6=1o*6;1v=f(m1,m2,h6+2);8A=f(m1,m2,h6);1F=f(m1,m2,h6-2)}F{r:1v,g:8A,b:1F,a:bL}},bA:G(1v,4K,1F,bK){if(M.K==1){u 1B=1v;1v=1B.r;4K=1B.g;1F=1B.b;bK=1B.a}u 29=28.29(28.29(1v,4K),1F);u 2a=28.2a(28.2a(1v,4K),1F);u 1o;u 8z;u hb=29;if(2a==29){1o=0;8z=0}N{u 6H=(29-2a);8z=6H/29;if(1v==29){1o=(4K-1F)/6H}N{if(4K==29){1o=2+((1F-1v)/6H)}N{1o=4+((1v-4K)/6H)}}1o/=6;if(1o<0){1o+=1}if(1o>1){1o-=1}}F{h:1o,s:8z,v:hb,a:bK}},bC:G(1v,4J,1F,bI){if(M.K==1){u 1B=1v;1v=1B.r;4J=1B.g;1F=1B.b;bI=1B.a}u 29=28.29(1v,28.29(4J,1F));u 2a=28.2a(1v,28.2a(4J,1F));u 1o;u 6G;u bJ=(29+2a)/2;u 4I=29-2a;if(4I===0){1o=0;6G=0}N{if(bJ<=0.5){6G=4I/(29+2a)}N{6G=4I/(2-29-2a)}if(1v==29){1o=(4J-1F)/4I}N{if(4J==29){1o=2+((1F-1v)/4I)}N{1o=4+((1v-4J)/4I)}}1o/=6;if(1o<0){1o+=1}if(1o>1){1o-=1}}F{h:1o,s:6G,l:bJ,a:bI}},6E:G(1P){1P=28.ha(1P);u bH=1P.1l(16);if(1P<16){F"0"+bH}F bH},2d:G(){u m=B.J;D.V.h9=m.1O(D.V.bG,D.V,"1B","3Y",[1/3h,1/3h,1/3h,1]);D.V.h8=m.1O(D.V.bG,D.V,"1G","4H",[1/bF,0.bE,0.bE,1]);u 4G=1/3;u bD={8y:[0,0,0],1F:[0,0,1],gY:[0.6,0.4,0.2],gX:[0,1,1],sJ:[4G,4G,4G],gR:[0.5,0.5,0.5],bx:[0,1,0],sI:[2*4G,2*4G,2*4G],gN:[1,0,1],gL:[1,0.5,0],gK:[0.5,0,0.5],1v:[1,0,0],aP:[0,0,0,0],4F:[1,1,1],gI:[1,1,0]};u h7=G(1b,r,g,b,a){u W=D.3Y(r,g,b,a);D[1b]=G(){F W};F W};R(u k in bD){u 1b=k+"V";u h5=m.2o([h7,D.V,1b],bD[k]);D.V[1b]=m.1O.1w(O,h5)}u h0=G(){R(u i=0;i1){u 1d=B.S.1E(M[0]);u 2D=M[1];u 1i=M[2];u 1A=M[3];R(u i=5o.K-1;i>=0;i--){u o=5o[i];if(o[0]===1d&&o[1]===2D&&o[4]===1i&&o[5]===1A){I.6t(o);5o.4y(i,1);F 1h}}}N{u 5n=m.bi(5o,bh);if(5n>=0){I.6t(bh);5o.4y(5n,1);F 1h}}F 1m},8i:G(1d,2D){1d=B.S.1E(1d);u m=B.J;u 8l=m.bg(m.1R(O,M,1));u I=B.1u;u bd=I.6t;u 4z=I.4x;if(8l.K===0){R(u i=4z.K-1;i>=0;i--){u 4A=4z[i];if(4A[0]===1d){bd(4A);4z.4y(i,1)}}}N{u bf={};R(u i=0;i<8l.K;i++){bf[8l[i]]=1h}R(u i=4z.K-1;i>=0;i--){u 4A=4z[i];if(4A[0]===1d&&4A[1]in bf){bd(4A);4z.4y(i,1)}}}},8h:G(1d,2D){u bc=B.1u.4x;1d=B.S.1E(1d);u 3G=B.J.1R(O,M,2);u 5m=[];R(u i=0;i1){u e=Y 2x("mZ bb mY in mX \'2D\', mW bb mV");e.bb=5m;14 e}}}});B.1u.1W=[];B.1u.1z=["6s","8j","8h","8i"];B.1u.2d=G(2m){u m=B.J;D.1Z=2v;D.3X=2m;1f{D.6s(2O,"g8",D.g7)}1e(e){}D.2k={":3e":D.1z,":1p":m.2o(D.1z,D.1W)};m.3f(D)};B.1u.2d(D);if(!B.3d){6s=B.1u.6s;8j=B.1u.8j;8i=B.1u.8i;8h=B.1u.8h}B.J.2Y(D,B.1u);if(H(1q)!="L"){1q.2X("B.1X");1q.2M("B.J");1q.2M("B.S");1q.2M("B.V")}if(H(1x)!="L"){1x.26("B.J",[]);1x.26("B.S",[]);1x.26("B.V",[])}1f{if(H(B.J)=="L"||H(B.S)=="L"||H(B.V)=="L"){14""}}1e(e){14"B.1X 3F on B.J, B.S 3W B.V!"}if(H(B.1X)=="L"){B.1X={}}B.1X.1r="B.1X";B.1X.1Y="1.3.1";B.1X.1K=G(){F"["+D.1r+" "+D.1Y+"]"};B.1X.1l=G(){F D.1K()};B.1X.aI=G(e,g6){e=B.S.1E(e);D.fN(g6);if(D.1S.fL){e=D.g5(e)}u 4w=D.1S.3U;u C=B.V.V;if(D.1S.3U=="aW"){4w=C.ba(e)}N{if(!(4w 2C C)){4w=C.8f(4w)}}D.82=(4w.6r().a<=0);u 5l=D.1S.aV;if(D.1S.aV=="fM"){5l=C.ba(e.8g)}N{if(!(5l 2C C)){5l=C.8f(5l)}}D.g3(e,4w,5l)};B.1X.aI.1U={g5:G(e){u mU=e.3t;u 1N=B.S.b9();if(H(1N.5k)=="L"||1N.5k===O){F e}u 4v=1N.5k.g4(e,O);if(H(4v)=="L"||4v===O){F e}u b8=B.S.6m({"1T":{3u:"8c",mT:4v.6q("6p-3D"),85:4v.6q("6p-3g"),mS:4v.6q("6p-6f"),86:4v.6q("6p-2I"),6p:"2N"}});b8.6o=e.6o;e.6o="";e.2c(b8);F e},g3:G(e,b7,8e){if(D.1S.3E){D.g2(e,8e)}if(D.fy()){D.fX(e,b7,8e)}if(D.fx()){D.fV(e,b7,8e)}},g2:G(el,g1){u b6="6l 8a "+D.aQ(g1);u g0="3E-2I: "+b6;u fZ="3E-3g: "+b6;u fY="1T=\'"+g0+";"+fZ+"\'";el.6o="<4u "+fY+">"+el.6o+""},fX:G(el,fW,b5){u b4=D.b1(b5);R(u i=0;i=0;i--){b2.2c(D.b0(fU,b3,i,"6f"))}el.1T.mP=0;el.2c(b2)},b1:G(fT){u 2q=B.S;F 2q.6m({1T:{aZ:fT.1l()}})},b0:G(aY,fQ,n,aX){u 6k=B.S.8d();u 2p=6k.1T;2p.aZ=aY.1l();2p.3u="8c";2p.3V="6l";2p.fS="fR";2p.mO="6l";u 8b=D.aQ(aY,fQ);if(D.1S.3E&&n===0){2p.mN="8a";2p.mM="6l";2p.84="2N";2p.83="2N";2p.mL="2N";2p.3V="2N";2p.fP=8b.1l()}N{if(8b){2p.fP=8b.1l();2p.mK="8a";2p.mJ="2N 6l"}}if(!D.1S.4r&&(n==(D.1S.89-1))){2p.3V="fO"}D.fI(6k,n,aX);D.fG(6k,n,aX);F 6k},fN:G(fK){D.1S={6g:"1p",3U:"aW",aV:"fM",5j:1h,3E:1m,4r:1m,fL:1m};B.J.2l(D.1S,fK);D.1S.89=(D.1S.4r?2:4)},aL:G(){u 88=D.1S.6g;if(D.6h(88,"1p","3D")){F""}u aU=(88.2A("tl")!=-1);u aT=(88.2A("tr")!=-1);if(aU&&aT){F""}if(aU){F"2I"}if(aT){F"3g"}F""},aK:G(){u 87=D.1S.6g;if(D.6h(87,"1p","6f")){F""}u aS=(87.2A("bl")!=-1);u aR=(87.2A("br")!=-1);if(aS&&aR){F""}if(aS){F"2I"}if(aR){F"3g"}F""},aQ:G(aN,aO){if(aN=="aP"){F aO}N{if(D.1S.3E){F D.1S.3E}N{if(D.1S.5j){F aO.fJ(aN)}}}F""},fI:G(el,n,fH){u 6j=D.fE(n)+"px";u aM=(fH=="3D"?D.aL():D.aK());u 4t=el.1T;if(aM=="2I"){4t.86=6j;4t.85="2N"}N{if(aM=="3g"){4t.85=6j;4t.86="2N"}N{4t.86=6j;4t.85=6j}}},fG:G(el,n,fF){u 6i=D.fz(n)+"px";u aJ=(fF=="3D"?D.aL():D.aK());u 4s=el.1T;if(aJ=="2I"){4s.84=6i;4s.83="2N"}N{if(aJ=="3g"){4s.83=6i;4s.84="2N"}N{4s.84=6i;4s.83=6i}}},fE:G(n){if(D.82){F 0}u o=D.1S;if(o.4r&&o.5j){u fD=[1,0];F fD[n]}N{if(o.4r){u fC=[2,1];F fC[n]}N{if(o.5j){u fB=[3,2,1,0];F fB[n]}N{u fA=[5,3,2,1];F fA[n]}}}},fz:G(n){u o=D.1S;u 5i;if(o.4r&&(o.5j||D.82)){F 1}N{if(o.4r){5i=[1,0]}N{if(o.5j){5i=[2,1,1,1]}N{if(o.3E){5i=[0,2,0,0]}N{if(D.82){5i=[5,3,2,1]}N{F 0}}}}}F 5i[n]},6h:G(1y){R(u i=1;i")}}})()}',62,1976,'||||||||||||||||||||||||||||||var|||||||MochiKit||this||return|function|typeof|self|Base|length|undefined|arguments|else|null||elem|for|DOM||repr|Color|rval|res|new||||||throw|Iter|||||next|name|push|src|catch|try|lst|true|obj|node|Async|toString|false|string|hue|all|dojo|NAME|Format|msg|Signal|red|apply|JSAN|str|EXPORT|func|rgb|_425|DateTime|getElement|blue|hsl|Logging|LoggingPane|type|__repr__|_event|while|doc|bind|num|iter|extend|options|style|prototype|seq|EXPORT_OK|Visual|VERSION|_document||_434||replace|forwardCall|StopIteration|use||Math|max|min|join|appendChild|__new__|button|compare|date|key|val|_329|EXPORT_TAGS|update|win|pair|concat|_596|dom|map|req|Deferred|sync|document|base|Error|number|partial|indexOf||instanceof|sig|not|cls|list|fired|left|stop|break|logger|require|0px|window|shift|hsv|split|createElement|_423|callee|continue|substring|provide|_exportSymbols|ccc||_464|||||||||step|pred|_51|__compat__|common|nameFunctions|right|255|_517|case|100|_loggingPane|value|object|callback|TypeError|_251|_246|_113|parentNode|display|_522|parseInt|cssText|wrap|info|isArrayLike|end|match|top|border|depends|args|substr|mouse|code|_519|_443|className|level|err|frac|Date|_135|_85|nodeType|color|height|and|_window|fromRGB|charAt||asHSL|_444|message||||filter||LogMessage|AdapterRegistry|_366|imap|NotFound|locked|counter|_262|_messages|operator|cmp|_165|_161|pairs|arr|_52|setAttribute|computedStyle|compact|_614|_610|div|_576|_572|_observers|splice|_565|_566|_555|scrollTop|page|modifier|white|_541|fromHSL|_539|_535|_528|clone|parseFloat|_505|pre|_499|_497|_427|createTextNode|_446|attributeArray|_388|_379|updateNodeAttributes|_341|_326||box|errback|results|paused|chain|_285||ofs||NamedError|_175|_147|_122|_83|_54|_17|childNodes|_619|blend|defaultView|_574|_569|idx|_562|must|_554|_specialKeys|body|Coordinates|registerComparator|_521|_516|hex|mid|_478|width|loggingPane|LogLevel|nwin|head|url|setElementClass|callStack|path|dest|_359|boolean|register|Dimensions|DeferredLock|_313|addCallback|_310|waiting|onreadystatechange|_290|LOCALE|year|printfire|_214|log|_213|_211|pos|_155|_153||typeMatcher|listMinMax|_114|_40|itr|typ|_19|_634|_625|bottom|corners|_hasString|_612|_608|_595|1px|DIV|firstChild|innerHTML|padding|getPropertyValue|asRGB|connect|_disconnect|_559|middle|which|clientY|scrollLeft|clientX|client|charCode|relatedTarget|event|toColorPart|clampColorComponent|_537|_534|toFixed|_468|buildAndApplyFilter|_442|_441|_440|_439|position|_463|_447|removeChild|_449|uid|_428|_426|compliant|attributes|_422|_409|_412|_400|_395|_390|_389|_377|_375|_363|attr|ctx|repeat|_340|_339|isNotEmpty|_335|_333|opera|DeferredList|ret|_309|silentlyCancelled|canceller|_nextId|Array|_293|XMLHttpRequest|chained|_281|tail|_252|_225|msec|day|month|iso|Logger|_208|listeners|_200|_198|_194|_196|reduce|range|_169|_162|truth|registerRepr|_121|_70|_58|_56|_47|_45|_41|_13|_1|script|text|uri|documentElement|_630|_629|isTransparent|borderRightWidth|borderLeftWidth|marginRight|marginLeft|_602|_599|numSlices|solid|_597|block|SPAN|_579|fromString|offsetParent|signal|disconnectAll|disconnect|_570|_563|_557|preventDefault|stopPropagation|clientTop|clientLeft|pageY|pageX|keyCode|meta|ctrl|alt|target|black|_532|_524|floor|_513|_512|_500|_495|toLowerCase|_487|DEBUG|INFO|WARNING|FATAL|ERROR|colorTable|logFont|closed|inline|onclick|_438|_437|_445|RegExp|_452|space|title|updatetree|||||withDocument|withWindow||setDisplayForElement|none|renames|forEach|domConverters|escapeHTML|addElementClass|removeElementClass|once|_378|_380|_376|appendChildNodes|coerceToDOM|_355|opt|clientWidth|opacity|GenericError|fail|resultList|_307|_301|_fire|can|addCallbacks|_resback|percent|decimal|separator|twoDigitFloat|_274|_273|_264|_257|_250|_249|_254|_248|_243|_242|fmt|_240|_245|getTime|sec|hour|_209|slice|_206|iterateNextIter|registerIteratorFactory|arrayLikeIter|iteratorRegistry|takewhile|ifilterfalse|ifilter|_181|_176|_168|_166|_159|_tee|deque|arg|fun|jsonRegistry|reprString|reprRegistry|comparatorRegistry|urlEncode|_110|_108|cur|_95|_87|_71|im_preargs||_53|_57|_46|present|like|array|Argument|_15|_12|_632|_631|_633|SUBMODULES|only|_628|_627|_626|roundElement|_624|getElementsByTagAndClassName|_RoundCorners|_613|_whichSideBottom|_whichSideTop|_609|_605|_606|transparent|_borderColor|_604|_603|_601|_600|bgColor|fromElement|_594|_592|backgroundColor|_createCornerSlice|_createCorner|_590|_589|_587|_586|_581|_578|_577|currentDocument|fromBackground|errors|_568|_564||sigs|flattenArguments|_561|findIdentical|_560|_558||_556|attachEvent|addEventListener|funcOrStr|Event||_548|fromCharCode|String|_specialMacKeys|any|green|_namedColors|hsvToRGB|rgbToHSV|hslToRGB|rgbToHSL|_542|01|360|_fromColorString|_540|_536|_538|_529|_523|_518|fromComputedStyle|_511|_507|_508|_506|_501|fromHexString|_498|_496|_486|__class__|createLoggingPane|_459|_461|font|_462|_430|_435|1000|index|_460|getMessages|removeListener|_451||_457|_450|infore|_448|_456|logDebug|offsetHeight|span|input|_436|TR||HTML|open|alert|currentWindow|swapDOM|SELECT|FORM|INPUT|createDOMFunc|ignoreAttr|_421|call|_417|_410|_415|nodeName|_414|_413|emitHTML|good|_406|_399|_397|_393|_392|addLoadEvent|addToCallStack|_387|_386|_381|_382|_383|_373|_372|_369|createDOM|_365|Function|_360|_362|_358|_344|nodeWalk|formContents|_337|_338|_334|_332|offsetTop|offsetLeft|visibility|parentElement|||XMLHttpRequestError|BrowserComplianceError|CancelledError|AlreadyCalledError|evalJSONRequest|sendXMLHttpRequest|wait|doSimpleXMLHttpRequest|getXMLHttpRequest|succeed|_312|finishedCount|_308|_cbDeferred|_303|_297|queryString|_nothing|_289|XMLHTTP|ActiveXObject|eval|_284|_check|error|_279|default|rstrip|lstrip|formatLocale|roundToFixed|truncToFixed|_276|pow|_272|_271|_270|sign|_265|_263|tmp|_238|_232|toISODate|toISOTime|getFullYear|getDate|getMonth|_230|_padTwo|_228|useNativeConsole|_212|compareLogMessage|isLogMessage|unshift|_207||maxSize|_202|_199|logLevelAtLeast|console|hasIterateNext|iterateNext|arrayLike|groupby||exhaust|tee|dropwhile|applymap||islice|izip|cycle|count||_189|_188|_183|_185|_184|_186|_187|_182|identity|fetch|_180|_177|listMin|reprNumber|reprArrayLike|compareArrayLike|compareDateLike|isDateLike|findValue|_128|__export__|keyComparator|_124|_118|_93|_94|_90|_88|_84|_77|_68|_67|_66|_65|_60|im_func|_55|im_self|_48|_44|_42|_39|_36|_33|_27|_26|_25|_22|_24|_20|javascript|write|getAttribute||org|www|http|getElementsByTagName|roundClass|_623|_622|_621|_620|_isBottomRounded|_isTopRounded|_borderSize|_618|_617|_616|_615|_marginSize|_611|_setBorder|_607|_setMargin|blendedColor|_598|__unstable__wrapElement|fromParent|_setOptions|2px|borderColor|_593|hidden|overflow|_591|_588|_roundBottomCorners|_585|_roundTopCorners|_584|_583|_582|_580|_renderBorder|_roundCornersImpl|getComputedStyle|_doWrap|_571|_unloadCache|onunload|detachEvent|removeEventListener|_listener|objOrFunc|_552||_551|_549|onload|delete|112|KEY_F|KEY_|MINUS|KEY_SEMICOLON|KEY_DELETE|KEY_INSERT|KEY_ARROW_DOWN|KEY_ARROW_RIGHT|KEY_ARROW_UP||KEY_ARROW_LEFT|KEY_HOME|KEY_END|KEY_PAGE_DOWN|KEY_PAGE_UP|KEY_ENTER|KEY_NUM_PAD_CLEAR|63236|mousemove|contextmenu|click|mouseout|mouseover|_src|yellow|708090|purple|orange|ff00ff|magenta|778899|d3d3d3|808080|gray|696969|2f4f4f|darkred|a9a9a9|00ffff|cyan|brown|_547|_546||||compareRGB|_545||_543|fromHSLString|fromRGBString|round|_533|_hslValue|switch|background|_503|_504||fromName|_488|col|toRGBString|_hexString|_rgbString|_hslString|toPrecision|isLight||_481|_477|_476|_475|_474|_473|_469|_466|closePane|_458|onkeypress|_454|addListener|_455|close|test|scrollHeight|option|word|moz|_431|getElementById|html|pop|200|_|removeElement|showElement|hideElement|CANVAS|STRONG|FIELDSET|LEGEND|OPTGROUP|OPTION|TEXTAREA|LABEL|HR|BR|H3|H2|H1|PRE|TT|BUTTON|IMG|TH||TABLE||TFOOT|THEAD|TBODY|TD|LI|OL|||UL|checked|class|ignoreAttrFilter||_424|_419|nodeValue|scrapeText|_416|_418|sort|_411|toHTML|_404|hasElementClass|_403|_402|_401|swapElementClass|_398|_394|toggleElementClass|_391|focusOnLoad|_newCallStack|currentStyle|_371|replaceChildNodes|_364|_361|getNodeAttribute|_357|setNodeAttribute|_354|_352|_350|_353|toDOM|_346|_345|registerDOMConverter|selectedIndex|setElementPosition|setElementDimensions|tagName|absolute|getBoxObjectFor|getBoundingClientRect|elementPosition|_325|_324|_322|_323|offsetWidth|elementDimensions|clientHeight|innerWidth|getViewportDimensions|setOpacity|status|_317|deferred|_316|_newNamedError|maybeDeferred||gatherResults|callLater|loadJSONDoc|_311|consumeErrors|fireOnOneErrback|fireOnOneCallback|addErrback|_305|_304|_306|unlocked|release|_300|_299|_298|_296|_xhr_onreadystatechange|_xhr_canceller|304|responseText|Msxml2|addBoth|_pause|_continue|result|the|are|they|instances|_unpause|cancel|_280|_278|en_US|strip|percentFormat|twoDigitAverage|numberFormatter|_277|_275|isNaN|_259|_258|_260|_255|_253|_numberFormatter|_241|_239|_237|_236|_235|_234|_233|_231|toAmericanDate|toPaddedAmericanDate|americanDate|toISOTimestamp|isoTimestamp|isoDate|foot|sep||60000|_221|_isoRegexp|dispatchEvent|createEvent|warning|logWarning|fatal|logFatal|debug|logError|baseLog|_210|getMessageText|logToConsole|dispatchListeners|_204|_203|ident|_201|postError|alertListener|_197|_192|groupby_as_array|iextend|some|reversed|sorted|every|sum|_190|eat|_174|_173|_172|_171|_167|_163|_158|_157|_151|_144|_141||_139|_136|_134||_133|_132|zip|merge|isUndefined|isCallable|listMax|_131|_130|encodeURIComponent||_127|method|parseQueryString|evalJSON|registerJSON|serializeJSON|objMin|objMax|reverseKeyComparator|arrayEqual|objEqual|bindMethods|xfilter|xmap|isEmpty|isNull|isUndefinedOrNull|itemgetter|items|keys|setdefault|_126|_120|decodeURIComponent|_119|len|_109|_107|_104|_105|_101|_102|_98|||_100|_97|_96|_91|json|__json__|_82|_81|_80|_79|_76||_75|_74|_73|_69|_primitives|_64|_63||_62|_61|_59|_wrapDumbFunction|_49|_50|_31|_30|_21|_7|application|MochiKit_|createElementNS|namespaceURI|lastIndexOf|xul|there|gatekeeper|keymaster|mozilla|getElementsComputedStyle|_hasSingleTextChild|borderWidth|borderStyle|borderBottomWidth|borderTopWidth|borderTopStyle|fontSize|paddingBottom|insertBefore|paddingTop|marginBottom|marginTop|_575|property|see|handling|thrown|Multiple|element|||given|123|KEY_NUM_PAD_|105|KEY_APOSTROPHE|222|KEY_RIGHT_SQUARE_BRACKET|221|KEY_REVERSE_SOLIDUS|220|KEY_LEFT_SQUARE_BRACKET||219|KEY_GRAVE_ACCENT|192|KEY_SOLIDUS|191|KEY_FULL_STOP|190|KEY_HYPHEN|189||KEY_COMMA|188|KEY_EQUALS_SIGN|187|186|KEY_SCROLL_LOCK|145|KEY_NUM_LOCK|144|KEY_NUM_PAD_SOLIDUS|111|KEY_NUM_PAD_FULL_STOP|110|KEY_NUM_PAD_HYPHEN|109|KEY_NUM_PAD_PLUS_SIGN|107|KEY_NUM_PAD_ASTERISK|106|KEY_SELECT|KEY_WINDOWS_RIGHT|KEY_WINDOWS_LEFT|KEY_PRINT_SCREEN|KEY_SPACEBAR|KEY_ESCAPE|KEY_CAPS_LOCK|KEY_PAUSE|KEY_ALT|KEY_CTRL|KEY_SHIFT|KEY_TAB|KEY_BACKSPACE|63242|63272|63302|63233|63235|63232|63234|63273|63275|63277|63276|63289|returnValue|cancelBubble|keypress|KEY_UNKNOWN|keyup|keydown|shiftKey|metaKey||ctrlKey|altKey|toElement|srcElement|9acd32||yellowgreen||ffff00|f5f5f5|whitesmoke||ffffff|f5deb3|wheat|ee82ee|violet|40e0d0|turquoise|ff6347|tomato|d8bfd8|thistle|008080|teal|d2b48c|tan|4682b4|steelblue|00ff7f|springgreen|fffafa|snow|slategrey|slategray|6a5acd|slateblue|87ceeb|skyblue|c0c0c0|silver|a0522d|sienna|fff5ee|seashell|2e8b57|seagreen|f4a460|sandybrown|fa8072|salmon|8b4513|saddlebrown|4169e1|royalblue|bc8f8f|rosybrown|ff0000|800080|b0e0e6|powderblue|dda0dd|plum|ffc0cb|pink|cd853f||peru|ffdab9|peachpuff|ffefd5|papayawhip|db7093|palevioletred|afeeee|paleturquoise|98fb98|palegreen|eee8aa||palegoldenrod|da70d6|orchid|ff4500|orangered|ffa500|6b8e23|olivedrab|808000|olive|fdf5e6|oldlace|000080|navy|ffdead|navajowhite|ffe4b5|moccasin|ffe4e1|mistyrose|f5fffa|mintcream|191970|midnightblue|c71585|mediumvioletred|48d1cc|mediumturquoise|00fa9a|mediumspringgreen|7b68ee|mediumslateblue|3cb371|mediumseagreen|9370db|mediumpurple|ba55d3|mediumorchid|0000cd|mediumblue|66cdaa|mediumaquamarine|800000|maroon|faf0e6|linen|32cd32|limegreen|00ff00|lime|ffffe0|lightyellow|b0c4de|lightsteelblue|lightslategrey|lightslategray||87cefa|lightskyblue|20b2aa|lightseagreen|ffa07a|lightsalmon|ffb6c1|lightpink|lightgrey|90ee90|lightgreen|lightgray|fafad2|lightgoldenrodyellow|e0ffff|lightcyan|f08080|lightcoral|add8e6|lightblue|fffacd|lemonchiffon|7cfc00|lawngreen|fff0f5|lavenderblush|e6e6fa|lavender|f0e68c|khaki|fffff0|ivory|4b0082|indigo|cd5c5c|indianred|ff69b4|hotpink|f0fff0|honeydew|grey|adff2f|greenyellow|008000|daa520|goldenrod|ffd700||gold|f8f8ff|ghostwhite|dcdcdc|gainsboro|fuchsia|228b22|forestgreen|fffaf0|floralwhite|b22222|firebrick|1e90ff|dodgerblue|dimgrey|dimgray|00bfff|deepskyblue|ff1493|deeppink|9400d3|darkviolet|00ced1|darkturquoise|darkslategrey|darkslategray|483d8b|darkslateblue|8fbc8f|darkseagreen|e9967a|darksalmon|8b0000|9932cc|darkorchid|ff8c00|darkorange|556b2f|darkolivegreen|8b008b|darkmagenta|bdb76b|darkkhaki|darkgrey|006400|darkgreen|darkgray|b8860b|darkgoldenrod|008b8b|darkcyan|00008b|darkblue|dc143c|crimson|fff8dc|cornsilk|6495ed|cornflowerblue|ff7f50|coral|d2691e||chocolate|7fff00|chartreuse|5f9ea0|cadetblue|deb887|burlywood|a52a2a|8a2be2|blueviolet|0000ff|ffebcd||blanchedalmond|000000|ffe4c4|bisque|f5f5dc|beige|f0ffff|azure|7fffd4|aquamarine|aqua|faebd7|antiquewhite|f0f8ff|aliceblue|lightGray|darkGray|namedColors|blackColor|fromText|whiteColor|_510|_509|PI|rad|deg|transparentColor|_494|_493|_492|fromHSV|_491|_490|_489|asHSV|toHexString|rgba|hsla|toHSLString|isDark|lighterColorWithLevel|darkerColorWithLevel|colorWithLightness|colorWithSaturation|colorWithHue|colorWithAlpha||serif|sans|Verdana||8pt|8em|auto||Close|Clear||Load|Filter||10em||fixed|regex|emergency|line|margin|_Listener|dtd|loose|html4|w3|EN|Transitional|DTD|W3C|PUBLIC|DOCTYPE|blocking|due|debugging|able|Not|resizable|dependent|href|location|_MochiKit_LoggingPane|_429|canvas|strong|fieldset|legend|optgroup|select|form|textarea|label|img|table|tfoot|thead|tbody|htmlFor||useMap|usemap|defaultChecked|hasChildNodes|quot|amp|_405|focus|replaceChild|checkbox||radio|_win|BODY||safari|version|userAgent|navigator|innerHeight|alpha|khtml|Tried|acquire|clearTimeout|setTimeout|GET|ignore|send|abort|failed|Request|readyState|support|does|Browser|Microsoft|_288|_287|used|Deferreds|Chained|success|unfired|fr_FR|de_DE|00|abs|search|pattern|Invalid|getTimezoneOffset|getSeconds|getMinutes|getHours|UTC|3600000|initEvent|Events|debuggingBookmarklet|MESSAGES|LAST|_205|clear|ninfo|nlevel|timestamp|reverse|takes|initial|with|sequence|empty|iterable|numbers|dateLike|escape|find|forward|unregister|unescape|Object|compared|item|contains|logor|logand|cle|clt|cge|cgt|cne|ceq|zrshift|rshift|lshift|xor|mul|mod|sub|add|neg|lognot|_9|_2'.split('|'),0,{}) + + +/* + * jQuery 1.2.1 - New Wave Javascript + * + * Copyright (c) 2007 John Resig (jquery.com) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * $Date: 2007-09-16 23:42:06 -0400 (Sun, 16 Sep 2007) $ + * $Rev: 3353 $ + */ + +var decompressedJQuery = function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(G(){9(1m E!="W")H w=E;H E=18.15=G(a,b){I 6 7u E?6.5N(a,b):1u E(a,b)};9(1m $!="W")H D=$;18.$=E;H u=/^[^<]*(<(.|\\s)+>)[^>]*$|^#(\\w+)$/;E.1b=E.3A={5N:G(c,a){c=c||U;9(1m c=="1M"){H m=u.2S(c);9(m&&(m[1]||!a)){9(m[1])c=E.4D([m[1]],a);J{H b=U.3S(m[3]);9(b)9(b.22!=m[3])I E().1Y(c);J{6[0]=b;6.K=1;I 6}J c=[]}}J I 1u E(a).1Y(c)}J 9(E.1n(c))I 1u E(U)[E.1b.2d?"2d":"39"](c);I 6.6v(c.1c==1B&&c||(c.4c||c.K&&c!=18&&!c.1y&&c[0]!=W&&c[0].1y)&&E.2h(c)||[c])},4c:"1.2.1",7Y:G(){I 6.K},K:0,21:G(a){I a==W?E.2h(6):6[a]},2o:G(a){H b=E(a);b.4Y=6;I b},6v:G(a){6.K=0;1B.3A.1a.16(6,a);I 6},N:G(a,b){I E.N(6,a,b)},4I:G(a){H b=-1;6.N(G(i){9(6==a)b=i});I b},1x:G(f,d,e){H c=f;9(f.1c==3X)9(d==W)I 6.K&&E[e||"1x"](6[0],f)||W;J{c={};c[f]=d}I 6.N(G(a){L(H b 1i c)E.1x(e?6.R:6,b,E.1e(6,c[b],e,a,b))})},17:G(b,a){I 6.1x(b,a,"3C")},2g:G(e){9(1m e!="5i"&&e!=S)I 6.4n().3g(U.6F(e));H t="";E.N(e||6,G(){E.N(6.3j,G(){9(6.1y!=8)t+=6.1y!=1?6.6x:E.1b.2g([6])})});I t},5m:G(b){9(6[0])E(b,6[0].3H).6u().3d(6[0]).1X(G(){H a=6;1W(a.1w)a=a.1w;I a}).3g(6);I 6},8m:G(a){I 6.N(G(){E(6).6q().5m(a)})},8d:G(a){I 6.N(G(){E(6).5m(a)})},3g:G(){I 6.3z(1q,Q,1,G(a){6.58(a)})},6j:G(){I 6.3z(1q,Q,-1,G(a){6.3d(a,6.1w)})},6g:G(){I 6.3z(1q,P,1,G(a){6.12.3d(a,6)})},50:G(){I 6.3z(1q,P,-1,G(a){6.12.3d(a,6.2q)})},2D:G(){I 6.4Y||E([])},1Y:G(t){H b=E.1X(6,G(a){I E.1Y(t,a)});I 6.2o(/[^+>] [^+>]/.14(t)||t.1g("..")>-1?E.4V(b):b)},6u:G(e){H f=6.1X(G(){I 6.67?E(6.67)[0]:6.4R(Q)});H d=f.1Y("*").4O().N(G(){9(6[F]!=W)6[F]=S});9(e===Q)6.1Y("*").4O().N(G(i){H c=E.M(6,"2P");L(H a 1i c)L(H b 1i c[a])E.1j.1f(d[i],a,c[a][b],c[a][b].M)});I f},1E:G(t){I 6.2o(E.1n(t)&&E.2W(6,G(b,a){I t.16(b,[a])})||E.3m(t,6))},5V:G(t){I 6.2o(t.1c==3X&&E.3m(t,6,Q)||E.2W(6,G(a){I(t.1c==1B||t.4c)?E.2A(a,t)<0:a!=t}))},1f:G(t){I 6.2o(E.1R(6.21(),t.1c==3X?E(t).21():t.K!=W&&(!t.11||E.11(t,"2Y"))?t:[t]))},3t:G(a){I a?E.3m(a,6).K>0:P},7c:G(a){I 6.3t("."+a)},3i:G(b){9(b==W){9(6.K){H c=6[0];9(E.11(c,"24")){H e=c.4Z,a=[],Y=c.Y,2G=c.O=="24-2G";9(e<0)I S;L(H i=2G?e:0,33=2G?e+1:Y.K;i<33;i++){H d=Y[i];9(d.26){H b=E.V.1h&&!d.9V["1Q"].9L?d.2g:d.1Q;9(2G)I b;a.1a(b)}}I a}J I 6[0].1Q.1p(/\\r/g,"")}}J I 6.N(G(){9(b.1c==1B&&/4k|5j/.14(6.O))6.2Q=(E.2A(6.1Q,b)>=0||E.2A(6.2H,b)>=0);J 9(E.11(6,"24")){H a=b.1c==1B?b:[b];E("9h",6).N(G(){6.26=(E.2A(6.1Q,a)>=0||E.2A(6.2g,a)>=0)});9(!a.K)6.4Z=-1}J 6.1Q=b})},4o:G(a){I a==W?(6.K?6[0].3O:S):6.4n().3g(a)},6H:G(a){I 6.50(a).28()},6E:G(i){I 6.2J(i,i+1)},2J:G(){I 6.2o(1B.3A.2J.16(6,1q))},1X:G(b){I 6.2o(E.1X(6,G(a,i){I b.2O(a,i,a)}))},4O:G(){I 6.1f(6.4Y)},3z:G(f,d,g,e){H c=6.K>1,a;I 6.N(G(){9(!a){a=E.4D(f,6.3H);9(g<0)a.8U()}H b=6;9(d&&E.11(6,"1I")&&E.11(a[0],"4m"))b=6.4l("1K")[0]||6.58(U.5B("1K"));E.N(a,G(){H a=c?6.4R(Q):6;9(!5A(0,a))e.2O(b,a)})})}};G 5A(i,b){H a=E.11(b,"1J");9(a){9(b.3k)E.3G({1d:b.3k,3e:P,1V:"1J"});J E.5f(b.2g||b.6s||b.3O||"");9(b.12)b.12.3b(b)}J 9(b.1y==1)E("1J",b).N(5A);I a}E.1k=E.1b.1k=G(){H c=1q[0]||{},a=1,2c=1q.K,5e=P;9(c.1c==8o){5e=c;c=1q[1]||{}}9(2c==1){c=6;a=0}H b;L(;a<2c;a++)9((b=1q[a])!=S)L(H i 1i b){9(c==b[i])6r;9(5e&&1m b[i]==\'5i\'&&c[i])E.1k(c[i],b[i]);J 9(b[i]!=W)c[i]=b[i]}I c};H F="15"+(1u 3D()).3B(),6p=0,5c={};E.1k({8a:G(a){18.$=D;9(a)18.15=w;I E},1n:G(a){I!!a&&1m a!="1M"&&!a.11&&a.1c!=1B&&/G/i.14(a+"")},4a:G(a){I a.2V&&!a.1G||a.37&&a.3H&&!a.3H.1G},5f:G(a){a=E.36(a);9(a){9(18.6l)18.6l(a);J 9(E.V.1N)18.56(a,0);J 3w.2O(18,a)}},11:G(b,a){I b.11&&b.11.27()==a.27()},1L:{},M:G(c,d,b){c=c==18?5c:c;H a=c[F];9(!a)a=c[F]=++6p;9(d&&!E.1L[a])E.1L[a]={};9(b!=W)E.1L[a][d]=b;I d?E.1L[a][d]:a},30:G(c,b){c=c==18?5c:c;H a=c[F];9(b){9(E.1L[a]){2E E.1L[a][b];b="";L(b 1i E.1L[a])1T;9(!b)E.30(c)}}J{2a{2E c[F]}29(e){9(c.53)c.53(F)}2E E.1L[a]}},N:G(a,b,c){9(c){9(a.K==W)L(H i 1i a)b.16(a[i],c);J L(H i=0,48=a.K;i<48;i++)9(b.16(a[i],c)===P)1T}J{9(a.K==W)L(H i 1i a)b.2O(a[i],i,a[i]);J L(H i=0,48=a.K,3i=a[0];i<48&&b.2O(3i,i,3i)!==P;3i=a[++i]){}}I a},1e:G(c,b,d,e,a){9(E.1n(b))b=b.2O(c,[e]);H f=/z-?4I|7T-?7Q|1r|69|7P-?1H/i;I b&&b.1c==4W&&d=="3C"&&!f.14(a)?b+"2T":b},1o:{1f:G(b,c){E.N((c||"").2l(/\\s+/),G(i,a){9(!E.1o.3K(b.1o,a))b.1o+=(b.1o?" ":"")+a})},28:G(b,c){b.1o=c!=W?E.2W(b.1o.2l(/\\s+/),G(a){I!E.1o.3K(c,a)}).66(" "):""},3K:G(t,c){I E.2A(c,(t.1o||t).3s().2l(/\\s+/))>-1}},2k:G(e,o,f){L(H i 1i o){e.R["3r"+i]=e.R[i];e.R[i]=o[i]}f.16(e,[]);L(H i 1i o)e.R[i]=e.R["3r"+i]},17:G(e,p){9(p=="1H"||p=="2N"){H b={},42,41,d=["7J","7I","7G","7F"];E.N(d,G(){b["7C"+6]=0;b["7B"+6+"5Z"]=0});E.2k(e,b,G(){9(E(e).3t(\':3R\')){42=e.7A;41=e.7w}J{e=E(e.4R(Q)).1Y(":4k").5W("2Q").2D().17({4C:"1P",2X:"4F",19:"2Z",7o:"0",1S:"0"}).5R(e.12)[0];H a=E.17(e.12,"2X")||"3V";9(a=="3V")e.12.R.2X="7g";42=e.7e;41=e.7b;9(a=="3V")e.12.R.2X="3V";e.12.3b(e)}});I p=="1H"?42:41}I E.3C(e,p)},3C:G(h,j,i){H g,2w=[],2k=[];G 3n(a){9(!E.V.1N)I P;H b=U.3o.3Z(a,S);I!b||b.4y("3n")==""}9(j=="1r"&&E.V.1h){g=E.1x(h.R,"1r");I g==""?"1":g}9(j.1t(/4u/i))j=y;9(!i&&h.R[j])g=h.R[j];J 9(U.3o&&U.3o.3Z){9(j.1t(/4u/i))j="4u";j=j.1p(/([A-Z])/g,"-$1").2p();H d=U.3o.3Z(h,S);9(d&&!3n(h))g=d.4y(j);J{L(H a=h;a&&3n(a);a=a.12)2w.4w(a);L(a=0;a<2w.K;a++)9(3n(2w[a])){2k[a]=2w[a].R.19;2w[a].R.19="2Z"}g=j=="19"&&2k[2w.K-1]!=S?"2s":U.3o.3Z(h,S).4y(j)||"";L(a=0;a<2k.K;a++)9(2k[a]!=S)2w[a].R.19=2k[a]}9(j=="1r"&&g=="")g="1"}J 9(h.3Q){H f=j.1p(/\\-(\\w)/g,G(m,c){I c.27()});g=h.3Q[j]||h.3Q[f];9(!/^\\d+(2T)?$/i.14(g)&&/^\\d/.14(g)){H k=h.R.1S;H e=h.4v.1S;h.4v.1S=h.3Q.1S;h.R.1S=g||0;g=h.R.71+"2T";h.R.1S=k;h.4v.1S=e}}I g},4D:G(a,e){H r=[];e=e||U;E.N(a,G(i,d){9(!d)I;9(d.1c==4W)d=d.3s();9(1m d=="1M"){d=d.1p(/(<(\\w+)[^>]*?)\\/>/g,G(m,a,b){I b.1t(/^(70|6Z|6Y|9Q|4t|9N|9K|3a|9G|9E)$/i)?m:a+">"});H s=E.36(d).2p(),1s=e.5B("1s"),2x=[];H c=!s.1g("<9y")&&[1,"<24>",""]||!s.1g("<9w")&&[1,"<6T>",""]||s.1t(/^<(9u|1K|9t|9r|9p)/)&&[1,"<1I>",""]||!s.1g("<4m")&&[2,"<1I><1K>",""]||(!s.1g("<9m")||!s.1g("<9k"))&&[3,"<1I><1K><4m>",""]||!s.1g("<6Y")&&[2,"<1I><1K><6L>",""]||E.V.1h&&[1,"1s<1s>",""]||[0,"",""];1s.3O=c[1]+d+c[2];1W(c[0]--)1s=1s.5p;9(E.V.1h){9(!s.1g("<1I")&&s.1g("<1K")<0)2x=1s.1w&&1s.1w.3j;J 9(c[1]=="<1I>"&&s.1g("<1K")<0)2x=1s.3j;L(H n=2x.K-1;n>=0;--n)9(E.11(2x[n],"1K")&&!2x[n].3j.K)2x[n].12.3b(2x[n]);9(/^\\s/.14(d))1s.3d(e.6F(d.1t(/^\\s*/)[0]),1s.1w)}d=E.2h(1s.3j)}9(0===d.K&&(!E.11(d,"2Y")&&!E.11(d,"24")))I;9(d[0]==W||E.11(d,"2Y")||d.Y)r.1a(d);J r=E.1R(r,d)});I r},1x:G(c,d,a){H e=E.4a(c)?{}:E.5o;9(d=="26"&&E.V.1N)c.12.4Z;9(e[d]){9(a!=W)c[e[d]]=a;I c[e[d]]}J 9(E.V.1h&&d=="R")I E.1x(c.R,"9e",a);J 9(a==W&&E.V.1h&&E.11(c,"2Y")&&(d=="9d"||d=="9a"))I c.97(d).6x;J 9(c.37){9(a!=W){9(d=="O"&&E.11(c,"4t")&&c.12)6G"O 94 93\'t 92 91";c.90(d,a)}9(E.V.1h&&/6C|3k/.14(d)&&!E.4a(c))I c.4p(d,2);I c.4p(d)}J{9(d=="1r"&&E.V.1h){9(a!=W){c.69=1;c.1E=(c.1E||"").1p(/6O\\([^)]*\\)/,"")+(3I(a).3s()=="8S"?"":"6O(1r="+a*6A+")")}I c.1E?(3I(c.1E.1t(/1r=([^)]*)/)[1])/6A).3s():""}d=d.1p(/-([a-z])/8Q,G(z,b){I b.27()});9(a!=W)c[d]=a;I c[d]}},36:G(t){I(t||"").1p(/^\\s+|\\s+$/g,"")},2h:G(a){H r=[];9(1m a!="8P")L(H i=0,2c=a.K;i<2c;i++)r.1a(a[i]);J r=a.2J(0);I r},2A:G(b,a){L(H i=0,2c=a.K;i<2c;i++)9(a[i]==b)I i;I-1},1R:G(a,b){9(E.V.1h){L(H i=0;b[i];i++)9(b[i].1y!=8)a.1a(b[i])}J L(H i=0;b[i];i++)a.1a(b[i]);I a},4V:G(b){H r=[],2f={};2a{L(H i=0,6y=b.K;i<6y;i++){H a=E.M(b[i]);9(!2f[a]){2f[a]=Q;r.1a(b[i])}}}29(e){r=b}I r},2W:G(b,a,c){9(1m a=="1M")a=3w("P||G(a,i){I "+a+"}");H d=[];L(H i=0,4g=b.K;i<4g;i++)9(!c&&a(b[i],i)||c&&!a(b[i],i))d.1a(b[i]);I d},1X:G(c,b){9(1m b=="1M")b=3w("P||G(a){I "+b+"}");H d=[];L(H i=0,4g=c.K;i<4g;i++){H a=b(c[i],i);9(a!==S&&a!=W){9(a.1c!=1B)a=[a];d=d.8M(a)}}I d}});H v=8K.8I.2p();E.V={4s:(v.1t(/.+(?:8F|8E|8C|8B)[\\/: ]([\\d.]+)/)||[])[1],1N:/6w/.14(v),34:/34/.14(v),1h:/1h/.14(v)&&!/34/.14(v),35:/35/.14(v)&&!/(8z|6w)/.14(v)};H y=E.V.1h?"4h":"5h";E.1k({5g:!E.V.1h||U.8y=="8x",4h:E.V.1h?"4h":"5h",5o:{"L":"8w","8v":"1o","4u":y,5h:y,4h:y,3O:"3O",1o:"1o",1Q:"1Q",3c:"3c",2Q:"2Q",8u:"8t",26:"26",8s:"8r"}});E.N({1D:"a.12",8q:"15.4e(a,\'12\')",8p:"15.2I(a,2,\'2q\')",8n:"15.2I(a,2,\'4d\')",8l:"15.4e(a,\'2q\')",8k:"15.4e(a,\'4d\')",8j:"15.5d(a.12.1w,a)",8i:"15.5d(a.1w)",6q:"15.11(a,\'8h\')?a.8f||a.8e.U:15.2h(a.3j)"},G(i,n){E.1b[i]=G(a){H b=E.1X(6,n);9(a&&1m a=="1M")b=E.3m(a,b);I 6.2o(E.4V(b))}});E.N({5R:"3g",8c:"6j",3d:"6g",8b:"50",89:"6H"},G(i,n){E.1b[i]=G(){H a=1q;I 6.N(G(){L(H j=0,2c=a.K;j<2c;j++)E(a[j])[n](6)})}});E.N({5W:G(a){E.1x(6,a,"");6.53(a)},88:G(c){E.1o.1f(6,c)},87:G(c){E.1o.28(6,c)},86:G(c){E.1o[E.1o.3K(6,c)?"28":"1f"](6,c)},28:G(a){9(!a||E.1E(a,[6]).r.K){E.30(6);6.12.3b(6)}},4n:G(){E("*",6).N(G(){E.30(6)});1W(6.1w)6.3b(6.1w)}},G(i,n){E.1b[i]=G(){I 6.N(n,1q)}});E.N(["85","5Z"],G(i,a){H n=a.2p();E.1b[n]=G(h){I 6[0]==18?E.V.1N&&3y["84"+a]||E.5g&&38.33(U.2V["5a"+a],U.1G["5a"+a])||U.1G["5a"+a]:6[0]==U?38.33(U.1G["6n"+a],U.1G["6m"+a]):h==W?(6.K?E.17(6[0],n):S):6.17(n,h.1c==3X?h:h+"2T")}});H C=E.V.1N&&3x(E.V.4s)<83?"(?:[\\\\w*57-]|\\\\\\\\.)":"(?:[\\\\w\\82-\\81*57-]|\\\\\\\\.)",6k=1u 47("^>\\\\s*("+C+"+)"),6i=1u 47("^("+C+"+)(#)("+C+"+)"),6h=1u 47("^([#.]?)("+C+"*)");E.1k({55:{"":"m[2]==\'*\'||15.11(a,m[2])","#":"a.4p(\'22\')==m[2]",":":{80:"im[3]-0",2I:"m[3]-0==i",6E:"m[3]-0==i",3v:"i==0",3u:"i==r.K-1",6f:"i%2==0",6e:"i%2","3v-46":"a.12.4l(\'*\')[0]==a","3u-46":"15.2I(a.12.5p,1,\'4d\')==a","7X-46":"!15.2I(a.12.5p,2,\'4d\')",1D:"a.1w",4n:"!a.1w",7W:"(a.6s||a.7V||15(a).2g()||\'\').1g(m[3])>=0",3R:\'"1P"!=a.O&&15.17(a,"19")!="2s"&&15.17(a,"4C")!="1P"\',1P:\'"1P"==a.O||15.17(a,"19")=="2s"||15.17(a,"4C")=="1P"\',7U:"!a.3c",3c:"a.3c",2Q:"a.2Q",26:"a.26||15.1x(a,\'26\')",2g:"\'2g\'==a.O",4k:"\'4k\'==a.O",5j:"\'5j\'==a.O",54:"\'54\'==a.O",52:"\'52\'==a.O",51:"\'51\'==a.O",6d:"\'6d\'==a.O",6c:"\'6c\'==a.O",2r:\'"2r"==a.O||15.11(a,"2r")\',4t:"/4t|24|6b|2r/i.14(a.11)",3K:"15.1Y(m[3],a).K",7S:"/h\\\\d/i.14(a.11)",7R:"15.2W(15.32,G(1b){I a==1b.T;}).K"}},6a:[/^(\\[) *@?([\\w-]+) *([!*$^~=]*) *(\'?"?)(.*?)\\4 *\\]/,/^(:)([\\w-]+)\\("?\'?(.*?(\\(.*?\\))?[^(]*?)"?\'?\\)/,1u 47("^([:.#]*)("+C+"+)")],3m:G(a,c,b){H d,2b=[];1W(a&&a!=d){d=a;H f=E.1E(a,c,b);a=f.t.1p(/^\\s*,\\s*/,"");2b=b?c=f.r:E.1R(2b,f.r)}I 2b},1Y:G(t,o){9(1m t!="1M")I[t];9(o&&!o.1y)o=S;o=o||U;H d=[o],2f=[],3u;1W(t&&3u!=t){H r=[];3u=t;t=E.36(t);H l=P;H g=6k;H m=g.2S(t);9(m){H p=m[1].27();L(H i=0;d[i];i++)L(H c=d[i].1w;c;c=c.2q)9(c.1y==1&&(p=="*"||c.11.27()==p.27()))r.1a(c);d=r;t=t.1p(g,"");9(t.1g(" ")==0)6r;l=Q}J{g=/^([>+~])\\s*(\\w*)/i;9((m=g.2S(t))!=S){r=[];H p=m[2],1R={};m=m[1];L(H j=0,31=d.K;j<31;j++){H n=m=="~"||m=="+"?d[j].2q:d[j].1w;L(;n;n=n.2q)9(n.1y==1){H h=E.M(n);9(m=="~"&&1R[h])1T;9(!p||n.11.27()==p.27()){9(m=="~")1R[h]=Q;r.1a(n)}9(m=="+")1T}}d=r;t=E.36(t.1p(g,""));l=Q}}9(t&&!l){9(!t.1g(",")){9(o==d[0])d.44();2f=E.1R(2f,d);r=d=[o];t=" "+t.68(1,t.K)}J{H k=6i;H m=k.2S(t);9(m){m=[0,m[2],m[3],m[1]]}J{k=6h;m=k.2S(t)}m[2]=m[2].1p(/\\\\/g,"");H f=d[d.K-1];9(m[1]=="#"&&f&&f.3S&&!E.4a(f)){H q=f.3S(m[2]);9((E.V.1h||E.V.34)&&q&&1m q.22=="1M"&&q.22!=m[2])q=E(\'[@22="\'+m[2]+\'"]\',f)[0];d=r=q&&(!m[3]||E.11(q,m[3]))?[q]:[]}J{L(H i=0;d[i];i++){H a=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];9(a=="*"&&d[i].11.2p()=="5i")a="3a";r=E.1R(r,d[i].4l(a))}9(m[1]==".")r=E.4X(r,m[2]);9(m[1]=="#"){H e=[];L(H i=0;r[i];i++)9(r[i].4p("22")==m[2]){e=[r[i]];1T}r=e}d=r}t=t.1p(k,"")}}9(t){H b=E.1E(t,r);d=r=b.r;t=E.36(b.t)}}9(t)d=[];9(d&&o==d[0])d.44();2f=E.1R(2f,d);I 2f},4X:G(r,m,a){m=" "+m+" ";H c=[];L(H i=0;r[i];i++){H b=(" "+r[i].1o+" ").1g(m)>=0;9(!a&&b||a&&!b)c.1a(r[i])}I c},1E:G(t,r,h){H d;1W(t&&t!=d){d=t;H p=E.6a,m;L(H i=0;p[i];i++){m=p[i].2S(t);9(m){t=t.7O(m[0].K);m[2]=m[2].1p(/\\\\/g,"");1T}}9(!m)1T;9(m[1]==":"&&m[2]=="5V")r=E.1E(m[3],r,Q).r;J 9(m[1]==".")r=E.4X(r,m[2],h);J 9(m[1]=="["){H g=[],O=m[3];L(H i=0,31=r.K;i<31;i++){H a=r[i],z=a[E.5o[m[2]]||m[2]];9(z==S||/6C|3k|26/.14(m[2]))z=E.1x(a,m[2])||\'\';9((O==""&&!!z||O=="="&&z==m[5]||O=="!="&&z!=m[5]||O=="^="&&z&&!z.1g(m[5])||O=="$="&&z.68(z.K-m[5].K)==m[5]||(O=="*="||O=="~=")&&z.1g(m[5])>=0)^h)g.1a(a)}r=g}J 9(m[1]==":"&&m[2]=="2I-46"){H e={},g=[],14=/(\\d*)n\\+?(\\d*)/.2S(m[3]=="6f"&&"2n"||m[3]=="6e"&&"2n+1"||!/\\D/.14(m[3])&&"n+"+m[3]||m[3]),3v=(14[1]||1)-0,d=14[2]-0;L(H i=0,31=r.K;i<31;i++){H j=r[i],12=j.12,22=E.M(12);9(!e[22]){H c=1;L(H n=12.1w;n;n=n.2q)9(n.1y==1)n.4U=c++;e[22]=Q}H b=P;9(3v==1){9(d==0||j.4U==d)b=Q}J 9((j.4U+d)%3v==0)b=Q;9(b^h)g.1a(j)}r=g}J{H f=E.55[m[1]];9(1m f!="1M")f=E.55[m[1]][m[2]];f=3w("P||G(a,i){I "+f+"}");r=E.2W(r,f,h)}}I{r:r,t:t}},4e:G(b,c){H d=[];H a=b[c];1W(a&&a!=U){9(a.1y==1)d.1a(a);a=a[c]}I d},2I:G(a,e,c,b){e=e||1;H d=0;L(;a;a=a[c])9(a.1y==1&&++d==e)1T;I a},5d:G(n,a){H r=[];L(;n;n=n.2q){9(n.1y==1&&(!a||n!=a))r.1a(n)}I r}});E.1j={1f:G(g,e,c,h){9(E.V.1h&&g.4j!=W)g=18;9(!c.2u)c.2u=6.2u++;9(h!=W){H d=c;c=G(){I d.16(6,1q)};c.M=h;c.2u=d.2u}H i=e.2l(".");e=i[0];c.O=i[1];H b=E.M(g,"2P")||E.M(g,"2P",{});H f=E.M(g,"2t",G(){H a;9(1m E=="W"||E.1j.4T)I a;a=E.1j.2t.16(g,1q);I a});H j=b[e];9(!j){j=b[e]={};9(g.4S)g.4S(e,f,P);J g.7N("43"+e,f)}j[c.2u]=c;6.1Z[e]=Q},2u:1,1Z:{},28:G(d,c,b){H e=E.M(d,"2P"),2L,4I;9(1m c=="1M"){H a=c.2l(".");c=a[0]}9(e){9(c&&c.O){b=c.4Q;c=c.O}9(!c){L(c 1i e)6.28(d,c)}J 9(e[c]){9(b)2E e[c][b.2u];J L(b 1i e[c])9(!a[1]||e[c][b].O==a[1])2E e[c][b];L(2L 1i e[c])1T;9(!2L){9(d.4P)d.4P(c,E.M(d,"2t"),P);J d.7M("43"+c,E.M(d,"2t"));2L=S;2E e[c]}}L(2L 1i e)1T;9(!2L){E.30(d,"2P");E.30(d,"2t")}}},1F:G(d,b,e,c,f){b=E.2h(b||[]);9(!e){9(6.1Z[d])E("*").1f([18,U]).1F(d,b)}J{H a,2L,1b=E.1n(e[d]||S),4N=!b[0]||!b[0].2M;9(4N)b.4w(6.4M({O:d,2m:e}));b[0].O=d;9(E.1n(E.M(e,"2t")))a=E.M(e,"2t").16(e,b);9(!1b&&e["43"+d]&&e["43"+d].16(e,b)===P)a=P;9(4N)b.44();9(f&&f.16(e,b)===P)a=P;9(1b&&c!==P&&a!==P&&!(E.11(e,\'a\')&&d=="4L")){6.4T=Q;e[d]()}6.4T=P}I a},2t:G(d){H a;d=E.1j.4M(d||18.1j||{});H b=d.O.2l(".");d.O=b[0];H c=E.M(6,"2P")&&E.M(6,"2P")[d.O],3q=1B.3A.2J.2O(1q,1);3q.4w(d);L(H j 1i c){3q[0].4Q=c[j];3q[0].M=c[j].M;9(!b[1]||c[j].O==b[1]){H e=c[j].16(6,3q);9(a!==P)a=e;9(e===P){d.2M();d.3p()}}}9(E.V.1h)d.2m=d.2M=d.3p=d.4Q=d.M=S;I a},4M:G(c){H a=c;c=E.1k({},a);c.2M=G(){9(a.2M)a.2M();a.7L=P};c.3p=G(){9(a.3p)a.3p();a.7K=Q};9(!c.2m&&c.65)c.2m=c.65;9(E.V.1N&&c.2m.1y==3)c.2m=a.2m.12;9(!c.4K&&c.4J)c.4K=c.4J==c.2m?c.7H:c.4J;9(c.64==S&&c.63!=S){H e=U.2V,b=U.1G;c.64=c.63+(e&&e.2R||b.2R||0);c.7E=c.7D+(e&&e.2B||b.2B||0)}9(!c.3Y&&(c.61||c.60))c.3Y=c.61||c.60;9(!c.5F&&c.5D)c.5F=c.5D;9(!c.3Y&&c.2r)c.3Y=(c.2r&1?1:(c.2r&2?3:(c.2r&4?2:0)));I c}};E.1b.1k({3W:G(c,a,b){I c=="5Y"?6.2G(c,a,b):6.N(G(){E.1j.1f(6,c,b||a,b&&a)})},2G:G(d,b,c){I 6.N(G(){E.1j.1f(6,d,G(a){E(6).5X(a);I(c||b).16(6,1q)},c&&b)})},5X:G(a,b){I 6.N(G(){E.1j.28(6,a,b)})},1F:G(c,a,b){I 6.N(G(){E.1j.1F(c,a,6,Q,b)})},7x:G(c,a,b){9(6[0])I E.1j.1F(c,a,6[0],P,b)},25:G(){H a=1q;I 6.4L(G(e){6.4H=0==6.4H?1:0;e.2M();I a[6.4H].16(6,[e])||P})},7v:G(f,g){G 4G(e){H p=e.4K;1W(p&&p!=6)2a{p=p.12}29(e){p=6};9(p==6)I P;I(e.O=="4x"?f:g).16(6,[e])}I 6.4x(4G).5U(4G)},2d:G(f){5T();9(E.3T)f.16(U,[E]);J E.3l.1a(G(){I f.16(6,[E])});I 6}});E.1k({3T:P,3l:[],2d:G(){9(!E.3T){E.3T=Q;9(E.3l){E.N(E.3l,G(){6.16(U)});E.3l=S}9(E.V.35||E.V.34)U.4P("5S",E.2d,P);9(!18.7t.K)E(18).39(G(){E("#4E").28()})}}});E.N(("7s,7r,39,7q,6n,5Y,4L,7p,"+"7n,7m,7l,4x,5U,7k,24,"+"51,7j,7i,7h,3U").2l(","),G(i,o){E.1b[o]=G(f){I f?6.3W(o,f):6.1F(o)}});H x=P;G 5T(){9(x)I;x=Q;9(E.V.35||E.V.34)U.4S("5S",E.2d,P);J 9(E.V.1h){U.7f("<7d"+"7y 22=4E 7z=Q "+"3k=//:><\\/1J>");H a=U.3S("4E");9(a)a.62=G(){9(6.2C!="1l")I;E.2d()};a=S}J 9(E.V.1N)E.4B=4j(G(){9(U.2C=="5Q"||U.2C=="1l"){4A(E.4B);E.4B=S;E.2d()}},10);E.1j.1f(18,"39",E.2d)}E.1b.1k({39:G(g,d,c){9(E.1n(g))I 6.3W("39",g);H e=g.1g(" ");9(e>=0){H i=g.2J(e,g.K);g=g.2J(0,e)}c=c||G(){};H f="4z";9(d)9(E.1n(d)){c=d;d=S}J{d=E.3a(d);f="5P"}H h=6;E.3G({1d:g,O:f,M:d,1l:G(a,b){9(b=="1C"||b=="5O")h.4o(i?E("<1s/>").3g(a.40.1p(/<1J(.|\\s)*?\\/1J>/g,"")).1Y(i):a.40);56(G(){h.N(c,[a.40,b,a])},13)}});I 6},7a:G(){I E.3a(6.5M())},5M:G(){I 6.1X(G(){I E.11(6,"2Y")?E.2h(6.79):6}).1E(G(){I 6.2H&&!6.3c&&(6.2Q||/24|6b/i.14(6.11)||/2g|1P|52/i.14(6.O))}).1X(G(i,c){H b=E(6).3i();I b==S?S:b.1c==1B?E.1X(b,G(a,i){I{2H:c.2H,1Q:a}}):{2H:c.2H,1Q:b}}).21()}});E.N("5L,5K,6t,5J,5I,5H".2l(","),G(i,o){E.1b[o]=G(f){I 6.3W(o,f)}});H B=(1u 3D).3B();E.1k({21:G(d,b,a,c){9(E.1n(b)){a=b;b=S}I E.3G({O:"4z",1d:d,M:b,1C:a,1V:c})},78:G(b,a){I E.21(b,S,a,"1J")},77:G(c,b,a){I E.21(c,b,a,"45")},76:G(d,b,a,c){9(E.1n(b)){a=b;b={}}I E.3G({O:"5P",1d:d,M:b,1C:a,1V:c})},75:G(a){E.1k(E.59,a)},59:{1Z:Q,O:"4z",2z:0,5G:"74/x-73-2Y-72",6o:Q,3e:Q,M:S},49:{},3G:G(s){H f,2y=/=(\\?|%3F)/g,1v,M;s=E.1k(Q,s,E.1k(Q,{},E.59,s));9(s.M&&s.6o&&1m s.M!="1M")s.M=E.3a(s.M);9(s.1V=="4b"){9(s.O.2p()=="21"){9(!s.1d.1t(2y))s.1d+=(s.1d.1t(/\\?/)?"&":"?")+(s.4b||"5E")+"=?"}J 9(!s.M||!s.M.1t(2y))s.M=(s.M?s.M+"&":"")+(s.4b||"5E")+"=?";s.1V="45"}9(s.1V=="45"&&(s.M&&s.M.1t(2y)||s.1d.1t(2y))){f="4b"+B++;9(s.M)s.M=s.M.1p(2y,"="+f);s.1d=s.1d.1p(2y,"="+f);s.1V="1J";18[f]=G(a){M=a;1C();1l();18[f]=W;2a{2E 18[f]}29(e){}}}9(s.1V=="1J"&&s.1L==S)s.1L=P;9(s.1L===P&&s.O.2p()=="21")s.1d+=(s.1d.1t(/\\?/)?"&":"?")+"57="+(1u 3D()).3B();9(s.M&&s.O.2p()=="21"){s.1d+=(s.1d.1t(/\\?/)?"&":"?")+s.M;s.M=S}9(s.1Z&&!E.5b++)E.1j.1F("5L");9(!s.1d.1g("8g")&&s.1V=="1J"){H h=U.4l("9U")[0];H g=U.5B("1J");g.3k=s.1d;9(!f&&(s.1C||s.1l)){H j=P;g.9R=g.62=G(){9(!j&&(!6.2C||6.2C=="5Q"||6.2C=="1l")){j=Q;1C();1l();h.3b(g)}}}h.58(g);I}H k=P;H i=18.6X?1u 6X("9P.9O"):1u 6W();i.9M(s.O,s.1d,s.3e);9(s.M)i.5C("9J-9I",s.5G);9(s.5y)i.5C("9H-5x-9F",E.49[s.1d]||"9D, 9C 9B 9A 5v:5v:5v 9z");i.5C("X-9x-9v","6W");9(s.6U)s.6U(i);9(s.1Z)E.1j.1F("5H",[i,s]);H c=G(a){9(!k&&i&&(i.2C==4||a=="2z")){k=Q;9(d){4A(d);d=S}1v=a=="2z"&&"2z"||!E.6S(i)&&"3U"||s.5y&&E.6R(i,s.1d)&&"5O"||"1C";9(1v=="1C"){2a{M=E.6Q(i,s.1V)}29(e){1v="5k"}}9(1v=="1C"){H b;2a{b=i.5s("6P-5x")}29(e){}9(s.5y&&b)E.49[s.1d]=b;9(!f)1C()}J E.5r(s,i,1v);1l();9(s.3e)i=S}};9(s.3e){H d=4j(c,13);9(s.2z>0)56(G(){9(i){i.9q();9(!k)c("2z")}},s.2z)}2a{i.9o(s.M)}29(e){E.5r(s,i,S,e)}9(!s.3e)c();I i;G 1C(){9(s.1C)s.1C(M,1v);9(s.1Z)E.1j.1F("5I",[i,s])}G 1l(){9(s.1l)s.1l(i,1v);9(s.1Z)E.1j.1F("6t",[i,s]);9(s.1Z&&!--E.5b)E.1j.1F("5K")}},5r:G(s,a,b,e){9(s.3U)s.3U(a,b,e);9(s.1Z)E.1j.1F("5J",[a,s,e])},5b:0,6S:G(r){2a{I!r.1v&&9n.9l=="54:"||(r.1v>=6N&&r.1v<9j)||r.1v==6M||E.V.1N&&r.1v==W}29(e){}I P},6R:G(a,c){2a{H b=a.5s("6P-5x");I a.1v==6M||b==E.49[c]||E.V.1N&&a.1v==W}29(e){}I P},6Q:G(r,b){H c=r.5s("9i-O");H d=b=="6K"||!b&&c&&c.1g("6K")>=0;H a=d?r.9g:r.40;9(d&&a.2V.37=="5k")6G"5k";9(b=="1J")E.5f(a);9(b=="45")a=3w("("+a+")");I a},3a:G(a){H s=[];9(a.1c==1B||a.4c)E.N(a,G(){s.1a(3f(6.2H)+"="+3f(6.1Q))});J L(H j 1i a)9(a[j]&&a[j].1c==1B)E.N(a[j],G(){s.1a(3f(j)+"="+3f(6))});J s.1a(3f(j)+"="+3f(a[j]));I s.66("&").1p(/%20/g,"+")}});E.1b.1k({1A:G(b,a){I b?6.1U({1H:"1A",2N:"1A",1r:"1A"},b,a):6.1E(":1P").N(G(){6.R.19=6.3h?6.3h:"";9(E.17(6,"19")=="2s")6.R.19="2Z"}).2D()},1z:G(b,a){I b?6.1U({1H:"1z",2N:"1z",1r:"1z"},b,a):6.1E(":3R").N(G(){6.3h=6.3h||E.17(6,"19");9(6.3h=="2s")6.3h="2Z";6.R.19="2s"}).2D()},6J:E.1b.25,25:G(a,b){I E.1n(a)&&E.1n(b)?6.6J(a,b):a?6.1U({1H:"25",2N:"25",1r:"25"},a,b):6.N(G(){E(6)[E(6).3t(":1P")?"1A":"1z"]()})},9c:G(b,a){I 6.1U({1H:"1A"},b,a)},9b:G(b,a){I 6.1U({1H:"1z"},b,a)},99:G(b,a){I 6.1U({1H:"25"},b,a)},98:G(b,a){I 6.1U({1r:"1A"},b,a)},96:G(b,a){I 6.1U({1r:"1z"},b,a)},95:G(c,a,b){I 6.1U({1r:a},c,b)},1U:G(k,i,h,g){H j=E.6D(i,h,g);I 6[j.3L===P?"N":"3L"](G(){j=E.1k({},j);H f=E(6).3t(":1P"),3y=6;L(H p 1i k){9(k[p]=="1z"&&f||k[p]=="1A"&&!f)I E.1n(j.1l)&&j.1l.16(6);9(p=="1H"||p=="2N"){j.19=E.17(6,"19");j.2U=6.R.2U}}9(j.2U!=S)6.R.2U="1P";j.3M=E.1k({},k);E.N(k,G(c,a){H e=1u E.2j(3y,j,c);9(/25|1A|1z/.14(a))e[a=="25"?f?"1A":"1z":a](k);J{H b=a.3s().1t(/^([+-]=)?([\\d+-.]+)(.*)$/),1O=e.2b(Q)||0;9(b){H d=3I(b[2]),2i=b[3]||"2T";9(2i!="2T"){3y.R[c]=(d||1)+2i;1O=((d||1)/e.2b(Q))*1O;3y.R[c]=1O+2i}9(b[1])d=((b[1]=="-="?-1:1)*d)+1O;e.3N(1O,d,2i)}J e.3N(1O,a,"")}});I Q})},3L:G(a,b){9(E.1n(a)){b=a;a="2j"}9(!a||(1m a=="1M"&&!b))I A(6[0],a);I 6.N(G(){9(b.1c==1B)A(6,a,b);J{A(6,a).1a(b);9(A(6,a).K==1)b.16(6)}})},9f:G(){H a=E.32;I 6.N(G(){L(H i=0;i-8O?r:3I(E.17(6.T,6.1e))||0},3N:G(c,b,e){6.5u=(1u 3D()).3B();6.1O=c;6.2D=b;6.2i=e||6.2i||"2T";6.2v=6.1O;6.4q=6.4i=0;6.4r();H f=6;G t(){I f.2F()}t.T=6.T;E.32.1a(t);9(E.32.K==1){H d=4j(G(){H a=E.32;L(H i=0;i6.Y.2e+6.5u){6.2v=6.2D;6.4q=6.4i=1;6.4r();6.Y.3M[6.1e]=Q;H a=Q;L(H i 1i 6.Y.3M)9(6.Y.3M[i]!==Q)a=P;9(a){9(6.Y.19!=S){6.T.R.2U=6.Y.2U;6.T.R.19=6.Y.19;9(E.17(6.T,"19")=="2s")6.T.R.19="2Z"}9(6.Y.1z)6.T.R.19="2s";9(6.Y.1z||6.Y.1A)L(H p 1i 6.Y.3M)E.1x(6.T.R,p,6.Y.3P[p])}9(a&&E.1n(6.Y.1l))6.Y.1l.16(6.T);I P}J{H n=t-6.5u;6.4i=n/6.Y.2e;6.4q=E.3J[6.Y.3J||(E.3J.5q?"5q":"6B")](6.4i,n,0,1,6.Y.2e);6.2v=6.1O+((6.2D-6.1O)*6.4q);6.4r()}I Q}};E.2j.2F={2R:G(a){a.T.2R=a.2v},2B:G(a){a.T.2B=a.2v},1r:G(a){E.1x(a.T.R,"1r",a.2v)},6z:G(a){a.T.R[a.1e]=a.2v+a.2i}};E.1b.6m=G(){H c=0,3E=0,T=6[0],5t;9(T)8L(E.V){H b=E.17(T,"2X")=="4F",1D=T.12,23=T.23,2K=T.3H,4f=1N&&3x(4s)<8J;9(T.6V){5w=T.6V();1f(5w.1S+38.33(2K.2V.2R,2K.1G.2R),5w.3E+38.33(2K.2V.2B,2K.1G.2B));9(1h){H d=E("4o").17("8H");d=(d=="8G"||E.5g&&3x(4s)>=7)&&2||d;1f(-d,-d)}}J{1f(T.5l,T.5z);1W(23){1f(23.5l,23.5z);9(35&&/^t[d|h]$/i.14(1D.37)||!4f)d(23);9(4f&&!b&&E.17(23,"2X")=="4F")b=Q;23=23.23}1W(1D.37&&!/^1G|4o$/i.14(1D.37)){9(!/^8D|1I-9S.*$/i.14(E.17(1D,"19")))1f(-1D.2R,-1D.2B);9(35&&E.17(1D,"2U")!="3R")d(1D);1D=1D.12}9(4f&&b)1f(-2K.1G.5l,-2K.1G.5z)}5t={3E:3E,1S:c}}I 5t;G d(a){1f(E.17(a,"9T"),E.17(a,"8A"))}G 1f(l,t){c+=3x(l)||0;3E+=3x(t)||0}}})();',62,616,'||||||this|||if|||||||||||||||||||||||||||||||||function|var|return|else|length|for|data|each|type|false|true|style|null|elem|document|browser|undefined||options|||nodeName|parentNode||test|jQuery|apply|css|window|display|push|fn|constructor|url|prop|add|indexOf|msie|in|event|extend|complete|typeof|isFunction|className|replace|arguments|opacity|div|match|new|status|firstChild|attr|nodeType|hide|show|Array|success|parent|filter|trigger|body|height|table|script|tbody|cache|string|safari|start|hidden|value|merge|left|break|animate|dataType|while|map|find|global||get|id|offsetParent|select|toggle|selected|toUpperCase|remove|catch|try|cur|al|ready|duration|done|text|makeArray|unit|fx|swap|split|target||pushStack|toLowerCase|nextSibling|button|none|handle|guid|now|stack|tb|jsre|timeout|inArray|scrollTop|readyState|end|delete|step|one|name|nth|slice|doc|ret|preventDefault|width|call|events|checked|scrollLeft|exec|px|overflow|documentElement|grep|position|form|block|removeData|rl|timers|max|opera|mozilla|trim|tagName|Math|load|param|removeChild|disabled|insertBefore|async|encodeURIComponent|append|oldblock|val|childNodes|src|readyList|multiFilter|color|defaultView|stopPropagation|args|old|toString|is|last|first|eval|parseInt|self|domManip|prototype|getTime|curCSS|Date|top||ajax|ownerDocument|parseFloat|easing|has|queue|curAnim|custom|innerHTML|orig|currentStyle|visible|getElementById|isReady|error|static|bind|String|which|getComputedStyle|responseText|oWidth|oHeight|on|shift|json|child|RegExp|ol|lastModified|isXMLDoc|jsonp|jquery|previousSibling|dir|safari2|el|styleFloat|state|setInterval|radio|getElementsByTagName|tr|empty|html|getAttribute|pos|update|version|input|float|runtimeStyle|unshift|mouseover|getPropertyValue|GET|clearInterval|safariTimer|visibility|clean|__ie_init|absolute|handleHover|lastToggle|index|fromElement|relatedTarget|click|fix|evt|andSelf|removeEventListener|handler|cloneNode|addEventListener|triggered|nodeIndex|unique|Number|classFilter|prevObject|selectedIndex|after|submit|password|removeAttribute|file|expr|setTimeout|_|appendChild|ajaxSettings|client|active|win|sibling|deep|globalEval|boxModel|cssFloat|object|checkbox|parsererror|offsetLeft|wrapAll|dequeue|props|lastChild|swing|handleError|getResponseHeader|results|startTime|00|box|Modified|ifModified|offsetTop|evalScript|createElement|setRequestHeader|ctrlKey|callback|metaKey|contentType|ajaxSend|ajaxSuccess|ajaxError|ajaxStop|ajaxStart|serializeArray|init|notmodified|POST|loaded|appendTo|DOMContentLoaded|bindReady|mouseout|not|removeAttr|unbind|unload|Width|keyCode|charCode|onreadystatechange|clientX|pageX|srcElement|join|outerHTML|substr|zoom|parse|textarea|reset|image|odd|even|before|quickClass|quickID|prepend|quickChild|execScript|offset|scroll|processData|uuid|contents|continue|textContent|ajaxComplete|clone|setArray|webkit|nodeValue|fl|_default|100|linear|href|speed|eq|createTextNode|throw|replaceWith|splice|_toggle|xml|colgroup|304|200|alpha|Last|httpData|httpNotModified|httpSuccess|fieldset|beforeSend|getBoundingClientRect|XMLHttpRequest|ActiveXObject|col|br|abbr|pixelLeft|urlencoded|www|application|ajaxSetup|post|getJSON|getScript|elements|serialize|clientWidth|hasClass|scr|clientHeight|write|relative|keyup|keypress|keydown|change|mousemove|mouseup|mousedown|right|dblclick|resize|focus|blur|frames|instanceof|hover|offsetWidth|triggerHandler|ipt|defer|offsetHeight|border|padding|clientY|pageY|Left|Right|toElement|Bottom|Top|cancelBubble|returnValue|detachEvent|attachEvent|substring|line|weight|animated|header|font|enabled|innerText|contains|only|size|gt|lt|uFFFF|u0128|417|inner|Height|toggleClass|removeClass|addClass|replaceAll|noConflict|insertAfter|prependTo|wrap|contentWindow|contentDocument|http|iframe|children|siblings|prevAll|nextAll|wrapInner|prev|Boolean|next|parents|maxLength|maxlength|readOnly|readonly|class|htmlFor|CSS1Compat|compatMode|compatible|borderTopWidth|ie|ra|inline|it|rv|medium|borderWidth|userAgent|522|navigator|with|concat|1px|10000|array|ig|PI|NaN|400|reverse|fast|600|slow|Function|Object|setAttribute|changed|be|can|property|fadeTo|fadeOut|getAttributeNode|fadeIn|slideToggle|method|slideUp|slideDown|action|cssText|stop|responseXML|option|content|300|th|protocol|td|location|send|cap|abort|colg|cos|tfoot|thead|With|leg|Requested|opt|GMT|1970|Jan|01|Thu|area|Since|hr|If|Type|Content|meta|specified|open|link|XMLHTTP|Microsoft|img|onload|row|borderLeftWidth|head|attributes'.split('|'),0,{}); + +/* + Copyright (c) 2004-2007, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +/* + This is a compiled version of Dojo, built for deployment and not for + development. To get an editable version, please visit: + + http://dojotoolkit.org + + for documentation and information on getting the source. +*/ + +var decompressedDojo = function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('if(V z=="1k"){(B(){if(V D["1o"]=="1k"){D.1o={}}if((!D["1z"])||(!1z["ca"])){D.1z={}}A cn=["rA","rz","1K","ry","rx","9f","rw","rv","ru","rt","rs","rr","rq","ro","rn","rm"];A i=0,24;1s(24=cn[i++]){if(!1z[24]){1z[24]=B(){}}}if(V D["z"]=="1k"){D.z={}}z.1W=D;A d3={im:U,rl:U,rk:"",rj:"",ri:"",rh:K,rg:U};R(A 8z in d3){if(V 1o[8z]=="1k"){1o[8z]=d3[8z]}}A jK=["rf","rd","rc","rb"];A t;1s(t=jK.3a()){z["is"+t]=U}})();z.8h=1o.8h;z.cY={jJ:0,jI:9,jH:0,jG:"",jF:2V("$ra: r9 $".1f(/[0-9]+/)[0]),2i:B(){4G(z.cY){C jJ+"."+jI+"."+jH+jG+" ("+jF+")"}}};z.d1=B(jE,jD,1V){A 2h=1V||z.1W;R(A i=0,p;2h&&(p=jE[i]);i++){2h=(p in 2h?2h[p]:(jD?2h[p]={}:1k))}C 2h};z.88=B(jC,jA,jB){A d2=jC.1A("."),p=d2.8q(),M=z.d1(d2,K,jB);C(M&&p?(M[p]=jA):1k)};z.6q=B(jz,jy,jx){C z.d1(jz.1A("."),jy,jx)};z.r8=B(jw,M){C!!z.6q(jw,U,M)};z["3u"]=B(d0){C z.1W.3u?z.1W.3u(d0):3u(d0)};z.ia=B(jv,cZ,cX){A 8y="r7: "+jv;if(cZ){8y+=" "+cZ}if(cX){8y+=" -- r6 be r5 in cY: "+cX}1z.1K(8y)};z.r4=B(ju,cW){A cV="r3: "+ju+" -- r2 r1 4F r0 qZ qY.";if(cW){cV+=" "+cW}1z.1K(cV)};(B(){A cR={53:{},6p:0,1h:{},8k:{z:{1p:"z",1Z:"."},cU:{1p:"cU",1Z:"../qX/cU"},cT:{1p:"cT",1Z:"cT"}},cN:B(cS){A mp=D.8k;C jp(mp[cS]&&mp[cS].1Z)},jk:B(8x){A mp=D.8k;if(D.cN(8x)){C mp[8x].1Z}C 8x},8v:[],6t:U,56:[],8t:[],8u:U};R(A cQ in cR){z[cQ]=cR[cQ]}})();z.jg=B(8w,cP,cb){A 1g=(((8w.2s(0)=="/"||8w.1f(/^\\w+:/)))?"":D.51)+8w;if(1o.jt&&z.c8){1g+="?"+67(1o.jt).2f(/\\W+/g,"")}1u{C!cP?D.cO(1g,cb):D.jq(1g,cP,cb)}1y(e){1z.1K(e);C U}};z.cO=B(1g,cb){if(D.8v[1g]){C K}A 6u=D.iR(1g,K);if(!6u){C U}D.8v[1g]=K;D.8v.Y(1g);if(cb){6u="("+6u+")"}A jr=z["3u"](6u+"\\r\\n//@ qW="+1g);if(cb){cb(jr)}C K};z.jq=B(1g,jo,cb){A ok=U;1u{ok=D.cO(1g,cb)}1y(e){1z.1K("qV je ",1g," 4G 9f: ",e)}C jp(ok&&D.53[jo])};z.6m=B(){D.8u=K;D.6t=K;A 57=D.56;D.56=[];R(A x=0;x<57.G;x++){57[x]()}D.8u=U;if(z.6t&&z.6p==0&&D.56.G>0){z.8s()}};z.ck=B(){A 57=D.8t;1s(57.G){(57.8q())()}};z.qU=B(M,jn){A d=z;if(P.G==1){d.56.Y(M)}I{if(P.G>1){d.56.Y(B(){M[jn]()})}}if(d.6t&&d.6p==0&&!d.8u){d.8s()}};z.dW=B(M,jm){A d=z;if(P.G==1){d.8t.Y(M)}I{if(P.G>1){d.8t.Y(B(){M[jm]()})}}};z.iM=B(){if(D.6t){C}if(D.6p>0){1z.1K("qT qS in qR!");C}z.8s()};z.8s=B(){if(V 5c=="8b"||(1o["qQ"]&&z.2M)){5c("z.6m();",0)}I{z.6m()}};z.cF=B(jl){A 4v=jl.1A(".");R(A i=4v.G;i>0;i--){A 8r=4v.2w(0,i).22(".");if((i==1)&&!D.cN(8r)){4v[0]="../"+4v[0]}I{A cM=D.jk(8r);if(cM!=8r){4v.3S(0,i,cM);3f}}}C 4v};z.jj=U;z.8m=B(2T,qP,55){55=D.jj||55;A 54=D.53[2T];if(54){C 54}A cL=2T.1A(".");A 3L=D.cF(2T);A jh=((3L[0].2s(0)!="/")&&!3L[0].1f(/^\\w+:/));A ji=3L[3L.G-1];A 3m;if(ji=="*"){2T=cL.2w(0,-1).22(".");3L.8q();3m=3L.22("/")+"/"+(1o["qO"]||"qN")+".js";if(jh&&3m.2s(0)=="/"){3m=3m.2w(1)}}I{3m=3L.22("/")+".js";2T=cL.22(".")}A jf=(!55)?2T:L;A ok=D.jg(3m,jf);if((!ok)&&(!55)){2m S 1O("qM 3O 4E \'"+2T+"\'; 72 qL \'"+3m+"\'")}if((!55)&&(!D["qK"])){54=D.53[2T];if(!54){2m S 1O("qJ \'"+2T+"\' is 3O qI a8 je \'"+3m+"\'")}}C 54};z.8c=z.8m;z.1Q=B(cK){A cJ=cK+"";A 8p=cJ;A 6s=cK.1A(/\\./);if(6s[6s.G-1]=="*"){6s.8q();8p=6s.22(".")}A 8o=z.6q(8p,K);D.53[cJ]=8o;D.53[8p]=8o;C 8o};z.qH=B(8n){A jd=8n["qG"]||[];A cI=jd.3U(8n[z.j4]||8n["aY"]||[]);R(A x=0;x0&&!(j==1&&1X[0]=="")&&1X[j]==".."&&1X[j-1]!=".."){if(j==(1X.G-1)){1X.3S(j,1);1X[j-1]=""}I{1X.3S(j-1,2);j-=2}}}}1t.28=1X.22("/")}}}}1g="";if(1t.4t){1g+=1t.4t+":"}if(1t.3l){1g+="//"+1t.3l}1g+=1t.28;if(1t.1r){1g+="?"+1t.1r}if(1t.52){1g+="#"+1t.52}}D.1g=1g.2i();A r=D.1g.1f(j7);D.4t=r[2]||(r[1]?"":n);D.3l=r[4]||(r[3]?"":n);D.28=r[5];D.1r=r[7]||(r[6]?"":n);D.52=r[9]||(r[8]?"":n);if(D.3l!=n){r=D.3l.1f(j6);D.8X=r[3]||n;D.8W=r[4]||n;D.qw=r[5];D.qv=r[7]||n}};z.4r.1C.2i=B(){C D.1g}})();z.qu=B(j5,2E){A 2B=z.cF(j5).22("/");if(!2B){C L}if(2B.31("/")!=2B.G-1){2B+="/"}A cE=2B.T(":");if(2B.2s(0)!="/"&&(cE==-1||cE>2B.T("/"))){2B=z.51+2B}C S z.4r(2B,2E)};if(V 26!="1k"){z.c8=K;z.j4="qt";(B(){A d=z;if(1q&&1q.4I){A 8j=1q.4I("ak");A j3=/z(\\.qs)?\\.js([\\?\\.]|$)/i;R(A i=0;i<8j.G;i++){A 4X=8j[i].5t("4X");if(!4X){6c}A m=4X.1f(j3);if(m){if(!1o["51"]){1o["51"]=4X.21(0,m.hK)}A cD=8j[i].5t("1o");if(cD){A cC=3u("({ "+cD+" })");R(A x in cC){1o[x]=cC[x]}}3f}}}d.51=1o["51"];A n=cq;A 8i=n.iL;A 4Z=n.qr;A 6r=2k(4Z);d.2M=(8i.T("qq")>=0)?6r:0;d.6B=(4Z.T("qo")>=0)||(4Z.T("j2")>=0)?6r:0;d.3o=(4Z.T("j2")>=0)?6r:0;A j1=8i.T("qn");d.gu=d.7B=((j1>=0)&&(!d.6B))?6r:0;d.j0=0;d.1l=0;d.iV=0;1u{if(d.7B){d.j0=2k(8i.1A("qm/")[1].1A(" ")[0])}if((1q.gx)&&(!d.2M)){d.1l=2k(4Z.1A("qk ")[1].1A(";")[0])}}1y(e){}if(z.1l&&(26.8f.cu==="9q:")){1o.iT=K}d.iX=B(){A 2A;A qj;A cB=d.6q("cz.cy");if(cB){C cB}if(V iZ!="1k"){2A=S iZ()}I{if(d.1l){1u{2A=S 9j("qi.qh")}1y(e){}}I{if(cq.qg["8Z/x-iY"]){2A=1q.a9("8b");2A.cA("Z","8Z/x-iY");2A.cA("3n",0);2A.cA("58",0);2A.1c.gq="7C";1q.5K.4c(2A)}}}if(!2A){C L}z.88("cz.cy.qf",2A);C z.6q("cz.cy")};A iW=d.iX();if(iW){d.iV=K}A cm=1q["aX"];d.qe=(cm=="aW")||(cm=="gr")||(d.1l<6);d.8h=1o.8h||(d.1l?n.qd:n.qc).1M();d.qb=1z.1K;d.cx=["iU.8g","em.8g","iU.8g.4.0"];d.9b=B(){A 4s=L;A cv=L;if(!z.1l||!1o.iT){1u{4s=S qa()}1y(e){}}if(!4s){R(A i=0;i<3;++i){A cw=z.cx[i];1u{4s=S 9j(cw)}1y(e){cv=e}if(4s){z.cx=[cw];3f}}}if(!4s){2m S 1O("8g 3O q9: "+cv)}C 4s};d.8Y=B(iS){A 4Y=iS.3N||0;C((4Y>=q8)&&(4Y0);d.iR=B(1g,iP){A 3K=D.9b();if(!iQ&&z.4r){1g=(S z.4r(26.8f,1g)).2i()}3K.dL("dD",1g,U);1u{3K.dI(L);if(!d.8Y(3K)){A 1G=1O("q2 4F 4E "+1g+" 3N:"+3K.3N);1G.3N=3K.3N;1G.2G=3K.2G;2m 1G}}1y(e){if(iP){C L}2m e}C 3K.2G}})();z.iO=U;z.6o=B(e){z.iO=K;A cr=(e&&e.Z)?e.Z.1M():"4E";if(P.2O.iN||(cr!="q1"&&cr!="4E")){C}P.2O.iN=K;if(V z["8e"]!="1k"){dX(z.8e);63 z.8e}if(z.6p==0){z.iM()}};if(1q.66){if(z.2M||(z.7B&&(1o["q0"]===K))){1q.66("pZ",z.6o,L)}26.66("4E",z.6o,L)}if(/(pY|pX)/i.6Z(cq.iL)){z.8e=dN(B(){if(/6m|iJ/.6Z(1q.6F)){z.6o()}},10)}(B(){A 3g=26;A 8d=B(cp,fp){A iK=3g[cp]||B(){};3g[cp]=B(){fp.14(3g,P);iK.14(3g,P)}};if(z.1l){1q.fJ(""+"");A co=K;8d("iG",B(){3g.5c(B(){co=U},0)});8d("pU",B(){if(co){z.ck()}});1u{1q.pT.2P("v","pS:pR-pQ-pP:pO");1q.pN().pM("v\\\\:*","pL:2E(#aY#pK)")}1y(e){}}I{8d("iG",B(){z.ck()})}})();z.pJ=B(){};z.1e=26["1q"]||L;z.3E=B(){C z.1e.3E||z.1e.4I("3E")[0]};z.ch=B(iF,iE){z.1W=iF;z.1e=iE};z.cf=B(4q,6n,iD){if((6n)&&((V 4q=="3c")||(4q 1N 67))){4q=6n[4q]}C(6n?4q.14(6n,iD||[]):4q())};z.pI=B(cj,iC,iB,iA){A cg;A iz=z.1W;A iy=z.1e;1u{z.ch(cj,cj.1q);cg=z.cf(iC,iB,iA)}ir{z.ch(iz,iy)}C cg};z.pH=B(ix,iw,iv,iu){A ce;A ip=z.1e;1u{z.1e=ix;ce=z.cf(iw,iv,iu)}ir{z.1e=ip}C ce};if(1o["cd"]){R(A cc in 1o["cd"]){z.io(cc,1o["cd"][cc])}}}if(1o.im){if(!1z.ca){z.8c("z.pG.ca")}}}if(!z.1h["z.X.c9"]){z.1h["z.X.c9"]=K;z.1Q("z.X.c9");z.1R=B(it){C(V it=="3c"||it 1N 67)};z.2l=B(it){C(it&&it 1N 4e||V it=="6a"||((V z["1H"]!="1k")&&(it 1N z.1H)))};if(z.c8&&z.3o){z.1Y=B(it){if((V(it)=="B")&&(it=="[8b 1H]")){C U}C(V it=="B"||it 1N bI)}}I{z.1Y=B(it){C(V it=="B"||it 1N bI)}}z.ib=B(it){if(V it=="1k"){C U}C(it===L||V it=="8b"||z.2l(it)||z.1Y(it))};z.pF=B(it){A d=z;if((!it)||(V it=="1k")){C U}if(d.1R(it)){C U}if(d.1Y(it)){C U}if(d.2l(it)){C K}if((it.5w)&&(it.5w.1M()=="3R")){C U}if(pE(it.G)){C K}C U};z.pD=B(it){if(!it){C U}C!z.1Y(it)&&/\\{\\s*\\[il 5h\\]\\s*\\}/.6Z(67(it))};z.c7=B(M,4W){A 8a={};R(A x in 4W){if((V 8a[x]=="1k")||(8a[x]!=4W[x])){M[x]=4W[x]}}if(z.1l){A p=4W.2i;if((V(p)=="B")&&(p!=M.2i)&&(p!=8a.2i)&&(p!="\\pC 2i() {\\n [il 5h]\\n}\\n")){M.2i=4W.2i}}C M};z.1x=B(M,pB){R(A i=1,l=P.G;i2){C z.ig.14(z,P)}if(!3k){3k=2z;2z=L}if(z.1R(3k)){2z=2z||z.1W;if(!2z[3k]){2m(["z.2p: ie[\\"",3k,"\\"] is L (ie=\\"",2z,"\\")"].22(""))}C B(){C 2z[3k].14(2z,P||[])}}I{C(!2z?3k:B(){C 3k.14(2z,P||[])})}};z.6j=B(M,c3){B c4(){};c4.1C=M;A c2=S c4();if(c3){z.1x(c2,c3)}C c2};z.7X=B(pz){A Q=[L];C z.2p.14(z,Q.3U(z.4d(P)))};z.4d=B(M,ic){A Q=[];R(A x=ic||0;x3)){z.ia("z.2r: R 9P \'"+6l+"\' py pw B as \'1P\' pv pu of as a pt i3.","","1.0");A c=3j;3j=P[3]||{};3j.1P=c}A dd=P.2O,4V=L;if(z.2l(4p)){4V=4p;4p=4V.3a()}if(4V){R(A i=0,m;i<4V.G;i++){m=4V[i];if(!m){2m("ps #"+i+" 4F pr of "+6l+" is L. pq\'s pp a po pl is 3O 6m.")}4p=dd.6j(4p,m)}}A i9=(3j||0).1P,6k=dd.6j(4p),fn;R(A i in 3j){if(z.1Y(fn=3j[i])&&(!0[i])){fn.i4=i}}z.4M(6k,{4o:6l,bY:i9,bZ:L},3j||0);6k.1C.1P=6k;C z.88(6l,6k)};z.1x(z.2r,{6j:B(c0,i8){A bp=(c0||0).1C,mp=(i8||0).1C;A 2S=z.2r.i7();z.1x(2S,{84:bp,1x:mp});if(c0){2S.1C=z.6j(bp)}z.4M(2S,z.2r.i6,mp||0,{bY:L});2S.1C.1P=2S;2S.1C.4o=(bp||0).4o+"pk"+(mp||0).4o;z.88(2S.1C.4o,2S);C 2S},i7:B(){C B(){D.i5(P)}},i6:{i5:B(86){A c=86.2O,s=c.84,ct=s&&s.1P,m=c.1x,87=m&&m.1P,a=86,ii,fn;if(a[0]){if((fn=a[0]["bZ"])){a=fn.14(D,a)||a}}if(fn=c.1C.bZ){a=fn.14(D,a)||a}if(ct&&ct.14){ct.14(D,a)}if(87&&87.14){87.14(D,a)}if(ii=c.1C.bY){ii.14(D,86)}},bX:B(85){A c=D.1P,p,m;1s(c){p=c.84;m=c.1x;if(m==85||(m 1N 85.1P)){C p}if(m&&(m=m.bX(85))){C m}c=p&&p.1P}},6h:B(83,82,bW,6i){A p=bW,c,m,f;do{c=p.1P;m=c.1x;if(m&&(m=D.6h(83,82,m,6i))){C m}if((f=p[83])&&(6i==(f==82))){C p}p=c.84}1s(p);C!6i&&(p=D.bX(bW))&&D.6h(83,82,p,6i)},bU:B(2R,4U,bV){A a=P;if(!z.1R(a[0])){bV=4U;4U=2R;2R=4U.2O.i4}A c=4U.2O,p=D.1P.1C,a=bV||4U,fn,mp;if(D[2R]!=c||p[2R]==c){mp=D.6h(2R,c,p,K);if(!mp){2m(D.4o+": 1p i3 (\\""+2R+"\\") 4F bU pj 1f 2O (2r.js)")}p=D.6h(2R,c,mp,U)}fn=p&&p[2R];if(!fn){1z.1K(mp.4o+": no bU \\""+2R+"\\" ph pg (2r.js)");C}C fn.14(D,a)}}})}if(!z.1h["z.X.2c"]){z.1h["z.X.2c"]=K;z.1Q("z.X.2c");z.3i={i2:B(){C B(){A ap=4e.1C,c=P.2O,ls=c.2b,t=c.5V;A r=t&&t.14(D,P);R(A i in ls){if(!(i in ap)){ls[i].14(D,P)}}C r}},2P:B(6g,bT,i1){6g=6g||z.1W;A f=6g[bT];if(!f||!f.2b){A d=z.3i.i2();d.5V=f;d.2b=[];f=6g[bT]=d}C f.2b.Y(i1)},3J:B(i0,hZ,bS){A f=(i0||z.1W)[hZ];if(f&&f.2b&&bS--){63 f.2b[bS]}}};z.2c=B(M,pd,pc,pa,p9){A a=P,F=[],i=0;F.Y(z.1R(a[0])?L:a[i++],a[i++]);A a1=a[i+1];F.Y(z.1R(a1)||z.1Y(a1)?a[i++]:L,a[i++]);R(A l=a.G;i2){6e=z.7X(6e,P,2)}C D.5k(6e,6e)},ef:B(cb,4T){A 7Y=z.2p(cb,4T);if(P.G>2){7Y=z.7X(7Y,P,2)}C D.5k(7Y,L)},ed:B(cb,4T){A 7W=z.2p(cb,4T);if(P.G>2){7W=z.7X(7W,P,2)}C D.5k(L,7W)},5k:B(cb,eb){D.bM.Y([cb,eb]);if(D.2y>=0){D.7U()}C D},7U:B(){A bL=D.bM;A 4n=D.2y;A 1v=D.4R[4n];A 4S=D;A cb=L;1s((bL.G>0)&&(D.3M==0)){A f=bL.3a()[4n];if(!f){6c}1u{1v=f(1v);4n=((1v 1N 1O)?1:0);if(1v 1N z.30){cb=B(1v){4S.7V(1v);4S.3M--;if((4S.3M==0)&&(4S.2y>=0)){4S.7U()}};D.3M++}}1y(1G){1z.1K(1G);4n=1;1v=1G}}D.2y=4n;D.4R[4n]=1v;if((cb)&&(D.3M)){1v.9e(cb)}}})}if(!z.1h["z.X.2e"]){z.1h["z.X.2e"]=K;z.1Q("z.X.2e");z.5m=B(2e){1u{C 3u("("+2e+")")}1y(e){1z.1K(e);C 2e}};z.bK=B(2H){C("\\""+2H.2f(/(["\\\\])/g,"\\\\$1")+"\\"").2f(/[\\f]/g,"\\\\f").2f(/[\\b]/g,"\\\\b").2f(/[\\n]/g,"\\\\n").2f(/[\\t]/g,"\\\\t").2f(/[\\r]/g,"\\\\r")};z.hM="\\t";z.eq=B(it,4l,4P){4P=4P||"";A 4k=(4l?4P+z.hM:"");A 6b=(4l?"\\n":"");A 4Q=V(it);if(4Q=="1k"){C"1k"}I{if((4Q=="4J")||(4Q=="p1")){C it+""}I{if(it===L){C"L"}}}if(4Q=="3c"){C z.bK(it)}A 6d=P.2O;A 4m;if(V it.hL=="B"){4m=it.hL();if(it!==4m){C 6d(4m,4l,4k)}}if(V it.2e=="B"){4m=it.2e();if(it!==4m){C 6d(4m,4l,4k)}}if(z.2l(it)){A 1v=[];R(A i=0;i>=7R;t[x]=7R==4?17*c:c});t.a=1;C t};z.7P=B(a,M){A t=M||S z.1J();t.bz(2V(a[0]),2V(a[1]),2V(a[2]),2V(a[3]));if(2L(t.a)){t.a=1}C t.7Q()};z.hq=B(2H,M){A a=z.1J.hp[2H];C a&&z.7P(a,M)||z.ho(2H,M)||z.hn(2H,M)}}if(!z.1h["z.X"]){z.1h["z.X"]=K;z.1Q("z.X")}if(!z.1h["z.X.5Z"]){z.1h["z.X.5Z"]=K;z.1Q("z.X.5Z");(B(){A 1j=z.b2={2P:B(E,68,fp){if(!E){C}68=1j.4O(68);fp=1j.7G(68,fp);E.66(68,fp,U);C fp},3J:B(E,hm,hl){(E)&&(E.oF(1j.4O(hm),hl,U))},4O:B(1p){C(1p.2w(0,2)=="on"?1p.2w(2):1p)},7G:B(1p,fp){C(1p!="4b"?fp:B(e){C fp.2d(D,1j.4i(e,D))})},4i:B(H,oE){4w(H.Z){2X"4b":1j.7K(H);3f}C H},7K:B(H){H.oD=(H.3h?67.oC(H.3h):"")}};z.oB=B(H,hk){C 1j.4i(H,hk)};z.gY=B(H){H.7J();H.7I()};A 7O=z.3i;z.by=B(M,bx,hh,hg,hi){A hj=M&&(M.2t||M.oA||M.66);A bw=!hj?0:(!hi?1:2),l=[z.3i,1j,7O][bw];A h=l.2P(M,bx,z.2p(hh,hg));C[M,bx,h,bw]};z.bv=B(M,he,hd,hf){([z.3i,1j,7O][hf]).3J(M,he,hd)};z.5W={oz:8,gV:9,oy:12,ox:13,ow:16,ov:17,ou:18,gG:19,ot:20,os:27,or:32,b5:33,b4:34,gE:35,gF:36,b7:37,b9:38,b6:39,b8:40,gD:45,8S:46,oq:47,oo:91,om:92,ol:93,oj:96,oi:97,oh:98,og:99,oe:6D,od:oc,ob:oa,o9:o8,o7:o6,o5:o4,o3:bi,o2:o1,o0:nZ,nY:nX,nW:nV,nU:bk,gS:nT,gR:nS,gQ:nR,gP:nQ,gO:nP,gN:nO,gM:nN,gL:nM,gK:nL,gJ:nK,gI:nJ,gH:nI,nH:nG,nF:nE,nD:nC,gB:nB,gC:nA};if(z.1l){bf=B(e,5h){1u{C(e.3I=5h)}1y(e){C 0}};A 61=z.3i;if(!1o.nz){7O=61=z.gy={b3:[],2P:B(64,bu,hc){64=64||z.1W;A f=64[bu];if(!f||!f.2b){A d=z.gz();d.5V=f&&(7M.Y(f)-1);d.2b=[];f=64[bu]=d}C f.2b.Y(7M.Y(hc)-1)},3J:B(hb,ha,7N){A f=(hb||z.1W)[ha],l=f&&f.2b;if(f&&l&&7N--){63 7M[l[7N]];63 l[7N]}}};A 7M=61.b3}z.1x(1j,{2P:B(E,62,fp){if(!E){C}62=1j.4O(62);if(62=="h3"){A kd=E.bs;if(!kd||!kd.2b||!kd.h9){1j.2P(E,"bs",1j.h4);E.bs.h9=K}}C 61.2P(E,62,1j.7G(fp))},3J:B(E,h8,h7){61.3J(E,1j.4O(h8),h7)},4O:B(7L){C(7L.2w(0,2)!="on"?"on"+7L:7L)},ny:B(){},4i:B(H,4N){if(!H){A w=(4N)&&((4N.aD||4N.1q||4N).nx)||26;H=w.5Z}if(!H){C(H)}H.5V=H.br;H.bh=(4N||H.br);H.nw=H.nv;H.nu=H.nr;A bq=H.br,1e=(bq&&bq.aD)||1q;A bn=((z.1l<6)||(1e["aX"]=="aW"))?1e.3E:1e.5K;A bm=z.aB();H.nq=H.np+z.aH(bn.5I||0)-bm.x;H.nn=H.nm+(bn.5G||0)-bm.y;if(H.Z=="fk"){H.h6=H.nl}if(H.Z=="fj"){H.h6=H.nk}H.7I=1j.bc;H.7J=1j.ba;C 1j.h5(H)},h5:B(H){4w(H.Z){2X"4b":A c=("3h"in H?H.3h:H.3I);if(c==10){c=0;H.3I=13}I{if(c==13||c==27){c=0}I{if(c==3){c=99}}}H.3h=c;1j.7K(H);3f}C H},gZ:{bi:42,bk:47,h2:59,nj:43,ni:44,nh:45,ng:46,nf:47,60:96,h1:91,nb:92,na:93,h0:39},h4:B(H){A kp=H.bh.h3;if(!kp||!kp.2b){C}A k=H.3I;A bj=(k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>bk)&&(k60)&&(kh0);if(bj||H.5Y){A c=(bj?0:k);if(H.5Y){if(k==3||k==13){C}I{if(c>95&&c=65&&c<=90)){c+=32}I{c=1j.gZ[c]||c}}}}A 2x=1j.7H(H,{Z:"4b",2x:K,3h:c});kp.2d(H.bh,2x);H.bg=2x.bg;H.bd=2x.bd;bf(H,2x.3I)}},bc:B(){D.bg=K},ba:B(){D.n9=D.3I;if(D.5Y){bf(D,0)}D.bd=U}});z.gY=B(H){H=H||26.5Z;1j.bc.2d(H);1j.ba.2d(H)}}1j.7H=B(H,gX){A 2x=z.1x({},H,gX);1j.7K(2x);2x.7J=B(){H.7J()};2x.7I=B(){H.7I()};C 2x};if(z.2M){z.1x(1j,{4i:B(H,n8){4w(H.Z){2X"4b":A c=H.n7;if(c==3){c=99}c=((c<41)&&(!H.5X)?0:c);if((H.5Y)&&(!H.5X)&&(c>=65)&&(c<=90)){c+=32}C 1j.7H(H,{3h:c})}C H}})}if(z.3o){z.1x(1j,{4i:B(H,n6){4w(H.Z){2X"4b":A c=H.3h,s=H.5X,k=H.3I;k=k||gA[H.gW]||0;if(H.gW=="n5"){c=0}I{if((H.5Y)&&(c>0)&&(c<27)){c+=96}I{if(c==z.5W.gU){c=z.5W.gV;s=K}I{c=(c>=32&&c gh",E).1n(B(i){i.1c.7E=i.1c.7E.2f(/gk:[^;]*;/i,"")})}}I{A o="mh(mg="+(7D*6D)+")";E.1c.3T=o}if(E.gj.1M()=="gi"){z.1r("> gh",E).1n(B(i){i.1c.3T=o})}C 7D}:B(E,gg){C E.1c.2W=gg});A 5Q={3n:K,58:K,2g:K,5J:K};A gd=B(E,Z,5P){Z=Z.1M();if(5Q[Z]===K){C z.4g(E,5P)}I{if(5Q[Z]===U){C 5P}I{if((Z.T("mf")>=0)||(Z.T("md")>=0)||(Z.T("3n")>=0)||(Z.T("58")>=0)||(Z.T("5q")>=0)||(Z.T("mc")>=0)||(Z.T("ma")>=0)){5Q[Z]=K;C z.4g(E,5P)}I{5Q[Z]=U;C 5P}}}};z.1c=B(E,5O,aT){A n=z.1D(E),F=P.G,op=(5O=="2W");if(F==3){C op?z.gf(n,aT):n.1c[5O]=aT}if(F==2&&op){C z.ge(n)}A s=z.3F(n);C(F==1)?s:gd(n,5O,s[5O])};z.7A=B(n,gc){A s=gc||1E(n),px=z.4g,l=px(n,s.m9),t=px(n,s.m8);C{l:l,t:t,w:l+px(n,s.m7),h:t+px(n,s.m6)}};z.5N=B(n,gb){A ne="7C",px=z.4g,s=gb||1E(n),bl=(s.m5!=ne?px(n,s.m4):0),bt=(s.m3!=ne?px(n,s.m2):0);C{l:bl,t:bt,w:bl+(s.m1!=ne?px(n,s.m0):0),h:bt+(s.lZ!=ne?px(n,s.lY):0)}};z.aN=B(n,ga){A s=ga||1E(n),p=z.7A(n,s),b=z.5N(n,s);C{l:p.l+b.l,t:p.t+b.t,w:p.w+b.w,h:p.h+b.h}};z.aM=B(n,g9){A s=g9||1E(n),px=z.4g,l=px(n,s.lX),t=px(n,s.lW),r=px(n,s.lV),b=px(n,s.lU);if(z.3o&&(s.ax!="fU")){r=l}C{l:l,t:t,w:l+r,h:t+b}};z.au=B(E,g8){A s=g8||1E(E),me=z.aM(E,s);A l=E.fT-me.l,t=E.fS-me.t;if(z.7B){A aS=2k(s.2g),aR=2k(s.5J);if(!2L(aS)&&!2L(aR)){l=aS,t=aR}I{A p=E.1L;if(p&&p.1c){A aQ=1E(p);if(aQ.lT!="lS"){A be=z.5N(p,aQ);l+=be.l,t+=be.t}}}}I{if(z.2M){A p=E.1L;if(p){A be=z.5N(p);l-=be.l,t-=be.t}}}C{l:l,t:t,w:E.6v+me.w,h:E.8D+me.h}};z.aK=B(E,g7){A s=g7||1E(E),pe=z.7A(E,s),be=z.5N(E,s),w=E.aF,h;if(!w){w=E.6v,h=E.8D}I{h=E.lR,be.w=be.h=0}if(z.2M){pe.l+=be.l;pe.t+=be.t}C{l:pe.l,t:pe.t,w:w-pe.w-be.w,h:h-pe.h-be.h}};z.lQ=B(E,g6){A s=g6||1E(E),pe=z.7A(E,s),cb=z.aK(E,s);C{l:cb.l-pe.l,t:cb.t-pe.t,w:cb.w+pe.w,h:cb.h+pe.h}};z.aL=B(E,l,t,w,h,u){u=u||"px";4G(E.1c){if(!2L(l)){2g=l+u}if(!2L(t)){5J=t+u}if(w>=0){3n=w+u}if(h>=0){58=h+u}}};z.aO=B(E){A n=E.5w;C(z.aP=="g5-3G")||(n=="lP")||(n=="lO")};z.fX=B(E,7z,7y,g4){A bb=z.aO(E);if(bb){A pb=z.aN(E,g4);if(7z>=0){7z+=pb.w}if(7y>=0){7y+=pb.h}}z.aL(E,g3,g3,7z,7y)};z.fY=B(E,g1,g0,5M,5L,g2){A s=g2||z.3F(E);A bb=z.aO(E),pb=bb?fZ:z.aN(E,s),mb=z.aM(E,s);if(5M>=0){5M=2Y.5q(5M-pb.w-mb.w,0)}if(5L>=0){5L=2Y.5q(5L-pb.h-mb.h,0)}z.aL(E,g1,g0,5M,5L)};A fZ={l:0,t:0,w:0,h:0};z.lN=B(E,3G){A n=z.1D(E),s=1E(n),b=3G;C!b?z.au(n,s):z.fY(n,b.l,b.t,b.w,b.h,s)};z.lM=B(E,3G){A n=z.1D(E),s=1E(n),b=3G;C!b?z.aK(n,s):z.fX(n,b.w,b.h,s)};A 5H=B(E,1a){if(!(E=(E||0).1L)){C 0}A 1U,aJ=0,2h=z.3E();1s(E&&E.1c){if(1E(E).ax=="lL"){C 0}1U=E[1a];if(1U){aJ+=1U-0;if(E==2h){3f}}E=E.1L}C aJ};z.fQ=B(){A 2h=z.3E();A 3g=z.1W;A de=z.1e.5K;C{y:(3g.lK||de.5G||2h.5G||0),x:(3g.lJ||z.aH(de.5I)||2h.5I||0)}};z.aG=B(){C V z.aI=="1k"?(z.aI=z.3F(z.3E()).lI=="lH"):z.aI};z.aB=B(){A de=z.1e.5K;if(z.1l>=7){C{x:de.aC().2g,y:de.aC().5J}}I{C{x:z.aG()||26.am==26?de.fW:de.6v-de.aF-de.fW,y:de.lG}}};z.aH=B(aE){if(z.1l&&!z.aG()){A de=z.1e.5K;C aE+de.aF-de.lF}C aE};z.fP=B(E,aw){A ay=E.aD;A J={x:0,y:0};A 7w=U;A db=z.3E();if(z.1l){A aA=E.aC();A az=z.aB();J.x=aA.2g-az.x;J.y=aA.5J-az.y}I{if(ay["fV"]){A bo=ay.fV(E);J.x=bo.x-5H(E,"5I");J.y=bo.y-5H(E,"5G")}I{if(E["fR"]){7w=K;A 7x;if(z.3o&&(1E(E).ax=="fU")&&(E.1L==db)){7x=db}I{7x=db.1L}if(E.1L!=db){A nd=E;if(z.2M){nd=db}J.x-=5H(nd,"5I");J.y-=5H(nd,"5G")}A 4f=E;do{A n=4f["fT"];if(!z.2M||n>0){J.x+=2L(n)?0:n}A m=4f["fS"];J.y+=2L(m)?0:m;4f=4f.fR}1s((4f!=7x)&&4f)}I{if(E["x"]&&E["y"]){J.x+=2L(E.x)?0:E.x;J.y+=2L(E.y)?0:E.y}}}}if(7w||aw){A av=z.fQ();A m=7w?(!aw?-1:0):1;J.y+=m*av.y;J.x+=m*av.x}C J};z.af=B(E,fO){A n=z.1D(E),s=1E(n),mb=z.au(n,s);A at=z.fP(n,fO);mb.x=at.x;mb.y=at.y;C mb}})();z.fL=B(E,fN){C((" "+E.3A+" ").T(" "+fN+" ")>=0)};z.7s=B(E,ar){A 7v=E.3A;if((" "+7v+" ").T(" "+ar+" ")<0){E.3A=7v+(7v?" ":"")+ar}};z.7r=B(E,fM){A t=z.7g((" "+E.3A+" ").2f(" "+fM+" "," "));if(E.3A!=t){E.3A=t}};z.lE=B(E,aq,7u){if(V 7u=="1k"){7u=!z.fL(E,aq)}z[7u?"7s":"7r"](E,aq)}}if(!z.1h["z.X.1H"]){z.1h["z.X.1H"]=K;z.1Q("z.X.1H");(B(){A d=z;z.1H=B(){A F=P;if((F.G==1)&&(V F[0]=="4J")){D.G=eK(F[0])}I{if(F.G){d.1n(F,B(i){D.Y(i)},D)}}};z.1H.1C=S 4e;if(d.1l){A fK=B(al){C("A a2 = am."+al+"; "+"A ap = 4e.1C; "+"A ao = a2.1C; "+"R(A x in ao){ ap[x] = ao[x]; } "+"am."+al+" = 4e; ")};A fI=fK("z.1H");A aj=26.lD();aj.1q.fJ(""+fI+"");aj.lC(1,1,1,1)}z.4M(z.1H,{T:B(fH,fG){C d.T(D,fH,fG)},31:B(lB,lA){A aa=d.4d(P);aa.ae(D);C d.31.14(d,aa)},ah:B(fF,fE){C d.ah(D,fF,fE)},ag:B(fD,fC){C d.ag(D,fD,fC)},1n:B(fB,fA){d.1n(D,fB,fA);C D},23:B(7t,M){C d.23(D,7t,M,d.1H)},af:B(){C d.23(D,d.af)},1c:B(lz,ly){A aa=d.4d(P);aa.ae(D[0]);A s=d.1c.14(d,aa);C(P.G>1)?D:s},lx:B(lw,lv){A aa=d.4d(P);aa.ae(L);A s=D.23(B(i){aa[0]=i;C d.1c.14(d,aa)});C(P.G>1)?D:s},7s:B(fz){C D.1n(B(i){z.7s(i,fz)})},7r:B(fy){C D.1n(B(i){z.7r(i,fy)})},5E:B(fw,7q){A 1m=d.1r(fw)[0];7q=7q||"72";R(A x=0;x=0){if(i[x]<1d){1d=i[x]}}}C(1d<0)?ql:1d};A 6X=B(7l){A i=2I(7l);if(i[0]!=-1){C 7l.21(i[0]+1,a0(7l,1))}I{C""}};A 5r=B(7k){A 5D;A i=2I(7k);if((i[0]==0)||(i[1]==0)){5D=0}I{5D=a0(7k,0)}C((5D>0)?7k.3b(0,5D).1M():"*")};A fg=B(Q){A J=-1;R(A x=0;x=0){if((1S>J)||(J==-1)){J=1S}}}C J};A 9H=B(7i){A i=2I(7i);if(-1==i[1]){C""}A di=i[1]+1;A 7j=fg(i.2w(2));if(di<7j){C 7i.21(di,7j)}I{if(-1==7j){C 7i.3b(di)}I{C""}}};A f3=[{1i:"|=",1f:B(15,fe){C"[5z(3U(\' \',@"+15+",\' \'), \' "+fe+"-\')]"}},{1i:"~=",1f:B(15,fd){C"[5z(3U(\' \',@"+15+",\' \'), \' "+fd+" \')]"}},{1i:"^=",1f:B(15,fb){C"[li-4G(@"+15+", \'"+fb+"\')]"}},{1i:"*=",1f:B(15,fa){C"[5z(@"+15+", \'"+fa+"\')]"}},{1i:"$=",1f:B(15,9Z){C"[21(@"+15+", 3c-G(@"+15+")-"+(9Z.G-1)+")=\'"+9Z+"\']"}},{1i:"!=",1f:B(15,f9){C"[3O(@"+15+"=\'"+f9+"\')]"}},{1i:"=",1f:B(15,f8){C"[@"+15+"=\'"+f8+"\']"}}];A 9C=B(9Y,3Z,f7,f6){A 49;A i=2I(3Z);if(i[2]>=0){A 4L=3Z.T("]",i[2]);A 29=3Z.21(i[2]+1,4L);1s(29&&29.G){if(29.2s(0)=="@"){29=29.2w(1)}49=L;R(A x=0;x<9Y.G;x++){A 1S=9Y[x];A 7h=29.T(1S.1i);if(7h>=0){A 15=29.21(0,7h);A 4a=29.21(7h+1S.1i.G);if((4a.2s(0)=="\\"")||(4a.2s(0)=="\'")){4a=4a.21(1,4a.G-1)}49=1S.1f(d.7g(15),d.7g(4a));3f}}if((!49)&&(29.G)){49=f7(29)}if(49){f6(49)}29=L;A 7f=3Z.T("[",4L);if(0<=7f){4L=3Z.T("]",7f);if(0<=4L){29=3Z.21(7f+1,4L)}}}}};A f0=B(f5){A 4K=".";A 7e=f5.1A(" ");1s(7e.G){A 2K=7e.3a();A 7d;if(2K==">"){7d="/";2K=7e.3a()}I{7d="//"}A f4=5r(2K);4K+=7d+f4;A id=6X(2K);if(id.G){4K+="[@id=\'"+id+"\'][1]"}A cn=9H(2K);if(cn.G){A 9X=" ";if(cn.2s(cn.G-1)=="*"){9X="";cn=cn.3b(0,cn.G-1)}4K+="[5z(3U(\' \',@9P,\' \'), \' "+cn+9X+"\')]"}9C(f3,2K,B(f2){C"[@"+f2+"]"},B(f1){4K+=f1})}C 4K};A 7a={};A eC=B(28){if(7a[28]){C 7a[28]}A 1e=d.1e;A 9W=f0(28);A 4H=B(9V){A J=[];A 7b;1u{7b=1e.9x(9W,9V,L,lh.lg,L)}1y(e){1z.1K("lf in le:",9W,"lc:",9V);1z.1K(e)}A 7c=7b.eZ();1s(7c){J.Y(7c);7c=7b.eZ()}C J};C 7a[28]=4H};A 5x={};A 9B={};A 3y=B(79,78){if(!79){C 78}if(!78){C 79}C B(){C 79.14(26,P)&&78.14(26,P)}};A 75=B(9U,3Y,5B,2J){A 2v=2J+1;A 76=(3Y.G==2v);A 2K=3Y[2J];if(2K==">"){A 77=9U.3W;if(!77.G){C}2v++;76=(3Y.G==2v);A 4H=6O(3Y[2J+1]);R(A x=0,11;x<77.G,11=77[x];x++){if(4H(11)){if(76){5B.Y(11)}I{75(11,3Y,5B,2v)}}}}A 5C=6U(2K)(9U);if(76){1s(5C.G){5B.Y(5C.3a())}}I{1s(5C.G){75(5C.3a(),3Y,5B,2v)}}};A eE=B(9T,eY){A J=[];A x=9T.G-1,11;1s(11=9T[x--]){75(11,eY,J,0)}C J};A 6O=B(3D){if(5x[3D]){C 5x[3D]}A ff=L;A 9S=5r(3D);if(9S!="*"){ff=3y(ff,B(N){C((N.2t==1)&&(9S==N.5w.1M()))})}A 9R=6X(3D);if(9R.G){ff=3y(ff,B(N){C((N.2t==1)&&(N.id==9R))})}if(2Y.5q.14(D,2I(3D).2w(1))>=0){ff=3y(ff,9z(3D))}C 5x[3D]=ff};A 5y=B(E){A pn=E.1L;A 9Q=pn.3W;A 2v=-1;A 3C=pn.5A;if(!3C){C 2v}A ci=E["eW"];A cl=pn["eX"];if(((V cl=="4J")&&(cl!=9Q.G))||(V ci!="4J")){pn["eX"]=9Q.G;A 2J=1;do{if(3C===E){2v=2J}if(3C.2t==1){3C["eW"]=2J;2J++}3C=3C.71}1s(3C)}I{2v=ci}C 2v};A lb=0;A 3X=B(N,15){A 74="";if(15=="9P"){C N.3A||74}if(15=="R"){C N.la||74}C N.5t(15,2)||74};A eH=[{1i:"|=",1f:B(15,9O){A eV=" "+9O+"-";C B(N){A ea=" "+(N.5t(15,2)||"");C((ea==9O)||(ea.T(eV)==0))}}},{1i:"^=",1f:B(15,eU){C B(N){C(3X(N,15).T(eU)==0)}}},{1i:"*=",1f:B(15,eT){C B(N){C(3X(N,15).T(eT)>=0)}}},{1i:"~=",1f:B(15,eS){A 9N=" "+eS+" ";C B(N){A ea=" "+3X(N,15)+" ";C(ea.T(9N)>=0)}}},{1i:"$=",1f:B(15,73){A 9N=" "+73;C B(N){A ea=" "+3X(N,15);C(ea.31(73)==(ea.G-73.G))}}},{1i:"!=",1f:B(15,eR){C B(N){C(3X(N,15)!=eR)}}},{1i:"=",1f:B(15,eQ){C B(N){C(3X(N,15)==eQ)}}}];A 9E=[{1i:"9M-9K",1f:B(1p,l9){C B(N){if(N.2t!=1){C U}A fc=N.eP;1s(fc&&(fc.2t!=1)){fc=fc.eP}C(!fc)}}},{1i:"72-9K",1f:B(1p,l8){C B(N){if(N.2t!=1){C U}A nc=N.71;1s(nc&&(nc.2t!=1)){nc=nc.71}C(!nc)}}},{1i:"l7",1f:B(1p,l6){C B(N){A cn=N.3W;A eO=N.3W.G;R(A x=eO-1;x>=0;x--){A nt=cn[x].2t;if((nt==1)||(nt==3)){C U}}C K}}},{1i:"5z",1f:B(1p,eN){C B(N){C(N.9L.T(eN)>=0)}}},{1i:"3O",1f:B(1p,eM){A eL=6O(eM);C B(N){C(!eL(N))}}},{1i:"l5-9K",1f:B(1p,2u){A pi=eK;if(2u=="l4"){C B(N){C(((5y(N))%2)==1)}}I{if((2u=="2n")||(2u=="l3")){C B(N){C((5y(N)%2)==0)}}I{if(2u.T("l2+")==0){A 70=pi(2u.3b(3));C B(N){C(N.1L.3W[70-1]===N)}}I{if((2u.T("n+")>0)&&(2u.G>3)){A 9J=2u.1A("n+",2);A eJ=pi(9J[0]);A 2J=pi(9J[1]);C B(N){C((5y(N)%eJ)==2J)}}I{if(2u.T("n")==-1){A 70=pi(2u);C B(N){C(5y(N)==70)}}}}}}}}];A 9z=B(3e){A 9I=(9B[3e]||5x[3e]);if(9I){C 9I}A ff=L;A i=2I(3e);if(i[0]>=0){A 24=5r(3e);if(24!="*"){ff=3y(ff,B(N){C(N.5w.1M()==24)})}}A 5u;A 3B=9H(3e);if(3B.G){A 9F=3B.2s(3B.G-1)=="*";if(9F){3B=3B.3b(0,3B.G-1)}A re=S 9G("(?:^|\\\\s)"+3B+(9F?".*":"")+"(?:\\\\s|$)");ff=3y(ff,B(N){C re.6Z(N.3A)})}if(i[3]>=0){A 3z=3e.3b(i[3]+1);A 9D="";A 5v=3z.T("(");A 6Y=3z.31(")");if((0<=5v)&&(0<=6Y)&&(6Y>5v)){9D=3z.21(5v+1,6Y);3z=3z.3b(0,5v)}5u=L;R(A x=0;x<9E.G;x++){A 1S=9E[x];if(1S.1i==3z){5u=1S.1f(3z,9D);3f}}if(5u){ff=3y(ff,5u)}}A eG=(d.1l)?B(5s){A eI=5s.1M();C B(N){C N[5s]||N[eI]}}:B(5s){C B(N){C(N&&N.5t&&N.l1(5s))}};9C(eH,3e,eG,B(eF){ff=3y(ff,eF)});if(!ff){ff=B(){C K}}C 9B[3e]=ff};A 6W={};A 6U=B(3d,1B){A 9A=6W[3d];if(9A){C 9A}A i=2I(3d);A id=6X(3d);if(i[0]==0){C 6W[3d]=B(1B){C[d.1D(id)]}}A 9y=9z(3d);A 5p;if(i[0]>=0){5p=B(1B){A 11=d.1D(id);if(9y(11)){C[11]}}}I{A 3V;A 24=5r(3d);if(2Y.5q.14(D,2I(3d))==-1){5p=B(1B){A J=[];A 11,x=0,3V=1B.4I(24);1s(11=3V[x++]){J.Y(11)}C J}}I{5p=B(1B){A J=[];A 11,x=0,3V=1B.4I(24);1s(11=3V[x++]){if(9y(11)){J.Y(11)}}C J}}}C 6W[3d]=5p};A l0={};A 5o={">":B(1B){A J=[];A 11,x=0,3V=1B.3W;1s(11=3V[x++]){if(11.2t==1){J.Y(11)}}C J}};A 9w=B(6V){if(0>6V.T(" ")){C 6U(6V)}A eD=B(1B){A 6S=6V.1A(" ");A 6T;if(6S[0]==">"){6T=[1B]}I{6T=6U(6S.3a())(1B)}C eE(6T,6S)};C eD};A 9v=((1q["9x"]&&!d.3o)?B(3x){A 6R=3x.1A(" ");if((1q["9x"])&&(3x.T(":")==-1)&&((K))){if(((6R.G>2)&&(3x.T(">")==-1))||(6R.G>3)||(3x.T("[")>=0)||((1==6R.G)&&(0<=3x.T(".")))){C eC(3x)}}C 9w(3x)}:9w);A ey=B(3w){if(5o[3w]){C 5o[3w]}if(0>3w.T(",")){C 5o[3w]=9v(3w)}I{A eB=3w.1A(/\\s*,\\s*/);A 4H=B(1B){A eA=0;A J=[];A 6Q;1s(6Q=eB[eA++]){J=J.3U(9v(6Q,6Q.T(" "))(1B))}C J};C 5o[3w]=4H}};A 5n=0;A ez=B(Q){A J=S d.1H();if(!Q){C J}if(Q[0]){J.Y(Q[0])}if(Q.G<2){C J}5n++;Q[0]["9u"]=5n;R(A x=1,11;11=Q[x];x++){if(Q[x]["9u"]!=5n){J.Y(11)}11["9u"]=5n}C J};d.1r=B(6P,1B){if(V 6P!="3c"){C S d.1H(6P)}if(V 1B=="3c"){1B=d.1D(1B)}C ez(ey(6P)(1B||d.1e))};d.9t=B(ex,9s){A 9r=S d.1H();A ff=(9s)?6O(9s):B(){C K};R(A x=0,11;11=ex[x];x++){if(ff(11)){9r.Y(11)}}C 9r}})()}if(!z.1h["z.X.1b"]){z.1h["z.X.1b"]=K;z.1Q("z.X.1b");z.6K=B(ew){A J={};A iq="kZ[Z!=9q][Z!=kY][Z!=et][Z!=kX][Z!=kW], kV, kU";z.1r(iq,ew).3T(B(E){C(!E.kT)}).1n(B(1m){A 3v=1m.1p;A Z=(1m.Z||"").1M();if((Z=="kS")||(Z=="kR")){if(1m.kQ){J[3v]=1m.1Z}}I{if(1m.kP){A ev=J[3v]=[];z.1r("kO[kN]",1m).1n(B(eu){ev.Y(eu.1Z)})}I{J[3v]=1m.1Z;if(Z=="et"){J[3v+".x"]=J[3v+".y"]=J[3v].x=J[3v].y=0}}}});C J};z.9h=B(23){A ec=kM;A J="";A es={};R(A x in 23){if(23[x]!=es[x]){if(z.2l(23[x])){R(A y=0;y<23[x].G;y++){J+=ec(x)+"="+ec(23[x][y])+"&"}}I{J+=ec(x)+"="+ec(23[x])+"&"}}}if((J.G)&&(J.2s(J.G-1)=="&")){J=J.3b(0,J.G-1)}C J};z.kL=B(er){C z.9h(z.6K(er))};z.kK=B(ep){C z.eq(z.6K(ep))};z.kJ=B(2H){A J={};A qp=2H.1A("&");A dc=kI;z.1n(qp,B(1m){if(1m.G){A 9p=1m.1A("=");A 1p=dc(9p.3a());A 1U=dc(9p.22("="));if(z.1R(J[1p])){J[1p]=[J[1p]]}if(z.2l(J[1p])){J[1p].Y(1U)}I{J[1p]=1U}}});C J};z.e1=U;z.e6={"9g":B(1b){C 1b.2G},"2e":B(1b){if(!1o.eo){1z.1K("kH kG kF a kE of 9g/2e-6M-9m"+" 4F kD kC kB kA 4G en kz"+" (ky 1o.eo=K 4F kx kw D kv)")}C z.5m(1b.2G)},"2e-6M-ku":B(1b){A 6N=1b.2G;A 9o=6N.T("/*");A 9n=6N.31("*/");if((9o==-1)||(9n==-1)){C z.5m(1b.2G)}C z.5m(6N.21(9o+2,9n))},"2e-6M-9m":B(1b){A 6L=1b.2G;A 9l=6L.T("/*");A 9k=6L.31("*/");if((9l==-1)||(9k==-1)){1z.1K("kt en ks\'t 6M 9m!");C""}C z.5m(6L.21(9l+2,9k))},"kr":B(1b){C z.3u(1b.2G)},"kq":B(1b){if(z.1l&&!1b.el){z.1n(["ko","em","kn","km"],B(i){1u{A 1e=S 9j(kl[i]+".kk");1e.kj=U;1e.ki(1b.2G);C 1e}1y(e){}})}I{C 1b.el}}};(B(){z.e5=B(F,ej,ei,eh){A 2F={};2F.F=F;A 6J=L;if(F.3R){A 3R=z.1D(F.3R);A 9i=3R.kh("kg");2F.2E=F.2E||(9i?9i.1Z:L);6J=z.6K(3R)}I{2F.2E=F.2E}A 5l=[{}];if(6J){5l.Y(6J)}if(F.5g){5l.Y(F.5g)}if(F.ek){5l.Y({"z.ek":S 5d().8O()})}2F.1r=z.9h(z.1x.14(L,5l));2F.9d=F.9d||"9g";A d=S z.30(ej);d.5k(ei,B(eg){C eh(eg,d)});A ld=F.4E;if(ld&&z.1Y(ld)){d.ef(B(ee){C ld.2d(F,ee,2F)})}A 1G=F.9f;if(1G&&z.1Y(1G)){d.ed(B(e9){C 1G.2d(F,e9,2F)})}A 6I=F.kf;if(6I&&z.1Y(6I)){d.9e(B(e8){C 6I.2d(F,e8,2F)})}d.1F=2F;C d};A e4=B(O){O.e0=K;A 1b=O.1F.1b;if(V 1b.e7=="B"){1b.e7()}};A e3=B(O){C z.e6[O.1F.9d](O.1F.1b)};A e2=B(9c,O){1z.1K(9c);C 9c};A 3Q=B(F){A O=z.e5(F,e4,e3,e2);O.1F.1b=z.9b(O.1F.F);C O};A 5j=L;A 3t=[];A 94=B(){A dZ=(S 5d()).dU();if(!z.e1){z.1n(3t,B(4D,6H){if(!4D){C}A O=4D.O;1u{if(!O||O.e0||!4D.dT(O)){3t.3S(6H,1);C}if(4D.dR(O)){3t.3S(6H,1);4D.dP(O)}I{if(O.9a){if(O.9a+(O.1F.F.6G||0)0){5c(z.2p(D,B(){D.5b(L,8R)}),d);C D}D.4A=S 5d().8O();if(D.2Z){D.4A-=D.8Q*D.2o}D.8N=D.4A+D.8Q;D.2D=K;D.2Z=U;A 8P=D.2C.4x(D.2o);if(!D.2o){if(!D.4y){D.4y=D.4z}D.3q("dt",[8P])}D.3q("ds",[8P]);D.8M();C D},jS:B(){5e(D.3r);if(!D.2D){C D}D.2Z=K;D.3q("dr",[D.2C.4x(D.2o)]);C D},jR:B(dq,dp){5e(D.3r);D.2D=D.2Z=K;D.2o=dq*6D;if(dp){D.5b()}C D},jQ:B(dn){if(!D.3r){C}5e(D.3r);if(dn){D.2o=1}D.3q("dm",[D.2C.4x(D.2o)]);D.2D=D.2Z=U;C D},3N:B(){if(D.2D){C D.2Z?"3M":"jP"}C"jO"},8M:B(){5e(D.3r);if(D.2D){A dl=S 5d().8O();A 2q=(dl-D.4A)/(D.8N-D.4A);if(2q>=1){2q=1}D.2o=2q;if(D.5a){2q=D.5a(2q)}D.3q("8B",[D.2C.4x(2q)]);if(2q<1){D.3r=5c(z.2p(D,"8M"),D.dj)}I{D.2D=U;if(D.4z>0){D.4z--;D.5b(L,K)}I{if(D.4z==-1){D.5b(L,K)}I{if(D.4y){D.4z=D.4y;D.4y=0}}}D.2o=0;D.3q("dh")}}C D}});(B(){A df=B(E){if(z.1l){A ns=E.1c;if(!ns.8L.G&&z.1c(E,"8L")=="dg"){ns.8L="1"}if(!ns.3n.G&&z.1c(E,"3n")=="8K"){ns.3n="8K"}}};z.6C=B(F){if(V F.1d=="1k"){2m S 1O("z.6C jN an 1d 1Z")}F.E=z.1D(F.E);A 3p=z.1x({6w:{}},F);A 8J=(3p.6w.2W={});8J.1w=(V 3p.1w=="1k")?B(){C 2V(z.1c(3p.E,"2W"))}:3p.1w;8J.1d=3p.1d;A 2U=z.6y(3p);z.2c(2U,"6x",L,B(){df(3p.E)});C 2U};z.8I=B(F){C z.6C(z.1x({1d:1},F))};z.8H=B(F){C z.6C(z.1x({1d:0},F))};if(z.6B&&!z.3o){z.8E=B(n){C 2k("0.5")+((2Y.da((n+2k("1.5"))*2Y.d9))/2)}}I{z.8E=B(n){C 0.5+((2Y.da((n+1.5)*2Y.d9))/2)}}A d4=B(6A){D.8G=6A;R(A p in 6A){A 1a=6A[p];if(1a.1w 1N z.1J){1a.d7=S z.1J()}}D.4x=B(r){A J={};R(A p in D.8G){A 1a=D.8G[p];A 6z=L;if(1a.1w 1N z.1J){6z=z.d8(1a.1w,1a.1d,r,1a.d7).8F()}I{if(!z.2l(1a.1w)){6z=((1a.1d-1a.1w)*r)+1a.1w+(p!="2W"?1a.jM||"px":"")}}J[p]=6z}C J}};z.6y=B(F){F.E=z.1D(F.E);if(!F.5a){F.5a=z.8E}A 2U=S z.d6(F);z.2c(2U,"6x",2U,B(){A pm={};R(A p in D.6w){A 1a=pm[p]=z.1x({},D.6w[p]);if(z.1Y(1a.1w)){1a.1w=1a.1w()}if(z.1Y(1a.1d)){1a.1d=1a.1d()}A d5=(p.1M().T("jL")>=0);B 8C(E,p){4w(p){2X"58":C E.8D;2X"3n":C E.6v}A v=z.1c(E,p);C(p=="2W")?2V(v):2k(v)};if(V 1a.1d=="1k"){1a.1d=8C(D.E,p)}I{if(V 1a.1w=="1k"){1a.1w=8C(D.E,p)}}if(d5){1a.1w=S z.1J(1a.1w);1a.1d=S z.1J(1a.1d)}I{1a.1w=(p=="2W")?2V(1a.1w):2k(1a.1w)}}D.2C=S d4(pm)});z.2c(2U,"8B",2U,B(8A){R(A s in 8A){z.1c(D.E,s,8A[s])}});C 2U}})()}',62,1711,'|||||||||||||||||||||||||||||||||||dojo|var|function|return|this|node|args|length|evt|else|ret|true|null|obj|elem|dfd|arguments|arr|for|new|indexOf|false|typeof||_base|push|type||te|||apply|attr|||||prop|xhr|style|end|doc|match|uri|_hasResource|key|del|undefined|isIE|item|forEach|djConfig|name|document|query|while|_66|try|res|start|mixin|catch|console|split|root|prototype|byId|gcs|ioArgs|err|NodeList|_p|Color|debug|parentNode|toLowerCase|instanceof|Error|constructor|provide|isString|ta|255|val|_a|global|_69|isFunction|value||substring|join|map|tn||window||path|_343|_220|_listeners|connect|call|json|replace|left|_b|toString|128|parseFloat|isArray|throw||_percent|hitch|step|declare|charAt|nodeType|_3c3|nidx|slice|faux|fired|_c4|_7e|loc|curve|_active|url|_44c|responseText|str|_312|idx|tqp|isNaN|isOpera|_22d|callee|add|_18b|_f8|_e2|_41|anim|Number|opacity|case|Math|_paused|Deferred|lastIndexOf|||||||||shift|substr|string|_3e7|_3ce|break|_w|charCode|_listener|_d5|_c5|authority|_49|width|isSafari|_49e|fire|_timer|_47b|_465|eval|_in|_40c|_409|_362|_3d9|className|_3d5|_386|_37a|body|getComputedStyle|box|_221|keyCode|remove|_8d|_46|paused|status|not|_478|_461|form|splice|filter|concat|tret|childNodes|_38b|_367|_33d||||||||||_340|_348|keypress|appendChild|_toArray|Array|_2b0|_toPixelValue|ref|_fixEvent|_19f|_14c|_14a|_150|_141|declaredClass|_d4|_99|_Url|_83|scheme|_67|_3d|switch|getValue|_startRepeatCount|repeat|_startTime|_47e|cancel|tif|load|to|with|tf|getElementsByTagName|number|_34c|_342|extend|_1e3|_normalizeEventName|_14b|_14e|results|self|cbfn|_f9|_d8|_b2|src|_88|dav||baseUrl|fragment|_loadedModules|_44|_43|_loaders|mll|height||easing|play|setTimeout|Date|clearTimeout|hdr|content|code|errback|_464|addCallbacks|_450|fromJson|_413|_3fc|_3ee|max|_31e|cond|getAttribute|_3d4|obi|tagName|_360|_381|contains|firstChild|_368|_372|_320|place|_2fa|scrollTop|_299|scrollLeft|top|documentElement|_288|_287|_getBorderExtents|_23f|_23d|_239|_218|_216|_211|eles|target|keys|shiftKey|ctrlKey|event|192|iel|_1db|delete|_1cf||addEventListener|String|_1af|_157|array|_14d|continue|_14f|_137|_11f|_106|_findMethod|has|_delegate|_dc|_d3|loaded|_9a|_loadInit|_inFlightCount|getObject|tv|_4f|_postLoad|_2d|offsetWidth|properties|beforeBegin|animateProperty|_4ad|_4a6|isKhtml|_fade|100|headers|readyState|timeout|_469|_457|_44d|formToObject|_441|comment|_43d|_36f|_419|tp|_40a|_406|_407|_373|_403|_3e6|_31b|cbi|test|_3c7|nextSibling|last|_3a1|_38e|_365|_36b|ecn|_364|_363|_356|_35e|_35f|_34f|_34d|_349|trim|tci|_328|_32b|_31f|_31c|_anim|_300|_2ff|_2f5|_2e7|removeClass|addClass|func|_2c4|cls|_2a9|_2ae|_280|_27f|_getPadExtents|isMoz|none|_233|cssText|_214|_fixCallback|_synthesizeEvent|stopPropagation|preventDefault|_setKeyChar|_1e1|ieh|_1d7|_1be|colorFromArray|sanitize|bits|rgb|_156|_fire|_resback|_13d|partial|_13a|silentlyCancelled|_topics|_127|_f1|_f0|superclass|_ec|_e3|mct|setObject|_bf|_b3|object|require|_92|_khtmlTimer|location|XMLHTTP|locale|dua|_71|_modulePrefixes|_55|_loadModule|_51|_50|_4e|pop|_3f|_callLoaded|_unloaders|_loadNotifying|_loadedUrls|_27|_24|_1d|_5|_4b7|onAnimate|getStyle|offsetHeight|_defaultEasing|toCss|_properties|fadeOut|fadeIn|_49f|auto|zoom|_cycle|_endTime|valueOf|_494|duration|_492|DELETE|_ioAddQueryToUrl|putData|contentType|password|user|_isDocumentOk|application|||||_466||||||startTime|_xhrObj|_45f|handleAs|addBoth|error|text|objectToQuery|_44f|ActiveXObject|_443|_442|filtered|_43f|_43e|_437|file|tnl|_41c|_filterQueryResult|_zipIdx|_408|_402|evaluate|_3ed|_380|fHit|_361|_33b|_3da|_3ab|_3d6|RegExp|_327|_3cf|_3c9|child|innerHTML|first|tval|_391|class|pnc|_37e|_37c|_375|_366|_35c|_35a|_353|_33c|_336|_314|||_315|_oe|_307|_309|cloneNode|after|createElement||_2f8|_2ef|_2ee|unshift|coords|some|every||_2cb|script|_2c9|parent||a2p||_2c3|_2bd||abs|_getMarginBox|_2b3|_2a6|position|_2a7|_2ac|_2ab|_getIeDocumentElementOffset|getBoundingClientRect|ownerDocument|_2a3|clientWidth|_isBodyLtr|_fixIeBiDiScrollLeft|_bodyLtr|_29d|_getContentBox|_setBox|_getMarginExtents|_getPadBorderExtents|_usesBorderBox|boxModel|pcs|st|sl|_240|runtimeStyle|_dcm|BackCompat|compatMode|default|_21b|_d|html|_event_listener|handlers|PAGE_DOWN|PAGE_UP|RIGHT_ARROW|LEFT_ARROW|DOWN_ARROW|UP_ARROW|_preventDefault||_stopPropagation|returnValue||_trySetKeyCode|cancelBubble|currentTarget|106|_1ee|111||_1e8|_1e7|||se|srcElement|onkeydown||_1d0|_disconnect|lid|_1c0|_connect|_set|_195|_185|_183|_17d|_everyOrSome|_16b|_172|_15b|Function|_154|_escapeString|_140|chain|_check|canceller|_12d|_124|_11a|_10d|_107|inherited|_fa|_f2|_findMixin|_constructor|preamble|_de|clone|tmp|_c7|TMP|_be|_ba|_mixin|isBrowser|lang|firebug||param|modulePaths|_a7|_fireCallback|_a0|setContext||_9c|unloaded||||_96|_93|navigator|_90|_89||protocol|_84|_86|_XMLHTTP_PROGIDS|gears|google|setAttribute|_80|_77|cfg|_6f|_getModuleSymbols|_5a|_58|_53|_4d|_4c|_45|_40|_moduleHasPrefix|_loadUri|_28|_26|_21|_22|tests|doh|_20|_1f|_1c|version|_1b|_19|_getProp|_11|_4|_4a5|_4b3|_Animation|tempColor|blendColors|PI|sin|||||_49a|normal|onEnd||rate||curr|onStop|_497||_496|pct|onPause|onPlay|onBegin|delay||_491|_Line|_48b|wrapForm|PUT|_487|POST|GET|_476|_474|_472|_ioWatch|send|_471|setRequestHeader|open|callback|setInterval|_470|resHandle|_46f|ioCheck|_46e|validCheck|getTime|_ioCancelAll|addOnUnload|clearInterval|dojoType|now|canceled|_blockAsync|_45e|_45c|_459|_ioSetArgs|_contentHandlers|abort|_458|_456||||addErrback|_454|addCallback|_452|_44b|_44a|_449|preventCache|responseXML|Microsoft|JSON|usePlainJson|_431|toJson|_430|_42d|image|opt|ria|_421|_41b|_40b|_zip|_410|_40d|_357|sqf|_374|_3e5|_3df|_38f|clc|pred|parseInt|ntf|_3bf|_3bc|cnl|previousSibling|_3a9|_3a6|_39c|_399|_396|_392|__cachedIndex|__cachedLength|_376|iterateNext|_34a|_355|_354|_32c|_350|_34b|_33f|_33e|_33a|_338|_334|_332||_330|_32e||_322|_316|mousemove|mouseout|mouseover|_305|lastChild||_2f9||_2f2|_2f1|removeChild|_2ec|_2eb|_2ea|_2e6||_2e4|_2e2|_2d6|_2d5|_2d4|_2d3|_2d2|_2d1|_2cd|_2cc|scs|write|_2c8|hasClass|_2c0|_2bb|_2b5|_abs|_docScroll|offsetParent|offsetTop|offsetLeft|absolute|getBoxObjectFor|clientLeft|_setContentSize|_setMarginBox|_28d|_286|_285|_289|NaN|_281|border|_272|_26b|_260|_258|_253|_24c|_246|_23a|_getOpacity|_setOpacity|_238|td|tr|nodeName|FILTER|_22f|_22e|currentStyle|_22c|_22b|display|QuirksMode|unselectable|_217|isMozilla|getElementById|attributes|all|_ie_listener|_getIeDispatcher|_1fd|NUM_LOCK|SCROLL_LOCK|INSERT|END|HOME|PAUSE|F12|F11|F10|F9|F8|F7|F6|F5|F4|F3|F2|F1|63232|SHIFT_TAB|TAB|keyIdentifier|_1f3|stopEvent|_punctMap|222|219|186|onkeypress|_stealthKeyDown|_fixKeys|relatedTarget|_1e0|_1df|_stealthKeydown|_1d6|_1d5|_1d1|_1ca|_1c9|_1cb|_1c2|_1c1|_1c3|_1c4|_1bc|_1b3|_1b2|colorFromHex|colorFromRgb|named|colorFromString|mask|rgba|_19c|_197|_192|setColor|_180|_178|_177|_175|_174|_16d|_166|_164|_163|_162|_15c|_15d|_15e|index|__json__|toJsonIndentStr|_nextId|_12f|_12b|publish|_128|_126|_125|_122|_121|_123|_11c|_11b|_10c|_10b|_108|getDispatcher|argument|nom|_construct|_core|_makeCtor|_df|_db|deprecated|isObject|_cc||scope||_hitchArgs|_c2||pre|_c1|native|isDebug||registerModulePath|_a8||finally|||_a6|_a5|_a4|_a3|_a2|_a1|_9f|_9e|_9d|_9b|_98|_97|onbeforeunload|ipt|scr|complete|_95|userAgent|_modulesLoaded|initialized|_initFired|_8c|_8a|_getText|_87|ieForceActiveXXhr|Msxml2|isGears|_81|_gearsObject|googlegears|GearsFactory|isFF|_7d|Safari|_72|_name|_6c|ire|ore|_68|i18n|_5b|requireIf|_56|_52|loading|_4a|_loadPath|_47|_48|_global_omit_module_check|_getModulePrefix|_3c|_3a|_37|_30|Boolean|_loadUriAndCheck|_2e||cacheBust|_1e|_1a|_17|_16|_15|_14|_f|_10|_e|_9|_8|revision|flag|patch|minor|major|_6|color|units|needs|stopped|playing|stop|gotoPercent|pause|1000|implemented|yet|_48a|xhrDelete|rawXhrPut|xhrPut|postData|rawXhrPost|xhrPost|xhrGet|Type|Content|sync|response|http|bad|urlencoded|www|_watchInFlightError||exceeded|handle|action|getAttributeNode|loadXML|async|XMLDOM|prefixes|MSXML3|MSXML|MSXML2||xml|javascript|wasn|your|optional|message|off|turn|use|endpoints|issues|security|potential|avoid|mimetype|using|consider|please|decodeURIComponent|queryToObject|formToJson|formToQuery|encodeURIComponent|selected|option|multiple|checked|checkbox|radio|disabled|textarea|select|button|reset|submit|input|_3fb|hasAttribute|0n|even|odd|nth|_3b5|empty|_3b1|_3ad|htmlFor|_38a|under||exprssion|failure|ANY_TYPE|XPathResult|starts|keyup|keydown|mouseup|mousedown|blur|click|combine|span|addContent||adopt|orphan|_2de|_2dd|styles|_2da|_2d9|_2cf|_2ce|show|createPopup|toggleClass|scrollWidth|clientTop|ltr|direction|pageXOffset|pageYOffset|fixed|contentBox|marginBox|BUTTON|TABLE|_getBorderBox|clientHeight|visible|overflow|marginBottom|marginRight|marginTop|marginLeft|borderBottomWidth|borderBottomStyle|borderRightWidth|borderRightStyle|borderTopWidth|borderTopStyle|borderLeftWidth|borderLeftStyle|paddingBottom|paddingRight|paddingTop|paddingLeft|offset||min|padding||margin|Opacity|Alpha|alpha|filters|pixelLeft|medium|_22a|defaultView|before||insertBefore|KhtmlUserSelect|MozUserSelect|setSelectable|isDescendant|div|_destroyElement|BackgroundImageCache|execCommand|PageDown|PageUp|Right|Left|Down|Up|63289|63249|63248|PRINT_SCREEN|63302|63277|63276|63275|63273|63272|63250|63247|63246|63245|63244|63243|63242|63241|63240|63239|63238|63237|63236|63235|63234|63233|Enter|_1f9|which|_1f6|bubbledKeyCode|221|220||||191|190|189|188|187|toElement|fromElement|clientY|pageY||clientX|pageX|offsetY|||layerY|offsetX|layerX|parentWindow|_nop|_allow_leaks|145|144|126|F15|125|F14|124|F13|123|122|121|120|119|118|117|116|115|114|113|112|NUMPAD_DIVIDE|110|NUMPAD_PERIOD|109|NUMPAD_MINUS|108|NUMPAD_ENTER|107|NUMPAD_PLUS|NUMPAD_MULTIPLY|105|NUMPAD_9|104|NUMPAD_8|103|NUMPAD_7|102|NUMPAD_6|101|NUMPAD_5|NUMPAD_4||NUMPAD_3|NUMPAD_2|NUMPAD_1|NUMPAD_0||SELECT|RIGHT_WINDOW||LEFT_WINDOW||HELP|SPACE|ESCAPE|CAPS_LOCK|ALT|CTRL|SHIFT|ENTER|CLEAR|BACKSPACE|attachEvent|fixEvent|fromCharCode|keyChar|_1b9|removeEventListener|0x|round|toHex|toRgba|toRgb|aqua|teal|blue|navy|yellow|olive|lime|green|fuchsia|purple|red|maroon|white|gray|silver|black|boolean|called|already|Cancelled|connectPublisher|unsubscribe|subscribe|disconnect|_113|_112||_111|_110|||found|was||must|_|module|||required|likely|It|declaration|Mixin|separate|instead|property|initializer||pass|_c9|_bb|_b7|nfunction|isAlien|isFinite|isArrayLike|_firebug|withDoc|withGlobal|_writeIncludes|VML|behavior|addRule|createStyleSheet|vml|com|microsoft|schemas|urn|namespaces|onunload|onreadystatechange|defer|khtml|WebKit|DOMContentLoaded|enableMozDomContentLoaded|domcontentloaded|Unable|base|chrome|1223|304|300|200|available|XMLHttpRequest|_println|language|userLanguage|isQuirks|factory|mimeTypes|Factory|Gears|_7f|MSIE||Firefox|Gecko|Konqueror||Opera|appVersion|xd|browser|moduleUrl|port|host|hostenv|_requireLocalization|_5f|_5e|_5d|_5c|requireLocalization|requireAfterIf|_57|common|platformRequire|defined|symbol|_isXDomain|tried|Could|__package__|packageFileName|_42|useXDomain|flight|still|files|addOnLoad|failed|sourceURL|util|notice|without|change|subject|APIs|EXPERIMENTAL|experimental|removed|will|DEPRECATED|exists|10315|Rev|Mobile|Spidermonkey|Rhino||Browser|delayMozLoadingFix|preventBackButtonFix|libraryScriptUri|baseRelativePath|baseScriptUri|allowQueryConfig|warn|trace|timeEnd||time|profileEnd|profile|log|info|groupEnd|group|dirxml|dir|count|assert'.split('|'),0,{}); + + +/* + +Prototype 1.5 rc0 + - Adapted from Ruby on Rails - http://dev.rubyonrails.org/browser/spinoffs/prototype/src + - By Lunarmedia, 06 August, 2006 + - Available at (and packed with) JavascriptCompressor.com + +Please note this version is missing the selector.js component of the full Prototype library. +You can get the compressed version of selector at JavascriptCompressor.com + +*/ + +var decompressedPrototype = function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[(function(e){return d[e]})];e=(function(){return'\\w+'});c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('d T={4l:\'1.5.8P\',3E:\'(?:<3G.*?>)((\\n|\\r|.)*?)(?:<\\/3G>)\',2v:7(){},K:7(x){c x}};d 1b={17:7(){c 7(){6.1I.2n(6,N)}}};d 1e=z q();q.u=7(5d,O){G(d 1G 2M O){5d[1G]=O[1G]}c 5d};q.1U=7(U){1j{f(U==1v)c\'1v\';f(U==1L)c\'1L\';c U.1U?U.1U():U.2C()}1s(e){f(e 8R 9l)c\'...\';25 e}};7j.v.1d=7(){d 43=6,23=$A(N),U=23.8S();c 7(){c 43.2n(U,23.3s($A(N)))}};7j.v.8U=7(U){d 43=6;c 7(C){c 43.8V(U,C||1W.C)}};q.u(8Q.v,{8W:7(){d 4Z=6.2C(16);f(6<16)c\'0\'+4Z;c 4Z},5j:7(){c 6+1},8Y:7(o){$R(0,6,11).V(o);c 6}});d 6s={6j:7(){d 48;G(d i=0;i0){f(I=O.I(1A)){L+=O.47(0,I.w);L+=(1z(I)||\'\').2C();O=O.47(I.w+I[0].t)}1D{L+=O,O=\'\'}}c L},92:7(1A,1z,3i){1z=6.2T.52(1z);3i=3i===1v?1:3i;c 6.2T(1A,7(I){f(--3i<0)c I[0];c 1z(I)})},93:7(1A,o){6.2T(1A,o);c 6},94:7(t,2S){t=t||30;2S=2S===1v?\'...\':2S;c 6.t>t?6.47(0,t-2S.t)+2S:6},9F:7(){c 6.2y(/^\\s+/,\'\').2y(/\\s+$/,\'\')},71:7(){c 6.2y(/<\\/?[^>]+>/7Y,\'\')},2Q:7(){c 6.2y(z 3O(T.3E,\'5P\'),\'\')},70:7(){d 6Y=z 3O(T.3E,\'5P\');d 5p=z 3O(T.3E,\'98\');c(6.I(6Y)||[]).1C(7(5o){c(5o.I(5p)||[\'\',\'\'])[1]})},3q:7(){c 6.70().1C(7(3G){c 4q(3G)})},9E:7(){d 1q=J.4Y(\'1q\');d 1Y=J.9D(6);1q.75(1Y);c 1q.3h},9c:7(){d 1q=J.4Y(\'1q\');1q.3h=6.71();c 1q.2z[0]?1q.2z[0].6q:\'\'},78:7(){d 7i=6.I(/^\\??(.*)$/)[1].3j(\'&\');c 7i.36({},7(5b,72){d 1i=72.3j(\'=\');5b[1i[0]]=1i[1];c 5b})},1Z:7(){c 6.3j(\'\')},3P:7(){d 2l=6.3j(\'-\');f(2l.t==1)c 2l[0];d 54=6.5g(\'-\')==0?2l[0].7e(0).3Y()+2l[0].7g(1):2l[0];G(d i=1,73=2l.t;i<73;i++){d s=2l[i];54+=s.7e(0).3Y()+s.7g(1)}c 54},1U:7(){c"\'"+6.2y(/\\\\/g,\'\\\\\\\\\').2y(/\'/g,\'\\\\\\\'\')+"\'"}});4b.v.2T.52=7(1z){f(2i 1z==\'7\')c 1z;d 2U=z 3n(1z);c 7(I){c 2U.7a(I)}};4b.v.9h=4b.v.78;d 3n=1b.17();3n.79=/(^|.|\\r|\\n)(#\\{(.*?)\\})/;3n.v={1I:7(2U,1A){6.2U=2U.2C();6.1A=1A||3n.79},7a:7(U){c 6.2U.2T(6.1A,7(I){d 53=I[1];f(53==\'\\\\\')c I[2];c 53+(U[I[3]]||\'\').2C()})}};d $1y=z q();d $49=z q();d 1p={V:7(o){d w=0;1j{6.2m(7(h){1j{o(h,w++)}1s(e){f(e!=$49)25 e}})}1s(e){f(e!=$1y)25 e}},9n:7(o){d L=11;6.V(7(h,w){L=L&&!!(o||T.K)(h,w);f(!L)25 $1y});c L},9o:7(o){d L=11;6.V(7(h,w){f(L=!!(o||T.K)(h,w))25 $1y});c L},3e:7(o){d P=[];6.V(7(h,w){P.W(o(h,w))});c P},7n:7(o){d L;6.V(7(h,w){f(o(h,w)){L=h;25 $1y}});c L},7o:7(o){d P=[];6.V(7(h,w){f(o(h,w))P.W(h)});c P},9p:7(1A,o){d P=[];6.V(7(h,w){d 7c=h.2C();f(7c.I(1A))P.W((o||T.K)(h,w))});c P},1M:7(U){d 51=Y;6.V(7(h){f(h==U){51=11;25 $1y}});c 51},36:7(45,o){6.V(7(h,w){45=o(45,h,w)});c 45},9q:7(1F){d 23=$A(N).47(1);c 6.3e(7(h){c h[1F].2n(h,23)})},9s:7(o){d L;6.V(7(h,w){h=(o||T.K)(h,w);f(L==1v||h>=L)L=h});c L},9u:7(o){d L;6.V(7(h,w){h=(o||T.K)(h,w);f(L==1v||hb?1:0}).3r(\'h\')},1Z:7(){c 6.3e(T.K)},9B:7(){d o=T.K,23=$A(N);f(2i 23.5e()==\'7\')o=23.9C();d 7l=[6].3s(23).1C($A);c 6.1C(7(h,w){c o(7l.3r(w))})},1U:7(){c\'#<1p:\'+6.1Z().1U()+\'>\'}};q.u(1p,{1C:1p.3e,5v:1p.7n,1k:1p.7o,8M:1p.1M,7p:1p.1Z});d $A=1E.7q=7(2R){f(!2R)c[];f(2R.1Z){c 2R.1Z()}1D{d P=[];G(d i=0;i<2R.t;i++)P.W(2R[i]);c P}};q.u(1E.v,1p);f(!1E.v.4d)1E.v.4d=1E.v.4m;q.u(1E.v,{2m:7(o){G(d i=0;i<6.t;i++)o(6[i])},5i:7(){6.t=0;c 6},7r:7(){c 6[0]},5e:7(){c 6[6.t-1]},7s:7(){c 6.1k(7(h){c h!=1v||h!=1L})},6J:7(){c 6.36([],7(6H,h){c 6H.3s(h&&h.5D==1E?h.6J():[h])})},5s:7(){d 4N=$A(N);c 6.1k(7(h){c!4N.1M(h)})},5g:7(U){G(d i=0;i<6.t;i++)f(6[i]==U)c i;c-1},4m:7(5h){c(5h!==Y?6:6.1Z()).4d()},1U:7(){c\'[\'+6.1C(q.1U).1N(\', \')+\']\'}});d 4h={2m:7(o){G(d 1O 2M 6){d h=6[1O];f(2i h==\'7\')49;d 1i=[1O,h];1i.1O=1O;1i.h=h;o(1i)}},7t:7(){c 6.3r(\'1O\')},4N:7(){c 6.3r(\'h\')},7u:7(2N){c $H(2N).36($H(6),7(4Q,1i){4Q[1i.1O]=1i.h;c 4Q})},7w:7(){c 6.1C(7(1i){c 1i.1C(4n).1N(\'=\')}).1N(\'&\')},1U:7(){c\'#<4h:{\'+6.1C(7(1i){c 1i.1C(q.1U).1N(\': \')}).1N(\', \')+\'}>\'}};7 $H(U){d 2N=q.u({},U||{});q.u(2N,1p);q.u(2N,4h);c 2N};3L=1b.17();q.u(3L.v,1p);q.u(3L.v,{1I:7(22,2x,2H){6.22=22;6.2x=2x;6.2H=2H},2m:7(o){d h=6.22;2q{o(h);h=h.5j()}1H(6.1M(h))},1M:7(h){f(h<6.22)c Y;f(6.2H)c h<6.2x;c h<=6.2x}});d $R=7(22,2x,2H){c z 3L(22,2x,2H)};d M={4w:7(){c 6s.6j(7(){c z 5C()},7(){c z 5n(\'7y.6d\')},7(){c z 5n(\'7z.6d\')})||Y},4s:0};M.2W={3b:[],2m:7(o){6.3b.2m(o)},69:7(4F){f(!6.1M(4F))6.3b.W(4F)},7A:7(5t){6.3b=6.3b.5s(5t)},3y:7(1a,26,E,2Z){6.V(7(3o){f(3o[1a]&&2i 3o[1a]==\'7\'){1j{3o[1a].2n(3o,[26,E,2Z])}1s(e){}}})}};q.u(M.2W,1p);M.2W.69({5G:7(){M.4s++},1B:7(){M.4s--}});M.44=7(){};M.44.v={4a:7(m){6.m={1F:\'4j\',4p:11,5H:\'5E/x-86-Q-7C\',28:\'\'};q.u(6.m,m||{})},3l:7(){c 6.E.32==1v||6.E.32==0||(6.E.32>=84&&6.E.32<7E)},7G:7(){c!6.3l()}};M.3t=1b.17();M.3t.5L=[\'7H\',\'80\',\'7I\',\'7J\',\'4t\'];M.3t.v=q.u(z M.44(),{1I:7(1l,m){6.E=M.4w();6.4a(m);6.26(1l)},26:7(1l){d 28=6.m.28||\'\';f(28.t>0)28+=\'&7K=\';1j{6.1l=1l;f(6.m.1F==\'7L\'&&28.t>0)6.1l+=(6.1l.I(/\\?/)?\'&\':\'?\')+28;M.2W.3y(\'5G\',6,6.E);6.E.7N(6.m.1F,6.1l,6.m.4p);f(6.m.4p){6.E.5T=6.5J.1d(6);2Y((7(){6.4r(1)}).1d(6),10)}6.5A();d 1c=6.m.5V?6.m.5V:28;6.E.7O(6.m.1F==\'4j\'?1c:1L)}1s(e){6.3p(e)}},5A:7(){d 1P=[\'X-7P-7Q\',\'5C\',\'X-T-4l\',T.4l,\'7R\',\'1Y/7m, 1Y/2e, 5E/5F, 1Y/5F, */*\'];f(6.m.1F==\'4j\'){1P.W(\'5Q-2g\',6.m.5H);f(6.E.7S)1P.W(\'7T\',\'7U\')}f(6.m.1P)1P.W.2n(1P,6.m.1P);G(d i=0;i<1P.t;i+=2)6.E.7V(1P[i],1P[i+1])},5J:7(){d 2F=6.E.2F;f(2F!=1)6.4r(6.E.2F)},4A:7(B){1j{c 6.E.7W(B)}1s(e){}},5M:7(){1j{c 4q(\'(\'+6.4A(\'X-7X\')+\')\')}1s(e){}},5R:7(){1j{c 4q(6.E.3F)}1s(e){6.3p(e)}},4r:7(2F){d C=M.3t.5L[2F];d E=6.E,2Z=6.5M();f(C==\'4t\'){1j{(6.m[\'2I\'+6.E.32]||6.m[\'2I\'+(6.3l()?\'81\':\'82\')]||T.2v)(E,2Z)}1s(e){6.3p(e)}f((6.4A(\'5Q-2g\')||\'\').I(/^1Y\\/7m/i))6.5R()}1j{(6.m[\'2I\'+C]||T.2v)(E,2Z);M.2W.3y(\'2I\'+C,6,E,2Z)}1s(e){6.3p(e)}f(C==\'4t\')6.E.5T=T.2v},3p:7(57){(6.m.5W||T.2v)(6,57);M.2W.3y(\'5W\',6,57)}});M.4C=1b.17();q.u(q.u(M.4C.v,M.3t.v),{1I:7(1w,1l,m){6.4x={3m:1w.3m?$(1w.3m):$(1w),3z:1w.3z?$(1w.3z):(1w.3m?1L:$(1w))};6.E=M.4w();6.4a(m);d 1B=6.m.1B||T.2v;6.m.1B=(7(E,U){6.5Y();1B(E,U)}).1d(6);6.26(1l)},5Y:7(){d 3A=6.3l()?6.4x.3m:6.4x.3z;d 3k=6.E.3F;f(!6.m.3q)3k=3k.2Q();f(3A){f(6.m.60){z 6.m.60(3A,3k)}1D{k.6h(3A,3k)}}f(6.3l()){f(6.1B)2Y(6.1B.1d(6),10)}}});M.61=1b.17();M.61.v=q.u(z M.44(),{1I:7(1w,1l,m){6.4a(m);6.1B=6.m.1B;6.1J=(6.m.1J||2);6.2s=(6.m.2s||1);6.4B={};6.1w=1w;6.1l=1l;6.22()},22:7(){6.m.1B=6.63.1d(6);6.2D()},7b:7(){6.4B.1B=1v;89(6.65);(6.1B||T.2v).2n(6,N)},63:7(26){f(6.m.2s){6.2s=(26.3F==6.64?6.2s*6.m.2s:1);6.64=26.3F}6.65=2Y(6.2D.1d(6),6.2s*6.1J*4z)},2D:7(){6.4B=z M.4C(6.1w,6.1l,6.m)}});7 $(){d P=[],4;G(d i=0;i<4V>\'+6.2t+\'\';c $A(1q.2z[0].2z[0].2z)}};d 1g=z q();1g.6W=1b.17();1g.6W.v=q.u(z 1e.1g(\'96\'),{2V:7(){6.1K.97(6.4)},2X:7(2h){2h.V((7(2j){6.4.1X.55(2j,6.4)}).1d(6))}});1g.5m=1b.17();1g.5m.v=q.u(z 1e.1g(\'99\'),{2V:7(){6.1K.56(6.4);6.1K.74(11)},2X:7(2h){2h.4m(Y).V((7(2j){6.4.55(2j,6.4.9a)}).1d(6))}});1g.7h=1b.17();1g.7h.v=q.u(z 1e.1g(\'9d\'),{2V:7(){6.1K.56(6.4);6.1K.74(6.4)},2X:7(2h){2h.V((7(2j){6.4.75(2j)}).1d(6))}});1g.76=1b.17();1g.76.v=q.u(z 1e.1g(\'9i\'),{2V:7(){6.1K.9m(6.4)},2X:7(2h){2h.V((7(2j){6.4.1X.55(2j,6.4.9t)}).1d(6))}});k.3S=1b.17();k.3S.v={1I:7(4){6.4=$(4)},2m:7(o){6.4.1f.3j(/\\s+/).1k(7(B){c B.t>0}).2m(o)},5c:7(1f){6.4.1f=1f},7k:7(5a){f(6.1M(5a))c;6.5c(6.1Z().3s(5a).1N(\' \'))},42:7(4c){f(!6.1M(4c))c;6.5c(6.1k(7(1f){c 1f!=4c}).1N(\' \'))},2C:7(){c 6.1Z().1N(\' \')}};q.u(k.3S.v,1p);d 5I={5i:7(){G(d i=0;i=0){2b=4.m[w];h=2b.h||2b.1Y}c[4.B,h]},5X:7(4){d h=[];G(d i=0;i<4.t;i++){d 2b=4.m[i];f(2b.87)h.W(2b.h||2b.1Y)}c[4.B,h]}};d $F=D.k.1x;1e.3D=7(){};1e.3D.v={1I:7(4,1J,1a){6.1J=1J;6.4=$(4);6.1a=1a;6.2K=6.1x();6.2A()},2A:7(){5Z(6.2D.1d(6),6.1J*4z)},2D:7(){d h=6.1x();f(6.2K!=h){6.1a(6.4,h);6.2K=h}}};D.k.3C=1b.17();D.k.3C.v=q.u(z 1e.3D(),{1x:7(){c D.k.1x(6.4)}});D.3C=1b.17();D.3C.v=q.u(z 1e.3D(),{1x:7(){c D.3a(6.4)}});1e.2c=7(){};1e.2c.v={1I:7(4,1a){6.4=$(4);6.1a=1a;6.2K=6.1x();f(6.4.1h.2w()==\'Q\')6.67();1D 6.2A(6.4)},4K:7(){d h=6.1x();f(6.2K!=h){6.1a(6.4,h);6.2K=h}},67:7(){d 12=D.2L(6.4);G(d i=0;i<12.t;i++)6.2A(12[i])},2A:7(4){f(4.2g){6c(4.2g.2w()){1r\'6g\':1r\'6i\':1o.3B(4,\'8j\',6.4K.1d(6));1y;1r\'6l\':1r\'1Y\':1r\'3J\':1r\'1k-6n\':1r\'1k-8t\':1o.3B(4,\'8u\',6.4K.1d(6));1y}}}};D.k.2c=1b.17();D.k.2c.v=q.u(z 1e.2c(),{1x:7(){c D.k.1x(6.4)}});D.2c=1b.17();D.2c.v=q.u(z 1e.2c(),{1x:7(){c D.3a(6.4)}});f(!1W.1o){d 1o=z q()}q.u(1o,{8C:8,8F:9,8H:13,8I:27,8J:37,8L:38,8O:39,8T:40,8X:46,4:7(C){c C.Z||C.91},95:7(C){c(((C.6X)&&(C.6X==1))||((C.6Z)&&(C.6Z==1)))},9b:7(C){c C.9e||(C.9f+(J.3R.2G||J.1c.2G))},9g:7(C){c C.9j||(C.9k+(J.3R.2O||J.1c.2O))},7b:7(C){f(C.7d){C.7d();C.9r()}1D{C.48=Y;C.9w=11}},9A:7(C,1h){d 4=1o.4(C);1H(4.1X&&(!4.1h||(4.1h.3Y()!=1h.3Y())))4=4.1X;c 4},1T:Y,5u:7(4,B,1V,1u){f(!6.1T)6.1T=[];f(4.5f){6.1T.W([4,B,1V,1u]);4.5f(B,1V,1u)}1D f(4.4i){6.1T.W([4,B,1V,1u]);4.4i(\'2I\'+B,1V)}},66:7(){f(!1o.1T)c;G(d i=0;i<1o.1T.t;i++){1o.5N.2n(6,1o.1T[i]);1o.1T[i][0]=1L}1o.1T=Y},3B:7(4,B,1V,1u){d 4=$(4);1u=1u||Y;f(B==\'5U\'&&(33.4u.I(/3x|3w|3u/)||4.4i))B=\'5K\';6.5u(4,B,1V,1u)},5N:7(4,B,1V,1u){d 4=$(4);1u=1u||Y;f(B==\'5U\'&&(33.4u.I(/3x|3w|3u/)||4.4k))B=\'5K\';f(4.5x){4.5x(B,1V,1u)}1D f(4.4k){1j{4.4k(\'2I\'+B,1V)}1s(e){}}}});f(33.4u.I(/\\88\\b/))1o.3B(1W,\'8a\',1o.66,Y);d 2d={6o:Y,4P:7(){6.6z=1W.8e||J.3R.2G||J.1c.2G||0;6.6F=1W.8g||J.3R.2O||J.1c.2O||0},6u:7(4){d 19=0,15=0;2q{19+=4.2O||0;15+=4.2G||0;4=4.1X}1H(4);c[15,19]},35:7(4){d 19=0,15=0;2q{19+=4.29||0;15+=4.2f||0;4=4.1Q}1H(4);c[15,19]},68:7(4){d 19=0,15=0;2q{19+=4.29||0;15+=4.2f||0;4=4.1Q;f(4){p=k.1R(4,\'14\');f(p==\'3T\'||p==\'2o\')1y}}1H(4);c[15,19]},1Q:7(4){f(4.1Q)c 4.1Q;f(4==J.1c)c 4;1H((4=4.1X)&&4!=J.1c)f(k.1R(4,\'14\')!=\'4G\')c 4;c J.1c},8o:7(4,x,y){f(6.6o)c 6.6r(4,x,y);6.3g=x;6.34=y;6.1t=6.35(4);c(y>=6.1t[1]&&y<6.1t[1]+4.2k&&x>=6.1t[0]&&x<6.1t[0]+4.2p)},6r:7(4,x,y){d 4S=6.6u(4);6.3g=x+4S[0]-6.6z;6.34=y+4S[1]-6.6F;6.1t=6.35(4);c(6.34>=6.1t[1]&&6.34<6.1t[1]+4.2k&&6.3g>=6.1t[0]&&6.3g<6.1t[0]+4.2p)},8E:7(3Z,4){f(!3Z)c 0;f(3Z==\'8G\')c((6.1t[1]+4.2k)-6.34)/4.2k;f(3Z==\'8K\')c((6.1t[0]+4.2p)-6.3g)/4.2p},77:7(O,Z){O=$(O);Z=$(Z);Z.l.14=\'2o\';d 2P=6.35(O);Z.l.1n=2P[1]+\'1m\';Z.l.18=2P[0]+\'1m\';Z.l.21=O.2p+\'1m\';Z.l.24=O.2k+\'1m\'},4e:7(4M){d 19=0,15=0;d 4=4M;2q{19+=4.29||0;15+=4.2f||0;f(4.1Q==J.1c)f(k.1R(4,\'14\')==\'2o\')1y}1H(4=4.1Q);4=4M;2q{19-=4.2O||0;15-=4.2G||0}1H(4=4.1X);c[15,19]},77:7(O,Z){d m=q.u({5l:11,5r:11,5B:11,5q:11,29:0,2f:0},N[2]||{});O=$(O);d p=2d.4e(O);Z=$(Z);d 2J=[0,0];d 3v=1L;f(k.1R(Z,\'14\')==\'2o\'){3v=2d.1Q(Z);2J=2d.4e(3v)}f(3v==J.1c){2J[0]-=J.1c.2f;2J[1]-=J.1c.29}f(m.5l)Z.l.18=(p[0]-2J[0]+m.2f)+\'1m\';f(m.5r)Z.l.1n=(p[1]-2J[1]+m.29)+\'1m\';f(m.5B)Z.l.21=O.2p+\'1m\';f(m.5q)Z.l.24=O.2k+\'1m\'},8b:7(4){4=$(4);f(4.l.14==\'2o\')c;2d.4P();d 2P=2d.68(4);d 1n=2P[1];d 18=2P[0];d 21=4.6m;d 24=4.6p;4.6P=18-3X(4.l.18||0);4.6I=1n-3X(4.l.1n||0);4.5k=4.l.21;4.7f=4.l.24;4.l.14=\'2o\';4.l.1n=1n+\'1m\';4.l.18=18+\'1m\';4.l.21=21+\'1m\';4.l.24=24+\'1m\'},8w:7(4){4=$(4);f(4.l.14==\'3T\')c;2d.4P();4.l.14=\'3T\';d 1n=3X(4.l.1n||0)-(4.6I||0);d 18=3X(4.l.18||0)-(4.6P||0);4.l.1n=1n+\'1m\';4.l.18=18+\'1m\';4.l.24=4.7f;4.l.21=4.5k}};f(/3x|3w|3u/.4v(33.62)){2d.35=7(4){d 19=0,15=0;2q{19+=4.29||0;15+=4.2f||0;f(4.1Q==J.1c)f(k.1R(4,\'14\')==\'2o\')1y;4=4.1Q}1H(4);c[15,19]}};',62,600,'||||element||this|function|||||return|var||if||value|||Element|style|options||iterator||Object|||length|extend|prototype|index|||new||name|event|Form|transport||for||match|document||result|Ajax|arguments|source|results|form|||Prototype|object|each|push||false|target||true|elements||position|valueL||create|left|valueT|callback|Class|body|bind|Abstract|className|Insertion|tagName|pair|try|select|url|px|top|Event|Enumerable|div|case|catch|offset|useCapture|undefined|container|getValue|break|replacement|pattern|onComplete|map|else|Array|method|property|while|initialize|frequency|range|null|include|join|key|requestHeaders|offsetParent|getStyle|parameter|observers|inspect|observer|window|parentNode|text|toArray|els|width|start|args|height|throw|request||parameters|offsetTop|methods|opt|EventObserver|Position|html|offsetLeft|type|fragments|typeof|fragment|offsetHeight|oStringList|_each|apply|absolute|offsetWidth|do|cache|decay|content|input|emptyFunction|toLowerCase|end|replace|childNodes|registerCallback|display|toString|onTimerEvent|Serializers|readyState|scrollLeft|exclusive|on|delta|lastValue|getElements|in|hash|scrollTop|offsets|stripScripts|iterable|truncation|gsub|template|initializeRange|Responders|insertContent|setTimeout|json||hidden|status|navigator|ycomp|cumulativeOffset|inject||||serialize|responders|_overflow|Methods|collect|adjacency|xcomp|innerHTML|count|split|response|responseIsSuccess|success|Template|responder|dispatchException|evalScripts|pluck|concat|Request|KHTML|parent|Safari|Konqueror|dispatch|failure|receiver|observe|Observer|TimedObserver|ScriptFragment|responseText|script|inputs|ancestor|textarea|classNames|ObjectRange|node|typeName|RegExp|camelize|none|documentElement|ClassNames|relative|right|overflow|HTMLElement|parseFloat|toUpperCase|mode||currentlyExecuting|remove|__method|Base|memo||slice|returnValue|continue|setOptions|String|classNameToRemove|_reverse|page|focus|queryComponent|Hash|attachEvent|post|detachEvent|Version|reverse|encodeURIComponent|disabled|asynchronous|eval|respondToReadyState|activeRequestCount|Complete|appVersion|test|getTransport|containers|matchingInputs|1000|header|updater|Updater|getElementsByTagName|child|responderToAdd|static|tagElements|queryComponents|defaultView|onElementEvent|css|forElement|values|visibility|prepare|mergedHash|pos|offsetcache|_madePositioned|visible|tbody|findOrStore|_nativeExtensions|createElement|digits|trues|found|prepareReplacement|before|camelizedString|insertBefore|selectNodeContents|exception|falses|criteria|classNameToAdd|params|set|destination|last|addEventListener|indexOf|inline|clear|succ|_originalWidth|setLeft|Top|ActiveXObject|scriptTag|matchOne|setHeight|setTop|without|responderToRemove|_observeAndCache|find|reset|removeEventListener|activate|findFirstElement|setRequestHeaders|setWidth|XMLHttpRequest|constructor|application|xml|onCreate|contentType|Field|onStateChange|keydown|Events|evalJSON|stopObserving|inputSelector|img|Content|evalResponse|selectOne|onreadystatechange|keypress|postBody|onException|selectMany|updateContent|setInterval|insertion|PeriodicalUpdater|userAgent|updateComplete|lastText|timer|unloadCache|registerFormCallbacks|positionedOffset|register|parentElement|children|switch|XMLHTTP|_extended|hide|checkbox|update|radio|these|outerHTML|password|clientWidth|one|includeScrollOffsets|clientHeight|nodeValue|withinIncludingScrolloffsets|Try|scrollTo|realOffset|getComputedStyle|show|currentStyle|auto|deltaX|originalPosition|originalVisibility|originalWidth|originalHeight|opera|deltaY|bottom|array|_originalTop|flatten|addMethods|lambda|Toggle|toggle|insertAdjacentHTML|_originalLeft|PeriodicalExecuter|ownerDocument|createRange|createContextualFragment|contentFromAnonymousTable|table|Before|which|matchAll|button|extractScripts|stripTags|pairString|len|collapse|appendChild|After|clone|toQueryParams|Pattern|evaluate|stop|stringValue|preventDefault|charAt|_originalHeight|substring|Bottom|pairs|Function|add|collections|javascript|detect|findAll|entries|from|first|compact|keys|merge|present|toQueryString|getInputs|Msxml2|Microsoft|unregister|disable|urlencoded|blur|300|enable|responseIsFailure|Uninitialized|Loaded|Interactive|_|get|focusFirstElement|open|send|Requested|With|Accept|overrideMimeType|Connection|close|setRequestHeader|getResponseHeader|JSON|gi|submit|Loading|Success|Failure|checked|200|selectedIndex|www|selected|bMSIE|clearTimeout|unload|absolutize|string|getElementById|pageXOffset|getElementsByClassName|pageYOffset|removeChild|replaceChild|click|getHeight|hasClassName|addClassName|removeClassName|within|cleanWhitespace|nodeType|empty|childOf|multiple|change|getPropertyValue|relativize|setStyle|getDimensions|makePositioned|undoPositioned|makeClipping|KEY_BACKSPACE|undoClipping|overlap|KEY_TAB|vertical|KEY_RETURN|KEY_ESC|KEY_LEFT|horizontal|KEY_UP|member|tr|KEY_RIGHT|0_RC_0|Number|instanceof|shift|KEY_DOWN|bindAsEventListener|call|toColorPart|KEY_DELETE|times|finally|callee|srcElement|sub|scan|truncate|isLeftClick|beforeBegin|setStartBefore|im|afterBegin|firstChild|pointerX|unescapeHTML|beforeEnd|pageX|clientX|pointerY|parseQuery|afterEnd|pageY|clientY|RangeError|setStartAfter|all|any|grep|invoke|stopPropagation|max|nextSibling|min|partition|cancelBubble|reject|sortBy|sort|findElement|zip|pop|createTextNode|escapeHTML|strip'.split('|'),0,{}) + +} + +assertEq(decompressedMochiKit.length, 106415) +assertEq(decompressedMochiKit[2000], '5') +assertEq(decompressedMochiKit[12000], '_') +assertEq(decompressedMochiKit[82556], '>') diff --git a/js/src/jit-test/tests/testCrossGlobalInvokeSession.js b/js/src/jit-test/tests/testCrossGlobalInvokeSession.js new file mode 100644 index 0000000..014f079 --- /dev/null +++ b/js/src/jit-test/tests/testCrossGlobalInvokeSession.js @@ -0,0 +1,12 @@ +otherGlobal = newGlobal("same-compartment"); +otherGlobal.poison = Proxy.create({}); +callee = new otherGlobal.Function("return this.poison;"); + +var caught = false; +try { + [1,2,3,4,5,6,7,8].sort(callee); +} catch(e) { + assertEq(e instanceof Error, true); + caught = true; +} +assertEq(caught, true); diff --git a/js/src/jit-test/tests/v8-v5/check-crypto.js b/js/src/jit-test/tests/v8-v5/check-crypto.js new file mode 100644 index 0000000..56897a9 --- /dev/null +++ b/js/src/jit-test/tests/v8-v5/check-crypto.js @@ -0,0 +1,1713 @@ +/* + * Copyright (c) 2003-2005 Tom Wu + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * In addition, the following condition applies: + * + * All redistributions must retain an intact copy of this copyright notice + * and disclaimer. + */ + + +// The code has been adapted for use as a benchmark by Google. +//var Crypto = new BenchmarkSuite('Crypto', 203037, [ +// new Benchmark("Encrypt", encrypt), +// new Benchmark("Decrypt", decrypt) +//]); + + +// Basic JavaScript BN library - subset useful for RSA encryption. + +// Bits per digit +var dbits; +var BI_DB; +var BI_DM; +var BI_DV; + +var BI_FP; +var BI_FV; +var BI_F1; +var BI_F2; + +// JavaScript engine analysis +var canary = 0xdeadbeefcafe; +var j_lm = ((canary&0xffffff)==0xefcafe); + +// This is the best random number generator available to mankind ;) +var MyMath = { + curr: 0, + random: function() { + this.curr = this.curr + 1; + return this.curr; + }, +}; + + +// (public) Constructor +function BigInteger(a,b,c) { + this.array = new Array(); + if(a != null) + if("number" == typeof a) this.fromNumber(a,b,c); + else if(b == null && "string" != typeof a) this.fromString(a,256); + else this.fromString(a,b); +} + +// return new, unset BigInteger +function nbi() { return new BigInteger(null); } + +// am: Compute w_j += (x*this_i), propagate carries, +// c is initial carry, returns final carry. +// c < 3*dvalue, x < 2*dvalue, this_i < dvalue +// We need to select the fastest one that works in this environment. + +// am1: use a single mult and divide to get the high bits, +// max digit bits should be 26 because +// max internal value = 2*dvalue^2-2*dvalue (< 2^53) +function am1(i,x,w,j,c,n) { + var this_array = this.array; + var w_array = w.array; + while(--n >= 0) { + var v = x*this_array[i++]+w_array[j]+c; + c = Math.floor(v/0x4000000); + w_array[j++] = v&0x3ffffff; + } + return c; +} + +// am2 avoids a big mult-and-extract completely. +// Max digit bits should be <= 30 because we do bitwise ops +// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) +function am2(i,x,w,j,c,n) { + var this_array = this.array; + var w_array = w.array; + var xl = x&0x7fff, xh = x>>15; + while(--n >= 0) { + var l = this_array[i]&0x7fff; + var h = this_array[i++]>>15; + var m = xh*l+h*xl; + l = xl*l+((m&0x7fff)<<15)+w_array[j]+(c&0x3fffffff); + c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); + w_array[j++] = l&0x3fffffff; + } + return c; +} + +// Alternately, set max digit bits to 28 since some +// browsers slow down when dealing with 32-bit numbers. +function am3(i,x,w,j,c,n) { + var this_array = this.array; + var w_array = w.array; + + var xl = x&0x3fff, xh = x>>14; + while(--n >= 0) { + var l = this_array[i]&0x3fff; + var h = this_array[i++]>>14; + var m = xh*l+h*xl; + l = xl*l+((m&0x3fff)<<14)+w_array[j]+c; + c = (l>>28)+(m>>14)+xh*h; + w_array[j++] = l&0xfffffff; + } + return c; +} + +// This is tailored to VMs with 2-bit tagging. It makes sure +// that all the computations stay within the 29 bits available. +function am4(i,x,w,j,c,n) { + var this_array = this.array; + var w_array = w.array; + + var xl = x&0x1fff, xh = x>>13; + while(--n >= 0) { + var l = this_array[i]&0x1fff; + var h = this_array[i++]>>13; + var m = xh*l+h*xl; + l = xl*l+((m&0x1fff)<<13)+w_array[j]+c; + c = (l>>26)+(m>>13)+xh*h; + w_array[j++] = l&0x3ffffff; + } + return c; +} + +// am3/28 is best for SM, Rhino, but am4/26 is best for v8. +// Kestrel (Opera 9.5) gets its best result with am4/26. +// IE7 does 9% better with am3/28 than with am4/26. +// Firefox (SM) gets 10% faster with am3/28 than with am4/26. + +setupEngine = function(fn, bits) { + BigInteger.prototype.am = fn; + dbits = bits; + + BI_DB = dbits; + BI_DM = ((1<= 0; --i) r_array[i] = this_array[i]; + r.t = this.t; + r.s = this.s; +} + +// (protected) set from integer value x, -DV <= x < DV +function bnpFromInt(x) { + var this_array = this.array; + this.t = 1; + this.s = (x<0)?-1:0; + if(x > 0) this_array[0] = x; + else if(x < -1) this_array[0] = x+DV; + else this.t = 0; +} + +// return bigint initialized to value +function nbv(i) { var r = nbi(); r.fromInt(i); return r; } + +// (protected) set from string and radix +function bnpFromString(s,b) { + var this_array = this.array; + var k; + if(b == 16) k = 4; + else if(b == 8) k = 3; + else if(b == 256) k = 8; // byte array + else if(b == 2) k = 1; + else if(b == 32) k = 5; + else if(b == 4) k = 2; + else { this.fromRadix(s,b); return; } + this.t = 0; + this.s = 0; + var i = s.length, mi = false, sh = 0; + while(--i >= 0) { + var x = (k==8)?s[i]&0xff:intAt(s,i); + if(x < 0) { + if(s.charAt(i) == "-") mi = true; + continue; + } + mi = false; + if(sh == 0) + this_array[this.t++] = x; + else if(sh+k > BI_DB) { + this_array[this.t-1] |= (x&((1<<(BI_DB-sh))-1))<>(BI_DB-sh)); + } + else + this_array[this.t-1] |= x<= BI_DB) sh -= BI_DB; + } + if(k == 8 && (s[0]&0x80) != 0) { + this.s = -1; + if(sh > 0) this_array[this.t-1] |= ((1<<(BI_DB-sh))-1)< 0 && this_array[this.t-1] == c) --this.t; +} + +// (public) return string representation in given radix +function bnToString(b) { + var this_array = this.array; + if(this.s < 0) return "-"+this.negate().toString(b); + var k; + if(b == 16) k = 4; + else if(b == 8) k = 3; + else if(b == 2) k = 1; + else if(b == 32) k = 5; + else if(b == 4) k = 2; + else return this.toRadix(b); + var km = (1< 0) { + if(p < BI_DB && (d = this_array[i]>>p) > 0) { m = true; r = int2char(d); } + while(i >= 0) { + if(p < k) { + d = (this_array[i]&((1<>(p+=BI_DB-k); + } + else { + d = (this_array[i]>>(p-=k))&km; + if(p <= 0) { p += BI_DB; --i; } + } + if(d > 0) m = true; + if(m) r += int2char(d); + } + } + return m?r:"0"; +} + +// (public) -this +function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; } + +// (public) |this| +function bnAbs() { return (this.s<0)?this.negate():this; } + +// (public) return + if this > a, - if this < a, 0 if equal +function bnCompareTo(a) { + var this_array = this.array; + var a_array = a.array; + + var r = this.s-a.s; + if(r != 0) return r; + var i = this.t; + r = i-a.t; + if(r != 0) return r; + while(--i >= 0) if((r=this_array[i]-a_array[i]) != 0) return r; + return 0; +} + +// returns bit length of the integer x +function nbits(x) { + var r = 1, t; + if((t=x>>>16) != 0) { x = t; r += 16; } + if((t=x>>8) != 0) { x = t; r += 8; } + if((t=x>>4) != 0) { x = t; r += 4; } + if((t=x>>2) != 0) { x = t; r += 2; } + if((t=x>>1) != 0) { x = t; r += 1; } + return r; +} + +// (public) return the number of bits in "this" +function bnBitLength() { + var this_array = this.array; + if(this.t <= 0) return 0; + return BI_DB*(this.t-1)+nbits(this_array[this.t-1]^(this.s&BI_DM)); +} + +// (protected) r = this << n*DB +function bnpDLShiftTo(n,r) { + var this_array = this.array; + var r_array = r.array; + var i; + for(i = this.t-1; i >= 0; --i) r_array[i+n] = this_array[i]; + for(i = n-1; i >= 0; --i) r_array[i] = 0; + r.t = this.t+n; + r.s = this.s; +} + +// (protected) r = this >> n*DB +function bnpDRShiftTo(n,r) { + var this_array = this.array; + var r_array = r.array; + for(var i = n; i < this.t; ++i) r_array[i-n] = this_array[i]; + r.t = Math.max(this.t-n,0); + r.s = this.s; +} + +// (protected) r = this << n +function bnpLShiftTo(n,r) { + var this_array = this.array; + var r_array = r.array; + var bs = n%BI_DB; + var cbs = BI_DB-bs; + var bm = (1<= 0; --i) { + r_array[i+ds+1] = (this_array[i]>>cbs)|c; + c = (this_array[i]&bm)<= 0; --i) r_array[i] = 0; + r_array[ds] = c; + r.t = this.t+ds+1; + r.s = this.s; + r.clamp(); +} + +// (protected) r = this >> n +function bnpRShiftTo(n,r) { + var this_array = this.array; + var r_array = r.array; + r.s = this.s; + var ds = Math.floor(n/BI_DB); + if(ds >= this.t) { r.t = 0; return; } + var bs = n%BI_DB; + var cbs = BI_DB-bs; + var bm = (1<>bs; + for(var i = ds+1; i < this.t; ++i) { + r_array[i-ds-1] |= (this_array[i]&bm)<>bs; + } + if(bs > 0) r_array[this.t-ds-1] |= (this.s&bm)<>= BI_DB; + } + if(a.t < this.t) { + c -= a.s; + while(i < this.t) { + c += this_array[i]; + r_array[i++] = c&BI_DM; + c >>= BI_DB; + } + c += this.s; + } + else { + c += this.s; + while(i < a.t) { + c -= a_array[i]; + r_array[i++] = c&BI_DM; + c >>= BI_DB; + } + c -= a.s; + } + r.s = (c<0)?-1:0; + if(c < -1) r_array[i++] = BI_DV+c; + else if(c > 0) r_array[i++] = c; + r.t = i; + r.clamp(); +} + +// (protected) r = this * a, r != this,a (HAC 14.12) +// "this" should be the larger one if appropriate. +function bnpMultiplyTo(a,r) { + var this_array = this.array; + var r_array = r.array; + var x = this.abs(), y = a.abs(); + var y_array = y.array; + + var i = x.t; + r.t = i+y.t; + while(--i >= 0) r_array[i] = 0; + for(i = 0; i < y.t; ++i) r_array[i+x.t] = x.am(0,y_array[i],r,i,0,x.t); + r.s = 0; + r.clamp(); + if(this.s != a.s) BigInteger.ZERO.subTo(r,r); +} + +// (protected) r = this^2, r != this (HAC 14.16) +function bnpSquareTo(r) { + var x = this.abs(); + var x_array = x.array; + var r_array = r.array; + + var i = r.t = 2*x.t; + while(--i >= 0) r_array[i] = 0; + for(i = 0; i < x.t-1; ++i) { + var c = x.am(i,x_array[i],r,2*i,0,1); + if((r_array[i+x.t]+=x.am(i+1,2*x_array[i],r,2*i+1,c,x.t-i-1)) >= BI_DV) { + r_array[i+x.t] -= BI_DV; + r_array[i+x.t+1] = 1; + } + } + if(r.t > 0) r_array[r.t-1] += x.am(i,x_array[i],r,2*i,0,1); + r.s = 0; + r.clamp(); +} + +// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) +// r != q, this != m. q or r may be null. +function bnpDivRemTo(m,q,r) { + var pm = m.abs(); + if(pm.t <= 0) return; + var pt = this.abs(); + if(pt.t < pm.t) { + if(q != null) q.fromInt(0); + if(r != null) this.copyTo(r); + return; + } + if(r == null) r = nbi(); + var y = nbi(), ts = this.s, ms = m.s; + var pm_array = pm.array; + var nsh = BI_DB-nbits(pm_array[pm.t-1]); // normalize modulus + if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } + else { pm.copyTo(y); pt.copyTo(r); } + var ys = y.t; + + var y_array = y.array; + var y0 = y_array[ys-1]; + if(y0 == 0) return; + var yt = y0*(1<1)?y_array[ys-2]>>BI_F2:0); + var d1 = BI_FV/yt, d2 = (1<= 0) { + r_array[r.t++] = 1; + r.subTo(t,r); + } + BigInteger.ONE.dlShiftTo(ys,t); + t.subTo(y,y); // "negative" y so we can replace sub with am later + while(y.t < ys) y_array[y.t++] = 0; + while(--j >= 0) { + // Estimate quotient digit + var qd = (r_array[--i]==y0)?BI_DM:Math.floor(r_array[i]*d1+(r_array[i-1]+e)*d2); + if((r_array[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out + y.dlShiftTo(j,t); + r.subTo(t,r); + while(r_array[i] < --qd) r.subTo(t,r); + } + } + if(q != null) { + r.drShiftTo(ys,q); + if(ts != ms) BigInteger.ZERO.subTo(q,q); + } + r.t = ys; + r.clamp(); + if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder + if(ts < 0) BigInteger.ZERO.subTo(r,r); +} + +// (public) this mod a +function bnMod(a) { + var r = nbi(); + this.abs().divRemTo(a,null,r); + if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r); + return r; +} + +// Modular reduction using "classic" algorithm +function Classic(m) { this.m = m; } +function cConvert(x) { + if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); + else return x; +} +function cRevert(x) { return x; } +function cReduce(x) { x.divRemTo(this.m,null,x); } +function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } +function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +Classic.prototype.convert = cConvert; +Classic.prototype.revert = cRevert; +Classic.prototype.reduce = cReduce; +Classic.prototype.mulTo = cMulTo; +Classic.prototype.sqrTo = cSqrTo; + +// (protected) return "-1/this % 2^DB"; useful for Mont. reduction +// justification: +// xy == 1 (mod m) +// xy = 1+km +// xy(2-xy) = (1+km)(1-km) +// x[y(2-xy)] = 1-k^2m^2 +// x[y(2-xy)] == 1 (mod m^2) +// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 +// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. +// JS multiply "overflows" differently from C/C++, so care is needed here. +function bnpInvDigit() { + var this_array = this.array; + if(this.t < 1) return 0; + var x = this_array[0]; + if((x&1) == 0) return 0; + var y = x&3; // y == 1/x mod 2^2 + y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 + y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 + y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 + // last step - calculate inverse mod DV directly; + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints + y = (y*(2-x*y%BI_DV))%BI_DV; // y == 1/x mod 2^dbits + // we really want the negative inverse, and -DV < y < DV + return (y>0)?BI_DV-y:-y; +} + +// Montgomery reduction +function Montgomery(m) { + this.m = m; + this.mp = m.invDigit(); + this.mpl = this.mp&0x7fff; + this.mph = this.mp>>15; + this.um = (1<<(BI_DB-15))-1; + this.mt2 = 2*m.t; +} + +// xR mod m +function montConvert(x) { + var r = nbi(); + x.abs().dlShiftTo(this.m.t,r); + r.divRemTo(this.m,null,r); + if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r); + return r; +} + +// x/R mod m +function montRevert(x) { + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; +} + +// x = x/R mod m (HAC 14.32) +function montReduce(x) { + var x_array = x.array; + while(x.t <= this.mt2) // pad x so am has enough room later + x_array[x.t++] = 0; + for(var i = 0; i < this.m.t; ++i) { + // faster way of calculating u0 = x[i]*mp mod DV + var j = x_array[i]&0x7fff; + var u0 = (j*this.mpl+(((j*this.mph+(x_array[i]>>15)*this.mpl)&this.um)<<15))&BI_DM; + // use am to combine the multiply-shift-add into one call + j = i+this.m.t; + x_array[j] += this.m.am(0,u0,x,i,0,this.m.t); + // propagate carry + while(x_array[j] >= BI_DV) { x_array[j] -= BI_DV; x_array[++j]++; } + } + x.clamp(); + x.drShiftTo(this.m.t,x); + if(x.compareTo(this.m) >= 0) x.subTo(this.m,x); +} + +// r = "x^2/R mod m"; x != r +function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +// r = "xy/R mod m"; x,y != r +function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + +Montgomery.prototype.convert = montConvert; +Montgomery.prototype.revert = montRevert; +Montgomery.prototype.reduce = montReduce; +Montgomery.prototype.mulTo = montMulTo; +Montgomery.prototype.sqrTo = montSqrTo; + +// (protected) true iff this is even +function bnpIsEven() { + var this_array = this.array; + return ((this.t>0)?(this_array[0]&1):this.s) == 0; +} + +// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) +function bnpExp(e,z) { + if(e > 0xffffffff || e < 1) return BigInteger.ONE; + var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; + g.copyTo(r); + while(--i >= 0) { + z.sqrTo(r,r2); + if((e&(1< 0) z.mulTo(r2,g,r); + else { var t = r; r = r2; r2 = t; } + } + return z.revert(r); +} + +// (public) this^e % m, 0 <= e < 2^32 +function bnModPowInt(e,m) { + var z; + if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); + return this.exp(e,z); +} + +// protected +BigInteger.prototype.copyTo = bnpCopyTo; +BigInteger.prototype.fromInt = bnpFromInt; +BigInteger.prototype.fromString = bnpFromString; +BigInteger.prototype.clamp = bnpClamp; +BigInteger.prototype.dlShiftTo = bnpDLShiftTo; +BigInteger.prototype.drShiftTo = bnpDRShiftTo; +BigInteger.prototype.lShiftTo = bnpLShiftTo; +BigInteger.prototype.rShiftTo = bnpRShiftTo; +BigInteger.prototype.subTo = bnpSubTo; +BigInteger.prototype.multiplyTo = bnpMultiplyTo; +BigInteger.prototype.squareTo = bnpSquareTo; +BigInteger.prototype.divRemTo = bnpDivRemTo; +BigInteger.prototype.invDigit = bnpInvDigit; +BigInteger.prototype.isEven = bnpIsEven; +BigInteger.prototype.exp = bnpExp; + +// public +BigInteger.prototype.toString = bnToString; +BigInteger.prototype.negate = bnNegate; +BigInteger.prototype.abs = bnAbs; +BigInteger.prototype.compareTo = bnCompareTo; +BigInteger.prototype.bitLength = bnBitLength; +BigInteger.prototype.mod = bnMod; +BigInteger.prototype.modPowInt = bnModPowInt; + +// "constants" +BigInteger.ZERO = nbv(0); +BigInteger.ONE = nbv(1); +// Copyright (c) 2005 Tom Wu +// All Rights Reserved. +// See "LICENSE" for details. + +// Extended JavaScript BN functions, required for RSA private ops. + +// (public) +function bnClone() { var r = nbi(); this.copyTo(r); return r; } + +// (public) return value as integer +function bnIntValue() { + var this_array = this.array; + if(this.s < 0) { + if(this.t == 1) return this_array[0]-BI_DV; + else if(this.t == 0) return -1; + } + else if(this.t == 1) return this_array[0]; + else if(this.t == 0) return 0; + // assumes 16 < DB < 32 + return ((this_array[1]&((1<<(32-BI_DB))-1))<>24; +} + +// (public) return value as short (assumes DB>=16) +function bnShortValue() { + var this_array = this.array; + return (this.t==0)?this.s:(this_array[0]<<16)>>16; +} + +// (protected) return x s.t. r^x < DV +function bnpChunkSize(r) { return Math.floor(Math.LN2*BI_DB/Math.log(r)); } + +// (public) 0 if this == 0, 1 if this > 0 +function bnSigNum() { + var this_array = this.array; + if(this.s < 0) return -1; + else if(this.t <= 0 || (this.t == 1 && this_array[0] <= 0)) return 0; + else return 1; +} + +// (protected) convert to radix string +function bnpToRadix(b) { + if(b == null) b = 10; + if(this.signum() == 0 || b < 2 || b > 36) return "0"; + var cs = this.chunkSize(b); + var a = Math.pow(b,cs); + var d = nbv(a), y = nbi(), z = nbi(), r = ""; + this.divRemTo(d,y,z); + while(y.signum() > 0) { + r = (a+z.intValue()).toString(b).substr(1) + r; + y.divRemTo(d,y,z); + } + return z.intValue().toString(b) + r; +} + +// (protected) convert from radix string +function bnpFromRadix(s,b) { + this.fromInt(0); + if(b == null) b = 10; + var cs = this.chunkSize(b); + var d = Math.pow(b,cs), mi = false, j = 0, w = 0; + for(var i = 0; i < s.length; ++i) { + var x = intAt(s,i); + if(x < 0) { + if(s.charAt(i) == "-" && this.signum() == 0) mi = true; + continue; + } + w = b*w+x; + if(++j >= cs) { + this.dMultiply(d); + this.dAddOffset(w,0); + j = 0; + w = 0; + } + } + if(j > 0) { + this.dMultiply(Math.pow(b,j)); + this.dAddOffset(w,0); + } + if(mi) BigInteger.ZERO.subTo(this,this); +} + +// (protected) alternate constructor +function bnpFromNumber(a,b,c) { + if("number" == typeof b) { + // new BigInteger(int,int,RNG) + if(a < 2) this.fromInt(1); + else { + this.fromNumber(a,c); + if(!this.testBit(a-1)) // force MSB set + this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this); + if(this.isEven()) this.dAddOffset(1,0); // force odd + while(!this.isProbablePrime(b)) { + this.dAddOffset(2,0); + if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this); + } + } + } + else { + // new BigInteger(int,RNG) + var x = new Array(), t = a&7; + x.length = (a>>3)+1; + b.nextBytes(x); + if(t > 0) x[0] &= ((1< 0) { + if(p < BI_DB && (d = this_array[i]>>p) != (this.s&BI_DM)>>p) + r[k++] = d|(this.s<<(BI_DB-p)); + while(i >= 0) { + if(p < 8) { + d = (this_array[i]&((1<>(p+=BI_DB-8); + } + else { + d = (this_array[i]>>(p-=8))&0xff; + if(p <= 0) { p += BI_DB; --i; } + } + if((d&0x80) != 0) d |= -256; + if(k == 0 && (this.s&0x80) != (d&0x80)) ++k; + if(k > 0 || d != this.s) r[k++] = d; + } + } + return r; +} + +function bnEquals(a) { return(this.compareTo(a)==0); } +function bnMin(a) { return(this.compareTo(a)<0)?this:a; } +function bnMax(a) { return(this.compareTo(a)>0)?this:a; } + +// (protected) r = this op a (bitwise) +function bnpBitwiseTo(a,op,r) { + var this_array = this.array; + var a_array = a.array; + var r_array = r.array; + var i, f, m = Math.min(a.t,this.t); + for(i = 0; i < m; ++i) r_array[i] = op(this_array[i],a_array[i]); + if(a.t < this.t) { + f = a.s&BI_DM; + for(i = m; i < this.t; ++i) r_array[i] = op(this_array[i],f); + r.t = this.t; + } + else { + f = this.s&BI_DM; + for(i = m; i < a.t; ++i) r_array[i] = op(f,a_array[i]); + r.t = a.t; + } + r.s = op(this.s,a.s); + r.clamp(); +} + +// (public) this & a +function op_and(x,y) { return x&y; } +function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; } + +// (public) this | a +function op_or(x,y) { return x|y; } +function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; } + +// (public) this ^ a +function op_xor(x,y) { return x^y; } +function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; } + +// (public) this & ~a +function op_andnot(x,y) { return x&~y; } +function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; } + +// (public) ~this +function bnNot() { + var this_array = this.array; + var r = nbi(); + var r_array = r.array; + + for(var i = 0; i < this.t; ++i) r_array[i] = BI_DM&~this_array[i]; + r.t = this.t; + r.s = ~this.s; + return r; +} + +// (public) this << n +function bnShiftLeft(n) { + var r = nbi(); + if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r); + return r; +} + +// (public) this >> n +function bnShiftRight(n) { + var r = nbi(); + if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r); + return r; +} + +// return index of lowest 1-bit in x, x < 2^31 +function lbit(x) { + if(x == 0) return -1; + var r = 0; + if((x&0xffff) == 0) { x >>= 16; r += 16; } + if((x&0xff) == 0) { x >>= 8; r += 8; } + if((x&0xf) == 0) { x >>= 4; r += 4; } + if((x&3) == 0) { x >>= 2; r += 2; } + if((x&1) == 0) ++r; + return r; +} + +// (public) returns index of lowest 1-bit (or -1 if none) +function bnGetLowestSetBit() { + var this_array = this.array; + for(var i = 0; i < this.t; ++i) + if(this_array[i] != 0) return i*BI_DB+lbit(this_array[i]); + if(this.s < 0) return this.t*BI_DB; + return -1; +} + +// return number of 1 bits in x +function cbit(x) { + var r = 0; + while(x != 0) { x &= x-1; ++r; } + return r; +} + +// (public) return number of set bits +function bnBitCount() { + var r = 0, x = this.s&BI_DM; + for(var i = 0; i < this.t; ++i) r += cbit(this_array[i]^x); + return r; +} + +// (public) true iff nth bit is set +function bnTestBit(n) { + var this_array = this.array; + var j = Math.floor(n/BI_DB); + if(j >= this.t) return(this.s!=0); + return((this_array[j]&(1<<(n%BI_DB)))!=0); +} + +// (protected) this op (1<>= BI_DB; + } + if(a.t < this.t) { + c += a.s; + while(i < this.t) { + c += this_array[i]; + r_array[i++] = c&BI_DM; + c >>= BI_DB; + } + c += this.s; + } + else { + c += this.s; + while(i < a.t) { + c += a_array[i]; + r_array[i++] = c&BI_DM; + c >>= BI_DB; + } + c += a.s; + } + r.s = (c<0)?-1:0; + if(c > 0) r_array[i++] = c; + else if(c < -1) r_array[i++] = BI_DV+c; + r.t = i; + r.clamp(); +} + +// (public) this + a +function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; } + +// (public) this - a +function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; } + +// (public) this * a +function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; } + +// (public) this / a +function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; } + +// (public) this % a +function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; } + +// (public) [this/a,this%a] +function bnDivideAndRemainder(a) { + var q = nbi(), r = nbi(); + this.divRemTo(a,q,r); + return new Array(q,r); +} + +// (protected) this *= n, this >= 0, 1 < n < DV +function bnpDMultiply(n) { + var this_array = this.array; + this_array[this.t] = this.am(0,n-1,this,0,0,this.t); + ++this.t; + this.clamp(); +} + +// (protected) this += n << w words, this >= 0 +function bnpDAddOffset(n,w) { + var this_array = this.array; + while(this.t <= w) this_array[this.t++] = 0; + this_array[w] += n; + while(this_array[w] >= BI_DV) { + this_array[w] -= BI_DV; + if(++w >= this.t) this_array[this.t++] = 0; + ++this_array[w]; + } +} + +// A "null" reducer +function NullExp() {} +function nNop(x) { return x; } +function nMulTo(x,y,r) { x.multiplyTo(y,r); } +function nSqrTo(x,r) { x.squareTo(r); } + +NullExp.prototype.convert = nNop; +NullExp.prototype.revert = nNop; +NullExp.prototype.mulTo = nMulTo; +NullExp.prototype.sqrTo = nSqrTo; + +// (public) this^e +function bnPow(e) { return this.exp(e,new NullExp()); } + +// (protected) r = lower n words of "this * a", a.t <= n +// "this" should be the larger one if appropriate. +function bnpMultiplyLowerTo(a,n,r) { + var r_array = r.array; + var a_array = a.array; + var i = Math.min(this.t+a.t,n); + r.s = 0; // assumes a,this >= 0 + r.t = i; + while(i > 0) r_array[--i] = 0; + var j; + for(j = r.t-this.t; i < j; ++i) r_array[i+this.t] = this.am(0,a_array[i],r,i,0,this.t); + for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a_array[i],r,i,0,n-i); + r.clamp(); +} + +// (protected) r = "this * a" without lower n words, n > 0 +// "this" should be the larger one if appropriate. +function bnpMultiplyUpperTo(a,n,r) { + var r_array = r.array; + var a_array = a.array; + --n; + var i = r.t = this.t+a.t-n; + r.s = 0; // assumes a,this >= 0 + while(--i >= 0) r_array[i] = 0; + for(i = Math.max(n-this.t,0); i < a.t; ++i) + r_array[this.t+i-n] = this.am(n-i,a_array[i],r,0,0,this.t+i-n); + r.clamp(); + r.drShiftTo(1,r); +} + +// Barrett modular reduction +function Barrett(m) { + // setup Barrett + this.r2 = nbi(); + this.q3 = nbi(); + BigInteger.ONE.dlShiftTo(2*m.t,this.r2); + this.mu = this.r2.divide(m); + this.m = m; +} + +function barrettConvert(x) { + if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m); + else if(x.compareTo(this.m) < 0) return x; + else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } +} + +function barrettRevert(x) { return x; } + +// x = x mod m (HAC 14.42) +function barrettReduce(x) { + x.drShiftTo(this.m.t-1,this.r2); + if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); } + this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3); + this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2); + while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1); + x.subTo(this.r2,x); + while(x.compareTo(this.m) >= 0) x.subTo(this.m,x); +} + +// r = x^2 mod m; x != r +function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +// r = x*y mod m; x,y != r +function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + +Barrett.prototype.convert = barrettConvert; +Barrett.prototype.revert = barrettRevert; +Barrett.prototype.reduce = barrettReduce; +Barrett.prototype.mulTo = barrettMulTo; +Barrett.prototype.sqrTo = barrettSqrTo; + +// (public) this^e % m (HAC 14.85) +function bnModPow(e,m) { + var e_array = e.array; + var i = e.bitLength(), k, r = nbv(1), z; + if(i <= 0) return r; + else if(i < 18) k = 1; + else if(i < 48) k = 3; + else if(i < 144) k = 4; + else if(i < 768) k = 5; + else k = 6; + if(i < 8) + z = new Classic(m); + else if(m.isEven()) + z = new Barrett(m); + else + z = new Montgomery(m); + + // precomputation + var g = new Array(), n = 3, k1 = k-1, km = (1< 1) { + var g2 = nbi(); + z.sqrTo(g[1],g2); + while(n <= km) { + g[n] = nbi(); + z.mulTo(g2,g[n-2],g[n]); + n += 2; + } + } + + var j = e.t-1, w, is1 = true, r2 = nbi(), t; + i = nbits(e_array[j])-1; + while(j >= 0) { + if(i >= k1) w = (e_array[j]>>(i-k1))&km; + else { + w = (e_array[j]&((1<<(i+1))-1))<<(k1-i); + if(j > 0) w |= e_array[j-1]>>(BI_DB+i-k1); + } + + n = k; + while((w&1) == 0) { w >>= 1; --n; } + if((i -= n) < 0) { i += BI_DB; --j; } + if(is1) { // ret == 1, don't bother squaring or multiplying it + g[w].copyTo(r); + is1 = false; + } + else { + while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; } + if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; } + z.mulTo(r2,g[w],r); + } + + while(j >= 0 && (e_array[j]&(1< 0) { + x.rShiftTo(g,x); + y.rShiftTo(g,y); + } + while(x.signum() > 0) { + if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x); + if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y); + if(x.compareTo(y) >= 0) { + x.subTo(y,x); + x.rShiftTo(1,x); + } + else { + y.subTo(x,y); + y.rShiftTo(1,y); + } + } + if(g > 0) y.lShiftTo(g,y); + return y; +} + +// (protected) this % n, n < 2^26 +function bnpModInt(n) { + var this_array = this.array; + if(n <= 0) return 0; + var d = BI_DV%n, r = (this.s<0)?n-1:0; + if(this.t > 0) + if(d == 0) r = this_array[0]%n; + else for(var i = this.t-1; i >= 0; --i) r = (d*r+this_array[i])%n; + return r; +} + +// (public) 1/this % m (HAC 14.61) +function bnModInverse(m) { + var ac = m.isEven(); + if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO; + var u = m.clone(), v = this.clone(); + var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); + while(u.signum() != 0) { + while(u.isEven()) { + u.rShiftTo(1,u); + if(ac) { + if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); } + a.rShiftTo(1,a); + } + else if(!b.isEven()) b.subTo(m,b); + b.rShiftTo(1,b); + } + while(v.isEven()) { + v.rShiftTo(1,v); + if(ac) { + if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); } + c.rShiftTo(1,c); + } + else if(!d.isEven()) d.subTo(m,d); + d.rShiftTo(1,d); + } + if(u.compareTo(v) >= 0) { + u.subTo(v,u); + if(ac) a.subTo(c,a); + b.subTo(d,b); + } + else { + v.subTo(u,v); + if(ac) c.subTo(a,c); + d.subTo(b,d); + } + } + if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO; + if(d.compareTo(m) >= 0) return d.subtract(m); + if(d.signum() < 0) d.addTo(m,d); else return d; + if(d.signum() < 0) return d.add(m); else return d; +} + +var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509]; +var lplim = (1<<26)/lowprimes[lowprimes.length-1]; + +// (public) test primality with certainty >= 1-.5^t +function bnIsProbablePrime(t) { + var i, x = this.abs(); + var x_array = x.array; + if(x.t == 1 && x_array[0] <= lowprimes[lowprimes.length-1]) { + for(i = 0; i < lowprimes.length; ++i) + if(x_array[0] == lowprimes[i]) return true; + return false; + } + if(x.isEven()) return false; + i = 1; + while(i < lowprimes.length) { + var m = lowprimes[i], j = i+1; + while(j < lowprimes.length && m < lplim) m *= lowprimes[j++]; + m = x.modInt(m); + while(i < j) if(m%lowprimes[i++] == 0) return false; + } + return x.millerRabin(t); +} + +// (protected) true if probably prime (HAC 4.24, Miller-Rabin) +function bnpMillerRabin(t) { + var n1 = this.subtract(BigInteger.ONE); + var k = n1.getLowestSetBit(); + if(k <= 0) return false; + var r = n1.shiftRight(k); + t = (t+1)>>1; + if(t > lowprimes.length) t = lowprimes.length; + var a = nbi(); + for(var i = 0; i < t; ++i) { + a.fromInt(lowprimes[i]); + var y = a.modPow(r,this); + if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { + var j = 1; + while(j++ < k && y.compareTo(n1) != 0) { + y = y.modPowInt(2,this); + if(y.compareTo(BigInteger.ONE) == 0) return false; + } + if(y.compareTo(n1) != 0) return false; + } + } + return true; +} + +// protected +BigInteger.prototype.chunkSize = bnpChunkSize; +BigInteger.prototype.toRadix = bnpToRadix; +BigInteger.prototype.fromRadix = bnpFromRadix; +BigInteger.prototype.fromNumber = bnpFromNumber; +BigInteger.prototype.bitwiseTo = bnpBitwiseTo; +BigInteger.prototype.changeBit = bnpChangeBit; +BigInteger.prototype.addTo = bnpAddTo; +BigInteger.prototype.dMultiply = bnpDMultiply; +BigInteger.prototype.dAddOffset = bnpDAddOffset; +BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo; +BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo; +BigInteger.prototype.modInt = bnpModInt; +BigInteger.prototype.millerRabin = bnpMillerRabin; + +// public +BigInteger.prototype.clone = bnClone; +BigInteger.prototype.intValue = bnIntValue; +BigInteger.prototype.byteValue = bnByteValue; +BigInteger.prototype.shortValue = bnShortValue; +BigInteger.prototype.signum = bnSigNum; +BigInteger.prototype.toByteArray = bnToByteArray; +BigInteger.prototype.equals = bnEquals; +BigInteger.prototype.min = bnMin; +BigInteger.prototype.max = bnMax; +BigInteger.prototype.and = bnAnd; +BigInteger.prototype.or = bnOr; +BigInteger.prototype.xor = bnXor; +BigInteger.prototype.andNot = bnAndNot; +BigInteger.prototype.not = bnNot; +BigInteger.prototype.shiftLeft = bnShiftLeft; +BigInteger.prototype.shiftRight = bnShiftRight; +BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit; +BigInteger.prototype.bitCount = bnBitCount; +BigInteger.prototype.testBit = bnTestBit; +BigInteger.prototype.setBit = bnSetBit; +BigInteger.prototype.clearBit = bnClearBit; +BigInteger.prototype.flipBit = bnFlipBit; +BigInteger.prototype.add = bnAdd; +BigInteger.prototype.subtract = bnSubtract; +BigInteger.prototype.multiply = bnMultiply; +BigInteger.prototype.divide = bnDivide; +BigInteger.prototype.remainder = bnRemainder; +BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder; +BigInteger.prototype.modPow = bnModPow; +BigInteger.prototype.modInverse = bnModInverse; +BigInteger.prototype.pow = bnPow; +BigInteger.prototype.gcd = bnGCD; +BigInteger.prototype.isProbablePrime = bnIsProbablePrime; + +// BigInteger interfaces not implemented in jsbn: + +// BigInteger(int signum, byte[] magnitude) +// double doubleValue() +// float floatValue() +// int hashCode() +// long longValue() +// static BigInteger valueOf(long val) +// prng4.js - uses Arcfour as a PRNG + +function Arcfour() { + this.i = 0; + this.j = 0; + this.S = new Array(); +} + +// Initialize arcfour context from key, an array of ints, each from [0..255] +function ARC4init(key) { + var i, j, t; + for(i = 0; i < 256; ++i) + this.S[i] = i; + j = 0; + for(i = 0; i < 256; ++i) { + j = (j + this.S[i] + key[i % key.length]) & 255; + t = this.S[i]; + this.S[i] = this.S[j]; + this.S[j] = t; + } + this.i = 0; + this.j = 0; +} + +function ARC4next() { + var t; + this.i = (this.i + 1) & 255; + this.j = (this.j + this.S[this.i]) & 255; + t = this.S[this.i]; + this.S[this.i] = this.S[this.j]; + this.S[this.j] = t; + return this.S[(t + this.S[this.i]) & 255]; +} + +Arcfour.prototype.init = ARC4init; +Arcfour.prototype.next = ARC4next; + +// Plug in your RNG constructor here +function prng_newstate() { + return new Arcfour(); +} + +// Pool size must be a multiple of 4 and greater than 32. +// An array of bytes the size of the pool will be passed to init() +var rng_psize = 256; +// Random number generator - requires a PRNG backend, e.g. prng4.js + +// For best results, put code like +// +// in your main HTML document. + +var rng_state; +var rng_pool; +var rng_pptr; + +// Mix in a 32-bit integer into the pool +function rng_seed_int(x) { + rng_pool[rng_pptr++] ^= x & 255; + rng_pool[rng_pptr++] ^= (x >> 8) & 255; + rng_pool[rng_pptr++] ^= (x >> 16) & 255; + rng_pool[rng_pptr++] ^= (x >> 24) & 255; + if(rng_pptr >= rng_psize) rng_pptr -= rng_psize; +} + +// Mix in the current time (w/milliseconds) into the pool +function rng_seed_time() { + // Use pre-computed date to avoid making the benchmark + // results dependent on the current date. + rng_seed_int(1122926989487); +} + +// Initialize the pool with junk if needed. +if(rng_pool == null) { + rng_pool = new Array(); + rng_pptr = 0; + var t; + while(rng_pptr < rng_psize) { // extract some randomness from Math.random() + t = Math.floor(65536 * MyMath.random()); + rng_pool[rng_pptr++] = t >>> 8; + rng_pool[rng_pptr++] = t & 255; + } + rng_pptr = 0; + rng_seed_time(); + //rng_seed_int(window.screenX); + //rng_seed_int(window.screenY); +} + +function rng_get_byte() { + if(rng_state == null) { + rng_seed_time(); + rng_state = prng_newstate(); + rng_state.init(rng_pool); + for(rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr) + rng_pool[rng_pptr] = 0; + rng_pptr = 0; + //rng_pool = null; + } + // TODO: allow reseeding after first request + return rng_state.next(); +} + +function rng_get_bytes(ba) { + var i; + for(i = 0; i < ba.length; ++i) ba[i] = rng_get_byte(); +} + +function SecureRandom() {} + +SecureRandom.prototype.nextBytes = rng_get_bytes; +// Depends on jsbn.js and rng.js + +// convert a (hex) string to a bignum object +function parseBigInt(str,r) { + return new BigInteger(str,r); +} + +function linebrk(s,n) { + var ret = ""; + var i = 0; + while(i + n < s.length) { + ret += s.substring(i,i+n) + "\n"; + i += n; + } + return ret + s.substring(i,s.length); +} + +function byte2Hex(b) { + if(b < 0x10) + return "0" + b.toString(16); + else + return b.toString(16); +} + +// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint +function pkcs1pad2(s,n) { + if(n < s.length + 11) { + alert("Message too long for RSA"); + return null; + } + var ba = new Array(); + var i = s.length - 1; + while(i >= 0 && n > 0) ba[--n] = s.charCodeAt(i--); + ba[--n] = 0; + var rng = new SecureRandom(); + var x = new Array(); + while(n > 2) { // random non-zero pad + x[0] = 0; + while(x[0] == 0) rng.nextBytes(x); + ba[--n] = x[0]; + } + ba[--n] = 2; + ba[--n] = 0; + return new BigInteger(ba); +} + +// "empty" RSA key constructor +function RSAKey() { + this.n = null; + this.e = 0; + this.d = null; + this.p = null; + this.q = null; + this.dmp1 = null; + this.dmq1 = null; + this.coeff = null; +} + +// Set the public key fields N and e from hex strings +function RSASetPublic(N,E) { + if(N != null && E != null && N.length > 0 && E.length > 0) { + this.n = parseBigInt(N,16); + this.e = parseInt(E,16); + } + else + alert("Invalid RSA public key"); +} + +// Perform raw public operation on "x": return x^e (mod n) +function RSADoPublic(x) { + return x.modPowInt(this.e, this.n); +} + +// Return the PKCS#1 RSA encryption of "text" as an even-length hex string +function RSAEncrypt(text) { + var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3); + if(m == null) return null; + var c = this.doPublic(m); + if(c == null) return null; + var h = c.toString(16); + if((h.length & 1) == 0) return h; else return "0" + h; +} + +// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string +//function RSAEncryptB64(text) { +// var h = this.encrypt(text); +// if(h) return hex2b64(h); else return null; +//} + +// protected +RSAKey.prototype.doPublic = RSADoPublic; + +// public +RSAKey.prototype.setPublic = RSASetPublic; +RSAKey.prototype.encrypt = RSAEncrypt; +//RSAKey.prototype.encrypt_b64 = RSAEncryptB64; +// Depends on rsa.js and jsbn2.js + +// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext +function pkcs1unpad2(d,n) { + var b = d.toByteArray(); + var i = 0; + while(i < b.length && b[i] == 0) ++i; + if(b.length-i != n-1 || b[i] != 2) + return null; + ++i; + while(b[i] != 0) + if(++i >= b.length) return null; + var ret = ""; + while(++i < b.length) + ret += String.fromCharCode(b[i]); + return ret; +} + +// Set the private key fields N, e, and d from hex strings +function RSASetPrivate(N,E,D) { + if(N != null && E != null && N.length > 0 && E.length > 0) { + this.n = parseBigInt(N,16); + this.e = parseInt(E,16); + this.d = parseBigInt(D,16); + } + else + alert("Invalid RSA private key"); +} + +// Set the private key fields N, e, d and CRT params from hex strings +function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) { + if(N != null && E != null && N.length > 0 && E.length > 0) { + this.n = parseBigInt(N,16); + this.e = parseInt(E,16); + this.d = parseBigInt(D,16); + this.p = parseBigInt(P,16); + this.q = parseBigInt(Q,16); + this.dmp1 = parseBigInt(DP,16); + this.dmq1 = parseBigInt(DQ,16); + this.coeff = parseBigInt(C,16); + } + else + alert("Invalid RSA private key"); +} + +// Generate a new random private key B bits long, using public expt E +function RSAGenerate(B,E) { + var rng = new SecureRandom(); + var qs = B>>1; + this.e = parseInt(E,16); + var ee = new BigInteger(E,16); + for(;;) { + for(;;) { + this.p = new BigInteger(B-qs,1,rng); + if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break; + } + for(;;) { + this.q = new BigInteger(qs,1,rng); + if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break; + } + if(this.p.compareTo(this.q) <= 0) { + var t = this.p; + this.p = this.q; + this.q = t; + } + var p1 = this.p.subtract(BigInteger.ONE); + var q1 = this.q.subtract(BigInteger.ONE); + var phi = p1.multiply(q1); + if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) { + this.n = this.p.multiply(this.q); + this.d = ee.modInverse(phi); + this.dmp1 = this.d.mod(p1); + this.dmq1 = this.d.mod(q1); + this.coeff = this.q.modInverse(this.p); + break; + } + } +} + +// Perform raw private operation on "x": return x^d (mod n) +function RSADoPrivate(x) { + if(this.p == null || this.q == null) + return x.modPow(this.d, this.n); + + // TODO: re-calculate any missing CRT params + var xp = x.mod(this.p).modPow(this.dmp1, this.p); + var xq = x.mod(this.q).modPow(this.dmq1, this.q); + + while(xp.compareTo(xq) < 0) + xp = xp.add(this.p); + return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq); +} + +// Return the PKCS#1 RSA decryption of "ctext". +// "ctext" is an even-length hex string and the output is a plain string. +function RSADecrypt(ctext) { + var c = parseBigInt(ctext, 16); + var m = this.doPrivate(c); + if(m == null) return null; + return pkcs1unpad2(m, (this.n.bitLength()+7)>>3); +} + +// Return the PKCS#1 RSA decryption of "ctext". +// "ctext" is a Base64-encoded string and the output is a plain string. +//function RSAB64Decrypt(ctext) { +// var h = b64tohex(ctext); +// if(h) return this.decrypt(h); else return null; +//} + +// protected +RSAKey.prototype.doPrivate = RSADoPrivate; + +// public +RSAKey.prototype.setPrivate = RSASetPrivate; +RSAKey.prototype.setPrivateEx = RSASetPrivateEx; +RSAKey.prototype.generate = RSAGenerate; +RSAKey.prototype.decrypt = RSADecrypt; +//RSAKey.prototype.b64_decrypt = RSAB64Decrypt; + + +nValue="a5261939975948bb7a58dffe5ff54e65f0498f9175f5a09288810b8975871e99af3b5dd94057b0fc07535f5f97444504fa35169d461d0d30cf0192e307727c065168c788771c561a9400fb49175e9e6aa4e23fe11af69e9412dd23b0cb6684c4c2429bce139e848ab26d0829073351f4acd36074eafd036a5eb83359d2a698d3"; +eValue="10001"; +dValue="8e9912f6d3645894e8d38cb58c0db81ff516cf4c7e5a14c7f1eddb1459d2cded4d8d293fc97aee6aefb861859c8b6a3d1dfe710463e1f9ddc72048c09751971c4a580aa51eb523357a3cc48d31cfad1d4a165066ed92d4748fb6571211da5cb14bc11b6e2df7c1a559e6d5ac1cd5c94703a22891464fba23d0d965086277a161"; +pValue="d090ce58a92c75233a6486cb0a9209bf3583b64f540c76f5294bb97d285eed33aec220bde14b2417951178ac152ceab6da7090905b478195498b352048f15e7d"; +qValue="cab575dc652bb66df15a0359609d51d1db184750c00c6698b90ef3465c99655103edbf0d54c56aec0ce3c4d22592338092a126a0cc49f65a4a30d222b411e58f"; +dmp1Value="1a24bca8e273df2f0e47c199bbf678604e7df7215480c77c8db39f49b000ce2cf7500038acfff5433b7d582a01f1826e6f4d42e1c57f5e1fef7b12aabc59fd25"; +dmq1Value="3d06982efbbe47339e1f6d36b1216b8a741d410b0c662f54f7118b27b9a4ec9d914337eb39841d8666f3034408cf94f5b62f11c402fc994fe15a05493150d9fd"; +coeffValue="3a3e731acd8960b7ff9eb81a7ff93bd1cfa74cbd56987db58b4594fb09c09084db1734c8143f98b602b981aaa9243ca28deb69b5b280ee8dcee0fd2625e53250"; + +setupEngine(am3, 28); + +// So that v8 understands assertEq() +if (assertEq == undefined) +{ + function assertEq(to_check, expected) { + if ( to_check !== expected ) + { + print( "Error: Assertion failed: got \"" + to_check + "\", expected \"" + expected + "\"" ); + } + } +} + +function check_correctness(text, hash) { + var RSA = new RSAKey(); + RSA.setPublic(nValue, eValue); + RSA.setPrivateEx(nValue, eValue, dValue, pValue, qValue, dmp1Value, dmq1Value, coeffValue); + var encrypted = RSA.encrypt(text); + var decrypted = RSA.decrypt(encrypted); + assertEq( encrypted, hash ); + assertEq( decrypted, text ); +} + +// All 'correct' hashes here come from v8's javascript shell built off of tag 2.3.4 +check_correctness("Hello! I am some text.", "142b19b40fee712ab9468be296447d38c7dfe81a7850f11ae6aa21e49396a4e90bd6ba4aa385105e15960a59f95447dfad89671da6e08ed42229939583753be84d07558abb4feee4d46a92fd31d962679a1a5f4bf0fb7af414b9a756e18df7e6d1e96971cc66769f3b27d61ad932f2211373e0de388dc040557d4c3c3fe74320"); +check_correctness("PLEASE ENCRYPT ME. I AM TEXT. I AM DIEING TO BE ENCRYPTED. OH WHY WONT YOU ENCRYPT ME!?", "490c1fae87d7046296e4b34b357912a72cb7c38c0da3198f1ac3aad3489662ce02663ec5ea1be58ae73a275f3096b16c491f3520ebf822df6c65cc95e28be1cc0a4454dfba3fdd402c3a9de0db2f308989bfc1a7fada0dd680db76d24b2d96bd6b7e7d7e7f962deb953038bae06092f7bb9bcb40bba4ec92e040df32f98e035e"); +check_correctness("x","46c1b7cf202171b1b588e9ecf250e768dcf3b300490e859d508f708e702ef799bc496b9fac7634d60a82644653c5fd25b808393b234567116b8890d5f119c7c74dae7c97c8e40ba78ca2dc3e3d78ce859a7fa3815f42c27d0607eafc3940896abb6019cc28b2ff875531ed581a6351728a8df0d607b7c2c26265bf3dddbe4f84"); diff --git a/js/src/jit-test/tests/v8-v5/check-deltablue.js b/js/src/jit-test/tests/v8-v5/check-deltablue.js new file mode 100644 index 0000000..ea12d39 --- /dev/null +++ b/js/src/jit-test/tests/v8-v5/check-deltablue.js @@ -0,0 +1,883 @@ +// Copyright 2008 the V8 project authors. All rights reserved. +// Copyright 1996 John Maloney and Mario Wolczko. + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +// This implementation of the DeltaBlue benchmark is derived +// from the Smalltalk implementation by John Maloney and Mario +// Wolczko. Some parts have been translated directly, whereas +// others have been modified more aggresively to make it feel +// more like a JavaScript program. + + +//var DeltaBlue = new BenchmarkSuite('DeltaBlue', 71104, [ +// new Benchmark('DeltaBlue', deltaBlue) +//]); + + +/** + * A JavaScript implementation of the DeltaBlue constrain-solving + * algorithm, as described in: + * + * "The DeltaBlue Algorithm: An Incremental Constraint Hierarchy Solver" + * Bjorn N. Freeman-Benson and John Maloney + * January 1990 Communications of the ACM, + * also available as University of Washington TR 89-08-06. + * + * Beware: this benchmark is written in a grotesque style where + * the constraint model is built by side-effects from constructors. + * I've kept it this way to avoid deviating too much from the original + * implementation. + */ + +function alert(msg) { + print(msg); + assertEq(false, true); +} + +/* --- O b j e c t M o d e l --- */ + +Object.prototype.inheritsFrom = function (shuper) { + function Inheriter() { } + Inheriter.prototype = shuper.prototype; + this.prototype = new Inheriter(); + this.superConstructor = shuper; +} + +function OrderedCollection() { + this.elms = new Array(); +} + +OrderedCollection.prototype.add = function (elm) { + this.elms.push(elm); +} + +OrderedCollection.prototype.at = function (index) { + return this.elms[index]; +} + +OrderedCollection.prototype.size = function () { + return this.elms.length; +} + +OrderedCollection.prototype.removeFirst = function () { + return this.elms.pop(); +} + +OrderedCollection.prototype.remove = function (elm) { + var index = 0, skipped = 0; + for (var i = 0; i < this.elms.length; i++) { + var value = this.elms[i]; + if (value != elm) { + this.elms[index] = value; + index++; + } else { + skipped++; + } + } + for (var i = 0; i < skipped; i++) + this.elms.pop(); +} + +/* --- * + * S t r e n g t h + * --- */ + +/** + * Strengths are used to measure the relative importance of constraints. + * New strengths may be inserted in the strength hierarchy without + * disrupting current constraints. Strengths cannot be created outside + * this class, so pointer comparison can be used for value comparison. + */ +function Strength(strengthValue, name) { + this.strengthValue = strengthValue; + this.name = name; +} + +Strength.stronger = function (s1, s2) { + return s1.strengthValue < s2.strengthValue; +} + +Strength.weaker = function (s1, s2) { + return s1.strengthValue > s2.strengthValue; +} + +Strength.weakestOf = function (s1, s2) { + return this.weaker(s1, s2) ? s1 : s2; +} + +Strength.strongest = function (s1, s2) { + return this.stronger(s1, s2) ? s1 : s2; +} + +Strength.prototype.nextWeaker = function () { + switch (this.strengthValue) { + case 0: return Strength.WEAKEST; + case 1: return Strength.WEAK_DEFAULT; + case 2: return Strength.NORMAL; + case 3: return Strength.STRONG_DEFAULT; + case 4: return Strength.PREFERRED; + case 5: return Strength.REQUIRED; + } +} + +// Strength constants. +Strength.REQUIRED = new Strength(0, "required"); +Strength.STONG_PREFERRED = new Strength(1, "strongPreferred"); +Strength.PREFERRED = new Strength(2, "preferred"); +Strength.STRONG_DEFAULT = new Strength(3, "strongDefault"); +Strength.NORMAL = new Strength(4, "normal"); +Strength.WEAK_DEFAULT = new Strength(5, "weakDefault"); +Strength.WEAKEST = new Strength(6, "weakest"); + +/* --- * + * C o n s t r a i n t + * --- */ + +/** + * An abstract class representing a system-maintainable relationship + * (or "constraint") between a set of variables. A constraint supplies + * a strength instance variable; concrete subclasses provide a means + * of storing the constrained variables and other information required + * to represent a constraint. + */ +function Constraint(strength) { + this.strength = strength; +} + +/** + * Activate this constraint and attempt to satisfy it. + */ +Constraint.prototype.addConstraint = function () { + this.addToGraph(); + planner.incrementalAdd(this); +} + +/** + * Attempt to find a way to enforce this constraint. If successful, + * record the solution, perhaps modifying the current dataflow + * graph. Answer the constraint that this constraint overrides, if + * there is one, or nil, if there isn't. + * Assume: I am not already satisfied. + */ +Constraint.prototype.satisfy = function (mark) { + this.chooseMethod(mark); + if (!this.isSatisfied()) { + if (this.strength == Strength.REQUIRED) + alert("Could not satisfy a required constraint!"); + return null; + } + this.markInputs(mark); + var out = this.output(); + var overridden = out.determinedBy; + if (overridden != null) overridden.markUnsatisfied(); + out.determinedBy = this; + if (!planner.addPropagate(this, mark)) + alert("Cycle encountered"); + out.mark = mark; + return overridden; +} + +Constraint.prototype.destroyConstraint = function () { + if (this.isSatisfied()) planner.incrementalRemove(this); + else this.removeFromGraph(); +} + +/** + * Normal constraints are not input constraints. An input constraint + * is one that depends on external state, such as the mouse, the + * keybord, a clock, or some arbitraty piece of imperative code. + */ +Constraint.prototype.isInput = function () { + return false; +} + +/* --- * + * U n a r y C o n s t r a i n t + * --- */ + +/** + * Abstract superclass for constraints having a single possible output + * variable. + */ +function UnaryConstraint(v, strength) { + UnaryConstraint.superConstructor.call(this, strength); + this.myOutput = v; + this.satisfied = false; + this.addConstraint(); +} + +UnaryConstraint.inheritsFrom(Constraint); + +/** + * Adds this constraint to the constraint graph + */ +UnaryConstraint.prototype.addToGraph = function () { + this.myOutput.addConstraint(this); + this.satisfied = false; +} + +/** + * Decides if this constraint can be satisfied and records that + * decision. + */ +UnaryConstraint.prototype.chooseMethod = function (mark) { + this.satisfied = (this.myOutput.mark != mark) + && Strength.stronger(this.strength, this.myOutput.walkStrength); +} + +/** + * Returns true if this constraint is satisfied in the current solution. + */ +UnaryConstraint.prototype.isSatisfied = function () { + return this.satisfied; +} + +UnaryConstraint.prototype.markInputs = function (mark) { + // has no inputs +} + +/** + * Returns the current output variable. + */ +UnaryConstraint.prototype.output = function () { + return this.myOutput; +} + +/** + * Calculate the walkabout strength, the stay flag, and, if it is + * 'stay', the value for the current output of this constraint. Assume + * this constraint is satisfied. + */ +UnaryConstraint.prototype.recalculate = function () { + this.myOutput.walkStrength = this.strength; + this.myOutput.stay = !this.isInput(); + if (this.myOutput.stay) this.execute(); // Stay optimization +} + +/** + * Records that this constraint is unsatisfied + */ +UnaryConstraint.prototype.markUnsatisfied = function () { + this.satisfied = false; +} + +UnaryConstraint.prototype.inputsKnown = function () { + return true; +} + +UnaryConstraint.prototype.removeFromGraph = function () { + if (this.myOutput != null) this.myOutput.removeConstraint(this); + this.satisfied = false; +} + +/* --- * + * S t a y C o n s t r a i n t + * --- */ + +/** + * Variables that should, with some level of preference, stay the same. + * Planners may exploit the fact that instances, if satisfied, will not + * change their output during plan execution. This is called "stay + * optimization". + */ +function StayConstraint(v, str) { + StayConstraint.superConstructor.call(this, v, str); +} + +StayConstraint.inheritsFrom(UnaryConstraint); + +StayConstraint.prototype.execute = function () { + // Stay constraints do nothing +} + +/* --- * + * E d i t C o n s t r a i n t + * --- */ + +/** + * A unary input constraint used to mark a variable that the client + * wishes to change. + */ +function EditConstraint(v, str) { + EditConstraint.superConstructor.call(this, v, str); +} + +EditConstraint.inheritsFrom(UnaryConstraint); + +/** + * Edits indicate that a variable is to be changed by imperative code. + */ +EditConstraint.prototype.isInput = function () { + return true; +} + +EditConstraint.prototype.execute = function () { + // Edit constraints do nothing +} + +/* --- * + * B i n a r y C o n s t r a i n t + * --- */ + +var Direction = new Object(); +Direction.NONE = 0; +Direction.FORWARD = 1; +Direction.BACKWARD = -1; + +/** + * Abstract superclass for constraints having two possible output + * variables. + */ +function BinaryConstraint(var1, var2, strength) { + BinaryConstraint.superConstructor.call(this, strength); + this.v1 = var1; + this.v2 = var2; + this.direction = Direction.NONE; + this.addConstraint(); +} + +BinaryConstraint.inheritsFrom(Constraint); + +/** + * Decides if this constratint can be satisfied and which way it + * should flow based on the relative strength of the variables related, + * and record that decision. + */ +BinaryConstraint.prototype.chooseMethod = function (mark) { + if (this.v1.mark == mark) { + this.direction = (this.v1.mark != mark && Strength.stronger(this.strength, this.v2.walkStrength)) + ? Direction.FORWARD + : Direction.NONE; + } + if (this.v2.mark == mark) { + this.direction = (this.v1.mark != mark && Strength.stronger(this.strength, this.v1.walkStrength)) + ? Direction.BACKWARD + : Direction.NONE; + } + if (Strength.weaker(this.v1.walkStrength, this.v2.walkStrength)) { + this.direction = Strength.stronger(this.strength, this.v1.walkStrength) + ? Direction.BACKWARD + : Direction.NONE; + } else { + this.direction = Strength.stronger(this.strength, this.v2.walkStrength) + ? Direction.FORWARD + : Direction.BACKWARD + } +} + +/** + * Add this constraint to the constraint graph + */ +BinaryConstraint.prototype.addToGraph = function () { + this.v1.addConstraint(this); + this.v2.addConstraint(this); + this.direction = Direction.NONE; +} + +/** + * Answer true if this constraint is satisfied in the current solution. + */ +BinaryConstraint.prototype.isSatisfied = function () { + return this.direction != Direction.NONE; +} + +/** + * Mark the input variable with the given mark. + */ +BinaryConstraint.prototype.markInputs = function (mark) { + this.input().mark = mark; +} + +/** + * Returns the current input variable + */ +BinaryConstraint.prototype.input = function () { + return (this.direction == Direction.FORWARD) ? this.v1 : this.v2; +} + +/** + * Returns the current output variable + */ +BinaryConstraint.prototype.output = function () { + return (this.direction == Direction.FORWARD) ? this.v2 : this.v1; +} + +/** + * Calculate the walkabout strength, the stay flag, and, if it is + * 'stay', the value for the current output of this + * constraint. Assume this constraint is satisfied. + */ +BinaryConstraint.prototype.recalculate = function () { + var ihn = this.input(), out = this.output(); + out.walkStrength = Strength.weakestOf(this.strength, ihn.walkStrength); + out.stay = ihn.stay; + if (out.stay) this.execute(); +} + +/** + * Record the fact that this constraint is unsatisfied. + */ +BinaryConstraint.prototype.markUnsatisfied = function () { + this.direction = Direction.NONE; +} + +BinaryConstraint.prototype.inputsKnown = function (mark) { + var i = this.input(); + return i.mark == mark || i.stay || i.determinedBy == null; +} + +BinaryConstraint.prototype.removeFromGraph = function () { + if (this.v1 != null) this.v1.removeConstraint(this); + if (this.v2 != null) this.v2.removeConstraint(this); + this.direction = Direction.NONE; +} + +/* --- * + * S c a l e C o n s t r a i n t + * --- */ + +/** + * Relates two variables by the linear scaling relationship: "v2 = + * (v1 * scale) + offset". Either v1 or v2 may be changed to maintain + * this relationship but the scale factor and offset are considered + * read-only. + */ +function ScaleConstraint(src, scale, offset, dest, strength) { + this.direction = Direction.NONE; + this.scale = scale; + this.offset = offset; + ScaleConstraint.superConstructor.call(this, src, dest, strength); +} + +ScaleConstraint.inheritsFrom(BinaryConstraint); + +/** + * Adds this constraint to the constraint graph. + */ +ScaleConstraint.prototype.addToGraph = function () { + ScaleConstraint.superConstructor.prototype.addToGraph.call(this); + this.scale.addConstraint(this); + this.offset.addConstraint(this); +} + +ScaleConstraint.prototype.removeFromGraph = function () { + ScaleConstraint.superConstructor.prototype.removeFromGraph.call(this); + if (this.scale != null) this.scale.removeConstraint(this); + if (this.offset != null) this.offset.removeConstraint(this); +} + +ScaleConstraint.prototype.markInputs = function (mark) { + ScaleConstraint.superConstructor.prototype.markInputs.call(this, mark); + this.scale.mark = this.offset.mark = mark; +} + +/** + * Enforce this constraint. Assume that it is satisfied. + */ +ScaleConstraint.prototype.execute = function () { + if (this.direction == Direction.FORWARD) { + this.v2.value = this.v1.value * this.scale.value + this.offset.value; + } else { + this.v1.value = (this.v2.value - this.offset.value) / this.scale.value; + } +} + +/** + * Calculate the walkabout strength, the stay flag, and, if it is + * 'stay', the value for the current output of this constraint. Assume + * this constraint is satisfied. + */ +ScaleConstraint.prototype.recalculate = function () { + var ihn = this.input(), out = this.output(); + out.walkStrength = Strength.weakestOf(this.strength, ihn.walkStrength); + out.stay = ihn.stay && this.scale.stay && this.offset.stay; + if (out.stay) this.execute(); +} + +/* --- * + * E q u a l i t y C o n s t r a i n t + * --- */ + +/** + * Constrains two variables to have the same value. + */ +function EqualityConstraint(var1, var2, strength) { + EqualityConstraint.superConstructor.call(this, var1, var2, strength); +} + +EqualityConstraint.inheritsFrom(BinaryConstraint); + +/** + * Enforce this constraint. Assume that it is satisfied. + */ +EqualityConstraint.prototype.execute = function () { + this.output().value = this.input().value; +} + +/* --- * + * V a r i a b l e + * --- */ + +/** + * A constrained variable. In addition to its value, it maintain the + * structure of the constraint graph, the current dataflow graph, and + * various parameters of interest to the DeltaBlue incremental + * constraint solver. + **/ +function Variable(name, initialValue) { + this.value = initialValue || 0; + this.constraints = new OrderedCollection(); + this.determinedBy = null; + this.mark = 0; + this.walkStrength = Strength.WEAKEST; + this.stay = true; + this.name = name; +} + +/** + * Add the given constraint to the set of all constraints that refer + * this variable. + */ +Variable.prototype.addConstraint = function (c) { + this.constraints.add(c); +} + +/** + * Removes all traces of c from this variable. + */ +Variable.prototype.removeConstraint = function (c) { + this.constraints.remove(c); + if (this.determinedBy == c) this.determinedBy = null; +} + +/* --- * + * P l a n n e r + * --- */ + +/** + * The DeltaBlue planner + */ +function Planner() { + this.currentMark = 0; +} + +/** + * Attempt to satisfy the given constraint and, if successful, + * incrementally update the dataflow graph. Details: If satifying + * the constraint is successful, it may override a weaker constraint + * on its output. The algorithm attempts to resatisfy that + * constraint using some other method. This process is repeated + * until either a) it reaches a variable that was not previously + * determined by any constraint or b) it reaches a constraint that + * is too weak to be satisfied using any of its methods. The + * variables of constraints that have been processed are marked with + * a unique mark value so that we know where we've been. This allows + * the algorithm to avoid getting into an infinite loop even if the + * constraint graph has an inadvertent cycle. + */ +Planner.prototype.incrementalAdd = function (c) { + var mark = this.newMark(); + var overridden = c.satisfy(mark); + while (overridden != null) + overridden = overridden.satisfy(mark); +} + +/** + * Entry point for retracting a constraint. Remove the given + * constraint and incrementally update the dataflow graph. + * Details: Retracting the given constraint may allow some currently + * unsatisfiable downstream constraint to be satisfied. We therefore collect + * a list of unsatisfied downstream constraints and attempt to + * satisfy each one in turn. This list is traversed by constraint + * strength, strongest first, as a heuristic for avoiding + * unnecessarily adding and then overriding weak constraints. + * Assume: c is satisfied. + */ +Planner.prototype.incrementalRemove = function (c) { + var out = c.output(); + c.markUnsatisfied(); + c.removeFromGraph(); + var unsatisfied = this.removePropagateFrom(out); + var strength = Strength.REQUIRED; + do { + for (var i = 0; i < unsatisfied.size(); i++) { + var u = unsatisfied.at(i); + if (u.strength == strength) + this.incrementalAdd(u); + } + strength = strength.nextWeaker(); + } while (strength != Strength.WEAKEST); +} + +/** + * Select a previously unused mark value. + */ +Planner.prototype.newMark = function () { + return ++this.currentMark; +} + +/** + * Extract a plan for resatisfaction starting from the given source + * constraints, usually a set of input constraints. This method + * assumes that stay optimization is desired; the plan will contain + * only constraints whose output variables are not stay. Constraints + * that do no computation, such as stay and edit constraints, are + * not included in the plan. + * Details: The outputs of a constraint are marked when it is added + * to the plan under construction. A constraint may be appended to + * the plan when all its input variables are known. A variable is + * known if either a) the variable is marked (indicating that has + * been computed by a constraint appearing earlier in the plan), b) + * the variable is 'stay' (i.e. it is a constant at plan execution + * time), or c) the variable is not determined by any + * constraint. The last provision is for past states of history + * variables, which are not stay but which are also not computed by + * any constraint. + * Assume: sources are all satisfied. + */ +Planner.prototype.makePlan = function (sources) { + var mark = this.newMark(); + var plan = new Plan(); + var todo = sources; + while (todo.size() > 0) { + var c = todo.removeFirst(); + if (c.output().mark != mark && c.inputsKnown(mark)) { + plan.addConstraint(c); + c.output().mark = mark; + this.addConstraintsConsumingTo(c.output(), todo); + } + } + return plan; +} + +/** + * Extract a plan for resatisfying starting from the output of the + * given constraints, usually a set of input constraints. + */ +Planner.prototype.extractPlanFromConstraints = function (constraints) { + var sources = new OrderedCollection(); + for (var i = 0; i < constraints.size(); i++) { + var c = constraints.at(i); + if (c.isInput() && c.isSatisfied()) + // not in plan already and eligible for inclusion + sources.add(c); + } + return this.makePlan(sources); +} + +/** + * Recompute the walkabout strengths and stay flags of all variables + * downstream of the given constraint and recompute the actual + * values of all variables whose stay flag is true. If a cycle is + * detected, remove the given constraint and answer + * false. Otherwise, answer true. + * Details: Cycles are detected when a marked variable is + * encountered downstream of the given constraint. The sender is + * assumed to have marked the inputs of the given constraint with + * the given mark. Thus, encountering a marked node downstream of + * the output constraint means that there is a path from the + * constraint's output to one of its inputs. + */ +Planner.prototype.addPropagate = function (c, mark) { + var todo = new OrderedCollection(); + todo.add(c); + while (todo.size() > 0) { + var d = todo.removeFirst(); + if (d.output().mark == mark) { + this.incrementalRemove(c); + return false; + } + d.recalculate(); + this.addConstraintsConsumingTo(d.output(), todo); + } + return true; +} + + +/** + * Update the walkabout strengths and stay flags of all variables + * downstream of the given constraint. Answer a collection of + * unsatisfied constraints sorted in order of decreasing strength. + */ +Planner.prototype.removePropagateFrom = function (out) { + out.determinedBy = null; + out.walkStrength = Strength.WEAKEST; + out.stay = true; + var unsatisfied = new OrderedCollection(); + var todo = new OrderedCollection(); + todo.add(out); + while (todo.size() > 0) { + var v = todo.removeFirst(); + for (var i = 0; i < v.constraints.size(); i++) { + var c = v.constraints.at(i); + if (!c.isSatisfied()) + unsatisfied.add(c); + } + var determining = v.determinedBy; + for (var i = 0; i < v.constraints.size(); i++) { + var next = v.constraints.at(i); + if (next != determining && next.isSatisfied()) { + next.recalculate(); + todo.add(next.output()); + } + } + } + return unsatisfied; +} + +Planner.prototype.addConstraintsConsumingTo = function (v, coll) { + var determining = v.determinedBy; + var cc = v.constraints; + for (var i = 0; i < cc.size(); i++) { + var c = cc.at(i); + if (c != determining && c.isSatisfied()) + coll.add(c); + } +} + +/* --- * + * P l a n + * --- */ + +/** + * A Plan is an ordered list of constraints to be executed in sequence + * to resatisfy all currently satisfiable constraints in the face of + * one or more changing inputs. + */ +function Plan() { + this.v = new OrderedCollection(); +} + +Plan.prototype.addConstraint = function (c) { + this.v.add(c); +} + +Plan.prototype.size = function () { + return this.v.size(); +} + +Plan.prototype.constraintAt = function (index) { + return this.v.at(index); +} + +Plan.prototype.execute = function () { + for (var i = 0; i < this.size(); i++) { + var c = this.constraintAt(i); + c.execute(); + } +} + +/* --- * + * M a i n + * --- */ + +/** + * This is the standard DeltaBlue benchmark. A long chain of equality + * constraints is constructed with a stay constraint on one end. An + * edit constraint is then added to the opposite end and the time is + * measured for adding and removing this constraint, and extracting + * and executing a constraint satisfaction plan. There are two cases. + * In case 1, the added constraint is stronger than the stay + * constraint and values must propagate down the entire length of the + * chain. In case 2, the added constraint is weaker than the stay + * constraint so it cannot be accomodated. The cost in this case is, + * of course, very low. Typical situations lie somewhere between these + * two extremes. + */ +function chainTest(n) { + planner = new Planner(); + var prev = null, first = null, last = null; + + // Build chain of n equality constraints + for (var i = 0; i <= n; i++) { + var name = "v" + i; + var v = new Variable(name); + if (prev != null) + new EqualityConstraint(prev, v, Strength.REQUIRED); + if (i == 0) first = v; + if (i == n) last = v; + prev = v; + } + + new StayConstraint(last, Strength.STRONG_DEFAULT); + var edit = new EditConstraint(first, Strength.PREFERRED); + var edits = new OrderedCollection(); + edits.add(edit); + var plan = planner.extractPlanFromConstraints(edits); + for (var i = 0; i < 100; i++) { + first.value = i; + plan.execute(); + assertEq(last.value, i); + } +} + +/** + * This test constructs a two sets of variables related to each + * other by a simple linear transformation (scale and offset). The + * time is measured to change a variable on either side of the + * mapping and to change the scale and offset factors. + */ +function projectionTest(n) { + planner = new Planner(); + var scale = new Variable("scale", 10); + var offset = new Variable("offset", 1000); + var src = null, dst = null; + + var dests = new OrderedCollection(); + for (var i = 0; i < n; i++) { + src = new Variable("src" + i, i); + dst = new Variable("dst" + i, i); + dests.add(dst); + new StayConstraint(src, Strength.NORMAL); + new ScaleConstraint(src, scale, offset, dst, Strength.REQUIRED); + } + + change(src, 17); + assertEq(dst.value, 1170); + change(dst, 1050); + assertEq(src.value, 5); + change(scale, 5); + for (var i = 0; i < n - 1; i++) { + assertEq(dests.at(i).value, i * 5 + 1000); + } + change(offset, 2000); + for (var i = 0; i < n - 1; i++) { + assertEq(dests.at(i).value, i * 5 + 2000); + } +} + +function change(v, newValue) { + var edit = new EditConstraint(v, Strength.PREFERRED); + var edits = new OrderedCollection(); + edits.add(edit); + var plan = planner.extractPlanFromConstraints(edits); + for (var i = 0; i < 10; i++) { + v.value = newValue; + plan.execute(); + } + edit.destroyConstraint(); +} + +// Global variable holding the current planner. +var planner = null; + +function deltaBlue() { + chainTest(100); + projectionTest(100); +} + +deltaBlue(); diff --git a/js/src/jit-test/tests/v8-v5/check-earley-boyer.js b/js/src/jit-test/tests/v8-v5/check-earley-boyer.js new file mode 100644 index 0000000..e9df6ce --- /dev/null +++ b/js/src/jit-test/tests/v8-v5/check-earley-boyer.js @@ -0,0 +1,4694 @@ +// This file is automatically generated by scheme2js, except for the +// benchmark harness code at the beginning and end of the file. + +//var EarleyBoyer = new BenchmarkSuite('EarleyBoyer', 765819, [ +// new Benchmark("Earley", function () { BgL_earleyzd2benchmarkzd2(); }), +// new Benchmark("Boyer", function () { BgL_nboyerzd2benchmarkzd2(); }) +//]); + + +/************* GENERATED FILE - DO NOT EDIT *************/ +/************* GENERATED FILE - DO NOT EDIT *************/ +/************* GENERATED FILE - DO NOT EDIT *************/ +/************* GENERATED FILE - DO NOT EDIT *************/ +/************* GENERATED FILE - DO NOT EDIT *************/ +/************* GENERATED FILE - DO NOT EDIT *************/ +/************* GENERATED FILE - DO NOT EDIT *************/ +/************* GENERATED FILE - DO NOT EDIT *************/ +/* + * To use write/prints/... the default-output port has to be set first. + * Simply setting SC_DEFAULT_OUT and SC_ERROR_OUT to the desired values + * should do the trick. + * In the following example the std-out and error-port are redirected to + * a DIV. +function initRuntime() { + function escapeHTML(s) { + var tmp = s; + tmp = tmp.replace(/&/g, "&"); + tmp = tmp.replace(//g, ">"); + tmp = tmp.replace(/ /g, " "); + tmp = tmp.replace(/\n/g, "
"); + tmp = tmp.replace(/\t/g, "    "); + return tmp; + + } + + document.write("

"); + SC_DEFAULT_OUT = new sc_GenericOutputPort( + function(s) { + var stdout = document.getElementById('stdout'); + stdout.innerHTML = stdout.innerHTML + escapeHTML(s); + }); + SC_ERROR_OUT = SC_DEFAULT_OUT; +} +*/ + + +function sc_print_debug() { + sc_print.apply(null, arguments); +} +/*** META ((export *js*)) */ +var sc_JS_GLOBALS = this; + +var __sc_LINE=-1; +var __sc_FILE=""; + +/*** META ((export #t)) */ +function sc_alert() { + var len = arguments.length; + var s = ""; + var i; + + for( i = 0; i < len; i++ ) { + s += sc_toDisplayString(arguments[ i ]); + } + + return alert( s ); +} + +/*** META ((export #t)) */ +function sc_typeof( x ) { + return typeof x; +} + +/*** META ((export #t)) */ +function sc_error() { + var a = [sc_jsstring2symbol("*error*")]; + for (var i = 0; i < arguments.length; i++) { + a[i+1] = arguments[i]; + } + throw a; +} + +/*** META ((export #t) + (peephole (prefix "throw "))) +*/ +function sc_raise(obj) { + throw obj; +} + +/*** META ((export with-handler-lambda)) */ +function sc_withHandlerLambda(handler, body) { + try { + return body(); + } catch(e) { + if (!e._internalException) + return handler(e); + else + throw e; + } +} + +var sc_properties = new Object(); + +/*** META ((export #t)) */ +function sc_putpropBang(sym, key, val) { + var ht = sc_properties[sym]; + if (!ht) { + ht = new Object(); + sc_properties[sym] = ht; + } + ht[key] = val; +} + +/*** META ((export #t)) */ +function sc_getprop(sym, key) { + var ht = sc_properties[sym]; + if (ht) { + if (key in ht) + return ht[key]; + else + return false; + } else + return false; +} + +/*** META ((export #t)) */ +function sc_rempropBang(sym, key) { + var ht = sc_properties[sym]; + if (ht) + delete ht[key]; +} + +/*** META ((export #t)) */ +function sc_any2String(o) { + return jsstring2string(sc_toDisplayString(o)); +} + +/*** META ((export #t) + (peephole (infix 2 2 "===")) + (type bool)) +*/ +function sc_isEqv(o1, o2) { + return (o1 === o2); +} + +/*** META ((export #t) + (peephole (infix 2 2 "===")) + (type bool)) +*/ +function sc_isEq(o1, o2) { + return (o1 === o2); +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isNumber(n) { + return (typeof n === "number"); +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isComplex(n) { + return sc_isNumber(n); +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isReal(n) { + return sc_isNumber(n); +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isRational(n) { + return sc_isReal(n); +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isInteger(n) { + return (parseInt(n) === n); +} + +/*** META ((export #t) + (type bool) + (peephole (postfix ", false"))) +*/ +// we don't have exact numbers... +function sc_isExact(n) { + return false; +} + +/*** META ((export #t) + (peephole (postfix ", true")) + (type bool)) +*/ +function sc_isInexact(n) { + return true; +} + +/*** META ((export = =fx =fl) + (type bool) + (peephole (infix 2 2 "==="))) +*/ +function sc_equal(x) { + for (var i = 1; i < arguments.length; i++) + if (x !== arguments[i]) + return false; + return true; +} + +/*** META ((export < = arguments[i]) + return false; + x = arguments[i]; + } + return true; +} + +/*** META ((export > >fx >fl) + (type bool) + (peephole (infix 2 2 ">"))) +*/ +function sc_greater(x, y) { + for (var i = 1; i < arguments.length; i++) { + if (x <= arguments[i]) + return false; + x = arguments[i]; + } + return true; +} + +/*** META ((export <= <=fx <=fl) + (type bool) + (peephole (infix 2 2 "<="))) +*/ +function sc_lessEqual(x, y) { + for (var i = 1; i < arguments.length; i++) { + if (x > arguments[i]) + return false; + x = arguments[i]; + } + return true; +} + +/*** META ((export >= >=fl >=fx) + (type bool) + (peephole (infix 2 2 ">="))) +*/ +function sc_greaterEqual(x, y) { + for (var i = 1; i < arguments.length; i++) { + if (x < arguments[i]) + return false; + x = arguments[i]; + } + return true; +} + +/*** META ((export #t) + (type bool) + (peephole (postfix "=== 0"))) +*/ +function sc_isZero(x) { + return (x === 0); +} + +/*** META ((export #t) + (type bool) + (peephole (postfix "> 0"))) +*/ +function sc_isPositive(x) { + return (x > 0); +} + +/*** META ((export #t) + (type bool) + (peephole (postfix "< 0"))) +*/ +function sc_isNegative(x) { + return (x < 0); +} + +/*** META ((export #t) + (type bool) + (peephole (postfix "%2===1"))) +*/ +function sc_isOdd(x) { + return (x % 2 === 1); +} + +/*** META ((export #t) + (type bool) + (peephole (postfix "%2===0"))) +*/ +function sc_isEven(x) { + return (x % 2 === 0); +} + +/*** META ((export #t)) */ +var sc_max = Math.max; +/*** META ((export #t)) */ +var sc_min = Math.min; + +/*** META ((export + +fx +fl) + (peephole (infix 0 #f "+" "0"))) +*/ +function sc_plus() { + var sum = 0; + for (var i = 0; i < arguments.length; i++) + sum += arguments[i]; + return sum; +} + +/*** META ((export * *fx *fl) + (peephole (infix 0 #f "*" "1"))) +*/ +function sc_multi() { + var product = 1; + for (var i = 0; i < arguments.length; i++) + product *= arguments[i]; + return product; +} + +/*** META ((export - -fx -fl) + (peephole (minus))) +*/ +function sc_minus(x) { + if (arguments.length === 1) + return -x; + else { + var res = x; + for (var i = 1; i < arguments.length; i++) + res -= arguments[i]; + return res; + } +} + +/*** META ((export / /fl) + (peephole (div))) +*/ +function sc_div(x) { + if (arguments.length === 1) + return 1/x; + else { + var res = x; + for (var i = 1; i < arguments.length; i++) + res /= arguments[i]; + return res; + } +} + +/*** META ((export #t)) */ +var sc_abs = Math.abs; + +/*** META ((export quotient /fx) + (peephole (hole 2 "parseInt(" x "/" y ")"))) +*/ +function sc_quotient(x, y) { + return parseInt(x / y); +} + +/*** META ((export #t) + (peephole (infix 2 2 "%"))) +*/ +function sc_remainder(x, y) { + return x % y; +} + +/*** META ((export #t) + (peephole (modulo))) +*/ +function sc_modulo(x, y) { + var remainder = x % y; + // if they don't have the same sign + if ((remainder * y) < 0) + return remainder + y; + else + return remainder; +} + +function sc_euclid_gcd(a, b) { + var temp; + if (a === 0) return b; + if (b === 0) return a; + if (a < 0) {a = -a;}; + if (b < 0) {b = -b;}; + if (b > a) {temp = a; a = b; b = temp;}; + while (true) { + a %= b; + if(a === 0) {return b;}; + b %= a; + if(b === 0) {return a;}; + }; + return b; +} + +/*** META ((export #t)) */ +function sc_gcd() { + var gcd = 0; + for (var i = 0; i < arguments.length; i++) + gcd = sc_euclid_gcd(gcd, arguments[i]); + return gcd; +} + +/*** META ((export #t)) */ +function sc_lcm() { + var lcm = 1; + for (var i = 0; i < arguments.length; i++) { + var f = Math.round(arguments[i] / sc_euclid_gcd(arguments[i], lcm)); + lcm *= Math.abs(f); + } + return lcm; +} + +// LIMITATION: numerator and denominator don't make sense in floating point world. +//var SC_MAX_DECIMALS = 1000000 +// +// function sc_numerator(x) { +// var rounded = Math.round(x * SC_MAX_DECIMALS); +// return Math.round(rounded / sc_euclid_gcd(rounded, SC_MAX_DECIMALS)); +// } + +// function sc_denominator(x) { +// var rounded = Math.round(x * SC_MAX_DECIMALS); +// return Math.round(SC_MAX_DECIMALS / sc_euclid_gcd(rounded, SC_MAX_DECIMALS)); +// } + +/*** META ((export #t)) */ +var sc_floor = Math.floor; +/*** META ((export #t)) */ +var sc_ceiling = Math.ceil; +/*** META ((export #t)) */ +var sc_truncate = parseInt; +/*** META ((export #t)) */ +var sc_round = Math.round; + +// LIMITATION: sc_rationalize doesn't make sense in a floating point world. + +/*** META ((export #t)) */ +var sc_exp = Math.exp; +/*** META ((export #t)) */ +var sc_log = Math.log; +/*** META ((export #t)) */ +var sc_sin = Math.sin; +/*** META ((export #t)) */ +var sc_cos = Math.cos; +/*** META ((export #t)) */ +var sc_tan = Math.tan; +/*** META ((export #t)) */ +var sc_asin = Math.asin; +/*** META ((export #t)) */ +var sc_acos = Math.acos; +/*** META ((export #t)) */ +var sc_atan = Math.atan; + +/*** META ((export #t)) */ +var sc_sqrt = Math.sqrt; +/*** META ((export #t)) */ +var sc_expt = Math.pow; + +// LIMITATION: we don't have complex numbers. +// LIMITATION: the following functions are hence not implemented. +// LIMITATION: make-rectangular, make-polar, real-part, imag-part, magnitude, angle +// LIMITATION: 2 argument atan + +/*** META ((export #t) + (peephole (id))) +*/ +function sc_exact2inexact(x) { + return x; +} + +/*** META ((export #t) + (peephole (id))) +*/ +function sc_inexact2exact(x) { + return x; +} + +function sc_number2jsstring(x, radix) { + if (radix) + return x.toString(radix); + else + return x.toString(); +} + +function sc_jsstring2number(s, radix) { + if (s === "") return false; + + if (radix) { + var t = parseInt(s, radix); + if (!t && t !== 0) return false; + // verify that each char is in range. (parseInt ignores leading + // white and trailing chars) + var allowedChars = "01234567890abcdefghijklmnopqrstuvwxyz".substring(0, radix+1); + if ((new RegExp("^["+allowedChars+"]*$", "i")).test(s)) + return t; + else return false; + } else { + var t = +s; // does not ignore trailing chars. + if (!t && t !== 0) return false; + // simply verify that first char is not whitespace. + var c = s.charAt(0); + // if +c is 0, but the char is not "0", then we have a whitespace. + if (+c === 0 && c !== "0") return false; + return t; + } +} + +/*** META ((export #t) + (type bool) + (peephole (not))) +*/ +function sc_not(b) { + return b === false; +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isBoolean(b) { + return (b === true) || (b === false); +} + +function sc_Pair(car, cdr) { + this.car = car; + this.cdr = cdr; +} + +sc_Pair.prototype.toString = function() { + return sc_toDisplayString(this); +}; +sc_Pair.prototype.sc_toWriteOrDisplayString = function(writeOrDisplay) { + var current = this; + + var res = "("; + + while(true) { + res += writeOrDisplay(current.car); + if (sc_isPair(current.cdr)) { + res += " "; + current = current.cdr; + } else if (current.cdr !== null) { + res += " . " + writeOrDisplay(current.cdr); + break; + } else // current.cdr == null + break; + } + + res += ")"; + + return res; +}; +sc_Pair.prototype.sc_toDisplayString = function() { + return this.sc_toWriteOrDisplayString(sc_toDisplayString); +}; +sc_Pair.prototype.sc_toWriteString = function() { + return this.sc_toWriteOrDisplayString(sc_toWriteString); +}; +// sc_Pair.prototype.sc_toWriteCircleString in IO.js + +/*** META ((export #t) + (type bool) + (peephole (postfix " instanceof sc_Pair"))) +*/ +function sc_isPair(p) { + return (p instanceof sc_Pair); +} + +function sc_isPairEqual(p1, p2, comp) { + return (comp(p1.car, p2.car) && comp(p1.cdr, p2.cdr)); +} + +/*** META ((export #t) + (peephole (hole 2 "new sc_Pair(" car ", " cdr ")"))) +*/ +function sc_cons(car, cdr) { + return new sc_Pair(car, cdr); +} + +/*** META ((export cons*)) */ +function sc_consStar() { + var res = arguments[arguments.length - 1]; + for (var i = arguments.length-2; i >= 0; i--) + res = new sc_Pair(arguments[i], res); + return res; +} + +/*** META ((export #t) + (peephole (postfix ".car"))) +*/ +function sc_car(p) { + return p.car; +} + +/*** META ((export #t) + (peephole (postfix ".cdr"))) +*/ +function sc_cdr(p) { + return p.cdr; +} + +/*** META ((export #t) + (peephole (hole 2 p ".car = " val))) +*/ +function sc_setCarBang(p, val) { + p.car = val; +} + +/*** META ((export #t) + (peephole (hole 2 p ".cdr = " val))) +*/ +function sc_setCdrBang(p, val) { + p.cdr = val; +} + +/*** META ((export #t) + (peephole (postfix ".car.car"))) +*/ +function sc_caar(p) { return p.car.car; } +/*** META ((export #t) + (peephole (postfix ".cdr.car"))) +*/ +function sc_cadr(p) { return p.cdr.car; } +/*** META ((export #t) + (peephole (postfix ".car.cdr"))) +*/ +function sc_cdar(p) { return p.car.cdr; } +/*** META ((export #t) + (peephole (postfix ".cdr.cdr"))) +*/ +function sc_cddr(p) { return p.cdr.cdr; } +/*** META ((export #t) + (peephole (postfix ".car.car.car"))) +*/ +function sc_caaar(p) { return p.car.car.car; } +/*** META ((export #t) + (peephole (postfix ".car.cdr.car"))) +*/ +function sc_cadar(p) { return p.car.cdr.car; } +/*** META ((export #t) + (peephole (postfix ".cdr.car.car"))) +*/ +function sc_caadr(p) { return p.cdr.car.car; } +/*** META ((export #t) + (peephole (postfix ".cdr.cdr.car"))) +*/ +function sc_caddr(p) { return p.cdr.cdr.car; } +/*** META ((export #t) + (peephole (postfix ".car.car.cdr"))) +*/ +function sc_cdaar(p) { return p.car.car.cdr; } +/*** META ((export #t) + (peephole (postfix ".cdr.car.cdr"))) +*/ +function sc_cdadr(p) { return p.cdr.car.cdr; } +/*** META ((export #t) + (peephole (postfix ".car.cdr.cdr"))) +*/ +function sc_cddar(p) { return p.car.cdr.cdr; } +/*** META ((export #t) + (peephole (postfix ".cdr.cdr.cdr"))) +*/ +function sc_cdddr(p) { return p.cdr.cdr.cdr; } +/*** META ((export #t) + (peephole (postfix ".car.car.car.car"))) +*/ +function sc_caaaar(p) { return p.car.car.car.car; } +/*** META ((export #t) + (peephole (postfix ".car.cdr.car.car"))) +*/ +function sc_caadar(p) { return p.car.cdr.car.car; } +/*** META ((export #t) + (peephole (postfix ".cdr.car.car.car"))) +*/ +function sc_caaadr(p) { return p.cdr.car.car.car; } +/*** META ((export #t) + (peephole (postfix ".cdr.cdr.car.car"))) +*/ +function sc_caaddr(p) { return p.cdr.cdr.car.car; } +/*** META ((export #t) + (peephole (postfix ".car.car.car.cdr"))) +*/ +function sc_cdaaar(p) { return p.car.car.car.cdr; } +/*** META ((export #t) + (peephole (postfix ".car.cdr.car.cdr"))) +*/ +function sc_cdadar(p) { return p.car.cdr.car.cdr; } +/*** META ((export #t) + (peephole (postfix ".cdr.car.car.cdr"))) +*/ +function sc_cdaadr(p) { return p.cdr.car.car.cdr; } +/*** META ((export #t) + (peephole (postfix ".cdr.cdr.car.cdr"))) +*/ +function sc_cdaddr(p) { return p.cdr.cdr.car.cdr; } +/*** META ((export #t) + (peephole (postfix ".car.car.cdr.car"))) +*/ +function sc_cadaar(p) { return p.car.car.cdr.car; } +/*** META ((export #t) + (peephole (postfix ".car.cdr.cdr.car"))) +*/ +function sc_caddar(p) { return p.car.cdr.cdr.car; } +/*** META ((export #t) + (peephole (postfix ".cdr.car.cdr.car"))) +*/ +function sc_cadadr(p) { return p.cdr.car.cdr.car; } +/*** META ((export #t) + (peephole (postfix ".cdr.cdr.cdr.car"))) +*/ +function sc_cadddr(p) { return p.cdr.cdr.cdr.car; } +/*** META ((export #t) + (peephole (postfix ".car.car.cdr.cdr"))) +*/ +function sc_cddaar(p) { return p.car.car.cdr.cdr; } +/*** META ((export #t) + (peephole (postfix ".car.cdr.cdr.cdr"))) +*/ +function sc_cdddar(p) { return p.car.cdr.cdr.cdr; } +/*** META ((export #t) + (peephole (postfix ".cdr.car.cdr.cdr"))) +*/ +function sc_cddadr(p) { return p.cdr.car.cdr.cdr; } +/*** META ((export #t) + (peephole (postfix ".cdr.cdr.cdr.cdr"))) +*/ +function sc_cddddr(p) { return p.cdr.cdr.cdr.cdr; } + +/*** META ((export #t)) */ +function sc_lastPair(l) { + if (!sc_isPair(l)) sc_error("sc_lastPair: pair expected"); + var res = l; + var cdr = l.cdr; + while (sc_isPair(cdr)) { + res = cdr; + cdr = res.cdr; + } + return res; +} + +/*** META ((export #t) + (type bool) + (peephole (postfix " === null"))) +*/ +function sc_isNull(o) { + return (o === null); +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isList(o) { + var rabbit; + var turtle; + + var rabbit = o; + var turtle = o; + while (true) { + if (rabbit === null || + (rabbit instanceof sc_Pair && rabbit.cdr === null)) + return true; // end of list + else if ((rabbit instanceof sc_Pair) && + (rabbit.cdr instanceof sc_Pair)) { + rabbit = rabbit.cdr.cdr; + turtle = turtle.cdr; + if (rabbit === turtle) return false; // cycle + } else + return false; // not pair + } +} + +/*** META ((export #t)) */ +function sc_list() { + var res = null; + var a = arguments; + for (var i = a.length-1; i >= 0; i--) + res = new sc_Pair(a[i], res); + return res; +} + +/*** META ((export #t)) */ +function sc_iota(num, init) { + var res = null; + if (!init) init = 0; + for (var i = num - 1; i >= 0; i--) + res = new sc_Pair(i + init, res); + return res; +} + +/*** META ((export #t)) */ +function sc_makeList(nbEls, fill) { + var res = null; + for (var i = 0; i < nbEls; i++) + res = new sc_Pair(fill, res); + return res; +} + +/*** META ((export #t)) */ +function sc_length(l) { + var res = 0; + while (l !== null) { + res++; + l = l.cdr; + } + return res; +} + +/*** META ((export #t)) */ +function sc_remq(o, l) { + var dummy = { cdr : null }; + var tail = dummy; + while (l !== null) { + if (l.car !== o) { + tail.cdr = sc_cons(l.car, null); + tail = tail.cdr; + } + l = l.cdr; + } + return dummy.cdr; +} + +/*** META ((export #t)) */ +function sc_remqBang(o, l) { + var dummy = { cdr : null }; + var tail = dummy; + var needsAssig = true; + while (l !== null) { + if (l.car === o) { + needsAssig = true; + } else { + if (needsAssig) { + tail.cdr = l; + needsAssig = false; + } + tail = l; + } + l = l.cdr; + } + tail.cdr = null; + return dummy.cdr; +} + +/*** META ((export #t)) */ +function sc_delete(o, l) { + var dummy = { cdr : null }; + var tail = dummy; + while (l !== null) { + if (!sc_isEqual(l.car, o)) { + tail.cdr = sc_cons(l.car, null); + tail = tail.cdr; + } + l = l.cdr; + } + return dummy.cdr; +} + +/*** META ((export #t)) */ +function sc_deleteBang(o, l) { + var dummy = { cdr : null }; + var tail = dummy; + var needsAssig = true; + while (l !== null) { + if (sc_isEqual(l.car, o)) { + needsAssig = true; + } else { + if (needsAssig) { + tail.cdr = l; + needsAssig = false; + } + tail = l; + } + l = l.cdr; + } + tail.cdr = null; + return dummy.cdr; +} + +function sc_reverseAppendBang(l1, l2) { + var res = l2; + while (l1 !== null) { + var tmp = res; + res = l1; + l1 = l1.cdr; + res.cdr = tmp; + } + return res; +} + +function sc_dualAppend(l1, l2) { + if (l1 === null) return l2; + if (l2 === null) return l1; + var rev = sc_reverse(l1); + return sc_reverseAppendBang(rev, l2); +} + +/*** META ((export #t)) */ +function sc_append() { + if (arguments.length === 0) + return null; + var res = arguments[arguments.length - 1]; + for (var i = arguments.length - 2; i >= 0; i--) + res = sc_dualAppend(arguments[i], res); + return res; +} + +function sc_dualAppendBang(l1, l2) { + if (l1 === null) return l2; + if (l2 === null) return l1; + var tmp = l1; + while (tmp.cdr !== null) tmp=tmp.cdr; + tmp.cdr = l2; + return l1; +} + +/*** META ((export #t)) */ +function sc_appendBang() { + var res = null; + for (var i = 0; i < arguments.length; i++) + res = sc_dualAppendBang(res, arguments[i]); + return res; +} + +/*** META ((export #t)) */ +function sc_reverse(l1) { + var res = null; + while (l1 !== null) { + res = sc_cons(l1.car, res); + l1 = l1.cdr; + } + return res; +} + +/*** META ((export #t)) */ +function sc_reverseBang(l) { + return sc_reverseAppendBang(l, null); +} + +/*** META ((export #t)) */ +function sc_listTail(l, k) { + var res = l; + for (var i = 0; i < k; i++) { + res = res.cdr; + } + return res; +} + +/*** META ((export #t)) */ +function sc_listRef(l, k) { + return sc_listTail(l, k).car; +} + +/* // unoptimized generic versions +function sc_memX(o, l, comp) { + while (l != null) { + if (comp(l.car, o)) + return l; + l = l.cdr; + } + return false; +} +function sc_memq(o, l) { return sc_memX(o, l, sc_isEq); } +function sc_memv(o, l) { return sc_memX(o, l, sc_isEqv); } +function sc_member(o, l) { return sc_memX(o, l, sc_isEqual); } +*/ + +/* optimized versions */ +/*** META ((export #t)) */ +function sc_memq(o, l) { + while (l !== null) { + if (l.car === o) + return l; + l = l.cdr; + } + return false; +} +/*** META ((export #t)) */ +function sc_memv(o, l) { + while (l !== null) { + if (l.car === o) + return l; + l = l.cdr; + } + return false; +} +/*** META ((export #t)) */ +function sc_member(o, l) { + while (l !== null) { + if (sc_isEqual(l.car,o)) + return l; + l = l.cdr; + } + return false; +} + +/* // generic unoptimized versions +function sc_assX(o, al, comp) { + while (al != null) { + if (comp(al.car.car, o)) + return al.car; + al = al.cdr; + } + return false; +} +function sc_assq(o, al) { return sc_assX(o, al, sc_isEq); } +function sc_assv(o, al) { return sc_assX(o, al, sc_isEqv); } +function sc_assoc(o, al) { return sc_assX(o, al, sc_isEqual); } +*/ +// optimized versions +/*** META ((export #t)) */ +function sc_assq(o, al) { + while (al !== null) { + if (al.car.car === o) + return al.car; + al = al.cdr; + } + return false; +} +/*** META ((export #t)) */ +function sc_assv(o, al) { + while (al !== null) { + if (al.car.car === o) + return al.car; + al = al.cdr; + } + return false; +} +/*** META ((export #t)) */ +function sc_assoc(o, al) { + while (al !== null) { + if (sc_isEqual(al.car.car, o)) + return al.car; + al = al.cdr; + } + return false; +} + +/* can be used for mutable strings and characters */ +function sc_isCharStringEqual(cs1, cs2) { return cs1.val === cs2.val; } +function sc_isCharStringLess(cs1, cs2) { return cs1.val < cs2.val; } +function sc_isCharStringGreater(cs1, cs2) { return cs1.val > cs2.val; } +function sc_isCharStringLessEqual(cs1, cs2) { return cs1.val <= cs2.val; } +function sc_isCharStringGreaterEqual(cs1, cs2) { return cs1.val >= cs2.val; } +function sc_isCharStringCIEqual(cs1, cs2) + { return cs1.val.toLowerCase() === cs2.val.toLowerCase(); } +function sc_isCharStringCILess(cs1, cs2) + { return cs1.val.toLowerCase() < cs2.val.toLowerCase(); } +function sc_isCharStringCIGreater(cs1, cs2) + { return cs1.val.toLowerCase() > cs2.val.toLowerCase(); } +function sc_isCharStringCILessEqual(cs1, cs2) + { return cs1.val.toLowerCase() <= cs2.val.toLowerCase(); } +function sc_isCharStringCIGreaterEqual(cs1, cs2) + { return cs1.val.toLowerCase() >= cs2.val.toLowerCase(); } + + + + +function sc_Char(c) { + var cached = sc_Char.lazy[c]; + if (cached) + return cached; + this.val = c; + sc_Char.lazy[c] = this; + // add return, so FF does not complain. + return undefined; +} +sc_Char.lazy = new Object(); +// thanks to Eric +sc_Char.char2readable = { + "\000": "#\\null", + "\007": "#\\bell", + "\010": "#\\backspace", + "\011": "#\\tab", + "\012": "#\\newline", + "\014": "#\\page", + "\015": "#\\return", + "\033": "#\\escape", + "\040": "#\\space", + "\177": "#\\delete", + + /* poeticless names */ + "\001": "#\\soh", + "\002": "#\\stx", + "\003": "#\\etx", + "\004": "#\\eot", + "\005": "#\\enq", + "\006": "#\\ack", + + "\013": "#\\vt", + "\016": "#\\so", + "\017": "#\\si", + + "\020": "#\\dle", + "\021": "#\\dc1", + "\022": "#\\dc2", + "\023": "#\\dc3", + "\024": "#\\dc4", + "\025": "#\\nak", + "\026": "#\\syn", + "\027": "#\\etb", + + "\030": "#\\can", + "\031": "#\\em", + "\032": "#\\sub", + "\033": "#\\esc", + "\034": "#\\fs", + "\035": "#\\gs", + "\036": "#\\rs", + "\037": "#\\us"}; + +sc_Char.readable2char = { + "null": "\000", + "bell": "\007", + "backspace": "\010", + "tab": "\011", + "newline": "\012", + "page": "\014", + "return": "\015", + "escape": "\033", + "space": "\040", + "delete": "\000", + "soh": "\001", + "stx": "\002", + "etx": "\003", + "eot": "\004", + "enq": "\005", + "ack": "\006", + "bel": "\007", + "bs": "\010", + "ht": "\011", + "nl": "\012", + "vt": "\013", + "np": "\014", + "cr": "\015", + "so": "\016", + "si": "\017", + "dle": "\020", + "dc1": "\021", + "dc2": "\022", + "dc3": "\023", + "dc4": "\024", + "nak": "\025", + "syn": "\026", + "etb": "\027", + "can": "\030", + "em": "\031", + "sub": "\032", + "esc": "\033", + "fs": "\034", + "gs": "\035", + "rs": "\036", + "us": "\037", + "sp": "\040", + "del": "\177"}; + +sc_Char.prototype.toString = function() { + return this.val; +}; +// sc_toDisplayString == toString +sc_Char.prototype.sc_toWriteString = function() { + var entry = sc_Char.char2readable[this.val]; + if (entry) + return entry; + else + return "#\\" + this.val; +}; + +/*** META ((export #t) + (type bool) + (peephole (postfix "instanceof sc_Char"))) +*/ +function sc_isChar(c) { + return (c instanceof sc_Char); +} + +/*** META ((export char=?) + (type bool) + (peephole (hole 2 c1 ".val === " c2 ".val"))) +*/ +var sc_isCharEqual = sc_isCharStringEqual; +/*** META ((export char?) + (type bool) + (peephole (hole 2 c1 ".val > " c2 ".val"))) +*/ +var sc_isCharGreater = sc_isCharStringGreater; +/*** META ((export char<=?) + (type bool) + (peephole (hole 2 c1 ".val <= " c2 ".val"))) +*/ +var sc_isCharLessEqual = sc_isCharStringLessEqual; +/*** META ((export char>=?) + (type bool) + (peephole (hole 2 c1 ".val >= " c2 ".val"))) +*/ +var sc_isCharGreaterEqual = sc_isCharStringGreaterEqual; +/*** META ((export char-ci=?) + (type bool) + (peephole (hole 2 c1 ".val.toLowerCase() === " c2 ".val.toLowerCase()"))) +*/ +var sc_isCharCIEqual = sc_isCharStringCIEqual; +/*** META ((export char-ci?) + (type bool) + (peephole (hole 2 c1 ".val.toLowerCase() > " c2 ".val.toLowerCase()"))) +*/ +var sc_isCharCIGreater = sc_isCharStringCIGreater; +/*** META ((export char-ci<=?) + (type bool) + (peephole (hole 2 c1 ".val.toLowerCase() <= " c2 ".val.toLowerCase()"))) +*/ +var sc_isCharCILessEqual = sc_isCharStringCILessEqual; +/*** META ((export char-ci>=?) + (type bool) + (peephole (hole 2 c1 ".val.toLowerCase() >= " c2 ".val.toLowerCase()"))) +*/ +var sc_isCharCIGreaterEqual = sc_isCharStringCIGreaterEqual; + +var SC_NUMBER_CLASS = "0123456789"; +var SC_WHITESPACE_CLASS = ' \r\n\t\f'; +var SC_LOWER_CLASS = 'abcdefghijklmnopqrstuvwxyz'; +var SC_UPPER_CLASS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + +function sc_isCharOfClass(c, cl) { return (cl.indexOf(c) != -1); } +/*** META ((export #t) + (type bool)) +*/ +function sc_isCharAlphabetic(c) + { return sc_isCharOfClass(c.val, SC_LOWER_CLASS) || + sc_isCharOfClass(c.val, SC_UPPER_CLASS); } +/*** META ((export #t) + (type bool) + (peephole (hole 1 "SC_NUMBER_CLASS.indexOf(" c ".val) != -1"))) +*/ +function sc_isCharNumeric(c) + { return sc_isCharOfClass(c.val, SC_NUMBER_CLASS); } +/*** META ((export #t) + (type bool)) +*/ +function sc_isCharWhitespace(c) { + var tmp = c.val; + return tmp === " " || tmp === "\r" || tmp === "\n" || tmp === "\t" || tmp === "\f"; +} +/*** META ((export #t) + (type bool) + (peephole (hole 1 "SC_UPPER_CLASS.indexOf(" c ".val) != -1"))) +*/ +function sc_isCharUpperCase(c) + { return sc_isCharOfClass(c.val, SC_UPPER_CLASS); } +/*** META ((export #t) + (type bool) + (peephole (hole 1 "SC_LOWER_CLASS.indexOf(" c ".val) != -1"))) +*/ +function sc_isCharLowerCase(c) + { return sc_isCharOfClass(c.val, SC_LOWER_CLASS); } + +/*** META ((export #t) + (peephole (postfix ".val.charCodeAt(0)"))) +*/ +function sc_char2integer(c) + { return c.val.charCodeAt(0); } +/*** META ((export #t) + (peephole (hole 1 "new sc_Char(String.fromCharCode(" n "))"))) +*/ +function sc_integer2char(n) + { return new sc_Char(String.fromCharCode(n)); } + +/*** META ((export #t) + (peephole (hole 1 "new sc_Char(" c ".val.toUpperCase())"))) +*/ +function sc_charUpcase(c) + { return new sc_Char(c.val.toUpperCase()); } +/*** META ((export #t) + (peephole (hole 1 "new sc_Char(" c ".val.toLowerCase())"))) +*/ +function sc_charDowncase(c) + { return new sc_Char(c.val.toLowerCase()); } + +function sc_makeJSStringOfLength(k, c) { + var fill; + if (c === undefined) + fill = " "; + else + fill = c; + var res = ""; + var len = 1; + // every round doubles the size of fill. + while (k >= len) { + if (k & len) + res = res.concat(fill); + fill = fill.concat(fill); + len *= 2; + } + return res; +} + +function sc_makejsString(k, c) { + var fill; + if (c) + fill = c.val; + else + fill = " "; + return sc_makeJSStringOfLength(k, fill); +} + +function sc_jsstring2list(s) { + var res = null; + for (var i = s.length - 1; i >= 0; i--) + res = sc_cons(new sc_Char(s.charAt(i)), res); + return res; +} + +function sc_list2jsstring(l) { + var a = new Array(); + while(l !== null) { + a.push(l.car.val); + l = l.cdr; + } + return "".concat.apply("", a); +} + +var sc_Vector = Array; + +sc_Vector.prototype.sc_toWriteOrDisplayString = function(writeOrDisplay) { + if (this.length === 0) return "#()"; + + var res = "#(" + writeOrDisplay(this[0]); + for (var i = 1; i < this.length; i++) + res += " " + writeOrDisplay(this[i]); + res += ")"; + return res; +}; +sc_Vector.prototype.sc_toDisplayString = function() { + return this.sc_toWriteOrDisplayString(sc_toDisplayString); +}; +sc_Vector.prototype.sc_toWriteString = function() { + return this.sc_toWriteOrDisplayString(sc_toWriteString); +}; + +/*** META ((export vector? array?) + (type bool) + (peephole (postfix " instanceof sc_Vector"))) +*/ +function sc_isVector(v) { + return (v instanceof sc_Vector); +} + +// only applies to vectors +function sc_isVectorEqual(v1, v2, comp) { + if (v1.length !== v2.length) return false; + for (var i = 0; i < v1.length; i++) + if (!comp(v1[i], v2[i])) return false; + return true; +} + +/*** META ((export make-vector make-array)) */ +function sc_makeVector(size, fill) { + var a = new sc_Vector(size); + if (fill !== undefined) + sc_vectorFillBang(a, fill); + return a; +} + +/*** META ((export vector array) + (peephole (vector))) +*/ +function sc_vector() { + var a = new sc_Vector(); + for (var i = 0; i < arguments.length; i++) + a.push(arguments[i]); + return a; +} + +/*** META ((export vector-length array-length) + (peephole (postfix ".length"))) +*/ +function sc_vectorLength(v) { + return v.length; +} + +/*** META ((export vector-ref array-ref) + (peephole (hole 2 v "[" pos "]"))) +*/ +function sc_vectorRef(v, pos) { + return v[pos]; +} + +/*** META ((export vector-set! array-set!) + (peephole (hole 3 v "[" pos "] = " val))) +*/ +function sc_vectorSetBang(v, pos, val) { + v[pos] = val; +} + +/*** META ((export vector->list array->list)) */ +function sc_vector2list(a) { + var res = null; + for (var i = a.length-1; i >= 0; i--) + res = sc_cons(a[i], res); + return res; +} + +/*** META ((export list->vector list->array)) */ +function sc_list2vector(l) { + var a = new sc_Vector(); + while(l !== null) { + a.push(l.car); + l = l.cdr; + } + return a; +} + +/*** META ((export vector-fill! array-fill!)) */ +function sc_vectorFillBang(a, fill) { + for (var i = 0; i < a.length; i++) + a[i] = fill; +} + + +/*** META ((export #t)) */ +function sc_copyVector(a, len) { + if (len <= a.length) + return a.slice(0, len); + else { + var tmp = a.concat(); + tmp.length = len; + return tmp; + } +} + +/*** META ((export #t) + (peephole (hole 3 a ".slice(" start "," end ")"))) +*/ +function sc_vectorCopy(a, start, end) { + return a.slice(start, end); +} + +/*** META ((export #t)) */ +function sc_vectorCopyBang(target, tstart, source, sstart, send) { + if (!sstart) sstart = 0; + if (!send) send = source.length; + + // if target == source we don't want to overwrite not yet copied elements. + if (tstart <= sstart) { + for (var i = tstart, j = sstart; j < send; i++, j++) { + target[i] = source[j]; + } + } else { + var diff = send - sstart; + for (var i = tstart + diff - 1, j = send - 1; + j >= sstart; + i--, j--) { + target[i] = source[j]; + } + } + return target; +} + +/*** META ((export #t) + (type bool) + (peephole (hole 1 "typeof " o " === 'function'"))) +*/ +function sc_isProcedure(o) { + return (typeof o === "function"); +} + +/*** META ((export #t)) */ +function sc_apply(proc) { + var args = new Array(); + // first part of arguments are not in list-form. + for (var i = 1; i < arguments.length - 1; i++) + args.push(arguments[i]); + var l = arguments[arguments.length - 1]; + while (l !== null) { + args.push(l.car); + l = l.cdr; + } + return proc.apply(null, args); +} + +/*** META ((export #t)) */ +function sc_map(proc, l1) { + if (l1 === undefined) + return null; + // else + var nbApplyArgs = arguments.length - 1; + var applyArgs = new Array(nbApplyArgs); + var revres = null; + while (l1 !== null) { + for (var i = 0; i < nbApplyArgs; i++) { + applyArgs[i] = arguments[i + 1].car; + arguments[i + 1] = arguments[i + 1].cdr; + } + revres = sc_cons(proc.apply(null, applyArgs), revres); + } + return sc_reverseAppendBang(revres, null); +} + +/*** META ((export #t)) */ +function sc_mapBang(proc, l1) { + if (l1 === undefined) + return null; + // else + var l1_orig = l1; + var nbApplyArgs = arguments.length - 1; + var applyArgs = new Array(nbApplyArgs); + while (l1 !== null) { + var tmp = l1; + for (var i = 0; i < nbApplyArgs; i++) { + applyArgs[i] = arguments[i + 1].car; + arguments[i + 1] = arguments[i + 1].cdr; + } + tmp.car = proc.apply(null, applyArgs); + } + return l1_orig; +} + +/*** META ((export #t)) */ +function sc_forEach(proc, l1) { + if (l1 === undefined) + return undefined; + // else + var nbApplyArgs = arguments.length - 1; + var applyArgs = new Array(nbApplyArgs); + while (l1 !== null) { + for (var i = 0; i < nbApplyArgs; i++) { + applyArgs[i] = arguments[i + 1].car; + arguments[i + 1] = arguments[i + 1].cdr; + } + proc.apply(null, applyArgs); + } + // add return so FF does not complain. + return undefined; +} + +/*** META ((export #t)) */ +function sc_filter(proc, l1) { + var dummy = { cdr : null }; + var tail = dummy; + while (l1 !== null) { + if (proc(l1.car) !== false) { + tail.cdr = sc_cons(l1.car, null); + tail = tail.cdr; + } + l1 = l1.cdr; + } + return dummy.cdr; +} + +/*** META ((export #t)) */ +function sc_filterBang(proc, l1) { + var head = sc_cons("dummy", l1); + var it = head; + var next = l1; + while (next !== null) { + if (proc(next.car) !== false) { + it.cdr = next + it = next; + } + next = next.cdr; + } + it.cdr = null; + return head.cdr; +} + +function sc_filterMap1(proc, l1) { + var revres = null; + while (l1 !== null) { + var tmp = proc(l1.car) + if (tmp !== false) revres = sc_cons(tmp, revres); + l1 = l1.cdr; + } + return sc_reverseAppendBang(revres, null); +} +function sc_filterMap2(proc, l1, l2) { + var revres = null; + while (l1 !== null) { + var tmp = proc(l1.car, l2.car); + if(tmp !== false) revres = sc_cons(tmp, revres); + l1 = l1.cdr; + l2 = l2.cdr + } + return sc_reverseAppendBang(revres, null); +} + +/*** META ((export #t)) */ +function sc_filterMap(proc, l1, l2, l3) { + if (l2 === undefined) + return sc_filterMap1(proc, l1); + else if (l3 === undefined) + return sc_filterMap2(proc, l1, l2); + // else + var nbApplyArgs = arguments.length - 1; + var applyArgs = new Array(nbApplyArgs); + var revres = null; + while (l1 !== null) { + for (var i = 0; i < nbApplyArgs; i++) { + applyArgs[i] = arguments[i + 1].car; + arguments[i + 1] = arguments[i + 1].cdr; + } + var tmp = proc.apply(null, applyArgs); + if(tmp !== false) revres = sc_cons(tmp, revres); + } + return sc_reverseAppendBang(revres, null); +} + +/*** META ((export #t)) */ +function sc_any(proc, l) { + var revres = null; + while (l !== null) { + var tmp = proc(l.car); + if(tmp !== false) return tmp; + l = l.cdr; + } + return false; +} + +/*** META ((export any?) + (peephole (hole 2 "sc_any(" proc "," l ") !== false"))) +*/ +function sc_anyPred(proc, l) { + return sc_any(proc, l)!== false; +} + +/*** META ((export #t)) */ +function sc_every(proc, l) { + var revres = null; + var tmp = true; + while (l !== null) { + tmp = proc(l.car); + if (tmp === false) return false; + l = l.cdr; + } + return tmp; +} + +/*** META ((export every?) + (peephole (hole 2 "sc_every(" proc "," l ") !== false"))) +*/ +function sc_everyPred(proc, l) { + var tmp = sc_every(proc, l); + if (tmp !== false) return true; + return false; +} + +/*** META ((export #t) + (peephole (postfix "()"))) +*/ +function sc_force(o) { + return o(); +} + +/*** META ((export #t)) */ +function sc_makePromise(proc) { + var isResultReady = false; + var result = undefined; + return function() { + if (!isResultReady) { + var tmp = proc(); + if (!isResultReady) { + isResultReady = true; + result = tmp; + } + } + return result; + }; +} + +function sc_Values(values) { + this.values = values; +} + +/*** META ((export #t) + (peephole (values))) +*/ +function sc_values() { + if (arguments.length === 1) + return arguments[0]; + else + return new sc_Values(arguments); +} + +/*** META ((export #t)) */ +function sc_callWithValues(producer, consumer) { + var produced = producer(); + if (produced instanceof sc_Values) + return consumer.apply(null, produced.values); + else + return consumer(produced); +} + +/*** META ((export #t)) */ +function sc_dynamicWind(before, thunk, after) { + before(); + try { + var res = thunk(); + return res; + } finally { + after(); + } +} + + +// TODO: eval/scheme-report-environment/null-environment/interaction-environment + +// LIMITATION: 'load' doesn't exist without files. +// LIMITATION: transcript-on/transcript-off doesn't exist without files. + + +function sc_Struct(name) { + this.name = name; +} +sc_Struct.prototype.sc_toDisplayString = function() { + return "#"; +}; +sc_Struct.prototype.sc_toWriteString = sc_Struct.prototype.sc_toDisplayString; + +/*** META ((export #t) + (peephole (hole 1 "new sc_Struct(" name ")"))) +*/ +function sc_makeStruct(name) { + return new sc_Struct(name); +} + +/*** META ((export #t) + (type bool) + (peephole (postfix " instanceof sc_Struct"))) +*/ +function sc_isStruct(o) { + return (o instanceof sc_Struct); +} + +/*** META ((export #t) + (type bool) + (peephole (hole 2 "(" 1 " instanceof sc_Struct) && ( " 1 ".name === " 0 ")"))) +*/ +function sc_isStructNamed(name, s) { + return ((s instanceof sc_Struct) && (s.name === name)); +} + +/*** META ((export struct-field) + (peephole (hole 3 0 "[" 2 "]"))) +*/ +function sc_getStructField(s, name, field) { + return s[field]; +} + +/*** META ((export struct-field-set!) + (peephole (hole 4 0 "[" 2 "] = " 3))) +*/ +function sc_setStructFieldBang(s, name, field, val) { + s[field] = val; +} + +/*** META ((export #t) + (peephole (prefix "~"))) +*/ +function sc_bitNot(x) { + return ~x; +} + +/*** META ((export #t) + (peephole (infix 2 2 "&"))) +*/ +function sc_bitAnd(x, y) { + return x & y; +} + +/*** META ((export #t) + (peephole (infix 2 2 "|"))) +*/ +function sc_bitOr(x, y) { + return x | y; +} + +/*** META ((export #t) + (peephole (infix 2 2 "^"))) +*/ +function sc_bitXor(x, y) { + return x ^ y; +} + +/*** META ((export #t) + (peephole (infix 2 2 "<<"))) +*/ +function sc_bitLsh(x, y) { + return x << y; +} + +/*** META ((export #t) + (peephole (infix 2 2 ">>"))) +*/ +function sc_bitRsh(x, y) { + return x >> y; +} + +/*** META ((export #t) + (peephole (infix 2 2 ">>>"))) +*/ +function sc_bitUrsh(x, y) { + return x >>> y; +} + +/*** META ((export js-field js-property) + (peephole (hole 2 o "[" field "]"))) +*/ +function sc_jsField(o, field) { + return o[field]; +} + +/*** META ((export js-field-set! js-property-set!) + (peephole (hole 3 o "[" field "] = " val))) +*/ +function sc_setJsFieldBang(o, field, val) { + return o[field] = val; +} + +/*** META ((export js-field-delete! js-property-delete!) + (peephole (hole 2 "delete" o "[" field "]"))) +*/ +function sc_deleteJsFieldBang(o, field) { + delete o[field]; +} + +/*** META ((export #t) + (peephole (jsCall))) +*/ +function sc_jsCall(o, fun) { + var args = new Array(); + for (var i = 2; i < arguments.length; i++) + args[i-2] = arguments[i]; + return fun.apply(o, args); +} + +/*** META ((export #t) + (peephole (jsMethodCall))) +*/ +function sc_jsMethodCall(o, field) { + var args = new Array(); + for (var i = 2; i < arguments.length; i++) + args[i-2] = arguments[i]; + return o[field].apply(o, args); +} + +/*** META ((export new js-new) + (peephole (jsNew))) +*/ +function sc_jsNew(c) { + var evalStr = "new c("; + evalStr +=arguments.length > 1? "arguments[1]": ""; + for (var i = 2; i < arguments.length; i++) + evalStr += ", arguments[" + i + "]"; + evalStr +=")"; + return eval(evalStr); +} + +// ======================== RegExp ==================== +/*** META ((export #t)) */ +function sc_pregexp(re) { + return new RegExp(sc_string2jsstring(re)); +} + +/*** META ((export #t)) */ +function sc_pregexpMatch(re, s) { + var reg = (re instanceof RegExp) ? re : sc_pregexp(re); + var tmp = reg.exec(sc_string2jsstring(s)); + + if (tmp == null) return false; + + var res = null; + for (var i = tmp.length-1; i >= 0; i--) { + if (tmp[i] !== null) { + res = sc_cons(sc_jsstring2string(tmp[i]), res); + } else { + res = sc_cons(false, res); + } + } + return res; +} + +/*** META ((export #t)) */ +function sc_pregexpReplace(re, s1, s2) { + var reg; + var jss1 = sc_string2jsstring(s1); + var jss2 = sc_string2jsstring(s2); + + if (re instanceof RegExp) { + if (re.global) + reg = re; + else + reg = new RegExp(re.source); + } else { + reg = new RegExp(sc_string2jsstring(re)); + } + + return jss1.replace(reg, jss2); +} + +/*** META ((export pregexp-replace*)) */ +function sc_pregexpReplaceAll(re, s1, s2) { + var reg; + var jss1 = sc_string2jsstring(s1); + var jss2 = sc_string2jsstring(s2); + + if (re instanceof RegExp) { + if (re.global) + reg = re; + else + reg = new RegExp(re.source, "g"); + } else { + reg = new RegExp(sc_string2jsstring(re), "g"); + } + + return jss1.replace(reg, jss2); +} + +/*** META ((export #t)) */ +function sc_pregexpSplit(re, s) { + var reg = ((re instanceof RegExp) ? + re : + new RegExp(sc_string2jsstring(re))); + var jss = sc_string2jsstring(s); + var tmp = jss.split(reg); + + if (tmp == null) return false; + + return sc_vector2list(tmp); +} + + +/* =========================================================================== */ +/* Other library stuff */ +/* =========================================================================== */ + +/*** META ((export #t) + (peephole (hole 1 "Math.floor(Math.random()*" 'n ")"))) +*/ +function sc_random(n) { + return Math.floor(Math.random()*n); +} + +/*** META ((export current-date) + (peephole (hole 0 "new Date()"))) +*/ +function sc_currentDate() { + return new Date(); +} + +function sc_Hashtable() { +} +sc_Hashtable.prototype.toString = function() { + return "#{%hashtable}"; +}; +// sc_toWriteString == sc_toDisplayString == toString + +function sc_HashtableElement(key, val) { + this.key = key; + this.val = val; +} + +/*** META ((export #t) + (peephole (hole 0 "new sc_Hashtable()"))) +*/ +function sc_makeHashtable() { + return new sc_Hashtable(); +} + +/*** META ((export #t)) */ +function sc_hashtablePutBang(ht, key, val) { + var hash = sc_hash(key); + ht[hash] = new sc_HashtableElement(key, val); +} + +/*** META ((export #t)) */ +function sc_hashtableGet(ht, key) { + var hash = sc_hash(key); + if (hash in ht) + return ht[hash].val; + else + return false; +} + +/*** META ((export #t)) */ +function sc_hashtableForEach(ht, f) { + for (var v in ht) { + if (ht[v] instanceof sc_HashtableElement) + f(ht[v].key, ht[v].val); + } +} + +/*** META ((export hashtable-contains?) + (peephole (hole 2 "sc_hash(" 1 ") in " 0))) +*/ +function sc_hashtableContains(ht, key) { + var hash = sc_hash(key); + if (hash in ht) + return true; + else + return false; +} + +var SC_HASH_COUNTER = 0; + +function sc_hash(o) { + if (o === null) + return "null"; + else if (o === undefined) + return "undefined"; + else if (o === true) + return "true"; + else if (o === false) + return "false"; + else if (typeof o === "number") + return "num-" + o; + else if (typeof o === "string") + return "jsstr-" + o; + else if (o.sc_getHash) + return o.sc_getHash(); + else + return sc_counterHash.call(o); +} +function sc_counterHash() { + if (!this.sc_hash) { + this.sc_hash = "hash-" + SC_HASH_COUNTER; + SC_HASH_COUNTER++; + } + return this.sc_hash; +} + +function sc_Trampoline(args, maxTailCalls) { + this['__trampoline return__'] = true; + this.args = args; + this.MAX_TAIL_CALLs = maxTailCalls; +} +// TODO: call/cc stuff +sc_Trampoline.prototype.restart = function() { + var o = this; + while (true) { + // set both globals. + SC_TAIL_OBJECT.calls = o.MAX_TAIL_CALLs-1; + var fun = o.args.callee; + var res = fun.apply(SC_TAIL_OBJECT, o.args); + if (res instanceof sc_Trampoline) + o = res; + else + return res; + } +} + +/*** META ((export bind-exit-lambda)) */ +function sc_bindExitLambda(proc) { + var escape_obj = new sc_BindExitException(); + var escape = function(res) { + escape_obj.res = res; + throw escape_obj; + }; + try { + return proc(escape); + } catch(e) { + if (e === escape_obj) { + return e.res; + } + throw e; + } +} +function sc_BindExitException() { + this._internalException = true; +} + +var SC_SCM2JS_GLOBALS = new Object(); + +// default tail-call depth. +// normally the program should set it again. but just in case... +var SC_TAIL_OBJECT = new Object(); +SC_SCM2JS_GLOBALS.TAIL_OBJECT = SC_TAIL_OBJECT; +// ======================== I/O ======================= + +/*------------------------------------------------------------------*/ + +function sc_EOF() { +} +var SC_EOF_OBJECT = new sc_EOF(); + +function sc_Port() { +} + +/* --------------- Input ports -------------------------------------*/ + +function sc_InputPort() { +} +sc_InputPort.prototype = new sc_Port(); + +sc_InputPort.prototype.peekChar = function() { + if (!("peeked" in this)) + this.peeked = this.getNextChar(); + return this.peeked; +} +sc_InputPort.prototype.readChar = function() { + var tmp = this.peekChar(); + delete this.peeked; + return tmp; +} +sc_InputPort.prototype.isCharReady = function() { + return true; +} +sc_InputPort.prototype.close = function() { + // do nothing +} + +/* .............. String port ..........................*/ +function sc_ErrorInputPort() { +}; +sc_ErrorInputPort.prototype = new sc_InputPort(); +sc_ErrorInputPort.prototype.getNextChar = function() { + throw "can't read from error-port."; +}; +sc_ErrorInputPort.prototype.isCharReady = function() { + return false; +}; + + +/* .............. String port ..........................*/ + +function sc_StringInputPort(jsStr) { + // we are going to do some charAts on the str. + // instead of recreating all the time a String-object, we + // create one in the beginning. (not sure, if this is really an optim) + this.str = new String(jsStr); + this.pos = 0; +} +sc_StringInputPort.prototype = new sc_InputPort(); +sc_StringInputPort.prototype.getNextChar = function() { + if (this.pos >= this.str.length) + return SC_EOF_OBJECT; + return this.str.charAt(this.pos++); +}; + +/* ------------- Read and other lib-funs -------------------------------*/ +function sc_Token(type, val, pos) { + this.type = type; + this.val = val; + this.pos = pos; +} +sc_Token.EOF = 0/*EOF*/; +sc_Token.OPEN_PAR = 1/*OPEN_PAR*/; +sc_Token.CLOSE_PAR = 2/*CLOSE_PAR*/; +sc_Token.OPEN_BRACE = 3/*OPEN_BRACE*/; +sc_Token.CLOSE_BRACE = 4/*CLOSE_BRACE*/; +sc_Token.OPEN_BRACKET = 5/*OPEN_BRACKET*/; +sc_Token.CLOSE_BRACKET = 6/*CLOSE_BRACKET*/; +sc_Token.WHITESPACE = 7/*WHITESPACE*/; +sc_Token.QUOTE = 8/*QUOTE*/; +sc_Token.ID = 9/*ID*/; +sc_Token.DOT = 10/*DOT*/; +sc_Token.STRING = 11/*STRING*/; +sc_Token.NUMBER = 12/*NUMBER*/; +sc_Token.ERROR = 13/*ERROR*/; +sc_Token.VECTOR_BEGIN = 14/*VECTOR_BEGIN*/; +sc_Token.TRUE = 15/*TRUE*/; +sc_Token.FALSE = 16/*FALSE*/; +sc_Token.UNSPECIFIED = 17/*UNSPECIFIED*/; +sc_Token.REFERENCE = 18/*REFERENCE*/; +sc_Token.STORE = 19/*STORE*/; +sc_Token.CHAR = 20/*CHAR*/; + +var SC_ID_CLASS = SC_LOWER_CLASS + SC_UPPER_CLASS + "!$%*+-./:<=>?@^_~"; +function sc_Tokenizer(port) { + this.port = port; +} +sc_Tokenizer.prototype.peekToken = function() { + if (this.peeked) + return this.peeked; + var newToken = this.nextToken(); + this.peeked = newToken; + return newToken; +}; +sc_Tokenizer.prototype.readToken = function() { + var tmp = this.peekToken(); + delete this.peeked; + return tmp; +}; +sc_Tokenizer.prototype.nextToken = function() { + var port = this.port; + + function isNumberChar(c) { + return (c >= "0" && c <= "9"); + }; + function isIdOrNumberChar(c) { + return SC_ID_CLASS.indexOf(c) != -1 || // ID-char + (c >= "0" && c <= "9"); + } + function isWhitespace(c) { + return c === " " || c === "\r" || c === "\n" || c === "\t" || c === "\f"; + }; + function isWhitespaceOrEOF(c) { + return isWhitespace(c) || c === SC_EOF_OBJECT; + }; + + function readString() { + res = ""; + while (true) { + var c = port.readChar(); + switch (c) { + case '"': + return new sc_Token(11/*STRING*/, res); + case "\\": + var tmp = port.readChar(); + switch (tmp) { + case '0': res += "\0"; break; + case 'a': res += "\a"; break; + case 'b': res += "\b"; break; + case 'f': res += "\f"; break; + case 'n': res += "\n"; break; + case 'r': res += "\r"; break; + case 't': res += "\t"; break; + case 'v': res += "\v"; break; + case '"': res += '"'; break; + case '\\': res += '\\'; break; + case 'x': + /* hexa-number */ + var nb = 0; + while (true) { + var hexC = port.peekChar(); + if (hexC >= '0' && hexC <= '9') { + port.readChar(); + nb = nb * 16 + hexC.charCodeAt(0) - '0'.charCodeAt(0); + } else if (hexC >= 'a' && hexC <= 'f') { + port.readChar(); + nb = nb * 16 + hexC.charCodeAt(0) - 'a'.charCodeAt(0); + } else if (hexC >= 'A' && hexC <= 'F') { + port.readChar(); + nb = nb * 16 + hexC.charCodeAt(0) - 'A'.charCodeAt(0); + } else { + // next char isn't part of hex. + res += String.fromCharCode(nb); + break; + } + } + break; + default: + if (tmp === SC_EOF_OBJECT) { + return new sc_Token(13/*ERROR*/, "unclosed string-literal" + res); + } + res += tmp; + } + break; + default: + if (c === SC_EOF_OBJECT) { + return new sc_Token(13/*ERROR*/, "unclosed string-literal" + res); + } + res += c; + } + } + }; + function readIdOrNumber(firstChar) { + var res = firstChar; + while (isIdOrNumberChar(port.peekChar())) + res += port.readChar(); + if (isNaN(res)) + return new sc_Token(9/*ID*/, res); + else + return new sc_Token(12/*NUMBER*/, res - 0); + }; + + function skipWhitespaceAndComments() { + var done = false; + while (!done) { + done = true; + while (isWhitespace(port.peekChar())) + port.readChar(); + if (port.peekChar() === ';') { + port.readChar(); + done = false; + while (true) { + curChar = port.readChar(); + if (curChar === SC_EOF_OBJECT || + curChar === '\n') + break; + } + } + } + }; + + function readDot() { + if (isWhitespace(port.peekChar())) + return new sc_Token(10/*DOT*/); + else + return readIdOrNumber("."); + }; + + function readSharp() { + var c = port.readChar(); + if (isWhitespace(c)) + return new sc_Token(13/*ERROR*/, "bad #-pattern0."); + + // reference + if (isNumberChar(c)) { + var nb = c - 0; + while (isNumberChar(port.peekChar())) + nb = nb*10 + (port.readChar() - 0); + switch (port.readChar()) { + case '#': + return new sc_Token(18/*REFERENCE*/, nb); + case '=': + return new sc_Token(19/*STORE*/, nb); + default: + return new sc_Token(13/*ERROR*/, "bad #-pattern1." + nb); + } + } + + if (c === "(") + return new sc_Token(14/*VECTOR_BEGIN*/); + + if (c === "\\") { // character + var tmp = "" + while (!isWhitespaceOrEOF(port.peekChar())) + tmp += port.readChar(); + switch (tmp.length) { + case 0: // it's escaping a whitespace char: + if (sc_isEOFObject(port.peekChar)) + return new sc_Token(13/*ERROR*/, "bad #-pattern2."); + else + return new sc_Token(20/*CHAR*/, port.readChar()); + case 1: + return new sc_Token(20/*CHAR*/, tmp); + default: + var entry = sc_Char.readable2char[tmp.toLowerCase()]; + if (entry) + return new sc_Token(20/*CHAR*/, entry); + else + return new sc_Token(13/*ERROR*/, "unknown character description: #\\" + tmp); + } + } + + // some constants (#t, #f, #unspecified) + var res; + var needing; + switch (c) { + case 't': res = new sc_Token(15/*TRUE*/, true); needing = ""; break; + case 'f': res = new sc_Token(16/*FALSE*/, false); needing = ""; break; + case 'u': res = new sc_Token(17/*UNSPECIFIED*/, undefined); needing = "nspecified"; break; + default: + return new sc_Token(13/*ERROR*/, "bad #-pattern3: " + c); + } + while(true) { + c = port.peekChar(); + if ((isWhitespaceOrEOF(c) || c === ')') && + needing == "") + return res; + else if (isWhitespace(c) || needing == "") + return new sc_Token(13/*ERROR*/, "bad #-pattern4 " + c + " " + needing); + else if (needing.charAt(0) == c) { + port.readChar(); // consume + needing = needing.slice(1); + } else + return new sc_Token(13/*ERROR*/, "bad #-pattern5"); + } + + }; + + skipWhitespaceAndComments(); + var curChar = port.readChar(); + if (curChar === SC_EOF_OBJECT) + return new sc_Token(0/*EOF*/, curChar); + switch (curChar) + { + case " ": + case "\n": + case "\t": + return readWhitespace(); + case "(": + return new sc_Token(1/*OPEN_PAR*/); + case ")": + return new sc_Token(2/*CLOSE_PAR*/); + case "{": + return new sc_Token(3/*OPEN_BRACE*/); + case "}": + return new sc_Token(4/*CLOSE_BRACE*/); + case "[": + return new sc_Token(5/*OPEN_BRACKET*/); + case "]": + return new sc_Token(6/*CLOSE_BRACKET*/); + case "'": + return new sc_Token(8/*QUOTE*/); + case "#": + return readSharp(); + case ".": + return readDot(); + case '"': + return readString(); + default: + if (isIdOrNumberChar(curChar)) + return readIdOrNumber(curChar); + throw "unexpected character: " + curChar; + } +}; + +function sc_Reader(tokenizer) { + this.tokenizer = tokenizer; + this.backref = new Array(); +} +sc_Reader.prototype.read = function() { + function readList(listBeginType) { + function matchesPeer(open, close) { + return open === 1/*OPEN_PAR*/ && close === 2/*CLOSE_PAR*/ + || open === 3/*OPEN_BRACE*/ && close === 4/*CLOSE_BRACE*/ + || open === 5/*OPEN_BRACKET*/ && close === 6/*CLOSE_BRACKET*/; + }; + var res = null; + + while (true) { + var token = tokenizer.peekToken(); + + switch (token.type) { + case 2/*CLOSE_PAR*/: + case 4/*CLOSE_BRACE*/: + case 6/*CLOSE_BRACKET*/: + if (matchesPeer(listBeginType, token.type)) { + tokenizer.readToken(); // consume token + return sc_reverseBang(res); + } else + throw "closing par doesn't match: " + listBeginType + + " " + listEndType; + + case 0/*EOF*/: + throw "unexpected end of file"; + + case 10/*DOT*/: + tokenizer.readToken(); // consume token + var cdr = this.read(); + var par = tokenizer.readToken(); + if (!matchesPeer(listBeginType, par.type)) + throw "closing par doesn't match: " + listBeginType + + " " + par.type; + else + return sc_reverseAppendBang(res, cdr); + + + default: + res = sc_cons(this.read(), res); + } + } + }; + function readQuote() { + return sc_cons("quote", sc_cons(this.read(), null)); + }; + function readVector() { + // opening-parenthesis is already consumed + var a = new Array(); + while (true) { + var token = tokenizer.peekToken(); + switch (token.type) { + case 2/*CLOSE_PAR*/: + tokenizer.readToken(); + return a; + + default: + a.push(this.read()); + } + } + }; + + function storeRefence(nb) { + var tmp = this.read(); + this.backref[nb] = tmp; + return tmp; + }; + + function readReference(nb) { + if (nb in this.backref) + return this.backref[nb]; + else + throw "bad reference: " + nb; + }; + + var tokenizer = this.tokenizer; + + var token = tokenizer.readToken(); + + // handle error + if (token.type === 13/*ERROR*/) + throw token.val; + + switch (token.type) { + case 1/*OPEN_PAR*/: + case 3/*OPEN_BRACE*/: + case 5/*OPEN_BRACKET*/: + return readList.call(this, token.type); + case 8/*QUOTE*/: + return readQuote.call(this); + case 11/*STRING*/: + return sc_jsstring2string(token.val); + case 20/*CHAR*/: + return new sc_Char(token.val); + case 14/*VECTOR_BEGIN*/: + return readVector.call(this); + case 18/*REFERENCE*/: + return readReference.call(this, token.val); + case 19/*STORE*/: + return storeRefence.call(this, token.val); + case 9/*ID*/: + return sc_jsstring2symbol(token.val); + case 0/*EOF*/: + case 12/*NUMBER*/: + case 15/*TRUE*/: + case 16/*FALSE*/: + case 17/*UNSPECIFIED*/: + return token.val; + default: + throw "unexpected token " + token.type + " " + token.val; + } +}; + +/*** META ((export #t)) */ +function sc_read(port) { + if (port === undefined) // we assume the port hasn't been given. + port = SC_DEFAULT_IN; // THREAD: shared var... + var reader = new sc_Reader(new sc_Tokenizer(port)); + return reader.read(); +} +/*** META ((export #t)) */ +function sc_readChar(port) { + if (port === undefined) // we assume the port hasn't been given. + port = SC_DEFAULT_IN; // THREAD: shared var... + var t = port.readChar(); + return t === SC_EOF_OBJECT? t: new sc_Char(t); +} +/*** META ((export #t)) */ +function sc_peekChar(port) { + if (port === undefined) // we assume the port hasn't been given. + port = SC_DEFAULT_IN; // THREAD: shared var... + var t = port.peekChar(); + return t === SC_EOF_OBJECT? t: new sc_Char(t); +} +/*** META ((export #t) + (type bool)) +*/ +function sc_isCharReady(port) { + if (port === undefined) // we assume the port hasn't been given. + port = SC_DEFAULT_IN; // THREAD: shared var... + return port.isCharReady(); +} +/*** META ((export #t) + (peephole (postfix ".close()"))) +*/ +function sc_closeInputPort(p) { + return p.close(); +} + +/*** META ((export #t) + (type bool) + (peephole (postfix " instanceof sc_InputPort"))) +*/ +function sc_isInputPort(o) { + return (o instanceof sc_InputPort); +} + +/*** META ((export eof-object?) + (type bool) + (peephole (postfix " === SC_EOF_OBJECT"))) +*/ +function sc_isEOFObject(o) { + return o === SC_EOF_OBJECT; +} + +/*** META ((export #t) + (peephole (hole 0 "SC_DEFAULT_IN"))) +*/ +function sc_currentInputPort() { + return SC_DEFAULT_IN; +} + +/* ------------ file operations are not supported -----------*/ +/*** META ((export #t)) */ +function sc_callWithInputFile(s, proc) { + throw "can't open " + s; +} + +/*** META ((export #t)) */ +function sc_callWithOutputFile(s, proc) { + throw "can't open " + s; +} + +/*** META ((export #t)) */ +function sc_withInputFromFile(s, thunk) { + throw "can't open " + s; +} + +/*** META ((export #t)) */ +function sc_withOutputToFile(s, thunk) { + throw "can't open " + s; +} + +/*** META ((export #t)) */ +function sc_openInputFile(s) { + throw "can't open " + s; +} + +/*** META ((export #t)) */ +function sc_openOutputFile(s) { + throw "can't open " + s; +} + +/* ----------------------------------------------------------------------------*/ +/*** META ((export #t)) */ +function sc_basename(p) { + var i = p.lastIndexOf('/'); + + if(i >= 0) + return p.substring(i + 1, p.length); + else + return ''; +} + +/*** META ((export #t)) */ +function sc_dirname(p) { + var i = p.lastIndexOf('/'); + + if(i >= 0) + return p.substring(0, i); + else + return ''; +} + +/* ----------------------------------------------------------------------------*/ + +/*** META ((export #t)) */ +function sc_withInputFromPort(p, thunk) { + try { + var tmp = SC_DEFAULT_IN; // THREAD: shared var. + SC_DEFAULT_IN = p; + return thunk(); + } finally { + SC_DEFAULT_IN = tmp; + } +} + +/*** META ((export #t)) */ +function sc_withInputFromString(s, thunk) { + return sc_withInputFromPort(new sc_StringInputPort(sc_string2jsstring(s)), thunk); +} + +/*** META ((export #t)) */ +function sc_withOutputToPort(p, thunk) { + try { + var tmp = SC_DEFAULT_OUT; // THREAD: shared var. + SC_DEFAULT_OUT = p; + return thunk(); + } finally { + SC_DEFAULT_OUT = tmp; + } +} + +/*** META ((export #t)) */ +function sc_withOutputToString(thunk) { + var p = new sc_StringOutputPort(); + sc_withOutputToPort(p, thunk); + return p.close(); +} + +/*** META ((export #t)) */ +function sc_withOutputToProcedure(proc, thunk) { + var t = function(s) { proc(sc_jsstring2string(s)); }; + return sc_withOutputToPort(new sc_GenericOutputPort(t), thunk); +} + +/*** META ((export #t) + (peephole (hole 0 "new sc_StringOutputPort()"))) +*/ +function sc_openOutputString() { + return new sc_StringOutputPort(); +} + +/*** META ((export #t)) */ +function sc_openInputString(str) { + return new sc_StringInputPort(sc_string2jsstring(str)); +} + +/* ----------------------------------------------------------------------------*/ + +function sc_OutputPort() { +} +sc_OutputPort.prototype = new sc_Port(); +sc_OutputPort.prototype.appendJSString = function(obj) { + /* do nothing */ +} +sc_OutputPort.prototype.close = function() { + /* do nothing */ +} + +function sc_StringOutputPort() { + this.res = ""; +} +sc_StringOutputPort.prototype = new sc_OutputPort(); +sc_StringOutputPort.prototype.appendJSString = function(s) { + this.res += s; +} +sc_StringOutputPort.prototype.close = function() { + return sc_jsstring2string(this.res); +} + +/*** META ((export #t)) */ +function sc_getOutputString(sp) { + return sc_jsstring2string(sp.res); +} + + +function sc_ErrorOutputPort() { +} +sc_ErrorOutputPort.prototype = new sc_OutputPort(); +sc_ErrorOutputPort.prototype.appendJSString = function(s) { + throw "don't write on ErrorPort!"; +} +sc_ErrorOutputPort.prototype.close = function() { + /* do nothing */ +} + +function sc_GenericOutputPort(appendJSString, close) { + this.appendJSString = appendJSString; + if (close) + this.close = close; +} +sc_GenericOutputPort.prototype = new sc_OutputPort(); + +/*** META ((export #t) + (type bool) + (peephole (postfix " instanceof sc_OutputPort"))) +*/ +function sc_isOutputPort(o) { + return (o instanceof sc_OutputPort); +} + +/*** META ((export #t) + (peephole (postfix ".close()"))) +*/ +function sc_closeOutputPort(p) { + return p.close(); +} + +/* ------------------ write ---------------------------------------------------*/ + +/*** META ((export #t)) */ +function sc_write(o, p) { + if (p === undefined) // we assume not given + p = SC_DEFAULT_OUT; + p.appendJSString(sc_toWriteString(o)); +} + +function sc_toWriteString(o) { + if (o === null) + return "()"; + else if (o === true) + return "#t"; + else if (o === false) + return "#f"; + else if (o === undefined) + return "#unspecified"; + else if (typeof o === 'function') + return "#"; + else if (o.sc_toWriteString) + return o.sc_toWriteString(); + else + return o.toString(); +} + +function sc_escapeWriteString(s) { + var res = ""; + var j = 0; + for (i = 0; i < s.length; i++) { + switch (s.charAt(i)) { + case "\0": res += s.substring(j, i) + "\\0"; j = i + 1; break; + case "\b": res += s.substring(j, i) + "\\b"; j = i + 1; break; + case "\f": res += s.substring(j, i) + "\\f"; j = i + 1; break; + case "\n": res += s.substring(j, i) + "\\n"; j = i + 1; break; + case "\r": res += s.substring(j, i) + "\\r"; j = i + 1; break; + case "\t": res += s.substring(j, i) + "\\t"; j = i + 1; break; + case "\v": res += s.substring(j, i) + "\\v"; j = i + 1; break; + case '"': res += s.substring(j, i) + '\\"'; j = i + 1; break; + case "\\": res += s.substring(j, i) + "\\\\"; j = i + 1; break; + default: + var c = s.charAt(i); + if ("\a" !== "a" && c == "\a") { + res += s.substring(j, i) + "\\a"; j = i + 1; continue; + } + if ("\v" !== "v" && c == "\v") { + res += s.substring(j, i) + "\\v"; j = i + 1; continue; + } + //if (s.charAt(i) < ' ' || s.charCodeAt(i) > 127) { + // CARE: Manuel is this OK with HOP? + if (s.charAt(i) < ' ') { + /* non printable character and special chars */ + res += s.substring(j, i) + "\\x" + s.charCodeAt(i).toString(16); + j = i + 1; + } + // else just let i increase... + } + } + res += s.substring(j, i); + return res; +} + +/* ------------------ display ---------------------------------------------------*/ + +/*** META ((export #t)) */ +function sc_display(o, p) { + if (p === undefined) // we assume not given + p = SC_DEFAULT_OUT; + p.appendJSString(sc_toDisplayString(o)); +} + +function sc_toDisplayString(o) { + if (o === null) + return "()"; + else if (o === true) + return "#t"; + else if (o === false) + return "#f"; + else if (o === undefined) + return "#unspecified"; + else if (typeof o === 'function') + return "#"; + else if (o.sc_toDisplayString) + return o.sc_toDisplayString(); + else + return o.toString(); +} + +/* ------------------ newline ---------------------------------------------------*/ + +/*** META ((export #t)) */ +function sc_newline(p) { + if (p === undefined) // we assume not given + p = SC_DEFAULT_OUT; + p.appendJSString("\n"); +} + +/* ------------------ write-char ---------------------------------------------------*/ + +/*** META ((export #t)) */ +function sc_writeChar(c, p) { + if (p === undefined) // we assume not given + p = SC_DEFAULT_OUT; + p.appendJSString(c.val); +} + +/* ------------------ write-circle ---------------------------------------------------*/ + +/*** META ((export #t)) */ +function sc_writeCircle(o, p) { + if (p === undefined) // we assume not given + p = SC_DEFAULT_OUT; + p.appendJSString(sc_toWriteCircleString(o)); +} + +function sc_toWriteCircleString(o) { + var symb = sc_gensym("writeCircle"); + var nbPointer = new Object(); + nbPointer.nb = 0; + sc_prepWriteCircle(o, symb, nbPointer); + return sc_genToWriteCircleString(o, symb); +} + +function sc_prepWriteCircle(o, symb, nbPointer) { + // TODO sc_Struct + if (o instanceof sc_Pair || + o instanceof sc_Vector) { + if (o[symb] !== undefined) { + // not the first visit. + o[symb]++; + // unless there is already a number, assign one. + if (!o[symb + "nb"]) o[symb + "nb"] = nbPointer.nb++; + return; + } + o[symb] = 0; + if (o instanceof sc_Pair) { + sc_prepWriteCircle(o.car, symb, nbPointer); + sc_prepWriteCircle(o.cdr, symb, nbPointer); + } else { + for (var i = 0; i < o.length; i++) + sc_prepWriteCircle(o[i], symb, nbPointer); + } + } +} + +function sc_genToWriteCircleString(o, symb) { + if (!(o instanceof sc_Pair || + o instanceof sc_Vector)) + return sc_toWriteString(o); + return o.sc_toWriteCircleString(symb); +} +sc_Pair.prototype.sc_toWriteCircleString = function(symb, inList) { + if (this[symb + "use"]) { // use-flag is set. Just use it. + var nb = this[symb + "nb"]; + if (this[symb]-- === 0) { // if we are the last use. remove all fields. + delete this[symb]; + delete this[symb + "nb"]; + delete this[symb + "use"]; + } + if (inList) + return '. #' + nb + '#'; + else + return '#' + nb + '#'; + } + if (this[symb]-- === 0) { // if we are the last use. remove all fields. + delete this[symb]; + delete this[symb + "nb"]; + delete this[symb + "use"]; + } + + var res = ""; + + if (this[symb] !== undefined) { // implies > 0 + this[symb + "use"] = true; + if (inList) + res += '. #' + this[symb + "nb"] + '='; + else + res += '#' + this[symb + "nb"] + '='; + inList = false; + } + + if (!inList) + res += "("; + + // print car + res += sc_genToWriteCircleString(this.car, symb); + + if (sc_isPair(this.cdr)) { + res += " " + this.cdr.sc_toWriteCircleString(symb, true); + } else if (this.cdr !== null) { + res += " . " + sc_genToWriteCircleString(this.cdr, symb); + } + if (!inList) + res += ")"; + return res; +}; +sc_Vector.prototype.sc_toWriteCircleString = function(symb) { + if (this[symb + "use"]) { // use-flag is set. Just use it. + var nb = this[symb + "nb"]; + if (this[symb]-- === 0) { // if we are the last use. remove all fields. + delete this[symb]; + delete this[symb + "nb"]; + delete this[symb + "use"]; + } + return '#' + nb + '#'; + } + if (this[symb]-- === 0) { // if we are the last use. remove all fields. + delete this[symb]; + delete this[symb + "nb"]; + delete this[symb + "use"]; + } + + var res = ""; + if (this[symb] !== undefined) { // implies > 0 + this[symb + "use"] = true; + res += '#' + this[symb + "nb"] + '='; + } + res += "#("; + for (var i = 0; i < this.length; i++) { + res += sc_genToWriteCircleString(this[i], symb); + if (i < this.length - 1) res += " "; + } + res += ")"; + return res; +}; + + +/* ------------------ print ---------------------------------------------------*/ + +/*** META ((export #t)) */ +function sc_print(s) { + if (arguments.length === 1) { + sc_display(s); + sc_newline(); + } + else { + for (var i = 0; i < arguments.length; i++) + sc_display(arguments[i]); + sc_newline(); + } +} + +/* ------------------ format ---------------------------------------------------*/ +/*** META ((export #t)) */ +function sc_format(s, args) { + var len = s.length; + var p = new sc_StringOutputPort(); + var i = 0, j = 1; + + while( i < len ) { + var i2 = s.indexOf("~", i); + + if (i2 == -1) { + p.appendJSString( s.substring( i, len ) ); + return p.close(); + } else { + if (i2 > i) { + if (i2 == (len - 1)) { + p.appendJSString(s.substring(i, len)); + return p.close(); + } else { + p.appendJSString(s.substring(i, i2)); + i = i2; + } + } + + switch(s.charCodeAt(i2 + 1)) { + case 65: + case 97: + // a + sc_display(arguments[j], p); + i += 2; j++; + break; + + case 83: + case 115: + // s + sc_write(arguments[j], p); + i += 2; j++; + break; + + case 86: + case 118: + // v + sc_display(arguments[j], p); + p.appendJSString("\n"); + i += 2; j++; + break; + + case 67: + case 99: + // c + p.appendJSString(String.fromCharCode(arguments[j])); + i += 2; j++; + break; + + case 88: + case 120: + // x + p.appendJSString(arguments[j].toString(6)); + i += 2; j++; + break; + + case 79: + case 111: + // o + p.appendJSString(arguments[j].toString(8)); + i += 2; j++; + break; + + case 66: + case 98: + // b + p.appendJSString(arguments[j].toString(2)); + i += 2; j++; + break; + + case 37: + case 110: + // %, n + p.appendJSString("\n"); + i += 2; break; + + case 114: + // r + p.appendJSString("\r"); + i += 2; break; + + case 126: + // ~ + p.appendJSString("~"); + i += 2; break; + + default: + sc_error( "format: illegal ~" + + String.fromCharCode(s.charCodeAt(i2 + 1)) + + " sequence" ); + return ""; + } + } + } + + return p.close(); +} + +/* ------------------ global ports ---------------------------------------------------*/ + +var SC_DEFAULT_IN = new sc_ErrorInputPort(); +var SC_DEFAULT_OUT = new sc_ErrorOutputPort(); +var SC_ERROR_OUT = new sc_ErrorOutputPort(); + +var sc_SYMBOL_PREFIX = "\u1E9C"; +var sc_KEYWORD_PREFIX = "\u1E9D"; + +/*** META ((export #t) + (peephole (id))) */ +function sc_jsstring2string(s) { + return s; +} + +/*** META ((export #t) + (peephole (prefix "'\\u1E9C' +"))) +*/ +function sc_jsstring2symbol(s) { + return sc_SYMBOL_PREFIX + s; +} + +/*** META ((export #t) + (peephole (id))) +*/ +function sc_string2jsstring(s) { + return s; +} + +/*** META ((export #t) + (peephole (symbol2jsstring_immutable))) +*/ +function sc_symbol2jsstring(s) { + return s.slice(1); +} + +/*** META ((export #t) + (peephole (postfix ".slice(1)"))) +*/ +function sc_keyword2jsstring(k) { + return k.slice(1); +} + +/*** META ((export #t) + (peephole (prefix "'\\u1E9D' +"))) +*/ +function sc_jsstring2keyword(s) { + return sc_KEYWORD_PREFIX + s; +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isKeyword(s) { + return (typeof s === "string") && + (s.charAt(0) === sc_KEYWORD_PREFIX); +} + + +/*** META ((export #t)) */ +var sc_gensym = function() { + var counter = 1000; + return function(sym) { + counter++; + if (!sym) sym = sc_SYMBOL_PREFIX; + return sym + "s" + counter + "~" + "^sC-GeNsYm "; + }; +}(); + + +/*** META ((export #t) + (type bool)) +*/ +function sc_isEqual(o1, o2) { + return ((o1 === o2) || + (sc_isPair(o1) && sc_isPair(o2) + && sc_isPairEqual(o1, o2, sc_isEqual)) || + (sc_isVector(o1) && sc_isVector(o2) + && sc_isVectorEqual(o1, o2, sc_isEqual))); +} + +/*** META ((export number->symbol integer->symbol)) */ +function sc_number2symbol(x, radix) { + return sc_SYMBOL_PREFIX + sc_number2jsstring(x, radix); +} + +/*** META ((export number->string integer->string)) */ +var sc_number2string = sc_number2jsstring; + +/*** META ((export #t)) */ +function sc_symbol2number(s, radix) { + return sc_jsstring2number(s.slice(1), radix); +} + +/*** META ((export #t)) */ +var sc_string2number = sc_jsstring2number; + +/*** META ((export #t) + (peephole (prefix "+" s))) + ;; peephole will only apply if no radix is given. +*/ +function sc_string2integer(s, radix) { + if (!radix) return +s; + return parseInt(s, radix); +} + +/*** META ((export #t) + (peephole (prefix "+"))) +*/ +function sc_string2real(s) { + return +s; +} + + +/*** META ((export #t) + (type bool)) +*/ +function sc_isSymbol(s) { + return (typeof s === "string") && + (s.charAt(0) === sc_SYMBOL_PREFIX); +} + +/*** META ((export #t) + (peephole (symbol2string_immutable))) +*/ +function sc_symbol2string(s) { + return s.slice(1); +} + +/*** META ((export #t) + (peephole (prefix "'\\u1E9C' +"))) +*/ +function sc_string2symbol(s) { + return sc_SYMBOL_PREFIX + s; +} + +/*** META ((export symbol-append) + (peephole (symbolAppend_immutable))) +*/ +function sc_symbolAppend() { + var res = sc_SYMBOL_PREFIX; + for (var i = 0; i < arguments.length; i++) + res += arguments[i].slice(1); + return res; +} + +/*** META ((export #t) + (peephole (postfix ".val"))) +*/ +function sc_char2string(c) { return c.val; } + +/*** META ((export #t) + (peephole (hole 1 "'\\u1E9C' + " c ".val"))) +*/ +function sc_char2symbol(c) { return sc_SYMBOL_PREFIX + c.val; } + +/*** META ((export #t) + (type bool)) +*/ +function sc_isString(s) { + return (typeof s === "string") && + (s.charAt(0) !== sc_SYMBOL_PREFIX); +} + +/*** META ((export #t)) */ +var sc_makeString = sc_makejsString; + + +/*** META ((export #t)) */ +function sc_string() { + for (var i = 0; i < arguments.length; i++) + arguments[i] = arguments[i].val; + return "".concat.apply("", arguments); +} + +/*** META ((export #t) + (peephole (postfix ".length"))) +*/ +function sc_stringLength(s) { return s.length; } + +/*** META ((export #t)) */ +function sc_stringRef(s, k) { + return new sc_Char(s.charAt(k)); +} + +/* there's no stringSet in the immutable version +function sc_stringSet(s, k, c) +*/ + + +/*** META ((export string=?) + (type bool) + (peephole (hole 2 str1 " === " str2))) +*/ +function sc_isStringEqual(s1, s2) { + return s1 === s2; +} +/*** META ((export string?) + (type bool) + (peephole (hole 2 str1 " > " str2))) +*/ +function sc_isStringGreater(s1, s2) { + return s1 > s2; +} +/*** META ((export string<=?) + (type bool) + (peephole (hole 2 str1 " <= " str2))) +*/ +function sc_isStringLessEqual(s1, s2) { + return s1 <= s2; +} +/*** META ((export string>=?) + (type bool) + (peephole (hole 2 str1 " >= " str2))) +*/ +function sc_isStringGreaterEqual(s1, s2) { + return s1 >= s2; +} +/*** META ((export string-ci=?) + (type bool) + (peephole (hole 2 str1 ".toLowerCase() === " str2 ".toLowerCase()"))) +*/ +function sc_isStringCIEqual(s1, s2) { + return s1.toLowerCase() === s2.toLowerCase(); +} +/*** META ((export string-ci?) + (type bool) + (peephole (hole 2 str1 ".toLowerCase() > " str2 ".toLowerCase()"))) +*/ +function sc_isStringCIGreater(s1, s2) { + return s1.toLowerCase() > s2.toLowerCase(); +} +/*** META ((export string-ci<=?) + (type bool) + (peephole (hole 2 str1 ".toLowerCase() <= " str2 ".toLowerCase()"))) +*/ +function sc_isStringCILessEqual(s1, s2) { + return s1.toLowerCase() <= s2.toLowerCase(); +} +/*** META ((export string-ci>=?) + (type bool) + (peephole (hole 2 str1 ".toLowerCase() >= " str2 ".toLowerCase()"))) +*/ +function sc_isStringCIGreaterEqual(s1, s2) { + return s1.toLowerCase() >= s2.toLowerCase(); +} + +/*** META ((export #t) + (peephole (hole 3 s ".substring(" start ", " end ")"))) +*/ +function sc_substring(s, start, end) { + return s.substring(start, end); +} + +/*** META ((export #t)) +*/ +function sc_isSubstring_at(s1, s2, i) { + return s2 == s1.substring(i, i+ s2.length); +} + +/*** META ((export #t) + (peephole (infix 0 #f "+" "''"))) +*/ +function sc_stringAppend() { + return "".concat.apply("", arguments); +} + +/*** META ((export #t)) */ +var sc_string2list = sc_jsstring2list; + +/*** META ((export #t)) */ +var sc_list2string = sc_list2jsstring; + +/*** META ((export #t) + (peephole (id))) +*/ +function sc_stringCopy(s) { + return s; +} + +/* there's no string-fill in the immutable version +function sc_stringFill(s, c) +*/ + +/*** META ((export #t) + (peephole (postfix ".slice(1)"))) +*/ +function sc_keyword2string(o) { + return o.slice(1); +} + +/*** META ((export #t) + (peephole (prefix "'\\u1E9D' +"))) +*/ +function sc_string2keyword(o) { + return sc_KEYWORD_PREFIX + o; +} + +String.prototype.sc_toDisplayString = function() { + if (this.charAt(0) === sc_SYMBOL_PREFIX) + // TODO: care for symbols with spaces (escape-chars symbols). + return this.slice(1); + else if (this.charAt(0) === sc_KEYWORD_PREFIX) + return ":" + this.slice(1); + else + return this.toString(); +}; + +String.prototype.sc_toWriteString = function() { + if (this.charAt(0) === sc_SYMBOL_PREFIX) + // TODO: care for symbols with spaces (escape-chars symbols). + return this.slice(1); + else if (this.charAt(0) === sc_KEYWORD_PREFIX) + return ":" + this.slice(1); + else + return '"' + sc_escapeWriteString(this) + '"'; +}; +/* Exported Variables */ +var BgL_testzd2boyerzd2; +var BgL_nboyerzd2benchmarkzd2; +var BgL_setupzd2boyerzd2; +/* End Exports */ + +var translate_term_nboyer; +var translate_args_nboyer; +var untranslate_term_nboyer; +var BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer; +var BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer; +var translate_alist_nboyer; +var apply_subst_nboyer; +var apply_subst_lst_nboyer; +var tautologyp_nboyer; +var if_constructor_nboyer; +var rewrite_count_nboyer; +var rewrite_nboyer; +var rewrite_args_nboyer; +var unify_subst_nboyer; +var one_way_unify1_nboyer; +var false_term_nboyer; +var true_term_nboyer; +var trans_of_implies1_nboyer; +var is_term_equal_nboyer; +var is_term_member_nboyer; +var const_nboyer; +var sc_const_3_nboyer; +var sc_const_4_nboyer; +{ + (sc_const_4_nboyer = (new sc_Pair("\u1E9Cimplies",(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cu",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cu",(new sc_Pair("\u1E9Cw",null)))))),null)))))),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cw",null)))))),null))))))); + (sc_const_3_nboyer = sc_list((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ccompile",(new sc_Pair("\u1E9Cform",null)))),(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair((new sc_Pair("\u1E9Ccodegen",(new sc_Pair((new sc_Pair("\u1E9Coptimize",(new sc_Pair("\u1E9Cform",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ceqp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreaterp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clesseqp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreatereqp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cboolean",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ciff",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ceven1",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Codd",(new sc_Pair((new sc_Pair("\u1E9Csub1",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ccountps-",(new sc_Pair("\u1E9Cl",(new sc_Pair("\u1E9Cpred",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ccountps-loop",(new sc_Pair("\u1E9Cl",(new sc_Pair("\u1E9Cpred",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfact-",(new sc_Pair("\u1E9Ci",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfact-loop",(new sc_Pair("\u1E9Ci",(new sc_Pair((1),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Creverse-",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Creverse-loop",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdivides",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cassume-true",(new sc_Pair("\u1E9Cvar",(new sc_Pair("\u1E9Calist",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cvar",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),null)))))),(new sc_Pair("\u1E9Calist",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cassume-false",(new sc_Pair("\u1E9Cvar",(new sc_Pair("\u1E9Calist",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cvar",(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))),(new sc_Pair("\u1E9Calist",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctautology-checker",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ctautologyp",(new sc_Pair((new sc_Pair("\u1E9Cnormalize",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfalsify",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfalsify1",(new sc_Pair((new sc_Pair("\u1E9Cnormalize",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cprime",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))),null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cprime1",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Csub1",(new sc_Pair("\u1E9Cx",null)))),null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair("\u1E9Cp",(new sc_Pair("\u1E9Cq",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cp",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cq",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair("\u1E9Cp",(new sc_Pair("\u1E9Cq",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cp",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cq",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair("\u1E9Cp",null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cp",(new sc_Pair((new sc_Pair("\u1E9Cf",null)),(new sc_Pair((new sc_Pair("\u1E9Ct",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cp",(new sc_Pair("\u1E9Cq",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cp",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cq",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))))),(new sc_Pair((new sc_Pair("\u1E9Ct",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cc",null)))))))),(new sc_Pair("\u1E9Cd",(new sc_Pair("\u1E9Ce",null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Ca",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cd",(new sc_Pair("\u1E9Ce",null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cc",(new sc_Pair("\u1E9Cd",(new sc_Pair("\u1E9Ce",null)))))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Ca",null)))),(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cb",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cc",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cc",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair("\u1E9Ca",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair((new sc_Pair("\u1E9Cplus-fringe",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Ca",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cexec",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cpds",(new sc_Pair("\u1E9Cenvrn",null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cexec",(new sc_Pair("\u1E9Cy",(new sc_Pair((new sc_Pair("\u1E9Cexec",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cpds",(new sc_Pair("\u1E9Cenvrn",null)))))))),(new sc_Pair("\u1E9Cenvrn",null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmc-flatten",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Cy",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cb",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cy",null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Ca",(new sc_Pair((new sc_Pair("\u1E9Cintersect",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cc",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cc",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Ck",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cj",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Ck",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Ck",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cj",null)))))),(new sc_Pair("\u1E9Ck",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Creverse-loop",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Cy",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Creverse-loop",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ccount-list",(new sc_Pair("\u1E9Cz",(new sc_Pair((new sc_Pair("\u1E9Csort-lp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Ccount-list",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ccount-list",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cc",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cc",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair((new sc_Pair("\u1E9Cbig-plus1",(new sc_Pair("\u1E9Cl",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cbase",null)))))))),(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair("\u1E9Cl",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair("\u1E9Ci",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair((new sc_Pair("\u1E9Cbig-plus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cbase",null)))))))))),(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cbase",null)))))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cy",(new sc_Pair((1),null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cj",null)))))),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Ci",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cj",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cj",(new sc_Pair((1),null)))))),null)))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair((new sc_Pair("\u1E9Cpower-rep",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Ci",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair((new sc_Pair("\u1E9Cbig-plus",(new sc_Pair((new sc_Pair("\u1E9Cpower-rep",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cpower-rep",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair("\u1E9Cbase",null)))))))))),(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cj",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgcd",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cgcd",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair("\u1E9Cb",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Ca",null)))),null)))))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cy",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cy",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cc",(new sc_Pair("\u1E9Cw",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cc",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cw",(new sc_Pair("\u1E9Cx",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cb",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cc",null)))))),null)))))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cc",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cy",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cz",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgcd",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cz",(new sc_Pair((new sc_Pair("\u1E9Cgcd",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cvalue",(new sc_Pair((new sc_Pair("\u1E9Cnormalize",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cvalue",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cy",(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnlistp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair((new sc_Pair("\u1E9Cgopher",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csamefringe",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreatest-factor",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cy",(new sc_Pair((1),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreatest-factor",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((1),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((1),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair((new sc_Pair("\u1E9Cgreatest-factor",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cy",(new sc_Pair((1),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes-list",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair((new sc_Pair("\u1E9Ctimes-list",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ctimes-list",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cprime-list",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cprime-list",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cprime-list",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cz",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cw",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cz",null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cz",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cw",(new sc_Pair((1),null)))))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreatereqp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cy",(new sc_Pair((1),null)))))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((1),null)))))),(new sc_Pair(sc_list("\u1E9Cand", (new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Ca",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),null)))), (new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cb",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),null)))), (new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Ca",null)))), (new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cb",null)))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csub1",(new sc_Pair("\u1E9Ca",null)))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csub1",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair((new sc_Pair("\u1E9Cdelete",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cl",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Cl",null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cl",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csort2",(new sc_Pair((new sc_Pair("\u1E9Cdelete",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cl",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cdelete",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Csort2",(new sc_Pair("\u1E9Cl",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdsort",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Csort2",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx1",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx2",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx3",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx4",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx5",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx6",(new sc_Pair("\u1E9Cx7",null)))))),null)))))),null)))))),null)))))),null)))))),null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((6),(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Cx7",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((2),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((2),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair("\u1E9Cy",(new sc_Pair((2),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csigma",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Ci",null)))),null)))))),(new sc_Pair((2),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cy",null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cx",null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cz",null)))),null)))))),null)))))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair((new sc_Pair("\u1E9Cdelete",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair("\u1E9Ca",null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cy",null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Ci",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clast",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Clast",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Ca",null)))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair((new sc_Pair("\u1E9Ccar",(new sc_Pair((new sc_Pair("\u1E9Clast",(new sc_Pair("\u1E9Ca",null)))),null)))),(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair("\u1E9Cb",null)))))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cf",null)),(new sc_Pair("\u1E9Cz",null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cassignment",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cassignedp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cassignment",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cassignment",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cb",null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ccar",(new sc_Pair((new sc_Pair("\u1E9Cgopher",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ccar",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair((new sc_Pair("\u1E9Ccdr",(new sc_Pair((new sc_Pair("\u1E9Cgopher",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ccdr",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cget",(new sc_Pair("\u1E9Cj",(new sc_Pair((new sc_Pair("\u1E9Cset",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cval",(new sc_Pair("\u1E9Cmem",null)))))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Ceqp",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair("\u1E9Cval",(new sc_Pair((new sc_Pair("\u1E9Cget",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Cmem",null)))))),null)))))))),null)))))))); + (const_nboyer = (new sc_Pair((new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cf",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cc",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cf",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cc",(new sc_Pair("\u1E9Cd",null)))))),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cf",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cu",(new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cw",(new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Ca",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Cb",null)))),null)))))),null)))))))),null))))))))))); + BgL_nboyerzd2benchmarkzd2 = function() { + var args = null; + for (var sc_tmp = arguments.length - 1; sc_tmp >= 0; sc_tmp--) { + args = sc_cons(arguments[sc_tmp], args); + } + var n; + return ((n = ((args === null)?(0):(args.car))), (BgL_setupzd2boyerzd2()), (BgL_runzd2benchmarkzd2(("nboyer"+(sc_number2string(n))), (1), function() { + return (BgL_testzd2boyerzd2(n)); + }, function(rewrites) { + if ((sc_isNumber(rewrites))) + switch (n) { + case (0): + assertEq(rewrites, 95024); + return true; + break; + case (1): + assertEq(rewrites, 591777); + return true; + break; + case (2): + assertEq(rewrites, 1813975); + return true; + break; + case (3): + assertEq(rewrites, 5375678); + return true; + break; + case (4): + assertEq(rewrites, 16445406); + return true; + break; + case (5): + assertEq(rewrites, 51507739); + return true; + break; + default: + return true; + break; + } + else + return false; + }))); + }; + BgL_setupzd2boyerzd2 = function() { + return true; + }; + BgL_testzd2boyerzd2 = function() { + return true; + }; + translate_term_nboyer = function(term) { + var lst; + return (!(term instanceof sc_Pair)?term:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((term.car))), ((lst = (term.cdr)), ((lst === null)?null:(new sc_Pair((translate_term_nboyer((lst.car))), (translate_args_nboyer((lst.cdr)))))))))); + }; + translate_args_nboyer = function(lst) { + var sc_lst_5; + var term; + return ((lst === null)?null:(new sc_Pair(((term = (lst.car)), (!(term instanceof sc_Pair)?term:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((term.car))), (translate_args_nboyer((term.cdr))))))), ((sc_lst_5 = (lst.cdr)), ((sc_lst_5 === null)?null:(new sc_Pair((translate_term_nboyer((sc_lst_5.car))), (translate_args_nboyer((sc_lst_5.cdr)))))))))); + }; + untranslate_term_nboyer = function(term) { + var optrOpnd; + var tail1131; + var L1127; + var falseHead1130; + var symbol_record; + if (!(term instanceof sc_Pair)) + return term; + else + { + (falseHead1130 = (new sc_Pair(null, null))); + (L1127 = (term.cdr)); + (tail1131 = falseHead1130); + while (!(L1127 === null)) { + { + (tail1131.cdr = (new sc_Pair((untranslate_term_nboyer((L1127.car))), null))); + (tail1131 = (tail1131.cdr)); + (L1127 = (L1127.cdr)); + } + } + (optrOpnd = (falseHead1130.cdr)); + return (new sc_Pair(((symbol_record = (term.car)), (symbol_record[(0)])), optrOpnd)); + } + }; + BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer = function(sym) { + var r; + var x; + return ((x = (sc_assq(sym, BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer))), ((x!== false)?(x.cdr):((r = [sym, null]), (BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer = (new sc_Pair((new sc_Pair(sym, r)), BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer))), r))); + }; + (BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer = null); + translate_alist_nboyer = function(alist) { + var sc_alist_6; + var term; + return ((alist === null)?null:(new sc_Pair((new sc_Pair((alist.car.car), ((term = (alist.car.cdr)), (!(term instanceof sc_Pair)?term:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((term.car))), (translate_args_nboyer((term.cdr))))))))), ((sc_alist_6 = (alist.cdr)), ((sc_alist_6 === null)?null:(new sc_Pair((new sc_Pair((sc_alist_6.car.car), (translate_term_nboyer((sc_alist_6.car.cdr))))), (translate_alist_nboyer((sc_alist_6.cdr)))))))))); + }; + apply_subst_nboyer = function(alist, term) { + var lst; + var temp_temp; + return (!(term instanceof sc_Pair)?((temp_temp = (sc_assq(term, alist))), ((temp_temp!== false)?(temp_temp.cdr):term)):(new sc_Pair((term.car), ((lst = (term.cdr)), ((lst === null)?null:(new sc_Pair((apply_subst_nboyer(alist, (lst.car))), (apply_subst_lst_nboyer(alist, (lst.cdr)))))))))); + }; + apply_subst_lst_nboyer = function(alist, lst) { + var sc_lst_7; + return ((lst === null)?null:(new sc_Pair((apply_subst_nboyer(alist, (lst.car))), ((sc_lst_7 = (lst.cdr)), ((sc_lst_7 === null)?null:(new sc_Pair((apply_subst_nboyer(alist, (sc_lst_7.car))), (apply_subst_lst_nboyer(alist, (sc_lst_7.cdr)))))))))); + }; + tautologyp_nboyer = function(sc_x_11, true_lst, false_lst) { + var tmp1125; + var x; + var tmp1126; + var sc_x_8; + var sc_tmp1125_9; + var sc_tmp1126_10; + var sc_x_11; + var true_lst; + var false_lst; + while (true) { + if ((((sc_tmp1126_10 = (is_term_equal_nboyer(sc_x_11, true_term_nboyer))), ((sc_tmp1126_10!== false)?sc_tmp1126_10:(is_term_member_nboyer(sc_x_11, true_lst))))!== false)) + return true; + else + if ((((sc_tmp1125_9 = (is_term_equal_nboyer(sc_x_11, false_term_nboyer))), ((sc_tmp1125_9!== false)?sc_tmp1125_9:(is_term_member_nboyer(sc_x_11, false_lst))))!== false)) + return false; + else + if (!(sc_x_11 instanceof sc_Pair)) + return false; + else + if (((sc_x_11.car)===if_constructor_nboyer)) + if ((((sc_x_8 = (sc_x_11.cdr.car)), (tmp1126 = (is_term_equal_nboyer(sc_x_8, true_term_nboyer))), ((tmp1126!== false)?tmp1126:(is_term_member_nboyer(sc_x_8, true_lst))))!== false)) + (sc_x_11 = (sc_x_11.cdr.cdr.car)); + else + if ((((x = (sc_x_11.cdr.car)), (tmp1125 = (is_term_equal_nboyer(x, false_term_nboyer))), ((tmp1125!== false)?tmp1125:(is_term_member_nboyer(x, false_lst))))!== false)) + (sc_x_11 = (sc_x_11.cdr.cdr.cdr.car)); + else + if (((tautologyp_nboyer((sc_x_11.cdr.cdr.car), (new sc_Pair((sc_x_11.cdr.car), true_lst)), false_lst))!== false)) + { + (false_lst = (new sc_Pair((sc_x_11.cdr.car), false_lst))); + (sc_x_11 = (sc_x_11.cdr.cdr.cdr.car)); + } + else + return false; + else + return false; + } + }; + (if_constructor_nboyer = "\u1E9C*"); + (rewrite_count_nboyer = (0)); + rewrite_nboyer = function(term) { + var term2; + var sc_term_12; + var lst; + var symbol_record; + var sc_lst_13; + { + (++rewrite_count_nboyer); + if (!(term instanceof sc_Pair)) + return term; + else + { + (sc_term_12 = (new sc_Pair((term.car), ((sc_lst_13 = (term.cdr)), ((sc_lst_13 === null)?null:(new sc_Pair((rewrite_nboyer((sc_lst_13.car))), (rewrite_args_nboyer((sc_lst_13.cdr)))))))))); + (lst = ((symbol_record = (term.car)), (symbol_record[(1)]))); + while (true) { + if ((lst === null)) + return sc_term_12; + else + if ((((term2 = ((lst.car).cdr.car)), (unify_subst_nboyer = null), (one_way_unify1_nboyer(sc_term_12, term2)))!== false)) + return (rewrite_nboyer((apply_subst_nboyer(unify_subst_nboyer, ((lst.car).cdr.cdr.car))))); + else + (lst = (lst.cdr)); + } + } + } + }; + rewrite_args_nboyer = function(lst) { + var sc_lst_14; + return ((lst === null)?null:(new sc_Pair((rewrite_nboyer((lst.car))), ((sc_lst_14 = (lst.cdr)), ((sc_lst_14 === null)?null:(new sc_Pair((rewrite_nboyer((sc_lst_14.car))), (rewrite_args_nboyer((sc_lst_14.cdr)))))))))); + }; + (unify_subst_nboyer = "\u1E9C*"); + one_way_unify1_nboyer = function(term1, term2) { + var lst1; + var lst2; + var temp_temp; + if (!(term2 instanceof sc_Pair)) + { + (temp_temp = (sc_assq(term2, unify_subst_nboyer))); + if ((temp_temp!== false)) + return (is_term_equal_nboyer(term1, (temp_temp.cdr))); + else + if ((sc_isNumber(term2))) + return (sc_isEqual(term1, term2)); + else + { + (unify_subst_nboyer = (new sc_Pair((new sc_Pair(term2, term1)), unify_subst_nboyer))); + return true; + } + } + else + if (!(term1 instanceof sc_Pair)) + return false; + else + if (((term1.car)===(term2.car))) + { + (lst1 = (term1.cdr)); + (lst2 = (term2.cdr)); + while (true) { + if ((lst1 === null)) + return (lst2 === null); + else + if ((lst2 === null)) + return false; + else + if (((one_way_unify1_nboyer((lst1.car), (lst2.car)))!== false)) + { + (lst1 = (lst1.cdr)); + (lst2 = (lst2.cdr)); + } + else + return false; + } + } + else + return false; + }; + (false_term_nboyer = "\u1E9C*"); + (true_term_nboyer = "\u1E9C*"); + trans_of_implies1_nboyer = function(n) { + var sc_n_15; + return ((sc_isEqual(n, (1)))?(sc_list("\u1E9Cimplies", (0), (1))):(sc_list("\u1E9Cand", (sc_list("\u1E9Cimplies", (n-(1)), n)), ((sc_n_15 = (n-(1))), ((sc_isEqual(sc_n_15, (1)))?(sc_list("\u1E9Cimplies", (0), (1))):(sc_list("\u1E9Cand", (sc_list("\u1E9Cimplies", (sc_n_15-(1)), sc_n_15)), (trans_of_implies1_nboyer((sc_n_15-(1))))))))))); + }; + is_term_equal_nboyer = function(x, y) { + var lst1; + var lst2; + var r2; + var r1; + if ((x instanceof sc_Pair)) + if ((y instanceof sc_Pair)) + if ((((r1 = (x.car)), (r2 = (y.car)), (r1===r2))!== false)) + { + (lst1 = (x.cdr)); + (lst2 = (y.cdr)); + while (true) { + if ((lst1 === null)) + return (lst2 === null); + else + if ((lst2 === null)) + return false; + else + if (((is_term_equal_nboyer((lst1.car), (lst2.car)))!== false)) + { + (lst1 = (lst1.cdr)); + (lst2 = (lst2.cdr)); + } + else + return false; + } + } + else + return false; + else + return false; + else + return (sc_isEqual(x, y)); + }; + is_term_member_nboyer = function(x, lst) { + var x; + var lst; + while (true) { + if ((lst === null)) + return false; + else + if (((is_term_equal_nboyer(x, (lst.car)))!== false)) + return true; + else + (lst = (lst.cdr)); + } + }; + BgL_setupzd2boyerzd2 = function() { + var symbol_record; + var value; + var BgL_sc_symbolzd2record_16zd2; + var sym; + var sc_sym_17; + var term; + var lst; + var sc_term_18; + var sc_term_19; + { + (BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer = null); + (if_constructor_nboyer = (BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer("\u1E9Cif"))); + (false_term_nboyer = ((sc_term_19 = (new sc_Pair("\u1E9Cf",null))), (!(sc_term_19 instanceof sc_Pair)?sc_term_19:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((sc_term_19.car))), (translate_args_nboyer((sc_term_19.cdr)))))))); + (true_term_nboyer = ((sc_term_18 = (new sc_Pair("\u1E9Ct",null))), (!(sc_term_18 instanceof sc_Pair)?sc_term_18:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((sc_term_18.car))), (translate_args_nboyer((sc_term_18.cdr)))))))); + (lst = sc_const_3_nboyer); + while (!(lst === null)) { + { + (term = (lst.car)); + if (((term instanceof sc_Pair)&&(((term.car)==="\u1E9Cequal")&&((term.cdr.car) instanceof sc_Pair)))) + { + (sc_sym_17 = ((term.cdr.car).car)); + (value = (new sc_Pair((!(term instanceof sc_Pair)?term:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((term.car))), (translate_args_nboyer((term.cdr)))))), ((sym = ((term.cdr.car).car)), (BgL_sc_symbolzd2record_16zd2 = (BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(sym))), (BgL_sc_symbolzd2record_16zd2[(1)]))))); + (symbol_record = (BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(sc_sym_17))); + (symbol_record[(1)] = value); + } + else + (sc_error("ADD-LEMMA did not like term: ", term)); + (lst = (lst.cdr)); + } + } + return true; + } + }; + BgL_testzd2boyerzd2 = function(n) { + var optrOpnd; + var term; + var sc_n_20; + var answer; + var sc_term_21; + var sc_term_22; + { + (rewrite_count_nboyer = (0)); + (term = sc_const_4_nboyer); + (sc_n_20 = n); + while (!(sc_n_20=== 0)) { + { + (term = (sc_list("\u1E9Cor", term, (new sc_Pair("\u1E9Cf",null))))); + (--sc_n_20); + } + } + (sc_term_22 = term); + if (!(sc_term_22 instanceof sc_Pair)) + (optrOpnd = sc_term_22); + else + (optrOpnd = (new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((sc_term_22.car))), (translate_args_nboyer((sc_term_22.cdr)))))); + (sc_term_21 = (apply_subst_nboyer(((const_nboyer === null)?null:(new sc_Pair((new sc_Pair((const_nboyer.car.car), (translate_term_nboyer((const_nboyer.car.cdr))))), (translate_alist_nboyer((const_nboyer.cdr)))))), optrOpnd))); + (answer = (tautologyp_nboyer((rewrite_nboyer(sc_term_21)), null, null))); + (sc_write(rewrite_count_nboyer)); + (sc_display(" rewrites")); + (sc_newline()); + if ((answer!== false)) + return rewrite_count_nboyer; + else + return false; + } + }; +} +/* Exported Variables */ +var BgL_parsezd2ze3nbzd2treesze3; +var BgL_earleyzd2benchmarkzd2; +var BgL_parsezd2ze3parsedzf3zc2; +var test; +var BgL_parsezd2ze3treesz31; +var BgL_makezd2parserzd2; +/* End Exports */ + +var const_earley; +{ + (const_earley = (new sc_Pair((new sc_Pair("\u1E9Cs",(new sc_Pair((new sc_Pair("\u1E9Ca",null)),(new sc_Pair((new sc_Pair("\u1E9Cs",(new sc_Pair("\u1E9Cs",null)))),null)))))),null))); + BgL_makezd2parserzd2 = function(grammar, lexer) { + var i; + var parser_descr; + var def_loop; + var nb_nts; + var names; + var steps; + var predictors; + var enders; + var starters; + var nts; + var sc_names_1; + var sc_steps_2; + var sc_predictors_3; + var sc_enders_4; + var sc_starters_5; + var nb_confs; + var BgL_sc_defzd2loop_6zd2; + var BgL_sc_nbzd2nts_7zd2; + var sc_nts_8; + var BgL_sc_defzd2loop_9zd2; + var ind; + { + ind = function(nt, sc_nts_10) { + var i; + { + (i = ((sc_nts_10.length)-(1))); + while (true) { + if ((i>=(0))) + if ((sc_isEqual((sc_nts_10[i]), nt))) + return i; + else + (--i); + else + return false; + } + } + }; + (sc_nts_8 = ((BgL_sc_defzd2loop_9zd2 = function(defs, sc_nts_11) { + var rule_loop; + var head; + var def; + return ((defs instanceof sc_Pair)?((def = (defs.car)), (head = (def.car)), (rule_loop = function(rules, sc_nts_12) { + var nt; + var l; + var sc_nts_13; + var rule; + if ((rules instanceof sc_Pair)) + { + (rule = (rules.car)); + (l = rule); + (sc_nts_13 = sc_nts_12); + while ((l instanceof sc_Pair)) { + { + (nt = (l.car)); + (l = (l.cdr)); + (sc_nts_13 = (((sc_member(nt, sc_nts_13))!== false)?sc_nts_13:(new sc_Pair(nt, sc_nts_13)))); + } + } + return (rule_loop((rules.cdr), sc_nts_13)); + } + else + return (BgL_sc_defzd2loop_9zd2((defs.cdr), sc_nts_12)); + }), (rule_loop((def.cdr), (((sc_member(head, sc_nts_11))!== false)?sc_nts_11:(new sc_Pair(head, sc_nts_11)))))):(sc_list2vector((sc_reverse(sc_nts_11))))); + }), (BgL_sc_defzd2loop_9zd2(grammar, null)))); + (BgL_sc_nbzd2nts_7zd2 = (sc_nts_8.length)); + (nb_confs = (((BgL_sc_defzd2loop_6zd2 = function(defs, BgL_sc_nbzd2confs_14zd2) { + var rule_loop; + var def; + return ((defs instanceof sc_Pair)?((def = (defs.car)), (rule_loop = function(rules, BgL_sc_nbzd2confs_15zd2) { + var l; + var BgL_sc_nbzd2confs_16zd2; + var rule; + if ((rules instanceof sc_Pair)) + { + (rule = (rules.car)); + (l = rule); + (BgL_sc_nbzd2confs_16zd2 = BgL_sc_nbzd2confs_15zd2); + while ((l instanceof sc_Pair)) { + { + (l = (l.cdr)); + (++BgL_sc_nbzd2confs_16zd2); + } + } + return (rule_loop((rules.cdr), (BgL_sc_nbzd2confs_16zd2+(1)))); + } + else + return (BgL_sc_defzd2loop_6zd2((defs.cdr), BgL_sc_nbzd2confs_15zd2)); + }), (rule_loop((def.cdr), BgL_sc_nbzd2confs_14zd2))):BgL_sc_nbzd2confs_14zd2); + }), (BgL_sc_defzd2loop_6zd2(grammar, (0))))+BgL_sc_nbzd2nts_7zd2)); + (sc_starters_5 = (sc_makeVector(BgL_sc_nbzd2nts_7zd2, null))); + (sc_enders_4 = (sc_makeVector(BgL_sc_nbzd2nts_7zd2, null))); + (sc_predictors_3 = (sc_makeVector(BgL_sc_nbzd2nts_7zd2, null))); + (sc_steps_2 = (sc_makeVector(nb_confs, false))); + (sc_names_1 = (sc_makeVector(nb_confs, false))); + (nts = sc_nts_8); + (starters = sc_starters_5); + (enders = sc_enders_4); + (predictors = sc_predictors_3); + (steps = sc_steps_2); + (names = sc_names_1); + (nb_nts = (sc_nts_8.length)); + (i = (nb_nts-(1))); + while ((i>=(0))) { + { + (sc_steps_2[i] = (i-nb_nts)); + (sc_names_1[i] = (sc_list((sc_nts_8[i]), (0)))); + (sc_enders_4[i] = (sc_list(i))); + (--i); + } + } + def_loop = function(defs, conf) { + var rule_loop; + var head; + var def; + return ((defs instanceof sc_Pair)?((def = (defs.car)), (head = (def.car)), (rule_loop = function(rules, conf, rule_num) { + var i; + var sc_i_17; + var nt; + var l; + var sc_conf_18; + var sc_i_19; + var rule; + if ((rules instanceof sc_Pair)) + { + (rule = (rules.car)); + (names[conf] = (sc_list(head, rule_num))); + (sc_i_19 = (ind(head, nts))); + (starters[sc_i_19] = (new sc_Pair(conf, (starters[sc_i_19])))); + (l = rule); + (sc_conf_18 = conf); + while ((l instanceof sc_Pair)) { + { + (nt = (l.car)); + (steps[sc_conf_18] = (ind(nt, nts))); + (sc_i_17 = (ind(nt, nts))); + (predictors[sc_i_17] = (new sc_Pair(sc_conf_18, (predictors[sc_i_17])))); + (l = (l.cdr)); + (++sc_conf_18); + } + } + (steps[sc_conf_18] = ((ind(head, nts))-nb_nts)); + (i = (ind(head, nts))); + (enders[i] = (new sc_Pair(sc_conf_18, (enders[i])))); + return (rule_loop((rules.cdr), (sc_conf_18+(1)), (rule_num+(1)))); + } + else + return (def_loop((defs.cdr), conf)); + }), (rule_loop((def.cdr), conf, (1)))):undefined); + }; + (def_loop(grammar, (sc_nts_8.length))); + (parser_descr = [lexer, sc_nts_8, sc_starters_5, sc_enders_4, sc_predictors_3, sc_steps_2, sc_names_1]); + return function(input) { + var optrOpnd; + var sc_optrOpnd_20; + var sc_optrOpnd_21; + var sc_optrOpnd_22; + var loop1; + var BgL_sc_stateza2_23za2; + var toks; + var BgL_sc_nbzd2nts_24zd2; + var sc_steps_25; + var sc_enders_26; + var state_num; + var BgL_sc_statesza2_27za2; + var states; + var i; + var conf; + var l; + var tok_nts; + var sc_i_28; + var sc_i_29; + var l1; + var l2; + var tok; + var tail1129; + var L1125; + var goal_enders; + var BgL_sc_statesza2_30za2; + var BgL_sc_nbzd2nts_31zd2; + var BgL_sc_nbzd2confs_32zd2; + var nb_toks; + var goal_starters; + var sc_states_33; + var BgL_sc_nbzd2confs_34zd2; + var BgL_sc_nbzd2toks_35zd2; + var sc_toks_36; + var falseHead1128; + var sc_names_37; + var sc_steps_38; + var sc_predictors_39; + var sc_enders_40; + var sc_starters_41; + var sc_nts_42; + var lexer; + var sc_ind_43; + var make_states; + var BgL_sc_confzd2setzd2getza2_44za2; + var conf_set_merge_new_bang; + var conf_set_adjoin; + var BgL_sc_confzd2setzd2adjoinza2_45za2; + var BgL_sc_confzd2setzd2adjoinza2za2_46z00; + var conf_set_union; + var forw; + var is_parsed; + var deriv_trees; + var BgL_sc_derivzd2treesza2_47z70; + var nb_deriv_trees; + var BgL_sc_nbzd2derivzd2treesza2_48za2; + { + sc_ind_43 = function(nt, sc_nts_49) { + var i; + { + (i = ((sc_nts_49.length)-(1))); + while (true) { + if ((i>=(0))) + if ((sc_isEqual((sc_nts_49[i]), nt))) + return i; + else + (--i); + else + return false; + } + } + }; + make_states = function(BgL_sc_nbzd2toks_50zd2, BgL_sc_nbzd2confs_51zd2) { + var v; + var i; + var sc_states_52; + { + (sc_states_52 = (sc_makeVector((BgL_sc_nbzd2toks_50zd2+(1)), false))); + (i = BgL_sc_nbzd2toks_50zd2); + while ((i>=(0))) { + { + (v = (sc_makeVector((BgL_sc_nbzd2confs_51zd2+(1)), false))); + (v[(0)] = (-1)); + (sc_states_52[i] = v); + (--i); + } + } + return sc_states_52; + } + }; + BgL_sc_confzd2setzd2getza2_44za2 = function(state, BgL_sc_statezd2num_53zd2, sc_conf_54) { + var conf_set; + var BgL_sc_confzd2set_55zd2; + return ((BgL_sc_confzd2set_55zd2 = (state[(sc_conf_54+(1))])), ((BgL_sc_confzd2set_55zd2!== false)?BgL_sc_confzd2set_55zd2:((conf_set = (sc_makeVector((BgL_sc_statezd2num_53zd2+(6)), false))), (conf_set[(1)] = (-3)), (conf_set[(2)] = (-1)), (conf_set[(3)] = (-1)), (conf_set[(4)] = (-1)), (state[(sc_conf_54+(1))] = conf_set), conf_set))); + }; + conf_set_merge_new_bang = function(conf_set) { + return ((conf_set[((conf_set[(1)])+(5))] = (conf_set[(4)])), (conf_set[(1)] = (conf_set[(3)])), (conf_set[(3)] = (-1)), (conf_set[(4)] = (-1))); + }; + conf_set_adjoin = function(state, conf_set, sc_conf_56, i) { + var tail; + return ((tail = (conf_set[(3)])), (conf_set[(i+(5))] = (-1)), (conf_set[(tail+(5))] = i), (conf_set[(3)] = i), ((tail<(0))?((conf_set[(0)] = (state[(0)])), (state[(0)] = sc_conf_56)):undefined)); + }; + BgL_sc_confzd2setzd2adjoinza2_45za2 = function(sc_states_57, BgL_sc_statezd2num_58zd2, l, i) { + var conf_set; + var sc_conf_59; + var l1; + var state; + { + (state = (sc_states_57[BgL_sc_statezd2num_58zd2])); + (l1 = l); + while ((l1 instanceof sc_Pair)) { + { + (sc_conf_59 = (l1.car)); + (conf_set = (BgL_sc_confzd2setzd2getza2_44za2(state, BgL_sc_statezd2num_58zd2, sc_conf_59))); + if (((conf_set[(i+(5))])=== false)) + { + (conf_set_adjoin(state, conf_set, sc_conf_59, i)); + (l1 = (l1.cdr)); + } + else + (l1 = (l1.cdr)); + } + } + return undefined; + } + }; + BgL_sc_confzd2setzd2adjoinza2za2_46z00 = function(sc_states_60, BgL_sc_statesza2_61za2, BgL_sc_statezd2num_62zd2, sc_conf_63, i) { + var BgL_sc_confzd2setza2_64z70; + var BgL_sc_stateza2_65za2; + var conf_set; + var state; + return ((state = (sc_states_60[BgL_sc_statezd2num_62zd2])), ((((conf_set = (state[(sc_conf_63+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false)?((BgL_sc_stateza2_65za2 = (BgL_sc_statesza2_61za2[BgL_sc_statezd2num_62zd2])), (BgL_sc_confzd2setza2_64z70 = (BgL_sc_confzd2setzd2getza2_44za2(BgL_sc_stateza2_65za2, BgL_sc_statezd2num_62zd2, sc_conf_63))), (((BgL_sc_confzd2setza2_64z70[(i+(5))])=== false)?(conf_set_adjoin(BgL_sc_stateza2_65za2, BgL_sc_confzd2setza2_64z70, sc_conf_63, i)):undefined), true):false)); + }; + conf_set_union = function(state, conf_set, sc_conf_66, other_set) { + var i; + { + (i = (other_set[(2)])); + while ((i>=(0))) { + if (((conf_set[(i+(5))])=== false)) + { + (conf_set_adjoin(state, conf_set, sc_conf_66, i)); + (i = (other_set[(i+(5))])); + } + else + (i = (other_set[(i+(5))])); + } + return undefined; + } + }; + forw = function(sc_states_67, BgL_sc_statezd2num_68zd2, sc_starters_69, sc_enders_70, sc_predictors_71, sc_steps_72, sc_nts_73) { + var next_set; + var next; + var conf_set; + var ender; + var l; + var starter_set; + var starter; + var sc_l_74; + var sc_loop1_75; + var head; + var BgL_sc_confzd2set_76zd2; + var BgL_sc_statezd2num_77zd2; + var state; + var sc_states_78; + var preds; + var BgL_sc_confzd2set_79zd2; + var step; + var sc_conf_80; + var BgL_sc_nbzd2nts_81zd2; + var sc_state_82; + { + (sc_state_82 = (sc_states_67[BgL_sc_statezd2num_68zd2])); + (BgL_sc_nbzd2nts_81zd2 = (sc_nts_73.length)); + while (true) { + { + (sc_conf_80 = (sc_state_82[(0)])); + if ((sc_conf_80>=(0))) + { + (step = (sc_steps_72[sc_conf_80])); + (BgL_sc_confzd2set_79zd2 = (sc_state_82[(sc_conf_80+(1))])); + (head = (BgL_sc_confzd2set_79zd2[(4)])); + (sc_state_82[(0)] = (BgL_sc_confzd2set_79zd2[(0)])); + (conf_set_merge_new_bang(BgL_sc_confzd2set_79zd2)); + if ((step>=(0))) + { + (sc_l_74 = (sc_starters_69[step])); + while ((sc_l_74 instanceof sc_Pair)) { + { + (starter = (sc_l_74.car)); + (starter_set = (BgL_sc_confzd2setzd2getza2_44za2(sc_state_82, BgL_sc_statezd2num_68zd2, starter))); + if (((starter_set[(BgL_sc_statezd2num_68zd2+(5))])=== false)) + { + (conf_set_adjoin(sc_state_82, starter_set, starter, BgL_sc_statezd2num_68zd2)); + (sc_l_74 = (sc_l_74.cdr)); + } + else + (sc_l_74 = (sc_l_74.cdr)); + } + } + (l = (sc_enders_70[step])); + while ((l instanceof sc_Pair)) { + { + (ender = (l.car)); + if ((((conf_set = (sc_state_82[(ender+(1))])), ((conf_set!== false)?(conf_set[(BgL_sc_statezd2num_68zd2+(5))]):false))!== false)) + { + (next = (sc_conf_80+(1))); + (next_set = (BgL_sc_confzd2setzd2getza2_44za2(sc_state_82, BgL_sc_statezd2num_68zd2, next))); + (conf_set_union(sc_state_82, next_set, next, BgL_sc_confzd2set_79zd2)); + (l = (l.cdr)); + } + else + (l = (l.cdr)); + } + } + } + else + { + (preds = (sc_predictors_71[(step+BgL_sc_nbzd2nts_81zd2)])); + (sc_states_78 = sc_states_67); + (state = sc_state_82); + (BgL_sc_statezd2num_77zd2 = BgL_sc_statezd2num_68zd2); + (BgL_sc_confzd2set_76zd2 = BgL_sc_confzd2set_79zd2); + sc_loop1_75 = function(l) { + var sc_state_83; + var BgL_sc_nextzd2set_84zd2; + var sc_next_85; + var pred_set; + var i; + var pred; + if ((l instanceof sc_Pair)) + { + (pred = (l.car)); + (i = head); + while ((i>=(0))) { + { + (pred_set = ((sc_state_83 = (sc_states_78[i])), (sc_state_83[(pred+(1))]))); + if ((pred_set!== false)) + { + (sc_next_85 = (pred+(1))); + (BgL_sc_nextzd2set_84zd2 = (BgL_sc_confzd2setzd2getza2_44za2(state, BgL_sc_statezd2num_77zd2, sc_next_85))); + (conf_set_union(state, BgL_sc_nextzd2set_84zd2, sc_next_85, pred_set)); + } + (i = (BgL_sc_confzd2set_76zd2[(i+(5))])); + } + } + return (sc_loop1_75((l.cdr))); + } + else + return undefined; + }; + (sc_loop1_75(preds)); + } + } + else + return undefined; + } + } + } + }; + is_parsed = function(nt, i, j, sc_nts_86, sc_enders_87, sc_states_88) { + var conf_set; + var state; + var sc_conf_89; + var l; + var BgL_sc_ntza2_90za2; + { + (BgL_sc_ntza2_90za2 = (sc_ind_43(nt, sc_nts_86))); + if ((BgL_sc_ntza2_90za2!== false)) + { + (sc_nts_86.length); + (l = (sc_enders_87[BgL_sc_ntza2_90za2])); + while (true) { + if ((l instanceof sc_Pair)) + { + (sc_conf_89 = (l.car)); + if ((((state = (sc_states_88[j])), (conf_set = (state[(sc_conf_89+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false)) + return true; + else + (l = (l.cdr)); + } + else + return false; + } + } + else + return false; + } + }; + deriv_trees = function(sc_conf_91, i, j, sc_enders_92, sc_steps_93, sc_names_94, sc_toks_95, sc_states_96, BgL_sc_nbzd2nts_97zd2) { + var sc_loop1_98; + var prev; + var name; + return ((name = (sc_names_94[sc_conf_91])), ((name!== false)?((sc_conf_91=(0))) + if (((k>=i)&&(((sc_state_99 = (sc_states_96[k])), (conf_set = (sc_state_99[(prev+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false))) + { + (prev_trees = (deriv_trees(prev, i, k, sc_enders_92, sc_steps_93, sc_names_94, sc_toks_95, sc_states_96, BgL_sc_nbzd2nts_97zd2))); + (ender_trees = (deriv_trees(ender, k, j, sc_enders_92, sc_steps_93, sc_names_94, sc_toks_95, sc_states_96, BgL_sc_nbzd2nts_97zd2))); + loop3 = function(l3, l2) { + var l4; + var sc_l2_100; + var ender_tree; + if ((l3 instanceof sc_Pair)) + { + (ender_tree = (sc_list((l3.car)))); + (l4 = prev_trees); + (sc_l2_100 = l2); + while ((l4 instanceof sc_Pair)) { + { + (sc_l2_100 = (new sc_Pair((sc_append((l4.car), ender_tree)), sc_l2_100))); + (l4 = (l4.cdr)); + } + } + return (loop3((l3.cdr), sc_l2_100)); + } + else + return (loop2((ender_set[(k+(5))]), l2)); + }; + return (loop3(ender_trees, l2)); + } + else + (k = (ender_set[(k+(5))])); + else + return (sc_loop1_98((l1.cdr), l2)); + } + }; + return (loop2((ender_set[(2)]), l2)); + } + else + (l1 = (l1.cdr)); + } + else + return l2; + } + }), (sc_loop1_98((sc_enders_92[(sc_steps_93[prev])]), null))))); + }; + BgL_sc_derivzd2treesza2_47z70 = function(nt, i, j, sc_nts_101, sc_enders_102, sc_steps_103, sc_names_104, sc_toks_105, sc_states_106) { + var conf_set; + var state; + var sc_conf_107; + var l; + var trees; + var BgL_sc_nbzd2nts_108zd2; + var BgL_sc_ntza2_109za2; + { + (BgL_sc_ntza2_109za2 = (sc_ind_43(nt, sc_nts_101))); + if ((BgL_sc_ntza2_109za2!== false)) + { + (BgL_sc_nbzd2nts_108zd2 = (sc_nts_101.length)); + (l = (sc_enders_102[BgL_sc_ntza2_109za2])); + (trees = null); + while ((l instanceof sc_Pair)) { + { + (sc_conf_107 = (l.car)); + if ((((state = (sc_states_106[j])), (conf_set = (state[(sc_conf_107+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false)) + { + (l = (l.cdr)); + (trees = (sc_append((deriv_trees(sc_conf_107, i, j, sc_enders_102, sc_steps_103, sc_names_104, sc_toks_105, sc_states_106, BgL_sc_nbzd2nts_108zd2)), trees))); + } + else + (l = (l.cdr)); + } + } + return trees; + } + else + return false; + } + }; + nb_deriv_trees = function(sc_conf_110, i, j, sc_enders_111, sc_steps_112, sc_toks_113, sc_states_114, BgL_sc_nbzd2nts_115zd2) { + var sc_loop1_116; + var tmp1124; + var prev; + return ((prev = (sc_conf_110-(1))), ((((tmp1124 = (sc_conf_110=(0))) { + if (((k>=i)&&(((state = (sc_states_114[k])), (conf_set = (state[(prev+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false))) + { + (nb_prev_trees = (nb_deriv_trees(prev, i, k, sc_enders_111, sc_steps_112, sc_toks_113, sc_states_114, BgL_sc_nbzd2nts_115zd2))); + (nb_ender_trees = (nb_deriv_trees(ender, k, j, sc_enders_111, sc_steps_112, sc_toks_113, sc_states_114, BgL_sc_nbzd2nts_115zd2))); + (k = (ender_set[(k+(5))])); + (n +=(nb_prev_trees*nb_ender_trees)); + } + else + (k = (ender_set[(k+(5))])); + } + return (sc_loop1_116((l.cdr), n)); + } + else + (l = (l.cdr)); + } + else + return sc_n_118; + } + }), (sc_loop1_116((sc_enders_111[(sc_steps_112[prev])]), (0)))))); + }; + BgL_sc_nbzd2derivzd2treesza2_48za2 = function(nt, i, j, sc_nts_119, sc_enders_120, sc_steps_121, sc_toks_122, sc_states_123) { + var conf_set; + var state; + var sc_conf_124; + var l; + var nb_trees; + var BgL_sc_nbzd2nts_125zd2; + var BgL_sc_ntza2_126za2; + { + (BgL_sc_ntza2_126za2 = (sc_ind_43(nt, sc_nts_119))); + if ((BgL_sc_ntza2_126za2!== false)) + { + (BgL_sc_nbzd2nts_125zd2 = (sc_nts_119.length)); + (l = (sc_enders_120[BgL_sc_ntza2_126za2])); + (nb_trees = (0)); + while ((l instanceof sc_Pair)) { + { + (sc_conf_124 = (l.car)); + if ((((state = (sc_states_123[j])), (conf_set = (state[(sc_conf_124+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false)) + { + (l = (l.cdr)); + (nb_trees = ((nb_deriv_trees(sc_conf_124, i, j, sc_enders_120, sc_steps_121, sc_toks_122, sc_states_123, BgL_sc_nbzd2nts_125zd2))+nb_trees)); + } + else + (l = (l.cdr)); + } + } + return nb_trees; + } + else + return false; + } + }; + (lexer = (parser_descr[(0)])); + (sc_nts_42 = (parser_descr[(1)])); + (sc_starters_41 = (parser_descr[(2)])); + (sc_enders_40 = (parser_descr[(3)])); + (sc_predictors_39 = (parser_descr[(4)])); + (sc_steps_38 = (parser_descr[(5)])); + (sc_names_37 = (parser_descr[(6)])); + (falseHead1128 = (new sc_Pair(null, null))); + (L1125 = (lexer(input))); + (tail1129 = falseHead1128); + while (!(L1125 === null)) { + { + (tok = (L1125.car)); + (l1 = (tok.cdr)); + (l2 = null); + while ((l1 instanceof sc_Pair)) { + { + (sc_i_29 = (sc_ind_43((l1.car), sc_nts_42))); + if ((sc_i_29!== false)) + { + (l1 = (l1.cdr)); + (l2 = (new sc_Pair(sc_i_29, l2))); + } + else + (l1 = (l1.cdr)); + } + } + (sc_optrOpnd_22 = (new sc_Pair((tok.car), (sc_reverse(l2))))); + (sc_optrOpnd_21 = (new sc_Pair(sc_optrOpnd_22, null))); + (tail1129.cdr = sc_optrOpnd_21); + (tail1129 = (tail1129.cdr)); + (L1125 = (L1125.cdr)); + } + } + (sc_optrOpnd_20 = (falseHead1128.cdr)); + (sc_toks_36 = (sc_list2vector(sc_optrOpnd_20))); + (BgL_sc_nbzd2toks_35zd2 = (sc_toks_36.length)); + (BgL_sc_nbzd2confs_34zd2 = (sc_steps_38.length)); + (sc_states_33 = (make_states(BgL_sc_nbzd2toks_35zd2, BgL_sc_nbzd2confs_34zd2))); + (goal_starters = (sc_starters_41[(0)])); + (BgL_sc_confzd2setzd2adjoinza2_45za2(sc_states_33, (0), goal_starters, (0))); + (forw(sc_states_33, (0), sc_starters_41, sc_enders_40, sc_predictors_39, sc_steps_38, sc_nts_42)); + (sc_i_28 = (0)); + while ((sc_i_28=(0))) { + { + (states = sc_states_33); + (BgL_sc_statesza2_27za2 = BgL_sc_statesza2_30za2); + (state_num = i); + (sc_enders_26 = sc_enders_40); + (sc_steps_25 = sc_steps_38); + (BgL_sc_nbzd2nts_24zd2 = BgL_sc_nbzd2nts_31zd2); + (toks = sc_toks_36); + (BgL_sc_stateza2_23za2 = (BgL_sc_statesza2_30za2[i])); + loop1 = function() { + var sc_loop1_127; + var prev; + var BgL_sc_statesza2_128za2; + var sc_states_129; + var j; + var i; + var sc_i_130; + var head; + var conf_set; + var sc_conf_131; + { + (sc_conf_131 = (BgL_sc_stateza2_23za2[(0)])); + if ((sc_conf_131>=(0))) + { + (conf_set = (BgL_sc_stateza2_23za2[(sc_conf_131+(1))])); + (head = (conf_set[(4)])); + (BgL_sc_stateza2_23za2[(0)] = (conf_set[(0)])); + (conf_set_merge_new_bang(conf_set)); + (sc_i_130 = head); + while ((sc_i_130>=(0))) { + { + (i = sc_i_130); + (j = state_num); + (sc_states_129 = states); + (BgL_sc_statesza2_128za2 = BgL_sc_statesza2_27za2); + (prev = (sc_conf_131-(1))); + if (((sc_conf_131>=BgL_sc_nbzd2nts_24zd2)&&((sc_steps_25[prev])>=(0)))) + { + sc_loop1_127 = function(l) { + var k; + var ender_set; + var state; + var ender; + var l; + while (true) { + if ((l instanceof sc_Pair)) + { + (ender = (l.car)); + (ender_set = ((state = (sc_states_129[j])), (state[(ender+(1))]))); + if ((ender_set!== false)) + { + (k = (ender_set[(2)])); + while ((k>=(0))) { + { + if ((k>=i)) + if (((BgL_sc_confzd2setzd2adjoinza2za2_46z00(sc_states_129, BgL_sc_statesza2_128za2, k, prev, i))!== false)) + (BgL_sc_confzd2setzd2adjoinza2za2_46z00(sc_states_129, BgL_sc_statesza2_128za2, j, ender, k)); + (k = (ender_set[(k+(5))])); + } + } + return (sc_loop1_127((l.cdr))); + } + else + (l = (l.cdr)); + } + else + return undefined; + } + }; + (sc_loop1_127((sc_enders_26[(sc_steps_25[prev])]))); + } + (sc_i_130 = (conf_set[(sc_i_130+(5))])); + } + } + return (loop1()); + } + else + return undefined; + } + }; + (loop1()); + (--i); + } + } + (optrOpnd = BgL_sc_statesza2_30za2); + return [sc_nts_42, sc_starters_41, sc_enders_40, sc_predictors_39, sc_steps_38, sc_names_37, sc_toks_36, optrOpnd, is_parsed, BgL_sc_derivzd2treesza2_47z70, BgL_sc_nbzd2derivzd2treesza2_48za2]; + } + }; + } + }; + BgL_parsezd2ze3parsedzf3zc2 = function(parse, nt, i, j) { + var is_parsed; + var states; + var enders; + var nts; + return ((nts = (parse[(0)])), (enders = (parse[(2)])), (states = (parse[(7)])), (is_parsed = (parse[(8)])), (is_parsed(nt, i, j, nts, enders, states))); + }; + BgL_parsezd2ze3treesz31 = function(parse, nt, i, j) { + var BgL_sc_derivzd2treesza2_132z70; + var states; + var toks; + var names; + var steps; + var enders; + var nts; + return ((nts = (parse[(0)])), (enders = (parse[(2)])), (steps = (parse[(4)])), (names = (parse[(5)])), (toks = (parse[(6)])), (states = (parse[(7)])), (BgL_sc_derivzd2treesza2_132z70 = (parse[(9)])), (BgL_sc_derivzd2treesza2_132z70(nt, i, j, nts, enders, steps, names, toks, states))); + }; + BgL_parsezd2ze3nbzd2treesze3 = function(parse, nt, i, j) { + var BgL_sc_nbzd2derivzd2treesza2_133za2; + var states; + var toks; + var steps; + var enders; + var nts; + return ((nts = (parse[(0)])), (enders = (parse[(2)])), (steps = (parse[(4)])), (toks = (parse[(6)])), (states = (parse[(7)])), (BgL_sc_nbzd2derivzd2treesza2_133za2 = (parse[(10)])), (BgL_sc_nbzd2derivzd2treesza2_133za2(nt, i, j, nts, enders, steps, toks, states))); + }; + test = function(k) { + var x; + var p; + return ((p = (BgL_makezd2parserzd2(const_earley, function(l) { + var sc_x_134; + var tail1134; + var L1130; + var falseHead1133; + { + (falseHead1133 = (new sc_Pair(null, null))); + (tail1134 = falseHead1133); + (L1130 = l); + while (!(L1130 === null)) { + { + (tail1134.cdr = (new sc_Pair(((sc_x_134 = (L1130.car)), (sc_list(sc_x_134, sc_x_134))), null))); + (tail1134 = (tail1134.cdr)); + (L1130 = (L1130.cdr)); + } + } + return (falseHead1133.cdr); + } + }))), (x = (p((sc_vector2list((sc_makeVector(k, "\u1E9Ca"))))))), (sc_length((BgL_parsezd2ze3treesz31(x, "\u1E9Cs", (0), k))))); + }; + BgL_earleyzd2benchmarkzd2 = function() { + var args = null; + for (var sc_tmp = arguments.length - 1; sc_tmp >= 0; sc_tmp--) { + args = sc_cons(arguments[sc_tmp], args); + } + var k; + return ((k = ((args === null)?(7):(args.car))), (BgL_runzd2benchmarkzd2("earley", (1), function() { + return (test(k)); + }, function(result) { + return ((sc_display(result)), (sc_newline()), result == 132); + }))); + }; +} + + +/************* END OF GENERATED CODE *************/ +// Invoke this function to run a benchmark. +// The first argument is a string identifying the benchmark. +// The second argument is the number of times to run the benchmark. +// The third argument is a function that runs the benchmark. +// The fourth argument is a unary function that warns if the result +// returned by the benchmark is incorrect. +// +// Example: +// RunBenchmark("new Array()", +// 1, +// function () { new Array(1000000); } +// function (v) { +// return (v instanceof Array) && (v.length == 1000000); +// }); + +SC_DEFAULT_OUT = new sc_GenericOutputPort(function(s) {}); +SC_ERROR_OUT = SC_DEFAULT_OUT; + +function RunBenchmark(name, count, run, warn) { + for (var n = 0; n < count; ++n) { + result = run(); + if (!warn(result)) { + throw new Error("Earley or Boyer did incorrect number of rewrites"); + } + } +} + +var BgL_runzd2benchmarkzd2 = RunBenchmark; + + +(function () { BgL_earleyzd2benchmarkzd2(); })(); +(function () { BgL_nboyerzd2benchmarkzd2(); })(); diff --git a/js/src/jit-test/tests/v8-v5/check-raytrace.js b/js/src/jit-test/tests/v8-v5/check-raytrace.js new file mode 100644 index 0000000..901cb3f --- /dev/null +++ b/js/src/jit-test/tests/v8-v5/check-raytrace.js @@ -0,0 +1,935 @@ +// The ray tracer code in this file is written by Adam Burmister. It +// is available in its original form from: +// +// http://labs.flog.nz.co/raytracer/ +// +// It has been modified slightly by Google to work as a standalone +// benchmark, but the all the computational code remains +// untouched. This file also contains a copy of parts of the Prototype +// JavaScript framework which is used by the ray tracer. + +//var RayTrace = new BenchmarkSuite('RayTrace', 932666, [ +// new Benchmark('RayTrace', renderScene) +//]); + + +// Variable used to hold a number that can be used to verify that +// the scene was ray traced correctly. +var checkNumber; + + +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ + +// The following is a copy of parts of the Prototype JavaScript library: + +// Prototype JavaScript framework, version 1.5.0 +// (c) 2005-2007 Sam Stephenson +// +// Prototype is freely distributable under the terms of an MIT-style license. +// For details, see the Prototype web site: http://prototype.conio.net/ + + +var Class = { + create: function() { + return function() { + this.initialize.apply(this, arguments); + } + } +}; + + +Object.extend = function(destination, source) { + for (var property in source) { + destination[property] = source[property]; + } + return destination; +}; + + +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ + +// The rest of this file is the actual ray tracer written by Adam +// Burmister. It's a concatenation of the following files: +// +// flog/color.js +// flog/light.js +// flog/vector.js +// flog/ray.js +// flog/scene.js +// flog/material/basematerial.js +// flog/material/solid.js +// flog/material/chessboard.js +// flog/shape/baseshape.js +// flog/shape/sphere.js +// flog/shape/plane.js +// flog/intersectioninfo.js +// flog/camera.js +// flog/background.js +// flog/engine.js + + +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Color = Class.create(); + +Flog.RayTracer.Color.prototype = { + red : 0.0, + green : 0.0, + blue : 0.0, + + initialize : function(r, g, b) { + if(!r) r = 0.0; + if(!g) g = 0.0; + if(!b) b = 0.0; + + this.red = r; + this.green = g; + this.blue = b; + }, + + add : function(c1, c2){ + var result = new Flog.RayTracer.Color(0,0,0); + + result.red = c1.red + c2.red; + result.green = c1.green + c2.green; + result.blue = c1.blue + c2.blue; + + return result; + }, + + addScalar: function(c1, s){ + var result = new Flog.RayTracer.Color(0,0,0); + + result.red = c1.red + s; + result.green = c1.green + s; + result.blue = c1.blue + s; + + result.limit(); + + return result; + }, + + subtract: function(c1, c2){ + var result = new Flog.RayTracer.Color(0,0,0); + + result.red = c1.red - c2.red; + result.green = c1.green - c2.green; + result.blue = c1.blue - c2.blue; + + return result; + }, + + multiply : function(c1, c2) { + var result = new Flog.RayTracer.Color(0,0,0); + + result.red = c1.red * c2.red; + result.green = c1.green * c2.green; + result.blue = c1.blue * c2.blue; + + return result; + }, + + multiplyScalar : function(c1, f) { + var result = new Flog.RayTracer.Color(0,0,0); + + result.red = c1.red * f; + result.green = c1.green * f; + result.blue = c1.blue * f; + + return result; + }, + + divideFactor : function(c1, f) { + var result = new Flog.RayTracer.Color(0,0,0); + + result.red = c1.red / f; + result.green = c1.green / f; + result.blue = c1.blue / f; + + return result; + }, + + limit: function(){ + this.red = (this.red > 0.0) ? ( (this.red > 1.0) ? 1.0 : this.red ) : 0.0; + this.green = (this.green > 0.0) ? ( (this.green > 1.0) ? 1.0 : this.green ) : 0.0; + this.blue = (this.blue > 0.0) ? ( (this.blue > 1.0) ? 1.0 : this.blue ) : 0.0; + }, + + distance : function(color) { + var d = Math.abs(this.red - color.red) + Math.abs(this.green - color.green) + Math.abs(this.blue - color.blue); + return d; + }, + + blend: function(c1, c2, w){ + var result = new Flog.RayTracer.Color(0,0,0); + result = Flog.RayTracer.Color.prototype.add( + Flog.RayTracer.Color.prototype.multiplyScalar(c1, 1 - w), + Flog.RayTracer.Color.prototype.multiplyScalar(c2, w) + ); + return result; + }, + + brightness : function() { + var r = Math.floor(this.red*255); + var g = Math.floor(this.green*255); + var b = Math.floor(this.blue*255); + return (r * 77 + g * 150 + b * 29) >> 8; + }, + + toString : function () { + var r = Math.floor(this.red*255); + var g = Math.floor(this.green*255); + var b = Math.floor(this.blue*255); + + return "rgb("+ r +","+ g +","+ b +")"; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Light = Class.create(); + +Flog.RayTracer.Light.prototype = { + position: null, + color: null, + intensity: 10.0, + + initialize : function(pos, color, intensity) { + this.position = pos; + this.color = color; + this.intensity = (intensity ? intensity : 10.0); + }, + + getIntensity: function(distance){ + if(distance >= intensity) return 0; + + return Math.pow((intensity - distance) / strength, 0.2); + }, + + toString : function () { + return 'Light [' + this.position.x + ',' + this.position.y + ',' + this.position.z + ']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Vector = Class.create(); + +Flog.RayTracer.Vector.prototype = { + x : 0.0, + y : 0.0, + z : 0.0, + + initialize : function(x, y, z) { + this.x = (x ? x : 0); + this.y = (y ? y : 0); + this.z = (z ? z : 0); + }, + + copy: function(vector){ + this.x = vector.x; + this.y = vector.y; + this.z = vector.z; + }, + + normalize : function() { + var m = this.magnitude(); + return new Flog.RayTracer.Vector(this.x / m, this.y / m, this.z / m); + }, + + magnitude : function() { + return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z)); + }, + + cross : function(w) { + return new Flog.RayTracer.Vector( + -this.z * w.y + this.y * w.z, + this.z * w.x - this.x * w.z, + -this.y * w.x + this.x * w.y); + }, + + dot : function(w) { + return this.x * w.x + this.y * w.y + this.z * w.z; + }, + + add : function(v, w) { + return new Flog.RayTracer.Vector(w.x + v.x, w.y + v.y, w.z + v.z); + }, + + subtract : function(v, w) { + if(!w || !v) throw 'Vectors must be defined [' + v + ',' + w + ']'; + return new Flog.RayTracer.Vector(v.x - w.x, v.y - w.y, v.z - w.z); + }, + + multiplyVector : function(v, w) { + return new Flog.RayTracer.Vector(v.x * w.x, v.y * w.y, v.z * w.z); + }, + + multiplyScalar : function(v, w) { + return new Flog.RayTracer.Vector(v.x * w, v.y * w, v.z * w); + }, + + toString : function () { + return 'Vector [' + this.x + ',' + this.y + ',' + this.z + ']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Ray = Class.create(); + +Flog.RayTracer.Ray.prototype = { + position : null, + direction : null, + initialize : function(pos, dir) { + this.position = pos; + this.direction = dir; + }, + + toString : function () { + return 'Ray [' + this.position + ',' + this.direction + ']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Scene = Class.create(); + +Flog.RayTracer.Scene.prototype = { + camera : null, + shapes : [], + lights : [], + background : null, + + initialize : function() { + this.camera = new Flog.RayTracer.Camera( + new Flog.RayTracer.Vector(0,0,-5), + new Flog.RayTracer.Vector(0,0,1), + new Flog.RayTracer.Vector(0,1,0) + ); + this.shapes = new Array(); + this.lights = new Array(); + this.background = new Flog.RayTracer.Background(new Flog.RayTracer.Color(0,0,0.5), 0.2); + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; +if(typeof(Flog.RayTracer.Material) == 'undefined') Flog.RayTracer.Material = {}; + +Flog.RayTracer.Material.BaseMaterial = Class.create(); + +Flog.RayTracer.Material.BaseMaterial.prototype = { + + gloss: 2.0, // [0...infinity] 0 = matt + transparency: 0.0, // 0=opaque + reflection: 0.0, // [0...infinity] 0 = no reflection + refraction: 0.50, + hasTexture: false, + + initialize : function() { + + }, + + getColor: function(u, v){ + + }, + + wrapUp: function(t){ + t = t % 2.0; + if(t < -1) t += 2.0; + if(t >= 1) t -= 2.0; + return t; + }, + + toString : function () { + return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Material.Solid = Class.create(); + +Flog.RayTracer.Material.Solid.prototype = Object.extend( + new Flog.RayTracer.Material.BaseMaterial(), { + initialize : function(color, reflection, refraction, transparency, gloss) { + this.color = color; + this.reflection = reflection; + this.transparency = transparency; + this.gloss = gloss; + this.hasTexture = false; + }, + + getColor: function(u, v){ + return this.color; + }, + + toString : function () { + return 'SolidMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']'; + } + } +); +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Material.Chessboard = Class.create(); + +Flog.RayTracer.Material.Chessboard.prototype = Object.extend( + new Flog.RayTracer.Material.BaseMaterial(), { + colorEven: null, + colorOdd: null, + density: 0.5, + + initialize : function(colorEven, colorOdd, reflection, transparency, gloss, density) { + this.colorEven = colorEven; + this.colorOdd = colorOdd; + this.reflection = reflection; + this.transparency = transparency; + this.gloss = gloss; + this.density = density; + this.hasTexture = true; + }, + + getColor: function(u, v){ + var t = this.wrapUp(u * this.density) * this.wrapUp(v * this.density); + + if(t < 0.0) + return this.colorEven; + else + return this.colorOdd; + }, + + toString : function () { + return 'ChessMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']'; + } + } +); +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; +if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {}; + +Flog.RayTracer.Shape.BaseShape = Class.create(); + +Flog.RayTracer.Shape.BaseShape.prototype = { + position: null, + material: null, + + initialize : function() { + this.position = new Vector(0,0,0); + this.material = new Flog.RayTracer.Material.SolidMaterial( + new Flog.RayTracer.Color(1,0,1), + 0, + 0, + 0 + ); + }, + + toString : function () { + return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; +if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {}; + +Flog.RayTracer.Shape.Sphere = Class.create(); + +Flog.RayTracer.Shape.Sphere.prototype = { + initialize : function(pos, radius, material) { + this.radius = radius; + this.position = pos; + this.material = material; + }, + + intersect: function(ray){ + var info = new Flog.RayTracer.IntersectionInfo(); + info.shape = this; + + var dst = Flog.RayTracer.Vector.prototype.subtract(ray.position, this.position); + + var B = dst.dot(ray.direction); + var C = dst.dot(dst) - (this.radius * this.radius); + var D = (B * B) - C; + + if(D > 0){ // intersection! + info.isHit = true; + info.distance = (-B) - Math.sqrt(D); + info.position = Flog.RayTracer.Vector.prototype.add( + ray.position, + Flog.RayTracer.Vector.prototype.multiplyScalar( + ray.direction, + info.distance + ) + ); + info.normal = Flog.RayTracer.Vector.prototype.subtract( + info.position, + this.position + ).normalize(); + + info.color = this.material.getColor(0,0); + } else { + info.isHit = false; + } + return info; + }, + + toString : function () { + return 'Sphere [position=' + this.position + ', radius=' + this.radius + ']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; +if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {}; + +Flog.RayTracer.Shape.Plane = Class.create(); + +Flog.RayTracer.Shape.Plane.prototype = { + d: 0.0, + + initialize : function(pos, d, material) { + this.position = pos; + this.d = d; + this.material = material; + }, + + intersect: function(ray){ + var info = new Flog.RayTracer.IntersectionInfo(); + + var Vd = this.position.dot(ray.direction); + if(Vd == 0) return info; // no intersection + + var t = -(this.position.dot(ray.position) + this.d) / Vd; + if(t <= 0) return info; + + info.shape = this; + info.isHit = true; + info.position = Flog.RayTracer.Vector.prototype.add( + ray.position, + Flog.RayTracer.Vector.prototype.multiplyScalar( + ray.direction, + t + ) + ); + info.normal = this.position; + info.distance = t; + + if(this.material.hasTexture){ + var vU = new Flog.RayTracer.Vector(this.position.y, this.position.z, -this.position.x); + var vV = vU.cross(this.position); + var u = info.position.dot(vU); + var v = info.position.dot(vV); + info.color = this.material.getColor(u,v); + } else { + info.color = this.material.getColor(0,0); + } + + return info; + }, + + toString : function () { + return 'Plane [' + this.position + ', d=' + this.d + ']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.IntersectionInfo = Class.create(); + +Flog.RayTracer.IntersectionInfo.prototype = { + isHit: false, + hitCount: 0, + shape: null, + position: null, + normal: null, + color: null, + distance: null, + + initialize : function() { + this.color = new Flog.RayTracer.Color(0,0,0); + }, + + toString : function () { + return 'Intersection [' + this.position + ']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Camera = Class.create(); + +Flog.RayTracer.Camera.prototype = { + position: null, + lookAt: null, + equator: null, + up: null, + screen: null, + + initialize : function(pos, lookAt, up) { + this.position = pos; + this.lookAt = lookAt; + this.up = up; + this.equator = lookAt.normalize().cross(this.up); + this.screen = Flog.RayTracer.Vector.prototype.add(this.position, this.lookAt); + }, + + getRay: function(vx, vy){ + var pos = Flog.RayTracer.Vector.prototype.subtract( + this.screen, + Flog.RayTracer.Vector.prototype.subtract( + Flog.RayTracer.Vector.prototype.multiplyScalar(this.equator, vx), + Flog.RayTracer.Vector.prototype.multiplyScalar(this.up, vy) + ) + ); + pos.y = pos.y * -1; + var dir = Flog.RayTracer.Vector.prototype.subtract( + pos, + this.position + ); + + var ray = new Flog.RayTracer.Ray(pos, dir.normalize()); + + return ray; + }, + + toString : function () { + return 'Ray []'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Background = Class.create(); + +Flog.RayTracer.Background.prototype = { + color : null, + ambience : 0.0, + + initialize : function(color, ambience) { + this.color = color; + this.ambience = ambience; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Engine = Class.create(); + +Flog.RayTracer.Engine.prototype = { + canvas: null, /* 2d context we can render to */ + + initialize: function(options){ + this.options = Object.extend({ + canvasHeight: 100, + canvasWidth: 100, + pixelWidth: 2, + pixelHeight: 2, + renderDiffuse: false, + renderShadows: false, + renderHighlights: false, + renderReflections: false, + rayDepth: 2 + }, options || {}); + + this.options.canvasHeight /= this.options.pixelHeight; + this.options.canvasWidth /= this.options.pixelWidth; + + /* TODO: dynamically include other scripts */ + }, + + setPixel: function(x, y, color){ + var pxW, pxH; + pxW = this.options.pixelWidth; + pxH = this.options.pixelHeight; + + if (this.canvas) { + this.canvas.fillStyle = color.toString(); + this.canvas.fillRect (x * pxW, y * pxH, pxW, pxH); + } else { + if (x === y) { + checkNumber += color.brightness(); + } + // print(x * pxW, y * pxH, pxW, pxH); + } + }, + + renderScene: function(scene, canvas){ + checkNumber = 0; + /* Get canvas */ + if (canvas) { + this.canvas = canvas.getContext("2d"); + } else { + this.canvas = null; + } + + var canvasHeight = this.options.canvasHeight; + var canvasWidth = this.options.canvasWidth; + + for(var y=0; y < canvasHeight; y++){ + for(var x=0; x < canvasWidth; x++){ + var yp = y * 1.0 / canvasHeight * 2 - 1; + var xp = x * 1.0 / canvasWidth * 2 - 1; + + var ray = scene.camera.getRay(xp, yp); + + var color = this.getPixelColor(ray, scene); + + this.setPixel(x, y, color); + } + } + assertEq(checkNumber, 2321); + }, + + getPixelColor: function(ray, scene){ + var info = this.testIntersection(ray, scene, null); + if(info.isHit){ + var color = this.rayTrace(info, ray, scene, 0); + return color; + } + return scene.background.color; + }, + + testIntersection: function(ray, scene, exclude){ + var hits = 0; + var best = new Flog.RayTracer.IntersectionInfo(); + best.distance = 2000; + + for(var i=0; i= 0 && info.distance < best.distance){ + best = info; + hits++; + } + } + } + best.hitCount = hits; + return best; + }, + + getReflectionRay: function(P,N,V){ + var c1 = -N.dot(V); + var R1 = Flog.RayTracer.Vector.prototype.add( + Flog.RayTracer.Vector.prototype.multiplyScalar(N, 2*c1), + V + ); + return new Flog.RayTracer.Ray(P, R1); + }, + + rayTrace: function(info, ray, scene, depth){ + // Calc ambient + var color = Flog.RayTracer.Color.prototype.multiplyScalar(info.color, scene.background.ambience); + var oldColor = color; + var shininess = Math.pow(10, info.shape.material.gloss + 1); + + for(var i=0; i 0.0){ + color = Flog.RayTracer.Color.prototype.add( + color, + Flog.RayTracer.Color.prototype.multiply( + info.color, + Flog.RayTracer.Color.prototype.multiplyScalar( + light.color, + L + ) + ) + ); + } + } + + // The greater the depth the more accurate the colours, but + // this is exponentially (!) expensive + if(depth <= this.options.rayDepth){ + // calculate reflection ray + if(this.options.renderReflections && info.shape.material.reflection > 0) + { + var reflectionRay = this.getReflectionRay(info.position, info.normal, ray.direction); + var refl = this.testIntersection(reflectionRay, scene, info.shape); + + if (refl.isHit && refl.distance > 0){ + refl.color = this.rayTrace(refl, reflectionRay, scene, depth + 1); + } else { + refl.color = scene.background.color; + } + + color = Flog.RayTracer.Color.prototype.blend( + color, + refl.color, + info.shape.material.reflection + ); + } + + // Refraction + /* TODO */ + } + + /* Render shadows and highlights */ + + var shadowInfo = new Flog.RayTracer.IntersectionInfo(); + + if(this.options.renderShadows){ + var shadowRay = new Flog.RayTracer.Ray(info.position, v); + + shadowInfo = this.testIntersection(shadowRay, scene, info.shape); + if(shadowInfo.isHit && shadowInfo.shape != info.shape /*&& shadowInfo.shape.type != 'PLANE'*/){ + var vA = Flog.RayTracer.Color.prototype.multiplyScalar(color, 0.5); + var dB = (0.5 * Math.pow(shadowInfo.shape.material.transparency, 0.5)); + color = Flog.RayTracer.Color.prototype.addScalar(vA,dB); + } + } + + // Phong specular highlights + if(this.options.renderHighlights && !shadowInfo.isHit && info.shape.material.gloss > 0){ + var Lv = Flog.RayTracer.Vector.prototype.subtract( + info.shape.position, + light.position + ).normalize(); + + var E = Flog.RayTracer.Vector.prototype.subtract( + scene.camera.position, + info.shape.position + ).normalize(); + + var H = Flog.RayTracer.Vector.prototype.subtract( + E, + Lv + ).normalize(); + + var glossWeight = Math.pow(Math.max(info.normal.dot(H), 0), shininess); + color = Flog.RayTracer.Color.prototype.add( + Flog.RayTracer.Color.prototype.multiplyScalar(light.color, glossWeight), + color + ); + } + } + color.limit(); + return color; + } +}; + + +function renderScene(){ + var scene = new Flog.RayTracer.Scene(); + + scene.camera = new Flog.RayTracer.Camera( + new Flog.RayTracer.Vector(0, 0, -15), + new Flog.RayTracer.Vector(-0.2, 0, 5), + new Flog.RayTracer.Vector(0, 1, 0) + ); + + scene.background = new Flog.RayTracer.Background( + new Flog.RayTracer.Color(0.5, 0.5, 0.5), + 0.4 + ); + + var sphere = new Flog.RayTracer.Shape.Sphere( + new Flog.RayTracer.Vector(-1.5, 1.5, 2), + 1.5, + new Flog.RayTracer.Material.Solid( + new Flog.RayTracer.Color(0,0.5,0.5), + 0.3, + 0.0, + 0.0, + 2.0 + ) + ); + + var sphere1 = new Flog.RayTracer.Shape.Sphere( + new Flog.RayTracer.Vector(1, 0.25, 1), + 0.5, + new Flog.RayTracer.Material.Solid( + new Flog.RayTracer.Color(0.9,0.9,0.9), + 0.1, + 0.0, + 0.0, + 1.5 + ) + ); + + var plane = new Flog.RayTracer.Shape.Plane( + new Flog.RayTracer.Vector(0.1, 0.9, -0.5).normalize(), + 1.2, + new Flog.RayTracer.Material.Chessboard( + new Flog.RayTracer.Color(1,1,1), + new Flog.RayTracer.Color(0,0,0), + 0.2, + 0.0, + 1.0, + 0.7 + ) + ); + + scene.shapes.push(plane); + scene.shapes.push(sphere); + scene.shapes.push(sphere1); + + var light = new Flog.RayTracer.Light( + new Flog.RayTracer.Vector(5, 10, -1), + new Flog.RayTracer.Color(0.8, 0.8, 0.8) + ); + + var light1 = new Flog.RayTracer.Light( + new Flog.RayTracer.Vector(-3, 5, -15), + new Flog.RayTracer.Color(0.8, 0.8, 0.8), + 100 + ); + + scene.lights.push(light); + scene.lights.push(light1); + + var imageWidth = 100; // $F('imageWidth'); + var imageHeight = 100; // $F('imageHeight'); + var pixelSize = "5,5".split(','); // $F('pixelSize').split(','); + var renderDiffuse = true; // $F('renderDiffuse'); + var renderShadows = true; // $F('renderShadows'); + var renderHighlights = true; // $F('renderHighlights'); + var renderReflections = true; // $F('renderReflections'); + var rayDepth = 2;//$F('rayDepth'); + + var raytracer = new Flog.RayTracer.Engine( + { + canvasWidth: imageWidth, + canvasHeight: imageHeight, + pixelWidth: pixelSize[0], + pixelHeight: pixelSize[1], + "renderDiffuse": renderDiffuse, + "renderHighlights": renderHighlights, + "renderShadows": renderShadows, + "renderReflections": renderReflections, + "rayDepth": rayDepth + } + ); + + raytracer.renderScene(scene, null, 0); +} + +renderScene(); diff --git a/js/src/jit-test/tests/v8-v5/check-regexp.js b/js/src/jit-test/tests/v8-v5/check-regexp.js new file mode 100644 index 0000000..9bcd72a --- /dev/null +++ b/js/src/jit-test/tests/v8-v5/check-regexp.js @@ -0,0 +1,1616 @@ +// Copyright 2009 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Automatically generated on 2009-01-30. + +// This benchmark is generated by loading 50 of the most popular pages +// on the web and logging all regexp operations performed. Each +// operation is given a weight that is calculated from an estimate of +// the popularity of the pages where it occurs and the number of times +// it is executed while loading each page. Finally the literal +// letters in the data are encoded using ROT13 in a way that does not +// affect how the regexps match their input. + +//var RegRxp = new BenchmarkSuite('RegExp', 995230, [ +// new Benchmark("RegExp", runRegExpBenchmark) +//]); + +function runRegExpBenchmark() { + var re0 = /^ba/; + var re1 = /(((\w+):\/\/)([^\/:]*)(:(\d+))?)?([^#?]*)(\?([^#]*))?(#(.*))?/; + var re2 = /^\s*|\s*$/g; + var re3 = /\bQBZPbageby_cynprubyqre\b/; + var re4 = /,/; + var re5 = /\bQBZPbageby_cynprubyqre\b/g; + var re6 = /^[\s\xa0]+|[\s\xa0]+$/g; + var re7 = /(\d*)(\D*)/g; + var re8 = /=/; + var re9 = /(^|\s)lhv\-h(\s|$)/; + var str0 = 'Zbmvyyn/5.0 (Jvaqbjf; H; Jvaqbjf AG 5.1; ra-HF) NccyrJroXvg/528.9 (XUGZY, yvxr Trpxb) Puebzr/2.0.157.0 Fnsnev/528.9'; + var re10 = /\#/g; + var re11 = /\./g; + var re12 = /'/g; + var re13 = /\?[\w\W]*(sevraqvq|punaaryvq|tebhcvq)=([^\&\?#]*)/i; + var str1 = 'Fubpxjnir Synfu 9.0 e115'; + var re14 = /\s+/g; + var re15 = /^\s*(\S*(\s+\S+)*)\s*$/; + var re16 = /(-[a-z])/i; + function runBlock0() { + for (var i = 0; i < 6511; i++) { + re0.exec('pyvpx'); + } + for (var i = 0; i < 1844; i++) { + re1.exec('uggc://jjj.snprobbx.pbz/ybtva.cuc'); + } + for (var i = 0; i < 739; i++) { + 'QBZPbageby_cynprubyqre'.replace(re2, ''); + } + for (var i = 0; i < 598; i++) { + re1.exec('uggc://jjj.snprobbx.pbz/'); + } + for (var i = 0; i < 454; i++) { + re1.exec('uggc://jjj.snprobbx.pbz/fepu.cuc'); + } + for (var i = 0; i < 352; i++) { + /qqqq|qqq|qq|q|ZZZZ|ZZZ|ZZ|Z|llll|ll|l|uu|u|UU|U|zz|z|ff|f|gg|g|sss|ss|s|mmm|mm|m/g.exec('qqqq, ZZZ q, llll'); + } + for (var i = 0; i < 312; i++) { + re3.exec('vachggrkg QBZPbageby_cynprubyqre'); + } + for (var i = 0; i < 282; i++) { + re4.exec('/ZlFcnprUbzrcntr/Vaqrk-FvgrUbzr,10000000'); + } + for (var i = 0; i < 177; i++) { + 'vachggrkg'.replace(re5, ''); + } + for (var i = 0; i < 170; i++) { + '528.9'.replace(re6, ''); + re7.exec('528'); + } + for (var i = 0; i < 156; i++) { + re8.exec('VCPhygher=ra-HF'); + re8.exec('CersreerqPhygher=ra-HF'); + } + for (var i = 0; i < 144; i++) { + re0.exec('xrlcerff'); + } + for (var i = 0; i < 139; i++) { + '521'.replace(re6, ''); + re7.exec('521'); + re9.exec(''); + /JroXvg\/(\S+)/.exec(str0); + } + for (var i = 0; i < 137; i++) { + 'qvi .so_zrah'.replace(re10, ''); + 'qvi .so_zrah'.replace(/\[/g, ''); + 'qvi.so_zrah'.replace(re11, ''); + } + for (var i = 0; i < 117; i++) { + 'uvqqra_ryrz'.replace(re2, ''); + } + for (var i = 0; i < 95; i++) { + /(?:^|;)\s*sevraqfgre_ynat=([^;]*)/.exec('sevraqfgre_naba=nvq%3Qn6ss9p85n868ro9s059pn854735956o3%26ers%3Q%26df%3Q%26vpgl%3QHF'); + } + for (var i = 0; i < 93; i++) { + 'uggc://ubzr.zlfcnpr.pbz/vaqrk.psz'.replace(re12, ''); + re13.exec('uggc://ubzr.zlfcnpr.pbz/vaqrk.psz'); + } + for (var i = 0; i < 92; i++) { + str1.replace(/([a-zA-Z]|\s)+/, ''); + } + for (var i = 0; i < 85; i++) { + 'svefg'.replace(re14, ''); + 'svefg'.replace(re15, ''); + 'uggc://cebsvyr.zlfcnpr.pbz/vaqrk.psz'.replace(re12, ''); + 'ynfg'.replace(re14, ''); + 'ynfg'.replace(re15, ''); + re16.exec('qvfcynl'); + re13.exec('uggc://cebsvyr.zlfcnpr.pbz/vaqrk.psz'); + } + } + var re17 = /(^|[^\\])\"\\\/Qngr\((-?[0-9]+)\)\\\/\"/g; + var str2 = '{"anzr":"","ahzoreSbezng":{"PheeraplQrpvznyQvtvgf":2,"PheeraplQrpvznyFrcnengbe":".","VfErnqBayl":gehr,"PheeraplTebhcFvmrf":[3],"AhzoreTebhcFvmrf":[3],"CrepragTebhcFvmrf":[3],"PheeraplTebhcFrcnengbe":",","PheeraplFlzoby":"\xa4","AnAFlzoby":"AnA","PheeraplArtngvirCnggrea":0,"AhzoreArtngvirCnggrea":1,"CrepragCbfvgvirCnggrea":0,"CrepragArtngvirCnggrea":0,"ArtngvirVasvavglFlzoby":"-Vasvavgl","ArtngvirFvta":"-","AhzoreQrpvznyQvtvgf":2,"AhzoreQrpvznyFrcnengbe":".","AhzoreTebhcFrcnengbe":",","PheeraplCbfvgvirCnggrea":0,"CbfvgvirVasvavglFlzoby":"Vasvavgl","CbfvgvirFvta":"+","CrepragQrpvznyQvtvgf":2,"CrepragQrpvznyFrcnengbe":".","CrepragTebhcFrcnengbe":",","CrepragFlzoby":"%","CreZvyyrFlzoby":"\u2030","AngvirQvtvgf":["0","1","2","3","4","5","6","7","8","9"],"QvtvgFhofgvghgvba":1},"qngrGvzrSbezng":{"NZQrfvtangbe":"NZ","Pnyraqne":{"ZvaFhccbegrqQngrGvzr":"@-62135568000000@","ZnkFhccbegrqQngrGvzr":"@253402300799999@","NytbevguzGlcr":1,"PnyraqneGlcr":1,"Renf":[1],"GjbQvtvgLrneZnk":2029,"VfErnqBayl":gehr},"QngrFrcnengbe":"/","SvefgQnlBsJrrx":0,"PnyraqneJrrxEhyr":0,"ShyyQngrGvzrCnggrea":"qqqq, qq ZZZZ llll UU:zz:ff","YbatQngrCnggrea":"qqqq, qq ZZZZ llll","YbatGvzrCnggrea":"UU:zz:ff","ZbaguQnlCnggrea":"ZZZZ qq","CZQrfvtangbe":"CZ","ESP1123Cnggrea":"qqq, qq ZZZ llll UU\':\'zz\':\'ff \'TZG\'","FubegQngrCnggrea":"ZZ/qq/llll","FubegGvzrCnggrea":"UU:zz","FbegnoyrQngrGvzrCnggrea":"llll\'-\'ZZ\'-\'qq\'G\'UU\':\'zz\':\'ff","GvzrFrcnengbe":":","HavirefnyFbegnoyrQngrGvzrCnggrea":"llll\'-\'ZZ\'-\'qq UU\':\'zz\':\'ff\'M\'","LrneZbaguCnggrea":"llll ZZZZ","NooerivngrqQnlAnzrf":["Fha","Zba","Ghr","Jrq","Guh","Sev","Fng"],"FubegrfgQnlAnzrf":["Fh","Zb","Gh","Jr","Gu","Se","Fn"],"QnlAnzrf":["Fhaqnl","Zbaqnl","Ghrfqnl","Jrqarfqnl","Guhefqnl","Sevqnl","Fngheqnl"],"NooerivngrqZbaguAnzrf":["Wna","Sro","Zne","Nce","Znl","Wha","Why","Nht","Frc","Bpg","Abi","Qrp",""],"ZbaguAnzrf":["Wnahnel","Sroehnel","Znepu","Ncevy","Znl","Whar","Whyl","Nhthfg","Frcgrzore","Bpgbore","Abirzore","Qrprzore",""],"VfErnqBayl":gehr,"AngvirPnyraqneAnzr":"Tertbevna Pnyraqne","NooerivngrqZbaguTravgvirAnzrf":["Wna","Sro","Zne","Nce","Znl","Wha","Why","Nht","Frc","Bpg","Abi","Qrp",""],"ZbaguTravgvirAnzrf":["Wnahnel","Sroehnel","Znepu","Ncevy","Znl","Whar","Whyl","Nhthfg","Frcgrzore","Bpgbore","Abirzore","Qrprzore",""]}}'; + var str3 = '{"anzr":"ra-HF","ahzoreSbezng":{"PheeraplQrpvznyQvtvgf":2,"PheeraplQrpvznyFrcnengbe":".","VfErnqBayl":snyfr,"PheeraplTebhcFvmrf":[3],"AhzoreTebhcFvmrf":[3],"CrepragTebhcFvmrf":[3],"PheeraplTebhcFrcnengbe":",","PheeraplFlzoby":"$","AnAFlzoby":"AnA","PheeraplArtngvirCnggrea":0,"AhzoreArtngvirCnggrea":1,"CrepragCbfvgvirCnggrea":0,"CrepragArtngvirCnggrea":0,"ArtngvirVasvavglFlzoby":"-Vasvavgl","ArtngvirFvta":"-","AhzoreQrpvznyQvtvgf":2,"AhzoreQrpvznyFrcnengbe":".","AhzoreTebhcFrcnengbe":",","PheeraplCbfvgvirCnggrea":0,"CbfvgvirVasvavglFlzoby":"Vasvavgl","CbfvgvirFvta":"+","CrepragQrpvznyQvtvgf":2,"CrepragQrpvznyFrcnengbe":".","CrepragTebhcFrcnengbe":",","CrepragFlzoby":"%","CreZvyyrFlzoby":"\u2030","AngvirQvtvgf":["0","1","2","3","4","5","6","7","8","9"],"QvtvgFhofgvghgvba":1},"qngrGvzrSbezng":{"NZQrfvtangbe":"NZ","Pnyraqne":{"ZvaFhccbegrqQngrGvzr":"@-62135568000000@","ZnkFhccbegrqQngrGvzr":"@253402300799999@","NytbevguzGlcr":1,"PnyraqneGlcr":1,"Renf":[1],"GjbQvtvgLrneZnk":2029,"VfErnqBayl":snyfr},"QngrFrcnengbe":"/","SvefgQnlBsJrrx":0,"PnyraqneJrrxEhyr":0,"ShyyQngrGvzrCnggrea":"qqqq, ZZZZ qq, llll u:zz:ff gg","YbatQngrCnggrea":"qqqq, ZZZZ qq, llll","YbatGvzrCnggrea":"u:zz:ff gg","ZbaguQnlCnggrea":"ZZZZ qq","CZQrfvtangbe":"CZ","ESP1123Cnggrea":"qqq, qq ZZZ llll UU\':\'zz\':\'ff \'TZG\'","FubegQngrCnggrea":"Z/q/llll","FubegGvzrCnggrea":"u:zz gg","FbegnoyrQngrGvzrCnggrea":"llll\'-\'ZZ\'-\'qq\'G\'UU\':\'zz\':\'ff","GvzrFrcnengbe":":","HavirefnyFbegnoyrQngrGvzrCnggrea":"llll\'-\'ZZ\'-\'qq UU\':\'zz\':\'ff\'M\'","LrneZbaguCnggrea":"ZZZZ, llll","NooerivngrqQnlAnzrf":["Fha","Zba","Ghr","Jrq","Guh","Sev","Fng"],"FubegrfgQnlAnzrf":["Fh","Zb","Gh","Jr","Gu","Se","Fn"],"QnlAnzrf":["Fhaqnl","Zbaqnl","Ghrfqnl","Jrqarfqnl","Guhefqnl","Sevqnl","Fngheqnl"],"NooerivngrqZbaguAnzrf":["Wna","Sro","Zne","Nce","Znl","Wha","Why","Nht","Frc","Bpg","Abi","Qrp",""],"ZbaguAnzrf":["Wnahnel","Sroehnel","Znepu","Ncevy","Znl","Whar","Whyl","Nhthfg","Frcgrzore","Bpgbore","Abirzore","Qrprzore",""],"VfErnqBayl":snyfr,"AngvirPnyraqneAnzr":"Tertbevna Pnyraqne","NooerivngrqZbaguTravgvirAnzrf":["Wna","Sro","Zne","Nce","Znl","Wha","Why","Nht","Frc","Bpg","Abi","Qrp",""],"ZbaguTravgvirAnzrf":["Wnahnel","Sroehnel","Znepu","Ncevy","Znl","Whar","Whyl","Nhthfg","Frcgrzore","Bpgbore","Abirzore","Qrprzore",""]}}'; + var str4 = 'HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str5 = 'HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R='; + var re18 = /^\s+|\s+$/g; + var str6 = 'uggc://jjj.snprobbx.pbz/vaqrk.cuc'; + var re19 = /(?:^|\s+)ba(?:\s+|$)/; + var re20 = /[+, ]/; + var re21 = /ybnqrq|pbzcyrgr/; + var str7 = ';;jvaqbj.IjPurpxZbhfrCbfvgvbaNQ_VQ=shapgvba(r){vs(!r)ine r=jvaqbj.rirag;ine c=-1;vs(d1)c=d1.EbyybssCnary;ine bo=IjTrgBow("IjCnayNQ_VQ_"+c);vs(bo&&bo.fglyr.ivfvovyvgl=="ivfvoyr"){ine fns=IjFns?8:0;ine pheK=r.pyvragK+IjBOFpe("U")+fns,pheL=r.pyvragL+IjBOFpe("I")+fns;ine y=IjBOEC(NQ_VQ,bo,"Y"),g=IjBOEC(NQ_VQ,bo,"G");ine e=y+d1.Cnaryf[c].Jvqgu,o=g+d1.Cnaryf[c].Urvtug;vs((pheKe)||(pheLo)){vs(jvaqbj.IjBaEbyybssNQ_VQ)IjBaEbyybssNQ_VQ(c);ryfr IjPybfrNq(NQ_VQ,c,gehr,"");}ryfr erghea;}IjPnapryZbhfrYvfgrareNQ_VQ();};;jvaqbj.IjFrgEbyybssCnaryNQ_VQ=shapgvba(c){ine z="zbhfrzbir",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;c=IjTc(NQ_VQ,c);vs(d1&&d1.EbyybssCnary>-1)IjPnapryZbhfrYvfgrareNQ_VQ();vs(d1)d1.EbyybssCnary=c;gel{vs(q.nqqRiragYvfgrare)q.nqqRiragYvfgrare(z,s,snyfr);ryfr vs(q.nggnpuRirag)q.nggnpuRirag("ba"+z,s);}pngpu(r){}};;jvaqbj.IjPnapryZbhfrYvfgrareNQ_VQ=shapgvba(){ine z="zbhfrzbir",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;vs(d1)d1.EbyybssCnary=-1;gel{vs(q.erzbirRiragYvfgrare)q.erzbirRiragYvfgrare(z,s,snyfr);ryfr vs(q.qrgnpuRirag)q.qrgnpuRirag("ba"+z,s);}pngpu(r){}};;d1.IjTc=d2(n,c){ine nq=d1;vs(vfAnA(c)){sbe(ine v=0;v0){vs(nq.FzV.yratgu>0)nq.FzV+="/";nq.FzV+=vh[v];nq.FtZ[nq.FtZ.yratgu]=snyfr;}}};;d1.IjYvzvg0=d2(n,f){ine nq=d1,vh=f.fcyvg("/");sbe(ine v=0;v0){vs(nq.OvC.yratgu>0)nq.OvC+="/";nq.OvC+=vh[v];}}};;d1.IjRVST=d2(n,c){jvaqbj["IjCnayNQ_VQ_"+c+"_Bow"]=IjTrgBow("IjCnayNQ_VQ_"+c+"_Bow");vs(jvaqbj["IjCnayNQ_VQ_"+c+"_Bow"]==ahyy)frgGvzrbhg("IjRVST(NQ_VQ,"+c+")",d1.rvsg);};;d1.IjNavzSHC=d2(n,c){ine nq=d1;vs(c>nq.Cnaryf.yratgu)erghea;ine cna=nq.Cnaryf[c],nn=gehr,on=gehr,yn=gehr,en=gehr,cn=nq.Cnaryf[0],sf=nq.ShF,j=cn.Jvqgu,u=cn.Urvtug;vs(j=="100%"){j=sf;en=snyfr;yn=snyfr;}vs(u=="100%"){u=sf;nn=snyfr;on=snyfr;}vs(cn.YnY=="Y")yn=snyfr;vs(cn.YnY=="E")en=snyfr;vs(cn.GnY=="G")nn=snyfr;vs(cn.GnY=="O")on=snyfr;ine k=0,l=0;fjvgpu(nq.NshP%8){pnfr 0:oernx;pnfr 1:vs(nn)l=-sf;oernx;pnfr 2:k=j-sf;oernx;pnfr 3:vs(en)k=j;oernx;pnfr 4:k=j-sf;l=u-sf;oernx;pnfr 5:k=j-sf;vs(on)l=u;oernx;pnfr 6:l=u-sf;oernx;pnfr 7:vs(yn)k=-sf;l=u-sf;oernx;}vs(nq.NshP++ 0)||(nethzragf.yratgu==3&&bG>0))){pyrneGvzrbhg(cay.UgU);cay.UgU=frgGvzrbhg(cay.UvqrNpgvba,(nethzragf.yratgu==3?bG:cay.UvqrGvzrbhgInyhr));}};;d1.IjErfrgGvzrbhg=d2(n,c,bG){c=IjTc(n,c);IjPnapryGvzrbhg(n,c);riny("IjFgnegGvzrbhg(NQ_VQ,c"+(nethzragf.yratgu==3?",bG":"")+")");};;d1.IjErfrgNyyGvzrbhgf=d2(n){sbe(ine c=0;c]/g; + var str15 = 'FrffvbaQQS2=s6r4579npn4rn2135s904r0s75pp1o5334p6s6pospo12696; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669316860113296&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=; AFP_zp_dfctwzs-aowb_80=44132r503660'; + var str16 = 'FrffvbaQQS2=s6r4579npn4rn2135s904r0s75pp1o5334p6s6pospo12696; AFP_zp_dfctwzs-aowb_80=44132r503660; __hgzm=144631658.1231363638.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.965867047679498800.1231363638.1231363638.1231363638.1; __hgzo=144631658.0.10.1231363638; __hgzp=144631658; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669316860113296&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str17 = 'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231363621014&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231363621014&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Scebsvyr.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=348699119.1231363624&tn_fvq=1231363624&tn_uvq=895511034&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22'; + var str18 = 'uggc://jjj.yrobapbva.se/yv'; + var str19 = 'ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669316860113296&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str20 = 'ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669316860113296&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R='; + function runBlock3() { + for (var i = 0; i < 27; i++) { + 'e115'.replace(/[A-Za-z]/g, ''); + } + for (var i = 0; i < 23; i++) { + 'qvfcynl'.replace(re27, ''); + 'cbfvgvba'.replace(re27, ''); + } + for (var i = 0; i < 22; i++) { + 'unaqyr'.replace(re14, ''); + 'unaqyr'.replace(re15, ''); + 'yvar'.replace(re14, ''); + 'yvar'.replace(re15, ''); + 'cnerag puebzr6 fvatyr1 gno'.replace(re14, ''); + 'cnerag puebzr6 fvatyr1 gno'.replace(re15, ''); + 'fyvqre'.replace(re14, ''); + 'fyvqre'.replace(re15, ''); + re28.exec(''); + } + for (var i = 0; i < 21; i++) { + 'uggc://jjj.zlfcnpr.pbz/'.replace(re12, ''); + re13.exec('uggc://jjj.zlfcnpr.pbz/'); + } + for (var i = 0; i < 20; i++) { + 'cntrivrj'.replace(re29, ''); + 'cntrivrj'.replace(re30, ''); + re19.exec('ynfg'); + re19.exec('ba svefg'); + re8.exec('VC=74.125.75.3'); + } + for (var i = 0; i < 19; i++) { + re31.exec('ra'); + } + for (var i = 0; i < 18; i++) { + str10.split(re32); + str11.split(re32); + str12.replace(re33, ''); + re8.exec('144631658.0.10.1231363570'); + re8.exec('144631658.1231363570.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re8.exec('144631658.3426875219718084000.1231363570.1231363570.1231363570.1'); + re8.exec(str13); + re8.exec(str14); + re8.exec('__hgzn=144631658.3426875219718084000.1231363570.1231363570.1231363570.1'); + re8.exec('__hgzo=144631658.0.10.1231363570'); + re8.exec('__hgzm=144631658.1231363570.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re34.exec(str10); + re34.exec(str11); + } + for (var i = 0; i < 17; i++) { + str0.match(/zfvr/gi); + str0.match(/bcren/gi); + str15.split(re32); + str16.split(re32); + 'ohggba'.replace(re14, ''); + 'ohggba'.replace(re15, ''); + 'puvyq p1 svefg sylbhg pybfrq'.replace(re14, ''); + 'puvyq p1 svefg sylbhg pybfrq'.replace(re15, ''); + 'pvgvrf'.replace(re14, ''); + 'pvgvrf'.replace(re15, ''); + 'pybfrq'.replace(re14, ''); + 'pybfrq'.replace(re15, ''); + 'qry'.replace(re14, ''); + 'qry'.replace(re15, ''); + 'uqy_zba'.replace(re14, ''); + 'uqy_zba'.replace(re15, ''); + str17.replace(re33, ''); + str18.replace(/%3P/g, ''); + str18.replace(/%3R/g, ''); + str18.replace(/%3q/g, ''); + str18.replace(re35, ''); + 'yvaxyvfg16'.replace(re14, ''); + 'yvaxyvfg16'.replace(re15, ''); + 'zvahf'.replace(re14, ''); + 'zvahf'.replace(re15, ''); + 'bcra'.replace(re14, ''); + 'bcra'.replace(re15, ''); + 'cnerag puebzr5 fvatyr1 ps NU'.replace(re14, ''); + 'cnerag puebzr5 fvatyr1 ps NU'.replace(re15, ''); + 'cynlre'.replace(re14, ''); + 'cynlre'.replace(re15, ''); + 'cyhf'.replace(re14, ''); + 'cyhf'.replace(re15, ''); + 'cb_uqy'.replace(re14, ''); + 'cb_uqy'.replace(re15, ''); + 'hyJVzt'.replace(re14, ''); + 'hyJVzt'.replace(re15, ''); + re8.exec('144631658.0.10.1231363638'); + re8.exec('144631658.1231363638.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re8.exec('144631658.965867047679498800.1231363638.1231363638.1231363638.1'); + re8.exec('4413268q3660'); + re8.exec('4ss747o77904333q374or84qrr1s9r0nprp8r5q81534o94n'); + re8.exec('SbeprqRkcvengvba=633669321699093060'); + re8.exec('VC=74.125.75.20'); + re8.exec(str19); + re8.exec(str20); + re8.exec('AFP_zp_tfwsbrg-aowb_80=4413268q3660'); + re8.exec('FrffvbaQQS2=4ss747o77904333q374or84qrr1s9r0nprp8r5q81534o94n'); + re8.exec('__hgzn=144631658.965867047679498800.1231363638.1231363638.1231363638.1'); + re8.exec('__hgzo=144631658.0.10.1231363638'); + re8.exec('__hgzm=144631658.1231363638.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re34.exec(str15); + re34.exec(str16); + } + } + var re36 = /uers|fep|fryrpgrq/; + var re37 = /\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g; + var re38 = /^(\w+|\*)$/; + var str21 = 'FrffvbaQQS2=s15q53p9n372sn76npr13o271n4s3p5r29p235746p908p58; ZFPhygher=VC=66.249.85.130&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669358527244818&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R='; + var str22 = 'FrffvbaQQS2=s15q53p9n372sn76npr13o271n4s3p5r29p235746p908p58; __hgzm=144631658.1231367822.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.4127520630321984500.1231367822.1231367822.1231367822.1; __hgzo=144631658.0.10.1231367822; __hgzp=144631658; ZFPhygher=VC=66.249.85.130&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669358527244818&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str23 = 'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231367803797&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231367803797&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Szrffntvat.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1192552091.1231367807&tn_fvq=1231367807&tn_uvq=1155446857&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22'; + var str24 = 'ZFPhygher=VC=66.249.85.130&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669358527244818&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str25 = 'ZFPhygher=VC=66.249.85.130&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669358527244818&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R='; + var str26 = 'hy.ynat-fryrpgbe'; + var re39 = /\\/g; + var re40 = / /g; + var re41 = /\/\xc4\/t/; + var re42 = /\/\xd6\/t/; + var re43 = /\/\xdc\/t/; + var re44 = /\/\xdf\/t/; + var re45 = /\/\xe4\/t/; + var re46 = /\/\xf6\/t/; + var re47 = /\/\xfc\/t/; + var re48 = /\W/g; + var re49 = /uers|fep|fglyr/; + function runBlock4() { + for (var i = 0; i < 16; i++) { + ''.replace(/\*/g, ''); + /\bnpgvir\b/.exec('npgvir'); + /sversbk/i.exec(str0); + re36.exec('glcr'); + /zfvr/i.exec(str0); + /bcren/i.exec(str0); + } + for (var i = 0; i < 15; i++) { + str21.split(re32); + str22.split(re32); + 'uggc://ohyyrgvaf.zlfcnpr.pbz/vaqrk.psz'.replace(re12, ''); + str23.replace(re33, ''); + 'yv'.replace(re37, ''); + 'yv'.replace(re18, ''); + re8.exec('144631658.0.10.1231367822'); + re8.exec('144631658.1231367822.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re8.exec('144631658.4127520630321984500.1231367822.1231367822.1231367822.1'); + re8.exec(str24); + re8.exec(str25); + re8.exec('__hgzn=144631658.4127520630321984500.1231367822.1231367822.1231367822.1'); + re8.exec('__hgzo=144631658.0.10.1231367822'); + re8.exec('__hgzm=144631658.1231367822.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re34.exec(str21); + re34.exec(str22); + /\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)["']?(.*?)["']?)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g.exec(str26); + re13.exec('uggc://ohyyrgvaf.zlfcnpr.pbz/vaqrk.psz'); + re38.exec('yv'); + } + for (var i = 0; i < 14; i++) { + ''.replace(re18, ''); + '9.0 e115'.replace(/(\s+e|\s+o[0-9]+)/, ''); + 'Funer guvf tnqtrg'.replace(//g, ''); + 'Funer guvf tnqtrg'.replace(re39, ''); + 'uggc://cebsvyrrqvg.zlfcnpr.pbz/vaqrk.psz'.replace(re12, ''); + 'grnfre'.replace(re40, ''); + 'grnfre'.replace(re41, ''); + 'grnfre'.replace(re42, ''); + 'grnfre'.replace(re43, ''); + 'grnfre'.replace(re44, ''); + 'grnfre'.replace(re45, ''); + 'grnfre'.replace(re46, ''); + 'grnfre'.replace(re47, ''); + 'grnfre'.replace(re48, ''); + re16.exec('znetva-gbc'); + re16.exec('cbfvgvba'); + re19.exec('gno1'); + re9.exec('qz'); + re9.exec('qg'); + re9.exec('zbqobk'); + re9.exec('zbqobkva'); + re9.exec('zbqgvgyr'); + re13.exec('uggc://cebsvyrrqvg.zlfcnpr.pbz/vaqrk.psz'); + re26.exec('/vt/znvytnqtrg'); + re49.exec('glcr'); + } + } + var re50 = /(?:^|\s+)fryrpgrq(?:\s+|$)/; + var re51 = /\&/g; + var re52 = /\+/g; + var re53 = /\?/g; + var re54 = /\t/g; + var re55 = /(\$\{nqiHey\})|(\$nqiHey\b)/g; + var re56 = /(\$\{cngu\})|(\$cngu\b)/g; + function runBlock5() { + for (var i = 0; i < 13; i++) { + 'purpx'.replace(re14, ''); + 'purpx'.replace(re15, ''); + 'pvgl'.replace(re14, ''); + 'pvgl'.replace(re15, ''); + 'qrpe fyvqrgrkg'.replace(re14, ''); + 'qrpe fyvqrgrkg'.replace(re15, ''); + 'svefg fryrpgrq'.replace(re14, ''); + 'svefg fryrpgrq'.replace(re15, ''); + 'uqy_rag'.replace(re14, ''); + 'uqy_rag'.replace(re15, ''); + 'vape fyvqrgrkg'.replace(re14, ''); + 'vape fyvqrgrkg'.replace(re15, ''); + 'vachggrkg QBZPbageby_cynprubyqre'.replace(re5, ''); + 'cnerag puebzr6 fvatyr1 gno fryrpgrq'.replace(re14, ''); + 'cnerag puebzr6 fvatyr1 gno fryrpgrq'.replace(re15, ''); + 'cb_guz'.replace(re14, ''); + 'cb_guz'.replace(re15, ''); + 'fhozvg'.replace(re14, ''); + 'fhozvg'.replace(re15, ''); + re50.exec(''); + /NccyrJroXvg\/([^\s]*)/.exec(str0); + /XUGZY/.exec(str0); + } + for (var i = 0; i < 12; i++) { + '${cebg}://${ubfg}${cngu}/${dz}'.replace(/(\$\{cebg\})|(\$cebg\b)/g, ''); + '1'.replace(re40, ''); + '1'.replace(re10, ''); + '1'.replace(re51, ''); + '1'.replace(re52, ''); + '1'.replace(re53, ''); + '1'.replace(re39, ''); + '1'.replace(re54, ''); + '9.0 e115'.replace(/^(.*)\..*$/, ''); + '9.0 e115'.replace(/^.*e(.*)$/, ''); + ''.replace(re55, ''); + ''.replace(re55, ''); + str1.replace(/^.*\s+(\S+\s+\S+$)/, ''); + 'tzk%2Subzrcntr%2Sfgneg%2Sqr%2S'.replace(re30, ''); + 'tzk'.replace(re30, ''); + 'uggc://${ubfg}${cngu}/${dz}'.replace(/(\$\{ubfg\})|(\$ubfg\b)/g, ''); + 'uggc://nqpyvrag.hvzfrei.arg${cngu}/${dz}'.replace(re56, ''); + 'uggc://nqpyvrag.hvzfrei.arg/wf.at/${dz}'.replace(/(\$\{dz\})|(\$dz\b)/g, ''); + 'frpgvba'.replace(re29, ''); + 'frpgvba'.replace(re30, ''); + 'fvgr'.replace(re29, ''); + 'fvgr'.replace(re30, ''); + 'fcrpvny'.replace(re29, ''); + 'fcrpvny'.replace(re30, ''); + re36.exec('anzr'); + /e/.exec('9.0 e115'); + } + } + var re57 = /##yv4##/gi; + var re58 = /##yv16##/gi; + var re59 = /##yv19##/gi; + var str27 = '##yv4##Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.##yv19##Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.##yv16##Ybgf bs fgbentr (5 TO) - zber pbby fghss ba gur jnl.##OE## ##OE## ##N##Yrnea zber##/N##'; + var str28 = 'Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.##yv19##Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.##yv16##Ybgf bs fgbentr (5 TO) - zber pbby fghss ba gur jnl.##OE## ##OE## ##N##Yrnea zber##/N##'; + var str29 = 'Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.##yv19##Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.Ybgf bs fgbentr (5 TO) - zber pbby fghss ba gur jnl.##OE## ##OE## ##N##Yrnea zber##/N##'; + var str30 = 'Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.Ybgf bs fgbentr (5 TO) - zber pbby fghss ba gur jnl.##OE## ##OE## ##N##Yrnea zber##/N##'; + var str31 = 'Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.Ybgf bs fgbentr (5 TO) - zber pbby fghss ba gur jnl. ##N##Yrnea zber##/N##'; + var str32 = 'Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.Ybgf bs fgbentr (5 TO) - zber pbby fghss ba gur jnl. Yrnea zber##/N##'; + var str33 = 'Bar Jvaqbjf Yvir VQ trgf lbh vagb Ubgznvy, Zrffratre, Kobk YVIR \u2014 naq bgure cynprf lbh frr #~#argjbexybtb#~#'; + var re60 = /(?:^|\s+)bss(?:\s+|$)/; + var re61 = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/; + var re62 = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; + var str34 = '${1}://${2}${3}${4}${5}'; + var str35 = ' O=6gnyg0g4znrrn&o=3&f=gc; Q=_lyu=K3bQZGSxnT4lZzD3OS9GNmV3ZGLkAQxRpTyxNmRlZmRmAmNkAQLRqTImqNZjOUEgpTjQnJ5xMKtgoN--; SCF=qy'; + function runBlock6() { + for (var i = 0; i < 11; i++) { + str27.replace(/##yv0##/gi, ''); + str27.replace(re57, ''); + str28.replace(re58, ''); + str29.replace(re59, ''); + str30.replace(/##\/o##/gi, ''); + str30.replace(/##\/v##/gi, ''); + str30.replace(/##\/h##/gi, ''); + str30.replace(/##o##/gi, ''); + str30.replace(/##oe##/gi, ''); + str30.replace(/##v##/gi, ''); + str30.replace(/##h##/gi, ''); + str31.replace(/##n##/gi, ''); + str32.replace(/##\/n##/gi, ''); + str33.replace(/#~#argjbexybtb#~#/g, ''); + / Zbovyr\//.exec(str0); + /##yv1##/gi.exec(str27); + /##yv10##/gi.exec(str28); + /##yv11##/gi.exec(str28); + /##yv12##/gi.exec(str28); + /##yv13##/gi.exec(str28); + /##yv14##/gi.exec(str28); + /##yv15##/gi.exec(str28); + re58.exec(str28); + /##yv17##/gi.exec(str29); + /##yv18##/gi.exec(str29); + re59.exec(str29); + /##yv2##/gi.exec(str27); + /##yv20##/gi.exec(str30); + /##yv21##/gi.exec(str30); + /##yv22##/gi.exec(str30); + /##yv23##/gi.exec(str30); + /##yv3##/gi.exec(str27); + re57.exec(str27); + /##yv5##/gi.exec(str28); + /##yv6##/gi.exec(str28); + /##yv7##/gi.exec(str28); + /##yv8##/gi.exec(str28); + /##yv9##/gi.exec(str28); + re8.exec('473qq1rs0n2r70q9qo1pq48n021s9468ron90nps048p4p29'); + re8.exec('SbeprqRkcvengvba=633669325184628362'); + re8.exec('FrffvbaQQS2=473qq1rs0n2r70q9qo1pq48n021s9468ron90nps048p4p29'); + /AbxvnA[^\/]*/.exec(str0); + } + for (var i = 0; i < 10; i++) { + ' bss'.replace(/(?:^|\s+)bss(?:\s+|$)/g, ''); + str34.replace(/(\$\{0\})|(\$0\b)/g, ''); + str34.replace(/(\$\{1\})|(\$1\b)/g, ''); + str34.replace(/(\$\{pbzcyrgr\})|(\$pbzcyrgr\b)/g, ''); + str34.replace(/(\$\{sentzrag\})|(\$sentzrag\b)/g, ''); + str34.replace(/(\$\{ubfgcbeg\})|(\$ubfgcbeg\b)/g, ''); + str34.replace(re56, ''); + str34.replace(/(\$\{cebgbpby\})|(\$cebgbpby\b)/g, ''); + str34.replace(/(\$\{dhrel\})|(\$dhrel\b)/g, ''); + 'nqfvmr'.replace(re29, ''); + 'nqfvmr'.replace(re30, ''); + 'uggc://${2}${3}${4}${5}'.replace(/(\$\{2\})|(\$2\b)/g, ''); + 'uggc://wf.hv-cbegny.qr${3}${4}${5}'.replace(/(\$\{3\})|(\$3\b)/g, ''); + 'arjf'.replace(re40, ''); + 'arjf'.replace(re41, ''); + 'arjf'.replace(re42, ''); + 'arjf'.replace(re43, ''); + 'arjf'.replace(re44, ''); + 'arjf'.replace(re45, ''); + 'arjf'.replace(re46, ''); + 'arjf'.replace(re47, ''); + 'arjf'.replace(re48, ''); + / PC=i=(\d+)&oe=(.)/.exec(str35); + re60.exec(' '); + re60.exec(' bss'); + re60.exec(''); + re19.exec(' '); + re19.exec('svefg ba'); + re19.exec('ynfg vtaber'); + re19.exec('ba'); + re9.exec('scnq so '); + re9.exec('zrqvgobk'); + re9.exec('hsgy'); + re9.exec('lhv-h'); + /Fnsnev|Xbadhrebe|XUGZY/gi.exec(str0); + re61.exec('uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/onfr.wf'); + re62.exec('#Ybtva_rznvy'); + } + } + var re63 = /\{0\}/g; + var str36 = 'FrffvbaQQS2=4ss747o77904333q374or84qrr1s9r0nprp8r5q81534o94n; ZFPhygher=VC=74.125.75.20&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669321699093060&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=; AFP_zp_tfwsbrg-aowb_80=4413268q3660'; + var str37 = 'FrffvbaQQS2=4ss747o77904333q374or84qrr1s9r0nprp8r5q81534o94n; AFP_zp_tfwsbrg-aowb_80=4413268q3660; __hgzm=144631658.1231364074.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.2294274870215848400.1231364074.1231364074.1231364074.1; __hgzo=144631658.0.10.1231364074; __hgzp=144631658; ZFPhygher=VC=74.125.75.20&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669321699093060&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str38 = 'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231364057761&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231364057761&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Ssevraqf.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1667363813.1231364061&tn_fvq=1231364061&tn_uvq=1917563877&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22'; + var str39 = 'ZFPhygher=VC=74.125.75.20&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669321699093060&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str40 = 'ZFPhygher=VC=74.125.75.20&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669321699093060&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R='; + function runBlock7() { + for (var i = 0; i < 9; i++) { + '0'.replace(re40, ''); + '0'.replace(re10, ''); + '0'.replace(re51, ''); + '0'.replace(re52, ''); + '0'.replace(re53, ''); + '0'.replace(re39, ''); + '0'.replace(re54, ''); + 'Lrf'.replace(re40, ''); + 'Lrf'.replace(re10, ''); + 'Lrf'.replace(re51, ''); + 'Lrf'.replace(re52, ''); + 'Lrf'.replace(re53, ''); + 'Lrf'.replace(re39, ''); + 'Lrf'.replace(re54, ''); + } + for (var i = 0; i < 8; i++) { + 'Pybfr {0}'.replace(re63, ''); + 'Bcra {0}'.replace(re63, ''); + str36.split(re32); + str37.split(re32); + 'puvyq p1 svefg gnournqref'.replace(re14, ''); + 'puvyq p1 svefg gnournqref'.replace(re15, ''); + 'uqy_fcb'.replace(re14, ''); + 'uqy_fcb'.replace(re15, ''); + 'uvag'.replace(re14, ''); + 'uvag'.replace(re15, ''); + str38.replace(re33, ''); + 'yvfg'.replace(re14, ''); + 'yvfg'.replace(re15, ''); + 'at_bhgre'.replace(re30, ''); + 'cnerag puebzr5 qbhoyr2 NU'.replace(re14, ''); + 'cnerag puebzr5 qbhoyr2 NU'.replace(re15, ''); + 'cnerag puebzr5 dhnq5 ps NU osyvax zbarl'.replace(re14, ''); + 'cnerag puebzr5 dhnq5 ps NU osyvax zbarl'.replace(re15, ''); + 'cnerag puebzr6 fvatyr1'.replace(re14, ''); + 'cnerag puebzr6 fvatyr1'.replace(re15, ''); + 'cb_qrs'.replace(re14, ''); + 'cb_qrs'.replace(re15, ''); + 'gnopbagrag'.replace(re14, ''); + 'gnopbagrag'.replace(re15, ''); + 'iv_svefg_gvzr'.replace(re30, ''); + /(^|.)(ronl|qri-ehf3.wbg)(|fgberf|zbgbef|yvirnhpgvbaf|jvxv|rkcerff|punggre).(pbz(|.nh|.pa|.ux|.zl|.ft|.oe|.zk)|pb(.hx|.xe|.am)|pn|qr|se|vg|ay|or|ng|pu|vr|va|rf|cy|cu|fr)$/i.exec('cntrf.ronl.pbz'); + re8.exec('144631658.0.10.1231364074'); + re8.exec('144631658.1231364074.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re8.exec('144631658.2294274870215848400.1231364074.1231364074.1231364074.1'); + re8.exec('4413241q3660'); + re8.exec('SbeprqRkcvengvba=633669357391353591'); + re8.exec(str39); + re8.exec(str40); + re8.exec('AFP_zp_kkk-gdzogv_80=4413241q3660'); + re8.exec('FrffvbaQQS2=p98s8o9q42nr21or1r61pqorn1n002nsss569635984s6qp7'); + re8.exec('__hgzn=144631658.2294274870215848400.1231364074.1231364074.1231364074.1'); + re8.exec('__hgzo=144631658.0.10.1231364074'); + re8.exec('__hgzm=144631658.1231364074.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re8.exec('p98s8o9q42nr21or1r61pqorn1n002nsss569635984s6qp7'); + re34.exec(str36); + re34.exec(str37); + } + } + var re64 = /\b[a-z]/g; + var re65 = /^uggc:\/\//; + var re66 = /(?:^|\s+)qvfnoyrq(?:\s+|$)/; + var str41 = 'uggc://cebsvyr.zlfcnpr.pbz/Zbqhyrf/Nccyvpngvbaf/Cntrf/Pnainf.nfck'; + function runBlock8() { + for (var i = 0; i < 7; i++) { + str1.match(/\d+/g); + 'nsgre'.replace(re64, ''); + 'orsber'.replace(re64, ''); + 'obggbz'.replace(re64, ''); + 'ohvygva_jrngure.kzy'.replace(re65, ''); + 'ohggba'.replace(re37, ''); + 'ohggba'.replace(re18, ''); + 'qngrgvzr.kzy'.replace(re65, ''); + 'uggc://eff.paa.pbz/eff/paa_gbcfgbevrf.eff'.replace(re65, ''); + 'vachg'.replace(re37, ''); + 'vachg'.replace(re18, ''); + 'vafvqr'.replace(re64, ''); + 'cbvagre'.replace(re27, ''); + 'cbfvgvba'.replace(/[A-Z]/g, ''); + 'gbc'.replace(re27, ''); + 'gbc'.replace(re64, ''); + 'hy'.replace(re37, ''); + 'hy'.replace(re18, ''); + str26.replace(re37, ''); + str26.replace(re18, ''); + 'lbhghor_vtbbtyr/i2/lbhghor.kzy'.replace(re65, ''); + 'm-vaqrk'.replace(re27, ''); + /#([\w-]+)/.exec(str26); + re16.exec('urvtug'); + re16.exec('znetvaGbc'); + re16.exec('jvqgu'); + re19.exec('gno0 svefg ba'); + re19.exec('gno0 ba'); + re19.exec('gno4 ynfg'); + re19.exec('gno4'); + re19.exec('gno5'); + re19.exec('gno6'); + re19.exec('gno7'); + re19.exec('gno8'); + /NqborNVE\/([^\s]*)/.exec(str0); + /NccyrJroXvg\/([^ ]*)/.exec(str0); + /XUGZY/gi.exec(str0); + /^(?:obql|ugzy)$/i.exec('YV'); + re38.exec('ohggba'); + re38.exec('vachg'); + re38.exec('hy'); + re38.exec(str26); + /^(\w+|\*)/.exec(str26); + /znp|jva|yvahk/i.exec('Jva32'); + /eton?\([\d\s,]+\)/.exec('fgngvp'); + } + for (var i = 0; i < 6; i++) { + ''.replace(/\r/g, ''); + '/'.replace(re40, ''); + '/'.replace(re10, ''); + '/'.replace(re51, ''); + '/'.replace(re52, ''); + '/'.replace(re53, ''); + '/'.replace(re39, ''); + '/'.replace(re54, ''); + 'uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/{0}?[NDO]&{1}&{2}&[NDR]'.replace(re63, ''); + str41.replace(re12, ''); + 'uggc://jjj.snprobbx.pbz/fepu.cuc'.replace(re23, ''); + 'freivpr'.replace(re40, ''); + 'freivpr'.replace(re41, ''); + 'freivpr'.replace(re42, ''); + 'freivpr'.replace(re43, ''); + 'freivpr'.replace(re44, ''); + 'freivpr'.replace(re45, ''); + 'freivpr'.replace(re46, ''); + 'freivpr'.replace(re47, ''); + 'freivpr'.replace(re48, ''); + /((ZFVR\s+([6-9]|\d\d)\.))/.exec(str0); + re66.exec(''); + re50.exec('fryrpgrq'); + re8.exec('8sqq78r9n442851q565599o401385sp3s04r92rnn7o19ssn'); + re8.exec('SbeprqRkcvengvba=633669340386893867'); + re8.exec('VC=74.125.75.17'); + re8.exec('FrffvbaQQS2=8sqq78r9n442851q565599o401385sp3s04r92rnn7o19ssn'); + /Xbadhrebe|Fnsnev|XUGZY/.exec(str0); + re13.exec(str41); + re49.exec('unfsbphf'); + } + } + var re67 = /zrah_byq/g; + var str42 = 'FrffvbaQQS2=473qq1rs0n2r70q9qo1pq48n021s9468ron90nps048p4p29; ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669325184628362&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R='; + var str43 = 'FrffvbaQQS2=473qq1rs0n2r70q9qo1pq48n021s9468ron90nps048p4p29; __hgzm=144631658.1231364380.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.3931862196947939300.1231364380.1231364380.1231364380.1; __hgzo=144631658.0.10.1231364380; __hgzp=144631658; ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669325184628362&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str44 = 'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_vzntrf_wf&qg=1231364373088&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231364373088&punaary=svz_zlfcnpr_hfre-ivrj-pbzzragf%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Spbzzrag.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1158737789.1231364375&tn_fvq=1231364375&tn_uvq=415520832&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22'; + var str45 = 'ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669325184628362&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str46 = 'ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669325184628362&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R='; + var re68 = /^([#.]?)((?:[\w\u0128-\uffff*_-]|\\.)*)/; + var re69 = /\{1\}/g; + var re70 = /\s+/; + var re71 = /(\$\{4\})|(\$4\b)/g; + var re72 = /(\$\{5\})|(\$5\b)/g; + var re73 = /\{2\}/g; + var re74 = /[^+>] [^+>]/; + var re75 = /\bucpyv\s*=\s*([^;]*)/i; + var re76 = /\bucuvqr\s*=\s*([^;]*)/i; + var re77 = /\bucfie\s*=\s*([^;]*)/i; + var re78 = /\bhfucjrn\s*=\s*([^;]*)/i; + var re79 = /\bmvc\s*=\s*([^;]*)/i; + var re80 = /^((?:[\w\u0128-\uffff*_-]|\\.)+)(#)((?:[\w\u0128-\uffff*_-]|\\.)+)/; + var re81 = /^([>+~])\s*(\w*)/i; + var re82 = /^>\s*((?:[\w\u0128-\uffff*_-]|\\.)+)/; + var re83 = /^[\s[]?shapgvba/; + var re84 = /v\/g.tvs#(.*)/i; + var str47 = '#Zbq-Vasb-Vasb-WninFpevcgUvag'; + var str48 = ',n.svryqOgaPnapry'; + var str49 = 'FrffvbaQQS2=p98s8o9q42nr21or1r61pqorn1n002nsss569635984s6qp7; ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669357391353591&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=; AFP_zp_kkk-gdzogv_80=4413241q3660'; + var str50 = 'FrffvbaQQS2=p98s8o9q42nr21or1r61pqorn1n002nsss569635984s6qp7; AFP_zp_kkk-gdzogv_80=4413241q3660; AFP_zp_kkk-aowb_80=4413235p3660; __hgzm=144631658.1231367708.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.2770915348920628700.1231367708.1231367708.1231367708.1; __hgzo=144631658.0.10.1231367708; __hgzp=144631658; ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669357391353591&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str51 = 'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231367691141&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231367691141&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Sjjj.zlfcnpr.pbz%2S&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=320757904.1231367694&tn_fvq=1231367694&tn_uvq=1758792003&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22'; + var str52 = 'uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/f55332979829981?[NDO]&aqu=1&g=7%2S0%2S2009%2014%3N38%3N42%203%20480&af=zfacbegny&cntrAnzr=HF%20UCZFSGJ&t=uggc%3N%2S%2Sjjj.zfa.pbz%2S&f=1024k768&p=24&x=L&oj=994&ou=634&uc=A&{2}&[NDR]'; + var str53 = 'cnerag puebzr6 fvatyr1 gno fryrpgrq ovaq qbhoyr2 ps'; + var str54 = 'ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669357391353591&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str55 = 'ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669357391353591&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R='; + var str56 = 'ne;ng;nh;or;oe;pn;pu;py;pa;qr;qx;rf;sv;se;to;ux;vq;vr;va;vg;wc;xe;zk;zl;ay;ab;am;cu;cy;cg;eh;fr;ft;gu;ge;gj;mn;'; + var str57 = 'ZP1=I=3&THVQ=6nnpr9q661804s33nnop45nosqp17q85; zu=ZFSG; PHYGHER=RA-HF; SyvtugTebhcVq=97; SyvtugVq=OnfrCntr; ucfie=Z:5|S:5|G:5|R:5|Q:oyh|J:S; ucpyv=J.U|Y.|F.|E.|H.Y|P.|U.; hfucjrn=jp:HFPN0746; ZHVQ=Q783SN9O14054831N4869R51P0SO8886&GHVQ=1'; + var str58 = 'ZP1=I=3&THVQ=6nnpr9q661804s33nnop45nosqp17q85; zu=ZFSG; PHYGHER=RA-HF; SyvtugTebhcVq=97; SyvtugVq=OnfrCntr; ucfie=Z:5|S:5|G:5|R:5|Q:oyh|J:S; ucpyv=J.U|Y.|F.|E.|H.Y|P.|U.; hfucjrn=jp:HFPN0746; ZHVQ=Q783SN9O14054831N4869R51P0SO8886'; + var str59 = 'ZP1=I=3&THVQ=6nnpr9q661804s33nnop45nosqp17q85; zu=ZFSG; PHYGHER=RA-HF; SyvtugTebhcVq=97; SyvtugVq=OnfrCntr; ucfie=Z:5|S:5|G:5|R:5|Q:oyh|J:S; ucpyv=J.U|Y.|F.|E.|H.Y|P.|U.; hfucjrn=jp:HFPN0746; ZHVQ=Q783SN9O14054831N4869R51P0SO8886; mvc=m:94043|yn:37.4154|yb:-122.0585|p:HF|ue:1'; + var str60 = 'ZP1=I=3&THVQ=6nnpr9q661804s33nnop45nosqp17q85; zu=ZFSG; PHYGHER=RA-HF; SyvtugTebhcVq=97; SyvtugVq=OnfrCntr; ucfie=Z:5|S:5|G:5|R:5|Q:oyh|J:S; ucpyv=J.U|Y.|F.|E.|H.Y|P.|U.; hfucjrn=jp:HFPN0746; ZHVQ=Q783SN9O14054831N4869R51P0SO8886; mvc=m:94043|yn:37.4154|yb:-122.0585|p:HF'; + var str61 = 'uggc://gx2.fgp.f-zfa.pbz/oe/uc/11/ra-hf/pff/v/g.tvs#uggc://gx2.fgo.f-zfa.pbz/v/29/4RQP4969777N048NPS4RRR3PO2S7S.wct'; + var str62 = 'uggc://gx2.fgp.f-zfa.pbz/oe/uc/11/ra-hf/pff/v/g.tvs#uggc://gx2.fgo.f-zfa.pbz/v/OQ/63NP9O94NS5OQP1249Q9S1ROP7NS3.wct'; + var str63 = 'zbmvyyn/5.0 (jvaqbjf; h; jvaqbjf ag 5.1; ra-hf) nccyrjroxvg/528.9 (xugzy, yvxr trpxb) puebzr/2.0.157.0 fnsnev/528.9'; + function runBlock9() { + for (var i = 0; i < 5; i++) { + str42.split(re32); + str43.split(re32); + 'svz_zlfcnpr_hfre-ivrj-pbzzragf,svz_zlfcnpr_havgrq-fgngrf'.split(re20); + str44.replace(re33, ''); + 'zrah_arj zrah_arj_gbttyr zrah_gbttyr'.replace(re67, ''); + 'zrah_byq zrah_byq_gbttyr zrah_gbttyr'.replace(re67, ''); + re8.exec('102n9o0o9pq60132qn0337rr867p75953502q2s27s2s5r98'); + re8.exec('144631658.0.10.1231364380'); + re8.exec('144631658.1231364380.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re8.exec('144631658.3931862196947939300.1231364380.1231364380.1231364380.1'); + re8.exec('441326q33660'); + re8.exec('SbeprqRkcvengvba=633669341278771470'); + re8.exec(str45); + re8.exec(str46); + re8.exec('AFP_zp_dfctwzssrwh-aowb_80=441326q33660'); + re8.exec('FrffvbaQQS2=102n9o0o9pq60132qn0337rr867p75953502q2s27s2s5r98'); + re8.exec('__hgzn=144631658.3931862196947939300.1231364380.1231364380.1231364380.1'); + re8.exec('__hgzo=144631658.0.10.1231364380'); + re8.exec('__hgzm=144631658.1231364380.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + } + for (var i = 0; i < 4; i++) { + ' yvfg1'.replace(re14, ''); + ' yvfg1'.replace(re15, ''); + ' yvfg2'.replace(re14, ''); + ' yvfg2'.replace(re15, ''); + ' frneputebhc1'.replace(re14, ''); + ' frneputebhc1'.replace(re15, ''); + str47.replace(re68, ''); + str47.replace(re18, ''); + ''.replace(/&/g, ''); + ''.replace(re35, ''); + '(..-{0})(\|(\d+)|)'.replace(re63, ''); + str48.replace(re18, ''); + '//vzt.jro.qr/vij/FC/${cngu}/${anzr}/${inyhr}?gf=${abj}'.replace(re56, ''); + '//vzt.jro.qr/vij/FC/tzk_uc/${anzr}/${inyhr}?gf=${abj}'.replace(/(\$\{anzr\})|(\$anzr\b)/g, ''); + 'Jvaqbjf Yvir Ubgznvy{1}'.replace(re69, ''); + '{0}{1}'.replace(re63, ''); + '{1}'.replace(re69, ''); + '{1}'.replace(re63, ''); + 'Vzntrf'.replace(re15, ''); + 'ZFA'.replace(re15, ''); + 'Zncf'.replace(re15, ''); + 'Zbq-Vasb-Vasb-WninFpevcgUvag'.replace(re39, ''); + 'Arjf'.replace(re15, ''); + str49.split(re32); + str50.split(re32); + 'Ivqrb'.replace(re15, ''); + 'Jro'.replace(re15, ''); + 'n'.replace(re39, ''); + 'nwnkFgneg'.split(re70); + 'nwnkFgbc'.split(re70); + 'ovaq'.replace(re14, ''); + 'ovaq'.replace(re15, ''); + 'oevatf lbh zber. Zber fcnpr (5TO), zber frphevgl, fgvyy serr.'.replace(re63, ''); + 'puvyq p1 svefg qrpx'.replace(re14, ''); + 'puvyq p1 svefg qrpx'.replace(re15, ''); + 'puvyq p1 svefg qbhoyr2'.replace(re14, ''); + 'puvyq p1 svefg qbhoyr2'.replace(re15, ''); + 'puvyq p2 ynfg'.replace(re14, ''); + 'puvyq p2 ynfg'.replace(re15, ''); + 'puvyq p2'.replace(re14, ''); + 'puvyq p2'.replace(re15, ''); + 'puvyq p3'.replace(re14, ''); + 'puvyq p3'.replace(re15, ''); + 'puvyq p4 ynfg'.replace(re14, ''); + 'puvyq p4 ynfg'.replace(re15, ''); + 'pbclevtug'.replace(re14, ''); + 'pbclevtug'.replace(re15, ''); + 'qZFAZR_1'.replace(re14, ''); + 'qZFAZR_1'.replace(re15, ''); + 'qbhoyr2 ps'.replace(re14, ''); + 'qbhoyr2 ps'.replace(re15, ''); + 'qbhoyr2'.replace(re14, ''); + 'qbhoyr2'.replace(re15, ''); + 'uqy_arj'.replace(re14, ''); + 'uqy_arj'.replace(re15, ''); + 'uc_fubccvatobk'.replace(re30, ''); + 'ugzy%2Rvq'.replace(re29, ''); + 'ugzy%2Rvq'.replace(re30, ''); + str51.replace(re33, ''); + 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/cebgbglcr.wf${4}${5}'.replace(re71, ''); + 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/cebgbglcr.wf${5}'.replace(re72, ''); + str52.replace(re73, ''); + 'uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/f55332979829981?[NDO]&{1}&{2}&[NDR]'.replace(re69, ''); + 'vztZFSG'.replace(re14, ''); + 'vztZFSG'.replace(re15, ''); + 'zfasbbg1 ps'.replace(re14, ''); + 'zfasbbg1 ps'.replace(re15, ''); + str53.replace(re14, ''); + str53.replace(re15, ''); + 'cnerag puebzr6 fvatyr1 gno fryrpgrq ovaq'.replace(re14, ''); + 'cnerag puebzr6 fvatyr1 gno fryrpgrq ovaq'.replace(re15, ''); + 'cevznel'.replace(re14, ''); + 'cevznel'.replace(re15, ''); + 'erpgnatyr'.replace(re30, ''); + 'frpbaqnel'.replace(re14, ''); + 'frpbaqnel'.replace(re15, ''); + 'haybnq'.split(re70); + '{0}{1}1'.replace(re63, ''); + '|{1}1'.replace(re69, ''); + /(..-HF)(\|(\d+)|)/i.exec('xb-xe,ra-va,gu-gu'); + re4.exec('/ZlFcnprNccf/NccPnainf,45000012'); + re8.exec('144631658.0.10.1231367708'); + re8.exec('144631658.1231367708.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re8.exec('144631658.2770915348920628700.1231367708.1231367708.1231367708.1'); + re8.exec('4413235p3660'); + re8.exec('441327q73660'); + re8.exec('9995p6rp12rrnr893334ro7nq70o7p64p69rqn844prs1473'); + re8.exec('SbeprqRkcvengvba=633669350559478880'); + re8.exec(str54); + re8.exec(str55); + re8.exec('AFP_zp_dfctwzs-aowb_80=441327q73660'); + re8.exec('AFP_zp_kkk-aowb_80=4413235p3660'); + re8.exec('FrffvbaQQS2=9995p6rp12rrnr893334ro7nq70o7p64p69rqn844prs1473'); + re8.exec('__hgzn=144631658.2770915348920628700.1231367708.1231367708.1231367708.1'); + re8.exec('__hgzo=144631658.0.10.1231367708'); + re8.exec('__hgzm=144631658.1231367708.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re34.exec(str49); + re34.exec(str50); + /ZFVR\s+5[.]01/.exec(str0); + /HF(?=;)/i.exec(str56); + re74.exec(str47); + re28.exec('svefg npgvir svefgNpgvir'); + re28.exec('ynfg'); + /\bp:(..)/i.exec('m:94043|yn:37.4154|yb:-122.0585|p:HF'); + re75.exec(str57); + re75.exec(str58); + re76.exec(str57); + re76.exec(str58); + re77.exec(str57); + re77.exec(str58); + /\bhfucce\s*=\s*([^;]*)/i.exec(str59); + re78.exec(str57); + re78.exec(str58); + /\bjci\s*=\s*([^;]*)/i.exec(str59); + re79.exec(str58); + re79.exec(str60); + re79.exec(str59); + /\|p:([a-z]{2})/i.exec('m:94043|yn:37.4154|yb:-122.0585|p:HF|ue:1'); + re80.exec(str47); + re61.exec('cebgbglcr.wf'); + re68.exec(str47); + re81.exec(str47); + re82.exec(str47); + /^Fubpxjnir Synfu (\d)/.exec(str1); + /^Fubpxjnir Synfu (\d+)/.exec(str1); + re83.exec('[bowrpg tybony]'); + re62.exec(str47); + re84.exec(str61); + re84.exec(str62); + /jroxvg/.exec(str63); + } + } + var re85 = /eaq_zbqobkva/; + var str64 = '1231365729213'; + var str65 = '74.125.75.3-1057165600.29978900'; + var str66 = '74.125.75.3-1057165600.29978900.1231365730214'; + var str67 = 'Frnepu%20Zvpebfbsg.pbz'; + var str68 = 'FrffvbaQQS2=8sqq78r9n442851q565599o401385sp3s04r92rnn7o19ssn; ZFPhygher=VC=74.125.75.17&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669340386893867&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R='; + var str69 = 'FrffvbaQQS2=8sqq78r9n442851q565599o401385sp3s04r92rnn7o19ssn; __hgzm=144631658.1231365779.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.1877536177953918500.1231365779.1231365779.1231365779.1; __hgzo=144631658.0.10.1231365779; __hgzp=144631658; ZFPhygher=VC=74.125.75.17&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669340386893867&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str70 = 'I=3%26THVQ=757q3ss871q44o7o805n8113n5p72q52'; + var str71 = 'I=3&THVQ=757q3ss871q44o7o805n8113n5p72q52'; + var str72 = 'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231365765292&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231365765292&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Sohyyrgvaf.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1579793869.1231365768&tn_fvq=1231365768&tn_uvq=2056210897&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22'; + var str73 = 'frnepu.zvpebfbsg.pbz'; + var str74 = 'frnepu.zvpebfbsg.pbz/'; + var str75 = 'ZFPhygher=VC=74.125.75.17&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669340386893867&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str76 = 'ZFPhygher=VC=74.125.75.17&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669340386893867&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R='; + function runBlock10() { + for (var i = 0; i < 3; i++) { + '%3Szxg=ra-HF'.replace(re39, ''); + '-8'.replace(re40, ''); + '-8'.replace(re10, ''); + '-8'.replace(re51, ''); + '-8'.replace(re52, ''); + '-8'.replace(re53, ''); + '-8'.replace(re39, ''); + '-8'.replace(re54, ''); + '1.5'.replace(re40, ''); + '1.5'.replace(re10, ''); + '1.5'.replace(re51, ''); + '1.5'.replace(re52, ''); + '1.5'.replace(re53, ''); + '1.5'.replace(re39, ''); + '1.5'.replace(re54, ''); + '1024k768'.replace(re40, ''); + '1024k768'.replace(re10, ''); + '1024k768'.replace(re51, ''); + '1024k768'.replace(re52, ''); + '1024k768'.replace(re53, ''); + '1024k768'.replace(re39, ''); + '1024k768'.replace(re54, ''); + str64.replace(re40, ''); + str64.replace(re10, ''); + str64.replace(re51, ''); + str64.replace(re52, ''); + str64.replace(re53, ''); + str64.replace(re39, ''); + str64.replace(re54, ''); + '14'.replace(re40, ''); + '14'.replace(re10, ''); + '14'.replace(re51, ''); + '14'.replace(re52, ''); + '14'.replace(re53, ''); + '14'.replace(re39, ''); + '14'.replace(re54, ''); + '24'.replace(re40, ''); + '24'.replace(re10, ''); + '24'.replace(re51, ''); + '24'.replace(re52, ''); + '24'.replace(re53, ''); + '24'.replace(re39, ''); + '24'.replace(re54, ''); + str65.replace(re40, ''); + str65.replace(re10, ''); + str65.replace(re51, ''); + str65.replace(re52, ''); + str65.replace(re53, ''); + str65.replace(re39, ''); + str65.replace(re54, ''); + str66.replace(re40, ''); + str66.replace(re10, ''); + str66.replace(re51, ''); + str66.replace(re52, ''); + str66.replace(re53, ''); + str66.replace(re39, ''); + str66.replace(re54, ''); + '9.0'.replace(re40, ''); + '9.0'.replace(re10, ''); + '9.0'.replace(re51, ''); + '9.0'.replace(re52, ''); + '9.0'.replace(re53, ''); + '9.0'.replace(re39, ''); + '9.0'.replace(re54, ''); + '994k634'.replace(re40, ''); + '994k634'.replace(re10, ''); + '994k634'.replace(re51, ''); + '994k634'.replace(re52, ''); + '994k634'.replace(re53, ''); + '994k634'.replace(re39, ''); + '994k634'.replace(re54, ''); + '?zxg=ra-HF'.replace(re40, ''); + '?zxg=ra-HF'.replace(re10, ''); + '?zxg=ra-HF'.replace(re51, ''); + '?zxg=ra-HF'.replace(re52, ''); + '?zxg=ra-HF'.replace(re53, ''); + '?zxg=ra-HF'.replace(re54, ''); + 'PAA.pbz'.replace(re25, ''); + 'PAA.pbz'.replace(re12, ''); + 'PAA.pbz'.replace(re39, ''); + 'Qngr & Gvzr'.replace(re25, ''); + 'Qngr & Gvzr'.replace(re12, ''); + 'Qngr & Gvzr'.replace(re39, ''); + 'Frnepu Zvpebfbsg.pbz'.replace(re40, ''); + 'Frnepu Zvpebfbsg.pbz'.replace(re54, ''); + str67.replace(re10, ''); + str67.replace(re51, ''); + str67.replace(re52, ''); + str67.replace(re53, ''); + str67.replace(re39, ''); + str68.split(re32); + str69.split(re32); + str70.replace(re52, ''); + str70.replace(re53, ''); + str70.replace(re39, ''); + str71.replace(re40, ''); + str71.replace(re10, ''); + str71.replace(re51, ''); + str71.replace(re54, ''); + 'Jrngure'.replace(re25, ''); + 'Jrngure'.replace(re12, ''); + 'Jrngure'.replace(re39, ''); + 'LbhGhor'.replace(re25, ''); + 'LbhGhor'.replace(re12, ''); + 'LbhGhor'.replace(re39, ''); + str72.replace(re33, ''); + 'erzbgr_vsenzr_1'.replace(/^erzbgr_vsenzr_/, ''); + str73.replace(re40, ''); + str73.replace(re10, ''); + str73.replace(re51, ''); + str73.replace(re52, ''); + str73.replace(re53, ''); + str73.replace(re39, ''); + str73.replace(re54, ''); + str74.replace(re40, ''); + str74.replace(re10, ''); + str74.replace(re51, ''); + str74.replace(re52, ''); + str74.replace(re53, ''); + str74.replace(re39, ''); + str74.replace(re54, ''); + 'lhv-h'.replace(/\-/g, ''); + re9.exec('p'); + re9.exec('qz p'); + re9.exec('zbqynory'); + re9.exec('lhv-h svefg'); + re8.exec('144631658.0.10.1231365779'); + re8.exec('144631658.1231365779.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re8.exec('144631658.1877536177953918500.1231365779.1231365779.1231365779.1'); + re8.exec(str75); + re8.exec(str76); + re8.exec('__hgzn=144631658.1877536177953918500.1231365779.1231365779.1231365779.1'); + re8.exec('__hgzo=144631658.0.10.1231365779'); + re8.exec('__hgzm=144631658.1231365779.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re34.exec(str68); + re34.exec(str69); + /^$/.exec(''); + re31.exec('qr'); + /^znk\d+$/.exec(''); + /^zva\d+$/.exec(''); + /^erfgber$/.exec(''); + re85.exec('zbqobkva zbqobk_abcnqqvat '); + re85.exec('zbqgvgyr'); + re85.exec('eaq_zbqobkva '); + re85.exec('eaq_zbqgvgyr '); + /frpgvba\d+_pbagragf/.exec('obggbz_ani'); + } + } + var re86 = /;\s*/; + var re87 = /(\$\{inyhr\})|(\$inyhr\b)/g; + var re88 = /(\$\{abj\})|(\$abj\b)/g; + var re89 = /\s+$/; + var re90 = /^\s+/; + var re91 = /(\\\"|\x00-|\x1f|\x7f-|\x9f|\u00ad|\u0600-|\u0604|\u070f|\u17b4|\u17b5|\u200c-|\u200f|\u2028-|\u202f|\u2060-|\u206f|\ufeff|\ufff0-|\uffff)/g; + var re92 = /^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/; + var re93 = /^([:.#]*)((?:[\w\u0128-\uffff*_-]|\\.)+)/; + var re94 = /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/; + var str77 = '#fubhgobk .pybfr'; + var str78 = 'FrffvbaQQS2=102n9o0o9pq60132qn0337rr867p75953502q2s27s2s5r98; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669341278771470&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=; AFP_zp_dfctwzssrwh-aowb_80=441326q33660'; + var str79 = 'FrffvbaQQS2=102n9o0o9pq60132qn0337rr867p75953502q2s27s2s5r98; AFP_zp_dfctwzssrwh-aowb_80=441326q33660; __hgzm=144631658.1231365869.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.1670816052019209000.1231365869.1231365869.1231365869.1; __hgzo=144631658.0.10.1231365869; __hgzp=144631658; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669341278771470&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str80 = 'FrffvbaQQS2=9995p6rp12rrnr893334ro7nq70o7p64p69rqn844prs1473; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669350559478880&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=; AFP_zp_dfctwzs-aowb_80=441327q73660'; + var str81 = 'FrffvbaQQS2=9995p6rp12rrnr893334ro7nq70o7p64p69rqn844prs1473; AFP_zp_dfctwzs-aowb_80=441327q73660; __hgzm=144631658.1231367054.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.1796080716621419500.1231367054.1231367054.1231367054.1; __hgzo=144631658.0.10.1231367054; __hgzp=144631658; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669350559478880&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str82 = '[glcr=fhozvg]'; + var str83 = 'n.svryqOga,n.svryqOgaPnapry'; + var str84 = 'n.svryqOgaPnapry'; + var str85 = 'oyvpxchaxg'; + var str86 = 'qvi.bow-nppbeqvba qg'; + var str87 = 'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_nccf_wf&qg=1231367052227&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231367052227&punaary=svz_zlfcnpr_nccf-pnainf%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Scebsvyr.zlfcnpr.pbz%2SZbqhyrf%2SNccyvpngvbaf%2SCntrf%2SPnainf.nfck&nq_glcr=grkg&rvq=6083027&rn=0&sez=1&tn_ivq=716357910.1231367056&tn_fvq=1231367056&tn_uvq=1387206491&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22'; + var str88 = 'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231365851658&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231365851658&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Scebsvyrrqvg.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1979828129.1231365855&tn_fvq=1231365855&tn_uvq=2085229649&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22'; + var str89 = 'uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/f55023338617756?[NDO]&aqu=1&g=7%2S0%2S2009%2014%3N12%3N47%203%20480&af=zfacbegny&cntrAnzr=HF%20UCZFSGJ&t=uggc%3N%2S%2Sjjj.zfa.pbz%2S&f=0k0&p=43835816&x=A&oj=994&ou=634&uc=A&{2}&[NDR]'; + var str90 = 'zrgn[anzr=nwnkHey]'; + var str91 = 'anpuevpugra'; + var str92 = 'b oS={\'oT\':1.1};x $8n(B){z(B!=o9)};x $S(B){O(!$8n(B))z A;O(B.4L)z\'T\';b S=7t B;O(S==\'2P\'&&B.p4){23(B.7f){12 1:z\'T\';12 3:z/\S/.2g(B.8M)?\'ox\':\'oh\'}}O(S==\'2P\'||S==\'x\'){23(B.nE){12 2V:z\'1O\';12 7I:z\'5a\';12 18:z\'4B\'}O(7t B.I==\'4F\'){O(B.3u)z\'pG\';O(B.8e)z\'1p\'}}z S};x $2p(){b 4E={};Z(b v=0;v<1p.I;v++){Z(b X 1o 1p[v]){b nc=1p[v][X];b 6E=4E[X];O(6E&&$S(nc)==\'2P\'&&$S(6E)==\'2P\')4E[X]=$2p(6E,nc);17 4E[X]=nc}}z 4E};b $E=7p.E=x(){b 1d=1p;O(!1d[1])1d=[p,1d[0]];Z(b X 1o 1d[1])1d[0][X]=1d[1][X];z 1d[0]};b $4D=7p.pJ=x(){Z(b v=0,y=1p.I;v-1:p.3F(2R)>-1},nX:x(){z p.3y(/([.*+?^${}()|[\]\/\\])/t,\'\\$1\')}});2V.E({5V:x(1O){O(p.I<3)z A;O(p.I==4&&p[3]==0&&!1O)z\'p5\';b 3P=[];Z(b v=0;v<3;v++){b 52=(p[v]-0).4h(16);3P.1x((52.I==1)?\'0\'+52:52)}z 1O?3P:\'#\'+3P.2u(\'\')},5U:x(1O){O(p.I!=3)z A;b 1i=[];Z(b v=0;v<3;v++){1i.1x(5K((p[v].I==1)?p[v]+p[v]:p[v],16))}z 1O?1i:\'1i(\'+1i.2u(\',\')+\')\'}});7F.E({3n:x(P){b J=p;P=$2p({\'L\':J,\'V\':A,\'1p\':1S,\'2x\':A,\'4s\':A,\'6W\':A},P);O($2O(P.1p)&&$S(P.1p)!=\'1O\')P.1p=[P.1p];z x(V){b 1d;O(P.V){V=V||H.V;1d=[(P.V===1r)?V:Y P.V(V)];O(P.1p)1d.E(P.1p)}17 1d=P.1p||1p;b 3C=x(){z J.3H($5S(P'; + var str93 = 'hagreunyghat'; + var str94 = 'ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669341278771470&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str95 = 'ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669350559478880&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q'; + var str96 = 'ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669341278771470&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R='; + var str97 = 'ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669350559478880&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R='; + var str98 = 'shapgvba (){Cuk.Nccyvpngvba.Frghc.Pber();Cuk.Nccyvpngvba.Frghc.Nwnk();Cuk.Nccyvpngvba.Frghc.Synfu();Cuk.Nccyvpngvba.Frghc.Zbqhyrf()}'; + function runBlock11() { + for (var i = 0; i < 2; i++) { + ' .pybfr'.replace(re18, ''); + ' n.svryqOgaPnapry'.replace(re18, ''); + ' qg'.replace(re18, ''); + str77.replace(re68, ''); + str77.replace(re18, ''); + ''.replace(re39, ''); + ''.replace(/^/, ''); + ''.split(re86); + '*'.replace(re39, ''); + '*'.replace(re68, ''); + '*'.replace(re18, ''); + '.pybfr'.replace(re68, ''); + '.pybfr'.replace(re18, ''); + '//vzt.jro.qr/vij/FC/tzk_uc/fperra/${inyhr}?gf=${abj}'.replace(re87, ''); + '//vzt.jro.qr/vij/FC/tzk_uc/fperra/1024?gf=${abj}'.replace(re88, ''); + '//vzt.jro.qr/vij/FC/tzk_uc/jvafvmr/${inyhr}?gf=${abj}'.replace(re87, ''); + '//vzt.jro.qr/vij/FC/tzk_uc/jvafvmr/992/608?gf=${abj}'.replace(re88, ''); + '300k120'.replace(re30, ''); + '300k250'.replace(re30, ''); + '310k120'.replace(re30, ''); + '310k170'.replace(re30, ''); + '310k250'.replace(re30, ''); + '9.0 e115'.replace(/^.*\.(.*)\s.*$/, ''); + 'Nppbeqvba'.replace(re2, ''); + 'Nxghryy\x0a'.replace(re89, ''); + 'Nxghryy\x0a'.replace(re90, ''); + 'Nccyvpngvba'.replace(re2, ''); + 'Oyvpxchaxg\x0a'.replace(re89, ''); + 'Oyvpxchaxg\x0a'.replace(re90, ''); + 'Svanamra\x0a'.replace(re89, ''); + 'Svanamra\x0a'.replace(re90, ''); + 'Tnzrf\x0a'.replace(re89, ''); + 'Tnzrf\x0a'.replace(re90, ''); + 'Ubebfxbc\x0a'.replace(re89, ''); + 'Ubebfxbc\x0a'.replace(re90, ''); + 'Xvab\x0a'.replace(re89, ''); + 'Xvab\x0a'.replace(re90, ''); + 'Zbqhyrf'.replace(re2, ''); + 'Zhfvx\x0a'.replace(re89, ''); + 'Zhfvx\x0a'.replace(re90, ''); + 'Anpuevpugra\x0a'.replace(re89, ''); + 'Anpuevpugra\x0a'.replace(re90, ''); + 'Cuk'.replace(re2, ''); + 'ErdhrfgSvavfu'.split(re70); + 'ErdhrfgSvavfu.NWNK.Cuk'.split(re70); + 'Ebhgr\x0a'.replace(re89, ''); + 'Ebhgr\x0a'.replace(re90, ''); + str78.split(re32); + str79.split(re32); + str80.split(re32); + str81.split(re32); + 'Fcbeg\x0a'.replace(re89, ''); + 'Fcbeg\x0a'.replace(re90, ''); + 'GI-Fcbg\x0a'.replace(re89, ''); + 'GI-Fcbg\x0a'.replace(re90, ''); + 'Gbhe\x0a'.replace(re89, ''); + 'Gbhe\x0a'.replace(re90, ''); + 'Hagreunyghat\x0a'.replace(re89, ''); + 'Hagreunyghat\x0a'.replace(re90, ''); + 'Ivqrb\x0a'.replace(re89, ''); + 'Ivqrb\x0a'.replace(re90, ''); + 'Jrggre\x0a'.replace(re89, ''); + 'Jrggre\x0a'.replace(re90, ''); + str82.replace(re68, ''); + str82.replace(re18, ''); + str83.replace(re68, ''); + str83.replace(re18, ''); + str84.replace(re68, ''); + str84.replace(re18, ''); + 'nqiFreivprObk'.replace(re30, ''); + 'nqiFubccvatObk'.replace(re30, ''); + 'nwnk'.replace(re39, ''); + 'nxghryy'.replace(re40, ''); + 'nxghryy'.replace(re41, ''); + 'nxghryy'.replace(re42, ''); + 'nxghryy'.replace(re43, ''); + 'nxghryy'.replace(re44, ''); + 'nxghryy'.replace(re45, ''); + 'nxghryy'.replace(re46, ''); + 'nxghryy'.replace(re47, ''); + 'nxghryy'.replace(re48, ''); + str85.replace(re40, ''); + str85.replace(re41, ''); + str85.replace(re42, ''); + str85.replace(re43, ''); + str85.replace(re44, ''); + str85.replace(re45, ''); + str85.replace(re46, ''); + str85.replace(re47, ''); + str85.replace(re48, ''); + 'pngrtbel'.replace(re29, ''); + 'pngrtbel'.replace(re30, ''); + 'pybfr'.replace(re39, ''); + 'qvi'.replace(re39, ''); + str86.replace(re68, ''); + str86.replace(re18, ''); + 'qg'.replace(re39, ''); + 'qg'.replace(re68, ''); + 'qg'.replace(re18, ''); + 'rzorq'.replace(re39, ''); + 'rzorq'.replace(re68, ''); + 'rzorq'.replace(re18, ''); + 'svryqOga'.replace(re39, ''); + 'svryqOgaPnapry'.replace(re39, ''); + 'svz_zlfcnpr_nccf-pnainf,svz_zlfcnpr_havgrq-fgngrf'.split(re20); + 'svanamra'.replace(re40, ''); + 'svanamra'.replace(re41, ''); + 'svanamra'.replace(re42, ''); + 'svanamra'.replace(re43, ''); + 'svanamra'.replace(re44, ''); + 'svanamra'.replace(re45, ''); + 'svanamra'.replace(re46, ''); + 'svanamra'.replace(re47, ''); + 'svanamra'.replace(re48, ''); + 'sbphf'.split(re70); + 'sbphf.gno sbphfva.gno'.split(re70); + 'sbphfva'.split(re70); + 'sbez'.replace(re39, ''); + 'sbez.nwnk'.replace(re68, ''); + 'sbez.nwnk'.replace(re18, ''); + 'tnzrf'.replace(re40, ''); + 'tnzrf'.replace(re41, ''); + 'tnzrf'.replace(re42, ''); + 'tnzrf'.replace(re43, ''); + 'tnzrf'.replace(re44, ''); + 'tnzrf'.replace(re45, ''); + 'tnzrf'.replace(re46, ''); + 'tnzrf'.replace(re47, ''); + 'tnzrf'.replace(re48, ''); + 'ubzrcntr'.replace(re30, ''); + 'ubebfxbc'.replace(re40, ''); + 'ubebfxbc'.replace(re41, ''); + 'ubebfxbc'.replace(re42, ''); + 'ubebfxbc'.replace(re43, ''); + 'ubebfxbc'.replace(re44, ''); + 'ubebfxbc'.replace(re45, ''); + 'ubebfxbc'.replace(re46, ''); + 'ubebfxbc'.replace(re47, ''); + 'ubebfxbc'.replace(re48, ''); + 'uc_cebzbobk_ugzy%2Puc_cebzbobk_vzt'.replace(re30, ''); + 'uc_erpgnatyr'.replace(re30, ''); + str87.replace(re33, ''); + str88.replace(re33, ''); + 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/onfr.wf${4}${5}'.replace(re71, ''); + 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/onfr.wf${5}'.replace(re72, ''); + 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/qlaYvo.wf${4}${5}'.replace(re71, ''); + 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/qlaYvo.wf${5}'.replace(re72, ''); + 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/rssrpgYvo.wf${4}${5}'.replace(re71, ''); + 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/rssrpgYvo.wf${5}'.replace(re72, ''); + str89.replace(re73, ''); + 'uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/f55023338617756?[NDO]&{1}&{2}&[NDR]'.replace(re69, ''); + str6.replace(re23, ''); + 'xvab'.replace(re40, ''); + 'xvab'.replace(re41, ''); + 'xvab'.replace(re42, ''); + 'xvab'.replace(re43, ''); + 'xvab'.replace(re44, ''); + 'xvab'.replace(re45, ''); + 'xvab'.replace(re46, ''); + 'xvab'.replace(re47, ''); + 'xvab'.replace(re48, ''); + 'ybnq'.split(re70); + 'zrqvnzbqgno lhv-anifrg lhv-anifrg-gbc'.replace(re18, ''); + 'zrgn'.replace(re39, ''); + str90.replace(re68, ''); + str90.replace(re18, ''); + 'zbhfrzbir'.split(re70); + 'zbhfrzbir.gno'.split(re70); + str63.replace(/^.*jroxvg\/(\d+(\.\d+)?).*$/, ''); + 'zhfvx'.replace(re40, ''); + 'zhfvx'.replace(re41, ''); + 'zhfvx'.replace(re42, ''); + 'zhfvx'.replace(re43, ''); + 'zhfvx'.replace(re44, ''); + 'zhfvx'.replace(re45, ''); + 'zhfvx'.replace(re46, ''); + 'zhfvx'.replace(re47, ''); + 'zhfvx'.replace(re48, ''); + 'zlfcnpr_nccf_pnainf'.replace(re52, ''); + str91.replace(re40, ''); + str91.replace(re41, ''); + str91.replace(re42, ''); + str91.replace(re43, ''); + str91.replace(re44, ''); + str91.replace(re45, ''); + str91.replace(re46, ''); + str91.replace(re47, ''); + str91.replace(re48, ''); + 'anzr'.replace(re39, ''); + str92.replace(/\b\w+\b/g, ''); + 'bow-nppbeqvba'.replace(re39, ''); + 'bowrpg'.replace(re39, ''); + 'bowrpg'.replace(re68, ''); + 'bowrpg'.replace(re18, ''); + 'cnenzf%2Rfglyrf'.replace(re29, ''); + 'cnenzf%2Rfglyrf'.replace(re30, ''); + 'cbchc'.replace(re30, ''); + 'ebhgr'.replace(re40, ''); + 'ebhgr'.replace(re41, ''); + 'ebhgr'.replace(re42, ''); + 'ebhgr'.replace(re43, ''); + 'ebhgr'.replace(re44, ''); + 'ebhgr'.replace(re45, ''); + 'ebhgr'.replace(re46, ''); + 'ebhgr'.replace(re47, ''); + 'ebhgr'.replace(re48, ''); + 'freivprobk_uc'.replace(re30, ''); + 'fubccvatobk_uc'.replace(re30, ''); + 'fubhgobk'.replace(re39, ''); + 'fcbeg'.replace(re40, ''); + 'fcbeg'.replace(re41, ''); + 'fcbeg'.replace(re42, ''); + 'fcbeg'.replace(re43, ''); + 'fcbeg'.replace(re44, ''); + 'fcbeg'.replace(re45, ''); + 'fcbeg'.replace(re46, ''); + 'fcbeg'.replace(re47, ''); + 'fcbeg'.replace(re48, ''); + 'gbhe'.replace(re40, ''); + 'gbhe'.replace(re41, ''); + 'gbhe'.replace(re42, ''); + 'gbhe'.replace(re43, ''); + 'gbhe'.replace(re44, ''); + 'gbhe'.replace(re45, ''); + 'gbhe'.replace(re46, ''); + 'gbhe'.replace(re47, ''); + 'gbhe'.replace(re48, ''); + 'gi-fcbg'.replace(re40, ''); + 'gi-fcbg'.replace(re41, ''); + 'gi-fcbg'.replace(re42, ''); + 'gi-fcbg'.replace(re43, ''); + 'gi-fcbg'.replace(re44, ''); + 'gi-fcbg'.replace(re45, ''); + 'gi-fcbg'.replace(re46, ''); + 'gi-fcbg'.replace(re47, ''); + 'gi-fcbg'.replace(re48, ''); + 'glcr'.replace(re39, ''); + 'haqrsvarq'.replace(/\//g, ''); + str93.replace(re40, ''); + str93.replace(re41, ''); + str93.replace(re42, ''); + str93.replace(re43, ''); + str93.replace(re44, ''); + str93.replace(re45, ''); + str93.replace(re46, ''); + str93.replace(re47, ''); + str93.replace(re48, ''); + 'ivqrb'.replace(re40, ''); + 'ivqrb'.replace(re41, ''); + 'ivqrb'.replace(re42, ''); + 'ivqrb'.replace(re43, ''); + 'ivqrb'.replace(re44, ''); + 'ivqrb'.replace(re45, ''); + 'ivqrb'.replace(re46, ''); + 'ivqrb'.replace(re47, ''); + 'ivqrb'.replace(re48, ''); + 'ivfvgf=1'.split(re86); + 'jrggre'.replace(re40, ''); + 'jrggre'.replace(re41, ''); + 'jrggre'.replace(re42, ''); + 'jrggre'.replace(re43, ''); + 'jrggre'.replace(re44, ''); + 'jrggre'.replace(re45, ''); + 'jrggre'.replace(re46, ''); + 'jrggre'.replace(re47, ''); + 'jrggre'.replace(re48, ''); + /#[a-z0-9]+$/i.exec('uggc://jjj.fpuhryreim.arg/Qrsnhyg'); + re66.exec('fryrpgrq'); + /(?:^|\s+)lhv-ani(?:\s+|$)/.exec('sff lhv-ani'); + /(?:^|\s+)lhv-anifrg(?:\s+|$)/.exec('zrqvnzbqgno lhv-anifrg'); + /(?:^|\s+)lhv-anifrg-gbc(?:\s+|$)/.exec('zrqvnzbqgno lhv-anifrg'); + re91.exec('GnoThvq'); + re91.exec('thvq'); + /(pbzcngvoyr|jroxvg)/.exec(str63); + /.+(?:ei|vg|en|vr)[\/: ]([\d.]+)/.exec(str63); + re8.exec('144631658.0.10.1231365869'); + re8.exec('144631658.0.10.1231367054'); + re8.exec('144631658.1231365869.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re8.exec('144631658.1231367054.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re8.exec('144631658.1670816052019209000.1231365869.1231365869.1231365869.1'); + re8.exec('144631658.1796080716621419500.1231367054.1231367054.1231367054.1'); + re8.exec(str94); + re8.exec(str95); + re8.exec(str96); + re8.exec(str97); + re8.exec('__hgzn=144631658.1670816052019209000.1231365869.1231365869.1231365869.1'); + re8.exec('__hgzn=144631658.1796080716621419500.1231367054.1231367054.1231367054.1'); + re8.exec('__hgzo=144631658.0.10.1231365869'); + re8.exec('__hgzo=144631658.0.10.1231367054'); + re8.exec('__hgzm=144631658.1231365869.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re8.exec('__hgzm=144631658.1231367054.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)'); + re34.exec(str78); + re34.exec(str79); + re34.exec(str81); + re74.exec(str77); + re74.exec('*'); + re74.exec(str82); + re74.exec(str83); + re74.exec(str86); + re74.exec('rzorq'); + re74.exec('sbez.nwnk'); + re74.exec(str90); + re74.exec('bowrpg'); + /\/onfr.wf(\?.+)?$/.exec('/uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/onfr.wf'); + re28.exec('uvag ynfgUvag ynfg'); + re75.exec(''); + re76.exec(''); + re77.exec(''); + re78.exec(''); + re80.exec(str77); + re80.exec('*'); + re80.exec('.pybfr'); + re80.exec(str82); + re80.exec(str83); + re80.exec(str84); + re80.exec(str86); + re80.exec('qg'); + re80.exec('rzorq'); + re80.exec('sbez.nwnk'); + re80.exec(str90); + re80.exec('bowrpg'); + re61.exec('qlaYvo.wf'); + re61.exec('rssrpgYvo.wf'); + re61.exec('uggc://jjj.tzk.arg/qr/?fgnghf=uvajrvf'); + re92.exec(' .pybfr'); + re92.exec(' n.svryqOgaPnapry'); + re92.exec(' qg'); + re92.exec(str48); + re92.exec('.nwnk'); + re92.exec('.svryqOga,n.svryqOgaPnapry'); + re92.exec('.svryqOgaPnapry'); + re92.exec('.bow-nppbeqvba qg'); + re68.exec(str77); + re68.exec('*'); + re68.exec('.pybfr'); + re68.exec(str82); + re68.exec(str83); + re68.exec(str84); + re68.exec(str86); + re68.exec('qg'); + re68.exec('rzorq'); + re68.exec('sbez.nwnk'); + re68.exec(str90); + re68.exec('bowrpg'); + re93.exec(' .pybfr'); + re93.exec(' n.svryqOgaPnapry'); + re93.exec(' qg'); + re93.exec(str48); + re93.exec('.nwnk'); + re93.exec('.svryqOga,n.svryqOgaPnapry'); + re93.exec('.svryqOgaPnapry'); + re93.exec('.bow-nppbeqvba qg'); + re81.exec(str77); + re81.exec('*'); + re81.exec(str48); + re81.exec('.pybfr'); + re81.exec(str82); + re81.exec(str83); + re81.exec(str84); + re81.exec(str86); + re81.exec('qg'); + re81.exec('rzorq'); + re81.exec('sbez.nwnk'); + re81.exec(str90); + re81.exec('bowrpg'); + re94.exec(' .pybfr'); + re94.exec(' n.svryqOgaPnapry'); + re94.exec(' qg'); + re94.exec(str48); + re94.exec('.nwnk'); + re94.exec('.svryqOga,n.svryqOgaPnapry'); + re94.exec('.svryqOgaPnapry'); + re94.exec('.bow-nppbeqvba qg'); + re94.exec('[anzr=nwnkHey]'); + re94.exec(str82); + re31.exec('rf'); + re31.exec('wn'); + re82.exec(str77); + re82.exec('*'); + re82.exec(str48); + re82.exec('.pybfr'); + re82.exec(str82); + re82.exec(str83); + re82.exec(str84); + re82.exec(str86); + re82.exec('qg'); + re82.exec('rzorq'); + re82.exec('sbez.nwnk'); + re82.exec(str90); + re82.exec('bowrpg'); + re83.exec(str98); + re83.exec('shapgvba sbphf() { [angvir pbqr] }'); + re62.exec('#Ybtva'); + re62.exec('#Ybtva_cnffjbeq'); + re62.exec(str77); + re62.exec('#fubhgobkWf'); + re62.exec('#fubhgobkWfReebe'); + re62.exec('#fubhgobkWfFhpprff'); + re62.exec('*'); + re62.exec(str82); + re62.exec(str83); + re62.exec(str86); + re62.exec('rzorq'); + re62.exec('sbez.nwnk'); + re62.exec(str90); + re62.exec('bowrpg'); + re49.exec('pbagrag'); + re24.exec(str6); + /xbadhrebe/.exec(str63); + /znp/.exec('jva32'); + /zbmvyyn/.exec(str63); + /zfvr/.exec(str63); + /ag\s5\.1/.exec(str63); + /bcren/.exec(str63); + /fnsnev/.exec(str63); + /jva/.exec('jva32'); + /jvaqbjf/.exec(str63); + } + } + for (var i = 0; i < 5; i++) { + runBlock0(); + runBlock1(); + runBlock2(); + runBlock3(); + runBlock4(); + runBlock5(); + runBlock6(); + runBlock7(); + runBlock8(); + runBlock9(); + runBlock10(); + runBlock11(); + } +} + +runRegExpBenchmark(); diff --git a/js/src/jit-test/tests/v8-v5/check-richards.js b/js/src/jit-test/tests/v8-v5/check-richards.js new file mode 100644 index 0000000..f91d878 --- /dev/null +++ b/js/src/jit-test/tests/v8-v5/check-richards.js @@ -0,0 +1,536 @@ +// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// This is a JavaScript implementation of the Richards +// benchmark from: +// +// http://www.cl.cam.ac.uk/~mr10/Bench.html +// +// The benchmark was originally implemented in BCPL by +// Martin Richards. + + +//var Richards = new BenchmarkSuite('Richards', 34886, [ +// new Benchmark("Richards", runRichards) +//]); + + +/** + * The Richards benchmark simulates the task dispatcher of an + * operating system. + **/ +function runRichards() { + var scheduler = new Scheduler(); + scheduler.addIdleTask(ID_IDLE, 0, null, COUNT); + + var queue = new Packet(null, ID_WORKER, KIND_WORK); + queue = new Packet(queue, ID_WORKER, KIND_WORK); + scheduler.addWorkerTask(ID_WORKER, 1000, queue); + + queue = new Packet(null, ID_DEVICE_A, KIND_DEVICE); + queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE); + queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE); + scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue); + + queue = new Packet(null, ID_DEVICE_B, KIND_DEVICE); + queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE); + queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE); + scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue); + + scheduler.addDeviceTask(ID_DEVICE_A, 4000, null); + + scheduler.addDeviceTask(ID_DEVICE_B, 5000, null); + + scheduler.schedule(); + + assertEq(scheduler.queueCount, EXPECTED_QUEUE_COUNT); + assertEq(scheduler.holdCount, EXPECTED_HOLD_COUNT); +} + +var COUNT = 1000; + +/** + * These two constants specify how many times a packet is queued and + * how many times a task is put on hold in a correct run of richards. + * They don't have any meaning a such but are characteristic of a + * correct run so if the actual queue or hold count is different from + * the expected there must be a bug in the implementation. + **/ +var EXPECTED_QUEUE_COUNT = 2322; +var EXPECTED_HOLD_COUNT = 928; + + +/** + * A scheduler can be used to schedule a set of tasks based on their relative + * priorities. Scheduling is done by maintaining a list of task control blocks + * which holds tasks and the data queue they are processing. + * @constructor + */ +function Scheduler() { + this.queueCount = 0; + this.holdCount = 0; + this.blocks = new Array(NUMBER_OF_IDS); + this.list = null; + this.currentTcb = null; + this.currentId = null; +} + +var ID_IDLE = 0; +var ID_WORKER = 1; +var ID_HANDLER_A = 2; +var ID_HANDLER_B = 3; +var ID_DEVICE_A = 4; +var ID_DEVICE_B = 5; +var NUMBER_OF_IDS = 6; + +var KIND_DEVICE = 0; +var KIND_WORK = 1; + +/** + * Add an idle task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + * @param {int} count the number of times to schedule the task + */ +Scheduler.prototype.addIdleTask = function (id, priority, queue, count) { + this.addRunningTask(id, priority, queue, new IdleTask(this, 1, count)); +}; + +/** + * Add a work task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + */ +Scheduler.prototype.addWorkerTask = function (id, priority, queue) { + this.addTask(id, priority, queue, new WorkerTask(this, ID_HANDLER_A, 0)); +}; + +/** + * Add a handler task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + */ +Scheduler.prototype.addHandlerTask = function (id, priority, queue) { + this.addTask(id, priority, queue, new HandlerTask(this)); +}; + +/** + * Add a handler task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + */ +Scheduler.prototype.addDeviceTask = function (id, priority, queue) { + this.addTask(id, priority, queue, new DeviceTask(this)) +}; + +/** + * Add the specified task and mark it as running. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + * @param {Task} task the task to add + */ +Scheduler.prototype.addRunningTask = function (id, priority, queue, task) { + this.addTask(id, priority, queue, task); + this.currentTcb.setRunning(); +}; + +/** + * Add the specified task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + * @param {Task} task the task to add + */ +Scheduler.prototype.addTask = function (id, priority, queue, task) { + this.currentTcb = new TaskControlBlock(this.list, id, priority, queue, task); + this.list = this.currentTcb; + this.blocks[id] = this.currentTcb; +}; + +/** + * Execute the tasks managed by this scheduler. + */ +Scheduler.prototype.schedule = function () { + this.currentTcb = this.list; + while (this.currentTcb != null) { + if (this.currentTcb.isHeldOrSuspended()) { + this.currentTcb = this.currentTcb.link; + } else { + this.currentId = this.currentTcb.id; + this.currentTcb = this.currentTcb.run(); + } + } +}; + +/** + * Release a task that is currently blocked and return the next block to run. + * @param {int} id the id of the task to suspend + */ +Scheduler.prototype.release = function (id) { + var tcb = this.blocks[id]; + if (tcb == null) return tcb; + tcb.markAsNotHeld(); + if (tcb.priority > this.currentTcb.priority) { + return tcb; + } else { + return this.currentTcb; + } +}; + +/** + * Block the currently executing task and return the next task control block + * to run. The blocked task will not be made runnable until it is explicitly + * released, even if new work is added to it. + */ +Scheduler.prototype.holdCurrent = function () { + this.holdCount++; + this.currentTcb.markAsHeld(); + return this.currentTcb.link; +}; + +/** + * Suspend the currently executing task and return the next task control block + * to run. If new work is added to the suspended task it will be made runnable. + */ +Scheduler.prototype.suspendCurrent = function () { + this.currentTcb.markAsSuspended(); + return this.currentTcb; +}; + +/** + * Add the specified packet to the end of the worklist used by the task + * associated with the packet and make the task runnable if it is currently + * suspended. + * @param {Packet} packet the packet to add + */ +Scheduler.prototype.queue = function (packet) { + var t = this.blocks[packet.id]; + if (t == null) return t; + this.queueCount++; + packet.link = null; + packet.id = this.currentId; + return t.checkPriorityAdd(this.currentTcb, packet); +}; + +/** + * A task control block manages a task and the queue of work packages associated + * with it. + * @param {TaskControlBlock} link the preceding block in the linked block list + * @param {int} id the id of this block + * @param {int} priority the priority of this block + * @param {Packet} queue the queue of packages to be processed by the task + * @param {Task} task the task + * @constructor + */ +function TaskControlBlock(link, id, priority, queue, task) { + this.link = link; + this.id = id; + this.priority = priority; + this.queue = queue; + this.task = task; + if (queue == null) { + this.state = STATE_SUSPENDED; + } else { + this.state = STATE_SUSPENDED_RUNNABLE; + } +} + +/** + * The task is running and is currently scheduled. + */ +var STATE_RUNNING = 0; + +/** + * The task has packets left to process. + */ +var STATE_RUNNABLE = 1; + +/** + * The task is not currently running. The task is not blocked as such and may +* be started by the scheduler. + */ +var STATE_SUSPENDED = 2; + +/** + * The task is blocked and cannot be run until it is explicitly released. + */ +var STATE_HELD = 4; + +var STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE; +var STATE_NOT_HELD = ~STATE_HELD; + +TaskControlBlock.prototype.setRunning = function () { + this.state = STATE_RUNNING; +}; + +TaskControlBlock.prototype.markAsNotHeld = function () { + this.state = this.state & STATE_NOT_HELD; +}; + +TaskControlBlock.prototype.markAsHeld = function () { + this.state = this.state | STATE_HELD; +}; + +TaskControlBlock.prototype.isHeldOrSuspended = function () { + return (this.state & STATE_HELD) != 0 || (this.state == STATE_SUSPENDED); +}; + +TaskControlBlock.prototype.markAsSuspended = function () { + this.state = this.state | STATE_SUSPENDED; +}; + +TaskControlBlock.prototype.markAsRunnable = function () { + this.state = this.state | STATE_RUNNABLE; +}; + +/** + * Runs this task, if it is ready to be run, and returns the next task to run. + */ +TaskControlBlock.prototype.run = function () { + var packet; + if (this.state == STATE_SUSPENDED_RUNNABLE) { + packet = this.queue; + this.queue = packet.link; + if (this.queue == null) { + this.state = STATE_RUNNING; + } else { + this.state = STATE_RUNNABLE; + } + } else { + packet = null; + } + return this.task.run(packet); +}; + +/** + * Adds a packet to the worklist of this block's task, marks this as runnable if + * necessary, and returns the next runnable object to run (the one + * with the highest priority). + */ +TaskControlBlock.prototype.checkPriorityAdd = function (task, packet) { + if (this.queue == null) { + this.queue = packet; + this.markAsRunnable(); + if (this.priority > task.priority) return this; + } else { + this.queue = packet.addTo(this.queue); + } + return task; +}; + +TaskControlBlock.prototype.toString = function () { + return "tcb { " + this.task + "@" + this.state + " }"; +}; + +/** + * An idle task doesn't do any work itself but cycles control between the two + * device tasks. + * @param {Scheduler} scheduler the scheduler that manages this task + * @param {int} v1 a seed value that controls how the device tasks are scheduled + * @param {int} count the number of times this task should be scheduled + * @constructor + */ +function IdleTask(scheduler, v1, count) { + this.scheduler = scheduler; + this.v1 = v1; + this.count = count; +} + +IdleTask.prototype.run = function (packet) { + this.count--; + if (this.count == 0) return this.scheduler.holdCurrent(); + if ((this.v1 & 1) == 0) { + this.v1 = this.v1 >> 1; + return this.scheduler.release(ID_DEVICE_A); + } else { + this.v1 = (this.v1 >> 1) ^ 0xD008; + return this.scheduler.release(ID_DEVICE_B); + } +}; + +IdleTask.prototype.toString = function () { + return "IdleTask" +}; + +/** + * A task that suspends itself after each time it has been run to simulate + * waiting for data from an external device. + * @param {Scheduler} scheduler the scheduler that manages this task + * @constructor + */ +function DeviceTask(scheduler) { + this.scheduler = scheduler; + this.v1 = null; +} + +DeviceTask.prototype.run = function (packet) { + if (packet == null) { + if (this.v1 == null) return this.scheduler.suspendCurrent(); + var v = this.v1; + this.v1 = null; + return this.scheduler.queue(v); + } else { + this.v1 = packet; + return this.scheduler.holdCurrent(); + } +}; + +DeviceTask.prototype.toString = function () { + return "DeviceTask"; +}; + +/** + * A task that manipulates work packets. + * @param {Scheduler} scheduler the scheduler that manages this task + * @param {int} v1 a seed used to specify how work packets are manipulated + * @param {int} v2 another seed used to specify how work packets are manipulated + * @constructor + */ +function WorkerTask(scheduler, v1, v2) { + this.scheduler = scheduler; + this.v1 = v1; + this.v2 = v2; +} + +WorkerTask.prototype.run = function (packet) { + if (packet == null) { + return this.scheduler.suspendCurrent(); + } else { + if (this.v1 == ID_HANDLER_A) { + this.v1 = ID_HANDLER_B; + } else { + this.v1 = ID_HANDLER_A; + } + packet.id = this.v1; + packet.a1 = 0; + for (var i = 0; i < DATA_SIZE; i++) { + this.v2++; + if (this.v2 > 26) this.v2 = 1; + packet.a2[i] = this.v2; + } + return this.scheduler.queue(packet); + } +}; + +WorkerTask.prototype.toString = function () { + return "WorkerTask"; +}; + +/** + * A task that manipulates work packets and then suspends itself. + * @param {Scheduler} scheduler the scheduler that manages this task + * @constructor + */ +function HandlerTask(scheduler) { + this.scheduler = scheduler; + this.v1 = null; + this.v2 = null; +} + +HandlerTask.prototype.run = function (packet) { + if (packet != null) { + if (packet.kind == KIND_WORK) { + this.v1 = packet.addTo(this.v1); + } else { + this.v2 = packet.addTo(this.v2); + } + } + if (this.v1 != null) { + var count = this.v1.a1; + var v; + if (count < DATA_SIZE) { + if (this.v2 != null) { + v = this.v2; + this.v2 = this.v2.link; + v.a1 = this.v1.a2[count]; + this.v1.a1 = count + 1; + return this.scheduler.queue(v); + } + } else { + v = this.v1; + this.v1 = this.v1.link; + return this.scheduler.queue(v); + } + } + return this.scheduler.suspendCurrent(); +}; + +HandlerTask.prototype.toString = function () { + return "HandlerTask"; +}; + +/* --- * + * P a c k e t + * --- */ + +var DATA_SIZE = 4; + +/** + * A simple package of data that is manipulated by the tasks. The exact layout + * of the payload data carried by a packet is not importaint, and neither is the + * nature of the work performed on packets by the tasks. + * + * Besides carrying data, packets form linked lists and are hence used both as + * data and worklists. + * @param {Packet} link the tail of the linked list of packets + * @param {int} id an ID for this packet + * @param {int} kind the type of this packet + * @constructor + */ +function Packet(link, id, kind) { + this.link = link; + this.id = id; + this.kind = kind; + this.a1 = 0; + this.a2 = new Array(DATA_SIZE); +} + +/** + * Add this packet to the end of a worklist, and return the worklist. + * @param {Packet} queue the worklist to add this packet to + */ +Packet.prototype.addTo = function (queue) { + this.link = null; + if (queue == null) return this; + var peek, next = queue; + while ((peek = next.link) != null) + next = peek; + next.link = this; + return queue; +}; + +Packet.prototype.toString = function () { + return "Packet"; +}; + +runRichards(); diff --git a/js/src/jit-test/tests/v8-v5/check-splay.js b/js/src/jit-test/tests/v8-v5/check-splay.js new file mode 100644 index 0000000..cd83e41 --- /dev/null +++ b/js/src/jit-test/tests/v8-v5/check-splay.js @@ -0,0 +1,393 @@ +// Copyright 2009 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This benchmark is based on a JavaScript log processing module used +// by the V8 profiler to generate execution time profiles for runs of +// JavaScript applications, and it effectively measures how fast the +// JavaScript engine is at allocating nodes and reclaiming the memory +// used for old nodes. Because of the way splay trees work, the engine +// also has to deal with a lot of changes to the large tree object +// graph. + +//var Splay = new BenchmarkSuite('Splay', 126125, [ +// new Benchmark("Splay", SplayRun, SplaySetup, SplayTearDown) +//]); + +// This is the best random number generator available to mankind ;) +var MyMath = { + seed: 49734321, + random: function() { + // Robert Jenkins' 32 bit integer hash function. + this.seed = ((this.seed + 0x7ed55d16) + (this.seed << 12)) & 0xffffffff; + this.seed = ((this.seed ^ 0xc761c23c) ^ (this.seed >>> 19)) & 0xffffffff; + this.seed = ((this.seed + 0x165667b1) + (this.seed << 5)) & 0xffffffff; + this.seed = ((this.seed + 0xd3a2646c) ^ (this.seed << 9)) & 0xffffffff; + this.seed = ((this.seed + 0xfd7046c5) + (this.seed << 3)) & 0xffffffff; + this.seed = ((this.seed ^ 0xb55a4f09) ^ (this.seed >>> 16)) & 0xffffffff; + return (this.seed & 0xfffffff) / 0x10000000; + }, +}; + +// Configuration. +var kSplayTreeSize = 8000; +var kSplayTreeModifications = 80; +var kSplayTreePayloadDepth = 5; + +var splayTree = null; + + +function GeneratePayloadTree(depth, key) { + if (depth == 0) { + return { + array : [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], + string : 'String for key ' + key + ' in leaf node' + }; + } else { + return { + left: GeneratePayloadTree(depth - 1, key), + right: GeneratePayloadTree(depth - 1, key) + }; + } +} + + +function GenerateKey() { + // The benchmark framework guarantees that Math.random is + // deterministic; see base.js. + // base.js isn't pulled in for jit-tests + return MyMath.random(); +} + + +function InsertNewNode() { + // Insert new node with a unique key. + var key; + do { + key = GenerateKey(); + } while (splayTree.find(key) != null); + splayTree.insert(key, GeneratePayloadTree(kSplayTreePayloadDepth, key)); + return key; +} + + + +function SplaySetup() { + splayTree = new SplayTree(); + for (var i = 0; i < kSplayTreeSize; i++) InsertNewNode(); +} + + +function SplayTearDown() { + // Allow the garbage collector to reclaim the memory + // used by the splay tree no matter how we exit the + // tear down function. + var keys = splayTree.exportKeys(); + splayTree = null; + + // Verify that the splay tree has the right size. + var length = keys.length; + assertEq(length, kSplayTreeSize); + + // Verify that the splay tree has sorted, unique keys. + for (var i = 0; i < length - 1; i++) { + assertEq(keys[i] < keys[i + 1], true); + } +} + + +function SplayRun() { + // Replace a few nodes in the splay tree. + for (var i = 0; i < kSplayTreeModifications; i++) { + var key = InsertNewNode(); + var greatest = splayTree.findGreatestLessThan(key); + if (greatest == null) splayTree.remove(key); + else splayTree.remove(greatest.key); + } +} + + +/** + * Constructs a Splay tree. A splay tree is a self-balancing binary + * search tree with the additional property that recently accessed + * elements are quick to access again. It performs basic operations + * such as insertion, look-up and removal in O(log(n)) amortized time. + * + * @constructor + */ +function SplayTree() { +}; + + +/** + * Pointer to the root node of the tree. + * + * @type {SplayTree.Node} + * @private + */ +SplayTree.prototype.root_ = null; + + +/** + * @return {boolean} Whether the tree is empty. + */ +SplayTree.prototype.isEmpty = function() { + return !this.root_; +}; + + +/** + * Inserts a node into the tree with the specified key and value if + * the tree does not already contain a node with the specified key. If + * the value is inserted, it becomes the root of the tree. + * + * @param {number} key Key to insert into the tree. + * @param {*} value Value to insert into the tree. + */ +SplayTree.prototype.insert = function(key, value) { + if (this.isEmpty()) { + this.root_ = new SplayTree.Node(key, value); + return; + } + // Splay on the key to move the last node on the search path for + // the key to the root of the tree. + this.splay_(key); + if (this.root_.key == key) { + return; + } + var node = new SplayTree.Node(key, value); + if (key > this.root_.key) { + node.left = this.root_; + node.right = this.root_.right; + this.root_.right = null; + } else { + node.right = this.root_; + node.left = this.root_.left; + this.root_.left = null; + } + this.root_ = node; +}; + + +/** + * Removes a node with the specified key from the tree if the tree + * contains a node with this key. The removed node is returned. If the + * key is not found, an exception is thrown. + * + * @param {number} key Key to find and remove from the tree. + * @return {SplayTree.Node} The removed node. + */ +SplayTree.prototype.remove = function(key) { + if (this.isEmpty()) { + throw Error('Key not found: ' + key); + } + this.splay_(key); + if (this.root_.key != key) { + throw Error('Key not found: ' + key); + } + var removed = this.root_; + if (!this.root_.left) { + this.root_ = this.root_.right; + } else { + var right = this.root_.right; + this.root_ = this.root_.left; + // Splay to make sure that the new root has an empty right child. + this.splay_(key); + // Insert the original right child as the right child of the new + // root. + this.root_.right = right; + } + return removed; +}; + + +/** + * Returns the node having the specified key or null if the tree doesn't contain + * a node with the specified key. + * + * @param {number} key Key to find in the tree. + * @return {SplayTree.Node} Node having the specified key. + */ +SplayTree.prototype.find = function(key) { + if (this.isEmpty()) { + return null; + } + this.splay_(key); + return this.root_.key == key ? this.root_ : null; +}; + + +/** + * @return {SplayTree.Node} Node having the maximum key value that + * is less or equal to the specified key value. + */ +SplayTree.prototype.findGreatestLessThan = function(key) { + if (this.isEmpty()) { + return null; + } + // Splay on the key to move the node with the given key or the last + // node on the search path to the top of the tree. + this.splay_(key); + // Now the result is either the root node or the greatest node in + // the left subtree. + if (this.root_.key <= key) { + return this.root_; + } else if (this.root_.left) { + return this.findMax(this.root_.left); + } else { + return null; + } +}; + + +/** + * @return {Array<*>} An array containing all the keys of tree's nodes. + */ +SplayTree.prototype.exportKeys = function() { + var result = []; + if (!this.isEmpty()) { + this.root_.traverse_(function(node) { result.push(node.key); }); + } + return result; +}; + + +/** + * Perform the splay operation for the given key. Moves the node with + * the given key to the top of the tree. If no node has the given + * key, the last node on the search path is moved to the top of the + * tree. This is the simplified top-down splaying algorithm from: + * "Self-adjusting Binary Search Trees" by Sleator and Tarjan + * + * @param {number} key Key to splay the tree on. + * @private + */ +SplayTree.prototype.splay_ = function(key) { + if (this.isEmpty()) { + return; + } + // Create a dummy node. The use of the dummy node is a bit + // counter-intuitive: The right child of the dummy node will hold + // the L tree of the algorithm. The left child of the dummy node + // will hold the R tree of the algorithm. Using a dummy node, left + // and right will always be nodes and we avoid special cases. + var dummy, left, right; + dummy = left = right = new SplayTree.Node(null, null); + var current = this.root_; + while (true) { + if (key < current.key) { + if (!current.left) { + break; + } + if (key < current.left.key) { + // Rotate right. + var tmp = current.left; + current.left = tmp.right; + tmp.right = current; + current = tmp; + if (!current.left) { + break; + } + } + // Link right. + right.left = current; + right = current; + current = current.left; + } else if (key > current.key) { + if (!current.right) { + break; + } + if (key > current.right.key) { + // Rotate left. + var tmp = current.right; + current.right = tmp.left; + tmp.left = current; + current = tmp; + if (!current.right) { + break; + } + } + // Link left. + left.right = current; + left = current; + current = current.right; + } else { + break; + } + } + // Assemble. + left.right = current.left; + right.left = current.right; + current.left = dummy.right; + current.right = dummy.left; + this.root_ = current; +}; + + +/** + * Constructs a Splay tree node. + * + * @param {number} key Key. + * @param {*} value Value. + */ +SplayTree.Node = function(key, value) { + this.key = key; + this.value = value; +}; + + +/** + * @type {SplayTree.Node} + */ +SplayTree.Node.prototype.left = null; + + +/** + * @type {SplayTree.Node} + */ +SplayTree.Node.prototype.right = null; + + +/** + * Performs an ordered traversal of the subtree starting at + * this SplayTree.Node. + * + * @param {function(SplayTree.Node)} f Visitor function. + * @private + */ +SplayTree.Node.prototype.traverse_ = function(f) { + var current = this; + while (current) { + var left = current.left; + if (left) left.traverse_(f); + f(current); + current = current.right; + } +}; + +SplaySetup(); +SplayRun(); +SplayTearDown(); diff --git a/js/src/jitstats.tbl b/js/src/jitstats.tbl new file mode 100644 index 0000000..74a6b7f --- /dev/null +++ b/js/src/jitstats.tbl @@ -0,0 +1,97 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=0 ft=C: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * June 22, 2008. + * + * The Initial Developer of the Original Code is + * Brian Crowder + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* NB: Keep this list synced with jitstatHandler in jit-test.js. */ +/** + * Proper use of this file: Consumers must define JITSTAT; they can optionally + * also define MONITOR_JITSTAT or RECORDER_JITSTAT or both to do separate + * things with stats that are monitor or recorder specific. If those are not + * defined, they will be automatically defined to JITSTAT. + */ +#ifdef DEFINED_MONITOR_JITSTAT +#error "How did that happen?" +#endif + +#ifdef DEFINED_RECORDER_JITSTAT +#error "How did that happen?" +#endif + +#ifndef MONITOR_JITSTAT +#define MONITOR_JITSTAT(_ident, _name) JITSTAT(_ident) +#define DEFINED_MONITOR_JITSTAT +#endif + +#ifndef RECORDER_JITSTAT +#define RECORDER_JITSTAT(_ident, _name) JITSTAT(_ident) +#define DEFINED_RECORDER_JITSTAT +#endif + +RECORDER_JITSTAT(recorderStarted, "started") +RECORDER_JITSTAT(recorderAborted, "aborted") +RECORDER_JITSTAT(traceCompleted, "completed") +MONITOR_JITSTAT(sideExitIntoInterpreter, "exits") +MONITOR_JITSTAT(timeoutIntoInterpreter, "timeouts") +MONITOR_JITSTAT(typeMapMismatchAtEntry, "type mismatch") +RECORDER_JITSTAT(returnToDifferentLoopHeader, "different header") +MONITOR_JITSTAT(traceTriggered, "triggered") +MONITOR_JITSTAT(globalShapeMismatchAtEntry, "global mismatch") +RECORDER_JITSTAT(treesTrashed, "trees trashed") +RECORDER_JITSTAT(slotPromoted, "slot promoted") +RECORDER_JITSTAT(unstableLoopVariable, "unstable loop variable") +RECORDER_JITSTAT(breakLoopExits, "breaks") +RECORDER_JITSTAT(returnLoopExits, "returns") +RECORDER_JITSTAT(mergedLoopExits, "merged loop exits") +RECORDER_JITSTAT(noCompatInnerTrees, "unstableInnerCalls") +RECORDER_JITSTAT(blacklisted, "blacklisted") +MONITOR_JITSTAT(cacheFlushed, "flushed") +JITSTAT(archIsIA32) +JITSTAT(archIsAMD64) +JITSTAT(archIs64BIT) +JITSTAT(archIsARM) +JITSTAT(archIsSPARC) +JITSTAT(archIsPPC) + +#ifdef DEFINED_MONITOR_JITSTAT +#undef DEFINED_MONITOR_JITSTAT +#undef MONITOR_JITSTAT +#endif + +#ifdef DEFINED_RECORDER_JITSTAT +#undef DEFINED_RECORDER_JITSTAT +#undef RECORDER_JITSTAT +#endif diff --git a/js/src/js-config.h.in b/js/src/js-config.h.in new file mode 100644 index 0000000..e3a5f74 --- /dev/null +++ b/js/src/js-config.h.in @@ -0,0 +1,91 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef js_config_h___ +#define js_config_h___ + +/* Definitions set at build time that affect SpiderMonkey's public API. + This header file is generated by the SpiderMonkey configure script, + and installed along with jsapi.h. */ + +/* Define to 1 if SpiderMonkey should support multi-threaded clients. */ +#undef JS_THREADSAFE + +/* Define to 1 if SpiderMonkey should include ctypes support. */ +#undef JS_HAS_CTYPES + +/* Define to 1 if SpiderMonkey should support the ability to perform + entirely too much GC. */ +#undef JS_GC_ZEAL + +/* Define to 1 if the standard header is present and + useable. See jstypes.h and jsstdint.h. */ +#undef JS_HAVE_STDINT_H + +/* Define to 1 if the defines int8_t, etc. */ +#undef JS_SYS_TYPES_H_DEFINES_EXACT_SIZE_TYPES + +/* Define to 1 if the N-byte __intN types are defined by the + compiler. */ +#undef JS_HAVE___INTN + +/* Define to 1 if #including provides definitions for + intptr_t and uintptr_t. */ +#undef JS_STDDEF_H_HAS_INTPTR_T + +/* Define to 1 if #including provides definitions for + intptr_t and uintptr_t. */ +#undef JS_CRTDEFS_H_HAS_INTPTR_T + +/* The configure script defines these if it doesn't #define + JS_HAVE_STDINT_H. */ +#undef JS_INT8_TYPE +#undef JS_INT16_TYPE +#undef JS_INT32_TYPE +#undef JS_INT64_TYPE +#undef JS_INTPTR_TYPE +#undef JS_BYTES_PER_WORD + +/* Some mozilla code uses JS-friend APIs that depend on JS_TRACER and + JS_METHODJIT being correct. */ +#undef JS_TRACER +#undef JS_METHODJIT + +#endif /* js_config_h___ */ diff --git a/js/src/js-config.in b/js/src/js-config.in new file mode 100644 index 0000000..59b4719 --- /dev/null +++ b/js/src/js-config.in @@ -0,0 +1,111 @@ +#!/bin/sh + +prefix='@prefix@' +mozilla_version='@MOZILLA_VERSION@' +LIBRARY_NAME='@LIBRARY_NAME@' +NSPR_CFLAGS='@NSPR_CFLAGS@' +JS_CONFIG_LIBS='@JS_CONFIG_LIBS@' +MOZ_JS_LIBS='@MOZ_JS_LIBS@' + +usage() +{ + cat <&2 +fi + +while test $# -gt 0; do + case "$1" in + -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + case $1 in + --prefix=*) + prefix=$optarg + ;; + --prefix) + echo_prefix=yes + ;; + --exec-prefix=*) + exec_prefix=$optarg + ;; + --exec-prefix) + echo_exec_prefix=yes + ;; + --includedir=*) + includedir=$optarg + ;; + --includedir) + echo_includedir=yes + ;; + --libdir=*) + libdir=$optarg + ;; + --libdir) + echo_libdir=yes + ;; + --version) + echo "$mozilla_version" + ;; + --cflags) + echo_cflags=yes + ;; + --libs) + echo_libs=yes + ;; + *) + usage 1 1>&2 + ;; + esac + shift +done + +# Set variables that may be dependent upon other variables +if test -z "$exec_prefix"; then + exec_prefix=@exec_prefix@ +fi +if test -z "$includedir"; then + includedir=@includedir@ +fi +if test -z "$libdir"; then + libdir=@libdir@ +fi + +if test "$echo_prefix" = "yes"; then + echo $prefix +fi + +if test "$echo_exec_prefix" = "yes"; then + echo $exec_prefix +fi + +if test "$echo_includedir" = "yes"; then + echo $includedir +fi + +if test "$echo_libdir" = "yes"; then + echo $libdir +fi + +if test "$echo_cflags" = "yes"; then + echo "-I$includedir/js $NSPR_CFLAGS" +fi + +if test "$echo_libs" = "yes"; then + echo "$MOZ_JS_LIBS $JS_CONFIG_LIBS" +fi diff --git a/js/src/js.mdp b/js/src/js.mdp new file mode 100644 index 0000000000000000000000000000000000000000..8da64fb6b61a5a047ac54c88020cf397fa7eaa25 GIT binary patch literal 17922 zcmeI3-A)rh6vxj}3RDD&d|#MMV&sNEPuNv)f8dOnd+p zzn{e$6YhNi?|2EX)acnQgDY|a;b!UCWV@63|IgWTeltmvNxQmvcQFOMum#Wqbafqp z-*j~~frGB@o|<2Sd3X%hU>ZUe!_g;E=^g^HFT9`K(=~N!2=qcf47Th_&0ktvsJALV z_P(WOMQm5lkO&X~B0vO)01+SpM1Tko0U|&IhyW2tJb^Ek)njD=KEonp`@bi?A8O!q z1k%ulCqM&`flDw5mtp91;p9#-48~ysCSmFfIVdEl1TuK`n>sB1>yua)(V<}Uhmc4P zcSRbk+nKzQfmYspKJfu8zqq~EY)EJ*Ka7_jq5K_pU7#=+iY1irQ=5_ zgd-eN#w&D8u6T+EtRSS)b*yH+AvBjqme*(*KeV_l*AcAJW?MollVk6%p(w>Jw*z)x z_)YH!+#57ZbuttWi;dn9FZC^YhC811meAXtdTR2&Lus@lZ3f(~vHXs(Yes#K>PSa@ zAf10BKcF^Ql!2%UjeJfj{v%ql#&Z14pThVJje)pM!Z~T3exYT!Q`Yh5WefIa3Z)W; z;i}*oJ&Se>Tj7}Q2(Rte52nhlt(C8~1D2ng`+uFoJ=%+R-yV9tJ==Y!JgEEm>X5bG% C_`cBq literal 0 HcmV?d00001 diff --git a/js/src/js.msg b/js/src/js.msg new file mode 100644 index 0000000..6f3c67a --- /dev/null +++ b/js/src/js.msg @@ -0,0 +1,351 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This is the JavaScript error message file. + * + * The format for each JS error message is: + * + * MSG_DEF(, , , , + * ) + * + * where ; + * is a legal C identifer that will be used in the + * JS engine source. + * + * is an unique integral value identifying this error. + * + * is an integer literal specifying the total number of + * replaceable arguments in the following format string. + * + * is an exception index from the enum in jsexn.c; + * JSEXN_NONE for none. The given exception index will be raised by the + * engine when the corresponding error occurs. + * + * is a string literal, optionally containing sequences + * {X} where X is an integer representing the argument number that will + * be replaced with a string value when the error is reported. + * + * e.g. + * + * MSG_DEF(JSMSG_NOT_A_SUBSPECIES, 73, JSEXN_NONE, 2, + * "{0} is not a member of the {1} family") + * + * can be used: + * + * JS_ReportErrorNumber(JSMSG_NOT_A_SUBSPECIES, "Rhino", "Monkey"); + * + * to report: + * + * "Rhino is not a member of the Monkey family" + * + * Before adding a new MSG_DEF at the end, look for JSMSG_UNUSED free + * index placeholders in the middle of the list. + */ + +MSG_DEF(JSMSG_NOT_AN_ERROR, 0, 0, JSEXN_NONE, "") +MSG_DEF(JSMSG_NOT_DEFINED, 1, 1, JSEXN_REFERENCEERR, "{0} is not defined") +MSG_DEF(JSMSG_INACTIVE, 2, 0, JSEXN_INTERNALERR, "nothing active on context") +MSG_DEF(JSMSG_MORE_ARGS_NEEDED, 3, 3, JSEXN_TYPEERR, "{0} requires more than {1} argument{2}") +MSG_DEF(JSMSG_BAD_CHAR, 4, 1, JSEXN_INTERNALERR, "invalid format character {0}") +MSG_DEF(JSMSG_BAD_TYPE, 5, 1, JSEXN_TYPEERR, "unknown type {0}") +MSG_DEF(JSMSG_ALLOC_OVERFLOW, 6, 0, JSEXN_INTERNALERR, "allocation size overflow") +MSG_DEF(JSMSG_MISSING_HEXDIGITS, 7, 0, JSEXN_SYNTAXERR, "missing hexadecimal digits after '0x'") +MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 8, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}") +MSG_DEF(JSMSG_NO_CONSTRUCTOR, 9, 1, JSEXN_TYPEERR, "{0} has no constructor") +MSG_DEF(JSMSG_CANT_ALIAS, 10, 3, JSEXN_TYPEERR, "can't alias {0} to {1} in class {2}") +MSG_DEF(JSMSG_NOT_SCRIPTED_FUNCTION, 11, 1, JSEXN_TYPEERR, "{0} is not a scripted function") +MSG_DEF(JSMSG_BAD_SORT_ARG, 12, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument") +MSG_DEF(JSMSG_BAD_ATOMIC_NUMBER, 13, 1, JSEXN_INTERNALERR, "internal error: no index for atom {0}") +MSG_DEF(JSMSG_TOO_MANY_LITERALS, 14, 0, JSEXN_INTERNALERR, "too many literals") +MSG_DEF(JSMSG_CANT_WATCH, 15, 1, JSEXN_TYPEERR, "can't watch non-native objects of class {0}") +MSG_DEF(JSMSG_STACK_UNDERFLOW, 16, 2, JSEXN_INTERNALERR, "internal error compiling {0}: stack underflow at pc {1}") +MSG_DEF(JSMSG_NEED_DIET, 17, 1, JSEXN_INTERNALERR, "{0} too large") +MSG_DEF(JSMSG_TOO_MANY_LOCAL_ROOTS, 18, 0, JSEXN_ERR, "out of local root space") +MSG_DEF(JSMSG_READ_ONLY, 19, 1, JSEXN_TYPEERR, "{0} is read-only") +MSG_DEF(JSMSG_BAD_FORMAL, 20, 0, JSEXN_SYNTAXERR, "malformed formal parameter") +MSG_DEF(JSMSG_CANT_DELETE, 21, 1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted") +MSG_DEF(JSMSG_NOT_FUNCTION, 22, 1, JSEXN_TYPEERR, "{0} is not a function") +MSG_DEF(JSMSG_NOT_CONSTRUCTOR, 23, 1, JSEXN_TYPEERR, "{0} is not a constructor") +MSG_DEF(JSMSG_SCRIPT_STACK_QUOTA, 24, 0, JSEXN_INTERNALERR, "script stack space quota is exhausted") +MSG_DEF(JSMSG_TOO_DEEP, 25, 1, JSEXN_INTERNALERR, "{0} nested too deeply") +MSG_DEF(JSMSG_OVER_RECURSED, 26, 0, JSEXN_INTERNALERR, "too much recursion") +MSG_DEF(JSMSG_IN_NOT_OBJECT, 27, 1, JSEXN_TYPEERR, "invalid 'in' operand {0}") +MSG_DEF(JSMSG_BAD_NEW_RESULT, 28, 1, JSEXN_TYPEERR, "invalid new expression result {0}") +MSG_DEF(JSMSG_BAD_SHARP_DEF, 29, 1, JSEXN_ERR, "invalid sharp variable definition #{0}=") +MSG_DEF(JSMSG_BAD_SHARP_USE, 30, 1, JSEXN_ERR, "invalid sharp variable use #{0}#") +MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS, 31, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}") +MSG_DEF(JSMSG_BAD_BYTECODE, 32, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}") +MSG_DEF(JSMSG_BAD_RADIX, 33, 1, JSEXN_ERR, "illegal radix {0}") +MSG_DEF(JSMSG_PAREN_BEFORE_LET, 34, 0, JSEXN_SYNTAXERR, "missing ( before let head") +MSG_DEF(JSMSG_CANT_CONVERT, 35, 1, JSEXN_ERR, "can't convert {0} to an integer") +MSG_DEF(JSMSG_CYCLIC_VALUE, 36, 1, JSEXN_TYPEERR, "cyclic {0} value") +MSG_DEF(JSMSG_COMPILE_EXECED_SCRIPT, 37, 0, JSEXN_TYPEERR, "can't compile over a script that is currently executing") +MSG_DEF(JSMSG_CANT_CONVERT_TO, 38, 2, JSEXN_TYPEERR, "can't convert {0} to {1}") +MSG_DEF(JSMSG_NO_PROPERTIES, 39, 1, JSEXN_TYPEERR, "{0} has no properties") +MSG_DEF(JSMSG_CANT_FIND_CLASS, 40, 1, JSEXN_TYPEERR, "can't find class id {0}") +MSG_DEF(JSMSG_CANT_XDR_CLASS, 41, 1, JSEXN_TYPEERR, "can't XDR class {0}") +MSG_DEF(JSMSG_BYTECODE_TOO_BIG, 42, 2, JSEXN_INTERNALERR, "bytecode {0} too large (limit {1})") +MSG_DEF(JSMSG_UNKNOWN_FORMAT, 43, 1, JSEXN_INTERNALERR, "unknown bytecode format {0}") +MSG_DEF(JSMSG_TOO_MANY_CON_ARGS, 44, 0, JSEXN_SYNTAXERR, "too many constructor arguments") +MSG_DEF(JSMSG_TOO_MANY_FUN_ARGS, 45, 0, JSEXN_SYNTAXERR, "too many function arguments") +MSG_DEF(JSMSG_BAD_QUANTIFIER, 46, 0, JSEXN_SYNTAXERR, "invalid quantifier") +MSG_DEF(JSMSG_MIN_TOO_BIG, 47, 1, JSEXN_SYNTAXERR, "overlarge minimum {0}") +MSG_DEF(JSMSG_MAX_TOO_BIG, 48, 1, JSEXN_SYNTAXERR, "overlarge maximum {0}") +MSG_DEF(JSMSG_OUT_OF_ORDER, 49, 1, JSEXN_SYNTAXERR, "maximum {0} less than minimum") +MSG_DEF(JSMSG_BAD_DESTRUCT_DECL, 50, 0, JSEXN_SYNTAXERR, "missing = in destructuring declaration") +MSG_DEF(JSMSG_BAD_DESTRUCT_ASS, 51, 0, JSEXN_REFERENCEERR, "invalid destructuring assignment operator") +MSG_DEF(JSMSG_PAREN_AFTER_LET, 52, 0, JSEXN_SYNTAXERR, "missing ) after let head") +MSG_DEF(JSMSG_CURLY_AFTER_LET, 53, 0, JSEXN_SYNTAXERR, "missing } after let block") +MSG_DEF(JSMSG_MISSING_PAREN, 54, 0, JSEXN_SYNTAXERR, "unterminated parenthetical") +MSG_DEF(JSMSG_UNTERM_CLASS, 55, 1, JSEXN_SYNTAXERR, "unterminated character class {0}") +MSG_DEF(JSMSG_TRAILING_SLASH, 56, 0, JSEXN_SYNTAXERR, "trailing \\ in regular expression") +MSG_DEF(JSMSG_BAD_CLASS_RANGE, 57, 0, JSEXN_SYNTAXERR, "invalid range in character class") +MSG_DEF(JSMSG_BAD_REGEXP_FLAG, 58, 1, JSEXN_SYNTAXERR, "invalid regular expression flag {0}") +MSG_DEF(JSMSG_NO_INPUT, 59, 5, JSEXN_SYNTAXERR, "no input for /{0}/{1}{2}{3}{4}") +MSG_DEF(JSMSG_CANT_OPEN, 60, 2, JSEXN_ERR, "can't open {0}: {1}") +MSG_DEF(JSMSG_BAD_STRING_MASK, 61, 1, JSEXN_ERR, "invalid string escape mask {0}") +MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 62, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression") +MSG_DEF(JSMSG_END_OF_DATA, 63, 0, JSEXN_INTERNALERR, "unexpected end of data") +MSG_DEF(JSMSG_SEEK_BEYOND_START, 64, 0, JSEXN_INTERNALERR, "illegal seek beyond start") +MSG_DEF(JSMSG_SEEK_BEYOND_END, 65, 0, JSEXN_INTERNALERR, "illegal seek beyond end") +MSG_DEF(JSMSG_END_SEEK, 66, 0, JSEXN_INTERNALERR, "illegal end-based seek") +MSG_DEF(JSMSG_WHITHER_WHENCE, 67, 1, JSEXN_INTERNALERR, "unknown seek whence: {0}") +MSG_DEF(JSMSG_BAD_SCRIPT_MAGIC, 68, 0, JSEXN_INTERNALERR, "bad script XDR magic number") +MSG_DEF(JSMSG_PAREN_BEFORE_FORMAL, 69, 0, JSEXN_SYNTAXERR, "missing ( before formal parameters") +MSG_DEF(JSMSG_MISSING_FORMAL, 70, 0, JSEXN_SYNTAXERR, "missing formal parameter") +MSG_DEF(JSMSG_PAREN_AFTER_FORMAL, 71, 0, JSEXN_SYNTAXERR, "missing ) after formal parameters") +MSG_DEF(JSMSG_CURLY_BEFORE_BODY, 72, 0, JSEXN_SYNTAXERR, "missing { before function body") +MSG_DEF(JSMSG_CURLY_AFTER_BODY, 73, 0, JSEXN_SYNTAXERR, "missing } after function body") +MSG_DEF(JSMSG_PAREN_BEFORE_COND, 74, 0, JSEXN_SYNTAXERR, "missing ( before condition") +MSG_DEF(JSMSG_PAREN_AFTER_COND, 75, 0, JSEXN_SYNTAXERR, "missing ) after condition") +MSG_DEF(JSMSG_DESTRUCT_DUP_ARG, 76, 0, JSEXN_SYNTAXERR, "duplicate argument is mixed with destructuring pattern") +MSG_DEF(JSMSG_NAME_AFTER_DOT, 77, 0, JSEXN_SYNTAXERR, "missing name after . operator") +MSG_DEF(JSMSG_BRACKET_IN_INDEX, 78, 0, JSEXN_SYNTAXERR, "missing ] in index expression") +MSG_DEF(JSMSG_XML_WHOLE_PROGRAM, 79, 0, JSEXN_SYNTAXERR, "XML can't be the whole program") +MSG_DEF(JSMSG_PAREN_BEFORE_SWITCH, 80, 0, JSEXN_SYNTAXERR, "missing ( before switch expression") +MSG_DEF(JSMSG_PAREN_AFTER_SWITCH, 81, 0, JSEXN_SYNTAXERR, "missing ) after switch expression") +MSG_DEF(JSMSG_CURLY_BEFORE_SWITCH, 82, 0, JSEXN_SYNTAXERR, "missing { before switch body") +MSG_DEF(JSMSG_COLON_AFTER_CASE, 83, 0, JSEXN_SYNTAXERR, "missing : after case label") +MSG_DEF(JSMSG_WHILE_AFTER_DO, 84, 0, JSEXN_SYNTAXERR, "missing while after do-loop body") +MSG_DEF(JSMSG_PAREN_AFTER_FOR, 85, 0, JSEXN_SYNTAXERR, "missing ( after for") +MSG_DEF(JSMSG_SEMI_AFTER_FOR_INIT, 86, 0, JSEXN_SYNTAXERR, "missing ; after for-loop initializer") +MSG_DEF(JSMSG_SEMI_AFTER_FOR_COND, 87, 0, JSEXN_SYNTAXERR, "missing ; after for-loop condition") +MSG_DEF(JSMSG_PAREN_AFTER_FOR_CTRL, 88, 0, JSEXN_SYNTAXERR, "missing ) after for-loop control") +MSG_DEF(JSMSG_CURLY_BEFORE_TRY, 89, 0, JSEXN_SYNTAXERR, "missing { before try block") +MSG_DEF(JSMSG_CURLY_AFTER_TRY, 90, 0, JSEXN_SYNTAXERR, "missing } after try block") +MSG_DEF(JSMSG_PAREN_BEFORE_CATCH, 91, 0, JSEXN_SYNTAXERR, "missing ( before catch") +MSG_DEF(JSMSG_CATCH_IDENTIFIER, 92, 0, JSEXN_SYNTAXERR, "missing identifier in catch") +MSG_DEF(JSMSG_PAREN_AFTER_CATCH, 93, 0, JSEXN_SYNTAXERR, "missing ) after catch") +MSG_DEF(JSMSG_CURLY_BEFORE_CATCH, 94, 0, JSEXN_SYNTAXERR, "missing { before catch block") +MSG_DEF(JSMSG_CURLY_AFTER_CATCH, 95, 0, JSEXN_SYNTAXERR, "missing } after catch block") +MSG_DEF(JSMSG_CURLY_BEFORE_FINALLY, 96, 0, JSEXN_SYNTAXERR, "missing { before finally block") +MSG_DEF(JSMSG_CURLY_AFTER_FINALLY, 97, 0, JSEXN_SYNTAXERR, "missing } after finally block") +MSG_DEF(JSMSG_CATCH_OR_FINALLY, 98, 0, JSEXN_SYNTAXERR, "missing catch or finally after try") +MSG_DEF(JSMSG_PAREN_BEFORE_WITH, 99, 0, JSEXN_SYNTAXERR, "missing ( before with-statement object") +MSG_DEF(JSMSG_PAREN_AFTER_WITH, 100, 0, JSEXN_SYNTAXERR, "missing ) after with-statement object") +MSG_DEF(JSMSG_CURLY_IN_COMPOUND, 101, 0, JSEXN_SYNTAXERR, "missing } in compound statement") +MSG_DEF(JSMSG_NO_VARIABLE_NAME, 102, 0, JSEXN_SYNTAXERR, "missing variable name") +MSG_DEF(JSMSG_COLON_IN_COND, 103, 0, JSEXN_SYNTAXERR, "missing : in conditional expression") +MSG_DEF(JSMSG_PAREN_AFTER_ARGS, 104, 0, JSEXN_SYNTAXERR, "missing ) after argument list") +MSG_DEF(JSMSG_BRACKET_AFTER_LIST, 105, 0, JSEXN_SYNTAXERR, "missing ] after element list") +MSG_DEF(JSMSG_COLON_AFTER_ID, 106, 0, JSEXN_SYNTAXERR, "missing : after property id") +MSG_DEF(JSMSG_CURLY_AFTER_LIST, 107, 0, JSEXN_SYNTAXERR, "missing } after property list") +MSG_DEF(JSMSG_PAREN_IN_PAREN, 108, 0, JSEXN_SYNTAXERR, "missing ) in parenthetical") +MSG_DEF(JSMSG_SEMI_BEFORE_STMNT, 109, 0, JSEXN_SYNTAXERR, "missing ; before statement") +MSG_DEF(JSMSG_NO_RETURN_VALUE, 110, 1, JSEXN_TYPEERR, "function {0} does not always return a value") +MSG_DEF(JSMSG_DUPLICATE_FORMAL, 111, 1, JSEXN_SYNTAXERR, "duplicate formal argument {0}") +MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 112, 1, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?{0}") +MSG_DEF(JSMSG_OPTIMIZED_CLOSURE_LEAK, 113, 0, JSEXN_INTERNALERR, "can't access optimized closure") +MSG_DEF(JSMSG_TOO_MANY_DEFAULTS, 114, 0, JSEXN_SYNTAXERR, "more than one switch default") +MSG_DEF(JSMSG_TOO_MANY_CASES, 115, 0, JSEXN_INTERNALERR, "too many switch cases") +MSG_DEF(JSMSG_BAD_SWITCH, 116, 0, JSEXN_SYNTAXERR, "invalid switch statement") +MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 117, 0, JSEXN_SYNTAXERR, "invalid for/in left-hand side") +MSG_DEF(JSMSG_CATCH_AFTER_GENERAL, 118, 0, JSEXN_SYNTAXERR, "catch after unconditional catch") +MSG_DEF(JSMSG_CATCH_WITHOUT_TRY, 119, 0, JSEXN_SYNTAXERR, "catch without try") +MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY, 120, 0, JSEXN_SYNTAXERR, "finally without try") +MSG_DEF(JSMSG_LABEL_NOT_FOUND, 121, 0, JSEXN_SYNTAXERR, "label not found") +MSG_DEF(JSMSG_TOUGH_BREAK, 122, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch") +MSG_DEF(JSMSG_BAD_CONTINUE, 123, 0, JSEXN_SYNTAXERR, "continue must be inside loop") +MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 124, 1, JSEXN_SYNTAXERR, "{0} not in function") +MSG_DEF(JSMSG_BAD_LABEL, 125, 0, JSEXN_SYNTAXERR, "invalid label") +MSG_DEF(JSMSG_DUPLICATE_LABEL, 126, 0, JSEXN_SYNTAXERR, "duplicate label") +MSG_DEF(JSMSG_VAR_HIDES_ARG, 127, 1, JSEXN_TYPEERR, "variable {0} redeclares argument") +MSG_DEF(JSMSG_BAD_VAR_INIT, 128, 0, JSEXN_SYNTAXERR, "invalid variable initialization") +MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS, 129, 0, JSEXN_REFERENCEERR, "invalid assignment left-hand side") +MSG_DEF(JSMSG_BAD_OPERAND, 130, 1, JSEXN_SYNTAXERR, "invalid {0} operand") +MSG_DEF(JSMSG_BAD_PROP_ID, 131, 0, JSEXN_SYNTAXERR, "invalid property id") +MSG_DEF(JSMSG_RESERVED_ID, 132, 1, JSEXN_SYNTAXERR, "{0} is a reserved identifier") +MSG_DEF(JSMSG_SYNTAX_ERROR, 133, 0, JSEXN_SYNTAXERR, "syntax error") +MSG_DEF(JSMSG_BAD_SHARP_VAR_DEF, 134, 0, JSEXN_SYNTAXERR, "invalid sharp variable definition") +MSG_DEF(JSMSG_BAD_PROTOTYPE, 135, 1, JSEXN_TYPEERR, "'prototype' property of {0} is not an object") +MSG_DEF(JSMSG_MISSING_EXPONENT, 136, 0, JSEXN_SYNTAXERR, "missing exponent") +MSG_DEF(JSMSG_OUT_OF_MEMORY, 137, 0, JSEXN_ERR, "out of memory") +MSG_DEF(JSMSG_UNTERMINATED_STRING, 138, 0, JSEXN_SYNTAXERR, "unterminated string literal") +MSG_DEF(JSMSG_TOO_MANY_PARENS, 139, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression") +MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 140, 0, JSEXN_SYNTAXERR, "unterminated comment") +MSG_DEF(JSMSG_UNTERMINATED_REGEXP, 141, 0, JSEXN_SYNTAXERR, "unterminated regular expression literal") +MSG_DEF(JSMSG_BAD_CLONE_FUNOBJ_SCOPE, 142, 0, JSEXN_TYPEERR, "bad cloned function scope chain") +MSG_DEF(JSMSG_SHARPVAR_TOO_BIG, 143, 0, JSEXN_SYNTAXERR, "overlarge sharp variable number") +MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 144, 0, JSEXN_SYNTAXERR, "illegal character") +MSG_DEF(JSMSG_BAD_OCTAL, 145, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant") +MSG_DEF(JSMSG_BAD_INDIRECT_CALL, 146, 1, JSEXN_EVALERR, "function {0} must be called directly, and not by way of a function of another name") +MSG_DEF(JSMSG_UNCAUGHT_EXCEPTION, 147, 1, JSEXN_INTERNALERR, "uncaught exception: {0}") +MSG_DEF(JSMSG_INVALID_BACKREF, 148, 0, JSEXN_SYNTAXERR, "non-octal digit in an escape sequence that doesn't match a back-reference") +MSG_DEF(JSMSG_BAD_BACKREF, 149, 0, JSEXN_SYNTAXERR, "back-reference exceeds number of capturing parentheses") +MSG_DEF(JSMSG_PRECISION_RANGE, 150, 1, JSEXN_RANGEERR, "precision {0} out of range") +MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER, 151, 1, JSEXN_SYNTAXERR, "invalid {0} usage") +MSG_DEF(JSMSG_BAD_ARRAY_LENGTH, 152, 0, JSEXN_RANGEERR, "invalid array length") +MSG_DEF(JSMSG_CANT_DESCRIBE_PROPS, 153, 1, JSEXN_TYPEERR, "can't describe non-native properties of class {0}") +MSG_DEF(JSMSG_BAD_APPLY_ARGS, 154, 1, JSEXN_TYPEERR, "second argument to Function.prototype.{0} must be an array") +MSG_DEF(JSMSG_REDECLARED_VAR, 155, 2, JSEXN_TYPEERR, "redeclaration of {0} {1}") +MSG_DEF(JSMSG_UNDECLARED_VAR, 156, 1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}") +MSG_DEF(JSMSG_ANON_NO_RETURN_VALUE, 157, 0, JSEXN_TYPEERR, "anonymous function does not always return a value") +MSG_DEF(JSMSG_DEPRECATED_USAGE, 158, 1, JSEXN_REFERENCEERR, "deprecated {0} usage") +MSG_DEF(JSMSG_BAD_URI, 159, 0, JSEXN_URIERR, "malformed URI sequence") +MSG_DEF(JSMSG_GETTER_ONLY, 160, 0, JSEXN_TYPEERR, "setting a property that has only a getter") +MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER, 161, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal") +MSG_DEF(JSMSG_UNDEFINED_PROP, 162, 1, JSEXN_REFERENCEERR, "reference to undefined property {0}") +MSG_DEF(JSMSG_USELESS_EXPR, 163, 0, JSEXN_TYPEERR, "useless expression") +MSG_DEF(JSMSG_REDECLARED_PARAM, 164, 1, JSEXN_TYPEERR, "redeclaration of formal parameter {0}") +MSG_DEF(JSMSG_NEWREGEXP_FLAGGED, 165, 0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another") +MSG_DEF(JSMSG_RESERVED_SLOT_RANGE, 166, 0, JSEXN_RANGEERR, "reserved slot index out of range") +MSG_DEF(JSMSG_CANT_DECODE_PRINCIPALS, 167, 0, JSEXN_INTERNALERR, "can't decode JSPrincipals") +MSG_DEF(JSMSG_CANT_SEAL_OBJECT, 168, 1, JSEXN_ERR, "can't seal {0} objects") +MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS, 169, 0, JSEXN_SYNTAXERR, "too many catch variables") +MSG_DEF(JSMSG_BAD_XML_MARKUP, 170, 0, JSEXN_SYNTAXERR, "invalid XML markup") +MSG_DEF(JSMSG_BAD_XML_CHARACTER, 171, 0, JSEXN_SYNTAXERR, "illegal XML character") +MSG_DEF(JSMSG_BAD_DEFAULT_XML_NAMESPACE,172,0,JSEXN_SYNTAXERR, "invalid default XML namespace") +MSG_DEF(JSMSG_BAD_XML_NAME_SYNTAX, 173, 0, JSEXN_SYNTAXERR, "invalid XML name") +MSG_DEF(JSMSG_BRACKET_AFTER_ATTR_EXPR,174, 0, JSEXN_SYNTAXERR, "missing ] after attribute expression") +MSG_DEF(JSMSG_NESTING_GENERATOR, 175, 1, JSEXN_TYPEERR, "already executing generator {0}") +MSG_DEF(JSMSG_CURLY_IN_XML_EXPR, 176, 0, JSEXN_SYNTAXERR, "missing } in XML expression") +MSG_DEF(JSMSG_BAD_XML_NAMESPACE, 177, 1, JSEXN_TYPEERR, "invalid XML namespace {0}") +MSG_DEF(JSMSG_BAD_XML_ATTR_NAME, 178, 1, JSEXN_TYPEERR, "invalid XML attribute name {0}") +MSG_DEF(JSMSG_BAD_XML_NAME, 179, 1, JSEXN_TYPEERR, "invalid XML name {0}") +MSG_DEF(JSMSG_BAD_XML_CONVERSION, 180, 1, JSEXN_TYPEERR, "can't convert {0} to XML") +MSG_DEF(JSMSG_BAD_XMLLIST_CONVERSION, 181, 1, JSEXN_TYPEERR, "can't convert {0} to XMLList") +MSG_DEF(JSMSG_BAD_GENERATOR_SEND, 182, 1, JSEXN_TYPEERR, "attempt to send {0} to newborn generator") +MSG_DEF(JSMSG_NO_ASSIGN_IN_XML_ATTR, 183, 0, JSEXN_SYNTAXERR, "missing = in XML attribute") +MSG_DEF(JSMSG_BAD_XML_ATTR_VALUE, 184, 0, JSEXN_SYNTAXERR, "invalid XML attribute value") +MSG_DEF(JSMSG_XML_TAG_NAME_MISMATCH, 185, 1, JSEXN_SYNTAXERR, "XML tag name mismatch (expected {0})") +MSG_DEF(JSMSG_BAD_XML_TAG_SYNTAX, 186, 0, JSEXN_SYNTAXERR, "invalid XML tag syntax") +MSG_DEF(JSMSG_BAD_XML_LIST_SYNTAX, 187, 0, JSEXN_SYNTAXERR, "invalid XML list syntax") +MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 188, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}") +MSG_DEF(JSMSG_CANT_SET_XML_ATTRS, 189, 0, JSEXN_INTERNALERR, "can't set XML property attributes") +MSG_DEF(JSMSG_END_OF_XML_SOURCE, 190, 0, JSEXN_SYNTAXERR, "unexpected end of XML source") +MSG_DEF(JSMSG_END_OF_XML_ENTITY, 191, 0, JSEXN_SYNTAXERR, "unexpected end of XML entity") +MSG_DEF(JSMSG_BAD_XML_QNAME, 192, 0, JSEXN_SYNTAXERR, "invalid XML qualified name") +MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 193, 0, JSEXN_SYNTAXERR, "invalid for each loop") +MSG_DEF(JSMSG_BAD_XMLLIST_PUT, 194, 1, JSEXN_TYPEERR, "can't set property {0} in XMLList") +MSG_DEF(JSMSG_UNKNOWN_XML_ENTITY, 195, 1, JSEXN_TYPEERR, "unknown XML entity {0}") +MSG_DEF(JSMSG_BAD_XML_NCR, 196, 1, JSEXN_TYPEERR, "malformed XML character {0}") +MSG_DEF(JSMSG_UNDEFINED_XML_NAME, 197, 1, JSEXN_REFERENCEERR, "reference to undefined XML name {0}") +MSG_DEF(JSMSG_DUPLICATE_XML_ATTR, 198, 1, JSEXN_TYPEERR, "duplicate XML attribute {0}") +MSG_DEF(JSMSG_TOO_MANY_LOCALS, 199, 0, JSEXN_SYNTAXERR, "too many local variables") +MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 200, 0, JSEXN_INTERNALERR, "array initialiser too large") +MSG_DEF(JSMSG_REGEXP_TOO_COMPLEX, 201, 0, JSEXN_INTERNALERR, "regular expression too complex") +MSG_DEF(JSMSG_BUFFER_TOO_SMALL, 202, 0, JSEXN_INTERNALERR, "buffer too small") +MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 203, 1, JSEXN_TYPEERR, "bad surrogate character {0}") +MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 204, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large") +MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR, 205, 1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}") +MSG_DEF(JSMSG_USER_DEFINED_ERROR, 206, 0, JSEXN_ERR, "JS_ReportError was called") +MSG_DEF(JSMSG_WRONG_CONSTRUCTOR, 207, 1, JSEXN_TYPEERR, "wrong constructor called for {0}") +MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 208, 1, JSEXN_TYPEERR, "generator function {0} returns a value") +MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 209, 0, JSEXN_TYPEERR, "anonymous generator function returns a value") +MSG_DEF(JSMSG_NAME_AFTER_FOR_PAREN, 210, 0, JSEXN_SYNTAXERR, "missing name after for (") +MSG_DEF(JSMSG_IN_AFTER_FOR_NAME, 211, 0, JSEXN_SYNTAXERR, "missing in after for") +MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE, 212, 2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value") +MSG_DEF(JSMSG_KEYWORD_NOT_NS, 213, 0, JSEXN_SYNTAXERR, "keyword is used as namespace") +MSG_DEF(JSMSG_BAD_GENERATOR_YIELD, 214, 1, JSEXN_TYPEERR, "yield from closing generator {0}") +MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX, 215, 1, JSEXN_SYNTAXERR, "{0} expression must be parenthesized") +MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 216, 0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side") +MSG_DEF(JSMSG_NON_XML_FILTER, 217, 1, JSEXN_TYPEERR, "XML filter is applied to non-XML value {0}") +MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 218, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value") +MSG_DEF(JSMSG_NON_LIST_XML_METHOD, 219, 2, JSEXN_TYPEERR, "can't call {0} method on an XML list with {1} elements") +MSG_DEF(JSMSG_BAD_DELETE_OPERAND, 220, 0, JSEXN_REFERENCEERR, "invalid delete operand") +MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 221, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand") +MSG_DEF(JSMSG_UNEXPECTED_TYPE, 222, 2, JSEXN_TYPEERR, "{0} is {1}") +MSG_DEF(JSMSG_LET_DECL_NOT_IN_BLOCK, 223, 0, JSEXN_SYNTAXERR, "let declaration not directly within block") +MSG_DEF(JSMSG_BAD_OBJECT_INIT, 224, 0, JSEXN_SYNTAXERR, "invalid object initializer") +MSG_DEF(JSMSG_CANT_SET_ARRAY_ATTRS, 225, 0, JSEXN_INTERNALERR, "can't set attributes on indexed array properties") +MSG_DEF(JSMSG_EVAL_ARITY, 226, 0, JSEXN_TYPEERR, "eval accepts only one parameter") +MSG_DEF(JSMSG_MISSING_FUN_ARG, 227, 2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}") +MSG_DEF(JSMSG_JSON_BAD_PARSE, 228, 0, JSEXN_SYNTAXERR, "JSON.parse") +MSG_DEF(JSMSG_JSON_BAD_STRINGIFY, 229, 0, JSEXN_ERR, "JSON.stringify") +MSG_DEF(JSMSG_XDR_CLOSURE_WRAPPER, 230, 1, JSEXN_INTERNALERR, "can't XDR closure wrapper for function {0}") +MSG_DEF(JSMSG_NOT_NONNULL_OBJECT, 231, 0, JSEXN_TYPEERR, "value is not a non-null object") +MSG_DEF(JSMSG_DEPRECATED_OCTAL, 232, 0, JSEXN_SYNTAXERR, "octal literals and octal escape sequences are deprecated") +MSG_DEF(JSMSG_STRICT_CODE_WITH, 233, 0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements") +MSG_DEF(JSMSG_DUPLICATE_PROPERTY, 234, 1, JSEXN_SYNTAXERR, "property name {0} appears more than once in object literal") +MSG_DEF(JSMSG_DEPRECATED_DELETE_OPERAND, 235, 0, JSEXN_SYNTAXERR, "applying the 'delete' operator to an unqualified name is deprecated") +MSG_DEF(JSMSG_DEPRECATED_ASSIGN, 236, 1, JSEXN_SYNTAXERR, "assignment to {0} is deprecated") +MSG_DEF(JSMSG_BAD_BINDING, 237, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated") +MSG_DEF(JSMSG_INVALID_DESCRIPTOR, 238, 0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified") +MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE, 239, 1, JSEXN_TYPEERR, "{0} is not extensible") +MSG_DEF(JSMSG_CANT_REDEFINE_PROP, 240, 1, JSEXN_TYPEERR, "can't redefine non-configurable property '{0}'") +MSG_DEF(JSMSG_CANT_APPEND_TO_ARRAY, 241, 0, JSEXN_TYPEERR, "can't add elements past the end of an array if its length property is unwritable") +MSG_DEF(JSMSG_CANT_DEFINE_ARRAY_LENGTH,242, 0, JSEXN_INTERNALERR, "defining the length property on an array is not currently supported") +MSG_DEF(JSMSG_CANT_DEFINE_ARRAY_INDEX,243, 0, JSEXN_TYPEERR, "can't define array index property") +MSG_DEF(JSMSG_TYPED_ARRAY_BAD_INDEX, 244, 0, JSEXN_ERR, "invalid or out-of-range index") +MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG, 245, 1, JSEXN_ERR, "argument {0} must be >= 0") +MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 246, 0, JSEXN_ERR, "invalid arguments") +MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 247, 0, JSEXN_ERR, "call to Function() blocked by CSP") +MSG_DEF(JSMSG_BAD_GET_SET_FIELD, 248, 1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function") +MSG_DEF(JSMSG_BAD_PROXY_FIX, 249, 0, JSEXN_TYPEERR, "proxy was fixed while executing the handler") +MSG_DEF(JSMSG_INVALID_EVAL_SCOPE_ARG, 250, 0, JSEXN_EVALERR, "invalid eval scope argument") +MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS, 251, 3, JSEXN_SYNTAXERR, "{0} functions must have {1} argument{2}") +MSG_DEF(JSMSG_THROW_TYPE_ERROR, 252, 0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them") +MSG_DEF(JSMSG_BAD_TOISOSTRING_PROP, 253, 0, JSEXN_TYPEERR, "toISOString property is not callable") +MSG_DEF(JSMSG_BAD_PARSE_NODE, 254, 0, JSEXN_INTERNALERR, "bad parse node") +MSG_DEF(JSMSG_NOT_EXPECTED_TYPE, 255, 3, JSEXN_TYPEERR, "{0}: expected {1}, got {2}") +MSG_DEF(JSMSG_CALLER_IS_STRICT, 256, 0, JSEXN_TYPEERR, "access to strict mode caller function is censored") +MSG_DEF(JSMSG_NEED_DEBUG_MODE, 257, 0, JSEXN_ERR, "function can be called only in debug mode") +MSG_DEF(JSMSG_STRICT_CODE_LET_EXPR_STMT, 258, 0, JSEXN_ERR, "strict mode code may not contain unparenthesized let expression statements") +MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 259, 0, JSEXN_TYPEERR, "can't change object's extensibility") +MSG_DEF(JSMSG_SC_BAD_SERIALIZED_DATA, 260, 1, JSEXN_INTERNALERR, "bad serialized structured data ({0})") +MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE, 261, 0, JSEXN_TYPEERR, "unsupported type for structured data") +MSG_DEF(JSMSG_SC_RECURSION, 262, 0, JSEXN_INTERNALERR, "recursive object") +MSG_DEF(JSMSG_CANT_WRAP_XML_OBJECT, 263, 0, JSEXN_TYPEERR, "can't wrap XML objects") +MSG_DEF(JSMSG_BAD_CLONE_VERSION, 264, 0, JSEXN_ERR, "unsupported structured clone version") +MSG_DEF(JSMSG_CANT_CLONE_OBJECT, 265, 0, JSEXN_TYPEERR, "can't clone object") +MSG_DEF(JSMSG_NON_NATIVE_SCOPE, 266, 0, JSEXN_TYPEERR, "non-native scope object") +MSG_DEF(JSMSG_STRICT_FUNCTION_STATEMENT, 267, 0, JSEXN_SYNTAXERR, "in strict mode code, functions may be declared only at top level or immediately within another function") +MSG_DEF(JSMSG_INVALID_FOR_IN_INIT, 268, 0, JSEXN_SYNTAXERR, "for-in loop let declaration may not have an initializer") +MSG_DEF(JSMSG_CLEARED_SCOPE, 269, 0, JSEXN_TYPEERR, "attempt to run compile-and-go script on a cleared scope") diff --git a/js/src/jsanalyze.cpp b/js/src/jsanalyze.cpp new file mode 100644 index 0000000..c16a83c --- /dev/null +++ b/js/src/jsanalyze.cpp @@ -0,0 +1,676 @@ +/* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */ +/* vim: set ts=40 sw=4 et tw=99: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Mozilla SpiderMonkey bytecode analysis + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian Hackett + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsanalyze.h" +#include "jsautooplen.h" +#include "jscompartment.h" +#include "jscntxt.h" + +namespace js { +namespace analyze { + +///////////////////////////////////////////////////////////////////// +// Script +///////////////////////////////////////////////////////////////////// + +void +Script::destroy() +{ + JS_FinishArenaPool(&pool); +} + +template +inline T * +ArenaArray(JSArenaPool &pool, unsigned count) +{ + void *v; + JS_ARENA_ALLOCATE(v, &pool, count * sizeof(T)); + return (T *) v; +} + +template +inline T * +ArenaNew(JSArenaPool &pool) +{ + void *v; + JS_ARENA_ALLOCATE(v, &pool, sizeof(T)); + return new (v) T(); +} + +///////////////////////////////////////////////////////////////////// +// Bytecode +///////////////////////////////////////////////////////////////////// + +bool +Bytecode::mergeDefines(JSContext *cx, Script *script, bool initial, unsigned newDepth, + uint32 *newArray, unsigned newCount) +{ + if (initial) { + /* + * Haven't handled any incoming edges to this bytecode before. + * Define arrays are copy on write, so just reuse the array for this bytecode. + */ + stackDepth = newDepth; + defineArray = newArray; + defineCount = newCount; + return true; + } + + /* + * This bytecode has multiple incoming edges, intersect the new array with any + * variables known to be defined along other incoming edges. + */ + if (analyzed) { +#ifdef DEBUG + /* + * Once analyzed, a bytecode has its full set of definitions. There are two + * properties we depend on to ensure this. First, bytecode for a function + * is emitted in topological order, and since we analyze bytecodes in the + * order they were emitted we will have seen all incoming jumps except + * for any loop back edges. Second, javascript has structured control flow, + * so loop heads dominate their bodies; the set of variables defined + * on a back edge will be at least as large as at the head of the loop, + * so no intersection or further analysis needs to be done. + */ + JS_ASSERT(stackDepth == newDepth); + for (unsigned i = 0; i < defineCount; i++) { + bool found = false; + for (unsigned j = 0; j < newCount; j++) { + if (newArray[j] == defineArray[i]) + found = true; + } + JS_ASSERT(found); + } +#endif + } else { + JS_ASSERT(stackDepth == newDepth); + bool owned = false; + for (unsigned i = 0; i < defineCount; i++) { + bool found = false; + for (unsigned j = 0; j < newCount; j++) { + if (newArray[j] == defineArray[i]) + found = true; + } + if (!found) { + /* + * Get a mutable copy of the defines. This can end up making + * several copies for a bytecode if it has many incoming edges + * with progressively smaller sets of defined variables. + */ + if (!owned) { + uint32 *reallocArray = ArenaArray(script->pool, defineCount); + if (!reallocArray) { + script->setOOM(cx); + return false; + } + memcpy(reallocArray, defineArray, defineCount * sizeof(uint32)); + defineArray = reallocArray; + owned = true; + } + + /* Swap with the last element and pop the array. */ + defineArray[i--] = defineArray[--defineCount]; + } + } + } + + return true; +} + +///////////////////////////////////////////////////////////////////// +// Analysis +///////////////////////////////////////////////////////////////////// + +inline bool +Script::addJump(JSContext *cx, unsigned offset, + unsigned *currentOffset, unsigned *forwardJump, + unsigned stackDepth, uint32 *defineArray, unsigned defineCount) +{ + JS_ASSERT(offset < script->length); + + Bytecode *&bytecode = code[offset]; + bool initial = (bytecode == NULL); + if (initial) { + bytecode = ArenaNew(pool); + if (!bytecode) { + setOOM(cx); + return false; + } + } + + if (!bytecode->mergeDefines(cx, this, initial, stackDepth, defineArray, defineCount)) + return false; + bytecode->jumpTarget = true; + + if (offset < *currentOffset) { + /* Don't follow back edges to bytecode which has already been analyzed. */ + if (!bytecode->analyzed) { + if (*forwardJump == 0) + *forwardJump = *currentOffset; + *currentOffset = offset; + } + } else if (offset > *forwardJump) { + *forwardJump = offset; + } + + return true; +} + +inline void +Script::setLocal(uint32 local, uint32 offset) +{ + JS_ASSERT(local < localCount()); + JS_ASSERT(offset != LOCAL_CONDITIONALLY_DEFINED); + + /* + * It isn't possible to change the point when a variable becomes unconditionally + * defined, or to mark it as unconditionally defined after it has already been + * marked as having a use before def. It *is* possible to mark it as having + * a use before def after marking it as unconditionally defined. In a loop such as: + * + * while ((a = b) != 0) { x = a; } + * + * When walking through the body of this loop, we will first analyze the test + * (which comes after the body in the bytecode stream) as unconditional code, + * and mark a as definitely defined. a is not in the define array when taking + * the loop's back edge, so it is treated as possibly undefined when written to x. + */ + JS_ASSERT(locals[local] == LOCAL_CONDITIONALLY_DEFINED || + locals[local] == offset || offset == LOCAL_USE_BEFORE_DEF); + + locals[local] = offset; +} + +static inline ptrdiff_t +GetJumpOffset(jsbytecode *pc, jsbytecode *pc2) +{ + uint32 type = JOF_OPTYPE(*pc); + if (JOF_TYPE_IS_EXTENDED_JUMP(type)) + return GET_JUMPX_OFFSET(pc2); + return GET_JUMP_OFFSET(pc2); +} + +static inline unsigned +GetBytecodeLength(jsbytecode *pc) +{ + JSOp op = (JSOp)*pc; + JS_ASSERT(op < JSOP_LIMIT); + JS_ASSERT(op != JSOP_TRAP); + + if (js_CodeSpec[op].length != -1) + return js_CodeSpec[op].length; + return js_GetVariableBytecodeLength(pc); +} + +// return whether op bytecodes do not fallthrough (they may do a jump). +static inline bool +BytecodeNoFallThrough(JSOp op) +{ + switch (op) { + case JSOP_GOTO: + case JSOP_GOTOX: + case JSOP_DEFAULT: + case JSOP_DEFAULTX: + case JSOP_RETURN: + case JSOP_STOP: + case JSOP_RETRVAL: + case JSOP_THROW: + case JSOP_TABLESWITCH: + case JSOP_TABLESWITCHX: + case JSOP_LOOKUPSWITCH: + case JSOP_LOOKUPSWITCHX: + case JSOP_FILTER: + return true; + case JSOP_GOSUB: + case JSOP_GOSUBX: + // these fall through indirectly, after executing a 'finally'. + return false; + default: + return false; + } +} + +/* Untrap a single PC, and retrap it at scope exit. */ +struct UntrapOpcode +{ + jsbytecode *pc; + bool trap; + + UntrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc) + : pc(pc), trap(JSOp(*pc) == JSOP_TRAP) + { + if (trap) + *pc = JS_GetTrapOpcode(cx, script, pc); + } + + ~UntrapOpcode() + { + if (trap) + *pc = JSOP_TRAP; + } +}; + +void +Script::analyze(JSContext *cx, JSScript *script) +{ + JS_ASSERT(!code && !locals); + this->script = script; + + JS_InitArenaPool(&pool, "script_analyze", 256, 8, NULL); + + unsigned length = script->length; + unsigned nfixed = localCount(); + + code = ArenaArray(pool, length); + locals = ArenaArray(pool, nfixed); + + if (!code || !locals) { + setOOM(cx); + return; + } + + PodZero(code, length); + + for (unsigned i = 0; i < nfixed; i++) + locals[i] = LOCAL_CONDITIONALLY_DEFINED; + + /* + * Treat locals as having a possible use-before-def if they could be accessed + * by debug code or by eval, or if they could be accessed by an inner script. + */ + + if (script->usesEval || cx->compartment->debugMode) { + for (uint32 i = 0; i < nfixed; i++) + setLocal(i, LOCAL_USE_BEFORE_DEF); + } + + for (uint32 i = 0; i < script->nClosedVars; i++) { + uint32 slot = script->getClosedVar(i); + if (slot < nfixed) + setLocal(slot, LOCAL_USE_BEFORE_DEF); + } + + /* + * If the script is in debug mode, JS_SetFrameReturnValue can be called at + * any safe point. + */ + if (cx->compartment->debugMode) + usesRval = true; + + /* + * If we are in the middle of one or more jumps, the offset of the highest + * target jumping over this bytecode. Includes implicit jumps from + * try/catch/finally blocks. + */ + unsigned forwardJump = 0; + + /* + * If we are in the middle of a try block, the offset of the highest + * catch/finally/enditer. + */ + unsigned forwardCatch = 0; + + /* Fill in stack depth and definitions at initial bytecode. */ + Bytecode *startcode = ArenaNew(pool); + if (!startcode) { + setOOM(cx); + return; + } + + startcode->stackDepth = 0; + code[0] = startcode; + + unsigned offset, nextOffset = 0; + while (nextOffset < length) { + offset = nextOffset; + + JS_ASSERT(forwardCatch <= forwardJump); + + /* Check if the current forward jump/try-block has finished. */ + if (forwardJump && forwardJump == offset) + forwardJump = 0; + if (forwardCatch && forwardCatch == offset) + forwardCatch = 0; + + Bytecode *&bytecode = code[offset]; + jsbytecode *pc = script->code + offset; + + UntrapOpcode untrap(cx, script, pc); + + JSOp op = (JSOp)*pc; + JS_ASSERT(op < JSOP_LIMIT); + + /* Immediate successor of this bytecode. */ + unsigned successorOffset = offset + GetBytecodeLength(pc); + + /* + * Next bytecode to analyze. This is either the successor, or is an + * earlier bytecode if this bytecode has a loop backedge. + */ + nextOffset = successorOffset; + + if (!bytecode) { + /* Haven't found a path by which this bytecode is reachable. */ + continue; + } + + if (bytecode->analyzed) { + /* No need to reanalyze, see Bytecode::mergeDefines. */ + continue; + } + + bytecode->analyzed = true; + + if (forwardCatch) + bytecode->inTryBlock = true; + + unsigned stackDepth = bytecode->stackDepth; + uint32 *defineArray = bytecode->defineArray; + unsigned defineCount = bytecode->defineCount; + + if (!forwardJump) { + /* + * There is no jump over this bytecode, nor a containing try block. + * Either this bytecode will definitely be executed, or an exception + * will be thrown which the script does not catch. Either way, + * any variables definitely defined at this bytecode will stay + * defined throughout the rest of the script. We just need to + * remember the offset where the variable became unconditionally + * defined, rather than continue to maintain it in define arrays. + */ + for (unsigned i = 0; i < defineCount; i++) { + uint32 local = defineArray[i]; + JS_ASSERT_IF(locals[local] != LOCAL_CONDITIONALLY_DEFINED && + locals[local] != LOCAL_USE_BEFORE_DEF, + locals[local] <= offset); + if (locals[local] == LOCAL_CONDITIONALLY_DEFINED) + setLocal(local, offset); + } + defineArray = NULL; + defineCount = 0; + } + + unsigned nuses, ndefs; + if (js_CodeSpec[op].nuses == -1) + nuses = js_GetVariableStackUses(op, pc); + else + nuses = js_CodeSpec[op].nuses; + + if (js_CodeSpec[op].ndefs == -1) + ndefs = js_GetEnterBlockStackDefs(cx, script, pc); + else + ndefs = js_CodeSpec[op].ndefs; + + JS_ASSERT(stackDepth >= nuses); + stackDepth -= nuses; + stackDepth += ndefs; + + switch (op) { + + case JSOP_SETRVAL: + case JSOP_POPV: + usesRval = true; + break; + + case JSOP_NAME: + case JSOP_CALLNAME: + case JSOP_BINDNAME: + case JSOP_SETNAME: + case JSOP_DELNAME: + case JSOP_INCNAME: + case JSOP_DECNAME: + case JSOP_NAMEINC: + case JSOP_NAMEDEC: + case JSOP_FORNAME: + usesScope = true; + break; + + /* Watch for opcodes the method JIT doesn't compile. */ + case JSOP_GOSUB: + case JSOP_GOSUBX: + case JSOP_IFPRIMTOP: + case JSOP_FILTER: + case JSOP_ENDFILTER: + case JSOP_TABLESWITCHX: + case JSOP_LOOKUPSWITCHX: + hadFailure = true; + return; + + case JSOP_TABLESWITCH: { + jsbytecode *pc2 = pc; + unsigned defaultOffset = offset + GetJumpOffset(pc, pc2); + pc2 += JUMP_OFFSET_LEN; + jsint low = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + jsint high = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + + if (!addJump(cx, defaultOffset, &nextOffset, &forwardJump, + stackDepth, defineArray, defineCount)) { + return; + } + + for (jsint i = low; i <= high; i++) { + unsigned targetOffset = offset + GetJumpOffset(pc, pc2); + if (targetOffset != offset) { + if (!addJump(cx, targetOffset, &nextOffset, &forwardJump, + stackDepth, defineArray, defineCount)) { + return; + } + } + pc2 += JUMP_OFFSET_LEN; + } + break; + } + + case JSOP_LOOKUPSWITCH: { + jsbytecode *pc2 = pc; + unsigned defaultOffset = offset + GetJumpOffset(pc, pc2); + pc2 += JUMP_OFFSET_LEN; + unsigned npairs = GET_UINT16(pc2); + pc2 += UINT16_LEN; + + if (!addJump(cx, defaultOffset, &nextOffset, &forwardJump, + stackDepth, defineArray, defineCount)) { + return; + } + + while (npairs) { + pc2 += INDEX_LEN; + unsigned targetOffset = offset + GetJumpOffset(pc, pc2); + if (!addJump(cx, targetOffset, &nextOffset, &forwardJump, + stackDepth, defineArray, defineCount)) { + return; + } + pc2 += JUMP_OFFSET_LEN; + npairs--; + } + break; + } + + case JSOP_TRY: { + /* + * Everything between a try and corresponding catch or finally is conditional. + * Note that there is no problem with code which is skipped by a thrown + * exception but is not caught by a later handler in the same function: + * no more code will execute, and it does not matter what is defined. + */ + JSTryNote *tn = script->trynotes()->vector; + JSTryNote *tnlimit = tn + script->trynotes()->length; + for (; tn < tnlimit; tn++) { + unsigned startOffset = script->main - script->code + tn->start; + if (startOffset == offset + 1) { + unsigned catchOffset = startOffset + tn->length; + + /* This will overestimate try block code, for multiple catch/finally. */ + if (catchOffset > forwardCatch) + forwardCatch = catchOffset; + + if (tn->kind != JSTRY_ITER) { + if (!addJump(cx, catchOffset, &nextOffset, &forwardJump, + stackDepth, defineArray, defineCount)) { + return; + } + code[catchOffset]->exceptionEntry = true; + } + } + } + break; + } + + case JSOP_GETLOCAL: + /* + * Watch for uses of variables not known to be defined, and mark + * them as having possible uses before definitions. Ignore GETLOCAL + * followed by a POP, these are generated for, e.g. 'var x;' + */ + if (pc[JSOP_GETLOCAL_LENGTH] != JSOP_POP) { + uint32 local = GET_SLOTNO(pc); + if (local < nfixed && !localDefined(local, offset)) + setLocal(local, LOCAL_USE_BEFORE_DEF); + } + break; + + case JSOP_CALLLOCAL: + case JSOP_GETLOCALPROP: + case JSOP_INCLOCAL: + case JSOP_DECLOCAL: + case JSOP_LOCALINC: + case JSOP_LOCALDEC: { + uint32 local = GET_SLOTNO(pc); + if (local < nfixed && !localDefined(local, offset)) + setLocal(local, LOCAL_USE_BEFORE_DEF); + break; + } + + case JSOP_SETLOCAL: + case JSOP_FORLOCAL: { + uint32 local = GET_SLOTNO(pc); + + /* + * The local variable may already have been marked as unconditionally + * defined at a later point in the script, if that definition was in the + * condition for a loop which then jumped back here. In such cases we + * will not treat the variable as ever being defined in the loop body + * (see setLocal). + */ + if (local < nfixed && locals[local] == LOCAL_CONDITIONALLY_DEFINED) { + if (forwardJump) { + /* Add this local to the variables defined after this bytecode. */ + uint32 *newArray = ArenaArray(pool, defineCount + 1); + if (!newArray) { + setOOM(cx); + return; + } + if (defineCount) + memcpy(newArray, defineArray, defineCount * sizeof(uint32)); + defineArray = newArray; + defineArray[defineCount++] = local; + } else { + /* This local is unconditionally defined by this bytecode. */ + setLocal(local, offset); + } + } + break; + } + + default: + break; + } + + uint32 type = JOF_TYPE(js_CodeSpec[op].format); + + /* Check basic jump opcodes, which may or may not have a fallthrough. */ + if (type == JOF_JUMP || type == JOF_JUMPX) { + /* Some opcodes behave differently on their branching path. */ + unsigned newStackDepth; + + switch (op) { + case JSOP_OR: + case JSOP_AND: + case JSOP_ORX: + case JSOP_ANDX: + /* OR/AND instructions push the operation result when short circuiting. */ + newStackDepth = stackDepth + 1; + break; + + case JSOP_CASE: + case JSOP_CASEX: + /* Case instructions do not push the lvalue back when branching. */ + newStackDepth = stackDepth - 1; + break; + + default: + newStackDepth = stackDepth; + break; + } + + unsigned targetOffset = offset + GetJumpOffset(pc, pc); + if (!addJump(cx, targetOffset, &nextOffset, &forwardJump, + newStackDepth, defineArray, defineCount)) { + return; + } + } + + /* Handle any fallthrough from this opcode. */ + if (!BytecodeNoFallThrough(op)) { + JS_ASSERT(successorOffset < script->length); + + Bytecode *&nextcode = code[successorOffset]; + bool initial = (nextcode == NULL); + + if (initial) { + nextcode = ArenaNew(pool); + if (!nextcode) { + setOOM(cx); + return; + } + } + + if (!nextcode->mergeDefines(cx, this, initial, stackDepth, defineArray, defineCount)) + return; + } + } + + JS_ASSERT(!failed()); + JS_ASSERT(forwardJump == 0 && forwardCatch == 0); +} + +} /* namespace analyze */ +} /* namespace js */ diff --git a/js/src/jsanalyze.h b/js/src/jsanalyze.h new file mode 100644 index 0000000..de74302 --- /dev/null +++ b/js/src/jsanalyze.h @@ -0,0 +1,213 @@ +/* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */ +/* vim: set ts=40 sw=4 et tw=99: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Mozilla SpiderMonkey bytecode analysis + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Definitions for javascript analysis. */ + +#ifndef jsanalyze_h___ +#define jsanalyze_h___ + +#include "jsarena.h" +#include "jscntxt.h" +#include "jsscript.h" + +struct JSScript; + +namespace js { +namespace analyze { + +class Script; + +/* Information about a bytecode instruction. */ +struct Bytecode +{ + friend class Script; + + /* Whether there are any incoming jumps to this instruction. */ + bool jumpTarget : 1; + + /* Whether this instruction has been analyzed to get its output defines and stack. */ + bool analyzed : 1; + + /* Whether this is a catch/finally entry point. */ + bool exceptionEntry : 1; + + /* Whether this is in a try block. */ + bool inTryBlock : 1; + + /* Whether this is a method JIT safe point. */ + bool safePoint : 1; + + /* Stack depth before this opcode. */ + uint32 stackDepth; + + /* + * The set of locals defined at this point. This does not include locals which + * were unconditionally defined at an earlier point in the script. + */ + uint32 defineCount; + uint32 *defineArray; + + Bytecode() + { + PodZero(this); + } + + private: + bool mergeDefines(JSContext *cx, + Script *script, bool initial, uint32 newDepth, + uint32 *newArray, uint32 newCount); + + /* Whether a local variable is in the define set at this bytecode. */ + bool isDefined(uint32 slot) + { + JS_ASSERT(analyzed); + for (size_t ind = 0; ind < defineCount; ind++) { + if (defineArray[ind] == slot) + return true; + } + return false; + } +}; + +/* Information about a script. */ +class Script +{ + friend struct Bytecode; + + JSScript *script; + Bytecode **code; + + /* Maximum number of locals to consider for a script. */ + static const unsigned LOCAL_LIMIT = 50; + + /* Offsets at which each local becomes unconditionally defined, or a value below. */ + uint32 *locals; + + static const uint32 LOCAL_USE_BEFORE_DEF = uint32(-1); + static const uint32 LOCAL_CONDITIONALLY_DEFINED = uint32(-2); + + bool outOfMemory; + bool hadFailure; + bool usesRval; + bool usesScope; + + public: + /* Pool for allocating analysis structures which will not outlive this script. */ + JSArenaPool pool; + + void analyze(JSContext *cx, JSScript *script); + void destroy(); + + /* + * For analysis scripts allocated on the stack. Scripts don't have constructors, + * and must be zeroed out before being used. + */ + ~Script() { destroy(); } + + /* Whether we ran out of memory during analysis. */ + bool OOM() { return outOfMemory; } + + /* Whether the script was analyzed successfully. */ + bool failed() { return hadFailure; } + + /* Whether there are POPV/SETRVAL bytecodes which can write to the frame's rval. */ + bool usesReturnValue() const { return usesRval; } + + /* Whether there are NAME bytecodes which can access the frame's scope chain. */ + bool usesScopeChain() const { return usesScope; } + + /* Accessors for bytecode information. */ + + Bytecode& getCode(uint32 offset) { + JS_ASSERT(offset < script->length); + JS_ASSERT(code[offset]); + return *code[offset]; + } + Bytecode& getCode(jsbytecode *pc) { return getCode(pc - script->code); } + + Bytecode* maybeCode(uint32 offset) { + JS_ASSERT(offset < script->length); + return code[offset]; + } + Bytecode* maybeCode(jsbytecode *pc) { return maybeCode(pc - script->code); } + + bool jumpTarget(uint32 offset) { + JS_ASSERT(offset < script->length); + return code[offset] && code[offset]->jumpTarget; + } + bool jumpTarget(jsbytecode *pc) { return jumpTarget(pc - script->code); } + + /* Accessors for local variable information. */ + + unsigned localCount() { + return (script->nfixed >= LOCAL_LIMIT) ? LOCAL_LIMIT : script->nfixed; + } + + bool localHasUseBeforeDef(uint32 local) { + JS_ASSERT(local < script->nfixed && !failed()); + return local >= localCount() || locals[local] == LOCAL_USE_BEFORE_DEF; + } + + /* These return true for variables that may have a use before def. */ + bool localDefined(uint32 local, uint32 offset) { + return localHasUseBeforeDef(local) || (locals[local] <= offset) || + getCode(offset).isDefined(local); + } + bool localDefined(uint32 local, jsbytecode *pc) { + return localDefined(local, pc - script->code); + } + + private: + void setOOM(JSContext *cx) { + if (!outOfMemory) + js_ReportOutOfMemory(cx); + outOfMemory = true; + hadFailure = true; + } + + inline bool addJump(JSContext *cx, unsigned offset, + unsigned *currentOffset, unsigned *forwardJump, + unsigned stackDepth, uint32 *defineArray, unsigned defineCount); + + inline void setLocal(uint32 local, uint32 offset); +}; + +} /* namespace analyze */ +} /* namespace js */ + +#endif // jsanalyze_h___ diff --git a/js/src/jsapi-tests/Makefile.in b/js/src/jsapi-tests/Makefile.in new file mode 100644 index 0000000..f79f557 --- /dev/null +++ b/js/src/jsapi-tests/Makefile.in @@ -0,0 +1,97 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Spidermonkey build system. +# +# The Initial Developer of the Original Code is +# The Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2009 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Jason Orendorff +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +PROGRAM = jsapi-tests$(BIN_SUFFIX) + +CPPSRCS = \ + tests.cpp \ + selfTest.cpp \ + testBug604087.cpp \ + testClassGetter.cpp \ + testCloneScript.cpp \ + testConservativeGC.cpp \ + testContexts.cpp \ + testDebugger.cpp \ + testDeepFreeze.cpp \ + testDefineGetterSetterNonEnumerable.cpp \ + testDefineProperty.cpp \ + testExtendedEq.cpp \ + testFuncCallback.cpp \ + testGCChunkAlloc.cpp \ + testGetPropertyDefault.cpp \ + testIntString.cpp \ + testLookup.cpp \ + testNewObject.cpp \ + testOps.cpp \ + testPropCache.cpp \ + testSameValue.cpp \ + testScriptObject.cpp \ + testSetProperty.cpp \ + testThreadGC.cpp \ + testThreads.cpp \ + testTrap.cpp \ + testUTF8.cpp \ + testVersion.cpp \ + testXDR.cpp \ + testCustomIterator.cpp \ + $(NULL) + +DEFINES += -DEXPORT_JS_API + +LIBS = $(DEPTH)/$(LIB_PREFIX)js_static.$(LIB_SUFFIX) $(NSPR_LIBS) + +LOCAL_INCLUDES += -I$(topsrcdir) -I.. + +ifdef _MSC_VER +ifdef WINCE +WIN32_EXE_LDFLAGS += -ENTRY:mainACRTStartup +endif +endif + +include $(topsrcdir)/config/rules.mk + +check:: + $(wildcard $(RUN_TEST_PROGRAM)) $(DIST)/bin/jsapi-tests$(BIN_SUFFIX) diff --git a/js/src/jsapi-tests/README b/js/src/jsapi-tests/README new file mode 100644 index 0000000..8066b1b --- /dev/null +++ b/js/src/jsapi-tests/README @@ -0,0 +1,160 @@ +=== JSAPI Test Suite + +The tests in this directory exercise the JSAPI. + + +--- Building and running the tests + +If you built JS, you already built the tests. + +If you did `make check` in your JS objdir, you already ran them. + +The tests are built by default when you build JS. All the tests are compiled +into a single binary named jsapi-tests. They all run in a single process. + +To run the tests in a debugger: + + cd $OBJDIR/jsapi-tests + gdb ./jsapi-tests + + +--- Creating new tests + + 1. You can either add to an existing test*.cpp file or make a new one. + Copy an existing test and replace the body with your test code. + The test harness provides `cx`, `rt`, and `global` for your use. + + 2. If you made a new .cpp file, add it to the CPPSRCS list in Makefile.in. + + +--- Writing test code + +Here is a sample test: + + #include "tests.h" + + BEGIN_TEST(testIntString_bug515273) + { + jsval v; + EVAL("'42';", &v); + + JSString *str = JSVAL_TO_STRING(v); + const char *bytes = JS_GetStringBytes(str); + CHECK(strcmp(bytes, "42") == 0); + return true; + } + END_TEST(testIntString_bug515273) + +The BEGIN_TEST and END_TEST macros bracket each test. By convention, the test +name is _. (The above test is in testIntString.cpp.) + +The curly braces are required. This block is the body of a C++ member function +that returns JSBool. The test harness calls this member function +automatically. If the function returns true, the test passes. False, it fails. + +JSAPI tests often need extra global C/C++ code: a JSClass, a getter or setter +function, a resolve hook. Put these before the BEGIN_TEST macro. + +The body of the test can use these member variables and macros, defined in +tests.h: + + JSRuntime *rt; + JSContext *cx; + JSObject *global; + + The test framework creates these fresh for each test. The default + environment has reasonable default settings, including + JSOPTION_VAROBJFIX, JSOPTION_JIT, a global object of a class with + JSCLASS_GLOBAL_FLAGS, and an error reporter that prints to stderr. + See also "Custom test setup" below. + + EXEC(const char *code); + + Execute some JS code in global scope, using JS_EvaluateScript. Return + false if that fails. (This means that if the code throws an uncaught JS + exception, the test fails.) + + EVAL(const char *code, jsval *vp); + + Same as EXEC, but store the result value in *vp. + + CHECK(bool cond); + + If the condition is not true, print an error message and return false, + failing the test. + + CHECK_SAME(jsval a, jsval b); + + If a and b are different values, print an error message and return + false, failing the test. + + This is like CHECK(sameValue(a, b)) but with a more detailed error + message. See sameValue below. + + bool knownFail; + + Set this to true if your test is known to fail. The test runner will + print a TEST-KNOWN-FAIL line rather than a TEST-UNEXPECTED-FAIL + line. This way you can check in a test illustrating a bug ahead of the + fix. + + If your test actually crashes the process or triggers an assertion, + this of course will not help, so you should add something like + + knownFail = true; // see bug 123456 + return false; // the code below crashes! + + as the first two lines of the test. + + bool isNegativeZero(jsval v); + bool isNaN(jsval v); + + Self-explanatory. + + bool sameValue(jsval v1, jsval v2); + + True if v1 and v2 are the same value according to the ES5 SameValue() + function, to wit: + + SameValue(NaN, NaN) is true. + SameValue(-0, 0) is false. + Otherwise SameValue(a, b) iff a === b. + +And see class jsvalRoot, also defined in tests.h. + + +--- Custom test setup + +Before executing each test, the test framework calls the tests' init() member +function, which populates the rt, cx, and global member variables. + +A test can customize the test setup process by overloading virtual member +functions, like this: + + JSClass globalClassWithResolve = { ... }; + + BEGIN_TEST(testGlobalResolveHook) + { + jsvalRoot v; + EVAL("v", v.addr()); + CHECK_SAME(v, JSVAL_VOID); + return true; + } + + // Other class members can go here. + + // This one overloads a base-class method. + virtual JSClass *getGlobalJSClass() { + return &globalClassWithResolve; + } + END_TEST(testGlobalResolveHook) + +The overloadable member functions are: + + virtual bool init(); + virtual void uninit(); + virtual JSRuntime * createRuntime(); + virtual JSContext * createContext(); + virtual JSClass * getGlobalClass(); + virtual JSObject * createGlobal(); + diff --git a/js/src/jsapi-tests/selfTest.cpp b/js/src/jsapi-tests/selfTest.cpp new file mode 100644 index 0000000..4ae7629 --- /dev/null +++ b/js/src/jsapi-tests/selfTest.cpp @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" + +BEGIN_TEST(selfTest_NaNsAreSame) +{ + jsvalRoot v1(cx), v2(cx); + EVAL("0/0", v1.addr()); // NaN + CHECK_SAME(v1, v1); + + EVAL("Math.sin('no')", v2.addr()); // also NaN + CHECK_SAME(v1, v2); + return true; +} +END_TEST(selfTest_NaNsAreSame) + +BEGIN_TEST(selfTest_globalHasNoParent) +{ + CHECK(JS_GetParent(cx, global) == NULL); + return true; +} +END_TEST(selfTest_globalHasNoParent) diff --git a/js/src/jsapi-tests/testBug604087.cpp b/js/src/jsapi-tests/testBug604087.cpp new file mode 100644 index 0000000..402c362 --- /dev/null +++ b/js/src/jsapi-tests/testBug604087.cpp @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * Tests JS_TransplantObject + */ + +#include "tests.h" +#include "jswrapper.h" + +struct OuterWrapper : JSWrapper +{ + OuterWrapper() : JSWrapper(0) {} + + virtual bool isOuterWindow() { + return true; + } + + static OuterWrapper singleton; +}; + +OuterWrapper +OuterWrapper::singleton; + +static JSObject * +wrap(JSContext *cx, JSObject *toWrap, JSObject *target) +{ + JSAutoEnterCompartment ac; + if (!ac.enter(cx, target)) + return NULL; + + JSObject *wrapper = toWrap; + if (!JS_WrapObject(cx, &wrapper)) + return NULL; + return wrapper; +} + +static JSObject * +PreWrap(JSContext *cx, JSObject *scope, JSObject *obj, uintN flags) +{ + JS_GC(cx); + return obj; +} + +static JSObject * +Wrap(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, uintN flags) +{ + return JSWrapper::New(cx, obj, proto, parent, &JSCrossCompartmentWrapper::singleton); +} + +BEGIN_TEST(testBug604087) +{ + JSObject *outerObj = JSWrapper::New(cx, global, global->getProto(), global, + &OuterWrapper::singleton); + JSObject *compartment2 = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL); + JSObject *compartment3 = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL); + JSObject *compartment4 = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL); + + JSObject *c2wrapper = wrap(cx, outerObj, compartment2); + CHECK(c2wrapper); + c2wrapper->setProxyExtra(js::Int32Value(2)); + + JSObject *c3wrapper = wrap(cx, outerObj, compartment3); + CHECK(c3wrapper); + c3wrapper->setProxyExtra(js::Int32Value(3)); + + JSObject *c4wrapper = wrap(cx, outerObj, compartment4); + CHECK(c4wrapper); + c4wrapper->setProxyExtra(js::Int32Value(4)); + compartment4 = c4wrapper = NULL; + + JSObject *next; + { + JSAutoEnterCompartment ac; + CHECK(ac.enter(cx, compartment2)); + next = JSWrapper::New(cx, compartment2, compartment2->getProto(), compartment2, + &OuterWrapper::singleton); + CHECK(next); + } + + JS_SetWrapObjectCallbacks(JS_GetRuntime(cx), Wrap, PreWrap); + CHECK(JS_TransplantObject(cx, outerObj, next)); + return true; +} +END_TEST(testBug604087) diff --git a/js/src/jsapi-tests/testClassGetter.cpp b/js/src/jsapi-tests/testClassGetter.cpp new file mode 100644 index 0000000..ae8f450 --- /dev/null +++ b/js/src/jsapi-tests/testClassGetter.cpp @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * Tests the JSClass::getProperty hook + */ + +#include "tests.h" + +int called_test_fn; +int called_test_prop_get; + +static JSBool test_prop_get( JSContext *cx, JSObject *obj, jsid id, jsval *vp ) +{ + called_test_prop_get++; + return JS_TRUE; +} + +static JSBool +PTest(JSContext* cx, uintN argc, jsval *vp) +{ + JSObject *obj = JS_NewObjectForConstructor(cx, vp); + if (!obj) + return JS_FALSE; + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj)); + return JS_TRUE; +} + +static JSClass ptestClass = { + "PTest", + JSCLASS_HAS_PRIVATE, + + JS_PropertyStub, // add + JS_PropertyStub, // delete + test_prop_get, // get + JS_StrictPropertyStub, // set + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSBool test_fn(JSContext *cx, uintN argc, jsval *vp) +{ + called_test_fn++; + return JS_TRUE; +} + +static JSFunctionSpec ptestFunctions[] = { + JS_FS( "test_fn", test_fn, 0, 0 ), + JS_FS_END +}; + +BEGIN_TEST(testClassGetter_isCalled) +{ + CHECK(JS_InitClass(cx, JS_GetGlobalObject(cx), NULL, &ptestClass, PTest, 0, + NULL, ptestFunctions, NULL, NULL)); + + EXEC("function check() { var o = new PTest(); o.test_fn(); o.test_value1; o.test_value2; o.test_value1; }"); + + for (int i = 1; i < 9; i++) { + jsvalRoot rval(cx); + CHECK(JS_CallFunctionName(cx, global, "check", 0, NULL, rval.addr())); + CHECK_SAME(INT_TO_JSVAL(called_test_fn), INT_TO_JSVAL(i)); + CHECK_SAME(INT_TO_JSVAL(called_test_prop_get), INT_TO_JSVAL(4 * i)); + } + return true; +} +END_TEST(testClassGetter_isCalled) diff --git a/js/src/jsapi-tests/testCloneScript.cpp b/js/src/jsapi-tests/testCloneScript.cpp new file mode 100644 index 0000000..690642a --- /dev/null +++ b/js/src/jsapi-tests/testCloneScript.cpp @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * Test script cloning. + */ + +#include "tests.h" +#include "jsapi.h" + +BEGIN_TEST(test_cloneScript) +{ + JSObject *A, *B; + + CHECK(A = createGlobal()); + CHECK(B = createGlobal()); + + const char *source = + "var i = 0;\n" + "var sum = 0;\n" + "while (i < 10) {\n" + " sum += i;\n" + " ++i;\n" + "}\n" + "(sum);\n"; + + JSObject *obj; + + // compile for A + { + JSAutoEnterCompartment a; + if (!a.enter(cx, A)) + return false; + + JSFunction *fun; + CHECK(fun = JS_CompileFunction(cx, A, "f", 0, NULL, source, strlen(source), __FILE__, 1)); + CHECK(obj = JS_GetFunctionObject(fun)); + } + + // clone into B + { + JSAutoEnterCompartment b; + if (!b.enter(cx, B)) + return false; + + CHECK(JS_CloneFunctionObject(cx, obj, B)); + } + + return true; +} +END_TEST(test_cloneScript) diff --git a/js/src/jsapi-tests/testConservativeGC.cpp b/js/src/jsapi-tests/testConservativeGC.cpp new file mode 100644 index 0000000..47aa059 --- /dev/null +++ b/js/src/jsapi-tests/testConservativeGC.cpp @@ -0,0 +1,80 @@ +#include "tests.h" +#include "jsobj.h" +#include "jsstr.h" + +BEGIN_TEST(testConservativeGC) +{ + jsval v2; + EVAL("({foo: 'bar'});", &v2); + CHECK(JSVAL_IS_OBJECT(v2)); + JSObject objCopy = *JSVAL_TO_OBJECT(v2); + + jsval v3; + EVAL("String(Math.PI);", &v3); + CHECK(JSVAL_IS_STRING(v3)); + JSString strCopy = *JSVAL_TO_STRING(v3); + + jsval tmp; + EVAL("({foo2: 'bar2'});", &tmp); + CHECK(JSVAL_IS_OBJECT(tmp)); + JSObject *obj2 = JSVAL_TO_OBJECT(tmp); + JSObject obj2Copy = *obj2; + + EVAL("String(Math.sqrt(3));", &tmp); + CHECK(JSVAL_IS_STRING(tmp)); + JSString *str2 = JSVAL_TO_STRING(tmp); + JSString str2Copy = *str2; + + tmp = JSVAL_NULL; + + JS_GC(cx); + + EVAL("var a = [];\n" + "for (var i = 0; i != 10000; ++i) {\n" + "a.push(i + 0.1, [1, 2], String(Math.sqrt(i)), {a: i});\n" + "}", &tmp); + + JS_GC(cx); + + checkObjectFields(&objCopy, JSVAL_TO_OBJECT(v2)); + CHECK(!memcmp(&strCopy, JSVAL_TO_STRING(v3), sizeof(strCopy))); + + checkObjectFields(&obj2Copy, obj2); + CHECK(!memcmp(&str2Copy, str2, sizeof(str2Copy))); + + return true; +} + +bool checkObjectFields(JSObject *savedCopy, JSObject *obj) +{ + /* + * The GC can change the shape and shrink dslots so we update them before + * doing memcmp. + */ + savedCopy->objShape = obj->objShape; + savedCopy->slots = obj->slots; + CHECK(!memcmp(savedCopy, obj, sizeof(*obj))); + return true; +} + +END_TEST(testConservativeGC) + +BEGIN_TEST(testDerivedValues) +{ + JSString *str = JS_NewStringCopyZ(cx, "once upon a midnight dreary"); + JS::Anchor str_anchor(str); + static const jschar expected[] = { 'o', 'n', 'c', 'e' }; + const jschar *ch = JS_GetStringCharsZ(cx, str); + str = NULL; + + /* Do a lot of allocation and collection. */ + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 1000; j++) + JS_NewStringCopyZ(cx, "as I pondered weak and weary"); + JS_GC(cx); + } + + CHECK(!memcmp(ch, expected, sizeof(expected))); + return true; +} +END_TEST(testDerivedValues) diff --git a/js/src/jsapi-tests/testContexts.cpp b/js/src/jsapi-tests/testContexts.cpp new file mode 100644 index 0000000..699730f --- /dev/null +++ b/js/src/jsapi-tests/testContexts.cpp @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" + +BEGIN_TEST(testContexts_IsRunning) + { + CHECK(JS_DefineFunction(cx, global, "chk", chk, 0, 0)); + EXEC("for (var i = 0; i < 9; i++) chk();"); + return true; + } + + static JSBool chk(JSContext *cx, uintN argc, jsval *vp) + { + JSRuntime *rt = JS_GetRuntime(cx); + JSContext *acx = JS_NewContext(rt, 8192); + if (!acx) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + + // acx should not be running + bool ok = !JS_IsRunning(acx); + if (!ok) + JS_ReportError(cx, "Assertion failed: brand new context claims to be running"); + JS_DestroyContext(acx); + return ok; + } +END_TEST(testContexts_IsRunning) + +BEGIN_TEST(testContexts_bug563735) +{ + JSContext *cx2 = JS_NewContext(rt, 8192); + CHECK(cx2); + + JSBool ok; + { + JSAutoRequest req(cx2); + JSAutoEnterCompartment ac; + CHECK(ac.enter(cx2, global)); + jsval v = JSVAL_NULL; + ok = JS_SetProperty(cx2, global, "x", &v); + } + CHECK(ok); + + EXEC("(function () { for (var i = 0; i < 9; i++) ; })();"); + + JS_DestroyContext(cx2); + return true; +} +END_TEST(testContexts_bug563735) diff --git a/js/src/jsapi-tests/testCustomIterator.cpp b/js/src/jsapi-tests/testCustomIterator.cpp new file mode 100644 index 0000000..c05eef3 --- /dev/null +++ b/js/src/jsapi-tests/testCustomIterator.cpp @@ -0,0 +1,81 @@ +#include "tests.h" + +#include "jsvalue.h" + +int count = 0; + +static JSBool +IterNext(JSContext *cx, uintN argc, jsval *vp) +{ + if (count++ == 100) + return JS_ThrowStopIteration(cx); + JS_SET_RVAL(cx, vp, INT_TO_JSVAL(count)); + return true; +} + +static JSObject * +IterHook(JSContext *cx, JSObject *obj, JSBool keysonly) +{ + JSObject *iterObj = JS_NewObject(cx, NULL, NULL, NULL); + if (!iterObj) + return NULL; + if (!JS_DefineFunction(cx, iterObj, "next", IterNext, 0, 0)) + return NULL; + return iterObj; +} + +js::Class HasCustomIterClass = { + "HasCustomIter", + 0, + js::PropertyStub, + js::PropertyStub, + js::PropertyStub, + js::StrictPropertyStub, + js::EnumerateStub, + js::ResolveStub, + js::ConvertStub, + NULL, + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + NULL, /* mark */ + { + NULL, + NULL, + NULL, + IterHook, + NULL + } +}; + +JSBool +IterClassConstructor(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj = JS_NewObjectForConstructor(cx, vp); + if (!obj) + return false; + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj)); + return true; +} + +BEGIN_TEST(testCustomIterator_bug612523) +{ + CHECK(JS_InitClass(cx, JS_GetGlobalObject(cx), NULL, Jsvalify(&HasCustomIterClass), + IterClassConstructor, 0, NULL, NULL, NULL, NULL)); + + jsval result; + EVAL("var o = new HasCustomIter(); \n" + "var j = 0; \n" + "for (var i in o) { ++j; }; \n" + "j;", &result); + + CHECK(JSVAL_IS_INT(result)); + CHECK(JSVAL_TO_INT(result) == 100); + CHECK(count == 101); + + return true; +} +END_TEST(testCustomIterator_bug612523) diff --git a/js/src/jsapi-tests/testDebugger.cpp b/js/src/jsapi-tests/testDebugger.cpp new file mode 100644 index 0000000..035e515 --- /dev/null +++ b/js/src/jsapi-tests/testDebugger.cpp @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" +#include "jsdbgapi.h" + +static int callCount[2] = {0, 0}; + +static void * +callCountHook(JSContext *cx, JSStackFrame *fp, JSBool before, JSBool *ok, void *closure) +{ + callCount[before]++; + + jsval thisv; + JS_GetFrameThis(cx, fp, &thisv); // assert if fp is incomplete + + return cx; // any non-null value causes the hook to be called again after +} + +BEGIN_TEST(testDebugger_bug519719) +{ + JS_SetCallHook(rt, callCountHook, NULL); + EXEC("function call(fn) { fn(0); }\n" + "function f(g) { for (var i = 0; i < 9; i++) call(g); }\n" + "f(Math.sin);\n" // record loop, starting in f + "f(Math.cos);\n"); // side exit in f -> call + CHECK(callCount[0] == 20); + CHECK(callCount[1] == 20); + return true; +} +END_TEST(testDebugger_bug519719) + +static void * +nonStrictThisHook(JSContext *cx, JSStackFrame *fp, JSBool before, JSBool *ok, void *closure) +{ + if (before) { + bool *allWrapped = (bool *) closure; + jsval thisv; + JS_GetFrameThis(cx, fp, &thisv); + *allWrapped = *allWrapped && !JSVAL_IS_PRIMITIVE(thisv); + } + return NULL; +} + +BEGIN_TEST(testDebugger_getThisNonStrict) +{ + bool allWrapped = true; + JS_SetCallHook(rt, nonStrictThisHook, (void *) &allWrapped); + EXEC("function nonstrict() { }\n" + "Boolean.prototype.nonstrict = nonstrict;\n" + "String.prototype.nonstrict = nonstrict;\n" + "Number.prototype.nonstrict = nonstrict;\n" + "Object.prototype.nonstrict = nonstrict;\n" + "nonstrict.call(true);\n" + "true.nonstrict();\n" + "nonstrict.call('');\n" + "''.nonstrict();\n" + "nonstrict.call(42);\n" + "(42).nonstrict();\n" + // The below don't really get 'wrapped', but it's okay. + "nonstrict.call(undefined);\n" + "nonstrict.call(null);\n" + "nonstrict.call({});\n" + "({}).nonstrict();\n"); + CHECK(allWrapped); + return true; +} +END_TEST(testDebugger_getThisNonStrict) + +static void * +strictThisHook(JSContext *cx, JSStackFrame *fp, JSBool before, JSBool *ok, void *closure) +{ + if (before) { + bool *anyWrapped = (bool *) closure; + jsval thisv; + JS_GetFrameThis(cx, fp, &thisv); + *anyWrapped = *anyWrapped || !JSVAL_IS_PRIMITIVE(thisv); + } + return NULL; +} + +BEGIN_TEST(testDebugger_getThisStrict) +{ + bool anyWrapped = false; + JS_SetCallHook(rt, strictThisHook, (void *) &anyWrapped); + EXEC("function strict() { 'use strict'; }\n" + "Boolean.prototype.strict = strict;\n" + "String.prototype.strict = strict;\n" + "Number.prototype.strict = strict;\n" + "strict.call(true);\n" + "true.strict();\n" + "strict.call('');\n" + "''.strict();\n" + "strict.call(42);\n" + "(42).strict();\n" + "strict.call(undefined);\n" + "strict.call(null);\n"); + CHECK(!anyWrapped); + return true; +} +END_TEST(testDebugger_getThisStrict) diff --git a/js/src/jsapi-tests/testDeepFreeze.cpp b/js/src/jsapi-tests/testDeepFreeze.cpp new file mode 100644 index 0000000..3c2d354 --- /dev/null +++ b/js/src/jsapi-tests/testDeepFreeze.cpp @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" + +BEGIN_TEST(testDeepFreeze_bug535703) +{ + jsval v; + EVAL("var x = {}; x;", &v); + CHECK(JS_DeepFreezeObject(cx, JSVAL_TO_OBJECT(v))); // don't crash + EVAL("Object.isFrozen(x)", &v); + CHECK_SAME(v, JSVAL_TRUE); + return true; +} +END_TEST(testDeepFreeze_bug535703) + +BEGIN_TEST(testDeepFreeze_deep) +{ + jsval a, o; + EXEC("var a = {}, o = a;\n" + "for (var i = 0; i < 10000; i++)\n" + " a = {x: a, y: a};\n"); + EVAL("a", &a); + EVAL("o", &o); + + CHECK(JS_DeepFreezeObject(cx, JSVAL_TO_OBJECT(a))); + + jsval b; + EVAL("Object.isFrozen(a)", &b); + CHECK_SAME(b, JSVAL_TRUE); + EVAL("Object.isFrozen(o)", &b); + CHECK_SAME(b, JSVAL_TRUE); + return true; +} +END_TEST(testDeepFreeze_deep) + +BEGIN_TEST(testDeepFreeze_loop) +{ + jsval x, y; + EXEC("var x = [], y = {x: x}; y.y = y; x.push(x, y);"); + EVAL("x", &x); + EVAL("y", &y); + + CHECK(JS_DeepFreezeObject(cx, JSVAL_TO_OBJECT(x))); + + jsval b; + EVAL("Object.isFrozen(x)", &b); + CHECK_SAME(b, JSVAL_TRUE); + EVAL("Object.isFrozen(y)", &b); + CHECK_SAME(b, JSVAL_TRUE); + return true; +} +END_TEST(testDeepFreeze_loop) diff --git a/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp b/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp new file mode 100644 index 0000000..23e6e5e --- /dev/null +++ b/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" +#include "jsxdrapi.h" + +static JSBool +native(JSContext *cx, uintN argc, jsval *vp) +{ + return JS_TRUE; +} + +static const char PROPERTY_NAME[] = "foo"; + +BEGIN_TEST(testDefineGetterSetterNonEnumerable) +{ + jsvalRoot vobj(cx); + JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL); + CHECK(obj); + vobj = OBJECT_TO_JSVAL(obj); + + jsvalRoot vget(cx); + JSFunction *funGet = JS_NewFunction(cx, native, 0, 0, NULL, "get"); + CHECK(funGet); + JSObject *funGetObj = JS_GetFunctionObject(funGet); + vget = OBJECT_TO_JSVAL(funGetObj); + + jsvalRoot vset(cx); + JSFunction *funSet = JS_NewFunction(cx, native, 1, 0, NULL, "set"); + CHECK(funSet); + JSObject *funSetObj = JS_GetFunctionObject(funSet); + vset = OBJECT_TO_JSVAL(funSetObj); + + CHECK(JS_DefineProperty(cx, JSVAL_TO_OBJECT(vobj), PROPERTY_NAME, + JSVAL_VOID, + JS_DATA_TO_FUNC_PTR(JSPropertyOp, funGetObj), + JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, funSetObj), + JSPROP_GETTER | JSPROP_SETTER | JSPROP_ENUMERATE)); + + CHECK(JS_DefineProperty(cx, JSVAL_TO_OBJECT(vobj), PROPERTY_NAME, + JSVAL_VOID, + JS_DATA_TO_FUNC_PTR(JSPropertyOp, funGetObj), + JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, funSetObj), + JSPROP_GETTER | JSPROP_SETTER | JSPROP_PERMANENT)); + + JSBool found = JS_FALSE; + uintN attrs = 0; + CHECK(JS_GetPropertyAttributes(cx, JSVAL_TO_OBJECT(vobj), PROPERTY_NAME, + &attrs, &found)); + CHECK(found); + CHECK(attrs & JSPROP_GETTER); + CHECK(attrs & JSPROP_SETTER); + CHECK(attrs & JSPROP_PERMANENT); + CHECK(!(attrs & JSPROP_ENUMERATE)); + + return true; +} +END_TEST(testDefineGetterSetterNonEnumerable) diff --git a/js/src/jsapi-tests/testDefineProperty.cpp b/js/src/jsapi-tests/testDefineProperty.cpp new file mode 100644 index 0000000..15730fa --- /dev/null +++ b/js/src/jsapi-tests/testDefineProperty.cpp @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" + +BEGIN_TEST(testDefineProperty_bug564344) +{ + jsvalRoot x(cx); + EVAL("function f() {}\n" + "var x = {p: f};\n" + "x.p(); // brand x's scope\n" + "x;", x.addr()); + + JSObject *obj = JSVAL_TO_OBJECT(x.value()); + for (int i = 0; i < 2; i++) + CHECK(JS_DefineProperty(cx, obj, "q", JSVAL_VOID, NULL, NULL, JSPROP_SHARED)); + return true; +} +END_TEST(testDefineProperty_bug564344) diff --git a/js/src/jsapi-tests/testExtendedEq.cpp b/js/src/jsapi-tests/testExtendedEq.cpp new file mode 100644 index 0000000..e47664e --- /dev/null +++ b/js/src/jsapi-tests/testExtendedEq.cpp @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * This tests user-specified (via JSExtendedClass) equality operations on + * trace. + */ + +#include "tests.h" +#include "jsobj.h" + +static JSBool +my_Equality(JSContext *cx, JSObject *obj, const jsval *, JSBool *bp) +{ + *bp = JS_TRUE; + return JS_TRUE; +} + +js::Class TestExtendedEq_JSClass = { + "TestExtendedEq", + 0, + js::PropertyStub, /* addProperty */ + js::PropertyStub, /* delProperty */ + js::PropertyStub, /* getProperty */ + js::StrictPropertyStub, /* setProperty */ + JS_EnumerateStub, + JS_ResolveStub, + NULL, /* convert */ + NULL, /* finalize */ + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + NULL, /* mark */ + { + js::Valueify(my_Equality), + NULL, /* outerObject */ + NULL, /* innerObject */ + NULL, /* iteratorObject */ + NULL, /* wrappedObject */ + } +}; + +BEGIN_TEST(testExtendedEq_bug530489) +{ + JSClass *clasp = (JSClass *) &TestExtendedEq_JSClass; + + CHECK(JS_InitClass(cx, global, global, clasp, NULL, 0, NULL, NULL, NULL, NULL)); + + CHECK(JS_DefineObject(cx, global, "obj1", clasp, NULL, 0)); + CHECK(JS_DefineObject(cx, global, "obj2", clasp, NULL, 0)); + + jsval v; + EVAL("(function() { var r; for (var i = 0; i < 10; ++i) r = obj1 == obj2; return r; })()", &v); + CHECK_SAME(v, JSVAL_TRUE); + return true; +} +END_TEST(testExtendedEq_bug530489) diff --git a/js/src/jsapi-tests/testFuncCallback.cpp b/js/src/jsapi-tests/testFuncCallback.cpp new file mode 100644 index 0000000..42fb458 --- /dev/null +++ b/js/src/jsapi-tests/testFuncCallback.cpp @@ -0,0 +1,138 @@ +#include "tests.h" +#include "jsfun.h" +#include "jscntxt.h" + +// For TRACING_ENABLED +#include "jstracer.h" + +#ifdef MOZ_TRACE_JSCALLS + +static int depth = 0; +static int enters = 0; +static int leaves = 0; +static int interpreted = 0; + +static void +funcTransition(const JSFunction *, + const JSScript *, + const JSContext *cx, + int entering) +{ + if (entering > 0) { + ++depth; + ++enters; + if (! JS_ON_TRACE(cx)) + ++interpreted; + } else { + --depth; + ++leaves; + } +} + +static JSBool called2 = false; + +static void +funcTransition2(const JSFunction *, const JSScript*, const JSContext*, int) +{ + called2 = true; +} + +static int overlays = 0; +static JSFunctionCallback innerCallback = NULL; +static void +funcTransitionOverlay(const JSFunction *fun, + const JSScript *script, + const JSContext *cx, + int entering) +{ + (*innerCallback)(fun, script, cx, entering); + overlays++; +} +#endif + +BEGIN_TEST(testFuncCallback_bug507012) +{ +#ifdef MOZ_TRACE_JSCALLS + // Call funcTransition() whenever a Javascript method is invoked + JS_SetFunctionCallback(cx, funcTransition); + + EXEC("x = 0; function f (n) { if (n > 1) { f(n - 1); } }"); + interpreted = enters = leaves = depth = 0; + + // Check whether JS_Execute() tracking works + EXEC("42"); + CHECK(enters == 1 && leaves == 1 && depth == 0); + interpreted = enters = leaves = depth = 0; + + // Check whether the basic function tracking works + EXEC("f(1)"); + CHECK(enters == 1+1 && leaves == 1+1 && depth == 0); + + // Can we switch to a different callback? + enters = 777; + JS_SetFunctionCallback(cx, funcTransition2); + EXEC("f(1)"); + CHECK(called2 && enters == 777); + + // Check whether we can turn off function tracing + JS_SetFunctionCallback(cx, NULL); + EXEC("f(1)"); + CHECK(enters == 777); + interpreted = enters = leaves = depth = 0; + + // Check nested invocations + JS_SetFunctionCallback(cx, funcTransition); + enters = leaves = depth = 0; + EXEC("f(3)"); + CHECK(enters == 1+3 && leaves == 1+3 && depth == 0); + interpreted = enters = leaves = depth = 0; + + // Check calls invoked while running on trace + EXEC("function g () { ++x; }"); + interpreted = enters = leaves = depth = 0; + EXEC("for (i = 0; i < 50; ++i) { g(); }"); + CHECK(enters == 1+50 && leaves == 1+50 && depth == 0); + + // If this fails, it means that the code was interpreted rather + // than trace-JITted, and so is not testing what it's supposed to + // be testing. Which doesn't necessarily imply that the + // functionality is broken. +#ifdef JS_TRACER + if (TRACING_ENABLED(cx)) + CHECK(interpreted < enters); +#endif + + // Test nesting callbacks via JS_GetFunctionCallback() + JS_SetFunctionCallback(cx, funcTransition); + innerCallback = JS_GetFunctionCallback(cx); + JS_SetFunctionCallback(cx, funcTransitionOverlay); + + EXEC("x = 0; function f (n) { if (n > 1) { f(n - 1); } }"); + interpreted = enters = leaves = depth = overlays = 0; + + EXEC("42.5"); + CHECK(enters == 1); + CHECK(leaves == 1); + CHECK(depth == 0); + CHECK(overlays == enters + leaves); + interpreted = enters = leaves = depth = overlays = 0; +#endif + + return true; +} + +// Not strictly necessary, but part of the test attempts to check +// whether these callbacks still trigger when traced, so force +// JSOPTION_JIT just to be sure. Once the method jit and tracing jit +// are integrated, this'll probably have to change (and we'll probably +// want to test in all modes.) +virtual +JSContext *createContext() +{ + JSContext *cx = JSAPITest::createContext(); + if (cx) + JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_JIT); + return cx; +} + +END_TEST(testFuncCallback_bug507012) diff --git a/js/src/jsapi-tests/testGCChunkAlloc.cpp b/js/src/jsapi-tests/testGCChunkAlloc.cpp new file mode 100644 index 0000000..a63af4b --- /dev/null +++ b/js/src/jsapi-tests/testGCChunkAlloc.cpp @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: Igor Bukanov + */ + +#include "tests.h" +#include "jsgcchunk.h" +#include "jscntxt.h" + +/* We allow to allocate only single chunk. */ + +class CustomGCChunkAllocator: public js::GCChunkAllocator { + public: + CustomGCChunkAllocator() : pool(NULL) {} + void *pool; + + private: + + virtual void *doAlloc() { + if (!pool) + return NULL; + void *chunk = pool; + pool = NULL; + return chunk; + } + + virtual void doFree(void *chunk) { + JS_ASSERT(!pool); + pool = chunk; + } +}; + +static CustomGCChunkAllocator customGCChunkAllocator; + +static unsigned errorCount = 0; + +static void +ErrorCounter(JSContext *cx, const char *message, JSErrorReport *report) +{ + ++errorCount; +} + +BEGIN_TEST(testGCChunkAlloc) +{ + JS_SetErrorReporter(cx, ErrorCounter); + + jsvalRoot root(cx); + + /* + * We loop until out-of-memory happens during the chunk allocation. But + * we have to disable the jit since it cannot tolerate OOM during the + * chunk allocation. + */ + JS_ToggleOptions(cx, JSOPTION_JIT); + + static const char source[] = + "var max = 0; (function() {" + " var array = [];" + " for (; ; ++max)" + " array.push({});" + "})();"; + JSBool ok = JS_EvaluateScript(cx, global, source, strlen(source), "", 1, + root.addr()); + + /* Check that we get OOM. */ + CHECK(!ok); + CHECK(!JS_IsExceptionPending(cx)); + CHECK(errorCount == 1); + CHECK(!customGCChunkAllocator.pool); + JS_GC(cx); + JS_ToggleOptions(cx, JSOPTION_JIT); + EVAL("(function() {" + " var array = [];" + " for (var i = max >> 1; i != 0;) {" + " --i;" + " array.push({});" + " }" + "})();", root.addr()); + CHECK(errorCount == 1); + return true; +} + +virtual JSRuntime * createRuntime() { + /* + * To test failure of chunk allocation allow to use GC twice the memory + * the single chunk contains. + */ + JSRuntime *rt = JS_NewRuntime(2 * js::GC_CHUNK_SIZE); + if (!rt) + return NULL; + + customGCChunkAllocator.pool = js::AllocGCChunk(); + JS_ASSERT(customGCChunkAllocator.pool); + + rt->setCustomGCChunkAllocator(&customGCChunkAllocator); + return rt; +} + +virtual void destroyRuntime() { + JS_DestroyRuntime(rt); + + /* We should get the initial chunk back at this point. */ + JS_ASSERT(customGCChunkAllocator.pool); + js::FreeGCChunk(customGCChunkAllocator.pool); + customGCChunkAllocator.pool = NULL; +} + +END_TEST(testGCChunkAlloc) diff --git a/js/src/jsapi-tests/testGetPropertyDefault.cpp b/js/src/jsapi-tests/testGetPropertyDefault.cpp new file mode 100644 index 0000000..5933b04 --- /dev/null +++ b/js/src/jsapi-tests/testGetPropertyDefault.cpp @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" + +#define JSVAL_IS_FALSE(x) ((JSVAL_IS_BOOLEAN(x)) && !(JSVAL_TO_BOOLEAN(x))) +#define JSVAL_IS_TRUE(x) ((JSVAL_IS_BOOLEAN(x)) && (JSVAL_TO_BOOLEAN(x))) + +static JSBool +stringToId(JSContext *cx, const char *s, jsid *idp) +{ + JSString *str = JS_NewStringCopyZ(cx, s); + if (!str) + return false; + + return JS_ValueToId(cx, STRING_TO_JSVAL(str), idp); +} + +BEGIN_TEST(testGetPropertyDefault_bug594060) +{ + { + // Check JS_GetPropertyDefault + + JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL); + CHECK(obj); + + jsval v0 = JSVAL_TRUE; + CHECK(JS_SetProperty(cx, obj, "here", &v0)); + + jsval v1; + CHECK(JS_GetPropertyDefault(cx, obj, "here", JSVAL_FALSE, &v1)); + CHECK(JSVAL_IS_TRUE(v1)); + + jsval v2; + CHECK(JS_GetPropertyDefault(cx, obj, "nothere", JSVAL_FALSE, &v2)); + CHECK(JSVAL_IS_FALSE(v2)); + } + + { + // Check JS_GetPropertyByIdDefault + + JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL); + CHECK(obj); + + jsid hereid; + CHECK(stringToId(cx, "here", &hereid)); + + jsid nothereid; + CHECK(stringToId(cx, "nothere", ¬hereid)); + + jsval v0 = JSVAL_TRUE; + CHECK(JS_SetPropertyById(cx, obj, hereid, &v0)); + + jsval v1; + CHECK(JS_GetPropertyByIdDefault(cx, obj, hereid, JSVAL_FALSE, &v1)); + CHECK(JSVAL_IS_TRUE(v1)); + + jsval v2; + CHECK(JS_GetPropertyByIdDefault(cx, obj, nothereid, JSVAL_FALSE, &v2)); + CHECK(JSVAL_IS_FALSE(v2)); + } + + return true; +} +END_TEST(testGetPropertyDefault_bug594060) diff --git a/js/src/jsapi-tests/testIntString.cpp b/js/src/jsapi-tests/testIntString.cpp new file mode 100644 index 0000000..c46c43f --- /dev/null +++ b/js/src/jsapi-tests/testIntString.cpp @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" +#include "jsstr.h" + +BEGIN_TEST(testIntString_bug515273) +{ + jsvalRoot v(cx); + + EVAL("'1';", v.addr()); + JSString *str = JSVAL_TO_STRING(v.value()); + CHECK(JSString::isStatic(str)); + CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "1")); + + EVAL("'42';", v.addr()); + str = JSVAL_TO_STRING(v.value()); + CHECK(JSString::isStatic(str)); + CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "42")); + + EVAL("'111';", v.addr()); + str = JSVAL_TO_STRING(v.value()); + CHECK(JSString::isStatic(str)); + CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "111")); + + /* Test other types of static strings. */ + EVAL("'a';", v.addr()); + str = JSVAL_TO_STRING(v.value()); + CHECK(JSString::isStatic(str)); + CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "a")); + + EVAL("'bc';", v.addr()); + str = JSVAL_TO_STRING(v.value()); + CHECK(JSString::isStatic(str)); + CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "bc")); + + return true; +} +END_TEST(testIntString_bug515273) diff --git a/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp b/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp new file mode 100644 index 0000000..4846277 --- /dev/null +++ b/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" +#include "jsstr.h" + +static JSGCCallback oldGCCallback; + +static void **checkPointers; +static jsuint checkPointersLength; +static size_t checkPointersStaticStrings; + +static JSBool +TestAboutToBeFinalizedCallback(JSContext *cx, JSGCStatus status) +{ + if (status == JSGC_MARK_END && checkPointers) { + for (jsuint i = 0; i != checkPointersLength; ++i) { + void *p = checkPointers[i]; + JS_ASSERT(p); + if (JS_IsAboutToBeFinalized(cx, p)) + checkPointers[i] = NULL; + } + } + + return !oldGCCallback || oldGCCallback(cx, status); +} + +/* + * NativeFrameCleaner write to sink so a compiler nwould not be able to optimze out + * the buffer memset there. + */ +volatile void *ptrSink; + +static JS_NEVER_INLINE void +NativeFrameCleaner() +{ + char buffer[1 << 16]; + memset(buffer, 0, sizeof buffer); + ptrSink = buffer; +} + +BEGIN_TEST(testIsAboutToBeFinalized_bug528645) +{ + /* + * Due to the conservative GC we use separated never-inline function to + * test rooted elements. + */ + CHECK(createAndTestRooted()); + NativeFrameCleaner(); + + JS_GC(cx); + + /* Everything is unrooted except unit strings. */ + for (jsuint i = 0; i != checkPointersLength; ++i) { + void *p = checkPointers[i]; + if (p) { + CHECK(JSString::isStatic(p)); + CHECK(checkPointersStaticStrings != 0); + --checkPointersStaticStrings; + } + } + CHECK(checkPointersStaticStrings == 0); + + free(checkPointers); + checkPointers = NULL; + JS_SetGCCallback(cx, oldGCCallback); + + return true; +} + +JS_NEVER_INLINE bool createAndTestRooted(); + +END_TEST(testIsAboutToBeFinalized_bug528645) + +JS_NEVER_INLINE bool +cls_testIsAboutToBeFinalized_bug528645::createAndTestRooted() +{ + jsvalRoot root(cx); + + /* + * Check various types of GC things against JS_IsAboutToBeFinalized. + * Make sure to include unit and numeric strings to the set. + */ + EVAL("var x = 1.1; " + "[''+x, 'a', '123456789', 'something'.substring(1), " + "{}, [], new Function('return 10;'), ];", + root.addr()); + + JSObject *array = JSVAL_TO_OBJECT(root.value()); + JS_ASSERT(JS_IsArrayObject(cx, array)); + + JSBool ok = JS_GetArrayLength(cx, array, &checkPointersLength); + CHECK(ok); + + checkPointers = (void **) malloc(sizeof(void *) * checkPointersLength); + CHECK(checkPointers); + + checkPointersStaticStrings = 0; + for (jsuint i = 0; i != checkPointersLength; ++i) { + jsval v; + ok = JS_GetElement(cx, array, i, &v); + CHECK(ok); + JS_ASSERT(JSVAL_IS_GCTHING(v)); + JS_ASSERT(!JSVAL_IS_NULL(v)); + checkPointers[i] = JSVAL_TO_GCTHING(v); + if (JSString::isStatic(checkPointers[i])) + ++checkPointersStaticStrings; + } + + oldGCCallback = JS_SetGCCallback(cx, TestAboutToBeFinalizedCallback); + JS_GC(cx); + + /* + * All GC things are rooted via the root holding the array containing them + * and TestAboutToBeFinalizedCallback must keep them as is. + */ + for (jsuint i = 0; i != checkPointersLength; ++i) + CHECK(checkPointers[i]); + + /* + * Overwrite the registers and stack with new GC things to avoid false + * positives with the finalization test. + */ + EVAL("[]", root.addr()); + + array = JSVAL_TO_OBJECT(root.value()); + JS_ASSERT(JS_IsArrayObject(cx, array)); + + jsuint tmp; + CHECK(JS_GetArrayLength(cx, array, &tmp)); + CHECK(ok); + + return true; +} + diff --git a/js/src/jsapi-tests/testLookup.cpp b/js/src/jsapi-tests/testLookup.cpp new file mode 100644 index 0000000..784ed8b --- /dev/null +++ b/js/src/jsapi-tests/testLookup.cpp @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" +#include "jsfun.h" // for js::IsInternalFunctionObject + +BEGIN_TEST(testLookup_bug522590) +{ + // Define a function that makes method-bearing objects. + jsvalRoot x(cx); + EXEC("function mkobj() { return {f: function () {return 2;}} }"); + + // Calling mkobj() multiple times must create multiple functions in ES5. + EVAL("mkobj().f !== mkobj().f", x.addr()); + CHECK_SAME(x, JSVAL_TRUE); + + // Now make x.f a method. + EVAL("mkobj()", x.addr()); + JSObject *xobj = JSVAL_TO_OBJECT(x); + + // This lookup must not return an internal function object. + jsvalRoot r(cx); + CHECK(JS_LookupProperty(cx, xobj, "f", r.addr())); + CHECK(JSVAL_IS_OBJECT(r)); + JSObject *funobj = JSVAL_TO_OBJECT(r); + CHECK(funobj->isFunction()); + CHECK(!js::IsInternalFunctionObject(funobj)); + CHECK(GET_FUNCTION_PRIVATE(cx, funobj) != (JSFunction *) funobj); + + return true; +} +END_TEST(testLookup_bug522590) + +JSBool +document_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) +{ + // If id is "all", and we're not detecting, resolve document.all=true. + jsvalRoot v(cx); + if (!JS_IdToValue(cx, id, v.addr())) + return false; + if (JSVAL_IS_STRING(v.value())) { + JSString *str = JSVAL_TO_STRING(v.value()); + JSFlatString *flatStr = JS_FlattenString(cx, str); + if (!flatStr) + return false; + if (JS_FlatStringEqualsAscii(flatStr, "all") && !(flags & JSRESOLVE_DETECTING)) { + JSBool ok = JS_DefinePropertyById(cx, obj, id, JSVAL_TRUE, NULL, NULL, 0); + *objp = ok ? obj : NULL; + return ok; + } + } + *objp = NULL; + return true; +} + +static JSClass document_class = { + "document", JSCLASS_NEW_RESOLVE, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, (JSResolveOp) document_resolve, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +BEGIN_TEST(testLookup_bug570195) +{ + JSObject *obj = JS_NewObject(cx, &document_class, NULL, NULL); + CHECK(obj); + CHECK(JS_DefineProperty(cx, global, "document", OBJECT_TO_JSVAL(obj), NULL, NULL, 0)); + jsvalRoot v(cx); + EVAL("document.all ? true : false", v.addr()); + CHECK_SAME(v.value(), JSVAL_FALSE); + EVAL("document.hasOwnProperty('all')", v.addr()); + CHECK_SAME(v.value(), JSVAL_FALSE); + return true; +} +END_TEST(testLookup_bug570195) diff --git a/js/src/jsapi-tests/testNewObject.cpp b/js/src/jsapi-tests/testNewObject.cpp new file mode 100644 index 0000000..7f289f0 --- /dev/null +++ b/js/src/jsapi-tests/testNewObject.cpp @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" + +const size_t N = 1000; +static jsval argv[N]; + +static JSBool +constructHook(JSContext *cx, uintN argc, jsval *vp) +{ + // Check that arguments were passed properly from JS_New. + JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); + + JSObject *obj = JS_NewObjectForConstructor(cx, vp); + if (!obj) { + JS_ReportError(cx, "test failed, could not construct object"); + return false; + } + if (strcmp(JS_GET_CLASS(cx, obj)->name, "Object") != 0) { + JS_ReportError(cx, "test failed, wrong class for 'this'"); + return false; + } + if (argc != 3) { + JS_ReportError(cx, "test failed, argc == %d", argc); + return false; + } + if (!JSVAL_IS_INT(argv[2]) || JSVAL_TO_INT(argv[2]) != 2) { + JS_ReportError(cx, "test failed, wrong value in argv[2]"); + return false; + } + if (!JS_IsConstructing(cx, vp)) { + JS_ReportError(cx, "test failed, not constructing"); + return false; + } + + // Perform a side-effect to indicate that this hook was actually called. + if (!JS_SetElement(cx, callee, 0, &argv[0])) + return false; + + *vp = OBJECT_TO_JSVAL(obj); + argv[0] = argv[1] = argv[2] = JSVAL_VOID; // trash the argv, perversely + return true; +} + +BEGIN_TEST(testNewObject_1) +{ + jsval v; + EVAL("Array", &v); + JSObject *Array = JSVAL_TO_OBJECT(v); + + // With no arguments. + JSObject *obj = JS_New(cx, Array, 0, NULL); + CHECK(obj); + jsvalRoot rt(cx, OBJECT_TO_JSVAL(obj)); + CHECK(JS_IsArrayObject(cx, obj)); + jsuint len; + CHECK(JS_GetArrayLength(cx, obj, &len)); + CHECK(len == 0); + + // With one argument. + argv[0] = INT_TO_JSVAL(4); + obj = JS_New(cx, Array, 1, argv); + CHECK(obj); + rt = OBJECT_TO_JSVAL(obj); + CHECK(JS_IsArrayObject(cx, obj)); + CHECK(JS_GetArrayLength(cx, obj, &len)); + CHECK(len == 4); + + // With N arguments. + for (size_t i = 0; i < N; i++) + argv[i] = INT_TO_JSVAL(i); + obj = JS_New(cx, Array, N, argv); + CHECK(obj); + rt = OBJECT_TO_JSVAL(obj); + CHECK(JS_IsArrayObject(cx, obj)); + CHECK(JS_GetArrayLength(cx, obj, &len)); + CHECK(len == N); + CHECK(JS_GetElement(cx, obj, N - 1, &v)); + CHECK_SAME(v, INT_TO_JSVAL(N - 1)); + + // With JSClass.construct. + static JSClass cls = { + "testNewObject_1", + 0, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + NULL, NULL, NULL, constructHook, NULL, NULL, NULL, NULL + }; + JSObject *ctor = JS_NewObject(cx, &cls, NULL, NULL); + CHECK(ctor); + jsvalRoot rt2(cx, OBJECT_TO_JSVAL(ctor)); + obj = JS_New(cx, ctor, 3, argv); + CHECK(obj); + CHECK(JS_GetElement(cx, ctor, 0, &v)); + CHECK_SAME(v, JSVAL_ZERO); + return true; +} +END_TEST(testNewObject_1) diff --git a/js/src/jsapi-tests/testOps.cpp b/js/src/jsapi-tests/testOps.cpp new file mode 100644 index 0000000..ac7e02d --- /dev/null +++ b/js/src/jsapi-tests/testOps.cpp @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * Tests for operators and implicit type conversion. + */ + +#include "tests.h" + +static JSBool +my_convert(JSContext* context, JSObject* obj, JSType type, jsval* rval) +{ + if (type == JSTYPE_VOID || type == JSTYPE_STRING || type == JSTYPE_NUMBER || type == JSTYPE_BOOLEAN) + return JS_NewNumberValue(context, 123, rval); + return JS_FALSE; +} + +static JSClass myClass = { + "MyClass", + 0, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, my_convert, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSBool +createMyObject(JSContext* context, uintN argc, jsval *vp) +{ + JS_BeginRequest(context); + + //JS_GC(context); //<- if we make GC here, all is ok + + JSObject* myObject = JS_NewObject(context, &myClass, NULL, NULL); + *vp = OBJECT_TO_JSVAL(myObject); + + JS_EndRequest(context); + + return JS_TRUE; +} + +static JSFunctionSpec s_functions[] = +{ + { "createMyObject", createMyObject, 0 }, + { 0,0,0,0 } +}; + +BEGIN_TEST(testOps_bug559006) +{ + CHECK(JS_DefineFunctions(cx, global, s_functions)); + + EXEC("function main() { while(1) return 0 + createMyObject(); }"); + + for (int i = 0; i < 9; i++) { + jsvalRoot rval(cx); + CHECK(JS_CallFunctionName(cx, global, "main", 0, NULL, rval.addr())); + CHECK_SAME(rval, INT_TO_JSVAL(123)); + } + return true; +} +END_TEST(testOps_bug559006) + diff --git a/js/src/jsapi-tests/testPropCache.cpp b/js/src/jsapi-tests/testPropCache.cpp new file mode 100644 index 0000000..37026e9 --- /dev/null +++ b/js/src/jsapi-tests/testPropCache.cpp @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" + +static int g_counter; + +static JSBool +CounterAdd(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + g_counter++; + return JS_TRUE; +} + +static JSClass CounterClass = { + "Counter", /* name */ + 0, /* flags */ + CounterAdd, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +BEGIN_TEST(testPropCache_bug505798) +{ + g_counter = 0; + EXEC("var x = {};"); + CHECK(JS_DefineObject(cx, global, "y", &CounterClass, NULL, JSPROP_ENUMERATE)); + EXEC("var arr = [x, y];\n" + "for (var i = 0; i < arr.length; i++)\n" + " arr[i].p = 1;\n"); + CHECK(g_counter == 1); + return true; +} +END_TEST(testPropCache_bug505798) diff --git a/js/src/jsapi-tests/testSameValue.cpp b/js/src/jsapi-tests/testSameValue.cpp new file mode 100644 index 0000000..2209674 --- /dev/null +++ b/js/src/jsapi-tests/testSameValue.cpp @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" + +BEGIN_TEST(testSameValue) +{ + + /* + * NB: passing a double that fits in an integer jsval is API misuse. As a + * matter of defense in depth, however, JS_SameValue should return the + * correct result comparing a positive-zero double to a negative-zero + * double, and this is believed to be the only way to make such a + * comparison possible. + */ + jsval v1 = DOUBLE_TO_JSVAL(0.0); + jsval v2 = DOUBLE_TO_JSVAL(-0.0); + JSBool same; + CHECK(JS_SameValue(cx, v1, v2, &same)); + CHECK(!same); + return true; +} +END_TEST(testSameValue) diff --git a/js/src/jsapi-tests/testScriptObject.cpp b/js/src/jsapi-tests/testScriptObject.cpp new file mode 100644 index 0000000..13ed975 --- /dev/null +++ b/js/src/jsapi-tests/testScriptObject.cpp @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" + +struct ScriptObjectFixture : public JSAPITest { + static const int code_size; + static const char code[]; + static jschar uc_code[]; + + ScriptObjectFixture() + { + for (int i = 0; i < code_size; i++) + uc_code[i] = code[i]; + } + + bool tryScript(JSObject *scriptObj) + { + CHECK(scriptObj); + + JS_GC(cx); + + /* After a garbage collection, the script should still work. */ + jsval result; + CHECK(JS_ExecuteScript(cx, global, scriptObj, &result)); + + return true; + } +}; + +const char ScriptObjectFixture::code[] = + "(function(a, b){return a+' '+b;}('hello', 'world'))"; +const int ScriptObjectFixture::code_size = sizeof(ScriptObjectFixture::code) - 1; +jschar ScriptObjectFixture::uc_code[ScriptObjectFixture::code_size]; + +BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript) +{ + return tryScript(JS_CompileScript(cx, global, code, code_size, + __FILE__, __LINE__)); +} +END_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript) + +BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript_empty) +{ + return tryScript(JS_CompileScript(cx, global, "", 0, + __FILE__, __LINE__)); +} +END_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript_empty) + +BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScriptForPrincipals) +{ + return tryScript(JS_CompileScriptForPrincipals(cx, global, NULL, + code, code_size, + __FILE__, __LINE__)); +} +END_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScriptForPrincipals) + +BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript) +{ + return tryScript(JS_CompileUCScript(cx, global, + uc_code, code_size, + __FILE__, __LINE__)); +} +END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript) + +BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript_empty) +{ + return tryScript(JS_CompileUCScript(cx, global, + uc_code, 0, + __FILE__, __LINE__)); +} +END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript_empty) + +BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScriptForPrincipals) +{ + return tryScript(JS_CompileUCScriptForPrincipals(cx, global, NULL, + uc_code, code_size, + __FILE__, __LINE__)); +} +END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScriptForPrincipals) + +BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFile) +{ + TempFile tempScript; + static const char script_filename[] = "temp-bug438633_JS_CompileFile"; + FILE *script_stream = tempScript.open(script_filename); + CHECK(fputs(code, script_stream) != EOF); + tempScript.close(); + JSObject *scriptObj = JS_CompileFile(cx, global, script_filename); + tempScript.remove(); + return tryScript(scriptObj); +} +END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFile) + +BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFile_empty) +{ + TempFile tempScript; + static const char script_filename[] = "temp-bug438633_JS_CompileFile_empty"; + tempScript.open(script_filename); + tempScript.close(); + JSObject *scriptObj = JS_CompileFile(cx, global, script_filename); + tempScript.remove(); + return tryScript(scriptObj); +} +END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFile_empty) + +BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandle) +{ + TempFile tempScript; + FILE *script_stream = tempScript.open("temp-bug438633_JS_CompileFileHandle"); + CHECK(fputs(code, script_stream) != EOF); + CHECK(fseek(script_stream, 0, SEEK_SET) != EOF); + return tryScript(JS_CompileFileHandle(cx, global, "temporary file", + script_stream)); +} +END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandle) + +BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandle_empty) +{ + TempFile tempScript; + FILE *script_stream = tempScript.open("temp-bug438633_JS_CompileFileHandle_empty"); + return tryScript(JS_CompileFileHandle(cx, global, "empty temporary file", + script_stream)); +} +END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandle_empty) + +BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandleForPrincipals) +{ + TempFile tempScript; + FILE *script_stream = tempScript.open("temp-bug438633_JS_CompileFileHandleForPrincipals"); + CHECK(fputs(code, script_stream) != EOF); + CHECK(fseek(script_stream, 0, SEEK_SET) != EOF); + return tryScript(JS_CompileFileHandleForPrincipals(cx, global, + "temporary file", + script_stream, NULL)); +} +END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandleForPrincipals) diff --git a/js/src/jsapi-tests/testSetProperty.cpp b/js/src/jsapi-tests/testSetProperty.cpp new file mode 100644 index 0000000..7b242dd --- /dev/null +++ b/js/src/jsapi-tests/testSetProperty.cpp @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" +#include "jsxdrapi.h" + +static JSBool +nativeGet(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + *vp = INT_TO_JSVAL(17); + return JS_TRUE; +} + +BEGIN_TEST(testSetProperty_NativeGetterStubSetter) +{ + jsvalRoot vobj(cx); + JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL); + CHECK(obj); + vobj = OBJECT_TO_JSVAL(obj); + + CHECK(JS_DefineProperty(cx, global, "globalProp", vobj, + JS_PropertyStub, JS_StrictPropertyStub, + JSPROP_ENUMERATE)); + + CHECK(JS_DefineProperty(cx, obj, "prop", JSVAL_VOID, + nativeGet, JS_StrictPropertyStub, + JSPROP_SHARED)); + + EXEC("'use strict'; \n" + "var error, passed = false; \n" + "try \n" + "{ \n" + " this.globalProp.prop = 42; \n" + " throw new Error('setting property succeeded!'); \n" + "} \n" + "catch (e) \n" + "{ \n" + " error = e; \n" + " if (e instanceof TypeError) \n" + " passed = true; \n" + "} \n" + " \n" + "if (!passed) \n" + " throw error; \n"); + + EXEC("var error, passed = false; \n" + "try \n" + "{ \n" + " this.globalProp.prop = 42; \n" + " if (this.globalProp.prop === 17) \n" + " passed = true; \n" + " else \n" + " throw new Error('bad value after set!'); \n" + "} \n" + "catch (e) \n" + "{ \n" + " error = e; \n" + "} \n" + " \n" + "if (!passed) \n" + " throw error; \n"); + + return true; +} +END_TEST(testSetProperty_NativeGetterStubSetter) + +BEGIN_TEST(testSetProperty_InheritedGlobalSetter) +{ + // This is a JSAPI test because jsapi-test globals do not have a resolve + // hook and therefore can use the property cache in some cases where the + // shell can't. + JS_ASSERT(JS_GET_CLASS(cx, global)->resolve == &JS_ResolveStub); + + CHECK(JS_DefineProperty(cx, global, "HOTLOOP", INT_TO_JSVAL(8), NULL, NULL, 0)); + EXEC("var n = 0;\n" + "var global = this;\n" + "function f() { n++; }\n" + "Object.defineProperty(Object.prototype, 'x', {set: f});\n" + "for (var i = 0; i < HOTLOOP; i++)\n" + " global.x = i;\n"); + EXEC("if (n != HOTLOOP)\n" + " throw 'FAIL';\n"); + return true; +} +END_TEST(testSetProperty_InheritedGlobalSetter) + diff --git a/js/src/jsapi-tests/testThreadGC.cpp b/js/src/jsapi-tests/testThreadGC.cpp new file mode 100644 index 0000000..fadbf97 --- /dev/null +++ b/js/src/jsapi-tests/testThreadGC.cpp @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#ifdef JS_THREADSAFE + +#include "tests.h" +#include "prthread.h" + +#include "jscntxt.h" + +/* + * We test that if a GC callback cancels the GC on a child thread the GC can + * still proceed on the main thread even if the child thread continue to + * run uninterrupted. + */ + +struct SharedData { + enum ChildState { + CHILD_STARTING, + CHILD_RUNNING, + CHILD_DONE, + CHILD_ERROR + }; + + JSRuntime *const runtime; + PRThread *const mainThread; + PRLock *const lock; + PRCondVar *const signal; + ChildState childState; + bool childShouldStop; + JSContext *childContext; + + SharedData(JSRuntime *rt, bool *ok) + : runtime(rt), + mainThread(PR_GetCurrentThread()), + lock(PR_NewLock()), + signal(lock ? PR_NewCondVar(lock) : NULL), + childState(CHILD_STARTING), + childShouldStop(false), + childContext(NULL) + { + JS_ASSERT(!*ok); + *ok = !!signal; + } + + ~SharedData() { + if (signal) + PR_DestroyCondVar(signal); + if (lock) + PR_DestroyLock(lock); + } +}; + +static SharedData *shared; + +static JSBool +CancelNonMainThreadGCCallback(JSContext *cx, JSGCStatus status) +{ + return status != JSGC_BEGIN || PR_GetCurrentThread() == shared->mainThread; +} + +static JSBool +StopChildOperationCallback(JSContext *cx) +{ + bool shouldStop; + PR_Lock(shared->lock); + shouldStop = shared->childShouldStop; + PR_Unlock(shared->lock); + return !shouldStop; +} + +static JSBool +NotifyMainThreadAboutBusyLoop(JSContext *cx, uintN argc, jsval *vp) +{ + PR_Lock(shared->lock); + JS_ASSERT(shared->childState == SharedData::CHILD_STARTING); + shared->childState = SharedData::CHILD_RUNNING; + shared->childContext = cx; + PR_NotifyCondVar(shared->signal); + PR_Unlock(shared->lock); + + return true; +} + +static void +ChildThreadMain(void *arg) +{ + JS_ASSERT(!arg); + bool error = true; + JSContext *cx = JS_NewContext(shared->runtime, 8192); + if (cx) { + JS_SetOperationCallback(cx, StopChildOperationCallback); + JSAutoRequest ar(cx); + JSObject *global = JS_NewCompartmentAndGlobalObject(cx, JSAPITest::basicGlobalClass(), + NULL); + if (global) { + JS_SetGlobalObject(cx, global); + if (JS_InitStandardClasses(cx, global) && + JS_DefineFunction(cx, global, "notify", NotifyMainThreadAboutBusyLoop, 0, 0)) { + + jsval rval; + static const char code[] = "var i = 0; notify(); for (var i = 0; ; ++i);"; + JSBool ok = JS_EvaluateScript(cx, global, code, strlen(code), + __FILE__, __LINE__, &rval); + if (!ok && !JS_IsExceptionPending(cx)) { + /* Evaluate should only return via the callback cancellation. */ + error = false; + } + } + } + } + + PR_Lock(shared->lock); + shared->childState = error ? SharedData::CHILD_DONE : SharedData::CHILD_ERROR; + shared->childContext = NULL; + PR_NotifyCondVar(shared->signal); + PR_Unlock(shared->lock); + + if (cx) + JS_DestroyContextNoGC(cx); +} + +BEGIN_TEST(testThreadGC_bug590533) + { + /* + * Test the child thread busy running while the current thread calls + * the GC both with JSRuntime->gcIsNeeded set and unset. + */ + bool ok = TestChildThread(true); + CHECK(ok); + ok = TestChildThread(false); + CHECK(ok); + return ok; + } + + bool TestChildThread(bool setGCIsNeeded) + { + bool ok = false; + shared = new SharedData(rt, &ok); + CHECK(ok); + + JSGCCallback oldGCCallback = JS_SetGCCallback(cx, CancelNonMainThreadGCCallback); + + PRThread *thread = + PR_CreateThread(PR_USER_THREAD, ChildThreadMain, NULL, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + if (!thread) + return false; + + PR_Lock(shared->lock); + while (shared->childState == SharedData::CHILD_STARTING) + PR_WaitCondVar(shared->signal, PR_INTERVAL_NO_TIMEOUT); + JS_ASSERT(shared->childState != SharedData::CHILD_DONE); + ok = (shared->childState == SharedData::CHILD_RUNNING); + PR_Unlock(shared->lock); + + CHECK(ok); + + if (setGCIsNeeded) { + /* + * Use JS internal API to set the GC trigger flag after we know + * that the child is in a request and is about to run an infinite + * loop. Then run the GC with JSRuntime->gcIsNeeded flag set. + */ + js::AutoLockGC lock(rt); + js::TriggerGC(rt); + } + + JS_GC(cx); + + PR_Lock(shared->lock); + shared->childShouldStop = true; + while (shared->childState == SharedData::CHILD_RUNNING) { + JS_TriggerOperationCallback(shared->childContext); + PR_WaitCondVar(shared->signal, PR_INTERVAL_NO_TIMEOUT); + } + JS_ASSERT(shared->childState != SharedData::CHILD_STARTING); + ok = (shared->childState == SharedData::CHILD_DONE); + PR_Unlock(shared->lock); + + JS_SetGCCallback(cx, oldGCCallback); + + PR_JoinThread(thread); + + delete shared; + shared = NULL; + + return true; + } + + +END_TEST(testThreadGC_bug590533) + +#endif diff --git a/js/src/jsapi-tests/testThreads.cpp b/js/src/jsapi-tests/testThreads.cpp new file mode 100644 index 0000000..c6ab694 --- /dev/null +++ b/js/src/jsapi-tests/testThreads.cpp @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#ifdef JS_THREADSAFE + +#include "tests.h" +#include "prthread.h" + +struct ThreadData { + JSRuntime *rt; + JSObject *obj; + const char *code; + bool ok; +}; + +BEGIN_TEST(testThreads_bug561444) + { + const char *code = ".b.@c = '';"; + EXEC(code); + + jsrefcount rc = JS_SuspendRequest(cx); + { + ThreadData data = {rt, global, code, false}; + PRThread *thread = + PR_CreateThread(PR_USER_THREAD, threadMain, &data, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + CHECK(thread); + PR_JoinThread(thread); + CHECK(data.ok); + } + JS_ResumeRequest(cx, rc); + return true; + } + + static void threadMain(void *arg) { + ThreadData *d = (ThreadData *) arg; + + JSContext *cx = JS_NewContext(d->rt, 8192); + if (!cx) + return; + JS_BeginRequest(cx); + { + JSAutoEnterCompartment ac; + jsval v; + d->ok = ac.enter(cx, d->obj) && + JS_EvaluateScript(cx, d->obj, d->code, strlen(d->code), __FILE__, __LINE__, + &v); + } + JS_DestroyContext(cx); + } +END_TEST(testThreads_bug561444) + +const PRUint32 NATIVE_STACK_SIZE = 64 * 1024; +const PRUint32 NATIVE_STACK_HEADROOM = 8 * 1024; + +template +class Repeat { + size_t n; + const T &t; + + public: + Repeat(size_t n, const T &t) : n(n), t(t) {} + + bool operator()() const { + for (size_t i = 0; i < n; i++) + if (!t()) + return false; + return true; + } +}; + +template Repeat repeat(size_t n, const T &t) { return Repeat(n, t); } + +/* Class of callable that does something in n parallel threads. */ +template +class Parallel { + size_t n; + const T &t; + + struct pair { const Parallel *self; bool ok; }; + + static void threadMain(void *arg) { + pair *p = (pair *) arg; + if (!p->self->t()) + p->ok = false; + } + + public: + Parallel(size_t n, const T &t) : n(n), t(t) {} + + bool operator()() const { + pair p = {this, true}; + + PRThread **thread = new PRThread *[n]; + if (!thread) + return false; + + size_t i; + for (i = 0; i < n; i++) { + thread[i] = PR_CreateThread(PR_USER_THREAD, threadMain, &p, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, NATIVE_STACK_SIZE); + if (thread[i] == NULL) { + p.ok = false; + break; + } + } + while (i--) + PR_JoinThread(thread[i]); + + delete[] thread; + return p.ok; + } +}; + +template Parallel parallel(size_t n, const T &t) { return Parallel(n, t); } + +/* Class of callable that creates a compartment and runs some code in it. */ +class eval { + JSRuntime *rt; + const char *code; + + public: + eval(JSRuntime *rt, const char *code) : rt(rt), code(code) {} + + bool operator()() const { + JSContext *cx = JS_NewContext(rt, 8192); + if (!cx) + return false; + + JS_SetNativeStackQuota(cx, NATIVE_STACK_SIZE - NATIVE_STACK_HEADROOM); + bool ok = false; + { + JSAutoRequest ar(cx); + JSObject *global = + JS_NewCompartmentAndGlobalObject(cx, JSAPITest::basicGlobalClass(), NULL); + if (global) { + JS_SetGlobalObject(cx, global); + jsval rval; + ok = JS_InitStandardClasses(cx, global) && + JS_EvaluateScript(cx, global, code, strlen(code), "", 0, &rval); + } + } + JS_DestroyContextMaybeGC(cx); + return ok; + } +}; + +BEGIN_TEST(testThreads_bug604782) +{ + jsrefcount rc = JS_SuspendRequest(cx); + bool ok = repeat(20, parallel(3, eval(rt, "for(i=0;i<1000;i++);")))(); + JS_ResumeRequest(cx, rc); + CHECK(ok); + return true; +} +END_TEST(testThreads_bug604782) + +BEGIN_TEST(testThreads_bug609103) +{ + const char *code = + "var x = {};\n" + "for (var i = 0; i < 10000; i++)\n" + " x = {next: x};\n"; + + jsrefcount rc = JS_SuspendRequest(cx); + bool ok = parallel(2, eval(rt, code))(); + JS_ResumeRequest(cx, rc); + CHECK(ok); + return true; +} +END_TEST(testThreads_bug609103) + +#endif diff --git a/js/src/jsapi-tests/testTrap.cpp b/js/src/jsapi-tests/testTrap.cpp new file mode 100644 index 0000000..6368dd2 --- /dev/null +++ b/js/src/jsapi-tests/testTrap.cpp @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" +#include "jsdbgapi.h" + +static int emptyTrapCallCount = 0; + +static JSTrapStatus +EmptyTrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, + jsval closure) +{ + JS_GC(cx); + if (JSVAL_IS_STRING(closure)) + ++emptyTrapCallCount; + return JSTRAP_CONTINUE; +} + +BEGIN_TEST(testTrap_gc) +{ + static const char source[] = +"var i = 0;\n" +"var sum = 0;\n" +"while (i < 10) {\n" +" sum += i;\n" +" ++i;\n" +"}\n" +"({ result: sum });\n" + ; + + // compile + JSObject *scriptObj = JS_CompileScript(cx, global, source, strlen(source), __FILE__, 1); + CHECK(scriptObj); + + // execute + jsvalRoot v2(cx); + CHECK(JS_ExecuteScript(cx, global, scriptObj, v2.addr())); + CHECK(JSVAL_IS_OBJECT(v2)); + CHECK(emptyTrapCallCount == 0); + + // Disable JIT for debugging + JS_SetOptions(cx, JS_GetOptions(cx) & ~JSOPTION_JIT); + + // Enable debug mode + CHECK(JS_SetDebugMode(cx, JS_TRUE)); + + static const char trapClosureText[] = "some trap closure"; + + // scope JSScript usage to make sure that it is not used after + // JS_ExecuteScript. This way we avoid using Anchor. + JSString *trapClosure; + { + JSScript *script = JS_GetScriptFromObject(scriptObj); + jsbytecode *line2 = JS_LineNumberToPC(cx, script, 1); + CHECK(line2); + + jsbytecode *line6 = JS_LineNumberToPC(cx, script, 5); + CHECK(line2); + + trapClosure = JS_NewStringCopyZ(cx, trapClosureText); + CHECK(trapClosure); + JS_SetTrap(cx, script, line2, EmptyTrapHandler, STRING_TO_JSVAL(trapClosure)); + JS_SetTrap(cx, script, line6, EmptyTrapHandler, STRING_TO_JSVAL(trapClosure)); + + JS_GC(cx); + + CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(trapClosure), trapClosureText)); + } + + // execute + CHECK(JS_ExecuteScript(cx, global, scriptObj, v2.addr())); + CHECK(emptyTrapCallCount == 11); + + JS_GC(cx); + + CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(trapClosure), trapClosureText)); + + return true; +} +END_TEST(testTrap_gc) + diff --git a/js/src/jsapi-tests/testUTF8.cpp b/js/src/jsapi-tests/testUTF8.cpp new file mode 100644 index 0000000..fdbe5e9 --- /dev/null +++ b/js/src/jsapi-tests/testUTF8.cpp @@ -0,0 +1,21 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" + +BEGIN_TEST(testUTF8_bug589917) +{ + const jschar surrogate_pair[] = { 0xd800, 0xdc00 }; + char output_buffer[10]; + size_t utf8_len = sizeof(output_buffer); + + CHECK(JS_EncodeCharacters(cx, surrogate_pair, 2, output_buffer, &utf8_len)); + CHECK(utf8_len == 4); + + CHECK(JS_EncodeCharacters(cx, surrogate_pair, 2, NULL, &utf8_len)); + CHECK(utf8_len == 4); + + return true; +} +END_TEST(testUTF8_bug589917) diff --git a/js/src/jsapi-tests/testVersion.cpp b/js/src/jsapi-tests/testVersion.cpp new file mode 100644 index 0000000..41eb0f6 --- /dev/null +++ b/js/src/jsapi-tests/testVersion.cpp @@ -0,0 +1,264 @@ +#include "tests.h" +#include "jsscript.h" +#include "jscntxt.h" + +using namespace js; + +struct VersionFixture; + +/* + * Fast-native callbacks for use from JS. + * They set their results on the current fixture instance. + */ + +static VersionFixture *callbackData = NULL; + +JSBool CheckVersionHasXML(JSContext *cx, uintN argc, jsval *vp); +JSBool DisableXMLOption(JSContext *cx, uintN argc, jsval *vp); +JSBool CallSetVersion17(JSContext *cx, uintN argc, jsval *vp); +JSBool CheckNewScriptNoXML(JSContext *cx, uintN argc, jsval *vp); +JSBool OverrideVersion15(JSContext *cx, uintN argc, jsval *vp); +JSBool CaptureVersion(JSContext *cx, uintN argc, jsval *vp); +JSBool CheckOverride(JSContext *cx, uintN argc, jsval *vp); +JSBool EvalScriptVersion16(JSContext *cx, uintN argc, jsval *vp); + +struct VersionFixture : public JSAPITest +{ + JSVersion captured; + + virtual bool init() { + JSAPITest::init(); + callbackData = this; + captured = JSVERSION_UNKNOWN; + return JS_DefineFunction(cx, global, "checkVersionHasXML", CheckVersionHasXML, 0, 0) && + JS_DefineFunction(cx, global, "disableXMLOption", DisableXMLOption, 0, 0) && + JS_DefineFunction(cx, global, "callSetVersion17", CallSetVersion17, 0, 0) && + JS_DefineFunction(cx, global, "checkNewScriptNoXML", CheckNewScriptNoXML, 0, 0) && + JS_DefineFunction(cx, global, "overrideVersion15", OverrideVersion15, 0, 0) && + JS_DefineFunction(cx, global, "captureVersion", CaptureVersion, 0, 0) && + JS_DefineFunction(cx, global, "checkOverride", CheckOverride, 1, 0) && + JS_DefineFunction(cx, global, "evalScriptVersion16", + EvalScriptVersion16, 0, 0); + } + + JSObject *fakeScript(const char *contents, size_t length) { + return JS_CompileScript(cx, global, contents, length, "", 1); + } + + bool hasXML(uintN version) { + return VersionHasXML(JSVersion(version)); + } + + bool hasXML(JSScript *script) { + return hasXML(script->getVersion()); + } + + bool hasXML() { + return OptionsHasXML(JS_GetOptions(cx)); + } + + bool checkOptionsHasNoXML() { + CHECK(!OptionsHasXML(JS_GetOptions(cx))); + return true; + } + + bool disableXMLOption() { + JS_SetOptions(cx, JS_GetOptions(cx) & ~JSOPTION_XML); + return true; + } + + bool checkVersionIsOverridden() { + CHECK(cx->isVersionOverridden()); + return true; + } + + /* Check that script compilation results in a version without XML. */ + bool checkNewScriptNoXML() { + JSObject *scriptObj = fakeScript("", 0); + CHECK(scriptObj); + CHECK(!hasXML(JS_GetScriptFromObject(scriptObj)->getVersion())); + return true; + } + + bool checkVersionHasXML() { + CHECK(VersionHasXML(cx->findVersion())); + return true; + } + + bool setVersion(JSVersion version) { + CHECK(JS_GetVersion(cx) != version); + JS_SetVersion(cx, version); + return true; + } + + bool evalVersion(const jschar *chars, size_t len, JSVersion version) { + CHECK(JS_GetVersion(cx) != version); + jsval rval; + CHECK(JS_EvaluateUCScriptForPrincipalsVersion( + cx, global, NULL, chars, len, "", 0, &rval, version)); + return true; + } + + bool toggleXML(bool shouldEnable) { + CHECK(hasXML() == !shouldEnable); + JS_ToggleOptions(cx, JSOPTION_XML); + CHECK(hasXML() == shouldEnable); + return true; + } + + bool disableXML() { + return toggleXML(false); + } + + bool enableXML() { + return toggleXML(true); + } +}; + +/* Callbacks to throw into JS-land. */ + +JSBool +CallSetVersion17(JSContext *cx, uintN argc, jsval *vp) +{ + return callbackData->setVersion(JSVERSION_1_7); +} + +JSBool +CheckVersionHasXML(JSContext *cx, uintN argc, jsval *vp) +{ + return callbackData->checkVersionHasXML(); +} + +JSBool +DisableXMLOption(JSContext *cx, uintN argc, jsval *vp) +{ + return callbackData->disableXMLOption(); +} + +JSBool +CheckNewScriptNoXML(JSContext *cx, uintN argc, jsval *vp) +{ + return callbackData->checkNewScriptNoXML(); +} + +JSBool +OverrideVersion15(JSContext *cx, uintN argc, jsval *vp) +{ + if (!callbackData->setVersion(JSVERSION_1_5)) + return false; + return callbackData->checkVersionIsOverridden(); +} + +JSBool +EvalScriptVersion16(JSContext *cx, uintN argc, jsval *vp) +{ + JS_ASSERT(argc == 1); + jsval *argv = JS_ARGV(cx, vp); + JS_ASSERT(JSVAL_IS_STRING(argv[0])); + JSString *str = JSVAL_TO_STRING(argv[0]); + const jschar *chars = str->getChars(cx); + JS_ASSERT(chars); + size_t len = str->length(); + return callbackData->evalVersion(chars, len, JSVERSION_1_6); +} + +JSBool +CaptureVersion(JSContext *cx, uintN argc, jsval *vp) +{ + callbackData->captured = JS_GetVersion(cx); + return true; +} + +JSBool +CheckOverride(JSContext *cx, uintN argc, jsval *vp) +{ + JS_ASSERT(argc == 1); + jsval *argv = JS_ARGV(cx, vp); + JS_ASSERT(JSVAL_IS_BOOLEAN(argv[0])); + bool shouldHaveOverride = !!JSVAL_TO_BOOLEAN(argv[0]); + return shouldHaveOverride == cx->isVersionOverridden(); +} + +/* + * See bug 611462. We are checking that the XML option setting from a JSAPI + * call is propagated to newly compiled scripts, instead of inheriting the XML + * setting from a script on the stack. + */ +BEGIN_FIXTURE_TEST(VersionFixture, testOptionsAreUsedForVersionFlags) +{ + callbackData = this; + + /* Enable XML and compile a script to activate. */ + enableXML(); + const char toActivateChars[] = + "checkVersionHasXML();" + "disableXMLOption();" + "callSetVersion17();" + "checkNewScriptNoXML();"; + JSObject *toActivate = fakeScript(toActivateChars, sizeof(toActivateChars) - 1); + CHECK(toActivate); + CHECK(hasXML(JS_GetScriptFromObject(toActivate))); + + disableXML(); + + /* Activate the script. */ + jsval dummy; + CHECK(JS_ExecuteScript(cx, global, toActivate, &dummy)); + return true; +} +END_FIXTURE_TEST(VersionFixture, testOptionsAreUsedForVersionFlags) + +/* + * When re-entering the virtual machine through a *Version API the version + * is no longer forced -- it continues with its natural push/pop oriented + * version progression. This is maintained by the |AutoVersionAPI| class in + * jsapi.cpp. + */ +BEGIN_FIXTURE_TEST(VersionFixture, testEntryLosesOverride) +{ + EXEC("overrideVersion15(); evalScriptVersion16('checkOverride(false); captureVersion()');"); + CHECK(captured == JSVERSION_1_6); + + /* + * Override gets propagated to default version as non-override when you leave the VM's execute + * call. + */ + CHECK(JS_GetVersion(cx) == JSVERSION_1_5); + CHECK(!cx->isVersionOverridden()); + return true; +} +END_FIXTURE_TEST(VersionFixture, testEntryLosesOverride) + +/* + * EvalScriptVersion does not propagate overrides to its caller, it + * restores things exactly as they were before the call. This is as opposed to + * the normal (no Version suffix) API which propagates overrides + * to the caller. + */ +BEGIN_FIXTURE_TEST(VersionFixture, testReturnLosesOverride) +{ + CHECK(JS_GetVersion(cx) == JSVERSION_ECMA_5); + EXEC( + "checkOverride(false);" + "evalScriptVersion16('overrideVersion15();');" + "checkOverride(false);" + "captureVersion();" + ); + CHECK(captured == JSVERSION_ECMA_5); + return true; +} +END_FIXTURE_TEST(VersionFixture, testReturnLosesOverride) + +BEGIN_FIXTURE_TEST(VersionFixture, testEvalPropagatesOverride) +{ + CHECK(JS_GetVersion(cx) == JSVERSION_ECMA_5); + EXEC( + "checkOverride(false);" + "eval('overrideVersion15();');" + "checkOverride(true);" + "captureVersion();" + ); + CHECK(captured == JSVERSION_1_5); + return true; +} +END_FIXTURE_TEST(VersionFixture, testEvalPropagatesOverride) diff --git a/js/src/jsapi-tests/testXDR.cpp b/js/src/jsapi-tests/testXDR.cpp new file mode 100644 index 0000000..5921b2a --- /dev/null +++ b/js/src/jsapi-tests/testXDR.cpp @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + */ + +#include "tests.h" +#include "jsscript.h" +#include "jsxdrapi.h" + +BEGIN_TEST(testXDR_bug506491) +{ + const char *s = + "function makeClosure(s, name, value) {\n" + " eval(s);\n" + " return let (n = name, v = value) function () { return String(v); };\n" + "}\n" + "var f = makeClosure('0;', 'status', 'ok');\n"; + + // compile + JSObject *scriptObj = JS_CompileScript(cx, global, s, strlen(s), __FILE__, __LINE__); + CHECK(scriptObj); + + // freeze + JSXDRState *w = JS_XDRNewMem(cx, JSXDR_ENCODE); + CHECK(w); + CHECK(JS_XDRScriptObject(w, &scriptObj)); + uint32 nbytes; + void *p = JS_XDRMemGetData(w, &nbytes); + CHECK(p); + void *frozen = JS_malloc(cx, nbytes); + CHECK(frozen); + memcpy(frozen, p, nbytes); + JS_XDRDestroy(w); + + // thaw + scriptObj = NULL; + JSXDRState *r = JS_XDRNewMem(cx, JSXDR_DECODE); + JS_XDRMemSetData(r, frozen, nbytes); + CHECK(JS_XDRScriptObject(r, &scriptObj)); + JS_XDRDestroy(r); // this frees `frozen` + + // execute + jsvalRoot v2(cx); + CHECK(JS_ExecuteScript(cx, global, scriptObj, v2.addr())); + + // try to break the Block object that is the parent of f + JS_GC(cx); + + // confirm + EVAL("f() === 'ok';\n", v2.addr()); + jsvalRoot trueval(cx, JSVAL_TRUE); + CHECK_SAME(v2, trueval); + return true; +} +END_TEST(testXDR_bug506491) + +BEGIN_TEST(testXDR_bug516827) +{ + // compile an empty script + JSObject *scriptObj = JS_CompileScript(cx, global, "", 0, __FILE__, __LINE__); + CHECK(scriptObj); + + // freeze + JSXDRState *w = JS_XDRNewMem(cx, JSXDR_ENCODE); + CHECK(w); + CHECK(JS_XDRScriptObject(w, &scriptObj)); + uint32 nbytes; + void *p = JS_XDRMemGetData(w, &nbytes); + CHECK(p); + void *frozen = JS_malloc(cx, nbytes); + CHECK(frozen); + memcpy(frozen, p, nbytes); + JS_XDRDestroy(w); + + // thaw + scriptObj = NULL; + JSXDRState *r = JS_XDRNewMem(cx, JSXDR_DECODE); + JS_XDRMemSetData(r, frozen, nbytes); + CHECK(JS_XDRScriptObject(r, &scriptObj)); + JS_XDRDestroy(r); // this frees `frozen` + + // execute with null result meaning no result wanted + CHECK(JS_ExecuteScript(cx, global, scriptObj, NULL)); + return true; +} +END_TEST(testXDR_bug516827) diff --git a/js/src/jsapi-tests/tests.cpp b/js/src/jsapi-tests/tests.cpp new file mode 100644 index 0000000..243338b --- /dev/null +++ b/js/src/jsapi-tests/tests.cpp @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is JSAPI tests. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jason Orendorff + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "tests.h" +#include + +JSAPITest *JSAPITest::list; + +int main(int argc, char *argv[]) +{ + int total = 0; + int failures = 0; + const char *filter = (argc == 2) ? argv[1] : NULL; + + JS_SetCStringsAreUTF8(); + + for (JSAPITest *test = JSAPITest::list; test; test = test->next) { + const char *name = test->name(); + if (filter && strstr(name, filter) == NULL) + continue; + + total += 1; + + printf("%s\n", name); + if (!test->init()) { + printf("TEST-UNEXPECTED-FAIL | %s | Failed to initialize.\n", name); + failures++; + continue; + } + + if (test->run()) { + printf("TEST-PASS | %s | ok\n", name); + } else { + JSAPITestString messages = test->messages(); + printf("%s | %s | %.*s\n", + (test->knownFail ? "TEST-KNOWN-FAIL" : "TEST-UNEXPECTED-FAIL"), + name, (int) messages.length(), messages.begin()); + if (!test->knownFail) + failures++; + } + test->uninit(); + } + + if (failures) { + printf("\n%d unexpected failure%s.\n", failures, (failures == 1 ? "" : "s")); + return 1; + } + printf("\nPassed: ran %d tests.\n", total); + return 0; +} diff --git a/js/src/jsapi-tests/tests.h b/js/src/jsapi-tests/tests.h new file mode 100644 index 0000000..0bf3ee3 --- /dev/null +++ b/js/src/jsapi-tests/tests.h @@ -0,0 +1,397 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is JSAPI tests. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jason Orendorff + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsapi.h" +#include "jsprvtd.h" +#include "jsvector.h" +#include +#include +#include +#include + +class jsvalRoot +{ + public: + explicit jsvalRoot(JSContext *context, jsval value = JSVAL_NULL) + : cx(context), v(value) + { + if (!JS_AddValueRoot(cx, &v)) { + fprintf(stderr, "Out of memory in jsvalRoot constructor, aborting\n"); + abort(); + } + } + + ~jsvalRoot() { JS_RemoveValueRoot(cx, &v); } + + operator jsval() const { return value(); } + + jsvalRoot & operator=(jsval value) { + v = value; + return *this; + } + + jsval * addr() { return &v; } + jsval value() const { return v; } + + private: + JSContext *cx; + jsval v; +}; + +/* Note: Aborts on OOM. */ +class JSAPITestString { + js::Vector chars; + public: + JSAPITestString() {} + JSAPITestString(const char *s) { *this += s; } + JSAPITestString(const JSAPITestString &s) { *this += s; } + + const char *begin() const { return chars.begin(); } + const char *end() const { return chars.end(); } + size_t length() const { return chars.length(); } + + JSAPITestString & operator +=(const char *s) { + if (!chars.append(s, strlen(s))) + abort(); + return *this; + } + + JSAPITestString & operator +=(const JSAPITestString &s) { + if (!chars.append(s.begin(), s.length())) + abort(); + return *this; + } +}; + +inline JSAPITestString operator+(JSAPITestString a, const char *b) { return a += b; } +inline JSAPITestString operator+(JSAPITestString a, const JSAPITestString &b) { return a += b; } + +class JSAPITest +{ + public: + static JSAPITest *list; + JSAPITest *next; + + JSRuntime *rt; + JSContext *cx; + JSObject *global; + bool knownFail; + JSAPITestString msgs; + JSCrossCompartmentCall *call; + + JSAPITest() : rt(NULL), cx(NULL), global(NULL), knownFail(false), call(NULL) { + next = list; + list = this; + } + + virtual ~JSAPITest() { uninit(); } + + virtual bool init() { + rt = createRuntime(); + if (!rt) + return false; + cx = createContext(); + if (!cx) + return false; + JS_BeginRequest(cx); + global = createGlobal(); + if (!global) + return false; + call = JS_EnterCrossCompartmentCall(cx, global); + return call != NULL; + } + + virtual void uninit() { + if (call) { + JS_LeaveCrossCompartmentCall(call); + call = NULL; + } + if (cx) { + JS_EndRequest(cx); + JS_DestroyContext(cx); + cx = NULL; + } + if (rt) { + destroyRuntime(); + rt = NULL; + } + } + + virtual const char * name() = 0; + virtual bool run() = 0; + +#define EXEC(s) do { if (!exec(s, __FILE__, __LINE__)) return false; } while (false) + + bool exec(const char *bytes, const char *filename, int lineno) { + jsvalRoot v(cx); + return JS_EvaluateScript(cx, global, bytes, strlen(bytes), filename, lineno, v.addr()) || + fail(bytes, filename, lineno); + } + +#define EVAL(s, vp) do { if (!evaluate(s, __FILE__, __LINE__, vp)) return false; } while (false) + + bool evaluate(const char *bytes, const char *filename, int lineno, jsval *vp) { + return JS_EvaluateScript(cx, global, bytes, strlen(bytes), filename, lineno, vp) || + fail(bytes, filename, lineno); + } + + JSAPITestString toSource(jsval v) { + JSString *str = JS_ValueToSource(cx, v); + if (str) { + JSAutoByteString bytes(cx, str); + if (!!bytes) + return JSAPITestString(bytes.ptr()); + } + JS_ClearPendingException(cx); + return JSAPITestString("<>"); + } + +#define CHECK_SAME(actual, expected) \ + do { \ + if (!checkSame(actual, expected, #actual, #expected, __FILE__, __LINE__)) \ + return false; \ + } while (false) + + bool checkSame(jsval actual, jsval expected, + const char *actualExpr, const char *expectedExpr, + const char *filename, int lineno) { + JSBool same; + return (JS_SameValue(cx, actual, expected, &same) && same) || + fail(JSAPITestString("CHECK_SAME failed: expected JS_SameValue(cx, ") + + actualExpr + ", " + expectedExpr + "), got !JS_SameValue(cx, " + + toSource(actual) + ", " + toSource(expected) + ")", filename, lineno); + } + +#define CHECK(expr) \ + do { \ + if (!(expr)) \ + return fail("CHECK failed: " #expr, __FILE__, __LINE__); \ + } while (false) + + bool fail(JSAPITestString msg = JSAPITestString(), const char *filename = "-", int lineno = 0) { + if (JS_IsExceptionPending(cx)) { + jsvalRoot v(cx); + JS_GetPendingException(cx, v.addr()); + JS_ClearPendingException(cx); + JSString *s = JS_ValueToString(cx, v); + if (s) { + JSAutoByteString bytes(cx, s); + if (!!bytes) + msg += bytes.ptr(); + } + } + fprintf(stderr, "%s:%d:%.*s\n", filename, lineno, (int) msg.length(), msg.begin()); + msgs += msg; + return false; + } + + JSAPITestString messages() const { return msgs; } + + static JSClass * basicGlobalClass() { + static JSClass c = { + "global", JSCLASS_GLOBAL_FLAGS, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS + }; + return &c; + } + + protected: + static JSBool + print(JSContext *cx, uintN argc, jsval *vp) + { + jsval *argv = JS_ARGV(cx, vp); + for (uintN i = 0; i < argc; i++) { + JSString *str = JS_ValueToString(cx, argv[i]); + if (!str) + return JS_FALSE; + char *bytes = JS_EncodeString(cx, str); + if (!bytes) + return JS_FALSE; + printf("%s%s", i ? " " : "", bytes); + JS_free(cx, bytes); + } + + putchar('\n'); + fflush(stdout); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return JS_TRUE; + } + + bool definePrint() { + return JS_DefineFunction(cx, global, "print", (JSNative) print, 0, 0); + } + + virtual JSRuntime * createRuntime() { + return JS_NewRuntime(8L * 1024 * 1024); + } + + virtual void destroyRuntime() { + JS_ASSERT(!cx); + JS_ASSERT(rt); + JS_DestroyRuntime(rt); + } + + static void reportError(JSContext *cx, const char *message, JSErrorReport *report) { + fprintf(stderr, "%s:%u:%s\n", + report->filename ? report->filename : "", + (unsigned int) report->lineno, + message); + } + + virtual JSContext * createContext() { + JSContext *cx = JS_NewContext(rt, 8192); + if (!cx) + return NULL; + JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT); + JS_SetVersion(cx, JSVERSION_LATEST); + JS_SetErrorReporter(cx, &reportError); + return cx; + } + + virtual JSClass * getGlobalClass() { + return basicGlobalClass(); + } + + virtual JSObject * createGlobal() { + /* Create the global object. */ + JSObject *global = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL); + if (!global) + return NULL; + + JSAutoEnterCompartment ac; + if (!ac.enter(cx, global)) + return NULL; + + /* Populate the global object with the standard globals, + like Object and Array. */ + if (!JS_InitStandardClasses(cx, global)) + return NULL; + return global; + } +}; + +#define BEGIN_TEST(testname) \ + class cls_##testname : public JSAPITest { \ + public: \ + virtual const char * name() { return #testname; } \ + virtual bool run() + +#define END_TEST(testname) \ + }; \ + static cls_##testname cls_##testname##_instance; + +/* + * A "fixture" is a subclass of JSAPITest that holds common definitions for a + * set of tests. Each test that wants to use the fixture should use + * BEGIN_FIXTURE_TEST and END_FIXTURE_TEST, just as one would use BEGIN_TEST and + * END_TEST, but include the fixture class as the first argument. The fixture + * class's declarations are then in scope for the test bodies. + */ + +#define BEGIN_FIXTURE_TEST(fixture, testname) \ + class cls_##testname : public fixture { \ + public: \ + virtual const char * name() { return #testname; } \ + virtual bool run() + +#define END_FIXTURE_TEST(fixture, testname) \ + }; \ + static cls_##testname cls_##testname##_instance; + +/* + * A class for creating and managing one temporary file. + * + * We could use the ISO C temporary file functions here, but those try to + * create files in the root directory on Windows, which fails for users + * without Administrator privileges. + */ +class TempFile { + const char *name; + FILE *stream; + + public: + TempFile() : name(), stream() { } + ~TempFile() { + if (stream) + close(); + if (name) + remove(); + } + + /* + * Return a stream for a temporary file named |fileName|. Infallible. + * Use only once per TempFile instance. If the file is not explicitly + * closed and deleted via the member functions below, this object's + * destructor will clean them up. + */ + FILE *open(const char *fileName) + { + stream = fopen(fileName, "wb+"); + if (!stream) { + fprintf(stderr, "error opening temporary file '%s': %s\n", + fileName, strerror(errno)); + exit(1); + } + name = fileName; + return stream; + } + + /* Close the temporary file's stream. */ + void close() { + if (fclose(stream) == EOF) { + fprintf(stderr, "error closing temporary file '%s': %s\n", + name, strerror(errno)); + exit(1); + } + stream = NULL; + } + + /* Delete the temporary file. */ + void remove() { + if (::remove(name) != 0) { + fprintf(stderr, "error deleting temporary file '%s': %s\n", + name, strerror(errno)); + exit(1); + } + name = NULL; + } +}; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp new file mode 100644 index 0000000..7ba4ea6 --- /dev/null +++ b/js/src/jsapi.cpp @@ -0,0 +1,6186 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript API. + */ +#include +#include +#include +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsarena.h" +#include "jsutil.h" +#include "jsclist.h" +#include "jsdhash.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jsbuiltins.h" +#include "jsclone.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdate.h" +#include "jsemit.h" +#include "jsexn.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsmath.h" +#include "jsnum.h" +#include "json.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsproxy.h" +#include "jsregexp.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jstracer.h" +#include "prmjtime.h" +#include "jsstaticcheck.h" +#include "jsvector.h" +#include "jswrapper.h" +#include "jstypedarray.h" + +#include "jsatominlines.h" +#include "jscntxtinlines.h" +#include "jsinterpinlines.h" +#include "jsobjinlines.h" +#include "jsscopeinlines.h" +#include "jscntxtinlines.h" +#include "jsregexpinlines.h" +#include "jsscriptinlines.h" +#include "jsstrinlines.h" +#include "assembler/wtf/Platform.h" + +#if ENABLE_YARR_JIT +#include "assembler/jit/ExecutableAllocator.h" +#include "methodjit/Logging.h" +#endif + +#if JS_HAS_XML_SUPPORT +#include "jsxml.h" +#endif + +using namespace js; +using namespace js::gc; + +/* + * This class is a version-establising barrier at the head of a VM entry or + * re-entry. It ensures that: + * + * - |newVersion| is the starting (default) version used for the context. + * - The starting version state is not an override. + * - Overrides in the VM session are not propagated to the caller. + */ +class AutoVersionAPI +{ + JSContext * const cx; + JSVersion oldDefaultVersion; + bool oldHasVersionOverride; + JSVersion oldVersionOverride; +#ifdef DEBUG + uintN oldCompileOptions; +#endif + JSVersion newVersion; + + public: + explicit AutoVersionAPI(JSContext *cx, JSVersion newVersion) + : cx(cx), + oldDefaultVersion(cx->getDefaultVersion()), + oldHasVersionOverride(cx->isVersionOverridden()), + oldVersionOverride(oldHasVersionOverride ? cx->findVersion() : JSVERSION_UNKNOWN) +#ifdef DEBUG + , oldCompileOptions(cx->getCompileOptions()) +#endif + { + /* + * Note: ANONFUNFIX in newVersion is ignored for backwards + * compatibility, must be set via JS_SetOptions. (Because of this, we + * inherit the current ANONFUNFIX setting from the options. + */ + VersionSetAnonFunFix(&newVersion, OptionsHasAnonFunFix(cx->getCompileOptions())); + this->newVersion = newVersion; + cx->clearVersionOverride(); + cx->setDefaultVersion(newVersion); + } + + ~AutoVersionAPI() { + cx->setDefaultVersion(oldDefaultVersion); + if (oldHasVersionOverride) + cx->overrideVersion(oldVersionOverride); + else + cx->clearVersionOverride(); + JS_ASSERT(oldCompileOptions == cx->getCompileOptions()); + } + + /* The version that this scoped-entity establishes. */ + JSVersion version() const { return newVersion; } +}; + +#ifdef HAVE_VA_LIST_AS_ARRAY +#define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap)) +#else +#define JS_ADDRESSOF_VA_LIST(ap) (&(ap)) +#endif + +#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES +JS_PUBLIC_DATA(jsid) JS_DEFAULT_XML_NAMESPACE_ID = { size_t(JSID_TYPE_DEFAULT_XML_NAMESPACE) }; +JS_PUBLIC_DATA(jsid) JSID_VOID = { size_t(JSID_TYPE_VOID) }; +JS_PUBLIC_DATA(jsid) JSID_EMPTY = { size_t(JSID_TYPE_OBJECT) }; +#endif + +#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES +JS_PUBLIC_DATA(jsval) JSVAL_NULL = { BUILD_JSVAL(JSVAL_TAG_NULL, 0) }; +JS_PUBLIC_DATA(jsval) JSVAL_ZERO = { BUILD_JSVAL(JSVAL_TAG_INT32, 0) }; +JS_PUBLIC_DATA(jsval) JSVAL_ONE = { BUILD_JSVAL(JSVAL_TAG_INT32, 1) }; +JS_PUBLIC_DATA(jsval) JSVAL_FALSE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_FALSE) }; +JS_PUBLIC_DATA(jsval) JSVAL_TRUE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_TRUE) }; +JS_PUBLIC_DATA(jsval) JSVAL_VOID = { BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0) }; +#endif + +/* Make sure that jschar is two bytes unsigned integer */ +JS_STATIC_ASSERT((jschar)-1 > 0); +JS_STATIC_ASSERT(sizeof(jschar) == 2); + +JS_PUBLIC_API(int64) +JS_Now() +{ + return PRMJ_Now(); +} + +JS_PUBLIC_API(jsval) +JS_GetNaNValue(JSContext *cx) +{ + return Jsvalify(cx->runtime->NaNValue); +} + +JS_PUBLIC_API(jsval) +JS_GetNegativeInfinityValue(JSContext *cx) +{ + return Jsvalify(cx->runtime->negativeInfinityValue); +} + +JS_PUBLIC_API(jsval) +JS_GetPositiveInfinityValue(JSContext *cx) +{ + return Jsvalify(cx->runtime->positiveInfinityValue); +} + +JS_PUBLIC_API(jsval) +JS_GetEmptyStringValue(JSContext *cx) +{ + return STRING_TO_JSVAL(cx->runtime->emptyString); +} + +JS_PUBLIC_API(JSString *) +JS_GetEmptyString(JSRuntime *rt) +{ + JS_ASSERT(rt->state == JSRTS_UP); + return rt->emptyString; +} + +static JSBool +TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS, jsval **vpp, va_list *app) +{ + const char *format; + JSArgumentFormatMap *map; + + format = *formatp; + for (map = cx->argumentFormatMap; map; map = map->next) { + if (!strncmp(format, map->format, map->length)) { + *formatp = format + map->length; + return map->formatter(cx, format, fromJS, vpp, app); + } + } + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format); + return JS_FALSE; +} + +JS_PUBLIC_API(JSBool) +JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format, ...) +{ + va_list ap; + JSBool ok; + + va_start(ap, format); + ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap); + va_end(ap); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format, va_list ap) +{ + jsval *sp; + JSBool required; + char c; + JSFunction *fun; + jsdouble d; + JSString *str; + JSObject *obj; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, JSValueArray(argv - 2, argc + 2)); + sp = argv; + required = JS_TRUE; + while ((c = *format++) != '\0') { + if (isspace(c)) + continue; + if (c == '/') { + required = JS_FALSE; + continue; + } + if (sp == argv + argc) { + if (required) { + fun = js_ValueToFunction(cx, Valueify(&argv[-2]), 0); + if (fun) { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%u", argc); + JSAutoByteString funNameBytes; + if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, + name, numBuf, (argc == 1) ? "" : "s"); + } + } + return JS_FALSE; + } + break; + } + switch (c) { + case 'b': + *va_arg(ap, JSBool *) = js_ValueToBoolean(Valueify(*sp)); + break; + case 'c': + if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *))) + return JS_FALSE; + break; + case 'i': + if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *))) + return JS_FALSE; + break; + case 'u': + if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *))) + return JS_FALSE; + break; + case 'j': + if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32 *))) + return JS_FALSE; + break; + case 'd': + if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *))) + return JS_FALSE; + break; + case 'I': + if (!JS_ValueToNumber(cx, *sp, &d)) + return JS_FALSE; + *va_arg(ap, jsdouble *) = js_DoubleToInteger(d); + break; + case 'S': + case 'W': + str = js_ValueToString(cx, Valueify(*sp)); + if (!str) + return JS_FALSE; + *sp = STRING_TO_JSVAL(str); + if (c == 'W') { + const jschar *chars = js_GetStringChars(cx, str); + if (!chars) + return JS_FALSE; + *va_arg(ap, const jschar **) = chars; + } else { + *va_arg(ap, JSString **) = str; + } + break; + case 'o': + if (!js_ValueToObjectOrNull(cx, Valueify(*sp), &obj)) + return JS_FALSE; + *sp = OBJECT_TO_JSVAL(obj); + *va_arg(ap, JSObject **) = obj; + break; + case 'f': + obj = js_ValueToFunctionObject(cx, Valueify(sp), 0); + if (!obj) + return JS_FALSE; + *sp = OBJECT_TO_JSVAL(obj); + *va_arg(ap, JSFunction **) = GET_FUNCTION_PRIVATE(cx, obj); + break; + case 'v': + *va_arg(ap, jsval *) = *sp; + break; + case '*': + break; + default: + format--; + if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp, + JS_ADDRESSOF_VA_LIST(ap))) { + return JS_FALSE; + } + /* NB: the formatter already updated sp, so we continue here. */ + continue; + } + sp++; + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_AddArgumentFormatter(JSContext *cx, const char *format, JSArgumentFormatter formatter) +{ + size_t length; + JSArgumentFormatMap **mpp, *map; + + length = strlen(format); + mpp = &cx->argumentFormatMap; + while ((map = *mpp) != NULL) { + /* Insert before any shorter string to match before prefixes. */ + if (map->length < length) + break; + if (map->length == length && !strcmp(map->format, format)) + goto out; + mpp = &map->next; + } + map = (JSArgumentFormatMap *) cx->malloc(sizeof *map); + if (!map) + return JS_FALSE; + map->format = format; + map->length = length; + map->next = *mpp; + *mpp = map; +out: + map->formatter = formatter; + return JS_TRUE; +} + +JS_PUBLIC_API(void) +JS_RemoveArgumentFormatter(JSContext *cx, const char *format) +{ + size_t length; + JSArgumentFormatMap **mpp, *map; + + length = strlen(format); + mpp = &cx->argumentFormatMap; + while ((map = *mpp) != NULL) { + if (map->length == length && !strcmp(map->format, format)) { + *mpp = map->next; + cx->free(map); + return; + } + mpp = &map->next; + } +} + +JS_PUBLIC_API(JSBool) +JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp) +{ + JSBool ok; + JSObject *obj; + JSString *str; + jsdouble d; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + switch (type) { + case JSTYPE_VOID: + *vp = JSVAL_VOID; + ok = JS_TRUE; + break; + case JSTYPE_OBJECT: + ok = js_ValueToObjectOrNull(cx, Valueify(v), &obj); + if (ok) + *vp = OBJECT_TO_JSVAL(obj); + break; + case JSTYPE_FUNCTION: + *vp = v; + obj = js_ValueToFunctionObject(cx, Valueify(vp), JSV2F_SEARCH_STACK); + ok = (obj != NULL); + break; + case JSTYPE_STRING: + str = js_ValueToString(cx, Valueify(v)); + ok = (str != NULL); + if (ok) + *vp = STRING_TO_JSVAL(str); + break; + case JSTYPE_NUMBER: + ok = JS_ValueToNumber(cx, v, &d); + if (ok) + *vp = DOUBLE_TO_JSVAL(d); + break; + case JSTYPE_BOOLEAN: + *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(Valueify(v))); + return JS_TRUE; + default: { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE, numBuf); + ok = JS_FALSE; + break; + } + } + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + return js_ValueToObjectOrNull(cx, Valueify(v), objp); +} + +JS_PUBLIC_API(JSFunction *) +JS_ValueToFunction(JSContext *cx, jsval v) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK); +} + +JS_PUBLIC_API(JSFunction *) +JS_ValueToConstructor(JSContext *cx, jsval v) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK); +} + +JS_PUBLIC_API(JSString *) +JS_ValueToString(JSContext *cx, jsval v) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + return js_ValueToString(cx, Valueify(v)); +} + +JS_PUBLIC_API(JSString *) +JS_ValueToSource(JSContext *cx, jsval v) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + return js_ValueToSource(cx, Valueify(v)); +} + +JS_PUBLIC_API(JSBool) +JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + + AutoValueRooter tvr(cx, Valueify(v)); + return ValueToNumber(cx, tvr.value(), dp); +} + +JS_PUBLIC_API(JSBool) +JS_DoubleIsInt32(jsdouble d, jsint *ip) +{ + return JSDOUBLE_IS_INT32(d, (int32_t *)ip); +} + +JS_PUBLIC_API(JSBool) +JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + + AutoValueRooter tvr(cx, Valueify(v)); + return ValueToECMAInt32(cx, tvr.value(), (int32_t *)ip); +} + +JS_PUBLIC_API(JSBool) +JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + + AutoValueRooter tvr(cx, Valueify(v)); + return ValueToECMAUint32(cx, tvr.value(), (uint32_t *)ip); +} + +JS_PUBLIC_API(JSBool) +JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + + AutoValueRooter tvr(cx, Valueify(v)); + return ValueToInt32(cx, tvr.value(), (int32_t *)ip); +} + +JS_PUBLIC_API(JSBool) +JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + + AutoValueRooter tvr(cx, Valueify(v)); + return ValueToUint16(cx, tvr.value(), (uint16_t *)ip); +} + +JS_PUBLIC_API(JSBool) +JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + *bp = js_ValueToBoolean(Valueify(v)); + return JS_TRUE; +} + +JS_PUBLIC_API(JSType) +JS_TypeOfValue(JSContext *cx, jsval v) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + return TypeOfValue(cx, Valueify(v)); +} + +JS_PUBLIC_API(const char *) +JS_GetTypeName(JSContext *cx, JSType type) +{ + if ((uintN)type >= (uintN)JSTYPE_LIMIT) + return NULL; + return JS_TYPE_STR(type); +} + +JS_PUBLIC_API(JSBool) +JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal) +{ + assertSameCompartment(cx, v1, v2); + return StrictlyEqual(cx, Valueify(v1), Valueify(v2), equal); +} + +JS_PUBLIC_API(JSBool) +JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same) +{ + assertSameCompartment(cx, v1, v2); + return SameValue(cx, Valueify(v1), Valueify(v2), same); +} + +/************************************************************************/ + +/* + * Has a new runtime ever been created? This flag is used to detect unsafe + * changes to js_CStringsAreUTF8 after a runtime has been created, and to + * ensure that "first checks" on runtime creation are run only once. + */ +#ifdef DEBUG +static JSBool js_NewRuntimeWasCalled = JS_FALSE; +#endif + +JSRuntime::JSRuntime() + : gcChunkAllocator(&defaultGCChunkAllocator) +{ + /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */ + JS_INIT_CLIST(&contextList); + JS_INIT_CLIST(&trapList); + JS_INIT_CLIST(&watchPointList); +} + +bool +JSRuntime::init(uint32 maxbytes) +{ +#ifdef JS_METHODJIT_SPEW + JMCheckLogging(); +#endif + +#ifdef DEBUG + functionMeterFilename = getenv("JS_FUNCTION_STATFILE"); + if (functionMeterFilename) { + if (!methodReadBarrierCountMap.init()) + return false; + if (!unjoinedFunctionCountMap.init()) + return false; + } + propTreeStatFilename = getenv("JS_PROPTREE_STATFILE"); + propTreeDumpFilename = getenv("JS_PROPTREE_DUMPFILE"); +#endif + + if (!(atomsCompartment = js_new(this)) || + !atomsCompartment->init() || + !compartments.append(atomsCompartment)) { + return false; + } + + if (!js_InitGC(this, maxbytes) || !js_InitAtomState(this)) + return false; + + wrapObjectCallback = js::TransparentObjectWrapper; + +#ifdef JS_THREADSAFE + /* this is asymmetric with JS_ShutDown: */ + if (!js_SetupLocks(8, 16)) + return false; + rtLock = JS_NEW_LOCK(); + if (!rtLock) + return false; + stateChange = JS_NEW_CONDVAR(gcLock); + if (!stateChange) + return false; + debuggerLock = JS_NEW_LOCK(); + if (!debuggerLock) + return false; +#endif + + debugMode = JS_FALSE; + + return js_InitThreads(this); +} + +JSRuntime::~JSRuntime() +{ +#ifdef DEBUG + /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */ + if (!JS_CLIST_IS_EMPTY(&contextList)) { + JSContext *cx, *iter = NULL; + uintN cxcount = 0; + while ((cx = js_ContextIterator(this, JS_TRUE, &iter)) != NULL) { + fprintf(stderr, +"JS API usage error: found live context at %p\n", + (void *) cx); + cxcount++; + } + fprintf(stderr, +"JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n", + cxcount, (cxcount == 1) ? "" : "s"); + } +#endif + + js_FinishThreads(this); + js_FreeRuntimeScriptState(this); + js_FinishAtomState(this); + + js_FinishGC(this); +#ifdef JS_THREADSAFE + if (gcLock) + JS_DESTROY_LOCK(gcLock); + if (gcDone) + JS_DESTROY_CONDVAR(gcDone); + if (requestDone) + JS_DESTROY_CONDVAR(requestDone); + if (rtLock) + JS_DESTROY_LOCK(rtLock); + if (stateChange) + JS_DESTROY_CONDVAR(stateChange); + if (debuggerLock) + JS_DESTROY_LOCK(debuggerLock); +#endif +} + +JS_PUBLIC_API(JSRuntime *) +JS_NewRuntime(uint32 maxbytes) +{ +#ifdef DEBUG + if (!js_NewRuntimeWasCalled) { + /* + * This code asserts that the numbers associated with the error names + * in jsmsg.def are monotonically increasing. It uses values for the + * error names enumerated in jscntxt.c. It's not a compile-time check + * but it's better than nothing. + */ + int errorNumber = 0; +#define MSG_DEF(name, number, count, exception, format) \ + JS_ASSERT(name == errorNumber++); +#include "js.msg" +#undef MSG_DEF + +#define MSG_DEF(name, number, count, exception, format) \ + JS_BEGIN_MACRO \ + uintN numfmtspecs = 0; \ + const char *fmt; \ + for (fmt = format; *fmt != '\0'; fmt++) { \ + if (*fmt == '{' && isdigit(fmt[1])) \ + ++numfmtspecs; \ + } \ + JS_ASSERT(count == numfmtspecs); \ + JS_END_MACRO; +#include "js.msg" +#undef MSG_DEF + + js_NewRuntimeWasCalled = JS_TRUE; + } +#endif /* DEBUG */ + + void *mem = js_calloc(sizeof(JSRuntime)); + if (!mem) + return NULL; + + JSRuntime *rt = new (mem) JSRuntime(); + if (!rt->init(maxbytes)) { + JS_DestroyRuntime(rt); + return NULL; + } + + return rt; +} + +JS_PUBLIC_API(void) +JS_DestroyRuntime(JSRuntime *rt) +{ + rt->~JSRuntime(); + + js_free(rt); +} + +#ifdef JS_REPRMETER +namespace reprmeter { + extern void js_DumpReprMeter(); +} +#endif + +JS_PUBLIC_API(void) +JS_ShutDown(void) +{ +#ifdef MOZ_TRACEVIS + StopTraceVis(); +#endif + +#ifdef JS_OPMETER + extern void js_DumpOpMeters(); + js_DumpOpMeters(); +#endif + +#ifdef JS_REPRMETER + reprmeter::js_DumpReprMeter(); +#endif + +#ifdef JS_THREADSAFE + js_CleanupLocks(); +#endif + PRMJ_NowShutdown(); +} + +JS_PUBLIC_API(void *) +JS_GetRuntimePrivate(JSRuntime *rt) +{ + return rt->data; +} + +JS_PUBLIC_API(void) +JS_SetRuntimePrivate(JSRuntime *rt, void *data) +{ + rt->data = data; +} + +#ifdef JS_THREADSAFE +static void +StartRequest(JSContext *cx) +{ + JSThread *t = cx->thread; + JS_ASSERT(CURRENT_THREAD_IS_ME(t)); + + if (t->data.requestDepth) { + t->data.requestDepth++; + } else { + JSRuntime *rt = cx->runtime; + AutoLockGC lock(rt); + + /* Wait until the GC is finished. */ + if (rt->gcThread != cx->thread) { + while (rt->gcThread) + JS_AWAIT_GC_DONE(rt); + } + + /* Indicate that a request is running. */ + rt->requestCount++; + t->data.requestDepth = 1; + + /* + * Adjust rt->interruptCounter to reflect any interrupts added while the + * thread was suspended. + */ + if (t->data.interruptFlags) + JS_ATOMIC_INCREMENT(&rt->interruptCounter); + + if (rt->requestCount == 1 && rt->activityCallback) + rt->activityCallback(rt->activityCallbackArg, true); + } +} + +static void +StopRequest(JSContext *cx) +{ + JSThread *t = cx->thread; + JS_ASSERT(CURRENT_THREAD_IS_ME(t)); + JS_ASSERT(t->data.requestDepth != 0); + if (t->data.requestDepth != 1) { + t->data.requestDepth--; + } else { + LeaveTrace(cx); /* for GC safety */ + + t->data.conservativeGC.updateForRequestEnd(t->suspendCount); + + /* Lock before clearing to interlock with ClaimScope, in jslock.c. */ + JSRuntime *rt = cx->runtime; + AutoLockGC lock(rt); + + t->data.requestDepth = 0; + + /* + * Adjust rt->interruptCounter to reflect any interrupts added while the + * thread still had active requests. + */ + if (t->data.interruptFlags) + JS_ATOMIC_DECREMENT(&rt->interruptCounter); + + /* Give the GC a chance to run if this was the last request running. */ + JS_ASSERT(rt->requestCount > 0); + rt->requestCount--; + if (rt->requestCount == 0) { + JS_NOTIFY_REQUEST_DONE(rt); + if (rt->activityCallback) + rt->activityCallback(rt->activityCallbackArg, false); + } + } +} +#endif /* JS_THREADSAFE */ + +JS_PUBLIC_API(void) +JS_BeginRequest(JSContext *cx) +{ +#ifdef JS_THREADSAFE + cx->outstandingRequests++; + StartRequest(cx); +#endif +} + +JS_PUBLIC_API(void) +JS_EndRequest(JSContext *cx) +{ +#ifdef JS_THREADSAFE + JS_ASSERT(cx->outstandingRequests != 0); + cx->outstandingRequests--; + StopRequest(cx); +#endif +} + +/* Yield to pending GC operations, regardless of request depth */ +JS_PUBLIC_API(void) +JS_YieldRequest(JSContext *cx) +{ +#ifdef JS_THREADSAFE + CHECK_REQUEST(cx); + JS_ResumeRequest(cx, JS_SuspendRequest(cx)); +#endif +} + +JS_PUBLIC_API(jsrefcount) +JS_SuspendRequest(JSContext *cx) +{ +#ifdef JS_THREADSAFE + JSThread *t = cx->thread; + JS_ASSERT(CURRENT_THREAD_IS_ME(t)); + + jsrefcount saveDepth = t->data.requestDepth; + if (!saveDepth) + return 0; + + t->suspendCount++; + t->data.requestDepth = 1; + StopRequest(cx); + return saveDepth; +#else + return 0; +#endif +} + +JS_PUBLIC_API(void) +JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth) +{ +#ifdef JS_THREADSAFE + JSThread *t = cx->thread; + JS_ASSERT(CURRENT_THREAD_IS_ME(t)); + if (saveDepth == 0) + return; + JS_ASSERT(saveDepth >= 1); + JS_ASSERT(!t->data.requestDepth); + JS_ASSERT(t->suspendCount); + StartRequest(cx); + t->data.requestDepth = saveDepth; + t->suspendCount--; +#endif +} + +JS_PUBLIC_API(JSBool) +JS_IsInRequest(JSContext *cx) +{ +#ifdef JS_THREADSAFE + JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread)); + return JS_THREAD_DATA(cx)->requestDepth != 0; +#else + return false; +#endif +} + +JS_PUBLIC_API(void) +JS_Lock(JSRuntime *rt) +{ + JS_LOCK_RUNTIME(rt); +} + +JS_PUBLIC_API(void) +JS_Unlock(JSRuntime *rt) +{ + JS_UNLOCK_RUNTIME(rt); +} + +JS_PUBLIC_API(JSContextCallback) +JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback) +{ + JSContextCallback old; + + old = rt->cxCallback; + rt->cxCallback = cxCallback; + return old; +} + +JS_PUBLIC_API(JSContext *) +JS_NewContext(JSRuntime *rt, size_t stackChunkSize) +{ + return js_NewContext(rt, stackChunkSize); +} + +JS_PUBLIC_API(void) +JS_DestroyContext(JSContext *cx) +{ + js_DestroyContext(cx, JSDCM_FORCE_GC); +} + +JS_PUBLIC_API(void) +JS_DestroyContextNoGC(JSContext *cx) +{ + js_DestroyContext(cx, JSDCM_NO_GC); +} + +JS_PUBLIC_API(void) +JS_DestroyContextMaybeGC(JSContext *cx) +{ + js_DestroyContext(cx, JSDCM_MAYBE_GC); +} + +JS_PUBLIC_API(void *) +JS_GetContextPrivate(JSContext *cx) +{ + return cx->data; +} + +JS_PUBLIC_API(void) +JS_SetContextPrivate(JSContext *cx, void *data) +{ + cx->data = data; +} + +JS_PUBLIC_API(JSRuntime *) +JS_GetRuntime(JSContext *cx) +{ + return cx->runtime; +} + +JS_PUBLIC_API(JSContext *) +JS_ContextIterator(JSRuntime *rt, JSContext **iterp) +{ + return js_ContextIterator(rt, JS_TRUE, iterp); +} + +JS_PUBLIC_API(JSVersion) +JS_GetVersion(JSContext *cx) +{ + return VersionNumber(cx->findVersion()); +} + +JS_PUBLIC_API(JSVersion) +JS_SetVersion(JSContext *cx, JSVersion newVersion) +{ + JS_ASSERT(VersionIsKnown(newVersion)); + JS_ASSERT(!VersionHasFlags(newVersion)); + JSVersion newVersionNumber = newVersion; + +#ifdef DEBUG + uintN coptsBefore = cx->getCompileOptions(); +#endif + JSVersion oldVersion = cx->findVersion(); + JSVersion oldVersionNumber = VersionNumber(oldVersion); + if (oldVersionNumber == newVersionNumber) + return oldVersionNumber; /* No override actually occurs! */ + + /* We no longer support 1.4 or below. */ + if (newVersionNumber != JSVERSION_DEFAULT && newVersionNumber <= JSVERSION_1_4) + return oldVersionNumber; + + VersionCopyFlags(&newVersion, oldVersion); + cx->maybeOverrideVersion(newVersion); + JS_ASSERT(cx->getCompileOptions() == coptsBefore); + return oldVersionNumber; +} + +static struct v2smap { + JSVersion version; + const char *string; +} v2smap[] = { + {JSVERSION_1_0, "1.0"}, + {JSVERSION_1_1, "1.1"}, + {JSVERSION_1_2, "1.2"}, + {JSVERSION_1_3, "1.3"}, + {JSVERSION_1_4, "1.4"}, + {JSVERSION_ECMA_3, "ECMAv3"}, + {JSVERSION_1_5, "1.5"}, + {JSVERSION_1_6, "1.6"}, + {JSVERSION_1_7, "1.7"}, + {JSVERSION_1_8, "1.8"}, + {JSVERSION_ECMA_5, "ECMAv5"}, + {JSVERSION_DEFAULT, js_default_str}, + {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */ +}; + +JS_PUBLIC_API(const char *) +JS_VersionToString(JSVersion version) +{ + int i; + + for (i = 0; v2smap[i].string; i++) + if (v2smap[i].version == version) + return v2smap[i].string; + return "unknown"; +} + +JS_PUBLIC_API(JSVersion) +JS_StringToVersion(const char *string) +{ + int i; + + for (i = 0; v2smap[i].string; i++) + if (strcmp(v2smap[i].string, string) == 0) + return v2smap[i].version; + return JSVERSION_UNKNOWN; +} + +JS_PUBLIC_API(uint32) +JS_GetOptions(JSContext *cx) +{ + /* + * Can't check option/version synchronization here. + * We may have been synchronized with a script version that was formerly on + * the stack, but has now been popped. + */ + return cx->allOptions(); +} + +static uintN +SetOptionsCommon(JSContext *cx, uintN options) +{ + JS_ASSERT((options & JSALLOPTION_MASK) == options); + uintN oldopts = cx->allOptions(); + uintN newropts = options & JSRUNOPTION_MASK; + uintN newcopts = options & JSCOMPILEOPTION_MASK; + cx->setRunOptions(newropts); + cx->setCompileOptions(newcopts); + cx->updateJITEnabled(); + return oldopts; +} + +JS_PUBLIC_API(uint32) +JS_SetOptions(JSContext *cx, uint32 options) +{ + AutoLockGC lock(cx->runtime); + return SetOptionsCommon(cx, options); +} + +JS_PUBLIC_API(uint32) +JS_ToggleOptions(JSContext *cx, uint32 options) +{ + AutoLockGC lock(cx->runtime); + uintN oldopts = cx->allOptions(); + uintN newopts = oldopts ^ options; + return SetOptionsCommon(cx, newopts); +} + +JS_PUBLIC_API(const char *) +JS_GetImplementationVersion(void) +{ + return "JavaScript-C 1.8.5 2011-03-31"; +} + +JS_PUBLIC_API(JSCompartmentCallback) +JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback) +{ + JSCompartmentCallback old = rt->compartmentCallback; + rt->compartmentCallback = callback; + return old; +} + +JS_PUBLIC_API(JSWrapObjectCallback) +JS_SetWrapObjectCallbacks(JSRuntime *rt, + JSWrapObjectCallback callback, + JSPreWrapCallback precallback) +{ + JSWrapObjectCallback old = rt->wrapObjectCallback; + rt->wrapObjectCallback = callback; + rt->preWrapObjectCallback = precallback; + return old; +} + +JS_PUBLIC_API(JSCrossCompartmentCall *) +JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target) +{ + CHECK_REQUEST(cx); + + JS_ASSERT(target); + AutoCompartment *call = js_new(cx, target); + if (!call) + return NULL; + if (!call->enter()) { + js_delete(call); + return NULL; + } + return reinterpret_cast(call); +} + +JS_PUBLIC_API(JSCrossCompartmentCall *) +JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target) +{ + static JSClass dummy_class = { + "jdummy", + JSCLASS_GLOBAL_FLAGS, + JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, + JS_ConvertStub, NULL, + JSCLASS_NO_OPTIONAL_MEMBERS + }; + + CHECK_REQUEST(cx); + + JS_ASSERT(target); + JSObject *scriptObject = target->u.object; + if (!scriptObject) { + SwitchToCompartment sc(cx, target->compartment); + scriptObject = JS_NewGlobalObject(cx, &dummy_class); + if (!scriptObject) + return NULL; + } + return JS_EnterCrossCompartmentCall(cx, scriptObject); +} + +JS_PUBLIC_API(void) +JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call) +{ + AutoCompartment *realcall = reinterpret_cast(call); + CHECK_REQUEST(realcall->context); + realcall->leave(); + js_delete(realcall); +} + +bool +JSAutoEnterCompartment::enter(JSContext *cx, JSObject *target) +{ + JS_ASSERT(!call); + if (cx->compartment == target->getCompartment()) { + call = reinterpret_cast(1); + return true; + } + call = JS_EnterCrossCompartmentCall(cx, target); + return call != NULL; +} + +void +JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target) +{ + (void) enter(cx, target); +} + +namespace JS { + +bool +AutoEnterScriptCompartment::enter(JSContext *cx, JSScript *target) +{ + JS_ASSERT(!call); + if (cx->compartment == target->compartment) { + call = reinterpret_cast(1); + return true; + } + call = JS_EnterCrossCompartmentCallScript(cx, target); + return call != NULL; +} + +} /* namespace JS */ + +JS_PUBLIC_API(void *) +JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data) +{ + CHECK_REQUEST(cx); + void *old = compartment->data; + compartment->data = data; + return old; +} + +JS_PUBLIC_API(void *) +JS_GetCompartmentPrivate(JSContext *cx, JSCompartment *compartment) +{ + CHECK_REQUEST(cx); + return compartment->data; +} + +JS_PUBLIC_API(JSBool) +JS_WrapObject(JSContext *cx, JSObject **objp) +{ + CHECK_REQUEST(cx); + return cx->compartment->wrap(cx, objp); +} + +JS_PUBLIC_API(JSBool) +JS_WrapValue(JSContext *cx, jsval *vp) +{ + CHECK_REQUEST(cx); + return cx->compartment->wrap(cx, Valueify(vp)); +} + +JS_PUBLIC_API(JSObject *) +JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target) +{ + // This function is called when an object moves between two + // different compartments. In that case, we need to "move" the + // window from origobj's compartment to target's compartment. + JSCompartment *destination = target->getCompartment(); + WrapperMap &map = destination->crossCompartmentWrappers; + Value origv = ObjectValue(*origobj); + JSObject *obj; + + if (origobj->getCompartment() == destination) { + // If the original object is in the same compartment as the + // destination, then we know that we won't find wrapper in the + // destination's cross compartment map and that the same + // object will continue to work. Note the rare case where + // |origobj == target|. In that case, we can just treat this + // as a same compartment navigation. The effect is to clear + // all of the wrappers and their holders if they have + // them. This would be cleaner as a separate API. + if (origobj != target && !origobj->swap(cx, target)) + return NULL; + obj = origobj; + } else if (WrapperMap::Ptr p = map.lookup(origv)) { + // There might already be a wrapper for the original object in + // the new compartment. If there is, make it the primary outer + // window proxy around the inner (accomplished by swapping + // target's innards with the old, possibly security wrapper, + // innards). + obj = &p->value.toObject(); + map.remove(p); + if (!obj->swap(cx, target)) + return NULL; + } else { + // Otherwise, this is going to be our outer window proxy in + // the new compartment. + obj = target; + } + + // Now, iterate through other scopes looking for references to the + // old outer window. They need to be updated to point at the new + // outer window. They also might transition between different + // types of security wrappers based on whether the new compartment + // is same origin with them. + Value targetv = ObjectValue(*obj); + WrapperVector &vector = cx->runtime->compartments; + AutoValueVector toTransplant(cx); + toTransplant.reserve(vector.length()); + + for (JSCompartment **p = vector.begin(), **end = vector.end(); p != end; ++p) { + WrapperMap &pmap = (*p)->crossCompartmentWrappers; + if (WrapperMap::Ptr wp = pmap.lookup(origv)) { + // We found a wrapper. Remember and root it. + toTransplant.append(wp->value); + } + } + + for (Value *begin = toTransplant.begin(), *end = toTransplant.end(); begin != end; ++begin) { + JSObject *wobj = &begin->toObject(); + JSCompartment *wcompartment = wobj->compartment(); + WrapperMap &pmap = wcompartment->crossCompartmentWrappers; + JS_ASSERT(pmap.lookup(origv)); + pmap.remove(origv); + + // First, we wrap it in the new compartment. This will return + // a new wrapper. + AutoCompartment ac(cx, wobj); + JSObject *tobj = obj; + if (!ac.enter() || !wcompartment->wrap(cx, &tobj)) + return NULL; + + // Now, because we need to maintain object identity, we do a + // brain transplant on the old object. At the same time, we + // update the entry in the compartment's wrapper map to point + // to the old wrapper. + JS_ASSERT(tobj != wobj); + if (!wobj->swap(cx, tobj)) + return NULL; + pmap.put(targetv, ObjectValue(*wobj)); + } + + // Lastly, update the original object to point to the new one. + if (origobj->getCompartment() != destination) { + AutoCompartment ac(cx, origobj); + JSObject *tobj = obj; + if (!ac.enter() || !JS_WrapObject(cx, &tobj)) + return NULL; + if (!origobj->swap(cx, tobj)) + return NULL; + origobj->getCompartment()->crossCompartmentWrappers.put(targetv, origv); + } + + return obj; +} + +/* + * The location object is special. There is the location object itself and + * then the location object wrapper. Because there are no direct references to + * the location object itself, we don't want the old obj (|origobj| here) to + * become the new wrapper but the wrapper itself instead. This leads to very + * subtle differences between js_TransplantObjectWithWrapper and + * JS_TransplantObject. + */ +JS_FRIEND_API(JSObject *) +js_TransplantObjectWithWrapper(JSContext *cx, + JSObject *origobj, + JSObject *origwrapper, + JSObject *targetobj, + JSObject *targetwrapper) +{ + JSObject *obj; + JSCompartment *destination = targetobj->getCompartment(); + WrapperMap &map = destination->crossCompartmentWrappers; + + // |origv| is the map entry we're looking up. The map entries are going to + // be for the location object itself. + Value origv = ObjectValue(*origobj); + + // There might already be a wrapper for the original object in the new + // compartment. + if (WrapperMap::Ptr p = map.lookup(origv)) { + // There is. Make the existing wrapper a same compartment location + // wrapper (swapping it with the given new wrapper). + obj = &p->value.toObject(); + map.remove(p); + if (!obj->swap(cx, targetwrapper)) + return NULL; + } else { + // Otherwise, use the passed-in wrapper as the same compartment + // location wrapper. + obj = targetwrapper; + } + + // Now, iterate through other scopes looking for references to the old + // location object. Note that the entries in the maps are for |origobj| + // and not |origwrapper|. They need to be updated to point at the new + // location object. + Value targetv = ObjectValue(*targetobj); + WrapperVector &vector = cx->runtime->compartments; + AutoValueVector toTransplant(cx); + toTransplant.reserve(vector.length()); + + for (JSCompartment **p = vector.begin(), **end = vector.end(); p != end; ++p) { + WrapperMap &pmap = (*p)->crossCompartmentWrappers; + if (WrapperMap::Ptr wp = pmap.lookup(origv)) { + // We found a wrapper. Remember and root it. + toTransplant.append(wp->value); + } + } + + for (Value *begin = toTransplant.begin(), *end = toTransplant.end(); begin != end; ++begin) { + JSObject *wobj = &begin->toObject(); + JSCompartment *wcompartment = wobj->compartment(); + WrapperMap &pmap = wcompartment->crossCompartmentWrappers; + JS_ASSERT(pmap.lookup(origv)); + pmap.remove(origv); + + // First, we wrap it in the new compartment. This will return a + // new wrapper. + AutoCompartment ac(cx, wobj); + + JSObject *tobj = targetobj; + if (!ac.enter() || !wcompartment->wrap(cx, &tobj)) + return NULL; + + // Now, because we need to maintain object identity, we do a brain + // transplant on the old object. At the same time, we update the + // entry in the compartment's wrapper map to point to the old + // wrapper. + JS_ASSERT(tobj != wobj); + if (!wobj->swap(cx, tobj)) + return NULL; + pmap.put(targetv, ObjectValue(*wobj)); + } + + // Lastly, update the original object to point to the new one. However, as + // mentioned above, we do the transplant on the wrapper, not the object + // itself, since all of the references are to the object itself. + { + AutoCompartment ac(cx, origobj); + JSObject *tobj = obj; + if (!ac.enter() || !JS_WrapObject(cx, &tobj)) + return NULL; + if (!origwrapper->swap(cx, tobj)) + return NULL; + origwrapper->getCompartment()->crossCompartmentWrappers.put(targetv, + ObjectValue(*origwrapper)); + } + + return obj; +} + +JS_PUBLIC_API(JSObject *) +JS_GetGlobalObject(JSContext *cx) +{ + return cx->globalObject; +} + +JS_PUBLIC_API(void) +JS_SetGlobalObject(JSContext *cx, JSObject *obj) +{ + CHECK_REQUEST(cx); + + cx->globalObject = obj; + if (!cx->hasfp()) + cx->resetCompartment(); +} + +class AutoResolvingEntry { +public: + AutoResolvingEntry() : entry(NULL) {} + + /* + * Returns false on error. But N.B. if obj[id] was already being resolved, + * this is a no-op, and we silently treat that as success. + */ + bool start(JSContext *cx, JSObject *obj, jsid id, uint32 flag) { + JS_ASSERT(!entry); + this->cx = cx; + key.obj = obj; + key.id = id; + this->flag = flag; + bool ok = !!js_StartResolving(cx, &key, flag, &entry); + JS_ASSERT_IF(!ok, !entry); + return ok; + } + + ~AutoResolvingEntry() { + if (entry) + js_StopResolving(cx, &key, flag, NULL, 0); + } + +private: + JSContext *cx; + JSResolvingKey key; + uint32 flag; + JSResolvingEntry *entry; +}; + +JSObject * +js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + JSObject *fun_proto, *obj_proto; + + /* If cx has no global object, use obj so prototypes can be found. */ + if (!cx->globalObject) + JS_SetGlobalObject(cx, obj); + + /* Record Function and Object in cx->resolvingTable. */ + AutoResolvingEntry e1, e2; + JSAtom **classAtoms = cx->runtime->atomState.classAtoms; + if (!e1.start(cx, obj, ATOM_TO_JSID(classAtoms[JSProto_Function]), JSRESFLAG_LOOKUP) || + !e2.start(cx, obj, ATOM_TO_JSID(classAtoms[JSProto_Object]), JSRESFLAG_LOOKUP)) { + return NULL; + } + + /* Initialize the function class first so constructors can be made. */ + if (!js_GetClassPrototype(cx, obj, JSProto_Function, &fun_proto)) + return NULL; + if (!fun_proto) { + fun_proto = js_InitFunctionClass(cx, obj); + if (!fun_proto) + return NULL; + } else { + JSObject *ctor; + + ctor = JS_GetConstructor(cx, fun_proto); + if (!ctor) + return NULL; + if (!obj->defineProperty(cx, ATOM_TO_JSID(CLASS_ATOM(cx, Function)), + ObjectValue(*ctor), 0, 0, 0)) { + return NULL; + } + } + + /* Initialize the object class next so Object.prototype works. */ + if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto)) + return NULL; + if (!obj_proto) + obj_proto = js_InitObjectClass(cx, obj); + if (!obj_proto) + return NULL; + + /* Function.prototype and the global object delegate to Object.prototype. */ + fun_proto->setProto(obj_proto); + if (!obj->getProto()) + obj->setProto(obj_proto); + + return fun_proto; +} + +JS_PUBLIC_API(JSBool) +JS_InitStandardClasses(JSContext *cx, JSObject *obj) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + + /* + * JS_SetGlobalObject might or might not change cx's compartment, so call + * it before assertSameCompartment. (The API contract is that *after* this, + * cx and obj must be in the same compartment.) + */ + if (!cx->globalObject) + JS_SetGlobalObject(cx, obj); + assertSameCompartment(cx, obj); + + /* Define a top-level property 'undefined' with the undefined value. */ + JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID]; + if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(), + PropertyStub, StrictPropertyStub, + JSPROP_PERMANENT | JSPROP_READONLY)) { + return JS_FALSE; + } + + /* Function and Object require cooperative bootstrapping magic. */ + if (!js_InitFunctionAndObjectClasses(cx, obj)) + return JS_FALSE; + + /* Initialize the rest of the standard objects and functions. */ + return js_InitArrayClass(cx, obj) && + js_InitBooleanClass(cx, obj) && + js_InitExceptionClasses(cx, obj) && + js_InitMathClass(cx, obj) && + js_InitNumberClass(cx, obj) && + js_InitJSONClass(cx, obj) && + js_InitRegExpClass(cx, obj) && + js_InitStringClass(cx, obj) && + js_InitTypedArrayClasses(cx, obj) && +#if JS_HAS_XML_SUPPORT + js_InitXMLClasses(cx, obj) && +#endif +#if JS_HAS_GENERATORS + js_InitIteratorClasses(cx, obj) && +#endif + js_InitDateClass(cx, obj) && + js_InitProxyClass(cx, obj); +} + +#define CLASP(name) (&js_##name##Class) +#define TYPED_ARRAY_CLASP(type) (&TypedArray::fastClasses[TypedArray::type]) +#define EAGER_ATOM(name) ATOM_OFFSET(name), NULL +#define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL +#define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name) +#define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str + +typedef struct JSStdName { + JSObjectOp init; + size_t atomOffset; /* offset of atom pointer in JSAtomState */ + const char *name; /* null if atom is pre-pinned, else name */ + Class *clasp; +} JSStdName; + +static JSAtom * +StdNameToAtom(JSContext *cx, JSStdName *stdn) +{ + size_t offset; + JSAtom *atom; + const char *name; + + offset = stdn->atomOffset; + atom = OFFSET_TO_ATOM(cx->runtime, offset); + if (!atom) { + name = stdn->name; + if (name) { + atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED); + OFFSET_TO_ATOM(cx->runtime, offset) = atom; + } + } + return atom; +} + +/* + * Table of class initializers and their atom offsets in rt->atomState. + * If you add a "standard" class, remember to update this table. + */ +static JSStdName standard_class_atoms[] = { + {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Function)}, + {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Object)}, + {js_InitArrayClass, EAGER_ATOM_AND_CLASP(Array)}, + {js_InitBooleanClass, EAGER_ATOM_AND_CLASP(Boolean)}, + {js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)}, + {js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)}, + {js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)}, + {js_InitStringClass, EAGER_ATOM_AND_CLASP(String)}, + {js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)}, + {js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)}, +#if JS_HAS_XML_SUPPORT + {js_InitXMLClass, EAGER_ATOM_AND_CLASP(XML)}, + {js_InitNamespaceClass, EAGER_ATOM_AND_CLASP(Namespace)}, + {js_InitQNameClass, EAGER_ATOM_AND_CLASP(QName)}, +#endif +#if JS_HAS_GENERATORS + {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)}, +#endif + {js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)}, + {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass}, + {NULL, 0, NULL, NULL} +}; + +/* + * Table of top-level function and constant names and their init functions. + * If you add a "standard" global function or property, remember to update + * this table. + */ +static JSStdName standard_class_names[] = { + {js_InitObjectClass, EAGER_ATOM(eval), CLASP(Object)}, + + /* Global properties and functions defined by the Number class. */ + {js_InitNumberClass, EAGER_ATOM(NaN), CLASP(Number)}, + {js_InitNumberClass, EAGER_ATOM(Infinity), CLASP(Number)}, + {js_InitNumberClass, LAZY_ATOM(isNaN), CLASP(Number)}, + {js_InitNumberClass, LAZY_ATOM(isFinite), CLASP(Number)}, + {js_InitNumberClass, LAZY_ATOM(parseFloat), CLASP(Number)}, + {js_InitNumberClass, LAZY_ATOM(parseInt), CLASP(Number)}, + + /* String global functions. */ + {js_InitStringClass, LAZY_ATOM(escape), CLASP(String)}, + {js_InitStringClass, LAZY_ATOM(unescape), CLASP(String)}, + {js_InitStringClass, LAZY_ATOM(decodeURI), CLASP(String)}, + {js_InitStringClass, LAZY_ATOM(encodeURI), CLASP(String)}, + {js_InitStringClass, LAZY_ATOM(decodeURIComponent), CLASP(String)}, + {js_InitStringClass, LAZY_ATOM(encodeURIComponent), CLASP(String)}, +#if JS_HAS_UNEVAL + {js_InitStringClass, LAZY_ATOM(uneval), CLASP(String)}, +#endif + + /* Exception constructors. */ + {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), CLASP(Error)}, + {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), CLASP(Error)}, + +#if JS_HAS_XML_SUPPORT + {js_InitXMLClass, LAZY_ATOM(XMLList), CLASP(XML)}, + {js_InitXMLClass, LAZY_ATOM(isXMLName), CLASP(XML)}, +#endif + +#if JS_HAS_GENERATORS + {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)}, + {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Generator)}, +#endif + + /* Typed Arrays */ + {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass}, + {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int8Array), TYPED_ARRAY_CLASP(TYPE_INT8)}, + {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8Array), TYPED_ARRAY_CLASP(TYPE_UINT8)}, + {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int16Array), TYPED_ARRAY_CLASP(TYPE_INT16)}, + {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint16Array), TYPED_ARRAY_CLASP(TYPE_UINT16)}, + {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int32Array), TYPED_ARRAY_CLASP(TYPE_INT32)}, + {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint32Array), TYPED_ARRAY_CLASP(TYPE_UINT32)}, + {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float32Array), TYPED_ARRAY_CLASP(TYPE_FLOAT32)}, + {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)}, + {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8ClampedArray), + TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)}, + + {js_InitProxyClass, EAGER_ATOM_AND_CLASP(Proxy)}, + + {NULL, 0, NULL, NULL} +}; + +static JSStdName object_prototype_names[] = { + /* Object.prototype properties (global delegates to Object.prototype). */ + {js_InitObjectClass, EAGER_ATOM(proto), CLASP(Object)}, +#if JS_HAS_TOSOURCE + {js_InitObjectClass, EAGER_ATOM(toSource), CLASP(Object)}, +#endif + {js_InitObjectClass, EAGER_ATOM(toString), CLASP(Object)}, + {js_InitObjectClass, EAGER_ATOM(toLocaleString), CLASP(Object)}, + {js_InitObjectClass, EAGER_ATOM(valueOf), CLASP(Object)}, +#if JS_HAS_OBJ_WATCHPOINT + {js_InitObjectClass, LAZY_ATOM(watch), CLASP(Object)}, + {js_InitObjectClass, LAZY_ATOM(unwatch), CLASP(Object)}, +#endif + {js_InitObjectClass, LAZY_ATOM(hasOwnProperty), CLASP(Object)}, + {js_InitObjectClass, LAZY_ATOM(isPrototypeOf), CLASP(Object)}, + {js_InitObjectClass, LAZY_ATOM(propertyIsEnumerable), CLASP(Object)}, +#if OLD_GETTER_SETTER_METHODS + {js_InitObjectClass, LAZY_ATOM(defineGetter), CLASP(Object)}, + {js_InitObjectClass, LAZY_ATOM(defineSetter), CLASP(Object)}, + {js_InitObjectClass, LAZY_ATOM(lookupGetter), CLASP(Object)}, + {js_InitObjectClass, LAZY_ATOM(lookupSetter), CLASP(Object)}, +#endif + + {NULL, 0, NULL, NULL} +}; + +JS_PUBLIC_API(JSBool) +JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved) +{ + JSString *idstr; + JSRuntime *rt; + JSAtom *atom; + JSStdName *stdnm; + uintN i; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id); + *resolved = JS_FALSE; + + rt = cx->runtime; + JS_ASSERT(rt->state != JSRTS_DOWN); + if (rt->state == JSRTS_LANDING || !JSID_IS_ATOM(id)) + return JS_TRUE; + + idstr = JSID_TO_STRING(id); + + /* Check whether we're resolving 'undefined', and define it if so. */ + atom = rt->atomState.typeAtoms[JSTYPE_VOID]; + if (idstr == ATOM_TO_STRING(atom)) { + *resolved = JS_TRUE; + return obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(), + PropertyStub, StrictPropertyStub, + JSPROP_PERMANENT | JSPROP_READONLY); + } + + /* Try for class constructors/prototypes named by well-known atoms. */ + stdnm = NULL; + for (i = 0; standard_class_atoms[i].init; i++) { + JS_ASSERT(standard_class_atoms[i].clasp); + atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset); + if (idstr == ATOM_TO_STRING(atom)) { + stdnm = &standard_class_atoms[i]; + break; + } + } + + if (!stdnm) { + /* Try less frequently used top-level functions and constants. */ + for (i = 0; standard_class_names[i].init; i++) { + JS_ASSERT(standard_class_names[i].clasp); + atom = StdNameToAtom(cx, &standard_class_names[i]); + if (!atom) + return JS_FALSE; + if (idstr == ATOM_TO_STRING(atom)) { + stdnm = &standard_class_names[i]; + break; + } + } + + if (!stdnm && !obj->getProto()) { + /* + * Try even less frequently used names delegated from the global + * object to Object.prototype, but only if the Object class hasn't + * yet been initialized. + */ + for (i = 0; object_prototype_names[i].init; i++) { + JS_ASSERT(object_prototype_names[i].clasp); + atom = StdNameToAtom(cx, &object_prototype_names[i]); + if (!atom) + return JS_FALSE; + if (idstr == ATOM_TO_STRING(atom)) { + stdnm = &object_prototype_names[i]; + break; + } + } + } + } + + if (stdnm) { + /* + * If this standard class is anonymous, then we don't want to resolve + * by name. + */ + JS_ASSERT(obj->isGlobal()); + if (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS) + return JS_TRUE; + + JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(stdnm->clasp); + if (obj->getReservedSlot(key).isObject()) + return JS_TRUE; + + if (!stdnm->init(cx, obj)) + return JS_FALSE; + *resolved = JS_TRUE; + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj) +{ + JSRuntime *rt; + JSAtom *atom; + uintN i; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + rt = cx->runtime; + + /* Check whether we need to bind 'undefined' and define it if so. */ + atom = rt->atomState.typeAtoms[JSTYPE_VOID]; + if (!obj->nativeContains(ATOM_TO_JSID(atom)) && + !obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(), + PropertyStub, StrictPropertyStub, + JSPROP_PERMANENT | JSPROP_READONLY)) { + return JS_FALSE; + } + + /* Initialize any classes that have not been resolved yet. */ + for (i = 0; standard_class_atoms[i].init; i++) { + atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset); + if (!obj->nativeContains(ATOM_TO_JSID(atom)) && + !standard_class_atoms[i].init(cx, obj)) { + return JS_FALSE; + } + } + + return JS_TRUE; +} + +namespace js { + +JSIdArray * +NewIdArray(JSContext *cx, jsint length) +{ + JSIdArray *ida; + + ida = (JSIdArray *) + cx->calloc(offsetof(JSIdArray, vector) + length * sizeof(jsval)); + if (ida) + ida->length = length; + return ida; +} + +} + +/* + * Unlike realloc(3), this function frees ida on failure. + */ +static JSIdArray * +SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length) +{ + JSIdArray *rida; + + rida = (JSIdArray *) + JS_realloc(cx, ida, + offsetof(JSIdArray, vector) + length * sizeof(jsval)); + if (!rida) { + JS_DestroyIdArray(cx, ida); + } else { + rida->length = length; + } + return rida; +} + +static JSIdArray * +AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip) +{ + jsint i, length; + + i = *ip; + length = ida->length; + if (i >= length) { + ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8)); + if (!ida) + return NULL; + JS_ASSERT(i < ida->length); + } + ida->vector[i] = ATOM_TO_JSID(atom); + *ip = i + 1; + return ida; +} + +static JSIdArray * +EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida, + jsint *ip, JSBool *foundp) +{ + *foundp = obj->nativeContains(ATOM_TO_JSID(atom)); + if (*foundp) + ida = AddAtomToArray(cx, atom, ida, ip); + return ida; +} + +JS_PUBLIC_API(JSIdArray *) +JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, JSIdArray *ida) +{ + JSRuntime *rt; + jsint i, j, k; + JSAtom *atom; + JSBool found; + JSObjectOp init; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, ida); + rt = cx->runtime; + if (ida) { + i = ida->length; + } else { + ida = NewIdArray(cx, 8); + if (!ida) + return NULL; + i = 0; + } + + /* Check whether 'undefined' has been resolved and enumerate it if so. */ + atom = rt->atomState.typeAtoms[JSTYPE_VOID]; + ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found); + if (!ida) + return NULL; + + /* Enumerate only classes that *have* been resolved. */ + for (j = 0; standard_class_atoms[j].init; j++) { + atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset); + ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found); + if (!ida) + return NULL; + + if (found) { + init = standard_class_atoms[j].init; + + for (k = 0; standard_class_names[k].init; k++) { + if (standard_class_names[k].init == init) { + atom = StdNameToAtom(cx, &standard_class_names[k]); + ida = AddAtomToArray(cx, atom, ida, &i); + if (!ida) + return NULL; + } + } + + if (init == js_InitObjectClass) { + for (k = 0; object_prototype_names[k].init; k++) { + atom = StdNameToAtom(cx, &object_prototype_names[k]); + ida = AddAtomToArray(cx, atom, ida, &i); + if (!ida) + return NULL; + } + } + } + } + + /* Trim to exact length. */ + return SetIdArrayLength(cx, ida, i); +} + +#undef CLASP +#undef EAGER_ATOM +#undef EAGER_CLASS_ATOM +#undef EAGER_ATOM_CLASP +#undef LAZY_ATOM + +JS_PUBLIC_API(JSBool) +JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject **objp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + return js_GetClassObject(cx, obj, key, objp); +} + +JS_PUBLIC_API(JSObject *) +JS_GetScopeChain(JSContext *cx) +{ + CHECK_REQUEST(cx); + return GetScopeChain(cx); +} + +JS_PUBLIC_API(JSObject *) +JS_GetGlobalForObject(JSContext *cx, JSObject *obj) +{ + assertSameCompartment(cx, obj); + return obj->getGlobal(); +} + +JS_PUBLIC_API(JSObject *) +JS_GetGlobalForScopeChain(JSContext *cx) +{ + CHECK_REQUEST(cx); + return GetGlobalForScopeChain(cx); +} + +JS_PUBLIC_API(jsval) +JS_ComputeThis(JSContext *cx, jsval *vp) +{ + assertSameCompartment(cx, JSValueArray(vp, 2)); + return BoxThisForVp(cx, Valueify(vp)) ? vp[1] : JSVAL_NULL; +} + +JS_PUBLIC_API(void *) +JS_malloc(JSContext *cx, size_t nbytes) +{ + return cx->malloc(nbytes); +} + +JS_PUBLIC_API(void *) +JS_realloc(JSContext *cx, void *p, size_t nbytes) +{ + return cx->realloc(p, nbytes); +} + +JS_PUBLIC_API(void) +JS_free(JSContext *cx, void *p) +{ + return cx->free(p); +} + +JS_PUBLIC_API(void) +JS_updateMallocCounter(JSContext *cx, size_t nbytes) +{ + return cx->runtime->updateMallocCounter(nbytes); +} + +JS_PUBLIC_API(char *) +JS_strdup(JSContext *cx, const char *s) +{ + size_t n; + void *p; + + n = strlen(s) + 1; + p = cx->malloc(n); + if (!p) + return NULL; + return (char *)memcpy(p, s, n); +} + +JS_PUBLIC_API(JSBool) +JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval) +{ + d = JS_CANONICALIZE_NAN(d); + Valueify(rval)->setNumber(d); + return JS_TRUE; +} + +#undef JS_AddRoot + +JS_PUBLIC_API(JSBool) +JS_AddValueRoot(JSContext *cx, jsval *vp) +{ + CHECK_REQUEST(cx); + return js_AddRoot(cx, Valueify(vp), NULL); +} + +JS_PUBLIC_API(JSBool) +JS_AddStringRoot(JSContext *cx, JSString **rp) +{ + CHECK_REQUEST(cx); + return js_AddGCThingRoot(cx, (void **)rp, NULL); +} + +JS_PUBLIC_API(JSBool) +JS_AddObjectRoot(JSContext *cx, JSObject **rp) +{ + CHECK_REQUEST(cx); + return js_AddGCThingRoot(cx, (void **)rp, NULL); +} + +JS_PUBLIC_API(JSBool) +JS_AddGCThingRoot(JSContext *cx, void **rp) +{ + CHECK_REQUEST(cx); + return js_AddGCThingRoot(cx, (void **)rp, NULL); +} + +JS_PUBLIC_API(JSBool) +JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name) +{ + CHECK_REQUEST(cx); + return js_AddRoot(cx, Valueify(vp), name); +} + +JS_PUBLIC_API(JSBool) +JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name) +{ + CHECK_REQUEST(cx); + return js_AddGCThingRoot(cx, (void **)rp, name); +} + +JS_PUBLIC_API(JSBool) +JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name) +{ + CHECK_REQUEST(cx); + return js_AddGCThingRoot(cx, (void **)rp, name); +} + +JS_PUBLIC_API(JSBool) +JS_AddNamedGCThingRoot(JSContext *cx, void **rp, const char *name) +{ + CHECK_REQUEST(cx); + return js_AddGCThingRoot(cx, (void **)rp, name); +} + +JS_PUBLIC_API(JSBool) +JS_RemoveValueRoot(JSContext *cx, jsval *vp) +{ + CHECK_REQUEST(cx); + return js_RemoveRoot(cx->runtime, (void *)vp); +} + +JS_PUBLIC_API(JSBool) +JS_RemoveStringRoot(JSContext *cx, JSString **rp) +{ + CHECK_REQUEST(cx); + return js_RemoveRoot(cx->runtime, (void *)rp); +} + +JS_PUBLIC_API(JSBool) +JS_RemoveObjectRoot(JSContext *cx, JSObject **rp) +{ + CHECK_REQUEST(cx); + return js_RemoveRoot(cx->runtime, (void *)rp); +} + +JS_PUBLIC_API(JSBool) +JS_RemoveGCThingRoot(JSContext *cx, void **rp) +{ + CHECK_REQUEST(cx); + return js_RemoveRoot(cx->runtime, (void *)rp); +} + +JS_NEVER_INLINE JS_PUBLIC_API(void) +JS_AnchorPtr(void *p) +{ +} + +#ifdef DEBUG + +JS_PUBLIC_API(void) +JS_DumpNamedRoots(JSRuntime *rt, + void (*dump)(const char *name, void *rp, JSGCRootType type, void *data), + void *data) +{ + js_DumpNamedRoots(rt, dump, data); +} + +#endif /* DEBUG */ + +JS_PUBLIC_API(uint32) +JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data) +{ + return js_MapGCRoots(rt, map, data); +} + +JS_PUBLIC_API(JSBool) +JS_LockGCThing(JSContext *cx, void *thing) +{ + JSBool ok; + + CHECK_REQUEST(cx); + ok = js_LockGCThingRT(cx->runtime, thing); + if (!ok) + JS_ReportOutOfMemory(cx); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_LockGCThingRT(JSRuntime *rt, void *thing) +{ + return js_LockGCThingRT(rt, thing); +} + +JS_PUBLIC_API(JSBool) +JS_UnlockGCThing(JSContext *cx, void *thing) +{ + CHECK_REQUEST(cx); + js_UnlockGCThingRT(cx->runtime, thing); + return true; +} + +JS_PUBLIC_API(JSBool) +JS_UnlockGCThingRT(JSRuntime *rt, void *thing) +{ + js_UnlockGCThingRT(rt, thing); + return true; +} + +JS_PUBLIC_API(void) +JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data) +{ + rt->gcExtraRootsTraceOp = traceOp; + rt->gcExtraRootsData = data; +} + +JS_PUBLIC_API(void) +JS_TraceRuntime(JSTracer *trc) +{ + TraceRuntime(trc); +} + +JS_PUBLIC_API(void) +JS_CallTracer(JSTracer *trc, void *thing, uint32 kind) +{ + JS_ASSERT(thing); + MarkKind(trc, thing, kind); +} + +#ifdef DEBUG + +#ifdef HAVE_XPCONNECT +#include "dump_xpc.h" +#endif + +JS_PUBLIC_API(void) +JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, uint32 kind, + JSBool details) +{ + const char *name; + size_t n; + + if (bufsize == 0) + return; + + switch (kind) { + case JSTRACE_OBJECT: + { + JSObject *obj = (JSObject *)thing; + Class *clasp = obj->getClass(); + + name = clasp->name; +#ifdef HAVE_XPCONNECT + if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) { + void *privateThing = obj->getPrivate(); + if (privateThing) { + const char *xpcClassName = GetXPCObjectClassName(privateThing); + if (xpcClassName) + name = xpcClassName; + } + } +#endif + break; + } + + case JSTRACE_STRING: + name = ((JSString *)thing)->isDependent() + ? "substring" + : "string"; + break; + +#if JS_HAS_XML_SUPPORT + case JSTRACE_XML: + name = "xml"; + break; +#endif + default: + JS_ASSERT(0); + return; + break; + } + + n = strlen(name); + if (n > bufsize - 1) + n = bufsize - 1; + memcpy(buf, name, n + 1); + buf += n; + bufsize -= n; + + if (details && bufsize > 2) { + *buf++ = ' '; + bufsize--; + + switch (kind) { + case JSTRACE_OBJECT: + { + JSObject *obj = (JSObject *)thing; + Class *clasp = obj->getClass(); + if (clasp == &js_FunctionClass) { + JSFunction *fun = GET_FUNCTION_PRIVATE(trc->context, obj); + if (!fun) { + JS_snprintf(buf, bufsize, ""); + } else if (FUN_OBJECT(fun) != obj) { + JS_snprintf(buf, bufsize, "%p", fun); + } else { + if (fun->atom) + PutEscapedString(buf, bufsize, ATOM_TO_STRING(fun->atom), 0); + } + } else if (clasp->flags & JSCLASS_HAS_PRIVATE) { + JS_snprintf(buf, bufsize, "%p", obj->getPrivate()); + } else { + JS_snprintf(buf, bufsize, ""); + } + break; + } + + case JSTRACE_STRING: + { + JSString *str = (JSString *)thing; + if (str->isLinear()) + PutEscapedString(buf, bufsize, str->assertIsLinear(), 0); + else + JS_snprintf(buf, bufsize, "", (int)str->length()); + break; + } + +#if JS_HAS_XML_SUPPORT + case JSTRACE_XML: + { + extern const char *js_xml_class_str[]; + JSXML *xml = (JSXML *)thing; + + JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]); + break; + } +#endif + default: + JS_ASSERT(0); + break; + } + } + buf[bufsize - 1] = '\0'; +} + +typedef struct JSHeapDumpNode JSHeapDumpNode; + +struct JSHeapDumpNode { + void *thing; + uint32 kind; + JSHeapDumpNode *next; /* next sibling */ + JSHeapDumpNode *parent; /* node with the thing that refer to thing + from this node */ + char edgeName[1]; /* name of the edge from parent->thing + into thing */ +}; + +typedef struct JSDumpingTracer { + JSTracer base; + JSDHashTable visited; + JSBool ok; + void *startThing; + void *thingToFind; + void *thingToIgnore; + JSHeapDumpNode *parentNode; + JSHeapDumpNode **lastNodep; + char buffer[200]; +} JSDumpingTracer; + +static void +DumpNotify(JSTracer *trc, void *thing, uint32 kind) +{ + JSDumpingTracer *dtrc; + JSContext *cx; + JSDHashEntryStub *entry; + JSHeapDumpNode *node; + const char *edgeName; + size_t edgeNameSize; + + JS_ASSERT(trc->callback == DumpNotify); + dtrc = (JSDumpingTracer *)trc; + + if (!dtrc->ok || thing == dtrc->thingToIgnore) + return; + + cx = trc->context; + + /* + * Check if we have already seen thing unless it is thingToFind to include + * it to the graph each time we reach it and print all live things that + * refer to thingToFind. + * + * This does not print all possible paths leading to thingToFind since + * when a thing A refers directly or indirectly to thingToFind and A is + * present several times in the graph, we will print only the first path + * leading to A and thingToFind, other ways to reach A will be ignored. + */ + if (dtrc->thingToFind != thing) { + /* + * The startThing check allows to avoid putting startThing into the + * hash table before tracing startThing in JS_DumpHeap. + */ + if (thing == dtrc->startThing) + return; + entry = (JSDHashEntryStub *) + JS_DHashTableOperate(&dtrc->visited, thing, JS_DHASH_ADD); + if (!entry) { + JS_ReportOutOfMemory(cx); + dtrc->ok = JS_FALSE; + return; + } + if (entry->key) + return; + entry->key = thing; + } + + if (dtrc->base.debugPrinter) { + dtrc->base.debugPrinter(trc, dtrc->buffer, sizeof(dtrc->buffer)); + edgeName = dtrc->buffer; + } else if (dtrc->base.debugPrintIndex != (size_t)-1) { + JS_snprintf(dtrc->buffer, sizeof(dtrc->buffer), "%s[%lu]", + (const char *)dtrc->base.debugPrintArg, + dtrc->base.debugPrintIndex); + edgeName = dtrc->buffer; + } else { + edgeName = (const char*)dtrc->base.debugPrintArg; + } + + edgeNameSize = strlen(edgeName) + 1; + node = (JSHeapDumpNode *) js_malloc(offsetof(JSHeapDumpNode, edgeName) + edgeNameSize); + if (!node) { + dtrc->ok = JS_FALSE; + return; + } + + node->thing = thing; + node->kind = kind; + node->next = NULL; + node->parent = dtrc->parentNode; + memcpy(node->edgeName, edgeName, edgeNameSize); + + JS_ASSERT(!*dtrc->lastNodep); + *dtrc->lastNodep = node; + dtrc->lastNodep = &node->next; +} + +/* Dump node and the chain that leads to thing it contains. */ +static JSBool +DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node) +{ + JSHeapDumpNode *prev, *following; + size_t chainLimit; + JSBool ok; + enum { MAX_PARENTS_TO_PRINT = 10 }; + + JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer, + &dtrc->base, node->thing, node->kind, JS_TRUE); + if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0) + return JS_FALSE; + + /* + * We need to print the parent chain in the reverse order. To do it in + * O(N) time where N is the chain length we first reverse the chain while + * searching for the top and then print each node while restoring the + * chain order. + */ + chainLimit = MAX_PARENTS_TO_PRINT; + prev = NULL; + for (;;) { + following = node->parent; + node->parent = prev; + prev = node; + node = following; + if (!node) + break; + if (chainLimit == 0) { + if (fputs("...", fp) < 0) + return JS_FALSE; + break; + } + --chainLimit; + } + + node = prev; + prev = following; + ok = JS_TRUE; + do { + /* Loop must continue even when !ok to restore the parent chain. */ + if (ok) { + if (!prev) { + /* Print edge from some runtime root or startThing. */ + if (fputs(node->edgeName, fp) < 0) + ok = JS_FALSE; + } else { + JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer, + &dtrc->base, prev->thing, prev->kind, + JS_FALSE); + if (fprintf(fp, "(%p %s).%s", + prev->thing, dtrc->buffer, node->edgeName) < 0) { + ok = JS_FALSE; + } + } + } + following = node->parent; + node->parent = prev; + prev = node; + node = following; + } while (node); + + return ok && putc('\n', fp) >= 0; +} + +JS_PUBLIC_API(JSBool) +JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind, + void *thingToFind, size_t maxDepth, void *thingToIgnore) +{ + JSDumpingTracer dtrc; + JSHeapDumpNode *node, *children, *next, *parent; + size_t depth; + JSBool thingToFindWasTraced; + + if (maxDepth == 0) + return JS_TRUE; + + JS_TRACER_INIT(&dtrc.base, cx, DumpNotify); + if (!JS_DHashTableInit(&dtrc.visited, JS_DHashGetStubOps(), + NULL, sizeof(JSDHashEntryStub), + JS_DHASH_DEFAULT_CAPACITY(100))) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + dtrc.ok = JS_TRUE; + dtrc.startThing = startThing; + dtrc.thingToFind = thingToFind; + dtrc.thingToIgnore = thingToIgnore; + dtrc.parentNode = NULL; + node = NULL; + dtrc.lastNodep = &node; + if (!startThing) { + JS_ASSERT(startKind == 0); + TraceRuntime(&dtrc.base); + } else { + JS_TraceChildren(&dtrc.base, startThing, startKind); + } + + depth = 1; + if (!node) + goto dump_out; + + thingToFindWasTraced = thingToFind && thingToFind == startThing; + for (;;) { + /* + * Loop must continue even when !dtrc.ok to free all nodes allocated + * so far. + */ + if (dtrc.ok) { + if (thingToFind == NULL || thingToFind == node->thing) + dtrc.ok = DumpNode(&dtrc, fp, node); + + /* Descend into children. */ + if (dtrc.ok && + depth < maxDepth && + (thingToFind != node->thing || !thingToFindWasTraced)) { + dtrc.parentNode = node; + children = NULL; + dtrc.lastNodep = &children; + JS_TraceChildren(&dtrc.base, node->thing, node->kind); + if (thingToFind == node->thing) + thingToFindWasTraced = JS_TRUE; + if (children != NULL) { + ++depth; + node = children; + continue; + } + } + } + + /* Move to next or parents next and free the node. */ + for (;;) { + next = node->next; + parent = node->parent; + js_free(node); + node = next; + if (node) + break; + if (!parent) + goto dump_out; + JS_ASSERT(depth > 1); + --depth; + node = parent; + } + } + + dump_out: + JS_ASSERT(depth == 1); + JS_DHashTableFinish(&dtrc.visited); + return dtrc.ok; +} + +#endif /* DEBUG */ + +JS_PUBLIC_API(void) +JS_MarkGCThing(JSContext *cx, jsval v, const char *name, void *arg) +{ + JSTracer *trc; + + trc = (JSTracer *)arg; + if (!trc) + trc = cx->runtime->gcMarkingTracer; + else + JS_ASSERT(trc == cx->runtime->gcMarkingTracer); + +#ifdef JS_THREADSAFE + JS_ASSERT(cx->runtime->gcThread == trc->context->thread); +#endif + MarkValue(trc, Valueify(v), name ? name : "unknown"); +} + +extern JS_PUBLIC_API(JSBool) +JS_IsGCMarkingTracer(JSTracer *trc) +{ + return IS_GC_MARKING_TRACER(trc); +} + +JS_PUBLIC_API(void) +JS_GC(JSContext *cx) +{ + LeaveTrace(cx); + + /* Don't nuke active arenas if executing or compiling. */ + if (cx->tempPool.current == &cx->tempPool.first) + JS_FinishArenaPool(&cx->tempPool); + js_GC(cx, NULL, GC_NORMAL); +} + +JS_PUBLIC_API(void) +JS_MaybeGC(JSContext *cx) +{ + LeaveTrace(cx); + + /* Don't nuke active arenas if executing or compiling. */ + if (cx->tempPool.current == &cx->tempPool.first) + JS_FinishArenaPool(&cx->tempPool); + + MaybeGC(cx); +} + +JS_PUBLIC_API(JSGCCallback) +JS_SetGCCallback(JSContext *cx, JSGCCallback cb) +{ + CHECK_REQUEST(cx); + return JS_SetGCCallbackRT(cx->runtime, cb); +} + +JS_PUBLIC_API(JSGCCallback) +JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb) +{ + JSGCCallback oldcb; + + oldcb = rt->gcCallback; + rt->gcCallback = cb; + return oldcb; +} + +JS_PUBLIC_API(JSBool) +JS_IsAboutToBeFinalized(JSContext *cx, void *thing) +{ + JS_ASSERT(thing); + JS_ASSERT(!cx->runtime->gcMarkingTracer); + return IsAboutToBeFinalized(cx, thing); +} + +JS_PUBLIC_API(void) +JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value) +{ + switch (key) { + case JSGC_MAX_BYTES: + rt->gcMaxBytes = value; + break; + case JSGC_MAX_MALLOC_BYTES: + rt->setGCMaxMallocBytes(value); + break; + case JSGC_STACKPOOL_LIFESPAN: + rt->gcEmptyArenaPoolLifespan = value; + break; + case JSGC_MODE: + rt->gcMode = JSGCMode(value); + JS_ASSERT(rt->gcMode == JSGC_MODE_GLOBAL || + rt->gcMode == JSGC_MODE_COMPARTMENT); + break; + default: + JS_ASSERT(key == JSGC_TRIGGER_FACTOR); + JS_ASSERT(value >= 100); + rt->setGCTriggerFactor(value); + return; + } +} + +JS_PUBLIC_API(uint32) +JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key) +{ + switch (key) { + case JSGC_MAX_BYTES: + return rt->gcMaxBytes; + case JSGC_MAX_MALLOC_BYTES: + return rt->gcMaxMallocBytes; + case JSGC_STACKPOOL_LIFESPAN: + return rt->gcEmptyArenaPoolLifespan; + case JSGC_TRIGGER_FACTOR: + return rt->gcTriggerFactor; + case JSGC_BYTES: + return rt->gcBytes; + case JSGC_MODE: + return uint32(rt->gcMode); + case JSGC_UNUSED_CHUNKS: + return uint32(rt->gcChunksWaitingToExpire); + default: + JS_ASSERT(key == JSGC_NUMBER); + return rt->gcNumber; + } +} + +JS_PUBLIC_API(void) +JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32 value) +{ + JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES); +#ifdef JS_TRACER + SetMaxCodeCacheBytes(cx, value); +#endif +} + +JS_PUBLIC_API(uint32) +JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key) +{ + JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES); +#ifdef JS_TRACER + return JS_THREAD_DATA(cx)->maxCodeCacheBytes; +#else + return 0; +#endif +} + +JS_PUBLIC_API(void) +JS_FlushCaches(JSContext *cx) +{ +#ifdef JS_TRACER + FlushJITCache(cx, &cx->compartment->traceMonitor); +#endif +} + +JS_PUBLIC_API(intN) +JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer) +{ + return JSExternalString::changeFinalizer(NULL, finalizer); +} + +JS_PUBLIC_API(intN) +JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer) +{ + return JSExternalString::changeFinalizer(finalizer, NULL); +} + +JS_PUBLIC_API(JSString *) +JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type) +{ + CHECK_REQUEST(cx); + JS_ASSERT(uintN(type) < JSExternalString::TYPE_LIMIT); + + JSExternalString *str = js_NewGCExternalString(cx, uintN(type)); + if (!str) + return NULL; + str->initFlat(chars, length); + str->externalStringType = type; + cx->runtime->updateMallocCounter((length + 1) * sizeof(jschar)); + return str; +} + +JS_PUBLIC_API(intN) +JS_GetExternalStringGCType(JSRuntime *rt, JSString *str) +{ + /* + * No need to test this in js_GetExternalStringGCType, which asserts its + * inverse instead of wasting cycles on testing a condition we can ensure + * by auditing in-VM calls to the js_... helper. + */ + if (JSString::isStatic(str)) + return -1; + + return js_GetExternalStringGCType(str); +} + +JS_PUBLIC_API(void) +JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr) +{ +#if JS_STACK_GROWTH_DIRECTION > 0 + if (limitAddr == 0) + limitAddr = jsuword(-1); +#endif + cx->stackLimit = limitAddr; +} + +JS_PUBLIC_API(void) +JS_SetNativeStackQuota(JSContext *cx, size_t stackSize) +{ +#ifdef JS_THREADSAFE + JS_ASSERT(cx->thread); +#endif + +#if JS_STACK_GROWTH_DIRECTION > 0 + if (stackSize == 0) { + cx->stackLimit = jsuword(-1); + } else { + jsuword stackBase = reinterpret_cast(JS_THREAD_DATA(cx)->nativeStackBase); + JS_ASSERT(stackBase <= size_t(-1) - stackSize); + cx->stackLimit = stackBase + stackSize - 1; + } +#else + if (stackSize == 0) { + cx->stackLimit = 0; + } else { + jsuword stackBase = reinterpret_cast(JS_THREAD_DATA(cx)->nativeStackBase); + JS_ASSERT(stackBase >= stackSize); + cx->stackLimit = stackBase - (stackSize - 1); + } +#endif +} + +JS_PUBLIC_API(void) +JS_SetScriptStackQuota(JSContext *cx, size_t quota) +{ + cx->scriptStackQuota = quota; +} + +/************************************************************************/ + +JS_PUBLIC_API(void) +JS_DestroyIdArray(JSContext *cx, JSIdArray *ida) +{ + cx->free(ida); +} + +JS_PUBLIC_API(JSBool) +JS_ValueToId(JSContext *cx, jsval v, jsid *idp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + return ValueToId(cx, Valueify(v), idp); +} + +JS_PUBLIC_API(JSBool) +JS_IdToValue(JSContext *cx, jsid id, jsval *vp) +{ + CHECK_REQUEST(cx); + *vp = IdToJsval(id); + assertSameCompartment(cx, *vp); + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_StrictPropertyStub(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +{ + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_EnumerateStub(JSContext *cx, JSObject *obj) +{ + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_ResolveStub(JSContext *cx, JSObject *obj, jsid id) +{ + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp) +{ + JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION); + return js_TryValueOf(cx, obj, type, Valueify(vp)); +} + +JS_PUBLIC_API(void) +JS_FinalizeStub(JSContext *cx, JSObject *obj) +{} + +JS_PUBLIC_API(JSObject *) +JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, + JSClass *clasp, JSNative constructor, uintN nargs, + JSPropertySpec *ps, JSFunctionSpec *fs, + JSPropertySpec *static_ps, JSFunctionSpec *static_fs) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, parent_proto); + return js_InitClass(cx, obj, parent_proto, Valueify(clasp), + Valueify(constructor), nargs, + ps, fs, static_ps, static_fs); +} + +#ifdef JS_THREADSAFE +JS_PUBLIC_API(JSClass *) +JS_GetClass(JSContext *cx, JSObject *obj) +{ + return Jsvalify(obj->getClass()); +} +#else +JS_PUBLIC_API(JSClass *) +JS_GetClass(JSObject *obj) +{ + return Jsvalify(obj->getClass()); +} +#endif + +JS_PUBLIC_API(JSBool) +JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + return InstanceOf(cx, obj, Valueify(clasp), Valueify(argv)); +} + +JS_PUBLIC_API(JSBool) +JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +{ + assertSameCompartment(cx, obj, v); + return HasInstance(cx, obj, Valueify(&v), bp); +} + +JS_PUBLIC_API(void *) +JS_GetPrivate(JSContext *cx, JSObject *obj) +{ + return obj->getPrivate(); +} + +JS_PUBLIC_API(JSBool) +JS_SetPrivate(JSContext *cx, JSObject *obj, void *data) +{ + obj->setPrivate(data); + return true; +} + +JS_PUBLIC_API(void *) +JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv) +{ + if (!InstanceOf(cx, obj, Valueify(clasp), Valueify(argv))) + return NULL; + return obj->getPrivate(); +} + +JS_PUBLIC_API(JSObject *) +JS_GetPrototype(JSContext *cx, JSObject *obj) +{ + JSObject *proto; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + proto = obj->getProto(); + + /* Beware ref to dead object (we may be called from obj's finalizer). */ + return proto && proto->map ? proto : NULL; +} + +JS_PUBLIC_API(JSBool) +JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, proto); + return SetProto(cx, obj, proto, JS_FALSE); +} + +JS_PUBLIC_API(JSObject *) +JS_GetParent(JSContext *cx, JSObject *obj) +{ + assertSameCompartment(cx, obj); + JSObject *parent = obj->getParent(); + + /* Beware ref to dead object (we may be called from obj's finalizer). */ + return parent && parent->map ? parent : NULL; +} + +JS_PUBLIC_API(JSBool) +JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent) +{ + CHECK_REQUEST(cx); + JS_ASSERT(parent || !obj->getParent()); + assertSameCompartment(cx, obj, parent); + obj->setParent(parent); + return true; +} + +JS_PUBLIC_API(JSObject *) +JS_GetConstructor(JSContext *cx, JSObject *proto) +{ + Value cval; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, proto); + { + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + + if (!proto->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), &cval)) + return NULL; + } + JSObject *funobj; + if (!IsFunctionObject(cval, &funobj)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR, + proto->getClass()->name); + return NULL; + } + return &cval.toObject(); +} + +JS_PUBLIC_API(JSBool) +JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp) +{ + assertSameCompartment(cx, obj); + *idp = OBJECT_TO_JSID(obj); + return JS_TRUE; +} + +JS_PUBLIC_API(JSObject *) +JS_NewGlobalObject(JSContext *cx, JSClass *clasp) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + JS_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL); + JSObject *obj = NewNonFunction(cx, Valueify(clasp), NULL, NULL); + if (!obj) + return NULL; + + obj->syncSpecialEquality(); + + /* Construct a regexp statics object for this global object. */ + JSObject *res = regexp_statics_construct(cx, obj); + if (!res || + !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_REGEXP_STATICS, ObjectValue(*res)) || + !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_FLAGS, Int32Value(0))) { + return NULL; + } + + return obj; +} + +JS_PUBLIC_API(JSObject *) +JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals) +{ + CHECK_REQUEST(cx); + JSCompartment *compartment = NewCompartment(cx, principals); + if (!compartment) + return NULL; + + JSCompartment *saved = cx->compartment; + cx->compartment = compartment; + JSObject *obj = JS_NewGlobalObject(cx, clasp); + cx->compartment = saved; + + return obj; +} + +JS_PUBLIC_API(JSObject *) +JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + assertSameCompartment(cx, proto, parent); + + Class *clasp = Valueify(jsclasp); + if (!clasp) + clasp = &js_ObjectClass; /* default class is Object */ + + JS_ASSERT(clasp != &js_FunctionClass); + JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL)); + + JSObject *obj = NewNonFunction(cx, clasp, proto, parent); + if (obj) + obj->syncSpecialEquality(); + + JS_ASSERT_IF(obj, obj->getParent()); + return obj; +} + +JS_PUBLIC_API(JSObject *) +JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + assertSameCompartment(cx, proto, parent); + + Class *clasp = Valueify(jsclasp); + if (!clasp) + clasp = &js_ObjectClass; /* default class is Object */ + + JS_ASSERT(clasp != &js_FunctionClass); + JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL)); + + JSObject *obj = NewNonFunction(cx, clasp, proto, parent); + if (obj) + obj->syncSpecialEquality(); + return obj; +} + +JS_PUBLIC_API(JSObject *) +JS_NewObjectForConstructor(JSContext *cx, const jsval *vp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, *vp); + + return js_CreateThis(cx, JSVAL_TO_OBJECT(*vp)); +} + +JS_PUBLIC_API(JSBool) +JS_IsExtensible(JSObject *obj) +{ + return obj->isExtensible(); +} + +JS_PUBLIC_API(JSBool) +JS_FreezeObject(JSContext *cx, JSObject *obj) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + + return obj->freeze(cx); +} + +JS_PUBLIC_API(JSBool) +JS_DeepFreezeObject(JSContext *cx, JSObject *obj) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + + /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */ + if (!obj->isExtensible()) + return true; + + if (!obj->freeze(cx)) + return false; + + /* Walk slots in obj and if any value is a non-null object, seal it. */ + for (uint32 i = 0, n = obj->slotSpan(); i < n; ++i) { + const Value &v = obj->getSlot(i); + if (v.isPrimitive()) + continue; + if (!JS_DeepFreezeObject(cx, &v.toObject())) + return false; + } + + return true; +} + +JS_PUBLIC_API(JSObject *) +JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, proto, parent); + Class *clasp = Valueify(jsclasp); + if (!clasp) + clasp = &js_ObjectClass; /* default class is Object */ + return js_ConstructObject(cx, clasp, proto, parent, 0, NULL); +} + +JS_PUBLIC_API(JSObject *) +JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *proto, + JSObject *parent, uintN argc, jsval *argv) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, proto, parent, JSValueArray(argv, argc)); + Class *clasp = Valueify(jsclasp); + if (!clasp) + clasp = &js_ObjectClass; /* default class is Object */ + return js_ConstructObject(cx, clasp, proto, parent, argc, Valueify(argv)); +} + +static JSBool +LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSObject **objp, JSProperty **propp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id); + + JSAutoResolveFlags rf(cx, flags); + id = js_CheckForStringIndex(id); + return obj->lookupProperty(cx, id, objp, propp); +} + +#define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n)) + +static JSBool +LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, jsid id, + JSProperty *prop, Value *vp) +{ + if (!prop) { + /* XXX bad API: no way to tell "not defined" from "void value" */ + vp->setUndefined(); + return JS_TRUE; + } + + if (obj2->isNative()) { + Shape *shape = (Shape *) prop; + + if (shape->isMethod()) { + AutoShapeRooter root(cx, shape); + vp->setObject(shape->methodObject()); + return !!obj2->methodReadBarrier(cx, *shape, vp); + } + + /* Peek at the native property's slot value, without doing a Get. */ + if (obj2->containsSlot(shape->slot)) { + *vp = obj2->nativeGetSlot(shape->slot); + return true; + } + } else { + if (obj2->isDenseArray()) + return js_GetDenseArrayElementValue(cx, obj2, id, vp); + if (obj2->isProxy()) { + AutoPropertyDescriptorRooter desc(cx); + if (!JSProxy::getPropertyDescriptor(cx, obj2, id, false, &desc)) + return false; + if (!(desc.attrs & JSPROP_SHARED)) { + *vp = desc.value; + return true; + } + } + } + + /* XXX bad API: no way to return "defined but value unknown" */ + vp->setBoolean(true); + return true; +} + +JS_PUBLIC_API(JSBool) +JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + JSObject *obj2; + JSProperty *prop; + return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) && + LookupResult(cx, obj, obj2, id, prop, Valueify(vp)); +} + +JS_PUBLIC_API(JSBool) +JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp) +{ + return JS_LookupPropertyById(cx, obj, INT_TO_JSID(index), vp); +} + +JS_PUBLIC_API(JSBool) +JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp) +{ + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp); +} + +JS_PUBLIC_API(JSBool) +JS_LookupUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp) +{ + JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp); +} + +JS_PUBLIC_API(JSBool) +JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSObject **objp, jsval *vp) +{ + JSBool ok; + JSProperty *prop; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id); + ok = obj->isNative() + ? js_LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop) >= 0 + : obj->lookupProperty(cx, id, objp, &prop); + return ok && LookupResult(cx, obj, *objp, id, prop, Valueify(vp)); +} + +JS_PUBLIC_API(JSBool) +JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, uintN flags, jsval *vp) +{ + JSObject *obj2; + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + return atom && JS_LookupPropertyWithFlagsById(cx, obj, ATOM_TO_JSID(atom), flags, &obj2, vp); +} + +JS_PUBLIC_API(JSBool) +JS_HasPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp) +{ + JSObject *obj2; + JSProperty *prop; + JSBool ok = LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING, + &obj2, &prop); + *foundp = (prop != NULL); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp) +{ + return JS_HasPropertyById(cx, obj, INT_TO_JSID(index), foundp); +} + +JS_PUBLIC_API(JSBool) +JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp) +{ + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp); +} + +JS_PUBLIC_API(JSBool) +JS_HasUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, JSBool *foundp) +{ + JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp); +} + +JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id); + + if (!obj->isNative()) { + JSObject *obj2; + JSProperty *prop; + + if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING, + &obj2, &prop)) { + return JS_FALSE; + } + *foundp = (obj == obj2); + return JS_TRUE; + } + + *foundp = obj->nativeContains(id); + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp) +{ + return JS_AlreadyHasOwnPropertyById(cx, obj, INT_TO_JSID(index), foundp); +} + +JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp) +{ + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp); +} + +JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, + JSBool *foundp) +{ + JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp); +} + +static JSBool +DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, const Value &value, + PropertyOp getter, StrictPropertyOp setter, uintN attrs, + uintN flags, intN tinyid) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id, value, + (attrs & JSPROP_GETTER) + ? JS_FUNC_TO_DATA_PTR(JSObject *, getter) + : NULL, + (attrs & JSPROP_SETTER) + ? JS_FUNC_TO_DATA_PTR(JSObject *, setter) + : NULL); + + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING); + if (flags != 0 && obj->isNative()) { + return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter, + attrs, flags, tinyid, NULL); + } + return obj->defineProperty(cx, id, value, getter, setter, attrs); +} + +JS_PUBLIC_API(JSBool) +JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value, + JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs) +{ + return DefinePropertyById(cx, obj, id, Valueify(value), Valueify(getter), + Valueify(setter), attrs, 0, 0); +} + +JS_PUBLIC_API(JSBool) +JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value, + JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs) +{ + return DefinePropertyById(cx, obj, INT_TO_JSID(index), Valueify(value), + Valueify(getter), Valueify(setter), attrs, 0, 0); +} + +static JSBool +DefineProperty(JSContext *cx, JSObject *obj, const char *name, const Value &value, + PropertyOp getter, StrictPropertyOp setter, uintN attrs, + uintN flags, intN tinyid) +{ + jsid id; + JSAtom *atom; + + if (attrs & JSPROP_INDEX) { + id = INT_TO_JSID(intptr_t(name)); + atom = NULL; + attrs &= ~JSPROP_INDEX; + } else { + atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return JS_FALSE; + id = ATOM_TO_JSID(atom); + } + return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags, tinyid); +} + +JS_PUBLIC_API(JSBool) +JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value, + JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs) +{ + return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter), + Valueify(setter), attrs, 0, 0); +} + +JS_PUBLIC_API(JSBool) +JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, int8 tinyid, + jsval value, JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs) +{ + return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter), + Valueify(setter), attrs, Shape::HAS_SHORTID, tinyid); +} + +static JSBool +DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, + const Value &value, PropertyOp getter, StrictPropertyOp setter, uintN attrs, + uintN flags, intN tinyid) +{ + JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + return atom && DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs, + flags, tinyid); +} + +JS_PUBLIC_API(JSBool) +JS_DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, + jsval value, JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs) +{ + return DefineUCProperty(cx, obj, name, namelen, Valueify(value), + Valueify(getter), Valueify(setter), attrs, 0, 0); +} + +JS_PUBLIC_API(JSBool) +JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, + int8 tinyid, jsval value, + JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs) +{ + return DefineUCProperty(cx, obj, name, namelen, Valueify(value), Valueify(getter), + Valueify(setter), attrs, Shape::HAS_SHORTID, tinyid); +} + +JS_PUBLIC_API(JSBool) +JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id, descriptor); + return js_DefineOwnProperty(cx, obj, id, Valueify(descriptor), bp); +} + +JS_PUBLIC_API(JSObject *) +JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp, + JSObject *proto, uintN attrs) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, proto); + + Class *clasp = Valueify(jsclasp); + if (!clasp) + clasp = &js_ObjectClass; /* default class is Object */ + + JSObject *nobj = NewObject(cx, clasp, proto, obj); + if (!nobj) + return NULL; + + nobj->syncSpecialEquality(); + + if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0)) + return NULL; + + return nobj; +} + +JS_PUBLIC_API(JSBool) +JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds) +{ + JSBool ok; + uintN attrs; + + CHECK_REQUEST(cx); + for (ok = JS_TRUE; cds->name; cds++) { + Value value = DoubleValue(cds->dval); + attrs = cds->flags; + if (!attrs) + attrs = JSPROP_READONLY | JSPROP_PERMANENT; + ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0); + if (!ok) + break; + } + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps) +{ + JSBool ok; + + for (ok = true; ps->name; ps++) { + ok = DefineProperty(cx, obj, ps->name, UndefinedValue(), + Valueify(ps->getter), Valueify(ps->setter), + ps->flags, Shape::HAS_SHORTID, ps->tinyid); + if (!ok) + break; + } + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, const char *alias) +{ + JSObject *obj2; + JSProperty *prop; + JSBool ok; + Shape *shape; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return JS_FALSE; + if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop)) + return JS_FALSE; + if (!prop) { + js_ReportIsNotDefined(cx, name); + return JS_FALSE; + } + if (obj2 != obj || !obj->isNative()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS, + alias, name, obj2->getClass()->name); + return JS_FALSE; + } + atom = js_Atomize(cx, alias, strlen(alias), 0); + if (!atom) { + ok = JS_FALSE; + } else { + shape = (Shape *)prop; + ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom), + shape->getter(), shape->setter(), shape->slot, + shape->attributes(), shape->getFlags() | Shape::ALIAS, + shape->shortid) + != NULL); + } + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias) +{ + JSObject *obj2; + JSProperty *prop; + Shape *shape; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return JS_FALSE; + if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop)) + return JS_FALSE; + if (!prop) { + js_ReportIsNotDefined(cx, name); + return JS_FALSE; + } + if (obj2 != obj || !obj->isNative()) { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS, + numBuf, name, obj2->getClass()->name); + return JS_FALSE; + } + shape = (Shape *)prop; + return js_AddNativeProperty(cx, obj, INT_TO_JSID(alias), + shape->getter(), shape->setter(), shape->slot, + shape->attributes(), shape->getFlags() | Shape::ALIAS, + shape->shortid) + != NULL; +} + +static JSBool +GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSBool own, PropertyDescriptor *desc) +{ + JSObject *obj2; + JSProperty *prop; + + if (!LookupPropertyById(cx, obj, id, flags, &obj2, &prop)) + return JS_FALSE; + + if (!prop || (own && obj != obj2)) { + desc->obj = NULL; + desc->attrs = 0; + desc->getter = NULL; + desc->setter = NULL; + desc->value.setUndefined(); + return JS_TRUE; + } + + desc->obj = obj2; + if (obj2->isNative()) { + Shape *shape = (Shape *) prop; + desc->attrs = shape->attributes(); + + if (shape->isMethod()) { + desc->getter = PropertyStub; + desc->setter = StrictPropertyStub; + desc->value.setObject(shape->methodObject()); + } else { + desc->getter = shape->getter(); + desc->setter = shape->setter(); + if (obj2->containsSlot(shape->slot)) + desc->value = obj2->nativeGetSlot(shape->slot); + else + desc->value.setUndefined(); + } + } else { + if (obj2->isProxy()) { + JSAutoResolveFlags rf(cx, flags); + return own + ? JSProxy::getOwnPropertyDescriptor(cx, obj2, id, false, desc) + : JSProxy::getPropertyDescriptor(cx, obj2, id, false, desc); + } + if (!obj2->getAttributes(cx, id, &desc->attrs)) + return false; + desc->getter = NULL; + desc->setter = NULL; + desc->value.setUndefined(); + } + return true; +} + +JS_PUBLIC_API(JSBool) +JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSPropertyDescriptor *desc) +{ + return GetPropertyDescriptorById(cx, obj, id, flags, JS_FALSE, Valueify(desc)); +} + +JS_PUBLIC_API(JSBool) +JS_GetPropertyAttrsGetterAndSetterById(JSContext *cx, JSObject *obj, jsid id, + uintN *attrsp, JSBool *foundp, + JSPropertyOp *getterp, JSStrictPropertyOp *setterp) +{ + PropertyDescriptor desc; + if (!GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, JS_FALSE, &desc)) + return false; + + *attrsp = desc.attrs; + *foundp = (desc.obj != NULL); + if (getterp) + *getterp = Jsvalify(desc.getter); + if (setterp) + *setterp = Jsvalify(desc.setter); + return true; +} + +JS_PUBLIC_API(JSBool) +JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name, + uintN *attrsp, JSBool *foundp) +{ + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom), + attrsp, foundp, NULL, NULL); +} + +JS_PUBLIC_API(JSBool) +JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, + uintN *attrsp, JSBool *foundp) +{ + JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom), + attrsp, foundp, NULL, NULL); +} + +JS_PUBLIC_API(JSBool) +JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, const char *name, + uintN *attrsp, JSBool *foundp, + JSPropertyOp *getterp, JSStrictPropertyOp *setterp) +{ + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom), + attrsp, foundp, getterp, setterp); +} + +JS_PUBLIC_API(JSBool) +JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + uintN *attrsp, JSBool *foundp, + JSPropertyOp *getterp, JSStrictPropertyOp *setterp) +{ + JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom), + attrsp, foundp, getterp, setterp); +} + +JS_PUBLIC_API(JSBool) +JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + CHECK_REQUEST(cx); + return js_GetOwnPropertyDescriptor(cx, obj, id, Valueify(vp)); +} + +static JSBool +SetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, uintN attrs, JSBool *foundp) +{ + JSObject *obj2; + JSProperty *prop; + + if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop)) + return false; + if (!prop || obj != obj2) { + *foundp = false; + return true; + } + JSBool ok = obj->isNative() + ? js_SetNativeAttributes(cx, obj, (Shape *) prop, attrs) + : obj->setAttributes(cx, id, &attrs); + if (ok) + *foundp = true; + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name, + uintN attrs, JSBool *foundp) +{ + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp); +} + +JS_PUBLIC_API(JSBool) +JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, + uintN attrs, JSBool *foundp) +{ + JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp); +} + +JS_PUBLIC_API(JSBool) +JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id); + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + return obj->getProperty(cx, id, Valueify(vp)); +} + +JS_PUBLIC_API(JSBool) +JS_GetPropertyByIdDefault(JSContext *cx, JSObject *obj, jsid id, jsval def, jsval *vp) +{ + return GetPropertyDefault(cx, obj, id, Valueify(def), Valueify(vp)); +} + +JS_PUBLIC_API(JSBool) +JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp) +{ + return JS_GetPropertyById(cx, obj, INT_TO_JSID(index), vp); +} + +JS_PUBLIC_API(JSBool) +JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp) +{ + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp); +} + +JS_PUBLIC_API(JSBool) +JS_GetPropertyDefault(JSContext *cx, JSObject *obj, const char *name, jsval def, jsval *vp) +{ + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + return atom && JS_GetPropertyByIdDefault(cx, obj, ATOM_TO_JSID(atom), def, vp); +} + +JS_PUBLIC_API(JSBool) +JS_GetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp) +{ + JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp); +} + +JS_PUBLIC_API(JSBool) +JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsval *vp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id); + if (!js_GetMethod(cx, obj, id, JSGET_METHOD_BARRIER, Valueify(vp))) + return JS_FALSE; + if (objp) + *objp = obj; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, jsval *vp) +{ + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + return atom && JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), objp, vp); +} + +JS_PUBLIC_API(JSBool) +JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id); + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING); + return obj->setProperty(cx, id, Valueify(vp), false); +} + +JS_PUBLIC_API(JSBool) +JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp) +{ + return JS_SetPropertyById(cx, obj, INT_TO_JSID(index), vp); +} + +JS_PUBLIC_API(JSBool) +JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp) +{ + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp); +} + +JS_PUBLIC_API(JSBool) +JS_SetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp) +{ + JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp); +} + +JS_PUBLIC_API(JSBool) +JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id); + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + return obj->deleteProperty(cx, id, Valueify(rval), false); +} + +JS_PUBLIC_API(JSBool) +JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval) +{ + return JS_DeletePropertyById2(cx, obj, INT_TO_JSID(index), rval); +} + +JS_PUBLIC_API(JSBool) +JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name, jsval *rval) +{ + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval); +} + +JS_PUBLIC_API(JSBool) +JS_DeleteUCProperty2(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *rval) +{ + JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval); +} + +JS_PUBLIC_API(JSBool) +JS_DeletePropertyById(JSContext *cx, JSObject *obj, jsid id) +{ + jsval junk; + return JS_DeletePropertyById2(cx, obj, id, &junk); +} + +JS_PUBLIC_API(JSBool) +JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index) +{ + jsval junk; + return JS_DeleteElement2(cx, obj, index, &junk); +} + +JS_PUBLIC_API(JSBool) +JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name) +{ + jsval junk; + return JS_DeleteProperty2(cx, obj, name, &junk); +} + +JS_PUBLIC_API(void) +JS_ClearScope(JSContext *cx, JSObject *obj) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + + JSFinalizeOp clearOp = obj->getOps()->clear; + if (clearOp) + clearOp(cx, obj); + + if (obj->isNative()) + js_ClearNative(cx, obj); + + /* Clear cached class objects on the global object. */ + if (obj->isGlobal()) { + /* This can return false but that doesn't mean it failed. */ + obj->unbrand(cx); + + for (int key = JSProto_Null; key < JSProto_LIMIT * 3; key++) + JS_SetReservedSlot(cx, obj, key, JSVAL_VOID); + + /* Clear regexp statics. */ + RegExpStatics::extractFrom(obj)->clear(); + + /* Clear the CSP eval-is-allowed cache. */ + JS_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_EVAL_ALLOWED, JSVAL_VOID); + + /* + * Mark global as cleared. If we try to execute any compile-and-go + * scripts from here on, we will throw. + */ + int32 flags = obj->getReservedSlot(JSRESERVED_GLOBAL_FLAGS).toInt32(); + flags |= JSGLOBAL_FLAGS_CLEARED; + JS_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_FLAGS, Jsvalify(Int32Value(flags))); + } + + js_InitRandom(cx); +} + +JS_PUBLIC_API(JSIdArray *) +JS_Enumerate(JSContext *cx, JSObject *obj) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + + AutoIdVector props(cx); + JSIdArray *ida; + if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida)) + return false; + for (size_t n = 0; n < size_t(ida->length); ++n) + JS_ASSERT(js_CheckForStringIndex(ida->vector[n]) == ida->vector[n]); + return ida; +} + +/* + * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's + * prop_iterator_class somehow... + * + preserve the obj->enumerate API while optimizing the native object case + * + native case here uses a Shape *, but that iterates in reverse! + * + so we make non-native match, by reverse-iterating after JS_Enumerating + */ +const uint32 JSSLOT_ITER_INDEX = 0; + +static void +prop_iter_finalize(JSContext *cx, JSObject *obj) +{ + void *pdata = obj->getPrivate(); + if (!pdata) + return; + + if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) { + /* Non-native case: destroy the ida enumerated when obj was created. */ + JSIdArray *ida = (JSIdArray *) pdata; + JS_DestroyIdArray(cx, ida); + } +} + +static void +prop_iter_trace(JSTracer *trc, JSObject *obj) +{ + void *pdata = obj->getPrivate(); + if (!pdata) + return; + + if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) { + /* Native case: just mark the next property to visit. */ + ((Shape *) pdata)->trace(trc); + } else { + /* Non-native case: mark each id in the JSIdArray private. */ + JSIdArray *ida = (JSIdArray *) pdata; + MarkIdRange(trc, ida->length, ida->vector, "prop iter"); + } +} + +static Class prop_iter_class = { + "PropertyIterator", + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | + JSCLASS_MARK_IS_TRACE, + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub, + prop_iter_finalize, + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + JS_CLASS_TRACE(prop_iter_trace) +}; + +JS_PUBLIC_API(JSObject *) +JS_NewPropertyIterator(JSContext *cx, JSObject *obj) +{ + JSObject *iterobj; + const void *pdata; + jsint index; + JSIdArray *ida; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + iterobj = NewNonFunction(cx, &prop_iter_class, NULL, obj); + if (!iterobj) + return NULL; + + if (obj->isNative()) { + /* Native case: start with the last property in obj. */ + pdata = obj->lastProperty(); + index = -1; + } else { + /* + * Non-native case: enumerate a JSIdArray and keep it via private. + * + * Note: we have to make sure that we root obj around the call to + * JS_Enumerate to protect against multiple allocations under it. + */ + AutoObjectRooter tvr(cx, iterobj); + ida = JS_Enumerate(cx, obj); + if (!ida) + return NULL; + pdata = ida; + index = ida->length; + } + + /* iterobj cannot escape to other threads here. */ + iterobj->setPrivate(const_cast(pdata)); + iterobj->getSlotRef(JSSLOT_ITER_INDEX).setInt32(index); + return iterobj; +} + +JS_PUBLIC_API(JSBool) +JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp) +{ + jsint i; + const Shape *shape; + JSIdArray *ida; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, iterobj); + i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32(); + if (i < 0) { + /* Native case: private data is a property tree node pointer. */ + JS_ASSERT(iterobj->getParent()->isNative()); + shape = (Shape *) iterobj->getPrivate(); + + while (shape->previous() && (!shape->enumerable() || shape->isAlias())) + shape = shape->previous(); + + if (!shape->previous()) { + JS_ASSERT(JSID_IS_EMPTY(shape->id)); + *idp = JSID_VOID; + } else { + iterobj->setPrivate(const_cast(shape->previous())); + *idp = shape->id; + } + } else { + /* Non-native case: use the ida enumerated when iterobj was created. */ + ida = (JSIdArray *) iterobj->getPrivate(); + JS_ASSERT(i <= ida->length); + STATIC_ASSUME(i <= ida->length); + if (i == 0) { + *idp = JSID_VOID; + } else { + *idp = ida->vector[--i]; + iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i)); + } + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + return js_GetReservedSlot(cx, obj, index, Valueify(vp)); +} + +JS_PUBLIC_API(JSBool) +JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, v); + return js_SetReservedSlot(cx, obj, index, Valueify(v)); +} + +JS_PUBLIC_API(JSObject *) +JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + /* NB: jsuint cast does ToUint32. */ + assertSameCompartment(cx, JSValueArray(vector, vector ? (jsuint)length : 0)); + return NewDenseCopiedArray(cx, (jsuint)length, Valueify(vector)); +} + +JS_PUBLIC_API(JSBool) +JS_IsArrayObject(JSContext *cx, JSObject *obj) +{ + assertSameCompartment(cx, obj); + return obj->isArray() || + (obj->isWrapper() && JSWrapper::wrappedObject(obj)->isArray()); +} + +JS_PUBLIC_API(JSBool) +JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + return js_GetLengthProperty(cx, obj, lengthp); +} + +JS_PUBLIC_API(JSBool) +JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + return js_SetLengthProperty(cx, obj, length); +} + +JS_PUBLIC_API(JSBool) +JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + return js_HasLengthProperty(cx, obj, lengthp); +} + +JS_PUBLIC_API(JSBool) +JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, + jsval *vp, uintN *attrsp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, id); + return CheckAccess(cx, obj, id, mode, Valueify(vp), attrsp); +} + +#ifdef JS_THREADSAFE +JS_PUBLIC_API(jsrefcount) +JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals) +{ + return JS_ATOMIC_INCREMENT(&principals->refcount); +} + +JS_PUBLIC_API(jsrefcount) +JS_DropPrincipals(JSContext *cx, JSPrincipals *principals) +{ + jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount); + if (rc == 0) + principals->destroy(cx, principals); + return rc; +} +#endif + +JS_PUBLIC_API(JSSecurityCallbacks *) +JS_SetRuntimeSecurityCallbacks(JSRuntime *rt, JSSecurityCallbacks *callbacks) +{ + JSSecurityCallbacks *oldcallbacks; + + oldcallbacks = rt->securityCallbacks; + rt->securityCallbacks = callbacks; + return oldcallbacks; +} + +JS_PUBLIC_API(JSSecurityCallbacks *) +JS_GetRuntimeSecurityCallbacks(JSRuntime *rt) +{ + return rt->securityCallbacks; +} + +JS_PUBLIC_API(JSSecurityCallbacks *) +JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks) +{ + JSSecurityCallbacks *oldcallbacks; + + oldcallbacks = cx->securityCallbacks; + cx->securityCallbacks = callbacks; + return oldcallbacks; +} + +JS_PUBLIC_API(JSSecurityCallbacks *) +JS_GetSecurityCallbacks(JSContext *cx) +{ + return cx->securityCallbacks + ? cx->securityCallbacks + : cx->runtime->securityCallbacks; +} + +JS_PUBLIC_API(JSFunction *) +JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags, + JSObject *parent, const char *name) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + JSAtom *atom; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, parent); + + if (!name) { + atom = NULL; + } else { + atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return NULL; + } + return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, atom); +} + +JS_PUBLIC_API(JSFunction *) +JS_NewFunctionById(JSContext *cx, JSNative native, uintN nargs, uintN flags, JSObject *parent, + jsid id) +{ + JS_ASSERT(JSID_IS_STRING(id)); + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + assertSameCompartment(cx, parent); + + return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, JSID_TO_ATOM(id)); +} + +JS_PUBLIC_API(JSObject *) +JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, parent); // XXX no funobj for now + if (!parent) { + if (cx->hasfp()) + parent = GetScopeChain(cx, cx->fp()); + if (!parent) + parent = cx->globalObject; + JS_ASSERT(parent); + } + + if (funobj->getClass() != &js_FunctionClass) { + /* + * We cannot clone this object, so fail (we used to return funobj, bad + * idea, but we changed incompatibly to teach any abusers a lesson!). + */ + Value v = ObjectValue(*funobj); + js_ReportIsNotFunction(cx, &v, 0); + return NULL; + } + + JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); + if (!FUN_FLAT_CLOSURE(fun)) + return CloneFunctionObject(cx, fun, parent); + + /* + * A flat closure carries its own environment, so why clone it? In case + * someone wants to mutate its fixed slots or add ad-hoc properties. API + * compatibility suggests we not return funobj and let callers mutate the + * returned object at will. + * + * But it's worse than that: API compatibility according to the test for + * bug 300079 requires we get "upvars" from parent and its ancestors! So + * we do that (grudgingly!). The scope chain ancestors are searched as if + * they were activations, respecting the skip field in each upvar's cookie + * but looking up the property by name instead of frame slot. + */ + JSObject *clone = js_AllocFlatClosure(cx, fun, parent); + if (!clone) + return NULL; + + JSUpvarArray *uva = fun->u.i.script->upvars(); + uint32 i = uva->length; + JS_ASSERT(i != 0); + + for (Shape::Range r(fun->script()->bindings.lastUpvar()); i-- != 0; r.popFront()) { + JSObject *obj = parent; + int skip = uva->vector[i].level(); + while (--skip > 0) { + if (!obj) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_CLONE_FUNOBJ_SCOPE); + return NULL; + } + obj = obj->getParent(); + } + + if (!obj->getProperty(cx, r.front().id, clone->getFlatClosureUpvars() + i)) + return NULL; + } + + return clone; +} + +JS_PUBLIC_API(JSObject *) +JS_GetFunctionObject(JSFunction *fun) +{ + return FUN_OBJECT(fun); +} + +JS_PUBLIC_API(JSString *) +JS_GetFunctionId(JSFunction *fun) +{ + return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL; +} + +JS_PUBLIC_API(uintN) +JS_GetFunctionFlags(JSFunction *fun) +{ + return fun->flags; +} + +JS_PUBLIC_API(uint16) +JS_GetFunctionArity(JSFunction *fun) +{ + return fun->nargs; +} + +JS_PUBLIC_API(JSBool) +JS_ObjectIsFunction(JSContext *cx, JSObject *obj) +{ + return obj->getClass() == &js_FunctionClass; +} + +JS_PUBLIC_API(JSBool) +JS_ObjectIsCallable(JSContext *cx, JSObject *obj) +{ + return obj->isCallable(); +} + +static JSBool +js_generic_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp) +{ + JSFunctionSpec *fs = (JSFunctionSpec *) vp->toObject().getReservedSlot(0).toPrivate(); + JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0); + + if (argc < 1) { + js_ReportMissingArg(cx, *vp, 0); + return JS_FALSE; + } + + /* + * Copy all actual (argc) arguments down over our |this| parameter, vp[1], + * which is almost always the class constructor object, e.g. Array. Then + * call the corresponding prototype native method with our first argument + * passed as |this|. + */ + memmove(vp + 1, vp + 2, argc * sizeof(jsval)); + + /* Clear the last parameter in case too few arguments were passed. */ + vp[2 + --argc].setUndefined(); + + Native native = +#ifdef JS_TRACER + (fs->flags & JSFUN_TRCINFO) + ? JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, fs->call)->native + : +#endif + Valueify(fs->call); + return native(cx, argc, vp); +} + +JS_PUBLIC_API(JSBool) +JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + uintN flags; + JSObject *ctor; + JSFunction *fun; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + ctor = NULL; + for (; fs->name; fs++) { + flags = fs->flags; + + /* + * Define a generic arity N+1 static method for the arity N prototype + * method if flags contains JSFUN_GENERIC_NATIVE. + */ + if (flags & JSFUN_GENERIC_NATIVE) { + if (!ctor) { + ctor = JS_GetConstructor(cx, obj); + if (!ctor) + return JS_FALSE; + } + + flags &= ~JSFUN_GENERIC_NATIVE; + fun = JS_DefineFunction(cx, ctor, fs->name, + Jsvalify(js_generic_native_method_dispatcher), + fs->nargs + 1, + flags & ~JSFUN_TRCINFO); + if (!fun) + return JS_FALSE; + + /* + * As jsapi.h notes, fs must point to storage that lives as long + * as fun->object lives. + */ + Value priv = PrivateValue(fs); + if (!js_SetReservedSlot(cx, FUN_OBJECT(fun), 0, priv)) + return JS_FALSE; + } + + fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags); + if (!fun) + return JS_FALSE; + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSFunction *) +JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call, + uintN nargs, uintN attrs) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + if (!atom) + return NULL; + return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), Valueify(call), nargs, attrs); +} + +JS_PUBLIC_API(JSFunction *) +JS_DefineUCFunction(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, JSNative call, + uintN nargs, uintN attrs) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); + if (!atom) + return NULL; + return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), Valueify(call), nargs, attrs); +} + +extern JS_PUBLIC_API(JSFunction *) +JS_DefineFunctionById(JSContext *cx, JSObject *obj, jsid id, JSNative call, + uintN nargs, uintN attrs) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + return js_DefineFunction(cx, obj, id, Valueify(call), nargs, attrs); +} + +inline static void +LAST_FRAME_EXCEPTION_CHECK(JSContext *cx, bool result) +{ + if (!result && !cx->hasRunOption(JSOPTION_DONT_REPORT_UNCAUGHT)) + js_ReportUncaughtException(cx); +} + +inline static void +LAST_FRAME_CHECKS(JSContext *cx, bool result) +{ + if (!JS_IsRunning(cx)) { + LAST_FRAME_EXCEPTION_CHECK(cx, result); + } +} + +inline static uint32 +JS_OPTIONS_TO_TCFLAGS(JSContext *cx) +{ + return (cx->hasRunOption(JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) | + (cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0); +} + +static JSObject * +CompileUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj, JSPrincipals *principals, + const jschar *chars, size_t length, + const char *filename, uintN lineno, JSVersion version) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, principals); + + uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT; + JSScript *script = Compiler::compileScript(cx, obj, NULL, principals, tcflags, + chars, length, filename, lineno, version); + JSObject *scriptObj = NULL; + if (script) { + scriptObj = js_NewScriptObject(cx, script); + if (!scriptObj) + js_DestroyScript(cx, script); + } + LAST_FRAME_CHECKS(cx, scriptObj); + return scriptObj; +} + +extern JS_PUBLIC_API(JSObject *) +JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const jschar *chars, size_t length, + const char *filename, uintN lineno, + JSVersion version) +{ + AutoVersionAPI avi(cx, version); + return CompileUCScriptForPrincipalsCommon(cx, obj, principals, chars, length, filename, lineno, + avi.version()); +} + +JS_PUBLIC_API(JSObject *) +JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals, + const jschar *chars, size_t length, + const char *filename, uintN lineno) +{ + return CompileUCScriptForPrincipalsCommon(cx, obj, principals, chars, length, filename, lineno, + cx->findVersion()); +} + +JS_PUBLIC_API(JSObject *) +JS_CompileUCScript(JSContext *cx, JSObject *obj, const jschar *chars, size_t length, + const char *filename, uintN lineno) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno); +} + +JS_PUBLIC_API(JSObject *) +JS_CompileScriptForPrincipalsVersion(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const char *bytes, size_t length, + const char *filename, uintN lineno, + JSVersion version) +{ + AutoVersionAPI ava(cx, version); + return JS_CompileScriptForPrincipals(cx, obj, principals, bytes, length, filename, lineno); +} + +JS_PUBLIC_API(JSObject *) +JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const char *bytes, size_t length, + const char *filename, uintN lineno) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + + jschar *chars = js_InflateString(cx, bytes, &length); + if (!chars) + return NULL; + JSObject *scriptObj = + JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno); + cx->free(chars); + return scriptObj; +} + +JS_PUBLIC_API(JSObject *) +JS_CompileScript(JSContext *cx, JSObject *obj, const char *bytes, size_t length, + const char *filename, uintN lineno) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + return JS_CompileScriptForPrincipals(cx, obj, NULL, bytes, length, filename, lineno); +} + +JS_PUBLIC_API(JSBool) +JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, const char *bytes, size_t length) +{ + jschar *chars; + JSBool result; + JSExceptionState *exnState; + JSErrorReporter older; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + chars = js_InflateString(cx, bytes, &length); + if (!chars) + return JS_TRUE; + + /* + * Return true on any out-of-memory error, so our caller doesn't try to + * collect more buffered source. + */ + result = JS_TRUE; + exnState = JS_SaveExceptionState(cx); + { + Parser parser(cx); + if (parser.init(chars, length, NULL, 1, cx->findVersion())) { + older = JS_SetErrorReporter(cx, NULL); + if (!parser.parse(obj) && + parser.tokenStream.isUnexpectedEOF()) { + /* + * We ran into an error. If it was because we ran out of + * source, we return false so our caller knows to try to + * collect more buffered source. + */ + result = JS_FALSE; + } + JS_SetErrorReporter(cx, older); + } + } + cx->free(chars); + JS_RestoreExceptionState(cx, exnState); + return result; +} + +/* Use the fastest available getc. */ +#if defined(HAVE_GETC_UNLOCKED) +# define fast_getc getc_unlocked +#elif defined(HAVE__GETC_NOLOCK) +# define fast_getc _getc_nolock +#else +# define fast_getc getc +#endif + +static JSObject * +CompileFileHelper(JSContext *cx, JSObject *obj, JSPrincipals *principals, + const char* filename, FILE *fp) +{ + struct stat st; + int ok = fstat(fileno(fp), &st); + if (ok != 0) + return NULL; + + jschar *buf = NULL; + size_t len = st.st_size; + size_t i = 0; + JSScript *script; + + /* Read in the whole file, then compile it. */ + if (fp == stdin) { + JS_ASSERT(len == 0); + len = 8; /* start with a small buffer, expand as necessary */ + int c; + bool hitEOF = false; + while (!hitEOF) { + len *= 2; + jschar* tmpbuf = (jschar *) js_realloc(buf, len * sizeof(jschar)); + if (!tmpbuf) { + cx->free(buf); + return NULL; + } + buf = tmpbuf; + + while (i < len) { + c = fast_getc(fp); + if (c == EOF) { + hitEOF = true; + break; + } + buf[i++] = (jschar) (unsigned char) c; + } + } + } else { + buf = (jschar *) js_malloc(len * sizeof(jschar)); + if (!buf) + return NULL; + + int c; + while ((c = fast_getc(fp)) != EOF) + buf[i++] = (jschar) (unsigned char) c; + } + + JS_ASSERT(i <= len); + len = i; + uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT; + script = Compiler::compileScript(cx, obj, NULL, principals, tcflags, buf, len, filename, 1, + cx->findVersion()); + js_free(buf); + if (!script) + return NULL; + + JSObject *scriptObj = js_NewScriptObject(cx, script); + if (!scriptObj) + js_DestroyScript(cx, script); + + return scriptObj; +} + +JS_PUBLIC_API(JSObject *) +JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + JSObject *scriptObj = NULL; + do { + FILE *fp; + if (!filename || strcmp(filename, "-") == 0) { + fp = stdin; + } else { + fp = fopen(filename, "r"); + if (!fp) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN, + filename, "No such file or directory"); + break; + } + } + + scriptObj = CompileFileHelper(cx, obj, NULL, filename, fp); + if (fp != stdin) + fclose(fp); + } while (false); + + LAST_FRAME_CHECKS(cx, scriptObj); + return scriptObj; +} + +JS_PUBLIC_API(JSObject *) +JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *filename, + FILE *file, JSPrincipals *principals) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, principals); + JSObject *scriptObj = CompileFileHelper(cx, obj, principals, filename, file); + LAST_FRAME_CHECKS(cx, scriptObj); + return scriptObj; +} + +JS_PUBLIC_API(JSObject *) +JS_CompileFileHandleForPrincipalsVersion(JSContext *cx, JSObject *obj, const char *filename, + FILE *file, JSPrincipals *principals, JSVersion version) +{ + AutoVersionAPI ava(cx, version); + return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, principals); +} + +JS_PUBLIC_API(JSObject *) +JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *file) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL); +} + +JS_PUBLIC_API(JSScript *) +JS_GetScriptFromObject(JSObject *scriptObj) +{ + JS_ASSERT(scriptObj->isScript()); + + return (JSScript *) scriptObj->getPrivate(); +} + +static JSFunction * +CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj, + JSPrincipals *principals, const char *name, + uintN nargs, const char **argnames, + const jschar *chars, size_t length, + const char *filename, uintN lineno, JSVersion version) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + JSFunction *fun; + JSAtom *funAtom, *argAtom; + uintN i; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, principals); + if (!name) { + funAtom = NULL; + } else { + funAtom = js_Atomize(cx, name, strlen(name), 0); + if (!funAtom) { + fun = NULL; + goto out2; + } + } + + fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom); + if (!fun) + goto out2; + + { + AutoObjectRooter tvr(cx, FUN_OBJECT(fun)); + MUST_FLOW_THROUGH("out"); + + Bindings bindings(cx); + AutoBindingsRooter root(cx, bindings); + for (i = 0; i < nargs; i++) { + argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0); + if (!argAtom) { + fun = NULL; + goto out2; + } + + uint16 dummy; + if (!bindings.addArgument(cx, argAtom, &dummy)) { + fun = NULL; + goto out2; + } + } + + if (!Compiler::compileFunctionBody(cx, fun, principals, &bindings, + chars, length, filename, lineno, version)) { + fun = NULL; + goto out2; + } + + if (obj && funAtom && + !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), ObjectValue(*fun), + NULL, NULL, JSPROP_ENUMERATE)) { + fun = NULL; + } + +#ifdef JS_SCOPE_DEPTH_METER + if (fun && obj) { + JSObject *pobj = obj; + uintN depth = 1; + + while ((pobj = pobj->getParent()) != NULL) + ++depth; + JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth); + } +#endif + } + + out2: + LAST_FRAME_CHECKS(cx, fun); + return fun; +} +JS_PUBLIC_API(JSFunction *) +JS_CompileUCFunctionForPrincipalsVersion(JSContext *cx, JSObject *obj, + JSPrincipals *principals, const char *name, + uintN nargs, const char **argnames, + const jschar *chars, size_t length, + const char *filename, uintN lineno, + JSVersion version) +{ + AutoVersionAPI avi(cx, version); + return CompileUCFunctionForPrincipalsCommon(cx, obj, principals, name, nargs, argnames, chars, + length, filename, lineno, avi.version()); +} + +JS_PUBLIC_API(JSFunction *) +JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, const char *name, + uintN nargs, const char **argnames, + const jschar *chars, size_t length, + const char *filename, uintN lineno) +{ + return CompileUCFunctionForPrincipalsCommon(cx, obj, principals, name, nargs, argnames, chars, + length, filename, lineno, cx->findVersion()); +} + +JS_PUBLIC_API(JSFunction *) +JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name, + uintN nargs, const char **argnames, + const jschar *chars, size_t length, + const char *filename, uintN lineno) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames, + chars, length, filename, lineno); +} + +JS_PUBLIC_API(JSFunction *) +JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, const char *name, + uintN nargs, const char **argnames, + const char *bytes, size_t length, + const char *filename, uintN lineno) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + jschar *chars = js_InflateString(cx, bytes, &length); + if (!chars) + return NULL; + JSFunction *fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name, + nargs, argnames, chars, length, + filename, lineno); + cx->free(chars); + return fun; +} + +JS_PUBLIC_API(JSFunction *) +JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name, + uintN nargs, const char **argnames, + const char *bytes, size_t length, + const char *filename, uintN lineno) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + return JS_CompileFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames, bytes, length, + filename, lineno); +} + +JS_PUBLIC_API(JSString *) +JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, uintN indent) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + JSPrinter *jp; + JSString *str; + + CHECK_REQUEST(cx); +#ifdef DEBUG + if (cx->compartment != script->compartment) + CompartmentChecker::fail(cx->compartment, script->compartment); +#endif + jp = js_NewPrinter(cx, name, NULL, + indent & ~JS_DONT_PRETTY_PRINT, + !(indent & JS_DONT_PRETTY_PRINT), + false, false); + if (!jp) + return NULL; + if (js_DecompileScript(jp, script)) + str = js_GetPrinterOutput(jp); + else + str = NULL; + js_DestroyPrinter(jp); + return str; +} + +JS_PUBLIC_API(JSString *) +JS_DecompileScriptObject(JSContext *cx, JSObject *scriptObj, const char *name, uintN indent) +{ + return JS_DecompileScript(cx, scriptObj->getScript(), name, indent); +} + +JS_PUBLIC_API(JSString *) +JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + assertSameCompartment(cx, fun); + return js_DecompileToString(cx, "JS_DecompileFunction", fun, + indent & ~JS_DONT_PRETTY_PRINT, + !(indent & JS_DONT_PRETTY_PRINT), + false, false, js_DecompileFunction); +} + +JS_PUBLIC_API(JSString *) +JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + assertSameCompartment(cx, fun); + return js_DecompileToString(cx, "JS_DecompileFunctionBody", fun, + indent & ~JS_DONT_PRETTY_PRINT, + !(indent & JS_DONT_PRETTY_PRINT), + false, false, js_DecompileFunctionBody); +} + +JS_PUBLIC_API(JSBool) +JS_ExecuteScript(JSContext *cx, JSObject *obj, JSObject *scriptObj, jsval *rval) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, scriptObj); + + JSBool ok = Execute(cx, obj, scriptObj->getScript(), NULL, 0, Valueify(rval)); + LAST_FRAME_CHECKS(cx, ok); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_ExecuteScriptVersion(JSContext *cx, JSObject *obj, JSObject *scriptObj, jsval *rval, + JSVersion version) +{ + AutoVersionAPI ava(cx, version); + return JS_ExecuteScript(cx, obj, scriptObj, rval); +} + +bool +EvaluateUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const jschar *chars, uintN length, + const char *filename, uintN lineno, + jsval *rval, JSVersion compileVersion) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + + CHECK_REQUEST(cx); + JSScript *script = Compiler::compileScript(cx, obj, NULL, principals, + !rval + ? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL + : TCF_COMPILE_N_GO, + chars, length, filename, lineno, compileVersion); + if (!script) { + LAST_FRAME_CHECKS(cx, script); + return false; + } + JS_ASSERT(script->getVersion() == compileVersion); + bool ok = Execute(cx, obj, script, NULL, 0, Valueify(rval)); + LAST_FRAME_CHECKS(cx, ok); + js_DestroyScript(cx, script); + return ok; + +} + +JS_PUBLIC_API(JSBool) +JS_EvaluateUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const jschar *chars, uintN length, + const char *filename, uintN lineno, + jsval *rval, JSVersion version) +{ + AutoVersionAPI avi(cx, version); + return EvaluateUCScriptForPrincipalsCommon(cx, obj, principals, chars, length, + filename, lineno, rval, avi.version()); +} + +JS_PUBLIC_API(JSBool) +JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const jschar *chars, uintN length, + const char *filename, uintN lineno, + jsval *rval) +{ + return EvaluateUCScriptForPrincipalsCommon(cx, obj, principals, chars, length, + filename, lineno, rval, cx->findVersion()); +} + +JS_PUBLIC_API(JSBool) +JS_EvaluateUCScript(JSContext *cx, JSObject *obj, const jschar *chars, uintN length, + const char *filename, uintN lineno, jsval *rval) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno, rval); +} + +/* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */ +JS_PUBLIC_API(JSBool) +JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals, + const char *bytes, uintN nbytes, + const char *filename, uintN lineno, jsval *rval) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + size_t length = nbytes; + jschar *chars = js_InflateString(cx, bytes, &length); + if (!chars) + return JS_FALSE; + JSBool ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length, + filename, lineno, rval); + cx->free(chars); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_EvaluateScriptForPrincipalsVersion(JSContext *cx, JSObject *obj, JSPrincipals *principals, + const char *bytes, uintN nbytes, + const char *filename, uintN lineno, jsval *rval, JSVersion version) +{ + AutoVersionAPI avi(cx, version); + return JS_EvaluateScriptForPrincipals(cx, obj, principals, bytes, nbytes, filename, lineno, + rval); +} + +JS_PUBLIC_API(JSBool) +JS_EvaluateScript(JSContext *cx, JSObject *obj, const char *bytes, uintN nbytes, + const char *filename, uintN lineno, jsval *rval) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + return JS_EvaluateScriptForPrincipals(cx, obj, NULL, bytes, nbytes, filename, lineno, rval); +} + +JS_PUBLIC_API(JSBool) +JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, jsval *argv, + jsval *rval) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, fun, JSValueArray(argv, argc)); + JSBool ok = ExternalInvoke(cx, ObjectOrNullValue(obj), ObjectValue(*fun), argc, + Valueify(argv), Valueify(rval)); + LAST_FRAME_CHECKS(cx, ok); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, jsval *argv, + jsval *rval) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, JSValueArray(argv, argc)); + + AutoValueRooter tvr(cx); + JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); + JSBool ok = + atom && + js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, tvr.addr()) && + ExternalInvoke(cx, ObjectOrNullValue(obj), tvr.value(), argc, Valueify(argv), + Valueify(rval)); + LAST_FRAME_CHECKS(cx, ok); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, jsval *argv, + jsval *rval) +{ + JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment); + + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj, fval, JSValueArray(argv, argc)); + JSBool ok = ExternalInvoke(cx, ObjectOrNullValue(obj), Valueify(fval), argc, Valueify(argv), + Valueify(rval)); + LAST_FRAME_CHECKS(cx, ok); + return ok; +} + +namespace JS { + +JS_PUBLIC_API(bool) +Call(JSContext *cx, jsval thisv, jsval fval, uintN argc, jsval *argv, jsval *rval) +{ + JSBool ok; + + CHECK_REQUEST(cx); + assertSameCompartment(cx, thisv, fval, JSValueArray(argv, argc)); + ok = ExternalInvoke(cx, Valueify(thisv), Valueify(fval), argc, Valueify(argv), Valueify(rval)); + LAST_FRAME_CHECKS(cx, ok); + return ok; +} + +} // namespace JS + +JS_PUBLIC_API(JSObject *) +JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, ctor, JSValueArray(argv, argc)); + + // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW + // is not a simple variation of JSOP_CALL. We have to determine what class + // of object to create, create it, and clamp the return value to an object, + // among other details. js_InvokeConstructor does the hard work. + InvokeArgsGuard args; + if (!cx->stack().pushInvokeArgs(cx, argc, &args)) + return NULL; + + args.callee().setObject(*ctor); + args.thisv().setNull(); + memcpy(args.argv(), argv, argc * sizeof(jsval)); + + bool ok = InvokeConstructor(cx, args); + + JSObject *obj = NULL; + if (ok) { + if (args.rval().isObject()) { + obj = &args.rval().toObject(); + } else { + /* + * Although constructors may return primitives (via proxies), this + * API is asking for an object, so we report an error. + */ + JSAutoByteString bytes; + if (js_ValueToPrintable(cx, args.rval(), &bytes)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_NEW_RESULT, + bytes.ptr()); + } + } + } + + LAST_FRAME_CHECKS(cx, ok); + return obj; +} + +JS_PUBLIC_API(JSOperationCallback) +JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback) +{ +#ifdef JS_THREADSAFE + JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread)); +#endif + JSOperationCallback old = cx->operationCallback; + cx->operationCallback = callback; + return old; +} + +JS_PUBLIC_API(JSOperationCallback) +JS_GetOperationCallback(JSContext *cx) +{ + return cx->operationCallback; +} + +JS_PUBLIC_API(void) +JS_TriggerOperationCallback(JSContext *cx) +{ +#ifdef JS_THREADSAFE + AutoLockGC lock(cx->runtime); +#endif + TriggerOperationCallback(cx); +} + +JS_PUBLIC_API(void) +JS_TriggerAllOperationCallbacks(JSRuntime *rt) +{ +#ifdef JS_THREADSAFE + AutoLockGC lock(rt); +#endif + TriggerAllOperationCallbacks(rt); +} + +JS_PUBLIC_API(JSBool) +JS_IsRunning(JSContext *cx) +{ + /* + * The use of cx->fp below is safe. Rationale: Here we don't care if the + * interpreter state is stale. We just want to know if there *is* any + * interpreter state. + */ + VOUCH_DOES_NOT_REQUIRE_STACK(); + +#ifdef JS_TRACER + JS_ASSERT_IF(JS_ON_TRACE(cx) && JS_TRACE_MONITOR_ON_TRACE(cx)->tracecx == cx, cx->hasfp()); +#endif + JSStackFrame *fp = cx->maybefp(); + while (fp && fp->isDummyFrame()) + fp = fp->prev(); + return fp != NULL; +} + +JS_PUBLIC_API(JSStackFrame *) +JS_SaveFrameChain(JSContext *cx) +{ + CHECK_REQUEST(cx); + JSStackFrame *fp = js_GetTopStackFrame(cx); + if (!fp) + return NULL; + cx->saveActiveSegment(); + return fp; +} + +JS_PUBLIC_API(void) +JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp) +{ + CHECK_REQUEST(cx); + JS_ASSERT_NOT_ON_TRACE(cx); + JS_ASSERT(!cx->hasfp()); + if (!fp) + return; + cx->restoreSegment(); +} + +/************************************************************************/ +JS_PUBLIC_API(JSString *) +JS_NewStringCopyN(JSContext *cx, const char *s, size_t n) +{ + CHECK_REQUEST(cx); + return js_NewStringCopyN(cx, s, n); +} + +JS_PUBLIC_API(JSString *) +JS_NewStringCopyZ(JSContext *cx, const char *s) +{ + size_t n; + jschar *js; + JSString *str; + + CHECK_REQUEST(cx); + if (!s) + return cx->runtime->emptyString; + n = strlen(s); + js = js_InflateString(cx, s, &n); + if (!js) + return NULL; + str = js_NewString(cx, js, n); + if (!str) + cx->free(js); + return str; +} + +JS_PUBLIC_API(JSBool) +JS_StringHasBeenInterned(JSString *str) +{ + return str->isAtomized(); +} + +JS_PUBLIC_API(JSString *) +JS_InternJSString(JSContext *cx, JSString *str) +{ + CHECK_REQUEST(cx); + JSAtom *atom = js_AtomizeString(cx, str, 0); + if (!atom) + return NULL; + return ATOM_TO_STRING(atom); +} + +JS_PUBLIC_API(JSString *) +JS_InternString(JSContext *cx, const char *s) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED); + if (!atom) + return NULL; + return ATOM_TO_STRING(atom); +} + +JS_PUBLIC_API(JSString *) +JS_NewUCString(JSContext *cx, jschar *chars, size_t length) +{ + CHECK_REQUEST(cx); + return js_NewString(cx, chars, length); +} + +JS_PUBLIC_API(JSString *) +JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n) +{ + CHECK_REQUEST(cx); + return js_NewStringCopyN(cx, s, n); +} + +JS_PUBLIC_API(JSString *) +JS_NewUCStringCopyZ(JSContext *cx, const jschar *s) +{ + CHECK_REQUEST(cx); + if (!s) + return cx->runtime->emptyString; + return js_NewStringCopyZ(cx, s); +} + +JS_PUBLIC_API(JSString *) +JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length) +{ + JSAtom *atom; + + CHECK_REQUEST(cx); + atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED); + if (!atom) + return NULL; + return ATOM_TO_STRING(atom); +} + +JS_PUBLIC_API(JSString *) +JS_InternUCString(JSContext *cx, const jschar *s) +{ + return JS_InternUCStringN(cx, s, js_strlen(s)); +} + +JS_PUBLIC_API(size_t) +JS_GetStringLength(JSString *str) +{ + return str->length(); +} + +JS_PUBLIC_API(const jschar *) +JS_GetStringCharsZ(JSContext *cx, JSString *str) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, str); + return str->getCharsZ(cx); +} + +JS_PUBLIC_API(const jschar *) +JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *plength) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, str); + *plength = str->length(); + return str->getCharsZ(cx); +} + +JS_PUBLIC_API(const jschar *) +JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, str); + *plength = str->length(); + return str->getChars(cx); +} + +JS_PUBLIC_API(const jschar *) +JS_GetInternedStringChars(JSString *str) +{ + JS_ASSERT(str->isAtomized()); + return str->flatChars(); +} + +JS_PUBLIC_API(const jschar *) +JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength) +{ + JS_ASSERT(str->isAtomized()); + *plength = str->flatLength(); + return str->flatChars(); +} + +extern JS_PUBLIC_API(JSFlatString *) +JS_FlattenString(JSContext *cx, JSString *str) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, str); + return str->getCharsZ(cx) ? (JSFlatString *)str : NULL; +} + +extern JS_PUBLIC_API(const jschar *) +JS_GetFlatStringChars(JSFlatString *str) +{ + return str->chars(); +} + +JS_PUBLIC_API(JSBool) +JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result) +{ + return CompareStrings(cx, str1, str2, result); +} + +JS_PUBLIC_API(JSBool) +JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match) +{ + JSLinearString *linearStr = str->ensureLinear(cx); + if (!linearStr) + return false; + *match = StringEqualsAscii(linearStr, asciiBytes); + return true; +} + +JS_PUBLIC_API(JSBool) +JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes) +{ + return StringEqualsAscii(str, asciiBytes); +} + +JS_PUBLIC_API(size_t) +JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote) +{ + return PutEscapedString(buffer, size, str, quote); +} + +JS_PUBLIC_API(size_t) +JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote) +{ + JSLinearString *linearStr = str->ensureLinear(cx); + if (!linearStr) + return size_t(-1); + return PutEscapedString(buffer, size, linearStr, quote); +} + +JS_PUBLIC_API(JSBool) +JS_FileEscapedString(FILE *fp, JSString *str, char quote) +{ + JSLinearString *linearStr = str->ensureLinear(NULL); + return linearStr && FileEscapedString(fp, linearStr, quote); +} + +JS_PUBLIC_API(JSString *) +JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length) +{ + CHECK_REQUEST(cx); + return js_NewString(cx, chars, length); +} + +JS_PUBLIC_API(JSString *) +JS_NewDependentString(JSContext *cx, JSString *str, size_t start, size_t length) +{ + CHECK_REQUEST(cx); + return js_NewDependentString(cx, str, start, length); +} + +JS_PUBLIC_API(JSString *) +JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right) +{ + CHECK_REQUEST(cx); + return js_ConcatStrings(cx, left, right); +} + +JS_PUBLIC_API(const jschar *) +JS_UndependString(JSContext *cx, JSString *str) +{ + CHECK_REQUEST(cx); + return str->getCharsZ(cx); +} + +JS_PUBLIC_API(JSBool) +JS_MakeStringImmutable(JSContext *cx, JSString *str) +{ + CHECK_REQUEST(cx); + return js_MakeStringImmutable(cx, str); +} + +JS_PUBLIC_API(JSBool) +JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, size_t *dstlenp) +{ + size_t n; + if (!dst) { + n = js_GetDeflatedStringLength(cx, src, srclen); + if (n == (size_t)-1) { + *dstlenp = 0; + return JS_FALSE; + } + *dstlenp = n; + return JS_TRUE; + } + + return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp); +} + +JS_PUBLIC_API(JSBool) +JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_t *dstlenp) +{ + return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp); +} + +JS_PUBLIC_API(char *) +JS_EncodeString(JSContext *cx, JSString *str) +{ + const jschar *chars = str->getChars(cx); + if (!chars) + return NULL; + return js_DeflateString(cx, chars, str->length()); +} + +JS_PUBLIC_API(size_t) +JS_GetStringEncodingLength(JSContext *cx, JSString *str) +{ + const jschar *chars = str->getChars(cx); + if (!chars) + return size_t(-1); + return js_GetDeflatedStringLength(cx, chars, str->length()); +} + +JS_PUBLIC_API(size_t) +JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length) +{ + /* + * FIXME bug 612141 - fix js_DeflateStringToBuffer interface so the result + * would allow to distinguish between insufficient buffer and encoding + * error. + */ + size_t writtenLength = length; + const jschar *chars = str->getChars(NULL); + if (!chars) + return size_t(-1); + if (js_DeflateStringToBuffer(NULL, chars, str->length(), buffer, &writtenLength)) { + JS_ASSERT(writtenLength <= length); + return writtenLength; + } + JS_ASSERT(writtenLength <= length); + size_t necessaryLength = js_GetDeflatedStringLength(NULL, chars, str->length()); + if (necessaryLength == size_t(-1)) + return size_t(-1); + if (writtenLength != length) { + /* Make sure that the buffer contains only valid UTF-8 sequences. */ + JS_ASSERT(js_CStringsAreUTF8); + PodZero(buffer + writtenLength, length - writtenLength); + } + return necessaryLength; +} + +JS_PUBLIC_API(JSBool) +JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space, + JSONWriteCallback callback, void *data) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, replacer, space); + StringBuffer sb(cx); + if (!js_Stringify(cx, Valueify(vp), replacer, Valueify(space), sb)) + return false; + return callback(sb.begin(), sb.length(), data); +} + +JS_PUBLIC_API(JSBool) +JS_TryJSON(JSContext *cx, jsval *vp) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, *vp); + return js_TryJSON(cx, Valueify(vp)); +} + +JS_PUBLIC_API(JSONParser *) +JS_BeginJSONParse(JSContext *cx, jsval *vp) +{ + CHECK_REQUEST(cx); + return js_BeginJSONParse(cx, Valueify(vp)); +} + +JS_PUBLIC_API(JSBool) +JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len) +{ + CHECK_REQUEST(cx); + return js_ConsumeJSONText(cx, jp, data, len); +} + +JS_PUBLIC_API(JSBool) +JS_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, reviver); + return js_FinishJSONParse(cx, jp, Valueify(reviver)); +} + +JS_PUBLIC_API(JSBool) +JS_ReadStructuredClone(JSContext *cx, const uint64 *buf, size_t nbytes, + uint32 version, jsval *vp, + const JSStructuredCloneCallbacks *optionalCallbacks, + void *closure) +{ + if (version > JS_STRUCTURED_CLONE_VERSION) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CLONE_VERSION); + return false; + } + const JSStructuredCloneCallbacks *callbacks = + optionalCallbacks ? + optionalCallbacks : + cx->runtime->structuredCloneCallbacks; + return ReadStructuredClone(cx, buf, nbytes, Valueify(vp), callbacks, closure); +} + +JS_PUBLIC_API(JSBool) +JS_WriteStructuredClone(JSContext *cx, jsval v, uint64 **bufp, size_t *nbytesp, + const JSStructuredCloneCallbacks *optionalCallbacks, + void *closure) +{ + const JSStructuredCloneCallbacks *callbacks = + optionalCallbacks ? + optionalCallbacks : + cx->runtime->structuredCloneCallbacks; + return WriteStructuredClone(cx, Valueify(v), (uint64_t **) bufp, nbytesp, + callbacks, closure); +} + +JS_PUBLIC_API(JSBool) +JS_StructuredClone(JSContext *cx, jsval v, jsval *vp, + ReadStructuredCloneOp optionalReadOp, + const JSStructuredCloneCallbacks *optionalCallbacks, + void *closure) +{ + const JSStructuredCloneCallbacks *callbacks = + optionalCallbacks ? + optionalCallbacks : + cx->runtime->structuredCloneCallbacks; + JSAutoStructuredCloneBuffer buf; + return buf.write(cx, v, callbacks, closure) && + buf.read(vp, cx, callbacks, closure); +} + +JS_PUBLIC_API(void) +JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks) +{ + rt->structuredCloneCallbacks = callbacks; +} + +JS_PUBLIC_API(JSBool) +JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32 *p1, uint32 *p2) +{ + return r->input().readPair((uint32_t *) p1, (uint32_t *) p2); +} + +JS_PUBLIC_API(JSBool) +JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len) +{ + return r->input().readBytes(p, len); +} + +JS_PUBLIC_API(JSBool) +JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32 tag, uint32 data) +{ + return w->output().writePair(tag, data); +} + +JS_PUBLIC_API(JSBool) +JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len) +{ + return w->output().writeBytes(p, len); +} + +/* + * The following determines whether C Strings are to be treated as UTF-8 + * or ISO-8859-1. For correct operation, it must be set prior to the + * first call to JS_NewRuntime. + */ +#ifndef JS_C_STRINGS_ARE_UTF8 +JSBool js_CStringsAreUTF8 = JS_FALSE; +#endif + +JS_PUBLIC_API(JSBool) +JS_CStringsAreUTF8() +{ + return js_CStringsAreUTF8; +} + +JS_PUBLIC_API(void) +JS_SetCStringsAreUTF8() +{ + JS_ASSERT(!js_NewRuntimeWasCalled); + +#ifndef JS_C_STRINGS_ARE_UTF8 + js_CStringsAreUTF8 = JS_TRUE; +#endif +} + +/************************************************************************/ + +JS_PUBLIC_API(void) +JS_ReportError(JSContext *cx, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap); + va_end(ap); +} + +JS_PUBLIC_API(void) +JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback, + void *userRef, const uintN errorNumber, ...) +{ + va_list ap; + + va_start(ap, errorNumber); + js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef, + errorNumber, JS_TRUE, ap); + va_end(ap); +} + +JS_PUBLIC_API(void) +JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback, + void *userRef, const uintN errorNumber, ...) +{ + va_list ap; + + va_start(ap, errorNumber); + js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef, + errorNumber, JS_FALSE, ap); + va_end(ap); +} + +JS_PUBLIC_API(JSBool) +JS_ReportWarning(JSContext *cx, const char *format, ...) +{ + va_list ap; + JSBool ok; + + va_start(ap, format); + ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap); + va_end(ap); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags, + JSErrorCallback errorCallback, void *userRef, + const uintN errorNumber, ...) +{ + va_list ap; + JSBool ok; + + va_start(ap, errorNumber); + ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef, + errorNumber, JS_TRUE, ap); + va_end(ap); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags, + JSErrorCallback errorCallback, void *userRef, + const uintN errorNumber, ...) +{ + va_list ap; + JSBool ok; + + va_start(ap, errorNumber); + ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef, + errorNumber, JS_FALSE, ap); + va_end(ap); + return ok; +} + +JS_PUBLIC_API(void) +JS_ReportOutOfMemory(JSContext *cx) +{ + js_ReportOutOfMemory(cx); +} + +JS_PUBLIC_API(void) +JS_ReportAllocationOverflow(JSContext *cx) +{ + js_ReportAllocationOverflow(cx); +} + +JS_PUBLIC_API(JSErrorReporter) +JS_SetErrorReporter(JSContext *cx, JSErrorReporter er) +{ + JSErrorReporter older; + + older = cx->errorReporter; + cx->errorReporter = er; + return older; +} + +/************************************************************************/ + +/* + * Dates. + */ +JS_PUBLIC_API(JSObject *) +JS_NewDateObject(JSContext *cx, int year, int mon, int mday, int hour, int min, int sec) +{ + CHECK_REQUEST(cx); + return js_NewDateObject(cx, year, mon, mday, hour, min, sec); +} + +JS_PUBLIC_API(JSObject *) +JS_NewDateObjectMsec(JSContext *cx, jsdouble msec) +{ + CHECK_REQUEST(cx); + return js_NewDateObjectMsec(cx, msec); +} + +JS_PUBLIC_API(JSBool) +JS_ObjectIsDate(JSContext *cx, JSObject *obj) +{ + JS_ASSERT(obj); + return obj->isDate(); +} + +/************************************************************************/ + +/* + * Regular Expressions. + */ +JS_PUBLIC_API(JSObject *) +JS_NewRegExpObject(JSContext *cx, JSObject *obj, char *bytes, size_t length, uintN flags) +{ + CHECK_REQUEST(cx); + jschar *chars = js_InflateString(cx, bytes, &length); + if (!chars) + return NULL; + RegExpStatics *res = RegExpStatics::extractFrom(obj); + JSObject *reobj = RegExp::createObject(cx, res, chars, length, flags); + cx->free(chars); + return reobj; +} + +JS_PUBLIC_API(JSObject *) +JS_NewUCRegExpObject(JSContext *cx, JSObject *obj, jschar *chars, size_t length, uintN flags) +{ + CHECK_REQUEST(cx); + RegExpStatics *res = RegExpStatics::extractFrom(obj); + return RegExp::createObject(cx, res, chars, length, flags); +} + +JS_PUBLIC_API(void) +JS_SetRegExpInput(JSContext *cx, JSObject *obj, JSString *input, JSBool multiline) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, input); + + RegExpStatics::extractFrom(obj)->reset(input, !!multiline); +} + +JS_PUBLIC_API(void) +JS_ClearRegExpStatics(JSContext *cx, JSObject *obj) +{ + CHECK_REQUEST(cx); + JS_ASSERT(obj); + + RegExpStatics::extractFrom(obj)->clear(); +} + +JS_PUBLIC_API(JSBool) +JS_ExecuteRegExp(JSContext *cx, JSObject *obj, JSObject *reobj, jschar *chars, size_t length, + size_t *indexp, JSBool test, jsval *rval) +{ + CHECK_REQUEST(cx); + + RegExp *re = RegExp::extractFrom(reobj); + if (!re) + return false; + + JSString *str = js_NewStringCopyN(cx, chars, length); + if (!str) + return false; + + return re->execute(cx, RegExpStatics::extractFrom(obj), str, indexp, test, Valueify(rval)); +} + +JS_PUBLIC_API(JSObject *) +JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, uintN flags) +{ + CHECK_REQUEST(cx); + jschar *chars = js_InflateString(cx, bytes, &length); + if (!chars) + return NULL; + JSObject *obj = RegExp::createObjectNoStatics(cx, chars, length, flags); + cx->free(chars); + return obj; +} + +JS_PUBLIC_API(JSObject *) +JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, uintN flags) +{ + CHECK_REQUEST(cx); + return RegExp::createObjectNoStatics(cx, chars, length, flags); +} + +JS_PUBLIC_API(JSBool) +JS_ExecuteRegExpNoStatics(JSContext *cx, JSObject *obj, jschar *chars, size_t length, + size_t *indexp, JSBool test, jsval *rval) +{ + CHECK_REQUEST(cx); + + RegExp *re = RegExp::extractFrom(obj); + if (!re) + return false; + + JSString *str = js_NewStringCopyN(cx, chars, length); + if (!str) + return false; + + return re->executeNoStatics(cx, str, indexp, test, Valueify(rval)); +} + +/************************************************************************/ + +JS_PUBLIC_API(void) +JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks) +{ + cx->localeCallbacks = callbacks; +} + +JS_PUBLIC_API(JSLocaleCallbacks *) +JS_GetLocaleCallbacks(JSContext *cx) +{ + return cx->localeCallbacks; +} + +/************************************************************************/ + +JS_PUBLIC_API(JSBool) +JS_IsExceptionPending(JSContext *cx) +{ + return (JSBool) cx->isExceptionPending(); +} + +JS_PUBLIC_API(JSBool) +JS_GetPendingException(JSContext *cx, jsval *vp) +{ + CHECK_REQUEST(cx); + if (!cx->isExceptionPending()) + return JS_FALSE; + Valueify(*vp) = cx->getPendingException(); + assertSameCompartment(cx, *vp); + return JS_TRUE; +} + +JS_PUBLIC_API(void) +JS_SetPendingException(JSContext *cx, jsval v) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + cx->setPendingException(Valueify(v)); +} + +JS_PUBLIC_API(void) +JS_ClearPendingException(JSContext *cx) +{ + cx->clearPendingException(); +} + +JS_PUBLIC_API(JSBool) +JS_ReportPendingException(JSContext *cx) +{ + JSBool ok; + JSPackedBool save; + + CHECK_REQUEST(cx); + + /* + * Set cx->generatingError to suppress the standard error-to-exception + * conversion done by all {js,JS}_Report* functions except for OOM. The + * cx->generatingError flag was added to suppress recursive divergence + * under js_ErrorToException, but it serves for our purposes here too. + */ + save = cx->generatingError; + cx->generatingError = JS_TRUE; + ok = js_ReportUncaughtException(cx); + cx->generatingError = save; + return ok; +} + +struct JSExceptionState { + JSBool throwing; + jsval exception; +}; + +JS_PUBLIC_API(JSExceptionState *) +JS_SaveExceptionState(JSContext *cx) +{ + JSExceptionState *state; + + CHECK_REQUEST(cx); + state = (JSExceptionState *) cx->malloc(sizeof(JSExceptionState)); + if (state) { + state->throwing = JS_GetPendingException(cx, &state->exception); + if (state->throwing && JSVAL_IS_GCTHING(state->exception)) + js_AddRoot(cx, Valueify(&state->exception), "JSExceptionState.exception"); + } + return state; +} + +JS_PUBLIC_API(void) +JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state) +{ + CHECK_REQUEST(cx); + if (state) { + if (state->throwing) + JS_SetPendingException(cx, state->exception); + else + JS_ClearPendingException(cx); + JS_DropExceptionState(cx, state); + } +} + +JS_PUBLIC_API(void) +JS_DropExceptionState(JSContext *cx, JSExceptionState *state) +{ + CHECK_REQUEST(cx); + if (state) { + if (state->throwing && JSVAL_IS_GCTHING(state->exception)) { + assertSameCompartment(cx, state->exception); + JS_RemoveValueRoot(cx, &state->exception); + } + cx->free(state); + } +} + +JS_PUBLIC_API(JSErrorReport *) +JS_ErrorFromException(JSContext *cx, jsval v) +{ + CHECK_REQUEST(cx); + assertSameCompartment(cx, v); + return js_ErrorFromException(cx, v); +} + +JS_PUBLIC_API(JSBool) +JS_ThrowReportedError(JSContext *cx, const char *message, + JSErrorReport *reportp) +{ + return JS_IsRunning(cx) && + js_ErrorToException(cx, message, reportp, NULL, NULL); +} + +JS_PUBLIC_API(JSBool) +JS_ThrowStopIteration(JSContext *cx) +{ + return js_ThrowStopIteration(cx); +} + +/* + * Get the owning thread id of a context. Returns 0 if the context is not + * owned by any thread. + */ +JS_PUBLIC_API(jsword) +JS_GetContextThread(JSContext *cx) +{ +#ifdef JS_THREADSAFE + return reinterpret_cast(JS_THREAD_ID(cx)); +#else + return 0; +#endif +} + +/* + * Set the current thread as the owning thread of a context. Returns the + * old owning thread id, or -1 if the operation failed. + */ +JS_PUBLIC_API(jsword) +JS_SetContextThread(JSContext *cx) +{ +#ifdef JS_THREADSAFE + JS_ASSERT(!cx->outstandingRequests); + if (cx->thread) { + JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread)); + return reinterpret_cast(cx->thread->id); + } + + if (!js_InitContextThread(cx)) { + js_ReportOutOfMemory(cx); + return -1; + } + + /* Here the GC lock is still held after js_InitContextThread took it. */ + JS_UNLOCK_GC(cx->runtime); +#endif + return 0; +} + +JS_PUBLIC_API(jsword) +JS_ClearContextThread(JSContext *cx) +{ +#ifdef JS_THREADSAFE + /* + * cx must have exited all requests it entered and, if cx is associated + * with a thread, this must be called only from that thread. If not, this + * is a harmless no-op. + */ + JS_ASSERT(cx->outstandingRequests == 0); + JSThread *t = cx->thread; + if (!t) + return 0; + JS_ASSERT(CURRENT_THREAD_IS_ME(t)); + + /* + * We must not race with a GC that accesses cx->thread for all threads, + * see bug 476934. + */ + JSRuntime *rt = cx->runtime; + AutoLockGC lock(rt); + js_WaitForGC(rt); + js_ClearContextThread(cx); + JS_ASSERT_IF(JS_CLIST_IS_EMPTY(&t->contextList), !t->data.requestDepth); + + /* + * We can access t->id as long as the GC lock is held and we cannot race + * with the GC that may delete t. + */ + return reinterpret_cast(t->id); +#else + return 0; +#endif +} + +#ifdef JS_GC_ZEAL +JS_PUBLIC_API(void) +JS_SetGCZeal(JSContext *cx, uint8 zeal) +{ + cx->runtime->gcZeal = zeal; +} +#endif + +/************************************************************************/ + +#if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN) && !defined (WINCE) + +#include "jswin.h" + +/* + * Initialization routine for the JS DLL. + */ +BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved) +{ + return TRUE; +} + +#endif diff --git a/js/src/jsapi.h b/js/src/jsapi.h new file mode 100644 index 0000000..7a4bee3 --- /dev/null +++ b/js/src/jsapi.h @@ -0,0 +1,3842 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsapi_h___ +#define jsapi_h___ +/* + * JavaScript API. + */ +#include +#include +#include "js-config.h" +#include "jspubtd.h" +#include "jsutil.h" + +JS_BEGIN_EXTERN_C + +/* + * In release builds, jsval and jsid are defined to be integral types. This + * prevents many bugs from being caught at compile time. E.g.: + * + * jsval v = ... + * if (v == JS_TRUE) // error + * ... + * + * jsid id = v; // error + * + * To catch more errors, jsval and jsid are given struct types in debug builds. + * Struct assignment and (in C++) operator== allow correct code to be mostly + * oblivious to the change. This feature can be explicitly disabled in debug + * builds by defining JS_NO_JSVAL_JSID_STRUCT_TYPES. + */ +#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES + +/* Well-known JS values. N.B. These constants are initialized at startup. */ +extern JS_PUBLIC_DATA(jsval) JSVAL_NULL; +extern JS_PUBLIC_DATA(jsval) JSVAL_ZERO; +extern JS_PUBLIC_DATA(jsval) JSVAL_ONE; +extern JS_PUBLIC_DATA(jsval) JSVAL_FALSE; +extern JS_PUBLIC_DATA(jsval) JSVAL_TRUE; +extern JS_PUBLIC_DATA(jsval) JSVAL_VOID; + +#else + +/* Well-known JS values. */ +#define JSVAL_NULL BUILD_JSVAL(JSVAL_TAG_NULL, 0) +#define JSVAL_ZERO BUILD_JSVAL(JSVAL_TAG_INT32, 0) +#define JSVAL_ONE BUILD_JSVAL(JSVAL_TAG_INT32, 1) +#define JSVAL_FALSE BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_FALSE) +#define JSVAL_TRUE BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_TRUE) +#define JSVAL_VOID BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0) + +#endif + +/************************************************************************/ + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_NULL(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_NULL_IMPL(l); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_VOID(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_UNDEFINED_IMPL(l); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_INT(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_INT32_IMPL(l); +} + +static JS_ALWAYS_INLINE jsint +JSVAL_TO_INT(jsval v) +{ + jsval_layout l; + JS_ASSERT(JSVAL_IS_INT(v)); + l.asBits = JSVAL_BITS(v); + return JSVAL_TO_INT32_IMPL(l); +} + +#define JSVAL_INT_BITS 32 +#define JSVAL_INT_MIN ((jsint)0x80000000) +#define JSVAL_INT_MAX ((jsint)0x7fffffff) + +static JS_ALWAYS_INLINE jsval +INT_TO_JSVAL(int32 i) +{ + return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i)); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_DOUBLE(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_DOUBLE_IMPL(l); +} + +static JS_ALWAYS_INLINE jsdouble +JSVAL_TO_DOUBLE(jsval v) +{ + jsval_layout l; + JS_ASSERT(JSVAL_IS_DOUBLE(v)); + l.asBits = JSVAL_BITS(v); + return l.asDouble; +} + +static JS_ALWAYS_INLINE jsval +DOUBLE_TO_JSVAL(jsdouble d) +{ + d = JS_CANONICALIZE_NAN(d); + return IMPL_TO_JSVAL(DOUBLE_TO_JSVAL_IMPL(d)); +} + +static JS_ALWAYS_INLINE jsval +UINT_TO_JSVAL(uint32 i) +{ + if (i <= JSVAL_INT_MAX) + return INT_TO_JSVAL((int32)i); + return DOUBLE_TO_JSVAL((jsdouble)i); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_NUMBER(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_NUMBER_IMPL(l); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_STRING(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_STRING_IMPL(l); +} + +static JS_ALWAYS_INLINE JSString * +JSVAL_TO_STRING(jsval v) +{ + jsval_layout l; + JS_ASSERT(JSVAL_IS_STRING(v)); + l.asBits = JSVAL_BITS(v); + return JSVAL_TO_STRING_IMPL(l); +} + +static JS_ALWAYS_INLINE jsval +STRING_TO_JSVAL(JSString *str) +{ + return IMPL_TO_JSVAL(STRING_TO_JSVAL_IMPL(str)); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_OBJECT(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_OBJECT_OR_NULL_IMPL(l); +} + +static JS_ALWAYS_INLINE JSObject * +JSVAL_TO_OBJECT(jsval v) +{ + jsval_layout l; + JS_ASSERT(JSVAL_IS_OBJECT(v)); + l.asBits = JSVAL_BITS(v); + return JSVAL_TO_OBJECT_IMPL(l); +} + +static JS_ALWAYS_INLINE jsval +OBJECT_TO_JSVAL(JSObject *obj) +{ + if (obj) + return IMPL_TO_JSVAL(OBJECT_TO_JSVAL_IMPL(obj)); + return JSVAL_NULL; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_BOOLEAN(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_BOOLEAN_IMPL(l); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_TO_BOOLEAN(jsval v) +{ + jsval_layout l; + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + l.asBits = JSVAL_BITS(v); + return JSVAL_TO_BOOLEAN_IMPL(l); +} + +static JS_ALWAYS_INLINE jsval +BOOLEAN_TO_JSVAL(JSBool b) +{ + return IMPL_TO_JSVAL(BOOLEAN_TO_JSVAL_IMPL(b)); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_PRIMITIVE(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_PRIMITIVE_IMPL(l); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_GCTHING(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_GCTHING_IMPL(l); +} + +static JS_ALWAYS_INLINE void * +JSVAL_TO_GCTHING(jsval v) +{ + jsval_layout l; + JS_ASSERT(JSVAL_IS_GCTHING(v)); + l.asBits = JSVAL_BITS(v); + return JSVAL_TO_GCTHING_IMPL(l); +} + +/* To be GC-safe, privates are tagged as doubles. */ + +static JS_ALWAYS_INLINE jsval +PRIVATE_TO_JSVAL(void *ptr) +{ + return IMPL_TO_JSVAL(PRIVATE_PTR_TO_JSVAL_IMPL(ptr)); +} + +static JS_ALWAYS_INLINE void * +JSVAL_TO_PRIVATE(jsval v) +{ + jsval_layout l; + JS_ASSERT(JSVAL_IS_DOUBLE(v)); + l.asBits = JSVAL_BITS(v); + return JSVAL_TO_PRIVATE_PTR_IMPL(l); +} + +/************************************************************************/ + +/* + * A jsid is an identifier for a property or method of an object which is + * either a 31-bit signed integer, interned string or object. If XML is + * enabled, there is an additional singleton jsid value; see + * JS_DEFAULT_XML_NAMESPACE_ID below. Finally, there is an additional jsid + * value, JSID_VOID, which does not occur in JS scripts but may be used to + * indicate the absence of a valid jsid. + * + * A jsid is not implicitly convertible to or from a jsval; JS_ValueToId or + * JS_IdToValue must be used instead. + */ + +#define JSID_TYPE_STRING 0x0 +#define JSID_TYPE_INT 0x1 +#define JSID_TYPE_VOID 0x2 +#define JSID_TYPE_OBJECT 0x4 +#define JSID_TYPE_DEFAULT_XML_NAMESPACE 0x6 +#define JSID_TYPE_MASK 0x7 + +/* + * Avoid using canonical 'id' for jsid parameters since this is a magic word in + * Objective-C++ which, apparently, wants to be able to #include jsapi.h. + */ +#define id iden + +static JS_ALWAYS_INLINE JSBool +JSID_IS_STRING(jsid id) +{ + return (JSID_BITS(id) & JSID_TYPE_MASK) == 0; +} + +static JS_ALWAYS_INLINE JSString * +JSID_TO_STRING(jsid id) +{ + JS_ASSERT(JSID_IS_STRING(id)); + return (JSString *)(JSID_BITS(id)); +} + +static JS_ALWAYS_INLINE JSBool +JSID_IS_ZERO(jsid id) +{ + return JSID_BITS(id) == 0; +} + +JS_PUBLIC_API(JSBool) +JS_StringHasBeenInterned(JSString *str); + +/* A jsid may only hold an interned JSString. */ +static JS_ALWAYS_INLINE jsid +INTERNED_STRING_TO_JSID(JSString *str) +{ + jsid id; + JS_ASSERT(str); + JS_ASSERT(JS_StringHasBeenInterned(str)); + JS_ASSERT(((size_t)str & JSID_TYPE_MASK) == 0); + JSID_BITS(id) = (size_t)str; + return id; +} + +static JS_ALWAYS_INLINE JSBool +JSID_IS_INT(jsid id) +{ + return !!(JSID_BITS(id) & JSID_TYPE_INT); +} + +static JS_ALWAYS_INLINE int32 +JSID_TO_INT(jsid id) +{ + JS_ASSERT(JSID_IS_INT(id)); + return ((int32)JSID_BITS(id)) >> 1; +} + +/* + * Note: when changing these values, verify that their use in + * js_CheckForStringIndex is still valid. + */ +#define JSID_INT_MIN (-(1 << 30)) +#define JSID_INT_MAX ((1 << 30) - 1) + +static JS_ALWAYS_INLINE JSBool +INT_FITS_IN_JSID(int32 i) +{ + return ((jsuint)(i) - (jsuint)JSID_INT_MIN <= + (jsuint)(JSID_INT_MAX - JSID_INT_MIN)); +} + +static JS_ALWAYS_INLINE jsid +INT_TO_JSID(int32 i) +{ + jsid id; + JS_ASSERT(INT_FITS_IN_JSID(i)); + JSID_BITS(id) = ((i << 1) | JSID_TYPE_INT); + return id; +} + +static JS_ALWAYS_INLINE JSBool +JSID_IS_OBJECT(jsid id) +{ + return (JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_OBJECT && + (size_t)JSID_BITS(id) != JSID_TYPE_OBJECT; +} + +static JS_ALWAYS_INLINE JSObject * +JSID_TO_OBJECT(jsid id) +{ + JS_ASSERT(JSID_IS_OBJECT(id)); + return (JSObject *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); +} + +static JS_ALWAYS_INLINE jsid +OBJECT_TO_JSID(JSObject *obj) +{ + jsid id; + JS_ASSERT(obj != NULL); + JS_ASSERT(((size_t)obj & JSID_TYPE_MASK) == 0); + JSID_BITS(id) = ((size_t)obj | JSID_TYPE_OBJECT); + return id; +} + +static JS_ALWAYS_INLINE JSBool +JSID_IS_GCTHING(jsid id) +{ + return JSID_IS_STRING(id) || JSID_IS_OBJECT(id); +} + +static JS_ALWAYS_INLINE void * +JSID_TO_GCTHING(jsid id) +{ + return (void *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); +} + +/* + * The magic XML namespace id is not a valid jsid. Global object classes in + * embeddings that enable JS_HAS_XML_SUPPORT (E4X) should handle this id. + */ + +static JS_ALWAYS_INLINE JSBool +JSID_IS_DEFAULT_XML_NAMESPACE(jsid id) +{ + JS_ASSERT_IF(((size_t)JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_DEFAULT_XML_NAMESPACE, + JSID_BITS(id) == JSID_TYPE_DEFAULT_XML_NAMESPACE); + return ((size_t)JSID_BITS(id) == JSID_TYPE_DEFAULT_XML_NAMESPACE); +} + +#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES +extern JS_PUBLIC_DATA(jsid) JS_DEFAULT_XML_NAMESPACE_ID; +#else +#define JS_DEFAULT_XML_NAMESPACE_ID ((jsid)JSID_TYPE_DEFAULT_XML_NAMESPACE) +#endif + +/* + * A void jsid is not a valid id and only arises as an exceptional API return + * value, such as in JS_NextProperty. Embeddings must not pass JSID_VOID into + * JSAPI entry points expecting a jsid and do not need to handle JSID_VOID in + * hooks receiving a jsid except when explicitly noted in the API contract. + */ + +static JS_ALWAYS_INLINE JSBool +JSID_IS_VOID(jsid id) +{ + JS_ASSERT_IF(((size_t)JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_VOID, + JSID_BITS(id) == JSID_TYPE_VOID); + return ((size_t)JSID_BITS(id) == JSID_TYPE_VOID); +} + +static JS_ALWAYS_INLINE JSBool +JSID_IS_EMPTY(jsid id) +{ + return ((size_t)JSID_BITS(id) == JSID_TYPE_OBJECT); +} + +#undef id + +#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES +extern JS_PUBLIC_DATA(jsid) JSID_VOID; +extern JS_PUBLIC_DATA(jsid) JSID_EMPTY; +#else +# define JSID_VOID ((jsid)JSID_TYPE_VOID) +# define JSID_EMPTY ((jsid)JSID_TYPE_OBJECT) +#endif + +/************************************************************************/ + +/* Lock and unlock the GC thing held by a jsval. */ +#define JSVAL_LOCK(cx,v) (JSVAL_IS_GCTHING(v) \ + ? JS_LockGCThing(cx, JSVAL_TO_GCTHING(v)) \ + : JS_TRUE) +#define JSVAL_UNLOCK(cx,v) (JSVAL_IS_GCTHING(v) \ + ? JS_UnlockGCThing(cx, JSVAL_TO_GCTHING(v)) \ + : JS_TRUE) + +/* Property attributes, set in JSPropertySpec and passed to API functions. */ +#define JSPROP_ENUMERATE 0x01 /* property is visible to for/in loop */ +#define JSPROP_READONLY 0x02 /* not settable: assignment is no-op */ +#define JSPROP_PERMANENT 0x04 /* property cannot be deleted */ +#define JSPROP_GETTER 0x10 /* property holds getter function */ +#define JSPROP_SETTER 0x20 /* property holds setter function */ +#define JSPROP_SHARED 0x40 /* don't allocate a value slot for this + property; don't copy the property on + set of the same-named property in an + object that delegates to a prototype + containing this property */ +#define JSPROP_INDEX 0x80 /* name is actually (jsint) index */ +#define JSPROP_SHORTID 0x100 /* set in JSPropertyDescriptor.attrs + if getters/setters use a shortid */ + +/* Function flags, set in JSFunctionSpec and passed to JS_NewFunction etc. */ +#define JSFUN_LAMBDA 0x08 /* expressed, not declared, function */ +#define JSFUN_HEAVYWEIGHT 0x80 /* activation requires a Call object */ + +#define JSFUN_HEAVYWEIGHT_TEST(f) ((f) & JSFUN_HEAVYWEIGHT) + +/* 0x0100 is unused */ +#define JSFUN_CONSTRUCTOR 0x0200 /* native that can be called as a ctor + without creating a this object */ + +#define JSFUN_FLAGS_MASK 0x07f8 /* overlay JSFUN_* attributes -- + bits 12-15 are used internally to + flag interpreted functions */ + +#define JSFUN_STUB_GSOPS 0x1000 /* use JS_PropertyStub getter/setter + instead of defaulting to class gsops + for property holding function */ + +/* + * Re-use JSFUN_LAMBDA, which applies only to scripted functions, for use in + * JSFunctionSpec arrays that specify generic native prototype methods, i.e., + * methods of a class prototype that are exposed as static methods taking an + * extra leading argument: the generic |this| parameter. + * + * If you set this flag in a JSFunctionSpec struct's flags initializer, then + * that struct must live at least as long as the native static method object + * created due to this flag by JS_DefineFunctions or JS_InitClass. Typically + * JSFunctionSpec structs are allocated in static arrays. + */ +#define JSFUN_GENERIC_NATIVE JSFUN_LAMBDA + +/* + * Microseconds since the epoch, midnight, January 1, 1970 UTC. See the + * comment in jstypes.h regarding safe int64 usage. + */ +extern JS_PUBLIC_API(int64) +JS_Now(void); + +/* Don't want to export data, so provide accessors for non-inline jsvals. */ +extern JS_PUBLIC_API(jsval) +JS_GetNaNValue(JSContext *cx); + +extern JS_PUBLIC_API(jsval) +JS_GetNegativeInfinityValue(JSContext *cx); + +extern JS_PUBLIC_API(jsval) +JS_GetPositiveInfinityValue(JSContext *cx); + +extern JS_PUBLIC_API(jsval) +JS_GetEmptyStringValue(JSContext *cx); + +extern JS_PUBLIC_API(JSString *) +JS_GetEmptyString(JSRuntime *rt); + +/* + * Format is a string of the following characters (spaces are insignificant), + * specifying the tabulated type conversions: + * + * b JSBool Boolean + * c uint16/jschar ECMA uint16, Unicode char + * i int32 ECMA int32 + * u uint32 ECMA uint32 + * j int32 Rounded int32 (coordinate) + * d jsdouble IEEE double + * I jsdouble Integral IEEE double + * S JSString * Unicode string, accessed by a JSString pointer + * W jschar * Unicode character vector, 0-terminated (W for wide) + * o JSObject * Object reference + * f JSFunction * Function private + * v jsval Argument value (no conversion) + * * N/A Skip this argument (no vararg) + * / N/A End of required arguments + * + * The variable argument list after format must consist of &b, &c, &s, e.g., + * where those variables have the types given above. For the pointer types + * char *, JSString *, and JSObject *, the pointed-at memory returned belongs + * to the JS runtime, not to the calling native code. The runtime promises + * to keep this memory valid so long as argv refers to allocated stack space + * (so long as the native function is active). + * + * Fewer arguments than format specifies may be passed only if there is a / + * in format after the last required argument specifier and argc is at least + * the number of required arguments. More arguments than format specifies + * may be passed without error; it is up to the caller to deal with trailing + * unconverted arguments. + */ +extern JS_PUBLIC_API(JSBool) +JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format, + ...); + +#ifdef va_start +extern JS_PUBLIC_API(JSBool) +JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, + const char *format, va_list ap); +#endif + +#ifdef JS_ARGUMENT_FORMATTER_DEFINED + +/* + * Add and remove a format string handler for JS_{Convert,Push}Arguments{,VA}. + * The handler function has this signature (see jspubtd.h): + * + * JSBool MyArgumentFormatter(JSContext *cx, const char *format, + * JSBool fromJS, jsval **vpp, va_list *app); + * + * It should return true on success, and return false after reporting an error + * or detecting an already-reported error. + * + * For a given format string, for example "AA", the formatter is called from + * JS_ConvertArgumentsVA like so: + * + * formatter(cx, "AA...", JS_TRUE, &sp, &ap); + * + * sp points into the arguments array on the JS stack, while ap points into + * the stdarg.h va_list on the C stack. The JS_TRUE passed for fromJS tells + * the formatter to convert zero or more jsvals at sp to zero or more C values + * accessed via pointers-to-values at ap, updating both sp (via *vpp) and ap + * (via *app) to point past the converted arguments and their result pointers + * on the C stack. + * + * When called from JS_PushArgumentsVA, the formatter is invoked thus: + * + * formatter(cx, "AA...", JS_FALSE, &sp, &ap); + * + * where JS_FALSE for fromJS means to wrap the C values at ap according to the + * format specifier and store them at sp, updating ap and sp appropriately. + * + * The "..." after "AA" is the rest of the format string that was passed into + * JS_{Convert,Push}Arguments{,VA}. The actual format trailing substring used + * in each Convert or PushArguments call is passed to the formatter, so that + * one such function may implement several formats, in order to share code. + * + * Remove just forgets about any handler associated with format. Add does not + * copy format, it points at the string storage allocated by the caller, which + * is typically a string constant. If format is in dynamic storage, it is up + * to the caller to keep the string alive until Remove is called. + */ +extern JS_PUBLIC_API(JSBool) +JS_AddArgumentFormatter(JSContext *cx, const char *format, + JSArgumentFormatter formatter); + +extern JS_PUBLIC_API(void) +JS_RemoveArgumentFormatter(JSContext *cx, const char *format); + +#endif /* JS_ARGUMENT_FORMATTER_DEFINED */ + +extern JS_PUBLIC_API(JSBool) +JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp); + +extern JS_PUBLIC_API(JSFunction *) +JS_ValueToFunction(JSContext *cx, jsval v); + +extern JS_PUBLIC_API(JSFunction *) +JS_ValueToConstructor(JSContext *cx, jsval v); + +extern JS_PUBLIC_API(JSString *) +JS_ValueToString(JSContext *cx, jsval v); + +extern JS_PUBLIC_API(JSString *) +JS_ValueToSource(JSContext *cx, jsval v); + +extern JS_PUBLIC_API(JSBool) +JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp); + +extern JS_PUBLIC_API(JSBool) +JS_DoubleIsInt32(jsdouble d, jsint *ip); + +/* + * Convert a value to a number, then to an int32, according to the ECMA rules + * for ToInt32. + */ +extern JS_PUBLIC_API(JSBool) +JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip); + +/* + * Convert a value to a number, then to a uint32, according to the ECMA rules + * for ToUint32. + */ +extern JS_PUBLIC_API(JSBool) +JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip); + +/* + * Convert a value to a number, then to an int32 if it fits by rounding to + * nearest; but failing with an error report if the double is out of range + * or unordered. + */ +extern JS_PUBLIC_API(JSBool) +JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip); + +/* + * ECMA ToUint16, for mapping a jsval to a Unicode point. + */ +extern JS_PUBLIC_API(JSBool) +JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip); + +extern JS_PUBLIC_API(JSBool) +JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp); + +extern JS_PUBLIC_API(JSType) +JS_TypeOfValue(JSContext *cx, jsval v); + +extern JS_PUBLIC_API(const char *) +JS_GetTypeName(JSContext *cx, JSType type); + +extern JS_PUBLIC_API(JSBool) +JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal); + +extern JS_PUBLIC_API(JSBool) +JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same); + +/************************************************************************/ + +/* + * Initialization, locking, contexts, and memory allocation. + * + * It is important that the first runtime and first context be created in a + * single-threaded fashion, otherwise the behavior of the library is undefined. + * See: http://developer.mozilla.org/en/docs/Category:JSAPI_Reference + */ +#define JS_NewRuntime JS_Init +#define JS_DestroyRuntime JS_Finish +#define JS_LockRuntime JS_Lock +#define JS_UnlockRuntime JS_Unlock + +extern JS_PUBLIC_API(JSRuntime *) +JS_NewRuntime(uint32 maxbytes); + +/* Deprecated. */ +#define JS_CommenceRuntimeShutDown(rt) ((void) 0) + +extern JS_PUBLIC_API(void) +JS_DestroyRuntime(JSRuntime *rt); + +extern JS_PUBLIC_API(void) +JS_ShutDown(void); + +JS_PUBLIC_API(void *) +JS_GetRuntimePrivate(JSRuntime *rt); + +JS_PUBLIC_API(void) +JS_SetRuntimePrivate(JSRuntime *rt, void *data); + +extern JS_PUBLIC_API(void) +JS_BeginRequest(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_EndRequest(JSContext *cx); + +/* Yield to pending GC operations, regardless of request depth */ +extern JS_PUBLIC_API(void) +JS_YieldRequest(JSContext *cx); + +extern JS_PUBLIC_API(jsrefcount) +JS_SuspendRequest(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth); + +extern JS_PUBLIC_API(JSBool) +JS_IsInRequest(JSContext *cx); + +#ifdef __cplusplus +JS_END_EXTERN_C + +class JSAutoRequest { + public: + JSAutoRequest(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx), mSaveDepth(0) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_BeginRequest(mContext); + } + ~JSAutoRequest() { + JS_EndRequest(mContext); + } + + void suspend() { + mSaveDepth = JS_SuspendRequest(mContext); + } + void resume() { + JS_ResumeRequest(mContext, mSaveDepth); + } + + protected: + JSContext *mContext; + jsrefcount mSaveDepth; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + +#if 0 + private: + static void *operator new(size_t) CPP_THROW_NEW { return 0; }; + static void operator delete(void *, size_t) { }; +#endif +}; + +class JSAutoSuspendRequest { + public: + JSAutoSuspendRequest(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx), mSaveDepth(0) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + if (mContext) { + mSaveDepth = JS_SuspendRequest(mContext); + } + } + ~JSAutoSuspendRequest() { + resume(); + } + + void resume() { + if (mContext) { + JS_ResumeRequest(mContext, mSaveDepth); + mContext = 0; + } + } + + protected: + JSContext *mContext; + jsrefcount mSaveDepth; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + +#if 0 + private: + static void *operator new(size_t) CPP_THROW_NEW { return 0; }; + static void operator delete(void *, size_t) { }; +#endif +}; + +class JSAutoCheckRequest { + public: + JSAutoCheckRequest(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) { +#if defined JS_THREADSAFE && defined DEBUG + mContext = cx; + JS_ASSERT(JS_IsInRequest(cx)); +#endif + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + ~JSAutoCheckRequest() { +#if defined JS_THREADSAFE && defined DEBUG + JS_ASSERT(JS_IsInRequest(mContext)); +#endif + } + + + private: +#if defined JS_THREADSAFE && defined DEBUG + JSContext *mContext; +#endif + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +JS_BEGIN_EXTERN_C +#endif + +extern JS_PUBLIC_API(void) +JS_Lock(JSRuntime *rt); + +extern JS_PUBLIC_API(void) +JS_Unlock(JSRuntime *rt); + +extern JS_PUBLIC_API(JSContextCallback) +JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback); + +extern JS_PUBLIC_API(JSContext *) +JS_NewContext(JSRuntime *rt, size_t stackChunkSize); + +extern JS_PUBLIC_API(void) +JS_DestroyContext(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_DestroyContextNoGC(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_DestroyContextMaybeGC(JSContext *cx); + +extern JS_PUBLIC_API(void *) +JS_GetContextPrivate(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_SetContextPrivate(JSContext *cx, void *data); + +extern JS_PUBLIC_API(JSRuntime *) +JS_GetRuntime(JSContext *cx); + +extern JS_PUBLIC_API(JSContext *) +JS_ContextIterator(JSRuntime *rt, JSContext **iterp); + +extern JS_PUBLIC_API(JSVersion) +JS_GetVersion(JSContext *cx); + +extern JS_PUBLIC_API(JSVersion) +JS_SetVersion(JSContext *cx, JSVersion version); + +extern JS_PUBLIC_API(const char *) +JS_VersionToString(JSVersion version); + +extern JS_PUBLIC_API(JSVersion) +JS_StringToVersion(const char *string); + +/* + * JS options are orthogonal to version, and may be freely composed with one + * another as well as with version. + * + * JSOPTION_VAROBJFIX is recommended -- see the comments associated with the + * prototypes for JS_ExecuteScript, JS_EvaluateScript, etc. + */ +#define JSOPTION_STRICT JS_BIT(0) /* warn on dubious practice */ +#define JSOPTION_WERROR JS_BIT(1) /* convert warning to error */ +#define JSOPTION_VAROBJFIX JS_BIT(2) /* make JS_EvaluateScript use + the last object on its 'obj' + param's scope chain as the + ECMA 'variables object' */ +#define JSOPTION_PRIVATE_IS_NSISUPPORTS \ + JS_BIT(3) /* context private data points + to an nsISupports subclass */ +#define JSOPTION_COMPILE_N_GO JS_BIT(4) /* caller of JS_Compile*Script + promises to execute compiled + script once only; enables + compile-time scope chain + resolution of consts. */ +#define JSOPTION_ATLINE JS_BIT(5) /* //@line number ["filename"] + option supported for the + XUL preprocessor and kindred + beasts. */ +#define JSOPTION_XML JS_BIT(6) /* EMCAScript for XML support: + parse as a token, + not backward compatible with + the comment-hiding hack used + in HTML script tags. */ +#define JSOPTION_DONT_REPORT_UNCAUGHT \ + JS_BIT(8) /* When returning from the + outermost API call, prevent + uncaught exceptions from + being converted to error + reports */ + +#define JSOPTION_RELIMIT JS_BIT(9) /* Throw exception on any + regular expression which + backtracks more than n^3 + times, where n is length + of the input string */ +#define JSOPTION_ANONFUNFIX JS_BIT(10) /* Disallow function () {} in + statement context per + ECMA-262 Edition 3. */ + +#define JSOPTION_JIT JS_BIT(11) /* Enable JIT compilation. */ + +#define JSOPTION_NO_SCRIPT_RVAL JS_BIT(12) /* A promise to the compiler + that a null rval out-param + will be passed to each call + to JS_ExecuteScript. */ +#define JSOPTION_UNROOTED_GLOBAL JS_BIT(13) /* The GC will not root the + contexts' global objects + (see JS_GetGlobalObject), + leaving that up to the + embedding. */ + +#define JSOPTION_METHODJIT JS_BIT(14) /* Whole-method JIT. */ +#define JSOPTION_PROFILING JS_BIT(15) /* Profiler to make tracer/methodjit choices. */ +#define JSOPTION_METHODJIT_ALWAYS \ + JS_BIT(16) /* Always whole-method JIT, + don't tune at run-time. */ + +/* Options which reflect compile-time properties of scripts. */ +#define JSCOMPILEOPTION_MASK (JSOPTION_XML | JSOPTION_ANONFUNFIX) + +#define JSRUNOPTION_MASK (JS_BITMASK(17) & ~JSCOMPILEOPTION_MASK) +#define JSALLOPTION_MASK (JSCOMPILEOPTION_MASK | JSRUNOPTION_MASK) + +extern JS_PUBLIC_API(uint32) +JS_GetOptions(JSContext *cx); + +extern JS_PUBLIC_API(uint32) +JS_SetOptions(JSContext *cx, uint32 options); + +extern JS_PUBLIC_API(uint32) +JS_ToggleOptions(JSContext *cx, uint32 options); + +extern JS_PUBLIC_API(const char *) +JS_GetImplementationVersion(void); + +extern JS_PUBLIC_API(JSCompartmentCallback) +JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback); + +extern JS_PUBLIC_API(JSWrapObjectCallback) +JS_SetWrapObjectCallbacks(JSRuntime *rt, + JSWrapObjectCallback callback, + JSPreWrapCallback precallback); + +extern JS_PUBLIC_API(JSCrossCompartmentCall *) +JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target); + +extern JS_PUBLIC_API(void) +JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call); + +extern JS_PUBLIC_API(void *) +JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data); + +extern JS_PUBLIC_API(void *) +JS_GetCompartmentPrivate(JSContext *cx, JSCompartment *compartment); + +extern JS_PUBLIC_API(JSBool) +JS_WrapObject(JSContext *cx, JSObject **objp); + +extern JS_PUBLIC_API(JSBool) +JS_WrapValue(JSContext *cx, jsval *vp); + +extern JS_PUBLIC_API(JSObject *) +JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target); + +extern JS_FRIEND_API(JSObject *) +js_TransplantObjectWithWrapper(JSContext *cx, + JSObject *origobj, + JSObject *origwrapper, + JSObject *targetobj, + JSObject *targetwrapper); + +extern JS_FRIEND_API(JSObject *) +js_TransplantObjectWithWrapper(JSContext *cx, + JSObject *origobj, + JSObject *origwrapper, + JSObject *targetobj, + JSObject *targetwrapper); + +#ifdef __cplusplus +JS_END_EXTERN_C + +class JS_PUBLIC_API(JSAutoEnterCompartment) +{ + JSCrossCompartmentCall *call; + + public: + JSAutoEnterCompartment() : call(NULL) {} + + bool enter(JSContext *cx, JSObject *target); + + void enterAndIgnoreErrors(JSContext *cx, JSObject *target); + + bool entered() const { return call != NULL; } + + ~JSAutoEnterCompartment() { + if (call && call != reinterpret_cast(1)) + JS_LeaveCrossCompartmentCall(call); + } + + void swap(JSAutoEnterCompartment &other) { + JSCrossCompartmentCall *tmp = call; + call = other.call; + other.call = tmp; + } +}; + +JS_BEGIN_EXTERN_C +#endif + +extern JS_PUBLIC_API(JSObject *) +JS_GetGlobalObject(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_SetGlobalObject(JSContext *cx, JSObject *obj); + +/* + * Initialize standard JS class constructors, prototypes, and any top-level + * functions and constants associated with the standard classes (e.g. isNaN + * for Number). + * + * NB: This sets cx's global object to obj if it was null. + */ +extern JS_PUBLIC_API(JSBool) +JS_InitStandardClasses(JSContext *cx, JSObject *obj); + +/* + * Resolve id, which must contain either a string or an int, to a standard + * class name in obj if possible, defining the class's constructor and/or + * prototype and storing true in *resolved. If id does not name a standard + * class or a top-level property induced by initializing a standard class, + * store false in *resolved and just return true. Return false on error, + * as usual for JSBool result-typed API entry points. + * + * This API can be called directly from a global object class's resolve op, + * to define standard classes lazily. The class's enumerate op should call + * JS_EnumerateStandardClasses(cx, obj), to define eagerly during for..in + * loops any classes not yet resolved lazily. + */ +extern JS_PUBLIC_API(JSBool) +JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, + JSBool *resolved); + +extern JS_PUBLIC_API(JSBool) +JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj); + +/* + * Enumerate any already-resolved standard class ids into ida, or into a new + * JSIdArray if ida is null. Return the augmented array on success, null on + * failure with ida (if it was non-null on entry) destroyed. + */ +extern JS_PUBLIC_API(JSIdArray *) +JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, + JSIdArray *ida); + +extern JS_PUBLIC_API(JSBool) +JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, + JSObject **objp); + +extern JS_PUBLIC_API(JSObject *) +JS_GetScopeChain(JSContext *cx); + +extern JS_PUBLIC_API(JSObject *) +JS_GetGlobalForObject(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSObject *) +JS_GetGlobalForScopeChain(JSContext *cx); + +#ifdef JS_HAS_CTYPES +/* + * Initialize the 'ctypes' object on a global variable 'obj'. The 'ctypes' + * object will be sealed. + */ +extern JS_PUBLIC_API(JSBool) +JS_InitCTypesClass(JSContext *cx, JSObject *global); + +/* + * Convert a unicode string 'source' of length 'slen' to the platform native + * charset, returning a null-terminated string allocated with JS_malloc. On + * failure, this function should report an error. + */ +typedef char * +(* JSCTypesUnicodeToNativeFun)(JSContext *cx, const jschar *source, size_t slen); + +/* + * Set of function pointers that ctypes can use for various internal functions. + * See JS_SetCTypesCallbacks below. Providing NULL for a function is safe, + * and will result in the applicable ctypes functionality not being available. + */ +struct JSCTypesCallbacks { + JSCTypesUnicodeToNativeFun unicodeToNative; +}; + +typedef struct JSCTypesCallbacks JSCTypesCallbacks; + +/* + * Set the callbacks on the provided 'ctypesObj' object. 'callbacks' should be a + * pointer to static data that exists for the lifetime of 'ctypesObj', but it + * may safely be altered after calling this function and without having + * to call this function again. + */ +extern JS_PUBLIC_API(JSBool) +JS_SetCTypesCallbacks(JSContext *cx, JSObject *ctypesObj, JSCTypesCallbacks *callbacks); +#endif + +/* + * Macros to hide interpreter stack layout details from a JSFastNative using + * its jsval *vp parameter. The stack layout underlying invocation can't change + * without breaking source and binary compatibility (argv[-2] is well-known to + * be the callee jsval, and argv[-1] is as well known to be |this|). + * + * Note well: However, argv[-1] may be JSVAL_NULL where with slow natives it + * is the global object, so embeddings implementing fast natives *must* call + * JS_THIS or JS_THIS_OBJECT and test for failure indicated by a null return, + * which should propagate as a false return from native functions and hooks. + * + * To reduce boilerplace checks, JS_InstanceOf and JS_GetInstancePrivate now + * handle a null obj parameter by returning false (throwing a TypeError if + * given non-null argv), so most native functions that type-check their |this| + * parameter need not add null checking. + * + * NB: there is an anti-dependency between JS_CALLEE and JS_SET_RVAL: native + * methods that may inspect their callee must defer setting their return value + * until after any such possible inspection. Otherwise the return value will be + * inspected instead of the callee function object. + * + * WARNING: These are not (yet) mandatory macros, but new code outside of the + * engine should use them. In the Mozilla 2.0 milestone their definitions may + * change incompatibly. + * + * N.B. constructors must not use JS_THIS, as no 'this' object has been created. + */ + +#define JS_CALLEE(cx,vp) ((vp)[0]) +#define JS_THIS(cx,vp) JS_ComputeThis(cx, vp) +#define JS_THIS_OBJECT(cx,vp) (JSVAL_TO_OBJECT(JS_THIS(cx,vp))) +#define JS_ARGV(cx,vp) ((vp) + 2) +#define JS_RVAL(cx,vp) (*(vp)) +#define JS_SET_RVAL(cx,vp,v) (*(vp) = (v)) + +extern JS_PUBLIC_API(jsval) +JS_ComputeThis(JSContext *cx, jsval *vp); + +#ifdef __cplusplus +#undef JS_THIS +static inline jsval +JS_THIS(JSContext *cx, jsval *vp) +{ + return JSVAL_IS_PRIMITIVE(vp[1]) ? JS_ComputeThis(cx, vp) : vp[1]; +} +#endif + +/* + * |this| is passed to functions in ES5 without change. Functions themselves + * do any post-processing they desire to box |this|, compute the global object, + * &c. Use this macro to retrieve a function's unboxed |this| value. + * + * This macro must not be used in conjunction with JS_THIS or JS_THIS_OBJECT, + * or vice versa. Either use the provided this value with this macro, or + * compute the boxed this value using those. + * + * N.B. constructors must not use JS_THIS_VALUE, as no 'this' object has been + * created. + */ +#define JS_THIS_VALUE(cx,vp) ((vp)[1]) + +extern JS_PUBLIC_API(void *) +JS_malloc(JSContext *cx, size_t nbytes); + +extern JS_PUBLIC_API(void *) +JS_realloc(JSContext *cx, void *p, size_t nbytes); + +extern JS_PUBLIC_API(void) +JS_free(JSContext *cx, void *p); + +extern JS_PUBLIC_API(void) +JS_updateMallocCounter(JSContext *cx, size_t nbytes); + +extern JS_PUBLIC_API(char *) +JS_strdup(JSContext *cx, const char *s); + +extern JS_PUBLIC_API(JSBool) +JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval); + +/* + * A GC root is a pointer to a jsval, JSObject * or JSString * that itself + * points into the GC heap. JS_AddValueRoot takes a pointer to a jsval and + * JS_AddGCThingRoot takes a pointer to a JSObject * or JString *. + * + * Note that, since JS_Add*Root stores the address of a variable (of type + * jsval, JSString *, or JSObject *), that variable must live until + * JS_Remove*Root is called to remove that variable. For example, after: + * + * void some_function() { + * jsval v; + * JS_AddNamedRootedValue(cx, &v, "name"); + * + * the caller must perform + * + * JS_RemoveRootedValue(cx, &v); + * + * before some_function() returns. + * + * Also, use JS_AddNamed*Root(cx, &structPtr->memberObj, "structPtr->memberObj") + * in preference to JS_Add*Root(cx, &structPtr->memberObj), in order to identify + * roots by their source callsites. This way, you can find the callsite while + * debugging if you should fail to do JS_Remove*Root(cx, &structPtr->memberObj) + * before freeing structPtr's memory. + */ +extern JS_PUBLIC_API(JSBool) +JS_AddValueRoot(JSContext *cx, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_AddStringRoot(JSContext *cx, JSString **rp); + +extern JS_PUBLIC_API(JSBool) +JS_AddObjectRoot(JSContext *cx, JSObject **rp); + +extern JS_PUBLIC_API(JSBool) +JS_AddGCThingRoot(JSContext *cx, void **rp); + +#ifdef NAME_ALL_GC_ROOTS +#define JS_DEFINE_TO_TOKEN(def) #def +#define JS_DEFINE_TO_STRING(def) JS_DEFINE_TO_TOKEN(def) +#define JS_AddValueRoot(cx,vp) JS_AddNamedValueRoot((cx), (vp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__)) +#define JS_AddStringRoot(cx,rp) JS_AddNamedStringRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__)) +#define JS_AddObjectRoot(cx,rp) JS_AddNamedObjectRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__)) +#define JS_AddGCThingRoot(cx,rp) JS_AddNamedGCThingRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__)) +#endif + +extern JS_PUBLIC_API(JSBool) +JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name); + +extern JS_PUBLIC_API(JSBool) +JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name); + +extern JS_PUBLIC_API(JSBool) +JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name); + +extern JS_PUBLIC_API(JSBool) +JS_AddNamedGCThingRoot(JSContext *cx, void **rp, const char *name); + +extern JS_PUBLIC_API(JSBool) +JS_RemoveValueRoot(JSContext *cx, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_RemoveStringRoot(JSContext *cx, JSString **rp); + +extern JS_PUBLIC_API(JSBool) +JS_RemoveObjectRoot(JSContext *cx, JSObject **rp); + +extern JS_PUBLIC_API(JSBool) +JS_RemoveGCThingRoot(JSContext *cx, void **rp); + +/* TODO: remove these APIs */ + +extern JS_FRIEND_API(JSBool) +js_AddRootRT(JSRuntime *rt, jsval *vp, const char *name); + +extern JS_FRIEND_API(JSBool) +js_AddGCThingRootRT(JSRuntime *rt, void **rp, const char *name); + +extern JS_FRIEND_API(JSBool) +js_RemoveRoot(JSRuntime *rt, void *rp); + +#ifdef __cplusplus +JS_END_EXTERN_C + +namespace JS { + +/* + * Protecting non-jsval, non-JSObject *, non-JSString * values from collection + * + * Most of the time, the garbage collector's conservative stack scanner works + * behind the scenes, finding all live values and protecting them from being + * collected. However, when JSAPI client code obtains a pointer to data the + * scanner does not know about, owned by an object the scanner does know about, + * Care Must Be Taken. + * + * The scanner recognizes only a select set of types: pointers to JSObjects and + * similar things (JSFunctions, and so on), pointers to JSStrings, and jsvals. + * So while the scanner finds all live |JSString| pointers, it does not notice + * |jschar| pointers. + * + * So suppose we have: + * + * void f(JSString *str) { + * const jschar *ch = JS_GetStringCharsZ(str); + * ... do stuff with ch, but no uses of str ...; + * } + * + * After the call to |JS_GetStringCharsZ|, there are no further uses of + * |str|, which means that the compiler is within its rights to not store + * it anywhere. But because the stack scanner will not notice |ch|, there + * is no longer any live value in this frame that would keep the string + * alive. If |str| is the last reference to that |JSString|, and the + * collector runs while we are using |ch|, the string's array of |jschar|s + * may be freed out from under us. + * + * Note that there is only an issue when 1) we extract a thing X the scanner + * doesn't recognize from 2) a thing Y the scanner does recognize, and 3) if Y + * gets garbage-collected, then X gets freed. If we have code like this: + * + * void g(JSObject *obj) { + * jsval x; + * JS_GetProperty(obj, "x", &x); + * ... do stuff with x ... + * } + * + * there's no problem, because the value we've extracted, x, is a jsval, a + * type that the conservative scanner recognizes. + * + * Conservative GC frees us from the obligation to explicitly root the types it + * knows about, but when we work with derived values like |ch|, we must root + * their owners, as the derived value alone won't keep them alive. + * + * A JS::Anchor is a kind of GC root that allows us to keep the owners of + * derived values like |ch| alive throughout the Anchor's lifetime. We could + * fix the above code as follows: + * + * void f(JSString *str) { + * JS::Anchor a_str(str); + * const jschar *ch = JS_GetStringCharsZ(str); + * ... do stuff with ch, but no uses of str ...; + * } + * + * This simply ensures that |str| will be live until |a_str| goes out of scope. + * As long as we don't retain a pointer to the string's characters for longer + * than that, we have avoided all garbage collection hazards. + */ +template class AnchorPermitted; +template<> class AnchorPermitted { }; +template<> class AnchorPermitted { }; +template<> class AnchorPermitted { }; +template<> class AnchorPermitted { }; +template<> class AnchorPermitted { }; +template<> class AnchorPermitted { }; +template<> class AnchorPermitted { }; + +template +class Anchor: AnchorPermitted { + public: + Anchor() { } + explicit Anchor(T t) { hold = t; } + inline ~Anchor(); + T &get() { return hold; } + void set(const T &t) { hold = t; } + void clear() { hold = 0; } + private: + T hold; + /* Anchors should not be assigned or passed to functions. */ + Anchor(const Anchor &); + const Anchor &operator=(const Anchor &); +}; + +#ifdef __GNUC__ +template +inline Anchor::~Anchor() { + /* + * No code is generated for this. But because this is marked 'volatile', G++ will + * assume it has important side-effects, and won't delete it. (G++ never looks at + * the actual text and notices it's empty.) And because we have passed |hold| to + * it, GCC will keep |hold| alive until this point. + * + * The "memory" clobber operand ensures that G++ will not move prior memory + * accesses after the asm --- it's a barrier. Unfortunately, it also means that + * G++ will assume that all memory has changed after the asm, as it would for a + * call to an unknown function. I don't know of a way to avoid that consequence. + */ + asm volatile("":: "g" (hold) : "memory"); +} +#else +template +inline Anchor::~Anchor() { + /* + * An adequate portable substitute, for non-structure types. + * + * The compiler promises that, by the end of an expression statement, the + * last-stored value to a volatile object is the same as it would be in an + * unoptimized, direct implementation (the "abstract machine" whose behavior the + * language spec describes). However, the compiler is still free to reorder + * non-volatile accesses across this store --- which is what we must prevent. So + * assigning the held value to a volatile variable, as we do here, is not enough. + * + * In our case, however, garbage collection only occurs at function calls, so it + * is sufficient to ensure that the destructor's store isn't moved earlier across + * any function calls that could collect. It is hard to imagine the compiler + * analyzing the program so thoroughly that it could prove that such motion was + * safe. In practice, compilers treat calls to the collector as opaque operations + * --- in particular, as operations which could access volatile variables, across + * which this destructor must not be moved. + * + * ("Objection, your honor! *Alleged* killer whale!") + * + * The disadvantage of this approach is that it does generate code for the store. + * We do need to use Anchors in some cases where cycles are tight. + */ + volatile T sink; + sink = hold; +} + +#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES +/* + * The default assignment operator for |struct C| has the signature: + * + * C& C::operator=(const C&) + * + * And in particular requires implicit conversion of |this| to type |C| for the return + * value. But |volatile C| cannot thus be converted to |C|, so just doing |sink = hold| as + * in the non-specialized version would fail to compile. Do the assignment on asBits + * instead, since I don't think we want to give jsval_layout an assignment operator + * returning |volatile jsval_layout|. + */ +template<> +inline Anchor::~Anchor() { + volatile jsval sink; + sink.asBits = hold.asBits; +} +#endif +#endif + +} /* namespace JS */ + +JS_BEGIN_EXTERN_C +#endif + +/* + * C-compatible version of the Anchor class. It should be called after the last + * use of the variable it protects. + */ +extern JS_NEVER_INLINE JS_PUBLIC_API(void) +JS_AnchorPtr(void *p); + +/* + * This symbol may be used by embedders to detect the change from the old + * JS_AddRoot(JSContext *, void *) APIs to the new ones above. + */ +#define JS_TYPED_ROOTING_API + +/* Obsolete rooting APIs. */ +#define JS_ClearNewbornRoots(cx) ((void) 0) +#define JS_EnterLocalRootScope(cx) (JS_TRUE) +#define JS_LeaveLocalRootScope(cx) ((void) 0) +#define JS_LeaveLocalRootScopeWithResult(cx, rval) ((void) 0) +#define JS_ForgetLocalRoot(cx, thing) ((void) 0) + +typedef enum JSGCRootType { + JS_GC_ROOT_VALUE_PTR, + JS_GC_ROOT_GCTHING_PTR +} JSGCRootType; + +#ifdef DEBUG +extern JS_PUBLIC_API(void) +JS_DumpNamedRoots(JSRuntime *rt, + void (*dump)(const char *name, void *rp, JSGCRootType type, void *data), + void *data); +#endif + +/* + * Call JS_MapGCRoots to map the GC's roots table using map(rp, name, data). + * The root is pointed at by rp; if the root is unnamed, name is null; data is + * supplied from the third parameter to JS_MapGCRoots. + * + * The map function should return JS_MAP_GCROOT_REMOVE to cause the currently + * enumerated root to be removed. To stop enumeration, set JS_MAP_GCROOT_STOP + * in the return value. To keep on mapping, return JS_MAP_GCROOT_NEXT. These + * constants are flags; you can OR them together. + * + * This function acquires and releases rt's GC lock around the mapping of the + * roots table, so the map function should run to completion in as few cycles + * as possible. Of course, map cannot call JS_GC, JS_MaybeGC, JS_BeginRequest, + * or any JS API entry point that acquires locks, without double-tripping or + * deadlocking on the GC lock. + * + * The JSGCRootType parameter indicates whether rp is a pointer to a Value + * (which is obtained by '(Value *)rp') or a pointer to a GC-thing pointer + * (which is obtained by '(void **)rp'). + * + * JS_MapGCRoots returns the count of roots that were successfully mapped. + */ +#define JS_MAP_GCROOT_NEXT 0 /* continue mapping entries */ +#define JS_MAP_GCROOT_STOP 1 /* stop mapping entries */ +#define JS_MAP_GCROOT_REMOVE 2 /* remove and free the current entry */ + +typedef intN +(* JSGCRootMapFun)(void *rp, JSGCRootType type, const char *name, void *data); + +extern JS_PUBLIC_API(uint32) +JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data); + +extern JS_PUBLIC_API(JSBool) +JS_LockGCThing(JSContext *cx, void *thing); + +extern JS_PUBLIC_API(JSBool) +JS_LockGCThingRT(JSRuntime *rt, void *thing); + +extern JS_PUBLIC_API(JSBool) +JS_UnlockGCThing(JSContext *cx, void *thing); + +extern JS_PUBLIC_API(JSBool) +JS_UnlockGCThingRT(JSRuntime *rt, void *thing); + +/* + * Register externally maintained GC roots. + * + * traceOp: the trace operation. For each root the implementation should call + * JS_CallTracer whenever the root contains a traceable thing. + * data: the data argument to pass to each invocation of traceOp. + */ +extern JS_PUBLIC_API(void) +JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data); + +/* + * For implementors of JSMarkOp. All new code should implement JSTraceOp + * instead. + */ +extern JS_PUBLIC_API(void) +JS_MarkGCThing(JSContext *cx, jsval v, const char *name, void *arg); + +/* + * JS_CallTracer API and related macros for implementors of JSTraceOp, to + * enumerate all references to traceable things reachable via a property or + * other strong ref identified for debugging purposes by name or index or + * a naming callback. + * + * By definition references to traceable things include non-null pointers + * to JSObject, JSString and jsdouble and corresponding jsvals. + * + * See the JSTraceOp typedef in jspubtd.h. + */ + +/* Trace kinds to pass to JS_Tracing. */ +#define JSTRACE_OBJECT 0 +#define JSTRACE_STRING 1 + +/* + * Use the following macros to check if a particular jsval is a traceable + * thing and to extract the thing and its kind to pass to JS_CallTracer. + */ +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_TRACEABLE(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_TRACEABLE_IMPL(l); +} + +static JS_ALWAYS_INLINE void * +JSVAL_TO_TRACEABLE(jsval v) +{ + return JSVAL_TO_GCTHING(v); +} + +static JS_ALWAYS_INLINE uint32 +JSVAL_TRACE_KIND(jsval v) +{ + jsval_layout l; + JS_ASSERT(JSVAL_IS_GCTHING(v)); + l.asBits = JSVAL_BITS(v); + return JSVAL_TRACE_KIND_IMPL(l); +} + +struct JSTracer { + JSContext *context; + JSTraceCallback callback; + JSTraceNamePrinter debugPrinter; + const void *debugPrintArg; + size_t debugPrintIndex; +}; + +/* + * The method to call on each reference to a traceable thing stored in a + * particular JSObject or other runtime structure. With DEBUG defined the + * caller before calling JS_CallTracer must initialize JSTracer fields + * describing the reference using the macros below. + */ +extern JS_PUBLIC_API(void) +JS_CallTracer(JSTracer *trc, void *thing, uint32 kind); + +/* + * Set debugging information about a reference to a traceable thing to prepare + * for the following call to JS_CallTracer. + * + * When printer is null, arg must be const char * or char * C string naming + * the reference and index must be either (size_t)-1 indicating that the name + * alone describes the reference or it must be an index into some array vector + * that stores the reference. + * + * When printer callback is not null, the arg and index arguments are + * available to the callback as debugPrinterArg and debugPrintIndex fields + * of JSTracer. + * + * The storage for name or callback's arguments needs to live only until + * the following call to JS_CallTracer returns. + */ +#ifdef DEBUG +# define JS_SET_TRACING_DETAILS(trc, printer, arg, index) \ + JS_BEGIN_MACRO \ + (trc)->debugPrinter = (printer); \ + (trc)->debugPrintArg = (arg); \ + (trc)->debugPrintIndex = (index); \ + JS_END_MACRO +#else +# define JS_SET_TRACING_DETAILS(trc, printer, arg, index) \ + JS_BEGIN_MACRO \ + JS_END_MACRO +#endif + +/* + * Convenience macro to describe the argument of JS_CallTracer using C string + * and index. + */ +# define JS_SET_TRACING_INDEX(trc, name, index) \ + JS_SET_TRACING_DETAILS(trc, NULL, name, index) + +/* + * Convenience macro to describe the argument of JS_CallTracer using C string. + */ +# define JS_SET_TRACING_NAME(trc, name) \ + JS_SET_TRACING_DETAILS(trc, NULL, name, (size_t)-1) + +/* + * Convenience macro to invoke JS_CallTracer using C string as the name for + * the reference to a traceable thing. + */ +# define JS_CALL_TRACER(trc, thing, kind, name) \ + JS_BEGIN_MACRO \ + JS_SET_TRACING_NAME(trc, name); \ + JS_CallTracer((trc), (thing), (kind)); \ + JS_END_MACRO + +/* + * Convenience macros to invoke JS_CallTracer when jsval represents a + * reference to a traceable thing. + */ +#define JS_CALL_VALUE_TRACER(trc, val, name) \ + JS_BEGIN_MACRO \ + if (JSVAL_IS_TRACEABLE(val)) { \ + JS_CALL_TRACER((trc), JSVAL_TO_GCTHING(val), \ + JSVAL_TRACE_KIND(val), name); \ + } \ + JS_END_MACRO + +#define JS_CALL_OBJECT_TRACER(trc, object, name) \ + JS_BEGIN_MACRO \ + JSObject *obj_ = (object); \ + JS_ASSERT(obj_); \ + JS_CALL_TRACER((trc), obj_, JSTRACE_OBJECT, name); \ + JS_END_MACRO + +#define JS_CALL_STRING_TRACER(trc, string, name) \ + JS_BEGIN_MACRO \ + JSString *str_ = (string); \ + JS_ASSERT(str_); \ + JS_CALL_TRACER((trc), str_, JSTRACE_STRING, name); \ + JS_END_MACRO + +/* + * API for JSTraceCallback implementations. + */ +# define JS_TRACER_INIT(trc, cx_, callback_) \ + JS_BEGIN_MACRO \ + (trc)->context = (cx_); \ + (trc)->callback = (callback_); \ + (trc)->debugPrinter = NULL; \ + (trc)->debugPrintArg = NULL; \ + (trc)->debugPrintIndex = (size_t)-1; \ + JS_END_MACRO + +extern JS_PUBLIC_API(void) +JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind); + +extern JS_PUBLIC_API(void) +JS_TraceRuntime(JSTracer *trc); + +#ifdef DEBUG + +extern JS_PUBLIC_API(void) +JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, + void *thing, uint32 kind, JSBool includeDetails); + +/* + * DEBUG-only method to dump the object graph of heap-allocated things. + * + * fp: file for the dump output. + * start: when non-null, dump only things reachable from start + * thing. Otherwise dump all things reachable from the + * runtime roots. + * startKind: trace kind of start if start is not null. Must be 0 when + * start is null. + * thingToFind: dump only paths in the object graph leading to thingToFind + * when non-null. + * maxDepth: the upper bound on the number of edges to descend from the + * graph roots. + * thingToIgnore: thing to ignore during the graph traversal when non-null. + */ +extern JS_PUBLIC_API(JSBool) +JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind, + void *thingToFind, size_t maxDepth, void *thingToIgnore); + +#endif + +/* + * Garbage collector API. + */ +extern JS_PUBLIC_API(void) +JS_GC(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_MaybeGC(JSContext *cx); + +extern JS_PUBLIC_API(JSGCCallback) +JS_SetGCCallback(JSContext *cx, JSGCCallback cb); + +extern JS_PUBLIC_API(JSGCCallback) +JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb); + +extern JS_PUBLIC_API(JSBool) +JS_IsGCMarkingTracer(JSTracer *trc); + +extern JS_PUBLIC_API(JSBool) +JS_IsAboutToBeFinalized(JSContext *cx, void *thing); + +typedef enum JSGCParamKey { + /* Maximum nominal heap before last ditch GC. */ + JSGC_MAX_BYTES = 0, + + /* Number of JS_malloc bytes before last ditch GC. */ + JSGC_MAX_MALLOC_BYTES = 1, + + /* Hoard stackPools for this long, in ms, default is 30 seconds. */ + JSGC_STACKPOOL_LIFESPAN = 2, + + /* + * The factor that defines when the GC is invoked. The factor is a + * percent of the memory allocated by the GC after the last run of + * the GC. When the current memory allocated by the GC is more than + * this percent then the GC is invoked. The factor cannot be less + * than 100 since the current memory allocated by the GC cannot be less + * than the memory allocated after the last run of the GC. + */ + JSGC_TRIGGER_FACTOR = 3, + + /* Amount of bytes allocated by the GC. */ + JSGC_BYTES = 4, + + /* Number of times when GC was invoked. */ + JSGC_NUMBER = 5, + + /* Max size of the code cache in bytes. */ + JSGC_MAX_CODE_CACHE_BYTES = 6, + + /* Select GC mode. */ + JSGC_MODE = 7, + + /* Number of GC chunks waiting to expire. */ + JSGC_UNUSED_CHUNKS = 8 +} JSGCParamKey; + +typedef enum JSGCMode { + /* Perform only global GCs. */ + JSGC_MODE_GLOBAL = 0, + + /* Perform per-compartment GCs until too much garbage has accumulated. */ + JSGC_MODE_COMPARTMENT = 1 +} JSGCMode; + +extern JS_PUBLIC_API(void) +JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value); + +extern JS_PUBLIC_API(uint32) +JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key); + +extern JS_PUBLIC_API(void) +JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32 value); + +extern JS_PUBLIC_API(uint32) +JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key); + +/* + * Flush the code cache for the current thread. The operation might be + * delayed if the cache cannot be flushed currently because native + * code is currently executing. + */ + +extern JS_PUBLIC_API(void) +JS_FlushCaches(JSContext *cx); + +/* + * Add a finalizer for external strings created by JS_NewExternalString (see + * below) using a type-code returned from this function, and that understands + * how to free or release the memory pointed at by JS_GetStringChars(str). + * + * Return a nonnegative type index if there is room for finalizer in the + * global GC finalizers table, else return -1. If the engine is compiled + * JS_THREADSAFE and used in a multi-threaded environment, this function must + * be invoked on the primordial thread only, at startup -- or else the entire + * program must single-thread itself while loading a module that calls this + * function. + */ +extern JS_PUBLIC_API(intN) +JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer); + +/* + * Remove finalizer from the global GC finalizers table, returning its type + * code if found, -1 if not found. + * + * As with JS_AddExternalStringFinalizer, there is a threading restriction + * if you compile the engine JS_THREADSAFE: this function may be called for a + * given finalizer pointer on only one thread; different threads may call to + * remove distinct finalizers safely. + * + * You must ensure that all strings with finalizer's type have been collected + * before calling this function. Otherwise, string data will be leaked by the + * GC, for want of a finalizer to call. + */ +extern JS_PUBLIC_API(intN) +JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer); + +/* + * Create a new JSString whose chars member refers to external memory, i.e., + * memory requiring spe, type-specific finalization. The type code must + * be a nonnegative return value from JS_AddExternalStringFinalizer. + */ +extern JS_PUBLIC_API(JSString *) +JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type); + +/* + * Returns the external-string finalizer index for this string, or -1 if it is + * an "internal" (native to JS engine) string. + */ +extern JS_PUBLIC_API(intN) +JS_GetExternalStringGCType(JSRuntime *rt, JSString *str); + +/* + * Deprecated. Use JS_SetNativeStackQuoata instead. + */ +extern JS_PUBLIC_API(void) +JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr); + +/* + * Set the size of the native stack that should not be exceed. To disable + * stack size checking pass 0. + */ +extern JS_PUBLIC_API(void) +JS_SetNativeStackQuota(JSContext *cx, size_t stackSize); + + +/* + * Set the quota on the number of bytes that stack-like data structures can + * use when the runtime compiles and executes scripts. These structures + * consume heap space, so JS_SetThreadStackLimit does not bound their size. + * The default quota is 128MB which is very generous. + * + * The function must be called before any script compilation or execution API + * calls, i.e. either immediately after JS_NewContext or from JSCONTEXT_NEW + * context callback. + */ +extern JS_PUBLIC_API(void) +JS_SetScriptStackQuota(JSContext *cx, size_t quota); + +#define JS_DEFAULT_SCRIPT_STACK_QUOTA ((size_t) 0x8000000) + +/************************************************************************/ + +/* + * Classes, objects, and properties. + */ +typedef void (*JSClassInternal)(); + +/* For detailed comments on the function pointer types, see jspubtd.h. */ +struct JSClass { + const char *name; + uint32 flags; + + /* Mandatory non-null function pointer members. */ + JSPropertyOp addProperty; + JSPropertyOp delProperty; + JSPropertyOp getProperty; + JSStrictPropertyOp setProperty; + JSEnumerateOp enumerate; + JSResolveOp resolve; + JSConvertOp convert; + JSFinalizeOp finalize; + + /* Optionally non-null members start here. */ + JSClassInternal reserved0; + JSCheckAccessOp checkAccess; + JSNative call; + JSNative construct; + JSXDRObjectOp xdrObject; + JSHasInstanceOp hasInstance; + JSMarkOp mark; + + JSClassInternal reserved1; + void *reserved[19]; +}; + +#define JSCLASS_HAS_PRIVATE (1<<0) /* objects have private slot */ +#define JSCLASS_NEW_ENUMERATE (1<<1) /* has JSNewEnumerateOp hook */ +#define JSCLASS_NEW_RESOLVE (1<<2) /* has JSNewResolveOp hook */ +#define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) /* private is (nsISupports *) */ +#define JSCLASS_NEW_RESOLVE_GETS_START (1<<5) /* JSNewResolveOp gets starting + object in prototype chain + passed in via *objp in/out + parameter */ +#define JSCLASS_CONSTRUCT_PROTOTYPE (1<<6) /* call constructor on class + prototype */ +#define JSCLASS_DOCUMENT_OBSERVER (1<<7) /* DOM document observer */ + +/* + * To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or + * JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where + * n is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1. + */ +#define JSCLASS_RESERVED_SLOTS_SHIFT 8 /* room for 8 flags below */ +#define JSCLASS_RESERVED_SLOTS_WIDTH 8 /* and 16 above this field */ +#define JSCLASS_RESERVED_SLOTS_MASK JS_BITMASK(JSCLASS_RESERVED_SLOTS_WIDTH) +#define JSCLASS_HAS_RESERVED_SLOTS(n) (((n) & JSCLASS_RESERVED_SLOTS_MASK) \ + << JSCLASS_RESERVED_SLOTS_SHIFT) +#define JSCLASS_RESERVED_SLOTS(clasp) (((clasp)->flags \ + >> JSCLASS_RESERVED_SLOTS_SHIFT) \ + & JSCLASS_RESERVED_SLOTS_MASK) + +#define JSCLASS_HIGH_FLAGS_SHIFT (JSCLASS_RESERVED_SLOTS_SHIFT + \ + JSCLASS_RESERVED_SLOTS_WIDTH) + +#define JSCLASS_INTERNAL_FLAG1 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+0)) +#define JSCLASS_IS_ANONYMOUS (1<<(JSCLASS_HIGH_FLAGS_SHIFT+1)) +#define JSCLASS_IS_GLOBAL (1<<(JSCLASS_HIGH_FLAGS_SHIFT+2)) + +/* Indicates that JSClass.mark is a tracer with JSTraceOp type. */ +#define JSCLASS_MARK_IS_TRACE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+3)) +#define JSCLASS_INTERNAL_FLAG2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+4)) + +/* Indicate whether the proto or ctor should be frozen. */ +#define JSCLASS_FREEZE_PROTO (1<<(JSCLASS_HIGH_FLAGS_SHIFT+5)) +#define JSCLASS_FREEZE_CTOR (1<<(JSCLASS_HIGH_FLAGS_SHIFT+6)) + +/* Additional global reserved slots, beyond those for standard prototypes. */ +#define JSRESERVED_GLOBAL_SLOTS_COUNT 6 +#define JSRESERVED_GLOBAL_THIS (JSProto_LIMIT * 3) +#define JSRESERVED_GLOBAL_THROWTYPEERROR (JSRESERVED_GLOBAL_THIS + 1) +#define JSRESERVED_GLOBAL_REGEXP_STATICS (JSRESERVED_GLOBAL_THROWTYPEERROR + 1) +#define JSRESERVED_GLOBAL_FUNCTION_NS (JSRESERVED_GLOBAL_REGEXP_STATICS + 1) +#define JSRESERVED_GLOBAL_EVAL_ALLOWED (JSRESERVED_GLOBAL_FUNCTION_NS + 1) +#define JSRESERVED_GLOBAL_FLAGS (JSRESERVED_GLOBAL_EVAL_ALLOWED + 1) + +/* Global flags. */ +#define JSGLOBAL_FLAGS_CLEARED 0x1 + +/* + * ECMA-262 requires that most constructors used internally create objects + * with "the original Foo.prototype value" as their [[Prototype]] (__proto__) + * member initial value. The "original ... value" verbiage is there because + * in ECMA-262, global properties naming class objects are read/write and + * deleteable, for the most part. + * + * Implementing this efficiently requires that global objects have classes + * with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was + * prevously allowed, but is now an ES5 violation and thus unsupported. + */ +#define JSCLASS_GLOBAL_FLAGS \ + (JSCLASS_IS_GLOBAL | \ + JSCLASS_HAS_RESERVED_SLOTS(JSRESERVED_GLOBAL_THIS + JSRESERVED_GLOBAL_SLOTS_COUNT)) + +/* Fast access to the original value of each standard class's prototype. */ +#define JSCLASS_CACHED_PROTO_SHIFT (JSCLASS_HIGH_FLAGS_SHIFT + 8) +#define JSCLASS_CACHED_PROTO_WIDTH 8 +#define JSCLASS_CACHED_PROTO_MASK JS_BITMASK(JSCLASS_CACHED_PROTO_WIDTH) +#define JSCLASS_HAS_CACHED_PROTO(key) ((key) << JSCLASS_CACHED_PROTO_SHIFT) +#define JSCLASS_CACHED_PROTO_KEY(clasp) ((JSProtoKey) \ + (((clasp)->flags \ + >> JSCLASS_CACHED_PROTO_SHIFT) \ + & JSCLASS_CACHED_PROTO_MASK)) + +/* Initializer for unused members of statically initialized JSClass structs. */ +#define JSCLASS_NO_INTERNAL_MEMBERS 0,{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} +#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,0,0,JSCLASS_NO_INTERNAL_MEMBERS + +struct JSIdArray { + jsint length; + jsid vector[1]; /* actually, length jsid words */ +}; + +extern JS_PUBLIC_API(void) +JS_DestroyIdArray(JSContext *cx, JSIdArray *ida); + +extern JS_PUBLIC_API(JSBool) +JS_ValueToId(JSContext *cx, jsval v, jsid *idp); + +extern JS_PUBLIC_API(JSBool) +JS_IdToValue(JSContext *cx, jsid id, jsval *vp); + +/* + * JSNewResolveOp flag bits. + */ +#define JSRESOLVE_QUALIFIED 0x01 /* resolve a qualified property id */ +#define JSRESOLVE_ASSIGNING 0x02 /* resolve on the left of assignment */ +#define JSRESOLVE_DETECTING 0x04 /* 'if (o.p)...' or '(o.p) ?...:...' */ +#define JSRESOLVE_DECLARING 0x08 /* var, const, or function prolog op */ +#define JSRESOLVE_CLASSNAME 0x10 /* class name used when constructing */ +#define JSRESOLVE_WITH 0x20 /* resolve inside a with statement */ + +extern JS_PUBLIC_API(JSBool) +JS_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_StrictPropertyStub(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_EnumerateStub(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_ResolveStub(JSContext *cx, JSObject *obj, jsid id); + +extern JS_PUBLIC_API(JSBool) +JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp); + +extern JS_PUBLIC_API(void) +JS_FinalizeStub(JSContext *cx, JSObject *obj); + +struct JSConstDoubleSpec { + jsdouble dval; + const char *name; + uint8 flags; + uint8 spare[3]; +}; + +/* + * To define an array element rather than a named property member, cast the + * element's index to (const char *) and initialize name with it, and set the + * JSPROP_INDEX bit in flags. + */ +struct JSPropertySpec { + const char *name; + int8 tinyid; + uint8 flags; + JSPropertyOp getter; + JSStrictPropertyOp setter; +}; + +struct JSFunctionSpec { + const char *name; + JSNative call; + uint16 nargs; + uint16 flags; +}; + +/* + * Terminating sentinel initializer to put at the end of a JSFunctionSpec array + * that's passed to JS_DefineFunctions or JS_InitClass. + */ +#define JS_FS_END JS_FS(NULL,NULL,0,0) + +/* + * Initializer macros for a JSFunctionSpec array element. JS_FN (whose name + * pays homage to the old JSNative/JSFastNative split) simply adds the flag + * JSFUN_STUB_GSOPS. + */ +#define JS_FS(name,call,nargs,flags) \ + {name, call, nargs, flags} +#define JS_FN(name,call,nargs,flags) \ + {name, call, nargs, (flags) | JSFUN_STUB_GSOPS} + +extern JS_PUBLIC_API(JSObject *) +JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, + JSClass *clasp, JSNative constructor, uintN nargs, + JSPropertySpec *ps, JSFunctionSpec *fs, + JSPropertySpec *static_ps, JSFunctionSpec *static_fs); + +#ifdef JS_THREADSAFE +extern JS_PUBLIC_API(JSClass *) +JS_GetClass(JSContext *cx, JSObject *obj); + +#define JS_GET_CLASS(cx,obj) JS_GetClass(cx, obj) +#else +extern JS_PUBLIC_API(JSClass *) +JS_GetClass(JSObject *obj); + +#define JS_GET_CLASS(cx,obj) JS_GetClass(obj) +#endif + +extern JS_PUBLIC_API(JSBool) +JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv); + +extern JS_PUBLIC_API(JSBool) +JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); + +extern JS_PUBLIC_API(void *) +JS_GetPrivate(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_SetPrivate(JSContext *cx, JSObject *obj, void *data); + +extern JS_PUBLIC_API(void *) +JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, + jsval *argv); + +extern JS_PUBLIC_API(JSObject *) +JS_GetPrototype(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto); + +extern JS_PUBLIC_API(JSObject *) +JS_GetParent(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent); + +extern JS_PUBLIC_API(JSObject *) +JS_GetConstructor(JSContext *cx, JSObject *proto); + +/* + * Get a unique identifier for obj, good for the lifetime of obj (even if it + * is moved by a copying GC). Return false on failure (likely out of memory), + * and true with *idp containing the unique id on success. + */ +extern JS_PUBLIC_API(JSBool) +JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp); + +extern JS_PUBLIC_API(JSObject *) +JS_NewGlobalObject(JSContext *cx, JSClass *clasp); + +extern JS_PUBLIC_API(JSObject *) +JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals); + +extern JS_PUBLIC_API(JSObject *) +JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent); + +/* Queries the [[Extensible]] property of the object. */ +extern JS_PUBLIC_API(JSBool) +JS_IsExtensible(JSObject *obj); + +/* + * Unlike JS_NewObject, JS_NewObjectWithGivenProto does not compute a default + * proto if proto's actual parameter value is null. + */ +extern JS_PUBLIC_API(JSObject *) +JS_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent); + +/* + * Freeze obj, and all objects it refers to, recursively. This will not recurse + * through non-extensible objects, on the assumption that those are already + * deep-frozen. + */ +extern JS_PUBLIC_API(JSBool) +JS_DeepFreezeObject(JSContext *cx, JSObject *obj); + +/* + * Freezes an object; see ES5's Object.freeze(obj) method. + */ +extern JS_PUBLIC_API(JSBool) +JS_FreezeObject(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSObject *) +JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent); + +extern JS_PUBLIC_API(JSObject *) +JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto, + JSObject *parent, uintN argc, jsval *argv); + +extern JS_PUBLIC_API(JSObject *) +JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv); + +extern JS_PUBLIC_API(JSObject *) +JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp, + JSObject *proto, uintN attrs); + +extern JS_PUBLIC_API(JSBool) +JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds); + +extern JS_PUBLIC_API(JSBool) +JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps); + +extern JS_PUBLIC_API(JSBool) +JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value, + JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs); + +extern JS_PUBLIC_API(JSBool) +JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value, + JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs); + +extern JS_PUBLIC_API(JSBool) +JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp); + +/* + * Determine the attributes (JSPROP_* flags) of a property on a given object. + * + * If the object does not have a property by that name, *foundp will be + * JS_FALSE and the value of *attrsp is undefined. + */ +extern JS_PUBLIC_API(JSBool) +JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name, + uintN *attrsp, JSBool *foundp); + +/* + * The same, but if the property is native, return its getter and setter via + * *getterp and *setterp, respectively (and only if the out parameter pointer + * is not null). + */ +extern JS_PUBLIC_API(JSBool) +JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, + const char *name, + uintN *attrsp, JSBool *foundp, + JSPropertyOp *getterp, + JSStrictPropertyOp *setterp); + +extern JS_PUBLIC_API(JSBool) +JS_GetPropertyAttrsGetterAndSetterById(JSContext *cx, JSObject *obj, + jsid id, + uintN *attrsp, JSBool *foundp, + JSPropertyOp *getterp, + JSStrictPropertyOp *setterp); + +/* + * Set the attributes of a property on a given object. + * + * If the object does not have a property by that name, *foundp will be + * JS_FALSE and nothing will be altered. + */ +extern JS_PUBLIC_API(JSBool) +JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name, + uintN attrs, JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, + int8 tinyid, jsval value, + JSPropertyOp getter, JSStrictPropertyOp setter, + uintN attrs); + +extern JS_PUBLIC_API(JSBool) +JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, + const char *alias); + +extern JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name, + JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj, jsid id, + JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_HasPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, + uintN flags, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, + uintN flags, JSObject **objp, jsval *vp); + +struct JSPropertyDescriptor { + JSObject *obj; + uintN attrs; + JSPropertyOp getter; + JSStrictPropertyOp setter; + jsval value; + uintN shortid; +}; + +/* + * Like JS_GetPropertyAttrsGetterAndSetterById but will return a property on + * an object on the prototype chain (returned in objp). If data->obj is null, + * then this property was not found on the prototype chain. + */ +extern JS_PUBLIC_API(JSBool) +JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSPropertyDescriptor *desc); + +extern JS_PUBLIC_API(JSBool) +JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_GetPropertyDefault(JSContext *cx, JSObject *obj, const char *name, jsval def, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_GetPropertyByIdDefault(JSContext *cx, JSObject *obj, jsid id, jsval def, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, + jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name); + +extern JS_PUBLIC_API(JSBool) +JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name, + jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_DeletePropertyById(JSContext *cx, JSObject *obj, jsid id); + +extern JS_PUBLIC_API(JSBool) +JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_DefineUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, jsval value, + JSPropertyOp getter, JSStrictPropertyOp setter, + uintN attrs); + +/* + * Determine the attributes (JSPROP_* flags) of a property on a given object. + * + * If the object does not have a property by that name, *foundp will be + * JS_FALSE and the value of *attrsp is undefined. + */ +extern JS_PUBLIC_API(JSBool) +JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + uintN *attrsp, JSBool *foundp); + +/* + * The same, but if the property is native, return its getter and setter via + * *getterp and *setterp, respectively (and only if the out parameter pointer + * is not null). + */ +extern JS_PUBLIC_API(JSBool) +JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + uintN *attrsp, JSBool *foundp, + JSPropertyOp *getterp, + JSStrictPropertyOp *setterp); + +/* + * Set the attributes of a property on a given object. + * + * If the object does not have a property by that name, *foundp will be + * JS_FALSE and nothing will be altered. + */ +extern JS_PUBLIC_API(JSBool) +JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + uintN attrs, JSBool *foundp); + + +extern JS_PUBLIC_API(JSBool) +JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + int8 tinyid, jsval value, + JSPropertyOp getter, JSStrictPropertyOp setter, + uintN attrs); + +extern JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, const jschar *name, + size_t namelen, JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_HasUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + JSBool *vp); + +extern JS_PUBLIC_API(JSBool) +JS_LookupUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_GetUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_SetUCProperty(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_DeleteUCProperty2(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, + jsval *rval); + +extern JS_PUBLIC_API(JSObject *) +JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector); + +extern JS_PUBLIC_API(JSBool) +JS_IsArrayObject(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp); + +extern JS_PUBLIC_API(JSBool) +JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length); + +extern JS_PUBLIC_API(JSBool) +JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp); + +extern JS_PUBLIC_API(JSBool) +JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value, + JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs); + +extern JS_PUBLIC_API(JSBool) +JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias); + +extern JS_PUBLIC_API(JSBool) +JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index, + JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp); + +extern JS_PUBLIC_API(JSBool) +JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index); + +extern JS_PUBLIC_API(JSBool) +JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval); + +extern JS_PUBLIC_API(void) +JS_ClearScope(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSIdArray *) +JS_Enumerate(JSContext *cx, JSObject *obj); + +/* + * Create an object to iterate over enumerable properties of obj, in arbitrary + * property definition order. NB: This differs from longstanding for..in loop + * order, which uses order of property definition in obj. + */ +extern JS_PUBLIC_API(JSObject *) +JS_NewPropertyIterator(JSContext *cx, JSObject *obj); + +/* + * Return true on success with *idp containing the id of the next enumerable + * property to visit using iterobj, or JSID_IS_VOID if there is no such property + * left to visit. Return false on error. + */ +extern JS_PUBLIC_API(JSBool) +JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp); + +extern JS_PUBLIC_API(JSBool) +JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, + jsval *vp, uintN *attrsp); + +extern JS_PUBLIC_API(JSBool) +JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v); + +/************************************************************************/ + +/* + * Security protocol. + */ +struct JSPrincipals { + char *codebase; + + /* XXX unspecified and unused by Mozilla code -- can we remove these? */ + void * (* getPrincipalArray)(JSContext *cx, JSPrincipals *); + JSBool (* globalPrivilegesEnabled)(JSContext *cx, JSPrincipals *); + + /* Don't call "destroy"; use reference counting macros below. */ + jsrefcount refcount; + + void (* destroy)(JSContext *cx, JSPrincipals *); + JSBool (* subsume)(JSPrincipals *, JSPrincipals *); +}; + +#ifdef JS_THREADSAFE +#define JSPRINCIPALS_HOLD(cx, principals) JS_HoldPrincipals(cx,principals) +#define JSPRINCIPALS_DROP(cx, principals) JS_DropPrincipals(cx,principals) + +extern JS_PUBLIC_API(jsrefcount) +JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals); + +extern JS_PUBLIC_API(jsrefcount) +JS_DropPrincipals(JSContext *cx, JSPrincipals *principals); + +#else +#define JSPRINCIPALS_HOLD(cx, principals) (++(principals)->refcount) +#define JSPRINCIPALS_DROP(cx, principals) \ + ((--(principals)->refcount == 0) \ + ? ((*(principals)->destroy)((cx), (principals)), 0) \ + : (principals)->refcount) +#endif + + +struct JSSecurityCallbacks { + JSCheckAccessOp checkObjectAccess; + JSPrincipalsTranscoder principalsTranscoder; + JSObjectPrincipalsFinder findObjectPrincipals; + JSCSPEvalChecker contentSecurityPolicyAllows; +}; + +extern JS_PUBLIC_API(JSSecurityCallbacks *) +JS_SetRuntimeSecurityCallbacks(JSRuntime *rt, JSSecurityCallbacks *callbacks); + +extern JS_PUBLIC_API(JSSecurityCallbacks *) +JS_GetRuntimeSecurityCallbacks(JSRuntime *rt); + +extern JS_PUBLIC_API(JSSecurityCallbacks *) +JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks); + +extern JS_PUBLIC_API(JSSecurityCallbacks *) +JS_GetSecurityCallbacks(JSContext *cx); + +/************************************************************************/ + +/* + * Functions and scripts. + */ +extern JS_PUBLIC_API(JSFunction *) +JS_NewFunction(JSContext *cx, JSNative call, uintN nargs, uintN flags, + JSObject *parent, const char *name); + +/* + * Create the function with the name given by the id. JSID_IS_STRING(id) must + * be true. + */ +extern JS_PUBLIC_API(JSFunction *) +JS_NewFunctionById(JSContext *cx, JSNative call, uintN nargs, uintN flags, + JSObject *parent, jsid id); + +extern JS_PUBLIC_API(JSObject *) +JS_GetFunctionObject(JSFunction *fun); + +/* + * Return the function's identifier as a JSString, or null if fun is unnamed. + * The returned string lives as long as fun, so you don't need to root a saved + * reference to it if fun is well-connected or rooted, and provided you bound + * the use of the saved reference by fun's lifetime. + */ +extern JS_PUBLIC_API(JSString *) +JS_GetFunctionId(JSFunction *fun); + +/* + * Return JSFUN_* flags for fun. + */ +extern JS_PUBLIC_API(uintN) +JS_GetFunctionFlags(JSFunction *fun); + +/* + * Return the arity (length) of fun. + */ +extern JS_PUBLIC_API(uint16) +JS_GetFunctionArity(JSFunction *fun); + +/* + * Infallible predicate to test whether obj is a function object (faster than + * comparing obj's class name to "Function", but equivalent unless someone has + * overwritten the "Function" identifier with a different constructor and then + * created instances using that constructor that might be passed in as obj). + */ +extern JS_PUBLIC_API(JSBool) +JS_ObjectIsFunction(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_ObjectIsCallable(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs); + +extern JS_PUBLIC_API(JSFunction *) +JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call, + uintN nargs, uintN attrs); + +extern JS_PUBLIC_API(JSFunction *) +JS_DefineUCFunction(JSContext *cx, JSObject *obj, + const jschar *name, size_t namelen, JSNative call, + uintN nargs, uintN attrs); + +extern JS_PUBLIC_API(JSFunction *) +JS_DefineFunctionById(JSContext *cx, JSObject *obj, jsid id, JSNative call, + uintN nargs, uintN attrs); + +extern JS_PUBLIC_API(JSObject *) +JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent); + +/* + * Given a buffer, return JS_FALSE if the buffer might become a valid + * javascript statement with the addition of more lines. Otherwise return + * JS_TRUE. The intent is to support interactive compilation - accumulate + * lines in a buffer until JS_BufferIsCompilableUnit is true, then pass it to + * the compiler. + */ +extern JS_PUBLIC_API(JSBool) +JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, + const char *bytes, size_t length); + +extern JS_PUBLIC_API(JSObject *) +JS_CompileScript(JSContext *cx, JSObject *obj, + const char *bytes, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSObject *) +JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const char *bytes, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSObject *) +JS_CompileScriptForPrincipalsVersion(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const char *bytes, size_t length, + const char *filename, uintN lineno, + JSVersion version); + +extern JS_PUBLIC_API(JSObject *) +JS_CompileUCScript(JSContext *cx, JSObject *obj, + const jschar *chars, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSObject *) +JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const jschar *chars, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSObject *) +JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const jschar *chars, size_t length, + const char *filename, uintN lineno, + JSVersion version); + +extern JS_PUBLIC_API(JSObject *) +JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename); + +extern JS_PUBLIC_API(JSObject *) +JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, + FILE *fh); + +extern JS_PUBLIC_API(JSObject *) +JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, + const char *filename, FILE *fh, + JSPrincipals *principals); + +extern JS_PUBLIC_API(JSObject *) +JS_CompileFileHandleForPrincipalsVersion(JSContext *cx, JSObject *obj, + const char *filename, FILE *fh, + JSPrincipals *principals, + JSVersion version); + +extern JS_PUBLIC_API(JSFunction *) +JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name, + uintN nargs, const char **argnames, + const char *bytes, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSFunction *) +JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, const char *name, + uintN nargs, const char **argnames, + const char *bytes, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSFunction *) +JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name, + uintN nargs, const char **argnames, + const jschar *chars, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSFunction *) +JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, const char *name, + uintN nargs, const char **argnames, + const jschar *chars, size_t length, + const char *filename, uintN lineno); + +extern JS_PUBLIC_API(JSFunction *) +JS_CompileUCFunctionForPrincipalsVersion(JSContext *cx, JSObject *obj, + JSPrincipals *principals, const char *name, + uintN nargs, const char **argnames, + const jschar *chars, size_t length, + const char *filename, uintN lineno, + JSVersion version); + +extern JS_PUBLIC_API(JSString *) +JS_DecompileScriptObject(JSContext *cx, JSObject *scriptObj, const char *name, uintN indent); + +/* + * API extension: OR this into indent to avoid pretty-printing the decompiled + * source resulting from JS_DecompileFunction{,Body}. + */ +#define JS_DONT_PRETTY_PRINT ((uintN)0x8000) + +extern JS_PUBLIC_API(JSString *) +JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent); + +extern JS_PUBLIC_API(JSString *) +JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent); + +/* + * NB: JS_ExecuteScript and the JS_Evaluate*Script* quadruplets use the obj + * parameter as the initial scope chain header, the 'this' keyword value, and + * the variables object (ECMA parlance for where 'var' and 'function' bind + * names) of the execution context for script. + * + * Using obj as the variables object is problematic if obj's parent (which is + * the scope chain link; see JS_SetParent and JS_NewObject) is not null: in + * this case, variables created by 'var x = 0', e.g., go in obj, but variables + * created by assignment to an unbound id, 'x = 0', go in the last object on + * the scope chain linked by parent. + * + * ECMA calls that last scoping object the "global object", but note that many + * embeddings have several such objects. ECMA requires that "global code" be + * executed with the variables object equal to this global object. But these + * JS API entry points provide freedom to execute code against a "sub-global", + * i.e., a parented or scoped object, in which case the variables object will + * differ from the last object on the scope chain, resulting in confusing and + * non-ECMA explicit vs. implicit variable creation. + * + * Caveat embedders: unless you already depend on this buggy variables object + * binding behavior, you should call JS_SetOptions(cx, JSOPTION_VAROBJFIX) or + * JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_VAROBJFIX) -- the latter if + * someone may have set other options on cx already -- for each context in the + * application, if you pass parented objects as the obj parameter, or may ever + * pass such objects in the future. + * + * Why a runtime option? The alternative is to add six or so new API entry + * points with signatures matching the following six, and that doesn't seem + * worth the code bloat cost. Such new entry points would probably have less + * obvious names, too, so would not tend to be used. The JS_SetOption call, + * OTOH, can be more easily hacked into existing code that does not depend on + * the bug; such code can continue to use the familiar JS_EvaluateScript, + * etc., entry points. + */ +extern JS_PUBLIC_API(JSBool) +JS_ExecuteScript(JSContext *cx, JSObject *obj, JSObject *scriptObj, jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_ExecuteScriptVersion(JSContext *cx, JSObject *obj, JSObject *scriptObj, jsval *rval, + JSVersion version); + +/* + * Execute either the function-defining prolog of a script, or the script's + * main body, but not both. + */ +typedef enum JSExecPart { JSEXEC_PROLOG, JSEXEC_MAIN } JSExecPart; + +extern JS_PUBLIC_API(JSBool) +JS_EvaluateScript(JSContext *cx, JSObject *obj, + const char *bytes, uintN length, + const char *filename, uintN lineno, + jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const char *bytes, uintN length, + const char *filename, uintN lineno, + jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_EvaluateScriptForPrincipalsVersion(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const char *bytes, uintN length, + const char *filename, uintN lineno, + jsval *rval, JSVersion version); + +extern JS_PUBLIC_API(JSBool) +JS_EvaluateUCScript(JSContext *cx, JSObject *obj, + const jschar *chars, uintN length, + const char *filename, uintN lineno, + jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_EvaluateUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const jschar *chars, uintN length, + const char *filename, uintN lineno, + jsval *rval, JSVersion version); + +extern JS_PUBLIC_API(JSBool) +JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj, + JSPrincipals *principals, + const jschar *chars, uintN length, + const char *filename, uintN lineno, + jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, + jsval *argv, jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, + jsval *argv, jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, + jsval *argv, jsval *rval); + +#ifdef __cplusplus +JS_END_EXTERN_C + +namespace JS { + +static inline bool +Call(JSContext *cx, JSObject *thisObj, JSFunction *fun, uintN argc, jsval *argv, jsval *rval) { + return !!JS_CallFunction(cx, thisObj, fun, argc, argv, rval); +} + +static inline bool +Call(JSContext *cx, JSObject *thisObj, const char *name, uintN argc, jsval *argv, jsval *rval) { + return !!JS_CallFunctionName(cx, thisObj, name, argc, argv, rval); +} + +static inline bool +Call(JSContext *cx, JSObject *thisObj, jsval fun, uintN argc, jsval *argv, jsval *rval) { + return !!JS_CallFunctionValue(cx, thisObj, fun, argc, argv, rval); +} + +extern JS_PUBLIC_API(bool) +Call(JSContext *cx, jsval thisv, jsval fun, uintN argc, jsval *argv, jsval *rval); + +static inline bool +Call(JSContext *cx, jsval thisv, JSObject *funObj, uintN argc, jsval *argv, jsval *rval) { + return Call(cx, thisv, OBJECT_TO_JSVAL(funObj), argc, argv, rval); +} + +} /* namespace js */ + +JS_BEGIN_EXTERN_C +#endif /* __cplusplus */ + +/* + * These functions allow setting an operation callback that will be called + * from the thread the context is associated with some time after any thread + * triggered the callback using JS_TriggerOperationCallback(cx). + * + * In a threadsafe build the engine internally triggers operation callbacks + * under certain circumstances (i.e. GC and title transfer) to force the + * context to yield its current request, which the engine always + * automatically does immediately prior to calling the callback function. + * The embedding should thus not rely on callbacks being triggered through + * the external API only. + * + * Important note: Additional callbacks can occur inside the callback handler + * if it re-enters the JS engine. The embedding must ensure that the callback + * is disconnected before attempting such re-entry. + */ + +extern JS_PUBLIC_API(JSOperationCallback) +JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback); + +extern JS_PUBLIC_API(JSOperationCallback) +JS_GetOperationCallback(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_TriggerOperationCallback(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_TriggerAllOperationCallbacks(JSRuntime *rt); + +extern JS_PUBLIC_API(JSBool) +JS_IsRunning(JSContext *cx); + +/* + * Saving and restoring frame chains. + * + * These two functions are used to set aside cx's call stack while that stack + * is inactive. After a call to JS_SaveFrameChain, it looks as if there is no + * code running on cx. Before calling JS_RestoreFrameChain, cx's call stack + * must be balanced and all nested calls to JS_SaveFrameChain must have had + * matching JS_RestoreFrameChain calls. + * + * JS_SaveFrameChain deals with cx not having any code running on it. A null + * return does not signify an error, and JS_RestoreFrameChain handles a null + * frame pointer argument safely. + */ +extern JS_PUBLIC_API(JSStackFrame *) +JS_SaveFrameChain(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp); + +/************************************************************************/ + +/* + * Strings. + * + * NB: JS_NewUCString takes ownership of bytes on success, avoiding a copy; + * but on error (signified by null return), it leaves chars owned by the + * caller. So the caller must free bytes in the error case, if it has no use + * for them. In contrast, all the JS_New*StringCopy* functions do not take + * ownership of the character memory passed to them -- they copy it. + */ +extern JS_PUBLIC_API(JSString *) +JS_NewStringCopyN(JSContext *cx, const char *s, size_t n); + +extern JS_PUBLIC_API(JSString *) +JS_NewStringCopyZ(JSContext *cx, const char *s); + +extern JS_PUBLIC_API(JSString *) +JS_InternJSString(JSContext *cx, JSString *str); + +extern JS_PUBLIC_API(JSString *) +JS_InternString(JSContext *cx, const char *s); + +extern JS_PUBLIC_API(JSString *) +JS_NewUCString(JSContext *cx, jschar *chars, size_t length); + +extern JS_PUBLIC_API(JSString *) +JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n); + +extern JS_PUBLIC_API(JSString *) +JS_NewUCStringCopyZ(JSContext *cx, const jschar *s); + +extern JS_PUBLIC_API(JSString *) +JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length); + +extern JS_PUBLIC_API(JSString *) +JS_InternUCString(JSContext *cx, const jschar *s); + +extern JS_PUBLIC_API(JSBool) +JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result); + +extern JS_PUBLIC_API(JSBool) +JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match); + +extern JS_PUBLIC_API(size_t) +JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote); + +extern JS_PUBLIC_API(JSBool) +JS_FileEscapedString(FILE *fp, JSString *str, char quote); + +/* + * Extracting string characters and length. + * + * While getting the length of a string is infallible, getting the chars can + * fail. As indicated by the lack of a JSContext parameter, there are two + * special cases where getting the chars is infallible: + * + * The first case is interned strings, i.e., strings from JS_InternString or + * JSID_TO_STRING(id), using JS_GetInternedStringChars*. + * + * The second case is "flat" strings that have been explicitly prepared in a + * fallible context by JS_FlattenString. To catch errors, a separate opaque + * JSFlatString type is returned by JS_FlattenString and expected by + * JS_GetFlatStringChars. Note, though, that this is purely a syntactic + * distinction: the input and output of JS_FlattenString are the same actual + * GC-thing so only one needs to be rooted. If a JSString is known to be flat, + * JS_ASSERT_STRING_IS_FLAT can be used to make a debug-checked cast. Example: + * + * // in a fallible context + * JSFlatString *fstr = JS_FlattenString(cx, str); + * if (!fstr) + * return JS_FALSE; + * JS_ASSERT(fstr == JS_ASSERT_STRING_IS_FLAT(str)); + * + * // in an infallible context, for the same 'str' + * const jschar *chars = JS_GetFlatStringChars(fstr) + * JS_ASSERT(chars); + * + * The CharsZ APIs guarantee that the returned array has a null character at + * chars[length]. This can require additional copying so clients should prefer + * APIs without CharsZ if possible. The infallible functions also return + * null-terminated arrays. (There is no additional cost or non-Z alternative + * for the infallible functions, so 'Z' is left out of the identifier.) + */ + +extern JS_PUBLIC_API(size_t) +JS_GetStringLength(JSString *str); + +extern JS_PUBLIC_API(const jschar *) +JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *length); + +extern JS_PUBLIC_API(const jschar *) +JS_GetInternedStringChars(JSString *str); + +extern JS_PUBLIC_API(const jschar *) +JS_GetInternedStringCharsAndLength(JSString *str, size_t *length); + +extern JS_PUBLIC_API(const jschar *) +JS_GetStringCharsZ(JSContext *cx, JSString *str); + +extern JS_PUBLIC_API(const jschar *) +JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *length); + +extern JS_PUBLIC_API(JSFlatString *) +JS_FlattenString(JSContext *cx, JSString *str); + +extern JS_PUBLIC_API(const jschar *) +JS_GetFlatStringChars(JSFlatString *str); + +static JS_ALWAYS_INLINE JSFlatString * +JSID_TO_FLAT_STRING(jsid id) +{ + JS_ASSERT(JSID_IS_STRING(id)); + return (JSFlatString *)(JSID_BITS(id)); +} + +static JS_ALWAYS_INLINE JSFlatString * +JS_ASSERT_STRING_IS_FLAT(JSString *str) +{ + JS_ASSERT(JS_GetFlatStringChars((JSFlatString *)str)); + return (JSFlatString *)str; +} + +static JS_ALWAYS_INLINE JSString * +JS_FORGET_STRING_FLATNESS(JSFlatString *fstr) +{ + return (JSString *)fstr; +} + +/* + * Additional APIs that avoid fallibility when given a flat string. + */ + +extern JS_PUBLIC_API(JSBool) +JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes); + +extern JS_PUBLIC_API(size_t) +JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote); + +/* + * This function is now obsolete and behaves the same as JS_NewUCString. Use + * JS_NewUCString instead. + */ +extern JS_PUBLIC_API(JSString *) +JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length); + +/* + * Mutable string support. A string's characters are never mutable in this JS + * implementation, but a dependent string is a substring of another dependent + * or immutable string, and a rope is a lazily concatenated string that creates + * its underlying buffer the first time it is accessed. Even after a rope + * creates its underlying buffer, it still considered mutable. The direct data + * members of the (opaque to API clients) JSString struct may be changed in a + * single-threaded way for dependent strings and ropes. + * + * Therefore mutable strings (ropes and dependent strings) cannot be used by + * more than one thread at a time. You may call JS_MakeStringImmutable to + * convert the string from a mutable string to an immutable (and therefore + * thread-safe) string. The engine takes care of converting ropes and dependent + * strings to immutable for you if you store strings in multi-threaded objects + * using JS_SetProperty or kindred API entry points. + * + * If you store a JSString pointer in a native data structure that is (safely) + * accessible to multiple threads, you must call JS_MakeStringImmutable before + * retiring the store. + */ + +/* + * Create a dependent string, i.e., a string that owns no character storage, + * but that refers to a slice of another string's chars. Dependent strings + * are mutable by definition, so the thread safety comments above apply. + */ +extern JS_PUBLIC_API(JSString *) +JS_NewDependentString(JSContext *cx, JSString *str, size_t start, + size_t length); + +/* + * Concatenate two strings, possibly resulting in a rope. + * See above for thread safety comments. + */ +extern JS_PUBLIC_API(JSString *) +JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right); + +/* + * Convert a dependent string into an independent one. This function does not + * change the string's mutability, so the thread safety comments above apply. + */ +extern JS_PUBLIC_API(const jschar *) +JS_UndependString(JSContext *cx, JSString *str); + +/* + * Convert a mutable string (either rope or dependent) into an immutable, + * thread-safe one. + */ +extern JS_PUBLIC_API(JSBool) +JS_MakeStringImmutable(JSContext *cx, JSString *str); + +/* + * Return JS_TRUE if C (char []) strings passed via the API and internally + * are UTF-8. + */ +JS_PUBLIC_API(JSBool) +JS_CStringsAreUTF8(void); + +/* + * Update the value to be returned by JS_CStringsAreUTF8(). Once set, it + * can never be changed. This API must be called before the first call to + * JS_NewRuntime. + */ +JS_PUBLIC_API(void) +JS_SetCStringsAreUTF8(void); + +/* + * Character encoding support. + * + * For both JS_EncodeCharacters and JS_DecodeBytes, set *dstlenp to the size + * of the destination buffer before the call; on return, *dstlenp contains the + * number of bytes (JS_EncodeCharacters) or jschars (JS_DecodeBytes) actually + * stored. To determine the necessary destination buffer size, make a sizing + * call that passes NULL for dst. + * + * On errors, the functions report the error. In that case, *dstlenp contains + * the number of characters or bytes transferred so far. If cx is NULL, no + * error is reported on failure, and the functions simply return JS_FALSE. + * + * NB: Neither function stores an additional zero byte or jschar after the + * transcoded string. + * + * If JS_CStringsAreUTF8() is true then JS_EncodeCharacters encodes to + * UTF-8, and JS_DecodeBytes decodes from UTF-8, which may create additional + * errors if the character sequence is malformed. If UTF-8 support is + * disabled, the functions deflate and inflate, respectively. + */ +JS_PUBLIC_API(JSBool) +JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, + size_t *dstlenp); + +JS_PUBLIC_API(JSBool) +JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, + size_t *dstlenp); + +/* + * A variation on JS_EncodeCharacters where a null terminated string is + * returned that you are expected to call JS_free on when done. + */ +JS_PUBLIC_API(char *) +JS_EncodeString(JSContext *cx, JSString *str); + +/* + * Get number of bytes in the string encoding (without accounting for a + * terminating zero bytes. The function returns (size_t) -1 if the string + * can not be encoded into bytes and reports an error using cx accordingly. + */ +JS_PUBLIC_API(size_t) +JS_GetStringEncodingLength(JSContext *cx, JSString *str); + +/* + * Encode string into a buffer. The function does not stores an additional + * zero byte. The function returns (size_t) -1 if the string can not be + * encoded into bytes with no error reported. Otherwise it returns the number + * of bytes that are necessary to encode the string. If that exceeds the + * length parameter, the string will be cut and only length bytes will be + * written into the buffer. + * + * If JS_CStringsAreUTF8() is true, the string does not fit into the buffer + * and the the first length bytes ends in the middle of utf-8 encoding for + * some character, then such partial utf-8 encoding is replaced by zero bytes. + * This way the result always represents the valid UTF-8 sequence. + */ +JS_PUBLIC_API(size_t) +JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length); + +#ifdef __cplusplus + +class JSAutoByteString { + public: + JSAutoByteString(JSContext *cx, JSString *str JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mBytes(JS_EncodeString(cx, str)) { + JS_ASSERT(cx); + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + JSAutoByteString(JS_GUARD_OBJECT_NOTIFIER_PARAM0) + : mBytes(NULL) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + ~JSAutoByteString() { + js_free(mBytes); + } + + /* Take ownership of the given byte array. */ + void initBytes(char *bytes) { + JS_ASSERT(!mBytes); + mBytes = bytes; + } + + char *encode(JSContext *cx, JSString *str) { + JS_ASSERT(!mBytes); + JS_ASSERT(cx); + mBytes = JS_EncodeString(cx, str); + return mBytes; + } + + void clear() { + js_free(mBytes); + mBytes = NULL; + } + + char *ptr() const { + return mBytes; + } + + bool operator!() const { + return !mBytes; + } + + private: + char *mBytes; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + + /* Copy and assignment are not supported. */ + JSAutoByteString(const JSAutoByteString &another); + JSAutoByteString &operator=(const JSAutoByteString &another); +}; + +#endif + +/************************************************************************/ +/* + * JSON functions + */ +typedef JSBool (* JSONWriteCallback)(const jschar *buf, uint32 len, void *data); + +/* + * JSON.stringify as specified by ES3.1 (draft) + */ +JS_PUBLIC_API(JSBool) +JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space, + JSONWriteCallback callback, void *data); + +/* + * Retrieve a toJSON function. If found, set vp to its result. + */ +JS_PUBLIC_API(JSBool) +JS_TryJSON(JSContext *cx, jsval *vp); + +/* + * JSON.parse as specified by ES3.1 (draft) + */ +JS_PUBLIC_API(JSONParser *) +JS_BeginJSONParse(JSContext *cx, jsval *vp); + +JS_PUBLIC_API(JSBool) +JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len); + +JS_PUBLIC_API(JSBool) +JS_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver); + +/************************************************************************/ + +/* API for the HTML5 internal structured cloning algorithm. */ + +/* The maximum supported structured-clone serialization format version. */ +#define JS_STRUCTURED_CLONE_VERSION 1 + +struct JSStructuredCloneCallbacks { + ReadStructuredCloneOp read; + WriteStructuredCloneOp write; + StructuredCloneErrorOp reportError; +}; + +JS_PUBLIC_API(JSBool) +JS_ReadStructuredClone(JSContext *cx, const uint64 *data, size_t nbytes, + uint32 version, jsval *vp, + const JSStructuredCloneCallbacks *optionalCallbacks, + void *closure); + +/* Note: On success, the caller is responsible for calling js_free(*datap). */ +JS_PUBLIC_API(JSBool) +JS_WriteStructuredClone(JSContext *cx, jsval v, uint64 **datap, size_t *nbytesp, + const JSStructuredCloneCallbacks *optionalCallbacks, + void *closure); + +JS_PUBLIC_API(JSBool) +JS_StructuredClone(JSContext *cx, jsval v, jsval *vp, + const JSStructuredCloneCallbacks *optionalCallbacks, + void *closure); + +#ifdef __cplusplus +/* RAII sugar for JS_WriteStructuredClone. */ +class JSAutoStructuredCloneBuffer { + JSContext *cx_; + uint64 *data_; + size_t nbytes_; + uint32 version_; + + public: + JSAutoStructuredCloneBuffer() + : cx_(NULL), data_(NULL), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION) {} + + ~JSAutoStructuredCloneBuffer() { clear(); } + + JSContext *cx() const { return cx_; } + uint64 *data() const { return data_; } + size_t nbytes() const { return nbytes_; } + + void clear(JSContext *cx=NULL) { + if (data_) { + if (!cx) + cx = cx_; + JS_ASSERT(cx); + JS_free(cx, data_); + cx_ = NULL; + data_ = NULL; + nbytes_ = 0; + version_ = 0; + } + } + + /* + * Adopt some memory. It will be automatically freed by the destructor. + * data must have been allocated using JS_malloc. + */ + void adopt(JSContext *cx, uint64 *data, size_t nbytes, + uint32 version=JS_STRUCTURED_CLONE_VERSION) { + clear(cx); + cx_ = cx; + data_ = data; + nbytes_ = nbytes; + version_ = version; + } + + /* + * Remove the buffer so that it will not be automatically freed. + * After this, the caller is responsible for calling JS_free(*datap). + */ + void steal(uint64 **datap, size_t *nbytesp, JSContext **cxp=NULL, + uint32 *versionp=NULL) { + *datap = data_; + *nbytesp = nbytes_; + if (cxp) + *cxp = cx_; + if (versionp) + *versionp = version_; + + cx_ = NULL; + data_ = NULL; + nbytes_ = 0; + version_ = 0; + } + + bool read(jsval *vp, JSContext *cx=NULL, + const JSStructuredCloneCallbacks *optionalCallbacks=NULL, + void *closure=NULL) const { + if (!cx) + cx = cx_; + JS_ASSERT(cx); + JS_ASSERT(data_); + return !!JS_ReadStructuredClone(cx, data_, nbytes_, version_, vp, + optionalCallbacks, closure); + } + + bool write(JSContext *cx, jsval v, + const JSStructuredCloneCallbacks *optionalCallbacks=NULL, + void *closure=NULL) { + clear(cx); + cx_ = cx; + bool ok = !!JS_WriteStructuredClone(cx, v, &data_, &nbytes_, + optionalCallbacks, closure); + if (!ok) { + data_ = NULL; + nbytes_ = 0; + version_ = JS_STRUCTURED_CLONE_VERSION; + } + return ok; + } + + /** + * Swap ownership with another JSAutoStructuredCloneBuffer. + */ + void swap(JSAutoStructuredCloneBuffer &other) { + JSContext *cx = other.cx_; + uint64 *data = other.data_; + size_t nbytes = other.nbytes_; + uint32 version = other.version_; + + other.cx_ = this->cx_; + other.data_ = this->data_; + other.nbytes_ = this->nbytes_; + other.version_ = this->version_; + + this->cx_ = cx; + this->data_ = data; + this->nbytes_ = nbytes; + this->version_ = version; + } + + private: + /* Copy and assignment are not supported. */ + JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer &other); + JSAutoStructuredCloneBuffer &operator=(const JSAutoStructuredCloneBuffer &other); +}; +#endif + +/* API for implementing custom serialization behavior (for ImageData, File, etc.) */ + +/* The range of tag values the application may use for its own custom object types. */ +#define JS_SCTAG_USER_MIN ((uint32) 0xFFFF8000) +#define JS_SCTAG_USER_MAX ((uint32) 0xFFFFFFFF) + +#define JS_SCERR_RECURSION 0 + +JS_PUBLIC_API(void) +JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks); + +JS_PUBLIC_API(JSBool) +JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32 *p1, uint32 *p2); + +JS_PUBLIC_API(JSBool) +JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len); + +JS_PUBLIC_API(JSBool) +JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32 tag, uint32 data); + +JS_PUBLIC_API(JSBool) +JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len); + +/************************************************************************/ + +/* + * Locale specific string conversion and error message callbacks. + */ +struct JSLocaleCallbacks { + JSLocaleToUpperCase localeToUpperCase; + JSLocaleToLowerCase localeToLowerCase; + JSLocaleCompare localeCompare; + JSLocaleToUnicode localeToUnicode; + JSErrorCallback localeGetErrorMessage; +}; + +/* + * Establish locale callbacks. The pointer must persist as long as the + * JSContext. Passing NULL restores the default behaviour. + */ +extern JS_PUBLIC_API(void) +JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks); + +/* + * Return the address of the current locale callbacks struct, which may + * be NULL. + */ +extern JS_PUBLIC_API(JSLocaleCallbacks *) +JS_GetLocaleCallbacks(JSContext *cx); + +/************************************************************************/ + +/* + * Error reporting. + */ + +/* + * Report an exception represented by the sprintf-like conversion of format + * and its arguments. This exception message string is passed to a pre-set + * JSErrorReporter function (set by JS_SetErrorReporter; see jspubtd.h for + * the JSErrorReporter typedef). + */ +extern JS_PUBLIC_API(void) +JS_ReportError(JSContext *cx, const char *format, ...); + +/* + * Use an errorNumber to retrieve the format string, args are char * + */ +extern JS_PUBLIC_API(void) +JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback, + void *userRef, const uintN errorNumber, ...); + +/* + * Use an errorNumber to retrieve the format string, args are jschar * + */ +extern JS_PUBLIC_API(void) +JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback, + void *userRef, const uintN errorNumber, ...); + +/* + * As above, but report a warning instead (JSREPORT_IS_WARNING(report.flags)). + * Return true if there was no error trying to issue the warning, and if the + * warning was not converted into an error due to the JSOPTION_WERROR option + * being set, false otherwise. + */ +extern JS_PUBLIC_API(JSBool) +JS_ReportWarning(JSContext *cx, const char *format, ...); + +extern JS_PUBLIC_API(JSBool) +JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags, + JSErrorCallback errorCallback, void *userRef, + const uintN errorNumber, ...); + +extern JS_PUBLIC_API(JSBool) +JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags, + JSErrorCallback errorCallback, void *userRef, + const uintN errorNumber, ...); + +/* + * Complain when out of memory. + */ +extern JS_PUBLIC_API(void) +JS_ReportOutOfMemory(JSContext *cx); + +/* + * Complain when an allocation size overflows the maximum supported limit. + */ +extern JS_PUBLIC_API(void) +JS_ReportAllocationOverflow(JSContext *cx); + +struct JSErrorReport { + const char *filename; /* source file name, URL, etc., or null */ + uintN lineno; /* source line number */ + const char *linebuf; /* offending source line without final \n */ + const char *tokenptr; /* pointer to error token in linebuf */ + const jschar *uclinebuf; /* unicode (original) line buffer */ + const jschar *uctokenptr; /* unicode (original) token pointer */ + uintN flags; /* error/warning, etc. */ + uintN errorNumber; /* the error number, e.g. see js.msg */ + const jschar *ucmessage; /* the (default) error message */ + const jschar **messageArgs; /* arguments for the error message */ +}; + +/* + * JSErrorReport flag values. These may be freely composed. + */ +#define JSREPORT_ERROR 0x0 /* pseudo-flag for default case */ +#define JSREPORT_WARNING 0x1 /* reported via JS_ReportWarning */ +#define JSREPORT_EXCEPTION 0x2 /* exception was thrown */ +#define JSREPORT_STRICT 0x4 /* error or warning due to strict option */ + +/* + * This condition is an error in strict mode code, a warning if + * JS_HAS_STRICT_OPTION(cx), and otherwise should not be reported at + * all. We check the strictness of the context's top frame's script; + * where that isn't appropriate, the caller should do the right checks + * itself instead of using this flag. + */ +#define JSREPORT_STRICT_MODE_ERROR 0x8 + +/* + * If JSREPORT_EXCEPTION is set, then a JavaScript-catchable exception + * has been thrown for this runtime error, and the host should ignore it. + * Exception-aware hosts should also check for JS_IsExceptionPending if + * JS_ExecuteScript returns failure, and signal or propagate the exception, as + * appropriate. + */ +#define JSREPORT_IS_WARNING(flags) (((flags) & JSREPORT_WARNING) != 0) +#define JSREPORT_IS_EXCEPTION(flags) (((flags) & JSREPORT_EXCEPTION) != 0) +#define JSREPORT_IS_STRICT(flags) (((flags) & JSREPORT_STRICT) != 0) +#define JSREPORT_IS_STRICT_MODE_ERROR(flags) (((flags) & \ + JSREPORT_STRICT_MODE_ERROR) != 0) + +extern JS_PUBLIC_API(JSErrorReporter) +JS_SetErrorReporter(JSContext *cx, JSErrorReporter er); + +/************************************************************************/ + +/* + * Dates. + */ + +extern JS_PUBLIC_API(JSObject *) +JS_NewDateObject(JSContext *cx, int year, int mon, int mday, int hour, int min, int sec); + +extern JS_PUBLIC_API(JSObject *) +JS_NewDateObjectMsec(JSContext *cx, jsdouble msec); + +/* + * Infallible predicate to test whether obj is a date object. + */ +extern JS_PUBLIC_API(JSBool) +JS_ObjectIsDate(JSContext *cx, JSObject *obj); + +/************************************************************************/ + +/* + * Regular Expressions. + */ +#define JSREG_FOLD 0x01 /* fold uppercase to lowercase */ +#define JSREG_GLOB 0x02 /* global exec, creates array of matches */ +#define JSREG_MULTILINE 0x04 /* treat ^ and $ as begin and end of line */ +#define JSREG_STICKY 0x08 /* only match starting at lastIndex */ +#define JSREG_FLAT 0x10 /* parse as a flat regexp */ +#define JSREG_NOCOMPILE 0x20 /* do not try to compile to native code */ + +extern JS_PUBLIC_API(JSObject *) +JS_NewRegExpObject(JSContext *cx, JSObject *obj, char *bytes, size_t length, uintN flags); + +extern JS_PUBLIC_API(JSObject *) +JS_NewUCRegExpObject(JSContext *cx, JSObject *obj, jschar *chars, size_t length, uintN flags); + +extern JS_PUBLIC_API(void) +JS_SetRegExpInput(JSContext *cx, JSObject *obj, JSString *input, JSBool multiline); + +extern JS_PUBLIC_API(void) +JS_ClearRegExpStatics(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_ExecuteRegExp(JSContext *cx, JSObject *obj, JSObject *reobj, jschar *chars, size_t length, + size_t *indexp, JSBool test, jsval *rval); + +/* RegExp interface for clients without a global object. */ + +extern JS_PUBLIC_API(JSObject *) +JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, uintN flags); + +extern JS_PUBLIC_API(JSObject *) +JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, uintN flags); + +extern JS_PUBLIC_API(JSBool) +JS_ExecuteRegExpNoStatics(JSContext *cx, JSObject *reobj, jschar *chars, size_t length, + size_t *indexp, JSBool test, jsval *rval); + +/************************************************************************/ + +extern JS_PUBLIC_API(JSBool) +JS_IsExceptionPending(JSContext *cx); + +extern JS_PUBLIC_API(JSBool) +JS_GetPendingException(JSContext *cx, jsval *vp); + +extern JS_PUBLIC_API(void) +JS_SetPendingException(JSContext *cx, jsval v); + +extern JS_PUBLIC_API(void) +JS_ClearPendingException(JSContext *cx); + +extern JS_PUBLIC_API(JSBool) +JS_ReportPendingException(JSContext *cx); + +/* + * Save the current exception state. This takes a snapshot of cx's current + * exception state without making any change to that state. + * + * The returned state pointer MUST be passed later to JS_RestoreExceptionState + * (to restore that saved state, overriding any more recent state) or else to + * JS_DropExceptionState (to free the state struct in case it is not correct + * or desirable to restore it). Both Restore and Drop free the state struct, + * so callers must stop using the pointer returned from Save after calling the + * Release or Drop API. + */ +extern JS_PUBLIC_API(JSExceptionState *) +JS_SaveExceptionState(JSContext *cx); + +extern JS_PUBLIC_API(void) +JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state); + +extern JS_PUBLIC_API(void) +JS_DropExceptionState(JSContext *cx, JSExceptionState *state); + +/* + * If the given value is an exception object that originated from an error, + * the exception will contain an error report struct, and this API will return + * the address of that struct. Otherwise, it returns NULL. The lifetime of + * the error report struct that might be returned is the same as the lifetime + * of the exception object. + */ +extern JS_PUBLIC_API(JSErrorReport *) +JS_ErrorFromException(JSContext *cx, jsval v); + +/* + * Given a reported error's message and JSErrorReport struct pointer, throw + * the corresponding exception on cx. + */ +extern JS_PUBLIC_API(JSBool) +JS_ThrowReportedError(JSContext *cx, const char *message, + JSErrorReport *reportp); + +/* + * Throws a StopIteration exception on cx. + */ +extern JS_PUBLIC_API(JSBool) +JS_ThrowStopIteration(JSContext *cx); + +/* + * Associate the current thread with the given context. This is done + * implicitly by JS_NewContext. + * + * Returns the old thread id for this context, which should be treated as + * an opaque value. This value is provided for comparison to 0, which + * indicates that ClearContextThread has been called on this context + * since the last SetContextThread, or non-0, which indicates the opposite. + */ +extern JS_PUBLIC_API(jsword) +JS_GetContextThread(JSContext *cx); + +extern JS_PUBLIC_API(jsword) +JS_SetContextThread(JSContext *cx); + +extern JS_PUBLIC_API(jsword) +JS_ClearContextThread(JSContext *cx); + +/************************************************************************/ + +/* + * JS_IsConstructing must be called from within a native given the + * native's original cx and vp arguments. If JS_IsConstructing is true, + * JS_THIS must not be used; the constructor should construct and return a + * new object. Otherwise, the native is called as an ordinary function and + * JS_THIS may be used. + */ +static JS_ALWAYS_INLINE JSBool +JS_IsConstructing(JSContext *cx, const jsval *vp) +{ + jsval_layout l; + +#ifdef DEBUG + JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); + if (JS_ObjectIsFunction(cx, callee)) { + JSFunction *fun = JS_ValueToFunction(cx, JS_CALLEE(cx, vp)); + JS_ASSERT((JS_GetFunctionFlags(fun) & JSFUN_CONSTRUCTOR) != 0); + } else { + JS_ASSERT(JS_GET_CLASS(cx, callee)->construct != NULL); + } +#endif + + l.asBits = JSVAL_BITS(vp[1]); + return JSVAL_IS_MAGIC_IMPL(l); +} + +/* + * In the case of a constructor called from JS_ConstructObject and + * JS_InitClass where the class has the JSCLASS_CONSTRUCT_PROTOTYPE flag set, + * the JS engine passes the constructor a non-standard 'this' object. In such + * cases, the following query provides the additional information of whether a + * special 'this' was supplied. E.g.: + * + * JSBool foo_native(JSContext *cx, uintN argc, jsval *vp) { + * JSObject *maybeThis; + * if (JS_IsConstructing_PossiblyWithGivenThisObject(cx, vp, &maybeThis)) { + * // native called as a constructor + * if (maybeThis) + * // native called as a constructor with maybeThis as 'this' + * } else { + * // native called as function, maybeThis is still uninitialized + * } + * } + * + * Note that embeddings do not need to use this query unless they use the + * aforementioned API/flags. + */ +static JS_ALWAYS_INLINE JSBool +JS_IsConstructing_PossiblyWithGivenThisObject(JSContext *cx, const jsval *vp, + JSObject **maybeThis) +{ + jsval_layout l; + JSBool isCtor; + +#ifdef DEBUG + JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); + if (JS_ObjectIsFunction(cx, callee)) { + JSFunction *fun = JS_ValueToFunction(cx, JS_CALLEE(cx, vp)); + JS_ASSERT((JS_GetFunctionFlags(fun) & JSFUN_CONSTRUCTOR) != 0); + } else { + JS_ASSERT(JS_GET_CLASS(cx, callee)->construct != NULL); + } +#endif + + l.asBits = JSVAL_BITS(vp[1]); + isCtor = JSVAL_IS_MAGIC_IMPL(l); + if (isCtor) + *maybeThis = MAGIC_JSVAL_TO_OBJECT_OR_NULL_IMPL(l); + return isCtor; +} + +/* + * If a constructor does not have any static knowledge about the type of + * object to create, it can request that the JS engine create a default new + * 'this' object, as is done for non-constructor natives when called with new. + */ +extern JS_PUBLIC_API(JSObject *) +JS_NewObjectForConstructor(JSContext *cx, const jsval *vp); + +/************************************************************************/ + +#ifdef DEBUG +#define JS_GC_ZEAL 1 +#endif + +#ifdef JS_GC_ZEAL +extern JS_PUBLIC_API(void) +JS_SetGCZeal(JSContext *cx, uint8 zeal); +#endif + +JS_END_EXTERN_C + +#endif /* jsapi_h___ */ diff --git a/js/src/jsarena.cpp b/js/src/jsarena.cpp new file mode 100644 index 0000000..dd1b8a6 --- /dev/null +++ b/js/src/jsarena.cpp @@ -0,0 +1,450 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Lifetime-based fast allocation, inspired by much prior art, including + * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes" + * David R. Hanson, Software -- Practice and Experience, Vol. 20(1). + */ +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsbit.h" +#include "jsarena.h" +#include "jsprvtd.h" + +#ifdef JS_ARENAMETER +static JSArenaStats *arena_stats_list; + +#define COUNT(pool,what) (pool)->stats.what++ +#else +#define COUNT(pool,what) /* nothing */ +#endif + +#define JS_ARENA_DEFAULT_ALIGN sizeof(double) + +JS_PUBLIC_API(void) +JS_InitArenaPool(JSArenaPool *pool, const char *name, size_t size, + size_t align, size_t *quotap) +{ + if (align == 0) + align = JS_ARENA_DEFAULT_ALIGN; + pool->mask = JS_BITMASK(JS_CeilingLog2(align)); + pool->first.next = NULL; + pool->first.base = pool->first.avail = pool->first.limit = + JS_ARENA_ALIGN(pool, &pool->first + 1); + pool->current = &pool->first; + pool->arenasize = size; + pool->quotap = quotap; +#ifdef JS_ARENAMETER + memset(&pool->stats, 0, sizeof pool->stats); + pool->stats.name = strdup(name); + pool->stats.next = arena_stats_list; + arena_stats_list = &pool->stats; +#endif +} + +/* + * An allocation that consumes more than pool->arenasize also has a header + * pointing back to its previous arena's next member. This header is not + * included in [a->base, a->limit), so its space can't be wrongly claimed. + * + * As the header is a pointer, it must be well-aligned. If pool->mask is + * greater than or equal to POINTER_MASK, the header just preceding a->base + * for an oversized arena a is well-aligned, because a->base is well-aligned. + * However, we may need to add more space to pad the JSArena ** back-pointer + * so that it lies just behind a->base, because a might not be aligned such + * that (jsuword)(a + 1) is on a pointer boundary. + * + * By how much must we pad? Let M be the alignment modulus for pool and P + * the modulus for a pointer. Given M >= P, the base of an oversized arena + * that satisfies M is well-aligned for P. + * + * On the other hand, if M < P, we must include enough space in the header + * size to align the back-pointer on a P boundary so that it can be found by + * subtracting P from a->base. This means a->base must be on a P boundary, + * even though subsequent allocations from a may be aligned on a lesser (M) + * boundary. Given powers of two M and P as above, the extra space needed + * when M < P is P-M or POINTER_MASK - pool->mask. + * + * The size of a header including padding is given by the HEADER_SIZE macro, + * below, for any pool (for any value of M). + * + * The mask to align a->base for any pool is (pool->mask | POINTER_MASK), or + * HEADER_BASE_MASK(pool). + * + * PTR_TO_HEADER computes the address of the back-pointer, given an oversized + * allocation at p. By definition, p must be a->base for the arena a that + * contains p. GET_HEADER and SET_HEADER operate on an oversized arena a, in + * the case of SET_HEADER with back-pointer ap. + */ +#define POINTER_MASK ((jsuword)(JS_ALIGN_OF_POINTER - 1)) +#define HEADER_SIZE(pool) (sizeof(JSArena **) \ + + (((pool)->mask < POINTER_MASK) \ + ? POINTER_MASK - (pool)->mask \ + : 0)) +#define HEADER_BASE_MASK(pool) ((pool)->mask | POINTER_MASK) +#define PTR_TO_HEADER(pool,p) (JS_ASSERT(((jsuword)(p) \ + & HEADER_BASE_MASK(pool)) \ + == 0), \ + (JSArena ***)(p) - 1) +#define GET_HEADER(pool,a) (*PTR_TO_HEADER(pool, (a)->base)) +#define SET_HEADER(pool,a,ap) (*PTR_TO_HEADER(pool, (a)->base) = (ap)) + +JS_PUBLIC_API(void *) +JS_ArenaAllocate(JSArenaPool *pool, size_t nb) +{ + JSArena **ap, *a, *b; + jsuword extra, hdrsz, gross; + void *p; + + /* + * Search pool from current forward till we find or make enough space. + * + * NB: subtract nb from a->limit in the loop condition, instead of adding + * nb to a->avail, to avoid overflowing a 32-bit address space (possible + * when running a 32-bit program on a 64-bit system where the kernel maps + * the heap up against the top of the 32-bit address space). + * + * Thanks to Juergen Kreileder , who brought this up in + * https://bugzilla.mozilla.org/show_bug.cgi?id=279273. + */ + JS_ASSERT((nb & pool->mask) == 0); + for (a = pool->current; nb > a->limit || a->avail > a->limit - nb; + pool->current = a) { + ap = &a->next; + if (!*ap) { + /* Not enough space in pool, so we must malloc. */ + extra = (nb > pool->arenasize) ? HEADER_SIZE(pool) : 0; + hdrsz = sizeof *a + extra + pool->mask; + gross = hdrsz + JS_MAX(nb, pool->arenasize); + if (gross < nb) + return NULL; + if (pool->quotap) { + if (gross > *pool->quotap) + return NULL; + b = (JSArena *) js_malloc(gross); + if (!b) + return NULL; + *pool->quotap -= gross; + } else { + b = (JSArena *) js_malloc(gross); + if (!b) + return NULL; + } + + b->next = NULL; + b->limit = (jsuword)b + gross; + JS_COUNT_ARENA(pool,++); + COUNT(pool, nmallocs); + + /* If oversized, store ap in the header, just before a->base. */ + *ap = a = b; + JS_ASSERT(gross <= JS_UPTRDIFF(a->limit, a)); + if (extra) { + a->base = a->avail = + ((jsuword)a + hdrsz) & ~HEADER_BASE_MASK(pool); + SET_HEADER(pool, a, ap); + } else { + a->base = a->avail = JS_ARENA_ALIGN(pool, a + 1); + } + continue; + } + a = *ap; /* move to next arena */ + } + + p = (void *)a->avail; + a->avail += nb; + JS_ASSERT(a->base <= a->avail && a->avail <= a->limit); + return p; +} + +JS_PUBLIC_API(void *) +JS_ArenaRealloc(JSArenaPool *pool, void *p, size_t size, size_t incr) +{ + JSArena **ap, *a, *b; + jsuword boff, aoff, extra, hdrsz, gross, growth; + + /* + * Use the oversized-single-allocation header to avoid searching for ap. + * See JS_ArenaAllocate, the SET_HEADER call. + */ + if (size > pool->arenasize) { + ap = *PTR_TO_HEADER(pool, p); + a = *ap; + } else { + ap = &pool->first.next; + while ((a = *ap) != pool->current) + ap = &a->next; + } + + JS_ASSERT(a->base == (jsuword)p); + boff = JS_UPTRDIFF(a->base, a); + aoff = JS_ARENA_ALIGN(pool, size + incr); + JS_ASSERT(aoff > pool->arenasize); + extra = HEADER_SIZE(pool); /* oversized header holds ap */ + hdrsz = sizeof *a + extra + pool->mask; /* header and alignment slop */ + gross = hdrsz + aoff; + JS_ASSERT(gross > aoff); + if (pool->quotap) { + growth = gross - (a->limit - (jsuword) a); + if (growth > *pool->quotap) + return NULL; + a = (JSArena *) js_realloc(a, gross); + if (!a) + return NULL; + *pool->quotap -= growth; + } else { + a = (JSArena *) js_realloc(a, gross); + if (!a) + return NULL; + } +#ifdef JS_ARENAMETER + pool->stats.nreallocs++; +#endif + + if (a != *ap) { + /* Oops, realloc moved the allocation: update other pointers to a. */ + if (pool->current == *ap) + pool->current = a; + b = a->next; + if (b && b->avail - b->base > pool->arenasize) { + JS_ASSERT(GET_HEADER(pool, b) == &(*ap)->next); + SET_HEADER(pool, b, &a->next); + } + + /* Now update *ap, the next link of the arena before a. */ + *ap = a; + } + + a->base = ((jsuword)a + hdrsz) & ~HEADER_BASE_MASK(pool); + a->limit = (jsuword)a + gross; + a->avail = a->base + aoff; + JS_ASSERT(a->base <= a->avail && a->avail <= a->limit); + + /* Check whether realloc aligned differently, and copy if necessary. */ + if (boff != JS_UPTRDIFF(a->base, a)) + memmove((void *)a->base, (char *)a + boff, size); + + /* Store ap in the oversized-load arena header. */ + SET_HEADER(pool, a, ap); + return (void *)a->base; +} + +JS_PUBLIC_API(void *) +JS_ArenaGrow(JSArenaPool *pool, void *p, size_t size, size_t incr) +{ + void *newp; + + /* + * If p points to an oversized allocation, it owns an entire arena, so we + * can simply realloc the arena. + */ + if (size > pool->arenasize) + return JS_ArenaRealloc(pool, p, size, incr); + + JS_ARENA_ALLOCATE(newp, pool, size + incr); + if (newp) + memcpy(newp, p, size); + return newp; +} + +/* + * Free tail arenas linked after head, which may not be the true list head. + * Reset pool->current to point to head in case it pointed at a tail arena. + */ +static void +FreeArenaList(JSArenaPool *pool, JSArena *head) +{ + JSArena **ap, *a; + + ap = &head->next; + a = *ap; + if (!a) + return; + +#ifdef DEBUG + do { + JS_ASSERT(a->base <= a->avail && a->avail <= a->limit); + a->avail = a->base; + JS_CLEAR_UNUSED(a); + } while ((a = a->next) != NULL); + a = *ap; +#endif + + do { + *ap = a->next; + if (pool->quotap) + *pool->quotap += a->limit - (jsuword) a; + JS_CLEAR_ARENA(a); + JS_COUNT_ARENA(pool,--); + js_free(a); + } while ((a = *ap) != NULL); + + pool->current = head; +} + +JS_PUBLIC_API(void) +JS_ArenaRelease(JSArenaPool *pool, char *mark) +{ + JSArena *a; + + for (a = &pool->first; a; a = a->next) { + JS_ASSERT(a->base <= a->avail && a->avail <= a->limit); + + if (JS_ARENA_MARK_MATCH(a, mark)) { + a->avail = JS_ARENA_ALIGN(pool, mark); + JS_ASSERT(a->avail <= a->limit); + FreeArenaList(pool, a); + return; + } + } +} + +JS_PUBLIC_API(void) +JS_FreeArenaPool(JSArenaPool *pool) +{ + FreeArenaList(pool, &pool->first); + COUNT(pool, ndeallocs); +} + +JS_PUBLIC_API(void) +JS_FinishArenaPool(JSArenaPool *pool) +{ + FreeArenaList(pool, &pool->first); +#ifdef JS_ARENAMETER + { + JSArenaStats *stats, **statsp; + + if (pool->stats.name) { + js_free(pool->stats.name); + pool->stats.name = NULL; + } + for (statsp = &arena_stats_list; (stats = *statsp) != 0; + statsp = &stats->next) { + if (stats == &pool->stats) { + *statsp = stats->next; + return; + } + } + } +#endif +} + +JS_PUBLIC_API(void) +JS_ArenaFinish() +{ +} + +JS_PUBLIC_API(void) +JS_ArenaShutDown(void) +{ +} + +#ifdef JS_ARENAMETER +JS_PUBLIC_API(void) +JS_ArenaCountAllocation(JSArenaPool *pool, size_t nb) +{ + pool->stats.nallocs++; + pool->stats.nbytes += nb; + if (nb > pool->stats.maxalloc) + pool->stats.maxalloc = nb; + pool->stats.variance += nb * nb; +} + +JS_PUBLIC_API(void) +JS_ArenaCountInplaceGrowth(JSArenaPool *pool, size_t size, size_t incr) +{ + pool->stats.ninplace++; +} + +JS_PUBLIC_API(void) +JS_ArenaCountGrowth(JSArenaPool *pool, size_t size, size_t incr) +{ + pool->stats.ngrows++; + pool->stats.nbytes += incr; + pool->stats.variance -= size * size; + size += incr; + if (size > pool->stats.maxalloc) + pool->stats.maxalloc = size; + pool->stats.variance += size * size; +} + +JS_PUBLIC_API(void) +JS_ArenaCountRelease(JSArenaPool *pool, char *mark) +{ + pool->stats.nreleases++; +} + +JS_PUBLIC_API(void) +JS_ArenaCountRetract(JSArenaPool *pool, char *mark) +{ + pool->stats.nfastrels++; +} + +#include + +JS_PUBLIC_API(void) +JS_DumpArenaStats(FILE *fp) +{ + JSArenaStats *stats; + double mean, sigma; + + for (stats = arena_stats_list; stats; stats = stats->next) { + mean = JS_MeanAndStdDev(stats->nallocs, stats->nbytes, stats->variance, + &sigma); + + fprintf(fp, "\n%s allocation statistics:\n", stats->name); + fprintf(fp, " number of arenas: %u\n", stats->narenas); + fprintf(fp, " number of allocations: %u\n", stats->nallocs); + fprintf(fp, " number of malloc calls: %u\n", stats->nmallocs); + fprintf(fp, " number of deallocations: %u\n", stats->ndeallocs); + fprintf(fp, " number of allocation growths: %u\n", stats->ngrows); + fprintf(fp, " number of in-place growths: %u\n", stats->ninplace); + fprintf(fp, " number of realloc'ing growths: %u\n", stats->nreallocs); + fprintf(fp, "number of released allocations: %u\n", stats->nreleases); + fprintf(fp, " number of fast releases: %u\n", stats->nfastrels); + fprintf(fp, " total bytes allocated: %u\n", stats->nbytes); + fprintf(fp, " mean allocation size: %g\n", mean); + fprintf(fp, " standard deviation: %g\n", sigma); + fprintf(fp, " maximum allocation size: %u\n", stats->maxalloc); + } +} +#endif /* JS_ARENAMETER */ diff --git a/js/src/jsarena.h b/js/src/jsarena.h new file mode 100644 index 0000000..6eeb04a --- /dev/null +++ b/js/src/jsarena.h @@ -0,0 +1,291 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsarena_h___ +#define jsarena_h___ +/* + * Lifetime-based fast allocation, inspired by much prior art, including + * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes" + * David R. Hanson, Software -- Practice and Experience, Vol. 20(1). + * + * Also supports LIFO allocation (JS_ARENA_MARK/JS_ARENA_RELEASE). + */ +#include +#include "jstypes.h" +#include "jscompat.h" + +JS_BEGIN_EXTERN_C + +typedef struct JSArena JSArena; +typedef struct JSArenaPool JSArenaPool; + +struct JSArena { + JSArena *next; /* next arena for this lifetime */ + jsuword base; /* aligned base address, follows this header */ + jsuword limit; /* one beyond last byte in arena */ + jsuword avail; /* points to next available byte */ +}; + +#ifdef JS_ARENAMETER +typedef struct JSArenaStats JSArenaStats; + +struct JSArenaStats { + JSArenaStats *next; /* next in arenaStats list */ + char *name; /* name for debugging */ + uint32 narenas; /* number of arenas in pool */ + uint32 nallocs; /* number of JS_ARENA_ALLOCATE() calls */ + uint32 nmallocs; /* number of malloc() calls */ + uint32 ndeallocs; /* number of lifetime deallocations */ + uint32 ngrows; /* number of JS_ARENA_GROW() calls */ + uint32 ninplace; /* number of in-place growths */ + uint32 nreallocs; /* number of arena grow extending reallocs */ + uint32 nreleases; /* number of JS_ARENA_RELEASE() calls */ + uint32 nfastrels; /* number of "fast path" releases */ + size_t nbytes; /* total bytes allocated */ + size_t maxalloc; /* maximum allocation size in bytes */ + double variance; /* size variance accumulator */ +}; +#endif + +struct JSArenaPool { + JSArena first; /* first arena in pool list */ + JSArena *current; /* arena from which to allocate space */ + size_t arenasize; /* net exact size of a new arena */ + jsuword mask; /* alignment mask (power-of-2 - 1) */ + size_t *quotap; /* pointer to the quota on pool allocation + size or null if pool is unlimited */ +#ifdef JS_ARENAMETER + JSArenaStats stats; +#endif +}; + +#define JS_ARENA_ALIGN(pool, n) (((jsuword)(n) + (pool)->mask) & ~(pool)->mask) + +#define JS_ARENA_ALLOCATE(p, pool, nb) \ + JS_ARENA_ALLOCATE_CAST(p, void *, pool, nb) + +#define JS_ARENA_ALLOCATE_TYPE(p, type, pool) \ + JS_ARENA_ALLOCATE_COMMON(p, type *, pool, sizeof(type), 0) + +#define JS_ARENA_ALLOCATE_CAST(p, type, pool, nb) \ + JS_ARENA_ALLOCATE_COMMON(p, type, pool, nb, _nb > _a->limit) + +/* + * NB: In JS_ARENA_ALLOCATE_CAST and JS_ARENA_GROW_CAST, always subtract _nb + * from a->limit rather than adding _nb to _p, to avoid overflowing a 32-bit + * address space (possible when running a 32-bit program on a 64-bit system + * where the kernel maps the heap up against the top of the 32-bit address + * space). + * + * Thanks to Juergen Kreileder , who brought this up in + * https://bugzilla.mozilla.org/show_bug.cgi?id=279273. + */ +#define JS_ARENA_ALLOCATE_COMMON(p, type, pool, nb, guard) \ + JS_BEGIN_MACRO \ + JSArena *_a = (pool)->current; \ + size_t _nb = JS_ARENA_ALIGN(pool, nb); \ + jsuword _p = _a->avail; \ + if ((guard) || _p > _a->limit - _nb) \ + _p = (jsuword)JS_ArenaAllocate(pool, _nb); \ + else \ + _a->avail = _p + _nb; \ + p = (type) _p; \ + STATIC_ASSUME(!p || ubound((char *)p) >= nb) \ + JS_ArenaCountAllocation(pool, nb); \ + JS_END_MACRO + +#define JS_ARENA_GROW(p, pool, size, incr) \ + JS_ARENA_GROW_CAST(p, void *, pool, size, incr) + +#define JS_ARENA_GROW_CAST(p, type, pool, size, incr) \ + JS_BEGIN_MACRO \ + JSArena *_a = (pool)->current; \ + if (_a->avail == (jsuword)(p) + JS_ARENA_ALIGN(pool, size)) { \ + size_t _nb = (size) + (incr); \ + _nb = JS_ARENA_ALIGN(pool, _nb); \ + if (_a->limit >= _nb && (jsuword)(p) <= _a->limit - _nb) { \ + _a->avail = (jsuword)(p) + _nb; \ + JS_ArenaCountInplaceGrowth(pool, size, incr); \ + } else if ((jsuword)(p) == _a->base) { \ + p = (type) JS_ArenaRealloc(pool, p, size, incr); \ + } else { \ + p = (type) JS_ArenaGrow(pool, p, size, incr); \ + } \ + } else { \ + p = (type) JS_ArenaGrow(pool, p, size, incr); \ + } \ + STATIC_ASSUME(!p || ubound((char *)p) >= size + incr); \ + JS_ArenaCountGrowth(pool, size, incr); \ + JS_END_MACRO + +#define JS_ARENA_MARK(pool) ((void *) (pool)->current->avail) +#define JS_UPTRDIFF(p,q) ((jsuword)(p) - (jsuword)(q)) + +/* + * Check if the mark is inside arena's allocated area. + */ +#define JS_ARENA_MARK_MATCH(a, mark) \ + (JS_UPTRDIFF(mark, (a)->base) <= JS_UPTRDIFF((a)->avail, (a)->base)) + +#ifdef DEBUG +#define JS_FREE_PATTERN 0xDA +#define JS_CLEAR_UNUSED(a) (JS_ASSERT((a)->avail <= (a)->limit), \ + memset((void*)(a)->avail, JS_FREE_PATTERN, \ + (a)->limit - (a)->avail)) +#define JS_CLEAR_ARENA(a) memset((void*)(a), JS_FREE_PATTERN, \ + (a)->limit - (jsuword)(a)) +#else +#define JS_CLEAR_UNUSED(a) /* nothing */ +#define JS_CLEAR_ARENA(a) /* nothing */ +#endif + +#define JS_ARENA_RELEASE(pool, mark) \ + JS_BEGIN_MACRO \ + char *_m = (char *)(mark); \ + JSArena *_a = (pool)->current; \ + if (_a != &(pool)->first && JS_ARENA_MARK_MATCH(_a, _m)) { \ + _a->avail = (jsuword)JS_ARENA_ALIGN(pool, _m); \ + JS_ASSERT(_a->avail <= _a->limit); \ + JS_CLEAR_UNUSED(_a); \ + JS_ArenaCountRetract(pool, _m); \ + } else { \ + JS_ArenaRelease(pool, _m); \ + } \ + JS_ArenaCountRelease(pool, _m); \ + JS_END_MACRO + +#ifdef JS_ARENAMETER +#define JS_COUNT_ARENA(pool,op) ((pool)->stats.narenas op) +#else +#define JS_COUNT_ARENA(pool,op) +#endif + +#define JS_ARENA_DESTROY(pool, a, pnext) \ + JS_BEGIN_MACRO \ + JS_COUNT_ARENA(pool,--); \ + if ((pool)->current == (a)) (pool)->current = &(pool)->first; \ + *(pnext) = (a)->next; \ + JS_CLEAR_ARENA(a); \ + js_free(a); \ + (a) = NULL; \ + JS_END_MACRO + +/* + * Initialize an arena pool with a minimum size per arena of size bytes. + */ +extern JS_PUBLIC_API(void) +JS_InitArenaPool(JSArenaPool *pool, const char *name, size_t size, + size_t align, size_t *quotap); + +/* + * Free the arenas in pool. The user may continue to allocate from pool + * after calling this function. There is no need to call JS_InitArenaPool() + * again unless JS_FinishArenaPool(pool) has been called. + */ +extern JS_PUBLIC_API(void) +JS_FreeArenaPool(JSArenaPool *pool); + +/* + * Free the arenas in pool and finish using it altogether. + */ +extern JS_PUBLIC_API(void) +JS_FinishArenaPool(JSArenaPool *pool); + +/* + * Deprecated do-nothing function. + */ +extern JS_PUBLIC_API(void) +JS_ArenaFinish(void); + +/* + * Deprecated do-nothing function. + */ +extern JS_PUBLIC_API(void) +JS_ArenaShutDown(void); + +/* + * Friend functions used by the JS_ARENA_*() macros. + */ +extern JS_PUBLIC_API(void *) +JS_ArenaAllocate(JSArenaPool *pool, size_t nb); + +extern JS_PUBLIC_API(void *) +JS_ArenaRealloc(JSArenaPool *pool, void *p, size_t size, size_t incr); + +extern JS_PUBLIC_API(void *) +JS_ArenaGrow(JSArenaPool *pool, void *p, size_t size, size_t incr); + +extern JS_PUBLIC_API(void) +JS_ArenaRelease(JSArenaPool *pool, char *mark); + +#ifdef JS_ARENAMETER + +#include + +extern JS_PUBLIC_API(void) +JS_ArenaCountAllocation(JSArenaPool *pool, size_t nb); + +extern JS_PUBLIC_API(void) +JS_ArenaCountInplaceGrowth(JSArenaPool *pool, size_t size, size_t incr); + +extern JS_PUBLIC_API(void) +JS_ArenaCountGrowth(JSArenaPool *pool, size_t size, size_t incr); + +extern JS_PUBLIC_API(void) +JS_ArenaCountRelease(JSArenaPool *pool, char *mark); + +extern JS_PUBLIC_API(void) +JS_ArenaCountRetract(JSArenaPool *pool, char *mark); + +extern JS_PUBLIC_API(void) +JS_DumpArenaStats(FILE *fp); + +#else /* !JS_ARENAMETER */ + +#define JS_ArenaCountAllocation(ap, nb) /* nothing */ +#define JS_ArenaCountInplaceGrowth(ap, size, incr) /* nothing */ +#define JS_ArenaCountGrowth(ap, size, incr) /* nothing */ +#define JS_ArenaCountRelease(ap, mark) /* nothing */ +#define JS_ArenaCountRetract(ap, mark) /* nothing */ + +#endif /* !JS_ARENAMETER */ + +JS_END_EXTERN_C + +#endif /* jsarena_h___ */ diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp new file mode 100644 index 0000000..7e5cdc0 --- /dev/null +++ b/js/src/jsarray.cpp @@ -0,0 +1,3291 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=8 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS array class. + * + * Array objects begin as "dense" arrays, optimized for index-only property + * access over a vector of slots with high load factor. Array methods + * optimize for denseness by testing that the object's class is + * &js_ArrayClass, and can then directly manipulate the slots for efficiency. + * + * We track these pieces of metadata for arrays in dense mode: + * - The array's length property as a uint32, accessible with + * getArrayLength(), setArrayLength(). + * - The number of element slots (capacity), gettable with + * getDenseArrayCapacity(). + * + * In dense mode, holes in the array are represented by + * MagicValue(JS_ARRAY_HOLE) invalid values. + * + * NB: the capacity and length of a dense array are entirely unrelated! The + * length may be greater than, less than, or equal to the capacity. The first + * case may occur when the user writes "new Array(100), in which case the + * length is 100 while the capacity remains 0 (indices below length and above + * capaicty must be treated as holes). See array_length_setter for another + * explanation of how the first case may occur. + * + * Arrays are converted to use js_SlowArrayClass when any of these conditions + * are met: + * - there are more than MIN_SPARSE_INDEX slots total + * - the load factor (COUNT / capacity) is less than 0.25 + * - a property is set that is not indexed (and not "length") + * - a property is defined that has non-default property attributes. + * + * Dense arrays do not track property creation order, so unlike other native + * objects and slow arrays, enumerating an array does not necessarily visit the + * properties in the order they were created. We could instead maintain the + * scope to track property enumeration order, but still use the fast slot + * access. That would have the same memory cost as just using a + * js_SlowArrayClass, but have the same performance characteristics as a dense + * array for slot accesses, at some cost in code complexity. + */ +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsutil.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbit.h" +#include "jsbool.h" +#include "jstracer.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsscope.h" +#include "jsstr.h" +#include "jsstaticcheck.h" +#include "jsvector.h" +#include "jswrapper.h" + +#include "jsatominlines.h" +#include "jscntxtinlines.h" +#include "jsinterpinlines.h" +#include "jsobjinlines.h" + +using namespace js; +using namespace js::gc; + +/* 2^32 - 1 as a number and a string */ +#define MAXINDEX 4294967295u +#define MAXSTR "4294967295" + +static inline bool +ENSURE_SLOW_ARRAY(JSContext *cx, JSObject *obj) +{ + return obj->getClass() == &js_SlowArrayClass || + obj->makeDenseArraySlow(cx); +} + +/* + * Determine if the id represents an array index or an XML property index. + * + * An id is an array index according to ECMA by (15.4): + * + * "Array objects give special treatment to a certain class of property names. + * A property name P (in the form of a string value) is an array index if and + * only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal + * to 2^32-1." + * + * In our implementation, it would be sufficient to check for JSVAL_IS_INT(id) + * except that by using signed 31-bit integers we miss the top half of the + * valid range. This function checks the string representation itself; note + * that calling a standard conversion routine might allow strings such as + * "08" or "4.0" as array indices, which they are not. + * + * 'id' is passed as a jsboxedword since the given id need not necessarily hold + * an atomized string. + */ +bool +js_StringIsIndex(JSLinearString *str, jsuint *indexp) +{ + const jschar *cp = str->chars(); + if (JS7_ISDEC(*cp) && str->length() < sizeof(MAXSTR)) { + jsuint index = JS7_UNDEC(*cp++); + jsuint oldIndex = 0; + jsuint c = 0; + if (index != 0) { + while (JS7_ISDEC(*cp)) { + oldIndex = index; + c = JS7_UNDEC(*cp); + index = 10*index + c; + cp++; + } + } + + /* Ensure that all characters were consumed and we didn't overflow. */ + if (*cp == 0 && + (oldIndex < (MAXINDEX / 10) || + (oldIndex == (MAXINDEX / 10) && c < (MAXINDEX % 10)))) + { + *indexp = index; + return true; + } + } + return false; +} + +static bool +ValueToLength(JSContext *cx, Value* vp, jsuint* plength) +{ + if (vp->isInt32()) { + int32_t i = vp->toInt32(); + if (i < 0) + goto error; + + *plength = (jsuint)(i); + return true; + } + + jsdouble d; + if (!ValueToNumber(cx, *vp, &d)) + goto error; + + if (JSDOUBLE_IS_NaN(d)) + goto error; + + jsuint length; + length = (jsuint) d; + if (d != (jsdouble) length) + goto error; + + + *plength = length; + return true; + +error: + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_ARRAY_LENGTH); + return false; +} + +JSBool +js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) +{ + if (obj->isArray()) { + *lengthp = obj->getArrayLength(); + return true; + } + + if (obj->isArguments() && !obj->isArgsLengthOverridden()) { + *lengthp = obj->getArgsInitialLength(); + return true; + } + + AutoValueRooter tvr(cx); + if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), tvr.addr())) + return false; + + if (tvr.value().isInt32()) { + *lengthp = jsuint(jsint(tvr.value().toInt32())); /* jsuint cast does ToUint32 */ + return true; + } + + JS_STATIC_ASSERT(sizeof(jsuint) == sizeof(uint32_t)); + return ValueToECMAUint32(cx, tvr.value(), (uint32_t *)lengthp); +} + +JSBool JS_FASTCALL +js_IndexToId(JSContext *cx, jsuint index, jsid *idp) +{ + JSString *str; + + if (index <= JSID_INT_MAX) { + *idp = INT_TO_JSID(index); + return JS_TRUE; + } + str = js_NumberToString(cx, index); + if (!str) + return JS_FALSE; + return js_ValueToStringId(cx, StringValue(str), idp); +} + +static JSBool +BigIndexToId(JSContext *cx, JSObject *obj, jsuint index, JSBool createAtom, + jsid *idp) +{ + jschar buf[10], *start; + Class *clasp; + JSAtom *atom; + JS_STATIC_ASSERT((jsuint)-1 == 4294967295U); + + JS_ASSERT(index > JSID_INT_MAX); + + start = JS_ARRAY_END(buf); + do { + --start; + *start = (jschar)('0' + index % 10); + index /= 10; + } while (index != 0); + + /* + * Skip the atomization if the class is known to store atoms corresponding + * to big indexes together with elements. In such case we know that the + * array does not have an element at the given index if its atom does not + * exist. Fast arrays (clasp == &js_ArrayClass) don't use atoms for + * any indexes, though it would be rare to see them have a big index + * in any case. + */ + if (!createAtom && + ((clasp = obj->getClass()) == &js_SlowArrayClass || + clasp == &js_ArgumentsClass || + clasp == &js_ObjectClass)) { + atom = js_GetExistingStringAtom(cx, start, JS_ARRAY_END(buf) - start); + if (!atom) { + *idp = JSID_VOID; + return JS_TRUE; + } + } else { + atom = js_AtomizeChars(cx, start, JS_ARRAY_END(buf) - start, 0); + if (!atom) + return JS_FALSE; + } + + *idp = ATOM_TO_JSID(atom); + return JS_TRUE; +} + +bool +JSObject::willBeSparseDenseArray(uintN requiredCapacity, uintN newElementsHint) +{ + JS_ASSERT(isDenseArray()); + JS_ASSERT(requiredCapacity > MIN_SPARSE_INDEX); + + uintN cap = numSlots(); + JS_ASSERT(requiredCapacity >= cap); + + if (requiredCapacity >= JSObject::NSLOTS_LIMIT) + return true; + + uintN minimalDenseCount = requiredCapacity / 4; + if (newElementsHint >= minimalDenseCount) + return false; + minimalDenseCount -= newElementsHint; + + if (minimalDenseCount > cap) + return true; + + Value *elems = getDenseArrayElements(); + for (uintN i = 0; i < cap; i++) { + if (!elems[i].isMagic(JS_ARRAY_HOLE) && !--minimalDenseCount) + return false; + } + return true; +} + +static bool +ReallyBigIndexToId(JSContext* cx, jsdouble index, jsid* idp) +{ + return js_ValueToStringId(cx, DoubleValue(index), idp); +} + +static bool +IndexToId(JSContext* cx, JSObject* obj, jsdouble index, JSBool* hole, jsid* idp, + JSBool createAtom = JS_FALSE) +{ + if (index <= JSID_INT_MAX) { + *idp = INT_TO_JSID(int(index)); + return JS_TRUE; + } + + if (index <= jsuint(-1)) { + if (!BigIndexToId(cx, obj, jsuint(index), createAtom, idp)) + return JS_FALSE; + if (hole && JSID_IS_VOID(*idp)) + *hole = JS_TRUE; + return JS_TRUE; + } + + return ReallyBigIndexToId(cx, index, idp); +} + +/* + * If the property at the given index exists, get its value into location + * pointed by vp and set *hole to false. Otherwise set *hole to true and *vp + * to JSVAL_VOID. This function assumes that the location pointed by vp is + * properly rooted and can be used as GC-protected storage for temporaries. + */ +static JSBool +GetElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, Value *vp) +{ + JS_ASSERT(index >= 0); + if (obj->isDenseArray() && index < obj->getDenseArrayCapacity() && + !(*vp = obj->getDenseArrayElement(uint32(index))).isMagic(JS_ARRAY_HOLE)) { + *hole = JS_FALSE; + return JS_TRUE; + } + if (obj->isArguments() && + index < obj->getArgsInitialLength() && + !(*vp = obj->getArgsElement(uint32(index))).isMagic(JS_ARGS_HOLE)) { + *hole = JS_FALSE; + JSStackFrame *fp = (JSStackFrame *)obj->getPrivate(); + if (fp != JS_ARGUMENTS_OBJECT_ON_TRACE) { + if (fp) + *vp = fp->canonicalActualArg(index); + return JS_TRUE; + } + } + + AutoIdRooter idr(cx); + + *hole = JS_FALSE; + if (!IndexToId(cx, obj, index, hole, idr.addr())) + return JS_FALSE; + if (*hole) { + vp->setUndefined(); + return JS_TRUE; + } + + JSObject *obj2; + JSProperty *prop; + if (!obj->lookupProperty(cx, idr.id(), &obj2, &prop)) + return JS_FALSE; + if (!prop) { + *hole = JS_TRUE; + vp->setUndefined(); + } else { + if (!obj->getProperty(cx, idr.id(), vp)) + return JS_FALSE; + *hole = JS_FALSE; + } + return JS_TRUE; +} + +namespace js { + +bool +GetElements(JSContext *cx, JSObject *aobj, jsuint length, Value *vp) +{ + if (aobj->isDenseArray() && length <= aobj->getDenseArrayCapacity() && + !js_PrototypeHasIndexedProperties(cx, aobj)) { + /* The prototype does not have indexed properties so hole = undefined */ + Value *srcbeg = aobj->getDenseArrayElements(); + Value *srcend = srcbeg + length; + for (Value *dst = vp, *src = srcbeg; src < srcend; ++dst, ++src) + *dst = src->isMagic(JS_ARRAY_HOLE) ? UndefinedValue() : *src; + } else if (aobj->isArguments() && !aobj->isArgsLengthOverridden() && + !js_PrototypeHasIndexedProperties(cx, aobj)) { + /* + * Two cases, two loops: note how in the case of an active stack frame + * backing aobj, even though we copy from fp->argv, we still must check + * aobj->getArgsElement(i) for a hole, to handle a delete on the + * corresponding arguments element. See args_delProperty. + */ + if (JSStackFrame *fp = (JSStackFrame *) aobj->getPrivate()) { + JS_ASSERT(fp->numActualArgs() <= JS_ARGS_LENGTH_MAX); + fp->forEachCanonicalActualArg(CopyNonHoleArgsTo(aobj, vp)); + } else { + Value *srcbeg = aobj->getArgsElements(); + Value *srcend = srcbeg + length; + for (Value *dst = vp, *src = srcbeg; src < srcend; ++dst, ++src) + *dst = src->isMagic(JS_ARGS_HOLE) ? UndefinedValue() : *src; + } + } else { + for (uintN i = 0; i < length; i++) { + if (!aobj->getProperty(cx, INT_TO_JSID(jsint(i)), &vp[i])) + return JS_FALSE; + } + } + + return true; +} + +} + +/* + * Set the value of the property at the given index to v assuming v is rooted. + */ +static JSBool +SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, const Value &v) +{ + JS_ASSERT(index >= 0); + + if (obj->isDenseArray()) { + /* Predicted/prefetched code should favor the remains-dense case. */ + JSObject::EnsureDenseResult result = JSObject::ED_SPARSE; + do { + if (index > jsuint(-1)) + break; + jsuint idx = jsuint(index); + result = obj->ensureDenseArrayElements(cx, idx, 1); + if (result != JSObject::ED_OK) + break; + if (idx >= obj->getArrayLength()) + obj->setArrayLength(idx + 1); + obj->setDenseArrayElement(idx, v); + return true; + } while (false); + + if (result == JSObject::ED_FAILED) + return false; + JS_ASSERT(result == JSObject::ED_SPARSE); + if (!obj->makeDenseArraySlow(cx)) + return JS_FALSE; + } + + AutoIdRooter idr(cx); + + if (!IndexToId(cx, obj, index, NULL, idr.addr(), JS_TRUE)) + return JS_FALSE; + JS_ASSERT(!JSID_IS_VOID(idr.id())); + + Value tmp = v; + return obj->setProperty(cx, idr.id(), &tmp, true); +} + +#ifdef JS_TRACER +JSBool JS_FASTCALL +js_EnsureDenseArrayCapacity(JSContext *cx, JSObject *obj, jsint i) +{ +#ifdef DEBUG + Class *origObjClasp = obj->clasp; +#endif + jsuint u = jsuint(i); + JSBool ret = (obj->ensureDenseArrayElements(cx, u, 1) == JSObject::ED_OK); + + /* Partially check the CallInfo's storeAccSet is correct. */ + JS_ASSERT(obj->clasp == origObjClasp); + return ret; +} +/* This function and its callees do not touch any object's .clasp field. */ +JS_DEFINE_CALLINFO_3(extern, BOOL, js_EnsureDenseArrayCapacity, CONTEXT, OBJECT, INT32, + 0, nanojit::ACCSET_STORE_ANY & ~tjit::ACCSET_OBJ_CLASP) +#endif + +/* + * Delete the element |index| from |obj|. If |strict|, do a strict + * deletion: throw if the property is not configurable. + * + * - Return 1 if the deletion succeeds (that is, ES5's [[Delete]] would + * return true) + * + * - Return 0 if the deletion fails because the property is not + * configurable (that is, [[Delete]] would return false). Note that if + * |strict| is true we will throw, not return zero. + * + * - Return -1 if an exception occurs (that is, [[Delete]] would throw). + */ +static int +DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index, bool strict) +{ + JS_ASSERT(index >= 0); + if (obj->isDenseArray()) { + if (index <= jsuint(-1)) { + jsuint idx = jsuint(index); + if (idx < obj->getDenseArrayCapacity()) { + obj->setDenseArrayElement(idx, MagicValue(JS_ARRAY_HOLE)); + if (!js_SuppressDeletedIndexProperties(cx, obj, idx, idx+1)) + return -1; + } + } + return 1; + } + + AutoIdRooter idr(cx); + + if (!IndexToId(cx, obj, index, NULL, idr.addr())) + return -1; + if (JSID_IS_VOID(idr.id())) + return 1; + + Value v; + if (!obj->deleteProperty(cx, idr.id(), &v, strict)) + return -1; + return v.isTrue() ? 1 : 0; +} + +/* + * When hole is true, delete the property at the given index. Otherwise set + * its value to v assuming v is rooted. + */ +static JSBool +SetOrDeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index, + JSBool hole, const Value &v) +{ + if (hole) { + JS_ASSERT(v.isUndefined()); + return DeleteArrayElement(cx, obj, index, true) >= 0; + } + return SetArrayElement(cx, obj, index, v); +} + +JSBool +js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length) +{ + Value v; + jsid id; + + v.setNumber(length); + id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); + /* We don't support read-only array length yet. */ + return obj->setProperty(cx, id, &v, false); +} + +JSBool +js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) +{ + JSErrorReporter older = JS_SetErrorReporter(cx, NULL); + AutoValueRooter tvr(cx); + jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); + JSBool ok = obj->getProperty(cx, id, tvr.addr()); + JS_SetErrorReporter(cx, older); + if (!ok) + return false; + + if (!ValueToLength(cx, tvr.addr(), lengthp)) + return false; + + return true; +} + +/* + * Since SpiderMonkey supports cross-class prototype-based delegation, we have + * to be careful about the length getter and setter being called on an object + * not of Array class. For the getter, we search obj's prototype chain for the + * array that caused this getter to be invoked. In the setter case to overcome + * the JSPROP_SHARED attribute, we must define a shadowing length property. + */ +static JSBool +array_length_getter(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + do { + if (obj->isArray()) { + vp->setNumber(obj->getArrayLength()); + return JS_TRUE; + } + } while ((obj = obj->getProto()) != NULL); + return JS_TRUE; +} + +static JSBool +array_length_setter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) +{ + jsuint newlen, oldlen, gap, index; + Value junk; + + if (!obj->isArray()) { + jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); + + return obj->defineProperty(cx, lengthId, *vp, NULL, NULL, JSPROP_ENUMERATE); + } + + if (!ValueToLength(cx, vp, &newlen)) + return false; + + oldlen = obj->getArrayLength(); + + if (oldlen == newlen) + return true; + + vp->setNumber(newlen); + if (oldlen < newlen) { + obj->setArrayLength(newlen); + return true; + } + + if (obj->isDenseArray()) { + /* + * Don't reallocate if we're not actually shrinking our slots. If we do + * shrink slots here, ensureDenseArrayElements will fill all slots to the + * right of newlen with JS_ARRAY_HOLE. This permits us to disregard + * length when reading from arrays as long we are within the capacity. + */ + jsuint oldcap = obj->getDenseArrayCapacity(); + if (oldcap > newlen) + obj->shrinkDenseArrayElements(cx, newlen); + obj->setArrayLength(newlen); + } else if (oldlen - newlen < (1 << 24)) { + do { + --oldlen; + if (!JS_CHECK_OPERATION_LIMIT(cx)) { + obj->setArrayLength(oldlen + 1); + return false; + } + int deletion = DeleteArrayElement(cx, obj, oldlen, strict); + if (deletion <= 0) { + obj->setArrayLength(oldlen + 1); + return deletion >= 0; + } + } while (oldlen != newlen); + obj->setArrayLength(newlen); + } else { + /* + * We are going to remove a lot of indexes in a presumably sparse + * array. So instead of looping through indexes between newlen and + * oldlen, we iterate through all properties and remove those that + * correspond to indexes in the half-open range [newlen, oldlen). See + * bug 322135. + */ + JSObject *iter = JS_NewPropertyIterator(cx, obj); + if (!iter) + return false; + + /* Protect iter against GC under JSObject::deleteProperty. */ + AutoObjectRooter tvr(cx, iter); + + gap = oldlen - newlen; + for (;;) { + if (!JS_CHECK_OPERATION_LIMIT(cx) || !JS_NextProperty(cx, iter, &id)) + return false; + if (JSID_IS_VOID(id)) + break; + if (js_IdIsIndex(id, &index) && index - newlen < gap && + !obj->deleteProperty(cx, id, &junk, false)) { + return false; + } + } + obj->setArrayLength(newlen); + } + + return true; +} + +/* + * We have only indexed properties up to capacity (excepting holes), plus the + * length property. For all else, we delegate to the prototype. + */ +static inline bool +IsDenseArrayId(JSContext *cx, JSObject *obj, jsid id) +{ + JS_ASSERT(obj->isDenseArray()); + + uint32 i; + return JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) || + (js_IdIsIndex(id, &i) && + obj->getArrayLength() != 0 && + i < obj->getDenseArrayCapacity() && + !obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)); +} + +static JSBool +array_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + JSProperty **propp) +{ + if (!obj->isDenseArray()) + return js_LookupProperty(cx, obj, id, objp, propp); + + if (IsDenseArrayId(cx, obj, id)) { + *propp = (JSProperty *) 1; /* non-null to indicate found */ + *objp = obj; + return JS_TRUE; + } + + JSObject *proto = obj->getProto(); + if (!proto) { + *objp = NULL; + *propp = NULL; + return JS_TRUE; + } + return proto->lookupProperty(cx, id, objp, propp); +} + +JSBool +js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + JS_ASSERT(obj->isDenseArray()); + + uint32 i; + if (!js_IdIsIndex(id, &i)) { + JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)); + vp->setNumber(obj->getArrayLength()); + return JS_TRUE; + } + *vp = obj->getDenseArrayElement(i); + return JS_TRUE; +} + +static JSBool +array_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp) +{ + uint32 i; + + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + vp->setNumber(obj->getArrayLength()); + return JS_TRUE; + } + + if (JSID_IS_ATOM(id, cx->runtime->atomState.protoAtom)) { + vp->setObjectOrNull(obj->getProto()); + return JS_TRUE; + } + + if (!obj->isDenseArray()) + return js_GetProperty(cx, obj, id, vp); + + if (!js_IdIsIndex(id, &i) || i >= obj->getDenseArrayCapacity() || + obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) { + JSObject *obj2; + JSProperty *prop; + const Shape *shape; + + JSObject *proto = obj->getProto(); + if (!proto) { + vp->setUndefined(); + return JS_TRUE; + } + + vp->setUndefined(); + if (js_LookupPropertyWithFlags(cx, proto, id, cx->resolveFlags, + &obj2, &prop) < 0) + return JS_FALSE; + + if (prop && obj2->isNative()) { + shape = (const Shape *) prop; + if (!js_NativeGet(cx, obj, obj2, shape, JSGET_METHOD_BARRIER, vp)) + return JS_FALSE; + } + return JS_TRUE; + } + + *vp = obj->getDenseArrayElement(i); + return JS_TRUE; +} + +static JSBool +slowarray_addProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + jsuint index, length; + + if (!js_IdIsIndex(id, &index)) + return JS_TRUE; + length = obj->getArrayLength(); + if (index >= length) + obj->setArrayLength(index + 1); + return JS_TRUE; +} + +static JSType +array_typeOf(JSContext *cx, JSObject *obj) +{ + return JSTYPE_OBJECT; +} + +static JSBool +array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) +{ + uint32 i; + + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) + return array_length_setter(cx, obj, id, strict, vp); + + if (!obj->isDenseArray()) + return js_SetProperty(cx, obj, id, vp, strict); + + do { + if (!js_IdIsIndex(id, &i)) + break; + if (js_PrototypeHasIndexedProperties(cx, obj)) + break; + + JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, i, 1); + if (result != JSObject::ED_OK) { + if (result == JSObject::ED_FAILED) + return false; + JS_ASSERT(result == JSObject::ED_SPARSE); + break; + } + + if (i >= obj->getArrayLength()) + obj->setArrayLength(i + 1); + obj->setDenseArrayElement(i, *vp); + return true; + } while (false); + + if (!obj->makeDenseArraySlow(cx)) + return false; + return js_SetProperty(cx, obj, id, vp, strict); +} + +JSBool +js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj) +{ + /* + * Walk up the prototype chain and see if this indexed element already + * exists. If we hit the end of the prototype chain, it's safe to set the + * element on the original object. + */ + while ((obj = obj->getProto()) != NULL) { + /* + * If the prototype is a non-native object (possibly a dense array), or + * a native object (possibly a slow array) that has indexed properties, + * return true. + */ + if (!obj->isNative()) + return JS_TRUE; + if (obj->isIndexed()) + return JS_TRUE; + } + return JS_FALSE; +} + +static JSBool +array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value, + PropertyOp getter, StrictPropertyOp setter, uintN attrs) +{ + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) + return JS_TRUE; + + if (!obj->isDenseArray()) + return js_DefineProperty(cx, obj, id, value, getter, setter, attrs); + + do { + uint32 i = 0; // init to shut GCC up + bool isIndex = js_IdIsIndex(id, &i); + if (!isIndex || attrs != JSPROP_ENUMERATE) + break; + + JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, i, 1); + if (result != JSObject::ED_OK) { + if (result == JSObject::ED_FAILED) + return false; + JS_ASSERT(result == JSObject::ED_SPARSE); + break; + } + + if (i >= obj->getArrayLength()) + obj->setArrayLength(i + 1); + obj->setDenseArrayElement(i, *value); + return true; + } while (false); + + if (!obj->makeDenseArraySlow(cx)) + return false; + return js_DefineProperty(cx, obj, id, value, getter, setter, attrs); +} + +static JSBool +array_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +{ + *attrsp = JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) + ? JSPROP_PERMANENT : JSPROP_ENUMERATE; + return JS_TRUE; +} + +static JSBool +array_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_SET_ARRAY_ATTRS); + return JS_FALSE; +} + +static JSBool +array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) +{ + uint32 i; + + if (!obj->isDenseArray()) + return js_DeleteProperty(cx, obj, id, rval, strict); + + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + rval->setBoolean(false); + return JS_TRUE; + } + + if (js_IdIsIndex(id, &i) && i < obj->getDenseArrayCapacity()) + obj->setDenseArrayElement(i, MagicValue(JS_ARRAY_HOLE)); + + if (!js_SuppressDeletedProperty(cx, obj, id)) + return false; + + rval->setBoolean(true); + return JS_TRUE; +} + +static void +array_trace(JSTracer *trc, JSObject *obj) +{ + JS_ASSERT(obj->isDenseArray()); + + uint32 capacity = obj->getDenseArrayCapacity(); + for (uint32 i = 0; i < capacity; i++) + MarkValue(trc, obj->getDenseArrayElement(i), "dense_array_elems"); +} + +static JSBool +array_fix(JSContext *cx, JSObject *obj, bool *success, AutoIdVector *props) +{ + JS_ASSERT(obj->isDenseArray()); + + /* + * We must slowify dense arrays; otherwise, we'd need to detect assignments to holes, + * since that is effectively adding a new property to the array. + */ + if (!obj->makeDenseArraySlow(cx) || + !GetPropertyNames(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, props)) + return false; + + *success = true; + return true; +} + +Class js_ArrayClass = { + "Array", + Class::NON_NATIVE | + JSCLASS_HAS_PRIVATE | + JSCLASS_HAS_CACHED_PROTO(JSProto_Array), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + js_TryValueOf, + NULL, + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + NULL, /* mark */ + JS_NULL_CLASS_EXT, + { + array_lookupProperty, + array_defineProperty, + array_getProperty, + array_setProperty, + array_getAttributes, + array_setAttributes, + array_deleteProperty, + NULL, /* enumerate */ + array_typeOf, + array_trace, + array_fix, + NULL, /* thisObject */ + NULL, /* clear */ + } +}; + +Class js_SlowArrayClass = { + "Array", + JSCLASS_HAS_PRIVATE | + JSCLASS_HAS_CACHED_PROTO(JSProto_Array), + slowarray_addProperty, + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + js_TryValueOf +}; + +static bool +AddLengthProperty(JSContext *cx, JSObject *obj) +{ + const jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); + JS_ASSERT(!obj->nativeLookup(lengthId)); + + return obj->addProperty(cx, lengthId, array_length_getter, array_length_setter, + SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0); +} + +/* + * Convert an array object from fast-and-dense to slow-and-flexible. + */ +JSBool +JSObject::makeDenseArraySlow(JSContext *cx) +{ + JS_ASSERT(isDenseArray()); + + /* + * Save old map now, before calling InitScopeForObject. We'll have to undo + * on error. This is gross, but a better way is not obvious. + */ + JSObjectMap *oldMap = map; + + /* Create a native scope. */ + JSObject *arrayProto = getProto(); + js::gc::FinalizeKind kind = js::gc::FinalizeKind(arena()->header()->thingKind); + if (!InitScopeForObject(cx, this, &js_SlowArrayClass, arrayProto, kind)) + return false; + + uint32 capacity = getDenseArrayCapacity(); + + /* + * Begin with the length property to share more of the property tree. + * The getter/setter here will directly access the object's private value. + */ + if (!AddLengthProperty(cx, this)) { + setMap(oldMap); + return false; + } + + /* + * Create new properties pointing to existing elements. Pack the array to + * remove holes, so that shapes use successive slots (as for other objects). + */ + uint32 next = 0; + for (uint32 i = 0; i < capacity; i++) { + jsid id; + if (!ValueToId(cx, Int32Value(i), &id)) { + setMap(oldMap); + return false; + } + + if (getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) + continue; + + setDenseArrayElement(next, getDenseArrayElement(i)); + + if (!addDataProperty(cx, id, next, JSPROP_ENUMERATE)) { + setMap(oldMap); + return false; + } + + next++; + } + + /* + * Dense arrays with different numbers of slots but the same number of fixed + * slots and the same non-hole indexes must use their fixed slots consistently. + */ + if (hasSlotsArray() && next <= numFixedSlots()) + revertToFixedSlots(cx); + + ClearValueRange(slots + next, this->capacity - next, false); + + /* + * Finally, update class. If |this| is Array.prototype, then js_InitClass + * will create an emptyShape whose class is &js_SlowArrayClass, to ensure + * that delegating instances can share shapes in the tree rooted at the + * proto's empty shape. + */ + clasp = &js_SlowArrayClass; + return true; +} + +/* Transfer ownership of buffer to returned string. */ +static inline JSBool +BufferToString(JSContext *cx, StringBuffer &sb, Value *rval) +{ + JSString *str = sb.finishString(); + if (!str) + return false; + rval->setString(str); + return true; +} + +#if JS_HAS_TOSOURCE +static JSBool +array_toSource(JSContext *cx, uintN argc, Value *vp) +{ + JS_CHECK_RECURSION(cx, return false); + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + if (!obj->isSlowArray() && !InstanceOf(cx, obj, &js_ArrayClass, vp + 2)) + return false; + + /* Find joins or cycles in the reachable object graph. */ + jschar *sharpchars; + JSHashEntry *he = js_EnterSharpObject(cx, obj, NULL, &sharpchars); + if (!he) + return false; + bool initiallySharp = IS_SHARP(he); + + /* After this point, all paths exit through the 'out' label. */ + MUST_FLOW_THROUGH("out"); + bool ok = false; + + /* + * This object will take responsibility for the jschar buffer until the + * buffer is transferred to the returned JSString. + */ + StringBuffer sb(cx); + + /* Cycles/joins are indicated by sharp objects. */ +#if JS_HAS_SHARP_VARS + if (IS_SHARP(he)) { + JS_ASSERT(sharpchars != 0); + sb.replaceRawBuffer(sharpchars, js_strlen(sharpchars)); + goto make_string; + } else if (sharpchars) { + MAKE_SHARP(he); + sb.replaceRawBuffer(sharpchars, js_strlen(sharpchars)); + } +#else + if (IS_SHARP(he)) { + if (!sb.append("[]")) + goto out; + cx->free(sharpchars); + goto make_string; + } +#endif + + if (!sb.append('[')) + goto out; + + jsuint length; + if (!js_GetLengthProperty(cx, obj, &length)) + goto out; + + for (jsuint index = 0; index < length; index++) { + /* Use vp to locally root each element value. */ + JSBool hole; + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !GetElement(cx, obj, index, &hole, vp)) { + goto out; + } + + /* Get element's character string. */ + JSString *str; + if (hole) { + str = cx->runtime->emptyString; + } else { + str = js_ValueToSource(cx, *vp); + if (!str) + goto out; + } + vp->setString(str); + + const jschar *chars = str->getChars(cx); + if (!chars) + goto out; + + /* Append element to buffer. */ + if (!sb.append(chars, chars + str->length())) + goto out; + if (index + 1 != length) { + if (!sb.append(", ")) + goto out; + } else if (hole) { + if (!sb.append(',')) + goto out; + } + } + + /* Finalize the buffer. */ + if (!sb.append(']')) + goto out; + + make_string: + if (!BufferToString(cx, sb, vp)) + goto out; + + ok = true; + + out: + if (!initiallySharp) + js_LeaveSharpObject(cx, NULL); + return ok; +} +#endif + +static JSBool +array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale, + JSString *sepstr, Value *rval) +{ + JS_CHECK_RECURSION(cx, return false); + + /* Get characters to use for the separator. */ + static const jschar comma = ','; + const jschar *sep; + size_t seplen; + if (sepstr) { + seplen = sepstr->length(); + sep = sepstr->getChars(cx); + if (!sep) + return false; + } else { + sep = , + seplen = 1; + } + + /* + * Use HashTable entry as the cycle indicator. On first visit, create the + * entry, and, when leaving, remove the entry. + */ + BusyArraysMap::AddPtr hashp = cx->busyArrays.lookupForAdd(obj); + uint32 genBefore; + if (!hashp) { + /* Not in hash table, so not a cycle. */ + if (!cx->busyArrays.add(hashp, obj)) + return false; + genBefore = cx->busyArrays.generation(); + } else { + /* Cycle, so return empty string. */ + rval->setString(ATOM_TO_STRING(cx->runtime->atomState.emptyAtom)); + return true; + } + + AutoObjectRooter tvr(cx, obj); + + /* After this point, all paths exit through the 'out' label. */ + MUST_FLOW_THROUGH("out"); + bool ok = false; + + /* + * This object will take responsibility for the jschar buffer until the + * buffer is transferred to the returned JSString. + */ + StringBuffer sb(cx); + + jsuint length; + if (!js_GetLengthProperty(cx, obj, &length)) + goto out; + + for (jsuint index = 0; index < length; index++) { + /* Use rval to locally root each element value. */ + JSBool hole; + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !GetElement(cx, obj, index, &hole, rval)) { + goto out; + } + + /* Get element's character string. */ + if (!(hole || rval->isNullOrUndefined())) { + if (locale) { + /* Work on obj.toLocalString() instead. */ + JSObject *robj; + + if (!js_ValueToObjectOrNull(cx, *rval, &robj)) + goto out; + rval->setObjectOrNull(robj); + JSAtom *atom = cx->runtime->atomState.toLocaleStringAtom; + if (!js_TryMethod(cx, robj, atom, 0, NULL, rval)) + goto out; + } + + if (!ValueToStringBuffer(cx, *rval, sb)) + goto out; + } + + /* Append the separator. */ + if (index + 1 != length) { + if (!sb.append(sep, seplen)) + goto out; + } + } + + /* Finalize the buffer. */ + if (!BufferToString(cx, sb, rval)) + goto out; + + ok = true; + + out: + if (genBefore == cx->busyArrays.generation()) + cx->busyArrays.remove(hashp); + else + cx->busyArrays.remove(obj); + return ok; +} + +/* ES5 15.4.4.2. NB: The algorithm here differs from the one in ES3. */ +static JSBool +array_toString(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + Value &join = vp[0]; + if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.joinAtom), &join)) + return false; + + if (!js_IsCallable(join)) { + JSString *str = obj_toStringHelper(cx, obj); + if (!str) + return false; + vp->setString(str); + return true; + } + + LeaveTrace(cx); + InvokeArgsGuard args; + if (!cx->stack().pushInvokeArgs(cx, 0, &args)) + return false; + + args.callee() = join; + args.thisv().setObject(*obj); + + /* Do the call. */ + if (!Invoke(cx, args, 0)) + return false; + *vp = args.rval(); + return true; +} + +static JSBool +array_toLocaleString(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + /* + * Passing comma here as the separator. Need a way to get a + * locale-specific version. + */ + return array_toString_sub(cx, obj, JS_TRUE, NULL, vp); +} + +static JSBool +InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, Value *vector) +{ + JS_ASSERT(count < MAXINDEX); + + /* + * Optimize for dense arrays so long as adding the given set of elements + * wouldn't otherwise make the array slow. + */ + do { + if (!obj->isDenseArray()) + break; + if (js_PrototypeHasIndexedProperties(cx, obj)) + break; + + JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, start, count); + if (result != JSObject::ED_OK) { + if (result == JSObject::ED_FAILED) + return false; + JS_ASSERT(result == JSObject::ED_SPARSE); + break; + } + jsuint newlen = start + count; + if (newlen > obj->getArrayLength()) + obj->setArrayLength(newlen); + + JS_ASSERT(count < uint32(-1) / sizeof(Value)); + memcpy(obj->getDenseArrayElements() + start, vector, sizeof(jsval) * count); + JS_ASSERT_IF(count != 0, !obj->getDenseArrayElement(newlen - 1).isMagic(JS_ARRAY_HOLE)); + return true; + } while (false); + + Value* end = vector + count; + while (vector != end && start < MAXINDEX) { + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !SetArrayElement(cx, obj, start++, *vector++)) { + return JS_FALSE; + } + } + + if (vector == end) + return JS_TRUE; + + /* Finish out any remaining elements past the max array index. */ + if (obj->isDenseArray() && !ENSURE_SLOW_ARRAY(cx, obj)) + return JS_FALSE; + + JS_ASSERT(start == MAXINDEX); + AutoValueRooter tvr(cx); + AutoIdRooter idr(cx); + Value idval = DoubleValue(MAXINDEX); + do { + *tvr.addr() = *vector++; + if (!js_ValueToStringId(cx, idval, idr.addr()) || + !obj->setProperty(cx, idr.id(), tvr.addr(), true)) { + return JS_FALSE; + } + idval.getDoubleRef() += 1; + } while (vector != end); + + return JS_TRUE; +} + +static JSBool +InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector) +{ + JS_ASSERT(obj->isArray()); + + JS_ASSERT(obj->isDenseArray()); + obj->setArrayLength(length); + if (!vector || !length) + return true; + + /* Avoid ensureDenseArrayElements to skip sparse array checks there. */ + if (!obj->ensureSlots(cx, length)) + return false; + memcpy(obj->getDenseArrayElements(), vector, length * sizeof(Value)); + return true; +} + +/* + * Perl-inspired join, reverse, and sort. + */ +static JSBool +array_join(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str; + if (argc == 0 || vp[2].isUndefined()) { + str = NULL; + } else { + str = js_ValueToString(cx, vp[2]); + if (!str) + return JS_FALSE; + vp[2].setString(str); + } + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + return array_toString_sub(cx, obj, JS_FALSE, str, vp); +} + +static JSBool +array_reverse(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + jsuint len; + if (!js_GetLengthProperty(cx, obj, &len)) + return false; + vp->setObject(*obj); + + do { + if (!obj->isDenseArray()) + break; + if (js_PrototypeHasIndexedProperties(cx, obj)) + break; + + /* An empty array or an array with no elements is already reversed. */ + if (len == 0 || obj->getDenseArrayCapacity() == 0) + return true; + + /* + * It's actually surprisingly complicated to reverse an array due to the + * orthogonality of array length and array capacity while handling + * leading and trailing holes correctly. Reversing seems less likely to + * be a common operation than other array mass-mutation methods, so for + * now just take a probably-small memory hit (in the absence of too many + * holes in the array at its start) and ensure that the capacity is + * sufficient to hold all the elements in the array if it were full. + */ + JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, len, 0); + if (result != JSObject::ED_OK) { + if (result == JSObject::ED_FAILED) + return false; + JS_ASSERT(result == JSObject::ED_SPARSE); + break; + } + + uint32 lo = 0, hi = len - 1; + for (; lo < hi; lo++, hi--) { + Value origlo = obj->getDenseArrayElement(lo); + Value orighi = obj->getDenseArrayElement(hi); + obj->setDenseArrayElement(lo, orighi); + if (orighi.isMagic(JS_ARRAY_HOLE) && + !js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(lo))) { + return false; + } + obj->setDenseArrayElement(hi, origlo); + if (origlo.isMagic(JS_ARRAY_HOLE) && + !js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(hi))) { + return false; + } + } + + /* + * Per ECMA-262, don't update the length of the array, even if the new + * array has trailing holes (and thus the original array began with + * holes). + */ + return true; + } while (false); + + AutoValueRooter tvr(cx); + for (jsuint i = 0, half = len / 2; i < half; i++) { + JSBool hole, hole2; + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !GetElement(cx, obj, i, &hole, tvr.addr()) || + !GetElement(cx, obj, len - i - 1, &hole2, vp) || + !SetOrDeleteArrayElement(cx, obj, len - i - 1, hole, tvr.value()) || + !SetOrDeleteArrayElement(cx, obj, i, hole2, *vp)) { + return false; + } + } + vp->setObject(*obj); + return true; +} + +typedef struct MSortArgs { + size_t elsize; + JSComparator cmp; + void *arg; + JSBool isValue; +} MSortArgs; + +/* Helper function for js_MergeSort. */ +static JSBool +MergeArrays(MSortArgs *msa, void *src, void *dest, size_t run1, size_t run2) +{ + void *arg, *a, *b, *c; + size_t elsize, runtotal; + int cmp_result; + JSComparator cmp; + JSBool isValue; + + runtotal = run1 + run2; + + elsize = msa->elsize; + cmp = msa->cmp; + arg = msa->arg; + isValue = msa->isValue; + +#define CALL_CMP(a, b) \ + if (!cmp(arg, (a), (b), &cmp_result)) return JS_FALSE; + + /* Copy runs already in sorted order. */ + b = (char *)src + run1 * elsize; + a = (char *)b - elsize; + CALL_CMP(a, b); + if (cmp_result <= 0) { + memcpy(dest, src, runtotal * elsize); + return JS_TRUE; + } + +#define COPY_ONE(p,q,n) \ + (isValue ? (void)(*(Value*)p = *(Value*)q) : (void)memcpy(p, q, n)) + + a = src; + c = dest; + for (; runtotal != 0; runtotal--) { + JSBool from_a = run2 == 0; + if (!from_a && run1 != 0) { + CALL_CMP(a,b); + from_a = cmp_result <= 0; + } + + if (from_a) { + COPY_ONE(c, a, elsize); + run1--; + a = (char *)a + elsize; + } else { + COPY_ONE(c, b, elsize); + run2--; + b = (char *)b + elsize; + } + c = (char *)c + elsize; + } +#undef COPY_ONE +#undef CALL_CMP + + return JS_TRUE; +} + +/* + * This sort is stable, i.e. sequence of equal elements is preserved. + * See also bug #224128. + */ +bool +js_MergeSort(void *src, size_t nel, size_t elsize, + JSComparator cmp, void *arg, void *tmp, + JSMergeSortElemType elemType) +{ + void *swap, *vec1, *vec2; + MSortArgs msa; + size_t i, j, lo, hi, run; + int cmp_result; + + JS_ASSERT_IF(JS_SORTING_VALUES, elsize == sizeof(Value)); + bool isValue = elemType == JS_SORTING_VALUES; + + /* Avoid memcpy overhead for word-sized and word-aligned elements. */ +#define COPY_ONE(p,q,n) \ + (isValue ? (void)(*(Value*)p = *(Value*)q) : (void)memcpy(p, q, n)) +#define CALL_CMP(a, b) \ + if (!cmp(arg, (a), (b), &cmp_result)) return JS_FALSE; +#define INS_SORT_INT 4 + + /* + * Apply insertion sort to small chunks to reduce the number of merge + * passes needed. + */ + for (lo = 0; lo < nel; lo += INS_SORT_INT) { + hi = lo + INS_SORT_INT; + if (hi >= nel) + hi = nel; + for (i = lo + 1; i < hi; i++) { + vec1 = (char *)src + i * elsize; + vec2 = (char *)vec1 - elsize; + for (j = i; j > lo; j--) { + CALL_CMP(vec2, vec1); + /* "<=" instead of "<" insures the sort is stable */ + if (cmp_result <= 0) { + break; + } + + /* Swap elements, using "tmp" as tmp storage */ + COPY_ONE(tmp, vec2, elsize); + COPY_ONE(vec2, vec1, elsize); + COPY_ONE(vec1, tmp, elsize); + vec1 = vec2; + vec2 = (char *)vec1 - elsize; + } + } + } +#undef CALL_CMP +#undef COPY_ONE + + msa.elsize = elsize; + msa.cmp = cmp; + msa.arg = arg; + msa.isValue = isValue; + + vec1 = src; + vec2 = tmp; + for (run = INS_SORT_INT; run < nel; run *= 2) { + for (lo = 0; lo < nel; lo += 2 * run) { + hi = lo + run; + if (hi >= nel) { + memcpy((char *)vec2 + lo * elsize, (char *)vec1 + lo * elsize, + (nel - lo) * elsize); + break; + } + if (!MergeArrays(&msa, (char *)vec1 + lo * elsize, + (char *)vec2 + lo * elsize, run, + hi + run > nel ? nel - hi : run)) { + return JS_FALSE; + } + } + swap = vec1; + vec1 = vec2; + vec2 = swap; + } + if (src != vec1) + memcpy(src, tmp, nel * elsize); + + return JS_TRUE; +} + +struct CompareArgs +{ + JSContext *context; + InvokeSessionGuard session; + + CompareArgs(JSContext *cx) + : context(cx) + {} +}; + +static JS_REQUIRES_STACK JSBool +sort_compare(void *arg, const void *a, const void *b, int *result) +{ + const Value *av = (const Value *)a, *bv = (const Value *)b; + CompareArgs *ca = (CompareArgs *) arg; + JSContext *cx = ca->context; + + /* + * array_sort deals with holes and undefs on its own and they should not + * come here. + */ + JS_ASSERT(!av->isMagic() && !av->isUndefined()); + JS_ASSERT(!av->isMagic() && !bv->isUndefined()); + + if (!JS_CHECK_OPERATION_LIMIT(cx)) + return JS_FALSE; + + InvokeSessionGuard &session = ca->session; + session[0] = *av; + session[1] = *bv; + + if (!session.invoke(cx)) + return JS_FALSE; + + jsdouble cmp; + if (!ValueToNumber(cx, session.rval(), &cmp)) + return JS_FALSE; + + /* Clamp cmp to -1, 0, 1. */ + *result = 0; + if (!JSDOUBLE_IS_NaN(cmp) && cmp != 0) + *result = cmp > 0 ? 1 : -1; + + /* + * XXX else report some kind of error here? ECMA talks about 'consistent + * compare functions' that don't return NaN, but is silent about what the + * result should be. So we currently ignore it. + */ + + return JS_TRUE; +} + +typedef JSBool (JS_REQUIRES_STACK *JSRedComparator)(void*, const void*, + const void*, int *); + +static inline JS_IGNORE_STACK JSComparator +comparator_stack_cast(JSRedComparator func) +{ + return func; +} + +static int +sort_compare_strings(void *arg, const void *a, const void *b, int *result) +{ + JSContext *cx = (JSContext *)arg; + JSString *astr = ((const Value *)a)->toString(); + JSString *bstr = ((const Value *)b)->toString(); + return JS_CHECK_OPERATION_LIMIT(cx) && CompareStrings(cx, astr, bstr, result); +} + +JSBool +js::array_sort(JSContext *cx, uintN argc, Value *vp) +{ + jsuint len, newlen, i, undefs; + size_t elemsize; + JSString *str; + + Value *argv = JS_ARGV(cx, vp); + Value fval; + if (argc > 0 && !argv[0].isUndefined()) { + if (argv[0].isPrimitive()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG); + return false; + } + fval = argv[0]; /* non-default compare function */ + } else { + fval.setNull(); + } + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + if (!js_GetLengthProperty(cx, obj, &len)) + return false; + if (len == 0) { + vp->setObject(*obj); + return true; + } + + /* + * We need a temporary array of 2 * len Value to hold the array elements + * and the scratch space for merge sort. Check that its size does not + * overflow size_t, which would allow for indexing beyond the end of the + * malloc'd vector. + */ +#if JS_BITS_PER_WORD == 32 + if (size_t(len) > size_t(-1) / (2 * sizeof(Value))) { + js_ReportAllocationOverflow(cx); + return false; + } +#endif + + /* + * Initialize vec as a root. We will clear elements of vec one by + * one while increasing the rooted amount of vec when we know that the + * property at the corresponding index exists and its value must be rooted. + * + * In this way when sorting a huge mostly sparse array we will not + * access the tail of vec corresponding to properties that do not + * exist, allowing OS to avoiding committing RAM. See bug 330812. + */ + { + Value *vec = (Value *) cx->malloc(2 * size_t(len) * sizeof(Value)); + if (!vec) + return false; + + DEFINE_LOCAL_CLASS_OF_STATIC_FUNCTION(AutoFreeVector) { + JSContext *const cx; + Value *&vec; + public: + AutoFreeVector(JSContext *cx, Value *&vec) : cx(cx), vec(vec) { } + ~AutoFreeVector() { + cx->free(vec); + } + } free(cx, vec); + + AutoArrayRooter tvr(cx, 0, vec); + + /* + * By ECMA 262, 15.4.4.11, a property that does not exist (which we + * call a "hole") is always greater than an existing property with + * value undefined and that is always greater than any other property. + * Thus to sort holes and undefs we simply count them, sort the rest + * of elements, append undefs after them and then make holes after + * undefs. + */ + undefs = 0; + newlen = 0; + bool allStrings = true; + for (i = 0; i < len; i++) { + if (!JS_CHECK_OPERATION_LIMIT(cx)) + return false; + + /* Clear vec[newlen] before including it in the rooted set. */ + JSBool hole; + vec[newlen].setNull(); + tvr.changeLength(newlen + 1); + if (!GetElement(cx, obj, i, &hole, &vec[newlen])) + return false; + + if (hole) + continue; + + if (vec[newlen].isUndefined()) { + ++undefs; + continue; + } + + allStrings = allStrings && vec[newlen].isString(); + + ++newlen; + } + + if (newlen == 0) { + vp->setObject(*obj); + return true; /* The array has only holes and undefs. */ + } + + /* + * The first newlen elements of vec are copied from the array object + * (above). The remaining newlen positions are used as GC-rooted scratch + * space for mergesort. We must clear the space before including it to + * the root set covered by tvr.count. + */ + Value *mergesort_tmp = vec + newlen; + MakeRangeGCSafe(mergesort_tmp, newlen); + tvr.changeLength(newlen * 2); + + /* Here len == 2 * (newlen + undefs + number_of_holes). */ + if (fval.isNull()) { + /* + * Sort using the default comparator converting all elements to + * strings. + */ + if (allStrings) { + elemsize = sizeof(Value); + } else { + /* + * To avoid string conversion on each compare we do it only once + * prior to sorting. But we also need the space for the original + * values to recover the sorting result. To reuse + * sort_compare_strings we move the original values to the odd + * indexes in vec, put the string conversion results in the even + * indexes and pass 2 * sizeof(Value) as an element size to the + * sorting function. In this way sort_compare_strings will only + * see the string values when it casts the compare arguments as + * pointers to Value. + * + * This requires doubling the temporary storage including the + * scratch space for the merge sort. Since vec already contains + * the rooted scratch space for newlen elements at the tail, we + * can use it to rearrange and convert to strings first and try + * realloc only when we know that we successfully converted all + * the elements. + */ +#if JS_BITS_PER_WORD == 32 + if (size_t(newlen) > size_t(-1) / (4 * sizeof(Value))) { + js_ReportAllocationOverflow(cx); + return false; + } +#endif + + /* + * Rearrange and string-convert the elements of the vector from + * the tail here and, after sorting, move the results back + * starting from the start to prevent overwrite the existing + * elements. + */ + i = newlen; + do { + --i; + if (!JS_CHECK_OPERATION_LIMIT(cx)) + return false; + const Value &v = vec[i]; + str = js_ValueToString(cx, v); + if (!str) + return false; + // Copying v must come first, because the following line overwrites v + // when i == 0. + vec[2 * i + 1] = v; + vec[2 * i].setString(str); + } while (i != 0); + + JS_ASSERT(tvr.array == vec); + vec = (Value *) cx->realloc(vec, 4 * size_t(newlen) * sizeof(Value)); + if (!vec) { + vec = tvr.array; /* N.B. AutoFreeVector */ + return false; + } + mergesort_tmp = vec + 2 * newlen; + MakeRangeGCSafe(mergesort_tmp, 2 * newlen); + tvr.changeArray(vec, newlen * 4); + elemsize = 2 * sizeof(Value); + } + if (!js_MergeSort(vec, size_t(newlen), elemsize, + sort_compare_strings, cx, mergesort_tmp, + JS_SORTING_GENERIC)) { + return false; + } + if (!allStrings) { + /* + * We want to make the following loop fast and to unroot the + * cached results of toString invocations before the operation + * callback has a chance to run the GC. For this reason we do + * not call JS_CHECK_OPERATION_LIMIT in the loop. + */ + i = 0; + do { + vec[i] = vec[2 * i + 1]; + } while (++i != newlen); + } + } else { + CompareArgs ca(cx); + if (!ca.session.start(cx, fval, UndefinedValue(), 2)) + return false; + + if (!js_MergeSort(vec, size_t(newlen), sizeof(Value), + comparator_stack_cast(sort_compare), + &ca, mergesort_tmp, + JS_SORTING_VALUES)) { + return false; + } + } + + /* + * We no longer need to root the scratch space for the merge sort, so + * unroot it now to make the job of a potential GC under + * InitArrayElements easier. + */ + tvr.changeLength(newlen); + if (!InitArrayElements(cx, obj, 0, newlen, vec)) + return false; + } + + /* Set undefs that sorted after the rest of elements. */ + while (undefs != 0) { + --undefs; + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !SetArrayElement(cx, obj, newlen++, UndefinedValue())) { + return false; + } + } + + /* Re-create any holes that sorted to the end of the array. */ + while (len > newlen) { + if (!JS_CHECK_OPERATION_LIMIT(cx) || DeleteArrayElement(cx, obj, --len, true) < 0) + return false; + } + vp->setObject(*obj); + return true; +} + +/* + * Perl-inspired push, pop, shift, unshift, and splice methods. + */ +static JSBool +array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) +{ + jsuint length; + + if (!js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + if (!InitArrayElements(cx, obj, length, argc, argv)) + return JS_FALSE; + + /* Per ECMA-262, return the new array length. */ + jsdouble newlength = length + jsdouble(argc); + rval->setNumber(newlength); + return js_SetLengthProperty(cx, obj, newlength); +} + +static JSBool +array_push1_dense(JSContext* cx, JSObject* obj, const Value &v, Value *rval) +{ + uint32 length = obj->getArrayLength(); + do { + JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, 1); + if (result != JSObject::ED_OK) { + if (result == JSObject::ED_FAILED) + return false; + JS_ASSERT(result == JSObject::ED_SPARSE); + break; + } + + obj->setArrayLength(length + 1); + + JS_ASSERT(obj->getDenseArrayElement(length).isMagic(JS_ARRAY_HOLE)); + obj->setDenseArrayElement(length, v); + rval->setNumber(obj->getArrayLength()); + return true; + } while (false); + + if (!obj->makeDenseArraySlow(cx)) + return false; + Value tmp = v; + return array_push_slowly(cx, obj, 1, &tmp, rval); +} + +JS_ALWAYS_INLINE JSBool +ArrayCompPushImpl(JSContext *cx, JSObject *obj, const Value &v) +{ + uint32 length = obj->getArrayLength(); + if (obj->isSlowArray()) { + /* This can happen in one evil case. See bug 630377. */ + jsid id; + return js_IndexToId(cx, length, &id) && + js_DefineProperty(cx, obj, id, &v, NULL, NULL, JSPROP_ENUMERATE); + } + + JS_ASSERT(obj->isDenseArray()); + JS_ASSERT(length <= obj->getDenseArrayCapacity()); + + if (length == obj->getDenseArrayCapacity()) { + if (length > JS_ARGS_LENGTH_MAX) { + JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL, + JSMSG_ARRAY_INIT_TOO_BIG); + return false; + } + + /* + * An array comprehension cannot add holes to the array. So we can use + * ensureSlots instead of ensureDenseArrayElements. + */ + if (!obj->ensureSlots(cx, length + 1)) + return false; + } + obj->setArrayLength(length + 1); + obj->setDenseArrayElement(length, v); + return true; +} + +JSBool +js_ArrayCompPush(JSContext *cx, JSObject *obj, const Value &vp) +{ + return ArrayCompPushImpl(cx, obj, vp); +} + +#ifdef JS_TRACER +JSBool JS_FASTCALL +js_ArrayCompPush_tn(JSContext *cx, JSObject *obj, ValueArgType v) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + if (!ArrayCompPushImpl(cx, obj, ValueArgToConstRef(v))) { + SetBuiltinError(tm); + return JS_FALSE; + } + + return WasBuiltinSuccessful(tm); +} +JS_DEFINE_CALLINFO_3(extern, BOOL_FAIL, js_ArrayCompPush_tn, CONTEXT, OBJECT, + VALUE, 0, nanojit::ACCSET_STORE_ANY) +#endif + +static JSBool +array_push(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + /* Insist on one argument and obj of the expected class. */ + if (argc != 1 || !obj->isDenseArray()) + return array_push_slowly(cx, obj, argc, vp + 2, vp); + + return array_push1_dense(cx, obj, vp[2], vp); +} + +static JSBool +array_pop_slowly(JSContext *cx, JSObject* obj, Value *vp) +{ + jsuint index; + JSBool hole; + + if (!js_GetLengthProperty(cx, obj, &index)) + return JS_FALSE; + if (index == 0) { + vp->setUndefined(); + } else { + index--; + + /* Get the to-be-deleted property's value into vp. */ + if (!GetElement(cx, obj, index, &hole, vp)) + return JS_FALSE; + if (!hole && DeleteArrayElement(cx, obj, index, true) < 0) + return JS_FALSE; + } + return js_SetLengthProperty(cx, obj, index); +} + +static JSBool +array_pop_dense(JSContext *cx, JSObject* obj, Value *vp) +{ + jsuint index; + JSBool hole; + + index = obj->getArrayLength(); + if (index == 0) { + vp->setUndefined(); + return JS_TRUE; + } + index--; + if (!GetElement(cx, obj, index, &hole, vp)) + return JS_FALSE; + if (!hole && DeleteArrayElement(cx, obj, index, true) < 0) + return JS_FALSE; + obj->setArrayLength(index); + return JS_TRUE; +} + +static JSBool +array_pop(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + if (obj->isDenseArray()) + return array_pop_dense(cx, obj, vp); + return array_pop_slowly(cx, obj, vp); +} + +static JSBool +array_shift(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return JS_FALSE; + + jsuint length; + if (!js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + + if (length == 0) { + vp->setUndefined(); + } else { + length--; + + if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) && + length < obj->getDenseArrayCapacity()) { + *vp = obj->getDenseArrayElement(0); + if (vp->isMagic(JS_ARRAY_HOLE)) + vp->setUndefined(); + Value *elems = obj->getDenseArrayElements(); + memmove(elems, elems + 1, length * sizeof(jsval)); + obj->setDenseArrayElement(length, MagicValue(JS_ARRAY_HOLE)); + obj->setArrayLength(length); + if (!js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(length))) + return JS_FALSE; + return JS_TRUE; + } + + /* Get the to-be-deleted property's value into vp ASAP. */ + JSBool hole; + if (!GetElement(cx, obj, 0, &hole, vp)) + return JS_FALSE; + + /* Slide down the array above the first element. */ + AutoValueRooter tvr(cx); + for (jsuint i = 0; i < length; i++) { + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !GetElement(cx, obj, i + 1, &hole, tvr.addr()) || + !SetOrDeleteArrayElement(cx, obj, i, hole, tvr.value())) { + return JS_FALSE; + } + } + + /* Delete the only or last element when it exists. */ + if (!hole && DeleteArrayElement(cx, obj, length, true) < 0) + return JS_FALSE; + } + return js_SetLengthProperty(cx, obj, length); +} + +static JSBool +array_unshift(JSContext *cx, uintN argc, Value *vp) +{ + Value *argv; + JSBool hole; + jsdouble last, newlen; + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + jsuint length; + if (!js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + newlen = length; + if (argc > 0) { + /* Slide up the array to make room for argc at the bottom. */ + argv = JS_ARGV(cx, vp); + if (length > 0) { + bool optimized = false; + do { + if (!obj->isDenseArray()) + break; + if (js_PrototypeHasIndexedProperties(cx, obj)) + break; + JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, argc); + if (result != JSObject::ED_OK) { + if (result == JSObject::ED_FAILED) + return false; + JS_ASSERT(result == JSObject::ED_SPARSE); + break; + } + Value *elems = obj->getDenseArrayElements(); + memmove(elems + argc, elems, length * sizeof(jsval)); + for (uint32 i = 0; i < argc; i++) + obj->setDenseArrayElement(i, MagicValue(JS_ARRAY_HOLE)); + optimized = true; + } while (false); + + if (!optimized) { + last = length; + jsdouble upperIndex = last + argc; + AutoValueRooter tvr(cx); + do { + --last, --upperIndex; + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !GetElement(cx, obj, last, &hole, tvr.addr()) || + !SetOrDeleteArrayElement(cx, obj, upperIndex, hole, tvr.value())) { + return JS_FALSE; + } + } while (last != 0); + } + } + + /* Copy from argv to the bottom of the array. */ + if (!InitArrayElements(cx, obj, 0, argc, argv)) + return JS_FALSE; + + newlen += argc; + } + if (!js_SetLengthProperty(cx, obj, newlen)) + return JS_FALSE; + + /* Follow Perl by returning the new array length. */ + vp->setNumber(newlen); + return JS_TRUE; +} + +static JSBool +array_splice(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + jsuint length, begin, end, count, delta, last; + JSBool hole; + + /* Create a new array value to return. */ + JSObject *obj2 = NewDenseEmptyArray(cx); + if (!obj2) + return JS_FALSE; + vp->setObject(*obj2); + + /* Nothing to do if no args. Otherwise get length. */ + if (argc == 0) + return JS_TRUE; + Value *argv = JS_ARGV(cx, vp); + if (!js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + jsuint origlength = length; + + /* Convert the first argument into a starting index. */ + jsdouble d; + if (!ValueToNumber(cx, *argv, &d)) + return JS_FALSE; + d = js_DoubleToInteger(d); + if (d < 0) { + d += length; + if (d < 0) + d = 0; + } else if (d > length) { + d = length; + } + begin = (jsuint)d; /* d has been clamped to uint32 */ + argc--; + argv++; + + /* Convert the second argument from a count into a fencepost index. */ + delta = length - begin; + if (argc == 0) { + count = delta; + end = length; + } else { + if (!ValueToNumber(cx, *argv, &d)) + return JS_FALSE; + d = js_DoubleToInteger(d); + if (d < 0) + d = 0; + else if (d > delta) + d = delta; + count = (jsuint)d; + end = begin + count; + argc--; + argv++; + } + + AutoValueRooter tvr(cx); + + /* If there are elements to remove, put them into the return value. */ + if (count > 0) { + if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) && + end <= obj->getDenseArrayCapacity()) { + if (!InitArrayObject(cx, obj2, count, obj->getDenseArrayElements() + begin)) + return JS_FALSE; + } else { + for (last = begin; last < end; last++) { + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !GetElement(cx, obj, last, &hole, tvr.addr())) { + return JS_FALSE; + } + + /* Copy tvr.value() to the new array unless it's a hole. */ + if (!hole && !SetArrayElement(cx, obj2, last - begin, tvr.value())) + return JS_FALSE; + } + + if (!js_SetLengthProperty(cx, obj2, count)) + return JS_FALSE; + } + } + + /* Find the direction (up or down) to copy and make way for argv. */ + if (argc > count) { + delta = (jsuint)argc - count; + last = length; + bool optimized = false; + do { + if (!obj->isDenseArray()) + break; + if (js_PrototypeHasIndexedProperties(cx, obj)) + break; + if (length > obj->getDenseArrayCapacity()) + break; + if (length != 0 && obj->getDenseArrayElement(length - 1).isMagic(JS_ARRAY_HOLE)) + break; + JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, delta); + if (result != JSObject::ED_OK) { + if (result == JSObject::ED_FAILED) + return false; + JS_ASSERT(result == JSObject::ED_SPARSE); + break; + } + Value *arraybeg = obj->getDenseArrayElements(); + Value *srcbeg = arraybeg + last - 1; + Value *srcend = arraybeg + end - 1; + Value *dstbeg = srcbeg + delta; + for (Value *src = srcbeg, *dst = dstbeg; src > srcend; --src, --dst) + *dst = *src; + + obj->setArrayLength(obj->getArrayLength() + delta); + optimized = true; + } while (false); + + if (!optimized) { + /* (uint) end could be 0, so we can't use a vanilla >= test. */ + while (last-- > end) { + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !GetElement(cx, obj, last, &hole, tvr.addr()) || + !SetOrDeleteArrayElement(cx, obj, last + delta, hole, tvr.value())) { + return JS_FALSE; + } + } + } + length += delta; + } else if (argc < count) { + delta = count - (jsuint)argc; + if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) && + length <= obj->getDenseArrayCapacity()) { + + Value *arraybeg = obj->getDenseArrayElements(); + Value *srcbeg = arraybeg + end; + Value *srcend = arraybeg + length; + Value *dstbeg = srcbeg - delta; + for (Value *src = srcbeg, *dst = dstbeg; src < srcend; ++src, ++dst) + *dst = *src; + } else { + for (last = end; last < length; last++) { + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !GetElement(cx, obj, last, &hole, tvr.addr()) || + !SetOrDeleteArrayElement(cx, obj, last - delta, hole, tvr.value())) { + return JS_FALSE; + } + } + } + length -= delta; + } + + if (length < origlength && !js_SuppressDeletedIndexProperties(cx, obj, length, origlength)) + return JS_FALSE; + + /* + * Copy from argv into the hole to complete the splice, and update length in + * case we deleted elements from the end. + */ + return InitArrayElements(cx, obj, begin, argc, argv) && + js_SetLengthProperty(cx, obj, length); +} + +/* + * Python-esque sequence operations. + */ +static JSBool +array_concat(JSContext *cx, uintN argc, Value *vp) +{ + /* Treat our |this| object as the first argument; see ECMA 15.4.4.4. */ + Value *p = JS_ARGV(cx, vp) - 1; + + /* Create a new Array object and root it using *vp. */ + JSObject *aobj = ToObject(cx, &vp[1]); + if (!aobj) + return false; + + JSObject *nobj; + jsuint length; + if (aobj->isDenseArray()) { + /* + * Clone aobj but pass the minimum of its length and capacity, to + * handle a = [1,2,3]; a.length = 10000 "dense" cases efficiently. In + * the normal case where length is <= capacity, nobj and aobj will have + * the same capacity. + */ + length = aobj->getArrayLength(); + jsuint capacity = aobj->getDenseArrayCapacity(); + nobj = NewDenseCopiedArray(cx, JS_MIN(length, capacity), aobj->getDenseArrayElements()); + if (!nobj) + return JS_FALSE; + nobj->setArrayLength(length); + vp->setObject(*nobj); + if (argc == 0) + return JS_TRUE; + argc--; + p++; + } else { + nobj = NewDenseEmptyArray(cx); + if (!nobj) + return JS_FALSE; + vp->setObject(*nobj); + length = 0; + } + + AutoValueRooter tvr(cx); + + /* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */ + for (uintN i = 0; i <= argc; i++) { + if (!JS_CHECK_OPERATION_LIMIT(cx)) + return false; + const Value &v = p[i]; + if (v.isObject()) { + aobj = &v.toObject(); + if (aobj->isArray() || + (aobj->isWrapper() && JSWrapper::wrappedObject(aobj)->isArray())) { + jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); + if (!aobj->getProperty(cx, id, tvr.addr())) + return false; + jsuint alength; + if (!ValueToLength(cx, tvr.addr(), &alength)) + return false; + for (jsuint slot = 0; slot < alength; slot++) { + JSBool hole; + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !GetElement(cx, aobj, slot, &hole, tvr.addr())) { + return false; + } + + /* + * Per ECMA 262, 15.4.4.4, step 9, ignore nonexistent + * properties. + */ + if (!hole && + !SetArrayElement(cx, nobj, length+slot, tvr.value())) { + return false; + } + } + length += alength; + continue; + } + } + + if (!SetArrayElement(cx, nobj, length, v)) + return false; + length++; + } + + return js_SetLengthProperty(cx, nobj, length); +} + +static JSBool +array_slice(JSContext *cx, uintN argc, Value *vp) +{ + Value *argv; + JSObject *nobj; + jsuint length, begin, end, slot; + JSBool hole; + + argv = JS_ARGV(cx, vp); + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + begin = 0; + end = length; + + if (argc > 0) { + jsdouble d; + if (!ValueToNumber(cx, argv[0], &d)) + return JS_FALSE; + d = js_DoubleToInteger(d); + if (d < 0) { + d += length; + if (d < 0) + d = 0; + } else if (d > length) { + d = length; + } + begin = (jsuint)d; + + if (argc > 1 && !argv[1].isUndefined()) { + if (!ValueToNumber(cx, argv[1], &d)) + return JS_FALSE; + d = js_DoubleToInteger(d); + if (d < 0) { + d += length; + if (d < 0) + d = 0; + } else if (d > length) { + d = length; + } + end = (jsuint)d; + } + } + + if (begin > end) + begin = end; + + if (obj->isDenseArray() && end <= obj->getDenseArrayCapacity() && + !js_PrototypeHasIndexedProperties(cx, obj)) { + nobj = NewDenseCopiedArray(cx, end - begin, obj->getDenseArrayElements() + begin); + if (!nobj) + return JS_FALSE; + vp->setObject(*nobj); + return JS_TRUE; + } + + /* Create a new Array object and root it using *vp. */ + nobj = NewDenseAllocatedArray(cx, end - begin); + if (!nobj) + return JS_FALSE; + vp->setObject(*nobj); + + AutoValueRooter tvr(cx); + for (slot = begin; slot < end; slot++) { + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !GetElement(cx, obj, slot, &hole, tvr.addr())) { + return JS_FALSE; + } + if (!hole && !SetArrayElement(cx, nobj, slot - begin, tvr.value())) + return JS_FALSE; + } + + return JS_TRUE; +} + +#if JS_HAS_ARRAY_EXTRAS + +static JSBool +array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp) +{ + jsuint length, i, stop; + Value tosearch; + jsint direction; + JSBool hole; + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + if (!js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + if (length == 0) + goto not_found; + + if (argc <= 1) { + i = isLast ? length - 1 : 0; + tosearch = (argc != 0) ? vp[2] : UndefinedValue(); + } else { + jsdouble start; + + tosearch = vp[2]; + if (!ValueToNumber(cx, vp[3], &start)) + return JS_FALSE; + start = js_DoubleToInteger(start); + if (start < 0) { + start += length; + if (start < 0) { + if (isLast) + goto not_found; + i = 0; + } else { + i = (jsuint)start; + } + } else if (start >= length) { + if (!isLast) + goto not_found; + i = length - 1; + } else { + i = (jsuint)start; + } + } + + if (isLast) { + stop = 0; + direction = -1; + } else { + stop = length - 1; + direction = 1; + } + + for (;;) { + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !GetElement(cx, obj, (jsuint)i, &hole, vp)) { + return JS_FALSE; + } + if (!hole) { + JSBool equal; + if (!StrictlyEqual(cx, *vp, tosearch, &equal)) + return JS_FALSE; + if (equal) { + vp->setNumber(i); + return JS_TRUE; + } + } + if (i == stop) + goto not_found; + i += direction; + } + + not_found: + vp->setInt32(-1); + return JS_TRUE; +} + +static JSBool +array_indexOf(JSContext *cx, uintN argc, Value *vp) +{ + return array_indexOfHelper(cx, JS_FALSE, argc, vp); +} + +static JSBool +array_lastIndexOf(JSContext *cx, uintN argc, Value *vp) +{ + return array_indexOfHelper(cx, JS_TRUE, argc, vp); +} + +/* Order is important; extras that take a predicate funarg must follow MAP. */ +typedef enum ArrayExtraMode { + FOREACH, + REDUCE, + REDUCE_RIGHT, + MAP, + FILTER, + SOME, + EVERY +} ArrayExtraMode; + +#define REDUCE_MODE(mode) ((mode) == REDUCE || (mode) == REDUCE_RIGHT) + +static JSBool +array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + jsuint length; + if (!js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + + /* + * First, get or compute our callee, so that we error out consistently + * when passed a non-callable object. + */ + if (argc == 0) { + js_ReportMissingArg(cx, *vp, 0); + return JS_FALSE; + } + Value *argv = vp + 2; + JSObject *callable = js_ValueToCallableObject(cx, &argv[0], JSV2F_SEARCH_STACK); + if (!callable) + return JS_FALSE; + + /* + * Set our initial return condition, used for zero-length array cases + * (and pre-size our map return to match our known length, for all cases). + */ + jsuint newlen; + JSObject *newarr; +#ifdef __GNUC__ /* quell GCC overwarning */ + newlen = 0; + newarr = NULL; +#endif + jsint start = 0, end = length, step = 1; + + switch (mode) { + case REDUCE_RIGHT: + start = length - 1, end = -1, step = -1; + /* FALL THROUGH */ + case REDUCE: + if (length == 0 && argc == 1) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_EMPTY_ARRAY_REDUCE); + return JS_FALSE; + } + if (argc >= 2) { + *vp = argv[1]; + } else { + JSBool hole; + do { + if (!GetElement(cx, obj, start, &hole, vp)) + return JS_FALSE; + start += step; + } while (hole && start != end); + + if (hole && start == end) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_EMPTY_ARRAY_REDUCE); + return JS_FALSE; + } + } + break; + case MAP: + case FILTER: + newlen = (mode == MAP) ? length : 0; + newarr = NewDenseAllocatedArray(cx, newlen); + if (!newarr) + return JS_FALSE; + vp->setObject(*newarr); + break; + case SOME: + vp->setBoolean(false); + break; + case EVERY: + vp->setBoolean(true); + break; + case FOREACH: + vp->setUndefined(); + break; + } + + if (length == 0) + return JS_TRUE; + + Value thisv = (argc > 1 && !REDUCE_MODE(mode)) ? argv[1] : UndefinedValue(); + + /* + * For all but REDUCE, we call with 3 args (value, index, array). REDUCE + * requires 4 args (accum, value, index, array). + */ + argc = 3 + REDUCE_MODE(mode); + + InvokeSessionGuard session; + if (!session.start(cx, ObjectValue(*callable), thisv, argc)) + return JS_FALSE; + + MUST_FLOW_THROUGH("out"); + JSBool ok = JS_TRUE; + JSBool cond; + + Value objv = ObjectValue(*obj); + AutoValueRooter tvr(cx); + for (jsint i = start; i != end; i += step) { + JSBool hole; + ok = JS_CHECK_OPERATION_LIMIT(cx) && + GetElement(cx, obj, i, &hole, tvr.addr()); + if (!ok) + goto out; + if (hole) + continue; + + /* + * Push callable and 'this', then args. We must do this for every + * iteration around the loop since Invoke clobbers its arguments. + */ + uintN argi = 0; + if (REDUCE_MODE(mode)) + session[argi++] = *vp; + session[argi++] = tvr.value(); + session[argi++] = Int32Value(i); + session[argi] = objv; + + /* Do the call. */ + ok = session.invoke(cx); + if (!ok) + break; + + const Value &rval = session.rval(); + + if (mode > MAP) + cond = js_ValueToBoolean(rval); +#ifdef __GNUC__ /* quell GCC overwarning */ + else + cond = JS_FALSE; +#endif + + switch (mode) { + case FOREACH: + break; + case REDUCE: + case REDUCE_RIGHT: + *vp = rval; + break; + case MAP: + ok = SetArrayElement(cx, newarr, i, rval); + if (!ok) + goto out; + break; + case FILTER: + if (!cond) + break; + /* The element passed the filter, so push it onto our result. */ + ok = SetArrayElement(cx, newarr, newlen++, tvr.value()); + if (!ok) + goto out; + break; + case SOME: + if (cond) { + vp->setBoolean(true); + goto out; + } + break; + case EVERY: + if (!cond) { + vp->setBoolean(false); + goto out; + } + break; + } + } + + out: + if (ok && mode == FILTER) + ok = js_SetLengthProperty(cx, newarr, newlen); + return ok; +} + +static JSBool +array_forEach(JSContext *cx, uintN argc, Value *vp) +{ + return array_extra(cx, FOREACH, argc, vp); +} + +static JSBool +array_map(JSContext *cx, uintN argc, Value *vp) +{ + return array_extra(cx, MAP, argc, vp); +} + +static JSBool +array_reduce(JSContext *cx, uintN argc, Value *vp) +{ + return array_extra(cx, REDUCE, argc, vp); +} + +static JSBool +array_reduceRight(JSContext *cx, uintN argc, Value *vp) +{ + return array_extra(cx, REDUCE_RIGHT, argc, vp); +} + +static JSBool +array_filter(JSContext *cx, uintN argc, Value *vp) +{ + return array_extra(cx, FILTER, argc, vp); +} + +static JSBool +array_some(JSContext *cx, uintN argc, Value *vp) +{ + return array_extra(cx, SOME, argc, vp); +} + +static JSBool +array_every(JSContext *cx, uintN argc, Value *vp) +{ + return array_extra(cx, EVERY, argc, vp); +} +#endif + +static JSBool +array_isArray(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj; + vp->setBoolean(argc > 0 && + vp[2].isObject() && + ((obj = &vp[2].toObject())->isArray() || + (obj->isWrapper() && JSWrapper::wrappedObject(obj)->isArray()))); + return true; +} + +static JSFunctionSpec array_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, array_toSource, 0,0), +#endif + JS_FN(js_toString_str, array_toString, 0,0), + JS_FN(js_toLocaleString_str,array_toLocaleString,0,0), + + /* Perl-ish methods. */ + JS_FN("join", array_join, 1,JSFUN_GENERIC_NATIVE), + JS_FN("reverse", array_reverse, 0,JSFUN_GENERIC_NATIVE), + JS_FN("sort", array_sort, 1,JSFUN_GENERIC_NATIVE), + JS_FN("push", array_push, 1,JSFUN_GENERIC_NATIVE), + JS_FN("pop", array_pop, 0,JSFUN_GENERIC_NATIVE), + JS_FN("shift", array_shift, 0,JSFUN_GENERIC_NATIVE), + JS_FN("unshift", array_unshift, 1,JSFUN_GENERIC_NATIVE), + JS_FN("splice", array_splice, 2,JSFUN_GENERIC_NATIVE), + + /* Pythonic sequence methods. */ + JS_FN("concat", array_concat, 1,JSFUN_GENERIC_NATIVE), + JS_FN("slice", array_slice, 2,JSFUN_GENERIC_NATIVE), + +#if JS_HAS_ARRAY_EXTRAS + JS_FN("indexOf", array_indexOf, 1,JSFUN_GENERIC_NATIVE), + JS_FN("lastIndexOf", array_lastIndexOf, 1,JSFUN_GENERIC_NATIVE), + JS_FN("forEach", array_forEach, 1,JSFUN_GENERIC_NATIVE), + JS_FN("map", array_map, 1,JSFUN_GENERIC_NATIVE), + JS_FN("reduce", array_reduce, 1,JSFUN_GENERIC_NATIVE), + JS_FN("reduceRight", array_reduceRight, 1,JSFUN_GENERIC_NATIVE), + JS_FN("filter", array_filter, 1,JSFUN_GENERIC_NATIVE), + JS_FN("some", array_some, 1,JSFUN_GENERIC_NATIVE), + JS_FN("every", array_every, 1,JSFUN_GENERIC_NATIVE), +#endif + + JS_FS_END +}; + +static JSFunctionSpec array_static_methods[] = { + JS_FN("isArray", array_isArray, 1,0), + JS_FS_END +}; + +JSBool +js_Array(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj; + + if (argc == 0) { + obj = NewDenseEmptyArray(cx); + } else if (argc > 1) { + obj = NewDenseCopiedArray(cx, argc, vp + 2); + } else if (!vp[2].isNumber()) { + obj = NewDenseCopiedArray(cx, 1, vp + 2); + } else { + jsuint length; + if (!ValueToLength(cx, vp + 2, &length)) + return JS_FALSE; + obj = NewDenseUnallocatedArray(cx, length); + } + + if (!obj) + return JS_FALSE; + vp->setObject(*obj); + + return JS_TRUE; +} + +JSObject * +js_InitArrayClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto = js_InitClass(cx, obj, NULL, &js_ArrayClass, js_Array, 1, + NULL, array_methods, NULL, array_static_methods); + if (!proto) + return NULL; + + /* + * Assert that js_InitClass used the correct (slow array, not dense array) + * class for proto's emptyShape class. + */ + JS_ASSERT(proto->emptyShapes && proto->emptyShapes[0]->getClass() == proto->getClass()); + + proto->setArrayLength(0); + return proto; +} + +/* + * Array allocation functions. + */ +namespace js { + +template +static JS_ALWAYS_INLINE JSObject * +NewArray(JSContext *cx, jsuint length, JSObject *proto) +{ + JS_ASSERT_IF(proto, proto->isArray()); + + gc::FinalizeKind kind = GuessObjectGCKind(length, true); + JSObject *obj = detail::NewObject(cx, &js_ArrayClass, proto, NULL, kind); + if (!obj) + return NULL; + + obj->setArrayLength(length); + + if (allocateCapacity && !obj->ensureSlots(cx, length)) + return NULL; + + return obj; +} + +JSObject * JS_FASTCALL +NewDenseEmptyArray(JSContext *cx, JSObject *proto) +{ + return NewArray(cx, 0, proto); +} + +JSObject * JS_FASTCALL +NewDenseAllocatedArray(JSContext *cx, uint32 length, JSObject *proto) +{ + return NewArray(cx, length, proto); +} + +JSObject * JS_FASTCALL +NewDenseUnallocatedArray(JSContext *cx, uint32 length, JSObject *proto) +{ + return NewArray(cx, length, proto); +} + +JSObject * +NewDenseCopiedArray(JSContext *cx, uintN length, Value *vp, JSObject *proto) +{ + JSObject* obj = NewArray(cx, length, proto); + if (!obj) + return NULL; + + JS_ASSERT(obj->getDenseArrayCapacity() >= length); + + if (vp) + memcpy(obj->getDenseArrayElements(), vp, length * sizeof(Value)); + + return obj; +} + +#ifdef JS_TRACER +JS_DEFINE_CALLINFO_2(extern, OBJECT, NewDenseEmptyArray, CONTEXT, OBJECT, 0, + nanojit::ACCSET_STORE_ANY) +JS_DEFINE_CALLINFO_3(extern, OBJECT, NewDenseAllocatedArray, CONTEXT, UINT32, OBJECT, 0, + nanojit::ACCSET_STORE_ANY) +JS_DEFINE_CALLINFO_3(extern, OBJECT, NewDenseUnallocatedArray, CONTEXT, UINT32, OBJECT, 0, + nanojit::ACCSET_STORE_ANY) +#endif + + + +JSObject * +NewSlowEmptyArray(JSContext *cx) +{ + JSObject *obj = NewNonFunction(cx, &js_SlowArrayClass, NULL, NULL); + if (!obj || !AddLengthProperty(cx, obj)) + return NULL; + + obj->setArrayLength(0); + return obj; +} + +} + + +#ifdef DEBUG +JSBool +js_ArrayInfo(JSContext *cx, uintN argc, jsval *vp) +{ + uintN i; + JSObject *array; + + for (i = 0; i < argc; i++) { + Value arg = Valueify(JS_ARGV(cx, vp)[i]); + + char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, arg, NULL); + if (!bytes) + return JS_FALSE; + if (arg.isPrimitive() || + !(array = arg.toObjectOrNull())->isArray()) { + fprintf(stderr, "%s: not array\n", bytes); + cx->free(bytes); + continue; + } + fprintf(stderr, "%s: %s (len %u", bytes, + array->isDenseArray() ? "dense" : "sparse", + array->getArrayLength()); + if (array->isDenseArray()) { + fprintf(stderr, ", capacity %u", + array->getDenseArrayCapacity()); + } + fputs(")\n", stderr); + cx->free(bytes); + } + + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return true; +} +#endif + +JS_FRIEND_API(JSBool) +js_CoerceArrayToCanvasImageData(JSObject *obj, jsuint offset, jsuint count, + JSUint8 *dest) +{ + uint32 length; + + if (!obj || !obj->isDenseArray()) + return JS_FALSE; + + length = obj->getArrayLength(); + if (length < offset + count) + return JS_FALSE; + + JSUint8 *dp = dest; + for (uintN i = offset; i < offset+count; i++) { + const Value &v = obj->getDenseArrayElement(i); + if (v.isInt32()) { + jsint vi = v.toInt32(); + if (jsuint(vi) > 255) + vi = (vi < 0) ? 0 : 255; + *dp++ = JSUint8(vi); + } else if (v.isDouble()) { + jsdouble vd = v.toDouble(); + if (!(vd >= 0)) /* Not < so that NaN coerces to 0 */ + *dp++ = 0; + else if (vd > 255) + *dp++ = 255; + else { + jsdouble toTruncate = vd + 0.5; + JSUint8 val = JSUint8(toTruncate); + + /* + * now val is rounded to nearest, ties rounded up. We want + * rounded to nearest ties to even, so check whether we had a + * tie. + */ + if (val == toTruncate) { + /* + * It was a tie (since adding 0.5 gave us the exact integer + * we want). Since we rounded up, we either already have an + * even number or we have an odd number but the number we + * want is one less. So just unconditionally masking out the + * ones bit should do the trick to get us the value we + * want. + */ + *dp++ = (val & ~1); + } else { + *dp++ = val; + } + } + } else { + return JS_FALSE; + } + } + + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_IsDensePrimitiveArray(JSObject *obj) +{ + if (!obj || !obj->isDenseArray()) + return JS_FALSE; + + jsuint capacity = obj->getDenseArrayCapacity(); + for (jsuint i = 0; i < capacity; i++) { + if (obj->getDenseArrayElement(i).isObject()) + return JS_FALSE; + } + + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone) +{ + JS_ASSERT(obj); + if (!obj->isDenseArray()) { + /* + * This wasn't a dense array. Return JS_TRUE but a NULL clone to signal + * that no exception was encountered. + */ + *clone = NULL; + return JS_TRUE; + } + + jsuint length = obj->getArrayLength(); + + /* + * Must use the minimum of original array's length and capacity, to handle + * |a = [1,2,3]; a.length = 10000| "dense" cases efficiently. In the normal + * case where length is <= capacity, the clone and original array will have + * the same capacity. + */ + jsuint jsvalCount = JS_MIN(obj->getDenseArrayCapacity(), length); + + js::AutoValueVector vector(cx); + if (!vector.reserve(jsvalCount)) + return JS_FALSE; + + for (jsuint i = 0; i < jsvalCount; i++) { + const Value &val = obj->getDenseArrayElement(i); + + if (val.isString()) { + // Strings must be made immutable before being copied to a clone. + if (!js_MakeStringImmutable(cx, val.toString())) + return JS_FALSE; + } else if (val.isObject()) { + /* + * This wasn't an array of primitives. Return JS_TRUE but a null + * clone to signal that no exception was encountered. + */ + *clone = NULL; + return JS_TRUE; + } + + vector.append(val); + } + + *clone = NewDenseCopiedArray(cx, jsvalCount, vector.begin()); + if (!*clone) + return JS_FALSE; + + /* The length will be set to the JS_MIN, above, but length might be larger. */ + (*clone)->setArrayLength(length); + return JS_TRUE; +} diff --git a/js/src/jsarray.h b/js/src/jsarray.h new file mode 100644 index 0000000..a230b50 --- /dev/null +++ b/js/src/jsarray.h @@ -0,0 +1,342 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsarray_h___ +#define jsarray_h___ +/* + * JS Array interface. + */ +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jsatom.h" +#include "jsobj.h" +#include "jsstr.h" + +/* Small arrays are dense, no matter what. */ +const uintN MIN_SPARSE_INDEX = 256; + +inline JSObject::EnsureDenseResult +JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra) +{ + JS_ASSERT(isDenseArray()); + uintN currentCapacity = numSlots(); + + uintN requiredCapacity; + if (extra == 1) { + /* Optimize for the common case. */ + if (index < currentCapacity) + return ED_OK; + requiredCapacity = index + 1; + if (requiredCapacity == 0) { + /* Overflow. */ + return ED_SPARSE; + } + } else { + requiredCapacity = index + extra; + if (requiredCapacity < index) { + /* Overflow. */ + return ED_SPARSE; + } + if (requiredCapacity <= currentCapacity) + return ED_OK; + } + + /* + * We use the extra argument also as a hint about number of non-hole + * elements to be inserted. + */ + if (requiredCapacity > MIN_SPARSE_INDEX && + willBeSparseDenseArray(requiredCapacity, extra)) { + return ED_SPARSE; + } + return growSlots(cx, requiredCapacity) ? ED_OK : ED_FAILED; +} + +extern bool +js_StringIsIndex(JSLinearString *str, jsuint *indexp); + +inline JSBool +js_IdIsIndex(jsid id, jsuint *indexp) +{ + if (JSID_IS_INT(id)) { + jsint i; + i = JSID_TO_INT(id); + if (i < 0) + return JS_FALSE; + *indexp = (jsuint)i; + return JS_TRUE; + } + + if (JS_UNLIKELY(!JSID_IS_STRING(id))) + return JS_FALSE; + + return js_StringIsIndex(JSID_TO_ATOM(id), indexp); +} + +/* XML really wants to pretend jsvals are jsids. */ +inline bool +js_IdValIsIndex(JSContext *cx, jsval id, jsuint *indexp, bool *isIndex) +{ + if (JSVAL_IS_INT(id)) { + jsint i; + i = JSVAL_TO_INT(id); + if (i < 0) { + *isIndex = false; + return true; + } + *indexp = (jsuint)i; + *isIndex = true; + return true; + } + + if (!JSVAL_IS_STRING(id)) { + *isIndex = false; + return true; + } + + JSLinearString *str = JSVAL_TO_STRING(id)->ensureLinear(cx); + if (!str) + return false; + + *isIndex = js_StringIsIndex(str, indexp); + return true; +} + +extern js::Class js_ArrayClass, js_SlowArrayClass; + +inline bool +JSObject::isDenseArray() const +{ + return getClass() == &js_ArrayClass; +} + +inline bool +JSObject::isSlowArray() const +{ + return getClass() == &js_SlowArrayClass; +} + +inline bool +JSObject::isArray() const +{ + return isDenseArray() || isSlowArray(); +} + +/* + * Dense arrays are not native -- aobj->isNative() for a dense array aobj + * results in false, meaning aobj->map does not point to a js::Shape. + * + * But Array methods are called via aobj.sort(), e.g., and the interpreter and + * the trace recorder must consult the property cache in order to perform well. + * The cache works only for native objects. + * + * Therefore the interpreter (js_Interpret in JSOP_GETPROP and JSOP_CALLPROP) + * and js_GetPropertyHelper use this inline function to skip up one link in the + * prototype chain when obj is a dense array, in order to find a native object + * (to wit, Array.prototype) in which to probe for cached methods. + * + * Note that setting aobj.__proto__ for a dense array aobj turns aobj into a + * slow array, avoiding the neede to skip. + * + * Callers of js_GetProtoIfDenseArray must take care to use the original object + * (obj) for the |this| value of a getter, setter, or method call (bug 476447). + */ +static JS_INLINE JSObject * +js_GetProtoIfDenseArray(JSObject *obj) +{ + return obj->isDenseArray() ? obj->getProto() : obj; +} + +extern JSObject * +js_InitArrayClass(JSContext *cx, JSObject *obj); + +extern bool +js_InitContextBusyArrayTable(JSContext *cx); + +namespace js +{ + +/* Create a dense array with no capacity allocated, length set to 0. */ +extern JSObject * JS_FASTCALL +NewDenseEmptyArray(JSContext *cx, JSObject *proto=NULL); + +/* Create a dense array with length and capacity == 'length'. */ +extern JSObject * JS_FASTCALL +NewDenseAllocatedArray(JSContext *cx, uint length, JSObject *proto=NULL); + +/* + * Create a dense array with a set length, but without allocating space for the + * contents. This is useful, e.g., when accepting length from the user. + */ +extern JSObject * JS_FASTCALL +NewDenseUnallocatedArray(JSContext *cx, uint length, JSObject *proto=NULL); + +/* Create a dense array with a copy of vp. */ +extern JSObject * +NewDenseCopiedArray(JSContext *cx, uint length, Value *vp, JSObject *proto=NULL); + +/* Create a sparse array. */ +extern JSObject * +NewSlowEmptyArray(JSContext *cx); + +} + +extern JSBool +js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp); + +extern JSBool +js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length); + +extern JSBool +js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp); + +extern JSBool JS_FASTCALL +js_IndexToId(JSContext *cx, jsuint index, jsid *idp); + +namespace js { + +/* + * This function assumes 'length' is effectively the result of calling + * js_GetLengthProperty on aobj. + */ +extern bool +GetElements(JSContext *cx, JSObject *aobj, jsuint length, js::Value *vp); + +} + +/* + * JS-specific merge sort function. + */ +typedef JSBool (*JSComparator)(void *arg, const void *a, const void *b, + int *result); + +enum JSMergeSortElemType { + JS_SORTING_VALUES, + JS_SORTING_GENERIC +}; + +/* + * NB: vec is the array to be sorted, tmp is temporary space at least as big + * as vec. Both should be GC-rooted if appropriate. + * + * isValue should true iff vec points to an array of js::Value + * + * The sorted result is in vec. vec may be in an inconsistent state if the + * comparator function cmp returns an error inside a comparison, so remember + * to check the return value of this function. + */ +extern bool +js_MergeSort(void *vec, size_t nel, size_t elsize, JSComparator cmp, + void *arg, void *tmp, JSMergeSortElemType elemType); + +/* + * The Array.prototype.sort fast-native entry point is exported for joined + * function optimization in js{interp,tracer}.cpp. + */ +namespace js { +extern JSBool +array_sort(JSContext *cx, uintN argc, js::Value *vp); +} + +#ifdef DEBUG +extern JSBool +js_ArrayInfo(JSContext *cx, uintN argc, jsval *vp); +#endif + +extern JSBool +js_ArrayCompPush(JSContext *cx, JSObject *obj, const js::Value &vp); + +/* + * Fast dense-array-to-buffer conversion for use by canvas. + * + * If the array is a dense array, fill [offset..offset+count] values into + * destination, assuming that types are consistent. Return JS_TRUE if + * successful, otherwise JS_FALSE -- note that the destination buffer may be + * modified even if JS_FALSE is returned (e.g. due to finding an inappropriate + * type later on in the array). If JS_FALSE is returned, no error conditions + * or exceptions are set on the context. + * + * This method succeeds if each element of the array is an integer or a double. + * Values outside the 0-255 range are clamped to that range. Double values are + * converted to integers in this range by clamping and then rounding to + * nearest, ties to even. + */ + +JS_FRIEND_API(JSBool) +js_CoerceArrayToCanvasImageData(JSObject *obj, jsuint offset, jsuint count, + JSUint8 *dest); + +JSBool +js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj); + +/* + * Utility to access the value from the id returned by array_lookupProperty. + */ +JSBool +js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, jsid id, + js::Value *vp); + +/* Array constructor native. Exposed only so the JIT can know its address. */ +JSBool +js_Array(JSContext *cx, uintN argc, js::Value *vp); + +/* + * Makes a fast clone of a dense array as long as the array only contains + * primitive values. + * + * If the return value is JS_FALSE then clone will not be set. + * + * If the return value is JS_TRUE then clone will either be set to the address + * of a new JSObject or to NULL if the array was not dense or contained values + * that were not primitives. + */ +JS_FRIEND_API(JSBool) +js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone); + +/* + * Returns JS_TRUE if the given object is a dense array that contains only + * primitive values. + */ +JS_FRIEND_API(JSBool) +js_IsDensePrimitiveArray(JSObject *obj); + +extern JSBool JS_FASTCALL +js_EnsureDenseArrayCapacity(JSContext *cx, JSObject *obj, jsint i); + +#endif /* jsarray_h___ */ diff --git a/js/src/jsast.tbl b/js/src/jsast.tbl new file mode 100644 index 0000000..5815563 --- /dev/null +++ b/js/src/jsast.tbl @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* AST_ERROR = -1 */ + +ASTDEF(AST_PROGRAM, "Program", "program") + +ASTDEF(AST_IDENTIFIER, "Identifier", "identifier") +ASTDEF(AST_LITERAL, "Literal", "literal") +ASTDEF(AST_PROPERTY, "Property", "property") + +ASTDEF(AST_FUNC_DECL, "FunctionDeclaration", "functionDeclaration") +ASTDEF(AST_VAR_DECL, "VariableDeclaration", "variableDeclaration") +ASTDEF(AST_VAR_DTOR, "VariableDeclarator", "variableDeclarator") + +ASTDEF(AST_LIST_EXPR, "SequenceExpression", "sequenceExpression") +ASTDEF(AST_COND_EXPR, "ConditionalExpression", "conditionalExpression") +ASTDEF(AST_UNARY_EXPR, "UnaryExpression", "unaryExpression") +ASTDEF(AST_BINARY_EXPR, "BinaryExpression", "binaryExpression") +ASTDEF(AST_ASSIGN_EXPR, "AssignmentExpression", "assignmentExpression") +ASTDEF(AST_LOGICAL_EXPR, "LogicalExpression", "logicalExpression") +ASTDEF(AST_UPDATE_EXPR, "UpdateExpression", "updateExpression") +ASTDEF(AST_NEW_EXPR, "NewExpression", "newExpression") +ASTDEF(AST_CALL_EXPR, "CallExpression", "callExpression") +ASTDEF(AST_MEMBER_EXPR, "MemberExpression", "memberExpression") +ASTDEF(AST_FUNC_EXPR, "FunctionExpression", "functionExpression") +ASTDEF(AST_ARRAY_EXPR, "ArrayExpression", "arrayExpression") +ASTDEF(AST_OBJECT_EXPR, "ObjectExpression", "objectExpression") +ASTDEF(AST_THIS_EXPR, "ThisExpression", "thisExpression") +ASTDEF(AST_GRAPH_EXPR, "GraphExpression", "graphExpression") +ASTDEF(AST_GRAPH_IDX_EXPR, "GraphIndexExpression", "graphIndexExpression") +ASTDEF(AST_COMP_EXPR, "ComprehensionExpression", "comprehensionExpression") +ASTDEF(AST_GENERATOR_EXPR, "GeneratorExpression", "generatorExpression") +ASTDEF(AST_YIELD_EXPR, "YieldExpression", "yieldExpression") +ASTDEF(AST_LET_EXPR, "LetExpression", "letExpression") + +ASTDEF(AST_EMPTY_STMT, "EmptyStatement", "emptyStatement") +ASTDEF(AST_BLOCK_STMT, "BlockStatement", "blockStatement") +ASTDEF(AST_EXPR_STMT, "ExpressionStatement", "expressionStatement") +ASTDEF(AST_LAB_STMT, "LabeledStatement", "labeledStatement") +ASTDEF(AST_IF_STMT, "IfStatement", "ifStatement") +ASTDEF(AST_SWITCH_STMT, "SwitchStatement", "switchStatement") +ASTDEF(AST_WHILE_STMT, "WhileStatement", "whileStatement") +ASTDEF(AST_DO_STMT, "DoWhileStatement", "doWhileStatement") +ASTDEF(AST_FOR_STMT, "ForStatement", "forStatement") +ASTDEF(AST_FOR_IN_STMT, "ForInStatement", "forInStatement") +ASTDEF(AST_BREAK_STMT, "BreakStatement", "breakStatement") +ASTDEF(AST_CONTINUE_STMT, "ContinueStatement", "continueStatement") +ASTDEF(AST_WITH_STMT, "WithStatement", "withStatement") +ASTDEF(AST_RETURN_STMT, "ReturnStatement", "returnStatement") +ASTDEF(AST_TRY_STMT, "TryStatement", "tryStatement") +ASTDEF(AST_THROW_STMT, "ThrowStatement", "throwStatement") +ASTDEF(AST_DEBUGGER_STMT, "DebuggerStatement", "debuggerStatement") +ASTDEF(AST_LET_STMT, "LetStatement", "letStatement") + +ASTDEF(AST_CASE, "SwitchCase", "switchCase") +ASTDEF(AST_CATCH, "CatchClause", "catchClause") +ASTDEF(AST_COMP_BLOCK, "ComprehensionBlock", "comprehensionBlock") + +ASTDEF(AST_ARRAY_PATT, "ArrayPattern", "arrayPattern") +ASTDEF(AST_OBJECT_PATT, "ObjectPattern", "objectPattern") +ASTDEF(AST_PROP_PATT, "Property", "propertyPattern") + +ASTDEF(AST_XMLANYNAME, "XMLAnyName", "xmlAnyName") +ASTDEF(AST_XMLATTR_SEL, "XMLAttributeSelector", "xmlAttributeSelector") +ASTDEF(AST_XMLESCAPE, "XMLEscape", "xmlEscape") +ASTDEF(AST_XMLFILTER, "XMLFilterExpression", "xmlFilterExpression") +ASTDEF(AST_XMLDEFAULT, "XMLDefaultDeclaration", "xmlDefaultDeclaration") +ASTDEF(AST_XMLQUAL, "XMLQualifiedIdentifier", "xmlQualifiedIdentifier") +ASTDEF(AST_XMLFUNCQUAL, "XMLFunctionQualifiedIdentifier", "xmlFunctionQualifiedIdentifier") +ASTDEF(AST_XMLELEM, "XMLElement", "xmlElement") +ASTDEF(AST_XMLTEXT, "XMLText", "xmlText") +ASTDEF(AST_XMLLIST, "XMLList", "xmlList") +ASTDEF(AST_XMLSTART, "XMLStartTag", "xmlStartTag") +ASTDEF(AST_XMLEND, "XMLEndTag", "xmlEndTag") +ASTDEF(AST_XMLPOINT, "XMLPointTag", "xmlPointTag") +ASTDEF(AST_XMLNAME, "XMLName", "xmlName") +ASTDEF(AST_XMLATTR, "XMLAttribute", "xmlAttribute") +ASTDEF(AST_XMLCDATA, "XMLCdata", "xmlCdata") +ASTDEF(AST_XMLCOMMENT, "XMLComment", "xmlComment") +ASTDEF(AST_XMLPI, "XMLProcessingInstruction", "xmlProcessingInstruction") + +/* AST_LIMIT = last + 1 */ diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp new file mode 100644 index 0000000..3d97066 --- /dev/null +++ b/js/src/jsatom.cpp @@ -0,0 +1,1026 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS atom table. + */ +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsutil.h" +#include "jshash.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jsbit.h" +#include "jscntxt.h" +#include "jsgc.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsparse.h" +#include "jsscan.h" +#include "jsstr.h" +#include "jsversion.h" +#include "jsxml.h" + +#include "jsstrinlines.h" +#include "jsatominlines.h" +#include "jsobjinlines.h" + +using namespace js; +using namespace js::gc; + +/* + * ATOM_HASH assumes that JSHashNumber is 32-bit even on 64-bit systems. + */ +JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4); +JS_STATIC_ASSERT(sizeof(JSAtom *) == JS_BYTES_PER_WORD); + +/* + * Start and limit offsets for atom pointers in JSAtomState must be aligned + * on the word boundary. + */ +JS_STATIC_ASSERT(ATOM_OFFSET_START % sizeof(JSAtom *) == 0); +JS_STATIC_ASSERT(ATOM_OFFSET_LIMIT % sizeof(JSAtom *) == 0); + +/* + * JS_BOOLEAN_STR and JS_TYPE_STR assume that boolean names starts from the + * index 1 and type name starts from the index 1+2 atoms in JSAtomState. + */ +JS_STATIC_ASSERT(1 * sizeof(JSAtom *) == + offsetof(JSAtomState, booleanAtoms) - ATOM_OFFSET_START); +JS_STATIC_ASSERT((1 + 2) * sizeof(JSAtom *) == + offsetof(JSAtomState, typeAtoms) - ATOM_OFFSET_START); + +const char * +js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes) +{ + return js_ValueToPrintable(cx, StringValue(ATOM_TO_STRING(atom)), bytes); +} + +#define JS_PROTO(name,code,init) const char js_##name##_str[] = #name; +#include "jsproto.tbl" +#undef JS_PROTO + +/* + * String constants for common atoms defined in JSAtomState starting from + * JSAtomState.emptyAtom until JSAtomState.lazy. + * + * The elements of the array after the first empty string define strings + * corresponding to the two boolean literals, false and true, followed by the + * JSType enumerators from jspubtd.h starting with "undefined" for JSTYPE_VOID + * (which is special-value 2) and continuing as initialized below. The static + * asserts check these relations. + */ +JS_STATIC_ASSERT(JSTYPE_LIMIT == 8); +JS_STATIC_ASSERT(JSTYPE_VOID == 0); + +const char *const js_common_atom_names[] = { + "", /* emptyAtom */ + js_false_str, /* booleanAtoms[0] */ + js_true_str, /* booleanAtoms[1] */ + js_undefined_str, /* typeAtoms[JSTYPE_VOID] */ + js_object_str, /* typeAtoms[JSTYPE_OBJECT] */ + js_function_str, /* typeAtoms[JSTYPE_FUNCTION] */ + "string", /* typeAtoms[JSTYPE_STRING] */ + "number", /* typeAtoms[JSTYPE_NUMBER] */ + "boolean", /* typeAtoms[JSTYPE_BOOLEAN] */ + js_null_str, /* typeAtoms[JSTYPE_NULL] */ + "xml", /* typeAtoms[JSTYPE_XML] */ + js_null_str, /* nullAtom */ + +#define JS_PROTO(name,code,init) js_##name##_str, +#include "jsproto.tbl" +#undef JS_PROTO + + js_anonymous_str, /* anonymousAtom */ + js_apply_str, /* applyAtom */ + js_arguments_str, /* argumentsAtom */ + js_arity_str, /* arityAtom */ + js_call_str, /* callAtom */ + js_callee_str, /* calleeAtom */ + js_caller_str, /* callerAtom */ + js_class_prototype_str, /* classPrototypeAtom */ + js_constructor_str, /* constructorAtom */ + js_each_str, /* eachAtom */ + js_eval_str, /* evalAtom */ + js_fileName_str, /* fileNameAtom */ + js_get_str, /* getAtom */ + js_global_str, /* globalAtom */ + js_ignoreCase_str, /* ignoreCaseAtom */ + js_index_str, /* indexAtom */ + js_input_str, /* inputAtom */ + "toISOString", /* toISOStringAtom */ + js_iterator_str, /* iteratorAtom */ + js_join_str, /* joinAtom */ + js_lastIndex_str, /* lastIndexAtom */ + js_length_str, /* lengthAtom */ + js_lineNumber_str, /* lineNumberAtom */ + js_message_str, /* messageAtom */ + js_multiline_str, /* multilineAtom */ + js_name_str, /* nameAtom */ + js_next_str, /* nextAtom */ + js_noSuchMethod_str, /* noSuchMethodAtom */ + "[object Null]", /* objectNullAtom */ + "[object Undefined]", /* objectUndefinedAtom */ + js_proto_str, /* protoAtom */ + js_set_str, /* setAtom */ + js_source_str, /* sourceAtom */ + js_stack_str, /* stackAtom */ + js_sticky_str, /* stickyAtom */ + js_toGMTString_str, /* toGMTStringAtom */ + js_toLocaleString_str, /* toLocaleStringAtom */ + js_toSource_str, /* toSourceAtom */ + js_toString_str, /* toStringAtom */ + js_toUTCString_str, /* toUTCStringAtom */ + js_valueOf_str, /* valueOfAtom */ + js_toJSON_str, /* toJSONAtom */ + "(void 0)", /* void0Atom */ + js_enumerable_str, /* enumerableAtom */ + js_configurable_str, /* configurableAtom */ + js_writable_str, /* writableAtom */ + js_value_str, /* valueAtom */ + js_test_str, /* testAtom */ + "use strict", /* useStrictAtom */ + "loc", /* locAtom */ + "line", /* lineAtom */ + "Infinity", /* InfinityAtom */ + "NaN", /* NaNAtom */ + "builder", /* builderAtom */ + +#if JS_HAS_XML_SUPPORT + js_etago_str, /* etagoAtom */ + js_namespace_str, /* namespaceAtom */ + js_ptagc_str, /* ptagcAtom */ + js_qualifier_str, /* qualifierAtom */ + js_space_str, /* spaceAtom */ + js_stago_str, /* stagoAtom */ + js_star_str, /* starAtom */ + js_starQualifier_str, /* starQualifierAtom */ + js_tagc_str, /* tagcAtom */ + js_xml_str, /* xmlAtom */ + "@mozilla.org/js/function", /* functionNamespaceURIAtom */ +#endif + + "Proxy", /* ProxyAtom */ + + "getOwnPropertyDescriptor", /* getOwnPropertyDescriptorAtom */ + "getPropertyDescriptor", /* getPropertyDescriptorAtom */ + "defineProperty", /* definePropertyAtom */ + "delete", /* deleteAtom */ + "getOwnPropertyNames", /* getOwnPropertyNames */ + "enumerate", /* enumerateAtom */ + "fix", /* fixAtom */ + + "has", /* hasAtom */ + "hasOwn", /* hasOwnAtom */ + "keys", /* keysAtom */ + "iterate" /* iterateAtom */ +}; + +JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) * sizeof(JSAtom *) == + LAZY_ATOM_OFFSET_START - ATOM_OFFSET_START); + +/* + * Interpreter macros called by the trace recorder assume common atom indexes + * fit in one byte of immediate operand. + */ +JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) < 256); + +const size_t js_common_atom_count = JS_ARRAY_LENGTH(js_common_atom_names); + +const char js_anonymous_str[] = "anonymous"; +const char js_apply_str[] = "apply"; +const char js_arguments_str[] = "arguments"; +const char js_arity_str[] = "arity"; +const char js_call_str[] = "call"; +const char js_callee_str[] = "callee"; +const char js_caller_str[] = "caller"; +const char js_class_prototype_str[] = "prototype"; +const char js_constructor_str[] = "constructor"; +const char js_each_str[] = "each"; +const char js_eval_str[] = "eval"; +const char js_fileName_str[] = "fileName"; +const char js_get_str[] = "get"; +const char js_getter_str[] = "getter"; +const char js_global_str[] = "global"; +const char js_ignoreCase_str[] = "ignoreCase"; +const char js_index_str[] = "index"; +const char js_input_str[] = "input"; +const char js_iterator_str[] = "__iterator__"; +const char js_join_str[] = "join"; +const char js_lastIndex_str[] = "lastIndex"; +const char js_length_str[] = "length"; +const char js_lineNumber_str[] = "lineNumber"; +const char js_message_str[] = "message"; +const char js_multiline_str[] = "multiline"; +const char js_name_str[] = "name"; +const char js_next_str[] = "next"; +const char js_noSuchMethod_str[] = "__noSuchMethod__"; +const char js_object_str[] = "object"; +const char js_proto_str[] = "__proto__"; +const char js_setter_str[] = "setter"; +const char js_set_str[] = "set"; +const char js_source_str[] = "source"; +const char js_stack_str[] = "stack"; +const char js_sticky_str[] = "sticky"; +const char js_toGMTString_str[] = "toGMTString"; +const char js_toLocaleString_str[] = "toLocaleString"; +const char js_toSource_str[] = "toSource"; +const char js_toString_str[] = "toString"; +const char js_toUTCString_str[] = "toUTCString"; +const char js_undefined_str[] = "undefined"; +const char js_valueOf_str[] = "valueOf"; +const char js_toJSON_str[] = "toJSON"; +const char js_enumerable_str[] = "enumerable"; +const char js_configurable_str[] = "configurable"; +const char js_writable_str[] = "writable"; +const char js_value_str[] = "value"; +const char js_test_str[] = "test"; + +#if JS_HAS_XML_SUPPORT +const char js_etago_str[] = ""; +const char js_qualifier_str[] = "::"; +const char js_space_str[] = " "; +const char js_stago_str[] = "<"; +const char js_star_str[] = "*"; +const char js_starQualifier_str[] = "*::"; +const char js_tagc_str[] = ">"; +const char js_xml_str[] = "xml"; +#endif + +#if JS_HAS_GENERATORS +const char js_close_str[] = "close"; +const char js_send_str[] = "send"; +#endif + +/* + * Helper macros to access and modify JSAtomHashEntry. + */ + +inline AtomEntryType +StringToInitialAtomEntry(JSString *str) +{ + return (AtomEntryType) str; +} + +inline uintN +AtomEntryFlags(AtomEntryType entry) +{ + return (uintN) (entry & ATOM_ENTRY_FLAG_MASK); +} + +/* + * Conceptually, we have compressed a HashMap into a + * HashMap. Here, we promise that we are only changing the "value" of + * the HashMap entry, so the const_cast is safe. + */ + +inline void +AddAtomEntryFlags(const AtomEntryType &entry, uintN flags) +{ + const_cast(entry) |= AtomEntryType(flags); +} + +inline void +ClearAtomEntryFlags(const AtomEntryType &entry, uintN flags) +{ + const_cast(entry) &= ~AtomEntryType(flags); +} + +/* + * For a browser build from 2007-08-09 after the browser starts up there are + * just 55 double atoms, but over 15000 string atoms. Not to penalize more + * economical embeddings allocating too much memory initially we initialize + * atomized strings with just 1K entries. + */ +#define JS_STRING_HASH_COUNT 1024 + +JSBool +js_InitAtomState(JSRuntime *rt) +{ + JSAtomState *state = &rt->atomState; + + JS_ASSERT(!state->atoms.initialized()); + if (!state->atoms.init(JS_STRING_HASH_COUNT)) + return false; + +#ifdef JS_THREADSAFE + js_InitLock(&state->lock); +#endif + JS_ASSERT(state->atoms.initialized()); + return JS_TRUE; +} + +void +js_FinishAtomState(JSRuntime *rt) +{ + JSAtomState *state = &rt->atomState; + + if (!state->atoms.initialized()) { + /* + * We are called with uninitialized state when JS_NewRuntime fails and + * calls JS_DestroyRuntime on a partially initialized runtime. + */ + return; + } + + for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) { + JSString *str = AtomEntryToKey(r.front()); + js_FinalizeStringRT(rt, str); + } + +#ifdef JS_THREADSAFE + js_FinishLock(&state->lock); +#endif +} + +JSBool +js_InitCommonAtoms(JSContext *cx) +{ + JSAtomState *state = &cx->runtime->atomState; + uintN i; + JSAtom **atoms; + + atoms = COMMON_ATOMS_START(state); + for (i = 0; i < JS_ARRAY_LENGTH(js_common_atom_names); i++, atoms++) { + *atoms = js_Atomize(cx, js_common_atom_names[i], + strlen(js_common_atom_names[i]), ATOM_PINNED); + if (!*atoms) + return JS_FALSE; + } + JS_ASSERT((uint8 *)atoms - (uint8 *)state == LAZY_ATOM_OFFSET_START); + memset(atoms, 0, ATOM_OFFSET_LIMIT - LAZY_ATOM_OFFSET_START); + + cx->runtime->emptyString = ATOM_TO_STRING(state->emptyAtom); + return JS_TRUE; +} + +void +js_FinishCommonAtoms(JSContext *cx) +{ + cx->runtime->emptyString = NULL; + JSAtomState *state = &cx->runtime->atomState; + + for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) + ClearAtomEntryFlags(r.front(), ATOM_PINNED); + +#ifdef DEBUG + memset(COMMON_ATOMS_START(state), JS_FREE_PATTERN, + ATOM_OFFSET_LIMIT - ATOM_OFFSET_START); +#endif +} + +void +js_TraceAtomState(JSTracer *trc) +{ + JSRuntime *rt = trc->context->runtime; + JSAtomState *state = &rt->atomState; + +#ifdef DEBUG + size_t number = 0; +#endif + + if (rt->gcKeepAtoms) { + for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) { + JS_SET_TRACING_INDEX(trc, "locked_atom", number++); + MarkString(trc, AtomEntryToKey(r.front())); + } + } else { + for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) { + AtomEntryType entry = r.front(); + uintN flags = AtomEntryFlags(entry); + if (flags & (ATOM_PINNED | ATOM_INTERNED)) { + JS_SET_TRACING_INDEX(trc, + flags & ATOM_PINNED + ? "pinned_atom" + : "interned_atom", + number++); + MarkString(trc, AtomEntryToKey(entry)); + } + } + } +} + +void +js_SweepAtomState(JSContext *cx) +{ + JSAtomState *state = &cx->runtime->atomState; + + for (AtomSet::Enum e(state->atoms); !e.empty(); e.popFront()) { + AtomEntryType entry = e.front(); + if (AtomEntryFlags(entry) & (ATOM_PINNED | ATOM_INTERNED)) { + /* Pinned or interned key cannot be finalized. */ + JS_ASSERT(!IsAboutToBeFinalized(cx, AtomEntryToKey(entry))); + } else if (IsAboutToBeFinalized(cx, AtomEntryToKey(entry))) { + e.removeFront(); + } + } +} + +JSAtom * +js_AtomizeString(JSContext *cx, JSString *strArg, uintN flags) +{ + JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_TMPSTR|ATOM_NOCOPY))); + JS_ASSERT_IF(flags & ATOM_NOCOPY, flags & ATOM_TMPSTR); + + if (strArg->isAtomized()) + return STRING_TO_ATOM(strArg); + + JSLinearString *str = strArg->ensureLinear(cx); + if (!str) + return NULL; + + const jschar *chars = str->chars(); + size_t length = str->length(); + + JSString *staticStr = JSString::lookupStaticString(chars, length); + if (staticStr) + return STRING_TO_ATOM(staticStr); + + JSAtomState *state = &cx->runtime->atomState; + AtomSet &atoms = state->atoms; + + AutoLockAtomsCompartment lock(cx); + AtomSet::AddPtr p = atoms.lookupForAdd(str); + + /* Hashing the string should have flattened it if it was a rope. */ + JS_ASSERT(str->isFlat() || str->isDependent()); + + JSLinearString *key; + if (p) { + key = AtomEntryToKey(*p); + } else { + /* + * Ensure that any atomized string lives only in the default + * compartment. + */ + bool needNewString = !!(flags & ATOM_TMPSTR) || + str->asCell()->compartment() != cx->runtime->atomsCompartment; + + /* + * Unless str is already comes from the default compartment and flat, + * we have to relookup the key as the last ditch GC invoked from the + * string allocation or OOM handling may unlock the default + * compartment lock. + */ + if (!needNewString && str->isFlat()) { + str->flatClearExtensible(); + key = str; + atoms.add(p, StringToInitialAtomEntry(key)); + } else { + if (needNewString) { + SwitchToCompartment sc(cx, cx->runtime->atomsCompartment); + if (flags & ATOM_NOCOPY) { + key = js_NewString(cx, const_cast(str->flatChars()), length); + if (!key) + return NULL; + + /* Finish handing off chars to the GC'ed key string. */ + JS_ASSERT(flags & ATOM_TMPSTR); + str->u.chars = NULL; + } else { + key = js_NewStringCopyN(cx, chars, length); + if (!key) + return NULL; + } + } else { + JS_ASSERT(str->isDependent()); + if (!str->undepend(cx)) + return NULL; + key = str; + } + + if (!atoms.relookupOrAdd(p, key, StringToInitialAtomEntry(key))) { + JS_ReportOutOfMemory(cx); /* SystemAllocPolicy does not report */ + return NULL; + } + } + key->flatSetAtomized(); + } + + AddAtomEntryFlags(*p, flags & (ATOM_PINNED | ATOM_INTERNED)); + + JSAtom *atom = STRING_TO_ATOM(key); + return atom; +} + +JSAtom * +js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags) +{ + jschar *chars; + JSString str; + JSAtom *atom; + + CHECK_REQUEST(cx); + + /* + * Avoiding the malloc in js_InflateString on shorter strings saves us + * over 20,000 malloc calls on mozilla browser startup. This compares to + * only 131 calls where the string is longer than a 31 char (net) buffer. + * The vast majority of atomized strings are already in the hashtable. So + * js_AtomizeString rarely has to copy the temp string we make. + */ +#define ATOMIZE_BUF_MAX 32 + jschar inflated[ATOMIZE_BUF_MAX]; + size_t inflatedLength = ATOMIZE_BUF_MAX - 1; + + if (length < ATOMIZE_BUF_MAX) { + js_InflateStringToBuffer(cx, bytes, length, inflated, &inflatedLength); + inflated[inflatedLength] = 0; + chars = inflated; + } else { + inflatedLength = length; + chars = js_InflateString(cx, bytes, &inflatedLength); + if (!chars) + return NULL; + flags |= ATOM_NOCOPY; + } + + str.initFlat(chars, inflatedLength); + atom = js_AtomizeString(cx, &str, ATOM_TMPSTR | flags); + if (chars != inflated && str.flatChars()) + cx->free(chars); + return atom; +} + +JSAtom * +js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags) +{ + JSString str; + + CHECK_REQUEST(cx); + + if (!CheckStringLength(cx, length)) + return NULL; + + str.initFlatNotTerminated((jschar *)chars, length); + return js_AtomizeString(cx, &str, ATOM_TMPSTR | flags); +} + +JSAtom * +js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length) +{ + JSString str, *str2; + JSAtomState *state; + + if (length == 1) { + jschar c = *chars; + if (c < UNIT_STRING_LIMIT) + return STRING_TO_ATOM(JSString::unitString(c)); + } + + str.initFlatNotTerminated((jschar *)chars, length); + state = &cx->runtime->atomState; + + JS_LOCK(cx, &state->lock); + AtomSet::Ptr p = state->atoms.lookup(str.assertIsFlat()); + str2 = p ? AtomEntryToKey(*p) : NULL; + JS_UNLOCK(cx, &state->lock); + + return str2 ? STRING_TO_ATOM(str2) : NULL; +} + +#ifdef DEBUG +JS_FRIEND_API(void) +js_DumpAtoms(JSContext *cx, FILE *fp) +{ + JSAtomState *state = &cx->runtime->atomState; + + fprintf(fp, "atoms table contents:\n"); + unsigned number = 0; + for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) { + AtomEntryType entry = r.front(); + fprintf(fp, "%3u ", number++); + if (entry == 0) { + fputs("", fp); + } else { + JSAtom *key = AtomEntryToKey(entry); + FileEscapedString(fp, key, '"'); + uintN flags = AtomEntryFlags(entry); + if (flags != 0) { + fputs((flags & (ATOM_PINNED | ATOM_INTERNED)) + ? " pinned | interned" + : (flags & ATOM_PINNED) ? " pinned" : " interned", + fp); + } + } + putc('\n', fp); + } + putc('\n', fp); +} +#endif + +static JSHashNumber +js_hash_atom_ptr(const void *key) +{ + const JSAtom *atom = (const JSAtom *) key; + return ATOM_HASH(atom); +} + +#if JS_BITS_PER_WORD == 32 +# define TEMP_SIZE_START_LOG2 5 +#else +# define TEMP_SIZE_START_LOG2 6 +#endif +#define TEMP_SIZE_LIMIT_LOG2 (TEMP_SIZE_START_LOG2 + NUM_TEMP_FREELISTS) + +#define TEMP_SIZE_START JS_BIT(TEMP_SIZE_START_LOG2) +#define TEMP_SIZE_LIMIT JS_BIT(TEMP_SIZE_LIMIT_LOG2) + +JS_STATIC_ASSERT(TEMP_SIZE_START >= sizeof(JSHashTable)); + +static void * +js_alloc_temp_space(void *priv, size_t size) +{ + Parser *parser = (Parser *) priv; + + void *space; + if (size < TEMP_SIZE_LIMIT) { + int bin = JS_CeilingLog2(size) - TEMP_SIZE_START_LOG2; + JS_ASSERT(unsigned(bin) < NUM_TEMP_FREELISTS); + + space = parser->tempFreeList[bin]; + if (space) { + parser->tempFreeList[bin] = *(void **)space; + return space; + } + } + + JS_ARENA_ALLOCATE(space, &parser->context->tempPool, size); + if (!space) + js_ReportOutOfScriptQuota(parser->context); + return space; +} + +static void +js_free_temp_space(void *priv, void *item, size_t size) +{ + if (size >= TEMP_SIZE_LIMIT) + return; + + Parser *parser = (Parser *) priv; + int bin = JS_CeilingLog2(size) - TEMP_SIZE_START_LOG2; + JS_ASSERT(unsigned(bin) < NUM_TEMP_FREELISTS); + + *(void **)item = parser->tempFreeList[bin]; + parser->tempFreeList[bin] = item; +} + +static JSHashEntry * +js_alloc_temp_entry(void *priv, const void *key) +{ + Parser *parser = (Parser *) priv; + JSAtomListElement *ale; + + ale = parser->aleFreeList; + if (ale) { + parser->aleFreeList = ALE_NEXT(ale); + return &ale->entry; + } + + JS_ARENA_ALLOCATE_TYPE(ale, JSAtomListElement, &parser->context->tempPool); + if (!ale) { + js_ReportOutOfScriptQuota(parser->context); + return NULL; + } + return &ale->entry; +} + +static void +js_free_temp_entry(void *priv, JSHashEntry *he, uintN flag) +{ + Parser *parser = (Parser *) priv; + JSAtomListElement *ale = (JSAtomListElement *) he; + + ALE_SET_NEXT(ale, parser->aleFreeList); + parser->aleFreeList = ale; +} + +static JSHashAllocOps temp_alloc_ops = { + js_alloc_temp_space, js_free_temp_space, + js_alloc_temp_entry, js_free_temp_entry +}; + +JSAtomListElement * +JSAtomList::rawLookup(JSAtom *atom, JSHashEntry **&hep) +{ + if (table) { + hep = JS_HashTableRawLookup(table, ATOM_HASH(atom), atom); + return (JSAtomListElement *) *hep; + } + + JSHashEntry **alep = &list; + hep = NULL; + JSAtomListElement *ale; + while ((ale = (JSAtomListElement *)*alep) != NULL) { + if (ALE_ATOM(ale) == atom) { + /* Hit, move atom's element to the front of the list. */ + *alep = ale->entry.next; + ale->entry.next = list; + list = &ale->entry; + break; + } + alep = &ale->entry.next; + } + return ale; +} + +#define ATOM_LIST_HASH_THRESHOLD 12 + +JSAtomListElement * +JSAtomList::add(Parser *parser, JSAtom *atom, AddHow how) +{ + JS_ASSERT(!set); + + JSAtomListElement *ale, *ale2, *next; + JSHashEntry **hep; + + ale = rawLookup(atom, hep); + if (!ale || how != UNIQUE) { + if (count < ATOM_LIST_HASH_THRESHOLD && !table) { + /* Few enough for linear search and no hash table yet needed. */ + ale = (JSAtomListElement *)js_alloc_temp_entry(parser, atom); + if (!ale) + return NULL; + ALE_SET_ATOM(ale, atom); + + if (how == HOIST) { + ale->entry.next = NULL; + hep = (JSHashEntry **) &list; + while (*hep) + hep = &(*hep)->next; + *hep = &ale->entry; + } else { + ale->entry.next = list; + list = &ale->entry; + } + } else { + /* + * We should hash, or else we already are hashing, but count was + * reduced by JSAtomList::rawRemove below ATOM_LIST_HASH_THRESHOLD. + * Check whether we should create the table. + */ + if (!table) { + /* No hash table yet, so hep had better be null! */ + JS_ASSERT(!hep); + table = JS_NewHashTable(count + 1, js_hash_atom_ptr, + JS_CompareValues, JS_CompareValues, + &temp_alloc_ops, parser); + if (!table) + return NULL; + + /* + * Set ht->nentries explicitly, because we are moving entries + * from list to ht, not calling JS_HashTable(Raw|)Add. + */ + table->nentries = count; + + /* + * Insert each ale on list into the new hash table. Append to + * the hash chain rather than inserting at the bucket head, to + * preserve order among entries with the same key. + */ + for (ale2 = (JSAtomListElement *)list; ale2; ale2 = next) { + next = ALE_NEXT(ale2); + ale2->entry.keyHash = ATOM_HASH(ALE_ATOM(ale2)); + hep = JS_HashTableRawLookup(table, ale2->entry.keyHash, + ale2->entry.key); + while (*hep) + hep = &(*hep)->next; + *hep = &ale2->entry; + ale2->entry.next = NULL; + } + list = NULL; + + /* Set hep for insertion of atom's ale, immediately below. */ + hep = JS_HashTableRawLookup(table, ATOM_HASH(atom), atom); + } + + /* Finally, add an entry for atom into the hash bucket at hep. */ + ale = (JSAtomListElement *) + JS_HashTableRawAdd(table, hep, ATOM_HASH(atom), atom, NULL); + if (!ale) + return NULL; + + /* + * If hoisting, move ale to the end of its chain after we called + * JS_HashTableRawAdd, since RawAdd may have grown the table and + * then recomputed hep to refer to the pointer to the first entry + * with the given key. + */ + if (how == HOIST && ale->entry.next) { + JS_ASSERT(*hep == &ale->entry); + *hep = ale->entry.next; + ale->entry.next = NULL; + do { + hep = &(*hep)->next; + } while (*hep); + *hep = &ale->entry; + } + } + + ALE_SET_INDEX(ale, count++); + } + return ale; +} + +void +JSAtomList::rawRemove(Parser *parser, JSAtomListElement *ale, JSHashEntry **hep) +{ + JS_ASSERT(!set); + JS_ASSERT(count != 0); + + if (table) { + JS_ASSERT(hep); + JS_HashTableRawRemove(table, hep, &ale->entry); + } else { + JS_ASSERT(!hep); + hep = &list; + while (*hep != &ale->entry) { + JS_ASSERT(*hep); + hep = &(*hep)->next; + } + *hep = ale->entry.next; + js_free_temp_entry(parser, &ale->entry, HT_FREE_ENTRY); + } + + --count; +} + +JSAutoAtomList::~JSAutoAtomList() +{ + if (table) { + JS_HashTableDestroy(table); + } else { + JSHashEntry *hep = list; + while (hep) { + JSHashEntry *next = hep->next; + js_free_temp_entry(parser, hep, HT_FREE_ENTRY); + hep = next; + } + } +} + +JSAtomListElement * +JSAtomListIterator::operator ()() +{ + JSAtomListElement *ale; + JSHashTable *ht; + + if (index == uint32(-1)) + return NULL; + + ale = next; + if (!ale) { + ht = list->table; + if (!ht) + goto done; + do { + if (index == JS_BIT(JS_HASH_BITS - ht->shift)) + goto done; + next = (JSAtomListElement *) ht->buckets[index++]; + } while (!next); + ale = next; + } + + next = ALE_NEXT(ale); + return ale; + + done: + index = uint32(-1); + return NULL; +} + +static intN +js_map_atom(JSHashEntry *he, intN i, void *arg) +{ + JSAtomListElement *ale = (JSAtomListElement *)he; + JSAtom **vector = (JSAtom **) arg; + + vector[ALE_INDEX(ale)] = ALE_ATOM(ale); + return HT_ENUMERATE_NEXT; +} + +#ifdef DEBUG +static jsrefcount js_atom_map_count; +static jsrefcount js_atom_map_hash_table_count; +#endif + +void +js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al) +{ + JSAtom **vector; + JSAtomListElement *ale; + uint32 count; + + /* Map length must already be initialized. */ + JS_ASSERT(al->count == map->length); +#ifdef DEBUG + JS_ATOMIC_INCREMENT(&js_atom_map_count); +#endif + ale = (JSAtomListElement *)al->list; + if (!ale && !al->table) { + JS_ASSERT(!map->vector); + return; + } + + count = al->count; + vector = map->vector; + if (al->table) { +#ifdef DEBUG + JS_ATOMIC_INCREMENT(&js_atom_map_hash_table_count); +#endif + JS_HashTableEnumerateEntries(al->table, js_map_atom, vector); + } else { + do { + vector[ALE_INDEX(ale)] = ALE_ATOM(ale); + } while ((ale = ALE_NEXT(ale)) != NULL); + } + al->clear(); +} + +#if JS_HAS_XML_SUPPORT +bool +js_InternNonIntElementIdSlow(JSContext *cx, JSObject *obj, const Value &idval, + jsid *idp) +{ + JS_ASSERT(idval.isObject()); + if (obj->isXML()) { + *idp = OBJECT_TO_JSID(&idval.toObject()); + return true; + } + + if (!js_IsFunctionQName(cx, &idval.toObject(), idp)) + return JS_FALSE; + if (!JSID_IS_VOID(*idp)) + return true; + + return js_ValueToStringId(cx, idval, idp); +} + +bool +js_InternNonIntElementIdSlow(JSContext *cx, JSObject *obj, const Value &idval, + jsid *idp, Value *vp) +{ + JS_ASSERT(idval.isObject()); + if (obj->isXML()) { + JSObject &idobj = idval.toObject(); + *idp = OBJECT_TO_JSID(&idobj); + vp->setObject(idobj); + return true; + } + + if (!js_IsFunctionQName(cx, &idval.toObject(), idp)) + return JS_FALSE; + if (!JSID_IS_VOID(*idp)) { + *vp = IdToValue(*idp); + return true; + } + + if (js_ValueToStringId(cx, idval, idp)) { + vp->setString(JSID_TO_STRING(*idp)); + return true; + } + return false; +} +#endif diff --git a/js/src/jsatom.h b/js/src/jsatom.h new file mode 100644 index 0000000..ced0ebc --- /dev/null +++ b/js/src/jsatom.h @@ -0,0 +1,614 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsatom_h___ +#define jsatom_h___ +/* + * JS atom table. + */ +#include +#include "jsversion.h" +#include "jsapi.h" +#include "jsprvtd.h" +#include "jshash.h" +#include "jshashtable.h" +#include "jspubtd.h" +#include "jsstr.h" +#include "jslock.h" +#include "jsvalue.h" + +#define ATOM_PINNED 0x1 /* atom is pinned against GC */ +#define ATOM_INTERNED 0x2 /* pinned variant for JS_Intern* API */ +#define ATOM_NOCOPY 0x4 /* don't copy atom string bytes */ +#define ATOM_TMPSTR 0x8 /* internal, to avoid extra string */ + +#define STRING_TO_ATOM(str) (JS_ASSERT(str->isAtomized()), \ + (JSAtom *)str) +#define ATOM_TO_STRING(atom) (atom) +#define ATOM_TO_JSVAL(atom) STRING_TO_JSVAL(ATOM_TO_STRING(atom)) + +/* Engine-internal extensions of jsid */ + +static JS_ALWAYS_INLINE jsid +JSID_FROM_BITS(size_t bits) +{ + jsid id; + JSID_BITS(id) = bits; + return id; +} + +static JS_ALWAYS_INLINE jsid +ATOM_TO_JSID(JSAtom *atom) +{ + JS_ASSERT(((size_t)atom & 0x7) == 0); + return JSID_FROM_BITS((size_t)atom); +} + +/* All strings stored in jsids are atomized. */ +static JS_ALWAYS_INLINE JSBool +JSID_IS_ATOM(jsid id) +{ + return JSID_IS_STRING(id); +} + +static JS_ALWAYS_INLINE JSBool +JSID_IS_ATOM(jsid id, JSAtom *atom) +{ + return JSID_BITS(id) == JSID_BITS(ATOM_TO_JSID(atom)); +} + +static JS_ALWAYS_INLINE JSAtom * +JSID_TO_ATOM(jsid id) +{ + return (JSAtom *)JSID_TO_STRING(id); +} + +namespace js { + +static JS_ALWAYS_INLINE Value +IdToValue(jsid id) +{ + if (JSID_IS_STRING(id)) + return StringValue(JSID_TO_STRING(id)); + if (JS_LIKELY(JSID_IS_INT(id))) + return Int32Value(JSID_TO_INT(id)); + if (JS_LIKELY(JSID_IS_OBJECT(id))) + return ObjectValue(*JSID_TO_OBJECT(id)); + JS_ASSERT(JSID_IS_DEFAULT_XML_NAMESPACE(id) || JSID_IS_VOID(id)); + return UndefinedValue(); +} + +static JS_ALWAYS_INLINE jsval +IdToJsval(jsid id) +{ + return Jsvalify(IdToValue(id)); +} + +} + +#if JS_BYTES_PER_WORD == 4 +# define ATOM_HASH(atom) ((JSHashNumber)(atom) >> 2) +#elif JS_BYTES_PER_WORD == 8 +# define ATOM_HASH(atom) (((JSHashNumber)(jsuword)(atom) >> 3) ^ \ + (JSHashNumber)((jsuword)(atom) >> 32)) +#else +# error "Unsupported configuration" +#endif + +/* + * Return a printable, lossless char[] representation of a string-type atom. + * The lifetime of the result matches the lifetime of bytes. + */ +extern const char * +js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes); + +struct JSAtomListElement { + JSHashEntry entry; +}; + +#define ALE_ATOM(ale) ((JSAtom *) (ale)->entry.key) +#define ALE_INDEX(ale) (jsatomid(uintptr_t((ale)->entry.value))) +#define ALE_VALUE(ale) ((jsboxedword) (ale)->entry.value) +#define ALE_NEXT(ale) ((JSAtomListElement *) (ale)->entry.next) + +/* + * In an upvars list, ALE_DEFN(ale)->resolve() is the outermost definition the + * name may reference. If a with block or a function that calls eval encloses + * the use, the name may end up referring to something else at runtime. + */ +#define ALE_DEFN(ale) ((JSDefinition *) (ale)->entry.value) + +#define ALE_SET_ATOM(ale,atom) ((ale)->entry.key = (const void *)(atom)) +#define ALE_SET_INDEX(ale,index)((ale)->entry.value = (void *)(index)) +#define ALE_SET_DEFN(ale, dn) ((ale)->entry.value = (void *)(dn)) +#define ALE_SET_VALUE(ale, v) ((ale)->entry.value = (void *)(v)) +#define ALE_SET_NEXT(ale,nxt) ((ale)->entry.next = (JSHashEntry *)(nxt)) + +/* + * NB: JSAtomSet must be plain-old-data as it is embedded in the pn_u union in + * JSParseNode. JSAtomList encapsulates all operational uses of a JSAtomSet. + * + * The JSAtomList name is traditional, even though the implementation is a map + * (not to be confused with JSAtomMap). In particular the "ALE" and "ale" short + * names for JSAtomListElement variables roll off the fingers, compared to ASE + * or AME alternatives. + */ +struct JSAtomSet { + JSHashEntry *list; /* literals indexed for mapping */ + JSHashTable *table; /* hash table if list gets too long */ + jsuint count; /* count of indexed literals */ +}; + +struct JSAtomList : public JSAtomSet +{ +#ifdef DEBUG + const JSAtomSet* set; /* asserted null in mutating methods */ +#endif + + JSAtomList() { + list = NULL; table = NULL; count = 0; +#ifdef DEBUG + set = NULL; +#endif + } + + JSAtomList(const JSAtomSet& as) { + list = as.list; table = as.table; count = as.count; +#ifdef DEBUG + set = &as; +#endif + } + + void clear() { JS_ASSERT(!set); list = NULL; table = NULL; count = 0; } + + JSAtomListElement *lookup(JSAtom *atom) { + JSHashEntry **hep; + return rawLookup(atom, hep); + } + + JSAtomListElement *rawLookup(JSAtom *atom, JSHashEntry **&hep); + + enum AddHow { UNIQUE, SHADOW, HOIST }; + + JSAtomListElement *add(js::Parser *parser, JSAtom *atom, AddHow how = UNIQUE); + + void remove(js::Parser *parser, JSAtom *atom) { + JSHashEntry **hep; + JSAtomListElement *ale = rawLookup(atom, hep); + if (ale) + rawRemove(parser, ale, hep); + } + + void rawRemove(js::Parser *parser, JSAtomListElement *ale, JSHashEntry **hep); +}; + +/* + * A subclass of JSAtomList with a destructor. This atom list owns its + * hash table and its entries, but no keys or values. + */ +struct JSAutoAtomList: public JSAtomList +{ + JSAutoAtomList(js::Parser *p): parser(p) {} + ~JSAutoAtomList(); + private: + js::Parser *parser; /* For freeing list entries. */ +}; + +/* + * Iterate over an atom list. We define a call operator to minimize the syntax + * tax for users. We do not use a more standard pattern using ++ and * because + * (a) it's the wrong pattern for a non-scalar; (b) it's overkill -- one method + * is enough. (This comment is overkill!) + */ +class JSAtomListIterator { + JSAtomList* list; + JSAtomListElement* next; + uint32 index; + + public: + JSAtomListIterator(JSAtomList* al) : list(al) { reset(); } + + void reset() { + next = (JSAtomListElement *) list->list; + index = 0; + } + + JSAtomListElement* operator ()(); +}; + +struct JSAtomMap { + JSAtom **vector; /* array of ptrs to indexed atoms */ + jsatomid length; /* count of (to-be-)indexed atoms */ +}; + +namespace js { + +#define ATOM_ENTRY_FLAG_MASK ((size_t)(ATOM_PINNED | ATOM_INTERNED)) + +JS_STATIC_ASSERT(ATOM_ENTRY_FLAG_MASK < JS_GCTHING_ALIGN); + +typedef uintptr_t AtomEntryType; + +static JS_ALWAYS_INLINE JSAtom * +AtomEntryToKey(AtomEntryType entry) +{ + JS_ASSERT(entry != 0); + return (JSAtom *)(entry & ~ATOM_ENTRY_FLAG_MASK); +} + +struct AtomHasher +{ + typedef JSLinearString *Lookup; + + static HashNumber hash(JSLinearString *str) { + return js_HashString(str); + } + + static bool match(AtomEntryType entry, JSLinearString *lookup) { + return entry ? EqualStrings(AtomEntryToKey(entry), lookup) : false; + } +}; + +typedef HashSet AtomSet; + +} /* namespace js */ + +struct JSAtomState +{ + js::AtomSet atoms; + +#ifdef JS_THREADSAFE + JSThinLock lock; +#endif + + /* + * From this point until the end of struct definition the struct must + * contain only JSAtom fields. We use this to access the storage occupied + * by the common atoms in js_FinishCommonAtoms. + * + * js_common_atom_names defined in jsatom.c contains C strings for atoms + * in the order of atom fields here. Therefore you must update that array + * if you change member order here. + */ + + /* The rt->emptyString atom, see jsstr.c's js_InitRuntimeStringState. */ + JSAtom *emptyAtom; + + /* + * Literal value and type names. + * NB: booleanAtoms must come right before typeAtoms! + */ + JSAtom *booleanAtoms[2]; + JSAtom *typeAtoms[JSTYPE_LIMIT]; + JSAtom *nullAtom; + + /* Standard class constructor or prototype names. */ + JSAtom *classAtoms[JSProto_LIMIT]; + + /* Various built-in or commonly-used atoms, pinned on first context. */ + JSAtom *anonymousAtom; + JSAtom *applyAtom; + JSAtom *argumentsAtom; + JSAtom *arityAtom; + JSAtom *callAtom; + JSAtom *calleeAtom; + JSAtom *callerAtom; + JSAtom *classPrototypeAtom; + JSAtom *constructorAtom; + JSAtom *eachAtom; + JSAtom *evalAtom; + JSAtom *fileNameAtom; + JSAtom *getAtom; + JSAtom *globalAtom; + JSAtom *ignoreCaseAtom; + JSAtom *indexAtom; + JSAtom *inputAtom; + JSAtom *toISOStringAtom; + JSAtom *iteratorAtom; + JSAtom *joinAtom; + JSAtom *lastIndexAtom; + JSAtom *lengthAtom; + JSAtom *lineNumberAtom; + JSAtom *messageAtom; + JSAtom *multilineAtom; + JSAtom *nameAtom; + JSAtom *nextAtom; + JSAtom *noSuchMethodAtom; + JSAtom *objectNullAtom; + JSAtom *objectUndefinedAtom; + JSAtom *protoAtom; + JSAtom *setAtom; + JSAtom *sourceAtom; + JSAtom *stackAtom; + JSAtom *stickyAtom; + JSAtom *toGMTStringAtom; + JSAtom *toLocaleStringAtom; + JSAtom *toSourceAtom; + JSAtom *toStringAtom; + JSAtom *toUTCStringAtom; + JSAtom *valueOfAtom; + JSAtom *toJSONAtom; + JSAtom *void0Atom; + JSAtom *enumerableAtom; + JSAtom *configurableAtom; + JSAtom *writableAtom; + JSAtom *valueAtom; + JSAtom *testAtom; + JSAtom *useStrictAtom; + JSAtom *locAtom; + JSAtom *lineAtom; + JSAtom *InfinityAtom; + JSAtom *NaNAtom; + JSAtom *builderAtom; + +#if JS_HAS_XML_SUPPORT + JSAtom *etagoAtom; + JSAtom *namespaceAtom; + JSAtom *ptagcAtom; + JSAtom *qualifierAtom; + JSAtom *spaceAtom; + JSAtom *stagoAtom; + JSAtom *starAtom; + JSAtom *starQualifierAtom; + JSAtom *tagcAtom; + JSAtom *xmlAtom; + + /* Represents an invalid URI, for internal use only. */ + JSAtom *functionNamespaceURIAtom; +#endif + + JSAtom *ProxyAtom; + + JSAtom *getOwnPropertyDescriptorAtom; + JSAtom *getPropertyDescriptorAtom; + JSAtom *definePropertyAtom; + JSAtom *deleteAtom; + JSAtom *getOwnPropertyNamesAtom; + JSAtom *enumerateAtom; + JSAtom *fixAtom; + + JSAtom *hasAtom; + JSAtom *hasOwnAtom; + JSAtom *keysAtom; + JSAtom *iterateAtom; + + /* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */ + struct { + JSAtom *XMLListAtom; + JSAtom *decodeURIAtom; + JSAtom *decodeURIComponentAtom; + JSAtom *defineGetterAtom; + JSAtom *defineSetterAtom; + JSAtom *encodeURIAtom; + JSAtom *encodeURIComponentAtom; + JSAtom *escapeAtom; + JSAtom *hasOwnPropertyAtom; + JSAtom *isFiniteAtom; + JSAtom *isNaNAtom; + JSAtom *isPrototypeOfAtom; + JSAtom *isXMLNameAtom; + JSAtom *lookupGetterAtom; + JSAtom *lookupSetterAtom; + JSAtom *parseFloatAtom; + JSAtom *parseIntAtom; + JSAtom *propertyIsEnumerableAtom; + JSAtom *unescapeAtom; + JSAtom *unevalAtom; + JSAtom *unwatchAtom; + JSAtom *watchAtom; + } lazy; +}; + +#define ATOM(name) cx->runtime->atomState.name##Atom + +#define ATOM_OFFSET_START offsetof(JSAtomState, emptyAtom) +#define LAZY_ATOM_OFFSET_START offsetof(JSAtomState, lazy) +#define ATOM_OFFSET_LIMIT (sizeof(JSAtomState)) + +#define COMMON_ATOMS_START(state) \ + ((JSAtom **)((uint8 *)(state) + ATOM_OFFSET_START)) +#define COMMON_ATOM_INDEX(name) \ + ((offsetof(JSAtomState, name##Atom) - ATOM_OFFSET_START) \ + / sizeof(JSAtom*)) +#define COMMON_TYPE_ATOM_INDEX(type) \ + ((offsetof(JSAtomState, typeAtoms[type]) - ATOM_OFFSET_START) \ + / sizeof(JSAtom*)) + +#define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom) +#define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off))) +#define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState,classAtoms[JSProto_##name]) + +#define CLASS_ATOM(cx,name) \ + ((cx)->runtime->atomState.classAtoms[JSProto_##name]) + +extern const char *const js_common_atom_names[]; +extern const size_t js_common_atom_count; + +/* + * Macros to access C strings for JSType and boolean literals. + */ +#define JS_BOOLEAN_STR(type) (js_common_atom_names[1 + (type)]) +#define JS_TYPE_STR(type) (js_common_atom_names[1 + 2 + (type)]) + +/* Well-known predefined C strings. */ +#define JS_PROTO(name,code,init) extern const char js_##name##_str[]; +#include "jsproto.tbl" +#undef JS_PROTO + +extern const char js_anonymous_str[]; +extern const char js_apply_str[]; +extern const char js_arguments_str[]; +extern const char js_arity_str[]; +extern const char js_call_str[]; +extern const char js_callee_str[]; +extern const char js_caller_str[]; +extern const char js_class_prototype_str[]; +extern const char js_close_str[]; +extern const char js_constructor_str[]; +extern const char js_count_str[]; +extern const char js_etago_str[]; +extern const char js_each_str[]; +extern const char js_eval_str[]; +extern const char js_fileName_str[]; +extern const char js_get_str[]; +extern const char js_getter_str[]; +extern const char js_global_str[]; +extern const char js_ignoreCase_str[]; +extern const char js_index_str[]; +extern const char js_input_str[]; +extern const char js_iterator_str[]; +extern const char js_join_str[]; +extern const char js_lastIndex_str[]; +extern const char js_length_str[]; +extern const char js_lineNumber_str[]; +extern const char js_message_str[]; +extern const char js_multiline_str[]; +extern const char js_name_str[]; +extern const char js_namespace_str[]; +extern const char js_next_str[]; +extern const char js_noSuchMethod_str[]; +extern const char js_object_str[]; +extern const char js_proto_str[]; +extern const char js_ptagc_str[]; +extern const char js_qualifier_str[]; +extern const char js_send_str[]; +extern const char js_setter_str[]; +extern const char js_set_str[]; +extern const char js_source_str[]; +extern const char js_space_str[]; +extern const char js_stack_str[]; +extern const char js_sticky_str[]; +extern const char js_stago_str[]; +extern const char js_star_str[]; +extern const char js_starQualifier_str[]; +extern const char js_tagc_str[]; +extern const char js_toGMTString_str[]; +extern const char js_toLocaleString_str[]; +extern const char js_toSource_str[]; +extern const char js_toString_str[]; +extern const char js_toUTCString_str[]; +extern const char js_undefined_str[]; +extern const char js_valueOf_str[]; +extern const char js_toJSON_str[]; +extern const char js_xml_str[]; +extern const char js_enumerable_str[]; +extern const char js_configurable_str[]; +extern const char js_writable_str[]; +extern const char js_value_str[]; +extern const char js_test_str[]; + +/* + * Initialize atom state. Return true on success, false on failure to allocate + * memory. The caller must zero rt->atomState before calling this function and + * only call it after js_InitGC successfully returns. + */ +extern JSBool +js_InitAtomState(JSRuntime *rt); + +/* + * Free and clear atom state including any interned string atoms. This + * function must be called before js_FinishGC. + */ +extern void +js_FinishAtomState(JSRuntime *rt); + +/* + * Atom tracing and garbage collection hooks. + */ + +extern void +js_TraceAtomState(JSTracer *trc); + +extern void +js_SweepAtomState(JSContext *cx); + +extern JSBool +js_InitCommonAtoms(JSContext *cx); + +extern void +js_FinishCommonAtoms(JSContext *cx); + +/* + * Find or create the atom for a string. Return null on failure to allocate + * memory. + */ +extern JSAtom * +js_AtomizeString(JSContext *cx, JSString *str, uintN flags); + +extern JSAtom * +js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags); + +extern JSAtom * +js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags); + +/* + * Return an existing atom for the given char array or null if the char + * sequence is currently not atomized. + */ +extern JSAtom * +js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length); + +#ifdef DEBUG + +extern JS_FRIEND_API(void) +js_DumpAtoms(JSContext *cx, FILE *fp); + +#endif + +inline bool +js_ValueToAtom(JSContext *cx, const js::Value &v, JSAtom **atomp); + +inline bool +js_ValueToStringId(JSContext *cx, const js::Value &v, jsid *idp); + +inline bool +js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval, + jsid *idp); +inline bool +js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval, + jsid *idp, js::Value *vp); +/* + * For all unmapped atoms recorded in al, add a mapping from the atom's index + * to its address. map->length must already be set to the number of atoms in + * the list and map->vector must point to pre-allocated memory. + */ +extern void +js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al); + +#endif /* jsatom_h___ */ diff --git a/js/src/jsatominlines.h b/js/src/jsatominlines.h new file mode 100644 index 0000000..17be76f --- /dev/null +++ b/js/src/jsatominlines.h @@ -0,0 +1,145 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsatominlines_h___ +#define jsatominlines_h___ + +#include "jsatom.h" +#include "jsnum.h" + +/* + * Convert v to an atomized string and wrap it as an id. + */ +inline bool +js_ValueToAtom(JSContext *cx, const js::Value &v, JSAtom **atomp) +{ + JSString *str; + JSAtom *atom; + + /* + * Optimize for the common case where v is an already-atomized string. The + * comment in jsstr.h before JSString::flatSetAtomized explains why this is + * thread-safe. The extra rooting via lastAtom (which would otherwise be + * done in js_js_AtomizeString) ensures the caller that the resulting id at + * is least weakly rooted. + */ + if (v.isString()) { + str = v.toString(); + if (str->isAtomized()) { + *atomp = STRING_TO_ATOM(str); + return true; + } + } else { + str = js_ValueToString(cx, v); + if (!str) + return false; + } + atom = js_AtomizeString(cx, str, 0); + if (!atom) + return false; + *atomp = atom; + return true; +} + +inline bool +js_ValueToStringId(JSContext *cx, const js::Value &v, jsid *idp) +{ + JSAtom *atom; + if (js_ValueToAtom(cx, v, &atom)) { + *idp = ATOM_TO_JSID(atom); + return true; + } + return false; +} + +inline bool +js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval, + jsid *idp) +{ + JS_ASSERT(!idval.isInt32() || !INT_FITS_IN_JSID(idval.toInt32())); + +#if JS_HAS_XML_SUPPORT + extern bool js_InternNonIntElementIdSlow(JSContext *, JSObject *, + const js::Value &, jsid *); + if (idval.isObject()) + return js_InternNonIntElementIdSlow(cx, obj, idval, idp); +#endif + + return js_ValueToStringId(cx, idval, idp); +} + +inline bool +js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval, + jsid *idp, js::Value *vp) +{ + JS_ASSERT(!idval.isInt32() || !INT_FITS_IN_JSID(idval.toInt32())); + +#if JS_HAS_XML_SUPPORT + extern bool js_InternNonIntElementIdSlow(JSContext *, JSObject *, + const js::Value &, + jsid *, js::Value *); + if (idval.isObject()) + return js_InternNonIntElementIdSlow(cx, obj, idval, idp, vp); +#endif + + JSAtom *atom; + if (js_ValueToAtom(cx, idval, &atom)) { + *idp = ATOM_TO_JSID(atom); + vp->setString(ATOM_TO_STRING(atom)); + return true; + } + return false; +} + +inline bool +js_Int32ToId(JSContext* cx, int32 index, jsid* id) +{ + if (INT_FITS_IN_JSID(index)) { + *id = INT_TO_JSID(index); + return true; + } + + JSString* str = js_NumberToString(cx, index); + if (!str) + return false; + + return js_ValueToStringId(cx, js::StringValue(str), id); +} + +#endif /* jsatominlines_h___ */ diff --git a/js/src/jsbit.h b/js/src/jsbit.h new file mode 100644 index 0000000..de1e291 --- /dev/null +++ b/js/src/jsbit.h @@ -0,0 +1,305 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsbit_h___ +#define jsbit_h___ + +#include "jstypes.h" +#include "jscompat.h" +#include "jsutil.h" + +JS_BEGIN_EXTERN_C + +/* +** A jsbitmap_t is a long integer that can be used for bitmaps +*/ +typedef jsuword jsbitmap_t; /* NSPR name, a la Unix system types */ +typedef jsbitmap_t jsbitmap; /* JS-style scalar typedef name */ + +#define JS_BITMAP_SIZE(bits) (JS_HOWMANY(bits, JS_BITS_PER_WORD) * \ + sizeof(jsbitmap)) + +#define JS_TEST_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] & \ + ((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1)))) +#define JS_SET_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] |= \ + ((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1)))) +#define JS_CLEAR_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] &= \ + ~((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1)))) + +/* +** Compute the log of the least power of 2 greater than or equal to n +*/ +extern JS_PUBLIC_API(JSIntn) JS_CeilingLog2(JSUint32 i); + +/* +** Compute the log of the greatest power of 2 less than or equal to n +*/ +extern JS_PUBLIC_API(JSIntn) JS_FloorLog2(JSUint32 i); + +/* + * Replace bit-scanning code sequences with CPU-specific instructions to + * speedup calculations of ceiling/floor log2. + * + * With GCC 3.4 or later we can use __builtin_clz for that, see bug 327129. + * + * SWS: Added MSVC intrinsic bitscan support. See bugs 349364 and 356856. + */ +#if defined(_WIN32) && (_MSC_VER >= 1300) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64)) + +unsigned char _BitScanForward(unsigned long * Index, unsigned long Mask); +unsigned char _BitScanReverse(unsigned long * Index, unsigned long Mask); +# pragma intrinsic(_BitScanForward,_BitScanReverse) + +__forceinline static int +__BitScanForward32(unsigned int val) +{ + unsigned long idx; + + _BitScanForward(&idx, (unsigned long)val); + return (int)idx; +} +__forceinline static int +__BitScanReverse32(unsigned int val) +{ + unsigned long idx; + + _BitScanReverse(&idx, (unsigned long)val); + return (int)(31-idx); +} +# define js_bitscan_ctz32(val) __BitScanForward32(val) +# define js_bitscan_clz32(val) __BitScanReverse32(val) +# define JS_HAS_BUILTIN_BITSCAN32 + +#if defined(_M_AMD64) || defined(_M_X64) +unsigned char _BitScanForward64(unsigned long * Index, unsigned __int64 Mask); +unsigned char _BitScanReverse64(unsigned long * Index, unsigned __int64 Mask); +# pragma intrinsic(_BitScanForward64,_BitScanReverse64) + +__forceinline static int +__BitScanForward64(unsigned __int64 val) +{ + unsigned long idx; + + _BitScanForward64(&idx, val); + return (int)idx; +} +__forceinline static int +__BitScanReverse64(unsigned __int64 val) +{ + unsigned long idx; + + _BitScanReverse64(&idx, val); + return (int)(63-idx); +} +# define js_bitscan_ctz64(val) __BitScanForward64(val) +# define js_bitscan_clz64(val) __BitScanReverse64(val) +# define JS_HAS_BUILTIN_BITSCAN64 +#endif +#elif (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + +# define js_bitscan_ctz32(val) __builtin_ctz(val) +# define js_bitscan_clz32(val) __builtin_clz(val) +# define JS_HAS_BUILTIN_BITSCAN32 +# if (JS_BYTES_PER_WORD == 8) +# define js_bitscan_ctz64(val) __builtin_ctzll(val) +# define js_bitscan_clz64(val) __builtin_clzll(val) +# define JS_HAS_BUILTIN_BITSCAN64 +# endif + +#endif + +/* +** Macro version of JS_CeilingLog2: Compute the log of the least power of +** 2 greater than or equal to _n. The result is returned in _log2. +*/ +#ifdef JS_HAS_BUILTIN_BITSCAN32 +/* + * Use intrinsic function or count-leading-zeros to calculate ceil(log2(_n)). + * The macro checks for "n <= 1" and not "n != 0" as js_bitscan_clz32(0) is + * undefined. + */ +# define JS_CEILING_LOG2(_log2,_n) \ + JS_BEGIN_MACRO \ + unsigned int j_ = (unsigned int)(_n); \ + (_log2) = (j_ <= 1 ? 0 : 32 - js_bitscan_clz32(j_ - 1)); \ + JS_END_MACRO +#else +# define JS_CEILING_LOG2(_log2,_n) \ + JS_BEGIN_MACRO \ + JSUint32 j_ = (JSUint32)(_n); \ + (_log2) = 0; \ + if ((j_) & ((j_)-1)) \ + (_log2) += 1; \ + if ((j_) >> 16) \ + (_log2) += 16, (j_) >>= 16; \ + if ((j_) >> 8) \ + (_log2) += 8, (j_) >>= 8; \ + if ((j_) >> 4) \ + (_log2) += 4, (j_) >>= 4; \ + if ((j_) >> 2) \ + (_log2) += 2, (j_) >>= 2; \ + if ((j_) >> 1) \ + (_log2) += 1; \ + JS_END_MACRO +#endif + +/* +** Macro version of JS_FloorLog2: Compute the log of the greatest power of +** 2 less than or equal to _n. The result is returned in _log2. +** +** This is equivalent to finding the highest set bit in the word. +*/ +#ifdef JS_HAS_BUILTIN_BITSCAN32 +/* + * Use js_bitscan_clz32 or count-leading-zeros to calculate floor(log2(_n)). + * Since js_bitscan_clz32(0) is undefined, the macro set the loweset bit to 1 + * to ensure 0 result when _n == 0. + */ +# define JS_FLOOR_LOG2(_log2,_n) \ + JS_BEGIN_MACRO \ + (_log2) = 31 - js_bitscan_clz32(((unsigned int)(_n)) | 1); \ + JS_END_MACRO +#else +# define JS_FLOOR_LOG2(_log2,_n) \ + JS_BEGIN_MACRO \ + JSUint32 j_ = (JSUint32)(_n); \ + (_log2) = 0; \ + if ((j_) >> 16) \ + (_log2) += 16, (j_) >>= 16; \ + if ((j_) >> 8) \ + (_log2) += 8, (j_) >>= 8; \ + if ((j_) >> 4) \ + (_log2) += 4, (j_) >>= 4; \ + if ((j_) >> 2) \ + (_log2) += 2, (j_) >>= 2; \ + if ((j_) >> 1) \ + (_log2) += 1; \ + JS_END_MACRO +#endif + +/* + * Internal function. + * Compute the log of the least power of 2 greater than or equal to n. This is + * a version of JS_CeilingLog2 that operates on unsigned integers with + * CPU-dependant size. + */ +#define JS_CEILING_LOG2W(n) ((n) <= 1 ? 0 : 1 + JS_FLOOR_LOG2W((n) - 1)) + +/* + * Internal function. + * Compute the log of the greatest power of 2 less than or equal to n. + * This is a version of JS_FloorLog2 that operates on unsigned integers with + * CPU-dependant size and requires that n != 0. + */ +#define JS_FLOOR_LOG2W(n) (JS_ASSERT((n) != 0), js_FloorLog2wImpl(n)) + +#if JS_BYTES_PER_WORD == 4 + +# ifdef JS_HAS_BUILTIN_BITSCAN32 +# define js_FloorLog2wImpl(n) \ + ((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz32(n))) +# else +# define js_FloorLog2wImpl(n) ((size_t)JS_FloorLog2(n)) +#endif + +#elif JS_BYTES_PER_WORD == 8 + +# ifdef JS_HAS_BUILTIN_BITSCAN64 +# define js_FloorLog2wImpl(n) \ + ((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz64(n))) +# else +extern size_t js_FloorLog2wImpl(size_t n); +# endif + +#else + +# error "NOT SUPPORTED" + +#endif + +namespace js { + +inline size_t +CountTrailingZeros(size_t n) +{ + JS_ASSERT(n != 0); +#if JS_BYTES_PER_WORD != 4 && JS_BYTES_PER_WORD != 8 +# error "NOT SUPPORTED" +#endif + +#if JS_BYTES_PER_WORD == 4 && defined JS_HAS_BUILTIN_BITSCAN32 + return js_bitscan_ctz32(n); +#elif JS_BYTES_PER_WORD == 8 && defined JS_HAS_BUILTIN_BITSCAN64 + return js_bitscan_ctz64(n); +#else + size_t count = 0; +# if JS_BYTES_PER_WORD == 8 + if (!(n & size_t(0xFFFFFFFFU))) { count += 32; n >>= 32; } +# endif + if (!(n & 0xFFFF)) { count += 16; n >>= 16; } + if (!(n & 0xFF)) { count += 8; n >>= 8; } + if (!(n & 0xF)) { count += 4; n >>= 4; } + if (!(n & 0x3)) { count += 2; n >>= 2; } + if (!(n & 0x1)) { count += 1; n >>= 1; } + return count + 1 - (n & 0x1); +#endif +} + +} + +/* + * Macros for rotate left. There is no rotate operation in the C Language so + * the construct (a << 4) | (a >> 28) is used instead. Most compilers convert + * this to a rotate instruction but some versions of MSVC don't without a + * little help. To get MSVC to generate a rotate instruction, we have to use + * the _rotl intrinsic and use a pragma to make _rotl inline. + * + * MSVC in VS2005 will do an inline rotate instruction on the above construct. + */ + +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || \ + defined(_M_X64)) +#include +#pragma intrinsic(_rotl) +#define JS_ROTATE_LEFT32(a, bits) _rotl(a, bits) +#else +#define JS_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits)))) +#endif + +JS_END_EXTERN_C +#endif /* jsbit_h___ */ diff --git a/js/src/jsbool.cpp b/js/src/jsbool.cpp new file mode 100644 index 0000000..fb678b0 --- /dev/null +++ b/js/src/jsbool.cpp @@ -0,0 +1,194 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS boolean implementation. + */ +#include "jstypes.h" +#include "jsstdint.h" +#include "jsutil.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsstr.h" +#include "jsvector.h" + +#include "jsinterpinlines.h" +#include "jsobjinlines.h" + +using namespace js; + +Class js_BooleanClass = { + "Boolean", + JSCLASS_HAS_RESERVED_SLOTS(1) | + JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub +}; + +#if JS_HAS_TOSOURCE +#include "jsprf.h" + +static JSBool +bool_toSource(JSContext *cx, uintN argc, Value *vp) +{ + bool b; + if (!GetPrimitiveThis(cx, vp, &b)) + return false; + + char buf[32]; + JS_snprintf(buf, sizeof buf, "(new Boolean(%s))", JS_BOOLEAN_STR(b)); + JSString *str = JS_NewStringCopyZ(cx, buf); + if (!str) + return false; + vp->setString(str); + return true; +} +#endif + +static JSBool +bool_toString(JSContext *cx, uintN argc, Value *vp) +{ + bool b; + if (!GetPrimitiveThis(cx, vp, &b)) + return false; + + JSAtom *atom = cx->runtime->atomState.booleanAtoms[b ? 1 : 0]; + JSString *str = ATOM_TO_STRING(atom); + if (!str) + return JS_FALSE; + vp->setString(str); + return JS_TRUE; +} + +static JSBool +bool_valueOf(JSContext *cx, uintN argc, Value *vp) +{ + bool b; + if (!GetPrimitiveThis(cx, vp, &b)) + return false; + + vp->setBoolean(b); + return JS_TRUE; +} + +static JSFunctionSpec boolean_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, bool_toSource, 0, 0), +#endif + JS_FN(js_toString_str, bool_toString, 0, 0), + JS_FN(js_valueOf_str, bool_valueOf, 0, 0), + JS_FN(js_toJSON_str, bool_valueOf, 0, 0), + JS_FS_END +}; + +static JSBool +Boolean(JSContext *cx, uintN argc, Value *vp) +{ + Value *argv = vp + 2; + bool b = argc != 0 ? js_ValueToBoolean(argv[0]) : false; + + if (IsConstructing(vp)) { + JSObject *obj = NewBuiltinClassInstance(cx, &js_BooleanClass); + if (!obj) + return false; + obj->setPrimitiveThis(BooleanValue(b)); + vp->setObject(*obj); + } else { + vp->setBoolean(b); + } + return true; +} + +JSObject * +js_InitBooleanClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto; + + proto = js_InitClass(cx, obj, NULL, &js_BooleanClass, Boolean, 1, + NULL, boolean_methods, NULL, NULL); + if (!proto) + return NULL; + proto->setPrimitiveThis(BooleanValue(false)); + return proto; +} + +JSString * +js_BooleanToString(JSContext *cx, JSBool b) +{ + return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[b ? 1 : 0]); +} + +/* This function implements E-262-3 section 9.8, toString. */ +bool +js::BooleanToStringBuffer(JSContext *cx, JSBool b, StringBuffer &sb) +{ + return b ? sb.append("true") : sb.append("false"); +} + +JSBool +js_ValueToBoolean(const Value &v) +{ + if (v.isInt32()) + return v.toInt32() != 0; + if (v.isString()) + return v.toString()->length() != 0; + if (v.isObject()) + return JS_TRUE; + if (v.isNullOrUndefined()) + return JS_FALSE; + if (v.isDouble()) { + jsdouble d; + + d = v.toDouble(); + return !JSDOUBLE_IS_NaN(d) && d != 0; + } + JS_ASSERT(v.isBoolean()); + return v.toBoolean(); +} diff --git a/js/src/jsbool.h b/js/src/jsbool.h new file mode 100644 index 0000000..477b409 --- /dev/null +++ b/js/src/jsbool.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsbool_h___ +#define jsbool_h___ +/* + * JS boolean interface. + */ + +#include "jsapi.h" +#include "jsobj.h" +#include "jsstr.h" + +extern js::Class js_BooleanClass; + +inline bool +JSObject::isBoolean() const +{ + return getClass() == &js_BooleanClass; +} + +extern JSObject * +js_InitBooleanClass(JSContext *cx, JSObject *obj); + +extern JSString * +js_BooleanToString(JSContext *cx, JSBool b); + +namespace js { + +extern bool +BooleanToStringBuffer(JSContext *cx, JSBool b, StringBuffer &sb); + +} /* namespace js */ + +extern JSBool +js_ValueToBoolean(const js::Value &v); + +#endif /* jsbool_h___ */ diff --git a/js/src/jsbuiltins.cpp b/js/src/jsbuiltins.cpp new file mode 100644 index 0000000..605d287 --- /dev/null +++ b/js/src/jsbuiltins.cpp @@ -0,0 +1,322 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Andreas Gal + * + * Contributor(s): + * Brendan Eich + * Mike Shaver + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include + +#include "jsapi.h" +#include "jsstdint.h" +#include "jsarray.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jsgc.h" +#include "jsiter.h" +#include "jsnum.h" +#include "jslibmath.h" +#include "jsmath.h" +#include "jsnum.h" +#include "prmjtime.h" +#include "jsdate.h" +#include "jsscope.h" +#include "jsstr.h" +#include "jsbuiltins.h" +#include "jstracer.h" +#include "jsvector.h" + +#include "jsatominlines.h" +#include "jsobjinlines.h" +#include "jsscopeinlines.h" +#include "jscntxtinlines.h" + +using namespace avmplus; +using namespace nanojit; +using namespace js; + +JS_FRIEND_API(void) +js_SetTraceableNativeFailed(JSContext *cx) +{ + /* + * We might not be on trace (we might have deep bailed) so we hope + * cx->compartment is correct. + */ + SetBuiltinError(JS_TRACE_MONITOR_FROM_CONTEXT(cx)); +} + +/* + * NB: bool FASTCALL is not compatible with Nanojit's calling convention usage. + * Do not use bool FASTCALL, use JSBool only! + */ + +jsdouble FASTCALL +js_dmod(jsdouble a, jsdouble b) +{ + if (b == 0.0) { + jsdpun u; + u.s.hi = JSDOUBLE_HI32_NAN; + u.s.lo = JSDOUBLE_LO32_NAN; + return u.d; + } + return js_fmod(a, b); +} +JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_dmod, DOUBLE, DOUBLE, 1, ACCSET_NONE) + +int32 FASTCALL +js_imod(int32 a, int32 b) +{ + if (a < 0 || b <= 0) + return -1; + int r = a % b; + return r; +} +JS_DEFINE_CALLINFO_2(extern, INT32, js_imod, INT32, INT32, 1, ACCSET_NONE) + +#if JS_BITS_PER_WORD == 32 + +jsdouble FASTCALL +js_UnboxDouble(uint32 tag, uint32 payload) +{ + if (tag == JSVAL_TAG_INT32) + return (double)(int32)payload; + + jsval_layout l; + l.s.tag = (JSValueTag)tag; + l.s.payload.u32 = payload; + return l.asDouble; +} +JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_UnboxDouble, UINT32, UINT32, 1, ACCSET_NONE) + +int32 FASTCALL +js_UnboxInt32(uint32 tag, uint32 payload) +{ + if (tag == JSVAL_TAG_INT32) + return (int32)payload; + + jsval_layout l; + l.s.tag = (JSValueTag)tag; + l.s.payload.u32 = payload; + return js_DoubleToECMAInt32(l.asDouble); +} +JS_DEFINE_CALLINFO_2(extern, INT32, js_UnboxInt32, UINT32, UINT32, 1, ACCSET_NONE) + +#elif JS_BITS_PER_WORD == 64 + +jsdouble FASTCALL +js_UnboxDouble(Value v) +{ + if (v.isInt32()) + return (jsdouble)v.toInt32(); + return v.toDouble(); +} +JS_DEFINE_CALLINFO_1(extern, DOUBLE, js_UnboxDouble, JSVAL, 1, ACCSET_NONE) + +int32 FASTCALL +js_UnboxInt32(Value v) +{ + if (v.isInt32()) + return v.toInt32(); + return js_DoubleToECMAInt32(v.toDouble()); +} +JS_DEFINE_CALLINFO_1(extern, INT32, js_UnboxInt32, VALUE, 1, ACCSET_NONE) + +#endif + +int32 FASTCALL +js_DoubleToInt32(jsdouble d) +{ + return js_DoubleToECMAInt32(d); +} +JS_DEFINE_CALLINFO_1(extern, INT32, js_DoubleToInt32, DOUBLE, 1, ACCSET_NONE) + +uint32 FASTCALL +js_DoubleToUint32(jsdouble d) +{ + return js_DoubleToECMAUint32(d); +} +JS_DEFINE_CALLINFO_1(extern, UINT32, js_DoubleToUint32, DOUBLE, 1, ACCSET_NONE) + +/* + * js_StringToNumber and js_StringToInt32 store into their second argument, so + * they need to be annotated accordingly. To be future-proof, we use + * ACCSET_STORE_ANY so that new callers don't have to remember to update the + * annotation. + */ +jsdouble FASTCALL +js_StringToNumber(JSContext* cx, JSString* str, JSBool *ok) +{ + double out = 0; /* silence warnings. */ + *ok = StringToNumberType(cx, str, &out); + return out; +} +JS_DEFINE_CALLINFO_3(extern, DOUBLE, js_StringToNumber, CONTEXT, STRING, BOOLPTR, + 0, ACCSET_STORE_ANY) + +int32 FASTCALL +js_StringToInt32(JSContext* cx, JSString* str, JSBool *ok) +{ + int32 out = 0; /* silence warnings. */ + *ok = StringToNumberType(cx, str, &out); + return out; +} +JS_DEFINE_CALLINFO_3(extern, INT32, js_StringToInt32, CONTEXT, STRING, BOOLPTR, + 0, ACCSET_STORE_ANY) + +/* Nb: it's always safe to set isDefinitelyAtom to false if you're unsure or don't know. */ +static inline JSBool +AddPropertyHelper(JSContext* cx, JSObject* obj, Shape* shape, bool isDefinitelyAtom) +{ + JS_ASSERT(shape->previous() == obj->lastProperty()); + + if (obj->nativeEmpty()) { + if (!obj->ensureClassReservedSlotsForEmptyObject(cx)) + return false; + } + + uint32 slot; + slot = shape->slot; + JS_ASSERT(slot == obj->slotSpan()); + + if (slot < obj->numSlots()) { + JS_ASSERT(obj->getSlot(slot).isUndefined()); + } else { + if (!obj->allocSlot(cx, &slot)) + return false; + JS_ASSERT(slot == shape->slot); + } + + obj->extend(cx, shape, isDefinitelyAtom); + return !js_IsPropertyCacheDisabled(cx); +} + +JSBool FASTCALL +js_AddProperty(JSContext* cx, JSObject* obj, Shape* shape) +{ + return AddPropertyHelper(cx, obj, shape, /* isDefinitelyAtom = */false); +} +JS_DEFINE_CALLINFO_3(extern, BOOL, js_AddProperty, CONTEXT, OBJECT, SHAPE, 0, ACCSET_STORE_ANY) + +JSBool FASTCALL +js_AddAtomProperty(JSContext* cx, JSObject* obj, Shape* shape) +{ + return AddPropertyHelper(cx, obj, shape, /* isDefinitelyAtom = */true); +} +JS_DEFINE_CALLINFO_3(extern, BOOL, js_AddAtomProperty, CONTEXT, OBJECT, SHAPE, 0, ACCSET_STORE_ANY) + +static JSBool +HasProperty(JSContext* cx, JSObject* obj, jsid id) +{ + // Check that we know how the lookup op will behave. + for (JSObject* pobj = obj; pobj; pobj = pobj->getProto()) { + if (pobj->getOps()->lookupProperty) + return JS_NEITHER; + Class* clasp = pobj->getClass(); + if (clasp->resolve != JS_ResolveStub && clasp != &js_StringClass) + return JS_NEITHER; + } + + JSObject* obj2; + JSProperty* prop; + if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) < 0) + return JS_NEITHER; + return prop != NULL; +} + +JSBool FASTCALL +js_HasNamedProperty(JSContext* cx, JSObject* obj, JSString* idstr) +{ + JSAtom *atom = js_AtomizeString(cx, idstr, 0); + if (!atom) + return JS_NEITHER; + + return HasProperty(cx, obj, ATOM_TO_JSID(atom)); +} +JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedProperty, CONTEXT, OBJECT, STRING, + 0, ACCSET_STORE_ANY) + +JSBool FASTCALL +js_HasNamedPropertyInt32(JSContext* cx, JSObject* obj, int32 index) +{ + jsid id; + if (!js_Int32ToId(cx, index, &id)) + return JS_NEITHER; + + return HasProperty(cx, obj, id); +} +JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedPropertyInt32, CONTEXT, OBJECT, INT32, + 0, ACCSET_STORE_ANY) + +JSString* FASTCALL +js_TypeOfObject(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(obj); + return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[obj->typeOf(cx)]); +} +JS_DEFINE_CALLINFO_2(extern, STRING, js_TypeOfObject, CONTEXT, OBJECT, 1, ACCSET_NONE) + +JSString* FASTCALL +js_BooleanIntToString(JSContext *cx, int32 unboxed) +{ + JS_ASSERT(uint32(unboxed) <= 1); + return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[unboxed]); +} +JS_DEFINE_CALLINFO_2(extern, STRING, js_BooleanIntToString, CONTEXT, INT32, 1, ACCSET_NONE) + +JSObject* FASTCALL +js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* parent) +{ + JS_ASSERT(funobj->isFunction()); + JS_ASSERT(proto->isFunction()); + JS_ASSERT(JS_ON_TRACE(cx)); + + JSFunction *fun = (JSFunction*) funobj; + JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun); + + JSObject* closure = js_NewGCObject(cx, gc::FINALIZE_OBJECT2); + if (!closure) + return NULL; + + if (!closure->initSharingEmptyShape(cx, &js_FunctionClass, proto, parent, + fun, gc::FINALIZE_OBJECT2)) { + return NULL; + } + return closure; +} +JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewNullClosure, CONTEXT, OBJECT, OBJECT, OBJECT, + 0, ACCSET_STORE_ANY) + diff --git a/js/src/jsbuiltins.h b/js/src/jsbuiltins.h new file mode 100644 index 0000000..5381814 --- /dev/null +++ b/js/src/jsbuiltins.h @@ -0,0 +1,635 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * + * Contributor(s): + * Jason Orendorff + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsbuiltins_h___ +#define jsbuiltins_h___ + +#ifdef JS_TRACER + +#include "nanojit/nanojit.h" +#include "jsvalue.h" + +#ifdef THIS +#undef THIS +#endif + +enum JSTNErrType { INFALLIBLE, FAIL_STATUS, FAIL_NULL, FAIL_NEG, FAIL_NEITHER }; +enum { + JSTN_ERRTYPE_MASK = 0x07, + JSTN_UNBOX_AFTER = 0x08, + JSTN_MORE = 0x10, + JSTN_CONSTRUCTOR = 0x20, + JSTN_RETURN_NULLABLE_STR = 0x40, + JSTN_RETURN_NULLABLE_OBJ = 0x80 +}; + +#define JSTN_ERRTYPE(jstn) ((jstn)->flags & JSTN_ERRTYPE_MASK) + +/* + * Type describing a type specialization of a js::Native. + * + * |prefix| and |argtypes| declare what arguments should be passed to the + * native function. |prefix| can contain the following characters: + * + * 'C': a JSContext* argument + * 'T': |this| as a JSObject* argument (bails if |this| is not an object) + * 'S': |this| as a JSString* argument (bails if |this| is not a string) + * 'R': a JSRuntime* argument + * 'P': the pc as a jsbytecode* + * 'D': |this| as a number (jsdouble) + * 'f': the function being called, as a JSObject* + * 'p': the .prototype of the function, as a JSObject* + * + * The corresponding things will get passed as arguments to the builtin in + * reverse order (so TC means JSContext* as the first arg, and the + * JSObject* for |this| as the second arg). + * + * |argtypes| can contain the following characters: + * 'd': a number (double) argument + * 'i': an integer argument + * 's': a JSString* argument + * 'o': a JSObject* argument + * 'r': a JSObject* argument that is of class js_RegExpClass + * 'f': a JSObject* argument that is of class js_FunctionClass + * 'v': a value argument: on 32-bit, a Value*, on 64-bit, a jsval + */ +struct JSSpecializedNative { + const nanojit::CallInfo *builtin; + const char *prefix; + const char *argtypes; + uintN flags; /* JSTNErrType | JSTN_UNBOX_AFTER | JSTN_MORE | + JSTN_CONSTRUCTOR */ +}; + +/* + * Type holding extra trace-specific information about a fast native. + * + * 'specializations' points to a static array of available specializations + * terminated by the lack of having the JSTN_MORE flag set. + */ +struct JSNativeTraceInfo { + js::Native native; + JSSpecializedNative *specializations; +}; + +/* Macros used by JS_DEFINE_CALLINFOn. */ +#ifdef DEBUG +#define _JS_CI_NAME(op) ,#op +#else +#define _JS_CI_NAME(op) +#endif + +#define _JS_I32_ARGTYPE nanojit::ARGTYPE_I +#define _JS_I32_RETTYPE nanojit::ARGTYPE_I +#define _JS_U64_ARGTYPE nanojit::ARGTYPE_Q +#define _JS_U64_RETTYPE nanojit::ARGTYPE_Q +#define _JS_F64_ARGTYPE nanojit::ARGTYPE_D +#define _JS_F64_RETTYPE nanojit::ARGTYPE_D +#define _JS_PTR_ARGTYPE nanojit::ARGTYPE_P +#define _JS_PTR_RETTYPE nanojit::ARGTYPE_P + +struct ClosureVarInfo; + +/* + * Supported types for builtin functions. + * + * Types with -- for the two string fields are not permitted as argument types + * in JS_DEFINE_TRCINFO. + * + * There are three kinds of traceable-native error handling. + * + * - If a traceable native's return type ends with _FAIL, it always runs to + * completion. It can either succeed or fail with an error or exception; + * on success, it may or may not stay on trace. There may be side effects + * in any case. If the call succeeds but bails off trace, we resume in the + * interpreter at the next opcode. + * + * _FAIL builtins indicate failure or bailing off trace by setting bits in + * cx->interpState->builtinStatus. + * + * - If a traceable native's return type contains _RETRY, it can either + * succeed, fail with a JS exception, or tell the caller to bail off trace + * and retry the call from the interpreter. The last case happens if the + * builtin discovers that it can't do its job without examining the JS + * stack, reentering the interpreter, accessing properties of the global + * object, etc. + * + * The builtin must detect the need to retry before committing any side + * effects. If a builtin can't do this, it must use a _FAIL return type + * instead of _RETRY. + * + * _RETRY builtins indicate failure with a special return value that + * depends on the return type: + * + * BOOL_RETRY: JS_NEITHER + * INT32_RETRY: any negative value + * STRING_RETRY: NULL + * OBJECT_RETRY_NULL: NULL + * + * _RETRY function calls are faster than _FAIL calls. Each _RETRY call + * saves two writes to tm->bailExit and a read from state->builtinStatus. + * + * - All other traceable natives are infallible (e.g. Date.now, Math.log). + * + * Special builtins known to the tracer can have their own idiosyncratic + * error codes. + * + * When a traceable native returns a value indicating failure, we fall off + * trace. If an exception is pending, it is thrown; otherwise, we assume the + * builtin had no side effects and retry the current bytecode in the + * interpreter. + * + * So a builtin must not return a value indicating failure after causing side + * effects (such as reporting an error), without setting an exception pending. + * The operation would be retried, despite the first attempt's observable + * effects. + */ +#define _JS_CTYPE(ctype, size, pch, ach, flags) (ctype, size, pch, ach, flags) + +#define _JS_CTYPE_CONTEXT _JS_CTYPE(JSContext *, _JS_PTR,"C", "", INFALLIBLE) +#define _JS_CTYPE_RUNTIME _JS_CTYPE(JSRuntime *, _JS_PTR,"R", "", INFALLIBLE) +#define _JS_CTYPE_MATHCACHE _JS_CTYPE(js::MathCache *, _JS_PTR,"M", "", INFALLIBLE) +#define _JS_CTYPE_THIS _JS_CTYPE(JSObject *, _JS_PTR,"T", "", INFALLIBLE) +#define _JS_CTYPE_THIS_DOUBLE _JS_CTYPE(jsdouble, _JS_F64,"D", "", INFALLIBLE) +#define _JS_CTYPE_THIS_STRING _JS_CTYPE(JSString *, _JS_PTR,"S", "", INFALLIBLE) +#define _JS_CTYPE_CALLEE _JS_CTYPE(JSObject *, _JS_PTR,"f", "", INFALLIBLE) +#define _JS_CTYPE_CALLEE_PROTOTYPE _JS_CTYPE(JSObject *, _JS_PTR,"p", "", INFALLIBLE) +#define _JS_CTYPE_FUNCTION _JS_CTYPE(JSFunction *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_PC _JS_CTYPE(jsbytecode *, _JS_PTR,"P", "", INFALLIBLE) +#define _JS_CTYPE_VALUEPTR _JS_CTYPE(js::Value *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_CVALUEPTR _JS_CTYPE(const js::Value *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_JSID _JS_CTYPE(jsid, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_JSVAL _JS_CTYPE(js::Value, _JS_U64, --, --, INFALLIBLE) +#define _JS_CTYPE_BOOL _JS_CTYPE(JSBool, _JS_I32, "","i", INFALLIBLE) +#define _JS_CTYPE_BOOL_RETRY _JS_CTYPE(JSBool, _JS_I32, --, --, FAIL_NEITHER) +#define _JS_CTYPE_BOOL_FAIL _JS_CTYPE(JSBool, _JS_I32, --, --, FAIL_STATUS) +#define _JS_CTYPE_BOOLPTR _JS_CTYPE(JSBool *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_INT32 _JS_CTYPE(int32, _JS_I32, "","i", INFALLIBLE) +#define _JS_CTYPE_INT32_RETRY _JS_CTYPE(int32, _JS_I32, --, --, FAIL_NEG) +#define _JS_CTYPE_INT32_FAIL _JS_CTYPE(int32, _JS_I32, --, --, FAIL_STATUS) +#define _JS_CTYPE_INT32PTR _JS_CTYPE(int32 *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_UINT32 _JS_CTYPE(uint32, _JS_I32, "","i", INFALLIBLE) +#define _JS_CTYPE_UINT32_RETRY _JS_CTYPE(uint32, _JS_I32, --, --, FAIL_NEG) +#define _JS_CTYPE_UINT32_FAIL _JS_CTYPE(uint32, _JS_I32, --, --, FAIL_STATUS) +#define _JS_CTYPE_DOUBLE _JS_CTYPE(jsdouble, _JS_F64, "","d", INFALLIBLE) +#define _JS_CTYPE_DOUBLE_FAIL _JS_CTYPE(jsdouble, _JS_F64, --, --, FAIL_STATUS) +#define _JS_CTYPE_STRING _JS_CTYPE(JSString *, _JS_PTR, "","s", INFALLIBLE) +#define _JS_CTYPE_STRING_RETRY _JS_CTYPE(JSString *, _JS_PTR, --, --, FAIL_NULL) +#define _JS_CTYPE_STRING_FAIL _JS_CTYPE(JSString *, _JS_PTR, --, --, FAIL_STATUS) +#define _JS_CTYPE_STRING_OR_NULL_FAIL _JS_CTYPE(JSString *, _JS_PTR, --, --, FAIL_STATUS | \ + JSTN_RETURN_NULLABLE_STR) +#define _JS_CTYPE_STRINGPTR _JS_CTYPE(JSString **, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_OBJECT _JS_CTYPE(JSObject *, _JS_PTR, "","o", INFALLIBLE) +#define _JS_CTYPE_OBJECT_RETRY _JS_CTYPE(JSObject *, _JS_PTR, --, --, FAIL_NULL) +#define _JS_CTYPE_OBJECT_FAIL _JS_CTYPE(JSObject *, _JS_PTR, --, --, FAIL_STATUS) +#define _JS_CTYPE_OBJECT_OR_NULL_FAIL _JS_CTYPE(JSObject *, _JS_PTR, --, --, FAIL_STATUS | \ + JSTN_RETURN_NULLABLE_OBJ) +#define _JS_CTYPE_OBJECTPTR _JS_CTYPE(JSObject **, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_CONSTRUCTOR_RETRY _JS_CTYPE(JSObject *, _JS_PTR, --, --, FAIL_NULL | \ + JSTN_CONSTRUCTOR) +#define _JS_CTYPE_REGEXP _JS_CTYPE(JSObject *, _JS_PTR, "","r", INFALLIBLE) +#define _JS_CTYPE_SHAPE _JS_CTYPE(js::Shape *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_TRACERSTATE _JS_CTYPE(TracerState *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_FRAGMENT _JS_CTYPE(nanojit::Fragment *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_CLASS _JS_CTYPE(js::Class *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_DOUBLEPTR _JS_CTYPE(double *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_CHARPTR _JS_CTYPE(char *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_CVIPTR _JS_CTYPE(const ClosureVarInfo *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_FRAMEINFO _JS_CTYPE(FrameInfo *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_PICTABLE _JS_CTYPE(PICTable *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_UINTN _JS_CTYPE(uintN, _JS_PTR, --, --, INFALLIBLE) + +/* + * The "VALUE" type is used to indicate that a native takes a js::Value + * parameter by value. Unfortunately, for technical reasons, we can't simply + * have the parameter type be js::Value. Furthermore, the right thing to pass + * differs based on word size. Thus, a native that declares a parameter of type + * VALUE should have the corresponding argument type be: + * - on 32-bit: const Value* + * - on 64-bit: jsval (which is a uint64) + * + * To write code that just does the right thing, use the pattern: + * void foo(js::ValueArgType arg) { + * const js::Value &v = js::ValueArgToConstRef(arg); + */ +#if JS_BITS_PER_WORD == 32 +# define _JS_CTYPE_VALUE _JS_CTYPE(js::ValueArgType, _JS_PTR, "","v", INFALLIBLE) +#elif JS_BITS_PER_WORD == 64 +# define _JS_CTYPE_VALUE _JS_CTYPE(js::ValueArgType, _JS_U64, "","v", INFALLIBLE) +#endif + +#define _JS_EXPAND(tokens) tokens + +#define _JS_CTYPE_TYPE2(t,s,p,a,f) t +#define _JS_CTYPE_TYPE(tyname) _JS_EXPAND(_JS_CTYPE_TYPE2 _JS_CTYPE_##tyname) +#define _JS_CTYPE_RETTYPE2(t,s,p,a,f) s##_RETTYPE +#define _JS_CTYPE_RETTYPE(tyname) _JS_EXPAND(_JS_CTYPE_RETTYPE2 _JS_CTYPE_##tyname) +#define _JS_CTYPE_ARGTYPE2(t,s,p,a,f) s##_ARGTYPE +#define _JS_CTYPE_ARGTYPE(tyname) _JS_EXPAND(_JS_CTYPE_ARGTYPE2 _JS_CTYPE_##tyname) +#define _JS_CTYPE_PCH2(t,s,p,a,f) p +#define _JS_CTYPE_PCH(tyname) _JS_EXPAND(_JS_CTYPE_PCH2 _JS_CTYPE_##tyname) +#define _JS_CTYPE_ACH2(t,s,p,a,f) a +#define _JS_CTYPE_ACH(tyname) _JS_EXPAND(_JS_CTYPE_ACH2 _JS_CTYPE_##tyname) +#define _JS_CTYPE_FLAGS2(t,s,p,a,f) f +#define _JS_CTYPE_FLAGS(tyname) _JS_EXPAND(_JS_CTYPE_FLAGS2 _JS_CTYPE_##tyname) + +#define _JS_static_TN(t) static t +#define _JS_static_CI static +#define _JS_extern_TN(t) extern t +#define _JS_extern_CI +#define _JS_FRIEND_TN(t) extern JS_FRIEND_API(t) +#define _JS_FRIEND_CI +#define _JS_TN_LINKAGE(linkage, t) _JS_##linkage##_TN(t) +#define _JS_CI_LINKAGE(linkage) _JS_##linkage##_CI + +#define _JS_CALLINFO(name) name##_ci + +#if defined(JS_NO_FASTCALL) && defined(NANOJIT_IA32) +#define _JS_DEFINE_CALLINFO(linkage, name, crtype, cargtypes, argtypes, isPure, storeAccSet) \ + _JS_TN_LINKAGE(linkage, crtype) name cargtypes; \ + _JS_CI_LINKAGE(linkage) const nanojit::CallInfo _JS_CALLINFO(name) = \ + { (intptr_t) &name, argtypes, nanojit::ABI_CDECL, isPure, storeAccSet _JS_CI_NAME(name) };\ + JS_STATIC_ASSERT_IF(isPure, (storeAccSet) == nanojit::ACCSET_NONE); + +#else +#define _JS_DEFINE_CALLINFO(linkage, name, crtype, cargtypes, argtypes, isPure, storeAccSet) \ + _JS_TN_LINKAGE(linkage, crtype) FASTCALL name cargtypes; \ + _JS_CI_LINKAGE(linkage) const nanojit::CallInfo _JS_CALLINFO(name) = \ + { (intptr_t) &name, argtypes, nanojit::ABI_FASTCALL, isPure, storeAccSet _JS_CI_NAME(name) }; \ + JS_STATIC_ASSERT_IF(isPure, (storeAccSet) == nanojit::ACCSET_NONE); +#endif + +/* + * This macro is used for builtin functions that can be called from JITted + * code. It declares a C function named and a CallInfo struct named + * _ci so the tracer can call it. The in JS_DEFINE_CALLINFO_ is + * the number of arguments the builtin takes. Builtins with no arguments + * are not supported. Using a macro is clunky but ensures that the types + * for each C function matches those for the corresponding CallInfo struct; + * mismatched types can cause subtle problems. + * + * The macro arguments are: + * + * - The linkage for the function and the associated CallInfo global. It + * can be extern, static, or FRIEND, which specifies JS_FRIEND_API linkage + * for the function. + * + * - The return type. This identifier must name one of the _JS_TYPEINFO_* + * macros defined in jsbuiltins.h. + * + * - The builtin name. + * + * - The parameter types. + * + * - The isPure flag. Set to 1 if: + * (a) the function's return value is determined solely by its arguments + * (ie. no hidden state, no implicit inputs used such as global + * variables or the result of an I/O operation); and + * (b) the function causes no observable side-effects (ie. no writes to + * global variables, no I/O output). + * Multiple calls to a pure function can be merged during CSE. + * + * - The storeAccSet. This indicates which memory access regions the function + * accesses. It must be ACCSET_NONE if the function is pure; use + * ACCSET_STORE_ANY if you're not sure. Used to determine if each call site + * of the function aliases any loads. + */ +#define JS_DEFINE_CALLINFO_1(linkage, rt, op, at0, isPure, storeAccSet) \ + _JS_DEFINE_CALLINFO(linkage, op, \ + _JS_CTYPE_TYPE(rt), \ + (_JS_CTYPE_TYPE(at0)), \ + nanojit::CallInfo::typeSig1(_JS_CTYPE_RETTYPE(rt), \ + _JS_CTYPE_ARGTYPE(at0)), \ + isPure, storeAccSet) +#define JS_DEFINE_CALLINFO_2(linkage, rt, op, at0, at1, isPure, storeAccSet) \ + _JS_DEFINE_CALLINFO(linkage, op, \ + _JS_CTYPE_TYPE(rt), \ + (_JS_CTYPE_TYPE(at0), \ + _JS_CTYPE_TYPE(at1)), \ + nanojit::CallInfo::typeSig2(_JS_CTYPE_RETTYPE(rt), \ + _JS_CTYPE_ARGTYPE(at0), \ + _JS_CTYPE_ARGTYPE(at1)), \ + isPure, storeAccSet) +#define JS_DEFINE_CALLINFO_3(linkage, rt, op, at0, at1, at2, isPure, storeAccSet) \ + _JS_DEFINE_CALLINFO(linkage, op, \ + _JS_CTYPE_TYPE(rt), \ + (_JS_CTYPE_TYPE(at0), \ + _JS_CTYPE_TYPE(at1), \ + _JS_CTYPE_TYPE(at2)), \ + nanojit::CallInfo::typeSig3(_JS_CTYPE_RETTYPE(rt), \ + _JS_CTYPE_ARGTYPE(at0), \ + _JS_CTYPE_ARGTYPE(at1), \ + _JS_CTYPE_ARGTYPE(at2)), \ + isPure, storeAccSet) +#define JS_DEFINE_CALLINFO_4(linkage, rt, op, at0, at1, at2, at3, isPure, storeAccSet) \ + _JS_DEFINE_CALLINFO(linkage, op, \ + _JS_CTYPE_TYPE(rt), \ + (_JS_CTYPE_TYPE(at0), \ + _JS_CTYPE_TYPE(at1), \ + _JS_CTYPE_TYPE(at2), \ + _JS_CTYPE_TYPE(at3)), \ + nanojit::CallInfo::typeSig4(_JS_CTYPE_RETTYPE(rt), \ + _JS_CTYPE_ARGTYPE(at0), \ + _JS_CTYPE_ARGTYPE(at1), \ + _JS_CTYPE_ARGTYPE(at2), \ + _JS_CTYPE_ARGTYPE(at3)), \ + isPure, storeAccSet) +#define JS_DEFINE_CALLINFO_5(linkage, rt, op, at0, at1, at2, at3, at4, isPure, storeAccSet) \ + _JS_DEFINE_CALLINFO(linkage, op, \ + _JS_CTYPE_TYPE(rt), \ + (_JS_CTYPE_TYPE(at0), \ + _JS_CTYPE_TYPE(at1), \ + _JS_CTYPE_TYPE(at2), \ + _JS_CTYPE_TYPE(at3), \ + _JS_CTYPE_TYPE(at4)), \ + nanojit::CallInfo::typeSig5(_JS_CTYPE_RETTYPE(rt), \ + _JS_CTYPE_ARGTYPE(at0), \ + _JS_CTYPE_ARGTYPE(at1), \ + _JS_CTYPE_ARGTYPE(at2), \ + _JS_CTYPE_ARGTYPE(at3), \ + _JS_CTYPE_ARGTYPE(at4)), \ + isPure, storeAccSet) +#define JS_DEFINE_CALLINFO_6(linkage, rt, op, at0, at1, at2, at3, at4, at5, isPure, storeAccSet) \ + _JS_DEFINE_CALLINFO(linkage, op, \ + _JS_CTYPE_TYPE(rt), \ + (_JS_CTYPE_TYPE(at0), \ + _JS_CTYPE_TYPE(at1), \ + _JS_CTYPE_TYPE(at2), \ + _JS_CTYPE_TYPE(at3), \ + _JS_CTYPE_TYPE(at4), \ + _JS_CTYPE_TYPE(at5)), \ + nanojit::CallInfo::typeSig6(_JS_CTYPE_RETTYPE(rt), \ + _JS_CTYPE_ARGTYPE(at0), \ + _JS_CTYPE_ARGTYPE(at1), \ + _JS_CTYPE_ARGTYPE(at2), \ + _JS_CTYPE_ARGTYPE(at3), \ + _JS_CTYPE_ARGTYPE(at4), \ + _JS_CTYPE_ARGTYPE(at5)), \ + isPure, storeAccSet) +#define JS_DEFINE_CALLINFO_7(linkage, rt, op, at0, at1, at2, at3, at4, at5, at6, isPure, \ + storeAccSet) \ + _JS_DEFINE_CALLINFO(linkage, op, \ + _JS_CTYPE_TYPE(rt), \ + (_JS_CTYPE_TYPE(at0), \ + _JS_CTYPE_TYPE(at1), \ + _JS_CTYPE_TYPE(at2), \ + _JS_CTYPE_TYPE(at3), \ + _JS_CTYPE_TYPE(at4), \ + _JS_CTYPE_TYPE(at5), \ + _JS_CTYPE_TYPE(at6)), \ + nanojit::CallInfo::typeSig7(_JS_CTYPE_RETTYPE(rt), \ + _JS_CTYPE_ARGTYPE(at0), \ + _JS_CTYPE_ARGTYPE(at1), \ + _JS_CTYPE_ARGTYPE(at2), \ + _JS_CTYPE_ARGTYPE(at3), \ + _JS_CTYPE_ARGTYPE(at4), \ + _JS_CTYPE_ARGTYPE(at5), \ + _JS_CTYPE_ARGTYPE(at6)), \ + isPure, storeAccSet) +#define JS_DEFINE_CALLINFO_8(linkage, rt, op, at0, at1, at2, at3, at4, at5, at6, at7, isPure, \ + storeAccSet) \ + _JS_DEFINE_CALLINFO(linkage, op, \ + _JS_CTYPE_TYPE(rt), \ + (_JS_CTYPE_TYPE(at0), \ + _JS_CTYPE_TYPE(at1), \ + _JS_CTYPE_TYPE(at2), \ + _JS_CTYPE_TYPE(at3), \ + _JS_CTYPE_TYPE(at4), \ + _JS_CTYPE_TYPE(at5), \ + _JS_CTYPE_TYPE(at6), \ + _JS_CTYPE_TYPE(at7)), \ + nanojit::CallInfo::typeSig8(_JS_CTYPE_RETTYPE(rt), \ + _JS_CTYPE_ARGTYPE(at0), \ + _JS_CTYPE_ARGTYPE(at1), \ + _JS_CTYPE_ARGTYPE(at2), \ + _JS_CTYPE_ARGTYPE(at3), \ + _JS_CTYPE_ARGTYPE(at4), \ + _JS_CTYPE_ARGTYPE(at5), \ + _JS_CTYPE_ARGTYPE(at6), \ + _JS_CTYPE_ARGTYPE(at7)), \ + isPure, storeAccSet) + +#define JS_DECLARE_CALLINFO(name) extern const nanojit::CallInfo _JS_CALLINFO(name); + +#define _JS_TN_INIT_HELPER_n(n, args) _JS_TN_INIT_HELPER_##n args + +#define _JS_TN_INIT_HELPER_1(linkage, rt, op, at0, isPure, storeAccSet) \ + &_JS_CALLINFO(op), \ + _JS_CTYPE_PCH(at0), \ + _JS_CTYPE_ACH(at0), \ + _JS_CTYPE_FLAGS(rt) + +#define _JS_TN_INIT_HELPER_2(linkage, rt, op, at0, at1, isPure, storeAccSet) \ + &_JS_CALLINFO(op), \ + _JS_CTYPE_PCH(at1) _JS_CTYPE_PCH(at0), \ + _JS_CTYPE_ACH(at1) _JS_CTYPE_ACH(at0), \ + _JS_CTYPE_FLAGS(rt) + +#define _JS_TN_INIT_HELPER_3(linkage, rt, op, at0, at1, at2, isPure, storeAccSet) \ + &_JS_CALLINFO(op), \ + _JS_CTYPE_PCH(at2) _JS_CTYPE_PCH(at1) _JS_CTYPE_PCH(at0), \ + _JS_CTYPE_ACH(at2) _JS_CTYPE_ACH(at1) _JS_CTYPE_ACH(at0), \ + _JS_CTYPE_FLAGS(rt) + +#define _JS_TN_INIT_HELPER_4(linkage, rt, op, at0, at1, at2, at3, isPure, storeAccSet) \ + &_JS_CALLINFO(op), \ + _JS_CTYPE_PCH(at3) _JS_CTYPE_PCH(at2) _JS_CTYPE_PCH(at1) _JS_CTYPE_PCH(at0), \ + _JS_CTYPE_ACH(at3) _JS_CTYPE_ACH(at2) _JS_CTYPE_ACH(at1) _JS_CTYPE_ACH(at0), \ + _JS_CTYPE_FLAGS(rt) + +#define _JS_TN_INIT_HELPER_5(linkage, rt, op, at0, at1, at2, at3, at4, isPure, storeAccSet) \ + &_JS_CALLINFO(op), \ + _JS_CTYPE_PCH(at4) _JS_CTYPE_PCH(at3) _JS_CTYPE_PCH(at2) _JS_CTYPE_PCH(at1) \ + _JS_CTYPE_PCH(at0), \ + _JS_CTYPE_ACH(at4) _JS_CTYPE_ACH(at3) _JS_CTYPE_ACH(at2) _JS_CTYPE_ACH(at1) \ + _JS_CTYPE_ACH(at0), \ + _JS_CTYPE_FLAGS(rt) + +#define _JS_TN_INIT_HELPER_6(linkage, rt, op, at0, at1, at2, at3, at4, at5, isPure, storeAccSet) \ + &_JS_CALLINFO(op), \ + _JS_CTYPE_PCH(at5) _JS_CTYPE_PCH(at4) _JS_CTYPE_PCH(at3) _JS_CTYPE_PCH(at2) \ + _JS_CTYPE_PCH(at1) _JS_CTYPE_PCH(at0), \ + _JS_CTYPE_ACH(at5) _JS_CTYPE_ACH(at4) _JS_CTYPE_ACH(at3) _JS_CTYPE_ACH(at2) \ + _JS_CTYPE_ACH(at1) _JS_CTYPE_ACH(at0), \ + _JS_CTYPE_FLAGS(rt) + +#define _JS_TN_INIT_HELPER_7(linkage, rt, op, at0, at1, at2, at3, at4, at5, at6, isPure, storeAccSet) \ + &_JS_CALLINFO(op), \ + _JS_CTYPE_PCH(at6) _JS_CTYPE_PCH(at5) _JS_CTYPE_PCH(at4) _JS_CTYPE_PCH(at3) \ + _JS_CTYPE_PCH(at2) _JS_CTYPE_PCH(at1) _JS_CTYPE_PCH(at0), \ + _JS_CTYPE_ACH(at6) _JS_CTYPE_ACH(at5) _JS_CTYPE_ACH(at4) _JS_CTYPE_ACH(at3) \ + _JS_CTYPE_ACH(at2) _JS_CTYPE_ACH(at1) _JS_CTYPE_ACH(at0), \ + _JS_CTYPE_FLAGS(rt) + +#define _JS_TN_INIT_HELPER_8(linkage, rt, op, at0, at1, at2, at3, at4, at5, at6, at7, isPure, storeAccSet) \ + &_JS_CALLINFO(op), \ + _JS_CTYPE_PCH(at7) _JS_CTYPE_PCH(at6) _JS_CTYPE_PCH(at5) _JS_CTYPE_PCH(at4) \ + _JS_CTYPE_PCH(at3) _JS_CTYPE_PCH(at2) _JS_CTYPE_PCH(at1) _JS_CTYPE_PCH(at0), \ + _JS_CTYPE_ACH(at7) _JS_CTYPE_ACH(at6) _JS_CTYPE_ACH(at5) _JS_CTYPE_ACH(at4) \ + _JS_CTYPE_ACH(at3) _JS_CTYPE_ACH(at2) _JS_CTYPE_ACH(at1) _JS_CTYPE_ACH(at0), \ + _JS_CTYPE_FLAGS(rt) + +#define JS_DEFINE_TRCINFO_1(name, tn0) \ + _JS_DEFINE_CALLINFO_n tn0 \ + JSSpecializedNative name##_sns[] = { \ + { _JS_TN_INIT_HELPER_n tn0 } \ + }; \ + JSNativeTraceInfo name##_trcinfo = { JS_VALUEIFY_NATIVE(name), name##_sns }; + +#define JS_DEFINE_TRCINFO_2(name, tn0, tn1) \ + _JS_DEFINE_CALLINFO_n tn0 \ + _JS_DEFINE_CALLINFO_n tn1 \ + JSSpecializedNative name##_sns[] = { \ + { _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE }, \ + { _JS_TN_INIT_HELPER_n tn1 } \ + }; \ + JSNativeTraceInfo name##_trcinfo = { JS_VALUEIFY_NATIVE(name), name##_sns }; + +#define JS_DEFINE_TRCINFO_3(name, tn0, tn1, tn2) \ + _JS_DEFINE_CALLINFO_n tn0 \ + _JS_DEFINE_CALLINFO_n tn1 \ + _JS_DEFINE_CALLINFO_n tn2 \ + JSSpecializedNative name##_sns[] = { \ + { _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE }, \ + { _JS_TN_INIT_HELPER_n tn1 | JSTN_MORE }, \ + { _JS_TN_INIT_HELPER_n tn2 } \ + }; \ + JSNativeTraceInfo name##_trcinfo = { JS_VALUEIFY_NATIVE(name), name##_sns }; + +#define JS_DEFINE_TRCINFO_4(name, tn0, tn1, tn2, tn3) \ + _JS_DEFINE_CALLINFO_n tn0 \ + _JS_DEFINE_CALLINFO_n tn1 \ + _JS_DEFINE_CALLINFO_n tn2 \ + _JS_DEFINE_CALLINFO_n tn3 \ + JSSpecializedNative name##_sns[] = { \ + { _JS_TN_INIT_HELPER_n tn0 | JSTN_MORE }, \ + { _JS_TN_INIT_HELPER_n tn1 | JSTN_MORE }, \ + { _JS_TN_INIT_HELPER_n tn2 | JSTN_MORE }, \ + { _JS_TN_INIT_HELPER_n tn3 } \ + }; \ + JSNativeTraceInfo name##_trcinfo = { JS_VALUEIFY_NATIVE(name), name##_sns }; + +#define _JS_DEFINE_CALLINFO_n(n, args) JS_DEFINE_CALLINFO_##n args + +jsdouble FASTCALL +js_StringToNumber(JSContext* cx, JSString* str, JSBool *ok); + +/* Extern version of SetBuiltinError. */ +extern JS_FRIEND_API(void) +js_SetTraceableNativeFailed(JSContext *cx); + +extern jsdouble FASTCALL +js_dmod(jsdouble a, jsdouble b); + +#else + +#define JS_DEFINE_CALLINFO_1(linkage, rt, op, at0, isPure, storeAccSet) +#define JS_DEFINE_CALLINFO_2(linkage, rt, op, at0, at1, isPure, storeAccSet) +#define JS_DEFINE_CALLINFO_3(linkage, rt, op, at0, at1, at2, isPure, storeAccSet) +#define JS_DEFINE_CALLINFO_4(linkage, rt, op, at0, at1, at2, at3, isPure, storeAccSet) +#define JS_DEFINE_CALLINFO_5(linkage, rt, op, at0, at1, at2, at3, at4, isPure, storeAccSet) +#define JS_DEFINE_CALLINFO_6(linkage, rt, op, at0, at1, at2, at3, at4, at5, isPure, storeAccSet) +#define JS_DEFINE_CALLINFO_7(linkage, rt, op, at0, at1, at2, at3, at4, at5, at6, isPure, storeAccSet) +#define JS_DEFINE_CALLINFO_8(linkage, rt, op, at0, at1, at2, at3, at4, at5, at6, at7, isPure, storeAccSet) +#define JS_DECLARE_CALLINFO(name) +#define JS_DEFINE_TRCINFO_1(name, tn0) +#define JS_DEFINE_TRCINFO_2(name, tn0, tn1) +#define JS_DEFINE_TRCINFO_3(name, tn0, tn1, tn2) +#define JS_DEFINE_TRCINFO_4(name, tn0, tn1, tn2, tn3) + +#endif /* !JS_TRACER */ + +/* Defined in jsarray.cpp. */ +namespace js { +JS_DECLARE_CALLINFO(NewDenseEmptyArray) +JS_DECLARE_CALLINFO(NewDenseAllocatedArray) +JS_DECLARE_CALLINFO(NewDenseUnallocatedArray) +} +JS_DECLARE_CALLINFO(js_ArrayCompPush_tn) +JS_DECLARE_CALLINFO(js_EnsureDenseArrayCapacity) + +/* Defined in jsbuiltins.cpp. */ +JS_DECLARE_CALLINFO(js_UnboxDouble) +JS_DECLARE_CALLINFO(js_UnboxInt32) +JS_DECLARE_CALLINFO(js_dmod) +JS_DECLARE_CALLINFO(js_imod) +JS_DECLARE_CALLINFO(js_DoubleToInt32) +JS_DECLARE_CALLINFO(js_DoubleToUint32) +JS_DECLARE_CALLINFO(js_StringToNumber) +JS_DECLARE_CALLINFO(js_StringToInt32) +JS_DECLARE_CALLINFO(js_AddProperty) +JS_DECLARE_CALLINFO(js_AddAtomProperty) +JS_DECLARE_CALLINFO(js_HasNamedProperty) +JS_DECLARE_CALLINFO(js_HasNamedPropertyInt32) +JS_DECLARE_CALLINFO(js_TypeOfObject) +JS_DECLARE_CALLINFO(js_BooleanIntToString) +JS_DECLARE_CALLINFO(js_NewNullClosure) + +/* Defined in jsfun.cpp. */ +JS_DECLARE_CALLINFO(js_AllocFlatClosure) +JS_DECLARE_CALLINFO(js_PutArgumentsOnTrace) +JS_DECLARE_CALLINFO(js_PutCallObjectOnTrace) +JS_DECLARE_CALLINFO(js_SetCallVar) +JS_DECLARE_CALLINFO(js_SetCallArg) +JS_DECLARE_CALLINFO(js_CloneFunctionObject) +JS_DECLARE_CALLINFO(js_CreateCallObjectOnTrace) +JS_DECLARE_CALLINFO(js_NewArgumentsOnTrace) + +/* Defined in jsnum.cpp. */ +JS_DECLARE_CALLINFO(js_NumberToString) + +/* Defined in jsobj.cpp. */ +JS_DECLARE_CALLINFO(js_Object_tn) +JS_DECLARE_CALLINFO(js_CreateThisFromTrace) +JS_DECLARE_CALLINFO(js_InitializerObject) + +/* Defined in jsregexp.cpp. */ +JS_DECLARE_CALLINFO(js_CloneRegExpObject) + +/* Defined in jsstr.cpp. */ +JS_DECLARE_CALLINFO(js_String_tn) +JS_DECLARE_CALLINFO(js_CompareStringsOnTrace) +JS_DECLARE_CALLINFO(js_ConcatStrings) +JS_DECLARE_CALLINFO(js_EqualStringsOnTrace) +JS_DECLARE_CALLINFO(js_Flatten) + +/* Defined in jstypedarray.cpp. */ +JS_DECLARE_CALLINFO(js_TypedArray_uint8_clamp_double) + +#endif /* jsbuiltins_h___ */ diff --git a/js/src/jscell.h b/js/src/jscell.h new file mode 100644 index 0000000..aadfe8d --- /dev/null +++ b/js/src/jscell.h @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Gregor Wagner + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jscell_h___ +#define jscell_h___ + +struct JSCompartment; + +namespace js { +namespace gc { + +template struct Arena; +struct ArenaBitmap; +struct MarkingDelay; +struct Chunk; +struct FreeCell; + +/* + * A GC cell is the base class for GC Things like JSObject, JSShortString, + * JSFunction, JSXML and for an empty cell called FreeCell. It helps avoiding + * casts from an Object to a Cell whenever we call GC related mark functions. + * Cell is not the base Class for JSString because static initialization + * (used for unitStringTables) does not work with inheritance. + */ + +struct Cell { + static const size_t CellShift = 3; + static const size_t CellSize = size_t(1) << CellShift; + static const size_t CellMask = CellSize - 1; + + inline Arena *arena() const; + inline Chunk *chunk() const; + inline ArenaBitmap *bitmap() const; + JS_ALWAYS_INLINE size_t cellIndex() const; + + JS_ALWAYS_INLINE bool isMarked(uint32 color) const; + JS_ALWAYS_INLINE bool markIfUnmarked(uint32 color) const; + JS_ALWAYS_INLINE void unmark(uint32 color) const; + + inline JSCompartment *compartment() const; + + /* Needed for compatibility reasons because Cell can't be a base class of JSString */ + JS_ALWAYS_INLINE js::gc::Cell *asCell() { return this; } + + JS_ALWAYS_INLINE js::gc::FreeCell *asFreeCell() { + return reinterpret_cast(this); + } +}; + +/* FreeCell has always size 8 */ +struct FreeCell : Cell { + union { + FreeCell *link; + double data; + }; +}; + +JS_STATIC_ASSERT(sizeof(FreeCell) == 8); + +} /* namespace gc */ +} /* namespace js */ + +#endif /* jscell_h___ */ diff --git a/js/src/jsclist.h b/js/src/jsclist.h new file mode 100644 index 0000000..604ec0e --- /dev/null +++ b/js/src/jsclist.h @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsclist_h___ +#define jsclist_h___ + +#include "jstypes.h" + +/* +** Circular linked list +*/ +typedef struct JSCListStr { + struct JSCListStr *next; + struct JSCListStr *prev; +} JSCList; + +/* +** Insert element "_e" into the list, before "_l". +*/ +#define JS_INSERT_BEFORE(_e,_l) \ + JS_BEGIN_MACRO \ + (_e)->next = (_l); \ + (_e)->prev = (_l)->prev; \ + (_l)->prev->next = (_e); \ + (_l)->prev = (_e); \ + JS_END_MACRO + +/* +** Insert element "_e" into the list, after "_l". +*/ +#define JS_INSERT_AFTER(_e,_l) \ + JS_BEGIN_MACRO \ + (_e)->next = (_l)->next; \ + (_e)->prev = (_l); \ + (_l)->next->prev = (_e); \ + (_l)->next = (_e); \ + JS_END_MACRO + +/* +** Return the element following element "_e" +*/ +#define JS_NEXT_LINK(_e) \ + ((_e)->next) +/* +** Return the element preceding element "_e" +*/ +#define JS_PREV_LINK(_e) \ + ((_e)->prev) + +/* +** Append an element "_e" to the end of the list "_l" +*/ +#define JS_APPEND_LINK(_e,_l) JS_INSERT_BEFORE(_e,_l) + +/* +** Insert an element "_e" at the head of the list "_l" +*/ +#define JS_INSERT_LINK(_e,_l) JS_INSERT_AFTER(_e,_l) + +/* Return the head/tail of the list */ +#define JS_LIST_HEAD(_l) (_l)->next +#define JS_LIST_TAIL(_l) (_l)->prev + +/* +** Remove the element "_e" from it's circular list. +*/ +#define JS_REMOVE_LINK(_e) \ + JS_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + JS_END_MACRO + +/* +** Remove the element "_e" from it's circular list. Also initializes the +** linkage. +*/ +#define JS_REMOVE_AND_INIT_LINK(_e) \ + JS_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + (_e)->next = (_e); \ + (_e)->prev = (_e); \ + JS_END_MACRO + +/* +** Return non-zero if the given circular list "_l" is empty, zero if the +** circular list is not empty +*/ +#define JS_CLIST_IS_EMPTY(_l) \ + ((_l)->next == (_l)) + +/* +** Initialize a circular list +*/ +#define JS_INIT_CLIST(_l) \ + JS_BEGIN_MACRO \ + (_l)->next = (_l); \ + (_l)->prev = (_l); \ + JS_END_MACRO + +#define JS_INIT_STATIC_CLIST(_l) \ + {(_l), (_l)} + +#endif /* jsclist_h___ */ diff --git a/js/src/jsclone.cpp b/js/src/jsclone.cpp new file mode 100644 index 0000000..c1d1f7e --- /dev/null +++ b/js/src/jsclone.cpp @@ -0,0 +1,861 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is JavaScript structured data serialization. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jason Orendorff + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsclone.h" +#include "jsdate.h" +#include "jsregexp.h" +#include "jstypedarray.h" + +#include "jsregexpinlines.h" + +using namespace js; + +namespace js +{ + +bool +WriteStructuredClone(JSContext *cx, const Value &v, uint64 **bufp, size_t *nbytesp, + const JSStructuredCloneCallbacks *cb, void *cbClosure) +{ + SCOutput out(cx); + JSStructuredCloneWriter w(out, cb, cbClosure); + return w.init() && w.write(v) && out.extractBuffer(bufp, nbytesp); +} + +bool +ReadStructuredClone(JSContext *cx, const uint64_t *data, size_t nbytes, Value *vp, + const JSStructuredCloneCallbacks *cb, void *cbClosure) +{ + SCInput in(cx, data, nbytes); + JSStructuredCloneReader r(in, cb, cbClosure); + return r.read(vp); +} + +} + +enum StructuredDataType { + /* Structured data types provided by the engine */ + SCTAG_FLOAT_MAX = 0xFFF00000, + SCTAG_NULL = 0xFFFF0000, + SCTAG_UNDEFINED, + SCTAG_BOOLEAN, + SCTAG_INDEX, + SCTAG_STRING, + SCTAG_DATE_OBJECT, + SCTAG_REGEXP_OBJECT, + SCTAG_ARRAY_OBJECT, + SCTAG_OBJECT_OBJECT, + SCTAG_ARRAY_BUFFER_OBJECT, + SCTAG_BOOLEAN_OBJECT, + SCTAG_STRING_OBJECT, + SCTAG_NUMBER_OBJECT, + SCTAG_TYPED_ARRAY_MIN = 0xFFFF0100, + SCTAG_TYPED_ARRAY_MAX = SCTAG_TYPED_ARRAY_MIN + TypedArray::TYPE_MAX - 1, + SCTAG_END_OF_BUILTIN_TYPES +}; + +JS_STATIC_ASSERT(SCTAG_END_OF_BUILTIN_TYPES <= JS_SCTAG_USER_MIN); +JS_STATIC_ASSERT(JS_SCTAG_USER_MIN <= JS_SCTAG_USER_MAX); + +static uint8_t +SwapBytes(uint8_t u) +{ + return u; +} + +static uint16_t +SwapBytes(uint16_t u) +{ +#ifdef IS_BIG_ENDIAN + return ((u & 0x00ff) << 8) | ((u & 0xff00) >> 8); +#else + return u; +#endif +} + +static uint32_t +SwapBytes(uint32_t u) +{ +#ifdef IS_BIG_ENDIAN + return ((u & 0x000000ffU) << 24) | + ((u & 0x0000ff00U) << 8) | + ((u & 0x00ff0000U) >> 8) | + ((u & 0xff000000U) >> 24); +#else + return u; +#endif +} + +static uint64_t +SwapBytes(uint64_t u) +{ +#ifdef IS_BIG_ENDIAN + return ((u & 0x00000000000000ffLLU) << 56) | + ((u & 0x000000000000ff00LLU) << 40) | + ((u & 0x0000000000ff0000LLU) << 24) | + ((u & 0x00000000ff000000LLU) << 8) | + ((u & 0x000000ff00000000LLU) >> 8) | + ((u & 0x0000ff0000000000LLU) >> 24) | + ((u & 0x00ff000000000000LLU) >> 40) | + ((u & 0xff00000000000000LLU) >> 56); +#else + return u; +#endif +} + +bool +SCInput::eof() +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "truncated"); + return false; +} + +SCInput::SCInput(JSContext *cx, const uint64_t *data, size_t nbytes) + : cx(cx), point(data), end(data + nbytes / 8) +{ + JS_ASSERT((uintptr_t(data) & 7) == 0); + JS_ASSERT((nbytes & 7) == 0); +} + +bool +SCInput::read(uint64_t *p) +{ + if (point == end) + return eof(); + *p = SwapBytes(*point++); + return true; +} + +bool +SCInput::readPair(uint32_t *tagp, uint32_t *datap) +{ + uint64_t u = 0; /* initialize to shut GCC up */ + bool ok = read(&u); + if (ok) { + *tagp = uint32_t(u >> 32); + *datap = uint32_t(u); + } + return ok; +} + +/* + * The purpose of this never-inlined function is to avoid a strange g++ build + * error on OS X 10.5 (see bug 624080). :-( + */ +static JS_NEVER_INLINE double +CanonicalizeNan(double d) +{ + return JS_CANONICALIZE_NAN(d); +} + +bool +SCInput::readDouble(jsdouble *p) +{ + union { + uint64_t u; + jsdouble d; + } pun; + if (!read(&pun.u)) + return false; + *p = CanonicalizeNan(pun.d); + return true; +} + +template +bool +SCInput::readArray(T *p, size_t nelems) +{ + JS_STATIC_ASSERT(sizeof(uint64_t) % sizeof(T) == 0); + + /* + * Fail if nelems is so huge as to make JS_HOWMANY overflow or if nwords is + * larger than the remaining data. + */ + size_t nwords = JS_HOWMANY(nelems, sizeof(uint64_t) / sizeof(T)); + if (nelems + sizeof(uint64_t) / sizeof(T) - 1 < nelems || nwords > size_t(end - point)) + return eof(); + + if (sizeof(T) == 1) { + memcpy(p, point, nelems); + } else { + const T *q = (const T *) point; + const T *qend = q + nelems; + while (q != qend) + *p++ = SwapBytes(*q++); + } + point += nwords; + return true; +} + +bool +SCInput::readBytes(void *p, size_t nbytes) +{ + return readArray((uint8_t *) p, nbytes); +} + +bool +SCInput::readChars(jschar *p, size_t nchars) +{ + JS_ASSERT(sizeof(jschar) == sizeof(uint16_t)); + return readArray((uint16_t *) p, nchars); +} + +SCOutput::SCOutput(JSContext *cx) : cx(cx), buf(cx) {} + +bool +SCOutput::write(uint64_t u) +{ + return buf.append(SwapBytes(u)); +} + +static inline uint64_t +PairToUInt64(uint32_t tag, uint32_t data) +{ + return uint64_t(data) | (uint64_t(tag) << 32); +} + +bool +SCOutput::writePair(uint32_t tag, uint32_t data) +{ + /* + * As it happens, the tag word appears after the data word in the output. + * This is because exponents occupy the last 2 bytes of jsdoubles on the + * little-endian platforms we care most about. + * + * For example, JSVAL_TRUE is written using writePair(SCTAG_BOOLEAN, 1). + * PairToUInt64 produces the number 0xFFFF000200000001. + * That is written out as the bytes 01 00 00 00 02 00 FF FF. + */ + return write(PairToUInt64(tag, data)); +} + +static inline uint64_t +ReinterpretDoubleAsUInt64(jsdouble d) +{ + union { + jsdouble d; + uint64_t u; + } pun; + pun.d = d; + return pun.u; +} + +static inline jsdouble +ReinterpretUInt64AsDouble(uint64_t u) +{ + union { + uint64_t u; + jsdouble d; + } pun; + pun.u = u; + return pun.d; +} + +static inline jsdouble +ReinterpretPairAsDouble(uint32_t tag, uint32_t data) +{ + return ReinterpretUInt64AsDouble(PairToUInt64(tag, data)); +} + +bool +SCOutput::writeDouble(jsdouble d) +{ + return write(ReinterpretDoubleAsUInt64(CanonicalizeNan(d))); +} + +template +bool +SCOutput::writeArray(const T *p, size_t nelems) +{ + JS_ASSERT(8 % sizeof(T) == 0); + JS_ASSERT(sizeof(uint64_t) % sizeof(T) == 0); + + if (nelems == 0) + return true; + + if (nelems + sizeof(uint64_t) / sizeof(T) - 1 < nelems) { + js_ReportAllocationOverflow(context()); + return false; + } + size_t nwords = JS_HOWMANY(nelems, sizeof(uint64_t) / sizeof(T)); + size_t start = buf.length(); + if (!buf.growByUninitialized(nwords)) + return false; + + buf.back() = 0; /* zero-pad to an 8-byte boundary */ + + T *q = (T *) &buf[start]; + if (sizeof(T) == 1) { + memcpy(q, p, nelems); + } else { + const T *pend = p + nelems; + while (p != pend) + *q++ = SwapBytes(*p++); + } + return true; +} + +bool +SCOutput::writeBytes(const void *p, size_t nbytes) +{ + return writeArray((const uint8_t *) p, nbytes); +} + +bool +SCOutput::writeChars(const jschar *p, size_t nchars) +{ + JS_ASSERT(sizeof(jschar) == sizeof(uint16_t)); + return writeArray((const uint16_t *) p, nchars); +} + +bool +SCOutput::extractBuffer(uint64_t **datap, size_t *sizep) +{ + *sizep = buf.length() * sizeof(uint64_t); + return (*datap = buf.extractRawBuffer()) != NULL; +} + +JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX); + +bool +JSStructuredCloneWriter::writeString(uint32_t tag, JSString *str) +{ + size_t length = str->length(); + const jschar *chars = str->getChars(context()); + if (!chars) + return false; + return out.writePair(tag, uint32_t(length)) && out.writeChars(chars, length); +} + +bool +JSStructuredCloneWriter::writeId(jsid id) +{ + if (JSID_IS_INT(id)) + return out.writePair(SCTAG_INDEX, uint32_t(JSID_TO_INT(id))); + JS_ASSERT(JSID_IS_STRING(id)); + return writeString(SCTAG_STRING, JSID_TO_STRING(id)); +} + +inline void +JSStructuredCloneWriter::checkStack() +{ +#ifdef DEBUG + /* To avoid making serialization O(n^2), limit stack-checking at 10. */ + const size_t MAX = 10; + + size_t limit = JS_MIN(counts.length(), MAX); + JS_ASSERT(objs.length() == counts.length()); + size_t total = 0; + for (size_t i = 0; i < limit; i++) { + JS_ASSERT(total + counts[i] >= total); + total += counts[i]; + } + if (counts.length() <= MAX) + JS_ASSERT(total == ids.length()); + else + JS_ASSERT(total <= ids.length()); + + JS_ASSERT(memory.count() == objs.length()); + size_t j = objs.length(); + for (size_t i = 0; i < limit; i++) + JS_ASSERT(memory.has(&objs[--j].toObject())); +#endif +} + +static inline uint32_t +ArrayTypeToTag(uint32_t type) +{ + /* + * As long as these are all true, we can just add. Note that for backward + * compatibility, the tags cannot change. So if the ArrayType type codes + * change, this function and TagToArrayType will have to do more work. + */ + JS_STATIC_ASSERT(TypedArray::TYPE_INT8 == 0); + JS_STATIC_ASSERT(TypedArray::TYPE_UINT8 == 1); + JS_STATIC_ASSERT(TypedArray::TYPE_INT16 == 2); + JS_STATIC_ASSERT(TypedArray::TYPE_UINT16 == 3); + JS_STATIC_ASSERT(TypedArray::TYPE_INT32 == 4); + JS_STATIC_ASSERT(TypedArray::TYPE_UINT32 == 5); + JS_STATIC_ASSERT(TypedArray::TYPE_FLOAT32 == 6); + JS_STATIC_ASSERT(TypedArray::TYPE_FLOAT64 == 7); + JS_STATIC_ASSERT(TypedArray::TYPE_UINT8_CLAMPED == 8); + JS_STATIC_ASSERT(TypedArray::TYPE_MAX == TypedArray::TYPE_UINT8_CLAMPED + 1); + + JS_ASSERT(type < TypedArray::TYPE_MAX); + return SCTAG_TYPED_ARRAY_MIN + type; +} + +static inline uint32_t +TagToArrayType(uint32_t tag) +{ + JS_ASSERT(SCTAG_TYPED_ARRAY_MIN <= tag && tag <= SCTAG_TYPED_ARRAY_MAX); + return tag - SCTAG_TYPED_ARRAY_MIN; +} + +bool +JSStructuredCloneWriter::writeTypedArray(JSObject *obj) +{ + TypedArray *arr = TypedArray::fromJSObject(obj); + if (!out.writePair(ArrayTypeToTag(arr->type), arr->length)) + return false; + + switch (arr->type) { + case TypedArray::TYPE_INT8: + case TypedArray::TYPE_UINT8: + case TypedArray::TYPE_UINT8_CLAMPED: + return out.writeArray((const uint8_t *) arr->data, arr->length); + case TypedArray::TYPE_INT16: + case TypedArray::TYPE_UINT16: + return out.writeArray((const uint16_t *) arr->data, arr->length); + case TypedArray::TYPE_INT32: + case TypedArray::TYPE_UINT32: + case TypedArray::TYPE_FLOAT32: + return out.writeArray((const uint32_t *) arr->data, arr->length); + case TypedArray::TYPE_FLOAT64: + return out.writeArray((const uint64_t *) arr->data, arr->length); + default: + JS_NOT_REACHED("unknown TypedArray type"); + return false; + } +} + +bool +JSStructuredCloneWriter::writeArrayBuffer(JSObject *obj) +{ + ArrayBuffer *abuf = ArrayBuffer::fromJSObject(obj); + return out.writePair(SCTAG_ARRAY_BUFFER_OBJECT, abuf->byteLength) && + out.writeBytes(abuf->data, abuf->byteLength); +} + +bool +JSStructuredCloneWriter::startObject(JSObject *obj) +{ + JS_ASSERT(obj->isArray() || obj->isObject()); + + /* Fail if obj is already on the stack. */ + HashSet::AddPtr p = memory.lookupForAdd(obj); + if (p) { + JSContext *cx = context(); + if (callbacks && callbacks->reportError) + callbacks->reportError(cx, JS_SCERR_RECURSION); + else + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_SC_RECURSION); + return false; + } + if (!memory.add(p, obj)) + return false; + + /* + * Get enumerable property ids and put them in reverse order so that they + * will come off the stack in forward order. + */ + size_t initialLength = ids.length(); + if (!GetPropertyNames(context(), obj, JSITER_OWNONLY, &ids)) + return false; + jsid *begin = ids.begin() + initialLength, *end = ids.end(); + size_t count = size_t(end - begin); + Reverse(begin, end); + + /* Push obj and count to the stack. */ + if (!objs.append(ObjectValue(*obj)) || !counts.append(count)) + return false; + checkStack(); + + /* Write the header for obj. */ + return out.writePair(obj->isArray() ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0); +} + +bool +JSStructuredCloneWriter::startWrite(const js::Value &v) +{ + if (v.isString()) { + return writeString(SCTAG_STRING, v.toString()); + } else if (v.isNumber()) { + return out.writeDouble(v.toNumber()); + } else if (v.isBoolean()) { + return out.writePair(SCTAG_BOOLEAN, v.toBoolean()); + } else if (v.isNull()) { + return out.writePair(SCTAG_NULL, 0); + } else if (v.isUndefined()) { + return out.writePair(SCTAG_UNDEFINED, 0); + } else if (v.isObject()) { + JSObject *obj = &v.toObject(); + if (obj->isRegExp()) { + RegExp *re = RegExp::extractFrom(obj); + return out.writePair(SCTAG_REGEXP_OBJECT, re->getFlags()) && + writeString(SCTAG_STRING, re->getSource()); + } else if (obj->isDate()) { + jsdouble d = js_DateGetMsecSinceEpoch(context(), obj); + return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(d); + } else if (obj->isObject() || obj->isArray()) { + return startObject(obj); + } else if (js_IsTypedArray(obj)) { + return writeTypedArray(obj); + } else if (js_IsArrayBuffer(obj) && ArrayBuffer::fromJSObject(obj)) { + return writeArrayBuffer(obj); + } else if (obj->isBoolean()) { + return out.writePair(SCTAG_BOOLEAN_OBJECT, obj->getPrimitiveThis().toBoolean()); + } else if (obj->isNumber()) { + return out.writePair(SCTAG_NUMBER_OBJECT, 0) && + out.writeDouble(obj->getPrimitiveThis().toNumber()); + } else if (obj->isString()) { + return writeString(SCTAG_STRING_OBJECT, obj->getPrimitiveThis().toString()); + } + + if (callbacks && callbacks->write) + return callbacks->write(context(), this, obj, closure); + /* else fall through */ + } + + JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_UNSUPPORTED_TYPE); + return false; +} + +bool +JSStructuredCloneWriter::write(const Value &v) +{ + if (!startWrite(v)) + return false; + + while (!counts.empty()) { + JSObject *obj = &objs.back().toObject(); + if (counts.back()) { + counts.back()--; + jsid id = ids.back(); + ids.popBack(); + checkStack(); + if (JSID_IS_STRING(id) || JSID_IS_INT(id)) { + /* + * If obj still has an own property named id, write it out. + * The cost of re-checking could be avoided by using + * NativeIterators. + */ + JSObject *obj2; + JSProperty *prop; + if (!js_HasOwnProperty(context(), obj->getOps()->lookupProperty, obj, id, + &obj2, &prop)) { + return false; + } + + if (prop) { + Value val; + if (!writeId(id) || !obj->getProperty(context(), id, &val) || !startWrite(val)) + return false; + } + } + } else { + out.writePair(SCTAG_NULL, 0); + memory.remove(obj); + objs.popBack(); + counts.popBack(); + } + } + return true; +} + +bool +JSStructuredCloneReader::checkDouble(jsdouble d) +{ + jsval_layout l; + l.asDouble = d; + if (!JSVAL_IS_DOUBLE(JSVAL_FROM_LAYOUT(l))) { + JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, + JSMSG_SC_BAD_SERIALIZED_DATA, "unrecognized NaN"); + return false; + } + return true; +} + +class Chars { + JSContext *cx; + jschar *p; + public: + Chars() : p(NULL) {} + ~Chars() { if (p) cx->free(p); } + + bool allocate(JSContext *cx, size_t len) { + JS_ASSERT(!p); + // We're going to null-terminate! + p = (jschar *) cx->malloc((len + 1) * sizeof(jschar)); + this->cx = cx; + if (p) { + p[len] = jschar(0); + return true; + } + return false; + } + jschar *get() { return p; } + void forget() { p = NULL; } +}; + +JSString * +JSStructuredCloneReader::readString(uint32_t nchars) +{ + if (nchars > JSString::MAX_LENGTH) { + JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, + "string length"); + return NULL; + } + Chars chars; + if (!chars.allocate(context(), nchars) || !in.readChars(chars.get(), nchars)) + return NULL; + JSString *str = js_NewString(context(), chars.get(), nchars); + if (str) + chars.forget(); + return str; +} + +bool +JSStructuredCloneReader::readTypedArray(uint32_t tag, uint32_t nelems, Value *vp) +{ + uint32_t atype = TagToArrayType(tag); + JSObject *obj = js_CreateTypedArray(context(), atype, nelems); + if (!obj) + return false; + vp->setObject(*obj); + + TypedArray *arr = TypedArray::fromJSObject(obj); + JS_ASSERT(arr->length == nelems); + JS_ASSERT(arr->type == atype); + switch (atype) { + case TypedArray::TYPE_INT8: + case TypedArray::TYPE_UINT8: + case TypedArray::TYPE_UINT8_CLAMPED: + return in.readArray((uint8_t *) arr->data, nelems); + case TypedArray::TYPE_INT16: + case TypedArray::TYPE_UINT16: + return in.readArray((uint16_t *) arr->data, nelems); + case TypedArray::TYPE_INT32: + case TypedArray::TYPE_UINT32: + case TypedArray::TYPE_FLOAT32: + return in.readArray((uint32_t *) arr->data, nelems); + case TypedArray::TYPE_FLOAT64: + return in.readArray((uint64_t *) arr->data, nelems); + default: + JS_NOT_REACHED("unknown TypedArray type"); + return false; + } +} + +bool +JSStructuredCloneReader::readArrayBuffer(uint32_t nbytes, Value *vp) +{ + JSObject *obj = js_CreateArrayBuffer(context(), nbytes); + if (!obj) + return false; + vp->setObject(*obj); + ArrayBuffer *abuf = ArrayBuffer::fromJSObject(obj); + JS_ASSERT(abuf->byteLength == nbytes); + return in.readArray((uint8_t *) abuf->data, nbytes); +} + +bool +JSStructuredCloneReader::startRead(Value *vp) +{ + uint32_t tag, data; + + if (!in.readPair(&tag, &data)) + return false; + switch (tag) { + case SCTAG_NULL: + vp->setNull(); + break; + + case SCTAG_UNDEFINED: + vp->setUndefined(); + break; + + case SCTAG_BOOLEAN: + case SCTAG_BOOLEAN_OBJECT: + vp->setBoolean(!!data); + if (tag == SCTAG_BOOLEAN_OBJECT && !js_PrimitiveToObject(context(), vp)) + return false; + break; + + case SCTAG_STRING: + case SCTAG_STRING_OBJECT: { + JSString *str = readString(data); + if (!str) + return false; + vp->setString(str); + if (tag == SCTAG_STRING_OBJECT && !js_PrimitiveToObject(context(), vp)) + return false; + break; + } + + case SCTAG_NUMBER_OBJECT: { + jsdouble d; + if (!in.readDouble(&d) || !checkDouble(d)) + return false; + vp->setDouble(d); + if (!js_PrimitiveToObject(context(), vp)) + return false; + break; + } + + case SCTAG_DATE_OBJECT: { + jsdouble d; + if (!in.readDouble(&d) || !checkDouble(d)) + return false; + if (d == d && d != TIMECLIP(d)) { + JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, + "date"); + return false; + } + JSObject *obj = js_NewDateObjectMsec(context(), d); + if (!obj) + return false; + vp->setObject(*obj); + break; + } + + case SCTAG_REGEXP_OBJECT: { + uint32_t tag2, nchars; + if (!in.readPair(&tag2, &nchars)) + return false; + if (tag2 != SCTAG_STRING) { + JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, + "regexp"); + return false; + } + JSString *str = readString(nchars); + if (!str) + return false; + size_t length = str->length(); + const jschar *chars = str->getChars(context()); + if (!chars) + return false; + JSObject *obj = RegExp::createObjectNoStatics(context(), chars, length, data); + if (!obj) + return false; + vp->setObject(*obj); + break; + } + + case SCTAG_ARRAY_OBJECT: + case SCTAG_OBJECT_OBJECT: { + JSObject *obj = (tag == SCTAG_ARRAY_OBJECT) + ? NewDenseEmptyArray(context()) + : NewBuiltinClassInstance(context(), &js_ObjectClass); + if (!obj || !objs.append(ObjectValue(*obj))) + return false; + vp->setObject(*obj); + break; + } + + case SCTAG_ARRAY_BUFFER_OBJECT: + return readArrayBuffer(data, vp); + + default: { + if (tag <= SCTAG_FLOAT_MAX) { + jsdouble d = ReinterpretPairAsDouble(tag, data); + if (!checkDouble(d)) + return false; + vp->setNumber(d); + break; + } + + if (SCTAG_TYPED_ARRAY_MIN <= tag && tag <= SCTAG_TYPED_ARRAY_MAX) + return readTypedArray(tag, data, vp); + + if (!callbacks || !callbacks->read) { + JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, + "unsupported type"); + return false; + } + JSObject *obj = callbacks->read(context(), this, tag, data, closure); + if (!obj) + return false; + vp->setObject(*obj); + } + } + return true; +} + +bool +JSStructuredCloneReader::readId(jsid *idp) +{ + uint32_t tag, data; + if (!in.readPair(&tag, &data)) + return false; + + if (tag == SCTAG_INDEX) { + *idp = INT_TO_JSID(int32_t(data)); + return true; + } + if (tag == SCTAG_STRING) { + JSString *str = readString(data); + if (!str) + return false; + JSAtom *atom = js_AtomizeString(context(), str, 0); + if (!atom) + return false; + *idp = ATOM_TO_JSID(atom); + return true; + } + if (tag == SCTAG_NULL) { + *idp = JSID_VOID; + return true; + } + JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "id"); + return false; +} + +bool +JSStructuredCloneReader::read(Value *vp) +{ + if (!startRead(vp)) + return false; + + while (objs.length() != 0) { + JSObject *obj = &objs.back().toObject(); + + jsid id; + if (!readId(&id)) + return false; + + if (JSID_IS_VOID(id)) { + objs.popBack(); + } else { + Value v; + if (!startRead(&v) || !obj->defineProperty(context(), id, v)) + return false; + } + } + return true; +} diff --git a/js/src/jsclone.h b/js/src/jsclone.h new file mode 100644 index 0000000..dbead17 --- /dev/null +++ b/js/src/jsclone.h @@ -0,0 +1,191 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is JavaScript structured data serialization. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jason Orendorff + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsclone_h___ +#define jsclone_h___ + +#include "jsapi.h" +#include "jscntxt.h" +#include "jshashtable.h" +#include "jsstdint.h" +#include "jsvector.h" +#include "jsvalue.h" + +namespace js { + +bool +WriteStructuredClone(JSContext *cx, const Value &v, uint64_t **bufp, size_t *nbytesp, + const JSStructuredCloneCallbacks *cb, void *cbClosure); + +bool +ReadStructuredClone(JSContext *cx, const uint64_t *data, size_t nbytes, Value *vp, + const JSStructuredCloneCallbacks *cb, void *cbClosure); + +struct SCOutput { + public: + explicit SCOutput(JSContext *cx); + + JSContext *context() const { return cx; } + + bool write(uint64_t u); + bool writePair(uint32_t tag, uint32_t data); + bool writeDouble(jsdouble d); + bool writeBytes(const void *p, size_t nbytes); + bool writeChars(const jschar *p, size_t nchars); + + template + bool writeArray(const T *p, size_t nbytes); + + bool extractBuffer(uint64_t **datap, size_t *sizep); + + private: + JSContext *cx; + js::Vector buf; +}; + +struct SCInput { + public: + SCInput(JSContext *cx, const uint64_t *data, size_t nbytes); + + JSContext *context() const { return cx; } + + bool read(uint64_t *p); + bool readPair(uint32_t *tagp, uint32_t *datap); + bool readDouble(jsdouble *p); + bool readBytes(void *p, size_t nbytes); + bool readChars(jschar *p, size_t nchars); + + template + bool readArray(T *p, size_t nelems); + + private: + bool eof(); + + void staticAssertions() { + JS_STATIC_ASSERT(sizeof(jschar) == 2); + JS_STATIC_ASSERT(sizeof(uint32_t) == 4); + JS_STATIC_ASSERT(sizeof(jsdouble) == 8); + } + + JSContext *cx; + const uint64_t *point; + const uint64_t *end; +}; + +} + +struct JSStructuredCloneReader { + public: + explicit JSStructuredCloneReader(js::SCInput &in, const JSStructuredCloneCallbacks *cb, + void *cbClosure) + : in(in), objs(in.context()), callbacks(cb), closure(cbClosure) { } + + js::SCInput &input() { return in; } + bool read(js::Value *vp); + + private: + JSContext *context() { return in.context(); } + + bool checkDouble(jsdouble d); + JSString *readString(uint32_t nchars); + bool readTypedArray(uint32_t tag, uint32_t nelems, js::Value *vp); + bool readArrayBuffer(uint32_t nbytes, js::Value *vp); + bool readId(jsid *idp); + bool startRead(js::Value *vp); + + js::SCInput ∈ + + // Stack of objects with properties remaining to be read. + js::AutoValueVector objs; + + // The user defined callbacks that will be used for cloning. + const JSStructuredCloneCallbacks *callbacks; + + // Any value passed to JS_ReadStructuredClone. + void *closure; +}; + +struct JSStructuredCloneWriter { + public: + explicit JSStructuredCloneWriter(js::SCOutput &out, const JSStructuredCloneCallbacks *cb, + void *cbClosure) + : out(out), objs(out.context()), counts(out.context()), ids(out.context()), + memory(out.context()), callbacks(cb), closure(cbClosure) { } + + bool init() { return memory.init(); } + + bool write(const js::Value &v); + + js::SCOutput &output() { return out; } + + private: + JSContext *context() { return out.context(); } + + bool writeString(uint32_t tag, JSString *str); + bool writeId(jsid id); + bool writeArrayBuffer(JSObject *obj); + bool writeTypedArray(JSObject *obj); + bool startObject(JSObject *obj); + bool startWrite(const js::Value &v); + + inline void checkStack(); + + js::SCOutput &out; + + // Stack of objects with properties remaining to be written. + js::AutoValueVector objs; + + // counts[i] is the number of properties of objs[i] remaining to be written. + // counts.length() == objs.length() and sum(counts) == ids.length(). + js::Vector counts; + + // Ids of properties remaining to be written. + js::AutoIdVector ids; + + // The "memory" list described in the HTML5 internal structured cloning algorithm. + // memory has the same elements as objs. + js::HashSet memory; + + // The user defined callbacks that will be used for cloning. + const JSStructuredCloneCallbacks *callbacks; + + // Any value passed to JS_WriteStructuredClone. + void *closure; +}; + +#endif /* jsclone_h___ */ diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp new file mode 100644 index 0000000..e530944 --- /dev/null +++ b/js/src/jscntxt.cpp @@ -0,0 +1,2314 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=80: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS execution context. + */ +#include +#include +#include +#include +#ifdef ANDROID +# include +# include +# include +#endif // ANDROID + +#include "jsstdint.h" + +#include "jstypes.h" +#include "jsarena.h" +#include "jsutil.h" +#include "jsclist.h" +#include "jsprf.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdbgapi.h" +#include "jsexn.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsmath.h" +#include "jsnativestack.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jspubtd.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstaticcheck.h" +#include "jsstr.h" +#include "jstracer.h" + +#ifdef JS_METHODJIT +# include "assembler/assembler/MacroAssembler.h" +#endif + +#include "jscntxtinlines.h" +#include "jscompartment.h" +#include "jsinterpinlines.h" +#include "jsobjinlines.h" + +#ifdef XP_WIN +# include "jswin.h" +#elif defined(XP_OS2) +# define INCL_DOSMEMMGR +# include +#else +# include +# include +# if !defined(MAP_ANONYMOUS) +# if defined(MAP_ANON) +# define MAP_ANONYMOUS MAP_ANON +# else +# define MAP_ANONYMOUS 0 +# endif +# endif +#endif + +using namespace js; +using namespace js::gc; + +static const size_t ARENA_HEADER_SIZE_HACK = 40; +static const size_t TEMP_POOL_CHUNK_SIZE = 4096 - ARENA_HEADER_SIZE_HACK; + +static void +FreeContext(JSContext *cx); + +#ifdef DEBUG +JS_REQUIRES_STACK bool +StackSegment::contains(const JSStackFrame *fp) const +{ + JS_ASSERT(inContext()); + JSStackFrame *start; + JSStackFrame *stop; + if (isActive()) { + JS_ASSERT(cx->hasfp()); + start = cx->fp(); + stop = cx->activeSegment()->initialFrame->prev(); + } else { + JS_ASSERT(suspendedRegs && suspendedRegs->fp); + start = suspendedRegs->fp; + stop = initialFrame->prev(); + } + for (JSStackFrame *f = start; f != stop; f = f->prev()) { + if (f == fp) + return true; + } + return false; +} +#endif + +bool +StackSpace::init() +{ + void *p; +#ifdef XP_WIN + p = VirtualAlloc(NULL, CAPACITY_BYTES, MEM_RESERVE, PAGE_READWRITE); + if (!p) + return false; + void *check = VirtualAlloc(p, COMMIT_BYTES, MEM_COMMIT, PAGE_READWRITE); + if (p != check) + return false; + base = reinterpret_cast(p); + commitEnd = base + COMMIT_VALS; + end = base + CAPACITY_VALS; +#elif defined(XP_OS2) + if (DosAllocMem(&p, CAPACITY_BYTES, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY) && + DosAllocMem(&p, CAPACITY_BYTES, PAG_COMMIT | PAG_READ | PAG_WRITE)) + return false; + base = reinterpret_cast(p); + end = base + CAPACITY_VALS; +#else + JS_ASSERT(CAPACITY_BYTES % getpagesize() == 0); + p = mmap(NULL, CAPACITY_BYTES, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (p == MAP_FAILED) + return false; + base = reinterpret_cast(p); + end = base + CAPACITY_VALS; +#endif + return true; +} + +void +StackSpace::finish() +{ +#ifdef XP_WIN + VirtualFree(base, (commitEnd - base) * sizeof(Value), MEM_DECOMMIT); + VirtualFree(base, 0, MEM_RELEASE); +#elif defined(XP_OS2) + DosFreeMem(base); +#else +#ifdef SOLARIS + munmap((caddr_t)base, CAPACITY_BYTES); +#else + munmap(base, CAPACITY_BYTES); +#endif +#endif +} + +#ifdef XP_WIN +JS_FRIEND_API(bool) +StackSpace::bumpCommit(Value *from, ptrdiff_t nvals) const +{ + JS_ASSERT(end - from >= nvals); + Value *newCommit = commitEnd; + Value *request = from + nvals; + + /* Use a dumb loop; will probably execute once. */ + JS_ASSERT((end - newCommit) % COMMIT_VALS == 0); + do { + newCommit += COMMIT_VALS; + JS_ASSERT((end - newCommit) >= 0); + } while (newCommit < request); + + /* The cast is safe because CAPACITY_BYTES is small. */ + int32 size = static_cast(newCommit - commitEnd) * sizeof(Value); + + if (!VirtualAlloc(commitEnd, size, MEM_COMMIT, PAGE_READWRITE)) + return false; + commitEnd = newCommit; + return true; +} +#endif + +void +StackSpace::mark(JSTracer *trc) +{ + /* + * The correctness/completeness of marking depends on the continuity + * invariants described by the StackSegment and StackSpace definitions. + * + * NB: + * Stack slots might be torn or uninitialized in the presence of method + * JIT'd code. Arguments are an exception and are always fully synced + * (so they can be read by functions). + */ + Value *end = firstUnused(); + for (StackSegment *seg = currentSegment; seg; seg = seg->getPreviousInMemory()) { + STATIC_ASSERT(ubound(end) >= 0); + if (seg->inContext()) { + /* This may be the only pointer to the initialVarObj. */ + if (seg->hasInitialVarObj()) + MarkObject(trc, seg->getInitialVarObj(), "varobj"); + + /* Mark slots/args trailing off of the last stack frame. */ + JSStackFrame *fp = seg->getCurrentFrame(); + MarkStackRangeConservatively(trc, fp->slots(), end); + + /* Mark stack frames and slots/args between stack frames. */ + JSStackFrame *initial = seg->getInitialFrame(); + for (JSStackFrame *f = fp; f != initial; f = f->prev()) { + js_TraceStackFrame(trc, f); + MarkStackRangeConservatively(trc, f->prev()->slots(), (Value *)f); + } + + /* Mark initial stack frame and leading args. */ + js_TraceStackFrame(trc, initial); + MarkStackRangeConservatively(trc, seg->valueRangeBegin(), (Value *)initial); + } else { + /* Mark slots/args trailing off segment. */ + MarkValueRange(trc, seg->valueRangeBegin(), end, "stack"); + } + end = (Value *)seg; + } +} + +bool +StackSpace::pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard *ag) +{ + Value *start = firstUnused(); + ptrdiff_t nvals = VALUES_PER_STACK_SEGMENT + 2 + argc; + if (!ensureSpace(cx, start, nvals)) + return false; + + StackSegment *seg = new(start) StackSegment; + seg->setPreviousInMemory(currentSegment); + currentSegment = seg; + + ag->cx = cx; + ag->seg = seg; + ag->argv_ = seg->valueRangeBegin() + 2; + ag->argc_ = argc; + + /* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */ +#ifdef DEBUG + ag->prevInvokeSegment = invokeSegment; + invokeSegment = seg; + ag->prevInvokeFrame = invokeFrame; + invokeFrame = NULL; +#endif + ag->prevInvokeArgEnd = invokeArgEnd; + invokeArgEnd = ag->argv() + ag->argc(); + return true; +} + +void +StackSpace::popSegmentForInvoke(const InvokeArgsGuard &ag) +{ + JS_ASSERT(!currentSegment->inContext()); + JS_ASSERT(ag.seg == currentSegment); + JS_ASSERT(invokeSegment == currentSegment); + JS_ASSERT(invokeArgEnd == ag.argv() + ag.argc()); + + currentSegment = currentSegment->getPreviousInMemory(); + +#ifdef DEBUG + invokeSegment = ag.prevInvokeSegment; + invokeFrame = ag.prevInvokeFrame; +#endif + invokeArgEnd = ag.prevInvokeArgEnd; +} + +bool +StackSpace::getSegmentAndFrame(JSContext *cx, uintN vplen, uintN nslots, + FrameGuard *fg) const +{ + Value *start = firstUnused(); + uintN nvals = VALUES_PER_STACK_SEGMENT + vplen + VALUES_PER_STACK_FRAME + nslots; + if (!ensureSpace(cx, start, nvals)) + return false; + + fg->seg_ = new(start) StackSegment; + fg->vp_ = start + VALUES_PER_STACK_SEGMENT; + fg->fp_ = reinterpret_cast(fg->vp() + vplen); + return true; +} + +void +StackSpace::pushSegmentAndFrame(JSContext *cx, JSFrameRegs *regs, FrameGuard *fg) +{ + /* Caller should have already initialized regs. */ + JS_ASSERT(regs->fp == fg->fp()); + StackSegment *seg = fg->segment(); + + /* Register new segment/frame with the context. */ + cx->pushSegmentAndFrame(seg, *regs); + + /* Officially push the segment/frame on the stack. */ + seg->setPreviousInMemory(currentSegment); + currentSegment = seg; + + /* Mark as 'pushed' in the guard. */ + fg->cx_ = cx; +} + +void +StackSpace::popSegmentAndFrame(JSContext *cx) +{ + JS_ASSERT(isCurrentAndActive(cx)); + JS_ASSERT(cx->hasActiveSegment()); + + /* Officially pop the segment/frame from the stack. */ + currentSegment = currentSegment->getPreviousInMemory(); + + /* Unregister pushed segment/frame from the context. */ + cx->popSegmentAndFrame(); + + /* + * N.B. This StackSpace should be GC-able without any operations after + * cx->popSegmentAndFrame executes since it can trigger GC. + */ +} + +FrameGuard::~FrameGuard() +{ + if (!pushed()) + return; + JS_ASSERT(cx_->activeSegment() == segment()); + JS_ASSERT(cx_->maybefp() == fp()); + cx_->stack().popSegmentAndFrame(cx_); +} + +bool +StackSpace::getExecuteFrame(JSContext *cx, JSScript *script, ExecuteFrameGuard *fg) const +{ + return getSegmentAndFrame(cx, 2, script->nslots, fg); +} + +void +StackSpace::pushExecuteFrame(JSContext *cx, JSObject *initialVarObj, ExecuteFrameGuard *fg) +{ + JSStackFrame *fp = fg->fp(); + JSScript *script = fp->script(); + fg->regs_.pc = script->code; + fg->regs_.fp = fp; + fg->regs_.sp = fp->base(); + pushSegmentAndFrame(cx, &fg->regs_, fg); + fg->seg_->setInitialVarObj(initialVarObj); +} + +bool +StackSpace::pushDummyFrame(JSContext *cx, JSObject &scopeChain, DummyFrameGuard *fg) +{ + if (!getSegmentAndFrame(cx, 0 /*vplen*/, 0 /*nslots*/, fg)) + return false; + fg->fp()->initDummyFrame(cx, scopeChain); + fg->regs_.fp = fg->fp(); + fg->regs_.pc = NULL; + fg->regs_.sp = fg->fp()->slots(); + pushSegmentAndFrame(cx, &fg->regs_, fg); + return true; +} + +bool +StackSpace::getGeneratorFrame(JSContext *cx, uintN vplen, uintN nslots, GeneratorFrameGuard *fg) +{ + return getSegmentAndFrame(cx, vplen, nslots, fg); +} + +void +StackSpace::pushGeneratorFrame(JSContext *cx, JSFrameRegs *regs, GeneratorFrameGuard *fg) +{ + JS_ASSERT(regs->fp == fg->fp()); + JS_ASSERT(regs->fp->prev() == cx->maybefp()); + pushSegmentAndFrame(cx, regs, fg); +} + +bool +StackSpace::bumpCommitAndLimit(JSStackFrame *base, Value *sp, uintN nvals, Value **limit) const +{ + JS_ASSERT(sp >= firstUnused()); + JS_ASSERT(sp + nvals >= *limit); +#ifdef XP_WIN + if (commitEnd <= *limit) { + Value *quotaEnd = (Value *)base + STACK_QUOTA; + if (sp + nvals < quotaEnd) { + if (!ensureSpace(NULL, sp, nvals)) + return false; + *limit = Min(quotaEnd, commitEnd); + return true; + } + } +#endif + return false; +} + +void +FrameRegsIter::initSlow() +{ + if (!curseg) { + curfp = NULL; + cursp = NULL; + curpc = NULL; + return; + } + + JS_ASSERT(curseg->isSuspended()); + curfp = curseg->getSuspendedFrame(); + cursp = curseg->getSuspendedRegs()->sp; + curpc = curseg->getSuspendedRegs()->pc; +} + +/* + * Using the invariant described in the js::StackSegment comment, we know that, + * when a pair of prev-linked stack frames are in the same segment, the + * first frame's address is the top of the prev-frame's stack, modulo missing + * arguments. + */ +void +FrameRegsIter::incSlow(JSStackFrame *fp, JSStackFrame *prev) +{ + JS_ASSERT(prev); + JS_ASSERT(curpc == curfp->pc(cx, fp)); + JS_ASSERT(fp == curseg->getInitialFrame()); + + /* + * If fp is in cs and the prev-frame is in csprev, it is not necessarily + * the case that |cs->getPreviousInContext == csprev| or that + * |csprev->getSuspendedFrame == prev| (because of indirect eval and + * JS_EvaluateInStackFrame). To compute prev's sp, we need to do a linear + * scan, keeping track of what is immediately after prev in memory. + */ + curseg = curseg->getPreviousInContext(); + cursp = curseg->getSuspendedRegs()->sp; + JSStackFrame *f = curseg->getSuspendedFrame(); + while (f != prev) { + if (f == curseg->getInitialFrame()) { + curseg = curseg->getPreviousInContext(); + cursp = curseg->getSuspendedRegs()->sp; + f = curseg->getSuspendedFrame(); + } else { + cursp = f->formalArgsEnd(); + f = f->prev(); + } + } +} + +AllFramesIter::AllFramesIter(JSContext *cx) + : curcs(cx->stack().getCurrentSegment()), + curfp(curcs ? curcs->getCurrentFrame() : NULL) +{ +} + +AllFramesIter& +AllFramesIter::operator++() +{ + JS_ASSERT(!done()); + if (curfp == curcs->getInitialFrame()) { + curcs = curcs->getPreviousInMemory(); + curfp = curcs ? curcs->getCurrentFrame() : NULL; + } else { + curfp = curfp->prev(); + } + return *this; +} + +bool +JSThreadData::init() +{ +#ifdef DEBUG + /* The data must be already zeroed. */ + for (size_t i = 0; i != sizeof(*this); ++i) + JS_ASSERT(reinterpret_cast(this)[i] == 0); +#endif + if (!stackSpace.init()) + return false; + dtoaState = js_NewDtoaState(); + if (!dtoaState) { + finish(); + return false; + } + nativeStackBase = GetNativeStackBase(); + +#ifdef JS_TRACER + /* Set the default size for the code cache to 16MB. */ + maxCodeCacheBytes = 16 * 1024 * 1024; +#endif + + return true; +} + +void +JSThreadData::finish() +{ + if (dtoaState) + js_DestroyDtoaState(dtoaState); + + js_FinishGSNCache(&gsnCache); + propertyCache.~PropertyCache(); + stackSpace.finish(); +} + +void +JSThreadData::mark(JSTracer *trc) +{ + stackSpace.mark(trc); +} + +void +JSThreadData::purge(JSContext *cx) +{ + js_PurgeGSNCache(&gsnCache); + + /* FIXME: bug 506341. */ + propertyCache.purge(cx); +} + +#ifdef JS_THREADSAFE + +static JSThread * +NewThread(void *id) +{ + JS_ASSERT(js_CurrentThreadId() == id); + JSThread *thread = (JSThread *) js_calloc(sizeof(JSThread)); + if (!thread) + return NULL; + JS_INIT_CLIST(&thread->contextList); + thread->id = id; + if (!thread->data.init()) { + js_free(thread); + return NULL; + } + return thread; +} + +static void +DestroyThread(JSThread *thread) +{ + /* The thread must have zero contexts. */ + JS_ASSERT(JS_CLIST_IS_EMPTY(&thread->contextList)); + + /* + * The conservative GC scanner should be disabled when the thread leaves + * the last request. + */ + JS_ASSERT(!thread->data.conservativeGC.hasStackToScan()); + + thread->data.finish(); + js_free(thread); +} + +JSThread * +js_CurrentThread(JSRuntime *rt) +{ + void *id = js_CurrentThreadId(); + JS_LOCK_GC(rt); + + /* + * We must not race with a GC that accesses cx->thread for JSContext + * instances on all threads, see bug 476934. + */ + js_WaitForGC(rt); + + JSThread *thread; + JSThread::Map::AddPtr p = rt->threads.lookupForAdd(id); + if (p) { + thread = p->value; + + /* + * If thread has no contexts, it might be left over from a previous + * thread with the same id but a different stack address. + */ + if (JS_CLIST_IS_EMPTY(&thread->contextList)) + thread->data.nativeStackBase = GetNativeStackBase(); + } else { + JS_UNLOCK_GC(rt); + thread = NewThread(id); + if (!thread) + return NULL; + JS_LOCK_GC(rt); + js_WaitForGC(rt); + if (!rt->threads.relookupOrAdd(p, id, thread)) { + JS_UNLOCK_GC(rt); + DestroyThread(thread); + return NULL; + } + + /* Another thread cannot add an entry for the current thread id. */ + JS_ASSERT(p->value == thread); + } + JS_ASSERT(thread->id == id); + +#ifdef DEBUG + char* gnsb = (char*) GetNativeStackBase(); + JS_ASSERT(gnsb + 0 == (char*) thread->data.nativeStackBase || + /* Work around apparent glibc bug; see bug 608526. */ + gnsb + 0x1000 == (char*) thread->data.nativeStackBase || + gnsb + 0x2000 == (char*) thread->data.nativeStackBase || + gnsb + 0x3000 == (char*) thread->data.nativeStackBase); +#endif + + return thread; +} + +JSBool +js_InitContextThread(JSContext *cx) +{ + JSThread *thread = js_CurrentThread(cx->runtime); + if (!thread) + return false; + + JS_APPEND_LINK(&cx->threadLinks, &thread->contextList); + cx->thread = thread; + return true; +} + +void +js_ClearContextThread(JSContext *cx) +{ + JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread)); + JS_REMOVE_AND_INIT_LINK(&cx->threadLinks); + cx->thread = NULL; +} + +#endif /* JS_THREADSAFE */ + +JSThreadData * +js_CurrentThreadData(JSRuntime *rt) +{ +#ifdef JS_THREADSAFE + JSThread *thread = js_CurrentThread(rt); + if (!thread) + return NULL; + + return &thread->data; +#else + return &rt->threadData; +#endif +} + +JSBool +js_InitThreads(JSRuntime *rt) +{ +#ifdef JS_THREADSAFE + if (!rt->threads.init(4)) + return false; +#else + if (!rt->threadData.init()) + return false; +#endif + return true; +} + +void +js_FinishThreads(JSRuntime *rt) +{ +#ifdef JS_THREADSAFE + if (!rt->threads.initialized()) + return; + for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) { + JSThread *thread = r.front().value; + JS_ASSERT(JS_CLIST_IS_EMPTY(&thread->contextList)); + DestroyThread(thread); + } + rt->threads.clear(); +#else + rt->threadData.finish(); +#endif +} + +void +js_PurgeThreads(JSContext *cx) +{ +#ifdef JS_THREADSAFE + for (JSThread::Map::Enum e(cx->runtime->threads); + !e.empty(); + e.popFront()) { + JSThread *thread = e.front().value; + + if (JS_CLIST_IS_EMPTY(&thread->contextList)) { + JS_ASSERT(cx->thread != thread); + + DestroyThread(thread); + e.removeFront(); + } else { + thread->data.purge(cx); + } + } +#else + cx->runtime->threadData.purge(cx); +#endif +} + +JSContext * +js_NewContext(JSRuntime *rt, size_t stackChunkSize) +{ + JSContext *cx; + JSBool ok, first; + JSContextCallback cxCallback; + + /* + * We need to initialize the new context fully before adding it to the + * runtime list. After that it can be accessed from another thread via + * js_ContextIterator. + */ + void *mem = js_calloc(sizeof *cx); + if (!mem) + return NULL; + + cx = new (mem) JSContext(rt); + cx->debugHooks = &rt->globalDebugHooks; +#if JS_STACK_GROWTH_DIRECTION > 0 + cx->stackLimit = (jsuword) -1; +#endif + cx->scriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA; + JS_STATIC_ASSERT(JSVERSION_DEFAULT == 0); + JS_ASSERT(cx->findVersion() == JSVERSION_DEFAULT); + VOUCH_DOES_NOT_REQUIRE_STACK(); + + JS_InitArenaPool(&cx->tempPool, "temp", TEMP_POOL_CHUNK_SIZE, sizeof(jsdouble), + &cx->scriptStackQuota); + JS_InitArenaPool(&cx->regExpPool, "regExp", TEMP_POOL_CHUNK_SIZE, sizeof(int), + &cx->scriptStackQuota); + + JS_ASSERT(cx->resolveFlags == 0); + + if (!cx->busyArrays.init()) { + FreeContext(cx); + return NULL; + } + +#ifdef JS_THREADSAFE + if (!js_InitContextThread(cx)) { + FreeContext(cx); + return NULL; + } +#endif + + /* + * Here the GC lock is still held after js_InitContextThread took it and + * the GC is not running on another thread. + */ + for (;;) { + if (rt->state == JSRTS_UP) { + JS_ASSERT(!JS_CLIST_IS_EMPTY(&rt->contextList)); + first = JS_FALSE; + break; + } + if (rt->state == JSRTS_DOWN) { + JS_ASSERT(JS_CLIST_IS_EMPTY(&rt->contextList)); + first = JS_TRUE; + rt->state = JSRTS_LAUNCHING; + break; + } + JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT); + + /* + * During the above wait after we are notified about the state change + * but before we wake up, another thread could enter the GC from + * js_DestroyContext, bug 478336. So we must wait here to ensure that + * when we exit the loop with the first flag set to true, that GC is + * finished. + */ + js_WaitForGC(rt); + } + JS_APPEND_LINK(&cx->link, &rt->contextList); + JS_UNLOCK_GC(rt); + + js_InitRandom(cx); + + /* + * If cx is the first context on this runtime, initialize well-known atoms, + * keywords, numbers, and strings. If one of these steps should fail, the + * runtime will be left in a partially initialized state, with zeroes and + * nulls stored in the default-initialized remainder of the struct. We'll + * clean the runtime up under js_DestroyContext, because cx will be "last" + * as well as "first". + */ + if (first) { +#ifdef JS_THREADSAFE + JS_BeginRequest(cx); +#endif + ok = js_InitCommonAtoms(cx); + + /* + * scriptFilenameTable may be left over from a previous episode of + * non-zero contexts alive in rt, so don't re-init the table if it's + * not necessary. + */ + if (ok && !rt->scriptFilenameTable) + ok = js_InitRuntimeScriptState(rt); + if (ok) + ok = js_InitRuntimeNumberState(cx); + +#ifdef JS_THREADSAFE + JS_EndRequest(cx); +#endif + if (!ok) { + js_DestroyContext(cx, JSDCM_NEW_FAILED); + return NULL; + } + + AutoLockGC lock(rt); + rt->state = JSRTS_UP; + JS_NOTIFY_ALL_CONDVAR(rt->stateChange); + } + + cxCallback = rt->cxCallback; + if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW)) { + js_DestroyContext(cx, JSDCM_NEW_FAILED); + return NULL; + } + + return cx; +} + +#if defined DEBUG && defined XP_UNIX +# include + +class JSAutoFile { +public: + JSAutoFile() : mFile(NULL) {} + + ~JSAutoFile() { + if (mFile) + fclose(mFile); + } + + FILE *open(const char *fname, const char *mode) { + return mFile = fopen(fname, mode); + } + operator FILE *() { + return mFile; + } + +private: + FILE *mFile; +}; + +static void +DumpEvalCacheMeter(JSContext *cx) +{ + if (const char *filename = getenv("JS_EVALCACHE_STATFILE")) { + struct { + const char *name; + ptrdiff_t offset; + } table[] = { +#define frob(x) { #x, offsetof(JSEvalCacheMeter, x) } + EVAL_CACHE_METER_LIST(frob) +#undef frob + }; + JSEvalCacheMeter *ecm = &cx->compartment->evalCacheMeter; + + static JSAutoFile fp; + if (!fp && !fp.open(filename, "w")) + return; + + fprintf(fp, "eval cache meter (%p):\n", +#ifdef JS_THREADSAFE + (void *) cx->thread +#else + (void *) cx->runtime +#endif + ); + for (uintN i = 0; i < JS_ARRAY_LENGTH(table); ++i) { + fprintf(fp, "%-8.8s %llu\n", + table[i].name, + (unsigned long long int) *(uint64 *)((uint8 *)ecm + table[i].offset)); + } + fprintf(fp, "hit ratio %g%%\n", ecm->hit * 100. / ecm->probe); + fprintf(fp, "avg steps %g\n", double(ecm->step) / ecm->probe); + fflush(fp); + } +} +# define DUMP_EVAL_CACHE_METER(cx) DumpEvalCacheMeter(cx) + +static void +DumpFunctionCountMap(const char *title, JSRuntime::FunctionCountMap &map, FILE *fp) +{ + fprintf(fp, "\n%s count map:\n", title); + + for (JSRuntime::FunctionCountMap::Range r = map.all(); !r.empty(); r.popFront()) { + JSFunction *fun = r.front().key; + int32 count = r.front().value; + + fprintf(fp, "%10d %s:%u\n", count, fun->u.i.script->filename, fun->u.i.script->lineno); + } +} + +static void +DumpFunctionMeter(JSContext *cx) +{ + if (const char *filename = cx->runtime->functionMeterFilename) { + struct { + const char *name; + ptrdiff_t offset; + } table[] = { +#define frob(x) { #x, offsetof(JSFunctionMeter, x) } + FUNCTION_KIND_METER_LIST(frob) +#undef frob + }; + JSFunctionMeter *fm = &cx->runtime->functionMeter; + + static JSAutoFile fp; + if (!fp && !fp.open(filename, "w")) + return; + + fprintf(fp, "function meter (%s):\n", cx->runtime->lastScriptFilename); + for (uintN i = 0; i < JS_ARRAY_LENGTH(table); ++i) + fprintf(fp, "%-19.19s %d\n", table[i].name, *(int32 *)((uint8 *)fm + table[i].offset)); + + DumpFunctionCountMap("method read barrier", cx->runtime->methodReadBarrierCountMap, fp); + DumpFunctionCountMap("unjoined function", cx->runtime->unjoinedFunctionCountMap, fp); + + putc('\n', fp); + fflush(fp); + } +} + +# define DUMP_FUNCTION_METER(cx) DumpFunctionMeter(cx) + +#endif /* DEBUG && XP_UNIX */ + +#ifndef DUMP_EVAL_CACHE_METER +# define DUMP_EVAL_CACHE_METER(cx) ((void) 0) +#endif + +#ifndef DUMP_FUNCTION_METER +# define DUMP_FUNCTION_METER(cx) ((void) 0) +#endif + +void +js_DestroyContext(JSContext *cx, JSDestroyContextMode mode) +{ + JSRuntime *rt; + JSContextCallback cxCallback; + JSBool last; + + JS_ASSERT(!cx->enumerators); + + rt = cx->runtime; +#ifdef JS_THREADSAFE + /* + * For API compatibility we allow to destroy contexts without a thread in + * optimized builds. We assume that the embedding knows that an OOM error + * cannot happen in JS_SetContextThread. + */ + JS_ASSERT(cx->thread && CURRENT_THREAD_IS_ME(cx->thread)); + if (!cx->thread) + JS_SetContextThread(cx); + + /* + * For API compatibility we support destroying contexts with non-zero + * cx->outstandingRequests but we assume that all JS_BeginRequest calls + * on this cx contributes to cx->thread->data.requestDepth and there is no + * JS_SuspendRequest calls that set aside the counter. + */ + JS_ASSERT(cx->outstandingRequests <= cx->thread->data.requestDepth); +#endif + + if (mode != JSDCM_NEW_FAILED) { + cxCallback = rt->cxCallback; + if (cxCallback) { + /* + * JSCONTEXT_DESTROY callback is not allowed to fail and must + * return true. + */ +#ifdef DEBUG + JSBool callbackStatus = +#endif + cxCallback(cx, JSCONTEXT_DESTROY); + JS_ASSERT(callbackStatus); + } + } + + JS_LOCK_GC(rt); + JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING); +#ifdef JS_THREADSAFE + /* + * Typically we are called outside a request, so ensure that the GC is not + * running before removing the context from rt->contextList, see bug 477021. + */ + if (cx->thread->data.requestDepth == 0) + js_WaitForGC(rt); +#endif + JS_REMOVE_LINK(&cx->link); + last = (rt->contextList.next == &rt->contextList); + if (last) + rt->state = JSRTS_LANDING; + if (last || mode == JSDCM_FORCE_GC || mode == JSDCM_MAYBE_GC +#ifdef JS_THREADSAFE + || cx->outstandingRequests != 0 +#endif + ) { + JS_ASSERT(!rt->gcRunning); + + JS_UNLOCK_GC(rt); + + if (last) { +#ifdef JS_THREADSAFE + /* + * If this thread is not in a request already, begin one now so + * that we wait for any racing GC started on a not-last context to + * finish, before we plow ahead and unpin atoms. Note that even + * though we begin a request here if necessary, we end all + * thread's requests before forcing a final GC. This lets any + * not-last context destruction racing in another thread try to + * force or maybe run the GC, but by that point, rt->state will + * not be JSRTS_UP, and that GC attempt will return early. + */ + if (cx->thread->data.requestDepth == 0) + JS_BeginRequest(cx); +#endif + + js_FinishRuntimeNumberState(cx); + + /* Unpin all common atoms before final GC. */ + js_FinishCommonAtoms(cx); + + /* Clear debugging state to remove GC roots. */ + JS_ClearAllTraps(cx); + JS_ClearAllWatchPoints(cx); + } + +#ifdef JS_THREADSAFE + /* + * Destroying a context implicitly calls JS_EndRequest(). Also, we must + * end our request here in case we are "last" -- in that event, another + * js_DestroyContext that was not last might be waiting in the GC for our + * request to end. We'll let it run below, just before we do the truly + * final GC and then free atom state. + */ + while (cx->outstandingRequests != 0) + JS_EndRequest(cx); +#endif + + if (last) { + js_GC(cx, NULL, GC_LAST_CONTEXT); + DUMP_EVAL_CACHE_METER(cx); + DUMP_FUNCTION_METER(cx); + + /* Take the runtime down, now that it has no contexts or atoms. */ + JS_LOCK_GC(rt); + rt->state = JSRTS_DOWN; + JS_NOTIFY_ALL_CONDVAR(rt->stateChange); + } else { + if (mode == JSDCM_FORCE_GC) + js_GC(cx, NULL, GC_NORMAL); + else if (mode == JSDCM_MAYBE_GC) + JS_MaybeGC(cx); + JS_LOCK_GC(rt); + js_WaitForGC(rt); + } + } +#ifdef JS_THREADSAFE +#ifdef DEBUG + JSThread *t = cx->thread; +#endif + js_ClearContextThread(cx); + JS_ASSERT_IF(JS_CLIST_IS_EMPTY(&t->contextList), !t->data.requestDepth); +#endif +#ifdef JS_METER_DST_OFFSET_CACHING + cx->dstOffsetCache.dumpStats(); +#endif + JS_UNLOCK_GC(rt); + FreeContext(cx); +} + +static void +FreeContext(JSContext *cx) +{ +#ifdef JS_THREADSAFE + JS_ASSERT(!cx->thread); +#endif + + /* Free the stuff hanging off of cx. */ + VOUCH_DOES_NOT_REQUIRE_STACK(); + JS_FinishArenaPool(&cx->tempPool); + JS_FinishArenaPool(&cx->regExpPool); + + if (cx->lastMessage) + js_free(cx->lastMessage); + + /* Remove any argument formatters. */ + JSArgumentFormatMap *map = cx->argumentFormatMap; + while (map) { + JSArgumentFormatMap *temp = map; + map = map->next; + cx->free(temp); + } + + /* Destroy the resolve recursion damper. */ + if (cx->resolvingTable) { + JS_DHashTableDestroy(cx->resolvingTable); + cx->resolvingTable = NULL; + } + + /* Finally, free cx itself. */ + cx->~JSContext(); + js_free(cx); +} + +JSContext * +js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp) +{ + JSContext *cx = *iterp; + + Conditionally lockIf(!!unlocked, rt); + cx = js_ContextFromLinkField(cx ? cx->link.next : rt->contextList.next); + if (&cx->link == &rt->contextList) + cx = NULL; + *iterp = cx; + return cx; +} + +JS_FRIEND_API(JSContext *) +js_NextActiveContext(JSRuntime *rt, JSContext *cx) +{ + JSContext *iter = cx; +#ifdef JS_THREADSAFE + while ((cx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) { + if (cx->outstandingRequests && cx->thread->data.requestDepth) + break; + } + return cx; +#else + return js_ContextIterator(rt, JS_FALSE, &iter); +#endif +} + +static JSDHashNumber +resolving_HashKey(JSDHashTable *table, const void *ptr) +{ + const JSResolvingKey *key = (const JSResolvingKey *)ptr; + + return (JSDHashNumber(uintptr_t(key->obj)) >> JS_GCTHING_ALIGN) ^ JSID_BITS(key->id); +} + +static JSBool +resolving_MatchEntry(JSDHashTable *table, + const JSDHashEntryHdr *hdr, + const void *ptr) +{ + const JSResolvingEntry *entry = (const JSResolvingEntry *)hdr; + const JSResolvingKey *key = (const JSResolvingKey *)ptr; + + return entry->key.obj == key->obj && entry->key.id == key->id; +} + +static const JSDHashTableOps resolving_dhash_ops = { + JS_DHashAllocTable, + JS_DHashFreeTable, + resolving_HashKey, + resolving_MatchEntry, + JS_DHashMoveEntryStub, + JS_DHashClearEntryStub, + JS_DHashFinalizeStub, + NULL +}; + +JSBool +js_StartResolving(JSContext *cx, JSResolvingKey *key, uint32 flag, + JSResolvingEntry **entryp) +{ + JSDHashTable *table; + JSResolvingEntry *entry; + + table = cx->resolvingTable; + if (!table) { + table = JS_NewDHashTable(&resolving_dhash_ops, NULL, + sizeof(JSResolvingEntry), + JS_DHASH_MIN_SIZE); + if (!table) + goto outofmem; + cx->resolvingTable = table; + } + + entry = (JSResolvingEntry *) + JS_DHashTableOperate(table, key, JS_DHASH_ADD); + if (!entry) + goto outofmem; + + if (entry->flags & flag) { + /* An entry for (key, flag) exists already -- dampen recursion. */ + entry = NULL; + } else { + /* Fill in key if we were the first to add entry, then set flag. */ + if (!entry->key.obj) + entry->key = *key; + entry->flags |= flag; + } + *entryp = entry; + return JS_TRUE; + +outofmem: + JS_ReportOutOfMemory(cx); + return JS_FALSE; +} + +void +js_StopResolving(JSContext *cx, JSResolvingKey *key, uint32 flag, + JSResolvingEntry *entry, uint32 generation) +{ + JSDHashTable *table; + + /* + * Clear flag from entry->flags and return early if other flags remain. + * We must take care to re-lookup entry if the table has changed since + * it was found by js_StartResolving. + */ + table = cx->resolvingTable; + if (!entry || table->generation != generation) { + entry = (JSResolvingEntry *) + JS_DHashTableOperate(table, key, JS_DHASH_LOOKUP); + } + JS_ASSERT(JS_DHASH_ENTRY_IS_BUSY(&entry->hdr)); + entry->flags &= ~flag; + if (entry->flags) + return; + + /* + * Do a raw remove only if fewer entries were removed than would cause + * alpha to be less than .5 (alpha is at most .75). Otherwise, we just + * call JS_DHashTableOperate to re-lookup the key and remove its entry, + * compressing or shrinking the table as needed. + */ + if (table->removedCount < JS_DHASH_TABLE_SIZE(table) >> 2) + JS_DHashTableRawRemove(table, &entry->hdr); + else + JS_DHashTableOperate(table, key, JS_DHASH_REMOVE); +} + +static void +ReportError(JSContext *cx, const char *message, JSErrorReport *reportp, + JSErrorCallback callback, void *userRef) +{ + /* + * Check the error report, and set a JavaScript-catchable exception + * if the error is defined to have an associated exception. If an + * exception is thrown, then the JSREPORT_EXCEPTION flag will be set + * on the error report, and exception-aware hosts should ignore it. + */ + JS_ASSERT(reportp); + if ((!callback || callback == js_GetErrorMessage) && + reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION) + reportp->flags |= JSREPORT_EXCEPTION; + + /* + * Call the error reporter only if an exception wasn't raised. + * + * If an exception was raised, then we call the debugErrorHook + * (if present) to give it a chance to see the error before it + * propagates out of scope. This is needed for compatability + * with the old scheme. + */ + if (!JS_IsRunning(cx) || + !js_ErrorToException(cx, message, reportp, callback, userRef)) { + js_ReportErrorAgain(cx, message, reportp); + } else if (cx->debugHooks->debugErrorHook && cx->errorReporter) { + JSDebugErrorHook hook = cx->debugHooks->debugErrorHook; + /* test local in case debugErrorHook changed on another thread */ + if (hook) + hook(cx, message, reportp, cx->debugHooks->debugErrorHookData); + } +} + +/* The report must be initially zeroed. */ +static void +PopulateReportBlame(JSContext *cx, JSErrorReport *report) +{ + /* + * Walk stack until we find a frame that is associated with some script + * rather than a native frame. + */ + for (JSStackFrame *fp = js_GetTopStackFrame(cx); fp; fp = fp->prev()) { + if (fp->pc(cx)) { + report->filename = fp->script()->filename; + report->lineno = js_FramePCToLineNumber(cx, fp); + break; + } + } +} + +/* + * We don't post an exception in this case, since doing so runs into + * complications of pre-allocating an exception object which required + * running the Exception class initializer early etc. + * Instead we just invoke the errorReporter with an "Out Of Memory" + * type message, and then hope the process ends swiftly. + */ +void +js_ReportOutOfMemory(JSContext *cx) +{ +#ifdef JS_TRACER + /* + * If we are in a builtin called directly from trace, don't report an + * error. We will retry in the interpreter instead. + */ + if (JS_ON_TRACE(cx) && !JS_TRACE_MONITOR_ON_TRACE(cx)->bailExit) + return; +#endif + + JSErrorReport report; + JSErrorReporter onError = cx->errorReporter; + + /* Get the message for this error, but we won't expand any arguments. */ + const JSErrorFormatString *efs = + js_GetLocalizedErrorMessage(cx, NULL, NULL, JSMSG_OUT_OF_MEMORY); + const char *msg = efs ? efs->format : "Out of memory"; + + /* Fill out the report, but don't do anything that requires allocation. */ + PodZero(&report); + report.flags = JSREPORT_ERROR; + report.errorNumber = JSMSG_OUT_OF_MEMORY; + PopulateReportBlame(cx, &report); + + /* + * If debugErrorHook is present then we give it a chance to veto sending + * the error on to the regular ErrorReporter. We also clear a pending + * exception if any now so the hooks can replace the out-of-memory error + * by a script-catchable exception. + */ + cx->clearPendingException(); + if (onError) { + JSDebugErrorHook hook = cx->debugHooks->debugErrorHook; + if (hook && + !hook(cx, msg, &report, cx->debugHooks->debugErrorHookData)) { + onError = NULL; + } + } + + if (onError) + onError(cx, msg, &report); +} + +void +js_ReportOutOfScriptQuota(JSContext *cx) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_SCRIPT_STACK_QUOTA); +} + +JS_FRIEND_API(void) +js_ReportOverRecursed(JSContext *cx) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED); +} + +void +js_ReportAllocationOverflow(JSContext *cx) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ALLOC_OVERFLOW); +} + +/* + * Given flags and the state of cx, decide whether we should report an + * error, a warning, or just continue execution normally. Return + * true if we should continue normally, without reporting anything; + * otherwise, adjust *flags as appropriate and return false. + */ +static bool +checkReportFlags(JSContext *cx, uintN *flags) +{ + if (JSREPORT_IS_STRICT_MODE_ERROR(*flags)) { + /* + * Error in strict code; warning with strict option; okay otherwise. + * We assume that if the top frame is a native, then it is strict if + * the nearest scripted frame is strict, see bug 536306. + */ + JSStackFrame *fp = js_GetScriptedCaller(cx, NULL); + if (fp && fp->script()->strictModeCode) + *flags &= ~JSREPORT_WARNING; + else if (cx->hasStrictOption()) + *flags |= JSREPORT_WARNING; + else + return true; + } else if (JSREPORT_IS_STRICT(*flags)) { + /* Warning/error only when JSOPTION_STRICT is set. */ + if (!cx->hasStrictOption()) + return true; + } + + /* Warnings become errors when JSOPTION_WERROR is set. */ + if (JSREPORT_IS_WARNING(*flags) && cx->hasWErrorOption()) + *flags &= ~JSREPORT_WARNING; + + return false; +} + +JSBool +js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap) +{ + char *message; + jschar *ucmessage; + size_t messagelen; + JSErrorReport report; + JSBool warning; + + if (checkReportFlags(cx, &flags)) + return JS_TRUE; + + message = JS_vsmprintf(format, ap); + if (!message) + return JS_FALSE; + messagelen = strlen(message); + + PodZero(&report); + report.flags = flags; + report.errorNumber = JSMSG_USER_DEFINED_ERROR; + report.ucmessage = ucmessage = js_InflateString(cx, message, &messagelen); + PopulateReportBlame(cx, &report); + + warning = JSREPORT_IS_WARNING(report.flags); + + ReportError(cx, message, &report, NULL, NULL); + js_free(message); + cx->free(ucmessage); + return warning; +} + +/* + * The arguments from ap need to be packaged up into an array and stored + * into the report struct. + * + * The format string addressed by the error number may contain operands + * identified by the format {N}, where N is a decimal digit. Each of these + * is to be replaced by the Nth argument from the va_list. The complete + * message is placed into reportp->ucmessage converted to a JSString. + * + * Returns true if the expansion succeeds (can fail if out of memory). + */ +JSBool +js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback, + void *userRef, const uintN errorNumber, + char **messagep, JSErrorReport *reportp, + bool charArgs, va_list ap) +{ + const JSErrorFormatString *efs; + int i; + int argCount; + + *messagep = NULL; + + /* Most calls supply js_GetErrorMessage; if this is so, assume NULL. */ + if (!callback || callback == js_GetErrorMessage) + efs = js_GetLocalizedErrorMessage(cx, userRef, NULL, errorNumber); + else + efs = callback(userRef, NULL, errorNumber); + if (efs) { + size_t totalArgsLength = 0; + size_t argLengths[10]; /* only {0} thru {9} supported */ + argCount = efs->argCount; + JS_ASSERT(argCount <= 10); + if (argCount > 0) { + /* + * Gather the arguments into an array, and accumulate + * their sizes. We allocate 1 more than necessary and + * null it out to act as the caboose when we free the + * pointers later. + */ + reportp->messageArgs = (const jschar **) + cx->malloc(sizeof(jschar *) * (argCount + 1)); + if (!reportp->messageArgs) + return JS_FALSE; + reportp->messageArgs[argCount] = NULL; + for (i = 0; i < argCount; i++) { + if (charArgs) { + char *charArg = va_arg(ap, char *); + size_t charArgLength = strlen(charArg); + reportp->messageArgs[i] + = js_InflateString(cx, charArg, &charArgLength); + if (!reportp->messageArgs[i]) + goto error; + } else { + reportp->messageArgs[i] = va_arg(ap, jschar *); + } + argLengths[i] = js_strlen(reportp->messageArgs[i]); + totalArgsLength += argLengths[i]; + } + /* NULL-terminate for easy copying. */ + reportp->messageArgs[i] = NULL; + } + /* + * Parse the error format, substituting the argument X + * for {X} in the format. + */ + if (argCount > 0) { + if (efs->format) { + jschar *buffer, *fmt, *out; + int expandedArgs = 0; + size_t expandedLength; + size_t len = strlen(efs->format); + + buffer = fmt = js_InflateString (cx, efs->format, &len); + if (!buffer) + goto error; + expandedLength = len + - (3 * argCount) /* exclude the {n} */ + + totalArgsLength; + + /* + * Note - the above calculation assumes that each argument + * is used once and only once in the expansion !!! + */ + reportp->ucmessage = out = (jschar *) + cx->malloc((expandedLength + 1) * sizeof(jschar)); + if (!out) { + cx->free(buffer); + goto error; + } + while (*fmt) { + if (*fmt == '{') { + if (isdigit(fmt[1])) { + int d = JS7_UNDEC(fmt[1]); + JS_ASSERT(d < argCount); + js_strncpy(out, reportp->messageArgs[d], + argLengths[d]); + out += argLengths[d]; + fmt += 3; + expandedArgs++; + continue; + } + } + *out++ = *fmt++; + } + JS_ASSERT(expandedArgs == argCount); + *out = 0; + cx->free(buffer); + *messagep = + js_DeflateString(cx, reportp->ucmessage, + (size_t)(out - reportp->ucmessage)); + if (!*messagep) + goto error; + } + } else { + /* + * Zero arguments: the format string (if it exists) is the + * entire message. + */ + if (efs->format) { + size_t len; + *messagep = JS_strdup(cx, efs->format); + if (!*messagep) + goto error; + len = strlen(*messagep); + reportp->ucmessage = js_InflateString(cx, *messagep, &len); + if (!reportp->ucmessage) + goto error; + } + } + } + if (*messagep == NULL) { + /* where's the right place for this ??? */ + const char *defaultErrorMessage + = "No error message available for error number %d"; + size_t nbytes = strlen(defaultErrorMessage) + 16; + *messagep = (char *)cx->malloc(nbytes); + if (!*messagep) + goto error; + JS_snprintf(*messagep, nbytes, defaultErrorMessage, errorNumber); + } + return JS_TRUE; + +error: + if (reportp->messageArgs) { + /* free the arguments only if we allocated them */ + if (charArgs) { + i = 0; + while (reportp->messageArgs[i]) + cx->free((void *)reportp->messageArgs[i++]); + } + cx->free((void *)reportp->messageArgs); + reportp->messageArgs = NULL; + } + if (reportp->ucmessage) { + cx->free((void *)reportp->ucmessage); + reportp->ucmessage = NULL; + } + if (*messagep) { + cx->free((void *)*messagep); + *messagep = NULL; + } + return JS_FALSE; +} + +JSBool +js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback, + void *userRef, const uintN errorNumber, + JSBool charArgs, va_list ap) +{ + JSErrorReport report; + char *message; + JSBool warning; + + if (checkReportFlags(cx, &flags)) + return JS_TRUE; + warning = JSREPORT_IS_WARNING(flags); + + PodZero(&report); + report.flags = flags; + report.errorNumber = errorNumber; + PopulateReportBlame(cx, &report); + + if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber, + &message, &report, !!charArgs, ap)) { + return JS_FALSE; + } + + ReportError(cx, message, &report, callback, userRef); + + if (message) + cx->free(message); + if (report.messageArgs) { + /* + * js_ExpandErrorArguments owns its messageArgs only if it had to + * inflate the arguments (from regular |char *|s). + */ + if (charArgs) { + int i = 0; + while (report.messageArgs[i]) + cx->free((void *)report.messageArgs[i++]); + } + cx->free((void *)report.messageArgs); + } + if (report.ucmessage) + cx->free((void *)report.ucmessage); + + return warning; +} + +JS_FRIEND_API(void) +js_ReportErrorAgain(JSContext *cx, const char *message, JSErrorReport *reportp) +{ + JSErrorReporter onError; + + if (!message) + return; + + if (cx->lastMessage) + js_free(cx->lastMessage); + cx->lastMessage = JS_strdup(cx, message); + if (!cx->lastMessage) + return; + onError = cx->errorReporter; + + /* + * If debugErrorHook is present then we give it a chance to veto + * sending the error on to the regular ErrorReporter. + */ + if (onError) { + JSDebugErrorHook hook = cx->debugHooks->debugErrorHook; + if (hook && + !hook(cx, cx->lastMessage, reportp, + cx->debugHooks->debugErrorHookData)) { + onError = NULL; + } + } + if (onError) + onError(cx, cx->lastMessage, reportp); +} + +void +js_ReportIsNotDefined(JSContext *cx, const char *name) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_DEFINED, name); +} + +JSBool +js_ReportIsNullOrUndefined(JSContext *cx, intN spindex, const Value &v, + JSString *fallback) +{ + char *bytes; + JSBool ok; + + bytes = DecompileValueGenerator(cx, spindex, v, fallback); + if (!bytes) + return JS_FALSE; + + if (strcmp(bytes, js_undefined_str) == 0 || + strcmp(bytes, js_null_str) == 0) { + ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, + js_GetErrorMessage, NULL, + JSMSG_NO_PROPERTIES, bytes, + NULL, NULL); + } else if (v.isUndefined()) { + ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, + js_GetErrorMessage, NULL, + JSMSG_UNEXPECTED_TYPE, bytes, + js_undefined_str, NULL); + } else { + JS_ASSERT(v.isNull()); + ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, + js_GetErrorMessage, NULL, + JSMSG_UNEXPECTED_TYPE, bytes, + js_null_str, NULL); + } + + cx->free(bytes); + return ok; +} + +void +js_ReportMissingArg(JSContext *cx, const Value &v, uintN arg) +{ + char argbuf[11]; + char *bytes; + JSAtom *atom; + + JS_snprintf(argbuf, sizeof argbuf, "%u", arg); + bytes = NULL; + if (IsFunctionObject(v)) { + atom = GET_FUNCTION_PRIVATE(cx, &v.toObject())->atom; + bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, + v, ATOM_TO_STRING(atom)); + if (!bytes) + return; + } + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_MISSING_FUN_ARG, argbuf, + bytes ? bytes : ""); + cx->free(bytes); +} + +JSBool +js_ReportValueErrorFlags(JSContext *cx, uintN flags, const uintN errorNumber, + intN spindex, const Value &v, JSString *fallback, + const char *arg1, const char *arg2) +{ + char *bytes; + JSBool ok; + + JS_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1); + JS_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3); + bytes = DecompileValueGenerator(cx, spindex, v, fallback); + if (!bytes) + return JS_FALSE; + + ok = JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage, + NULL, errorNumber, bytes, arg1, arg2); + cx->free(bytes); + return ok; +} + +#if defined DEBUG && defined XP_UNIX +/* For gdb usage. */ +void js_logon(JSContext *cx) { cx->logfp = stderr; cx->logPrevPc = NULL; } +void js_logoff(JSContext *cx) { cx->logfp = NULL; } +#endif + +JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = { +#define MSG_DEF(name, number, count, exception, format) \ + { format, count, exception } , +#include "js.msg" +#undef MSG_DEF +}; + +JS_FRIEND_API(const JSErrorFormatString *) +js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber) +{ + if ((errorNumber > 0) && (errorNumber < JSErr_Limit)) + return &js_ErrorFormatString[errorNumber]; + return NULL; +} + +JSBool +js_InvokeOperationCallback(JSContext *cx) +{ + JSRuntime *rt = cx->runtime; + JSThreadData *td = JS_THREAD_DATA(cx); + + JS_ASSERT_REQUEST_DEPTH(cx); + JS_ASSERT(td->interruptFlags != 0); + + /* + * Reset the callback counter first, then run GC and yield. If another + * thread is racing us here we will accumulate another callback request + * which will be serviced at the next opportunity. + */ + JS_LOCK_GC(rt); + td->interruptFlags = 0; +#ifdef JS_THREADSAFE + JS_ATOMIC_DECREMENT(&rt->interruptCounter); +#endif + JS_UNLOCK_GC(rt); + + if (rt->gcIsNeeded) { + js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL); + + /* + * On trace we can exceed the GC quota, see comments in NewGCArena. So + * we check the quota and report OOM here when we are off trace. + */ + bool delayedOutOfMemory; + JS_LOCK_GC(rt); + delayedOutOfMemory = (rt->gcBytes > rt->gcMaxBytes); + JS_UNLOCK_GC(rt); + if (delayedOutOfMemory) { + js_ReportOutOfMemory(cx); + return false; + } + } + +#ifdef JS_THREADSAFE + /* + * We automatically yield the current context every time the operation + * callback is hit since we might be called as a result of an impending + * GC on another thread, which would deadlock if we do not yield. + * Operation callbacks are supposed to happen rarely (seconds, not + * milliseconds) so it is acceptable to yield at every callback. + * + * As the GC can be canceled before it does any request checks we yield + * even if rt->gcIsNeeded was true above. See bug 590533. + */ + JS_YieldRequest(cx); +#endif + + JSOperationCallback cb = cx->operationCallback; + + /* + * Important: Additional callbacks can occur inside the callback handler + * if it re-enters the JS engine. The embedding must ensure that the + * callback is disconnected before attempting such re-entry. + */ + + return !cb || cb(cx); +} + +JSBool +js_HandleExecutionInterrupt(JSContext *cx) +{ + JSBool result = JS_TRUE; + if (JS_THREAD_DATA(cx)->interruptFlags) + result = js_InvokeOperationCallback(cx) && result; + return result; +} + +namespace js { + +void +TriggerOperationCallback(JSContext *cx) +{ + /* + * We allow for cx to come from another thread. Thus we must deal with + * possible JS_ClearContextThread calls when accessing cx->thread. But we + * assume that the calling thread is in a request so JSThread cannot be + * GC-ed. + */ + JSThreadData *td; +#ifdef JS_THREADSAFE + JSThread *thread = cx->thread; + if (!thread) + return; + td = &thread->data; +#else + td = JS_THREAD_DATA(cx); +#endif + td->triggerOperationCallback(cx->runtime); +} + +void +TriggerAllOperationCallbacks(JSRuntime *rt) +{ + for (ThreadDataIter i(rt); !i.empty(); i.popFront()) + i.threadData()->triggerOperationCallback(rt); +} + +} /* namespace js */ + +JSStackFrame * +js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp) +{ + if (!fp) + fp = js_GetTopStackFrame(cx); + while (fp && fp->isDummyFrame()) + fp = fp->prev(); + JS_ASSERT_IF(fp, fp->isScriptFrame()); + return fp; +} + +jsbytecode* +js_GetCurrentBytecodePC(JSContext* cx) +{ + jsbytecode *pc, *imacpc; + +#ifdef JS_TRACER + if (JS_ON_TRACE(cx)) { + pc = JS_TRACE_MONITOR_ON_TRACE(cx)->bailExit->pc; + imacpc = JS_TRACE_MONITOR_ON_TRACE(cx)->bailExit->imacpc; + } else +#endif + { + JS_ASSERT_NOT_ON_TRACE(cx); /* for static analysis */ + pc = cx->regs ? cx->regs->pc : NULL; + if (!pc) + return NULL; + imacpc = cx->fp()->maybeImacropc(); + } + + /* + * If we are inside GetProperty_tn or similar, return a pointer to the + * current instruction in the script, not the CALL instruction in the + * imacro, for the benefit of callers doing bytecode inspection. + */ + return (*pc == JSOP_CALL && imacpc) ? imacpc : pc; +} + +bool +js_CurrentPCIsInImacro(JSContext *cx) +{ +#ifdef JS_TRACER + VOUCH_DOES_NOT_REQUIRE_STACK(); + if (JS_ON_TRACE(cx)) + return JS_TRACE_MONITOR_ON_TRACE(cx)->bailExit->imacpc != NULL; + return cx->fp()->hasImacropc(); +#else + return false; +#endif +} + +void +DSTOffsetCache::purge() +{ + /* + * NB: The initial range values are carefully chosen to result in a cache + * miss on first use given the range of possible values. Be careful + * to keep these values and the caching algorithm in sync! + */ + offsetMilliseconds = 0; + rangeStartSeconds = rangeEndSeconds = INT64_MIN; + oldOffsetMilliseconds = 0; + oldRangeStartSeconds = oldRangeEndSeconds = INT64_MIN; + +#ifdef JS_METER_DST_OFFSET_CACHING + totalCalculations = 0; + hit = 0; + missIncreasing = missDecreasing = 0; + missIncreasingOffsetChangeExpand = missIncreasingOffsetChangeUpper = 0; + missDecreasingOffsetChangeExpand = missDecreasingOffsetChangeLower = 0; + missLargeIncrease = missLargeDecrease = 0; +#endif + + sanityCheck(); +} + +/* + * Since getDSTOffsetMilliseconds guarantees that all times seen will be + * positive, we can initialize the range at construction time with large + * negative numbers to ensure the first computation is always a cache miss and + * doesn't return a bogus offset. + */ +DSTOffsetCache::DSTOffsetCache() +{ + purge(); +} + +JSContext::JSContext(JSRuntime *rt) + : hasVersionOverride(false), + runtime(rt), + compartment(NULL), + regs(NULL), + busyArrays() +{} + +void +JSContext::resetCompartment() +{ + JSObject *scopeobj; + if (hasfp()) { + scopeobj = &fp()->scopeChain(); + } else { + scopeobj = globalObject; + if (!scopeobj) + goto error; + + /* + * Innerize. Assert, but check anyway, that this succeeds. (It + * can only fail due to bugs in the engine or embedding.) + */ + OBJ_TO_INNER_OBJECT(this, scopeobj); + if (!scopeobj) + goto error; + } + + compartment = scopeobj->compartment(); + + if (isExceptionPending()) + wrapPendingException(); + return; + +error: + + /* + * If we try to use the context without a selected compartment, + * we will crash. + */ + compartment = NULL; +} + +/* + * Since this function is only called in the context of a pending exception, + * the caller must subsequently take an error path. If wrapping fails, it will + * set a new (uncatchable) exception to be used in place of the original. + */ +void +JSContext::wrapPendingException() +{ + Value v = getPendingException(); + clearPendingException(); + if (compartment->wrap(this, &v)) + setPendingException(v); +} + +void +JSContext::pushSegmentAndFrame(js::StackSegment *newseg, JSFrameRegs &newregs) +{ + JS_ASSERT(regs != &newregs); + if (hasActiveSegment()) + currentSegment->suspend(regs); + newseg->setPreviousInContext(currentSegment); + currentSegment = newseg; + setCurrentRegs(&newregs); + newseg->joinContext(this, newregs.fp); +} + +void +JSContext::popSegmentAndFrame() +{ + /* + * NB: This function calls resetCompartment, which may GC, so the stack needs + * to be in a GC-able state by that point. + */ + + JS_ASSERT(currentSegment->maybeContext() == this); + JS_ASSERT(currentSegment->getInitialFrame() == regs->fp); + currentSegment->leaveContext(); + currentSegment = currentSegment->getPreviousInContext(); + if (currentSegment) { + if (currentSegment->isSaved()) { + setCurrentRegs(NULL); + resetCompartment(); + } else { + setCurrentRegs(currentSegment->getSuspendedRegs()); + currentSegment->resume(); + } + } else { + JS_ASSERT(regs->fp->prev() == NULL); + setCurrentRegs(NULL); + resetCompartment(); + } + maybeMigrateVersionOverride(); +} + +void +JSContext::saveActiveSegment() +{ + JS_ASSERT(hasActiveSegment()); + currentSegment->save(regs); + setCurrentRegs(NULL); + resetCompartment(); +} + +void +JSContext::restoreSegment() +{ + js::StackSegment *ccs = currentSegment; + setCurrentRegs(ccs->getSuspendedRegs()); + ccs->restore(); + resetCompartment(); +} + +JSGenerator * +JSContext::generatorFor(JSStackFrame *fp) const +{ + JS_ASSERT(stack().contains(fp) && fp->isGeneratorFrame()); + JS_ASSERT(!fp->isFloatingGenerator()); + JS_ASSERT(!genStack.empty()); + + if (JS_LIKELY(fp == genStack.back()->liveFrame())) + return genStack.back(); + + /* General case; should only be needed for debug APIs. */ + for (size_t i = 0; i < genStack.length(); ++i) { + if (genStack[i]->liveFrame() == fp) + return genStack[i]; + } + JS_NOT_REACHED("no matching generator"); + return NULL; +} + +StackSegment * +JSContext::containingSegment(const JSStackFrame *target) +{ + /* The context may have nothing running. */ + StackSegment *seg = currentSegment; + if (!seg) + return NULL; + + /* The active segments's top frame is cx->regs->fp. */ + if (regs) { + JS_ASSERT(regs->fp); + JS_ASSERT(activeSegment() == seg); + JSStackFrame *f = regs->fp; + JSStackFrame *stop = seg->getInitialFrame()->prev(); + for (; f != stop; f = f->prev()) { + if (f == target) + return seg; + } + seg = seg->getPreviousInContext(); + } + + /* A suspended segment's top frame is its suspended frame. */ + for (; seg; seg = seg->getPreviousInContext()) { + JSStackFrame *f = seg->getSuspendedFrame(); + JSStackFrame *stop = seg->getInitialFrame()->prev(); + for (; f != stop; f = f->prev()) { + if (f == target) + return seg; + } + } + + return NULL; +} + +JS_FRIEND_API(void) +JSRuntime::onTooMuchMalloc() +{ +#ifdef JS_THREADSAFE + AutoLockGC lock(this); + + /* + * We can be called outside a request and can race against a GC that + * mutates the JSThread set during the sweeping phase. + */ + js_WaitForGC(this); +#endif + TriggerGC(this); +} + +JS_FRIEND_API(void *) +JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx) +{ +#ifdef JS_THREADSAFE + gcHelperThread.waitBackgroundSweepEnd(this); + if (!p) + p = ::js_malloc(nbytes); + else if (p == reinterpret_cast(1)) + p = ::js_calloc(nbytes); + else + p = ::js_realloc(p, nbytes); + if (p) + return p; +#endif + if (cx) + js_ReportOutOfMemory(cx); + return NULL; +} + +/* + * Release pool's arenas if the stackPool has existed for longer than the + * limit specified by gcEmptyArenaPoolLifespan. + */ +inline void +FreeOldArenas(JSRuntime *rt, JSArenaPool *pool) +{ + JSArena *a = pool->current; + if (a == pool->first.next && a->avail == a->base + sizeof(int64)) { + int64 age = JS_Now() - *(int64 *) a->base; + if (age > int64(rt->gcEmptyArenaPoolLifespan) * 1000) + JS_FreeArenaPool(pool); + } +} + +void +JSContext::purge() +{ + FreeOldArenas(runtime, ®ExpPool); +} + +static bool +ComputeIsJITBroken() +{ +#ifndef ANDROID + return false; +#else // ANDROID + if (getenv("JS_IGNORE_JIT_BROKENNESS")) { + return false; + } + + std::string line; + + // Check for the known-bad kernel version (2.6.29). + std::ifstream osrelease("/proc/sys/kernel/osrelease"); + std::getline(osrelease, line); + __android_log_print(ANDROID_LOG_INFO, "Gecko", "Detected osrelease `%s'", + line.c_str()); + + if (line.npos == line.find("2.6.29")) { + // We're using something other than 2.6.29, so the JITs should work. + __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are not broken"); + return false; + } + + // We're using 2.6.29, and this causes trouble with the JITs on i9000. + line = ""; + bool broken = false; + std::ifstream cpuinfo("/proc/cpuinfo"); + do { + if (0 == line.find("Hardware")) { + const char* blacklist[] = { + "SGH-T959", // Samsung i9000, Vibrant device + "SGH-I897", // Samsung i9000, Captivate device + "SCH-I500", // Samsung i9000, Fascinate device + "SPH-D700", // Samsung i9000, Epic device + "GT-I9000", // Samsung i9000, UK/Europe device + NULL + }; + for (const char** hw = &blacklist[0]; *hw; ++hw) { + if (line.npos != line.find(*hw)) { + __android_log_print(ANDROID_LOG_INFO, "Gecko", + "Blacklisted device `%s'", *hw); + broken = true; + break; + } + } + break; + } + std::getline(cpuinfo, line); + } while(!cpuinfo.fail() && !cpuinfo.eof()); + + __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are %sbroken", + broken ? "" : "not "); + + return broken; +#endif // ifndef ANDROID +} + +static bool +IsJITBrokenHere() +{ + static bool computedIsBroken = false; + static bool isBroken = false; + if (!computedIsBroken) { + isBroken = ComputeIsJITBroken(); + computedIsBroken = true; + } + return isBroken; +} + +void +JSContext::updateJITEnabled() +{ +#ifdef JS_TRACER + traceJitEnabled = ((runOptions & JSOPTION_JIT) && + !IsJITBrokenHere() && + (debugHooks == &js_NullDebugHooks || + (debugHooks == &runtime->globalDebugHooks && + !runtime->debuggerInhibitsJIT()))); +#endif +#ifdef JS_METHODJIT + methodJitEnabled = (runOptions & JSOPTION_METHODJIT) && + !IsJITBrokenHere() +# if defined JS_CPU_X86 || defined JS_CPU_X64 + && JSC::MacroAssemblerX86Common::getSSEState() >= + JSC::MacroAssemblerX86Common::HasSSE2 +# endif + ; +#ifdef JS_TRACER + profilingEnabled = (runOptions & JSOPTION_PROFILING) && traceJitEnabled && methodJitEnabled; +#endif +#endif +} + +namespace js { + +JS_FORCES_STACK JS_FRIEND_API(void) +LeaveTrace(JSContext *cx) +{ +#ifdef JS_TRACER + if (JS_ON_TRACE(cx)) + DeepBail(cx); +#endif +} + +} /* namespace js */ diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h new file mode 100644 index 0000000..4c9a2cc --- /dev/null +++ b/js/src/jscntxt.h @@ -0,0 +1,3348 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jscntxt_h___ +#define jscntxt_h___ +/* + * JS execution context. + */ +#include + +/* Gross special case for Gecko, which defines malloc/calloc/free. */ +#ifdef mozilla_mozalloc_macro_wrappers_h +# define JS_CNTXT_UNDEFD_MOZALLOC_WRAPPERS +/* The "anti-header" */ +# include "mozilla/mozalloc_undef_macro_wrappers.h" +#endif + +#include "jsprvtd.h" +#include "jsarena.h" +#include "jsclist.h" +#include "jslong.h" +#include "jsatom.h" +#include "jsdhash.h" +#include "jsdtoa.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsgcchunk.h" +#include "jshashtable.h" +#include "jsinterp.h" +#include "jsmath.h" +#include "jsobj.h" +#include "jspropertycache.h" +#include "jspropertytree.h" +#include "jsstaticcheck.h" +#include "jsutil.h" +#include "jsarray.h" +#include "jsvector.h" +#include "prmjtime.h" + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */ +#pragma warning(push) +#pragma warning(disable:4355) /* Silence warning about "this" used in base member initializer list */ +#endif + +/* + * js_GetSrcNote cache to avoid O(n^2) growth in finding a source note for a + * given pc in a script. We use the script->code pointer to tag the cache, + * instead of the script address itself, so that source notes are always found + * by offset from the bytecode with which they were generated. + */ +typedef struct JSGSNCache { + jsbytecode *code; + JSDHashTable table; +#ifdef JS_GSNMETER + uint32 hits; + uint32 misses; + uint32 fills; + uint32 purges; +# define GSN_CACHE_METER(cache,cnt) (++(cache)->cnt) +#else +# define GSN_CACHE_METER(cache,cnt) /* nothing */ +#endif +} JSGSNCache; + +#define js_FinishGSNCache(cache) js_PurgeGSNCache(cache) + +extern void +js_PurgeGSNCache(JSGSNCache *cache); + +/* These helper macros take a cx as parameter and operate on its GSN cache. */ +#define JS_PURGE_GSN_CACHE(cx) js_PurgeGSNCache(&JS_GSN_CACHE(cx)) +#define JS_METER_GSN_CACHE(cx,cnt) GSN_CACHE_METER(&JS_GSN_CACHE(cx), cnt) + +/* Forward declarations of nanojit types. */ +namespace nanojit { + +class Assembler; +class CodeAlloc; +class Fragment; +template struct DefaultHash; +template class HashMap; +template class Seq; + +} /* namespace nanojit */ + +namespace js { + +/* Tracer constants. */ +static const size_t MONITOR_N_GLOBAL_STATES = 4; +static const size_t FRAGMENT_TABLE_SIZE = 512; +static const size_t MAX_NATIVE_STACK_SLOTS = 4096; +static const size_t MAX_CALL_STACK_ENTRIES = 500; +static const size_t MAX_GLOBAL_SLOTS = 4096; +static const size_t GLOBAL_SLOTS_BUFFER_SIZE = MAX_GLOBAL_SLOTS + 1; +static const size_t MAX_SLOW_NATIVE_EXTRA_SLOTS = 16; + +/* Forward declarations of tracer types. */ +class VMAllocator; +class FrameInfoCache; +struct FrameInfo; +struct VMSideExit; +struct TreeFragment; +struct TracerState; +template class Queue; +typedef Queue SlotList; +class TypeMap; +class LoopProfile; + +#if defined(JS_JIT_SPEW) || defined(DEBUG) +struct FragPI; +typedef nanojit::HashMap > FragStatsMap; +#endif + +namespace mjit { +class JaegerCompartment; +} + +/* + * Allocation policy that calls JSContext memory functions and reports errors + * to the context. Since the JSContext given on construction is stored for + * the lifetime of the container, this policy may only be used for containers + * whose lifetime is a shorter than the given JSContext. + */ +class ContextAllocPolicy +{ + JSContext *cx; + + public: + ContextAllocPolicy(JSContext *cx) : cx(cx) {} + JSContext *context() const { return cx; } + + /* Inline definitions below. */ + void *malloc(size_t bytes); + void free(void *p); + void *realloc(void *p, size_t bytes); + void reportAllocOverflow() const; +}; + +/* + * A StackSegment (referred to as just a 'segment') contains a prev-linked set + * of stack frames and the slots associated with each frame. A segment and its + * contained frames/slots also have a precise memory layout that is described + * in the js::StackSpace comment. A key layout invariant for segments is that + * prev-linked frames are adjacent in memory, separated only by the values that + * constitute the locals and expression stack of the prev-frame. + * + * The set of stack frames in a non-empty segment start at the segment's + * "current frame", which is the most recently pushed frame, and ends at the + * segment's "initial frame". Note that, while all stack frames in a segment + * are prev-linked, not all prev-linked frames are in the same segment. Hence, + * for a segment |ss|, |ss->getInitialFrame()->prev| may be non-null and in a + * different segment. This occurs when the VM reenters itself (via Invoke or + * Execute). In full generality, a single context may contain a forest of trees + * of stack frames. With respect to this forest, a segment contains a linear + * path along a single tree, not necessarily to the root. + * + * The frames of a non-empty segment must all be in the same context and thus + * each non-empty segment is referred to as being "in" a context. Segments in a + * context have an additional state of being either "active" or "suspended". A + * suspended segment |ss| has a "suspended frame" which is snapshot of |cx->regs| + * when the segment was suspended and serves as the current frame of |ss|. + * There is at most one active segment in a given context. Segments in a + * context execute LIFO and are maintained in a stack. The top of this stack + * is the context's "current segment". If a context |cx| has an active segment + * |ss|, then: + * 1. |ss| is |cx|'s current segment, + * 2. |cx->regs != NULL|, and + * 3. |ss|'s current frame is |cx->regs->fp|. + * Moreover, |cx->regs != NULL| iff |cx| has an active segment. + * + * An empty segment is not associated with any context. Empty segments are + * created when there is not an active segment for a context at the top of the + * stack and claim space for the arguments of an Invoke before the Invoke's + * stack frame is pushed. During the intervals when the arguments have been + * pushed, but not the stack frame, the segment cannot be pushed onto the + * context, since that would require some hack to deal with cx->fp not being + * the current frame of cx->currentSegment. + * + * Finally, (to support JS_SaveFrameChain/JS_RestoreFrameChain) a suspended + * segment may or may not be "saved". Normally, when the active segment is + * popped, the previous segment (which is necessarily suspended) becomes + * active. If the previous segment was saved, however, then it stays suspended + * until it is made active by a call to JS_RestoreFrameChain. This is why a + * context may have a current segment, but not an active segment. + */ +class StackSegment +{ + /* The context to which this segment belongs. */ + JSContext *cx; + + /* Link for JSContext segment stack mentioned in big comment above. */ + StackSegment *previousInContext; + + /* Link for StackSpace segment stack mentioned in StackSpace comment. */ + StackSegment *previousInMemory; + + /* The first frame executed in this segment. null iff cx is null */ + JSStackFrame *initialFrame; + + /* If this segment is suspended, |cx->regs| when it was suspended. */ + JSFrameRegs *suspendedRegs; + + /* The varobj on entry to initialFrame. */ + JSObject *initialVarObj; + + /* Whether this segment was suspended by JS_SaveFrameChain. */ + bool saved; + + /* Align at 8 bytes on all platforms. */ +#if JS_BITS_PER_WORD == 32 + void *padding; +#endif + + /* + * To make isActive a single null-ness check, this non-null constant is + * assigned to suspendedRegs when !inContext. + */ +#define NON_NULL_SUSPENDED_REGS ((JSFrameRegs *)0x1) + + public: + StackSegment() + : cx(NULL), previousInContext(NULL), previousInMemory(NULL), + initialFrame(NULL), suspendedRegs(NON_NULL_SUSPENDED_REGS), + initialVarObj(NULL), saved(false) + { + JS_ASSERT(!inContext()); + } + + /* Safe casts guaranteed by the contiguous-stack layout. */ + + Value *valueRangeBegin() const { + return (Value *)(this + 1); + } + + /* + * As described in the comment at the beginning of the class, a segment + * is in one of three states: + * + * !inContext: the segment has been created to root arguments for a + * future call to Invoke. + * isActive: the segment describes a set of stack frames in a context, + * where the top frame currently executing. + * isSuspended: like isActive, but the top frame has been suspended. + */ + + bool inContext() const { + JS_ASSERT(!!cx == !!initialFrame); + JS_ASSERT_IF(!cx, suspendedRegs == NON_NULL_SUSPENDED_REGS && !saved); + return cx; + } + + bool isActive() const { + JS_ASSERT_IF(!suspendedRegs, cx && !saved); + JS_ASSERT_IF(!cx, suspendedRegs == NON_NULL_SUSPENDED_REGS); + return !suspendedRegs; + } + + bool isSuspended() const { + JS_ASSERT_IF(!cx || !suspendedRegs, !saved); + JS_ASSERT_IF(!cx, suspendedRegs == NON_NULL_SUSPENDED_REGS); + return cx && suspendedRegs; + } + + /* Substate of suspended, queryable in any state. */ + + bool isSaved() const { + JS_ASSERT_IF(saved, isSuspended()); + return saved; + } + + /* Transitioning between inContext <--> isActive */ + + void joinContext(JSContext *cx, JSStackFrame *f) { + JS_ASSERT(!inContext()); + this->cx = cx; + initialFrame = f; + suspendedRegs = NULL; + JS_ASSERT(isActive()); + } + + void leaveContext() { + JS_ASSERT(isActive()); + this->cx = NULL; + initialFrame = NULL; + suspendedRegs = NON_NULL_SUSPENDED_REGS; + JS_ASSERT(!inContext()); + } + + JSContext *maybeContext() const { + return cx; + } + +#undef NON_NULL_SUSPENDED_REGS + + /* Transitioning between isActive <--> isSuspended */ + + void suspend(JSFrameRegs *regs) { + JS_ASSERT(isActive()); + JS_ASSERT(regs && regs->fp && contains(regs->fp)); + suspendedRegs = regs; + JS_ASSERT(isSuspended()); + } + + void resume() { + JS_ASSERT(isSuspended()); + suspendedRegs = NULL; + JS_ASSERT(isActive()); + } + + /* When isSuspended, transitioning isSaved <--> !isSaved */ + + void save(JSFrameRegs *regs) { + JS_ASSERT(!isSuspended()); + suspend(regs); + saved = true; + JS_ASSERT(isSaved()); + } + + void restore() { + JS_ASSERT(isSaved()); + saved = false; + resume(); + JS_ASSERT(!isSuspended()); + } + + /* Data available when inContext */ + + JSStackFrame *getInitialFrame() const { + JS_ASSERT(inContext()); + return initialFrame; + } + + inline JSFrameRegs *getCurrentRegs() const; + inline JSStackFrame *getCurrentFrame() const; + + /* Data available when isSuspended. */ + + JSFrameRegs *getSuspendedRegs() const { + JS_ASSERT(isSuspended()); + return suspendedRegs; + } + + JSStackFrame *getSuspendedFrame() const { + return suspendedRegs->fp; + } + + /* JSContext / js::StackSpace bookkeeping. */ + + void setPreviousInContext(StackSegment *seg) { + previousInContext = seg; + } + + StackSegment *getPreviousInContext() const { + return previousInContext; + } + + void setPreviousInMemory(StackSegment *seg) { + previousInMemory = seg; + } + + StackSegment *getPreviousInMemory() const { + return previousInMemory; + } + + void setInitialVarObj(JSObject *obj) { + JS_ASSERT(inContext()); + initialVarObj = obj; + } + + bool hasInitialVarObj() { + JS_ASSERT(inContext()); + return initialVarObj != NULL; + } + + JSObject &getInitialVarObj() const { + JS_ASSERT(inContext() && initialVarObj); + return *initialVarObj; + } + +#ifdef DEBUG + JS_REQUIRES_STACK bool contains(const JSStackFrame *fp) const; +#endif +}; + +static const size_t VALUES_PER_STACK_SEGMENT = sizeof(StackSegment) / sizeof(Value); +JS_STATIC_ASSERT(sizeof(StackSegment) % sizeof(Value) == 0); + +/* See StackSpace::pushInvokeArgs. */ +class InvokeArgsGuard : public CallArgs +{ + friend class StackSpace; + JSContext *cx; /* null implies nothing pushed */ + StackSegment *seg; + Value *prevInvokeArgEnd; +#ifdef DEBUG + StackSegment *prevInvokeSegment; + JSStackFrame *prevInvokeFrame; +#endif + public: + InvokeArgsGuard() : cx(NULL), seg(NULL) {} + ~InvokeArgsGuard(); + bool pushed() const { return cx != NULL; } +}; + +/* + * This type can be used to call Invoke when the arguments have already been + * pushed onto the stack as part of normal execution. + */ +struct InvokeArgsAlreadyOnTheStack : CallArgs +{ + InvokeArgsAlreadyOnTheStack(Value *vp, uintN argc) : CallArgs(vp + 2, argc) {} +}; + +/* See StackSpace::pushInvokeFrame. */ +class InvokeFrameGuard +{ + friend class StackSpace; + JSContext *cx_; /* null implies nothing pushed */ + JSFrameRegs regs_; + JSFrameRegs *prevRegs_; + public: + InvokeFrameGuard() : cx_(NULL) {} + ~InvokeFrameGuard() { if (pushed()) pop(); } + bool pushed() const { return cx_ != NULL; } + JSContext *pushedFrameContext() const { JS_ASSERT(pushed()); return cx_; } + void pop(); + JSStackFrame *fp() const { return regs_.fp; } +}; + +/* Reusable base; not for direct use. */ +class FrameGuard +{ + friend class StackSpace; + JSContext *cx_; /* null implies nothing pushed */ + StackSegment *seg_; + Value *vp_; + JSStackFrame *fp_; + public: + FrameGuard() : cx_(NULL), vp_(NULL), fp_(NULL) {} + JS_REQUIRES_STACK ~FrameGuard(); + bool pushed() const { return cx_ != NULL; } + StackSegment *segment() const { return seg_; } + Value *vp() const { return vp_; } + JSStackFrame *fp() const { return fp_; } +}; + +/* See StackSpace::pushExecuteFrame. */ +class ExecuteFrameGuard : public FrameGuard +{ + friend class StackSpace; + JSFrameRegs regs_; +}; + +/* See StackSpace::pushDummyFrame. */ +class DummyFrameGuard : public FrameGuard +{ + friend class StackSpace; + JSFrameRegs regs_; +}; + +/* See StackSpace::pushGeneratorFrame. */ +class GeneratorFrameGuard : public FrameGuard +{}; + +/* + * Stack layout + * + * Each JSThreadData has one associated StackSpace object which allocates all + * segments for the thread. StackSpace performs all such allocations in a + * single, fixed-size buffer using a specific layout scheme that allows some + * associations between segments, frames, and slots to be implicit, rather + * than explicitly stored as pointers. To maintain useful invariants, stack + * space is not given out arbitrarily, but rather allocated/deallocated for + * specific purposes. The use cases currently supported are: calling a function + * with arguments (e.g. Invoke), executing a script (e.g. Execute), inline + * interpreter calls, and pushing "dummy" frames for bookkeeping purposes. See + * associated member functions below. + * + * First, we consider the layout of individual segments. (See the + * js::StackSegment comment for terminology.) A non-empty segment (i.e., a + * segment in a context) has the following layout: + * + * initial frame current frame ------. if regs, + * .------------. | | regs->sp + * | V V V + * |segment| slots |frame| slots |frame| slots |frame| slots | + * | ^ | ^ | + * ? <----------' `----------' `----------' + * prev prev prev + * + * Moreover, the bytes in the following ranges form a contiguous array of + * Values that are marked during GC: + * 1. between a segment and its first frame + * 2. between two adjacent frames in a segment + * 3. between a segment's current frame and (if fp->regs) fp->regs->sp + * Thus, the VM must ensure that all such Values are safe to be marked. + * + * An empty segment is followed by arguments that are rooted by the + * StackSpace::invokeArgEnd pointer: + * + * invokeArgEnd + * | + * V + * |segment| slots | + * + * Above the level of segments, a StackSpace is simply a contiguous sequence + * of segments kept in a linked list: + * + * base currentSegment firstUnused end + * | | | | + * V V V V + * |segment| --- |segment| --- |segment| ------- | | + * | ^ | ^ | + * 0 <---' `-----------' `-----------' + * previous previous previous + * + * Both js::StackSpace and JSContext maintain a stack of segments, the top of + * which is the "current segment" for that thread or context, respectively. + * Since different contexts can arbitrarily interleave execution in a single + * thread, these stacks are different enough that a segment needs both + * "previousInMemory" and "previousInContext". + * + * For example, in a single thread, a function in segment S1 in a context CX1 + * may call out into C++ code that reenters the VM in a context CX2, which + * creates a new segment S2 in CX2, and CX1 may or may not equal CX2. + * + * Note that there is some structure to this interleaving of segments: + * 1. the inclusion from segments in a context to segments in a thread + * preserves order (in terms of previousInContext and previousInMemory, + * respectively). + * 2. the mapping from stack frames to their containing segment preserves + * order (in terms of prev and previousInContext, respectively). + */ +class StackSpace +{ + Value *base; +#ifdef XP_WIN + mutable Value *commitEnd; +#endif + Value *end; + StackSegment *currentSegment; +#ifdef DEBUG + /* + * Keep track of which segment/frame bumped invokeArgEnd so that + * firstUnused() can assert that, when invokeArgEnd is used as the top of + * the stack, it is being used appropriately. + */ + StackSegment *invokeSegment; + JSStackFrame *invokeFrame; +#endif + Value *invokeArgEnd; + + friend class InvokeArgsGuard; + friend class InvokeFrameGuard; + friend class FrameGuard; + + bool pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard *ag); + void popSegmentForInvoke(const InvokeArgsGuard &ag); + + bool pushInvokeFrameSlow(JSContext *cx, const InvokeArgsGuard &ag, + InvokeFrameGuard *fg); + void popInvokeFrameSlow(const CallArgs &args); + + bool getSegmentAndFrame(JSContext *cx, uintN vplen, uintN nslots, + FrameGuard *fg) const; + void pushSegmentAndFrame(JSContext *cx, JSFrameRegs *regs, FrameGuard *fg); + void popSegmentAndFrame(JSContext *cx); + + struct EnsureSpaceCheck { + inline bool operator()(const StackSpace &, JSContext *, Value *, uintN); + }; + + struct LimitCheck { + JSStackFrame *base; + Value **limit; + LimitCheck(JSStackFrame *base, Value **limit) : base(base), limit(limit) {} + inline bool operator()(const StackSpace &, JSContext *, Value *, uintN); + }; + + template + inline JSStackFrame *getCallFrame(JSContext *cx, Value *sp, uintN nactual, + JSFunction *fun, JSScript *script, + uint32 *pflags, Check check) const; + + inline void popInvokeArgs(const InvokeArgsGuard &args); + inline void popInvokeFrame(const InvokeFrameGuard &ag); + + inline Value *firstUnused() const; + + inline bool isCurrentAndActive(JSContext *cx) const; + friend class AllFramesIter; + StackSegment *getCurrentSegment() const { return currentSegment; } + +#ifdef XP_WIN + /* Commit more memory from the reserved stack space. */ + JS_FRIEND_API(bool) bumpCommit(Value *from, ptrdiff_t nvals) const; +#endif + + public: + static const size_t CAPACITY_VALS = 512 * 1024; + static const size_t CAPACITY_BYTES = CAPACITY_VALS * sizeof(Value); + static const size_t COMMIT_VALS = 16 * 1024; + static const size_t COMMIT_BYTES = COMMIT_VALS * sizeof(Value); + + /* + * SunSpider and v8bench have roughly an average of 9 slots per script. + * Our heuristic for a quick over-recursion check uses a generous slot + * count based on this estimate. We take this frame size and multiply it + * by the old recursion limit from the interpreter. + * + * Worst case, if an average size script (<=9 slots) over recurses, it'll + * effectively be the same as having increased the old inline call count + * to <= 5,000. + */ + static const size_t STACK_QUOTA = (VALUES_PER_STACK_FRAME + 18) * + JS_MAX_INLINE_CALL_COUNT; + + /* Kept as a member of JSThreadData; cannot use constructor/destructor. */ + bool init(); + void finish(); + +#ifdef DEBUG + template + bool contains(T *t) const { + char *v = (char *)t; + JS_ASSERT(size_t(-1) - uintptr_t(t) >= sizeof(T)); + return v >= (char *)base && v + sizeof(T) <= (char *)end; + } +#endif + + /* + * When we LeaveTree, we need to rebuild the stack, which requires stack + * allocation. There is no good way to handle an OOM for these allocations, + * so this function checks that they cannot occur using the size of the + * TraceNativeStorage as a conservative upper bound. + */ + inline bool ensureEnoughSpaceToEnterTrace(); + + /* +1 for slow native's stack frame. */ + static const ptrdiff_t MAX_TRACE_SPACE_VALS = + MAX_NATIVE_STACK_SLOTS + MAX_CALL_STACK_ENTRIES * VALUES_PER_STACK_FRAME + + (VALUES_PER_STACK_SEGMENT + VALUES_PER_STACK_FRAME /* synthesized slow native */); + + /* Mark all segments, frames, and slots on the stack. */ + JS_REQUIRES_STACK void mark(JSTracer *trc); + + /* + * For all five use cases below: + * - The boolean-valued functions call js_ReportOutOfScriptQuota on OOM. + * - The "get*Frame" functions do not change any global state, they just + * check OOM and return pointers to an uninitialized frame with the + * requested missing arguments/slots. Only once the "push*Frame" + * function has been called is global state updated. Thus, between + * "get*Frame" and "push*Frame", the frame and slots are unrooted. + * - The "push*Frame" functions will set fp->prev; the caller needn't. + * - Functions taking "*Guard" arguments will use the guard's destructor + * to pop the allocation. The caller must ensure the guard has the + * appropriate lifetime. + * - The get*Frame functions put the 'nmissing' slots contiguously after + * the arguments. + */ + + /* + * pushInvokeArgs allocates |argc + 2| rooted values that will be passed as + * the arguments to Invoke. A single allocation can be used for multiple + * Invoke calls. The InvokeArgumentsGuard passed to Invoke must come from + * an immediately-enclosing (stack-wise) call to pushInvokeArgs. + */ + bool pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard *ag); + + /* These functions are called inside Invoke, not Invoke clients. */ + bool getInvokeFrame(JSContext *cx, const CallArgs &args, JSFunction *fun, + JSScript *script, uint32 *flags, InvokeFrameGuard *fg) const; + + void pushInvokeFrame(JSContext *cx, const CallArgs &args, InvokeFrameGuard *fg); + + /* These functions are called inside Execute, not Execute clients. */ + bool getExecuteFrame(JSContext *cx, JSScript *script, ExecuteFrameGuard *fg) const; + void pushExecuteFrame(JSContext *cx, JSObject *initialVarObj, ExecuteFrameGuard *fg); + + /* + * Since RAII cannot be used for inline frames, callers must manually + * call pushInlineFrame/popInlineFrame. + */ + inline JSStackFrame *getInlineFrame(JSContext *cx, Value *sp, uintN nactual, + JSFunction *fun, JSScript *script, + uint32 *flags) const; + inline void pushInlineFrame(JSContext *cx, JSScript *script, JSStackFrame *fp, + JSFrameRegs *regs); + inline void popInlineFrame(JSContext *cx, JSStackFrame *prev, js::Value *newsp); + + /* These functions are called inside SendToGenerator. */ + bool getGeneratorFrame(JSContext *cx, uintN vplen, uintN nslots, + GeneratorFrameGuard *fg); + void pushGeneratorFrame(JSContext *cx, JSFrameRegs *regs, GeneratorFrameGuard *fg); + + /* Pushes a JSStackFrame::isDummyFrame. */ + bool pushDummyFrame(JSContext *cx, JSObject &scopeChain, DummyFrameGuard *fg); + + /* Check and bump the given stack limit. */ + inline JSStackFrame *getInlineFrameWithinLimit(JSContext *cx, Value *sp, uintN nactual, + JSFunction *fun, JSScript *script, uint32 *flags, + JSStackFrame *base, Value **limit) const; + + /* + * Compute a stack limit for entering method jit code which allows the + * method jit to check for end-of-stack and over-recursion with a single + * comparison. See STACK_QUOTA above. + */ + inline Value *getStackLimit(JSContext *cx); + + /* + * Try to bump the given 'limit' by bumping the commit limit. Return false + * if fully committed or if 'limit' exceeds 'base' + STACK_QUOTA. + */ + bool bumpCommitAndLimit(JSStackFrame *base, Value *from, uintN nvals, Value **limit) const; + + /* + * Allocate nvals on the top of the stack, report error on failure. + * N.B. the caller must ensure |from >= firstUnused()|. + */ + inline bool ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const; +}; + +JS_STATIC_ASSERT(StackSpace::CAPACITY_VALS % StackSpace::COMMIT_VALS == 0); + +/* + * While |cx->fp|'s pc/sp are available in |cx->regs|, to compute the saved + * value of pc/sp for any other frame, it is necessary to know about that + * frame's next-frame. This iterator maintains this information when walking + * a chain of stack frames starting at |cx->fp|. + * + * Usage: + * for (FrameRegsIter i(cx); !i.done(); ++i) + * ... i.fp() ... i.sp() ... i.pc() + */ +class FrameRegsIter +{ + JSContext *cx; + StackSegment *curseg; + JSStackFrame *curfp; + Value *cursp; + jsbytecode *curpc; + + void initSlow(); + void incSlow(JSStackFrame *fp, JSStackFrame *prev); + + public: + JS_REQUIRES_STACK inline FrameRegsIter(JSContext *cx); + + bool done() const { return curfp == NULL; } + inline FrameRegsIter &operator++(); + + JSStackFrame *fp() const { return curfp; } + Value *sp() const { return cursp; } + jsbytecode *pc() const { return curpc; } +}; + +/* + * Utility class for iteration over all active stack frames. + */ +class AllFramesIter +{ +public: + AllFramesIter(JSContext *cx); + + bool done() const { return curfp == NULL; } + AllFramesIter& operator++(); + + JSStackFrame *fp() const { return curfp; } + +private: + StackSegment *curcs; + JSStackFrame *curfp; +}; + +} /* namespace js */ + +#ifdef DEBUG +# define FUNCTION_KIND_METER_LIST(_) \ + _(allfun), _(heavy), _(nofreeupvar), _(onlyfreevar), \ + _(flat), _(badfunarg), \ + _(joinedsetmethod), _(joinedinitmethod), \ + _(joinedreplace), _(joinedsort), _(joinedmodulepat), \ + _(mreadbarrier), _(mwritebarrier), _(mwslotbarrier), \ + _(unjoined), _(indynamicscope) +# define identity(x) x + +struct JSFunctionMeter { + int32 FUNCTION_KIND_METER_LIST(identity); +}; + +# undef identity + +# define JS_FUNCTION_METER(cx,x) JS_RUNTIME_METER((cx)->runtime, functionMeter.x) +#else +# define JS_FUNCTION_METER(cx,x) ((void)0) +#endif + + +struct JSPendingProxyOperation { + JSPendingProxyOperation *next; + JSObject *object; +}; + +struct JSThreadData { +#ifdef JS_THREADSAFE + /* The request depth for this thread. */ + unsigned requestDepth; +#endif + +#ifdef JS_TRACER + /* + * During trace execution (or during trace recording or + * profiling), these fields point to the compartment doing the + * execution on this thread. At other times, they are NULL. If a + * thread tries to execute/record/profile one trace while another + * is still running, the initial one will abort. Therefore, we + * only need to track one at a time. + */ + JSCompartment *onTraceCompartment; + JSCompartment *recordingCompartment; + JSCompartment *profilingCompartment; + #endif + + /* + * If non-zero, we were been asked to call the operation callback as soon + * as possible. If the thread has an active request, this contributes + * towards rt->interruptCounter. + */ + volatile int32 interruptFlags; + + /* Keeper of the contiguous stack used by all contexts in this thread. */ + js::StackSpace stackSpace; + + /* + * Flag indicating that we are waiving any soft limits on the GC heap + * because we want allocations to be infallible (except when we hit OOM). + */ + bool waiveGCQuota; + + /* + * The GSN cache is per thread since even multi-cx-per-thread embeddings + * do not interleave js_GetSrcNote calls. + */ + JSGSNCache gsnCache; + + /* Property cache for faster call/get/set invocation. */ + js::PropertyCache propertyCache; + +#ifdef JS_TRACER + /* Maximum size of the tracer's code cache before we start flushing. */ + uint32 maxCodeCacheBytes; +#endif + + /* State used by dtoa.c. */ + DtoaState *dtoaState; + + /* Base address of the native stack for the current thread. */ + jsuword *nativeStackBase; + + /* List of currently pending operations on proxies. */ + JSPendingProxyOperation *pendingProxyOperation; + + js::ConservativeGCThreadData conservativeGC; + + bool init(); + void finish(); + void mark(JSTracer *trc); + void purge(JSContext *cx); + + /* This must be called with the GC lock held. */ + inline void triggerOperationCallback(JSRuntime *rt); +}; + +#ifdef JS_THREADSAFE + +/* + * Structure uniquely representing a thread. It holds thread-private data + * that can be accessed without a global lock. + */ +struct JSThread { + typedef js::HashMap, + js::SystemAllocPolicy> Map; + + /* Linked list of all contexts in use on this thread. */ + JSCList contextList; + + /* Opaque thread-id, from NSPR's PR_GetCurrentThread(). */ + void *id; + + /* Number of JS_SuspendRequest calls withot JS_ResumeRequest. */ + unsigned suspendCount; + +# ifdef DEBUG + unsigned checkRequestDepth; +# endif + + /* Factored out of JSThread for !JS_THREADSAFE embedding in JSRuntime. */ + JSThreadData data; +}; + +#define JS_THREAD_DATA(cx) (&(cx)->thread->data) + +extern JSThread * +js_CurrentThread(JSRuntime *rt); + +/* + * The function takes the GC lock and does not release in successful return. + * On error (out of memory) the function releases the lock but delegates + * the error reporting to the caller. + */ +extern JSBool +js_InitContextThread(JSContext *cx); + +/* + * On entrance the GC lock must be held and it will be held on exit. + */ +extern void +js_ClearContextThread(JSContext *cx); + +#endif /* JS_THREADSAFE */ + +typedef enum JSDestroyContextMode { + JSDCM_NO_GC, + JSDCM_MAYBE_GC, + JSDCM_FORCE_GC, + JSDCM_NEW_FAILED +} JSDestroyContextMode; + +typedef enum JSRuntimeState { + JSRTS_DOWN, + JSRTS_LAUNCHING, + JSRTS_UP, + JSRTS_LANDING +} JSRuntimeState; + +typedef struct JSPropertyTreeEntry { + JSDHashEntryHdr hdr; + js::Shape *child; +} JSPropertyTreeEntry; + +typedef void +(* JSActivityCallback)(void *arg, JSBool active); + +namespace js { + +typedef js::Vector WrapperVector; + +} + +struct JSRuntime { + /* Default compartment. */ + JSCompartment *atomsCompartment; +#ifdef JS_THREADSAFE + bool atomsCompartmentIsLocked; +#endif + + /* List of compartments (protected by the GC lock). */ + js::WrapperVector compartments; + + /* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */ + JSRuntimeState state; + + /* Context create/destroy callback. */ + JSContextCallback cxCallback; + + /* Compartment create/destroy callback. */ + JSCompartmentCallback compartmentCallback; + + /* + * Sets a callback that is run whenever the runtime goes idle - the + * last active request ceases - and begins activity - when it was + * idle and a request begins. Note: The callback is called under the + * GC lock. + */ + void setActivityCallback(JSActivityCallback cb, void *arg) { + activityCallback = cb; + activityCallbackArg = arg; + } + + JSActivityCallback activityCallback; + void *activityCallbackArg; + + /* + * Shape regenerated whenever a prototype implicated by an "add property" + * property cache fill and induced trace guard has a readonly property or a + * setter defined on it. This number proxies for the shapes of all objects + * along the prototype chain of all objects in the runtime on which such an + * add-property result has been cached/traced. + * + * See bug 492355 for more details. + * + * This comes early in JSRuntime to minimize the immediate format used by + * trace-JITted code that reads it. + */ + uint32 protoHazardShape; + + /* Garbage collector state, used by jsgc.c. */ + js::GCChunkSet gcChunkSet; + + js::RootedValueMap gcRootsHash; + js::GCLocks gcLocksHash; + jsrefcount gcKeepAtoms; + size_t gcBytes; + size_t gcTriggerBytes; + size_t gcLastBytes; + size_t gcMaxBytes; + size_t gcMaxMallocBytes; + size_t gcChunksWaitingToExpire; + uint32 gcEmptyArenaPoolLifespan; + uint32 gcNumber; + js::GCMarker *gcMarkingTracer; + uint32 gcTriggerFactor; + int64 gcJitReleaseTime; + JSGCMode gcMode; + volatile bool gcIsNeeded; + + /* + * Compartment that triggered GC. If more than one Compatment need GC, + * gcTriggerCompartment is reset to NULL and a global GC is performed. + */ + JSCompartment *gcTriggerCompartment; + + /* Compartment that is currently involved in per-compartment GC */ + JSCompartment *gcCurrentCompartment; + + /* + * We can pack these flags as only the GC thread writes to them. Atomic + * updates to packed bytes are not guaranteed, so stores issued by one + * thread may be lost due to unsynchronized read-modify-write cycles on + * other threads. + */ + bool gcPoke; + bool gcMarkAndSweep; + bool gcRunning; + bool gcRegenShapes; + +#ifdef JS_GC_ZEAL + jsrefcount gcZeal; +#endif + + JSGCCallback gcCallback; + + private: + /* + * Malloc counter to measure memory pressure for GC scheduling. It runs + * from gcMaxMallocBytes down to zero. + */ + volatile ptrdiff_t gcMallocBytes; + + public: + js::GCChunkAllocator *gcChunkAllocator; + + void setCustomGCChunkAllocator(js::GCChunkAllocator *allocator) { + JS_ASSERT(allocator); + JS_ASSERT(state == JSRTS_DOWN); + gcChunkAllocator = allocator; + } + + /* + * The trace operation and its data argument to trace embedding-specific + * GC roots. + */ + JSTraceDataOp gcExtraRootsTraceOp; + void *gcExtraRootsData; + + /* Well-known numbers held for use by this runtime's contexts. */ + js::Value NaNValue; + js::Value negativeInfinityValue; + js::Value positiveInfinityValue; + + JSFlatString *emptyString; + + /* List of active contexts sharing this runtime; protected by gcLock. */ + JSCList contextList; + + /* Per runtime debug hooks -- see jsprvtd.h and jsdbgapi.h. */ + JSDebugHooks globalDebugHooks; + + /* + * Right now, we only support runtime-wide debugging. + */ + JSBool debugMode; + +#ifdef JS_TRACER + /* True if any debug hooks not supported by the JIT are enabled. */ + bool debuggerInhibitsJIT() const { + return (globalDebugHooks.interruptHook || + globalDebugHooks.callHook); + } +#endif + + /* More debugging state, see jsdbgapi.c. */ + JSCList trapList; + JSCList watchPointList; + + /* Client opaque pointers */ + void *data; + +#ifdef JS_THREADSAFE + /* These combine to interlock the GC and new requests. */ + PRLock *gcLock; + PRCondVar *gcDone; + PRCondVar *requestDone; + uint32 requestCount; + JSThread *gcThread; + + js::GCHelperThread gcHelperThread; + + /* Lock and owning thread pointer for JS_LOCK_RUNTIME. */ + PRLock *rtLock; +#ifdef DEBUG + void * rtLockOwner; +#endif + + /* Used to synchronize down/up state change; protected by gcLock. */ + PRCondVar *stateChange; + + /* + * Lock serializing trapList and watchPointList accesses, and count of all + * mutations to trapList and watchPointList made by debugger threads. To + * keep the code simple, we define debuggerMutations for the thread-unsafe + * case too. + */ + PRLock *debuggerLock; + + JSThread::Map threads; +#endif /* JS_THREADSAFE */ + uint32 debuggerMutations; + + /* + * Security callbacks set on the runtime are used by each context unless + * an override is set on the context. + */ + JSSecurityCallbacks *securityCallbacks; + + /* Structured data callbacks are runtime-wide. */ + const JSStructuredCloneCallbacks *structuredCloneCallbacks; + + /* + * The propertyRemovals counter is incremented for every JSObject::clear, + * and for each JSObject::remove method call that frees a slot in the given + * object. See js_NativeGet and js_NativeSet in jsobj.cpp. + */ + int32 propertyRemovals; + + /* Script filename table. */ + struct JSHashTable *scriptFilenameTable; + JSCList scriptFilenamePrefixes; +#ifdef JS_THREADSAFE + PRLock *scriptFilenameTableLock; +#endif + + /* Number localization, used by jsnum.c */ + const char *thousandsSeparator; + const char *decimalSeparator; + const char *numGrouping; + + /* + * Weak references to lazily-created, well-known XML singletons. + * + * NB: Singleton objects must be carefully disconnected from the rest of + * the object graph usually associated with a JSContext's global object, + * including the set of standard class objects. See jsxml.c for details. + */ + JSObject *anynameObject; + JSObject *functionNamespaceObject; + +#ifdef JS_THREADSAFE + /* Number of threads with active requests and unhandled interrupts. */ + volatile int32 interruptCounter; +#else + JSThreadData threadData; + +#define JS_THREAD_DATA(cx) (&(cx)->runtime->threadData) +#endif + + /* + * Object shape (property cache structural type) identifier generator. + * + * Type 0 stands for the empty scope, and must not be regenerated due to + * uint32 wrap-around. Since js_GenerateShape (in jsinterp.cpp) uses + * atomic pre-increment, the initial value for the first typed non-empty + * scope will be 1. + * + * If this counter overflows into SHAPE_OVERFLOW_BIT (in jsinterp.h), the + * cache is disabled, to avoid aliasing two different types. It stays + * disabled until a triggered GC at some later moment compresses live + * types, minimizing rt->shapeGen in the process. + */ + volatile uint32 shapeGen; + + /* Literal table maintained by jsatom.c functions. */ + JSAtomState atomState; + + /* + * Various metering fields are defined at the end of JSRuntime. In this + * way there is no need to recompile all the code that refers to other + * fields of JSRuntime after enabling the corresponding metering macro. + */ +#ifdef JS_DUMP_ENUM_CACHE_STATS + int32 nativeEnumProbes; + int32 nativeEnumMisses; +# define ENUM_CACHE_METER(name) JS_ATOMIC_INCREMENT(&cx->runtime->name) +#else +# define ENUM_CACHE_METER(name) ((void) 0) +#endif + +#ifdef JS_DUMP_LOOP_STATS + /* Loop statistics, to trigger trace recording and compiling. */ + JSBasicStats loopStats; +#endif + +#ifdef DEBUG + /* Function invocation metering. */ + jsrefcount inlineCalls; + jsrefcount nativeCalls; + jsrefcount nonInlineCalls; + jsrefcount constructs; + + jsrefcount liveObjectProps; + jsrefcount liveObjectPropsPreSweep; + + /* + * NB: emptyShapes (in JSCompartment) is init'ed iff at least one + * of these envars is set: + * + * JS_PROPTREE_STATFILE statistics on the property tree forest + * JS_PROPTREE_DUMPFILE all paths in the property tree forest + */ + const char *propTreeStatFilename; + const char *propTreeDumpFilename; + + bool meterEmptyShapes() const { return propTreeStatFilename || propTreeDumpFilename; } + + /* String instrumentation. */ + jsrefcount liveStrings; + jsrefcount totalStrings; + jsrefcount liveDependentStrings; + jsrefcount totalDependentStrings; + jsrefcount badUndependStrings; + double lengthSum; + double lengthSquaredSum; + double strdepLengthSum; + double strdepLengthSquaredSum; + + /* Script instrumentation. */ + jsrefcount liveScripts; + jsrefcount totalScripts; + jsrefcount liveEmptyScripts; + jsrefcount totalEmptyScripts; + jsrefcount highWaterLiveScripts; +#endif /* DEBUG */ + +#ifdef JS_SCOPE_DEPTH_METER + /* + * Stats on runtime prototype chain lookups and scope chain depths, i.e., + * counts of objects traversed on a chain until the wanted id is found. + */ + JSBasicStats protoLookupDepthStats; + JSBasicStats scopeSearchDepthStats; + + /* + * Stats on compile-time host environment and lexical scope chain lengths + * (maximum depths). + */ + JSBasicStats hostenvScopeDepthStats; + JSBasicStats lexicalScopeDepthStats; +#endif + +#ifdef JS_GCMETER + js::gc::JSGCStats gcStats; + js::gc::JSGCArenaStats globalArenaStats[js::gc::FINALIZE_LIMIT]; +#endif + +#ifdef DEBUG + /* + * If functionMeterFilename, set from an envariable in JSRuntime's ctor, is + * null, the remaining members in this ifdef'ed group are not initialized. + */ + const char *functionMeterFilename; + JSFunctionMeter functionMeter; + char lastScriptFilename[1024]; + + typedef js::HashMap, + js::SystemAllocPolicy> FunctionCountMap; + + FunctionCountMap methodReadBarrierCountMap; + FunctionCountMap unjoinedFunctionCountMap; +#endif + + JSWrapObjectCallback wrapObjectCallback; + JSPreWrapCallback preWrapObjectCallback; + +#ifdef JS_METHODJIT + uint32 mjitMemoryUsed; +#endif + uint32 stringMemoryUsed; + + JSRuntime(); + ~JSRuntime(); + + bool init(uint32 maxbytes); + + void setGCTriggerFactor(uint32 factor); + void setGCLastBytes(size_t lastBytes); + + /* + * Call the system malloc while checking for GC memory pressure and + * reporting OOM error when cx is not null. + */ + void* malloc(size_t bytes, JSContext *cx = NULL) { + updateMallocCounter(bytes); + void *p = ::js_malloc(bytes); + return JS_LIKELY(!!p) ? p : onOutOfMemory(NULL, bytes, cx); + } + + /* + * Call the system calloc while checking for GC memory pressure and + * reporting OOM error when cx is not null. + */ + void* calloc(size_t bytes, JSContext *cx = NULL) { + updateMallocCounter(bytes); + void *p = ::js_calloc(bytes); + return JS_LIKELY(!!p) ? p : onOutOfMemory(reinterpret_cast(1), bytes, cx); + } + + void* realloc(void* p, size_t oldBytes, size_t newBytes, JSContext *cx = NULL) { + JS_ASSERT(oldBytes < newBytes); + updateMallocCounter(newBytes - oldBytes); + void *p2 = ::js_realloc(p, newBytes); + return JS_LIKELY(!!p2) ? p2 : onOutOfMemory(p, newBytes, cx); + } + + void* realloc(void* p, size_t bytes, JSContext *cx = NULL) { + /* + * For compatibility we do not account for realloc that increases + * previously allocated memory. + */ + if (!p) + updateMallocCounter(bytes); + void *p2 = ::js_realloc(p, bytes); + return JS_LIKELY(!!p2) ? p2 : onOutOfMemory(p, bytes, cx); + } + + void free(void* p) { ::js_free(p); } + + bool isGCMallocLimitReached() const { return gcMallocBytes <= 0; } + + void resetGCMallocBytes() { gcMallocBytes = ptrdiff_t(gcMaxMallocBytes); } + + void setGCMaxMallocBytes(size_t value) { + /* + * For compatibility treat any value that exceeds PTRDIFF_T_MAX to + * mean that value. + */ + gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1; + resetGCMallocBytes(); + } + + /* + * Call this after allocating memory held by GC things, to update memory + * pressure counters or report the OOM error if necessary. If oomError and + * cx is not null the function also reports OOM error. + * + * The function must be called outside the GC lock and in case of OOM error + * the caller must ensure that no deadlock possible during OOM reporting. + */ + void updateMallocCounter(size_t nbytes) { + /* We tolerate any thread races when updating gcMallocBytes. */ + ptrdiff_t newCount = gcMallocBytes - ptrdiff_t(nbytes); + gcMallocBytes = newCount; + if (JS_UNLIKELY(newCount <= 0)) + onTooMuchMalloc(); + } + + private: + /* + * The function must be called outside the GC lock. + */ + JS_FRIEND_API(void) onTooMuchMalloc(); + + /* + * This should be called after system malloc/realloc returns NULL to try + * to recove some memory or to report an error. Failures in malloc and + * calloc are signaled by p == null and p == reinterpret_cast(1). + * Other values of p mean a realloc failure. + * + * The function must be called outside the GC lock. + */ + JS_FRIEND_API(void *) onOutOfMemory(void *p, size_t nbytes, JSContext *cx); +}; + +/* Common macros to access thread-local caches in JSThread or JSRuntime. */ +#define JS_GSN_CACHE(cx) (JS_THREAD_DATA(cx)->gsnCache) +#define JS_PROPERTY_CACHE(cx) (JS_THREAD_DATA(cx)->propertyCache) + +#ifdef DEBUG +# define JS_RUNTIME_METER(rt, which) JS_ATOMIC_INCREMENT(&(rt)->which) +# define JS_RUNTIME_UNMETER(rt, which) JS_ATOMIC_DECREMENT(&(rt)->which) +#else +# define JS_RUNTIME_METER(rt, which) /* nothing */ +# define JS_RUNTIME_UNMETER(rt, which) /* nothing */ +#endif + +#define JS_KEEP_ATOMS(rt) JS_ATOMIC_INCREMENT(&(rt)->gcKeepAtoms); +#define JS_UNKEEP_ATOMS(rt) JS_ATOMIC_DECREMENT(&(rt)->gcKeepAtoms); + +#ifdef JS_ARGUMENT_FORMATTER_DEFINED +/* + * Linked list mapping format strings for JS_{Convert,Push}Arguments{,VA} to + * formatter functions. Elements are sorted in non-increasing format string + * length order. + */ +struct JSArgumentFormatMap { + const char *format; + size_t length; + JSArgumentFormatter formatter; + JSArgumentFormatMap *next; +}; +#endif + +/* + * Key and entry types for the JSContext.resolvingTable hash table, typedef'd + * here because all consumers need to see these declarations (and not just the + * typedef names, as would be the case for an opaque pointer-to-typedef'd-type + * declaration), along with cx->resolvingTable. + */ +typedef struct JSResolvingKey { + JSObject *obj; + jsid id; +} JSResolvingKey; + +typedef struct JSResolvingEntry { + JSDHashEntryHdr hdr; + JSResolvingKey key; + uint32 flags; +} JSResolvingEntry; + +#define JSRESFLAG_LOOKUP 0x1 /* resolving id from lookup */ +#define JSRESFLAG_WATCH 0x2 /* resolving id from watch */ +#define JSRESOLVE_INFER 0xffff /* infer bits from current bytecode */ + +extern const JSDebugHooks js_NullDebugHooks; /* defined in jsdbgapi.cpp */ + +namespace js { + +class AutoGCRooter; + +static inline bool +OptionsHasXML(uint32 options) +{ + return !!(options & JSOPTION_XML); +} + +static inline bool +OptionsHasAnonFunFix(uint32 options) +{ + return !!(options & JSOPTION_ANONFUNFIX); +} + +static inline bool +OptionsSameVersionFlags(uint32 self, uint32 other) +{ + static const uint32 mask = JSOPTION_XML | JSOPTION_ANONFUNFIX; + return !((self & mask) ^ (other & mask)); +} + +/* + * Flags accompany script version data so that a) dynamically created scripts + * can inherit their caller's compile-time properties and b) scripts can be + * appropriately compared in the eval cache across global option changes. An + * example of the latter is enabling the top-level-anonymous-function-is-error + * option: subsequent evals of the same, previously-valid script text may have + * become invalid. + */ +namespace VersionFlags { +static const uintN MASK = 0x0FFF; /* see JSVersion in jspubtd.h */ +static const uintN HAS_XML = 0x1000; /* flag induced by XML option */ +static const uintN ANONFUNFIX = 0x2000; /* see jsapi.h comment on JSOPTION_ANONFUNFIX */ +static const uintN FULL_MASK = 0x3FFF; +} + +static inline JSVersion +VersionNumber(JSVersion version) +{ + return JSVersion(uint32(version) & VersionFlags::MASK); +} + +static inline bool +VersionHasXML(JSVersion version) +{ + return !!(version & VersionFlags::HAS_XML); +} + +/* @warning This is a distinct condition from having the XML flag set. */ +static inline bool +VersionShouldParseXML(JSVersion version) +{ + return VersionHasXML(version) || VersionNumber(version) >= JSVERSION_1_6; +} + +static inline bool +VersionHasAnonFunFix(JSVersion version) +{ + return !!(version & VersionFlags::ANONFUNFIX); +} + +static inline void +VersionSetXML(JSVersion *version, bool enable) +{ + if (enable) + *version = JSVersion(uint32(*version) | VersionFlags::HAS_XML); + else + *version = JSVersion(uint32(*version) & ~VersionFlags::HAS_XML); +} + +static inline void +VersionSetAnonFunFix(JSVersion *version, bool enable) +{ + if (enable) + *version = JSVersion(uint32(*version) | VersionFlags::ANONFUNFIX); + else + *version = JSVersion(uint32(*version) & ~VersionFlags::ANONFUNFIX); +} + +static inline JSVersion +VersionExtractFlags(JSVersion version) +{ + return JSVersion(uint32(version) & ~VersionFlags::MASK); +} + +static inline void +VersionCopyFlags(JSVersion *version, JSVersion from) +{ + *version = JSVersion(VersionNumber(*version) | VersionExtractFlags(from)); +} + +static inline bool +VersionHasFlags(JSVersion version) +{ + return !!VersionExtractFlags(version); +} + +static inline uintN +VersionFlagsToOptions(JSVersion version) +{ + uintN copts = (VersionHasXML(version) ? JSOPTION_XML : 0) | + (VersionHasAnonFunFix(version) ? JSOPTION_ANONFUNFIX : 0); + JS_ASSERT((copts & JSCOMPILEOPTION_MASK) == copts); + return copts; +} + +static inline JSVersion +OptionFlagsToVersion(uintN options, JSVersion version) +{ + VersionSetXML(&version, OptionsHasXML(options)); + VersionSetAnonFunFix(&version, OptionsHasAnonFunFix(options)); + return version; +} + +static inline bool +VersionIsKnown(JSVersion version) +{ + return VersionNumber(version) != JSVERSION_UNKNOWN; +} + +typedef js::HashSet, + js::SystemAllocPolicy> BusyArraysMap; + +} /* namespace js */ + +struct JSContext +{ + explicit JSContext(JSRuntime *rt); + + /* JSRuntime contextList linkage. */ + JSCList link; + + private: + /* See JSContext::findVersion. */ + JSVersion defaultVersion; /* script compilation version */ + JSVersion versionOverride; /* supercedes defaultVersion when valid */ + bool hasVersionOverride; + + /* Exception state -- the exception member is a GC root by definition. */ + JSBool throwing; /* is there a pending exception? */ + js::Value exception; /* most-recently-thrown exception */ + + /* Per-context run options. */ + uintN runOptions; /* see jsapi.h for JSOPTION_* */ + + public: + /* Locale specific callbacks for string conversion. */ + JSLocaleCallbacks *localeCallbacks; + + /* + * cx->resolvingTable is non-null and non-empty if we are initializing + * standard classes lazily, or if we are otherwise recursing indirectly + * from js_LookupProperty through a Class.resolve hook. It is used to + * limit runaway recursion (see jsapi.c and jsobj.c). + */ + JSDHashTable *resolvingTable; + + /* + * True if generating an error, to prevent runaway recursion. + * NB: generatingError packs with throwing below. + */ + JSPackedBool generatingError; + + /* Limit pointer for checking native stack consumption during recursion. */ + jsuword stackLimit; + + /* Quota on the size of arenas used to compile and execute scripts. */ + size_t scriptStackQuota; + + /* Data shared by threads in an address space. */ + JSRuntime *const runtime; + + /* GC heap compartment. */ + JSCompartment *compartment; + + /* Currently executing frame and regs, set by stack operations. */ + JS_REQUIRES_STACK + JSFrameRegs *regs; + + /* Current frame accessors. */ + + JSStackFrame* fp() { + JS_ASSERT(regs && regs->fp); + return regs->fp; + } + + JSStackFrame* maybefp() { + JS_ASSERT_IF(regs, regs->fp); + return regs ? regs->fp : NULL; + } + + bool hasfp() { + JS_ASSERT_IF(regs, regs->fp); + return !!regs; + } + + public: + friend class js::StackSpace; + friend bool js::Interpret(JSContext *, JSStackFrame *, uintN, JSInterpMode); + + void resetCompartment(); + void wrapPendingException(); + + /* For grep-ability, changes to 'regs' should call this function. */ + void setCurrentRegs(JSFrameRegs *regs) { + JS_ASSERT_IF(regs, regs->fp); + this->regs = regs; + } + + /* Temporary arena pool used while compiling and decompiling. */ + JSArenaPool tempPool; + + /* Temporary arena pool used while evaluate regular expressions. */ + JSArenaPool regExpPool; + + /* Top-level object and pointer to top stack frame's scope chain. */ + JSObject *globalObject; + + /* State for object and array toSource conversion. */ + JSSharpObjectMap sharpObjectMap; + js::BusyArraysMap busyArrays; + + /* Argument formatter support for JS_{Convert,Push}Arguments{,VA}. */ + JSArgumentFormatMap *argumentFormatMap; + + /* Last message string and log file for debugging. */ + char *lastMessage; +#ifdef DEBUG + void *logfp; + jsbytecode *logPrevPc; +#endif + + /* Per-context optional error reporter. */ + JSErrorReporter errorReporter; + + /* Branch callback. */ + JSOperationCallback operationCallback; + + /* Interpreter activation count. */ + uintN interpLevel; + + /* Client opaque pointers. */ + void *data; + void *data2; + + private: + /* Linked list of segments. See StackSegment. */ + js::StackSegment *currentSegment; + + public: + void assertSegmentsInSync() const { +#ifdef DEBUG + if (regs) { + JS_ASSERT(currentSegment->isActive()); + if (js::StackSegment *prev = currentSegment->getPreviousInContext()) + JS_ASSERT(!prev->isActive()); + } else { + JS_ASSERT_IF(currentSegment, !currentSegment->isActive()); + } +#endif + } + + /* Return whether this context has an active segment. */ + bool hasActiveSegment() const { + assertSegmentsInSync(); + return !!regs; + } + + /* Assuming there is an active segment, return it. */ + js::StackSegment *activeSegment() const { + JS_ASSERT(hasActiveSegment()); + return currentSegment; + } + + /* Return the current segment, which may or may not be active. */ + js::StackSegment *getCurrentSegment() const { + assertSegmentsInSync(); + return currentSegment; + } + + inline js::RegExpStatics *regExpStatics(); + + /* Add the given segment to the list as the new active segment. */ + void pushSegmentAndFrame(js::StackSegment *newseg, JSFrameRegs ®s); + + /* Remove the active segment and make the next segment active. */ + void popSegmentAndFrame(); + + /* Mark the top segment as suspended, without pushing a new one. */ + void saveActiveSegment(); + + /* Undoes calls to suspendActiveSegment. */ + void restoreSegment(); + + /* Get the frame whose prev() is fp, which may be in any segment. */ + inline JSStackFrame *computeNextFrame(JSStackFrame *fp); + + /* + * Perform a linear search of all frames in all segments in the given context + * for the given frame, returning the segment, if found, and null otherwise. + */ + js::StackSegment *containingSegment(const JSStackFrame *target); + + /* Search the call stack for the nearest frame with static level targetLevel. */ + JSStackFrame *findFrameAtLevel(uintN targetLevel) const { + JSStackFrame *fp = regs->fp; + while (true) { + JS_ASSERT(fp && fp->isScriptFrame()); + if (fp->script()->staticLevel == targetLevel) + break; + fp = fp->prev(); + } + return fp; + } + + public: + /* + * The default script compilation version can be set iff there is no code running. + * This typically occurs via the JSAPI right after a context is constructed. + */ + bool canSetDefaultVersion() const { + return !regs && !hasVersionOverride; + } + + /* Force a version for future script compilation. */ + void overrideVersion(JSVersion newVersion) { + JS_ASSERT(!canSetDefaultVersion()); + versionOverride = newVersion; + hasVersionOverride = true; + } + + /* Set the default script compilation version. */ + void setDefaultVersion(JSVersion version) { + defaultVersion = version; + } + + void clearVersionOverride() { hasVersionOverride = false; } + JSVersion getDefaultVersion() const { return defaultVersion; } + bool isVersionOverridden() const { return hasVersionOverride; } + + JSVersion getVersionOverride() const { + JS_ASSERT(isVersionOverridden()); + return versionOverride; + } + + /* + * Set the default version if possible; otherwise, force the version. + * Return whether an override occurred. + */ + bool maybeOverrideVersion(JSVersion newVersion) { + if (canSetDefaultVersion()) { + setDefaultVersion(newVersion); + return false; + } + overrideVersion(newVersion); + return true; + } + + private: + /* + * If there is no code currently executing, turn the override version into + * the default version. + * + * NB: the only time the version is potentially capable of migrating is + * on return from the Execute or ExternalInvoke paths as they call through + * JSContext::popSegmentAndFrame. + */ + void maybeMigrateVersionOverride() { + if (JS_LIKELY(!isVersionOverridden() || currentSegment)) + return; + defaultVersion = versionOverride; + clearVersionOverride(); + } + + public: + /* + * Return: + * - The override version, if there is an override version. + * - The newest scripted frame's version, if there is such a frame. + * - The default verion. + * + * Note: if this ever shows up in a profile, just add caching! + */ + JSVersion findVersion() const { + if (hasVersionOverride) + return versionOverride; + + if (regs) { + /* There may be a scripted function somewhere on the stack! */ + JSStackFrame *fp = regs->fp; + while (fp && !fp->isScriptFrame()) + fp = fp->prev(); + if (fp) + return fp->script()->getVersion(); + } + + return defaultVersion; + } + + void setRunOptions(uintN ropts) { + JS_ASSERT((ropts & JSRUNOPTION_MASK) == ropts); + runOptions = ropts; + } + + /* Note: may override the version. */ + void setCompileOptions(uintN newcopts) { + JS_ASSERT((newcopts & JSCOMPILEOPTION_MASK) == newcopts); + if (JS_LIKELY(getCompileOptions() == newcopts)) + return; + JSVersion version = findVersion(); + JSVersion newVersion = js::OptionFlagsToVersion(newcopts, version); + maybeOverrideVersion(newVersion); + } + + uintN getRunOptions() const { return runOptions; } + uintN getCompileOptions() const { return js::VersionFlagsToOptions(findVersion()); } + uintN allOptions() const { return getRunOptions() | getCompileOptions(); } + + bool hasRunOption(uintN ropt) const { + JS_ASSERT((ropt & JSRUNOPTION_MASK) == ropt); + return !!(runOptions & ropt); + } + + bool hasStrictOption() const { return hasRunOption(JSOPTION_STRICT); } + bool hasWErrorOption() const { return hasRunOption(JSOPTION_WERROR); } + bool hasAtLineOption() const { return hasRunOption(JSOPTION_ATLINE); } + +#ifdef JS_THREADSAFE + JSThread *thread; + unsigned outstandingRequests;/* number of JS_BeginRequest calls + without the corresponding + JS_EndRequest. */ + JSCList threadLinks; /* JSThread contextList linkage */ + +#define CX_FROM_THREAD_LINKS(tl) \ + ((JSContext *)((char *)(tl) - offsetof(JSContext, threadLinks))) +#endif + + /* Stack of thread-stack-allocated GC roots. */ + js::AutoGCRooter *autoGCRooters; + + /* Debug hooks associated with the current context. */ + const JSDebugHooks *debugHooks; + + /* Security callbacks that override any defined on the runtime. */ + JSSecurityCallbacks *securityCallbacks; + + /* Stored here to avoid passing it around as a parameter. */ + uintN resolveFlags; + + /* Random number generator state, used by jsmath.cpp. */ + int64 rngSeed; + + /* Location to stash the iteration value between JSOP_MOREITER and JSOP_FOR*. */ + js::Value iterValue; + +#ifdef JS_TRACER + /* + * True if traces may be executed. Invariant: The value of traceJitenabled + * is always equal to the expression in updateJITEnabled below. + * + * This flag and the fields accessed by updateJITEnabled are written only + * in runtime->gcLock, to avoid race conditions that would leave the wrong + * value in traceJitEnabled. (But the interpreter reads this without + * locking. That can race against another thread setting debug hooks, but + * we always read cx->debugHooks without locking anyway.) + */ + bool traceJitEnabled; +#endif + +#ifdef JS_METHODJIT + bool methodJitEnabled; + bool profilingEnabled; +#endif + + /* Caller must be holding runtime->gcLock. */ + void updateJITEnabled(); + +#ifdef MOZ_TRACE_JSCALLS + /* Function entry/exit debugging callback. */ + JSFunctionCallback functionCallback; + + void doFunctionCallback(const JSFunction *fun, + const JSScript *scr, + int entering) const + { + if (functionCallback) + functionCallback(fun, scr, this, entering); + } +#endif + + DSTOffsetCache dstOffsetCache; + + /* List of currently active non-escaping enumerators (for-in). */ + JSObject *enumerators; + + private: + /* + * To go from a live generator frame (on the stack) to its generator object + * (see comment js_FloatingFrameIfGenerator), we maintain a stack of active + * generators, pushing and popping when entering and leaving generator + * frames, respectively. + */ + js::Vector genStack; + + public: +#ifdef JS_METHODJIT + inline js::mjit::JaegerCompartment *jaegerCompartment(); +#endif + + /* Return the generator object for the given generator frame. */ + JSGenerator *generatorFor(JSStackFrame *fp) const; + + /* Early OOM-check. */ + inline bool ensureGeneratorStackSpace(); + + bool enterGenerator(JSGenerator *gen) { + return genStack.append(gen); + } + + void leaveGenerator(JSGenerator *gen) { + JS_ASSERT(genStack.back() == gen); + genStack.popBack(); + } + +#ifdef JS_THREADSAFE + /* + * When non-null JSContext::free delegates the job to the background + * thread. + */ + js::GCHelperThread *gcBackgroundFree; +#endif + + inline void* malloc(size_t bytes) { + return runtime->malloc(bytes, this); + } + + inline void* mallocNoReport(size_t bytes) { + JS_ASSERT(bytes != 0); + return runtime->malloc(bytes, NULL); + } + + inline void* calloc(size_t bytes) { + JS_ASSERT(bytes != 0); + return runtime->calloc(bytes, this); + } + + inline void* realloc(void* p, size_t bytes) { + return runtime->realloc(p, bytes, this); + } + + inline void* realloc(void* p, size_t oldBytes, size_t newBytes) { + return runtime->realloc(p, oldBytes, newBytes, this); + } + + inline void free(void* p) { +#ifdef JS_THREADSAFE + if (gcBackgroundFree) { + gcBackgroundFree->freeLater(p); + return; + } +#endif + runtime->free(p); + } + + /* + * In the common case that we'd like to allocate the memory for an object + * with cx->malloc/free, we cannot use overloaded C++ operators (no + * placement delete). Factor the common workaround into one place. + */ +#define CREATE_BODY(parms) \ + void *memory = this->malloc(sizeof(T)); \ + if (!memory) \ + return NULL; \ + return new(memory) T parms; + + template + JS_ALWAYS_INLINE T *create() { + CREATE_BODY(()) + } + + template + JS_ALWAYS_INLINE T *create(const P1 &p1) { + CREATE_BODY((p1)) + } + + template + JS_ALWAYS_INLINE T *create(const P1 &p1, const P2 &p2) { + CREATE_BODY((p1, p2)) + } + + template + JS_ALWAYS_INLINE T *create(const P1 &p1, const P2 &p2, const P3 &p3) { + CREATE_BODY((p1, p2, p3)) + } +#undef CREATE_BODY + + template + JS_ALWAYS_INLINE void destroy(T *p) { + p->~T(); + this->free(p); + } + + void purge(); + + js::StackSpace &stack() const { + return JS_THREAD_DATA(this)->stackSpace; + } + +#ifdef DEBUG + void assertValidStackDepth(uintN depth) { + JS_ASSERT(0 <= regs->sp - regs->fp->base()); + JS_ASSERT(depth <= uintptr_t(regs->sp - regs->fp->base())); + } +#else + void assertValidStackDepth(uintN /*depth*/) {} +#endif + + bool isExceptionPending() { + return throwing; + } + + js::Value getPendingException() { + JS_ASSERT(throwing); + return exception; + } + + void setPendingException(js::Value v); + + void clearPendingException() { + this->throwing = false; + this->exception.setUndefined(); + } + + private: + /* + * The allocation code calls the function to indicate either OOM failure + * when p is null or that a memory pressure counter has reached some + * threshold when p is not null. The function takes the pointer and not + * a boolean flag to minimize the amount of code in its inlined callers. + */ + JS_FRIEND_API(void) checkMallocGCPressure(void *p); +}; /* struct JSContext */ + +#ifdef JS_THREADSAFE +# define JS_THREAD_ID(cx) ((cx)->thread ? (cx)->thread->id : 0) +#endif + +#if defined JS_THREADSAFE && defined DEBUG + +namespace js { + +class AutoCheckRequestDepth { + JSContext *cx; + public: + AutoCheckRequestDepth(JSContext *cx) : cx(cx) { cx->thread->checkRequestDepth++; } + + ~AutoCheckRequestDepth() { + JS_ASSERT(cx->thread->checkRequestDepth != 0); + cx->thread->checkRequestDepth--; + } +}; + +} + +# define CHECK_REQUEST(cx) \ + JS_ASSERT((cx)->thread); \ + JS_ASSERT((cx)->thread->data.requestDepth || (cx)->thread == (cx)->runtime->gcThread); \ + AutoCheckRequestDepth _autoCheckRequestDepth(cx); + +#else +# define CHECK_REQUEST(cx) ((void) 0) +# define CHECK_REQUEST_THREAD(cx) ((void) 0) +#endif + +static inline uintN +FramePCOffset(JSContext *cx, JSStackFrame* fp) +{ + jsbytecode *pc = fp->hasImacropc() ? fp->imacropc() : fp->pc(cx); + return uintN(pc - fp->script()->code); +} + +static inline JSAtom ** +FrameAtomBase(JSContext *cx, JSStackFrame *fp) +{ + return fp->hasImacropc() + ? COMMON_ATOMS_START(&cx->runtime->atomState) + : fp->script()->atomMap.vector; +} + +namespace js { + +class AutoGCRooter { + public: + AutoGCRooter(JSContext *cx, ptrdiff_t tag) + : down(cx->autoGCRooters), tag(tag), context(cx) + { + JS_ASSERT(this != cx->autoGCRooters); + CHECK_REQUEST(cx); + cx->autoGCRooters = this; + } + + ~AutoGCRooter() { + JS_ASSERT(this == context->autoGCRooters); + CHECK_REQUEST(context); + context->autoGCRooters = down; + } + + /* Implemented in jsgc.cpp. */ + inline void trace(JSTracer *trc); + +#ifdef __GNUC__ +# pragma GCC visibility push(default) +#endif + friend JS_FRIEND_API(void) MarkContext(JSTracer *trc, JSContext *acx); + friend void MarkRuntime(JSTracer *trc); +#ifdef __GNUC__ +# pragma GCC visibility pop +#endif + + protected: + AutoGCRooter * const down; + + /* + * Discriminates actual subclass of this being used. If non-negative, the + * subclass roots an array of values of the length stored in this field. + * If negative, meaning is indicated by the corresponding value in the enum + * below. Any other negative value indicates some deeper problem such as + * memory corruption. + */ + ptrdiff_t tag; + + JSContext * const context; + + enum { + JSVAL = -1, /* js::AutoValueRooter */ + SHAPE = -2, /* js::AutoShapeRooter */ + PARSER = -3, /* js::Parser */ + SCRIPT = -4, /* js::AutoScriptRooter */ + ENUMERATOR = -5, /* js::AutoEnumStateRooter */ + IDARRAY = -6, /* js::AutoIdArray */ + DESCRIPTORS = -7, /* js::AutoPropDescArrayRooter */ + NAMESPACES = -8, /* js::AutoNamespaceArray */ + XML = -9, /* js::AutoXMLRooter */ + OBJECT = -10, /* js::AutoObjectRooter */ + ID = -11, /* js::AutoIdRooter */ + VALVECTOR = -12, /* js::AutoValueVector */ + DESCRIPTOR = -13, /* js::AutoPropertyDescriptorRooter */ + STRING = -14, /* js::AutoStringRooter */ + IDVECTOR = -15, /* js::AutoIdVector */ + BINDINGS = -16, /* js::Bindings */ + SHAPEVECTOR = -17 /* js::AutoShapeVector */ + }; + + private: + /* No copy or assignment semantics. */ + AutoGCRooter(AutoGCRooter &ida); + void operator=(AutoGCRooter &ida); +}; + +/* FIXME(bug 332648): Move this into a public header. */ +class AutoValueRooter : private AutoGCRooter +{ + public: + explicit AutoValueRooter(JSContext *cx + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, JSVAL), val(js::NullValue()) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + AutoValueRooter(JSContext *cx, const Value &v + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, JSVAL), val(v) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + AutoValueRooter(JSContext *cx, jsval v + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, JSVAL), val(js::Valueify(v)) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + /* + * If you are looking for Object* overloads, use AutoObjectRooter instead; + * rooting Object*s as a js::Value requires discerning whether or not it is + * a function object. Also, AutoObjectRooter is smaller. + */ + + void set(Value v) { + JS_ASSERT(tag == JSVAL); + val = v; + } + + void set(jsval v) { + JS_ASSERT(tag == JSVAL); + val = js::Valueify(v); + } + + const Value &value() const { + JS_ASSERT(tag == JSVAL); + return val; + } + + Value *addr() { + JS_ASSERT(tag == JSVAL); + return &val; + } + + const jsval &jsval_value() const { + JS_ASSERT(tag == JSVAL); + return Jsvalify(val); + } + + jsval *jsval_addr() { + JS_ASSERT(tag == JSVAL); + return Jsvalify(&val); + } + + friend void AutoGCRooter::trace(JSTracer *trc); + friend void MarkRuntime(JSTracer *trc); + + private: + Value val; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoObjectRooter : private AutoGCRooter { + public: + AutoObjectRooter(JSContext *cx, JSObject *obj = NULL + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, OBJECT), obj(obj) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + void setObject(JSObject *obj) { + this->obj = obj; + } + + JSObject * object() const { + return obj; + } + + JSObject ** addr() { + return &obj; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + friend void MarkRuntime(JSTracer *trc); + + private: + JSObject *obj; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoStringRooter : private AutoGCRooter { + public: + AutoStringRooter(JSContext *cx, JSString *str = NULL + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, STRING), str(str) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + void setString(JSString *str) { + this->str = str; + } + + JSString * string() const { + return str; + } + + JSString ** addr() { + return &str; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + JSString *str; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoArrayRooter : private AutoGCRooter { + public: + AutoArrayRooter(JSContext *cx, size_t len, Value *vec + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, len), array(vec) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_ASSERT(tag >= 0); + } + + AutoArrayRooter(JSContext *cx, size_t len, jsval *vec + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, len), array(Valueify(vec)) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_ASSERT(tag >= 0); + } + + void changeLength(size_t newLength) { + tag = ptrdiff_t(newLength); + JS_ASSERT(tag >= 0); + } + + void changeArray(Value *newArray, size_t newLength) { + changeLength(newLength); + array = newArray; + } + + Value *array; + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoShapeRooter : private AutoGCRooter { + public: + AutoShapeRooter(JSContext *cx, const js::Shape *shape + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, SHAPE), shape(shape) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + friend void MarkRuntime(JSTracer *trc); + + private: + const js::Shape * const shape; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoScriptRooter : private AutoGCRooter { + public: + AutoScriptRooter(JSContext *cx, JSScript *script + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, SCRIPT), script(script) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + void setScript(JSScript *script) { + this->script = script; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + JSScript *script; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoIdRooter : private AutoGCRooter +{ + public: + explicit AutoIdRooter(JSContext *cx, jsid id = INT_TO_JSID(0) + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, ID), id_(id) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + jsid id() { + return id_; + } + + jsid * addr() { + return &id_; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + friend void MarkRuntime(JSTracer *trc); + + private: + jsid id_; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoIdArray : private AutoGCRooter { + public: + AutoIdArray(JSContext *cx, JSIdArray *ida JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, IDARRAY), idArray(ida) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + ~AutoIdArray() { + if (idArray) + JS_DestroyIdArray(context, idArray); + } + bool operator!() { + return idArray == NULL; + } + jsid operator[](size_t i) const { + JS_ASSERT(idArray); + JS_ASSERT(i < size_t(idArray->length)); + return idArray->vector[i]; + } + size_t length() const { + return idArray->length; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + JSIdArray *steal() { + JSIdArray *copy = idArray; + idArray = NULL; + return copy; + } + + protected: + inline void trace(JSTracer *trc); + + private: + JSIdArray * idArray; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + + /* No copy or assignment semantics. */ + AutoIdArray(AutoIdArray &ida); + void operator=(AutoIdArray &ida); +}; + +/* The auto-root for enumeration object and its state. */ +class AutoEnumStateRooter : private AutoGCRooter +{ + public: + AutoEnumStateRooter(JSContext *cx, JSObject *obj + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, ENUMERATOR), obj(obj), stateValue() + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_ASSERT(obj); + } + + ~AutoEnumStateRooter() { + if (!stateValue.isNull()) { +#ifdef DEBUG + JSBool ok = +#endif + obj->enumerate(context, JSENUMERATE_DESTROY, &stateValue, 0); + JS_ASSERT(ok); + } + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + const Value &state() const { return stateValue; } + Value *addr() { return &stateValue; } + + protected: + void trace(JSTracer *trc); + + JSObject * const obj; + + private: + Value stateValue; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +#ifdef JS_HAS_XML_SUPPORT +class AutoXMLRooter : private AutoGCRooter { + public: + AutoXMLRooter(JSContext *cx, JSXML *xml + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, XML), xml(xml) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_ASSERT(xml); + } + + friend void AutoGCRooter::trace(JSTracer *trc); + friend void MarkRuntime(JSTracer *trc); + + private: + JSXML * const xml; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; +#endif /* JS_HAS_XML_SUPPORT */ + +class AutoBindingsRooter : private AutoGCRooter { + public: + AutoBindingsRooter(JSContext *cx, Bindings &bindings + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, BINDINGS), bindings(bindings) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + Bindings &bindings; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoLockGC { + public: + explicit AutoLockGC(JSRuntime *rt + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : rt(rt) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_LOCK_GC(rt); + } + ~AutoLockGC() { JS_UNLOCK_GC(rt); } + + private: + JSRuntime *rt; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoUnlockGC { + private: + JSRuntime *rt; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + + public: + explicit AutoUnlockGC(JSRuntime *rt + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : rt(rt) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_UNLOCK_GC(rt); + } + ~AutoUnlockGC() { JS_LOCK_GC(rt); } +}; + +class AutoLockAtomsCompartment { + private: + JSContext *cx; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + + public: + AutoLockAtomsCompartment(JSContext *cx + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : cx(cx) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_LOCK(cx, &cx->runtime->atomState.lock); +#ifdef JS_THREADSAFE + cx->runtime->atomsCompartmentIsLocked = true; +#endif + } + ~AutoLockAtomsCompartment() { +#ifdef JS_THREADSAFE + cx->runtime->atomsCompartmentIsLocked = false; +#endif + JS_UNLOCK(cx, &cx->runtime->atomState.lock); + } +}; + +class AutoUnlockAtomsCompartment { + JSContext *cx; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + + public: + AutoUnlockAtomsCompartment(JSContext *cx + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : cx(cx) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; +#ifdef JS_THREADSAFE + cx->runtime->atomsCompartmentIsLocked = false; +#endif + JS_UNLOCK(cx, &cx->runtime->atomState.lock); + } + ~AutoUnlockAtomsCompartment() { + JS_LOCK(cx, &cx->runtime->atomState.lock); +#ifdef JS_THREADSAFE + cx->runtime->atomsCompartmentIsLocked = true; +#endif + } +}; + +class AutoKeepAtoms { + JSRuntime *rt; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + + public: + explicit AutoKeepAtoms(JSRuntime *rt + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : rt(rt) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_KEEP_ATOMS(rt); + } + ~AutoKeepAtoms() { JS_UNKEEP_ATOMS(rt); } +}; + +class AutoArenaAllocator { + JSArenaPool *pool; + void *mark; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + + public: + explicit AutoArenaAllocator(JSArenaPool *pool + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : pool(pool), mark(JS_ARENA_MARK(pool)) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + ~AutoArenaAllocator() { JS_ARENA_RELEASE(pool, mark); } + + template + T *alloc(size_t elems) { + void *ptr; + JS_ARENA_ALLOCATE(ptr, pool, elems * sizeof(T)); + return static_cast(ptr); + } +}; + +class AutoReleasePtr { + JSContext *cx; + void *ptr; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + + AutoReleasePtr operator=(const AutoReleasePtr &other); + + public: + explicit AutoReleasePtr(JSContext *cx, void *ptr + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : cx(cx), ptr(ptr) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + ~AutoReleasePtr() { cx->free(ptr); } +}; + +/* + * FIXME: bug 602774: cleaner API for AutoReleaseNullablePtr + */ +class AutoReleaseNullablePtr { + JSContext *cx; + void *ptr; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + + AutoReleaseNullablePtr operator=(const AutoReleaseNullablePtr &other); + + public: + explicit AutoReleaseNullablePtr(JSContext *cx, void *ptr + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : cx(cx), ptr(ptr) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + void reset(void *ptr2) { + if (ptr) + cx->free(ptr); + ptr = ptr2; + } + ~AutoReleaseNullablePtr() { if (ptr) cx->free(ptr); } +}; + +class AutoLocalNameArray { + public: + explicit AutoLocalNameArray(JSContext *cx, JSFunction *fun + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : context(cx), + mark(JS_ARENA_MARK(&cx->tempPool)), + names(fun->script()->bindings.getLocalNameArray(cx, &cx->tempPool)), + count(fun->script()->bindings.countLocalNames()) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + ~AutoLocalNameArray() { + JS_ARENA_RELEASE(&context->tempPool, mark); + } + + operator bool() const { return !!names; } + + uint32 length() const { return count; } + + const jsuword &operator [](unsigned i) const { return names[i]; } + + private: + JSContext *context; + void *mark; + jsuword *names; + uint32 count; + + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +template +class AlreadyIncRefed +{ + typedef RefCountable *****ConvertibleToBool; + + RefCountable *obj; + + public: + explicit AlreadyIncRefed(RefCountable *obj) : obj(obj) {} + + bool null() const { return obj == NULL; } + operator ConvertibleToBool() const { return (ConvertibleToBool)obj; } + + RefCountable *operator->() const { JS_ASSERT(!null()); return obj; } + RefCountable &operator*() const { JS_ASSERT(!null()); return *obj; } + RefCountable *get() const { return obj; } +}; + +template +class NeedsIncRef +{ + typedef RefCountable *****ConvertibleToBool; + + RefCountable *obj; + + public: + explicit NeedsIncRef(RefCountable *obj) : obj(obj) {} + + bool null() const { return obj == NULL; } + operator ConvertibleToBool() const { return (ConvertibleToBool)obj; } + + RefCountable *operator->() const { JS_ASSERT(!null()); return obj; } + RefCountable &operator*() const { JS_ASSERT(!null()); return *obj; } + RefCountable *get() const { return obj; } +}; + +template +class AutoRefCount +{ + typedef RefCountable *****ConvertibleToBool; + + JSContext *const cx; + RefCountable *obj; + + AutoRefCount(const AutoRefCount &); + void operator=(const AutoRefCount &); + + public: + explicit AutoRefCount(JSContext *cx) + : cx(cx), obj(NULL) + {} + + AutoRefCount(JSContext *cx, NeedsIncRef aobj) + : cx(cx), obj(aobj.get()) + { + if (obj) + obj->incref(cx); + } + + AutoRefCount(JSContext *cx, AlreadyIncRefed aobj) + : cx(cx), obj(aobj.get()) + {} + + ~AutoRefCount() { + if (obj) + obj->decref(cx); + } + + void reset(NeedsIncRef aobj) { + if (obj) + obj->decref(cx); + obj = aobj.get(); + if (obj) + obj->incref(cx); + } + + void reset(AlreadyIncRefed aobj) { + if (obj) + obj->decref(cx); + obj = aobj.get(); + } + + bool null() const { return obj == NULL; } + operator ConvertibleToBool() const { return (ConvertibleToBool)obj; } + + RefCountable *operator->() const { JS_ASSERT(!null()); return obj; } + RefCountable &operator*() const { JS_ASSERT(!null()); return *obj; } + RefCountable *get() const { return obj; } +}; + +} /* namespace js */ + +class JSAutoResolveFlags +{ + public: + JSAutoResolveFlags(JSContext *cx, uintN flags + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx), mSaved(cx->resolveFlags) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + cx->resolveFlags = flags; + } + + ~JSAutoResolveFlags() { mContext->resolveFlags = mSaved; } + + private: + JSContext *mContext; + uintN mSaved; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +extern JSThreadData * +js_CurrentThreadData(JSRuntime *rt); + +extern JSBool +js_InitThreads(JSRuntime *rt); + +extern void +js_FinishThreads(JSRuntime *rt); + +extern void +js_PurgeThreads(JSContext *cx); + +namespace js { + +#ifdef JS_THREADSAFE + +/* Iterator over JSThreadData from all JSThread instances. */ +class ThreadDataIter : public JSThread::Map::Range +{ + public: + ThreadDataIter(JSRuntime *rt) : JSThread::Map::Range(rt->threads.all()) {} + + JSThreadData *threadData() const { + return &front().value->data; + } +}; + +#else /* !JS_THREADSAFE */ + +class ThreadDataIter +{ + JSRuntime *runtime; + bool done; + public: + ThreadDataIter(JSRuntime *rt) : runtime(rt), done(false) {} + + bool empty() const { + return done; + } + + void popFront() { + JS_ASSERT(!done); + done = true; + } + + JSThreadData *threadData() const { + JS_ASSERT(!done); + return &runtime->threadData; + } +}; + +#endif /* !JS_THREADSAFE */ + +} /* namespace js */ + +/* + * Create and destroy functions for JSContext, which is manually allocated + * and exclusively owned. + */ +extern JSContext * +js_NewContext(JSRuntime *rt, size_t stackChunkSize); + +extern void +js_DestroyContext(JSContext *cx, JSDestroyContextMode mode); + +static JS_INLINE JSContext * +js_ContextFromLinkField(JSCList *link) +{ + JS_ASSERT(link); + return (JSContext *) ((uint8 *) link - offsetof(JSContext, link)); +} + +/* + * If unlocked, acquire and release rt->gcLock around *iterp update; otherwise + * the caller must be holding rt->gcLock. + */ +extern JSContext * +js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp); + +/* + * Iterate through contexts with active requests. The caller must be holding + * rt->gcLock in case of a thread-safe build, or otherwise guarantee that the + * context list is not alternated asynchroniously. + */ +extern JS_FRIEND_API(JSContext *) +js_NextActiveContext(JSRuntime *, JSContext *); + +/* + * Class.resolve and watchpoint recursion damping machinery. + */ +extern JSBool +js_StartResolving(JSContext *cx, JSResolvingKey *key, uint32 flag, + JSResolvingEntry **entryp); + +extern void +js_StopResolving(JSContext *cx, JSResolvingKey *key, uint32 flag, + JSResolvingEntry *entry, uint32 generation); + +/* + * Report an exception, which is currently realized as a printf-style format + * string and its arguments. + */ +typedef enum JSErrNum { +#define MSG_DEF(name, number, count, exception, format) \ + name = number, +#include "js.msg" +#undef MSG_DEF + JSErr_Limit +} JSErrNum; + +extern JS_FRIEND_API(const JSErrorFormatString *) +js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber); + +#ifdef va_start +extern JSBool +js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap); + +extern JSBool +js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback, + void *userRef, const uintN errorNumber, + JSBool charArgs, va_list ap); + +extern JSBool +js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback, + void *userRef, const uintN errorNumber, + char **message, JSErrorReport *reportp, + bool charArgs, va_list ap); +#endif + +extern void +js_ReportOutOfMemory(JSContext *cx); + +/* + * Report that cx->scriptStackQuota is exhausted. + */ +void +js_ReportOutOfScriptQuota(JSContext *cx); + +extern JS_FRIEND_API(void) +js_ReportOverRecursed(JSContext *cx); + +extern JS_FRIEND_API(void) +js_ReportAllocationOverflow(JSContext *cx); + +#define JS_CHECK_RECURSION(cx, onerror) \ + JS_BEGIN_MACRO \ + int stackDummy_; \ + \ + if (!JS_CHECK_STACK_SIZE(cx->stackLimit, &stackDummy_)) { \ + js_ReportOverRecursed(cx); \ + onerror; \ + } \ + JS_END_MACRO + +/* + * Report an exception using a previously composed JSErrorReport. + * XXXbe remove from "friend" API + */ +extern JS_FRIEND_API(void) +js_ReportErrorAgain(JSContext *cx, const char *message, JSErrorReport *report); + +extern void +js_ReportIsNotDefined(JSContext *cx, const char *name); + +/* + * Report an attempt to access the property of a null or undefined value (v). + */ +extern JSBool +js_ReportIsNullOrUndefined(JSContext *cx, intN spindex, const js::Value &v, + JSString *fallback); + +extern void +js_ReportMissingArg(JSContext *cx, const js::Value &v, uintN arg); + +/* + * Report error using js_DecompileValueGenerator(cx, spindex, v, fallback) as + * the first argument for the error message. If the error message has less + * then 3 arguments, use null for arg1 or arg2. + */ +extern JSBool +js_ReportValueErrorFlags(JSContext *cx, uintN flags, const uintN errorNumber, + intN spindex, const js::Value &v, JSString *fallback, + const char *arg1, const char *arg2); + +#define js_ReportValueError(cx,errorNumber,spindex,v,fallback) \ + ((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \ + spindex, v, fallback, NULL, NULL)) + +#define js_ReportValueError2(cx,errorNumber,spindex,v,fallback,arg1) \ + ((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \ + spindex, v, fallback, arg1, NULL)) + +#define js_ReportValueError3(cx,errorNumber,spindex,v,fallback,arg1,arg2) \ + ((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \ + spindex, v, fallback, arg1, arg2)) + +extern JSErrorFormatString js_ErrorFormatString[JSErr_Limit]; + +#ifdef JS_THREADSAFE +# define JS_ASSERT_REQUEST_DEPTH(cx) (JS_ASSERT((cx)->thread), \ + JS_ASSERT((cx)->thread->data.requestDepth >= 1)) +#else +# define JS_ASSERT_REQUEST_DEPTH(cx) ((void) 0) +#endif + +/* + * If the operation callback flag was set, call the operation callback. + * This macro can run the full GC. Return true if it is OK to continue and + * false otherwise. + */ +#define JS_CHECK_OPERATION_LIMIT(cx) \ + (JS_ASSERT_REQUEST_DEPTH(cx), \ + (!JS_THREAD_DATA(cx)->interruptFlags || js_InvokeOperationCallback(cx))) + +JS_ALWAYS_INLINE void +JSThreadData::triggerOperationCallback(JSRuntime *rt) +{ + /* + * Use JS_ATOMIC_SET and JS_ATOMIC_INCREMENT in the hope that it ensures + * the write will become immediately visible to other processors polling + * the flag. Note that we only care about visibility here, not read/write + * ordering: this field can only be written with the GC lock held. + */ + if (interruptFlags) + return; + JS_ATOMIC_SET(&interruptFlags, 1); + +#ifdef JS_THREADSAFE + /* rt->interruptCounter does not reflect suspended threads. */ + if (requestDepth != 0) + JS_ATOMIC_INCREMENT(&rt->interruptCounter); +#endif +} + +/* + * Invoke the operation callback and return false if the current execution + * is to be terminated. + */ +extern JSBool +js_InvokeOperationCallback(JSContext *cx); + +extern JSBool +js_HandleExecutionInterrupt(JSContext *cx); + +namespace js { + +/* These must be called with GC lock taken. */ + +JS_FRIEND_API(void) +TriggerOperationCallback(JSContext *cx); + +void +TriggerAllOperationCallbacks(JSRuntime *rt); + +} /* namespace js */ + +extern JSStackFrame * +js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp); + +extern jsbytecode* +js_GetCurrentBytecodePC(JSContext* cx); + +extern bool +js_CurrentPCIsInImacro(JSContext *cx); + +namespace js { + +class RegExpStatics; + +extern JS_FORCES_STACK JS_FRIEND_API(void) +LeaveTrace(JSContext *cx); + +} /* namespace js */ + +/* + * Get the current frame, first lazily instantiating stack frames if needed. + * (Do not access cx->fp() directly except in JS_REQUIRES_STACK code.) + * + * Defined in jstracer.cpp if JS_TRACER is defined. + */ +static JS_FORCES_STACK JS_INLINE JSStackFrame * +js_GetTopStackFrame(JSContext *cx) +{ + js::LeaveTrace(cx); + return cx->maybefp(); +} + +static JS_INLINE JSBool +js_IsPropertyCacheDisabled(JSContext *cx) +{ + return cx->runtime->shapeGen >= js::SHAPE_OVERFLOW_BIT; +} + +static JS_INLINE uint32 +js_RegenerateShapeForGC(JSRuntime *rt) +{ + JS_ASSERT(rt->gcRunning); + JS_ASSERT(rt->gcRegenShapes); + + /* + * Under the GC, compared with js_GenerateShape, we don't need to use + * atomic increments but we still must make sure that after an overflow + * the shape stays such. + */ + uint32 shape = rt->shapeGen; + shape = (shape + 1) | (shape & js::SHAPE_OVERFLOW_BIT); + rt->shapeGen = shape; + return shape; +} + +namespace js { + +inline void * +ContextAllocPolicy::malloc(size_t bytes) +{ + return cx->malloc(bytes); +} + +inline void +ContextAllocPolicy::free(void *p) +{ + cx->free(p); +} + +inline void * +ContextAllocPolicy::realloc(void *p, size_t bytes) +{ + return cx->realloc(p, bytes); +} + +inline void +ContextAllocPolicy::reportAllocOverflow() const +{ + js_ReportAllocationOverflow(cx); +} + +template +class AutoVectorRooter : protected AutoGCRooter +{ + public: + explicit AutoVectorRooter(JSContext *cx, ptrdiff_t tag + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, tag), vector(cx) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + size_t length() const { return vector.length(); } + + bool append(const T &v) { return vector.append(v); } + + void popBack() { vector.popBack(); } + + bool growBy(size_t inc) { + size_t oldLength = vector.length(); + if (!vector.growByUninitialized(inc)) + return false; + MakeRangeGCSafe(vector.begin() + oldLength, vector.end()); + return true; + } + + bool resize(size_t newLength) { + size_t oldLength = vector.length(); + if (newLength <= oldLength) { + vector.shrinkBy(oldLength - newLength); + return true; + } + if (!vector.growByUninitialized(newLength - oldLength)) + return false; + MakeRangeGCSafe(vector.begin() + oldLength, vector.end()); + return true; + } + + bool reserve(size_t newLength) { + return vector.reserve(newLength); + } + + T &operator[](size_t i) { return vector[i]; } + const T &operator[](size_t i) const { return vector[i]; } + + const T *begin() const { return vector.begin(); } + T *begin() { return vector.begin(); } + + const T *end() const { return vector.end(); } + T *end() { return vector.end(); } + + const T &back() const { return vector.back(); } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + Vector vector; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoValueVector : public AutoVectorRooter +{ + public: + explicit AutoValueVector(JSContext *cx + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoVectorRooter(cx, VALVECTOR) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + const jsval *jsval_begin() const { return Jsvalify(begin()); } + jsval *jsval_begin() { return Jsvalify(begin()); } + + const jsval *jsval_end() const { return Jsvalify(end()); } + jsval *jsval_end() { return Jsvalify(end()); } + + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoIdVector : public AutoVectorRooter +{ + public: + explicit AutoIdVector(JSContext *cx + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoVectorRooter(cx, IDVECTOR) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoShapeVector : public AutoVectorRooter +{ + public: + explicit AutoShapeVector(JSContext *cx + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoVectorRooter(cx, SHAPEVECTOR) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +JSIdArray * +NewIdArray(JSContext *cx, jsint length); + +} /* namespace js */ + +#ifdef _MSC_VER +#pragma warning(pop) +#pragma warning(pop) +#endif + +#ifdef JS_CNTXT_UNDEFD_MOZALLOC_WRAPPERS +# include "mozilla/mozalloc_macro_wrappers.h" +#endif + +#endif /* jscntxt_h___ */ diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h new file mode 100644 index 0000000..bf3b055 --- /dev/null +++ b/js/src/jscntxtinlines.h @@ -0,0 +1,825 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jeff Walden (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jscntxtinlines_h___ +#define jscntxtinlines_h___ + +#include "jscntxt.h" +#include "jscompartment.h" +#include "jsparse.h" +#include "jsstaticcheck.h" +#include "jsxml.h" +#include "jsregexp.h" +#include "jsgc.h" + +namespace js { + +static inline JSObject * +GetGlobalForScopeChain(JSContext *cx) +{ + /* + * This is essentially GetScopeChain(cx)->getGlobal(), but without + * falling off trace. + * + * This use of cx->fp, possibly on trace, is deliberate: + * cx->fp->scopeChain->getGlobal() returns the same object whether we're on + * trace or not, since we do not trace calls across global objects. + */ + VOUCH_DOES_NOT_REQUIRE_STACK(); + + if (cx->hasfp()) + return cx->fp()->scopeChain().getGlobal(); + + JSObject *scope = cx->globalObject; + if (!scope) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE); + return NULL; + } + OBJ_TO_INNER_OBJECT(cx, scope); + return scope; +} + +} + +#ifdef JS_METHODJIT +inline js::mjit::JaegerCompartment *JSContext::jaegerCompartment() +{ + return compartment->jaegerCompartment; +} +#endif + +inline bool +JSContext::ensureGeneratorStackSpace() +{ + bool ok = genStack.reserve(genStack.length() + 1); + if (!ok) + js_ReportOutOfMemory(this); + return ok; +} + +JSStackFrame * +JSContext::computeNextFrame(JSStackFrame *fp) +{ + JSStackFrame *next = NULL; + for (js::StackSegment *ss = currentSegment; ; ss = ss->getPreviousInContext()) { + JSStackFrame *end = ss->getInitialFrame()->prev(); + for (JSStackFrame *f = ss->getCurrentFrame(); f != end; next = f, f = f->prev()) { + if (f == fp) + return next; + } + if (end != ss->getPreviousInContext()->getCurrentFrame()) + next = NULL; + } +} + +inline js::RegExpStatics * +JSContext::regExpStatics() +{ + return js::RegExpStatics::extractFrom(js::GetGlobalForScopeChain(this)); +} + +namespace js { + +JS_REQUIRES_STACK JS_ALWAYS_INLINE JSFrameRegs * +StackSegment::getCurrentRegs() const +{ + JS_ASSERT(inContext()); + return isActive() ? cx->regs : getSuspendedRegs(); +} + +JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame * +StackSegment::getCurrentFrame() const +{ + return getCurrentRegs()->fp; +} + +JS_REQUIRES_STACK inline Value * +StackSpace::firstUnused() const +{ + StackSegment *seg = currentSegment; + if (!seg) { + JS_ASSERT(invokeArgEnd == NULL); + return base; + } + if (seg->inContext()) { + Value *sp = seg->getCurrentRegs()->sp; + if (invokeArgEnd > sp) { + JS_ASSERT(invokeSegment == currentSegment); + JS_ASSERT_IF(seg->maybeContext()->hasfp(), + invokeFrame == seg->maybeContext()->fp()); + return invokeArgEnd; + } + return sp; + } + JS_ASSERT(invokeArgEnd); + JS_ASSERT(invokeSegment == currentSegment); + return invokeArgEnd; +} + + +/* Inline so we don't need the friend API. */ +JS_ALWAYS_INLINE bool +StackSpace::isCurrentAndActive(JSContext *cx) const +{ +#ifdef DEBUG + JS_ASSERT_IF(cx->getCurrentSegment(), + cx->getCurrentSegment()->maybeContext() == cx); + cx->assertSegmentsInSync(); +#endif + return currentSegment && + currentSegment->isActive() && + currentSegment == cx->getCurrentSegment(); +} + +STATIC_POSTCONDITION(!return || ubound(from) >= nvals) +JS_ALWAYS_INLINE bool +StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const +{ + JS_ASSERT(from >= firstUnused()); +#ifdef XP_WIN + JS_ASSERT(from <= commitEnd); + if (commitEnd - from >= nvals) + goto success; + if (end - from < nvals) { + if (maybecx) + js_ReportOutOfScriptQuota(maybecx); + return false; + } + if (!bumpCommit(from, nvals)) { + if (maybecx) + js_ReportOutOfScriptQuota(maybecx); + return false; + } + goto success; +#else + if (end - from < nvals) { + if (maybecx) + js_ReportOutOfScriptQuota(maybecx); + return false; + } + goto success; +#endif + success: +#ifdef DEBUG + memset(from, 0xde, nvals * sizeof(js::Value)); +#endif + return true; +} + +JS_ALWAYS_INLINE bool +StackSpace::ensureEnoughSpaceToEnterTrace() +{ +#ifdef XP_WIN + return ensureSpace(NULL, firstUnused(), MAX_TRACE_SPACE_VALS); +#endif + return end - firstUnused() > MAX_TRACE_SPACE_VALS; +} + +JS_ALWAYS_INLINE bool +StackSpace::EnsureSpaceCheck::operator()(const StackSpace &stack, JSContext *cx, + Value *from, uintN nvals) +{ + return stack.ensureSpace(cx, from, nvals); +} + +JS_ALWAYS_INLINE bool +StackSpace::LimitCheck::operator()(const StackSpace &stack, JSContext *cx, + Value *from, uintN nvals) +{ + JS_ASSERT(from == stack.firstUnused()); + JS_ASSERT(from < *limit); + if (*limit - from >= ptrdiff_t(nvals)) + return true; + if (stack.bumpCommitAndLimit(base, from, nvals, limit)) + return true; + js_ReportOverRecursed(cx); + return false; +} + +JS_REQUIRES_STACK JS_ALWAYS_INLINE bool +StackSpace::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard *ag) +{ + if (JS_UNLIKELY(!isCurrentAndActive(cx))) + return pushSegmentForInvoke(cx, argc, ag); + + Value *sp = cx->regs->sp; + Value *start = invokeArgEnd > sp ? invokeArgEnd : sp; + JS_ASSERT(start == firstUnused()); + uintN nvals = 2 + argc; + if (!ensureSpace(cx, start, nvals)) + return false; + + Value *vp = start; + Value *vpend = vp + nvals; + /* Don't need to MakeRangeGCSafe: the VM stack is conservatively marked. */ + + /* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */ + ag->prevInvokeArgEnd = invokeArgEnd; + invokeArgEnd = vpend; +#ifdef DEBUG + ag->prevInvokeSegment = invokeSegment; + invokeSegment = currentSegment; + ag->prevInvokeFrame = invokeFrame; + invokeFrame = cx->maybefp(); +#endif + + ag->cx = cx; + ag->argv_ = vp + 2; + ag->argc_ = argc; + return true; +} + +JS_REQUIRES_STACK JS_ALWAYS_INLINE void +StackSpace::popInvokeArgs(const InvokeArgsGuard &ag) +{ + if (JS_UNLIKELY(ag.seg != NULL)) { + popSegmentForInvoke(ag); + return; + } + + JS_ASSERT(isCurrentAndActive(ag.cx)); + JS_ASSERT(invokeSegment == currentSegment); + JS_ASSERT(invokeFrame == ag.cx->maybefp()); + JS_ASSERT(invokeArgEnd == ag.argv() + ag.argc()); + +#ifdef DEBUG + invokeSegment = ag.prevInvokeSegment; + invokeFrame = ag.prevInvokeFrame; +#endif + invokeArgEnd = ag.prevInvokeArgEnd; +} + +JS_ALWAYS_INLINE +InvokeArgsGuard::~InvokeArgsGuard() +{ + if (JS_UNLIKELY(!pushed())) + return; + cx->stack().popInvokeArgs(*this); +} + +template +JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame * +StackSpace::getCallFrame(JSContext *cx, Value *firstUnused, uintN nactual, + JSFunction *fun, JSScript *script, uint32 *flags, + Check check) const +{ + JS_ASSERT(fun->script() == script); + + /* Include an extra sizeof(JSStackFrame) for the method-jit. */ + uintN nvals = VALUES_PER_STACK_FRAME + script->nslots; + uintN nformal = fun->nargs; + + /* Maintain layout invariant: &formalArgs[0] == ((Value *)fp) - nformal. */ + + if (nactual == nformal) { + if (JS_UNLIKELY(!check(*this, cx, firstUnused, nvals))) + return NULL; + return reinterpret_cast(firstUnused); + } + + if (nactual < nformal) { + *flags |= JSFRAME_UNDERFLOW_ARGS; + uintN nmissing = nformal - nactual; + if (JS_UNLIKELY(!check(*this, cx, firstUnused, nmissing + nvals))) + return NULL; + SetValueRangeToUndefined(firstUnused, nmissing); + return reinterpret_cast(firstUnused + nmissing); + } + + *flags |= JSFRAME_OVERFLOW_ARGS; + uintN ncopy = 2 + nformal; + if (JS_UNLIKELY(!check(*this, cx, firstUnused, ncopy + nvals))) + return NULL; + + Value *dst = firstUnused; + Value *src = firstUnused - (2 + nactual); + PodCopy(dst, src, ncopy); + Debug_SetValueRangeToCrashOnTouch(src, ncopy); + return reinterpret_cast(firstUnused + ncopy); +} + +JS_REQUIRES_STACK JS_ALWAYS_INLINE bool +StackSpace::getInvokeFrame(JSContext *cx, const CallArgs &args, + JSFunction *fun, JSScript *script, + uint32 *flags, InvokeFrameGuard *fg) const +{ + JS_ASSERT(firstUnused() == args.argv() + args.argc()); + + Value *firstUnused = args.argv() + args.argc(); + fg->regs_.fp = getCallFrame(cx, firstUnused, args.argc(), fun, script, flags, + EnsureSpaceCheck()); + fg->regs_.sp = fg->regs_.fp->slots() + script->nfixed; + fg->regs_.pc = script->code; + + return fg->regs_.fp != NULL; +} + +JS_REQUIRES_STACK JS_ALWAYS_INLINE void +StackSpace::pushInvokeFrame(JSContext *cx, const CallArgs &args, + InvokeFrameGuard *fg) +{ + JS_ASSERT(firstUnused() == args.argv() + args.argc()); + + if (JS_UNLIKELY(!currentSegment->inContext())) { + cx->pushSegmentAndFrame(currentSegment, fg->regs_); + } else { + fg->prevRegs_ = cx->regs; + cx->setCurrentRegs(&fg->regs_); + } + + fg->cx_ = cx; + JS_ASSERT(isCurrentAndActive(cx)); +} + +JS_REQUIRES_STACK JS_ALWAYS_INLINE void +StackSpace::popInvokeFrame(const InvokeFrameGuard &fg) +{ + JSContext *cx = fg.cx_; + JSStackFrame *fp = fg.regs_.fp; + + JS_ASSERT(isCurrentAndActive(cx)); + if (JS_UNLIKELY(currentSegment->getInitialFrame() == fp)) { + cx->popSegmentAndFrame(); + } else { + JS_ASSERT(&fg.regs_ == cx->regs); + JS_ASSERT(fp->prev_ == fg.prevRegs_->fp); + JS_ASSERT(fp->prevpc() == fg.prevRegs_->pc); + cx->setCurrentRegs(fg.prevRegs_); + } +} + +JS_ALWAYS_INLINE void +InvokeFrameGuard::pop() +{ + JS_ASSERT(pushed()); + cx_->stack().popInvokeFrame(*this); + cx_ = NULL; +} + +JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame * +StackSpace::getInlineFrame(JSContext *cx, Value *sp, uintN nactual, + JSFunction *fun, JSScript *script, uint32 *flags) const +{ + JS_ASSERT(isCurrentAndActive(cx)); + JS_ASSERT(cx->hasActiveSegment()); + JS_ASSERT(cx->regs->sp == sp); + + return getCallFrame(cx, sp, nactual, fun, script, flags, EnsureSpaceCheck()); +} + +JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame * +StackSpace::getInlineFrameWithinLimit(JSContext *cx, Value *sp, uintN nactual, + JSFunction *fun, JSScript *script, uint32 *flags, + JSStackFrame *base, Value **limit) const +{ + JS_ASSERT(isCurrentAndActive(cx)); + JS_ASSERT(cx->hasActiveSegment()); + JS_ASSERT(cx->regs->sp == sp); + + return getCallFrame(cx, sp, nactual, fun, script, flags, LimitCheck(base, limit)); +} + +JS_REQUIRES_STACK JS_ALWAYS_INLINE void +StackSpace::pushInlineFrame(JSContext *cx, JSScript *script, JSStackFrame *fp, + JSFrameRegs *regs) +{ + JS_ASSERT(isCurrentAndActive(cx)); + JS_ASSERT(cx->regs == regs && script == fp->script()); + + regs->fp = fp; + regs->pc = script->code; + regs->sp = fp->slots() + script->nfixed; +} + +JS_REQUIRES_STACK JS_ALWAYS_INLINE void +StackSpace::popInlineFrame(JSContext *cx, JSStackFrame *prev, Value *newsp) +{ + JS_ASSERT(isCurrentAndActive(cx)); + JS_ASSERT(cx->hasActiveSegment()); + JS_ASSERT(cx->regs->fp->prev_ == prev); + JS_ASSERT(!cx->regs->fp->hasImacropc()); + JS_ASSERT(prev->base() <= newsp && newsp <= cx->regs->fp->formalArgsEnd()); + + JSFrameRegs *regs = cx->regs; + regs->pc = prev->pc(cx, regs->fp); + regs->fp = prev; + regs->sp = newsp; +} + +JS_ALWAYS_INLINE Value * +StackSpace::getStackLimit(JSContext *cx) +{ + Value *sp = cx->regs->sp; + JS_ASSERT(sp == firstUnused()); + Value *limit = sp + STACK_QUOTA; + + /* + * Try to reserve the whole STACK_QUOTA. If that fails, though, just + * reserve the minimum required space: enough for the nslots + an + * additional stack frame. + */ +#ifdef XP_WIN + if (JS_LIKELY(limit <= commitEnd)) + return limit; + if (ensureSpace(NULL /* don't report error */, sp, STACK_QUOTA)) + return limit; + uintN minimum = cx->fp()->numSlots() + VALUES_PER_STACK_FRAME; + return ensureSpace(cx, sp, minimum) ? sp + minimum : NULL; +#else + if (JS_LIKELY(limit <= end)) + return limit; + uintN minimum = cx->fp()->numSlots() + VALUES_PER_STACK_FRAME; + return ensureSpace(cx, sp, minimum) ? sp + minimum : NULL; +#endif +} + +JS_REQUIRES_STACK inline +FrameRegsIter::FrameRegsIter(JSContext *cx) + : cx(cx) +{ + curseg = cx->getCurrentSegment(); + if (JS_UNLIKELY(!curseg || !curseg->isActive())) { + initSlow(); + return; + } + JS_ASSERT(cx->regs->fp); + curfp = cx->regs->fp; + cursp = cx->regs->sp; + curpc = cx->regs->pc; + return; +} + +inline FrameRegsIter & +FrameRegsIter::operator++() +{ + JSStackFrame *fp = curfp; + JSStackFrame *prev = curfp = curfp->prev(); + if (!prev) + return *this; + + curpc = curfp->pc(cx, fp); + + if (JS_UNLIKELY(fp == curseg->getInitialFrame())) { + incSlow(fp, prev); + return *this; + } + + cursp = fp->formalArgsEnd(); + return *this; +} + +class AutoNamespaceArray : protected AutoGCRooter { + public: + AutoNamespaceArray(JSContext *cx) : AutoGCRooter(cx, NAMESPACES) { + array.init(); + } + + ~AutoNamespaceArray() { + array.finish(context); + } + + uint32 length() const { return array.length; } + + public: + friend void AutoGCRooter::trace(JSTracer *trc); + + JSXMLArray array; +}; + +#ifdef DEBUG +class CompartmentChecker +{ + private: + JSContext *context; + JSCompartment *compartment; + + public: + explicit CompartmentChecker(JSContext *cx) : context(cx), compartment(cx->compartment) { + check(cx->hasfp() ? JS_GetGlobalForScopeChain(cx) : cx->globalObject); + VOUCH_DOES_NOT_REQUIRE_STACK(); + } + + /* + * Set a breakpoint here (break js::CompartmentChecker::fail) to debug + * compartment mismatches. + */ + static void fail(JSCompartment *c1, JSCompartment *c2) { + printf("*** Compartment mismatch %p vs. %p\n", (void *) c1, (void *) c2); + JS_NOT_REACHED("compartment mismatched"); + } + + /* Note: should only be used when neither c1 nor c2 may be the default compartment. */ + static void check(JSCompartment *c1, JSCompartment *c2) { + JS_ASSERT(c1 != c1->rt->atomsCompartment); + JS_ASSERT(c2 != c2->rt->atomsCompartment); + if (c1 != c2) + fail(c1, c2); + } + + void check(JSCompartment *c) { + if (c && c != context->runtime->atomsCompartment) { + if (!compartment) + compartment = c; + else if (c != compartment) + fail(compartment, c); + } + } + + void check(JSPrincipals *) { /* nothing for now */ } + + void check(JSObject *obj) { + if (obj) + check(obj->compartment()); + } + + void check(JSString *str) { + if (!JSString::isStatic(str) && !str->isAtomized()) + check(str->asCell()->compartment()); + } + + void check(const js::Value &v) { + if (v.isObject()) + check(&v.toObject()); + else if (v.isString()) + check(v.toString()); + } + + void check(jsval v) { + check(Valueify(v)); + } + + void check(const ValueArray &arr) { + for (size_t i = 0; i < arr.length; i++) + check(arr.array[i]); + } + + void check(const JSValueArray &arr) { + for (size_t i = 0; i < arr.length; i++) + check(arr.array[i]); + } + + void check(jsid id) { + if (JSID_IS_OBJECT(id)) + check(JSID_TO_OBJECT(id)); + } + + void check(JSIdArray *ida) { + if (ida) { + for (jsint i = 0; i < ida->length; i++) { + if (JSID_IS_OBJECT(ida->vector[i])) + check(ida->vector[i]); + } + } + } + + void check(JSScript *script) { + if (script) { + check(script->compartment); + if (script->u.object) + check(script->u.object); + } + } + + void check(JSStackFrame *fp) { + check(&fp->scopeChain()); + } +}; + +#endif + +/* + * Don't perform these checks when called from a finalizer. The checking + * depends on other objects not having been swept yet. + */ +#define START_ASSERT_SAME_COMPARTMENT() \ + if (cx->runtime->gcRunning) \ + return; \ + CompartmentChecker c(cx) + +template inline void +assertSameCompartment(JSContext *cx, T1 t1) +{ +#ifdef DEBUG + START_ASSERT_SAME_COMPARTMENT(); + c.check(t1); +#endif +} + +template inline void +assertSameCompartment(JSContext *cx, T1 t1, T2 t2) +{ +#ifdef DEBUG + START_ASSERT_SAME_COMPARTMENT(); + c.check(t1); + c.check(t2); +#endif +} + +template inline void +assertSameCompartment(JSContext *cx, T1 t1, T2 t2, T3 t3) +{ +#ifdef DEBUG + START_ASSERT_SAME_COMPARTMENT(); + c.check(t1); + c.check(t2); + c.check(t3); +#endif +} + +template inline void +assertSameCompartment(JSContext *cx, T1 t1, T2 t2, T3 t3, T4 t4) +{ +#ifdef DEBUG + START_ASSERT_SAME_COMPARTMENT(); + c.check(t1); + c.check(t2); + c.check(t3); + c.check(t4); +#endif +} + +template inline void +assertSameCompartment(JSContext *cx, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) +{ +#ifdef DEBUG + START_ASSERT_SAME_COMPARTMENT(); + c.check(t1); + c.check(t2); + c.check(t3); + c.check(t4); + c.check(t5); +#endif +} + +#undef START_ASSERT_SAME_COMPARTMENT + +STATIC_PRECONDITION_ASSUME(ubound(vp) >= argc + 2) +JS_ALWAYS_INLINE bool +CallJSNative(JSContext *cx, js::Native native, uintN argc, js::Value *vp) +{ +#ifdef DEBUG + JSBool alreadyThrowing = cx->isExceptionPending(); +#endif + assertSameCompartment(cx, ValueArray(vp, argc + 2)); + JSBool ok = native(cx, argc, vp); + if (ok) { + assertSameCompartment(cx, vp[0]); + JS_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending()); + } + return ok; +} + +extern JSBool CallOrConstructBoundFunction(JSContext *, uintN, js::Value *); + +STATIC_PRECONDITION(ubound(vp) >= argc + 2) +JS_ALWAYS_INLINE bool +CallJSNativeConstructor(JSContext *cx, js::Native native, uintN argc, js::Value *vp) +{ +#ifdef DEBUG + JSObject *callee = &vp[0].toObject(); +#endif + + JS_ASSERT(vp[1].isMagic()); + if (!CallJSNative(cx, native, argc, vp)) + return false; + + /* + * Native constructors must return non-primitive values on success. + * Although it is legal, if a constructor returns the callee, there is a + * 99.9999% chance it is a bug. If any valid code actually wants the + * constructor to return the callee, the assertion can be removed or + * (another) conjunct can be added to the antecedent. + * + * Proxies are exceptions to both rules: they can return primitives and + * they allow content to return the callee. + * + * CallOrConstructBoundFunction is an exception as well because we + * might have used bind on a proxy function. + * + * (new Object(Object)) returns the callee. + */ + extern JSBool proxy_Construct(JSContext *, uintN, Value *); + JS_ASSERT_IF(native != proxy_Construct && native != js::CallOrConstructBoundFunction && + (!callee->isFunction() || callee->getFunctionPrivate()->u.n.clasp != &js_ObjectClass), + !vp->isPrimitive() && callee != &vp[0].toObject()); + + return true; +} + +JS_ALWAYS_INLINE bool +CallJSPropertyOp(JSContext *cx, js::PropertyOp op, JSObject *obj, jsid id, js::Value *vp) +{ + assertSameCompartment(cx, obj, id, *vp); + JSBool ok = op(cx, obj, id, vp); + if (ok) + assertSameCompartment(cx, obj, *vp); + return ok; +} + +JS_ALWAYS_INLINE bool +CallJSPropertyOpSetter(JSContext *cx, js::StrictPropertyOp op, JSObject *obj, jsid id, + JSBool strict, js::Value *vp) +{ + assertSameCompartment(cx, obj, id, *vp); + return op(cx, obj, id, strict, vp); +} + +inline bool +CallSetter(JSContext *cx, JSObject *obj, jsid id, js::StrictPropertyOp op, uintN attrs, + uintN shortid, JSBool strict, js::Value *vp) +{ + if (attrs & JSPROP_SETTER) + return ExternalGetOrSet(cx, obj, id, CastAsObjectJsval(op), JSACC_WRITE, 1, vp, vp); + + if (attrs & JSPROP_GETTER) + return js_ReportGetterOnlyAssignment(cx); + + if (attrs & JSPROP_SHORTID) + id = INT_TO_JSID(shortid); + return CallJSPropertyOpSetter(cx, op, obj, id, strict, vp); +} + +#ifdef JS_TRACER +/* + * Reconstruct the JS stack and clear cx->tracecx. We must be currently in a + * _FAIL builtin from trace on cx or another context on the same thread. The + * machine code for the trace remains on the C stack when js_DeepBail returns. + * + * Implemented in jstracer.cpp. + */ +JS_FORCES_STACK JS_FRIEND_API(void) +DeepBail(JSContext *cx); +#endif + +static JS_INLINE void +LeaveTraceIfGlobalObject(JSContext *cx, JSObject *obj) +{ + if (!obj->parent) + LeaveTrace(cx); +} + +static JS_INLINE void +LeaveTraceIfArgumentsObject(JSContext *cx, JSObject *obj) +{ + if (obj->isArguments()) + LeaveTrace(cx); +} + +static JS_INLINE JSBool +CanLeaveTrace(JSContext *cx) +{ + JS_ASSERT(JS_ON_TRACE(cx)); +#ifdef JS_TRACER + return JS_TRACE_MONITOR_ON_TRACE(cx)->bailExit != NULL; +#else + return JS_FALSE; +#endif +} + +} /* namespace js */ + +inline void +JSContext::setPendingException(js::Value v) { + this->throwing = true; + this->exception = v; + assertSameCompartment(this, v); +} + +#endif /* jscntxtinlines_h___ */ diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp new file mode 100644 index 0000000..5996d99 --- /dev/null +++ b/js/src/jscompartment.cpp @@ -0,0 +1,615 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jscntxt.h" +#include "jscompartment.h" +#include "jsgc.h" +#include "jsiter.h" +#include "jsproxy.h" +#include "jsscope.h" +#include "jstracer.h" +#include "jswrapper.h" +#include "assembler/wtf/Platform.h" +#include "methodjit/MethodJIT.h" +#include "methodjit/PolyIC.h" +#include "methodjit/MonoIC.h" + +#include "jsgcinlines.h" + +#if ENABLE_YARR_JIT +#include "assembler/jit/ExecutableAllocator.h" +#endif + +using namespace js; +using namespace js::gc; + +JSCompartment::JSCompartment(JSRuntime *rt) + : rt(rt), + principals(NULL), + gcBytes(0), + gcTriggerBytes(0), + gcLastBytes(0), + data(NULL), + active(false), +#ifdef JS_METHODJIT + jaegerCompartment(NULL), +#endif + propertyTree(thisForCtor()), + debugMode(rt->debugMode), +#if ENABLE_YARR_JIT + regExpAllocator(NULL), +#endif + mathCache(NULL), + marked(false) +{ + JS_INIT_CLIST(&scripts); + +#ifdef JS_TRACER + /* InitJIT expects this area to be zero'd. */ + PodZero(&traceMonitor); +#endif + + PodArrayZero(scriptsToGC); +} + +JSCompartment::~JSCompartment() +{ + Shape::finishEmptyShapes(this); + propertyTree.finish(); + +#if ENABLE_YARR_JIT + js_delete(regExpAllocator); +#endif + +#if defined JS_TRACER + FinishJIT(&traceMonitor); +#endif + +#ifdef JS_METHODJIT + js_delete(jaegerCompartment); +#endif + + js_delete(mathCache); + +#ifdef DEBUG + for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i) + JS_ASSERT(!scriptsToGC[i]); +#endif +} + +bool +JSCompartment::init() +{ + chunk = NULL; + for (unsigned i = 0; i < FINALIZE_LIMIT; i++) + arenas[i].init(); + for (unsigned i = 0; i < FINALIZE_LIMIT; i++) + freeLists.finalizables[i] = NULL; +#ifdef JS_GCMETER + memset(&compartmentStats, 0, sizeof(JSGCArenaStats) * FINALIZE_LIMIT); +#endif + if (!crossCompartmentWrappers.init()) + return false; + + if (!propertyTree.init()) + return false; + +#ifdef DEBUG + if (rt->meterEmptyShapes()) { + if (!emptyShapes.init()) + return false; + } +#endif + + if (!Shape::initEmptyShapes(this)) + return false; + +#ifdef JS_TRACER + if (!InitJIT(&traceMonitor)) + return false; +#endif + + if (!toSourceCache.init()) + return false; + +#if ENABLE_YARR_JIT + regExpAllocator = JSC::ExecutableAllocator::create(); + if (!regExpAllocator) + return false; +#endif + + if (!backEdgeTable.init()) + return false; + +#ifdef JS_METHODJIT + if (!(jaegerCompartment = js_new())) + return false; + return jaegerCompartment->Initialize(); +#else + return true; +#endif +} + +bool +JSCompartment::arenaListsAreEmpty() +{ + for (unsigned i = 0; i < FINALIZE_LIMIT; i++) { + if (!arenas[i].isEmpty()) + return false; + } + return true; +} + +static bool +IsCrossCompartmentWrapper(JSObject *wrapper) +{ + return wrapper->isWrapper() && + !!(JSWrapper::wrapperHandler(wrapper)->flags() & JSWrapper::CROSS_COMPARTMENT); +} + +bool +JSCompartment::wrap(JSContext *cx, Value *vp) +{ + JS_ASSERT(cx->compartment == this); + + uintN flags = 0; + + JS_CHECK_RECURSION(cx, return false); + + /* Only GC things have to be wrapped or copied. */ + if (!vp->isMarkable()) + return true; + + if (vp->isString()) { + JSString *str = vp->toString(); + + /* Static strings do not have to be wrapped. */ + if (JSString::isStatic(str)) + return true; + + /* If the string is already in this compartment, we are done. */ + if (str->asCell()->compartment() == this) + return true; + + /* If the string is an atom, we don't have to copy. */ + if (str->isAtomized()) { + JS_ASSERT(str->asCell()->compartment() == cx->runtime->atomsCompartment); + return true; + } + } + + /* + * Wrappers should really be parented to the wrapped parent of the wrapped + * object, but in that case a wrapped global object would have a NULL + * parent without being a proper global object (JSCLASS_IS_GLOBAL). Instead +, + * we parent all wrappers to the global object in their home compartment. + * This loses us some transparency, and is generally very cheesy. + */ + JSObject *global; + if (cx->hasfp()) { + global = cx->fp()->scopeChain().getGlobal(); + } else { + global = cx->globalObject; + OBJ_TO_INNER_OBJECT(cx, global); + if (!global) + return false; + } + + /* Unwrap incoming objects. */ + if (vp->isObject()) { + JSObject *obj = &vp->toObject(); + + /* If the object is already in this compartment, we are done. */ + if (obj->compartment() == this) + return true; + + /* Translate StopIteration singleton. */ + if (obj->getClass() == &js_StopIterationClass) + return js_FindClassObject(cx, NULL, JSProto_StopIteration, vp); + + /* Don't unwrap an outer window proxy. */ + if (!obj->getClass()->ext.innerObject) { + obj = vp->toObject().unwrap(&flags); + vp->setObject(*obj); + if (obj->getCompartment() == this) + return true; + + if (cx->runtime->preWrapObjectCallback) { + obj = cx->runtime->preWrapObjectCallback(cx, global, obj, flags); + if (!obj) + return false; + } + + vp->setObject(*obj); + if (obj->getCompartment() == this) + return true; + } else { + if (cx->runtime->preWrapObjectCallback) { + obj = cx->runtime->preWrapObjectCallback(cx, global, obj, flags); + if (!obj) + return false; + } + + JS_ASSERT(!obj->isWrapper() || obj->getClass()->ext.innerObject); + vp->setObject(*obj); + } + +#ifdef DEBUG + { + JSObject *outer = obj; + OBJ_TO_OUTER_OBJECT(cx, outer); + JS_ASSERT(outer && outer == obj); + } +#endif + } + + /* If we already have a wrapper for this value, use it. */ + if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(*vp)) { + *vp = p->value; + if (vp->isObject()) { + JSObject *obj = &vp->toObject(); + JS_ASSERT(IsCrossCompartmentWrapper(obj)); + if (obj->getParent() != global) { + do { + obj->setParent(global); + obj = obj->getProto(); + } while (obj && IsCrossCompartmentWrapper(obj)); + } + } + return true; + } + + if (vp->isString()) { + Value orig = *vp; + JSString *str = vp->toString(); + const jschar *chars = str->getChars(cx); + if (!chars) + return false; + JSString *wrapped = js_NewStringCopyN(cx, chars, str->length()); + if (!wrapped) + return false; + vp->setString(wrapped); + return crossCompartmentWrappers.put(orig, *vp); + } + + JSObject *obj = &vp->toObject(); + + /* + * Recurse to wrap the prototype. Long prototype chains will run out of + * stack, causing an error in CHECK_RECURSE. + * + * Wrapping the proto before creating the new wrapper and adding it to the + * cache helps avoid leaving a bad entry in the cache on OOM. But note that + * if we wrapped both proto and parent, we would get infinite recursion + * here (since Object.prototype->parent->proto leads to Object.prototype + * itself). + */ + JSObject *proto = obj->getProto(); + if (!wrap(cx, &proto)) + return false; + + /* + * We hand in the original wrapped object into the wrap hook to allow + * the wrap hook to reason over what wrappers are currently applied + * to the object. + */ + JSObject *wrapper = cx->runtime->wrapObjectCallback(cx, obj, proto, global, flags); + if (!wrapper) + return false; + + vp->setObject(*wrapper); + + wrapper->setProto(proto); + if (!crossCompartmentWrappers.put(wrapper->getProxyPrivate(), *vp)) + return false; + + wrapper->setParent(global); + return true; +} + +bool +JSCompartment::wrap(JSContext *cx, JSString **strp) +{ + AutoValueRooter tvr(cx, StringValue(*strp)); + if (!wrap(cx, tvr.addr())) + return false; + *strp = tvr.value().toString(); + return true; +} + +bool +JSCompartment::wrap(JSContext *cx, JSObject **objp) +{ + if (!*objp) + return true; + AutoValueRooter tvr(cx, ObjectValue(**objp)); + if (!wrap(cx, tvr.addr())) + return false; + *objp = &tvr.value().toObject(); + return true; +} + +bool +JSCompartment::wrapId(JSContext *cx, jsid *idp) +{ + if (JSID_IS_INT(*idp)) + return true; + AutoValueRooter tvr(cx, IdToValue(*idp)); + if (!wrap(cx, tvr.addr())) + return false; + return ValueToId(cx, tvr.value(), idp); +} + +bool +JSCompartment::wrap(JSContext *cx, PropertyOp *propp) +{ + Value v = CastAsObjectJsval(*propp); + if (!wrap(cx, &v)) + return false; + *propp = CastAsPropertyOp(v.toObjectOrNull()); + return true; +} + +bool +JSCompartment::wrap(JSContext *cx, StrictPropertyOp *propp) +{ + Value v = CastAsObjectJsval(*propp); + if (!wrap(cx, &v)) + return false; + *propp = CastAsStrictPropertyOp(v.toObjectOrNull()); + return true; +} + +bool +JSCompartment::wrap(JSContext *cx, PropertyDescriptor *desc) +{ + return wrap(cx, &desc->obj) && + (!(desc->attrs & JSPROP_GETTER) || wrap(cx, &desc->getter)) && + (!(desc->attrs & JSPROP_SETTER) || wrap(cx, &desc->setter)) && + wrap(cx, &desc->value); +} + +bool +JSCompartment::wrap(JSContext *cx, AutoIdVector &props) +{ + jsid *vector = props.begin(); + jsint length = props.length(); + for (size_t n = 0; n < size_t(length); ++n) { + if (!wrapId(cx, &vector[n])) + return false; + } + return true; +} + +#if defined JS_METHODJIT && defined JS_MONOIC +/* + * Check if the pool containing the code for jit should be destroyed, per the + * heuristics in JSCompartment::sweep. + */ +static inline bool +ScriptPoolDestroyed(JSContext *cx, mjit::JITScript *jit, + uint32 releaseInterval, uint32 &counter) +{ + JSC::ExecutablePool *pool = jit->code.m_executablePool; + if (pool->m_gcNumber != cx->runtime->gcNumber) { + /* + * The m_destroy flag may have been set in a previous GC for a pool which had + * references we did not remove (e.g. from the compartment's ExecutableAllocator) + * and is still around. Forget we tried to destroy it in such cases. + */ + pool->m_destroy = false; + pool->m_gcNumber = cx->runtime->gcNumber; + if (--counter == 0) { + pool->m_destroy = true; + counter = releaseInterval; + } + } + return pool->m_destroy; +} +#endif + +/* + * This method marks pointers that cross compartment boundaries. It should be + * called only by per-compartment GCs, since full GCs naturally follow pointers + * across compartments. + */ +void +JSCompartment::markCrossCompartment(JSTracer *trc) +{ + for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) + MarkValue(trc, e.front().key, "cross-compartment wrapper"); +} + +void +JSCompartment::mark(JSTracer *trc) +{ + if (IS_GC_MARKING_TRACER(trc)) { + JSRuntime *rt = trc->context->runtime; + + if (rt->gcCurrentCompartment && rt->gcCurrentCompartment != this) + return; + + if (marked) + return; + marked = true; + } + + if (emptyArgumentsShape) + emptyArgumentsShape->trace(trc); + if (emptyBlockShape) + emptyBlockShape->trace(trc); + if (emptyCallShape) + emptyCallShape->trace(trc); + if (emptyDeclEnvShape) + emptyDeclEnvShape->trace(trc); + if (emptyEnumeratorShape) + emptyEnumeratorShape->trace(trc); + if (emptyWithShape) + emptyWithShape->trace(trc); +} + +void +JSCompartment::sweep(JSContext *cx, uint32 releaseInterval) +{ + chunk = NULL; + /* Remove dead wrappers from the table. */ + for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) { + JS_ASSERT_IF(IsAboutToBeFinalized(cx, e.front().key.toGCThing()) && + !IsAboutToBeFinalized(cx, e.front().value.toGCThing()), + e.front().key.isString()); + if (IsAboutToBeFinalized(cx, e.front().key.toGCThing()) || + IsAboutToBeFinalized(cx, e.front().value.toGCThing())) { + e.removeFront(); + } + } + +#ifdef JS_TRACER + traceMonitor.sweep(cx); +#endif + +#if defined JS_METHODJIT && defined JS_MONOIC + + /* + * The release interval is the frequency with which we should try to destroy + * executable pools by releasing all JIT code in them, zero to never destroy pools. + * Initialize counter so that the first pool will be destroyed, and eventually drive + * the amount of JIT code in never-used compartments to zero. Don't discard anything + * for compartments which currently have active stack frames. + */ + uint32 counter = 1; + bool discardScripts = !active && releaseInterval != 0; + + for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) { + JSScript *script = reinterpret_cast(cursor); + if (script->hasJITCode()) { + mjit::ic::SweepCallICs(cx, script, discardScripts); + if (discardScripts) { + if (script->jitNormal && + ScriptPoolDestroyed(cx, script->jitNormal, releaseInterval, counter)) { + mjit::ReleaseScriptCode(cx, script); + continue; + } + if (script->jitCtor && + ScriptPoolDestroyed(cx, script->jitCtor, releaseInterval, counter)) { + mjit::ReleaseScriptCode(cx, script); + } + } + } + } + +#endif /* JS_METHODJIT && JS_MONOIC */ + + active = false; +} + +void +JSCompartment::purge(JSContext *cx) +{ + freeLists.purge(); + dtoaCache.purge(); + + /* Destroy eval'ed scripts. */ + js_DestroyScriptsToGC(cx, this); + + nativeIterCache.purge(); + toSourceCache.clear(); + +#ifdef JS_TRACER + /* + * If we are about to regenerate shapes, we have to flush the JIT cache, + * which will eventually abort any current recording. + */ + if (cx->runtime->gcRegenShapes) + traceMonitor.needFlush = JS_TRUE; +#endif + +#ifdef JS_METHODJIT + for (JSScript *script = (JSScript *)scripts.next; + &script->links != &scripts; + script = (JSScript *)script->links.next) { + if (script->hasJITCode()) { +# if defined JS_POLYIC + mjit::ic::PurgePICs(cx, script); +# endif +# if defined JS_MONOIC + /* + * MICs do not refer to data which can be GC'ed and do not generate stubs + * which might need to be discarded, but are sensitive to shape regeneration. + */ + if (cx->runtime->gcRegenShapes) + mjit::ic::PurgeMICs(cx, script); +# endif + } + } +#endif +} + +MathCache * +JSCompartment::allocMathCache(JSContext *cx) +{ + JS_ASSERT(!mathCache); + mathCache = js_new(); + if (!mathCache) + js_ReportOutOfMemory(cx); + return mathCache; +} + +size_t +JSCompartment::backEdgeCount(jsbytecode *pc) const +{ + if (BackEdgeMap::Ptr p = backEdgeTable.lookup(pc)) + return p->value; + + return 0; +} + +size_t +JSCompartment::incBackEdgeCount(jsbytecode *pc) +{ + if (BackEdgeMap::AddPtr p = backEdgeTable.lookupForAdd(pc)) { + p->value++; + return p->value; + } else { + backEdgeTable.add(p, pc, 1); + return 1; + } +} + diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h new file mode 100644 index 0000000..8630801 --- /dev/null +++ b/js/src/jscompartment.h @@ -0,0 +1,635 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jscompartment_h___ +#define jscompartment_h___ + +#include "jscntxt.h" +#include "jsgc.h" +#include "jsmath.h" +#include "jsobj.h" +#include "jsfun.h" +#include "jsgcstats.h" +#include "jsclist.h" +#include "jsxml.h" + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) /* Silence warning about JS_FRIEND_API and data members. */ +#endif + +namespace JSC { + +class ExecutableAllocator; + +} + +namespace js { + +/* Holds the number of recording attemps for an address. */ +typedef HashMap, + SystemAllocPolicy> RecordAttemptMap; + +/* Holds the profile data for loops. */ +typedef HashMap, + SystemAllocPolicy> LoopProfileMap; + +class Oracle; + +typedef HashSet, + SystemAllocPolicy> TracedScriptSet; + +typedef HashMap, + SystemAllocPolicy> ToSourceCache; + +struct TraceMonitor; + +/* Holds the execution state during trace execution. */ +struct TracerState +{ + JSContext* cx; // current VM context handle + TraceMonitor* traceMonitor; // current TM + double* stackBase; // native stack base + double* sp; // native stack pointer, stack[0] is spbase[0] + double* eos; // first unusable word after the native stack / begin of globals + FrameInfo** callstackBase; // call stack base + void* sor; // start of rp stack + FrameInfo** rp; // call stack pointer + void* eor; // first unusable word after the call stack + VMSideExit* lastTreeExitGuard; // guard we exited on during a tree call + VMSideExit* lastTreeCallGuard; // guard we want to grow from if the tree + // call exit guard mismatched + void* rpAtLastTreeCall; // value of rp at innermost tree call guard + VMSideExit* outermostTreeExitGuard; // the last side exit returned by js_CallTree + TreeFragment* outermostTree; // the outermost tree we initially invoked + uintN* inlineCallCountp; // inline call count counter + VMSideExit** innermostNestedGuardp; + VMSideExit* innermost; + uint64 startTime; + TracerState* prev; + + // Used by _FAIL builtins; see jsbuiltins.h. The builtin sets the + // JSBUILTIN_BAILED bit if it bails off trace and the JSBUILTIN_ERROR bit + // if an error or exception occurred. + uint32 builtinStatus; + + // Used to communicate the location of the return value in case of a deep bail. + double* deepBailSp; + + // Used when calling natives from trace to root the vp vector. + uintN nativeVpLen; + js::Value* nativeVp; + + TracerState(JSContext *cx, TraceMonitor *tm, TreeFragment *ti, + uintN &inlineCallCountp, VMSideExit** innermostNestedGuardp); + ~TracerState(); +}; + +/* + * Storage for the execution state and store during trace execution. Generated + * code depends on the fact that the globals begin |MAX_NATIVE_STACK_SLOTS| + * doubles after the stack begins. Thus, on trace, |TracerState::eos| holds a + * pointer to the first global. + */ +struct TraceNativeStorage +{ + double stack_global_buf[MAX_NATIVE_STACK_SLOTS + GLOBAL_SLOTS_BUFFER_SIZE]; + FrameInfo *callstack_buf[MAX_CALL_STACK_ENTRIES]; + + double *stack() { return stack_global_buf; } + double *global() { return stack_global_buf + MAX_NATIVE_STACK_SLOTS; } + FrameInfo **callstack() { return callstack_buf; } +}; + +/* Holds data to track a single globa. */ +struct GlobalState { + JSObject* globalObj; + uint32 globalShape; + SlotList* globalSlots; +}; + +/* + * Trace monitor. Every JSCompartment has an associated trace monitor + * that keeps track of loop frequencies for all JavaScript code loaded + * into that runtime. + */ +struct TraceMonitor { + /* + * The context currently executing JIT-compiled code in this compartment, or + * NULL if none. Among other things, this can in certain cases prevent + * last-ditch GC and suppress calls to JS_ReportOutOfMemory. + * + * !tracecx && !recorder: not on trace + * !tracecx && recorder: recording + * tracecx && !recorder: executing a trace + * tracecx && recorder: executing inner loop, recording outer loop + */ + JSContext *tracecx; + + /* + * State for the current tree execution. bailExit is valid if the tree has + * called back into native code via a _FAIL builtin and has not yet bailed, + * else garbage (NULL in debug builds). + */ + js::TracerState *tracerState; + js::VMSideExit *bailExit; + + /* Counts the number of iterations run by the currently executing trace. */ + unsigned iterationCounter; + + /* + * Cached storage to use when executing on trace. While we may enter nested + * traces, we always reuse the outer trace's storage, so never need more + * than of these. + */ + TraceNativeStorage *storage; + + /* + * There are 4 allocators here. This might seem like overkill, but they + * have different lifecycles, and by keeping them separate we keep the + * amount of retained memory down significantly. They are flushed (ie. + * all the allocated memory is freed) periodically. + * + * - dataAlloc has the lifecycle of the monitor. It's flushed only when + * the monitor is flushed. It's used for fragments. + * + * - traceAlloc has the same flush lifecycle as the dataAlloc, but it is + * also *marked* when a recording starts and rewinds to the mark point + * if recording aborts. So you can put things in it that are only + * reachable on a successful record/compile cycle like GuardRecords and + * SideExits. + * + * - tempAlloc is flushed after each recording, successful or not. It's + * used to store LIR code and for all other elements in the LIR + * pipeline. + * + * - codeAlloc has the same lifetime as dataAlloc, but its API is + * different (CodeAlloc vs. VMAllocator). It's used for native code. + * It's also a good idea to keep code and data separate to avoid I-cache + * vs. D-cache issues. + */ + VMAllocator* dataAlloc; + VMAllocator* traceAlloc; + VMAllocator* tempAlloc; + nanojit::CodeAlloc* codeAlloc; + nanojit::Assembler* assembler; + FrameInfoCache* frameCache; + + /* This gets incremented every time the monitor is flushed. */ + uintN flushEpoch; + + Oracle* oracle; + TraceRecorder* recorder; + + /* If we are profiling a loop, this tracks the current profile. Otherwise NULL. */ + LoopProfile* profile; + + GlobalState globalStates[MONITOR_N_GLOBAL_STATES]; + TreeFragment *vmfragments[FRAGMENT_TABLE_SIZE]; + RecordAttemptMap* recordAttempts; + + /* A hashtable mapping PC values to loop profiles for those loops. */ + LoopProfileMap* loopProfiles; + + /* + * Maximum size of the code cache before we start flushing. 1/16 of this + * size is used as threshold for the regular expression code cache. + */ + uint32 maxCodeCacheBytes; + + /* + * If nonzero, do not flush the JIT cache after a deep bail. That would + * free JITted code pages that we will later return to. Instead, set the + * needFlush flag so that it can be flushed later. + */ + JSBool needFlush; + + // Cached temporary typemap to avoid realloc'ing every time we create one. + // This must be used in only one place at a given time. It must be cleared + // before use. + TypeMap* cachedTempTypeMap; + + /* Scripts with recorded fragments. */ + TracedScriptSet tracedScripts; + +#ifdef DEBUG + /* Fields needed for fragment/guard profiling. */ + nanojit::Seq* branches; + uint32 lastFragID; + /* + * profAlloc has a lifetime which spans exactly from InitJIT to + * FinishJIT. + */ + VMAllocator* profAlloc; + FragStatsMap* profTab; +#endif + + bool ontrace() const { + return !!tracecx; + } + + /* Flush the JIT cache. */ + void flush(); + + /* Sweep any cache entry pointing to dead GC things. */ + void sweep(JSContext *cx); + + /* Mark any tracer stacks that are active. */ + void mark(JSTracer *trc); + + bool outOfMemory() const; +}; + +namespace mjit { +class JaegerCompartment; +} +} + +/* Number of potentially reusable scriptsToGC to search for the eval cache. */ +#ifndef JS_EVAL_CACHE_SHIFT +# define JS_EVAL_CACHE_SHIFT 6 +#endif +#define JS_EVAL_CACHE_SIZE JS_BIT(JS_EVAL_CACHE_SHIFT) + +#ifdef DEBUG +# define EVAL_CACHE_METER_LIST(_) _(probe), _(hit), _(step), _(noscope) +# define identity(x) x + +struct JSEvalCacheMeter { + uint64 EVAL_CACHE_METER_LIST(identity); +}; + +# undef identity +#endif + +namespace js { + +class NativeIterCache { + static const size_t SIZE = size_t(1) << 8; + + /* Cached native iterators. */ + JSObject *data[SIZE]; + + static size_t getIndex(uint32 key) { + return size_t(key) % SIZE; + } + + public: + /* Native iterator most recently started. */ + JSObject *last; + + NativeIterCache() + : last(NULL) { + PodArrayZero(data); + } + + void purge() { + PodArrayZero(data); + last = NULL; + } + + JSObject *get(uint32 key) const { + return data[getIndex(key)]; + } + + void set(uint32 key, JSObject *iterobj) { + data[getIndex(key)] = iterobj; + } +}; + +/* + * A single-entry cache for some base-10 double-to-string conversions. This + * helps date-format-xparb.js. It also avoids skewing the results for + * v8-splay.js when measured by the SunSpider harness, where the splay tree + * initialization (which includes many repeated double-to-string conversions) + * is erroneously included in the measurement; see bug 562553. + */ +class DtoaCache { + double d; + jsint base; + JSString *s; // if s==NULL, d and base are not valid + public: + DtoaCache() : s(NULL) {} + void purge() { s = NULL; } + + JSString *lookup(jsint base, double d) { + return this->s && base == this->base && d == this->d ? this->s : NULL; + } + + void cache(jsint base, double d, JSString *s) { + this->base = base; + this->d = d; + this->s = s; + } + +}; + +} /* namespace js */ + +struct JS_FRIEND_API(JSCompartment) { + JSRuntime *rt; + JSPrincipals *principals; + js::gc::Chunk *chunk; + + js::gc::ArenaList arenas[js::gc::FINALIZE_LIMIT]; + js::gc::FreeLists freeLists; + + size_t gcBytes; + size_t gcTriggerBytes; + size_t gcLastBytes; + +#ifdef JS_GCMETER + js::gc::JSGCArenaStats compartmentStats[js::gc::FINALIZE_LIMIT]; +#endif + +#ifdef JS_TRACER + /* Trace-tree JIT recorder/interpreter state. */ + js::TraceMonitor traceMonitor; +#endif + + /* Hashed lists of scripts created by eval to garbage-collect. */ + JSScript *scriptsToGC[JS_EVAL_CACHE_SIZE]; + +#ifdef DEBUG + JSEvalCacheMeter evalCacheMeter; +#endif + + void *data; + bool active; // GC flag, whether there are active frames + js::WrapperMap crossCompartmentWrappers; + +#ifdef JS_METHODJIT + js::mjit::JaegerCompartment *jaegerCompartment; +#endif + + /* + * Shared scope property tree, and arena-pool for allocating its nodes. + */ + js::PropertyTree propertyTree; + +#ifdef DEBUG + /* Property metering. */ + jsrefcount livePropTreeNodes; + jsrefcount totalPropTreeNodes; + jsrefcount propTreeKidsChunks; + jsrefcount liveDictModeNodes; +#endif + + /* + * Runtime-shared empty scopes for well-known built-in objects that lack + * class prototypes (the usual locus of an emptyShape). Mnemonic: ABCDEW + */ + js::EmptyShape *emptyArgumentsShape; + js::EmptyShape *emptyBlockShape; + js::EmptyShape *emptyCallShape; + js::EmptyShape *emptyDeclEnvShape; + js::EmptyShape *emptyEnumeratorShape; + js::EmptyShape *emptyWithShape; + + typedef js::HashSet, + js::SystemAllocPolicy> EmptyShapeSet; + + EmptyShapeSet emptyShapes; + + bool debugMode; // true iff debug mode on + JSCList scripts; // scripts in this compartment + + JSC::ExecutableAllocator *regExpAllocator; + + js::NativeIterCache nativeIterCache; + + js::ToSourceCache toSourceCache; + + JSCompartment(JSRuntime *rt); + ~JSCompartment(); + + bool init(); + + /* Mark cross-compartment wrappers. */ + void markCrossCompartment(JSTracer *trc); + + /* Mark this compartment's local roots. */ + void mark(JSTracer *trc); + + bool wrap(JSContext *cx, js::Value *vp); + bool wrap(JSContext *cx, JSString **strp); + bool wrap(JSContext *cx, JSObject **objp); + bool wrapId(JSContext *cx, jsid *idp); + bool wrap(JSContext *cx, js::PropertyOp *op); + bool wrap(JSContext *cx, js::StrictPropertyOp *op); + bool wrap(JSContext *cx, js::PropertyDescriptor *desc); + bool wrap(JSContext *cx, js::AutoIdVector &props); + + void sweep(JSContext *cx, uint32 releaseInterval); + void purge(JSContext *cx); + void finishArenaLists(); + void finalizeObjectArenaLists(JSContext *cx); + void finalizeStringArenaLists(JSContext *cx); + bool arenaListsAreEmpty(); + + void setGCLastBytes(size_t lastBytes); + + js::DtoaCache dtoaCache; + + private: + js::MathCache *mathCache; + + js::MathCache *allocMathCache(JSContext *cx); + + bool marked; + + typedef js::HashMap, + js::SystemAllocPolicy> BackEdgeMap; + + BackEdgeMap backEdgeTable; + + JSCompartment *thisForCtor() { return this; } + public: + js::MathCache *getMathCache(JSContext *cx) { + return mathCache ? mathCache : allocMathCache(cx); + } + + bool isMarked() { return marked; } + void clearMark() { marked = false; } + + size_t backEdgeCount(jsbytecode *pc) const; + size_t incBackEdgeCount(jsbytecode *pc); +}; + +#define JS_SCRIPTS_TO_GC(cx) ((cx)->compartment->scriptsToGC) +#define JS_PROPERTY_TREE(cx) ((cx)->compartment->propertyTree) + +#ifdef DEBUG +#define JS_COMPARTMENT_METER(x) x +#else +#define JS_COMPARTMENT_METER(x) +#endif + +/* + * N.B. JS_ON_TRACE(cx) is true if JIT code is on the stack in the current + * thread, regardless of whether cx is the context in which that trace is + * executing. cx must be a context on the current thread. + */ +static inline bool +JS_ON_TRACE(JSContext *cx) +{ +#ifdef JS_TRACER + if (JS_THREAD_DATA(cx)->onTraceCompartment) + return JS_THREAD_DATA(cx)->onTraceCompartment->traceMonitor.ontrace(); +#endif + return false; +} + +#ifdef JS_TRACER +static inline js::TraceMonitor * +JS_TRACE_MONITOR_ON_TRACE(JSContext *cx) +{ + JS_ASSERT(JS_ON_TRACE(cx)); + return &JS_THREAD_DATA(cx)->onTraceCompartment->traceMonitor; +} + +/* + * Only call this directly from the interpreter loop or the method jit. + * Otherwise, we may get the wrong compartment, and thus the wrong + * TraceMonitor. + */ +static inline js::TraceMonitor * +JS_TRACE_MONITOR_FROM_CONTEXT(JSContext *cx) +{ + return &cx->compartment->traceMonitor; +} +#endif + +static inline js::TraceRecorder * +TRACE_RECORDER(JSContext *cx) +{ +#ifdef JS_TRACER + if (JS_THREAD_DATA(cx)->recordingCompartment) + return JS_THREAD_DATA(cx)->recordingCompartment->traceMonitor.recorder; +#endif + return NULL; +} + +static inline js::LoopProfile * +TRACE_PROFILER(JSContext *cx) +{ +#ifdef JS_TRACER + if (JS_THREAD_DATA(cx)->profilingCompartment) + return JS_THREAD_DATA(cx)->profilingCompartment->traceMonitor.profile; +#endif + return NULL; +} + +namespace js { +static inline MathCache * +GetMathCache(JSContext *cx) +{ + return cx->compartment->getMathCache(cx); +} +} + +#ifdef DEBUG +# define EVAL_CACHE_METER(x) (cx->compartment->evalCacheMeter.x++) +#else +# define EVAL_CACHE_METER(x) ((void) 0) +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +namespace js { + +class PreserveCompartment { + protected: + JSContext *cx; + private: + JSCompartment *oldCompartment; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + public: + PreserveCompartment(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) : cx(cx) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + oldCompartment = cx->compartment; + } + + ~PreserveCompartment() { + cx->compartment = oldCompartment; + } +}; + +class SwitchToCompartment : public PreserveCompartment { + public: + SwitchToCompartment(JSContext *cx, JSCompartment *newCompartment) : PreserveCompartment(cx) { + cx->compartment = newCompartment; + } + + SwitchToCompartment(JSContext *cx, JSObject *target) : PreserveCompartment(cx) { + cx->compartment = target->getCompartment(); + } +}; + +class AssertCompartmentUnchanged { + protected: + JSContext * const cx; + JSCompartment * const oldCompartment; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER + public: + AssertCompartmentUnchanged(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) + : cx(cx), oldCompartment(cx->compartment) { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + ~AssertCompartmentUnchanged() { + JS_ASSERT(cx->compartment == oldCompartment); + } +}; + +} + +#endif /* jscompartment_h___ */ diff --git a/js/src/jscompat.h b/js/src/jscompat.h new file mode 100644 index 0000000..5ecda6e --- /dev/null +++ b/js/src/jscompat.h @@ -0,0 +1,55 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jscompat_h___ +#define jscompat_h___ +/* + * Compatibility glue for various NSPR versions. We must always define int8, + * int16, jsword, and so on to minimize differences with js/ref, no matter what + * the NSPR typedef names may be. + */ +#include "jstypes.h" +#include "jslong.h" + +typedef JSIntn intN; +typedef JSUintn uintN; +typedef JSUword jsuword; +typedef JSWord jsword; +typedef float float32; +#endif /* jscompat_h___ */ diff --git a/js/src/jsconfig.mk b/js/src/jsconfig.mk new file mode 100644 index 0000000..0ee3b74 --- /dev/null +++ b/js/src/jsconfig.mk @@ -0,0 +1,169 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +ifndef OBJDIR + ifdef OBJDIR_NAME + OBJDIR = $(OBJDIR_NAME) + endif +endif + +NSPR_VERSION = v4.0 +NSPR_LIBSUFFIX = 4 + +NSPR_LOCAL = $(MOZ_DEPTH)/dist/$(OBJDIR)/nspr +NSPR_DIST = $(MOZ_DEPTH)/dist/$(OBJDIR) +NSPR_OBJDIR = $(OBJDIR) +ifeq ($(OS_ARCH), SunOS) + NSPR_OBJDIR := $(subst _sparc,,$(NSPR_OBJDIR)) +endif +ifeq ($(OS_ARCH), Linux) + LINUX_REL := $(shell uname -r) + ifneq (,$(findstring 2.0,$(LINUX_REL))) + NSPR_OBJDIR := $(subst _All,2.0_x86_glibc_PTH,$(NSPR_OBJDIR)) + else + NSPR_OBJDIR := $(subst _All,2.2_x86_glibc_PTH,$(NSPR_OBJDIR)) + endif +endif +ifeq ($(OS_ARCH), AIX) + NSPR_OBJDIR := $(subst 4.1,4.2,$(NSPR_OBJDIR)) +endif +ifeq ($(OS_CONFIG), IRIX6.2) + NSPR_OBJDIR := $(subst 6.2,6.2_n32_PTH,$(NSPR_OBJDIR)) +endif +ifeq ($(OS_CONFIG), IRIX6.5) + NSPR_OBJDIR := $(subst 6.5,6.5_n32_PTH,$(NSPR_OBJDIR)) +endif +ifeq ($(OS_ARCH), WINNT) + ifeq ($(OBJDIR), WIN32_D.OBJ) + NSPR_OBJDIR = WINNT4.0_DBG.OBJ + endif + ifeq ($(OBJDIR), WIN32_O.OBJ) + NSPR_OBJDIR = WINNT4.0_OPT.OBJ + endif +endif +NSPR_SHARED = /share/builds/components/nspr20/$(NSPR_VERSION)/$(NSPR_OBJDIR) +ifeq ($(OS_ARCH), WINNT) + NSPR_SHARED = nspr20/$(NSPR_VERSION)/$(NSPR_OBJDIR) +endif +NSPR_VERSIONFILE = $(NSPR_LOCAL)/Version +NSPR_CURVERSION := $(shell cat $(NSPR_VERSIONFILE) 2>/dev/null) + +get_nspr: + @echo "Grabbing NSPR component..." +ifeq ($(NSPR_VERSION), $(NSPR_CURVERSION)) + @echo "No need, NSPR is up to date in this tree (ver=$(NSPR_VERSION))." +else + mkdir -p $(NSPR_LOCAL) + mkdir -p $(NSPR_DIST) + ifneq ($(OS_ARCH), WINNT) + cp $(NSPR_SHARED)/*.jar $(NSPR_LOCAL) + else + sh $(MOZ_DEPTH)/../reltools/compftp.sh $(NSPR_SHARED) $(NSPR_LOCAL) *.jar + endif + unzip -o $(NSPR_LOCAL)/mdbinary.jar -d $(NSPR_DIST) + mkdir -p $(NSPR_DIST)/include + unzip -o $(NSPR_LOCAL)/mdheader.jar -d $(NSPR_DIST)/include + rm -rf $(NSPR_DIST)/META-INF + rm -rf $(NSPR_DIST)/include/META-INF + echo $(NSPR_VERSION) > $(NSPR_VERSIONFILE) +endif + +SHIP_DIST = $(MOZ_DEPTH)/dist/$(OBJDIR) +SHIP_DIR = $(SHIP_DIST)/SHIP + +SHIP_LIBS = libjs.$(SO_SUFFIX) libjs.a +ifeq ($(OS_ARCH), WINNT) + SHIP_LIBS = js32.dll js32.lib +endif +SHIP_LIBS += $(LCJAR) +SHIP_LIBS := $(addprefix $(SHIP_DIST)/lib/, $(SHIP_LIBS)) + +SHIP_INCS = js*.h prmjtime.h resource.h *.msg *.tbl +SHIP_INCS := $(addprefix $(SHIP_DIST)/include/, $(SHIP_INCS)) + +SHIP_BINS = js +ifeq ($(OS_ARCH), WINNT) + SHIP_BINS := $(addsuffix .exe, $(SHIP_BINS)) +endif +SHIP_BINS := $(addprefix $(SHIP_DIST)/bin/, $(SHIP_BINS)) + +ifdef BUILD_OPT + JSREFJAR = jsref_opt.jar +else +ifdef BUILD_IDG + JSREFJAR = jsref_idg.jar +else + JSREFJAR = jsref_dbg.jar +endif +endif + +ship: + mkdir -p $(SHIP_DIR)/$(LIBDIR) + mkdir -p $(SHIP_DIR)/include + mkdir -p $(SHIP_DIR)/bin + cp $(SHIP_LIBS) $(SHIP_DIR)/$(LIBDIR) + cp $(SHIP_INCS) $(SHIP_DIR)/include + cp $(SHIP_BINS) $(SHIP_DIR)/bin + cd $(SHIP_DIR); \ + zip -r $(JSREFJAR) bin lib include +ifdef BUILD_SHIP + cp $(SHIP_DIR)/$(JSREFJAR) $(BUILD_SHIP) +endif + +CWD = $(shell pwd) +shipSource: $(SHIP_DIR)/jsref_src.lst .FORCE + mkdir -p $(SHIP_DIR) + cd $(MOZ_DEPTH)/.. ; \ + zip $(CWD)/$(SHIP_DIR)/jsref_src.jar -@ < $(CWD)/$(SHIP_DIR)/jsref_src.lst +ifdef BUILD_SHIP + cp $(SHIP_DIR)/jsref_src.jar $(BUILD_SHIP) +endif + +JSREFSRCDIRS := $(shell cat $(DEPTH)/SpiderMonkey.rsp) +$(SHIP_DIR)/jsref_src.lst: .FORCE + mkdir -p $(SHIP_DIR) + rm -f $@ + touch $@ + for d in $(JSREFSRCDIRS); do \ + cd $(MOZ_DEPTH)/..; \ + ls -1 -d $$d | grep -v CVS | grep -v \.OBJ >> $(CWD)/$@; \ + cd $(CWD); \ + done + +.FORCE: diff --git a/js/src/jscpucfg.cpp b/js/src/jscpucfg.cpp new file mode 100644 index 0000000..028def6 --- /dev/null +++ b/js/src/jscpucfg.cpp @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Roland Mainz + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Generate CPU-specific bit-size and similar #defines. + */ +#include +#include + +#if defined(CROSS_COMPILE) && !defined(FORCE_BIG_ENDIAN) && !defined(FORCE_LITTLE_ENDIAN) +#include +#endif + +/************************************************************************/ + +int main(int argc, char **argv) +{ + printf("#ifndef js_cpucfg___\n"); + printf("#define js_cpucfg___\n\n"); + + printf("/* AUTOMATICALLY GENERATED - DO NOT EDIT */\n\n"); + +#ifdef CROSS_COMPILE +#if defined(__APPLE__) && !defined(FORCE_BIG_ENDIAN) && !defined(FORCE_LITTLE_ENDIAN) + /* + * Darwin NSPR uses the same MDCPUCFG (_darwin.cfg) for multiple + * processors, and determines which processor to configure for based + * on compiler predefined macros. We do the same thing here. + */ + printf("#ifdef __LITTLE_ENDIAN__\n"); + printf("#define IS_LITTLE_ENDIAN 1\n"); + printf("#undef IS_BIG_ENDIAN\n"); + printf("#else\n"); + printf("#undef IS_LITTLE_ENDIAN\n"); + printf("#define IS_BIG_ENDIAN 1\n"); + printf("#endif\n\n"); +#elif defined(IS_LITTLE_ENDIAN) || defined(FORCE_LITTLE_ENDIAN) + printf("#define IS_LITTLE_ENDIAN 1\n"); + printf("#undef IS_BIG_ENDIAN\n\n"); +#elif defined(IS_BIG_ENDIAN) || defined(FORCE_BIG_ENDIAN) + printf("#undef IS_LITTLE_ENDIAN\n"); + printf("#define IS_BIG_ENDIAN 1\n\n"); +#else +#error "Endianess not defined." +#endif + +#else + + /* + * We don't handle PDP-endian or similar orders: if a short is big-endian, + * so must int and long be big-endian for us to generate the IS_BIG_ENDIAN + * #define and the IS_LITTLE_ENDIAN #undef. + */ + { + int big_endian = 0, little_endian = 0, ntests = 0; + + if (sizeof(short) == 2) { + /* force |volatile| here to get rid of any compiler optimisations + * (var in register etc.) which may be appiled to |auto| vars - + * even those in |union|s... + * (|static| is used to get the same functionality for compilers + * which do not honor |volatile|...). + */ + volatile static union { + short i; + char c[2]; + } u; + + u.i = 0x0102; + big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02); + little_endian += (u.c[0] == 0x02 && u.c[1] == 0x01); + ntests++; + } + + if (sizeof(int) == 4) { + /* force |volatile| here ... */ + volatile static union { + int i; + char c[4]; + } u; + + u.i = 0x01020304; + big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02 && + u.c[2] == 0x03 && u.c[3] == 0x04); + little_endian += (u.c[0] == 0x04 && u.c[1] == 0x03 && + u.c[2] == 0x02 && u.c[3] == 0x01); + ntests++; + } + + if (sizeof(long) == 8) { + /* force |volatile| here ... */ + volatile static union { + long i; + char c[8]; + } u; + + /* + * Write this as portably as possible: avoid 0x0102030405060708L + * and <<= 32. + */ + u.i = 0x01020304; + u.i <<= 16, u.i <<= 16; + u.i |= 0x05060708; + big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02 && + u.c[2] == 0x03 && u.c[3] == 0x04 && + u.c[4] == 0x05 && u.c[5] == 0x06 && + u.c[6] == 0x07 && u.c[7] == 0x08); + little_endian += (u.c[0] == 0x08 && u.c[1] == 0x07 && + u.c[2] == 0x06 && u.c[3] == 0x05 && + u.c[4] == 0x04 && u.c[5] == 0x03 && + u.c[6] == 0x02 && u.c[7] == 0x01); + ntests++; + } + + if (big_endian && big_endian == ntests) { + printf("#undef IS_LITTLE_ENDIAN\n"); + printf("#define IS_BIG_ENDIAN 1\n\n"); + } else if (little_endian && little_endian == ntests) { + printf("#define IS_LITTLE_ENDIAN 1\n"); + printf("#undef IS_BIG_ENDIAN\n\n"); + } else { + fprintf(stderr, "%s: unknown byte order" + "(big_endian=%d, little_endian=%d, ntests=%d)!\n", + argv[0], big_endian, little_endian, ntests); + return EXIT_FAILURE; + } + } + +#endif /* CROSS_COMPILE */ + + // PA-RISC is the only platform we try to support on which the stack + // grows towards higher addresses. Trying to detect it here has + // historically led to portability problems, which aren't worth it + // given the near consensus on stack growth direction. + printf("#ifdef __hppa\n" + "# define JS_STACK_GROWTH_DIRECTION (1)\n" + "#else\n" + "# define JS_STACK_GROWTH_DIRECTION (-1)\n" + "#endif\n"); + + printf("#endif /* js_cpucfg___ */\n"); + + return EXIT_SUCCESS; +} + diff --git a/js/src/jscpucfg.h b/js/src/jscpucfg.h new file mode 100644 index 0000000..c52a44b --- /dev/null +++ b/js/src/jscpucfg.h @@ -0,0 +1,91 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef js_cpucfg___ +#define js_cpucfg___ + +#define JS_HAVE_LONG_LONG + +#if defined(XP_WIN) || defined(XP_OS2) || defined(WINCE) + +#if defined(_WIN64) + +#if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define JS_BYTES_PER_DOUBLE 8L +#define JS_BYTES_PER_WORD 8L +#define JS_BITS_PER_WORD_LOG2 6 +#define JS_ALIGN_OF_POINTER 8L +#else /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */ +#error "CPU type is unknown" +#endif /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */ + +#elif defined(_WIN32) || defined(XP_OS2) || defined(WINCE) + +#ifdef __WATCOMC__ +#define HAVE_VA_LIST_AS_ARRAY 1 +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define JS_BYTES_PER_DOUBLE 8L +#define JS_BYTES_PER_WORD 4L +#define JS_BITS_PER_WORD_LOG2 5 +#define JS_ALIGN_OF_POINTER 4L + +#endif /* _WIN32 || XP_OS2 || WINCE*/ + +#elif defined(XP_UNIX) || defined(XP_BEOS) + +#error "This file is supposed to be auto-generated on UNIX platforms, but the" +#error "static version for Mac and Windows platforms is being used." +#error "Something's probably wrong with paths/headers/dependencies/Makefiles." + +#else + +#error "Must define one of XP_BEOS, XP_OS2, XP_WIN, or XP_UNIX" + +#endif + +#ifndef JS_STACK_GROWTH_DIRECTION +#define JS_STACK_GROWTH_DIRECTION (-1) +#endif + +#endif /* js_cpucfg___ */ diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp new file mode 100644 index 0000000..fc95ce8 --- /dev/null +++ b/js/src/jsdate.cpp @@ -0,0 +1,2742 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS date methods. + */ + +/* + * "For example, OS/360 devotes 26 bytes of the permanently + * resident date-turnover routine to the proper handling of + * December 31 on leap years (when it is Day 366). That + * might have been left to the operator." + * + * Frederick Brooks, 'The Second-System Effect'. + */ + +#include +#include +#include +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsprf.h" +#include "prmjtime.h" +#include "jsutil.h" +#include "jsapi.h" +#include "jsversion.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsdate.h" +#include "jsinterp.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsstr.h" + +#include "jsobjinlines.h" + +using namespace js; + +/* + * The JS 'Date' object is patterned after the Java 'Date' object. + * Here is an script: + * + * today = new Date(); + * + * print(today.toLocaleString()); + * + * weekDay = today.getDay(); + * + * + * These Java (and ECMA-262) methods are supported: + * + * UTC + * getDate (getUTCDate) + * getDay (getUTCDay) + * getHours (getUTCHours) + * getMinutes (getUTCMinutes) + * getMonth (getUTCMonth) + * getSeconds (getUTCSeconds) + * getMilliseconds (getUTCMilliseconds) + * getTime + * getTimezoneOffset + * getYear + * getFullYear (getUTCFullYear) + * parse + * setDate (setUTCDate) + * setHours (setUTCHours) + * setMinutes (setUTCMinutes) + * setMonth (setUTCMonth) + * setSeconds (setUTCSeconds) + * setMilliseconds (setUTCMilliseconds) + * setTime + * setYear (setFullYear, setUTCFullYear) + * toGMTString (toUTCString) + * toLocaleString + * toString + * + * + * These Java methods are not supported + * + * setDay + * before + * after + * equals + * hashCode + */ + +/* + * 11/97 - jsdate.c has been rewritten to conform to the ECMA-262 language + * definition and reduce dependence on NSPR. NSPR is used to get the current + * time in milliseconds, the time zone offset, and the daylight savings time + * offset for a given time. NSPR is also used for Date.toLocaleString(), for + * locale-specific formatting, and to get a string representing the timezone. + * (Which turns out to be platform-dependent.) + * + * To do: + * (I did some performance tests by timing how long it took to run what + * I had of the js ECMA conformance tests.) + * + * - look at saving results across multiple calls to supporting + * functions; the toString functions compute some of the same values + * multiple times. Although - I took a quick stab at this, and I lost + * rather than gained. (Fractionally.) Hard to tell what compilers/processors + * are doing these days. + * + * - look at tweaking function return types to return double instead + * of int; this seems to make things run slightly faster sometimes. + * (though it could be architecture-dependent.) It'd be good to see + * how this does on win32. (Tried it on irix.) Types could use a + * general going-over. + */ + +/* + * Supporting functions - ECMA 15.9.1.* + */ + +#define HoursPerDay 24.0 +#define MinutesPerDay (HoursPerDay * MinutesPerHour) +#define MinutesPerHour 60.0 +#define SecondsPerDay (MinutesPerDay * SecondsPerMinute) +#define SecondsPerHour (MinutesPerHour * SecondsPerMinute) +#define SecondsPerMinute 60.0 + +#if defined(XP_WIN) || defined(XP_OS2) +/* Work around msvc double optimization bug by making these runtime values; if + * they're available at compile time, msvc optimizes division by them by + * computing the reciprocal and multiplying instead of dividing - this loses + * when the reciprocal isn't representable in a double. + */ +static jsdouble msPerSecond = 1000.0; +static jsdouble msPerDay = SecondsPerDay * 1000.0; +static jsdouble msPerHour = SecondsPerHour * 1000.0; +static jsdouble msPerMinute = SecondsPerMinute * 1000.0; +#else +#define msPerDay (SecondsPerDay * msPerSecond) +#define msPerHour (SecondsPerHour * msPerSecond) +#define msPerMinute (SecondsPerMinute * msPerSecond) +#define msPerSecond 1000.0 +#endif + +#define Day(t) floor((t) / msPerDay) + +static jsdouble +TimeWithinDay(jsdouble t) +{ + jsdouble result; + result = fmod(t, msPerDay); + if (result < 0) + result += msPerDay; + return result; +} + +static inline bool +IsLeapYear(jsint year) +{ + return year % 4 == 0 && (year % 100 || (year % 400 == 0)); +} + +static inline jsint +DaysInYear(jsint year) +{ + return IsLeapYear(year) ? 366 : 365; +} + +static inline jsint +DaysInFebruary(jsint year) +{ + return IsLeapYear(year) ? 29 : 28; +} + +/* math here has to be f.p, because we need + * floor((1968 - 1969) / 4) == -1 + */ +#define DayFromYear(y) (365 * ((y)-1970) + floor(((y)-1969)/4.0) \ + - floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0)) +#define TimeFromYear(y) (DayFromYear(y) * msPerDay) + +static jsint +YearFromTime(jsdouble t) +{ + jsint y = (jsint) floor(t /(msPerDay*365.2425)) + 1970; + jsdouble t2 = (jsdouble) TimeFromYear(y); + + /* + * Adjust the year if the approximation was wrong. Since the year was + * computed using the average number of ms per year, it will usually + * be wrong for dates within several hours of a year transition. + */ + if (t2 > t) { + y--; + } else { + if (t2 + msPerDay * DaysInYear(y) <= t) + y++; + } + return y; +} + +#define DayWithinYear(t, year) ((intN) (Day(t) - DayFromYear(year))) + +/* + * The following array contains the day of year for the first day of + * each month, where index 0 is January, and day 0 is January 1. + */ +static jsdouble firstDayOfMonth[2][13] = { + {0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0, 365.0}, + {0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0, 366.0} +}; + +#define DayFromMonth(m, leap) firstDayOfMonth[leap][(intN)m] + +static intN +DaysInMonth(jsint year, jsint month) +{ + JSBool leap = IsLeapYear(year); + intN result = intN(DayFromMonth(month, leap) - DayFromMonth(month-1, leap)); + return result; +} + +static intN +MonthFromTime(jsdouble t) +{ + intN d, step; + jsint year = YearFromTime(t); + d = DayWithinYear(t, year); + + if (d < (step = 31)) + return 0; + if (d < (step += DaysInFebruary(year))) + return 1; + if (d < (step += 31)) + return 2; + if (d < (step += 30)) + return 3; + if (d < (step += 31)) + return 4; + if (d < (step += 30)) + return 5; + if (d < (step += 31)) + return 6; + if (d < (step += 31)) + return 7; + if (d < (step += 30)) + return 8; + if (d < (step += 31)) + return 9; + if (d < (step += 30)) + return 10; + return 11; +} + +static intN +DateFromTime(jsdouble t) +{ + intN d, step, next; + jsint year = YearFromTime(t); + d = DayWithinYear(t, year); + + if (d <= (next = 30)) + return d + 1; + step = next; + if (d <= (next += DaysInFebruary(year))) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 30)) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 30)) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 30)) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 30)) + return d - step; + step = next; + return d - step; +} + +static intN +WeekDay(jsdouble t) +{ + jsint result; + result = (jsint) Day(t) + 4; + result = result % 7; + if (result < 0) + result += 7; + return (intN) result; +} + +#define MakeTime(hour, min, sec, ms) \ +((((hour) * MinutesPerHour + (min)) * SecondsPerMinute + (sec)) * msPerSecond + (ms)) + +static jsdouble +MakeDay(jsdouble year, jsdouble month, jsdouble date) +{ + JSBool leap; + jsdouble yearday; + jsdouble monthday; + + year += floor(month / 12); + + month = fmod(month, 12.0); + if (month < 0) + month += 12; + + leap = IsLeapYear((jsint) year); + + yearday = floor(TimeFromYear(year) / msPerDay); + monthday = DayFromMonth(month, leap); + + return yearday + monthday + date - 1; +} + +#define MakeDate(day, time) ((day) * msPerDay + (time)) + +/* + * Years and leap years on which Jan 1 is a Sunday, Monday, etc. + * + * yearStartingWith[0][i] is an example non-leap year where + * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc. + * + * yearStartingWith[1][i] is an example leap year where + * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc. + */ +static jsint yearStartingWith[2][7] = { + {1978, 1973, 1974, 1975, 1981, 1971, 1977}, + {1984, 1996, 1980, 1992, 1976, 1988, 1972} +}; + +/* + * Find a year for which any given date will fall on the same weekday. + * + * This function should be used with caution when used other than + * for determining DST; it hasn't been proven not to produce an + * incorrect year for times near year boundaries. + */ +static jsint +EquivalentYearForDST(jsint year) +{ + jsint day; + + day = (jsint) DayFromYear(year) + 4; + day = day % 7; + if (day < 0) + day += 7; + + return yearStartingWith[IsLeapYear(year)][day]; +} + +/* LocalTZA gets set by js_InitDateClass() */ +static jsdouble LocalTZA; + +static jsdouble +DaylightSavingTA(jsdouble t, JSContext *cx) +{ + /* abort if NaN */ + if (JSDOUBLE_IS_NaN(t)) + return t; + + /* + * If earlier than 1970 or after 2038, potentially beyond the ken of + * many OSes, map it to an equivalent year before asking. + */ + if (t < 0.0 || t > 2145916800000.0) { + jsint year = EquivalentYearForDST(YearFromTime(t)); + jsdouble day = MakeDay(year, MonthFromTime(t), DateFromTime(t)); + t = MakeDate(day, TimeWithinDay(t)); + } + + int64 timeMilliseconds = static_cast(t); + int64 offsetMilliseconds = cx->dstOffsetCache.getDSTOffsetMilliseconds(timeMilliseconds, cx); + return static_cast(offsetMilliseconds); +} + +static jsdouble +AdjustTime(jsdouble date, JSContext *cx) +{ + jsdouble t = DaylightSavingTA(date, cx) + LocalTZA; + t = (LocalTZA >= 0) ? fmod(t, msPerDay) : -fmod(msPerDay - t, msPerDay); + return t; +} + +static jsdouble +LocalTime(jsdouble t, JSContext *cx) +{ + return t + AdjustTime(t, cx); +} + +static jsdouble +UTC(jsdouble t, JSContext *cx) +{ + return t - AdjustTime(t - LocalTZA, cx); +} + +static intN +HourFromTime(jsdouble t) +{ + intN result = (intN) fmod(floor(t/msPerHour), HoursPerDay); + if (result < 0) + result += (intN)HoursPerDay; + return result; +} + +static intN +MinFromTime(jsdouble t) +{ + intN result = (intN) fmod(floor(t / msPerMinute), MinutesPerHour); + if (result < 0) + result += (intN)MinutesPerHour; + return result; +} + +static intN +SecFromTime(jsdouble t) +{ + intN result = (intN) fmod(floor(t / msPerSecond), SecondsPerMinute); + if (result < 0) + result += (intN)SecondsPerMinute; + return result; +} + +static intN +msFromTime(jsdouble t) +{ + intN result = (intN) fmod(t, msPerSecond); + if (result < 0) + result += (intN)msPerSecond; + return result; +} + +/** + * end of ECMA 'support' functions + */ + +/* + * Other Support routines and definitions + */ + +Class js_DateClass = { + js_Date_str, + JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_CLASS_RESERVED_SLOTS) | + JSCLASS_HAS_CACHED_PROTO(JSProto_Date), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub +}; + +/* for use by date_parse */ + +static const char* wtb[] = { + "am", "pm", + "monday", "tuesday", "wednesday", "thursday", "friday", + "saturday", "sunday", + "january", "february", "march", "april", "may", "june", + "july", "august", "september", "october", "november", "december", + "gmt", "ut", "utc", + "est", "edt", + "cst", "cdt", + "mst", "mdt", + "pst", "pdt" + /* time zone table needs to be expanded */ +}; + +static int ttb[] = { + -1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */ + 10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */ + 10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */ + 10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */ + 10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */ +}; + +/* helper for date_parse */ +static JSBool +date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off, + int count, int ignoreCase) +{ + JSBool result = JS_FALSE; + /* return true if matches, otherwise, false */ + + while (count > 0 && s1[s1off] && s2[s2off]) { + if (ignoreCase) { + if (JS_TOLOWER((jschar)s1[s1off]) != JS_TOLOWER(s2[s2off])) { + break; + } + } else { + if ((jschar)s1[s1off] != s2[s2off]) { + break; + } + } + s1off++; + s2off++; + count--; + } + + if (count == 0) { + result = JS_TRUE; + } + + return result; +} + +/* find UTC time from given date... no 1900 correction! */ +static jsdouble +date_msecFromDate(jsdouble year, jsdouble mon, jsdouble mday, jsdouble hour, + jsdouble min, jsdouble sec, jsdouble msec) +{ + jsdouble day; + jsdouble msec_time; + jsdouble result; + + day = MakeDay(year, mon, mday); + msec_time = MakeTime(hour, min, sec, msec); + result = MakeDate(day, msec_time); + return result; +} + +/* compute the time in msec (unclipped) from the given args */ +#define MAXARGS 7 + +static JSBool +date_msecFromArgs(JSContext *cx, uintN argc, Value *argv, jsdouble *rval) +{ + uintN loop; + jsdouble array[MAXARGS]; + jsdouble msec_time; + + for (loop = 0; loop < MAXARGS; loop++) { + if (loop < argc) { + jsdouble d; + if (!ValueToNumber(cx, argv[loop], &d)) + return JS_FALSE; + /* return NaN if any arg is not finite */ + if (!JSDOUBLE_IS_FINITE(d)) { + *rval = js_NaN; + return JS_TRUE; + } + array[loop] = js_DoubleToInteger(d); + } else { + if (loop == 2) { + array[loop] = 1; /* Default the date argument to 1. */ + } else { + array[loop] = 0; + } + } + } + + /* adjust 2-digit years into the 20th century */ + if (array[0] >= 0 && array[0] <= 99) + array[0] += 1900; + + msec_time = date_msecFromDate(array[0], array[1], array[2], + array[3], array[4], array[5], array[6]); + *rval = msec_time; + return JS_TRUE; +} + +/* + * See ECMA 15.9.4.[3-10]; + */ +static JSBool +date_UTC(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble msec_time; + + if (!date_msecFromArgs(cx, argc, vp + 2, &msec_time)) + return JS_FALSE; + + msec_time = TIMECLIP(msec_time); + + vp->setNumber(msec_time); + return JS_TRUE; +} + +/* + * Read and convert decimal digits from s[*i] into *result + * while *i < limit. + * + * Succeed if any digits are converted. Advance *i only + * as digits are consumed. + */ +static JSBool +digits(size_t *result, const jschar *s, size_t *i, size_t limit) +{ + size_t init = *i; + *result = 0; + while (*i < limit && + ('0' <= s[*i] && s[*i] <= '9')) { + *result *= 10; + *result += (s[*i] - '0'); + ++(*i); + } + return (*i != init); +} + +/* + * Read and convert decimal digits to the right of a decimal point, + * representing a fractional integer, from s[*i] into *result + * while *i < limit. + * + * Succeed if any digits are converted. Advance *i only + * as digits are consumed. + */ +static JSBool +fractional(jsdouble *result, const jschar *s, size_t *i, size_t limit) +{ + jsdouble factor = 0.1; + size_t init = *i; + *result = 0.0; + while (*i < limit && + ('0' <= s[*i] && s[*i] <= '9')) { + *result += (s[*i] - '0') * factor; + factor *= 0.1; + ++(*i); + } + return (*i != init); +} + +/* + * Read and convert exactly n decimal digits from s[*i] + * to s[min(*i+n,limit)] into *result. + * + * Succeed if exactly n digits are converted. Advance *i only + * on success. + */ +static JSBool +ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit) +{ + size_t init = *i; + + if (digits(result, s, i, JS_MIN(limit, init+n))) + return ((*i - init) == n); + + *i = init; + return JS_FALSE; +} + +/* + * Parse a string in one of the date-time formats given by the W3C + * "NOTE-datetime" specification. These formats make up a restricted + * profile of the ISO 8601 format. Quoted here: + * + * The formats are as follows. Exactly the components shown here + * must be present, with exactly this punctuation. Note that the "T" + * appears literally in the string, to indicate the beginning of the + * time element, as specified in ISO 8601. + * + * Any combination of the date formats with the time formats is + * allowed, and also either the date or the time can be missing. + * + * The specification is silent on the meaning when fields are + * ommitted so the interpretations are a guess, but hopefully a + * reasonable one. We default the month to January, the day to the + * 1st, and hours minutes and seconds all to 0. If the date is + * missing entirely then we assume 1970-01-01 so that the time can + * be aded to a date later. If the time is missing then we assume + * 00:00 UTC. If the time is present but the time zone field is + * missing then we use local time. + * + * Date part: + * + * Year: + * YYYY (eg 1997) + * + * Year and month: + * YYYY-MM (eg 1997-07) + * + * Complete date: + * YYYY-MM-DD (eg 1997-07-16) + * + * Time part: + * + * Hours and minutes: + * Thh:mmTZD (eg T19:20+01:00) + * + * Hours, minutes and seconds: + * Thh:mm:ssTZD (eg T19:20:30+01:00) + * + * Hours, minutes, seconds and a decimal fraction of a second: + * Thh:mm:ss.sTZD (eg T19:20:30.45+01:00) + * + * where: + * + * YYYY = four-digit year or six digit year as +YYYYYY or -YYYYYY + * MM = two-digit month (01=January, etc.) + * DD = two-digit day of month (01 through 31) + * hh = two digits of hour (00 through 23) (am/pm NOT allowed) + * mm = two digits of minute (00 through 59) + * ss = two digits of second (00 through 59) + * s = one or more digits representing a decimal fraction of a second + * TZD = time zone designator (Z or +hh:mm or -hh:mm or missing for local) + */ + +static JSBool +date_parseISOString(JSLinearString *str, jsdouble *result, JSContext *cx) +{ + jsdouble msec; + + const jschar *s; + size_t limit; + size_t i = 0; + int tzMul = 1; + int dateMul = 1; + size_t year = 1970; + size_t month = 1; + size_t day = 1; + size_t hour = 0; + size_t min = 0; + size_t sec = 0; + jsdouble frac = 0; + bool isLocalTime = JS_FALSE; + size_t tzHour = 0; + size_t tzMin = 0; + +#define PEEK(ch) (i < limit && s[i] == ch) + +#define NEED(ch) \ + JS_BEGIN_MACRO \ + if (i >= limit || s[i] != ch) { goto syntax; } else { ++i; } \ + JS_END_MACRO + +#define DONE_DATE_UNLESS(ch) \ + JS_BEGIN_MACRO \ + if (i >= limit || s[i] != ch) { goto done_date; } else { ++i; } \ + JS_END_MACRO + +#define DONE_UNLESS(ch) \ + JS_BEGIN_MACRO \ + if (i >= limit || s[i] != ch) { goto done; } else { ++i; } \ + JS_END_MACRO + +#define NEED_NDIGITS(n, field) \ + JS_BEGIN_MACRO \ + if (!ndigits(n, &field, s, &i, limit)) { goto syntax; } \ + JS_END_MACRO + + s = str->chars(); + limit = str->length(); + + if (PEEK('+') || PEEK('-')) { + if (PEEK('-')) + dateMul = -1; + ++i; + NEED_NDIGITS(6, year); + } else if (!PEEK('T')) { + NEED_NDIGITS(4, year); + } + DONE_DATE_UNLESS('-'); + NEED_NDIGITS(2, month); + DONE_DATE_UNLESS('-'); + NEED_NDIGITS(2, day); + + done_date: + DONE_UNLESS('T'); + NEED_NDIGITS(2, hour); + NEED(':'); + NEED_NDIGITS(2, min); + + if (PEEK(':')) { + ++i; + NEED_NDIGITS(2, sec); + if (PEEK('.')) { + ++i; + if (!fractional(&frac, s, &i, limit)) + goto syntax; + } + } + + if (PEEK('Z')) { + ++i; + } else if (PEEK('+') || PEEK('-')) { + if (PEEK('-')) + tzMul = -1; + ++i; + NEED_NDIGITS(2, tzHour); + NEED(':'); + NEED_NDIGITS(2, tzMin); + } else { + isLocalTime = JS_TRUE; + } + + done: + if (year > 275943 // ceil(1e8/365) + 1970 + || (month == 0 || month > 12) + || (day == 0 || day > size_t(DaysInMonth(year,month))) + || hour > 24 + || ((hour == 24) && (min > 0 || sec > 0)) + || min > 59 + || sec > 59 + || tzHour > 23 + || tzMin > 59) + goto syntax; + + if (i != limit) + goto syntax; + + month -= 1; /* convert month to 0-based */ + + msec = date_msecFromDate(dateMul * (jsdouble)year, month, day, + hour, min, sec, + frac * 1000.0);; + + if (isLocalTime) { + msec = UTC(msec, cx); + } else { + msec -= ((tzMul) * ((tzHour * msPerHour) + + (tzMin * msPerMinute))); + } + + if (msec < -8.64e15 || msec > 8.64e15) + goto syntax; + + *result = msec; + + return JS_TRUE; + + syntax: + /* syntax error */ + *result = 0; + return JS_FALSE; + +#undef PEEK +#undef NEED +#undef DONE_UNLESS +#undef NEED_NDIGITS +} + +static JSBool +date_parseString(JSLinearString *str, jsdouble *result, JSContext *cx) +{ + jsdouble msec; + + const jschar *s; + size_t limit; + size_t i = 0; + int year = -1; + int mon = -1; + int mday = -1; + int hour = -1; + int min = -1; + int sec = -1; + int c = -1; + int n = -1; + int tzoffset = -1; + int prevc = 0; + JSBool seenplusminus = JS_FALSE; + int temp; + JSBool seenmonthname = JS_FALSE; + + if (date_parseISOString(str, result, cx)) + return JS_TRUE; + + s = str->chars(); + limit = str->length(); + if (limit == 0) + goto syntax; + while (i < limit) { + c = s[i]; + i++; + if (c <= ' ' || c == ',' || c == '-') { + if (c == '-' && '0' <= s[i] && s[i] <= '9') { + prevc = c; + } + continue; + } + if (c == '(') { /* comments) */ + int depth = 1; + while (i < limit) { + c = s[i]; + i++; + if (c == '(') depth++; + else if (c == ')') + if (--depth <= 0) + break; + } + continue; + } + if ('0' <= c && c <= '9') { + n = c - '0'; + while (i < limit && '0' <= (c = s[i]) && c <= '9') { + n = n * 10 + c - '0'; + i++; + } + + /* allow TZA before the year, so + * 'Wed Nov 05 21:49:11 GMT-0800 1997' + * works */ + + /* uses of seenplusminus allow : in TZA, so Java + * no-timezone style of GMT+4:30 works + */ + + if ((prevc == '+' || prevc == '-')/* && year>=0 */) { + /* make ':' case below change tzoffset */ + seenplusminus = JS_TRUE; + + /* offset */ + if (n < 24) + n = n * 60; /* EG. "GMT-3" */ + else + n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */ + if (prevc == '+') /* plus means east of GMT */ + n = -n; + if (tzoffset != 0 && tzoffset != -1) + goto syntax; + tzoffset = n; + } else if (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) { + if (c <= ' ' || c == ',' || c == '/' || i >= limit) + year = n; + else + goto syntax; + } else if (c == ':') { + if (hour < 0) + hour = /*byte*/ n; + else if (min < 0) + min = /*byte*/ n; + else + goto syntax; + } else if (c == '/') { + /* until it is determined that mon is the actual + month, keep it as 1-based rather than 0-based */ + if (mon < 0) + mon = /*byte*/ n; + else if (mday < 0) + mday = /*byte*/ n; + else + goto syntax; + } else if (i < limit && c != ',' && c > ' ' && c != '-' && c != '(') { + goto syntax; + } else if (seenplusminus && n < 60) { /* handle GMT-3:30 */ + if (tzoffset < 0) + tzoffset -= n; + else + tzoffset += n; + } else if (hour >= 0 && min < 0) { + min = /*byte*/ n; + } else if (prevc == ':' && min >= 0 && sec < 0) { + sec = /*byte*/ n; + } else if (mon < 0) { + mon = /*byte*/n; + } else if (mon >= 0 && mday < 0) { + mday = /*byte*/ n; + } else if (mon >= 0 && mday >= 0 && year < 0) { + year = n; + } else { + goto syntax; + } + prevc = 0; + } else if (c == '/' || c == ':' || c == '+' || c == '-') { + prevc = c; + } else { + size_t st = i - 1; + int k; + while (i < limit) { + c = s[i]; + if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))) + break; + i++; + } + if (i <= st + 1) + goto syntax; + for (k = JS_ARRAY_LENGTH(wtb); --k >= 0;) + if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) { + int action = ttb[k]; + if (action != 0) { + if (action < 0) { + /* + * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as + * 12:30, instead of blindly adding 12 if PM. + */ + JS_ASSERT(action == -1 || action == -2); + if (hour > 12 || hour < 0) { + goto syntax; + } else { + if (action == -1 && hour == 12) { /* am */ + hour = 0; + } else if (action == -2 && hour != 12) { /* pm */ + hour += 12; + } + } + } else if (action <= 13) { /* month! */ + /* Adjust mon to be 1-based until the final values + for mon, mday and year are adjusted below */ + if (seenmonthname) { + goto syntax; + } + seenmonthname = JS_TRUE; + temp = /*byte*/ (action - 2) + 1; + + if (mon < 0) { + mon = temp; + } else if (mday < 0) { + mday = mon; + mon = temp; + } else if (year < 0) { + year = mon; + mon = temp; + } else { + goto syntax; + } + } else { + tzoffset = action - 10000; + } + } + break; + } + if (k < 0) + goto syntax; + prevc = 0; + } + } + if (year < 0 || mon < 0 || mday < 0) + goto syntax; + /* + Case 1. The input string contains an English month name. + The form of the string can be month f l, or f month l, or + f l month which each evaluate to the same date. + If f and l are both greater than or equal to 70, or + both less than 70, the date is invalid. + The year is taken to be the greater of the values f, l. + If the year is greater than or equal to 70 and less than 100, + it is considered to be the number of years after 1900. + Case 2. The input string is of the form "f/m/l" where f, m and l are + integers, e.g. 7/16/45. + Adjust the mon, mday and year values to achieve 100% MSIE + compatibility. + a. If 0 <= f < 70, f/m/l is interpreted as month/day/year. + i. If year < 100, it is the number of years after 1900 + ii. If year >= 100, it is the number of years after 0. + b. If 70 <= f < 100 + i. If m < 70, f/m/l is interpreted as + year/month/day where year is the number of years after + 1900. + ii. If m >= 70, the date is invalid. + c. If f >= 100 + i. If m < 70, f/m/l is interpreted as + year/month/day where year is the number of years after 0. + ii. If m >= 70, the date is invalid. + */ + if (seenmonthname) { + if ((mday >= 70 && year >= 70) || (mday < 70 && year < 70)) { + goto syntax; + } + if (mday > year) { + temp = year; + year = mday; + mday = temp; + } + if (year >= 70 && year < 100) { + year += 1900; + } + } else if (mon < 70) { /* (a) month/day/year */ + if (year < 100) { + year += 1900; + } + } else if (mon < 100) { /* (b) year/month/day */ + if (mday < 70) { + temp = year; + year = mon + 1900; + mon = mday; + mday = temp; + } else { + goto syntax; + } + } else { /* (c) year/month/day */ + if (mday < 70) { + temp = year; + year = mon; + mon = mday; + mday = temp; + } else { + goto syntax; + } + } + mon -= 1; /* convert month to 0-based */ + if (sec < 0) + sec = 0; + if (min < 0) + min = 0; + if (hour < 0) + hour = 0; + + msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0); + + if (tzoffset == -1) { /* no time zone specified, have to use local */ + msec = UTC(msec, cx); + } else { + msec += tzoffset * msPerMinute; + } + + *result = msec; + return JS_TRUE; + +syntax: + /* syntax error */ + *result = 0; + return JS_FALSE; +} + +static JSBool +date_parse(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str; + jsdouble result; + + if (argc == 0) { + vp->setDouble(js_NaN); + return true; + } + str = js_ValueToString(cx, vp[2]); + if (!str) + return JS_FALSE; + vp[2].setString(str); + JSLinearString *linearStr = str->ensureLinear(cx); + if (!linearStr) + return false; + + if (!date_parseString(linearStr, &result, cx)) { + vp->setDouble(js_NaN); + return true; + } + + result = TIMECLIP(result); + vp->setNumber(result); + return true; +} + +static inline jsdouble +NowAsMillis() +{ + return (jsdouble) (PRMJ_Now() / PRMJ_USEC_PER_MSEC); +} + +static JSBool +date_now(JSContext *cx, uintN argc, Value *vp) +{ + vp->setDouble(NowAsMillis()); + return JS_TRUE; +} + +#ifdef JS_TRACER +static jsdouble FASTCALL +date_now_tn(JSContext*) +{ + return NowAsMillis(); +} +#endif + +/* + * Get UTC time from the date object. Returns false if the object is not + * Date type. + */ +static JSBool +GetUTCTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *dp) +{ + if (!InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL)) + return JS_FALSE; + *dp = obj->getDateUTCTime().toNumber(); + return JS_TRUE; +} + +/* + * Set UTC time to a given time and invalidate cached local time. + */ +static JSBool +SetUTCTime(JSContext *cx, JSObject *obj, jsdouble t, Value *vp = NULL) +{ + JS_ASSERT(obj->isDate()); + + size_t slotCap = JS_MIN(obj->numSlots(), JSObject::DATE_CLASS_RESERVED_SLOTS); + for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START; ind < slotCap; ind++) + obj->getSlotRef(ind).setUndefined(); + + obj->setDateUTCTime(DoubleValue(t)); + if (vp) + vp->setDouble(t); + return true; +} + +static void +SetDateToNaN(JSContext *cx, JSObject *obj, Value *vp = NULL) +{ + jsdouble NaN = cx->runtime->NaNValue.getDoubleRef(); + SetUTCTime(cx, obj, NaN, vp); +} + +/* + * Cache the local time, year, month, and so forth of the object. + * If UTC time is not finite (e.g., NaN), the local time + * slots will be set to the UTC time without conversion. + */ +static bool +FillLocalTimes(JSContext *cx, JSObject *obj) +{ + JS_ASSERT(obj->isDate()); + + jsdouble utcTime = obj->getDateUTCTime().toNumber(); + + /* Make sure there are slots to store the cached information. */ + if (obj->numSlots() < JSObject::DATE_CLASS_RESERVED_SLOTS) { + if (!obj->growSlots(cx, JSObject::DATE_CLASS_RESERVED_SLOTS)) + return false; + } + + if (!JSDOUBLE_IS_FINITE(utcTime)) { + for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START; + ind < JSObject::DATE_CLASS_RESERVED_SLOTS; + ind++) { + obj->setSlot(ind, DoubleValue(utcTime)); + } + return true; + } + + jsdouble localTime = LocalTime(utcTime, cx); + + obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_TIME, DoubleValue(localTime)); + + jsint year = (jsint) floor(localTime /(msPerDay*365.2425)) + 1970; + jsdouble yearStartTime = (jsdouble) TimeFromYear(year); + + /* Adjust the year in case the approximation was wrong, as in YearFromTime. */ + jsint yearDays; + if (yearStartTime > localTime) { + year--; + yearStartTime -= (msPerDay * DaysInYear(year)); + yearDays = DaysInYear(year); + } else { + yearDays = DaysInYear(year); + jsdouble nextStart = yearStartTime + (msPerDay * yearDays); + if (nextStart <= localTime) { + year++; + yearStartTime = nextStart; + yearDays = DaysInYear(year); + } + } + + obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR, Int32Value(year)); + + uint64 yearTime = uint64(localTime - yearStartTime); + jsint yearSeconds = uint32(yearTime / 1000); + + jsint day = yearSeconds / jsint(SecondsPerDay); + + jsint step = -1, next = 30; + jsint month; + + do { + if (day <= next) { + month = 0; + break; + } + step = next; + next += ((yearDays == 366) ? 29 : 28); + if (day <= next) { + month = 1; + break; + } + step = next; + if (day <= (next += 31)) { + month = 2; + break; + } + step = next; + if (day <= (next += 30)) { + month = 3; + break; + } + step = next; + if (day <= (next += 31)) { + month = 4; + break; + } + step = next; + if (day <= (next += 30)) { + month = 5; + break; + } + step = next; + if (day <= (next += 31)) { + month = 6; + break; + } + step = next; + if (day <= (next += 31)) { + month = 7; + break; + } + step = next; + if (day <= (next += 30)) { + month = 8; + break; + } + step = next; + if (day <= (next += 31)) { + month = 9; + break; + } + step = next; + if (day <= (next += 30)) { + month = 10; + break; + } + step = next; + month = 11; + } while (0); + + obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH, Int32Value(month)); + obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DATE, Int32Value(day - step)); + + jsint weekday = WeekDay(localTime); + + obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_DAY, Int32Value(weekday)); + + jsint seconds = yearSeconds % 60; + + obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS, Int32Value(seconds)); + + jsint minutes = (yearSeconds / 60) % 60; + + obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES, Int32Value(minutes)); + + jsint hours = (yearSeconds / (60 * 60)) % 24; + + obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS, Int32Value(hours)); + + return true; +} + +/* Cache the local times in obj, if necessary. */ +static inline JSBool +GetAndCacheLocalTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *time = NULL) +{ + if (!obj || !InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL)) + return false; + + /* If the local time is undefined, we need to fill in the cached values. */ + if (obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).isUndefined()) { + if (!FillLocalTimes(cx, obj)) + return false; + } + + if (time) + *time = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).toDouble(); + + return true; +} + +static inline bool +GetThisUTCTime(JSContext *cx, Value *vp, jsdouble *dp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + return GetUTCTime(cx, obj, vp, dp); +} + +/* + * See ECMA 15.9.5.4 thru 15.9.5.23 + */ +static JSBool +date_getTime(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble result; + if (!GetThisUTCTime(cx, vp, &result)) + return false; + vp->setNumber(result); + return true; +} + +static JSBool +date_getYear(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!GetAndCacheLocalTime(cx, obj, vp)) + return false; + + Value yearVal = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR); + if (yearVal.isInt32()) { + /* Follow ECMA-262 to the letter, contrary to IE JScript. */ + jsint year = yearVal.toInt32() - 1900; + vp->setInt32(year); + } else { + *vp = yearVal; + } + + return true; +} + +static JSBool +date_getFullYear(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!GetAndCacheLocalTime(cx, obj, vp)) + return JS_FALSE; + + *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR); + return JS_TRUE; +} + +static JSBool +date_getUTCFullYear(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble result; + if (!GetThisUTCTime(cx, vp, &result)) + return false; + + if (JSDOUBLE_IS_FINITE(result)) + result = YearFromTime(result); + + vp->setNumber(result); + return true; +} + +static JSBool +date_getMonth(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!GetAndCacheLocalTime(cx, obj, vp)) + return false; + + *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH); + return true; +} + +static JSBool +date_getUTCMonth(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble result; + if (!GetThisUTCTime(cx, vp, &result)) + return false; + + if (JSDOUBLE_IS_FINITE(result)) + result = MonthFromTime(result); + + vp->setNumber(result); + return true; +} + +static JSBool +date_getDate(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!GetAndCacheLocalTime(cx, obj, vp)) + return false; + + *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE); + return true; +} + +static JSBool +date_getUTCDate(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble result; + if (!GetThisUTCTime(cx, vp, &result)) + return false; + + if (JSDOUBLE_IS_FINITE(result)) + result = DateFromTime(result); + + vp->setNumber(result); + return true; +} + +static JSBool +date_getDay(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!GetAndCacheLocalTime(cx, obj, vp)) + return false; + + *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY); + return true; +} + +static JSBool +date_getUTCDay(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble result; + if (!GetThisUTCTime(cx, vp, &result)) + return false; + + if (JSDOUBLE_IS_FINITE(result)) + result = WeekDay(result); + + vp->setNumber(result); + return true; +} + +static JSBool +date_getHours(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!GetAndCacheLocalTime(cx, obj, vp)) + return false; + + *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS); + return true; +} + +static JSBool +date_getUTCHours(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble result; + if (!GetThisUTCTime(cx, vp, &result)) + return false; + + if (JSDOUBLE_IS_FINITE(result)) + result = HourFromTime(result); + + vp->setNumber(result); + return JS_TRUE; +} + +static JSBool +date_getMinutes(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!GetAndCacheLocalTime(cx, obj, vp)) + return false; + + *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES); + return true; +} + +static JSBool +date_getUTCMinutes(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble result; + if (!GetThisUTCTime(cx, vp, &result)) + return false; + + if (JSDOUBLE_IS_FINITE(result)) + result = MinFromTime(result); + + vp->setNumber(result); + return true; +} + +/* Date.getSeconds is mapped to getUTCSeconds */ + +static JSBool +date_getUTCSeconds(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!GetAndCacheLocalTime(cx, obj, vp)) + return false; + + *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS); + return true; +} + +/* Date.getMilliseconds is mapped to getUTCMilliseconds */ + +static JSBool +date_getUTCMilliseconds(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble result; + if (!GetThisUTCTime(cx, vp, &result)) + return false; + + if (JSDOUBLE_IS_FINITE(result)) + result = msFromTime(result); + + vp->setNumber(result); + return true; +} + +static JSBool +date_getTimezoneOffset(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + jsdouble utctime; + if (!GetUTCTime(cx, obj, vp, &utctime)) + return false; + + jsdouble localtime; + if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime)) + return false; + + /* + * Return the time zone offset in minutes for the current locale that is + * appropriate for this time. This value would be a constant except for + * daylight savings time. + */ + jsdouble result = (utctime - localtime) / msPerMinute; + vp->setNumber(result); + return true; +} + +static JSBool +date_setTime(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!InstanceOf(cx, obj, &js_DateClass, vp + 2)) + return false; + + if (argc == 0) { + SetDateToNaN(cx, obj, vp); + return true; + } + + jsdouble result; + if (!ValueToNumber(cx, vp[2], &result)) + return false; + + return SetUTCTime(cx, obj, TIMECLIP(result), vp); +} + +static JSBool +date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, Value *vp) +{ + Value *argv; + uintN i; + jsdouble args[4], *argp, *stop; + jsdouble hour, min, sec, msec; + jsdouble lorutime; /* Local or UTC version of *date */ + + jsdouble msec_time; + jsdouble result; + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!GetUTCTime(cx, obj, vp, &result)) + return false; + + /* just return NaN if the date is already NaN */ + if (!JSDOUBLE_IS_FINITE(result)) { + vp->setNumber(result); + return true; + } + + /* + * Satisfy the ECMA rule that if a function is called with + * fewer arguments than the specified formal arguments, the + * remaining arguments are set to undefined. Seems like all + * the Date.setWhatever functions in ECMA are only varargs + * beyond the first argument; this should be set to undefined + * if it's not given. This means that "d = new Date(); + * d.setMilliseconds()" returns NaN. Blech. + */ + if (argc == 0) { + SetDateToNaN(cx, obj, vp); + return true; + } + if (argc > maxargs) + argc = maxargs; /* clamp argc */ + JS_ASSERT(argc <= 4); + + argv = vp + 2; + for (i = 0; i < argc; i++) { + if (!ValueToNumber(cx, argv[i], &args[i])) + return false; + if (!JSDOUBLE_IS_FINITE(args[i])) { + SetDateToNaN(cx, obj, vp); + return true; + } + args[i] = js_DoubleToInteger(args[i]); + } + + if (local) + lorutime = LocalTime(result, cx); + else + lorutime = result; + + argp = args; + stop = argp + argc; + if (maxargs >= 4 && argp < stop) + hour = *argp++; + else + hour = HourFromTime(lorutime); + + if (maxargs >= 3 && argp < stop) + min = *argp++; + else + min = MinFromTime(lorutime); + + if (maxargs >= 2 && argp < stop) + sec = *argp++; + else + sec = SecFromTime(lorutime); + + if (maxargs >= 1 && argp < stop) + msec = *argp; + else + msec = msFromTime(lorutime); + + msec_time = MakeTime(hour, min, sec, msec); + result = MakeDate(Day(lorutime), msec_time); + +/* fprintf(stderr, "%f\n", result); */ + + if (local) + result = UTC(result, cx); + +/* fprintf(stderr, "%f\n", result); */ + + return SetUTCTime(cx, obj, TIMECLIP(result), vp); +} + +static JSBool +date_setMilliseconds(JSContext *cx, uintN argc, Value *vp) +{ + return date_makeTime(cx, 1, JS_TRUE, argc, vp); +} + +static JSBool +date_setUTCMilliseconds(JSContext *cx, uintN argc, Value *vp) +{ + return date_makeTime(cx, 1, JS_FALSE, argc, vp); +} + +static JSBool +date_setSeconds(JSContext *cx, uintN argc, Value *vp) +{ + return date_makeTime(cx, 2, JS_TRUE, argc, vp); +} + +static JSBool +date_setUTCSeconds(JSContext *cx, uintN argc, Value *vp) +{ + return date_makeTime(cx, 2, JS_FALSE, argc, vp); +} + +static JSBool +date_setMinutes(JSContext *cx, uintN argc, Value *vp) +{ + return date_makeTime(cx, 3, JS_TRUE, argc, vp); +} + +static JSBool +date_setUTCMinutes(JSContext *cx, uintN argc, Value *vp) +{ + return date_makeTime(cx, 3, JS_FALSE, argc, vp); +} + +static JSBool +date_setHours(JSContext *cx, uintN argc, Value *vp) +{ + return date_makeTime(cx, 4, JS_TRUE, argc, vp); +} + +static JSBool +date_setUTCHours(JSContext *cx, uintN argc, Value *vp) +{ + return date_makeTime(cx, 4, JS_FALSE, argc, vp); +} + +static JSBool +date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, Value *vp) +{ + Value *argv; + uintN i; + jsdouble lorutime; /* local or UTC version of *date */ + jsdouble args[3], *argp, *stop; + jsdouble year, month, day; + jsdouble result; + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!GetUTCTime(cx, obj, vp, &result)) + return false; + + /* see complaint about ECMA in date_MakeTime */ + if (argc == 0) { + SetDateToNaN(cx, obj, vp); + return true; + } + if (argc > maxargs) + argc = maxargs; /* clamp argc */ + JS_ASSERT(1 <= argc && argc <= 3); + + argv = vp + 2; + for (i = 0; i < argc; i++) { + if (!ValueToNumber(cx, argv[i], &args[i])) + return JS_FALSE; + if (!JSDOUBLE_IS_FINITE(args[i])) { + SetDateToNaN(cx, obj, vp); + return true; + } + args[i] = js_DoubleToInteger(args[i]); + } + + /* return NaN if date is NaN and we're not setting the year, + * If we are, use 0 as the time. */ + if (!(JSDOUBLE_IS_FINITE(result))) { + if (maxargs < 3) { + vp->setDouble(result); + return true; + } + lorutime = +0.; + } else { + lorutime = local ? LocalTime(result, cx) : result; + } + + argp = args; + stop = argp + argc; + if (maxargs >= 3 && argp < stop) + year = *argp++; + else + year = YearFromTime(lorutime); + + if (maxargs >= 2 && argp < stop) + month = *argp++; + else + month = MonthFromTime(lorutime); + + if (maxargs >= 1 && argp < stop) + day = *argp++; + else + day = DateFromTime(lorutime); + + day = MakeDay(year, month, day); /* day within year */ + result = MakeDate(day, TimeWithinDay(lorutime)); + + if (local) + result = UTC(result, cx); + + return SetUTCTime(cx, obj, TIMECLIP(result), vp); +} + +static JSBool +date_setDate(JSContext *cx, uintN argc, Value *vp) +{ + return date_makeDate(cx, 1, JS_TRUE, argc, vp); +} + +static JSBool +date_setUTCDate(JSContext *cx, uintN argc, Value *vp) +{ + return date_makeDate(cx, 1, JS_FALSE, argc, vp); +} + +static JSBool +date_setMonth(JSContext *cx, uintN argc, Value *vp) +{ + return date_makeDate(cx, 2, JS_TRUE, argc, vp); +} + +static JSBool +date_setUTCMonth(JSContext *cx, uintN argc, Value *vp) +{ + return date_makeDate(cx, 2, JS_FALSE, argc, vp); +} + +static JSBool +date_setFullYear(JSContext *cx, uintN argc, Value *vp) +{ + return date_makeDate(cx, 3, JS_TRUE, argc, vp); +} + +static JSBool +date_setUTCFullYear(JSContext *cx, uintN argc, Value *vp) +{ + return date_makeDate(cx, 3, JS_FALSE, argc, vp); +} + +static JSBool +date_setYear(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + jsdouble result; + if (!GetUTCTime(cx, obj, vp, &result)) + return false; + + if (argc == 0) { + /* Call this only after GetUTCTime has verified that obj is Date. */ + SetDateToNaN(cx, obj, vp); + return true; + } + + jsdouble year; + if (!ValueToNumber(cx, vp[2], &year)) + return false; + if (!JSDOUBLE_IS_FINITE(year)) { + SetDateToNaN(cx, obj, vp); + return true; + } + year = js_DoubleToInteger(year); + if (year >= 0 && year <= 99) + year += 1900; + + jsdouble t = JSDOUBLE_IS_FINITE(result) ? LocalTime(result, cx) : +0.0; + jsdouble day = MakeDay(year, MonthFromTime(t), DateFromTime(t)); + result = MakeDate(day, TimeWithinDay(t)); + result = UTC(result, cx); + + return SetUTCTime(cx, obj, TIMECLIP(result), vp); +} + +/* constants for toString, toUTCString */ +static char js_NaN_date_str[] = "Invalid Date"; +static const char* days[] = +{ + "Sun","Mon","Tue","Wed","Thu","Fri","Sat" +}; +static const char* months[] = +{ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + + +// Avoid dependence on PRMJ_FormatTimeUSEnglish, because it +// requires a PRMJTime... which only has 16-bit years. Sub-ECMA. +static void +print_gmt_string(char* buf, size_t size, jsdouble utctime) +{ + JS_snprintf(buf, size, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT", + days[WeekDay(utctime)], + DateFromTime(utctime), + months[MonthFromTime(utctime)], + YearFromTime(utctime), + HourFromTime(utctime), + MinFromTime(utctime), + SecFromTime(utctime)); +} + +static void +print_iso_string(char* buf, size_t size, jsdouble utctime) +{ + JS_snprintf(buf, size, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ", + YearFromTime(utctime), + MonthFromTime(utctime) + 1, + DateFromTime(utctime), + HourFromTime(utctime), + MinFromTime(utctime), + SecFromTime(utctime), + msFromTime(utctime)); +} + +static JSBool +date_utc_format(JSContext *cx, Value *vp, + void (*printFunc)(char*, size_t, jsdouble)) +{ + jsdouble utctime; + if (!GetThisUTCTime(cx, vp, &utctime)) + return false; + + char buf[100]; + if (!JSDOUBLE_IS_FINITE(utctime)) + JS_snprintf(buf, sizeof buf, js_NaN_date_str); + else + (*printFunc)(buf, sizeof buf, utctime); + + JSString *str = JS_NewStringCopyZ(cx, buf); + if (!str) + return false; + vp->setString(str); + return true; +} + +static JSBool +date_toGMTString(JSContext *cx, uintN argc, Value *vp) +{ + return date_utc_format(cx, vp, print_gmt_string); +} + +static JSBool +date_toISOString(JSContext *cx, uintN argc, Value *vp) +{ + return date_utc_format(cx, vp, print_iso_string); +} + +/* ES5 15.9.5.44. */ +static JSBool +date_toJSON(JSContext *cx, uintN argc, Value *vp) +{ + /* Step 1. */ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + /* Step 2. */ + Value &tv = vp[0]; + if (!DefaultValue(cx, obj, JSTYPE_NUMBER, &tv)) + return false; + + /* Step 3. */ + if (tv.isDouble() && !JSDOUBLE_IS_FINITE(tv.toDouble())) { + vp->setNull(); + return true; + } + + /* Step 4. */ + Value &toISO = vp[0]; + if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.toISOStringAtom), &toISO)) + return false; + + /* Step 5. */ + if (!js_IsCallable(toISO)) { + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, + JSMSG_BAD_TOISOSTRING_PROP); + return false; + } + + /* Step 6. */ + LeaveTrace(cx); + InvokeArgsGuard args; + if (!cx->stack().pushInvokeArgs(cx, 0, &args)) + return false; + + args.callee() = toISO; + args.thisv().setObject(*obj); + + if (!Invoke(cx, args, 0)) + return false; + *vp = args.rval(); + return true; +} + +/* for Date.toLocaleString; interface to PRMJTime date struct. + */ +static void +new_explode(jsdouble timeval, PRMJTime *split, JSContext *cx) +{ + jsint year = YearFromTime(timeval); + + split->tm_usec = (int32) msFromTime(timeval) * 1000; + split->tm_sec = (int8) SecFromTime(timeval); + split->tm_min = (int8) MinFromTime(timeval); + split->tm_hour = (int8) HourFromTime(timeval); + split->tm_mday = (int8) DateFromTime(timeval); + split->tm_mon = (int8) MonthFromTime(timeval); + split->tm_wday = (int8) WeekDay(timeval); + split->tm_year = year; + split->tm_yday = (int16) DayWithinYear(timeval, year); + + /* not sure how this affects things, but it doesn't seem + to matter. */ + split->tm_isdst = (DaylightSavingTA(timeval, cx) != 0); +} + +typedef enum formatspec { + FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME +} formatspec; + +/* helper function */ +static JSBool +date_format(JSContext *cx, jsdouble date, formatspec format, Value *rval) +{ + char buf[100]; + JSString *str; + char tzbuf[100]; + JSBool usetz; + size_t i, tzlen; + PRMJTime split; + + if (!JSDOUBLE_IS_FINITE(date)) { + JS_snprintf(buf, sizeof buf, js_NaN_date_str); + } else { + jsdouble local = LocalTime(date, cx); + + /* offset from GMT in minutes. The offset includes daylight savings, + if it applies. */ + jsint minutes = (jsint) floor(AdjustTime(date, cx) / msPerMinute); + + /* map 510 minutes to 0830 hours */ + intN offset = (minutes / 60) * 100 + minutes % 60; + + /* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is + * printed as 'GMT-0800' rather than as 'PST' to avoid + * operating-system dependence on strftime (which + * PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints + * PST as 'Pacific Standard Time.' This way we always know + * what we're getting, and can parse it if we produce it. + * The OS TZA string is included as a comment. + */ + + /* get a timezone string from the OS to include as a + comment. */ + new_explode(date, &split, cx); + if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) { + + /* Decide whether to use the resulting timezone string. + * + * Reject it if it contains any non-ASCII, non-alphanumeric + * characters. It's then likely in some other character + * encoding, and we probably won't display it correctly. + */ + usetz = JS_TRUE; + tzlen = strlen(tzbuf); + if (tzlen > 100) { + usetz = JS_FALSE; + } else { + for (i = 0; i < tzlen; i++) { + jschar c = tzbuf[i]; + if (c > 127 || + !(isalpha(c) || isdigit(c) || + c == ' ' || c == '(' || c == ')')) { + usetz = JS_FALSE; + } + } + } + + /* Also reject it if it's not parenthesized or if it's '()'. */ + if (tzbuf[0] != '(' || tzbuf[1] == ')') + usetz = JS_FALSE; + } else + usetz = JS_FALSE; + + switch (format) { + case FORMATSPEC_FULL: + /* + * Avoid dependence on PRMJ_FormatTimeUSEnglish, because it + * requires a PRMJTime... which only has 16-bit years. Sub-ECMA. + */ + /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */ + JS_snprintf(buf, sizeof buf, + "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s", + days[WeekDay(local)], + months[MonthFromTime(local)], + DateFromTime(local), + YearFromTime(local), + HourFromTime(local), + MinFromTime(local), + SecFromTime(local), + offset, + usetz ? " " : "", + usetz ? tzbuf : ""); + break; + case FORMATSPEC_DATE: + /* Tue Oct 31 2000 */ + JS_snprintf(buf, sizeof buf, + "%s %s %.2d %.4d", + days[WeekDay(local)], + months[MonthFromTime(local)], + DateFromTime(local), + YearFromTime(local)); + break; + case FORMATSPEC_TIME: + /* 09:41:40 GMT-0800 (PST) */ + JS_snprintf(buf, sizeof buf, + "%.2d:%.2d:%.2d GMT%+.4d%s%s", + HourFromTime(local), + MinFromTime(local), + SecFromTime(local), + offset, + usetz ? " " : "", + usetz ? tzbuf : ""); + break; + } + } + + str = JS_NewStringCopyZ(cx, buf); + if (!str) + return JS_FALSE; + rval->setString(str); + return JS_TRUE; +} + +static JSBool +date_toLocaleHelper(JSContext *cx, JSObject *obj, const char *format, Value *vp) +{ + char buf[100]; + JSString *str; + PRMJTime split; + jsdouble utctime; + + if (!GetUTCTime(cx, obj, vp, &utctime)) + return false; + + if (!JSDOUBLE_IS_FINITE(utctime)) { + JS_snprintf(buf, sizeof buf, js_NaN_date_str); + } else { + intN result_len; + jsdouble local = LocalTime(utctime, cx); + new_explode(local, &split, cx); + + /* let PRMJTime format it. */ + result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split); + + /* If it failed, default to toString. */ + if (result_len == 0) + return date_format(cx, utctime, FORMATSPEC_FULL, vp); + + /* Hacked check against undesired 2-digit year 00/00/00 form. */ + if (strcmp(format, "%x") == 0 && result_len >= 6 && + /* Format %x means use OS settings, which may have 2-digit yr, so + hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/ + !isdigit(buf[result_len - 3]) && + isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1]) && + /* ...but not if starts with 4-digit year, like 2022/3/11. */ + !(isdigit(buf[0]) && isdigit(buf[1]) && + isdigit(buf[2]) && isdigit(buf[3]))) { + JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2), + "%d", js_DateGetYear(cx, obj)); + } + + } + + if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) + return cx->localeCallbacks->localeToUnicode(cx, buf, Jsvalify(vp)); + + str = JS_NewStringCopyZ(cx, buf); + if (!str) + return false; + vp->setString(str); + return true; +} + +static JSBool +date_toLocaleString(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + /* + * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k + * with msvc; '%#c' requests that a full year be used in the result string. + */ + return date_toLocaleHelper(cx, obj, +#if defined(_WIN32) && !defined(__MWERKS__) + "%#c" +#else + "%c" +#endif + , vp); +} + +static JSBool +date_toLocaleDateString(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + /* + * Use '%#x' for windows, because '%x' is backward-compatible and non-y2k + * with msvc; '%#x' requests that a full year be used in the result string. + */ + return date_toLocaleHelper(cx, obj, +#if defined(_WIN32) && !defined(__MWERKS__) + "%#x" +#else + "%x" +#endif + , vp); +} + +static JSBool +date_toLocaleTimeString(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + return date_toLocaleHelper(cx, obj, "%X", vp); +} + +static JSBool +date_toLocaleFormat(JSContext *cx, uintN argc, Value *vp) +{ + if (argc == 0) + return date_toLocaleString(cx, argc, vp); + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + JSString *fmt = js_ValueToString(cx, vp[2]); + if (!fmt) + return false; + vp[2].setString(fmt); + JSAutoByteString fmtbytes(cx, fmt); + if (!fmtbytes) + return false; + + return date_toLocaleHelper(cx, obj, fmtbytes.ptr(), vp); +} + +static JSBool +date_toTimeString(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble utctime; + if (!GetThisUTCTime(cx, vp, &utctime)) + return false; + return date_format(cx, utctime, FORMATSPEC_TIME, vp); +} + +static JSBool +date_toDateString(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble utctime; + if (!GetThisUTCTime(cx, vp, &utctime)) + return false; + return date_format(cx, utctime, FORMATSPEC_DATE, vp); +} + +#if JS_HAS_TOSOURCE +#include +#include "jsnum.h" + +static JSBool +date_toSource(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble utctime; + if (!GetThisUTCTime(cx, vp, &utctime)) + return false; + + ToCStringBuf cbuf; + char *numStr = NumberToCString(cx, &cbuf, utctime); + if (!numStr) { + JS_ReportOutOfMemory(cx); + return false; + } + + char *bytes = JS_smprintf("(new %s(%s))", js_Date_str, numStr); + if (!bytes) { + JS_ReportOutOfMemory(cx); + return false; + } + + JSString *str = JS_NewStringCopyZ(cx, bytes); + js_free(bytes); + if (!str) + return false; + vp->setString(str); + return true; +} +#endif + +static JSBool +date_toString(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble utctime; + if (!GetThisUTCTime(cx, vp, &utctime)) + return false; + + return date_format(cx, utctime, FORMATSPEC_FULL, vp); +} + +static JSBool +date_valueOf(JSContext *cx, uintN argc, Value *vp) +{ + /* + * It is an error to call date_valueOf on a non-date object, but we don't + * need to check for that explicitly here because every path calls + * GetUTCTime, which does the check. + */ + + /* If called directly with no arguments, convert to a time number. */ + if (argc == 0) + return date_getTime(cx, argc, vp); + + /* Verify this before extracting a string from the first argument. */ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + /* Convert to number only if the hint was given, otherwise favor string. */ + JSString *str = js_ValueToString(cx, vp[2]); + if (!str) + return false; + JSLinearString *linear_str = str->ensureLinear(cx); + if (!linear_str) + return false; + JSAtom *number_str = cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]; + if (EqualStrings(linear_str, number_str)) + return date_getTime(cx, argc, vp); + return date_toString(cx, argc, vp); +} + +// Don't really need an argument here, but we don't support arg-less builtins +JS_DEFINE_TRCINFO_1(date_now, + (1, (static, DOUBLE, date_now_tn, CONTEXT, 0, nanojit::ACCSET_STORE_ANY))) + +static JSFunctionSpec date_static_methods[] = { + JS_FN("UTC", date_UTC, MAXARGS,0), + JS_FN("parse", date_parse, 1,0), + JS_TN("now", date_now, 0,0, &date_now_trcinfo), + JS_FS_END +}; + +static JSFunctionSpec date_methods[] = { + JS_FN("getTime", date_getTime, 0,0), + JS_FN("getTimezoneOffset", date_getTimezoneOffset, 0,0), + JS_FN("getYear", date_getYear, 0,0), + JS_FN("getFullYear", date_getFullYear, 0,0), + JS_FN("getUTCFullYear", date_getUTCFullYear, 0,0), + JS_FN("getMonth", date_getMonth, 0,0), + JS_FN("getUTCMonth", date_getUTCMonth, 0,0), + JS_FN("getDate", date_getDate, 0,0), + JS_FN("getUTCDate", date_getUTCDate, 0,0), + JS_FN("getDay", date_getDay, 0,0), + JS_FN("getUTCDay", date_getUTCDay, 0,0), + JS_FN("getHours", date_getHours, 0,0), + JS_FN("getUTCHours", date_getUTCHours, 0,0), + JS_FN("getMinutes", date_getMinutes, 0,0), + JS_FN("getUTCMinutes", date_getUTCMinutes, 0,0), + JS_FN("getSeconds", date_getUTCSeconds, 0,0), + JS_FN("getUTCSeconds", date_getUTCSeconds, 0,0), + JS_FN("getMilliseconds", date_getUTCMilliseconds, 0,0), + JS_FN("getUTCMilliseconds", date_getUTCMilliseconds, 0,0), + JS_FN("setTime", date_setTime, 1,0), + JS_FN("setYear", date_setYear, 1,0), + JS_FN("setFullYear", date_setFullYear, 3,0), + JS_FN("setUTCFullYear", date_setUTCFullYear, 3,0), + JS_FN("setMonth", date_setMonth, 2,0), + JS_FN("setUTCMonth", date_setUTCMonth, 2,0), + JS_FN("setDate", date_setDate, 1,0), + JS_FN("setUTCDate", date_setUTCDate, 1,0), + JS_FN("setHours", date_setHours, 4,0), + JS_FN("setUTCHours", date_setUTCHours, 4,0), + JS_FN("setMinutes", date_setMinutes, 3,0), + JS_FN("setUTCMinutes", date_setUTCMinutes, 3,0), + JS_FN("setSeconds", date_setSeconds, 2,0), + JS_FN("setUTCSeconds", date_setUTCSeconds, 2,0), + JS_FN("setMilliseconds", date_setMilliseconds, 1,0), + JS_FN("setUTCMilliseconds", date_setUTCMilliseconds, 1,0), + JS_FN("toUTCString", date_toGMTString, 0,0), + JS_FN(js_toLocaleString_str, date_toLocaleString, 0,0), + JS_FN("toLocaleDateString", date_toLocaleDateString, 0,0), + JS_FN("toLocaleTimeString", date_toLocaleTimeString, 0,0), + JS_FN("toLocaleFormat", date_toLocaleFormat, 0,0), + JS_FN("toDateString", date_toDateString, 0,0), + JS_FN("toTimeString", date_toTimeString, 0,0), + JS_FN("toISOString", date_toISOString, 0,0), + JS_FN(js_toJSON_str, date_toJSON, 1,0), +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, date_toSource, 0,0), +#endif + JS_FN(js_toString_str, date_toString, 0,0), + JS_FN(js_valueOf_str, date_valueOf, 0,0), + JS_FS_END +}; + +JSBool +js_Date(JSContext *cx, uintN argc, Value *vp) +{ + /* Date called as function. */ + if (!IsConstructing(vp)) + return date_format(cx, NowAsMillis(), FORMATSPEC_FULL, vp); + + Value *argv = vp + 2; + + /* Date called as constructor. */ + jsdouble d; + if (argc == 0) { + d = NowAsMillis(); + } else if (argc == 1) { + if (!argv[0].isString()) { + /* the argument is a millisecond number */ + if (!ValueToNumber(cx, argv[0], &d)) + return false; + d = TIMECLIP(d); + } else { + /* the argument is a string; parse it. */ + JSString *str = js_ValueToString(cx, argv[0]); + if (!str) + return false; + argv[0].setString(str); + JSLinearString *linearStr = str->ensureLinear(cx); + if (!linearStr) + return false; + + if (!date_parseString(linearStr, &d, cx)) + d = js_NaN; + else + d = TIMECLIP(d); + } + } else { + jsdouble msec_time; + if (!date_msecFromArgs(cx, argc, argv, &msec_time)) + return false; + + if (JSDOUBLE_IS_FINITE(msec_time)) { + msec_time = UTC(msec_time, cx); + msec_time = TIMECLIP(msec_time); + } + d = msec_time; + } + + JSObject *obj = js_NewDateObjectMsec(cx, d); + if (!obj) + return false; + vp->setObject(*obj); + + return true; +} + +JSObject * +js_InitDateClass(JSContext *cx, JSObject *obj) +{ + /* set static LocalTZA */ + LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond); + JSObject *proto = js_InitClass(cx, obj, NULL, &js_DateClass, js_Date, MAXARGS, + NULL, date_methods, NULL, date_static_methods); + if (!proto) + return NULL; + + AutoObjectRooter tvr(cx, proto); + + SetDateToNaN(cx, proto); + + /* + * ES5 B.2.6: + * The Function object that is the initial value of + * Date.prototype.toGMTString is the same Function + * object that is the initial value of + * Date.prototype.toUTCString. + */ + AutoValueRooter toUTCStringFun(cx); + jsid toUTCStringId = ATOM_TO_JSID(cx->runtime->atomState.toUTCStringAtom); + jsid toGMTStringId = ATOM_TO_JSID(cx->runtime->atomState.toGMTStringAtom); + if (!js_GetProperty(cx, proto, toUTCStringId, toUTCStringFun.addr()) || + !js_DefineProperty(cx, proto, toGMTStringId, toUTCStringFun.addr(), + PropertyStub, StrictPropertyStub, 0)) { + return NULL; + } + + return proto; +} + +JS_FRIEND_API(JSObject *) +js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time) +{ + JSObject *obj = NewBuiltinClassInstance(cx, &js_DateClass); + if (!obj || !obj->ensureSlots(cx, JSObject::DATE_CLASS_RESERVED_SLOTS)) + return NULL; + if (!SetUTCTime(cx, obj, msec_time)) + return NULL; + return obj; +} + +JS_FRIEND_API(JSObject *) +js_NewDateObject(JSContext* cx, int year, int mon, int mday, + int hour, int min, int sec) +{ + JSObject *obj; + jsdouble msec_time; + + JS_ASSERT(mon < 12); + msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0); + obj = js_NewDateObjectMsec(cx, UTC(msec_time, cx)); + return obj; +} + +JS_FRIEND_API(JSBool) +js_DateIsValid(JSContext *cx, JSObject* obj) +{ + jsdouble utctime; + return GetUTCTime(cx, obj, NULL, &utctime) && !JSDOUBLE_IS_NaN(utctime); +} + +JS_FRIEND_API(int) +js_DateGetYear(JSContext *cx, JSObject* obj) +{ + jsdouble localtime; + + /* Preserve legacy API behavior of returning 0 for invalid dates. */ + if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) || + JSDOUBLE_IS_NaN(localtime)) { + return 0; + } + + return (int) YearFromTime(localtime); +} + +JS_FRIEND_API(int) +js_DateGetMonth(JSContext *cx, JSObject* obj) +{ + jsdouble localtime; + + if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) || + JSDOUBLE_IS_NaN(localtime)) { + return 0; + } + + return (int) MonthFromTime(localtime); +} + +JS_FRIEND_API(int) +js_DateGetDate(JSContext *cx, JSObject* obj) +{ + jsdouble localtime; + + if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) || + JSDOUBLE_IS_NaN(localtime)) { + return 0; + } + + return (int) DateFromTime(localtime); +} + +JS_FRIEND_API(int) +js_DateGetHours(JSContext *cx, JSObject* obj) +{ + jsdouble localtime; + + if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) || + JSDOUBLE_IS_NaN(localtime)) { + return 0; + } + + return (int) HourFromTime(localtime); +} + +JS_FRIEND_API(int) +js_DateGetMinutes(JSContext *cx, JSObject* obj) +{ + jsdouble localtime; + + if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) || + JSDOUBLE_IS_NaN(localtime)) { + return 0; + } + + return (int) MinFromTime(localtime); +} + +JS_FRIEND_API(int) +js_DateGetSeconds(JSContext *cx, JSObject* obj) +{ + jsdouble utctime; + + if (!GetUTCTime(cx, obj, NULL, &utctime) || JSDOUBLE_IS_NaN(utctime)) + return 0; + + return (int) SecFromTime(utctime); +} + +JS_FRIEND_API(jsdouble) +js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj) +{ + jsdouble utctime; + if (!GetUTCTime(cx, obj, NULL, &utctime)) + return 0; + return utctime; +} + +#ifdef JS_THREADSAFE +#include "prinrval.h" + +JS_FRIEND_API(uint32) +js_IntervalNow() +{ + return uint32(PR_IntervalToMilliseconds(PR_IntervalNow())); +} + +#else /* !JS_THREADSAFE */ + +JS_FRIEND_API(uint32) +js_IntervalNow() +{ + return uint32(PRMJ_Now() / PRMJ_USEC_PER_MSEC); +} +#endif diff --git a/js/src/jsdate.h b/js/src/jsdate.h new file mode 100644 index 0000000..ba97ddd --- /dev/null +++ b/js/src/jsdate.h @@ -0,0 +1,125 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS Date class interface. + */ + +#ifndef jsdate_h___ +#define jsdate_h___ + +#include "jsobj.h" + +extern js::Class js_DateClass; + +inline bool +JSObject::isDate() const +{ + return getClass() == &js_DateClass; +} + +#define HalfTimeDomain 8.64e15 + +#define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \ + && !((d < 0 ? -d : d) > HalfTimeDomain)) \ + ? js_DoubleToInteger(d + (+0.)) : js_NaN) + +extern JSObject * +js_InitDateClass(JSContext *cx, JSObject *obj); + +/* + * These functions provide a C interface to the date/time object + */ + +/* + * Construct a new Date Object from a time value given in milliseconds UTC + * since the epoch. + */ +extern JS_FRIEND_API(JSObject*) +js_NewDateObjectMsec(JSContext* cx, jsdouble msec_time); + +/* + * Construct a new Date Object from an exploded local time value. + * + * Assert that mon < 12 to help catch off-by-one user errors, which are common + * due to the 0-based month numbering copied into JS from Java (java.util.Date + * in 1995). + */ +extern JS_FRIEND_API(JSObject*) +js_NewDateObject(JSContext* cx, int year, int mon, int mday, + int hour, int min, int sec); + +/* + * Detect whether the internal date value is NaN. (Because failure is + * out-of-band for js_DateGet*) + */ +extern JS_FRIEND_API(JSBool) +js_DateIsValid(JSContext *cx, JSObject* obj); + +extern JS_FRIEND_API(int) +js_DateGetYear(JSContext *cx, JSObject* obj); + +extern JS_FRIEND_API(int) +js_DateGetMonth(JSContext *cx, JSObject* obj); + +extern JS_FRIEND_API(int) +js_DateGetDate(JSContext *cx, JSObject* obj); + +extern JS_FRIEND_API(int) +js_DateGetHours(JSContext *cx, JSObject* obj); + +extern JS_FRIEND_API(int) +js_DateGetMinutes(JSContext *cx, JSObject* obj); + +extern JS_FRIEND_API(int) +js_DateGetSeconds(JSContext *cx, JSObject* obj); + +extern JS_FRIEND_API(jsdouble) +js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj); + +typedef uint32 JSIntervalTime; + +extern JS_FRIEND_API(JSIntervalTime) +js_IntervalNow(); + +/* Date constructor native. Exposed only so the JIT can know its address. */ +JSBool +js_Date(JSContext *cx, uintN argc, js::Value *vp); + +#endif /* jsdate_h___ */ diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp new file mode 100644 index 0000000..130d7e5 --- /dev/null +++ b/js/src/jsdbgapi.cpp @@ -0,0 +1,2690 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS debugging API. + */ +#include +#include "jsprvtd.h" +#include "jstypes.h" +#include "jsstdint.h" +#include "jsutil.h" +#include "jsclist.h" +#include "jshashtable.h" +#include "jsapi.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdbgapi.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstaticcheck.h" +#include "jsstr.h" +#include "jswrapper.h" + +#include "jsatominlines.h" +#include "jsdbgapiinlines.h" +#include "jsinterpinlines.h" +#include "jsobjinlines.h" +#include "jsscopeinlines.h" +#include "jsscriptinlines.h" + +#include "jsautooplen.h" + +#include "methodjit/MethodJIT.h" +#include "methodjit/Retcon.h" + +using namespace js; +using namespace js::gc; + +typedef struct JSTrap { + JSCList links; + JSScript *script; + jsbytecode *pc; + JSOp op; + JSTrapHandler handler; + jsval closure; +} JSTrap; + +#define DBG_LOCK(rt) JS_ACQUIRE_LOCK((rt)->debuggerLock) +#define DBG_UNLOCK(rt) JS_RELEASE_LOCK((rt)->debuggerLock) +#define DBG_LOCK_EVAL(rt,expr) (DBG_LOCK(rt), (expr), DBG_UNLOCK(rt)) + +JS_PUBLIC_API(JSBool) +JS_GetDebugMode(JSContext *cx) +{ + return cx->compartment->debugMode; +} + +JS_PUBLIC_API(JSBool) +JS_SetDebugMode(JSContext *cx, JSBool debug) +{ + return JS_SetDebugModeForCompartment(cx, cx->compartment, debug); +} + +JS_PUBLIC_API(void) +JS_SetRuntimeDebugMode(JSRuntime *rt, JSBool debug) +{ + rt->debugMode = debug; +} + +#ifdef DEBUG +static bool +CompartmentHasLiveScripts(JSCompartment *comp) +{ +#ifdef JS_METHODJIT +# ifdef JS_THREADSAFE + jsword currentThreadId = reinterpret_cast(js_CurrentThreadId()); +# endif +#endif + + // Unsynchronized context iteration is technically a race; but this is only + // for debug asserts where such a race would be rare + JSContext *iter = NULL; + JSContext *icx; + while ((icx = JS_ContextIterator(comp->rt, &iter))) { +#ifdef JS_THREADSAFE + if (JS_GetContextThread(icx) != currentThreadId) + continue; +#endif + for (AllFramesIter i(icx); !i.done(); ++i) { + JSScript *script = i.fp()->maybeScript(); + if (script && script->compartment == comp) + return JS_TRUE; + } + } + + return JS_FALSE; +} +#endif + +JS_FRIEND_API(JSBool) +JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, JSBool debug) +{ + if (comp->debugMode == !!debug) + return JS_TRUE; + + // This should only be called when no scripts are live. It would even be + // incorrect to discard just the non-live scripts' JITScripts because they + // might share ICs with live scripts (bug 632343). + JS_ASSERT(!CompartmentHasLiveScripts(comp)); + + // All scripts compiled from this point on should be in the requested debugMode. + comp->debugMode = !!debug; + + // Discard JIT code for any scripts that change debugMode. This function + // assumes that 'comp' is in the same thread as 'cx'. + +#ifdef JS_METHODJIT + JS::AutoEnterScriptCompartment ac; + + for (JSScript *script = (JSScript *)comp->scripts.next; + &script->links != &comp->scripts; + script = (JSScript *)script->links.next) + { + if (!script->debugMode == !debug) + continue; + + /* + * If compartment entry fails, debug mode is left partially on, leading + * to a small performance overhead but no loss of correctness. We set + * the debug flags to false so that the caller will not later attempt + * to use debugging features. + */ + if (!ac.entered() && !ac.enter(cx, script)) { + comp->debugMode = JS_FALSE; + return JS_FALSE; + } + + mjit::ReleaseScriptCode(cx, script); + script->debugMode = !!debug; + } +#endif + + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep) +{ +#ifdef JS_METHODJIT + if (!script->singleStepMode == !singleStep) + return JS_TRUE; +#endif + + JS_ASSERT_IF(singleStep, cx->compartment->debugMode); + +#ifdef JS_METHODJIT + /* request the next recompile to inject single step interrupts */ + script->singleStepMode = !!singleStep; + + js::mjit::JITScript *jit = script->jitNormal ? script->jitNormal : script->jitCtor; + if (jit && script->singleStepMode != jit->singleStepMode) { + js::mjit::Recompiler recompiler(cx, script); + if (!recompiler.recompile()) { + script->singleStepMode = !singleStep; + return JS_FALSE; + } + } +#endif + return JS_TRUE; +} + +static JSBool +CheckDebugMode(JSContext *cx) +{ + JSBool debugMode = JS_GetDebugMode(cx); + /* + * :TODO: + * This probably should be an assertion, since it's indicative of a severe + * API misuse. + */ + if (!debugMode) { + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, + NULL, JSMSG_NEED_DEBUG_MODE); + } + return debugMode; +} + +JS_PUBLIC_API(JSBool) +JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep) +{ + if (!CheckDebugMode(cx)) + return JS_FALSE; + + return js_SetSingleStepMode(cx, script, singleStep); +} + +/* + * NB: FindTrap must be called with rt->debuggerLock acquired. + */ +static JSTrap * +FindTrap(JSRuntime *rt, JSScript *script, jsbytecode *pc) +{ + JSTrap *trap; + + for (trap = (JSTrap *)rt->trapList.next; + &trap->links != &rt->trapList; + trap = (JSTrap *)trap->links.next) { + if (trap->script == script && trap->pc == pc) + return trap; + } + return NULL; +} + +jsbytecode * +js_UntrapScriptCode(JSContext *cx, JSScript *script) +{ + jsbytecode *code; + JSRuntime *rt; + JSTrap *trap; + + code = script->code; + rt = cx->runtime; + DBG_LOCK(rt); + for (trap = (JSTrap *)rt->trapList.next; + &trap->links != + &rt->trapList; + trap = (JSTrap *)trap->links.next) { + if (trap->script == script && + (size_t)(trap->pc - script->code) < script->length) { + if (code == script->code) { + jssrcnote *sn, *notes; + size_t nbytes; + + nbytes = script->length * sizeof(jsbytecode); + notes = script->notes(); + for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) + continue; + nbytes += (sn - notes + 1) * sizeof *sn; + + code = (jsbytecode *) cx->malloc(nbytes); + if (!code) + break; + memcpy(code, script->code, nbytes); + JS_PURGE_GSN_CACHE(cx); + } + code[trap->pc - script->code] = trap->op; + } + } + DBG_UNLOCK(rt); + return code; +} + +JS_PUBLIC_API(JSBool) +JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc, + JSTrapHandler handler, jsval closure) +{ + JSTrap *junk, *trap, *twin; + JSRuntime *rt; + uint32 sample; + + if (!CheckDebugMode(cx)) + return JS_FALSE; + + JS_ASSERT((JSOp) *pc != JSOP_TRAP); + junk = NULL; + rt = cx->runtime; + DBG_LOCK(rt); + trap = FindTrap(rt, script, pc); + if (trap) { + JS_ASSERT(trap->script == script && trap->pc == pc); + JS_ASSERT(*pc == JSOP_TRAP); + } else { + sample = rt->debuggerMutations; + DBG_UNLOCK(rt); + trap = (JSTrap *) cx->malloc(sizeof *trap); + if (!trap) + return JS_FALSE; + trap->closure = JSVAL_NULL; + DBG_LOCK(rt); + twin = (rt->debuggerMutations != sample) + ? FindTrap(rt, script, pc) + : NULL; + if (twin) { + junk = trap; + trap = twin; + } else { + JS_APPEND_LINK(&trap->links, &rt->trapList); + ++rt->debuggerMutations; + trap->script = script; + trap->pc = pc; + trap->op = (JSOp)*pc; + *pc = JSOP_TRAP; + } + } + trap->handler = handler; + trap->closure = closure; + DBG_UNLOCK(rt); + if (junk) + cx->free(junk); + +#ifdef JS_METHODJIT + if (script->hasJITCode()) { + js::mjit::Recompiler recompiler(cx, script); + if (!recompiler.recompile()) + return JS_FALSE; + } +#endif + + return JS_TRUE; +} + +JS_PUBLIC_API(JSOp) +JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + JSRuntime *rt; + JSTrap *trap; + JSOp op; + + rt = cx->runtime; + DBG_LOCK(rt); + trap = FindTrap(rt, script, pc); + op = trap ? trap->op : (JSOp) *pc; + DBG_UNLOCK(rt); + return op; +} + +static void +DestroyTrapAndUnlock(JSContext *cx, JSTrap *trap) +{ + ++cx->runtime->debuggerMutations; + JS_REMOVE_LINK(&trap->links); + *trap->pc = (jsbytecode)trap->op; + DBG_UNLOCK(cx->runtime); + cx->free(trap); +} + +JS_PUBLIC_API(void) +JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc, + JSTrapHandler *handlerp, jsval *closurep) +{ + JSTrap *trap; + + DBG_LOCK(cx->runtime); + trap = FindTrap(cx->runtime, script, pc); + if (handlerp) + *handlerp = trap ? trap->handler : NULL; + if (closurep) + *closurep = trap ? trap->closure : JSVAL_NULL; + if (trap) + DestroyTrapAndUnlock(cx, trap); + else + DBG_UNLOCK(cx->runtime); + +#ifdef JS_METHODJIT + if (script->hasJITCode()) { + mjit::Recompiler recompiler(cx, script); + recompiler.recompile(); + } +#endif +} + +JS_PUBLIC_API(void) +JS_ClearScriptTraps(JSContext *cx, JSScript *script) +{ + JSRuntime *rt; + JSTrap *trap, *next; + uint32 sample; + + rt = cx->runtime; + DBG_LOCK(rt); + for (trap = (JSTrap *)rt->trapList.next; + &trap->links != &rt->trapList; + trap = next) { + next = (JSTrap *)trap->links.next; + if (trap->script == script) { + sample = rt->debuggerMutations; + DestroyTrapAndUnlock(cx, trap); + DBG_LOCK(rt); + if (rt->debuggerMutations != sample + 1) + next = (JSTrap *)rt->trapList.next; + } + } + DBG_UNLOCK(rt); +} + +JS_PUBLIC_API(void) +JS_ClearAllTraps(JSContext *cx) +{ + JSRuntime *rt; + JSTrap *trap, *next; + uint32 sample; + + rt = cx->runtime; + DBG_LOCK(rt); + for (trap = (JSTrap *)rt->trapList.next; + &trap->links != &rt->trapList; + trap = next) { + next = (JSTrap *)trap->links.next; + sample = rt->debuggerMutations; + DestroyTrapAndUnlock(cx, trap); + DBG_LOCK(rt); + if (rt->debuggerMutations != sample + 1) + next = (JSTrap *)rt->trapList.next; + } + DBG_UNLOCK(rt); +} + +/* + * NB: js_MarkTraps does not acquire cx->runtime->debuggerLock, since the + * debugger should never be racing with the GC (i.e., the debugger must + * respect the request model). + */ +void +js_MarkTraps(JSTracer *trc) +{ + JSRuntime *rt = trc->context->runtime; + + for (JSTrap *trap = (JSTrap *) rt->trapList.next; + &trap->links != &rt->trapList; + trap = (JSTrap *) trap->links.next) { + MarkValue(trc, Valueify(trap->closure), "trap->closure"); + } +} + +JS_PUBLIC_API(JSTrapStatus) +JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval) +{ + JSTrap *trap; + jsint op; + JSTrapStatus status; + + DBG_LOCK(cx->runtime); + trap = FindTrap(cx->runtime, script, pc); + JS_ASSERT(!trap || trap->handler); + if (!trap) { + op = (JSOp) *pc; + DBG_UNLOCK(cx->runtime); + + /* Defend against "pc for wrong script" API usage error. */ + JS_ASSERT(op != JSOP_TRAP); + +#ifdef JS_THREADSAFE + /* If the API was abused, we must fail for want of the real op. */ + if (op == JSOP_TRAP) + return JSTRAP_ERROR; + + /* Assume a race with a debugger thread and try to carry on. */ + *rval = INT_TO_JSVAL(op); + return JSTRAP_CONTINUE; +#else + /* Always fail if single-threaded (must be an API usage error). */ + return JSTRAP_ERROR; +#endif + } + DBG_UNLOCK(cx->runtime); + + /* + * It's important that we not use 'trap->' after calling the callback -- + * the callback might remove the trap! + */ + op = (jsint)trap->op; + status = trap->handler(cx, script, pc, rval, trap->closure); + if (status == JSTRAP_CONTINUE) { + /* By convention, return the true op to the interpreter in rval. */ + *rval = INT_TO_JSVAL(op); + } + return status; +} + +#ifdef JS_TRACER +static void +JITInhibitingHookChange(JSRuntime *rt, bool wasInhibited) +{ + if (wasInhibited) { + if (!rt->debuggerInhibitsJIT()) { + for (JSCList *cl = rt->contextList.next; cl != &rt->contextList; cl = cl->next) + js_ContextFromLinkField(cl)->updateJITEnabled(); + } + } else if (rt->debuggerInhibitsJIT()) { + for (JSCList *cl = rt->contextList.next; cl != &rt->contextList; cl = cl->next) + js_ContextFromLinkField(cl)->traceJitEnabled = false; + } +} +#endif + +JS_PUBLIC_API(JSBool) +JS_SetInterrupt(JSRuntime *rt, JSInterruptHook hook, void *closure) +{ +#ifdef JS_TRACER + { + AutoLockGC lock(rt); + bool wasInhibited = rt->debuggerInhibitsJIT(); +#endif + rt->globalDebugHooks.interruptHook = hook; + rt->globalDebugHooks.interruptHookData = closure; +#ifdef JS_TRACER + JITInhibitingHookChange(rt, wasInhibited); + } +#endif + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_ClearInterrupt(JSRuntime *rt, JSInterruptHook *hoop, void **closurep) +{ +#ifdef JS_TRACER + AutoLockGC lock(rt); + bool wasInhibited = rt->debuggerInhibitsJIT(); +#endif + if (hoop) + *hoop = rt->globalDebugHooks.interruptHook; + if (closurep) + *closurep = rt->globalDebugHooks.interruptHookData; + rt->globalDebugHooks.interruptHook = 0; + rt->globalDebugHooks.interruptHookData = 0; +#ifdef JS_TRACER + JITInhibitingHookChange(rt, wasInhibited); +#endif + return JS_TRUE; +} + +/************************************************************************/ + +struct JSWatchPoint { + JSCList links; + JSObject *object; /* weak link, see js_SweepWatchPoints */ + const Shape *shape; + StrictPropertyOp setter; + JSWatchPointHandler handler; + JSObject *closure; + uintN flags; +}; + +#define JSWP_LIVE 0x1 /* live because set and not cleared */ +#define JSWP_HELD 0x2 /* held while running handler/setter */ + +/* + * NB: DropWatchPointAndUnlock releases cx->runtime->debuggerLock in all cases. + */ +static JSBool +DropWatchPointAndUnlock(JSContext *cx, JSWatchPoint *wp, uintN flag) +{ + bool ok = true; + JSRuntime *rt = cx->runtime; + + wp->flags &= ~flag; + if (wp->flags != 0) { + DBG_UNLOCK(rt); + return ok; + } + + /* + * Switch to the same compartment as the watch point, since changeProperty, below, + * needs to have a compartment. + */ + SwitchToCompartment sc(cx, wp->object); + + /* Remove wp from the list, then restore wp->shape->setter from wp. */ + ++rt->debuggerMutations; + JS_REMOVE_LINK(&wp->links); + DBG_UNLOCK(rt); + + /* + * If the property isn't found on wp->object, then someone else must have deleted it, + * and we don't need to change the property attributes. + */ + const Shape *shape = wp->shape; + const Shape *wprop = wp->object->nativeLookup(shape->id); + if (wprop && + wprop->hasSetterValue() == shape->hasSetterValue() && + IsWatchedProperty(cx, wprop)) { + shape = wp->object->changeProperty(cx, wprop, 0, wprop->attributes(), + wprop->getter(), wp->setter); + if (!shape) + ok = false; + } + + cx->free(wp); + return ok; +} + +/* + * NB: js_TraceWatchPoints does not acquire cx->runtime->debuggerLock, since + * the debugger should never be racing with the GC (i.e., the debugger must + * respect the request model). + */ +void +js_TraceWatchPoints(JSTracer *trc, JSObject *obj) +{ + JSRuntime *rt; + JSWatchPoint *wp; + + rt = trc->context->runtime; + + for (wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = (JSWatchPoint *)wp->links.next) { + if (wp->object == obj) { + wp->shape->trace(trc); + if (wp->shape->hasSetterValue() && wp->setter) + MarkObject(trc, *CastAsObject(wp->setter), "wp->setter"); + MarkObject(trc, *wp->closure, "wp->closure"); + } + } +} + +void +js_SweepWatchPoints(JSContext *cx) +{ + JSRuntime *rt; + JSWatchPoint *wp, *next; + uint32 sample; + + rt = cx->runtime; + DBG_LOCK(rt); + for (wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = next) { + next = (JSWatchPoint *)wp->links.next; + if (IsAboutToBeFinalized(cx, wp->object)) { + sample = rt->debuggerMutations; + + /* Ignore failures. */ + DropWatchPointAndUnlock(cx, wp, JSWP_LIVE); + DBG_LOCK(rt); + if (rt->debuggerMutations != sample + 1) + next = (JSWatchPoint *)rt->watchPointList.next; + } + } + DBG_UNLOCK(rt); +} + + + +/* + * NB: LockedFindWatchPoint must be called with rt->debuggerLock acquired. + */ +static JSWatchPoint * +LockedFindWatchPoint(JSRuntime *rt, JSObject *obj, jsid id) +{ + JSWatchPoint *wp; + + for (wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = (JSWatchPoint *)wp->links.next) { + if (wp->object == obj && wp->shape->id == id) + return wp; + } + return NULL; +} + +static JSWatchPoint * +FindWatchPoint(JSRuntime *rt, JSObject *obj, jsid id) +{ + JSWatchPoint *wp; + + DBG_LOCK(rt); + wp = LockedFindWatchPoint(rt, obj, id); + DBG_UNLOCK(rt); + return wp; +} + +JSBool +js_watch_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) +{ + JSRuntime *rt = cx->runtime; + DBG_LOCK(rt); + for (JSWatchPoint *wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = (JSWatchPoint *)wp->links.next) { + const Shape *shape = wp->shape; + if (wp->object == obj && SHAPE_USERID(shape) == id && !(wp->flags & JSWP_HELD)) { + wp->flags |= JSWP_HELD; + DBG_UNLOCK(rt); + + jsid propid = shape->id; + shape = obj->nativeLookup(propid); + JS_ASSERT(IsWatchedProperty(cx, shape)); + jsid userid = SHAPE_USERID(shape); + + /* Determine the property's old value. */ + bool ok; + uint32 slot = shape->slot; + Value old = obj->containsSlot(slot) ? obj->nativeGetSlot(slot) : UndefinedValue(); + const Shape *needMethodSlotWrite = NULL; + if (shape->isMethod()) { + /* + * We get here in two cases: (1) the existing watched property + * is a method; or (2) the watched property was deleted and is + * now in the middle of being re-added via JSOP_SETMETHOD. In + * both cases we must trip the method read barrier in order to + * avoid passing an uncloned function object to the handler. + * + * Case 2 is especially hairy. js_watch_set, uniquely, gets + * called in the middle of creating a method property, after + * shape is in obj but before the slot has been set. So in this + * case we must finish initializing the half-finished method + * property before triggering the method read barrier. + * + * Bonus weirdness: because this changes obj's shape, + * js_NativeSet (which is our caller) will not write to the + * slot, as it will appear the property was deleted and a new + * property added. We must write the slot ourselves -- however + * we must do it after calling the watchpoint handler. So set + * needMethodSlotWrite here and use it to write to the slot + * below, if the handler does not tinker with the property + * further. + */ + JS_ASSERT(!wp->setter); + Value method = ObjectValue(shape->methodObject()); + if (old.isUndefined()) + obj->nativeSetSlot(slot, method); + ok = obj->methodReadBarrier(cx, *shape, &method); + if (!ok) + goto out; + wp->shape = shape = needMethodSlotWrite = obj->nativeLookup(propid); + JS_ASSERT(shape->isDataDescriptor()); + JS_ASSERT(!shape->isMethod()); + if (old.isUndefined()) + obj->nativeSetSlot(shape->slot, old); + else + old = method; + } + + { + Conditionally tvr(needMethodSlotWrite, cx, needMethodSlotWrite); + + /* + * Call the handler. This invalidates shape, so re-lookup the shape. + * NB: wp is held, so we can safely dereference it still. + */ + ok = wp->handler(cx, obj, propid, Jsvalify(old), Jsvalify(vp), wp->closure); + if (!ok) + goto out; + shape = obj->nativeLookup(propid); + + if (!shape) { + ok = true; + } else if (wp->setter) { + /* + * Pass the output of the handler to the setter. Security wrappers + * prevent any funny business between watchpoints and setters. + */ + ok = shape->hasSetterValue() + ? ExternalInvoke(cx, ObjectValue(*obj), + ObjectValue(*CastAsObject(wp->setter)), + 1, vp, vp) + : CallJSPropertyOpSetter(cx, wp->setter, obj, userid, strict, vp); + } else if (shape == needMethodSlotWrite) { + /* See comment above about needMethodSlotWrite. */ + obj->nativeSetSlot(shape->slot, *vp); + ok = true; + } else { + /* + * A property with the default setter might be either a method + * or an ordinary function-valued data property subject to the + * method write barrier. + * + * It is not the setter's job to call methodWriteBarrier, + * but js_watch_set must do so, because the caller will be + * fooled into not doing it: shape does *not* have the + * default setter and therefore seems not to be a method. + */ + ok = obj->methodWriteBarrier(cx, *shape, *vp) != NULL; + } + } + + out: + DBG_LOCK(rt); + return DropWatchPointAndUnlock(cx, wp, JSWP_HELD) && ok; + } + } + DBG_UNLOCK(rt); + return true; +} + +static JSBool +js_watch_set_wrapper(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + JSObject &funobj = JS_CALLEE(cx, vp).toObject(); + JSFunction *wrapper = funobj.getFunctionPrivate(); + jsid userid = ATOM_TO_JSID(wrapper->atom); + + JS_SET_RVAL(cx, vp, argc ? JS_ARGV(cx, vp)[0] : UndefinedValue()); + /* + * The strictness we pass here doesn't matter, since we know that it's + * a JS setter, which can't depend on the assigning code's strictness. + */ + return js_watch_set(cx, obj, userid, false, vp); +} + +namespace js { + +bool +IsWatchedProperty(JSContext *cx, const Shape *shape) +{ + if (shape->hasSetterValue()) { + JSObject *funobj = shape->setterObject(); + if (!funobj || !funobj->isFunction()) + return false; + + JSFunction *fun = funobj->getFunctionPrivate(); + return fun->maybeNative() == js_watch_set_wrapper; + } + return shape->setterOp() == js_watch_set; +} + +} + +/* + * Return an appropriate setter to substitute for |setter| on a property + * with attributes |attrs|, to implement a watchpoint on the property named + * |id|. + */ +static StrictPropertyOp +WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, StrictPropertyOp setter) +{ + JSAtom *atom; + JSFunction *wrapper; + + /* Wrap a C++ setter simply by returning our own C++ setter. */ + if (!(attrs & JSPROP_SETTER)) + return &js_watch_set; /* & to silence schoolmarmish MSVC */ + + /* + * Wrap a JSObject * setter by constructing our own JSFunction * that saves the + * property id as the function name, and calls js_watch_set. + */ + if (JSID_IS_ATOM(id)) { + atom = JSID_TO_ATOM(id); + } else if (JSID_IS_INT(id)) { + if (!js_ValueToStringId(cx, IdToValue(id), &id)) + return NULL; + atom = JSID_TO_ATOM(id); + } else { + atom = NULL; + } + + wrapper = js_NewFunction(cx, NULL, js_watch_set_wrapper, 1, 0, + setter ? CastAsObject(setter)->getParent() : NULL, atom); + if (!wrapper) + return NULL; + return CastAsStrictPropertyOp(FUN_OBJECT(wrapper)); +} + +static const Shape * +UpdateWatchpointShape(JSContext *cx, JSWatchPoint *wp, const Shape *newShape) +{ + JS_ASSERT_IF(wp->shape, wp->shape->id == newShape->id); + JS_ASSERT(!IsWatchedProperty(cx, newShape)); + + /* Create a watching setter we can substitute for the new shape's setter. */ + StrictPropertyOp watchingSetter = + WrapWatchedSetter(cx, newShape->id, newShape->attributes(), newShape->setter()); + if (!watchingSetter) + return NULL; + + /* + * Save the shape's setter; we don't know whether js_ChangeNativePropertyAttrs will + * return a new shape, or mutate this one. + */ + StrictPropertyOp originalSetter = newShape->setter(); + + /* + * Drop the watching setter into the object, in place of newShape. Note that a single + * watchpoint-wrapped shape may correspond to more than one non-watchpoint shape: we + * wrap all (JSPropertyOp, not JSObject *) setters with js_watch_set, so shapes that + * differ only in their setter may all get wrapped to the same shape. + */ + const Shape *watchingShape = + js_ChangeNativePropertyAttrs(cx, wp->object, newShape, 0, newShape->attributes(), + newShape->getter(), watchingSetter); + if (!watchingShape) + return NULL; + + /* Update the watchpoint with the new shape and its original setter. */ + wp->setter = originalSetter; + wp->shape = watchingShape; + + return watchingShape; +} + +const Shape * +js_SlowPathUpdateWatchpointsForShape(JSContext *cx, JSObject *obj, const Shape *newShape) +{ + /* + * The watchpoint code uses the normal property-modification functions to install its + * own watchpoint-aware shapes. Those functions report those changes back to the + * watchpoint code, just as they do user-level changes. So if this change is + * installing a watchpoint-aware shape, it's something we asked for ourselves, and can + * proceed without interference. + */ + if (IsWatchedProperty(cx, newShape)) + return newShape; + + JSWatchPoint *wp = FindWatchPoint(cx->runtime, obj, newShape->id); + if (!wp) + return newShape; + + return UpdateWatchpointShape(cx, wp, newShape); +} + +/* + * Return the underlying setter for |shape| on |obj|, seeing through any + * watchpoint-wrapping. Note that we need |obj| to disambiguate, since a single + * watchpoint-wrapped shape may correspond to more than one non-watchpoint shape; see the + * comments in UpdateWatchpointShape. + */ +static StrictPropertyOp +UnwrapSetter(JSContext *cx, JSObject *obj, const Shape *shape) +{ + /* If it's not a watched property, its setter is not wrapped. */ + if (!IsWatchedProperty(cx, shape)) + return shape->setter(); + + /* Look up the watchpoint, from which we can retrieve the underlying setter. */ + JSWatchPoint *wp = FindWatchPoint(cx->runtime, obj, shape->id); + + /* + * Since we know |shape| is watched, we *must* find a watchpoint: we should never + * leave wrapped setters lying around in shapes after removing a watchpoint. + */ + JS_ASSERT(wp); + + return wp->setter; +} + +JS_PUBLIC_API(JSBool) +JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id, + JSWatchPointHandler handler, JSObject *closure) +{ + JSObject *origobj; + Value v; + uintN attrs; + jsid propid; + + origobj = obj; + OBJ_TO_INNER_OBJECT(cx, obj); + if (!obj) + return JS_FALSE; + + AutoValueRooter idroot(cx); + if (JSID_IS_INT(id)) { + propid = id; + } else { + if (!js_ValueToStringId(cx, IdToValue(id), &propid)) + return JS_FALSE; + propid = js_CheckForStringIndex(propid); + idroot.set(IdToValue(propid)); + } + + /* + * If, by unwrapping and innerizing, we changed the object, check + * again to make sure that we're allowed to set a watch point. + */ + if (origobj != obj && !CheckAccess(cx, obj, propid, JSACC_WATCH, &v, &attrs)) + return JS_FALSE; + + if (!obj->isNative()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH, + obj->getClass()->name); + return JS_FALSE; + } + + JSObject *pobj; + JSProperty *prop; + if (!js_LookupProperty(cx, obj, propid, &pobj, &prop)) + return JS_FALSE; + const Shape *shape = (Shape *) prop; + JSRuntime *rt = cx->runtime; + if (!shape) { + /* Check for a deleted symbol watchpoint, which holds its property. */ + JSWatchPoint *wp = FindWatchPoint(rt, obj, propid); + if (!wp) { + /* Make a new property in obj so we can watch for the first set. */ + if (!js_DefineNativeProperty(cx, obj, propid, UndefinedValue(), NULL, NULL, + JSPROP_ENUMERATE, 0, 0, &prop)) { + return JS_FALSE; + } + shape = (Shape *) prop; + } + } else if (pobj != obj) { + /* Clone the prototype property so we can watch the right object. */ + AutoValueRooter valroot(cx); + PropertyOp getter; + StrictPropertyOp setter; + uintN attrs, flags; + intN shortid; + + if (pobj->isNative()) { + valroot.set(pobj->containsSlot(shape->slot) + ? pobj->nativeGetSlot(shape->slot) + : UndefinedValue()); + getter = shape->getter(); + setter = UnwrapSetter(cx, pobj, shape); + attrs = shape->attributes(); + flags = shape->getFlags(); + shortid = shape->shortid; + } else { + if (!pobj->getProperty(cx, propid, valroot.addr()) || + !pobj->getAttributes(cx, propid, &attrs)) { + return JS_FALSE; + } + getter = NULL; + setter = NULL; + flags = 0; + shortid = 0; + } + + /* Recall that obj is native, whether or not pobj is native. */ + if (!js_DefineNativeProperty(cx, obj, propid, valroot.value(), + getter, setter, attrs, flags, + shortid, &prop)) { + return JS_FALSE; + } + shape = (Shape *) prop; + } + + /* + * At this point, prop/shape exists in obj, obj is locked, and we must + * unlock the object before returning. + */ + DBG_LOCK(rt); + JSWatchPoint *wp = LockedFindWatchPoint(rt, obj, propid); + if (!wp) { + DBG_UNLOCK(rt); + wp = (JSWatchPoint *) cx->malloc(sizeof *wp); + if (!wp) + return JS_FALSE; + wp->handler = NULL; + wp->closure = NULL; + wp->object = obj; + wp->shape = NULL; + wp->flags = JSWP_LIVE; + + /* XXXbe nest in obj lock here */ + if (!UpdateWatchpointShape(cx, wp, shape)) { + /* Self-link so DropWatchPointAndUnlock can JS_REMOVE_LINK it. */ + JS_INIT_CLIST(&wp->links); + DBG_LOCK(rt); + DropWatchPointAndUnlock(cx, wp, JSWP_LIVE); + return JS_FALSE; + } + + /* + * Now that wp is fully initialized, append it to rt's wp list. + * Because obj is locked we know that no other thread could have added + * a watchpoint for (obj, propid). + */ + DBG_LOCK(rt); + JS_ASSERT(!LockedFindWatchPoint(rt, obj, propid)); + JS_APPEND_LINK(&wp->links, &rt->watchPointList); + ++rt->debuggerMutations; + } + + /* + * Ensure that an object with watchpoints never has the same shape as an + * object without them, even if the watched properties are deleted. + */ + obj->watchpointOwnShapeChange(cx); + + wp->handler = handler; + wp->closure = reinterpret_cast(closure); + DBG_UNLOCK(rt); + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsid id, + JSWatchPointHandler *handlerp, JSObject **closurep) +{ + JSRuntime *rt; + JSWatchPoint *wp; + + rt = cx->runtime; + DBG_LOCK(rt); + for (wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = (JSWatchPoint *)wp->links.next) { + if (wp->object == obj && SHAPE_USERID(wp->shape) == id) { + if (handlerp) + *handlerp = wp->handler; + if (closurep) + *closurep = wp->closure; + return DropWatchPointAndUnlock(cx, wp, JSWP_LIVE); + } + } + DBG_UNLOCK(rt); + if (handlerp) + *handlerp = NULL; + if (closurep) + *closurep = NULL; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj) +{ + JSRuntime *rt; + JSWatchPoint *wp, *next; + uint32 sample; + + rt = cx->runtime; + DBG_LOCK(rt); + for (wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = next) { + next = (JSWatchPoint *)wp->links.next; + if (wp->object == obj) { + sample = rt->debuggerMutations; + if (!DropWatchPointAndUnlock(cx, wp, JSWP_LIVE)) + return JS_FALSE; + DBG_LOCK(rt); + if (rt->debuggerMutations != sample + 1) + next = (JSWatchPoint *)rt->watchPointList.next; + } + } + DBG_UNLOCK(rt); + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_ClearAllWatchPoints(JSContext *cx) +{ + JSRuntime *rt; + JSWatchPoint *wp, *next; + uint32 sample; + + rt = cx->runtime; + DBG_LOCK(rt); + for (wp = (JSWatchPoint *)rt->watchPointList.next; + &wp->links != &rt->watchPointList; + wp = next) { + next = (JSWatchPoint *)wp->links.next; + sample = rt->debuggerMutations; + if (!DropWatchPointAndUnlock(cx, wp, JSWP_LIVE)) + return JS_FALSE; + DBG_LOCK(rt); + if (rt->debuggerMutations != sample + 1) + next = (JSWatchPoint *)rt->watchPointList.next; + } + DBG_UNLOCK(rt); + return JS_TRUE; +} + +/************************************************************************/ + +JS_PUBLIC_API(uintN) +JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + return js_PCToLineNumber(cx, script, pc); +} + +JS_PUBLIC_API(jsbytecode *) +JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno) +{ + return js_LineNumberToPC(script, lineno); +} + +JS_PUBLIC_API(jsbytecode *) +JS_EndPC(JSContext *cx, JSScript *script) +{ + return script->code + script->length; +} + +JS_PUBLIC_API(uintN) +JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun) +{ + return fun->nargs; +} + +JS_PUBLIC_API(JSBool) +JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun) +{ + return fun->script()->bindings.hasLocalNames(); +} + +extern JS_PUBLIC_API(jsuword *) +JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp) +{ + *markp = JS_ARENA_MARK(&cx->tempPool); + return fun->script()->bindings.getLocalNameArray(cx, &cx->tempPool); +} + +extern JS_PUBLIC_API(JSAtom *) +JS_LocalNameToAtom(jsuword w) +{ + return JS_LOCAL_NAME_TO_ATOM(w); +} + +extern JS_PUBLIC_API(JSString *) +JS_AtomKey(JSAtom *atom) +{ + return ATOM_TO_STRING(atom); +} + +extern JS_PUBLIC_API(void) +JS_ReleaseFunctionLocalNameArray(JSContext *cx, void *mark) +{ + JS_ARENA_RELEASE(&cx->tempPool, mark); +} + +JS_PUBLIC_API(JSScript *) +JS_GetFunctionScript(JSContext *cx, JSFunction *fun) +{ + return FUN_SCRIPT(fun); +} + +JS_PUBLIC_API(JSNative) +JS_GetFunctionNative(JSContext *cx, JSFunction *fun) +{ + return Jsvalify(fun->maybeNative()); +} + +JS_PUBLIC_API(JSPrincipals *) +JS_GetScriptPrincipals(JSContext *cx, JSScript *script) +{ + return script->principals; +} + +/************************************************************************/ + +/* + * Stack Frame Iterator + */ +JS_PUBLIC_API(JSStackFrame *) +JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp) +{ + *iteratorp = (*iteratorp == NULL) ? js_GetTopStackFrame(cx) : (*iteratorp)->prev(); + return *iteratorp; +} + +JS_PUBLIC_API(JSScript *) +JS_GetFrameScript(JSContext *cx, JSStackFrame *fp) +{ + return fp->maybeScript(); +} + +JS_PUBLIC_API(jsbytecode *) +JS_GetFramePC(JSContext *cx, JSStackFrame *fp) +{ + return fp->pc(cx); +} + +JS_PUBLIC_API(JSStackFrame *) +JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp) +{ + return js_GetScriptedCaller(cx, fp); +} + +JSPrincipals * +js_StackFramePrincipals(JSContext *cx, JSStackFrame *fp) +{ + JSSecurityCallbacks *callbacks; + + if (fp->isFunctionFrame()) { + callbacks = JS_GetSecurityCallbacks(cx); + if (callbacks && callbacks->findObjectPrincipals) { + if (&fp->fun()->compiledFunObj() != &fp->callee()) + return callbacks->findObjectPrincipals(cx, &fp->callee()); + /* FALL THROUGH */ + } + } + if (fp->isScriptFrame()) + return fp->script()->principals; + return NULL; +} + +JSPrincipals * +js_EvalFramePrincipals(JSContext *cx, JSObject *callee, JSStackFrame *caller) +{ + JSPrincipals *principals, *callerPrincipals; + JSSecurityCallbacks *callbacks; + + callbacks = JS_GetSecurityCallbacks(cx); + if (callbacks && callbacks->findObjectPrincipals) + principals = callbacks->findObjectPrincipals(cx, callee); + else + principals = NULL; + if (!caller) + return principals; + callerPrincipals = js_StackFramePrincipals(cx, caller); + return (callerPrincipals && principals && + callerPrincipals->subsume(callerPrincipals, principals)) + ? principals + : callerPrincipals; +} + +JS_PUBLIC_API(void *) +JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp) +{ + if (fp->annotation() && fp->isScriptFrame()) { + JSPrincipals *principals = js_StackFramePrincipals(cx, fp); + + if (principals && principals->globalPrivilegesEnabled(cx, principals)) { + /* + * Give out an annotation only if privileges have not been revoked + * or disabled globally. + */ + return fp->annotation(); + } + } + + return NULL; +} + +JS_PUBLIC_API(void) +JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation) +{ + fp->setAnnotation(annotation); +} + +JS_PUBLIC_API(void *) +JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp) +{ + JSPrincipals *principals; + + principals = js_StackFramePrincipals(cx, fp); + if (!principals) + return NULL; + return principals->getPrincipalArray(cx, principals); +} + +JS_PUBLIC_API(JSBool) +JS_IsScriptFrame(JSContext *cx, JSStackFrame *fp) +{ + return !fp->isDummyFrame(); +} + +/* this is deprecated, use JS_GetFrameScopeChain instead */ +JS_PUBLIC_API(JSObject *) +JS_GetFrameObject(JSContext *cx, JSStackFrame *fp) +{ + return &fp->scopeChain(); +} + +JS_PUBLIC_API(JSObject *) +JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp) +{ + JS_ASSERT(cx->stack().contains(fp)); + + js::AutoCompartment ac(cx, &fp->scopeChain()); + if (!ac.enter()) + return NULL; + + /* Force creation of argument and call objects if not yet created */ + (void) JS_GetFrameCallObject(cx, fp); + return GetScopeChain(cx, fp); +} + +JS_PUBLIC_API(JSObject *) +JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp) +{ + JS_ASSERT(cx->stack().contains(fp)); + + if (!fp->isFunctionFrame()) + return NULL; + + js::AutoCompartment ac(cx, &fp->scopeChain()); + if (!ac.enter()) + return NULL; + + /* Force creation of argument object if not yet created */ + (void) js_GetArgsObject(cx, fp); + + /* + * XXX ill-defined: null return here means error was reported, unlike a + * null returned above or in the #else + */ + return js_GetCallObject(cx, fp); +} + +JS_PUBLIC_API(JSBool) +JS_GetFrameThis(JSContext *cx, JSStackFrame *fp, jsval *thisv) +{ + if (fp->isDummyFrame()) + return false; + + js::AutoCompartment ac(cx, &fp->scopeChain()); + if (!ac.enter()) + return false; + + if (!fp->computeThis(cx)) + return false; + *thisv = Jsvalify(fp->thisValue()); + return true; +} + +JS_PUBLIC_API(JSFunction *) +JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp) +{ + return fp->maybeFun(); +} + +JS_PUBLIC_API(JSObject *) +JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp) +{ + if (!fp->isFunctionFrame()) + return NULL; + + JS_ASSERT(fp->callee().isFunction()); + JS_ASSERT(fp->callee().getPrivate() == fp->fun()); + return &fp->callee(); +} + +JS_PUBLIC_API(JSBool) +JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp) +{ + return fp->isConstructing(); +} + +JS_PUBLIC_API(JSObject *) +JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp) +{ + return fp->maybeCallee(); +} + +JS_PUBLIC_API(JSBool) +JS_GetValidFrameCalleeObject(JSContext *cx, JSStackFrame *fp, jsval *vp) +{ + Value v; + + if (!fp->getValidCalleeObject(cx, &v)) + return false; + *vp = Jsvalify(v); + return true; +} + +JS_PUBLIC_API(JSBool) +JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp) +{ + return fp->isDebuggerFrame(); +} + +JS_PUBLIC_API(jsval) +JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp) +{ + return Jsvalify(fp->returnValue()); +} + +JS_PUBLIC_API(void) +JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval) +{ +#ifdef JS_METHODJIT + JS_ASSERT_IF(fp->isScriptFrame(), fp->script()->debugMode); +#endif + assertSameCompartment(cx, fp, rval); + fp->setReturnValue(Valueify(rval)); +} + +/************************************************************************/ + +JS_PUBLIC_API(const char *) +JS_GetScriptFilename(JSContext *cx, JSScript *script) +{ + return script->filename; +} + +JS_PUBLIC_API(uintN) +JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script) +{ + return script->lineno; +} + +JS_PUBLIC_API(uintN) +JS_GetScriptLineExtent(JSContext *cx, JSScript *script) +{ + return js_GetScriptLineExtent(script); +} + +JS_PUBLIC_API(JSVersion) +JS_GetScriptVersion(JSContext *cx, JSScript *script) +{ + return VersionNumber(script->getVersion()); +} + +/***************************************************************************/ + +JS_PUBLIC_API(void) +JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata) +{ + rt->globalDebugHooks.newScriptHook = hook; + rt->globalDebugHooks.newScriptHookData = callerdata; +} + +JS_PUBLIC_API(void) +JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook, + void *callerdata) +{ + rt->globalDebugHooks.destroyScriptHook = hook; + rt->globalDebugHooks.destroyScriptHookData = callerdata; +} + +/***************************************************************************/ + +JS_PUBLIC_API(JSBool) +JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp, + const jschar *chars, uintN length, + const char *filename, uintN lineno, + jsval *rval) +{ + JS_ASSERT_NOT_ON_TRACE(cx); + + if (!CheckDebugMode(cx)) + return false; + + JSObject *scobj = JS_GetFrameScopeChain(cx, fp); + if (!scobj) + return false; + + js::AutoCompartment ac(cx, scobj); + if (!ac.enter()) + return false; + + /* + * NB: This function breaks the assumption that the compiler can see all + * calls and properly compute a static level. In order to get around this, + * we use a static level that will cause us not to attempt to optimize + * variable references made by this frame. + */ + JSScript *script = Compiler::compileScript(cx, scobj, fp, js_StackFramePrincipals(cx, fp), + TCF_COMPILE_N_GO, chars, length, + filename, lineno, cx->findVersion(), + NULL, UpvarCookie::UPVAR_LEVEL_LIMIT); + + if (!script) + return false; + + bool ok = Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL, Valueify(rval)); + + js_DestroyScript(cx, script); + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp, + const char *bytes, uintN length, + const char *filename, uintN lineno, + jsval *rval) +{ + jschar *chars; + JSBool ok; + size_t len = length; + + if (!CheckDebugMode(cx)) + return JS_FALSE; + + chars = js_InflateString(cx, bytes, &len); + if (!chars) + return JS_FALSE; + length = (uintN) len; + ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length, filename, lineno, + rval); + cx->free(chars); + + return ok; +} + +/************************************************************************/ + +/* This all should be reworked to avoid requiring JSScopeProperty types. */ + +JS_PUBLIC_API(JSScopeProperty *) +JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp) +{ + const Shape *shape; + + /* The caller passes null in *iteratorp to get things started. */ + shape = (Shape *) *iteratorp; + if (!shape) { + shape = obj->lastProperty(); + } else { + shape = shape->previous(); + if (!shape->previous()) { + JS_ASSERT(JSID_IS_EMPTY(shape->id)); + shape = NULL; + } + } + + return *iteratorp = reinterpret_cast(const_cast(shape)); +} + +JS_PUBLIC_API(JSBool) +JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, + JSPropertyDesc *pd) +{ + assertSameCompartment(cx, obj); + Shape *shape = (Shape *) sprop; + pd->id = IdToJsval(shape->id); + + JSBool wasThrowing = cx->isExceptionPending(); + Value lastException = UndefinedValue(); + if (wasThrowing) + lastException = cx->getPendingException(); + cx->clearPendingException(); + + if (!js_GetProperty(cx, obj, shape->id, Valueify(&pd->value))) { + if (!cx->isExceptionPending()) { + pd->flags = JSPD_ERROR; + pd->value = JSVAL_VOID; + } else { + pd->flags = JSPD_EXCEPTION; + pd->value = Jsvalify(cx->getPendingException()); + } + } else { + pd->flags = 0; + } + + if (wasThrowing) + cx->setPendingException(lastException); + + pd->flags |= (shape->enumerable() ? JSPD_ENUMERATE : 0) + | (!shape->writable() ? JSPD_READONLY : 0) + | (!shape->configurable() ? JSPD_PERMANENT : 0); + pd->spare = 0; + if (shape->getter() == GetCallArg) { + pd->slot = shape->shortid; + pd->flags |= JSPD_ARGUMENT; + } else if (shape->getter() == GetCallVar) { + pd->slot = shape->shortid; + pd->flags |= JSPD_VARIABLE; + } else { + pd->slot = 0; + } + pd->alias = JSVAL_VOID; + + if (obj->containsSlot(shape->slot)) { + for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) { + const Shape &aprop = r.front(); + if (&aprop != shape && aprop.slot == shape->slot) { + pd->alias = IdToJsval(aprop.id); + break; + } + } + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda) +{ + assertSameCompartment(cx, obj); + Class *clasp = obj->getClass(); + if (!obj->isNative() || (clasp->flags & JSCLASS_NEW_ENUMERATE)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_DESCRIBE_PROPS, clasp->name); + return JS_FALSE; + } + if (!clasp->enumerate(cx, obj)) + return JS_FALSE; + + /* Return an empty pda early if obj has no own properties. */ + if (obj->nativeEmpty()) { + pda->length = 0; + pda->array = NULL; + return JS_TRUE; + } + + uint32 n = obj->propertyCount(); + JSPropertyDesc *pd = (JSPropertyDesc *) cx->malloc(size_t(n) * sizeof(JSPropertyDesc)); + if (!pd) + return JS_FALSE; + uint32 i = 0; + for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) { + if (!js_AddRoot(cx, Valueify(&pd[i].id), NULL)) + goto bad; + if (!js_AddRoot(cx, Valueify(&pd[i].value), NULL)) + goto bad; + Shape *shape = const_cast(&r.front()); + if (!JS_GetPropertyDesc(cx, obj, reinterpret_cast(shape), &pd[i])) + goto bad; + if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, Valueify(&pd[i].alias), NULL)) + goto bad; + if (++i == n) + break; + } + pda->length = i; + pda->array = pd; + return JS_TRUE; + +bad: + pda->length = i + 1; + pda->array = pd; + JS_PutPropertyDescArray(cx, pda); + return JS_FALSE; +} + +JS_PUBLIC_API(void) +JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda) +{ + JSPropertyDesc *pd; + uint32 i; + + pd = pda->array; + for (i = 0; i < pda->length; i++) { + js_RemoveRoot(cx->runtime, &pd[i].id); + js_RemoveRoot(cx->runtime, &pd[i].value); + if (pd[i].flags & JSPD_ALIAS) + js_RemoveRoot(cx->runtime, &pd[i].alias); + } + cx->free(pd); +} + +/************************************************************************/ + +JS_PUBLIC_API(JSBool) +JS_SetDebuggerHandler(JSRuntime *rt, JSDebuggerHandler handler, void *closure) +{ + rt->globalDebugHooks.debuggerHandler = handler; + rt->globalDebugHooks.debuggerHandlerData = closure; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure) +{ + rt->globalDebugHooks.sourceHandler = handler; + rt->globalDebugHooks.sourceHandlerData = closure; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure) +{ + rt->globalDebugHooks.executeHook = hook; + rt->globalDebugHooks.executeHookData = closure; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure) +{ +#ifdef JS_TRACER + { + AutoLockGC lock(rt); + bool wasInhibited = rt->debuggerInhibitsJIT(); +#endif + rt->globalDebugHooks.callHook = hook; + rt->globalDebugHooks.callHookData = closure; +#ifdef JS_TRACER + JITInhibitingHookChange(rt, wasInhibited); + } +#endif + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_SetThrowHook(JSRuntime *rt, JSThrowHook hook, void *closure) +{ + rt->globalDebugHooks.throwHook = hook; + rt->globalDebugHooks.throwHookData = closure; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure) +{ + rt->globalDebugHooks.debugErrorHook = hook; + rt->globalDebugHooks.debugErrorHookData = closure; + return JS_TRUE; +} + +/************************************************************************/ + +JS_PUBLIC_API(size_t) +JS_GetObjectTotalSize(JSContext *cx, JSObject *obj) +{ + return obj->slotsAndStructSize(); +} + +static size_t +GetAtomTotalSize(JSContext *cx, JSAtom *atom) +{ + size_t nbytes; + + nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub); + nbytes += sizeof(JSString); + nbytes += (ATOM_TO_STRING(atom)->flatLength() + 1) * sizeof(jschar); + return nbytes; +} + +JS_PUBLIC_API(size_t) +JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun) +{ + size_t nbytes; + + nbytes = sizeof *fun; + nbytes += JS_GetObjectTotalSize(cx, FUN_OBJECT(fun)); + if (FUN_INTERPRETED(fun)) + nbytes += JS_GetScriptTotalSize(cx, fun->u.i.script); + if (fun->atom) + nbytes += GetAtomTotalSize(cx, fun->atom); + return nbytes; +} + +#include "jsemit.h" + +JS_PUBLIC_API(size_t) +JS_GetScriptTotalSize(JSContext *cx, JSScript *script) +{ + size_t nbytes, pbytes; + jsatomid i; + jssrcnote *sn, *notes; + JSObjectArray *objarray; + JSPrincipals *principals; + + nbytes = sizeof *script; + if (script->u.object) + nbytes += JS_GetObjectTotalSize(cx, script->u.object); + + nbytes += script->length * sizeof script->code[0]; + nbytes += script->atomMap.length * sizeof script->atomMap.vector[0]; + for (i = 0; i < script->atomMap.length; i++) + nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]); + + if (script->filename) + nbytes += strlen(script->filename) + 1; + + notes = script->notes(); + for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) + continue; + nbytes += (sn - notes + 1) * sizeof *sn; + + if (JSScript::isValidOffset(script->objectsOffset)) { + objarray = script->objects(); + i = objarray->length; + nbytes += sizeof *objarray + i * sizeof objarray->vector[0]; + do { + nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]); + } while (i != 0); + } + + if (JSScript::isValidOffset(script->regexpsOffset)) { + objarray = script->regexps(); + i = objarray->length; + nbytes += sizeof *objarray + i * sizeof objarray->vector[0]; + do { + nbytes += JS_GetObjectTotalSize(cx, objarray->vector[--i]); + } while (i != 0); + } + + if (JSScript::isValidOffset(script->trynotesOffset)) { + nbytes += sizeof(JSTryNoteArray) + + script->trynotes()->length * sizeof(JSTryNote); + } + + principals = script->principals; + if (principals) { + JS_ASSERT(principals->refcount); + pbytes = sizeof *principals; + if (principals->refcount > 1) + pbytes = JS_HOWMANY(pbytes, principals->refcount); + nbytes += pbytes; + } + + return nbytes; +} + +JS_PUBLIC_API(uint32) +JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp) +{ + if (!fp) + fp = js_GetTopStackFrame(cx); + while (fp) { + if (fp->isScriptFrame()) + return JS_GetScriptFilenameFlags(fp->script()); + fp = fp->prev(); + } + return 0; + } + +JS_PUBLIC_API(uint32) +JS_GetScriptFilenameFlags(JSScript *script) +{ + JS_ASSERT(script); + if (!script->filename) + return JSFILENAME_NULL; + return js_GetScriptFilenameFlags(script->filename); +} + +JS_PUBLIC_API(JSBool) +JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags) +{ + if (!js_SaveScriptFilenameRT(rt, prefix, flags)) + return JS_FALSE; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_IsSystemObject(JSContext *cx, JSObject *obj) +{ + return obj->isSystem(); +} + +JS_PUBLIC_API(JSBool) +JS_MakeSystemObject(JSContext *cx, JSObject *obj) +{ + obj->setSystem(); + return true; +} + +/************************************************************************/ + +JS_PUBLIC_API(JSObject *) +JS_UnwrapObject(JSContext *cx, JSObject *obj) +{ + return obj->unwrap(); +} + +/************************************************************************/ + +JS_FRIEND_API(void) +js_RevertVersion(JSContext *cx) +{ + cx->clearVersionOverride(); +} + +JS_PUBLIC_API(const JSDebugHooks *) +JS_GetGlobalDebugHooks(JSRuntime *rt) +{ + return &rt->globalDebugHooks; +} + +const JSDebugHooks js_NullDebugHooks = {}; + +JS_PUBLIC_API(JSDebugHooks *) +JS_SetContextDebugHooks(JSContext *cx, const JSDebugHooks *hooks) +{ + JS_ASSERT(hooks); + if (hooks != &cx->runtime->globalDebugHooks && hooks != &js_NullDebugHooks) + LeaveTrace(cx); + +#ifdef JS_TRACER + AutoLockGC lock(cx->runtime); +#endif + JSDebugHooks *old = const_cast(cx->debugHooks); + cx->debugHooks = hooks; +#ifdef JS_TRACER + cx->updateJITEnabled(); +#endif + return old; +} + +JS_PUBLIC_API(JSDebugHooks *) +JS_ClearContextDebugHooks(JSContext *cx) +{ + return JS_SetContextDebugHooks(cx, &js_NullDebugHooks); +} + +JS_PUBLIC_API(JSBool) +JS_StartProfiling() +{ + return Probes::startProfiling(); +} + +JS_PUBLIC_API(void) +JS_StopProfiling() +{ + Probes::stopProfiling(); +} + +#ifdef MOZ_PROFILING + +static JSBool +StartProfiling(JSContext *cx, uintN argc, jsval *vp) +{ + JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StartProfiling())); + return true; +} + +static JSBool +StopProfiling(JSContext *cx, uintN argc, jsval *vp) +{ + JS_StopProfiling(); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return true; +} + +#ifdef MOZ_SHARK + +static JSBool +IgnoreAndReturnTrue(JSContext *cx, uintN argc, jsval *vp) +{ + JS_SET_RVAL(cx, vp, JSVAL_TRUE); + return true; +} + +#endif + +static JSFunctionSpec profiling_functions[] = { + JS_FN("startProfiling", StartProfiling, 0,0), + JS_FN("stopProfiling", StopProfiling, 0,0), +#ifdef MOZ_SHARK + /* Keep users of the old shark API happy. */ + JS_FN("connectShark", IgnoreAndReturnTrue, 0,0), + JS_FN("disconnectShark", IgnoreAndReturnTrue, 0,0), + JS_FN("startShark", StartProfiling, 0,0), + JS_FN("stopShark", StopProfiling, 0,0), +#endif + JS_FS_END +}; + +#endif + +JS_PUBLIC_API(JSBool) +JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj) +{ +#ifdef MOZ_PROFILING + return JS_DefineFunctions(cx, obj, profiling_functions); +#else + return true; +#endif +} + +#ifdef MOZ_CALLGRIND + +#include + +JS_FRIEND_API(JSBool) +js_StartCallgrind(JSContext *cx, uintN argc, jsval *vp) +{ + CALLGRIND_START_INSTRUMENTATION; + CALLGRIND_ZERO_STATS; + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_StopCallgrind(JSContext *cx, uintN argc, jsval *vp) +{ + CALLGRIND_STOP_INSTRUMENTATION; + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + jsval *argv = JS_ARGV(cx, vp); + if (argc > 0 && JSVAL_IS_STRING(argv[0])) { + str = JSVAL_TO_STRING(argv[0]); + JSAutoByteString bytes(cx, str); + if (!!bytes) { + CALLGRIND_DUMP_STATS_AT(bytes.ptr()); + return JS_TRUE; + } + } + CALLGRIND_DUMP_STATS; + + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return JS_TRUE; +} + +#endif /* MOZ_CALLGRIND */ + +#ifdef MOZ_VTUNE +#include + +static const char *vtuneErrorMessages[] = { + "unknown, error #0", + "invalid 'max samples' field", + "invalid 'samples per buffer' field", + "invalid 'sample interval' field", + "invalid path", + "sample file in use", + "invalid 'number of events' field", + "unknown, error #7", + "internal error", + "bad event name", + "VTStopSampling called without calling VTStartSampling", + "no events selected for event-based sampling", + "events selected cannot be run together", + "no sampling parameters", + "sample database already exists", + "sampling already started", + "time-based sampling not supported", + "invalid 'sampling parameters size' field", + "invalid 'event size' field", + "sampling file already bound", + "invalid event path", + "invalid license", + "invalid 'global options' field", + +}; + +JS_FRIEND_API(JSBool) +js_StartVtune(JSContext *cx, uintN argc, jsval *vp) +{ + VTUNE_EVENT events[] = { + { 1000000, 0, 0, 0, "CPU_CLK_UNHALTED.CORE" }, + { 1000000, 0, 0, 0, "INST_RETIRED.ANY" }, + }; + + U32 n_events = sizeof(events) / sizeof(VTUNE_EVENT); + char *default_filename = "mozilla-vtune.tb5"; + JSString *str; + U32 status; + + VTUNE_SAMPLING_PARAMS params = { + sizeof(VTUNE_SAMPLING_PARAMS), + sizeof(VTUNE_EVENT), + 0, 0, /* Reserved fields */ + 1, /* Initialize in "paused" state */ + 0, /* Max samples, or 0 for "continuous" */ + 4096, /* Samples per buffer */ + 0.1, /* Sampling interval in ms */ + 1, /* 1 for event-based sampling, 0 for time-based */ + + n_events, + events, + default_filename, + }; + + jsval *argv = JS_ARGV(cx, vp); + if (argc > 0 && JSVAL_IS_STRING(argv[0])) { + str = JSVAL_TO_STRING(argv[0]); + params.tb5Filename = js_DeflateString(cx, str->chars(), str->length()); + } + + status = VTStartSampling(¶ms); + + if (params.tb5Filename != default_filename) + cx->free(params.tb5Filename); + + if (status != 0) { + if (status == VTAPI_MULTIPLE_RUNS) + VTStopSampling(0); + if (status < sizeof(vtuneErrorMessages)) + JS_ReportError(cx, "Vtune setup error: %s", + vtuneErrorMessages[status]); + else + JS_ReportError(cx, "Vtune setup error: %d", + status); + return false; + } + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return true; +} + +JS_FRIEND_API(JSBool) +js_StopVtune(JSContext *cx, uintN argc, jsval *vp) +{ + U32 status = VTStopSampling(1); + if (status) { + if (status < sizeof(vtuneErrorMessages)) + JS_ReportError(cx, "Vtune shutdown error: %s", + vtuneErrorMessages[status]); + else + JS_ReportError(cx, "Vtune shutdown error: %d", + status); + return false; + } + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return true; +} + +JS_FRIEND_API(JSBool) +js_PauseVtune(JSContext *cx, uintN argc, jsval *vp) +{ + VTPause(); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return true; +} + +JS_FRIEND_API(JSBool) +js_ResumeVtune(JSContext *cx, uintN argc, jsval *vp) +{ + VTResume(); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return true; +} + +#endif /* MOZ_VTUNE */ + +#ifdef MOZ_TRACEVIS +/* + * Ethogram - Javascript wrapper for TraceVis state + * + * ethology: The scientific study of animal behavior, + * especially as it occurs in a natural environment. + * ethogram: A pictorial catalog of the behavioral patterns of + * an organism or a species. + * + */ +#if defined(XP_WIN) +#include "jswin.h" +#else +#include +#endif +#include "jstracer.h" + +#define ETHOGRAM_BUF_SIZE 65536 + +static JSBool +ethogram_construct(JSContext *cx, uintN argc, jsval *vp); +static void +ethogram_finalize(JSContext *cx, JSObject *obj); + +static JSClass ethogram_class = { + "Ethogram", + JSCLASS_HAS_PRIVATE, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, ethogram_finalize, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +struct EthogramEvent { + TraceVisState s; + TraceVisExitReason r; + int ts; + int tus; + JSString *filename; + int lineno; +}; + +static int +compare_strings(const void *k1, const void *k2) +{ + return strcmp((const char *) k1, (const char *) k2) == 0; +} + +class EthogramEventBuffer { +private: + EthogramEvent mBuf[ETHOGRAM_BUF_SIZE]; + int mReadPos; + int mWritePos; + JSObject *mFilenames; + int mStartSecond; + + struct EthogramScriptEntry { + char *filename; + JSString *jsfilename; + + EthogramScriptEntry *next; + }; + EthogramScriptEntry *mScripts; + +public: + friend JSBool + ethogram_construct(JSContext *cx, uintN argc, jsval *vp); + + inline void push(TraceVisState s, TraceVisExitReason r, char *filename, int lineno) { + mBuf[mWritePos].s = s; + mBuf[mWritePos].r = r; +#if defined(XP_WIN) + FILETIME now; + GetSystemTimeAsFileTime(&now); + unsigned long long raw_us = 0.1 * + (((unsigned long long) now.dwHighDateTime << 32ULL) | + (unsigned long long) now.dwLowDateTime); + unsigned int sec = raw_us / 1000000L; + unsigned int usec = raw_us % 1000000L; + mBuf[mWritePos].ts = sec - mStartSecond; + mBuf[mWritePos].tus = usec; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + mBuf[mWritePos].ts = tv.tv_sec - mStartSecond; + mBuf[mWritePos].tus = tv.tv_usec; +#endif + + JSString *jsfilename = findScript(filename); + mBuf[mWritePos].filename = jsfilename; + mBuf[mWritePos].lineno = lineno; + + mWritePos = (mWritePos + 1) % ETHOGRAM_BUF_SIZE; + if (mWritePos == mReadPos) { + mReadPos = (mWritePos + 1) % ETHOGRAM_BUF_SIZE; + } + } + + inline EthogramEvent *pop() { + EthogramEvent *e = &mBuf[mReadPos]; + mReadPos = (mReadPos + 1) % ETHOGRAM_BUF_SIZE; + return e; + } + + bool isEmpty() { + return (mReadPos == mWritePos); + } + + EthogramScriptEntry *addScript(JSContext *cx, JSObject *obj, char *filename, JSString *jsfilename) { + JSHashNumber hash = JS_HashString(filename); + JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename); + if (*hep != NULL) + return NULL; + + JS_HashTableRawAdd(traceVisScriptTable, hep, hash, filename, this); + + EthogramScriptEntry * entry = (EthogramScriptEntry *) JS_malloc(cx, sizeof(EthogramScriptEntry)); + if (entry == NULL) + return NULL; + + entry->next = mScripts; + mScripts = entry; + entry->filename = filename; + entry->jsfilename = jsfilename; + + return mScripts; + } + + void removeScripts(JSContext *cx) { + EthogramScriptEntry *se = mScripts; + while (se != NULL) { + char *filename = se->filename; + + JSHashNumber hash = JS_HashString(filename); + JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename); + JSHashEntry *he = *hep; + if (he) { + /* we hardly knew he */ + JS_HashTableRawRemove(traceVisScriptTable, hep, he); + } + + EthogramScriptEntry *se_head = se; + se = se->next; + JS_free(cx, se_head); + } + } + + JSString *findScript(char *filename) { + EthogramScriptEntry *se = mScripts; + while (se != NULL) { + if (compare_strings(se->filename, filename)) + return (se->jsfilename); + se = se->next; + } + return NULL; + } + + JSObject *filenames() { + return mFilenames; + } + + int length() { + if (mWritePos < mReadPos) + return (mWritePos + ETHOGRAM_BUF_SIZE) - mReadPos; + else + return mWritePos - mReadPos; + } +}; + +static char jstv_empty[] = ""; + +inline char * +jstv_Filename(JSStackFrame *fp) +{ + while (fp && !fp->isScriptFrame()) + fp = fp->prev(); + return (fp && fp->maybeScript() && fp->script()->filename) + ? (char *)fp->script()->filename + : jstv_empty; +} +inline uintN +jstv_Lineno(JSContext *cx, JSStackFrame *fp) +{ + while (fp && fp->pc(cx) == NULL) + fp = fp->prev(); + return (fp && fp->pc(cx)) ? js_FramePCToLineNumber(cx, fp) : 0; +} + +/* Collect states here and distribute to a matching buffer, if any */ +JS_FRIEND_API(void) +js::StoreTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r) +{ + JSStackFrame *fp = cx->fp(); + + char *script_file = jstv_Filename(fp); + JSHashNumber hash = JS_HashString(script_file); + + JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, script_file); + /* update event buffer, flag if overflowed */ + JSHashEntry *he = *hep; + if (he) { + EthogramEventBuffer *p; + p = (EthogramEventBuffer *) he->value; + + p->push(s, r, script_file, jstv_Lineno(cx, fp)); + } +} + +static JSBool +ethogram_construct(JSContext *cx, uintN argc, jsval *vp) +{ + EthogramEventBuffer *p; + + p = (EthogramEventBuffer *) JS_malloc(cx, sizeof(EthogramEventBuffer)); + if (!p) + return JS_FALSE; + + p->mReadPos = p->mWritePos = 0; + p->mScripts = NULL; + p->mFilenames = JS_NewArrayObject(cx, 0, NULL); + +#if defined(XP_WIN) + FILETIME now; + GetSystemTimeAsFileTime(&now); + unsigned long long raw_us = 0.1 * + (((unsigned long long) now.dwHighDateTime << 32ULL) | + (unsigned long long) now.dwLowDateTime); + unsigned int s = raw_us / 1000000L; + p->mStartSecond = s; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + p->mStartSecond = tv.tv_sec; +#endif + JSObject *obj; + if (JS_IsConstructing(cx, vp)) { + obj = JS_NewObject(cx, ðogram_class, NULL, NULL); + if (!obj) + return JS_FALSE; + } else { + obj = JS_THIS_OBJECT(cx, vp); + } + + jsval filenames = OBJECT_TO_JSVAL(p->filenames()); + if (!JS_DefineProperty(cx, obj, "filenames", filenames, + NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT)) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj)); + JS_SetPrivate(cx, obj, p); + return JS_TRUE; +} + +static void +ethogram_finalize(JSContext *cx, JSObject *obj) +{ + EthogramEventBuffer *p; + p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, ðogram_class, NULL); + if (!p) + return; + + p->removeScripts(cx); + + JS_free(cx, p); +} + +static JSBool +ethogram_addScript(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + char *filename = NULL; + jsval *argv = JS_ARGV(cx, vp); + JSObject *obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return false; + if (argc < 1) { + /* silently ignore no args */ + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return true; + } + if (JSVAL_IS_STRING(argv[0])) { + str = JSVAL_TO_STRING(argv[0]); + filename = js_DeflateString(cx, str->chars(), str->length()); + if (!filename) + return false; + } + + EthogramEventBuffer *p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, ðogram_class, argv); + + p->addScript(cx, obj, filename, str); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + jsval dummy; + JS_CallFunctionName(cx, p->filenames(), "push", 1, argv, &dummy); + return true; +} + +static JSBool +ethogram_getAllEvents(JSContext *cx, uintN argc, jsval *vp) +{ + EthogramEventBuffer *p; + jsval *argv = JS_ARGV(cx, vp); + + JSObject *obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + + p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, ðogram_class, argv); + if (!p) + return JS_FALSE; + + if (p->isEmpty()) { + JS_SET_RVAL(cx, vp, JSVAL_NULL); + return JS_TRUE; + } + + JSObject *rarray = JS_NewArrayObject(cx, 0, NULL); + if (rarray == NULL) { + JS_SET_RVAL(cx, vp, JSVAL_NULL); + return JS_TRUE; + } + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(rarray)); + + for (int i = 0; !p->isEmpty(); i++) { + + JSObject *x = JS_NewObject(cx, NULL, NULL, NULL); + if (x == NULL) + return JS_FALSE; + + EthogramEvent *e = p->pop(); + + jsval state = INT_TO_JSVAL(e->s); + jsval reason = INT_TO_JSVAL(e->r); + jsval ts = INT_TO_JSVAL(e->ts); + jsval tus = INT_TO_JSVAL(e->tus); + + jsval filename = STRING_TO_JSVAL(e->filename); + jsval lineno = INT_TO_JSVAL(e->lineno); + + if (!JS_SetProperty(cx, x, "state", &state)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "reason", &reason)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "ts", &ts)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "tus", &tus)) + return JS_FALSE; + + if (!JS_SetProperty(cx, x, "filename", &filename)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "lineno", &lineno)) + return JS_FALSE; + + jsval element = OBJECT_TO_JSVAL(x); + JS_SetElement(cx, rarray, i, &element); + } + + return JS_TRUE; +} + +static JSBool +ethogram_getNextEvent(JSContext *cx, uintN argc, jsval *vp) +{ + EthogramEventBuffer *p; + jsval *argv = JS_ARGV(cx, vp); + + JSObject *obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + + p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, ðogram_class, argv); + if (!p) + return JS_FALSE; + + JSObject *x = JS_NewObject(cx, NULL, NULL, NULL); + if (x == NULL) + return JS_FALSE; + + if (p->isEmpty()) { + JS_SET_RVAL(cx, vp, JSVAL_NULL); + return JS_TRUE; + } + + EthogramEvent *e = p->pop(); + jsval state = INT_TO_JSVAL(e->s); + jsval reason = INT_TO_JSVAL(e->r); + jsval ts = INT_TO_JSVAL(e->ts); + jsval tus = INT_TO_JSVAL(e->tus); + + jsval filename = STRING_TO_JSVAL(e->filename); + jsval lineno = INT_TO_JSVAL(e->lineno); + + if (!JS_SetProperty(cx, x, "state", &state)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "reason", &reason)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "ts", &ts)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "tus", &tus)) + return JS_FALSE; + if (!JS_SetProperty(cx, x, "filename", &filename)) + return JS_FALSE; + + if (!JS_SetProperty(cx, x, "lineno", &lineno)) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(x)); + + return JS_TRUE; +} + +static JSFunctionSpec ethogram_methods[] = { + JS_FN("addScript", ethogram_addScript, 1,0), + JS_FN("getAllEvents", ethogram_getAllEvents, 0,0), + JS_FN("getNextEvent", ethogram_getNextEvent, 0,0), + JS_FS_END +}; + +/* + * An |Ethogram| organizes the output of a collection of files that should be + * monitored together. A single object gets events for the group. + */ +JS_FRIEND_API(JSBool) +js_InitEthogram(JSContext *cx, uintN argc, jsval *vp) +{ + if (!traceVisScriptTable) { + traceVisScriptTable = JS_NewHashTable(8, JS_HashString, compare_strings, + NULL, NULL, NULL); + } + + JS_InitClass(cx, JS_GetGlobalObject(cx), NULL, ðogram_class, + ethogram_construct, 0, NULL, ethogram_methods, + NULL, NULL); + + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return true; +} + +JS_FRIEND_API(JSBool) +js_ShutdownEthogram(JSContext *cx, uintN argc, jsval *vp) +{ + if (traceVisScriptTable) + JS_HashTableDestroy(traceVisScriptTable); + + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return true; +} + +#endif /* MOZ_TRACEVIS */ + +#ifdef MOZ_TRACE_JSCALLS + +JS_PUBLIC_API(void) +JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb) +{ + cx->functionCallback = fcb; +} + +JS_PUBLIC_API(JSFunctionCallback) +JS_GetFunctionCallback(JSContext *cx) +{ + return cx->functionCallback; +} + +#endif /* MOZ_TRACE_JSCALLS */ + diff --git a/js/src/jsdbgapi.h b/js/src/jsdbgapi.h new file mode 100644 index 0000000..69208e8 --- /dev/null +++ b/js/src/jsdbgapi.h @@ -0,0 +1,626 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsdbgapi_h___ +#define jsdbgapi_h___ +/* + * JS debugger API. + */ +#include "jsapi.h" +#include "jsopcode.h" +#include "jsprvtd.h" + +JS_BEGIN_EXTERN_C + +extern JS_PUBLIC_API(JSCrossCompartmentCall *) +JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target); + +#ifdef __cplusplus +JS_END_EXTERN_C + +namespace JS { + +class JS_PUBLIC_API(AutoEnterScriptCompartment) +{ + JSCrossCompartmentCall *call; + + public: + AutoEnterScriptCompartment() : call(NULL) {} + + bool enter(JSContext *cx, JSScript *target); + + bool entered() const { return call != NULL; } + + ~AutoEnterScriptCompartment() { + if (call && call != reinterpret_cast(1)) + JS_LeaveCrossCompartmentCall(call); + } +}; + +} /* namespace JS */ + +JS_BEGIN_EXTERN_C +#endif + +extern JS_PUBLIC_API(JSScript *) +JS_GetScriptFromObject(JSObject *scriptObject); + +extern JS_PUBLIC_API(JSString *) +JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, uintN indent); + +/* + * Currently, we only support runtime-wide debugging. In the future, we should + * be able to support compartment-wide debugging. + */ +extern JS_PUBLIC_API(void) +JS_SetRuntimeDebugMode(JSRuntime *rt, JSBool debug); + +/* + * Debug mode is a compartment-wide mode that enables a debugger to attach + * to and interact with running methodjit-ed frames. In particular, it causes + * every function to be compiled as if an eval was present (so eval-in-frame) + * can work, and it ensures that functions can be re-JITed for other debug + * features. In general, it is not safe to interact with frames that were live + * before debug mode was enabled. For this reason, it is also not safe to + * enable debug mode while frames are live. + */ + +/* Get current state of debugging mode. */ +extern JS_PUBLIC_API(JSBool) +JS_GetDebugMode(JSContext *cx); + +/* + * Turn on/off debugging mode for a single compartment. This must be + * called from the main thread and the compartment must be associated + * with the main thread. + */ +JS_FRIEND_API(JSBool) +JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, JSBool debug); + +/* + * Turn on/off debugging mode for a context's compartment. + */ +JS_FRIEND_API(JSBool) +JS_SetDebugMode(JSContext *cx, JSBool debug); + +/* Turn on single step mode. Requires debug mode. */ +extern JS_FRIEND_API(JSBool) +js_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep); + +/* Turn on single step mode. */ +extern JS_PUBLIC_API(JSBool) +JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep); + +/* + * Unexported library-private helper used to unpatch all traps in a script. + * Returns script->code if script has no traps, else a JS_malloc'ed copy of + * script->code which the caller must JS_free, or null on JS_malloc OOM. + */ +extern jsbytecode * +js_UntrapScriptCode(JSContext *cx, JSScript *script); + +/* The closure argument will be marked. */ +extern JS_PUBLIC_API(JSBool) +JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc, + JSTrapHandler handler, jsval closure); + +extern JS_PUBLIC_API(JSOp) +JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc); + +extern JS_PUBLIC_API(void) +JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc, + JSTrapHandler *handlerp, jsval *closurep); + +extern JS_PUBLIC_API(void) +JS_ClearScriptTraps(JSContext *cx, JSScript *script); + +extern JS_PUBLIC_API(void) +JS_ClearAllTraps(JSContext *cx); + +extern JS_PUBLIC_API(JSTrapStatus) +JS_HandleTrap(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_SetInterrupt(JSRuntime *rt, JSInterruptHook handler, void *closure); + +extern JS_PUBLIC_API(JSBool) +JS_ClearInterrupt(JSRuntime *rt, JSInterruptHook *handlerp, void **closurep); + +/************************************************************************/ + +extern JS_PUBLIC_API(JSBool) +JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id, + JSWatchPointHandler handler, JSObject *closure); + +extern JS_PUBLIC_API(JSBool) +JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsid id, + JSWatchPointHandler *handlerp, JSObject **closurep); + +extern JS_PUBLIC_API(JSBool) +JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(JSBool) +JS_ClearAllWatchPoints(JSContext *cx); + +#ifdef JS_HAS_OBJ_WATCHPOINT +/* + * Hide these non-API function prototypes by testing whether the internal + * header file "jsversion.h" has been included. + */ +extern void +js_TraceWatchPoints(JSTracer *trc, JSObject *obj); + +extern void +js_SweepWatchPoints(JSContext *cx); + +#ifdef __cplusplus + +extern JSBool +js_watch_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp); + +namespace js { + +bool +IsWatchedProperty(JSContext *cx, const Shape *shape); + +} + +#endif + +#endif /* JS_HAS_OBJ_WATCHPOINT */ + +/************************************************************************/ + +extern JS_PUBLIC_API(uintN) +JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc); + +extern JS_PUBLIC_API(jsbytecode *) +JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno); + +extern JS_PUBLIC_API(jsbytecode *) +JS_EndPC(JSContext *cx, JSScript *script); + +extern JS_PUBLIC_API(uintN) +JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun); + +extern JS_PUBLIC_API(JSBool) +JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun); + +/* + * N.B. The mark is in the context temp pool and thus the caller must take care + * to call JS_ReleaseFunctionLocalNameArray in a LIFO manner (wrt to any other + * call that may use the temp pool. + */ +extern JS_PUBLIC_API(jsuword *) +JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp); + +extern JS_PUBLIC_API(JSAtom *) +JS_LocalNameToAtom(jsuword w); + +extern JS_PUBLIC_API(JSString *) +JS_AtomKey(JSAtom *atom); + +extern JS_PUBLIC_API(void) +JS_ReleaseFunctionLocalNameArray(JSContext *cx, void *mark); + +extern JS_PUBLIC_API(JSScript *) +JS_GetFunctionScript(JSContext *cx, JSFunction *fun); + +extern JS_PUBLIC_API(JSNative) +JS_GetFunctionNative(JSContext *cx, JSFunction *fun); + +extern JS_PUBLIC_API(JSPrincipals *) +JS_GetScriptPrincipals(JSContext *cx, JSScript *script); + +/* + * Stack Frame Iterator + * + * Used to iterate through the JS stack frames to extract + * information from the frames. + */ + +extern JS_PUBLIC_API(JSStackFrame *) +JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp); + +extern JS_PUBLIC_API(JSScript *) +JS_GetFrameScript(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(jsbytecode *) +JS_GetFramePC(JSContext *cx, JSStackFrame *fp); + +/* + * Get the closest scripted frame below fp. If fp is null, start from cx->fp. + */ +extern JS_PUBLIC_API(JSStackFrame *) +JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp); + +/* + * Return a weak reference to fp's principals. A null return does not denote + * an error, it means there are no principals. + */ +extern JSPrincipals * +js_StackFramePrincipals(JSContext *cx, JSStackFrame *fp); + +JSPrincipals * +js_EvalFramePrincipals(JSContext *cx, JSObject *callee, JSStackFrame *caller); + +extern JS_PUBLIC_API(void *) +JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(void) +JS_SetFrameAnnotation(JSContext *cx, JSStackFrame *fp, void *annotation); + +extern JS_PUBLIC_API(void *) +JS_GetFramePrincipalArray(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(JSBool) +JS_IsScriptFrame(JSContext *cx, JSStackFrame *fp); + +/* this is deprecated, use JS_GetFrameScopeChain instead */ +extern JS_PUBLIC_API(JSObject *) +JS_GetFrameObject(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(JSObject *) +JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(JSObject *) +JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(JSBool) +JS_GetFrameThis(JSContext *cx, JSStackFrame *fp, jsval *thisv); + +extern JS_PUBLIC_API(JSFunction *) +JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(JSObject *) +JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp); + +/* XXXrginda Initially published with typo */ +#define JS_IsContructorFrame JS_IsConstructorFrame +extern JS_PUBLIC_API(JSBool) +JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(JSBool) +JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(jsval) +JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp); + +extern JS_PUBLIC_API(void) +JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval); + +/** + * Return fp's callee function object (fp->callee) if it has one. Note that + * this API cannot fail. A null return means "no callee": fp is a global or + * eval-from-global frame, not a call frame. + * + * This API began life as an infallible getter, but now it can return either: + * + * 1. An optimized closure that was compiled assuming the function could not + * escape and be called from sites the compiler could not see. + * + * 2. A "joined function object", an optimization whereby SpiderMonkey avoids + * creating fresh function objects for every evaluation of a function + * expression that is used only once by a consumer that either promises to + * clone later when asked for the value or that cannot leak the value. + * + * Because Mozilla's Gecko embedding of SpiderMonkey (and no doubt other + * embeddings) calls this API in potentially performance-sensitive ways (e.g. + * in nsContentUtils::GetDocumentFromCaller), we are leaving this API alone. It + * may now return an unwrapped non-escaping optimized closure, or a joined + * function object. Such optimized objects may work well if called from the + * correct context, never mutated or compared for identity, etc. + * + * However, if you really need to get the same callee object that JS code would + * see, which means undoing the optimizations, where an undo attempt can fail, + * then use JS_GetValidFrameCalleeObject. + */ +extern JS_PUBLIC_API(JSObject *) +JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp); + +/** + * Return fp's callee function object after running the deferred closure + * cloning "method read barrier". This API can fail! If the frame has no + * callee, this API returns true with JSVAL_IS_VOID(*vp). + */ +extern JS_PUBLIC_API(JSBool) +JS_GetValidFrameCalleeObject(JSContext *cx, JSStackFrame *fp, jsval *vp); + +/************************************************************************/ + +extern JS_PUBLIC_API(const char *) +JS_GetScriptFilename(JSContext *cx, JSScript *script); + +extern JS_PUBLIC_API(uintN) +JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script); + +extern JS_PUBLIC_API(uintN) +JS_GetScriptLineExtent(JSContext *cx, JSScript *script); + +extern JS_PUBLIC_API(JSVersion) +JS_GetScriptVersion(JSContext *cx, JSScript *script); + +/************************************************************************/ + +/* + * Hook setters for script creation and destruction, see jsprvtd.h for the + * typedefs. These macros provide binary compatibility and newer, shorter + * synonyms. + */ +#define JS_SetNewScriptHook JS_SetNewScriptHookProc +#define JS_SetDestroyScriptHook JS_SetDestroyScriptHookProc + +extern JS_PUBLIC_API(void) +JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata); + +extern JS_PUBLIC_API(void) +JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook, + void *callerdata); + +/************************************************************************/ + +extern JS_PUBLIC_API(JSBool) +JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp, + const jschar *chars, uintN length, + const char *filename, uintN lineno, + jsval *rval); + +extern JS_PUBLIC_API(JSBool) +JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp, + const char *bytes, uintN length, + const char *filename, uintN lineno, + jsval *rval); + +/************************************************************************/ + +typedef struct JSPropertyDesc { + jsval id; /* primary id, atomized string, or int */ + jsval value; /* property value */ + uint8 flags; /* flags, see below */ + uint8 spare; /* unused */ + uint16 slot; /* argument/variable slot */ + jsval alias; /* alias id if JSPD_ALIAS flag */ +} JSPropertyDesc; + +#define JSPD_ENUMERATE 0x01 /* visible to for/in loop */ +#define JSPD_READONLY 0x02 /* assignment is error */ +#define JSPD_PERMANENT 0x04 /* property cannot be deleted */ +#define JSPD_ALIAS 0x08 /* property has an alias id */ +#define JSPD_ARGUMENT 0x10 /* argument to function */ +#define JSPD_VARIABLE 0x20 /* local variable in function */ +#define JSPD_EXCEPTION 0x40 /* exception occurred fetching the property, */ + /* value is exception */ +#define JSPD_ERROR 0x80 /* native getter returned JS_FALSE without */ + /* throwing an exception */ + +typedef struct JSPropertyDescArray { + uint32 length; /* number of elements in array */ + JSPropertyDesc *array; /* alloc'd by Get, freed by Put */ +} JSPropertyDescArray; + +typedef struct JSScopeProperty JSScopeProperty; + +extern JS_PUBLIC_API(JSScopeProperty *) +JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp); + +extern JS_PUBLIC_API(JSBool) +JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *shape, + JSPropertyDesc *pd); + +extern JS_PUBLIC_API(JSBool) +JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda); + +extern JS_PUBLIC_API(void) +JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda); + +/************************************************************************/ + +extern JS_PUBLIC_API(JSBool) +JS_SetDebuggerHandler(JSRuntime *rt, JSDebuggerHandler hook, void *closure); + +extern JS_PUBLIC_API(JSBool) +JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure); + +extern JS_PUBLIC_API(JSBool) +JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure); + +extern JS_PUBLIC_API(JSBool) +JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure); + +extern JS_PUBLIC_API(JSBool) +JS_SetThrowHook(JSRuntime *rt, JSThrowHook hook, void *closure); + +extern JS_PUBLIC_API(JSBool) +JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure); + +/************************************************************************/ + +extern JS_PUBLIC_API(size_t) +JS_GetObjectTotalSize(JSContext *cx, JSObject *obj); + +extern JS_PUBLIC_API(size_t) +JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun); + +extern JS_PUBLIC_API(size_t) +JS_GetScriptTotalSize(JSContext *cx, JSScript *script); + +/* + * Get the top-most running script on cx starting from fp, or from the top of + * cx's frame stack if fp is null, and return its script filename flags. If + * the script has a null filename member, return JSFILENAME_NULL. + */ +extern JS_PUBLIC_API(uint32) +JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp); + +/* + * Get the script filename flags for the script. If the script doesn't have a + * filename, return JSFILENAME_NULL. + */ +extern JS_PUBLIC_API(uint32) +JS_GetScriptFilenameFlags(JSScript *script); + +/* + * Associate flags with a script filename prefix in rt, so that any subsequent + * script compilation will inherit those flags if the script's filename is the + * same as prefix, or if prefix is a substring of the script's filename. + * + * The API defines only one flag bit, JSFILENAME_SYSTEM, leaving the remaining + * 31 bits up to the API client to define. The union of all 32 bits must not + * be a legal combination, however, in order to preserve JSFILENAME_NULL as a + * unique value. API clients may depend on JSFILENAME_SYSTEM being a set bit + * in JSFILENAME_NULL -- a script with a null filename member is presumed to + * be a "system" script. + */ +extern JS_PUBLIC_API(JSBool) +JS_FlagScriptFilenamePrefix(JSRuntime *rt, const char *prefix, uint32 flags); + +#define JSFILENAME_NULL 0xffffffff /* null script filename */ +#define JSFILENAME_SYSTEM 0x00000001 /* "system" script, see below */ +#define JSFILENAME_PROTECTED 0x00000002 /* scripts need protection */ + +/* + * Return true if obj is a "system" object, that is, one created by + * JS_NewSystemObject with the system flag set and not JS_NewObject. + * + * What "system" means is up to the API client, but it can be used to implement + * access control policies based on script filenames and their prefixes, using + * JS_FlagScriptFilenamePrefix and JS_GetTopScriptFilenameFlags. + */ +extern JS_PUBLIC_API(JSBool) +JS_IsSystemObject(JSContext *cx, JSObject *obj); + +/* + * Mark an object as being a system object. This should be called immediately + * after allocating the object. A system object is an object for which + * JS_IsSystemObject returns true. + */ +extern JS_PUBLIC_API(JSBool) +JS_MakeSystemObject(JSContext *cx, JSObject *obj); + +/************************************************************************/ + +extern JS_PUBLIC_API(JSObject *) +JS_UnwrapObject(JSContext *cx, JSObject *obj); + +/************************************************************************/ + +extern JS_FRIEND_API(void) +js_RevertVersion(JSContext *cx); + +extern JS_PUBLIC_API(const JSDebugHooks *) +JS_GetGlobalDebugHooks(JSRuntime *rt); + +extern JS_PUBLIC_API(JSDebugHooks *) +JS_SetContextDebugHooks(JSContext *cx, const JSDebugHooks *hooks); + +/* Disable debug hooks for this context. */ +extern JS_PUBLIC_API(JSDebugHooks *) +JS_ClearContextDebugHooks(JSContext *cx); + +extern JS_PUBLIC_API(JSBool) +JS_StartProfiling(); + +extern JS_PUBLIC_API(void) +JS_StopProfiling(); + +extern JS_PUBLIC_API(JSBool) +JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj); + +#ifdef MOZ_CALLGRIND + +extern JS_FRIEND_API(JSBool) +js_StopCallgrind(JSContext *cx, uintN argc, jsval *vp); + +extern JS_FRIEND_API(JSBool) +js_StartCallgrind(JSContext *cx, uintN argc, jsval *vp); + +extern JS_FRIEND_API(JSBool) +js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp); + +#endif /* MOZ_CALLGRIND */ + +#ifdef MOZ_VTUNE + +extern JS_FRIEND_API(JSBool) +js_StartVtune(JSContext *cx, uintN argc, jsval *vp); + +extern JS_FRIEND_API(JSBool) +js_StopVtune(JSContext *cx, uintN argc, jsval *vp); + +extern JS_FRIEND_API(JSBool) +js_PauseVtune(JSContext *cx, uintN argc, jsval *vp); + +extern JS_FRIEND_API(JSBool) +js_ResumeVtune(JSContext *cx, uintN argc, jsval *vp); + +#endif /* MOZ_VTUNE */ + +#ifdef MOZ_TRACEVIS +extern JS_FRIEND_API(JSBool) +js_InitEthogram(JSContext *cx, uintN argc, jsval *vp); +extern JS_FRIEND_API(JSBool) +js_ShutdownEthogram(JSContext *cx, uintN argc, jsval *vp); +#endif /* MOZ_TRACEVIS */ + +#ifdef MOZ_TRACE_JSCALLS +typedef void (*JSFunctionCallback)(const JSFunction *fun, + const JSScript *scr, + const JSContext *cx, + int entering); + +/* + * The callback is expected to be quick and noninvasive. It should not + * trigger interrupts, turn on debugging, or produce uncaught JS + * exceptions. The state of the stack and registers in the context + * cannot be relied upon, since this callback may be invoked directly + * from either JIT. The 'entering' field means we are entering a + * function if it is positive, leaving a function if it is zero or + * negative. + */ +extern JS_PUBLIC_API(void) +JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb); + +extern JS_PUBLIC_API(JSFunctionCallback) +JS_GetFunctionCallback(JSContext *cx); +#endif /* MOZ_TRACE_JSCALLS */ + +JS_END_EXTERN_C + +#endif /* jsdbgapi_h___ */ diff --git a/js/src/jsdbgapiinlines.h b/js/src/jsdbgapiinlines.h new file mode 100644 index 0000000..b469ee2 --- /dev/null +++ b/js/src/jsdbgapiinlines.h @@ -0,0 +1,68 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jim Blandy (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsdbgapiinlines_h___ +#define jsdbgapiinlines_h___ + +#include "jsdbgapi.h" +#include "jscntxt.h" + +#if defined(JS_HAS_OBJ_WATCHPOINT) && defined(__cplusplus) + +extern const js::Shape * +js_SlowPathUpdateWatchpointsForShape(JSContext *cx, JSObject *obj, const js::Shape *newShape); + +/* + * Update any watchpoints on |obj| on |newShape->id| to use |newShape|. Property-manipulating + * functions must call this any time it takes on a new shape to represent a potentially + * watched property, or when it mutates a shape's attributes/setter/getter. + */ +static inline const js::Shape * +js_UpdateWatchpointsForShape(JSContext *cx, JSObject *obj, const js::Shape *newShape) +{ + if (JS_CLIST_IS_EMPTY(&cx->runtime->watchPointList)) + return newShape; + + return js_SlowPathUpdateWatchpointsForShape(cx, obj, newShape); +} + +#endif /* JS_HAS_OBJ_WATCHPOINT && __cplusplus */ + +#endif /* jsdbgapiinlines_h__ */ diff --git a/js/src/jsdhash.cpp b/js/src/jsdhash.cpp new file mode 100644 index 0000000..d19dea0 --- /dev/null +++ b/js/src/jsdhash.cpp @@ -0,0 +1,903 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla JavaScript code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (Original Author) + * Chris Waterson + * L. David Baron , Mozilla Corporation + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Double hashing implementation. + */ +#include +#include +#include +#include "jsstdint.h" +#include "jsbit.h" +#include "jsdhash.h" +#include "jsutil.h" /* for JS_ASSERT */ + +#ifdef JS_DHASHMETER +# if defined MOZILLA_CLIENT && defined DEBUG_XXXbrendan +# include "nsTraceMalloc.h" +# endif +# define METER(x) x +#else +# define METER(x) /* nothing */ +#endif + +/* + * The following DEBUG-only code is used to assert that calls to one of + * table->ops or to an enumerator do not cause re-entry into a call that + * can mutate the table. The recursion level is stored in additional + * space allocated at the end of the entry store to avoid changing + * JSDHashTable, which could cause issues when mixing DEBUG and + * non-DEBUG components. + */ +#ifdef DEBUG + +#define JSDHASH_ONELINE_ASSERT JS_ASSERT +#define RECURSION_LEVEL(table_) (*(uint32*)(table_->entryStore + \ + JS_DHASH_TABLE_SIZE(table_) * \ + table_->entrySize)) +/* + * Most callers that assert about the recursion level don't care about + * this magical value because they are asserting that mutation is + * allowed (and therefore the level is 0 or 1, depending on whether they + * incremented it). + * + * Only PL_DHashTableFinish needs to allow this special value. + */ +#define IMMUTABLE_RECURSION_LEVEL ((uint32)-1) + +#define RECURSION_LEVEL_SAFE_TO_FINISH(table_) \ + (RECURSION_LEVEL(table_) == 0 || \ + RECURSION_LEVEL(table_) == IMMUTABLE_RECURSION_LEVEL) + +#define ENTRY_STORE_EXTRA sizeof(uint32) +#define INCREMENT_RECURSION_LEVEL(table_) \ + JS_BEGIN_MACRO \ + if (RECURSION_LEVEL(table_) != IMMUTABLE_RECURSION_LEVEL) \ + ++RECURSION_LEVEL(table_); \ + JS_END_MACRO +#define DECREMENT_RECURSION_LEVEL(table_) \ + JS_BEGIN_MACRO \ + if (RECURSION_LEVEL(table_) != IMMUTABLE_RECURSION_LEVEL) { \ + JSDHASH_ONELINE_ASSERT(RECURSION_LEVEL(table_) > 0); \ + --RECURSION_LEVEL(table_); \ + } \ + JS_END_MACRO + +#else + +#define ENTRY_STORE_EXTRA 0 +#define INCREMENT_RECURSION_LEVEL(table_) JS_BEGIN_MACRO JS_END_MACRO +#define DECREMENT_RECURSION_LEVEL(table_) JS_BEGIN_MACRO JS_END_MACRO + +#endif /* defined(DEBUG) */ + +JS_PUBLIC_API(void *) +JS_DHashAllocTable(JSDHashTable *table, uint32 nbytes) +{ + return js_malloc(nbytes); +} + +JS_PUBLIC_API(void) +JS_DHashFreeTable(JSDHashTable *table, void *ptr) +{ + js_free(ptr); +} + +JS_PUBLIC_API(JSDHashNumber) +JS_DHashStringKey(JSDHashTable *table, const void *key) +{ + JSDHashNumber h; + const unsigned char *s; + + h = 0; + for (s = (const unsigned char *) key; *s != '\0'; s++) + h = JS_ROTATE_LEFT32(h, 4) ^ *s; + return h; +} + +JS_PUBLIC_API(JSDHashNumber) +JS_DHashVoidPtrKeyStub(JSDHashTable *table, const void *key) +{ + return (JSDHashNumber)(uintptr_t)key >> 2; +} + +JS_PUBLIC_API(JSBool) +JS_DHashMatchEntryStub(JSDHashTable *table, + const JSDHashEntryHdr *entry, + const void *key) +{ + const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry; + + return stub->key == key; +} + +JS_PUBLIC_API(JSBool) +JS_DHashMatchStringKey(JSDHashTable *table, + const JSDHashEntryHdr *entry, + const void *key) +{ + const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry; + + /* XXX tolerate null keys on account of sloppy Mozilla callers. */ + return stub->key == key || + (stub->key && key && + strcmp((const char *) stub->key, (const char *) key) == 0); +} + +JS_PUBLIC_API(void) +JS_DHashMoveEntryStub(JSDHashTable *table, + const JSDHashEntryHdr *from, + JSDHashEntryHdr *to) +{ + memcpy(to, from, table->entrySize); +} + +JS_PUBLIC_API(void) +JS_DHashClearEntryStub(JSDHashTable *table, JSDHashEntryHdr *entry) +{ + memset(entry, 0, table->entrySize); +} + +JS_PUBLIC_API(void) +JS_DHashFreeStringKey(JSDHashTable *table, JSDHashEntryHdr *entry) +{ + const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry; + + js_free((void *) stub->key); + memset(entry, 0, table->entrySize); +} + +JS_PUBLIC_API(void) +JS_DHashFinalizeStub(JSDHashTable *table) +{ +} + +static const JSDHashTableOps stub_ops = { + JS_DHashAllocTable, + JS_DHashFreeTable, + JS_DHashVoidPtrKeyStub, + JS_DHashMatchEntryStub, + JS_DHashMoveEntryStub, + JS_DHashClearEntryStub, + JS_DHashFinalizeStub, + NULL +}; + +JS_PUBLIC_API(const JSDHashTableOps *) +JS_DHashGetStubOps(void) +{ + return &stub_ops; +} + +JS_PUBLIC_API(JSDHashTable *) +JS_NewDHashTable(const JSDHashTableOps *ops, void *data, uint32 entrySize, + uint32 capacity) +{ + JSDHashTable *table; + + table = (JSDHashTable *) js_malloc(sizeof *table); + if (!table) + return NULL; + if (!JS_DHashTableInit(table, ops, data, entrySize, capacity)) { + js_free(table); + return NULL; + } + return table; +} + +JS_PUBLIC_API(void) +JS_DHashTableDestroy(JSDHashTable *table) +{ + JS_DHashTableFinish(table); + js_free(table); +} + +JS_PUBLIC_API(JSBool) +JS_DHashTableInit(JSDHashTable *table, const JSDHashTableOps *ops, void *data, + uint32 entrySize, uint32 capacity) +{ + int log2; + uint32 nbytes; + +#ifdef DEBUG + if (entrySize > 10 * sizeof(void *)) { + fprintf(stderr, + "jsdhash: for the table at address %p, the given entrySize" + " of %lu %s favors chaining over double hashing.\n", + (void *) table, + (unsigned long) entrySize, + (entrySize > 16 * sizeof(void*)) ? "definitely" : "probably"); + } +#endif + + table->ops = ops; + table->data = data; + if (capacity < JS_DHASH_MIN_SIZE) + capacity = JS_DHASH_MIN_SIZE; + + JS_CEILING_LOG2(log2, capacity); + + capacity = JS_BIT(log2); + if (capacity >= JS_DHASH_SIZE_LIMIT) + return JS_FALSE; + table->hashShift = JS_DHASH_BITS - log2; + table->maxAlphaFrac = (uint8)(0x100 * JS_DHASH_DEFAULT_MAX_ALPHA); + table->minAlphaFrac = (uint8)(0x100 * JS_DHASH_DEFAULT_MIN_ALPHA); + table->entrySize = entrySize; + table->entryCount = table->removedCount = 0; + table->generation = 0; + nbytes = capacity * entrySize; + + table->entryStore = (char *) ops->allocTable(table, + nbytes + ENTRY_STORE_EXTRA); + if (!table->entryStore) + return JS_FALSE; + memset(table->entryStore, 0, nbytes); + METER(memset(&table->stats, 0, sizeof table->stats)); + +#ifdef DEBUG + RECURSION_LEVEL(table) = 0; +#endif + + return JS_TRUE; +} + +/* + * Compute max and min load numbers (entry counts) from table params. + */ +#define MAX_LOAD(table, size) (((table)->maxAlphaFrac * (size)) >> 8) +#define MIN_LOAD(table, size) (((table)->minAlphaFrac * (size)) >> 8) + +JS_PUBLIC_API(void) +JS_DHashTableSetAlphaBounds(JSDHashTable *table, + float maxAlpha, + float minAlpha) +{ + uint32 size; + + /* + * Reject obviously insane bounds, rather than trying to guess what the + * buggy caller intended. + */ + JS_ASSERT(0.5 <= maxAlpha && maxAlpha < 1 && 0 <= minAlpha); + if (maxAlpha < 0.5 || 1 <= maxAlpha || minAlpha < 0) + return; + + /* + * Ensure that at least one entry will always be free. If maxAlpha at + * minimum size leaves no entries free, reduce maxAlpha based on minimum + * size and the precision limit of maxAlphaFrac's fixed point format. + */ + JS_ASSERT(JS_DHASH_MIN_SIZE - (maxAlpha * JS_DHASH_MIN_SIZE) >= 1); + if (JS_DHASH_MIN_SIZE - (maxAlpha * JS_DHASH_MIN_SIZE) < 1) { + maxAlpha = (float) + (JS_DHASH_MIN_SIZE - JS_MAX(JS_DHASH_MIN_SIZE / 256, 1)) + / JS_DHASH_MIN_SIZE; + } + + /* + * Ensure that minAlpha is strictly less than half maxAlpha. Take care + * not to truncate an entry's worth of alpha when storing in minAlphaFrac + * (8-bit fixed point format). + */ + JS_ASSERT(minAlpha < maxAlpha / 2); + if (minAlpha >= maxAlpha / 2) { + size = JS_DHASH_TABLE_SIZE(table); + minAlpha = (size * maxAlpha - JS_MAX(size / 256, 1)) / (2 * size); + } + + table->maxAlphaFrac = (uint8)(maxAlpha * 256); + table->minAlphaFrac = (uint8)(minAlpha * 256); +} + +/* + * Double hashing needs the second hash code to be relatively prime to table + * size, so we simply make hash2 odd. + */ +#define HASH1(hash0, shift) ((hash0) >> (shift)) +#define HASH2(hash0,log2,shift) ((((hash0) << (log2)) >> (shift)) | 1) + +/* + * Reserve keyHash 0 for free entries and 1 for removed-entry sentinels. Note + * that a removed-entry sentinel need be stored only if the removed entry had + * a colliding entry added after it. Therefore we can use 1 as the collision + * flag in addition to the removed-entry sentinel value. Multiplicative hash + * uses the high order bits of keyHash, so this least-significant reservation + * should not hurt the hash function's effectiveness much. + * + * If you change any of these magic numbers, also update JS_DHASH_ENTRY_IS_LIVE + * in jsdhash.h. It used to be private to jsdhash.c, but then became public to + * assist iterator writers who inspect table->entryStore directly. + */ +#define COLLISION_FLAG ((JSDHashNumber) 1) +#define MARK_ENTRY_FREE(entry) ((entry)->keyHash = 0) +#define MARK_ENTRY_REMOVED(entry) ((entry)->keyHash = 1) +#define ENTRY_IS_REMOVED(entry) ((entry)->keyHash == 1) +#define ENTRY_IS_LIVE(entry) JS_DHASH_ENTRY_IS_LIVE(entry) +#define ENSURE_LIVE_KEYHASH(hash0) if (hash0 < 2) hash0 -= 2; else (void)0 + +/* Match an entry's keyHash against an unstored one computed from a key. */ +#define MATCH_ENTRY_KEYHASH(entry,hash0) \ + (((entry)->keyHash & ~COLLISION_FLAG) == (hash0)) + +/* Compute the address of the indexed entry in table. */ +#define ADDRESS_ENTRY(table, index) \ + ((JSDHashEntryHdr *)((table)->entryStore + (index) * (table)->entrySize)) + +JS_PUBLIC_API(void) +JS_DHashTableFinish(JSDHashTable *table) +{ + char *entryAddr, *entryLimit; + uint32 entrySize; + JSDHashEntryHdr *entry; + +#ifdef DEBUG_XXXbrendan + static FILE *dumpfp = NULL; + if (!dumpfp) dumpfp = fopen("/tmp/jsdhash.bigdump", "w"); + if (dumpfp) { +#ifdef MOZILLA_CLIENT + NS_TraceStack(1, dumpfp); +#endif + JS_DHashTableDumpMeter(table, NULL, dumpfp); + fputc('\n', dumpfp); + } +#endif + + INCREMENT_RECURSION_LEVEL(table); + + /* Call finalize before clearing entries, so it can enumerate them. */ + table->ops->finalize(table); + + /* Clear any remaining live entries. */ + entryAddr = table->entryStore; + entrySize = table->entrySize; + entryLimit = entryAddr + JS_DHASH_TABLE_SIZE(table) * entrySize; + while (entryAddr < entryLimit) { + entry = (JSDHashEntryHdr *)entryAddr; + if (ENTRY_IS_LIVE(entry)) { + METER(table->stats.removeEnums++); + table->ops->clearEntry(table, entry); + } + entryAddr += entrySize; + } + + DECREMENT_RECURSION_LEVEL(table); + JS_ASSERT(RECURSION_LEVEL_SAFE_TO_FINISH(table)); + + /* Free entry storage last. */ + table->ops->freeTable(table, table->entryStore); +} + +static JSDHashEntryHdr * JS_DHASH_FASTCALL +SearchTable(JSDHashTable *table, const void *key, JSDHashNumber keyHash, + JSDHashOperator op) +{ + JSDHashNumber hash1, hash2; + int hashShift, sizeLog2; + JSDHashEntryHdr *entry, *firstRemoved; + JSDHashMatchEntry matchEntry; + uint32 sizeMask; + + METER(table->stats.searches++); + JS_ASSERT(!(keyHash & COLLISION_FLAG)); + + /* Compute the primary hash address. */ + hashShift = table->hashShift; + hash1 = HASH1(keyHash, hashShift); + entry = ADDRESS_ENTRY(table, hash1); + + /* Miss: return space for a new entry. */ + if (JS_DHASH_ENTRY_IS_FREE(entry)) { + METER(table->stats.misses++); + return entry; + } + + /* Hit: return entry. */ + matchEntry = table->ops->matchEntry; + if (MATCH_ENTRY_KEYHASH(entry, keyHash) && matchEntry(table, entry, key)) { + METER(table->stats.hits++); + return entry; + } + + /* Collision: double hash. */ + sizeLog2 = JS_DHASH_BITS - table->hashShift; + hash2 = HASH2(keyHash, sizeLog2, hashShift); + sizeMask = JS_BITMASK(sizeLog2); + + /* Save the first removed entry pointer so JS_DHASH_ADD can recycle it. */ + firstRemoved = NULL; + + for (;;) { + if (JS_UNLIKELY(ENTRY_IS_REMOVED(entry))) { + if (!firstRemoved) + firstRemoved = entry; + } else { + if (op == JS_DHASH_ADD) + entry->keyHash |= COLLISION_FLAG; + } + + METER(table->stats.steps++); + hash1 -= hash2; + hash1 &= sizeMask; + + entry = ADDRESS_ENTRY(table, hash1); + if (JS_DHASH_ENTRY_IS_FREE(entry)) { + METER(table->stats.misses++); + return (firstRemoved && op == JS_DHASH_ADD) ? firstRemoved : entry; + } + + if (MATCH_ENTRY_KEYHASH(entry, keyHash) && + matchEntry(table, entry, key)) { + METER(table->stats.hits++); + return entry; + } + } + + /* NOTREACHED */ + return NULL; +} + +/* + * This is a copy of SearchTable, used by ChangeTable, hardcoded to + * 1. assume |op == PL_DHASH_ADD|, + * 2. assume that |key| will never match an existing entry, and + * 3. assume that no entries have been removed from the current table + * structure. + * Avoiding the need for |key| means we can avoid needing a way to map + * entries to keys, which means callers can use complex key types more + * easily. + */ +static JSDHashEntryHdr * JS_DHASH_FASTCALL +FindFreeEntry(JSDHashTable *table, JSDHashNumber keyHash) +{ + JSDHashNumber hash1, hash2; + int hashShift, sizeLog2; + JSDHashEntryHdr *entry; + uint32 sizeMask; + + METER(table->stats.searches++); + JS_ASSERT(!(keyHash & COLLISION_FLAG)); + + /* Compute the primary hash address. */ + hashShift = table->hashShift; + hash1 = HASH1(keyHash, hashShift); + entry = ADDRESS_ENTRY(table, hash1); + + /* Miss: return space for a new entry. */ + if (JS_DHASH_ENTRY_IS_FREE(entry)) { + METER(table->stats.misses++); + return entry; + } + + /* Collision: double hash. */ + sizeLog2 = JS_DHASH_BITS - table->hashShift; + hash2 = HASH2(keyHash, sizeLog2, hashShift); + sizeMask = JS_BITMASK(sizeLog2); + + for (;;) { + JS_ASSERT(!ENTRY_IS_REMOVED(entry)); + entry->keyHash |= COLLISION_FLAG; + + METER(table->stats.steps++); + hash1 -= hash2; + hash1 &= sizeMask; + + entry = ADDRESS_ENTRY(table, hash1); + if (JS_DHASH_ENTRY_IS_FREE(entry)) { + METER(table->stats.misses++); + return entry; + } + } + + /* NOTREACHED */ + return NULL; +} + +static JSBool +ChangeTable(JSDHashTable *table, int deltaLog2) +{ + int oldLog2, newLog2; + uint32 oldCapacity, newCapacity; + char *newEntryStore, *oldEntryStore, *oldEntryAddr; + uint32 entrySize, i, nbytes; + JSDHashEntryHdr *oldEntry, *newEntry; + JSDHashMoveEntry moveEntry; +#ifdef DEBUG + uint32 recursionLevel; +#endif + + /* Look, but don't touch, until we succeed in getting new entry store. */ + oldLog2 = JS_DHASH_BITS - table->hashShift; + newLog2 = oldLog2 + deltaLog2; + oldCapacity = JS_BIT(oldLog2); + newCapacity = JS_BIT(newLog2); + if (newCapacity >= JS_DHASH_SIZE_LIMIT) + return JS_FALSE; + entrySize = table->entrySize; + nbytes = newCapacity * entrySize; + + newEntryStore = (char *) table->ops->allocTable(table, + nbytes + ENTRY_STORE_EXTRA); + if (!newEntryStore) + return JS_FALSE; + + /* We can't fail from here on, so update table parameters. */ +#ifdef DEBUG + recursionLevel = RECURSION_LEVEL(table); +#endif + table->hashShift = JS_DHASH_BITS - newLog2; + table->removedCount = 0; + table->generation++; + + /* Assign the new entry store to table. */ + memset(newEntryStore, 0, nbytes); + oldEntryAddr = oldEntryStore = table->entryStore; + table->entryStore = newEntryStore; + moveEntry = table->ops->moveEntry; +#ifdef DEBUG + RECURSION_LEVEL(table) = recursionLevel; +#endif + + /* Copy only live entries, leaving removed ones behind. */ + for (i = 0; i < oldCapacity; i++) { + oldEntry = (JSDHashEntryHdr *)oldEntryAddr; + if (ENTRY_IS_LIVE(oldEntry)) { + oldEntry->keyHash &= ~COLLISION_FLAG; + newEntry = FindFreeEntry(table, oldEntry->keyHash); + JS_ASSERT(JS_DHASH_ENTRY_IS_FREE(newEntry)); + moveEntry(table, oldEntry, newEntry); + newEntry->keyHash = oldEntry->keyHash; + } + oldEntryAddr += entrySize; + } + + table->ops->freeTable(table, oldEntryStore); + return JS_TRUE; +} + +JS_PUBLIC_API(JSDHashEntryHdr *) JS_DHASH_FASTCALL +JS_DHashTableOperate(JSDHashTable *table, const void *key, JSDHashOperator op) +{ + JSDHashNumber keyHash; + JSDHashEntryHdr *entry; + uint32 size; + int deltaLog2; + + JS_ASSERT(op == JS_DHASH_LOOKUP || RECURSION_LEVEL(table) == 0); + INCREMENT_RECURSION_LEVEL(table); + + keyHash = table->ops->hashKey(table, key); + keyHash *= JS_DHASH_GOLDEN_RATIO; + + /* Avoid 0 and 1 hash codes, they indicate free and removed entries. */ + ENSURE_LIVE_KEYHASH(keyHash); + keyHash &= ~COLLISION_FLAG; + + switch (op) { + case JS_DHASH_LOOKUP: + METER(table->stats.lookups++); + entry = SearchTable(table, key, keyHash, op); + break; + + case JS_DHASH_ADD: + /* + * If alpha is >= .75, grow or compress the table. If key is already + * in the table, we may grow once more than necessary, but only if we + * are on the edge of being overloaded. + */ + size = JS_DHASH_TABLE_SIZE(table); + if (table->entryCount + table->removedCount >= MAX_LOAD(table, size)) { + /* Compress if a quarter or more of all entries are removed. */ + if (table->removedCount >= size >> 2) { + METER(table->stats.compresses++); + deltaLog2 = 0; + } else { + METER(table->stats.grows++); + deltaLog2 = 1; + } + + /* + * Grow or compress table, returning null if ChangeTable fails and + * falling through might claim the last free entry. + */ + if (!ChangeTable(table, deltaLog2) && + table->entryCount + table->removedCount == size - 1) { + METER(table->stats.addFailures++); + entry = NULL; + break; + } + } + + /* + * Look for entry after possibly growing, so we don't have to add it, + * then skip it while growing the table and re-add it after. + */ + entry = SearchTable(table, key, keyHash, op); + if (!ENTRY_IS_LIVE(entry)) { + /* Initialize the entry, indicating that it's no longer free. */ + METER(table->stats.addMisses++); + if (ENTRY_IS_REMOVED(entry)) { + METER(table->stats.addOverRemoved++); + table->removedCount--; + keyHash |= COLLISION_FLAG; + } + if (table->ops->initEntry && + !table->ops->initEntry(table, entry, key)) { + /* We haven't claimed entry yet; fail with null return. */ + memset(entry + 1, 0, table->entrySize - sizeof *entry); + entry = NULL; + break; + } + entry->keyHash = keyHash; + table->entryCount++; + } + METER(else table->stats.addHits++); + break; + + case JS_DHASH_REMOVE: + entry = SearchTable(table, key, keyHash, op); + if (ENTRY_IS_LIVE(entry)) { + /* Clear this entry and mark it as "removed". */ + METER(table->stats.removeHits++); + JS_DHashTableRawRemove(table, entry); + + /* Shrink if alpha is <= .25 and table isn't too small already. */ + size = JS_DHASH_TABLE_SIZE(table); + if (size > JS_DHASH_MIN_SIZE && + table->entryCount <= MIN_LOAD(table, size)) { + METER(table->stats.shrinks++); + (void) ChangeTable(table, -1); + } + } + METER(else table->stats.removeMisses++); + entry = NULL; + break; + + default: + JS_ASSERT(0); + entry = NULL; + } + + DECREMENT_RECURSION_LEVEL(table); + + return entry; +} + +JS_PUBLIC_API(void) +JS_DHashTableRawRemove(JSDHashTable *table, JSDHashEntryHdr *entry) +{ + JSDHashNumber keyHash; /* load first in case clearEntry goofs it */ + + JS_ASSERT(RECURSION_LEVEL(table) != IMMUTABLE_RECURSION_LEVEL); + + JS_ASSERT(JS_DHASH_ENTRY_IS_LIVE(entry)); + keyHash = entry->keyHash; + table->ops->clearEntry(table, entry); + if (keyHash & COLLISION_FLAG) { + MARK_ENTRY_REMOVED(entry); + table->removedCount++; + } else { + METER(table->stats.removeFrees++); + MARK_ENTRY_FREE(entry); + } + table->entryCount--; +} + +JS_PUBLIC_API(uint32) +JS_DHashTableEnumerate(JSDHashTable *table, JSDHashEnumerator etor, void *arg) +{ + char *entryAddr, *entryLimit; + uint32 i, capacity, entrySize, ceiling; + JSBool didRemove; + JSDHashEntryHdr *entry; + JSDHashOperator op; + + INCREMENT_RECURSION_LEVEL(table); + + entryAddr = table->entryStore; + entrySize = table->entrySize; + capacity = JS_DHASH_TABLE_SIZE(table); + entryLimit = entryAddr + capacity * entrySize; + i = 0; + didRemove = JS_FALSE; + while (entryAddr < entryLimit) { + entry = (JSDHashEntryHdr *)entryAddr; + if (ENTRY_IS_LIVE(entry)) { + op = etor(table, entry, i++, arg); + if (op & JS_DHASH_REMOVE) { + METER(table->stats.removeEnums++); + JS_DHashTableRawRemove(table, entry); + didRemove = JS_TRUE; + } + if (op & JS_DHASH_STOP) + break; + } + entryAddr += entrySize; + } + + JS_ASSERT(!didRemove || RECURSION_LEVEL(table) == 1); + + /* + * Shrink or compress if a quarter or more of all entries are removed, or + * if the table is underloaded according to the configured minimum alpha, + * and is not minimal-size already. Do this only if we removed above, so + * non-removing enumerations can count on stable table->entryStore until + * the next non-lookup-Operate or removing-Enumerate. + */ + if (didRemove && + (table->removedCount >= capacity >> 2 || + (capacity > JS_DHASH_MIN_SIZE && + table->entryCount <= MIN_LOAD(table, capacity)))) { + METER(table->stats.enumShrinks++); + capacity = table->entryCount; + capacity += capacity >> 1; + if (capacity < JS_DHASH_MIN_SIZE) + capacity = JS_DHASH_MIN_SIZE; + + JS_CEILING_LOG2(ceiling, capacity); + ceiling -= JS_DHASH_BITS - table->hashShift; + + (void) ChangeTable(table, ceiling); + } + + DECREMENT_RECURSION_LEVEL(table); + + return i; +} + +#ifdef DEBUG +JS_PUBLIC_API(void) +JS_DHashMarkTableImmutable(JSDHashTable *table) +{ + RECURSION_LEVEL(table) = IMMUTABLE_RECURSION_LEVEL; +} +#endif + +#ifdef JS_DHASHMETER +#include + +JS_PUBLIC_API(void) +JS_DHashTableDumpMeter(JSDHashTable *table, JSDHashEnumerator dump, FILE *fp) +{ + char *entryAddr; + uint32 entrySize, entryCount; + int hashShift, sizeLog2; + uint32 i, tableSize, sizeMask, chainLen, maxChainLen, chainCount; + JSDHashNumber hash1, hash2, saveHash1, maxChainHash1, maxChainHash2; + double sqsum, mean, variance, sigma; + JSDHashEntryHdr *entry, *probe; + + entryAddr = table->entryStore; + entrySize = table->entrySize; + hashShift = table->hashShift; + sizeLog2 = JS_DHASH_BITS - hashShift; + tableSize = JS_DHASH_TABLE_SIZE(table); + sizeMask = JS_BITMASK(sizeLog2); + chainCount = maxChainLen = 0; + hash2 = 0; + sqsum = 0; + + for (i = 0; i < tableSize; i++) { + entry = (JSDHashEntryHdr *)entryAddr; + entryAddr += entrySize; + if (!ENTRY_IS_LIVE(entry)) + continue; + hash1 = HASH1(entry->keyHash & ~COLLISION_FLAG, hashShift); + saveHash1 = hash1; + probe = ADDRESS_ENTRY(table, hash1); + chainLen = 1; + if (probe == entry) { + /* Start of a (possibly unit-length) chain. */ + chainCount++; + } else { + hash2 = HASH2(entry->keyHash & ~COLLISION_FLAG, sizeLog2, + hashShift); + do { + chainLen++; + hash1 -= hash2; + hash1 &= sizeMask; + probe = ADDRESS_ENTRY(table, hash1); + } while (probe != entry); + } + sqsum += chainLen * chainLen; + if (chainLen > maxChainLen) { + maxChainLen = chainLen; + maxChainHash1 = saveHash1; + maxChainHash2 = hash2; + } + } + + entryCount = table->entryCount; + if (entryCount && chainCount) { + mean = (double)entryCount / chainCount; + variance = chainCount * sqsum - entryCount * entryCount; + if (variance < 0 || chainCount == 1) + variance = 0; + else + variance /= chainCount * (chainCount - 1); + sigma = sqrt(variance); + } else { + mean = sigma = 0; + } + + fprintf(fp, "Double hashing statistics:\n"); + fprintf(fp, " table size (in entries): %u\n", tableSize); + fprintf(fp, " number of entries: %u\n", table->entryCount); + fprintf(fp, " number of removed entries: %u\n", table->removedCount); + fprintf(fp, " number of searches: %u\n", table->stats.searches); + fprintf(fp, " number of hits: %u\n", table->stats.hits); + fprintf(fp, " number of misses: %u\n", table->stats.misses); + fprintf(fp, " mean steps per search: %g\n", table->stats.searches ? + (double)table->stats.steps + / table->stats.searches : + 0.); + fprintf(fp, " mean hash chain length: %g\n", mean); + fprintf(fp, " standard deviation: %g\n", sigma); + fprintf(fp, " maximum hash chain length: %u\n", maxChainLen); + fprintf(fp, " number of lookups: %u\n", table->stats.lookups); + fprintf(fp, " adds that made a new entry: %u\n", table->stats.addMisses); + fprintf(fp, "adds that recycled removeds: %u\n", table->stats.addOverRemoved); + fprintf(fp, " adds that found an entry: %u\n", table->stats.addHits); + fprintf(fp, " add failures: %u\n", table->stats.addFailures); + fprintf(fp, " useful removes: %u\n", table->stats.removeHits); + fprintf(fp, " useless removes: %u\n", table->stats.removeMisses); + fprintf(fp, "removes that freed an entry: %u\n", table->stats.removeFrees); + fprintf(fp, " removes while enumerating: %u\n", table->stats.removeEnums); + fprintf(fp, " number of grows: %u\n", table->stats.grows); + fprintf(fp, " number of shrinks: %u\n", table->stats.shrinks); + fprintf(fp, " number of compresses: %u\n", table->stats.compresses); + fprintf(fp, "number of enumerate shrinks: %u\n", table->stats.enumShrinks); + + if (dump && maxChainLen && hash2) { + fputs("Maximum hash chain:\n", fp); + hash1 = maxChainHash1; + hash2 = maxChainHash2; + entry = ADDRESS_ENTRY(table, hash1); + i = 0; + do { + if (dump(table, entry, i++, fp) != JS_DHASH_NEXT) + break; + hash1 -= hash2; + hash1 &= sizeMask; + entry = ADDRESS_ENTRY(table, hash1); + } while (JS_DHASH_ENTRY_IS_BUSY(entry)); + } +} +#endif /* JS_DHASHMETER */ diff --git a/js/src/jsdhash.h b/js/src/jsdhash.h new file mode 100644 index 0000000..13ab221 --- /dev/null +++ b/js/src/jsdhash.h @@ -0,0 +1,607 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla JavaScript code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsdhash_h___ +#define jsdhash_h___ +/* + * Double hashing, a la Knuth 6. + */ +#include "jstypes.h" + +JS_BEGIN_EXTERN_C + +#if defined(__GNUC__) && defined(__i386__) && (__GNUC__ >= 3) && !defined(XP_OS2) +#define JS_DHASH_FASTCALL __attribute__ ((regparm (3),stdcall)) +#elif defined(XP_WIN) +#define JS_DHASH_FASTCALL __fastcall +#else +#define JS_DHASH_FASTCALL +#endif + +#ifdef DEBUG_XXXbrendan +#define JS_DHASHMETER 1 +#endif + +/* Table size limit, do not equal or exceed (see min&maxAlphaFrac, below). */ +#undef JS_DHASH_SIZE_LIMIT +#define JS_DHASH_SIZE_LIMIT JS_BIT(24) + +/* Minimum table size, or gross entry count (net is at most .75 loaded). */ +#ifndef JS_DHASH_MIN_SIZE +#define JS_DHASH_MIN_SIZE 16 +#elif (JS_DHASH_MIN_SIZE & (JS_DHASH_MIN_SIZE - 1)) != 0 +#error "JS_DHASH_MIN_SIZE must be a power of two!" +#endif + +/* + * Multiplicative hash uses an unsigned 32 bit integer and the golden ratio, + * expressed as a fixed-point 32-bit fraction. + */ +#define JS_DHASH_BITS 32 +#define JS_DHASH_GOLDEN_RATIO 0x9E3779B9U + +/* Primitive and forward-struct typedefs. */ +typedef uint32 JSDHashNumber; +typedef struct JSDHashEntryHdr JSDHashEntryHdr; +typedef struct JSDHashEntryStub JSDHashEntryStub; +typedef struct JSDHashTable JSDHashTable; +typedef struct JSDHashTableOps JSDHashTableOps; + +/* + * Table entry header structure. + * + * In order to allow in-line allocation of key and value, we do not declare + * either here. Instead, the API uses const void *key as a formal parameter. + * The key need not be stored in the entry; it may be part of the value, but + * need not be stored at all. + * + * Callback types are defined below and grouped into the JSDHashTableOps + * structure, for single static initialization per hash table sub-type. + * + * Each hash table sub-type should nest the JSDHashEntryHdr structure at the + * front of its particular entry type. The keyHash member contains the result + * of multiplying the hash code returned from the hashKey callback (see below) + * by JS_DHASH_GOLDEN_RATIO, then constraining the result to avoid the magic 0 + * and 1 values. The stored keyHash value is table size invariant, and it is + * maintained automatically by JS_DHashTableOperate -- users should never set + * it, and its only uses should be via the entry macros below. + * + * The JS_DHASH_ENTRY_IS_LIVE macro tests whether entry is neither free nor + * removed. An entry may be either busy or free; if busy, it may be live or + * removed. Consumers of this API should not access members of entries that + * are not live. + * + * However, use JS_DHASH_ENTRY_IS_BUSY for faster liveness testing of entries + * returned by JS_DHashTableOperate, as JS_DHashTableOperate never returns a + * non-live, busy (i.e., removed) entry pointer to its caller. See below for + * more details on JS_DHashTableOperate's calling rules. + */ +struct JSDHashEntryHdr { + JSDHashNumber keyHash; /* every entry must begin like this */ +}; + +#define JS_DHASH_ENTRY_IS_FREE(entry) ((entry)->keyHash == 0) +#define JS_DHASH_ENTRY_IS_BUSY(entry) (!JS_DHASH_ENTRY_IS_FREE(entry)) +#define JS_DHASH_ENTRY_IS_LIVE(entry) ((entry)->keyHash >= 2) + +/* + * A JSDHashTable is currently 8 words (without the JS_DHASHMETER overhead) + * on most architectures, and may be allocated on the stack or within another + * structure or class (see below for the Init and Finish functions to use). + * + * To decide whether to use double hashing vs. chaining, we need to develop a + * trade-off relation, as follows: + * + * Let alpha be the load factor, esize the entry size in words, count the + * entry count, and pow2 the power-of-two table size in entries. + * + * (JSDHashTable overhead) > (JSHashTable overhead) + * (unused table entry space) > (malloc and .next overhead per entry) + + * (buckets overhead) + * (1 - alpha) * esize * pow2 > 2 * count + pow2 + * + * Notice that alpha is by definition (count / pow2): + * + * (1 - alpha) * esize * pow2 > 2 * alpha * pow2 + pow2 + * (1 - alpha) * esize > 2 * alpha + 1 + * + * esize > (1 + 2 * alpha) / (1 - alpha) + * + * This assumes both tables must keep keyHash, key, and value for each entry, + * where key and value point to separately allocated strings or structures. + * If key and value can be combined into one pointer, then the trade-off is: + * + * esize > (1 + 3 * alpha) / (1 - alpha) + * + * If the entry value can be a subtype of JSDHashEntryHdr, rather than a type + * that must be allocated separately and referenced by an entry.value pointer + * member, and provided key's allocation can be fused with its entry's, then + * k (the words wasted per entry with chaining) is 4. + * + * To see these curves, feed gnuplot input like so: + * + * gnuplot> f(x,k) = (1 + k * x) / (1 - x) + * gnuplot> plot [0:.75] f(x,2), f(x,3), f(x,4) + * + * For k of 2 and a well-loaded table (alpha > .5), esize must be more than 4 + * words for chaining to be more space-efficient than double hashing. + * + * Solving for alpha helps us decide when to shrink an underloaded table: + * + * esize > (1 + k * alpha) / (1 - alpha) + * esize - alpha * esize > 1 + k * alpha + * esize - 1 > (k + esize) * alpha + * (esize - 1) / (k + esize) > alpha + * + * alpha < (esize - 1) / (esize + k) + * + * Therefore double hashing should keep alpha >= (esize - 1) / (esize + k), + * assuming esize is not too large (in which case, chaining should probably be + * used for any alpha). For esize=2 and k=3, we want alpha >= .2; for esize=3 + * and k=2, we want alpha >= .4. For k=4, esize could be 6, and alpha >= .5 + * would still obtain. See the JS_DHASH_MIN_ALPHA macro further below. + * + * The current implementation uses a configurable lower bound on alpha, which + * defaults to .25, when deciding to shrink the table (while still respecting + * JS_DHASH_MIN_SIZE). + * + * Note a qualitative difference between chaining and double hashing: under + * chaining, entry addresses are stable across table shrinks and grows. With + * double hashing, you can't safely hold an entry pointer and use it after an + * ADD or REMOVE operation, unless you sample table->generation before adding + * or removing, and compare the sample after, dereferencing the entry pointer + * only if table->generation has not changed. + * + * The moral of this story: there is no one-size-fits-all hash table scheme, + * but for small table entry size, and assuming entry address stability is not + * required, double hashing wins. + */ +struct JSDHashTable { + const JSDHashTableOps *ops; /* virtual operations, see below */ + void *data; /* ops- and instance-specific data */ + int16 hashShift; /* multiplicative hash shift */ + uint8 maxAlphaFrac; /* 8-bit fixed point max alpha */ + uint8 minAlphaFrac; /* 8-bit fixed point min alpha */ + uint32 entrySize; /* number of bytes in an entry */ + uint32 entryCount; /* number of entries in table */ + uint32 removedCount; /* removed entry sentinels in table */ + uint32 generation; /* entry storage generation number */ + char *entryStore; /* entry storage */ +#ifdef JS_DHASHMETER + struct JSDHashStats { + uint32 searches; /* total number of table searches */ + uint32 steps; /* hash chain links traversed */ + uint32 hits; /* searches that found key */ + uint32 misses; /* searches that didn't find key */ + uint32 lookups; /* number of JS_DHASH_LOOKUPs */ + uint32 addMisses; /* adds that miss, and do work */ + uint32 addOverRemoved; /* adds that recycled a removed entry */ + uint32 addHits; /* adds that hit an existing entry */ + uint32 addFailures; /* out-of-memory during add growth */ + uint32 removeHits; /* removes that hit, and do work */ + uint32 removeMisses; /* useless removes that miss */ + uint32 removeFrees; /* removes that freed entry directly */ + uint32 removeEnums; /* removes done by Enumerate */ + uint32 grows; /* table expansions */ + uint32 shrinks; /* table contractions */ + uint32 compresses; /* table compressions */ + uint32 enumShrinks; /* contractions after Enumerate */ + } stats; +#endif +}; + +/* + * Size in entries (gross, not net of free and removed sentinels) for table. + * We store hashShift rather than sizeLog2 to optimize the collision-free case + * in SearchTable. + */ +#define JS_DHASH_TABLE_SIZE(table) JS_BIT(JS_DHASH_BITS - (table)->hashShift) + +/* + * Table space at entryStore is allocated and freed using these callbacks. + * The allocator should return null on error only (not if called with nbytes + * equal to 0; but note that jsdhash.c code will never call with 0 nbytes). + */ +typedef void * +(* JSDHashAllocTable)(JSDHashTable *table, uint32 nbytes); + +typedef void +(* JSDHashFreeTable) (JSDHashTable *table, void *ptr); + +/* + * Compute the hash code for a given key to be looked up, added, or removed + * from table. A hash code may have any JSDHashNumber value. + */ +typedef JSDHashNumber +(* JSDHashHashKey) (JSDHashTable *table, const void *key); + +/* + * Compare the key identifying entry in table with the provided key parameter. + * Return JS_TRUE if keys match, JS_FALSE otherwise. + */ +typedef JSBool +(* JSDHashMatchEntry)(JSDHashTable *table, const JSDHashEntryHdr *entry, + const void *key); + +/* + * Copy the data starting at from to the new entry storage at to. Do not add + * reference counts for any strong references in the entry, however, as this + * is a "move" operation: the old entry storage at from will be freed without + * any reference-decrementing callback shortly. + */ +typedef void +(* JSDHashMoveEntry)(JSDHashTable *table, const JSDHashEntryHdr *from, + JSDHashEntryHdr *to); + +/* + * Clear the entry and drop any strong references it holds. This callback is + * invoked during a JS_DHASH_REMOVE operation (see below for operation codes), + * but only if the given key is found in the table. + */ +typedef void +(* JSDHashClearEntry)(JSDHashTable *table, JSDHashEntryHdr *entry); + +/* + * Called when a table (whether allocated dynamically by itself, or nested in + * a larger structure, or allocated on the stack) is finished. This callback + * allows table->ops-specific code to finalize table->data. + */ +typedef void +(* JSDHashFinalize) (JSDHashTable *table); + +/* + * Initialize a new entry, apart from keyHash. This function is called when + * JS_DHashTableOperate's JS_DHASH_ADD case finds no existing entry for the + * given key, and must add a new one. At that point, entry->keyHash is not + * set yet, to avoid claiming the last free entry in a severely overloaded + * table. + */ +typedef JSBool +(* JSDHashInitEntry)(JSDHashTable *table, JSDHashEntryHdr *entry, + const void *key); + +/* + * Finally, the "vtable" structure for JSDHashTable. The first eight hooks + * must be provided by implementations; they're called unconditionally by the + * generic jsdhash.c code. Hooks after these may be null. + * + * Summary of allocation-related hook usage with C++ placement new emphasis: + * allocTable Allocate raw bytes with malloc, no ctors run. + * freeTable Free raw bytes with free, no dtors run. + * initEntry Call placement new using default key-based ctor. + * Return JS_TRUE on success, JS_FALSE on error. + * moveEntry Call placement new using copy ctor, run dtor on old + * entry storage. + * clearEntry Run dtor on entry. + * finalize Stub unless table->data was initialized and needs to + * be finalized. + * + * Note the reason why initEntry is optional: the default hooks (stubs) clear + * entry storage: On successful JS_DHashTableOperate(tbl, key, JS_DHASH_ADD), + * the returned entry pointer addresses an entry struct whose keyHash member + * has been set non-zero, but all other entry members are still clear (null). + * JS_DHASH_ADD callers can test such members to see whether the entry was + * newly created by the JS_DHASH_ADD call that just succeeded. If placement + * new or similar initialization is required, define an initEntry hook. Of + * course, the clearEntry hook must zero or null appropriately. + * + * XXX assumes 0 is null for pointer types. + */ +struct JSDHashTableOps { + /* Mandatory hooks. All implementations must provide these. */ + JSDHashAllocTable allocTable; + JSDHashFreeTable freeTable; + JSDHashHashKey hashKey; + JSDHashMatchEntry matchEntry; + JSDHashMoveEntry moveEntry; + JSDHashClearEntry clearEntry; + JSDHashFinalize finalize; + + /* Optional hooks start here. If null, these are not called. */ + JSDHashInitEntry initEntry; +}; + +/* + * Default implementations for the above ops. + */ +extern JS_PUBLIC_API(void *) +JS_DHashAllocTable(JSDHashTable *table, uint32 nbytes); + +extern JS_PUBLIC_API(void) +JS_DHashFreeTable(JSDHashTable *table, void *ptr); + +extern JS_PUBLIC_API(JSDHashNumber) +JS_DHashStringKey(JSDHashTable *table, const void *key); + +/* A minimal entry contains a keyHash header and a void key pointer. */ +struct JSDHashEntryStub { + JSDHashEntryHdr hdr; + const void *key; +}; + +extern JS_PUBLIC_API(JSDHashNumber) +JS_DHashVoidPtrKeyStub(JSDHashTable *table, const void *key); + +extern JS_PUBLIC_API(JSBool) +JS_DHashMatchEntryStub(JSDHashTable *table, + const JSDHashEntryHdr *entry, + const void *key); + +extern JS_PUBLIC_API(JSBool) +JS_DHashMatchStringKey(JSDHashTable *table, + const JSDHashEntryHdr *entry, + const void *key); + +extern JS_PUBLIC_API(void) +JS_DHashMoveEntryStub(JSDHashTable *table, + const JSDHashEntryHdr *from, + JSDHashEntryHdr *to); + +extern JS_PUBLIC_API(void) +JS_DHashClearEntryStub(JSDHashTable *table, JSDHashEntryHdr *entry); + +extern JS_PUBLIC_API(void) +JS_DHashFreeStringKey(JSDHashTable *table, JSDHashEntryHdr *entry); + +extern JS_PUBLIC_API(void) +JS_DHashFinalizeStub(JSDHashTable *table); + +/* + * If you use JSDHashEntryStub or a subclass of it as your entry struct, and + * if your entries move via memcpy and clear via memset(0), you can use these + * stub operations. + */ +extern JS_PUBLIC_API(const JSDHashTableOps *) +JS_DHashGetStubOps(void); + +/* + * Dynamically allocate a new JSDHashTable using malloc, initialize it using + * JS_DHashTableInit, and return its address. Return null on malloc failure. + * Note that the entry storage at table->entryStore will be allocated using + * the ops->allocTable callback. + */ +extern JS_PUBLIC_API(JSDHashTable *) +JS_NewDHashTable(const JSDHashTableOps *ops, void *data, uint32 entrySize, + uint32 capacity); + +/* + * Finalize table's data, free its entry storage (via table->ops->freeTable), + * and return the memory starting at table to the malloc heap. + */ +extern JS_PUBLIC_API(void) +JS_DHashTableDestroy(JSDHashTable *table); + +/* + * Initialize table with ops, data, entrySize, and capacity. Capacity is a + * guess for the smallest table size at which the table will usually be less + * than 75% loaded (the table will grow or shrink as needed; capacity serves + * only to avoid inevitable early growth from JS_DHASH_MIN_SIZE). + */ +extern JS_PUBLIC_API(JSBool) +JS_DHashTableInit(JSDHashTable *table, const JSDHashTableOps *ops, void *data, + uint32 entrySize, uint32 capacity); + +/* + * Set maximum and minimum alpha for table. The defaults are 0.75 and .25. + * maxAlpha must be in [0.5, 0.9375] for the default JS_DHASH_MIN_SIZE; or if + * MinSize=JS_DHASH_MIN_SIZE <= 256, in [0.5, (float)(MinSize-1)/MinSize]; or + * else in [0.5, 255.0/256]. minAlpha must be in [0, maxAlpha / 2), so that + * we don't shrink on the very next remove after growing a table upon adding + * an entry that brings entryCount past maxAlpha * tableSize. + */ +extern JS_PUBLIC_API(void) +JS_DHashTableSetAlphaBounds(JSDHashTable *table, + float maxAlpha, + float minAlpha); + +/* + * Call this macro with k, the number of pointer-sized words wasted per entry + * under chaining, to compute the minimum alpha at which double hashing still + * beats chaining. + */ +#define JS_DHASH_MIN_ALPHA(table, k) \ + ((float)((table)->entrySize / sizeof(void *) - 1) \ + / ((table)->entrySize / sizeof(void *) + (k))) + +/* + * Default max/min alpha, and macros to compute the value for the |capacity| + * parameter to JS_NewDHashTable and JS_DHashTableInit, given default or any + * max alpha, such that adding entryCount entries right after initializing the + * table will not require a reallocation (so JS_DHASH_ADD can't fail for those + * JS_DHashTableOperate calls). + * + * NB: JS_DHASH_CAP is a helper macro meant for use only in JS_DHASH_CAPACITY. + * Don't use it directly! + */ +#define JS_DHASH_DEFAULT_MAX_ALPHA 0.75 +#define JS_DHASH_DEFAULT_MIN_ALPHA 0.25 + +#define JS_DHASH_CAP(entryCount, maxAlpha) \ + ((uint32)((double)(entryCount) / (maxAlpha))) + +#define JS_DHASH_CAPACITY(entryCount, maxAlpha) \ + (JS_DHASH_CAP(entryCount, maxAlpha) + \ + (((JS_DHASH_CAP(entryCount, maxAlpha) * (uint8)(0x100 * (maxAlpha))) \ + >> 8) < (entryCount))) + +#define JS_DHASH_DEFAULT_CAPACITY(entryCount) \ + JS_DHASH_CAPACITY(entryCount, JS_DHASH_DEFAULT_MAX_ALPHA) + +/* + * Finalize table's data, free its entry storage using table->ops->freeTable, + * and leave its members unchanged from their last live values (which leaves + * pointers dangling). If you want to burn cycles clearing table, it's up to + * your code to call memset. + */ +extern JS_PUBLIC_API(void) +JS_DHashTableFinish(JSDHashTable *table); + +/* + * To consolidate keyHash computation and table grow/shrink code, we use a + * single entry point for lookup, add, and remove operations. The operation + * codes are declared here, along with codes returned by JSDHashEnumerator + * functions, which control JS_DHashTableEnumerate's behavior. + */ +typedef enum JSDHashOperator { + JS_DHASH_LOOKUP = 0, /* lookup entry */ + JS_DHASH_ADD = 1, /* add entry */ + JS_DHASH_REMOVE = 2, /* remove entry, or enumerator says remove */ + JS_DHASH_NEXT = 0, /* enumerator says continue */ + JS_DHASH_STOP = 1 /* enumerator says stop */ +} JSDHashOperator; + +/* + * To lookup a key in table, call: + * + * entry = JS_DHashTableOperate(table, key, JS_DHASH_LOOKUP); + * + * If JS_DHASH_ENTRY_IS_BUSY(entry) is true, key was found and it identifies + * entry. If JS_DHASH_ENTRY_IS_FREE(entry) is true, key was not found. + * + * To add an entry identified by key to table, call: + * + * entry = JS_DHashTableOperate(table, key, JS_DHASH_ADD); + * + * If entry is null upon return, then either the table is severely overloaded, + * and memory can't be allocated for entry storage via table->ops->allocTable; + * Or if table->ops->initEntry is non-null, the table->ops->initEntry op may + * have returned false. + * + * Otherwise, entry->keyHash has been set so that JS_DHASH_ENTRY_IS_BUSY(entry) + * is true, and it is up to the caller to initialize the key and value parts + * of the entry sub-type, if they have not been set already (i.e. if entry was + * not already in the table, and if the optional initEntry hook was not used). + * + * To remove an entry identified by key from table, call: + * + * (void) JS_DHashTableOperate(table, key, JS_DHASH_REMOVE); + * + * If key's entry is found, it is cleared (via table->ops->clearEntry) and + * the entry is marked so that JS_DHASH_ENTRY_IS_FREE(entry). This operation + * returns null unconditionally; you should ignore its return value. + */ +extern JS_PUBLIC_API(JSDHashEntryHdr *) JS_DHASH_FASTCALL +JS_DHashTableOperate(JSDHashTable *table, const void *key, JSDHashOperator op); + +/* + * Remove an entry already accessed via LOOKUP or ADD. + * + * NB: this is a "raw" or low-level routine, intended to be used only where + * the inefficiency of a full JS_DHashTableOperate (which rehashes in order + * to find the entry given its key) is not tolerable. This function does not + * shrink the table if it is underloaded. It does not update stats #ifdef + * JS_DHASHMETER, either. + */ +extern JS_PUBLIC_API(void) +JS_DHashTableRawRemove(JSDHashTable *table, JSDHashEntryHdr *entry); + +/* + * Enumerate entries in table using etor: + * + * count = JS_DHashTableEnumerate(table, etor, arg); + * + * JS_DHashTableEnumerate calls etor like so: + * + * op = etor(table, entry, number, arg); + * + * where number is a zero-based ordinal assigned to live entries according to + * their order in table->entryStore. + * + * The return value, op, is treated as a set of flags. If op is JS_DHASH_NEXT, + * then continue enumerating. If op contains JS_DHASH_REMOVE, then clear (via + * table->ops->clearEntry) and free entry. Then we check whether op contains + * JS_DHASH_STOP; if so, stop enumerating and return the number of live entries + * that were enumerated so far. Return the total number of live entries when + * enumeration completes normally. + * + * If etor calls JS_DHashTableOperate on table with op != JS_DHASH_LOOKUP, it + * must return JS_DHASH_STOP; otherwise undefined behavior results. + * + * If any enumerator returns JS_DHASH_REMOVE, table->entryStore may be shrunk + * or compressed after enumeration, but before JS_DHashTableEnumerate returns. + * Such an enumerator therefore can't safely set aside entry pointers, but an + * enumerator that never returns JS_DHASH_REMOVE can set pointers to entries + * aside, e.g., to avoid copying live entries into an array of the entry type. + * Copying entry pointers is cheaper, and safe so long as the caller of such a + * "stable" Enumerate doesn't use the set-aside pointers after any call either + * to PL_DHashTableOperate, or to an "unstable" form of Enumerate, which might + * grow or shrink entryStore. + * + * If your enumerator wants to remove certain entries, but set aside pointers + * to other entries that it retains, it can use JS_DHashTableRawRemove on the + * entries to be removed, returning JS_DHASH_NEXT to skip them. Likewise, if + * you want to remove entries, but for some reason you do not want entryStore + * to be shrunk or compressed, you can call JS_DHashTableRawRemove safely on + * the entry being enumerated, rather than returning JS_DHASH_REMOVE. + */ +typedef JSDHashOperator +(* JSDHashEnumerator)(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, + void *arg); + +extern JS_PUBLIC_API(uint32) +JS_DHashTableEnumerate(JSDHashTable *table, JSDHashEnumerator etor, void *arg); + +#ifdef DEBUG +/** + * Mark a table as immutable for the remainder of its lifetime. This + * changes the implementation from ASSERTing one set of invariants to + * ASSERTing a different set. + * + * When a table is NOT marked as immutable, the table implementation + * asserts that the table is not mutated from its own callbacks. It + * assumes the caller protects the table from being accessed on multiple + * threads simultaneously. + * + * When the table is marked as immutable, the re-entry assertions will + * no longer trigger erroneously due to multi-threaded access. Instead, + * mutations will cause assertions. + */ +extern JS_PUBLIC_API(void) +JS_DHashMarkTableImmutable(JSDHashTable *table); +#endif + +#ifdef JS_DHASHMETER +#include + +extern JS_PUBLIC_API(void) +JS_DHashTableDumpMeter(JSDHashTable *table, JSDHashEnumerator dump, FILE *fp); +#endif + +JS_END_EXTERN_C + +#endif /* jsdhash_h___ */ diff --git a/js/src/jsdtoa.cpp b/js/src/jsdtoa.cpp new file mode 100644 index 0000000..e03fa52 --- /dev/null +++ b/js/src/jsdtoa.cpp @@ -0,0 +1,540 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Portable double to alphanumeric string and back converters. + */ +#include "jstypes.h" +#include "jsstdint.h" +#include "jsdtoa.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsprvtd.h" +#include "jsnum.h" +#include "jsbit.h" +#include "jslibmath.h" +#include "jscntxt.h" + +#include "jsobjinlines.h" + +#ifdef IS_LITTLE_ENDIAN +#define IEEE_8087 +#else +#define IEEE_MC68k +#endif + +#ifndef Long +#define Long int32 +#endif + +#ifndef ULong +#define ULong uint32 +#endif + +/* +#ifndef Llong +#define Llong JSInt64 +#endif + +#ifndef ULlong +#define ULlong JSUint64 +#endif +*/ + +#define NO_GLOBAL_STATE +#define MALLOC js_malloc +#define FREE js_free +#include "dtoa.c" + +/* Mapping of JSDToStrMode -> js_dtoa mode */ +static const uint8 dtoaModes[] = { + 0, /* DTOSTR_STANDARD */ + 0, /* DTOSTR_STANDARD_EXPONENTIAL, */ + 3, /* DTOSTR_FIXED, */ + 2, /* DTOSTR_EXPONENTIAL, */ + 2}; /* DTOSTR_PRECISION */ + +double +js_strtod_harder(DtoaState *state, const char *s00, char **se, int *err) +{ + double retval; + if (err) + *err = 0; + retval = _strtod(state, s00, se); + return retval; +} + +char * +js_dtostr(DtoaState *state, char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, + double dinput) +{ + U d; + int decPt; /* Offset of decimal point from first digit */ + int sign; /* Nonzero if the sign bit was set in d */ + int nDigits; /* Number of significand digits returned by js_dtoa */ + char *numBegin; /* Pointer to the digits returned by js_dtoa */ + char *numEnd = 0; /* Pointer past the digits returned by js_dtoa */ + + JS_ASSERT(bufferSize >= (size_t)(mode <= DTOSTR_STANDARD_EXPONENTIAL + ? DTOSTR_STANDARD_BUFFER_SIZE + : DTOSTR_VARIABLE_BUFFER_SIZE(precision))); + + /* + * Change mode here rather than below because the buffer may not be large + * enough to hold a large integer. + */ + if (mode == DTOSTR_FIXED && (dinput >= 1e21 || dinput <= -1e21)) + mode = DTOSTR_STANDARD; + + dval(d) = dinput; + numBegin = dtoa(PASS_STATE d, dtoaModes[mode], precision, &decPt, &sign, &numEnd); + if (!numBegin) { + return NULL; + } + + nDigits = numEnd - numBegin; + JS_ASSERT((size_t) nDigits <= bufferSize - 2); + if ((size_t) nDigits > bufferSize - 2) { + return NULL; + } + + memcpy(buffer + 2, numBegin, nDigits); + freedtoa(PASS_STATE numBegin); + numBegin = buffer + 2; /* +2 leaves space for sign and/or decimal point */ + numEnd = numBegin + nDigits; + *numEnd = '\0'; + + /* If Infinity, -Infinity, or NaN, return the string regardless of mode. */ + if (decPt != 9999) { + JSBool exponentialNotation = JS_FALSE; + int minNDigits = 0; /* Min number of significant digits required */ + char *p; + char *q; + + switch (mode) { + case DTOSTR_STANDARD: + if (decPt < -5 || decPt > 21) + exponentialNotation = JS_TRUE; + else + minNDigits = decPt; + break; + + case DTOSTR_FIXED: + if (precision >= 0) + minNDigits = decPt + precision; + else + minNDigits = decPt; + break; + + case DTOSTR_EXPONENTIAL: + JS_ASSERT(precision > 0); + minNDigits = precision; + /* Fall through */ + case DTOSTR_STANDARD_EXPONENTIAL: + exponentialNotation = JS_TRUE; + break; + + case DTOSTR_PRECISION: + JS_ASSERT(precision > 0); + minNDigits = precision; + if (decPt < -5 || decPt > precision) + exponentialNotation = JS_TRUE; + break; + } + + /* If the number has fewer than minNDigits, end-pad it with zeros. */ + if (nDigits < minNDigits) { + p = numBegin + minNDigits; + nDigits = minNDigits; + do { + *numEnd++ = '0'; + } while (numEnd != p); + *numEnd = '\0'; + } + + if (exponentialNotation) { + /* Insert a decimal point if more than one significand digit */ + if (nDigits != 1) { + numBegin--; + numBegin[0] = numBegin[1]; + numBegin[1] = '.'; + } + JS_snprintf(numEnd, bufferSize - (numEnd - buffer), "e%+d", decPt-1); + } else if (decPt != nDigits) { + /* Some kind of a fraction in fixed notation */ + JS_ASSERT(decPt <= nDigits); + if (decPt > 0) { + /* dd...dd . dd...dd */ + p = --numBegin; + do { + *p = p[1]; + p++; + } while (--decPt); + *p = '.'; + } else { + /* 0 . 00...00dd...dd */ + p = numEnd; + numEnd += 1 - decPt; + q = numEnd; + JS_ASSERT(numEnd < buffer + bufferSize); + *numEnd = '\0'; + while (p != numBegin) + *--q = *--p; + for (p = numBegin + 1; p != q; p++) + *p = '0'; + *numBegin = '.'; + *--numBegin = '0'; + } + } + } + + /* If negative and neither -0.0 nor NaN, output a leading '-'. */ + if (sign && + !(word0(d) == Sign_bit && word1(d) == 0) && + !((word0(d) & Exp_mask) == Exp_mask && + (word1(d) || (word0(d) & Frac_mask)))) { + *--numBegin = '-'; + } + return numBegin; +} + + +/* Let b = floor(b / divisor), and return the remainder. b must be nonnegative. + * divisor must be between 1 and 65536. + * This function cannot run out of memory. */ +static uint32 +divrem(Bigint *b, uint32 divisor) +{ + int32 n = b->wds; + uint32 remainder = 0; + ULong *bx; + ULong *bp; + + JS_ASSERT(divisor > 0 && divisor <= 65536); + + if (!n) + return 0; /* b is zero */ + bx = b->x; + bp = bx + n; + do { + ULong a = *--bp; + ULong dividend = remainder << 16 | a >> 16; + ULong quotientHi = dividend / divisor; + ULong quotientLo; + + remainder = dividend - quotientHi*divisor; + JS_ASSERT(quotientHi <= 0xFFFF && remainder < divisor); + dividend = remainder << 16 | (a & 0xFFFF); + quotientLo = dividend / divisor; + remainder = dividend - quotientLo*divisor; + JS_ASSERT(quotientLo <= 0xFFFF && remainder < divisor); + *bp = quotientHi << 16 | quotientLo; + } while (bp != bx); + /* Decrease the size of the number if its most significant word is now zero. */ + if (bx[n-1] == 0) + b->wds--; + return remainder; +} + +/* Return floor(b/2^k) and set b to be the remainder. The returned quotient must be less than 2^32. */ +static uint32 quorem2(Bigint *b, int32 k) +{ + ULong mask; + ULong result; + ULong *bx, *bxe; + int32 w; + int32 n = k >> 5; + k &= 0x1F; + mask = (1<wds - n; + if (w <= 0) + return 0; + JS_ASSERT(w <= 2); + bx = b->x; + bxe = bx + n; + result = *bxe >> k; + *bxe &= mask; + if (w == 2) { + JS_ASSERT(!(bxe[1] & ~mask)); + if (k) + result |= bxe[1] << (32 - k); + } + n++; + while (!*bxe && bxe != bx) { + n--; + bxe--; + } + b->wds = n; + return result; +} + + +/* "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest string that we could produce, + * which occurs when printing -5e-324 in binary. We could compute a better estimate of the size of + * the output string and malloc fewer bytes depending on d and base, but why bother? */ +#define DTOBASESTR_BUFFER_SIZE 1078 +#define BASEDIGIT(digit) ((char)(((digit) >= 10) ? 'a' - 10 + (digit) : '0' + (digit))) + +char * +js_dtobasestr(DtoaState *state, int base, double dinput) +{ + U d; + char *buffer; /* The output string */ + char *p; /* Pointer to current position in the buffer */ + char *pInt; /* Pointer to the beginning of the integer part of the string */ + char *q; + uint32 digit; + U di; /* d truncated to an integer */ + U df; /* The fractional part of d */ + + JS_ASSERT(base >= 2 && base <= 36); + + dval(d) = dinput; + buffer = (char*) js_malloc(DTOBASESTR_BUFFER_SIZE); + if (!buffer) + return NULL; + p = buffer; + + if (dval(d) < 0.0 +#if defined(XP_WIN) || defined(XP_OS2) + && !((word0(d) & Exp_mask) == Exp_mask && ((word0(d) & Frac_mask) || word1(d))) /* Visual C++ doesn't know how to compare against NaN */ +#endif + ) { + *p++ = '-'; + dval(d) = -dval(d); + } + + /* Check for Infinity and NaN */ + if ((word0(d) & Exp_mask) == Exp_mask) { + strcpy(p, !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN"); + return buffer; + } + + /* Output the integer part of d with the digits in reverse order. */ + pInt = p; + dval(di) = floor(dval(d)); + if (dval(di) <= 4294967295.0) { + uint32 n = (uint32)dval(di); + if (n) + do { + uint32 m = n / base; + digit = n - m*base; + n = m; + JS_ASSERT(digit < (uint32)base); + *p++ = BASEDIGIT(digit); + } while (n); + else *p++ = '0'; + } else { + int e; + int bits; /* Number of significant bits in di; not used. */ + Bigint *b = d2b(PASS_STATE di, &e, &bits); + if (!b) + goto nomem1; + b = lshift(PASS_STATE b, e); + if (!b) { + nomem1: + Bfree(PASS_STATE b); + js_free(buffer); + return NULL; + } + do { + digit = divrem(b, base); + JS_ASSERT(digit < (uint32)base); + *p++ = BASEDIGIT(digit); + } while (b->wds); + Bfree(PASS_STATE b); + } + /* Reverse the digits of the integer part of d. */ + q = p-1; + while (q > pInt) { + char ch = *pInt; + *pInt++ = *q; + *q-- = ch; + } + + dval(df) = dval(d) - dval(di); + if (dval(df) != 0.0) { + /* We have a fraction. */ + int e, bbits; + int32 s2, done; + Bigint *b, *s, *mlo, *mhi; + + b = s = mlo = mhi = NULL; + + *p++ = '.'; + b = d2b(PASS_STATE df, &e, &bbits); + if (!b) { + nomem2: + Bfree(PASS_STATE b); + Bfree(PASS_STATE s); + if (mlo != mhi) + Bfree(PASS_STATE mlo); + Bfree(PASS_STATE mhi); + js_free(buffer); + return NULL; + } + JS_ASSERT(e < 0); + /* At this point df = b * 2^e. e must be less than zero because 0 < df < 1. */ + + s2 = -(int32)(word0(d) >> Exp_shift1 & Exp_mask>>Exp_shift1); +#ifndef Sudden_Underflow + if (!s2) + s2 = -1; +#endif + s2 += Bias + P; + /* 1/2^s2 = (nextDouble(d) - d)/2 */ + JS_ASSERT(-s2 < e); + mlo = i2b(PASS_STATE 1); + if (!mlo) + goto nomem2; + mhi = mlo; + if (!word1(d) && !(word0(d) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(d) & (Exp_mask & Exp_mask << 1) +#endif + ) { + /* The special case. Here we want to be within a quarter of the last input + significant digit instead of one half of it when the output string's value is less than d. */ + s2 += Log2P; + mhi = i2b(PASS_STATE 1< df = b/2^s2 > 0; + * (d - prevDouble(d))/2 = mlo/2^s2; + * (nextDouble(d) - d)/2 = mhi/2^s2. */ + + done = JS_FALSE; + do { + int32 j, j1; + Bigint *delta; + + b = multadd(PASS_STATE b, base, 0); + if (!b) + goto nomem2; + digit = quorem2(b, s2); + if (mlo == mhi) { + mlo = mhi = multadd(PASS_STATE mlo, base, 0); + if (!mhi) + goto nomem2; + } + else { + mlo = multadd(PASS_STATE mlo, base, 0); + if (!mlo) + goto nomem2; + mhi = multadd(PASS_STATE mhi, base, 0); + if (!mhi) + goto nomem2; + } + + /* Do we yet have the shortest string that will round to d? */ + j = cmp(b, mlo); + /* j is b/2^s2 compared with mlo/2^s2. */ + delta = diff(PASS_STATE s, mhi); + if (!delta) + goto nomem2; + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(PASS_STATE delta); + /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */ + +#ifndef ROUND_BIASED + if (j1 == 0 && !(word1(d) & 1)) { + if (j > 0) + digit++; + done = JS_TRUE; + } else +#endif + if (j < 0 || (j == 0 +#ifndef ROUND_BIASED + && !(word1(d) & 1) +#endif + )) { + if (j1 > 0) { + /* Either dig or dig+1 would work here as the least significant digit. + Use whichever would produce an output value closer to d. */ + b = lshift(PASS_STATE b, 1); + if (!b) + goto nomem2; + j1 = cmp(b, s); + if (j1 > 0) /* The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output + * such as 3.5 in base 3. */ + digit++; + } + done = JS_TRUE; + } else if (j1 > 0) { + digit++; + done = JS_TRUE; + } + JS_ASSERT(digit < (uint32)base); + *p++ = BASEDIGIT(digit); + } while (!done); + Bfree(PASS_STATE b); + Bfree(PASS_STATE s); + if (mlo != mhi) + Bfree(PASS_STATE mlo); + Bfree(PASS_STATE mhi); + } + JS_ASSERT(p < buffer + DTOBASESTR_BUFFER_SIZE); + *p = '\0'; + return buffer; +} + +DtoaState * +js_NewDtoaState() +{ + return newdtoa(); +} + +void +js_DestroyDtoaState(DtoaState *state) +{ + destroydtoa(state); +} diff --git a/js/src/jsdtoa.h b/js/src/jsdtoa.h new file mode 100644 index 0000000..eacfb4d --- /dev/null +++ b/js/src/jsdtoa.h @@ -0,0 +1,148 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsdtoa_h___ +#define jsdtoa_h___ +/* + * Public interface to portable double-precision floating point to string + * and back conversion package. + */ + +#include "jscompat.h" + +JS_BEGIN_EXTERN_C + +struct DtoaState; + +DtoaState * +js_NewDtoaState(); + +void +js_DestroyDtoaState(DtoaState *state); + +/* + * js_strtod_harder() returns as a double-precision floating-point number the + * value represented by the character string pointed to by s00. The string is + * scanned up to the first unrecognized character. + * + * If se is not NULL, *se receives a pointer to the character terminating the + * scan. If no number can be formed, *se receives a pointer to the first + * unparseable character in s00, and zero is returned. + * + * *err is set to zero on success; it's set to JS_DTOA_ERANGE on range + * errors and JS_DTOA_ENOMEM on memory failure. + */ +#define JS_DTOA_ERANGE 1 +#define JS_DTOA_ENOMEM 2 +double +js_strtod_harder(DtoaState *state, const char *s00, char **se, int *err); + +/* + * Modes for converting floating-point numbers to strings. + * + * Some of the modes can round-trip; this means that if the number is converted to + * a string using one of these mode and then converted back to a number, the result + * will be identical to the original number (except that, due to ECMA, -0 will get converted + * to +0). These round-trip modes return the minimum number of significand digits that + * permit the round trip. + * + * Some of the modes take an integer parameter . + */ +/* NB: Keep this in sync with number_constants[]. */ +typedef enum JSDToStrMode { + DTOSTR_STANDARD, /* Either fixed or exponential format; round-trip */ + DTOSTR_STANDARD_EXPONENTIAL, /* Always exponential format; round-trip */ + DTOSTR_FIXED, /* Round to digits after the decimal point; exponential if number is large */ + DTOSTR_EXPONENTIAL, /* Always exponential format; significant digits */ + DTOSTR_PRECISION /* Either fixed or exponential format; significant digits */ +} JSDToStrMode; + + +/* Maximum number of characters (including trailing null) that a DTOSTR_STANDARD or DTOSTR_STANDARD_EXPONENTIAL + * conversion can produce. This maximum is reached for a number like -0.0000012345678901234567. */ +#define DTOSTR_STANDARD_BUFFER_SIZE 26 + +/* Maximum number of characters (including trailing null) that one of the other conversions + * can produce. This maximum is reached for TO_FIXED, which can generate up to 21 digits before the decimal point. */ +#define DTOSTR_VARIABLE_BUFFER_SIZE(precision) ((precision)+24 > DTOSTR_STANDARD_BUFFER_SIZE ? (precision)+24 : DTOSTR_STANDARD_BUFFER_SIZE) + +/* + * DO NOT USE THIS FUNCTION IF YOU CAN AVOID IT. js::NumberToCString() is a + * better function to use. + * + * Convert dval according to the given mode and return a pointer to the + * resulting ASCII string. If mode == DTOSTR_STANDARD and precision == 0 it's + * equivalent to ToString() as specified by ECMA-262-5 section 9.8.1, but it + * doesn't handle integers specially so should be avoided in that case (that's + * why js::NumberToCString() is better). + * + * The result is held somewhere in buffer, but not necessarily at the + * beginning. The size of buffer is given in bufferSize, and must be at least + * as large as given by the above macros. + * + * Return NULL if out of memory. + */ +char * +js_dtostr(DtoaState *state, char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, + double dval); + +/* + * DO NOT USE THIS FUNCTION IF YOU CAN AVOID IT. js::NumberToCString() is a + * better function to use. + * + * Convert d to a string in the given base. The integral part of d will be + * printed exactly in that base, regardless of how large it is, because there + * is no exponential notation for non-base-ten numbers. The fractional part + * will be rounded to as few digits as possible while still preserving the + * round-trip property (analogous to that of printing decimal numbers). In + * other words, if one were to read the resulting string in via a hypothetical + * base-number-reading routine that rounds to the nearest IEEE double (and to + * an even significand if there are two equally near doubles), then the result + * would equal d (except for -0.0, which converts to "0", and NaN, which is + * not equal to itself). + * + * Return NULL if out of memory. If the result is not NULL, it must be + * released via js_free(). + */ +char * +js_dtobasestr(DtoaState *state, int base, double d); + +JS_END_EXTERN_C + +#endif /* jsdtoa_h___ */ diff --git a/js/src/jsemit.cpp b/js/src/jsemit.cpp new file mode 100644 index 0000000..df41257 --- /dev/null +++ b/js/src/jsemit.cpp @@ -0,0 +1,7744 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS bytecode generation. + */ +#ifdef HAVE_MEMORY_H +#include +#endif +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsarena.h" +#include "jsutil.h" +#include "jsbit.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsnum.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsregexp.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsautooplen.h" // generated headers last +#include "jsstaticcheck.h" + +#include "jsatominlines.h" +#include "jsobjinlines.h" +#include "jsscopeinlines.h" +#include "jsscriptinlines.h" + +/* Allocation chunk counts, must be powers of two in general. */ +#define BYTECODE_CHUNK 256 /* code allocation increment */ +#define SRCNOTE_CHUNK 64 /* initial srcnote allocation increment */ +#define TRYNOTE_CHUNK 64 /* trynote allocation increment */ + +/* Macros to compute byte sizes from typed element counts. */ +#define BYTECODE_SIZE(n) ((n) * sizeof(jsbytecode)) +#define SRCNOTE_SIZE(n) ((n) * sizeof(jssrcnote)) +#define TRYNOTE_SIZE(n) ((n) * sizeof(JSTryNote)) + +using namespace js; +using namespace js::gc; + +static JSBool +NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind, + uintN stackDepth, size_t start, size_t end); + +static JSBool +EmitIndexOp(JSContext *cx, JSOp op, uintN index, JSCodeGenerator *cg); + +static JSBool +EmitLeaveBlock(JSContext *cx, JSCodeGenerator *cg, JSOp op, JSObjectBox *box); + +void +JSTreeContext::trace(JSTracer *trc) +{ + bindings.trace(trc); +} + +JSCodeGenerator::JSCodeGenerator(Parser *parser, + JSArenaPool *cpool, JSArenaPool *npool, + uintN lineno) + : JSTreeContext(parser), + codePool(cpool), notePool(npool), + codeMark(JS_ARENA_MARK(cpool)), noteMark(JS_ARENA_MARK(npool)), + stackDepth(0), maxStackDepth(0), + ntrynotes(0), lastTryNode(NULL), + spanDeps(NULL), jumpTargets(NULL), jtFreeList(NULL), + numSpanDeps(0), numJumpTargets(0), spanDepTodo(0), + arrayCompDepth(0), + emitLevel(0), + constMap(parser->context), + constList(parser->context), + globalUses(ContextAllocPolicy(parser->context)), + closedArgs(ContextAllocPolicy(parser->context)), + closedVars(ContextAllocPolicy(parser->context)), + traceIndex(0) +{ + flags = TCF_COMPILING; + memset(&prolog, 0, sizeof prolog); + memset(&main, 0, sizeof main); + current = &main; + firstLine = prolog.currentLine = main.currentLine = lineno; + prolog.noteMask = main.noteMask = SRCNOTE_CHUNK - 1; + memset(&upvarMap, 0, sizeof upvarMap); +} + +bool JSCodeGenerator::init() +{ + return constMap.init(); +} + +JSCodeGenerator::~JSCodeGenerator() +{ + JS_ARENA_RELEASE(codePool, codeMark); + JS_ARENA_RELEASE(notePool, noteMark); + + /* NB: non-null only after OOM. */ + if (spanDeps) + parser->context->free(spanDeps); + + if (upvarMap.vector) + parser->context->free(upvarMap.vector); +} + +static ptrdiff_t +EmitCheck(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t delta) +{ + jsbytecode *base, *limit, *next; + ptrdiff_t offset, length; + size_t incr, size; + + base = CG_BASE(cg); + next = CG_NEXT(cg); + limit = CG_LIMIT(cg); + offset = next - base; + if (next + delta > limit) { + length = offset + delta; + length = (length <= BYTECODE_CHUNK) + ? BYTECODE_CHUNK + : JS_BIT(JS_CeilingLog2(length)); + incr = BYTECODE_SIZE(length); + if (!base) { + JS_ARENA_ALLOCATE_CAST(base, jsbytecode *, cg->codePool, incr); + } else { + size = BYTECODE_SIZE(limit - base); + incr -= size; + JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr); + } + if (!base) { + js_ReportOutOfScriptQuota(cx); + return -1; + } + CG_BASE(cg) = base; + CG_LIMIT(cg) = base + length; + CG_NEXT(cg) = base + offset; + } + return offset; +} + +static void +UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target) +{ + jsbytecode *pc; + JSOp op; + const JSCodeSpec *cs; + uintN extra, depth, nuses; + intN ndefs; + + pc = CG_CODE(cg, target); + op = (JSOp) *pc; + cs = &js_CodeSpec[op]; +#ifdef JS_TRACER + extern uint8 js_opcode2extra[]; + extra = js_opcode2extra[op]; +#else + extra = 0; +#endif + if ((cs->format & JOF_TMPSLOT_MASK) || extra) { + depth = (uintN) cg->stackDepth + + ((cs->format & JOF_TMPSLOT_MASK) >> JOF_TMPSLOT_SHIFT) + + extra; + /* :TODO: hack - remove later. */ + switch (op) { + case JSOP_PROPINC: + case JSOP_PROPDEC: + depth += 1; + break; + case JSOP_NAMEINC: + case JSOP_NAMEDEC: + case JSOP_INCNAME: + case JSOP_DECNAME: + case JSOP_GNAMEINC: + case JSOP_GNAMEDEC: + case JSOP_INCGNAME: + case JSOP_DECGNAME: + depth += 2; + break; + default: + break; + } + if (depth > cg->maxStackDepth) + cg->maxStackDepth = depth; + } + + nuses = js_GetStackUses(cs, op, pc); + cg->stackDepth -= nuses; + JS_ASSERT(cg->stackDepth >= 0); + if (cg->stackDepth < 0) { + char numBuf[12]; + TokenStream *ts; + + JS_snprintf(numBuf, sizeof numBuf, "%d", target); + ts = &cg->parser->tokenStream; + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, + js_GetErrorMessage, NULL, + JSMSG_STACK_UNDERFLOW, + ts->getFilename() ? ts->getFilename() : "stdin", + numBuf); + } + ndefs = cs->ndefs; + if (ndefs < 0) { + JSObject *blockObj; + + /* We just executed IndexParsedObject */ + JS_ASSERT(op == JSOP_ENTERBLOCK); + JS_ASSERT(nuses == 0); + blockObj = cg->objectList.lastbox->object; + JS_ASSERT(blockObj->isStaticBlock()); + JS_ASSERT(blockObj->getSlot(JSSLOT_BLOCK_DEPTH).isUndefined()); + + OBJ_SET_BLOCK_DEPTH(cx, blockObj, cg->stackDepth); + ndefs = OBJ_BLOCK_COUNT(cx, blockObj); + } + cg->stackDepth += ndefs; + if ((uintN)cg->stackDepth > cg->maxStackDepth) + cg->maxStackDepth = cg->stackDepth; +} + +ptrdiff_t +js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op) +{ + ptrdiff_t offset = EmitCheck(cx, cg, op, 1); + + if (offset >= 0) { + *CG_NEXT(cg)++ = (jsbytecode)op; + UpdateDepth(cx, cg, offset); + } + return offset; +} + +ptrdiff_t +js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1) +{ + ptrdiff_t offset = EmitCheck(cx, cg, op, 2); + + if (offset >= 0) { + jsbytecode *next = CG_NEXT(cg); + next[0] = (jsbytecode)op; + next[1] = op1; + CG_NEXT(cg) = next + 2; + UpdateDepth(cx, cg, offset); + } + return offset; +} + +ptrdiff_t +js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1, + jsbytecode op2) +{ + ptrdiff_t offset = EmitCheck(cx, cg, op, 3); + + if (offset >= 0) { + jsbytecode *next = CG_NEXT(cg); + next[0] = (jsbytecode)op; + next[1] = op1; + next[2] = op2; + CG_NEXT(cg) = next + 3; + UpdateDepth(cx, cg, offset); + } + return offset; +} + +ptrdiff_t +js_Emit5(JSContext *cx, JSCodeGenerator *cg, JSOp op, uint16 op1, uint16 op2) +{ + ptrdiff_t offset = EmitCheck(cx, cg, op, 5); + + if (offset >= 0) { + jsbytecode *next = CG_NEXT(cg); + next[0] = (jsbytecode)op; + next[1] = UINT16_HI(op1); + next[2] = UINT16_LO(op1); + next[3] = UINT16_HI(op2); + next[4] = UINT16_LO(op2); + CG_NEXT(cg) = next + 5; + UpdateDepth(cx, cg, offset); + } + return offset; +} + +ptrdiff_t +js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra) +{ + ptrdiff_t length = 1 + (ptrdiff_t)extra; + ptrdiff_t offset = EmitCheck(cx, cg, op, length); + + if (offset >= 0) { + jsbytecode *next = CG_NEXT(cg); + *next = (jsbytecode)op; + memset(next + 1, 0, BYTECODE_SIZE(extra)); + CG_NEXT(cg) = next + length; + + /* + * Don't UpdateDepth if op's use-count comes from the immediate + * operand yet to be stored in the extra bytes after op. + */ + if (js_CodeSpec[op].nuses >= 0) + UpdateDepth(cx, cg, offset); + } + return offset; +} + +/* XXX too many "... statement" L10N gaffes below -- fix via js.msg! */ +const char js_with_statement_str[] = "with statement"; +const char js_finally_block_str[] = "finally block"; +const char js_script_str[] = "script"; + +static const char *statementName[] = { + "label statement", /* LABEL */ + "if statement", /* IF */ + "else statement", /* ELSE */ + "destructuring body", /* BODY */ + "switch statement", /* SWITCH */ + "block", /* BLOCK */ + js_with_statement_str, /* WITH */ + "catch block", /* CATCH */ + "try block", /* TRY */ + js_finally_block_str, /* FINALLY */ + js_finally_block_str, /* SUBROUTINE */ + "do loop", /* DO_LOOP */ + "for loop", /* FOR_LOOP */ + "for/in loop", /* FOR_IN_LOOP */ + "while loop", /* WHILE_LOOP */ +}; + +JS_STATIC_ASSERT(JS_ARRAY_LENGTH(statementName) == STMT_LIMIT); + +static const char * +StatementName(JSCodeGenerator *cg) +{ + if (!cg->topStmt) + return js_script_str; + return statementName[cg->topStmt->type]; +} + +static void +ReportStatementTooLarge(JSContext *cx, JSCodeGenerator *cg) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEED_DIET, + StatementName(cg)); +} + +/** + Span-dependent instructions in JS bytecode consist of the jump (JOF_JUMP) + and switch (JOF_LOOKUPSWITCH, JOF_TABLESWITCH) format opcodes, subdivided + into unconditional (gotos and gosubs), and conditional jumps or branches + (which pop a value, test it, and jump depending on its value). Most jumps + have just one immediate operand, a signed offset from the jump opcode's pc + to the target bytecode. The lookup and table switch opcodes may contain + many jump offsets. + + Mozilla bug #80981 (http://bugzilla.mozilla.org/show_bug.cgi?id=80981) was + fixed by adding extended "X" counterparts to the opcodes/formats (NB: X is + suffixed to prefer JSOP_ORX thereby avoiding a JSOP_XOR name collision for + the extended form of the JSOP_OR branch opcode). The unextended or short + formats have 16-bit signed immediate offset operands, the extended or long + formats have 32-bit signed immediates. The span-dependency problem consists + of selecting as few long instructions as possible, or about as few -- since + jumps can span other jumps, extending one jump may cause another to need to + be extended. + + Most JS scripts are short, so need no extended jumps. We optimize for this + case by generating short jumps until we know a long jump is needed. After + that point, we keep generating short jumps, but each jump's 16-bit immediate + offset operand is actually an unsigned index into cg->spanDeps, an array of + JSSpanDep structs. Each struct tells the top offset in the script of the + opcode, the "before" offset of the jump (which will be the same as top for + simplex jumps, but which will index further into the bytecode array for a + non-initial jump offset in a lookup or table switch), the after "offset" + adjusted during span-dependent instruction selection (initially the same + value as the "before" offset), and the jump target (more below). + + Since we generate cg->spanDeps lazily, from within js_SetJumpOffset, we must + ensure that all bytecode generated so far can be inspected to discover where + the jump offset immediate operands lie within CG_CODE(cg). But the bonus is + that we generate span-dependency records sorted by their offsets, so we can + binary-search when trying to find a JSSpanDep for a given bytecode offset, + or the nearest JSSpanDep at or above a given pc. + + To avoid limiting scripts to 64K jumps, if the cg->spanDeps index overflows + 65534, we store SPANDEP_INDEX_HUGE in the jump's immediate operand. This + tells us that we need to binary-search for the cg->spanDeps entry by the + jump opcode's bytecode offset (sd->before). + + Jump targets need to be maintained in a data structure that lets us look + up an already-known target by its address (jumps may have a common target), + and that also lets us update the addresses (script-relative, a.k.a. absolute + offsets) of targets that come after a jump target (for when a jump below + that target needs to be extended). We use an AVL tree, implemented using + recursion, but with some tricky optimizations to its height-balancing code + (see http://www.cmcrossroads.com/bradapp/ftp/src/libs/C++/AvlTrees.html). + + A final wrinkle: backpatch chains are linked by jump-to-jump offsets with + positive sign, even though they link "backward" (i.e., toward lower bytecode + address). We don't want to waste space and search time in the AVL tree for + such temporary backpatch deltas, so we use a single-bit wildcard scheme to + tag true JSJumpTarget pointers and encode untagged, signed (positive) deltas + in JSSpanDep.target pointers, depending on whether the JSSpanDep has a known + target, or is still awaiting backpatching. + + Note that backpatch chains would present a problem for BuildSpanDepTable, + which inspects bytecode to build cg->spanDeps on demand, when the first + short jump offset overflows. To solve this temporary problem, we emit a + proxy bytecode (JSOP_BACKPATCH; JSOP_BACKPATCH_POP for branch ops) whose + nuses/ndefs counts help keep the stack balanced, but whose opcode format + distinguishes its backpatch delta immediate operand from a normal jump + offset. + */ +static int +BalanceJumpTargets(JSJumpTarget **jtp) +{ + JSJumpTarget *jt, *jt2, *root; + int dir, otherDir, heightChanged; + JSBool doubleRotate; + + jt = *jtp; + JS_ASSERT(jt->balance != 0); + + if (jt->balance < -1) { + dir = JT_RIGHT; + doubleRotate = (jt->kids[JT_LEFT]->balance > 0); + } else if (jt->balance > 1) { + dir = JT_LEFT; + doubleRotate = (jt->kids[JT_RIGHT]->balance < 0); + } else { + return 0; + } + + otherDir = JT_OTHER_DIR(dir); + if (doubleRotate) { + jt2 = jt->kids[otherDir]; + *jtp = root = jt2->kids[dir]; + + jt->kids[otherDir] = root->kids[dir]; + root->kids[dir] = jt; + + jt2->kids[dir] = root->kids[otherDir]; + root->kids[otherDir] = jt2; + + heightChanged = 1; + root->kids[JT_LEFT]->balance = -JS_MAX(root->balance, 0); + root->kids[JT_RIGHT]->balance = -JS_MIN(root->balance, 0); + root->balance = 0; + } else { + *jtp = root = jt->kids[otherDir]; + jt->kids[otherDir] = root->kids[dir]; + root->kids[dir] = jt; + + heightChanged = (root->balance != 0); + jt->balance = -((dir == JT_LEFT) ? --root->balance : ++root->balance); + } + + return heightChanged; +} + +typedef struct AddJumpTargetArgs { + JSContext *cx; + JSCodeGenerator *cg; + ptrdiff_t offset; + JSJumpTarget *node; +} AddJumpTargetArgs; + +static int +AddJumpTarget(AddJumpTargetArgs *args, JSJumpTarget **jtp) +{ + JSJumpTarget *jt; + int balanceDelta; + + jt = *jtp; + if (!jt) { + JSCodeGenerator *cg = args->cg; + + jt = cg->jtFreeList; + if (jt) { + cg->jtFreeList = jt->kids[JT_LEFT]; + } else { + JS_ARENA_ALLOCATE_CAST(jt, JSJumpTarget *, &args->cx->tempPool, + sizeof *jt); + if (!jt) { + js_ReportOutOfScriptQuota(args->cx); + return 0; + } + } + jt->offset = args->offset; + jt->balance = 0; + jt->kids[JT_LEFT] = jt->kids[JT_RIGHT] = NULL; + cg->numJumpTargets++; + args->node = jt; + *jtp = jt; + return 1; + } + + if (jt->offset == args->offset) { + args->node = jt; + return 0; + } + + if (args->offset < jt->offset) + balanceDelta = -AddJumpTarget(args, &jt->kids[JT_LEFT]); + else + balanceDelta = AddJumpTarget(args, &jt->kids[JT_RIGHT]); + if (!args->node) + return 0; + + jt->balance += balanceDelta; + return (balanceDelta && jt->balance) + ? 1 - BalanceJumpTargets(jtp) + : 0; +} + +#ifdef DEBUG_brendan +static int AVLCheck(JSJumpTarget *jt) +{ + int lh, rh; + + if (!jt) return 0; + JS_ASSERT(-1 <= jt->balance && jt->balance <= 1); + lh = AVLCheck(jt->kids[JT_LEFT]); + rh = AVLCheck(jt->kids[JT_RIGHT]); + JS_ASSERT(jt->balance == rh - lh); + return 1 + JS_MAX(lh, rh); +} +#endif + +static JSBool +SetSpanDepTarget(JSContext *cx, JSCodeGenerator *cg, JSSpanDep *sd, + ptrdiff_t off) +{ + AddJumpTargetArgs args; + + if (off < JUMPX_OFFSET_MIN || JUMPX_OFFSET_MAX < off) { + ReportStatementTooLarge(cx, cg); + return JS_FALSE; + } + + args.cx = cx; + args.cg = cg; + args.offset = sd->top + off; + args.node = NULL; + AddJumpTarget(&args, &cg->jumpTargets); + if (!args.node) + return JS_FALSE; + +#ifdef DEBUG_brendan + AVLCheck(cg->jumpTargets); +#endif + + SD_SET_TARGET(sd, args.node); + return JS_TRUE; +} + +#define SPANDEPS_MIN 256 +#define SPANDEPS_SIZE(n) ((n) * sizeof(JSSpanDep)) +#define SPANDEPS_SIZE_MIN SPANDEPS_SIZE(SPANDEPS_MIN) + +static JSBool +AddSpanDep(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, jsbytecode *pc2, + ptrdiff_t off) +{ + uintN index; + JSSpanDep *sdbase, *sd; + size_t size; + + index = cg->numSpanDeps; + if (index + 1 == 0) { + ReportStatementTooLarge(cx, cg); + return JS_FALSE; + } + + if ((index & (index - 1)) == 0 && + (!(sdbase = cg->spanDeps) || index >= SPANDEPS_MIN)) { + size = sdbase ? SPANDEPS_SIZE(index) : SPANDEPS_SIZE_MIN / 2; + sdbase = (JSSpanDep *) cx->realloc(sdbase, size + size); + if (!sdbase) + return JS_FALSE; + cg->spanDeps = sdbase; + } + + cg->numSpanDeps = index + 1; + sd = cg->spanDeps + index; + sd->top = pc - CG_BASE(cg); + sd->offset = sd->before = pc2 - CG_BASE(cg); + + if (js_CodeSpec[*pc].format & JOF_BACKPATCH) { + /* Jump offset will be backpatched if off is a non-zero "bpdelta". */ + if (off != 0) { + JS_ASSERT(off >= 1 + JUMP_OFFSET_LEN); + if (off > BPDELTA_MAX) { + ReportStatementTooLarge(cx, cg); + return JS_FALSE; + } + } + SD_SET_BPDELTA(sd, off); + } else if (off == 0) { + /* Jump offset will be patched directly, without backpatch chaining. */ + SD_SET_TARGET(sd, 0); + } else { + /* The jump offset in off is non-zero, therefore it's already known. */ + if (!SetSpanDepTarget(cx, cg, sd, off)) + return JS_FALSE; + } + + if (index > SPANDEP_INDEX_MAX) + index = SPANDEP_INDEX_HUGE; + SET_SPANDEP_INDEX(pc2, index); + return JS_TRUE; +} + +static jsbytecode * +AddSwitchSpanDeps(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc) +{ + JSOp op; + jsbytecode *pc2; + ptrdiff_t off; + jsint low, high; + uintN njumps, indexlen; + + op = (JSOp) *pc; + JS_ASSERT(op == JSOP_TABLESWITCH || op == JSOP_LOOKUPSWITCH); + pc2 = pc; + off = GET_JUMP_OFFSET(pc2); + if (!AddSpanDep(cx, cg, pc, pc2, off)) + return NULL; + pc2 += JUMP_OFFSET_LEN; + if (op == JSOP_TABLESWITCH) { + low = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + high = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + njumps = (uintN) (high - low + 1); + indexlen = 0; + } else { + njumps = GET_UINT16(pc2); + pc2 += UINT16_LEN; + indexlen = INDEX_LEN; + } + while (njumps) { + --njumps; + pc2 += indexlen; + off = GET_JUMP_OFFSET(pc2); + if (!AddSpanDep(cx, cg, pc, pc2, off)) + return NULL; + pc2 += JUMP_OFFSET_LEN; + } + return 1 + pc2; +} + +static JSBool +BuildSpanDepTable(JSContext *cx, JSCodeGenerator *cg) +{ + jsbytecode *pc, *end; + JSOp op; + const JSCodeSpec *cs; + ptrdiff_t off; + + pc = CG_BASE(cg) + cg->spanDepTodo; + end = CG_NEXT(cg); + while (pc != end) { + JS_ASSERT(pc < end); + op = (JSOp)*pc; + cs = &js_CodeSpec[op]; + + switch (JOF_TYPE(cs->format)) { + case JOF_TABLESWITCH: + case JOF_LOOKUPSWITCH: + pc = AddSwitchSpanDeps(cx, cg, pc); + if (!pc) + return JS_FALSE; + break; + + case JOF_JUMP: + off = GET_JUMP_OFFSET(pc); + if (!AddSpanDep(cx, cg, pc, pc, off)) + return JS_FALSE; + /* FALL THROUGH */ + default: + pc += cs->length; + break; + } + } + + return JS_TRUE; +} + +static JSSpanDep * +GetSpanDep(JSCodeGenerator *cg, jsbytecode *pc) +{ + uintN index; + ptrdiff_t offset; + int lo, hi, mid; + JSSpanDep *sd; + + index = GET_SPANDEP_INDEX(pc); + if (index != SPANDEP_INDEX_HUGE) + return cg->spanDeps + index; + + offset = pc - CG_BASE(cg); + lo = 0; + hi = cg->numSpanDeps - 1; + while (lo <= hi) { + mid = (lo + hi) / 2; + sd = cg->spanDeps + mid; + if (sd->before == offset) + return sd; + if (sd->before < offset) + lo = mid + 1; + else + hi = mid - 1; + } + + JS_ASSERT(0); + return NULL; +} + +static JSBool +SetBackPatchDelta(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, + ptrdiff_t delta) +{ + JSSpanDep *sd; + + JS_ASSERT(delta >= 1 + JUMP_OFFSET_LEN); + if (!cg->spanDeps && delta < JUMP_OFFSET_MAX) { + SET_JUMP_OFFSET(pc, delta); + return JS_TRUE; + } + + if (delta > BPDELTA_MAX) { + ReportStatementTooLarge(cx, cg); + return JS_FALSE; + } + + if (!cg->spanDeps && !BuildSpanDepTable(cx, cg)) + return JS_FALSE; + + sd = GetSpanDep(cg, pc); + JS_ASSERT(SD_GET_BPDELTA(sd) == 0); + SD_SET_BPDELTA(sd, delta); + return JS_TRUE; +} + +static void +UpdateJumpTargets(JSJumpTarget *jt, ptrdiff_t pivot, ptrdiff_t delta) +{ + if (jt->offset > pivot) { + jt->offset += delta; + if (jt->kids[JT_LEFT]) + UpdateJumpTargets(jt->kids[JT_LEFT], pivot, delta); + } + if (jt->kids[JT_RIGHT]) + UpdateJumpTargets(jt->kids[JT_RIGHT], pivot, delta); +} + +static JSSpanDep * +FindNearestSpanDep(JSCodeGenerator *cg, ptrdiff_t offset, int lo, + JSSpanDep *guard) +{ + int num, hi, mid; + JSSpanDep *sdbase, *sd; + + num = cg->numSpanDeps; + JS_ASSERT(num > 0); + hi = num - 1; + sdbase = cg->spanDeps; + while (lo <= hi) { + mid = (lo + hi) / 2; + sd = sdbase + mid; + if (sd->before == offset) + return sd; + if (sd->before < offset) + lo = mid + 1; + else + hi = mid - 1; + } + if (lo == num) + return guard; + sd = sdbase + lo; + JS_ASSERT(sd->before >= offset && (lo == 0 || sd[-1].before < offset)); + return sd; +} + +static void +FreeJumpTargets(JSCodeGenerator *cg, JSJumpTarget *jt) +{ + if (jt->kids[JT_LEFT]) + FreeJumpTargets(cg, jt->kids[JT_LEFT]); + if (jt->kids[JT_RIGHT]) + FreeJumpTargets(cg, jt->kids[JT_RIGHT]); + jt->kids[JT_LEFT] = cg->jtFreeList; + cg->jtFreeList = jt; +} + +static JSBool +OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg) +{ + jsbytecode *pc, *oldpc, *base, *limit, *next; + JSSpanDep *sd, *sd2, *sdbase, *sdlimit, *sdtop, guard; + ptrdiff_t offset, growth, delta, top, pivot, span, length, target; + JSBool done; + JSOp op; + uint32 type; + size_t size, incr; + jssrcnote *sn, *snlimit; + JSSrcNoteSpec *spec; + uintN i, n, noteIndex; + JSTryNode *tryNode; +#ifdef DEBUG_brendan + int passes = 0; +#endif + + base = CG_BASE(cg); + sdbase = cg->spanDeps; + sdlimit = sdbase + cg->numSpanDeps; + offset = CG_OFFSET(cg); + growth = 0; + + do { + done = JS_TRUE; + delta = 0; + top = pivot = -1; + sdtop = NULL; + pc = NULL; + op = JSOP_NOP; + type = 0; +#ifdef DEBUG_brendan + passes++; +#endif + + for (sd = sdbase; sd < sdlimit; sd++) { + JS_ASSERT(JT_HAS_TAG(sd->target)); + sd->offset += delta; + + if (sd->top != top) { + sdtop = sd; + top = sd->top; + JS_ASSERT(top == sd->before); + pivot = sd->offset; + pc = base + top; + op = (JSOp) *pc; + type = JOF_OPTYPE(op); + if (JOF_TYPE_IS_EXTENDED_JUMP(type)) { + /* + * We already extended all the jump offset operands for + * the opcode at sd->top. Jumps and branches have only + * one jump offset operand, but switches have many, all + * of which are adjacent in cg->spanDeps. + */ + continue; + } + + JS_ASSERT(type == JOF_JUMP || + type == JOF_TABLESWITCH || + type == JOF_LOOKUPSWITCH); + } + + if (!JOF_TYPE_IS_EXTENDED_JUMP(type)) { + span = SD_SPAN(sd, pivot); + if (span < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < span) { + ptrdiff_t deltaFromTop = 0; + + done = JS_FALSE; + + switch (op) { + case JSOP_GOTO: op = JSOP_GOTOX; break; + case JSOP_IFEQ: op = JSOP_IFEQX; break; + case JSOP_IFNE: op = JSOP_IFNEX; break; + case JSOP_OR: op = JSOP_ORX; break; + case JSOP_AND: op = JSOP_ANDX; break; + case JSOP_GOSUB: op = JSOP_GOSUBX; break; + case JSOP_CASE: op = JSOP_CASEX; break; + case JSOP_DEFAULT: op = JSOP_DEFAULTX; break; + case JSOP_TABLESWITCH: op = JSOP_TABLESWITCHX; break; + case JSOP_LOOKUPSWITCH: op = JSOP_LOOKUPSWITCHX; break; + default: + ReportStatementTooLarge(cx, cg); + return JS_FALSE; + } + *pc = (jsbytecode) op; + + for (sd2 = sdtop; sd2 < sdlimit && sd2->top == top; sd2++) { + if (sd2 <= sd) { + /* + * sd2->offset already includes delta as it stood + * before we entered this loop, but it must also + * include the delta relative to top due to all the + * extended jump offset immediates for the opcode + * starting at top, which we extend in this loop. + * + * If there is only one extended jump offset, then + * sd2->offset won't change and this for loop will + * iterate once only. + */ + sd2->offset += deltaFromTop; + deltaFromTop += JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN; + } else { + /* + * sd2 comes after sd, and won't be revisited by + * the outer for loop, so we have to increase its + * offset by delta, not merely by deltaFromTop. + */ + sd2->offset += delta; + } + + delta += JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN; + UpdateJumpTargets(cg->jumpTargets, sd2->offset, + JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN); + } + sd = sd2 - 1; + } + } + } + + growth += delta; + } while (!done); + + if (growth) { +#ifdef DEBUG_brendan + TokenStream *ts = &cg->parser->tokenStream; + + printf("%s:%u: %u/%u jumps extended in %d passes (%d=%d+%d)\n", + ts->filename ? ts->filename : "stdin", cg->firstLine, + growth / (JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN), cg->numSpanDeps, + passes, offset + growth, offset, growth); +#endif + + /* + * Ensure that we have room for the extended jumps, but don't round up + * to a power of two -- we're done generating code, so we cut to fit. + */ + limit = CG_LIMIT(cg); + length = offset + growth; + next = base + length; + if (next > limit) { + JS_ASSERT(length > BYTECODE_CHUNK); + size = BYTECODE_SIZE(limit - base); + incr = BYTECODE_SIZE(length) - size; + JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr); + if (!base) { + js_ReportOutOfScriptQuota(cx); + return JS_FALSE; + } + CG_BASE(cg) = base; + CG_LIMIT(cg) = next = base + length; + } + CG_NEXT(cg) = next; + + /* + * Set up a fake span dependency record to guard the end of the code + * being generated. This guard record is returned as a fencepost by + * FindNearestSpanDep if there is no real spandep at or above a given + * unextended code offset. + */ + guard.top = -1; + guard.offset = offset + growth; + guard.before = offset; + guard.target = NULL; + } + + /* + * Now work backwards through the span dependencies, copying chunks of + * bytecode between each extended jump toward the end of the grown code + * space, and restoring immediate offset operands for all jump bytecodes. + * The first chunk of bytecodes, starting at base and ending at the first + * extended jump offset (NB: this chunk includes the operation bytecode + * just before that immediate jump offset), doesn't need to be copied. + */ + JS_ASSERT(sd == sdlimit); + top = -1; + while (--sd >= sdbase) { + if (sd->top != top) { + top = sd->top; + op = (JSOp) base[top]; + type = JOF_OPTYPE(op); + + for (sd2 = sd - 1; sd2 >= sdbase && sd2->top == top; sd2--) + continue; + sd2++; + pivot = sd2->offset; + JS_ASSERT(top == sd2->before); + } + + oldpc = base + sd->before; + span = SD_SPAN(sd, pivot); + + /* + * If this jump didn't need to be extended, restore its span immediate + * offset operand now, overwriting the index of sd within cg->spanDeps + * that was stored temporarily after *pc when BuildSpanDepTable ran. + * + * Note that span might fit in 16 bits even for an extended jump op, + * if the op has multiple span operands, not all of which overflowed + * (e.g. JSOP_LOOKUPSWITCH or JSOP_TABLESWITCH where some cases are in + * range for a short jump, but others are not). + */ + if (!JOF_TYPE_IS_EXTENDED_JUMP(type)) { + JS_ASSERT(JUMP_OFFSET_MIN <= span && span <= JUMP_OFFSET_MAX); + SET_JUMP_OFFSET(oldpc, span); + continue; + } + + /* + * Set up parameters needed to copy the next run of bytecode starting + * at offset (which is a cursor into the unextended, original bytecode + * vector), down to sd->before (a cursor of the same scale as offset, + * it's the index of the original jump pc). Reuse delta to count the + * nominal number of bytes to copy. + */ + pc = base + sd->offset; + delta = offset - sd->before; + JS_ASSERT(delta >= 1 + JUMP_OFFSET_LEN); + + /* + * Don't bother copying the jump offset we're about to reset, but do + * copy the bytecode at oldpc (which comes just before its immediate + * jump offset operand), on the next iteration through the loop, by + * including it in offset's new value. + */ + offset = sd->before + 1; + size = BYTECODE_SIZE(delta - (1 + JUMP_OFFSET_LEN)); + if (size) { + memmove(pc + 1 + JUMPX_OFFSET_LEN, + oldpc + 1 + JUMP_OFFSET_LEN, + size); + } + + SET_JUMPX_OFFSET(pc, span); + } + + if (growth) { + /* + * Fix source note deltas. Don't hardwire the delta fixup adjustment, + * even though currently it must be JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN + * at each sd that moved. The future may bring different offset sizes + * for span-dependent instruction operands. However, we fix only main + * notes here, not prolog notes -- we know that prolog opcodes are not + * span-dependent, and aren't likely ever to be. + */ + offset = growth = 0; + sd = sdbase; + for (sn = cg->main.notes, snlimit = sn + cg->main.noteCount; + sn < snlimit; + sn = SN_NEXT(sn)) { + /* + * Recall that the offset of a given note includes its delta, and + * tells the offset of the annotated bytecode from the main entry + * point of the script. + */ + offset += SN_DELTA(sn); + while (sd < sdlimit && sd->before < offset) { + /* + * To compute the delta to add to sn, we need to look at the + * spandep after sd, whose offset - (before + growth) tells by + * how many bytes sd's instruction grew. + */ + sd2 = sd + 1; + if (sd2 == sdlimit) + sd2 = &guard; + delta = sd2->offset - (sd2->before + growth); + if (delta > 0) { + JS_ASSERT(delta == JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN); + sn = js_AddToSrcNoteDelta(cx, cg, sn, delta); + if (!sn) + return JS_FALSE; + snlimit = cg->main.notes + cg->main.noteCount; + growth += delta; + } + sd++; + } + + /* + * If sn has span-dependent offset operands, check whether each + * covers further span-dependencies, and increase those operands + * accordingly. Some source notes measure offset not from the + * annotated pc, but from that pc plus some small bias. NB: we + * assume that spec->offsetBias can't itself span span-dependent + * instructions! + */ + spec = &js_SrcNoteSpec[SN_TYPE(sn)]; + if (spec->isSpanDep) { + pivot = offset + spec->offsetBias; + n = spec->arity; + for (i = 0; i < n; i++) { + span = js_GetSrcNoteOffset(sn, i); + if (span == 0) + continue; + target = pivot + span * spec->isSpanDep; + sd2 = FindNearestSpanDep(cg, target, + (target >= pivot) + ? sd - sdbase + : 0, + &guard); + + /* + * Increase target by sd2's before-vs-after offset delta, + * which is absolute (i.e., relative to start of script, + * as is target). Recompute the span by subtracting its + * adjusted pivot from target. + */ + target += sd2->offset - sd2->before; + span = target - (pivot + growth); + span *= spec->isSpanDep; + noteIndex = sn - cg->main.notes; + if (!js_SetSrcNoteOffset(cx, cg, noteIndex, i, span)) + return JS_FALSE; + sn = cg->main.notes + noteIndex; + snlimit = cg->main.notes + cg->main.noteCount; + } + } + } + cg->main.lastNoteOffset += growth; + + /* + * Fix try/catch notes (O(numTryNotes * log2(numSpanDeps)), but it's + * not clear how we can beat that). + */ + for (tryNode = cg->lastTryNode; tryNode; tryNode = tryNode->prev) { + /* + * First, look for the nearest span dependency at/above tn->start. + * There may not be any such spandep, in which case the guard will + * be returned. + */ + offset = tryNode->note.start; + sd = FindNearestSpanDep(cg, offset, 0, &guard); + delta = sd->offset - sd->before; + tryNode->note.start = offset + delta; + + /* + * Next, find the nearest spandep at/above tn->start + tn->length. + * Use its delta minus tn->start's delta to increase tn->length. + */ + length = tryNode->note.length; + sd2 = FindNearestSpanDep(cg, offset + length, sd - sdbase, &guard); + if (sd2 != sd) { + tryNode->note.length = + length + sd2->offset - sd2->before - delta; + } + } + } + +#ifdef DEBUG_brendan + { + uintN bigspans = 0; + top = -1; + for (sd = sdbase; sd < sdlimit; sd++) { + offset = sd->offset; + + /* NB: sd->top cursors into the original, unextended bytecode vector. */ + if (sd->top != top) { + JS_ASSERT(top == -1 || + !JOF_TYPE_IS_EXTENDED_JUMP(type) || + bigspans != 0); + bigspans = 0; + top = sd->top; + JS_ASSERT(top == sd->before); + op = (JSOp) base[offset]; + type = JOF_OPTYPE(op); + JS_ASSERT(type == JOF_JUMP || + type == JOF_JUMPX || + type == JOF_TABLESWITCH || + type == JOF_TABLESWITCHX || + type == JOF_LOOKUPSWITCH || + type == JOF_LOOKUPSWITCHX); + pivot = offset; + } + + pc = base + offset; + if (JOF_TYPE_IS_EXTENDED_JUMP(type)) { + span = GET_JUMPX_OFFSET(pc); + if (span < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < span) { + bigspans++; + } else { + JS_ASSERT(type == JOF_TABLESWITCHX || + type == JOF_LOOKUPSWITCHX); + } + } else { + span = GET_JUMP_OFFSET(pc); + } + JS_ASSERT(SD_SPAN(sd, pivot) == span); + } + JS_ASSERT(!JOF_TYPE_IS_EXTENDED_JUMP(type) || bigspans != 0); + } +#endif + + /* + * Reset so we optimize at most once -- cg may be used for further code + * generation of successive, independent, top-level statements. No jump + * can span top-level statements, because JS lacks goto. + */ + size = SPANDEPS_SIZE(JS_BIT(JS_CeilingLog2(cg->numSpanDeps))); + cx->free(cg->spanDeps); + cg->spanDeps = NULL; + FreeJumpTargets(cg, cg->jumpTargets); + cg->jumpTargets = NULL; + cg->numSpanDeps = cg->numJumpTargets = 0; + cg->spanDepTodo = CG_OFFSET(cg); + return JS_TRUE; +} + +static ptrdiff_t +EmitJump(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t off) +{ + JSBool extend; + ptrdiff_t jmp; + jsbytecode *pc; + + extend = off < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < off; + if (extend && !cg->spanDeps && !BuildSpanDepTable(cx, cg)) + return -1; + + jmp = js_Emit3(cx, cg, op, JUMP_OFFSET_HI(off), JUMP_OFFSET_LO(off)); + if (jmp >= 0 && (extend || cg->spanDeps)) { + pc = CG_CODE(cg, jmp); + if (!AddSpanDep(cx, cg, pc, pc, off)) + return -1; + } + return jmp; +} + +static ptrdiff_t +GetJumpOffset(JSCodeGenerator *cg, jsbytecode *pc) +{ + JSSpanDep *sd; + JSJumpTarget *jt; + ptrdiff_t top; + + if (!cg->spanDeps) + return GET_JUMP_OFFSET(pc); + + sd = GetSpanDep(cg, pc); + jt = sd->target; + if (!JT_HAS_TAG(jt)) + return JT_TO_BPDELTA(jt); + + top = sd->top; + while (--sd >= cg->spanDeps && sd->top == top) + continue; + sd++; + return JT_CLR_TAG(jt)->offset - sd->offset; +} + +JSBool +js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, + ptrdiff_t off) +{ + if (!cg->spanDeps) { + if (JUMP_OFFSET_MIN <= off && off <= JUMP_OFFSET_MAX) { + SET_JUMP_OFFSET(pc, off); + return JS_TRUE; + } + + if (!BuildSpanDepTable(cx, cg)) + return JS_FALSE; + } + + return SetSpanDepTarget(cx, cg, GetSpanDep(cg, pc), off); +} + +bool +JSTreeContext::inStatement(JSStmtType type) +{ + for (JSStmtInfo *stmt = topStmt; stmt; stmt = stmt->down) { + if (stmt->type == type) + return true; + } + return false; +} + +bool +JSTreeContext::ensureSharpSlots() +{ +#if JS_HAS_SHARP_VARS + JS_STATIC_ASSERT(SHARP_NSLOTS == 2); + + if (sharpSlotBase >= 0) { + JS_ASSERT(flags & TCF_HAS_SHARPS); + return true; + } + + JS_ASSERT(!(flags & TCF_HAS_SHARPS)); + if (inFunction()) { + JSContext *cx = parser->context; + JSAtom *sharpArrayAtom = js_Atomize(cx, "#array", 6, 0); + JSAtom *sharpDepthAtom = js_Atomize(cx, "#depth", 6, 0); + if (!sharpArrayAtom || !sharpDepthAtom) + return false; + + sharpSlotBase = bindings.countVars(); + if (!bindings.addVariable(cx, sharpArrayAtom)) + return false; + if (!bindings.addVariable(cx, sharpDepthAtom)) + return false; + } else { + /* + * Compiler::compileScript will rebase immediate operands indexing + * the sharp slots to come at the end of the global script's |nfixed| + * slots storage, after gvars and regexps. + */ + sharpSlotBase = 0; + } + flags |= TCF_HAS_SHARPS; +#endif + return true; +} + +bool +JSTreeContext::skipSpansGenerator(unsigned skip) +{ + JSTreeContext *tc = this; + for (unsigned i = 0; i < skip; ++i, tc = tc->parent) { + if (!tc) + return false; + if (tc->flags & TCF_FUN_IS_GENERATOR) + return true; + } + return false; +} + +void +js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type, + ptrdiff_t top) +{ + stmt->type = type; + stmt->flags = 0; + stmt->blockid = tc->blockid(); + SET_STATEMENT_TOP(stmt, top); + stmt->label = NULL; + JS_ASSERT(!stmt->blockBox); + stmt->down = tc->topStmt; + tc->topStmt = stmt; + if (STMT_LINKS_SCOPE(stmt)) { + stmt->downScope = tc->topScopeStmt; + tc->topScopeStmt = stmt; + } else { + stmt->downScope = NULL; + } +} + +void +js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObjectBox *blockBox, + ptrdiff_t top) +{ + js_PushStatement(tc, stmt, STMT_BLOCK, top); + stmt->flags |= SIF_SCOPE; + blockBox->parent = tc->blockChainBox; + blockBox->object->setParent(tc->blockChain()); + stmt->downScope = tc->topScopeStmt; + tc->topScopeStmt = stmt; + tc->blockChainBox = blockBox; + stmt->blockBox = blockBox; +} + +/* + * Emit a backpatch op with offset pointing to the previous jump of this type, + * so that we can walk back up the chain fixing up the op and jump offset. + */ +static ptrdiff_t +EmitBackPatchOp(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t *lastp) +{ + ptrdiff_t offset, delta; + + offset = CG_OFFSET(cg); + delta = offset - *lastp; + *lastp = offset; + JS_ASSERT(delta > 0); + return EmitJump(cx, cg, op, delta); +} + +static ptrdiff_t +EmitTraceOp(JSContext *cx, JSCodeGenerator *cg) +{ + uint32 index = cg->traceIndex; + if (index < UINT16_MAX) + cg->traceIndex++; + return js_Emit3(cx, cg, JSOP_TRACE, UINT16_HI(index), UINT16_LO(index)); +} + +/* + * Macro to emit a bytecode followed by a uint16 immediate operand stored in + * big-endian order, used for arg and var numbers as well as for atomIndexes. + * NB: We use cx and cg from our caller's lexical environment, and return + * false on error. + */ +#define EMIT_UINT16_IMM_OP(op, i) \ + JS_BEGIN_MACRO \ + if (js_Emit3(cx, cg, op, UINT16_HI(i), UINT16_LO(i)) < 0) \ + return JS_FALSE; \ + JS_END_MACRO + +#define EMIT_UINT16PAIR_IMM_OP(op, i, j) \ + JS_BEGIN_MACRO \ + ptrdiff_t off_ = js_EmitN(cx, cg, op, 2 * UINT16_LEN); \ + if (off_ < 0) \ + return JS_FALSE; \ + jsbytecode *pc_ = CG_CODE(cg, off_); \ + SET_UINT16(pc_, i); \ + pc_ += UINT16_LEN; \ + SET_UINT16(pc_, j); \ + JS_END_MACRO + +#define EMIT_UINT16_IN_PLACE(offset, op, i) \ + JS_BEGIN_MACRO \ + CG_CODE(cg, offset)[0] = op; \ + CG_CODE(cg, offset)[1] = UINT16_HI(i); \ + CG_CODE(cg, offset)[2] = UINT16_LO(i); \ + JS_END_MACRO + +static JSBool +FlushPops(JSContext *cx, JSCodeGenerator *cg, intN *npops) +{ + JS_ASSERT(*npops != 0); + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + EMIT_UINT16_IMM_OP(JSOP_POPN, *npops); + *npops = 0; + return JS_TRUE; +} + +/* + * Emit additional bytecode(s) for non-local jumps. + */ +static JSBool +EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt) +{ + intN depth, npops; + JSStmtInfo *stmt; + + /* + * The non-local jump fixup we emit will unbalance cg->stackDepth, because + * the fixup replicates balanced code such as JSOP_LEAVEWITH emitted at the + * end of a with statement, so we save cg->stackDepth here and restore it + * just before a successful return. + */ + depth = cg->stackDepth; + npops = 0; + +#define FLUSH_POPS() if (npops && !FlushPops(cx, cg, &npops)) return JS_FALSE + + for (stmt = cg->topStmt; stmt != toStmt; stmt = stmt->down) { + switch (stmt->type) { + case STMT_FINALLY: + FLUSH_POPS(); + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + if (EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &GOSUBS(*stmt)) < 0) + return JS_FALSE; + break; + + case STMT_WITH: + /* There's a With object on the stack that we need to pop. */ + FLUSH_POPS(); + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) + return JS_FALSE; + break; + + case STMT_FOR_IN_LOOP: + /* + * The iterator and the object being iterated need to be popped. + */ + FLUSH_POPS(); + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_ENDITER) < 0) + return JS_FALSE; + break; + + case STMT_SUBROUTINE: + /* + * There's a [exception or hole, retsub pc-index] pair on the + * stack that we need to pop. + */ + npops += 2; + break; + + default:; + } + + if (stmt->flags & SIF_SCOPE) { + /* There is a Block object with locals on the stack to pop. */ + FLUSH_POPS(); + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + if (!EmitLeaveBlock(cx, cg, JSOP_LEAVEBLOCK, stmt->blockBox)) + return JS_FALSE; + } + } + + FLUSH_POPS(); + cg->stackDepth = depth; + return JS_TRUE; + +#undef FLUSH_POPS +} + +static JSBool +EmitKnownBlockChain(JSContext *cx, JSCodeGenerator *cg, JSObjectBox *box) +{ + if (box) + return EmitIndexOp(cx, JSOP_BLOCKCHAIN, box->index, cg); + return js_Emit1(cx, cg, JSOP_NULLBLOCKCHAIN) >= 0; +} + +static JSBool +EmitBlockChain(JSContext *cx, JSCodeGenerator *cg) +{ + return EmitKnownBlockChain(cx, cg, cg->blockChainBox); +} + +static ptrdiff_t +EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt, + ptrdiff_t *lastp, JSAtomListElement *label, JSSrcNoteType noteType) +{ + intN index; + + if (!EmitNonLocalJumpFixup(cx, cg, toStmt)) + return -1; + + if (label) + index = js_NewSrcNote2(cx, cg, noteType, (ptrdiff_t) ALE_INDEX(label)); + else if (noteType != SRC_NULL) + index = js_NewSrcNote(cx, cg, noteType); + else + index = 0; + if (index < 0) + return -1; + + ptrdiff_t result = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, lastp); + if (result < 0) + return result; + + if (!EmitBlockChain(cx, cg)) + return -1; + + return result; +} + +static JSBool +BackPatch(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t last, + jsbytecode *target, jsbytecode op) +{ + jsbytecode *pc, *stop; + ptrdiff_t delta, span; + + pc = CG_CODE(cg, last); + stop = CG_CODE(cg, -1); + while (pc != stop) { + delta = GetJumpOffset(cg, pc); + span = target - pc; + CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, span); + + /* + * Set *pc after jump offset in case bpdelta didn't overflow, but span + * does (if so, CHECK_AND_SET_JUMP_OFFSET might call BuildSpanDepTable + * and need to see the JSOP_BACKPATCH* op at *pc). + */ + *pc = op; + pc -= delta; + } + return JS_TRUE; +} + +void +js_PopStatement(JSTreeContext *tc) +{ + JSStmtInfo *stmt; + + stmt = tc->topStmt; + tc->topStmt = stmt->down; + if (STMT_LINKS_SCOPE(stmt)) { + tc->topScopeStmt = stmt->downScope; + if (stmt->flags & SIF_SCOPE) { + tc->blockChainBox = stmt->blockBox->parent; + JS_SCOPE_DEPTH_METERING(--tc->scopeDepth); + } + } +} + +JSBool +js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg) +{ + JSStmtInfo *stmt; + + stmt = cg->topStmt; + if (!STMT_IS_TRYING(stmt) && + (!BackPatch(cx, cg, stmt->breaks, CG_NEXT(cg), JSOP_GOTO) || + !BackPatch(cx, cg, stmt->continues, CG_CODE(cg, stmt->update), + JSOP_GOTO))) { + return JS_FALSE; + } + js_PopStatement(cg); + return JS_TRUE; +} + +JSBool +js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, + JSParseNode *pn) +{ + /* XXX just do numbers for now */ + if (pn->pn_type == TOK_NUMBER) { + if (!cg->constMap.put(atom, NumberValue(pn->pn_dval))) + return JS_FALSE; + } + return JS_TRUE; +} + +JSStmtInfo * +js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, JSStmtInfo *stmt) +{ + if (!stmt) + stmt = tc->topScopeStmt; + for (; stmt; stmt = stmt->downScope) { + if (stmt->type == STMT_WITH) + break; + + /* Skip "maybe scope" statements that don't contain let bindings. */ + if (!(stmt->flags & SIF_SCOPE)) + continue; + + JSObject *obj = stmt->blockBox->object; + JS_ASSERT(obj->isStaticBlock()); + + const Shape *shape = obj->nativeLookup(ATOM_TO_JSID(atom)); + if (shape) { + JS_ASSERT(shape->hasShortID()); + + if (slotp) { + JS_ASSERT(obj->getSlot(JSSLOT_BLOCK_DEPTH).isInt32()); + *slotp = obj->getSlot(JSSLOT_BLOCK_DEPTH).toInt32() + shape->shortid; + } + return stmt; + } + } + + if (slotp) + *slotp = -1; + return stmt; +} + +/* + * The function sets vp to NO_CONSTANT when the atom does not corresponds to a + * name defining a constant. + */ +static JSBool +LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, + Value *constp) +{ + JSStmtInfo *stmt; + JSObject *obj; + + /* + * Chase down the cg stack, but only until we reach the outermost cg. + * This enables propagating consts from top-level into switch cases in a + * function compiled along with the top-level script. + */ + constp->setMagic(JS_NO_CONSTANT); + do { + if (cg->inFunction() || cg->compileAndGo()) { + /* XXX this will need revising if 'const' becomes block-scoped. */ + stmt = js_LexicalLookup(cg, atom, NULL); + if (stmt) + return JS_TRUE; + + if (JSCodeGenerator::ConstMap::Ptr p = cg->constMap.lookup(atom)) { + JS_ASSERT(!p->value.isMagic(JS_NO_CONSTANT)); + *constp = p->value; + return JS_TRUE; + } + + /* + * Try looking in the variable object for a direct property that + * is readonly and permanent. We know such a property can't be + * shadowed by another property on obj's prototype chain, or a + * with object or catch variable; nor can prop's value be changed, + * nor can prop be deleted. + */ + if (cg->inFunction()) { + if (cg->bindings.hasBinding(cx, atom)) + break; + } else { + JS_ASSERT(cg->compileAndGo()); + obj = cg->scopeChain(); + + const Shape *shape = obj->nativeLookup(ATOM_TO_JSID(atom)); + if (shape) { + /* + * We're compiling code that will be executed immediately, + * not re-executed against a different scope chain and/or + * variable object. Therefore we can get constant values + * from our variable object here. + */ + if (!shape->writable() && !shape->configurable() && + shape->hasDefaultGetter() && obj->containsSlot(shape->slot)) { + *constp = obj->getSlot(shape->slot); + } + } + + if (shape) + break; + } + } + } while (cg->parent && (cg = cg->parent->asCodeGenerator())); + return JS_TRUE; +} + +static inline bool +FitsWithoutBigIndex(uintN index) +{ + return index < JS_BIT(16); +} + +/* + * Return JSOP_NOP to indicate that index fits 2 bytes and no index segment + * reset instruction is necessary, JSOP_FALSE to indicate an error or either + * JSOP_RESETBASE0 or JSOP_RESETBASE1 to indicate the reset bytecode to issue + * after the main bytecode sequence. + */ +static JSOp +EmitBigIndexPrefix(JSContext *cx, JSCodeGenerator *cg, uintN index) +{ + uintN indexBase; + + /* + * We have max 3 bytes for indexes and check for INDEX_LIMIT overflow only + * for big indexes. + */ + JS_STATIC_ASSERT(INDEX_LIMIT <= JS_BIT(24)); + JS_STATIC_ASSERT(INDEX_LIMIT >= + (JSOP_INDEXBASE3 - JSOP_INDEXBASE1 + 2) << 16); + + if (FitsWithoutBigIndex(index)) + return JSOP_NOP; + indexBase = index >> 16; + if (indexBase <= JSOP_INDEXBASE3 - JSOP_INDEXBASE1 + 1) { + if (js_Emit1(cx, cg, (JSOp)(JSOP_INDEXBASE1 + indexBase - 1)) < 0) + return JSOP_FALSE; + return JSOP_RESETBASE0; + } + + if (index >= INDEX_LIMIT) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TOO_MANY_LITERALS); + return JSOP_FALSE; + } + + if (js_Emit2(cx, cg, JSOP_INDEXBASE, (JSOp)indexBase) < 0) + return JSOP_FALSE; + return JSOP_RESETBASE; +} + +/* + * Emit a bytecode and its 2-byte constant index immediate operand. If the + * index requires more than 2 bytes, emit a prefix op whose 8-bit immediate + * operand effectively extends the 16-bit immediate of the prefixed opcode, + * by changing index "segment" (see jsinterp.c). We optimize segments 1-3 + * with single-byte JSOP_INDEXBASE[123] codes. + * + * Such prefixing currently requires a suffix to restore the "zero segment" + * register setting, but this could be optimized further. + */ +static JSBool +EmitIndexOp(JSContext *cx, JSOp op, uintN index, JSCodeGenerator *cg) +{ + JSOp bigSuffix; + + bigSuffix = EmitBigIndexPrefix(cx, cg, index); + if (bigSuffix == JSOP_FALSE) + return JS_FALSE; + EMIT_UINT16_IMM_OP(op, index); + return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0; +} + +/* + * Slight sugar for EmitIndexOp, again accessing cx and cg from the macro + * caller's lexical environment, and embedding a false return on error. + */ +#define EMIT_INDEX_OP(op, index) \ + JS_BEGIN_MACRO \ + if (!EmitIndexOp(cx, op, index, cg)) \ + return JS_FALSE; \ + JS_END_MACRO + +static JSBool +EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) +{ + JSAtomListElement *ale; + + JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM); + if (op == JSOP_GETPROP && + pn->pn_atom == cx->runtime->atomState.lengthAtom) { + return js_Emit1(cx, cg, JSOP_LENGTH) >= 0; + } + ale = cg->atomList.add(cg->parser, pn->pn_atom); + if (!ale) + return JS_FALSE; + return EmitIndexOp(cx, op, ALE_INDEX(ale), cg); +} + +static JSBool +EmitObjectOp(JSContext *cx, JSObjectBox *objbox, JSOp op, + JSCodeGenerator *cg) +{ + JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT); + return EmitIndexOp(cx, op, cg->objectList.index(objbox), cg); +} + +/* + * What good are ARGNO_LEN and SLOTNO_LEN, you ask? The answer is that, apart + * from EmitSlotIndexOp, they abstract out the detail that both are 2, and in + * other parts of the code there's no necessary relationship between the two. + * The abstraction cracks here in order to share EmitSlotIndexOp code among + * the JSOP_DEFLOCALFUN and JSOP_GET{ARG,VAR,LOCAL}PROP cases. + */ +JS_STATIC_ASSERT(ARGNO_LEN == 2); +JS_STATIC_ASSERT(SLOTNO_LEN == 2); + +static JSBool +EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index, + JSCodeGenerator *cg) +{ + JSOp bigSuffix; + ptrdiff_t off; + jsbytecode *pc; + + JS_ASSERT(JOF_OPTYPE(op) == JOF_SLOTATOM || + JOF_OPTYPE(op) == JOF_SLOTOBJECT); + bigSuffix = EmitBigIndexPrefix(cx, cg, index); + if (bigSuffix == JSOP_FALSE) + return JS_FALSE; + + /* Emit [op, slot, index]. */ + off = js_EmitN(cx, cg, op, 2 + INDEX_LEN); + if (off < 0) + return JS_FALSE; + pc = CG_CODE(cg, off); + SET_UINT16(pc, slot); + pc += 2; + SET_INDEX(pc, index); + return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0; +} + +bool +JSCodeGenerator::shouldNoteClosedName(JSParseNode *pn) +{ + return !callsEval() && pn->pn_defn && pn->isClosed(); +} + +/* + * Adjust the slot for a block local to account for the number of variables + * that share the same index space with locals. Due to the incremental code + * generation for top-level script, we do the adjustment via code patching in + * Compiler::compileScript; see comments there. + * + * The function returns -1 on failures. + */ +static jsint +AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot) +{ + JS_ASSERT((jsuint) slot < cg->maxStackDepth); + if (cg->inFunction()) { + slot += cg->bindings.countVars(); + if ((uintN) slot >= SLOTNO_LIMIT) { + ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS); + slot = -1; + } + } + return slot; +} + +static bool +EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg) +{ + JS_ASSERT(PN_TYPE(pn) == TOK_LEXICALSCOPE); + if (!EmitObjectOp(cx, pn->pn_objbox, JSOP_ENTERBLOCK, cg)) + return false; + + JSObject *blockObj = pn->pn_objbox->object; + jsint depth = AdjustBlockSlot(cx, cg, OBJ_BLOCK_DEPTH(cx, blockObj)); + if (depth < 0) + return false; + + uintN base = JSSLOT_FREE(&js_BlockClass); + for (uintN slot = base, limit = base + OBJ_BLOCK_COUNT(cx, blockObj); slot < limit; slot++) { + const Value &v = blockObj->getSlot(slot); + + /* Beware the empty destructuring dummy. */ + if (v.isUndefined()) { + JS_ASSERT(slot + 1 <= limit); + continue; + } + + JSDefinition *dn = (JSDefinition *) v.toPrivate(); + JS_ASSERT(dn->pn_defn); + JS_ASSERT(uintN(dn->frameSlot() + depth) < JS_BIT(16)); + dn->pn_cookie.set(dn->pn_cookie.level(), uint16(dn->frameSlot() + depth)); +#ifdef DEBUG + for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { + JS_ASSERT(pnu->pn_lexdef == dn); + JS_ASSERT(!(pnu->pn_dflags & PND_BOUND)); + JS_ASSERT(pnu->pn_cookie.isFree()); + } +#endif + + /* + * If this variable is closed over, and |eval| is not present, then + * then set a bit in dslots so the Method JIT can deoptimize this + * slot. + */ + bool isClosed = cg->shouldNoteClosedName(dn); + blockObj->setSlot(slot, BooleanValue(isClosed)); + } + + return true; +} + +static JSBool +EmitLeaveBlock(JSContext *cx, JSCodeGenerator *cg, JSOp op, + JSObjectBox *box) +{ + JSOp bigSuffix; + uintN count = OBJ_BLOCK_COUNT(cx, box->object); + + bigSuffix = EmitBigIndexPrefix(cx, cg, box->index); + if (bigSuffix == JSOP_FALSE) + return JS_FALSE; + if (js_Emit5(cx, cg, op, count, box->index) < 0) + return JS_FALSE; + return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0; +} + +/* + * Try to convert a *NAME op to a *GNAME op, which optimizes access to + * undeclared globals. Return true if a conversion was made. + * + * This conversion is not made if we are in strict mode. In eval code nested + * within (strict mode) eval code, access to an undeclared "global" might + * merely be to a binding local to that outer eval: + * + * "use strict"; + * var x = "global"; + * eval('var x = "eval"; eval("x");'); // 'eval', not 'global' + * + * Outside eval code, access to an undeclared global is a strict mode error: + * + * "use strict"; + * function foo() + * { + * undeclared = 17; // throws ReferenceError + * } + * foo(); + */ +static bool +TryConvertToGname(JSCodeGenerator *cg, JSParseNode *pn, JSOp *op) +{ + if (cg->compileAndGo() && + cg->compiler()->globalScope->globalObj && + !cg->mightAliasLocals() && + !pn->isDeoptimized() && + !(cg->flags & TCF_STRICT_MODE_CODE)) { + switch (*op) { + case JSOP_NAME: *op = JSOP_GETGNAME; break; + case JSOP_SETNAME: *op = JSOP_SETGNAME; break; + case JSOP_INCNAME: *op = JSOP_INCGNAME; break; + case JSOP_NAMEINC: *op = JSOP_GNAMEINC; break; + case JSOP_DECNAME: *op = JSOP_DECGNAME; break; + case JSOP_NAMEDEC: *op = JSOP_GNAMEDEC; break; + case JSOP_FORNAME: *op = JSOP_FORGNAME; break; + case JSOP_SETCONST: + case JSOP_DELNAME: + /* Not supported. */ + return false; + default: JS_NOT_REACHED("gname"); + } + return true; + } + return false; +} + +// Binds a global, given a |dn| that is known to have the PND_GVAR bit, and a pn +// that is |dn| or whose definition is |dn|. |pn->pn_cookie| is an outparam +// that will be free (meaning no binding), or a slot number. +static bool +BindKnownGlobal(JSContext *cx, JSCodeGenerator *cg, JSParseNode *dn, JSParseNode *pn, JSAtom *atom) +{ + // Cookie is an outparam; make sure caller knew to clear it. + JS_ASSERT(pn->pn_cookie.isFree()); + + if (cg->mightAliasLocals()) + return true; + + GlobalScope *globalScope = cg->compiler()->globalScope; + + uint32 index; + if (dn->pn_cookie.isFree()) { + // The definition wasn't bound, so find its atom's index in the + // mapping of defined globals. + JSAtomListElement *ale = globalScope->names.lookup(atom); + index = ALE_INDEX(ale); + } else { + JSCodeGenerator *globalcg = globalScope->cg; + + // If the definition is bound, and we're in the same cg, we can re-use + // its cookie. + if (globalcg == cg) { + pn->pn_cookie = dn->pn_cookie; + pn->pn_dflags |= PND_BOUND; + return true; + } + + // Otherwise, find the atom's index by using the originating cg's + // global use table. + index = globalcg->globalUses[dn->pn_cookie.asInteger()].slot; + } + + if (!cg->addGlobalUse(atom, index, &pn->pn_cookie)) + return false; + + if (!pn->pn_cookie.isFree()) + pn->pn_dflags |= PND_BOUND; + + return true; +} + +// See BindKnownGlobal()'s comment. +static bool +BindGlobal(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, JSAtom *atom) +{ + pn->pn_cookie.makeFree(); + + JSDefinition *dn; + if (pn->pn_used) { + dn = pn->pn_lexdef; + } else { + if (!pn->pn_defn) + return true; + dn = (JSDefinition *)pn; + } + + // Only optimize for defined globals. + if (!dn->isGlobal()) + return true; + + return BindKnownGlobal(cx, cg, dn, pn, atom); +} + +/* + * BindNameToSlot attempts to optimize name gets and sets to stack slot loads + * and stores, given the compile-time information in cg and a TOK_NAME node pn. + * It returns false on error, true on success. + * + * The caller can inspect pn->pn_cookie for FREE_UPVAR_COOKIE to tell whether + * optimization occurred, in which case BindNameToSlot also updated pn->pn_op. + * If pn->pn_cookie is still FREE_UPVAR_COOKIE on return, pn->pn_op still may + * have been optimized, e.g., from JSOP_NAME to JSOP_CALLEE. Whether or not + * pn->pn_op was modified, if this function finds an argument or local variable + * name, PND_CONST will be set in pn_dflags for read-only properties after a + * successful return. + * + * NB: if you add more opcodes specialized from JSOP_NAME, etc., don't forget + * to update the TOK_FOR (for-in) and TOK_ASSIGN (op=, e.g. +=) special cases + * in js_EmitTree. + */ +static JSBool +BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +{ + JSDefinition *dn; + JSOp op; + JSAtom *atom; + JSDefinition::Kind dn_kind; + JSAtomListElement *ale; + uintN index; + + JS_ASSERT(pn->pn_type == TOK_NAME); + + /* Idempotency tests come first, since we may be called more than once. */ + if (pn->pn_dflags & PND_BOUND) + return JS_TRUE; + + /* No cookie initialized for these two, they're pre-bound by definition. */ + JS_ASSERT(pn->pn_op != JSOP_ARGUMENTS && pn->pn_op != JSOP_CALLEE); + + /* + * The parser linked all uses (including forward references) to their + * definitions, unless a with statement or direct eval intervened. + */ + if (pn->pn_used) { + JS_ASSERT(pn->pn_cookie.isFree()); + dn = pn->pn_lexdef; + JS_ASSERT(dn->pn_defn); + if (pn->isDeoptimized()) + return JS_TRUE; + pn->pn_dflags |= (dn->pn_dflags & PND_CONST); + } else { + if (!pn->pn_defn) + return JS_TRUE; + dn = (JSDefinition *) pn; + } + + op = PN_OP(pn); + if (op == JSOP_NOP) + return JS_TRUE; + + JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM); + atom = pn->pn_atom; + UpvarCookie cookie = dn->pn_cookie; + dn_kind = dn->kind(); + + /* + * Turn attempts to mutate const-declared bindings into get ops (for + * pre-increment and pre-decrement ops, our caller will have to emit + * JSOP_POS, JSOP_ONE, and JSOP_ADD as well). + * + * Turn JSOP_DELNAME into JSOP_FALSE if dn is known, as all declared + * bindings visible to the compiler are permanent in JS unless the + * declaration originates at top level in eval code. + */ + switch (op) { + case JSOP_NAME: + case JSOP_SETCONST: + break; + case JSOP_DELNAME: + if (dn_kind != JSDefinition::UNKNOWN) { + if (cg->parser->callerFrame && dn->isTopLevel()) + JS_ASSERT(cg->compileAndGo()); + else + pn->pn_op = JSOP_FALSE; + pn->pn_dflags |= PND_BOUND; + return JS_TRUE; + } + break; + default: + if (pn->isConst()) + pn->pn_op = op = JSOP_NAME; + } + + if (dn->isGlobal()) { + if (op == JSOP_NAME) { + /* + * If the definition is a defined global, not potentially aliased + * by a local variable, and not mutating the variable, try and + * optimize to a fast, unguarded global access. + */ + if (!BindKnownGlobal(cx, cg, dn, pn, atom)) + return JS_FALSE; + if (!pn->pn_cookie.isFree()) { + pn->pn_op = JSOP_GETGLOBAL; + return JS_TRUE; + } + } + + /* + * The locally stored cookie here should really come from |pn|, not + * |dn|. For example, we could have a SETGNAME op's lexdef be a + * GETGLOBAL op, and their cookies have very different meanings. As + * a workaround, just make the cookie free. + */ + cookie.makeFree(); + } + + if (cookie.isFree()) { + JSStackFrame *caller = cg->parser->callerFrame; + if (caller) { + JS_ASSERT(cg->compileAndGo()); + + /* + * Don't generate upvars on the left side of a for loop. See + * bug 470758. + */ + if (cg->flags & TCF_IN_FOR_INIT) + return JS_TRUE; + + JS_ASSERT(caller->isScriptFrame()); + + /* + * If this is an eval in the global scope, then unbound variables + * must be globals, so try to use GNAME ops. + */ + if (caller->isGlobalFrame() && TryConvertToGname(cg, pn, &op)) { + ale = cg->atomList.add(cg->parser, atom); + if (!ale) + return JS_FALSE; + + pn->pn_op = op; + pn->pn_dflags |= PND_BOUND; + return JS_TRUE; + } + + /* + * Out of tricks, so we must rely on PICs to optimize named + * accesses from direct eval called from function code. + */ + return JS_TRUE; + } + + /* Optimize accesses to undeclared globals. */ + if (!cg->mightAliasLocals() && !TryConvertToGname(cg, pn, &op)) + return JS_TRUE; + + ale = cg->atomList.add(cg->parser, atom); + if (!ale) + return JS_FALSE; + + pn->pn_op = op; + pn->pn_dflags |= PND_BOUND; + + return JS_TRUE; + } + + uint16 level = cookie.level(); + JS_ASSERT(cg->staticLevel >= level); + + const uintN skip = cg->staticLevel - level; + if (skip != 0) { + JS_ASSERT(cg->inFunction()); + JS_ASSERT_IF(cookie.slot() != UpvarCookie::CALLEE_SLOT, cg->lexdeps.lookup(atom)); + JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM); + JS_ASSERT(cg->fun()->u.i.skipmin <= skip); + + /* + * If op is a mutating opcode, this upvar's lookup skips too many levels, + * or the function is heavyweight, we fall back on JSOP_*NAME*. + */ + if (op != JSOP_NAME) + return JS_TRUE; + if (level >= UpvarCookie::UPVAR_LEVEL_LIMIT) + return JS_TRUE; + if (cg->flags & TCF_FUN_HEAVYWEIGHT) + return JS_TRUE; + + if (!cg->fun()->isFlatClosure()) + return JS_TRUE; + + ale = cg->upvarList.lookup(atom); + if (ale) { + index = ALE_INDEX(ale); + } else { + if (!cg->bindings.addUpvar(cx, atom)) + return JS_FALSE; + + ale = cg->upvarList.add(cg->parser, atom); + if (!ale) + return JS_FALSE; + index = ALE_INDEX(ale); + JS_ASSERT(index == cg->upvarList.count - 1); + + UpvarCookie *vector = cg->upvarMap.vector; + uint32 length = cg->lexdeps.count; + if (!vector || cg->upvarMap.length != length) { + vector = (UpvarCookie *) js_realloc(vector, length * sizeof *vector); + if (!vector) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + cg->upvarMap.vector = vector; + cg->upvarMap.length = length; + } + + uintN slot = cookie.slot(); + if (slot != UpvarCookie::CALLEE_SLOT && dn_kind != JSDefinition::ARG) { + JSTreeContext *tc = cg; + do { + tc = tc->parent; + } while (tc->staticLevel != level); + if (tc->inFunction()) + slot += tc->fun()->nargs; + } + + JS_ASSERT(index < cg->upvarMap.length); + vector[index].set(skip, slot); + } + + pn->pn_op = JSOP_GETFCSLOT; + JS_ASSERT((index & JS_BITMASK(16)) == index); + pn->pn_cookie.set(0, index); + pn->pn_dflags |= PND_BOUND; + return JS_TRUE; + } + + /* + * We are compiling a function body and may be able to optimize name + * to stack slot. Look for an argument or variable in the function and + * rewrite pn_op and update pn accordingly. + */ + switch (dn_kind) { + case JSDefinition::UNKNOWN: + return JS_TRUE; + + case JSDefinition::LET: + switch (op) { + case JSOP_NAME: op = JSOP_GETLOCAL; break; + case JSOP_SETNAME: op = JSOP_SETLOCAL; break; + case JSOP_INCNAME: op = JSOP_INCLOCAL; break; + case JSOP_NAMEINC: op = JSOP_LOCALINC; break; + case JSOP_DECNAME: op = JSOP_DECLOCAL; break; + case JSOP_NAMEDEC: op = JSOP_LOCALDEC; break; + case JSOP_FORNAME: op = JSOP_FORLOCAL; break; + default: JS_NOT_REACHED("let"); + } + break; + + case JSDefinition::ARG: + switch (op) { + case JSOP_NAME: op = JSOP_GETARG; break; + case JSOP_SETNAME: op = JSOP_SETARG; break; + case JSOP_INCNAME: op = JSOP_INCARG; break; + case JSOP_NAMEINC: op = JSOP_ARGINC; break; + case JSOP_DECNAME: op = JSOP_DECARG; break; + case JSOP_NAMEDEC: op = JSOP_ARGDEC; break; + case JSOP_FORNAME: op = JSOP_FORARG; break; + default: JS_NOT_REACHED("arg"); + } + JS_ASSERT(!pn->isConst()); + break; + + case JSDefinition::VAR: + if (PN_OP(dn) == JSOP_CALLEE) { + JS_ASSERT(op != JSOP_CALLEE); + JS_ASSERT((cg->fun()->flags & JSFUN_LAMBDA) && atom == cg->fun()->atom); + + /* + * Leave pn->pn_op == JSOP_NAME if cg->fun is heavyweight to + * address two cases: a new binding introduced by eval, and + * assignment to the name in strict mode. + * + * var fun = (function f(s) { eval(s); return f; }); + * assertEq(fun("var f = 42"), 42); + * + * ECMAScript specifies that a function expression's name is bound + * in a lexical environment distinct from that used to bind its + * named parameters, the arguments object, and its variables. The + * new binding for "var f = 42" shadows the binding for the + * function itself, so the name of the function will not refer to + * the function. + * + * (function f() { "use strict"; f = 12; })(); + * + * Outside strict mode, assignment to a function expression's name + * has no effect. But in strict mode, this attempt to mutate an + * immutable binding must throw a TypeError. We implement this by + * not optimizing such assignments and by marking such functions as + * heavyweight, ensuring that the function name is represented in + * the scope chain so that assignment will throw a TypeError. + */ + JS_ASSERT(op != JSOP_DELNAME); + if (!(cg->flags & TCF_FUN_HEAVYWEIGHT)) { + op = JSOP_CALLEE; + pn->pn_dflags |= PND_CONST; + } + + pn->pn_op = op; + pn->pn_dflags |= PND_BOUND; + return JS_TRUE; + } + /* FALL THROUGH */ + + default: + JS_ASSERT_IF(dn_kind != JSDefinition::FUNCTION, + dn_kind == JSDefinition::VAR || + dn_kind == JSDefinition::CONST); + switch (op) { + case JSOP_NAME: op = JSOP_GETLOCAL; break; + case JSOP_SETNAME: op = JSOP_SETLOCAL; break; + case JSOP_SETCONST: op = JSOP_SETLOCAL; break; + case JSOP_INCNAME: op = JSOP_INCLOCAL; break; + case JSOP_NAMEINC: op = JSOP_LOCALINC; break; + case JSOP_DECNAME: op = JSOP_DECLOCAL; break; + case JSOP_NAMEDEC: op = JSOP_LOCALDEC; break; + case JSOP_FORNAME: op = JSOP_FORLOCAL; break; + default: JS_NOT_REACHED("local"); + } + JS_ASSERT_IF(dn_kind == JSDefinition::CONST, pn->pn_dflags & PND_CONST); + break; + } + + JS_ASSERT(op != PN_OP(pn)); + pn->pn_op = op; + pn->pn_cookie.set(0, cookie.slot()); + pn->pn_dflags |= PND_BOUND; + return JS_TRUE; +} + +bool +JSCodeGenerator::addGlobalUse(JSAtom *atom, uint32 slot, UpvarCookie *cookie) +{ + JSAtomListElement *ale = globalMap.lookup(atom); + if (ale) { + cookie->set(0, uint16(ALE_INDEX(ale))); + return true; + } + + /* Don't bother encoding indexes >= uint16 */ + if (globalUses.length() >= UINT16_LIMIT) { + cookie->makeFree(); + return true; + } + + /* Find or add an existing atom table entry. */ + ale = atomList.add(parser, atom); + if (!ale) + return false; + + cookie->set(0, globalUses.length()); + + GlobalSlotArray::Entry entry = { ALE_INDEX(ale), slot }; + if (!globalUses.append(entry)) + return false; + + ale = globalMap.add(parser, atom); + if (!ale) + return false; + + ALE_SET_INDEX(ale, cookie->asInteger()); + return true; +} + +/* + * If pn contains a useful expression, return true with *answer set to true. + * If pn contains a useless expression, return true with *answer set to false. + * Return false on error. + * + * The caller should initialize *answer to false and invoke this function on + * an expression statement or similar subtree to decide whether the tree could + * produce code that has any side effects. For an expression statement, we + * define useless code as code with no side effects, because the main effect, + * the value left on the stack after the code executes, will be discarded by a + * pop bytecode. + */ +static JSBool +CheckSideEffects(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, + JSBool *answer) +{ + JSBool ok; + JSParseNode *pn2; + + ok = JS_TRUE; + if (!pn || *answer) + return ok; + + switch (pn->pn_arity) { + case PN_FUNC: + /* + * A named function, contrary to ES3, is no longer useful, because we + * bind its name lexically (using JSOP_CALLEE) instead of creating an + * Object instance and binding a readonly, permanent property in it + * (the object and binding can be detected and hijacked or captured). + * This is a bug fix to ES3; it is fixed in ES3.1 drafts. + */ + *answer = JS_FALSE; + break; + + case PN_LIST: + if (pn->pn_op == JSOP_NOP || + pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND || + pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) { + /* + * Non-operators along with ||, &&, ===, and !== never invoke + * toString or valueOf. + */ + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) + ok &= CheckSideEffects(cx, cg, pn2, answer); + } else { + /* + * All invocation operations (construct: TOK_NEW, call: TOK_LP) + * are presumed to be useful, because they may have side effects + * even if their main effect (their return value) is discarded. + * + * TOK_LB binary trees of 3 or more nodes are flattened into lists + * to avoid too much recursion. All such lists must be presumed + * to be useful because each index operation could invoke a getter + * (the JSOP_ARGUMENTS special case below, in the PN_BINARY case, + * does not apply here: arguments[i][j] might invoke a getter). + * + * Likewise, array and object initialisers may call prototype + * setters (the __defineSetter__ built-in, and writable __proto__ + * on Array.prototype create this hazard). Initialiser list nodes + * have JSOP_NEWINIT in their pn_op. + */ + *answer = JS_TRUE; + } + break; + + case PN_TERNARY: + ok = CheckSideEffects(cx, cg, pn->pn_kid1, answer) && + CheckSideEffects(cx, cg, pn->pn_kid2, answer) && + CheckSideEffects(cx, cg, pn->pn_kid3, answer); + break; + + case PN_BINARY: + if (pn->pn_type == TOK_ASSIGN) { + /* + * Assignment is presumed to be useful, even if the next operation + * is another assignment overwriting this one's ostensible effect, + * because the left operand may be a property with a setter that + * has side effects. + * + * The only exception is assignment of a useless value to a const + * declared in the function currently being compiled. + */ + pn2 = pn->pn_left; + if (pn2->pn_type != TOK_NAME) { + *answer = JS_TRUE; + } else { + if (!BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + if (!CheckSideEffects(cx, cg, pn->pn_right, answer)) + return JS_FALSE; + if (!*answer && (pn->pn_op != JSOP_NOP || !pn2->isConst())) + *answer = JS_TRUE; + } + } else { + if (pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND || + pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) { + /* + * ||, &&, ===, and !== do not convert their operands via + * toString or valueOf method calls. + */ + ok = CheckSideEffects(cx, cg, pn->pn_left, answer) && + CheckSideEffects(cx, cg, pn->pn_right, answer); + } else { + /* + * We can't easily prove that neither operand ever denotes an + * object with a toString or valueOf method. + */ + *answer = JS_TRUE; + } + } + break; + + case PN_UNARY: + switch (pn->pn_type) { + case TOK_DELETE: + pn2 = pn->pn_kid; + switch (pn2->pn_type) { + case TOK_NAME: + if (!BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + if (pn2->isConst()) { + *answer = JS_FALSE; + break; + } + /* FALL THROUGH */ + case TOK_DOT: +#if JS_HAS_XML_SUPPORT + case TOK_DBLDOT: +#endif + case TOK_LP: + case TOK_LB: + /* All these delete addressing modes have effects too. */ + *answer = JS_TRUE; + break; + default: + ok = CheckSideEffects(cx, cg, pn2, answer); + break; + } + break; + + case TOK_UNARYOP: + if (pn->pn_op == JSOP_NOT) { + /* ! does not convert its operand via toString or valueOf. */ + ok = CheckSideEffects(cx, cg, pn->pn_kid, answer); + break; + } + /* FALL THROUGH */ + + default: + /* + * All of TOK_INC, TOK_DEC, TOK_THROW, TOK_YIELD, and TOK_DEFSHARP + * have direct effects. Of the remaining unary-arity node types, + * we can't easily prove that the operand never denotes an object + * with a toString or valueOf method. + */ + *answer = JS_TRUE; + break; + } + break; + + case PN_NAME: + /* + * Take care to avoid trying to bind a label name (labels, both for + * statements and property values in object initialisers, have pn_op + * defaulted to JSOP_NOP). + */ + if (pn->pn_type == TOK_NAME && pn->pn_op != JSOP_NOP) { + if (!BindNameToSlot(cx, cg, pn)) + return JS_FALSE; + if (pn->pn_op != JSOP_ARGUMENTS && pn->pn_op != JSOP_CALLEE && + pn->pn_cookie.isFree()) { + /* + * Not an argument or local variable use, and not a use of a + * unshadowed named function expression's given name, so this + * expression could invoke a getter that has side effects. + */ + *answer = JS_TRUE; + } + } + pn2 = pn->maybeExpr(); + if (pn->pn_type == TOK_DOT) { + if (pn2->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + if (!(pn2->pn_op == JSOP_ARGUMENTS && + pn->pn_atom == cx->runtime->atomState.lengthAtom)) { + /* + * Any dotted property reference could call a getter, except + * for arguments.length where arguments is unambiguous. + */ + *answer = JS_TRUE; + } + } + ok = CheckSideEffects(cx, cg, pn2, answer); + break; + + case PN_NAMESET: + ok = CheckSideEffects(cx, cg, pn->pn_tree, answer); + break; + + case PN_NULLARY: + if (pn->pn_type == TOK_DEBUGGER) + *answer = JS_TRUE; + break; + } + return ok; +} + +static JSBool +EmitNameOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, + JSBool callContext) +{ + JSOp op; + + if (!BindNameToSlot(cx, cg, pn)) + return JS_FALSE; + op = PN_OP(pn); + + if (callContext) { + switch (op) { + case JSOP_NAME: + op = JSOP_CALLNAME; + break; + case JSOP_GETGNAME: + op = JSOP_CALLGNAME; + break; + case JSOP_GETGLOBAL: + op = JSOP_CALLGLOBAL; + break; + case JSOP_GETARG: + op = JSOP_CALLARG; + break; + case JSOP_GETLOCAL: + op = JSOP_CALLLOCAL; + break; + case JSOP_GETFCSLOT: + op = JSOP_CALLFCSLOT; + break; + default: + JS_ASSERT(op == JSOP_ARGUMENTS || op == JSOP_CALLEE); + break; + } + } + + if (op == JSOP_ARGUMENTS || op == JSOP_CALLEE) { + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + if (callContext && js_Emit1(cx, cg, JSOP_PUSH) < 0) + return JS_FALSE; + } else { + if (!pn->pn_cookie.isFree()) { + EMIT_UINT16_IMM_OP(op, pn->pn_cookie.asInteger()); + } else { + if (!EmitAtomOp(cx, pn, op, cg)) + return JS_FALSE; + } + } + + return JS_TRUE; +} + +#if JS_HAS_XML_SUPPORT +static JSBool +EmitXMLName(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) +{ + JSParseNode *pn2; + uintN oldflags; + + JS_ASSERT(pn->pn_type == TOK_UNARYOP); + JS_ASSERT(pn->pn_op == JSOP_XMLNAME); + JS_ASSERT(op == JSOP_XMLNAME || op == JSOP_CALLXMLNAME); + + pn2 = pn->pn_kid; + oldflags = cg->flags; + cg->flags &= ~TCF_IN_FOR_INIT; + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + cg->flags |= oldflags & TCF_IN_FOR_INIT; + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, + CG_OFFSET(cg) - pn2->pn_offset) < 0) { + return JS_FALSE; + } + + return js_Emit1(cx, cg, op) >= 0; +} +#endif + +static JSBool +EmitSpecialPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) +{ + /* + * Special case for obj.__proto__ to deoptimize away from fast paths in the + * interpreter and trace recorder, which skip dense array instances by + * going up to Array.prototype before looking up the property name. + */ + JSAtomListElement *ale = cg->atomList.add(cg->parser, pn->pn_atom); + if (!ale) + return JS_FALSE; + if (!EmitIndexOp(cx, JSOP_QNAMEPART, ALE_INDEX(ale), cg)) + return JS_FALSE; + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + return JS_TRUE; +} + +static JSBool +EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg, + JSBool callContext) +{ + JSParseNode *pn2, *pndot, *pnup, *pndown; + ptrdiff_t top; + + JS_ASSERT(pn->pn_arity == PN_NAME); + pn2 = pn->maybeExpr(); + + /* Special case deoptimization for __proto__. */ + if ((op == JSOP_GETPROP || op == JSOP_CALLPROP) && + pn->pn_atom == cx->runtime->atomState.protoAtom) { + if (pn2 && !js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + return EmitSpecialPropOp(cx, pn, callContext ? JSOP_CALLELEM : JSOP_GETELEM, cg); + } + + if (callContext) { + JS_ASSERT(pn->pn_type == TOK_DOT); + JS_ASSERT(op == JSOP_GETPROP); + op = JSOP_CALLPROP; + } else if (op == JSOP_GETPROP && pn->pn_type == TOK_DOT) { + if (pn2->pn_op == JSOP_THIS) { + if (pn->pn_atom != cx->runtime->atomState.lengthAtom) { + /* Fast path for gets of |this.foo|. */ + return EmitAtomOp(cx, pn, JSOP_GETTHISPROP, cg); + } + } else if (pn2->pn_type == TOK_NAME) { + /* + * Try to optimize: + * - arguments.length into JSOP_ARGCNT + * - argname.prop into JSOP_GETARGPROP + * - localname.prop into JSOP_GETLOCALPROP + * but don't do this if the property is 'length' -- prefer to emit + * JSOP_GETARG, etc., and then JSOP_LENGTH. + */ + if (!BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + if (pn->pn_atom == cx->runtime->atomState.lengthAtom) { + if (pn2->pn_op == JSOP_ARGUMENTS) + return js_Emit1(cx, cg, JSOP_ARGCNT) >= 0; + } else { + switch (pn2->pn_op) { + case JSOP_GETARG: + op = JSOP_GETARGPROP; + goto do_indexconst; + case JSOP_GETLOCAL: + op = JSOP_GETLOCALPROP; + do_indexconst: { + JSAtomListElement *ale; + jsatomid atomIndex; + + ale = cg->atomList.add(cg->parser, pn->pn_atom); + if (!ale) + return JS_FALSE; + atomIndex = ALE_INDEX(ale); + return EmitSlotIndexOp(cx, op, pn2->pn_cookie.asInteger(), atomIndex, cg); + } + + default:; + } + } + } + } + + /* + * If the object operand is also a dotted property reference, reverse the + * list linked via pn_expr temporarily so we can iterate over it from the + * bottom up (reversing again as we go), to avoid excessive recursion. + */ + if (pn2->pn_type == TOK_DOT) { + pndot = pn2; + pnup = NULL; + top = CG_OFFSET(cg); + for (;;) { + /* Reverse pndot->pn_expr to point up, not down. */ + pndot->pn_offset = top; + JS_ASSERT(!pndot->pn_used); + pndown = pndot->pn_expr; + pndot->pn_expr = pnup; + if (pndown->pn_type != TOK_DOT) + break; + pnup = pndot; + pndot = pndown; + } + + /* pndown is a primary expression, not a dotted property reference. */ + if (!js_EmitTree(cx, cg, pndown)) + return JS_FALSE; + + do { + /* Walk back up the list, emitting annotated name ops. */ + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, + CG_OFFSET(cg) - pndown->pn_offset) < 0) { + return JS_FALSE; + } + + /* Special case deoptimization on __proto__, as above. */ + if (pndot->pn_arity == PN_NAME && pndot->pn_atom == cx->runtime->atomState.protoAtom) { + if (!EmitSpecialPropOp(cx, pndot, JSOP_GETELEM, cg)) + return JS_FALSE; + } else if (!EmitAtomOp(cx, pndot, PN_OP(pndot), cg)) { + return JS_FALSE; + } + + /* Reverse the pn_expr link again. */ + pnup = pndot->pn_expr; + pndot->pn_expr = pndown; + pndown = pndot; + } while ((pndot = pnup) != NULL); + } else { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + } + + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, + CG_OFFSET(cg) - pn2->pn_offset) < 0) { + return JS_FALSE; + } + + return EmitAtomOp(cx, pn, op, cg); +} + +static JSBool +EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) +{ + ptrdiff_t top; + JSParseNode *left, *right, *next, ltmp, rtmp; + int32_t slot; + + top = CG_OFFSET(cg); + if (pn->pn_arity == PN_LIST) { + /* Left-associative operator chain to avoid too much recursion. */ + JS_ASSERT(pn->pn_op == JSOP_GETELEM); + JS_ASSERT(pn->pn_count >= 3); + left = pn->pn_head; + right = pn->last(); + next = left->pn_next; + JS_ASSERT(next != right); + + /* + * Try to optimize arguments[0][j]... into JSOP_ARGSUB<0> followed by + * one or more index expression and JSOP_GETELEM op pairs. + */ + if (left->pn_type == TOK_NAME && next->pn_type == TOK_NUMBER) { + if (!BindNameToSlot(cx, cg, left)) + return JS_FALSE; + if (left->pn_op == JSOP_ARGUMENTS && + JSDOUBLE_IS_INT32(next->pn_dval, &slot) && + jsuint(slot) < JS_BIT(16) && + (!cg->inStrictMode() || + (!cg->mutatesParameter() && !cg->callsEval()))) { + /* + * arguments[i]() requires arguments object as "this". + * Check that we never generates list for that usage. + */ + JS_ASSERT(op != JSOP_CALLELEM || next->pn_next); + left->pn_offset = next->pn_offset = top; + EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot); + left = next; + next = left->pn_next; + } + } + + /* + * Check whether we generated JSOP_ARGSUB, just above, and have only + * one more index expression to emit. Given arguments[0][j], we must + * skip the while loop altogether, falling through to emit code for j + * (in the subtree referenced by right), followed by the annotated op, + * at the bottom of this function. + */ + JS_ASSERT(next != right || pn->pn_count == 3); + if (left == pn->pn_head) { + if (!js_EmitTree(cx, cg, left)) + return JS_FALSE; + } + while (next != right) { + if (!js_EmitTree(cx, cg, next)) + return JS_FALSE; + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_GETELEM) < 0) + return JS_FALSE; + next = next->pn_next; + } + } else { + if (pn->pn_arity == PN_NAME) { + /* + * Set left and right so pn appears to be a TOK_LB node, instead + * of a TOK_DOT node. See the TOK_FOR/IN case in js_EmitTree, and + * EmitDestructuringOps nearer below. In the destructuring case, + * the base expression (pn_expr) of the name may be null, which + * means we have to emit a JSOP_BINDNAME. + */ + left = pn->maybeExpr(); + if (!left) { + left = <mp; + left->pn_type = TOK_STRING; + left->pn_op = JSOP_BINDNAME; + left->pn_arity = PN_NULLARY; + left->pn_pos = pn->pn_pos; + left->pn_atom = pn->pn_atom; + } + right = &rtmp; + right->pn_type = TOK_STRING; + right->pn_op = js_IsIdentifier(ATOM_TO_STRING(pn->pn_atom)) + ? JSOP_QNAMEPART + : JSOP_STRING; + right->pn_arity = PN_NULLARY; + right->pn_pos = pn->pn_pos; + right->pn_atom = pn->pn_atom; + } else { + JS_ASSERT(pn->pn_arity == PN_BINARY); + left = pn->pn_left; + right = pn->pn_right; + } + + /* Try to optimize arguments[0] (e.g.) into JSOP_ARGSUB<0>. */ + if (op == JSOP_GETELEM && + left->pn_type == TOK_NAME && + right->pn_type == TOK_NUMBER) { + if (!BindNameToSlot(cx, cg, left)) + return JS_FALSE; + if (left->pn_op == JSOP_ARGUMENTS && + JSDOUBLE_IS_INT32(right->pn_dval, &slot) && + jsuint(slot) < JS_BIT(16) && + (!cg->inStrictMode() || + (!cg->mutatesParameter() && !cg->callsEval()))) { + left->pn_offset = right->pn_offset = top; + EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot); + return JS_TRUE; + } + } + + if (!js_EmitTree(cx, cg, left)) + return JS_FALSE; + } + + /* The right side of the descendant operator is implicitly quoted. */ + JS_ASSERT(op != JSOP_DESCENDANTS || right->pn_type != TOK_STRING || + right->pn_op == JSOP_QNAMEPART); + if (!js_EmitTree(cx, cg, right)) + return JS_FALSE; + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) + return JS_FALSE; + return js_Emit1(cx, cg, op) >= 0; +} + +static JSBool +EmitNumberOp(JSContext *cx, jsdouble dval, JSCodeGenerator *cg) +{ + int32_t ival; + uint32 u; + ptrdiff_t off; + jsbytecode *pc; + + if (JSDOUBLE_IS_INT32(dval, &ival)) { + if (ival == 0) + return js_Emit1(cx, cg, JSOP_ZERO) >= 0; + if (ival == 1) + return js_Emit1(cx, cg, JSOP_ONE) >= 0; + if ((jsint)(int8)ival == ival) + return js_Emit2(cx, cg, JSOP_INT8, (jsbytecode)(int8)ival) >= 0; + + u = (uint32)ival; + if (u < JS_BIT(16)) { + EMIT_UINT16_IMM_OP(JSOP_UINT16, u); + } else if (u < JS_BIT(24)) { + off = js_EmitN(cx, cg, JSOP_UINT24, 3); + if (off < 0) + return JS_FALSE; + pc = CG_CODE(cg, off); + SET_UINT24(pc, u); + } else { + off = js_EmitN(cx, cg, JSOP_INT32, 4); + if (off < 0) + return JS_FALSE; + pc = CG_CODE(cg, off); + SET_INT32(pc, ival); + } + return JS_TRUE; + } + + if (!cg->constList.append(DoubleValue(dval))) + return JS_FALSE; + + return EmitIndexOp(cx, JSOP_DOUBLE, cg->constList.length() - 1, cg); +} + +/* + * To avoid bloating all parse nodes for the special case of switch, values are + * allocated in the temp pool and pointed to by the parse node. These values + * are not currently recycled (like parse nodes) and the temp pool is only + * flushed at the end of compiling a script, so these values are technically + * leaked. This would only be a problem for scripts containing a large number + * of large switches, which seems unlikely. + */ +static Value * +AllocateSwitchConstant(JSContext *cx) +{ + Value *pv; + JS_ARENA_ALLOCATE_TYPE(pv, Value, &cx->tempPool); + return pv; +} + +static JSBool +EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, + JSStmtInfo *stmtInfo) +{ + JSOp switchOp; + JSBool ok, hasDefault, constPropagated; + ptrdiff_t top, off, defaultOffset; + JSParseNode *pn2, *pn3, *pn4; + uint32 caseCount, tableLength; + JSParseNode **table; + int32_t i, low, high; + JSAtomListElement *ale; + intN noteIndex; + size_t switchSize, tableSize; + jsbytecode *pc, *savepc; +#if JS_HAS_BLOCK_SCOPE + JSObjectBox *box; +#endif + + /* Try for most optimal, fall back if not dense ints, and per ECMAv2. */ + switchOp = JSOP_TABLESWITCH; + ok = JS_TRUE; + hasDefault = constPropagated = JS_FALSE; + defaultOffset = -1; + + /* + * If the switch contains let variables scoped by its body, model the + * resulting block on the stack first, before emitting the discriminant's + * bytecode (in case the discriminant contains a stack-model dependency + * such as a let expression). + */ + pn2 = pn->pn_right; +#if JS_HAS_BLOCK_SCOPE + if (pn2->pn_type == TOK_LEXICALSCOPE) { + /* + * Push the body's block scope before discriminant code-gen for proper + * static block scope linkage in case the discriminant contains a let + * expression. The block's locals must lie under the discriminant on + * the stack so that case-dispatch bytecodes can find the discriminant + * on top of stack. + */ + box = pn2->pn_objbox; + js_PushBlockScope(cg, stmtInfo, box, -1); + stmtInfo->type = STMT_SWITCH; + + /* Emit JSOP_ENTERBLOCK before code to evaluate the discriminant. */ + if (!EmitEnterBlock(cx, pn2, cg)) + return JS_FALSE; + + /* + * Pop the switch's statement info around discriminant code-gen. Note + * how this leaves cg->blockChain referencing the switch's + * block scope object, which is necessary for correct block parenting + * in the case where the discriminant contains a let expression. + */ + cg->topStmt = stmtInfo->down; + cg->topScopeStmt = stmtInfo->downScope; + } +#ifdef __GNUC__ + else { + box = NULL; + } +#endif +#endif + + /* + * Emit code for the discriminant first (or nearly first, in the case of a + * switch whose body is a block scope). + */ + if (!js_EmitTree(cx, cg, pn->pn_left)) + return JS_FALSE; + + /* Switch bytecodes run from here till end of final case. */ + top = CG_OFFSET(cg); +#if !JS_HAS_BLOCK_SCOPE + js_PushStatement(cg, stmtInfo, STMT_SWITCH, top); +#else + if (pn2->pn_type == TOK_LC) { + js_PushStatement(cg, stmtInfo, STMT_SWITCH, top); + } else { + /* Re-push the switch's statement info record. */ + cg->topStmt = cg->topScopeStmt = stmtInfo; + cg->blockChainBox = stmtInfo->blockBox; + + /* Set the statement info record's idea of top. */ + stmtInfo->update = top; + + /* Advance pn2 to refer to the switch case list. */ + pn2 = pn2->expr(); + } +#endif + + caseCount = pn2->pn_count; + tableLength = 0; + table = NULL; + + if (caseCount == 0 || + (caseCount == 1 && + (hasDefault = (pn2->pn_head->pn_type == TOK_DEFAULT)))) { + caseCount = 0; + low = 0; + high = -1; + } else { +#define INTMAP_LENGTH 256 + jsbitmap intmap_space[INTMAP_LENGTH]; + jsbitmap *intmap = NULL; + int32 intmap_bitlen = 0; + + low = JSVAL_INT_MAX; + high = JSVAL_INT_MIN; + + for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + if (pn3->pn_type == TOK_DEFAULT) { + hasDefault = JS_TRUE; + caseCount--; /* one of the "cases" was the default */ + continue; + } + + JS_ASSERT(pn3->pn_type == TOK_CASE); + if (switchOp == JSOP_CONDSWITCH) + continue; + + pn4 = pn3->pn_left; + while (pn4->pn_type == TOK_RP) + pn4 = pn4->pn_kid; + + Value constVal; + switch (pn4->pn_type) { + case TOK_NUMBER: + constVal.setNumber(pn4->pn_dval); + break; + case TOK_STRING: + constVal.setString(ATOM_TO_STRING(pn4->pn_atom)); + break; + case TOK_NAME: + if (!pn4->maybeExpr()) { + ok = LookupCompileTimeConstant(cx, cg, pn4->pn_atom, &constVal); + if (!ok) + goto release; + if (!constVal.isMagic(JS_NO_CONSTANT)) { + if (constVal.isObject()) { + /* + * XXX JSOP_LOOKUPSWITCH does not support const- + * propagated object values, see bug 407186. + */ + switchOp = JSOP_CONDSWITCH; + continue; + } + constPropagated = JS_TRUE; + break; + } + } + /* FALL THROUGH */ + case TOK_PRIMARY: + if (pn4->pn_op == JSOP_TRUE) { + constVal.setBoolean(true); + break; + } + if (pn4->pn_op == JSOP_FALSE) { + constVal.setBoolean(false); + break; + } + if (pn4->pn_op == JSOP_NULL) { + constVal.setNull(); + break; + } + /* FALL THROUGH */ + default: + switchOp = JSOP_CONDSWITCH; + continue; + } + JS_ASSERT(constVal.isPrimitive()); + + pn3->pn_pval = AllocateSwitchConstant(cx); + if (!pn3->pn_pval) { + ok = JS_FALSE; + goto release; + } + + *pn3->pn_pval = constVal; + + if (switchOp != JSOP_TABLESWITCH) + continue; + if (!pn3->pn_pval->isInt32()) { + switchOp = JSOP_LOOKUPSWITCH; + continue; + } + i = pn3->pn_pval->toInt32(); + if ((jsuint)(i + (jsint)JS_BIT(15)) >= (jsuint)JS_BIT(16)) { + switchOp = JSOP_LOOKUPSWITCH; + continue; + } + if (i < low) + low = i; + if (high < i) + high = i; + + /* + * Check for duplicates, which require a JSOP_LOOKUPSWITCH. + * We bias i by 65536 if it's negative, and hope that's a rare + * case (because it requires a malloc'd bitmap). + */ + if (i < 0) + i += JS_BIT(16); + if (i >= intmap_bitlen) { + if (!intmap && + i < (INTMAP_LENGTH << JS_BITS_PER_WORD_LOG2)) { + intmap = intmap_space; + intmap_bitlen = INTMAP_LENGTH << JS_BITS_PER_WORD_LOG2; + } else { + /* Just grab 8K for the worst-case bitmap. */ + intmap_bitlen = JS_BIT(16); + intmap = (jsbitmap *) + cx->malloc((JS_BIT(16) >> JS_BITS_PER_WORD_LOG2) + * sizeof(jsbitmap)); + if (!intmap) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + } + memset(intmap, 0, intmap_bitlen >> JS_BITS_PER_BYTE_LOG2); + } + if (JS_TEST_BIT(intmap, i)) { + switchOp = JSOP_LOOKUPSWITCH; + continue; + } + JS_SET_BIT(intmap, i); + } + + release: + if (intmap && intmap != intmap_space) + cx->free(intmap); + if (!ok) + return JS_FALSE; + + /* + * Compute table length and select lookup instead if overlarge or + * more than half-sparse. + */ + if (switchOp == JSOP_TABLESWITCH) { + tableLength = (uint32)(high - low + 1); + if (tableLength >= JS_BIT(16) || tableLength > 2 * caseCount) + switchOp = JSOP_LOOKUPSWITCH; + } else if (switchOp == JSOP_LOOKUPSWITCH) { + /* + * Lookup switch supports only atom indexes below 64K limit. + * Conservatively estimate the maximum possible index during + * switch generation and use conditional switch if it exceeds + * the limit. + */ + if (caseCount + cg->constList.length() > JS_BIT(16)) + switchOp = JSOP_CONDSWITCH; + } + } + + /* + * Emit a note with two offsets: first tells total switch code length, + * second tells offset to first JSOP_CASE if condswitch. + */ + noteIndex = js_NewSrcNote3(cx, cg, SRC_SWITCH, 0, 0); + if (noteIndex < 0) + return JS_FALSE; + + if (switchOp == JSOP_CONDSWITCH) { + /* + * 0 bytes of immediate for unoptimized ECMAv2 switch. + */ + switchSize = 0; + } else if (switchOp == JSOP_TABLESWITCH) { + /* + * 3 offsets (len, low, high) before the table, 1 per entry. + */ + switchSize = (size_t)(JUMP_OFFSET_LEN * (3 + tableLength)); + } else { + /* + * JSOP_LOOKUPSWITCH: + * 1 offset (len) and 1 atom index (npairs) before the table, + * 1 atom index and 1 jump offset per entry. + */ + switchSize = (size_t)(JUMP_OFFSET_LEN + INDEX_LEN + + (INDEX_LEN + JUMP_OFFSET_LEN) * caseCount); + } + + /* + * Emit switchOp followed by switchSize bytes of jump or lookup table. + * + * If switchOp is JSOP_LOOKUPSWITCH or JSOP_TABLESWITCH, it is crucial + * to emit the immediate operand(s) by which bytecode readers such as + * BuildSpanDepTable discover the length of the switch opcode *before* + * calling js_SetJumpOffset (which may call BuildSpanDepTable). It's + * also important to zero all unknown jump offset immediate operands, + * so they can be converted to span dependencies with null targets to + * be computed later (js_EmitN zeros switchSize bytes after switchOp). + */ + if (js_EmitN(cx, cg, switchOp, switchSize) < 0) + return JS_FALSE; + + off = -1; + if (switchOp == JSOP_CONDSWITCH) { + intN caseNoteIndex = -1; + JSBool beforeCases = JS_TRUE; + + /* Emit code for evaluating cases and jumping to case statements. */ + for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + pn4 = pn3->pn_left; + if (pn4 && !js_EmitTree(cx, cg, pn4)) + return JS_FALSE; + if (caseNoteIndex >= 0) { + /* off is the previous JSOP_CASE's bytecode offset. */ + if (!js_SetSrcNoteOffset(cx, cg, (uintN)caseNoteIndex, 0, + CG_OFFSET(cg) - off)) { + return JS_FALSE; + } + } + if (!pn4) { + JS_ASSERT(pn3->pn_type == TOK_DEFAULT); + continue; + } + caseNoteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0); + if (caseNoteIndex < 0) + return JS_FALSE; + off = EmitJump(cx, cg, JSOP_CASE, 0); + if (off < 0) + return JS_FALSE; + pn3->pn_offset = off; + if (beforeCases) { + uintN noteCount, noteCountDelta; + + /* Switch note's second offset is to first JSOP_CASE. */ + noteCount = CG_NOTE_COUNT(cg); + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, + off - top)) { + return JS_FALSE; + } + noteCountDelta = CG_NOTE_COUNT(cg) - noteCount; + if (noteCountDelta != 0) + caseNoteIndex += noteCountDelta; + beforeCases = JS_FALSE; + } + } + + /* + * If we didn't have an explicit default (which could fall in between + * cases, preventing us from fusing this js_SetSrcNoteOffset with the + * call in the loop above), link the last case to the implicit default + * for the decompiler. + */ + if (!hasDefault && + caseNoteIndex >= 0 && + !js_SetSrcNoteOffset(cx, cg, (uintN)caseNoteIndex, 0, + CG_OFFSET(cg) - off)) { + return JS_FALSE; + } + + /* Emit default even if no explicit default statement. */ + defaultOffset = EmitJump(cx, cg, JSOP_DEFAULT, 0); + if (defaultOffset < 0) + return JS_FALSE; + } else { + pc = CG_CODE(cg, top + JUMP_OFFSET_LEN); + + if (switchOp == JSOP_TABLESWITCH) { + /* Fill in switch bounds, which we know fit in 16-bit offsets. */ + SET_JUMP_OFFSET(pc, low); + pc += JUMP_OFFSET_LEN; + SET_JUMP_OFFSET(pc, high); + pc += JUMP_OFFSET_LEN; + + /* + * Use malloc to avoid arena bloat for programs with many switches. + * We free table if non-null at label out, so all control flow must + * exit this function through goto out or goto bad. + */ + if (tableLength != 0) { + tableSize = (size_t)tableLength * sizeof *table; + table = (JSParseNode **) cx->malloc(tableSize); + if (!table) + return JS_FALSE; + memset(table, 0, tableSize); + for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + if (pn3->pn_type == TOK_DEFAULT) + continue; + i = pn3->pn_pval->toInt32(); + i -= low; + JS_ASSERT((uint32)i < tableLength); + table[i] = pn3; + } + } + } else { + JS_ASSERT(switchOp == JSOP_LOOKUPSWITCH); + + /* Fill in the number of cases. */ + SET_INDEX(pc, caseCount); + pc += INDEX_LEN; + } + + /* + * After this point, all control flow involving JSOP_TABLESWITCH + * must set ok and goto out to exit this function. To keep things + * simple, all switchOp cases exit that way. + */ + MUST_FLOW_THROUGH("out"); + if (cg->spanDeps) { + /* + * We have already generated at least one big jump so we must + * explicitly add span dependencies for the switch jumps. When + * called below, js_SetJumpOffset can only do it when patching + * the first big jump or when cg->spanDeps is null. + */ + if (!AddSwitchSpanDeps(cx, cg, CG_CODE(cg, top))) + goto bad; + } + + if (constPropagated) { + /* + * Skip switchOp, as we are not setting jump offsets in the two + * for loops below. We'll restore CG_NEXT(cg) from savepc after, + * unless there was an error. + */ + savepc = CG_NEXT(cg); + CG_NEXT(cg) = pc + 1; + if (switchOp == JSOP_TABLESWITCH) { + for (i = 0; i < (jsint)tableLength; i++) { + pn3 = table[i]; + if (pn3 && + (pn4 = pn3->pn_left) != NULL && + pn4->pn_type == TOK_NAME) { + /* Note a propagated constant with the const's name. */ + JS_ASSERT(!pn4->maybeExpr()); + ale = cg->atomList.add(cg->parser, pn4->pn_atom); + if (!ale) + goto bad; + CG_NEXT(cg) = pc; + if (js_NewSrcNote2(cx, cg, SRC_LABEL, (ptrdiff_t) + ALE_INDEX(ale)) < 0) { + goto bad; + } + } + pc += JUMP_OFFSET_LEN; + } + } else { + for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + pn4 = pn3->pn_left; + if (pn4 && pn4->pn_type == TOK_NAME) { + /* Note a propagated constant with the const's name. */ + JS_ASSERT(!pn4->maybeExpr()); + ale = cg->atomList.add(cg->parser, pn4->pn_atom); + if (!ale) + goto bad; + CG_NEXT(cg) = pc; + if (js_NewSrcNote2(cx, cg, SRC_LABEL, (ptrdiff_t) + ALE_INDEX(ale)) < 0) { + goto bad; + } + } + pc += INDEX_LEN + JUMP_OFFSET_LEN; + } + } + CG_NEXT(cg) = savepc; + } + } + + /* Emit code for each case's statements, copying pn_offset up to pn3. */ + for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + if (switchOp == JSOP_CONDSWITCH && pn3->pn_type != TOK_DEFAULT) + CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx, cg, pn3->pn_offset, goto bad); + pn4 = pn3->pn_right; + ok = js_EmitTree(cx, cg, pn4); + if (!ok) + goto out; + pn3->pn_offset = pn4->pn_offset; + if (pn3->pn_type == TOK_DEFAULT) + off = pn3->pn_offset - top; + } + + if (!hasDefault) { + /* If no default case, offset for default is to end of switch. */ + off = CG_OFFSET(cg) - top; + } + + /* We better have set "off" by now. */ + JS_ASSERT(off != -1); + + /* Set the default offset (to end of switch if no default). */ + if (switchOp == JSOP_CONDSWITCH) { + pc = NULL; + JS_ASSERT(defaultOffset != -1); + ok = js_SetJumpOffset(cx, cg, CG_CODE(cg, defaultOffset), + off - (defaultOffset - top)); + if (!ok) + goto out; + } else { + pc = CG_CODE(cg, top); + ok = js_SetJumpOffset(cx, cg, pc, off); + if (!ok) + goto out; + pc += JUMP_OFFSET_LEN; + } + + /* Set the SRC_SWITCH note's offset operand to tell end of switch. */ + off = CG_OFFSET(cg) - top; + ok = js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, off); + if (!ok) + goto out; + + if (switchOp == JSOP_TABLESWITCH) { + /* Skip over the already-initialized switch bounds. */ + pc += 2 * JUMP_OFFSET_LEN; + + /* Fill in the jump table, if there is one. */ + for (i = 0; i < (jsint)tableLength; i++) { + pn3 = table[i]; + off = pn3 ? pn3->pn_offset - top : 0; + ok = js_SetJumpOffset(cx, cg, pc, off); + if (!ok) + goto out; + pc += JUMP_OFFSET_LEN; + } + } else if (switchOp == JSOP_LOOKUPSWITCH) { + /* Skip over the already-initialized number of cases. */ + pc += INDEX_LEN; + + for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + if (pn3->pn_type == TOK_DEFAULT) + continue; + if (!cg->constList.append(*pn3->pn_pval)) + goto bad; + SET_INDEX(pc, cg->constList.length() - 1); + pc += INDEX_LEN; + + off = pn3->pn_offset - top; + ok = js_SetJumpOffset(cx, cg, pc, off); + if (!ok) + goto out; + pc += JUMP_OFFSET_LEN; + } + } + +out: + if (table) + cx->free(table); + if (ok) { + ok = js_PopStatementCG(cx, cg); + +#if JS_HAS_BLOCK_SCOPE + if (ok && pn->pn_right->pn_type == TOK_LEXICALSCOPE) + ok = EmitLeaveBlock(cx, cg, JSOP_LEAVEBLOCK, box); +#endif + } + return ok; + +bad: + ok = JS_FALSE; + goto out; +} + +JSBool +js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body) +{ + /* + * The decompiler has assumptions about what may occur immediately after + * script->main (e.g., in the case of destructuring params). Thus, put the + * following ops into the range [script->code, script->main). Note: + * execution starts from script->code, so this has no semantic effect. + */ + + if (cg->flags & TCF_FUN_IS_GENERATOR) { + /* JSOP_GENERATOR must be the first instruction. */ + CG_SWITCH_TO_PROLOG(cg); + JS_ASSERT(CG_NEXT(cg) == CG_BASE(cg)); + if (js_Emit1(cx, cg, JSOP_GENERATOR) < 0) + return false; + CG_SWITCH_TO_MAIN(cg); + } + + /* + * Strict mode functions' arguments objects copy initial parameter values. + * We create arguments objects lazily -- but that doesn't work for strict + * mode functions where a parameter might be modified and arguments might + * be accessed. For such functions we synthesize an access to arguments to + * initialize it with the original parameter values. + */ + if (cg->needsEagerArguments()) { + CG_SWITCH_TO_PROLOG(cg); + if (js_Emit1(cx, cg, JSOP_ARGUMENTS) < 0 || js_Emit1(cx, cg, JSOP_POP) < 0) + return false; + CG_SWITCH_TO_MAIN(cg); + } + + if (cg->flags & TCF_FUN_UNBRAND_THIS) { + CG_SWITCH_TO_PROLOG(cg); + if (js_Emit1(cx, cg, JSOP_UNBRANDTHIS) < 0) + return false; + CG_SWITCH_TO_MAIN(cg); + } + + return js_EmitTree(cx, cg, body) && + js_Emit1(cx, cg, JSOP_STOP) >= 0 && + JSScript::NewScriptFromCG(cx, cg); +} + +/* A macro for inlining at the top of js_EmitTree (whence it came). */ +#define UPDATE_LINE_NUMBER_NOTES(cx, cg, line) \ + JS_BEGIN_MACRO \ + uintN line_ = (line); \ + uintN delta_ = line_ - CG_CURRENT_LINE(cg); \ + if (delta_ != 0) { \ + /* \ + * Encode any change in the current source line number by using \ + * either several SRC_NEWLINE notes or just one SRC_SETLINE note, \ + * whichever consumes less space. \ + * \ + * NB: We handle backward line number deltas (possible with for \ + * loops where the update part is emitted after the body, but its \ + * line number is <= any line number in the body) here by letting \ + * unsigned delta_ wrap to a very large number, which triggers a \ + * SRC_SETLINE. \ + */ \ + CG_CURRENT_LINE(cg) = line_; \ + if (delta_ >= (uintN)(2 + ((line_ > SN_3BYTE_OFFSET_MASK)<<1))) { \ + if (js_NewSrcNote2(cx, cg, SRC_SETLINE, (ptrdiff_t)line_) < 0)\ + return JS_FALSE; \ + } else { \ + do { \ + if (js_NewSrcNote(cx, cg, SRC_NEWLINE) < 0) \ + return JS_FALSE; \ + } while (--delta_ != 0); \ + } \ + } \ + JS_END_MACRO + +/* A function, so that we avoid macro-bloating all the other callsites. */ +static JSBool +UpdateLineNumberNotes(JSContext *cx, JSCodeGenerator *cg, uintN line) +{ + UPDATE_LINE_NUMBER_NOTES(cx, cg, line); + return JS_TRUE; +} + +static JSBool +MaybeEmitVarDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, + JSParseNode *pn, jsatomid *result) +{ + jsatomid atomIndex; + JSAtomListElement *ale; + + if (!pn->pn_cookie.isFree()) { + atomIndex = (jsatomid) pn->pn_cookie.slot(); + } else { + ale = cg->atomList.add(cg->parser, pn->pn_atom); + if (!ale) + return JS_FALSE; + atomIndex = ALE_INDEX(ale); + } + + if (JOF_OPTYPE(pn->pn_op) == JOF_ATOM && + (!cg->inFunction() || (cg->flags & TCF_FUN_HEAVYWEIGHT)) && + !(pn->pn_dflags & PND_GVAR)) + { + CG_SWITCH_TO_PROLOG(cg); + if (!UpdateLineNumberNotes(cx, cg, pn->pn_pos.begin.lineno)) + return JS_FALSE; + EMIT_INDEX_OP(prologOp, atomIndex); + CG_SWITCH_TO_MAIN(cg); + } + + if (cg->inFunction() && + JOF_OPTYPE(pn->pn_op) == JOF_LOCAL && + pn->pn_cookie.slot() < cg->bindings.countVars() && + cg->shouldNoteClosedName(pn)) + { + if (!cg->closedVars.append(pn->pn_cookie.slot())) + return JS_FALSE; + } + + if (result) + *result = atomIndex; + return JS_TRUE; +} + +#if JS_HAS_DESTRUCTURING + +typedef JSBool +(*DestructuringDeclEmitter)(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, + JSParseNode *pn); + +static JSBool +EmitDestructuringDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, + JSParseNode *pn) +{ + JS_ASSERT(pn->pn_type == TOK_NAME); + if (!BindNameToSlot(cx, cg, pn)) + return JS_FALSE; + + JS_ASSERT(PN_OP(pn) != JSOP_ARGUMENTS && PN_OP(pn) != JSOP_CALLEE); + return MaybeEmitVarDecl(cx, cg, prologOp, pn, NULL); +} + +static JSBool +EmitDestructuringDecls(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, + JSParseNode *pn) +{ + JSParseNode *pn2, *pn3; + DestructuringDeclEmitter emitter; + + if (pn->pn_type == TOK_RB) { + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + if (pn2->pn_type == TOK_COMMA) + continue; + emitter = (pn2->pn_type == TOK_NAME) + ? EmitDestructuringDecl + : EmitDestructuringDecls; + if (!emitter(cx, cg, prologOp, pn2)) + return JS_FALSE; + } + } else { + JS_ASSERT(pn->pn_type == TOK_RC); + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + pn3 = pn2->pn_right; + emitter = (pn3->pn_type == TOK_NAME) + ? EmitDestructuringDecl + : EmitDestructuringDecls; + if (!emitter(cx, cg, prologOp, pn3)) + return JS_FALSE; + } + } + return JS_TRUE; +} + +static JSBool +EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn); + +static JSBool +EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +{ + /* + * Now emit the lvalue opcode sequence. If the lvalue is a nested + * destructuring initialiser-form, call ourselves to handle it, then + * pop the matched value. Otherwise emit an lvalue bytecode sequence + * ending with a JSOP_ENUMELEM or equivalent op. + */ + if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC) { + if (!EmitDestructuringOpsHelper(cx, cg, pn)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + } else { + if (pn->pn_type == TOK_NAME) { + if (!BindNameToSlot(cx, cg, pn)) + return JS_FALSE; + if (pn->isConst() && !pn->isInitialized()) + return js_Emit1(cx, cg, JSOP_POP) >= 0; + } + + switch (pn->pn_op) { + case JSOP_SETNAME: + case JSOP_SETGNAME: + /* + * NB: pn is a PN_NAME node, not a PN_BINARY. Nevertheless, + * we want to emit JSOP_ENUMELEM, which has format JOF_ELEM. + * So here and for JSOP_ENUMCONSTELEM, we use EmitElemOp. + */ + if (!EmitElemOp(cx, pn, JSOP_ENUMELEM, cg)) + return JS_FALSE; + break; + + case JSOP_SETCONST: + if (!EmitElemOp(cx, pn, JSOP_ENUMCONSTELEM, cg)) + return JS_FALSE; + break; + + case JSOP_SETLOCAL: + { + jsuint slot = pn->pn_cookie.asInteger(); + EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, slot); + break; + } + + case JSOP_SETARG: + { + jsuint slot = pn->pn_cookie.asInteger(); + EMIT_UINT16_IMM_OP(PN_OP(pn), slot); + if (js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + break; + } + + default: + { + ptrdiff_t top; + + top = CG_OFFSET(cg); + if (!js_EmitTree(cx, cg, pn)) + return JS_FALSE; + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0) + return JS_FALSE; + break; + } + + case JSOP_ENUMELEM: + JS_ASSERT(0); + } + } + + return JS_TRUE; +} + +/* + * Recursive helper for EmitDestructuringOps. + * + * Given a value to destructure on the stack, walk over an object or array + * initialiser at pn, emitting bytecodes to match property values and store + * them in the lvalues identified by the matched property names. + */ +static JSBool +EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +{ + jsuint index; + JSParseNode *pn2, *pn3; + JSBool doElemOp; + +#ifdef DEBUG + intN stackDepth = cg->stackDepth; + JS_ASSERT(stackDepth != 0); + JS_ASSERT(pn->pn_arity == PN_LIST); + JS_ASSERT(pn->pn_type == TOK_RB || pn->pn_type == TOK_RC); +#endif + + if (pn->pn_count == 0) { + /* Emit a DUP;POP sequence for the decompiler. */ + return js_Emit1(cx, cg, JSOP_DUP) >= 0 && + js_Emit1(cx, cg, JSOP_POP) >= 0; + } + + index = 0; + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + /* + * Duplicate the value being destructured to use as a reference base. + * If dup is not the first one, annotate it for the decompiler. + */ + if (pn2 != pn->pn_head && js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_DUP) < 0) + return JS_FALSE; + + /* + * Now push the property name currently being matched, which is either + * the array initialiser's current index, or the current property name + * "label" on the left of a colon in the object initialiser. Set pn3 + * to the lvalue node, which is in the value-initializing position. + */ + doElemOp = JS_TRUE; + if (pn->pn_type == TOK_RB) { + if (!EmitNumberOp(cx, index, cg)) + return JS_FALSE; + pn3 = pn2; + } else { + JS_ASSERT(pn->pn_type == TOK_RC); + JS_ASSERT(pn2->pn_type == TOK_COLON); + pn3 = pn2->pn_left; + if (pn3->pn_type == TOK_NUMBER) { + /* + * If we are emitting an object destructuring initialiser, + * annotate the index op with SRC_INITPROP so we know we are + * not decompiling an array initialiser. + */ + if (js_NewSrcNote(cx, cg, SRC_INITPROP) < 0) + return JS_FALSE; + if (!EmitNumberOp(cx, pn3->pn_dval, cg)) + return JS_FALSE; + } else { + JS_ASSERT(pn3->pn_type == TOK_STRING || + pn3->pn_type == TOK_NAME); + if (!EmitAtomOp(cx, pn3, JSOP_GETPROP, cg)) + return JS_FALSE; + doElemOp = JS_FALSE; + } + pn3 = pn2->pn_right; + } + + if (doElemOp) { + /* + * Ok, get the value of the matching property name. This leaves + * that value on top of the value being destructured, so the stack + * is one deeper than when we started. + */ + if (js_Emit1(cx, cg, JSOP_GETELEM) < 0) + return JS_FALSE; + JS_ASSERT(cg->stackDepth == stackDepth + 1); + } + + /* Nullary comma node makes a hole in the array destructurer. */ + if (pn3->pn_type == TOK_COMMA && pn3->pn_arity == PN_NULLARY) { + JS_ASSERT(pn->pn_type == TOK_RB); + JS_ASSERT(pn2 == pn3); + if (js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + } else { + if (!EmitDestructuringLHS(cx, cg, pn3)) + return JS_FALSE; + } + + JS_ASSERT(cg->stackDepth == stackDepth); + ++index; + } + + return JS_TRUE; +} + +static ptrdiff_t +OpToDeclType(JSOp op) +{ + switch (op) { + case JSOP_NOP: + return SRC_DECL_LET; + case JSOP_DEFCONST: + return SRC_DECL_CONST; + case JSOP_DEFVAR: + return SRC_DECL_VAR; + default: + return SRC_DECL_NONE; + } +} + +static JSBool +EmitDestructuringOps(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, + JSParseNode *pn) +{ + /* + * If we're called from a variable declaration, help the decompiler by + * annotating the first JSOP_DUP that EmitDestructuringOpsHelper emits. + * If the destructuring initialiser is empty, our helper will emit a + * JSOP_DUP followed by a JSOP_POP for the decompiler. + */ + if (js_NewSrcNote2(cx, cg, SRC_DESTRUCT, OpToDeclType(prologOp)) < 0) + return JS_FALSE; + + /* + * Call our recursive helper to emit the destructuring assignments and + * related stack manipulations. + */ + return EmitDestructuringOpsHelper(cx, cg, pn); +} + +static JSBool +EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, + JSParseNode *lhs, JSParseNode *rhs) +{ + jsuint depth, limit, i, nslots; + JSParseNode *pn; + + depth = limit = (uintN) cg->stackDepth; + for (pn = rhs->pn_head; pn; pn = pn->pn_next) { + if (limit == JS_BIT(16)) { + ReportCompileErrorNumber(cx, CG_TS(cg), rhs, JSREPORT_ERROR, JSMSG_ARRAY_INIT_TOO_BIG); + return JS_FALSE; + } + + /* MaybeEmitGroupAssignment won't call us if rhs is holey. */ + JS_ASSERT(!(pn->pn_type == TOK_COMMA && pn->pn_arity == PN_NULLARY)); + if (!js_EmitTree(cx, cg, pn)) + return JS_FALSE; + ++limit; + } + + if (js_NewSrcNote2(cx, cg, SRC_GROUPASSIGN, OpToDeclType(prologOp)) < 0) + return JS_FALSE; + + i = depth; + for (pn = lhs->pn_head; pn; pn = pn->pn_next, ++i) { + /* MaybeEmitGroupAssignment requires lhs->pn_count <= rhs->pn_count. */ + JS_ASSERT(i < limit); + jsint slot = AdjustBlockSlot(cx, cg, i); + if (slot < 0) + return JS_FALSE; + EMIT_UINT16_IMM_OP(JSOP_GETLOCAL, slot); + + if (pn->pn_type == TOK_COMMA && pn->pn_arity == PN_NULLARY) { + if (js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + } else { + if (!EmitDestructuringLHS(cx, cg, pn)) + return JS_FALSE; + } + } + + nslots = limit - depth; + EMIT_UINT16_IMM_OP(JSOP_POPN, nslots); + cg->stackDepth = (uintN) depth; + return JS_TRUE; +} + +/* + * Helper called with pop out param initialized to a JSOP_POP* opcode. If we + * can emit a group assignment sequence, which results in 0 stack depth delta, + * we set *pop to JSOP_NOP so callers can veto emitting pn followed by a pop. + */ +static JSBool +MaybeEmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp, + JSParseNode *pn, JSOp *pop) +{ + JSParseNode *lhs, *rhs; + + JS_ASSERT(pn->pn_type == TOK_ASSIGN); + JS_ASSERT(*pop == JSOP_POP || *pop == JSOP_POPV); + lhs = pn->pn_left; + rhs = pn->pn_right; + if (lhs->pn_type == TOK_RB && rhs->pn_type == TOK_RB && + !(rhs->pn_xflags & PNX_HOLEY) && + lhs->pn_count <= rhs->pn_count) { + if (!EmitGroupAssignment(cx, cg, prologOp, lhs, rhs)) + return JS_FALSE; + *pop = JSOP_NOP; + } + return JS_TRUE; +} + +#endif /* JS_HAS_DESTRUCTURING */ + +static JSBool +EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, + JSBool inLetHead, ptrdiff_t *headNoteIndex) +{ + bool let, forInVar, first; +#if JS_HAS_BLOCK_SCOPE + bool forInLet, popScope; + JSStmtInfo *stmt, *scopeStmt; +#endif + ptrdiff_t off, noteIndex, tmp; + JSParseNode *pn2, *pn3, *next; + JSOp op; + jsatomid atomIndex; + uintN oldflags; + + /* Default in case of JS_HAS_BLOCK_SCOPE early return, below. */ + *headNoteIndex = -1; + + /* + * Let blocks and expressions have a parenthesized head in which the new + * scope is not yet open. Initializer evaluation uses the parent node's + * lexical scope. If popScope is true below, then we hide the top lexical + * block from any calls to BindNameToSlot hiding in pn2->pn_expr so that + * it won't find any names in the new let block. + * + * The same goes for let declarations in the head of any kind of for loop. + * Unlike a let declaration 'let x = i' within a block, where x is hoisted + * to the start of the block, a 'for (let x = i...) ...' loop evaluates i + * in the containing scope, and puts x in the loop body's scope. + */ + let = (pn->pn_op == JSOP_NOP); + forInVar = (pn->pn_xflags & PNX_FORINVAR) != 0; +#if JS_HAS_BLOCK_SCOPE + forInLet = let && forInVar; + popScope = (inLetHead || (let && (cg->flags & TCF_IN_FOR_INIT))); + if (popScope) { + stmt = cg->topStmt; + scopeStmt = cg->topScopeStmt; + } +# ifdef __GNUC__ + else stmt = scopeStmt = NULL; /* quell GCC overwarning */ +# endif + JS_ASSERT(!popScope || let); +#endif + + off = noteIndex = -1; + for (pn2 = pn->pn_head; ; pn2 = next) { + first = pn2 == pn->pn_head; + next = pn2->pn_next; + + if (pn2->pn_type != TOK_NAME) { +#if JS_HAS_DESTRUCTURING + if (pn2->pn_type == TOK_RB || pn2->pn_type == TOK_RC) { + /* + * Emit variable binding ops, but not destructuring ops. + * The parser (see Variables, jsparse.c) has ensured that + * our caller will be the TOK_FOR/TOK_IN case in js_EmitTree, + * and that case will emit the destructuring code only after + * emitting an enumerating opcode and a branch that tests + * whether the enumeration ended. + */ + JS_ASSERT(forInVar); + JS_ASSERT(pn->pn_count == 1); + if (!EmitDestructuringDecls(cx, cg, PN_OP(pn), pn2)) + return JS_FALSE; + break; + } +#endif + + /* + * A destructuring initialiser assignment preceded by var will + * never occur to the left of 'in' in a for-in loop. As with 'for + * (var x = i in o)...', this will cause the entire 'var [a, b] = + * i' to be hoisted out of the loop. + */ + JS_ASSERT(pn2->pn_type == TOK_ASSIGN); + JS_ASSERT(!forInVar); + + /* + * To allow the front end to rewrite var f = x; as f = x; when a + * function f(){} precedes the var, detect simple name assignment + * here and initialize the name. + */ +#if !JS_HAS_DESTRUCTURING + JS_ASSERT(pn2->pn_left->pn_type == TOK_NAME); +#else + if (pn2->pn_left->pn_type == TOK_NAME) +#endif + { + pn3 = pn2->pn_right; + pn2 = pn2->pn_left; + goto do_name; + } + +#if JS_HAS_DESTRUCTURING + if (pn->pn_count == 1) { + /* + * If this is the only destructuring assignment in the list, + * try to optimize to a group assignment. If we're in a let + * head, pass JSOP_POP rather than the pseudo-prolog JSOP_NOP + * in pn->pn_op, to suppress a second (and misplaced) 'let'. + */ + JS_ASSERT(noteIndex < 0 && !pn2->pn_next); + op = JSOP_POP; + if (!MaybeEmitGroupAssignment(cx, cg, + inLetHead ? JSOP_POP : PN_OP(pn), + pn2, &op)) { + return JS_FALSE; + } + if (op == JSOP_NOP) { + pn->pn_xflags = (pn->pn_xflags & ~PNX_POPVAR) | PNX_GROUPINIT; + break; + } + } + + pn3 = pn2->pn_left; + if (!EmitDestructuringDecls(cx, cg, PN_OP(pn), pn3)) + return JS_FALSE; + + if (!js_EmitTree(cx, cg, pn2->pn_right)) + return JS_FALSE; + + /* + * Veto pn->pn_op if inLetHead to avoid emitting a SRC_DESTRUCT + * that's redundant with respect to the SRC_DECL/SRC_DECL_LET that + * we will emit at the bottom of this function. + */ + if (!EmitDestructuringOps(cx, cg, + inLetHead ? JSOP_POP : PN_OP(pn), + pn3)) { + return JS_FALSE; + } + goto emit_note_pop; +#endif + } + + /* + * Load initializer early to share code above that jumps to do_name. + * NB: if this var redeclares an existing binding, then pn2 is linked + * on its definition's use-chain and pn_expr has been overlayed with + * pn_lexdef. + */ + pn3 = pn2->maybeExpr(); + + do_name: + if (!BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + + op = PN_OP(pn2); + if (op == JSOP_ARGUMENTS) { + /* JSOP_ARGUMENTS => no initializer */ + JS_ASSERT(!pn3 && !let); + pn3 = NULL; +#ifdef __GNUC__ + atomIndex = 0; /* quell GCC overwarning */ +#endif + } else { + JS_ASSERT(op != JSOP_CALLEE); + JS_ASSERT(!pn2->pn_cookie.isFree() || !let); + if (!MaybeEmitVarDecl(cx, cg, PN_OP(pn), pn2, &atomIndex)) + return JS_FALSE; + + if (pn3) { + JS_ASSERT(!forInVar); + if (op == JSOP_SETNAME) { + JS_ASSERT(!let); + EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex); + } else if (op == JSOP_SETGNAME) { + JS_ASSERT(!let); + EMIT_INDEX_OP(JSOP_BINDGNAME, atomIndex); + } + if (pn->pn_op == JSOP_DEFCONST && + !js_DefineCompileTimeConstant(cx, cg, pn2->pn_atom, pn3)) { + return JS_FALSE; + } + +#if JS_HAS_BLOCK_SCOPE + /* Evaluate expr in the outer lexical scope if requested. */ + if (popScope) { + cg->topStmt = stmt->down; + cg->topScopeStmt = scopeStmt->downScope; + } +#endif + + oldflags = cg->flags; + cg->flags &= ~TCF_IN_FOR_INIT; + if (!js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + cg->flags |= oldflags & TCF_IN_FOR_INIT; + +#if JS_HAS_BLOCK_SCOPE + if (popScope) { + cg->topStmt = stmt; + cg->topScopeStmt = scopeStmt; + JS_ASSERT(cg->blockChainBox == scopeStmt->blockBox); + } +#endif + } + } + + /* + * The parser rewrites 'for (var x = i in o)' to hoist 'var x = i' -- + * likewise 'for (let x = i in o)' becomes 'i; for (let x in o)' using + * a TOK_SEQ node to make the two statements appear as one. Therefore + * if this declaration is part of a for-in loop head, we do not need to + * emit op or any source note. Our caller, the TOK_FOR/TOK_IN case in + * js_EmitTree, will annotate appropriately. + */ + JS_ASSERT_IF(pn2->pn_defn, pn3 == pn2->pn_expr); + if (forInVar) { + JS_ASSERT(pn->pn_count == 1); + JS_ASSERT(!pn3); + break; + } + + if (first && + !inLetHead && + js_NewSrcNote2(cx, cg, SRC_DECL, + (pn->pn_op == JSOP_DEFCONST) + ? SRC_DECL_CONST + : (pn->pn_op == JSOP_DEFVAR) + ? SRC_DECL_VAR + : SRC_DECL_LET) < 0) { + return JS_FALSE; + } + if (op == JSOP_ARGUMENTS) { + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + } else if (!pn2->pn_cookie.isFree()) { + EMIT_UINT16_IMM_OP(op, atomIndex); + } else { + EMIT_INDEX_OP(op, atomIndex); + } + +#if JS_HAS_DESTRUCTURING + emit_note_pop: +#endif + tmp = CG_OFFSET(cg); + if (noteIndex >= 0) { + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off)) + return JS_FALSE; + } + if (!next) + break; + off = tmp; + noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0); + if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + } + + /* If this is a let head, emit and return a srcnote on the pop. */ + if (inLetHead) { + *headNoteIndex = js_NewSrcNote(cx, cg, SRC_DECL); + if (*headNoteIndex < 0) + return JS_FALSE; + if (!(pn->pn_xflags & PNX_POPVAR)) + return js_Emit1(cx, cg, JSOP_NOP) >= 0; + } + + return !(pn->pn_xflags & PNX_POPVAR) || js_Emit1(cx, cg, JSOP_POP) >= 0; +} + +#if defined DEBUG_brendan || defined DEBUG_mrbkap +static JSBool +GettableNoteForNextOp(JSCodeGenerator *cg) +{ + ptrdiff_t offset, target; + jssrcnote *sn, *end; + + offset = 0; + target = CG_OFFSET(cg); + for (sn = CG_NOTES(cg), end = sn + CG_NOTE_COUNT(cg); sn < end; + sn = SN_NEXT(sn)) { + if (offset == target && SN_IS_GETTABLE(sn)) + return JS_TRUE; + offset += SN_DELTA(sn); + } + return JS_FALSE; +} +#endif + +/* Top-level named functions need a nop for decompilation. */ +static JSBool +EmitFunctionDefNop(JSContext *cx, JSCodeGenerator *cg, uintN index) +{ + return js_NewSrcNote2(cx, cg, SRC_FUNCDEF, (ptrdiff_t)index) >= 0 && + js_Emit1(cx, cg, JSOP_NOP) >= 0; +} + +static bool +EmitNewInit(JSContext *cx, JSCodeGenerator *cg, JSProtoKey key, JSParseNode *pn, int sharpnum) +{ + if (js_Emit3(cx, cg, JSOP_NEWINIT, (jsbytecode) key, 0) < 0) + return false; +#if JS_HAS_SHARP_VARS + if (cg->hasSharps()) { + if (pn->pn_count != 0) + EMIT_UINT16_IMM_OP(JSOP_SHARPINIT, cg->sharpSlotBase); + if (sharpnum >= 0) + EMIT_UINT16PAIR_IMM_OP(JSOP_DEFSHARP, cg->sharpSlotBase, sharpnum); + } else { + JS_ASSERT(sharpnum < 0); + } +#endif + return true; +} + +static bool +EmitEndInit(JSContext *cx, JSCodeGenerator *cg, uint32 count) +{ +#if JS_HAS_SHARP_VARS + /* Emit an op for sharp array cleanup and decompilation. */ + if (cg->hasSharps() && count != 0) + EMIT_UINT16_IMM_OP(JSOP_SHARPINIT, cg->sharpSlotBase); +#endif + return js_Emit1(cx, cg, JSOP_ENDINIT) >= 0; +} + +bool +JSParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp) +{ + switch (pn_type) { + case TOK_NUMBER: + vp->setNumber(pn_dval); + return true; + case TOK_STRING: + vp->setString(ATOM_TO_STRING(pn_atom)); + return true; + case TOK_PRIMARY: + switch (pn_op) { + case JSOP_NULL: + vp->setNull(); + return true; + case JSOP_FALSE: + vp->setBoolean(false); + return true; + case JSOP_TRUE: + vp->setBoolean(true); + return true; + default: + JS_NOT_REACHED("Unexpected node"); + return false; + } + case TOK_RB: { + JS_ASSERT((pn_op == JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST)); + + JSObject *obj = NewDenseAllocatedArray(cx, pn_count); + if (!obj || !obj->ensureSlots(cx, pn_count)) + return false; + + unsigned idx = 0; + for (JSParseNode *pn = pn_head; pn; idx++, pn = pn->pn_next) { + Value value; + if (!pn->getConstantValue(cx, strictChecks, &value)) + return false; + obj->setDenseArrayElement(idx, value); + } + JS_ASSERT(idx == pn_count); + + vp->setObject(*obj); + return true; + } + case TOK_RC: { + JS_ASSERT((pn_op == JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST)); + + gc::FinalizeKind kind = GuessObjectGCKind(pn_count, false); + JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind); + if (!obj) + return false; + + for (JSParseNode *pn = pn_head; pn; pn = pn->pn_next) { + Value value; + if (!pn->pn_right->getConstantValue(cx, strictChecks, &value)) + return false; + + JSParseNode *pnid = pn->pn_left; + if (pnid->pn_type == TOK_NUMBER) { + Value idvalue = NumberValue(pnid->pn_dval); + jsid id; + if (idvalue.isInt32() && INT_FITS_IN_JSID(idvalue.toInt32())) + id = INT_TO_JSID(idvalue.toInt32()); + else if (!js_InternNonIntElementId(cx, obj, idvalue, &id)) + return false; + if (!obj->defineProperty(cx, id, value, NULL, NULL, JSPROP_ENUMERATE)) + return false; + } else { + JS_ASSERT(pnid->pn_type == TOK_NAME || + pnid->pn_type == TOK_STRING); + jsid id = ATOM_TO_JSID(pnid->pn_atom); + if (!((pnid->pn_atom == cx->runtime->atomState.protoAtom) + ? js_SetPropertyHelper(cx, obj, id, 0, &value, strictChecks) + : js_DefineNativeProperty(cx, obj, id, value, NULL, NULL, + JSPROP_ENUMERATE, 0, 0, NULL, 0))) { + return false; + } + } + } + + vp->setObject(*obj); + return true; + } + default: + JS_NOT_REACHED("Unexpected node"); + } + return false; +} + +static bool +EmitSingletonInitialiser(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +{ + Value value; + if (!pn->getConstantValue(cx, cg->needStrictChecks(), &value)) + return false; + + JS_ASSERT(value.isObject()); + JSObjectBox *objbox = cg->parser->newObjectBox(&value.toObject()); + if (!objbox) + return false; + + return EmitObjectOp(cx, objbox, JSOP_OBJECT, cg); +} + +/* See the SRC_FOR source note offsetBias comments later in this file. */ +JS_STATIC_ASSERT(JSOP_NOP_LENGTH == 1); +JS_STATIC_ASSERT(JSOP_POP_LENGTH == 1); + +class EmitLevelManager +{ +private: + JSCodeGenerator *cg; + +public: + EmitLevelManager(JSCodeGenerator *cg) : cg(cg) { cg->emitLevel++; } + + ~EmitLevelManager() { cg->emitLevel--; } +}; + +JSBool +js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) +{ + JSBool ok, useful, wantval; + JSStmtInfo *stmt, stmtInfo; + ptrdiff_t top, off, tmp, beq, jmp, tmp2, tmp3; + JSParseNode *pn2, *pn3; + JSAtom *atom; + JSAtomListElement *ale; + jsatomid atomIndex; + uintN index; + ptrdiff_t noteIndex, noteIndex2; + JSSrcNoteType noteType; + jsbytecode *pc; + JSOp op; + TokenKind type; + uint32 argc; + EmitLevelManager elm(cg); +#if JS_HAS_SHARP_VARS + jsint sharpnum; +#endif + + JS_CHECK_RECURSION(cx, return JS_FALSE); + + ok = JS_TRUE; + pn->pn_offset = top = CG_OFFSET(cg); + + /* Emit notes to tell the current bytecode's source line number. */ + UPDATE_LINE_NUMBER_NOTES(cx, cg, pn->pn_pos.begin.lineno); + + switch (pn->pn_type) { + case TOK_FUNCTION: + { + JSFunction *fun; + uintN slot; + +#if JS_HAS_XML_SUPPORT + if (pn->pn_arity == PN_NULLARY) { + if (js_Emit1(cx, cg, JSOP_GETFUNNS) < 0) + return JS_FALSE; + break; + } +#endif + + fun = (JSFunction *) pn->pn_funbox->object; + JS_ASSERT(FUN_INTERPRETED(fun)); + if (fun->u.i.script) { + /* + * This second pass is needed to emit JSOP_NOP with a source note + * for the already-emitted function definition prolog opcode. See + * comments in the TOK_LC case. + */ + JS_ASSERT(pn->pn_op == JSOP_NOP); + JS_ASSERT(cg->inFunction()); + if (!EmitFunctionDefNop(cx, cg, pn->pn_index)) + return JS_FALSE; + break; + } + + JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT, + FUN_KIND(fun) == JSFUN_INTERPRETED); + + /* Generate code for the function's body. */ + void *cg2mark = JS_ARENA_MARK(cg->codePool); + void *cg2space; + JS_ARENA_ALLOCATE_TYPE(cg2space, JSCodeGenerator, cg->codePool); + if (!cg2space) { + js_ReportOutOfScriptQuota(cx); + return JS_FALSE; + } + JSCodeGenerator *cg2 = + new (cg2space) JSCodeGenerator(cg->parser, + cg->codePool, cg->notePool, + pn->pn_pos.begin.lineno); + + if (!cg2->init()) + return JS_FALSE; + + cg2->flags = pn->pn_funbox->tcflags | TCF_COMPILING | TCF_IN_FUNCTION | + (cg->flags & TCF_FUN_MIGHT_ALIAS_LOCALS); + cg2->bindings.transfer(cx, &pn->pn_funbox->bindings); +#if JS_HAS_SHARP_VARS + if (cg2->flags & TCF_HAS_SHARPS) { + cg2->sharpSlotBase = cg2->bindings.sharpSlotBase(cx); + if (cg2->sharpSlotBase < 0) + return JS_FALSE; + } +#endif + cg2->setFunction(fun); + cg2->funbox = pn->pn_funbox; + cg2->parent = cg; + + /* + * jsparse.cpp:SetStaticLevel limited static nesting depth to fit in 16 + * bits and to reserve the all-ones value, thereby reserving the magic + * FREE_UPVAR_COOKIE value. Note the cg2->staticLevel assignment below. + */ + JS_ASSERT(cg->staticLevel < JS_BITMASK(16) - 1); + cg2->staticLevel = cg->staticLevel + 1; + + /* We measured the max scope depth when we parsed the function. */ + JS_SCOPE_DEPTH_METERING(cg2->maxScopeDepth = uint16(-1)); + if (!js_EmitFunctionScript(cx, cg2, pn->pn_body)) + pn = NULL; + + cg2->~JSCodeGenerator(); + JS_ARENA_RELEASE(cg->codePool, cg2mark); + cg2 = NULL; + if (!pn) + return JS_FALSE; + + /* Make the function object a literal in the outer script's pool. */ + index = cg->objectList.index(pn->pn_funbox); + + /* Emit a bytecode pointing to the closure object in its immediate. */ + op = PN_OP(pn); + if (op != JSOP_NOP) { + if ((pn->pn_funbox->tcflags & TCF_GENEXP_LAMBDA) && + js_NewSrcNote(cx, cg, SRC_GENEXP) < 0) { + return JS_FALSE; + } + EMIT_INDEX_OP(op, index); + + /* Make blockChain determination quicker. */ + if (EmitBlockChain(cx, cg) < 0) + return JS_FALSE; + break; + } + + /* + * For a script we emit the code as we parse. Thus the bytecode for + * top-level functions should go in the prolog to predefine their + * names in the variable object before the already-generated main code + * is executed. This extra work for top-level scripts is not necessary + * when we emit the code for a function. It is fully parsed prior to + * invocation of the emitter and calls to js_EmitTree for function + * definitions can be scheduled before generating the rest of code. + */ + if (!cg->inFunction()) { + JS_ASSERT(!cg->topStmt); + if (!BindGlobal(cx, cg, pn, fun->atom)) + return false; + if (pn->pn_cookie.isFree()) { + CG_SWITCH_TO_PROLOG(cg); + op = FUN_FLAT_CLOSURE(fun) ? JSOP_DEFFUN_FC : JSOP_DEFFUN; + EMIT_INDEX_OP(op, index); + + /* Make blockChain determination quicker. */ + if (EmitBlockChain(cx, cg) < 0) + return JS_FALSE; + CG_SWITCH_TO_MAIN(cg); + } + + /* Emit NOP for the decompiler. */ + if (!EmitFunctionDefNop(cx, cg, index)) + return JS_FALSE; + } else { +#ifdef DEBUG + BindingKind kind = +#endif + cg->bindings.lookup(cx, fun->atom, &slot); + JS_ASSERT(kind == VARIABLE || kind == CONSTANT); + JS_ASSERT(index < JS_BIT(20)); + pn->pn_index = index; + op = fun->isFlatClosure() ? JSOP_DEFLOCALFUN_FC : JSOP_DEFLOCALFUN; + if (pn->isClosed() && + !cg->callsEval() && + !cg->closedVars.append(pn->pn_cookie.slot())) { + return JS_FALSE; + } + if (!EmitSlotIndexOp(cx, op, slot, index, cg)) + return JS_FALSE; + + /* Make blockChain determination quicker. */ + if (EmitBlockChain(cx, cg) < 0) + return JS_FALSE; + } + break; + } + + case TOK_ARGSBODY: + { + JSParseNode *pnlast = pn->last(); + for (JSParseNode *pn2 = pn->pn_head; pn2 != pnlast; pn2 = pn2->pn_next) { + if (!pn2->pn_defn) + continue; + if (!BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + if (JOF_OPTYPE(pn2->pn_op) == JOF_QARG && cg->shouldNoteClosedName(pn2)) { + if (!cg->closedArgs.append(pn2->pn_cookie.slot())) + return JS_FALSE; + } + } + ok = js_EmitTree(cx, cg, pnlast); + break; + } + + case TOK_UPVARS: + JS_ASSERT(cg->lexdeps.count == 0); + JS_ASSERT(pn->pn_names.count != 0); + cg->lexdeps = pn->pn_names; + ok = js_EmitTree(cx, cg, pn->pn_tree); + break; + + case TOK_IF: + /* Initialize so we can detect else-if chains and avoid recursion. */ + stmtInfo.type = STMT_IF; + beq = jmp = -1; + noteIndex = -1; + + if_again: + /* Emit code for the condition before pushing stmtInfo. */ + if (!js_EmitTree(cx, cg, pn->pn_kid1)) + return JS_FALSE; + top = CG_OFFSET(cg); + if (stmtInfo.type == STMT_IF) { + js_PushStatement(cg, &stmtInfo, STMT_IF, top); + } else { + /* + * We came here from the goto further below that detects else-if + * chains, so we must mutate stmtInfo back into a STMT_IF record. + * Also (see below for why) we need a note offset for SRC_IF_ELSE + * to help the decompiler. Actually, we need two offsets, one for + * decompiling any else clause and the second for decompiling an + * else-if chain without bracing, overindenting, or incorrectly + * scoping let declarations. + */ + JS_ASSERT(stmtInfo.type == STMT_ELSE); + stmtInfo.type = STMT_IF; + stmtInfo.update = top; + if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq)) + return JS_FALSE; + if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 1, top - beq)) + return JS_FALSE; + } + + /* Emit an annotated branch-if-false around the then part. */ + pn3 = pn->pn_kid3; + noteIndex = js_NewSrcNote(cx, cg, pn3 ? SRC_IF_ELSE : SRC_IF); + if (noteIndex < 0) + return JS_FALSE; + beq = EmitJump(cx, cg, JSOP_IFEQ, 0); + if (beq < 0) + return JS_FALSE; + + /* Emit code for the then and optional else parts. */ + if (!js_EmitTree(cx, cg, pn->pn_kid2)) + return JS_FALSE; + if (pn3) { + /* Modify stmtInfo so we know we're in the else part. */ + stmtInfo.type = STMT_ELSE; + + /* + * Emit a JSOP_BACKPATCH op to jump from the end of our then part + * around the else part. The js_PopStatementCG call at the bottom + * of this switch case will fix up the backpatch chain linked from + * stmtInfo.breaks. + */ + jmp = EmitGoto(cx, cg, &stmtInfo, &stmtInfo.breaks, NULL, SRC_NULL); + if (jmp < 0) + return JS_FALSE; + + /* Ensure the branch-if-false comes here, then emit the else. */ + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq); + if (pn3->pn_type == TOK_IF) { + pn = pn3; + goto if_again; + } + + if (!js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + + /* + * Annotate SRC_IF_ELSE with the offset from branch to jump, for + * the decompiler's benefit. We can't just "back up" from the pc + * of the else clause, because we don't know whether an extended + * jump was required to leap from the end of the then clause over + * the else clause. + */ + if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq)) + return JS_FALSE; + } else { + /* No else part, fixup the branch-if-false to come here. */ + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq); + } + ok = js_PopStatementCG(cx, cg); + break; + + case TOK_SWITCH: + /* Out of line to avoid bloating js_EmitTree's stack frame size. */ + ok = EmitSwitch(cx, cg, pn, &stmtInfo); + break; + + case TOK_WHILE: + /* + * Minimize bytecodes issued for one or more iterations by jumping to + * the condition below the body and closing the loop if the condition + * is true with a backward branch. For iteration count i: + * + * i test at the top test at the bottom + * = =============== ================== + * 0 ifeq-pass goto; ifne-fail + * 1 ifeq-fail; goto; ifne-pass goto; ifne-pass; ifne-fail + * 2 2*(ifeq-fail; goto); ifeq-pass goto; 2*ifne-pass; ifne-fail + * . . . + * N N*(ifeq-fail; goto); ifeq-pass goto; N*ifne-pass; ifne-fail + * + * SpiderMonkey, pre-mozilla.org, emitted while parsing and so used + * test at the top. When JSParseNode trees were added during the ES3 + * work (1998-9), the code generation scheme was not optimized, and + * the decompiler continued to take advantage of the branch and jump + * that bracketed the body. But given the SRC_WHILE note, it is easy + * to support the more efficient scheme. + */ + js_PushStatement(cg, &stmtInfo, STMT_WHILE_LOOP, top); + noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE); + if (noteIndex < 0) + return JS_FALSE; + jmp = EmitJump(cx, cg, JSOP_GOTO, 0); + if (jmp < 0) + return JS_FALSE; + noteIndex2 = js_NewSrcNote(cx, cg, SRC_TRACE); + if (noteIndex2 < 0) + return JS_FALSE; + top = EmitTraceOp(cx, cg); + if (top < 0) + return JS_FALSE; + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); + if (!js_EmitTree(cx, cg, pn->pn_left)) + return JS_FALSE; + beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)); + if (beq < 0) + return JS_FALSE; + /* + * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex + * note gets bigger. + */ + if (!js_SetSrcNoteOffset(cx, cg, noteIndex2, 0, beq - top)) + return JS_FALSE; + if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, beq - jmp)) + return JS_FALSE; + ok = js_PopStatementCG(cx, cg); + break; + + case TOK_DO: + /* Emit an annotated nop so we know to decompile a 'do' keyword. */ + noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE); + if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0) + return JS_FALSE; + + noteIndex2 = js_NewSrcNote(cx, cg, SRC_TRACE); + if (noteIndex2 < 0) + return JS_FALSE; + + /* Compile the loop body. */ + top = EmitTraceOp(cx, cg); + if (top < 0) + return JS_FALSE; + js_PushStatement(cg, &stmtInfo, STMT_DO_LOOP, top); + if (!js_EmitTree(cx, cg, pn->pn_left)) + return JS_FALSE; + + /* Set loop and enclosing label update offsets, for continue. */ + stmt = &stmtInfo; + do { + stmt->update = CG_OFFSET(cg); + } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL); + + /* Compile the loop condition, now that continues know where to go. */ + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + + /* + * Since we use JSOP_IFNE for other purposes as well as for do-while + * loops, we must store 1 + (beq - top) in the SRC_WHILE note offset, + * and the decompiler must get that delta and decompile recursively. + */ + beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)); + if (beq < 0) + return JS_FALSE; + /* + * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex + * note gets bigger. + */ + if (!js_SetSrcNoteOffset(cx, cg, noteIndex2, 0, beq - top)) + return JS_FALSE; + if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, 1 + (beq - top))) + return JS_FALSE; + ok = js_PopStatementCG(cx, cg); + break; + + case TOK_FOR: + beq = 0; /* suppress gcc warnings */ + jmp = -1; + pn2 = pn->pn_left; + js_PushStatement(cg, &stmtInfo, STMT_FOR_LOOP, top); + + if (pn2->pn_type == TOK_IN) { + /* Set stmtInfo type for later testing. */ + stmtInfo.type = STMT_FOR_IN_LOOP; + + /* + * If the left part is 'var x', emit code to define x if necessary + * using a prolog opcode, but do not emit a pop. If the left part + * is 'var x = i', emit prolog code to define x if necessary; then + * emit code to evaluate i, assign the result to x, and pop the + * result off the stack. + * + * All the logic to do this is implemented in the outer switch's + * TOK_VAR case, conditioned on pn_xflags flags set by the parser. + * + * In the 'for (var x = i in o) ...' case, the js_EmitTree(...pn3) + * called here will generate the proper note for the assignment + * op that sets x = i, hoisting the initialized var declaration + * out of the loop: 'var x = i; for (x in o) ...'. + * + * In the 'for (var x in o) ...' case, nothing but the prolog op + * (if needed) should be generated here, we must emit the note + * just before the JSOP_FOR* opcode in the switch on pn3->pn_type + * a bit below, so nothing is hoisted: 'for (var x in o) ...'. + * + * A 'for (let x = i in o)' loop must not be hoisted, since in + * this form the let variable is scoped by the loop body (but not + * the head). The initializer expression i must be evaluated for + * any side effects. So we hoist only i in the let case. + */ + pn3 = pn2->pn_left; + type = PN_TYPE(pn3); + cg->flags |= TCF_IN_FOR_INIT; + if (TokenKindIsDecl(type) && !js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + cg->flags &= ~TCF_IN_FOR_INIT; + + /* Compile the object expression to the right of 'in'. */ + if (!js_EmitTree(cx, cg, pn2->pn_right)) + return JS_FALSE; + + /* + * Emit a bytecode to convert top of stack value to the iterator + * object depending on the loop variant (for-in, for-each-in, or + * destructuring for-in). + */ + JS_ASSERT(pn->pn_op == JSOP_ITER); + if (js_Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0) + return JS_FALSE; + + /* Annotate so the decompiler can find the loop-closing jump. */ + noteIndex = js_NewSrcNote(cx, cg, SRC_FOR_IN); + if (noteIndex < 0) + return JS_FALSE; + + /* + * Jump down to the loop condition to minimize overhead assuming at + * least one iteration, as the other loop forms do. + */ + jmp = EmitJump(cx, cg, JSOP_GOTO, 0); + if (jmp < 0) + return JS_FALSE; + + noteIndex2 = js_NewSrcNote(cx, cg, SRC_TRACE); + if (noteIndex2 < 0) + return JS_FALSE; + + top = CG_OFFSET(cg); + SET_STATEMENT_TOP(&stmtInfo, top); + if (EmitTraceOp(cx, cg) < 0) + return JS_FALSE; + +#ifdef DEBUG + intN loopDepth = cg->stackDepth; +#endif + + /* + * Compile a JSOP_FOR* bytecode based on the left hand side. + * + * Initialize op to JSOP_SETNAME in case of |for ([a, b] in o)...| + * or similar, to signify assignment, rather than declaration, to + * the decompiler. EmitDestructuringOps takes a prolog bytecode + * parameter and emits the appropriate source note, defaulting to + * assignment, so JSOP_SETNAME is not critical here; many similar + * ops could be used -- just not JSOP_NOP (which means 'let'). + */ + op = JSOP_SETNAME; + switch (type) { +#if JS_HAS_BLOCK_SCOPE + case TOK_LET: +#endif + case TOK_VAR: + JS_ASSERT(pn3->pn_arity == PN_LIST && pn3->pn_count == 1); + pn3 = pn3->pn_head; +#if JS_HAS_DESTRUCTURING + if (pn3->pn_type == TOK_ASSIGN) { + pn3 = pn3->pn_left; + JS_ASSERT(pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC); + } + if (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) { + op = PN_OP(pn2->pn_left); + goto destructuring_for; + } +#else + JS_ASSERT(pn3->pn_type == TOK_NAME); +#endif + /* FALL THROUGH */ + + case TOK_NAME: + { + /* + * Always annotate JSOP_FORLOCAL if given input of the form + * 'for (let x in * o)' -- the decompiler must not hoist the + * 'let x' out of the loop head, or x will be bound in the + * wrong scope. Likewise, but in this case only for the sake + * of higher decompilation fidelity only, do not hoist 'var x' + * when given 'for (var x in o)'. + */ + if (( +#if JS_HAS_BLOCK_SCOPE + type == TOK_LET || +#endif + (type == TOK_VAR && !pn3->maybeExpr())) && + js_NewSrcNote2(cx, cg, SRC_DECL, + (type == TOK_VAR) + ? SRC_DECL_VAR + : SRC_DECL_LET) < 0) { + return JS_FALSE; + } + UpvarCookie cookie = pn3->pn_cookie; + if (!cookie.isFree()) { + op = PN_OP(pn3); + switch (op) { + case JSOP_GETARG: + case JSOP_SETARG: + op = JSOP_FORARG; + break; + case JSOP_GETLOCAL: + case JSOP_SETLOCAL: + op = JSOP_FORLOCAL; + break; + case JSOP_GETGLOBAL: + op = JSOP_FORGNAME; + cookie.makeFree(); + break; + default: + JS_NOT_REACHED("unexpected opcode"); + } + } else { + pn3->pn_op = JSOP_FORNAME; + if (!BindNameToSlot(cx, cg, pn3)) + return JS_FALSE; + op = PN_OP(pn3); + cookie = pn3->pn_cookie; + } + if (pn3->isConst()) { + ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR, + JSMSG_BAD_FOR_LEFTSIDE); + return JS_FALSE; + } + if (!cookie.isFree()) { + atomIndex = (jsatomid) cookie.asInteger(); + EMIT_UINT16_IMM_OP(op, atomIndex); + } else { + if (!EmitAtomOp(cx, pn3, op, cg)) + return JS_FALSE; + } + break; + } + + case TOK_DOT: + /* + * 'for (o.p in q)' can use JSOP_FORPROP only if evaluating 'o' + * has no side effects. + */ + useful = JS_FALSE; + if (!CheckSideEffects(cx, cg, pn3->expr(), &useful)) + return JS_FALSE; + if (!useful) { + if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg, JS_FALSE)) + return JS_FALSE; + break; + } + /* FALL THROUGH */ + +#if JS_HAS_DESTRUCTURING + destructuring_for: +#endif + default: + if (js_Emit1(cx, cg, JSOP_FORELEM) < 0) + return JS_FALSE; + JS_ASSERT(cg->stackDepth >= 2); + +#if JS_HAS_DESTRUCTURING + if (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) { + if (!EmitDestructuringOps(cx, cg, op, pn3)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + } else +#endif + if (pn3->pn_type == TOK_LP) { + JS_ASSERT(pn3->pn_xflags & PNX_SETCALL); + if (!js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0) + return JS_FALSE; + } else +#if JS_HAS_XML_SUPPORT + if (pn3->pn_type == TOK_UNARYOP) { + JS_ASSERT(pn3->pn_op == JSOP_BINDXMLNAME); + if (!js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0) + return JS_FALSE; + } else +#endif + if (!EmitElemOp(cx, pn3, JSOP_ENUMELEM, cg)) + return JS_FALSE; + break; + } + + /* The stack should be balanced around the JSOP_FOR* opcode sequence. */ + JS_ASSERT(cg->stackDepth == loopDepth); + + tmp2 = CG_OFFSET(cg); + + /* Emit code for the loop body. */ + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + + /* Set loop and enclosing "update" offsets, for continue. */ + stmt = &stmtInfo; + do { + stmt->update = CG_OFFSET(cg); + } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL); + + /* + * Fixup the goto that starts the loop to jump down to JSOP_MOREITER. + */ + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); + if (js_Emit1(cx, cg, JSOP_MOREITER) < 0) + return JS_FALSE; + beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)); + if (beq < 0) + return JS_FALSE; + + /* + * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex + * note gets bigger. + */ + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, beq - top)) + return JS_FALSE; + /* Set the first srcnote offset so we can find the start of the loop body. */ + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp2 - jmp)) + return JS_FALSE; + /* Set the second srcnote offset so we can find the closing jump. */ + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, beq - jmp)) + return JS_FALSE; + } else { + /* C-style for (init; cond; update) ... loop. */ + op = JSOP_POP; + pn3 = pn2->pn_kid1; + if (!pn3) { + /* No initializer: emit an annotated nop for the decompiler. */ + op = JSOP_NOP; + } else { + cg->flags |= TCF_IN_FOR_INIT; +#if JS_HAS_DESTRUCTURING + if (pn3->pn_type == TOK_ASSIGN && + !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) { + return JS_FALSE; + } +#endif + if (op == JSOP_POP) { + if (!js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + if (TokenKindIsDecl(PN_TYPE(pn3))) { + /* + * Check whether a destructuring-initialized var decl + * was optimized to a group assignment. If so, we do + * not need to emit a pop below, so switch to a nop, + * just for the decompiler. + */ + JS_ASSERT(pn3->pn_arity == PN_LIST); + if (pn3->pn_xflags & PNX_GROUPINIT) + op = JSOP_NOP; + } + } + cg->flags &= ~TCF_IN_FOR_INIT; + } + + /* + * NB: the SRC_FOR note has offsetBias 1 (JSOP_{NOP,POP}_LENGTH). + * Use tmp to hold the biased srcnote "top" offset, which differs + * from the top local variable by the length of the JSOP_GOTO{,X} + * emitted in between tmp and top if this loop has a condition. + */ + noteIndex = js_NewSrcNote(cx, cg, SRC_FOR); + if (noteIndex < 0 || js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + tmp = CG_OFFSET(cg); + + if (pn2->pn_kid2) { + /* Goto the loop condition, which branches back to iterate. */ + jmp = EmitJump(cx, cg, JSOP_GOTO, 0); + if (jmp < 0) + return JS_FALSE; + } + + top = CG_OFFSET(cg); + SET_STATEMENT_TOP(&stmtInfo, top); + + noteIndex2 = js_NewSrcNote(cx, cg, SRC_TRACE); + if (noteIndex2 < 0) + return JS_FALSE; + + /* Emit code for the loop body. */ + if (EmitTraceOp(cx, cg) < 0) + return JS_FALSE; + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + + /* Set the second note offset so we can find the update part. */ + JS_ASSERT(noteIndex != -1); + tmp2 = CG_OFFSET(cg); + + /* Set loop and enclosing "update" offsets, for continue. */ + stmt = &stmtInfo; + do { + stmt->update = CG_OFFSET(cg); + } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL); + + /* Check for update code to do before the condition (if any). */ + pn3 = pn2->pn_kid3; + if (pn3) { + op = JSOP_POP; +#if JS_HAS_DESTRUCTURING + if (pn3->pn_type == TOK_ASSIGN && + !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) { + return JS_FALSE; + } +#endif + if (op == JSOP_POP && !js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + + /* Always emit the POP or NOP, to help the decompiler. */ + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + + /* Restore the absolute line number for source note readers. */ + off = (ptrdiff_t) pn->pn_pos.end.lineno; + if (CG_CURRENT_LINE(cg) != (uintN) off) { + if (js_NewSrcNote2(cx, cg, SRC_SETLINE, off) < 0) + return JS_FALSE; + CG_CURRENT_LINE(cg) = (uintN) off; + } + } + + tmp3 = CG_OFFSET(cg); + + if (pn2->pn_kid2) { + /* Fix up the goto from top to target the loop condition. */ + JS_ASSERT(jmp >= 0); + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); + + if (!js_EmitTree(cx, cg, pn2->pn_kid2)) + return JS_FALSE; + } + + /* + * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex + * note gets bigger. + */ + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, + CG_OFFSET(cg) - top)) { + return JS_FALSE; + } + /* Set the first note offset so we can find the loop condition. */ + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, + tmp3 - tmp)) { + return JS_FALSE; + } + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, + tmp2 - tmp)) { + return JS_FALSE; + } + /* The third note offset helps us find the loop-closing jump. */ + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2, + CG_OFFSET(cg) - tmp)) { + return JS_FALSE; + } + + if (pn2->pn_kid2) { + beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)); + if (beq < 0) + return JS_FALSE; + } else { + /* No loop condition -- emit the loop-closing jump. */ + jmp = EmitJump(cx, cg, JSOP_GOTO, top - CG_OFFSET(cg)); + if (jmp < 0) + return JS_FALSE; + } + } + + /* Now fixup all breaks and continues (before for/in's JSOP_ENDITER). */ + if (!js_PopStatementCG(cx, cg)) + return JS_FALSE; + + if (pn2->pn_type == TOK_IN) { + if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg)) || + js_Emit1(cx, cg, JSOP_ENDITER) < 0) { + return JS_FALSE; + } + } + break; + + case TOK_BREAK: + stmt = cg->topStmt; + atom = pn->pn_atom; + if (atom) { + ale = cg->atomList.add(cg->parser, atom); + if (!ale) + return JS_FALSE; + while (stmt->type != STMT_LABEL || stmt->label != atom) + stmt = stmt->down; + noteType = SRC_BREAK2LABEL; + } else { + ale = NULL; + while (!STMT_IS_LOOP(stmt) && stmt->type != STMT_SWITCH) + stmt = stmt->down; + noteType = (stmt->type == STMT_SWITCH) ? SRC_NULL : SRC_BREAK; + } + + if (EmitGoto(cx, cg, stmt, &stmt->breaks, ale, noteType) < 0) + return JS_FALSE; + break; + + case TOK_CONTINUE: + stmt = cg->topStmt; + atom = pn->pn_atom; + if (atom) { + /* Find the loop statement enclosed by the matching label. */ + JSStmtInfo *loop = NULL; + ale = cg->atomList.add(cg->parser, atom); + if (!ale) + return JS_FALSE; + while (stmt->type != STMT_LABEL || stmt->label != atom) { + if (STMT_IS_LOOP(stmt)) + loop = stmt; + stmt = stmt->down; + } + stmt = loop; + noteType = SRC_CONT2LABEL; + } else { + ale = NULL; + while (!STMT_IS_LOOP(stmt)) + stmt = stmt->down; + noteType = SRC_CONTINUE; + } + + if (EmitGoto(cx, cg, stmt, &stmt->continues, ale, noteType) < 0) + return JS_FALSE; + break; + + case TOK_WITH: + if (!js_EmitTree(cx, cg, pn->pn_left)) + return JS_FALSE; + js_PushStatement(cg, &stmtInfo, STMT_WITH, CG_OFFSET(cg)); + if (js_Emit1(cx, cg, JSOP_ENTERWITH) < 0) + return JS_FALSE; + + /* Make blockChain determination quicker. */ + if (EmitBlockChain(cx, cg) < 0) + return JS_FALSE; + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) + return JS_FALSE; + ok = js_PopStatementCG(cx, cg); + break; + + case TOK_TRY: + { + ptrdiff_t tryStart, tryEnd, catchJump, finallyStart; + intN depth; + JSParseNode *lastCatch; + + catchJump = -1; + + /* + * Push stmtInfo to track jumps-over-catches and gosubs-to-finally + * for later fixup. + * + * When a finally block is active (STMT_FINALLY in our tree context), + * non-local jumps (including jumps-over-catches) result in a GOSUB + * being written into the bytecode stream and fixed-up later (c.f. + * EmitBackPatchOp and BackPatch). + */ + js_PushStatement(cg, &stmtInfo, + pn->pn_kid3 ? STMT_FINALLY : STMT_TRY, + CG_OFFSET(cg)); + + /* + * Since an exception can be thrown at any place inside the try block, + * we need to restore the stack and the scope chain before we transfer + * the control to the exception handler. + * + * For that we store in a try note associated with the catch or + * finally block the stack depth upon the try entry. The interpreter + * uses this depth to properly unwind the stack and the scope chain. + */ + depth = cg->stackDepth; + + /* Mark try location for decompilation, then emit try block. */ + if (js_Emit1(cx, cg, JSOP_TRY) < 0) + return JS_FALSE; + tryStart = CG_OFFSET(cg); + if (!js_EmitTree(cx, cg, pn->pn_kid1)) + return JS_FALSE; + JS_ASSERT(depth == cg->stackDepth); + + /* GOSUB to finally, if present. */ + if (pn->pn_kid3) { + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &GOSUBS(stmtInfo)); + if (jmp < 0) + return JS_FALSE; + } + + /* Emit (hidden) jump over catch and/or finally. */ + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &catchJump); + if (jmp < 0) + return JS_FALSE; + + tryEnd = CG_OFFSET(cg); + + JSObjectBox *prevBox = NULL; + /* If this try has a catch block, emit it. */ + pn2 = pn->pn_kid2; + lastCatch = NULL; + if (pn2) { + uintN count = 0; /* previous catch block's population */ + + /* + * The emitted code for a catch block looks like: + * + * blockchain + * [throwing] only if 2nd+ catch block + * [leaveblock] only if 2nd+ catch block + * enterblock with SRC_CATCH + * exception + * [dup] only if catchguard + * setlocalpop or destructuring code + * [< catchguard code >] if there's a catchguard + * [ifeq ] " " + * [pop] only if catchguard + * < catch block contents > + * leaveblock + * goto non-local; finally applies + * + * If there's no catch block without a catchguard, the last + * points to rethrow code. This + * code will [gosub] to the finally code if appropriate, and is + * also used for the catch-all trynote for capturing exceptions + * thrown from catch{} blocks. + */ + for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { + ptrdiff_t guardJump, catchNote; + + JS_ASSERT(cg->stackDepth == depth); + guardJump = GUARDJUMP(stmtInfo); + if (guardJump != -1) { + if (EmitKnownBlockChain(cx, cg, prevBox) < 0) + return JS_FALSE; + + /* Fix up and clean up previous catch block. */ + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, guardJump); + + /* + * Account for JSOP_ENTERBLOCK (whose block object count + * is saved below) and pushed exception object that we + * still have after the jumping from the previous guard. + */ + cg->stackDepth = depth + count + 1; + + /* + * Move exception back to cx->exception to prepare for + * the next catch. We hide [throwing] from the decompiler + * since it compensates for the hidden JSOP_DUP at the + * start of the previous guarded catch. + */ + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || + js_Emit1(cx, cg, JSOP_THROWING) < 0) { + return JS_FALSE; + } + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + if (!EmitLeaveBlock(cx, cg, JSOP_LEAVEBLOCK, prevBox)) + return JS_FALSE; + JS_ASSERT(cg->stackDepth == depth); + } + + /* + * Annotate the JSOP_ENTERBLOCK that's about to be generated + * by the call to js_EmitTree immediately below. Save this + * source note's index in stmtInfo for use by the TOK_CATCH: + * case, where the length of the catch guard is set as the + * note's offset. + */ + catchNote = js_NewSrcNote2(cx, cg, SRC_CATCH, 0); + if (catchNote < 0) + return JS_FALSE; + CATCHNOTE(stmtInfo) = catchNote; + + /* + * Emit the lexical scope and catch body. Save the catch's + * block object population via count, for use when targeting + * guardJump at the next catch (the guard mismatch case). + */ + JS_ASSERT(pn3->pn_type == TOK_LEXICALSCOPE); + count = OBJ_BLOCK_COUNT(cx, pn3->pn_objbox->object); + prevBox = pn3->pn_objbox; + if (!js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + + /* gosub , if required */ + if (pn->pn_kid3) { + jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, + &GOSUBS(stmtInfo)); + if (jmp < 0) + return JS_FALSE; + JS_ASSERT(cg->stackDepth == depth); + } + + /* + * Jump over the remaining catch blocks. This will get fixed + * up to jump to after catch/finally. + */ + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &catchJump); + if (jmp < 0) + return JS_FALSE; + + /* + * Save a pointer to the last catch node to handle try-finally + * and try-catch(guard)-finally special cases. + */ + lastCatch = pn3->expr(); + } + } + + /* + * Last catch guard jumps to the rethrow code sequence if none of the + * guards match. Target guardJump at the beginning of the rethrow + * sequence, just in case a guard expression throws and leaves the + * stack unbalanced. + */ + if (lastCatch && lastCatch->pn_kid2) { + if (EmitKnownBlockChain(cx, cg, prevBox) < 0) + return JS_FALSE; + + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, GUARDJUMP(stmtInfo)); + + /* Sync the stack to take into account pushed exception. */ + JS_ASSERT(cg->stackDepth == depth); + cg->stackDepth = depth + 1; + + /* + * Rethrow the exception, delegating executing of finally if any + * to the exception handler. + */ + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || + js_Emit1(cx, cg, JSOP_THROW) < 0) { + return JS_FALSE; + } + + if (EmitBlockChain(cx, cg) < 0) + return JS_FALSE; + } + + JS_ASSERT(cg->stackDepth == depth); + + /* Emit finally handler if any. */ + finallyStart = 0; /* to quell GCC uninitialized warnings */ + if (pn->pn_kid3) { + /* + * Fix up the gosubs that might have been emitted before non-local + * jumps to the finally code. + */ + if (!BackPatch(cx, cg, GOSUBS(stmtInfo), CG_NEXT(cg), JSOP_GOSUB)) + return JS_FALSE; + + finallyStart = CG_OFFSET(cg); + + /* Indicate that we're emitting a subroutine body. */ + stmtInfo.type = STMT_SUBROUTINE; + if (!UpdateLineNumberNotes(cx, cg, pn->pn_kid3->pn_pos.begin.lineno)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_FINALLY) < 0 || + !js_EmitTree(cx, cg, pn->pn_kid3) || + js_Emit1(cx, cg, JSOP_RETSUB) < 0) { + return JS_FALSE; + } + JS_ASSERT(cg->stackDepth == depth); + } + if (!js_PopStatementCG(cx, cg)) + return JS_FALSE; + + if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 || + js_Emit1(cx, cg, JSOP_NOP) < 0) { + return JS_FALSE; + } + + /* Fix up the end-of-try/catch jumps to come here. */ + if (!BackPatch(cx, cg, catchJump, CG_NEXT(cg), JSOP_GOTO)) + return JS_FALSE; + + /* + * Add the try note last, to let post-order give us the right ordering + * (first to last for a given nesting level, inner to outer by level). + */ + if (pn->pn_kid2 && + !NewTryNote(cx, cg, JSTRY_CATCH, depth, tryStart, tryEnd)) { + return JS_FALSE; + } + + /* + * If we've got a finally, mark try+catch region with additional + * trynote to catch exceptions (re)thrown from a catch block or + * for the try{}finally{} case. + */ + if (pn->pn_kid3 && + !NewTryNote(cx, cg, JSTRY_FINALLY, depth, tryStart, finallyStart)) { + return JS_FALSE; + } + break; + } + + case TOK_CATCH: + { + ptrdiff_t catchStart, guardJump; + JSObject *blockObj; + + /* + * Morph STMT_BLOCK to STMT_CATCH, note the block entry code offset, + * and save the block object atom. + */ + stmt = cg->topStmt; + JS_ASSERT(stmt->type == STMT_BLOCK && (stmt->flags & SIF_SCOPE)); + stmt->type = STMT_CATCH; + catchStart = stmt->update; + blockObj = stmt->blockBox->object; + + /* Go up one statement info record to the TRY or FINALLY record. */ + stmt = stmt->down; + JS_ASSERT(stmt->type == STMT_TRY || stmt->type == STMT_FINALLY); + + /* Pick up the pending exception and bind it to the catch variable. */ + if (js_Emit1(cx, cg, JSOP_EXCEPTION) < 0) + return JS_FALSE; + + /* + * Dup the exception object if there is a guard for rethrowing to use + * it later when rethrowing or in other catches. + */ + if (pn->pn_kid2 && js_Emit1(cx, cg, JSOP_DUP) < 0) + return JS_FALSE; + + pn2 = pn->pn_kid1; + switch (pn2->pn_type) { +#if JS_HAS_DESTRUCTURING + case TOK_RB: + case TOK_RC: + if (!EmitDestructuringOps(cx, cg, JSOP_NOP, pn2)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + break; +#endif + + case TOK_NAME: + /* Inline and specialize BindNameToSlot for pn2. */ + JS_ASSERT(!pn2->pn_cookie.isFree()); + EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, pn2->pn_cookie.asInteger()); + break; + + default: + JS_ASSERT(0); + } + + /* Emit the guard expression, if there is one. */ + if (pn->pn_kid2) { + if (!js_EmitTree(cx, cg, pn->pn_kid2)) + return JS_FALSE; + if (!js_SetSrcNoteOffset(cx, cg, CATCHNOTE(*stmt), 0, + CG_OFFSET(cg) - catchStart)) { + return JS_FALSE; + } + /* ifeq */ + guardJump = EmitJump(cx, cg, JSOP_IFEQ, 0); + if (guardJump < 0) + return JS_FALSE; + GUARDJUMP(*stmt) = guardJump; + + /* Pop duplicated exception object as we no longer need it. */ + if (js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + } + + /* Emit the catch body. */ + if (!js_EmitTree(cx, cg, pn->pn_kid3)) + return JS_FALSE; + + /* + * Annotate the JSOP_LEAVEBLOCK that will be emitted as we unwind via + * our TOK_LEXICALSCOPE parent, so the decompiler knows to pop. + */ + off = cg->stackDepth; + if (js_NewSrcNote2(cx, cg, SRC_CATCH, off) < 0) + return JS_FALSE; + break; + } + + case TOK_VAR: + if (!EmitVariables(cx, cg, pn, JS_FALSE, ¬eIndex)) + return JS_FALSE; + break; + + case TOK_RETURN: + /* Push a return value */ + pn2 = pn->pn_kid; + if (pn2) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + } else { + if (js_Emit1(cx, cg, JSOP_PUSH) < 0) + return JS_FALSE; + } + + /* + * EmitNonLocalJumpFixup may add fixup bytecode to close open try + * blocks having finally clauses and to exit intermingled let blocks. + * We can't simply transfer control flow to our caller in that case, + * because we must gosub to those finally clauses from inner to outer, + * with the correct stack pointer (i.e., after popping any with, + * for/in, etc., slots nested inside the finally's try). + * + * In this case we mutate JSOP_RETURN into JSOP_SETRVAL and add an + * extra JSOP_RETRVAL after the fixups. + */ + top = CG_OFFSET(cg); + if (js_Emit1(cx, cg, JSOP_RETURN) < 0) + return JS_FALSE; + if (!EmitNonLocalJumpFixup(cx, cg, NULL)) + return JS_FALSE; + if (top + JSOP_RETURN_LENGTH != CG_OFFSET(cg)) { + CG_BASE(cg)[top] = JSOP_SETRVAL; + if (js_Emit1(cx, cg, JSOP_RETRVAL) < 0) + return JS_FALSE; + if (EmitBlockChain(cx, cg) < 0) + return JS_FALSE; + } + break; + +#if JS_HAS_GENERATORS + case TOK_YIELD: + if (!cg->inFunction()) { + ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, + JSMSG_BAD_RETURN_OR_YIELD, + js_yield_str); + return JS_FALSE; + } + if (pn->pn_kid) { + if (!js_EmitTree(cx, cg, pn->pn_kid)) + return JS_FALSE; + } else { + if (js_Emit1(cx, cg, JSOP_PUSH) < 0) + return JS_FALSE; + } + if (pn->pn_hidden && js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_YIELD) < 0) + return JS_FALSE; + break; +#endif + + case TOK_LC: + { +#if JS_HAS_XML_SUPPORT + if (pn->pn_arity == PN_UNARY) { + if (!js_EmitTree(cx, cg, pn->pn_kid)) + return JS_FALSE; + if (js_Emit1(cx, cg, PN_OP(pn)) < 0) + return JS_FALSE; + break; + } +#endif + + JS_ASSERT(pn->pn_arity == PN_LIST); + + noteIndex = -1; + tmp = CG_OFFSET(cg); + if (pn->pn_xflags & PNX_NEEDBRACES) { + noteIndex = js_NewSrcNote2(cx, cg, SRC_BRACE, 0); + if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0) + return JS_FALSE; + } + + js_PushStatement(cg, &stmtInfo, STMT_BLOCK, top); + + JSParseNode *pnchild = pn->pn_head; + if (pn->pn_xflags & PNX_FUNCDEFS) { + /* + * This block contains top-level function definitions. To ensure + * that we emit the bytecode defining them before the rest of code + * in the block we use a separate pass over functions. During the + * main pass later the emitter will add JSOP_NOP with source notes + * for the function to preserve the original functions position + * when decompiling. + * + * Currently this is used only for functions, as compile-as-we go + * mode for scripts does not allow separate emitter passes. + */ + JS_ASSERT(cg->inFunction()); + if (pn->pn_xflags & PNX_DESTRUCT) { + /* + * Assign the destructuring arguments before defining any + * functions, see bug 419662. + */ + JS_ASSERT(pnchild->pn_type == TOK_SEMI); + JS_ASSERT(pnchild->pn_kid->pn_type == TOK_VAR); + if (!js_EmitTree(cx, cg, pnchild)) + return JS_FALSE; + pnchild = pnchild->pn_next; + } + + for (pn2 = pnchild; pn2; pn2 = pn2->pn_next) { + if (pn2->pn_type == TOK_FUNCTION) { + if (pn2->pn_op == JSOP_NOP) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + } else { + /* + * JSOP_DEFFUN in a top-level block with function + * definitions appears, for example, when "if (true)" + * is optimized away from "if (true) function x() {}". + * See bug 428424. + */ + JS_ASSERT(pn2->pn_op == JSOP_DEFFUN); + } + } + } + } + for (pn2 = pnchild; pn2; pn2 = pn2->pn_next) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + } + + if (noteIndex >= 0 && + !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, + CG_OFFSET(cg) - tmp)) { + return JS_FALSE; + } + + ok = js_PopStatementCG(cx, cg); + break; + } + + case TOK_SEQ: + JS_ASSERT(pn->pn_arity == PN_LIST); + js_PushStatement(cg, &stmtInfo, STMT_SEQ, top); + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + } + ok = js_PopStatementCG(cx, cg); + break; + + case TOK_SEMI: + pn2 = pn->pn_kid; + if (pn2) { + /* + * Top-level or called-from-a-native JS_Execute/EvaluateScript, + * debugger, and eval frames may need the value of the ultimate + * expression statement as the script's result, despite the fact + * that it appears useless to the compiler. + * + * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when + * calling JS_Compile* to suppress JSOP_POPV. + */ + useful = wantval = !(cg->flags & (TCF_IN_FUNCTION | TCF_NO_SCRIPT_RVAL)); + + /* Don't eliminate expressions with side effects. */ + if (!useful) { + if (!CheckSideEffects(cx, cg, pn2, &useful)) + return JS_FALSE; + } + + /* + * Don't eliminate apparently useless expressions if they are + * labeled expression statements. The tc->topStmt->update test + * catches the case where we are nesting in js_EmitTree for a + * labeled compound statement. + */ + if (!useful && + cg->topStmt && + cg->topStmt->type == STMT_LABEL && + cg->topStmt->update >= CG_OFFSET(cg)) { + useful = true; + } + + if (!useful) { + /* Don't complain about directive prologue members; just don't emit their code. */ + if (!pn->isDirectivePrologueMember()) { + CG_CURRENT_LINE(cg) = pn2->pn_pos.begin.lineno; + if (!ReportCompileErrorNumber(cx, CG_TS(cg), pn2, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_USELESS_EXPR)) { + return JS_FALSE; + } + } + } else { + op = wantval ? JSOP_POPV : JSOP_POP; +#if JS_HAS_DESTRUCTURING + if (!wantval && + pn2->pn_type == TOK_ASSIGN && + !MaybeEmitGroupAssignment(cx, cg, op, pn2, &op)) { + return JS_FALSE; + } +#endif + if (op != JSOP_NOP) { + /* + * Specialize JSOP_SETPROP to JSOP_SETMETHOD to defer or + * avoid null closure cloning. Do this only for assignment + * statements that are not completion values wanted by a + * script evaluator, to ensure that the joined function + * can't escape directly. + */ + if (!wantval && + PN_TYPE(pn2) == TOK_ASSIGN && + PN_OP(pn2) == JSOP_NOP && + PN_OP(pn2->pn_left) == JSOP_SETPROP && + PN_OP(pn2->pn_right) == JSOP_LAMBDA && + pn2->pn_right->pn_funbox->joinable()) { + pn2->pn_left->pn_op = JSOP_SETMETHOD; + } + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + } + } + } + break; + + case TOK_COLON: + /* Emit an annotated nop so we know to decompile a label. */ + atom = pn->pn_atom; + ale = cg->atomList.add(cg->parser, atom); + if (!ale) + return JS_FALSE; + pn2 = pn->expr(); + noteType = (pn2->pn_type == TOK_LC || + (pn2->pn_type == TOK_LEXICALSCOPE && + pn2->expr()->pn_type == TOK_LC)) + ? SRC_LABELBRACE + : SRC_LABEL; + noteIndex = js_NewSrcNote2(cx, cg, noteType, + (ptrdiff_t) ALE_INDEX(ale)); + if (noteIndex < 0 || + js_Emit1(cx, cg, JSOP_NOP) < 0) { + return JS_FALSE; + } + + /* Emit code for the labeled statement. */ + js_PushStatement(cg, &stmtInfo, STMT_LABEL, CG_OFFSET(cg)); + stmtInfo.label = atom; + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (!js_PopStatementCG(cx, cg)) + return JS_FALSE; + + /* If the statement was compound, emit a note for the end brace. */ + if (noteType == SRC_LABELBRACE) { + if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 || + js_Emit1(cx, cg, JSOP_NOP) < 0) { + return JS_FALSE; + } + } + break; + + case TOK_COMMA: + /* + * Emit SRC_PCDELTA notes on each JSOP_POP between comma operands. + * These notes help the decompiler bracket the bytecodes generated + * from each sub-expression that follows a comma. + */ + off = noteIndex = -1; + for (pn2 = pn->pn_head; ; pn2 = pn2->pn_next) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + tmp = CG_OFFSET(cg); + if (noteIndex >= 0) { + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off)) + return JS_FALSE; + } + if (!pn2->pn_next) + break; + off = tmp; + noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0); + if (noteIndex < 0 || + js_Emit1(cx, cg, JSOP_POP) < 0) { + return JS_FALSE; + } + } + break; + + case TOK_ASSIGN: + /* + * Check left operand type and generate specialized code for it. + * Specialize to avoid ECMA "reference type" values on the operand + * stack, which impose pervasive runtime "GetValue" costs. + */ + pn2 = pn->pn_left; + atomIndex = (jsatomid) -1; /* quell GCC overwarning */ + switch (PN_TYPE(pn2)) { + case TOK_NAME: + if (!BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + if (!pn2->pn_cookie.isFree()) { + atomIndex = (jsatomid) pn2->pn_cookie.asInteger(); + } else { + ale = cg->atomList.add(cg->parser, pn2->pn_atom); + if (!ale) + return JS_FALSE; + atomIndex = ALE_INDEX(ale); + if (!pn2->isConst()) { + JSOp op = PN_OP(pn2) == JSOP_SETGNAME ? JSOP_BINDGNAME : JSOP_BINDNAME; + EMIT_INDEX_OP(op, atomIndex); + } + } + break; + case TOK_DOT: + if (!js_EmitTree(cx, cg, pn2->expr())) + return JS_FALSE; + ale = cg->atomList.add(cg->parser, pn2->pn_atom); + if (!ale) + return JS_FALSE; + atomIndex = ALE_INDEX(ale); + break; + case TOK_LB: + JS_ASSERT(pn2->pn_arity == PN_BINARY); + if (!js_EmitTree(cx, cg, pn2->pn_left)) + return JS_FALSE; + if (!js_EmitTree(cx, cg, pn2->pn_right)) + return JS_FALSE; + break; +#if JS_HAS_DESTRUCTURING + case TOK_RB: + case TOK_RC: + break; +#endif + case TOK_LP: + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + break; +#if JS_HAS_XML_SUPPORT + case TOK_UNARYOP: + JS_ASSERT(pn2->pn_op == JSOP_SETXMLNAME); + if (!js_EmitTree(cx, cg, pn2->pn_kid)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0) + return JS_FALSE; + break; +#endif + default: + JS_ASSERT(0); + } + + op = PN_OP(pn); + if (op != JSOP_NOP) { + switch (pn2->pn_type) { + case TOK_NAME: + if (pn2->isConst()) { + if (PN_OP(pn2) == JSOP_CALLEE) { + if (js_Emit1(cx, cg, JSOP_CALLEE) < 0) + return JS_FALSE; + } else { + EMIT_INDEX_OP(PN_OP(pn2), atomIndex); + } + } else if (PN_OP(pn2) == JSOP_SETNAME) { + if (js_Emit1(cx, cg, JSOP_DUP) < 0) + return JS_FALSE; + EMIT_INDEX_OP(JSOP_GETXPROP, atomIndex); + } else if (PN_OP(pn2) == JSOP_SETGNAME) { + if (!BindGlobal(cx, cg, pn2, pn2->pn_atom)) + return JS_FALSE; + if (pn2->pn_cookie.isFree()) + EmitAtomOp(cx, pn2, JSOP_GETGNAME, cg); + else + EMIT_UINT16_IMM_OP(JSOP_GETGLOBAL, pn2->pn_cookie.asInteger()); + } else { + EMIT_UINT16_IMM_OP((PN_OP(pn2) == JSOP_SETARG) + ? JSOP_GETARG + : JSOP_GETLOCAL, + atomIndex); + } + break; + case TOK_DOT: + if (js_Emit1(cx, cg, JSOP_DUP) < 0) + return JS_FALSE; + if (pn2->pn_atom == cx->runtime->atomState.lengthAtom) { + if (js_Emit1(cx, cg, JSOP_LENGTH) < 0) + return JS_FALSE; + } else if (pn2->pn_atom == cx->runtime->atomState.protoAtom) { + if (!EmitIndexOp(cx, JSOP_QNAMEPART, atomIndex, cg)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_GETELEM) < 0) + return JS_FALSE; + } else { + EMIT_INDEX_OP(JSOP_GETPROP, atomIndex); + } + break; + case TOK_LB: + case TOK_LP: +#if JS_HAS_XML_SUPPORT + case TOK_UNARYOP: +#endif + if (js_Emit1(cx, cg, JSOP_DUP2) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_GETELEM) < 0) + return JS_FALSE; + break; + default:; + } + } + + /* Now emit the right operand (it may affect the namespace). */ + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + + /* If += etc., emit the binary operator with a decompiler note. */ + if (op != JSOP_NOP) { + /* + * Take care to avoid SRC_ASSIGNOP if the left-hand side is a const + * declared in the current compilation unit, as in this case (just + * a bit further below) we will avoid emitting the assignment op. + */ + if (pn2->pn_type != TOK_NAME || !pn2->isConst()) { + if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0) + return JS_FALSE; + } + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + } + + /* Left parts such as a.b.c and a[b].c need a decompiler note. */ + if (pn2->pn_type != TOK_NAME && +#if JS_HAS_DESTRUCTURING + pn2->pn_type != TOK_RB && + pn2->pn_type != TOK_RC && +#endif + js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) { + return JS_FALSE; + } + + /* Finally, emit the specialized assignment bytecode. */ + switch (pn2->pn_type) { + case TOK_NAME: + if (pn2->isConst()) + break; + /* FALL THROUGH */ + case TOK_DOT: + EMIT_INDEX_OP(PN_OP(pn2), atomIndex); + break; + case TOK_LB: + case TOK_LP: + if (js_Emit1(cx, cg, JSOP_SETELEM) < 0) + return JS_FALSE; + break; +#if JS_HAS_DESTRUCTURING + case TOK_RB: + case TOK_RC: + if (!EmitDestructuringOps(cx, cg, JSOP_SETNAME, pn2)) + return JS_FALSE; + break; +#endif +#if JS_HAS_XML_SUPPORT + case TOK_UNARYOP: + if (js_Emit1(cx, cg, JSOP_SETXMLNAME) < 0) + return JS_FALSE; + break; +#endif + default: + JS_ASSERT(0); + } + break; + + case TOK_HOOK: + /* Emit the condition, then branch if false to the else part. */ + if (!js_EmitTree(cx, cg, pn->pn_kid1)) + return JS_FALSE; + noteIndex = js_NewSrcNote(cx, cg, SRC_COND); + if (noteIndex < 0) + return JS_FALSE; + beq = EmitJump(cx, cg, JSOP_IFEQ, 0); + if (beq < 0 || !js_EmitTree(cx, cg, pn->pn_kid2)) + return JS_FALSE; + + /* Jump around else, fixup the branch, emit else, fixup jump. */ + jmp = EmitJump(cx, cg, JSOP_GOTO, 0); + if (jmp < 0) + return JS_FALSE; + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq); + + /* + * Because each branch pushes a single value, but our stack budgeting + * analysis ignores branches, we now have to adjust cg->stackDepth to + * ignore the value pushed by the first branch. Execution will follow + * only one path, so we must decrement cg->stackDepth. + * + * Failing to do this will foil code, such as the try/catch/finally + * exception handling code generator, that samples cg->stackDepth for + * use at runtime (JSOP_SETSP), or in let expression and block code + * generation, which must use the stack depth to compute local stack + * indexes correctly. + */ + JS_ASSERT(cg->stackDepth > 0); + cg->stackDepth--; + if (!js_EmitTree(cx, cg, pn->pn_kid3)) + return JS_FALSE; + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); + if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq)) + return JS_FALSE; + break; + + case TOK_OR: + case TOK_AND: + /* + * JSOP_OR converts the operand on the stack to boolean, and if true, + * leaves the original operand value on the stack and jumps; otherwise + * it pops and falls into the next bytecode, which evaluates the right + * operand. The jump goes around the right operand evaluation. + * + * JSOP_AND converts the operand on the stack to boolean, and if false, + * leaves the original operand value on the stack and jumps; otherwise + * it pops and falls into the right operand's bytecode. + */ + if (pn->pn_arity == PN_BINARY) { + if (!js_EmitTree(cx, cg, pn->pn_left)) + return JS_FALSE; + top = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0); + if (top < 0) + return JS_FALSE; + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + off = CG_OFFSET(cg); + pc = CG_CODE(cg, top); + CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, off - top); + *pc = pn->pn_op; + } else { + JS_ASSERT(pn->pn_arity == PN_LIST); + JS_ASSERT(pn->pn_head->pn_next->pn_next); + + /* Left-associative operator chain: avoid too much recursion. */ + pn2 = pn->pn_head; + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + top = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0); + if (top < 0) + return JS_FALSE; + + /* Emit nodes between the head and the tail. */ + jmp = top; + while ((pn2 = pn2->pn_next)->pn_next) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + off = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0); + if (off < 0) + return JS_FALSE; + if (!SetBackPatchDelta(cx, cg, CG_CODE(cg, jmp), off - jmp)) + return JS_FALSE; + jmp = off; + + } + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + + pn2 = pn->pn_head; + off = CG_OFFSET(cg); + do { + pc = CG_CODE(cg, top); + tmp = GetJumpOffset(cg, pc); + CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, off - top); + *pc = pn->pn_op; + top += tmp; + } while ((pn2 = pn2->pn_next)->pn_next); + } + break; + + case TOK_PLUS: + case TOK_BITOR: + case TOK_BITXOR: + case TOK_BITAND: + case TOK_EQOP: + case TOK_RELOP: + case TOK_IN: + case TOK_INSTANCEOF: + case TOK_SHOP: + case TOK_MINUS: + case TOK_STAR: + case TOK_DIVOP: + if (pn->pn_arity == PN_LIST) { + /* Left-associative operator chain: avoid too much recursion. */ + pn2 = pn->pn_head; + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + op = PN_OP(pn); + while ((pn2 = pn2->pn_next) != NULL) { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + } + } else { +#if JS_HAS_XML_SUPPORT + uintN oldflags; + + case TOK_DBLCOLON: + if (pn->pn_arity == PN_NAME) { + if (!js_EmitTree(cx, cg, pn->expr())) + return JS_FALSE; + if (!EmitAtomOp(cx, pn, PN_OP(pn), cg)) + return JS_FALSE; + break; + } + + /* + * Binary :: has a right operand that brackets arbitrary code, + * possibly including a let (a = b) ... expression. We must clear + * TCF_IN_FOR_INIT to avoid mis-compiling such beasts. + */ + oldflags = cg->flags; + cg->flags &= ~TCF_IN_FOR_INIT; +#endif + + /* Binary operators that evaluate both operands unconditionally. */ + if (!js_EmitTree(cx, cg, pn->pn_left)) + return JS_FALSE; + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; +#if JS_HAS_XML_SUPPORT + cg->flags |= oldflags & TCF_IN_FOR_INIT; +#endif + if (js_Emit1(cx, cg, PN_OP(pn)) < 0) + return JS_FALSE; + } + break; + + case TOK_THROW: +#if JS_HAS_XML_SUPPORT + case TOK_AT: + case TOK_DEFAULT: + JS_ASSERT(pn->pn_arity == PN_UNARY); + /* FALL THROUGH */ +#endif + case TOK_UNARYOP: + { + uintN oldflags; + + /* Unary op, including unary +/-. */ + op = PN_OP(pn); +#if JS_HAS_XML_SUPPORT + if (op == JSOP_XMLNAME) { + if (!EmitXMLName(cx, pn, op, cg)) + return JS_FALSE; + break; + } +#endif + pn2 = pn->pn_kid; + + if (op == JSOP_TYPEOF && pn2->pn_type != TOK_NAME) + op = JSOP_TYPEOFEXPR; + + oldflags = cg->flags; + cg->flags &= ~TCF_IN_FOR_INIT; + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + cg->flags |= oldflags & TCF_IN_FOR_INIT; + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + break; + } + + case TOK_INC: + case TOK_DEC: + /* Emit lvalue-specialized code for ++/-- operators. */ + pn2 = pn->pn_kid; + JS_ASSERT(pn2->pn_type != TOK_RP); + op = PN_OP(pn); + switch (pn2->pn_type) { + default: + JS_ASSERT(pn2->pn_type == TOK_NAME); + pn2->pn_op = op; + if (!BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + op = PN_OP(pn2); + if (op == JSOP_CALLEE) { + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + } else if (!pn2->pn_cookie.isFree()) { + atomIndex = (jsatomid) pn2->pn_cookie.asInteger(); + EMIT_UINT16_IMM_OP(op, atomIndex); + } else { + JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM); + if (!EmitAtomOp(cx, pn2, op, cg)) + return JS_FALSE; + break; + } + if (pn2->isConst()) { + if (js_Emit1(cx, cg, JSOP_POS) < 0) + return JS_FALSE; + op = PN_OP(pn); + if (!(js_CodeSpec[op].format & JOF_POST)) { + if (js_Emit1(cx, cg, JSOP_ONE) < 0) + return JS_FALSE; + op = (js_CodeSpec[op].format & JOF_INC) ? JSOP_ADD : JSOP_SUB; + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + } + } + break; + case TOK_DOT: + if (!EmitPropOp(cx, pn2, op, cg, JS_FALSE)) + return JS_FALSE; + break; + case TOK_LB: + if (!EmitElemOp(cx, pn2, op, cg)) + return JS_FALSE; + break; + case TOK_LP: + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, + CG_OFFSET(cg) - pn2->pn_offset) < 0) { + return JS_FALSE; + } + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + break; +#if JS_HAS_XML_SUPPORT + case TOK_UNARYOP: + JS_ASSERT(pn2->pn_op == JSOP_SETXMLNAME); + if (!js_EmitTree(cx, cg, pn2->pn_kid)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + break; +#endif + } + break; + + case TOK_DELETE: + /* + * Under ECMA 3, deleting a non-reference returns true -- but alas we + * must evaluate the operand if it appears it might have side effects. + */ + pn2 = pn->pn_kid; + switch (pn2->pn_type) { + case TOK_NAME: + if (!BindNameToSlot(cx, cg, pn2)) + return JS_FALSE; + op = PN_OP(pn2); + if (op == JSOP_FALSE) { + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + } else { + if (!EmitAtomOp(cx, pn2, op, cg)) + return JS_FALSE; + } + break; + case TOK_DOT: + if (!EmitPropOp(cx, pn2, JSOP_DELPROP, cg, JS_FALSE)) + return JS_FALSE; + break; +#if JS_HAS_XML_SUPPORT + case TOK_DBLDOT: + if (!EmitElemOp(cx, pn2, JSOP_DELDESC, cg)) + return JS_FALSE; + break; +#endif + case TOK_LB: + if (!EmitElemOp(cx, pn2, JSOP_DELELEM, cg)) + return JS_FALSE; + break; + default: + /* + * If useless, just emit JSOP_TRUE; otherwise convert delete foo() + * to foo(), true (a comma expression, requiring SRC_PCDELTA). + */ + useful = JS_FALSE; + if (!CheckSideEffects(cx, cg, pn2, &useful)) + return JS_FALSE; + if (!useful) { + off = noteIndex = -1; + } else { + JS_ASSERT_IF(pn2->pn_type == TOK_LP, !(pn2->pn_xflags & PNX_SETCALL)); + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + off = CG_OFFSET(cg); + noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0); + if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_POP) < 0) + return JS_FALSE; + } + if (js_Emit1(cx, cg, JSOP_TRUE) < 0) + return JS_FALSE; + if (noteIndex >= 0) { + tmp = CG_OFFSET(cg); + if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off)) + return JS_FALSE; + } + } + break; + +#if JS_HAS_XML_SUPPORT + case TOK_FILTER: + if (!js_EmitTree(cx, cg, pn->pn_left)) + return JS_FALSE; + jmp = EmitJump(cx, cg, JSOP_FILTER, 0); + if (jmp < 0) + return JS_FALSE; + top = EmitTraceOp(cx, cg); + if (top < 0) + return JS_FALSE; + if (!js_EmitTree(cx, cg, pn->pn_right)) + return JS_FALSE; + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); + if (EmitJump(cx, cg, JSOP_ENDFILTER, top - CG_OFFSET(cg)) < 0) + return JS_FALSE; + + /* Make blockChain determination quicker. */ + if (EmitBlockChain(cx, cg) < 0) + return JS_FALSE; + break; +#endif + + case TOK_DOT: + /* + * Pop a stack operand, convert it to object, get a property named by + * this bytecode's immediate-indexed atom operand, and push its value + * (not a reference to it). + */ + ok = EmitPropOp(cx, pn, PN_OP(pn), cg, JS_FALSE); + break; + + case TOK_LB: +#if JS_HAS_XML_SUPPORT + case TOK_DBLDOT: +#endif + /* + * Pop two operands, convert the left one to object and the right one + * to property name (atom or tagged int), get the named property, and + * push its value. Set the "obj" register to the result of ToObject + * on the left operand. + */ + ok = EmitElemOp(cx, pn, PN_OP(pn), cg); + break; + + case TOK_NEW: + case TOK_LP: + { + bool callop = (PN_TYPE(pn) == TOK_LP); + + /* + * Emit callable invocation or operator new (constructor call) code. + * First, emit code for the left operand to evaluate the callable or + * constructable object expression. + * + * For operator new applied to other expressions than E4X ones, we emit + * JSOP_GETPROP instead of JSOP_CALLPROP, etc. This is necessary to + * interpose the lambda-initialized method read barrier -- see the code + * in jsinterp.cpp for JSOP_LAMBDA followed by JSOP_{SET,INIT}PROP. + * + * Then (or in a call case that has no explicit reference-base + * object) we emit JSOP_PUSH to produce the |this| slot required + * for calls (which non-strict mode functions will box into the + * global object). + */ + pn2 = pn->pn_head; + switch (pn2->pn_type) { + case TOK_NAME: + if (!EmitNameOp(cx, cg, pn2, callop)) + return JS_FALSE; + break; + case TOK_DOT: + if (!EmitPropOp(cx, pn2, PN_OP(pn2), cg, callop)) + return JS_FALSE; + break; + case TOK_LB: + JS_ASSERT(pn2->pn_op == JSOP_GETELEM); + if (!EmitElemOp(cx, pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM, cg)) + return JS_FALSE; + break; + case TOK_UNARYOP: +#if JS_HAS_XML_SUPPORT + if (pn2->pn_op == JSOP_XMLNAME) { + if (!EmitXMLName(cx, pn2, JSOP_CALLXMLNAME, cg)) + return JS_FALSE; + callop = true; /* suppress JSOP_PUSH after */ + break; + } +#endif + /* FALL THROUGH */ + default: + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + callop = false; /* trigger JSOP_PUSH after */ + break; + } + if (!callop && js_Emit1(cx, cg, JSOP_PUSH) < 0) + return JS_FALSE; + + /* Remember start of callable-object bytecode for decompilation hint. */ + off = top; + + /* + * Emit code for each argument in order, then emit the JSOP_*CALL or + * JSOP_NEW bytecode with a two-byte immediate telling how many args + * were pushed on the operand stack. + */ + uintN oldflags = cg->flags; + cg->flags &= ~TCF_IN_FOR_INIT; + for (pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) { + if (!js_EmitTree(cx, cg, pn3)) + return JS_FALSE; + } + cg->flags |= oldflags & TCF_IN_FOR_INIT; + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0) + return JS_FALSE; + + argc = pn->pn_count - 1; + if (js_Emit3(cx, cg, PN_OP(pn), ARGC_HI(argc), ARGC_LO(argc)) < 0) + return JS_FALSE; + if (PN_OP(pn) == JSOP_EVAL) { + EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno); + if (EmitBlockChain(cx, cg) < 0) + return JS_FALSE; + } + if (pn->pn_xflags & PNX_SETCALL) { + if (js_Emit1(cx, cg, JSOP_SETCALL) < 0) + return JS_FALSE; + } + break; + } + + case TOK_LEXICALSCOPE: + { + JSObjectBox *objbox; + + objbox = pn->pn_objbox; + js_PushBlockScope(cg, &stmtInfo, objbox, CG_OFFSET(cg)); + + /* + * If this lexical scope is not for a catch block, let block or let + * expression, or any kind of for loop (where the scope starts in the + * head after the first part if for (;;), else in the body if for-in); + * and if our container is top-level but not a function body, or else + * a block statement; then emit a SRC_BRACE note. All other container + * statements get braces by default from the decompiler. + */ + noteIndex = -1; + type = PN_TYPE(pn->expr()); + if (type != TOK_CATCH && type != TOK_LET && type != TOK_FOR && + (!(stmt = stmtInfo.down) + ? !cg->inFunction() + : stmt->type == STMT_BLOCK)) { +#if defined DEBUG_brendan || defined DEBUG_mrbkap + /* There must be no source note already output for the next op. */ + JS_ASSERT(CG_NOTE_COUNT(cg) == 0 || + CG_LAST_NOTE_OFFSET(cg) != CG_OFFSET(cg) || + !GettableNoteForNextOp(cg)); +#endif + noteIndex = js_NewSrcNote2(cx, cg, SRC_BRACE, 0); + if (noteIndex < 0) + return JS_FALSE; + } + + JS_ASSERT(CG_OFFSET(cg) == top); + if (!EmitEnterBlock(cx, pn, cg)) + return JS_FALSE; + + if (!js_EmitTree(cx, cg, pn->pn_expr)) + return JS_FALSE; + + op = PN_OP(pn); + if (op == JSOP_LEAVEBLOCKEXPR) { + if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) + return JS_FALSE; + } else { + if (noteIndex >= 0 && + !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, + CG_OFFSET(cg) - top)) { + return JS_FALSE; + } + } + + /* Emit the JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR opcode. */ + if (!EmitLeaveBlock(cx, cg, op, objbox)) + return JS_FALSE; + + ok = js_PopStatementCG(cx, cg); + break; + } + +#if JS_HAS_BLOCK_SCOPE + case TOK_LET: + /* Let statements have their variable declarations on the left. */ + if (pn->pn_arity == PN_BINARY) { + pn2 = pn->pn_right; + pn = pn->pn_left; + } else { + pn2 = NULL; + } + + /* Non-null pn2 means that pn is the variable list from a let head. */ + JS_ASSERT(pn->pn_arity == PN_LIST); + if (!EmitVariables(cx, cg, pn, pn2 != NULL, ¬eIndex)) + return JS_FALSE; + + /* Thus non-null pn2 is the body of the let block or expression. */ + tmp = CG_OFFSET(cg); + if (pn2 && !js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + + if (noteIndex >= 0 && + !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, + CG_OFFSET(cg) - tmp)) { + return JS_FALSE; + } + break; +#endif /* JS_HAS_BLOCK_SCOPE */ + +#if JS_HAS_GENERATORS + case TOK_ARRAYPUSH: { + jsint slot; + + /* + * The array object's stack index is in cg->arrayCompDepth. See below + * under the array initialiser code generator for array comprehension + * special casing. + */ + if (!js_EmitTree(cx, cg, pn->pn_kid)) + return JS_FALSE; + slot = AdjustBlockSlot(cx, cg, cg->arrayCompDepth); + if (slot < 0) + return JS_FALSE; + EMIT_UINT16_IMM_OP(PN_OP(pn), slot); + break; + } +#endif + + case TOK_RB: +#if JS_HAS_GENERATORS + case TOK_ARRAYCOMP: +#endif + /* + * Emit code for [a, b, c] that is equivalent to constructing a new + * array and in source order evaluating each element value and adding + * it to the array, without invoking latent setters. We use the + * JSOP_NEWINIT and JSOP_INITELEM bytecodes to ignore setters and to + * avoid dup'ing and popping the array as each element is added, as + * JSOP_SETELEM/JSOP_SETPROP would do. + */ +#if JS_HAS_SHARP_VARS + sharpnum = -1; + do_emit_array: +#endif + +#if JS_HAS_GENERATORS + if (pn->pn_type == TOK_ARRAYCOMP) { + uintN saveDepth; + + if (!EmitNewInit(cx, cg, JSProto_Array, pn, sharpnum)) + return JS_FALSE; + + /* + * Pass the new array's stack index to the TOK_ARRAYPUSH case via + * cg->arrayCompDepth, then simply traverse the TOK_FOR node and + * its kids under pn2 to generate this comprehension. + */ + JS_ASSERT(cg->stackDepth > 0); + saveDepth = cg->arrayCompDepth; + cg->arrayCompDepth = (uint32) (cg->stackDepth - 1); + if (!js_EmitTree(cx, cg, pn->pn_head)) + return JS_FALSE; + cg->arrayCompDepth = saveDepth; + + /* Emit the usual op needed for decompilation. */ + if (!EmitEndInit(cx, cg, 1)) + return JS_FALSE; + break; + } +#endif /* JS_HAS_GENERATORS */ + + if (!cg->hasSharps() && !(pn->pn_xflags & PNX_NONCONST) && cg->checkSingletonContext()) { + if (!EmitSingletonInitialiser(cx, cg, pn)) + return JS_FALSE; + break; + } + + /* Use the slower NEWINIT for arrays in scripts containing sharps. */ + if (cg->hasSharps()) { + if (!EmitNewInit(cx, cg, JSProto_Array, pn, sharpnum)) + return JS_FALSE; + } else { + ptrdiff_t off = js_EmitN(cx, cg, JSOP_NEWARRAY, 3); + if (off < 0) + return JS_FALSE; + pc = CG_CODE(cg, off); + SET_UINT24(pc, pn->pn_count); + } + + pn2 = pn->pn_head; + for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) { + if (!EmitNumberOp(cx, atomIndex, cg)) + return JS_FALSE; + if (pn2->pn_type == TOK_COMMA && pn2->pn_arity == PN_NULLARY) { + if (js_Emit1(cx, cg, JSOP_HOLE) < 0) + return JS_FALSE; + } else { + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + } + if (js_Emit1(cx, cg, JSOP_INITELEM) < 0) + return JS_FALSE; + } + JS_ASSERT(atomIndex == pn->pn_count); + + if (pn->pn_xflags & PNX_ENDCOMMA) { + /* Emit a source note so we know to decompile an extra comma. */ + if (js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0) + return JS_FALSE; + } + + /* + * Emit an op to finish the array and, secondarily, to aid in sharp + * array cleanup (if JS_HAS_SHARP_VARS) and decompilation. + */ + if (!EmitEndInit(cx, cg, atomIndex)) + return JS_FALSE; + break; + + case TOK_RC: { +#if JS_HAS_SHARP_VARS + sharpnum = -1; + do_emit_object: +#endif +#if JS_HAS_DESTRUCTURING_SHORTHAND + if (pn->pn_xflags & PNX_DESTRUCT) { + ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, JSMSG_BAD_OBJECT_INIT); + return JS_FALSE; + } +#endif + + if (!cg->hasSharps() && !(pn->pn_xflags & PNX_NONCONST) && cg->checkSingletonContext()) { + if (!EmitSingletonInitialiser(cx, cg, pn)) + return JS_FALSE; + break; + } + + /* + * Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing + * a new object and in source order evaluating each property value and + * adding the property to the object, without invoking latent setters. + * We use the JSOP_NEWINIT and JSOP_INITELEM/JSOP_INITPROP bytecodes to + * ignore setters and to avoid dup'ing and popping the object as each + * property is added, as JSOP_SETELEM/JSOP_SETPROP would do. + */ + ptrdiff_t offset = CG_NEXT(cg) - CG_BASE(cg); + if (!EmitNewInit(cx, cg, JSProto_Object, pn, sharpnum)) + return JS_FALSE; + + /* + * Try to construct the shape of the object as we go, so we can emit a + * JSOP_NEWOBJECT with the final shape instead. + */ + JSObject *obj = NULL; + if (!cg->hasSharps() && cg->compileAndGo()) { + gc::FinalizeKind kind = GuessObjectGCKind(pn->pn_count, false); + obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind); + if (!obj) + return JS_FALSE; + } + + uintN methodInits = 0, slowMethodInits = 0; + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */ + pn3 = pn2->pn_left; + if (pn3->pn_type == TOK_NUMBER) { + if (!EmitNumberOp(cx, pn3->pn_dval, cg)) + return JS_FALSE; + } + + /* Emit code for the property initializer. */ + if (!js_EmitTree(cx, cg, pn2->pn_right)) + return JS_FALSE; + + op = PN_OP(pn2); + if (op == JSOP_GETTER || op == JSOP_SETTER) { + obj = NULL; + if (js_Emit1(cx, cg, op) < 0) + return JS_FALSE; + } + + /* Annotate JSOP_INITELEM so we decompile 2:c and not just c. */ + if (pn3->pn_type == TOK_NUMBER) { + obj = NULL; + if (js_NewSrcNote(cx, cg, SRC_INITPROP) < 0) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_INITELEM) < 0) + return JS_FALSE; + } else { + JS_ASSERT(pn3->pn_type == TOK_NAME || + pn3->pn_type == TOK_STRING); + ale = cg->atomList.add(cg->parser, pn3->pn_atom); + if (!ale) + return JS_FALSE; + + /* Check whether we can optimize to JSOP_INITMETHOD. */ + JSParseNode *init = pn2->pn_right; + bool lambda = PN_OP(init) == JSOP_LAMBDA; + if (lambda) + ++methodInits; + if (op == JSOP_INITPROP && lambda && init->pn_funbox->joinable()) { + obj = NULL; + op = JSOP_INITMETHOD; + pn2->pn_op = uint8(op); + } else { + /* + * Disable NEWOBJECT on initializers that set __proto__, which has + * a non-standard setter on objects. + */ + if (pn3->pn_atom == cx->runtime->atomState.protoAtom) + obj = NULL; + op = JSOP_INITPROP; + if (lambda) + ++slowMethodInits; + } + + if (obj) { + JS_ASSERT(!obj->inDictionaryMode()); + if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(pn3->pn_atom), + UndefinedValue(), NULL, NULL, + JSPROP_ENUMERATE, 0, 0, NULL)) { + return JS_FALSE; + } + if (obj->inDictionaryMode()) + obj = NULL; + } + + EMIT_INDEX_OP(op, ALE_INDEX(ale)); + } + } + + if (cg->funbox && cg->funbox->shouldUnbrand(methodInits, slowMethodInits)) { + obj = NULL; + if (js_Emit1(cx, cg, JSOP_UNBRAND) < 0) + return JS_FALSE; + } + if (!EmitEndInit(cx, cg, pn->pn_count)) + return JS_FALSE; + + if (obj) { + /* + * The object survived and has a predictable shape. Update the original bytecode, + * as long as we can do so without using a big index prefix/suffix. + */ + JSObjectBox *objbox = cg->parser->newObjectBox(obj); + if (!objbox) + return JS_FALSE; + unsigned index = cg->objectList.index(objbox); + if (FitsWithoutBigIndex(index)) + EMIT_UINT16_IN_PLACE(offset, JSOP_NEWOBJECT, uint16(index)); + } + + break; + } + +#if JS_HAS_SHARP_VARS + case TOK_DEFSHARP: + JS_ASSERT(cg->hasSharps()); + sharpnum = pn->pn_num; + pn = pn->pn_kid; + if (pn->pn_type == TOK_RB) + goto do_emit_array; +# if JS_HAS_GENERATORS + if (pn->pn_type == TOK_ARRAYCOMP) + goto do_emit_array; +# endif + if (pn->pn_type == TOK_RC) + goto do_emit_object; + + if (!js_EmitTree(cx, cg, pn)) + return JS_FALSE; + EMIT_UINT16PAIR_IMM_OP(JSOP_DEFSHARP, cg->sharpSlotBase, (jsatomid) sharpnum); + break; + + case TOK_USESHARP: + JS_ASSERT(cg->hasSharps()); + EMIT_UINT16PAIR_IMM_OP(JSOP_USESHARP, cg->sharpSlotBase, (jsatomid) pn->pn_num); + break; +#endif /* JS_HAS_SHARP_VARS */ + + case TOK_NAME: + /* + * Cope with a left-over function definition that was replaced by a use + * of a later function definition of the same name. See FunctionDef and + * MakeDefIntoUse in jsparse.cpp. + */ + if (pn->pn_op == JSOP_NOP) + break; + if (!EmitNameOp(cx, cg, pn, JS_FALSE)) + return JS_FALSE; + break; + +#if JS_HAS_XML_SUPPORT + case TOK_XMLATTR: + case TOK_XMLSPACE: + case TOK_XMLTEXT: + case TOK_XMLCDATA: + case TOK_XMLCOMMENT: +#endif + case TOK_STRING: + ok = EmitAtomOp(cx, pn, PN_OP(pn), cg); + break; + + case TOK_NUMBER: + ok = EmitNumberOp(cx, pn->pn_dval, cg); + break; + + case TOK_REGEXP: { + JS_ASSERT(pn->pn_op == JSOP_REGEXP); + ok = EmitIndexOp(cx, JSOP_REGEXP, + cg->regexpList.index(pn->pn_objbox), + cg); + break; + } + +#if JS_HAS_XML_SUPPORT + case TOK_ANYNAME: +#endif + case TOK_PRIMARY: + if (js_Emit1(cx, cg, PN_OP(pn)) < 0) + return JS_FALSE; + break; + + case TOK_DEBUGGER: + if (js_Emit1(cx, cg, JSOP_DEBUGGER) < 0) + return JS_FALSE; + break; + +#if JS_HAS_XML_SUPPORT + case TOK_XMLELEM: + case TOK_XMLLIST: + JS_ASSERT(PN_TYPE(pn) == TOK_XMLLIST || pn->pn_count != 0); + switch (pn->pn_head ? PN_TYPE(pn->pn_head) : TOK_XMLLIST) { + case TOK_XMLETAGO: + JS_ASSERT(0); + /* FALL THROUGH */ + case TOK_XMLPTAGC: + case TOK_XMLSTAGO: + break; + default: + if (js_Emit1(cx, cg, JSOP_STARTXML) < 0) + return JS_FALSE; + } + + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + if (pn2->pn_type == TOK_LC && + js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) { + return JS_FALSE; + } + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0) + return JS_FALSE; + } + + if (pn->pn_xflags & PNX_XMLROOT) { + if (pn->pn_count == 0) { + JS_ASSERT(pn->pn_type == TOK_XMLLIST); + atom = cx->runtime->atomState.emptyAtom; + ale = cg->atomList.add(cg->parser, atom); + if (!ale) + return JS_FALSE; + EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale)); + } + if (js_Emit1(cx, cg, PN_OP(pn)) < 0) + return JS_FALSE; + } +#ifdef DEBUG + else + JS_ASSERT(pn->pn_count != 0); +#endif + break; + + case TOK_XMLPTAGC: + case TOK_XMLSTAGO: + case TOK_XMLETAGO: + { + uint32 i; + + if (js_Emit1(cx, cg, JSOP_STARTXML) < 0) + return JS_FALSE; + + ale = cg->atomList.add(cg->parser, + (pn->pn_type == TOK_XMLETAGO) + ? cx->runtime->atomState.etagoAtom + : cx->runtime->atomState.stagoAtom); + if (!ale) + return JS_FALSE; + EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale)); + + JS_ASSERT(pn->pn_count != 0); + pn2 = pn->pn_head; + if (pn2->pn_type == TOK_LC && js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) + return JS_FALSE; + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (js_Emit1(cx, cg, JSOP_ADD) < 0) + return JS_FALSE; + + for (pn2 = pn2->pn_next, i = 0; pn2; pn2 = pn2->pn_next, i++) { + if (pn2->pn_type == TOK_LC && + js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) { + return JS_FALSE; + } + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if ((i & 1) && pn2->pn_type == TOK_LC) { + if (js_Emit1(cx, cg, JSOP_TOATTRVAL) < 0) + return JS_FALSE; + } + if (js_Emit1(cx, cg, + (i & 1) ? JSOP_ADDATTRVAL : JSOP_ADDATTRNAME) < 0) { + return JS_FALSE; + } + } + + ale = cg->atomList.add(cg->parser, + (pn->pn_type == TOK_XMLPTAGC) + ? cx->runtime->atomState.ptagcAtom + : cx->runtime->atomState.tagcAtom); + if (!ale) + return JS_FALSE; + EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale)); + if (js_Emit1(cx, cg, JSOP_ADD) < 0) + return JS_FALSE; + + if ((pn->pn_xflags & PNX_XMLROOT) && js_Emit1(cx, cg, PN_OP(pn)) < 0) + return JS_FALSE; + break; + } + + case TOK_XMLNAME: + if (pn->pn_arity == PN_LIST) { + JS_ASSERT(pn->pn_count != 0); + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + if (pn2->pn_type == TOK_LC && + js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) { + return JS_FALSE; + } + if (!js_EmitTree(cx, cg, pn2)) + return JS_FALSE; + if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0) + return JS_FALSE; + } + } else { + JS_ASSERT(pn->pn_arity == PN_NULLARY); + ok = (pn->pn_op == JSOP_OBJECT) + ? EmitObjectOp(cx, pn->pn_objbox, PN_OP(pn), cg) + : EmitAtomOp(cx, pn, PN_OP(pn), cg); + } + break; + + case TOK_XMLPI: + ale = cg->atomList.add(cg->parser, pn->pn_atom2); + if (!ale) + return JS_FALSE; + if (!EmitIndexOp(cx, JSOP_QNAMEPART, ALE_INDEX(ale), cg)) + return JS_FALSE; + if (!EmitAtomOp(cx, pn, JSOP_XMLPI, cg)) + return JS_FALSE; + break; +#endif /* JS_HAS_XML_SUPPORT */ + + default: + JS_ASSERT(0); + } + + /* cg->emitLevel == 1 means we're last on the stack, so finish up. */ + if (ok && cg->emitLevel == 1) { + if (cg->spanDeps) + ok = OptimizeSpanDeps(cx, cg); + if (!UpdateLineNumberNotes(cx, cg, pn->pn_pos.end.lineno)) + return JS_FALSE; + } + + return ok; +} + +/* + * We should try to get rid of offsetBias (always 0 or 1, where 1 is + * JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR and SRC_DECL. + */ +JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = { + {"null", 0, 0, 0}, + {"if", 0, 0, 0}, + {"if-else", 2, 0, 1}, + {"for", 3, 1, 1}, + {"while", 1, 0, 1}, + {"continue", 0, 0, 0}, + {"decl", 1, 1, 1}, + {"pcdelta", 1, 0, 1}, + {"assignop", 0, 0, 0}, + {"cond", 1, 0, 1}, + {"brace", 1, 0, 1}, + {"hidden", 0, 0, 0}, + {"pcbase", 1, 0, -1}, + {"label", 1, 0, 0}, + {"labelbrace", 1, 0, 0}, + {"endbrace", 0, 0, 0}, + {"break2label", 1, 0, 0}, + {"cont2label", 1, 0, 0}, + {"switch", 2, 0, 1}, + {"funcdef", 1, 0, 0}, + {"catch", 1, 0, 1}, + {"extended", -1, 0, 0}, + {"newline", 0, 0, 0}, + {"setline", 1, 0, 0}, + {"xdelta", 0, 0, 0}, +}; + +static intN +AllocSrcNote(JSContext *cx, JSCodeGenerator *cg) +{ + intN index; + JSArenaPool *pool; + size_t size; + + index = CG_NOTE_COUNT(cg); + if (((uintN)index & CG_NOTE_MASK(cg)) == 0) { + pool = cg->notePool; + size = SRCNOTE_SIZE(CG_NOTE_MASK(cg) + 1); + if (!CG_NOTES(cg)) { + /* Allocate the first note array lazily; leave noteMask alone. */ + JS_ARENA_ALLOCATE_CAST(CG_NOTES(cg), jssrcnote *, pool, size); + } else { + /* Grow by doubling note array size; update noteMask on success. */ + JS_ARENA_GROW_CAST(CG_NOTES(cg), jssrcnote *, pool, size, size); + if (CG_NOTES(cg)) + CG_NOTE_MASK(cg) = (CG_NOTE_MASK(cg) << 1) | 1; + } + if (!CG_NOTES(cg)) { + js_ReportOutOfScriptQuota(cx); + return -1; + } + } + + CG_NOTE_COUNT(cg) = index + 1; + return index; +} + +intN +js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type) +{ + intN index, n; + jssrcnote *sn; + ptrdiff_t offset, delta, xdelta; + + /* + * Claim a note slot in CG_NOTES(cg) by growing it if necessary and then + * incrementing CG_NOTE_COUNT(cg). + */ + index = AllocSrcNote(cx, cg); + if (index < 0) + return -1; + sn = &CG_NOTES(cg)[index]; + + /* + * Compute delta from the last annotated bytecode's offset. If it's too + * big to fit in sn, allocate one or more xdelta notes and reset sn. + */ + offset = CG_OFFSET(cg); + delta = offset - CG_LAST_NOTE_OFFSET(cg); + CG_LAST_NOTE_OFFSET(cg) = offset; + if (delta >= SN_DELTA_LIMIT) { + do { + xdelta = JS_MIN(delta, SN_XDELTA_MASK); + SN_MAKE_XDELTA(sn, xdelta); + delta -= xdelta; + index = AllocSrcNote(cx, cg); + if (index < 0) + return -1; + sn = &CG_NOTES(cg)[index]; + } while (delta >= SN_DELTA_LIMIT); + } + + /* + * Initialize type and delta, then allocate the minimum number of notes + * needed for type's arity. Usually, we won't need more, but if an offset + * does take two bytes, js_SetSrcNoteOffset will grow CG_NOTES(cg). + */ + SN_MAKE_NOTE(sn, type, delta); + for (n = (intN)js_SrcNoteSpec[type].arity; n > 0; n--) { + if (js_NewSrcNote(cx, cg, SRC_NULL) < 0) + return -1; + } + return index; +} + +intN +js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, + ptrdiff_t offset) +{ + intN index; + + index = js_NewSrcNote(cx, cg, type); + if (index >= 0) { + if (!js_SetSrcNoteOffset(cx, cg, index, 0, offset)) + return -1; + } + return index; +} + +intN +js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, + ptrdiff_t offset1, ptrdiff_t offset2) +{ + intN index; + + index = js_NewSrcNote(cx, cg, type); + if (index >= 0) { + if (!js_SetSrcNoteOffset(cx, cg, index, 0, offset1)) + return -1; + if (!js_SetSrcNoteOffset(cx, cg, index, 1, offset2)) + return -1; + } + return index; +} + +static JSBool +GrowSrcNotes(JSContext *cx, JSCodeGenerator *cg) +{ + JSArenaPool *pool; + size_t size; + + /* Grow by doubling note array size; update noteMask on success. */ + pool = cg->notePool; + size = SRCNOTE_SIZE(CG_NOTE_MASK(cg) + 1); + JS_ARENA_GROW_CAST(CG_NOTES(cg), jssrcnote *, pool, size, size); + if (!CG_NOTES(cg)) { + js_ReportOutOfScriptQuota(cx); + return JS_FALSE; + } + CG_NOTE_MASK(cg) = (CG_NOTE_MASK(cg) << 1) | 1; + return JS_TRUE; +} + +jssrcnote * +js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn, + ptrdiff_t delta) +{ + ptrdiff_t base, limit, newdelta, diff; + intN index; + + /* + * Called only from OptimizeSpanDeps and js_FinishTakingSrcNotes to add to + * main script note deltas, and only by a small positive amount. + */ + JS_ASSERT(cg->current == &cg->main); + JS_ASSERT((unsigned) delta < (unsigned) SN_XDELTA_LIMIT); + + base = SN_DELTA(sn); + limit = SN_IS_XDELTA(sn) ? SN_XDELTA_LIMIT : SN_DELTA_LIMIT; + newdelta = base + delta; + if (newdelta < limit) { + SN_SET_DELTA(sn, newdelta); + } else { + index = sn - cg->main.notes; + if ((cg->main.noteCount & cg->main.noteMask) == 0) { + if (!GrowSrcNotes(cx, cg)) + return NULL; + sn = cg->main.notes + index; + } + diff = cg->main.noteCount - index; + cg->main.noteCount++; + memmove(sn + 1, sn, SRCNOTE_SIZE(diff)); + SN_MAKE_XDELTA(sn, delta); + sn++; + } + return sn; +} + +JS_FRIEND_API(uintN) +js_SrcNoteLength(jssrcnote *sn) +{ + uintN arity; + jssrcnote *base; + + arity = (intN)js_SrcNoteSpec[SN_TYPE(sn)].arity; + for (base = sn++; arity; sn++, arity--) { + if (*sn & SN_3BYTE_OFFSET_FLAG) + sn += 2; + } + return sn - base; +} + +JS_FRIEND_API(ptrdiff_t) +js_GetSrcNoteOffset(jssrcnote *sn, uintN which) +{ + /* Find the offset numbered which (i.e., skip exactly which offsets). */ + JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA); + JS_ASSERT((intN) which < js_SrcNoteSpec[SN_TYPE(sn)].arity); + for (sn++; which; sn++, which--) { + if (*sn & SN_3BYTE_OFFSET_FLAG) + sn += 2; + } + if (*sn & SN_3BYTE_OFFSET_FLAG) { + return (ptrdiff_t)(((uint32)(sn[0] & SN_3BYTE_OFFSET_MASK) << 16) + | (sn[1] << 8) + | sn[2]); + } + return (ptrdiff_t)*sn; +} + +JSBool +js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index, + uintN which, ptrdiff_t offset) +{ + jssrcnote *sn; + ptrdiff_t diff; + + if ((jsuword)offset >= (jsuword)((ptrdiff_t)SN_3BYTE_OFFSET_FLAG << 16)) { + ReportStatementTooLarge(cx, cg); + return JS_FALSE; + } + + /* Find the offset numbered which (i.e., skip exactly which offsets). */ + sn = &CG_NOTES(cg)[index]; + JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA); + JS_ASSERT((intN) which < js_SrcNoteSpec[SN_TYPE(sn)].arity); + for (sn++; which; sn++, which--) { + if (*sn & SN_3BYTE_OFFSET_FLAG) + sn += 2; + } + + /* See if the new offset requires three bytes. */ + if (offset > (ptrdiff_t)SN_3BYTE_OFFSET_MASK) { + /* Maybe this offset was already set to a three-byte value. */ + if (!(*sn & SN_3BYTE_OFFSET_FLAG)) { + /* Losing, need to insert another two bytes for this offset. */ + index = sn - CG_NOTES(cg); + + /* + * Simultaneously test to see if the source note array must grow to + * accommodate either the first or second byte of additional storage + * required by this 3-byte offset. + */ + if (((CG_NOTE_COUNT(cg) + 1) & CG_NOTE_MASK(cg)) <= 1) { + if (!GrowSrcNotes(cx, cg)) + return JS_FALSE; + sn = CG_NOTES(cg) + index; + } + CG_NOTE_COUNT(cg) += 2; + + diff = CG_NOTE_COUNT(cg) - (index + 3); + JS_ASSERT(diff >= 0); + if (diff > 0) + memmove(sn + 3, sn + 1, SRCNOTE_SIZE(diff)); + } + *sn++ = (jssrcnote)(SN_3BYTE_OFFSET_FLAG | (offset >> 16)); + *sn++ = (jssrcnote)(offset >> 8); + } + *sn = (jssrcnote)offset; + return JS_TRUE; +} + +#ifdef DEBUG_notme +#define DEBUG_srcnotesize +#endif + +#ifdef DEBUG_srcnotesize +#define NBINS 10 +static uint32 hist[NBINS]; + +void DumpSrcNoteSizeHist() +{ + static FILE *fp; + int i, n; + + if (!fp) { + fp = fopen("/tmp/srcnotes.hist", "w"); + if (!fp) + return; + setvbuf(fp, NULL, _IONBF, 0); + } + fprintf(fp, "SrcNote size histogram:\n"); + for (i = 0; i < NBINS; i++) { + fprintf(fp, "%4u %4u ", JS_BIT(i), hist[i]); + for (n = (int) JS_HOWMANY(hist[i], 10); n > 0; --n) + fputc('*', fp); + fputc('\n', fp); + } + fputc('\n', fp); +} +#endif + +/* + * Fill in the storage at notes with prolog and main srcnotes; the space at + * notes was allocated using the CG_COUNT_FINAL_SRCNOTES macro from jsemit.h. + * SO DON'T CHANGE THIS FUNCTION WITHOUT AT LEAST CHECKING WHETHER jsemit.h's + * CG_COUNT_FINAL_SRCNOTES MACRO NEEDS CORRESPONDING CHANGES! + */ +JSBool +js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes) +{ + uintN prologCount, mainCount, totalCount; + ptrdiff_t offset, delta; + jssrcnote *sn; + + JS_ASSERT(cg->current == &cg->main); + + prologCount = cg->prolog.noteCount; + if (prologCount && cg->prolog.currentLine != cg->firstLine) { + CG_SWITCH_TO_PROLOG(cg); + if (js_NewSrcNote2(cx, cg, SRC_SETLINE, (ptrdiff_t)cg->firstLine) < 0) + return JS_FALSE; + prologCount = cg->prolog.noteCount; + CG_SWITCH_TO_MAIN(cg); + } else { + /* + * Either no prolog srcnotes, or no line number change over prolog. + * We don't need a SRC_SETLINE, but we may need to adjust the offset + * of the first main note, by adding to its delta and possibly even + * prepending SRC_XDELTA notes to it to account for prolog bytecodes + * that came at and after the last annotated bytecode. + */ + offset = CG_PROLOG_OFFSET(cg) - cg->prolog.lastNoteOffset; + JS_ASSERT(offset >= 0); + if (offset > 0 && cg->main.noteCount != 0) { + /* NB: Use as much of the first main note's delta as we can. */ + sn = cg->main.notes; + delta = SN_IS_XDELTA(sn) + ? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK) + : SN_DELTA_MASK - (*sn & SN_DELTA_MASK); + if (offset < delta) + delta = offset; + for (;;) { + if (!js_AddToSrcNoteDelta(cx, cg, sn, delta)) + return JS_FALSE; + offset -= delta; + if (offset == 0) + break; + delta = JS_MIN(offset, SN_XDELTA_MASK); + sn = cg->main.notes; + } + } + } + + mainCount = cg->main.noteCount; + totalCount = prologCount + mainCount; + if (prologCount) + memcpy(notes, cg->prolog.notes, SRCNOTE_SIZE(prologCount)); + memcpy(notes + prologCount, cg->main.notes, SRCNOTE_SIZE(mainCount)); + SN_MAKE_TERMINATOR(¬es[totalCount]); + +#ifdef DEBUG_notme + { int bin = JS_CeilingLog2(totalCount); + if (bin >= NBINS) + bin = NBINS - 1; + ++hist[bin]; + } +#endif + return JS_TRUE; +} + +static JSBool +NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind, + uintN stackDepth, size_t start, size_t end) +{ + JSTryNode *tryNode; + + JS_ASSERT((uintN)(uint16)stackDepth == stackDepth); + JS_ASSERT(start <= end); + JS_ASSERT((size_t)(uint32)start == start); + JS_ASSERT((size_t)(uint32)end == end); + + JS_ARENA_ALLOCATE_TYPE(tryNode, JSTryNode, &cx->tempPool); + if (!tryNode) { + js_ReportOutOfScriptQuota(cx); + return JS_FALSE; + } + + tryNode->note.kind = kind; + tryNode->note.stackDepth = (uint16)stackDepth; + tryNode->note.start = (uint32)start; + tryNode->note.length = (uint32)(end - start); + tryNode->prev = cg->lastTryNode; + cg->lastTryNode = tryNode; + cg->ntrynotes++; + return JS_TRUE; +} + +void +js_FinishTakingTryNotes(JSCodeGenerator *cg, JSTryNoteArray *array) +{ + JSTryNode *tryNode; + JSTryNote *tn; + + JS_ASSERT(array->length > 0 && array->length == cg->ntrynotes); + tn = array->vector + array->length; + tryNode = cg->lastTryNode; + do { + *--tn = tryNode->note; + } while ((tryNode = tryNode->prev) != NULL); + JS_ASSERT(tn == array->vector); +} + +/* + * Find the index of the given object for code generator. + * + * Since the emitter refers to each parsed object only once, for the index we + * use the number of already indexes objects. We also add the object to a list + * to convert the list to a fixed-size array when we complete code generation, + * see JSCGObjectList::finish below. + * + * Most of the objects go to JSCodeGenerator.objectList but for regexp we use a + * separated JSCodeGenerator.regexpList. In this way the emitted index can be + * directly used to store and fetch a reference to a cloned RegExp object that + * shares the same JSRegExp private data created for the object literal in + * objbox. We need a cloned object to hold lastIndex and other direct properties + * that should not be shared among threads sharing a precompiled function or + * script. + * + * If the code being compiled is function code, allocate a reserved slot in + * the cloned function object that shares its precompiled script with other + * cloned function objects and with the compiler-created clone-parent. There + * are nregexps = script->regexps()->length such reserved slots in each + * function object cloned from fun->object. NB: during compilation, a funobj + * slots element must never be allocated, because JSObject::allocSlot could + * hand out one of the slots that should be given to a regexp clone. + * + * If the code being compiled is global code, the cloned regexp are stored in + * fp->vars slot and to protect regexp slots from GC we set fp->nvars to + * nregexps. + * + * The slots initially contain undefined or null. We populate them lazily when + * JSOP_REGEXP is executed for the first time. + * + * Why clone regexp objects? ECMA specifies that when a regular expression + * literal is scanned, a RegExp object is created. In the spec, compilation + * and execution happen indivisibly, but in this implementation and many of + * its embeddings, code is precompiled early and re-executed in multiple + * threads, or using multiple global objects, or both, for efficiency. + * + * In such cases, naively following ECMA leads to wrongful sharing of RegExp + * objects, which makes for collisions on the lastIndex property (especially + * for global regexps) and on any ad-hoc properties. Also, __proto__ refers to + * the pre-compilation prototype, a pigeon-hole problem for instanceof tests. + */ +uintN +JSCGObjectList::index(JSObjectBox *objbox) +{ + JS_ASSERT(!objbox->emitLink); + objbox->emitLink = lastbox; + lastbox = objbox; + objbox->index = length++; + return objbox->index; +} + +void +JSCGObjectList::finish(JSObjectArray *array) +{ + JSObject **cursor; + JSObjectBox *objbox; + + JS_ASSERT(length <= INDEX_LIMIT); + JS_ASSERT(length == array->length); + + cursor = array->vector + array->length; + objbox = lastbox; + do { + --cursor; + JS_ASSERT(!*cursor); + *cursor = objbox->object; + } while ((objbox = objbox->emitLink) != NULL); + JS_ASSERT(cursor == array->vector); +} + +void +JSGCConstList::finish(JSConstArray *array) +{ + JS_ASSERT(array->length == list.length()); + Value *src = list.begin(), *srcend = list.end(); + Value *dst = array->vector; + for (; src != srcend; ++src, ++dst) + *dst = *src; +} diff --git a/js/src/jsemit.h b/js/src/jsemit.h new file mode 100644 index 0000000..7d7ca67 --- /dev/null +++ b/js/src/jsemit.h @@ -0,0 +1,1071 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsemit_h___ +#define jsemit_h___ +/* + * JS bytecode generation. + */ +#include "jstypes.h" +#include "jsatom.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsscript.h" +#include "jsprvtd.h" +#include "jspubtd.h" + +JS_BEGIN_EXTERN_C + +/* + * NB: If you add enumerators for scope statements, add them between STMT_WITH + * and STMT_CATCH, or you will break the STMT_TYPE_IS_SCOPE macro. If you add + * non-looping statement enumerators, add them before STMT_DO_LOOP or you will + * break the STMT_TYPE_IS_LOOP macro. + * + * Also remember to keep the statementName array in jsemit.c in sync. + */ +typedef enum JSStmtType { + STMT_LABEL, /* labeled statement: L: s */ + STMT_IF, /* if (then) statement */ + STMT_ELSE, /* else clause of if statement */ + STMT_SEQ, /* synthetic sequence of statements */ + STMT_BLOCK, /* compound statement: { s1[;... sN] } */ + STMT_SWITCH, /* switch statement */ + STMT_WITH, /* with statement */ + STMT_CATCH, /* catch block */ + STMT_TRY, /* try block */ + STMT_FINALLY, /* finally block */ + STMT_SUBROUTINE, /* gosub-target subroutine body */ + STMT_DO_LOOP, /* do/while loop statement */ + STMT_FOR_LOOP, /* for loop statement */ + STMT_FOR_IN_LOOP, /* for/in loop statement */ + STMT_WHILE_LOOP, /* while loop statement */ + STMT_LIMIT +} JSStmtType; + +#define STMT_TYPE_IN_RANGE(t,b,e) ((uint)((t) - (b)) <= (uintN)((e) - (b))) + +/* + * A comment on the encoding of the JSStmtType enum and type-testing macros: + * + * STMT_TYPE_MAYBE_SCOPE tells whether a statement type is always, or may + * become, a lexical scope. It therefore includes block and switch (the two + * low-numbered "maybe" scope types) and excludes with (with has dynamic scope + * pending the "reformed with" in ES4/JS2). It includes all try-catch-finally + * types, which are high-numbered maybe-scope types. + * + * STMT_TYPE_LINKS_SCOPE tells whether a JSStmtInfo of the given type eagerly + * links to other scoping statement info records. It excludes the two early + * "maybe" types, block and switch, as well as the try and both finally types, + * since try and the other trailing maybe-scope types don't need block scope + * unless they contain let declarations. + * + * We treat WITH as a static scope because it prevents lexical binding from + * continuing further up the static scope chain. With the lost "reformed with" + * proposal for ES4, we would be able to model it statically, too. + */ +#define STMT_TYPE_MAYBE_SCOPE(type) \ + (type != STMT_WITH && \ + STMT_TYPE_IN_RANGE(type, STMT_BLOCK, STMT_SUBROUTINE)) + +#define STMT_TYPE_LINKS_SCOPE(type) \ + STMT_TYPE_IN_RANGE(type, STMT_WITH, STMT_CATCH) + +#define STMT_TYPE_IS_TRYING(type) \ + STMT_TYPE_IN_RANGE(type, STMT_TRY, STMT_SUBROUTINE) + +#define STMT_TYPE_IS_LOOP(type) ((type) >= STMT_DO_LOOP) + +#define STMT_MAYBE_SCOPE(stmt) STMT_TYPE_MAYBE_SCOPE((stmt)->type) +#define STMT_LINKS_SCOPE(stmt) (STMT_TYPE_LINKS_SCOPE((stmt)->type) || \ + ((stmt)->flags & SIF_SCOPE)) +#define STMT_IS_TRYING(stmt) STMT_TYPE_IS_TRYING((stmt)->type) +#define STMT_IS_LOOP(stmt) STMT_TYPE_IS_LOOP((stmt)->type) + +typedef struct JSStmtInfo JSStmtInfo; + +struct JSStmtInfo { + uint16 type; /* statement type */ + uint16 flags; /* flags, see below */ + uint32 blockid; /* for simplified dominance computation */ + ptrdiff_t update; /* loop update offset (top if none) */ + ptrdiff_t breaks; /* offset of last break in loop */ + ptrdiff_t continues; /* offset of last continue in loop */ + union { + JSAtom *label; /* name of LABEL */ + JSObjectBox *blockBox; /* block scope object */ + }; + JSStmtInfo *down; /* info for enclosing statement */ + JSStmtInfo *downScope; /* next enclosing lexical scope */ +}; + +#define SIF_SCOPE 0x0001 /* statement has its own lexical scope */ +#define SIF_BODY_BLOCK 0x0002 /* STMT_BLOCK type is a function body */ +#define SIF_FOR_BLOCK 0x0004 /* for (let ...) induced block scope */ + +/* + * To reuse space in JSStmtInfo, rename breaks and continues for use during + * try/catch/finally code generation and backpatching. To match most common + * use cases, the macro argument is a struct, not a struct pointer. Only a + * loop, switch, or label statement info record can have breaks and continues, + * and only a for loop has an update backpatch chain, so it's safe to overlay + * these for the "trying" JSStmtTypes. + */ +#define CATCHNOTE(stmt) ((stmt).update) +#define GOSUBS(stmt) ((stmt).breaks) +#define GUARDJUMP(stmt) ((stmt).continues) + +#define SET_STATEMENT_TOP(stmt, top) \ + ((stmt)->update = (top), (stmt)->breaks = (stmt)->continues = (-1)) + +#ifdef JS_SCOPE_DEPTH_METER +# define JS_SCOPE_DEPTH_METERING(code) ((void) (code)) +# define JS_SCOPE_DEPTH_METERING_IF(cond, code) ((cond) ? (void) (code) : (void) 0) +#else +# define JS_SCOPE_DEPTH_METERING(code) ((void) 0) +# define JS_SCOPE_DEPTH_METERING_IF(code, x) ((void) 0) +#endif + +#define TCF_COMPILING 0x01 /* JSTreeContext is JSCodeGenerator */ +#define TCF_IN_FUNCTION 0x02 /* parsing inside function body */ +#define TCF_RETURN_EXPR 0x04 /* function has 'return expr;' */ +#define TCF_RETURN_VOID 0x08 /* function has 'return;' */ +#define TCF_IN_FOR_INIT 0x10 /* parsing init expr of for; exclude 'in' */ +#define TCF_FUN_SETS_OUTER_NAME 0x20 /* function set outer name (lexical or free) */ +#define TCF_FUN_PARAM_ARGUMENTS 0x40 /* function has parameter named arguments */ +#define TCF_FUN_USES_ARGUMENTS 0x80 /* function uses arguments except as a + parameter name */ +#define TCF_FUN_HEAVYWEIGHT 0x100 /* function needs Call object per call */ +#define TCF_FUN_IS_GENERATOR 0x200 /* parsed yield statement in function */ +#define TCF_FUN_USES_OWN_NAME 0x400 /* named function expression that uses its + own name */ +#define TCF_HAS_FUNCTION_STMT 0x800 /* block contains a function statement */ +#define TCF_GENEXP_LAMBDA 0x1000 /* flag lambda from generator expression */ +#define TCF_COMPILE_N_GO 0x2000 /* compile-and-go mode of script, can + optimize name references based on scope + chain */ +#define TCF_NO_SCRIPT_RVAL 0x4000 /* API caller does not want result value + from global script */ +#define TCF_HAS_SHARPS 0x8000 /* source contains sharp defs or uses */ + +/* + * Set when parsing a declaration-like destructuring pattern. This + * flag causes PrimaryExpr to create PN_NAME parse nodes for variable + * references which are not hooked into any definition's use chain, + * added to any tree context's AtomList, etc. etc. CheckDestructuring + * will do that work later. + * + * The comments atop CheckDestructuring explain the distinction + * between assignment-like and declaration-like destructuring + * patterns, and why they need to be treated differently. + */ +#define TCF_DECL_DESTRUCTURING 0x10000 + +/* + * A request flag passed to Compiler::compileScript and then down via + * JSCodeGenerator to js_NewScriptFromCG, from script_compile_sub and any + * kindred functions that need to make mutable scripts (even empty ones; + * i.e., they can't share the const JSScript::emptyScript() singleton). + */ +#define TCF_NEED_MUTABLE_SCRIPT 0x20000 + +/* + * This function/global/eval code body contained a Use Strict Directive. Treat + * certain strict warnings as errors, and forbid the use of 'with'. See also + * TSF_STRICT_MODE_CODE, JSScript::strictModeCode, and JSREPORT_STRICT_ERROR. + */ +#define TCF_STRICT_MODE_CODE 0x40000 + +/* bit 0x80000 is unused */ + +/* + * Flag signifying that the current function seems to be a constructor that + * sets this.foo to define "methods", at least one of which can't be a null + * closure, so we should avoid over-specializing property cache entries and + * trace inlining guards to method function object identity, which will vary + * per instance. + */ +#define TCF_FUN_UNBRAND_THIS 0x100000 + +/* + * "Module pattern", i.e., a lambda that is immediately applied and the whole + * of an expression statement. + */ +#define TCF_FUN_MODULE_PATTERN 0x200000 + +/* + * Flag to prevent a non-escaping function from being optimized into a null + * closure (i.e., a closure that needs only its global object for free variable + * resolution), because this function contains a closure that needs one or more + * scope objects surrounding it (i.e., a Call object for an outer heavyweight + * function). See bug 560234. + */ +#define TCF_FUN_ENTRAINS_SCOPES 0x400000 + +/* The function calls 'eval'. */ +#define TCF_FUN_CALLS_EVAL 0x800000 + +/* The function mutates a positional (non-destructuring) parameter. */ +#define TCF_FUN_MUTATES_PARAMETER 0x1000000 + +/* + * Compiling an eval() script. + */ +#define TCF_COMPILE_FOR_EVAL 0x2000000 + +/* + * The function or a function that encloses it may define new local names + * at runtime through means other than calling eval. + */ +#define TCF_FUN_MIGHT_ALIAS_LOCALS 0x4000000 + +/* + * The script contains singleton initialiser JSOP_OBJECT. + */ +#define TCF_HAS_SINGLETONS 0x8000000 + +/* + * Some enclosing scope is a with-statement or E4X filter-expression. + */ +#define TCF_IN_WITH 0x10000000 + +/* + * Flags to check for return; vs. return expr; in a function. + */ +#define TCF_RETURN_FLAGS (TCF_RETURN_EXPR | TCF_RETURN_VOID) + +/* + * Sticky deoptimization flags to propagate from FunctionBody. + */ +#define TCF_FUN_FLAGS (TCF_FUN_SETS_OUTER_NAME | \ + TCF_FUN_USES_ARGUMENTS | \ + TCF_FUN_PARAM_ARGUMENTS | \ + TCF_FUN_HEAVYWEIGHT | \ + TCF_FUN_IS_GENERATOR | \ + TCF_FUN_USES_OWN_NAME | \ + TCF_HAS_SHARPS | \ + TCF_FUN_CALLS_EVAL | \ + TCF_FUN_MIGHT_ALIAS_LOCALS | \ + TCF_FUN_MUTATES_PARAMETER | \ + TCF_STRICT_MODE_CODE) + +struct JSTreeContext { /* tree context for semantic checks */ + uint32 flags; /* statement state flags, see above */ + uint32 bodyid; /* block number of program/function body */ + uint32 blockidGen; /* preincremented block number generator */ + JSStmtInfo *topStmt; /* top of statement info stack */ + JSStmtInfo *topScopeStmt; /* top lexical scope statement */ + JSObjectBox *blockChainBox; /* compile time block scope chain (NB: one + deeper than the topScopeStmt/downScope + chain when in head of let block/expr) */ + JSParseNode *blockNode; /* parse node for a block with let declarations + (block with its own lexical scope) */ + JSAtomList decls; /* function, const, and var declarations */ + js::Parser *parser; /* ptr to common parsing and lexing data */ + + private: + union { + JSFunction *fun_; /* function to store argument and variable + names when flags & TCF_IN_FUNCTION */ + JSObject *scopeChain_; /* scope chain object for the script */ + }; + + public: + JSFunction *fun() const { + JS_ASSERT(inFunction()); + return fun_; + } + void setFunction(JSFunction *fun) { + JS_ASSERT(inFunction()); + fun_ = fun; + } + JSObject *scopeChain() const { + JS_ASSERT(!inFunction()); + return scopeChain_; + } + void setScopeChain(JSObject *scopeChain) { + JS_ASSERT(!inFunction()); + scopeChain_ = scopeChain; + } + + JSAtomList lexdeps; /* unresolved lexical name dependencies */ + JSTreeContext *parent; /* enclosing function or global context */ + uintN staticLevel; /* static compilation unit nesting level */ + + JSFunctionBox *funbox; /* null or box for function we're compiling + if (flags & TCF_IN_FUNCTION) and not in + Compiler::compileFunctionBody */ + JSFunctionBox *functionList; + + JSParseNode *innermostWith; /* innermost WITH parse node */ + + js::Bindings bindings; /* bindings in this code, including + arguments if we're compiling a function */ + +#ifdef JS_SCOPE_DEPTH_METER + uint16 scopeDepth; /* current lexical scope chain depth */ + uint16 maxScopeDepth; /* maximum lexical scope chain depth */ +#endif + + void trace(JSTracer *trc); + + JSTreeContext(js::Parser *prs) + : flags(0), bodyid(0), blockidGen(0), topStmt(NULL), topScopeStmt(NULL), + blockChainBox(NULL), blockNode(NULL), parser(prs), scopeChain_(NULL), parent(prs->tc), + staticLevel(0), funbox(NULL), functionList(NULL), innermostWith(NULL), bindings(prs->context), + sharpSlotBase(-1) + { + prs->tc = this; + JS_SCOPE_DEPTH_METERING(scopeDepth = maxScopeDepth = 0); + } + + /* + * For functions the tree context is constructed and destructed a second + * time during code generation. To avoid a redundant stats update in such + * cases, we store uint16(-1) in maxScopeDepth. + */ + ~JSTreeContext() { + parser->tc = this->parent; + JS_SCOPE_DEPTH_METERING_IF((maxScopeDepth != uint16(-1)), + JS_BASIC_STATS_ACCUM(&parser + ->context + ->runtime + ->lexicalScopeDepthStats, + maxScopeDepth)); + } + + uintN blockid() { return topStmt ? topStmt->blockid : bodyid; } + + JSObject *blockChain() { + return blockChainBox ? blockChainBox->object : NULL; + } + + /* + * True if we are at the topmost level of a entire script or function body. + * For example, while parsing this code we would encounter f1 and f2 at + * body level, but we would not encounter f3 or f4 at body level: + * + * function f1() { function f2() { } } + * if (cond) { function f3() { if (cond) { function f4() { } } } } + */ + bool atBodyLevel() { return !topStmt || (topStmt->flags & SIF_BODY_BLOCK); } + + /* Test whether we're in a statement of given type. */ + bool inStatement(JSStmtType type); + + bool inStrictMode() const { + return flags & TCF_STRICT_MODE_CODE; + } + + inline bool needStrictChecks(); + + /* + * sharpSlotBase is -1 or first slot of pair for [sharpArray, sharpDepth]. + * The parser calls ensureSharpSlots to allocate these two stack locals. + */ + int sharpSlotBase; + bool ensureSharpSlots(); + + js::Compiler *compiler() { return (js::Compiler *)parser; } + + // Return true there is a generator function within |skip| lexical scopes + // (going upward) from this context's lexical scope. Always return true if + // this context is itself a generator. + bool skipSpansGenerator(unsigned skip); + + bool compileAndGo() const { return flags & TCF_COMPILE_N_GO; } + bool inFunction() const { return flags & TCF_IN_FUNCTION; } + + bool compiling() const { return flags & TCF_COMPILING; } + inline JSCodeGenerator *asCodeGenerator(); + + bool usesArguments() const { + return flags & TCF_FUN_USES_ARGUMENTS; + } + + void noteCallsEval() { + flags |= TCF_FUN_CALLS_EVAL; + } + + bool callsEval() const { + return flags & TCF_FUN_CALLS_EVAL; + } + + void noteMightAliasLocals() { + flags |= TCF_FUN_MIGHT_ALIAS_LOCALS; + } + + bool mightAliasLocals() const { + return flags & TCF_FUN_MIGHT_ALIAS_LOCALS; + } + + void noteParameterMutation() { + JS_ASSERT(inFunction()); + flags |= TCF_FUN_MUTATES_PARAMETER; + } + + bool mutatesParameter() const { + JS_ASSERT(inFunction()); + return flags & TCF_FUN_MUTATES_PARAMETER; + } + + void noteArgumentsUse() { + JS_ASSERT(inFunction()); + flags |= TCF_FUN_USES_ARGUMENTS; + if (funbox) + funbox->node->pn_dflags |= PND_FUNARG; + } + + bool needsEagerArguments() const { + return inStrictMode() && ((usesArguments() && mutatesParameter()) || callsEval()); + } +}; + +/* + * Return true if we need to check for conditions that elicit + * JSOPTION_STRICT warnings or strict mode errors. + */ +inline bool JSTreeContext::needStrictChecks() { + return parser->context->hasStrictOption() || inStrictMode(); +} + +/* + * Span-dependent instructions are jumps whose span (from the jump bytecode to + * the jump target) may require 2 or 4 bytes of immediate operand. + */ +typedef struct JSSpanDep JSSpanDep; +typedef struct JSJumpTarget JSJumpTarget; + +struct JSSpanDep { + ptrdiff_t top; /* offset of first bytecode in an opcode */ + ptrdiff_t offset; /* offset - 1 within opcode of jump operand */ + ptrdiff_t before; /* original offset - 1 of jump operand */ + JSJumpTarget *target; /* tagged target pointer or backpatch delta */ +}; + +/* + * Jump targets are stored in an AVL tree, for O(log(n)) lookup with targets + * sorted by offset from left to right, so that targets after a span-dependent + * instruction whose jump offset operand must be extended can be found quickly + * and adjusted upward (toward higher offsets). + */ +struct JSJumpTarget { + ptrdiff_t offset; /* offset of span-dependent jump target */ + int balance; /* AVL tree balance number */ + JSJumpTarget *kids[2]; /* left and right AVL tree child pointers */ +}; + +#define JT_LEFT 0 +#define JT_RIGHT 1 +#define JT_OTHER_DIR(dir) (1 - (dir)) +#define JT_IMBALANCE(dir) (((dir) << 1) - 1) +#define JT_DIR(imbalance) (((imbalance) + 1) >> 1) + +/* + * Backpatch deltas are encoded in JSSpanDep.target if JT_TAG_BIT is clear, + * so we can maintain backpatch chains when using span dependency records to + * hold jump offsets that overflow 16 bits. + */ +#define JT_TAG_BIT ((jsword) 1) +#define JT_UNTAG_SHIFT 1 +#define JT_SET_TAG(jt) ((JSJumpTarget *)((jsword)(jt) | JT_TAG_BIT)) +#define JT_CLR_TAG(jt) ((JSJumpTarget *)((jsword)(jt) & ~JT_TAG_BIT)) +#define JT_HAS_TAG(jt) ((jsword)(jt) & JT_TAG_BIT) + +#define BITS_PER_PTRDIFF (sizeof(ptrdiff_t) * JS_BITS_PER_BYTE) +#define BITS_PER_BPDELTA (BITS_PER_PTRDIFF - 1 - JT_UNTAG_SHIFT) +#define BPDELTA_MAX (((ptrdiff_t)1 << BITS_PER_BPDELTA) - 1) +#define BPDELTA_TO_JT(bp) ((JSJumpTarget *)((bp) << JT_UNTAG_SHIFT)) +#define JT_TO_BPDELTA(jt) ((ptrdiff_t)((jsword)(jt) >> JT_UNTAG_SHIFT)) + +#define SD_SET_TARGET(sd,jt) ((sd)->target = JT_SET_TAG(jt)) +#define SD_GET_TARGET(sd) (JS_ASSERT(JT_HAS_TAG((sd)->target)), \ + JT_CLR_TAG((sd)->target)) +#define SD_SET_BPDELTA(sd,bp) ((sd)->target = BPDELTA_TO_JT(bp)) +#define SD_GET_BPDELTA(sd) (JS_ASSERT(!JT_HAS_TAG((sd)->target)), \ + JT_TO_BPDELTA((sd)->target)) + +/* Avoid asserting twice by expanding SD_GET_TARGET in the "then" clause. */ +#define SD_SPAN(sd,pivot) (SD_GET_TARGET(sd) \ + ? JT_CLR_TAG((sd)->target)->offset - (pivot) \ + : 0) + +typedef struct JSTryNode JSTryNode; + +struct JSTryNode { + JSTryNote note; + JSTryNode *prev; +}; + +struct JSCGObjectList { + uint32 length; /* number of emitted so far objects */ + JSObjectBox *lastbox; /* last emitted object */ + + JSCGObjectList() : length(0), lastbox(NULL) {} + + uintN index(JSObjectBox *objbox); + void finish(JSObjectArray *array); +}; + +class JSGCConstList { + js::Vector list; + public: + JSGCConstList(JSContext *cx) : list(cx) {} + bool append(js::Value v) { return list.append(v); } + size_t length() const { return list.length(); } + void finish(JSConstArray *array); + +}; + +struct JSCodeGenerator : public JSTreeContext +{ + JSArenaPool *codePool; /* pointer to thread code arena pool */ + JSArenaPool *notePool; /* pointer to thread srcnote arena pool */ + void *codeMark; /* low watermark in cg->codePool */ + void *noteMark; /* low watermark in cg->notePool */ + + struct { + jsbytecode *base; /* base of JS bytecode vector */ + jsbytecode *limit; /* one byte beyond end of bytecode */ + jsbytecode *next; /* pointer to next free bytecode */ + jssrcnote *notes; /* source notes, see below */ + uintN noteCount; /* number of source notes so far */ + uintN noteMask; /* growth increment for notes */ + ptrdiff_t lastNoteOffset; /* code offset for last source note */ + uintN currentLine; /* line number for tree-based srcnote gen */ + } prolog, main, *current; + + JSAtomList atomList; /* literals indexed for mapping */ + uintN firstLine; /* first line, for js_NewScriptFromCG */ + + intN stackDepth; /* current stack depth in script frame */ + uintN maxStackDepth; /* maximum stack depth so far */ + + uintN ntrynotes; /* number of allocated so far try notes */ + JSTryNode *lastTryNode; /* the last allocated try node */ + + JSSpanDep *spanDeps; /* span dependent instruction records */ + JSJumpTarget *jumpTargets; /* AVL tree of jump target offsets */ + JSJumpTarget *jtFreeList; /* JT_LEFT-linked list of free structs */ + uintN numSpanDeps; /* number of span dependencies */ + uintN numJumpTargets; /* number of jump targets */ + ptrdiff_t spanDepTodo; /* offset from main.base of potentially + unoptimized spandeps */ + + uintN arrayCompDepth; /* stack depth of array in comprehension */ + + uintN emitLevel; /* js_EmitTree recursion level */ + + typedef js::HashMap ConstMap; + ConstMap constMap; /* compile time constants */ + + JSGCConstList constList; /* constants to be included with the script */ + + JSCGObjectList objectList; /* list of emitted objects */ + JSCGObjectList regexpList; /* list of emitted regexp that will be + cloned during execution */ + + JSAtomList upvarList; /* map of atoms to upvar indexes */ + JSUpvarArray upvarMap; /* indexed upvar pairs (JS_realloc'ed) */ + + typedef js::Vector GlobalUseVector; + + GlobalUseVector globalUses; /* per-script global uses */ + JSAtomList globalMap; /* per-script map of global name to globalUses vector */ + + /* Vectors of pn_cookie slot values. */ + typedef js::Vector SlotVector; + SlotVector closedArgs; + SlotVector closedVars; + + uint16 traceIndex; /* index for the next JSOP_TRACE instruction */ + + /* + * Initialize cg to allocate bytecode space from codePool, source note + * space from notePool, and all other arena-allocated temporaries from + * parser->context->tempPool. + */ + JSCodeGenerator(js::Parser *parser, + JSArenaPool *codePool, JSArenaPool *notePool, + uintN lineno); + bool init(); + + /* + * Release cg->codePool, cg->notePool, and parser->context->tempPool to + * marks set by JSCodeGenerator's ctor. Note that cgs are magic: they own + * the arena pool "tops-of-stack" space above their codeMark, noteMark, and + * tempMark points. This means you cannot alloc from tempPool and save the + * pointer beyond the next JSCodeGenerator destructor call. + */ + ~JSCodeGenerator(); + + /* + * Adds a use of a variable that is statically known to exist on the + * global object. + * + * The actual slot of the variable on the global object is not known + * until after compilation. Properties must be resolved before being + * added, to avoid aliasing properties that should be resolved. This makes + * slot prediction based on the global object's free slot impossible. So, + * we use the slot to index into cg->globalScope->defs, and perform a + * fixup of the script at the very end of compilation. + * + * If the global use can be cached, |cookie| will be set to |slot|. + * Otherwise, |cookie| is set to the free cookie value. + */ + bool addGlobalUse(JSAtom *atom, uint32 slot, js::UpvarCookie *cookie); + + bool hasSharps() const { + bool rv = !!(flags & TCF_HAS_SHARPS); + JS_ASSERT((sharpSlotBase >= 0) == rv); + return rv; + } + + uintN sharpSlots() const { + return hasSharps() ? SHARP_NSLOTS : 0; + } + + bool compilingForEval() const { return !!(flags & TCF_COMPILE_FOR_EVAL); } + JSVersion version() const { return parser->versionWithFlags(); } + + bool shouldNoteClosedName(JSParseNode *pn); + + bool checkSingletonContext() { + if (!compileAndGo() || inFunction()) + return false; + for (JSStmtInfo *stmt = topStmt; stmt; stmt = stmt->down) { + if (STMT_IS_LOOP(stmt)) + return false; + } + flags |= TCF_HAS_SINGLETONS; + return true; + } +}; + +#define CG_TS(cg) TS((cg)->parser) + +#define CG_BASE(cg) ((cg)->current->base) +#define CG_LIMIT(cg) ((cg)->current->limit) +#define CG_NEXT(cg) ((cg)->current->next) +#define CG_CODE(cg,offset) (CG_BASE(cg) + (offset)) +#define CG_OFFSET(cg) (CG_NEXT(cg) - CG_BASE(cg)) + +#define CG_NOTES(cg) ((cg)->current->notes) +#define CG_NOTE_COUNT(cg) ((cg)->current->noteCount) +#define CG_NOTE_MASK(cg) ((cg)->current->noteMask) +#define CG_LAST_NOTE_OFFSET(cg) ((cg)->current->lastNoteOffset) +#define CG_CURRENT_LINE(cg) ((cg)->current->currentLine) + +#define CG_PROLOG_BASE(cg) ((cg)->prolog.base) +#define CG_PROLOG_LIMIT(cg) ((cg)->prolog.limit) +#define CG_PROLOG_NEXT(cg) ((cg)->prolog.next) +#define CG_PROLOG_CODE(cg,poff) (CG_PROLOG_BASE(cg) + (poff)) +#define CG_PROLOG_OFFSET(cg) (CG_PROLOG_NEXT(cg) - CG_PROLOG_BASE(cg)) + +#define CG_SWITCH_TO_MAIN(cg) ((cg)->current = &(cg)->main) +#define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog) + +inline JSCodeGenerator * +JSTreeContext::asCodeGenerator() +{ + JS_ASSERT(compiling()); + return static_cast(this); +} + +/* + * Emit one bytecode. + */ +extern ptrdiff_t +js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op); + +/* + * Emit two bytecodes, an opcode (op) with a byte of immediate operand (op1). + */ +extern ptrdiff_t +js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1); + +/* + * Emit three bytecodes, an opcode with two bytes of immediate operands. + */ +extern ptrdiff_t +js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1, + jsbytecode op2); + +/* + * Emit five bytecodes, an opcode with two 16-bit immediates. + */ +extern ptrdiff_t +js_Emit5(JSContext *cx, JSCodeGenerator *cg, JSOp op, uint16 op1, + uint16 op2); + +/* + * Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand. + */ +extern ptrdiff_t +js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra); + +/* + * Unsafe macro to call js_SetJumpOffset and return false if it does. + */ +#define CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx,cg,pc,off,BAD_EXIT) \ + JS_BEGIN_MACRO \ + if (!js_SetJumpOffset(cx, cg, pc, off)) { \ + BAD_EXIT; \ + } \ + JS_END_MACRO + +#define CHECK_AND_SET_JUMP_OFFSET(cx,cg,pc,off) \ + CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx,cg,pc,off,return JS_FALSE) + +#define CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx,cg,off,BAD_EXIT) \ + CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx, cg, CG_CODE(cg,off), \ + CG_OFFSET(cg) - (off), BAD_EXIT) + +#define CHECK_AND_SET_JUMP_OFFSET_AT(cx,cg,off) \ + CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx, cg, off, return JS_FALSE) + +extern JSBool +js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, + ptrdiff_t off); + +/* + * Push the C-stack-allocated struct at stmt onto the stmtInfo stack. + */ +extern void +js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type, + ptrdiff_t top); + +/* + * Push a block scope statement and link blockObj into tc->blockChain. To pop + * this statement info record, use js_PopStatement as usual, or if appropriate + * (if generating code), js_PopStatementCG. + */ +extern void +js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObjectBox *blockBox, + ptrdiff_t top); + +/* + * Pop tc->topStmt. If the top JSStmtInfo struct is not stack-allocated, it + * is up to the caller to free it. + */ +extern void +js_PopStatement(JSTreeContext *tc); + +/* + * Like js_PopStatement(cg), also patch breaks and continues unless the top + * statement info record represents a try-catch-finally suite. May fail if a + * jump offset overflows. + */ +extern JSBool +js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg); + +/* + * Define and lookup a primitive jsval associated with the const named by atom. + * js_DefineCompileTimeConstant analyzes the constant-folded initializer at pn + * and saves the const's value in cg->constList, if it can be used at compile + * time. It returns true unless an error occurred. + * + * If the initializer's value could not be saved, js_DefineCompileTimeConstant + * calls will return the undefined value. js_DefineCompileTimeConstant tries + * to find a const value memorized for atom, returning true with *vp set to a + * value other than undefined if the constant was found, true with *vp set to + * JSVAL_VOID if not found, and false on error. + */ +extern JSBool +js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, + JSParseNode *pn); + +/* + * Find a lexically scoped variable (one declared by let, catch, or an array + * comprehension) named by atom, looking in tc's compile-time scopes. + * + * If a WITH statement is reached along the scope stack, return its statement + * info record, so callers can tell that atom is ambiguous. If slotp is not + * null, then if atom is found, set *slotp to its stack slot, otherwise to -1. + * This means that if slotp is not null, all the block objects on the lexical + * scope chain must have had their depth slots computed by the code generator, + * so the caller must be under js_EmitTree. + * + * In any event, directly return the statement info record in which atom was + * found. Otherwise return null. + */ +extern JSStmtInfo * +js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, + JSStmtInfo *stmt = NULL); + +/* + * Emit code into cg for the tree rooted at pn. + */ +extern JSBool +js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn); + +/* + * Emit function code using cg for the tree rooted at body. + */ +extern JSBool +js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body); + +/* + * Source notes generated along with bytecode for decompiling and debugging. + * A source note is a uint8 with 5 bits of type and 3 of offset from the pc of + * the previous note. If 3 bits of offset aren't enough, extended delta notes + * (SRC_XDELTA) consisting of 2 set high order bits followed by 6 offset bits + * are emitted before the next note. Some notes have operand offsets encoded + * immediately after them, in note bytes or byte-triples. + * + * Source Note Extended Delta + * +7-6-5-4-3+2-1-0+ +7-6-5+4-3-2-1-0+ + * |note-type|delta| |1 1| ext-delta | + * +---------+-----+ +---+-----------+ + * + * At most one "gettable" note (i.e., a note of type other than SRC_NEWLINE, + * SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode. + * + * NB: the js_SrcNoteSpec array in jsemit.c is indexed by this enum, so its + * initializers need to match the order here. + * + * Note on adding new source notes: every pair of bytecodes (A, B) where A and + * B have disjoint sets of source notes that could apply to each bytecode may + * reuse the same note type value for two notes (snA, snB) that have the same + * arity, offsetBias, and isSpanDep initializers in js_SrcNoteSpec. This is + * why SRC_IF and SRC_INITPROP have the same value below. For bad historical + * reasons, some bytecodes below that could be overlayed have not been, but + * before using SRC_EXTENDED, consider compressing the existing note types. + * + * Don't forget to update JSXDR_BYTECODE_VERSION in jsxdrapi.h for all such + * incompatible source note or other bytecode changes. + */ +typedef enum JSSrcNoteType { + SRC_NULL = 0, /* terminates a note vector */ + SRC_IF = 1, /* JSOP_IFEQ bytecode is from an if-then */ + SRC_BREAK = 1, /* JSOP_GOTO is a break */ + SRC_INITPROP = 1, /* disjoint meaning applied to JSOP_INITELEM or + to an index label in a regular (structuring) + or a destructuring object initialiser */ + SRC_GENEXP = 1, /* JSOP_LAMBDA from generator expression */ + SRC_IF_ELSE = 2, /* JSOP_IFEQ bytecode is from an if-then-else */ + SRC_FOR_IN = 2, /* JSOP_GOTO to for-in loop condition from + before loop (same arity as SRC_IF_ELSE) */ + SRC_FOR = 3, /* JSOP_NOP or JSOP_POP in for(;;) loop head */ + SRC_WHILE = 4, /* JSOP_GOTO to for or while loop condition + from before loop, else JSOP_NOP at top of + do-while loop */ + SRC_TRACE = 4, /* For JSOP_TRACE; includes distance to loop end */ + SRC_CONTINUE = 5, /* JSOP_GOTO is a continue, not a break; + also used on JSOP_ENDINIT if extra comma + at end of array literal: [1,2,,]; + JSOP_DUP continuing destructuring pattern */ + SRC_DECL = 6, /* type of a declaration (var, const, let*) */ + SRC_DESTRUCT = 6, /* JSOP_DUP starting a destructuring assignment + operation, with SRC_DECL_* offset operand */ + SRC_PCDELTA = 7, /* distance forward from comma-operator to + next POP, or from CONDSWITCH to first CASE + opcode, etc. -- always a forward delta */ + SRC_GROUPASSIGN = 7, /* SRC_DESTRUCT variant for [a, b] = [c, d] */ + SRC_ASSIGNOP = 8, /* += or another assign-op follows */ + SRC_COND = 9, /* JSOP_IFEQ is from conditional ?: operator */ + SRC_BRACE = 10, /* mandatory brace, for scope or to avoid + dangling else */ + SRC_HIDDEN = 11, /* opcode shouldn't be decompiled */ + SRC_PCBASE = 12, /* distance back from annotated getprop or + setprop op to left-most obj.prop.subprop + bytecode -- always a backward delta */ + SRC_LABEL = 13, /* JSOP_NOP for label: with atomid immediate */ + SRC_LABELBRACE = 14, /* JSOP_NOP for label: {...} begin brace */ + SRC_ENDBRACE = 15, /* JSOP_NOP for label: {...} end brace */ + SRC_BREAK2LABEL = 16, /* JSOP_GOTO for 'break label' with atomid */ + SRC_CONT2LABEL = 17, /* JSOP_GOTO for 'continue label' with atomid */ + SRC_SWITCH = 18, /* JSOP_*SWITCH with offset to end of switch, + 2nd off to first JSOP_CASE if condswitch */ + SRC_FUNCDEF = 19, /* JSOP_NOP for function f() with atomid */ + SRC_CATCH = 20, /* catch block has guard */ + SRC_EXTENDED = 21, /* extended source note, 32-159, in next byte */ + SRC_NEWLINE = 22, /* bytecode follows a source newline */ + SRC_SETLINE = 23, /* a file-absolute source line number note */ + SRC_XDELTA = 24 /* 24-31 are for extended delta notes */ +} JSSrcNoteType; + +/* + * Constants for the SRC_DECL source note. Note that span-dependent bytecode + * selection means that any SRC_DECL offset greater than SRC_DECL_LET may need + * to be adjusted, but these "offsets" are too small to span a span-dependent + * instruction, so can be used to denote distinct declaration syntaxes to the + * decompiler. + * + * NB: the var_prefix array in jsopcode.c depends on these dense indexes from + * SRC_DECL_VAR through SRC_DECL_LET. + */ +#define SRC_DECL_VAR 0 +#define SRC_DECL_CONST 1 +#define SRC_DECL_LET 2 +#define SRC_DECL_NONE 3 + +#define SN_TYPE_BITS 5 +#define SN_DELTA_BITS 3 +#define SN_XDELTA_BITS 6 +#define SN_TYPE_MASK (JS_BITMASK(SN_TYPE_BITS) << SN_DELTA_BITS) +#define SN_DELTA_MASK ((ptrdiff_t)JS_BITMASK(SN_DELTA_BITS)) +#define SN_XDELTA_MASK ((ptrdiff_t)JS_BITMASK(SN_XDELTA_BITS)) + +#define SN_MAKE_NOTE(sn,t,d) (*(sn) = (jssrcnote) \ + (((t) << SN_DELTA_BITS) \ + | ((d) & SN_DELTA_MASK))) +#define SN_MAKE_XDELTA(sn,d) (*(sn) = (jssrcnote) \ + ((SRC_XDELTA << SN_DELTA_BITS) \ + | ((d) & SN_XDELTA_MASK))) + +#define SN_IS_XDELTA(sn) ((*(sn) >> SN_DELTA_BITS) >= SRC_XDELTA) +#define SN_TYPE(sn) ((JSSrcNoteType)(SN_IS_XDELTA(sn) \ + ? SRC_XDELTA \ + : *(sn) >> SN_DELTA_BITS)) +#define SN_SET_TYPE(sn,type) SN_MAKE_NOTE(sn, type, SN_DELTA(sn)) +#define SN_IS_GETTABLE(sn) (SN_TYPE(sn) < SRC_NEWLINE) + +#define SN_DELTA(sn) ((ptrdiff_t)(SN_IS_XDELTA(sn) \ + ? *(sn) & SN_XDELTA_MASK \ + : *(sn) & SN_DELTA_MASK)) +#define SN_SET_DELTA(sn,delta) (SN_IS_XDELTA(sn) \ + ? SN_MAKE_XDELTA(sn, delta) \ + : SN_MAKE_NOTE(sn, SN_TYPE(sn), delta)) + +#define SN_DELTA_LIMIT ((ptrdiff_t)JS_BIT(SN_DELTA_BITS)) +#define SN_XDELTA_LIMIT ((ptrdiff_t)JS_BIT(SN_XDELTA_BITS)) + +/* + * Offset fields follow certain notes and are frequency-encoded: an offset in + * [0,0x7f] consumes one byte, an offset in [0x80,0x7fffff] takes three, and + * the high bit of the first byte is set. + */ +#define SN_3BYTE_OFFSET_FLAG 0x80 +#define SN_3BYTE_OFFSET_MASK 0x7f + +typedef struct JSSrcNoteSpec { + const char *name; /* name for disassembly/debugging output */ + int8 arity; /* number of offset operands */ + uint8 offsetBias; /* bias of offset(s) from annotated pc */ + int8 isSpanDep; /* 1 or -1 if offsets could span extended ops, + 0 otherwise; sign tells span direction */ +} JSSrcNoteSpec; + +extern JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[]; +extern JS_FRIEND_API(uintN) js_SrcNoteLength(jssrcnote *sn); + +#define SN_LENGTH(sn) ((js_SrcNoteSpec[SN_TYPE(sn)].arity == 0) ? 1 \ + : js_SrcNoteLength(sn)) +#define SN_NEXT(sn) ((sn) + SN_LENGTH(sn)) + +/* A source note array is terminated by an all-zero element. */ +#define SN_MAKE_TERMINATOR(sn) (*(sn) = SRC_NULL) +#define SN_IS_TERMINATOR(sn) (*(sn) == SRC_NULL) + +/* + * Append a new source note of the given type (and therefore size) to cg's + * notes dynamic array, updating cg->noteCount. Return the new note's index + * within the array pointed at by cg->current->notes. Return -1 if out of + * memory. + */ +extern intN +js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type); + +extern intN +js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, + ptrdiff_t offset); + +extern intN +js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type, + ptrdiff_t offset1, ptrdiff_t offset2); + +/* + * NB: this function can add at most one extra extended delta note. + */ +extern jssrcnote * +js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn, + ptrdiff_t delta); + +/* + * Get and set the offset operand identified by which (0 for the first, etc.). + */ +extern JS_FRIEND_API(ptrdiff_t) +js_GetSrcNoteOffset(jssrcnote *sn, uintN which); + +extern JSBool +js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index, + uintN which, ptrdiff_t offset); + +/* + * Finish taking source notes in cx's notePool, copying final notes to the new + * stable store allocated by the caller and passed in via notes. Return false + * on malloc failure, which means this function reported an error. + * + * To compute the number of jssrcnotes to allocate and pass in via notes, use + * the CG_COUNT_FINAL_SRCNOTES macro. This macro knows a lot about details of + * js_FinishTakingSrcNotes, SO DON'T CHANGE jsemit.c's js_FinishTakingSrcNotes + * FUNCTION WITHOUT CHECKING WHETHER THIS MACRO NEEDS CORRESPONDING CHANGES! + */ +#define CG_COUNT_FINAL_SRCNOTES(cg, cnt) \ + JS_BEGIN_MACRO \ + ptrdiff_t diff_ = CG_PROLOG_OFFSET(cg) - (cg)->prolog.lastNoteOffset; \ + cnt = (cg)->prolog.noteCount + (cg)->main.noteCount + 1; \ + if ((cg)->prolog.noteCount && \ + (cg)->prolog.currentLine != (cg)->firstLine) { \ + if (diff_ > SN_DELTA_MASK) \ + cnt += JS_HOWMANY(diff_ - SN_DELTA_MASK, SN_XDELTA_MASK); \ + cnt += 2 + (((cg)->firstLine > SN_3BYTE_OFFSET_MASK) << 1); \ + } else if (diff_ > 0) { \ + if (cg->main.noteCount) { \ + jssrcnote *sn_ = (cg)->main.notes; \ + diff_ -= SN_IS_XDELTA(sn_) \ + ? SN_XDELTA_MASK - (*sn_ & SN_XDELTA_MASK) \ + : SN_DELTA_MASK - (*sn_ & SN_DELTA_MASK); \ + } \ + if (diff_ > 0) \ + cnt += JS_HOWMANY(diff_, SN_XDELTA_MASK); \ + } \ + JS_END_MACRO + +extern JSBool +js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes); + +extern void +js_FinishTakingTryNotes(JSCodeGenerator *cg, JSTryNoteArray *array); + +JS_END_EXTERN_C + +#endif /* jsemit_h___ */ diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp new file mode 100644 index 0000000..8c987b3 --- /dev/null +++ b/js/src/jsexn.cpp @@ -0,0 +1,1298 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS standard exception implementation. + */ +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsbit.h" +#include "jsutil.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsexn.h" +#include "jsfun.h" +#include "jsinterp.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstaticcheck.h" +#include "jswrapper.h" + +#include "jscntxtinlines.h" +#include "jsinterpinlines.h" +#include "jsobjinlines.h" + +using namespace js; +using namespace js::gc; + +/* Forward declarations for js_ErrorClass's initializer. */ +static JSBool +Exception(JSContext *cx, uintN argc, Value *vp); + +static void +exn_trace(JSTracer *trc, JSObject *obj); + +static void +exn_finalize(JSContext *cx, JSObject *obj); + +static JSBool +exn_enumerate(JSContext *cx, JSObject *obj); + +static JSBool +exn_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSObject **objp); + +Class js_ErrorClass = { + js_Error_str, + JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_MARK_IS_TRACE | + JSCLASS_HAS_CACHED_PROTO(JSProto_Error), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + exn_enumerate, + (JSResolveOp)exn_resolve, + ConvertStub, + exn_finalize, + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + JS_CLASS_TRACE(exn_trace) +}; + +typedef struct JSStackTraceElem { + JSString *funName; + size_t argc; + const char *filename; + uintN ulineno; +} JSStackTraceElem; + +typedef struct JSExnPrivate { + /* A copy of the JSErrorReport originally generated. */ + JSErrorReport *errorReport; + JSString *message; + JSString *filename; + uintN lineno; + size_t stackDepth; + JSStackTraceElem stackElems[1]; +} JSExnPrivate; + +static JSString * +StackTraceToString(JSContext *cx, JSExnPrivate *priv); + +static JSErrorReport * +CopyErrorReport(JSContext *cx, JSErrorReport *report) +{ + /* + * We use a single malloc block to make a deep copy of JSErrorReport with + * the following layout: + * JSErrorReport + * array of copies of report->messageArgs + * jschar array with characters for all messageArgs + * jschar array with characters for ucmessage + * jschar array with characters for uclinebuf and uctokenptr + * char array with characters for linebuf and tokenptr + * char array with characters for filename + * Such layout together with the properties enforced by the following + * asserts does not need any extra alignment padding. + */ + JS_STATIC_ASSERT(sizeof(JSErrorReport) % sizeof(const char *) == 0); + JS_STATIC_ASSERT(sizeof(const char *) % sizeof(jschar) == 0); + + size_t filenameSize; + size_t linebufSize; + size_t uclinebufSize; + size_t ucmessageSize; + size_t i, argsArraySize, argsCopySize, argSize; + size_t mallocSize; + JSErrorReport *copy; + uint8 *cursor; + +#define JS_CHARS_SIZE(jschars) ((js_strlen(jschars) + 1) * sizeof(jschar)) + + filenameSize = report->filename ? strlen(report->filename) + 1 : 0; + linebufSize = report->linebuf ? strlen(report->linebuf) + 1 : 0; + uclinebufSize = report->uclinebuf ? JS_CHARS_SIZE(report->uclinebuf) : 0; + ucmessageSize = 0; + argsArraySize = 0; + argsCopySize = 0; + if (report->ucmessage) { + ucmessageSize = JS_CHARS_SIZE(report->ucmessage); + if (report->messageArgs) { + for (i = 0; report->messageArgs[i]; ++i) + argsCopySize += JS_CHARS_SIZE(report->messageArgs[i]); + + /* Non-null messageArgs should have at least one non-null arg. */ + JS_ASSERT(i != 0); + argsArraySize = (i + 1) * sizeof(const jschar *); + } + } + + /* + * The mallocSize can not overflow since it represents the sum of the + * sizes of already allocated objects. + */ + mallocSize = sizeof(JSErrorReport) + argsArraySize + argsCopySize + + ucmessageSize + uclinebufSize + linebufSize + filenameSize; + cursor = (uint8 *)cx->malloc(mallocSize); + if (!cursor) + return NULL; + + copy = (JSErrorReport *)cursor; + memset(cursor, 0, sizeof(JSErrorReport)); + cursor += sizeof(JSErrorReport); + + if (argsArraySize != 0) { + copy->messageArgs = (const jschar **)cursor; + cursor += argsArraySize; + for (i = 0; report->messageArgs[i]; ++i) { + copy->messageArgs[i] = (const jschar *)cursor; + argSize = JS_CHARS_SIZE(report->messageArgs[i]); + memcpy(cursor, report->messageArgs[i], argSize); + cursor += argSize; + } + copy->messageArgs[i] = NULL; + JS_ASSERT(cursor == (uint8 *)copy->messageArgs[0] + argsCopySize); + } + + if (report->ucmessage) { + copy->ucmessage = (const jschar *)cursor; + memcpy(cursor, report->ucmessage, ucmessageSize); + cursor += ucmessageSize; + } + + if (report->uclinebuf) { + copy->uclinebuf = (const jschar *)cursor; + memcpy(cursor, report->uclinebuf, uclinebufSize); + cursor += uclinebufSize; + if (report->uctokenptr) { + copy->uctokenptr = copy->uclinebuf + (report->uctokenptr - + report->uclinebuf); + } + } + + if (report->linebuf) { + copy->linebuf = (const char *)cursor; + memcpy(cursor, report->linebuf, linebufSize); + cursor += linebufSize; + if (report->tokenptr) { + copy->tokenptr = copy->linebuf + (report->tokenptr - + report->linebuf); + } + } + + if (report->filename) { + copy->filename = (const char *)cursor; + memcpy(cursor, report->filename, filenameSize); + } + JS_ASSERT(cursor + filenameSize == (uint8 *)copy + mallocSize); + + /* Copy non-pointer members. */ + copy->lineno = report->lineno; + copy->errorNumber = report->errorNumber; + + /* Note that this is before it gets flagged with JSREPORT_EXCEPTION */ + copy->flags = report->flags; + +#undef JS_CHARS_SIZE + return copy; +} + +static jsval * +GetStackTraceValueBuffer(JSExnPrivate *priv) +{ + /* + * We use extra memory after JSExnPrivateInfo.stackElems to store jsvals + * that helps to produce more informative stack traces. The following + * assert allows us to assume that no gap after stackElems is necessary to + * align the buffer properly. + */ + JS_STATIC_ASSERT(sizeof(JSStackTraceElem) % sizeof(jsval) == 0); + + return (jsval *)(priv->stackElems + priv->stackDepth); +} + +static JSBool +InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message, + JSString *filename, uintN lineno, JSErrorReport *report) +{ + JSSecurityCallbacks *callbacks; + CheckAccessOp checkAccess; + JSErrorReporter older; + JSExceptionState *state; + jsid callerid; + JSStackFrame *fp, *fpstop; + size_t stackDepth, valueCount, size; + JSBool overflow; + JSExnPrivate *priv; + JSStackTraceElem *elem; + jsval *values; + + JS_ASSERT(exnObject->getClass() == &js_ErrorClass); + + /* + * Prepare stack trace data. + * + * Set aside any error reporter for cx and save its exception state + * so we can suppress any checkAccess failures. Such failures should stop + * the backtrace procedure, not result in a failure of this constructor. + */ + callbacks = JS_GetSecurityCallbacks(cx); + checkAccess = callbacks + ? Valueify(callbacks->checkObjectAccess) + : NULL; + older = JS_SetErrorReporter(cx, NULL); + state = JS_SaveExceptionState(cx); + + callerid = ATOM_TO_JSID(cx->runtime->atomState.callerAtom); + stackDepth = 0; + valueCount = 0; + for (fp = js_GetTopStackFrame(cx); fp; fp = fp->prev()) { + if (fp->isFunctionFrame() && !fp->isEvalFrame()) { + Value v = NullValue(); + if (checkAccess && + !checkAccess(cx, &fp->callee(), callerid, JSACC_READ, &v)) { + break; + } + valueCount += fp->numActualArgs(); + } + ++stackDepth; + } + JS_RestoreExceptionState(cx, state); + JS_SetErrorReporter(cx, older); + fpstop = fp; + + size = offsetof(JSExnPrivate, stackElems); + overflow = (stackDepth > ((size_t)-1 - size) / sizeof(JSStackTraceElem)); + size += stackDepth * sizeof(JSStackTraceElem); + overflow |= (valueCount > ((size_t)-1 - size) / sizeof(jsval)); + size += valueCount * sizeof(jsval); + if (overflow) { + js_ReportAllocationOverflow(cx); + return JS_FALSE; + } + priv = (JSExnPrivate *)cx->malloc(size); + if (!priv) + return JS_FALSE; + + /* + * We initialize errorReport with a copy of report after setting the + * private slot, to prevent GC accessing a junk value we clear the field + * here. + */ + priv->errorReport = NULL; + priv->message = message; + priv->filename = filename; + priv->lineno = lineno; + priv->stackDepth = stackDepth; + + values = GetStackTraceValueBuffer(priv); + elem = priv->stackElems; + for (fp = js_GetTopStackFrame(cx); fp != fpstop; fp = fp->prev()) { + if (!fp->isFunctionFrame() || fp->isEvalFrame()) { + elem->funName = NULL; + elem->argc = 0; + } else { + elem->funName = fp->fun()->atom + ? ATOM_TO_STRING(fp->fun()->atom) + : cx->runtime->emptyString; + elem->argc = fp->numActualArgs(); + fp->forEachCanonicalActualArg(CopyTo(Valueify(values))); + values += elem->argc; + } + elem->ulineno = 0; + elem->filename = NULL; + if (fp->isScriptFrame()) { + elem->filename = fp->script()->filename; + if (fp->pc(cx)) + elem->ulineno = js_FramePCToLineNumber(cx, fp); + } + ++elem; + } + JS_ASSERT(priv->stackElems + stackDepth == elem); + JS_ASSERT(GetStackTraceValueBuffer(priv) + valueCount == values); + + exnObject->setPrivate(priv); + + if (report) { + /* + * Construct a new copy of the error report struct. We can't use the + * error report struct that was passed in, because it's allocated on + * the stack, and also because it may point to transient data in the + * TokenStream. + */ + priv->errorReport = CopyErrorReport(cx, report); + if (!priv->errorReport) { + /* The finalizer realeases priv since it is in the private slot. */ + return JS_FALSE; + } + } + + return JS_TRUE; +} + +static inline JSExnPrivate * +GetExnPrivate(JSContext *cx, JSObject *obj) +{ + return (JSExnPrivate *) obj->getPrivate(); +} + +static void +exn_trace(JSTracer *trc, JSObject *obj) +{ + JSExnPrivate *priv; + JSStackTraceElem *elem; + size_t vcount, i; + jsval *vp, v; + + priv = GetExnPrivate(trc->context, obj); + if (priv) { + if (priv->message) + MarkString(trc, priv->message, "exception message"); + if (priv->filename) + MarkString(trc, priv->filename, "exception filename"); + + elem = priv->stackElems; + for (vcount = i = 0; i != priv->stackDepth; ++i, ++elem) { + if (elem->funName) + MarkString(trc, elem->funName, "stack trace function name"); + if (IS_GC_MARKING_TRACER(trc) && elem->filename) + js_MarkScriptFilename(elem->filename); + vcount += elem->argc; + } + vp = GetStackTraceValueBuffer(priv); + for (i = 0; i != vcount; ++i, ++vp) { + v = *vp; + JS_CALL_VALUE_TRACER(trc, v, "stack trace argument"); + } + } +} + +static void +exn_finalize(JSContext *cx, JSObject *obj) +{ + JSExnPrivate *priv; + + priv = GetExnPrivate(cx, obj); + if (priv) { + if (priv->errorReport) + cx->free(priv->errorReport); + cx->free(priv); + } +} + +static JSBool +exn_enumerate(JSContext *cx, JSObject *obj) +{ + JSAtomState *atomState; + uintN i; + JSAtom *atom; + JSObject *pobj; + JSProperty *prop; + + JS_STATIC_ASSERT(sizeof(JSAtomState) <= (size_t)(uint16)-1); + static const uint16 offsets[] = { + (uint16)offsetof(JSAtomState, messageAtom), + (uint16)offsetof(JSAtomState, fileNameAtom), + (uint16)offsetof(JSAtomState, lineNumberAtom), + (uint16)offsetof(JSAtomState, stackAtom), + }; + + atomState = &cx->runtime->atomState; + for (i = 0; i != JS_ARRAY_LENGTH(offsets); ++i) { + atom = *(JSAtom **)((uint8 *)atomState + offsets[i]); + if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop)) + return JS_FALSE; + } + return JS_TRUE; +} + +static JSBool +exn_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSObject **objp) +{ + JSExnPrivate *priv; + JSString *str; + JSAtom *atom; + JSString *stack; + const char *prop; + jsval v; + + *objp = NULL; + priv = GetExnPrivate(cx, obj); + if (priv && JSID_IS_ATOM(id)) { + str = JSID_TO_STRING(id); + + atom = cx->runtime->atomState.messageAtom; + if (str == ATOM_TO_STRING(atom)) { + prop = js_message_str; + v = STRING_TO_JSVAL(priv->message); + goto define; + } + + atom = cx->runtime->atomState.fileNameAtom; + if (str == ATOM_TO_STRING(atom)) { + prop = js_fileName_str; + v = STRING_TO_JSVAL(priv->filename); + goto define; + } + + atom = cx->runtime->atomState.lineNumberAtom; + if (str == ATOM_TO_STRING(atom)) { + prop = js_lineNumber_str; + v = INT_TO_JSVAL(priv->lineno); + goto define; + } + + atom = cx->runtime->atomState.stackAtom; + if (str == ATOM_TO_STRING(atom)) { + stack = StackTraceToString(cx, priv); + if (!stack) + return JS_FALSE; + + /* Allow to GC all things that were used to build stack trace. */ + priv->stackDepth = 0; + prop = js_stack_str; + v = STRING_TO_JSVAL(stack); + goto define; + } + } + return JS_TRUE; + + define: + if (!JS_DefineProperty(cx, obj, prop, v, NULL, NULL, JSPROP_ENUMERATE)) + return JS_FALSE; + *objp = obj; + return JS_TRUE; +} + +JSErrorReport * +js_ErrorFromException(JSContext *cx, jsval exn) +{ + JSObject *obj; + JSExnPrivate *priv; + + if (JSVAL_IS_PRIMITIVE(exn)) + return NULL; + obj = JSVAL_TO_OBJECT(exn); + if (obj->getClass() != &js_ErrorClass) + return NULL; + priv = GetExnPrivate(cx, obj); + if (!priv) + return NULL; + return priv->errorReport; +} + +static JSString * +ValueToShortSource(JSContext *cx, jsval v) +{ + JSString *str; + + /* Avoid toSource bloat and fallibility for object types. */ + if (JSVAL_IS_PRIMITIVE(v)) + return js_ValueToSource(cx, Valueify(v)); + + AutoCompartment ac(cx, JSVAL_TO_OBJECT(v)); + if (!ac.enter()) + return NULL; + + if (VALUE_IS_FUNCTION(cx, v)) { + /* + * XXX Avoid function decompilation bloat for now. + */ + str = JS_GetFunctionId(JS_ValueToFunction(cx, v)); + if (!str && !(str = js_ValueToSource(cx, Valueify(v)))) { + /* + * Continue to soldier on if the function couldn't be + * converted into a string. + */ + JS_ClearPendingException(cx); + str = JS_NewStringCopyZ(cx, "[unknown function]"); + } + } else { + /* + * XXX Avoid toString on objects, it takes too long and uses too much + * memory, for too many classes (see Mozilla bug 166743). + */ + char buf[100]; + JS_snprintf(buf, sizeof buf, "[object %s]", + JSVAL_TO_OBJECT(v)->getClass()->name); + str = JS_NewStringCopyZ(cx, buf); + } + + ac.leave(); + + if (!str || !cx->compartment->wrap(cx, &str)) + return NULL; + return str; +} + +static JSString * +StackTraceToString(JSContext *cx, JSExnPrivate *priv) +{ + jschar *stackbuf; + size_t stacklen, stackmax; + JSStackTraceElem *elem, *endElem; + jsval *values; + size_t i; + JSString *str; + const char *cp; + char ulnbuf[11]; + + /* After this point, failing control flow must goto bad. */ + stackbuf = NULL; + stacklen = stackmax = 0; + +/* Limit the stackbuf length to a reasonable value to avoid overflow checks. */ +#define STACK_LENGTH_LIMIT JS_BIT(20) + +#define APPEND_CHAR_TO_STACK(c) \ + JS_BEGIN_MACRO \ + if (stacklen == stackmax) { \ + void *ptr_; \ + if (stackmax >= STACK_LENGTH_LIMIT) \ + goto done; \ + stackmax = stackmax ? 2 * stackmax : 64; \ + ptr_ = cx->realloc(stackbuf, (stackmax+1) * sizeof(jschar)); \ + if (!ptr_) \ + goto bad; \ + stackbuf = (jschar *) ptr_; \ + } \ + stackbuf[stacklen++] = (c); \ + JS_END_MACRO + +#define APPEND_STRING_TO_STACK(str) \ + JS_BEGIN_MACRO \ + JSString *str_ = str; \ + size_t length_ = str_->length(); \ + const jschar *chars_ = str_->getChars(cx); \ + if (!chars_) \ + goto bad; \ + \ + if (length_ > stackmax - stacklen) { \ + void *ptr_; \ + if (stackmax >= STACK_LENGTH_LIMIT || \ + length_ >= STACK_LENGTH_LIMIT - stacklen) { \ + goto done; \ + } \ + stackmax = JS_BIT(JS_CeilingLog2(stacklen + length_)); \ + ptr_ = cx->realloc(stackbuf, (stackmax+1) * sizeof(jschar)); \ + if (!ptr_) \ + goto bad; \ + stackbuf = (jschar *) ptr_; \ + } \ + js_strncpy(stackbuf + stacklen, chars_, length_); \ + stacklen += length_; \ + JS_END_MACRO + + values = GetStackTraceValueBuffer(priv); + elem = priv->stackElems; + for (endElem = elem + priv->stackDepth; elem != endElem; elem++) { + if (elem->funName) { + APPEND_STRING_TO_STACK(elem->funName); + APPEND_CHAR_TO_STACK('('); + for (i = 0; i != elem->argc; i++, values++) { + if (i > 0) + APPEND_CHAR_TO_STACK(','); + str = ValueToShortSource(cx, *values); + if (!str) + goto bad; + APPEND_STRING_TO_STACK(str); + } + APPEND_CHAR_TO_STACK(')'); + } + APPEND_CHAR_TO_STACK('@'); + if (elem->filename) { + for (cp = elem->filename; *cp; cp++) + APPEND_CHAR_TO_STACK(*cp); + } + APPEND_CHAR_TO_STACK(':'); + JS_snprintf(ulnbuf, sizeof ulnbuf, "%u", elem->ulineno); + for (cp = ulnbuf; *cp; cp++) + APPEND_CHAR_TO_STACK(*cp); + APPEND_CHAR_TO_STACK('\n'); + } +#undef APPEND_CHAR_TO_STACK +#undef APPEND_STRING_TO_STACK +#undef STACK_LENGTH_LIMIT + + done: + if (stacklen == 0) { + JS_ASSERT(!stackbuf); + return cx->runtime->emptyString; + } + if (stacklen < stackmax) { + /* + * Realloc can fail when shrinking on some FreeBSD versions, so + * don't use JS_realloc here; simply let the oversized allocation + * be owned by the string in that rare case. + */ + void *shrunk = cx->realloc(stackbuf, (stacklen+1) * sizeof(jschar)); + if (shrunk) + stackbuf = (jschar *) shrunk; + } + + stackbuf[stacklen] = 0; + str = js_NewString(cx, stackbuf, stacklen); + if (str) + return str; + + bad: + if (stackbuf) + cx->free(stackbuf); + return NULL; +} + +/* XXXbe Consolidate the ugly truth that we don't treat filename as UTF-8 + with these two functions. */ +static JSString * +FilenameToString(JSContext *cx, const char *filename) +{ + return JS_NewStringCopyZ(cx, filename); +} + +static JSBool +Exception(JSContext *cx, uintN argc, Value *vp) +{ + JSString *message, *filename; + JSStackFrame *fp; + + /* + * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when + * called as functions, without operator new. But as we do not give + * each constructor a distinct JSClass, whose .name member is used by + * NewNativeClassInstance to find the class prototype, we must get the + * class prototype ourselves. + */ + JSObject &callee = vp[0].toObject(); + Value protov; + if (!callee.getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &protov)) + return JS_FALSE; + + if (!protov.isObject()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE, "Error"); + return JS_FALSE; + } + + JSObject *errProto = &protov.toObject(); + JSObject *obj = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent()); + if (!obj) + return JS_FALSE; + + /* + * If it's a new object of class Exception, then null out the private + * data so that the finalizer doesn't attempt to free it. + */ + if (obj->getClass() == &js_ErrorClass) + obj->setPrivate(NULL); + + /* Set the 'message' property. */ + Value *argv = vp + 2; + if (argc != 0) { + message = js_ValueToString(cx, argv[0]); + if (!message) + return JS_FALSE; + argv[0].setString(message); + } else { + message = cx->runtime->emptyString; + } + + /* Set the 'fileName' property. */ + if (argc > 1) { + filename = js_ValueToString(cx, argv[1]); + if (!filename) + return JS_FALSE; + argv[1].setString(filename); + fp = NULL; + } else { + fp = js_GetScriptedCaller(cx, NULL); + if (fp) { + filename = FilenameToString(cx, fp->script()->filename); + if (!filename) + return JS_FALSE; + } else { + filename = cx->runtime->emptyString; + } + } + + /* Set the 'lineNumber' property. */ + uint32_t lineno; + if (argc > 2) { + if (!ValueToECMAUint32(cx, argv[2], &lineno)) + return JS_FALSE; + } else { + if (!fp) + fp = js_GetScriptedCaller(cx, NULL); + lineno = (fp && fp->pc(cx)) ? js_FramePCToLineNumber(cx, fp) : 0; + } + + if (obj->getClass() == &js_ErrorClass && + !InitExnPrivate(cx, obj, message, filename, lineno, NULL)) { + return JS_FALSE; + } + + vp->setObject(*obj); + return JS_TRUE; +} + +/* + * Convert to string. + * + * This method only uses JavaScript-modifiable properties name, message. It + * is left to the host to check for private data and report filename and line + * number information along with this message. + */ +static JSBool +exn_toString(JSContext *cx, uintN argc, Value *vp) +{ + jsval v; + JSString *name, *message, *result; + jschar *chars, *cp; + size_t name_length, message_length, length; + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return JS_FALSE; + if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), Valueify(&v))) + return JS_FALSE; + name = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) : cx->runtime->emptyString; + vp->setString(name); + + if (!JS_GetProperty(cx, obj, js_message_str, &v)) + return JS_FALSE; + message = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) + : cx->runtime->emptyString; + + if (message->length() != 0) { + name_length = name->length(); + message_length = message->length(); + length = (name_length ? name_length + 2 : 0) + message_length; + cp = chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar)); + if (!chars) + return JS_FALSE; + + if (name_length) { + const jschar *name_chars = name->getChars(cx); + if (!name_chars) + return JS_FALSE; + js_strncpy(cp, name_chars, name_length); + cp += name_length; + *cp++ = ':'; *cp++ = ' '; + } + const jschar *message_chars = message->getChars(cx); + if (!message_chars) + return JS_FALSE; + js_strncpy(cp, message_chars, message_length); + cp += message_length; + *cp = 0; + + result = js_NewString(cx, chars, length); + if (!result) { + cx->free(chars); + return JS_FALSE; + } + } else { + result = name; + } + + vp->setString(result); + return JS_TRUE; +} + +#if JS_HAS_TOSOURCE +/* + * Return a string that may eval to something similar to the original object. + */ +static JSBool +exn_toSource(JSContext *cx, uintN argc, Value *vp) +{ + JSString *name, *message, *filename, *lineno_as_str, *result; + jsval localroots[3] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; + size_t lineno_length, name_length, message_length, filename_length, length; + jschar *chars, *cp; + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), vp)) + return false; + name = js_ValueToString(cx, *vp); + if (!name) + return false; + vp->setString(name); + + { + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroots), Valueify(localroots)); + +#ifdef __GNUC__ + message = filename = NULL; +#endif + if (!JS_GetProperty(cx, obj, js_message_str, &localroots[0]) || + !(message = js_ValueToSource(cx, Valueify(localroots[0])))) { + return false; + } + localroots[0] = STRING_TO_JSVAL(message); + + if (!JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) || + !(filename = js_ValueToSource(cx, Valueify(localroots[1])))) { + return false; + } + localroots[1] = STRING_TO_JSVAL(filename); + + if (!JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2])) + return false; + uint32_t lineno; + if (!ValueToECMAUint32(cx, Valueify(localroots[2]), &lineno)) + return false; + + if (lineno != 0) { + lineno_as_str = js_ValueToString(cx, Valueify(localroots[2])); + if (!lineno_as_str) + return false; + lineno_length = lineno_as_str->length(); + } else { + lineno_as_str = NULL; + lineno_length = 0; + } + + /* Magic 8, for the characters in ``(new ())''. */ + name_length = name->length(); + message_length = message->length(); + length = 8 + name_length + message_length; + + filename_length = filename->length(); + if (filename_length != 0) { + /* append filename as ``, {filename}'' */ + length += 2 + filename_length; + if (lineno_as_str) { + /* append lineno as ``, {lineno_as_str}'' */ + length += 2 + lineno_length; + } + } else { + if (lineno_as_str) { + /* + * no filename, but have line number, + * need to append ``, "", {lineno_as_str}'' + */ + length += 6 + lineno_length; + } + } + + cp = chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar)); + if (!chars) + return false; + + *cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' '; + const jschar *name_chars = name->getChars(cx); + if (!name_chars) + return false; + js_strncpy(cp, name_chars, name_length); + cp += name_length; + *cp++ = '('; + const jschar *message_chars = message->getChars(cx); + if (!message_chars) + return false; + if (message_length != 0) { + js_strncpy(cp, message_chars, message_length); + cp += message_length; + } + + if (filename_length != 0) { + /* append filename as ``, {filename}'' */ + *cp++ = ','; *cp++ = ' '; + const jschar *filename_chars = filename->getChars(cx); + if (!filename_chars) + return false; + js_strncpy(cp, filename_chars, filename_length); + cp += filename_length; + } else { + if (lineno_as_str) { + /* + * no filename, but have line number, + * need to append ``, "", {lineno_as_str}'' + */ + *cp++ = ','; *cp++ = ' '; *cp++ = '"'; *cp++ = '"'; + } + } + if (lineno_as_str) { + /* append lineno as ``, {lineno_as_str}'' */ + *cp++ = ','; *cp++ = ' '; + const jschar *lineno_chars = lineno_as_str->getChars(cx); + if (!lineno_chars) + return false; + js_strncpy(cp, lineno_chars, lineno_length); + cp += lineno_length; + } + + *cp++ = ')'; *cp++ = ')'; *cp = 0; + + result = js_NewString(cx, chars, length); + if (!result) { + cx->free(chars); + return false; + } + vp->setString(result); + return true; + } +} +#endif + +static JSFunctionSpec exception_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, exn_toSource, 0,0), +#endif + JS_FN(js_toString_str, exn_toString, 0,0), + JS_FS_END +}; + +/* JSProto_ ordering for exceptions shall match JSEXN_ constants. */ +JS_STATIC_ASSERT(JSEXN_ERR == 0); +JS_STATIC_ASSERT(JSProto_Error + JSEXN_INTERNALERR == JSProto_InternalError); +JS_STATIC_ASSERT(JSProto_Error + JSEXN_EVALERR == JSProto_EvalError); +JS_STATIC_ASSERT(JSProto_Error + JSEXN_RANGEERR == JSProto_RangeError); +JS_STATIC_ASSERT(JSProto_Error + JSEXN_REFERENCEERR == JSProto_ReferenceError); +JS_STATIC_ASSERT(JSProto_Error + JSEXN_SYNTAXERR == JSProto_SyntaxError); +JS_STATIC_ASSERT(JSProto_Error + JSEXN_TYPEERR == JSProto_TypeError); +JS_STATIC_ASSERT(JSProto_Error + JSEXN_URIERR == JSProto_URIError); + +static JS_INLINE JSProtoKey +GetExceptionProtoKey(intN exn) +{ + JS_ASSERT(JSEXN_ERR <= exn); + JS_ASSERT(exn < JSEXN_LIMIT); + return (JSProtoKey) (JSProto_Error + exn); +} + +JSObject * +js_InitExceptionClasses(JSContext *cx, JSObject *obj) +{ + /* + * If lazy class initialization occurs for any Error subclass, then all + * classes are initialized, starting with Error. To avoid reentry and + * redundant initialization, we must not pass a null proto parameter to + * NewNonFunction below, when called for the Error superclass. We need to + * ensure that Object.prototype is the proto of Error.prototype. + * + * See the equivalent code to ensure that parent_proto is non-null when + * js_InitClass calls NewObject, in jsobj.cpp. + */ + JSObject *obj_proto; + if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto)) + return NULL; + + /* Define all error constructors. */ + Value empty = StringValue(cx->runtime->emptyString); + jsid nameId = ATOM_TO_JSID(cx->runtime->atomState.nameAtom); + jsid messageId = ATOM_TO_JSID(cx->runtime->atomState.messageAtom); + jsid fileNameId = ATOM_TO_JSID(cx->runtime->atomState.fileNameAtom); + jsid lineNumberId = ATOM_TO_JSID(cx->runtime->atomState.lineNumberAtom); + JSObject *error_proto = NULL; + for (intN i = JSEXN_ERR; i != JSEXN_LIMIT; i++) { + JSProtoKey protoKey = GetExceptionProtoKey(i); + JSAtom *atom = cx->runtime->atomState.classAtoms[protoKey]; + JSObject *proto = + DefineConstructorAndPrototype(cx, obj, protoKey, atom, + (i == JSEXN_ERR) ? obj_proto : error_proto, + &js_ErrorClass, Exception, 1, + NULL, (i == JSEXN_ERR) ? exception_methods : NULL, + NULL, NULL); + if (!proto) + return NULL; + JS_ASSERT(proto->privateData == NULL); + + if (i == JSEXN_ERR) + error_proto = proto; + + /* Add properties to the prototype. */ + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING); + if (!js_DefineNativeProperty(cx, proto, nameId, StringValue(atom), + PropertyStub, StrictPropertyStub, + JSPROP_ENUMERATE, 0, 0, NULL) || + !js_DefineNativeProperty(cx, proto, messageId, empty, + PropertyStub, StrictPropertyStub, + JSPROP_ENUMERATE, 0, 0, NULL) || + !js_DefineNativeProperty(cx, proto, fileNameId, empty, + PropertyStub, StrictPropertyStub, + JSPROP_ENUMERATE, 0, 0, NULL) || + !js_DefineNativeProperty(cx, proto, lineNumberId, Valueify(JSVAL_ZERO), + PropertyStub, StrictPropertyStub, + JSPROP_ENUMERATE, 0, 0, NULL)) { + return NULL; + } + } + + return error_proto; +} + +const JSErrorFormatString* +js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale, + const uintN errorNumber) +{ + const JSErrorFormatString *errorString = NULL; + + if (cx->localeCallbacks && cx->localeCallbacks->localeGetErrorMessage) { + errorString = cx->localeCallbacks + ->localeGetErrorMessage(userRef, locale, errorNumber); + } + if (!errorString) + errorString = js_GetErrorMessage(userRef, locale, errorNumber); + return errorString; +} + +#if defined ( DEBUG_mccabe ) && defined ( PRINTNAMES ) +/* For use below... get character strings for error name and exception name */ +static struct exnname { char *name; char *exception; } errortoexnname[] = { +#define MSG_DEF(name, number, count, exception, format) \ + {#name, #exception}, +#include "js.msg" +#undef MSG_DEF +}; +#endif /* DEBUG */ + +JSBool +js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, + JSErrorCallback callback, void *userRef) +{ + JSErrNum errorNumber; + const JSErrorFormatString *errorString; + JSExnType exn; + jsval tv[4]; + JSBool ok; + JSObject *errProto, *errObject; + JSString *messageStr, *filenameStr; + + /* + * Tell our caller to report immediately if this report is just a warning. + */ + JS_ASSERT(reportp); + if (JSREPORT_IS_WARNING(reportp->flags)) + return JS_FALSE; + + /* Find the exception index associated with this error. */ + errorNumber = (JSErrNum) reportp->errorNumber; + if (!callback || callback == js_GetErrorMessage) + errorString = js_GetLocalizedErrorMessage(cx, NULL, NULL, errorNumber); + else + errorString = callback(userRef, NULL, errorNumber); + exn = errorString ? (JSExnType) errorString->exnType : JSEXN_NONE; + JS_ASSERT(exn < JSEXN_LIMIT); + +#if defined( DEBUG_mccabe ) && defined ( PRINTNAMES ) + /* Print the error name and the associated exception name to stderr */ + fprintf(stderr, "%s\t%s\n", + errortoexnname[errorNumber].name, + errortoexnname[errorNumber].exception); +#endif + + /* + * Return false (no exception raised) if no exception is associated + * with the given error number. + */ + if (exn == JSEXN_NONE) + return JS_FALSE; + + /* + * Prevent runaway recursion, via cx->generatingError. If an out-of-memory + * error occurs, no exception object will be created, but we don't assume + * that OOM is the only kind of error that subroutines of this function + * called below might raise. + */ + if (cx->generatingError) + return JS_FALSE; + + MUST_FLOW_THROUGH("out"); + cx->generatingError = JS_TRUE; + + /* Protect the newly-created strings below from nesting GCs. */ + PodArrayZero(tv); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tv), Valueify(tv)); + + /* + * Try to get an appropriate prototype by looking up the corresponding + * exception constructor name in the scope chain of the current context's + * top stack frame, or in the global object if no frame is active. + */ + ok = js_GetClassPrototype(cx, NULL, GetExceptionProtoKey(exn), &errProto); + if (!ok) + goto out; + tv[0] = OBJECT_TO_JSVAL(errProto); + + errObject = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent()); + if (!errObject) { + ok = JS_FALSE; + goto out; + } + tv[1] = OBJECT_TO_JSVAL(errObject); + + messageStr = JS_NewStringCopyZ(cx, message); + if (!messageStr) { + ok = JS_FALSE; + goto out; + } + tv[2] = STRING_TO_JSVAL(messageStr); + + filenameStr = JS_NewStringCopyZ(cx, reportp->filename); + if (!filenameStr) { + ok = JS_FALSE; + goto out; + } + tv[3] = STRING_TO_JSVAL(filenameStr); + + ok = InitExnPrivate(cx, errObject, messageStr, filenameStr, + reportp->lineno, reportp); + if (!ok) + goto out; + + JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject)); + + /* Flag the error report passed in to indicate an exception was raised. */ + reportp->flags |= JSREPORT_EXCEPTION; + +out: + cx->generatingError = JS_FALSE; + return ok; +} + +JSBool +js_ReportUncaughtException(JSContext *cx) +{ + jsval exn; + JSObject *exnObject; + jsval roots[5]; + JSErrorReport *reportp, report; + JSString *str; + const char *bytes; + + if (!JS_IsExceptionPending(cx)) + return true; + + if (!JS_GetPendingException(cx, &exn)) + return false; + + PodArrayZero(roots); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), Valueify(roots)); + + /* + * Because js_ValueToString below could error and an exception object + * could become unrooted, we must root exnObject. Later, if exnObject is + * non-null, we need to root other intermediates, so allocate an operand + * stack segment to protect all of these values. + */ + if (JSVAL_IS_PRIMITIVE(exn)) { + exnObject = NULL; + } else { + exnObject = JSVAL_TO_OBJECT(exn); + roots[0] = exn; + } + + JS_ClearPendingException(cx); + reportp = js_ErrorFromException(cx, exn); + + /* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */ + str = js_ValueToString(cx, Valueify(exn)); + JSAutoByteString bytesStorage; + if (!str) { + bytes = "unknown (can't convert to string)"; + } else { + roots[1] = STRING_TO_JSVAL(str); + if (!bytesStorage.encode(cx, str)) + return false; + bytes = bytesStorage.ptr(); + } + + JSAutoByteString filename; + if (!reportp && exnObject && exnObject->getClass() == &js_ErrorClass) { + if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2])) + return false; + if (JSVAL_IS_STRING(roots[2])) { + bytesStorage.clear(); + if (!bytesStorage.encode(cx, str)) + return false; + bytes = bytesStorage.ptr(); + } + + if (!JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3])) + return false; + str = js_ValueToString(cx, Valueify(roots[3])); + if (!str || !filename.encode(cx, str)) + return false; + + if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4])) + return false; + uint32_t lineno; + if (!ValueToECMAUint32(cx, Valueify(roots[4]), &lineno)) + return false; + + reportp = &report; + PodZero(&report); + report.filename = filename.ptr(); + report.lineno = (uintN) lineno; + if (JSVAL_IS_STRING(roots[2])) { + report.ucmessage = js_GetStringChars(cx, JSVAL_TO_STRING(roots[2])); + if (!report.ucmessage) + return false; + } + } + + if (!reportp) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_UNCAUGHT_EXCEPTION, bytes); + } else { + /* Flag the error as an exception. */ + reportp->flags |= JSREPORT_EXCEPTION; + + /* Pass the exception object. */ + JS_SetPendingException(cx, exn); + js_ReportErrorAgain(cx, bytes, reportp); + JS_ClearPendingException(cx); + } + + return true; +} diff --git a/js/src/jsexn.h b/js/src/jsexn.h new file mode 100644 index 0000000..1d08b34 --- /dev/null +++ b/js/src/jsexn.h @@ -0,0 +1,93 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS runtime exception classes. + */ + +#ifndef jsexn_h___ +#define jsexn_h___ + +extern js::Class js_ErrorClass; + +/* + * Initialize the exception constructor/prototype hierarchy. + */ +extern JSObject * +js_InitExceptionClasses(JSContext *cx, JSObject *obj); + +/* + * Given a JSErrorReport, check to see if there is an exception associated with + * the error number. If there is, then create an appropriate exception object, + * set it as the pending exception, and set the JSREPORT_EXCEPTION flag on the + * error report. Exception-aware host error reporters should probably ignore + * error reports so flagged. Returns JS_TRUE if an associated exception is + * found and set, JS_FALSE otherwise. + */ +extern JSBool +js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, + JSErrorCallback callback, void *userRef); + +/* + * Called if a JS API call to js_Execute or js_InternalCall fails; calls the + * error reporter with the error report associated with any uncaught exception + * that has been raised. Returns true if there was an exception pending, and + * the error reporter was actually called. + * + * The JSErrorReport * that the error reporter is called with is currently + * associated with a JavaScript object, and is not guaranteed to persist after + * the object is collected. Any persistent uses of the JSErrorReport contents + * should make their own copy. + * + * The flags field of the JSErrorReport will have the JSREPORT_EXCEPTION flag + * set; embeddings that want to silently propagate JavaScript exceptions to + * other contexts may want to use an error reporter that ignores errors with + * this flag. + */ +extern JSBool +js_ReportUncaughtException(JSContext *cx); + +extern JSErrorReport * +js_ErrorFromException(JSContext *cx, jsval exn); + +extern const JSErrorFormatString * +js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale, + const uintN errorNumber); + +#endif /* jsexn_h___ */ diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp new file mode 100644 index 0000000..840376d --- /dev/null +++ b/js/src/jsfriendapi.cpp @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jscntxt.h" +#include "jsfriendapi.h" + +JS_FRIEND_API(JSString *) +JS_GetAnonymousString(JSRuntime *rt) +{ + JS_ASSERT(rt->state == JSRTS_UP); + return ATOM_TO_STRING(rt->atomState.anonymousAtom); +} diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h new file mode 100644 index 0000000..a609381 --- /dev/null +++ b/js/src/jsfriendapi.h @@ -0,0 +1,53 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * + * The Original Code is SpiderMonkey code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsfriendapi_h___ +#define jsfriendapi_h___ + +#include "jspubtd.h" +#include "jsprvtd.h" + +JS_BEGIN_EXTERN_C + +extern JS_FRIEND_API(JSString *) +JS_GetAnonymousString(JSRuntime *rt); + +JS_END_EXTERN_C + +#endif /* jsfriendapi_h___ */ diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp new file mode 100644 index 0000000..d9dd529 --- /dev/null +++ b/js/src/jsfun.cpp @@ -0,0 +1,3052 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS function support. + */ +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsbit.h" +#include "jsutil.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jspropertytree.h" +#include "jsproxy.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jsexn.h" +#include "jsstaticcheck.h" +#include "jstracer.h" + +#if JS_HAS_GENERATORS +# include "jsiter.h" +#endif + +#if JS_HAS_XDR +# include "jsxdrapi.h" +#endif + +#ifdef JS_METHODJIT +#include "methodjit/MethodJIT.h" +#endif + +#include "jsatominlines.h" +#include "jscntxtinlines.h" +#include "jsfuninlines.h" +#include "jsinterpinlines.h" +#include "jsobjinlines.h" +#include "jsscriptinlines.h" + +using namespace js; +using namespace js::gc; + +inline JSObject * +JSObject::getThrowTypeError() const +{ + return &getGlobal()->getReservedSlot(JSRESERVED_GLOBAL_THROWTYPEERROR).toObject(); +} + +JSBool +js_GetArgsValue(JSContext *cx, JSStackFrame *fp, Value *vp) +{ + JSObject *argsobj; + + if (fp->hasOverriddenArgs()) { + JS_ASSERT(fp->hasCallObj()); + jsid id = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom); + return fp->callObj().getProperty(cx, id, vp); + } + argsobj = js_GetArgsObject(cx, fp); + if (!argsobj) + return JS_FALSE; + vp->setObject(*argsobj); + return JS_TRUE; +} + +JSBool +js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, Value *vp) +{ + JS_ASSERT(fp->isFunctionFrame()); + + if (fp->hasOverriddenArgs()) { + JS_ASSERT(fp->hasCallObj()); + + jsid argumentsid = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom); + Value v; + if (!fp->callObj().getProperty(cx, argumentsid, &v)) + return false; + + JSObject *obj; + if (v.isPrimitive()) { + obj = js_ValueToNonNullObject(cx, v); + if (!obj) + return false; + } else { + obj = &v.toObject(); + } + return obj->getProperty(cx, id, vp); + } + + vp->setUndefined(); + if (JSID_IS_INT(id)) { + uint32 arg = uint32(JSID_TO_INT(id)); + JSObject *argsobj = fp->maybeArgsObj(); + if (arg < fp->numActualArgs()) { + if (argsobj) { + if (argsobj->getArgsElement(arg).isMagic(JS_ARGS_HOLE)) + return argsobj->getProperty(cx, id, vp); + } + *vp = fp->canonicalActualArg(arg); + } else { + /* + * Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share + * storage between the formal parameter and arguments[k] for all + * fp->argc <= k && k < fp->fun->nargs. For example, in + * + * function f(x) { x = 42; return arguments[0]; } + * f(); + * + * the call to f should return undefined, not 42. If fp->argsobj + * is null at this point, as it would be in the example, return + * undefined in *vp. + */ + if (argsobj) + return argsobj->getProperty(cx, id, vp); + } + } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + JSObject *argsobj = fp->maybeArgsObj(); + if (argsobj && argsobj->isArgsLengthOverridden()) + return argsobj->getProperty(cx, id, vp); + vp->setInt32(fp->numActualArgs()); + } + return true; +} + +static JSObject * +NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee) +{ + JSObject *proto; + if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto)) + return NULL; + + JS_STATIC_ASSERT(JSObject::ARGS_CLASS_RESERVED_SLOTS == 2); + JSObject *argsobj = js_NewGCObject(cx, FINALIZE_OBJECT2); + if (!argsobj) + return NULL; + + ArgumentsData *data = (ArgumentsData *) + cx->malloc(offsetof(ArgumentsData, slots) + argc * sizeof(Value)); + if (!data) + return NULL; + SetValueRangeToUndefined(data->slots, argc); + + /* Can't fail from here on, so initialize everything in argsobj. */ + argsobj->init(cx, callee.getFunctionPrivate()->inStrictMode() + ? &StrictArgumentsClass + : &js_ArgumentsClass, + proto, parent, NULL, false); + + argsobj->setMap(cx->compartment->emptyArgumentsShape); + + argsobj->setArgsLength(argc); + argsobj->setArgsData(data); + data->callee.setObject(callee); + + return argsobj; +} + +struct STATIC_SKIP_INFERENCE PutArg +{ + PutArg(Value *dst) : dst(dst) {} + Value *dst; + void operator()(uintN, Value *src) { + if (!dst->isMagic(JS_ARGS_HOLE)) + *dst = *src; + ++dst; + } +}; + +JSObject * +js_GetArgsObject(JSContext *cx, JSStackFrame *fp) +{ + /* + * We must be in a function activation; the function must be lightweight + * or else fp must have a variable object. + */ + JS_ASSERT_IF(fp->fun()->isHeavyweight(), fp->hasCallObj()); + + while (fp->isEvalOrDebuggerFrame()) + fp = fp->prev(); + + /* Create an arguments object for fp only if it lacks one. */ + if (fp->hasArgsObj()) + return &fp->argsObj(); + + /* Compute the arguments object's parent slot from fp's scope chain. */ + JSObject *global = fp->scopeChain().getGlobal(); + JSObject *argsobj = NewArguments(cx, global, fp->numActualArgs(), fp->callee()); + if (!argsobj) + return argsobj; + + /* + * Strict mode functions have arguments objects that copy the initial + * actual parameter values. It is the caller's responsibility to get the + * arguments object before any parameters are modified! (The emitter + * ensures this by synthesizing an arguments access at the start of any + * strict mode function that contains an assignment to a parameter, or + * that calls eval.) Non-strict mode arguments use the frame pointer to + * retrieve up-to-date parameter values. + */ + if (argsobj->isStrictArguments()) + fp->forEachCanonicalActualArg(PutArg(argsobj->getArgsData()->slots)); + else + argsobj->setPrivate(fp); + + fp->setArgsObj(*argsobj); + return argsobj; +} + +void +js_PutArgsObject(JSContext *cx, JSStackFrame *fp) +{ + JSObject &argsobj = fp->argsObj(); + if (argsobj.isNormalArguments()) { + JS_ASSERT(argsobj.getPrivate() == fp); + fp->forEachCanonicalActualArg(PutArg(argsobj.getArgsData()->slots)); + argsobj.setPrivate(NULL); + } else { + JS_ASSERT(!argsobj.getPrivate()); + } + fp->clearArgsObj(); +} + +#ifdef JS_TRACER + +/* + * Traced versions of js_GetArgsObject and js_PutArgsObject. + */ +JSObject * JS_FASTCALL +js_NewArgumentsOnTrace(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee) +{ + JSObject *argsobj = NewArguments(cx, parent, argc, *callee); + if (!argsobj) + return NULL; + + if (argsobj->isStrictArguments()) { + /* + * Strict mode callers must copy arguments into the created arguments + * object. The trace-JITting code is in TraceRecorder::newArguments. + */ + JS_ASSERT(!argsobj->getPrivate()); + } else { + argsobj->setPrivate(JS_ARGUMENTS_OBJECT_ON_TRACE); + } + + return argsobj; +} +JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewArgumentsOnTrace, CONTEXT, OBJECT, UINT32, OBJECT, + 0, nanojit::ACCSET_STORE_ANY) + +/* FIXME change the return type to void. */ +JSBool JS_FASTCALL +js_PutArgumentsOnTrace(JSContext *cx, JSObject *argsobj, Value *args) +{ + JS_ASSERT(argsobj->isNormalArguments()); + JS_ASSERT(argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE); + + /* + * TraceRecorder::putActivationObjects builds a single, contiguous array of + * the arguments, regardless of whether #actuals > #formals so there is no + * need to worry about actual vs. formal arguments. + */ + Value *srcend = args + argsobj->getArgsInitialLength(); + Value *dst = argsobj->getArgsData()->slots; + for (Value *src = args; src != srcend; ++src, ++dst) { + if (!dst->isMagic(JS_ARGS_HOLE)) + *dst = *src; + } + + argsobj->setPrivate(NULL); + return true; +} +JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArgumentsOnTrace, CONTEXT, OBJECT, VALUEPTR, 0, + nanojit::ACCSET_STORE_ANY) + +#endif /* JS_TRACER */ + +static JSBool +args_delProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + JS_ASSERT(obj->isArguments()); + + if (JSID_IS_INT(id)) { + uintN arg = uintN(JSID_TO_INT(id)); + if (arg < obj->getArgsInitialLength()) + obj->setArgsElement(arg, MagicValue(JS_ARGS_HOLE)); + } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + obj->setArgsLengthOverridden(); + } else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) { + obj->setArgsCallee(MagicValue(JS_ARGS_HOLE)); + } + return true; +} + +static JS_REQUIRES_STACK JSObject * +WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSFunction *fun) +{ + JS_ASSERT(fun->optimizedClosure()); + JS_ASSERT(!fun->u.i.wrapper); + + /* + * We do not attempt to reify Call and Block objects on demand for outer + * scopes. This could be done (see the "v8" patch in bug 494235) but it is + * fragile in the face of ongoing compile-time optimization. Instead, the + * _DBG* opcodes used by wrappers created here must cope with unresolved + * upvars and throw them as reference errors. Caveat debuggers! + */ + JSObject *scopeChain = GetScopeChain(cx, fp); + if (!scopeChain) + return NULL; + + JSObject *wfunobj = NewFunction(cx, scopeChain); + if (!wfunobj) + return NULL; + AutoObjectRooter tvr(cx, wfunobj); + + JSFunction *wfun = (JSFunction *) wfunobj; + wfunobj->setPrivate(wfun); + wfun->nargs = fun->nargs; + wfun->flags = fun->flags | JSFUN_HEAVYWEIGHT; + wfun->u.i.skipmin = fun->u.i.skipmin; + wfun->u.i.wrapper = true; + wfun->u.i.script = NULL; + wfun->atom = fun->atom; + + JSScript *script = fun->script(); + jssrcnote *snbase = script->notes(); + jssrcnote *sn = snbase; + while (!SN_IS_TERMINATOR(sn)) + sn = SN_NEXT(sn); + uintN nsrcnotes = (sn - snbase) + 1; + + /* NB: GC must not occur before wscript is homed in wfun->u.i.script. */ + JSScript *wscript = JSScript::NewScript(cx, script->length, nsrcnotes, + script->atomMap.length, + JSScript::isValidOffset(script->objectsOffset) + ? script->objects()->length + : 0, + script->bindings.countUpvars(), + JSScript::isValidOffset(script->regexpsOffset) + ? script->regexps()->length + : 0, + JSScript::isValidOffset(script->trynotesOffset) + ? script->trynotes()->length + : 0, + JSScript::isValidOffset(script->constOffset) + ? script->consts()->length + : 0, + JSScript::isValidOffset(script->globalsOffset) + ? script->globals()->length + : 0, + script->nClosedArgs, + script->nClosedVars, + script->getVersion()); + if (!wscript) + return NULL; + + memcpy(wscript->code, script->code, script->length); + wscript->main = wscript->code + (script->main - script->code); + + memcpy(wscript->notes(), snbase, nsrcnotes * sizeof(jssrcnote)); + memcpy(wscript->atomMap.vector, script->atomMap.vector, + wscript->atomMap.length * sizeof(JSAtom *)); + if (JSScript::isValidOffset(script->objectsOffset)) { + memcpy(wscript->objects()->vector, script->objects()->vector, + wscript->objects()->length * sizeof(JSObject *)); + } + if (JSScript::isValidOffset(script->regexpsOffset)) { + memcpy(wscript->regexps()->vector, script->regexps()->vector, + wscript->regexps()->length * sizeof(JSObject *)); + } + if (JSScript::isValidOffset(script->trynotesOffset)) { + memcpy(wscript->trynotes()->vector, script->trynotes()->vector, + wscript->trynotes()->length * sizeof(JSTryNote)); + } + if (JSScript::isValidOffset(script->globalsOffset)) { + memcpy(wscript->globals()->vector, script->globals()->vector, + wscript->globals()->length * sizeof(GlobalSlotArray::Entry)); + } + if (script->nClosedArgs + script->nClosedVars != 0) + script->copyClosedSlotsTo(wscript); + + if (script->bindings.hasUpvars()) { + JS_ASSERT(script->bindings.countUpvars() == wscript->upvars()->length); + memcpy(wscript->upvars()->vector, script->upvars()->vector, + script->bindings.countUpvars() * sizeof(uint32)); + } + + jsbytecode *pc = wscript->code; + while (*pc != JSOP_STOP) { + /* FIXME should copy JSOP_TRAP? */ + JSOp op = js_GetOpcode(cx, wscript, pc); + const JSCodeSpec *cs = &js_CodeSpec[op]; + ptrdiff_t oplen = cs->length; + if (oplen < 0) + oplen = js_GetVariableBytecodeLength(pc); + + /* + * Rewrite JSOP_{GET,CALL}FCSLOT as JSOP_{GET,CALL}UPVAR_DBG for the + * case where fun is an escaping flat closure. This works because the + * UPVAR and FCSLOT ops by design have the same format: an upvar index + * immediate operand. + */ + switch (op) { + case JSOP_GETFCSLOT: *pc = JSOP_GETUPVAR_DBG; break; + case JSOP_CALLFCSLOT: *pc = JSOP_CALLUPVAR_DBG; break; + case JSOP_DEFFUN_FC: *pc = JSOP_DEFFUN_DBGFC; break; + case JSOP_DEFLOCALFUN_FC: *pc = JSOP_DEFLOCALFUN_DBGFC; break; + case JSOP_LAMBDA_FC: *pc = JSOP_LAMBDA_DBGFC; break; + default:; + } + pc += oplen; + } + + /* + * Fill in the rest of wscript. This means if you add members to JSScript + * you must update this code. FIXME: factor into JSScript::clone method. + */ + JS_ASSERT(wscript->getVersion() == script->getVersion()); + wscript->nfixed = script->nfixed; + wscript->filename = script->filename; + wscript->lineno = script->lineno; + wscript->nslots = script->nslots; + wscript->staticLevel = script->staticLevel; + wscript->principals = script->principals; + wscript->noScriptRval = script->noScriptRval; + wscript->savedCallerFun = script->savedCallerFun; + wscript->hasSharps = script->hasSharps; + wscript->strictModeCode = script->strictModeCode; + wscript->compileAndGo = script->compileAndGo; + wscript->usesEval = script->usesEval; + wscript->usesArguments = script->usesArguments; + wscript->warnedAboutTwoArgumentEval = script->warnedAboutTwoArgumentEval; + if (wscript->principals) + JSPRINCIPALS_HOLD(cx, wscript->principals); +#ifdef CHECK_SCRIPT_OWNER + wscript->owner = script->owner; +#endif + + wscript->bindings.clone(cx, &script->bindings); + + /* Deoptimize wfun from FUN_{FLAT,NULL}_CLOSURE to FUN_INTERPRETED. */ + FUN_SET_KIND(wfun, JSFUN_INTERPRETED); + wfun->u.i.script = wscript; + return wfunobj; +} + +static JSBool +ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + LeaveTrace(cx); + + if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL)) + return true; + + if (JSID_IS_INT(id)) { + /* + * arg can exceed the number of arguments if a script changed the + * prototype to point to another Arguments object with a bigger argc. + */ + uintN arg = uintN(JSID_TO_INT(id)); + if (arg < obj->getArgsInitialLength()) { + JS_ASSERT(!obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE)); + if (JSStackFrame *fp = (JSStackFrame *) obj->getPrivate()) + *vp = fp->canonicalActualArg(arg); + else + *vp = obj->getArgsElement(arg); + } + } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + if (!obj->isArgsLengthOverridden()) + vp->setInt32(obj->getArgsInitialLength()); + } else { + JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)); + const Value &v = obj->getArgsCallee(); + if (!v.isMagic(JS_ARGS_HOLE)) { + /* + * If this function or one in it needs upvars that reach above it + * in the scope chain, it must not be a null closure (it could be a + * flat closure, or an unoptimized closure -- the latter itself not + * necessarily heavyweight). Rather than wrap here, we simply throw + * to reduce code size and tell debugger users the truth instead of + * passing off a fibbing wrapper. + */ + if (GET_FUNCTION_PRIVATE(cx, &v.toObject())->needsWrapper()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_OPTIMIZED_CLOSURE_LEAK); + return false; + } + *vp = v; + } + } + return true; +} + +static JSBool +ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) +{ +#ifdef JS_TRACER + // To be able to set a property here on trace, we would have to make + // sure any updates also get written back to the trace native stack. + // For simplicity, we just leave trace, since this is presumably not + // a common operation. + LeaveTrace(cx); +#endif + + if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL)) + return true; + + if (JSID_IS_INT(id)) { + uintN arg = uintN(JSID_TO_INT(id)); + if (arg < obj->getArgsInitialLength()) { + JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); + if (fp) { + JSScript *script = fp->functionScript(); + if (script->usesArguments) + fp->canonicalActualArg(arg) = *vp; + return true; + } + } + } else { + JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) || + JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)); + } + + /* + * For simplicity we use delete/define to replace the property with one + * backed by the default Object getter and setter. Note that we rely on + * args_delProperty to clear the corresponding reserved slot so the GC can + * collect its value. Note also that we must define the property instead + * of setting it in case the user has changed the prototype to an object + * that has a setter for this id. + */ + AutoValueRooter tvr(cx); + return js_DeleteProperty(cx, obj, id, tvr.addr(), false) && + js_DefineProperty(cx, obj, id, vp, NULL, NULL, JSPROP_ENUMERATE); +} + +static JSBool +args_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSObject **objp) +{ + JS_ASSERT(obj->isNormalArguments()); + + *objp = NULL; + + uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE; + if (JSID_IS_INT(id)) { + uint32 arg = uint32(JSID_TO_INT(id)); + if (arg >= obj->getArgsInitialLength() || obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE)) + return true; + + attrs |= JSPROP_ENUMERATE; + } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + if (obj->isArgsLengthOverridden()) + return true; + } else { + if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) + return true; + + if (obj->getArgsCallee().isMagic(JS_ARGS_HOLE)) + return true; + } + + Value undef = UndefinedValue(); + if (!js_DefineProperty(cx, obj, id, &undef, ArgGetter, ArgSetter, attrs)) + return JS_FALSE; + + *objp = obj; + return true; +} + +static JSBool +args_enumerate(JSContext *cx, JSObject *obj) +{ + JS_ASSERT(obj->isNormalArguments()); + + /* + * Trigger reflection in args_resolve using a series of js_LookupProperty + * calls. + */ + int argc = int(obj->getArgsInitialLength()); + for (int i = -2; i != argc; i++) { + jsid id = (i == -2) + ? ATOM_TO_JSID(cx->runtime->atomState.lengthAtom) + : (i == -1) + ? ATOM_TO_JSID(cx->runtime->atomState.calleeAtom) + : INT_TO_JSID(i); + + JSObject *pobj; + JSProperty *prop; + if (!js_LookupProperty(cx, obj, id, &pobj, &prop)) + return false; + } + return true; +} + +static JSBool +StrictArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + LeaveTrace(cx); + + if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL)) + return true; + + if (JSID_IS_INT(id)) { + /* + * arg can exceed the number of arguments if a script changed the + * prototype to point to another Arguments object with a bigger argc. + */ + uintN arg = uintN(JSID_TO_INT(id)); + if (arg < obj->getArgsInitialLength()) { + const Value &v = obj->getArgsElement(arg); + if (!v.isMagic(JS_ARGS_HOLE)) + *vp = v; + } + } else { + JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)); + if (!obj->isArgsLengthOverridden()) + vp->setInt32(obj->getArgsInitialLength()); + } + return true; +} + +static JSBool + +StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) +{ + if (!InstanceOf(cx, obj, &StrictArgumentsClass, NULL)) + return true; + + if (JSID_IS_INT(id)) { + uintN arg = uintN(JSID_TO_INT(id)); + if (arg < obj->getArgsInitialLength()) { + obj->setArgsElement(arg, *vp); + return true; + } + } else { + JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)); + } + + /* + * For simplicity we use delete/set to replace the property with one + * backed by the default Object getter and setter. Note that we rely on + * args_delProperty to clear the corresponding reserved slot so the GC can + * collect its value. + */ + AutoValueRooter tvr(cx); + return js_DeleteProperty(cx, obj, id, tvr.addr(), strict) && + js_SetProperty(cx, obj, id, vp, strict); +} + +static JSBool +strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) +{ + JS_ASSERT(obj->isStrictArguments()); + + *objp = NULL; + + uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE; + PropertyOp getter = StrictArgGetter; + StrictPropertyOp setter = StrictArgSetter; + + if (JSID_IS_INT(id)) { + uint32 arg = uint32(JSID_TO_INT(id)); + if (arg >= obj->getArgsInitialLength() || obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE)) + return true; + + attrs |= JSPROP_ENUMERATE; + } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + if (obj->isArgsLengthOverridden()) + return true; + } else { + if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom) && + !JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) { + return true; + } + + attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED; + getter = CastAsPropertyOp(obj->getThrowTypeError()); + setter = CastAsStrictPropertyOp(obj->getThrowTypeError()); + } + + Value undef = UndefinedValue(); + if (!js_DefineProperty(cx, obj, id, &undef, getter, setter, attrs)) + return false; + + *objp = obj; + return true; +} + +static JSBool +strictargs_enumerate(JSContext *cx, JSObject *obj) +{ + JS_ASSERT(obj->isStrictArguments()); + + /* + * Trigger reflection in strictargs_resolve using a series of + * js_LookupProperty calls. + */ + JSObject *pobj; + JSProperty *prop; + + // length + if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), &pobj, &prop)) + return false; + + // callee + if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.calleeAtom), &pobj, &prop)) + return false; + + // caller + if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.callerAtom), &pobj, &prop)) + return false; + + for (uint32 i = 0, argc = obj->getArgsInitialLength(); i < argc; i++) { + if (!js_LookupProperty(cx, obj, INT_TO_JSID(i), &pobj, &prop)) + return false; + } + + return true; +} + +static void +args_finalize(JSContext *cx, JSObject *obj) +{ + cx->free((void *) obj->getArgsData()); +} + +/* + * If a generator's arguments or call object escapes, and the generator frame + * is not executing, the generator object needs to be marked because it is not + * otherwise reachable. An executing generator is rooted by its invocation. To + * distinguish the two cases (which imply different access paths to the + * generator object), we use the JSFRAME_FLOATING_GENERATOR flag, which is only + * set on the JSStackFrame kept in the generator object's JSGenerator. + */ +static inline void +MaybeMarkGenerator(JSTracer *trc, JSObject *obj) +{ +#if JS_HAS_GENERATORS + JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); + if (fp && fp->isFloatingGenerator()) { + JSObject *genobj = js_FloatingFrameToGenerator(fp)->obj; + MarkObject(trc, *genobj, "generator object"); + } +#endif +} + +static void +args_trace(JSTracer *trc, JSObject *obj) +{ + JS_ASSERT(obj->isArguments()); + if (obj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE) { + JS_ASSERT(!obj->isStrictArguments()); + return; + } + + ArgumentsData *data = obj->getArgsData(); + if (data->callee.isObject()) + MarkObject(trc, data->callee.toObject(), js_callee_str); + MarkValueRange(trc, obj->getArgsInitialLength(), data->slots, js_arguments_str); + + MaybeMarkGenerator(trc, obj); +} + +/* + * The Arguments classes aren't initialized via js_InitClass, because arguments + * objects have the initial value of Object.prototype as their [[Prototype]]. + * However, Object.prototype.toString.call(arguments) === "[object Arguments]" + * per ES5 (although not ES3), so the class name is "Arguments" rather than + * "Object". + * + * The JSClass functions below collaborate to lazily reflect and synchronize + * actual argument values, argument count, and callee function object stored + * in a JSStackFrame with their corresponding property values in the frame's + * arguments object. + */ +Class js_ArgumentsClass = { + "Arguments", + JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | + JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_CLASS_RESERVED_SLOTS) | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), + PropertyStub, /* addProperty */ + args_delProperty, + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + args_enumerate, + (JSResolveOp) args_resolve, + ConvertStub, + args_finalize, /* finalize */ + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + JS_CLASS_TRACE(args_trace) +}; + +namespace js { + +/* + * Strict mode arguments is significantly less magical than non-strict mode + * arguments, so it is represented by a different class while sharing some + * functionality. + */ +Class StrictArgumentsClass = { + "Arguments", + JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | + JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_CLASS_RESERVED_SLOTS) | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), + PropertyStub, /* addProperty */ + args_delProperty, + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + strictargs_enumerate, + reinterpret_cast(strictargs_resolve), + ConvertStub, + args_finalize, /* finalize */ + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + JS_CLASS_TRACE(args_trace) +}; + +} + +/* + * A Declarative Environment object stores its active JSStackFrame pointer in + * its private slot, just as Call and Arguments objects do. + */ +Class js_DeclEnvClass = { + js_Object_str, + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub +}; + +static JSBool +CheckForEscapingClosure(JSContext *cx, JSObject *obj, Value *vp) +{ + JS_ASSERT(obj->isCall() || obj->getClass() == &js_DeclEnvClass); + + const Value &v = *vp; + + JSObject *funobj; + if (IsFunctionObject(v, &funobj)) { + JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); + + /* + * Any escaping null or flat closure that reaches above itself or + * contains nested functions that reach above it must be wrapped. + * We can wrap only when this Call or Declarative Environment obj + * still has an active stack frame associated with it. + */ + if (fun->needsWrapper()) { + LeaveTrace(cx); + + JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); + if (fp) { + JSObject *wrapper = WrapEscapingClosure(cx, fp, fun); + if (!wrapper) + return false; + vp->setObject(*wrapper); + return true; + } + + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_OPTIMIZED_CLOSURE_LEAK); + return false; + } + } + return true; +} + +static JSBool +CalleeGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + return CheckForEscapingClosure(cx, obj, vp); +} + +namespace js { + +/* + * Construct a call object for the given bindings. The callee is the function + * on behalf of which the call object is being created. + */ +JSObject * +NewCallObject(JSContext *cx, Bindings *bindings, JSObject &scopeChain, JSObject *callee) +{ + size_t argsVars = bindings->countArgsAndVars(); + size_t slots = JSObject::CALL_RESERVED_SLOTS + argsVars; + gc::FinalizeKind kind = gc::GetGCObjectKind(slots); + + JSObject *callobj = js_NewGCObject(cx, kind); + if (!callobj) + return NULL; + + /* Init immediately to avoid GC seeing a half-init'ed object. */ + callobj->init(cx, &js_CallClass, NULL, &scopeChain, NULL, false); + callobj->setMap(bindings->lastShape()); + + /* This must come after callobj->lastProp has been set. */ + if (!callobj->ensureInstanceReservedSlots(cx, argsVars)) + return NULL; + +#ifdef DEBUG + for (Shape::Range r = callobj->lastProp; !r.empty(); r.popFront()) { + const Shape &s = r.front(); + if (s.slot != SHAPE_INVALID_SLOT) { + JS_ASSERT(s.slot + 1 == callobj->slotSpan()); + break; + } + } +#endif + + callobj->setCallObjCallee(callee); + return callobj; +} + +} // namespace js + +static inline JSObject * +NewDeclEnvObject(JSContext *cx, JSStackFrame *fp) +{ + JSObject *envobj = js_NewGCObject(cx, FINALIZE_OBJECT2); + if (!envobj) + return NULL; + + envobj->init(cx, &js_DeclEnvClass, NULL, &fp->scopeChain(), fp, false); + envobj->setMap(cx->compartment->emptyDeclEnvShape); + return envobj; +} + +JSObject * +js_GetCallObject(JSContext *cx, JSStackFrame *fp) +{ + /* Create a call object for fp only if it lacks one. */ + JS_ASSERT(fp->isFunctionFrame()); + if (fp->hasCallObj()) + return &fp->callObj(); + +#ifdef DEBUG + /* A call object should be a frame's outermost scope chain element. */ + Class *clasp = fp->scopeChain().getClass(); + if (clasp == &js_WithClass || clasp == &js_BlockClass) + JS_ASSERT(fp->scopeChain().getPrivate() != js_FloatingFrameIfGenerator(cx, fp)); + else if (clasp == &js_CallClass) + JS_ASSERT(fp->scopeChain().getPrivate() != fp); +#endif + + /* + * Create the call object, using the frame's enclosing scope as its + * parent, and link the call to its stack frame. For a named function + * expression Call's parent points to an environment object holding + * function's name. + */ + JSAtom *lambdaName = + (fp->fun()->flags & JSFUN_LAMBDA) ? fp->fun()->atom : NULL; + if (lambdaName) { + JSObject *envobj = NewDeclEnvObject(cx, fp); + if (!envobj) + return NULL; + + /* Root envobj before js_DefineNativeProperty (-> JSClass.addProperty). */ + fp->setScopeChainNoCallObj(*envobj); + if (!js_DefineNativeProperty(cx, &fp->scopeChain(), ATOM_TO_JSID(lambdaName), + ObjectValue(fp->callee()), + CalleeGetter, NULL, + JSPROP_PERMANENT | JSPROP_READONLY, + 0, 0, NULL)) { + return NULL; + } + } + + JSObject *callobj = + NewCallObject(cx, &fp->fun()->script()->bindings, fp->scopeChain(), &fp->callee()); + if (!callobj) + return NULL; + + callobj->setPrivate(fp); + JS_ASSERT(fp->fun() == fp->callee().getFunctionPrivate()); + + /* + * Push callobj on the top of the scope chain, and make it the + * variables object. + */ + fp->setScopeChainAndCallObj(*callobj); + return callobj; +} + +JSObject * JS_FASTCALL +js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSObject *scopeChain) +{ + JS_ASSERT(!js_IsNamedLambda(fun)); + JS_ASSERT(scopeChain); + JS_ASSERT(callee); + return NewCallObject(cx, &fun->script()->bindings, *scopeChain, callee); +} + +JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTION, OBJECT, OBJECT, + 0, nanojit::ACCSET_STORE_ANY) + +inline static void +CopyValuesToCallObject(JSObject &callobj, uintN nargs, Value *argv, uintN nvars, Value *slots) +{ + JS_ASSERT(callobj.numSlots() >= JSObject::CALL_RESERVED_SLOTS + nargs + nvars); + Value *base = callobj.getSlots() + JSObject::CALL_RESERVED_SLOTS; + memcpy(base, argv, nargs * sizeof(Value)); + memcpy(base + nargs, slots, nvars * sizeof(Value)); +} + +void +js_PutCallObject(JSContext *cx, JSStackFrame *fp) +{ + JSObject &callobj = fp->callObj(); + + /* + * Strict mode eval frames have Call objects to put. Normal eval frames + * never put a Call object. + */ + JS_ASSERT(fp->isEvalFrame() == callobj.callIsForEval()); + + /* Get the arguments object to snapshot fp's actual argument values. */ + if (fp->hasArgsObj()) { + if (!fp->hasOverriddenArgs()) + callobj.setCallObjArguments(ObjectValue(fp->argsObj())); + js_PutArgsObject(cx, fp); + } + + JSScript *script = fp->script(); + Bindings &bindings = script->bindings; + + if (callobj.callIsForEval()) { + JS_ASSERT(script->strictModeCode); + JS_ASSERT(bindings.countArgs() == 0); + + /* This could be optimized as below, but keep it simple for now. */ + CopyValuesToCallObject(callobj, 0, NULL, bindings.countVars(), fp->slots()); + } else { + JSFunction *fun = fp->fun(); + JS_ASSERT(fun == callobj.getCallObjCalleeFunction()); + JS_ASSERT(script == fun->script()); + + uintN n = bindings.countArgsAndVars(); + if (n > 0) { + JS_ASSERT(JSObject::CALL_RESERVED_SLOTS + n <= callobj.numSlots()); + + uint32 nvars = bindings.countVars(); + uint32 nargs = bindings.countArgs(); + JS_ASSERT(fun->nargs == nargs); + JS_ASSERT(nvars + nargs == n); + + JSScript *script = fun->script(); + if (script->usesEval +#ifdef JS_METHODJIT + || script->debugMode +#endif + ) { + CopyValuesToCallObject(callobj, nargs, fp->formalArgs(), nvars, fp->slots()); + } else { + /* + * For each arg & var that is closed over, copy it from the stack + * into the call object. + */ + uint32 nclosed = script->nClosedArgs; + for (uint32 i = 0; i < nclosed; i++) { + uint32 e = script->getClosedArg(i); + callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + e, fp->formalArg(e)); + } + + nclosed = script->nClosedVars; + for (uint32 i = 0; i < nclosed; i++) { + uint32 e = script->getClosedVar(i); + callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + nargs + e, fp->slots()[e]); + } + } + } + + /* Clear private pointers to fp, which is about to go away (js_Invoke). */ + if (js_IsNamedLambda(fun)) { + JSObject *env = callobj.getParent(); + + JS_ASSERT(env->getClass() == &js_DeclEnvClass); + JS_ASSERT(env->getPrivate() == fp); + env->setPrivate(NULL); + } + } + + callobj.setPrivate(NULL); + fp->clearCallObj(); +} + +JSBool JS_FASTCALL +js_PutCallObjectOnTrace(JSContext *cx, JSObject *callobj, uint32 nargs, Value *argv, + uint32 nvars, Value *slots) +{ + JS_ASSERT(callobj->isCall()); + JS_ASSERT(!callobj->getPrivate()); + + uintN n = nargs + nvars; + if (n != 0) + CopyValuesToCallObject(*callobj, nargs, argv, nvars, slots); + + return true; +} + +JS_DEFINE_CALLINFO_6(extern, BOOL, js_PutCallObjectOnTrace, CONTEXT, OBJECT, UINT32, VALUEPTR, + UINT32, VALUEPTR, 0, nanojit::ACCSET_STORE_ANY) + +namespace js { + +static JSBool +GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + JSStackFrame *fp = obj->maybeCallObjStackFrame(); + if (fp && !fp->hasOverriddenArgs()) { + JSObject *argsobj = js_GetArgsObject(cx, fp); + if (!argsobj) + return false; + vp->setObject(*argsobj); + } else { + *vp = obj->getCallObjArguments(); + } + return true; +} + +static JSBool +SetCallArguments(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) +{ + if (JSStackFrame *fp = obj->maybeCallObjStackFrame()) + fp->setOverriddenArgs(); + obj->setCallObjArguments(*vp); + return true; +} + +JSBool +GetCallArg(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id)); + uintN i = (uint16) JSID_TO_INT(id); + + if (JSStackFrame *fp = obj->maybeCallObjStackFrame()) + *vp = fp->formalArg(i); + else + *vp = obj->callObjArg(i); + return true; +} + +JSBool +SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) +{ + JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id)); + uintN i = (uint16) JSID_TO_INT(id); + + Value *argp; + if (JSStackFrame *fp = obj->maybeCallObjStackFrame()) + argp = &fp->formalArg(i); + else + argp = &obj->callObjArg(i); + + GC_POKE(cx, *argp); + *argp = *vp; + return true; +} + +JSBool +GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id)); + uintN i = (uint16) JSID_TO_INT(id); + + *vp = obj->getCallObjCallee()->getFlatClosureUpvar(i); + return true; +} + +JSBool +SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) +{ + JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id)); + uintN i = (uint16) JSID_TO_INT(id); + + Value *up = &obj->getCallObjCallee()->getFlatClosureUpvar(i); + + GC_POKE(cx, *up); + *up = *vp; + return true; +} + +JSBool +GetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id)); + uintN i = (uint16) JSID_TO_INT(id); + + if (JSStackFrame *fp = obj->maybeCallObjStackFrame()) + *vp = fp->varSlot(i); + else + *vp = obj->callObjVar(i); + + return true; +} + +JSBool +GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + if (!GetCallVar(cx, obj, id, vp)) + return false; + + return CheckForEscapingClosure(cx, obj, vp); +} + +JSBool +SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) +{ + JS_ASSERT(obj->isCall()); + + JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id)); + uintN i = (uint16) JSID_TO_INT(id); + + /* + * As documented in TraceRecorder::attemptTreeCall(), when recording an + * inner tree call, the recorder assumes the inner tree does not mutate + * any tracked upvars. The abort here is a pessimistic precaution against + * bug 620662, where an inner tree setting a closed stack variable in an + * outer tree is illegal, and runtime would fall off trace. + */ +#ifdef JS_TRACER + if (JS_ON_TRACE(cx)) { + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + if (tm->recorder && tm->tracecx) + AbortRecording(cx, "upvar write in nested tree"); + } +#endif + + Value *varp; + if (JSStackFrame *fp = obj->maybeCallObjStackFrame()) + varp = &fp->varSlot(i); + else + varp = &obj->callObjVar(i); + + GC_POKE(cx, *varp); + *varp = *vp; + return true; +} + +} // namespace js + +#if JS_TRACER +JSBool JS_FASTCALL +js_SetCallArg(JSContext *cx, JSObject *obj, jsid slotid, ValueArgType arg) +{ + Value argcopy = ValueArgToConstRef(arg); + return SetCallArg(cx, obj, slotid, false /* STRICT DUMMY */, &argcopy); +} +JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallArg, CONTEXT, OBJECT, JSID, VALUE, 0, + nanojit::ACCSET_STORE_ANY) + +JSBool JS_FASTCALL +js_SetCallVar(JSContext *cx, JSObject *obj, jsid slotid, ValueArgType arg) +{ + Value argcopy = ValueArgToConstRef(arg); + return SetCallVar(cx, obj, slotid, false /* STRICT DUMMY */, &argcopy); +} +JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallVar, CONTEXT, OBJECT, JSID, VALUE, 0, + nanojit::ACCSET_STORE_ANY) +#endif + +static JSBool +call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSObject **objp) +{ + JS_ASSERT(obj->isCall()); + JS_ASSERT(!obj->getProto()); + + if (!JSID_IS_ATOM(id)) + return true; + + JSObject *callee = obj->getCallObjCallee(); +#ifdef DEBUG + if (callee) { + JSScript *script = callee->getFunctionPrivate()->script(); + JS_ASSERT(!script->bindings.hasBinding(cx, JSID_TO_ATOM(id))); + } +#endif + + /* + * Resolve arguments so that we never store a particular Call object's + * arguments object reference in a Call prototype's |arguments| slot. + * + * Include JSPROP_ENUMERATE for consistency with all other Call object + * properties; see js::Bindings::add and js::Interpret's JSOP_DEFFUN + * rebinding-Call-property logic. + */ + if (callee && id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) { + if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(), + GetCallArguments, SetCallArguments, + JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE, + 0, 0, NULL, JSDNP_DONT_PURGE)) { + return false; + } + *objp = obj; + return true; + } + + /* Control flow reaches here only if id was not resolved. */ + return true; +} + +static void +call_trace(JSTracer *trc, JSObject *obj) +{ + JS_ASSERT(obj->isCall()); + if (JSStackFrame *fp = obj->maybeCallObjStackFrame()) { + /* + * FIXME: Hide copies of stack values rooted by fp from the Cycle + * Collector, which currently lacks a non-stub Unlink implementation + * for JS objects (including Call objects), so is unable to collect + * cycles involving Call objects whose frames are active without this + * hiding hack. + */ + uintN first = JSObject::CALL_RESERVED_SLOTS; + uintN count = fp->script()->bindings.countArgsAndVars(); + + JS_ASSERT(obj->numSlots() >= first + count); + SetValueRangeToUndefined(obj->getSlots() + first, count); + } + + MaybeMarkGenerator(trc, obj); +} + +JS_PUBLIC_DATA(Class) js_CallClass = { + "Call", + JSCLASS_HAS_PRIVATE | + JSCLASS_HAS_RESERVED_SLOTS(JSObject::CALL_RESERVED_SLOTS) | + JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE, + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + JS_EnumerateStub, + (JSResolveOp)call_resolve, + NULL, /* convert: Leave it NULL so we notice if calls ever escape */ + NULL, /* finalize */ + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + JS_CLASS_TRACE(call_trace) +}; + +bool +JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp) +{ + if (!isFunctionFrame()) { + vp->setUndefined(); + return true; + } + + JSFunction *fun = this->fun(); + + /* + * See the equivalent condition in ArgGetter for the 'callee' id case, but + * note that here we do not want to throw, since this escape can happen via + * a foo.caller reference alone, without any debugger or indirect eval. And + * alas, it seems foo.caller is still used on the Web. + */ + if (fun->needsWrapper()) { + JSObject *wrapper = WrapEscapingClosure(cx, this, fun); + if (!wrapper) + return false; + vp->setObject(*wrapper); + return true; + } + + JSObject &funobj = callee(); + vp->setObject(funobj); + + /* + * Check for an escape attempt by a joined function object, which must go + * through the frame's |this| object's method read barrier for the method + * atom by which it was uniquely associated with a property. + */ + const Value &thisv = functionThis(); + if (thisv.isObject()) { + JS_ASSERT(funobj.getFunctionPrivate() == fun); + + if (&fun->compiledFunObj() == &funobj && fun->methodAtom()) { + JSObject *thisp = &thisv.toObject(); + JSObject *first_barriered_thisp = NULL; + + do { + /* + * While a non-native object is responsible for handling its + * entire prototype chain, notable non-natives including dense + * and typed arrays have native prototypes, so keep going. + */ + if (!thisp->isNative()) + continue; + + if (thisp->hasMethodBarrier()) { + const Shape *shape = thisp->nativeLookup(ATOM_TO_JSID(fun->methodAtom())); + if (shape) { + /* + * Two cases follow: the method barrier was not crossed + * yet, so we cross it here; the method barrier *was* + * crossed but after the call, in which case we fetch + * and validate the cloned (unjoined) funobj from the + * method property's slot. + * + * In either case we must allow for the method property + * to have been replaced, or its value overwritten. + */ + if (shape->isMethod() && &shape->methodObject() == &funobj) { + if (!thisp->methodReadBarrier(cx, *shape, vp)) + return false; + calleeValue().setObject(vp->toObject()); + return true; + } + + if (shape->hasSlot()) { + Value v = thisp->getSlot(shape->slot); + JSObject *clone; + + if (IsFunctionObject(v, &clone) && + GET_FUNCTION_PRIVATE(cx, clone) == fun && + clone->hasMethodObj(*thisp)) { + JS_ASSERT(clone != &funobj); + *vp = v; + calleeValue().setObject(*clone); + return true; + } + } + } + + if (!first_barriered_thisp) + first_barriered_thisp = thisp; + } + } while ((thisp = thisp->getProto()) != NULL); + + if (!first_barriered_thisp) + return true; + + /* + * At this point, we couldn't find an already-existing clone (or + * force to exist a fresh clone) created via thisp's method read + * barrier, so we must clone fun and store it in fp's callee to + * avoid re-cloning upon repeated foo.caller access. + * + * This must mean the code in js_DeleteProperty could not find this + * stack frame on the stack when the method was deleted. We've lost + * track of the method, so we associate it with the first barriered + * object found starting from thisp on the prototype chain. + */ + JSObject *newfunobj = CloneFunctionObject(cx, fun, fun->getParent()); + if (!newfunobj) + return false; + newfunobj->setMethodObj(*first_barriered_thisp); + calleeValue().setObject(*newfunobj); + vp->setObject(*newfunobj); + return true; + } + } + + return true; +} + +/* Generic function tinyids. */ +enum { + FUN_ARGUMENTS = -1, /* predefined arguments local variable */ + FUN_LENGTH = -2, /* number of actual args, arity if inactive */ + FUN_ARITY = -3, /* number of formal parameters; desired argc */ + FUN_NAME = -4, /* function name, "" if anonymous */ + FUN_CALLER = -5 /* Function.prototype.caller, backward compat */ +}; + +static JSBool +fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + if (!JSID_IS_INT(id)) + return true; + + jsint slot = JSID_TO_INT(id); + + /* + * Loop because getter and setter can be delegated from another class, + * but loop only for FUN_LENGTH because we must pretend that f.length + * is in each function instance f, per ECMA-262, instead of only in the + * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED + * to make it appear so). + * + * This code couples tightly to the attributes for lazyFunctionDataProps[] + * and poisonPillProps[] initializers below, and to js_SetProperty and + * js_HasOwnProperty. + * + * It's important to allow delegating objects, even though they inherit + * this getter (fun_getProperty), to override arguments, arity, caller, + * and name. If we didn't return early for slot != FUN_LENGTH, we would + * clobber *vp with the native property value, instead of letting script + * override that value in delegating objects. + * + * Note how that clobbering is what simulates JSPROP_READONLY for all of + * the non-standard properties when the directly addressed object (obj) + * is a function object (i.e., when this loop does not iterate). + */ + JSFunction *fun; + while (!(fun = (JSFunction *) + GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) { + if (slot != FUN_LENGTH) + return true; + obj = obj->getProto(); + if (!obj) + return true; + } + + /* Find fun's top-most activation record. */ + JSStackFrame *fp; + for (fp = js_GetTopStackFrame(cx); + fp && (fp->maybeFun() != fun || fp->isEvalOrDebuggerFrame()); + fp = fp->prev()) { + continue; + } + + switch (slot) { + case FUN_ARGUMENTS: + /* Warn if strict about f.arguments or equivalent unqualified uses. */ + if (!JS_ReportErrorFlagsAndNumber(cx, + JSREPORT_WARNING | JSREPORT_STRICT, + js_GetErrorMessage, NULL, + JSMSG_DEPRECATED_USAGE, + js_arguments_str)) { + return false; + } + if (fp) { + if (!js_GetArgsValue(cx, fp, vp)) + return false; + } else { + vp->setNull(); + } + break; + + case FUN_LENGTH: + case FUN_ARITY: + vp->setInt32(fun->nargs); + break; + + case FUN_NAME: + vp->setString(fun->atom ? ATOM_TO_STRING(fun->atom) + : cx->runtime->emptyString); + break; + + case FUN_CALLER: + vp->setNull(); + if (fp && fp->prev() && !fp->prev()->getValidCalleeObject(cx, vp)) + return false; + + if (vp->isObject()) { + JSObject &caller = vp->toObject(); + + /* Censor the caller if it is from another compartment. */ + if (caller.getCompartment() != cx->compartment) { + vp->setNull(); + } else if (caller.isFunction()) { + JSFunction *callerFun = caller.getFunctionPrivate(); + if (callerFun->isInterpreted() && callerFun->inStrictMode()) { + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, + JSMSG_CALLER_IS_STRICT); + return false; + } + } + } + break; + + default: + /* XXX fun[0] and fun.arguments[0] are equivalent. */ + if (fp && fp->isFunctionFrame() && uint16(slot) < fp->numFormalArgs()) + *vp = fp->formalArg(slot); + break; + } + + return true; +} + +struct LazyFunctionDataProp { + uint16 atomOffset; + int8 tinyid; + uint8 attrs; +}; + +struct PoisonPillProp { + uint16 atomOffset; + int8 tinyid; +}; + +/* NB: no sentinels at ends -- use JS_ARRAY_LENGTH to bound loops. */ + +static const LazyFunctionDataProp lazyFunctionDataProps[] = { + {ATOM_OFFSET(arity), FUN_ARITY, JSPROP_PERMANENT|JSPROP_READONLY}, + {ATOM_OFFSET(name), FUN_NAME, JSPROP_PERMANENT|JSPROP_READONLY}, +}; + +/* Properties censored into [[ThrowTypeError]] in strict mode. */ +static const PoisonPillProp poisonPillProps[] = { + {ATOM_OFFSET(arguments), FUN_ARGUMENTS }, + {ATOM_OFFSET(caller), FUN_CALLER }, +}; + +static JSBool +fun_enumerate(JSContext *cx, JSObject *obj) +{ + JS_ASSERT(obj->isFunction()); + + jsid id; + bool found; + + if (!obj->isBoundFunction()) { + id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom); + if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED)) + return false; + } + + id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); + if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED)) + return false; + + for (uintN i = 0; i < JS_ARRAY_LENGTH(lazyFunctionDataProps); i++) { + const LazyFunctionDataProp &lfp = lazyFunctionDataProps[i]; + id = ATOM_TO_JSID(OFFSET_TO_ATOM(cx->runtime, lfp.atomOffset)); + if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED)) + return false; + } + + for (uintN i = 0; i < JS_ARRAY_LENGTH(poisonPillProps); i++) { + const PoisonPillProp &p = poisonPillProps[i]; + id = ATOM_TO_JSID(OFFSET_TO_ATOM(cx->runtime, p.atomOffset)); + if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED)) + return false; + } + + return true; +} + +static JSObject * +ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *obj) +{ +#ifdef DEBUG + JSFunction *fun = obj->getFunctionPrivate(); + JS_ASSERT(fun->isInterpreted()); + JS_ASSERT(!fun->isFunctionPrototype()); +#endif + + /* + * Assert that fun is not a compiler-created function object, which + * must never leak to script or embedding code and then be mutated. + * Also assert that obj is not bound, per the ES5 15.3.4.5 ref above. + */ + JS_ASSERT(!IsInternalFunctionObject(obj)); + JS_ASSERT(!obj->isBoundFunction()); + + /* + * Make the prototype object an instance of Object with the same parent + * as the function object itself. + */ + JSObject *parent = obj->getParent(); + JSObject *proto; + if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto)) + return NULL; + proto = NewNativeClassInstance(cx, &js_ObjectClass, proto, parent); + if (!proto) + return NULL; + + /* + * ECMA (15.3.5.2) says that a user-defined function's .prototype property + * is non-configurable, non-enumerable, and (initially) writable. Hence + * JSPROP_PERMANENT below. By contrast, the built-in constructors, such as + * Object (15.2.3.1) and Function (15.3.3.1), have non-writable + * .prototype properties. Those are eagerly defined, with attributes + * JSPROP_PERMANENT | JSPROP_READONLY, in js_InitClass. + */ + if (!js_SetClassPrototype(cx, obj, proto, JSPROP_PERMANENT)) + return NULL; + return proto; +} + +static JSBool +fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSObject **objp) +{ + if (!JSID_IS_ATOM(id)) + return true; + + JSFunction *fun = obj->getFunctionPrivate(); + + if (JSID_IS_ATOM(id, cx->runtime->atomState.classPrototypeAtom)) { + /* + * Native or "built-in" functions do not have a .prototype property per + * ECMA-262 (all editions). Built-in constructor functions, e.g. Object + * and Function to name two conspicuous examples, do have a .prototype + * property, but it is created eagerly by js_InitClass (jsobj.cpp). + * + * ES5 15.3.4: the non-native function object named Function.prototype + * must not have a .prototype property. + * + * ES5 15.3.4.5: bound functions don't have a prototype property. The + * isNative() test covers this case because bound functions are native + * functions by definition/construction. + */ + if (fun->isNative() || fun->isFunctionPrototype()) + return true; + + if (!ResolveInterpretedFunctionPrototype(cx, obj)) + return false; + *objp = obj; + return true; + } + + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + JS_ASSERT(!IsInternalFunctionObject(obj)); + if (!js_DefineNativeProperty(cx, obj, id, Int32Value(fun->nargs), + PropertyStub, StrictPropertyStub, + JSPROP_PERMANENT | JSPROP_READONLY, 0, 0, NULL)) { + return false; + } + *objp = obj; + return true; + } + + for (uintN i = 0; i < JS_ARRAY_LENGTH(lazyFunctionDataProps); i++) { + const LazyFunctionDataProp *lfp = &lazyFunctionDataProps[i]; + + if (JSID_IS_ATOM(id, OFFSET_TO_ATOM(cx->runtime, lfp->atomOffset))) { + JS_ASSERT(!IsInternalFunctionObject(obj)); + + if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(), + fun_getProperty, StrictPropertyStub, + lfp->attrs, Shape::HAS_SHORTID, + lfp->tinyid, NULL)) { + return false; + } + *objp = obj; + return true; + } + } + + for (uintN i = 0; i < JS_ARRAY_LENGTH(poisonPillProps); i++) { + const PoisonPillProp &p = poisonPillProps[i]; + + if (JSID_IS_ATOM(id, OFFSET_TO_ATOM(cx->runtime, p.atomOffset))) { + JS_ASSERT(!IsInternalFunctionObject(obj)); + + PropertyOp getter; + StrictPropertyOp setter; + uintN attrs = JSPROP_PERMANENT; + if (fun->isInterpreted() ? fun->inStrictMode() : obj->isBoundFunction()) { + JSObject *throwTypeError = obj->getThrowTypeError(); + + getter = CastAsPropertyOp(throwTypeError); + setter = CastAsStrictPropertyOp(throwTypeError); + attrs |= JSPROP_GETTER | JSPROP_SETTER; + } else { + getter = fun_getProperty; + setter = StrictPropertyStub; + } + + if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(), + getter, setter, + attrs, Shape::HAS_SHORTID, + p.tinyid, NULL)) { + return false; + } + *objp = obj; + return true; + } + } + + return true; +} + +#if JS_HAS_XDR + +/* XXX store parent and proto, if defined */ +JSBool +js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) +{ + JSContext *cx; + JSFunction *fun; + uint32 firstword; /* flag telling whether fun->atom is non-null, + plus for fun->u.i.skipmin, fun->u.i.wrapper, + and 14 bits reserved for future use */ + uint32 flagsword; /* word for argument count and fun->flags */ + + cx = xdr->cx; + if (xdr->mode == JSXDR_ENCODE) { + fun = GET_FUNCTION_PRIVATE(cx, *objp); + if (!FUN_INTERPRETED(fun)) { + JSAutoByteString funNameBytes; + if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION, + name); + } + return false; + } + if (fun->u.i.wrapper) { + JSAutoByteString funNameBytes; + if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XDR_CLOSURE_WRAPPER, name); + return false; + } + JS_ASSERT((fun->u.i.wrapper & ~1U) == 0); + firstword = (fun->u.i.skipmin << 2) | (fun->u.i.wrapper << 1) | !!fun->atom; + flagsword = (fun->nargs << 16) | fun->flags; + } else { + fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL); + if (!fun) + return false; + FUN_OBJECT(fun)->clearParent(); + FUN_OBJECT(fun)->clearProto(); + } + + AutoObjectRooter tvr(cx, FUN_OBJECT(fun)); + + if (!JS_XDRUint32(xdr, &firstword)) + return false; + if ((firstword & 1U) && !js_XDRAtom(xdr, &fun->atom)) + return false; + if (!JS_XDRUint32(xdr, &flagsword)) + return false; + + if (xdr->mode == JSXDR_DECODE) { + fun->nargs = flagsword >> 16; + JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED); + fun->flags = uint16(flagsword); + fun->u.i.skipmin = uint16(firstword >> 2); + fun->u.i.wrapper = JSPackedBool((firstword >> 1) & 1); + } + + if (!js_XDRScript(xdr, &fun->u.i.script, NULL)) + return false; + + if (xdr->mode == JSXDR_DECODE) { + *objp = FUN_OBJECT(fun); +#ifdef CHECK_SCRIPT_OWNER + fun->script()->owner = NULL; +#endif + JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs()); + js_CallNewScriptHook(cx, fun->script(), fun); + } + + return true; +} + +#else /* !JS_HAS_XDR */ + +#define js_XDRFunctionObject NULL + +#endif /* !JS_HAS_XDR */ + +/* + * [[HasInstance]] internal method for Function objects: fetch the .prototype + * property of its 'this' parameter, and walks the prototype chain of v (only + * if v is an object) returning true if .prototype is found. + */ +static JSBool +fun_hasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp) +{ + while (obj->isFunction()) { + if (!obj->isBoundFunction()) + break; + obj = obj->getBoundFunctionTarget(); + } + + jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom); + Value pval; + if (!obj->getProperty(cx, id, &pval)) + return JS_FALSE; + + if (pval.isPrimitive()) { + /* + * Throw a runtime error if instanceof is called on a function that + * has a non-object as its .prototype value. + */ + js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, ObjectValue(*obj), NULL); + return JS_FALSE; + } + + *bp = js_IsDelegate(cx, &pval.toObject(), *v); + return JS_TRUE; +} + +static void +fun_trace(JSTracer *trc, JSObject *obj) +{ + /* A newborn function object may have a not yet initialized private slot. */ + JSFunction *fun = (JSFunction *) obj->getPrivate(); + if (!fun) + return; + + if (fun != obj) { + /* obj is a cloned function object, trace the clone-parent, fun. */ + MarkObject(trc, *fun, "private"); + + /* The function could be a flat closure with upvar copies in the clone. */ + if (fun->isFlatClosure() && fun->script()->bindings.hasUpvars()) { + MarkValueRange(trc, fun->script()->bindings.countUpvars(), + obj->getFlatClosureUpvars(), "upvars"); + } + return; + } + + if (fun->atom) + MarkString(trc, ATOM_TO_STRING(fun->atom), "atom"); + + if (fun->isInterpreted() && fun->script()) + js_TraceScript(trc, fun->script()); +} + +static void +fun_finalize(JSContext *cx, JSObject *obj) +{ + /* Ignore newborn function objects. */ + JSFunction *fun = obj->getFunctionPrivate(); + if (!fun) + return; + + /* Cloned function objects may be flat closures with upvars to free. */ + if (fun != obj) { + if (fun->isFlatClosure() && fun->script()->bindings.hasUpvars()) + cx->free((void *) obj->getFlatClosureUpvars()); + return; + } + + /* + * Null-check fun->script() because the parser sets interpreted very early. + */ + if (fun->isInterpreted() && fun->script()) + js_DestroyScriptFromGC(cx, fun->script()); +} + +/* + * Reserve two slots in all function objects for XPConnect. Note that this + * does not bloat every instance, only those on which reserved slots are set, + * and those on which ad-hoc properties are defined. + */ +JS_PUBLIC_DATA(Class) js_FunctionClass = { + js_Function_str, + JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | + JSCLASS_HAS_RESERVED_SLOTS(JSFunction::CLASS_RESERVED_SLOTS) | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Function), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + fun_enumerate, + (JSResolveOp)fun_resolve, + ConvertStub, + fun_finalize, + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + js_XDRFunctionObject, + fun_hasInstance, + JS_CLASS_TRACE(fun_trace) +}; + +JSString * +fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent) +{ + if (!obj->isFunction()) { + if (obj->isFunctionProxy()) + return JSProxy::fun_toString(cx, obj, indent); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_PROTO, + js_Function_str, js_toString_str, + "object"); + return NULL; + } + + JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj); + if (!fun) + return NULL; + + if (!indent) { + ToSourceCache::Ptr p = cx->compartment->toSourceCache.lookup(fun); + if (p) + return p->value; + } + + JSString *str = JS_DecompileFunction(cx, fun, indent); + if (!str) + return false; + + if (!indent) + cx->compartment->toSourceCache.put(fun, str); + + return str; +} + +static JSBool +fun_toString(JSContext *cx, uintN argc, Value *vp) +{ + JS_ASSERT(IsFunctionObject(vp[0])); + uint32_t indent = 0; + + if (argc != 0 && !ValueToECMAUint32(cx, vp[2], &indent)) + return false; + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + JSString *str = fun_toStringHelper(cx, obj, indent); + if (!str) + return false; + + vp->setString(str); + return true; +} + +#if JS_HAS_TOSOURCE +static JSBool +fun_toSource(JSContext *cx, uintN argc, Value *vp) +{ + JS_ASSERT(IsFunctionObject(vp[0])); + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + JSString *str = fun_toStringHelper(cx, obj, JS_DONT_PRETTY_PRINT); + if (!str) + return false; + + vp->setString(str); + return true; +} +#endif + +JSBool +js_fun_call(JSContext *cx, uintN argc, Value *vp) +{ + LeaveTrace(cx); + Value fval = vp[1]; + + if (!js_IsCallable(fval)) { + if (JSString *str = js_ValueToString(cx, fval)) { + JSAutoByteString bytes(cx, str); + if (!!bytes) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_PROTO, + js_Function_str, js_call_str, + bytes.ptr()); + } + } + return false; + } + + Value *argv = vp + 2; + Value thisv; + if (argc == 0) { + thisv.setUndefined(); + } else { + thisv = argv[0]; + + argc--; + argv++; + } + + /* Allocate stack space for fval, obj, and the args. */ + InvokeArgsGuard args; + if (!cx->stack().pushInvokeArgs(cx, argc, &args)) + return JS_FALSE; + + /* Push fval, thisv, and the args. */ + args.callee() = fval; + args.thisv() = thisv; + memcpy(args.argv(), argv, argc * sizeof *argv); + + bool ok = Invoke(cx, args, 0); + *vp = args.rval(); + return ok; +} + +/* ES5 15.3.4.3 */ +JSBool +js_fun_apply(JSContext *cx, uintN argc, Value *vp) +{ + /* Step 1. */ + Value fval = vp[1]; + if (!js_IsCallable(fval)) { + if (JSString *str = js_ValueToString(cx, fval)) { + JSAutoByteString bytes(cx, str); + if (!!bytes) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_PROTO, + js_Function_str, js_apply_str, + bytes.ptr()); + } + } + return false; + } + + /* Step 2. */ + if (argc < 2 || vp[3].isNullOrUndefined()) + return js_fun_call(cx, (argc > 0) ? 1 : 0, vp); + + /* N.B. Changes need to be propagated to stubs::SplatApplyArgs. */ + + /* Step 3. */ + if (!vp[3].isObject()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_APPLY_ARGS, js_apply_str); + return false; + } + + /* + * Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in + * original version of ES5). + */ + JSObject *aobj = &vp[3].toObject(); + jsuint length; + if (!js_GetLengthProperty(cx, aobj, &length)) + return false; + + LeaveTrace(cx); + + /* Step 6. */ + uintN n = uintN(JS_MIN(length, JS_ARGS_LENGTH_MAX)); + + InvokeArgsGuard args; + if (!cx->stack().pushInvokeArgs(cx, n, &args)) + return false; + + /* Push fval, obj, and aobj's elements as args. */ + args.callee() = fval; + args.thisv() = vp[2]; + + /* Steps 7-8. */ + if (!GetElements(cx, aobj, n, args.argv())) + return false; + + /* Step 9. */ + if (!Invoke(cx, args, 0)) + return false; + *vp = args.rval(); + return true; +} + +namespace js { + +JSBool +CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp); + +} + +inline bool +JSObject::initBoundFunction(JSContext *cx, const Value &thisArg, + const Value *args, uintN argslen) +{ + JS_ASSERT(isFunction()); + + flags |= JSObject::BOUND_FUNCTION; + getSlotRef(JSSLOT_BOUND_FUNCTION_THIS) = thisArg; + getSlotRef(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).setPrivateUint32(argslen); + if (argslen != 0) { + /* FIXME? Burn memory on an empty scope whose shape covers the args slots. */ + EmptyShape *empty = EmptyShape::create(cx, clasp); + if (!empty) + return false; + + empty->slotSpan += argslen; + map = empty; + + if (!ensureInstanceReservedSlots(cx, argslen)) + return false; + + JS_ASSERT(numSlots() >= argslen + FUN_CLASS_RESERVED_SLOTS); + memcpy(getSlots() + FUN_CLASS_RESERVED_SLOTS, args, argslen * sizeof(Value)); + } + return true; +} + +inline JSObject * +JSObject::getBoundFunctionTarget() const +{ + JS_ASSERT(isFunction()); + JS_ASSERT(isBoundFunction()); + + /* Bound functions abuse |parent| to store their target function. */ + return getParent(); +} + +inline const js::Value & +JSObject::getBoundFunctionThis() const +{ + JS_ASSERT(isFunction()); + JS_ASSERT(isBoundFunction()); + + return getSlot(JSSLOT_BOUND_FUNCTION_THIS); +} + +inline const js::Value * +JSObject::getBoundFunctionArguments(uintN &argslen) const +{ + JS_ASSERT(isFunction()); + JS_ASSERT(isBoundFunction()); + + argslen = getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).toPrivateUint32(); + JS_ASSERT_IF(argslen > 0, numSlots() >= argslen); + + return getSlots() + FUN_CLASS_RESERVED_SLOTS; +} + +namespace js { + +/* ES5 15.3.4.5.1 and 15.3.4.5.2. */ +JSBool +CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = &vp[0].toObject(); + JS_ASSERT(obj->isFunction()); + JS_ASSERT(obj->isBoundFunction()); + + LeaveTrace(cx); + + bool constructing = IsConstructing(vp); + + /* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */ + uintN argslen; + const Value *boundArgs = obj->getBoundFunctionArguments(argslen); + + if (argc + argslen > JS_ARGS_LENGTH_MAX) { + js_ReportAllocationOverflow(cx); + return false; + } + + /* 15.3.4.5.1 step 3, 15.3.4.5.2 step 1. */ + JSObject *target = obj->getBoundFunctionTarget(); + + /* 15.3.4.5.1 step 2. */ + const Value &boundThis = obj->getBoundFunctionThis(); + + InvokeArgsGuard args; + if (!cx->stack().pushInvokeArgs(cx, argc + argslen, &args)) + return false; + + /* 15.3.4.5.1, 15.3.4.5.2 step 4. */ + memcpy(args.argv(), boundArgs, argslen * sizeof(Value)); + memcpy(args.argv() + argslen, vp + 2, argc * sizeof(Value)); + + /* 15.3.4.5.1, 15.3.4.5.2 step 5. */ + args.callee().setObject(*target); + + if (!constructing) + args.thisv() = boundThis; + + if (constructing ? !InvokeConstructor(cx, args) : !Invoke(cx, args, 0)) + return false; + + *vp = args.rval(); + return true; +} + +} + +/* ES5 15.3.4.5. */ +static JSBool +fun_bind(JSContext *cx, uintN argc, Value *vp) +{ + /* Step 1. */ + Value &thisv = vp[1]; + + /* Step 2. */ + if (!js_IsCallable(thisv)) { + if (JSString *str = js_ValueToString(cx, thisv)) { + JSAutoByteString bytes(cx, str); + if (!!bytes) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_PROTO, + js_Function_str, "bind", bytes.ptr()); + } + } + return false; + } + + JSObject *target = &thisv.toObject(); + + /* Step 3. */ + Value *args = NULL; + uintN argslen = 0; + if (argc > 1) { + args = vp + 3; + argslen = argc - 1; + } + + /* Steps 15-16. */ + uintN length = 0; + if (target->isFunction()) { + uintN nargs = target->getFunctionPrivate()->nargs; + if (nargs > argslen) + length = nargs - argslen; + } + + /* Step 4-6, 10-11. */ + JSAtom *name = target->isFunction() ? target->getFunctionPrivate()->atom : NULL; + + /* NB: Bound functions abuse |parent| to store their target. */ + JSObject *funobj = + js_NewFunction(cx, NULL, CallOrConstructBoundFunction, length, + JSFUN_CONSTRUCTOR, target, name); + if (!funobj) + return false; + + /* Steps 7-9. */ + Value thisArg = argc >= 1 ? vp[2] : UndefinedValue(); + if (!funobj->initBoundFunction(cx, thisArg, args, argslen)) + return false; + + /* Steps 17, 19-21 are handled by fun_resolve. */ + /* Step 18 is the default for new functions. */ + + /* Step 22. */ + vp->setObject(*funobj); + return true; +} + +static JSFunctionSpec function_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, fun_toSource, 0,0), +#endif + JS_FN(js_toString_str, fun_toString, 0,0), + JS_FN(js_apply_str, js_fun_apply, 2,0), + JS_FN(js_call_str, js_fun_call, 1,0), + JS_FN("bind", fun_bind, 1,0), + JS_FS_END +}; + +static JSBool +Function(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = NewFunction(cx, NULL); + if (!obj) + return JS_FALSE; + + /* N.B. overwriting callee with return value */ + JSObject *parent = vp[0].toObject().getParent(); + vp[0].setObject(*obj); + + /* + * NB: (new Function) is not lexically closed by its caller, it's just an + * anonymous function in the top-level scope that its constructor inhabits. + * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42, + * and so would a call to f from another top-level's script or function. + * + * In older versions, before call objects, a new Function was adopted by + * its running context's globalObject, which might be different from the + * top-level reachable from scopeChain (in HTML frames, e.g.). + */ + JSFunction *fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED, + parent, cx->runtime->atomState.anonymousAtom); + if (!fun) + return JS_FALSE; + + /* + * Function is static and not called directly by other functions in this + * file, therefore it is callable only as a native function by js_Invoke. + * Find the scripted caller, possibly skipping other native frames such as + * are built for Function.prototype.call or .apply activations that invoke + * Function indirectly from a script. + */ + JSStackFrame *caller = js_GetScriptedCaller(cx, NULL); + uintN lineno; + const char *filename; + JSPrincipals *principals; + if (caller) { + JSObject *callee = &JS_CALLEE(cx, vp).toObject(); + principals = js_EvalFramePrincipals(cx, callee, caller); + filename = js_ComputeFilename(cx, caller, principals, &lineno); + } else { + filename = NULL; + lineno = 0; + principals = NULL; + } + + /* Belt-and-braces: check that the caller has access to parent. */ + if (!js_CheckPrincipalsAccess(cx, parent, principals, + CLASS_ATOM(cx, Function))) { + return JS_FALSE; + } + + /* + * CSP check: whether new Function() is allowed at all. + * Report errors via CSP is done in the script security manager. + * js_CheckContentSecurityPolicy is defined in jsobj.cpp + */ + if (!js_CheckContentSecurityPolicy(cx, parent)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_FUNCTION); + return JS_FALSE; + } + + Bindings bindings(cx); + AutoBindingsRooter root(cx, bindings); + + Value *argv = vp + 2; + uintN n = argc ? argc - 1 : 0; + if (n > 0) { + enum { OK, BAD, BAD_FORMAL } state; + + /* + * Collect the function-argument arguments into one string, separated + * by commas, then make a tokenstream from that string, and scan it to + * get the arguments. We need to throw the full scanner at the + * problem, because the argument string can legitimately contain + * comments and linefeeds. XXX It might be better to concatenate + * everything up into a function definition and pass it to the + * compiler, but doing it this way is less of a delta from the old + * code. See ECMA 15.3.2.1. + */ + state = BAD_FORMAL; + size_t args_length = 0; + for (uintN i = 0; i < n; i++) { + /* Collect the lengths for all the function-argument arguments. */ + JSString *arg = js_ValueToString(cx, argv[i]); + if (!arg) + return JS_FALSE; + argv[i].setString(arg); + + /* + * Check for overflow. The < test works because the maximum + * JSString length fits in 2 fewer bits than size_t has. + */ + size_t old_args_length = args_length; + args_length = old_args_length + arg->length(); + if (args_length < old_args_length) { + js_ReportAllocationOverflow(cx); + return JS_FALSE; + } + } + + /* Add 1 for each joining comma and check for overflow (two ways). */ + size_t old_args_length = args_length; + args_length = old_args_length + n - 1; + if (args_length < old_args_length || + args_length >= ~(size_t)0 / sizeof(jschar)) { + js_ReportAllocationOverflow(cx); + return JS_FALSE; + } + + /* + * Allocate a string to hold the concatenated arguments, including room + * for a terminating 0. Mark cx->tempPool for later release, to free + * collected_args and its tokenstream in one swoop. + */ + void *mark = JS_ARENA_MARK(&cx->tempPool); + jschar *cp; + JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool, + (args_length+1) * sizeof(jschar)); + if (!cp) { + js_ReportOutOfScriptQuota(cx); + return JS_FALSE; + } + jschar *collected_args = cp; + + /* + * Concatenate the arguments into the new string, separated by commas. + */ + for (uintN i = 0; i < n; i++) { + JSString *arg = argv[i].toString(); + size_t arg_length = arg->length(); + const jschar *arg_chars = arg->getChars(cx); + if (!arg_chars) { + JS_ARENA_RELEASE(&cx->tempPool, mark); + return JS_FALSE; + } + (void) js_strncpy(cp, arg_chars, arg_length); + cp += arg_length; + + /* Add separating comma or terminating 0. */ + *cp++ = (i + 1 < n) ? ',' : 0; + } + + /* Initialize a tokenstream that reads from the given string. */ + TokenStream ts(cx); + if (!ts.init(collected_args, args_length, filename, lineno, cx->findVersion())) { + JS_ARENA_RELEASE(&cx->tempPool, mark); + return JS_FALSE; + } + + /* The argument string may be empty or contain no tokens. */ + TokenKind tt = ts.getToken(); + if (tt != TOK_EOF) { + for (;;) { + /* + * Check that it's a name. This also implicitly guards against + * TOK_ERROR, which was already reported. + */ + if (tt != TOK_NAME) + goto after_args; + + /* + * Get the atom corresponding to the name from the token + * stream; we're assured at this point that it's a valid + * identifier. + */ + JSAtom *atom = ts.currentToken().t_atom; + + /* Check for a duplicate parameter name. */ + if (bindings.hasBinding(cx, atom)) { + JSAutoByteString name; + if (!js_AtomToPrintableString(cx, atom, &name)) { + state = BAD; + goto after_args; + } + if (!ReportCompileErrorNumber(cx, &ts, NULL, + JSREPORT_WARNING | JSREPORT_STRICT, + JSMSG_DUPLICATE_FORMAL, name.ptr())) { + state = BAD; + goto after_args; + } + } + + uint16 dummy; + if (!bindings.addArgument(cx, atom, &dummy)) { + state = BAD; + goto after_args; + } + + /* + * Get the next token. Stop on end of stream. Otherwise + * insist on a comma, get another name, and iterate. + */ + tt = ts.getToken(); + if (tt == TOK_EOF) + break; + if (tt != TOK_COMMA) + goto after_args; + tt = ts.getToken(); + } + } + + state = OK; + after_args: + if (state == BAD_FORMAL && !ts.isError()) { + /* + * Report "malformed formal parameter" iff no illegal char or + * similar scanner error was already reported. + */ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_FORMAL); + } + ts.close(); + JS_ARENA_RELEASE(&cx->tempPool, mark); + if (state != OK) + return JS_FALSE; + } + + JSString *str; + if (argc) { + str = js_ValueToString(cx, argv[argc - 1]); + if (!str) + return JS_FALSE; + argv[argc - 1].setString(str); + } else { + str = cx->runtime->emptyString; + } + + size_t length = str->length(); + const jschar *chars = str->getChars(cx); + if (!chars) + return JS_FALSE; + + return Compiler::compileFunctionBody(cx, fun, principals, &bindings, + chars, length, filename, lineno, cx->findVersion()); +} + +namespace js { + +JS_FRIEND_API(bool) +IsBuiltinFunctionConstructor(JSFunction *fun) +{ + return fun->maybeNative() == Function; +} + +const Shape * +LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj) +{ +#ifdef DEBUG + JSFunction *fun = funobj->getFunctionPrivate(); + JS_ASSERT(fun->isInterpreted()); + JS_ASSERT(!fun->isFunctionPrototype()); + JS_ASSERT(!funobj->isBoundFunction()); +#endif + + jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom); + const Shape *shape = funobj->nativeLookup(id); + if (!shape) { + if (!ResolveInterpretedFunctionPrototype(cx, funobj)) + return false; + shape = funobj->nativeLookup(id); + } + JS_ASSERT(!shape->configurable()); + JS_ASSERT(shape->isDataDescriptor()); + JS_ASSERT(shape->hasSlot()); + JS_ASSERT(!shape->isMethod()); + return shape; +} + +} /* namespace js */ + +static JSBool +ThrowTypeError(JSContext *cx, uintN argc, Value *vp) +{ + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, + JSMSG_THROW_TYPE_ERROR); + return false; +} + +JSObject * +js_InitFunctionClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto = js_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1, + NULL, function_methods, NULL, NULL); + if (!proto) + return NULL; + + JSFunction *fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL); + if (!fun) + return NULL; + fun->flags |= JSFUN_PROTOTYPE; + + JSScript *script = JSScript::NewScript(cx, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, JSVERSION_DEFAULT); + if (!script) + return NULL; + script->noScriptRval = true; + script->code[0] = JSOP_STOP; + script->code[1] = SRC_NULL; +#ifdef CHECK_SCRIPT_OWNER + script->owner = NULL; +#endif + fun->u.i.script = script; + + if (obj->isGlobal()) { + /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */ + JSObject *throwTypeError = + js_NewFunction(cx, NULL, reinterpret_cast(ThrowTypeError), 0, + 0, obj, NULL); + if (!throwTypeError) + return NULL; + + JS_ALWAYS_TRUE(js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_THROWTYPEERROR, + ObjectValue(*throwTypeError))); + } + + return proto; +} + +JSFunction * +js_NewFunction(JSContext *cx, JSObject *funobj, Native native, uintN nargs, + uintN flags, JSObject *parent, JSAtom *atom) +{ + JSFunction *fun; + + if (funobj) { + JS_ASSERT(funobj->isFunction()); + funobj->setParent(parent); + } else { + funobj = NewFunction(cx, parent); + if (!funobj) + return NULL; + } + JS_ASSERT(!funobj->getPrivate()); + fun = (JSFunction *) funobj; + + /* Initialize all function members. */ + fun->nargs = uint16(nargs); + fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | JSFUN_TRCINFO); + if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) { + JS_ASSERT(!native); + JS_ASSERT(nargs == 0); + fun->u.i.skipmin = 0; + fun->u.i.wrapper = false; + fun->u.i.script = NULL; + } else { + fun->u.n.clasp = NULL; + if (flags & JSFUN_TRCINFO) { +#ifdef JS_TRACER + JSNativeTraceInfo *trcinfo = + JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, native); + fun->u.n.native = (js::Native) trcinfo->native; + fun->u.n.trcinfo = trcinfo; +#else + fun->u.n.trcinfo = NULL; +#endif + } else { + fun->u.n.native = native; + fun->u.n.trcinfo = NULL; + } + JS_ASSERT(fun->u.n.native); + } + fun->atom = atom; + + /* Set private to self to indicate non-cloned fully initialized function. */ + FUN_OBJECT(fun)->setPrivate(fun); + return fun; +} + +JSObject * JS_FASTCALL +js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent, + JSObject *proto) +{ + JS_ASSERT(parent); + JS_ASSERT(proto); + + JSObject *clone; + if (cx->compartment == fun->compartment()) { + /* + * The cloned function object does not need the extra JSFunction members + * beyond JSObject as it points to fun via the private slot. + */ + clone = NewNativeClassInstance(cx, &js_FunctionClass, proto, parent); + if (!clone) + return NULL; + clone->setPrivate(fun); + } else { + /* + * Across compartments we have to deep copy JSFunction and clone the + * script (for interpreted functions). + */ + clone = NewFunction(cx, parent); + if (!clone) + return NULL; + JSFunction *cfun = (JSFunction *) clone; + cfun->nargs = fun->nargs; + cfun->flags = fun->flags; + cfun->u = fun->getFunctionPrivate()->u; + cfun->atom = fun->atom; + clone->setPrivate(cfun); + if (cfun->isInterpreted()) { + JSScript *script = cfun->u.i.script; + JS_ASSERT(script); + JS_ASSERT(script->compartment == fun->compartment()); + JS_ASSERT(script->compartment != cx->compartment); + + cfun->u.i.script = js_CloneScript(cx, script); + if (!cfun->u.i.script) + return NULL; +#ifdef CHECK_SCRIPT_OWNER + cfun->script()->owner = NULL; +#endif + js_CallNewScriptHook(cx, cfun->script(), cfun); + } + } + return clone; +} + +#ifdef JS_TRACER +JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CloneFunctionObject, CONTEXT, FUNCTION, OBJECT, OBJECT, 0, + nanojit::ACCSET_STORE_ANY) +#endif + +/* + * Create a new flat closure, but don't initialize the imported upvar + * values. The tracer calls this function and then initializes the upvar + * slots on trace. + */ +JSObject * JS_FASTCALL +js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain) +{ + JS_ASSERT(fun->isFlatClosure()); + JS_ASSERT(JSScript::isValidOffset(fun->script()->upvarsOffset) == + fun->script()->bindings.hasUpvars()); + JS_ASSERT_IF(JSScript::isValidOffset(fun->script()->upvarsOffset), + fun->script()->upvars()->length == fun->script()->bindings.countUpvars()); + + JSObject *closure = CloneFunctionObject(cx, fun, scopeChain); + if (!closure) + return closure; + + uint32 nslots = fun->script()->bindings.countUpvars(); + if (nslots == 0) + return closure; + + Value *upvars = (Value *) cx->malloc(nslots * sizeof(Value)); + if (!upvars) + return NULL; + + closure->setFlatClosureUpvars(upvars); + return closure; +} + +JS_DEFINE_CALLINFO_3(extern, OBJECT, js_AllocFlatClosure, + CONTEXT, FUNCTION, OBJECT, 0, nanojit::ACCSET_STORE_ANY) + +JSObject * +js_NewFlatClosure(JSContext *cx, JSFunction *fun, JSOp op, size_t oplen) +{ + /* + * Flat closures cannot yet be partial, that is, all upvars must be copied, + * or the closure won't be flattened. Therefore they do not need to search + * enclosing scope objects via JSOP_NAME, etc. + * + * FIXME: bug 545759 proposes to enable partial flat closures. Fixing this + * bug requires a GetScopeChainFast call here, along with JS_REQUIRES_STACK + * annotations on this function's prototype and definition. + */ + VOUCH_DOES_NOT_REQUIRE_STACK(); + JSObject *scopeChain = &cx->fp()->scopeChain(); + + JSObject *closure = js_AllocFlatClosure(cx, fun, scopeChain); + if (!closure || !fun->script()->bindings.hasUpvars()) + return closure; + + Value *upvars = closure->getFlatClosureUpvars(); + uintN level = fun->u.i.script->staticLevel; + JSUpvarArray *uva = fun->script()->upvars(); + + for (uint32 i = 0, n = uva->length; i < n; i++) + upvars[i] = GetUpvar(cx, level, uva->vector[i]); + + return closure; +} + +JSObject * +js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun) +{ + JS_ASSERT(cx->fp()->fun()->flags & JSFUN_HEAVYWEIGHT); + JS_ASSERT(!cx->fp()->fun()->optimizedClosure()); + JS_ASSERT(FUN_FLAT_CLOSURE(fun)); + + return WrapEscapingClosure(cx, cx->fp(), fun); +} + +JSFunction * +js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native, + uintN nargs, uintN attrs) +{ + PropertyOp gop; + StrictPropertyOp sop; + JSFunction *fun; + + if (attrs & JSFUN_STUB_GSOPS) { + /* + * JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or + * the defined property's attributes. This allows us to encode another, + * internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h + * for more on this. + */ + attrs &= ~JSFUN_STUB_GSOPS; + gop = PropertyStub; + sop = StrictPropertyStub; + } else { + gop = NULL; + sop = NULL; + } + + /* + * Historically, all objects have had a parent member as intrinsic scope + * chain link. We want to move away from this universal parent, but JS + * requires that function objects have something like parent (ES3 and ES5 + * call it the [[Scope]] internal property), to bake a particular static + * scope environment into each function object. + * + * All function objects thus have parent, including all native functions. + * All native functions defined by the JS_DefineFunction* APIs are created + * via the call below to js_NewFunction, which passes obj as the parent + * parameter, and so binds fun's parent to obj using JSObject::setParent, + * under js_NewFunction (in JSObject::init, called from NewObject -- see + * jsobjinlines.h). + * + * But JSObject::setParent sets the DELEGATE object flag on its receiver, + * to mark the object as a proto or parent of another object. Such objects + * may intervene in property lookups and scope chain searches, so require + * special handling when caching lookup and search results (since such + * intervening objects can in general grow shadowing properties later). + * + * Thus using setParent prematurely flags certain objects, notably class + * prototypes, so that defining native methods on them, where the method's + * name (e.g., toString) is already bound on Object.prototype, triggers + * shadowingShapeChange events and gratuitous shape regeneration. + * + * To fix this longstanding bug, we set check whether obj is already a + * delegate, and if not, then if js_NewFunction flagged obj as a delegate, + * we clear the flag. + * + * We thus rely on the fact that native functions (including indirect eval) + * do not use the property cache or equivalent JIT techniques that require + * this bit to be set on their parent-linked scope chain objects. + * + * Note: we keep API compatibility by setting parent to obj for all native + * function objects, even if obj->getGlobal() would suffice. This should be + * revisited when parent is narrowed to exist only for function objects and + * possibly a few prehistoric scope objects (e.g. event targets). + * + * FIXME: bug 611190. + */ + bool wasDelegate = obj->isDelegate(); + + fun = js_NewFunction(cx, NULL, native, nargs, + attrs & (JSFUN_FLAGS_MASK | JSFUN_TRCINFO), + obj, + JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : NULL); + if (!fun) + return NULL; + + if (!wasDelegate && obj->isDelegate()) + obj->clearDelegate(); + + if (!obj->defineProperty(cx, id, ObjectValue(*fun), gop, sop, attrs & ~JSFUN_FLAGS_MASK)) + return NULL; + return fun; +} + +#if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK) +# error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!" +#endif + +JSFunction * +js_ValueToFunction(JSContext *cx, const Value *vp, uintN flags) +{ + JSObject *funobj; + if (!IsFunctionObject(*vp, &funobj)) { + js_ReportIsNotFunction(cx, vp, flags); + return NULL; + } + return GET_FUNCTION_PRIVATE(cx, funobj); +} + +JSObject * +js_ValueToFunctionObject(JSContext *cx, Value *vp, uintN flags) +{ + JSObject *funobj; + if (!IsFunctionObject(*vp, &funobj)) { + js_ReportIsNotFunction(cx, vp, flags); + return NULL; + } + + return funobj; +} + +JSObject * +js_ValueToCallableObject(JSContext *cx, Value *vp, uintN flags) +{ + if (vp->isObject()) { + JSObject *callable = &vp->toObject(); + if (callable->isCallable()) + return callable; + } + + js_ReportIsNotFunction(cx, vp, flags); + return NULL; +} + +void +js_ReportIsNotFunction(JSContext *cx, const Value *vp, uintN flags) +{ + const char *name = NULL, *source = NULL; + AutoValueRooter tvr(cx); + uintN error = (flags & JSV2F_CONSTRUCT) ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION; + LeaveTrace(cx); + + /* + * We try to the print the code that produced vp if vp is a value in the + * most recent interpreted stack frame. Note that additional values, not + * directly produced by the script, may have been pushed onto the frame's + * expression stack (e.g. by pushInvokeArgs) thereby incrementing sp past + * the depth simulated by ReconstructPCStack. + * + * Conversely, values may have been popped from the stack in preparation + * for a call (e.g., by SplatApplyArgs). Since we must pass an offset from + * the top of the simulated stack to js_ReportValueError3, we do bounds + * checking using the minimum of both the simulated and actual stack depth. + */ + ptrdiff_t spindex = 0; + + FrameRegsIter i(cx); + while (!i.done() && !i.pc()) + ++i; + + if (!i.done()) { + uintN depth = js_ReconstructStackDepth(cx, i.fp()->script(), i.pc()); + Value *simsp = i.fp()->base() + depth; + if (i.fp()->base() <= vp && vp < Min(simsp, i.sp())) + spindex = vp - simsp; + } + + if (!spindex) + spindex = ((flags & JSV2F_SEARCH_STACK) ? JSDVG_SEARCH_STACK : JSDVG_IGNORE_STACK); + + js_ReportValueError3(cx, error, spindex, *vp, NULL, name, source); +} diff --git a/js/src/jsfun.h b/js/src/jsfun.h new file mode 100644 index 0000000..a52092c --- /dev/null +++ b/js/src/jsfun.h @@ -0,0 +1,613 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsfun_h___ +#define jsfun_h___ +/* + * JS function definitions. + */ +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jsobj.h" +#include "jsatom.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jsopcode.h" + +/* + * The high two bits of JSFunction.flags encode whether the function is native + * or interpreted, and if interpreted, what kind of optimized closure form (if + * any) it might be. + * + * 00 not interpreted + * 01 interpreted, neither flat nor null closure + * 10 interpreted, flat closure + * 11 interpreted, null closure + * + * FUN_FLAT_CLOSURE implies FUN_INTERPRETED and u.i.script->upvarsOffset != 0. + * FUN_NULL_CLOSURE implies FUN_INTERPRETED and u.i.script->upvarsOffset == 0. + * + * FUN_INTERPRETED but not FUN_FLAT_CLOSURE and u.i.script->upvarsOffset != 0 + * is an Algol-like function expression or nested function, i.e., a function + * that never escapes upward or downward (heapward), and is only ever called. + * + * Finally, FUN_INTERPRETED and u.i.script->upvarsOffset == 0 could be either + * a non-closure (a global function definition, or any function that uses no + * outer names), or a closure of an escaping function that uses outer names + * whose values can't be snapshot (because the outer names could be reassigned + * after the closure is formed, or because assignments could not be analyzed + * due to with or eval). + * + * Such a hard-case function must use JSOP_NAME, etc., and reify outer function + * activations' call objects, etc. if it's not a global function. + * + * NB: JSFUN_EXPR_CLOSURE reuses JSFUN_STUB_GSOPS, which is an API request flag + * bit only, never stored in fun->flags. + * + * If we need more bits in the future, all flags for FUN_INTERPRETED functions + * can move to u.i.script->flags. For now we use function flag bits to minimize + * pointer-chasing. + */ +#define JSFUN_JOINABLE 0x0001 /* function is null closure that does not + appear to call itself via its own name + or arguments.callee */ + +#define JSFUN_PROTOTYPE 0x0800 /* function is Function.prototype for some + global object */ + +#define JSFUN_EXPR_CLOSURE 0x1000 /* expression closure: function(x) x*x */ +#define JSFUN_TRCINFO 0x2000 /* when set, u.n.trcinfo is non-null, + JSFunctionSpec::call points to a + JSNativeTraceInfo. */ +#define JSFUN_INTERPRETED 0x4000 /* use u.i if kind >= this value else u.n */ +#define JSFUN_FLAT_CLOSURE 0x8000 /* flag (aka "display") closure */ +#define JSFUN_NULL_CLOSURE 0xc000 /* null closure entrains no scope chain */ +#define JSFUN_KINDMASK 0xc000 /* encode interp vs. native and closure + optimization level -- see above */ + +#define FUN_OBJECT(fun) (static_cast(fun)) +#define FUN_KIND(fun) ((fun)->flags & JSFUN_KINDMASK) +#define FUN_SET_KIND(fun,k) ((fun)->flags = ((fun)->flags & ~JSFUN_KINDMASK) | (k)) +#define FUN_INTERPRETED(fun) (FUN_KIND(fun) >= JSFUN_INTERPRETED) +#define FUN_FLAT_CLOSURE(fun)(FUN_KIND(fun) == JSFUN_FLAT_CLOSURE) +#define FUN_NULL_CLOSURE(fun)(FUN_KIND(fun) == JSFUN_NULL_CLOSURE) +#define FUN_SCRIPT(fun) (FUN_INTERPRETED(fun) ? (fun)->u.i.script : NULL) +#define FUN_CLASP(fun) (JS_ASSERT(!FUN_INTERPRETED(fun)), \ + fun->u.n.clasp) +#define FUN_TRCINFO(fun) (JS_ASSERT(!FUN_INTERPRETED(fun)), \ + JS_ASSERT((fun)->flags & JSFUN_TRCINFO), \ + fun->u.n.trcinfo) + +struct JSFunction : public JSObject_Slots2 +{ + /* Functions always have two fixed slots (FUN_CLASS_RESERVED_SLOTS). */ + + uint16 nargs; /* maximum number of specified arguments, + reflected as f.length/f.arity */ + uint16 flags; /* flags, see JSFUN_* below and in jsapi.h */ + union U { + struct { + js::Native native; /* native method pointer or null */ + js::Class *clasp; /* class of objects constructed + by this function */ + JSNativeTraceInfo *trcinfo; + } n; + struct Scripted { + JSScript *script; /* interpreted bytecode descriptor or null */ + uint16 skipmin; /* net skip amount up (toward zero) from + script->staticLevel to nearest upvar, + including upvars in nested functions */ + JSPackedBool wrapper; /* true if this function is a wrapper that + rewrites bytecode optimized for a function + judged non-escaping by the compiler, which + then escaped via the debugger or a rogue + indirect eval; if true, then this function + object's proto is the wrapped object */ + js::Shape *names; /* argument and variable names */ + } i; + void *nativeOrScript; + } u; + JSAtom *atom; /* name for diagnostics and decompiling */ + + bool optimizedClosure() const { return FUN_KIND(this) > JSFUN_INTERPRETED; } + bool needsWrapper() const { return FUN_NULL_CLOSURE(this) && u.i.skipmin != 0; } + bool isInterpreted() const { return FUN_INTERPRETED(this); } + bool isNative() const { return !FUN_INTERPRETED(this); } + bool isConstructor() const { return flags & JSFUN_CONSTRUCTOR; } + bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); } + bool isFlatClosure() const { return FUN_KIND(this) == JSFUN_FLAT_CLOSURE; } + + bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; } + + /* Returns the strictness of this function, which must be interpreted. */ + inline bool inStrictMode() const; + + void setArgCount(uint16 nargs) { + JS_ASSERT(this->nargs == 0); + this->nargs = nargs; + } + + /* uint16 representation bounds number of call object dynamic slots. */ + enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) }; + +#define JS_LOCAL_NAME_TO_ATOM(nameWord) ((JSAtom *) ((nameWord) & ~(jsuword) 1)) +#define JS_LOCAL_NAME_IS_CONST(nameWord) ((((nameWord) & (jsuword) 1)) != 0) + + bool mightEscape() const { + return isInterpreted() && (isFlatClosure() || !script()->bindings.hasUpvars()); + } + + bool joinable() const { + return flags & JSFUN_JOINABLE; + } + + JSObject &compiledFunObj() { + return *this; + } + + private: + /* + * js_FunctionClass reserves two slots, which are free in JSObject::fslots + * without requiring dslots allocation. Null closures that can be joined to + * a compiler-created function object use the first one to hold a mutable + * methodAtom() state variable, needed for correct foo.caller handling. + */ + enum { + METHOD_ATOM_SLOT = JSSLOT_FUN_METHOD_ATOM + }; + + public: + void setJoinable() { + JS_ASSERT(FUN_INTERPRETED(this)); + getSlotRef(METHOD_ATOM_SLOT).setNull(); + flags |= JSFUN_JOINABLE; + } + + /* + * Method name imputed from property uniquely assigned to or initialized, + * where the function does not need to be cloned to carry a scope chain or + * flattened upvars. + */ + JSAtom *methodAtom() const { + return (joinable() && getSlot(METHOD_ATOM_SLOT).isString()) + ? STRING_TO_ATOM(getSlot(METHOD_ATOM_SLOT).toString()) + : NULL; + } + + void setMethodAtom(JSAtom *atom) { + JS_ASSERT(joinable()); + getSlotRef(METHOD_ATOM_SLOT).setString(ATOM_TO_STRING(atom)); + } + + js::Native maybeNative() const { + return isInterpreted() ? NULL : u.n.native; + } + + JSScript *script() const { + JS_ASSERT(isInterpreted()); + return u.i.script; + } + + static uintN offsetOfNativeOrScript() { + JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, i.script)); + JS_STATIC_ASSERT(offsetof(U, n.native) == offsetof(U, nativeOrScript)); + return offsetof(JSFunction, u.nativeOrScript); + } + + /* Number of extra fixed function object slots. */ + static const uint32 CLASS_RESERVED_SLOTS = JSObject::FUN_CLASS_RESERVED_SLOTS; +}; + +/* + * Trace-annotated native. This expands to a JSFunctionSpec initializer (like + * JS_FN in jsapi.h). fastcall is a FastNative; trcinfo is a + * JSNativeTraceInfo*. + */ +#ifdef JS_TRACER +/* MSVC demands the intermediate (void *) cast here. */ +# define JS_TN(name,fastcall,nargs,flags,trcinfo) \ + JS_FN(name, JS_DATA_TO_FUNC_PTR(Native, trcinfo), nargs, \ + (flags) | JSFUN_STUB_GSOPS | JSFUN_TRCINFO) +#else +# define JS_TN(name,fastcall,nargs,flags,trcinfo) \ + JS_FN(name, fastcall, nargs, flags) +#endif + +/* + * NB: the Arguments classes are uninitialized internal classes that masquerade + * (according to Object.prototype.toString.call(arguments)) as "Arguments", + * while having Object.getPrototypeOf(arguments) === Object.prototype. + * + * WARNING (to alert embedders reading this private .h file): arguments objects + * are *not* thread-safe and should not be used concurrently -- they should be + * used by only one thread at a time, preferably by only one thread over their + * lifetime (a JS worker that migrates from one OS thread to another but shares + * nothing is ok). + * + * Yes, this is an incompatible change, which prefigures the impending move to + * single-threaded objects and GC heaps. + */ +extern js::Class js_ArgumentsClass; + +namespace js { + +extern Class StrictArgumentsClass; + +struct ArgumentsData { + js::Value callee; + js::Value slots[1]; +}; + +} + +inline bool +JSObject::isNormalArguments() const +{ + return getClass() == &js_ArgumentsClass; +} + +inline bool +JSObject::isStrictArguments() const +{ + return getClass() == &js::StrictArgumentsClass; +} + +inline bool +JSObject::isArguments() const +{ + return isNormalArguments() || isStrictArguments(); +} + +#define JS_ARGUMENTS_OBJECT_ON_TRACE ((void *)0xa126) + +extern JS_PUBLIC_DATA(js::Class) js_CallClass; +extern JS_PUBLIC_DATA(js::Class) js_FunctionClass; +extern js::Class js_DeclEnvClass; + +inline bool +JSObject::isCall() const +{ + return getClass() == &js_CallClass; +} + +inline bool +JSObject::isFunction() const +{ + return getClass() == &js_FunctionClass; +} + +inline JSFunction * +JSObject::getFunctionPrivate() const +{ + JS_ASSERT(isFunction()); + return reinterpret_cast(getPrivate()); +} + +namespace js { + +/* + * Construct a call object for the given bindings. If this is a call object + * for a function invocation, callee should be the function being called. + * Otherwise it must be a call object for eval of strict mode code, and callee + * must be null. + */ +extern JSObject * +NewCallObject(JSContext *cx, js::Bindings *bindings, JSObject &scopeChain, JSObject *callee); + +/* + * NB: jsapi.h and jsobj.h must be included before any call to this macro. + */ +#define VALUE_IS_FUNCTION(cx, v) \ + (!JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isFunction()) + +static JS_ALWAYS_INLINE bool +IsFunctionObject(const js::Value &v) +{ + return v.isObject() && v.toObject().isFunction(); +} + +static JS_ALWAYS_INLINE bool +IsFunctionObject(const js::Value &v, JSObject **funobj) +{ + return v.isObject() && (*funobj = &v.toObject())->isFunction(); +} + +static JS_ALWAYS_INLINE bool +IsFunctionObject(const js::Value &v, JSFunction **fun) +{ + JSObject *funobj; + bool b = IsFunctionObject(v, &funobj); + if (b) + *fun = funobj->getFunctionPrivate(); + return b; +} + +extern JS_ALWAYS_INLINE bool +SameTraceType(const Value &lhs, const Value &rhs) +{ + return SameType(lhs, rhs) && + (lhs.isPrimitive() || + lhs.toObject().isFunction() == rhs.toObject().isFunction()); +} + +/* + * Macro to access the private slot of the function object after the slot is + * initialized. + */ +#define GET_FUNCTION_PRIVATE(cx, funobj) \ + (JS_ASSERT((funobj)->isFunction()), \ + (JSFunction *) (funobj)->getPrivate()) + +/* + * Return true if this is a compiler-created internal function accessed by + * its own object. Such a function object must not be accessible to script + * or embedding code. + */ +inline bool +IsInternalFunctionObject(JSObject *funobj) +{ + JS_ASSERT(funobj->isFunction()); + JSFunction *fun = (JSFunction *) funobj->getPrivate(); + return funobj == fun && (fun->flags & JSFUN_LAMBDA) && !funobj->getParent(); +} + +/* Valueified JS_IsConstructing. */ +static JS_ALWAYS_INLINE bool +IsConstructing(const Value *vp) +{ +#ifdef DEBUG + JSObject *callee = &JS_CALLEE(cx, vp).toObject(); + if (callee->isFunction()) { + JSFunction *fun = callee->getFunctionPrivate(); + JS_ASSERT((fun->flags & JSFUN_CONSTRUCTOR) != 0); + } else { + JS_ASSERT(callee->getClass()->construct != NULL); + } +#endif + return vp[1].isMagic(); +} + +static JS_ALWAYS_INLINE bool +IsConstructing_PossiblyWithGivenThisObject(const Value *vp, JSObject **ctorThis) +{ +#ifdef DEBUG + JSObject *callee = &JS_CALLEE(cx, vp).toObject(); + if (callee->isFunction()) { + JSFunction *fun = callee->getFunctionPrivate(); + JS_ASSERT((fun->flags & JSFUN_CONSTRUCTOR) != 0); + } else { + JS_ASSERT(callee->getClass()->construct != NULL); + } +#endif + bool isCtor = vp[1].isMagic(); + if (isCtor) + *ctorThis = vp[1].getMagicObjectOrNullPayload(); + return isCtor; +} + +inline const char * +GetFunctionNameBytes(JSContext *cx, JSFunction *fun, JSAutoByteString *bytes) +{ + if (fun->atom) + return bytes->encode(cx, ATOM_TO_STRING(fun->atom)); + return js_anonymous_str; +} + +extern JS_FRIEND_API(bool) +IsBuiltinFunctionConstructor(JSFunction *fun); + +/* + * Preconditions: funobj->isInterpreted() && !funobj->isFunctionPrototype() && + * !funobj->isBoundFunction(). This is sufficient to establish that funobj has + * a non-configurable non-method .prototype data property, thought it might not + * have been resolved yet, and its value could be anything. + * + * Return the shape of the .prototype property of funobj, resolving it if + * needed. On error, return NULL. + * + * This is not safe to call on trace because it defines properties, which can + * trigger lookups that could reenter. + */ +const Shape * +LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj); + +} /* namespace js */ + +extern JSString * +fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent); + +extern JSFunction * +js_NewFunction(JSContext *cx, JSObject *funobj, js::Native native, uintN nargs, + uintN flags, JSObject *parent, JSAtom *atom); + +extern JSObject * +js_InitFunctionClass(JSContext *cx, JSObject *obj); + +extern JSObject * +js_InitArgumentsClass(JSContext *cx, JSObject *obj); + +extern void +js_TraceFunction(JSTracer *trc, JSFunction *fun); + +extern void +js_FinalizeFunction(JSContext *cx, JSFunction *fun); + +extern JSObject * JS_FASTCALL +js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent, + JSObject *proto); + +inline JSObject * +CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent) +{ + JS_ASSERT(parent); + JSObject *proto; + if (!js_GetClassPrototype(cx, parent, JSProto_Function, &proto)) + return NULL; + return js_CloneFunctionObject(cx, fun, parent, proto); +} + +extern JSObject * JS_FASTCALL +js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain); + +extern JSObject * +js_NewFlatClosure(JSContext *cx, JSFunction *fun, JSOp op, size_t oplen); + +extern JS_REQUIRES_STACK JSObject * +js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun); + +extern JSFunction * +js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, js::Native native, + uintN nargs, uintN flags); + +/* + * Flags for js_ValueToFunction and js_ReportIsNotFunction. We depend on the + * fact that JSINVOKE_CONSTRUCT (aka JSFRAME_CONSTRUCTING) is 1, and test that + * with #if/#error in jsfun.c. + */ +#define JSV2F_CONSTRUCT JSINVOKE_CONSTRUCT +#define JSV2F_SEARCH_STACK 0x10000 + +extern JSFunction * +js_ValueToFunction(JSContext *cx, const js::Value *vp, uintN flags); + +extern JSObject * +js_ValueToFunctionObject(JSContext *cx, js::Value *vp, uintN flags); + +extern JSObject * +js_ValueToCallableObject(JSContext *cx, js::Value *vp, uintN flags); + +extern void +js_ReportIsNotFunction(JSContext *cx, const js::Value *vp, uintN flags); + +extern JSObject * +js_GetCallObject(JSContext *cx, JSStackFrame *fp); + +extern JSObject * JS_FASTCALL +js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSObject *scopeChain); + +extern void +js_PutCallObject(JSContext *cx, JSStackFrame *fp); + +extern JSBool JS_FASTCALL +js_PutCallObjectOnTrace(JSContext *cx, JSObject *scopeChain, uint32 nargs, + js::Value *argv, uint32 nvars, js::Value *slots); + +namespace js { + +extern JSBool +GetCallArg(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); + +extern JSBool +GetCallVar(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); + +/* + * Slower version of js_GetCallVar used when call_resolve detects an attempt to + * leak an optimized closure via indirect or debugger eval. + */ +extern JSBool +GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); + +extern JSBool +GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); + +extern JSBool +SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp); + +extern JSBool +SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp); + +extern JSBool +SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp); + +} // namespace js + +extern JSBool +js_GetArgsValue(JSContext *cx, JSStackFrame *fp, js::Value *vp); + +extern JSBool +js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, js::Value *vp); + +/* + * Get the arguments object for the given frame. If the frame is strict mode + * code, its current arguments will be copied into the arguments object. + * + * NB: Callers *must* get the arguments object before any parameters are + * mutated when the frame is strict mode code! The emitter ensures this + * occurs for strict mode functions containing syntax which might mutate a + * named parameter by synthesizing an arguments access at the start of the + * function. + */ +extern JSObject * +js_GetArgsObject(JSContext *cx, JSStackFrame *fp); + +extern void +js_PutArgsObject(JSContext *cx, JSStackFrame *fp); + +inline bool +js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->atom; } + +/* + * Maximum supported value of arguments.length. It bounds the maximum number of + * arguments that can be supplied via the second (so-called |argArray|) param + * to Function.prototype.apply. This value also bounds the number of elements + * parsed in an array initialiser. + * + * The thread's stack is the limiting factor for this number. It is currently + * 2MB, which fits a little less than 2^19 arguments (once the stack frame, + * callstack, etc. are included). Pick a max args length that is a little less. + */ +const uint32 JS_ARGS_LENGTH_MAX = JS_BIT(19) - 1024; + +/* + * JSSLOT_ARGS_LENGTH stores ((argc << 1) | overwritten_flag) as an Int32 + * Value. Thus (JS_ARGS_LENGTH_MAX << 1) | 1 must be less than JSVAL_INT_MAX. + */ +JS_STATIC_ASSERT(JS_ARGS_LENGTH_MAX <= JS_BIT(30)); +JS_STATIC_ASSERT(((JS_ARGS_LENGTH_MAX << 1) | 1) <= JSVAL_INT_MAX); + +extern JSBool +js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp); + +extern JSBool +js_fun_apply(JSContext *cx, uintN argc, js::Value *vp); + +extern JSBool +js_fun_call(JSContext *cx, uintN argc, js::Value *vp); + +#endif /* jsfun_h___ */ diff --git a/js/src/jsfuninlines.h b/js/src/jsfuninlines.h new file mode 100644 index 0000000..4cbb744 --- /dev/null +++ b/js/src/jsfuninlines.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsfuninlines_h___ +#define jsfuninlines_h___ + +#include "jsfun.h" +#include "jsscript.h" + +inline bool +JSFunction::inStrictMode() const +{ + return script()->strictModeCode; +} + +#endif /* jsfuninlines_h___ */ diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp new file mode 100644 index 0000000..3fe567d --- /dev/null +++ b/js/src/jsgc.cpp @@ -0,0 +1,2951 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS Mark-and-Sweep Garbage Collector. + * + * This GC allocates fixed-sized things with sizes up to GC_NBYTES_MAX (see + * jsgc.h). It allocates from a special GC arena pool with each arena allocated + * using malloc. It uses an ideally parallel array of flag bytes to hold the + * mark bit, finalizer type index, etc. + * + * XXX swizzle page to freelist for better locality of reference + */ +#include /* for free */ +#include +#include /* for memset used when DEBUG */ +#include "jstypes.h" +#include "jsstdint.h" +#include "jsutil.h" +#include "jshash.h" +#include "jsbit.h" +#include "jsclist.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdbgapi.h" +#include "jsexn.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsgcchunk.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsparse.h" +#include "jsproxy.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstaticcheck.h" +#include "jsstr.h" +#include "jstracer.h" +#include "methodjit/MethodJIT.h" + +#if JS_HAS_XML_SUPPORT +#include "jsxml.h" +#endif + +#include "jsprobes.h" +#include "jscntxtinlines.h" +#include "jsinterpinlines.h" +#include "jsobjinlines.h" +#include "jshashtable.h" + +#include "jsstrinlines.h" +#include "jscompartment.h" + +#ifdef MOZ_VALGRIND +# define JS_VALGRIND +#endif +#ifdef JS_VALGRIND +# include +#endif + +using namespace js; +using namespace js::gc; + +/* + * Check that JSTRACE_XML follows JSTRACE_OBJECT and JSTRACE_STRING. + */ +JS_STATIC_ASSERT(JSTRACE_OBJECT == 0); +JS_STATIC_ASSERT(JSTRACE_STRING == 1); +JS_STATIC_ASSERT(JSTRACE_XML == 2); + +/* + * JS_IS_VALID_TRACE_KIND assumes that JSTRACE_STRING is the last non-xml + * trace kind when JS_HAS_XML_SUPPORT is false. + */ +JS_STATIC_ASSERT(JSTRACE_STRING + 1 == JSTRACE_XML); + +/* + * Everything we store in the heap must be a multiple of the cell size. + */ +JS_STATIC_ASSERT(sizeof(JSString) % sizeof(FreeCell) == 0); +JS_STATIC_ASSERT(sizeof(JSShortString) % sizeof(FreeCell) == 0); +JS_STATIC_ASSERT(sizeof(JSObject) % sizeof(FreeCell) == 0); +JS_STATIC_ASSERT(sizeof(JSFunction) % sizeof(FreeCell) == 0); +#ifdef JSXML +JS_STATIC_ASSERT(sizeof(JSXML) % sizeof(FreeCell) == 0); +#endif + +/* + * All arenas must be exactly 4k. + */ +JS_STATIC_ASSERT(sizeof(Arena) == 4096); +JS_STATIC_ASSERT(sizeof(Arena) == 4096); +JS_STATIC_ASSERT(sizeof(Arena) == 4096); +JS_STATIC_ASSERT(sizeof(Arena) == 4096); +JS_STATIC_ASSERT(sizeof(Arena) == 4096); +JS_STATIC_ASSERT(sizeof(Arena) == 4096); + +#ifdef JS_GCMETER +# define METER(x) ((void) (x)) +# define METER_IF(condition, x) ((void) ((condition) && (x))) +#else +# define METER(x) ((void) 0) +# define METER_IF(condition, x) ((void) 0) +#endif + +# define METER_UPDATE_MAX(maxLval, rval) \ + METER_IF((maxLval) < (rval), (maxLval) = (rval)) + +namespace js{ +namespace gc{ + +/* This array should be const, but that doesn't link right under GCC. */ +FinalizeKind slotsToThingKind[] = { + /* 0 */ FINALIZE_OBJECT0, FINALIZE_OBJECT2, FINALIZE_OBJECT2, FINALIZE_OBJECT4, + /* 4 */ FINALIZE_OBJECT4, FINALIZE_OBJECT8, FINALIZE_OBJECT8, FINALIZE_OBJECT8, + /* 8 */ FINALIZE_OBJECT8, FINALIZE_OBJECT12, FINALIZE_OBJECT12, FINALIZE_OBJECT12, + /* 12 */ FINALIZE_OBJECT12, FINALIZE_OBJECT16, FINALIZE_OBJECT16, FINALIZE_OBJECT16, + /* 16 */ FINALIZE_OBJECT16 +}; + +JS_STATIC_ASSERT(JS_ARRAY_LENGTH(slotsToThingKind) == SLOTS_TO_THING_KIND_LIMIT); + +/* Initialize the arena and setup the free list. */ +template +void +Arena::init(JSCompartment *compartment, unsigned thingKind) +{ + aheader.compartment = compartment; + aheader.thingKind = thingKind; + aheader.freeList = &t.things[0].cell; + aheader.thingSize = sizeof(T); + aheader.isUsed = true; + JS_ASSERT(sizeof(T) == sizeof(ThingOrCell)); + ThingOrCell *thing = &t.things[0]; + ThingOrCell *last = &t.things[JS_ARRAY_LENGTH(t.things) - 1]; + while (thing < last) { + thing->cell.link = &(thing + 1)->cell; + ++thing; + } + last->cell.link = NULL; +#ifdef DEBUG + aheader.hasFreeThings = true; +#endif +} + +template +bool +Arena::inFreeList(void *thing) const +{ + FreeCell *cursor = aheader.freeList; + while (cursor) { + JS_ASSERT(aheader.thingSize == sizeof(T)); + JS_ASSERT(!cursor->isMarked()); + + /* If the cursor moves past the thing, it's not in the freelist. */ + if (thing < cursor) + break; + + /* If we find it on the freelist, it's dead. */ + if (thing == cursor) + return true; + JS_ASSERT_IF(cursor->link, cursor < cursor->link); + cursor = cursor->link; + } + return false; +} + +template +inline ConservativeGCTest +Arena::mark(T *thing, JSTracer *trc) +{ + JS_ASSERT(sizeof(T) == aheader.thingSize); + + T *alignedThing = getAlignedThing(thing); + + if (alignedThing > &t.things[ThingsPerArena-1].t || alignedThing < &t.things[0].t) + return CGCT_NOTARENA; + + if (!aheader.isUsed || inFreeList(alignedThing)) + return CGCT_NOTLIVE; + + JS_SET_TRACING_NAME(trc, "machine stack"); + Mark(trc, alignedThing); + +#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS + if (alignedThing != thing) + return CGCT_VALIDWITHOFFSET; +#endif + return CGCT_VALID; +} + +#ifdef DEBUG +bool +checkArenaListsForThing(JSCompartment *comp, void *thing) { + if (comp->arenas[FINALIZE_OBJECT0].arenasContainThing(thing) || + comp->arenas[FINALIZE_OBJECT2].arenasContainThing(thing) || + comp->arenas[FINALIZE_OBJECT4].arenasContainThing(thing) || + comp->arenas[FINALIZE_OBJECT8].arenasContainThing(thing) || + comp->arenas[FINALIZE_OBJECT12].arenasContainThing(thing) || + comp->arenas[FINALIZE_OBJECT16].arenasContainThing(thing) || + comp->arenas[FINALIZE_FUNCTION].arenasContainThing(thing) || +#if JS_HAS_XML_SUPPORT + comp->arenas[FINALIZE_XML].arenasContainThing(thing) || +#endif + comp->arenas[FINALIZE_STRING].arenasContainThing(thing) || + comp->arenas[FINALIZE_EXTERNAL_STRING].arenasContainThing(thing) || + comp->arenas[FINALIZE_SHORT_STRING].arenasContainThing(thing)) { + return true; + } + + return false; +} + +bool +checkArenaListAllUnmarked(JSCompartment *comp) { + for (unsigned i = 0; i < FINALIZE_LIMIT; i++) { + if (comp->arenas[i].markedThingsInArenaList()) + return false; + } + return true; +} +#endif + +} /* namespace gc */ +} /* namespace js */ + +void +JSCompartment::finishArenaLists() +{ + for (int i = 0; i < FINALIZE_LIMIT; i++) + arenas[i].releaseAll(); +} + +void +Chunk::clearMarkBitmap() +{ + PodZero(&bitmaps[0], ArenasPerChunk); +} + +void +Chunk::init(JSRuntime *rt) +{ + info.runtime = rt; + info.age = 0; + info.emptyArenaLists.init(); + info.emptyArenaLists.cellFreeList = &arenas[0]; + Arena *arena = &arenas[0]; + Arena *last = &arenas[JS_ARRAY_LENGTH(arenas) - 1]; + while (arena < last) { + arena->header()->next = arena + 1; + arena->header()->isUsed = false; + ++arena; + } + last->header()->next = NULL; + last->header()->isUsed = false; + info.numFree = ArenasPerChunk; +} + +bool +Chunk::unused() +{ + return info.numFree == ArenasPerChunk; +} + +bool +Chunk::hasAvailableArenas() +{ + return info.numFree > 0; +} + +bool +Chunk::withinArenasRange(Cell *cell) +{ + uintptr_t addr = uintptr_t(cell); + if (addr >= uintptr_t(&arenas[0]) && addr < uintptr_t(&arenas[ArenasPerChunk])) + return true; + return false; +} + +template +Arena * +Chunk::allocateArena(JSCompartment *comp, unsigned thingKind) +{ + JS_ASSERT(hasAvailableArenas()); + Arena *arena = info.emptyArenaLists.getNext(comp, thingKind); + JS_ASSERT(arena); + JS_ASSERT(arena->header()->isUsed); + --info.numFree; + + JSRuntime *rt = info.runtime; + rt->gcBytes += sizeof(Arena); + comp->gcBytes += sizeof(Arena); + if (comp->gcBytes >= comp->gcTriggerBytes) + TriggerCompartmentGC(comp); + METER(rt->gcStats.nallarenas++); + return arena; +} + +template +void +Chunk::releaseArena(Arena *arena) +{ + JSRuntime *rt = info.runtime; + JSCompartment *comp = arena->header()->compartment; + METER(rt->gcStats.afree++); + JS_ASSERT(rt->gcStats.nallarenas != 0); + METER(rt->gcStats.nallarenas--); + JS_ASSERT(rt->gcBytes >= sizeof(Arena)); + JS_ASSERT(comp->gcBytes >= sizeof(Arena)); + + rt->gcBytes -= sizeof(Arena); + comp->gcBytes -= sizeof(Arena); + info.emptyArenaLists.insert((Arena *)arena); + arena->header()->isUsed = false; + ++info.numFree; + if (unused()) + info.age = 0; +} + +JSRuntime * +Chunk::getRuntime() +{ + return info.runtime; +} + +inline jsuword +GetGCChunk(JSRuntime *rt) +{ + void *p = rt->gcChunkAllocator->alloc(); +#ifdef MOZ_GCTIMER + if (p) + JS_ATOMIC_INCREMENT(&newChunkCount); +#endif + METER_IF(p, rt->gcStats.nchunks++); + METER_UPDATE_MAX(rt->gcStats.maxnchunks, rt->gcStats.nchunks); + return reinterpret_cast(p); +} + +inline void +ReleaseGCChunk(JSRuntime *rt, jsuword chunk) +{ + void *p = reinterpret_cast(chunk); + JS_ASSERT(p); +#ifdef MOZ_GCTIMER + JS_ATOMIC_INCREMENT(&destroyChunkCount); +#endif + JS_ASSERT(rt->gcStats.nchunks != 0); + METER(rt->gcStats.nchunks--); + rt->gcChunkAllocator->free(p); +} + +inline Chunk * +AllocateGCChunk(JSRuntime *rt) +{ + Chunk *p = (Chunk *)rt->gcChunkAllocator->alloc(); +#ifdef MOZ_GCTIMER + if (p) + JS_ATOMIC_INCREMENT(&newChunkCount); +#endif + METER_IF(p, rt->gcStats.nchunks++); + return p; +} + +inline void +ReleaseGCChunk(JSRuntime *rt, Chunk *p) +{ + JS_ASSERT(p); +#ifdef MOZ_GCTIMER + JS_ATOMIC_INCREMENT(&destroyChunkCount); +#endif + JS_ASSERT(rt->gcStats.nchunks != 0); + METER(rt->gcStats.nchunks--); + rt->gcChunkAllocator->free(p); +} + +static Chunk * +PickChunk(JSRuntime *rt) +{ + Chunk *chunk; + for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) { + if (r.front()->hasAvailableArenas()) + return r.front(); + } + + chunk = AllocateGCChunk(rt); + if (!chunk) + return NULL; + + /* + * FIXME bug 583732 - chunk is newly allocated and cannot be present in + * the table so using ordinary lookupForAdd is suboptimal here. + */ + GCChunkSet::AddPtr p = rt->gcChunkSet.lookupForAdd(chunk); + JS_ASSERT(!p); + if (!rt->gcChunkSet.add(p, chunk)) { + ReleaseGCChunk(rt, chunk); + return NULL; + } + + chunk->init(rt); + + return chunk; +} + +static void +ExpireGCChunks(JSRuntime *rt) +{ + static const size_t MaxAge = 3; + + /* Remove unused chunks. */ + AutoLockGC lock(rt); + + rt->gcChunksWaitingToExpire = 0; + for (GCChunkSet::Enum e(rt->gcChunkSet); !e.empty(); e.popFront()) { + Chunk *chunk = e.front(); + JS_ASSERT(chunk->info.runtime == rt); + if (chunk->unused()) { + if (chunk->info.age++ > MaxAge) { + e.removeFront(); + ReleaseGCChunk(rt, chunk); + continue; + } + rt->gcChunksWaitingToExpire++; + } + } +} + +template +static Arena * +AllocateArena(JSContext *cx, unsigned thingKind) +{ + JSRuntime *rt = cx->runtime; + AutoLockGC lock(rt); + Chunk *chunk = cx->compartment->chunk; + if (!chunk || !chunk->hasAvailableArenas()) { + chunk = PickChunk(rt); + if (!chunk) { + TriggerGC(rt); + return NULL; + } + cx->compartment->chunk = chunk; + } + return chunk->allocateArena(cx->compartment, thingKind); +} + +JS_FRIEND_API(bool) +IsAboutToBeFinalized(JSContext *cx, void *thing) +{ + if (JSString::isStatic(thing)) + return false; + JS_ASSERT(cx); + + JSCompartment *thingCompartment = reinterpret_cast(thing)->compartment(); + JSRuntime *rt = cx->runtime; + JS_ASSERT(rt == thingCompartment->rt); + if (rt->gcCurrentCompartment != NULL && rt->gcCurrentCompartment != thingCompartment) + return false; + + return !reinterpret_cast(thing)->isMarked(); +} + +JS_FRIEND_API(bool) +js_GCThingIsMarked(void *thing, uintN color = BLACK) +{ + JS_ASSERT(thing); + AssertValidColor(thing, color); + return reinterpret_cast(thing)->isMarked(color); +} + +/* + * 1/8 life for JIT code. After this number of microseconds have passed, 1/8 of all + * JIT code is discarded in inactive compartments, regardless of how often that + * code runs. + */ +static const int64 JIT_SCRIPT_EIGHTH_LIFETIME = 120 * 1000 * 1000; + +JSBool +js_InitGC(JSRuntime *rt, uint32 maxbytes) +{ + /* + * Make room for at least 16 chunks so the table would not grow before + * the browser starts up. + */ + if (!rt->gcChunkSet.init(16)) + return false; + + if (!rt->gcRootsHash.init(256)) + return false; + + if (!rt->gcLocksHash.init(256)) + return false; + +#ifdef JS_THREADSAFE + rt->gcLock = JS_NEW_LOCK(); + if (!rt->gcLock) + return false; + rt->gcDone = JS_NEW_CONDVAR(rt->gcLock); + if (!rt->gcDone) + return false; + rt->requestDone = JS_NEW_CONDVAR(rt->gcLock); + if (!rt->requestDone) + return false; + if (!rt->gcHelperThread.init(rt)) + return false; +#endif + + /* + * Separate gcMaxMallocBytes from gcMaxBytes but initialize to maxbytes + * for default backward API compatibility. + */ + rt->gcMaxBytes = maxbytes; + rt->setGCMaxMallocBytes(maxbytes); + + rt->gcEmptyArenaPoolLifespan = 30000; + + rt->gcTriggerFactor = uint32(100.0f * GC_HEAP_GROWTH_FACTOR); + + rt->atomsCompartment->setGCLastBytes(8192); + + /* + * The assigned value prevents GC from running when GC memory is too low + * (during JS engine start). + */ + rt->setGCLastBytes(8192); + + rt->gcJitReleaseTime = PRMJ_Now() + JIT_SCRIPT_EIGHTH_LIFETIME; + + METER(PodZero(&rt->gcStats)); + return true; +} + +namespace js { + +template +static inline ConservativeGCTest +MarkCell(Cell *cell, JSTracer *trc) +{ + return GetArena(cell)->mark((T *)cell, trc); +} + +/* + * Returns CGCT_VALID or CGCT_VALIDWITHOFFSET and mark it if the w can be a + * live GC thing and sets thingKind accordingly. Otherwise returns the + * reason for rejection. + */ +inline ConservativeGCTest +MarkIfGCThingWord(JSTracer *trc, jsuword w, uint32 &thingKind) +{ + JSRuntime *rt = trc->context->runtime; + /* + * The conservative scanner may access words that valgrind considers as + * undefined. To avoid false positives and not to alter valgrind view of + * the memory we make as memcheck-defined the argument, a copy of the + * original word. See bug 572678. + */ +#ifdef JS_VALGRIND + VALGRIND_MAKE_MEM_DEFINED(&w, sizeof(w)); +#endif + + /* + * We assume that the compiler never uses sub-word alignment to store + * pointers and does not tag pointers on its own. Additionally, the value + * representation for all values and the jsid representation for GC-things + * do not touch the low two bits. Thus any word with the low two bits set + * is not a valid GC-thing. + */ + JS_STATIC_ASSERT(JSID_TYPE_STRING == 0 && JSID_TYPE_OBJECT == 4); + if (w & 0x3) + return CGCT_LOWBITSET; + + /* + * An object jsid has its low bits tagged. In the value representation on + * 64-bit, the high bits are tagged. + */ + const jsuword JSID_PAYLOAD_MASK = ~jsuword(JSID_TYPE_MASK); +#if JS_BITS_PER_WORD == 32 + jsuword payload = w & JSID_PAYLOAD_MASK; +#elif JS_BITS_PER_WORD == 64 + jsuword payload = w & JSID_PAYLOAD_MASK & JSVAL_PAYLOAD_MASK; +#endif + + Cell *cell = reinterpret_cast(payload); + Chunk *chunk = cell->chunk(); + + if (!rt->gcChunkSet.has(chunk)) + return CGCT_NOTCHUNK; + + if (!chunk->withinArenasRange(cell)) + return CGCT_NOTARENA; + + ArenaHeader *aheader = cell->arena()->header(); + + if (!aheader->isUsed) + return CGCT_FREEARENA; + + ConservativeGCTest test; + thingKind = aheader->thingKind; + + switch (thingKind) { + case FINALIZE_OBJECT0: + test = MarkCell(cell, trc); + break; + case FINALIZE_OBJECT2: + test = MarkCell(cell, trc); + break; + case FINALIZE_OBJECT4: + test = MarkCell(cell, trc); + break; + case FINALIZE_OBJECT8: + test = MarkCell(cell, trc); + break; + case FINALIZE_OBJECT12: + test = MarkCell(cell, trc); + break; + case FINALIZE_OBJECT16: + test = MarkCell(cell, trc); + break; + case FINALIZE_STRING: + test = MarkCell(cell, trc); + break; + case FINALIZE_EXTERNAL_STRING: + test = MarkCell(cell, trc); + break; + case FINALIZE_SHORT_STRING: + test = MarkCell(cell, trc); + break; + case FINALIZE_FUNCTION: + test = MarkCell(cell, trc); + break; +#if JS_HAS_XML_SUPPORT + case FINALIZE_XML: + test = MarkCell(cell, trc); + break; +#endif + default: + test = CGCT_WRONGTAG; + JS_NOT_REACHED("wrong tag"); + } + + return test; +} + +inline ConservativeGCTest +MarkIfGCThingWord(JSTracer *trc, jsuword w) +{ + uint32 thingKind; + return MarkIfGCThingWord(trc, w, thingKind); +} + +static void +MarkWordConservatively(JSTracer *trc, jsuword w) +{ + /* + * The conservative scanner may access words that valgrind considers as + * undefined. To avoid false positives and not to alter valgrind view of + * the memory we make as memcheck-defined the argument, a copy of the + * original word. See bug 572678. + */ +#ifdef JS_VALGRIND + VALGRIND_MAKE_MEM_DEFINED(&w, sizeof(w)); +#endif + + uint32 thingKind; +#if defined JS_DUMP_CONSERVATIVE_GC_ROOTS || defined JS_GCMETER + ConservativeGCTest test = +#endif + MarkIfGCThingWord(trc, w, thingKind); + +#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS + if (test == CGCT_VALID || test == CGCT_VALIDWITHOFFSET) { + if (IS_GC_MARKING_TRACER(trc) && static_cast(trc)->conservativeDumpFileName) { + const jsuword JSID_PAYLOAD_MASK = ~jsuword(JSID_TYPE_MASK); +#if JS_BITS_PER_WORD == 32 + jsuword payload = w & JSID_PAYLOAD_MASK; +#elif JS_BITS_PER_WORD == 64 + jsuword payload = w & JSID_PAYLOAD_MASK & JSVAL_PAYLOAD_MASK; +#endif + void *thing = (test == CGCT_VALIDWITHOFFSET) + ? GetAlignedThing((void *)payload, thingKind) + : (void *)payload; + GCMarker::ConservativeRoot root = {thing, thingKind}; + static_cast(trc)->conservativeRoots.append(root); + } + } +#endif + +#if defined JS_DUMP_CONSERVATIVE_GC_ROOTS || defined JS_GCMETER + if (IS_GC_MARKING_TRACER(trc)) + static_cast(trc)->conservativeStats.counter[test]++; +#endif +} + +static void +MarkRangeConservatively(JSTracer *trc, const jsuword *begin, const jsuword *end) +{ + JS_ASSERT(begin <= end); + for (const jsuword *i = begin; i != end; ++i) + MarkWordConservatively(trc, *i); +} + +static void +MarkThreadDataConservatively(JSTracer *trc, JSThreadData *td) +{ + ConservativeGCThreadData *ctd = &td->conservativeGC; + JS_ASSERT(ctd->hasStackToScan()); + jsuword *stackMin, *stackEnd; +#if JS_STACK_GROWTH_DIRECTION > 0 + stackMin = td->nativeStackBase; + stackEnd = ctd->nativeStackTop; +#else + stackMin = ctd->nativeStackTop + 1; + stackEnd = td->nativeStackBase; +#endif + JS_ASSERT(stackMin <= stackEnd); + MarkRangeConservatively(trc, stackMin, stackEnd); + MarkRangeConservatively(trc, ctd->registerSnapshot.words, + JS_ARRAY_END(ctd->registerSnapshot.words)); + +} + +void +MarkStackRangeConservatively(JSTracer *trc, Value *beginv, Value *endv) +{ + const jsuword *begin = beginv->payloadWord(); + const jsuword *end = endv->payloadWord();; +#ifdef JS_NUNBOX32 + /* + * With 64-bit jsvals on 32-bit systems, we can optimize a bit by + * scanning only the payloads. + */ + JS_ASSERT(begin <= end); + for (const jsuword *i = begin; i != end; i += sizeof(Value)/sizeof(jsuword)) + MarkWordConservatively(trc, *i); +#else + MarkRangeConservatively(trc, begin, end); +#endif +} + +void +MarkConservativeStackRoots(JSTracer *trc) +{ +#ifdef JS_THREADSAFE + for (JSThread::Map::Range r = trc->context->runtime->threads.all(); !r.empty(); r.popFront()) { + JSThread *thread = r.front().value; + ConservativeGCThreadData *ctd = &thread->data.conservativeGC; + if (ctd->hasStackToScan()) { + JS_ASSERT_IF(!thread->data.requestDepth, thread->suspendCount); + MarkThreadDataConservatively(trc, &thread->data); + } else { + JS_ASSERT(!thread->suspendCount); + JS_ASSERT(thread->data.requestDepth <= ctd->requestThreshold); + } + } +#else + MarkThreadDataConservatively(trc, &trc->context->runtime->threadData); +#endif +} + +JS_NEVER_INLINE void +ConservativeGCThreadData::recordStackTop() +{ + /* Update the native stack pointer if it points to a bigger stack. */ + jsuword dummy; + nativeStackTop = &dummy; + + /* + * To record and update the register snapshot for the conservative + * scanning with the latest values we use setjmp. + */ +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4611) +#endif + (void) setjmp(registerSnapshot.jmpbuf); +#if defined(_MSC_VER) +# pragma warning(pop) +#endif +} + +static inline void +RecordNativeStackTopForGC(JSContext *cx) +{ + ConservativeGCThreadData *ctd = &JS_THREAD_DATA(cx)->conservativeGC; + +#ifdef JS_THREADSAFE + /* Record the stack top here only if we are called from a request. */ + JS_ASSERT(cx->thread->data.requestDepth >= ctd->requestThreshold); + if (cx->thread->data.requestDepth == ctd->requestThreshold) + return; +#endif + ctd->recordStackTop(); +} + +} /* namespace js */ + +#ifdef DEBUG +static void +CheckLeakedRoots(JSRuntime *rt); +#endif + +void +js_FinishGC(JSRuntime *rt) +{ +#ifdef JS_ARENAMETER + JS_DumpArenaStats(stdout); +#endif +#ifdef JS_GCMETER + if (JS_WANT_GC_METER_PRINT) + js_DumpGCStats(rt, stdout); +#endif + + /* Delete all remaining Compartments. */ + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) { + JSCompartment *comp = *c; + comp->finishArenaLists(); + js_delete(comp); + } + rt->compartments.clear(); + rt->atomsCompartment = NULL; + + for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) + ReleaseGCChunk(rt, r.front()); + rt->gcChunkSet.clear(); + +#ifdef JS_THREADSAFE + rt->gcHelperThread.finish(rt); +#endif + +#ifdef DEBUG + if (!rt->gcRootsHash.empty()) + CheckLeakedRoots(rt); +#endif + rt->gcRootsHash.clear(); + rt->gcLocksHash.clear(); +} + +JSBool +js_AddRoot(JSContext *cx, Value *vp, const char *name) +{ + JSBool ok = js_AddRootRT(cx->runtime, Jsvalify(vp), name); + if (!ok) + JS_ReportOutOfMemory(cx); + return ok; +} + +JSBool +js_AddGCThingRoot(JSContext *cx, void **rp, const char *name) +{ + JSBool ok = js_AddGCThingRootRT(cx->runtime, rp, name); + if (!ok) + JS_ReportOutOfMemory(cx); + return ok; +} + +JS_FRIEND_API(JSBool) +js_AddRootRT(JSRuntime *rt, jsval *vp, const char *name) +{ + /* + * Due to the long-standing, but now removed, use of rt->gcLock across the + * bulk of js_GC, API users have come to depend on JS_AddRoot etc. locking + * properly with a racing GC, without calling JS_AddRoot from a request. + * We have to preserve API compatibility here, now that we avoid holding + * rt->gcLock across the mark phase (including the root hashtable mark). + */ + AutoLockGC lock(rt); + js_WaitForGC(rt); + + return !!rt->gcRootsHash.put((void *)vp, + RootInfo(name, JS_GC_ROOT_VALUE_PTR)); +} + +JS_FRIEND_API(JSBool) +js_AddGCThingRootRT(JSRuntime *rt, void **rp, const char *name) +{ + /* + * Due to the long-standing, but now removed, use of rt->gcLock across the + * bulk of js_GC, API users have come to depend on JS_AddRoot etc. locking + * properly with a racing GC, without calling JS_AddRoot from a request. + * We have to preserve API compatibility here, now that we avoid holding + * rt->gcLock across the mark phase (including the root hashtable mark). + */ + AutoLockGC lock(rt); + js_WaitForGC(rt); + + return !!rt->gcRootsHash.put((void *)rp, + RootInfo(name, JS_GC_ROOT_GCTHING_PTR)); +} + +JS_FRIEND_API(JSBool) +js_RemoveRoot(JSRuntime *rt, void *rp) +{ + /* + * Due to the JS_RemoveRootRT API, we may be called outside of a request. + * Same synchronization drill as above in js_AddRoot. + */ + AutoLockGC lock(rt); + js_WaitForGC(rt); + rt->gcRootsHash.remove(rp); + rt->gcPoke = JS_TRUE; + return JS_TRUE; +} + +typedef RootedValueMap::Range RootRange; +typedef RootedValueMap::Entry RootEntry; +typedef RootedValueMap::Enum RootEnum; + +#ifdef DEBUG + +static void +CheckLeakedRoots(JSRuntime *rt) +{ + uint32 leakedroots = 0; + + /* Warn (but don't assert) debug builds of any remaining roots. */ + for (RootRange r = rt->gcRootsHash.all(); !r.empty(); r.popFront()) { + RootEntry &entry = r.front(); + leakedroots++; + fprintf(stderr, + "JS engine warning: leaking GC root \'%s\' at %p\n", + entry.value.name ? entry.value.name : "", entry.key); + } + + if (leakedroots > 0) { + if (leakedroots == 1) { + fprintf(stderr, +"JS engine warning: 1 GC root remains after destroying the JSRuntime at %p.\n" +" This root may point to freed memory. Objects reachable\n" +" through it have not been finalized.\n", + (void *) rt); + } else { + fprintf(stderr, +"JS engine warning: %lu GC roots remain after destroying the JSRuntime at %p.\n" +" These roots may point to freed memory. Objects reachable\n" +" through them have not been finalized.\n", + (unsigned long) leakedroots, (void *) rt); + } + } +} + +void +js_DumpNamedRoots(JSRuntime *rt, + void (*dump)(const char *name, void *rp, JSGCRootType type, void *data), + void *data) +{ + for (RootRange r = rt->gcRootsHash.all(); !r.empty(); r.popFront()) { + RootEntry &entry = r.front(); + if (const char *name = entry.value.name) + dump(name, entry.key, entry.value.type, data); + } +} + +#endif /* DEBUG */ + +uint32 +js_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data) +{ + AutoLockGC lock(rt); + int ct = 0; + for (RootEnum e(rt->gcRootsHash); !e.empty(); e.popFront()) { + RootEntry &entry = e.front(); + + ct++; + intN mapflags = map(entry.key, entry.value.type, entry.value.name, data); + + if (mapflags & JS_MAP_GCROOT_REMOVE) + e.removeFront(); + if (mapflags & JS_MAP_GCROOT_STOP) + break; + } + + return ct; +} + +void +JSRuntime::setGCTriggerFactor(uint32 factor) +{ + JS_ASSERT(factor >= 100); + + gcTriggerFactor = factor; + setGCLastBytes(gcLastBytes); + + for (JSCompartment **c = compartments.begin(); c != compartments.end(); ++c) { + (*c)->setGCLastBytes(gcLastBytes); + } +} + +void +JSRuntime::setGCLastBytes(size_t lastBytes) +{ + gcLastBytes = lastBytes; + + /* FIXME bug 603916 - we should unify the triggers here. */ + float trigger1 = float(lastBytes) * float(gcTriggerFactor) / 100.0f; + float trigger2 = float(Max(lastBytes, GC_ARENA_ALLOCATION_TRIGGER)) * + GC_HEAP_GROWTH_FACTOR; + float maxtrigger = Max(trigger1, trigger2); + gcTriggerBytes = (float(gcMaxBytes) < maxtrigger) ? gcMaxBytes : size_t(maxtrigger); +} + +void +JSCompartment::setGCLastBytes(size_t lastBytes) +{ + gcLastBytes = lastBytes; + + /* FIXME bug 603916 - we should unify the triggers here. */ + float trigger1 = float(lastBytes) * float(rt->gcTriggerFactor) / 100.0f; + float trigger2 = float(Max(lastBytes, GC_ARENA_ALLOCATION_TRIGGER)) * + GC_HEAP_GROWTH_FACTOR; + float maxtrigger = Max(trigger1, trigger2); + gcTriggerBytes = (float(rt->gcMaxBytes) < maxtrigger) ? rt->gcMaxBytes : size_t(maxtrigger); +} + +void +FreeLists::purge() +{ + /* + * Return the free list back to the arena so the GC finalization will not + * run the finalizers over unitialized bytes from free things. + */ + for (FreeCell ***p = finalizables; p != JS_ARRAY_END(finalizables); ++p) + *p = NULL; +} + +class JSShortString; + +ArenaList * +GetFinalizableArenaList(JSCompartment *c, unsigned thingKind) { + JS_ASSERT(thingKind < FINALIZE_LIMIT); + return &c->arenas[thingKind]; +} + +#ifdef DEBUG +bool +CheckAllocation(JSContext *cx) +{ +#ifdef JS_THREADSAFE + JS_ASSERT(cx->thread); +#endif + JS_ASSERT(!cx->runtime->gcRunning); + return true; +} +#endif + +inline bool +NeedLastDitchGC(JSContext *cx) +{ + JSRuntime *rt = cx->runtime; +#ifdef JS_GC_ZEAL + if (rt->gcZeal >= 1) + return true; +#endif + return rt->gcIsNeeded; +} + +/* + * Return false only if the GC run but could not bring its memory usage under + * JSRuntime::gcMaxBytes. + */ +static bool +RunLastDitchGC(JSContext *cx) +{ + JSRuntime *rt = cx->runtime; + METER(rt->gcStats.lastditch++); +#ifdef JS_THREADSAFE + Conditionally + unlockAtomsCompartmenIf(cx->compartment == rt->atomsCompartment && + rt->atomsCompartmentIsLocked, cx); +#endif + /* The last ditch GC preserves all atoms. */ + AutoKeepAtoms keep(rt); + js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL); + + return rt->gcBytes < rt->gcMaxBytes; +} + +template +inline bool +RefillTypedFreeList(JSContext *cx, unsigned thingKind) +{ + JSCompartment *compartment = cx->compartment; + JS_ASSERT_IF(compartment->freeLists.finalizables[thingKind], + !*compartment->freeLists.finalizables[thingKind]); + + JS_ASSERT(!cx->runtime->gcRunning); + if (cx->runtime->gcRunning) + return false; + + bool canGC = !JS_ON_TRACE(cx) && !JS_THREAD_DATA(cx)->waiveGCQuota; + do { + if (canGC && JS_UNLIKELY(NeedLastDitchGC(cx))) { + if (!RunLastDitchGC(cx)) + break; + + /* + * The JSGC_END callback can legitimately allocate new GC + * things and populate the free list. If that happens, just + * return that list head. + */ + if (compartment->freeLists.finalizables[thingKind]) + return true; + canGC = false; + } + + ArenaList *arenaList = GetFinalizableArenaList(compartment, thingKind); + Arena *a = reinterpret_cast *>(arenaList->getNextWithFreeList()); + if (a) { + JS_ASSERT(a->header()->freeList); + JS_ASSERT(sizeof(T) == a->header()->thingSize); + compartment->freeLists.populate(a, thingKind); + return true; + } + + /* + * If the allocation fails rt->gcIsNeeded will be set and we will run + * the GC on the next loop iteration if the last ditch GC is allowed. + */ + a = AllocateArena(cx, thingKind); + if (a) { + compartment->freeLists.populate(a, thingKind); + arenaList->insert((Arena *) a); + a->getMarkingDelay()->init(); + return true; + } + } while (canGC); + + METER(cx->runtime->gcStats.fail++); + js_ReportOutOfMemory(cx); + return false; +} + +bool +RefillFinalizableFreeList(JSContext *cx, unsigned thingKind) +{ + switch (thingKind) { + case FINALIZE_OBJECT0: + return RefillTypedFreeList(cx, thingKind); + case FINALIZE_OBJECT2: + return RefillTypedFreeList(cx, thingKind); + case FINALIZE_OBJECT4: + return RefillTypedFreeList(cx, thingKind); + case FINALIZE_OBJECT8: + return RefillTypedFreeList(cx, thingKind); + case FINALIZE_OBJECT12: + return RefillTypedFreeList(cx, thingKind); + case FINALIZE_OBJECT16: + return RefillTypedFreeList(cx, thingKind); + case FINALIZE_STRING: + return RefillTypedFreeList(cx, thingKind); + case FINALIZE_EXTERNAL_STRING: + return RefillTypedFreeList(cx, thingKind); + case FINALIZE_SHORT_STRING: + return RefillTypedFreeList(cx, thingKind); + case FINALIZE_FUNCTION: + return RefillTypedFreeList(cx, thingKind); +#if JS_HAS_XML_SUPPORT + case FINALIZE_XML: + return RefillTypedFreeList(cx, thingKind); +#endif + default: + JS_NOT_REACHED("bad finalize kind"); + return false; + } +} + +intN +js_GetExternalStringGCType(JSString *str) { + return GetExternalStringGCType((JSExternalString *)str); +} + +uint32 +js_GetGCThingTraceKind(void *thing) { + return GetGCThingTraceKind(thing); +} + +JSBool +js_LockGCThingRT(JSRuntime *rt, void *thing) +{ + GCLocks *locks; + + if (!thing) + return true; + locks = &rt->gcLocksHash; + AutoLockGC lock(rt); + GCLocks::AddPtr p = locks->lookupForAdd(thing); + + if (!p) { + if (!locks->add(p, thing, 1)) + return false; + } else { + JS_ASSERT(p->value >= 1); + p->value++; + } + + METER(rt->gcStats.lock++); + return true; +} + +void +js_UnlockGCThingRT(JSRuntime *rt, void *thing) +{ + if (!thing) + return; + + AutoLockGC lock(rt); + GCLocks::Ptr p = rt->gcLocksHash.lookup(thing); + + if (p) { + rt->gcPoke = true; + if (--p->value == 0) + rt->gcLocksHash.remove(p); + + METER(rt->gcStats.unlock++); + } +} + +JS_PUBLIC_API(void) +JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind) +{ + switch (kind) { + case JSTRACE_OBJECT: { + MarkChildren(trc, (JSObject *)thing); + break; + } + + case JSTRACE_STRING: { + MarkChildren(trc, (JSString *)thing); + break; + } + +#if JS_HAS_XML_SUPPORT + case JSTRACE_XML: + MarkChildren(trc, (JSXML *)thing); + break; +#endif + } +} + +namespace js { + +/* + * When the native stack is low, the GC does not call JS_TraceChildren to mark + * the reachable "children" of the thing. Rather the thing is put aside and + * JS_TraceChildren is called later with more space on the C stack. + * + * To implement such delayed marking of the children with minimal overhead for + * the normal case of sufficient native stack, the code adds a field per + * arena. The field marlingdelay->link links all arenas with delayed things + * into a stack list with the pointer to stack top in + * GCMarker::unmarkedArenaStackTop. delayMarkingChildren adds + * arenas to the stack as necessary while markDelayedChildren pops the arenas + * from the stack until it empties. + */ + +GCMarker::GCMarker(JSContext *cx) + : color(0), stackLimit(0), unmarkedArenaStackTop(NULL) +{ + JS_TRACER_INIT(this, cx, NULL); +#ifdef DEBUG + markLaterCount = 0; +#endif +#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS + conservativeDumpFileName = getenv("JS_DUMP_CONSERVATIVE_GC_ROOTS"); + memset(&conservativeStats, 0, sizeof(conservativeStats)); +#endif +} + +GCMarker::~GCMarker() +{ +#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS + dumpConservativeRoots(); +#endif +#ifdef JS_GCMETER + /* Update total stats. */ + context->runtime->gcStats.conservative.add(conservativeStats); +#endif +} + +void +GCMarker::delayMarkingChildren(void *thing) +{ + Cell *cell = reinterpret_cast(thing); + Arena *a = cell->arena(); + JS_ASSERT(cell->isMarked()); + METER(cell->compartment()->rt->gcStats.unmarked++); + MarkingDelay *markingDelay = a->getMarkingDelay(); + + if (markingDelay->link) { + if (markingDelay->start > (jsuword)cell) + markingDelay->start = (jsuword)cell; + /* Arena already scheduled to be marked again */ + return; + } + markingDelay->start = (jsuword)cell; + Arena *tos = unmarkedArenaStackTop; + markingDelay->link = tos ? tos : a; + unmarkedArenaStackTop = a; +#ifdef DEBUG + JSCompartment *comp = cell->compartment(); + markLaterCount += Arena::ThingsPerArena; + METER_UPDATE_MAX(comp->rt->gcStats.maxunmarked, markLaterCount); +#endif +} + +template +void +Arena::markDelayedChildren(JSTracer *trc) +{ + T* thing = (T *)getMarkingDelay()->start; + T *thingsEnd = &t.things[ThingsPerArena-1].t; + JS_ASSERT(thing == getAlignedThing(thing)); + while (thing <= thingsEnd) { + if (thing->asCell()->isMarked()) + MarkChildren(trc, thing); + + thing++; + } +} + +void +GCMarker::markDelayedChildren() +{ + while (Arena *a = unmarkedArenaStackTop) { + /* + * markingDelay->link == current arena indicates last arena on stack. + * If marking gets delayed at the same arena again, the arena is pushed + * again in delayMarkingChildren. markingDelay->link has to be cleared, + * otherwise the arena is not pushed again. + */ + MarkingDelay *markingDelay = a->getMarkingDelay(); + unmarkedArenaStackTop = (markingDelay->link != a) + ? markingDelay->link + : NULL; + markingDelay->link = NULL; +#ifdef DEBUG + markLaterCount -= Arena::ThingsPerArena; +#endif + + switch (a->header()->thingKind) { + case FINALIZE_OBJECT0: + reinterpret_cast *>(a)->markDelayedChildren(this); + break; + case FINALIZE_OBJECT2: + reinterpret_cast *>(a)->markDelayedChildren(this); + break; + case FINALIZE_OBJECT4: + reinterpret_cast *>(a)->markDelayedChildren(this); + break; + case FINALIZE_OBJECT8: + reinterpret_cast *>(a)->markDelayedChildren(this); + break; + case FINALIZE_OBJECT12: + reinterpret_cast *>(a)->markDelayedChildren(this); + break; + case FINALIZE_OBJECT16: + reinterpret_cast *>(a)->markDelayedChildren(this); + break; + case FINALIZE_STRING: + reinterpret_cast *>(a)->markDelayedChildren(this); + break; + case FINALIZE_EXTERNAL_STRING: + reinterpret_cast *>(a)->markDelayedChildren(this); + break; + case FINALIZE_SHORT_STRING: + JS_ASSERT(false); + break; + case FINALIZE_FUNCTION: + reinterpret_cast *>(a)->markDelayedChildren(this); + break; +#if JS_HAS_XML_SUPPORT + case FINALIZE_XML: + reinterpret_cast *>(a)->markDelayedChildren(this); + break; +#endif + default: + JS_NOT_REACHED("wrong thingkind"); + } + } + JS_ASSERT(markLaterCount == 0); + JS_ASSERT(!unmarkedArenaStackTop); +} + +} /* namespace js */ + +static void +gc_root_traversal(JSTracer *trc, const RootEntry &entry) +{ +#ifdef DEBUG + void *ptr; + if (entry.value.type == JS_GC_ROOT_GCTHING_PTR) { + ptr = *reinterpret_cast(entry.key); + } else { + Value *vp = reinterpret_cast(entry.key); + ptr = vp->isGCThing() ? vp->toGCThing() : NULL; + } + + if (ptr) { + if (!JSString::isStatic(ptr)) { + bool root_points_to_gcArenaList = false; + JSCompartment **c = trc->context->runtime->compartments.begin(); + for (; c != trc->context->runtime->compartments.end(); ++c) { + JSCompartment *comp = *c; + if (checkArenaListsForThing(comp, ptr)) { + root_points_to_gcArenaList = true; + break; + } + } + if (!root_points_to_gcArenaList && entry.value.name) { + fprintf(stderr, +"JS API usage error: the address passed to JS_AddNamedRoot currently holds an\n" +"invalid gcthing. This is usually caused by a missing call to JS_RemoveRoot.\n" +"The root's name is \"%s\".\n", + entry.value.name); + } + JS_ASSERT(root_points_to_gcArenaList); + } + } +#endif + JS_SET_TRACING_NAME(trc, entry.value.name ? entry.value.name : "root"); + if (entry.value.type == JS_GC_ROOT_GCTHING_PTR) + MarkGCThing(trc, *reinterpret_cast(entry.key)); + else + MarkValueRaw(trc, *reinterpret_cast(entry.key)); +} + +static void +gc_lock_traversal(const GCLocks::Entry &entry, JSTracer *trc) +{ + JS_ASSERT(entry.value >= 1); + MarkGCThing(trc, entry.key, "locked object"); +} + +void +js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) +{ + MarkObject(trc, fp->scopeChain(), "scope chain"); + if (fp->isDummyFrame()) + return; + + if (fp->hasCallObj()) + MarkObject(trc, fp->callObj(), "call"); + if (fp->hasArgsObj()) + MarkObject(trc, fp->argsObj(), "arguments"); + if (fp->isScriptFrame()) { + js_TraceScript(trc, fp->script()); + fp->script()->compartment->active = true; + } + + MarkValue(trc, fp->returnValue(), "rval"); +} + +void +AutoIdArray::trace(JSTracer *trc) +{ + JS_ASSERT(tag == IDARRAY); + gc::MarkIdRange(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray"); +} + +void +AutoEnumStateRooter::trace(JSTracer *trc) +{ + js::gc::MarkObject(trc, *obj, "js::AutoEnumStateRooter.obj"); +} + +inline void +AutoGCRooter::trace(JSTracer *trc) +{ + switch (tag) { + case JSVAL: + MarkValue(trc, static_cast(this)->val, "js::AutoValueRooter.val"); + return; + + case SHAPE: + static_cast(this)->shape->trace(trc); + return; + + case PARSER: + static_cast(this)->trace(trc); + return; + + case SCRIPT: + if (JSScript *script = static_cast(this)->script) + js_TraceScript(trc, script); + return; + + case ENUMERATOR: + static_cast(this)->trace(trc); + return; + + case IDARRAY: { + JSIdArray *ida = static_cast(this)->idArray; + MarkIdRange(trc, ida->length, ida->vector, "js::AutoIdArray.idArray"); + return; + } + + case DESCRIPTORS: { + PropDescArray &descriptors = + static_cast(this)->descriptors; + for (size_t i = 0, len = descriptors.length(); i < len; i++) { + PropDesc &desc = descriptors[i]; + MarkValue(trc, desc.pd, "PropDesc::pd"); + MarkValue(trc, desc.value, "PropDesc::value"); + MarkValue(trc, desc.get, "PropDesc::get"); + MarkValue(trc, desc.set, "PropDesc::set"); + MarkId(trc, desc.id, "PropDesc::id"); + } + return; + } + + case DESCRIPTOR : { + PropertyDescriptor &desc = *static_cast(this); + if (desc.obj) + MarkObject(trc, *desc.obj, "Descriptor::obj"); + MarkValue(trc, desc.value, "Descriptor::value"); + if ((desc.attrs & JSPROP_GETTER) && desc.getter) + MarkObject(trc, *CastAsObject(desc.getter), "Descriptor::get"); + if (desc.attrs & JSPROP_SETTER && desc.setter) + MarkObject(trc, *CastAsObject(desc.setter), "Descriptor::set"); + return; + } + + case NAMESPACES: { + JSXMLArray &array = static_cast(this)->array; + MarkObjectRange(trc, array.length, reinterpret_cast(array.vector), + "JSXMLArray.vector"); + array.cursors->trace(trc); + return; + } + + case XML: + js_TraceXML(trc, static_cast(this)->xml); + return; + + case OBJECT: + if (JSObject *obj = static_cast(this)->obj) + MarkObject(trc, *obj, "js::AutoObjectRooter.obj"); + return; + + case ID: + MarkId(trc, static_cast(this)->id_, "js::AutoIdRooter.val"); + return; + + case VALVECTOR: { + Vector &vector = static_cast(this)->vector; + MarkValueRange(trc, vector.length(), vector.begin(), "js::AutoValueVector.vector"); + return; + } + + case STRING: + if (JSString *str = static_cast(this)->str) + MarkString(trc, str, "js::AutoStringRooter.str"); + return; + + case IDVECTOR: { + Vector &vector = static_cast(this)->vector; + MarkIdRange(trc, vector.length(), vector.begin(), "js::AutoIdVector.vector"); + return; + } + + case SHAPEVECTOR: { + Vector &vector = static_cast(this)->vector; + MarkShapeRange(trc, vector.length(), vector.begin(), "js::AutoShapeVector.vector"); + return; + } + + case BINDINGS: { + static_cast(this)->bindings.trace(trc); + return; + } + } + + JS_ASSERT(tag >= 0); + MarkValueRange(trc, tag, static_cast(this)->array, "js::AutoArrayRooter.array"); +} + +namespace js { + +JS_FRIEND_API(void) +MarkContext(JSTracer *trc, JSContext *acx) +{ + /* Stack frames and slots are traced by StackSpace::mark. */ + + /* Mark other roots-by-definition in acx. */ + if (acx->globalObject && !acx->hasRunOption(JSOPTION_UNROOTED_GLOBAL)) + MarkObject(trc, *acx->globalObject, "global object"); + if (acx->isExceptionPending()) + MarkValue(trc, acx->getPendingException(), "exception"); + + for (js::AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down) + gcr->trace(trc); + + if (acx->sharpObjectMap.depth > 0) + js_TraceSharpMap(trc, &acx->sharpObjectMap); + + MarkValue(trc, acx->iterValue, "iterValue"); + + if (acx->compartment) + acx->compartment->mark(trc); +} + +JS_REQUIRES_STACK void +MarkRuntime(JSTracer *trc) +{ + JSRuntime *rt = trc->context->runtime; + + if (rt->state != JSRTS_LANDING) + MarkConservativeStackRoots(trc); + + /* + * Verify that we do not have at this point unmarked GC things stored in + * autorooters. To maximize test coverage we abort even in non-debug + * builds for now, see bug 574313. + */ + JSContext *iter; +#if 0 + iter = NULL; + while (JSContext *acx = js_ContextIterator(rt, JS_TRUE, &iter)) { + for (AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down) { +#ifdef JS_THREADSAFE + JS_ASSERT_IF(!acx->thread->data.requestDepth, acx->thread->suspendCount); +#endif + JS_ASSERT(JS_THREAD_DATA(acx)->conservativeGC.hasStackToScan()); + void *thing; + switch (gcr->tag) { + default: + continue; + case AutoGCRooter::JSVAL: { + const Value &v = static_cast(gcr)->val; + if (!v.isMarkable()) + continue; + thing = v.toGCThing(); + break; + } + case AutoGCRooter::XML: + thing = static_cast(gcr)->xml; + break; + case AutoGCRooter::OBJECT: + thing = static_cast(gcr)->obj; + if (!thing) + continue; + break; + case AutoGCRooter::ID: { + jsid id = static_cast(gcr)->id(); + if (!JSID_IS_GCTHING(id)) + continue; + thing = JSID_TO_GCTHING(id); + break; + } + } + + if (JSString::isStatic(thing)) + continue; + + if (!reinterpret_cast(thing)->isMarked()) { + ConservativeGCTest test = MarkIfGCThingWord(trc, reinterpret_cast(thing)); + fprintf(stderr, + "Conservative GC scanner has missed the root 0x%p with tag %ld" + " on the stack due to %d. The root location 0x%p, distance from" + " the stack base %ld, conservative gc span %ld." + " Consevtaive GC status for the thread %d." + " Aborting.\n", + thing, (long) gcr->tag, int(test), (void *) gcr, + (long) ((jsword) JS_THREAD_DATA(acx)->nativeStackBase - (jsword) gcr), + (long) ((jsword) JS_THREAD_DATA(acx)->nativeStackBase - + (jsword) JS_THREAD_DATA(acx)->conservativeGC.nativeStackTop), + int(JS_THREAD_DATA(acx)->conservativeGC.hasStackToScan())); + JS_ASSERT(false); + abort(); + } + } + } +#endif + + for (RootRange r = rt->gcRootsHash.all(); !r.empty(); r.popFront()) + gc_root_traversal(trc, r.front()); + + for (GCLocks::Range r = rt->gcLocksHash.all(); !r.empty(); r.popFront()) + gc_lock_traversal(r.front(), trc); + + js_TraceAtomState(trc); + js_MarkTraps(trc); + + iter = NULL; + while (JSContext *acx = js_ContextIterator(rt, JS_TRUE, &iter)) + MarkContext(trc, acx); + + rt->atomsCompartment->mark(trc); + +#ifdef JS_TRACER + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) + (*c)->traceMonitor.mark(trc); +#endif + + for (ThreadDataIter i(rt); !i.empty(); i.popFront()) + i.threadData()->mark(trc); + + /* + * We mark extra roots at the last thing so it can use use additional + * colors to implement cycle collection. + */ + if (rt->gcExtraRootsTraceOp) + rt->gcExtraRootsTraceOp(trc, rt->gcExtraRootsData); + +#ifdef DEBUG + if (rt->functionMeterFilename) { + for (int k = 0; k < 2; k++) { + typedef JSRuntime::FunctionCountMap HM; + HM &h = (k == 0) ? rt->methodReadBarrierCountMap : rt->unjoinedFunctionCountMap; + for (HM::Range r = h.all(); !r.empty(); r.popFront()) { + JSFunction *fun = r.front().key; + JS_CALL_OBJECT_TRACER(trc, fun, "FunctionCountMap key"); + } + } + } +#endif +} + +void +TriggerGC(JSRuntime *rt) +{ + JS_ASSERT(!rt->gcRunning); + if (rt->gcIsNeeded) + return; + + /* + * Trigger the GC when it is safe to call an operation callback on any + * thread. + */ + rt->gcIsNeeded = true; + rt->gcTriggerCompartment = NULL; + TriggerAllOperationCallbacks(rt); +} + +void +TriggerCompartmentGC(JSCompartment *comp) +{ + JSRuntime *rt = comp->rt; + JS_ASSERT(!rt->gcRunning); + +#ifdef JS_GC_ZEAL + if (rt->gcZeal >= 1) { + TriggerGC(rt); + return; + } +#endif + + if (rt->gcMode != JSGC_MODE_COMPARTMENT || comp == rt->atomsCompartment) { + /* We can't do a compartmental GC of the default compartment. */ + TriggerGC(rt); + return; + } + + if (rt->gcIsNeeded) { + /* If we need to GC more than one compartment, run a full GC. */ + if (rt->gcTriggerCompartment != comp) + rt->gcTriggerCompartment = NULL; + return; + } + + if (rt->gcBytes > 8192 && rt->gcBytes >= 3 * (rt->gcTriggerBytes / 2)) { + /* If we're using significantly more than our quota, do a full GC. */ + TriggerGC(rt); + return; + } + + /* + * Trigger the GC when it is safe to call an operation callback on any + * thread. + */ + rt->gcIsNeeded = true; + rt->gcTriggerCompartment = comp; + TriggerAllOperationCallbacks(comp->rt); +} + +void +MaybeGC(JSContext *cx) +{ + JSRuntime *rt = cx->runtime; + +#ifdef JS_GC_ZEAL + if (rt->gcZeal > 0) { + js_GC(cx, NULL, GC_NORMAL); + return; + } +#endif + + JSCompartment *comp = cx->compartment; + if (rt->gcIsNeeded) { + js_GC(cx, (comp == rt->gcTriggerCompartment) ? comp : NULL, GC_NORMAL); + return; + } + + if (comp->gcBytes > 8192 && comp->gcBytes >= 3 * (comp->gcTriggerBytes / 4)) + js_GC(cx, (rt->gcMode == JSGC_MODE_COMPARTMENT) ? comp : NULL, GC_NORMAL); +} + +} /* namespace js */ + +void +js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp) +{ + JSScript **listp, *script; + + for (size_t i = 0; i != JS_ARRAY_LENGTH(comp->scriptsToGC); ++i) { + listp = &comp->scriptsToGC[i]; + while ((script = *listp) != NULL) { + *listp = script->u.nextToGC; + script->u.nextToGC = NULL; + js_DestroyCachedScript(cx, script); + } + } +} + +/* + * This function is called from js_FinishAtomState to force the finalization + * of the permanently interned strings when cx is not available. + */ +void +js_FinalizeStringRT(JSRuntime *rt, JSString *str) +{ + JS_RUNTIME_UNMETER(rt, liveStrings); + JS_ASSERT(!JSString::isStatic(str)); + JS_ASSERT(!str->isRope()); + + if (str->isDependent()) { + /* A dependent string can not be external and must be valid. */ + JS_ASSERT(str->asCell()->arena()->header()->thingKind == FINALIZE_STRING); + JS_ASSERT(str->dependentBase()); + JS_RUNTIME_UNMETER(rt, liveDependentStrings); + } else { + unsigned thingKind = str->asCell()->arena()->header()->thingKind; + JS_ASSERT(IsFinalizableStringKind(thingKind)); + + /* A stillborn string has null chars, so is not valid. */ + jschar *chars = const_cast(str->flatChars()); + if (!chars) + return; + if (thingKind == FINALIZE_STRING) { + rt->stringMemoryUsed -= str->length() * 2; + rt->free(chars); + } else if (thingKind == FINALIZE_EXTERNAL_STRING) { + ((JSExternalString *)str)->finalize(); + } + } +} + +template +static void +FinalizeArenaList(JSCompartment *comp, JSContext *cx, unsigned thingKind) +{ + JS_STATIC_ASSERT(!(sizeof(T) & Cell::CellMask)); + ArenaList *arenaList = GetFinalizableArenaList(comp, thingKind); + Arena **ap = &arenaList->head; + Arena *a = (Arena *) *ap; + if (!a) + return; + JS_ASSERT(sizeof(T) == arenaList->head->header()->thingSize); + +#ifdef JS_GCMETER + uint32 nlivearenas = 0, nkilledarenas = 0, nthings = 0; +#endif + for (;;) { + ArenaHeader *header = a->header(); + JS_ASSERT_IF(header->hasFreeThings, header->freeList); + JS_ASSERT(header->thingKind == thingKind); + JS_ASSERT(!a->getMarkingDelay()->link); + JS_ASSERT(a->getMarkingDelay()->unmarkedChildren == 0); + JS_ASSERT(a->header()->isUsed); + + FreeCell *nextFree = header->freeList; + FreeCell *freeList = NULL; + FreeCell **tailp = &freeList; + bool allClear = true; + + T *thingsEnd = &a->t.things[a->ThingsPerArena-1].t; + T *thing = &a->t.things[0].t; + thingsEnd++; + + if (!nextFree) { + nextFree = thingsEnd->asFreeCell(); + } else { + JS_ASSERT(thing->asCell() <= nextFree); + JS_ASSERT(nextFree < thingsEnd->asCell()); + } + + for (;; thing++) { + if (thing->asCell() == nextFree) { + if (thing == thingsEnd) + break; + nextFree = nextFree->link; + if (!nextFree) { + nextFree = thingsEnd->asFreeCell(); + } else { + JS_ASSERT(thing->asCell() < nextFree); + JS_ASSERT(nextFree < thingsEnd->asFreeCell()); + } + } else if (thing->asCell()->isMarked()) { + allClear = false; + METER(nthings++); + continue; + } else { + thing->finalize(cx); +#ifdef DEBUG + memset(thing, JS_FREE_PATTERN, sizeof(T)); +#endif + } + FreeCell *t = thing->asFreeCell(); + *tailp = t; + tailp = &t->link; + } + +#ifdef DEBUG + /* Check that the free list is consistent. */ + unsigned nfree = 0; + if (freeList) { + JS_ASSERT(tailp != &freeList); + FreeCell *t = freeList; + for (;;) { + ++nfree; + if (&t->link == tailp) + break; + JS_ASSERT(t < t->link); + t = t->link; + } + } +#endif + if (allClear) { + /* + * Forget just assembled free list head for the arena and + * add the arena itself to the destroy list. + */ + JS_ASSERT(nfree == a->ThingsPerArena); + JS_ASSERT((T *)tailp == &a->t.things[a->ThingsPerArena-1].t); + *tailp = NULL; + header->freeList = freeList; +#ifdef DEBUG + header->hasFreeThings = true; +#endif + *ap = (header->next); + JS_ASSERT((T *)header->freeList == &a->t.things[0].t); + a->chunk()->releaseArena(a); + METER(nkilledarenas++); + } else { + JS_ASSERT(nfree < a->ThingsPerArena); + *tailp = NULL; + header->freeList = freeList; +#ifdef DEBUG + header->hasFreeThings = (nfree == 0) ? false : true; +#endif + ap = &header->next; + METER(nlivearenas++); + } + if (!(a = (Arena *) *ap)) + break; + } + arenaList->cursor = arenaList->head; + METER(UpdateCompartmentStats(comp, thingKind, nlivearenas, nkilledarenas, nthings)); +} + +void +JSCompartment::finalizeObjectArenaLists(JSContext *cx) +{ + FinalizeArenaList(this, cx, FINALIZE_OBJECT0); + FinalizeArenaList(this, cx, FINALIZE_OBJECT2); + FinalizeArenaList(this, cx, FINALIZE_OBJECT4); + FinalizeArenaList(this, cx, FINALIZE_OBJECT8); + FinalizeArenaList(this, cx, FINALIZE_OBJECT12); + FinalizeArenaList(this, cx, FINALIZE_OBJECT16); + FinalizeArenaList(this, cx, FINALIZE_FUNCTION); +#if JS_HAS_XML_SUPPORT + FinalizeArenaList(this, cx, FINALIZE_XML); +#endif +} + +void +JSCompartment::finalizeStringArenaLists(JSContext *cx) +{ + FinalizeArenaList(this, cx, FINALIZE_SHORT_STRING); + FinalizeArenaList(this, cx, FINALIZE_STRING); + FinalizeArenaList(this, cx, FINALIZE_EXTERNAL_STRING); +} + +#ifdef JS_THREADSAFE + +namespace js { + +bool +GCHelperThread::init(JSRuntime *rt) +{ + if (!(wakeup = PR_NewCondVar(rt->gcLock))) + return false; + if (!(sweepingDone = PR_NewCondVar(rt->gcLock))) + return false; + + thread = PR_CreateThread(PR_USER_THREAD, threadMain, rt, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + return !!thread; + +} + +void +GCHelperThread::finish(JSRuntime *rt) +{ + PRThread *join = NULL; + { + AutoLockGC lock(rt); + if (thread && !shutdown) { + shutdown = true; + PR_NotifyCondVar(wakeup); + join = thread; + } + } + if (join) { + /* PR_DestroyThread is not necessary. */ + PR_JoinThread(join); + } + if (wakeup) + PR_DestroyCondVar(wakeup); + if (sweepingDone) + PR_DestroyCondVar(sweepingDone); +} + +/* static */ +void +GCHelperThread::threadMain(void *arg) +{ + JSRuntime *rt = static_cast(arg); + rt->gcHelperThread.threadLoop(rt); +} + +void +GCHelperThread::threadLoop(JSRuntime *rt) +{ + AutoLockGC lock(rt); + while (!shutdown) { + /* + * Sweeping can be true here on the first iteration if a GC and the + * corresponding startBackgroundSweep call happen before this thread + * has a chance to run. + */ + if (!sweeping) + PR_WaitCondVar(wakeup, PR_INTERVAL_NO_TIMEOUT); + if (sweeping) { + AutoUnlockGC unlock(rt); + doSweep(); + } + sweeping = false; + PR_NotifyAllCondVar(sweepingDone); + } +} + +void +GCHelperThread::startBackgroundSweep(JSRuntime *rt) +{ + /* The caller takes the GC lock. */ + JS_ASSERT(!sweeping); + sweeping = true; + PR_NotifyCondVar(wakeup); +} + +void +GCHelperThread::waitBackgroundSweepEnd(JSRuntime *rt) +{ + AutoLockGC lock(rt); + while (sweeping) + PR_WaitCondVar(sweepingDone, PR_INTERVAL_NO_TIMEOUT); +} + +JS_FRIEND_API(void) +GCHelperThread::replenishAndFreeLater(void *ptr) +{ + JS_ASSERT(freeCursor == freeCursorEnd); + do { + if (freeCursor && !freeVector.append(freeCursorEnd - FREE_ARRAY_LENGTH)) + break; + freeCursor = (void **) js_malloc(FREE_ARRAY_SIZE); + if (!freeCursor) { + freeCursorEnd = NULL; + break; + } + freeCursorEnd = freeCursor + FREE_ARRAY_LENGTH; + *freeCursor++ = ptr; + return; + } while (false); + js_free(ptr); +} + +void +GCHelperThread::doSweep() +{ + if (freeCursor) { + void **array = freeCursorEnd - FREE_ARRAY_LENGTH; + freeElementsAndArray(array, freeCursor); + freeCursor = freeCursorEnd = NULL; + } else { + JS_ASSERT(!freeCursorEnd); + } + for (void ***iter = freeVector.begin(); iter != freeVector.end(); ++iter) { + void **array = *iter; + freeElementsAndArray(array, array + FREE_ARRAY_LENGTH); + } + freeVector.resize(0); +} + +} + +#endif /* JS_THREADSAFE */ + +static void +SweepCrossCompartmentWrappers(JSContext *cx) +{ + JSRuntime *rt = cx->runtime; + /* + * Figure out how much JIT code should be released from inactive compartments. + * If multiple eighth-lives have passed, compound the release interval linearly; + * if enough time has passed, all inactive JIT code will be released. + */ + uint32 releaseInterval = 0; + int64 now = PRMJ_Now(); + if (now >= rt->gcJitReleaseTime) { + releaseInterval = 8; + while (now >= rt->gcJitReleaseTime) { + if (--releaseInterval == 1) + rt->gcJitReleaseTime = now; + rt->gcJitReleaseTime += JIT_SCRIPT_EIGHTH_LIFETIME; + } + } + + /* Remove dead wrappers from the compartment map. */ + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) + (*c)->sweep(cx, releaseInterval); +} + +static void +SweepCompartments(JSContext *cx, JSGCInvocationKind gckind) +{ + JSRuntime *rt = cx->runtime; + JSCompartmentCallback callback = rt->compartmentCallback; + + /* Skip the atomsCompartment. */ + JSCompartment **read = rt->compartments.begin() + 1; + JSCompartment **end = rt->compartments.end(); + JSCompartment **write = read; + JS_ASSERT(rt->compartments.length() >= 1); + JS_ASSERT(*rt->compartments.begin() == rt->atomsCompartment); + + while (read < end) { + JSCompartment *compartment = *read++; + + /* + * Unmarked compartments containing marked objects don't get deleted, + * except when LAST_CONTEXT GC is performed. + */ + if ((!compartment->isMarked() && compartment->arenaListsAreEmpty()) || + gckind == GC_LAST_CONTEXT) + { + JS_ASSERT(compartment->freeLists.isEmpty()); + if (callback) + (void) callback(cx, compartment, JSCOMPARTMENT_DESTROY); + if (compartment->principals) + JSPRINCIPALS_DROP(cx, compartment->principals); + js_delete(compartment); + continue; + } + *write++ = compartment; + } + rt->compartments.resize(write - rt->compartments.begin()); +} + +/* + * Common cache invalidation and so forth that must be done before GC. Even if + * GCUntilDone calls GC several times, this work needs to be done only once. + */ +static void +PreGCCleanup(JSContext *cx, JSGCInvocationKind gckind) +{ + JSRuntime *rt = cx->runtime; + + /* Clear gcIsNeeded now, when we are about to start a normal GC cycle. */ + rt->gcIsNeeded = false; + rt->gcTriggerCompartment = NULL; + + /* Reset malloc counter. */ + rt->resetGCMallocBytes(); + +#ifdef JS_DUMP_SCOPE_METERS + { + extern void js_DumpScopeMeters(JSRuntime *rt); + js_DumpScopeMeters(rt); + } +#endif + + /* + * Reset the property cache's type id generator so we can compress ids. + * Same for the protoHazardShape proxy-shape standing in for all object + * prototypes having readonly or setter properties. + */ + if (rt->shapeGen & SHAPE_OVERFLOW_BIT +#ifdef JS_GC_ZEAL + || rt->gcZeal >= 1 +#endif + ) { + rt->gcRegenShapes = true; + rt->shapeGen = 0; + rt->protoHazardShape = 0; + } + + if (rt->gcCurrentCompartment) { + rt->gcCurrentCompartment->purge(cx); + } else { + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) + (*c)->purge(cx); + } + + js_PurgeThreads(cx); + { + JSContext *iter = NULL; + while (JSContext *acx = js_ContextIterator(rt, JS_TRUE, &iter)) + acx->purge(); + } +} + +static void +MarkAndSweepCompartment(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIMER_PARAM) +{ + JSRuntime *rt = cx->runtime; + rt->gcNumber++; + JS_ASSERT(!rt->gcRegenShapes); + JS_ASSERT(gckind != GC_LAST_CONTEXT); + JS_ASSERT(comp != rt->atomsCompartment); + JS_ASSERT(!comp->isMarked()); + JS_ASSERT(comp->rt->gcMode == JSGC_MODE_COMPARTMENT); + + /* + * Mark phase. + */ + GCMarker gcmarker(cx); + JS_ASSERT(IS_GC_MARKING_TRACER(&gcmarker)); + JS_ASSERT(gcmarker.getMarkColor() == BLACK); + rt->gcMarkingTracer = &gcmarker; + gcmarker.stackLimit = cx->stackLimit; + + for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) + r.front()->clearMarkBitmap(); + + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) + (*c)->markCrossCompartment(&gcmarker); + + comp->mark(&gcmarker); + + MarkRuntime(&gcmarker); + + /* + * Mark children of things that caused too deep recursion during the above + * tracing. + */ + gcmarker.markDelayedChildren(); + + rt->gcMarkingTracer = NULL; + + if (rt->gcCallback) + (void) rt->gcCallback(cx, JSGC_MARK_END); + +#ifdef JS_THREADSAFE + /* + * cx->gcBackgroundFree is set if we need several mark-and-sweep loops to + * finish the GC. + */ + if(!cx->gcBackgroundFree) { + /* Wait until the sweeping from the previois GC finishes. */ + rt->gcHelperThread.waitBackgroundSweepEnd(rt); + cx->gcBackgroundFree = &rt->gcHelperThread; + } +#endif +#ifdef DEBUG + /* Make sure that we didn't mark an object in another compartment */ + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) + JS_ASSERT_IF(*c != comp, checkArenaListAllUnmarked(*c)); +#endif + + /* + * Sweep phase. + * + * Finalize as we sweep, outside of rt->gcLock but with rt->gcRunning set + * so that any attempt to allocate a GC-thing from a finalizer will fail, + * rather than nest badly and leave the unmarked newborn to be swept. + * + * We first sweep atom state so we can use js_IsAboutToBeFinalized on + * JSString held in a hashtable to check if the hashtable entry can be + * freed. Note that even after the entry is freed, JSObject finalizers can + * continue to access the corresponding JSString* assuming that they are + * unique. This works since the atomization API must not be called during + * the GC. + */ + TIMESTAMP(startSweep); + js_SweepAtomState(cx); + + /* Finalize watch points associated with unreachable objects. */ + js_SweepWatchPoints(cx); + +#ifdef DEBUG + /* Save the pre-sweep count of scope-mapped properties. */ + rt->liveObjectPropsPreSweep = rt->liveObjectProps; +#endif + + /* + * We finalize iterators before other objects so the iterator can use the + * object which properties it enumerates over to finalize the enumeration + * state. We finalize objects before other GC things to ensure that + * object's finalizer can access them even if they will be freed. + */ + comp->sweep(cx, 0); + + comp->finalizeObjectArenaLists(cx); + TIMESTAMP(sweepObjectEnd); + + comp->finalizeStringArenaLists(cx); + TIMESTAMP(sweepStringEnd); + + /* + * Unmark all shapes. Even a per-compartment GC can mark shapes in other + * compartments, and we need to clear these bits. See bug 635873. This will + * be fixed in bug 569422. + */ + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) + (*c)->propertyTree.unmarkShapes(cx); + + PropertyTree::dumpShapes(cx); + TIMESTAMP(sweepShapeEnd); + + /* + * Destroy arenas after we finished the sweeping so finalizers can safely + * use js_IsAboutToBeFinalized(). + */ + ExpireGCChunks(rt); + TIMESTAMP(sweepDestroyEnd); + + comp->clearMark(); + + if (rt->gcCallback) + (void) rt->gcCallback(cx, JSGC_FINALIZE_END); +} + +/* + * Perform mark-and-sweep GC. + * + * In a JS_THREADSAFE build, the calling thread must be rt->gcThread and each + * other thread must be either outside all requests or blocked waiting for GC + * to finish. Note that the caller does not hold rt->gcLock. + */ +static void +MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM) +{ + JSRuntime *rt = cx->runtime; + rt->gcNumber++; + + /* + * Mark phase. + */ + GCMarker gcmarker(cx); + JS_ASSERT(IS_GC_MARKING_TRACER(&gcmarker)); + JS_ASSERT(gcmarker.getMarkColor() == BLACK); + rt->gcMarkingTracer = &gcmarker; + gcmarker.stackLimit = cx->stackLimit; + + for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) + r.front()->clearMarkBitmap(); + + MarkRuntime(&gcmarker); + js_MarkScriptFilenames(rt); + + /* + * Mark children of things that caused too deep recursion during the above + * tracing. + */ + gcmarker.markDelayedChildren(); + + rt->gcMarkingTracer = NULL; + + if (rt->gcCallback) + (void) rt->gcCallback(cx, JSGC_MARK_END); + +#ifdef JS_THREADSAFE + /* + * cx->gcBackgroundFree is set if we need several mark-and-sweep loops to + * finish the GC. + */ + if(!cx->gcBackgroundFree) { + /* Wait until the sweeping from the previois GC finishes. */ + rt->gcHelperThread.waitBackgroundSweepEnd(rt); + cx->gcBackgroundFree = &rt->gcHelperThread; + } +#endif + + /* + * Sweep phase. + * + * Finalize as we sweep, outside of rt->gcLock but with rt->gcRunning set + * so that any attempt to allocate a GC-thing from a finalizer will fail, + * rather than nest badly and leave the unmarked newborn to be swept. + * + * We first sweep atom state so we can use js_IsAboutToBeFinalized on + * JSString held in a hashtable to check if the hashtable entry can be + * freed. Note that even after the entry is freed, JSObject finalizers can + * continue to access the corresponding JSString* assuming that they are + * unique. This works since the atomization API must not be called during + * the GC. + */ + TIMESTAMP(startSweep); + js_SweepAtomState(cx); + + /* Finalize watch points associated with unreachable objects. */ + js_SweepWatchPoints(cx); + +#ifdef DEBUG + /* Save the pre-sweep count of scope-mapped properties. */ + rt->liveObjectPropsPreSweep = rt->liveObjectProps; +#endif + + SweepCrossCompartmentWrappers(cx); + + /* + * We finalize iterators before other objects so the iterator can use the + * object which properties it enumerates over to finalize the enumeration + * state. We finalize objects before other GC things to ensure that + * object's finalizer can access them even if they will be freed. + */ + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) + (*c)->finalizeObjectArenaLists(cx); + + TIMESTAMP(sweepObjectEnd); + + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) + (*c)->finalizeStringArenaLists(cx); + + TIMESTAMP(sweepStringEnd); + + /* + * Sweep the runtime's property trees after finalizing objects, in case any + * had watchpoints referencing tree nodes. + * + * Do this before sweeping compartments, so that we sweep all shapes in + * unreachable compartments. + */ + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) + (*c)->propertyTree.sweepShapes(cx); + + PropertyTree::dumpShapes(cx); + TIMESTAMP(sweepShapeEnd); + + SweepCompartments(cx, gckind); + + /* + * Sweep script filenames after sweeping functions in the generic loop + * above. In this way when a scripted function's finalizer destroys the + * script and calls rt->destroyScriptHook, the hook can still access the + * script's filename. See bug 323267. + */ + js_SweepScriptFilenames(rt); + + /* + * Destroy arenas after we finished the sweeping so finalizers can safely + * use js_IsAboutToBeFinalized(). + */ + ExpireGCChunks(rt); + TIMESTAMP(sweepDestroyEnd); + + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) + (*c)->clearMark(); + + if (rt->gcCallback) + (void) rt->gcCallback(cx, JSGC_FINALIZE_END); +#ifdef DEBUG_srcnotesize + { extern void DumpSrcNoteSizeHist(); + DumpSrcNoteSizeHist(); + printf("GC HEAP SIZE %lu\n", (unsigned long)rt->gcBytes); + } +#endif + +#ifdef JS_SCOPE_DEPTH_METER + DumpScopeDepthMeter(rt); +#endif + +#ifdef JS_DUMP_LOOP_STATS + DumpLoopStats(rt); +#endif +} + +#ifdef JS_THREADSAFE + +/* + * If the GC is running and we're called on another thread, wait for this GC + * activation to finish. We can safely wait here without fear of deadlock (in + * the case where we are called within a request on another thread's context) + * because the GC doesn't set rt->gcRunning until after it has waited for all + * active requests to end. + * + * We call here js_CurrentThreadId() after checking for rt->gcState to avoid + * an expensive call when the GC is not running. + */ +void +js_WaitForGC(JSRuntime *rt) +{ + if (rt->gcRunning && rt->gcThread->id != js_CurrentThreadId()) { + do { + JS_AWAIT_GC_DONE(rt); + } while (rt->gcRunning); + } +} + +/* + * GC is running on another thread. Temporarily suspend all requests running + * on the current thread and wait until the GC is done. + */ +static void +LetOtherGCFinish(JSContext *cx) +{ + JSRuntime *rt = cx->runtime; + JS_ASSERT(rt->gcThread); + JS_ASSERT(cx->thread != rt->gcThread); + + size_t requestDebit = cx->thread->data.requestDepth ? 1 : 0; + JS_ASSERT(requestDebit <= rt->requestCount); +#ifdef JS_TRACER + JS_ASSERT_IF(requestDebit == 0, !JS_ON_TRACE(cx)); +#endif + if (requestDebit != 0) { +#ifdef JS_TRACER + if (JS_ON_TRACE(cx)) { + /* + * Leave trace before we decrease rt->requestCount and notify the + * GC. Otherwise the GC may start immediately after we unlock while + * this thread is still on trace. + */ + AutoUnlockGC unlock(rt); + LeaveTrace(cx); + } +#endif + rt->requestCount -= requestDebit; + if (rt->requestCount == 0) + JS_NOTIFY_REQUEST_DONE(rt); + } + + /* + * Check that we did not release the GC lock above and let the GC to + * finish before we wait. + */ + JS_ASSERT(rt->gcThread); + + /* + * Wait for GC to finish on the other thread, even if requestDebit is 0 + * and even if GC has not started yet because the gcThread is waiting in + * AutoGCSession. This ensures that js_GC never returns without a full GC + * cycle happening. + */ + do { + JS_AWAIT_GC_DONE(rt); + } while (rt->gcThread); + + rt->requestCount += requestDebit; +} + +#endif + +class AutoGCSession { + public: + explicit AutoGCSession(JSContext *cx); + ~AutoGCSession(); + + private: + JSContext *context; + + /* Disable copy constructor or assignments */ + AutoGCSession(const AutoGCSession&); + void operator=(const AutoGCSession&); +}; + +/* + * Start a new GC session. Together with LetOtherGCFinish this function + * contains the rendezvous algorithm by which we stop the world for GC. + * + * This thread becomes the GC thread. Wait for all other threads to quiesce. + * Then set rt->gcRunning and return. + */ +AutoGCSession::AutoGCSession(JSContext *cx) + : context(cx) +{ + JSRuntime *rt = cx->runtime; + +#ifdef JS_THREADSAFE + if (rt->gcThread && rt->gcThread != cx->thread) + LetOtherGCFinish(cx); +#endif + + JS_ASSERT(!rt->gcRunning); + +#ifdef JS_THREADSAFE + /* No other thread is in GC, so indicate that we're now in GC. */ + JS_ASSERT(!rt->gcThread); + rt->gcThread = cx->thread; + + /* + * Notify operation callbacks on other threads, which will give them a + * chance to yield their requests. Threads without requests perform their + * callback at some later point, which then will be unnecessary, but + * harmless. + */ + for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) { + JSThread *thread = r.front().value; + if (thread != cx->thread) + thread->data.triggerOperationCallback(rt); + } + + /* + * Discount the request on the current thread from contributing to + * rt->requestCount before we wait for all other requests to finish. + * JS_NOTIFY_REQUEST_DONE, which will wake us up, is only called on + * rt->requestCount transitions to 0. + */ + size_t requestDebit = cx->thread->data.requestDepth ? 1 : 0; + JS_ASSERT(requestDebit <= rt->requestCount); + if (requestDebit != rt->requestCount) { + rt->requestCount -= requestDebit; + + do { + JS_AWAIT_REQUEST_DONE(rt); + } while (rt->requestCount > 0); + rt->requestCount += requestDebit; + } + +#endif /* JS_THREADSAFE */ + + /* + * Set rt->gcRunning here within the GC lock, and after waiting for any + * active requests to end. This way js_WaitForGC called outside a request + * would not block on the GC that is waiting for other requests to finish + * with rt->gcThread set while JS_BeginRequest would do such wait. + */ + rt->gcRunning = true; +} + +/* End the current GC session and allow other threads to proceed. */ +AutoGCSession::~AutoGCSession() +{ + JSRuntime *rt = context->runtime; + rt->gcRunning = false; +#ifdef JS_THREADSAFE + JS_ASSERT(rt->gcThread == context->thread); + rt->gcThread = NULL; + JS_NOTIFY_GC_DONE(rt); +#endif +} + +/* + * GC, repeatedly if necessary, until we think we have not created any new + * garbage and no other threads are demanding more GC. + */ +static void +GCUntilDone(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIMER_PARAM) +{ + if (JS_ON_TRACE(cx)) + return; + + JSRuntime *rt = cx->runtime; + + /* Recursive GC or a call from another thread restarts the GC cycle. */ + if (rt->gcMarkAndSweep) { + rt->gcPoke = true; +#ifdef JS_THREADSAFE + JS_ASSERT(rt->gcThread); + if (rt->gcThread != cx->thread) { + /* We do not return until another GC finishes. */ + LetOtherGCFinish(cx); + } +#endif + return; + } + + AutoGCSession gcsession(cx); + + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) + JS_ASSERT(!(*c)->isMarked()); + + /* + * We should not be depending on cx->compartment in the GC, so set it to + * NULL to look for violations. + */ + SwitchToCompartment(cx, (JSCompartment *)NULL); + + JS_ASSERT(!rt->gcCurrentCompartment); + rt->gcCurrentCompartment = comp; + + METER(rt->gcStats.poke++); + + bool firstRun = true; + rt->gcMarkAndSweep = true; +#ifdef JS_THREADSAFE + JS_ASSERT(!cx->gcBackgroundFree); +#endif + do { + rt->gcPoke = false; + + AutoUnlockGC unlock(rt); + if (firstRun) { + PreGCCleanup(cx, gckind); + TIMESTAMP(startMark); + firstRun = false; + } + + if (comp) + MarkAndSweepCompartment(cx, comp, gckind GCTIMER_ARG); + else + MarkAndSweep(cx, gckind GCTIMER_ARG); + + // GC again if: + // - another thread, not in a request, called js_GC + // - js_GC was called recursively + // - a finalizer called js_RemoveRoot or js_UnlockGCThingRT. + } while (rt->gcPoke); + +#ifdef JS_THREADSAFE + JS_ASSERT(cx->gcBackgroundFree == &rt->gcHelperThread); + cx->gcBackgroundFree = NULL; + rt->gcHelperThread.startBackgroundSweep(rt); +#endif + + rt->gcMarkAndSweep = false; + rt->gcRegenShapes = false; + rt->setGCLastBytes(rt->gcBytes); + rt->gcCurrentCompartment = NULL; + + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) + (*c)->setGCLastBytes((*c)->gcBytes); +} + +void +js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind) +{ + JSRuntime *rt = cx->runtime; + + /* + * Don't collect garbage if the runtime isn't up, and cx is not the last + * context in the runtime. The last context must force a GC, and nothing + * should suppress that final collection or there may be shutdown leaks, + * or runtime bloat until the next context is created. + */ + if (rt->state != JSRTS_UP && gckind != GC_LAST_CONTEXT) + return; + + RecordNativeStackTopForGC(cx); + +#ifdef DEBUG + int stackDummy; +# if JS_STACK_GROWTH_DIRECTION > 0 + /* cx->stackLimit is set to jsuword(-1) by default. */ + JS_ASSERT_IF(cx->stackLimit != jsuword(-1), + JS_CHECK_STACK_SIZE(cx->stackLimit + (1 << 14), &stackDummy)); +# else + /* -16k because it is possible to perform a GC during an overrecursion report. */ + JS_ASSERT_IF(cx->stackLimit, JS_CHECK_STACK_SIZE(cx->stackLimit - (1 << 14), &stackDummy)); +# endif +#endif + + GCTIMER_BEGIN(); + + do { + /* + * Let the API user decide to defer a GC if it wants to (unless this + * is the last context). Invoke the callback regardless. Sample the + * callback in case we are freely racing with a JS_SetGCCallback{,RT} + * on another thread. + */ + if (JSGCCallback callback = rt->gcCallback) { + if (!callback(cx, JSGC_BEGIN) && gckind != GC_LAST_CONTEXT) + return; + } + + { + /* Lock out other GC allocator and collector invocations. */ + AutoLockGC lock(rt); + + GCUntilDone(cx, comp, gckind GCTIMER_ARG); + } + + /* We re-sample the callback again as the finalizers can change it. */ + if (JSGCCallback callback = rt->gcCallback) + (void) callback(cx, JSGC_END); + + /* + * On shutdown, iterate until the JSGC_END callback stops creating + * garbage. + */ + } while (gckind == GC_LAST_CONTEXT && rt->gcPoke); +#ifdef JS_GCMETER + js_DumpGCStats(cx->runtime, stderr); +#endif + GCTIMER_END(gckind == GC_LAST_CONTEXT); +} + +namespace js { +namespace gc { + +bool +SetProtoCheckingForCycles(JSContext *cx, JSObject *obj, JSObject *proto) +{ + /* + * This function cannot be called during the GC and always requires a + * request. + */ +#ifdef JS_THREADSAFE + JS_ASSERT(cx->thread->data.requestDepth); + + /* + * This is only necessary if AutoGCSession below would wait for GC to + * finish on another thread, but to capture the minimal stack space and + * for code simplicity we do it here unconditionally. + */ + RecordNativeStackTopForGC(cx); +#endif + + JSRuntime *rt = cx->runtime; + AutoLockGC lock(rt); + AutoGCSession gcsession(cx); + AutoUnlockGC unlock(rt); + + bool cycle = false; + for (JSObject *obj2 = proto; obj2;) { + if (obj2 == obj) { + cycle = true; + break; + } + obj2 = obj2->getProto(); + } + if (!cycle) + obj->setProto(proto); + + return !cycle; +} + +JSCompartment * +NewCompartment(JSContext *cx, JSPrincipals *principals) +{ + JSRuntime *rt = cx->runtime; + JSCompartment *compartment = js_new(rt); + if (!compartment || !compartment->init()) { + js_delete(compartment); + JS_ReportOutOfMemory(cx); + return NULL; + } + + if (principals) { + compartment->principals = principals; + JSPRINCIPALS_HOLD(cx, principals); + } + + compartment->setGCLastBytes(8192); + + { + AutoLockGC lock(rt); + + if (!rt->compartments.append(compartment)) { + AutoUnlockGC unlock(rt); + JS_ReportOutOfMemory(cx); + return NULL; + } + } + + JSCompartmentCallback callback = rt->compartmentCallback; + if (callback && !callback(cx, compartment, JSCOMPARTMENT_NEW)) { + AutoLockGC lock(rt); + rt->compartments.popBack(); + return NULL; + } + return compartment; +} + +} /* namespace gc */ + +void +TraceRuntime(JSTracer *trc) +{ + LeaveTrace(trc->context); + +#ifdef JS_THREADSAFE + { + JSContext *cx = trc->context; + JSRuntime *rt = cx->runtime; + AutoLockGC lock(rt); + + if (rt->gcThread != cx->thread) { + AutoGCSession gcsession(cx); + AutoUnlockGC unlock(rt); + RecordNativeStackTopForGC(trc->context); + MarkRuntime(trc); + return; + } + } +#else + RecordNativeStackTopForGC(trc->context); +#endif + + /* + * Calls from inside a normal GC or a recursive calls are OK and do not + * require session setup. + */ + MarkRuntime(trc); +} + +} /* namespace js */ diff --git a/js/src/jsgc.h b/js/src/jsgc.h new file mode 100644 index 0000000..bb666e6 --- /dev/null +++ b/js/src/jsgc.h @@ -0,0 +1,1114 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsgc_h___ +#define jsgc_h___ + +/* Gross special case for Gecko, which defines malloc/calloc/free. */ +#ifdef mozilla_mozalloc_macro_wrappers_h +# define JS_GC_UNDEFD_MOZALLOC_WRAPPERS +/* The "anti-header" */ +# include "mozilla/mozalloc_undef_macro_wrappers.h" +#endif + +/* + * JS Garbage Collector. + */ +#include + +#include "jstypes.h" +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jsdhash.h" +#include "jsbit.h" +#include "jsgcchunk.h" +#include "jsutil.h" +#include "jsvector.h" +#include "jsversion.h" +#include "jsobj.h" +#include "jsfun.h" +#include "jsgcstats.h" +#include "jscell.h" + +struct JSCompartment; + +extern "C" void +js_TraceXML(JSTracer *trc, JSXML* thing); + +#if JS_STACK_GROWTH_DIRECTION > 0 +# define JS_CHECK_STACK_SIZE(limit, lval) ((jsuword)(lval) < limit) +#else +# define JS_CHECK_STACK_SIZE(limit, lval) ((jsuword)(lval) > limit) +#endif + +namespace js { + +struct Shape; + +namespace gc { + +/* + * The kind of GC thing with a finalizer. The external strings follow the + * ordinary string to simplify js_GetExternalStringGCType. + */ +enum FinalizeKind { + FINALIZE_OBJECT0, + FINALIZE_OBJECT2, + FINALIZE_OBJECT4, + FINALIZE_OBJECT8, + FINALIZE_OBJECT12, + FINALIZE_OBJECT16, + FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16, + FINALIZE_FUNCTION, +#if JS_HAS_XML_SUPPORT + FINALIZE_XML, +#endif + FINALIZE_SHORT_STRING, + FINALIZE_STRING, + FINALIZE_EXTERNAL_STRING, + FINALIZE_LIMIT +}; + +const uintN JS_FINALIZE_OBJECT_LIMIT = 6; + +/* Every arena has a header. */ +struct ArenaHeader { + JSCompartment *compartment; + Arena *next; + FreeCell *freeList; + unsigned thingKind; + bool isUsed; + size_t thingSize; +#ifdef DEBUG + bool hasFreeThings; +#endif +}; + +template +union ThingOrCell { + T t; + FreeCell cell; +}; + +template +struct Things { + ThingOrCell things[N]; + char filler[R]; +}; + +template +struct Things { + ThingOrCell things[N]; +}; + +template +struct Arena { + static const size_t ArenaSize = 4096; + + struct AlignedArenaHeader { + T align[(sizeof(ArenaHeader) + sizeof(T) - 1) / sizeof(T)]; + }; + + /* We want things in the arena to be aligned, so align the header. */ + union { + ArenaHeader aheader; + AlignedArenaHeader align; + }; + + static const size_t ThingsPerArena = (ArenaSize - sizeof(AlignedArenaHeader)) / sizeof(T); + static const size_t FillerSize = ArenaSize - sizeof(AlignedArenaHeader) - sizeof(T) * ThingsPerArena; + Things t; + + inline Chunk *chunk() const; + inline size_t arenaIndex() const; + + inline ArenaHeader *header() { return &aheader; }; + + inline MarkingDelay *getMarkingDelay() const; + inline ArenaBitmap *bitmap() const; + + inline ConservativeGCTest mark(T *thing, JSTracer *trc); + void markDelayedChildren(JSTracer *trc); + inline bool inFreeList(void *thing) const; + inline T *getAlignedThing(void *thing); +#ifdef DEBUG + inline bool assureThingIsAligned(void *thing); +#endif + + void init(JSCompartment *compartment, unsigned thingKind); +}; +JS_STATIC_ASSERT(sizeof(Arena) == 4096); + +/* + * Live objects are marked black. How many other additional colors are available + * depends on the size of the GCThing. + */ +static const uint32 BLACK = 0; + +/* An arena bitmap contains enough mark bits for all the cells in an arena. */ +struct ArenaBitmap { + static const size_t BitCount = Arena::ArenaSize / Cell::CellSize; + static const size_t BitWords = BitCount / JS_BITS_PER_WORD; + + uintptr_t bitmap[BitWords]; + + JS_ALWAYS_INLINE bool isMarked(size_t bit, uint32 color) { + bit += color; + JS_ASSERT(bit < BitCount); + uintptr_t *word = &bitmap[bit / JS_BITS_PER_WORD]; + return *word & (uintptr_t(1) << (bit % JS_BITS_PER_WORD)); + } + + JS_ALWAYS_INLINE bool markIfUnmarked(size_t bit, uint32 color) { + JS_ASSERT(bit + color < BitCount); + uintptr_t *word = &bitmap[bit / JS_BITS_PER_WORD]; + uintptr_t mask = (uintptr_t(1) << (bit % JS_BITS_PER_WORD)); + if (*word & mask) + return false; + *word |= mask; + if (color != BLACK) { + bit += color; + word = &bitmap[bit / JS_BITS_PER_WORD]; + mask = (uintptr_t(1) << (bit % JS_BITS_PER_WORD)); + if (*word & mask) + return false; + *word |= mask; + } + return true; + } + + JS_ALWAYS_INLINE void unmark(size_t bit, uint32 color) { + bit += color; + JS_ASSERT(bit < BitCount); + uintptr_t *word = &bitmap[bit / JS_BITS_PER_WORD]; + *word &= ~(uintptr_t(1) << (bit % JS_BITS_PER_WORD)); + } + +#ifdef DEBUG + bool noBitsSet() { + for (unsigned i = 0; i < BitWords; i++) { + if (bitmap[i] != uintptr_t(0)) + return false; + } + return true; + } +#endif +}; + +/* Ensure that bitmap covers the whole arena. */ +JS_STATIC_ASSERT(Arena::ArenaSize % Cell::CellSize == 0); +JS_STATIC_ASSERT(ArenaBitmap::BitCount % JS_BITS_PER_WORD == 0); + +/* Marking delay is used to resume marking later when recursive marking uses too much stack. */ +struct MarkingDelay { + Arena *link; + uintptr_t unmarkedChildren; + jsuword start; + + void init() + { + link = NULL; + unmarkedChildren = 0; + } +}; + +struct EmptyArenaLists { + /* Arenas with no internal freelist prepared. */ + Arena *cellFreeList; + + /* Arenas with internal freelists prepared for a given finalize kind. */ + Arena *freeLists[FINALIZE_LIMIT]; + + void init() { + PodZero(this); + } + + Arena *getOtherArena() { + Arena *arena = cellFreeList; + if (arena) { + cellFreeList = arena->header()->next; + return arena; + } + for (int i = 0; i < FINALIZE_LIMIT; i++) { + if ((arena = (Arena *) freeLists[i])) { + freeLists[i] = freeLists[i]->header()->next; + return arena; + } + } + JS_NOT_REACHED("No arena"); + return NULL; + } + + template + inline Arena *getTypedFreeList(unsigned thingKind); + + template + inline Arena *getNext(JSCompartment *comp, unsigned thingKind); + + template + inline void insert(Arena *arena); +}; + +template +inline Arena * +EmptyArenaLists::getTypedFreeList(unsigned thingKind) { + JS_ASSERT(thingKind < FINALIZE_LIMIT); + Arena *arena = (Arena*) freeLists[thingKind]; + if (arena) { + freeLists[thingKind] = freeLists[thingKind]->header()->next; + return arena; + } + return NULL; +} + +template +inline Arena * +EmptyArenaLists::getNext(JSCompartment *comp, unsigned thingKind) { + Arena *arena = getTypedFreeList(thingKind); + if (arena) { + JS_ASSERT(arena->header()->isUsed == false); + JS_ASSERT(arena->header()->thingSize == sizeof(T)); + arena->header()->isUsed = true; + arena->header()->thingKind = thingKind; + arena->header()->compartment = comp; + return arena; + } + arena = (Arena *)getOtherArena(); + JS_ASSERT(arena->header()->isUsed == false); + arena->init(comp, thingKind); + return arena; +} + +template +inline void +EmptyArenaLists::insert(Arena *arena) { + unsigned thingKind = arena->header()->thingKind; + JS_ASSERT(thingKind < FINALIZE_LIMIT); + arena->header()->next = freeLists[thingKind]; + freeLists[thingKind] = (Arena *) arena; +} + +/* The chunk header (located at the end of the chunk to preserve arena alignment). */ +struct ChunkInfo { + Chunk *link; + JSRuntime *runtime; + EmptyArenaLists emptyArenaLists; + size_t age; + size_t numFree; +}; + +/* Chunks contain arenas and associated data structures (mark bitmap, delayed marking state). */ +struct Chunk { + static const size_t BytesPerArena = sizeof(Arena) + + sizeof(ArenaBitmap) + + sizeof(MarkingDelay); + + static const size_t ArenasPerChunk = (GC_CHUNK_SIZE - sizeof(ChunkInfo)) / BytesPerArena; + + Arena arenas[ArenasPerChunk]; + ArenaBitmap bitmaps[ArenasPerChunk]; + MarkingDelay markingDelay[ArenasPerChunk]; + + ChunkInfo info; + + void clearMarkBitmap(); + void init(JSRuntime *rt); + + bool unused(); + bool hasAvailableArenas(); + bool withinArenasRange(Cell *cell); + + template + Arena *allocateArena(JSCompartment *comp, unsigned thingKind); + + template + void releaseArena(Arena *a); + + JSRuntime *getRuntime(); +}; +JS_STATIC_ASSERT(sizeof(Chunk) <= GC_CHUNK_SIZE); +JS_STATIC_ASSERT(sizeof(Chunk) + Chunk::BytesPerArena > GC_CHUNK_SIZE); + +Arena * +Cell::arena() const +{ + uintptr_t addr = uintptr_t(this); + JS_ASSERT(addr % sizeof(FreeCell) == 0); + addr &= ~(Arena::ArenaSize - 1); + return reinterpret_cast *>(addr); +} + +Chunk * +Cell::chunk() const +{ + uintptr_t addr = uintptr_t(this); + JS_ASSERT(addr % sizeof(FreeCell) == 0); + addr &= ~(GC_CHUNK_SIZE - 1); + return reinterpret_cast(addr); +} + +ArenaBitmap * +Cell::bitmap() const +{ + return &chunk()->bitmaps[arena()->arenaIndex()]; +} + +STATIC_POSTCONDITION_ASSUME(return < ArenaBitmap::BitCount) +size_t +Cell::cellIndex() const +{ + return reinterpret_cast(this) - reinterpret_cast(&arena()->t); +} + +template +Chunk * +Arena::chunk() const +{ + uintptr_t addr = uintptr_t(this); + JS_ASSERT(addr % sizeof(FreeCell) == 0); + addr &= ~(GC_CHUNK_SIZE - 1); + return reinterpret_cast(addr); +} + +template +size_t +Arena::arenaIndex() const +{ + return reinterpret_cast *>(this) - chunk()->arenas; +} + +template +MarkingDelay * +Arena::getMarkingDelay() const +{ + return &chunk()->markingDelay[arenaIndex()]; +} + +template +ArenaBitmap * +Arena::bitmap() const +{ + return &chunk()->bitmaps[arenaIndex()]; +} + +template +inline T * +Arena::getAlignedThing(void *thing) +{ + jsuword start = reinterpret_cast(&t.things[0]); + jsuword offset = reinterpret_cast(thing) - start; + offset -= offset % aheader.thingSize; + return reinterpret_cast(start + offset); +} + +#ifdef DEBUG +template +inline bool +Arena::assureThingIsAligned(void *thing) +{ + return (getAlignedThing(thing) == thing); +} +#endif + +static void +AssertValidColor(const void *thing, uint32 color) +{ + JS_ASSERT_IF(color, color < reinterpret_cast(thing)->arena()->header()->thingSize / sizeof(FreeCell)); +} + +inline bool +Cell::isMarked(uint32 color = BLACK) const +{ + AssertValidColor(this, color); + return bitmap()->isMarked(cellIndex(), color); +} + +bool +Cell::markIfUnmarked(uint32 color = BLACK) const +{ + AssertValidColor(this, color); + return bitmap()->markIfUnmarked(cellIndex(), color); +} + +void +Cell::unmark(uint32 color) const +{ + JS_ASSERT(color != BLACK); + AssertValidColor(this, color); + bitmap()->unmark(cellIndex(), color); +} + +JSCompartment * +Cell::compartment() const +{ + return arena()->header()->compartment; +} + +template +static inline +Arena * +GetArena(Cell *cell) +{ + return reinterpret_cast *>(cell->arena()); +} + +#define JSTRACE_XML 2 + +/* + * One past the maximum trace kind. + */ +#define JSTRACE_LIMIT 3 + +/* + * Lower limit after which we limit the heap growth + */ +const size_t GC_ARENA_ALLOCATION_TRIGGER = 30 * js::GC_CHUNK_SIZE; + +/* + * A GC is triggered once the number of newly allocated arenas + * is GC_HEAP_GROWTH_FACTOR times the number of live arenas after + * the last GC starting after the lower limit of + * GC_ARENA_ALLOCATION_TRIGGER. + */ +const float GC_HEAP_GROWTH_FACTOR = 3.0f; + +static inline size_t +GetFinalizableTraceKind(size_t thingKind) +{ + JS_STATIC_ASSERT(JSExternalString::TYPE_LIMIT == 8); + + static const uint8 map[FINALIZE_LIMIT] = { + JSTRACE_OBJECT, /* FINALIZE_OBJECT0 */ + JSTRACE_OBJECT, /* FINALIZE_OBJECT2 */ + JSTRACE_OBJECT, /* FINALIZE_OBJECT4 */ + JSTRACE_OBJECT, /* FINALIZE_OBJECT8 */ + JSTRACE_OBJECT, /* FINALIZE_OBJECT12 */ + JSTRACE_OBJECT, /* FINALIZE_OBJECT16 */ + JSTRACE_OBJECT, /* FINALIZE_FUNCTION */ +#if JS_HAS_XML_SUPPORT /* FINALIZE_XML */ + JSTRACE_XML, +#endif + JSTRACE_STRING, /* FINALIZE_SHORT_STRING */ + JSTRACE_STRING, /* FINALIZE_STRING */ + JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING */ + }; + + JS_ASSERT(thingKind < FINALIZE_LIMIT); + return map[thingKind]; +} + +static inline bool +IsFinalizableStringKind(unsigned thingKind) +{ + return unsigned(FINALIZE_SHORT_STRING) <= thingKind && + thingKind <= unsigned(FINALIZE_EXTERNAL_STRING); +} + +/* + * Get the type of the external string or -1 if the string was not created + * with JS_NewExternalString. + */ +static inline intN +GetExternalStringGCType(JSExternalString *str) +{ + JS_STATIC_ASSERT(FINALIZE_STRING + 1 == FINALIZE_EXTERNAL_STRING); + JS_ASSERT(!JSString::isStatic(str)); + + unsigned thingKind = str->externalStringType; + JS_ASSERT(IsFinalizableStringKind(thingKind)); + return intN(thingKind); +} + +static inline uint32 +GetGCThingTraceKind(void *thing) +{ + JS_ASSERT(thing); + if (JSString::isStatic(thing)) + return JSTRACE_STRING; + Cell *cell = reinterpret_cast(thing); + return GetFinalizableTraceKind(cell->arena()->header()->thingKind); +} + +static inline JSRuntime * +GetGCThingRuntime(void *thing) +{ + return reinterpret_cast(thing)->chunk()->info.runtime; +} + +#ifdef DEBUG +extern bool +checkArenaListsForThing(JSCompartment *comp, jsuword thing); +#endif + +/* The arenas in a list have uniform kind. */ +struct ArenaList { + Arena *head; /* list start */ + Arena *cursor; /* arena with free things */ + + inline void init() { + head = NULL; + cursor = NULL; + } + + inline Arena *getNextWithFreeList() { + Arena *a; + while (cursor != NULL) { + ArenaHeader *aheader = cursor->header(); + a = cursor; + cursor = aheader->next; + if (aheader->freeList) + return a; + } + return NULL; + } + +#ifdef DEBUG + template + bool arenasContainThing(void *thing) { + for (Arena *a = (Arena *) head; a; a = (Arena *) a->header()->next) { + JS_ASSERT(a->header()->isUsed); + if (thing >= &a->t.things[0] && thing < &a->t.things[a->ThingsPerArena]) + return true; + } + return false; + } + + bool markedThingsInArenaList() { + for (Arena *a = (Arena *) head; a; a = (Arena *) a->header()->next) { + if (!a->bitmap()->noBitsSet()) + return true; + } + return false; + } +#endif + + inline void insert(Arena *a) { + a->header()->next = head; + head = a; + } + + void releaseAll() { + while (head) { + Arena *next = head->header()->next; + head->chunk()->releaseArena(head); + head = next; + } + head = NULL; + cursor = NULL; + } + + inline bool isEmpty() const { + return (head == NULL); + } +}; + +struct FreeLists { + FreeCell **finalizables[FINALIZE_LIMIT]; + + void purge(); + + inline FreeCell *getNext(uint32 kind) { + FreeCell *top = NULL; + if (finalizables[kind]) { + top = *finalizables[kind]; + if (top) { + *finalizables[kind] = top->link; + } else { + finalizables[kind] = NULL; + } +#ifdef DEBUG + if (top && !top->link) + top->arena()->header()->hasFreeThings = false; +#endif + } + return top; + } + + template + inline void populate(Arena *a, uint32 thingKind) { + finalizables[thingKind] = &a->header()->freeList; + } + +#ifdef DEBUG + bool isEmpty() const { + for (size_t i = 0; i != JS_ARRAY_LENGTH(finalizables); ++i) { + if (finalizables[i]) + return false; + } + return true; + } +#endif +}; +} + +typedef Vector GCChunks; + +struct GCPtrHasher +{ + typedef void *Lookup; + + static HashNumber hash(void *key) { + return HashNumber(uintptr_t(key) >> JS_GCTHING_ZEROBITS); + } + + static bool match(void *l, void *k) { return l == k; } +}; + +typedef HashMap GCLocks; + +struct RootInfo { + RootInfo() {} + RootInfo(const char *name, JSGCRootType type) : name(name), type(type) {} + const char *name; + JSGCRootType type; +}; + +typedef js::HashMap, + js::SystemAllocPolicy> RootedValueMap; + +/* If HashNumber grows, need to change WrapperHasher. */ +JS_STATIC_ASSERT(sizeof(HashNumber) == 4); + +struct WrapperHasher +{ + typedef Value Lookup; + + static HashNumber hash(Value key) { + uint64 bits = JSVAL_BITS(Jsvalify(key)); + return (uint32)bits ^ (uint32)(bits >> 32); + } + + static bool match(const Value &l, const Value &k) { return l == k; } +}; + +typedef HashMap WrapperMap; + +class AutoValueVector; +class AutoIdVector; +} + +static inline void +CheckGCFreeListLink(js::gc::FreeCell *cell) +{ + /* + * The GC things on the free lists come from one arena and the things on + * the free list are linked in ascending address order. + */ + JS_ASSERT_IF(cell->link, + cell->arena() == + cell->link->arena()); + JS_ASSERT_IF(cell->link, cell < cell->link); +} + +extern bool +RefillFinalizableFreeList(JSContext *cx, unsigned thingKind); + +#ifdef DEBUG +extern bool +CheckAllocation(JSContext *cx); +#endif + +/* + * Get the type of the external string or -1 if the string was not created + * with JS_NewExternalString. + */ +extern intN +js_GetExternalStringGCType(JSString *str); + +extern JS_FRIEND_API(uint32) +js_GetGCThingTraceKind(void *thing); + +#if 1 +/* + * Since we're forcing a GC from JS_GC anyway, don't bother wasting cycles + * loading oldval. XXX remove implied force, fix jsinterp.c's "second arg + * ignored", etc. + */ +#define GC_POKE(cx, oldval) ((cx)->runtime->gcPoke = JS_TRUE) +#else +#define GC_POKE(cx, oldval) ((cx)->runtime->gcPoke = JSVAL_IS_GCTHING(oldval)) +#endif + +extern JSBool +js_InitGC(JSRuntime *rt, uint32 maxbytes); + +extern void +js_FinishGC(JSRuntime *rt); + +extern JSBool +js_AddRoot(JSContext *cx, js::Value *vp, const char *name); + +extern JSBool +js_AddGCThingRoot(JSContext *cx, void **rp, const char *name); + +#ifdef DEBUG +extern void +js_DumpNamedRoots(JSRuntime *rt, + void (*dump)(const char *name, void *rp, JSGCRootType type, void *data), + void *data); +#endif + +extern uint32 +js_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data); + +/* Table of pointers with count valid members. */ +typedef struct JSPtrTable { + size_t count; + void **array; +} JSPtrTable; + +extern JSBool +js_RegisterCloseableIterator(JSContext *cx, JSObject *obj); + +#ifdef JS_TRACER +extern JSBool +js_ReserveObjects(JSContext *cx, size_t nobjects); +#endif + +extern JSBool +js_LockGCThingRT(JSRuntime *rt, void *thing); + +extern void +js_UnlockGCThingRT(JSRuntime *rt, void *thing); + +extern JS_FRIEND_API(bool) +IsAboutToBeFinalized(JSContext *cx, void *thing); + +extern JS_FRIEND_API(bool) +js_GCThingIsMarked(void *thing, uintN color); + +extern void +js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp); + +namespace js { + +extern JS_REQUIRES_STACK void +MarkRuntime(JSTracer *trc); + +extern void +TraceRuntime(JSTracer *trc); + +extern JS_REQUIRES_STACK JS_FRIEND_API(void) +MarkContext(JSTracer *trc, JSContext *acx); + +/* Must be called with GC lock taken. */ +extern void +TriggerGC(JSRuntime *rt); + +/* Must be called with GC lock taken. */ +extern void +TriggerCompartmentGC(JSCompartment *comp); + +extern void +MaybeGC(JSContext *cx); + +} /* namespace js */ + +/* + * Kinds of js_GC invocation. + */ +typedef enum JSGCInvocationKind { + /* Normal invocation. */ + GC_NORMAL = 0, + + /* + * Called from js_DestroyContext for last JSContext in a JSRuntime, when + * it is imperative that rt->gcPoke gets cleared early in js_GC. + */ + GC_LAST_CONTEXT = 1 +} JSGCInvocationKind; + +/* Pass NULL for |comp| to get a full GC. */ +extern void +js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind); + +#ifdef JS_THREADSAFE +/* + * This is a helper for code at can potentially run outside JS request to + * ensure that the GC is not running when the function returns. + * + * This function must be called with the GC lock held. + */ +extern void +js_WaitForGC(JSRuntime *rt); + +#else /* !JS_THREADSAFE */ + +# define js_WaitForGC(rt) ((void) 0) + +#endif + +extern void +js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp); + +namespace js { + +#ifdef JS_THREADSAFE + +/* + * During the finalization we do not free immediately. Rather we add the + * corresponding pointers to a buffer which we later release on a separated + * thread. + * + * The buffer is implemented as a vector of 64K arrays of pointers, not as a + * simple vector, to avoid realloc calls during the vector growth and to not + * bloat the binary size of the inlined freeLater method. Any OOM during + * buffer growth results in the pointer being freed immediately. + */ +class GCHelperThread { + static const size_t FREE_ARRAY_SIZE = size_t(1) << 16; + static const size_t FREE_ARRAY_LENGTH = FREE_ARRAY_SIZE / sizeof(void *); + + PRThread* thread; + PRCondVar* wakeup; + PRCondVar* sweepingDone; + bool shutdown; + bool sweeping; + + Vector freeVector; + void **freeCursor; + void **freeCursorEnd; + + JS_FRIEND_API(void) + replenishAndFreeLater(void *ptr); + + static void freeElementsAndArray(void **array, void **end) { + JS_ASSERT(array <= end); + for (void **p = array; p != end; ++p) + js_free(*p); + js_free(array); + } + + static void threadMain(void* arg); + + void threadLoop(JSRuntime *rt); + void doSweep(); + + public: + GCHelperThread() + : thread(NULL), + wakeup(NULL), + sweepingDone(NULL), + shutdown(false), + sweeping(false), + freeCursor(NULL), + freeCursorEnd(NULL) { } + + bool init(JSRuntime *rt); + void finish(JSRuntime *rt); + + /* Must be called with GC lock taken. */ + void startBackgroundSweep(JSRuntime *rt); + + /* Must be called outside the GC lock. */ + void waitBackgroundSweepEnd(JSRuntime *rt); + + void freeLater(void *ptr) { + JS_ASSERT(!sweeping); + if (freeCursor != freeCursorEnd) + *freeCursor++ = ptr; + else + replenishAndFreeLater(ptr); + } +}; + +#endif /* JS_THREADSAFE */ + +struct GCChunkHasher { + typedef gc::Chunk *Lookup; + + /* + * Strip zeros for better distribution after multiplying by the golden + * ratio. + */ + static HashNumber hash(gc::Chunk *chunk) { + JS_ASSERT(!(jsuword(chunk) & GC_CHUNK_MASK)); + return HashNumber(jsuword(chunk) >> GC_CHUNK_SHIFT); + } + + static bool match(gc::Chunk *k, gc::Chunk *l) { + JS_ASSERT(!(jsuword(k) & GC_CHUNK_MASK)); + JS_ASSERT(!(jsuword(l) & GC_CHUNK_MASK)); + return k == l; + } +}; + +typedef HashSet GCChunkSet; + +struct ConservativeGCThreadData { + + /* + * The GC scans conservatively between JSThreadData::nativeStackBase and + * nativeStackTop unless the latter is NULL. + */ + jsuword *nativeStackTop; + + union { + jmp_buf jmpbuf; + jsuword words[JS_HOWMANY(sizeof(jmp_buf), sizeof(jsuword))]; + } registerSnapshot; + + /* + * Cycle collector uses this to communicate that the native stack of the + * GC thread should be scanned only if the thread have more than the given + * threshold of requests. + */ + unsigned requestThreshold; + + JS_NEVER_INLINE void recordStackTop(); + +#ifdef JS_THREADSAFE + void updateForRequestEnd(unsigned suspendCount) { + if (suspendCount) + recordStackTop(); + else + nativeStackTop = NULL; + } +#endif + + bool hasStackToScan() const { + return !!nativeStackTop; + } +}; + +struct GCMarker : public JSTracer { + private: + /* The color is only applied to objects, functions and xml. */ + uint32 color; + public: + jsuword stackLimit; + /* See comments before delayMarkingChildren is jsgc.cpp. */ + js::gc::Arena *unmarkedArenaStackTop; +#ifdef DEBUG + size_t markLaterCount; +#endif + +#if defined(JS_DUMP_CONSERVATIVE_GC_ROOTS) || defined(JS_GCMETER) + js::gc::ConservativeGCStats conservativeStats; +#endif + +#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS + struct ConservativeRoot { void *thing; uint32 thingKind; }; + Vector conservativeRoots; + const char *conservativeDumpFileName; + + void dumpConservativeRoots(); +#endif + + public: + explicit GCMarker(JSContext *cx); + ~GCMarker(); + + uint32 getMarkColor() const { + return color; + } + + void setMarkColor(uint32 newColor) { + /* + * We must process any delayed marking here, otherwise we confuse + * colors. + */ + markDelayedChildren(); + color = newColor; + } + + void delayMarkingChildren(void *thing); + + JS_FRIEND_API(void) markDelayedChildren(); +}; + +void +MarkStackRangeConservatively(JSTracer *trc, Value *begin, Value *end); + +} /* namespace js */ + +extern void +js_FinalizeStringRT(JSRuntime *rt, JSString *str); + +/* + * This function is defined in jsdbgapi.cpp but is declared here to avoid + * polluting jsdbgapi.h, a public API header, with internal functions. + */ +extern void +js_MarkTraps(JSTracer *trc); + +namespace js { +namespace gc { + +/* + * Macro to test if a traversal is the marking phase of GC to avoid exposing + * ScriptFilenameEntry to traversal implementations. + */ +#define IS_GC_MARKING_TRACER(trc) ((trc)->callback == NULL) + +#if JS_HAS_XML_SUPPORT +# define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) < JSTRACE_LIMIT) +#else +# define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) <= JSTRACE_STRING) +#endif + +/* + * Set object's prototype while checking that doing so would not create + * a cycle in the proto chain. The cycle check and proto change are done + * only when all other requests are finished or suspended to ensure exclusive + * access to the chain. If there is a cycle, return false without reporting + * an error. Otherwise, set the proto and return true. + */ +extern bool +SetProtoCheckingForCycles(JSContext *cx, JSObject *obj, JSObject *proto); + +JSCompartment * +NewCompartment(JSContext *cx, JSPrincipals *principals); + +} /* namespace js */ +} /* namespace gc */ + +inline JSCompartment * +JSObject::getCompartment() const +{ + return compartment(); +} + +#ifdef JS_GC_UNDEFD_MOZALLOC_WRAPPERS +# include "mozilla/mozalloc_macro_wrappers.h" +#endif + +#endif /* jsgc_h___ */ diff --git a/js/src/jsgcchunk.cpp b/js/src/jsgcchunk.cpp new file mode 100644 index 0000000..08ca549 --- /dev/null +++ b/js/src/jsgcchunk.cpp @@ -0,0 +1,419 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Copyright (C) 2006-2008 Jason Evans . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsgcchunk.h" + +#ifdef XP_WIN +# include "jswin.h" + +# ifdef _MSC_VER +# pragma warning( disable: 4267 4996 4146 ) +# endif + +#elif defined(XP_OS2) + +# define INCL_DOSMEMMGR +# include + +#elif defined(XP_MACOSX) || defined(DARWIN) + +# include +# include +# include +# include +# include + +#elif defined(XP_UNIX) || defined(XP_BEOS) + +# include +# include + +# ifndef MAP_NOSYNC +# define MAP_NOSYNC 0 +# endif + +#endif + +#ifdef XP_WIN + +/* + * On Windows CE < 6 we must use separated MEM_RESERVE and MEM_COMMIT + * VirtualAlloc calls and we cannot use MEM_RESERVE to allocate at the given + * address. So we use a workaround based on oversized allocation. + */ +# if defined(WINCE) && !defined(MOZ_MEMORY_WINCE6) + +# define JS_GC_HAS_MAP_ALIGN + +static void +UnmapPagesAtBase(void *p) +{ + JS_ALWAYS_TRUE(VirtualFree(p, 0, MEM_RELEASE)); +} + +static void * +MapAlignedPages(size_t size, size_t alignment) +{ + JS_ASSERT(size % alignment == 0); + JS_ASSERT(size >= alignment); + + void *reserve = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS); + if (!reserve) + return NULL; + + void *p = VirtualAlloc(reserve, size, MEM_COMMIT, PAGE_READWRITE); + JS_ASSERT(p == reserve); + + size_t mask = alignment - 1; + size_t offset = (uintptr_t) p & mask; + if (!offset) + return p; + + /* Try to extend the initial allocation. */ + UnmapPagesAtBase(reserve); + reserve = VirtualAlloc(NULL, size + alignment - offset, MEM_RESERVE, + PAGE_NOACCESS); + if (!reserve) + return NULL; + if (offset == ((uintptr_t) reserve & mask)) { + void *aligned = (void *) ((uintptr_t) reserve + alignment - offset); + p = VirtualAlloc(aligned, size, MEM_COMMIT, PAGE_READWRITE); + JS_ASSERT(p == aligned); + return p; + } + + /* over allocate to ensure we have an aligned region */ + UnmapPagesAtBase(reserve); + reserve = VirtualAlloc(NULL, size + alignment, MEM_RESERVE, PAGE_NOACCESS); + if (!reserve) + return NULL; + + offset = (uintptr_t) reserve & mask; + void *aligned = (void *) ((uintptr_t) reserve + alignment - offset); + p = VirtualAlloc(aligned, size, MEM_COMMIT, PAGE_READWRITE); + JS_ASSERT(p == aligned); + + return p; +} + +static void +UnmapPages(void *p, size_t size) +{ + if (VirtualFree(p, 0, MEM_RELEASE)) + return; + + /* We could have used the over allocation. */ + JS_ASSERT(GetLastError() == ERROR_INVALID_PARAMETER); + MEMORY_BASIC_INFORMATION info; + VirtualQuery(p, &info, sizeof(info)); + + UnmapPagesAtBase(info.AllocationBase); +} + +# else /* WINCE */ + +static void * +MapPages(void *addr, size_t size) +{ + void *p = VirtualAlloc(addr, size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); + JS_ASSERT_IF(p && addr, p == addr); + return p; +} + +static void +UnmapPages(void *addr, size_t size) +{ + JS_ALWAYS_TRUE(VirtualFree(addr, 0, MEM_RELEASE)); +} + +# endif /* !WINCE */ + +#elif defined(XP_OS2) + +#define JS_GC_HAS_MAP_ALIGN 1 +#define OS2_MAX_RECURSIONS 16 + +static void +UnmapPages(void *addr, size_t size) +{ + if (!DosFreeMem(addr)) + return; + + /* if DosFreeMem() failed, 'addr' is probably part of an "expensive" + * allocation, so calculate the base address and try again + */ + unsigned long cb = 2 * size; + unsigned long flags; + if (DosQueryMem(addr, &cb, &flags) || cb < size) + return; + + jsuword base = reinterpret_cast(addr) - ((2 * size) - cb); + DosFreeMem(reinterpret_cast(base)); + + return; +} + +static void * +MapAlignedPagesRecursively(size_t size, size_t alignment, int& recursions) +{ + if (++recursions >= OS2_MAX_RECURSIONS) + return NULL; + + void *tmp; + if (DosAllocMem(&tmp, size, + OBJ_ANY | PAG_COMMIT | PAG_READ | PAG_WRITE)) { + JS_ALWAYS_TRUE(DosAllocMem(&tmp, size, + PAG_COMMIT | PAG_READ | PAG_WRITE) == 0); + } + size_t offset = reinterpret_cast(tmp) & (alignment - 1); + if (!offset) + return tmp; + + /* if there are 'filler' bytes of free space above 'tmp', free 'tmp', + * then reallocate it as a 'filler'-sized block; assuming we're not + * in a race with another thread, the next recursion should succeed + */ + size_t filler = size + alignment - offset; + unsigned long cb = filler; + unsigned long flags = 0; + unsigned long rc = DosQueryMem(&(static_cast(tmp))[size], + &cb, &flags); + if (!rc && (flags & PAG_FREE) && cb >= filler) { + UnmapPages(tmp, 0); + if (DosAllocMem(&tmp, filler, + OBJ_ANY | PAG_COMMIT | PAG_READ | PAG_WRITE)) { + JS_ALWAYS_TRUE(DosAllocMem(&tmp, filler, + PAG_COMMIT | PAG_READ | PAG_WRITE) == 0); + } + } + + void *p = MapAlignedPagesRecursively(size, alignment, recursions); + UnmapPages(tmp, 0); + + return p; +} + +static void * +MapAlignedPages(size_t size, size_t alignment) +{ + int recursions = -1; + + /* make up to OS2_MAX_RECURSIONS attempts to get an aligned block + * of the right size by recursively allocating blocks of unaligned + * free memory until only an aligned allocation is possible + */ + void *p = MapAlignedPagesRecursively(size, alignment, recursions); + if (p) + return p; + + /* if memory is heavily fragmented, the recursive strategy may fail; + * instead, use the "expensive" strategy: allocate twice as much + * as requested and return an aligned address within this block + */ + if (DosAllocMem(&p, 2 * size, + OBJ_ANY | PAG_COMMIT | PAG_READ | PAG_WRITE)) { + JS_ALWAYS_TRUE(DosAllocMem(&p, 2 * size, + PAG_COMMIT | PAG_READ | PAG_WRITE) == 0); + } + + jsuword addr = reinterpret_cast(p); + addr = (addr + (alignment - 1)) & ~(alignment - 1); + + return reinterpret_cast(addr); +} + +#elif defined(XP_MACOSX) || defined(DARWIN) + +static void * +MapPages(void *addr, size_t size) +{ + vm_address_t p; + int flags; + if (addr) { + p = (vm_address_t) addr; + flags = 0; + } else { + flags = VM_FLAGS_ANYWHERE; + } + + kern_return_t err = vm_allocate((vm_map_t) mach_task_self(), + &p, (vm_size_t) size, flags); + if (err != KERN_SUCCESS) + return NULL; + + JS_ASSERT(p); + JS_ASSERT_IF(addr, p == (vm_address_t) addr); + return (void *) p; +} + +static void +UnmapPages(void *addr, size_t size) +{ + JS_ALWAYS_TRUE(vm_deallocate((vm_map_t) mach_task_self(), + (vm_address_t) addr, + (vm_size_t) size) + == KERN_SUCCESS); +} + +#elif defined(XP_UNIX) || defined(XP_BEOS) + +/* Required on Solaris 10. Might improve performance elsewhere. */ +# if defined(SOLARIS) && defined(MAP_ALIGN) +# define JS_GC_HAS_MAP_ALIGN + +static void * +MapAlignedPages(size_t size, size_t alignment) +{ + /* + * We don't use MAP_FIXED here, because it can cause the *replacement* + * of existing mappings, and we only want to create new mappings. + */ +#ifdef SOLARIS + void *p = mmap((caddr_t) alignment, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_NOSYNC | MAP_ALIGN | MAP_ANON, -1, 0); +#else + void *p = mmap((void *) alignment, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_NOSYNC | MAP_ALIGN | MAP_ANON, -1, 0); +#endif + if (p == MAP_FAILED) + return NULL; + return p; +} + +# else /* JS_GC_HAS_MAP_ALIGN */ + +static void * +MapPages(void *addr, size_t size) +{ + /* + * We don't use MAP_FIXED here, because it can cause the *replacement* + * of existing mappings, and we only want to create new mappings. + */ + void *p = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, + -1, 0); + if (p == MAP_FAILED) + return NULL; + if (addr && p != addr) { + /* We succeeded in mapping memory, but not in the right place. */ + JS_ALWAYS_TRUE(munmap(p, size) == 0); + return NULL; + } + return p; +} + +# endif /* !JS_GC_HAS_MAP_ALIGN */ + +static void +UnmapPages(void *addr, size_t size) +{ +#ifdef SOLARIS + JS_ALWAYS_TRUE(munmap((caddr_t) addr, size) == 0); +#else + JS_ALWAYS_TRUE(munmap(addr, size) == 0); +#endif +} + +#endif + +namespace js { + +GCChunkAllocator defaultGCChunkAllocator; + +inline void * +FindChunkStart(void *p) +{ + jsuword addr = reinterpret_cast(p); + addr = (addr + GC_CHUNK_MASK) & ~GC_CHUNK_MASK; + return reinterpret_cast(addr); +} + +JS_FRIEND_API(void *) +AllocGCChunk() +{ + void *p; + +#ifdef JS_GC_HAS_MAP_ALIGN + p = MapAlignedPages(GC_CHUNK_SIZE, GC_CHUNK_SIZE); + if (!p) + return NULL; +#else + /* + * Windows requires that there be a 1:1 mapping between VM allocation + * and deallocation operations. Therefore, take care here to acquire the + * final result via one mapping operation. This means unmapping any + * preliminary result that is not correctly aligned. + */ + p = MapPages(NULL, GC_CHUNK_SIZE); + if (!p) + return NULL; + + if (reinterpret_cast(p) & GC_CHUNK_MASK) { + UnmapPages(p, GC_CHUNK_SIZE); + p = MapPages(FindChunkStart(p), GC_CHUNK_SIZE); + while (!p) { + /* + * Over-allocate in order to map a memory region that is + * definitely large enough then deallocate and allocate again the + * correct size, within the over-sized mapping. + */ + p = MapPages(NULL, GC_CHUNK_SIZE * 2); + if (!p) + return 0; + UnmapPages(p, GC_CHUNK_SIZE * 2); + p = MapPages(FindChunkStart(p), GC_CHUNK_SIZE); + + /* + * Failure here indicates a race with another thread, so + * try again. + */ + } + } +#endif /* !JS_GC_HAS_MAP_ALIGN */ + + JS_ASSERT(!(reinterpret_cast(p) & GC_CHUNK_MASK)); + return p; +} + +JS_FRIEND_API(void) +FreeGCChunk(void *p) +{ + JS_ASSERT(p); + JS_ASSERT(!(reinterpret_cast(p) & GC_CHUNK_MASK)); + UnmapPages(p, GC_CHUNK_SIZE); +} + +} /* namespace js */ + diff --git a/js/src/jsgcchunk.h b/js/src/jsgcchunk.h new file mode 100644 index 0000000..c4fb923 --- /dev/null +++ b/js/src/jsgcchunk.h @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9.1 code, released + * June 30, 2009. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation + * + * Contributor(s): + * Igor Bukanov + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsgchunk_h__ +#define jsgchunk_h__ + +#include "jsprvtd.h" +#include "jsutil.h" + +namespace js { + +#if defined(WINCE) && !defined(MOZ_MEMORY_WINCE6) +const size_t GC_CHUNK_SHIFT = 21; +#else +const size_t GC_CHUNK_SHIFT = 20; +#endif + +const size_t GC_CHUNK_SIZE = size_t(1) << GC_CHUNK_SHIFT; +const size_t GC_CHUNK_MASK = GC_CHUNK_SIZE - 1; + +JS_FRIEND_API(void *) +AllocGCChunk(); + +JS_FRIEND_API(void) +FreeGCChunk(void *p); + +class GCChunkAllocator { + public: + GCChunkAllocator() {} + + void *alloc() { + void *chunk = doAlloc(); + JS_ASSERT(!(reinterpret_cast(chunk) & GC_CHUNK_MASK)); + return chunk; + } + + void free(void *chunk) { + JS_ASSERT(chunk); + JS_ASSERT(!(reinterpret_cast(chunk) & GC_CHUNK_MASK)); + doFree(chunk); + } + + private: + virtual void *doAlloc() { + return AllocGCChunk(); + } + + virtual void doFree(void *chunk) { + FreeGCChunk(chunk); + } + + /* No copy or assignment semantics. */ + GCChunkAllocator(const GCChunkAllocator &); + void operator=(const GCChunkAllocator &); +}; + +extern GCChunkAllocator defaultGCChunkAllocator; + +} + +#endif /* jsgchunk_h__ */ diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h new file mode 100644 index 0000000..e200ee8 --- /dev/null +++ b/js/src/jsgcinlines.h @@ -0,0 +1,683 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsgcinlines_h___ +#define jsgcinlines_h___ + +#include "jsgc.h" +#include "jscntxt.h" +#include "jscompartment.h" + +#include "jslock.h" +#include "jstl.h" + +#ifdef JS_GCMETER +# define METER(x) ((void) (x)) +# define METER_IF(condition, x) ((void) ((condition) && (x))) +#else +# define METER(x) ((void) 0) +# define METER_IF(condition, x) ((void) 0) +#endif + +namespace js { +namespace gc { + +/* Capacity for slotsToThingKind */ +const size_t SLOTS_TO_THING_KIND_LIMIT = 17; + +/* Get the best kind to use when making an object with the given slot count. */ +static inline FinalizeKind +GetGCObjectKind(size_t numSlots) +{ + extern FinalizeKind slotsToThingKind[]; + + if (numSlots >= SLOTS_TO_THING_KIND_LIMIT) + return FINALIZE_OBJECT0; + return slotsToThingKind[numSlots]; +} + +/* Get the number of fixed slots and initial capacity associated with a kind. */ +static inline size_t +GetGCKindSlots(FinalizeKind thingKind) +{ + /* Using a switch in hopes that thingKind will usually be a compile-time constant. */ + switch (thingKind) { + case FINALIZE_OBJECT0: + return 0; + case FINALIZE_OBJECT2: + return 2; + case FINALIZE_OBJECT4: + return 4; + case FINALIZE_OBJECT8: + return 8; + case FINALIZE_OBJECT12: + return 12; + case FINALIZE_OBJECT16: + return 16; + default: + JS_NOT_REACHED("Bad object finalize kind"); + return 0; + } +} + +} /* namespace gc */ +} /* namespace js */ + +/* + * Allocates a new GC thing. After a successful allocation the caller must + * fully initialize the thing before calling any function that can potentially + * trigger GC. This will ensure that GC tracing never sees junk values stored + * in the partially initialized thing. + */ + +template +JS_ALWAYS_INLINE T * +NewFinalizableGCThing(JSContext *cx, unsigned thingKind) +{ + JS_ASSERT(thingKind < js::gc::FINALIZE_LIMIT); +#ifdef JS_THREADSAFE + JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment), + (thingKind == js::gc::FINALIZE_STRING) || + (thingKind == js::gc::FINALIZE_SHORT_STRING)); +#endif + + METER(cx->compartment->compartmentStats[thingKind].alloc++); + do { + js::gc::FreeCell *cell = cx->compartment->freeLists.getNext(thingKind); + if (cell) { + CheckGCFreeListLink(cell); + return (T *)cell; + } + if (!RefillFinalizableFreeList(cx, thingKind)) + return NULL; + } while (true); +} + +#undef METER +#undef METER_IF + +inline JSObject * +js_NewGCObject(JSContext *cx, js::gc::FinalizeKind kind) +{ + JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST); + JSObject *obj = NewFinalizableGCThing(cx, kind); + if (obj) + obj->capacity = js::gc::GetGCKindSlots(kind); + return obj; +} + +inline JSString * +js_NewGCString(JSContext *cx) +{ + return NewFinalizableGCThing(cx, js::gc::FINALIZE_STRING); +} + +inline JSShortString * +js_NewGCShortString(JSContext *cx) +{ + return NewFinalizableGCThing(cx, js::gc::FINALIZE_SHORT_STRING); +} + +inline JSExternalString * +js_NewGCExternalString(JSContext *cx, uintN type) +{ + JS_ASSERT(type < JSExternalString::TYPE_LIMIT); + JSExternalString *str = NewFinalizableGCThing(cx, js::gc::FINALIZE_EXTERNAL_STRING); + return str; +} + +inline JSFunction* +js_NewGCFunction(JSContext *cx) +{ + JSFunction *fun = NewFinalizableGCThing(cx, js::gc::FINALIZE_FUNCTION); + if (fun) + fun->capacity = JSObject::FUN_CLASS_RESERVED_SLOTS; + return fun; +} + +#if JS_HAS_XML_SUPPORT +inline JSXML * +js_NewGCXML(JSContext *cx) +{ + return NewFinalizableGCThing(cx, js::gc::FINALIZE_XML); +} +#endif + +namespace js { +namespace gc { + +static JS_ALWAYS_INLINE void +TypedMarker(JSTracer *trc, JSXML *thing); + +static JS_ALWAYS_INLINE void +TypedMarker(JSTracer *trc, JSObject *thing); + +static JS_ALWAYS_INLINE void +TypedMarker(JSTracer *trc, JSFunction *thing); + +static JS_ALWAYS_INLINE void +TypedMarker(JSTracer *trc, JSShortString *thing); + +static JS_ALWAYS_INLINE void +TypedMarker(JSTracer *trc, JSString *thing); + +template +static JS_ALWAYS_INLINE void +Mark(JSTracer *trc, T *thing) +{ + JS_ASSERT(thing); + JS_ASSERT(JS_IS_VALID_TRACE_KIND(GetGCThingTraceKind(thing))); + JS_ASSERT(trc->debugPrinter || trc->debugPrintArg); + + /* Per-Compartment GC only with GCMarker and no custom JSTracer */ + JS_ASSERT_IF(trc->context->runtime->gcCurrentCompartment, IS_GC_MARKING_TRACER(trc)); + + JSRuntime *rt = trc->context->runtime; + /* Don't mark things outside a compartment if we are in a per-compartment GC */ + if (rt->gcCurrentCompartment && thing->asCell()->compartment() != rt->gcCurrentCompartment) + goto out; + + if (!IS_GC_MARKING_TRACER(trc)) { + uint32 kind = GetGCThingTraceKind(thing); + trc->callback(trc, thing, kind); + goto out; + } + + TypedMarker(trc, thing); + + out: +#ifdef DEBUG + trc->debugPrinter = NULL; + trc->debugPrintArg = NULL; +#endif + return; /* to avoid out: right_curl when DEBUG is not defined */ +} + +static inline void +MarkString(JSTracer *trc, JSString *str) +{ + JS_ASSERT(str); + if (JSString::isStatic(str)) + return; + JS_ASSERT(GetArena((Cell *)str)->assureThingIsAligned((JSString *)str)); + Mark(trc, str); +} + +static inline void +MarkString(JSTracer *trc, JSString *str, const char *name) +{ + JS_ASSERT(str); + JS_SET_TRACING_NAME(trc, name); + MarkString(trc, str); +} + +static inline void +MarkObject(JSTracer *trc, JSObject &obj, const char *name) +{ + JS_ASSERT(trc); + JS_ASSERT(&obj); + JS_SET_TRACING_NAME(trc, name); + JS_ASSERT(GetArena((Cell *)&obj)->assureThingIsAligned(&obj) || + GetArena((Cell *)&obj)->assureThingIsAligned(&obj) || + GetArena((Cell *)&obj)->assureThingIsAligned(&obj) || + GetArena((Cell *)&obj)->assureThingIsAligned(&obj) || + GetArena((Cell *)&obj)->assureThingIsAligned(&obj) || + GetArena((Cell *)&obj)->assureThingIsAligned(&obj) || + GetArena((Cell *)&obj)->assureThingIsAligned(&obj)); + Mark(trc, &obj); +} + +static inline void +MarkChildren(JSTracer *trc, JSObject *obj) +{ + /* If obj has no map, it must be a newborn. */ + if (!obj->map) + return; + + /* Trace universal (ops-independent) members. */ + if (JSObject *proto = obj->getProto()) + MarkObject(trc, *proto, "proto"); + if (JSObject *parent = obj->getParent()) + MarkObject(trc, *parent, "parent"); + + if (obj->emptyShapes) { + int count = FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 + 1; + for (int i = 0; i < count; i++) { + if (obj->emptyShapes[i]) + obj->emptyShapes[i]->trace(trc); + } + } + + /* Delegate to ops or the native marking op. */ + TraceOp op = obj->getOps()->trace; + (op ? op : js_TraceObject)(trc, obj); +} + +static inline void +MarkChildren(JSTracer *trc, JSString *str) +{ + if (str->isDependent()) + MarkString(trc, str->dependentBase(), "base"); + else if (str->isRope()) { + MarkString(trc, str->ropeLeft(), "left child"); + MarkString(trc, str->ropeRight(), "right child"); + } +} + +#ifdef JS_HAS_XML_SUPPORT +static inline void +MarkChildren(JSTracer *trc, JSXML *xml) +{ + js_TraceXML(trc, xml); +} +#endif + +static inline bool +RecursionTooDeep(GCMarker *gcmarker) { +#ifdef JS_GC_ASSUME_LOW_C_STACK + return true; +#else + int stackDummy; + return !JS_CHECK_STACK_SIZE(gcmarker->stackLimit, &stackDummy); +#endif +} + +static JS_ALWAYS_INLINE void +TypedMarker(JSTracer *trc, JSXML *thing) +{ + if (!reinterpret_cast(thing)->markIfUnmarked(reinterpret_cast(trc)->getMarkColor())) + return; + GCMarker *gcmarker = static_cast(trc); + if (RecursionTooDeep(gcmarker)) { + gcmarker->delayMarkingChildren(thing); + } else { + MarkChildren(trc, thing); + } +} + +static JS_ALWAYS_INLINE void +TypedMarker(JSTracer *trc, JSObject *thing) +{ + JS_ASSERT(thing); + JS_ASSERT(JSTRACE_OBJECT == GetFinalizableTraceKind(thing->asCell()->arena()->header()->thingKind)); + + GCMarker *gcmarker = static_cast(trc); + if (!thing->markIfUnmarked(gcmarker->getMarkColor())) + return; + + if (RecursionTooDeep(gcmarker)) { + gcmarker->delayMarkingChildren(thing); + } else { + MarkChildren(trc, thing); + } +} + +static JS_ALWAYS_INLINE void +TypedMarker(JSTracer *trc, JSFunction *thing) +{ + JS_ASSERT(thing); + JS_ASSERT(JSTRACE_OBJECT == GetFinalizableTraceKind(thing->asCell()->arena()->header()->thingKind)); + + GCMarker *gcmarker = static_cast(trc); + if (!thing->markIfUnmarked(gcmarker->getMarkColor())) + return; + + if (RecursionTooDeep(gcmarker)) { + gcmarker->delayMarkingChildren(thing); + } else { + MarkChildren(trc, static_cast(thing)); + } +} + +static JS_ALWAYS_INLINE void +TypedMarker(JSTracer *trc, JSShortString *thing) +{ + /* + * A short string cannot refer to other GC things so we don't have + * anything to mark if the string was unmarked and ignore the + * markIfUnmarked result. + */ + (void) thing->asCell()->markIfUnmarked(); +} + +} /* namespace gc */ + +namespace detail { + +static JS_ALWAYS_INLINE JSString * +Tag(JSString *str) +{ + JS_ASSERT(!(size_t(str) & 1)); + return (JSString *)(size_t(str) | 1); +} + +static JS_ALWAYS_INLINE bool +Tagged(JSString *str) +{ + return (size_t(str) & 1) != 0; +} + +static JS_ALWAYS_INLINE JSString * +Untag(JSString *str) +{ + JS_ASSERT((size_t(str) & 1) == 1); + return (JSString *)(size_t(str) & ~size_t(1)); +} + +static JS_ALWAYS_INLINE void +NonRopeTypedMarker(JSRuntime *rt, JSString *str) +{ + /* N.B. The base of a dependent string is not necessarily flat. */ + JS_ASSERT(!str->isRope()); + + if (rt->gcCurrentCompartment) { + for (;;) { + if (JSString::isStatic(str)) + break; + + /* + * If we perform single-compartment GC don't mark Strings outside the current compartment. + * Dependent Strings are not shared between compartments and they can't be in the atomsCompartment. + */ + if (str->asCell()->compartment() != rt->gcCurrentCompartment) { + JS_ASSERT(str->asCell()->compartment() == rt->atomsCompartment); + break; + } + if (!str->asCell()->markIfUnmarked()) + break; + if (!str->isDependent()) + break; + str = str->dependentBase(); + } + } else { + while (!JSString::isStatic(str) && + str->asCell()->markIfUnmarked() && + str->isDependent()) { + str = str->dependentBase(); + } + } +} + +} /* namespace detail */ + +namespace gc { + +static JS_ALWAYS_INLINE void +TypedMarker(JSTracer *trc, JSString *str) +{ + using namespace detail; + JSRuntime *rt = trc->context->runtime; + JS_ASSERT(!JSString::isStatic(str)); +#ifdef DEBUG + JSCompartment *strComp = str->asCell()->compartment(); +#endif + if (!str->isRope()) { + NonRopeTypedMarker(rt, str); + return; + } + + /* + * This function must not fail, so a simple stack-based traversal must not + * be used (since it may oom if the stack grows large). Instead, strings + * are temporarily mutated to embed parent pointers as they are traversed. + * This algorithm is homomorphic to JSString::flatten. + */ + JSString *parent = NULL; + first_visit_node: { + JS_ASSERT(strComp == str->asCell()->compartment() || str->asCell()->compartment() == rt->atomsCompartment); + JS_ASSERT(!JSString::isStatic(str)); + if (!str->asCell()->markIfUnmarked()) + goto finish_node; + JSString *left = str->ropeLeft(); + if (left->isRope()) { + JS_ASSERT(!Tagged(str->u.left) && !Tagged(str->s.right)); + str->u.left = Tag(parent); + parent = str; + str = left; + goto first_visit_node; + } + JS_ASSERT_IF(!JSString::isStatic(left), + strComp == left->asCell()->compartment() + || left->asCell()->compartment() == rt->atomsCompartment); + NonRopeTypedMarker(rt, left); + } + visit_right_child: { + JSString *right = str->ropeRight(); + if (right->isRope()) { + JS_ASSERT(!Tagged(str->u.left) && !Tagged(str->s.right)); + str->s.right = Tag(parent); + parent = str; + str = right; + goto first_visit_node; + } + JS_ASSERT_IF(!JSString::isStatic(right), + strComp == right->asCell()->compartment() + || right->asCell()->compartment() == rt->atomsCompartment); + NonRopeTypedMarker(rt, right); + } + finish_node: { + if (!parent) + return; + if (Tagged(parent->u.left)) { + JS_ASSERT(!Tagged(parent->s.right)); + JSString *nextParent = Untag(parent->u.left); + parent->u.left = str; + str = parent; + parent = nextParent; + goto visit_right_child; + } + JS_ASSERT(Tagged(parent->s.right)); + JSString *nextParent = Untag(parent->s.right); + parent->s.right = str; + str = parent; + parent = nextParent; + goto finish_node; + } +} + +static inline void +MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name) +{ + for (uint32 i = 0; i < len; i++) { + if (JSAtom *atom = vec[i]) { + JS_SET_TRACING_INDEX(trc, name, i); + JSString *str = ATOM_TO_STRING(atom); + if (!JSString::isStatic(str)) + Mark(trc, str); + } + } +} + +static inline void +MarkObjectRange(JSTracer *trc, size_t len, JSObject **vec, const char *name) +{ + for (uint32 i = 0; i < len; i++) { + if (JSObject *obj = vec[i]) { + JS_SET_TRACING_INDEX(trc, name, i); + Mark(trc, obj); + } + } +} + +static inline void +MarkId(JSTracer *trc, jsid id) +{ + if (JSID_IS_STRING(id)) { + JSString *str = JSID_TO_STRING(id); + if (!JSString::isStatic(str)) + Mark(trc, str); + } + else if (JS_UNLIKELY(JSID_IS_OBJECT(id))) + Mark(trc, JSID_TO_OBJECT(id)); +} + +static inline void +MarkId(JSTracer *trc, jsid id, const char *name) +{ + JS_SET_TRACING_NAME(trc, name); + MarkId(trc, id); +} + +static inline void +MarkIdRange(JSTracer *trc, jsid *beg, jsid *end, const char *name) +{ + for (jsid *idp = beg; idp != end; ++idp) { + JS_SET_TRACING_INDEX(trc, name, (idp - beg)); + MarkId(trc, *idp); + } +} + +static inline void +MarkIdRange(JSTracer *trc, size_t len, jsid *vec, const char *name) +{ + MarkIdRange(trc, vec, vec + len, name); +} + +static inline void +MarkKind(JSTracer *trc, void *thing, uint32 kind) +{ + JS_ASSERT(thing); + JS_ASSERT(kind == GetGCThingTraceKind(thing)); + switch (kind) { + case JSTRACE_OBJECT: + Mark(trc, reinterpret_cast(thing)); + break; + case JSTRACE_STRING: + MarkString(trc, reinterpret_cast(thing)); + break; +#if JS_HAS_XML_SUPPORT + case JSTRACE_XML: + Mark(trc, reinterpret_cast(thing)); + break; +#endif + default: + JS_ASSERT(false); + } +} + +/* N.B. Assumes JS_SET_TRACING_NAME/INDEX has already been called. */ +static inline void +MarkValueRaw(JSTracer *trc, const js::Value &v) +{ + if (v.isMarkable()) { + JS_ASSERT(v.toGCThing()); + return MarkKind(trc, v.toGCThing(), v.gcKind()); + } +} + +static inline void +MarkValue(JSTracer *trc, const js::Value &v, const char *name) +{ + JS_SET_TRACING_NAME(trc, name); + MarkValueRaw(trc, v); +} + +static inline void +MarkValueRange(JSTracer *trc, Value *beg, Value *end, const char *name) +{ + for (Value *vp = beg; vp < end; ++vp) { + JS_SET_TRACING_INDEX(trc, name, vp - beg); + MarkValueRaw(trc, *vp); + } +} + +static inline void +MarkValueRange(JSTracer *trc, size_t len, Value *vec, const char *name) +{ + MarkValueRange(trc, vec, vec + len, name); +} + +static inline void +MarkShapeRange(JSTracer *trc, const Shape **beg, const Shape **end, const char *name) +{ + for (const Shape **sp = beg; sp < end; ++sp) { + JS_SET_TRACING_INDEX(trc, name, sp - beg); + (*sp)->trace(trc); + } +} + +static inline void +MarkShapeRange(JSTracer *trc, size_t len, const Shape **vec, const char *name) +{ + MarkShapeRange(trc, vec, vec + len, name); +} + +/* N.B. Assumes JS_SET_TRACING_NAME/INDEX has already been called. */ +static inline void +MarkGCThing(JSTracer *trc, void *thing, uint32 kind) +{ + if (!thing) + return; + + MarkKind(trc, thing, kind); +} + +static inline void +MarkGCThing(JSTracer *trc, void *thing) +{ + if (!thing) + return; + MarkKind(trc, thing, GetGCThingTraceKind(thing)); +} + +static inline void +MarkGCThing(JSTracer *trc, void *thing, const char *name) +{ + JS_SET_TRACING_NAME(trc, name); + MarkGCThing(trc, thing); +} + +static inline void +MarkGCThing(JSTracer *trc, void *thing, const char *name, size_t index) +{ + JS_SET_TRACING_INDEX(trc, name, index); + MarkGCThing(trc, thing); +} + +static inline void +Mark(JSTracer *trc, void *thing, uint32 kind, const char *name) +{ + JS_ASSERT(thing); + JS_SET_TRACING_NAME(trc, name); + MarkKind(trc, thing, kind); +} + +}} + +#endif /* jsgcinlines_h___ */ diff --git a/js/src/jsgcstats.cpp b/js/src/jsgcstats.cpp new file mode 100644 index 0000000..0fd0e42 --- /dev/null +++ b/js/src/jsgcstats.cpp @@ -0,0 +1,456 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * June 30, 2010 + * + * The Initial Developer of the Original Code is + * the Mozilla Corporation. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jstypes.h" +#include "jscntxt.h" +#include "jsgcstats.h" +#include "jsgc.h" +#include "jsxml.h" +#include "jsbuiltins.h" +#include "jscompartment.h" + +using namespace js; +using namespace js::gc; + +#define UL(x) ((unsigned long)(x)) +#define PERCENT(x,y) (100.0 * (double) (x) / (double) (y)) + +namespace js { +namespace gc { + +#if defined(JS_DUMP_CONSERVATIVE_GC_ROOTS) || defined(JS_GCMETER) + +void +ConservativeGCStats::dump(FILE *fp) +{ + size_t words = 0; + for (size_t i = 0; i != JS_ARRAY_LENGTH(counter); ++i) + words += counter[i]; + +#define ULSTAT(x) ((unsigned long)(x)) + fprintf(fp, "CONSERVATIVE STACK SCANNING:\n"); + fprintf(fp, " number of stack words: %lu\n", ULSTAT(words)); + fprintf(fp, " excluded, low bit set: %lu\n", ULSTAT(counter[CGCT_LOWBITSET])); + fprintf(fp, " not withing a chunk: %lu\n", ULSTAT(counter[CGCT_NOTCHUNK])); + fprintf(fp, " not within arena range: %lu\n", ULSTAT(counter[CGCT_NOTARENA])); + fprintf(fp, " points to free arena: %lu\n", ULSTAT(counter[CGCT_FREEARENA])); + fprintf(fp, " excluded, wrong tag: %lu\n", ULSTAT(counter[CGCT_WRONGTAG])); + fprintf(fp, " excluded, not live: %lu\n", ULSTAT(counter[CGCT_NOTLIVE])); + fprintf(fp, " valid GC things: %lu\n", ULSTAT(counter[CGCT_VALID])); + fprintf(fp, " valid but not aligned: %lu\n", ULSTAT(counter[CGCT_VALIDWITHOFFSET])); +#undef ULSTAT +} +#endif + +#ifdef JS_GCMETER +void +UpdateCompartmentStats(JSCompartment *comp, unsigned thingKind, uint32 nlivearenas, + uint32 nkilledArenas, uint32 nthings) +{ + size_t narenas = 0; + JSGCArenaStats *compSt = &comp->compartmentStats[thingKind]; + JSGCArenaStats *globSt = &comp->rt->globalArenaStats[thingKind]; + narenas = nlivearenas + nkilledArenas; + JS_ASSERT(narenas >= compSt->livearenas); + + compSt->newarenas = narenas - compSt->livearenas; + compSt->narenas = narenas; + compSt->livearenas = nlivearenas; + if (compSt->maxarenas < narenas) + compSt->maxarenas = narenas; + compSt->totalarenas += narenas; + + compSt->nthings = nthings; + if (compSt->maxthings < nthings) + compSt->maxthings = nthings; + compSt->totalthings += nthings; + globSt->newarenas += compSt->newarenas; + globSt->narenas += narenas; + globSt->livearenas += compSt->livearenas; + globSt->totalarenas += compSt->totalarenas; + globSt->nthings += compSt->nthings; + globSt->totalthings += compSt->totalthings; + if (globSt->maxarenas < compSt->maxarenas) + globSt->maxarenas = compSt->maxarenas; + if (globSt->maxthings < compSt->maxthings) + globSt->maxthings = compSt->maxthings; +} + +static const char *const GC_ARENA_NAMES[] = { + "object_0", + "object_2", + "object_4", + "object_8", + "object_12", + "object_16", + "function", +#if JS_HAS_XML_SUPPORT + "xml", +#endif + "short string", + "string", + "external_string", +}; +JS_STATIC_ASSERT(JS_ARRAY_LENGTH(GC_ARENA_NAMES) == FINALIZE_LIMIT); + +template +static inline void +GetSizeAndThings(size_t &thingSize, size_t &thingsPerArena) +{ + thingSize = sizeof(T); + thingsPerArena = Arena::ThingsPerArena; +} + +#if defined JS_DUMP_CONSERVATIVE_GC_ROOTS +void * +GetAlignedThing(void *thing, int thingKind) +{ + Cell *cell = (Cell *)thing; + switch (thingKind) { + case FINALIZE_OBJECT0: + return (void *)GetArena(cell)->getAlignedThing(thing); + case FINALIZE_OBJECT2: + return (void *)GetArena(cell)->getAlignedThing(thing); + case FINALIZE_OBJECT4: + return (void *)GetArena(cell)->getAlignedThing(thing); + case FINALIZE_OBJECT8: + return (void *)GetArena(cell)->getAlignedThing(thing); + case FINALIZE_OBJECT12: + return (void *)GetArena(cell)->getAlignedThing(thing); + case FINALIZE_OBJECT16: + return (void *)GetArena(cell)->getAlignedThing(thing); + case FINALIZE_STRING: + return (void *)GetArena(cell)->getAlignedThing(thing); + case FINALIZE_EXTERNAL_STRING: + return (void *)GetArena(cell)->getAlignedThing(thing); + case FINALIZE_SHORT_STRING: + return (void *)GetArena(cell)->getAlignedThing(thing); + case FINALIZE_FUNCTION: + return (void *)GetArena(cell)->getAlignedThing(thing); +#if JS_HAS_XML_SUPPORT + case FINALIZE_XML: + return (void *)GetArena(cell)->getAlignedThing(thing); +#endif + default: + JS_ASSERT(false); + return NULL; + } +} +#endif + +void GetSizeAndThingsPerArena(int thingKind, size_t &thingSize, size_t &thingsPerArena) +{ + switch (thingKind) { + case FINALIZE_OBJECT0: + GetSizeAndThings(thingSize, thingsPerArena); + break; + case FINALIZE_OBJECT2: + GetSizeAndThings(thingSize, thingsPerArena); + break; + case FINALIZE_OBJECT4: + GetSizeAndThings(thingSize, thingsPerArena); + break; + case FINALIZE_OBJECT8: + GetSizeAndThings(thingSize, thingsPerArena); + break; + case FINALIZE_OBJECT12: + GetSizeAndThings(thingSize, thingsPerArena); + break; + case FINALIZE_OBJECT16: + GetSizeAndThings(thingSize, thingsPerArena); + break; + case FINALIZE_EXTERNAL_STRING: + case FINALIZE_STRING: + GetSizeAndThings(thingSize, thingsPerArena); + break; + case FINALIZE_SHORT_STRING: + GetSizeAndThings(thingSize, thingsPerArena); + break; + case FINALIZE_FUNCTION: + GetSizeAndThings(thingSize, thingsPerArena); + break; +#if JS_HAS_XML_SUPPORT + case FINALIZE_XML: + GetSizeAndThings(thingSize, thingsPerArena); + break; +#endif + default: + JS_ASSERT(false); + } +} + +void +DumpArenaStats(JSGCArenaStats *stp, FILE *fp) +{ + size_t sumArenas = 0, sumTotalArenas = 0, sumThings =0, sumMaxThings = 0; + size_t sumThingSize = 0, sumTotalThingSize = 0, sumArenaCapacity = 0; + size_t sumTotalArenaCapacity = 0, sumAlloc = 0, sumLocalAlloc = 0; + + for (int i = 0; i < (int) FINALIZE_LIMIT; i++) { + JSGCArenaStats *st = &stp[i]; + if (st->maxarenas == 0) + continue; + size_t thingSize = 0, thingsPerArena = 0; + GetSizeAndThingsPerArena(i, thingSize, thingsPerArena); + + fprintf(fp, "%s arenas (thing size %lu, %lu things per arena):\n", + GC_ARENA_NAMES[i], UL(thingSize), UL(thingsPerArena)); + fprintf(fp, " arenas before GC: %lu\n", UL(st->narenas)); + fprintf(fp, " arenas after GC: %lu (%.1f%%)\n", + UL(st->livearenas), PERCENT(st->livearenas, st->narenas)); + fprintf(fp, " max arenas: %lu\n", UL(st->maxarenas)); + fprintf(fp, " things: %lu\n", UL(st->nthings)); + fprintf(fp, " GC cell utilization: %.1f%%\n", + PERCENT(st->nthings, thingsPerArena * st->narenas)); + fprintf(fp, " average cell utilization: %.1f%%\n", + PERCENT(st->totalthings, thingsPerArena * st->totalarenas)); + fprintf(fp, " max things: %lu\n", UL(st->maxthings)); + fprintf(fp, " alloc attempts: %lu\n", UL(st->alloc)); + fprintf(fp, " alloc without locks: %lu (%.1f%%)\n", + UL(st->localalloc), PERCENT(st->localalloc, st->alloc)); + sumArenas += st->narenas; + sumTotalArenas += st->totalarenas; + sumThings += st->nthings; + sumMaxThings += st->maxthings; + sumThingSize += thingSize * st->nthings; + sumTotalThingSize += size_t(thingSize * st->totalthings); + sumArenaCapacity += thingSize * thingsPerArena * st->narenas; + sumTotalArenaCapacity += thingSize * thingsPerArena * st->totalarenas; + sumAlloc += st->alloc; + sumLocalAlloc += st->localalloc; + putc('\n', fp); + } + + fputs("Never used arenas:\n", fp); + for (int i = 0; i < (int) FINALIZE_LIMIT; i++) { + JSGCArenaStats *st = &stp[i]; + if (st->maxarenas != 0) + continue; + fprintf(fp, "%s\n", GC_ARENA_NAMES[i]); + } + fprintf(fp, "\nTOTAL STATS:\n"); + fprintf(fp, " total GC arenas: %lu\n", UL(sumArenas)); + fprintf(fp, " total GC things: %lu\n", UL(sumThings)); + fprintf(fp, " max total GC things: %lu\n", UL(sumMaxThings)); + fprintf(fp, " GC cell utilization: %.1f%%\n", + PERCENT(sumThingSize, sumArenaCapacity)); + fprintf(fp, " average cell utilization: %.1f%%\n", + PERCENT(sumTotalThingSize, sumTotalArenaCapacity)); + fprintf(fp, " alloc attempts: %lu\n", UL(sumAlloc)); + fprintf(fp, " alloc without locks: %lu (%.1f%%)\n", + UL(sumLocalAlloc), PERCENT(sumLocalAlloc, sumAlloc)); +} + +void +DumpCompartmentStats(JSCompartment *comp, FILE *fp) +{ + if (comp->rt->atomsCompartment == comp) + fprintf(fp, "\n**** AtomsCompartment Allocation Statistics: %p ****\n\n", (void *) comp); + else + fprintf(fp, "\n**** Compartment Allocation Statistics: %p ****\n\n", (void *) comp); + + DumpArenaStats(&comp->compartmentStats[0], fp); +} + +#endif + +} //gc +} //js + +#ifdef JS_GCMETER + +JS_FRIEND_API(void) +js_DumpGCStats(JSRuntime *rt, FILE *fp) +{ +#define ULSTAT(x) UL(rt->gcStats.x) + if (JS_WANT_GC_METER_PRINT) { + fprintf(fp, "\n**** Global Arena Allocation Statistics: ****\n"); + DumpArenaStats(&rt->globalArenaStats[0], fp); + fprintf(fp, " bytes allocated: %lu\n", UL(rt->gcBytes)); + fprintf(fp, " allocation failures: %lu\n", ULSTAT(fail)); + fprintf(fp, " last ditch GC runs: %lu\n", ULSTAT(lastditch)); + fprintf(fp, " valid lock calls: %lu\n", ULSTAT(lock)); + fprintf(fp, " valid unlock calls: %lu\n", ULSTAT(unlock)); + fprintf(fp, " delayed tracing calls: %lu\n", ULSTAT(unmarked)); +#ifdef DEBUG + fprintf(fp, " max trace later count: %lu\n", ULSTAT(maxunmarked)); +#endif + fprintf(fp, "potentially useful GC calls: %lu\n", ULSTAT(poke)); + fprintf(fp, " thing arenas freed so far: %lu\n\n", ULSTAT(afree)); + } + + if (JS_WANT_GC_PER_COMPARTMENT_PRINT) + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) + DumpCompartmentStats(*c, fp); + PodZero(&rt->globalArenaStats); + if (JS_WANT_CONSERVATIVE_GC_PRINT) + rt->gcStats.conservative.dump(fp); +#undef ULSTAT +} +#endif + +namespace js { + +#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS +void +GCMarker::dumpConservativeRoots() +{ + if (!conservativeDumpFileName) + return; + + FILE *fp; + if (!strcmp(conservativeDumpFileName, "stdout")) { + fp = stdout; + } else if (!strcmp(conservativeDumpFileName, "stderr")) { + fp = stderr; + } else if (!(fp = fopen(conservativeDumpFileName, "aw"))) { + fprintf(stderr, + "Warning: cannot open %s to dump the conservative roots\n", + conservativeDumpFileName); + return; + } + + conservativeStats.dump(fp); + + for (ConservativeRoot *i = conservativeRoots.begin(); + i != conservativeRoots.end(); + ++i) { + fprintf(fp, " %p: ", i->thing); + switch (GetFinalizableTraceKind(i->thingKind)) { + default: + JS_NOT_REACHED("Unknown trace kind"); + + case JSTRACE_OBJECT: { + JSObject *obj = (JSObject *) i->thing; + fprintf(fp, "object %s", obj->getClass()->name); + break; + } + case JSTRACE_STRING: { + JSString *str = (JSString *) i->thing; + if (str->isLinear()) { + char buf[50]; + PutEscapedString(buf, sizeof buf, str->assertIsLinear(), '"'); + fprintf(fp, "string %s", buf); + } else { + fprintf(fp, "rope: length %d", (int)str->length()); + } + break; + } +# if JS_HAS_XML_SUPPORT + case JSTRACE_XML: { + JSXML *xml = (JSXML *) i->thing; + fprintf(fp, "xml %u", (unsigned)xml->xml_class); + break; + } +# endif + } + fputc('\n', fp); + } + fputc('\n', fp); + + if (fp != stdout && fp != stderr) + fclose(fp); +} +#endif /* JS_DUMP_CONSERVATIVE_GC_ROOTS */ + +#ifdef MOZ_GCTIMER + +jsrefcount newChunkCount = 0; +jsrefcount destroyChunkCount = 0; + +GCTimer::GCTimer() { + getFirstEnter(); + memset(this, 0, sizeof(GCTimer)); + enter = rdtsc(); +} + +uint64 +GCTimer::getFirstEnter() { + static uint64 firstEnter = rdtsc(); + return firstEnter; +} + +void +GCTimer::finish(bool lastGC) { + end = rdtsc(); + + if (startMark > 0) { + if (JS_WANT_GC_SUITE_PRINT) { + fprintf(stderr, "%f %f %f\n", + (double)(end - enter) / 1e6, + (double)(startSweep - startMark) / 1e6, + (double)(sweepDestroyEnd - startSweep) / 1e6); + } else { + static FILE *gcFile; + + if (!gcFile) { + gcFile = fopen("gcTimer.dat", "a"); + + fprintf(gcFile, " AppTime, Total, Mark, Sweep, FinObj,"); + fprintf(gcFile, " FinStr, SwShapes, Destroy, +Chunks, -Chunks\n"); + } + JS_ASSERT(gcFile); + fprintf(gcFile, "%12.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %8.1f, %6.1f, ", + (double)(enter - getFirstEnter()) / 1e6, + (double)(end - enter) / 1e6, + (double)(startSweep - startMark) / 1e6, + (double)(sweepDestroyEnd - startSweep) / 1e6, + (double)(sweepObjectEnd - startSweep) / 1e6, + (double)(sweepStringEnd - sweepObjectEnd) / 1e6, + (double)(sweepShapeEnd - sweepStringEnd) / 1e6, + (double)(sweepDestroyEnd - sweepShapeEnd) / 1e6); + fprintf(gcFile, "%7d, %7d \n", newChunkCount, + destroyChunkCount); + fflush(gcFile); + + if (lastGC) { + fclose(gcFile); + gcFile = NULL; + } + } + } + newChunkCount = 0; + destroyChunkCount = 0; +} + +#endif + +} //js + +#undef UL +#undef PERCENT diff --git a/js/src/jsgcstats.h b/js/src/jsgcstats.h new file mode 100644 index 0000000..8f3b623 --- /dev/null +++ b/js/src/jsgcstats.h @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * June 30, 2010 + * + * The Initial Developer of the Original Code is + * the Mozilla Corporation. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsgcstats_h___ +#define jsgcstats_h___ + +#if !defined JS_DUMP_CONSERVATIVE_GC_ROOTS && defined DEBUG +# define JS_DUMP_CONSERVATIVE_GC_ROOTS 1 +#endif + +/* Define JS_GCMETER here if wanted */ +#if defined JS_GCMETER +const bool JS_WANT_GC_METER_PRINT = true; +const bool JS_WANT_GC_PER_COMPARTMENT_PRINT = true; +const bool JS_WANT_CONSERVATIVE_GC_PRINT = true; +#elif defined DEBUG +# define JS_GCMETER 1 +const bool JS_WANT_GC_METER_PRINT = false; +const bool JS_WANT_GC_PER_COMPARTMENT_PRINT = false; +const bool JS_WANT_CONSERVATIVE_GC_PRINT = false; +#endif + +namespace js { +namespace gc { +/* + * The conservative GC test for a word shows that it is either a valid GC + * thing or is not for one of the following reasons. + */ +enum ConservativeGCTest { + CGCT_VALID, + CGCT_VALIDWITHOFFSET, /* points within an object */ + CGCT_LOWBITSET, /* excluded because one of the low bits was set */ + CGCT_NOTARENA, /* not within arena range in a chunk */ + CGCT_NOTCHUNK, /* not within a valid chunk */ + CGCT_FREEARENA, /* within arena containing only free things */ + CGCT_WRONGTAG, /* tagged pointer but wrong type */ + CGCT_NOTLIVE, /* gcthing is not allocated */ + CGCT_END +}; + +struct ConservativeGCStats { + uint32 counter[gc::CGCT_END]; /* ConservativeGCTest classification + counters */ + + void add(const ConservativeGCStats &another) { + for (size_t i = 0; i != JS_ARRAY_LENGTH(counter); ++i) + counter[i] += another.counter[i]; + } + + void dump(FILE *fp); +}; + +#ifdef JS_GCMETER +struct JSGCArenaStats { + uint32 alloc; /* allocation attempts */ + uint32 localalloc; /* allocations from local lists */ + uint32 nthings; /* live GC things */ + uint32 maxthings; /* maximum of live GC cells */ + double totalthings; /* live GC things the GC scanned so far */ + uint32 narenas; /* number of arena in list before the GC */ + uint32 newarenas; /* new arenas allocated before the last GC */ + uint32 livearenas; /* number of live arenas after the last GC */ + uint32 maxarenas; /* maximum of allocated arenas */ + uint32 totalarenas; /* total number of arenas with live things that + GC scanned so far */ +}; +#endif + +#ifdef JS_GCMETER + +struct JSGCStats { + uint32 lock; /* valid lock calls */ + uint32 unlock; /* valid unlock calls */ + uint32 unmarked; /* number of times marking of GC thing's children were + delayed due to a low C stack */ + uint32 lastditch; /* number of times the last ditch GC run */ + uint32 fail; /* allocation failures */ +#ifdef DEBUG + uint32 maxunmarked;/* maximum number of things with children to mark + later */ +#endif + uint32 poke; /* number of potentially useful GC calls */ + uint32 afree; /* thing arenas freed so far */ + uint32 nallarenas; /* number of all allocated arenas */ + uint32 maxnallarenas; /* maximum number of all allocated arenas */ + uint32 nchunks; /* number of allocated chunks */ + uint32 maxnchunks; /* maximum number of allocated chunks */ + + ConservativeGCStats conservative; +}; + +extern void +UpdateCompartmentStats(JSCompartment *comp, unsigned thingKind, uint32 nlivearenas, + uint32 nkilledArenas, uint32 nthings); +#endif /* JS_GCMETER */ + +#if defined JS_DUMP_CONSERVATIVE_GC_ROOTS +void *GetAlignedThing(void *thing, int thingKind); +#endif + +} //gc + +#ifdef MOZ_GCTIMER + +const bool JS_WANT_GC_SUITE_PRINT = false; //false for gnuplot output + +extern jsrefcount newChunkCount; +extern jsrefcount destroyChunkCount; + +struct GCTimer { + uint64 enter; + uint64 startMark; + uint64 startSweep; + uint64 sweepObjectEnd; + uint64 sweepStringEnd; + uint64 sweepShapeEnd; + uint64 sweepDestroyEnd; + uint64 end; + + GCTimer(); + + uint64 getFirstEnter(); + + void finish(bool lastGC); +}; + +# define GCTIMER_PARAM , GCTimer &gcTimer +# define GCTIMER_ARG , gcTimer +# define TIMESTAMP(x) (gcTimer.x = rdtsc()) +# define GCTIMER_BEGIN() GCTimer gcTimer +# define GCTIMER_END(last) (gcTimer.finish(last)) +#else +# define GCTIMER_PARAM +# define GCTIMER_ARG +# define TIMESTAMP(x) ((void) 0) +# define GCTIMER_BEGIN() ((void) 0) +# define GCTIMER_END(last) ((void) 0) +#endif + +} //js + +extern JS_FRIEND_API(void) +js_DumpGCStats(JSRuntime *rt, FILE *fp); + +#endif /* jsgcstats_h__ */ diff --git a/js/src/jshash.cpp b/js/src/jshash.cpp new file mode 100644 index 0000000..3d546e3 --- /dev/null +++ b/js/src/jshash.cpp @@ -0,0 +1,477 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * PR hash table package. + */ +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsbit.h" +#include "jsutil.h" +#include "jshash.h" + +/* Compute the number of buckets in ht */ +#define NBUCKETS(ht) JS_BIT(JS_HASH_BITS - (ht)->shift) + +/* The smallest table has 16 buckets */ +#define MINBUCKETSLOG2 4 +#define MINBUCKETS JS_BIT(MINBUCKETSLOG2) + +/* Compute the maximum entries given n buckets that we will tolerate, ~90% */ +#define OVERLOADED(n) ((n) - ((n) >> 3)) + +/* Compute the number of entries below which we shrink the table by half */ +#define UNDERLOADED(n) (((n) > MINBUCKETS) ? ((n) >> 2) : 0) + +/* +** Stubs for default hash allocator ops. +*/ +static void * +DefaultAllocTable(void *pool, size_t size) +{ + return js_malloc(size); +} + +static void +DefaultFreeTable(void *pool, void *item, size_t size) +{ + js_free(item); +} + +static JSHashEntry * +DefaultAllocEntry(void *pool, const void *key) +{ + return (JSHashEntry*) js_malloc(sizeof(JSHashEntry)); +} + +static void +DefaultFreeEntry(void *pool, JSHashEntry *he, uintN flag) +{ + if (flag == HT_FREE_ENTRY) + js_free(he); +} + +static JSHashAllocOps defaultHashAllocOps = { + DefaultAllocTable, DefaultFreeTable, + DefaultAllocEntry, DefaultFreeEntry +}; + +JS_PUBLIC_API(JSHashTable *) +JS_NewHashTable(uint32 n, JSHashFunction keyHash, + JSHashComparator keyCompare, JSHashComparator valueCompare, + JSHashAllocOps *allocOps, void *allocPriv) +{ + JSHashTable *ht; + size_t nb; + + if (n <= MINBUCKETS) { + n = MINBUCKETSLOG2; + } else { + n = JS_CeilingLog2(n); + if ((int32)n < 0) + return NULL; + } + + if (!allocOps) allocOps = &defaultHashAllocOps; + + ht = (JSHashTable*) allocOps->allocTable(allocPriv, sizeof *ht); + if (!ht) + return NULL; + memset(ht, 0, sizeof *ht); + ht->shift = JS_HASH_BITS - n; + n = JS_BIT(n); + nb = n * sizeof(JSHashEntry *); + ht->buckets = (JSHashEntry**) allocOps->allocTable(allocPriv, nb); + if (!ht->buckets) { + allocOps->freeTable(allocPriv, ht, nb); + return NULL; + } + memset(ht->buckets, 0, nb); + + ht->keyHash = keyHash; + ht->keyCompare = keyCompare; + ht->valueCompare = valueCompare; + ht->allocOps = allocOps; + ht->allocPriv = allocPriv; + return ht; +} + +JS_PUBLIC_API(void) +JS_HashTableDestroy(JSHashTable *ht) +{ + uint32 i, n; + JSHashEntry *he, **hep; + JSHashAllocOps *allocOps = ht->allocOps; + void *allocPriv = ht->allocPriv; + + n = NBUCKETS(ht); + for (i = 0; i < n; i++) { + hep = &ht->buckets[i]; + while ((he = *hep) != NULL) { + *hep = he->next; + allocOps->freeEntry(allocPriv, he, HT_FREE_ENTRY); + } + } +#ifdef DEBUG + memset(ht->buckets, 0xDB, n * sizeof ht->buckets[0]); +#endif + allocOps->freeTable(allocPriv, ht->buckets, n * sizeof ht->buckets[0]); +#ifdef DEBUG + memset(ht, 0xDB, sizeof *ht); +#endif + allocOps->freeTable(allocPriv, ht, sizeof *ht); +} + +/* + * Multiplicative hash, from Knuth 6.4. + */ +#define BUCKET_HEAD(ht, keyHash) \ + (&(ht)->buckets[((keyHash) * JS_GOLDEN_RATIO) >> (ht)->shift]) + +JS_PUBLIC_API(JSHashEntry **) +JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key) +{ + JSHashEntry *he, **hep, **hep0; + +#ifdef JS_HASHMETER + ht->nlookups++; +#endif + hep = hep0 = BUCKET_HEAD(ht, keyHash); + while ((he = *hep) != NULL) { + if (he->keyHash == keyHash && ht->keyCompare(key, he->key)) { + /* Move to front of chain if not already there */ + if (hep != hep0) { + *hep = he->next; + he->next = *hep0; + *hep0 = he; + } + return hep0; + } + hep = &he->next; +#ifdef JS_HASHMETER + ht->nsteps++; +#endif + } + return hep; +} + +static JSBool +Resize(JSHashTable *ht, uint32 newshift) +{ + size_t nb, nentries, i; + JSHashEntry **oldbuckets, *he, *next, **hep; + size_t nold = NBUCKETS(ht); + + JS_ASSERT(newshift < JS_HASH_BITS); + + nb = (size_t)1 << (JS_HASH_BITS - newshift); + + /* Integer overflow protection. */ + if (nb > (size_t)-1 / sizeof(JSHashEntry*)) + return JS_FALSE; + nb *= sizeof(JSHashEntry*); + + oldbuckets = ht->buckets; + ht->buckets = (JSHashEntry**)ht->allocOps->allocTable(ht->allocPriv, nb); + if (!ht->buckets) { + ht->buckets = oldbuckets; + return JS_FALSE; + } + memset(ht->buckets, 0, nb); + + ht->shift = newshift; + nentries = ht->nentries; + + for (i = 0; nentries != 0; i++) { + for (he = oldbuckets[i]; he; he = next) { + JS_ASSERT(nentries != 0); + --nentries; + next = he->next; + hep = BUCKET_HEAD(ht, he->keyHash); + + /* + * We do not require unique entries, instead appending he to the + * chain starting at hep. + */ + while (*hep) + hep = &(*hep)->next; + he->next = NULL; + *hep = he; + } + } +#ifdef DEBUG + memset(oldbuckets, 0xDB, nold * sizeof oldbuckets[0]); +#endif + ht->allocOps->freeTable(ht->allocPriv, oldbuckets, + nold * sizeof oldbuckets[0]); + return JS_TRUE; +} + +JS_PUBLIC_API(JSHashEntry *) +JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **&hep, + JSHashNumber keyHash, const void *key, void *value) +{ + uint32 n; + JSHashEntry *he; + + /* Grow the table if it is overloaded */ + n = NBUCKETS(ht); + if (ht->nentries >= OVERLOADED(n)) { + if (!Resize(ht, ht->shift - 1)) + return NULL; +#ifdef JS_HASHMETER + ht->ngrows++; +#endif + hep = JS_HashTableRawLookup(ht, keyHash, key); + } + + /* Make a new key value entry */ + he = ht->allocOps->allocEntry(ht->allocPriv, key); + if (!he) + return NULL; + he->keyHash = keyHash; + he->key = key; + he->value = value; + he->next = *hep; + *hep = he; + ht->nentries++; + return he; +} + +JS_PUBLIC_API(JSHashEntry *) +JS_HashTableAdd(JSHashTable *ht, const void *key, void *value) +{ + JSHashNumber keyHash; + JSHashEntry *he, **hep; + + keyHash = ht->keyHash(key); + hep = JS_HashTableRawLookup(ht, keyHash, key); + if ((he = *hep) != NULL) { + /* Hit; see if values match */ + if (ht->valueCompare(he->value, value)) { + /* key,value pair is already present in table */ + return he; + } + if (he->value) + ht->allocOps->freeEntry(ht->allocPriv, he, HT_FREE_VALUE); + he->value = value; + return he; + } + return JS_HashTableRawAdd(ht, hep, keyHash, key, value); +} + +JS_PUBLIC_API(void) +JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he) +{ + uint32 n; + + *hep = he->next; + ht->allocOps->freeEntry(ht->allocPriv, he, HT_FREE_ENTRY); + + /* Shrink table if it's underloaded */ + n = NBUCKETS(ht); + if (--ht->nentries < UNDERLOADED(n)) { + Resize(ht, ht->shift + 1); +#ifdef JS_HASHMETER + ht->nshrinks++; +#endif + } +} + +JS_PUBLIC_API(JSBool) +JS_HashTableRemove(JSHashTable *ht, const void *key) +{ + JSHashNumber keyHash; + JSHashEntry *he, **hep; + + keyHash = ht->keyHash(key); + hep = JS_HashTableRawLookup(ht, keyHash, key); + if ((he = *hep) == NULL) + return JS_FALSE; + + /* Hit; remove element */ + JS_HashTableRawRemove(ht, hep, he); + return JS_TRUE; +} + +JS_PUBLIC_API(void *) +JS_HashTableLookup(JSHashTable *ht, const void *key) +{ + JSHashNumber keyHash; + JSHashEntry *he, **hep; + + keyHash = ht->keyHash(key); + hep = JS_HashTableRawLookup(ht, keyHash, key); + if ((he = *hep) != NULL) { + return he->value; + } + return NULL; +} + +/* +** Iterate over the entries in the hash table calling func for each +** entry found. Stop if "f" says to (return value & JS_ENUMERATE_STOP). +** Return a count of the number of elements scanned. +*/ +JS_PUBLIC_API(int) +JS_HashTableEnumerateEntries(JSHashTable *ht, JSHashEnumerator f, void *arg) +{ + JSHashEntry *he, **hep, **bucket; + uint32 nlimit, n, nbuckets, newlog2; + int rv; + + nlimit = ht->nentries; + n = 0; + for (bucket = ht->buckets; n != nlimit; ++bucket) { + hep = bucket; + while ((he = *hep) != NULL) { + JS_ASSERT(n < nlimit); + rv = f(he, n, arg); + n++; + if (rv & HT_ENUMERATE_REMOVE) { + *hep = he->next; + ht->allocOps->freeEntry(ht->allocPriv, he, HT_FREE_ENTRY); + --ht->nentries; + } else { + hep = &he->next; + } + if (rv & HT_ENUMERATE_STOP) { + goto out; + } + } + } + +out: + /* Shrink table if removal of entries made it underloaded */ + if (ht->nentries != nlimit) { + JS_ASSERT(ht->nentries < nlimit); + nbuckets = NBUCKETS(ht); + if (MINBUCKETS < nbuckets && ht->nentries < UNDERLOADED(nbuckets)) { + newlog2 = JS_CeilingLog2(ht->nentries); + if (newlog2 < MINBUCKETSLOG2) + newlog2 = MINBUCKETSLOG2; + + /* Check that we really shrink the table. */ + JS_ASSERT(JS_HASH_BITS - ht->shift > newlog2); + Resize(ht, JS_HASH_BITS - newlog2); + } + } + return (int)n; +} + +#ifdef JS_HASHMETER +#include + +JS_PUBLIC_API(void) +JS_HashTableDumpMeter(JSHashTable *ht, JSHashEnumerator dump, FILE *fp) +{ + double sqsum, mean, sigma; + uint32 nchains, nbuckets; + uint32 i, n, maxChain, maxChainLen; + JSHashEntry *he; + + sqsum = 0; + nchains = 0; + maxChain = maxChainLen = 0; + nbuckets = NBUCKETS(ht); + for (i = 0; i < nbuckets; i++) { + he = ht->buckets[i]; + if (!he) + continue; + nchains++; + for (n = 0; he; he = he->next) + n++; + sqsum += n * n; + if (n > maxChainLen) { + maxChainLen = n; + maxChain = i; + } + } + + mean = JS_MeanAndStdDev(nchains, ht->nentries, sqsum, &sigma); + + fprintf(fp, "\nHash table statistics:\n"); + fprintf(fp, " number of lookups: %u\n", ht->nlookups); + fprintf(fp, " number of entries: %u\n", ht->nentries); + fprintf(fp, " number of grows: %u\n", ht->ngrows); + fprintf(fp, " number of shrinks: %u\n", ht->nshrinks); + fprintf(fp, " mean steps per hash: %g\n", (double)ht->nsteps + / ht->nlookups); + fprintf(fp, "mean hash chain length: %g\n", mean); + fprintf(fp, " standard deviation: %g\n", sigma); + fprintf(fp, " max hash chain length: %u\n", maxChainLen); + fprintf(fp, " max hash chain: [%u]\n", maxChain); + + for (he = ht->buckets[maxChain], i = 0; he; he = he->next, i++) + if (dump(he, i, fp) != HT_ENUMERATE_NEXT) + break; +} +#endif /* JS_HASHMETER */ + +JS_PUBLIC_API(int) +JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp) +{ + int count; + + count = JS_HashTableEnumerateEntries(ht, dump, fp); +#ifdef JS_HASHMETER + JS_HashTableDumpMeter(ht, dump, fp); +#endif + return count; +} + +JS_PUBLIC_API(JSHashNumber) +JS_HashString(const void *key) +{ + JSHashNumber h; + const unsigned char *s; + + h = 0; + for (s = (const unsigned char *)key; *s; s++) + h = JS_ROTATE_LEFT32(h, 4) ^ *s; + return h; +} + +JS_PUBLIC_API(int) +JS_CompareValues(const void *v1, const void *v2) +{ + return v1 == v2; +} diff --git a/js/src/jshash.h b/js/src/jshash.h new file mode 100644 index 0000000..a365a51 --- /dev/null +++ b/js/src/jshash.h @@ -0,0 +1,153 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jshash_h___ +#define jshash_h___ +/* + * API to portable hash table code. + */ +#include +#include +#include "jstypes.h" +#include "jscompat.h" + +JS_BEGIN_EXTERN_C + +typedef uint32 JSHashNumber; +typedef struct JSHashEntry JSHashEntry; +typedef struct JSHashTable JSHashTable; + +#define JS_HASH_BITS 32 +#define JS_GOLDEN_RATIO 0x9E3779B9U + +typedef JSHashNumber (* JSHashFunction)(const void *key); +typedef intN (* JSHashComparator)(const void *v1, const void *v2); +typedef intN (* JSHashEnumerator)(JSHashEntry *he, intN i, void *arg); + +/* Flag bits in JSHashEnumerator's return value */ +#define HT_ENUMERATE_NEXT 0 /* continue enumerating entries */ +#define HT_ENUMERATE_STOP 1 /* stop enumerating entries */ +#define HT_ENUMERATE_REMOVE 2 /* remove and free the current entry */ + +typedef struct JSHashAllocOps { + void * (*allocTable)(void *pool, size_t size); + void (*freeTable)(void *pool, void *item, size_t size); + JSHashEntry * (*allocEntry)(void *pool, const void *key); + void (*freeEntry)(void *pool, JSHashEntry *he, uintN flag); +} JSHashAllocOps; + +#define HT_FREE_VALUE 0 /* just free the entry's value */ +#define HT_FREE_ENTRY 1 /* free value and entire entry */ + +struct JSHashEntry { + JSHashEntry *next; /* hash chain linkage */ + JSHashNumber keyHash; /* key hash function result */ + const void *key; /* ptr to opaque key */ + void *value; /* ptr to opaque value */ +}; + +struct JSHashTable { + JSHashEntry **buckets; /* vector of hash buckets */ + uint32 nentries; /* number of entries in table */ + uint32 shift; /* multiplicative hash shift */ + JSHashFunction keyHash; /* key hash function */ + JSHashComparator keyCompare; /* key comparison function */ + JSHashComparator valueCompare; /* value comparison function */ + JSHashAllocOps *allocOps; /* allocation operations */ + void *allocPriv; /* allocation private data */ +#ifdef JS_HASHMETER + uint32 nlookups; /* total number of lookups */ + uint32 nsteps; /* number of hash chains traversed */ + uint32 ngrows; /* number of table expansions */ + uint32 nshrinks; /* number of table contractions */ +#endif +}; + +/* + * Create a new hash table. + * If allocOps is null, use default allocator ops built on top of malloc(). + */ +extern JS_PUBLIC_API(JSHashTable *) +JS_NewHashTable(uint32 n, JSHashFunction keyHash, + JSHashComparator keyCompare, JSHashComparator valueCompare, + JSHashAllocOps *allocOps, void *allocPriv); + +extern JS_PUBLIC_API(void) +JS_HashTableDestroy(JSHashTable *ht); + +/* Low level access methods */ +extern JS_PUBLIC_API(JSHashEntry **) +JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key); + +#ifdef __cplusplus +extern JS_PUBLIC_API(JSHashEntry *) +JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **&hep, JSHashNumber keyHash, + const void *key, void *value); +#endif + +extern JS_PUBLIC_API(void) +JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he); + +/* Higher level access methods */ +extern JS_PUBLIC_API(JSHashEntry *) +JS_HashTableAdd(JSHashTable *ht, const void *key, void *value); + +extern JS_PUBLIC_API(JSBool) +JS_HashTableRemove(JSHashTable *ht, const void *key); + +extern JS_PUBLIC_API(intN) +JS_HashTableEnumerateEntries(JSHashTable *ht, JSHashEnumerator f, void *arg); + +extern JS_PUBLIC_API(void *) +JS_HashTableLookup(JSHashTable *ht, const void *key); + +extern JS_PUBLIC_API(intN) +JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp); + +/* General-purpose C string hash function. */ +extern JS_PUBLIC_API(JSHashNumber) +JS_HashString(const void *key); + +/* Stub function just returns v1 == v2 */ +extern JS_PUBLIC_API(intN) +JS_CompareValues(const void *v1, const void *v2); + +JS_END_EXTERN_C + +#endif /* jshash_h___ */ diff --git a/js/src/jshashtable.h b/js/src/jshashtable.h new file mode 100644 index 0000000..c0969d0 --- /dev/null +++ b/js/src/jshashtable.h @@ -0,0 +1,1124 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * November 13, 2009. + * + * The Initial Developer of the Original Code is + * the Mozilla Corporation. + * + * Contributor(s): + * Brendan Eich (Original Author) + * Chris Waterson + * L. David Baron , Mozilla Corporation + * Luke Wagner + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jshashtable_h_ +#define jshashtable_h_ + +#include "jstl.h" + +namespace js { + +/* Integral types for all hash functions. */ +typedef uint32 HashNumber; + +namespace detail { + +/* Reusable implementation of HashMap and HashSet. */ +template +class HashTable : AllocPolicy +{ + typedef typename tl::StripConst::result NonConstT; + typedef typename HashPolicy::KeyType Key; + typedef typename HashPolicy::Lookup Lookup; + + /* + * T::operator= is a private operation for HashMap::Entry. HashMap::Entry + * makes HashTable a friend, but MSVC does not allow HashMap::Entry to make + * HashTable::Entry a friend. So do assignment here: + */ + static void assignT(NonConstT &dst, const T &src) { dst = src; } + + public: + class Entry { + HashNumber keyHash; + + public: + Entry() : keyHash(0), t() {} + void operator=(const Entry &rhs) { keyHash = rhs.keyHash; assignT(t, rhs.t); } + + NonConstT t; + + bool isFree() const { return keyHash == sFreeKey; } + void setFree() { keyHash = sFreeKey; assignT(t, T()); } + bool isRemoved() const { return keyHash == sRemovedKey; } + void setRemoved() { keyHash = sRemovedKey; assignT(t, T()); } + bool isLive() const { return isLiveHash(keyHash); } + void setLive(HashNumber hn) { JS_ASSERT(isLiveHash(hn)); keyHash = hn; } + + void setCollision() { JS_ASSERT(isLive()); keyHash |= sCollisionBit; } + void setCollision(HashNumber collisionBit) { + JS_ASSERT(isLive()); keyHash |= collisionBit; + } + void unsetCollision() { JS_ASSERT(isLive()); keyHash &= ~sCollisionBit; } + bool hasCollision() const { JS_ASSERT(isLive()); return keyHash & sCollisionBit; } + bool matchHash(HashNumber hn) { return (keyHash & ~sCollisionBit) == hn; } + HashNumber getKeyHash() const { JS_ASSERT(!hasCollision()); return keyHash; } + }; + + /* + * A nullable pointer to a hash table element. A Ptr |p| can be tested + * either explicitly |if (p.found()) p->...| or using boolean conversion + * |if (p) p->...|. Ptr objects must not be used after any mutating hash + * table operations unless |generation()| is tested. + */ + class Ptr + { + friend class HashTable; + typedef void (Ptr::* ConvertibleToBool)(); + void nonNull() {} + + Entry *entry; + + protected: + Ptr(Entry &entry) : entry(&entry) {} + + public: + bool found() const { return entry->isLive(); } + operator ConvertibleToBool() const { return found() ? &Ptr::nonNull : 0; } + bool operator==(const Ptr &rhs) const { JS_ASSERT(found() && rhs.found()); return entry == rhs.entry; } + bool operator!=(const Ptr &rhs) const { return !(*this == rhs); } + + T &operator*() const { return entry->t; } + T *operator->() const { return &entry->t; } + }; + + /* A Ptr that can be used to add a key after a failed lookup. */ + class AddPtr : public Ptr + { + friend class HashTable; + HashNumber keyHash; +#ifdef DEBUG + uint64 mutationCount; + + AddPtr(Entry &entry, HashNumber hn, uint64 mutationCount) + : Ptr(entry), keyHash(hn), mutationCount(mutationCount) {} +#else + AddPtr(Entry &entry, HashNumber hn) : Ptr(entry), keyHash(hn) {} +#endif + }; + + /* + * A collection of hash table entries. The collection is enumerated by + * calling |front()| followed by |popFront()| as long as |!empty()|. As + * with Ptr/AddPtr, Range objects must not be used after any mutating hash + * table operation unless the |generation()| is tested. + */ + class Range + { + protected: + friend class HashTable; + + Range(Entry *c, Entry *e) : cur(c), end(e) { + while (cur != end && !cur->isLive()) + ++cur; + } + + Entry *cur, *end; + + public: + bool empty() const { + return cur == end; + } + + T &front() const { + JS_ASSERT(!empty()); + return cur->t; + } + + void popFront() { + JS_ASSERT(!empty()); + while (++cur != end && !cur->isLive()); + } + }; + + /* + * A Range whose lifetime delimits a mutating enumeration of a hash table. + * Since rehashing when elements were removed during enumeration would be + * bad, it is postponed until |endEnumeration()| is called. If + * |endEnumeration()| is not called before an Enum's constructor, it will + * be called automatically. Since |endEnumeration()| touches the hash + * table, the user must ensure that the hash table is still alive when this + * happens. + */ + class Enum : public Range + { + friend class HashTable; + + HashTable &table; + bool removed; + + /* Not copyable. */ + Enum(const Enum &); + void operator=(const Enum &); + + public: + template explicit + Enum(Map &map) : Range(map.all()), table(map.impl), removed(false) {} + + /* + * Removes the |front()| element from the table, leaving |front()| + * invalid until the next call to |popFront()|. For example: + * + * HashSet s; + * for (HashSet::Enum e(s); !e.empty(); e.popFront()) + * if (e.front() == 42) + * e.removeFront(); + */ + void removeFront() { + table.remove(*this->cur); + removed = true; + } + + /* Potentially rehashes the table. */ + ~Enum() { + if (removed) + table.checkUnderloaded(); + } + + /* Can be used to end the enumeration before the destructor. */ + void endEnumeration() { + if (removed) { + table.checkUnderloaded(); + removed = false; + } + } + }; + + private: + uint32 hashShift; /* multiplicative hash shift */ + uint32 tableCapacity; /* = JS_BIT(sHashBits - hashShift) */ + uint32 entryCount; /* number of entries in table */ + uint32 gen; /* entry storage generation number */ + uint32 removedCount; /* removed entry sentinels in table */ + Entry *table; /* entry storage */ + + void setTableSizeLog2(unsigned sizeLog2) { + hashShift = sHashBits - sizeLog2; + tableCapacity = JS_BIT(sizeLog2); + } + +#ifdef DEBUG + mutable struct Stats { + uint32 searches; /* total number of table searches */ + uint32 steps; /* hash chain links traversed */ + uint32 hits; /* searches that found key */ + uint32 misses; /* searches that didn't find key */ + uint32 addOverRemoved; /* adds that recycled a removed entry */ + uint32 removes; /* calls to remove */ + uint32 removeFrees; /* calls to remove that freed the entry */ + uint32 grows; /* table expansions */ + uint32 shrinks; /* table contractions */ + uint32 compresses; /* table compressions */ + } stats; +# define METER(x) x +#else +# define METER(x) +#endif + +#ifdef DEBUG + friend class js::ReentrancyGuard; + mutable bool entered; + uint64 mutationCount; +#endif + + static const unsigned sMinSizeLog2 = 4; + static const unsigned sMinSize = 1 << sMinSizeLog2; + static const unsigned sSizeLimit = JS_BIT(24); + static const unsigned sHashBits = tl::BitSize::result; + static const uint8 sMinAlphaFrac = 64; /* (0x100 * .25) taken from jsdhash.h */ + static const uint8 sMaxAlphaFrac = 192; /* (0x100 * .75) taken from jsdhash.h */ + static const uint8 sInvMaxAlpha = 171; /* (ceil(0x100 / .75) >> 1) */ + static const HashNumber sGoldenRatio = 0x9E3779B9U; /* taken from jsdhash.h */ + static const HashNumber sCollisionBit = 1; + static const HashNumber sFreeKey = 0; + static const HashNumber sRemovedKey = 1; + + static bool isLiveHash(HashNumber hash) + { + return hash > sRemovedKey; + } + + static HashNumber prepareHash(const Lookup& l) + { + HashNumber keyHash = HashPolicy::hash(l); + + /* Improve keyHash distribution. */ + keyHash *= sGoldenRatio; + + /* Avoid reserved hash codes. */ + if (!isLiveHash(keyHash)) + keyHash -= (sRemovedKey + 1); + return keyHash & ~sCollisionBit; + } + + static Entry *createTable(AllocPolicy &alloc, uint32 capacity) + { + Entry *newTable = (Entry *)alloc.malloc(capacity * sizeof(Entry)); + if (!newTable) + return NULL; + for (Entry *e = newTable, *end = e + capacity; e != end; ++e) + new(e) Entry(); + return newTable; + } + + static void destroyTable(AllocPolicy &alloc, Entry *oldTable, uint32 capacity) + { + for (Entry *e = oldTable, *end = e + capacity; e != end; ++e) + e->~Entry(); + alloc.free(oldTable); + } + + public: + HashTable(AllocPolicy ap) + : AllocPolicy(ap), + entryCount(0), + gen(0), + removedCount(0), + table(NULL) +#ifdef DEBUG + , entered(false), + mutationCount(0) +#endif + {} + + bool init(uint32 length) + { + /* Make sure that init isn't called twice. */ + JS_ASSERT(table == NULL); + + /* + * Correct for sMaxAlphaFrac such that the table will not resize + * when adding 'length' entries. + */ + JS_ASSERT(length < (uint32(1) << 23)); + uint32 capacity = (length * sInvMaxAlpha) >> 7; + + if (capacity < sMinSize) + capacity = sMinSize; + + /* FIXME: use JS_CEILING_LOG2 when PGO stops crashing (bug 543034). */ + uint32 roundUp = sMinSize, roundUpLog2 = sMinSizeLog2; + while (roundUp < capacity) { + roundUp <<= 1; + ++roundUpLog2; + } + + capacity = roundUp; + if (capacity >= sSizeLimit) { + this->reportAllocOverflow(); + return false; + } + + table = createTable(*this, capacity); + if (!table) + return false; + + setTableSizeLog2(roundUpLog2); + METER(memset(&stats, 0, sizeof(stats))); + return true; + } + + bool initialized() const + { + return !!table; + } + + ~HashTable() + { + if (table) + destroyTable(*this, table, tableCapacity); + } + + private: + static HashNumber hash1(HashNumber hash0, uint32 shift) { + return hash0 >> shift; + } + + static HashNumber hash2(HashNumber hash0, uint32 log2, uint32 shift) { + return ((hash0 << log2) >> shift) | 1; + } + + bool overloaded() { + return entryCount + removedCount >= ((sMaxAlphaFrac * tableCapacity) >> 8); + } + + bool underloaded() { + return tableCapacity > sMinSize && + entryCount <= ((sMinAlphaFrac * tableCapacity) >> 8); + } + + static bool match(Entry &e, const Lookup &l) { + return HashPolicy::match(HashPolicy::getKey(e.t), l); + } + + Entry &lookup(const Lookup &l, HashNumber keyHash, unsigned collisionBit) const + { + JS_ASSERT(isLiveHash(keyHash)); + JS_ASSERT(!(keyHash & sCollisionBit)); + JS_ASSERT(collisionBit == 0 || collisionBit == sCollisionBit); + JS_ASSERT(table); + METER(stats.searches++); + + /* Compute the primary hash address. */ + HashNumber h1 = hash1(keyHash, hashShift); + Entry *entry = &table[h1]; + + /* Miss: return space for a new entry. */ + if (entry->isFree()) { + METER(stats.misses++); + return *entry; + } + + /* Hit: return entry. */ + if (entry->matchHash(keyHash) && match(*entry, l)) { + METER(stats.hits++); + return *entry; + } + + /* Collision: double hash. */ + unsigned sizeLog2 = sHashBits - hashShift; + HashNumber h2 = hash2(keyHash, sizeLog2, hashShift); + HashNumber sizeMask = (HashNumber(1) << sizeLog2) - 1; + + /* Save the first removed entry pointer so we can recycle later. */ + Entry *firstRemoved = NULL; + + while(true) { + if (JS_UNLIKELY(entry->isRemoved())) { + if (!firstRemoved) + firstRemoved = entry; + } else { + entry->setCollision(collisionBit); + } + + METER(stats.steps++); + h1 -= h2; + h1 &= sizeMask; + + entry = &table[h1]; + if (entry->isFree()) { + METER(stats.misses++); + return firstRemoved ? *firstRemoved : *entry; + } + + if (entry->matchHash(keyHash) && match(*entry, l)) { + METER(stats.hits++); + return *entry; + } + } + } + + /* + * This is a copy of lookup hardcoded to the assumptions: + * 1. the lookup is a lookupForAdd + * 2. the key, whose |keyHash| has been passed is not in the table, + * 3. no entries have been removed from the table. + * This specialized search avoids the need for recovering lookup values + * from entries, which allows more flexible Lookup/Key types. + */ + Entry &findFreeEntry(HashNumber keyHash) + { + METER(stats.searches++); + JS_ASSERT(!(keyHash & sCollisionBit)); + + /* N.B. the |keyHash| has already been distributed. */ + + /* Compute the primary hash address. */ + HashNumber h1 = hash1(keyHash, hashShift); + Entry *entry = &table[h1]; + + /* Miss: return space for a new entry. */ + if (entry->isFree()) { + METER(stats.misses++); + return *entry; + } + + /* Collision: double hash. */ + unsigned sizeLog2 = sHashBits - hashShift; + HashNumber h2 = hash2(keyHash, sizeLog2, hashShift); + HashNumber sizeMask = (HashNumber(1) << sizeLog2) - 1; + + while(true) { + JS_ASSERT(!entry->isRemoved()); + entry->setCollision(); + + METER(stats.steps++); + h1 -= h2; + h1 &= sizeMask; + + entry = &table[h1]; + if (entry->isFree()) { + METER(stats.misses++); + return *entry; + } + } + } + + bool changeTableSize(int deltaLog2) + { + /* Look, but don't touch, until we succeed in getting new entry store. */ + Entry *oldTable = table; + uint32 oldCap = tableCapacity; + uint32 newLog2 = sHashBits - hashShift + deltaLog2; + uint32 newCapacity = JS_BIT(newLog2); + if (newCapacity >= sSizeLimit) { + this->reportAllocOverflow(); + return false; + } + + Entry *newTable = createTable(*this, newCapacity); + if (!newTable) + return false; + + /* We can't fail from here on, so update table parameters. */ + setTableSizeLog2(newLog2); + removedCount = 0; + gen++; + table = newTable; + + /* Copy only live entries, leaving removed ones behind. */ + for (Entry *src = oldTable, *end = src + oldCap; src != end; ++src) { + if (src->isLive()) { + src->unsetCollision(); + findFreeEntry(src->getKeyHash()) = *src; + } + } + + destroyTable(*this, oldTable, oldCap); + return true; + } + + void remove(Entry &e) + { + METER(stats.removes++); + if (e.hasCollision()) { + e.setRemoved(); + removedCount++; + } else { + METER(stats.removeFrees++); + e.setFree(); + } + entryCount--; +#ifdef DEBUG + mutationCount++; +#endif + } + + void checkUnderloaded() + { + if (underloaded()) { + METER(stats.shrinks++); + (void) changeTableSize(-1); + } + } + + public: + void clear() + { + for (Entry *e = table, *end = table + tableCapacity; e != end; ++e) + *e = Entry(); + removedCount = 0; + entryCount = 0; +#ifdef DEBUG + mutationCount++; +#endif + } + + Range all() const { + return Range(table, table + tableCapacity); + } + + bool empty() const { + return !entryCount; + } + + uint32 count() const{ + return entryCount; + } + + uint32 generation() const { + return gen; + } + + Ptr lookup(const Lookup &l) const { + ReentrancyGuard g(*this); + HashNumber keyHash = prepareHash(l); + return Ptr(lookup(l, keyHash, 0)); + } + + AddPtr lookupForAdd(const Lookup &l) const { + ReentrancyGuard g(*this); + HashNumber keyHash = prepareHash(l); + Entry &entry = lookup(l, keyHash, sCollisionBit); +#ifdef DEBUG + return AddPtr(entry, keyHash, mutationCount); +#else + return AddPtr(entry, keyHash); +#endif + } + + bool add(AddPtr &p) + { + ReentrancyGuard g(*this); + JS_ASSERT(mutationCount == p.mutationCount); + JS_ASSERT(table); + JS_ASSERT(!p.found()); + JS_ASSERT(!(p.keyHash & sCollisionBit)); + + /* + * Changing an entry from removed to live does not affect whether we + * are overloaded and can be handled separately. + */ + if (p.entry->isRemoved()) { + METER(stats.addOverRemoved++); + removedCount--; + p.keyHash |= sCollisionBit; + } else { + /* If alpha is >= .75, grow or compress the table. */ + if (overloaded()) { + /* Compress if a quarter or more of all entries are removed. */ + int deltaLog2; + if (removedCount >= (tableCapacity >> 2)) { + METER(stats.compresses++); + deltaLog2 = 0; + } else { + METER(stats.grows++); + deltaLog2 = 1; + } + + if (!changeTableSize(deltaLog2)) + return false; + + /* Preserve the validity of |p.entry|. */ + p.entry = &findFreeEntry(p.keyHash); + } + } + + p.entry->setLive(p.keyHash); + entryCount++; +#ifdef DEBUG + mutationCount++; +#endif + return true; + } + + /* + * There is an important contract between the caller and callee for this + * function: if add() returns true, the caller must assign the T value + * which produced p before using the hashtable again. + */ + bool add(AddPtr &p, T** pentry) + { + if (!add(p)) + return false; + *pentry = &p.entry->t; + return true; + } + + bool add(AddPtr &p, const T &t) + { + if (!add(p)) + return false; + p.entry->t = t; + return true; + } + + bool relookupOrAdd(AddPtr& p, const Lookup &l, const T& t) + { +#ifdef DEBUG + p.mutationCount = mutationCount; +#endif + { + ReentrancyGuard g(*this); + p.entry = &lookup(l, p.keyHash, sCollisionBit); + } + return p.found() || add(p, t); + } + + void remove(Ptr p) + { + ReentrancyGuard g(*this); + JS_ASSERT(p.found()); + remove(*p.entry); + checkUnderloaded(); + } +#undef METER +}; + +} + +/* + * Hash policy + * + * A hash policy P for a hash table with key-type Key must provide: + * - a type |P::Lookup| to use to lookup table entries; + * - a static member function |P::hash| with signature + * + * static js::HashNumber hash(Lookup) + * + * to use to hash the lookup type; and + * - a static member function |P::match| with signature + * + * static bool match(Key, Lookup) + * + * to use to test equality of key and lookup values. + * + * Normally, Lookup = Key. In general, though, different values and types of + * values can be used to lookup and store. If a Lookup value |l| is != to the + * added Key value |k|, the user must ensure that |P::match(k,l)|. E.g.: + * + * js::HashSet::AddPtr p = h.lookup(l); + * if (!p) { + * assert(P::match(k, l)); // must hold + * h.add(p, k); + * } + */ + +/* Default hashing policies. */ +template +struct DefaultHasher +{ + typedef Key Lookup; + static HashNumber hash(const Lookup &l) { + /* Hash if can implicitly cast to hash number type. */ + return l; + } + static bool match(const Key &k, const Lookup &l) { + /* Use builtin or overloaded operator==. */ + return k == l; + } +}; + +/* Specialized hashing policy for pointer types. */ +template +struct DefaultHasher +{ + typedef T *Lookup; + static HashNumber hash(T *l) { + /* + * Strip often-0 lower bits for better distribution after multiplying + * by the sGoldenRatio. + */ + return HashNumber(reinterpret_cast(l) >> + tl::FloorLog2::result); + } + static bool match(T *k, T *l) { + return k == l; + } +}; + +/* + * JS-friendly, STL-like container providing a hash-based map from keys to + * values. In particular, HashMap calls constructors and destructors of all + * objects added so non-PODs may be used safely. + * + * Key/Value requirements: + * - default constructible, copyable, destructible, assignable + * HashPolicy requirements: + * - see "Hash policy" above (default js::DefaultHasher) + * AllocPolicy: + * - see "Allocation policies" in jstl.h (default js::ContextAllocPolicy) + * + * N.B: HashMap is not reentrant: Key/Value/HashPolicy/AllocPolicy members + * called by HashMap must not call back into the same HashMap object. + * N.B: Due to the lack of exception handling, the user must call |init()|. + */ +template +class HashMap +{ + public: + typedef typename HashPolicy::Lookup Lookup; + + class Entry + { + template friend class detail::HashTable; + void operator=(const Entry &rhs) { + const_cast(key) = rhs.key; + value = rhs.value; + } + + public: + Entry() : key(), value() {} + Entry(const Key &k, const Value &v) : key(k), value(v) {} + + const Key key; + Value value; + }; + + private: + /* Implement HashMap using HashTable. Lift |Key| operations to |Entry|. */ + struct MapHashPolicy : HashPolicy + { + typedef Key KeyType; + static const Key &getKey(Entry &e) { return e.key; } + }; + typedef detail::HashTable Impl; + + friend class Impl::Enum; + + /* Not implicitly copyable (expensive). May add explicit |clone| later. */ + HashMap(const HashMap &); + HashMap &operator=(const HashMap &); + + Impl impl; + + public: + /* + * HashMap construction is fallible (due to OOM); thus the user must call + * init after constructing a HashMap and check the return value. + */ + HashMap(AllocPolicy a = AllocPolicy()) : impl(a) {} + bool init(uint32 len = 0) { return impl.init(len); } + bool initialized() const { return impl.initialized(); } + + /* + * Return whether the given lookup value is present in the map. E.g.: + * + * typedef HashMap HM; + * HM h; + * if (HM::Ptr p = h.lookup(3)) { + * const HM::Entry &e = *p; // p acts like a pointer to Entry + * assert(p->key == 3); // Entry contains the key + * char val = p->value; // and value + * } + * + * Also see the definition of Ptr in HashTable above (with T = Entry). + */ + typedef typename Impl::Ptr Ptr; + Ptr lookup(const Lookup &l) const { return impl.lookup(l); } + + /* Assuming |p.found()|, remove |*p|. */ + void remove(Ptr p) { impl.remove(p); } + + /* + * Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient + * insertion of Key |k| (where |HashPolicy::match(k,l) == true|) using + * |add(p,k,v)|. After |add(p,k,v)|, |p| points to the new Entry. E.g.: + * + * typedef HashMap HM; + * HM h; + * HM::AddPtr p = h.lookupForAdd(3); + * if (!p) { + * if (!h.add(p, 3, 'a')) + * return false; + * } + * const HM::Entry &e = *p; // p acts like a pointer to Entry + * assert(p->key == 3); // Entry contains the key + * char val = p->value; // and value + * + * Also see the definition of AddPtr in HashTable above (with T = Entry). + * + * N.B. The caller must ensure that no mutating hash table operations + * occur between a pair of |lookupForAdd| and |add| calls. To avoid + * looking up the key a second time, the caller may use the more efficient + * relookupOrAdd method. This method reuses part of the hashing computation + * to more efficiently insert the key if it has not been added. For + * example, a mutation-handling version of the previous example: + * + * HM::AddPtr p = h.lookupForAdd(3); + * if (!p) { + * call_that_may_mutate_h(); + * if (!h.relookupOrAdd(p, 3, 'a')) + * return false; + * } + * const HM::Entry &e = *p; + * assert(p->key == 3); + * char val = p->value; + */ + typedef typename Impl::AddPtr AddPtr; + AddPtr lookupForAdd(const Lookup &l) const { + return impl.lookupForAdd(l); + } + + bool add(AddPtr &p, const Key &k, const Value &v) { + Entry *pentry; + if (!impl.add(p, &pentry)) + return false; + const_cast(pentry->key) = k; + pentry->value = v; + return true; + } + + bool add(AddPtr &p, const Key &k) { + Entry *pentry; + if (!impl.add(p, &pentry)) + return false; + const_cast(pentry->key) = k; + return true; + } + + bool relookupOrAdd(AddPtr &p, const Key &k, const Value &v) { + return impl.relookupOrAdd(p, k, Entry(k, v)); + } + + /* + * |all()| returns a Range containing |count()| elements. E.g.: + * + * typedef HashMap HM; + * HM h; + * for (HM::Range r = h.all(); !r.empty(); r.popFront()) + * char c = r.front().value; + * + * Also see the definition of Range in HashTable above (with T = Entry). + */ + typedef typename Impl::Range Range; + Range all() const { return impl.all(); } + size_t count() const { return impl.count(); } + + /* + * Typedef for the enumeration class. An Enum may be used to examine and + * remove table entries: + * + * typedef HashMap HM; + * HM s; + * for (HM::Enum e(s); !e.empty(); e.popFront()) + * if (e.front().value == 'l') + * e.removeFront(); + * + * Table resize may occur in Enum's destructor. Also see the definition of + * Enum in HashTable above (with T = Entry). + */ + typedef typename Impl::Enum Enum; + + /* Remove all entries. */ + void clear() { impl.clear(); } + + /* Does the table contain any entries? */ + bool empty() const { return impl.empty(); } + + /* + * If |generation()| is the same before and after a HashMap operation, + * pointers into the table remain valid. + */ + unsigned generation() const { return impl.generation(); } + + /* Shorthand operations: */ + + bool has(const Lookup &l) const { + return impl.lookup(l) != NULL; + } + + Entry *put(const Key &k, const Value &v) { + AddPtr p = lookupForAdd(k); + if (p) { + p->value = v; + return &*p; + } + return add(p, k, v) ? &*p : NULL; + } + + void remove(const Lookup &l) { + if (Ptr p = lookup(l)) + remove(p); + } +}; + +/* + * JS-friendly, STL-like container providing a hash-based set of values. In + * particular, HashSet calls constructors and destructors of all objects added + * so non-PODs may be used safely. + * + * T requirements: + * - default constructible, copyable, destructible, assignable + * HashPolicy requirements: + * - see "Hash policy" above (default js::DefaultHasher) + * AllocPolicy: + * - see "Allocation policies" in jstl.h (default js::ContextAllocPolicy) + * + * N.B: HashSet is not reentrant: T/HashPolicy/AllocPolicy members called by + * HashSet must not call back into the same HashSet object. + * N.B: Due to the lack of exception handling, the user must call |init()|. + */ +template +class HashSet +{ + typedef typename HashPolicy::Lookup Lookup; + + /* Implement HashSet in terms of HashTable. */ + struct SetOps : HashPolicy { + typedef T KeyType; + static const KeyType &getKey(const T &t) { return t; } + }; + typedef detail::HashTable Impl; + + friend class Impl::Enum; + + /* Not implicitly copyable (expensive). May add explicit |clone| later. */ + HashSet(const HashSet &); + HashSet &operator=(const HashSet &); + + Impl impl; + + public: + /* + * HashSet construction is fallible (due to OOM); thus the user must call + * init after constructing a HashSet and check the return value. + */ + HashSet(AllocPolicy a = AllocPolicy()) : impl(a) {} + bool init(uint32 len = 0) { return impl.init(len); } + bool initialized() const { return impl.initialized(); } + + /* + * Return whether the given lookup value is present in the map. E.g.: + * + * typedef HashSet HS; + * HS h; + * if (HS::Ptr p = h.lookup(3)) { + * assert(*p == 3); // p acts like a pointer to int + * } + * + * Also see the definition of Ptr in HashTable above. + */ + typedef typename Impl::Ptr Ptr; + Ptr lookup(const Lookup &l) const { return impl.lookup(l); } + + /* Assuming |p.found()|, remove |*p|. */ + void remove(Ptr p) { impl.remove(p); } + + /* + * Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient + * insertion of T value |t| (where |HashPolicy::match(t,l) == true|) using + * |add(p,t)|. After |add(p,t)|, |p| points to the new element. E.g.: + * + * typedef HashSet HS; + * HS h; + * HS::AddPtr p = h.lookupForAdd(3); + * if (!p) { + * if (!h.add(p, 3)) + * return false; + * } + * assert(*p == 3); // p acts like a pointer to int + * + * Also see the definition of AddPtr in HashTable above. + * + * N.B. The caller must ensure that no mutating hash table operations + * occur between a pair of |lookupForAdd| and |add| calls. To avoid + * looking up the key a second time, the caller may use the more efficient + * relookupOrAdd method. This method reuses part of the hashing computation + * to more efficiently insert the key if it has not been added. For + * example, a mutation-handling version of the previous example: + * + * HS::AddPtr p = h.lookupForAdd(3); + * if (!p) { + * call_that_may_mutate_h(); + * if (!h.relookupOrAdd(p, 3, 3)) + * return false; + * } + * assert(*p == 3); + * + * Note that relookupOrAdd(p,l,t) performs Lookup using l and adds the + * entry t, where the caller ensures match(l,t). + */ + typedef typename Impl::AddPtr AddPtr; + AddPtr lookupForAdd(const Lookup &l) const { + return impl.lookupForAdd(l); + } + + bool add(AddPtr &p, const T &t) { + return impl.add(p, t); + } + + bool relookupOrAdd(AddPtr &p, const Lookup &l, const T &t) { + return impl.relookupOrAdd(p, l, t); + } + + /* + * |all()| returns a Range containing |count()| elements: + * + * typedef HashSet HS; + * HS h; + * for (HS::Range r = h.all(); !r.empty(); r.popFront()) + * int i = r.front(); + * + * Also see the definition of Range in HashTable above. + */ + typedef typename Impl::Range Range; + Range all() const { return impl.all(); } + size_t count() const { return impl.count(); } + + /* + * Typedef for the enumeration class. An Enum may be used to examine and + * remove table entries: + * + * typedef HashSet HS; + * HS s; + * for (HS::Enum e(s); !e.empty(); e.popFront()) + * if (e.front() == 42) + * e.removeFront(); + * + * Table resize may occur in Enum's destructor. Also see the definition of + * Enum in HashTable above. + */ + typedef typename Impl::Enum Enum; + + /* Remove all entries. */ + void clear() { impl.clear(); } + + /* Does the table contain any entries? */ + bool empty() const { return impl.empty(); } + + /* + * If |generation()| is the same before and after a HashSet operation, + * pointers into the table remain valid. + */ + unsigned generation() const { return impl.generation(); } + + /* Shorthand operations: */ + + bool has(const Lookup &l) const { + return impl.lookup(l) != NULL; + } + + const T *put(const T &t) { + AddPtr p = lookupForAdd(t); + return p ? &*p : (add(p, t) ? &*p : NULL); + } + + void remove(const Lookup &l) { + if (Ptr p = lookup(l)) + remove(p); + } +}; + +} /* namespace js */ + +#endif diff --git a/js/src/jshotloop.h b/js/src/jshotloop.h new file mode 100644 index 0000000..a47ae76 --- /dev/null +++ b/js/src/jshotloop.h @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Mozilla SpiderMonkey JaegerMonkey implementation + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2002-2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jshotloop_h___ +#define jshotloop_h___ + +#include "jscntxt.h" + +namespace js { + +uint32 +GetHotloop(JSContext *cx); + +} + +#endif diff --git a/js/src/jsify.pl b/js/src/jsify.pl new file mode 100644 index 0000000..0ce2186 --- /dev/null +++ b/js/src/jsify.pl @@ -0,0 +1,483 @@ +#!/usr/local/bin/perl + +# This script modifies C code to use the hijacked NSPR routines that are +# now baked into the JavaScript engine rather than using the NSPR +# routines that they were based on, i.e. types like PRArenaPool are changed +# to JSArenaPool. +# +# This script was used in 9/98 to facilitate the incorporation of some NSPR +# code into the JS engine so as to minimize dependency on NSPR. +# + +# Command-line: jsify.pl [options] [filename]* +# +# Options: +# -r Reverse direction of transformation, i.e. JS ==> NSPR2 +# -outdir Directory in which to place output files + + +# NSPR2 symbols that will be modified to JS symbols, e.g. +# PRArena <==> JSArena + +@NSPR_symbols = ( +"PRArena", +"PRArenaPool", +"PRArenaStats", +"PR_ARENAMETER", +"PR_ARENA_", +"PR_ARENA_ALIGN", +"PR_ARENA_ALLOCATE", +"PR_ARENA_CONST_ALIGN_MASK", +"PR_ARENA_DEFAULT_ALIGN", +"PR_ARENA_DESTROY", +"PR_ARENA_GROW", +"PR_ARENA_MARK", +"PR_ARENA_RELEASE", + +"PR_smprintf", +"PR_smprintf_free", +"PR_snprintf", +"PR_sprintf_append", +"PR_sscanf", +"PR_sxprintf", +"PR_vsmprintf", +"PR_vsnprintf", +"PR_vsprintf_append", +"PR_vsxprintf", + +"PRCList", +"PRCListStr", +"PRCLists", + +"PRDestroyEventProc", +"PREvent", +"PREventFunProc", +"PREventQueue", +"PRHandleEventProc", +"PR_PostEvent", +"PR_PostSynchronousEvent", +"PR_ProcessPendingEvents", +"PR_CreateEventQueue", +"PR_DequeueEvent", +"PR_DestroyEvent", +"PR_DestroyEventQueue", +"PR_EventAvailable", +"PR_EventLoop", +"PR_GetEvent", +"PR_GetEventOwner", +"PR_GetEventQueueMonitor", +"PR_GetEventQueueSelectFD", +"PR_GetMainEventQueue", +"PR_HandleEvent", +"PR_InitEvent", +"PR_ENTER_EVENT_QUEUE_MONITOR", +"PR_EXIT_EVENT_QUEUE_MONITOR", +"PR_MapEvents", +"PR_RevokeEvents", + +"PR_cnvtf", +"PR_dtoa", +"PR_strtod", + +"PRFileDesc", + +"PR_HASH_BITS", +"PR_GOLDEN_RATIO", +"PRHashAllocOps", +"PRHashComparator", +"PRHashEntry", +"PRHashEnumerator", +"PRHashFunction", +"PRHashNumber", +"PRHashTable", +"PR_HashString", +"PR_HashTableAdd", +"PR_HashTableDestroy", +"PR_HashTableDump", +"PR_HashTableEnumerateEntries", +"PR_HashTableLookup", +"PR_HashTableRawAdd", +"PR_HashTableRawLookup", +"PR_HashTableRawRemove", +"PR_HashTableRemove", + +"PRBool", +"PRFloat64", +"PRInt16", +"PRInt32", +"PRInt64", +"PRInt8", +"PRIntn", +"PRUint16", +"PRUint32", +"PRUint64", +"PRUint8", +"PRUintn", +"PRPtrDiff", +"PRPtrdiff", +"PRUptrdiff", +"PRUword", +"PRWord", +"PRPackedBool", +"PRSize", +"PRStatus", +"pruword", +"prword", +"prword_t", + +"PR_ALIGN_OF_DOUBLE", +"PR_ALIGN_OF_FLOAT", +"PR_ALIGN_OF_INT", +"PR_ALIGN_OF_INT64", +"PR_ALIGN_OF_LONG", +"PR_ALIGN_OF_POINTER", +"PR_ALIGN_OF_SHORT", +"PR_ALIGN_OF_WORD", +"PR_BITS_PER_BYTE", +"PR_BITS_PER_BYTE_LOG2", +"PR_BITS_PER_DOUBLE", +"PR_BITS_PER_DOUBLE_LOG2", +"PR_BITS_PER_FLOAT", +"PR_BITS_PER_FLOAT_LOG2", +"PR_BITS_PER_INT", +"PR_BITS_PER_INT64", +"PR_BITS_PER_INT64_LOG2", +"PR_BITS_PER_INT_LOG2", +"PR_BITS_PER_LONG", +"PR_BITS_PER_LONG_LOG2", +"PR_BITS_PER_SHORT", +"PR_BITS_PER_SHORT_LOG2", +"PR_BITS_PER_WORD", +"PR_BITS_PER_WORD_LOG2", +"PR_BYTES_PER_BYTE", +"PR_BYTES_PER_DOUBLE", +"PR_BYTES_PER_DWORD", +"PR_BYTES_PER_DWORD_LOG2", +"PR_BYTES_PER_FLOAT", +"PR_BYTES_PER_INT", +"PR_BYTES_PER_INT64", +"PR_BYTES_PER_LONG", +"PR_BYTES_PER_SHORT", +"PR_BYTES_PER_WORD", +"PR_BYTES_PER_WORD_LOG2", + +"PRSegment", +"PRSegmentAccess", +"PRStuffFunc", +"PRThread", + +"PR_APPEND_LINK", + +"PR_ASSERT", + +"PR_ATOMIC_DWORD_LOAD", +"PR_ATOMIC_DWORD_STORE", + +"PR_Abort", + +"PR_ArenaAllocate", +"PR_ArenaCountAllocation", +"PR_ArenaCountGrowth", +"PR_ArenaCountInplaceGrowth", +"PR_ArenaCountRelease", +"PR_ArenaCountRetract", +"PR_ArenaFinish", +"PR_ArenaGrow", +"PR_ArenaRelease", +"PR_CompactArenaPool", +"PR_DumpArenaStats", +"PR_FinishArenaPool", +"PR_FreeArenaPool", +"PR_InitArenaPool", + +"PR_Assert", + +"PR_AttachThread", + +"PR_BEGIN_EXTERN_C", +"PR_BEGIN_MACRO", + +"PR_BIT", +"PR_BITMASK", + +"PR_BUFFER_OVERFLOW_ERROR", + +"PR_CALLBACK", +"PR_CALLBACK_DECL", +"PR_CALLOC", +"PR_CEILING_LOG2", +"PR_CLEAR_ARENA", +"PR_CLEAR_BIT", +"PR_CLEAR_UNUSED", +"PR_CLIST_IS_EMPTY", +"PR_COUNT_ARENA", +"PR_CURRENT_THREAD", + +"PR_GetSegmentAccess", +"PR_GetSegmentSize", +"PR_GetSegmentVaddr", +"PR_GrowSegment", +"PR_DestroySegment", +"PR_MapSegment", +"PR_NewSegment", +"PR_Segment", +"PR_Seg", +"PR_SEGMENT_NONE", +"PR_SEGMENT_RDONLY", +"PR_SEGMENT_RDWR", + +"PR_Calloc", +"PR_CeilingLog2", +"PR_CompareStrings", +"PR_CompareValues", +"PR_DELETE", +"PR_END_EXTERN_C", +"PR_END_MACRO", +"PR_ENUMERATE_STOP", +"PR_FAILURE", +"PR_FALSE", +"PR_FLOOR_LOG2", +"PR_FREEIF", +"PR_FREE_PATTERN", +"PR_FloorLog2", +"PR_FormatTime", +"PR_Free", + +"PR_GetEnv", +"PR_GetError", +"PR_INIT_ARENA_POOL", +"PR_INIT_CLIST", +"PR_INIT_STATIC_CLIST", +"PR_INLINE", +"PR_INSERT_AFTER", +"PR_INSERT_BEFORE", +"PR_INSERT_LINK", +"PR_INT32", +"PR_INTERVAL_NO_TIMEOUT", +"PR_INTERVAL_NO_WAIT", +"PR_Init", +"PR_LIST_HEAD", +"PR_LIST_TAIL", +"PR_LOG", +"PR_LOGGING", +"PR_LOG_ALWAYS", +"PR_LOG_BEGIN", +"PR_LOG_DEBUG", +"PR_LOG_DEFINE", +"PR_LOG_END", +"PR_LOG_ERROR", +"PR_LOG_MAX", +"PR_LOG_MIN", +"PR_LOG_NONE", +"PR_LOG_NOTICE", +"PR_LOG_TEST", +"PR_LOG_WARN", +"PR_LOG_WARNING", +"PR_LogFlush", +"PR_LogPrint", +"PR_MALLOC", +"PR_MAX", +"PR_MD_calloc", +"PR_MD_free", +"PR_MD_malloc", +"PR_MD_realloc", +"PR_MIN", +"PR_Malloc", +"PR_NEW", +"PR_NEWZAP", +"PR_NEXT_LINK", +"PR_NOT_REACHED", +"PR_NewCondVar", +"PR_NewHashTable", +"PR_NewLogModule", +"PR_PREV_LINK", +"PR_PUBLIC_API", +"PR_PUBLIC_DATA", +"PR_RANGE_ERROR", +"PR_REALLOC", +"PR_REMOVE_AND_INIT_LINK", +"PR_REMOVE_LINK", +"PR_ROUNDUP", +"PR_Realloc", + +"PR_SET_BIT", +"PR_STATIC_CALLBACK", +"PR_SUCCESS", +"PR_SetError", +"PR_SetLogBuffering", +"PR_SetLogFile", + +"PR_TEST_BIT", +"PR_TRUE", +"PR_UINT32", +"PR_UPTRDIFF", + +"prarena_h___", +"prbit_h___", +"prclist_h___", +"prdtoa_h___", +"prlog_h___", +"prlong_h___", +"prmacos_h___", +"prmem_h___", +"prprf_h___", +"prtypes_h___", + +"prarena", +"prbit", +"prbitmap_t", +"prclist", +"prcpucfg", +"prdtoa", +"prhash", +"plhash", +"prlong", +"prmacos", +"prmem", +"prosdep", +"protypes", +"prprf", +"prtypes" +); + +while ($ARGV[0] =~ /^-/) { + if ($ARGV[0] eq "-r") { + shift; + $reverse_conversion = 1; + } elsif ($ARGV[0] eq "-outdir") { + shift; + $outdir = shift; + } +} + +# Given an NSPR symbol compute the JS equivalent or +# vice-versa +sub subst { + local ($replacement); + local ($sym) = @_; + + $replacement = substr($sym,0,2) eq "pr" ? "js" : "JS"; + $replacement .= substr($sym, 2); + return $replacement; +} + +# Build the regular expression that will convert between the NSPR +# types and the JS types +if ($reverse_conversion) { + die "Not implemented yet"; +} else { + foreach $sym (@NSPR_symbols) { + $regexp .= $sym . "|" + } + # Get rid of the last "!" + chop $regexp; + + # Replace PR* with JS* and replace pr* with js* + $regexp = 's/(^|\\W)(' . $regexp . ')/$1 . &subst($2)/eg'; +# print $regexp; +} + +# Pre-compile a little subroutine to perform the regexp substitution +# between NSPR types and JS types +eval('sub convert_from_NSPR {($line) = @_; $line =~ ' . $regexp . ';}'); + +sub convert_mallocs { + ($line) = @_; + $line =~ s/PR_MALLOC/malloc/g; + $line =~ s/PR_REALLOC/realloc/g; + $line =~ s/PR_FREE/free/g; + return $line; +} + +sub convert_includes { + ($line) = @_; + if ($line !~ /include/) { + return $line; + } + + if ($line =~ /prlog\.h/) { + $line = '#include "jsutil.h"'. " /* Added by JSIFY */\n"; + } elsif ($line =~ /plhash\.h/) { + $line = '#include "jshash.h"'. " /* Added by JSIFY */\n"; + } elsif ($line =~ /plarena\.h/) { + $line = '#include "jsarena.h"'. " /* Added by JSIFY */\n"; + } elsif ($line =~ /prmem\.h/) { + $line = ""; + } elsif ($line =~ /jsmsg\.def/) { + $line = '#include "js.msg"' . "\n"; + } elsif ($line =~ /shellmsg\.def/) { + $line = '#include "jsshell.msg"' . "\n"; + } elsif ($line =~ /jsopcode\.def/) { + $line = '#include "jsopcode.tbl"' . "\n"; + } + return $line; +} + +sub convert_declarations { + ($line) = @_; + $line =~ s/PR_EXTERN/JS_EXTERN_API/g; + $line =~ s/PR_IMPLEMENT_DATA/JS_EXPORT_DATA/g; + $line =~ s/PR_IMPLEMENT/JS_EXPORT_API/g; + $line =~ s/PR_IMPORT/JS_IMPORT/g; + $line =~ s/PR_PUBLIC_API/JS_EXPORT_API/g; + $line =~ s/PR_PUBLIC_DATA/JS_EXPORT_DATA/g; + return $line; +} + +sub convert_long_long_macros { + ($line) = @_; + $line =~ s/\b(LL_)/JSLL_/g; + return $line; +} + +sub convert_asserts { + ($line) = @_; + $line =~ s/\bPR_ASSERT/JS_ASSERT/g; + return $line; +} + +while ($#ARGV >= 0) { + $infile = shift; + + # Change filename, e.g. prtime.h to jsprtime.h, except for legacy + # files that start with 'prmj', like prmjtime.h. + $outfile = $infile; + if ($infile !~ /^prmj/) { + $outfile =~ s/^pr/js/; + $outfile =~ s/^pl/js/; + } + + if ($outdir) { + $outfile = $outdir . '/' . $outfile; + } + + if ($infile eq $outfile) { + die "Error: refuse to overwrite $outfile, use -outdir option." + } + die "Can't open $infile" if !open(INFILE, "<$infile"); + die "Can't open $outfile for writing" if !open(OUTFILE, ">$outfile"); + + while () { + $line = $_; + + #Get rid of #include "prlog.h" + &convert_includes($line); + + # Rename PR_EXTERN, PR_IMPORT, etc. + &convert_declarations($line); + + # Convert from PR_MALLOC to malloc, etc. + &convert_mallocs($line); + + # Convert from PR_ASSERT to JS_ASSERT +# &convert_asserts($line); + + # Convert from, e.g. PRArena to JSPRArena + &convert_from_NSPR($line); + + # Change LL_* macros to JSLL_* + &convert_long_long_macros($line); + + print OUTFILE $line; + } +} diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp new file mode 100644 index 0000000..e48958a --- /dev/null +++ b/js/src/jsinterp.cpp @@ -0,0 +1,6989 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript bytecode interpreter. + */ +#include +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsarena.h" +#include "jsutil.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jsdate.h" +#include "jsversion.h" +#include "jsdbgapi.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jspropertycache.h" +#include "jsscan.h" +#include "jsemit.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jsstaticcheck.h" +#include "jstracer.h" +#include "jslibmath.h" +#include "jsvector.h" +#include "methodjit/MethodJIT.h" +#include "methodjit/MethodJIT-inl.h" +#include "methodjit/Logging.h" + +#include "jsatominlines.h" +#include "jscntxtinlines.h" +#include "jsinterpinlines.h" +#include "jsobjinlines.h" +#include "jsprobes.h" +#include "jspropertycacheinlines.h" +#include "jsscopeinlines.h" +#include "jsscriptinlines.h" +#include "jsstrinlines.h" +#include "jsopcodeinlines.h" + +#if JS_HAS_XML_SUPPORT +#include "jsxml.h" +#endif + +#include "jsautooplen.h" + +#if defined(JS_METHODJIT) && defined(JS_MONOIC) +#include "methodjit/MonoIC.h" +#endif + +using namespace js; +using namespace js::gc; + +/* jsinvoke_cpp___ indicates inclusion from jsinvoke.cpp. */ +#if !JS_LONE_INTERPRET ^ defined jsinvoke_cpp___ + +#ifdef DEBUG +JSObject *const JSStackFrame::sInvalidScopeChain = (JSObject *)0xbeef; +#endif + +jsbytecode * +JSStackFrame::pc(JSContext *cx, JSStackFrame *next) +{ + JS_ASSERT_IF(next, next->prev_ == this); + JS_ASSERT(cx->containingSegment(this) != NULL); + + JSFrameRegs *regs; + if (cx->regs) { + regs = cx->regs; + } else { + StackSegment *segment = cx->getCurrentSegment(); + regs = segment->getSuspendedRegs(); + } + + if (this == regs->fp) + return regs->pc; + + if (!next) + next = cx->computeNextFrame(this); + + if (next->flags_ & JSFRAME_HAS_PREVPC) + return next->prevpc_; + +#if defined(JS_METHODJIT) && defined(JS_MONOIC) + js::mjit::JITScript *jit = script()->getJIT(isConstructing()); + return jit->nativeToPC(next->ncode_); +#else + JS_NOT_REACHED("Unknown PC for frame"); + return NULL; +#endif +} + +JSObject * +js::GetScopeChain(JSContext *cx) +{ + JSStackFrame *fp = js_GetTopStackFrame(cx); + if (!fp) { + /* + * There is no code active on this context. In place of an actual + * scope chain, use the context's global object, which is set in + * js_InitFunctionAndObjectClasses, and which represents the default + * scope chain for the embedding. See also js_FindClassObject. + * + * For embeddings that use the inner and outer object hooks, the inner + * object represents the ultimate global object, with the outer object + * acting as a stand-in. + */ + JSObject *obj = cx->globalObject; + if (!obj) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE); + return NULL; + } + + OBJ_TO_INNER_OBJECT(cx, obj); + return obj; + } + return GetScopeChain(cx, fp); +} + +/* + * This computes the blockChain by iterating through the bytecode + * of the current script until it reaches the PC. Each time it sees + * an ENTERBLOCK or LEAVEBLOCK instruction, it records the new + * blockChain. A faster variant of this function that doesn't + * require bytecode scanning appears below. + */ +JSObject * +js::GetBlockChain(JSContext *cx, JSStackFrame *fp) +{ + if (!fp->isScriptFrame()) + return NULL; + + /* Assume that imacros don't affect blockChain */ + jsbytecode *target = fp->hasImacropc() ? fp->imacropc() : fp->pc(cx); + + JSScript *script = fp->script(); + jsbytecode *start = script->code; + JS_ASSERT(target >= start && target < start + script->length); + + JSObject *blockChain = NULL; + uintN indexBase = 0; + ptrdiff_t oplen; + for (jsbytecode *pc = start; pc < target; pc += oplen) { + JSOp op = js_GetOpcode(cx, script, pc); + const JSCodeSpec *cs = &js_CodeSpec[op]; + oplen = cs->length; + if (oplen < 0) + oplen = js_GetVariableBytecodeLength(pc); + + if (op == JSOP_INDEXBASE) + indexBase = GET_INDEXBASE(pc); + else if (op == JSOP_INDEXBASE1 || op == JSOP_INDEXBASE2 || op == JSOP_INDEXBASE3) + indexBase = (op - JSOP_INDEXBASE1 + 1) << 16; + else if (op == JSOP_RESETBASE || op == JSOP_RESETBASE0) + indexBase = 0; + else if (op == JSOP_ENTERBLOCK) + blockChain = script->getObject(indexBase + GET_INDEX(pc)); + else if (op == JSOP_LEAVEBLOCK || op == JSOP_LEAVEBLOCKEXPR) + blockChain = blockChain->getParent(); + else if (op == JSOP_BLOCKCHAIN) + blockChain = script->getObject(indexBase + GET_INDEX(pc)); + else if (op == JSOP_NULLBLOCKCHAIN) + blockChain = NULL; + } + + return blockChain; +} + +/* + * This function computes the current blockChain, but only in + * the special case where a BLOCKCHAIN or NULLBLOCKCHAIN + * instruction appears immediately after the current PC. + * We ensure this happens for a few important ops like DEFFUN. + * |oplen| is the length of opcode at the current PC. + */ +JSObject * +js::GetBlockChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen) +{ + /* Assume that we're in a script frame. */ + jsbytecode *pc = fp->pc(cx); + JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == op); + + pc += oplen; + op = JSOp(*pc); + JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == op); + + /* The fast paths assume no JSOP_RESETBASE/INDEXBASE noise. */ + if (op == JSOP_NULLBLOCKCHAIN) + return NULL; + if (op == JSOP_BLOCKCHAIN) + return fp->script()->getObject(GET_INDEX(pc)); + + return GetBlockChain(cx, fp); +} + +/* + * We can't determine in advance which local variables can live on the stack and + * be freed when their dynamic scope ends, and which will be closed over and + * need to live in the heap. So we place variables on the stack initially, note + * when they are closed over, and copy those that are out to the heap when we + * leave their dynamic scope. + * + * The bytecode compiler produces a tree of block objects accompanying each + * JSScript representing those lexical blocks in the script that have let-bound + * variables associated with them. These block objects are never modified, and + * never become part of any function's scope chain. Their parent slots point to + * the innermost block that encloses them, or are NULL in the outermost blocks + * within a function or in eval or global code. + * + * When we are in the static scope of such a block, blockChain points to its + * compiler-allocated block object; otherwise, it is NULL. + * + * scopeChain is the current scope chain, including 'call' and 'block' objects + * for those function calls and lexical blocks whose static scope we are + * currently executing in, and 'with' objects for with statements; the chain is + * typically terminated by a global object. However, as an optimization, the + * young end of the chain omits block objects we have not yet cloned. To create + * a closure, we clone the missing blocks from blockChain (which is always + * current), place them at the head of scopeChain, and use that for the + * closure's scope chain. If we never close over a lexical block, we never + * place a mutable clone of it on scopeChain. + * + * This lazy cloning is implemented in GetScopeChain, which is also used in + * some other cases --- entering 'with' blocks, for example. + */ +static JSObject * +GetScopeChainFull(JSContext *cx, JSStackFrame *fp, JSObject *blockChain) +{ + JSObject *sharedBlock = blockChain; + + if (!sharedBlock) { + /* + * Don't force a call object for a lightweight function call, but do + * insist that there is a call object for a heavyweight function call. + */ + JS_ASSERT_IF(fp->isFunctionFrame() && fp->fun()->isHeavyweight(), + fp->hasCallObj()); + return &fp->scopeChain(); + } + + /* We don't handle cloning blocks on trace. */ + LeaveTrace(cx); + + /* + * We have one or more lexical scopes to reflect into fp->scopeChain, so + * make sure there's a call object at the current head of the scope chain, + * if this frame is a call frame. + * + * Also, identify the innermost compiler-allocated block we needn't clone. + */ + JSObject *limitBlock, *limitClone; + if (fp->isFunctionFrame() && !fp->hasCallObj()) { + JS_ASSERT_IF(fp->scopeChain().isClonedBlock(), + fp->scopeChain().getPrivate() != js_FloatingFrameIfGenerator(cx, fp)); + if (!js_GetCallObject(cx, fp)) + return NULL; + + /* We know we must clone everything on blockChain. */ + limitBlock = limitClone = NULL; + } else { + /* + * scopeChain includes all blocks whose static scope we're within that + * have already been cloned. Find the innermost such block. Its + * prototype should appear on blockChain; we'll clone blockChain up + * to, but not including, that prototype. + */ + limitClone = &fp->scopeChain(); + while (limitClone->getClass() == &js_WithClass) + limitClone = limitClone->getParent(); + JS_ASSERT(limitClone); + + /* + * It may seem like we don't know enough about limitClone to be able + * to just grab its prototype as we do here, but it's actually okay. + * + * If limitClone is a block object belonging to this frame, then its + * prototype is the innermost entry in blockChain that we have already + * cloned, and is thus the place to stop when we clone below. + * + * Otherwise, there are no blocks for this frame on scopeChain, and we + * need to clone the whole blockChain. In this case, limitBlock can + * point to any object known not to be on blockChain, since we simply + * loop until we hit limitBlock or NULL. If limitClone is a block, it + * isn't a block from this function, since blocks can't be nested + * within themselves on scopeChain (recursion is dynamic nesting, not + * static nesting). If limitClone isn't a block, its prototype won't + * be a block either. So we can just grab limitClone's prototype here + * regardless of its type or which frame it belongs to. + */ + limitBlock = limitClone->getProto(); + + /* If the innermost block has already been cloned, we are done. */ + if (limitBlock == sharedBlock) + return &fp->scopeChain(); + } + + /* + * Special-case cloning the innermost block; this doesn't have enough in + * common with subsequent steps to include in the loop. + * + * js_CloneBlockObject leaves the clone's parent slot uninitialized. We + * populate it below. + */ + JSObject *innermostNewChild = js_CloneBlockObject(cx, sharedBlock, fp); + if (!innermostNewChild) + return NULL; + AutoObjectRooter tvr(cx, innermostNewChild); + + /* + * Clone our way towards outer scopes until we reach the innermost + * enclosing function, or the innermost block we've already cloned. + */ + JSObject *newChild = innermostNewChild; + for (;;) { + JS_ASSERT(newChild->getProto() == sharedBlock); + sharedBlock = sharedBlock->getParent(); + + /* Sometimes limitBlock will be NULL, so check that first. */ + if (sharedBlock == limitBlock || !sharedBlock) + break; + + /* As in the call above, we don't know the real parent yet. */ + JSObject *clone = js_CloneBlockObject(cx, sharedBlock, fp); + if (!clone) + return NULL; + + newChild->setParent(clone); + newChild = clone; + } + newChild->setParent(&fp->scopeChain()); + + + /* + * If we found a limit block belonging to this frame, then we should have + * found it in blockChain. + */ + JS_ASSERT_IF(limitBlock && + limitBlock->isBlock() && + limitClone->getPrivate() == js_FloatingFrameIfGenerator(cx, fp), + sharedBlock); + + /* Place our newly cloned blocks at the head of the scope chain. */ + fp->setScopeChainNoCallObj(*innermostNewChild); + return innermostNewChild; +} + +JSObject * +js::GetScopeChain(JSContext *cx, JSStackFrame *fp) +{ + return GetScopeChainFull(cx, fp, GetBlockChain(cx, fp)); +} + +JSObject * +js::GetScopeChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen) +{ + return GetScopeChainFull(cx, fp, GetBlockChainFast(cx, fp, op, oplen)); +} + +/* Some objects (e.g., With) delegate 'this' to another object. */ +static inline JSObject * +CallThisObjectHook(JSContext *cx, JSObject *obj, Value *argv) +{ + JSObject *thisp = obj->thisObject(cx); + if (!thisp) + return NULL; + argv[-1].setObject(*thisp); + return thisp; +} + +/* + * ECMA requires "the global object", but in embeddings such as the browser, + * which have multiple top-level objects (windows, frames, etc. in the DOM), + * we prefer fun's parent. An example that causes this code to run: + * + * // in window w1 + * function f() { return this } + * function g() { return f } + * + * // in window w2 + * var h = w1.g() + * alert(h() == w1) + * + * The alert should display "true". + */ +JS_STATIC_INTERPRET bool +ComputeGlobalThis(JSContext *cx, Value *vp) +{ + JSObject *thisp = vp[0].toObject().getGlobal()->thisObject(cx); + if (!thisp) + return false; + vp[1].setObject(*thisp); + return true; +} + +namespace js { + +void +ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp) +{ + Value &thisv = vp[1]; + +#ifdef DEBUG + if (thisv.isObject()) { + JS_ASSERT(thisv.toObject().getClass() != clasp); + } else if (thisv.isString()) { + JS_ASSERT(clasp != &js_StringClass); + } else if (thisv.isNumber()) { + JS_ASSERT(clasp != &js_NumberClass); + } else if (thisv.isBoolean()) { + JS_ASSERT(clasp != &js_BooleanClass); + } else { + JS_ASSERT(thisv.isUndefined() || thisv.isNull()); + } +#endif + + if (JSFunction *fun = js_ValueToFunction(cx, &vp[0], 0)) { + const char *name = thisv.isObject() + ? thisv.toObject().getClass()->name + : thisv.isString() + ? "string" + : thisv.isNumber() + ? "number" + : thisv.isBoolean() + ? "boolean" + : thisv.isNull() + ? js_null_str + : thisv.isUndefined() + ? js_undefined_str + : "value"; + JSAutoByteString funNameBytes; + if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO, + clasp->name, funName, name); + } + } +} + +bool +BoxThisForVp(JSContext *cx, Value *vp) +{ + /* + * Check for SynthesizeFrame poisoning and fast constructors which + * didn't check their vp properly. + */ + JS_ASSERT(!vp[1].isMagic()); +#ifdef DEBUG + JSFunction *fun = vp[0].toObject().isFunction() ? vp[0].toObject().getFunctionPrivate() : NULL; + JS_ASSERT_IF(fun && fun->isInterpreted(), !fun->inStrictMode()); +#endif + + if (vp[1].isNullOrUndefined()) + return ComputeGlobalThis(cx, vp); + + if (!vp[1].isObject()) + return !!js_PrimitiveToObject(cx, &vp[1]); + + return true; +} + +} + +#if JS_HAS_NO_SUCH_METHOD + +const uint32 JSSLOT_FOUND_FUNCTION = 0; +const uint32 JSSLOT_SAVED_ID = 1; + +Class js_NoSuchMethodClass = { + "NoSuchMethod", + JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS, + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub, +}; + +/* + * When JSOP_CALLPROP or JSOP_CALLELEM does not find the method property of + * the base object, we search for the __noSuchMethod__ method in the base. + * If it exists, we store the method and the property's id into an object of + * NoSuchMethod class and store this object into the callee's stack slot. + * Later, js_Invoke will recognise such an object and transfer control to + * NoSuchMethod that invokes the method like: + * + * this.__noSuchMethod__(id, args) + * + * where id is the name of the method that this invocation attempted to + * call by name, and args is an Array containing this invocation's actual + * parameters. + */ +JSBool +js_OnUnknownMethod(JSContext *cx, Value *vp) +{ + JS_ASSERT(!vp[1].isPrimitive()); + + JSObject *obj = &vp[1].toObject(); + jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom); + AutoValueRooter tvr(cx); + if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, tvr.addr())) + return false; + if (tvr.value().isPrimitive()) { + vp[0] = tvr.value(); + } else { +#if JS_HAS_XML_SUPPORT + /* Extract the function name from function::name qname. */ + if (vp[0].isObject()) { + obj = &vp[0].toObject(); + if (!js_IsFunctionQName(cx, obj, &id)) + return false; + if (!JSID_IS_VOID(id)) + vp[0] = IdToValue(id); + } +#endif + obj = js_NewGCObject(cx, FINALIZE_OBJECT2); + if (!obj) + return false; + + /* + * Null map to cause prompt and safe crash if this object were to + * escape due to a bug. This will make the object appear to be a + * stillborn instance that needs no finalization, which is sound: + * NoSuchMethod helper objects own no manually allocated resources. + */ + obj->map = NULL; + obj->init(cx, &js_NoSuchMethodClass, NULL, NULL, NULL, false); + obj->setSlot(JSSLOT_FOUND_FUNCTION, tvr.value()); + obj->setSlot(JSSLOT_SAVED_ID, vp[0]); + vp[0].setObject(*obj); + } + return true; +} + +static JS_REQUIRES_STACK JSBool +NoSuchMethod(JSContext *cx, uintN argc, Value *vp, uint32 flags) +{ + InvokeArgsGuard args; + if (!cx->stack().pushInvokeArgs(cx, 2, &args)) + return JS_FALSE; + + JS_ASSERT(vp[0].isObject()); + JS_ASSERT(vp[1].isObject()); + JSObject *obj = &vp[0].toObject(); + JS_ASSERT(obj->getClass() == &js_NoSuchMethodClass); + + args.callee() = obj->getSlot(JSSLOT_FOUND_FUNCTION); + args.thisv() = vp[1]; + args[0] = obj->getSlot(JSSLOT_SAVED_ID); + JSObject *argsobj = NewDenseCopiedArray(cx, argc, vp + 2); + if (!argsobj) + return JS_FALSE; + args[1].setObject(*argsobj); + JSBool ok = (flags & JSINVOKE_CONSTRUCT) + ? InvokeConstructor(cx, args) + : Invoke(cx, args, flags); + vp[0] = args.rval(); + return ok; +} + +#endif /* JS_HAS_NO_SUCH_METHOD */ + +namespace js { + +JS_REQUIRES_STACK bool +RunScript(JSContext *cx, JSScript *script, JSStackFrame *fp) +{ + JS_ASSERT(script); + JS_ASSERT(fp == cx->fp()); + JS_ASSERT(fp->script() == script); +#ifdef JS_METHODJIT_SPEW + JMCheckLogging(); +#endif + + AutoInterpPreparer prepareInterp(cx, script); + bool ok; + + /* FIXME: Once bug 470510 is fixed, make this an assert. */ + if (script->compileAndGo) { + int32 flags = fp->scopeChain().getGlobal()->getReservedSlot(JSRESERVED_GLOBAL_FLAGS).toInt32(); + if (flags & JSGLOBAL_FLAGS_CLEARED) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CLEARED_SCOPE); + goto error; + } + } + +#ifdef JS_METHODJIT + mjit::CompileStatus status; + status = mjit::CanMethodJIT(cx, script, fp, mjit::CompileRequest_Interpreter); + if (status == mjit::Compile_Error) + goto error; + + if (status == mjit::Compile_Okay) { + ok = mjit::JaegerShot(cx); + JS_ASSERT_IF(!fp->isYielding() && !(fp->isEvalFrame() && !fp->script()->strictModeCode), + !fp->hasCallObj() && !fp->hasArgsObj()); + return ok; + } +#endif + + ok = Interpret(cx, fp); + JS_ASSERT_IF(!fp->isYielding() && !(fp->isEvalFrame() && !fp->script()->strictModeCode), + !fp->hasCallObj() && !fp->hasArgsObj()); + return ok; + + error: + PutOwnedActivationObjects(cx, fp); + return false; +} + +/* + * Find a function reference and its 'this' value implicit first parameter + * under argc arguments on cx's stack, and call the function. Push missing + * required arguments, allocate declared local variables, and pop everything + * when done. Then push the return value. + */ +JS_REQUIRES_STACK bool +Invoke(JSContext *cx, const CallArgs &argsRef, uint32 flags) +{ + /* N.B. Must be kept in sync with InvokeSessionGuard::start/invoke */ + + CallArgs args = argsRef; + JS_ASSERT(args.argc() <= JS_ARGS_LENGTH_MAX); + + if (args.callee().isPrimitive()) { + js_ReportIsNotFunction(cx, &args.callee(), flags & JSINVOKE_FUNFLAGS); + return false; + } + + JSObject &callee = args.callee().toObject(); + Class *clasp = callee.getClass(); + + /* Invoke non-functions. */ + if (JS_UNLIKELY(clasp != &js_FunctionClass)) { +#if JS_HAS_NO_SUCH_METHOD + if (JS_UNLIKELY(clasp == &js_NoSuchMethodClass)) + return NoSuchMethod(cx, args.argc(), args.base(), 0); +#endif + JS_ASSERT_IF(flags & JSINVOKE_CONSTRUCT, !clasp->construct); + if (!clasp->call) { + js_ReportIsNotFunction(cx, &args.callee(), flags); + return false; + } + return CallJSNative(cx, clasp->call, args.argc(), args.base()); + } + + /* Invoke native functions. */ + JSFunction *fun = callee.getFunctionPrivate(); + JS_ASSERT_IF(flags & JSINVOKE_CONSTRUCT, !fun->isConstructor()); + if (fun->isNative()) + return CallJSNative(cx, fun->u.n.native, args.argc(), args.base()); + + /* Handle the empty-script special case. */ + JSScript *script = fun->script(); + if (JS_UNLIKELY(script->isEmpty())) { + if (flags & JSINVOKE_CONSTRUCT) { + JSObject *obj = js_CreateThisForFunction(cx, &callee); + if (!obj) + return false; + args.rval().setObject(*obj); + } else { + args.rval().setUndefined(); + } + return true; + } + + /* Get pointer to new frame/slots, prepare arguments. */ + InvokeFrameGuard frame; + if (JS_UNLIKELY(!cx->stack().getInvokeFrame(cx, args, fun, script, &flags, &frame))) + return false; + + /* Initialize frame, locals. */ + JSStackFrame *fp = frame.fp(); + fp->initCallFrame(cx, callee, fun, args.argc(), flags); + SetValueRangeToUndefined(fp->slots(), script->nfixed); + + /* Officially push fp. frame's destructor pops. */ + cx->stack().pushInvokeFrame(cx, args, &frame); + + /* Now that the new frame is rooted, maybe create a call object. */ + if (fun->isHeavyweight() && !js_GetCallObject(cx, fp)) + return false; + + /* Run function until JSOP_STOP, JSOP_RETURN or error. */ + JSBool ok; + { + AutoPreserveEnumerators preserve(cx); + ok = RunScript(cx, script, fp); + } + + args.rval() = fp->returnValue(); + JS_ASSERT_IF(ok && (flags & JSINVOKE_CONSTRUCT), !args.rval().isPrimitive()); + + return ok; +} + +bool +InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &thisv, uintN argc) +{ +#ifdef JS_TRACER + if (TRACE_RECORDER(cx)) + AbortRecording(cx, "attempt to reenter VM while recording"); + LeaveTrace(cx); +#endif + + /* Always push arguments, regardless of optimized/normal invoke. */ + StackSpace &stack = cx->stack(); + if (!stack.pushInvokeArgs(cx, argc, &args_)) + return false; + + /* Callees may clobber 'this' or 'callee'. */ + savedCallee_ = args_.callee() = calleev; + savedThis_ = args_.thisv() = thisv; + + do { + /* Hoist dynamic checks from scripted Invoke. */ + if (!calleev.isObject()) + break; + JSObject &callee = calleev.toObject(); + if (callee.getClass() != &js_FunctionClass) + break; + JSFunction *fun = callee.getFunctionPrivate(); + if (fun->isNative()) + break; + script_ = fun->script(); + if (fun->isHeavyweight() || script_->isEmpty()) + break; + + /* + * The frame will remain pushed even when the callee isn't active which + * will affect the observable current global, so avoid any change. + */ + if (callee.getGlobal() != GetGlobalForScopeChain(cx)) + break; + + /* Push the stack frame once for the session. */ + uint32 flags = 0; + if (!stack.getInvokeFrame(cx, args_, fun, script_, &flags, &frame_)) + return false; + JSStackFrame *fp = frame_.fp(); + fp->initCallFrame(cx, calleev.toObject(), fun, argc, flags); + stack.pushInvokeFrame(cx, args_, &frame_); + +#ifdef JS_METHODJIT + /* Hoist dynamic checks from RunScript. */ + mjit::CompileStatus status = mjit::CanMethodJIT(cx, script_, fp, mjit::CompileRequest_JIT); + if (status == mjit::Compile_Error) + return false; + if (status != mjit::Compile_Okay) + break; + /* Cannot also cache the raw code pointer; it can change. */ + + /* Hoist dynamic checks from CheckStackAndEnterMethodJIT. */ + JS_CHECK_RECURSION(cx, return JS_FALSE); + stackLimit_ = stack.getStackLimit(cx); + if (!stackLimit_) + return false; + + stop_ = script_->code + script_->length - 1; + JS_ASSERT(*stop_ == JSOP_STOP); +#endif + + /* Cached to avoid canonicalActualArg in InvokeSessionGuard::operator[]. */ + nformals_ = fp->numFormalArgs(); + formals_ = fp->formalArgs(); + actuals_ = args_.argv(); + JS_ASSERT(actuals_ == fp->actualArgs()); + return true; + } while (0); + + /* + * Use the normal invoke path. + * + * The callee slot gets overwritten during an unoptimized Invoke, so we + * cache it here and restore it before every Invoke call. The 'this' value + * does not get overwritten, so we can fill it here once. + */ + if (frame_.pushed()) + frame_.pop(); + formals_ = actuals_ = args_.argv(); + nformals_ = (unsigned)-1; + return true; +} + +bool +ExternalInvoke(JSContext *cx, const Value &thisv, const Value &fval, + uintN argc, Value *argv, Value *rval) +{ + LeaveTrace(cx); + + InvokeArgsGuard args; + if (!cx->stack().pushInvokeArgs(cx, argc, &args)) + return false; + + args.callee() = fval; + args.thisv() = thisv; + memcpy(args.argv(), argv, argc * sizeof(Value)); + + if (args.thisv().isObject()) { + /* + * We must call the thisObject hook in case we are not called from the + * interpreter, where a prior bytecode has computed an appropriate + * |this| already. + */ + JSObject *thisp = args.thisv().toObject().thisObject(cx); + if (!thisp) + return false; + args.thisv().setObject(*thisp); + } + + if (!Invoke(cx, args, 0)) + return false; + + *rval = args.rval(); + return true; +} + +bool +ExternalInvokeConstructor(JSContext *cx, const Value &fval, uintN argc, Value *argv, + Value *rval) +{ + LeaveTrace(cx); + + InvokeArgsGuard args; + if (!cx->stack().pushInvokeArgs(cx, argc, &args)) + return false; + + args.callee() = fval; + args.thisv().setMagic(JS_THIS_POISON); + memcpy(args.argv(), argv, argc * sizeof(Value)); + + if (!InvokeConstructor(cx, args)) + return false; + + *rval = args.rval(); + return true; +} + +bool +ExternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, const Value &fval, + JSAccessMode mode, uintN argc, Value *argv, Value *rval) +{ + LeaveTrace(cx); + + /* + * ExternalInvoke could result in another try to get or set the same id + * again, see bug 355497. + */ + JS_CHECK_RECURSION(cx, return JS_FALSE); + + return ExternalInvoke(cx, ObjectValue(*obj), fval, argc, argv, rval); +} + +bool +Execute(JSContext *cx, JSObject *chain, JSScript *script, + JSStackFrame *prev, uintN flags, Value *result) +{ + JS_ASSERT(chain); + JS_ASSERT_IF(prev, !prev->isDummyFrame()); + + if (script->isEmpty()) { + if (result) + result->setUndefined(); + return true; + } + + LeaveTrace(cx); + + /* + * Get a pointer to new frame/slots. This memory is not "claimed", so the + * code before pushExecuteFrame must not reenter the interpreter. + */ + ExecuteFrameGuard frame; + if (!cx->stack().getExecuteFrame(cx, script, &frame)) + return false; + + /* Initialize fixed slots (GVAR ops expect NULL). */ + SetValueRangeToNull(frame.fp()->slots(), script->nfixed); + + /* Initialize frame and locals. */ + JSObject *initialVarObj; + if (prev) { + JS_ASSERT(chain == &prev->scopeChain()); + frame.fp()->initEvalFrame(cx, script, prev, flags); + + /* + * We want to call |prev->varobj()|, but this requires knowing the + * CallStackSegment of |prev|. If |prev == cx->fp()|, the callstack is + * simply the context's active callstack, so we can use + * |prev->varobj(cx)|. When |prev != cx->fp()|, we need to do a slow + * linear search. Luckily, this only happens with EvaluateInFrame. + */ + initialVarObj = (prev == cx->maybefp()) + ? &prev->varobj(cx) + : &prev->varobj(cx->containingSegment(prev)); + } else { + /* The scope chain could be anything, so innerize just in case. */ + JSObject *innerizedChain = chain; + OBJ_TO_INNER_OBJECT(cx, innerizedChain); + if (!innerizedChain) + return false; + + /* If we were handed a non-native object, complain bitterly. */ + if (!innerizedChain->isNative()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_NON_NATIVE_SCOPE); + return false; + } + + /* Initialize frame. */ + frame.fp()->initGlobalFrame(script, *innerizedChain, flags); + + /* Compute 'this'. */ + JSObject *thisp = chain->thisObject(cx); + if (!thisp) + return false; + frame.fp()->globalThis().setObject(*thisp); + + initialVarObj = cx->hasRunOption(JSOPTION_VAROBJFIX) ? chain->getGlobal() : chain; + } + + /* + * Strict mode eval code receives its own, fresh lexical environment; thus + * strict mode eval can't mutate its calling frame's binding set. + */ + if ((flags & JSFRAME_EVAL) && script->strictModeCode) { + AutoScriptRooter root(cx, script); + initialVarObj = NewCallObject(cx, &script->bindings, *initialVarObj, NULL); + if (!initialVarObj) + return false; + initialVarObj->setPrivate(frame.fp()); + + /* Clear the Call object propagated from the previous frame, if any. */ + if (frame.fp()->hasCallObj()) + frame.fp()->clearCallObj(); + frame.fp()->setScopeChainAndCallObj(*initialVarObj); + } + JS_ASSERT(!initialVarObj->getOps()->defineProperty); + +#if JS_HAS_SHARP_VARS + JS_STATIC_ASSERT(SHARP_NSLOTS == 2); + if (script->hasSharps) { + JS_ASSERT(script->nfixed >= SHARP_NSLOTS); + Value *sharps = &frame.fp()->slots()[script->nfixed - SHARP_NSLOTS]; + if (prev && prev->script()->hasSharps) { + JS_ASSERT(prev->numFixed() >= SHARP_NSLOTS); + int base = (prev->isFunctionFrame() && !prev->isEvalOrDebuggerFrame()) + ? prev->fun()->script()->bindings.sharpSlotBase(cx) + : prev->numFixed() - SHARP_NSLOTS; + if (base < 0) + return false; + sharps[0] = prev->slots()[base]; + sharps[1] = prev->slots()[base + 1]; + } else { + sharps[0].setUndefined(); + sharps[1].setUndefined(); + } + } +#endif + + /* Officially push |fp|. |frame|'s destructor pops. */ + cx->stack().pushExecuteFrame(cx, initialVarObj, &frame); + + /* Now that the frame has been pushed, we can call the thisObject hook. */ + if (!prev) { + JSObject *thisp = chain->thisObject(cx); + if (!thisp) + return false; + frame.fp()->globalThis().setObject(*thisp); + } + + Probes::startExecution(cx, script); + + /* Run script until JSOP_STOP or error. */ + AutoPreserveEnumerators preserve(cx); + JSBool ok = RunScript(cx, script, frame.fp()); + if (result) + *result = frame.fp()->returnValue(); + + Probes::stopExecution(cx, script); + + return !!ok; +} + +bool +CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs) +{ + JSObject *obj2; + JSProperty *prop; + uintN oldAttrs; + bool isFunction; + const char *type, *name; + + if (!obj->lookupProperty(cx, id, &obj2, &prop)) + return false; + if (!prop) + return true; + if (obj2->isNative()) { + oldAttrs = ((Shape *) prop)->attributes(); + } else { + if (!obj2->getAttributes(cx, id, &oldAttrs)) + return false; + } + + /* We allow redeclaring some non-readonly properties. */ + if (((oldAttrs | attrs) & JSPROP_READONLY) == 0) { + /* Allow redeclaration of variables and functions. */ + if (!(attrs & (JSPROP_GETTER | JSPROP_SETTER))) + return true; + + /* + * Allow adding a getter only if a property already has a setter + * but no getter and similarly for adding a setter. That is, we + * allow only the following transitions: + * + * no-property --> getter --> getter + setter + * no-property --> setter --> getter + setter + */ + if ((~(oldAttrs ^ attrs) & (JSPROP_GETTER | JSPROP_SETTER)) == 0) + return true; + + /* + * Allow redeclaration of an impermanent property (in which case + * anyone could delete it and redefine it, willy-nilly). + */ + if (!(oldAttrs & JSPROP_PERMANENT)) + return true; + } + + isFunction = (oldAttrs & (JSPROP_GETTER | JSPROP_SETTER)) != 0; + if (!isFunction) { + Value value; + if (!obj->getProperty(cx, id, &value)) + return JS_FALSE; + isFunction = IsFunctionObject(value); + } + + type = (oldAttrs & attrs & JSPROP_GETTER) + ? js_getter_str + : (oldAttrs & attrs & JSPROP_SETTER) + ? js_setter_str + : (oldAttrs & JSPROP_READONLY) + ? js_const_str + : isFunction + ? js_function_str + : js_var_str; + JSAutoByteString bytes; + name = js_ValueToPrintable(cx, IdToValue(id), &bytes); + if (!name) + return false; + JS_ALWAYS_FALSE(JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, + JSMSG_REDECLARED_VAR, type, name)); + return false; +} + +JSBool +HasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp) +{ + Class *clasp = obj->getClass(); + if (clasp->hasInstance) + return clasp->hasInstance(cx, obj, v, bp); + js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, + JSDVG_SEARCH_STACK, ObjectValue(*obj), NULL); + return JS_FALSE; +} + +bool +StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, JSBool *equal) +{ + Value lval = lref, rval = rref; + if (SameType(lval, rval)) { + if (lval.isString()) + return EqualStrings(cx, lval.toString(), rval.toString(), equal); + if (lval.isDouble()) { + *equal = JSDOUBLE_COMPARE(lval.toDouble(), ==, rval.toDouble(), JS_FALSE); + return true; + } + if (lval.isObject()) { + *equal = &lval.toObject() == &rval.toObject(); + return true; + } + if (lval.isUndefined()) { + *equal = true; + return true; + } + *equal = lval.payloadAsRawUint32() == rval.payloadAsRawUint32(); + return true; + } + + if (lval.isDouble() && rval.isInt32()) { + double ld = lval.toDouble(); + double rd = rval.toInt32(); + *equal = JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE); + return true; + } + if (lval.isInt32() && rval.isDouble()) { + double ld = lval.toInt32(); + double rd = rval.toDouble(); + *equal = JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE); + return true; + } + + *equal = false; + return true; +} + +static inline bool +IsNegativeZero(const Value &v) +{ + return v.isDouble() && JSDOUBLE_IS_NEGZERO(v.toDouble()); +} + +static inline bool +IsNaN(const Value &v) +{ + return v.isDouble() && JSDOUBLE_IS_NaN(v.toDouble()); +} + +bool +SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same) +{ + if (IsNegativeZero(v1)) { + *same = IsNegativeZero(v2); + return true; + } + if (IsNegativeZero(v2)) { + *same = false; + return true; + } + if (IsNaN(v1) && IsNaN(v2)) { + *same = true; + return true; + } + return StrictlyEqual(cx, v1, v2, same); +} + +JSType +TypeOfValue(JSContext *cx, const Value &vref) +{ + Value v = vref; + if (v.isNumber()) + return JSTYPE_NUMBER; + if (v.isString()) + return JSTYPE_STRING; + if (v.isNull()) + return JSTYPE_OBJECT; + if (v.isUndefined()) + return JSTYPE_VOID; + if (v.isObject()) + return v.toObject().typeOf(cx); + JS_ASSERT(v.isBoolean()); + return JSTYPE_BOOLEAN; +} + +bool +InstanceOfSlow(JSContext *cx, JSObject *obj, Class *clasp, Value *argv) +{ + JS_ASSERT(!obj || obj->getClass() != clasp); + if (argv) { + JSFunction *fun = js_ValueToFunction(cx, &argv[-2], 0); + if (fun) { + JSAutoByteString funNameBytes; + if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO, + clasp->name, funName, + obj ? obj->getClass()->name : js_null_str); + } + } + } + return false; +} + +JS_REQUIRES_STACK bool +InvokeConstructor(JSContext *cx, const CallArgs &argsRef) +{ + JS_ASSERT(!js_FunctionClass.construct); + CallArgs args = argsRef; + + JSObject *callee; + if (args.callee().isPrimitive() || !(callee = &args.callee().toObject())->getParent()) { + js_ReportIsNotFunction(cx, &args.callee(), JSV2F_CONSTRUCT); + return false; + } + + /* Handle the fast-constructors cases before falling into the general case . */ + Class *clasp = callee->getClass(); + JSFunction *fun = NULL; + if (clasp == &js_FunctionClass) { + fun = callee->getFunctionPrivate(); + if (fun->isConstructor()) { + args.thisv().setMagicWithObjectOrNullPayload(NULL); + return CallJSNativeConstructor(cx, fun->u.n.native, args.argc(), args.base()); + } + } else if (clasp->construct) { + args.thisv().setMagicWithObjectOrNullPayload(NULL); + return CallJSNativeConstructor(cx, clasp->construct, args.argc(), args.base()); + } + + /* Scripts create their own |this| in JSOP_BEGIN */ + if (!fun || !fun->isInterpreted()) { + JSObject *obj = js_CreateThis(cx, callee); + if (!obj) + return false; + args.thisv().setObject(*obj); + } + + if (!Invoke(cx, args, JSINVOKE_CONSTRUCT)) + return false; + + if (args.rval().isPrimitive()) { + if (clasp != &js_FunctionClass) { + /* native [[Construct]] returning primitive is error */ + JSAutoByteString bytes; + if (js_ValueToPrintable(cx, args.rval(), &bytes)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_NEW_RESULT, bytes.ptr()); + return false; + } + } + + /* The interpreter fixes rval for us. */ + JS_ASSERT(!fun->isInterpreted()); + + args.rval() = args.thisv(); + } + + JS_RUNTIME_METER(cx->runtime, constructs); + return true; +} + +bool +InvokeConstructorWithGivenThis(JSContext *cx, JSObject *thisobj, const Value &fval, + uintN argc, Value *argv, Value *rval) +{ + LeaveTrace(cx); + + InvokeArgsGuard args; + if (!cx->stack().pushInvokeArgs(cx, argc, &args)) + return JS_FALSE; + + args.callee() = fval; + /* Initialize args.thisv on all paths below. */ + memcpy(args.argv(), argv, argc * sizeof(Value)); + + /* Handle the fast-constructor cases before calling the general case. */ + JSObject &callee = fval.toObject(); + Class *clasp = callee.getClass(); + JSFunction *fun; + bool ok; + if (clasp == &js_FunctionClass && (fun = callee.getFunctionPrivate())->isConstructor()) { + args.thisv().setMagicWithObjectOrNullPayload(thisobj); + ok = CallJSNativeConstructor(cx, fun->u.n.native, args.argc(), args.base()); + } else if (clasp->construct) { + args.thisv().setMagicWithObjectOrNullPayload(thisobj); + ok = CallJSNativeConstructor(cx, clasp->construct, args.argc(), args.base()); + } else { + args.thisv().setObjectOrNull(thisobj); + ok = Invoke(cx, args, JSINVOKE_CONSTRUCT); + } + + *rval = args.rval(); + return ok; +} + +bool +DirectEval(JSContext *cx, JSFunction *evalfun, uint32 argc, Value *vp) +{ + JS_ASSERT(vp == cx->regs->sp - argc - 2); + JS_ASSERT(vp[0].isObject()); + JS_ASSERT(vp[0].toObject().isFunction()); + JS_ASSERT(vp[0].toObject().getFunctionPrivate() == evalfun); + JS_ASSERT(IsBuiltinEvalFunction(evalfun)); + + JSStackFrame *caller = cx->fp(); + JS_ASSERT(caller->isScriptFrame()); + AutoFunctionCallProbe callProbe(cx, evalfun, caller->script()); + + JSObject *scopeChain = + GetScopeChainFast(cx, caller, JSOP_EVAL, JSOP_EVAL_LENGTH + JSOP_LINENO_LENGTH); + if (!scopeChain || !EvalKernel(cx, argc, vp, DIRECT_EVAL, caller, scopeChain)) + return false; + cx->regs->sp = vp + 1; + return true; +} + +bool +ValueToId(JSContext *cx, const Value &v, jsid *idp) +{ + int32_t i; + if (ValueFitsInInt32(v, &i) && INT_FITS_IN_JSID(i)) { + *idp = INT_TO_JSID(i); + return true; + } + +#if JS_HAS_XML_SUPPORT + if (v.isObject()) { + JSObject *obj = &v.toObject(); + if (obj->isXMLId()) { + *idp = OBJECT_TO_JSID(obj); + return JS_TRUE; + } + } +#endif + + return js_ValueToStringId(cx, v, idp); +} + +} /* namespace js */ + +/* + * Enter the new with scope using an object at sp[-1] and associate the depth + * of the with block with sp + stackIndex. + */ +JS_STATIC_INTERPRET JS_REQUIRES_STACK JSBool +js_EnterWith(JSContext *cx, jsint stackIndex, JSOp op, size_t oplen) +{ + JSStackFrame *fp = cx->fp(); + Value *sp = cx->regs->sp; + JS_ASSERT(stackIndex < 0); + JS_ASSERT(fp->base() <= sp + stackIndex); + + JSObject *obj; + if (sp[-1].isObject()) { + obj = &sp[-1].toObject(); + } else { + obj = js_ValueToNonNullObject(cx, sp[-1]); + if (!obj) + return JS_FALSE; + sp[-1].setObject(*obj); + } + + JSObject *parent = GetScopeChainFast(cx, fp, op, oplen); + if (!parent) + return JS_FALSE; + + OBJ_TO_INNER_OBJECT(cx, obj); + if (!obj) + return JS_FALSE; + + JSObject *withobj = js_NewWithObject(cx, obj, parent, + sp + stackIndex - fp->base()); + if (!withobj) + return JS_FALSE; + + fp->setScopeChainNoCallObj(*withobj); + return JS_TRUE; +} + +JS_STATIC_INTERPRET JS_REQUIRES_STACK void +js_LeaveWith(JSContext *cx) +{ + JSObject *withobj; + + withobj = &cx->fp()->scopeChain(); + JS_ASSERT(withobj->getClass() == &js_WithClass); + JS_ASSERT(withobj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp())); + JS_ASSERT(OBJ_BLOCK_DEPTH(cx, withobj) >= 0); + withobj->setPrivate(NULL); + cx->fp()->setScopeChainNoCallObj(*withobj->getParent()); +} + +JS_REQUIRES_STACK Class * +js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth) +{ + Class *clasp; + + clasp = obj->getClass(); + if ((clasp == &js_WithClass || clasp == &js_BlockClass) && + obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()) && + OBJ_BLOCK_DEPTH(cx, obj) >= stackDepth) { + return clasp; + } + return NULL; +} + +/* + * Unwind block and scope chains to match the given depth. The function sets + * fp->sp on return to stackDepth. + */ +JS_REQUIRES_STACK JSBool +js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind) +{ + Class *clasp; + + JS_ASSERT(stackDepth >= 0); + JS_ASSERT(cx->fp()->base() + stackDepth <= cx->regs->sp); + + JSStackFrame *fp = cx->fp(); + for (;;) { + clasp = js_IsActiveWithOrBlock(cx, &fp->scopeChain(), stackDepth); + if (!clasp) + break; + if (clasp == &js_BlockClass) { + /* Don't fail until after we've updated all stacks. */ + normalUnwind &= js_PutBlockObject(cx, normalUnwind); + } else { + js_LeaveWith(cx); + } + } + + cx->regs->sp = fp->base() + stackDepth; + return normalUnwind; +} + +JS_STATIC_INTERPRET JSBool +js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, Value *vp, Value *vp2) +{ + if (cs->format & JOF_POST) { + double d; + if (!ValueToNumber(cx, *vp, &d)) + return JS_FALSE; + vp->setNumber(d); + (cs->format & JOF_INC) ? ++d : --d; + vp2->setNumber(d); + return JS_TRUE; + } + + double d; + if (!ValueToNumber(cx, *vp, &d)) + return JS_FALSE; + (cs->format & JOF_INC) ? ++d : --d; + vp->setNumber(d); + *vp2 = *vp; + return JS_TRUE; +} + +const Value & +js::GetUpvar(JSContext *cx, uintN closureLevel, UpvarCookie cookie) +{ + JS_ASSERT(closureLevel >= cookie.level() && cookie.level() > 0); + const uintN targetLevel = closureLevel - cookie.level(); + JS_ASSERT(targetLevel < UpvarCookie::UPVAR_LEVEL_LIMIT); + + JSStackFrame *fp = cx->findFrameAtLevel(targetLevel); + uintN slot = cookie.slot(); + Value *vp; + + if (!fp->isFunctionFrame() || fp->isEvalFrame()) { + vp = fp->slots() + fp->numFixed(); + } else if (slot < fp->numFormalArgs()) { + vp = fp->formalArgs(); + } else if (slot == UpvarCookie::CALLEE_SLOT) { + vp = &fp->calleeValue(); + slot = 0; + } else { + slot -= fp->numFormalArgs(); + JS_ASSERT(slot < fp->numSlots()); + vp = fp->slots(); + } + + return vp[slot]; +} + +#ifdef DEBUG + +JS_STATIC_INTERPRET JS_REQUIRES_STACK void +js_LogOpcode(JSContext *cx) +{ + FILE *logfp; + JSStackFrame *fp; + JSFrameRegs *regs; + intN ndefs, n, nuses; + JSOp op; + + logfp = (FILE *) cx->logfp; + JS_ASSERT(logfp); + fp = cx->fp(); + regs = cx->regs; + + /* + * Operations in prologues don't produce interesting values, and + * js_DecompileValueGenerator isn't set up to handle them anyway. + */ + if (cx->logPrevPc && regs->pc >= fp->script()->main) { + JSOp logPrevOp = JSOp(*cx->logPrevPc); + ndefs = js_GetStackDefs(cx, &js_CodeSpec[logPrevOp], logPrevOp, + fp->script(), cx->logPrevPc); + + /* + * If there aren't that many elements on the stack, then we have + * probably entered a new frame, and printing output would just be + * misleading. + */ + if (ndefs != 0 && + ndefs < regs->sp - fp->slots()) { + for (n = -ndefs; n < 0; n++) { + char *bytes = DecompileValueGenerator(cx, n, regs->sp[n], NULL); + if (bytes) { + fprintf(logfp, "%s %s", + (n == -ndefs) ? " output:" : ",", + bytes); + cx->free(bytes); + } else { + JS_ClearPendingException(cx); + } + } + fprintf(logfp, " @ %u\n", (uintN) (regs->sp - fp->base())); + } + fprintf(logfp, " stack: "); + for (Value *siter = fp->base(); siter < regs->sp; siter++) { + if (siter->isObject() && siter->toObject().getClass() == &js_CallClass) { + /* + * Call objects have NULL convert ops so that we catch cases + * where they escape. So js_ValueToString doesn't work on them. + */ + fputs("", logfp); + } else { + JSString *str = js_ValueToString(cx, *siter); + JSLinearString *linearStr = str ? str->ensureLinear(cx) : NULL; + if (!linearStr) { + fputs("", logfp); + JS_ClearPendingException(cx); + } else { + FileEscapedString(logfp, linearStr, 0); + } + } + fputc(' ', logfp); + } + fputc('\n', logfp); + } + + fprintf(logfp, "%4u: ", + js_PCToLineNumber(cx, fp->script(), + fp->hasImacropc() ? fp->imacropc() : regs->pc)); + js_Disassemble1(cx, fp->script(), regs->pc, + regs->pc - fp->script()->code, + JS_FALSE, logfp); + op = (JSOp) *regs->pc; + nuses = js_GetStackUses(&js_CodeSpec[op], op, regs->pc); + if (nuses != 0) { + for (n = -nuses; n < 0; n++) { + char *bytes = DecompileValueGenerator(cx, n, regs->sp[n], NULL); + if (bytes) { + fprintf(logfp, "%s %s", + (n == -nuses) ? " inputs:" : ",", + bytes); + cx->free(bytes); + } else { + JS_ClearPendingException(cx); + } + } + fprintf(logfp, " @ %u\n", (uintN) (regs->sp - fp->base())); + } + cx->logPrevPc = regs->pc; + + /* It's nice to have complete logs when debugging a crash. */ + fflush(logfp); +} + +#endif /* DEBUG */ + +#ifdef JS_OPMETER + +# include + +# define HIST_NSLOTS 8 + +/* + * The second dimension is hardcoded at 256 because we know that many bits fit + * in a byte, and mainly to optimize away multiplying by JSOP_LIMIT to address + * any particular row. + */ +static uint32 succeeds[JSOP_LIMIT][256]; +static uint32 slot_ops[JSOP_LIMIT][HIST_NSLOTS]; + +JS_STATIC_INTERPRET void +js_MeterOpcodePair(JSOp op1, JSOp op2) +{ + if (op1 != JSOP_STOP) + ++succeeds[op1][op2]; +} + +JS_STATIC_INTERPRET void +js_MeterSlotOpcode(JSOp op, uint32 slot) +{ + if (slot < HIST_NSLOTS) + ++slot_ops[op][slot]; +} + +typedef struct Edge { + const char *from; + const char *to; + uint32 count; +} Edge; + +static int +compare_edges(const void *a, const void *b) +{ + const Edge *ea = (const Edge *) a; + const Edge *eb = (const Edge *) b; + + return (int32)eb->count - (int32)ea->count; +} + +void +js_DumpOpMeters() +{ + const char *name, *from, *style; + FILE *fp; + uint32 total, count; + uint32 i, j, nedges; + Edge *graph; + + name = getenv("JS_OPMETER_FILE"); + if (!name) + name = "/tmp/ops.dot"; + fp = fopen(name, "w"); + if (!fp) { + perror(name); + return; + } + + total = nedges = 0; + for (i = 0; i < JSOP_LIMIT; i++) { + for (j = 0; j < JSOP_LIMIT; j++) { + count = succeeds[i][j]; + if (count != 0) { + total += count; + ++nedges; + } + } + } + +# define SIGNIFICANT(count,total) (200. * (count) >= (total)) + + graph = (Edge *) js_calloc(nedges * sizeof graph[0]); + if (!graph) + return; + for (i = nedges = 0; i < JSOP_LIMIT; i++) { + from = js_CodeName[i]; + for (j = 0; j < JSOP_LIMIT; j++) { + count = succeeds[i][j]; + if (count != 0 && SIGNIFICANT(count, total)) { + graph[nedges].from = from; + graph[nedges].to = js_CodeName[j]; + graph[nedges].count = count; + ++nedges; + } + } + } + qsort(graph, nedges, sizeof(Edge), compare_edges); + +# undef SIGNIFICANT + + fputs("digraph {\n", fp); + for (i = 0, style = NULL; i < nedges; i++) { + JS_ASSERT(i == 0 || graph[i-1].count >= graph[i].count); + if (!style || graph[i-1].count != graph[i].count) { + style = (i > nedges * .75) ? "dotted" : + (i > nedges * .50) ? "dashed" : + (i > nedges * .25) ? "solid" : "bold"; + } + fprintf(fp, " %s -> %s [label=\"%lu\" style=%s]\n", + graph[i].from, graph[i].to, + (unsigned long)graph[i].count, style); + } + js_free(graph); + fputs("}\n", fp); + fclose(fp); + + name = getenv("JS_OPMETER_HIST"); + if (!name) + name = "/tmp/ops.hist"; + fp = fopen(name, "w"); + if (!fp) { + perror(name); + return; + } + fputs("bytecode", fp); + for (j = 0; j < HIST_NSLOTS; j++) + fprintf(fp, " slot %1u", (unsigned)j); + putc('\n', fp); + fputs("========", fp); + for (j = 0; j < HIST_NSLOTS; j++) + fputs(" =======", fp); + putc('\n', fp); + for (i = 0; i < JSOP_LIMIT; i++) { + for (j = 0; j < HIST_NSLOTS; j++) { + if (slot_ops[i][j] != 0) { + /* Reuse j in the next loop, since we break after. */ + fprintf(fp, "%-8.8s", js_CodeName[i]); + for (j = 0; j < HIST_NSLOTS; j++) + fprintf(fp, " %7lu", (unsigned long)slot_ops[i][j]); + putc('\n', fp); + break; + } + } + } + fclose(fp); +} + +#endif /* JS_OPSMETER */ + +#endif /* !JS_LONE_INTERPRET ^ defined jsinvoke_cpp___ */ + +#ifndef jsinvoke_cpp___ + +#ifdef JS_REPRMETER +// jsval representation metering: this measures the kinds of jsvals that +// are used as inputs to each JSOp. +namespace reprmeter { + enum Repr { + NONE, + INT, + DOUBLE, + BOOLEAN_PROPER, + BOOLEAN_OTHER, + STRING, + OBJECT_NULL, + OBJECT_PLAIN, + FUNCTION_INTERPRETED, + FUNCTION_FASTNATIVE, + ARRAY_SLOW, + ARRAY_DENSE + }; + + // Return the |repr| value giving the representation of the given jsval. + static Repr + GetRepr(jsval v) + { + if (JSVAL_IS_INT(v)) + return INT; + if (JSVAL_IS_DOUBLE(v)) + return DOUBLE; + if (JSVAL_IS_SPECIAL(v)) { + return (v == JSVAL_TRUE || v == JSVAL_FALSE) + ? BOOLEAN_PROPER + : BOOLEAN_OTHER; + } + if (JSVAL_IS_STRING(v)) + return STRING; + + JS_ASSERT(JSVAL_IS_OBJECT(v)); + + JSObject *obj = JSVAL_TO_OBJECT(v); + if (VALUE_IS_FUNCTION(cx, v)) { + JSFunction *fun = obj->getFunctionPrivate(); + if (FUN_INTERPRETED(fun)) + return FUNCTION_INTERPRETED; + return FUNCTION_FASTNATIVE; + } + // This must come before the general array test, because that + // one subsumes this one. + if (!obj) + return OBJECT_NULL; + if (obj->isDenseArray()) + return ARRAY_DENSE; + if (obj->isArray()) + return ARRAY_SLOW; + return OBJECT_PLAIN; + } + + static const char *reprName[] = { "invalid", "int", "double", "bool", "special", + "string", "null", "object", + "fun:interp", "fun:native" + "array:slow", "array:dense" }; + + // Logically, a tuple of (JSOp, repr_1, ..., repr_n) where repr_i is + // the |repr| of the ith input to the JSOp. + struct OpInput { + enum { max_uses = 16 }; + + JSOp op; + Repr uses[max_uses]; + + OpInput() : op(JSOp(255)) { + for (int i = 0; i < max_uses; ++i) + uses[i] = NONE; + } + + OpInput(JSOp op) : op(op) { + for (int i = 0; i < max_uses; ++i) + uses[i] = NONE; + } + + // Hash function + operator uint32() const { + uint32 h = op; + for (int i = 0; i < max_uses; ++i) + h = h * 7 + uses[i] * 13; + return h; + } + + bool operator==(const OpInput &opinput) const { + if (op != opinput.op) + return false; + for (int i = 0; i < max_uses; ++i) { + if (uses[i] != opinput.uses[i]) + return false; + } + return true; + } + + OpInput &operator=(const OpInput &opinput) { + op = opinput.op; + for (int i = 0; i < max_uses; ++i) + uses[i] = opinput.uses[i]; + return *this; + } + }; + + typedef HashMap, SystemAllocPolicy> OpInputHistogram; + + OpInputHistogram opinputs; + bool opinputsInitialized = false; + + // Record an OpInput for the current op. This should be called just + // before executing the op. + static void + MeterRepr(JSContext *cx) + { + // Note that we simply ignore the possibility of errors (OOMs) + // using the hash map, since this is only metering code. + + if (!opinputsInitialized) { + opinputs.init(); + opinputsInitialized = true; + } + + JSOp op = JSOp(*cx->regs->pc); + int nuses = js_GetStackUses(&js_CodeSpec[op], op, cx->regs->pc); + + // Build the OpInput. + OpInput opinput(op); + for (int i = 0; i < nuses; ++i) { + jsval v = cx->regs->sp[-nuses+i]; + opinput.uses[i] = GetRepr(v); + } + + OpInputHistogram::AddPtr p = opinputs.lookupForAdd(opinput); + if (p) + ++p->value; + else + opinputs.add(p, opinput, 1); + } + + void + js_DumpReprMeter() + { + FILE *f = fopen("/tmp/reprmeter.txt", "w"); + JS_ASSERT(f); + for (OpInputHistogram::Range r = opinputs.all(); !r.empty(); r.popFront()) { + const OpInput &o = r.front().key; + uint64 c = r.front().value; + fprintf(f, "%3d,%s", o.op, js_CodeName[o.op]); + for (int i = 0; i < OpInput::max_uses && o.uses[i] != NONE; ++i) + fprintf(f, ",%s", reprName[o.uses[i]]); + fprintf(f, ",%llu\n", c); + } + fclose(f); + } +} +#endif /* JS_REPRMETER */ + +#define PUSH_COPY(v) do { *regs.sp++ = v; assertSameCompartment(cx, regs.sp[-1]); } while (0) +#define PUSH_NULL() regs.sp++->setNull() +#define PUSH_UNDEFINED() regs.sp++->setUndefined() +#define PUSH_BOOLEAN(b) regs.sp++->setBoolean(b) +#define PUSH_DOUBLE(d) regs.sp++->setDouble(d) +#define PUSH_INT32(i) regs.sp++->setInt32(i) +#define PUSH_STRING(s) do { regs.sp++->setString(s); assertSameCompartment(cx, regs.sp[-1]); } while (0) +#define PUSH_OBJECT(obj) do { regs.sp++->setObject(obj); assertSameCompartment(cx, regs.sp[-1]); } while (0) +#define PUSH_OBJECT_OR_NULL(obj) do { regs.sp++->setObjectOrNull(obj); assertSameCompartment(cx, regs.sp[-1]); } while (0) +#define PUSH_HOLE() regs.sp++->setMagic(JS_ARRAY_HOLE) +#define POP_COPY_TO(v) v = *--regs.sp +#define POP_RETURN_VALUE() regs.fp->setReturnValue(*--regs.sp) + +#define POP_BOOLEAN(cx, vp, b) \ + JS_BEGIN_MACRO \ + vp = ®s.sp[-1]; \ + if (vp->isNull()) { \ + b = false; \ + } else if (vp->isBoolean()) { \ + b = vp->toBoolean(); \ + } else { \ + b = !!js_ValueToBoolean(*vp); \ + } \ + regs.sp--; \ + JS_END_MACRO + +#define VALUE_TO_OBJECT(cx, vp, obj) \ + JS_BEGIN_MACRO \ + if ((vp)->isObject()) { \ + obj = &(vp)->toObject(); \ + } else { \ + obj = js_ValueToNonNullObject(cx, *(vp)); \ + if (!obj) \ + goto error; \ + (vp)->setObject(*obj); \ + } \ + JS_END_MACRO + +#define FETCH_OBJECT(cx, n, obj) \ + JS_BEGIN_MACRO \ + Value *vp_ = ®s.sp[n]; \ + VALUE_TO_OBJECT(cx, vp_, obj); \ + JS_END_MACRO + +#define DEFAULT_VALUE(cx, n, hint, v) \ + JS_BEGIN_MACRO \ + JS_ASSERT(v.isObject()); \ + JS_ASSERT(v == regs.sp[n]); \ + if (!DefaultValue(cx, &v.toObject(), hint, ®s.sp[n])) \ + goto error; \ + v = regs.sp[n]; \ + JS_END_MACRO + +/* Test whether v is an int in the range [-2^31 + 1, 2^31 - 2] */ +static JS_ALWAYS_INLINE bool +CanIncDecWithoutOverflow(int32_t i) +{ + return (i > JSVAL_INT_MIN) && (i < JSVAL_INT_MAX); +} + +/* + * Define JS_OPMETER to instrument bytecode succession, generating a .dot file + * on shutdown that shows the graph of significant predecessor/successor pairs + * executed, where the edge labels give the succession counts. The .dot file + * is named by the JS_OPMETER_FILE envariable, and defaults to /tmp/ops.dot. + * + * Bonus feature: JS_OPMETER also enables counters for stack-addressing ops + * such as JSOP_GETLOCAL, JSOP_INCARG, via METER_SLOT_OP. The resulting counts + * are written to JS_OPMETER_HIST, defaulting to /tmp/ops.hist. + */ +#ifndef JS_OPMETER +# define METER_OP_INIT(op) /* nothing */ +# define METER_OP_PAIR(op1,op2) /* nothing */ +# define METER_SLOT_OP(op,slot) /* nothing */ +#else + +/* + * The second dimension is hardcoded at 256 because we know that many bits fit + * in a byte, and mainly to optimize away multiplying by JSOP_LIMIT to address + * any particular row. + */ +# define METER_OP_INIT(op) ((op) = JSOP_STOP) +# define METER_OP_PAIR(op1,op2) (js_MeterOpcodePair(op1, op2)) +# define METER_SLOT_OP(op,slot) (js_MeterSlotOpcode(op, slot)) + +#endif + +#ifdef JS_REPRMETER +# define METER_REPR(cx) (reprmeter::MeterRepr(cx)) +#else +# define METER_REPR(cx) ((void) 0) +#endif /* JS_REPRMETER */ + +/* + * Threaded interpretation via computed goto appears to be well-supported by + * GCC 3 and higher. IBM's C compiler when run with the right options (e.g., + * -qlanglvl=extended) also supports threading. Ditto the SunPro C compiler. + * Currently it's broken for JS_VERSION < 160, though this isn't worth fixing. + * Add your compiler support macros here. + */ +#ifndef JS_THREADED_INTERP +# if JS_VERSION >= 160 && ( \ + __GNUC__ >= 3 || \ + (__IBMC__ >= 700 && defined __IBM_COMPUTED_GOTO) || \ + __SUNPRO_C >= 0x570) +# define JS_THREADED_INTERP 1 +# else +# define JS_THREADED_INTERP 0 +# endif +#endif + +/* + * Deadlocks or else bad races are likely if JS_THREADSAFE, so we must rely on + * single-thread DEBUG js shell testing to verify property cache hits. + */ +#if defined DEBUG && !defined JS_THREADSAFE + +# define ASSERT_VALID_PROPERTY_CACHE_HIT(pcoff,obj,pobj,entry) \ + JS_BEGIN_MACRO \ + if (!AssertValidPropertyCacheHit(cx, script, regs, pcoff, obj, pobj, \ + entry)) { \ + goto error; \ + } \ + JS_END_MACRO + +static bool +AssertValidPropertyCacheHit(JSContext *cx, JSScript *script, JSFrameRegs& regs, + ptrdiff_t pcoff, JSObject *start, JSObject *found, + PropertyCacheEntry *entry) +{ + uint32 sample = cx->runtime->gcNumber; + + JSAtom *atom; + if (pcoff >= 0) + GET_ATOM_FROM_BYTECODE(script, regs.pc, pcoff, atom); + else + atom = cx->runtime->atomState.lengthAtom; + + JSObject *obj, *pobj; + JSProperty *prop; + JSBool ok; + + if (JOF_OPMODE(*regs.pc) == JOF_NAME) { + ok = js_FindProperty(cx, ATOM_TO_JSID(atom), &obj, &pobj, &prop); + } else { + obj = start; + ok = js_LookupProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop); + } + if (!ok) + return false; + if (cx->runtime->gcNumber != sample || entry->vshape() != pobj->shape()) + return true; + JS_ASSERT(prop); + JS_ASSERT(pobj == found); + + const Shape *shape = (Shape *) prop; + if (entry->vword.isSlot()) { + JS_ASSERT(entry->vword.toSlot() == shape->slot); + JS_ASSERT(!shape->isMethod()); + } else if (entry->vword.isShape()) { + JS_ASSERT(entry->vword.toShape() == shape); + JS_ASSERT_IF(shape->isMethod(), + &shape->methodObject() == &pobj->nativeGetSlot(shape->slot).toObject()); + } else { + Value v; + JS_ASSERT(entry->vword.isFunObj()); + JS_ASSERT(!entry->vword.isNull()); + JS_ASSERT(pobj->brandedOrHasMethodBarrier()); + JS_ASSERT(shape->hasDefaultGetterOrIsMethod()); + JS_ASSERT(pobj->containsSlot(shape->slot)); + v = pobj->nativeGetSlot(shape->slot); + JS_ASSERT(&entry->vword.toFunObj() == &v.toObject()); + + if (shape->isMethod()) { + JS_ASSERT(js_CodeSpec[*regs.pc].format & JOF_CALLOP); + JS_ASSERT(&shape->methodObject() == &v.toObject()); + } + } + + return true; +} + +#else +# define ASSERT_VALID_PROPERTY_CACHE_HIT(pcoff,obj,pobj,entry) ((void) 0) +#endif + +/* + * Ensure that the intrepreter switch can close call-bytecode cases in the + * same way as non-call bytecodes. + */ +JS_STATIC_ASSERT(JSOP_NAME_LENGTH == JSOP_CALLNAME_LENGTH); +JS_STATIC_ASSERT(JSOP_GETUPVAR_DBG_LENGTH == JSOP_GETFCSLOT_LENGTH); +JS_STATIC_ASSERT(JSOP_GETUPVAR_DBG_LENGTH == JSOP_CALLUPVAR_DBG_LENGTH); +JS_STATIC_ASSERT(JSOP_GETFCSLOT_LENGTH == JSOP_CALLFCSLOT_LENGTH); +JS_STATIC_ASSERT(JSOP_GETARG_LENGTH == JSOP_CALLARG_LENGTH); +JS_STATIC_ASSERT(JSOP_GETLOCAL_LENGTH == JSOP_CALLLOCAL_LENGTH); +JS_STATIC_ASSERT(JSOP_XMLNAME_LENGTH == JSOP_CALLXMLNAME_LENGTH); + +/* + * Same for debuggable flat closures defined at top level in another function + * or program fragment. + */ +JS_STATIC_ASSERT(JSOP_DEFFUN_FC_LENGTH == JSOP_DEFFUN_DBGFC_LENGTH); + +/* + * Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but + * remain distinct for the decompiler. Likewise for JSOP_INIT{PROP,METHOD}. + */ +JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH); +JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETMETHOD_LENGTH); +JS_STATIC_ASSERT(JSOP_INITPROP_LENGTH == JSOP_INITMETHOD_LENGTH); + +/* See TRY_BRANCH_AFTER_COND. */ +JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH); +JS_STATIC_ASSERT(JSOP_IFNE == JSOP_IFEQ + 1); + +/* For the fastest case inder JSOP_INCNAME, etc. */ +JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_DECNAME_LENGTH); +JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEINC_LENGTH); +JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEDEC_LENGTH); + +#ifdef JS_TRACER +# define ABORT_RECORDING(cx, reason) \ + JS_BEGIN_MACRO \ + if (TRACE_RECORDER(cx)) \ + AbortRecording(cx, reason); \ + JS_END_MACRO +#else +# define ABORT_RECORDING(cx, reason) ((void) 0) +#endif + +/* + * Inline fast paths for iteration. js_IteratorMore and js_IteratorNext handle + * all cases, but we inline the most frequently taken paths here. + */ +static inline bool +IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, Value *rval) +{ + if (iterobj->getClass() == &js_IteratorClass) { + NativeIterator *ni = (NativeIterator *) iterobj->getPrivate(); + if (ni->isKeyIter()) { + *cond = (ni->props_cursor < ni->props_end); + return true; + } + } + if (!js_IteratorMore(cx, iterobj, rval)) + return false; + *cond = rval->isTrue(); + return true; +} + +static inline bool +IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval) +{ + if (iterobj->getClass() == &js_IteratorClass) { + NativeIterator *ni = (NativeIterator *) iterobj->getPrivate(); + if (ni->isKeyIter()) { + JS_ASSERT(ni->props_cursor < ni->props_end); + jsid id = *ni->current(); + if (JSID_IS_ATOM(id)) { + rval->setString(JSID_TO_STRING(id)); + ni->incCursor(); + return true; + } + /* Take the slow path if we have to stringify a numeric property name. */ + } + } + return js_IteratorNext(cx, iterobj, rval); +} + +static inline bool +ScriptPrologue(JSContext *cx, JSStackFrame *fp) +{ + if (fp->isConstructing()) { + JSObject *obj = js_CreateThisForFunction(cx, &fp->callee()); + if (!obj) + return false; + fp->functionThis().setObject(*obj); + } + if (fp->isExecuteFrame()) { + if (JSInterpreterHook hook = cx->debugHooks->executeHook) + fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->executeHookData)); + } else { + if (JSInterpreterHook hook = cx->debugHooks->callHook) + fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData)); + Probes::enterJSFun(cx, fp->maybeFun(), fp->maybeScript()); + } + + return true; +} + +namespace js { + +#ifdef __APPLE__ +static JS_NEVER_INLINE bool +NEVER_INLINE_ComputeImplicitThis(JSContext *cx, JSObject *obj, const Value &funval, Value *vp) +{ + return ComputeImplicitThis(cx, obj, funval, vp); +} +#define ComputeImplicitThis(cx, obj, funval, vp) NEVER_INLINE_ComputeImplicitThis(cx, obj, funval, vp) +#endif + +JS_REQUIRES_STACK JS_NEVER_INLINE bool +Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInterpMode interpMode) +{ +#ifdef MOZ_TRACEVIS + TraceVisStateObj tvso(cx, S_INTERP); +#endif + JSAutoResolveFlags rf(cx, JSRESOLVE_INFER); + +# ifdef DEBUG + /* + * We call this macro from BEGIN_CASE in threaded interpreters, + * and before entering the switch in non-threaded interpreters. + * However, reaching such points doesn't mean we've actually + * fetched an OP from the instruction stream: some opcodes use + * 'op=x; DO_OP()' to let another opcode's implementation finish + * their work, and many opcodes share entry points with a run of + * consecutive BEGIN_CASEs. + * + * Take care to trace OP only when it is the opcode fetched from + * the instruction stream, so the trace matches what one would + * expect from looking at the code. (We do omit POPs after SETs; + * unfortunate, but not worth fixing.) + */ +# define LOG_OPCODE(OP) JS_BEGIN_MACRO \ + if (JS_UNLIKELY(cx->logfp != NULL) && \ + (OP) == *regs.pc) \ + js_LogOpcode(cx); \ + JS_END_MACRO +# else +# define LOG_OPCODE(OP) ((void) 0) +# endif + + /* + * Macros for threaded interpreter loop + */ +#if JS_THREADED_INTERP + static void *const normalJumpTable[] = { +# define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + JS_EXTENSION &&L_##op, +# include "jsopcode.tbl" +# undef OPDEF + }; + + static void *const interruptJumpTable[] = { +# define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + JS_EXTENSION &&interrupt, +# include "jsopcode.tbl" +# undef OPDEF + }; + + register void * const *jumpTable = normalJumpTable; + + METER_OP_INIT(op); /* to nullify first METER_OP_PAIR */ + +# define ENABLE_INTERRUPTS() ((void) (jumpTable = interruptJumpTable)) + +# ifdef JS_TRACER +# define CHECK_RECORDER() \ + JS_ASSERT_IF(TRACE_RECORDER(cx), jumpTable == interruptJumpTable) +# else +# define CHECK_RECORDER() ((void)0) +# endif + +# define DO_OP() JS_BEGIN_MACRO \ + CHECK_RECORDER(); \ + JS_EXTENSION_(goto *jumpTable[op]); \ + JS_END_MACRO +# define DO_NEXT_OP(n) JS_BEGIN_MACRO \ + METER_OP_PAIR(op, JSOp(regs.pc[n])); \ + op = (JSOp) *(regs.pc += (n)); \ + METER_REPR(cx); \ + DO_OP(); \ + JS_END_MACRO + +# define BEGIN_CASE(OP) L_##OP: LOG_OPCODE(OP); CHECK_RECORDER(); +# define END_CASE(OP) DO_NEXT_OP(OP##_LENGTH); +# define END_VARLEN_CASE DO_NEXT_OP(len); +# define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP) \ + JS_ASSERT(js_CodeSpec[OP].length == 1); \ + op = (JSOp) *++regs.pc; \ + DO_OP(); + +# define END_EMPTY_CASES + +#else /* !JS_THREADED_INTERP */ + + register intN switchMask = 0; + intN switchOp; + +# define ENABLE_INTERRUPTS() ((void) (switchMask = -1)) + +# ifdef JS_TRACER +# define CHECK_RECORDER() \ + JS_ASSERT_IF(TRACE_RECORDER(cx), switchMask == -1) +# else +# define CHECK_RECORDER() ((void)0) +# endif + +# define DO_OP() goto do_op +# define DO_NEXT_OP(n) JS_BEGIN_MACRO \ + JS_ASSERT((n) == len); \ + goto advance_pc; \ + JS_END_MACRO + +# define BEGIN_CASE(OP) case OP: CHECK_RECORDER(); +# define END_CASE(OP) END_CASE_LEN(OP##_LENGTH) +# define END_CASE_LEN(n) END_CASE_LENX(n) +# define END_CASE_LENX(n) END_CASE_LEN##n + +/* + * To share the code for all len == 1 cases we use the specialized label with + * code that falls through to advance_pc: . + */ +# define END_CASE_LEN1 goto advance_pc_by_one; +# define END_CASE_LEN2 len = 2; goto advance_pc; +# define END_CASE_LEN3 len = 3; goto advance_pc; +# define END_CASE_LEN4 len = 4; goto advance_pc; +# define END_CASE_LEN5 len = 5; goto advance_pc; +# define END_VARLEN_CASE goto advance_pc; +# define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP) +# define END_EMPTY_CASES goto advance_pc_by_one; + +#endif /* !JS_THREADED_INTERP */ + +#define LOAD_ATOM(PCOFF, atom) \ + JS_BEGIN_MACRO \ + JS_ASSERT(regs.fp->hasImacropc() \ + ? atoms == COMMON_ATOMS_START(&rt->atomState) && \ + GET_INDEX(regs.pc + PCOFF) < js_common_atom_count \ + : (size_t)(atoms - script->atomMap.vector) < \ + (size_t)(script->atomMap.length - \ + GET_INDEX(regs.pc + PCOFF))); \ + atom = atoms[GET_INDEX(regs.pc + PCOFF)]; \ + JS_END_MACRO + +#define GET_FULL_INDEX(PCOFF) \ + (atoms - script->atomMap.vector + GET_INDEX(regs.pc + (PCOFF))) + +#define LOAD_OBJECT(PCOFF, obj) \ + (obj = script->getObject(GET_FULL_INDEX(PCOFF))) + +#define LOAD_FUNCTION(PCOFF) \ + (fun = script->getFunction(GET_FULL_INDEX(PCOFF))) + +#define LOAD_DOUBLE(PCOFF, dbl) \ + (dbl = script->getConst(GET_FULL_INDEX(PCOFF)).toDouble()) + + bool useMethodJIT = false; + +#ifdef JS_METHODJIT + +#define RESET_USE_METHODJIT() \ + JS_BEGIN_MACRO \ + useMethodJIT = cx->methodJitEnabled && \ + interpMode == JSINTERP_NORMAL && \ + script->getJITStatus(regs.fp->isConstructing()) != JITScript_Invalid; \ + JS_END_MACRO + +#define MONITOR_BRANCH_METHODJIT() \ + JS_BEGIN_MACRO \ + mjit::CompileStatus status = \ + mjit::CanMethodJITAtBranch(cx, script, regs.fp, regs.pc); \ + if (status == mjit::Compile_Error) \ + goto error; \ + if (status == mjit::Compile_Okay) { \ + void *ncode = \ + script->nativeCodeForPC(regs.fp->isConstructing(), regs.pc); \ + interpReturnOK = mjit::JaegerShotAtSafePoint(cx, ncode); \ + if (inlineCallCount) \ + goto jit_return; \ + regs.fp->setFinishedInInterpreter(); \ + goto leave_on_safe_point; \ + } \ + if (status == mjit::Compile_Abort) { \ + useMethodJIT = false; \ + } \ + JS_END_MACRO + +#else + +#define RESET_USE_METHODJIT() ((void) 0) + +#define MONITOR_BRANCH_METHODJIT() ((void) 0) + +#endif + +#ifdef JS_TRACER + +#ifdef MOZ_TRACEVIS +#if JS_THREADED_INTERP +#define MONITOR_BRANCH_TRACEVIS \ + JS_BEGIN_MACRO \ + if (jumpTable != interruptJumpTable) \ + EnterTraceVisState(cx, S_RECORD, R_NONE); \ + JS_END_MACRO +#else /* !JS_THREADED_INTERP */ +#define MONITOR_BRANCH_TRACEVIS \ + JS_BEGIN_MACRO \ + EnterTraceVisState(cx, S_RECORD, R_NONE); \ + JS_END_MACRO +#endif +#else +#define MONITOR_BRANCH_TRACEVIS +#endif + +#define RESTORE_INTERP_VARS() \ + JS_BEGIN_MACRO \ + script = regs.fp->script(); \ + argv = regs.fp->maybeFormalArgs(); \ + atoms = FrameAtomBase(cx, regs.fp); \ + JS_ASSERT(cx->regs == ®s); \ + if (cx->isExceptionPending()) \ + goto error; \ + JS_END_MACRO + +#define MONITOR_BRANCH() \ + JS_BEGIN_MACRO \ + if (TRACING_ENABLED(cx)) { \ + if (!TRACE_RECORDER(cx) && !TRACE_PROFILER(cx) && useMethodJIT) { \ + MONITOR_BRANCH_METHODJIT(); \ + } else { \ + MonitorResult r = MonitorLoopEdge(cx, inlineCallCount, interpMode); \ + if (r == MONITOR_RECORDING) { \ + JS_ASSERT(TRACE_RECORDER(cx)); \ + JS_ASSERT(!TRACE_PROFILER(cx)); \ + MONITOR_BRANCH_TRACEVIS; \ + ENABLE_INTERRUPTS(); \ + CLEAR_LEAVE_ON_TRACE_POINT(); \ + } \ + RESTORE_INTERP_VARS(); \ + JS_ASSERT_IF(cx->isExceptionPending(), r == MONITOR_ERROR); \ + if (r == MONITOR_ERROR) \ + goto error; \ + } \ + } else { \ + MONITOR_BRANCH_METHODJIT(); \ + } \ + JS_END_MACRO + +#else /* !JS_TRACER */ + +#define MONITOR_BRANCH() \ + JS_BEGIN_MACRO \ + MONITOR_BRANCH_METHODJIT(); \ + JS_END_MACRO + +#endif /* !JS_TRACER */ + + /* + * Prepare to call a user-supplied branch handler, and abort the script + * if it returns false. + */ +#define CHECK_BRANCH() \ + JS_BEGIN_MACRO \ + if (JS_THREAD_DATA(cx)->interruptFlags && !js_HandleExecutionInterrupt(cx)) \ + goto error; \ + JS_END_MACRO + +#if defined(JS_TRACER) && defined(JS_METHODJIT) +# define LEAVE_ON_SAFE_POINT() \ + do { \ + JS_ASSERT_IF(leaveOnSafePoint, !TRACE_RECORDER(cx)); \ + JS_ASSERT_IF(leaveOnSafePoint, !TRACE_PROFILER(cx)); \ + JS_ASSERT_IF(leaveOnSafePoint, interpMode != JSINTERP_NORMAL); \ + if (leaveOnSafePoint && !regs.fp->hasImacropc() && \ + script->maybeNativeCodeForPC(regs.fp->isConstructing(), regs.pc)) { \ + JS_ASSERT(!TRACE_RECORDER(cx)); \ + interpReturnOK = true; \ + goto leave_on_safe_point; \ + } \ + } while (0) +#else +# define LEAVE_ON_SAFE_POINT() /* nop */ +#endif + +#define BRANCH(n) \ + JS_BEGIN_MACRO \ + regs.pc += (n); \ + op = (JSOp) *regs.pc; \ + if ((n) <= 0) { \ + CHECK_BRANCH(); \ + if (op == JSOP_NOTRACE) { \ + if (TRACE_RECORDER(cx) || TRACE_PROFILER(cx)) { \ + MONITOR_BRANCH(); \ + op = (JSOp) *regs.pc; \ + } \ + } else if (op == JSOP_TRACE) { \ + MONITOR_BRANCH(); \ + op = (JSOp) *regs.pc; \ + } \ + } \ + LEAVE_ON_SAFE_POINT(); \ + DO_OP(); \ + JS_END_MACRO + +#define CHECK_INTERRUPT_HANDLER() \ + JS_BEGIN_MACRO \ + if (cx->debugHooks->interruptHook) \ + ENABLE_INTERRUPTS(); \ + JS_END_MACRO + + JSFrameRegs regs = *cx->regs; + + /* Repoint cx->regs to a local variable for faster access. */ + struct InterpExitGuard { + JSContext *cx; + const JSFrameRegs ®s; + JSFrameRegs *prevContextRegs; + InterpExitGuard(JSContext *cx, JSFrameRegs ®s) + : cx(cx), regs(regs), prevContextRegs(cx->regs) { + cx->setCurrentRegs(®s); + ++cx->interpLevel; + } + ~InterpExitGuard() { + --cx->interpLevel; + JS_ASSERT(cx->regs == ®s); + *prevContextRegs = regs; + cx->setCurrentRegs(prevContextRegs); + } + } interpGuard(cx, regs); + + /* Copy in hot values that change infrequently. */ + JSRuntime *const rt = cx->runtime; + JSScript *script = regs.fp->script(); + Value *argv = regs.fp->maybeFormalArgs(); + CHECK_INTERRUPT_HANDLER(); + +#if defined(JS_TRACER) && defined(JS_METHODJIT) + bool leaveOnSafePoint = (interpMode == JSINTERP_SAFEPOINT); +# define CLEAR_LEAVE_ON_TRACE_POINT() ((void) (leaveOnSafePoint = false)) +#else +# define CLEAR_LEAVE_ON_TRACE_POINT() ((void) 0) +#endif + + if (!entryFrame) + entryFrame = regs.fp; + + /* + * Initialize the index segment register used by LOAD_ATOM and + * GET_FULL_INDEX macros below. As a register we use a pointer based on + * the atom map to turn frequently executed LOAD_ATOM into simple array + * access. For less frequent object and regexp loads we have to recover + * the segment from atoms pointer first. + */ + JSAtom **atoms = script->atomMap.vector; + +#if JS_HAS_GENERATORS + if (JS_UNLIKELY(regs.fp->isGeneratorFrame())) { + JS_ASSERT(interpGuard.prevContextRegs == &cx->generatorFor(regs.fp)->regs); + JS_ASSERT((size_t) (regs.pc - script->code) <= script->length); + JS_ASSERT((size_t) (regs.sp - regs.fp->base()) <= StackDepth(script)); + + /* + * To support generator_throw and to catch ignored exceptions, + * fail if cx->isExceptionPending() is true. + */ + if (cx->isExceptionPending()) + goto error; + } +#endif + +#ifdef JS_TRACER + /* + * The method JIT may have already initiated a recording, in which case + * there should already be a valid recorder. Otherwise... + * we cannot reenter the interpreter while recording. + */ + if (interpMode == JSINTERP_RECORD) { + JS_ASSERT(TRACE_RECORDER(cx)); + JS_ASSERT(!TRACE_PROFILER(cx)); + ENABLE_INTERRUPTS(); + } else if (interpMode == JSINTERP_PROFILE) { + ENABLE_INTERRUPTS(); + } else if (TRACE_RECORDER(cx)) { + AbortRecording(cx, "attempt to reenter interpreter while recording"); + } + + if (regs.fp->hasImacropc()) + atoms = COMMON_ATOMS_START(&rt->atomState); +#endif + + /* Don't call the script prologue if executing between Method and Trace JIT. */ + if (interpMode == JSINTERP_NORMAL) { + JS_ASSERT_IF(!regs.fp->isGeneratorFrame(), regs.pc == script->code); + if (!ScriptPrologue(cx, regs.fp)) + goto error; + } + + CHECK_INTERRUPT_HANDLER(); + + RESET_USE_METHODJIT(); + + /* State communicated between non-local jumps: */ + JSBool interpReturnOK; + JSAtom *atomNotDefined; + + /* + * It is important that "op" be initialized before calling DO_OP because + * it is possible for "op" to be specially assigned during the normal + * processing of an opcode while looping. We rely on DO_NEXT_OP to manage + * "op" correctly in all other cases. + */ + JSOp op; + jsint len; + len = 0; + + /* Check for too deep of a native thread stack. */ +#ifdef JS_TRACER +#ifdef JS_METHODJIT + JS_CHECK_RECURSION(cx, do { + if (TRACE_RECORDER(cx)) + AbortRecording(cx, "too much recursion"); + if (TRACE_PROFILER(cx)) + AbortProfiling(cx); + goto error; + } while (0);); +#else + JS_CHECK_RECURSION(cx, do { + if (TRACE_RECORDER(cx)) + AbortRecording(cx, "too much recursion"); + goto error; + } while (0);); +#endif +#else + JS_CHECK_RECURSION(cx, return JS_FALSE); +#endif + +#if JS_THREADED_INTERP + DO_NEXT_OP(len); +#else + DO_NEXT_OP(len); +#endif + +#if JS_THREADED_INTERP + /* + * This is a loop, but it does not look like a loop. The loop-closing + * jump is distributed throughout goto *jumpTable[op] inside of DO_OP. + * When interrupts are enabled, jumpTable is set to interruptJumpTable + * where all jumps point to the interrupt label. The latter, after + * calling the interrupt handler, dispatches through normalJumpTable to + * continue the normal bytecode processing. + */ + +#else /* !JS_THREADED_INTERP */ + for (;;) { + advance_pc_by_one: + JS_ASSERT(js_CodeSpec[op].length == 1); + len = 1; + advance_pc: + regs.pc += len; + op = (JSOp) *regs.pc; + + do_op: + CHECK_RECORDER(); + LOG_OPCODE(op); + switchOp = intN(op) | switchMask; + do_switch: + switch (switchOp) { +#endif + +#if JS_THREADED_INTERP + interrupt: +#else /* !JS_THREADED_INTERP */ + case -1: + JS_ASSERT(switchMask == -1); +#endif /* !JS_THREADED_INTERP */ + { + bool moreInterrupts = false; + JSInterruptHook hook = cx->debugHooks->interruptHook; + if (hook) { +#ifdef JS_TRACER + if (TRACE_RECORDER(cx)) + AbortRecording(cx, "interrupt hook"); +#ifdef JS_METHODJIT + if (TRACE_PROFILER(cx)) + AbortProfiling(cx); +#endif +#endif + Value rval; + switch (hook(cx, script, regs.pc, Jsvalify(&rval), + cx->debugHooks->interruptHookData)) { + case JSTRAP_ERROR: + goto error; + case JSTRAP_CONTINUE: + break; + case JSTRAP_RETURN: + regs.fp->setReturnValue(rval); + interpReturnOK = JS_TRUE; + goto forced_return; + case JSTRAP_THROW: + cx->setPendingException(rval); + goto error; + default:; + } + moreInterrupts = true; + } + +#ifdef JS_TRACER +#ifdef JS_METHODJIT + if (TRACE_PROFILER(cx) && interpMode == JSINTERP_PROFILE) { + LoopProfile *prof = TRACE_PROFILER(cx); + JS_ASSERT(!TRACE_RECORDER(cx)); + LoopProfile::ProfileAction act = prof->profileOperation(cx, op); + switch (act) { + case LoopProfile::ProfComplete: + if (interpMode != JSINTERP_NORMAL) { + leaveOnSafePoint = true; + LEAVE_ON_SAFE_POINT(); + } + break; + default: + moreInterrupts = true; + break; + } + } +#endif + if (TraceRecorder* tr = TRACE_RECORDER(cx)) { + JS_ASSERT(!TRACE_PROFILER(cx)); + AbortableRecordingStatus status = tr->monitorRecording(op); + JS_ASSERT_IF(cx->isExceptionPending(), status == ARECORD_ERROR); + + if (interpMode != JSINTERP_NORMAL) { + JS_ASSERT(interpMode == JSINTERP_RECORD || JSINTERP_SAFEPOINT); + switch (status) { + case ARECORD_IMACRO_ABORTED: + case ARECORD_ABORTED: + case ARECORD_COMPLETED: + case ARECORD_STOP: +#ifdef JS_METHODJIT + leaveOnSafePoint = true; + LEAVE_ON_SAFE_POINT(); +#endif + break; + default: + break; + } + } + + switch (status) { + case ARECORD_CONTINUE: + moreInterrupts = true; + break; + case ARECORD_IMACRO: + case ARECORD_IMACRO_ABORTED: + atoms = COMMON_ATOMS_START(&rt->atomState); + op = JSOp(*regs.pc); + CLEAR_LEAVE_ON_TRACE_POINT(); + if (status == ARECORD_IMACRO) + DO_OP(); /* keep interrupting for op. */ + break; + case ARECORD_ERROR: + // The code at 'error:' aborts the recording. + goto error; + case ARECORD_ABORTED: + case ARECORD_COMPLETED: + break; + case ARECORD_STOP: + /* A 'stop' error should have already aborted recording. */ + default: + JS_NOT_REACHED("Bad recording status"); + } + } +#endif /* !JS_TRACER */ + +#if JS_THREADED_INTERP +#ifdef MOZ_TRACEVIS + if (!moreInterrupts) + ExitTraceVisState(cx, R_ABORT); +#endif + jumpTable = moreInterrupts ? interruptJumpTable : normalJumpTable; + JS_EXTENSION_(goto *normalJumpTable[op]); +#else + switchMask = moreInterrupts ? -1 : 0; + switchOp = intN(op); + goto do_switch; +#endif + } + +/* No-ops for ease of decompilation. */ +ADD_EMPTY_CASE(JSOP_NOP) +ADD_EMPTY_CASE(JSOP_CONDSWITCH) +ADD_EMPTY_CASE(JSOP_TRY) +#if JS_HAS_XML_SUPPORT +ADD_EMPTY_CASE(JSOP_STARTXML) +ADD_EMPTY_CASE(JSOP_STARTXMLEXPR) +#endif +ADD_EMPTY_CASE(JSOP_NULLBLOCKCHAIN) +END_EMPTY_CASES + +BEGIN_CASE(JSOP_TRACE) +BEGIN_CASE(JSOP_NOTRACE) + LEAVE_ON_SAFE_POINT(); +END_CASE(JSOP_TRACE) + +/* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */ +BEGIN_CASE(JSOP_LINENO) +END_CASE(JSOP_LINENO) + +BEGIN_CASE(JSOP_BLOCKCHAIN) +END_CASE(JSOP_BLOCKCHAIN) + +BEGIN_CASE(JSOP_PUSH) + PUSH_UNDEFINED(); +END_CASE(JSOP_PUSH) + +BEGIN_CASE(JSOP_POP) + regs.sp--; +END_CASE(JSOP_POP) + +BEGIN_CASE(JSOP_POPN) +{ + regs.sp -= GET_UINT16(regs.pc); +#ifdef DEBUG + JS_ASSERT(regs.fp->base() <= regs.sp); + JSObject *obj = GetBlockChain(cx, regs.fp); + JS_ASSERT_IF(obj, + OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj) + <= (size_t) (regs.sp - regs.fp->base())); + for (obj = ®s.fp->scopeChain(); obj; obj = obj->getParent()) { + Class *clasp = obj->getClass(); + if (clasp != &js_BlockClass && clasp != &js_WithClass) + continue; + if (obj->getPrivate() != js_FloatingFrameIfGenerator(cx, regs.fp)) + break; + JS_ASSERT(regs.fp->base() + OBJ_BLOCK_DEPTH(cx, obj) + + ((clasp == &js_BlockClass) + ? OBJ_BLOCK_COUNT(cx, obj) + : 1) + <= regs.sp); + } +#endif +} +END_CASE(JSOP_POPN) + +BEGIN_CASE(JSOP_SETRVAL) +BEGIN_CASE(JSOP_POPV) + POP_RETURN_VALUE(); +END_CASE(JSOP_POPV) + +BEGIN_CASE(JSOP_ENTERWITH) + if (!js_EnterWith(cx, -1, JSOP_ENTERWITH, JSOP_ENTERWITH_LENGTH)) + goto error; + + /* + * We must ensure that different "with" blocks have different stack depth + * associated with them. This allows the try handler search to properly + * recover the scope chain. Thus we must keep the stack at least at the + * current level. + * + * We set sp[-1] to the current "with" object to help asserting the + * enter/leave balance in [leavewith]. + */ + regs.sp[-1].setObject(regs.fp->scopeChain()); +END_CASE(JSOP_ENTERWITH) + +BEGIN_CASE(JSOP_LEAVEWITH) + JS_ASSERT(®s.sp[-1].toObject() == ®s.fp->scopeChain()); + regs.sp--; + js_LeaveWith(cx); +END_CASE(JSOP_LEAVEWITH) + +BEGIN_CASE(JSOP_RETURN) + POP_RETURN_VALUE(); + /* FALL THROUGH */ + +BEGIN_CASE(JSOP_RETRVAL) /* fp return value already set */ +BEGIN_CASE(JSOP_STOP) +{ + /* + * When the inlined frame exits with an exception or an error, ok will be + * false after the inline_return label. + */ + CHECK_BRANCH(); + +#ifdef JS_TRACER + if (regs.fp->hasImacropc()) { + /* + * If we are at the end of an imacro, return to its caller in the + * current frame. + */ + JS_ASSERT(op == JSOP_STOP); + JS_ASSERT((uintN)(regs.sp - regs.fp->slots()) <= script->nslots); + jsbytecode *imacpc = regs.fp->imacropc(); + regs.pc = imacpc + js_CodeSpec[*imacpc].length; + regs.fp->clearImacropc(); + LEAVE_ON_SAFE_POINT(); + atoms = script->atomMap.vector; + op = JSOp(*regs.pc); + DO_OP(); + } +#endif + + interpReturnOK = true; + if (entryFrame != regs.fp) + inline_return: + { + JS_ASSERT(!js_IsActiveWithOrBlock(cx, ®s.fp->scopeChain(), 0)); + interpReturnOK = ScriptEpilogue(cx, regs.fp, interpReturnOK); + CHECK_INTERRUPT_HANDLER(); + + /* The JIT inlines ScriptEpilogue. */ + jit_return: + Value *newsp = regs.fp->actualArgs() - 1; + newsp[-1] = regs.fp->returnValue(); + cx->stack().popInlineFrame(cx, regs.fp->prev(), newsp); + + /* Sync interpreter registers. */ + script = regs.fp->script(); + argv = regs.fp->maybeFormalArgs(); + atoms = FrameAtomBase(cx, regs.fp); + + /* Resume execution in the calling frame. */ + RESET_USE_METHODJIT(); + JS_ASSERT(inlineCallCount); + inlineCallCount--; + if (JS_LIKELY(interpReturnOK)) { + JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, script, regs.pc)].length + == JSOP_CALL_LENGTH); + TRACE_0(LeaveFrame); + len = JSOP_CALL_LENGTH; + DO_NEXT_OP(len); + } + goto error; + } else { + JS_ASSERT(regs.sp == regs.fp->base()); + } + interpReturnOK = true; + goto exit; +} + +BEGIN_CASE(JSOP_DEFAULT) + regs.sp--; + /* FALL THROUGH */ +BEGIN_CASE(JSOP_GOTO) +{ + len = GET_JUMP_OFFSET(regs.pc); + BRANCH(len); +} +END_CASE(JSOP_GOTO) + +BEGIN_CASE(JSOP_IFEQ) +{ + bool cond; + Value *_; + POP_BOOLEAN(cx, _, cond); + if (cond == false) { + len = GET_JUMP_OFFSET(regs.pc); + BRANCH(len); + } +} +END_CASE(JSOP_IFEQ) + +BEGIN_CASE(JSOP_IFNE) +{ + bool cond; + Value *_; + POP_BOOLEAN(cx, _, cond); + if (cond != false) { + len = GET_JUMP_OFFSET(regs.pc); + BRANCH(len); + } +} +END_CASE(JSOP_IFNE) + +BEGIN_CASE(JSOP_OR) +{ + bool cond; + Value *vp; + POP_BOOLEAN(cx, vp, cond); + if (cond == true) { + len = GET_JUMP_OFFSET(regs.pc); + PUSH_COPY(*vp); + DO_NEXT_OP(len); + } +} +END_CASE(JSOP_OR) + +BEGIN_CASE(JSOP_AND) +{ + bool cond; + Value *vp; + POP_BOOLEAN(cx, vp, cond); + if (cond == false) { + len = GET_JUMP_OFFSET(regs.pc); + PUSH_COPY(*vp); + DO_NEXT_OP(len); + } +} +END_CASE(JSOP_AND) + +BEGIN_CASE(JSOP_DEFAULTX) + regs.sp--; + /* FALL THROUGH */ +BEGIN_CASE(JSOP_GOTOX) +{ + len = GET_JUMPX_OFFSET(regs.pc); + BRANCH(len); +} +END_CASE(JSOP_GOTOX); + +BEGIN_CASE(JSOP_IFEQX) +{ + bool cond; + Value *_; + POP_BOOLEAN(cx, _, cond); + if (cond == false) { + len = GET_JUMPX_OFFSET(regs.pc); + BRANCH(len); + } +} +END_CASE(JSOP_IFEQX) + +BEGIN_CASE(JSOP_IFNEX) +{ + bool cond; + Value *_; + POP_BOOLEAN(cx, _, cond); + if (cond != false) { + len = GET_JUMPX_OFFSET(regs.pc); + BRANCH(len); + } +} +END_CASE(JSOP_IFNEX) + +BEGIN_CASE(JSOP_ORX) +{ + bool cond; + Value *vp; + POP_BOOLEAN(cx, vp, cond); + if (cond == true) { + len = GET_JUMPX_OFFSET(regs.pc); + PUSH_COPY(*vp); + DO_NEXT_OP(len); + } +} +END_CASE(JSOP_ORX) + +BEGIN_CASE(JSOP_ANDX) +{ + bool cond; + Value *vp; + POP_BOOLEAN(cx, vp, cond); + if (cond == JS_FALSE) { + len = GET_JUMPX_OFFSET(regs.pc); + PUSH_COPY(*vp); + DO_NEXT_OP(len); + } +} +END_CASE(JSOP_ANDX) + +/* + * If the index value at sp[n] is not an int that fits in a jsval, it could + * be an object (an XML QName, AttributeName, or AnyName), but only if we are + * compiling with JS_HAS_XML_SUPPORT. Otherwise convert the index value to a + * string atom id. + */ +#define FETCH_ELEMENT_ID(obj, n, id) \ + JS_BEGIN_MACRO \ + const Value &idval_ = regs.sp[n]; \ + int32_t i_; \ + if (ValueFitsInInt32(idval_, &i_) && INT_FITS_IN_JSID(i_)) { \ + id = INT_TO_JSID(i_); \ + } else { \ + if (!js_InternNonIntElementId(cx, obj, idval_, &id, ®s.sp[n])) \ + goto error; \ + } \ + JS_END_MACRO + +#define TRY_BRANCH_AFTER_COND(cond,spdec) \ + JS_BEGIN_MACRO \ + JS_ASSERT(js_CodeSpec[op].length == 1); \ + uintN diff_ = (uintN) regs.pc[1] - (uintN) JSOP_IFEQ; \ + if (diff_ <= 1) { \ + regs.sp -= spdec; \ + if (cond == (diff_ != 0)) { \ + ++regs.pc; \ + len = GET_JUMP_OFFSET(regs.pc); \ + BRANCH(len); \ + } \ + len = 1 + JSOP_IFEQ_LENGTH; \ + DO_NEXT_OP(len); \ + } \ + JS_END_MACRO + +BEGIN_CASE(JSOP_IN) +{ + const Value &rref = regs.sp[-1]; + if (!rref.isObject()) { + js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL); + goto error; + } + JSObject *obj = &rref.toObject(); + jsid id; + FETCH_ELEMENT_ID(obj, -2, id); + JSObject *obj2; + JSProperty *prop; + if (!obj->lookupProperty(cx, id, &obj2, &prop)) + goto error; + bool cond = prop != NULL; + TRY_BRANCH_AFTER_COND(cond, 2); + regs.sp--; + regs.sp[-1].setBoolean(cond); +} +END_CASE(JSOP_IN) + +BEGIN_CASE(JSOP_ITER) +{ + JS_ASSERT(regs.sp > regs.fp->base()); + uintN flags = regs.pc[1]; + if (!js_ValueToIterator(cx, flags, ®s.sp[-1])) + goto error; + CHECK_INTERRUPT_HANDLER(); + JS_ASSERT(!regs.sp[-1].isPrimitive()); +} +END_CASE(JSOP_ITER) + +BEGIN_CASE(JSOP_MOREITER) +{ + JS_ASSERT(regs.sp - 1 >= regs.fp->base()); + JS_ASSERT(regs.sp[-1].isObject()); + PUSH_NULL(); + bool cond; + if (!IteratorMore(cx, ®s.sp[-2].toObject(), &cond, ®s.sp[-1])) + goto error; + CHECK_INTERRUPT_HANDLER(); + regs.sp[-1].setBoolean(cond); +} +END_CASE(JSOP_MOREITER) + +BEGIN_CASE(JSOP_ENDITER) +{ + JS_ASSERT(regs.sp - 1 >= regs.fp->base()); + bool ok = !!js_CloseIterator(cx, ®s.sp[-1].toObject()); + regs.sp--; + if (!ok) + goto error; +} +END_CASE(JSOP_ENDITER) + +BEGIN_CASE(JSOP_FORARG) +{ + JS_ASSERT(regs.sp - 1 >= regs.fp->base()); + uintN slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < regs.fp->numFormalArgs()); + JS_ASSERT(regs.sp[-1].isObject()); + if (!IteratorNext(cx, ®s.sp[-1].toObject(), &argv[slot])) + goto error; +} +END_CASE(JSOP_FORARG) + +BEGIN_CASE(JSOP_FORLOCAL) +{ + JS_ASSERT(regs.sp - 1 >= regs.fp->base()); + uintN slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < regs.fp->numSlots()); + JS_ASSERT(regs.sp[-1].isObject()); + if (!IteratorNext(cx, ®s.sp[-1].toObject(), ®s.fp->slots()[slot])) + goto error; +} +END_CASE(JSOP_FORLOCAL) + +BEGIN_CASE(JSOP_FORNAME) +BEGIN_CASE(JSOP_FORGNAME) +{ + JS_ASSERT(regs.sp - 1 >= regs.fp->base()); + JSAtom *atom; + LOAD_ATOM(0, atom); + jsid id = ATOM_TO_JSID(atom); + JSObject *obj, *obj2; + JSProperty *prop; + if (!js_FindProperty(cx, id, &obj, &obj2, &prop)) + goto error; + + { + AutoValueRooter tvr(cx); + JS_ASSERT(regs.sp[-1].isObject()); + if (!IteratorNext(cx, ®s.sp[-1].toObject(), tvr.addr())) + goto error; + if (!obj->setProperty(cx, id, tvr.addr(), script->strictModeCode)) + goto error; + } +} +END_CASE(JSOP_FORNAME) + +BEGIN_CASE(JSOP_FORPROP) +{ + JS_ASSERT(regs.sp - 2 >= regs.fp->base()); + JSAtom *atom; + LOAD_ATOM(0, atom); + jsid id = ATOM_TO_JSID(atom); + JSObject *obj; + FETCH_OBJECT(cx, -1, obj); + { + AutoValueRooter tvr(cx); + JS_ASSERT(regs.sp[-2].isObject()); + if (!IteratorNext(cx, ®s.sp[-2].toObject(), tvr.addr())) + goto error; + if (!obj->setProperty(cx, id, tvr.addr(), script->strictModeCode)) + goto error; + } + regs.sp--; +} +END_CASE(JSOP_FORPROP) + +BEGIN_CASE(JSOP_FORELEM) + /* + * JSOP_FORELEM simply dups the property identifier at top of stack and + * lets the subsequent JSOP_ENUMELEM opcode sequence handle the left-hand + * side expression evaluation and assignment. This opcode exists solely to + * help the decompiler. + */ + JS_ASSERT(regs.sp - 1 >= regs.fp->base()); + JS_ASSERT(regs.sp[-1].isObject()); + PUSH_NULL(); + if (!IteratorNext(cx, ®s.sp[-2].toObject(), ®s.sp[-1])) + goto error; +END_CASE(JSOP_FORELEM) + +BEGIN_CASE(JSOP_DUP) +{ + JS_ASSERT(regs.sp > regs.fp->base()); + const Value &rref = regs.sp[-1]; + PUSH_COPY(rref); +} +END_CASE(JSOP_DUP) + +BEGIN_CASE(JSOP_DUP2) +{ + JS_ASSERT(regs.sp - 2 >= regs.fp->base()); + const Value &lref = regs.sp[-2]; + const Value &rref = regs.sp[-1]; + PUSH_COPY(lref); + PUSH_COPY(rref); +} +END_CASE(JSOP_DUP2) + +BEGIN_CASE(JSOP_SWAP) +{ + JS_ASSERT(regs.sp - 2 >= regs.fp->base()); + Value &lref = regs.sp[-2]; + Value &rref = regs.sp[-1]; + lref.swap(rref); +} +END_CASE(JSOP_SWAP) + +BEGIN_CASE(JSOP_PICK) +{ + jsint i = regs.pc[1]; + JS_ASSERT(regs.sp - (i+1) >= regs.fp->base()); + Value lval = regs.sp[-(i+1)]; + memmove(regs.sp - (i+1), regs.sp - i, sizeof(Value)*i); + regs.sp[-1] = lval; +} +END_CASE(JSOP_PICK) + +#define NATIVE_GET(cx,obj,pobj,shape,getHow,vp) \ + JS_BEGIN_MACRO \ + if (shape->isDataDescriptor() && shape->hasDefaultGetter()) { \ + /* Fast path for Object instance properties. */ \ + JS_ASSERT((shape)->slot != SHAPE_INVALID_SLOT || \ + !shape->hasDefaultSetter()); \ + if (((shape)->slot != SHAPE_INVALID_SLOT)) \ + *(vp) = (pobj)->nativeGetSlot((shape)->slot); \ + else \ + (vp)->setUndefined(); \ + } else { \ + if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp)) \ + goto error; \ + } \ + JS_END_MACRO + +#define NATIVE_SET(cx,obj,shape,entry,strict,vp) \ + JS_BEGIN_MACRO \ + if (shape->hasDefaultSetter() && \ + (shape)->slot != SHAPE_INVALID_SLOT && \ + !(obj)->brandedOrHasMethodBarrier()) { \ + /* Fast path for, e.g., plain Object instance properties. */ \ + (obj)->nativeSetSlot((shape)->slot, *vp); \ + } else { \ + if (!js_NativeSet(cx, obj, shape, false, strict, vp)) \ + goto error; \ + } \ + JS_END_MACRO + +/* + * Skip the JSOP_POP typically found after a JSOP_SET* opcode, where oplen is + * the constant length of the SET opcode sequence, and spdec is the constant + * by which to decrease the stack pointer to pop all of the SET op's operands. + * + * NB: unlike macros that could conceivably be replaced by functions (ignoring + * goto error), where a call should not have to be braced in order to expand + * correctly (e.g., in if (cond) FOO(); else BAR()), these three macros lack + * JS_{BEGIN,END}_MACRO brackets. They are also indented so as to align with + * nearby opcode code. + */ +#define SKIP_POP_AFTER_SET(oplen,spdec) \ + if (regs.pc[oplen] == JSOP_POP) { \ + regs.sp -= spdec; \ + regs.pc += oplen + JSOP_POP_LENGTH; \ + op = (JSOp) *regs.pc; \ + DO_OP(); \ + } + +#define END_SET_CASE(OP) \ + SKIP_POP_AFTER_SET(OP##_LENGTH, 1); \ + END_CASE(OP) + +#define END_SET_CASE_STORE_RVAL(OP,spdec) \ + SKIP_POP_AFTER_SET(OP##_LENGTH, spdec); \ + { \ + Value *newsp = regs.sp - ((spdec) - 1); \ + newsp[-1] = regs.sp[-1]; \ + regs.sp = newsp; \ + } \ + END_CASE(OP) + +BEGIN_CASE(JSOP_SETCONST) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + JSObject &obj = regs.fp->varobj(cx); + const Value &ref = regs.sp[-1]; + if (!obj.defineProperty(cx, ATOM_TO_JSID(atom), ref, + PropertyStub, StrictPropertyStub, + JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) { + goto error; + } +} +END_SET_CASE(JSOP_SETCONST); + +#if JS_HAS_DESTRUCTURING +BEGIN_CASE(JSOP_ENUMCONSTELEM) +{ + const Value &ref = regs.sp[-3]; + JSObject *obj; + FETCH_OBJECT(cx, -2, obj); + jsid id; + FETCH_ELEMENT_ID(obj, -1, id); + if (!obj->defineProperty(cx, id, ref, + PropertyStub, StrictPropertyStub, + JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) { + goto error; + } + regs.sp -= 3; +} +END_CASE(JSOP_ENUMCONSTELEM) +#endif + +BEGIN_CASE(JSOP_BINDGNAME) + PUSH_OBJECT(*regs.fp->scopeChain().getGlobal()); +END_CASE(JSOP_BINDGNAME) + +BEGIN_CASE(JSOP_BINDNAME) +{ + JSObject *obj; + do { + /* + * We can skip the property lookup for the global object. If the + * property does not exist anywhere on the scope chain, JSOP_SETNAME + * adds the property to the global. + * + * As a consequence of this optimization for the global object we run + * its JSRESOLVE_ASSIGNING-tolerant resolve hooks only in JSOP_SETNAME, + * after the interpreter evaluates the right- hand-side of the + * assignment, and not here. + * + * This should be transparent to the hooks because the script, instead + * of name = rhs, could have used global.name = rhs given a global + * object reference, which also calls the hooks only after evaluating + * the rhs. We desire such resolve hook equivalence between the two + * forms. + */ + obj = ®s.fp->scopeChain(); + if (!obj->getParent()) + break; + + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + break; + } + + jsid id = ATOM_TO_JSID(atom); + obj = js_FindIdentifierBase(cx, ®s.fp->scopeChain(), id); + if (!obj) + goto error; + } while (0); + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_BINDNAME) + +BEGIN_CASE(JSOP_IMACOP) + JS_ASSERT(JS_UPTRDIFF(regs.fp->imacropc(), script->code) < script->length); + op = JSOp(*regs.fp->imacropc()); + DO_OP(); + +#define BITWISE_OP(OP) \ + JS_BEGIN_MACRO \ + int32_t i, j; \ + if (!ValueToECMAInt32(cx, regs.sp[-2], &i)) \ + goto error; \ + if (!ValueToECMAInt32(cx, regs.sp[-1], &j)) \ + goto error; \ + i = i OP j; \ + regs.sp--; \ + regs.sp[-1].setInt32(i); \ + JS_END_MACRO + +BEGIN_CASE(JSOP_BITOR) + BITWISE_OP(|); +END_CASE(JSOP_BITOR) + +BEGIN_CASE(JSOP_BITXOR) + BITWISE_OP(^); +END_CASE(JSOP_BITXOR) + +BEGIN_CASE(JSOP_BITAND) + BITWISE_OP(&); +END_CASE(JSOP_BITAND) + +#undef BITWISE_OP + +/* + * NB: These macros can't use JS_BEGIN_MACRO/JS_END_MACRO around their bodies + * because they begin if/else chains, so callers must not put semicolons after + * the call expressions! + */ +#if JS_HAS_XML_SUPPORT +#define XML_EQUALITY_OP(OP) \ + if ((lval.isObject() && lval.toObject().isXML()) || \ + (rval.isObject() && rval.toObject().isXML())) { \ + if (!js_TestXMLEquality(cx, lval, rval, &cond)) \ + goto error; \ + cond = cond OP JS_TRUE; \ + } else +#else +#define XML_EQUALITY_OP(OP) /* nothing */ +#endif + +#define EQUALITY_OP(OP, IFNAN) \ + JS_BEGIN_MACRO \ + JSBool cond; \ + Value rval = regs.sp[-1]; \ + Value lval = regs.sp[-2]; \ + XML_EQUALITY_OP(OP) \ + if (SameType(lval, rval)) { \ + if (lval.isString()) { \ + JSString *l = lval.toString(), *r = rval.toString(); \ + JSBool equal; \ + if (!EqualStrings(cx, l, r, &equal)) \ + goto error; \ + cond = equal OP JS_TRUE; \ + } else if (lval.isDouble()) { \ + double l = lval.toDouble(), r = rval.toDouble(); \ + cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN); \ + } else if (lval.isObject()) { \ + JSObject *l = &lval.toObject(), *r = &rval.toObject(); \ + l->assertSpecialEqualitySynced(); \ + if (EqualityOp eq = l->getClass()->ext.equality) { \ + if (!eq(cx, l, &rval, &cond)) \ + goto error; \ + cond = cond OP JS_TRUE; \ + } else { \ + cond = l OP r; \ + } \ + } else { \ + cond = lval.payloadAsRawUint32() OP rval.payloadAsRawUint32();\ + } \ + } else { \ + if (lval.isNullOrUndefined()) { \ + cond = rval.isNullOrUndefined() OP true; \ + } else if (rval.isNullOrUndefined()) { \ + cond = true OP false; \ + } else { \ + if (lval.isObject()) \ + DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval); \ + if (rval.isObject()) \ + DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); \ + if (lval.isString() && rval.isString()) { \ + JSString *l = lval.toString(), *r = rval.toString(); \ + JSBool equal; \ + if (!EqualStrings(cx, l, r, &equal)) \ + goto error; \ + cond = equal OP JS_TRUE; \ + } else { \ + double l, r; \ + if (!ValueToNumber(cx, lval, &l) || \ + !ValueToNumber(cx, rval, &r)) { \ + goto error; \ + } \ + cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN); \ + } \ + } \ + } \ + TRY_BRANCH_AFTER_COND(cond, 2); \ + regs.sp--; \ + regs.sp[-1].setBoolean(cond); \ + JS_END_MACRO + +BEGIN_CASE(JSOP_EQ) + EQUALITY_OP(==, false); +END_CASE(JSOP_EQ) + +BEGIN_CASE(JSOP_NE) + EQUALITY_OP(!=, true); +END_CASE(JSOP_NE) + +#undef EQUALITY_OP +#undef XML_EQUALITY_OP +#undef EXTENDED_EQUALITY_OP + +#define STRICT_EQUALITY_OP(OP, COND) \ + JS_BEGIN_MACRO \ + const Value &rref = regs.sp[-1]; \ + const Value &lref = regs.sp[-2]; \ + JSBool equal; \ + if (!StrictlyEqual(cx, lref, rref, &equal)) \ + goto error; \ + COND = equal OP JS_TRUE; \ + regs.sp--; \ + JS_END_MACRO + +BEGIN_CASE(JSOP_STRICTEQ) +{ + bool cond; + STRICT_EQUALITY_OP(==, cond); + regs.sp[-1].setBoolean(cond); +} +END_CASE(JSOP_STRICTEQ) + +BEGIN_CASE(JSOP_STRICTNE) +{ + bool cond; + STRICT_EQUALITY_OP(!=, cond); + regs.sp[-1].setBoolean(cond); +} +END_CASE(JSOP_STRICTNE) + +BEGIN_CASE(JSOP_CASE) +{ + bool cond; + STRICT_EQUALITY_OP(==, cond); + if (cond) { + regs.sp--; + len = GET_JUMP_OFFSET(regs.pc); + BRANCH(len); + } +} +END_CASE(JSOP_CASE) + +BEGIN_CASE(JSOP_CASEX) +{ + bool cond; + STRICT_EQUALITY_OP(==, cond); + if (cond) { + regs.sp--; + len = GET_JUMPX_OFFSET(regs.pc); + BRANCH(len); + } +} +END_CASE(JSOP_CASEX) + +#undef STRICT_EQUALITY_OP + +#define RELATIONAL_OP(OP) \ + JS_BEGIN_MACRO \ + Value rval = regs.sp[-1]; \ + Value lval = regs.sp[-2]; \ + bool cond; \ + /* Optimize for two int-tagged operands (typical loop control). */ \ + if (lval.isInt32() && rval.isInt32()) { \ + cond = lval.toInt32() OP rval.toInt32(); \ + } else { \ + if (lval.isObject()) \ + DEFAULT_VALUE(cx, -2, JSTYPE_NUMBER, lval); \ + if (rval.isObject()) \ + DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \ + if (lval.isString() && rval.isString()) { \ + JSString *l = lval.toString(), *r = rval.toString(); \ + int32 result; \ + if (!CompareStrings(cx, l, r, &result)) \ + goto error; \ + cond = result OP 0; \ + } else { \ + double l, r; \ + if (!ValueToNumber(cx, lval, &l) || \ + !ValueToNumber(cx, rval, &r)) { \ + goto error; \ + } \ + cond = JSDOUBLE_COMPARE(l, OP, r, false); \ + } \ + } \ + TRY_BRANCH_AFTER_COND(cond, 2); \ + regs.sp--; \ + regs.sp[-1].setBoolean(cond); \ + JS_END_MACRO + +BEGIN_CASE(JSOP_LT) + RELATIONAL_OP(<); +END_CASE(JSOP_LT) + +BEGIN_CASE(JSOP_LE) + RELATIONAL_OP(<=); +END_CASE(JSOP_LE) + +BEGIN_CASE(JSOP_GT) + RELATIONAL_OP(>); +END_CASE(JSOP_GT) + +BEGIN_CASE(JSOP_GE) + RELATIONAL_OP(>=); +END_CASE(JSOP_GE) + +#undef RELATIONAL_OP + +#define SIGNED_SHIFT_OP(OP) \ + JS_BEGIN_MACRO \ + int32_t i, j; \ + if (!ValueToECMAInt32(cx, regs.sp[-2], &i)) \ + goto error; \ + if (!ValueToECMAInt32(cx, regs.sp[-1], &j)) \ + goto error; \ + i = i OP (j & 31); \ + regs.sp--; \ + regs.sp[-1].setInt32(i); \ + JS_END_MACRO + +BEGIN_CASE(JSOP_LSH) + SIGNED_SHIFT_OP(<<); +END_CASE(JSOP_LSH) + +BEGIN_CASE(JSOP_RSH) + SIGNED_SHIFT_OP(>>); +END_CASE(JSOP_RSH) + +#undef SIGNED_SHIFT_OP + +BEGIN_CASE(JSOP_URSH) +{ + uint32_t u; + if (!ValueToECMAUint32(cx, regs.sp[-2], &u)) + goto error; + int32_t j; + if (!ValueToECMAInt32(cx, regs.sp[-1], &j)) + goto error; + + u >>= (j & 31); + + regs.sp--; + regs.sp[-1].setNumber(uint32(u)); +} +END_CASE(JSOP_URSH) + +BEGIN_CASE(JSOP_ADD) +{ + Value rval = regs.sp[-1]; + Value lval = regs.sp[-2]; + + if (lval.isInt32() && rval.isInt32()) { + int32_t l = lval.toInt32(), r = rval.toInt32(); + int32_t sum = l + r; + regs.sp--; + if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) + regs.sp[-1].setDouble(double(l) + double(r)); + else + regs.sp[-1].setInt32(sum); + } else +#if JS_HAS_XML_SUPPORT + if (IsXML(lval) && IsXML(rval)) { + if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), &rval)) + goto error; + regs.sp--; + regs.sp[-1] = rval; + } else +#endif + { + if (lval.isObject()) + DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval); + if (rval.isObject()) + DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); + bool lIsString, rIsString; + if ((lIsString = lval.isString()) | (rIsString = rval.isString())) { + JSString *lstr, *rstr; + if (lIsString) { + lstr = lval.toString(); + } else { + lstr = js_ValueToString(cx, lval); + if (!lstr) + goto error; + regs.sp[-2].setString(lstr); + } + if (rIsString) { + rstr = rval.toString(); + } else { + rstr = js_ValueToString(cx, rval); + if (!rstr) + goto error; + regs.sp[-1].setString(rstr); + } + JSString *str = js_ConcatStrings(cx, lstr, rstr); + if (!str) + goto error; + regs.sp--; + regs.sp[-1].setString(str); + } else { + double l, r; + if (!ValueToNumber(cx, lval, &l) || !ValueToNumber(cx, rval, &r)) + goto error; + l += r; + regs.sp--; + regs.sp[-1].setNumber(l); + } + } +} +END_CASE(JSOP_ADD) + +#define BINARY_OP(OP) \ + JS_BEGIN_MACRO \ + double d1, d2; \ + if (!ValueToNumber(cx, regs.sp[-2], &d1) || \ + !ValueToNumber(cx, regs.sp[-1], &d2)) { \ + goto error; \ + } \ + double d = d1 OP d2; \ + regs.sp--; \ + regs.sp[-1].setNumber(d); \ + JS_END_MACRO + +BEGIN_CASE(JSOP_SUB) + BINARY_OP(-); +END_CASE(JSOP_SUB) + +BEGIN_CASE(JSOP_MUL) + BINARY_OP(*); +END_CASE(JSOP_MUL) + +#undef BINARY_OP + +BEGIN_CASE(JSOP_DIV) +{ + double d1, d2; + if (!ValueToNumber(cx, regs.sp[-2], &d1) || + !ValueToNumber(cx, regs.sp[-1], &d2)) { + goto error; + } + regs.sp--; + if (d2 == 0) { + const Value *vp; +#ifdef XP_WIN + /* XXX MSVC miscompiles such that (NaN == 0) */ + if (JSDOUBLE_IS_NaN(d2)) + vp = &rt->NaNValue; + else +#endif + if (d1 == 0 || JSDOUBLE_IS_NaN(d1)) + vp = &rt->NaNValue; + else if (JSDOUBLE_IS_NEG(d1) != JSDOUBLE_IS_NEG(d2)) + vp = &rt->negativeInfinityValue; + else + vp = &rt->positiveInfinityValue; + regs.sp[-1] = *vp; + } else { + d1 /= d2; + regs.sp[-1].setNumber(d1); + } +} +END_CASE(JSOP_DIV) + +BEGIN_CASE(JSOP_MOD) +{ + Value &lref = regs.sp[-2]; + Value &rref = regs.sp[-1]; + int32_t l, r; + if (lref.isInt32() && rref.isInt32() && + (l = lref.toInt32()) >= 0 && (r = rref.toInt32()) > 0) { + int32_t mod = l % r; + regs.sp--; + regs.sp[-1].setInt32(mod); + } else { + double d1, d2; + if (!ValueToNumber(cx, regs.sp[-2], &d1) || + !ValueToNumber(cx, regs.sp[-1], &d2)) { + goto error; + } + regs.sp--; + if (d2 == 0) { + regs.sp[-1].setDouble(js_NaN); + } else { + d1 = js_fmod(d1, d2); + regs.sp[-1].setDouble(d1); + } + } +} +END_CASE(JSOP_MOD) + +BEGIN_CASE(JSOP_NOT) +{ + Value *_; + bool cond; + POP_BOOLEAN(cx, _, cond); + PUSH_BOOLEAN(!cond); +} +END_CASE(JSOP_NOT) + +BEGIN_CASE(JSOP_BITNOT) +{ + int32_t i; + if (!ValueToECMAInt32(cx, regs.sp[-1], &i)) + goto error; + i = ~i; + regs.sp[-1].setInt32(i); +} +END_CASE(JSOP_BITNOT) + +BEGIN_CASE(JSOP_NEG) +{ + /* + * When the operand is int jsval, INT32_FITS_IN_JSVAL(i) implies + * INT32_FITS_IN_JSVAL(-i) unless i is 0 or INT32_MIN when the + * results, -0.0 or INT32_MAX + 1, are jsdouble values. + */ + const Value &ref = regs.sp[-1]; + int32_t i; + if (ref.isInt32() && (i = ref.toInt32()) != 0 && i != INT32_MIN) { + i = -i; + regs.sp[-1].setInt32(i); + } else { + double d; + if (!ValueToNumber(cx, regs.sp[-1], &d)) + goto error; + d = -d; + regs.sp[-1].setDouble(d); + } +} +END_CASE(JSOP_NEG) + +BEGIN_CASE(JSOP_POS) + if (!ValueToNumber(cx, ®s.sp[-1])) + goto error; +END_CASE(JSOP_POS) + +BEGIN_CASE(JSOP_DELNAME) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + jsid id = ATOM_TO_JSID(atom); + JSObject *obj, *obj2; + JSProperty *prop; + if (!js_FindProperty(cx, id, &obj, &obj2, &prop)) + goto error; + + /* Strict mode code should never contain JSOP_DELNAME opcodes. */ + JS_ASSERT(!script->strictModeCode); + + /* ECMA says to return true if name is undefined or inherited. */ + PUSH_BOOLEAN(true); + if (prop) { + if (!obj->deleteProperty(cx, id, ®s.sp[-1], false)) + goto error; + } +} +END_CASE(JSOP_DELNAME) + +BEGIN_CASE(JSOP_DELPROP) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + jsid id = ATOM_TO_JSID(atom); + + JSObject *obj; + FETCH_OBJECT(cx, -1, obj); + + Value rval; + if (!obj->deleteProperty(cx, id, &rval, script->strictModeCode)) + goto error; + + regs.sp[-1] = rval; +} +END_CASE(JSOP_DELPROP) + +BEGIN_CASE(JSOP_DELELEM) +{ + /* Fetch the left part and resolve it to a non-null object. */ + JSObject *obj; + FETCH_OBJECT(cx, -2, obj); + + /* Fetch index and convert it to id suitable for use with obj. */ + jsid id; + FETCH_ELEMENT_ID(obj, -1, id); + + /* Get or set the element. */ + if (!obj->deleteProperty(cx, id, ®s.sp[-2], script->strictModeCode)) + goto error; + + regs.sp--; +} +END_CASE(JSOP_DELELEM) + +BEGIN_CASE(JSOP_TYPEOFEXPR) +BEGIN_CASE(JSOP_TYPEOF) +{ + const Value &ref = regs.sp[-1]; + JSType type = JS_TypeOfValue(cx, Jsvalify(ref)); + JSAtom *atom = rt->atomState.typeAtoms[type]; + regs.sp[-1].setString(ATOM_TO_STRING(atom)); +} +END_CASE(JSOP_TYPEOF) + +BEGIN_CASE(JSOP_VOID) + regs.sp[-1].setUndefined(); +END_CASE(JSOP_VOID) + +{ + JSObject *obj; + JSAtom *atom; + jsid id; + jsint i; + +BEGIN_CASE(JSOP_INCELEM) +BEGIN_CASE(JSOP_DECELEM) +BEGIN_CASE(JSOP_ELEMINC) +BEGIN_CASE(JSOP_ELEMDEC) + + /* + * Delay fetching of id until we have the object to ensure the proper + * evaluation order. See bug 372331. + */ + id = JSID_VOID; + i = -2; + goto fetch_incop_obj; + +BEGIN_CASE(JSOP_INCPROP) +BEGIN_CASE(JSOP_DECPROP) +BEGIN_CASE(JSOP_PROPINC) +BEGIN_CASE(JSOP_PROPDEC) + LOAD_ATOM(0, atom); + id = ATOM_TO_JSID(atom); + i = -1; + + fetch_incop_obj: + FETCH_OBJECT(cx, i, obj); + if (JSID_IS_VOID(id)) + FETCH_ELEMENT_ID(obj, -1, id); + goto do_incop; + +BEGIN_CASE(JSOP_INCNAME) +BEGIN_CASE(JSOP_DECNAME) +BEGIN_CASE(JSOP_NAMEINC) +BEGIN_CASE(JSOP_NAMEDEC) +BEGIN_CASE(JSOP_INCGNAME) +BEGIN_CASE(JSOP_DECGNAME) +BEGIN_CASE(JSOP_GNAMEINC) +BEGIN_CASE(JSOP_GNAMEDEC) +{ + obj = ®s.fp->scopeChain(); + if (js_CodeSpec[op].format & JOF_GNAME) + obj = obj->getGlobal(); + + JSObject *obj2; + PropertyCacheEntry *entry; + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + if (obj == obj2 && entry->vword.isSlot()) { + uint32 slot = entry->vword.toSlot(); + Value &rref = obj->nativeGetSlotRef(slot); + int32_t tmp; + if (JS_LIKELY(rref.isInt32() && CanIncDecWithoutOverflow(tmp = rref.toInt32()))) { + int32_t inc = tmp + ((js_CodeSpec[op].format & JOF_INC) ? 1 : -1); + if (!(js_CodeSpec[op].format & JOF_POST)) + tmp = inc; + rref.getInt32Ref() = inc; + PUSH_INT32(tmp); + len = JSOP_INCNAME_LENGTH; + DO_NEXT_OP(len); + } + } + LOAD_ATOM(0, atom); + } + + id = ATOM_TO_JSID(atom); + JSProperty *prop; + if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop)) + goto error; + if (!prop) { + atomNotDefined = atom; + goto atom_not_defined; + } +} + +do_incop: +{ + /* + * We need a root to store the value to leave on the stack until + * we have done with obj->setProperty. + */ + PUSH_NULL(); + if (!obj->getProperty(cx, id, ®s.sp[-1])) + goto error; + + const JSCodeSpec *cs = &js_CodeSpec[op]; + JS_ASSERT(cs->ndefs == 1); + JS_ASSERT((cs->format & JOF_TMPSLOT_MASK) >= JOF_TMPSLOT2); + Value &ref = regs.sp[-1]; + int32_t tmp; + if (JS_LIKELY(ref.isInt32() && CanIncDecWithoutOverflow(tmp = ref.toInt32()))) { + int incr = (cs->format & JOF_INC) ? 1 : -1; + if (cs->format & JOF_POST) + ref.getInt32Ref() = tmp + incr; + else + ref.getInt32Ref() = tmp += incr; + regs.fp->setAssigning(); + JSBool ok = obj->setProperty(cx, id, &ref, script->strictModeCode); + regs.fp->clearAssigning(); + if (!ok) + goto error; + + /* + * We must set regs.sp[-1] to tmp for both post and pre increments + * as the setter overwrites regs.sp[-1]. + */ + ref.setInt32(tmp); + } else { + /* We need an extra root for the result. */ + PUSH_NULL(); + if (!js_DoIncDec(cx, cs, ®s.sp[-2], ®s.sp[-1])) + goto error; + regs.fp->setAssigning(); + JSBool ok = obj->setProperty(cx, id, ®s.sp[-1], script->strictModeCode); + regs.fp->clearAssigning(); + if (!ok) + goto error; + regs.sp--; + } + + if (cs->nuses == 0) { + /* regs.sp[-1] already contains the result of name increment. */ + } else { + regs.sp[-1 - cs->nuses] = regs.sp[-1]; + regs.sp -= cs->nuses; + } + len = cs->length; + DO_NEXT_OP(len); +} +} + +{ + int incr, incr2; + uint32 slot; + Value *vp; + + /* Position cases so the most frequent i++ does not need a jump. */ +BEGIN_CASE(JSOP_DECARG) + incr = -1; incr2 = -1; goto do_arg_incop; +BEGIN_CASE(JSOP_ARGDEC) + incr = -1; incr2 = 0; goto do_arg_incop; +BEGIN_CASE(JSOP_INCARG) + incr = 1; incr2 = 1; goto do_arg_incop; +BEGIN_CASE(JSOP_ARGINC) + incr = 1; incr2 = 0; + + do_arg_incop: + slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < regs.fp->numFormalArgs()); + METER_SLOT_OP(op, slot); + vp = argv + slot; + goto do_int_fast_incop; + +BEGIN_CASE(JSOP_DECLOCAL) + incr = -1; incr2 = -1; goto do_local_incop; +BEGIN_CASE(JSOP_LOCALDEC) + incr = -1; incr2 = 0; goto do_local_incop; +BEGIN_CASE(JSOP_INCLOCAL) + incr = 1; incr2 = 1; goto do_local_incop; +BEGIN_CASE(JSOP_LOCALINC) + incr = 1; incr2 = 0; + + /* + * do_local_incop comes right before do_int_fast_incop as we want to + * avoid an extra jump for variable cases as local++ is more frequent + * than arg++. + */ + do_local_incop: + slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < regs.fp->numSlots()); + METER_SLOT_OP(op, slot); + vp = regs.fp->slots() + slot; + + do_int_fast_incop: + int32_t tmp; + if (JS_LIKELY(vp->isInt32() && CanIncDecWithoutOverflow(tmp = vp->toInt32()))) { + vp->getInt32Ref() = tmp + incr; + JS_ASSERT(JSOP_INCARG_LENGTH == js_CodeSpec[op].length); + SKIP_POP_AFTER_SET(JSOP_INCARG_LENGTH, 0); + PUSH_INT32(tmp + incr2); + } else { + PUSH_COPY(*vp); + if (!js_DoIncDec(cx, &js_CodeSpec[op], ®s.sp[-1], vp)) + goto error; + } + len = JSOP_INCARG_LENGTH; + JS_ASSERT(len == js_CodeSpec[op].length); + DO_NEXT_OP(len); +} + +BEGIN_CASE(JSOP_THIS) + if (!regs.fp->computeThis(cx)) + goto error; + PUSH_COPY(regs.fp->thisValue()); +END_CASE(JSOP_THIS) + +BEGIN_CASE(JSOP_UNBRANDTHIS) +{ + if (!regs.fp->computeThis(cx)) + goto error; + Value &thisv = regs.fp->thisValue(); + if (thisv.isObject()) { + JSObject *obj = &thisv.toObject(); + if (obj->isNative()) + obj->unbrand(cx); + } +} +END_CASE(JSOP_UNBRANDTHIS) + +{ + JSObject *obj; + Value *vp; + jsint i; + +BEGIN_CASE(JSOP_GETTHISPROP) + if (!regs.fp->computeThis(cx)) + goto error; + i = 0; + PUSH_COPY(regs.fp->thisValue()); + goto do_getprop_body; + +BEGIN_CASE(JSOP_GETARGPROP) +{ + i = ARGNO_LEN; + uint32 slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < regs.fp->numFormalArgs()); + PUSH_COPY(argv[slot]); + goto do_getprop_body; +} + +BEGIN_CASE(JSOP_GETLOCALPROP) +{ + i = SLOTNO_LEN; + uint32 slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < script->nslots); + PUSH_COPY(regs.fp->slots()[slot]); + goto do_getprop_body; +} + +BEGIN_CASE(JSOP_GETPROP) +BEGIN_CASE(JSOP_GETXPROP) + i = 0; + + do_getprop_body: + vp = ®s.sp[-1]; + + do_getprop_with_lval: + VALUE_TO_OBJECT(cx, vp, obj); + + { + Value rval; + do { + /* + * We do not impose the method read barrier if in an imacro, + * assuming any property gets it does (e.g., for 'toString' + * from JSOP_NEW) will not be leaked to the calling script. + */ + JSObject *aobj = js_GetProtoIfDenseArray(obj); + + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(i, aobj, obj2, entry); + if (entry->vword.isFunObj()) { + rval.setObject(entry->vword.toFunObj()); + } else if (entry->vword.isSlot()) { + uint32 slot = entry->vword.toSlot(); + rval = obj2->nativeGetSlot(slot); + } else { + JS_ASSERT(entry->vword.isShape()); + const Shape *shape = entry->vword.toShape(); + NATIVE_GET(cx, obj, obj2, shape, + regs.fp->hasImacropc() ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER, + &rval); + } + break; + } + + jsid id = ATOM_TO_JSID(atom); + if (JS_LIKELY(!aobj->getOps()->getProperty) + ? !js_GetPropertyHelper(cx, obj, id, + (regs.fp->hasImacropc() || + regs.pc[JSOP_GETPROP_LENGTH + i] == JSOP_IFEQ) + ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER + : JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER, + &rval) + : !obj->getProperty(cx, id, &rval)) { + goto error; + } + } while (0); + + regs.sp[-1] = rval; + assertSameCompartment(cx, regs.sp[-1]); + JS_ASSERT(JSOP_GETPROP_LENGTH + i == js_CodeSpec[op].length); + len = JSOP_GETPROP_LENGTH + i; + } +END_VARLEN_CASE + +BEGIN_CASE(JSOP_LENGTH) + vp = ®s.sp[-1]; + if (vp->isString()) { + vp->setInt32(vp->toString()->length()); + } else if (vp->isObject()) { + JSObject *obj = &vp->toObject(); + if (obj->isArray()) { + jsuint length = obj->getArrayLength(); + regs.sp[-1].setNumber(length); + } else if (obj->isArguments() && !obj->isArgsLengthOverridden()) { + uint32 length = obj->getArgsInitialLength(); + JS_ASSERT(length < INT32_MAX); + regs.sp[-1].setInt32(int32_t(length)); + } else { + i = -2; + goto do_getprop_with_lval; + } + } else { + i = -2; + goto do_getprop_with_lval; + } +END_CASE(JSOP_LENGTH) + +} + +BEGIN_CASE(JSOP_CALLPROP) +{ + Value lval = regs.sp[-1]; + + Value objv; + if (lval.isObject()) { + objv = lval; + } else { + JSProtoKey protoKey; + if (lval.isString()) { + protoKey = JSProto_String; + } else if (lval.isNumber()) { + protoKey = JSProto_Number; + } else if (lval.isBoolean()) { + protoKey = JSProto_Boolean; + } else { + JS_ASSERT(lval.isNull() || lval.isUndefined()); + js_ReportIsNullOrUndefined(cx, -1, lval, NULL); + goto error; + } + JSObject *pobj; + if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj)) + goto error; + objv.setObject(*pobj); + } + + JSObject *aobj = js_GetProtoIfDenseArray(&objv.toObject()); + Value rval; + + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, aobj, obj2, entry); + if (entry->vword.isFunObj()) { + rval.setObject(entry->vword.toFunObj()); + } else if (entry->vword.isSlot()) { + uint32 slot = entry->vword.toSlot(); + rval = obj2->nativeGetSlot(slot); + } else { + JS_ASSERT(entry->vword.isShape()); + const Shape *shape = entry->vword.toShape(); + NATIVE_GET(cx, &objv.toObject(), obj2, shape, JSGET_NO_METHOD_BARRIER, &rval); + } + regs.sp[-1] = rval; + assertSameCompartment(cx, regs.sp[-1]); + PUSH_COPY(lval); + } else { + /* + * Cache miss: use the immediate atom that was loaded for us under + * PropertyCache::test. + */ + jsid id; + id = ATOM_TO_JSID(atom); + + PUSH_NULL(); + if (lval.isObject()) { + if (!js_GetMethod(cx, &objv.toObject(), id, + JS_LIKELY(!aobj->getOps()->getProperty) + ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER + : JSGET_NO_METHOD_BARRIER, + &rval)) { + goto error; + } + regs.sp[-1] = objv; + regs.sp[-2] = rval; + assertSameCompartment(cx, regs.sp[-1], regs.sp[-2]); + } else { + JS_ASSERT(!objv.toObject().getOps()->getProperty); + if (!js_GetPropertyHelper(cx, &objv.toObject(), id, + JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER, + &rval)) { + goto error; + } + regs.sp[-1] = lval; + regs.sp[-2] = rval; + assertSameCompartment(cx, regs.sp[-1], regs.sp[-2]); + } + } +#if JS_HAS_NO_SUCH_METHOD + if (JS_UNLIKELY(rval.isUndefined()) && regs.sp[-1].isObject()) { + LOAD_ATOM(0, atom); + regs.sp[-2].setString(ATOM_TO_STRING(atom)); + if (!js_OnUnknownMethod(cx, regs.sp - 2)) + goto error; + } +#endif +} +END_CASE(JSOP_CALLPROP) + +BEGIN_CASE(JSOP_UNBRAND) + JS_ASSERT(regs.sp - regs.fp->slots() >= 1); + regs.sp[-1].toObject().unbrand(cx); +END_CASE(JSOP_UNBRAND) + +BEGIN_CASE(JSOP_SETGNAME) +BEGIN_CASE(JSOP_SETNAME) +BEGIN_CASE(JSOP_SETPROP) +BEGIN_CASE(JSOP_SETMETHOD) +{ + Value rval = regs.sp[-1]; + JS_ASSERT_IF(op == JSOP_SETMETHOD, IsFunctionObject(rval)); + Value &lref = regs.sp[-2]; + JS_ASSERT_IF(op == JSOP_SETNAME, lref.isObject()); + JSObject *obj; + VALUE_TO_OBJECT(cx, &lref, obj); + + JS_ASSERT_IF(op == JSOP_SETGNAME, obj == regs.fp->scopeChain().getGlobal()); + + do { + PropertyCache *cache = &JS_PROPERTY_CACHE(cx); + + /* + * Probe the property cache, specializing for two important + * set-property cases. First: + * + * function f(a, b, c) { + * var o = {p:a, q:b, r:c}; + * return o; + * } + * + * or similar real-world cases, which evolve a newborn native + * object predicatably through some bounded number of property + * additions. And second: + * + * o.p = x; + * + * in a frequently executed method or loop body, where p will + * (possibly after the first iteration) always exist in native + * object o. + */ + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + if (cache->testForSet(cx, regs.pc, obj, &entry, &obj2, &atom)) { + /* + * Property cache hit, only partially confirmed by testForSet. We + * know that the entry applies to regs.pc and that obj's shape + * matches. + * + * The entry predicts either a new property to be added directly to + * obj by this set, or on an existing "own" property, or on a + * prototype property that has a setter. + */ + const Shape *shape = entry->vword.toShape(); + JS_ASSERT_IF(shape->isDataDescriptor(), shape->writable()); + JS_ASSERT_IF(shape->hasSlot(), entry->vcapTag() == 0); + + /* + * Fastest path: check whether obj already has the cached shape and + * call NATIVE_SET and break to get out of the do-while(0). But we + * can call NATIVE_SET only for a direct or proto-setter hit. + */ + if (!entry->adding()) { + if (entry->vcapTag() == 0 || + ((obj2 = obj->getProto()) && obj2->shape() == entry->vshape())) + { +#ifdef DEBUG + if (entry->directHit()) { + JS_ASSERT(obj->nativeContains(*shape)); + } else { + JS_ASSERT(obj2->nativeContains(*shape)); + JS_ASSERT(entry->vcapTag() == 1); + JS_ASSERT(entry->kshape != entry->vshape()); + JS_ASSERT(!shape->hasSlot()); + } +#endif + + PCMETER(cache->pchits++); + PCMETER(cache->setpchits++); + NATIVE_SET(cx, obj, shape, entry, script->strictModeCode, &rval); + break; + } + } else { + JS_ASSERT(obj->isExtensible()); + + if (obj->nativeEmpty()) { + if (!obj->ensureClassReservedSlotsForEmptyObject(cx)) + goto error; + } + + uint32 slot; + if (shape->previous() == obj->lastProperty() && + entry->vshape() == rt->protoHazardShape && + shape->hasDefaultSetter()) { + slot = shape->slot; + JS_ASSERT(slot == obj->slotSpan()); + + /* + * Fast path: adding a plain old property that was once at + * the frontier of the property tree, whose slot is next to + * claim among the already-allocated slots in obj, where + * shape->table has not been created yet. + */ + PCMETER(cache->pchits++); + PCMETER(cache->addpchits++); + + if (slot < obj->numSlots()) { + JS_ASSERT(obj->getSlot(slot).isUndefined()); + } else { + if (!obj->allocSlot(cx, &slot)) + goto error; + JS_ASSERT(slot == shape->slot); + } + + /* Simply extend obj's property tree path with shape! */ + obj->extend(cx, shape); + + /* + * No method change check here because here we are adding a + * new property, not updating an existing slot's value that + * might contain a method of a branded shape. + */ + TRACE_1(AddProperty, obj); + obj->nativeSetSlot(slot, rval); + + /* + * Purge the property cache of the id we may have just + * shadowed in obj's scope and proto chains. + */ + js_PurgeScopeChain(cx, obj, shape->id); + break; + } + } + PCMETER(cache->setpcmisses++); + + LOAD_ATOM(0, atom); + } else { + JS_ASSERT(atom); + } + + jsid id = ATOM_TO_JSID(atom); + if (entry && JS_LIKELY(!obj->getOps()->setProperty)) { + uintN defineHow; + if (op == JSOP_SETMETHOD) + defineHow = JSDNP_CACHE_RESULT | JSDNP_SET_METHOD; + else if (op == JSOP_SETNAME) + defineHow = JSDNP_CACHE_RESULT | JSDNP_UNQUALIFIED; + else + defineHow = JSDNP_CACHE_RESULT; + if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rval, script->strictModeCode)) + goto error; + } else { + if (!obj->setProperty(cx, id, &rval, script->strictModeCode)) + goto error; + ABORT_RECORDING(cx, "Non-native set"); + } + } while (0); +} +END_SET_CASE_STORE_RVAL(JSOP_SETPROP, 2); + +BEGIN_CASE(JSOP_GETELEM) +{ + Value &lref = regs.sp[-2]; + Value &rref = regs.sp[-1]; + if (lref.isString() && rref.isInt32()) { + JSString *str = lref.toString(); + int32_t i = rref.toInt32(); + if (size_t(i) < str->length()) { + str = JSString::getUnitString(cx, str, size_t(i)); + if (!str) + goto error; + regs.sp--; + regs.sp[-1].setString(str); + len = JSOP_GETELEM_LENGTH; + DO_NEXT_OP(len); + } + } + + JSObject *obj; + VALUE_TO_OBJECT(cx, &lref, obj); + + const Value *copyFrom; + Value rval; + jsid id; + if (rref.isInt32()) { + int32_t i = rref.toInt32(); + if (obj->isDenseArray()) { + jsuint idx = jsuint(i); + + if (idx < obj->getDenseArrayCapacity()) { + copyFrom = obj->addressOfDenseArrayElement(idx); + if (!copyFrom->isMagic()) + goto end_getelem; + } + } else if (obj->isArguments()) { + uint32 arg = uint32(i); + + if (arg < obj->getArgsInitialLength()) { + copyFrom = obj->addressOfArgsElement(arg); + if (!copyFrom->isMagic(JS_ARGS_HOLE)) { + if (JSStackFrame *afp = (JSStackFrame *) obj->getPrivate()) + copyFrom = &afp->canonicalActualArg(arg); + goto end_getelem; + } + } + } + if (JS_LIKELY(INT_FITS_IN_JSID(i))) + id = INT_TO_JSID(i); + else + goto intern_big_int; + } else { + int32_t i; + if (ValueFitsInInt32(rref, &i) && INT_FITS_IN_JSID(i)) { + id = INT_TO_JSID(i); + } else { + intern_big_int: + if (!js_InternNonIntElementId(cx, obj, rref, &id)) + goto error; + } + } + + if (!obj->getProperty(cx, id, &rval)) + goto error; + copyFrom = &rval; + + end_getelem: + regs.sp--; + regs.sp[-1] = *copyFrom; + assertSameCompartment(cx, regs.sp[-1]); +} +END_CASE(JSOP_GETELEM) + +BEGIN_CASE(JSOP_CALLELEM) +{ + /* Find the object on which to look for |this|'s properties. */ + Value thisv = regs.sp[-2]; + JSObject *thisObj = ValuePropertyBearer(cx, thisv, -2); + if (!thisObj) + goto error; + + /* Fetch index and convert it to id suitable for use with obj. */ + jsid id; + FETCH_ELEMENT_ID(thisObj, -1, id); + + /* Get the method. */ + if (!js_GetMethod(cx, thisObj, id, JSGET_NO_METHOD_BARRIER, ®s.sp[-2])) + goto error; + +#if JS_HAS_NO_SUCH_METHOD + if (JS_UNLIKELY(regs.sp[-2].isUndefined()) && thisv.isObject()) { + /* For js_OnUnknownMethod, sp[-2] is the index, and sp[-1] is the object missing it. */ + regs.sp[-2] = regs.sp[-1]; + regs.sp[-1].setObject(*thisObj); + if (!js_OnUnknownMethod(cx, regs.sp - 2)) + goto error; + } else +#endif + { + regs.sp[-1] = thisv; + } +} +END_CASE(JSOP_CALLELEM) + +BEGIN_CASE(JSOP_SETELEM) +{ + JSObject *obj; + FETCH_OBJECT(cx, -3, obj); + jsid id; + FETCH_ELEMENT_ID(obj, -2, id); + Value rval; + do { + if (obj->isDenseArray() && JSID_IS_INT(id)) { + jsuint length = obj->getDenseArrayCapacity(); + jsint i = JSID_TO_INT(id); + if ((jsuint)i < length) { + if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) { + if (js_PrototypeHasIndexedProperties(cx, obj)) + break; + if ((jsuint)i >= obj->getArrayLength()) + obj->setArrayLength(i + 1); + } + obj->setDenseArrayElement(i, regs.sp[-1]); + goto end_setelem; + } + } + } while (0); + rval = regs.sp[-1]; + if (!obj->setProperty(cx, id, &rval, script->strictModeCode)) + goto error; + end_setelem:; +} +END_SET_CASE_STORE_RVAL(JSOP_SETELEM, 3) + +BEGIN_CASE(JSOP_ENUMELEM) +{ + /* Funky: the value to set is under the [obj, id] pair. */ + JSObject *obj; + FETCH_OBJECT(cx, -2, obj); + jsid id; + FETCH_ELEMENT_ID(obj, -1, id); + Value rval = regs.sp[-3]; + if (!obj->setProperty(cx, id, &rval, script->strictModeCode)) + goto error; + regs.sp -= 3; +} +END_CASE(JSOP_ENUMELEM) + +{ // begin block around calling opcodes + JSFunction *newfun; + JSObject *callee; + uint32 flags; + uintN argc; + Value *vp; + +BEGIN_CASE(JSOP_NEW) +{ + /* Get immediate argc and find the constructor function. */ + argc = GET_ARGC(regs.pc); + vp = regs.sp - (2 + argc); + JS_ASSERT(vp >= regs.fp->base()); + + /* + * Assign lval, callee, and newfun exactly as the code at inline_call: expects to + * find them, to avoid nesting a js_Interpret call via js_InvokeConstructor. + */ + if (IsFunctionObject(vp[0], &callee)) { + newfun = callee->getFunctionPrivate(); + if (newfun->isInterpreted()) { + if (newfun->u.i.script->isEmpty()) { + JSObject *obj2 = js_CreateThisForFunction(cx, callee); + if (!obj2) + goto error; + vp[0].setObject(*obj2); + regs.sp = vp + 1; + goto end_new; + } + + flags = JSFRAME_CONSTRUCTING; + goto inline_call; + } + } + + if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc))) + goto error; + regs.sp = vp + 1; + CHECK_INTERRUPT_HANDLER(); + TRACE_0(NativeCallComplete); + + end_new:; +} +END_CASE(JSOP_NEW) + +BEGIN_CASE(JSOP_EVAL) +{ + argc = GET_ARGC(regs.pc); + vp = regs.sp - (argc + 2); + + if (!IsFunctionObject(*vp, &callee)) + goto call_using_invoke; + + newfun = callee->getFunctionPrivate(); + if (!IsBuiltinEvalFunction(newfun)) + goto call_using_invoke; + + if (!DirectEval(cx, newfun, argc, vp)) + goto error; +} +END_CASE(JSOP_EVAL) + +BEGIN_CASE(JSOP_CALL) +BEGIN_CASE(JSOP_FUNAPPLY) +BEGIN_CASE(JSOP_FUNCALL) +{ + argc = GET_ARGC(regs.pc); + vp = regs.sp - (argc + 2); + + if (IsFunctionObject(*vp, &callee)) { + newfun = callee->getFunctionPrivate(); + + /* Clear frame flags since this is not a constructor call. */ + flags = 0; + if (newfun->isInterpreted()) + inline_call: + { + JSScript *newscript = newfun->script(); + if (JS_UNLIKELY(newscript->isEmpty())) { + vp->setUndefined(); + regs.sp = vp + 1; + goto end_call; + } + + /* Restrict recursion of lightweight functions. */ + if (JS_UNLIKELY(inlineCallCount >= JS_MAX_INLINE_CALL_COUNT)) { + js_ReportOverRecursed(cx); + goto error; + } + + /* Get pointer to new frame/slots, prepare arguments. */ + StackSpace &stack = cx->stack(); + JSStackFrame *newfp = stack.getInlineFrame(cx, regs.sp, argc, newfun, + newscript, &flags); + if (JS_UNLIKELY(!newfp)) + goto error; + + /* Initialize frame, locals. */ + newfp->initCallFrame(cx, *callee, newfun, argc, flags); + SetValueRangeToUndefined(newfp->slots(), newscript->nfixed); + + /* Officially push the frame. */ + stack.pushInlineFrame(cx, newscript, newfp, ®s); + + /* Refresh interpreter locals. */ + JS_ASSERT(newfp == regs.fp); + script = newscript; + argv = regs.fp->formalArgsEnd() - newfun->nargs; + atoms = script->atomMap.vector; + + /* Now that the new frame is rooted, maybe create a call object. */ + if (newfun->isHeavyweight() && !js_GetCallObject(cx, regs.fp)) + goto error; + + RESET_USE_METHODJIT(); + inlineCallCount++; + JS_RUNTIME_METER(rt, inlineCalls); + + TRACE_0(EnterFrame); + + CHECK_INTERRUPT_HANDLER(); + +#ifdef JS_METHODJIT + /* Try to ensure methods are method JIT'd. */ + mjit::CompileRequest request = (interpMode == JSINTERP_NORMAL) + ? mjit::CompileRequest_Interpreter + : mjit::CompileRequest_JIT; + mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, regs.fp, request); + if (status == mjit::Compile_Error) + goto error; + if (!TRACE_RECORDER(cx) && !TRACE_PROFILER(cx) && status == mjit::Compile_Okay) { + interpReturnOK = mjit::JaegerShot(cx); + CHECK_INTERRUPT_HANDLER(); + goto jit_return; + } +#endif + + if (!ScriptPrologue(cx, regs.fp)) + goto error; + + CHECK_INTERRUPT_HANDLER(); + + /* Load first op and dispatch it (safe since JSOP_STOP). */ + op = (JSOp) *regs.pc; + DO_OP(); + } + + Probes::enterJSFun(cx, newfun, script); + JSBool ok = CallJSNative(cx, newfun->u.n.native, argc, vp); + Probes::exitJSFun(cx, newfun, script); + regs.sp = vp + 1; + if (!ok) + goto error; + TRACE_0(NativeCallComplete); + goto end_call; + } + + call_using_invoke: + bool ok; + ok = Invoke(cx, InvokeArgsAlreadyOnTheStack(vp, argc), 0); + regs.sp = vp + 1; + CHECK_INTERRUPT_HANDLER(); + if (!ok) + goto error; + JS_RUNTIME_METER(rt, nonInlineCalls); + TRACE_0(NativeCallComplete); + + end_call:; +} +END_CASE(JSOP_CALL) + +} // end block around calling opcodes + +BEGIN_CASE(JSOP_SETCALL) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_LEFTSIDE_OF_ASS); + goto error; +} +END_CASE(JSOP_SETCALL) + +#define PUSH_IMPLICIT_THIS(cx, obj, funval) \ + JS_BEGIN_MACRO \ + Value v; \ + if (!ComputeImplicitThis(cx, obj, funval, &v)) \ + goto error; \ + PUSH_COPY(v); \ + JS_END_MACRO \ + +BEGIN_CASE(JSOP_GETGNAME) +BEGIN_CASE(JSOP_CALLGNAME) +BEGIN_CASE(JSOP_NAME) +BEGIN_CASE(JSOP_CALLNAME) +{ + JSObject *obj = ®s.fp->scopeChain(); + + const Shape *shape; + Value rval; + + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + if (entry->vword.isFunObj()) { + PUSH_OBJECT(entry->vword.toFunObj()); + } else if (entry->vword.isSlot()) { + uintN slot = entry->vword.toSlot(); + PUSH_COPY(obj2->nativeGetSlot(slot)); + } else { + JS_ASSERT(entry->vword.isShape()); + shape = entry->vword.toShape(); + NATIVE_GET(cx, obj, obj2, shape, JSGET_METHOD_BARRIER, &rval); + PUSH_COPY(rval); + } + + JS_ASSERT(obj->isGlobal() || IsCacheableNonGlobalScope(obj)); + if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME) + PUSH_IMPLICIT_THIS(cx, obj, regs.sp[-1]); + len = JSOP_NAME_LENGTH; + DO_NEXT_OP(len); + } + + jsid id; + id = ATOM_TO_JSID(atom); + JSProperty *prop; + if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop)) + goto error; + if (!prop) { + /* Kludge to allow (typeof foo == "undefined") tests. */ + JSOp op2 = js_GetOpcode(cx, script, regs.pc + JSOP_NAME_LENGTH); + if (op2 == JSOP_TYPEOF) { + PUSH_UNDEFINED(); + len = JSOP_NAME_LENGTH; + DO_NEXT_OP(len); + } + atomNotDefined = atom; + goto atom_not_defined; + } + + /* Take the slow path if prop was not found in a native object. */ + if (!obj->isNative() || !obj2->isNative()) { + if (!obj->getProperty(cx, id, &rval)) + goto error; + } else { + shape = (Shape *)prop; + JSObject *normalized = obj; + if (normalized->getClass() == &js_WithClass && !shape->hasDefaultGetter()) + normalized = js_UnwrapWithObject(cx, normalized); + NATIVE_GET(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, &rval); + } + + PUSH_COPY(rval); + + /* obj must be on the scope chain, thus not a function. */ + if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME) + PUSH_IMPLICIT_THIS(cx, obj, rval); +} +END_CASE(JSOP_NAME) + +BEGIN_CASE(JSOP_UINT16) + PUSH_INT32((int32_t) GET_UINT16(regs.pc)); +END_CASE(JSOP_UINT16) + +BEGIN_CASE(JSOP_UINT24) + PUSH_INT32((int32_t) GET_UINT24(regs.pc)); +END_CASE(JSOP_UINT24) + +BEGIN_CASE(JSOP_INT8) + PUSH_INT32(GET_INT8(regs.pc)); +END_CASE(JSOP_INT8) + +BEGIN_CASE(JSOP_INT32) + PUSH_INT32(GET_INT32(regs.pc)); +END_CASE(JSOP_INT32) + +BEGIN_CASE(JSOP_INDEXBASE) + /* + * Here atoms can exceed script->atomMap.length as we use atoms as a + * segment register for object literals as well. + */ + atoms += GET_INDEXBASE(regs.pc); +END_CASE(JSOP_INDEXBASE) + +BEGIN_CASE(JSOP_INDEXBASE1) +BEGIN_CASE(JSOP_INDEXBASE2) +BEGIN_CASE(JSOP_INDEXBASE3) + atoms += (op - JSOP_INDEXBASE1 + 1) << 16; +END_CASE(JSOP_INDEXBASE3) + +BEGIN_CASE(JSOP_RESETBASE0) +BEGIN_CASE(JSOP_RESETBASE) + atoms = script->atomMap.vector; +END_CASE(JSOP_RESETBASE) + +BEGIN_CASE(JSOP_DOUBLE) +{ + JS_ASSERT(!regs.fp->hasImacropc()); + double dbl; + LOAD_DOUBLE(0, dbl); + PUSH_DOUBLE(dbl); +} +END_CASE(JSOP_DOUBLE) + +BEGIN_CASE(JSOP_STRING) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + PUSH_STRING(ATOM_TO_STRING(atom)); +} +END_CASE(JSOP_STRING) + +BEGIN_CASE(JSOP_OBJECT) +{ + JSObject *obj; + LOAD_OBJECT(0, obj); + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_OBJECT) + +BEGIN_CASE(JSOP_REGEXP) +{ + /* + * Push a regexp object cloned from the regexp literal object mapped by the + * bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was + * flouted by many browser-based implementations. + * + * We avoid the GetScopeChain call here and pass fp->scopeChain as + * js_GetClassPrototype uses the latter only to locate the global. + */ + jsatomid index = GET_FULL_INDEX(0); + JSObject *proto; + if (!js_GetClassPrototype(cx, ®s.fp->scopeChain(), JSProto_RegExp, &proto)) + goto error; + JS_ASSERT(proto); + JSObject *obj = js_CloneRegExpObject(cx, script->getRegExp(index), proto); + if (!obj) + goto error; + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_REGEXP) + +BEGIN_CASE(JSOP_ZERO) + PUSH_INT32(0); +END_CASE(JSOP_ZERO) + +BEGIN_CASE(JSOP_ONE) + PUSH_INT32(1); +END_CASE(JSOP_ONE) + +BEGIN_CASE(JSOP_NULL) + PUSH_NULL(); +END_CASE(JSOP_NULL) + +BEGIN_CASE(JSOP_FALSE) + PUSH_BOOLEAN(false); +END_CASE(JSOP_FALSE) + +BEGIN_CASE(JSOP_TRUE) + PUSH_BOOLEAN(true); +END_CASE(JSOP_TRUE) + +{ +BEGIN_CASE(JSOP_TABLESWITCH) +{ + jsbytecode *pc2 = regs.pc; + len = GET_JUMP_OFFSET(pc2); + + /* + * ECMAv2+ forbids conversion of discriminant, so we will skip to the + * default case if the discriminant isn't already an int jsval. (This + * opcode is emitted only for dense jsint-domain switches.) + */ + const Value &rref = *--regs.sp; + int32_t i; + if (rref.isInt32()) { + i = rref.toInt32(); + } else { + double d; + /* Don't use JSDOUBLE_IS_INT32; treat -0 (double) as 0. */ + if (!rref.isDouble() || (d = rref.toDouble()) != (i = int32_t(rref.toDouble()))) + DO_NEXT_OP(len); + } + + pc2 += JUMP_OFFSET_LEN; + jsint low = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + jsint high = GET_JUMP_OFFSET(pc2); + + i -= low; + if ((jsuint)i < (jsuint)(high - low + 1)) { + pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i; + jsint off = (jsint) GET_JUMP_OFFSET(pc2); + if (off) + len = off; + } +} +END_VARLEN_CASE +} + +{ +BEGIN_CASE(JSOP_TABLESWITCHX) +{ + jsbytecode *pc2 = regs.pc; + len = GET_JUMPX_OFFSET(pc2); + + /* + * ECMAv2+ forbids conversion of discriminant, so we will skip to the + * default case if the discriminant isn't already an int jsval. (This + * opcode is emitted only for dense jsint-domain switches.) + */ + const Value &rref = *--regs.sp; + int32_t i; + if (rref.isInt32()) { + i = rref.toInt32(); + } else if (rref.isDouble() && rref.toDouble() == 0) { + /* Treat -0 (double) as 0. */ + i = 0; + } else { + DO_NEXT_OP(len); + } + + pc2 += JUMPX_OFFSET_LEN; + jsint low = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + jsint high = GET_JUMP_OFFSET(pc2); + + i -= low; + if ((jsuint)i < (jsuint)(high - low + 1)) { + pc2 += JUMP_OFFSET_LEN + JUMPX_OFFSET_LEN * i; + jsint off = (jsint) GET_JUMPX_OFFSET(pc2); + if (off) + len = off; + } +} +END_VARLEN_CASE +} + +{ +BEGIN_CASE(JSOP_LOOKUPSWITCHX) +{ + jsint off; + off = JUMPX_OFFSET_LEN; + goto do_lookup_switch; + +BEGIN_CASE(JSOP_LOOKUPSWITCH) + off = JUMP_OFFSET_LEN; + + do_lookup_switch: + /* + * JSOP_LOOKUPSWITCH and JSOP_LOOKUPSWITCHX are never used if any atom + * index in it would exceed 64K limit. + */ + JS_ASSERT(!regs.fp->hasImacropc()); + JS_ASSERT(atoms == script->atomMap.vector); + jsbytecode *pc2 = regs.pc; + + Value lval = regs.sp[-1]; + regs.sp--; + + if (!lval.isPrimitive()) + goto end_lookup_switch; + + pc2 += off; + jsint npairs; + npairs = (jsint) GET_UINT16(pc2); + pc2 += UINT16_LEN; + JS_ASSERT(npairs); /* empty switch uses JSOP_TABLESWITCH */ + + bool match; +#define SEARCH_PAIRS(MATCH_CODE) \ + for (;;) { \ + Value rval = script->getConst(GET_INDEX(pc2)); \ + MATCH_CODE \ + pc2 += INDEX_LEN; \ + if (match) \ + break; \ + pc2 += off; \ + if (--npairs == 0) { \ + pc2 = regs.pc; \ + break; \ + } \ + } + + if (lval.isString()) { + JSLinearString *str = lval.toString()->ensureLinear(cx); + if (!str) + goto error; + JSLinearString *str2; + SEARCH_PAIRS( + match = (rval.isString() && + ((str2 = rval.toString()->assertIsLinear()) == str || + EqualStrings(str2, str))); + ) + } else if (lval.isNumber()) { + double ldbl = lval.toNumber(); + SEARCH_PAIRS( + match = rval.isNumber() && ldbl == rval.toNumber(); + ) + } else { + SEARCH_PAIRS( + match = (lval == rval); + ) + } +#undef SEARCH_PAIRS + + end_lookup_switch: + len = (op == JSOP_LOOKUPSWITCH) + ? GET_JUMP_OFFSET(pc2) + : GET_JUMPX_OFFSET(pc2); +} +END_VARLEN_CASE +} + +BEGIN_CASE(JSOP_TRAP) +{ + Value rval; + JSTrapStatus status = JS_HandleTrap(cx, script, regs.pc, Jsvalify(&rval)); + switch (status) { + case JSTRAP_ERROR: + goto error; + case JSTRAP_RETURN: + regs.fp->setReturnValue(rval); + interpReturnOK = JS_TRUE; + goto forced_return; + case JSTRAP_THROW: + cx->setPendingException(rval); + goto error; + default: + break; + } + JS_ASSERT(status == JSTRAP_CONTINUE); + CHECK_INTERRUPT_HANDLER(); + JS_ASSERT(rval.isInt32()); + op = (JSOp) rval.toInt32(); + JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT); + DO_OP(); +} + +BEGIN_CASE(JSOP_ARGUMENTS) +{ + Value rval; + if (!js_GetArgsValue(cx, regs.fp, &rval)) + goto error; + PUSH_COPY(rval); +} +END_CASE(JSOP_ARGUMENTS) + +BEGIN_CASE(JSOP_ARGSUB) +{ + jsid id = INT_TO_JSID(GET_ARGNO(regs.pc)); + Value rval; + if (!js_GetArgsProperty(cx, regs.fp, id, &rval)) + goto error; + PUSH_COPY(rval); +} +END_CASE(JSOP_ARGSUB) + +BEGIN_CASE(JSOP_ARGCNT) +{ + jsid id = ATOM_TO_JSID(rt->atomState.lengthAtom); + Value rval; + if (!js_GetArgsProperty(cx, regs.fp, id, &rval)) + goto error; + PUSH_COPY(rval); +} +END_CASE(JSOP_ARGCNT) + +BEGIN_CASE(JSOP_GETARG) +BEGIN_CASE(JSOP_CALLARG) +{ + uint32 slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < regs.fp->numFormalArgs()); + METER_SLOT_OP(op, slot); + PUSH_COPY(argv[slot]); + if (op == JSOP_CALLARG) + PUSH_UNDEFINED(); +} +END_CASE(JSOP_GETARG) + +BEGIN_CASE(JSOP_SETARG) +{ + uint32 slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < regs.fp->numFormalArgs()); + METER_SLOT_OP(op, slot); + argv[slot] = regs.sp[-1]; +} +END_SET_CASE(JSOP_SETARG) + +BEGIN_CASE(JSOP_GETLOCAL) +{ + uint32 slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < script->nslots); + PUSH_COPY(regs.fp->slots()[slot]); +} +END_CASE(JSOP_GETLOCAL) + +BEGIN_CASE(JSOP_CALLLOCAL) +{ + uint32 slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < script->nslots); + PUSH_COPY(regs.fp->slots()[slot]); + PUSH_UNDEFINED(); +} +END_CASE(JSOP_CALLLOCAL) + +BEGIN_CASE(JSOP_SETLOCAL) +{ + uint32 slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < script->nslots); + regs.fp->slots()[slot] = regs.sp[-1]; +} +END_SET_CASE(JSOP_SETLOCAL) + +BEGIN_CASE(JSOP_GETUPVAR_DBG) +BEGIN_CASE(JSOP_CALLUPVAR_DBG) +{ + JSFunction *fun = regs.fp->fun(); + JS_ASSERT(FUN_KIND(fun) == JSFUN_INTERPRETED); + JS_ASSERT(fun->u.i.wrapper); + + /* Scope for tempPool mark and local names allocation in it. */ + JSObject *obj, *obj2; + JSProperty *prop; + jsid id; + JSAtom *atom; + { + AutoLocalNameArray names(cx, fun); + if (!names) + goto error; + + uintN index = fun->script()->bindings.countArgsAndVars() + GET_UINT16(regs.pc); + atom = JS_LOCAL_NAME_TO_ATOM(names[index]); + id = ATOM_TO_JSID(atom); + + if (!js_FindProperty(cx, id, &obj, &obj2, &prop)) + goto error; + } + + if (!prop) { + atomNotDefined = atom; + goto atom_not_defined; + } + + /* Minimize footprint with generic code instead of NATIVE_GET. */ + Value *vp = regs.sp; + PUSH_NULL(); + if (!obj->getProperty(cx, id, vp)) + goto error; + + if (op == JSOP_CALLUPVAR_DBG) + PUSH_UNDEFINED(); +} +END_CASE(JSOP_GETUPVAR_DBG) + +BEGIN_CASE(JSOP_GETFCSLOT) +BEGIN_CASE(JSOP_CALLFCSLOT) +{ + JS_ASSERT(regs.fp->isFunctionFrame() && !regs.fp->isEvalFrame()); + uintN index = GET_UINT16(regs.pc); + JSObject *obj = &argv[-2].toObject(); + + JS_ASSERT(index < obj->getFunctionPrivate()->script()->bindings.countUpvars()); + PUSH_COPY(obj->getFlatClosureUpvar(index)); + if (op == JSOP_CALLFCSLOT) + PUSH_UNDEFINED(); +} +END_CASE(JSOP_GETFCSLOT) + +BEGIN_CASE(JSOP_GETGLOBAL) +BEGIN_CASE(JSOP_CALLGLOBAL) +{ + uint32 slot = GET_SLOTNO(regs.pc); + slot = script->getGlobalSlot(slot); + JSObject *obj = regs.fp->scopeChain().getGlobal(); + JS_ASSERT(obj->containsSlot(slot)); + PUSH_COPY(obj->getSlot(slot)); + if (op == JSOP_CALLGLOBAL) + PUSH_UNDEFINED(); +} +END_CASE(JSOP_GETGLOBAL) + +BEGIN_CASE(JSOP_DEFCONST) +BEGIN_CASE(JSOP_DEFVAR) +{ + uint32 index = GET_INDEX(regs.pc); + JSAtom *atom = atoms[index]; + + JSObject *obj = ®s.fp->varobj(cx); + JS_ASSERT(!obj->getOps()->defineProperty); + uintN attrs = JSPROP_ENUMERATE; + if (!regs.fp->isEvalFrame()) + attrs |= JSPROP_PERMANENT; + + /* Lookup id in order to check for redeclaration problems. */ + jsid id = ATOM_TO_JSID(atom); + bool shouldDefine; + if (op == JSOP_DEFVAR) { + /* + * Redundant declaration of a |var|, even one for a non-writable + * property like |undefined| in ES5, does nothing. + */ + JSProperty *prop; + JSObject *obj2; + if (!obj->lookupProperty(cx, id, &obj2, &prop)) + goto error; + shouldDefine = (!prop || obj2 != obj); + } else { + JS_ASSERT(op == JSOP_DEFCONST); + attrs |= JSPROP_READONLY; + if (!CheckRedeclaration(cx, obj, id, attrs)) + goto error; + + /* + * As attrs includes readonly, CheckRedeclaration can succeed only + * if prop does not exist. + */ + shouldDefine = true; + } + + /* Bind a variable only if it's not yet defined. */ + if (shouldDefine && + !js_DefineNativeProperty(cx, obj, id, UndefinedValue(), + PropertyStub, StrictPropertyStub, attrs, 0, 0, NULL)) { + goto error; + } +} +END_CASE(JSOP_DEFVAR) + +BEGIN_CASE(JSOP_DEFFUN) +{ + /* + * A top-level function defined in Global or Eval code (see ECMA-262 + * Ed. 3), or else a SpiderMonkey extension: a named function statement in + * a compound statement (not at the top statement level of global code, or + * at the top level of a function body). + */ + JSFunction *fun; + LOAD_FUNCTION(0); + JSObject *obj = FUN_OBJECT(fun); + + JSObject *obj2; + if (FUN_NULL_CLOSURE(fun)) { + /* + * Even a null closure needs a parent for principals finding. + * FIXME: bug 476950, although debugger users may also demand some kind + * of scope link for debugger-assisted eval-in-frame. + */ + obj2 = ®s.fp->scopeChain(); + } else { + JS_ASSERT(!fun->isFlatClosure()); + + obj2 = GetScopeChainFast(cx, regs.fp, JSOP_DEFFUN, JSOP_DEFFUN_LENGTH); + if (!obj2) + goto error; + } + + /* + * If static link is not current scope, clone fun's object to link to the + * current scope via parent. We do this to enable sharing of compiled + * functions among multiple equivalent scopes, amortizing the cost of + * compilation over a number of executions. Examples include XUL scripts + * and event handlers shared among Firefox or other Mozilla app chrome + * windows, and user-defined JS functions precompiled and then shared among + * requests in server-side JS. + */ + if (obj->getParent() != obj2) { + obj = CloneFunctionObject(cx, fun, obj2); + if (!obj) + goto error; + } + + /* + * ECMA requires functions defined when entering Eval code to be + * impermanent. + */ + uintN attrs = regs.fp->isEvalFrame() + ? JSPROP_ENUMERATE + : JSPROP_ENUMERATE | JSPROP_PERMANENT; + + /* + * We define the function as a property of the variable object and not the + * current scope chain even for the case of function expression statements + * and functions defined by eval inside let or with blocks. + */ + JSObject *parent = ®s.fp->varobj(cx); + + /* ES5 10.5 (NB: with subsequent errata). */ + jsid id = ATOM_TO_JSID(fun->atom); + JSProperty *prop = NULL; + JSObject *pobj; + if (!parent->lookupProperty(cx, id, &pobj, &prop)) + goto error; + + Value rval = ObjectValue(*obj); + + do { + /* Steps 5d, 5f. */ + if (!prop || pobj != parent) { + if (!parent->defineProperty(cx, id, rval, PropertyStub, StrictPropertyStub, attrs)) + goto error; + break; + } + + /* Step 5e. */ + JS_ASSERT(parent->isNative()); + Shape *shape = reinterpret_cast(prop); + if (parent->isGlobal()) { + if (shape->configurable()) { + if (!parent->defineProperty(cx, id, rval, PropertyStub, StrictPropertyStub, attrs)) + goto error; + break; + } + + if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) { + JSAutoByteString bytes; + if (const char *name = js_ValueToPrintable(cx, IdToValue(id), &bytes)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_REDEFINE_PROP, name); + } + goto error; + } + } + + /* + * Non-global properties, and global properties which we aren't simply + * redefining, must be set. First, this preserves their attributes. + * Second, this will produce warnings and/or errors as necessary if the + * specified Call object property is not writable (const). + */ + + /* Step 5f. */ + if (!parent->setProperty(cx, id, &rval, script->strictModeCode)) + goto error; + } while (false); +} +END_CASE(JSOP_DEFFUN) + +BEGIN_CASE(JSOP_DEFFUN_FC) +BEGIN_CASE(JSOP_DEFFUN_DBGFC) +{ + JSFunction *fun; + LOAD_FUNCTION(0); + + JSObject *obj = (op == JSOP_DEFFUN_FC) + ? js_NewFlatClosure(cx, fun, JSOP_DEFFUN_FC, JSOP_DEFFUN_FC_LENGTH) + : js_NewDebuggableFlatClosure(cx, fun); + if (!obj) + goto error; + + Value rval = ObjectValue(*obj); + + uintN attrs = regs.fp->isEvalFrame() + ? JSPROP_ENUMERATE + : JSPROP_ENUMERATE | JSPROP_PERMANENT; + + JSObject &parent = regs.fp->varobj(cx); + + jsid id = ATOM_TO_JSID(fun->atom); + if (!CheckRedeclaration(cx, &parent, id, attrs)) + goto error; + + if ((attrs == JSPROP_ENUMERATE) + ? !parent.setProperty(cx, id, &rval, script->strictModeCode) + : !parent.defineProperty(cx, id, rval, PropertyStub, StrictPropertyStub, attrs)) { + goto error; + } +} +END_CASE(JSOP_DEFFUN_FC) + +BEGIN_CASE(JSOP_DEFLOCALFUN) +{ + /* + * Define a local function (i.e., one nested at the top level of another + * function), parented by the current scope chain, stored in a local + * variable slot that the compiler allocated. This is an optimization over + * JSOP_DEFFUN that avoids requiring a call object for the outer function's + * activation. + */ + JSFunction *fun; + LOAD_FUNCTION(SLOTNO_LEN); + JS_ASSERT(fun->isInterpreted()); + JS_ASSERT(!FUN_FLAT_CLOSURE(fun)); + JSObject *obj = FUN_OBJECT(fun); + + if (FUN_NULL_CLOSURE(fun)) { + obj = CloneFunctionObject(cx, fun, ®s.fp->scopeChain()); + if (!obj) + goto error; + } else { + JSObject *parent = GetScopeChainFast(cx, regs.fp, JSOP_DEFLOCALFUN, + JSOP_DEFLOCALFUN_LENGTH); + if (!parent) + goto error; + + if (obj->getParent() != parent) { +#ifdef JS_TRACER + if (TRACE_RECORDER(cx)) + AbortRecording(cx, "DEFLOCALFUN for closure"); +#endif + obj = CloneFunctionObject(cx, fun, parent); + if (!obj) + goto error; + } + } + + uint32 slot = GET_SLOTNO(regs.pc); + TRACE_2(DefLocalFunSetSlot, slot, obj); + + regs.fp->slots()[slot].setObject(*obj); +} +END_CASE(JSOP_DEFLOCALFUN) + +BEGIN_CASE(JSOP_DEFLOCALFUN_FC) +{ + JSFunction *fun; + LOAD_FUNCTION(SLOTNO_LEN); + + JSObject *obj = js_NewFlatClosure(cx, fun, JSOP_DEFLOCALFUN_FC, JSOP_DEFLOCALFUN_FC_LENGTH); + if (!obj) + goto error; + + uint32 slot = GET_SLOTNO(regs.pc); + TRACE_2(DefLocalFunSetSlot, slot, obj); + + regs.fp->slots()[slot].setObject(*obj); +} +END_CASE(JSOP_DEFLOCALFUN_FC) + +BEGIN_CASE(JSOP_DEFLOCALFUN_DBGFC) +{ + JSFunction *fun; + LOAD_FUNCTION(SLOTNO_LEN); + + JSObject *obj = js_NewDebuggableFlatClosure(cx, fun); + if (!obj) + goto error; + + uint32 slot = GET_SLOTNO(regs.pc); + regs.fp->slots()[slot].setObject(*obj); +} +END_CASE(JSOP_DEFLOCALFUN_DBGFC) + +BEGIN_CASE(JSOP_LAMBDA) +{ + /* Load the specified function object literal. */ + JSFunction *fun; + LOAD_FUNCTION(0); + JSObject *obj = FUN_OBJECT(fun); + + /* do-while(0) so we can break instead of using a goto. */ + do { + JSObject *parent; + if (FUN_NULL_CLOSURE(fun)) { + parent = ®s.fp->scopeChain(); + + if (obj->getParent() == parent) { + jsbytecode *pc2 = AdvanceOverBlockchainOp(regs.pc + JSOP_LAMBDA_LENGTH); + JSOp op2 = JSOp(*pc2); + + /* + * Optimize var obj = {method: function () { ... }, ...}, + * this.method = function () { ... }; and other significant + * single-use-of-null-closure bytecode sequences. + * + * WARNING: code in TraceRecorder::record_JSOP_LAMBDA must + * match the optimization cases in the following code that + * break from the outer do-while(0). + */ + if (op2 == JSOP_INITMETHOD) { +#ifdef DEBUG + const Value &lref = regs.sp[-1]; + JS_ASSERT(lref.isObject()); + JSObject *obj2 = &lref.toObject(); + JS_ASSERT(obj2->getClass() == &js_ObjectClass); +#endif + + fun->setMethodAtom(script->getAtom(GET_FULL_INDEX(pc2 - regs.pc))); + JS_FUNCTION_METER(cx, joinedinitmethod); + break; + } + + if (op2 == JSOP_SETMETHOD) { +#ifdef DEBUG + op2 = JSOp(pc2[JSOP_SETMETHOD_LENGTH]); + JS_ASSERT(op2 == JSOP_POP || op2 == JSOP_POPV); +#endif + const Value &lref = regs.sp[-1]; + if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) { + fun->setMethodAtom(script->getAtom(GET_FULL_INDEX(pc2 - regs.pc))); + JS_FUNCTION_METER(cx, joinedsetmethod); + break; + } + } else if (fun->joinable()) { + if (op2 == JSOP_CALL) { + /* + * Array.prototype.sort and String.prototype.replace are + * optimized as if they are special form. We know that they + * won't leak the joined function object in obj, therefore + * we don't need to clone that compiler- created function + * object for identity/mutation reasons. + */ + int iargc = GET_ARGC(pc2); + + /* + * Note that we have not yet pushed obj as the final argument, + * so regs.sp[1 - (iargc + 2)], and not regs.sp[-(iargc + 2)], + * is the callee for this JSOP_CALL. + */ + const Value &cref = regs.sp[1 - (iargc + 2)]; + JSObject *callee; + + if (IsFunctionObject(cref, &callee)) { + JSFunction *calleeFun = GET_FUNCTION_PRIVATE(cx, callee); + if (Native native = calleeFun->maybeNative()) { + if (iargc == 1 && native == array_sort) { + JS_FUNCTION_METER(cx, joinedsort); + break; + } + if (iargc == 2 && native == str_replace) { + JS_FUNCTION_METER(cx, joinedreplace); + break; + } + } + } + } else if (op2 == JSOP_NULL) { + pc2 += JSOP_NULL_LENGTH; + op2 = JSOp(*pc2); + + if (op2 == JSOP_CALL && GET_ARGC(pc2) == 0) { + JS_FUNCTION_METER(cx, joinedmodulepat); + break; + } + } + } + } + +#ifdef DEBUG + if (rt->functionMeterFilename) { + // No locking, this is mainly for js shell testing. + ++rt->functionMeter.unjoined; + + typedef JSRuntime::FunctionCountMap HM; + HM &h = rt->unjoinedFunctionCountMap; + HM::AddPtr p = h.lookupForAdd(fun); + if (!p) { + h.add(p, fun, 1); + } else { + JS_ASSERT(p->key == fun); + ++p->value; + } + } +#endif + } else { + parent = GetScopeChainFast(cx, regs.fp, JSOP_LAMBDA, JSOP_LAMBDA_LENGTH); + if (!parent) + goto error; + } + + obj = CloneFunctionObject(cx, fun, parent); + if (!obj) + goto error; + } while (0); + + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_LAMBDA) + +BEGIN_CASE(JSOP_LAMBDA_FC) +{ + JSFunction *fun; + LOAD_FUNCTION(0); + + JSObject *obj = js_NewFlatClosure(cx, fun, JSOP_LAMBDA_FC, JSOP_LAMBDA_FC_LENGTH); + if (!obj) + goto error; + + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_LAMBDA_FC) + +BEGIN_CASE(JSOP_LAMBDA_DBGFC) +{ + JSFunction *fun; + LOAD_FUNCTION(0); + + JSObject *obj = js_NewDebuggableFlatClosure(cx, fun); + if (!obj) + goto error; + + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_LAMBDA_DBGFC) + +BEGIN_CASE(JSOP_CALLEE) + JS_ASSERT(regs.fp->isFunctionFrame() && !regs.fp->isEvalFrame()); + PUSH_COPY(argv[-2]); +END_CASE(JSOP_CALLEE) + +BEGIN_CASE(JSOP_GETTER) +BEGIN_CASE(JSOP_SETTER) +{ + do_getter_setter: + JSOp op2 = (JSOp) *++regs.pc; + jsid id; + Value rval; + jsint i; + JSObject *obj; + switch (op2) { + case JSOP_INDEXBASE: + atoms += GET_INDEXBASE(regs.pc); + regs.pc += JSOP_INDEXBASE_LENGTH - 1; + goto do_getter_setter; + case JSOP_INDEXBASE1: + case JSOP_INDEXBASE2: + case JSOP_INDEXBASE3: + atoms += (op2 - JSOP_INDEXBASE1 + 1) << 16; + goto do_getter_setter; + + case JSOP_SETNAME: + case JSOP_SETPROP: + { + JSAtom *atom; + LOAD_ATOM(0, atom); + id = ATOM_TO_JSID(atom); + rval = regs.sp[-1]; + i = -1; + goto gs_pop_lval; + } + case JSOP_SETELEM: + rval = regs.sp[-1]; + id = JSID_VOID; + i = -2; + gs_pop_lval: + FETCH_OBJECT(cx, i - 1, obj); + break; + + case JSOP_INITPROP: + { + JS_ASSERT(regs.sp - regs.fp->base() >= 2); + rval = regs.sp[-1]; + i = -1; + JSAtom *atom; + LOAD_ATOM(0, atom); + id = ATOM_TO_JSID(atom); + goto gs_get_lval; + } + default: + JS_ASSERT(op2 == JSOP_INITELEM); + + JS_ASSERT(regs.sp - regs.fp->base() >= 3); + rval = regs.sp[-1]; + id = JSID_VOID; + i = -2; + gs_get_lval: + { + const Value &lref = regs.sp[i-1]; + JS_ASSERT(lref.isObject()); + obj = &lref.toObject(); + break; + } + } + + /* Ensure that id has a type suitable for use with obj. */ + if (JSID_IS_VOID(id)) + FETCH_ELEMENT_ID(obj, i, id); + + if (!js_IsCallable(rval)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_GETTER_OR_SETTER, + (op == JSOP_GETTER) + ? js_getter_str + : js_setter_str); + goto error; + } + + /* + * Getters and setters are just like watchpoints from an access control + * point of view. + */ + Value rtmp; + uintN attrs; + if (!CheckAccess(cx, obj, id, JSACC_WATCH, &rtmp, &attrs)) + goto error; + + PropertyOp getter; + StrictPropertyOp setter; + if (op == JSOP_GETTER) { + getter = CastAsPropertyOp(&rval.toObject()); + setter = StrictPropertyStub; + attrs = JSPROP_GETTER; + } else { + getter = PropertyStub; + setter = CastAsStrictPropertyOp(&rval.toObject()); + attrs = JSPROP_SETTER; + } + attrs |= JSPROP_ENUMERATE | JSPROP_SHARED; + + /* Check for a readonly or permanent property of the same name. */ + if (!CheckRedeclaration(cx, obj, id, attrs)) + goto error; + + if (!obj->defineProperty(cx, id, UndefinedValue(), getter, setter, attrs)) + goto error; + + regs.sp += i; + if (js_CodeSpec[op2].ndefs > js_CodeSpec[op2].nuses) { + JS_ASSERT(js_CodeSpec[op2].ndefs == js_CodeSpec[op2].nuses + 1); + regs.sp[-1] = rval; + assertSameCompartment(cx, regs.sp[-1]); + } + len = js_CodeSpec[op2].length; + DO_NEXT_OP(len); +} + +BEGIN_CASE(JSOP_HOLE) + PUSH_HOLE(); +END_CASE(JSOP_HOLE) + +BEGIN_CASE(JSOP_NEWINIT) +{ + jsint i = regs.pc[1]; + + JS_ASSERT(i == JSProto_Array || i == JSProto_Object); + JSObject *obj; + + if (i == JSProto_Array) { + obj = NewDenseEmptyArray(cx); + } else { + gc::FinalizeKind kind = GuessObjectGCKind(0, false); + obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind); + } + + if (!obj) + goto error; + + PUSH_OBJECT(*obj); + CHECK_INTERRUPT_HANDLER(); +} +END_CASE(JSOP_NEWINIT) + +BEGIN_CASE(JSOP_NEWARRAY) +{ + unsigned count = GET_UINT24(regs.pc); + JSObject *obj = NewDenseAllocatedArray(cx, count); + if (!obj) + goto error; + + PUSH_OBJECT(*obj); + CHECK_INTERRUPT_HANDLER(); +} +END_CASE(JSOP_NEWARRAY) + +BEGIN_CASE(JSOP_NEWOBJECT) +{ + JSObject *baseobj; + LOAD_OBJECT(0, baseobj); + + JSObject *obj = CopyInitializerObject(cx, baseobj); + + if (!obj) + goto error; + + PUSH_OBJECT(*obj); + CHECK_INTERRUPT_HANDLER(); +} +END_CASE(JSOP_NEWOBJECT) + +BEGIN_CASE(JSOP_ENDINIT) +{ + /* FIXME remove JSOP_ENDINIT bug 588522 */ + JS_ASSERT(regs.sp - regs.fp->base() >= 1); + JS_ASSERT(regs.sp[-1].isObject()); +} +END_CASE(JSOP_ENDINIT) + +BEGIN_CASE(JSOP_INITPROP) +BEGIN_CASE(JSOP_INITMETHOD) +{ + /* Load the property's initial value into rval. */ + JS_ASSERT(regs.sp - regs.fp->base() >= 2); + Value rval = regs.sp[-1]; + + /* Load the object being initialized into lval/obj. */ + JSObject *obj = ®s.sp[-2].toObject(); + JS_ASSERT(obj->isObject()); + + /* + * Probe the property cache. + * + * On a hit, if the cached shape has a non-default setter, it must be + * __proto__. If shape->previous() != obj->lastProperty(), there must be a + * repeated property name. The fast path does not handle these two cases. + */ + PropertyCacheEntry *entry; + const Shape *shape; + if (JS_PROPERTY_CACHE(cx).testForInit(rt, regs.pc, obj, &shape, &entry) && + shape->hasDefaultSetter() && + shape->previous() == obj->lastProperty()) + { + /* Fast path. Property cache hit. */ + uint32 slot = shape->slot; + + JS_ASSERT(slot == obj->slotSpan()); + JS_ASSERT(slot >= JSSLOT_FREE(obj->getClass())); + if (slot < obj->numSlots()) { + JS_ASSERT(obj->getSlot(slot).isUndefined()); + } else { + if (!obj->allocSlot(cx, &slot)) + goto error; + JS_ASSERT(slot == shape->slot); + } + + /* A new object, or one we just extended in a recent initprop op. */ + JS_ASSERT(!obj->lastProperty() || + obj->shape() == obj->lastProperty()->shape); + obj->extend(cx, shape); + + /* + * No method change check here because here we are adding a new + * property, not updating an existing slot's value that might + * contain a method of a branded shape. + */ + TRACE_1(AddProperty, obj); + obj->nativeSetSlot(slot, rval); + } else { + PCMETER(JS_PROPERTY_CACHE(cx).inipcmisses++); + + /* Get the immediate property name into id. */ + JSAtom *atom; + LOAD_ATOM(0, atom); + jsid id = ATOM_TO_JSID(atom); + + uintN defineHow = (op == JSOP_INITMETHOD) + ? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD + : JSDNP_CACHE_RESULT; + if (!(JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom) + ? js_SetPropertyHelper(cx, obj, id, defineHow, &rval, script->strictModeCode) + : js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL, + JSPROP_ENUMERATE, 0, 0, NULL, + defineHow))) { + goto error; + } + } + + /* Common tail for property cache hit and miss cases. */ + regs.sp--; +} +END_CASE(JSOP_INITPROP); + +BEGIN_CASE(JSOP_INITELEM) +{ + /* Pop the element's value into rval. */ + JS_ASSERT(regs.sp - regs.fp->base() >= 3); + const Value &rref = regs.sp[-1]; + + /* Find the object being initialized at top of stack. */ + const Value &lref = regs.sp[-3]; + JS_ASSERT(lref.isObject()); + JSObject *obj = &lref.toObject(); + + /* Fetch id now that we have obj. */ + jsid id; + FETCH_ELEMENT_ID(obj, -2, id); + + /* + * If rref is a hole, do not call JSObject::defineProperty. In this case, + * obj must be an array, so if the current op is the last element + * initialiser, set the array length to one greater than id. + */ + if (rref.isMagic(JS_ARRAY_HOLE)) { + JS_ASSERT(obj->isArray()); + JS_ASSERT(JSID_IS_INT(id)); + JS_ASSERT(jsuint(JSID_TO_INT(id)) < JS_ARGS_LENGTH_MAX); + if (js_GetOpcode(cx, script, regs.pc + JSOP_INITELEM_LENGTH) == JSOP_ENDINIT && + !js_SetLengthProperty(cx, obj, (jsuint) (JSID_TO_INT(id) + 1))) { + goto error; + } + } else { + if (!obj->defineProperty(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE)) + goto error; + } + regs.sp -= 2; +} +END_CASE(JSOP_INITELEM) + +#if JS_HAS_SHARP_VARS + +BEGIN_CASE(JSOP_DEFSHARP) +{ + uint32 slot = GET_UINT16(regs.pc); + JS_ASSERT(slot + 1 < regs.fp->numFixed()); + const Value &lref = regs.fp->slots()[slot]; + JSObject *obj; + if (lref.isObject()) { + obj = &lref.toObject(); + } else { + JS_ASSERT(lref.isUndefined()); + obj = NewDenseEmptyArray(cx); + if (!obj) + goto error; + regs.fp->slots()[slot].setObject(*obj); + } + jsint i = (jsint) GET_UINT16(regs.pc + UINT16_LEN); + jsid id = INT_TO_JSID(i); + const Value &rref = regs.sp[-1]; + if (rref.isPrimitive()) { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_SHARP_DEF, numBuf); + goto error; + } + if (!obj->defineProperty(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE)) + goto error; +} +END_CASE(JSOP_DEFSHARP) + +BEGIN_CASE(JSOP_USESHARP) +{ + uint32 slot = GET_UINT16(regs.pc); + JS_ASSERT(slot + 1 < regs.fp->numFixed()); + const Value &lref = regs.fp->slots()[slot]; + jsint i = (jsint) GET_UINT16(regs.pc + UINT16_LEN); + Value rval; + if (lref.isUndefined()) { + rval.setUndefined(); + } else { + JSObject *obj = ®s.fp->slots()[slot].toObject(); + jsid id = INT_TO_JSID(i); + if (!obj->getProperty(cx, id, &rval)) + goto error; + } + if (!rval.isObjectOrNull()) { + char numBuf[12]; + + JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_SHARP_USE, numBuf); + goto error; + } + PUSH_COPY(rval); +} +END_CASE(JSOP_USESHARP) + +BEGIN_CASE(JSOP_SHARPINIT) +{ + uint32 slot = GET_UINT16(regs.pc); + JS_ASSERT(slot + 1 < regs.fp->numFixed()); + Value *vp = ®s.fp->slots()[slot]; + Value rval = vp[1]; + + /* + * We peek ahead safely here because empty initialisers get zero + * JSOP_SHARPINIT ops, and non-empty ones get two: the first comes + * immediately after JSOP_NEWINIT followed by one or more property + * initialisers; and the second comes directly before JSOP_ENDINIT. + */ + if (regs.pc[JSOP_SHARPINIT_LENGTH] != JSOP_ENDINIT) { + rval.setInt32(rval.isUndefined() ? 1 : rval.toInt32() + 1); + } else { + JS_ASSERT(rval.isInt32()); + rval.getInt32Ref() -= 1; + if (rval.toInt32() == 0) + vp[0].setUndefined(); + } + vp[1] = rval; +} +END_CASE(JSOP_SHARPINIT) + +#endif /* JS_HAS_SHARP_VARS */ + +{ +BEGIN_CASE(JSOP_GOSUB) + PUSH_BOOLEAN(false); + jsint i = (regs.pc - script->main) + JSOP_GOSUB_LENGTH; + PUSH_INT32(i); + len = GET_JUMP_OFFSET(regs.pc); +END_VARLEN_CASE +} + +{ +BEGIN_CASE(JSOP_GOSUBX) + PUSH_BOOLEAN(false); + jsint i = (regs.pc - script->main) + JSOP_GOSUBX_LENGTH; + len = GET_JUMPX_OFFSET(regs.pc); + PUSH_INT32(i); +END_VARLEN_CASE +} + +{ +BEGIN_CASE(JSOP_RETSUB) + /* Pop [exception or hole, retsub pc-index]. */ + Value rval, lval; + POP_COPY_TO(rval); + POP_COPY_TO(lval); + JS_ASSERT(lval.isBoolean()); + if (lval.toBoolean()) { + /* + * Exception was pending during finally, throw it *before* we adjust + * pc, because pc indexes into script->trynotes. This turns out not to + * be necessary, but it seems clearer. And it points out a FIXME: + * 350509, due to Igor Bukanov. + */ + cx->setPendingException(rval); + goto error; + } + JS_ASSERT(rval.isInt32()); + len = rval.toInt32(); + regs.pc = script->main; +END_VARLEN_CASE +} + +BEGIN_CASE(JSOP_EXCEPTION) + PUSH_COPY(cx->getPendingException()); + cx->clearPendingException(); +#if defined(JS_TRACER) && defined(JS_METHODJIT) + if (interpMode == JSINTERP_PROFILE) { + leaveOnSafePoint = true; + LEAVE_ON_SAFE_POINT(); + } +#endif + CHECK_BRANCH(); +END_CASE(JSOP_EXCEPTION) + +BEGIN_CASE(JSOP_FINALLY) + CHECK_BRANCH(); +END_CASE(JSOP_FINALLY) + +BEGIN_CASE(JSOP_THROWING) +{ + JS_ASSERT(!cx->isExceptionPending()); + Value v; + POP_COPY_TO(v); + cx->setPendingException(v); +} +END_CASE(JSOP_THROWING) + +BEGIN_CASE(JSOP_THROW) +{ + JS_ASSERT(!cx->isExceptionPending()); + CHECK_BRANCH(); + Value v; + POP_COPY_TO(v); + cx->setPendingException(v); + /* let the code at error try to catch the exception. */ + goto error; +} +BEGIN_CASE(JSOP_SETLOCALPOP) +{ + /* + * The stack must have a block with at least one local slot below the + * exception object. + */ + JS_ASSERT((size_t) (regs.sp - regs.fp->base()) >= 2); + uint32 slot = GET_UINT16(regs.pc); + JS_ASSERT(slot + 1 < script->nslots); + POP_COPY_TO(regs.fp->slots()[slot]); +} +END_CASE(JSOP_SETLOCALPOP) + +BEGIN_CASE(JSOP_IFPRIMTOP) + /* + * If the top of stack is of primitive type, jump to our target. Otherwise + * advance to the next opcode. + */ + JS_ASSERT(regs.sp > regs.fp->base()); + if (regs.sp[-1].isPrimitive()) { + len = GET_JUMP_OFFSET(regs.pc); + BRANCH(len); + } +END_CASE(JSOP_IFPRIMTOP) + +BEGIN_CASE(JSOP_PRIMTOP) + JS_ASSERT(regs.sp > regs.fp->base()); + if (regs.sp[-1].isObject()) { + jsint i = GET_INT8(regs.pc); + js_ReportValueError2(cx, JSMSG_CANT_CONVERT_TO, -2, regs.sp[-2], NULL, + (i == JSTYPE_VOID) ? "primitive type" : JS_TYPE_STR(i)); + goto error; + } +END_CASE(JSOP_PRIMTOP) + +BEGIN_CASE(JSOP_OBJTOP) + if (regs.sp[-1].isPrimitive()) { + js_ReportValueError(cx, GET_UINT16(regs.pc), -1, regs.sp[-1], NULL); + goto error; + } +END_CASE(JSOP_OBJTOP) + +BEGIN_CASE(JSOP_INSTANCEOF) +{ + const Value &rref = regs.sp[-1]; + if (rref.isPrimitive()) { + js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, NULL); + goto error; + } + JSObject *obj = &rref.toObject(); + const Value &lref = regs.sp[-2]; + JSBool cond = JS_FALSE; + if (!HasInstance(cx, obj, &lref, &cond)) + goto error; + regs.sp--; + regs.sp[-1].setBoolean(cond); +} +END_CASE(JSOP_INSTANCEOF) + +BEGIN_CASE(JSOP_DEBUGGER) +{ + JSDebuggerHandler handler = cx->debugHooks->debuggerHandler; + if (handler) { + Value rval; + switch (handler(cx, script, regs.pc, Jsvalify(&rval), cx->debugHooks->debuggerHandlerData)) { + case JSTRAP_ERROR: + goto error; + case JSTRAP_CONTINUE: + break; + case JSTRAP_RETURN: + regs.fp->setReturnValue(rval); + interpReturnOK = JS_TRUE; + goto forced_return; + case JSTRAP_THROW: + cx->setPendingException(rval); + goto error; + default:; + } + CHECK_INTERRUPT_HANDLER(); + } +} +END_CASE(JSOP_DEBUGGER) + +#if JS_HAS_XML_SUPPORT +BEGIN_CASE(JSOP_DEFXMLNS) +{ + if (!js_SetDefaultXMLNamespace(cx, regs.sp[-1])) + goto error; + regs.sp--; +} +END_CASE(JSOP_DEFXMLNS) + +BEGIN_CASE(JSOP_ANYNAME) +{ + jsid id; + if (!js_GetAnyName(cx, &id)) + goto error; + PUSH_COPY(IdToValue(id)); +} +END_CASE(JSOP_ANYNAME) + +BEGIN_CASE(JSOP_QNAMEPART) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + PUSH_STRING(ATOM_TO_STRING(atom)); +} +END_CASE(JSOP_QNAMEPART) + +BEGIN_CASE(JSOP_QNAMECONST) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + Value rval = StringValue(ATOM_TO_STRING(atom)); + Value lval = regs.sp[-1]; + JSObject *obj = js_ConstructXMLQNameObject(cx, lval, rval); + if (!obj) + goto error; + regs.sp[-1].setObject(*obj); +} +END_CASE(JSOP_QNAMECONST) + +BEGIN_CASE(JSOP_QNAME) +{ + Value rval = regs.sp[-1]; + Value lval = regs.sp[-2]; + JSObject *obj = js_ConstructXMLQNameObject(cx, lval, rval); + if (!obj) + goto error; + regs.sp--; + regs.sp[-1].setObject(*obj); +} +END_CASE(JSOP_QNAME) + +BEGIN_CASE(JSOP_TOATTRNAME) +{ + Value rval; + rval = regs.sp[-1]; + if (!js_ToAttributeName(cx, &rval)) + goto error; + regs.sp[-1] = rval; +} +END_CASE(JSOP_TOATTRNAME) + +BEGIN_CASE(JSOP_TOATTRVAL) +{ + Value rval; + rval = regs.sp[-1]; + JS_ASSERT(rval.isString()); + JSString *str = js_EscapeAttributeValue(cx, rval.toString(), JS_FALSE); + if (!str) + goto error; + regs.sp[-1].setString(str); +} +END_CASE(JSOP_TOATTRVAL) + +BEGIN_CASE(JSOP_ADDATTRNAME) +BEGIN_CASE(JSOP_ADDATTRVAL) +{ + Value rval = regs.sp[-1]; + Value lval = regs.sp[-2]; + JSString *str = lval.toString(); + JSString *str2 = rval.toString(); + str = js_AddAttributePart(cx, op == JSOP_ADDATTRNAME, str, str2); + if (!str) + goto error; + regs.sp--; + regs.sp[-1].setString(str); +} +END_CASE(JSOP_ADDATTRNAME) + +BEGIN_CASE(JSOP_BINDXMLNAME) +{ + Value lval; + lval = regs.sp[-1]; + JSObject *obj; + jsid id; + if (!js_FindXMLProperty(cx, lval, &obj, &id)) + goto error; + regs.sp[-1].setObjectOrNull(obj); + PUSH_COPY(IdToValue(id)); +} +END_CASE(JSOP_BINDXMLNAME) + +BEGIN_CASE(JSOP_SETXMLNAME) +{ + JSObject *obj = ®s.sp[-3].toObject(); + Value rval = regs.sp[-1]; + jsid id; + FETCH_ELEMENT_ID(obj, -2, id); + if (!obj->setProperty(cx, id, &rval, script->strictModeCode)) + goto error; + rval = regs.sp[-1]; + regs.sp -= 2; + regs.sp[-1] = rval; +} +END_CASE(JSOP_SETXMLNAME) + +BEGIN_CASE(JSOP_CALLXMLNAME) +BEGIN_CASE(JSOP_XMLNAME) +{ + Value lval = regs.sp[-1]; + JSObject *obj; + jsid id; + if (!js_FindXMLProperty(cx, lval, &obj, &id)) + goto error; + Value rval; + if (!obj->getProperty(cx, id, &rval)) + goto error; + regs.sp[-1] = rval; + if (op == JSOP_CALLXMLNAME) + PUSH_IMPLICIT_THIS(cx, obj, rval); +} +END_CASE(JSOP_XMLNAME) + +BEGIN_CASE(JSOP_DESCENDANTS) +BEGIN_CASE(JSOP_DELDESC) +{ + JSObject *obj; + FETCH_OBJECT(cx, -2, obj); + jsval rval = Jsvalify(regs.sp[-1]); + if (!js_GetXMLDescendants(cx, obj, rval, &rval)) + goto error; + + if (op == JSOP_DELDESC) { + regs.sp[-1] = Valueify(rval); /* set local root */ + if (!js_DeleteXMLListElements(cx, JSVAL_TO_OBJECT(rval))) + goto error; + rval = JSVAL_TRUE; /* always succeed */ + } + + regs.sp--; + regs.sp[-1] = Valueify(rval); +} +END_CASE(JSOP_DESCENDANTS) + +{ +BEGIN_CASE(JSOP_FILTER) + /* + * We push the hole value before jumping to [enditer] so we can detect the + * first iteration and direct js_StepXMLListFilter to initialize filter's + * state. + */ + PUSH_HOLE(); + len = GET_JUMP_OFFSET(regs.pc); + JS_ASSERT(len > 0); +END_VARLEN_CASE +} + +BEGIN_CASE(JSOP_ENDFILTER) +{ + bool cond = !regs.sp[-1].isMagic(); + if (cond) { + /* Exit the "with" block left from the previous iteration. */ + js_LeaveWith(cx); + } + if (!js_StepXMLListFilter(cx, cond)) + goto error; + if (!regs.sp[-1].isNull()) { + /* + * Decrease sp after EnterWith returns as we use sp[-1] there to root + * temporaries. + */ + JS_ASSERT(IsXML(regs.sp[-1])); + if (!js_EnterWith(cx, -2, JSOP_ENDFILTER, JSOP_ENDFILTER_LENGTH)) + goto error; + regs.sp--; + len = GET_JUMP_OFFSET(regs.pc); + JS_ASSERT(len < 0); + BRANCH(len); + } + regs.sp--; +} +END_CASE(JSOP_ENDFILTER); + +BEGIN_CASE(JSOP_TOXML) +{ + Value rval = regs.sp[-1]; + JSObject *obj = js_ValueToXMLObject(cx, rval); + if (!obj) + goto error; + regs.sp[-1].setObject(*obj); +} +END_CASE(JSOP_TOXML) + +BEGIN_CASE(JSOP_TOXMLLIST) +{ + Value rval = regs.sp[-1]; + JSObject *obj = js_ValueToXMLListObject(cx, rval); + if (!obj) + goto error; + regs.sp[-1].setObject(*obj); +} +END_CASE(JSOP_TOXMLLIST) + +BEGIN_CASE(JSOP_XMLTAGEXPR) +{ + Value rval = regs.sp[-1]; + JSString *str = js_ValueToString(cx, rval); + if (!str) + goto error; + regs.sp[-1].setString(str); +} +END_CASE(JSOP_XMLTAGEXPR) + +BEGIN_CASE(JSOP_XMLELTEXPR) +{ + Value rval = regs.sp[-1]; + JSString *str; + if (IsXML(rval)) { + str = js_ValueToXMLString(cx, rval); + } else { + str = js_ValueToString(cx, rval); + if (str) + str = js_EscapeElementValue(cx, str); + } + if (!str) + goto error; + regs.sp[-1].setString(str); +} +END_CASE(JSOP_XMLELTEXPR) + +BEGIN_CASE(JSOP_XMLCDATA) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + JSString *str = ATOM_TO_STRING(atom); + JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, str); + if (!obj) + goto error; + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_XMLCDATA) + +BEGIN_CASE(JSOP_XMLCOMMENT) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + JSString *str = ATOM_TO_STRING(atom); + JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, str); + if (!obj) + goto error; + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_XMLCOMMENT) + +BEGIN_CASE(JSOP_XMLPI) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + JSString *str = ATOM_TO_STRING(atom); + Value rval = regs.sp[-1]; + JSString *str2 = rval.toString(); + JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_PROCESSING_INSTRUCTION, str, str2); + if (!obj) + goto error; + regs.sp[-1].setObject(*obj); +} +END_CASE(JSOP_XMLPI) + +BEGIN_CASE(JSOP_GETFUNNS) +{ + Value rval; + if (!js_GetFunctionNamespace(cx, &rval)) + goto error; + PUSH_COPY(rval); +} +END_CASE(JSOP_GETFUNNS) +#endif /* JS_HAS_XML_SUPPORT */ + +BEGIN_CASE(JSOP_ENTERBLOCK) +{ + JSObject *obj; + LOAD_OBJECT(0, obj); + JS_ASSERT(obj->isStaticBlock()); + JS_ASSERT(regs.fp->base() + OBJ_BLOCK_DEPTH(cx, obj) == regs.sp); + Value *vp = regs.sp + OBJ_BLOCK_COUNT(cx, obj); + JS_ASSERT(regs.sp < vp); + JS_ASSERT(vp <= regs.fp->slots() + script->nslots); + SetValueRangeToUndefined(regs.sp, vp); + regs.sp = vp; + +#ifdef DEBUG + /* + * The young end of fp->scopeChain may omit blocks if we haven't closed + * over them, but if there are any closure blocks on fp->scopeChain, they'd + * better be (clones of) ancestors of the block we're entering now; + * anything else we should have popped off fp->scopeChain when we left its + * static scope. + */ + JSObject *obj2 = ®s.fp->scopeChain(); + Class *clasp; + while ((clasp = obj2->getClass()) == &js_WithClass) + obj2 = obj2->getParent(); + if (clasp == &js_BlockClass && + obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, regs.fp)) { + JSObject *youngestProto = obj2->getProto(); + JS_ASSERT(youngestProto->isStaticBlock()); + JSObject *parent = obj; + while ((parent = parent->getParent()) != youngestProto) + JS_ASSERT(parent); + } +#endif +} +END_CASE(JSOP_ENTERBLOCK) + +BEGIN_CASE(JSOP_LEAVEBLOCKEXPR) +BEGIN_CASE(JSOP_LEAVEBLOCK) +{ + JSObject *blockChain; + LOAD_OBJECT(UINT16_LEN, blockChain); +#ifdef DEBUG + JS_ASSERT(blockChain->isStaticBlock()); + uintN blockDepth = OBJ_BLOCK_DEPTH(cx, blockChain); + JS_ASSERT(blockDepth <= StackDepth(script)); +#endif + /* + * If we're about to leave the dynamic scope of a block that has been + * cloned onto fp->scopeChain, clear its private data, move its locals from + * the stack into the clone, and pop it off the chain. + */ + JSObject &obj = regs.fp->scopeChain(); + if (obj.getProto() == blockChain) { + JS_ASSERT(obj.isClonedBlock()); + if (!js_PutBlockObject(cx, JS_TRUE)) + goto error; + } + + /* Move the result of the expression to the new topmost stack slot. */ + Value *vp = NULL; /* silence GCC warnings */ + if (op == JSOP_LEAVEBLOCKEXPR) + vp = ®s.sp[-1]; + regs.sp -= GET_UINT16(regs.pc); + if (op == JSOP_LEAVEBLOCKEXPR) { + JS_ASSERT(regs.fp->base() + blockDepth == regs.sp - 1); + regs.sp[-1] = *vp; + } else { + JS_ASSERT(regs.fp->base() + blockDepth == regs.sp); + } +} +END_CASE(JSOP_LEAVEBLOCK) + +#if JS_HAS_GENERATORS +BEGIN_CASE(JSOP_GENERATOR) +{ + JS_ASSERT(!cx->isExceptionPending()); + regs.pc += JSOP_GENERATOR_LENGTH; + JSObject *obj = js_NewGenerator(cx); + if (!obj) + goto error; + JS_ASSERT(!regs.fp->hasCallObj() && !regs.fp->hasArgsObj()); + regs.fp->setReturnValue(ObjectValue(*obj)); + interpReturnOK = true; + if (entryFrame != regs.fp) + goto inline_return; + goto exit; +} + +BEGIN_CASE(JSOP_YIELD) + JS_ASSERT(!cx->isExceptionPending()); + JS_ASSERT(regs.fp->isFunctionFrame() && !regs.fp->isEvalFrame()); + if (cx->generatorFor(regs.fp)->state == JSGEN_CLOSING) { + js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, + JSDVG_SEARCH_STACK, argv[-2], NULL); + goto error; + } + regs.fp->setReturnValue(regs.sp[-1]); + regs.fp->setYielding(); + regs.pc += JSOP_YIELD_LENGTH; + interpReturnOK = JS_TRUE; + goto exit; + +BEGIN_CASE(JSOP_ARRAYPUSH) +{ + uint32 slot = GET_UINT16(regs.pc); + JS_ASSERT(script->nfixed <= slot); + JS_ASSERT(slot < script->nslots); + JSObject *obj = ®s.fp->slots()[slot].toObject(); + if (!js_ArrayCompPush(cx, obj, regs.sp[-1])) + goto error; + regs.sp--; +} +END_CASE(JSOP_ARRAYPUSH) +#endif /* JS_HAS_GENERATORS */ + +#if JS_THREADED_INTERP + L_JSOP_BACKPATCH: + L_JSOP_BACKPATCH_POP: + +# if !JS_HAS_GENERATORS + L_JSOP_GENERATOR: + L_JSOP_YIELD: + L_JSOP_ARRAYPUSH: +# endif + +# if !JS_HAS_SHARP_VARS + L_JSOP_DEFSHARP: + L_JSOP_USESHARP: + L_JSOP_SHARPINIT: +# endif + +# if !JS_HAS_DESTRUCTURING + L_JSOP_ENUMCONSTELEM: +# endif + +# if !JS_HAS_XML_SUPPORT + L_JSOP_CALLXMLNAME: + L_JSOP_STARTXMLEXPR: + L_JSOP_STARTXML: + L_JSOP_DELDESC: + L_JSOP_GETFUNNS: + L_JSOP_XMLPI: + L_JSOP_XMLCOMMENT: + L_JSOP_XMLCDATA: + L_JSOP_XMLELTEXPR: + L_JSOP_XMLTAGEXPR: + L_JSOP_TOXMLLIST: + L_JSOP_TOXML: + L_JSOP_ENDFILTER: + L_JSOP_FILTER: + L_JSOP_DESCENDANTS: + L_JSOP_XMLNAME: + L_JSOP_SETXMLNAME: + L_JSOP_BINDXMLNAME: + L_JSOP_ADDATTRVAL: + L_JSOP_ADDATTRNAME: + L_JSOP_TOATTRVAL: + L_JSOP_TOATTRNAME: + L_JSOP_QNAME: + L_JSOP_QNAMECONST: + L_JSOP_QNAMEPART: + L_JSOP_ANYNAME: + L_JSOP_DEFXMLNS: +# endif + +#endif /* !JS_THREADED_INTERP */ +#if !JS_THREADED_INTERP + default: +#endif + { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%d", op); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_BYTECODE, numBuf); + goto error; + } + +#if !JS_THREADED_INTERP + } /* switch (op) */ + } /* for (;;) */ +#endif /* !JS_THREADED_INTERP */ + + error: + JS_ASSERT(cx->regs == ®s); +#ifdef JS_TRACER + if (regs.fp->hasImacropc() && cx->isExceptionPending()) { + // Handle exceptions as if they came from the imacro-calling pc. + regs.pc = regs.fp->imacropc(); + regs.fp->clearImacropc(); + } +#endif + + JS_ASSERT(size_t((regs.fp->hasImacropc() ? regs.fp->imacropc() : regs.pc) - script->code) < + script->length); + +#ifdef JS_TRACER + /* + * This abort could be weakened to permit tracing through exceptions that + * are thrown and caught within a loop, with the co-operation of the tracer. + * For now just bail on any sign of trouble. + */ + if (TRACE_RECORDER(cx)) + AbortRecording(cx, "error or exception while recording"); +# ifdef JS_METHODJIT + if (TRACE_PROFILER(cx)) + AbortProfiling(cx); +# endif +#endif + + if (!cx->isExceptionPending()) { + /* This is an error, not a catchable exception, quit the frame ASAP. */ + interpReturnOK = JS_FALSE; + } else { + JSThrowHook handler; + JSTryNote *tn, *tnlimit; + uint32 offset; + + /* Restore atoms local in case we will resume. */ + atoms = script->atomMap.vector; + + /* Call debugger throw hook if set. */ + handler = cx->debugHooks->throwHook; + if (handler) { + Value rval; + switch (handler(cx, script, regs.pc, Jsvalify(&rval), + cx->debugHooks->throwHookData)) { + case JSTRAP_ERROR: + cx->clearPendingException(); + goto error; + case JSTRAP_RETURN: + cx->clearPendingException(); + regs.fp->setReturnValue(rval); + interpReturnOK = JS_TRUE; + goto forced_return; + case JSTRAP_THROW: + cx->setPendingException(rval); + case JSTRAP_CONTINUE: + default:; + } + CHECK_INTERRUPT_HANDLER(); + } + + /* + * Look for a try block in script that can catch this exception. + */ + if (!JSScript::isValidOffset(script->trynotesOffset)) + goto no_catch; + + offset = (uint32)(regs.pc - script->main); + tn = script->trynotes()->vector; + tnlimit = tn + script->trynotes()->length; + do { + if (offset - tn->start >= tn->length) + continue; + + /* + * We have a note that covers the exception pc but we must check + * whether the interpreter has already executed the corresponding + * handler. This is possible when the executed bytecode + * implements break or return from inside a for-in loop. + * + * In this case the emitter generates additional [enditer] and + * [gosub] opcodes to close all outstanding iterators and execute + * the finally blocks. If such an [enditer] throws an exception, + * its pc can still be inside several nested for-in loops and + * try-finally statements even if we have already closed the + * corresponding iterators and invoked the finally blocks. + * + * To address this, we make [enditer] always decrease the stack + * even when its implementation throws an exception. Thus already + * executed [enditer] and [gosub] opcodes will have try notes + * with the stack depth exceeding the current one and this + * condition is what we use to filter them out. + */ + if (tn->stackDepth > regs.sp - regs.fp->base()) + continue; + + /* + * Set pc to the first bytecode after the the try note to point + * to the beginning of catch or finally or to [enditer] closing + * the for-in loop. + */ + regs.pc = (script)->main + tn->start + tn->length; + + JSBool ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE); + JS_ASSERT(regs.sp == regs.fp->base() + tn->stackDepth); + if (!ok) { + /* + * Restart the handler search with updated pc and stack depth + * to properly notify the debugger. + */ + goto error; + } + + switch (tn->kind) { + case JSTRY_CATCH: +#if JS_HAS_GENERATORS + /* Catch cannot intercept the closing of a generator. */ + if (JS_UNLIKELY(cx->getPendingException().isMagic(JS_GENERATOR_CLOSING))) + break; +#endif + + /* + * Don't clear exceptions to save cx->exception from GC + * until it is pushed to the stack via [exception] in the + * catch block. + */ + len = 0; + DO_NEXT_OP(len); + + case JSTRY_FINALLY: + /* + * Push (true, exception) pair for finally to indicate that + * [retsub] should rethrow the exception. + */ + PUSH_BOOLEAN(true); + PUSH_COPY(cx->getPendingException()); + cx->clearPendingException(); + len = 0; + DO_NEXT_OP(len); + + case JSTRY_ITER: { + /* This is similar to JSOP_ENDITER in the interpreter loop. */ + JS_ASSERT(js_GetOpcode(cx, regs.fp->script(), regs.pc) == JSOP_ENDITER); + Value v = cx->getPendingException(); + cx->clearPendingException(); + ok = js_CloseIterator(cx, ®s.sp[-1].toObject()); + regs.sp -= 1; + if (!ok) + goto error; + cx->setPendingException(v); + } + } + } while (++tn != tnlimit); + + no_catch: + /* + * Propagate the exception or error to the caller unless the exception + * is an asynchronous return from a generator. + */ + interpReturnOK = JS_FALSE; +#if JS_HAS_GENERATORS + if (JS_UNLIKELY(cx->isExceptionPending() && + cx->getPendingException().isMagic(JS_GENERATOR_CLOSING))) { + cx->clearPendingException(); + interpReturnOK = JS_TRUE; + regs.fp->clearReturnValue(); + } +#endif + } + + forced_return: + /* + * Unwind the scope making sure that interpReturnOK stays false even when + * js_UnwindScope returns true. + * + * When a trap handler returns JSTRAP_RETURN, we jump here with + * interpReturnOK set to true bypassing any finally blocks. + */ + interpReturnOK &= js_UnwindScope(cx, 0, interpReturnOK || cx->isExceptionPending()); + JS_ASSERT(regs.sp == regs.fp->base()); + +#ifdef DEBUG + cx->logPrevPc = NULL; +#endif + + if (entryFrame != regs.fp) + goto inline_return; + + exit: + interpReturnOK = ScriptEpilogue(cx, regs.fp, interpReturnOK); + regs.fp->setFinishedInInterpreter(); + + /* + * At this point we are inevitably leaving an interpreted function or a + * top-level script, and returning to one of: + * (a) an "out of line" call made through js_Invoke; + * (b) a js_Execute activation; + * (c) a generator (SendToGenerator, jsiter.c). + * + * We must not be in an inline frame. The check above ensures that for the + * error case and for a normal return, the code jumps directly to parent's + * frame pc. + */ + JS_ASSERT(entryFrame == regs.fp); + +#ifdef JS_TRACER + JS_ASSERT_IF(interpReturnOK && interpMode == JSINTERP_RECORD, !TRACE_RECORDER(cx)); + if (TRACE_RECORDER(cx)) + AbortRecording(cx, "recording out of Interpret"); +# ifdef JS_METHODJIT + if (TRACE_PROFILER(cx)) + AbortProfiling(cx); +# endif +#endif + + JS_ASSERT_IF(!regs.fp->isGeneratorFrame(), !js_IsActiveWithOrBlock(cx, ®s.fp->scopeChain(), 0)); + + return interpReturnOK; + + atom_not_defined: + { + JSAutoByteString printable; + if (js_AtomToPrintableString(cx, atomNotDefined, &printable)) + js_ReportIsNotDefined(cx, printable.ptr()); + } + goto error; + + /* + * This path is used when it's guaranteed the method can be finished + * inside the JIT. + */ +#if defined(JS_METHODJIT) + leave_on_safe_point: +#endif + return interpReturnOK; +} + +} /* namespace js */ + +#endif /* !defined jsinvoke_cpp___ */ diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h new file mode 100644 index 0000000..b2e490e --- /dev/null +++ b/js/src/jsinterp.h @@ -0,0 +1,1122 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsinterp_h___ +#define jsinterp_h___ +/* + * JS interpreter interface. + */ +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jsfun.h" +#include "jsopcode.h" +#include "jsscript.h" +#include "jsvalue.h" + +struct JSFrameRegs +{ + STATIC_SKIP_INFERENCE + js::Value *sp; /* stack pointer */ + jsbytecode *pc; /* program counter */ + JSStackFrame *fp; /* active frame */ +}; + +/* Flags to toggle js::Interpret() execution. */ +enum JSInterpMode +{ + JSINTERP_NORMAL = 0, /* interpreter is running normally */ + JSINTERP_RECORD = 1, /* interpreter has been started to record/run traces */ + JSINTERP_SAFEPOINT = 2, /* interpreter should leave on a method JIT safe point */ + JSINTERP_PROFILE = 3 /* interpreter should profile a loop */ +}; + +/* Flags used in JSStackFrame::flags_ */ +enum JSFrameFlags +{ + /* Primary frame type */ + JSFRAME_GLOBAL = 0x1, /* frame pushed for a global script */ + JSFRAME_FUNCTION = 0x2, /* frame pushed for a scripted call */ + JSFRAME_DUMMY = 0x4, /* frame pushed for bookkeeping */ + + /* Frame subtypes */ + JSFRAME_EVAL = 0x8, /* frame pushed for eval() or debugger eval */ + JSFRAME_DEBUGGER = 0x10, /* frame pushed for debugger eval */ + JSFRAME_GENERATOR = 0x20, /* frame is associated with a generator */ + JSFRAME_FLOATING_GENERATOR = 0x40, /* frame is is in generator obj, not on stack */ + JSFRAME_CONSTRUCTING = 0x80, /* frame is for a constructor invocation */ + + /* Temporary frame states */ + JSFRAME_ASSIGNING = 0x100, /* not-JOF_ASSIGNING op is assigning */ + JSFRAME_YIELDING = 0x200, /* js::Interpret dispatched JSOP_YIELD */ + JSFRAME_FINISHED_IN_INTERPRETER = 0x400, /* set if frame finished in Interpret() */ + + /* Concerning function arguments */ + JSFRAME_OVERRIDE_ARGS = 0x1000, /* overridden arguments local variable */ + JSFRAME_OVERFLOW_ARGS = 0x2000, /* numActualArgs > numFormalArgs */ + JSFRAME_UNDERFLOW_ARGS = 0x4000, /* numActualArgs < numFormalArgs */ + + /* Lazy frame initialization */ + JSFRAME_HAS_IMACRO_PC = 0x8000, /* frame has imacpc value available */ + JSFRAME_HAS_CALL_OBJ = 0x10000, /* frame has a callobj reachable from scopeChain_ */ + JSFRAME_HAS_ARGS_OBJ = 0x20000, /* frame has an argsobj in JSStackFrame::args */ + JSFRAME_HAS_HOOK_DATA = 0x40000, /* frame has hookData_ set */ + JSFRAME_HAS_ANNOTATION = 0x80000, /* frame has annotation_ set */ + JSFRAME_HAS_RVAL = 0x100000, /* frame has rval_ set */ + JSFRAME_HAS_SCOPECHAIN = 0x200000, /* frame has scopeChain_ set */ + JSFRAME_HAS_PREVPC = 0x400000 /* frame has prevpc_ set */ +}; + +namespace js { namespace mjit { struct JITScript; } } + +/* + * A stack frame is a part of a stack segment (see js::StackSegment) which is + * on the per-thread VM stack (see js::StackSpace). + */ +struct JSStackFrame +{ + private: + mutable uint32 flags_; /* bits described by JSFrameFlags */ + union { /* describes what code is executing in a */ + JSScript *script; /* global frame */ + JSFunction *fun; /* function frame, pre GetScopeChain */ + } exec; + union { /* describes the arguments of a function */ + uintN nactual; /* pre GetArgumentsObject */ + JSObject *obj; /* post GetArgumentsObject */ + JSScript *script; /* eval has no args, but needs a script */ + } args; + mutable JSObject *scopeChain_; /* current scope chain */ + JSStackFrame *prev_; /* previous cx->regs->fp */ + void *ncode_; /* return address for method JIT */ + + /* Lazily initialized */ + js::Value rval_; /* return value of the frame */ + jsbytecode *prevpc_; /* pc of previous frame*/ + jsbytecode *imacropc_; /* pc of macro caller */ + void *hookData_; /* closure returned by call hook */ + void *annotation_; /* perhaps remove with bug 546848 */ + + friend class js::StackSpace; + friend class js::FrameRegsIter; + friend struct JSContext; + + inline void initPrev(JSContext *cx); + + public: + /* + * Stack frame sort (see JSStackFrame comment above) + * + * A stack frame may have one of three types, which determines which + * members of the frame may be accessed and other invariants: + * + * global frame: execution of global code or an eval in global code + * function frame: execution of function code or an eval in a function + * dummy frame: bookkeeping frame (read: hack) + * + * As noted, global and function frames may optionally be 'eval frames', which + * further restricts the stack frame members which may be used. Namely, the + * argument-related members of function eval frames are not valid, since an eval + * shares its containing function's arguments rather than having its own. + */ + + bool isFunctionFrame() const { + return !!(flags_ & JSFRAME_FUNCTION); + } + + bool isGlobalFrame() const { + return !!(flags_ & JSFRAME_GLOBAL); + } + + bool isDummyFrame() const { + return !!(flags_ & JSFRAME_DUMMY); + } + + bool isScriptFrame() const { + return !!(flags_ & (JSFRAME_FUNCTION | JSFRAME_GLOBAL)); + } + + bool isEvalFrame() const { + JS_ASSERT_IF(flags_ & JSFRAME_EVAL, isScriptFrame()); + return flags_ & JSFRAME_EVAL; + } + + bool isExecuteFrame() const { + return !!(flags_ & (JSFRAME_GLOBAL | JSFRAME_EVAL)); + } + + /* + * Frame initialization + * + * After acquiring a pointer to an uninitialized stack frame on the VM + * stack from js::StackSpace, these members are used to initialize the + * stack frame before officially pushing the frame into the context. + * Collecting frame initialization into a set of inline helpers allows + * simpler reasoning and makes call-optimization easier. + */ + + /* Used for Invoke, Interpret, trace-jit LeaveTree, and method-jit stubs. */ + inline void initCallFrame(JSContext *cx, JSObject &callee, JSFunction *fun, + uint32 nactual, uint32 flags); + + /* Used for SessionInvoke. */ + inline void resetInvokeCallFrame(); + + /* Called by method-jit stubs and serve as a specification for jit-code. */ + inline void initCallFrameCallerHalf(JSContext *cx, uint32 flags, void *ncode); + inline void initCallFrameEarlyPrologue(JSFunction *fun, uint32 nactual); + inline void initCallFrameLatePrologue(); + + /* Used for eval. */ + inline void initEvalFrame(JSContext *cx, JSScript *script, JSStackFrame *prev, + uint32 flags); + inline void initGlobalFrame(JSScript *script, JSObject &chain, uint32 flags); + + /* Used when activating generators. */ + inline void stealFrameAndSlots(js::Value *vp, JSStackFrame *otherfp, + js::Value *othervp, js::Value *othersp); + + /* Perhaps one fine day we will remove dummy frames. */ + inline void initDummyFrame(JSContext *cx, JSObject &chain); + + /* + * Previous frame + * + * A frame's 'prev' frame is either null or the previous frame pointed to + * by cx->regs->fp when this frame was pushed. Often, given two prev-linked + * frames, the next-frame is a function or eval that was called by the + * prev-frame, but not always: the prev-frame may have called a native that + * reentered the VM through JS_CallFunctionValue on the same context + * (without calling JS_SaveFrameChain) which pushed the next-frame. Thus, + * 'prev' has little semantic meaning and basically just tells the VM what + * to set cx->regs->fp to when this frame is popped. + */ + + JSStackFrame *prev() const { + return prev_; + } + + inline void resetGeneratorPrev(JSContext *cx); + + /* + * Frame slots + * + * A frame's 'slots' are the fixed slots associated with the frame (like + * local variables) followed by an expression stack holding temporary + * values. A frame's 'base' is the base of the expression stack. + */ + + js::Value *slots() const { + return (js::Value *)(this + 1); + } + + js::Value *base() const { + return slots() + script()->nfixed; + } + + js::Value &varSlot(uintN i) { + JS_ASSERT(i < script()->nfixed); + JS_ASSERT_IF(maybeFun(), i < script()->bindings.countVars()); + return slots()[i]; + } + + /* + * Script + * + * All function and global frames have an associated JSScript which holds + * the bytecode being executed for the frame. + */ + + /* + * Get the frame's current bytecode, assuming |this| is in |cx|. + * next is frame whose prev == this, NULL if not known or if this == cx->fp(). + */ + jsbytecode *pc(JSContext *cx, JSStackFrame *next = NULL); + + jsbytecode *prevpc() { + JS_ASSERT((prev_ != NULL) && (flags_ & JSFRAME_HAS_PREVPC)); + return prevpc_; + } + + JSScript *script() const { + JS_ASSERT(isScriptFrame()); + return isFunctionFrame() + ? isEvalFrame() ? args.script : fun()->script() + : exec.script; + } + + JSScript *functionScript() const { + JS_ASSERT(isFunctionFrame()); + return isEvalFrame() ? args.script : fun()->script(); + } + + JSScript *globalScript() const { + JS_ASSERT(isGlobalFrame()); + return exec.script; + } + + JSScript *maybeScript() const { + return isScriptFrame() ? script() : NULL; + } + + size_t numFixed() const { + return script()->nfixed; + } + + size_t numSlots() const { + return script()->nslots; + } + + size_t numGlobalVars() const { + JS_ASSERT(isGlobalFrame()); + return exec.script->nfixed; + } + + /* + * Function + * + * All function frames have an associated interpreted JSFunction. + */ + + JSFunction* fun() const { + JS_ASSERT(isFunctionFrame()); + return exec.fun; + } + + JSFunction* maybeFun() const { + return isFunctionFrame() ? fun() : NULL; + } + + /* + * Arguments + * + * Only non-eval function frames have arguments. A frame follows its + * arguments contiguously in memory. The arguments pushed by the caller are + * the 'actual' arguments. The declared arguments of the callee are the + * 'formal' arguments. When the caller passes less or equal actual + * arguments, the actual and formal arguments are the same array (but with + * different extents). When the caller passes too many arguments, the + * formal subset of the actual arguments is copied onto the top of the + * stack. This allows the engine to maintain a jit-time constant offset of + * arguments from the frame pointer. Since the formal subset of the actual + * arguments is potentially on the stack twice, it is important for all + * reads/writes to refer to the same canonical memory location. + * + * An arguments object (the object returned by the 'arguments' keyword) is + * lazily created, so a given function frame may or may not have one. + */ + + /* True if this frame has arguments. Contrast with hasArgsObj. */ + bool hasArgs() const { + return isFunctionFrame() && !isEvalFrame(); + } + + uintN numFormalArgs() const { + JS_ASSERT(hasArgs()); + return fun()->nargs; + } + + js::Value &formalArg(uintN i) const { + JS_ASSERT(i < numFormalArgs()); + return formalArgs()[i]; + } + + js::Value *formalArgs() const { + JS_ASSERT(hasArgs()); + return (js::Value *)this - numFormalArgs(); + } + + js::Value *formalArgsEnd() const { + JS_ASSERT(hasArgs()); + return (js::Value *)this; + } + + js::Value *maybeFormalArgs() const { + return (flags_ & (JSFRAME_FUNCTION | JSFRAME_EVAL)) == JSFRAME_FUNCTION + ? formalArgs() + : NULL; + } + + inline uintN numActualArgs() const; + inline js::Value *actualArgs() const; + inline js::Value *actualArgsEnd() const; + + inline js::Value &canonicalActualArg(uintN i) const; + template inline void forEachCanonicalActualArg(Op op); + template inline void forEachFormalArg(Op op); + + inline void clearMissingArgs(); + + bool hasArgsObj() const { + return !!(flags_ & JSFRAME_HAS_ARGS_OBJ); + } + + JSObject &argsObj() const { + JS_ASSERT(hasArgsObj()); + JS_ASSERT(!isEvalFrame()); + return *args.obj; + } + + JSObject *maybeArgsObj() const { + return hasArgsObj() ? &argsObj() : NULL; + } + + inline void setArgsObj(JSObject &obj); + inline void clearArgsObj(); + + /* + * This value + * + * Every frame has a this value although, until 'this' is computed, the + * value may not be the semantically-correct 'this' value. + * + * The 'this' value is stored before the formal arguments for function + * frames and directly before the frame for global frames. The *Args + * members assert !isEvalFrame(), so we implement specialized inline + * methods for accessing 'this'. When the caller has static knowledge that + * a frame is a function or global frame, 'functionThis' and 'globalThis', + * respectively, allow more efficient access. + */ + + js::Value &functionThis() const { + JS_ASSERT(isFunctionFrame()); + if (isEvalFrame()) + return ((js::Value *)this)[-1]; + return formalArgs()[-1]; + } + + JSObject &constructorThis() const { + JS_ASSERT(hasArgs()); + return formalArgs()[-1].toObject(); + } + + js::Value &globalThis() const { + JS_ASSERT(isGlobalFrame()); + return ((js::Value *)this)[-1]; + } + + js::Value &thisValue() const { + if (flags_ & (JSFRAME_EVAL | JSFRAME_GLOBAL)) + return ((js::Value *)this)[-1]; + return formalArgs()[-1]; + } + + inline bool computeThis(JSContext *cx); + + /* + * Callee + * + * Only function frames have a callee. An eval frame in a function has the + * same caller as its containing function frame. + */ + + js::Value &calleeValue() const { + JS_ASSERT(isFunctionFrame()); + if (isEvalFrame()) + return ((js::Value *)this)[-2]; + return formalArgs()[-2]; + } + + JSObject &callee() const { + JS_ASSERT(isFunctionFrame()); + return calleeValue().toObject(); + } + + JSObject *maybeCallee() const { + return isFunctionFrame() ? &callee() : NULL; + } + + /* + * getValidCalleeObject is a fallible getter to compute the correct callee + * function object, which may require deferred cloning due to the JSObject + * methodReadBarrier. For a non-function frame, return true with *vp set + * from calleeValue, which may not be an object (it could be undefined). + */ + bool getValidCalleeObject(JSContext *cx, js::Value *vp); + + /* + * Scope chain + * + * Every frame has a scopeChain which, when traversed via the 'parent' link + * to the root, indicates the current global object. A 'call object' is a + * node on a scope chain representing a function's activation record. A + * call object is used for dynamically-scoped name lookup and lexically- + * scoped upvar access. The call object holds the values of locals and + * arguments when a function returns (and its stack frame is popped). For + * performance reasons, call objects are created lazily for 'lightweight' + * functions, i.e., functions which are not statically known to require a + * call object. Thus, a given function frame may or may not have a call + * object. When a function does have a call object, it is found by walking + * up the scope chain until the first call object. Thus, it is important, + * when setting the scope chain, to indicate whether the new scope chain + * contains a new call object and thus changes the 'hasCallObj' state. + */ + + JSObject &scopeChain() const { + JS_ASSERT_IF(!(flags_ & JSFRAME_HAS_SCOPECHAIN), isFunctionFrame()); + if (!(flags_ & JSFRAME_HAS_SCOPECHAIN)) { + scopeChain_ = callee().getParent(); + flags_ |= JSFRAME_HAS_SCOPECHAIN; + } + return *scopeChain_; + } + + bool hasCallObj() const { + return !!(flags_ & JSFRAME_HAS_CALL_OBJ); + } + + inline JSObject &callObj() const; + inline JSObject *maybeCallObj() const; + inline void setScopeChainNoCallObj(JSObject &obj); + inline void setScopeChainAndCallObj(JSObject &obj); + inline void clearCallObj(); + + /* + * Imacropc + * + * A frame's IMacro pc is the bytecode address when an imacro started + * executing (guaranteed non-null). An imacro does not push a frame, so + * when the imacro finishes, the frame's IMacro pc becomes the current pc. + */ + + bool hasImacropc() const { + return flags_ & JSFRAME_HAS_IMACRO_PC; + } + + jsbytecode *imacropc() const { + JS_ASSERT(hasImacropc()); + return imacropc_; + } + + jsbytecode *maybeImacropc() const { + return hasImacropc() ? imacropc() : NULL; + } + + void clearImacropc() { + flags_ &= ~JSFRAME_HAS_IMACRO_PC; + } + + void setImacropc(jsbytecode *pc) { + JS_ASSERT(pc); + JS_ASSERT(!(flags_ & JSFRAME_HAS_IMACRO_PC)); + imacropc_ = pc; + flags_ |= JSFRAME_HAS_IMACRO_PC; + } + + /* Annotation (will be removed after bug 546848) */ + + void* annotation() const { + return (flags_ & JSFRAME_HAS_ANNOTATION) ? annotation_ : NULL; + } + + void setAnnotation(void *annot) { + flags_ |= JSFRAME_HAS_ANNOTATION; + annotation_ = annot; + } + + /* Debugger hook data */ + + bool hasHookData() const { + return !!(flags_ & JSFRAME_HAS_HOOK_DATA); + } + + void* hookData() const { + JS_ASSERT(hasHookData()); + return hookData_; + } + + void* maybeHookData() const { + return hasHookData() ? hookData_ : NULL; + } + + void setHookData(void *v) { + hookData_ = v; + flags_ |= JSFRAME_HAS_HOOK_DATA; + } + + /* Return value */ + + const js::Value &returnValue() { + if (!(flags_ & JSFRAME_HAS_RVAL)) + rval_.setUndefined(); + return rval_; + } + + void markReturnValue() { + flags_ |= JSFRAME_HAS_RVAL; + } + + void setReturnValue(const js::Value &v) { + rval_ = v; + markReturnValue(); + } + + void clearReturnValue() { + rval_.setUndefined(); + markReturnValue(); + } + + /* Native-code return address */ + + void *nativeReturnAddress() const { + return ncode_; + } + + void setNativeReturnAddress(void *addr) { + ncode_ = addr; + } + + void **addressOfNativeReturnAddress() { + return &ncode_; + } + + /* + * Generator-specific members + * + * A non-eval function frame may optionally be the activation of a + * generator. For the most part, generator frames act like ordinary frames. + * For exceptions, see js_FloatingFrameIfGenerator. + */ + + bool isGeneratorFrame() const { + return !!(flags_ & JSFRAME_GENERATOR); + } + + bool isFloatingGenerator() const { + JS_ASSERT_IF(flags_ & JSFRAME_FLOATING_GENERATOR, isGeneratorFrame()); + return !!(flags_ & JSFRAME_FLOATING_GENERATOR); + } + + void initFloatingGenerator() { + JS_ASSERT(!(flags_ & JSFRAME_GENERATOR)); + flags_ |= (JSFRAME_GENERATOR | JSFRAME_FLOATING_GENERATOR); + } + + void unsetFloatingGenerator() { + flags_ &= ~JSFRAME_FLOATING_GENERATOR; + } + + void setFloatingGenerator() { + flags_ |= JSFRAME_FLOATING_GENERATOR; + } + + /* + * Other flags + */ + + bool isConstructing() const { + return !!(flags_ & JSFRAME_CONSTRUCTING); + } + + uint32 isConstructingFlag() const { + JS_ASSERT(isFunctionFrame()); + JS_ASSERT((flags_ & ~(JSFRAME_CONSTRUCTING | JSFRAME_FUNCTION)) == 0); + return flags_; + } + + bool isDebuggerFrame() const { + return !!(flags_ & JSFRAME_DEBUGGER); + } + + bool isEvalOrDebuggerFrame() const { + return !!(flags_ & (JSFRAME_EVAL | JSFRAME_DEBUGGER)); + } + + bool hasOverriddenArgs() const { + return !!(flags_ & JSFRAME_OVERRIDE_ARGS); + } + + bool hasOverflowArgs() const { + return !!(flags_ & JSFRAME_OVERFLOW_ARGS); + } + + void setOverriddenArgs() { + flags_ |= JSFRAME_OVERRIDE_ARGS; + } + + bool isAssigning() const { + return !!(flags_ & JSFRAME_ASSIGNING); + } + + void setAssigning() { + flags_ |= JSFRAME_ASSIGNING; + } + + void clearAssigning() { + flags_ &= ~JSFRAME_ASSIGNING; + } + + bool isYielding() { + return !!(flags_ & JSFRAME_YIELDING); + } + + void setYielding() { + flags_ |= JSFRAME_YIELDING; + } + + void clearYielding() { + flags_ &= ~JSFRAME_YIELDING; + } + + void setFinishedInInterpreter() { + flags_ |= JSFRAME_FINISHED_IN_INTERPRETER; + } + + bool finishedInInterpreter() const { + return !!(flags_ & JSFRAME_FINISHED_IN_INTERPRETER); + } + + /* + * Variables object accessors + * + * A stack frame's 'varobj' refers to the 'variables object' (ES3 term) + * associated with the Execution Context's VariableEnvironment (ES5 10.3). + * + * To compute the frame's varobj, the caller must supply the segment + * containing the frame (see js::StackSegment comment). As an abbreviation, + * the caller may pass the context if the frame is contained in that + * context's active segment. + */ + + inline JSObject &varobj(js::StackSegment *seg) const; + inline JSObject &varobj(JSContext *cx) const; + + /* Access to privates from the jits. */ + + static size_t offsetOfFlags() { + return offsetof(JSStackFrame, flags_); + } + + static size_t offsetOfExec() { + return offsetof(JSStackFrame, exec); + } + + void *addressOfArgs() { + return &args; + } + + static size_t offsetOfScopeChain() { + return offsetof(JSStackFrame, scopeChain_); + } + + JSObject **addressOfScopeChain() { + JS_ASSERT(flags_ & JSFRAME_HAS_SCOPECHAIN); + return &scopeChain_; + } + + static size_t offsetOfPrev() { + return offsetof(JSStackFrame, prev_); + } + + static size_t offsetOfReturnValue() { + return offsetof(JSStackFrame, rval_); + } + + static ptrdiff_t offsetOfncode() { + return offsetof(JSStackFrame, ncode_); + } + + static ptrdiff_t offsetOfCallee(JSFunction *fun) { + JS_ASSERT(fun != NULL); + return -(fun->nargs + 2) * sizeof(js::Value); + } + + static ptrdiff_t offsetOfThis(JSFunction *fun) { + return fun == NULL + ? -1 * ptrdiff_t(sizeof(js::Value)) + : -(fun->nargs + 1) * ptrdiff_t(sizeof(js::Value)); + } + + static ptrdiff_t offsetOfFormalArg(JSFunction *fun, uintN i) { + JS_ASSERT(i < fun->nargs); + return (-(int)fun->nargs + i) * sizeof(js::Value); + } + + static size_t offsetOfFixed(uintN i) { + return sizeof(JSStackFrame) + i * sizeof(js::Value); + } + + /* Workaround for static asserts on private members. */ + + void staticAsserts() { + JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) % sizeof(js::Value) == 0); + JS_STATIC_ASSERT(sizeof(JSStackFrame) % sizeof(js::Value) == 0); + } + +#ifdef JS_METHODJIT + js::mjit::JITScript *jit() { + return script()->getJIT(isConstructing()); + } +#endif + + void methodjitStaticAsserts(); + +#ifdef DEBUG + /* Poison scopeChain value set before a frame is flushed. */ + static JSObject *const sInvalidScopeChain; +#endif +}; + +namespace js { + +static const size_t VALUES_PER_STACK_FRAME = sizeof(JSStackFrame) / sizeof(Value); + +extern JSObject * +GetBlockChain(JSContext *cx, JSStackFrame *fp); + +extern JSObject * +GetBlockChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen); + +extern JSObject * +GetScopeChain(JSContext *cx); + +/* + * Refresh and return fp->scopeChain. It may be stale if block scopes are + * active but not yet reflected by objects in the scope chain. If a block + * scope contains a with, eval, XML filtering predicate, or similar such + * dynamically scoped construct, then compile-time block scope at fp->blocks + * must reflect at runtime. + */ +extern JSObject * +GetScopeChain(JSContext *cx, JSStackFrame *fp); + +extern JSObject * +GetScopeChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen); + +/* + * Report an error that the this value passed as |this| in the given arguments + * vector is not compatible with the specified class. + */ +void +ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp); + +/* + * Given a context and a vector of [callee, this, args...] for a function + * whose JSFUN_PRIMITIVE_THIS flag is set, set |*v| to the primitive value + * of |this|. If |this| is an object, insist that it be an instance of the + * appropriate wrapper class for T, and set |*v| to its private slot value. + * If |this| is a primitive, unbox it into |*v| if it's of the required + * type, and throw an error otherwise. + */ +template +bool GetPrimitiveThis(JSContext *cx, Value *vp, T *v); + +inline void +PutActivationObjects(JSContext *cx, JSStackFrame *fp); + +inline void +PutOwnedActivationObjects(JSContext *cx, JSStackFrame *fp); + +/* + * For a call's vp (which necessarily includes callee at vp[0] and the original + * specified |this| at vp[1]), convert null/undefined |this| into the global + * object for the callee and replace other primitives with boxed versions. The + * callee must not be strict mode code. + */ +extern bool +BoxThisForVp(JSContext *cx, js::Value *vp); + +/* + * Abstracts the layout of the stack passed to natives from the engine and from + * natives to js::Invoke. + */ +struct CallArgs +{ + Value *argv_; + uintN argc_; + protected: + CallArgs() {} + CallArgs(Value *argv, uintN argc) : argv_(argv), argc_(argc) {} + public: + Value *base() const { return argv_ - 2; } + Value &callee() const { return argv_[-2]; } + Value &thisv() const { return argv_[-1]; } + Value &operator[](unsigned i) const { JS_ASSERT(i < argc_); return argv_[i]; } + Value *argv() const { return argv_; } + uintN argc() const { return argc_; } + Value &rval() const { return argv_[-2]; } +}; + +/* + * The js::InvokeArgumentsGuard passed to js_Invoke must come from an + * immediately-enclosing successful call to js::StackSpace::pushInvokeArgs, + * i.e., there must have been no un-popped pushes to cx->stack(). Furthermore, + * |args.getvp()[0]| should be the callee, |args.getvp()[1]| should be |this|, + * and the range [args.getvp() + 2, args.getvp() + 2 + args.getArgc()) should + * be initialized actual arguments. + */ +extern JS_REQUIRES_STACK bool +Invoke(JSContext *cx, const CallArgs &args, uint32 flags); + +/* + * Natives like sort/forEach/replace call Invoke repeatedly with the same + * callee, this, and number of arguments. To optimize this, such natives can + * start an "invoke session" to factor out much of the dynamic setup logic + * required by a normal Invoke. Usage is: + * + * InvokeSessionGuard session(cx); + * if (!session.start(cx, callee, thisp, argc, &session)) + * ... + * + * while (...) { + * // write actual args (not callee, this) + * session[0] = ... + * ... + * session[argc - 1] = ... + * + * if (!session.invoke(cx, session)) + * ... + * + * ... = session.rval(); + * } + * + * // session ended by ~InvokeSessionGuard + */ +class InvokeSessionGuard; + +/* + * Consolidated js_Invoke flags simply rename certain JSFRAME_* flags, so that + * we can share bits stored in JSStackFrame.flags and passed to: + * + * js_Invoke + * js_InternalInvoke + * js_ValueToFunction + * js_ValueToFunctionObject + * js_ValueToCallableObject + * js_ReportIsNotFunction + * + * See jsfun.h for the latter four and flag renaming macros. + */ +#define JSINVOKE_CONSTRUCT JSFRAME_CONSTRUCTING + +/* + * Mask to isolate construct and iterator flags for use with jsfun.h functions. + */ +#define JSINVOKE_FUNFLAGS JSINVOKE_CONSTRUCT + +/* + * "External" calls may come from C or C++ code using a JSContext on which no + * JS is running (!cx->fp), so they may need to push a dummy JSStackFrame. + */ + +extern bool +ExternalInvoke(JSContext *cx, const Value &thisv, const Value &fval, + uintN argc, Value *argv, Value *rval); + +extern bool +ExternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, const Value &fval, + JSAccessMode mode, uintN argc, Value *argv, Value *rval); + +/* + * These two functions invoke a function called from a constructor context + * (e.g. 'new'). InvokeConstructor handles the general case where a new object + * needs to be created for/by the constructor. ConstructWithGivenThis directly + * calls the constructor with the given 'this', hence the caller must + * understand the semantics of the constructor call. + */ + +extern JS_REQUIRES_STACK bool +InvokeConstructor(JSContext *cx, const CallArgs &args); + +extern JS_REQUIRES_STACK bool +InvokeConstructorWithGivenThis(JSContext *cx, JSObject *thisobj, const Value &fval, + uintN argc, Value *argv, Value *rval); + +extern bool +ExternalInvokeConstructor(JSContext *cx, const Value &fval, uintN argc, Value *argv, + Value *rval); + +/* + * Performs a direct eval for the given arguments, which must correspond to the + * currently-executing stack frame, which must be a script frame. evalfun must + * be the built-in eval function and must correspond to the callee in vp[0]. + * When this function succeeds it returns the result in *vp, adjusts the JS + * stack pointer, and returns true. + */ +extern JS_REQUIRES_STACK bool +DirectEval(JSContext *cx, JSFunction *evalfun, uint32 argc, Value *vp); + +/* + * Performs a direct eval for the given arguments, which must correspond to the + * currently-executing stack frame, which must be a script frame. evalfun must + * be the built-in eval function and must correspond to the callee in vp[0]. + * When this function succeeds it returns the result in *vp, adjusts the JS + * stack pointer, and returns true. + */ +extern JS_REQUIRES_STACK bool +DirectEval(JSContext *cx, JSFunction *evalfun, uint32 argc, Value *vp); + +/* + * Executes a script with the given scope chain in the context of the given + * frame. + */ +extern JS_FORCES_STACK bool +Execute(JSContext *cx, JSObject *chain, JSScript *script, + JSStackFrame *prev, uintN flags, Value *result); + +/* + * Execute the caller-initialized frame for a user-defined script or function + * pointed to by cx->fp until completion or error. + */ +extern JS_REQUIRES_STACK JS_NEVER_INLINE bool +Interpret(JSContext *cx, JSStackFrame *stopFp, uintN inlineCallCount = 0, JSInterpMode mode = JSINTERP_NORMAL); + +extern JS_REQUIRES_STACK bool +RunScript(JSContext *cx, JSScript *script, JSStackFrame *fp); + +extern bool +CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs); + +extern bool +StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *equal); + +/* === except that NaN is the same as NaN and -0 is not the same as +0. */ +extern bool +SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same); + +extern JSType +TypeOfValue(JSContext *cx, const Value &v); + +inline bool +InstanceOf(JSContext *cx, JSObject *obj, Class *clasp, Value *argv) +{ + if (obj && obj->getClass() == clasp) + return true; + extern bool InstanceOfSlow(JSContext *, JSObject *, Class *, Value *); + return InstanceOfSlow(cx, obj, clasp, argv); +} + +extern JSBool +HasInstance(JSContext *cx, JSObject *obj, const js::Value *v, JSBool *bp); + +inline void * +GetInstancePrivate(JSContext *cx, JSObject *obj, Class *clasp, Value *argv) +{ + if (!InstanceOf(cx, obj, clasp, argv)) + return NULL; + return obj->getPrivate(); +} + +extern bool +ValueToId(JSContext *cx, const Value &v, jsid *idp); + +/* + * @param closureLevel The static level of the closure that the cookie + * pertains to. + * @param cookie Level amount is a "skip" (delta) value from the + * closure level. + * @return The value of the upvar. + */ +extern const js::Value & +GetUpvar(JSContext *cx, uintN level, js::UpvarCookie cookie); + +} /* namespace js */ + +/* + * JS_LONE_INTERPRET indicates that the compiler should see just the code for + * the js_Interpret function when compiling jsinterp.cpp. The rest of the code + * from the file should be visible only when compiling jsinvoke.cpp. It allows + * platform builds to optimize selectively js_Interpret when the granularity + * of the optimizations with the given compiler is a compilation unit. + * + * JS_STATIC_INTERPRET is the modifier for functions defined in jsinterp.cpp + * that only js_Interpret calls. When JS_LONE_INTERPRET is true all such + * functions are declared below. + */ +#ifndef JS_LONE_INTERPRET +# ifdef _MSC_VER +# define JS_LONE_INTERPRET 0 +# else +# define JS_LONE_INTERPRET 1 +# endif +#endif + +#define JS_MAX_INLINE_CALL_COUNT 3000 + +#if !JS_LONE_INTERPRET +# define JS_STATIC_INTERPRET static +#else +# define JS_STATIC_INTERPRET + +extern JS_REQUIRES_STACK JSBool +js_EnterWith(JSContext *cx, jsint stackIndex, JSOp op, size_t oplen); + +extern JS_REQUIRES_STACK void +js_LeaveWith(JSContext *cx); + +/* + * Find the results of incrementing or decrementing *vp. For pre-increments, + * both *vp and *vp2 will contain the result on return. For post-increments, + * vp will contain the original value converted to a number and vp2 will get + * the result. Both vp and vp2 must be roots. + */ +extern JSBool +js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, js::Value *vp, js::Value *vp2); + +/* + * Opcode tracing helper. When len is not 0, cx->fp->regs->pc[-len] gives the + * previous opcode. + */ +extern JS_REQUIRES_STACK void +js_LogOpcode(JSContext *cx); + +/* + * JS_OPMETER helper functions. + */ +extern void +js_MeterOpcodePair(JSOp op1, JSOp op2); + +extern void +js_MeterSlotOpcode(JSOp op, uint32 slot); + +#endif /* JS_LONE_INTERPRET */ +/* + * Unwind block and scope chains to match the given depth. The function sets + * fp->sp on return to stackDepth. + */ +extern JS_REQUIRES_STACK JSBool +js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind); + +extern JSBool +js_OnUnknownMethod(JSContext *cx, js::Value *vp); + +extern JS_REQUIRES_STACK js::Class * +js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth); + +#endif /* jsinterp_h___ */ diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h new file mode 100644 index 0000000..6efb854 --- /dev/null +++ b/js/src/jsinterpinlines.h @@ -0,0 +1,850 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Luke Wagner + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsinterpinlines_h__ +#define jsinterpinlines_h__ + +#include "jsapi.h" +#include "jsbool.h" +#include "jsinterp.h" +#include "jsnum.h" +#include "jsprobes.h" +#include "jsstr.h" +#include "methodjit/MethodJIT.h" + +#include "jsfuninlines.h" + +inline void +JSStackFrame::initPrev(JSContext *cx) +{ + JS_ASSERT(flags_ & JSFRAME_HAS_PREVPC); + if (JSFrameRegs *regs = cx->regs) { + prev_ = regs->fp; + prevpc_ = regs->pc; + JS_ASSERT_IF(!prev_->isDummyFrame() && !prev_->hasImacropc(), + uint32(prevpc_ - prev_->script()->code) < prev_->script()->length); + } else { + prev_ = NULL; +#ifdef DEBUG + prevpc_ = (jsbytecode *)0xbadc; +#endif + } +} + +inline void +JSStackFrame::resetGeneratorPrev(JSContext *cx) +{ + flags_ |= JSFRAME_HAS_PREVPC; + initPrev(cx); +} + +inline void +JSStackFrame::initCallFrame(JSContext *cx, JSObject &callee, JSFunction *fun, + uint32 nactual, uint32 flagsArg) +{ + JS_ASSERT((flagsArg & ~(JSFRAME_CONSTRUCTING | + JSFRAME_OVERFLOW_ARGS | + JSFRAME_UNDERFLOW_ARGS)) == 0); + JS_ASSERT(fun == callee.getFunctionPrivate()); + + /* Initialize stack frame members. */ + flags_ = JSFRAME_FUNCTION | JSFRAME_HAS_PREVPC | JSFRAME_HAS_SCOPECHAIN | flagsArg; + exec.fun = fun; + args.nactual = nactual; /* only need to write if over/under-flow */ + scopeChain_ = callee.getParent(); + initPrev(cx); + JS_ASSERT(!hasImacropc()); + JS_ASSERT(!hasHookData()); + JS_ASSERT(annotation() == NULL); + + JS_ASSERT(!hasCallObj()); +} + +inline void +JSStackFrame::resetInvokeCallFrame() +{ + /* Undo changes to frame made during execution; see initCallFrame */ + + JS_ASSERT(!(flags_ & ~(JSFRAME_FUNCTION | + JSFRAME_OVERFLOW_ARGS | + JSFRAME_UNDERFLOW_ARGS | + JSFRAME_OVERRIDE_ARGS | + JSFRAME_HAS_PREVPC | + JSFRAME_HAS_RVAL | + JSFRAME_HAS_SCOPECHAIN | + JSFRAME_HAS_ANNOTATION | + JSFRAME_FINISHED_IN_INTERPRETER))); + flags_ &= JSFRAME_FUNCTION | + JSFRAME_OVERFLOW_ARGS | + JSFRAME_HAS_PREVPC | + JSFRAME_UNDERFLOW_ARGS; + + JS_ASSERT(exec.fun == callee().getFunctionPrivate()); + scopeChain_ = callee().getParent(); +} + +inline void +JSStackFrame::initCallFrameCallerHalf(JSContext *cx, uint32 flagsArg, + void *ncode) +{ + JS_ASSERT((flagsArg & ~(JSFRAME_CONSTRUCTING | + JSFRAME_FUNCTION | + JSFRAME_OVERFLOW_ARGS | + JSFRAME_UNDERFLOW_ARGS)) == 0); + + flags_ = JSFRAME_FUNCTION | flagsArg; + prev_ = cx->regs->fp; + ncode_ = ncode; +} + +/* + * The "early prologue" refers to the members that are stored for the benefit + * of slow paths before initializing the rest of the members. + */ +inline void +JSStackFrame::initCallFrameEarlyPrologue(JSFunction *fun, uint32 nactual) +{ + exec.fun = fun; + if (flags_ & (JSFRAME_OVERFLOW_ARGS | JSFRAME_UNDERFLOW_ARGS)) + args.nactual = nactual; +} + +/* + * The "late prologue" refers to the members that are stored after having + * checked for stack overflow and formal/actual arg mismatch. + */ +inline void +JSStackFrame::initCallFrameLatePrologue() +{ + SetValueRangeToUndefined(slots(), script()->nfixed); +} + +inline void +JSStackFrame::initEvalFrame(JSContext *cx, JSScript *script, JSStackFrame *prev, uint32 flagsArg) +{ + JS_ASSERT(flagsArg & JSFRAME_EVAL); + JS_ASSERT((flagsArg & ~(JSFRAME_EVAL | JSFRAME_DEBUGGER)) == 0); + JS_ASSERT(prev->flags_ & (JSFRAME_FUNCTION | JSFRAME_GLOBAL)); + + /* Copy (callee, thisv). */ + js::Value *dstvp = (js::Value *)this - 2; + js::Value *srcvp = prev->flags_ & (JSFRAME_GLOBAL | JSFRAME_EVAL) + ? (js::Value *)prev - 2 + : prev->formalArgs() - 2; + dstvp[0] = srcvp[0]; + dstvp[1] = srcvp[1]; + JS_ASSERT_IF(prev->flags_ & JSFRAME_FUNCTION, + dstvp[0].toObject().isFunction()); + + /* Initialize stack frame members. */ + flags_ = flagsArg | JSFRAME_HAS_PREVPC | JSFRAME_HAS_SCOPECHAIN | + (prev->flags_ & (JSFRAME_FUNCTION | JSFRAME_GLOBAL | JSFRAME_HAS_CALL_OBJ)); + if (isFunctionFrame()) { + exec = prev->exec; + args.script = script; + } else { + exec.script = script; + } + + scopeChain_ = &prev->scopeChain(); + JS_ASSERT_IF(isFunctionFrame(), &callObj() == &prev->callObj()); + + prev_ = prev; + prevpc_ = prev->pc(cx); + JS_ASSERT(!hasImacropc()); + JS_ASSERT(!hasHookData()); + setAnnotation(prev->annotation()); +} + +inline void +JSStackFrame::initGlobalFrame(JSScript *script, JSObject &chain, uint32 flagsArg) +{ + JS_ASSERT((flagsArg & ~(JSFRAME_EVAL | JSFRAME_DEBUGGER)) == 0); + + /* Initialize (callee, thisv). */ + js::Value *vp = (js::Value *)this - 2; + vp[0].setUndefined(); + vp[1].setUndefined(); /* Set after frame pushed using thisObject */ + + /* Initialize stack frame members. */ + flags_ = flagsArg | JSFRAME_GLOBAL | JSFRAME_HAS_PREVPC | JSFRAME_HAS_SCOPECHAIN; + exec.script = script; + args.script = (JSScript *)0xbad; + scopeChain_ = &chain; + prev_ = NULL; + JS_ASSERT(!hasImacropc()); + JS_ASSERT(!hasHookData()); + JS_ASSERT(annotation() == NULL); +} + +inline void +JSStackFrame::initDummyFrame(JSContext *cx, JSObject &chain) +{ + js::PodZero(this); + flags_ = JSFRAME_DUMMY | JSFRAME_HAS_PREVPC | JSFRAME_HAS_SCOPECHAIN; + initPrev(cx); + chain.isGlobal(); + setScopeChainNoCallObj(chain); +} + +inline void +JSStackFrame::stealFrameAndSlots(js::Value *vp, JSStackFrame *otherfp, + js::Value *othervp, js::Value *othersp) +{ + JS_ASSERT(vp == (js::Value *)this - (otherfp->formalArgsEnd() - othervp)); + JS_ASSERT(othervp == otherfp->actualArgs() - 2); + JS_ASSERT(othersp >= otherfp->slots()); + JS_ASSERT(othersp <= otherfp->base() + otherfp->numSlots()); + + PodCopy(vp, othervp, othersp - othervp); + JS_ASSERT(vp == this->actualArgs() - 2); + + /* Catch bad-touching of non-canonical args (e.g., generator_trace). */ + if (otherfp->hasOverflowArgs()) + Debug_SetValueRangeToCrashOnTouch(othervp, othervp + 2 + otherfp->numFormalArgs()); + + /* + * Repoint Call, Arguments, Block and With objects to the new live frame. + * Call and Arguments are done directly because we have pointers to them. + * Block and With objects are done indirectly through 'liveFrame'. See + * js_LiveFrameToFloating comment in jsiter.h. + */ + if (hasCallObj()) { + callObj().setPrivate(this); + otherfp->flags_ &= ~JSFRAME_HAS_CALL_OBJ; + if (js_IsNamedLambda(fun())) { + JSObject *env = callObj().getParent(); + JS_ASSERT(env->getClass() == &js_DeclEnvClass); + env->setPrivate(this); + } + } + if (hasArgsObj()) { + JSObject &args = argsObj(); + JS_ASSERT(args.isArguments()); + if (args.isNormalArguments()) + args.setPrivate(this); + else + JS_ASSERT(!args.getPrivate()); + otherfp->flags_ &= ~JSFRAME_HAS_ARGS_OBJ; + } +} + +inline js::Value & +JSStackFrame::canonicalActualArg(uintN i) const +{ + if (i < numFormalArgs()) + return formalArg(i); + JS_ASSERT(i < numActualArgs()); + return actualArgs()[i]; +} + +template +inline void +JSStackFrame::forEachCanonicalActualArg(Op op) +{ + uintN nformal = fun()->nargs; + js::Value *formals = formalArgsEnd() - nformal; + uintN nactual = numActualArgs(); + if (nactual <= nformal) { + uintN i = 0; + js::Value *actualsEnd = formals + nactual; + for (js::Value *p = formals; p != actualsEnd; ++p, ++i) + op(i, p); + } else { + uintN i = 0; + js::Value *formalsEnd = formalArgsEnd(); + for (js::Value *p = formals; p != formalsEnd; ++p, ++i) + op(i, p); + js::Value *actuals = formalsEnd - (nactual + 2); + js::Value *actualsEnd = formals - 2; + for (js::Value *p = actuals; p != actualsEnd; ++p, ++i) + op(i, p); + } +} + +template +inline void +JSStackFrame::forEachFormalArg(Op op) +{ + js::Value *formals = formalArgsEnd() - fun()->nargs; + js::Value *formalsEnd = formalArgsEnd(); + uintN i = 0; + for (js::Value *p = formals; p != formalsEnd; ++p, ++i) + op(i, p); +} + +namespace js { + +struct STATIC_SKIP_INFERENCE CopyNonHoleArgsTo +{ + CopyNonHoleArgsTo(JSObject *aobj, Value *dst) : aobj(aobj), dst(dst) {} + JSObject *aobj; + Value *dst; + void operator()(uintN argi, Value *src) { + if (aobj->getArgsElement(argi).isMagic(JS_ARGS_HOLE)) + dst->setUndefined(); + else + *dst = *src; + ++dst; + } +}; + +struct CopyTo +{ + Value *dst; + CopyTo(Value *dst) : dst(dst) {} + void operator()(uintN, Value *src) { + *dst++ = *src; + } +}; + +} + +JS_ALWAYS_INLINE void +JSStackFrame::clearMissingArgs() +{ + if (flags_ & JSFRAME_UNDERFLOW_ARGS) + SetValueRangeToUndefined(formalArgs() + numActualArgs(), formalArgsEnd()); +} + +inline bool +JSStackFrame::computeThis(JSContext *cx) +{ + js::Value &thisv = thisValue(); + if (thisv.isObject()) + return true; + if (isFunctionFrame()) { + if (fun()->inStrictMode()) + return true; + /* + * Eval function frames have their own |this| slot, which is a copy of the function's + * |this| slot. If we lazily wrap a primitive |this| in an eval function frame, the + * eval's frame will get the wrapper, but the function's frame will not. To prevent + * this, we always wrap a function's |this| before pushing an eval frame, and should + * thus never see an unwrapped primitive in a non-strict eval function frame. + */ + JS_ASSERT(!isEvalFrame()); + } + if (!js::BoxThisForVp(cx, &thisv - 1)) + return false; + return true; +} + +inline JSObject & +JSStackFrame::varobj(js::StackSegment *seg) const +{ + JS_ASSERT(seg->contains(this)); + return isFunctionFrame() ? callObj() : seg->getInitialVarObj(); +} + +inline JSObject & +JSStackFrame::varobj(JSContext *cx) const +{ + JS_ASSERT(cx->activeSegment()->contains(this)); + return isFunctionFrame() ? callObj() : cx->activeSegment()->getInitialVarObj(); +} + +inline uintN +JSStackFrame::numActualArgs() const +{ + JS_ASSERT(hasArgs()); + if (JS_UNLIKELY(flags_ & (JSFRAME_OVERFLOW_ARGS | JSFRAME_UNDERFLOW_ARGS))) + return hasArgsObj() ? argsObj().getArgsInitialLength() : args.nactual; + return numFormalArgs(); +} + +inline js::Value * +JSStackFrame::actualArgs() const +{ + JS_ASSERT(hasArgs()); + js::Value *argv = formalArgs(); + if (JS_UNLIKELY(flags_ & JSFRAME_OVERFLOW_ARGS)) { + uintN nactual = hasArgsObj() ? argsObj().getArgsInitialLength() : args.nactual; + return argv - (2 + nactual); + } + return argv; +} + +inline js::Value * +JSStackFrame::actualArgsEnd() const +{ + JS_ASSERT(hasArgs()); + if (JS_UNLIKELY(flags_ & JSFRAME_OVERFLOW_ARGS)) + return formalArgs() - 2; + return formalArgs() + numActualArgs(); +} + +inline void +JSStackFrame::setArgsObj(JSObject &obj) +{ + JS_ASSERT_IF(hasArgsObj(), &obj == args.obj); + JS_ASSERT_IF(!hasArgsObj(), numActualArgs() == obj.getArgsInitialLength()); + args.obj = &obj; + flags_ |= JSFRAME_HAS_ARGS_OBJ; +} + +inline void +JSStackFrame::clearArgsObj() +{ + JS_ASSERT(hasArgsObj()); + args.nactual = args.obj->getArgsInitialLength(); + flags_ ^= JSFRAME_HAS_ARGS_OBJ; +} + +inline void +JSStackFrame::setScopeChainNoCallObj(JSObject &obj) +{ +#ifdef DEBUG + JS_ASSERT(&obj != NULL); + JSObject *callObjBefore = maybeCallObj(); + if (!hasCallObj() && &scopeChain() != sInvalidScopeChain) { + for (JSObject *pobj = &scopeChain(); pobj; pobj = pobj->getParent()) + JS_ASSERT_IF(pobj->isCall(), pobj->getPrivate() != this); + } +#endif + scopeChain_ = &obj; + flags_ |= JSFRAME_HAS_SCOPECHAIN; + JS_ASSERT(callObjBefore == maybeCallObj()); +} + +inline void +JSStackFrame::setScopeChainAndCallObj(JSObject &obj) +{ + JS_ASSERT(&obj != NULL); + JS_ASSERT(!hasCallObj() && obj.isCall() && obj.getPrivate() == this); + scopeChain_ = &obj; + flags_ |= JSFRAME_HAS_SCOPECHAIN | JSFRAME_HAS_CALL_OBJ; +} + +inline void +JSStackFrame::clearCallObj() +{ + JS_ASSERT(hasCallObj()); + flags_ ^= JSFRAME_HAS_CALL_OBJ; +} + +inline JSObject & +JSStackFrame::callObj() const +{ + JS_ASSERT(hasCallObj()); + JSObject *pobj = &scopeChain(); + while (JS_UNLIKELY(pobj->getClass() != &js_CallClass)) { + JS_ASSERT(js::IsCacheableNonGlobalScope(pobj) || pobj->isWith()); + pobj = pobj->getParent(); + } + return *pobj; +} + +inline JSObject * +JSStackFrame::maybeCallObj() const +{ + return hasCallObj() ? &callObj() : NULL; +} + +namespace js { + +class AutoPreserveEnumerators { + JSContext *cx; + JSObject *enumerators; + + public: + AutoPreserveEnumerators(JSContext *cx) : cx(cx), enumerators(cx->enumerators) + { + } + + ~AutoPreserveEnumerators() + { + cx->enumerators = enumerators; + } +}; + +struct AutoInterpPreparer { + JSContext *cx; + JSScript *script; + + AutoInterpPreparer(JSContext *cx, JSScript *script) + : cx(cx), script(script) + { + cx->interpLevel++; + } + + ~AutoInterpPreparer() + { + --cx->interpLevel; + } +}; + +inline void +PutActivationObjects(JSContext *cx, JSStackFrame *fp) +{ + JS_ASSERT(!fp->isYielding()); + JS_ASSERT(!fp->isEvalFrame() || fp->script()->strictModeCode); + + /* The order is important as js_PutCallObject needs to access argsObj. */ + if (fp->hasCallObj()) { + js_PutCallObject(cx, fp); + } else if (fp->hasArgsObj()) { + js_PutArgsObject(cx, fp); + } +} + +/* + * FIXME Remove with bug 635811 + * + * NB: a non-strict eval frame aliases its non-eval-parent's call/args object. + */ +inline void +PutOwnedActivationObjects(JSContext *cx, JSStackFrame *fp) +{ + JS_ASSERT(!fp->isYielding()); + if (!fp->isEvalFrame() || fp->script()->strictModeCode) + PutActivationObjects(cx, fp); +} + +class InvokeSessionGuard +{ + InvokeArgsGuard args_; + InvokeFrameGuard frame_; + Value savedCallee_, savedThis_; + Value *formals_, *actuals_; + unsigned nformals_; + JSScript *script_; + Value *stackLimit_; + jsbytecode *stop_; + + bool optimized() const { return frame_.pushed(); } + + public: + InvokeSessionGuard() : args_(), frame_() {} + inline ~InvokeSessionGuard(); + + bool start(JSContext *cx, const Value &callee, const Value &thisv, uintN argc); + bool invoke(JSContext *cx) const; + + bool started() const { + return args_.pushed(); + } + + Value &operator[](unsigned i) const { + JS_ASSERT(i < argc()); + Value &arg = i < nformals_ ? formals_[i] : actuals_[i]; + JS_ASSERT_IF(optimized(), &arg == &frame_.fp()->canonicalActualArg(i)); + JS_ASSERT_IF(!optimized(), &arg == &args_[i]); + return arg; + } + + uintN argc() const { + return args_.argc(); + } + + const Value &rval() const { + return optimized() ? frame_.fp()->returnValue() : args_.rval(); + } +}; + +inline +InvokeSessionGuard::~InvokeSessionGuard() +{ + if (frame_.pushed()) + PutActivationObjects(frame_.pushedFrameContext(), frame_.fp()); +} + +inline bool +InvokeSessionGuard::invoke(JSContext *cx) const +{ + /* N.B. Must be kept in sync with Invoke */ + + /* Refer to canonical (callee, this) for optimized() sessions. */ + formals_[-2] = savedCallee_; + formals_[-1] = savedThis_; + +#ifdef JS_METHODJIT + void *code; + if (!optimized() || !(code = script_->getJIT(false /* !constructing */)->invokeEntry)) +#else + if (!optimized()) +#endif + return Invoke(cx, args_, 0); + + /* Clear any garbage left from the last Invoke. */ + JSStackFrame *fp = frame_.fp(); + fp->clearMissingArgs(); + PutActivationObjects(cx, frame_.fp()); + fp->resetInvokeCallFrame(); + SetValueRangeToUndefined(fp->slots(), script_->nfixed); + + JSBool ok; + { + AutoPreserveEnumerators preserve(cx); + Probes::enterJSFun(cx, fp->fun(), script_); +#ifdef JS_METHODJIT + AutoInterpPreparer prepareInterp(cx, script_); + ok = mjit::EnterMethodJIT(cx, fp, code, stackLimit_); + cx->regs->pc = stop_; +#else + cx->regs->pc = script_->code; + ok = Interpret(cx, cx->fp()); +#endif + Probes::exitJSFun(cx, fp->fun(), script_); + } + + /* Don't clobber callee with rval; rval gets read from fp->rval. */ + return ok; +} + +namespace detail { + +template class PrimitiveBehavior { }; + +template<> +class PrimitiveBehavior { + public: + static inline bool isType(const Value &v) { return v.isString(); } + static inline JSString *extract(const Value &v) { return v.toString(); } + static inline Class *getClass() { return &js_StringClass; } +}; + +template<> +class PrimitiveBehavior { + public: + static inline bool isType(const Value &v) { return v.isBoolean(); } + static inline bool extract(const Value &v) { return v.toBoolean(); } + static inline Class *getClass() { return &js_BooleanClass; } +}; + +template<> +class PrimitiveBehavior { + public: + static inline bool isType(const Value &v) { return v.isNumber(); } + static inline double extract(const Value &v) { return v.toNumber(); } + static inline Class *getClass() { return &js_NumberClass; } +}; + +} // namespace detail + +/* + * Compute the implicit |this| parameter for a call expression where the callee + * is an unqualified name reference. + * + * We can avoid computing |this| eagerly and push the implicit callee-coerced + * |this| value, undefined, according to this decision tree: + * + * 1. If the called value, funval, is not an object, bind |this| to undefined. + * + * 2. The nominal |this|, obj, has one of Block, Call, or DeclEnv class (this + * is what IsCacheableNonGlobalScope tests). Such objects-as-scopes must be + * censored. + * + * 3. obj is a global. There are several sub-cases: + * + * a) obj is a proxy: we try unwrapping it (see jswrapper.cpp) in order to find + * a function object inside. If the proxy is not a wrapper, or else it wraps + * a non-function, then bind |this| to undefined per ES5-strict/Harmony. + * + * [Else fall through with callee pointing to an unwrapped function object.] + * + * b) If callee is a function (after unwrapping if necessary), check whether it + * is interpreted and in strict mode. If so, then bind |this| to undefined + * per ES5 strict. + * + * c) Now check that callee is scoped by the same global object as the object + * in which its unqualified name was bound as a property. ES1-3 bound |this| + * to the name's "Reference base object", which in the context of multiple + * global objects may not be the callee's global. If globals match, bind + * |this| to undefined. + * + * This is a backward compatibility measure; see bug 634590. + * + * 4. Finally, obj is neither a declarative scope object to be censored, nor a + * global where the callee requires no backward-compatible special handling + * or future-proofing based on (explicit or imputed by Harmony status in the + * proxy case) strict mode opt-in. Bind |this| to obj->thisObject(). + * + * We set *vp to undefined early to reduce code size and bias this code for the + * common and future-friendly cases. + */ +inline bool +ComputeImplicitThis(JSContext *cx, JSObject *obj, const Value &funval, Value *vp) +{ + vp->setUndefined(); + + if (!funval.isObject()) + return true; + + if (!obj->isGlobal()) { + if (IsCacheableNonGlobalScope(obj)) + return true; + } else { + JSObject *callee = &funval.toObject(); + + if (callee->isProxy()) { + callee = callee->unwrap(); + if (!callee->isFunction()) + return true; // treat any non-wrapped-function proxy as strict + } + if (callee->isFunction()) { + JSFunction *fun = callee->getFunctionPrivate(); + if (fun->isInterpreted() && fun->inStrictMode()) + return true; + } + if (callee->getGlobal() == cx->fp()->scopeChain().getGlobal()) + return true;; + } + + obj = obj->thisObject(cx); + if (!obj) + return false; + + vp->setObject(*obj); + return true; +} + +template +bool +GetPrimitiveThis(JSContext *cx, Value *vp, T *v) +{ + typedef detail::PrimitiveBehavior Behavior; + + const Value &thisv = vp[1]; + if (Behavior::isType(thisv)) { + *v = Behavior::extract(thisv); + return true; + } + + if (thisv.isObject() && thisv.toObject().getClass() == Behavior::getClass()) { + *v = Behavior::extract(thisv.toObject().getPrimitiveThis()); + return true; + } + + ReportIncompatibleMethod(cx, vp, Behavior::getClass()); + return false; +} + +/* + * Return an object on which we should look for the properties of |value|. + * This helps us implement the custom [[Get]] method that ES5's GetValue + * algorithm uses for primitive values, without actually constructing the + * temporary object that the specification does. + * + * For objects, return the object itself. For string, boolean, and number + * primitive values, return the appropriate constructor's prototype. For + * undefined and null, throw an error and return NULL, attributing the + * problem to the value at |spindex| on the stack. + */ +JS_ALWAYS_INLINE JSObject * +ValuePropertyBearer(JSContext *cx, const Value &v, int spindex) +{ + if (v.isObject()) + return &v.toObject(); + + JSProtoKey protoKey; + if (v.isString()) { + protoKey = JSProto_String; + } else if (v.isNumber()) { + protoKey = JSProto_Number; + } else if (v.isBoolean()) { + protoKey = JSProto_Boolean; + } else { + JS_ASSERT(v.isNull() || v.isUndefined()); + js_ReportIsNullOrUndefined(cx, spindex, v, NULL); + return NULL; + } + + JSObject *pobj; + if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj)) + return NULL; + return pobj; +} + +static inline bool +ScriptEpilogue(JSContext *cx, JSStackFrame *fp, JSBool ok) +{ + if (!fp->isExecuteFrame()) + Probes::exitJSFun(cx, fp->maybeFun(), fp->maybeScript()); + + JSInterpreterHook hook = + fp->isExecuteFrame() ? cx->debugHooks->executeHook : cx->debugHooks->callHook; + + void* hookData; + if (JS_UNLIKELY(hook != NULL) && (hookData = fp->maybeHookData())) + hook(cx, fp, JS_FALSE, &ok, hookData); + + if (fp->isEvalFrame()) { + /* + * The parent (ancestor for nested eval) of a non-strict eval frame + * owns its activation objects. Strict mode eval frames own their own + * Call objects but never have an arguments object (the first non-eval + * parent frame has it). + */ + if (fp->script()->strictModeCode) { + JS_ASSERT(!fp->isYielding()); + JS_ASSERT(!fp->hasArgsObj()); + JS_ASSERT(fp->hasCallObj()); + JS_ASSERT(fp->callObj().callIsForEval()); + js_PutCallObject(cx, fp); + } + } else { + /* + * Otherwise only function frames have activation objects. A yielding + * frame's activation objects are transferred to the floating frame, + * stored in the generator, and thus need not be synced. + */ + if (fp->isFunctionFrame() && !fp->isYielding()) { + JS_ASSERT_IF(fp->hasCallObj(), !fp->callObj().callIsForEval()); + PutActivationObjects(cx, fp); + } + } + + /* + * If inline-constructing, replace primitive rval with the new object + * passed in via |this|, and instrument this constructor invocation. + */ + if (fp->isConstructing() && ok) { + if (fp->returnValue().isPrimitive()) + fp->setReturnValue(ObjectValue(fp->constructorThis())); + JS_RUNTIME_METER(cx->runtime, constructs); + } + + return ok; +} + +} + +#endif /* jsinterpinlines_h__ */ diff --git a/js/src/jsinttypes.h b/js/src/jsinttypes.h new file mode 100644 index 0000000..5f90eaa --- /dev/null +++ b/js/src/jsinttypes.h @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Jim Blandy + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsinttypes_h___ +#define jsinttypes_h___ + +#include "js-config.h" + +/* + * Types: + * JSInt, JSUint (for = 8, 16, 32, and 64) + * JSIntPtr, JSUIntPtr + * + * JSInt and JSUint are signed and unsigned types known to be + * bits long. Note that neither JSInt8 nor JSUInt8 is necessarily + * equivalent to a plain "char". + * + * JSIntPtr and JSUintPtr are signed and unsigned types capable of + * holding an object pointer. + * + * Use these types in public SpiderMonkey header files, not the + * corresponding types from the C standard header. Windows + * doesn't support , and Microsoft says it has no plans to + * do so in the future; this means that projects that embed + * SpiderMonkey often take matters into their own hands and define the + * standard types themselves. If we define them in our public + * headers, our definitions may conflict with embedders' (see bug + * 479258). The JS* types are in our namespace, and can be used + * without troubling anyone. + * + * Internal SpiderMonkey code wishing to use the type names ISO C + * defines in the standard header can #include + * "jsstdint.h", which provides those types regardless of whether + * itself is available. + */ + +#if defined(JS_HAVE_STDINT_H) || \ + defined(JS_SYS_TYPES_H_DEFINES_EXACT_SIZE_TYPES) + +#if defined(JS_HAVE_STDINT_H) +#include +#else +#include +#endif + +typedef int8_t JSInt8; +typedef int16_t JSInt16; +typedef int32_t JSInt32; +typedef int64_t JSInt64; +typedef intptr_t JSIntPtr; + +typedef uint8_t JSUint8; +typedef uint16_t JSUint16; +typedef uint32_t JSUint32; +typedef uint64_t JSUint64; +typedef uintptr_t JSUintPtr; + +#else + +#if defined(JS_HAVE___INTN) + +typedef __int8 JSInt8; +typedef __int16 JSInt16; +typedef __int32 JSInt32; +typedef __int64 JSInt64; + +typedef unsigned __int8 JSUint8; +typedef unsigned __int16 JSUint16; +typedef unsigned __int32 JSUint32; +typedef unsigned __int64 JSUint64; + +#elif defined(JS_INT8_TYPE) + +typedef signed JS_INT8_TYPE JSInt8; +typedef signed JS_INT16_TYPE JSInt16; +typedef signed JS_INT32_TYPE JSInt32; +typedef signed JS_INT64_TYPE JSInt64; + +typedef unsigned JS_INT8_TYPE JSUint8; +typedef unsigned JS_INT16_TYPE JSUint16; +typedef unsigned JS_INT32_TYPE JSUint32; +typedef unsigned JS_INT64_TYPE JSUint64; + +#else +#error "couldn't find exact-width integer types" +#endif + +/* Microsoft Visual C/C++ defines intptr_t and uintptr_t in . */ +#if defined(JS_STDDEF_H_HAS_INTPTR_T) +#include +typedef intptr_t JSIntPtr; +typedef uintptr_t JSUintPtr; + +/* Windows Mobile defines intptr_t and uintptr_t in . Why not? */ +#elif defined(JS_CRTDEFS_H_HAS_INTPTR_T) +#include +typedef intptr_t JSIntPtr; +typedef uintptr_t JSUintPtr; + +/* Failing that, the configure script will have found something. */ +#elif defined(JS_INTPTR_TYPE) +typedef signed JS_INTPTR_TYPE JSIntPtr; +typedef unsigned JS_INTPTR_TYPE JSUintPtr; + +#else +#error "couldn't find pointer-sized integer types" +#endif + +#endif /* JS_HAVE_STDINT_H */ + +#endif /* jsinttypes_h___ */ diff --git a/js/src/jsinvoke.cpp b/js/src/jsinvoke.cpp new file mode 100644 index 0000000..5857e41 --- /dev/null +++ b/js/src/jsinvoke.cpp @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.8 code, released + * March 4, 2008. + * + * The Initial Developer of the Original Code is + * Igor Bukanov + * + * Contributor(s): + * Brendan Eich /* for memcpy */ +#include "jstypes.h" +#include "jsstdint.h" +#include "jsutil.h" +#include "jsarena.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsexn.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jshashtable.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsproxy.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstaticcheck.h" +#include "jstracer.h" +#include "jsvector.h" + +#if JS_HAS_XML_SUPPORT +#include "jsxml.h" +#endif + +#include "jscntxtinlines.h" +#include "jsinterpinlines.h" +#include "jsobjinlines.h" +#include "jsstrinlines.h" + +using namespace js; +using namespace js::gc; + +static void iterator_finalize(JSContext *cx, JSObject *obj); +static void iterator_trace(JSTracer *trc, JSObject *obj); +static JSObject *iterator_iterator(JSContext *cx, JSObject *obj, JSBool keysonly); + +Class js_IteratorClass = { + "Iterator", + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) | + JSCLASS_MARK_IS_TRACE, + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub, + iterator_finalize, + NULL, /* reserved */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + JS_CLASS_TRACE(iterator_trace), + { + NULL, /* equality */ + NULL, /* outerObject */ + NULL, /* innerObject */ + iterator_iterator, + NULL /* unused */ + } +}; + +void +NativeIterator::mark(JSTracer *trc) +{ + MarkIdRange(trc, begin(), end(), "props"); + if (obj) + MarkObject(trc, *obj, "obj"); +} + +static void +iterator_finalize(JSContext *cx, JSObject *obj) +{ + JS_ASSERT(obj->getClass() == &js_IteratorClass); + + NativeIterator *ni = obj->getNativeIterator(); + if (ni) { + cx->free(ni); + obj->setNativeIterator(NULL); + } +} + +static void +iterator_trace(JSTracer *trc, JSObject *obj) +{ + NativeIterator *ni = obj->getNativeIterator(); + + if (ni) + ni->mark(trc); +} + +struct IdHashPolicy { + typedef jsid Lookup; + static HashNumber hash(jsid id) { + return JSID_BITS(id); + } + static bool match(jsid id1, jsid id2) { + return id1 == id2; + } +}; + +typedef HashSet IdSet; + +static inline bool +NewKeyValuePair(JSContext *cx, jsid id, const Value &val, Value *rval) +{ + Value vec[2] = { IdToValue(id), val }; + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec); + + JSObject *aobj = NewDenseCopiedArray(cx, 2, vec); + if (!aobj) + return false; + rval->setObject(*aobj); + return true; +} + +static inline bool +Enumerate(JSContext *cx, JSObject *obj, JSObject *pobj, jsid id, + bool enumerable, bool sharedPermanent, uintN flags, IdSet& ht, + AutoIdVector *props) +{ + IdSet::AddPtr p = ht.lookupForAdd(id); + JS_ASSERT_IF(obj == pobj && !obj->isProxy(), !p); + + /* If we've already seen this, we definitely won't add it. */ + if (JS_UNLIKELY(!!p)) + return true; + + /* + * It's not necessary to add properties to the hash table at the end of the + * prototype chain -- but a proxy might return duplicated properties, so + * always add for them. + */ + if ((pobj->getProto() || pobj->isProxy()) && !ht.add(p, id)) + return false; + + if (JS_UNLIKELY(flags & JSITER_OWNONLY)) { + /* + * Shared-permanent hack: If this property is shared permanent + * and pobj and obj have the same class, then treat it as an own + * property of obj, even if pobj != obj. (But see bug 575997.) + * + * Omit the magic __proto__ property so that JS code can use + * Object.getOwnPropertyNames without worrying about it. + */ + if (!pobj->getProto() && id == ATOM_TO_JSID(cx->runtime->atomState.protoAtom)) + return true; + if (pobj != obj && !(sharedPermanent && pobj->getClass() == obj->getClass())) + return true; + } + + if (enumerable || (flags & JSITER_HIDDEN)) + return props->append(id); + + return true; +} + +static bool +EnumerateNativeProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uintN flags, IdSet &ht, + AutoIdVector *props) +{ + size_t initialLength = props->length(); + + /* Collect all unique properties from this object's scope. */ + for (Shape::Range r = pobj->lastProperty()->all(); !r.empty(); r.popFront()) { + const Shape &shape = r.front(); + + if (!JSID_IS_DEFAULT_XML_NAMESPACE(shape.id) && + !shape.isAlias() && + !Enumerate(cx, obj, pobj, shape.id, shape.enumerable(), + shape.isSharedPermanent(), flags, ht, props)) + { + return false; + } + } + + Reverse(props->begin() + initialLength, props->end()); + return true; +} + +static bool +EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uintN flags, + IdSet &ht, AutoIdVector *props) +{ + if (!Enumerate(cx, obj, pobj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), false, true, + flags, ht, props)) { + return false; + } + + if (pobj->getArrayLength() > 0) { + size_t capacity = pobj->getDenseArrayCapacity(); + Value *vp = pobj->getDenseArrayElements(); + for (size_t i = 0; i < capacity; ++i, ++vp) { + if (!vp->isMagic(JS_ARRAY_HOLE)) { + /* Dense arrays never get so large that i would not fit into an integer id. */ + if (!Enumerate(cx, obj, pobj, INT_TO_JSID(i), true, false, flags, ht, props)) + return false; + } + } + } + + return true; +} + +static bool +Snapshot(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector *props) +{ + /* + * FIXME: Bug 575997 - We won't need to initialize this hash table if + * (flags & JSITER_OWNONLY) when we eliminate inheritance of + * shared-permanent properties as own properties. + */ + IdSet ht(cx); + if (!ht.init(32)) + return NULL; + + JSObject *pobj = obj; + do { + Class *clasp = pobj->getClass(); + if (pobj->isNative() && + !pobj->getOps()->enumerate && + !(clasp->flags & JSCLASS_NEW_ENUMERATE)) { + if (!clasp->enumerate(cx, pobj)) + return false; + if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props)) + return false; + } else if (pobj->isDenseArray()) { + if (!EnumerateDenseArrayProperties(cx, obj, pobj, flags, ht, props)) + return false; + } else { + if (pobj->isProxy()) { + AutoIdVector proxyProps(cx); + if (flags & JSITER_OWNONLY) { + if (flags & JSITER_HIDDEN) { + if (!JSProxy::getOwnPropertyNames(cx, pobj, proxyProps)) + return false; + } else { + if (!JSProxy::keys(cx, pobj, proxyProps)) + return false; + } + } else { + if (!JSProxy::enumerate(cx, pobj, proxyProps)) + return false; + } + for (size_t n = 0, len = proxyProps.length(); n < len; n++) { + if (!Enumerate(cx, obj, pobj, proxyProps[n], true, false, flags, ht, props)) + return false; + } + /* Proxy objects enumerate the prototype on their own, so we are done here. */ + break; + } + Value state; + JSIterateOp op = (flags & JSITER_HIDDEN) ? JSENUMERATE_INIT_ALL : JSENUMERATE_INIT; + if (!pobj->enumerate(cx, op, &state, NULL)) + return false; + if (state.isMagic(JS_NATIVE_ENUMERATE)) { + if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props)) + return false; + } else { + while (true) { + jsid id; + if (!pobj->enumerate(cx, JSENUMERATE_NEXT, &state, &id)) + return false; + if (state.isNull()) + break; + if (!Enumerate(cx, obj, pobj, id, true, false, flags, ht, props)) + return false; + } + } + } + + if (JS_UNLIKELY(pobj->isXML())) + break; + } while ((pobj = pobj->getProto()) != NULL); + + return true; +} + +namespace js { + +bool +VectorToIdArray(JSContext *cx, AutoIdVector &props, JSIdArray **idap) +{ + JS_STATIC_ASSERT(sizeof(JSIdArray) > sizeof(jsid)); + size_t len = props.length(); + size_t idsz = len * sizeof(jsid); + size_t sz = (sizeof(JSIdArray) - sizeof(jsid)) + idsz; + JSIdArray *ida = static_cast(cx->malloc(sz)); + if (!ida) + return false; + + ida->length = static_cast(len); + memcpy(ida->vector, props.begin(), idsz); + *idap = ida; + return true; +} + +JS_FRIEND_API(bool) +GetPropertyNames(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector *props) +{ + return Snapshot(cx, obj, flags & (JSITER_OWNONLY | JSITER_HIDDEN), props); +} + +} + +static inline bool +GetCustomIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp) +{ + /* Check whether we have a valid __iterator__ method. */ + JSAtom *atom = cx->runtime->atomState.iteratorAtom; + if (!js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, vp)) + return false; + + /* If there is no custom __iterator__ method, we are done here. */ + if (!vp->isObject()) { + vp->setUndefined(); + return true; + } + + /* Otherwise call it and return that object. */ + LeaveTrace(cx); + Value arg = BooleanValue((flags & JSITER_FOREACH) == 0); + if (!ExternalInvoke(cx, ObjectValue(*obj), *vp, 1, &arg, vp)) + return false; + if (vp->isPrimitive()) { + /* + * We are always coming from js_ValueToIterator, and we are no longer on + * trace, so the object we are iterating over is on top of the stack (-1). + */ + JSAutoByteString bytes; + if (!js_AtomToPrintableString(cx, atom, &bytes)) + return false; + js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE, + -1, ObjectValue(*obj), NULL, bytes.ptr()); + return false; + } + return true; +} + +template +static inline bool +Compare(T *a, T *b, size_t c) +{ + size_t n = (c + size_t(7)) / size_t(8); + switch (c % 8) { + case 0: do { if (*a++ != *b++) return false; + case 7: if (*a++ != *b++) return false; + case 6: if (*a++ != *b++) return false; + case 5: if (*a++ != *b++) return false; + case 4: if (*a++ != *b++) return false; + case 3: if (*a++ != *b++) return false; + case 2: if (*a++ != *b++) return false; + case 1: if (*a++ != *b++) return false; + } while (--n > 0); + } + return true; +} + +static inline JSObject * +NewIteratorObject(JSContext *cx, uintN flags) +{ + if (flags & JSITER_ENUMERATE) { + /* + * Non-escaping native enumerator objects do not need map, proto, or + * parent. However, code in jstracer.cpp and elsewhere may find such a + * native enumerator object via the stack and (as for all objects that + * are not stillborn, with the exception of "NoSuchMethod" internal + * helper objects) expect it to have a non-null map pointer, so we + * share an empty Enumerator scope in the runtime. + */ + JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT0); + if (!obj) + return false; + obj->init(cx, &js_IteratorClass, NULL, NULL, NULL, false); + obj->setMap(cx->compartment->emptyEnumeratorShape); + return obj; + } + + return NewBuiltinClassInstance(cx, &js_IteratorClass); +} + +NativeIterator * +NativeIterator::allocateIterator(JSContext *cx, uint32 slength, const AutoIdVector &props) +{ + size_t plength = props.length(); + NativeIterator *ni = (NativeIterator *) + cx->malloc(sizeof(NativeIterator) + plength * sizeof(jsid) + slength * sizeof(uint32)); + if (!ni) + return NULL; + ni->props_array = ni->props_cursor = (jsid *) (ni + 1); + ni->props_end = (jsid *)ni->props_array + plength; + if (plength) + memcpy(ni->props_array, props.begin(), plength * sizeof(jsid)); + return ni; +} + +inline void +NativeIterator::init(JSObject *obj, uintN flags, uint32 slength, uint32 key) +{ + this->obj = obj; + this->flags = flags; + this->shapes_array = (uint32 *) this->props_end; + this->shapes_length = slength; + this->shapes_key = key; +} + +static inline void +RegisterEnumerator(JSContext *cx, JSObject *iterobj, NativeIterator *ni) +{ + /* Register non-escaping native enumerators (for-in) with the current context. */ + if (ni->flags & JSITER_ENUMERATE) { + ni->next = cx->enumerators; + cx->enumerators = iterobj; + + JS_ASSERT(!(ni->flags & JSITER_ACTIVE)); + ni->flags |= JSITER_ACTIVE; + } +} + +static inline bool +VectorToKeyIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector &keys, + uint32 slength, uint32 key, Value *vp) +{ + JS_ASSERT(!(flags & JSITER_FOREACH)); + + JSObject *iterobj = NewIteratorObject(cx, flags); + if (!iterobj) + return false; + + NativeIterator *ni = NativeIterator::allocateIterator(cx, slength, keys); + if (!ni) + return false; + ni->init(obj, flags, slength, key); + + if (slength) { + /* + * Fill in the shape array from scratch. We can't use the array that was + * computed for the cache lookup earlier, as constructing iterobj could + * have triggered a shape-regenerating GC. Don't bother with regenerating + * the shape key; if such a GC *does* occur, we can only get hits through + * the one-slot lastNativeIterator cache. + */ + JSObject *pobj = obj; + size_t ind = 0; + do { + ni->shapes_array[ind++] = pobj->shape(); + pobj = pobj->getProto(); + } while (pobj); + JS_ASSERT(ind == slength); + } + + iterobj->setNativeIterator(ni); + vp->setObject(*iterobj); + + RegisterEnumerator(cx, iterobj, ni); + return true; +} + +namespace js { + +bool +VectorToKeyIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector &props, Value *vp) +{ + return VectorToKeyIterator(cx, obj, flags, props, 0, 0, vp); +} + +bool +VectorToValueIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector &keys, + Value *vp) +{ + JS_ASSERT(flags & JSITER_FOREACH); + + JSObject *iterobj = NewIteratorObject(cx, flags); + if (!iterobj) + return false; + + NativeIterator *ni = NativeIterator::allocateIterator(cx, 0, keys); + if (!ni) + return false; + ni->init(obj, flags, 0, 0); + + iterobj->setNativeIterator(ni); + vp->setObject(*iterobj); + + RegisterEnumerator(cx, iterobj, ni); + return true; +} + +bool +EnumeratedIdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector &props, Value *vp) +{ + if (!(flags & JSITER_FOREACH)) + return VectorToKeyIterator(cx, obj, flags, props, vp); + + return VectorToValueIterator(cx, obj, flags, props, vp); +} + +typedef Vector ShapeVector; + +static inline void +UpdateNativeIterator(NativeIterator *ni, JSObject *obj) +{ + // Update the object for which the native iterator is associated, so + // SuppressDeletedPropertyHelper will recognize the iterator as a match. + ni->obj = obj; +} + +bool +GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp) +{ + Vector shapes(cx); + uint32 key = 0; + + bool keysOnly = (flags == JSITER_ENUMERATE); + + if (obj) { + /* Enumerate Iterator.prototype directly. */ + JSIteratorOp op = obj->getClass()->ext.iteratorObject; + if (op && (obj->getClass() != &js_IteratorClass || obj->getNativeIterator())) { + JSObject *iterobj = op(cx, obj, !(flags & JSITER_FOREACH)); + if (!iterobj) + return false; + vp->setObject(*iterobj); + return true; + } + + if (keysOnly) { + /* + * Check to see if this is the same as the most recent object which + * was iterated over. We don't explicitly check for shapeless + * objects here, as they are not inserted into the cache and + * will result in a miss. + */ + JSObject *last = cx->compartment->nativeIterCache.last; + JSObject *proto = obj->getProto(); + if (last) { + NativeIterator *lastni = last->getNativeIterator(); + if (!(lastni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) && + obj->isNative() && + obj->shape() == lastni->shapes_array[0] && + proto && proto->isNative() && + proto->shape() == lastni->shapes_array[1] && + !proto->getProto()) { + vp->setObject(*last); + UpdateNativeIterator(lastni, obj); + RegisterEnumerator(cx, last, lastni); + return true; + } + } + + /* + * The iterator object for JSITER_ENUMERATE never escapes, so we + * don't care for the proper parent/proto to be set. This also + * allows us to re-use a previous iterator object that is not + * currently active. + */ + JSObject *pobj = obj; + do { + if (!pobj->isNative() || + obj->getOps()->enumerate || + pobj->getClass()->enumerate != JS_EnumerateStub) { + shapes.clear(); + goto miss; + } + uint32 shape = pobj->shape(); + key = (key + (key << 16)) ^ shape; + if (!shapes.append(shape)) + return false; + pobj = pobj->getProto(); + } while (pobj); + + JSObject *iterobj = cx->compartment->nativeIterCache.get(key); + if (iterobj) { + NativeIterator *ni = iterobj->getNativeIterator(); + if (!(ni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) && + ni->shapes_key == key && + ni->shapes_length == shapes.length() && + Compare(ni->shapes_array, shapes.begin(), ni->shapes_length)) { + vp->setObject(*iterobj); + + UpdateNativeIterator(ni, obj); + RegisterEnumerator(cx, iterobj, ni); + if (shapes.length() == 2) + cx->compartment->nativeIterCache.last = iterobj; + return true; + } + } + } + + miss: + if (obj->isProxy()) + return JSProxy::iterate(cx, obj, flags, vp); + if (!GetCustomIterator(cx, obj, flags, vp)) + return false; + if (!vp->isUndefined()) + return true; + } + + /* NB: for (var p in null) succeeds by iterating over no properties. */ + + AutoIdVector keys(cx); + if (flags & JSITER_FOREACH) { + if (JS_LIKELY(obj != NULL) && !Snapshot(cx, obj, flags, &keys)) + return false; + JS_ASSERT(shapes.empty()); + if (!VectorToValueIterator(cx, obj, flags, keys, vp)) + return false; + } else { + if (JS_LIKELY(obj != NULL) && !Snapshot(cx, obj, flags, &keys)) + return false; + if (!VectorToKeyIterator(cx, obj, flags, keys, shapes.length(), key, vp)) + return false; + } + + JSObject *iterobj = &vp->toObject(); + + /* Cache the iterator object if possible. */ + if (shapes.length()) + cx->compartment->nativeIterCache.set(key, iterobj); + + if (shapes.length() == 2) + cx->compartment->nativeIterCache.last = iterobj; + return true; +} + +} + +static JSObject * +iterator_iterator(JSContext *cx, JSObject *obj, JSBool keysonly) +{ + return obj; +} + +static JSBool +Iterator(JSContext *cx, uintN argc, Value *vp) +{ + Value *argv = JS_ARGV(cx, vp); + bool keyonly = argc >= 2 ? js_ValueToBoolean(argv[1]) : false; + uintN flags = JSITER_OWNONLY | (keyonly ? 0 : (JSITER_FOREACH | JSITER_KEYVALUE)); + *vp = argc >= 1 ? argv[0] : UndefinedValue(); + return js_ValueToIterator(cx, flags, vp); +} + +JSBool +js_ThrowStopIteration(JSContext *cx) +{ + Value v; + + JS_ASSERT(!JS_IsExceptionPending(cx)); + if (js_FindClassObject(cx, NULL, JSProto_StopIteration, &v)) + cx->setPendingException(v); + return JS_FALSE; +} + +static JSBool +iterator_next(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj || !InstanceOf(cx, obj, &js_IteratorClass, vp + 2)) + return false; + + if (!js_IteratorMore(cx, obj, vp)) + return false; + if (!vp->toBoolean()) { + js_ThrowStopIteration(cx); + return false; + } + return js_IteratorNext(cx, obj, vp); +} + +#define JSPROP_ROPERM (JSPROP_READONLY | JSPROP_PERMANENT) + +static JSFunctionSpec iterator_methods[] = { + JS_FN(js_next_str, iterator_next, 0,JSPROP_ROPERM), + JS_FS_END +}; + +/* + * Call ToObject(v).__iterator__(keyonly) if ToObject(v).__iterator__ exists. + * Otherwise construct the default iterator. + */ +JS_FRIEND_API(JSBool) +js_ValueToIterator(JSContext *cx, uintN flags, Value *vp) +{ + /* JSITER_KEYVALUE must always come with JSITER_FOREACH */ + JS_ASSERT_IF(flags & JSITER_KEYVALUE, flags & JSITER_FOREACH); + + /* + * Make sure the more/next state machine doesn't get stuck. A value might be + * left in iterValue when a trace is left due to an operation time-out after + * JSOP_MOREITER but before the value is picked up by FOR*. + */ + cx->iterValue.setMagic(JS_NO_ITER_VALUE); + + JSObject *obj; + if (vp->isObject()) { + /* Common case. */ + obj = &vp->toObject(); + } else { + /* + * Enumerating over null and undefined gives an empty enumerator. + * This is contrary to ECMA-262 9.9 ToObject, invoked from step 3 of + * the first production in 12.6.4 and step 4 of the second production, + * but it's "web JS" compatible. ES5 fixed for-in to match this de-facto + * standard. + */ + if ((flags & JSITER_ENUMERATE)) { + if (!js_ValueToObjectOrNull(cx, *vp, &obj)) + return false; + /* fall through */ + } else { + obj = js_ValueToNonNullObject(cx, *vp); + if (!obj) + return false; + } + } + + return GetIterator(cx, obj, flags, vp); +} + +#if JS_HAS_GENERATORS +static JS_REQUIRES_STACK JSBool +CloseGenerator(JSContext *cx, JSObject *genobj); +#endif + +JS_FRIEND_API(JSBool) +js_CloseIterator(JSContext *cx, JSObject *obj) +{ + cx->iterValue.setMagic(JS_NO_ITER_VALUE); + + Class *clasp = obj->getClass(); + if (clasp == &js_IteratorClass) { + /* Remove enumerators from the active list, which is a stack. */ + NativeIterator *ni = obj->getNativeIterator(); + + if (ni->flags & JSITER_ENUMERATE) { + JS_ASSERT(cx->enumerators == obj); + cx->enumerators = ni->next; + + JS_ASSERT(ni->flags & JSITER_ACTIVE); + ni->flags &= ~JSITER_ACTIVE; + + /* + * Reset the enumerator; it may still be in the cached iterators + * for this thread, and can be reused. + */ + ni->props_cursor = ni->props_array; + } + } +#if JS_HAS_GENERATORS + else if (clasp == &js_GeneratorClass) { + return CloseGenerator(cx, obj); + } +#endif + return JS_TRUE; +} + +/* + * Suppress enumeration of deleted properties. This function must be called + * when a property is deleted and there might be active enumerators. + * + * We maintain a list of active non-escaping for-in enumerators. To suppress + * a property, we check whether each active enumerator contains the (obj, id) + * pair and has not yet enumerated |id|. If so, and |id| is the next property, + * we simply advance the cursor. Otherwise, we delete |id| from the list. + * + * We do not suppress enumeration of a property deleted along an object's + * prototype chain. Only direct deletions on the object are handled. + * + * This function can suppress multiple properties at once. The |predicate| + * argument is an object which can be called on an id and returns true or + * false. It also must have a method |matchesAtMostOne| which allows us to + * stop searching after the first deletion if true. + */ +template +static bool +SuppressDeletedPropertyHelper(JSContext *cx, JSObject *obj, IdPredicate predicate) +{ + JSObject *iterobj = cx->enumerators; + while (iterobj) { + again: + NativeIterator *ni = iterobj->getNativeIterator(); + /* This only works for identified surpressed keys, not values. */ + if (ni->isKeyIter() && ni->obj == obj && ni->props_cursor < ni->props_end) { + /* Check whether id is still to come. */ + jsid *props_cursor = ni->current(); + jsid *props_end = ni->end(); + for (jsid *idp = props_cursor; idp < props_end; ++idp) { + if (predicate(*idp)) { + /* + * Check whether another property along the prototype chain + * became visible as a result of this deletion. + */ + if (obj->getProto()) { + AutoObjectRooter proto(cx, obj->getProto()); + AutoObjectRooter obj2(cx); + JSProperty *prop; + if (!proto.object()->lookupProperty(cx, *idp, obj2.addr(), &prop)) + return false; + if (prop) { + uintN attrs; + if (obj2.object()->isNative()) + attrs = ((Shape *) prop)->attributes(); + else if (!obj2.object()->getAttributes(cx, *idp, &attrs)) + return false; + + if (attrs & JSPROP_ENUMERATE) + continue; + } + } + + /* + * If lookupProperty or getAttributes above removed a property from + * ni, start over. + */ + if (props_end != ni->props_end || props_cursor != ni->props_cursor) + goto again; + + /* + * No property along the prototype chain stepped in to take the + * property's place, so go ahead and delete id from the list. + * If it is the next property to be enumerated, just skip it. + */ + if (idp == props_cursor) { + ni->incCursor(); + } else { + memmove(idp, idp + 1, (props_end - (idp + 1)) * sizeof(jsid)); + ni->props_end = ni->end() - 1; + } + + /* Don't reuse modified native iterators. */ + ni->flags |= JSITER_UNREUSABLE; + + if (predicate.matchesAtMostOne()) + break; + } + } + } + iterobj = ni->next; + } + return true; +} + +class SingleIdPredicate { + jsid id; +public: + SingleIdPredicate(jsid id) : id(id) {} + + bool operator()(jsid id) { return id == this->id; } + bool matchesAtMostOne() { return true; } +}; + +bool +js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id) +{ + id = js_CheckForStringIndex(id); + return SuppressDeletedPropertyHelper(cx, obj, SingleIdPredicate(id)); +} + +class IndexRangePredicate { + jsint begin, end; +public: + IndexRangePredicate(jsint begin, jsint end) : begin(begin), end(end) {} + + bool operator()(jsid id) { + return JSID_IS_INT(id) && begin <= JSID_TO_INT(id) && JSID_TO_INT(id) < end; + } + bool matchesAtMostOne() { return false; } +}; + +bool +js_SuppressDeletedIndexProperties(JSContext *cx, JSObject *obj, jsint begin, jsint end) +{ + return SuppressDeletedPropertyHelper(cx, obj, IndexRangePredicate(begin, end)); +} + +JSBool +js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval) +{ + /* Fast path for native iterators */ + NativeIterator *ni = NULL; + if (iterobj->getClass() == &js_IteratorClass) { + /* Key iterators are handled by fast-paths. */ + ni = iterobj->getNativeIterator(); + bool more = ni->props_cursor < ni->props_end; + if (ni->isKeyIter() || !more) { + rval->setBoolean(more); + return true; + } + } + + /* We might still have a pending value. */ + if (!cx->iterValue.isMagic(JS_NO_ITER_VALUE)) { + rval->setBoolean(true); + return true; + } + + /* Fetch and cache the next value from the iterator. */ + if (!ni) { + jsid id = ATOM_TO_JSID(cx->runtime->atomState.nextAtom); + if (!js_GetMethod(cx, iterobj, id, JSGET_METHOD_BARRIER, rval)) + return false; + if (!ExternalInvoke(cx, ObjectValue(*iterobj), *rval, 0, NULL, rval)) { + /* Check for StopIteration. */ + if (!cx->isExceptionPending() || !js_ValueIsStopIteration(cx->getPendingException())) + return false; + + cx->clearPendingException(); + cx->iterValue.setMagic(JS_NO_ITER_VALUE); + rval->setBoolean(false); + return true; + } + } else { + JS_ASSERT(!ni->isKeyIter()); + jsid id = *ni->current(); + ni->incCursor(); + if (!ni->obj->getProperty(cx, id, rval)) + return false; + if ((ni->flags & JSITER_KEYVALUE) && !NewKeyValuePair(cx, id, *rval, rval)) + return false; + } + + /* Cache the value returned by iterobj.next() so js_IteratorNext() can find it. */ + JS_ASSERT(!rval->isMagic(JS_NO_ITER_VALUE)); + cx->iterValue = *rval; + rval->setBoolean(true); + return true; +} + +JSBool +js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval) +{ + /* Fast path for native iterators */ + if (iterobj->getClass() == &js_IteratorClass) { + /* + * Implement next directly as all the methods of the native iterator are + * read-only and permanent. + */ + NativeIterator *ni = iterobj->getNativeIterator(); + if (ni->isKeyIter()) { + JS_ASSERT(ni->props_cursor < ni->props_end); + *rval = IdToValue(*ni->current()); + ni->incCursor(); + + if (rval->isString()) + return true; + + JSString *str; + jsint i; + if (rval->isInt32() && (jsuint(i = rval->toInt32()) < INT_STRING_LIMIT)) { + str = JSString::intString(i); + } else { + str = js_ValueToString(cx, *rval); + if (!str) + return false; + } + + rval->setString(str); + return true; + } + } + + JS_ASSERT(!cx->iterValue.isMagic(JS_NO_ITER_VALUE)); + *rval = cx->iterValue; + cx->iterValue.setMagic(JS_NO_ITER_VALUE); + + return true; +} + +static JSBool +stopiter_hasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp) +{ + *bp = js_ValueIsStopIteration(*v); + return JS_TRUE; +} + +Class js_StopIterationClass = { + js_StopIteration_str, + JSCLASS_HAS_CACHED_PROTO(JSProto_StopIteration) | + JSCLASS_FREEZE_PROTO, + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub, + NULL, /* finalize */ + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + stopiter_hasInstance +}; + +#if JS_HAS_GENERATORS + +static void +generator_finalize(JSContext *cx, JSObject *obj) +{ + JSGenerator *gen = (JSGenerator *) obj->getPrivate(); + if (!gen) + return; + + /* + * gen is open when a script has not called its close method while + * explicitly manipulating it. + */ + JS_ASSERT(gen->state == JSGEN_NEWBORN || + gen->state == JSGEN_CLOSED || + gen->state == JSGEN_OPEN); + cx->free(gen); +} + +static void +generator_trace(JSTracer *trc, JSObject *obj) +{ + JSGenerator *gen = (JSGenerator *) obj->getPrivate(); + if (!gen) + return; + + /* + * Do not mark if the generator is running; the contents may be trash and + * will be replaced when the generator stops. + */ + if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) + return; + + JSStackFrame *fp = gen->floatingFrame(); + JS_ASSERT(gen->liveFrame() == fp); + + /* + * Currently, generators are not mjitted. Still, (overflow) args can be + * pushed by the mjit and need to be conservatively marked. Technically, the + * formal args and generator slots are safe for exact marking, but since the + * plan is to eventually mjit generators, it makes sense to future-proof + * this code and save someone an hour later. + */ + MarkStackRangeConservatively(trc, gen->floatingStack, fp->formalArgsEnd()); + js_TraceStackFrame(trc, fp); + MarkStackRangeConservatively(trc, fp->slots(), gen->regs.sp); +} + +Class js_GeneratorClass = { + js_Generator_str, + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Generator) | + JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE, + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub, + generator_finalize, + NULL, /* reserved */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + JS_CLASS_TRACE(generator_trace), + { + NULL, /* equality */ + NULL, /* outerObject */ + NULL, /* innerObject */ + iterator_iterator, + NULL /* unused */ + } +}; + +static inline void +RebaseRegsFromTo(JSFrameRegs *regs, JSStackFrame *from, JSStackFrame *to) +{ + regs->fp = to; + regs->sp = to->slots() + (regs->sp - from->slots()); +} + +/* + * Called from the JSOP_GENERATOR case in the interpreter, with fp referring + * to the frame by which the generator function was activated. Create a new + * JSGenerator object, which contains its own JSStackFrame that we populate + * from *fp. We know that upon return, the JSOP_GENERATOR opcode will return + * from the activation in fp, so we can steal away fp->callobj and fp->argsobj + * if they are non-null. + */ +JS_REQUIRES_STACK JSObject * +js_NewGenerator(JSContext *cx) +{ + JSObject *obj = NewBuiltinClassInstance(cx, &js_GeneratorClass); + if (!obj) + return NULL; + + JSStackFrame *stackfp = cx->fp(); + JS_ASSERT(stackfp->base() == cx->regs->sp); + JS_ASSERT(stackfp->actualArgs() <= stackfp->formalArgs()); + + /* Load and compute stack slot counts. */ + Value *stackvp = stackfp->actualArgs() - 2; + uintN vplen = stackfp->formalArgsEnd() - stackvp; + + /* Compute JSGenerator size. */ + uintN nbytes = sizeof(JSGenerator) + + (-1 + /* one Value included in JSGenerator */ + vplen + + VALUES_PER_STACK_FRAME + + stackfp->numSlots()) * sizeof(Value); + + JSGenerator *gen = (JSGenerator *) cx->malloc(nbytes); + if (!gen) + return NULL; + + /* Cut up floatingStack space. */ + Value *genvp = gen->floatingStack; + JSStackFrame *genfp = reinterpret_cast(genvp + vplen); + + /* Initialize JSGenerator. */ + gen->obj = obj; + gen->state = JSGEN_NEWBORN; + gen->enumerators = NULL; + gen->floating = genfp; + + /* Initialize regs stored in generator. */ + gen->regs = *cx->regs; + RebaseRegsFromTo(&gen->regs, stackfp, genfp); + + /* Copy frame off the stack. */ + genfp->stealFrameAndSlots(genvp, stackfp, stackvp, cx->regs->sp); + genfp->initFloatingGenerator(); + + obj->setPrivate(gen); + return obj; +} + +JSGenerator * +js_FloatingFrameToGenerator(JSStackFrame *fp) +{ + JS_ASSERT(fp->isGeneratorFrame() && fp->isFloatingGenerator()); + char *floatingStackp = (char *)(fp->actualArgs() - 2); + char *p = floatingStackp - offsetof(JSGenerator, floatingStack); + return reinterpret_cast(p); +} + +typedef enum JSGeneratorOp { + JSGENOP_NEXT, + JSGENOP_SEND, + JSGENOP_THROW, + JSGENOP_CLOSE +} JSGeneratorOp; + +/* + * Start newborn or restart yielding generator and perform the requested + * operation inside its frame. + */ +static JS_REQUIRES_STACK JSBool +SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, + JSGenerator *gen, const Value &arg) +{ + if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) { + js_ReportValueError(cx, JSMSG_NESTING_GENERATOR, + JSDVG_SEARCH_STACK, ObjectOrNullValue(obj), + JS_GetFunctionId(gen->floatingFrame()->fun())); + return JS_FALSE; + } + + /* Check for OOM errors here, where we can fail easily. */ + if (!cx->ensureGeneratorStackSpace()) + return JS_FALSE; + + JS_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN); + switch (op) { + case JSGENOP_NEXT: + case JSGENOP_SEND: + if (gen->state == JSGEN_OPEN) { + /* + * Store the argument to send as the result of the yield + * expression. + */ + gen->regs.sp[-1] = arg; + } + gen->state = JSGEN_RUNNING; + break; + + case JSGENOP_THROW: + cx->setPendingException(arg); + gen->state = JSGEN_RUNNING; + break; + + default: + JS_ASSERT(op == JSGENOP_CLOSE); + cx->setPendingException(MagicValue(JS_GENERATOR_CLOSING)); + gen->state = JSGEN_CLOSING; + break; + } + + JSStackFrame *genfp = gen->floatingFrame(); + Value *genvp = gen->floatingStack; + uintN vplen = genfp->formalArgsEnd() - genvp; + + JSStackFrame *stackfp; + Value *stackvp; + JSBool ok; + { + /* + * Get a pointer to new frame/slots. This memory is not "claimed", so + * the code before pushExecuteFrame must not reenter the interpreter. + */ + GeneratorFrameGuard frame; + if (!cx->stack().getGeneratorFrame(cx, vplen, genfp->numSlots(), &frame)) { + gen->state = JSGEN_CLOSED; + return JS_FALSE; + } + stackfp = frame.fp(); + stackvp = frame.vp(); + + /* Copy frame onto the stack. */ + stackfp->stealFrameAndSlots(stackvp, genfp, genvp, gen->regs.sp); + stackfp->resetGeneratorPrev(cx); + stackfp->unsetFloatingGenerator(); + RebaseRegsFromTo(&gen->regs, genfp, stackfp); + MUST_FLOW_THROUGH("restore"); + + /* Officially push frame. frame's destructor pops. */ + cx->stack().pushGeneratorFrame(cx, &gen->regs, &frame); + + cx->enterGenerator(gen); /* OOM check above. */ + JSObject *enumerators = cx->enumerators; + cx->enumerators = gen->enumerators; + + ok = RunScript(cx, stackfp->script(), stackfp); + + gen->enumerators = cx->enumerators; + cx->enumerators = enumerators; + cx->leaveGenerator(gen); + + /* + * Copy the stack frame and rebase the regs, but not before popping + * the stack, since cx->regs == &gen->regs. + */ + genfp->stealFrameAndSlots(genvp, stackfp, stackvp, gen->regs.sp); + genfp->setFloatingGenerator(); + } + MUST_FLOW_LABEL(restore) + RebaseRegsFromTo(&gen->regs, stackfp, genfp); + + if (gen->floatingFrame()->isYielding()) { + /* Yield cannot fail, throw or be called on closing. */ + JS_ASSERT(ok); + JS_ASSERT(!cx->isExceptionPending()); + JS_ASSERT(gen->state == JSGEN_RUNNING); + JS_ASSERT(op != JSGENOP_CLOSE); + genfp->clearYielding(); + gen->state = JSGEN_OPEN; + return JS_TRUE; + } + + genfp->clearReturnValue(); + gen->state = JSGEN_CLOSED; + if (ok) { + /* Returned, explicitly or by falling off the end. */ + if (op == JSGENOP_CLOSE) + return JS_TRUE; + return js_ThrowStopIteration(cx); + } + + /* + * An error, silent termination by operation callback or an exception. + * Propagate the condition to the caller. + */ + return JS_FALSE; +} + +static JS_REQUIRES_STACK JSBool +CloseGenerator(JSContext *cx, JSObject *obj) +{ + JS_ASSERT(obj->getClass() == &js_GeneratorClass); + + JSGenerator *gen = (JSGenerator *) obj->getPrivate(); + if (!gen) { + /* Generator prototype object. */ + return JS_TRUE; + } + + if (gen->state == JSGEN_CLOSED) + return JS_TRUE; + + return SendToGenerator(cx, JSGENOP_CLOSE, obj, gen, UndefinedValue()); +} + +/* + * Common subroutine of generator_(next|send|throw|close) methods. + */ +static JSBool +generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc) +{ + LeaveTrace(cx); + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj || !InstanceOf(cx, obj, &js_GeneratorClass, vp + 2)) + return JS_FALSE; + + JSGenerator *gen = (JSGenerator *) obj->getPrivate(); + if (!gen) { + /* This happens when obj is the generator prototype. See bug 352885. */ + goto closed_generator; + } + + if (gen->state == JSGEN_NEWBORN) { + switch (op) { + case JSGENOP_NEXT: + case JSGENOP_THROW: + break; + + case JSGENOP_SEND: + if (argc >= 1 && !vp[2].isUndefined()) { + js_ReportValueError(cx, JSMSG_BAD_GENERATOR_SEND, + JSDVG_SEARCH_STACK, vp[2], NULL); + return JS_FALSE; + } + break; + + default: + JS_ASSERT(op == JSGENOP_CLOSE); + gen->state = JSGEN_CLOSED; + return JS_TRUE; + } + } else if (gen->state == JSGEN_CLOSED) { + closed_generator: + switch (op) { + case JSGENOP_NEXT: + case JSGENOP_SEND: + return js_ThrowStopIteration(cx); + case JSGENOP_THROW: + cx->setPendingException(argc >= 1 ? vp[2] : UndefinedValue()); + return JS_FALSE; + default: + JS_ASSERT(op == JSGENOP_CLOSE); + return JS_TRUE; + } + } + + bool undef = ((op == JSGENOP_SEND || op == JSGENOP_THROW) && argc != 0); + if (!SendToGenerator(cx, op, obj, gen, undef ? vp[2] : UndefinedValue())) + return JS_FALSE; + *vp = gen->floatingFrame()->returnValue(); + return JS_TRUE; +} + +static JSBool +generator_send(JSContext *cx, uintN argc, Value *vp) +{ + return generator_op(cx, JSGENOP_SEND, vp, argc); +} + +static JSBool +generator_next(JSContext *cx, uintN argc, Value *vp) +{ + return generator_op(cx, JSGENOP_NEXT, vp, argc); +} + +static JSBool +generator_throw(JSContext *cx, uintN argc, Value *vp) +{ + return generator_op(cx, JSGENOP_THROW, vp, argc); +} + +static JSBool +generator_close(JSContext *cx, uintN argc, Value *vp) +{ + return generator_op(cx, JSGENOP_CLOSE, vp, argc); +} + +static JSFunctionSpec generator_methods[] = { + JS_FN(js_next_str, generator_next, 0,JSPROP_ROPERM), + JS_FN(js_send_str, generator_send, 1,JSPROP_ROPERM), + JS_FN(js_throw_str, generator_throw, 1,JSPROP_ROPERM), + JS_FN(js_close_str, generator_close, 0,JSPROP_ROPERM), + JS_FS_END +}; + +#endif /* JS_HAS_GENERATORS */ + +JSObject * +js_InitIteratorClasses(JSContext *cx, JSObject *obj) +{ + JSObject *proto, *stop; + + /* Idempotency required: we initialize several things, possibly lazily. */ + if (!js_GetClassObject(cx, obj, JSProto_StopIteration, &stop)) + return NULL; + if (stop) + return stop; + + proto = js_InitClass(cx, obj, NULL, &js_IteratorClass, Iterator, 2, + NULL, iterator_methods, NULL, NULL); + if (!proto) + return NULL; + +#if JS_HAS_GENERATORS + /* Initialize the generator internals if configured. */ + if (!js_InitClass(cx, obj, NULL, &js_GeneratorClass, NULL, 0, + NULL, generator_methods, NULL, NULL)) { + return NULL; + } +#endif + + return js_InitClass(cx, obj, NULL, &js_StopIterationClass, NULL, 0, + NULL, NULL, NULL, NULL); +} diff --git a/js/src/jsiter.h b/js/src/jsiter.h new file mode 100644 index 0000000..9ae01d3 --- /dev/null +++ b/js/src/jsiter.h @@ -0,0 +1,248 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsiter_h___ +#define jsiter_h___ + +/* + * JavaScript iterators. + */ +#include "jscntxt.h" +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jsversion.h" + +/* + * NB: these flag bits are encoded into the bytecode stream in the immediate + * operand of JSOP_ITER, so don't change them without advancing jsxdrapi.h's + * JSXDR_BYTECODE_VERSION. + */ +#define JSITER_ENUMERATE 0x1 /* for-in compatible hidden default iterator */ +#define JSITER_FOREACH 0x2 /* return [key, value] pair rather than key */ +#define JSITER_KEYVALUE 0x4 /* destructuring for-in wants [key, value] */ +#define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */ +#define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */ + +/* + * For cacheable native iterators, whether the iterator is currently active. + * Not serialized by XDR. + */ +#define JSITER_ACTIVE 0x1000 +#define JSITER_UNREUSABLE 0x2000 + +namespace js { + +struct NativeIterator { + JSObject *obj; + jsid *props_array; + jsid *props_cursor; + jsid *props_end; + uint32 *shapes_array; + uint32 shapes_length; + uint32 shapes_key; + uint32 flags; + JSObject *next; /* Forms cx->enumerators list, garbage otherwise. */ + + bool isKeyIter() const { return (flags & JSITER_FOREACH) == 0; } + + inline jsid *begin() const { + return props_array; + } + + inline jsid *end() const { + return props_end; + } + + size_t numKeys() const { + return end() - begin(); + } + + jsid *current() const { + JS_ASSERT(props_cursor < props_end); + return props_cursor; + } + + void incCursor() { + props_cursor = props_cursor + 1; + } + + static NativeIterator *allocateIterator(JSContext *cx, uint32 slength, + const js::AutoIdVector &props); + void init(JSObject *obj, uintN flags, uint32 slength, uint32 key); + + void mark(JSTracer *trc); +}; + +bool +VectorToIdArray(JSContext *cx, js::AutoIdVector &props, JSIdArray **idap); + +JS_FRIEND_API(bool) +GetPropertyNames(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector *props); + +bool +GetIterator(JSContext *cx, JSObject *obj, uintN flags, js::Value *vp); + +bool +VectorToKeyIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp); + +bool +VectorToValueIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp); + +/* + * Creates either a key or value iterator, depending on flags. For a value + * iterator, performs value-lookup to convert the given list of jsids. + */ +bool +EnumeratedIdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp); + +} + +/* + * Convert the value stored in *vp to its iteration object. The flags should + * contain JSITER_ENUMERATE if js_ValueToIterator is called when enumerating + * for-in semantics are required, and when the caller can guarantee that the + * iterator will never be exposed to scripts. + */ +extern JS_FRIEND_API(JSBool) +js_ValueToIterator(JSContext *cx, uintN flags, js::Value *vp); + +extern JS_FRIEND_API(JSBool) +js_CloseIterator(JSContext *cx, JSObject *iterObj); + +bool +js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id); + +bool +js_SuppressDeletedIndexProperties(JSContext *cx, JSObject *obj, jsint begin, jsint end); + +/* + * IteratorMore() indicates whether another value is available. It might + * internally call iterobj.next() and then cache the value until its + * picked up by IteratorNext(). The value is cached in the current context. + */ +extern JSBool +js_IteratorMore(JSContext *cx, JSObject *iterobj, js::Value *rval); + +extern JSBool +js_IteratorNext(JSContext *cx, JSObject *iterobj, js::Value *rval); + +extern JSBool +js_ThrowStopIteration(JSContext *cx); + +#if JS_HAS_GENERATORS + +/* + * Generator state codes. + */ +typedef enum JSGeneratorState { + JSGEN_NEWBORN, /* not yet started */ + JSGEN_OPEN, /* started by a .next() or .send(undefined) call */ + JSGEN_RUNNING, /* currently executing via .next(), etc., call */ + JSGEN_CLOSING, /* close method is doing asynchronous return */ + JSGEN_CLOSED /* closed, cannot be started or closed again */ +} JSGeneratorState; + +struct JSGenerator { + JSObject *obj; + JSGeneratorState state; + JSFrameRegs regs; + JSObject *enumerators; + JSStackFrame *floating; + js::Value floatingStack[1]; + + JSStackFrame *floatingFrame() { + return floating; + } + + JSStackFrame *liveFrame() { + JS_ASSERT((state == JSGEN_RUNNING || state == JSGEN_CLOSING) == + (regs.fp != floatingFrame())); + return regs.fp; + } +}; + +extern JSObject * +js_NewGenerator(JSContext *cx); + +/* + * Generator stack frames do not have stable pointers since they get copied to + * and from the generator object and the stack (see SendToGenerator). This is a + * problem for Block and With objects, which need to store a pointer to the + * enclosing stack frame. The solution is for Block and With objects to store + * a pointer to the "floating" stack frame stored in the generator object, + * since it is stable, and maintain, in the generator object, a pointer to the + * "live" stack frame (either a copy on the stack or the floating frame). Thus, + * Block and With objects must "normalize" to and from the floating/live frames + * in the case of generators using the following functions. + */ +inline JSStackFrame * +js_FloatingFrameIfGenerator(JSContext *cx, JSStackFrame *fp) +{ + JS_ASSERT(cx->stack().contains(fp)); + if (JS_UNLIKELY(fp->isGeneratorFrame())) + return cx->generatorFor(fp)->floatingFrame(); + return fp; +} + +/* Given a floating frame, given the JSGenerator containing it. */ +extern JSGenerator * +js_FloatingFrameToGenerator(JSStackFrame *fp); + +inline JSStackFrame * +js_LiveFrameIfGenerator(JSStackFrame *fp) +{ + return fp->isGeneratorFrame() ? js_FloatingFrameToGenerator(fp)->liveFrame() : fp; +} + +#endif + +extern js::Class js_GeneratorClass; +extern js::Class js_IteratorClass; +extern js::Class js_StopIterationClass; + +static inline bool +js_ValueIsStopIteration(const js::Value &v) +{ + return v.isObject() && v.toObject().getClass() == &js_StopIterationClass; +} + +extern JSObject * +js_InitIteratorClasses(JSContext *cx, JSObject *obj); + +#endif /* jsiter_h___ */ diff --git a/js/src/jskeyword.tbl b/js/src/jskeyword.tbl new file mode 100644 index 0000000..3a5c1ef --- /dev/null +++ b/js/src/jskeyword.tbl @@ -0,0 +1,115 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=8 et tw=80: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Keywords used as primary expressions, sharing the TOK_PRIMARY token kind, + * distinguished by opcode. + */ +JS_KEYWORD(false, TOK_PRIMARY, JSOP_FALSE, JSVERSION_DEFAULT) +JS_KEYWORD(true, TOK_PRIMARY, JSOP_TRUE, JSVERSION_DEFAULT) +JS_KEYWORD(null, TOK_PRIMARY, JSOP_NULL, JSVERSION_DEFAULT) + +/* ES5 Keywords. */ +JS_KEYWORD(break, TOK_BREAK, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(case, TOK_CASE, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(catch, TOK_CATCH, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(continue, TOK_CONTINUE, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(debugger, TOK_DEBUGGER, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(default, TOK_DEFAULT, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(delete, TOK_DELETE, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(do, TOK_DO, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(else, TOK_ELSE, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(finally, TOK_FINALLY, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(for, TOK_FOR, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(function, TOK_FUNCTION, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(if, TOK_IF, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(in, TOK_IN, JSOP_IN, JSVERSION_DEFAULT) +JS_KEYWORD(instanceof, TOK_INSTANCEOF, JSOP_INSTANCEOF,JSVERSION_DEFAULT) +JS_KEYWORD(new, TOK_NEW, JSOP_NEW, JSVERSION_DEFAULT) +JS_KEYWORD(return, TOK_RETURN, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(switch, TOK_SWITCH, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(this, TOK_PRIMARY, JSOP_THIS, JSVERSION_DEFAULT) +JS_KEYWORD(throw, TOK_THROW, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(try, TOK_TRY, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(typeof, TOK_UNARYOP, JSOP_TYPEOF, JSVERSION_DEFAULT) +JS_KEYWORD(var, TOK_VAR, JSOP_DEFVAR, JSVERSION_DEFAULT) +JS_KEYWORD(void, TOK_UNARYOP, JSOP_VOID, JSVERSION_DEFAULT) +JS_KEYWORD(while, TOK_WHILE, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(with, TOK_WITH, JSOP_NOP, JSVERSION_DEFAULT) + +/* + * ES5 FutureReservedWord keywords which we historically unreserved, forcing us + * to re-reserve them only in strict mode. + */ +JS_KEYWORD(class, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(enum, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(export, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(extends, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(import, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(super, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) + +/* + * ES5 reserved keywords with long-implemented behavior, allowed in our + * implementation to ease code migration. + */ +#if JS_HAS_CONST +JS_KEYWORD(const, TOK_VAR, JSOP_DEFCONST, JSVERSION_DEFAULT) +#else +JS_KEYWORD(const, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +#endif +#if JS_HAS_BLOCK_SCOPE +JS_KEYWORD(let, TOK_LET, JSOP_NOP, JSVERSION_1_7) +#else +JS_KEYWORD(let, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_1_7) +#endif +#if JS_HAS_GENERATORS +JS_KEYWORD(yield, TOK_YIELD, JSOP_NOP, JSVERSION_1_7) +#else +JS_KEYWORD(yield, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_1_7) +#endif + +/* ES5 future reserved keywords in strict mode. */ +JS_KEYWORD(implements, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(interface, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(package, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(private, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(protected, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(public, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) +JS_KEYWORD(static, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) diff --git a/js/src/jskwgen.cpp b/js/src/jskwgen.cpp new file mode 100644 index 0000000..f808b92 --- /dev/null +++ b/js/src/jskwgen.cpp @@ -0,0 +1,460 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=8 et tw=80: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is String Switch Generator for JavaScript Keywords, + * released 2005-12-09. + * + * The Initial Developer of the Original Code is + * Igor Bukanov. + * Portions created by the Initial Developer are Copyright (C) 2005-2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include +#include +#include +#include +#include + +#include "jsversion.h" + +const char * const keyword_list[] = { +#define JS_KEYWORD(keyword, type, op, version) #keyword, +#include "jskeyword.tbl" +#undef JS_KEYWORD +}; + +struct gen_opt { + FILE *output; /* output file for generated source */ + unsigned use_if_threshold; /* max number of choices to generate + "if" selector instead of "switch" */ + unsigned char_tail_test_threshold; /* max number of unprocessed columns + to use inlined char compare + for remaining chars and not generic + string compare code */ + unsigned indent_level; /* current source identation level */ +}; + +static unsigned column_to_compare; + +static int +length_comparator(const void *a, const void *b) +{ + const char *str1 = keyword_list[*(unsigned *)a]; + const char *str2 = keyword_list[*(unsigned *)b]; + return (int)strlen(str1) - (int)strlen(str2); +} + +static int +column_comparator(const void *a, const void *b) +{ + const char *str1 = keyword_list[*(unsigned *)a]; + const char *str2 = keyword_list[*(unsigned *)b]; + return (int)str1[column_to_compare] - (int)str2[column_to_compare]; +} + +static unsigned +count_different_lengths(unsigned indexes[], unsigned nelem) +{ + unsigned nlength, current_length, i, l; + + current_length = 0; + nlength = 0; + for (i = 0; i != nelem; ++i) { + l = (unsigned)strlen(keyword_list[indexes[i]]); + assert(l != 0); + if (current_length != l) { + ++nlength; + current_length = l; + } + } + return nlength; +} + +static void +find_char_span_and_count(unsigned indexes[], unsigned nelem, unsigned column, + unsigned *span_result, unsigned *count_result) +{ + unsigned i, count; + unsigned char c, prev, minc, maxc; + + assert(nelem != 0); + minc = maxc = prev = (unsigned char)keyword_list[indexes[0]][column]; + count = 1; + for (i = 1; i != nelem; ++i) { + c = (unsigned char)keyword_list[indexes[i]][column]; + if (prev != c) { + prev = c; + ++count; + if (minc > c) { + minc = c; + } else if (maxc < c) { + maxc = c; + } + } + } + + *span_result = maxc - minc + 1; + *count_result = count; +} + +static unsigned +find_optimal_switch_column(struct gen_opt *opt, + unsigned indexes[], unsigned nelem, + unsigned columns[], unsigned unprocessed_columns, + int *use_if_result) +{ + unsigned i; + unsigned span, min_span, min_span_index; + unsigned nchar, min_nchar, min_nchar_index; + + assert(unprocessed_columns != 0); + i = 0; + min_nchar = min_span = (unsigned)-1; + min_nchar_index = min_span_index = 0; + do { + column_to_compare = columns[i]; + qsort(indexes, nelem, sizeof(indexes[0]), column_comparator); + find_char_span_and_count(indexes, nelem, column_to_compare, + &span, &nchar); + assert(span != 0); + if (span == 1) { + assert(nchar == 1); + *use_if_result = 1; + return 1; + } + assert(nchar != 1); + if (min_span > span) { + min_span = span; + min_span_index = i; + } + if (min_nchar > nchar) { + min_nchar = nchar; + min_nchar_index = i; + } + } while (++i != unprocessed_columns); + + if (min_nchar <= opt->use_if_threshold) { + *use_if_result = 1; + i = min_nchar_index; + } else { + *use_if_result = 0; + i = min_span_index; + } + + /* + * Restore order corresponding to i if it was destroyed by + * subsequent sort. + */ + if (i != unprocessed_columns - 1) { + column_to_compare = columns[i]; + qsort(indexes, nelem, sizeof(indexes[0]), column_comparator); + } + + return i; +} + + +static void +p(struct gen_opt *opt, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vfprintf(opt->output, format, ap); + va_end(ap); +} + +/* Size for '\xxx' where xxx is octal escape */ +#define MIN_QUOTED_CHAR_BUFFER 7 + +static char * +qchar(char c, char *quoted_buffer) +{ + char *s; + + s = quoted_buffer; + *s++ = '\''; + switch (c) { + case '\n': c = 'n'; goto one_char_escape; + case '\r': c = 'r'; goto one_char_escape; + case '\t': c = 't'; goto one_char_escape; + case '\f': c = 't'; goto one_char_escape; + case '\0': c = '0'; goto one_char_escape; + case '\'': goto one_char_escape; + one_char_escape: + *s++ = '\\'; + break; + default: + if (!isprint(c)) { + *s++ = '\\'; + *s++ = (char)('0' + (0x3 & (((unsigned char)c) >> 6))); + *s++ = (char)('0' + (0x7 & (((unsigned char)c) >> 3))); + c = (char)('0' + (0x7 & ((unsigned char)c))); + } + } + *s++ = c; + *s++ = '\''; + *s = '\0'; + assert(s + 1 <= quoted_buffer + MIN_QUOTED_CHAR_BUFFER); + return quoted_buffer; +} + +static void +nl(struct gen_opt *opt) +{ + putc('\n', opt->output); +} + +static void +indent(struct gen_opt *opt) +{ + unsigned n = opt->indent_level; + while (n != 0) { + --n; + fputs(" ", opt->output); + } +} + +static void +line(struct gen_opt *opt, const char *format, ...) +{ + va_list ap; + + indent(opt); + va_start(ap, format); + vfprintf(opt->output, format, ap); + va_end(ap); + nl(opt); +} + +static void +generate_letter_switch_r(struct gen_opt *opt, + unsigned indexes[], unsigned nelem, + unsigned columns[], unsigned unprocessed_columns) +{ + char qbuf[MIN_QUOTED_CHAR_BUFFER]; + + assert(nelem != 0); + if (nelem == 1) { + unsigned kw_index = indexes[0]; + const char *keyword = keyword_list[kw_index]; + + if (unprocessed_columns == 0) { + line(opt, "JSKW_GOT_MATCH(%u) /* %s */", kw_index, keyword); + } else if (unprocessed_columns > opt->char_tail_test_threshold) { + line(opt, "JSKW_TEST_GUESS(%u) /* %s */", kw_index, keyword); + } else { + unsigned i, column; + + indent(opt); p(opt, "if ("); + for (i = 0; i != unprocessed_columns; ++i) { + column = columns[i]; + qchar(keyword[column], qbuf); + p(opt, "%sJSKW_AT(%u)==%s", (i == 0) ? "" : " && ", + column, qbuf); + } + p(opt, ") {"); nl(opt); + ++opt->indent_level; + line(opt, "JSKW_GOT_MATCH(%u) /* %s */", kw_index, keyword); + --opt->indent_level; + line(opt, "}"); + line(opt, "JSKW_NO_MATCH()"); + } + } else { + unsigned optimal_column_index, optimal_column; + unsigned i; + int use_if; + char current; + + assert(unprocessed_columns != 0); + optimal_column_index = find_optimal_switch_column(opt, indexes, nelem, + columns, + unprocessed_columns, + &use_if); + optimal_column = columns[optimal_column_index]; + columns[optimal_column_index] = columns[unprocessed_columns - 1]; + + if (!use_if) + line(opt, "switch (JSKW_AT(%u)) {", optimal_column); + + current = keyword_list[indexes[0]][optimal_column]; + for (i = 0; i != nelem;) { + unsigned same_char_begin = i; + char next = current; + + for (++i; i != nelem; ++i) { + next = keyword_list[indexes[i]][optimal_column]; + if (next != current) + break; + } + qchar(current, qbuf); + if (use_if) { + line(opt, "if (JSKW_AT(%u) == %s) {", optimal_column, qbuf); + } else { + line(opt, " case %s:", qbuf); + } + ++opt->indent_level; + generate_letter_switch_r(opt, indexes + same_char_begin, + i - same_char_begin, + columns, unprocessed_columns - 1); + --opt->indent_level; + if (use_if) { + line(opt, "}"); + } + current = next; + } + + if (!use_if) { + line(opt, "}"); + } + + columns[optimal_column_index] = optimal_column; + + line(opt, "JSKW_NO_MATCH()"); + } +} + +static void +generate_letter_switch(struct gen_opt *opt, + unsigned indexes[], unsigned nelem, + unsigned current_length) +{ + unsigned *columns; + unsigned i; + + columns = (unsigned *) malloc(sizeof(columns[0]) * current_length); + if (!columns) { + perror("malloc"); + exit(EXIT_FAILURE); + } + for (i = 0; i != current_length; ++i) { + columns[i] = i; + } + generate_letter_switch_r(opt, indexes, nelem, columns, current_length); + free(columns); +} + + +static void +generate_switch(struct gen_opt *opt) +{ + unsigned *indexes; + unsigned nlength; + unsigned i, current; + int use_if; + unsigned nelem; + + nelem = sizeof(keyword_list)/sizeof(keyword_list[0]); + + line(opt, "/*"); + line(opt, " * Generating switch for the list of %u entries:", nelem); + for (i = 0; i != nelem; ++i) { + line(opt, " * %s", keyword_list[i]); + } + line(opt, " */"); + + indexes = (unsigned *) malloc(sizeof(indexes[0]) * nelem); + if (!indexes) { + perror("malloc"); + exit(EXIT_FAILURE); + } + for (i = 0; i != nelem; ++i) + indexes[i] = i; + qsort(indexes, nelem, sizeof(indexes[i]), length_comparator); + nlength = count_different_lengths(indexes, nelem); + + use_if = (nlength <= opt->use_if_threshold); + + if (!use_if) + line(opt, "switch (JSKW_LENGTH()) {"); + + current = (unsigned)strlen(keyword_list[indexes[0]]); + for (i = 0; i != nelem;) { + unsigned same_length_begin = i; + unsigned next = current; + + for (++i; i != nelem; ++i) { + next = (unsigned)strlen(keyword_list[indexes[i]]); + if (next != current) + break; + } + if (use_if) { + line(opt, "if (JSKW_LENGTH() == %u) {", current); + } else { + line(opt, " case %u:", current); + } + ++opt->indent_level; + generate_letter_switch(opt, indexes + same_length_begin, + i - same_length_begin, + current); + --opt->indent_level; + if (use_if) { + line(opt, "}"); + } + current = next; + } + if (!use_if) + line(opt, "}"); + line(opt, "JSKW_NO_MATCH()"); + free(indexes); +} + +int main(int argc, char **argv) +{ + struct gen_opt opt; + + if (argc < 2) { + opt.output = stdout; + } else { + opt.output = fopen(argv[1], "w"); + if (!opt.output) { + perror("fopen"); + exit(EXIT_FAILURE); + } + } + opt.indent_level = 1; + opt.use_if_threshold = 3; + opt.char_tail_test_threshold = 4; + + generate_switch(&opt); + + if (opt.output != stdout) { + if (fclose(opt.output)) { + perror("fclose"); + exit(EXIT_FAILURE); + } + } + + return EXIT_SUCCESS; +} diff --git a/js/src/jslibmath.h b/js/src/jslibmath.h new file mode 100644 index 0000000..236bca2 --- /dev/null +++ b/js/src/jslibmath.h @@ -0,0 +1,88 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _LIBMATH_H +#define _LIBMATH_H + +#include +#ifdef XP_WIN +# include "jsnum.h" +#endif + +/* + * Use system provided math routines. + */ + +/* The right copysign function is not always named the same thing. */ +#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define js_copysign __builtin_copysign +#elif defined WINCE +#define js_copysign _copysign +#elif defined _WIN32 +#if _MSC_VER < 1400 +/* Try to work around apparent _copysign bustage in VC7.x. */ +#define js_copysign js_copysign +extern double js_copysign(double, double); +#else +#define js_copysign _copysign +#endif +#else +#define js_copysign copysign +#endif + +/* Consistency wrapper for platform deviations in fmod() */ +static inline double +js_fmod(double d, double d2) +{ +#ifdef XP_WIN + /* + * Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. + * Workaround MS fmod bug where -0 % -N => 0, not -0. + */ + if ((JSDOUBLE_IS_FINITE(d) && JSDOUBLE_IS_INFINITE(d2)) || + (d == 0 && JSDOUBLE_IS_FINITE(d2))) { + return d; + } +#endif + return fmod(d, d2); +} + +#endif /* _LIBMATH_H */ + diff --git a/js/src/jslock.cpp b/js/src/jslock.cpp new file mode 100644 index 0000000..e9f505e --- /dev/null +++ b/js/src/jslock.cpp @@ -0,0 +1,736 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifdef JS_THREADSAFE + +/* + * JS locking stubs. + */ +#include +#include +#include "jspubtd.h" +#include "jsutil.h" +#include "jstypes.h" +#include "jsstdint.h" +#include "jsbit.h" +#include "jscntxt.h" +#include "jsgc.h" +#include "jslock.h" +#include "jsscope.h" +#include "jsstr.h" + +using namespace js; + +#define ReadWord(W) (W) + +#if !defined(__GNUC__) +# define __asm__ asm +# define __volatile__ volatile +#endif + +/* Implement NativeCompareAndSwap. */ + +#if defined(_MSC_VER) && defined(_M_IX86) +#pragma warning( disable : 4035 ) +JS_BEGIN_EXTERN_C +extern long __cdecl +_InterlockedCompareExchange(long *volatile dest, long exchange, long comp); +JS_END_EXTERN_C +#pragma intrinsic(_InterlockedCompareExchange) + +JS_STATIC_ASSERT(sizeof(jsword) == sizeof(long)); + +static JS_ALWAYS_INLINE int +NativeCompareAndSwapHelper(volatile jsword *w, jsword ov, jsword nv) +{ + _InterlockedCompareExchange((long*) w, nv, ov); + __asm { + sete al + } +} + +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(volatile jsword *w, jsword ov, jsword nv) +{ + return (NativeCompareAndSwapHelper(w, ov, nv) & 1); +} + +#elif defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_X64)) +JS_BEGIN_EXTERN_C +extern long long __cdecl +_InterlockedCompareExchange64(long long *volatile dest, long long exchange, long long comp); +JS_END_EXTERN_C +#pragma intrinsic(_InterlockedCompareExchange64) + +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(volatile jsword *w, jsword ov, jsword nv) +{ + return _InterlockedCompareExchange64((long long *volatile)w, nv, ov) == ov; +} + +#elif defined(XP_MACOSX) || defined(DARWIN) + +#include + +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(volatile jsword *w, jsword ov, jsword nv) +{ + /* Details on these functions available in the manpage for atomic */ + return OSAtomicCompareAndSwapPtrBarrier(reinterpret_cast(ov), + reinterpret_cast(nv), + reinterpret_cast(w)); +} + +#elif defined(__i386) && (defined(__GNUC__) || defined(__SUNPRO_CC)) + +/* Note: This fails on 386 cpus, cmpxchgl is a >= 486 instruction */ +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(volatile jsword *w, jsword ov, jsword nv) +{ + unsigned int res; + + __asm__ __volatile__ ( + "lock\n" + "cmpxchgl %2, (%1)\n" + "sete %%al\n" + "andl $1, %%eax\n" + : "=a" (res) +#ifdef __SUNPRO_CC +/* Different code for Sun Studio because of a bug of SS12U1 */ + : "c" (w), "d" (nv), "a" (ov) +#else + : "r" (w), "r" (nv), "a" (ov) +#endif + : "cc", "memory"); + return (int)res; +} +#elif defined(__x86_64) && (defined(__GNUC__) || defined(__SUNPRO_CC)) + +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(volatile jsword *w, jsword ov, jsword nv) +{ + unsigned int res; + + __asm__ __volatile__ ( + "lock\n" + "cmpxchgq %2, (%1)\n" + "sete %%al\n" + "movzbl %%al, %%eax\n" + : "=a" (res) + : "r" (w), "r" (nv), "a" (ov) + : "cc", "memory"); + return (int)res; +} + +#elif defined(__sparc) +#if defined(__GNUC__) + +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(volatile jsword *w, jsword ov, jsword nv) +{ + unsigned int res; + + __asm__ __volatile__ ( + "membar #StoreLoad | #LoadLoad\n" +#if JS_BITS_PER_WORD == 32 + "cas [%1],%2,%3\n" +#else + "casx [%1],%2,%3\n" +#endif + "membar #StoreLoad | #LoadLoad\n" + "cmp %2,%3\n" + "be,a 1f\n" + "mov 1,%0\n" + "mov 0,%0\n" + "1:" + : "=r" (res) + : "r" (w), "r" (ov), "r" (nv)); + return (int)res; +} + +#elif defined(__SUNPRO_CC) + +/* Implementation in lock_sparc*.il */ +extern "C" int +NativeCompareAndSwap(volatile jsword *w, jsword ov, jsword nv); + +#endif + +#elif defined(AIX) + +#include + +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(volatile jsword *w, jsword ov, jsword nv) +{ + int res; + JS_STATIC_ASSERT(sizeof(jsword) == sizeof(long)); + + res = compare_and_swaplp((atomic_l)w, &ov, nv); + if (res) + __asm__("isync"); + return res; +} + +#elif defined(USE_ARM_KUSER) + +/* See https://bugzilla.mozilla.org/show_bug.cgi?id=429387 for a + * description of this ABI; this is a function provided at a fixed + * location by the kernel in the memory space of each process. + */ +typedef int (__kernel_cmpxchg_t)(int oldval, int newval, volatile int *ptr); +#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0) + +JS_STATIC_ASSERT(sizeof(jsword) == sizeof(int)); + +static JS_ALWAYS_INLINE int +NativeCompareAndSwap(volatile jsword *w, jsword ov, jsword nv) +{ + volatile int *vp = (volatile int *) w; + PRInt32 failed = 1; + + /* Loop until a __kernel_cmpxchg succeeds. See bug 446169 */ + do { + failed = __kernel_cmpxchg(ov, nv, vp); + } while (failed && *vp == ov); + return !failed; +} + +#elif JS_HAS_NATIVE_COMPARE_AND_SWAP + +#error "JS_HAS_NATIVE_COMPARE_AND_SWAP should be 0 if your platform lacks a compare-and-swap instruction." + +#endif /* arch-tests */ + +#if JS_HAS_NATIVE_COMPARE_AND_SWAP + +JSBool +js_CompareAndSwap(volatile jsword *w, jsword ov, jsword nv) +{ + return !!NativeCompareAndSwap(w, ov, nv); +} + +#elif defined(NSPR_LOCK) + +# ifdef __GNUC__ +# warning "js_CompareAndSwap is implemented using NSPR lock" +# endif + +JSBool +js_CompareAndSwap(volatile jsword *w, jsword ov, jsword nv) +{ + int result; + static PRLock *CompareAndSwapLock = JS_NEW_LOCK(); + + JS_ACQUIRE_LOCK(CompareAndSwapLock); + result = (*w == ov); + if (result) + *w = nv; + JS_RELEASE_LOCK(CompareAndSwapLock); + return result; +} + +#else /* !defined(NSPR_LOCK) */ + +#error "NSPR_LOCK should be on when the platform lacks native compare-and-swap." + +#endif + +void +js_AtomicSetMask(volatile jsword *w, jsword mask) +{ + jsword ov, nv; + + do { + ov = *w; + nv = ov | mask; + } while (!js_CompareAndSwap(w, ov, nv)); +} + +void +js_AtomicClearMask(volatile jsword *w, jsword mask) +{ + jsword ov, nv; + + do { + ov = *w; + nv = ov & ~mask; + } while (!js_CompareAndSwap(w, ov, nv)); +} + +#ifndef NSPR_LOCK + +struct JSFatLock { + int susp; + PRLock *slock; + PRCondVar *svar; + JSFatLock *next; + JSFatLock **prevp; +}; + +typedef struct JSFatLockTable { + JSFatLock *free; + JSFatLock *taken; +} JSFatLockTable; + +#define GLOBAL_LOCK_INDEX(id) (((uint32)(jsuword)(id)>>2) & global_locks_mask) + +static void +js_Dequeue(JSThinLock *); + +static PRLock **global_locks; +static uint32 global_lock_count = 1; +static uint32 global_locks_log2 = 0; +static uint32 global_locks_mask = 0; + +static void +js_LockGlobal(void *id) +{ + uint32 i = GLOBAL_LOCK_INDEX(id); + PR_Lock(global_locks[i]); +} + +static void +js_UnlockGlobal(void *id) +{ + uint32 i = GLOBAL_LOCK_INDEX(id); + PR_Unlock(global_locks[i]); +} + +#endif /* !NSPR_LOCK */ + +void +js_InitLock(JSThinLock *tl) +{ +#ifdef NSPR_LOCK + tl->owner = 0; + tl->fat = (JSFatLock*)JS_NEW_LOCK(); +#else + PodZero(tl); +#endif +} + +void +js_FinishLock(JSThinLock *tl) +{ +#ifdef NSPR_LOCK + tl->owner = 0xdeadbeef; + if (tl->fat) + JS_DESTROY_LOCK(((JSLock*)tl->fat)); +#else + JS_ASSERT(tl->owner == 0); + JS_ASSERT(tl->fat == NULL); +#endif +} + +#ifndef NSPR_LOCK + +static JSFatLock * +NewFatlock() +{ + JSFatLock *fl = (JSFatLock *)js_malloc(sizeof(JSFatLock)); /* for now */ + if (!fl) return NULL; + fl->susp = 0; + fl->next = NULL; + fl->prevp = NULL; + fl->slock = PR_NewLock(); + fl->svar = PR_NewCondVar(fl->slock); + return fl; +} + +static void +DestroyFatlock(JSFatLock *fl) +{ + PR_DestroyLock(fl->slock); + PR_DestroyCondVar(fl->svar); + js_free(fl); +} + +static JSFatLock * +ListOfFatlocks(int listc) +{ + JSFatLock *m; + JSFatLock *m0; + int i; + + JS_ASSERT(listc>0); + m0 = m = NewFatlock(); + for (i=1; inext = NewFatlock(); + m = m->next; + } + return m0; +} + +static void +DeleteListOfFatlocks(JSFatLock *m) +{ + JSFatLock *m0; + for (; m; m=m0) { + m0 = m->next; + DestroyFatlock(m); + } +} + +static JSFatLockTable *fl_list_table = NULL; +static uint32 fl_list_table_len = 0; +static uint32 fl_list_chunk_len = 0; + +static JSFatLock * +GetFatlock(void *id) +{ + JSFatLock *m; + + uint32 i = GLOBAL_LOCK_INDEX(id); + if (fl_list_table[i].free == NULL) { +#ifdef DEBUG + if (fl_list_table[i].taken) + printf("Ran out of fat locks!\n"); +#endif + fl_list_table[i].free = ListOfFatlocks(fl_list_chunk_len); + } + m = fl_list_table[i].free; + fl_list_table[i].free = m->next; + m->susp = 0; + m->next = fl_list_table[i].taken; + m->prevp = &fl_list_table[i].taken; + if (fl_list_table[i].taken) + fl_list_table[i].taken->prevp = &m->next; + fl_list_table[i].taken = m; + return m; +} + +static void +PutFatlock(JSFatLock *m, void *id) +{ + uint32 i; + if (m == NULL) + return; + + /* Unlink m from fl_list_table[i].taken. */ + *m->prevp = m->next; + if (m->next) + m->next->prevp = m->prevp; + + /* Insert m in fl_list_table[i].free. */ + i = GLOBAL_LOCK_INDEX(id); + m->next = fl_list_table[i].free; + fl_list_table[i].free = m; +} + +#endif /* !NSPR_LOCK */ + +JSBool +js_SetupLocks(int listc, int globc) +{ +#ifndef NSPR_LOCK + uint32 i; + + if (global_locks) + return JS_TRUE; +#ifdef DEBUG + if (listc > 10000 || listc < 0) /* listc == fat lock list chunk length */ + printf("Bad number %d in js_SetupLocks()!\n", listc); + if (globc > 100 || globc < 0) /* globc == number of global locks */ + printf("Bad number %d in js_SetupLocks()!\n", listc); +#endif + global_locks_log2 = JS_CeilingLog2(globc); + global_locks_mask = JS_BITMASK(global_locks_log2); + global_lock_count = JS_BIT(global_locks_log2); + global_locks = (PRLock **) js_malloc(global_lock_count * sizeof(PRLock*)); + if (!global_locks) + return JS_FALSE; + for (i = 0; i < global_lock_count; i++) { + global_locks[i] = PR_NewLock(); + if (!global_locks[i]) { + global_lock_count = i; + js_CleanupLocks(); + return JS_FALSE; + } + } + fl_list_table = (JSFatLockTable *) js_malloc(i * sizeof(JSFatLockTable)); + if (!fl_list_table) { + js_CleanupLocks(); + return JS_FALSE; + } + fl_list_table_len = global_lock_count; + for (i = 0; i < global_lock_count; i++) + fl_list_table[i].free = fl_list_table[i].taken = NULL; + fl_list_chunk_len = listc; +#endif /* !NSPR_LOCK */ + return JS_TRUE; +} + +void +js_CleanupLocks() +{ +#ifndef NSPR_LOCK + uint32 i; + + if (global_locks) { + for (i = 0; i < global_lock_count; i++) + PR_DestroyLock(global_locks[i]); + js_free(global_locks); + global_locks = NULL; + global_lock_count = 1; + global_locks_log2 = 0; + global_locks_mask = 0; + } + if (fl_list_table) { + for (i = 0; i < fl_list_table_len; i++) { + DeleteListOfFatlocks(fl_list_table[i].free); + fl_list_table[i].free = NULL; + DeleteListOfFatlocks(fl_list_table[i].taken); + fl_list_table[i].taken = NULL; + } + js_free(fl_list_table); + fl_list_table = NULL; + fl_list_table_len = 0; + } +#endif /* !NSPR_LOCK */ +} + +#ifdef NSPR_LOCK + +static JS_ALWAYS_INLINE void +ThinLock(JSThinLock *tl, jsword me) +{ + JS_ACQUIRE_LOCK((JSLock *) tl->fat); + tl->owner = me; +} + +static JS_ALWAYS_INLINE void +ThinUnlock(JSThinLock *tl, jsword /*me*/) +{ + tl->owner = 0; + JS_RELEASE_LOCK((JSLock *) tl->fat); +} + +#else + +/* + * Fast locking and unlocking is implemented by delaying the allocation of a + * system lock (fat lock) until contention. As long as a locking thread A + * runs uncontended, the lock is represented solely by storing A's identity in + * the object being locked. + * + * If another thread B tries to lock the object currently locked by A, B is + * enqueued into a fat lock structure (which might have to be allocated and + * pointed to by the object), and suspended using NSPR conditional variables + * (wait). A wait bit (Bacon bit) is set in the lock word of the object, + * signalling to A that when releasing the lock, B must be dequeued and + * notified. + * + * The basic operation of the locking primitives (js_Lock, js_Unlock, + * js_Enqueue, and js_Dequeue) is compare-and-swap. Hence, when locking into + * the word pointed at by p, compare-and-swap(p, 0, A) success implies that p + * is unlocked. Similarly, when unlocking p, if compare-and-swap(p, A, 0) + * succeeds this implies that p is uncontended (no one is waiting because the + * wait bit is not set). + * + * When dequeueing, the lock is released, and one of the threads suspended on + * the lock is notified. If other threads still are waiting, the wait bit is + * kept (in js_Enqueue), and if not, the fat lock is deallocated. + * + * The functions js_Enqueue, js_Dequeue, js_SuspendThread, and js_ResumeThread + * are serialized using a global lock. For scalability, a hashtable of global + * locks is used, which is indexed modulo the thin lock pointer. + */ + +/* + * Invariants: + * (i) global lock is held + * (ii) fl->susp >= 0 + */ +static int +js_SuspendThread(JSThinLock *tl) +{ + JSFatLock *fl; + PRStatus stat; + + if (tl->fat == NULL) + fl = tl->fat = GetFatlock(tl); + else + fl = tl->fat; + JS_ASSERT(fl->susp >= 0); + fl->susp++; + PR_Lock(fl->slock); + js_UnlockGlobal(tl); + stat = PR_WaitCondVar(fl->svar, PR_INTERVAL_NO_TIMEOUT); + JS_ASSERT(stat != PR_FAILURE); + PR_Unlock(fl->slock); + js_LockGlobal(tl); + fl->susp--; + if (fl->susp == 0) { + PutFatlock(fl, tl); + tl->fat = NULL; + } + return tl->fat == NULL; +} + +/* + * (i) global lock is held + * (ii) fl->susp > 0 + */ +static void +js_ResumeThread(JSThinLock *tl) +{ + JSFatLock *fl = tl->fat; + PRStatus stat; + + JS_ASSERT(fl != NULL); + JS_ASSERT(fl->susp > 0); + PR_Lock(fl->slock); + js_UnlockGlobal(tl); + stat = PR_NotifyCondVar(fl->svar); + JS_ASSERT(stat != PR_FAILURE); + PR_Unlock(fl->slock); +} + +static void +js_Enqueue(JSThinLock *tl, jsword me) +{ + jsword o, n; + + js_LockGlobal(tl); + for (;;) { + o = ReadWord(tl->owner); + n = Thin_SetWait(o); + if (o != 0 && NativeCompareAndSwap(&tl->owner, o, n)) { + if (js_SuspendThread(tl)) + me = Thin_RemoveWait(me); + else + me = Thin_SetWait(me); + } + else if (NativeCompareAndSwap(&tl->owner, 0, me)) { + js_UnlockGlobal(tl); + return; + } + } +} + +static void +js_Dequeue(JSThinLock *tl) +{ + jsword o; + + js_LockGlobal(tl); + o = ReadWord(tl->owner); + JS_ASSERT(Thin_GetWait(o) != 0); + JS_ASSERT(tl->fat != NULL); + if (!NativeCompareAndSwap(&tl->owner, o, 0)) /* release it */ + JS_ASSERT(0); + js_ResumeThread(tl); +} + +static JS_ALWAYS_INLINE void +ThinLock(JSThinLock *tl, jsword me) +{ + JS_ASSERT(CURRENT_THREAD_IS_ME(me)); + if (NativeCompareAndSwap(&tl->owner, 0, me)) + return; + if (Thin_RemoveWait(ReadWord(tl->owner)) != me) + js_Enqueue(tl, me); +#ifdef DEBUG + else + JS_ASSERT(0); +#endif +} + +static JS_ALWAYS_INLINE void +ThinUnlock(JSThinLock *tl, jsword me) +{ + JS_ASSERT(CURRENT_THREAD_IS_ME(me)); + + /* + * Since we can race with the NativeCompareAndSwap in js_Enqueue, we need + * to use a C_A_S here as well -- Arjan van de Ven 30/1/08 + */ + if (NativeCompareAndSwap(&tl->owner, me, 0)) + return; + + JS_ASSERT(Thin_GetWait(tl->owner)); + if (Thin_RemoveWait(ReadWord(tl->owner)) == me) + js_Dequeue(tl); +#ifdef DEBUG + else + JS_ASSERT(0); /* unbalanced unlock */ +#endif +} + +#endif /* !NSPR_LOCK */ + +void +js_Lock(JSContext *cx, JSThinLock *tl) +{ + ThinLock(tl, CX_THINLOCK_ID(cx)); +} + +void +js_Unlock(JSContext *cx, JSThinLock *tl) +{ + ThinUnlock(tl, CX_THINLOCK_ID(cx)); +} + +void +js_LockRuntime(JSRuntime *rt) +{ + PR_Lock(rt->rtLock); +#ifdef DEBUG + rt->rtLockOwner = js_CurrentThreadId(); +#endif +} + +void +js_UnlockRuntime(JSRuntime *rt) +{ +#ifdef DEBUG + rt->rtLockOwner = NULL; +#endif + PR_Unlock(rt->rtLock); +} + +#ifdef DEBUG +JSBool +js_IsRuntimeLocked(JSRuntime *rt) +{ + return js_CurrentThreadId() == rt->rtLockOwner; +} +#endif /* DEBUG */ +#endif /* JS_THREADSAFE */ diff --git a/js/src/jslock.h b/js/src/jslock.h new file mode 100644 index 0000000..d3b9067 --- /dev/null +++ b/js/src/jslock.h @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef jslock_h__ +#define jslock_h__ + +#include "jstypes.h" +#include "jsapi.h" +#include "jsprvtd.h" + +#ifdef JS_THREADSAFE +# include "pratom.h" +# include "prlock.h" +# include "prcvar.h" +# include "prthread.h" +#endif + +JS_BEGIN_EXTERN_C + +#ifdef JS_THREADSAFE + +#if (defined(_WIN32) && defined(_M_IX86)) || \ + (defined(_WIN64) && (defined(_M_AMD64) || defined(_M_X64))) || \ + (defined(__i386) && (defined(__GNUC__) || defined(__SUNPRO_CC))) || \ + (defined(__x86_64) && (defined(__GNUC__) || defined(__SUNPRO_CC))) || \ + (defined(__sparc) && (defined(__GNUC__) || defined(__SUNPRO_CC))) || \ + defined(AIX) || \ + defined(USE_ARM_KUSER) +# define JS_HAS_NATIVE_COMPARE_AND_SWAP 1 +#else +# define JS_HAS_NATIVE_COMPARE_AND_SWAP 0 +#endif + +#if defined(JS_USE_ONLY_NSPR_LOCKS) || !JS_HAS_NATIVE_COMPARE_AND_SWAP +# define NSPR_LOCK 1 +#else +# undef NSPR_LOCK +#endif + +#define Thin_GetWait(W) ((jsword)(W) & 0x1) +#define Thin_SetWait(W) ((jsword)(W) | 0x1) +#define Thin_RemoveWait(W) ((jsword)(W) & ~0x1) + +typedef struct JSFatLock JSFatLock; + +typedef struct JSThinLock { + jsword owner; + JSFatLock *fat; +} JSThinLock; + +#define CX_THINLOCK_ID(cx) ((jsword)(cx)->thread) +#define CURRENT_THREAD_IS_ME(me) (((JSThread *)me)->id == js_CurrentThreadId()) + +typedef PRLock JSLock; + +/* + * Atomic increment and decrement for a reference counter, given jsrefcount *p. + * NB: jsrefcount is int32, aka PRInt32, so that pratom.h functions work. + */ +#define JS_ATOMIC_INCREMENT(p) PR_AtomicIncrement((PRInt32 *)(p)) +#define JS_ATOMIC_DECREMENT(p) PR_AtomicDecrement((PRInt32 *)(p)) +#define JS_ATOMIC_ADD(p,v) PR_AtomicAdd((PRInt32 *)(p), (PRInt32)(v)) +#define JS_ATOMIC_SET(p,v) PR_AtomicSet((PRInt32 *)(p), (PRInt32)(v)) + +#define js_CurrentThreadId() PR_GetCurrentThread() +#define JS_NEW_LOCK() PR_NewLock() +#define JS_DESTROY_LOCK(l) PR_DestroyLock(l) +#define JS_ACQUIRE_LOCK(l) PR_Lock(l) +#define JS_RELEASE_LOCK(l) PR_Unlock(l) + +#define JS_NEW_CONDVAR(l) PR_NewCondVar(l) +#define JS_DESTROY_CONDVAR(cv) PR_DestroyCondVar(cv) +#define JS_WAIT_CONDVAR(cv,to) PR_WaitCondVar(cv,to) +#define JS_NO_TIMEOUT PR_INTERVAL_NO_TIMEOUT +#define JS_NOTIFY_CONDVAR(cv) PR_NotifyCondVar(cv) +#define JS_NOTIFY_ALL_CONDVAR(cv) PR_NotifyAllCondVar(cv) + +#define JS_LOCK(cx, tl) js_Lock(cx, tl) +#define JS_UNLOCK(cx, tl) js_Unlock(cx, tl) + +#define JS_LOCK_RUNTIME(rt) js_LockRuntime(rt) +#define JS_UNLOCK_RUNTIME(rt) js_UnlockRuntime(rt) + +extern void js_Lock(JSContext *cx, JSThinLock *tl); +extern void js_Unlock(JSContext *cx, JSThinLock *tl); +extern void js_LockRuntime(JSRuntime *rt); +extern void js_UnlockRuntime(JSRuntime *rt); +extern int js_SetupLocks(int,int); +extern void js_CleanupLocks(); +extern void js_InitLock(JSThinLock *); +extern void js_FinishLock(JSThinLock *); + +#ifdef DEBUG + +#define JS_IS_RUNTIME_LOCKED(rt) js_IsRuntimeLocked(rt) + +extern JSBool js_IsRuntimeLocked(JSRuntime *rt); + +#else + +#define JS_IS_RUNTIME_LOCKED(rt) 0 + +#endif /* DEBUG */ + +#else /* !JS_THREADSAFE */ + +#define JS_ATOMIC_INCREMENT(p) (++*(p)) +#define JS_ATOMIC_DECREMENT(p) (--*(p)) +#define JS_ATOMIC_ADD(p,v) (*(p) += (v)) +#define JS_ATOMIC_SET(p,v) (*(p) = (v)) + +#define JS_CurrentThreadId() 0 +#define JS_NEW_LOCK() NULL +#define JS_DESTROY_LOCK(l) ((void)0) +#define JS_ACQUIRE_LOCK(l) ((void)0) +#define JS_RELEASE_LOCK(l) ((void)0) +#define JS_LOCK(cx, tl) ((void)0) +#define JS_UNLOCK(cx, tl) ((void)0) + +#define JS_NEW_CONDVAR(l) NULL +#define JS_DESTROY_CONDVAR(cv) ((void)0) +#define JS_WAIT_CONDVAR(cv,to) ((void)0) +#define JS_NOTIFY_CONDVAR(cv) ((void)0) +#define JS_NOTIFY_ALL_CONDVAR(cv) ((void)0) + +#define JS_LOCK_RUNTIME(rt) ((void)0) +#define JS_UNLOCK_RUNTIME(rt) ((void)0) + +#define JS_IS_RUNTIME_LOCKED(rt) 1 + +#endif /* !JS_THREADSAFE */ + +#define JS_LOCK_RUNTIME_VOID(rt,e) \ + JS_BEGIN_MACRO \ + JS_LOCK_RUNTIME(rt); \ + e; \ + JS_UNLOCK_RUNTIME(rt); \ + JS_END_MACRO + +#define JS_LOCK_GC(rt) JS_ACQUIRE_LOCK((rt)->gcLock) +#define JS_UNLOCK_GC(rt) JS_RELEASE_LOCK((rt)->gcLock) +#define JS_AWAIT_GC_DONE(rt) JS_WAIT_CONDVAR((rt)->gcDone, JS_NO_TIMEOUT) +#define JS_NOTIFY_GC_DONE(rt) JS_NOTIFY_ALL_CONDVAR((rt)->gcDone) +#define JS_AWAIT_REQUEST_DONE(rt) JS_WAIT_CONDVAR((rt)->requestDone, \ + JS_NO_TIMEOUT) +#define JS_NOTIFY_REQUEST_DONE(rt) JS_NOTIFY_CONDVAR((rt)->requestDone) + +#ifndef JS_SET_OBJ_INFO +#define JS_SET_OBJ_INFO(obj,f,l) ((void)0) +#endif +#ifndef JS_SET_TITLE_INFO +#define JS_SET_TITLE_INFO(title,f,l) ((void)0) +#endif + +#ifdef JS_THREADSAFE + +extern JSBool +js_CompareAndSwap(volatile jsword *w, jsword ov, jsword nv); + +/* Atomically bitwise-or the mask into the word *w using compare and swap. */ +extern void +js_AtomicSetMask(volatile jsword *w, jsword mask); + +/* + * Atomically bitwise-and the complement of the mask into the word *w using + * compare and swap. + */ +extern void +js_AtomicClearMask(volatile jsword *w, jsword mask); + +#define JS_ATOMIC_SET_MASK(w, mask) js_AtomicSetMask(w, mask) +#define JS_ATOMIC_CLEAR_MASK(w, mask) js_AtomicClearMask(w, mask) + +#else + +static inline JSBool +js_CompareAndSwap(jsword *w, jsword ov, jsword nv) +{ + return (*w == ov) ? *w = nv, JS_TRUE : JS_FALSE; +} + +#define JS_ATOMIC_SET_MASK(w, mask) (*(w) |= (mask)) +#define JS_ATOMIC_CLEAR_MASK(w, mask) (*(w) &= ~(mask)) + +#endif /* JS_THREADSAFE */ + +JS_END_EXTERN_C + +#if defined JS_THREADSAFE && defined __cplusplus +namespace js { + +class AutoLock { + private: + JSLock *lock; + + public: + AutoLock(JSLock *lock) : lock(lock) { JS_ACQUIRE_LOCK(lock); } + ~AutoLock() { JS_RELEASE_LOCK(lock); } +}; + +} +#endif + +#endif /* jslock_h___ */ diff --git a/js/src/jslocko.asm b/js/src/jslocko.asm new file mode 100644 index 0000000..95353ba --- /dev/null +++ b/js/src/jslocko.asm @@ -0,0 +1,60 @@ +; -*- Mode: asm; tab-width: 8; c-basic-offset: 4 -*- + +; ***** BEGIN LICENSE BLOCK ***** +; Version: MPL 1.1/GPL 2.0/LGPL 2.1 +; +; The contents of this file are subject to the Mozilla Public License Version +; 1.1 (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.mozilla.org/MPL/ +; +; Software distributed under the License is distributed on an "AS IS" basis, +; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +; for the specific language governing rights and limitations under the +; License. +; +; The Original Code is an OS/2 implementation of js_CompareAndSwap in assembly. +; +; The Initial Developer of the Original Code is +; IBM Corporation. +; Portions created by the Initial Developer are Copyright (C) 2001 +; the Initial Developer. All Rights Reserved. +; +; Contributor(s): +; +; Alternatively, the contents of this file may be used under the terms of +; either the GNU General Public License Version 2 or later (the "GPL"), or +; the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +; in which case the provisions of the GPL or the LGPL are applicable instead +; of those above. If you wish to allow use of your version of this file only +; under the terms of either the GPL or the LGPL, and not to allow others to +; use your version of this file under the terms of the MPL, indicate your +; decision by deleting the provisions above and replace them with the notice +; and other provisions required by the GPL or the LGPL. If you do not delete +; the provisions above, a recipient may use your version of this file under +; the terms of any one of the MPL, the GPL or the LGPL. +; +; ***** END LICENSE BLOCK ***** + + .486P + .MODEL FLAT, OPTLINK + .STACK + + .CODE + +;;;--------------------------------------------------------------------- +;;; int _Optlink js_CompareAndSwap(jsword *w, jsword ov, jsword nv) +;;;--------------------------------------------------------------------- +js_CompareAndSwap PROC OPTLINK EXPORT + push ebx + mov ebx, eax + mov eax, edx + mov edx, ebx + lock cmpxchg [ebx], ecx + sete al + and eax, 1h + pop ebx + ret +js_CompareAndSwap endp + + END diff --git a/js/src/jslog2.cpp b/js/src/jslog2.cpp new file mode 100644 index 0000000..5241a97 --- /dev/null +++ b/js/src/jslog2.cpp @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsstdint.h" +#include "jsbit.h" +#include "jsutil.h" + +/* + * Check that we can use js_bitscan_clz32 to implement JS_FLOOR_LOG2 and + * JS_FLOOR_LOG2W and js_bitscan_clz64 to implement JS_FLOOR_LOG2W on 64-bit + * systems. + */ +#ifdef JS_HAS_BUILTIN_BITSCAN32 +JS_STATIC_ASSERT(sizeof(unsigned int) == sizeof(JSUint32)); +JS_STATIC_ASSERT_IF(JS_BYTES_PER_WORD == 4, + sizeof(unsigned int) == sizeof(JSUword)); +#endif +#ifdef JS_HAS_BUILTIN_BITSCAN64 +JS_STATIC_ASSERT_IF(JS_BYTES_PER_WORD == 8, + sizeof(unsigned long long) == sizeof(JSUword)); +#endif + +/* + * Compute the log of the least power of 2 greater than or equal to n + */ +JS_PUBLIC_API(JSIntn) +JS_CeilingLog2(JSUint32 n) +{ + JSIntn log2; + + JS_CEILING_LOG2(log2, n); + return log2; +} + +/* + * Compute the log of the greatest power of 2 less than or equal to n. + * This really just finds the highest set bit in the word. + */ +JS_PUBLIC_API(JSIntn) +JS_FloorLog2(JSUint32 n) +{ + JSIntn log2; + + JS_FLOOR_LOG2(log2, n); + return log2; +} + +/* + * js_FloorLog2wImpl has to be defined only for 64-bit non-GCC case. + */ +#if !defined(JS_HAS_BUILTIN_BITSCAN64) && JS_BYTES_PER_WORD == 8 + +size_t +js_FloorLog2wImpl(size_t n) +{ + size_t log2, m; + + JS_ASSERT(n != 0); + + log2 = 0; + m = n >> 32; + if (m != 0) { n = m; log2 = 32; } + m = n >> 16; + if (m != 0) { n = m; log2 |= 16; } + m = n >> 8; + if (m != 0) { n = m; log2 |= 8; } + m = n >> 4; + if (m != 0) { n = m; log2 |= 4; } + m = n >> 2; + if (m != 0) { n = m; log2 |= 2; } + log2 |= (n >> 1); + + return log2; +} + +#endif diff --git a/js/src/jslong.h b/js/src/jslong.h new file mode 100644 index 0000000..4a1fccc --- /dev/null +++ b/js/src/jslong.h @@ -0,0 +1,167 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: jslong.h +** Description: Portable access to 64 bit numerics +** +** Long-long (64-bit signed integer type) support. Some C compilers +** don't support 64 bit integers yet, so we use these macros to +** support both machines that do and don't. +**/ +#ifndef jslong_h___ +#define jslong_h___ + +#include "jstypes.h" + +JS_BEGIN_EXTERN_C + +#define JSLL_INIT(hi, lo) ((((JSInt64)(hi)) << 32) + (JSInt64)(lo)) + +/*********************************************************************** +** MACROS: JSLL_* +** DESCRIPTION: +** The following macros define portable access to the 64 bit +** math facilities. +** +***********************************************************************/ + +/*********************************************************************** +** MACROS: JSLL_ +** +** JSLL_IS_ZERO Test for zero +** JSLL_EQ Test for equality +** JSLL_NE Test for inequality +** JSLL_GE_ZERO Test for zero or positive +** JSLL_CMP Compare two values +***********************************************************************/ +#define JSLL_IS_ZERO(a) ((a) == 0) +#define JSLL_EQ(a, b) ((a) == (b)) +#define JSLL_NE(a, b) ((a) != (b)) +#define JSLL_GE_ZERO(a) ((a) >= 0) +#define JSLL_CMP(a, op, b) ((JSInt64)(a) op (JSInt64)(b)) +#define JSLL_UCMP(a, op, b) ((JSUint64)(a) op (JSUint64)(b)) + +/*********************************************************************** +** MACROS: JSLL_ +** +** JSLL_AND Logical and +** JSLL_OR Logical or +** JSLL_XOR Logical exclusion +** JSLL_OR2 A disgusting deviation +** JSLL_NOT Negation (one's compliment) +***********************************************************************/ +#define JSLL_AND(r, a, b) ((r) = (a) & (b)) +#define JSLL_OR(r, a, b) ((r) = (a) | (b)) +#define JSLL_XOR(r, a, b) ((r) = (a) ^ (b)) +#define JSLL_OR2(r, a) ((r) = (r) | (a)) +#define JSLL_NOT(r, a) ((r) = ~(a)) + +/*********************************************************************** +** MACROS: JSLL_ +** +** JSLL_NEG Negation (two's compliment) +** JSLL_ADD Summation (two's compliment) +** JSLL_SUB Difference (two's compliment) +***********************************************************************/ +#define JSLL_NEG(r, a) ((r) = -(a)) +#define JSLL_ADD(r, a, b) ((r) = (a) + (b)) +#define JSLL_SUB(r, a, b) ((r) = (a) - (b)) + +/*********************************************************************** +** MACROS: JSLL_ +** +** JSLL_MUL Product (two's compliment) +** JSLL_DIV Quotient (two's compliment) +** JSLL_MOD Modulus (two's compliment) +***********************************************************************/ +#define JSLL_MUL(r, a, b) ((r) = (a) * (b)) +#define JSLL_DIV(r, a, b) ((r) = (a) / (b)) +#define JSLL_MOD(r, a, b) ((r) = (a) % (b)) + +/*********************************************************************** +** MACROS: JSLL_ +** +** JSLL_SHL Shift left [0..64] bits +** JSLL_SHR Shift right [0..64] bits with sign extension +** JSLL_USHR Unsigned shift right [0..64] bits +** JSLL_ISHL Signed shift left [0..64] bits +***********************************************************************/ +#define JSLL_SHL(r, a, b) ((r) = (JSInt64)(a) << (b)) +#define JSLL_SHR(r, a, b) ((r) = (JSInt64)(a) >> (b)) +#define JSLL_USHR(r, a, b) ((r) = (JSUint64)(a) >> (b)) +#define JSLL_ISHL(r, a, b) ((r) = (JSInt64)(a) << (b)) + +/*********************************************************************** +** MACROS: JSLL_ +** +** JSLL_L2I Convert to signed 32 bit +** JSLL_L2UI Convert to unsigned 32 bit +** JSLL_L2F Convert to floating point +** JSLL_L2D Convert to floating point +** JSLL_I2L Convert signed to 64 bit +** JSLL_UI2L Convert unsigned to 64 bit +** JSLL_F2L Convert float to 64 bit +** JSLL_D2L Convert float to 64 bit +***********************************************************************/ +#define JSLL_L2I(i, l) ((i) = (JSInt32)(l)) +#define JSLL_L2UI(ui, l) ((ui) = (JSUint32)(l)) +#define JSLL_L2F(f, l) ((f) = (JSFloat64)(l)) +#define JSLL_L2D(d, l) ((d) = (JSFloat64)(l)) + +#define JSLL_I2L(l, i) ((l) = (JSInt64)(i)) +#define JSLL_UI2L(l, ui) ((l) = (JSInt64)(ui)) +#define JSLL_F2L(l, f) ((l) = (JSInt64)(f)) +#define JSLL_D2L(l, d) ((l) = (JSInt64)(d)) + +/*********************************************************************** +** MACROS: JSLL_UDIVMOD +** DESCRIPTION: +** Produce both a quotient and a remainder given an unsigned +** INPUTS: JSUint64 a: The dividend of the operation +** JSUint64 b: The quotient of the operation +** OUTPUTS: JSUint64 *qp: pointer to quotient +** JSUint64 *rp: pointer to remainder +***********************************************************************/ +#define JSLL_UDIVMOD(qp, rp, a, b) \ + (*(qp) = ((JSUint64)(a) / (b)), \ + *(rp) = ((JSUint64)(a) % (b))) + +JS_END_EXTERN_C + +#endif /* jslong_h___ */ diff --git a/js/src/jsmath.cpp b/js/src/jsmath.cpp new file mode 100644 index 0000000..352dead --- /dev/null +++ b/js/src/jsmath.cpp @@ -0,0 +1,885 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS math package. + */ +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jslong.h" +#include "prmjtime.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jslock.h" +#include "jsmath.h" +#include "jsnum.h" +#include "jslibmath.h" +#include "jscompartment.h" + +using namespace js; + +#ifndef M_E +#define M_E 2.7182818284590452354 +#endif +#ifndef M_LOG2E +#define M_LOG2E 1.4426950408889634074 +#endif +#ifndef M_LOG10E +#define M_LOG10E 0.43429448190325182765 +#endif +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif +#ifndef M_LN10 +#define M_LN10 2.30258509299404568402 +#endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#ifndef M_SQRT2 +#define M_SQRT2 1.41421356237309504880 +#endif +#ifndef M_SQRT1_2 +#define M_SQRT1_2 0.70710678118654752440 +#endif + +static JSConstDoubleSpec math_constants[] = { + {M_E, "E", 0, {0,0,0}}, + {M_LOG2E, "LOG2E", 0, {0,0,0}}, + {M_LOG10E, "LOG10E", 0, {0,0,0}}, + {M_LN2, "LN2", 0, {0,0,0}}, + {M_LN10, "LN10", 0, {0,0,0}}, + {M_PI, "PI", 0, {0,0,0}}, + {M_SQRT2, "SQRT2", 0, {0,0,0}}, + {M_SQRT1_2, "SQRT1_2", 0, {0,0,0}}, + {0,0,0,{0,0,0}} +}; + +MathCache::MathCache() { + memset(table, 0, sizeof(table)); + + /* See comments in lookup(). */ + JS_ASSERT(JSDOUBLE_IS_NEGZERO(-0.0)); + JS_ASSERT(!JSDOUBLE_IS_NEGZERO(+0.0)); + JS_ASSERT(hash(-0.0) != hash(+0.0)); +} + +Class js_MathClass = { + js_Math_str, + JSCLASS_HAS_CACHED_PROTO(JSProto_Math), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub +}; + +JSBool +js_math_abs(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z; + + if (argc == 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; + z = fabs(x); + vp->setNumber(z); + return JS_TRUE; +} + +static JSBool +math_acos(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z; + + if (argc == 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; +#if defined(SOLARIS) && defined(__GNUC__) + if (x < -1 || 1 < x) { + vp->setDouble(js_NaN); + return JS_TRUE; + } +#endif + MathCache *mathCache = GetMathCache(cx); + if (!mathCache) + return JS_FALSE; + z = mathCache->lookup(acos, x); + vp->setDouble(z); + return JS_TRUE; +} + +static JSBool +math_asin(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z; + + if (argc == 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; +#if defined(SOLARIS) && defined(__GNUC__) + if (x < -1 || 1 < x) { + vp->setDouble(js_NaN); + return JS_TRUE; + } +#endif + MathCache *mathCache = GetMathCache(cx); + if (!mathCache) + return JS_FALSE; + z = mathCache->lookup(asin, x); + vp->setDouble(z); + return JS_TRUE; +} + +static JSBool +math_atan(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z; + + if (argc == 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; + MathCache *mathCache = GetMathCache(cx); + if (!mathCache) + return JS_FALSE; + z = mathCache->lookup(atan, x); + vp->setDouble(z); + return JS_TRUE; +} + +static inline jsdouble JS_FASTCALL +math_atan2_kernel(jsdouble x, jsdouble y) +{ +#if defined(_MSC_VER) + /* + * MSVC's atan2 does not yield the result demanded by ECMA when both x + * and y are infinite. + * - The result is a multiple of pi/4. + * - The sign of x determines the sign of the result. + * - The sign of y determines the multiplicator, 1 or 3. + */ + if (JSDOUBLE_IS_INFINITE(x) && JSDOUBLE_IS_INFINITE(y)) { + jsdouble z = js_copysign(M_PI / 4, x); + if (y < 0) + z *= 3; + return z; + } +#endif + +#if defined(SOLARIS) && defined(__GNUC__) + if (x == 0) { + if (JSDOUBLE_IS_NEGZERO(y)) + return js_copysign(M_PI, x); + if (y == 0) + return x; + } +#endif + return atan2(x, y); +} + +static JSBool +math_atan2(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, y, z; + + if (argc <= 1) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; + if (!ValueToNumber(cx, vp[3], &y)) + return JS_FALSE; + z = math_atan2_kernel(x, y); + vp->setDouble(z); + return JS_TRUE; +} + +jsdouble +js_math_ceil_impl(jsdouble x) +{ +#ifdef __APPLE__ + if (x < 0 && x > -1.0) + return js_copysign(0, -1); +#endif + return ceil(x); +} + +JSBool +js_math_ceil(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z; + + if (argc == 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; + z = js_math_ceil_impl(x); + vp->setNumber(z); + return JS_TRUE; +} + +static JSBool +math_cos(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z; + + if (argc == 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; + MathCache *mathCache = GetMathCache(cx); + if (!mathCache) + return JS_FALSE; + z = mathCache->lookup(cos, x); + vp->setDouble(z); + return JS_TRUE; +} + +static double +math_exp_body(double d) +{ +#ifdef _WIN32 + if (!JSDOUBLE_IS_NaN(d)) { + if (d == js_PositiveInfinity) + return js_PositiveInfinity; + if (d == js_NegativeInfinity) + return 0.0; + } +#endif + return exp(d); +} + +static JSBool +math_exp(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z; + + if (argc == 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; + MathCache *mathCache = GetMathCache(cx); + if (!mathCache) + return JS_FALSE; + z = mathCache->lookup(math_exp_body, x); + vp->setNumber(z); + return JS_TRUE; +} + +jsdouble +js_math_floor_impl(jsdouble x) +{ + return floor(x); +} + +JSBool +js_math_floor(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z; + + if (argc == 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; + z = js_math_floor_impl(x); + vp->setNumber(z); + return JS_TRUE; +} + +static JSBool +math_log(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z; + + if (argc == 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; +#if defined(SOLARIS) && defined(__GNUC__) + if (x < 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } +#endif + MathCache *mathCache = GetMathCache(cx); + if (!mathCache) + return JS_FALSE; + z = mathCache->lookup(log, x); + vp->setNumber(z); + return JS_TRUE; +} + +JSBool +js_math_max(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z = js_NegativeInfinity; + Value *argv; + uintN i; + + if (argc == 0) { + vp->setDouble(js_NegativeInfinity); + return JS_TRUE; + } + argv = vp + 2; + for (i = 0; i < argc; i++) { + if (!ValueToNumber(cx, argv[i], &x)) + return JS_FALSE; + if (JSDOUBLE_IS_NaN(x)) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (x == 0 && x == z) { + if (js_copysign(1.0, z) == -1) + z = x; + } else { + z = (x > z) ? x : z; + } + } + vp->setNumber(z); + return JS_TRUE; +} + +JSBool +js_math_min(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z = js_PositiveInfinity; + Value *argv; + uintN i; + + if (argc == 0) { + vp->setDouble(js_PositiveInfinity); + return JS_TRUE; + } + argv = vp + 2; + for (i = 0; i < argc; i++) { + if (!ValueToNumber(cx, argv[i], &x)) + return JS_FALSE; + if (JSDOUBLE_IS_NaN(x)) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (x == 0 && x == z) { + if (js_copysign(1.0, x) == -1) + z = x; + } else { + z = (x < z) ? x : z; + } + } + vp->setNumber(z); + return JS_TRUE; +} + +static jsdouble +powi(jsdouble x, jsint y) +{ + jsuint n = (y < 0) ? -y : y; + jsdouble m = x; + jsdouble p = 1; + while (true) { + if ((n & 1) != 0) p *= m; + n >>= 1; + if (n == 0) { + if (y < 0) { + // Unfortunately, we have to be careful when p has reached + // infinity in the computation, because sometimes the higher + // internal precision in the pow() implementation would have + // given us a finite p. This happens very rarely. + + jsdouble result = 1.0 / p; + return (result == 0 && JSDOUBLE_IS_INFINITE(p)) + ? pow(x, static_cast(y)) // Avoid pow(double, int). + : result; + } + + return p; + } + m *= m; + } +} + +static JSBool +math_pow(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, y, z; + + if (argc <= 1) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; + if (!ValueToNumber(cx, vp[3], &y)) + return JS_FALSE; + /* + * Special case for square roots. Note that pow(x, 0.5) != sqrt(x) + * when x = -0.0, so we have to guard for this. + */ + if (JSDOUBLE_IS_FINITE(x) && x != 0.0) { + if (y == 0.5) { + vp->setNumber(sqrt(x)); + return JS_TRUE; + } + if (y == -0.5) { + vp->setNumber(1.0/sqrt(x)); + return JS_TRUE; + } + } + /* + * Because C99 and ECMA specify different behavior for pow(), + * we need to wrap the libm call to make it ECMA compliant. + */ + if (!JSDOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0)) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + /* pow(x, +-0) is always 1, even for x = NaN. */ + if (y == 0) { + vp->setInt32(1); + return JS_TRUE; + } + + if (vp[3].isInt32()) + z = powi(x, vp[3].toInt32()); + else + z = pow(x, y); + + vp->setNumber(z); + return JS_TRUE; +} + +static const int64 RNG_MULTIPLIER = 0x5DEECE66DLL; +static const int64 RNG_ADDEND = 0xBLL; +static const int64 RNG_MASK = (1LL << 48) - 1; +static const jsdouble RNG_DSCALE = jsdouble(1LL << 53); + +/* + * Math.random() support, lifted from java.util.Random.java. + */ +static inline void +random_setSeed(JSContext *cx, int64 seed) +{ + cx->rngSeed = (seed ^ RNG_MULTIPLIER) & RNG_MASK; +} + +void +js_InitRandom(JSContext *cx) +{ + /* + * Set the seed from current time. Since we have a RNG per context and we often bring + * up several contexts at the same time, we xor in some additional values, namely + * the context and its successor. We don't just use the context because it might be + * possible to reverse engineer the context pointer if one guesses the time right. + */ + random_setSeed(cx, + (PRMJ_Now() / 1000) ^ + int64(cx) ^ + int64(cx->link.next)); +} + +static inline uint64 +random_next(JSContext *cx, int bits) +{ + uint64 nextseed = cx->rngSeed * RNG_MULTIPLIER; + nextseed += RNG_ADDEND; + nextseed &= RNG_MASK; + cx->rngSeed = nextseed; + return nextseed >> (48 - bits); +} + +static inline jsdouble +random_nextDouble(JSContext *cx) +{ + return jsdouble((random_next(cx, 26) << 27) + random_next(cx, 27)) / RNG_DSCALE; +} + +static JSBool +math_random(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble z = random_nextDouble(cx); + vp->setDouble(z); + return JS_TRUE; +} + +#if defined _WIN32 && !defined WINCE && _MSC_VER < 1400 +/* Try to work around apparent _copysign bustage in VC7.x. */ +double +js_copysign(double x, double y) +{ + jsdpun xu, yu; + + xu.d = x; + yu.d = y; + xu.s.hi &= ~JSDOUBLE_HI32_SIGNBIT; + xu.s.hi |= yu.s.hi & JSDOUBLE_HI32_SIGNBIT; + return xu.d; +} +#endif + +jsdouble +js_math_round_impl(jsdouble x) +{ + return js_copysign(floor(x + 0.5), x); +} + +JSBool +js_math_round(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z; + + if (argc == 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; + z = js_copysign(floor(x + 0.5), x); + vp->setNumber(z); + return JS_TRUE; +} + +static JSBool +math_sin(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z; + + if (argc == 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; + MathCache *mathCache = GetMathCache(cx); + if (!mathCache) + return JS_FALSE; + z = mathCache->lookup(sin, x); + vp->setDouble(z); + return JS_TRUE; +} + +static JSBool +math_sqrt(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z; + + if (argc == 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; + MathCache *mathCache = GetMathCache(cx); + if (!mathCache) + return JS_FALSE; + z = mathCache->lookup(sqrt, x); + vp->setDouble(z); + return JS_TRUE; +} + +static JSBool +math_tan(JSContext *cx, uintN argc, Value *vp) +{ + jsdouble x, z; + + if (argc == 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; + MathCache *mathCache = GetMathCache(cx); + if (!mathCache) + return JS_FALSE; + z = mathCache->lookup(tan, x); + vp->setDouble(z); + return JS_TRUE; +} + +#if JS_HAS_TOSOURCE +static JSBool +math_toSource(JSContext *cx, uintN argc, Value *vp) +{ + vp->setString(ATOM_TO_STRING(CLASS_ATOM(cx, Math))); + return JS_TRUE; +} +#endif + +#ifdef JS_TRACER + +#define MATH_BUILTIN_1(name, cfun) \ + static jsdouble FASTCALL name##_tn(MathCache *cache, jsdouble d) { \ + return cache->lookup(cfun, d); \ + } \ + JS_DEFINE_TRCINFO_1(name, \ + (2, (static, DOUBLE, name##_tn, MATHCACHE, DOUBLE, 1, nanojit::ACCSET_NONE))) + +MATH_BUILTIN_1(js_math_abs, fabs) +MATH_BUILTIN_1(math_atan, atan) +MATH_BUILTIN_1(math_sin, sin) +MATH_BUILTIN_1(math_cos, cos) +MATH_BUILTIN_1(math_sqrt, sqrt) +MATH_BUILTIN_1(math_tan, tan) + +static jsdouble FASTCALL +math_acos_tn(MathCache *cache, jsdouble d) +{ +#if defined(SOLARIS) && defined(__GNUC__) + if (d < -1 || 1 < d) { + return js_NaN; + } +#endif + return cache->lookup(acos, d); +} + +static jsdouble FASTCALL +math_asin_tn(MathCache *cache, jsdouble d) +{ +#if defined(SOLARIS) && defined(__GNUC__) + if (d < -1 || 1 < d) { + return js_NaN; + } +#endif + return cache->lookup(asin, d); +} + +static jsdouble FASTCALL +math_exp_tn(MathCache *cache, jsdouble d) +{ + return cache->lookup(math_exp_body, d); +} + +JS_DEFINE_TRCINFO_1(math_exp, + (2, (static, DOUBLE, math_exp_tn, MATHCACHE, DOUBLE, 1, nanojit::ACCSET_NONE))) + +static jsdouble FASTCALL +math_log_tn(MathCache *cache, jsdouble d) +{ +#if defined(SOLARIS) && defined(__GNUC__) + if (d < 0) + return js_NaN; +#endif + return cache->lookup(log, d); +} + +static jsdouble FASTCALL +math_max_tn(jsdouble d, jsdouble p) +{ + if (JSDOUBLE_IS_NaN(d) || JSDOUBLE_IS_NaN(p)) + return js_NaN; + + if (p == 0 && p == d) { + // Max prefers 0.0 to -0.0. + if (js_copysign(1.0, d) == -1) + return p; + return d; + } + return (p > d) ? p : d; +} + +static jsdouble FASTCALL +math_min_tn(jsdouble d, jsdouble p) +{ + if (JSDOUBLE_IS_NaN(d) || JSDOUBLE_IS_NaN(p)) + return js_NaN; + + if (p == 0 && p == d) { + // Min prefers -0.0 to 0.0. + if (js_copysign (1.0, p) == -1) + return p; + return d; + } + return (p < d) ? p : d; +} + +static jsdouble FASTCALL +math_pow_tn(jsdouble d, jsdouble p) +{ + /* + * Special case for square roots. Note that pow(x, 0.5) != sqrt(x) + * when x = -0.0, so we have to guard for this. + */ + if (JSDOUBLE_IS_FINITE(d) && d != 0.0) { + if (p == 0.5) + return sqrt(d); + + if (p == -0.5) + return 1.0/sqrt(d); + } + if (!JSDOUBLE_IS_FINITE(p) && (d == 1.0 || d == -1.0)) + return js_NaN; + if (p == 0) + return 1.0; + int32_t i; + if (JSDOUBLE_IS_INT32(p, &i)) + return powi(d, i); + + return pow(d, p); +} + +static jsdouble FASTCALL +math_random_tn(JSContext *cx) +{ + return random_nextDouble(cx); +} + +static jsdouble FASTCALL +math_round_tn(jsdouble x) +{ + return js_math_round_impl(x); +} + +static jsdouble FASTCALL +math_ceil_tn(jsdouble x) +{ + return js_math_ceil_impl(x); +} + +static jsdouble FASTCALL +math_floor_tn(jsdouble x) +{ + return js_math_floor_impl(x); +} + +JS_DEFINE_TRCINFO_1(math_acos, + (2, (static, DOUBLE, math_acos_tn, MATHCACHE, DOUBLE, 1, nanojit::ACCSET_NONE))) +JS_DEFINE_TRCINFO_1(math_asin, + (2, (static, DOUBLE, math_asin_tn, MATHCACHE, DOUBLE, 1, nanojit::ACCSET_NONE))) +JS_DEFINE_TRCINFO_1(math_atan2, + (2, (static, DOUBLE, math_atan2_kernel, DOUBLE, DOUBLE, 1, nanojit::ACCSET_NONE))) +JS_DEFINE_TRCINFO_1(js_math_floor, + (1, (static, DOUBLE, math_floor_tn, DOUBLE, 1, nanojit::ACCSET_NONE))) +JS_DEFINE_TRCINFO_1(math_log, + (2, (static, DOUBLE, math_log_tn, MATHCACHE, DOUBLE, 1, nanojit::ACCSET_NONE))) +JS_DEFINE_TRCINFO_1(js_math_max, + (2, (static, DOUBLE, math_max_tn, DOUBLE, DOUBLE, 1, nanojit::ACCSET_NONE))) +JS_DEFINE_TRCINFO_1(js_math_min, + (2, (static, DOUBLE, math_min_tn, DOUBLE, DOUBLE, 1, nanojit::ACCSET_NONE))) +JS_DEFINE_TRCINFO_1(math_pow, + (2, (static, DOUBLE, math_pow_tn, DOUBLE, DOUBLE, 1, nanojit::ACCSET_NONE))) +JS_DEFINE_TRCINFO_1(math_random, + (1, (static, DOUBLE, math_random_tn, CONTEXT, 0, nanojit::ACCSET_STORE_ANY))) +JS_DEFINE_TRCINFO_1(js_math_round, + (1, (static, DOUBLE, math_round_tn, DOUBLE, 1, nanojit::ACCSET_NONE))) +JS_DEFINE_TRCINFO_1(js_math_ceil, + (1, (static, DOUBLE, math_ceil_tn, DOUBLE, 1, nanojit::ACCSET_NONE))) + +#endif /* JS_TRACER */ + +static JSFunctionSpec math_static_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, math_toSource, 0, 0), +#endif + JS_TN("abs", js_math_abs, 1, 0, &js_math_abs_trcinfo), + JS_TN("acos", math_acos, 1, 0, &math_acos_trcinfo), + JS_TN("asin", math_asin, 1, 0, &math_asin_trcinfo), + JS_TN("atan", math_atan, 1, 0, &math_atan_trcinfo), + JS_TN("atan2", math_atan2, 2, 0, &math_atan2_trcinfo), + JS_TN("ceil", js_math_ceil, 1, 0, &js_math_ceil_trcinfo), + JS_TN("cos", math_cos, 1, 0, &math_cos_trcinfo), + JS_TN("exp", math_exp, 1, 0, &math_exp_trcinfo), + JS_TN("floor", js_math_floor, 1, 0, &js_math_floor_trcinfo), + JS_TN("log", math_log, 1, 0, &math_log_trcinfo), + JS_TN("max", js_math_max, 2, 0, &js_math_max_trcinfo), + JS_TN("min", js_math_min, 2, 0, &js_math_min_trcinfo), + JS_TN("pow", math_pow, 2, 0, &math_pow_trcinfo), + JS_TN("random", math_random, 0, 0, &math_random_trcinfo), + JS_TN("round", js_math_round, 1, 0, &js_math_round_trcinfo), + JS_TN("sin", math_sin, 1, 0, &math_sin_trcinfo), + JS_TN("sqrt", math_sqrt, 1, 0, &math_sqrt_trcinfo), + JS_TN("tan", math_tan, 1, 0, &math_tan_trcinfo), + JS_FS_END +}; + +bool +js_IsMathFunction(JSNative native) +{ + for (size_t i=0; math_static_methods[i].name != NULL; i++) { + if (native == math_static_methods[i].call) + return true; + } + return false; +} + +JSObject * +js_InitMathClass(JSContext *cx, JSObject *obj) +{ + JSObject *Math; + + Math = JS_NewObject(cx, Jsvalify(&js_MathClass), NULL, obj); + if (!Math) + return NULL; + if (!JS_DefineProperty(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math), + JS_PropertyStub, JS_StrictPropertyStub, 0)) { + return NULL; + } + + if (!JS_DefineFunctions(cx, Math, math_static_methods)) + return NULL; + if (!JS_DefineConstDoubles(cx, Math, math_constants)) + return NULL; + return Math; +} diff --git a/js/src/jsmath.h b/js/src/jsmath.h new file mode 100644 index 0000000..b6e059d --- /dev/null +++ b/js/src/jsmath.h @@ -0,0 +1,123 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsmath_h___ +#define jsmath_h___ + +namespace js { + +typedef double (*UnaryFunType)(double); + +class MathCache +{ + static const unsigned SizeLog2 = 12; + static const unsigned Size = 1 << SizeLog2; + struct Entry { double in; UnaryFunType f; double out; }; + Entry table[Size]; + + public: + MathCache(); + + uintN hash(double x) { + union { double d; struct { uint32 one, two; } s; } u = { x }; + uint32 hash32 = u.s.one ^ u.s.two; + uint16 hash16 = (uint16)(hash32 ^ (hash32 >> 16)); + return (hash16 & (Size - 1)) ^ (hash16 >> (16 - SizeLog2)); + } + + /* + * N.B. lookup uses double-equality. This is only safe if hash() maps +0 + * and -0 to different table entries, which is asserted in MathCache(). + */ + double lookup(UnaryFunType f, double x) { + uintN index = hash(x); + Entry &e = table[index]; + if (e.in == x && e.f == f) + return e.out; + e.in = x; + e.f = f; + return (e.out = f(x)); + } +}; + +} /* namespace js */ + +/* + * JS math functions. + */ + +extern js::Class js_MathClass; + +extern JSObject * +js_InitMathClass(JSContext *cx, JSObject *obj); + +extern bool +js_IsMathFunction(JSNative native); + +extern void +js_InitRandom(JSContext *cx); + +extern JSBool +js_math_abs(JSContext *cx, uintN argc, js::Value *vp); + +extern JSBool +js_math_ceil(JSContext *cx, uintN argc, js::Value *vp); + +extern JSBool +js_math_floor(JSContext *cx, uintN argc, js::Value *vp); + +extern JSBool +js_math_max(JSContext *cx, uintN argc, js::Value *vp); + +extern JSBool +js_math_min(JSContext *cx, uintN argc, js::Value *vp); + +extern JSBool +js_math_round(JSContext *cx, uintN argc, js::Value *vp); + +extern jsdouble +js_math_ceil_impl(jsdouble x); + +extern jsdouble +js_math_floor_impl(jsdouble x); + +extern jsdouble +js_math_round_impl(jsdouble x); + +#endif /* jsmath_h___ */ diff --git a/js/src/jsnativestack.cpp b/js/src/jsnativestack.cpp new file mode 100644 index 0000000..0366d25 --- /dev/null +++ b/js/src/jsnativestack.cpp @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 et sw=4 tw=80: + */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla code. + * + * The Initial Developer of the Original Code is the Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include "jstypes.h" +#include "jsnativestack.h" + +#ifdef XP_WIN +# include "jswin.h" + +#elif defined(XP_OS2) +# define INCL_DOSPROCESS +# include + +#elif defined(XP_MACOSX) || defined(DARWIN) || defined(XP_UNIX) +# include + +# if defined(__FreeBSD__) +# include +# endif + +#else +# error "Unsupported platform" + +#endif + +namespace js { + +#if defined(XP_WIN) && defined(WINCE) + +inline bool +isPageWritable(void *page) +{ + MEMORY_BASIC_INFORMATION memoryInformation; + jsuword result = VirtualQuery(page, &memoryInformation, sizeof(memoryInformation)); + + /* return false on error, including ptr outside memory */ + if (result != sizeof(memoryInformation)) + return false; + + jsuword protect = memoryInformation.Protect & ~(PAGE_GUARD | PAGE_NOCACHE); + return protect == PAGE_READWRITE || + protect == PAGE_WRITECOPY || + protect == PAGE_EXECUTE_READWRITE || + protect == PAGE_EXECUTE_WRITECOPY; +} + +void * +GetNativeStackBase() +{ + /* find the address of this stack frame by taking the address of a local variable */ + bool isGrowingDownward = JS_STACK_GROWTH_DIRECTION < 0; + void *thisFrame = (void *)(&isGrowingDownward); + + static jsuword pageSize = 0; + if (!pageSize) { + SYSTEM_INFO systemInfo; + GetSystemInfo(&systemInfo); + pageSize = systemInfo.dwPageSize; + } + + /* scan all of memory starting from this frame, and return the last writeable page found */ + register char *currentPage = (char *)((jsuword)thisFrame & ~(pageSize - 1)); + if (isGrowingDownward) { + while (currentPage > 0) { + /* check for underflow */ + if (currentPage >= (char *)pageSize) + currentPage -= pageSize; + else + currentPage = 0; + if (!isPageWritable(currentPage)) + return currentPage + pageSize; + } + return 0; + } else { + while (true) { + /* guaranteed to complete because isPageWritable returns false at end of memory */ + currentPage += pageSize; + if (!isPageWritable(currentPage)) + return currentPage; + } + } +} + +#elif defined(XP_WIN) + +void * +GetNativeStackBaseImpl() +{ +# if defined(_M_IX86) && defined(_MSC_VER) + /* + * offset 0x18 from the FS segment register gives a pointer to + * the thread information block for the current thread + */ + NT_TIB* pTib; + __asm { + MOV EAX, FS:[18h] + MOV pTib, EAX + } + return static_cast(pTib->StackBase); + +# elif defined(_M_X64) + PNT_TIB64 pTib = reinterpret_cast(NtCurrentTeb()); + return reinterpret_cast(pTib->StackBase); + +# elif defined(_WIN32) && defined(__GNUC__) + NT_TIB* pTib; + asm ("movl %%fs:0x18, %0\n" : "=r" (pTib)); + return static_cast(pTib->StackBase); + +# endif +} + +#elif defined(SOLARIS) + +#include + +JS_STATIC_ASSERT(JS_STACK_GROWTH_DIRECTION < 0); + +void * +GetNativeStackBaseImpl() +{ + stack_t st; + stack_getbounds(&st); + return static_cast(st.ss_sp) + st.ss_size; +} + +#elif defined(XP_OS2) + +void * +GetNativeStackBaseImpl() +{ + PTIB ptib; + PPIB ppib; + + DosGetInfoBlocks(&ptib, &ppib); + return ptib->tib_pstacklimit; +} + +#elif defined(SOLARIS) + +#include + +void * +GetNativeStackBaseImpl() +{ + stack_t st; + stack_getbounds(&st); + return static_cast(st.ss_sp) + st.ss_size; +} + +#else /* XP_UNIX */ + +void * +GetNativeStackBaseImpl() +{ + pthread_t thread = pthread_self(); +# if defined(XP_MACOSX) || defined(DARWIN) + return pthread_get_stackaddr_np(thread); + +# else + pthread_attr_t sattr; + pthread_attr_init(&sattr); +# if defined(PTHREAD_NP_H) || defined(_PTHREAD_NP_H_) || defined(NETBSD) + /* e.g. on FreeBSD 4.8 or newer, neundorf@kde.org */ + pthread_attr_get_np(thread, &sattr); +# else + /* + * FIXME: this function is non-portable; + * other POSIX systems may have different np alternatives + */ + pthread_getattr_np(thread, &sattr); +# endif + + void *stackBase = 0; + size_t stackSize = 0; +# ifdef DEBUG + int rc = +# endif + pthread_attr_getstack(&sattr, &stackBase, &stackSize); + JS_ASSERT(!rc); + JS_ASSERT(stackBase); + pthread_attr_destroy(&sattr); + +# if JS_STACK_GROWTH_DIRECTION > 0 + return stackBase; +# else + return static_cast(stackBase) + stackSize; +# endif +# endif +} + +#endif /* !XP_WIN */ + +} /* namespace js */ diff --git a/js/src/jsnativestack.h b/js/src/jsnativestack.h new file mode 100644 index 0000000..f8c4991 --- /dev/null +++ b/js/src/jsnativestack.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 et sw=4 tw=80: + */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla code. + * + * The Initial Developer of the Original Code is the Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsnativestack_h__ +#define jsnativestack_h__ + +#include "jspubtd.h" +#include "jsutil.h" + +namespace js { + +extern void * +GetNativeStackBaseImpl(); + +inline jsuword * +GetNativeStackBase() +{ + void *stackBase = GetNativeStackBaseImpl(); + JS_ASSERT(reinterpret_cast(stackBase) % sizeof(void *) == 0); + return static_cast(stackBase); +} + +} /* namespace js */ + +#endif /* jsnativestack_h__ */ diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp new file mode 100644 index 0000000..67f2d6e --- /dev/null +++ b/js/src/jsnum.cpp @@ -0,0 +1,1455 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS number type and wrapper class. + */ +#ifdef XP_OS2 +#define _PC_53 PC_53 +#define _MCW_EM MCW_EM +#define _MCW_PC MCW_PC +#endif +#include +#include +#include +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsutil.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdtoa.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsprf.h" +#include "jsscope.h" +#include "jsstr.h" +#include "jstracer.h" +#include "jsvector.h" + +#include "jsinterpinlines.h" +#include "jsobjinlines.h" +#include "jsstrinlines.h" + +using namespace js; + +#ifndef JS_HAVE_STDINT_H /* Native support is innocent until proven guilty. */ + +JS_STATIC_ASSERT(uint8_t(-1) == UINT8_MAX); +JS_STATIC_ASSERT(uint16_t(-1) == UINT16_MAX); +JS_STATIC_ASSERT(uint32_t(-1) == UINT32_MAX); +JS_STATIC_ASSERT(uint64_t(-1) == UINT64_MAX); + +JS_STATIC_ASSERT(INT8_MAX > INT8_MIN); +JS_STATIC_ASSERT(uint8_t(INT8_MAX) + uint8_t(1) == uint8_t(INT8_MIN)); +JS_STATIC_ASSERT(INT16_MAX > INT16_MIN); +JS_STATIC_ASSERT(uint16_t(INT16_MAX) + uint16_t(1) == uint16_t(INT16_MIN)); +JS_STATIC_ASSERT(INT32_MAX > INT32_MIN); +JS_STATIC_ASSERT(uint32_t(INT32_MAX) + uint32_t(1) == uint32_t(INT32_MIN)); +JS_STATIC_ASSERT(INT64_MAX > INT64_MIN); +JS_STATIC_ASSERT(uint64_t(INT64_MAX) + uint64_t(1) == uint64_t(INT64_MIN)); + +JS_STATIC_ASSERT(INTPTR_MAX > INTPTR_MIN); +JS_STATIC_ASSERT(uintptr_t(INTPTR_MAX) + uintptr_t(1) == uintptr_t(INTPTR_MIN)); +JS_STATIC_ASSERT(uintptr_t(-1) == UINTPTR_MAX); +JS_STATIC_ASSERT(size_t(-1) == SIZE_MAX); +JS_STATIC_ASSERT(PTRDIFF_MAX > PTRDIFF_MIN); +JS_STATIC_ASSERT(ptrdiff_t(PTRDIFF_MAX) == PTRDIFF_MAX); +JS_STATIC_ASSERT(ptrdiff_t(PTRDIFF_MIN) == PTRDIFF_MIN); +JS_STATIC_ASSERT(uintptr_t(PTRDIFF_MAX) + uintptr_t(1) == uintptr_t(PTRDIFF_MIN)); + +#endif /* JS_HAVE_STDINT_H */ + +/* + * If we're accumulating a decimal number and the number is >= 2^53, then the + * fast result from the loop in GetPrefixInteger may be inaccurate. Call + * js_strtod_harder to get the correct answer. + */ +static bool +ComputeAccurateDecimalInteger(JSContext *cx, const jschar *start, const jschar *end, jsdouble *dp) +{ + size_t length = end - start; + char *cstr = static_cast(cx->malloc(length + 1)); + if (!cstr) + return false; + + for (size_t i = 0; i < length; i++) { + char c = char(start[i]); + JS_ASSERT(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')); + cstr[i] = c; + } + cstr[length] = 0; + + char *estr; + int err = 0; + *dp = js_strtod_harder(JS_THREAD_DATA(cx)->dtoaState, cstr, &estr, &err); + if (err == JS_DTOA_ENOMEM) { + JS_ReportOutOfMemory(cx); + cx->free(cstr); + return false; + } + if (err == JS_DTOA_ERANGE && *dp == HUGE_VAL) + *dp = js_PositiveInfinity; + cx->free(cstr); + return true; +} + +class BinaryDigitReader +{ + const int base; /* Base of number; must be a power of 2 */ + int digit; /* Current digit value in radix given by base */ + int digitMask; /* Mask to extract the next bit from digit */ + const jschar *start; /* Pointer to the remaining digits */ + const jschar *end; /* Pointer to first non-digit */ + + public: + BinaryDigitReader(int base, const jschar *start, const jschar *end) + : base(base), digit(0), digitMask(0), start(start), end(end) + { + } + + /* Return the next binary digit from the number, or -1 if done. */ + int nextDigit() { + if (digitMask == 0) { + if (start == end) + return -1; + + int c = *start++; + JS_ASSERT(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')); + if ('0' <= c && c <= '9') + digit = c - '0'; + else if ('a' <= c && c <= 'z') + digit = c - 'a' + 10; + else + digit = c - 'A' + 10; + digitMask = base >> 1; + } + + int bit = (digit & digitMask) != 0; + digitMask >>= 1; + return bit; + } +}; + +/* + * The fast result might also have been inaccurate for power-of-two bases. This + * happens if the addition in value * 2 + digit causes a round-down to an even + * least significant mantissa bit when the first dropped bit is a one. If any + * of the following digits in the number (which haven't been added in yet) are + * nonzero, then the correct action would have been to round up instead of + * down. An example occurs when reading the number 0x1000000000000081, which + * rounds to 0x1000000000000000 instead of 0x1000000000000100. + */ +static jsdouble +ComputeAccurateBinaryBaseInteger(JSContext *cx, const jschar *start, const jschar *end, int base) +{ + BinaryDigitReader bdr(base, start, end); + + /* Skip leading zeroes. */ + int bit; + do { + bit = bdr.nextDigit(); + } while (bit == 0); + + JS_ASSERT(bit == 1); // guaranteed by GetPrefixInteger + + /* Gather the 53 significant bits (including the leading 1). */ + jsdouble value = 1.0; + for (int j = 52; j > 0; j--) { + bit = bdr.nextDigit(); + if (bit < 0) + return value; + value = value * 2 + bit; + } + + /* bit2 is the 54th bit (the first dropped from the mantissa). */ + int bit2 = bdr.nextDigit(); + if (bit2 >= 0) { + jsdouble factor = 2.0; + int sticky = 0; /* sticky is 1 if any bit beyond the 54th is 1 */ + int bit3; + + while ((bit3 = bdr.nextDigit()) >= 0) { + sticky |= bit3; + factor *= 2; + } + value += bit2 & (bit | sticky); + value *= factor; + } + + return value; +} + +namespace js { + +bool +GetPrefixInteger(JSContext *cx, const jschar *start, const jschar *end, int base, + const jschar **endp, jsdouble *dp) +{ + JS_ASSERT(start <= end); + JS_ASSERT(2 <= base && base <= 36); + + const jschar *s = start; + jsdouble d = 0.0; + for (; s < end; s++) { + int digit; + jschar c = *s; + if ('0' <= c && c <= '9') + digit = c - '0'; + else if ('a' <= c && c <= 'z') + digit = c - 'a' + 10; + else if ('A' <= c && c <= 'Z') + digit = c - 'A' + 10; + else + break; + if (digit >= base) + break; + d = d * base + digit; + } + + *endp = s; + *dp = d; + + /* If we haven't reached the limit of integer precision, we're done. */ + if (d < DOUBLE_INTEGRAL_PRECISION_LIMIT) + return true; + + /* + * Otherwise compute the correct integer from the prefix of valid digits + * if we're computing for base ten or a power of two. Don't worry about + * other bases; see 15.1.2.2 step 13. + */ + if (base == 10) + return ComputeAccurateDecimalInteger(cx, start, s, dp); + if ((base & (base - 1)) == 0) + *dp = ComputeAccurateBinaryBaseInteger(cx, start, s, base); + + return true; +} + +} // namespace js + +static JSBool +num_isNaN(JSContext *cx, uintN argc, Value *vp) +{ + if (argc == 0) { + vp->setBoolean(true); + return JS_TRUE; + } + jsdouble x; + if (!ValueToNumber(cx, vp[2], &x)) + return false; + vp->setBoolean(JSDOUBLE_IS_NaN(x)); + return JS_TRUE; +} + +static JSBool +num_isFinite(JSContext *cx, uintN argc, Value *vp) +{ + if (argc == 0) { + vp->setBoolean(false); + return JS_TRUE; + } + jsdouble x; + if (!ValueToNumber(cx, vp[2], &x)) + return JS_FALSE; + vp->setBoolean(JSDOUBLE_IS_FINITE(x)); + return JS_TRUE; +} + +static JSBool +num_parseFloat(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str; + jsdouble d; + const jschar *bp, *end, *ep; + + if (argc == 0) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + str = js_ValueToString(cx, vp[2]); + if (!str) + return JS_FALSE; + bp = str->getChars(cx); + if (!bp) + return JS_FALSE; + end = bp + str->length(); + if (!js_strtod(cx, bp, end, &ep, &d)) + return JS_FALSE; + if (ep == bp) { + vp->setDouble(js_NaN); + return JS_TRUE; + } + vp->setNumber(d); + return JS_TRUE; +} + +#ifdef JS_TRACER +static jsdouble FASTCALL +ParseFloat(JSContext* cx, JSString* str) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + const jschar *bp = str->getChars(cx); + if (!bp) { + SetBuiltinError(tm); + return js_NaN; + } + const jschar *end = bp + str->length(); + + const jschar *ep; + double d; + if (!js_strtod(cx, bp, end, &ep, &d) || ep == bp) + return js_NaN; + return d; +} +#endif + +static bool +ParseIntStringHelper(JSContext *cx, const jschar *ws, const jschar *end, int maybeRadix, + bool stripPrefix, jsdouble *dp) +{ + JS_ASSERT(maybeRadix == 0 || (2 <= maybeRadix && maybeRadix <= 36)); + JS_ASSERT(ws <= end); + + const jschar *s = js_SkipWhiteSpace(ws, end); + JS_ASSERT(ws <= s); + JS_ASSERT(s <= end); + + /* 15.1.2.2 steps 3-4. */ + bool negative = (s != end && s[0] == '-'); + + /* 15.1.2.2 step 5. */ + if (s != end && (s[0] == '-' || s[0] == '+')) + s++; + + /* 15.1.2.2 step 9. */ + int radix = maybeRadix; + if (radix == 0) { + if (end - s >= 2 && s[0] == '0' && (s[1] != 'x' && s[1] != 'X')) { + /* + * Non-standard: ES5 requires that parseInt interpret leading-zero + * strings not starting with "0x" or "0X" as decimal (absent an + * explicitly specified non-zero radix), but we continue to + * interpret such strings as octal, as per ES3 and web practice. + */ + radix = 8; + } else { + radix = 10; + } + } + + /* 15.1.2.2 step 10. */ + if (stripPrefix) { + if (end - s >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { + s += 2; + radix = 16; + } + } + + /* 15.1.2.2 steps 11-14. */ + const jschar *actualEnd; + if (!GetPrefixInteger(cx, s, end, radix, &actualEnd, dp)) + return false; + if (s == actualEnd) + *dp = js_NaN; + else if (negative) + *dp = -*dp; + return true; +} + +static jsdouble +ParseIntDoubleHelper(jsdouble d) +{ + if (!JSDOUBLE_IS_FINITE(d)) + return js_NaN; + if (d > 0) + return floor(d); + if (d < 0) + return -floor(-d); + return 0; +} + +/* See ECMA 15.1.2.2. */ +static JSBool +num_parseInt(JSContext *cx, uintN argc, Value *vp) +{ + /* Fast paths and exceptional cases. */ + if (argc == 0) { + vp->setDouble(js_NaN); + return true; + } + + if (argc == 1 || (vp[3].isInt32() && (vp[3].toInt32() == 0 || vp[3].toInt32() == 10))) { + if (vp[2].isInt32()) { + *vp = vp[2]; + return true; + } + if (vp[2].isDouble()) { + vp->setDouble(ParseIntDoubleHelper(vp[2].toDouble())); + return true; + } + } + + /* Step 1. */ + JSString *inputString = js_ValueToString(cx, vp[2]); + if (!inputString) + return false; + vp[2].setString(inputString); + + /* 15.1.2.2 steps 6-8. */ + bool stripPrefix = true; + int32_t radix = 0; + if (argc > 1) { + if (!ValueToECMAInt32(cx, vp[3], &radix)) + return false; + if (radix != 0) { + if (radix < 2 || radix > 36) { + vp->setDouble(js_NaN); + return true; + } + if (radix != 16) + stripPrefix = false; + } + } + + /* Steps 2-5, 9-14. */ + const jschar *ws = inputString->getChars(cx); + if (!ws) + return false; + const jschar *end = ws + inputString->length(); + + jsdouble number; + if (!ParseIntStringHelper(cx, ws, end, radix, stripPrefix, &number)) + return false; + + /* Step 15. */ + vp->setNumber(number); + return true; +} + +#ifdef JS_TRACER +static jsdouble FASTCALL +ParseInt(JSContext* cx, JSString* str) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + const jschar *start = str->getChars(cx); + if (!start) { + SetBuiltinError(tm); + return js_NaN; + } + const jschar *end = start + str->length(); + + jsdouble d; + if (!ParseIntStringHelper(cx, start, end, 0, true, &d)) { + SetBuiltinError(tm); + return js_NaN; + } + return d; +} + +static jsdouble FASTCALL +ParseIntDouble(jsdouble d) +{ + return ParseIntDoubleHelper(d); +} +#endif + +const char js_Infinity_str[] = "Infinity"; +const char js_NaN_str[] = "NaN"; +const char js_isNaN_str[] = "isNaN"; +const char js_isFinite_str[] = "isFinite"; +const char js_parseFloat_str[] = "parseFloat"; +const char js_parseInt_str[] = "parseInt"; + +#ifdef JS_TRACER + +JS_DEFINE_TRCINFO_2(num_parseInt, + (2, (static, DOUBLE_FAIL, ParseInt, CONTEXT, STRING,1, nanojit::ACCSET_NONE)), + (1, (static, DOUBLE, ParseIntDouble, DOUBLE, 1, nanojit::ACCSET_NONE))) + +JS_DEFINE_TRCINFO_1(num_parseFloat, + (2, (static, DOUBLE_FAIL, ParseFloat, CONTEXT, STRING, 1, nanojit::ACCSET_NONE))) + +#endif /* JS_TRACER */ + +static JSFunctionSpec number_functions[] = { + JS_FN(js_isNaN_str, num_isNaN, 1,0), + JS_FN(js_isFinite_str, num_isFinite, 1,0), + JS_TN(js_parseFloat_str, num_parseFloat, 1,0, &num_parseFloat_trcinfo), + JS_TN(js_parseInt_str, num_parseInt, 2,0, &num_parseInt_trcinfo), + JS_FS_END +}; + +Class js_NumberClass = { + js_Number_str, + JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub +}; + +static JSBool +Number(JSContext *cx, uintN argc, Value *vp) +{ + /* Sample JS_CALLEE before clobbering. */ + bool isConstructing = IsConstructing(vp); + + if (argc > 0) { + if (!ValueToNumber(cx, &vp[2])) + return false; + vp[0] = vp[2]; + } else { + vp[0].setInt32(0); + } + + if (!isConstructing) + return true; + + JSObject *obj = NewBuiltinClassInstance(cx, &js_NumberClass); + if (!obj) + return false; + obj->setPrimitiveThis(vp[0]); + vp->setObject(*obj); + return true; +} + +#if JS_HAS_TOSOURCE +static JSBool +num_toSource(JSContext *cx, uintN argc, Value *vp) +{ + double d; + if (!GetPrimitiveThis(cx, vp, &d)) + return false; + + ToCStringBuf cbuf; + char *numStr = NumberToCString(cx, &cbuf, d); + if (!numStr) { + JS_ReportOutOfMemory(cx); + return false; + } + + char buf[64]; + JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_NumberClass.name, numStr); + JSString *str = js_NewStringCopyZ(cx, buf); + if (!str) + return false; + vp->setString(str); + return true; +} +#endif + +ToCStringBuf::ToCStringBuf() :dbuf(NULL) +{ + JS_STATIC_ASSERT(sbufSize >= DTOSTR_STANDARD_BUFFER_SIZE); +} + +ToCStringBuf::~ToCStringBuf() +{ + if (dbuf) + js_free(dbuf); +} + +JSString * JS_FASTCALL +js_IntToString(JSContext *cx, int32 si) +{ + uint32 ui; + if (si >= 0) { + if (si < INT_STRING_LIMIT) + return JSString::intString(si); + ui = si; + } else { + ui = uint32(-si); + JS_ASSERT_IF(si == INT32_MIN, ui == uint32(INT32_MAX) + 1); + } + + JSCompartment *c = cx->compartment; + if (JSString *str = c->dtoaCache.lookup(10, si)) + return str; + + JSShortString *str = js_NewGCShortString(cx); + if (!str) + return NULL; + + /* +1, since MAX_SHORT_STRING_LENGTH does not count the null char. */ + JS_STATIC_ASSERT(JSShortString::MAX_SHORT_STRING_LENGTH + 1 >= sizeof("-2147483648")); + + jschar *end = str->getInlineStorageBeforeInit() + JSShortString::MAX_SHORT_STRING_LENGTH; + jschar *cp = end; + *cp = 0; + + do { + jsuint newui = ui / 10, digit = ui % 10; /* optimizers are our friends */ + *--cp = '0' + digit; + ui = newui; + } while (ui != 0); + + if (si < 0) + *--cp = '-'; + + str->initAtOffsetInBuffer(cp, end - cp); + + JSString *ret = str->header(); + c->dtoaCache.cache(10, si, ret); + return ret; +} + +/* Returns a non-NULL pointer to inside cbuf. */ +static char * +IntToCString(ToCStringBuf *cbuf, jsint i, jsint base = 10) +{ + char *cp; + jsuint u; + + u = (i < 0) ? -i : i; + + cp = cbuf->sbuf + cbuf->sbufSize; /* one past last buffer cell */ + *--cp = '\0'; /* null terminate the string to be */ + + /* + * Build the string from behind. We use multiply and subtraction + * instead of modulus because that's much faster. + */ + switch (base) { + case 10: + do { + jsuint newu = u / 10; + *--cp = (char)(u - newu * 10) + '0'; + u = newu; + } while (u != 0); + break; + case 16: + do { + jsuint newu = u / 16; + *--cp = "0123456789abcdef"[u - newu * 16]; + u = newu; + } while (u != 0); + break; + default: + JS_ASSERT(base >= 2 && base <= 36); + do { + jsuint newu = u / base; + *--cp = "0123456789abcdefghijklmnopqrstuvwxyz"[u - newu * base]; + u = newu; + } while (u != 0); + break; + } + if (i < 0) + *--cp = '-'; + + JS_ASSERT(cp >= cbuf->sbuf); + return cp; +} + +static JSString * JS_FASTCALL +js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base); + +static JSBool +num_toString(JSContext *cx, uintN argc, Value *vp) +{ + double d; + if (!GetPrimitiveThis(cx, vp, &d)) + return false; + + int32_t base = 10; + if (argc != 0 && !vp[2].isUndefined()) { + if (!ValueToECMAInt32(cx, vp[2], &base)) + return JS_FALSE; + + if (base < 2 || base > 36) { + ToCStringBuf cbuf; + char *numStr = IntToCString(&cbuf, base); /* convert the base itself to a string */ + JS_ASSERT(numStr); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX, + numStr); + return JS_FALSE; + } + } + JSString *str = js_NumberToStringWithBase(cx, d, base); + if (!str) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + vp->setString(str); + return JS_TRUE; +} + +static JSBool +num_toLocaleString(JSContext *cx, uintN argc, Value *vp) +{ + size_t thousandsLength, decimalLength; + const char *numGrouping, *tmpGroup; + JSRuntime *rt; + JSString *str; + const char *num, *end, *tmpSrc; + char *buf, *tmpDest; + const char *nint; + int digits, buflen, remainder, nrepeat; + + /* + * Create the string, move back to bytes to make string twiddling + * a bit easier and so we can insert platform charset seperators. + */ + if (!num_toString(cx, 0, vp)) + return JS_FALSE; + JS_ASSERT(vp->isString()); + JSAutoByteString numBytes(cx, vp->toString()); + if (!numBytes) + return JS_FALSE; + num = numBytes.ptr(); + if (!num) + return JS_FALSE; + + /* + * Find the first non-integer value, whether it be a letter as in + * 'Infinity', a decimal point, or an 'e' from exponential notation. + */ + nint = num; + if (*nint == '-') + nint++; + while (*nint >= '0' && *nint <= '9') + nint++; + digits = nint - num; + end = num + digits; + if (!digits) + return JS_TRUE; + + rt = cx->runtime; + thousandsLength = strlen(rt->thousandsSeparator); + decimalLength = strlen(rt->decimalSeparator); + + /* Figure out how long resulting string will be. */ + buflen = strlen(num); + if (*nint == '.') + buflen += decimalLength - 1; /* -1 to account for existing '.' */ + + numGrouping = tmpGroup = rt->numGrouping; + remainder = digits; + if (*num == '-') + remainder--; + + while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') { + if (*tmpGroup >= remainder) + break; + buflen += thousandsLength; + remainder -= *tmpGroup; + tmpGroup++; + } + if (*tmpGroup == '\0' && *numGrouping != '\0') { + nrepeat = (remainder - 1) / tmpGroup[-1]; + buflen += thousandsLength * nrepeat; + remainder -= nrepeat * tmpGroup[-1]; + } else { + nrepeat = 0; + } + tmpGroup--; + + buf = (char *)cx->malloc(buflen + 1); + if (!buf) + return JS_FALSE; + + tmpDest = buf; + tmpSrc = num; + + while (*tmpSrc == '-' || remainder--) { + JS_ASSERT(tmpDest - buf < buflen); + *tmpDest++ = *tmpSrc++; + } + while (tmpSrc < end) { + JS_ASSERT(tmpDest - buf + ptrdiff_t(thousandsLength) <= buflen); + strcpy(tmpDest, rt->thousandsSeparator); + tmpDest += thousandsLength; + JS_ASSERT(tmpDest - buf + *tmpGroup <= buflen); + memcpy(tmpDest, tmpSrc, *tmpGroup); + tmpDest += *tmpGroup; + tmpSrc += *tmpGroup; + if (--nrepeat < 0) + tmpGroup--; + } + + if (*nint == '.') { + JS_ASSERT(tmpDest - buf + ptrdiff_t(decimalLength) <= buflen); + strcpy(tmpDest, rt->decimalSeparator); + tmpDest += decimalLength; + JS_ASSERT(tmpDest - buf + ptrdiff_t(strlen(nint + 1)) <= buflen); + strcpy(tmpDest, nint + 1); + } else { + JS_ASSERT(tmpDest - buf + ptrdiff_t(strlen(nint)) <= buflen); + strcpy(tmpDest, nint); + } + + if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) { + JSBool ok = cx->localeCallbacks->localeToUnicode(cx, buf, Jsvalify(vp)); + cx->free(buf); + return ok; + } + + str = js_NewStringCopyN(cx, buf, buflen); + cx->free(buf); + if (!str) + return JS_FALSE; + + vp->setString(str); + return JS_TRUE; +} + +JSBool +js_num_valueOf(JSContext *cx, uintN argc, Value *vp) +{ + double d; + if (!GetPrimitiveThis(cx, vp, &d)) + return false; + + vp->setNumber(d); + return true; +} + + +#define MAX_PRECISION 100 + +static JSBool +num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode, + jsint precisionMin, jsint precisionMax, jsint precisionOffset, + uintN argc, Value *vp) +{ + /* Use MAX_PRECISION+1 because precisionOffset can be 1. */ + char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)]; + char *numStr; + + double d; + if (!GetPrimitiveThis(cx, vp, &d)) + return false; + + double precision; + if (argc == 0) { + precision = 0.0; + oneArgMode = zeroArgMode; + } else { + if (!ValueToNumber(cx, vp[2], &precision)) + return JS_FALSE; + precision = js_DoubleToInteger(precision); + if (precision < precisionMin || precision > precisionMax) { + ToCStringBuf cbuf; + numStr = IntToCString(&cbuf, jsint(precision)); + JS_ASSERT(numStr); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr); + return JS_FALSE; + } + } + + numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, sizeof buf, + oneArgMode, (jsint)precision + precisionOffset, d); + if (!numStr) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + JSString *str = js_NewStringCopyZ(cx, numStr); + if (!str) + return JS_FALSE; + vp->setString(str); + return JS_TRUE; +} + +/* + * In the following three implementations, we allow a larger range of precision + * than ECMA requires; this is permitted by ECMA-262. + */ +static JSBool +num_toFixed(JSContext *cx, uintN argc, Value *vp) +{ + return num_to(cx, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0, + argc, vp); +} + +static JSBool +num_toExponential(JSContext *cx, uintN argc, Value *vp) +{ + return num_to(cx, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0, MAX_PRECISION, 1, + argc, vp); +} + +static JSBool +num_toPrecision(JSContext *cx, uintN argc, Value *vp) +{ + if (argc == 0 || vp[2].isUndefined()) + return num_toString(cx, 0, vp); + return num_to(cx, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0, + argc, vp); +} + +#ifdef JS_TRACER + +JS_DEFINE_TRCINFO_2(num_toString, + (2, (extern, STRING_RETRY, js_NumberToString, CONTEXT, THIS_DOUBLE, + 1, nanojit::ACCSET_NONE)), + (3, (static, STRING_RETRY, js_NumberToStringWithBase, CONTEXT, THIS_DOUBLE, INT32, + 1, nanojit::ACCSET_NONE))) + +#endif /* JS_TRACER */ + +static JSFunctionSpec number_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, num_toSource, 0, 0), +#endif + JS_TN(js_toString_str, num_toString, 1, 0, &num_toString_trcinfo), + JS_FN(js_toLocaleString_str, num_toLocaleString, 0, 0), + JS_FN(js_valueOf_str, js_num_valueOf, 0, 0), + JS_FN(js_toJSON_str, js_num_valueOf, 0, 0), + JS_FN("toFixed", num_toFixed, 1, 0), + JS_FN("toExponential", num_toExponential, 1, 0), + JS_FN("toPrecision", num_toPrecision, 1, 0), + JS_FS_END +}; + +/* NB: Keep this in synch with number_constants[]. */ +enum nc_slot { + NC_NaN, + NC_POSITIVE_INFINITY, + NC_NEGATIVE_INFINITY, + NC_MAX_VALUE, + NC_MIN_VALUE, + NC_LIMIT +}; + +/* + * Some to most C compilers forbid spelling these at compile time, or barf + * if you try, so all but MAX_VALUE are set up by js_InitRuntimeNumberState + * using union jsdpun. + */ +static JSConstDoubleSpec number_constants[] = { + {0, js_NaN_str, 0,{0,0,0}}, + {0, "POSITIVE_INFINITY", 0,{0,0,0}}, + {0, "NEGATIVE_INFINITY", 0,{0,0,0}}, + {1.7976931348623157E+308, "MAX_VALUE", 0,{0,0,0}}, + {0, "MIN_VALUE", 0,{0,0,0}}, + {0,0,0,{0,0,0}} +}; + +jsdouble js_NaN; +jsdouble js_PositiveInfinity; +jsdouble js_NegativeInfinity; + +#if (defined __GNUC__ && defined __i386__) || \ + (defined __SUNPRO_CC && defined __i386) + +/* + * Set the exception mask to mask all exceptions and set the FPU precision + * to 53 bit mantissa (64 bit doubles). + */ +inline void FIX_FPU() { + short control; + asm("fstcw %0" : "=m" (control) : ); + control &= ~0x300; // Lower bits 8 and 9 (precision control). + control |= 0x2f3; // Raise bits 0-5 (exception masks) and 9 (64-bit precision). + asm("fldcw %0" : : "m" (control) ); +} + +#else + +#define FIX_FPU() ((void)0) + +#endif + +JSBool +js_InitRuntimeNumberState(JSContext *cx) +{ + JSRuntime *rt = cx->runtime; + + FIX_FPU(); + + jsdpun u; + u.s.hi = JSDOUBLE_HI32_NAN; + u.s.lo = JSDOUBLE_LO32_NAN; + number_constants[NC_NaN].dval = js_NaN = u.d; + rt->NaNValue.setDouble(u.d); + + u.s.hi = JSDOUBLE_HI32_EXPMASK; + u.s.lo = 0x00000000; + number_constants[NC_POSITIVE_INFINITY].dval = js_PositiveInfinity = u.d; + rt->positiveInfinityValue.setDouble(u.d); + + u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK; + u.s.lo = 0x00000000; + number_constants[NC_NEGATIVE_INFINITY].dval = js_NegativeInfinity = u.d; + rt->negativeInfinityValue.setDouble(u.d); + + u.s.hi = 0; + u.s.lo = 1; + number_constants[NC_MIN_VALUE].dval = u.d; + +#ifndef HAVE_LOCALECONV + const char* thousands_sep = getenv("LOCALE_THOUSANDS_SEP"); + const char* decimal_point = getenv("LOCALE_DECIMAL_POINT"); + const char* grouping = getenv("LOCALE_GROUPING"); + + rt->thousandsSeparator = + JS_strdup(cx, thousands_sep ? thousands_sep : "'"); + rt->decimalSeparator = + JS_strdup(cx, decimal_point ? decimal_point : "."); + rt->numGrouping = + JS_strdup(cx, grouping ? grouping : "\3\0"); +#else + struct lconv *locale = localeconv(); + rt->thousandsSeparator = + JS_strdup(cx, locale->thousands_sep ? locale->thousands_sep : "'"); + rt->decimalSeparator = + JS_strdup(cx, locale->decimal_point ? locale->decimal_point : "."); + rt->numGrouping = + JS_strdup(cx, locale->grouping ? locale->grouping : "\3\0"); +#endif + + return rt->thousandsSeparator && rt->decimalSeparator && rt->numGrouping; +} + +void +js_FinishRuntimeNumberState(JSContext *cx) +{ + JSRuntime *rt = cx->runtime; + + cx->free((void *) rt->thousandsSeparator); + cx->free((void *) rt->decimalSeparator); + cx->free((void *) rt->numGrouping); + rt->thousandsSeparator = rt->decimalSeparator = rt->numGrouping = NULL; +} + +JSObject * +js_InitNumberClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto, *ctor; + JSRuntime *rt; + + /* XXX must do at least once per new thread, so do it per JSContext... */ + FIX_FPU(); + + if (!JS_DefineFunctions(cx, obj, number_functions)) + return NULL; + + proto = js_InitClass(cx, obj, NULL, &js_NumberClass, Number, 1, + NULL, number_methods, NULL, NULL); + if (!proto || !(ctor = JS_GetConstructor(cx, proto))) + return NULL; + proto->setPrimitiveThis(Int32Value(0)); + if (!JS_DefineConstDoubles(cx, ctor, number_constants)) + return NULL; + + /* ECMA 15.1.1.1 */ + rt = cx->runtime; + if (!JS_DefineProperty(cx, obj, js_NaN_str, Jsvalify(rt->NaNValue), + JS_PropertyStub, JS_StrictPropertyStub, + JSPROP_PERMANENT | JSPROP_READONLY)) { + return NULL; + } + + /* ECMA 15.1.1.2 */ + if (!JS_DefineProperty(cx, obj, js_Infinity_str, Jsvalify(rt->positiveInfinityValue), + JS_PropertyStub, JS_StrictPropertyStub, + JSPROP_PERMANENT | JSPROP_READONLY)) { + return NULL; + } + return proto; +} + +namespace v8 { +namespace internal { +extern char* DoubleToCString(double v, char* buffer, int buflen); +} +} + +namespace js { + +static char * +FracNumberToCString(JSContext *cx, ToCStringBuf *cbuf, jsdouble d, jsint base = 10) +{ +#ifdef DEBUG + { + int32_t _; + JS_ASSERT(!JSDOUBLE_IS_INT32(d, &_)); + } +#endif + + char* numStr; + if (base == 10) { + /* + * This is V8's implementation of the algorithm described in the + * following paper: + * + * Printing floating-point numbers quickly and accurately with integers. + * Florian Loitsch, PLDI 2010. + * + * It fails on a small number of cases, whereupon we fall back to + * js_dtostr() (which uses David Gay's dtoa). + */ + numStr = v8::internal::DoubleToCString(d, cbuf->sbuf, cbuf->sbufSize); + if (!numStr) + numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, cbuf->sbuf, cbuf->sbufSize, + DTOSTR_STANDARD, 0, d); + } else { + numStr = cbuf->dbuf = js_dtobasestr(JS_THREAD_DATA(cx)->dtoaState, base, d); + } + return numStr; +} + +char * +NumberToCString(JSContext *cx, ToCStringBuf *cbuf, jsdouble d, jsint base/* = 10*/) +{ + int32_t i; + return (JSDOUBLE_IS_INT32(d, &i)) + ? IntToCString(cbuf, i, base) + : FracNumberToCString(cx, cbuf, d, base); +} + +} + +static JSString * JS_FASTCALL +js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base) +{ + ToCStringBuf cbuf; + char *numStr; + JSString *s; + + /* + * Caller is responsible for error reporting. When called from trace, + * returning NULL here will cause us to fall of trace and then retry + * from the interpreter (which will report the error). + */ + if (base < 2 || base > 36) + return NULL; + + JSCompartment *c = cx->compartment; + + int32_t i; + if (JSDOUBLE_IS_INT32(d, &i)) { + if (base == 10 && jsuint(i) < INT_STRING_LIMIT) + return JSString::intString(i); + if (jsuint(i) < jsuint(base)) { + if (i < 10) + return JSString::intString(i); + return JSString::unitString(jschar('a' + i - 10)); + } + + if (JSString *str = c->dtoaCache.lookup(base, d)) + return str; + + numStr = IntToCString(&cbuf, i, base); + JS_ASSERT(!cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize); + } else { + if (JSString *str = c->dtoaCache.lookup(base, d)) + return str; + + numStr = FracNumberToCString(cx, &cbuf, d, base); + if (!numStr) { + JS_ReportOutOfMemory(cx); + return NULL; + } + JS_ASSERT_IF(base == 10, + !cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize); + JS_ASSERT_IF(base != 10, + cbuf.dbuf && cbuf.dbuf == numStr); + } + + s = js_NewStringCopyZ(cx, numStr); + + c->dtoaCache.cache(base, d, s); + return s; +} + +JSString * JS_FASTCALL +js_NumberToString(JSContext *cx, jsdouble d) +{ + return js_NumberToStringWithBase(cx, d, 10); +} + +namespace js { + +JSFlatString * +NumberToString(JSContext *cx, jsdouble d) +{ + if (JSString *str = js_NumberToStringWithBase(cx, d, 10)) + return str->assertIsFlat(); + return NULL; +} + +bool JS_FASTCALL +NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb) +{ + /* Convert to C-string. */ + ToCStringBuf cbuf; + const char *cstr; + if (v.isInt32()) { + cstr = IntToCString(&cbuf, v.toInt32()); + } else { + cstr = NumberToCString(cx, &cbuf, v.toDouble()); + if (!cstr) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + } + + /* + * Inflate to jschar string. The input C-string characters are < 127, so + * even if jschars are UTF-8, all chars should map to one jschar. + */ + size_t cstrlen = strlen(cstr); + JS_ASSERT(!cbuf.dbuf && cstrlen < cbuf.sbufSize); + return sb.appendInflated(cstr, cstrlen); +} + +bool +ValueToNumberSlow(JSContext *cx, Value v, double *out) +{ + JS_ASSERT(!v.isNumber()); + goto skip_int_double; + for (;;) { + if (v.isNumber()) { + *out = v.toNumber(); + return true; + } + skip_int_double: + if (v.isString()) + return StringToNumberType(cx, v.toString(), out); + if (v.isBoolean()) { + if (v.toBoolean()) { + *out = 1.0; + return true; + } + *out = 0.0; + return true; + } + if (v.isNull()) { + *out = 0.0; + return true; + } + if (v.isUndefined()) + break; + + JS_ASSERT(v.isObject()); + if (!DefaultValue(cx, &v.toObject(), JSTYPE_NUMBER, &v)) + return false; + if (v.isObject()) + break; + } + + *out = js_NaN; + return true; +} + +bool +ValueToECMAInt32Slow(JSContext *cx, const Value &v, int32_t *out) +{ + JS_ASSERT(!v.isInt32()); + jsdouble d; + if (v.isDouble()) { + d = v.toDouble(); + } else { + if (!ValueToNumberSlow(cx, v, &d)) + return false; + } + *out = js_DoubleToECMAInt32(d); + return true; +} + +bool +ValueToECMAUint32Slow(JSContext *cx, const Value &v, uint32_t *out) +{ + JS_ASSERT(!v.isInt32()); + jsdouble d; + if (v.isDouble()) { + d = v.toDouble(); + } else { + if (!ValueToNumberSlow(cx, v, &d)) + return false; + } + *out = js_DoubleToECMAUint32(d); + return true; +} + +} /* namespace js */ + +uint32 +js_DoubleToECMAUint32(jsdouble d) +{ + int32 i; + JSBool neg; + jsdouble two32; + + if (!JSDOUBLE_IS_FINITE(d)) + return 0; + + /* + * We check whether d fits int32, not uint32, as all but the ">>>" bit + * manipulation bytecode stores the result as int, not uint. When the + * result does not fit int Value, it will be stored as a negative double. + */ + i = (int32) d; + if ((jsdouble) i == d) + return (int32)i; + + neg = (d < 0); + d = floor(neg ? -d : d); + d = neg ? -d : d; + + two32 = 4294967296.0; + d = fmod(d, two32); + + return (uint32) (d >= 0 ? d : d + two32); +} + +namespace js { + +bool +ValueToInt32Slow(JSContext *cx, const Value &v, int32_t *out) +{ + JS_ASSERT(!v.isInt32()); + jsdouble d; + if (v.isDouble()) { + d = v.toDouble(); + } else if (!ValueToNumberSlow(cx, v, &d)) { + return false; + } + + if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) { + js_ReportValueError(cx, JSMSG_CANT_CONVERT, + JSDVG_SEARCH_STACK, v, NULL); + return false; + } + *out = (int32) floor(d + 0.5); /* Round to nearest */ + return true; +} + +bool +ValueToUint16Slow(JSContext *cx, const Value &v, uint16_t *out) +{ + JS_ASSERT(!v.isInt32()); + jsdouble d; + if (v.isDouble()) { + d = v.toDouble(); + } else if (!ValueToNumberSlow(cx, v, &d)) { + return false; + } + + if (d == 0 || !JSDOUBLE_IS_FINITE(d)) { + *out = 0; + return true; + } + + uint16 u = (uint16) d; + if ((jsdouble)u == d) { + *out = u; + return true; + } + + bool neg = (d < 0); + d = floor(neg ? -d : d); + d = neg ? -d : d; + jsuint m = JS_BIT(16); + d = fmod(d, (double) m); + if (d < 0) + d += m; + *out = (uint16_t) d; + return true; +} + +} /* namespace js */ + +JSBool +js_strtod(JSContext *cx, const jschar *s, const jschar *send, + const jschar **ep, jsdouble *dp) +{ + const jschar *s1; + size_t length, i; + char cbuf[32]; + char *cstr, *istr, *estr; + JSBool negative; + jsdouble d; + + s1 = js_SkipWhiteSpace(s, send); + length = send - s1; + + /* Use cbuf to avoid malloc */ + if (length >= sizeof cbuf) { + cstr = (char *) cx->malloc(length + 1); + if (!cstr) + return JS_FALSE; + } else { + cstr = cbuf; + } + + for (i = 0; i != length; i++) { + if (s1[i] >> 8) + break; + cstr[i] = (char)s1[i]; + } + cstr[i] = 0; + + istr = cstr; + if ((negative = (*istr == '-')) != 0 || *istr == '+') + istr++; + if (*istr == 'I' && !strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) { + d = negative ? js_NegativeInfinity : js_PositiveInfinity; + estr = istr + 8; + } else { + int err; + d = js_strtod_harder(JS_THREAD_DATA(cx)->dtoaState, cstr, &estr, &err); + if (d == HUGE_VAL) + d = js_PositiveInfinity; + else if (d == -HUGE_VAL) + d = js_NegativeInfinity; + } + + i = estr - cstr; + if (cstr != cbuf) + cx->free(cstr); + *ep = i ? s1 + i : s; + *dp = d; + return JS_TRUE; +} diff --git a/js/src/jsnum.h b/js/src/jsnum.h new file mode 100644 index 0000000..9548cf5 --- /dev/null +++ b/js/src/jsnum.h @@ -0,0 +1,708 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsnum_h___ +#define jsnum_h___ + +#include +#if defined(XP_WIN) || defined(XP_OS2) +#include +#endif +#ifdef SOLARIS +#include +#endif +#include "jsvalue.h" + +#include "jsstdint.h" +#include "jsstr.h" +#include "jsobj.h" + +/* + * JS number (IEEE double) interface. + * + * JS numbers are optimistically stored in the top 31 bits of 32-bit integers, + * but floating point literals, results that overflow 31 bits, and division and + * modulus operands and results require a 64-bit IEEE double. These are GC'ed + * and pointed to by 32-bit jsvals on the stack and in object properties. + */ + +/* + * The ARM architecture supports two floating point models: VFP and FPA. When + * targetting FPA, doubles are mixed-endian on little endian ARMs (meaning that + * the high and low words are in big endian order). + */ +#if defined(__arm) || defined(__arm32__) || defined(__arm26__) || defined(__arm__) +#if !defined(__VFP_FP__) +#define FPU_IS_ARM_FPA +#endif +#endif + +typedef union jsdpun { + struct { +#if defined(IS_LITTLE_ENDIAN) && !defined(FPU_IS_ARM_FPA) + uint32 lo, hi; +#else + uint32 hi, lo; +#endif + } s; + uint64 u64; + jsdouble d; +} jsdpun; + +static inline int +JSDOUBLE_IS_NaN(jsdouble d) +{ +#ifdef WIN32 + return _isnan(d); +#else + return isnan(d); +#endif +} + +static inline int +JSDOUBLE_IS_FINITE(jsdouble d) +{ +#ifdef WIN32 + return _finite(d); +#else + return finite(d); +#endif +} + +static inline int +JSDOUBLE_IS_INFINITE(jsdouble d) +{ +#ifdef WIN32 + int c = _fpclass(d); + return c == _FPCLASS_NINF || c == _FPCLASS_PINF; +#elif defined(SOLARIS) + return !finite(d) && !isnan(d); +#else + return isinf(d); +#endif +} + +#define JSDOUBLE_HI32_SIGNBIT 0x80000000 +#define JSDOUBLE_HI32_EXPMASK 0x7ff00000 +#define JSDOUBLE_HI32_MANTMASK 0x000fffff +#define JSDOUBLE_HI32_NAN 0x7ff80000 +#define JSDOUBLE_LO32_NAN 0x00000000 + +static inline bool +JSDOUBLE_IS_NEG(jsdouble d) +{ +#ifdef WIN32 + return JSDOUBLE_IS_NEGZERO(d) || d < 0; +#elif defined(SOLARIS) + return copysign(1, d) < 0; +#else + return signbit(d); +#endif +} + +static inline uint32 +JS_HASH_DOUBLE(jsdouble d) +{ + jsdpun u; + u.d = d; + return u.s.lo ^ u.s.hi; +} + +#if defined(XP_WIN) +#define JSDOUBLE_COMPARE(LVAL, OP, RVAL, IFNAN) \ + ((JSDOUBLE_IS_NaN(LVAL) || JSDOUBLE_IS_NaN(RVAL)) \ + ? (IFNAN) \ + : (LVAL) OP (RVAL)) +#else +#define JSDOUBLE_COMPARE(LVAL, OP, RVAL, IFNAN) ((LVAL) OP (RVAL)) +#endif + +extern jsdouble js_NaN; +extern jsdouble js_PositiveInfinity; +extern jsdouble js_NegativeInfinity; + +/* Initialize number constants and runtime state for the first context. */ +extern JSBool +js_InitRuntimeNumberState(JSContext *cx); + +extern void +js_FinishRuntimeNumberState(JSContext *cx); + +/* Initialize the Number class, returning its prototype object. */ +extern js::Class js_NumberClass; + +inline bool +JSObject::isNumber() const +{ + return getClass() == &js_NumberClass; +} + +extern JSObject * +js_InitNumberClass(JSContext *cx, JSObject *obj); + +/* + * String constants for global function names, used in jsapi.c and jsnum.c. + */ +extern const char js_Infinity_str[]; +extern const char js_NaN_str[]; +extern const char js_isNaN_str[]; +extern const char js_isFinite_str[]; +extern const char js_parseFloat_str[]; +extern const char js_parseInt_str[]; + +extern JSString * JS_FASTCALL +js_IntToString(JSContext *cx, jsint i); + +/* + * When base == 10, this function implements ToString() as specified by + * ECMA-262-5 section 9.8.1; but note that it handles integers specially for + * performance. See also js::NumberToCString(). + */ +extern JSString * JS_FASTCALL +js_NumberToString(JSContext *cx, jsdouble d); + +namespace js { + +/* + * Convert an integer or double (contained in the given value) to a string and + * append to the given buffer. + */ +extern bool JS_FASTCALL +NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb); + +/* Same as js_NumberToString, different signature. */ +extern JSFlatString * +NumberToString(JSContext *cx, jsdouble d); + +/* + * Usually a small amount of static storage is enough, but sometimes we need + * to dynamically allocate much more. This struct encapsulates that. + * Dynamically allocated memory will be freed when the object is destroyed. + */ +struct ToCStringBuf +{ + /* + * The longest possible result that would need to fit in sbuf is + * (-0x80000000).toString(2), which has length 33. Longer cases are + * possible, but they'll go in dbuf. + */ + static const size_t sbufSize = 34; + char sbuf[sbufSize]; + char *dbuf; /* must be allocated with js_malloc() */ + + ToCStringBuf(); + ~ToCStringBuf(); +}; + +/* + * Convert a number to a C string. When base==10, this function implements + * ToString() as specified by ECMA-262-5 section 9.8.1. It handles integral + * values cheaply. Return NULL if we ran out of memory. See also + * js_NumberToCString(). + */ +extern char * +NumberToCString(JSContext *cx, ToCStringBuf *cbuf, jsdouble d, jsint base = 10); + +/* + * The largest positive integer such that all positive integers less than it + * may be precisely represented using the IEEE-754 double-precision format. + */ +const double DOUBLE_INTEGRAL_PRECISION_LIMIT = uint64(1) << 53; + +/* + * Compute the positive integer of the given base described immediately at the + * start of the range [start, end) -- no whitespace-skipping, no magical + * leading-"0" octal or leading-"0x" hex behavior, no "+"/"-" parsing, just + * reading the digits of the integer. Return the index one past the end of the + * digits of the integer in *endp, and return the integer itself in *dp. If + * base is 10 or a power of two the returned integer is the closest possible + * double; otherwise extremely large integers may be slightly inaccurate. + * + * If [start, end) does not begin with a number with the specified base, + * *dp == 0 and *endp == start upon return. + */ +extern bool +GetPrefixInteger(JSContext *cx, const jschar *start, const jschar *end, int base, + const jschar **endp, jsdouble *dp); + +/* + * Convert a value to a number, returning the converted value in 'out' if the + * conversion succeeds. + */ +JS_ALWAYS_INLINE bool +ValueToNumber(JSContext *cx, const js::Value &v, double *out) +{ + if (v.isNumber()) { + *out = v.toNumber(); + return true; + } + extern bool ValueToNumberSlow(JSContext *, js::Value, double *); + return ValueToNumberSlow(cx, v, out); +} + +/* Convert a value to a number, replacing 'vp' with the converted value. */ +JS_ALWAYS_INLINE bool +ValueToNumber(JSContext *cx, js::Value *vp) +{ + if (vp->isNumber()) + return true; + double d; + extern bool ValueToNumberSlow(JSContext *, js::Value, double *); + if (!ValueToNumberSlow(cx, *vp, &d)) + return false; + vp->setNumber(d); + return true; +} + +/* + * Convert a value to an int32 or uint32, according to the ECMA rules for + * ToInt32 and ToUint32. Return converted value in *out on success, !ok on + * failure. + */ +JS_ALWAYS_INLINE bool +ValueToECMAInt32(JSContext *cx, const js::Value &v, int32_t *out) +{ + if (v.isInt32()) { + *out = v.toInt32(); + return true; + } + extern bool ValueToECMAInt32Slow(JSContext *, const js::Value &, int32_t *); + return ValueToECMAInt32Slow(cx, v, out); +} + +JS_ALWAYS_INLINE bool +ValueToECMAUint32(JSContext *cx, const js::Value &v, uint32_t *out) +{ + if (v.isInt32()) { + *out = (uint32_t)v.toInt32(); + return true; + } + extern bool ValueToECMAUint32Slow(JSContext *, const js::Value &, uint32_t *); + return ValueToECMAUint32Slow(cx, v, out); +} + +/* + * Convert a value to a number, then to an int32 if it fits by rounding to + * nearest. Return converted value in *out on success, !ok on failure. As a + * side effect, *vp will be mutated to match *out. + */ +JS_ALWAYS_INLINE bool +ValueToInt32(JSContext *cx, const js::Value &v, int32_t *out) +{ + if (v.isInt32()) { + *out = v.toInt32(); + return true; + } + extern bool ValueToInt32Slow(JSContext *, const js::Value &, int32_t *); + return ValueToInt32Slow(cx, v, out); +} + +/* + * Convert a value to a number, then to a uint16 according to the ECMA rules + * for ToUint16. Return converted value on success, !ok on failure. v must be a + * copy of a rooted value. + */ +JS_ALWAYS_INLINE bool +ValueToUint16(JSContext *cx, const js::Value &v, uint16_t *out) +{ + if (v.isInt32()) { + *out = (uint16_t)v.toInt32(); + return true; + } + extern bool ValueToUint16Slow(JSContext *, const js::Value &, uint16_t *); + return ValueToUint16Slow(cx, v, out); +} + +} /* namespace js */ + +/* + * Specialized ToInt32 and ToUint32 converters for doubles. + */ +/* + * From the ES3 spec, 9.5 + * 2. If Result(1) is NaN, +0, -0, +Inf, or -Inf, return +0. + * 3. Compute sign(Result(1)) * floor(abs(Result(1))). + * 4. Compute Result(3) modulo 2^32; that is, a finite integer value k of Number + * type with positive sign and less than 2^32 in magnitude such the mathematical + * difference of Result(3) and k is mathematically an integer multiple of 2^32. + * 5. If Result(4) is greater than or equal to 2^31, return Result(4)- 2^32, + * otherwise return Result(4). + */ +static inline int32 +js_DoubleToECMAInt32(jsdouble d) +{ +#if defined(__i386__) || defined(__i386) || defined(__x86_64__) || \ + defined(_M_IX86) || defined(_M_X64) + jsdpun du, duh, two32; + uint32 di_h, u_tmp, expon, shift_amount; + int32 mask32; + + /* + * Algorithm Outline + * Step 1. If d is NaN, +/-Inf or |d|>=2^84 or |d|<1, then return 0 + * All of this is implemented based on an exponent comparison. + * Step 2. If |d|<2^31, then return (int)d + * The cast to integer (conversion in RZ mode) returns the correct result. + * Step 3. If |d|>=2^32, d:=fmod(d, 2^32) is taken -- but without a call + * Step 4. If |d|>=2^31, then the fractional bits are cleared before + * applying the correction by 2^32: d - sign(d)*2^32 + * Step 5. Return (int)d + */ + + du.d = d; + di_h = du.s.hi; + + u_tmp = (di_h & 0x7ff00000) - 0x3ff00000; + if (u_tmp >= (0x45300000-0x3ff00000)) { + // d is Nan, +/-Inf or +/-0, or |d|>=2^(32+52) or |d|<1, in which case result=0 + return 0; + } + + if (u_tmp < 0x01f00000) { + // |d|<2^31 + return int32_t(d); + } + + if (u_tmp > 0x01f00000) { + // |d|>=2^32 + expon = u_tmp >> 20; + shift_amount = expon - 21; + duh.u64 = du.u64; + mask32 = 0x80000000; + if (shift_amount < 32) { + mask32 >>= shift_amount; + duh.s.hi = du.s.hi & mask32; + duh.s.lo = 0; + } else { + mask32 >>= (shift_amount-32); + duh.s.hi = du.s.hi; + duh.s.lo = du.s.lo & mask32; + } + du.d -= duh.d; + } + + di_h = du.s.hi; + + // eliminate fractional bits + u_tmp = (di_h & 0x7ff00000); + if (u_tmp >= 0x41e00000) { + // |d|>=2^31 + expon = u_tmp >> 20; + shift_amount = expon - (0x3ff - 11); + mask32 = 0x80000000; + if (shift_amount < 32) { + mask32 >>= shift_amount; + du.s.hi &= mask32; + du.s.lo = 0; + } else { + mask32 >>= (shift_amount-32); + du.s.lo &= mask32; + } + two32.s.hi = 0x41f00000 ^ (du.s.hi & 0x80000000); + two32.s.lo = 0; + du.d -= two32.d; + } + + return int32(du.d); +#elif defined (__arm__) && defined (__GNUC__) + int32_t i; + uint32_t tmp0; + uint32_t tmp1; + uint32_t tmp2; + asm ( + // We use a pure integer solution here. In the 'softfp' ABI, the argument + // will start in r0 and r1, and VFP can't do all of the necessary ECMA + // conversions by itself so some integer code will be required anyway. A + // hybrid solution is faster on A9, but this pure integer solution is + // notably faster for A8. + + // %0 is the result register, and may alias either of the %[QR]1 registers. + // %Q4 holds the lower part of the mantissa. + // %R4 holds the sign, exponent, and the upper part of the mantissa. + // %1, %2 and %3 are used as temporary values. + + // Extract the exponent. +" mov %1, %R4, LSR #20\n" +" bic %1, %1, #(1 << 11)\n" // Clear the sign. + + // Set the implicit top bit of the mantissa. This clobbers a bit of the + // exponent, but we have already extracted that. +" orr %R4, %R4, #(1 << 20)\n" + + // Special Cases + // We should return zero in the following special cases: + // - Exponent is 0x000 - 1023: +/-0 or subnormal. + // - Exponent is 0x7ff - 1023: +/-INFINITY or NaN + // - This case is implicitly handled by the standard code path anyway, + // as shifting the mantissa up by the exponent will result in '0'. + // + // The result is composed of the mantissa, prepended with '1' and + // bit-shifted left by the (decoded) exponent. Note that because the r1[20] + // is the bit with value '1', r1 is effectively already shifted (left) by + // 20 bits, and r0 is already shifted by 52 bits. + + // Adjust the exponent to remove the encoding offset. If the decoded + // exponent is negative, quickly bail out with '0' as such values round to + // zero anyway. This also catches +/-0 and subnormals. +" sub %1, %1, #0xff\n" +" subs %1, %1, #0x300\n" +" bmi 8f\n" + + // %1 = (decoded) exponent >= 0 + // %R4 = upper mantissa and sign + + // ---- Lower Mantissa ---- +" subs %3, %1, #52\n" // Calculate exp-52 +" bmi 1f\n" + + // Shift r0 left by exp-52. + // Ensure that we don't overflow ARM's 8-bit shift operand range. + // We need to handle anything up to an 11-bit value here as we know that + // 52 <= exp <= 1024 (0x400). Any shift beyond 31 bits results in zero + // anyway, so as long as we don't touch the bottom 5 bits, we can use + // a logical OR to push long shifts into the 32 <= (exp&0xff) <= 255 range. +" bic %2, %3, #0xff\n" +" orr %3, %3, %2, LSR #3\n" + // We can now perform a straight shift, avoiding the need for any + // conditional instructions or extra branches. +" mov %Q4, %Q4, LSL %3\n" +" b 2f\n" +"1:\n" // Shift r0 right by 52-exp. + // We know that 0 <= exp < 52, and we can shift up to 255 bits so 52-exp + // will always be a valid shift and we can sk%3 the range check for this case. +" rsb %3, %1, #52\n" +" mov %Q4, %Q4, LSR %3\n" + + // %1 = (decoded) exponent + // %R4 = upper mantissa and sign + // %Q4 = partially-converted integer + +"2:\n" + // ---- Upper Mantissa ---- + // This is much the same as the lower mantissa, with a few different + // boundary checks and some masking to hide the exponent & sign bit in the + // upper word. + // Note that the upper mantissa is pre-shifted by 20 in %R4, but we shift + // it left more to remove the sign and exponent so it is effectively + // pre-shifted by 31 bits. +" subs %3, %1, #31\n" // Calculate exp-31 +" mov %1, %R4, LSL #11\n" // Re-use %1 as a temporary register. +" bmi 3f\n" + + // Shift %R4 left by exp-31. + // Avoid overflowing the 8-bit shift range, as before. +" bic %2, %3, #0xff\n" +" orr %3, %3, %2, LSR #3\n" + // Perform the shift. +" mov %2, %1, LSL %3\n" +" b 4f\n" +"3:\n" // Shift r1 right by 31-exp. + // We know that 0 <= exp < 31, and we can shift up to 255 bits so 31-exp + // will always be a valid shift and we can skip the range check for this case. +" rsb %3, %3, #0\n" // Calculate 31-exp from -(exp-31) +" mov %2, %1, LSR %3\n" // Thumb-2 can't do "LSR %3" in "orr". + + // %Q4 = partially-converted integer (lower) + // %R4 = upper mantissa and sign + // %2 = partially-converted integer (upper) + +"4:\n" + // Combine the converted parts. +" orr %Q4, %Q4, %2\n" + // Negate the result if we have to, and move it to %0 in the process. To + // avoid conditionals, we can do this by inverting on %R4[31], then adding + // %R4[31]>>31. +" eor %Q4, %Q4, %R4, ASR #31\n" +" add %0, %Q4, %R4, LSR #31\n" +" b 9f\n" +"8:\n" + // +/-INFINITY, +/-0, subnormals, NaNs, and anything else out-of-range that + // will result in a conversion of '0'. +" mov %0, #0\n" +"9:\n" + : "=r" (i), "=&r" (tmp0), "=&r" (tmp1), "=&r" (tmp2) + : "r" (d) + : "cc" + ); + return i; +#else + int32 i; + jsdouble two32, two31; + + if (!JSDOUBLE_IS_FINITE(d)) + return 0; + + i = (int32) d; + if ((jsdouble) i == d) + return i; + + two32 = 4294967296.0; + two31 = 2147483648.0; + d = fmod(d, two32); + d = (d >= 0) ? floor(d) : ceil(d) + two32; + return (int32) (d >= two31 ? d - two32 : d); +#endif +} + +uint32 +js_DoubleToECMAUint32(jsdouble d); + +/* + * Convert a jsdouble to an integral number, stored in a jsdouble. + * If d is NaN, return 0. If d is an infinity, return it without conversion. + */ +static inline jsdouble +js_DoubleToInteger(jsdouble d) +{ + if (d == 0) + return d; + + if (!JSDOUBLE_IS_FINITE(d)) { + if (JSDOUBLE_IS_NaN(d)) + return 0; + return d; + } + + JSBool neg = (d < 0); + d = floor(neg ? -d : d); + + return neg ? -d : d; +} + +/* + * Similar to strtod except that it replaces overflows with infinities of the + * correct sign, and underflows with zeros of the correct sign. Guaranteed to + * return the closest double number to the given input in dp. + * + * Also allows inputs of the form [+|-]Infinity, which produce an infinity of + * the appropriate sign. The case of the "Infinity" string must match exactly. + * If the string does not contain a number, set *ep to s and return 0.0 in dp. + * Return false if out of memory. + */ +extern JSBool +js_strtod(JSContext *cx, const jschar *s, const jschar *send, + const jschar **ep, jsdouble *dp); + +extern JSBool +js_num_valueOf(JSContext *cx, uintN argc, js::Value *vp); + +namespace js { + +static JS_ALWAYS_INLINE bool +ValueFitsInInt32(const Value &v, int32_t *pi) +{ + if (v.isInt32()) { + *pi = v.toInt32(); + return true; + } + return v.isDouble() && JSDOUBLE_IS_INT32(v.toDouble(), pi); +} + +template struct NumberTraits { }; +template<> struct NumberTraits { + static JS_ALWAYS_INLINE int32 NaN() { return 0; } + static JS_ALWAYS_INLINE int32 toSelfType(int32 i) { return i; } + static JS_ALWAYS_INLINE int32 toSelfType(jsdouble d) { return js_DoubleToECMAUint32(d); } +}; +template<> struct NumberTraits { + static JS_ALWAYS_INLINE jsdouble NaN() { return js_NaN; } + static JS_ALWAYS_INLINE jsdouble toSelfType(int32 i) { return i; } + static JS_ALWAYS_INLINE jsdouble toSelfType(jsdouble d) { return d; } +}; + +template +static JS_ALWAYS_INLINE bool +StringToNumberType(JSContext *cx, JSString *str, T *result) +{ + size_t length = str->length(); + const jschar *chars = str->getChars(NULL); + if (!chars) + return false; + + if (length == 1) { + jschar c = chars[0]; + if ('0' <= c && c <= '9') { + *result = NumberTraits::toSelfType(T(c - '0')); + return true; + } + if (JS_ISSPACE(c)) { + *result = NumberTraits::toSelfType(T(0)); + return true; + } + *result = NumberTraits::NaN(); + return true; + } + + const jschar *bp = chars; + const jschar *end = chars + length; + bp = js_SkipWhiteSpace(bp, end); + + /* ECMA doesn't allow signed hex numbers (bug 273467). */ + if (end - bp >= 2 && bp[0] == '0' && (bp[1] == 'x' || bp[1] == 'X')) { + /* Looks like a hex number. */ + const jschar *endptr; + double d; + if (!GetPrefixInteger(cx, bp + 2, end, 16, &endptr, &d) || + js_SkipWhiteSpace(endptr, end) != end) { + *result = NumberTraits::NaN(); + return true; + } + *result = NumberTraits::toSelfType(d); + return true; + } + + /* + * Note that ECMA doesn't treat a string beginning with a '0' as + * an octal number here. This works because all such numbers will + * be interpreted as decimal by js_strtod. Also, any hex numbers + * that have made it here (which can only be negative ones) will + * be treated as 0 without consuming the 'x' by js_strtod. + */ + const jschar *ep; + double d; + if (!js_strtod(cx, bp, end, &ep, &d) || js_SkipWhiteSpace(ep, end) != end) { + *result = NumberTraits::NaN(); + return true; + } + *result = NumberTraits::toSelfType(d); + return true; +} +} + +#endif /* jsnum_h___ */ diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp new file mode 100644 index 0000000..df80cc3 --- /dev/null +++ b/js/src/jsobj.cpp @@ -0,0 +1,7040 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS object implementation. + */ +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsarena.h" +#include "jsbit.h" +#include "jsutil.h" +#include "jshash.h" +#include "jsdhash.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsproxy.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstaticcheck.h" +#include "jsstdint.h" +#include "jsstr.h" +#include "jstracer.h" +#include "jsdbgapi.h" +#include "json.h" +#include "jswrapper.h" + +#include "jsinterpinlines.h" +#include "jsscopeinlines.h" +#include "jsscriptinlines.h" +#include "jsobjinlines.h" + +#if JS_HAS_GENERATORS +#include "jsiter.h" +#endif + +#if JS_HAS_XML_SUPPORT +#include "jsxml.h" +#endif + +#if JS_HAS_XDR +#include "jsxdrapi.h" +#endif + +#include "jsprobes.h" +#include "jsatominlines.h" +#include "jsobjinlines.h" +#include "jsscriptinlines.h" + +#include "jsautooplen.h" + +using namespace js; +using namespace js::gc; + +JS_FRIEND_DATA(const JSObjectMap) JSObjectMap::sharedNonNative(JSObjectMap::SHAPELESS); + +Class js_ObjectClass = { + js_Object_str, + JSCLASS_HAS_CACHED_PROTO(JSProto_Object), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub +}; + +JS_FRIEND_API(JSObject *) +js_ObjectToOuterObject(JSContext *cx, JSObject *obj) +{ + OBJ_TO_OUTER_OBJECT(cx, obj); + return obj; +} + +#if JS_HAS_OBJ_PROTO_PROP + +static JSBool +obj_getProto(JSContext *cx, JSObject *obj, jsid id, Value *vp); + +static JSBool +obj_setProto(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp); + +static JSPropertySpec object_props[] = { + {js_proto_str, 0, JSPROP_PERMANENT|JSPROP_SHARED, Jsvalify(obj_getProto), Jsvalify(obj_setProto)}, + {0,0,0,0,0} +}; + +static JSBool +obj_getProto(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + /* Let CheckAccess get the slot's value, based on the access mode. */ + uintN attrs; + id = ATOM_TO_JSID(cx->runtime->atomState.protoAtom); + return CheckAccess(cx, obj, id, JSACC_PROTO, vp, &attrs); +} + +static JSBool +obj_setProto(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) +{ + /* ECMAScript 5 8.6.2 forbids changing [[Prototype]] if not [[Extensible]]. */ + if (!obj->isExtensible()) { + obj->reportNotExtensible(cx); + return false; + } + + if (!vp->isObjectOrNull()) + return JS_TRUE; + + JSObject *pobj = vp->toObjectOrNull(); + if (pobj) { + /* + * Innerize pobj here to avoid sticking unwanted properties on the + * outer object. This ensures that any with statements only grant + * access to the inner object. + */ + OBJ_TO_INNER_OBJECT(cx, pobj); + if (!pobj) + return JS_FALSE; + } + + uintN attrs; + id = ATOM_TO_JSID(cx->runtime->atomState.protoAtom); + if (!CheckAccess(cx, obj, id, JSAccessMode(JSACC_PROTO|JSACC_WRITE), vp, &attrs)) + return JS_FALSE; + + return SetProto(cx, obj, pobj, JS_TRUE); +} + +#else /* !JS_HAS_OBJ_PROTO_PROP */ + +#define object_props NULL + +#endif /* !JS_HAS_OBJ_PROTO_PROP */ + +static JSHashNumber +js_hash_object(const void *key) +{ + return JSHashNumber(uintptr_t(key) >> JS_GCTHING_ALIGN); +} + +static JSHashEntry * +MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap) +{ + JSSharpObjectMap *map; + JSHashTable *table; + JSHashNumber hash; + JSHashEntry **hep, *he; + jsatomid sharpid; + JSIdArray *ida; + JSBool ok; + jsint i, length; + jsid id; + JSObject *obj2; + JSProperty *prop; + + JS_CHECK_RECURSION(cx, return NULL); + + map = &cx->sharpObjectMap; + JS_ASSERT(map->depth >= 1); + table = map->table; + hash = js_hash_object(obj); + hep = JS_HashTableRawLookup(table, hash, obj); + he = *hep; + if (!he) { + sharpid = 0; + he = JS_HashTableRawAdd(table, hep, hash, obj, (void *) sharpid); + if (!he) { + JS_ReportOutOfMemory(cx); + return NULL; + } + + ida = JS_Enumerate(cx, obj); + if (!ida) + return NULL; + + ok = JS_TRUE; + for (i = 0, length = ida->length; i < length; i++) { + id = ida->vector[i]; + ok = obj->lookupProperty(cx, id, &obj2, &prop); + if (!ok) + break; + if (!prop) + continue; + bool hasGetter, hasSetter; + AutoValueRooter v(cx); + AutoValueRooter setter(cx); + if (obj2->isNative()) { + const Shape *shape = (Shape *) prop; + hasGetter = shape->hasGetterValue(); + hasSetter = shape->hasSetterValue(); + if (hasGetter) + v.set(shape->getterValue()); + if (hasSetter) + setter.set(shape->setterValue()); + } else { + hasGetter = hasSetter = false; + } + if (hasSetter) { + /* Mark the getter, then set val to setter. */ + if (hasGetter && v.value().isObject()) { + ok = !!MarkSharpObjects(cx, &v.value().toObject(), NULL); + if (!ok) + break; + } + v.set(setter.value()); + } else if (!hasGetter) { + ok = obj->getProperty(cx, id, v.addr()); + if (!ok) + break; + } + if (v.value().isObject() && + !MarkSharpObjects(cx, &v.value().toObject(), NULL)) { + ok = JS_FALSE; + break; + } + } + if (!ok || !idap) + JS_DestroyIdArray(cx, ida); + if (!ok) + return NULL; + } else { + sharpid = uintptr_t(he->value); + if (sharpid == 0) { + sharpid = ++map->sharpgen << SHARP_ID_SHIFT; + he->value = (void *) sharpid; + } + ida = NULL; + } + if (idap) + *idap = ida; + return he; +} + +JSHashEntry * +js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, + jschar **sp) +{ + JSSharpObjectMap *map; + JSHashTable *table; + JSIdArray *ida; + JSHashNumber hash; + JSHashEntry *he, **hep; + jsatomid sharpid; + char buf[20]; + size_t len; + + if (!JS_CHECK_OPERATION_LIMIT(cx)) + return NULL; + + /* Set to null in case we return an early error. */ + *sp = NULL; + map = &cx->sharpObjectMap; + table = map->table; + if (!table) { + table = JS_NewHashTable(8, js_hash_object, JS_CompareValues, + JS_CompareValues, NULL, NULL); + if (!table) { + JS_ReportOutOfMemory(cx); + return NULL; + } + map->table = table; + JS_KEEP_ATOMS(cx->runtime); + } + + /* From this point the control must flow either through out: or bad:. */ + ida = NULL; + if (map->depth == 0) { + /* + * Although MarkSharpObjects tries to avoid invoking getters, + * it ends up doing so anyway under some circumstances; for + * example, if a wrapped object has getters, the wrapper will + * prevent MarkSharpObjects from recognizing them as such. + * This could lead to js_LeaveSharpObject being called while + * MarkSharpObjects is still working. + * + * Increment map->depth while we call MarkSharpObjects, to + * ensure that such a call doesn't free the hash table we're + * still using. + */ + ++map->depth; + he = MarkSharpObjects(cx, obj, &ida); + --map->depth; + if (!he) + goto bad; + JS_ASSERT((uintptr_t(he->value) & SHARP_BIT) == 0); + if (!idap) { + JS_DestroyIdArray(cx, ida); + ida = NULL; + } + } else { + hash = js_hash_object(obj); + hep = JS_HashTableRawLookup(table, hash, obj); + he = *hep; + + /* + * It's possible that the value of a property has changed from the + * first time the object's properties are traversed (when the property + * ids are entered into the hash table) to the second (when they are + * converted to strings), i.e., the JSObject::getProperty() call is not + * idempotent. + */ + if (!he) { + he = JS_HashTableRawAdd(table, hep, hash, obj, NULL); + if (!he) { + JS_ReportOutOfMemory(cx); + goto bad; + } + sharpid = 0; + goto out; + } + } + + sharpid = uintptr_t(he->value); + if (sharpid != 0) { + len = JS_snprintf(buf, sizeof buf, "#%u%c", + sharpid >> SHARP_ID_SHIFT, + (sharpid & SHARP_BIT) ? '#' : '='); + *sp = js_InflateString(cx, buf, &len); + if (!*sp) { + if (ida) + JS_DestroyIdArray(cx, ida); + goto bad; + } + } + +out: + JS_ASSERT(he); + if ((sharpid & SHARP_BIT) == 0) { + if (idap && !ida) { + ida = JS_Enumerate(cx, obj); + if (!ida) { + if (*sp) { + cx->free(*sp); + *sp = NULL; + } + goto bad; + } + } + map->depth++; + } + + if (idap) + *idap = ida; + return he; + +bad: + /* Clean up the sharpObjectMap table on outermost error. */ + if (map->depth == 0) { + JS_UNKEEP_ATOMS(cx->runtime); + map->sharpgen = 0; + JS_HashTableDestroy(map->table); + map->table = NULL; + } + return NULL; +} + +void +js_LeaveSharpObject(JSContext *cx, JSIdArray **idap) +{ + JSSharpObjectMap *map; + JSIdArray *ida; + + map = &cx->sharpObjectMap; + JS_ASSERT(map->depth > 0); + if (--map->depth == 0) { + JS_UNKEEP_ATOMS(cx->runtime); + map->sharpgen = 0; + JS_HashTableDestroy(map->table); + map->table = NULL; + } + if (idap) { + ida = *idap; + if (ida) { + JS_DestroyIdArray(cx, ida); + *idap = NULL; + } + } +} + +static intN +gc_sharp_table_entry_marker(JSHashEntry *he, intN i, void *arg) +{ + MarkObject((JSTracer *)arg, *(JSObject *)he->key, "sharp table entry"); + return JS_DHASH_NEXT; +} + +void +js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map) +{ + JS_ASSERT(map->depth > 0); + JS_ASSERT(map->table); + + /* + * During recursive calls to MarkSharpObjects a non-native object or + * object with a custom getProperty method can potentially return an + * unrooted value or even cut from the object graph an argument of one of + * MarkSharpObjects recursive invocations. So we must protect map->table + * entries against GC. + * + * We can not simply use JSTempValueRooter to mark the obj argument of + * MarkSharpObjects during recursion as we have to protect *all* entries + * in JSSharpObjectMap including those that contains otherwise unreachable + * objects just allocated through custom getProperty. Otherwise newer + * allocations can re-use the address of an object stored in the hashtable + * confusing js_EnterSharpObject. So to address the problem we simply + * mark all objects from map->table. + * + * An alternative "proper" solution is to use JSTempValueRooter in + * MarkSharpObjects with code to remove during finalization entries + * with otherwise unreachable objects. But this is way too complex + * to justify spending efforts. + */ + JS_HashTableEnumerateEntries(map->table, gc_sharp_table_entry_marker, trc); +} + +#if JS_HAS_TOSOURCE +static JSBool +obj_toSource(JSContext *cx, uintN argc, Value *vp) +{ + JSBool ok; + JSHashEntry *he; + JSIdArray *ida; + jschar *chars, *ochars, *vsharp; + const jschar *idstrchars, *vchars; + size_t nchars, idstrlength, gsoplength, vlength, vsharplength, curlen; + const char *comma; + JSObject *obj2; + JSProperty *prop; + Value *val; + JSString *gsop[2]; + JSString *valstr, *str; + JSLinearString *idstr; + + JS_CHECK_RECURSION(cx, return JS_FALSE); + + Value localroot[4]; + PodArrayZero(localroot); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroot), localroot); + + /* If outermost, we need parentheses to be an expression, not a block. */ + JSBool outermost = (cx->sharpObjectMap.depth == 0); + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!(he = js_EnterSharpObject(cx, obj, &ida, &chars))) { + ok = JS_FALSE; + goto out; + } + if (IS_SHARP(he)) { + /* + * We didn't enter -- obj is already "sharp", meaning we've visited it + * already in our depth first search, and therefore chars contains a + * string of the form "#n#". + */ + JS_ASSERT(!ida); +#if JS_HAS_SHARP_VARS + nchars = js_strlen(chars); +#else + chars[0] = '{'; + chars[1] = '}'; + chars[2] = 0; + nchars = 2; +#endif + goto make_string; + } + JS_ASSERT(ida); + ok = JS_TRUE; + + if (!chars) { + /* If outermost, allocate 4 + 1 for "({})" and the terminator. */ + chars = (jschar *) cx->runtime->malloc(((outermost ? 4 : 2) + 1) * sizeof(jschar)); + nchars = 0; + if (!chars) + goto error; + if (outermost) + chars[nchars++] = '('; + } else { + /* js_EnterSharpObject returned a string of the form "#n=" in chars. */ + MAKE_SHARP(he); + nchars = js_strlen(chars); + chars = (jschar *) + js_realloc((ochars = chars), (nchars + 2 + 1) * sizeof(jschar)); + if (!chars) { + js_free(ochars); + goto error; + } + if (outermost) { + /* + * No need for parentheses around the whole shebang, because #n= + * unambiguously begins an object initializer, and never a block + * statement. + */ + outermost = JS_FALSE; + } + } + + chars[nchars++] = '{'; + + comma = NULL; + + /* + * We have four local roots for cooked and raw value GC safety. Hoist the + * "localroot + 2" out of the loop using the val local, which refers to + * the raw (unconverted, "uncooked") values. + */ + val = localroot + 2; + + for (jsint i = 0, length = ida->length; i < length; i++) { + /* Get strings for id and value and GC-root them via vp. */ + jsid id = ida->vector[i]; + + ok = obj->lookupProperty(cx, id, &obj2, &prop); + if (!ok) + goto error; + + /* + * Convert id to a value and then to a string. Decide early whether we + * prefer get/set or old getter/setter syntax. + */ + JSString *s = js_ValueToString(cx, IdToValue(id)); + if (!s || !(idstr = s->ensureLinear(cx))) { + ok = JS_FALSE; + goto error; + } + vp->setString(idstr); /* local root */ + + jsint valcnt = 0; + if (prop) { + bool doGet = true; + if (obj2->isNative()) { + const Shape *shape = (Shape *) prop; + unsigned attrs = shape->attributes(); + if (attrs & JSPROP_GETTER) { + doGet = false; + val[valcnt] = shape->getterValue(); + gsop[valcnt] = ATOM_TO_STRING(cx->runtime->atomState.getAtom); + valcnt++; + } + if (attrs & JSPROP_SETTER) { + doGet = false; + val[valcnt] = shape->setterValue(); + gsop[valcnt] = ATOM_TO_STRING(cx->runtime->atomState.setAtom); + valcnt++; + } + } + if (doGet) { + valcnt = 1; + gsop[0] = NULL; + ok = obj->getProperty(cx, id, &val[0]); + if (!ok) + goto error; + } + } + + /* + * If id is a string that's not an identifier, or if it's a negative + * integer, then it must be quoted. + */ + bool idIsLexicalIdentifier = js_IsIdentifier(idstr); + if (JSID_IS_ATOM(id) + ? !idIsLexicalIdentifier + : (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0)) { + s = js_QuoteString(cx, idstr, jschar('\'')); + if (!s || !(idstr = s->ensureLinear(cx))) { + ok = JS_FALSE; + goto error; + } + vp->setString(idstr); /* local root */ + } + idstrlength = idstr->length(); + idstrchars = idstr->getChars(cx); + if (!idstrchars) { + ok = JS_FALSE; + goto error; + } + + for (jsint j = 0; j < valcnt; j++) { + /* + * Censor an accessor descriptor getter or setter part if it's + * undefined. + */ + if (gsop[j] && val[j].isUndefined()) + continue; + + /* Convert val[j] to its canonical source form. */ + valstr = js_ValueToSource(cx, val[j]); + if (!valstr) { + ok = JS_FALSE; + goto error; + } + localroot[j].setString(valstr); /* local root */ + vchars = valstr->getChars(cx); + if (!vchars) { + ok = JS_FALSE; + goto error; + } + vlength = valstr->length(); + + /* + * If val[j] is a non-sharp object, and we're not serializing an + * accessor (ECMA syntax can't accommodate sharpened accessors), + * consider sharpening it. + */ + vsharp = NULL; + vsharplength = 0; +#if JS_HAS_SHARP_VARS + if (!gsop[j] && val[j].isObject() && vchars[0] != '#') { + he = js_EnterSharpObject(cx, &val[j].toObject(), NULL, &vsharp); + if (!he) { + ok = JS_FALSE; + goto error; + } + if (IS_SHARP(he)) { + vchars = vsharp; + vlength = js_strlen(vchars); + } else { + if (vsharp) { + vsharplength = js_strlen(vsharp); + MAKE_SHARP(he); + } + js_LeaveSharpObject(cx, NULL); + } + } +#endif + + /* + * Remove '(function ' from the beginning of valstr and ')' from the + * end so that we can put "get" in front of the function definition. + */ + if (gsop[j] && IsFunctionObject(val[j])) { + const jschar *start = vchars; + const jschar *end = vchars + vlength; + + uint8 parenChomp = 0; + if (vchars[0] == '(') { + vchars++; + parenChomp = 1; + } + + /* Try to jump "function" keyword. */ + if (vchars) + vchars = js_strchr_limit(vchars, ' ', end); + + /* + * Jump over the function's name: it can't be encoded as part + * of an ECMA getter or setter. + */ + if (vchars) + vchars = js_strchr_limit(vchars, '(', end); + + if (vchars) { + if (*vchars == ' ') + vchars++; + vlength = end - vchars - parenChomp; + } else { + gsop[j] = NULL; + vchars = start; + } + } + +#define SAFE_ADD(n) \ + JS_BEGIN_MACRO \ + size_t n_ = (n); \ + curlen += n_; \ + if (curlen < n_) \ + goto overflow; \ + JS_END_MACRO + + curlen = nchars; + if (comma) + SAFE_ADD(2); + SAFE_ADD(idstrlength + 1); + if (gsop[j]) + SAFE_ADD(gsop[j]->length() + 1); + SAFE_ADD(vsharplength); + SAFE_ADD(vlength); + /* Account for the trailing null. */ + SAFE_ADD((outermost ? 2 : 1) + 1); +#undef SAFE_ADD + + if (curlen > size_t(-1) / sizeof(jschar)) + goto overflow; + + /* Allocate 1 + 1 at end for closing brace and terminating 0. */ + chars = (jschar *) js_realloc((ochars = chars), curlen * sizeof(jschar)); + if (!chars) { + chars = ochars; + goto overflow; + } + + if (comma) { + chars[nchars++] = comma[0]; + chars[nchars++] = comma[1]; + } + comma = ", "; + + if (gsop[j]) { + gsoplength = gsop[j]->length(); + const jschar *gsopchars = gsop[j]->getChars(cx); + if (!gsopchars) + goto overflow; + js_strncpy(&chars[nchars], gsopchars, gsoplength); + nchars += gsoplength; + chars[nchars++] = ' '; + } + js_strncpy(&chars[nchars], idstrchars, idstrlength); + nchars += idstrlength; + /* Extraneous space after id here will be extracted later */ + chars[nchars++] = gsop[j] ? ' ' : ':'; + + if (vsharplength) { + js_strncpy(&chars[nchars], vsharp, vsharplength); + nchars += vsharplength; + } + js_strncpy(&chars[nchars], vchars, vlength); + nchars += vlength; + + if (vsharp) + cx->free(vsharp); + } + } + + chars[nchars++] = '}'; + if (outermost) + chars[nchars++] = ')'; + chars[nchars] = 0; + + error: + js_LeaveSharpObject(cx, &ida); + + if (!ok) { + if (chars) + js_free(chars); + goto out; + } + + if (!chars) { + JS_ReportOutOfMemory(cx); + ok = JS_FALSE; + goto out; + } + make_string: + str = js_NewString(cx, chars, nchars); + if (!str) { + js_free(chars); + ok = JS_FALSE; + goto out; + } + vp->setString(str); + ok = JS_TRUE; + out: + return ok; + + overflow: + cx->free(vsharp); + js_free(chars); + chars = NULL; + goto error; +} +#endif /* JS_HAS_TOSOURCE */ + +namespace js { + +JSString * +obj_toStringHelper(JSContext *cx, JSObject *obj) +{ + if (obj->isProxy()) + return JSProxy::obj_toString(cx, obj); + + const char *clazz = obj->getClass()->name; + size_t nchars = 9 + strlen(clazz); /* 9 for "[object ]" */ + jschar *chars = (jschar *) cx->malloc((nchars + 1) * sizeof(jschar)); + if (!chars) + return NULL; + + const char *prefix = "[object "; + nchars = 0; + while ((chars[nchars] = (jschar)*prefix) != 0) + nchars++, prefix++; + while ((chars[nchars] = (jschar)*clazz) != 0) + nchars++, clazz++; + chars[nchars++] = ']'; + chars[nchars] = 0; + + JSString *str = js_NewString(cx, chars, nchars); + if (!str) + cx->free(chars); + return str; +} + +} + +/* ES5 15.2.4.2. Note steps 1 and 2 are errata. */ +static JSBool +obj_toString(JSContext *cx, uintN argc, Value *vp) +{ + Value &thisv = vp[1]; + + /* Step 1. */ + if (thisv.isUndefined()) { + vp->setString(ATOM_TO_STRING(cx->runtime->atomState.objectUndefinedAtom)); + return true; + } + + /* Step 2. */ + if (thisv.isNull()) { + vp->setString(ATOM_TO_STRING(cx->runtime->atomState.objectNullAtom)); + return true; + } + + /* Step 3. */ + JSObject *obj = ToObject(cx, &thisv); + if (!obj) + return false; + + /* Steps 4-5. */ + JSString *str = js::obj_toStringHelper(cx, obj); + if (!str) + return false; + vp->setString(str); + return true; +} + +static JSBool +obj_toLocaleString(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + JSString *str = js_ValueToString(cx, ObjectValue(*obj)); + if (!str) + return JS_FALSE; + + vp->setString(str); + return JS_TRUE; +} + +static JSBool +obj_valueOf(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + vp->setObject(*obj); + return true; +} + +/* + * Check if CSP allows new Function() or eval() to run in the current + * principals. + */ +JSBool +js_CheckContentSecurityPolicy(JSContext *cx, JSObject *scopeobj) +{ + // CSP is static per document, so if our check said yes before, that + // answer is still valid. + JSObject *global = scopeobj->getGlobal(); + Value v = global->getReservedSlot(JSRESERVED_GLOBAL_EVAL_ALLOWED); + if (v.isUndefined()) { + JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx); + + // if there are callbacks, make sure that the CSP callback is installed and + // that it permits eval(). + v.setBoolean((!callbacks || !callbacks->contentSecurityPolicyAllows) || + callbacks->contentSecurityPolicyAllows(cx)); + + // update the cache in the global object for the result of the security check + js_SetReservedSlot(cx, global, JSRESERVED_GLOBAL_EVAL_ALLOWED, v); + } + return !v.isFalse(); +} + +/* + * Check whether principals subsumes scopeobj's principals, and return true + * if so (or if scopeobj has no principals, for backward compatibility with + * the JS API, which does not require principals), and false otherwise. + */ +JSBool +js_CheckPrincipalsAccess(JSContext *cx, JSObject *scopeobj, + JSPrincipals *principals, JSAtom *caller) +{ + JSSecurityCallbacks *callbacks; + JSPrincipals *scopePrincipals; + + callbacks = JS_GetSecurityCallbacks(cx); + if (callbacks && callbacks->findObjectPrincipals) { + scopePrincipals = callbacks->findObjectPrincipals(cx, scopeobj); + if (!principals || !scopePrincipals || + !principals->subsume(principals, scopePrincipals)) { + JSAutoByteString callerstr; + if (!js_AtomToPrintableString(cx, caller, &callerstr)) + return JS_FALSE; + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_INDIRECT_CALL, callerstr.ptr()); + return JS_FALSE; + } + } + return JS_TRUE; +} + +static bool +CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj) +{ + JSObject *inner = scopeobj; + OBJ_TO_INNER_OBJECT(cx, inner); + if (!inner) + return false; + JS_ASSERT(inner == scopeobj); + + /* XXX This is an awful gross hack. */ + while (scopeobj) { + JSObjectOp op = scopeobj->getClass()->ext.innerObject; + if (op && op(cx, scopeobj) != scopeobj) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_INDIRECT_CALL, + js_eval_str); + return false; + } + scopeobj = scopeobj->getParent(); + } + + return true; +} + +const char * +js_ComputeFilename(JSContext *cx, JSStackFrame *caller, + JSPrincipals *principals, uintN *linenop) +{ + uint32 flags; +#ifdef DEBUG + JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx); +#endif + + JS_ASSERT(principals || !(callbacks && callbacks->findObjectPrincipals)); + flags = JS_GetScriptFilenameFlags(caller->script()); + if ((flags & JSFILENAME_PROTECTED) && + principals && + strcmp(principals->codebase, "[System Principal]")) { + *linenop = 0; + return principals->codebase; + } + + jsbytecode *pc = caller->pc(cx); + if (pc && js_GetOpcode(cx, caller->script(), pc) == JSOP_EVAL) { + JS_ASSERT(js_GetOpcode(cx, caller->script(), pc + JSOP_EVAL_LENGTH) == JSOP_LINENO); + *linenop = GET_UINT16(pc + JSOP_EVAL_LENGTH); + } else { + *linenop = js_FramePCToLineNumber(cx, caller); + } + return caller->script()->filename; +} + +#ifndef EVAL_CACHE_CHAIN_LIMIT +# define EVAL_CACHE_CHAIN_LIMIT 4 +#endif + +static inline JSScript ** +EvalCacheHash(JSContext *cx, JSLinearString *str) +{ + const jschar *s = str->chars(); + size_t n = str->length(); + + if (n > 100) + n = 100; + uint32 h; + for (h = 0; n; s++, n--) + h = JS_ROTATE_LEFT32(h, 4) ^ *s; + + h *= JS_GOLDEN_RATIO; + h >>= 32 - JS_EVAL_CACHE_SHIFT; + return &JS_SCRIPTS_TO_GC(cx)[h]; +} + +static JS_ALWAYS_INLINE JSScript * +EvalCacheLookup(JSContext *cx, JSLinearString *str, JSStackFrame *caller, uintN staticLevel, + JSPrincipals *principals, JSObject *scopeobj, JSScript **bucket) +{ + /* + * Cache local eval scripts indexed by source qualified by scope. + * + * An eval cache entry should never be considered a hit unless its + * strictness matches that of the new eval code. The existing code takes + * care of this, because hits are qualified by the function from which + * eval was called, whose strictness doesn't change. (We don't cache evals + * in eval code, so the calling function corresponds to the calling script, + * and its strictness never varies.) Scripts produced by calls to eval from + * global code aren't cached. + * + * FIXME bug 620141: Qualify hits by calling script rather than function. + * Then we wouldn't need the unintuitive !isEvalFrame() hack in EvalKernel + * to avoid caching nested evals in functions (thus potentially mismatching + * on strict mode), and we could cache evals in global code if desired. + */ + uintN count = 0; + JSScript **scriptp = bucket; + + EVAL_CACHE_METER(probe); + JSVersion version = cx->findVersion(); + JSScript *script; + while ((script = *scriptp) != NULL) { + if (script->savedCallerFun && + script->staticLevel == staticLevel && + script->getVersion() == version && + !script->hasSingletons && + (script->principals == principals || + (principals->subsume(principals, script->principals) && + script->principals->subsume(script->principals, principals)))) { + /* + * Get the prior (cache-filling) eval's saved caller function. + * See Compiler::compileScript in jsparse.cpp. + */ + JSFunction *fun = script->getFunction(0); + + if (fun == caller->fun()) { + /* + * Get the source string passed for safekeeping in the + * atom map by the prior eval to Compiler::compileScript. + */ + JSAtom *src = script->atomMap.vector[0]; + + if (src == str || EqualStrings(src, str)) { + /* + * Source matches, qualify by comparing scopeobj to the + * COMPILE_N_GO-memoized parent of the first literal + * function or regexp object if any. If none, then this + * script has no compiled-in dependencies on the prior + * eval's scopeobj. + */ + JSObjectArray *objarray = script->objects(); + int i = 1; + + if (objarray->length == 1) { + if (JSScript::isValidOffset(script->regexpsOffset)) { + objarray = script->regexps(); + i = 0; + } else { + EVAL_CACHE_METER(noscope); + i = -1; + } + } + if (i < 0 || + objarray->vector[i]->getParent() == scopeobj) { + JS_ASSERT(staticLevel == script->staticLevel); + EVAL_CACHE_METER(hit); + *scriptp = script->u.nextToGC; + script->u.nextToGC = NULL; + return script; + } + } + } + } + + if (++count == EVAL_CACHE_CHAIN_LIMIT) + return NULL; + EVAL_CACHE_METER(step); + scriptp = &script->u.nextToGC; + } + return NULL; +} + +/* ES5 15.1.2.1. */ +static JSBool +eval(JSContext *cx, uintN argc, Value *vp) +{ + /* + * NB: This method handles only indirect eval: direct eval is handled by + * JSOP_EVAL. + */ + + JSStackFrame *caller = js_GetScriptedCaller(cx, NULL); + + /* FIXME Bug 602994: This really should be perfectly cromulent. */ + if (!caller) { + /* Eval code needs to inherit principals from the caller. */ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_INDIRECT_CALL, js_eval_str); + return false; + } + + return EvalKernel(cx, argc, vp, INDIRECT_EVAL, caller, vp[0].toObject().getGlobal()); +} + +namespace js { + +bool +EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame *caller, + JSObject *scopeobj) +{ + /* + * FIXME Bug 602994: Calls with no scripted caller should be permitted and + * should be implemented as indirect calls. + */ + JS_ASSERT(caller); + JS_ASSERT(scopeobj); + + /* + * We once supported a second argument to eval to use as the scope chain + * when evaluating the code string. Warn when such uses are seen so that + * authors will know that support for eval(s, o) has been removed. + */ + JSScript *callerScript = caller->script(); + if (argc > 1 && !callerScript->warnedAboutTwoArgumentEval) { + static const char TWO_ARGUMENT_WARNING[] = + "Support for eval(code, scopeObject) has been removed. " + "Use |with (scopeObject) eval(code);| instead."; + if (!JS_ReportWarning(cx, TWO_ARGUMENT_WARNING)) + return false; + callerScript->warnedAboutTwoArgumentEval = true; + } + + /* + * CSP check: Is eval() allowed at all? + * Report errors via CSP is done in the script security mgr. + */ + if (!js_CheckContentSecurityPolicy(cx, scopeobj)) { + JS_ReportError(cx, "call to eval() blocked by CSP"); + return false; + } + + /* ES5 15.1.2.1 step 1. */ + if (argc < 1) { + vp->setUndefined(); + return true; + } + if (!vp[2].isString()) { + *vp = vp[2]; + return true; + } + JSString *str = vp[2].toString(); + + /* ES5 15.1.2.1 steps 2-8. */ + JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, Jsvalify(vp))); + JS_ASSERT(IsBuiltinEvalFunction(callee->getFunctionPrivate())); + JSPrincipals *principals = js_EvalFramePrincipals(cx, callee, caller); + + /* + * Per ES5, indirect eval runs in the global scope. (eval is specified this + * way so that the compiler can make assumptions about what bindings may or + * may not exist in the current frame if it doesn't see 'eval'.) + */ + uintN staticLevel; + if (evalType == DIRECT_EVAL) { + staticLevel = caller->script()->staticLevel + 1; + +#ifdef DEBUG + jsbytecode *callerPC = caller->pc(cx); + JS_ASSERT_IF(caller->isFunctionFrame(), caller->hasCallObj()); + JS_ASSERT(callerPC && js_GetOpcode(cx, caller->script(), callerPC) == JSOP_EVAL); +#endif + } else { + /* Pretend that we're top level. */ + staticLevel = 0; + + JS_ASSERT(scopeobj == scopeobj->getGlobal()); + JS_ASSERT(scopeobj->isGlobal()); + } + + /* Ensure we compile this eval with the right object in the scope chain. */ + if (!CheckScopeChainValidity(cx, scopeobj)) + return false; + + JSLinearString *linearStr = str->ensureLinear(cx); + if (!linearStr) + return false; + const jschar *chars = linearStr->chars(); + size_t length = linearStr->length(); + + /* + * If the eval string starts with '(' and ends with ')', it may be JSON. + * Try the JSON parser first because it's much faster. If the eval string + * isn't JSON, JSON parsing will probably fail quickly, so little time + * will be lost. + */ + if (length > 2 && chars[0] == '(' && chars[length - 1] == ')') { + JSONParser *jp = js_BeginJSONParse(cx, vp, /* suppressErrors = */true); + if (jp != NULL) { + /* Run JSON-parser on string inside ( and ). */ + bool ok = js_ConsumeJSONText(cx, jp, chars + 1, length - 2); + ok &= js_FinishJSONParse(cx, jp, NullValue()); + if (ok) + return true; + } + } + + /* + * Direct calls to eval are supposed to see the caller's |this|. If we + * haven't wrapped that yet, do so now, before we make a copy of it for + * the eval code to use. + */ + if (evalType == DIRECT_EVAL && !caller->computeThis(cx)) + return false; + + JSScript *script = NULL; + JSScript **bucket = EvalCacheHash(cx, linearStr); + if (evalType == DIRECT_EVAL && caller->isFunctionFrame() && !caller->isEvalFrame()) { + script = EvalCacheLookup(cx, linearStr, caller, staticLevel, principals, scopeobj, bucket); + + /* + * Although the eval cache keeps a script alive from the perspective of + * the JS engine, from a jsdbgapi user's perspective each eval() + * creates and destroys a script. This hides implementation details and + * allows jsdbgapi clients to avoid calling JS_GetScriptObject after a + * script has been returned to the eval cache, which is invalid since + * script->u.object aliases script->u.nextToGC. + */ + if (script) { + js_CallNewScriptHook(cx, script, NULL); + MUST_FLOW_THROUGH("destroy"); + } + } + + /* + * We can't have a callerFrame (down in js::Execute's terms) if we're in + * global code (or if we're an indirect eval). + */ + JSStackFrame *callerFrame = (staticLevel != 0) ? caller : NULL; + if (!script) { + uintN lineno; + const char *filename = js_ComputeFilename(cx, caller, principals, &lineno); + + uint32 tcflags = TCF_COMPILE_N_GO | TCF_NEED_MUTABLE_SCRIPT | TCF_COMPILE_FOR_EVAL; + script = Compiler::compileScript(cx, scopeobj, callerFrame, + principals, tcflags, chars, length, + filename, lineno, cx->findVersion(), + linearStr, staticLevel); + if (!script) + return false; + } + + assertSameCompartment(cx, scopeobj, script); + + /* + * Belt-and-braces: check that the lesser of eval's principals and the + * caller's principals has access to scopeobj. + */ + JSBool ok = js_CheckPrincipalsAccess(cx, scopeobj, principals, + cx->runtime->atomState.evalAtom) && + Execute(cx, scopeobj, script, callerFrame, JSFRAME_EVAL, vp); + + MUST_FLOW_LABEL(destroy); + js_CallDestroyScriptHook(cx, script); + + script->u.nextToGC = *bucket; + *bucket = script; +#ifdef CHECK_SCRIPT_OWNER + script->owner = NULL; +#endif + + return ok; +} + +JS_FRIEND_API(bool) +IsBuiltinEvalFunction(JSFunction *fun) +{ + return fun->maybeNative() == eval; +} + +} + +#if JS_HAS_OBJ_WATCHPOINT + +static JSBool +obj_watch_handler(JSContext *cx, JSObject *obj, jsid id, jsval old, + jsval *nvp, void *closure) +{ + JSObject *callable; + JSSecurityCallbacks *callbacks; + JSStackFrame *caller; + JSPrincipals *subject, *watcher; + JSResolvingKey key; + JSResolvingEntry *entry; + uint32 generation; + Value argv[3]; + JSBool ok; + + callable = (JSObject *) closure; + + callbacks = JS_GetSecurityCallbacks(cx); + if (callbacks && callbacks->findObjectPrincipals) { + /* Skip over any obj_watch_* frames between us and the real subject. */ + caller = js_GetScriptedCaller(cx, NULL); + if (caller) { + /* + * Only call the watch handler if the watcher is allowed to watch + * the currently executing script. + */ + watcher = callbacks->findObjectPrincipals(cx, callable); + subject = js_StackFramePrincipals(cx, caller); + + if (watcher && subject && !watcher->subsume(watcher, subject)) { + /* Silently don't call the watch handler. */ + return JS_TRUE; + } + } + } + + /* Avoid recursion on (obj, id) already being watched on cx. */ + key.obj = obj; + key.id = id; + if (!js_StartResolving(cx, &key, JSRESFLAG_WATCH, &entry)) + return JS_FALSE; + if (!entry) + return JS_TRUE; + generation = cx->resolvingTable->generation; + + argv[0] = IdToValue(id); + argv[1] = Valueify(old); + argv[2] = Valueify(*nvp); + ok = ExternalInvoke(cx, ObjectValue(*obj), ObjectOrNullValue(callable), 3, argv, + Valueify(nvp)); + js_StopResolving(cx, &key, JSRESFLAG_WATCH, entry, generation); + return ok; +} + +static JSBool +obj_watch(JSContext *cx, uintN argc, Value *vp) +{ + if (argc <= 1) { + js_ReportMissingArg(cx, *vp, 1); + return JS_FALSE; + } + + JSObject *callable = js_ValueToCallableObject(cx, &vp[3], 0); + if (!callable) + return JS_FALSE; + + /* Compute the unique int/atom symbol id needed by js_LookupProperty. */ + jsid propid; + if (!ValueToId(cx, vp[2], &propid)) + return JS_FALSE; + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + Value tmp; + uintN attrs; + if (!CheckAccess(cx, obj, propid, JSACC_WATCH, &tmp, &attrs)) + return JS_FALSE; + + vp->setUndefined(); + + if (attrs & JSPROP_READONLY) + return JS_TRUE; + if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx)) + return JS_FALSE; + return JS_SetWatchPoint(cx, obj, propid, obj_watch_handler, callable); +} + +static JSBool +obj_unwatch(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + vp->setUndefined(); + jsid id; + if (argc != 0) { + if (!ValueToId(cx, vp[2], &id)) + return JS_FALSE; + } else { + id = JSID_VOID; + } + return JS_ClearWatchPoint(cx, obj, id, NULL, NULL); +} + +#endif /* JS_HAS_OBJ_WATCHPOINT */ + +/* + * Prototype and property query methods, to complement the 'in' and + * 'instanceof' operators. + */ + +/* Proposed ECMA 15.2.4.5. */ +static JSBool +obj_hasOwnProperty(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + return js_HasOwnPropertyHelper(cx, obj->getOps()->lookupProperty, argc, vp); +} + +JSBool +js_HasOwnPropertyHelper(JSContext *cx, LookupPropOp lookup, uintN argc, + Value *vp) +{ + jsid id; + if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id)) + return JS_FALSE; + + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + JSObject *obj2; + JSProperty *prop; + if (obj->isProxy()) { + bool has; + if (!JSProxy::hasOwn(cx, obj, id, &has)) + return false; + vp->setBoolean(has); + return true; + } + if (!js_HasOwnProperty(cx, lookup, obj, id, &obj2, &prop)) + return JS_FALSE; + vp->setBoolean(!!prop); + return JS_TRUE; +} + +JSBool +js_HasOwnProperty(JSContext *cx, LookupPropOp lookup, JSObject *obj, jsid id, + JSObject **objp, JSProperty **propp) +{ + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING); + if (!(lookup ? lookup : js_LookupProperty)(cx, obj, id, objp, propp)) + return false; + if (!*propp) + return true; + + if (*objp == obj) + return true; + + Class *clasp = (*objp)->getClass(); + JSObject *outer = NULL; + if (JSObjectOp op = (*objp)->getClass()->ext.outerObject) { + outer = op(cx, *objp); + if (!outer) + return false; + } + + if (outer != *objp) { + if ((*objp)->isNative() && obj->getClass() == clasp) { + /* + * The combination of JSPROP_SHARED and JSPROP_PERMANENT in a + * delegated property makes that property appear to be direct in + * all delegating instances of the same native class. This hack + * avoids bloating every function instance with its own 'length' + * (AKA 'arity') property. But it must not extend across class + * boundaries, to avoid making hasOwnProperty lie (bug 320854). + * + * It's not really a hack, of course: a permanent property can't + * be deleted, and JSPROP_SHARED means "don't allocate a slot in + * any instance, prototype or delegating". Without a slot, and + * without the ability to remove and recreate (with differences) + * the property, there is no way to tell whether it is directly + * owned, or indirectly delegated. + */ + Shape *shape = reinterpret_cast(*propp); + if (shape->isSharedPermanent()) + return true; + } + + *propp = NULL; + } + return true; +} + +/* ES5 15.2.4.6. */ +static JSBool +obj_isPrototypeOf(JSContext *cx, uintN argc, Value *vp) +{ + /* Step 1. */ + if (argc < 1 || !vp[2].isObject()) { + vp->setBoolean(false); + return true; + } + + /* Step 2. */ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + /* Step 3. */ + vp->setBoolean(js_IsDelegate(cx, obj, vp[2])); + return true; +} + +/* ES5 15.2.4.7. */ +static JSBool +obj_propertyIsEnumerable(JSContext *cx, uintN argc, Value *vp) +{ + /* Step 1. */ + jsid id; + if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id)) + return false; + + /* Step 2. */ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + /* Steps 3-5. */ + return js_PropertyIsEnumerable(cx, obj, id, vp); +} + +JSBool +js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + JSObject *pobj; + JSProperty *prop; + if (!obj->lookupProperty(cx, id, &pobj, &prop)) + return JS_FALSE; + + if (!prop) { + vp->setBoolean(false); + return JS_TRUE; + } + + /* + * XXX ECMA spec error compatible: return false unless hasOwnProperty. + * The ECMA spec really should be fixed so propertyIsEnumerable and the + * for..in loop agree on whether prototype properties are enumerable, + * obviously by fixing this method (not by breaking the for..in loop!). + * + * We check here for shared permanent prototype properties, which should + * be treated as if they are local to obj. They are an implementation + * technique used to satisfy ECMA requirements; users should not be able + * to distinguish a shared permanent proto-property from a local one. + */ + bool shared; + uintN attrs; + if (pobj->isNative()) { + Shape *shape = (Shape *) prop; + shared = shape->isSharedPermanent(); + attrs = shape->attributes(); + } else { + shared = false; + if (!pobj->getAttributes(cx, id, &attrs)) + return false; + } + if (pobj != obj && !shared) { + vp->setBoolean(false); + return true; + } + vp->setBoolean((attrs & JSPROP_ENUMERATE) != 0); + return true; +} + +#if OLD_GETTER_SETTER_METHODS + +const char js_defineGetter_str[] = "__defineGetter__"; +const char js_defineSetter_str[] = "__defineSetter__"; +const char js_lookupGetter_str[] = "__lookupGetter__"; +const char js_lookupSetter_str[] = "__lookupSetter__"; + +JS_FRIEND_API(JSBool) +js_obj_defineGetter(JSContext *cx, uintN argc, Value *vp) +{ + if (!BoxThisForVp(cx, vp)) + return false; + JSObject *obj = &vp[1].toObject(); + + if (argc <= 1 || !js_IsCallable(vp[3])) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_GETTER_OR_SETTER, + js_getter_str); + return JS_FALSE; + } + PropertyOp getter = CastAsPropertyOp(&vp[3].toObject()); + + jsid id; + if (!ValueToId(cx, vp[2], &id)) + return JS_FALSE; + if (!CheckRedeclaration(cx, obj, id, JSPROP_GETTER)) + return JS_FALSE; + /* + * Getters and setters are just like watchpoints from an access + * control point of view. + */ + Value junk; + uintN attrs; + if (!CheckAccess(cx, obj, id, JSACC_WATCH, &junk, &attrs)) + return JS_FALSE; + vp->setUndefined(); + return obj->defineProperty(cx, id, UndefinedValue(), getter, StrictPropertyStub, + JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED); +} + +JS_FRIEND_API(JSBool) +js_obj_defineSetter(JSContext *cx, uintN argc, Value *vp) +{ + if (!BoxThisForVp(cx, vp)) + return false; + JSObject *obj = &vp[1].toObject(); + + if (argc <= 1 || !js_IsCallable(vp[3])) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_GETTER_OR_SETTER, + js_setter_str); + return JS_FALSE; + } + StrictPropertyOp setter = CastAsStrictPropertyOp(&vp[3].toObject()); + + jsid id; + if (!ValueToId(cx, vp[2], &id)) + return JS_FALSE; + if (!CheckRedeclaration(cx, obj, id, JSPROP_SETTER)) + return JS_FALSE; + /* + * Getters and setters are just like watchpoints from an access + * control point of view. + */ + Value junk; + uintN attrs; + if (!CheckAccess(cx, obj, id, JSACC_WATCH, &junk, &attrs)) + return JS_FALSE; + vp->setUndefined(); + return obj->defineProperty(cx, id, UndefinedValue(), PropertyStub, setter, + JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED); +} + +static JSBool +obj_lookupGetter(JSContext *cx, uintN argc, Value *vp) +{ + jsid id; + if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id)) + return JS_FALSE; + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return JS_FALSE; + JSObject *pobj; + JSProperty *prop; + if (!obj->lookupProperty(cx, id, &pobj, &prop)) + return JS_FALSE; + vp->setUndefined(); + if (prop) { + if (pobj->isNative()) { + Shape *shape = (Shape *) prop; + if (shape->hasGetterValue()) + *vp = shape->getterValue(); + } + } + return JS_TRUE; +} + +static JSBool +obj_lookupSetter(JSContext *cx, uintN argc, Value *vp) +{ + jsid id; + if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id)) + return JS_FALSE; + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return JS_FALSE; + JSObject *pobj; + JSProperty *prop; + if (!obj->lookupProperty(cx, id, &pobj, &prop)) + return JS_FALSE; + vp->setUndefined(); + if (prop) { + if (pobj->isNative()) { + Shape *shape = (Shape *) prop; + if (shape->hasSetterValue()) + *vp = shape->setterValue(); + } + } + return JS_TRUE; +} +#endif /* OLD_GETTER_SETTER_METHODS */ + +JSBool +obj_getPrototypeOf(JSContext *cx, uintN argc, Value *vp) +{ + if (argc == 0) { + js_ReportMissingArg(cx, *vp, 0); + return JS_FALSE; + } + + if (vp[2].isPrimitive()) { + char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, vp[2], NULL); + if (!bytes) + return JS_FALSE; + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_UNEXPECTED_TYPE, bytes, "not an object"); + JS_free(cx, bytes); + return JS_FALSE; + } + + JSObject *obj = &vp[2].toObject(); + uintN attrs; + return CheckAccess(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.protoAtom), + JSACC_PROTO, vp, &attrs); +} + +extern JSBool +js_NewPropertyDescriptorObject(JSContext *cx, jsid id, uintN attrs, + const Value &getter, const Value &setter, + const Value &value, Value *vp) +{ + /* We have our own property, so start creating the descriptor. */ + JSObject *desc = NewBuiltinClassInstance(cx, &js_ObjectClass); + if (!desc) + return false; + vp->setObject(*desc); /* Root and return. */ + + const JSAtomState &atomState = cx->runtime->atomState; + if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) { + if (!desc->defineProperty(cx, ATOM_TO_JSID(atomState.getAtom), getter, + PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE) || + !desc->defineProperty(cx, ATOM_TO_JSID(atomState.setAtom), setter, + PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE)) { + return false; + } + } else { + if (!desc->defineProperty(cx, ATOM_TO_JSID(atomState.valueAtom), value, + PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE) || + !desc->defineProperty(cx, ATOM_TO_JSID(atomState.writableAtom), + BooleanValue((attrs & JSPROP_READONLY) == 0), + PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE)) { + return false; + } + } + + return desc->defineProperty(cx, ATOM_TO_JSID(atomState.enumerableAtom), + BooleanValue((attrs & JSPROP_ENUMERATE) != 0), + PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE) && + desc->defineProperty(cx, ATOM_TO_JSID(atomState.configurableAtom), + BooleanValue((attrs & JSPROP_PERMANENT) == 0), + PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE); +} + +JSBool +js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + if (obj->isProxy()) + return JSProxy::getOwnPropertyDescriptor(cx, obj, id, false, vp); + + JSObject *pobj; + JSProperty *prop; + if (!js_HasOwnProperty(cx, obj->getOps()->lookupProperty, obj, id, &pobj, &prop)) + return false; + if (!prop) { + vp->setUndefined(); + return true; + } + + Value roots[] = { UndefinedValue(), UndefinedValue(), UndefinedValue() }; + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + unsigned attrs; + bool doGet = true; + if (pobj->isNative()) { + Shape *shape = (Shape *) prop; + attrs = shape->attributes(); + if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) { + doGet = false; + if (attrs & JSPROP_GETTER) + roots[0] = shape->getterValue(); + if (attrs & JSPROP_SETTER) + roots[1] = shape->setterValue(); + } + } else { + if (!pobj->getAttributes(cx, id, &attrs)) + return false; + } + + if (doGet && !obj->getProperty(cx, id, &roots[2])) + return false; + + return js_NewPropertyDescriptorObject(cx, id, + attrs, + roots[0], /* getter */ + roots[1], /* setter */ + roots[2], /* value */ + vp); +} + +static bool +GetFirstArgumentAsObject(JSContext *cx, uintN argc, Value *vp, const char *method, JSObject **objp) +{ + if (argc == 0) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, + method, "0", "s"); + return false; + } + + const Value &v = vp[2]; + if (!v.isObject()) { + char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL); + if (!bytes) + return false; + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE, + bytes, "not an object"); + JS_free(cx, bytes); + return false; + } + + *objp = &v.toObject(); + return true; +} + +static JSBool +obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj; + if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyDescriptor", &obj)) + return JS_FALSE; + AutoIdRooter nameidr(cx); + if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), nameidr.addr())) + return JS_FALSE; + return js_GetOwnPropertyDescriptor(cx, obj, nameidr.id(), vp); +} + +static JSBool +obj_keys(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj; + if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.keys", &obj)) + return false; + + AutoIdVector props(cx); + if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props)) + return false; + + AutoValueVector vals(cx); + if (!vals.reserve(props.length())) + return false; + for (size_t i = 0, len = props.length(); i < len; i++) { + jsid id = props[i]; + if (JSID_IS_STRING(id)) { + JS_ALWAYS_TRUE(vals.append(StringValue(JSID_TO_STRING(id)))); + } else if (JSID_IS_INT(id)) { + JSString *str = js_IntToString(cx, JSID_TO_INT(id)); + if (!str) + return false; + JS_ALWAYS_TRUE(vals.append(StringValue(str))); + } else { + JS_ASSERT(JSID_IS_OBJECT(id)); + } + } + + JS_ASSERT(props.length() <= UINT32_MAX); + JSObject *aobj = NewDenseCopiedArray(cx, jsuint(vals.length()), vals.begin()); + if (!aobj) + return false; + vp->setObject(*aobj); + + return true; +} + +static bool +HasProperty(JSContext* cx, JSObject* obj, jsid id, Value* vp, bool *foundp) +{ + if (!obj->hasProperty(cx, id, foundp, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING)) + return false; + if (!*foundp) { + vp->setUndefined(); + return true; + } + + /* + * We must go through the method read barrier in case id is 'get' or 'set'. + * There is no obvious way to defer cloning a joined function object whose + * identity will be used by DefinePropertyOnObject, e.g., or reflected via + * js_GetOwnPropertyDescriptor, as the getter or setter callable object. + */ + return !!obj->getProperty(cx, id, vp); +} + +PropDesc::PropDesc() + : pd(UndefinedValue()), + id(INT_TO_JSID(0)), + value(UndefinedValue()), + get(UndefinedValue()), + set(UndefinedValue()), + attrs(0), + hasGet(false), + hasSet(false), + hasValue(false), + hasWritable(false), + hasEnumerable(false), + hasConfigurable(false) +{ +} + +bool +PropDesc::initialize(JSContext* cx, jsid id, const Value &origval) +{ + Value v = origval; + this->id = id; + + /* 8.10.5 step 1 */ + if (v.isPrimitive()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT); + return false; + } + JSObject* desc = &v.toObject(); + + /* Make a copy of the descriptor. We might need it later. */ + pd = v; + + /* Start with the proper defaults. */ + attrs = JSPROP_PERMANENT | JSPROP_READONLY; + + bool found; + + /* 8.10.5 step 3 */ +#ifdef __GNUC__ /* quell GCC overwarning */ + found = false; +#endif + if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.enumerableAtom), &v, &found)) + return false; + if (found) { + hasEnumerable = JS_TRUE; + if (js_ValueToBoolean(v)) + attrs |= JSPROP_ENUMERATE; + } + + /* 8.10.5 step 4 */ + if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.configurableAtom), &v, &found)) + return false; + if (found) { + hasConfigurable = JS_TRUE; + if (js_ValueToBoolean(v)) + attrs &= ~JSPROP_PERMANENT; + } + + /* 8.10.5 step 5 */ + if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.valueAtom), &v, &found)) + return false; + if (found) { + hasValue = true; + value = v; + } + + /* 8.10.6 step 6 */ + if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.writableAtom), &v, &found)) + return false; + if (found) { + hasWritable = JS_TRUE; + if (js_ValueToBoolean(v)) + attrs &= ~JSPROP_READONLY; + } + + /* 8.10.7 step 7 */ + if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.getAtom), &v, &found)) + return false; + if (found) { + if ((v.isPrimitive() || !js_IsCallable(v)) && !v.isUndefined()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GET_SET_FIELD, + js_getter_str); + return false; + } + hasGet = true; + get = v; + attrs |= JSPROP_GETTER | JSPROP_SHARED; + } + + /* 8.10.7 step 8 */ + if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.setAtom), &v, &found)) + return false; + if (found) { + if ((v.isPrimitive() || !js_IsCallable(v)) && !v.isUndefined()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GET_SET_FIELD, + js_setter_str); + return false; + } + hasSet = true; + set = v; + attrs |= JSPROP_SETTER | JSPROP_SHARED; + } + + /* 8.10.7 step 9 */ + if ((hasGet || hasSet) && (hasValue || hasWritable)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INVALID_DESCRIPTOR); + return false; + } + + return true; +} + +static JSBool +Reject(JSContext *cx, uintN errorNumber, bool throwError, jsid id, bool *rval) +{ + if (throwError) { + jsid idstr; + if (!js_ValueToStringId(cx, IdToValue(id), &idstr)) + return JS_FALSE; + JSAutoByteString bytes(cx, JSID_TO_STRING(idstr)); + if (!bytes) + return JS_FALSE; + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber, bytes.ptr()); + return JS_FALSE; + } + + *rval = false; + return JS_TRUE; +} + +static JSBool +Reject(JSContext *cx, JSObject *obj, uintN errorNumber, bool throwError, bool *rval) +{ + if (throwError) { + if (js_ErrorFormatString[errorNumber].argCount == 1) { + js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, + JSDVG_IGNORE_STACK, ObjectValue(*obj), + NULL, NULL, NULL); + } else { + JS_ASSERT(js_ErrorFormatString[errorNumber].argCount == 0); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber); + } + return JS_FALSE; + } + + *rval = false; + return JS_TRUE; +} + +static JSBool +DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc, + bool throwError, bool *rval) +{ + /* 8.12.9 step 1. */ + JSProperty *current; + JSObject *obj2; + JS_ASSERT(!obj->getOps()->lookupProperty); + if (!js_HasOwnProperty(cx, NULL, obj, desc.id, &obj2, ¤t)) + return JS_FALSE; + + JS_ASSERT(!obj->getOps()->defineProperty); + + /* + * If we find a shared permanent property in a different object obj2 from + * obj, then if the property is shared permanent (an old hack to optimize + * per-object properties into one prototype property), ignore that lookup + * result (null current). + * + * FIXME: bug 575997 (see also bug 607863). + */ + if (current && obj2 != obj && obj2->isNative()) { + /* See same assertion with comment further below. */ + JS_ASSERT(obj2->getClass() == obj->getClass()); + + Shape *shape = (Shape *) current; + if (shape->isSharedPermanent()) + current = NULL; + } + + /* 8.12.9 steps 2-4. */ + if (!current) { + if (!obj->isExtensible()) + return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval); + + *rval = true; + + if (desc.isGenericDescriptor() || desc.isDataDescriptor()) { + JS_ASSERT(!obj->getOps()->defineProperty); + return js_DefineProperty(cx, obj, desc.id, &desc.value, + PropertyStub, StrictPropertyStub, desc.attrs); + } + + JS_ASSERT(desc.isAccessorDescriptor()); + + /* + * Getters and setters are just like watchpoints from an access + * control point of view. + */ + Value dummy; + uintN dummyAttrs; + if (!CheckAccess(cx, obj, desc.id, JSACC_WATCH, &dummy, &dummyAttrs)) + return JS_FALSE; + + Value tmp = UndefinedValue(); + return js_DefineProperty(cx, obj, desc.id, &tmp, + desc.getter(), desc.setter(), desc.attrs); + } + + /* 8.12.9 steps 5-6 (note 5 is merely a special case of 6). */ + Value v = UndefinedValue(); + + /* + * In the special case of shared permanent properties, the "own" property + * can be found on a different object. In that case the returned property + * might not be native, except: the shared permanent property optimization + * is not applied if the objects have different classes (bug 320854), as + * must be enforced by js_HasOwnProperty for the Shape cast below to be + * safe. + */ + JS_ASSERT(obj->getClass() == obj2->getClass()); + + const Shape *shape = reinterpret_cast(current); + do { + if (desc.isAccessorDescriptor()) { + if (!shape->isAccessorDescriptor()) + break; + + if (desc.hasGet) { + JSBool same; + if (!SameValue(cx, desc.getterValue(), shape->getterOrUndefined(), &same)) + return JS_FALSE; + if (!same) + break; + } + + if (desc.hasSet) { + JSBool same; + if (!SameValue(cx, desc.setterValue(), shape->setterOrUndefined(), &same)) + return JS_FALSE; + if (!same) + break; + } + } else { + /* + * Determine the current value of the property once, if the current + * value might actually need to be used or preserved later. NB: we + * guard on whether the current property is a data descriptor to + * avoid calling a getter; we won't need the value if it's not a + * data descriptor. + */ + if (shape->isDataDescriptor()) { + /* + * We must rule out a non-configurable js::PropertyOp-guarded + * property becoming a writable unguarded data property, since + * such a property can have its value changed to one the getter + * and setter preclude. + * + * A desc lacking writable but with value is a data descriptor + * and we must reject it as if it had writable: true if current + * is writable. + */ + if (!shape->configurable() && + (!shape->hasDefaultGetter() || !shape->hasDefaultSetter()) && + desc.isDataDescriptor() && + (desc.hasWritable ? desc.writable() : shape->writable())) + { + return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval); + } + + if (!js_NativeGet(cx, obj, obj2, shape, JSGET_NO_METHOD_BARRIER, &v)) + return JS_FALSE; + } + + if (desc.isDataDescriptor()) { + if (!shape->isDataDescriptor()) + break; + + JSBool same; + if (desc.hasValue) { + if (!SameValue(cx, desc.value, v, &same)) + return JS_FALSE; + if (!same) { + /* + * Insist that a non-configurable js::PropertyOp data + * property is frozen at exactly the last-got value. + * + * Duplicate the first part of the big conjunction that + * we tested above, rather than add a local bool flag. + * Likewise, don't try to keep shape->writable() in a + * flag we veto from true to false for non-configurable + * PropertyOp-based data properties and test before the + * SameValue check later on in order to re-use that "if + * (!SameValue) Reject" logic. + * + * This function is large and complex enough that it + * seems best to repeat a small bit of code and return + * Reject(...) ASAP, instead of being clever. + */ + if (!shape->configurable() && + (!shape->hasDefaultGetter() || !shape->hasDefaultSetter())) + { + return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval); + } + break; + } + } + if (desc.hasWritable && desc.writable() != shape->writable()) + break; + } else { + /* The only fields in desc will be handled below. */ + JS_ASSERT(desc.isGenericDescriptor()); + } + } + + if (desc.hasConfigurable && desc.configurable() != shape->configurable()) + break; + if (desc.hasEnumerable && desc.enumerable() != shape->enumerable()) + break; + + /* The conditions imposed by step 5 or step 6 apply. */ + *rval = true; + return JS_TRUE; + } while (0); + + /* 8.12.9 step 7. */ + if (!shape->configurable()) { + /* + * Since [[Configurable]] defaults to false, we don't need to check + * whether it was specified. We can't do likewise for [[Enumerable]] + * because its putative value is used in a comparison -- a comparison + * whose result must always be false per spec if the [[Enumerable]] + * field is not present. Perfectly pellucid logic, eh? + */ + JS_ASSERT_IF(!desc.hasConfigurable, !desc.configurable()); + if (desc.configurable() || + (desc.hasEnumerable && desc.enumerable() != shape->enumerable())) { + return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval); + } + } + + bool callDelProperty = false; + + if (desc.isGenericDescriptor()) { + /* 8.12.9 step 8, no validation required */ + } else if (desc.isDataDescriptor() != shape->isDataDescriptor()) { + /* 8.12.9 step 9. */ + if (!shape->configurable()) + return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval); + } else if (desc.isDataDescriptor()) { + /* 8.12.9 step 10. */ + JS_ASSERT(shape->isDataDescriptor()); + if (!shape->configurable() && !shape->writable()) { + if (desc.hasWritable && desc.writable()) + return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval); + if (desc.hasValue) { + JSBool same; + if (!SameValue(cx, desc.value, v, &same)) + return JS_FALSE; + if (!same) + return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval); + } + } + + callDelProperty = !shape->hasDefaultGetter() || !shape->hasDefaultSetter(); + } else { + /* 8.12.9 step 11. */ + JS_ASSERT(desc.isAccessorDescriptor() && shape->isAccessorDescriptor()); + if (!shape->configurable()) { + if (desc.hasSet) { + JSBool same; + if (!SameValue(cx, desc.setterValue(), shape->setterOrUndefined(), &same)) + return JS_FALSE; + if (!same) + return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval); + } + + if (desc.hasGet) { + JSBool same; + if (!SameValue(cx, desc.getterValue(), shape->getterOrUndefined(), &same)) + return JS_FALSE; + if (!same) + return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval); + } + } + } + + /* 8.12.9 step 12. */ + uintN attrs; + PropertyOp getter; + StrictPropertyOp setter; + if (desc.isGenericDescriptor()) { + uintN changed = 0; + if (desc.hasConfigurable) + changed |= JSPROP_PERMANENT; + if (desc.hasEnumerable) + changed |= JSPROP_ENUMERATE; + + attrs = (shape->attributes() & ~changed) | (desc.attrs & changed); + if (shape->isMethod()) { + JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); + getter = PropertyStub; + setter = StrictPropertyStub; + } else { + getter = shape->getter(); + setter = shape->setter(); + } + } else if (desc.isDataDescriptor()) { + uintN unchanged = 0; + if (!desc.hasConfigurable) + unchanged |= JSPROP_PERMANENT; + if (!desc.hasEnumerable) + unchanged |= JSPROP_ENUMERATE; + if (!desc.hasWritable) + unchanged |= JSPROP_READONLY; + + if (desc.hasValue) + v = desc.value; + attrs = (desc.attrs & ~unchanged) | (shape->attributes() & unchanged); + getter = PropertyStub; + setter = StrictPropertyStub; + } else { + JS_ASSERT(desc.isAccessorDescriptor()); + + /* + * Getters and setters are just like watchpoints from an access + * control point of view. + */ + Value dummy; + if (!CheckAccess(cx, obj2, desc.id, JSACC_WATCH, &dummy, &attrs)) + return JS_FALSE; + + JS_ASSERT_IF(shape->isMethod(), !(attrs & (JSPROP_GETTER | JSPROP_SETTER))); + + /* 8.12.9 step 12. */ + uintN changed = 0; + if (desc.hasConfigurable) + changed |= JSPROP_PERMANENT; + if (desc.hasEnumerable) + changed |= JSPROP_ENUMERATE; + if (desc.hasGet) + changed |= JSPROP_GETTER | JSPROP_SHARED; + if (desc.hasSet) + changed |= JSPROP_SETTER | JSPROP_SHARED; + + attrs = (desc.attrs & changed) | (shape->attributes() & ~changed); + if (desc.hasGet) { + getter = desc.getter(); + } else { + getter = (shape->isMethod() || (shape->hasDefaultGetter() && !shape->hasGetterValue())) + ? PropertyStub + : shape->getter(); + } + if (desc.hasSet) { + setter = desc.setter(); + } else { + setter = (shape->hasDefaultSetter() && !shape->hasSetterValue()) + ? StrictPropertyStub + : shape->setter(); + } + } + + *rval = true; + + /* + * Since "data" properties implemented using native C functions may rely on + * side effects during setting, we must make them aware that they have been + * "assigned"; deleting the property before redefining it does the trick. + * See bug 539766, where we ran into problems when we redefined + * arguments.length without making the property aware that its value had + * been changed (which would have happened if we had deleted it before + * redefining it or we had invoked its setter to change its value). + */ + if (callDelProperty) { + Value dummy = UndefinedValue(); + if (!CallJSPropertyOp(cx, obj2->getClass()->delProperty, obj2, desc.id, &dummy)) + return false; + } + + return js_DefineProperty(cx, obj, desc.id, &v, getter, setter, attrs); +} + +static JSBool +DefinePropertyOnArray(JSContext *cx, JSObject *obj, const PropDesc &desc, + bool throwError, bool *rval) +{ + /* + * We probably should optimize dense array property definitions where + * the descriptor describes a traditional array property (enumerable, + * configurable, writable, numeric index or length without altering its + * attributes). Such definitions are probably unlikely, so we don't bother + * for now. + */ + if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx)) + return JS_FALSE; + + jsuint oldLen = obj->getArrayLength(); + + if (JSID_IS_ATOM(desc.id, cx->runtime->atomState.lengthAtom)) { + /* + * Our optimization of storage of the length property of arrays makes + * it very difficult to properly implement defining the property. For + * now simply throw an exception (NB: not merely Reject) on any attempt + * to define the "length" property, rather than attempting to implement + * some difficult-for-authors-to-grasp subset of that functionality. + */ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_DEFINE_ARRAY_LENGTH); + return JS_FALSE; + } + + uint32 index; + if (js_IdIsIndex(desc.id, &index)) { + /* + // Disabled until we support defining "length": + if (index >= oldLen && lengthPropertyNotWritable()) + return ThrowTypeError(cx, JSMSG_CANT_APPEND_TO_ARRAY); + */ + if (!DefinePropertyOnObject(cx, obj, desc, false, rval)) + return JS_FALSE; + if (!*rval) + return Reject(cx, obj, JSMSG_CANT_DEFINE_ARRAY_INDEX, throwError, rval); + + if (index >= oldLen) { + JS_ASSERT(index != UINT32_MAX); + obj->setArrayLength(index + 1); + } + + *rval = true; + return JS_TRUE; + } + + return DefinePropertyOnObject(cx, obj, desc, throwError, rval); +} + +static JSBool +DefineProperty(JSContext *cx, JSObject *obj, const PropDesc &desc, bool throwError, + bool *rval) +{ + if (obj->isArray()) + return DefinePropertyOnArray(cx, obj, desc, throwError, rval); + + if (obj->getOps()->lookupProperty) { + if (obj->isProxy()) + return JSProxy::defineProperty(cx, obj, desc.id, desc.pd); + return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval); + } + + return DefinePropertyOnObject(cx, obj, desc, throwError, rval); +} + +JSBool +js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, + const Value &descriptor, JSBool *bp) +{ + AutoPropDescArrayRooter descs(cx); + PropDesc *desc = descs.append(); + if (!desc || !desc->initialize(cx, id, descriptor)) + return false; + + bool rval; + if (!DefineProperty(cx, obj, *desc, true, &rval)) + return false; + *bp = !!rval; + return true; +} + +/* ES5 15.2.3.6: Object.defineProperty(O, P, Attributes) */ +static JSBool +obj_defineProperty(JSContext* cx, uintN argc, Value* vp) +{ + /* 15.2.3.6 steps 1 and 5. */ + JSObject *obj; + if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperty", &obj)) + return JS_FALSE; + vp->setObject(*obj); + + /* 15.2.3.6 step 2. */ + AutoIdRooter nameidr(cx); + if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), nameidr.addr())) + return JS_FALSE; + + /* 15.2.3.6 step 3. */ + const Value &descval = argc >= 3 ? vp[4] : UndefinedValue(); + + /* 15.2.3.6 step 4 */ + JSBool junk; + return js_DefineOwnProperty(cx, obj, nameidr.id(), descval, &junk); +} + +static bool +DefineProperties(JSContext *cx, JSObject *obj, JSObject *props) +{ + AutoIdArray ida(cx, JS_Enumerate(cx, props)); + if (!ida) + return false; + + AutoPropDescArrayRooter descs(cx); + size_t len = ida.length(); + for (size_t i = 0; i < len; i++) { + jsid id = ida[i]; + PropDesc* desc = descs.append(); + AutoValueRooter tvr(cx); + if (!desc || + !JS_GetPropertyById(cx, props, id, tvr.jsval_addr()) || + !desc->initialize(cx, id, tvr.value())) { + return false; + } + } + + bool dummy; + for (size_t i = 0; i < len; i++) { + if (!DefineProperty(cx, obj, descs[i], true, &dummy)) + return false; + } + + return true; +} + +extern JSBool +js_PopulateObject(JSContext *cx, JSObject *newborn, JSObject *props) +{ + return DefineProperties(cx, newborn, props); +} + +/* ES5 15.2.3.7: Object.defineProperties(O, Properties) */ +static JSBool +obj_defineProperties(JSContext* cx, uintN argc, Value* vp) +{ + /* 15.2.3.6 steps 1 and 5. */ + JSObject *obj; + if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperties", &obj)) + return false; + vp->setObject(*obj); + + if (argc < 2) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, + "Object.defineProperties", "0", "s"); + return false; + } + + JSObject* props = js_ValueToNonNullObject(cx, vp[3]); + if (!props) + return false; + vp[3].setObject(*props); + + return DefineProperties(cx, obj, props); +} + +/* ES5 15.2.3.5: Object.create(O [, Properties]) */ +static JSBool +obj_create(JSContext *cx, uintN argc, Value *vp) +{ + if (argc == 0) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, + "Object.create", "0", "s"); + return JS_FALSE; + } + + const Value &v = vp[2]; + if (!v.isObjectOrNull()) { + char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL); + if (!bytes) + return JS_FALSE; + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE, + bytes, "not an object or null"); + JS_free(cx, bytes); + return JS_FALSE; + } + + /* + * Use the callee's global as the parent of the new object to avoid dynamic + * scoping (i.e., using the caller's global). + */ + JSObject *obj = NewNonFunction(cx, &js_ObjectClass, v.toObjectOrNull(), + vp->toObject().getGlobal()); + if (!obj) + return JS_FALSE; + vp->setObject(*obj); /* Root and prepare for eventual return. */ + + /* 15.2.3.5 step 4. */ + if (argc > 1 && !vp[3].isUndefined()) { + if (vp[3].isPrimitive()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT); + return JS_FALSE; + } + + JSObject *props = &vp[3].toObject(); + AutoIdArray ida(cx, JS_Enumerate(cx, props)); + if (!ida) + return JS_FALSE; + + AutoPropDescArrayRooter descs(cx); + size_t len = ida.length(); + for (size_t i = 0; i < len; i++) { + jsid id = ida[i]; + PropDesc *desc = descs.append(); + if (!desc || !JS_GetPropertyById(cx, props, id, Jsvalify(&vp[1])) || + !desc->initialize(cx, id, vp[1])) { + return JS_FALSE; + } + } + + bool dummy; + for (size_t i = 0; i < len; i++) { + if (!DefineProperty(cx, obj, descs[i], true, &dummy)) + return JS_FALSE; + } + } + + /* 5. Return obj. */ + return JS_TRUE; +} + +static JSBool +obj_getOwnPropertyNames(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj; + if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyNames", &obj)) + return false; + + AutoIdVector keys(cx); + if (!GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &keys)) + return false; + + AutoValueVector vals(cx); + if (!vals.resize(keys.length())) + return false; + + for (size_t i = 0, len = keys.length(); i < len; i++) { + jsid id = keys[i]; + if (JSID_IS_INT(id)) { + JSString *str = js_ValueToString(cx, Int32Value(JSID_TO_INT(id))); + if (!str) + return false; + vals[i].setString(str); + } else if (JSID_IS_ATOM(id)) { + vals[i].setString(JSID_TO_STRING(id)); + } else { + vals[i].setObject(*JSID_TO_OBJECT(id)); + } + } + + JSObject *aobj = NewDenseCopiedArray(cx, vals.length(), vals.begin()); + if (!aobj) + return false; + + vp->setObject(*aobj); + return true; +} + +static JSBool +obj_isExtensible(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj; + if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.isExtensible", &obj)) + return false; + + vp->setBoolean(obj->isExtensible()); + return true; +} + +static JSBool +obj_preventExtensions(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj; + if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.preventExtensions", &obj)) + return false; + + vp->setObject(*obj); + if (!obj->isExtensible()) + return true; + + AutoIdVector props(cx); + return obj->preventExtensions(cx, &props); +} + +bool +JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it) +{ + assertSameCompartment(cx, this); + JS_ASSERT(it == SEAL || it == FREEZE); + + AutoIdVector props(cx); + if (isExtensible()) { + if (!preventExtensions(cx, &props)) + return false; + } else { + if (!GetPropertyNames(cx, this, JSITER_HIDDEN | JSITER_OWNONLY, &props)) + return false; + } + + /* preventExtensions must slowify dense arrays, so we can assign to holes without checks. */ + JS_ASSERT(!isDenseArray()); + + for (size_t i = 0, len = props.length(); i < len; i++) { + jsid id = props[i]; + + uintN attrs; + if (!getAttributes(cx, id, &attrs)) + return false; + + /* Make all attributes permanent; if freezing, make data attributes read-only. */ + uintN new_attrs; + if (it == FREEZE && !(attrs & (JSPROP_GETTER | JSPROP_SETTER))) + new_attrs = JSPROP_PERMANENT | JSPROP_READONLY; + else + new_attrs = JSPROP_PERMANENT; + + /* If we already have the attributes we need, skip the setAttributes call. */ + if ((attrs | new_attrs) == attrs) + continue; + + attrs |= new_attrs; + if (!setAttributes(cx, id, &attrs)) + return false; + } + + return true; +} + +static JSBool +obj_freeze(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj; + if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.freeze", &obj)) + return false; + + vp->setObject(*obj); + + return obj->freeze(cx); +} + +static JSBool +obj_isFrozen(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj; + if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.preventExtensions", &obj)) + return false; + + vp->setBoolean(false); + + if (obj->isExtensible()) + return true; /* The JavaScript value returned is false. */ + + AutoIdVector props(cx); + if (!GetPropertyNames(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, &props)) + return false; + + for (size_t i = 0, len = props.length(); i < len; i++) { + jsid id = props[i]; + + uintN attrs = 0; + if (!obj->getAttributes(cx, id, &attrs)) + return false; + + /* The property must be non-configurable and either read-only or an accessor. */ + if (!(attrs & JSPROP_PERMANENT) || + !(attrs & (JSPROP_READONLY | JSPROP_GETTER | JSPROP_SETTER))) + return true; /* The JavaScript value returned is false. */ + } + + /* It really was sealed, so return true. */ + vp->setBoolean(true); + return true; +} + +static JSBool +obj_seal(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj; + if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.seal", &obj)) + return false; + + vp->setObject(*obj); + + return obj->seal(cx); +} + +static JSBool +obj_isSealed(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj; + if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.isSealed", &obj)) + return false; + + /* Assume not sealed until proven otherwise. */ + vp->setBoolean(false); + + if (obj->isExtensible()) + return true; /* The JavaScript value returned is false. */ + + AutoIdVector props(cx); + if (!GetPropertyNames(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, &props)) + return false; + + for (size_t i = 0, len = props.length(); i < len; i++) { + jsid id = props[i]; + + uintN attrs; + if (!obj->getAttributes(cx, id, &attrs)) + return false; + + if (!(attrs & JSPROP_PERMANENT)) + return true; /* The JavaScript value returned is false. */ + } + + /* It really was sealed, so return true. */ + vp->setBoolean(true); + return true; +} + +#if JS_HAS_OBJ_WATCHPOINT +const char js_watch_str[] = "watch"; +const char js_unwatch_str[] = "unwatch"; +#endif +const char js_hasOwnProperty_str[] = "hasOwnProperty"; +const char js_isPrototypeOf_str[] = "isPrototypeOf"; +const char js_propertyIsEnumerable_str[] = "propertyIsEnumerable"; + +static JSFunctionSpec object_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, obj_toSource, 0,0), +#endif + JS_FN(js_toString_str, obj_toString, 0,0), + JS_FN(js_toLocaleString_str, obj_toLocaleString, 0,0), + JS_FN(js_valueOf_str, obj_valueOf, 0,0), +#if JS_HAS_OBJ_WATCHPOINT + JS_FN(js_watch_str, obj_watch, 2,0), + JS_FN(js_unwatch_str, obj_unwatch, 1,0), +#endif + JS_FN(js_hasOwnProperty_str, obj_hasOwnProperty, 1,0), + JS_FN(js_isPrototypeOf_str, obj_isPrototypeOf, 1,0), + JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0), +#if OLD_GETTER_SETTER_METHODS + JS_FN(js_defineGetter_str, js_obj_defineGetter, 2,0), + JS_FN(js_defineSetter_str, js_obj_defineSetter, 2,0), + JS_FN(js_lookupGetter_str, obj_lookupGetter, 1,0), + JS_FN(js_lookupSetter_str, obj_lookupSetter, 1,0), +#endif + JS_FS_END +}; + +static JSFunctionSpec object_static_methods[] = { + JS_FN("getPrototypeOf", obj_getPrototypeOf, 1,0), + JS_FN("getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor,2,0), + JS_FN("keys", obj_keys, 1,0), + JS_FN("defineProperty", obj_defineProperty, 3,0), + JS_FN("defineProperties", obj_defineProperties, 2,0), + JS_FN("create", obj_create, 2,0), + JS_FN("getOwnPropertyNames", obj_getOwnPropertyNames, 1,0), + JS_FN("isExtensible", obj_isExtensible, 1,0), + JS_FN("preventExtensions", obj_preventExtensions, 1,0), + JS_FN("freeze", obj_freeze, 1,0), + JS_FN("isFrozen", obj_isFrozen, 1,0), + JS_FN("seal", obj_seal, 1,0), + JS_FN("isSealed", obj_isSealed, 1,0), + JS_FS_END +}; + +JSBool +js_Object(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj; + if (argc == 0) { + /* Trigger logic below to construct a blank object. */ + obj = NULL; + } else { + /* If argv[0] is null or undefined, obj comes back null. */ + if (!js_ValueToObjectOrNull(cx, vp[2], &obj)) + return JS_FALSE; + } + if (!obj) { + /* Make an object whether this was called with 'new' or not. */ + JS_ASSERT(!argc || vp[2].isNull() || vp[2].isUndefined()); + gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass); + obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind); + if (!obj) + return JS_FALSE; + } + vp->setObject(*obj); + return JS_TRUE; +} + +JSObject* +js_CreateThis(JSContext *cx, JSObject *callee) +{ + Class *clasp = callee->getClass(); + + Class *newclasp = &js_ObjectClass; + if (clasp == &js_FunctionClass) { + JSFunction *fun = callee->getFunctionPrivate(); + if (fun->isNative() && fun->u.n.clasp) + newclasp = fun->u.n.clasp; + } + + Value protov; + if (!callee->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &protov)) + return NULL; + + JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : NULL; + JSObject *parent = callee->getParent(); + gc::FinalizeKind kind = NewObjectGCKind(cx, newclasp); + JSObject *obj = NewObject(cx, newclasp, proto, parent, kind); + if (obj) + obj->syncSpecialEquality(); + return obj; +} + +JSObject * +js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *proto) +{ + gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass); + return NewNonFunction(cx, &js_ObjectClass, proto, callee->getParent(), kind); +} + +JSObject * +js_CreateThisForFunction(JSContext *cx, JSObject *callee) +{ + Value protov; + if (!callee->getProperty(cx, + ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), + &protov)) { + return NULL; + } + JSObject *proto = protov.isObject() ? &protov.toObject() : NULL; + return js_CreateThisForFunctionWithProto(cx, callee, proto); +} + +#ifdef JS_TRACER + +static JS_ALWAYS_INLINE JSObject* +NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto, + /*gc::FinalizeKind*/ unsigned _kind) +{ + JS_ASSERT(clasp->isNative()); + gc::FinalizeKind kind = gc::FinalizeKind(_kind); + + JSObject* obj = js_NewGCObject(cx, kind); + if (!obj) + return NULL; + + if (!obj->initSharingEmptyShape(cx, clasp, proto, proto->getParent(), NULL, kind)) + return NULL; + return obj; +} + +JSObject* FASTCALL +js_Object_tn(JSContext* cx, JSObject* proto) +{ + JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE)); + return NewObjectWithClassProto(cx, &js_ObjectClass, proto, FINALIZE_OBJECT8); +} + +JS_DEFINE_TRCINFO_1(js_Object, + (2, (extern, CONSTRUCTOR_RETRY, js_Object_tn, CONTEXT, CALLEE_PROTOTYPE, 0, + nanojit::ACCSET_STORE_ANY))) + +JSObject* FASTCALL +js_InitializerObject(JSContext* cx, JSObject *proto, JSObject *baseobj) +{ + if (!baseobj) { + gc::FinalizeKind kind = GuessObjectGCKind(0, false); + return NewObjectWithClassProto(cx, &js_ObjectClass, proto, kind); + } + + return CopyInitializerObject(cx, baseobj); +} + +JS_DEFINE_CALLINFO_3(extern, OBJECT, js_InitializerObject, CONTEXT, OBJECT, OBJECT, + 0, nanojit::ACCSET_STORE_ANY) + +JSObject* FASTCALL +js_String_tn(JSContext* cx, JSObject* proto, JSString* str) +{ + JS_ASSERT(JS_ON_TRACE(cx)); + JSObject *obj = NewObjectWithClassProto(cx, &js_StringClass, proto, FINALIZE_OBJECT2); + if (!obj) + return NULL; + obj->setPrimitiveThis(StringValue(str)); + return obj; +} +JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, STRING, 0, + nanojit::ACCSET_STORE_ANY) + +JSObject * FASTCALL +js_CreateThisFromTrace(JSContext *cx, JSObject *ctor, uintN protoSlot) +{ +#ifdef DEBUG + JS_ASSERT(ctor->isFunction()); + JS_ASSERT(ctor->getFunctionPrivate()->isInterpreted()); + jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom); + const Shape *shape = ctor->nativeLookup(id); + JS_ASSERT(shape->slot == protoSlot); + JS_ASSERT(!shape->configurable()); + JS_ASSERT(!shape->isMethod()); +#endif + + JSObject *parent = ctor->getParent(); + JSObject *proto; + const Value &protov = ctor->getSlotRef(protoSlot); + if (protov.isObject()) { + proto = &protov.toObject(); + } else { + /* + * GetInterpretedFunctionPrototype found that ctor.prototype is + * primitive. Use Object.prototype for proto, per ES5 13.2.2 step 7. + */ + if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto)) + return NULL; + } + + gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass); + return NewNativeClassInstance(cx, &js_ObjectClass, proto, parent, kind); +} +JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_CreateThisFromTrace, CONTEXT, OBJECT, UINTN, 0, + nanojit::ACCSET_STORE_ANY) + +#else /* !JS_TRACER */ + +# define js_Object_trcinfo NULL + +#endif /* !JS_TRACER */ + +/* + * Given pc pointing after a property accessing bytecode, return true if the + * access is "object-detecting" in the sense used by web scripts, e.g., when + * checking whether document.all is defined. + */ +JS_REQUIRES_STACK JSBool +Detecting(JSContext *cx, jsbytecode *pc) +{ + JSScript *script; + jsbytecode *endpc; + JSOp op; + JSAtom *atom; + + script = cx->fp()->script(); + endpc = script->code + script->length; + for (;; pc += js_CodeSpec[op].length) { + JS_ASSERT_IF(!cx->fp()->hasImacropc(), script->code <= pc && pc < endpc); + + /* General case: a branch or equality op follows the access. */ + op = js_GetOpcode(cx, script, pc); + if (js_CodeSpec[op].format & JOF_DETECTING) + return JS_TRUE; + + switch (op) { + case JSOP_NULL: + /* + * Special case #1: handle (document.all == null). Don't sweat + * about JS1.2's revision of the equality operators here. + */ + if (++pc < endpc) { + op = js_GetOpcode(cx, script, pc); + return *pc == JSOP_EQ || *pc == JSOP_NE; + } + return JS_FALSE; + + case JSOP_GETGNAME: + case JSOP_NAME: + /* + * Special case #2: handle (document.all == undefined). Don't + * worry about someone redefining undefined, which was added by + * Edition 3, so is read/write for backward compatibility. + */ + GET_ATOM_FROM_BYTECODE(script, pc, 0, atom); + if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] && + (pc += js_CodeSpec[op].length) < endpc) { + op = js_GetOpcode(cx, script, pc); + return op == JSOP_EQ || op == JSOP_NE || + op == JSOP_STRICTEQ || op == JSOP_STRICTNE; + } + return JS_FALSE; + + default: + /* + * At this point, anything but an extended atom index prefix means + * we're not detecting. + */ + if (!(js_CodeSpec[op].format & JOF_INDEXBASE)) + return JS_FALSE; + break; + } + } +} + +/* + * Infer lookup flags from the currently executing bytecode. This does + * not attempt to infer JSRESOLVE_WITH, because the current bytecode + * does not indicate whether we are in a with statement. Return defaultFlags + * if a currently executing bytecode cannot be determined. + */ +uintN +js_InferFlags(JSContext *cx, uintN defaultFlags) +{ +#ifdef JS_TRACER + if (JS_ON_TRACE(cx)) + return JS_TRACE_MONITOR_ON_TRACE(cx)->bailExit->lookupFlags; +#endif + + JS_ASSERT_NOT_ON_TRACE(cx); + + jsbytecode *pc; + const JSCodeSpec *cs; + uint32 format; + uintN flags = 0; + + JSStackFrame *const fp = js_GetTopStackFrame(cx); + if (!fp || !(pc = cx->regs->pc)) + return defaultFlags; + cs = &js_CodeSpec[js_GetOpcode(cx, fp->script(), pc)]; + format = cs->format; + if (JOF_MODE(format) != JOF_NAME) + flags |= JSRESOLVE_QUALIFIED; + if ((format & (JOF_SET | JOF_FOR)) || fp->isAssigning()) { + flags |= JSRESOLVE_ASSIGNING; + } else if (cs->length >= 0) { + pc += cs->length; + JSScript *script = cx->fp()->script(); + if (pc < script->code + script->length && Detecting(cx, pc)) + flags |= JSRESOLVE_DETECTING; + } + if (format & JOF_DECLARING) + flags |= JSRESOLVE_DECLARING; + return flags; +} + +/* + * ObjectOps and Class for with-statement stack objects. + */ +static JSBool +with_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + JSProperty **propp) +{ + /* Fixes bug 463997 */ + uintN flags = cx->resolveFlags; + if (flags == JSRESOLVE_INFER) + flags = js_InferFlags(cx, flags); + flags |= JSRESOLVE_WITH; + JSAutoResolveFlags rf(cx, flags); + return obj->getProto()->lookupProperty(cx, id, objp, propp); +} + +static JSBool +with_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp) +{ + return obj->getProto()->getProperty(cx, id, vp); +} + +static JSBool +with_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) +{ + return obj->getProto()->setProperty(cx, id, vp, strict); +} + +static JSBool +with_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +{ + return obj->getProto()->getAttributes(cx, id, attrsp); +} + +static JSBool +with_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +{ + return obj->getProto()->setAttributes(cx, id, attrsp); +} + +static JSBool +with_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) +{ + return obj->getProto()->deleteProperty(cx, id, rval, strict); +} + +static JSBool +with_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + Value *statep, jsid *idp) +{ + return obj->getProto()->enumerate(cx, enum_op, statep, idp); +} + +static JSType +with_TypeOf(JSContext *cx, JSObject *obj) +{ + return JSTYPE_OBJECT; +} + +static JSObject * +with_ThisObject(JSContext *cx, JSObject *obj) +{ + return obj->getWithThis(); +} + +Class js_WithClass = { + "With", + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS, + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub, + NULL, /* finalize */ + NULL, /* reserved */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + NULL, /* mark */ + JS_NULL_CLASS_EXT, + { + with_LookupProperty, + NULL, /* defineProperty */ + with_GetProperty, + with_SetProperty, + with_GetAttributes, + with_SetAttributes, + with_DeleteProperty, + with_Enumerate, + with_TypeOf, + NULL, /* trace */ + NULL, /* fix */ + with_ThisObject, + NULL, /* clear */ + } +}; + +JS_REQUIRES_STACK JSObject * +js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth) +{ + JSObject *obj; + + obj = js_NewGCObject(cx, FINALIZE_OBJECT2); + if (!obj) + return NULL; + + JSStackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp()); + + obj->init(cx, &js_WithClass, proto, parent, priv, false); + obj->setMap(cx->compartment->emptyWithShape); + OBJ_SET_BLOCK_DEPTH(cx, obj, depth); + + AutoObjectRooter tvr(cx, obj); + JSObject *thisp = proto->thisObject(cx); + if (!thisp) + return NULL; + + assertSameCompartment(cx, obj, thisp); + + obj->setWithThis(thisp); + return obj; +} + +JSObject * +js_NewBlockObject(JSContext *cx) +{ + /* + * Null obj's proto slot so that Object.prototype.* does not pollute block + * scopes and to give the block object its own scope. + */ + JSObject *blockObj = js_NewGCObject(cx, FINALIZE_OBJECT2); + if (!blockObj) + return NULL; + + blockObj->init(cx, &js_BlockClass, NULL, NULL, NULL, false); + blockObj->setMap(cx->compartment->emptyBlockShape); + return blockObj; +} + +JSObject * +js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp) +{ + JS_ASSERT(proto->isStaticBlock()); + + size_t count = OBJ_BLOCK_COUNT(cx, proto); + gc::FinalizeKind kind = gc::GetGCObjectKind(count + 1); + + JSObject *clone = js_NewGCObject(cx, kind); + if (!clone) + return NULL; + + JSStackFrame *priv = js_FloatingFrameIfGenerator(cx, fp); + + /* The caller sets parent on its own. */ + clone->init(cx, &js_BlockClass, proto, NULL, priv, false); + + clone->setMap(proto->map); + if (!clone->ensureInstanceReservedSlots(cx, count + 1)) + return NULL; + + clone->setSlot(JSSLOT_BLOCK_DEPTH, proto->getSlot(JSSLOT_BLOCK_DEPTH)); + + JS_ASSERT(clone->isClonedBlock()); + return clone; +} + +JS_REQUIRES_STACK JSBool +js_PutBlockObject(JSContext *cx, JSBool normalUnwind) +{ + JSStackFrame *const fp = cx->fp(); + JSObject *obj = &fp->scopeChain(); + JS_ASSERT(obj->isClonedBlock()); + JS_ASSERT(obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp())); + + /* Block objects should have all reserved slots allocated early. */ + uintN count = OBJ_BLOCK_COUNT(cx, obj); + JS_ASSERT(obj->numSlots() >= JSSLOT_BLOCK_DEPTH + 1 + count); + + /* The block and its locals must be on the current stack for GC safety. */ + uintN depth = OBJ_BLOCK_DEPTH(cx, obj); + JS_ASSERT(depth <= size_t(cx->regs->sp - fp->base())); + JS_ASSERT(count <= size_t(cx->regs->sp - fp->base() - depth)); + + /* See comments in CheckDestructuring from jsparse.cpp. */ + JS_ASSERT(count >= 1); + + if (normalUnwind) { + uintN slot = JSSLOT_BLOCK_FIRST_FREE_SLOT; + depth += fp->numFixed(); + memcpy(obj->getSlots() + slot, fp->slots() + depth, count * sizeof(Value)); + } + + /* We must clear the private slot even with errors. */ + obj->setPrivate(NULL); + fp->setScopeChainNoCallObj(*obj->getParent()); + return normalUnwind; +} + +static JSBool +block_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + /* + * Block objects are never exposed to script, and the engine handles them + * with care. So unlike other getters, this one can assert (rather than + * check) certain invariants about obj. + */ + JS_ASSERT(obj->isClonedBlock()); + uintN index = (uintN) JSID_TO_INT(id); + JS_ASSERT(index < OBJ_BLOCK_COUNT(cx, obj)); + + JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); + if (fp) { + fp = js_LiveFrameIfGenerator(fp); + index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj); + JS_ASSERT(index < fp->numSlots()); + *vp = fp->slots()[index]; + return true; + } + + /* Values are in slots immediately following the class-reserved ones. */ + JS_ASSERT(obj->getSlot(JSSLOT_FREE(&js_BlockClass) + index) == *vp); + return true; +} + +static JSBool +block_setProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp) +{ + JS_ASSERT(obj->isClonedBlock()); + uintN index = (uintN) JSID_TO_INT(id); + JS_ASSERT(index < OBJ_BLOCK_COUNT(cx, obj)); + + JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); + if (fp) { + fp = js_LiveFrameIfGenerator(fp); + index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj); + JS_ASSERT(index < fp->numSlots()); + fp->slots()[index] = *vp; + return true; + } + + /* + * The value in *vp will be written back to the slot in obj that was + * allocated when this let binding was defined. + */ + return true; +} + +const Shape * +JSObject::defineBlockVariable(JSContext *cx, jsid id, intN index) +{ + JS_ASSERT(isStaticBlock()); + + /* Use JSPROP_ENUMERATE to aid the disassembler. */ + uint32 slot = JSSLOT_FREE(&js_BlockClass) + index; + const Shape *shape = addProperty(cx, id, + block_getProperty, block_setProperty, + slot, JSPROP_ENUMERATE | JSPROP_PERMANENT, + Shape::HAS_SHORTID, index); + if (!shape) + return NULL; + if (slot >= numSlots() && !growSlots(cx, slot + 1)) + return NULL; + return shape; +} + +static size_t +GetObjectSize(JSObject *obj) +{ + return (obj->isFunction() && !obj->getPrivate()) + ? sizeof(JSFunction) + : sizeof(JSObject) + sizeof(js::Value) * obj->numFixedSlots(); +} + +bool +JSObject::copyPropertiesFrom(JSContext *cx, JSObject *obj) +{ + // If we're not native, then we cannot copy properties. + JS_ASSERT(isNative() == obj->isNative()); + if (!isNative()) + return true; + + AutoShapeVector shapes(cx); + for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) { + if (!shapes.append(&r.front())) + return false; + } + + size_t n = shapes.length(); + while (n > 0) { + const Shape *shape = shapes[--n]; + uintN attrs = shape->attributes(); + PropertyOp getter = shape->getter(); + if ((attrs & JSPROP_GETTER) && !cx->compartment->wrap(cx, &getter)) + return false; + StrictPropertyOp setter = shape->setter(); + if ((attrs & JSPROP_SETTER) && !cx->compartment->wrap(cx, &setter)) + return false; + Value v = shape->hasSlot() ? obj->getSlot(shape->slot) : UndefinedValue(); + if (!cx->compartment->wrap(cx, &v)) + return false; + if (!defineProperty(cx, shape->id, v, getter, setter, attrs)) + return false; + } + return true; +} + +static bool +CopySlots(JSContext *cx, JSObject *from, JSObject *to) +{ + JS_ASSERT(!from->isNative() && !to->isNative()); + size_t nslots = from->numSlots(); + if (to->ensureSlots(cx, nslots)) + return false; + + size_t n = 0; + if (to->isWrapper() && + (JSWrapper::wrapperHandler(to)->flags() & JSWrapper::CROSS_COMPARTMENT)) { + to->slots[0] = from->slots[0]; + to->slots[1] = from->slots[1]; + n = 2; + } + + for (; n < nslots; ++n) { + Value v = from->slots[n]; + if (!cx->compartment->wrap(cx, &v)) + return false; + to->slots[n] = v; + } + return true; +} + +JSObject * +JSObject::clone(JSContext *cx, JSObject *proto, JSObject *parent) +{ + /* + * We can only clone native objects and proxies. Dense arrays are slowified if + * we try to clone them. + */ + if (!isNative()) { + if (isDenseArray()) { + if (!makeDenseArraySlow(cx)) + return NULL; + } else if (!isProxy()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_CLONE_OBJECT); + return NULL; + } + } + JSObject *clone = NewObject(cx, getClass(), + proto, parent, + gc::FinalizeKind(finalizeKind())); + if (!clone) + return NULL; + if (isNative()) { + if (clone->isFunction() && (compartment() != clone->compartment())) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_CLONE_OBJECT); + return NULL; + } + + if (getClass()->flags & JSCLASS_HAS_PRIVATE) + clone->setPrivate(getPrivate()); + } else { + JS_ASSERT(isProxy()); + if (!CopySlots(cx, this, clone)) + return NULL; + } + return clone; +} + +static void +TradeGuts(JSObject *a, JSObject *b) +{ + JS_ASSERT(a->compartment() == b->compartment()); + JS_ASSERT(a->isFunction() == b->isFunction()); + + /* + * Regexp guts are more complicated -- we would need to migrate the + * refcounted JIT code blob for them across compartments instead of just + * swapping guts. + */ + JS_ASSERT(!a->isRegExp() && !b->isRegExp()); + + bool aInline = !a->hasSlotsArray(); + bool bInline = !b->hasSlotsArray(); + + /* Trade the guts of the objects. */ + const size_t size = GetObjectSize(a); + if (size == GetObjectSize(b)) { + /* + * If the objects are the same size, then we make no assumptions about + * whether they have dynamically allocated slots and instead just copy + * them over wholesale. + */ + char tmp[tl::Max::result]; + JS_ASSERT(size <= sizeof(tmp)); + + memcpy(tmp, a, size); + memcpy(a, b, size); + memcpy(b, tmp, size); + + /* Fixup pointers for inline slots on the objects. */ + if (aInline) + b->slots = b->fixedSlots(); + if (bInline) + a->slots = a->fixedSlots(); + } else { + /* + * If the objects are of differing sizes, then we only copy over the + * JSObject portion (things like class, etc.) and leave it to + * JSObject::clone to copy over the dynamic slots for us. + */ + if (a->isFunction()) { + JSFunction tmp; + memcpy(&tmp, a, sizeof tmp); + memcpy(a, b, sizeof tmp); + memcpy(b, &tmp, sizeof tmp); + } else { + JSObject tmp; + memcpy(&tmp, a, sizeof tmp); + memcpy(a, b, sizeof tmp); + memcpy(b, &tmp, sizeof tmp); + } + + JS_ASSERT(!aInline); + JS_ASSERT(!bInline); + } +} + +/* + * Use this method with extreme caution. It trades the guts of two objects and updates + * scope ownership. This operation is not thread-safe, just as fast array to slow array + * transitions are inherently not thread-safe. Don't perform a swap operation on objects + * shared across threads or, or bad things will happen. You have been warned. + */ +bool +JSObject::swap(JSContext *cx, JSObject *other) +{ + /* + * If we are swapping objects with a different number of builtin slots, force + * both to not use their inline slots. + */ + if (GetObjectSize(this) != GetObjectSize(other)) { + if (!hasSlotsArray()) { + if (!allocSlots(cx, numSlots())) + return false; + } + if (!other->hasSlotsArray()) { + if (!other->allocSlots(cx, other->numSlots())) + return false; + } + } + + if (this->compartment() == other->compartment()) { + TradeGuts(this, other); + return true; + } + + JSObject *thisClone; + JSObject *otherClone; + { + AutoCompartment ac(cx, other); + if (!ac.enter()) + return false; + thisClone = this->clone(cx, other->getProto(), other->getParent()); + if (!thisClone || !thisClone->copyPropertiesFrom(cx, this)) + return false; + } + { + AutoCompartment ac(cx, this); + if (!ac.enter()) + return false; + otherClone = other->clone(cx, other->getProto(), other->getParent()); + if (!otherClone || !otherClone->copyPropertiesFrom(cx, other)) + return false; + } + TradeGuts(this, otherClone); + TradeGuts(other, thisClone); + + return true; +} + +#if JS_HAS_XDR + +#define NO_PARENT_INDEX ((uint32)-1) + +uint32 +FindObjectIndex(JSObjectArray *array, JSObject *obj) +{ + size_t i; + + if (array) { + i = array->length; + do { + + if (array->vector[--i] == obj) + return i; + } while (i != 0); + } + + return NO_PARENT_INDEX; +} + +JSBool +js_XDRBlockObject(JSXDRState *xdr, JSObject **objp) +{ + JSContext *cx; + uint32 parentId; + JSObject *obj, *parent; + uintN depth, count; + uint32 depthAndCount; + const Shape *shape; + + cx = xdr->cx; +#ifdef __GNUC__ + obj = NULL; /* quell GCC overwarning */ +#endif + + if (xdr->mode == JSXDR_ENCODE) { + obj = *objp; + parent = obj->getParent(); + parentId = JSScript::isValidOffset(xdr->script->objectsOffset) + ? FindObjectIndex(xdr->script->objects(), parent) + : NO_PARENT_INDEX; + depth = (uint16)OBJ_BLOCK_DEPTH(cx, obj); + count = (uint16)OBJ_BLOCK_COUNT(cx, obj); + depthAndCount = (uint32)(depth << 16) | count; + } +#ifdef __GNUC__ /* suppress bogus gcc warnings */ + else count = 0; +#endif + + /* First, XDR the parent atomid. */ + if (!JS_XDRUint32(xdr, &parentId)) + return JS_FALSE; + + if (xdr->mode == JSXDR_DECODE) { + obj = js_NewBlockObject(cx); + if (!obj) + return JS_FALSE; + *objp = obj; + + /* + * If there's a parent id, then get the parent out of our script's + * object array. We know that we XDR block object in outer-to-inner + * order, which means that getting the parent now will work. + */ + if (parentId == NO_PARENT_INDEX) + parent = NULL; + else + parent = xdr->script->getObject(parentId); + obj->setParent(parent); + } + + AutoObjectRooter tvr(cx, obj); + + if (!JS_XDRUint32(xdr, &depthAndCount)) + return false; + + if (xdr->mode == JSXDR_DECODE) { + depth = (uint16)(depthAndCount >> 16); + count = (uint16)depthAndCount; + obj->setSlot(JSSLOT_BLOCK_DEPTH, Value(Int32Value(depth))); + + /* + * XDR the block object's properties. We know that there are 'count' + * properties to XDR, stored as id/shortid pairs. + */ + for (uintN i = 0; i < count; i++) { + JSAtom *atom; + uint16 shortid; + + /* XDR the real id, then the shortid. */ + if (!js_XDRAtom(xdr, &atom) || !JS_XDRUint16(xdr, &shortid)) + return false; + + if (!obj->defineBlockVariable(cx, ATOM_TO_JSID(atom), shortid)) + return false; + } + } else { + AutoShapeVector shapes(cx); + shapes.growBy(count); + + for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) { + shape = &r.front(); + shapes[shape->shortid] = shape; + } + + /* + * XDR the block object's properties. We know that there are 'count' + * properties to XDR, stored as id/shortid pairs. + */ + for (uintN i = 0; i < count; i++) { + shape = shapes[i]; + JS_ASSERT(shape->getter() == block_getProperty); + + jsid propid = shape->id; + JS_ASSERT(JSID_IS_ATOM(propid)); + JSAtom *atom = JSID_TO_ATOM(propid); + + uint16 shortid = uint16(shape->shortid); + JS_ASSERT(shortid == i); + + /* XDR the real id, then the shortid. */ + if (!js_XDRAtom(xdr, &atom) || !JS_XDRUint16(xdr, &shortid)) + return false; + } + } + return true; +} + +#endif + +Class js_BlockClass = { + "Block", + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_IS_ANONYMOUS, + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub +}; + +JSObject * +js_InitObjectClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto = js_InitClass(cx, obj, NULL, &js_ObjectClass, js_Object, 1, + object_props, object_methods, NULL, object_static_methods); + if (!proto) + return NULL; + + /* ECMA (15.1.2.1) says 'eval' is a property of the global object. */ + jsid id = ATOM_TO_JSID(cx->runtime->atomState.evalAtom); + if (!js_DefineFunction(cx, obj, id, eval, 1, JSFUN_STUB_GSOPS)) + return NULL; + + return proto; +} + +static bool +DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom, + const Value &v, uint32 attrs, bool &named) +{ + jsid id = ATOM_TO_JSID(atom); + + if (key != JSProto_Null) { + /* + * Initializing an actual standard class on a global object. If the + * property is not yet present, force it into a new one bound to a + * reserved slot. Otherwise, go through the normal property path. + */ + JS_ASSERT(obj->isGlobal()); + JS_ASSERT(obj->isNative()); + + if (!obj->ensureClassReservedSlots(cx)) + return false; + + const Shape *shape = obj->nativeLookup(id); + if (!shape) { + uint32 slot = 2 * JSProto_LIMIT + key; + if (!js_SetReservedSlot(cx, obj, slot, v)) + return false; + if (!obj->addProperty(cx, id, PropertyStub, StrictPropertyStub, slot, attrs, 0, 0)) + return false; + + named = true; + return true; + } + } + + named = obj->defineProperty(cx, id, v, PropertyStub, StrictPropertyStub, attrs); + return named; +} + +namespace js { + +JSObject * +DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom, + JSObject *protoProto, Class *clasp, + Native constructor, uintN nargs, + JSPropertySpec *ps, JSFunctionSpec *fs, + JSPropertySpec *static_ps, JSFunctionSpec *static_fs) +{ + /* + * Create a prototype object for this class. + * + * FIXME: lazy standard (built-in) class initialization and even older + * eager boostrapping code rely on all of these properties: + * + * 1. NewObject attempting to compute a default prototype object when + * passed null for proto; and + * + * 2. NewObject tolerating no default prototype (null proto slot value) + * due to this js_InitClass call coming from js_InitFunctionClass on an + * otherwise-uninitialized global. + * + * 3. NewObject allocating a JSFunction-sized GC-thing when clasp is + * &js_FunctionClass, not a JSObject-sized (smaller) GC-thing. + * + * The JS_NewObjectForGivenProto and JS_NewObject APIs also allow clasp to + * be &js_FunctionClass (we could break compatibility easily). But fixing + * (3) is not enough without addressing the bootstrapping dependency on (1) + * and (2). + */ + JSObject *proto = NewObject(cx, clasp, protoProto, obj); + if (!proto) + return NULL; + + proto->syncSpecialEquality(); + + /* After this point, control must exit via label bad or out. */ + AutoObjectRooter tvr(cx, proto); + + JSObject *ctor; + bool named = false; + if (!constructor) { + /* + * Lacking a constructor, name the prototype (e.g., Math) unless this + * class (a) is anonymous, i.e. for internal use only; (b) the class + * of obj (the global object) is has a reserved slot indexed by key; + * and (c) key is not the null key. + */ + if (!(clasp->flags & JSCLASS_IS_ANONYMOUS) || !obj->isGlobal() || key == JSProto_Null) { + uint32 attrs = (clasp->flags & JSCLASS_IS_ANONYMOUS) + ? JSPROP_READONLY | JSPROP_PERMANENT + : 0; + if (!DefineStandardSlot(cx, obj, key, atom, ObjectValue(*proto), attrs, named)) + goto bad; + } + + ctor = proto; + } else { + JSFunction *fun = js_NewFunction(cx, NULL, constructor, nargs, JSFUN_CONSTRUCTOR, obj, atom); + if (!fun) + goto bad; + + AutoValueRooter tvr2(cx, ObjectValue(*fun)); + if (!DefineStandardSlot(cx, obj, key, atom, tvr2.value(), 0, named)) + goto bad; + + /* + * Remember the class this function is a constructor for so that + * we know to create an object of this class when we call the + * constructor. + */ + FUN_CLASP(fun) = clasp; + + /* + * Optionally construct the prototype object, before the class has + * been fully initialized. Allow the ctor to replace proto with a + * different object, as is done for operator new -- and as at least + * XML support requires. + */ + ctor = FUN_OBJECT(fun); + if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) { + Value rval; + if (!InvokeConstructorWithGivenThis(cx, proto, ObjectOrNullValue(ctor), + 0, NULL, &rval)) { + goto bad; + } + if (rval.isObject() && &rval.toObject() != proto) + proto = &rval.toObject(); + } + + /* Connect constructor and prototype by named properties. */ + if (!js_SetClassPrototype(cx, ctor, proto, + JSPROP_READONLY | JSPROP_PERMANENT)) { + goto bad; + } + + /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */ + if (ctor->getClass() == clasp) + ctor->setProto(proto); + } + + /* Add properties and methods to the prototype and the constructor. */ + if ((ps && !JS_DefineProperties(cx, proto, ps)) || + (fs && !JS_DefineFunctions(cx, proto, fs)) || + (static_ps && !JS_DefineProperties(cx, ctor, static_ps)) || + (static_fs && !JS_DefineFunctions(cx, ctor, static_fs))) { + goto bad; + } + + /* + * Pre-brand the prototype and constructor if they have built-in methods. + * This avoids extra shape guard branch exits in the tracejitted code. + */ + if (fs) + proto->brand(cx); + if (ctor != proto && static_fs) + ctor->brand(cx); + + /* + * Make sure proto's emptyShape is available to be shared by objects of + * this class. JSObject::emptyShape is a one-slot cache. If we omit this, + * some other class could snap it up. (The risk is particularly great for + * Object.prototype.) + * + * All callers of JSObject::initSharingEmptyShape depend on this. + * + * FIXME: bug 592296 -- js_InitArrayClass should pass &js_SlowArrayClass + * and make the Array.prototype slow from the start. + */ + JS_ASSERT_IF(proto->clasp != clasp, + clasp == &js_ArrayClass && proto->clasp == &js_SlowArrayClass); + if (!proto->getEmptyShape(cx, proto->clasp, FINALIZE_OBJECT0)) + goto bad; + + if (clasp->flags & (JSCLASS_FREEZE_PROTO|JSCLASS_FREEZE_CTOR)) { + JS_ASSERT_IF(ctor == proto, !(clasp->flags & JSCLASS_FREEZE_CTOR)); + if (proto && (clasp->flags & JSCLASS_FREEZE_PROTO) && !proto->freeze(cx)) + goto bad; + if (ctor && (clasp->flags & JSCLASS_FREEZE_CTOR) && !ctor->freeze(cx)) + goto bad; + } + + /* If this is a standard class, cache its prototype. */ + if (key != JSProto_Null && !js_SetClassObject(cx, obj, key, ctor, proto)) + goto bad; + + return proto; + +bad: + if (named) { + Value rval; + obj->deleteProperty(cx, ATOM_TO_JSID(atom), &rval, false); + } + return NULL; +} + +} + +JSObject * +js_InitClass(JSContext *cx, JSObject *obj, JSObject *protoProto, + Class *clasp, Native constructor, uintN nargs, + JSPropertySpec *ps, JSFunctionSpec *fs, + JSPropertySpec *static_ps, JSFunctionSpec *static_fs) +{ + JSAtom *atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0); + if (!atom) + return NULL; + + /* + * All instances of the class will inherit properties from the prototype + * object we are about to create (in DefineConstructorAndPrototype), which + * in turn will inherit from protoProto. + * + * When initializing a standard class (other than Object), if protoProto is + * null, default to the Object prototype object. The engine's internal uses + * of js_InitClass depend on this nicety. Note that in + * js_InitFunctionAndObjectClasses, we specially hack the resolving table + * and then depend on js_GetClassPrototype here leaving protoProto NULL and + * returning true. + */ + JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp); + if (key != JSProto_Null && + !protoProto && + !js_GetClassPrototype(cx, obj, JSProto_Object, &protoProto)) { + return NULL; + } + + return DefineConstructorAndPrototype(cx, obj, key, atom, protoProto, clasp, constructor, nargs, + ps, fs, static_ps, static_fs); +} + +bool +JSObject::allocSlots(JSContext *cx, size_t newcap) +{ + uint32 oldcap = numSlots(); + + JS_ASSERT(newcap >= oldcap && !hasSlotsArray()); + + if (newcap > NSLOTS_LIMIT) { + if (!JS_ON_TRACE(cx)) + js_ReportAllocationOverflow(cx); + return false; + } + + Value *tmpslots = (Value*) cx->malloc(newcap * sizeof(Value)); + if (!tmpslots) + return false; /* Leave slots at inline buffer. */ + slots = tmpslots; + capacity = newcap; + + /* Copy over anything from the inline buffer. */ + memcpy(slots, fixedSlots(), oldcap * sizeof(Value)); + ClearValueRange(slots + oldcap, newcap - oldcap, isDenseArray()); + return true; +} + +bool +JSObject::growSlots(JSContext *cx, size_t newcap) +{ + /* + * When an object with CAPACITY_DOUBLING_MAX or fewer slots needs to + * grow, double its capacity, to add N elements in amortized O(N) time. + * + * Above this limit, grow by 12.5% each time. Speed is still amortized + * O(N), with a higher constant factor, and we waste less space. + */ + static const size_t CAPACITY_DOUBLING_MAX = 1024 * 1024; + static const size_t CAPACITY_CHUNK = CAPACITY_DOUBLING_MAX / sizeof(Value); + + uint32 oldcap = numSlots(); + JS_ASSERT(oldcap < newcap); + + uint32 nextsize = (oldcap <= CAPACITY_DOUBLING_MAX) + ? oldcap * 2 + : oldcap + (oldcap >> 3); + + uint32 actualCapacity = JS_MAX(newcap, nextsize); + if (actualCapacity >= CAPACITY_CHUNK) + actualCapacity = JS_ROUNDUP(actualCapacity, CAPACITY_CHUNK); + else if (actualCapacity < SLOT_CAPACITY_MIN) + actualCapacity = SLOT_CAPACITY_MIN; + + /* Don't let nslots get close to wrapping around uint32. */ + if (actualCapacity >= NSLOTS_LIMIT) { + JS_ReportOutOfMemory(cx); + return false; + } + + /* If nothing was allocated yet, treat it as initial allocation. */ + if (!hasSlotsArray()) + return allocSlots(cx, actualCapacity); + + Value *tmpslots = (Value*) cx->realloc(slots, oldcap * sizeof(Value), actualCapacity * sizeof(Value)); + if (!tmpslots) + return false; /* Leave dslots as its old size. */ + slots = tmpslots; + capacity = actualCapacity; + + /* Initialize the additional slots we added. */ + ClearValueRange(slots + oldcap, actualCapacity - oldcap, isDenseArray()); + return true; +} + +void +JSObject::shrinkSlots(JSContext *cx, size_t newcap) +{ + uint32 oldcap = numSlots(); + JS_ASSERT(newcap <= oldcap); + JS_ASSERT(newcap >= slotSpan()); + + if (oldcap <= SLOT_CAPACITY_MIN || !hasSlotsArray()) { + /* We won't shrink the slots any more. Clear excess holes. */ + ClearValueRange(slots + newcap, oldcap - newcap, isDenseArray()); + return; + } + + uint32 fill = newcap; + if (newcap < SLOT_CAPACITY_MIN) + newcap = SLOT_CAPACITY_MIN; + if (newcap < numFixedSlots()) + newcap = numFixedSlots(); + + Value *tmpslots = (Value*) cx->realloc(slots, newcap * sizeof(Value)); + if (!tmpslots) + return; /* Leave slots at its old size. */ + slots = tmpslots; + capacity = newcap; + + if (fill < newcap) { + /* Clear any excess holes if we tried to shrink below SLOT_CAPACITY_MIN. */ + ClearValueRange(slots + fill, newcap - fill, isDenseArray()); + } +} + +bool +JSObject::ensureInstanceReservedSlots(JSContext *cx, size_t nreserved) +{ + JS_ASSERT_IF(isNative(), + isBlock() || isCall() || (isFunction() && isBoundFunction())); + + uintN nslots = JSSLOT_FREE(clasp) + nreserved; + return nslots <= numSlots() || allocSlots(cx, nslots); +} + +static JSObject * +js_InitNullClass(JSContext *cx, JSObject *obj) +{ + JS_ASSERT(0); + return NULL; +} + +#define JS_PROTO(name,code,init) extern JSObject *init(JSContext *, JSObject *); +#include "jsproto.tbl" +#undef JS_PROTO + +static JSObjectOp lazy_prototype_init[JSProto_LIMIT] = { +#define JS_PROTO(name,code,init) init, +#include "jsproto.tbl" +#undef JS_PROTO +}; + +namespace js { + +bool +SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles) +{ + JS_ASSERT_IF(!checkForCycles, obj != proto); + JS_ASSERT(obj->isExtensible()); + + if (obj->isNative()) { + if (!obj->ensureClassReservedSlots(cx)) + return false; + } + + /* + * Regenerate property cache shape ids for all of the scopes along the + * old prototype chain to invalidate their property cache entries, in + * case any entries were filled by looking up through obj. + */ + JSObject *oldproto = obj; + while (oldproto && oldproto->isNative()) { + oldproto->protoShapeChange(cx); + oldproto = oldproto->getProto(); + } + + if (!proto || !checkForCycles) { + obj->setProto(proto); + } else if (!SetProtoCheckingForCycles(cx, obj, proto)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CYCLIC_VALUE, js_proto_str); + return false; + } + return true; +} + +} + +JSBool +js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, + JSObject **objp) +{ + JSObject *cobj; + JSResolvingKey rkey; + JSResolvingEntry *rentry; + uint32 generation; + JSObjectOp init; + Value v; + + obj = obj->getGlobal(); + if (!obj->isGlobal()) { + *objp = NULL; + return JS_TRUE; + } + + v = obj->getReservedSlot(key); + if (v.isObject()) { + *objp = &v.toObject(); + return JS_TRUE; + } + + rkey.obj = obj; + rkey.id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[key]); + if (!js_StartResolving(cx, &rkey, JSRESFLAG_LOOKUP, &rentry)) + return JS_FALSE; + if (!rentry) { + /* Already caching key in obj -- suppress recursion. */ + *objp = NULL; + return JS_TRUE; + } + generation = cx->resolvingTable->generation; + + JSBool ok = true; + cobj = NULL; + init = lazy_prototype_init[key]; + if (init) { + if (!init(cx, obj)) { + ok = JS_FALSE; + } else { + v = obj->getReservedSlot(key); + if (v.isObject()) + cobj = &v.toObject(); + } + } + + js_StopResolving(cx, &rkey, JSRESFLAG_LOOKUP, rentry, generation); + *objp = cobj; + return ok; +} + +JSBool +js_SetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject *cobj, JSObject *proto) +{ + JS_ASSERT(!obj->getParent()); + if (!obj->isGlobal()) + return JS_TRUE; + + return js_SetReservedSlot(cx, obj, key, ObjectOrNullValue(cobj)) && + js_SetReservedSlot(cx, obj, JSProto_LIMIT + key, ObjectOrNullValue(proto)); +} + +JSBool +js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey, + Value *vp, Class *clasp) +{ + JSStackFrame *fp; + JSObject *obj, *cobj, *pobj; + jsid id; + JSProperty *prop; + const Shape *shape; + + /* + * Find the global object. Use cx->fp() directly to avoid falling off + * trace; all JIT-elided stack frames have the same global object as + * cx->fp(). + */ + VOUCH_DOES_NOT_REQUIRE_STACK(); + if (!start && (fp = cx->maybefp()) != NULL) + start = &fp->scopeChain(); + + if (start) { + /* Find the topmost object in the scope chain. */ + do { + obj = start; + start = obj->getParent(); + } while (start); + } else { + obj = cx->globalObject; + if (!obj) { + vp->setUndefined(); + return JS_TRUE; + } + } + + OBJ_TO_INNER_OBJECT(cx, obj); + if (!obj) + return JS_FALSE; + + if (protoKey != JSProto_Null) { + JS_ASSERT(JSProto_Null < protoKey); + JS_ASSERT(protoKey < JSProto_LIMIT); + if (!js_GetClassObject(cx, obj, protoKey, &cobj)) + return JS_FALSE; + if (cobj) { + vp->setObject(*cobj); + return JS_TRUE; + } + id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[protoKey]); + } else { + JSAtom *atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0); + if (!atom) + return false; + id = ATOM_TO_JSID(atom); + } + + JS_ASSERT(obj->isNative()); + if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_CLASSNAME, + &pobj, &prop) < 0) { + return JS_FALSE; + } + Value v = UndefinedValue(); + if (prop && pobj->isNative()) { + shape = (Shape *) prop; + if (pobj->containsSlot(shape->slot)) { + v = pobj->nativeGetSlot(shape->slot); + if (v.isPrimitive()) + v.setUndefined(); + } + } + *vp = v; + return JS_TRUE; +} + +JSObject * +js_ConstructObject(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent, + uintN argc, Value *argv) +{ + AutoArrayRooter argtvr(cx, argc, argv); + + JSProtoKey protoKey = GetClassProtoKey(clasp); + + /* Protect constructor in case a crazy getter for .prototype uproots it. */ + AutoValueRooter tvr(cx); + if (!js_FindClassObject(cx, parent, protoKey, tvr.addr(), clasp)) + return NULL; + + const Value &cval = tvr.value(); + if (tvr.value().isPrimitive()) { + js_ReportIsNotFunction(cx, tvr.addr(), JSV2F_CONSTRUCT | JSV2F_SEARCH_STACK); + return NULL; + } + + /* + * If proto is NULL, set it to Constructor.prototype, just like JSOP_NEW + * does, likewise for the new object's parent. + */ + JSObject *ctor = &cval.toObject(); + if (!parent) + parent = ctor->getParent(); + if (!proto) { + Value rval; + if (!ctor->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), + &rval)) { + return NULL; + } + if (rval.isObjectOrNull()) + proto = rval.toObjectOrNull(); + } + + JSObject *obj = NewObject(cx, clasp, proto, parent); + if (!obj) + return NULL; + + obj->syncSpecialEquality(); + + Value rval; + if (!InvokeConstructorWithGivenThis(cx, obj, cval, argc, argv, &rval)) + return NULL; + + if (rval.isPrimitive()) + return obj; + + /* + * If the instance's class differs from what was requested, throw a type + * error. If the given class has both the JSCLASS_HAS_PRIVATE and the + * JSCLASS_CONSTRUCT_PROTOTYPE flags, and the instance does not have its + * private data set at this point, then the constructor was replaced and + * we should throw a type error. + */ + obj = &rval.toObject(); + if (obj->getClass() != clasp || + (!(~clasp->flags & (JSCLASS_HAS_PRIVATE | + JSCLASS_CONSTRUCT_PROTOTYPE)) && + !obj->getPrivate())) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_WRONG_CONSTRUCTOR, clasp->name); + return NULL; + } + return obj; +} + +bool +JSObject::allocSlot(JSContext *cx, uint32 *slotp) +{ + uint32 slot = slotSpan(); + JS_ASSERT(slot >= JSSLOT_FREE(clasp)); + + /* + * If this object is in dictionary mode and it has a property table, try to + * pull a free slot from the property table's slot-number freelist. + */ + if (inDictionaryMode() && lastProp->hasTable()) { + uint32 &last = lastProp->getTable()->freelist; + if (last != SHAPE_INVALID_SLOT) { +#ifdef DEBUG + JS_ASSERT(last < slot); + uint32 next = getSlot(last).toPrivateUint32(); + JS_ASSERT_IF(next != SHAPE_INVALID_SLOT, next < slot); +#endif + + *slotp = last; + + Value &vref = getSlotRef(last); + last = vref.toPrivateUint32(); + vref.setUndefined(); + return true; + } + } + + if (slot >= numSlots() && !growSlots(cx, slot + 1)) + return false; + + /* JSObject::growSlots or JSObject::freeSlot should set the free slots to void. */ + JS_ASSERT(getSlot(slot).isUndefined()); + *slotp = slot; + return true; +} + +bool +JSObject::freeSlot(JSContext *cx, uint32 slot) +{ + uint32 limit = slotSpan(); + JS_ASSERT(slot < limit); + + Value &vref = getSlotRef(slot); + if (inDictionaryMode() && lastProp->hasTable()) { + uint32 &last = lastProp->getTable()->freelist; + + /* Can't afford to check the whole freelist, but let's check the head. */ + JS_ASSERT_IF(last != SHAPE_INVALID_SLOT, last < limit && last != slot); + + /* + * Freeing a slot other than the last one mapped by this object's + * shape (and not a reserved slot; see bug 595230): push the slot onto + * the dictionary property table's freelist. We want to let the last + * slot be freed by shrinking the dslots vector; see js_TraceObject. + */ + if (JSSLOT_FREE(clasp) <= slot && slot + 1 < limit) { + JS_ASSERT_IF(last != SHAPE_INVALID_SLOT, last < slotSpan()); + vref.setPrivateUint32(last); + last = slot; + return true; + } + } + vref.setUndefined(); + return false; +} + +/* JSBOXEDWORD_INT_MAX as a string */ +#define JSBOXEDWORD_INT_MAX_STRING "1073741823" + +/* + * Convert string indexes that convert to int jsvals as ints to save memory. + * Care must be taken to use this macro every time a property name is used, or + * else double-sets, incorrect property cache misses, or other mistakes could + * occur. + */ +jsid +js_CheckForStringIndex(jsid id) +{ + if (!JSID_IS_ATOM(id)) + return id; + + JSAtom *atom = JSID_TO_ATOM(id); + JSString *str = ATOM_TO_STRING(atom); + const jschar *s = str->flatChars(); + jschar ch = *s; + + JSBool negative = (ch == '-'); + if (negative) + ch = *++s; + + if (!JS7_ISDEC(ch)) + return id; + + size_t n = str->flatLength() - negative; + if (n > sizeof(JSBOXEDWORD_INT_MAX_STRING) - 1) + return id; + + const jschar *cp = s; + const jschar *end = s + n; + + jsuint index = JS7_UNDEC(*cp++); + jsuint oldIndex = 0; + jsuint c = 0; + + if (index != 0) { + while (JS7_ISDEC(*cp)) { + oldIndex = index; + c = JS7_UNDEC(*cp); + index = 10 * index + c; + cp++; + } + } + + /* + * Non-integer indexes can't be represented as integers. Also, distinguish + * index "-0" from "0", because JSBOXEDWORD_INT cannot. + */ + if (cp != end || (negative && index == 0)) + return id; + + if (negative) { + if (oldIndex < -(JSID_INT_MIN / 10) || + (oldIndex == -(JSID_INT_MIN / 10) && c <= (-JSID_INT_MIN % 10))) + { + id = INT_TO_JSID(-jsint(index)); + } + } else { + if (oldIndex < JSID_INT_MAX / 10 || + (oldIndex == JSID_INT_MAX / 10 && c <= (JSID_INT_MAX % 10))) + { + id = INT_TO_JSID(jsint(index)); + } + } + + return id; +} + +static JSBool +PurgeProtoChain(JSContext *cx, JSObject *obj, jsid id) +{ + const Shape *shape; + + while (obj) { + if (!obj->isNative()) { + obj = obj->getProto(); + continue; + } + shape = obj->nativeLookup(id); + if (shape) { + PCMETER(JS_PROPERTY_CACHE(cx).pcpurges++); + obj->shadowingShapeChange(cx, *shape); + + if (!obj->getParent()) { + /* + * All scope chains end in a global object, so this will change + * the global shape. jstracer.cpp assumes that the global shape + * never changes on trace, so we must deep-bail here. + */ + LeaveTrace(cx); + } + return JS_TRUE; + } + obj = obj->getProto(); + } + return JS_FALSE; +} + +void +js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id) +{ + JS_ASSERT(obj->isDelegate()); + PurgeProtoChain(cx, obj->getProto(), id); + + /* + * We must purge the scope chain only for Call objects as they are the only + * kind of cacheable non-global object that can gain properties after outer + * properties with the same names have been cached or traced. Call objects + * may gain such properties via eval introducing new vars; see bug 490364. + */ + if (obj->isCall()) { + while ((obj = obj->getParent()) != NULL) { + if (PurgeProtoChain(cx, obj, id)) + break; + } + } +} + +const Shape * +js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id, + PropertyOp getter, StrictPropertyOp setter, uint32 slot, + uintN attrs, uintN flags, intN shortid) +{ + JS_ASSERT(!(flags & Shape::METHOD)); + + /* + * Purge the property cache of now-shadowed id in obj's scope chain. Do + * this optimistically (assuming no failure below) before locking obj, so + * we can lock the shadowed scope. + */ + js_PurgeScopeChain(cx, obj, id); + + if (!obj->ensureClassReservedSlots(cx)) + return NULL; + + /* Convert string indices to integers if appropriate. */ + id = js_CheckForStringIndex(id); + return obj->putProperty(cx, id, getter, setter, slot, attrs, flags, shortid); +} + +const Shape * +js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj, + const Shape *shape, uintN attrs, uintN mask, + PropertyOp getter, StrictPropertyOp setter) +{ + if (!obj->ensureClassReservedSlots(cx)) + return NULL; + + /* + * Check for freezing an object with shape-memoized methods here, on a + * shape-by-shape basis. Note that getter may be a pun of the method's + * joined function object value, to indicate "no getter change". In this + * case we must null getter to get the desired PropertyStub behavior. + */ + if ((attrs & JSPROP_READONLY) && shape->isMethod()) { + JSObject *funobj = &shape->methodObject(); + Value v = ObjectValue(*funobj); + + shape = obj->methodReadBarrier(cx, *shape, &v); + if (!shape) + return NULL; + + if (CastAsObject(getter) == funobj) { + JS_ASSERT(!(attrs & JSPROP_GETTER)); + getter = NULL; + } + } + + return obj->changeProperty(cx, shape, attrs, mask, getter, setter); +} + +JSBool +js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value, + PropertyOp getter, StrictPropertyOp setter, uintN attrs) +{ + return js_DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs, + 0, 0, NULL); +} + +/* + * Backward compatibility requires allowing addProperty hooks to mutate the + * nominal initial value of a slotful property, while GC safety wants that + * value to be stored before the call-out through the hook. Optimize to do + * both while saving cycles for classes that stub their addProperty hook. + */ +static inline bool +CallAddPropertyHook(JSContext *cx, Class *clasp, JSObject *obj, const Shape *shape, Value *vp) +{ + if (clasp->addProperty != PropertyStub) { + Value nominal = *vp; + + if (!CallJSPropertyOp(cx, clasp->addProperty, obj, shape->id, vp)) + return false; + if (*vp != nominal) { + if (obj->containsSlot(shape->slot)) + obj->nativeSetSlot(shape->slot, *vp); + } + } + return true; +} + +JSBool +js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value, + PropertyOp getter, StrictPropertyOp setter, uintN attrs, + uintN flags, intN shortid, JSProperty **propp, + uintN defineHow /* = 0 */) +{ + JS_ASSERT((defineHow & ~(JSDNP_CACHE_RESULT | JSDNP_DONT_PURGE | JSDNP_SET_METHOD)) == 0); + LeaveTraceIfGlobalObject(cx, obj); + + /* Convert string indices to integers if appropriate. */ + id = js_CheckForStringIndex(id); + + /* + * If defining a getter or setter, we must check for its counterpart and + * update the attributes and property ops. A getter or setter is really + * only half of a property. + */ + const Shape *shape = NULL; + if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) { + JSObject *pobj; + JSProperty *prop; + + /* + * If JS_THREADSAFE and id is found, js_LookupProperty returns with + * shape non-null and pobj locked. If pobj == obj, the property is + * already in obj and obj has its own (mutable) scope. So if we are + * defining a getter whose setter was already defined, or vice versa, + * finish the job via obj->changeProperty, and refresh the property + * cache line for (obj, id) to map shape. + */ + if (!js_LookupProperty(cx, obj, id, &pobj, &prop)) + return JS_FALSE; + shape = (Shape *) prop; + if (shape && pobj == obj && shape->isAccessorDescriptor()) { + shape = obj->changeProperty(cx, shape, attrs, + JSPROP_GETTER | JSPROP_SETTER, + (attrs & JSPROP_GETTER) + ? getter + : shape->getter(), + (attrs & JSPROP_SETTER) + ? setter + : shape->setter()); + + if (!shape) + return false; + } else if (prop) { + prop = NULL; + shape = NULL; + } + } + + /* + * Purge the property cache of any properties named by id that are about + * to be shadowed in obj's scope chain unless it is known a priori that it + * is not possible. We do this before locking obj to avoid nesting locks. + */ + if (!(defineHow & JSDNP_DONT_PURGE)) + js_PurgeScopeChain(cx, obj, id); + + /* + * Check whether a readonly property or setter is being defined on a known + * prototype object. See the comment in jscntxt.h before protoHazardShape's + * member declaration. + */ + if (obj->isDelegate() && (attrs & (JSPROP_READONLY | JSPROP_SETTER))) + cx->runtime->protoHazardShape = js_GenerateShape(cx); + + /* Use the object's class getter and setter by default. */ + Class *clasp = obj->getClass(); + if (!(defineHow & JSDNP_SET_METHOD)) { + if (!getter && !(attrs & JSPROP_GETTER)) + getter = clasp->getProperty; + if (!setter && !(attrs & JSPROP_SETTER)) + setter = clasp->setProperty; + } + + /* Get obj's own scope if it has one, or create a new one for obj. */ + if (!obj->ensureClassReservedSlots(cx)) + return false; + + /* + * Make a local copy of value, in case a method barrier needs to update the + * value to define, and just so addProperty can mutate its inout parameter. + */ + Value valueCopy = value; + bool adding = false; + + if (!shape) { + /* Add a new property, or replace an existing one of the same id. */ + if (defineHow & JSDNP_SET_METHOD) { + JS_ASSERT(clasp == &js_ObjectClass); + JS_ASSERT(IsFunctionObject(value)); + JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); + JS_ASSERT(!getter && !setter); + + JSObject *funobj = &value.toObject(); + if (FUN_OBJECT(GET_FUNCTION_PRIVATE(cx, funobj)) == funobj) { + flags |= Shape::METHOD; + getter = CastAsPropertyOp(funobj); + } + } + + if (const Shape *existingShape = obj->nativeLookup(id)) { + if (existingShape->hasSlot()) + AbortRecordingIfUnexpectedGlobalWrite(cx, obj, existingShape->slot); + + if (existingShape->isMethod() && + ObjectValue(existingShape->methodObject()) == valueCopy) + { + /* + * Redefining an existing shape-memoized method object without + * changing the property's value, perhaps to change attributes. + * Clone now via the method read barrier. + * + * But first, assert that our caller is not trying to preserve + * the joined function object value as the getter object for + * the redefined property. The joined function object cannot + * yet have leaked, so only an internal code path could attempt + * such a thing. Any such path would be a bug to fix. + */ + JS_ASSERT(existingShape->getter() != getter); + + if (!obj->methodReadBarrier(cx, *existingShape, &valueCopy)) + return false; + } + } else { + adding = true; + } + + uint32 oldShape = obj->shape(); + shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT, + attrs, flags, shortid); + if (!shape) + return false; + + /* + * If shape is a joined method, the above call to putProperty suffices + * to update the object's shape id if need be (because the shape's hash + * identity includes the method value). + * + * But if scope->branded(), the object's shape id may not have changed + * and we may be overwriting a cached function-valued property (note + * how methodWriteBarrier checks previous vs. would-be current value). + * See bug 560998. + */ + if (obj->shape() == oldShape && obj->branded() && shape->slot != SHAPE_INVALID_SLOT) { +#ifdef DEBUG + const Shape *newshape = +#endif + obj->methodWriteBarrier(cx, *shape, valueCopy); + JS_ASSERT(newshape == shape); + } + } + + /* Store valueCopy before calling addProperty, in case the latter GC's. */ + if (obj->containsSlot(shape->slot)) + obj->nativeSetSlot(shape->slot, valueCopy); + + /* XXXbe called with lock held */ + if (!CallAddPropertyHook(cx, clasp, obj, shape, &valueCopy)) { + obj->removeProperty(cx, id); + return false; + } + + if (defineHow & JSDNP_CACHE_RESULT) { + JS_ASSERT_NOT_ON_TRACE(cx); + if (adding) { + JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, 0, obj, shape, true); + TRACE_1(AddProperty, obj); + } + } + if (propp) + *propp = (JSProperty *) shape; + return true; + +#ifdef JS_TRACER + error: // TRACE_1 jumps here on error. +#endif + return false; +} + +#define SCOPE_DEPTH_ACCUM(bs,val) \ + JS_SCOPE_DEPTH_METERING(JS_BASIC_STATS_ACCUM(bs, val)) + +/* + * Call obj's resolve hook. obj is a native object and the caller holds its + * scope lock. + * + * cx, start, id, and flags are the parameters initially passed to the ongoing + * lookup; objp and propp are its out parameters. obj is an object along + * start's prototype chain. + * + * There are four possible outcomes: + * + * - On failure, report an error or exception, unlock obj, and return false. + * + * - If we are alrady resolving a property of *curobjp, set *recursedp = true, + * unlock obj, and return true. + * + * - If the resolve hook finds or defines the sought property, set *objp and + * *propp appropriately, set *recursedp = false, and return true with *objp's + * lock held. + * + * - Otherwise no property was resolved. Set *propp = NULL and *recursedp = false + * and return true. + */ +static JSBool +CallResolveOp(JSContext *cx, JSObject *start, JSObject *obj, jsid id, uintN flags, + JSObject **objp, JSProperty **propp, bool *recursedp) +{ + Class *clasp = obj->getClass(); + JSResolveOp resolve = clasp->resolve; + + /* + * Avoid recursion on (obj, id) already being resolved on cx. + * + * Once we have successfully added an entry for (obj, key) to + * cx->resolvingTable, control must go through cleanup: before + * returning. But note that JS_DHASH_ADD may find an existing + * entry, in which case we bail to suppress runaway recursion. + */ + JSResolvingKey key = {obj, id}; + JSResolvingEntry *entry; + if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) + return false; + if (!entry) { + /* Already resolving id in obj -- suppress recursion. */ + *recursedp = true; + return true; + } + uint32 generation = cx->resolvingTable->generation; + *recursedp = false; + + *propp = NULL; + + JSBool ok; + const Shape *shape = NULL; + if (clasp->flags & JSCLASS_NEW_RESOLVE) { + JSNewResolveOp newresolve = (JSNewResolveOp)resolve; + if (flags == JSRESOLVE_INFER) + flags = js_InferFlags(cx, 0); + JSObject *obj2 = (clasp->flags & JSCLASS_NEW_RESOLVE_GETS_START) ? start : NULL; + + { + /* Protect id and all atoms from a GC nested in resolve. */ + AutoKeepAtoms keep(cx->runtime); + ok = newresolve(cx, obj, id, flags, &obj2); + } + if (!ok) + goto cleanup; + + if (obj2) { + /* Resolved: lookup id again for backward compatibility. */ + if (!obj2->isNative()) { + /* Whoops, newresolve handed back a foreign obj2. */ + JS_ASSERT(obj2 != obj); + ok = obj2->lookupProperty(cx, id, objp, propp); + if (!ok || *propp) + goto cleanup; + } else { + /* + * Require that obj2 not be empty now, as we do for old-style + * resolve. If it doesn't, then id was not truly resolved, and + * we'll find it in the proto chain, or miss it if obj2's proto + * is not on obj's proto chain. That last case is a "too bad!" + * case. + */ + if (!obj2->nativeEmpty()) + shape = obj2->nativeLookup(id); + } + if (shape) { + JS_ASSERT(!obj2->nativeEmpty()); + obj = obj2; + } + } + } else { + /* + * Old resolve always requires id re-lookup if obj is not empty after + * resolve returns. + */ + ok = resolve(cx, obj, id); + if (!ok) + goto cleanup; + JS_ASSERT(obj->isNative()); + if (!obj->nativeEmpty()) + shape = obj->nativeLookup(id); + } + +cleanup: + if (ok && shape) { + *objp = obj; + *propp = (JSProperty *) shape; + } + js_StopResolving(cx, &key, JSRESFLAG_LOOKUP, entry, generation); + return ok; +} + +static JS_ALWAYS_INLINE int +js_LookupPropertyWithFlagsInline(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSObject **objp, JSProperty **propp) +{ + /* We should not get string indices which aren't already integers here. */ + JS_ASSERT(id == js_CheckForStringIndex(id)); + + /* Search scopes starting with obj and following the prototype link. */ + JSObject *start = obj; + int protoIndex; + for (protoIndex = 0; ; protoIndex++) { + const Shape *shape = obj->nativeLookup(id); + if (shape) { + SCOPE_DEPTH_ACCUM(&cx->runtime->protoLookupDepthStats, protoIndex); + *objp = obj; + *propp = (JSProperty *) shape; + return protoIndex; + } + + /* Try obj's class resolve hook if id was not found in obj's scope. */ + if (!shape && obj->getClass()->resolve != JS_ResolveStub) { + bool recursed; + if (!CallResolveOp(cx, start, obj, id, flags, objp, propp, &recursed)) + return -1; + if (recursed) + break; + if (*propp) { + /* Recalculate protoIndex in case it was resolved on some other object. */ + protoIndex = 0; + for (JSObject *proto = start; proto && proto != *objp; proto = proto->getProto()) + protoIndex++; + SCOPE_DEPTH_ACCUM(&cx->runtime->protoLookupDepthStats, protoIndex); + return protoIndex; + } + } + + JSObject *proto = obj->getProto(); + if (!proto) + break; + if (!proto->isNative()) { + if (!proto->lookupProperty(cx, id, objp, propp)) + return -1; +#ifdef DEBUG + /* + * Non-native objects must have either non-native lookup results, + * or else native results from the non-native's prototype chain. + * + * See JSStackFrame::getValidCalleeObject, where we depend on this + * fact to force a prototype-delegated joined method accessed via + * arguments.callee through the delegating |this| object's method + * read barrier. + */ + if (*propp && (*objp)->isNative()) { + while ((proto = proto->getProto()) != *objp) + JS_ASSERT(proto); + } +#endif + return protoIndex + 1; + } + + obj = proto; + } + + *objp = NULL; + *propp = NULL; + return protoIndex; +} + +JS_FRIEND_API(JSBool) +js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + JSProperty **propp) +{ + /* Convert string indices to integers if appropriate. */ + id = js_CheckForStringIndex(id); + + return js_LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, objp, propp) >= 0; +} + +int +js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSObject **objp, JSProperty **propp) +{ + /* Convert string indices to integers if appropriate. */ + id = js_CheckForStringIndex(id); + + return js_LookupPropertyWithFlagsInline(cx, obj, id, flags, objp, propp); +} + +PropertyCacheEntry * +js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult, + JSObject **objp, JSObject **pobjp, JSProperty **propp) +{ + JSObject *scopeChain, *obj, *parent, *pobj; + PropertyCacheEntry *entry; + int scopeIndex, protoIndex; + JSProperty *prop; + + JS_ASSERT_IF(cacheResult, !JS_ON_TRACE(cx)); + scopeChain = &js_GetTopStackFrame(cx)->scopeChain(); + + /* Scan entries on the scope chain that we can cache across. */ + entry = JS_NO_PROP_CACHE_FILL; + obj = scopeChain; + parent = obj->getParent(); + for (scopeIndex = 0; + parent + ? IsCacheableNonGlobalScope(obj) + : !obj->getOps()->lookupProperty; + ++scopeIndex) { + protoIndex = + js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, + &pobj, &prop); + if (protoIndex < 0) + return NULL; + + if (prop) { +#ifdef DEBUG + if (parent) { + Class *clasp = obj->getClass(); + JS_ASSERT(pobj->isNative()); + JS_ASSERT(pobj->getClass() == clasp); + if (clasp == &js_BlockClass) { + /* + * A block instance on the scope chain is immutable and it + * shares its shapes with its compile-time prototype. + */ + JS_ASSERT(pobj == obj); + JS_ASSERT(pobj->isClonedBlock()); + JS_ASSERT(protoIndex == 0); + } else { + /* Call and DeclEnvClass objects have no prototypes. */ + JS_ASSERT(!obj->getProto()); + JS_ASSERT(protoIndex == 0); + } + } else { + JS_ASSERT(obj->isNative()); + } +#endif + /* + * We must check if pobj is native as a global object can have + * non-native prototype. + */ + if (cacheResult && pobj->isNative()) { + entry = JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, + protoIndex, pobj, + (Shape *) prop); + } + SCOPE_DEPTH_ACCUM(&cx->runtime->scopeSearchDepthStats, scopeIndex); + goto out; + } + + if (!parent) { + pobj = NULL; + goto out; + } + obj = parent; + parent = obj->getParent(); + } + + for (;;) { + if (!obj->lookupProperty(cx, id, &pobj, &prop)) + return NULL; + if (prop) { + PCMETER(JS_PROPERTY_CACHE(cx).nofills++); + goto out; + } + + /* + * We conservatively assume that a resolve hook could mutate the scope + * chain during JSObject::lookupProperty. So we read parent here again. + */ + parent = obj->getParent(); + if (!parent) { + pobj = NULL; + break; + } + obj = parent; + } + + out: + JS_ASSERT(!!pobj == !!prop); + *objp = obj; + *pobjp = pobj; + *propp = prop; + return entry; +} + +/* + * On return, if |*pobjp| is a native object, then |*propp| is a |Shape *|. + * Otherwise, its type and meaning depends on the host object's implementation. + */ +JS_FRIEND_API(JSBool) +js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp, + JSProperty **propp) +{ + return !!js_FindPropertyHelper(cx, id, false, objp, pobjp, propp); +} + +JSObject * +js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id) +{ + /* + * This function should not be called for a global object or from the + * trace and should have a valid cache entry for native scopeChain. + */ + JS_ASSERT(scopeChain->getParent()); + JS_ASSERT(!JS_ON_TRACE(cx)); + + JSObject *obj = scopeChain; + + /* + * Loop over cacheable objects on the scope chain until we find a + * property. We also stop when we reach the global object skipping any + * farther checks or lookups. For details see the JSOP_BINDNAME case of + * js_Interpret. + * + * The test order here matters because IsCacheableNonGlobalScope + * must not be passed a global object (i.e. one with null parent). + */ + for (int scopeIndex = 0; + !obj->getParent() || IsCacheableNonGlobalScope(obj); + scopeIndex++) { + JSObject *pobj; + JSProperty *prop; + int protoIndex = js_LookupPropertyWithFlags(cx, obj, id, + cx->resolveFlags, + &pobj, &prop); + if (protoIndex < 0) + return NULL; + if (prop) { + if (!pobj->isNative()) { + JS_ASSERT(!obj->getParent()); + return obj; + } + JS_ASSERT_IF(obj->getParent(), pobj->getClass() == obj->getClass()); +#ifdef DEBUG + PropertyCacheEntry *entry = +#endif + JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, protoIndex, pobj, + (Shape *) prop); + JS_ASSERT(entry); + return obj; + } + + JSObject *parent = obj->getParent(); + if (!parent) + return obj; + obj = parent; + } + + /* Loop until we find a property or reach the global object. */ + do { + JSObject *pobj; + JSProperty *prop; + if (!obj->lookupProperty(cx, id, &pobj, &prop)) + return NULL; + if (prop) + break; + + /* + * We conservatively assume that a resolve hook could mutate the scope + * chain during JSObject::lookupProperty. So we must check if parent is + * not null here even if it wasn't before the lookup. + */ + JSObject *parent = obj->getParent(); + if (!parent) + break; + obj = parent; + } while (obj->getParent()); + return obj; +} + +static JS_ALWAYS_INLINE JSBool +js_NativeGetInline(JSContext *cx, JSObject *receiver, JSObject *obj, JSObject *pobj, + const Shape *shape, uintN getHow, Value *vp) +{ + LeaveTraceIfGlobalObject(cx, pobj); + + uint32 slot; + int32 sample; + + JS_ASSERT(pobj->isNative()); + + slot = shape->slot; + if (slot != SHAPE_INVALID_SLOT) { + *vp = pobj->nativeGetSlot(slot); + JS_ASSERT(!vp->isMagic()); + } else { + vp->setUndefined(); + } + if (shape->hasDefaultGetter()) + return true; + + if (JS_UNLIKELY(shape->isMethod()) && (getHow & JSGET_NO_METHOD_BARRIER)) { + JS_ASSERT(&shape->methodObject() == &vp->toObject()); + return true; + } + + sample = cx->runtime->propertyRemovals; + { + AutoShapeRooter tvr(cx, shape); + AutoObjectRooter tvr2(cx, pobj); + if (!shape->get(cx, receiver, obj, pobj, vp)) + return false; + } + + if (pobj->containsSlot(slot) && + (JS_LIKELY(cx->runtime->propertyRemovals == sample) || + pobj->nativeContains(*shape))) { + if (!pobj->methodWriteBarrier(cx, *shape, *vp)) + return false; + pobj->nativeSetSlot(slot, *vp); + } + + return true; +} + +JSBool +js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *shape, uintN getHow, + Value *vp) +{ + return js_NativeGetInline(cx, obj, obj, pobj, shape, getHow, vp); +} + +JSBool +js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, bool strict, Value *vp) +{ + LeaveTraceIfGlobalObject(cx, obj); + + uint32 slot; + int32 sample; + + JS_ASSERT(obj->isNative()); + + slot = shape->slot; + if (slot != SHAPE_INVALID_SLOT) { + JS_ASSERT(obj->containsSlot(slot)); + + /* If shape has a stub setter, keep obj locked and just store *vp. */ + if (shape->hasDefaultSetter()) { + if (!added) { + AbortRecordingIfUnexpectedGlobalWrite(cx, obj, slot); + + /* FIXME: This should pass *shape, not slot, but see bug 630354. */ + if (!obj->methodWriteBarrier(cx, slot, *vp)) + return false; + } + obj->nativeSetSlot(slot, *vp); + return true; + } + } else { + /* + * Allow API consumers to create shared properties with stub setters. + * Such properties effectively function as data descriptors which are + * not writable, so attempting to set such a property should do nothing + * or throw if we're in strict mode. + */ + if (!shape->hasGetterValue() && shape->hasDefaultSetter()) + return js_ReportGetterOnlyAssignment(cx); + } + + sample = cx->runtime->propertyRemovals; + { + AutoShapeRooter tvr(cx, shape); + if (!shape->set(cx, obj, strict, vp)) + return false; + + JS_ASSERT_IF(!obj->inDictionaryMode(), shape->slot == slot); + slot = shape->slot; + } + + if (obj->containsSlot(slot) && + (JS_LIKELY(cx->runtime->propertyRemovals == sample) || + obj->nativeContains(*shape))) { + if (!added) { + AbortRecordingIfUnexpectedGlobalWrite(cx, obj, slot); + if (!obj->methodWriteBarrier(cx, *shape, *vp)) + return false; + } + obj->setSlot(slot, *vp); + } + + return true; +} + +static JS_ALWAYS_INLINE bool +js_GetPropertyHelperWithShapeInline(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, + uintN getHow, Value *vp, + const Shape **shapeOut, JSObject **holderOut) +{ + JSObject *aobj, *obj2; + int protoIndex; + JSProperty *prop; + const Shape *shape; + + JS_ASSERT_IF(getHow & JSGET_CACHE_RESULT, !JS_ON_TRACE(cx)); + + *shapeOut = NULL; + + /* Convert string indices to integers if appropriate. */ + id = js_CheckForStringIndex(id); + + aobj = js_GetProtoIfDenseArray(obj); + /* This call site is hot -- use the always-inlined variant of js_LookupPropertyWithFlags(). */ + protoIndex = js_LookupPropertyWithFlagsInline(cx, aobj, id, cx->resolveFlags, + &obj2, &prop); + if (protoIndex < 0) + return JS_FALSE; + + *holderOut = obj2; + + if (!prop) { + vp->setUndefined(); + + if (!CallJSPropertyOp(cx, obj->getClass()->getProperty, obj, id, vp)) + return JS_FALSE; + + PCMETER(getHow & JSGET_CACHE_RESULT && JS_PROPERTY_CACHE(cx).nofills++); + + /* + * Give a strict warning if foo.bar is evaluated by a script for an + * object foo with no property named 'bar'. + */ + jsbytecode *pc; + if (vp->isUndefined() && ((pc = js_GetCurrentBytecodePC(cx)) != NULL)) { + JSOp op; + uintN flags; + + op = (JSOp) *pc; + if (op == JSOP_TRAP) { + JS_ASSERT_NOT_ON_TRACE(cx); + op = JS_GetTrapOpcode(cx, cx->fp()->script(), pc); + } + if (op == JSOP_GETXPROP) { + flags = JSREPORT_ERROR; + } else { + if (!cx->hasStrictOption() || + (op != JSOP_GETPROP && op != JSOP_GETELEM) || + js_CurrentPCIsInImacro(cx)) { + return JS_TRUE; + } + + /* + * XXX do not warn about missing __iterator__ as the function + * may be called from JS_GetMethodById. See bug 355145. + */ + if (JSID_IS_ATOM(id, cx->runtime->atomState.iteratorAtom)) + return JS_TRUE; + + /* Do not warn about tests like (obj[prop] == undefined). */ + if (cx->resolveFlags == JSRESOLVE_INFER) { + LeaveTrace(cx); + pc += js_CodeSpec[op].length; + if (Detecting(cx, pc)) + return JS_TRUE; + } else if (cx->resolveFlags & JSRESOLVE_DETECTING) { + return JS_TRUE; + } + + flags = JSREPORT_WARNING | JSREPORT_STRICT; + } + + /* Ok, bad undefined property reference: whine about it. */ + if (!js_ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP, + JSDVG_IGNORE_STACK, IdToValue(id), + NULL, NULL, NULL)) { + return JS_FALSE; + } + } + return JS_TRUE; + } + + if (!obj2->isNative()) { + return obj2->isProxy() + ? JSProxy::get(cx, obj2, receiver, id, vp) + : obj2->getProperty(cx, id, vp); + } + + shape = (Shape *) prop; + *shapeOut = shape; + + if (getHow & JSGET_CACHE_RESULT) { + JS_ASSERT_NOT_ON_TRACE(cx); + JS_PROPERTY_CACHE(cx).fill(cx, aobj, 0, protoIndex, obj2, shape); + } + + /* This call site is hot -- use the always-inlined variant of js_NativeGet(). */ + if (!js_NativeGetInline(cx, receiver, obj, obj2, shape, getHow, vp)) + return JS_FALSE; + + return JS_TRUE; +} + +bool +js_GetPropertyHelperWithShape(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, + uint32 getHow, Value *vp, + const Shape **shapeOut, JSObject **holderOut) +{ + return js_GetPropertyHelperWithShapeInline(cx, obj, receiver, id, getHow, vp, + shapeOut, holderOut); +} + +static JS_ALWAYS_INLINE JSBool +js_GetPropertyHelperInline(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, + uint32 getHow, Value *vp) +{ + const Shape *shape; + JSObject *holder; + return js_GetPropertyHelperWithShapeInline(cx, obj, receiver, id, getHow, vp, &shape, &holder); +} + +JSBool +js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uint32 getHow, Value *vp) +{ + return js_GetPropertyHelperInline(cx, obj, obj, id, getHow, vp); +} + +JSBool +js_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp) +{ + /* This call site is hot -- use the always-inlined variant of js_GetPropertyHelper(). */ + return js_GetPropertyHelperInline(cx, obj, receiver, id, JSGET_METHOD_BARRIER, vp); +} + +JSBool +js::GetPropertyDefault(JSContext *cx, JSObject *obj, jsid id, const Value &def, Value *vp) +{ + JSProperty *prop; + JSObject *obj2; + if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) < 0) + return false; + + if (!prop) { + *vp = def; + return true; + } + + return js_GetProperty(cx, obj2, id, vp); +} + +JSBool +js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, Value *vp) +{ + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + + PropertyIdOp op = obj->getOps()->getProperty; + if (!op) { +#if JS_HAS_XML_SUPPORT + JS_ASSERT(!obj->isXML()); +#endif + return js_GetPropertyHelper(cx, obj, id, getHow, vp); + } + JS_ASSERT_IF(getHow & JSGET_CACHE_RESULT, obj->isDenseArray()); +#if JS_HAS_XML_SUPPORT + if (obj->isXML()) + return js_GetXMLMethod(cx, obj, id, vp); +#endif + return op(cx, obj, obj, id, vp); +} + +JS_FRIEND_API(bool) +js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname) +{ + JSStackFrame *const fp = js_GetTopStackFrame(cx); + if (!fp) + return true; + + /* If neither cx nor the code is strict, then no check is needed. */ + if (!(fp->isScriptFrame() && fp->script()->strictModeCode) && + !cx->hasStrictOption()) { + return true; + } + + JSAutoByteString bytes(cx, propname); + return !!bytes && + JS_ReportErrorFlagsAndNumber(cx, + (JSREPORT_WARNING | JSREPORT_STRICT + | JSREPORT_STRICT_MODE_ERROR), + js_GetErrorMessage, NULL, + JSMSG_UNDECLARED_VAR, bytes.ptr()); +} + +bool +JSObject::reportReadOnly(JSContext* cx, jsid id, uintN report) +{ + return js_ReportValueErrorFlags(cx, report, JSMSG_READ_ONLY, + JSDVG_IGNORE_STACK, IdToValue(id), NULL, + NULL, NULL); +} + +bool +JSObject::reportNotConfigurable(JSContext* cx, jsid id, uintN report) +{ + return js_ReportValueErrorFlags(cx, report, JSMSG_CANT_DELETE, + JSDVG_IGNORE_STACK, IdToValue(id), NULL, + NULL, NULL); +} + +bool +JSObject::reportNotExtensible(JSContext *cx, uintN report) +{ + return js_ReportValueErrorFlags(cx, report, JSMSG_OBJECT_NOT_EXTENSIBLE, + JSDVG_IGNORE_STACK, ObjectValue(*this), + NULL, NULL, NULL); +} + +JSBool +js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, + Value *vp, JSBool strict) +{ + int protoIndex; + JSObject *pobj; + JSProperty *prop; + const Shape *shape; + uintN attrs, flags; + intN shortid; + Class *clasp; + PropertyOp getter; + StrictPropertyOp setter; + bool added; + + JS_ASSERT((defineHow & + ~(JSDNP_CACHE_RESULT | JSDNP_SET_METHOD | JSDNP_UNQUALIFIED)) == 0); + if (defineHow & JSDNP_CACHE_RESULT) + JS_ASSERT_NOT_ON_TRACE(cx); + + /* Convert string indices to integers if appropriate. */ + id = js_CheckForStringIndex(id); + + protoIndex = js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, + &pobj, &prop); + if (protoIndex < 0) + return JS_FALSE; + if (prop) { + if (!pobj->isNative()) { + if (pobj->isProxy()) { + AutoPropertyDescriptorRooter pd(cx); + if (!JSProxy::getPropertyDescriptor(cx, pobj, id, true, &pd)) + return false; + + if (pd.attrs & JSPROP_SHARED) + return CallSetter(cx, obj, id, pd.setter, pd.attrs, pd.shortid, strict, vp); + + if (pd.attrs & JSPROP_READONLY) { + if (strict) + return obj->reportReadOnly(cx, id); + if (cx->hasStrictOption()) + return obj->reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING); + return true; + } + } + + prop = NULL; + } + } else { + /* We should never add properties to lexical blocks. */ + JS_ASSERT(!obj->isBlock()); + + if (!obj->getParent() && + (defineHow & JSDNP_UNQUALIFIED) && + !js_CheckUndeclaredVarAssignment(cx, JSID_TO_STRING(id))) { + return JS_FALSE; + } + } + shape = (Shape *) prop; + + /* + * Now either shape is null, meaning id was not found in obj or one of its + * prototypes; or shape is non-null, meaning id was found directly in pobj. + */ + attrs = JSPROP_ENUMERATE; + flags = 0; + shortid = 0; + clasp = obj->getClass(); + getter = clasp->getProperty; + setter = clasp->setProperty; + + if (shape) { + /* ES5 8.12.4 [[Put]] step 2. */ + if (shape->isAccessorDescriptor()) { + if (shape->hasDefaultSetter()) + return js_ReportGetterOnlyAssignment(cx); + } else { + JS_ASSERT(shape->isDataDescriptor()); + + if (!shape->writable()) { + PCMETER((defineHow & JSDNP_CACHE_RESULT) && JS_PROPERTY_CACHE(cx).rofills++); + + /* Error in strict mode code, warn with strict option, otherwise do nothing. */ + if (strict) + return obj->reportReadOnly(cx, id); + if (cx->hasStrictOption()) + return obj->reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING); + return JS_TRUE; + } + } + + attrs = shape->attributes(); + if (pobj != obj) { + /* + * We found id in a prototype object: prepare to share or shadow. + */ + if (!shape->shadowable()) { + if (defineHow & JSDNP_CACHE_RESULT) + JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, protoIndex, pobj, shape); + + if (shape->hasDefaultSetter() && !shape->hasGetterValue()) + return JS_TRUE; + + return shape->set(cx, obj, strict, vp); + } + + /* + * Preserve attrs except JSPROP_SHARED, getter, and setter when + * shadowing any property that has no slot (is shared). We must + * clear the shared attribute for the shadowing shape so that the + * property in obj that it defines has a slot to retain the value + * being set, in case the setter simply cannot operate on instances + * of obj's class by storing the value in some class-specific + * location. + * + * A subset of slotless shared properties is the set of properties + * with shortids, which must be preserved too. An old API requires + * that the property's getter and setter receive the shortid, not + * id, when they are called on the shadowing property that we are + * about to create in obj. + */ + if (!shape->hasSlot()) { + defineHow &= ~JSDNP_SET_METHOD; + if (shape->hasShortID()) { + flags = Shape::HAS_SHORTID; + shortid = shape->shortid; + } + attrs &= ~JSPROP_SHARED; + getter = shape->getter(); + setter = shape->setter(); + } else { + /* Restore attrs to the ECMA default for new properties. */ + attrs = JSPROP_ENUMERATE; + } + + /* + * Forget we found the proto-property now that we've copied any + * needed member values. + */ + shape = NULL; + } + + JS_ASSERT_IF(shape && shape->isMethod(), pobj->hasMethodBarrier()); + JS_ASSERT_IF(shape && shape->isMethod(), + &pobj->getSlot(shape->slot).toObject() == &shape->methodObject()); + if (shape && (defineHow & JSDNP_SET_METHOD)) { + /* + * JSOP_SETMETHOD is assigning to an existing own property. If it + * is an identical method property, do nothing. Otherwise downgrade + * to ordinary assignment. Either way, do not fill the property + * cache, as the interpreter has no fast path for these unusual + * cases. + */ + bool identical = shape->isMethod() && &shape->methodObject() == &vp->toObject(); + if (!identical) { + shape = obj->methodShapeChange(cx, *shape); + if (!shape) + return false; + + JSObject *funobj = &vp->toObject(); + JSFunction *fun = funobj->getFunctionPrivate(); + if (fun == funobj) { + funobj = CloneFunctionObject(cx, fun, fun->parent); + if (!funobj) + return JS_FALSE; + vp->setObject(*funobj); + } + } + return identical || js_NativeSet(cx, obj, shape, false, strict, vp); + } + } + + added = false; + if (!shape) { + if (!obj->isExtensible()) { + /* Error in strict mode code, warn with strict option, otherwise do nothing. */ + if (strict) + return obj->reportNotExtensible(cx); + if (cx->hasStrictOption()) + return obj->reportNotExtensible(cx, JSREPORT_STRICT | JSREPORT_WARNING); + return JS_TRUE; + } + + /* + * Purge the property cache of now-shadowed id in obj's scope chain. + * Do this early, before locking obj to avoid nesting locks. + */ + js_PurgeScopeChain(cx, obj, id); + + /* Find or make a property descriptor with the right heritage. */ + if (!obj->ensureClassReservedSlots(cx)) + return JS_FALSE; + + /* + * Check for Object class here to avoid defining a method on a class + * with magic resolve, addProperty, getProperty, etc. hooks. + */ + if ((defineHow & JSDNP_SET_METHOD) && obj->canHaveMethodBarrier()) { + JS_ASSERT(IsFunctionObject(*vp)); + JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); + + JSObject *funobj = &vp->toObject(); + JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); + if (fun == funobj) { + flags |= Shape::METHOD; + getter = CastAsPropertyOp(funobj); + } + } + + shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT, + attrs, flags, shortid); + if (!shape) + return JS_FALSE; + + if (defineHow & JSDNP_CACHE_RESULT) + TRACE_1(AddProperty, obj); + + /* + * Initialize the new property value (passed to setter) to undefined. + * Note that we store before calling addProperty, to match the order + * in js_DefineNativeProperty. + */ + if (obj->containsSlot(shape->slot)) + obj->nativeSetSlot(shape->slot, UndefinedValue()); + + /* XXXbe called with obj locked */ + if (!CallAddPropertyHook(cx, clasp, obj, shape, vp)) { + obj->removeProperty(cx, id); + return JS_FALSE; + } + added = true; + } + + if (defineHow & JSDNP_CACHE_RESULT) + JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, 0, obj, shape, added); + + return js_NativeSet(cx, obj, shape, added, strict, vp); + +#ifdef JS_TRACER + error: // TRACE_1 jumps here in case of error. + return JS_FALSE; +#endif +} + +JSBool +js_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) +{ + return js_SetPropertyHelper(cx, obj, id, 0, vp, strict); +} + +JSBool +js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +{ + JSProperty *prop; + if (!js_LookupProperty(cx, obj, id, &obj, &prop)) + return false; + if (!prop) { + *attrsp = 0; + return true; + } + if (!obj->isNative()) + return obj->getAttributes(cx, id, attrsp); + + const Shape *shape = (Shape *)prop; + *attrsp = shape->attributes(); + return true; +} + +JSBool +js_SetNativeAttributes(JSContext *cx, JSObject *obj, Shape *shape, uintN attrs) +{ + JS_ASSERT(obj->isNative()); + return !!js_ChangeNativePropertyAttrs(cx, obj, shape, attrs, 0, + shape->getter(), shape->setter()); +} + +JSBool +js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +{ + JSProperty *prop; + if (!js_LookupProperty(cx, obj, id, &obj, &prop)) + return false; + if (!prop) + return true; + return obj->isNative() + ? js_SetNativeAttributes(cx, obj, (Shape *) prop, *attrsp) + : obj->setAttributes(cx, id, attrsp); +} + +JSBool +js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) +{ + JSObject *proto; + JSProperty *prop; + const Shape *shape; + + rval->setBoolean(true); + + /* Convert string indices to integers if appropriate. */ + id = js_CheckForStringIndex(id); + + if (!js_LookupProperty(cx, obj, id, &proto, &prop)) + return false; + if (!prop || proto != obj) { + /* + * If the property was found in a native prototype, check whether it's + * shared and permanent. Such a property stands for direct properties + * in all delegating objects, matching ECMA semantics without bloating + * each delegating object. + */ + if (prop && proto->isNative()) { + shape = (Shape *)prop; + if (shape->isSharedPermanent()) { + if (strict) + return obj->reportNotConfigurable(cx, id); + rval->setBoolean(false); + return true; + } + } + + /* + * If no property, or the property comes unshared or impermanent from + * a prototype, call the class's delProperty hook, passing rval as the + * result parameter. + */ + return CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, id, rval); + } + + shape = (Shape *)prop; + if (!shape->configurable()) { + if (strict) + return obj->reportNotConfigurable(cx, id); + rval->setBoolean(false); + return true; + } + + if (!CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, SHAPE_USERID(shape), rval)) + return false; + + if (obj->containsSlot(shape->slot)) { + const Value &v = obj->nativeGetSlot(shape->slot); + GC_POKE(cx, v); + + /* + * Delete is rare enough that we can take the hit of checking for an + * active cloned method function object that must be homed to a callee + * slot on the active stack frame before this delete completes, in case + * someone saved the clone and checks it against foo.caller for a foo + * called from the active method. + * + * We do not check suspended frames. They can't be reached via caller, + * so the only way they could have the method's joined function object + * as callee is through an API abusage. We break any such edge case. + */ + if (obj->hasMethodBarrier()) { + JSObject *funobj; + + if (IsFunctionObject(v, &funobj)) { + JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); + + if (fun != funobj) { + for (JSStackFrame *fp = cx->maybefp(); fp; fp = fp->prev()) { + if (fp->isFunctionFrame() && + &fp->callee() == &fun->compiledFunObj() && + fp->thisValue().isObject()) + { + JSObject *tmp = &fp->thisValue().toObject(); + do { + if (tmp == obj) { + fp->calleeValue().setObject(*funobj); + break; + } + } while ((tmp = tmp->getProto()) != NULL); + } + } + } + } + } + } + + return obj->removeProperty(cx, id) && js_SuppressDeletedProperty(cx, obj, id); +} + +namespace js { + +JSObject * +HasNativeMethod(JSObject *obj, jsid methodid, Native native) +{ + const Shape *shape = obj->nativeLookup(methodid); + if (!shape || !shape->hasDefaultGetter() || !obj->containsSlot(shape->slot)) + return NULL; + + const Value &fval = obj->nativeGetSlot(shape->slot); + JSObject *funobj; + if (!IsFunctionObject(fval, &funobj) || funobj->getFunctionPrivate()->maybeNative() != native) + return NULL; + + return funobj; +} + +bool +DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp) +{ + JS_ASSERT(hint != JSTYPE_OBJECT && hint != JSTYPE_FUNCTION); + + Value v = ObjectValue(*obj); + if (hint == JSTYPE_STRING) { + /* Optimize (new String(...)).toString(). */ + if (obj->getClass() == &js_StringClass && + ClassMethodIsNative(cx, obj, + &js_StringClass, + ATOM_TO_JSID(cx->runtime->atomState.toStringAtom), + js_str_toString)) { + *vp = obj->getPrimitiveThis(); + return true; + } + + if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0, NULL, &v)) + return false; + if (!v.isPrimitive()) { + if (!obj->getClass()->convert(cx, obj, hint, &v)) + return false; + } + } else { + /* Optimize (new String(...)).valueOf(). */ + Class *clasp = obj->getClass(); + if ((clasp == &js_StringClass && + ClassMethodIsNative(cx, obj, &js_StringClass, + ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom), + js_str_toString)) || + (clasp == &js_NumberClass && + ClassMethodIsNative(cx, obj, &js_NumberClass, + ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom), + js_num_valueOf))) { + *vp = obj->getPrimitiveThis(); + return true; + } + + if (!obj->getClass()->convert(cx, obj, hint, &v)) + return false; + if (v.isObject()) { + JS_ASSERT(hint != TypeOfValue(cx, v)); + if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0, NULL, &v)) + return false; + } + } + if (v.isObject()) { + /* Avoid recursive death when decompiling in js_ReportValueError. */ + JSString *str; + if (hint == JSTYPE_STRING) { + str = JS_InternString(cx, obj->getClass()->name); + if (!str) + return false; + } else { + str = NULL; + } + vp->setObject(*obj); + js_ReportValueError2(cx, JSMSG_CANT_CONVERT_TO, + JSDVG_SEARCH_STACK, *vp, str, + (hint == JSTYPE_VOID) + ? "primitive type" + : JS_TYPE_STR(hint)); + return false; + } + *vp = v; + return true; +} + +} /* namespace js */ + +JS_FRIEND_API(JSBool) +js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, Value *statep, jsid *idp) +{ + /* If the class has a custom JSCLASS_NEW_ENUMERATE hook, call it. */ + Class *clasp = obj->getClass(); + JSEnumerateOp enumerate = clasp->enumerate; + if (clasp->flags & JSCLASS_NEW_ENUMERATE) { + JS_ASSERT(enumerate != JS_EnumerateStub); + return ((NewEnumerateOp) enumerate)(cx, obj, enum_op, statep, idp); + } + + if (!enumerate(cx, obj)) + return false; + + /* Tell InitNativeIterator to treat us like a native object. */ + JS_ASSERT(enum_op == JSENUMERATE_INIT || enum_op == JSENUMERATE_INIT_ALL); + statep->setMagic(JS_NATIVE_ENUMERATE); + return true; +} + +namespace js { + +JSBool +CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, + Value *vp, uintN *attrsp) +{ + JSBool writing; + JSObject *pobj; + JSProperty *prop; + Class *clasp; + const Shape *shape; + JSSecurityCallbacks *callbacks; + CheckAccessOp check; + + while (JS_UNLIKELY(obj->getClass() == &js_WithClass)) + obj = obj->getProto(); + + writing = (mode & JSACC_WRITE) != 0; + switch (mode & JSACC_TYPEMASK) { + case JSACC_PROTO: + pobj = obj; + if (!writing) + vp->setObjectOrNull(obj->getProto()); + *attrsp = JSPROP_PERMANENT; + break; + + case JSACC_PARENT: + JS_ASSERT(!writing); + pobj = obj; + vp->setObject(*obj->getParent()); + *attrsp = JSPROP_READONLY | JSPROP_PERMANENT; + break; + + default: + if (!obj->lookupProperty(cx, id, &pobj, &prop)) + return JS_FALSE; + if (!prop) { + if (!writing) + vp->setUndefined(); + *attrsp = 0; + pobj = obj; + break; + } + + if (!pobj->isNative()) { + if (!writing) { + vp->setUndefined(); + *attrsp = 0; + } + break; + } + + shape = (Shape *)prop; + *attrsp = shape->attributes(); + if (!writing) { + if (pobj->containsSlot(shape->slot)) + *vp = pobj->nativeGetSlot(shape->slot); + else + vp->setUndefined(); + } + } + + /* + * If obj's class has a stub (null) checkAccess hook, use the per-runtime + * checkObjectAccess callback, if configured. + * + * We don't want to require all classes to supply a checkAccess hook; we + * need that hook only for certain classes used when precompiling scripts + * and functions ("brutal sharing"). But for general safety of built-in + * magic properties like __proto__, we route all access checks, even for + * classes that stub out checkAccess, through the global checkObjectAccess + * hook. This covers precompilation-based sharing and (possibly + * unintended) runtime sharing across trust boundaries. + */ + clasp = pobj->getClass(); + check = clasp->checkAccess; + if (!check) { + callbacks = JS_GetSecurityCallbacks(cx); + check = callbacks ? Valueify(callbacks->checkObjectAccess) : NULL; + } + return !check || check(cx, pobj, id, mode, vp); +} + +} + +JSType +js_TypeOf(JSContext *cx, JSObject *obj) +{ + /* + * ECMA 262, 11.4.3 says that any native object that implements + * [[Call]] should be of type "function". However, RegExp is of + * type "object", not "function", for Web compatibility. + */ + if (obj->isCallable()) { + return (obj->getClass() != &js_RegExpClass) + ? JSTYPE_FUNCTION + : JSTYPE_OBJECT; + } + + return JSTYPE_OBJECT; +} + +bool +js_IsDelegate(JSContext *cx, JSObject *obj, const Value &v) +{ + if (v.isPrimitive()) + return false; + JSObject *obj2 = &v.toObject(); + while ((obj2 = obj2->getProto()) != NULL) { + if (obj2 == obj) + return true; + } + return false; +} + +bool +js::FindClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey, + JSObject **protop, Class *clasp) +{ + Value v; + if (!js_FindClassObject(cx, scopeobj, protoKey, &v, clasp)) + return false; + + if (IsFunctionObject(v)) { + JSObject *ctor = &v.toObject(); + if (!ctor->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &v)) + return false; + } + + *protop = v.isObject() ? &v.toObject() : NULL; + return true; +} + +/* + * The first part of this function has been hand-expanded and optimized into + * NewBuiltinClassInstance in jsobjinlines.h. + */ +JSBool +js_GetClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey, + JSObject **protop, Class *clasp) +{ + VOUCH_DOES_NOT_REQUIRE_STACK(); + JS_ASSERT(JSProto_Null <= protoKey); + JS_ASSERT(protoKey < JSProto_LIMIT); + + if (protoKey != JSProto_Null) { + if (!scopeobj) { + if (cx->hasfp()) + scopeobj = &cx->fp()->scopeChain(); + if (!scopeobj) { + scopeobj = cx->globalObject; + if (!scopeobj) { + *protop = NULL; + return true; + } + } + } + scopeobj = scopeobj->getGlobal(); + if (scopeobj->isGlobal()) { + const Value &v = scopeobj->getReservedSlot(JSProto_LIMIT + protoKey); + if (v.isObject()) { + *protop = &v.toObject(); + return true; + } + } + } + + return FindClassPrototype(cx, scopeobj, protoKey, protop, clasp); +} + +JSBool +js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, uintN attrs) +{ + /* + * Use the given attributes for the prototype property of the constructor, + * as user-defined constructors have a DontDelete prototype (which may be + * reset), while native or "system" constructors have DontEnum | ReadOnly | + * DontDelete. + */ + if (!ctor->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), + ObjectOrNullValue(proto), PropertyStub, StrictPropertyStub, attrs)) { + return JS_FALSE; + } + + /* + * ECMA says that Object.prototype.constructor, or f.prototype.constructor + * for a user-defined function f, is DontEnum. + */ + return proto->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), + ObjectOrNullValue(ctor), PropertyStub, StrictPropertyStub, 0); +} + +JSObject * +PrimitiveToObject(JSContext *cx, const Value &v) +{ + JS_ASSERT(v.isPrimitive()); + + Class *clasp; + if (v.isNumber()) { + clasp = &js_NumberClass; + } else if (v.isString()) { + clasp = &js_StringClass; + } else { + JS_ASSERT(v.isBoolean()); + clasp = &js_BooleanClass; + } + + JSObject *obj = NewBuiltinClassInstance(cx, clasp); + if (!obj) + return NULL; + + obj->setPrimitiveThis(v); + return obj; +} + +JSBool +js_PrimitiveToObject(JSContext *cx, Value *vp) +{ + JSObject *obj = PrimitiveToObject(cx, *vp); + if (!obj) + return false; + + vp->setObject(*obj); + return true; +} + +JSBool +js_ValueToObjectOrNull(JSContext *cx, const Value &v, JSObject **objp) +{ + JSObject *obj; + + if (v.isObjectOrNull()) { + obj = v.toObjectOrNull(); + } else if (v.isUndefined()) { + obj = NULL; + } else { + obj = PrimitiveToObject(cx, v); + if (!obj) + return false; + } + *objp = obj; + return true; +} + +namespace js { + +/* Callers must handle the already-object case . */ +JSObject * +ToObjectSlow(JSContext *cx, Value *vp) +{ + JS_ASSERT(!vp->isMagic()); + JS_ASSERT(!vp->isObject()); + + if (vp->isNullOrUndefined()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO, + vp->isNull() ? "null" : "undefined", "object"); + return NULL; + } + + JSObject *obj = PrimitiveToObject(cx, *vp); + if (obj) + vp->setObject(*obj); + return obj; +} + +} + +JSObject * +js_ValueToNonNullObject(JSContext *cx, const Value &v) +{ + JSObject *obj; + + if (!js_ValueToObjectOrNull(cx, v, &obj)) + return NULL; + if (!obj) + js_ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, v, NULL); + return obj; +} + +JSBool +js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, Value *rval) +{ + Value argv[1]; + + argv[0].setString(ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type])); + return js_TryMethod(cx, obj, cx->runtime->atomState.valueOfAtom, + 1, argv, rval); +} + +JSBool +js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom, + uintN argc, Value *argv, Value *rval) +{ + JS_CHECK_RECURSION(cx, return JS_FALSE); + + /* + * Report failure only if an appropriate method was found, and calling it + * returned failure. We propagate failure in this case to make exceptions + * behave properly. + */ + JSErrorReporter older = JS_SetErrorReporter(cx, NULL); + jsid id = ATOM_TO_JSID(atom); + Value fval; + JSBool ok = js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, &fval); + JS_SetErrorReporter(cx, older); + if (!ok) + return false; + + if (fval.isPrimitive()) + return JS_TRUE; + return ExternalInvoke(cx, ObjectValue(*obj), fval, argc, argv, rval); +} + +#if JS_HAS_XDR + +JSBool +js_XDRObject(JSXDRState *xdr, JSObject **objp) +{ + JSContext *cx; + JSAtom *atom; + Class *clasp; + uint32 classId, classDef; + JSProtoKey protoKey; + JSObject *proto; + + cx = xdr->cx; + atom = NULL; + if (xdr->mode == JSXDR_ENCODE) { + clasp = (*objp)->getClass(); + classId = JS_XDRFindClassIdByName(xdr, clasp->name); + classDef = !classId; + if (classDef) { + if (!JS_XDRRegisterClass(xdr, Jsvalify(clasp), &classId)) + return JS_FALSE; + protoKey = JSCLASS_CACHED_PROTO_KEY(clasp); + if (protoKey != JSProto_Null) { + classDef |= (protoKey << 1); + } else { + atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0); + if (!atom) + return JS_FALSE; + } + } + } else { + clasp = NULL; /* quell GCC overwarning */ + classDef = 0; + } + + /* + * XDR a flag word, which could be 0 for a class use, in which case no + * name follows, only the id in xdr's class registry; 1 for a class def, + * in which case the flag word is followed by the class name transferred + * from or to atom; or a value greater than 1, an odd number that when + * divided by two yields the JSProtoKey for class. In the last case, as + * in the 0 classDef case, no name is transferred via atom. + */ + if (!JS_XDRUint32(xdr, &classDef)) + return JS_FALSE; + if (classDef == 1 && !js_XDRAtom(xdr, &atom)) + return JS_FALSE; + + if (!JS_XDRUint32(xdr, &classId)) + return JS_FALSE; + + if (xdr->mode == JSXDR_DECODE) { + if (classDef) { + /* NB: we know that JSProto_Null is 0 here, for backward compat. */ + protoKey = (JSProtoKey) (classDef >> 1); + if (!js_GetClassPrototype(cx, NULL, protoKey, &proto, clasp)) + return JS_FALSE; + clasp = proto->getClass(); + if (!JS_XDRRegisterClass(xdr, Jsvalify(clasp), &classId)) + return JS_FALSE; + } else { + clasp = Valueify(JS_XDRFindClassById(xdr, classId)); + if (!clasp) { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)classId); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_FIND_CLASS, numBuf); + return JS_FALSE; + } + } + } + + if (!clasp->xdrObject) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_XDR_CLASS, clasp->name); + return JS_FALSE; + } + return clasp->xdrObject(xdr, objp); +} + +#endif /* JS_HAS_XDR */ + +#ifdef JS_DUMP_SCOPE_METERS + +#include + +JSBasicStats js_entry_count_bs = JS_INIT_STATIC_BASIC_STATS; + +static void +MeterEntryCount(uintN count) +{ + JS_BASIC_STATS_ACCUM(&js_entry_count_bs, count); +} + +void +js_DumpScopeMeters(JSRuntime *rt) +{ + static FILE *logfp; + if (!logfp) + logfp = fopen("/tmp/scope.stats", "a"); + + { + double mean, sigma; + + mean = JS_MeanAndStdDevBS(&js_entry_count_bs, &sigma); + + fprintf(logfp, "scopes %u entries %g mean %g sigma %g max %u", + js_entry_count_bs.num, js_entry_count_bs.sum, mean, sigma, + js_entry_count_bs.max); + } + + JS_DumpHistogram(&js_entry_count_bs, logfp); + JS_BASIC_STATS_INIT(&js_entry_count_bs); + fflush(logfp); +} +#endif + +#ifdef DEBUG +void +js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize) +{ + JS_ASSERT(trc->debugPrinter == js_PrintObjectSlotName); + + JSObject *obj = (JSObject *)trc->debugPrintArg; + uint32 slot = (uint32)trc->debugPrintIndex; + + const Shape *shape; + if (obj->isNative()) { + shape = obj->lastProperty(); + while (shape->previous() && shape->slot != slot) + shape = shape->previous(); + if (shape->slot != slot) + shape = NULL; + } else { + shape = NULL; + } + + if (!shape) { + const char *slotname = NULL; + if (obj->isGlobal()) { +#define JS_PROTO(name,code,init) \ + if ((code) == slot) { slotname = js_##name##_str; goto found; } +#include "jsproto.tbl" +#undef JS_PROTO + } + found: + if (slotname) + JS_snprintf(buf, bufsize, "CLASS_OBJECT(%s)", slotname); + else + JS_snprintf(buf, bufsize, "**UNKNOWN SLOT %ld**", (long)slot); + } else { + jsid id = shape->id; + if (JSID_IS_INT(id)) { + JS_snprintf(buf, bufsize, "%ld", (long)JSID_TO_INT(id)); + } else if (JSID_IS_ATOM(id)) { + PutEscapedString(buf, bufsize, JSID_TO_ATOM(id), 0); + } else { + JS_snprintf(buf, bufsize, "**FINALIZED ATOM KEY**"); + } + } +} +#endif + +void +js_TraceObject(JSTracer *trc, JSObject *obj) +{ + JS_ASSERT(obj->isNative()); + + JSContext *cx = trc->context; + if (obj->hasSlotsArray() && !obj->nativeEmpty() && IS_GC_MARKING_TRACER(trc)) { + /* + * Trim overlong dslots allocations from the GC, to avoid thrashing in + * case of delete-happy code that settles down at a given population. + * The !obj->nativeEmpty() guard above is due to the bug described by + * the FIXME comment below. + */ + size_t slots = obj->slotSpan(); + if (obj->numSlots() != slots) + obj->shrinkSlots(cx, slots); + } + +#ifdef JS_DUMP_SCOPE_METERS + MeterEntryCount(obj->propertyCount); +#endif + + obj->trace(trc); + + if (!JS_CLIST_IS_EMPTY(&cx->runtime->watchPointList)) + js_TraceWatchPoints(trc, obj); + + /* No one runs while the GC is running, so we can use LOCKED_... here. */ + Class *clasp = obj->getClass(); + if (clasp->mark) { + if (clasp->flags & JSCLASS_MARK_IS_TRACE) + ((JSTraceOp) clasp->mark)(trc, obj); + else if (IS_GC_MARKING_TRACER(trc)) + (void) clasp->mark(cx, obj, trc); + } + if (clasp->flags & JSCLASS_IS_GLOBAL) { + JSCompartment *compartment = obj->getCompartment(); + compartment->mark(trc); + } + + /* + * NB: clasp->mark could mutate something (which would be a bug, but we are + * defensive), so don't hoist this above calling clasp->mark. + */ + uint32 nslots = Min(obj->numSlots(), obj->slotSpan()); + for (uint32 i = 0; i != nslots; ++i) { + const Value &v = obj->getSlot(i); + JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i); + MarkValueRaw(trc, v); + } +} + +void +js_ClearNative(JSContext *cx, JSObject *obj) +{ + /* + * Clear obj of all obj's properties. FIXME: we do not clear reserved slots + * lying below JSSLOT_FREE(clasp). JS_ClearScope does that. + */ + if (!obj->nativeEmpty()) { + /* Now that we're done using real properties, clear obj. */ + obj->clear(cx); + + /* Clear slot values since obj->clear reset our shape to empty. */ + uint32 freeslot = JSSLOT_FREE(obj->getClass()); + uint32 n = obj->numSlots(); + for (uint32 i = freeslot; i < n; ++i) + obj->setSlot(i, UndefinedValue()); + } +} + +bool +js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 slot, Value *vp) +{ + if (!obj->isNative()) { + vp->setUndefined(); + return true; + } + + if (slot < obj->numSlots()) + *vp = obj->getSlot(slot); + else + vp->setUndefined(); + return true; +} + +bool +js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 slot, const Value &v) +{ + if (!obj->isNative()) + return true; + + Class *clasp = obj->getClass(); + + if (slot >= obj->numSlots()) { + uint32 nslots = JSSLOT_FREE(clasp); + JS_ASSERT(slot < nslots); + if (!obj->allocSlots(cx, nslots)) + return false; + } + + obj->setSlot(slot, v); + GC_POKE(cx, JS_NULL); + return true; +} + +JSObject * +JSObject::getGlobal() const +{ + JSObject *obj = const_cast(this); + while (JSObject *parent = obj->getParent()) + obj = parent; + return obj; +} + +JSBool +js_ReportGetterOnlyAssignment(JSContext *cx) +{ + return JS_ReportErrorFlagsAndNumber(cx, + JSREPORT_WARNING | JSREPORT_STRICT | + JSREPORT_STRICT_MODE_ERROR, + js_GetErrorMessage, NULL, + JSMSG_GETTER_ONLY); +} + +JS_FRIEND_API(JSBool) +js_GetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_GETTER_ONLY); + return JS_FALSE; +} + +#ifdef DEBUG + +/* + * Routines to print out values during debugging. These are FRIEND_API to help + * the debugger find them and to support temporarily hacking js_Dump* calls + * into other code. + */ + +void +dumpChars(const jschar *s, size_t n) +{ + size_t i; + + if (n == (size_t) -1) { + while (s[++n]) ; + } + + fputc('"', stderr); + for (i = 0; i < n; i++) { + if (s[i] == '\n') + fprintf(stderr, "\\n"); + else if (s[i] == '\t') + fprintf(stderr, "\\t"); + else if (s[i] >= 32 && s[i] < 127) + fputc(s[i], stderr); + else if (s[i] <= 255) + fprintf(stderr, "\\x%02x", (unsigned int) s[i]); + else + fprintf(stderr, "\\u%04x", (unsigned int) s[i]); + } + fputc('"', stderr); +} + +JS_FRIEND_API(void) +js_DumpChars(const jschar *s, size_t n) +{ + fprintf(stderr, "jschar * (%p) = ", (void *) s); + dumpChars(s, n); + fputc('\n', stderr); +} + +void +dumpString(JSString *str) +{ + if (const jschar *chars = str->getChars(NULL)) + dumpChars(chars, str->length()); + else + fprintf(stderr, "(oom in dumpString)"); +} + +JS_FRIEND_API(void) +js_DumpString(JSString *str) +{ + if (const jschar *chars = str->getChars(NULL)) { + fprintf(stderr, "JSString* (%p) = jschar * (%p) = ", + (void *) str, (void *) chars); + dumpString(str); + } else { + fprintf(stderr, "(oom in JS_DumpString)"); + } + fputc('\n', stderr); +} + +JS_FRIEND_API(void) +js_DumpAtom(JSAtom *atom) +{ + fprintf(stderr, "JSAtom* (%p) = ", (void *) atom); + js_DumpString(ATOM_TO_STRING(atom)); +} + +void +dumpValue(const Value &v) +{ + if (v.isNull()) + fprintf(stderr, "null"); + else if (v.isUndefined()) + fprintf(stderr, "undefined"); + else if (v.isInt32()) + fprintf(stderr, "%d", v.toInt32()); + else if (v.isDouble()) + fprintf(stderr, "%g", v.toDouble()); + else if (v.isString()) + dumpString(v.toString()); + else if (v.isObject() && v.toObject().isFunction()) { + JSObject *funobj = &v.toObject(); + JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); + if (fun->atom) { + fputs("atom), 0); + } else { + fputs("isInterpreted()) { + JSScript *script = fun->script(); + fprintf(stderr, " (%s:%u)", + script->filename ? script->filename : "", script->lineno); + } + fprintf(stderr, " at %p (JSFunction at %p)>", (void *) funobj, (void *) fun); + } else if (v.isObject()) { + JSObject *obj = &v.toObject(); + Class *clasp = obj->getClass(); + fprintf(stderr, "<%s%s at %p>", + clasp->name, + (clasp == &js_ObjectClass) ? "" : " object", + (void *) obj); + } else if (v.isBoolean()) { + if (v.toBoolean()) + fprintf(stderr, "true"); + else + fprintf(stderr, "false"); + } else if (v.isMagic()) { + fprintf(stderr, ""); + } else { + fprintf(stderr, "unexpected value"); + } +} + +JS_FRIEND_API(void) +js_DumpValue(const Value &val) +{ + dumpValue(val); + fputc('\n', stderr); +} + +JS_FRIEND_API(void) +js_DumpId(jsid id) +{ + fprintf(stderr, "jsid %p = ", (void *) JSID_BITS(id)); + dumpValue(IdToValue(id)); + fputc('\n', stderr); +} + +static void +DumpProperty(JSObject *obj, const Shape &shape) +{ + jsid id = shape.id; + uint8 attrs = shape.attributes(); + + fprintf(stderr, " ((Shape *) %p) ", (void *) &shape); + if (attrs & JSPROP_ENUMERATE) fprintf(stderr, "enumerate "); + if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly "); + if (attrs & JSPROP_PERMANENT) fprintf(stderr, "permanent "); + if (attrs & JSPROP_SHARED) fprintf(stderr, "shared "); + if (shape.isAlias()) fprintf(stderr, "alias "); + if (shape.isMethod()) fprintf(stderr, "method=%p ", (void *) &shape.methodObject()); + + if (shape.hasGetterValue()) + fprintf(stderr, "getterValue=%p ", (void *) shape.getterObject()); + else if (!shape.hasDefaultGetter()) + fprintf(stderr, "getterOp=%p ", JS_FUNC_TO_DATA_PTR(void *, shape.getterOp())); + + if (shape.hasSetterValue()) + fprintf(stderr, "setterValue=%p ", (void *) shape.setterObject()); + else if (shape.setterOp() == js_watch_set) + fprintf(stderr, "setterOp=js_watch_set "); + else if (!shape.hasDefaultSetter()) + fprintf(stderr, "setterOp=%p ", JS_FUNC_TO_DATA_PTR(void *, shape.setterOp())); + + if (JSID_IS_ATOM(id)) + dumpString(JSID_TO_STRING(id)); + else if (JSID_IS_INT(id)) + fprintf(stderr, "%d", (int) JSID_TO_INT(id)); + else + fprintf(stderr, "unknown jsid %p", (void *) JSID_BITS(id)); + fprintf(stderr, ": slot %d", shape.slot); + if (obj->containsSlot(shape.slot)) { + fprintf(stderr, " = "); + dumpValue(obj->getSlot(shape.slot)); + } else if (shape.slot != SHAPE_INVALID_SLOT) { + fprintf(stderr, " (INVALID!)"); + } + fprintf(stderr, "\n"); +} + +JS_FRIEND_API(void) +js_DumpObject(JSObject *obj) +{ + fprintf(stderr, "object %p\n", (void *) obj); + Class *clasp = obj->getClass(); + fprintf(stderr, "class %p %s\n", (void *)clasp, clasp->name); + + fprintf(stderr, "flags:"); + uint32 flags = obj->flags; + if (flags & JSObject::DELEGATE) fprintf(stderr, " delegate"); + if (flags & JSObject::SYSTEM) fprintf(stderr, " system"); + if (flags & JSObject::NOT_EXTENSIBLE) fprintf(stderr, " not_extensible"); + if (flags & JSObject::BRANDED) fprintf(stderr, " branded"); + if (flags & JSObject::GENERIC) fprintf(stderr, " generic"); + if (flags & JSObject::METHOD_BARRIER) fprintf(stderr, " method_barrier"); + if (flags & JSObject::INDEXED) fprintf(stderr, " indexed"); + if (flags & JSObject::OWN_SHAPE) fprintf(stderr, " own_shape"); + if (flags & JSObject::HAS_EQUALITY) fprintf(stderr, " has_equality"); + + bool anyFlags = flags != 0; + if (obj->isNative()) { + if (obj->inDictionaryMode()) { + fprintf(stderr, " inDictionaryMode"); + anyFlags = true; + } + if (obj->hasPropertyTable()) { + fprintf(stderr, " hasPropertyTable"); + anyFlags = true; + } + } + if (!anyFlags) + fprintf(stderr, " none"); + fprintf(stderr, "\n"); + + if (obj->isDenseArray()) { + unsigned slots = JS_MIN(obj->getArrayLength(), obj->getDenseArrayCapacity()); + fprintf(stderr, "elements\n"); + for (unsigned i = 0; i < slots; i++) { + fprintf(stderr, " %3d: ", i); + dumpValue(obj->getDenseArrayElement(i)); + fprintf(stderr, "\n"); + fflush(stderr); + } + return; + } + + fprintf(stderr, "proto "); + dumpValue(ObjectOrNullValue(obj->getProto())); + fputc('\n', stderr); + + fprintf(stderr, "parent "); + dumpValue(ObjectOrNullValue(obj->getParent())); + fputc('\n', stderr); + + if (clasp->flags & JSCLASS_HAS_PRIVATE) + fprintf(stderr, "private %p\n", obj->getPrivate()); + + if (!obj->isNative()) + fprintf(stderr, "not native\n"); + + unsigned reservedEnd = JSCLASS_RESERVED_SLOTS(clasp); + unsigned slots = obj->slotSpan(); + unsigned stop = obj->isNative() ? reservedEnd : slots; + if (stop > 0) + fprintf(stderr, obj->isNative() ? "reserved slots:\n" : "slots:\n"); + for (unsigned i = 0; i < stop; i++) { + fprintf(stderr, " %3d ", i); + if (i < reservedEnd) + fprintf(stderr, "(reserved) "); + fprintf(stderr, "= "); + dumpValue(obj->getSlot(i)); + fputc('\n', stderr); + } + + if (obj->isNative()) { + fprintf(stderr, "properties:\n"); + Vector props; + for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) + props.append(&r.front()); + for (size_t i = props.length(); i-- != 0;) + DumpProperty(obj, *props[i]); + } + fputc('\n', stderr); +} + +static void +MaybeDumpObject(const char *name, JSObject *obj) +{ + if (obj) { + fprintf(stderr, " %s: ", name); + dumpValue(ObjectValue(*obj)); + fputc('\n', stderr); + } +} + +static void +MaybeDumpValue(const char *name, const Value &v) +{ + if (!v.isNull()) { + fprintf(stderr, " %s: ", name); + dumpValue(v); + fputc('\n', stderr); + } +} + +JS_FRIEND_API(void) +js_DumpStackFrame(JSContext *cx, JSStackFrame *start) +{ + /* This should only called during live debugging. */ + VOUCH_DOES_NOT_REQUIRE_STACK(); + + if (!start) + start = cx->maybefp(); + FrameRegsIter i(cx); + while (!i.done() && i.fp() != start) + ++i; + + if (i.done()) { + fprintf(stderr, "fp = %p not found in cx = %p\n", (void *)start, (void *)cx); + return; + } + + for (; !i.done(); ++i) { + JSStackFrame *const fp = i.fp(); + + fprintf(stderr, "JSStackFrame at %p\n", (void *) fp); + if (fp->isFunctionFrame()) { + fprintf(stderr, "callee fun: "); + dumpValue(ObjectValue(fp->callee())); + } else { + fprintf(stderr, "global frame, no callee"); + } + fputc('\n', stderr); + + if (fp->isScriptFrame()) { + fprintf(stderr, "file %s line %u\n", + fp->script()->filename, (unsigned) fp->script()->lineno); + } + + if (jsbytecode *pc = i.pc()) { + if (!fp->isScriptFrame()) { + fprintf(stderr, "*** pc && !script, skipping frame\n\n"); + continue; + } + if (fp->hasImacropc()) { + fprintf(stderr, " pc in imacro at %p\n called from ", pc); + pc = fp->imacropc(); + } else { + fprintf(stderr, " "); + } + fprintf(stderr, "pc = %p\n", pc); + fprintf(stderr, " current op: %s\n", js_CodeName[*pc]); + } + Value *sp = i.sp(); + fprintf(stderr, " slots: %p\n", (void *) fp->slots()); + fprintf(stderr, " sp: %p = slots + %u\n", (void *) sp, (unsigned) (sp - fp->slots())); + if (sp - fp->slots() < 10000) { // sanity + for (Value *p = fp->slots(); p < sp; p++) { + fprintf(stderr, " %p: ", (void *) p); + dumpValue(*p); + fputc('\n', stderr); + } + } + if (fp->isFunctionFrame() && !fp->isEvalFrame()) { + fprintf(stderr, " actuals: %p (%u) ", (void *) fp->actualArgs(), (unsigned) fp->numActualArgs()); + fprintf(stderr, " formals: %p (%u)\n", (void *) fp->formalArgs(), (unsigned) fp->numFormalArgs()); + } + MaybeDumpObject("callobj", fp->maybeCallObj()); + MaybeDumpObject("argsobj", fp->maybeArgsObj()); + if (!fp->isDummyFrame()) { + MaybeDumpValue("this", fp->thisValue()); + fprintf(stderr, " rval: "); + dumpValue(fp->returnValue()); + } else { + fprintf(stderr, "dummy frame"); + } + fputc('\n', stderr); + + fprintf(stderr, " flags:"); + if (fp->isConstructing()) + fprintf(stderr, " constructing"); + if (fp->hasOverriddenArgs()) + fprintf(stderr, " overridden_args"); + if (fp->isAssigning()) + fprintf(stderr, " assigning"); + if (fp->isDebuggerFrame()) + fprintf(stderr, " debugger"); + if (fp->isEvalFrame()) + fprintf(stderr, " eval"); + if (fp->isYielding()) + fprintf(stderr, " yielding"); + if (fp->isGeneratorFrame()) + fprintf(stderr, " generator"); + fputc('\n', stderr); + + fprintf(stderr, " scopeChain: (JSObject *) %p\n", (void *) &fp->scopeChain()); + + fputc('\n', stderr); + } +} + +#endif /* DEBUG */ + diff --git a/js/src/jsobj.h b/js/src/jsobj.h new file mode 100644 index 0000000..1595397 --- /dev/null +++ b/js/src/jsobj.h @@ -0,0 +1,1952 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsobj_h___ +#define jsobj_h___ + +/* Gross special case for Gecko, which defines malloc/calloc/free. */ +#ifdef mozilla_mozalloc_macro_wrappers_h +# define JS_OBJ_UNDEFD_MOZALLOC_WRAPPERS +/* The "anti-header" */ +# include "mozilla/mozalloc_undef_macro_wrappers.h" +#endif + +/* + * JS object definitions. + * + * A JS object consists of a possibly-shared object descriptor containing + * ordered property names, called the map; and a dense vector of property + * values, called slots. The map/slot pointer pair is GC'ed, while the map + * is reference counted and the slot vector is malloc'ed. + */ +#include "jsapi.h" +#include "jshash.h" +#include "jspubtd.h" +#include "jsprvtd.h" +#include "jslock.h" +#include "jsvalue.h" +#include "jsvector.h" +#include "jscell.h" + +namespace js { + +class JSProxyHandler; +class AutoPropDescArrayRooter; + +namespace mjit { +class Compiler; +} + +static inline PropertyOp +CastAsPropertyOp(JSObject *object) +{ + return JS_DATA_TO_FUNC_PTR(PropertyOp, object); +} + +static inline StrictPropertyOp +CastAsStrictPropertyOp(JSObject *object) +{ + return JS_DATA_TO_FUNC_PTR(StrictPropertyOp, object); +} + +static inline JSPropertyOp +CastAsJSPropertyOp(JSObject *object) +{ + return JS_DATA_TO_FUNC_PTR(JSPropertyOp, object); +} + +static inline JSStrictPropertyOp +CastAsJSStrictPropertyOp(JSObject *object) +{ + return JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, object); +} + +inline JSObject * +CastAsObject(PropertyOp op) +{ + return JS_FUNC_TO_DATA_PTR(JSObject *, op); +} + +inline JSObject * +CastAsObject(StrictPropertyOp op) +{ + return JS_FUNC_TO_DATA_PTR(JSObject *, op); +} + +inline Value +CastAsObjectJsval(PropertyOp op) +{ + return ObjectOrNullValue(CastAsObject(op)); +} + +inline Value +CastAsObjectJsval(StrictPropertyOp op) +{ + return ObjectOrNullValue(CastAsObject(op)); +} + +} /* namespace js */ + +/* + * A representation of ECMA-262 ed. 5's internal property descriptor data + * structure. + */ +struct PropDesc { + friend class js::AutoPropDescArrayRooter; + + PropDesc(); + + public: + /* 8.10.5 ToPropertyDescriptor(Obj) */ + bool initialize(JSContext* cx, jsid id, const js::Value &v); + + /* 8.10.1 IsAccessorDescriptor(desc) */ + bool isAccessorDescriptor() const { + return hasGet || hasSet; + } + + /* 8.10.2 IsDataDescriptor(desc) */ + bool isDataDescriptor() const { + return hasValue || hasWritable; + } + + /* 8.10.3 IsGenericDescriptor(desc) */ + bool isGenericDescriptor() const { + return !isAccessorDescriptor() && !isDataDescriptor(); + } + + bool configurable() const { + return (attrs & JSPROP_PERMANENT) == 0; + } + + bool enumerable() const { + return (attrs & JSPROP_ENUMERATE) != 0; + } + + bool writable() const { + return (attrs & JSPROP_READONLY) == 0; + } + + JSObject* getterObject() const { + return get.isUndefined() ? NULL : &get.toObject(); + } + JSObject* setterObject() const { + return set.isUndefined() ? NULL : &set.toObject(); + } + + const js::Value &getterValue() const { + return get; + } + const js::Value &setterValue() const { + return set; + } + + js::PropertyOp getter() const { + return js::CastAsPropertyOp(getterObject()); + } + js::StrictPropertyOp setter() const { + return js::CastAsStrictPropertyOp(setterObject()); + } + + js::Value pd; + jsid id; + js::Value value, get, set; + + /* Property descriptor boolean fields. */ + uint8 attrs; + + /* Bits indicating which values are set. */ + bool hasGet : 1; + bool hasSet : 1; + bool hasValue : 1; + bool hasWritable : 1; + bool hasEnumerable : 1; + bool hasConfigurable : 1; +}; + +namespace js { + +typedef Vector PropDescArray; + +} /* namespace js */ + +struct JSObjectMap { + uint32 shape; /* shape identifier */ + uint32 slotSpan; /* one more than maximum live slot number */ + + static JS_FRIEND_DATA(const JSObjectMap) sharedNonNative; + + explicit JSObjectMap(uint32 shape) : shape(shape), slotSpan(0) {} + JSObjectMap(uint32 shape, uint32 slotSpan) : shape(shape), slotSpan(slotSpan) {} + + enum { INVALID_SHAPE = 0x8fffffff, SHAPELESS = 0xffffffff }; + + bool isNative() const { return this != &sharedNonNative; } + + private: + /* No copy or assignment semantics. */ + JSObjectMap(JSObjectMap &); + void operator=(JSObjectMap &); +}; + +/* + * Unlike js_DefineNativeProperty, propp must be non-null. On success, and if + * id was found, return true with *objp non-null and with a property of *objp + * stored in *propp. If successful but id was not found, return true with both + * *objp and *propp null. + */ +extern JS_FRIEND_API(JSBool) +js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + JSProperty **propp); + +extern JSBool +js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value *value, + js::PropertyOp getter, js::StrictPropertyOp setter, uintN attrs); + +extern JSBool +js_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, js::Value *vp); + +inline JSBool +js_GetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp) +{ + return js_GetProperty(cx, obj, obj, id, vp); +} + +namespace js { + +extern JSBool +GetPropertyDefault(JSContext *cx, JSObject *obj, jsid id, const Value &def, Value *vp); + +} /* namespace js */ + +extern JSBool +js_SetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp, JSBool strict); + +extern JSBool +js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); + +extern JSBool +js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); + +extern JSBool +js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *rval, JSBool strict); + +extern JS_FRIEND_API(JSBool) +js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + js::Value *statep, jsid *idp); + +extern JSType +js_TypeOf(JSContext *cx, JSObject *obj); + +namespace js { + +struct NativeIterator; + +} + +struct JSFunction; + +namespace nanojit { +class ValidateWriter; +} + +/* + * JSObject struct, with members sized to fit in 32 bytes on 32-bit targets, + * 64 bytes on 64-bit systems. The JSFunction struct is an extension of this + * struct allocated from a larger GC size-class. + * + * The clasp member stores the js::Class pointer for this object. We do *not* + * synchronize updates of clasp or flags -- API clients must take care. + * + * An object is a delegate if it is on another object's prototype (the proto + * field) or scope chain (the parent field), and therefore the delegate might + * be asked implicitly to get or set a property on behalf of another object. + * Delegates may be accessed directly too, as may any object, but only those + * objects linked after the head of any prototype or scope chain are flagged + * as delegates. This definition helps to optimize shape-based property cache + * invalidation (see Purge{Scope,Proto}Chain in jsobj.cpp). + * + * The meaning of the system object bit is defined by the API client. It is + * set in JS_NewSystemObject and is queried by JS_IsSystemObject (jsdbgapi.h), + * but it has no intrinsic meaning to SpiderMonkey. Further, JSFILENAME_SYSTEM + * and JS_FlagScriptFilenamePrefix (also exported via jsdbgapi.h) are intended + * to be complementary to this bit, but it is up to the API client to implement + * any such association. + * + * Both these flag bits are initially zero; they may be set or queried using + * the (is|set)(Delegate|System) inline methods. + * + * The slots member is a pointer to the slot vector for the object. + * This can be either a fixed array allocated immediately after the object, + * or a dynamically allocated array. A dynamic array can be tested for with + * hasSlotsArray(). In all cases, capacity gives the number of usable slots. + * Two objects with the same shape have the same number of fixed slots, + * and either both have or neither have dynamically allocated slot arrays. + * + * If you change this struct, you'll probably need to change the AccSet values + * in jsbuiltins.h. + */ +struct JSObject : js::gc::Cell { + /* + * TraceRecorder must be a friend because it generates code that + * manipulates JSObjects, which requires peeking under any encapsulation. + * ValidateWriter must be a friend because it works in tandem with + * TraceRecorder. + */ + friend class js::TraceRecorder; + friend class nanojit::ValidateWriter; + friend class GetPropCompiler; + + /* + * Private pointer to the last added property and methods to manipulate the + * list it links among properties in this scope. The {remove,insert} pair + * for DictionaryProperties assert that the scope is in dictionary mode and + * any reachable properties are flagged as dictionary properties. + * + * For native objects, this field is always a Shape. For non-native objects, + * it points to the singleton sharedNonNative JSObjectMap, whose shape field + * is SHAPELESS. + * + * NB: these private methods do *not* update this scope's shape to track + * lastProp->shape after they finish updating the linked list in the case + * where lastProp is updated. It is up to calling code in jsscope.cpp to + * call updateShape(cx) after updating lastProp. + */ + union { + js::Shape *lastProp; + JSObjectMap *map; + }; + + js::Class *clasp; + + private: + inline void setLastProperty(const js::Shape *shape); + inline void removeLastProperty(); + +#ifdef DEBUG + void checkShapeConsistency(); +#endif + + public: + inline const js::Shape *lastProperty() const; + + inline js::Shape **nativeSearch(jsid id, bool adding = false); + inline const js::Shape *nativeLookup(jsid id); + + inline bool nativeContains(jsid id); + inline bool nativeContains(const js::Shape &shape); + + enum { + DELEGATE = 0x01, + SYSTEM = 0x02, + NOT_EXTENSIBLE = 0x04, + BRANDED = 0x08, + GENERIC = 0x10, + METHOD_BARRIER = 0x20, + INDEXED = 0x40, + OWN_SHAPE = 0x80, + BOUND_FUNCTION = 0x100, + HAS_EQUALITY = 0x200, + METHOD_THRASH_COUNT_MASK = 0xc00, + METHOD_THRASH_COUNT_SHIFT = 10, + METHOD_THRASH_COUNT_MAX = METHOD_THRASH_COUNT_MASK >> METHOD_THRASH_COUNT_SHIFT + }; + + /* + * Impose a sane upper bound, originally checked only for dense arrays, on + * number of slots in an object. + */ + enum { + NSLOTS_BITS = 29, + NSLOTS_LIMIT = JS_BIT(NSLOTS_BITS) + }; + + uint32 flags; /* flags */ + uint32 objShape; /* copy of lastProp->shape, or override if different */ + + /* If prototype, lazily filled array of empty shapes for each object size. */ + js::EmptyShape **emptyShapes; + + JSObject *proto; /* object's prototype */ + JSObject *parent; /* object's parent */ + void *privateData; /* private data */ + jsuword capacity; /* capacity of slots */ + js::Value *slots; /* dynamically allocated slots, + or pointer to fixedSlots() */ + + /* + * Return an immutable, shareable, empty shape with the same clasp as this + * and the same slotSpan as this had when empty. + * + * If |this| is the scope of an object |proto|, the resulting scope can be + * used as the scope of a new object whose prototype is |proto|. + */ + inline bool canProvideEmptyShape(js::Class *clasp); + inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp, + /* gc::FinalizeKind */ unsigned kind); + + bool isNative() const { return map->isNative(); } + + js::Class *getClass() const { return clasp; } + JSClass *getJSClass() const { return Jsvalify(clasp); } + + bool hasClass(const js::Class *c) const { + return c == clasp; + } + + const js::ObjectOps *getOps() const { + return &getClass()->ops; + } + + inline void trace(JSTracer *trc); + + uint32 shape() const { + JS_ASSERT(objShape != JSObjectMap::INVALID_SHAPE); + return objShape; + } + + bool isDelegate() const { return !!(flags & DELEGATE); } + void setDelegate() { flags |= DELEGATE; } + void clearDelegate() { flags &= ~DELEGATE; } + + bool isBoundFunction() const { return !!(flags & BOUND_FUNCTION); } + + static void setDelegateNullSafe(JSObject *obj) { + if (obj) + obj->setDelegate(); + } + + bool isSystem() const { return !!(flags & SYSTEM); } + void setSystem() { flags |= SYSTEM; } + + /* + * A branded object contains plain old methods (function-valued properties + * without magic getters and setters), and its shape evolves whenever a + * function value changes. + */ + bool branded() { return !!(flags & BRANDED); } + + /* + * NB: these return false on shape overflow but do not report any error. + * Callers who depend on shape guarantees should therefore bail off trace, + * e.g., on false returns. + */ + bool brand(JSContext *cx); + bool unbrand(JSContext *cx); + + bool generic() { return !!(flags & GENERIC); } + void setGeneric() { flags |= GENERIC; } + + uintN getMethodThrashCount() const { + return (flags & METHOD_THRASH_COUNT_MASK) >> METHOD_THRASH_COUNT_SHIFT; + } + + void setMethodThrashCount(uintN count) { + JS_ASSERT(count <= METHOD_THRASH_COUNT_MAX); + flags = (flags & ~METHOD_THRASH_COUNT_MASK) | (count << METHOD_THRASH_COUNT_SHIFT); + } + + bool hasSpecialEquality() const { return !!(flags & HAS_EQUALITY); } + void assertSpecialEqualitySynced() const { + JS_ASSERT(!!clasp->ext.equality == hasSpecialEquality()); + } + + /* Sets an object's HAS_EQUALITY flag based on its clasp. */ + inline void syncSpecialEquality(); + + private: + void generateOwnShape(JSContext *cx); + + void setOwnShape(uint32 s) { flags |= OWN_SHAPE; objShape = s; } + void clearOwnShape() { flags &= ~OWN_SHAPE; objShape = map->shape; } + + public: + inline bool nativeEmpty() const; + + bool hasOwnShape() const { return !!(flags & OWN_SHAPE); } + + void setMap(const JSObjectMap *amap) { + JS_ASSERT(!hasOwnShape()); + map = const_cast(amap); + objShape = map->shape; + } + + void setSharedNonNativeMap() { + setMap(&JSObjectMap::sharedNonNative); + } + + void deletingShapeChange(JSContext *cx, const js::Shape &shape); + const js::Shape *methodShapeChange(JSContext *cx, const js::Shape &shape); + bool methodShapeChange(JSContext *cx, uint32 slot); + void protoShapeChange(JSContext *cx); + void shadowingShapeChange(JSContext *cx, const js::Shape &shape); + bool globalObjectOwnShapeChange(JSContext *cx); + void watchpointOwnShapeChange(JSContext *cx) { generateOwnShape(cx); } + + void extensibleShapeChange(JSContext *cx) { + /* This will do for now. */ + generateOwnShape(cx); + } + + /* + * A scope has a method barrier when some compiler-created "null closure" + * function objects (functions that do not use lexical bindings above their + * scope, only free variable names) that have a correct JSSLOT_PARENT value + * thanks to the COMPILE_N_GO optimization are stored as newly added direct + * property values of the scope's object. + * + * The de-facto standard JS language requires each evaluation of such a + * closure to result in a unique (according to === and observable effects) + * function object. ES3 tried to allow implementations to "join" such + * objects to a single compiler-created object, but this makes an overt + * mutation hazard, also an "identity hazard" against interoperation among + * implementations that join and do not join. + * + * To stay compatible with the de-facto standard, we store the compiler- + * created function object as the method value and set the METHOD_BARRIER + * flag. + * + * The method value is part of the method property tree node's identity, so + * it effectively brands the scope with a predictable shape corresponding + * to the method value, but without the overhead of setting the BRANDED + * flag, which requires assigning a new shape peculiar to each branded + * scope. Instead the shape is shared via the property tree among all the + * scopes referencing the method property tree node. + * + * Then when reading from a scope for which scope->hasMethodBarrier() is + * true, we count on the scope's qualified/guarded shape being unique and + * add a read barrier that clones the compiler-created function object on + * demand, reshaping the scope. + * + * This read barrier is bypassed when evaluating the callee sub-expression + * of a call expression (see the JOF_CALLOP opcodes in jsopcode.tbl), since + * such ops do not present an identity or mutation hazard. The compiler + * performs this optimization only for null closures that do not use their + * own name or equivalent built-in references (arguments.callee). + * + * The BRANDED write barrier, JSObject::methodWriteBarrer, must check for + * METHOD_BARRIER too, and regenerate this scope's shape if the method's + * value is in fact changing. + */ + bool hasMethodBarrier() { return !!(flags & METHOD_BARRIER); } + void setMethodBarrier() { flags |= METHOD_BARRIER; } + + /* + * Test whether this object may be branded due to method calls, which means + * any assignment to a function-valued property must regenerate shape; else + * test whether this object has method properties, which require a method + * write barrier. + */ + bool brandedOrHasMethodBarrier() { return !!(flags & (BRANDED | METHOD_BARRIER)); } + + /* + * Read barrier to clone a joined function object stored as a method. + * Defined in jsobjinlines.h, but not declared inline per standard style in + * order to avoid gcc warnings. + */ + const js::Shape *methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp); + + /* + * Write barrier to check for a change of method value. Defined inline in + * jsobjinlines.h after methodReadBarrier. The slot flavor is required by + * JSOP_*GVAR, which deals in slots not shapes, while not deoptimizing to + * map slot to shape unless JSObject::flags show that this is necessary. + * The methodShapeChange overload (above) parallels this. + */ + const js::Shape *methodWriteBarrier(JSContext *cx, const js::Shape &shape, const js::Value &v); + bool methodWriteBarrier(JSContext *cx, uint32 slot, const js::Value &v); + + bool isIndexed() const { return !!(flags & INDEXED); } + void setIndexed() { flags |= INDEXED; } + + /* + * Return true if this object is a native one that has been converted from + * shared-immutable prototype-rooted shape storage to dictionary-shapes in + * a doubly-linked list. + */ + inline bool inDictionaryMode() const; + + inline uint32 propertyCount() const; + + inline bool hasPropertyTable() const; + + /* gc::FinalizeKind */ unsigned finalizeKind() const; + + uint32 numSlots() const { return capacity; } + + size_t slotsAndStructSize(uint32 nslots) const; + size_t slotsAndStructSize() const { return slotsAndStructSize(numSlots()); } + + inline js::Value* fixedSlots() const; + inline size_t numFixedSlots() const; + + static inline size_t getFixedSlotOffset(size_t slot); + + public: + /* Minimum size for dynamically allocated slots. */ + static const uint32 SLOT_CAPACITY_MIN = 8; + + bool allocSlots(JSContext *cx, size_t nslots); + bool growSlots(JSContext *cx, size_t nslots); + void shrinkSlots(JSContext *cx, size_t nslots); + + bool ensureSlots(JSContext *cx, size_t nslots) { + if (numSlots() < nslots) + return growSlots(cx, nslots); + return true; + } + + /* + * Ensure that the object has at least JSCLASS_RESERVED_SLOTS(clasp) + + * nreserved slots. + * + * This method may be called only for native objects freshly created using + * NewObject or one of its variant where the new object will both (a) never + * escape to script and (b) never be extended with ad-hoc properties that + * would try to allocate higher slots without the fresh object first having + * its map set to a shape path that maps those slots. + * + * Block objects satisfy (a) and (b), as there is no evil eval-based way to + * add ad-hoc properties to a Block instance. Call objects satisfy (a) and + * (b) as well, because the compiler-created Shape path that covers args, + * vars, and upvars, stored in their callee function in u.i.names, becomes + * their initial map. + */ + bool ensureInstanceReservedSlots(JSContext *cx, size_t nreserved); + + /* + * Get a direct pointer to the object's slots. + * This can be reallocated if the object is modified, watch out! + */ + js::Value *getSlots() const { + return slots; + } + + /* + * NB: ensureClassReservedSlotsForEmptyObject asserts that nativeEmpty() + * Use ensureClassReservedSlots for any object, either empty or already + * extended with properties. + */ + bool ensureClassReservedSlotsForEmptyObject(JSContext *cx); + + inline bool ensureClassReservedSlots(JSContext *cx); + + uint32 slotSpan() const { return map->slotSpan; } + + bool containsSlot(uint32 slot) const { return slot < slotSpan(); } + + js::Value& getSlotRef(uintN slot) { + JS_ASSERT(slot < capacity); + return slots[slot]; + } + + js::Value &nativeGetSlotRef(uintN slot) { + JS_ASSERT(isNative()); + JS_ASSERT(containsSlot(slot)); + return getSlotRef(slot); + } + + const js::Value &getSlot(uintN slot) const { + JS_ASSERT(slot < capacity); + return slots[slot]; + } + + const js::Value &nativeGetSlot(uintN slot) const { + JS_ASSERT(isNative()); + JS_ASSERT(containsSlot(slot)); + return getSlot(slot); + } + + void setSlot(uintN slot, const js::Value &value) { + JS_ASSERT(slot < capacity); + slots[slot] = value; + } + + void nativeSetSlot(uintN slot, const js::Value &value) { + JS_ASSERT(isNative()); + JS_ASSERT(containsSlot(slot)); + return setSlot(slot, value); + } + + inline js::Value getReservedSlot(uintN index) const; + + /* Defined in jsscopeinlines.h to avoid including implementation dependencies here. */ + inline void updateShape(JSContext *cx); + inline void updateFlags(const js::Shape *shape, bool isDefinitelyAtom = false); + + /* Extend this object to have shape as its last-added property. */ + inline void extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom = false); + + JSObject *getProto() const { return proto; } + void clearProto() { proto = NULL; } + + void setProto(JSObject *newProto) { +#ifdef DEBUG + for (JSObject *obj = newProto; obj; obj = obj->getProto()) + JS_ASSERT(obj != this); +#endif + setDelegateNullSafe(newProto); + proto = newProto; + } + + JSObject *getParent() const { + return parent; + } + + void clearParent() { + parent = NULL; + } + + void setParent(JSObject *newParent) { +#ifdef DEBUG + for (JSObject *obj = newParent; obj; obj = obj->getParent()) + JS_ASSERT(obj != this); +#endif + setDelegateNullSafe(newParent); + parent = newParent; + } + + JS_FRIEND_API(JSObject *) getGlobal() const; + + bool isGlobal() const { + return !!(getClass()->flags & JSCLASS_IS_GLOBAL); + } + + void *getPrivate() const { + JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE); + return privateData; + } + + void setPrivate(void *data) { + JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE); + privateData = data; + } + + + /* + * ES5 meta-object properties and operations. + */ + + private: + enum ImmutabilityType { SEAL, FREEZE }; + + /* + * The guts of Object.seal (ES5 15.2.3.8) and Object.freeze (ES5 15.2.3.9): mark the + * object as non-extensible, and adjust each property's attributes appropriately: each + * property becomes non-configurable, and if |freeze|, data properties become + * read-only as well. + */ + bool sealOrFreeze(JSContext *cx, ImmutabilityType it); + + public: + bool isExtensible() const { return !(flags & NOT_EXTENSIBLE); } + bool preventExtensions(JSContext *cx, js::AutoIdVector *props); + + /* ES5 15.2.3.8: non-extensible, all props non-configurable */ + inline bool seal(JSContext *cx) { return sealOrFreeze(cx, SEAL); } + /* ES5 15.2.3.9: non-extensible, all properties non-configurable, all data props read-only */ + bool freeze(JSContext *cx) { return sealOrFreeze(cx, FREEZE); } + + /* + * Primitive-specific getters and setters. + */ + + private: + static const uint32 JSSLOT_PRIMITIVE_THIS = 0; + + public: + inline const js::Value &getPrimitiveThis() const; + inline void setPrimitiveThis(const js::Value &pthis); + + /* + * Array-specific getters and setters (for both dense and slow arrays). + */ + + inline uint32 getArrayLength() const; + inline void setArrayLength(uint32 length); + + inline uint32 getDenseArrayCapacity(); + inline js::Value* getDenseArrayElements(); + inline const js::Value &getDenseArrayElement(uintN idx); + inline js::Value* addressOfDenseArrayElement(uintN idx); + inline void setDenseArrayElement(uintN idx, const js::Value &val); + inline void shrinkDenseArrayElements(JSContext *cx, uintN cap); + + /* + * ensureDenseArrayElements ensures that the dense array can hold at least + * index + extra elements. It returns ED_OK on success, ED_FAILED on + * failure to grow the array, ED_SPARSE when the array is too sparse to + * grow (this includes the case of index + extra overflow). In the last + * two cases the array is kept intact. + */ + enum EnsureDenseResult { ED_OK, ED_FAILED, ED_SPARSE }; + inline EnsureDenseResult ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra); + + /* + * Check if after growing the dense array will be too sparse. + * newElementsHint is an estimated number of elements to be added. + */ + bool willBeSparseDenseArray(uintN requiredCapacity, uintN newElementsHint); + + JSBool makeDenseArraySlow(JSContext *cx); + + /* + * Arguments-specific getters and setters. + */ + + private: + /* + * We represent arguments objects using js_ArgumentsClass and + * js::StrictArgumentsClass. The two are structured similarly, and methods + * valid on arguments objects of one class are also generally valid on + * arguments objects of the other. + * + * Arguments objects of either class store arguments length in a slot: + * + * JSSLOT_ARGS_LENGTH - the number of actual arguments and a flag + * indicating whether arguments.length was + * overwritten. This slot is not used to represent + * arguments.length after that property has been + * assigned, even if the new value is integral: it's + * always the original length. + * + * Both arguments classes use a slot for storing arguments data: + * + * JSSLOT_ARGS_DATA - pointer to an ArgumentsData structure + * + * ArgumentsData for normal arguments stores the value of arguments.callee, + * as long as that property has not been overwritten. If arguments.callee + * is overwritten, the corresponding value in ArgumentsData is set to + * MagicValue(JS_ARGS_HOLE). Strict arguments do not store this value + * because arguments.callee is a poison pill for strict mode arguments. + * + * The ArgumentsData structure also stores argument values. For normal + * arguments this occurs after the corresponding function has returned, and + * for strict arguments this occurs when the arguments object is created, + * or sometimes shortly after (but not observably so). arguments[i] is + * stored in ArgumentsData.slots[i], accessible via getArgsElement() and + * setArgsElement(). Deletion of arguments[i] overwrites that slot with + * MagicValue(JS_ARGS_HOLE); subsequent redefinition of arguments[i] will + * use a normal property to store the value, ignoring the slot. + * + * Non-strict arguments have a private: + * + * private - the function's stack frame until the function + * returns, when it is replaced with null; also, + * JS_ARGUMENTS_OBJECT_ON_TRACE while on trace, if + * arguments was created on trace + * + * Technically strict arguments have a private, but it's always null. + * Conceptually it would be better to remove this oddity, but preserving it + * allows us to work with arguments objects of either kind more abstractly, + * so we keep it for now. + */ + static const uint32 JSSLOT_ARGS_DATA = 1; + + public: + /* Number of extra fixed arguments object slots besides JSSLOT_PRIVATE. */ + static const uint32 JSSLOT_ARGS_LENGTH = 0; + static const uint32 ARGS_CLASS_RESERVED_SLOTS = 2; + static const uint32 ARGS_FIRST_FREE_SLOT = ARGS_CLASS_RESERVED_SLOTS + 1; + + /* Lower-order bit stolen from the length slot. */ + static const uint32 ARGS_LENGTH_OVERRIDDEN_BIT = 0x1; + static const uint32 ARGS_PACKED_BITS_COUNT = 1; + + /* + * Set the initial length of the arguments, and mark it as not overridden. + */ + inline void setArgsLength(uint32 argc); + + /* + * Return the initial length of the arguments. This may differ from the + * current value of arguments.length! + */ + inline uint32 getArgsInitialLength() const; + + inline void setArgsLengthOverridden(); + inline bool isArgsLengthOverridden() const; + + inline js::ArgumentsData *getArgsData() const; + inline void setArgsData(js::ArgumentsData *data); + + inline const js::Value &getArgsCallee() const; + inline void setArgsCallee(const js::Value &callee); + + inline const js::Value &getArgsElement(uint32 i) const; + inline js::Value *getArgsElements() const; + inline js::Value *addressOfArgsElement(uint32 i); + inline void setArgsElement(uint32 i, const js::Value &v); + + private: + /* + * Reserved slot structure for Call objects: + * + * private - the stack frame corresponding to the Call object + * until js_PutCallObject or its on-trace analog + * is called, null thereafter + * JSSLOT_CALL_CALLEE - callee function for the stack frame, or null if + * the stack frame is for strict mode eval code + * JSSLOT_CALL_ARGUMENTS - arguments object for non-strict mode eval stack + * frames (not valid for strict mode eval frames) + */ + static const uint32 JSSLOT_CALL_CALLEE = 0; + static const uint32 JSSLOT_CALL_ARGUMENTS = 1; + + public: + /* Number of reserved slots. */ + static const uint32 CALL_RESERVED_SLOTS = 2; + + /* True if this is for a strict mode eval frame or for a function call. */ + inline bool callIsForEval() const; + + /* The stack frame for this Call object, if the frame is still active. */ + inline JSStackFrame *maybeCallObjStackFrame() const; + + /* + * The callee function if this Call object was created for a function + * invocation, or null if it was created for a strict mode eval frame. + */ + inline JSObject *getCallObjCallee() const; + inline JSFunction *getCallObjCalleeFunction() const; + inline void setCallObjCallee(JSObject *callee); + + inline const js::Value &getCallObjArguments() const; + inline void setCallObjArguments(const js::Value &v); + + /* Returns the formal argument at the given index. */ + inline const js::Value &callObjArg(uintN i) const; + inline js::Value &callObjArg(uintN i); + + /* Returns the variable at the given index. */ + inline const js::Value &callObjVar(uintN i) const; + inline js::Value &callObjVar(uintN i); + + /* + * Date-specific getters and setters. + */ + + static const uint32 JSSLOT_DATE_UTC_TIME = 0; + + /* + * Cached slots holding local properties of the date. + * These are undefined until the first actual lookup occurs + * and are reset to undefined whenever the date's time is modified. + */ + static const uint32 JSSLOT_DATE_COMPONENTS_START = 1; + + static const uint32 JSSLOT_DATE_LOCAL_TIME = 1; + static const uint32 JSSLOT_DATE_LOCAL_YEAR = 2; + static const uint32 JSSLOT_DATE_LOCAL_MONTH = 3; + static const uint32 JSSLOT_DATE_LOCAL_DATE = 4; + static const uint32 JSSLOT_DATE_LOCAL_DAY = 5; + static const uint32 JSSLOT_DATE_LOCAL_HOURS = 6; + static const uint32 JSSLOT_DATE_LOCAL_MINUTES = 7; + static const uint32 JSSLOT_DATE_LOCAL_SECONDS = 8; + + static const uint32 DATE_CLASS_RESERVED_SLOTS = 9; + + inline const js::Value &getDateUTCTime() const; + inline void setDateUTCTime(const js::Value &pthis); + + /* + * Function-specific getters and setters. + */ + + private: + friend struct JSFunction; + friend class js::mjit::Compiler; + + /* + * Flat closures with one or more upvars snapshot the upvars' values into a + * vector of js::Values referenced from this slot. + */ + static const uint32 JSSLOT_FLAT_CLOSURE_UPVARS = 0; + + /* + * Null closures set or initialized as methods have these slots. See the + * "method barrier" comments and methods. + */ + + static const uint32 JSSLOT_FUN_METHOD_ATOM = 0; + static const uint32 JSSLOT_FUN_METHOD_OBJ = 1; + + static const uint32 JSSLOT_BOUND_FUNCTION_THIS = 0; + static const uint32 JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 1; + + public: + static const uint32 FUN_CLASS_RESERVED_SLOTS = 2; + + inline JSFunction *getFunctionPrivate() const; + + inline js::Value *getFlatClosureUpvars() const; + inline js::Value getFlatClosureUpvar(uint32 i) const; + inline js::Value &getFlatClosureUpvar(uint32 i); + inline void setFlatClosureUpvars(js::Value *upvars); + + inline bool hasMethodObj(const JSObject& obj) const; + inline void setMethodObj(JSObject& obj); + + inline bool initBoundFunction(JSContext *cx, const js::Value &thisArg, + const js::Value *args, uintN argslen); + + inline JSObject *getBoundFunctionTarget() const; + inline const js::Value &getBoundFunctionThis() const; + inline const js::Value *getBoundFunctionArguments(uintN &argslen) const; + + /* + * RegExp-specific getters and setters. + */ + + private: + static const uint32 JSSLOT_REGEXP_LAST_INDEX = 0; + + public: + static const uint32 REGEXP_CLASS_RESERVED_SLOTS = 1; + + inline const js::Value &getRegExpLastIndex() const; + inline void setRegExpLastIndex(const js::Value &v); + inline void setRegExpLastIndex(jsdouble d); + inline void zeroRegExpLastIndex(); + + /* + * Iterator-specific getters and setters. + */ + + inline js::NativeIterator *getNativeIterator() const; + inline void setNativeIterator(js::NativeIterator *); + + /* + * Script-related getters. + */ + + inline JSScript *getScript() const; + + /* + * XML-related getters and setters. + */ + + /* + * Slots for XML-related classes are as follows: + * - js_NamespaceClass.base reserves the *_NAME_* and *_NAMESPACE_* slots. + * - js_QNameClass.base, js_AttributeNameClass, js_AnyNameClass reserve + * the *_NAME_* and *_QNAME_* slots. + * - Others (js_XMLClass, js_XMLFilterClass) don't reserve any slots. + */ + private: + static const uint32 JSSLOT_NAME_PREFIX = 0; // shared + static const uint32 JSSLOT_NAME_URI = 1; // shared + + static const uint32 JSSLOT_NAMESPACE_DECLARED = 2; + + static const uint32 JSSLOT_QNAME_LOCAL_NAME = 2; + + public: + static const uint32 NAMESPACE_CLASS_RESERVED_SLOTS = 3; + static const uint32 QNAME_CLASS_RESERVED_SLOTS = 3; + + inline JSLinearString *getNamePrefix() const; + inline jsval getNamePrefixVal() const; + inline void setNamePrefix(JSLinearString *prefix); + inline void clearNamePrefix(); + + inline JSLinearString *getNameURI() const; + inline jsval getNameURIVal() const; + inline void setNameURI(JSLinearString *uri); + + inline jsval getNamespaceDeclared() const; + inline void setNamespaceDeclared(jsval decl); + + inline JSLinearString *getQNameLocalName() const; + inline jsval getQNameLocalNameVal() const; + inline void setQNameLocalName(JSLinearString *name); + + /* + * Proxy-specific getters and setters. + */ + + inline js::JSProxyHandler *getProxyHandler() const; + inline const js::Value &getProxyPrivate() const; + inline void setProxyPrivate(const js::Value &priv); + inline const js::Value &getProxyExtra() const; + inline void setProxyExtra(const js::Value &extra); + + /* + * With object-specific getters and setters. + */ + inline JSObject *getWithThis() const; + inline void setWithThis(JSObject *thisp); + + /* + * Back to generic stuff. + */ + inline bool isCallable(); + + /* The map field is not initialized here and should be set separately. */ + void init(JSContext *cx, js::Class *aclasp, JSObject *proto, JSObject *parent, + void *priv, bool useHoles); + + inline void finish(JSContext *cx); + JS_ALWAYS_INLINE void finalize(JSContext *cx); + + /* + * Like init, but also initializes map. The catch: proto must be the result + * of a call to js_InitClass(...clasp, ...). + */ + inline bool initSharingEmptyShape(JSContext *cx, + js::Class *clasp, + JSObject *proto, + JSObject *parent, + void *priv, + /* gc::FinalizeKind */ unsigned kind); + + inline bool hasSlotsArray() const; + + /* This method can only be called when hasSlotsArray() returns true. */ + inline void freeSlotsArray(JSContext *cx); + + /* Free the slots array and copy slots that fit into the fixed array. */ + inline void revertToFixedSlots(JSContext *cx); + + inline bool hasProperty(JSContext *cx, jsid id, bool *foundp, uintN flags = 0); + + /* + * Allocate and free an object slot. Note that freeSlot is infallible: it + * returns true iff this is a dictionary-mode object and the freed slot was + * added to the freelist. + * + * FIXME: bug 593129 -- slot allocation should be done by object methods + * after calling object-parameter-free shape methods, avoiding coupling + * logic across the object vs. shape module wall. + */ + bool allocSlot(JSContext *cx, uint32 *slotp); + bool freeSlot(JSContext *cx, uint32 slot); + + public: + bool reportReadOnly(JSContext* cx, jsid id, uintN report = JSREPORT_ERROR); + bool reportNotConfigurable(JSContext* cx, jsid id, uintN report = JSREPORT_ERROR); + bool reportNotExtensible(JSContext *cx, uintN report = JSREPORT_ERROR); + + private: + js::Shape *getChildProperty(JSContext *cx, js::Shape *parent, js::Shape &child); + + /* + * Internal helper that adds a shape not yet mapped by this object. + * + * Notes: + * 1. getter and setter must be normalized based on flags (see jsscope.cpp). + * 2. !isExtensible() checking must be done by callers. + */ + const js::Shape *addPropertyInternal(JSContext *cx, jsid id, + js::PropertyOp getter, js::StrictPropertyOp setter, + uint32 slot, uintN attrs, + uintN flags, intN shortid, + js::Shape **spp); + + bool toDictionaryMode(JSContext *cx); + + public: + /* Add a property whose id is not yet in this scope. */ + const js::Shape *addProperty(JSContext *cx, jsid id, + js::PropertyOp getter, js::StrictPropertyOp setter, + uint32 slot, uintN attrs, + uintN flags, intN shortid); + + /* Add a data property whose id is not yet in this scope. */ + const js::Shape *addDataProperty(JSContext *cx, jsid id, uint32 slot, uintN attrs) { + JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); + return addProperty(cx, id, NULL, NULL, slot, attrs, 0, 0); + } + + /* Add or overwrite a property for id in this scope. */ + const js::Shape *putProperty(JSContext *cx, jsid id, + js::PropertyOp getter, js::StrictPropertyOp setter, + uint32 slot, uintN attrs, + uintN flags, intN shortid); + + /* Change the given property into a sibling with the same id in this scope. */ + const js::Shape *changeProperty(JSContext *cx, const js::Shape *shape, uintN attrs, uintN mask, + js::PropertyOp getter, js::StrictPropertyOp setter); + + /* Remove the property named by id from this object. */ + bool removeProperty(JSContext *cx, jsid id); + + /* Clear the scope, making it empty. */ + void clear(JSContext *cx); + + JSBool lookupProperty(JSContext *cx, jsid id, JSObject **objp, JSProperty **propp) { + js::LookupPropOp op = getOps()->lookupProperty; + return (op ? op : js_LookupProperty)(cx, this, id, objp, propp); + } + + JSBool defineProperty(JSContext *cx, jsid id, const js::Value &value, + js::PropertyOp getter = js::PropertyStub, + js::StrictPropertyOp setter = js::StrictPropertyStub, + uintN attrs = JSPROP_ENUMERATE) { + js::DefinePropOp op = getOps()->defineProperty; + return (op ? op : js_DefineProperty)(cx, this, id, &value, getter, setter, attrs); + } + + JSBool getProperty(JSContext *cx, JSObject *receiver, jsid id, js::Value *vp) { + js::PropertyIdOp op = getOps()->getProperty; + return (op ? op : (js::PropertyIdOp)js_GetProperty)(cx, this, receiver, id, vp); + } + + JSBool getProperty(JSContext *cx, jsid id, js::Value *vp) { + return getProperty(cx, this, id, vp); + } + + JSBool setProperty(JSContext *cx, jsid id, js::Value *vp, JSBool strict) { + js::StrictPropertyIdOp op = getOps()->setProperty; + return (op ? op : js_SetProperty)(cx, this, id, vp, strict); + } + + JSBool getAttributes(JSContext *cx, jsid id, uintN *attrsp) { + js::AttributesOp op = getOps()->getAttributes; + return (op ? op : js_GetAttributes)(cx, this, id, attrsp); + } + + JSBool setAttributes(JSContext *cx, jsid id, uintN *attrsp) { + js::AttributesOp op = getOps()->setAttributes; + return (op ? op : js_SetAttributes)(cx, this, id, attrsp); + } + + JSBool deleteProperty(JSContext *cx, jsid id, js::Value *rval, JSBool strict) { + js::DeleteIdOp op = getOps()->deleteProperty; + return (op ? op : js_DeleteProperty)(cx, this, id, rval, strict); + } + + JSBool enumerate(JSContext *cx, JSIterateOp iterop, js::Value *statep, jsid *idp) { + js::NewEnumerateOp op = getOps()->enumerate; + return (op ? op : js_Enumerate)(cx, this, iterop, statep, idp); + } + + JSType typeOf(JSContext *cx) { + js::TypeOfOp op = getOps()->typeOf; + return (op ? op : js_TypeOf)(cx, this); + } + + /* These four are time-optimized to avoid stub calls. */ + JSObject *thisObject(JSContext *cx) { + JSObjectOp op = getOps()->thisObject; + return op ? op(cx, this) : this; + } + + static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp); + + inline JSCompartment *getCompartment() const; + + inline JSObject *getThrowTypeError() const; + + JS_FRIEND_API(JSObject *) clone(JSContext *cx, JSObject *proto, JSObject *parent); + JS_FRIEND_API(bool) copyPropertiesFrom(JSContext *cx, JSObject *obj); + bool swap(JSContext *cx, JSObject *other); + + const js::Shape *defineBlockVariable(JSContext *cx, jsid id, intN index); + + inline bool canHaveMethodBarrier() const; + + inline bool isArguments() const; + inline bool isNormalArguments() const; + inline bool isStrictArguments() const; + inline bool isArray() const; + inline bool isDenseArray() const; + inline bool isSlowArray() const; + inline bool isNumber() const; + inline bool isBoolean() const; + inline bool isString() const; + inline bool isPrimitive() const; + inline bool isDate() const; + inline bool isFunction() const; + inline bool isObject() const; + inline bool isWith() const; + inline bool isBlock() const; + inline bool isStaticBlock() const; + inline bool isClonedBlock() const; + inline bool isCall() const; + inline bool isRegExp() const; + inline bool isScript() const; + inline bool isXML() const; + inline bool isXMLId() const; + inline bool isNamespace() const; + inline bool isQName() const; + + inline bool isProxy() const; + inline bool isObjectProxy() const; + inline bool isFunctionProxy() const; + + JS_FRIEND_API(bool) isWrapper() const; + JS_FRIEND_API(JSObject *) unwrap(uintN *flagsp = NULL); + + inline void initArrayClass(); +}; + +/* Check alignment for any fixed slots allocated after the object. */ +JS_STATIC_ASSERT(sizeof(JSObject) % sizeof(js::Value) == 0); + +inline js::Value* +JSObject::fixedSlots() const { + return (js::Value*) (jsuword(this) + sizeof(JSObject)); +} + +inline bool +JSObject::hasSlotsArray() const { return this->slots != fixedSlots(); } + +/* static */ inline size_t +JSObject::getFixedSlotOffset(size_t slot) { + return sizeof(JSObject) + (slot * sizeof(js::Value)); +} + +struct JSObject_Slots2 : JSObject { js::Value fslots[2]; }; +struct JSObject_Slots4 : JSObject { js::Value fslots[4]; }; +struct JSObject_Slots8 : JSObject { js::Value fslots[8]; }; +struct JSObject_Slots12 : JSObject { js::Value fslots[12]; }; +struct JSObject_Slots16 : JSObject { js::Value fslots[16]; }; + +#define JSSLOT_FREE(clasp) JSCLASS_RESERVED_SLOTS(clasp) + +#ifdef JS_THREADSAFE + +/* + * The GC runs only when all threads except the one on which the GC is active + * are suspended at GC-safe points, so calling obj->getSlot() from the GC's + * thread is safe when rt->gcRunning is set. See jsgc.cpp for details. + */ +#define THREAD_IS_RUNNING_GC(rt, thread) \ + ((rt)->gcRunning && (rt)->gcThread == (thread)) + +#define CX_THREAD_IS_RUNNING_GC(cx) \ + THREAD_IS_RUNNING_GC((cx)->runtime, (cx)->thread) + +#endif /* JS_THREADSAFE */ + +inline void +OBJ_TO_INNER_OBJECT(JSContext *cx, JSObject *&obj) +{ + if (JSObjectOp op = obj->getClass()->ext.innerObject) + obj = op(cx, obj); +} + +inline void +OBJ_TO_OUTER_OBJECT(JSContext *cx, JSObject *&obj) +{ + if (JSObjectOp op = obj->getClass()->ext.outerObject) + obj = op(cx, obj); +} + +class JSValueArray { + public: + jsval *array; + size_t length; + + JSValueArray(jsval *v, size_t c) : array(v), length(c) {} +}; + +class ValueArray { + public: + js::Value *array; + size_t length; + + ValueArray(js::Value *v, size_t c) : array(v), length(c) {} +}; + +extern js::Class js_ObjectClass; +extern js::Class js_WithClass; +extern js::Class js_BlockClass; + +inline bool JSObject::isObject() const { return getClass() == &js_ObjectClass; } +inline bool JSObject::isWith() const { return getClass() == &js_WithClass; } +inline bool JSObject::isBlock() const { return getClass() == &js_BlockClass; } + +/* + * Block scope object macros. The slots reserved by js_BlockClass are: + * + * private JSStackFrame * active frame pointer or null + * JSSLOT_BLOCK_DEPTH int depth of block slots in frame + * + * After JSSLOT_BLOCK_DEPTH come one or more slots for the block locals. + * + * A With object is like a Block object, in that both have one reserved slot + * telling the stack depth of the relevant slots (the slot whose value is the + * object named in the with statement, the slots containing the block's local + * variables); and both have a private slot referring to the JSStackFrame in + * whose activation they were created (or null if the with or block object + * outlives the frame). + */ +static const uint32 JSSLOT_BLOCK_DEPTH = 0; +static const uint32 JSSLOT_BLOCK_FIRST_FREE_SLOT = JSSLOT_BLOCK_DEPTH + 1; + +inline bool +JSObject::isStaticBlock() const +{ + return isBlock() && !getProto(); +} + +inline bool +JSObject::isClonedBlock() const +{ + return isBlock() && !!getProto(); +} + +static const uint32 JSSLOT_WITH_THIS = 1; + +#define OBJ_BLOCK_COUNT(cx,obj) \ + (obj)->propertyCount() +#define OBJ_BLOCK_DEPTH(cx,obj) \ + (obj)->getSlot(JSSLOT_BLOCK_DEPTH).toInt32() +#define OBJ_SET_BLOCK_DEPTH(cx,obj,depth) \ + (obj)->setSlot(JSSLOT_BLOCK_DEPTH, Value(Int32Value(depth))) + +/* + * To make sure this slot is well-defined, always call js_NewWithObject to + * create a With object, don't call js_NewObject directly. When creating a + * With object that does not correspond to a stack slot, pass -1 for depth. + * + * When popping the stack across this object's "with" statement, client code + * must call withobj->setPrivate(NULL). + */ +extern JS_REQUIRES_STACK JSObject * +js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth); + +inline JSObject * +js_UnwrapWithObject(JSContext *cx, JSObject *withobj) +{ + JS_ASSERT(withobj->getClass() == &js_WithClass); + return withobj->getProto(); +} + +/* + * Create a new block scope object not linked to any proto or parent object. + * Blocks are created by the compiler to reify let blocks and comprehensions. + * Only when dynamic scope is captured do they need to be cloned and spliced + * into an active scope chain. + */ +extern JSObject * +js_NewBlockObject(JSContext *cx); + +extern JSObject * +js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp); + +extern JS_REQUIRES_STACK JSBool +js_PutBlockObject(JSContext *cx, JSBool normalUnwind); + +JSBool +js_XDRBlockObject(JSXDRState *xdr, JSObject **objp); + +struct JSSharpObjectMap { + jsrefcount depth; + jsatomid sharpgen; + JSHashTable *table; +}; + +#define SHARP_BIT ((jsatomid) 1) +#define BUSY_BIT ((jsatomid) 2) +#define SHARP_ID_SHIFT 2 +#define IS_SHARP(he) (uintptr_t((he)->value) & SHARP_BIT) +#define MAKE_SHARP(he) ((he)->value = (void *) (uintptr_t((he)->value)|SHARP_BIT)) +#define IS_BUSY(he) (uintptr_t((he)->value) & BUSY_BIT) +#define MAKE_BUSY(he) ((he)->value = (void *) (uintptr_t((he)->value)|BUSY_BIT)) +#define CLEAR_BUSY(he) ((he)->value = (void *) (uintptr_t((he)->value)&~BUSY_BIT)) + +extern JSHashEntry * +js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, + jschar **sp); + +extern void +js_LeaveSharpObject(JSContext *cx, JSIdArray **idap); + +/* + * Mark objects stored in map if GC happens between js_EnterSharpObject + * and js_LeaveSharpObject. GC calls this when map->depth > 0. + */ +extern void +js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map); + +extern JSBool +js_HasOwnPropertyHelper(JSContext *cx, js::LookupPropOp lookup, uintN argc, + js::Value *vp); + +extern JSBool +js_HasOwnProperty(JSContext *cx, js::LookupPropOp lookup, JSObject *obj, jsid id, + JSObject **objp, JSProperty **propp); + +extern JSBool +js_NewPropertyDescriptorObject(JSContext *cx, jsid id, uintN attrs, + const js::Value &getter, const js::Value &setter, + const js::Value &value, js::Value *vp); + +extern JSBool +js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); + +#ifdef OLD_GETTER_SETTER_METHODS +JS_FRIEND_API(JSBool) js_obj_defineGetter(JSContext *cx, uintN argc, js::Value *vp); +JS_FRIEND_API(JSBool) js_obj_defineSetter(JSContext *cx, uintN argc, js::Value *vp); +#endif + +extern JSObject * +js_InitObjectClass(JSContext *cx, JSObject *obj); + +namespace js { +JSObject * +DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom, + JSObject *protoProto, Class *clasp, + Native constructor, uintN nargs, + JSPropertySpec *ps, JSFunctionSpec *fs, + JSPropertySpec *static_ps, JSFunctionSpec *static_fs); +} + +extern JSObject * +js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, + js::Class *clasp, js::Native constructor, uintN nargs, + JSPropertySpec *ps, JSFunctionSpec *fs, + JSPropertySpec *static_ps, JSFunctionSpec *static_fs); + +/* + * Select Object.prototype method names shared between jsapi.cpp and jsobj.cpp. + */ +extern const char js_watch_str[]; +extern const char js_unwatch_str[]; +extern const char js_hasOwnProperty_str[]; +extern const char js_isPrototypeOf_str[]; +extern const char js_propertyIsEnumerable_str[]; + +#ifdef OLD_GETTER_SETTER_METHODS +extern const char js_defineGetter_str[]; +extern const char js_defineSetter_str[]; +extern const char js_lookupGetter_str[]; +extern const char js_lookupSetter_str[]; +#endif + +extern JSBool +js_PopulateObject(JSContext *cx, JSObject *newborn, JSObject *props); + +/* + * Fast access to immutable standard objects (constructors and prototypes). + */ +extern JSBool +js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, + JSObject **objp); + +extern JSBool +js_SetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, + JSObject *cobj, JSObject *prototype); + +/* + * If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is + * JSProto_Null, clasp must non-null. + */ +extern JSBool +js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey key, + js::Value *vp, js::Class *clasp = NULL); + +extern JSObject * +js_ConstructObject(JSContext *cx, js::Class *clasp, JSObject *proto, + JSObject *parent, uintN argc, js::Value *argv); + +// Specialized call for constructing |this| with a known function callee, +// and a known prototype. +extern JSObject * +js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *proto); + +// Specialized call for constructing |this| with a known function callee. +extern JSObject * +js_CreateThisForFunction(JSContext *cx, JSObject *callee); + +// Generic call for constructing |this|. +extern JSObject * +js_CreateThis(JSContext *cx, JSObject *callee); + +extern jsid +js_CheckForStringIndex(jsid id); + +/* + * js_PurgeScopeChain does nothing if obj is not itself a prototype or parent + * scope, else it reshapes the scope and prototype chains it links. It calls + * js_PurgeScopeChainHelper, which asserts that obj is flagged as a delegate + * (i.e., obj has ever been on a prototype or parent chain). + */ +extern void +js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id); + +inline void +js_PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id) +{ + if (obj->isDelegate()) + js_PurgeScopeChainHelper(cx, obj, id); +} + +/* + * Find or create a property named by id in obj's scope, with the given getter + * and setter, slot, attributes, and other members. + */ +extern const js::Shape * +js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id, + js::PropertyOp getter, js::StrictPropertyOp setter, uint32 slot, + uintN attrs, uintN flags, intN shortid); + +/* + * Change shape to have the given attrs, getter, and setter in scope, morphing + * it into a potentially new js::Shape. Return a pointer to the changed + * or identical property. + */ +extern const js::Shape * +js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj, + const js::Shape *shape, uintN attrs, uintN mask, + js::PropertyOp getter, js::StrictPropertyOp setter); + +extern JSBool +js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, + const js::Value &descriptor, JSBool *bp); + +/* + * Flags for the defineHow parameter of js_DefineNativeProperty. + */ +const uintN JSDNP_CACHE_RESULT = 1; /* an interpreter call from JSOP_INITPROP */ +const uintN JSDNP_DONT_PURGE = 2; /* suppress js_PurgeScopeChain */ +const uintN JSDNP_SET_METHOD = 4; /* js_{DefineNativeProperty,SetPropertyHelper} + must pass the js::Shape::METHOD + flag on to JSObject::{add,put}Property */ +const uintN JSDNP_UNQUALIFIED = 8; /* Unqualified property set. Only used in + the defineHow argument of + js_SetPropertyHelper. */ + +/* + * On error, return false. On success, if propp is non-null, return true with + * obj locked and with a held property in *propp; if propp is null, return true + * but release obj's lock first. + */ +extern JSBool +js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value &value, + js::PropertyOp getter, js::StrictPropertyOp setter, uintN attrs, + uintN flags, intN shortid, JSProperty **propp, + uintN defineHow = 0); + +/* + * Specialized subroutine that allows caller to preset JSRESOLVE_* flags and + * returns the index along the prototype chain in which *propp was found, or + * the last index if not found, or -1 on error. + */ +extern int +js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSObject **objp, JSProperty **propp); + + +extern JS_FRIEND_DATA(js::Class) js_CallClass; +extern JS_FRIEND_DATA(js::Class) js_DeclEnvClass; + +namespace js { + +/* + * We cache name lookup results only for the global object or for native + * non-global objects without prototype or with prototype that never mutates, + * see bug 462734 and bug 487039. + */ +static inline bool +IsCacheableNonGlobalScope(JSObject *obj) +{ + JS_ASSERT(obj->getParent()); + + js::Class *clasp = obj->getClass(); + bool cacheable = (clasp == &js_CallClass || + clasp == &js_BlockClass || + clasp == &js_DeclEnvClass); + + JS_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty); + return cacheable; +} + +} + +/* + * If cacheResult is false, return JS_NO_PROP_CACHE_FILL on success. + */ +extern js::PropertyCacheEntry * +js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult, + JSObject **objp, JSObject **pobjp, JSProperty **propp); + +/* + * Return the index along the scope chain in which id was found, or the last + * index if not found, or -1 on error. + */ +extern JS_FRIEND_API(JSBool) +js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp, + JSProperty **propp); + +extern JS_REQUIRES_STACK JSObject * +js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id); + +extern JSObject * +js_FindVariableScope(JSContext *cx, JSFunction **funp); + +/* + * JSGET_CACHE_RESULT is the analogue of JSDNP_CACHE_RESULT for js_GetMethod. + * + * JSGET_METHOD_BARRIER (the default, hence 0 but provided for documentation) + * enables a read barrier that preserves standard function object semantics (by + * default we assume our caller won't leak a joined callee to script, where it + * would create hazardous mutable object sharing as well as observable identity + * according to == and ===. + * + * JSGET_NO_METHOD_BARRIER avoids the performance overhead of the method read + * barrier, which is not needed when invoking a lambda that otherwise does not + * leak its callee reference (via arguments.callee or its name). + */ +const uintN JSGET_CACHE_RESULT = 1; // from a caching interpreter opcode +const uintN JSGET_METHOD_BARRIER = 0; // get can leak joined function object +const uintN JSGET_NO_METHOD_BARRIER = 2; // call to joined function can't leak + +/* + * NB: js_NativeGet and js_NativeSet are called with the scope containing shape + * (pobj's scope for Get, obj's for Set) locked, and on successful return, that + * scope is again locked. But on failure, both functions return false with the + * scope containing shape unlocked. + */ +extern JSBool +js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const js::Shape *shape, uintN getHow, + js::Value *vp); + +extern JSBool +js_NativeSet(JSContext *cx, JSObject *obj, const js::Shape *shape, bool added, + bool strict, js::Value *vp); + +extern JSBool +js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uint32 getHow, js::Value *vp); + +extern bool +js_GetPropertyHelperWithShape(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, + uint32 getHow, js::Value *vp, + const js::Shape **shapeOut, JSObject **holderOut); + +extern JSBool +js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); + +extern JSBool +js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, js::Value *vp); + +/* + * Check whether it is OK to assign an undeclared property with name + * propname of the global object in the current script on cx. Reports + * an error if one needs to be reported (in particular in all cases + * when it returns false). + */ +extern JS_FRIEND_API(bool) +js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname); + +extern JSBool +js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, + js::Value *vp, JSBool strict); + +/* + * Change attributes for the given native property. The caller must ensure + * that obj is locked and this function always unlocks obj on return. + */ +extern JSBool +js_SetNativeAttributes(JSContext *cx, JSObject *obj, js::Shape *shape, + uintN attrs); + +namespace js { + +/* + * If obj has a data property methodid which is a function object for the given + * native, return that function object. Otherwise, return NULL. + */ +extern JSObject * +HasNativeMethod(JSObject *obj, jsid methodid, Native native); + +extern bool +DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp); + +extern JSBool +CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, + js::Value *vp, uintN *attrsp); + +} /* namespace js */ + +extern bool +js_IsDelegate(JSContext *cx, JSObject *obj, const js::Value &v); + +/* + * If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is + * JSProto_Null, clasp must non-null. + */ +extern JS_FRIEND_API(JSBool) +js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, + JSObject **protop, js::Class *clasp = NULL); + +extern JSBool +js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, + uintN attrs); + +/* + * Wrap boolean, number or string as Boolean, Number or String object. + * *vp must not be an object, null or undefined. + */ +extern JSBool +js_PrimitiveToObject(JSContext *cx, js::Value *vp); + +/* + * v and vp may alias. On successful return, vp->isObjectOrNull(). If vp is not + * rooted, the caller must root vp before the next possible GC. + */ +extern JSBool +js_ValueToObjectOrNull(JSContext *cx, const js::Value &v, JSObject **objp); + +namespace js { + +/* + * Invokes the ES5 ToObject algorithm on *vp, writing back the object to vp. + * If *vp might already be an object, use ToObject. + */ +extern JSObject * +ToObjectSlow(JSContext *cx, js::Value *vp); + +JS_ALWAYS_INLINE JSObject * +ToObject(JSContext *cx, js::Value *vp) +{ + if (vp->isObject()) + return &vp->toObject(); + return ToObjectSlow(cx, vp); +} + +} + +/* + * v and vp may alias. On successful return, vp->isObject(). If vp is not + * rooted, the caller must root vp before the next possible GC. + */ +extern JSObject * +js_ValueToNonNullObject(JSContext *cx, const js::Value &v); + +extern JSBool +js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, js::Value *rval); + +extern JSBool +js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom, + uintN argc, js::Value *argv, js::Value *rval); + +extern JSBool +js_XDRObject(JSXDRState *xdr, JSObject **objp); + +extern void +js_TraceObject(JSTracer *trc, JSObject *obj); + +extern void +js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize); + +extern void +js_ClearNative(JSContext *cx, JSObject *obj); + +extern bool +js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, js::Value *vp); + +extern bool +js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, const js::Value &v); + +extern JSBool +js_CheckPrincipalsAccess(JSContext *cx, JSObject *scopeobj, + JSPrincipals *principals, JSAtom *caller); + +/* For CSP -- checks if eval() and friends are allowed to run. */ +extern JSBool +js_CheckContentSecurityPolicy(JSContext *cx, JSObject *scopeObj); + +/* NB: Infallible. */ +extern const char * +js_ComputeFilename(JSContext *cx, JSStackFrame *caller, + JSPrincipals *principals, uintN *linenop); + +extern JSBool +js_ReportGetterOnlyAssignment(JSContext *cx); + +extern JS_FRIEND_API(JSBool) +js_GetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp); + +#ifdef DEBUG +JS_FRIEND_API(void) js_DumpChars(const jschar *s, size_t n); +JS_FRIEND_API(void) js_DumpString(JSString *str); +JS_FRIEND_API(void) js_DumpAtom(JSAtom *atom); +JS_FRIEND_API(void) js_DumpObject(JSObject *obj); +JS_FRIEND_API(void) js_DumpValue(const js::Value &val); +JS_FRIEND_API(void) js_DumpId(jsid id); +JS_FRIEND_API(void) js_DumpStackFrame(JSContext *cx, JSStackFrame *start = NULL); +#endif + +extern uintN +js_InferFlags(JSContext *cx, uintN defaultFlags); + +/* Object constructor native. Exposed only so the JIT can know its address. */ +JSBool +js_Object(JSContext *cx, uintN argc, js::Value *vp); + + +namespace js { + +extern bool +SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles); + +extern JSString * +obj_toStringHelper(JSContext *cx, JSObject *obj); + +enum EvalType { INDIRECT_EVAL, DIRECT_EVAL }; + +/* + * Common code implementing direct and indirect eval. + * + * Evaluate vp[2], if it is a string, in the context of the given calling + * frame, with the provided scope chain, with the semantics of either a direct + * or indirect eval (see ES5 10.4.2). If this is an indirect eval, scopeobj + * must be a global object. + * + * On success, store the completion value in *vp and return true. + */ +extern bool +EvalKernel(JSContext *cx, uintN argc, js::Value *vp, EvalType evalType, JSStackFrame *caller, + JSObject *scopeobj); + +extern JS_FRIEND_API(bool) +IsBuiltinEvalFunction(JSFunction *fun); + +} + +#ifdef JS_OBJ_UNDEFD_MOZALLOC_WRAPPERS +# include "mozilla/mozalloc_macro_wrappers.h" +#endif + +#endif /* jsobj_h___ */ diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h new file mode 100644 index 0000000..d60557c --- /dev/null +++ b/js/src/jsobjinlines.h @@ -0,0 +1,1222 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsobjinlines_h___ +#define jsobjinlines_h___ + +#include +#include "jsdate.h" +#include "jsfun.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsobj.h" +#include "jsprobes.h" +#include "jspropertytree.h" +#include "jsproxy.h" +#include "jsscope.h" +#include "jsstaticcheck.h" +#include "jsxml.h" + +/* Headers included for inline implementations used by this header. */ +#include "jsbool.h" +#include "jscntxt.h" +#include "jsnum.h" +#include "jsscopeinlines.h" +#include "jsstr.h" + +#include "jsfuninlines.h" +#include "jsgcinlines.h" +#include "jsprobes.h" + +inline bool +JSObject::preventExtensions(JSContext *cx, js::AutoIdVector *props) +{ + JS_ASSERT(isExtensible()); + + if (js::FixOp fix = getOps()->fix) { + bool success; + if (!fix(cx, this, &success, props)) + return false; + if (!success) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CHANGE_EXTENSIBILITY); + return false; + } + } else { + if (!GetPropertyNames(cx, this, JSITER_HIDDEN | JSITER_OWNONLY, props)) + return false; + } + + if (isNative()) + extensibleShapeChange(cx); + + flags |= NOT_EXTENSIBLE; + return true; +} + +inline bool +JSObject::brand(JSContext *cx) +{ + JS_ASSERT(!generic()); + JS_ASSERT(!branded()); + JS_ASSERT(isNative()); + generateOwnShape(cx); + if (js_IsPropertyCacheDisabled(cx)) // check for rt->shapeGen overflow + return false; + flags |= BRANDED; + return true; +} + +inline bool +JSObject::unbrand(JSContext *cx) +{ + JS_ASSERT(isNative()); + if (branded()) { + generateOwnShape(cx); + if (js_IsPropertyCacheDisabled(cx)) // check for rt->shapeGen overflow + return false; + flags &= ~BRANDED; + } + setGeneric(); + return true; +} + +inline void +JSObject::syncSpecialEquality() +{ + if (clasp->ext.equality) + flags |= JSObject::HAS_EQUALITY; +} + +inline void +JSObject::finalize(JSContext *cx) +{ + /* Cope with stillborn objects that have no map. */ + if (!map) + return; + + /* Finalize obj first, in case it needs map and slots. */ + js::Class *clasp = getClass(); + if (clasp->finalize) + clasp->finalize(cx, this); + + js::Probes::finalizeObject(this); + + finish(cx); +} + +/* + * Property read barrier for deferred cloning of compiler-created function + * objects optimized as typically non-escaping, ad-hoc methods in obj. + */ +inline const js::Shape * +JSObject::methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp) +{ + JS_ASSERT(canHaveMethodBarrier()); + JS_ASSERT(hasMethodBarrier()); + JS_ASSERT(nativeContains(shape)); + JS_ASSERT(shape.isMethod()); + JS_ASSERT(&shape.methodObject() == &vp->toObject()); + JS_ASSERT(shape.writable()); + JS_ASSERT(shape.slot != SHAPE_INVALID_SLOT); + JS_ASSERT(shape.hasDefaultSetter() || shape.setterOp() == js_watch_set); + JS_ASSERT(!isGlobal()); /* i.e. we are not changing the global shape */ + + JSObject *funobj = &vp->toObject(); + JSFunction *fun = funobj->getFunctionPrivate(); + JS_ASSERT(fun == funobj); + JS_ASSERT(FUN_NULL_CLOSURE(fun)); + + funobj = CloneFunctionObject(cx, fun, funobj->getParent()); + if (!funobj) + return NULL; + funobj->setMethodObj(*this); + + /* + * Replace the method property with an ordinary data property. This is + * equivalent to this->setProperty(cx, shape.id, vp) except that any + * watchpoint on the property is not triggered. + */ + uint32 slot = shape.slot; + const js::Shape *newshape = methodShapeChange(cx, shape); + if (!newshape) + return NULL; + JS_ASSERT(!newshape->isMethod()); + JS_ASSERT(newshape->slot == slot); + vp->setObject(*funobj); + nativeSetSlot(slot, *vp); + +#ifdef DEBUG + if (cx->runtime->functionMeterFilename) { + JS_FUNCTION_METER(cx, mreadbarrier); + + typedef JSRuntime::FunctionCountMap HM; + HM &h = cx->runtime->methodReadBarrierCountMap; + HM::AddPtr p = h.lookupForAdd(fun); + if (!p) { + h.add(p, fun, 1); + } else { + JS_ASSERT(p->key == fun); + ++p->value; + } + } +#endif + return newshape; +} + +static JS_ALWAYS_INLINE bool +ChangesMethodValue(const js::Value &prev, const js::Value &v) +{ + JSObject *prevObj; + return prev.isObject() && (prevObj = &prev.toObject())->isFunction() && + (!v.isObject() || &v.toObject() != prevObj); +} + +inline const js::Shape * +JSObject::methodWriteBarrier(JSContext *cx, const js::Shape &shape, const js::Value &v) +{ + if (brandedOrHasMethodBarrier() && shape.slot != SHAPE_INVALID_SLOT) { + const js::Value &prev = nativeGetSlot(shape.slot); + + if (ChangesMethodValue(prev, v)) { + JS_FUNCTION_METER(cx, mwritebarrier); + return methodShapeChange(cx, shape); + } + } + return &shape; +} + +inline bool +JSObject::methodWriteBarrier(JSContext *cx, uint32 slot, const js::Value &v) +{ + if (brandedOrHasMethodBarrier()) { + const js::Value &prev = nativeGetSlot(slot); + + if (ChangesMethodValue(prev, v)) { + JS_FUNCTION_METER(cx, mwslotbarrier); + return methodShapeChange(cx, slot); + } + } + return true; +} + +inline bool +JSObject::ensureClassReservedSlots(JSContext *cx) +{ + return !nativeEmpty() || ensureClassReservedSlotsForEmptyObject(cx); +} + +inline js::Value +JSObject::getReservedSlot(uintN index) const +{ + return (index < numSlots()) ? getSlot(index) : js::UndefinedValue(); +} + +inline bool +JSObject::canHaveMethodBarrier() const +{ + return isObject() || isFunction() || isPrimitive() || isDate(); +} + +inline bool +JSObject::isPrimitive() const +{ + return isNumber() || isString() || isBoolean(); +} + +inline const js::Value & +JSObject::getPrimitiveThis() const +{ + JS_ASSERT(isPrimitive()); + return getSlot(JSSLOT_PRIMITIVE_THIS); +} + +inline void +JSObject::setPrimitiveThis(const js::Value &pthis) +{ + JS_ASSERT(isPrimitive()); + setSlot(JSSLOT_PRIMITIVE_THIS, pthis); +} + +inline /* gc::FinalizeKind */ unsigned +JSObject::finalizeKind() const +{ + return js::gc::FinalizeKind(arena()->header()->thingKind); +} + +inline size_t +JSObject::numFixedSlots() const +{ + if (isFunction()) + return JSObject::FUN_CLASS_RESERVED_SLOTS; + if (!hasSlotsArray()) + return capacity; + return js::gc::GetGCKindSlots(js::gc::FinalizeKind(finalizeKind())); +} + +inline size_t +JSObject::slotsAndStructSize(uint32 nslots) const +{ + bool isFun = isFunction() && this == (JSObject*) getPrivate(); + + int ndslots = hasSlotsArray() ? nslots : 0; + int nfslots = isFun ? 0 : numFixedSlots(); + + return sizeof(js::Value) * (ndslots + nfslots) + + isFun ? sizeof(JSFunction) : sizeof(JSObject); +} + +inline uint32 +JSObject::getArrayLength() const +{ + JS_ASSERT(isArray()); + return (uint32)(size_t) getPrivate(); +} + +inline void +JSObject::setArrayLength(uint32 length) +{ + JS_ASSERT(isArray()); + setPrivate((void*) length); +} + +inline uint32 +JSObject::getDenseArrayCapacity() +{ + JS_ASSERT(isDenseArray()); + return numSlots(); +} + +inline js::Value* +JSObject::getDenseArrayElements() +{ + JS_ASSERT(isDenseArray()); + return getSlots(); +} + +inline const js::Value & +JSObject::getDenseArrayElement(uintN idx) +{ + JS_ASSERT(isDenseArray()); + return getSlot(idx); +} + +inline js::Value * +JSObject::addressOfDenseArrayElement(uintN idx) +{ + JS_ASSERT(isDenseArray()); + return &getSlotRef(idx); +} + +inline void +JSObject::setDenseArrayElement(uintN idx, const js::Value &val) +{ + JS_ASSERT(isDenseArray()); + setSlot(idx, val); +} + +inline void +JSObject::shrinkDenseArrayElements(JSContext *cx, uintN cap) +{ + JS_ASSERT(isDenseArray()); + shrinkSlots(cx, cap); +} + +inline void +JSObject::setArgsLength(uint32 argc) +{ + JS_ASSERT(isArguments()); + JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX); + JS_ASSERT(UINT32_MAX > (uint64(argc) << ARGS_PACKED_BITS_COUNT)); + getSlotRef(JSSLOT_ARGS_LENGTH).setInt32(argc << ARGS_PACKED_BITS_COUNT); + JS_ASSERT(!isArgsLengthOverridden()); +} + +inline uint32 +JSObject::getArgsInitialLength() const +{ + JS_ASSERT(isArguments()); + uint32 argc = uint32(getSlot(JSSLOT_ARGS_LENGTH).toInt32()) >> ARGS_PACKED_BITS_COUNT; + JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX); + return argc; +} + +inline void +JSObject::setArgsLengthOverridden() +{ + JS_ASSERT(isArguments()); + getSlotRef(JSSLOT_ARGS_LENGTH).getInt32Ref() |= ARGS_LENGTH_OVERRIDDEN_BIT; +} + +inline bool +JSObject::isArgsLengthOverridden() const +{ + JS_ASSERT(isArguments()); + const js::Value &v = getSlot(JSSLOT_ARGS_LENGTH); + return v.toInt32() & ARGS_LENGTH_OVERRIDDEN_BIT; +} + +inline js::ArgumentsData * +JSObject::getArgsData() const +{ + JS_ASSERT(isArguments()); + return (js::ArgumentsData *) getSlot(JSSLOT_ARGS_DATA).toPrivate(); +} + +inline void +JSObject::setArgsData(js::ArgumentsData *data) +{ + JS_ASSERT(isArguments()); + getSlotRef(JSSLOT_ARGS_DATA).setPrivate(data); +} + +inline const js::Value & +JSObject::getArgsCallee() const +{ + return getArgsData()->callee; +} + +inline void +JSObject::setArgsCallee(const js::Value &callee) +{ + getArgsData()->callee = callee; +} + +inline const js::Value & +JSObject::getArgsElement(uint32 i) const +{ + JS_ASSERT(isArguments()); + JS_ASSERT(i < getArgsInitialLength()); + return getArgsData()->slots[i]; +} + +inline js::Value * +JSObject::getArgsElements() const +{ + JS_ASSERT(isArguments()); + return getArgsData()->slots; +} + +inline js::Value * +JSObject::addressOfArgsElement(uint32 i) +{ + JS_ASSERT(isArguments()); + JS_ASSERT(i < getArgsInitialLength()); + return &getArgsData()->slots[i]; +} + +inline void +JSObject::setArgsElement(uint32 i, const js::Value &v) +{ + JS_ASSERT(isArguments()); + JS_ASSERT(i < getArgsInitialLength()); + getArgsData()->slots[i] = v; +} + +inline bool +JSObject::callIsForEval() const +{ + JS_ASSERT(isCall()); + JS_ASSERT(getSlot(JSSLOT_CALL_CALLEE).isObjectOrNull()); + JS_ASSERT_IF(getSlot(JSSLOT_CALL_CALLEE).isObject(), + getSlot(JSSLOT_CALL_CALLEE).toObject().isFunction()); + return getSlot(JSSLOT_CALL_CALLEE).isNull(); +} + +inline JSStackFrame * +JSObject::maybeCallObjStackFrame() const +{ + JS_ASSERT(isCall()); + return reinterpret_cast(getPrivate()); +} + +inline void +JSObject::setCallObjCallee(JSObject *callee) +{ + JS_ASSERT(isCall()); + JS_ASSERT_IF(callee, callee->isFunction()); + return getSlotRef(JSSLOT_CALL_CALLEE).setObjectOrNull(callee); +} + +inline JSObject * +JSObject::getCallObjCallee() const +{ + JS_ASSERT(isCall()); + return getSlot(JSSLOT_CALL_CALLEE).toObjectOrNull(); +} + +inline JSFunction * +JSObject::getCallObjCalleeFunction() const +{ + JS_ASSERT(isCall()); + return getSlot(JSSLOT_CALL_CALLEE).toObject().getFunctionPrivate(); +} + +inline const js::Value & +JSObject::getCallObjArguments() const +{ + JS_ASSERT(isCall()); + JS_ASSERT(!callIsForEval()); + return getSlot(JSSLOT_CALL_ARGUMENTS); +} + +inline void +JSObject::setCallObjArguments(const js::Value &v) +{ + JS_ASSERT(isCall()); + JS_ASSERT(!callIsForEval()); + setSlot(JSSLOT_CALL_ARGUMENTS, v); +} + +inline const js::Value & +JSObject::callObjArg(uintN i) const +{ + JS_ASSERT(isCall()); + JS_ASSERT(i < getCallObjCalleeFunction()->nargs); + return getSlot(JSObject::CALL_RESERVED_SLOTS + i); +} + +inline js::Value & +JSObject::callObjArg(uintN i) +{ + JS_ASSERT(isCall()); + JS_ASSERT(i < getCallObjCalleeFunction()->nargs); + return getSlotRef(JSObject::CALL_RESERVED_SLOTS + i); +} + +inline const js::Value & +JSObject::callObjVar(uintN i) const +{ + JSFunction *fun = getCallObjCalleeFunction(); + JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs()); + JS_ASSERT(i < fun->script()->bindings.countVars()); + return getSlot(JSObject::CALL_RESERVED_SLOTS + fun->nargs + i); +} + +inline js::Value & +JSObject::callObjVar(uintN i) +{ + JSFunction *fun = getCallObjCalleeFunction(); + JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs()); + JS_ASSERT(i < fun->script()->bindings.countVars()); + return getSlotRef(JSObject::CALL_RESERVED_SLOTS + fun->nargs + i); +} + +inline const js::Value & +JSObject::getDateUTCTime() const +{ + JS_ASSERT(isDate()); + return getSlot(JSSLOT_DATE_UTC_TIME); +} + +inline void +JSObject::setDateUTCTime(const js::Value &time) +{ + JS_ASSERT(isDate()); + setSlot(JSSLOT_DATE_UTC_TIME, time); +} + +inline js::Value * +JSObject::getFlatClosureUpvars() const +{ +#ifdef DEBUG + JSFunction *fun = getFunctionPrivate(); + JS_ASSERT(fun->isFlatClosure()); + JS_ASSERT(fun->script()->bindings.countUpvars() == fun->script()->upvars()->length); +#endif + return (js::Value *) getSlot(JSSLOT_FLAT_CLOSURE_UPVARS).toPrivate(); +} + +inline js::Value +JSObject::getFlatClosureUpvar(uint32 i) const +{ + JS_ASSERT(i < getFunctionPrivate()->script()->bindings.countUpvars()); + return getFlatClosureUpvars()[i]; +} + +inline js::Value & +JSObject::getFlatClosureUpvar(uint32 i) +{ + JS_ASSERT(i < getFunctionPrivate()->script()->bindings.countUpvars()); + return getFlatClosureUpvars()[i]; +} + +inline void +JSObject::setFlatClosureUpvars(js::Value *upvars) +{ + JS_ASSERT(isFunction()); + JS_ASSERT(FUN_FLAT_CLOSURE(getFunctionPrivate())); + getSlotRef(JSSLOT_FLAT_CLOSURE_UPVARS).setPrivate(upvars); +} + +inline bool +JSObject::hasMethodObj(const JSObject& obj) const +{ + return JSSLOT_FUN_METHOD_OBJ < numSlots() && + getSlot(JSSLOT_FUN_METHOD_OBJ).isObject() && + &getSlot(JSSLOT_FUN_METHOD_OBJ).toObject() == &obj; +} + +inline void +JSObject::setMethodObj(JSObject& obj) +{ + getSlotRef(JSSLOT_FUN_METHOD_OBJ).setObject(obj); +} + +inline js::NativeIterator * +JSObject::getNativeIterator() const +{ + return (js::NativeIterator *) getPrivate(); +} + +inline void +JSObject::setNativeIterator(js::NativeIterator *ni) +{ + setPrivate(ni); +} + +inline JSLinearString * +JSObject::getNamePrefix() const +{ + JS_ASSERT(isNamespace() || isQName()); + const js::Value &v = getSlot(JSSLOT_NAME_PREFIX); + return !v.isUndefined() ? v.toString()->assertIsLinear() : NULL; +} + +inline jsval +JSObject::getNamePrefixVal() const +{ + JS_ASSERT(isNamespace() || isQName()); + return js::Jsvalify(getSlot(JSSLOT_NAME_PREFIX)); +} + +inline void +JSObject::setNamePrefix(JSLinearString *prefix) +{ + JS_ASSERT(isNamespace() || isQName()); + setSlot(JSSLOT_NAME_PREFIX, prefix ? js::StringValue(prefix) : js::UndefinedValue()); +} + +inline void +JSObject::clearNamePrefix() +{ + JS_ASSERT(isNamespace() || isQName()); + setSlot(JSSLOT_NAME_PREFIX, js::UndefinedValue()); +} + +inline JSLinearString * +JSObject::getNameURI() const +{ + JS_ASSERT(isNamespace() || isQName()); + const js::Value &v = getSlot(JSSLOT_NAME_URI); + return !v.isUndefined() ? v.toString()->assertIsLinear() : NULL; +} + +inline jsval +JSObject::getNameURIVal() const +{ + JS_ASSERT(isNamespace() || isQName()); + return js::Jsvalify(getSlot(JSSLOT_NAME_URI)); +} + +inline void +JSObject::setNameURI(JSLinearString *uri) +{ + JS_ASSERT(isNamespace() || isQName()); + setSlot(JSSLOT_NAME_URI, uri ? js::StringValue(uri) : js::UndefinedValue()); +} + +inline jsval +JSObject::getNamespaceDeclared() const +{ + JS_ASSERT(isNamespace()); + return js::Jsvalify(getSlot(JSSLOT_NAMESPACE_DECLARED)); +} + +inline void +JSObject::setNamespaceDeclared(jsval decl) +{ + JS_ASSERT(isNamespace()); + setSlot(JSSLOT_NAMESPACE_DECLARED, js::Valueify(decl)); +} + +inline JSLinearString * +JSObject::getQNameLocalName() const +{ + JS_ASSERT(isQName()); + const js::Value &v = getSlot(JSSLOT_QNAME_LOCAL_NAME); + return !v.isUndefined() ? v.toString()->assertIsLinear() : NULL; +} + +inline jsval +JSObject::getQNameLocalNameVal() const +{ + JS_ASSERT(isQName()); + return js::Jsvalify(getSlot(JSSLOT_QNAME_LOCAL_NAME)); +} + +inline void +JSObject::setQNameLocalName(JSLinearString *name) +{ + JS_ASSERT(isQName()); + setSlot(JSSLOT_QNAME_LOCAL_NAME, name ? js::StringValue(name) : js::UndefinedValue()); +} + +inline JSObject * +JSObject::getWithThis() const +{ + return &getSlot(JSSLOT_WITH_THIS).toObject(); +} + +inline void +JSObject::setWithThis(JSObject *thisp) +{ + getSlotRef(JSSLOT_WITH_THIS).setObject(*thisp); +} + +inline void +JSObject::init(JSContext *cx, js::Class *aclasp, JSObject *proto, JSObject *parent, + void *priv, bool useHoles) +{ + clasp = aclasp; + flags = 0; + +#ifdef DEBUG + /* + * NB: objShape must not be set here; rather, the caller must call setMap + * or setSharedNonNativeMap after calling init. To defend this requirement + * we set map to null in DEBUG builds, and set objShape to a value we then + * assert obj->shape() never returns. + */ + map = NULL; + objShape = JSObjectMap::INVALID_SHAPE; +#endif + + setProto(proto); + setParent(parent); + + privateData = priv; + slots = fixedSlots(); + + /* + * Fill the fixed slots with undefined or array holes. This object must + * already have its capacity filled in, as by js_NewGCObject. + */ + JS_ASSERT(capacity == numFixedSlots()); + ClearValueRange(slots, capacity, useHoles); + + emptyShapes = NULL; +} + +inline void +JSObject::finish(JSContext *cx) +{ +#ifdef DEBUG + if (isNative()) + JS_LOCK_RUNTIME_VOID(cx->runtime, cx->runtime->liveObjectProps -= propertyCount()); +#endif + if (hasSlotsArray()) + freeSlotsArray(cx); + if (emptyShapes) + cx->free(emptyShapes); +} + +inline bool +JSObject::initSharingEmptyShape(JSContext *cx, + js::Class *aclasp, + JSObject *proto, + JSObject *parent, + void *privateValue, + /* js::gc::FinalizeKind */ unsigned kind) +{ + init(cx, aclasp, proto, parent, privateValue, false); + + JS_ASSERT(!isDenseArray()); + + js::EmptyShape *empty = proto->getEmptyShape(cx, aclasp, kind); + if (!empty) + return false; + + setMap(empty); + return true; +} + +inline void +JSObject::freeSlotsArray(JSContext *cx) +{ + JS_ASSERT(hasSlotsArray()); + cx->free(slots); +} + +inline void +JSObject::revertToFixedSlots(JSContext *cx) +{ + JS_ASSERT(hasSlotsArray()); + size_t fixed = numFixedSlots(); + JS_ASSERT(capacity >= fixed); + memcpy(fixedSlots(), slots, fixed * sizeof(js::Value)); + freeSlotsArray(cx); + slots = fixedSlots(); + capacity = fixed; +} + +inline bool +JSObject::hasProperty(JSContext *cx, jsid id, bool *foundp, uintN flags) +{ + JSObject *pobj; + JSProperty *prop; + JSAutoResolveFlags rf(cx, flags); + if (!lookupProperty(cx, id, &pobj, &prop)) + return false; + *foundp = !!prop; + return true; +} + +inline bool +JSObject::isCallable() +{ + return isFunction() || getClass()->call; +} + +static inline bool +js_IsCallable(const js::Value &v) +{ + return v.isObject() && v.toObject().isCallable(); +} + +namespace js { + +class AutoPropDescArrayRooter : private AutoGCRooter +{ + public: + AutoPropDescArrayRooter(JSContext *cx) + : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx) + { } + + PropDesc *append() { + if (!descriptors.append(PropDesc())) + return NULL; + return &descriptors.back(); + } + + PropDesc& operator[](size_t i) { + JS_ASSERT(i < descriptors.length()); + return descriptors[i]; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + PropDescArray descriptors; +}; + +class AutoPropertyDescriptorRooter : private AutoGCRooter, public PropertyDescriptor +{ + public: + AutoPropertyDescriptorRooter(JSContext *cx) : AutoGCRooter(cx, DESCRIPTOR) { + obj = NULL; + attrs = 0; + getter = (PropertyOp) NULL; + setter = (StrictPropertyOp) NULL; + value.setUndefined(); + } + + AutoPropertyDescriptorRooter(JSContext *cx, PropertyDescriptor *desc) + : AutoGCRooter(cx, DESCRIPTOR) + { + obj = desc->obj; + attrs = desc->attrs; + getter = desc->getter; + setter = desc->setter; + value = desc->value; + } + + friend void AutoGCRooter::trace(JSTracer *trc); +}; + +static inline bool +InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* proto, + gc::FinalizeKind kind) +{ + JS_ASSERT(clasp->isNative()); + JS_ASSERT(proto == obj->getProto()); + + /* Share proto's emptyShape only if obj is similar to proto. */ + js::EmptyShape *empty = NULL; + + if (proto) { + if (proto->canProvideEmptyShape(clasp)) { + empty = proto->getEmptyShape(cx, clasp, kind); + if (!empty) + goto bad; + } + } + + if (!empty) { + empty = js::EmptyShape::create(cx, clasp); + if (!empty) + goto bad; + uint32 freeslot = JSSLOT_FREE(clasp); + if (freeslot > obj->numSlots() && !obj->allocSlots(cx, freeslot)) + goto bad; + } + + obj->setMap(empty); + return true; + + bad: + /* The GC nulls map initially. It should still be null on error. */ + JS_ASSERT(!obj->map); + return false; +} + +/* + * Helper optimized for creating a native instance of the given class (not the + * class's prototype object). Use this in preference to NewObject, but use + * NewBuiltinClassInstance if you need the default class prototype as proto, + * and its parent global as parent. + */ +static inline JSObject * +NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, + JSObject *parent, gc::FinalizeKind kind) +{ + JS_ASSERT(proto); + JS_ASSERT(parent); + + /* + * Allocate an object from the GC heap and initialize all its fields before + * doing any operation that can potentially trigger GC. + */ + JSObject* obj = js_NewGCObject(cx, kind); + + if (obj) { + /* + * Default parent to the parent of the prototype, which was set from + * the parent of the prototype's constructor. + */ + bool useHoles = (clasp == &js_ArrayClass); + obj->init(cx, clasp, proto, parent, NULL, useHoles); + + JS_ASSERT(proto->canProvideEmptyShape(clasp)); + js::EmptyShape *empty = proto->getEmptyShape(cx, clasp, kind); + + if (empty) + obj->setMap(empty); + else + obj = NULL; + } + + return obj; +} + +static inline JSObject * +NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent) +{ + gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp)); + return NewNativeClassInstance(cx, clasp, proto, parent, kind); +} + +bool +FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop, + Class *clasp); + +/* + * Helper used to create Boolean, Date, RegExp, etc. instances of built-in + * classes with class prototypes of the same Class. See, e.g., jsdate.cpp, + * jsregexp.cpp, and js_PrimitiveToObject in jsobj.cpp. Use this to get the + * right default proto and parent for clasp in cx. + */ +static inline JSObject * +NewBuiltinClassInstance(JSContext *cx, Class *clasp, gc::FinalizeKind kind) +{ + VOUCH_DOES_NOT_REQUIRE_STACK(); + + JSProtoKey protoKey = JSCLASS_CACHED_PROTO_KEY(clasp); + JS_ASSERT(protoKey != JSProto_Null); + + /* NB: inline-expanded and specialized version of js_GetClassPrototype. */ + JSObject *global; + if (!cx->hasfp()) { + global = cx->globalObject; + OBJ_TO_INNER_OBJECT(cx, global); + if (!global) + return NULL; + } else { + global = cx->fp()->scopeChain().getGlobal(); + } + JS_ASSERT(global->isGlobal()); + + const Value &v = global->getReservedSlot(JSProto_LIMIT + protoKey); + JSObject *proto; + if (v.isObject()) { + proto = &v.toObject(); + JS_ASSERT(proto->getParent() == global); + } else { + if (!FindClassPrototype(cx, global, protoKey, &proto, clasp)) + return NULL; + } + + return NewNativeClassInstance(cx, clasp, proto, global, kind); +} + +static inline JSObject * +NewBuiltinClassInstance(JSContext *cx, Class *clasp) +{ + gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp)); + return NewBuiltinClassInstance(cx, clasp, kind); +} + +static inline JSProtoKey +GetClassProtoKey(js::Class *clasp) +{ + JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp); + if (key != JSProto_Null) + return key; + if (clasp->flags & JSCLASS_IS_ANONYMOUS) + return JSProto_Object; + return JSProto_Null; +} + +namespace WithProto { + enum e { + Class = 0, + Given = 1 + }; +} + +/* + * Create an instance of any class, native or not, JSFunction-sized or not. + * + * If withProto is 'Class': + * If proto is null: + * for a built-in class: + * use the memoized original value of the class constructor .prototype + * property object + * else if available + * the current value of .prototype + * else + * Object.prototype. + * + * If parent is null, default it to proto->getParent() if proto is non + * null, else to null. + * + * If withProto is 'Given': + * We allocate an object with exactly the given proto. A null parent + * defaults to proto->getParent() if proto is non-null (else to null). + * + * If isFunction is true, return a JSFunction-sized object. If isFunction is + * false, return a normal object. + * + * Note that as a template, there will be lots of instantiations, which means + * the internals will be specialized based on the template parameters. + */ +static JS_ALWAYS_INLINE bool +FindProto(JSContext *cx, js::Class *clasp, JSObject *parent, JSObject ** proto) +{ + JSProtoKey protoKey = GetClassProtoKey(clasp); + if (!js_GetClassPrototype(cx, parent, protoKey, proto, clasp)) + return false; + if (!(*proto) && !js_GetClassPrototype(cx, parent, JSProto_Object, proto)) + return false; + + return true; +} + +namespace detail +{ +template +static JS_ALWAYS_INLINE JSObject * +NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent, + gc::FinalizeKind kind) +{ + /* Bootstrap the ur-object, and make it the default prototype object. */ + if (withProto == WithProto::Class && !proto) { + if (!FindProto(cx, clasp, parent, &proto)) + return NULL; + } + + /* + * Allocate an object from the GC heap and initialize all its fields before + * doing any operation that can potentially trigger GC. Functions have a + * larger non-standard allocation size. + * + * The should be specialized by the template. + */ + JSObject* obj = isFunction ? js_NewGCFunction(cx) : js_NewGCObject(cx, kind); + if (!obj) + goto out; + + /* This needs to match up with the size of JSFunction::data_padding. */ + JS_ASSERT_IF(isFunction, kind == gc::FINALIZE_OBJECT2); + + /* + * Default parent to the parent of the prototype, which was set from + * the parent of the prototype's constructor. + */ + obj->init(cx, clasp, proto, + (!parent && proto) ? proto->getParent() : parent, + NULL, clasp == &js_ArrayClass); + + if (clasp->isNative()) { + if (!InitScopeForObject(cx, obj, clasp, proto, kind)) { + obj = NULL; + goto out; + } + } else { + obj->setSharedNonNativeMap(); + } + +out: + Probes::createObject(cx, obj); + return obj; +} +} /* namespace detail */ + +static JS_ALWAYS_INLINE JSObject * +NewFunction(JSContext *cx, JSObject *parent) +{ + return detail::NewObject(cx, &js_FunctionClass, NULL, parent, + gc::FINALIZE_OBJECT2); +} + +template +static JS_ALWAYS_INLINE JSObject * +NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent, + gc::FinalizeKind kind) +{ + return detail::NewObject(cx, clasp, proto, parent, kind); +} + +template +static JS_ALWAYS_INLINE JSObject * +NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent) +{ + gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp)); + return detail::NewObject(cx, clasp, proto, parent, kind); +} + +template +static JS_ALWAYS_INLINE JSObject * +NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent, + gc::FinalizeKind kind) +{ + if (clasp == &js_FunctionClass) + return detail::NewObject(cx, clasp, proto, parent, kind); + return detail::NewObject(cx, clasp, proto, parent, kind); +} + +template +static JS_ALWAYS_INLINE JSObject * +NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent) +{ + gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp)); + return NewObject(cx, clasp, proto, parent, kind); +} + +/* + * As for gc::GetGCObjectKind, where numSlots is a guess at the final size of + * the object, zero if the final size is unknown. + */ +static inline gc::FinalizeKind +GuessObjectGCKind(size_t numSlots, bool isArray) +{ + if (numSlots) + return gc::GetGCObjectKind(numSlots); + return isArray ? gc::FINALIZE_OBJECT8 : gc::FINALIZE_OBJECT4; +} + +/* + * Get the GC kind to use for scripted 'new' on the given class. + * FIXME bug 547327: estimate the size from the allocation site. + */ +static inline gc::FinalizeKind +NewObjectGCKind(JSContext *cx, js::Class *clasp) +{ + if (clasp == &js_ArrayClass || clasp == &js_SlowArrayClass) + return gc::FINALIZE_OBJECT8; + if (clasp == &js_FunctionClass) + return gc::FINALIZE_OBJECT2; + return gc::FINALIZE_OBJECT4; +} + +/* Make an object with pregenerated shape from a NEWOBJECT bytecode. */ +static inline JSObject * +CopyInitializerObject(JSContext *cx, JSObject *baseobj) +{ + JS_ASSERT(baseobj->getClass() == &js_ObjectClass); + JS_ASSERT(!baseobj->inDictionaryMode()); + + gc::FinalizeKind kind = gc::FinalizeKind(baseobj->finalizeKind()); + JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind); + + if (!obj || !obj->ensureSlots(cx, baseobj->numSlots())) + return NULL; + + obj->flags = baseobj->flags; + obj->lastProp = baseobj->lastProp; + obj->objShape = baseobj->objShape; + + return obj; +} + +/* + * When we have an object of a builtin class, we don't quite know what its + * valueOf/toString methods are, since these methods may have been overwritten + * or shadowed. However, we can still do better than js_TryMethod by + * hard-coding the necessary properties for us to find the native we expect. + * + * TODO: a per-thread shape-based cache would be faster and simpler. + */ +static JS_ALWAYS_INLINE bool +ClassMethodIsNative(JSContext *cx, JSObject *obj, Class *clasp, jsid methodid, + Native native) +{ + JS_ASSERT(obj->getClass() == clasp); + + if (HasNativeMethod(obj, methodid, native)) + return true; + + JSObject *pobj = obj->getProto(); + return pobj && pobj->getClass() == clasp && + HasNativeMethod(pobj, methodid, native); +} + +} /* namespace js */ + +#endif /* jsobjinlines_h___ */ diff --git a/js/src/json.cpp b/js/src/json.cpp new file mode 100644 index 0000000..a37a6f3 --- /dev/null +++ b/js/src/json.cpp @@ -0,0 +1,1270 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey JSON. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert Sayre + * Dave Camp + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include "jsapi.h" +#include "jsarena.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jsfun.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsprf.h" +#include "jsscan.h" +#include "jsstr.h" +#include "jstypes.h" +#include "jsstdint.h" +#include "jsutil.h" +#include "jsxml.h" +#include "jsvector.h" + +#include "json.h" + +#include "jsatominlines.h" +#include "jsobjinlines.h" + +using namespace js; +using namespace js::gc; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4351) +#endif + +struct JSONParser +{ + JSONParser(JSContext *cx) + : hexChar(), numHex(), statep(), stateStack(), rootVal(), objectStack(), + objectKey(cx), buffer(cx), suppressErrors(false) + {} + + /* Used while handling \uNNNN in strings */ + jschar hexChar; + uint8 numHex; + + JSONParserState *statep; + JSONParserState stateStack[JSON_MAX_DEPTH]; + Value *rootVal; + JSObject *objectStack; + js::Vector objectKey; + js::Vector buffer; + bool suppressErrors; +}; + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +Class js_JSONClass = { + js_JSON_str, + JSCLASS_HAS_CACHED_PROTO(JSProto_JSON), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub +}; + +JSBool +js_json_parse(JSContext *cx, uintN argc, Value *vp) +{ + JSString *s = NULL; + Value *argv = vp + 2; + AutoValueRooter reviver(cx); + + if (!JS_ConvertArguments(cx, argc, Jsvalify(argv), "S / v", &s, reviver.addr())) + return JS_FALSE; + + JSLinearString *linearStr = s->ensureLinear(cx); + if (!linearStr) + return JS_FALSE; + + JSONParser *jp = js_BeginJSONParse(cx, vp); + JSBool ok = jp != NULL; + if (ok) { + const jschar *chars = linearStr->chars(); + size_t length = linearStr->length(); + ok = js_ConsumeJSONText(cx, jp, chars, length); + ok &= !!js_FinishJSONParse(cx, jp, reviver.value()); + } + + return ok; +} + +JSBool +js_json_stringify(JSContext *cx, uintN argc, Value *vp) +{ + Value *argv = vp + 2; + AutoValueRooter space(cx); + AutoObjectRooter replacer(cx); + + // Must throw an Error if there isn't a first arg + if (!JS_ConvertArguments(cx, argc, Jsvalify(argv), "v / o v", vp, replacer.addr(), space.addr())) + return JS_FALSE; + + StringBuffer sb(cx); + + if (!js_Stringify(cx, vp, replacer.object(), space.value(), sb)) + return JS_FALSE; + + // XXX This can never happen to nsJSON.cpp, but the JSON object + // needs to support returning undefined. So this is a little awkward + // for the API, because we want to support streaming writers. + if (!sb.empty()) { + JSString *str = sb.finishString(); + if (!str) + return JS_FALSE; + vp->setString(str); + } else { + vp->setUndefined(); + } + + return JS_TRUE; +} + +JSBool +js_TryJSON(JSContext *cx, Value *vp) +{ + // Checks whether the return value implements toJSON() + JSBool ok = JS_TRUE; + + if (vp->isObject()) { + JSObject *obj = &vp->toObject(); + ok = js_TryMethod(cx, obj, cx->runtime->atomState.toJSONAtom, 0, NULL, vp); + } + + return ok; +} + + +static const char quote = '\"'; +static const char backslash = '\\'; +static const char unicodeEscape[] = "\\u00"; + +static JSBool +write_string(JSContext *cx, StringBuffer &sb, const jschar *buf, uint32 len) +{ + if (!sb.append(quote)) + return JS_FALSE; + + uint32 mark = 0; + uint32 i; + for (i = 0; i < len; ++i) { + if (buf[i] == quote || buf[i] == backslash) { + if (!sb.append(&buf[mark], i - mark) || !sb.append(backslash) || + !sb.append(buf[i])) { + return JS_FALSE; + } + mark = i + 1; + } else if (buf[i] <= 31 || buf[i] == 127) { + if (!sb.append(&buf[mark], i - mark) || + !sb.append(unicodeEscape)) { + return JS_FALSE; + } + char ubuf[3]; + size_t len = JS_snprintf(ubuf, sizeof(ubuf), "%.2x", buf[i]); + JS_ASSERT(len == 2); + jschar wbuf[3]; + size_t wbufSize = JS_ARRAY_LENGTH(wbuf); + if (!js_InflateStringToBuffer(cx, ubuf, len, wbuf, &wbufSize) || + !sb.append(wbuf, wbufSize)) { + return JS_FALSE; + } + mark = i + 1; + } + } + + if (mark < len && !sb.append(&buf[mark], len - mark)) + return JS_FALSE; + + return sb.append(quote); +} + +class StringifyContext +{ +public: + StringifyContext(JSContext *cx, StringBuffer &sb, JSObject *replacer) + : sb(sb), gap(cx), replacer(replacer), depth(0), objectStack(cx) + {} + + bool initializeGap(JSContext *cx, const Value &space) { + AutoValueRooter gapValue(cx, space); + + if (space.isObject()) { + JSObject &obj = space.toObject(); + Class *clasp = obj.getClass(); + if (clasp == &js_NumberClass || clasp == &js_StringClass) + *gapValue.addr() = obj.getPrimitiveThis(); + } + + if (gapValue.value().isString()) { + if (!ValueToStringBuffer(cx, gapValue.value(), gap)) + return false; + if (gap.length() > 10) + gap.resize(10); + } else if (gapValue.value().isNumber()) { + jsdouble d = gapValue.value().isInt32() + ? gapValue.value().toInt32() + : js_DoubleToInteger(gapValue.value().toDouble()); + d = JS_MIN(10, d); + if (d >= 1 && !gap.appendN(' ', uint32(d))) + return false; + } + + return true; + } + + bool initializeStack() { + return objectStack.init(16); + } + +#ifdef DEBUG + ~StringifyContext() { JS_ASSERT(objectStack.empty()); } +#endif + + StringBuffer &sb; + StringBuffer gap; + JSObject *replacer; + uint32 depth; + HashSet objectStack; +}; + +static JSBool CallReplacerFunction(JSContext *cx, jsid id, JSObject *holder, + StringifyContext *scx, Value *vp); +static JSBool Str(JSContext *cx, jsid id, JSObject *holder, + StringifyContext *scx, Value *vp, bool callReplacer = true); + +static JSBool +WriteIndent(JSContext *cx, StringifyContext *scx, uint32 limit) +{ + if (!scx->gap.empty()) { + if (!scx->sb.append('\n')) + return JS_FALSE; + for (uint32 i = 0; i < limit; i++) { + if (!scx->sb.append(scx->gap.begin(), scx->gap.end())) + return JS_FALSE; + } + } + + return JS_TRUE; +} + +class CycleDetector +{ + public: + CycleDetector(StringifyContext *scx, JSObject *obj) + : objectStack(scx->objectStack), obj(obj) { + } + + bool init(JSContext *cx) { + HashSet::AddPtr ptr = objectStack.lookupForAdd(obj); + if (ptr) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CYCLIC_VALUE, js_object_str); + return false; + } + return objectStack.add(ptr, obj); + } + + ~CycleDetector() { + objectStack.remove(obj); + } + + private: + HashSet &objectStack; + JSObject *const obj; +}; + +static JSBool +JO(JSContext *cx, Value *vp, StringifyContext *scx) +{ + JSObject *obj = &vp->toObject(); + + CycleDetector detect(scx, obj); + if (!detect.init(cx)) + return JS_FALSE; + + if (!scx->sb.append('{')) + return JS_FALSE; + + Value vec[3] = { NullValue(), NullValue(), NullValue() }; + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec); + Value& outputValue = vec[0]; + Value& whitelistElement = vec[1]; + AutoIdRooter idr(cx); + jsid& id = *idr.addr(); + + Value *keySource = vp; + bool usingWhitelist = false; + + // if the replacer is an array, we use the keys from it + if (scx->replacer && JS_IsArrayObject(cx, scx->replacer)) { + usingWhitelist = true; + vec[2].setObject(*scx->replacer); + keySource = &vec[2]; + } + + JSBool memberWritten = JS_FALSE; + AutoIdVector props(cx); + if (!GetPropertyNames(cx, &keySource->toObject(), JSITER_OWNONLY, &props)) + return JS_FALSE; + + for (size_t i = 0, len = props.length(); i < len; i++) { + outputValue.setUndefined(); + + if (!usingWhitelist) { + if (!js_ValueToStringId(cx, IdToValue(props[i]), &id)) + return JS_FALSE; + } else { + // skip non-index properties + jsuint index = 0; + if (!js_IdIsIndex(props[i], &index)) + continue; + + if (!scx->replacer->getProperty(cx, props[i], &whitelistElement)) + return JS_FALSE; + + if (!js_ValueToStringId(cx, whitelistElement, &id)) + return JS_FALSE; + } + + // We should have a string id by this point. Either from + // JS_Enumerate's id array, or by converting an element + // of the whitelist. + JS_ASSERT(JSID_IS_ATOM(id)); + + if (!JS_GetPropertyById(cx, obj, id, Jsvalify(&outputValue))) + return JS_FALSE; + + if (outputValue.isObjectOrNull() && !js_TryJSON(cx, &outputValue)) + return JS_FALSE; + + // call this here, so we don't write out keys if the replacer function + // wants to elide the value. + if (!CallReplacerFunction(cx, id, obj, scx, &outputValue)) + return JS_FALSE; + + JSType type = JS_TypeOfValue(cx, Jsvalify(outputValue)); + + // elide undefined values and functions and XML + if (outputValue.isUndefined() || type == JSTYPE_FUNCTION || type == JSTYPE_XML) + continue; + + // output a comma unless this is the first member to write + if (memberWritten && !scx->sb.append(',')) + return JS_FALSE; + memberWritten = JS_TRUE; + + if (!WriteIndent(cx, scx, scx->depth)) + return JS_FALSE; + + // Be careful below, this string is weakly rooted + JSString *s = js_ValueToString(cx, IdToValue(id)); + if (!s) + return JS_FALSE; + + JS::Anchor anchor(s); + size_t length = s->length(); + const jschar *chars = s->getChars(cx); + if (!chars) + return JS_FALSE; + + if (!write_string(cx, scx->sb, chars, length) || + !scx->sb.append(':') || + !(scx->gap.empty() || scx->sb.append(' ')) || + !Str(cx, id, obj, scx, &outputValue, true)) { + return JS_FALSE; + } + } + + if (memberWritten && !WriteIndent(cx, scx, scx->depth - 1)) + return JS_FALSE; + + return scx->sb.append('}'); +} + +static JSBool +JA(JSContext *cx, Value *vp, StringifyContext *scx) +{ + JSObject *obj = &vp->toObject(); + + CycleDetector detect(scx, obj); + if (!detect.init(cx)) + return JS_FALSE; + + if (!scx->sb.append('[')) + return JS_FALSE; + + jsuint length; + if (!js_GetLengthProperty(cx, obj, &length)) + return JS_FALSE; + + if (length != 0 && !WriteIndent(cx, scx, scx->depth)) + return JS_FALSE; + + AutoValueRooter outputValue(cx); + + jsid id; + jsuint i; + for (i = 0; i < length; i++) { + id = INT_TO_JSID(i); + + if (!obj->getProperty(cx, id, outputValue.addr())) + return JS_FALSE; + + if (!Str(cx, id, obj, scx, outputValue.addr())) + return JS_FALSE; + + if (outputValue.value().isUndefined()) { + if (!scx->sb.append("null")) + return JS_FALSE; + } + + if (i < length - 1) { + if (!scx->sb.append(',')) + return JS_FALSE; + if (!WriteIndent(cx, scx, scx->depth)) + return JS_FALSE; + } + } + + if (length != 0 && !WriteIndent(cx, scx, scx->depth - 1)) + return JS_FALSE; + + return scx->sb.append(']'); +} + +static JSBool +CallReplacerFunction(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, Value *vp) +{ + if (scx->replacer && scx->replacer->isCallable()) { + Value vec[2] = { IdToValue(id), *vp}; + if (!JS_CallFunctionValue(cx, holder, OBJECT_TO_JSVAL(scx->replacer), + 2, Jsvalify(vec), Jsvalify(vp))) { + return JS_FALSE; + } + } + + return JS_TRUE; +} + +static JSBool +Str(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, Value *vp, bool callReplacer) +{ + JS_CHECK_RECURSION(cx, return JS_FALSE); + + if (vp->isObject() && !js_TryJSON(cx, vp)) + return JS_FALSE; + + if (callReplacer && !CallReplacerFunction(cx, id, holder, scx, vp)) + return JS_FALSE; + + // catches string and number objects with no toJSON + if (vp->isObject()) { + JSObject *obj = &vp->toObject(); + Class *clasp = obj->getClass(); + if (clasp == &js_StringClass || clasp == &js_NumberClass) + *vp = obj->getPrimitiveThis(); + } + + if (vp->isString()) { + JSString *str = vp->toString(); + size_t length = str->length(); + const jschar *chars = str->getChars(cx); + if (!chars) + return JS_FALSE; + return write_string(cx, scx->sb, chars, length); + } + + if (vp->isNull()) + return scx->sb.append("null"); + + if (vp->isBoolean()) + return vp->toBoolean() ? scx->sb.append("true") : scx->sb.append("false"); + + if (vp->isNumber()) { + if (vp->isDouble()) { + jsdouble d = vp->toDouble(); + if (!JSDOUBLE_IS_FINITE(d)) + return scx->sb.append("null"); + } + + StringBuffer sb(cx); + if (!NumberValueToStringBuffer(cx, *vp, sb)) + return JS_FALSE; + + return scx->sb.append(sb.begin(), sb.length()); + } + + if (vp->isObject() && !IsFunctionObject(*vp) && !IsXML(*vp)) { + JSBool ok; + + scx->depth++; + ok = (JS_IsArrayObject(cx, &vp->toObject()) ? JA : JO)(cx, vp, scx); + scx->depth--; + + return ok; + } + + vp->setUndefined(); + return JS_TRUE; +} + +JSBool +js_Stringify(JSContext *cx, Value *vp, JSObject *replacer, const Value &space, + StringBuffer &sb) +{ + StringifyContext scx(cx, sb, replacer); + if (!scx.initializeGap(cx, space) || !scx.initializeStack()) + return JS_FALSE; + + JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass); + if (!obj) + return JS_FALSE; + + AutoObjectRooter tvr(cx, obj); + if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), + *vp, NULL, NULL, JSPROP_ENUMERATE)) { + return JS_FALSE; + } + + return Str(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), obj, &scx, vp); +} + +// helper to determine whether a character could be part of a number +static JSBool IsNumChar(jschar c) +{ + return ((c <= '9' && c >= '0') || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E'); +} + +static JSBool HandleDataString(JSContext *cx, JSONParser *jp); +static JSBool HandleDataKeyString(JSContext *cx, JSONParser *jp); +static JSBool HandleDataNumber(JSContext *cx, JSONParser *jp); +static JSBool HandleDataKeyword(JSContext *cx, JSONParser *jp); +static JSBool PopState(JSContext *cx, JSONParser *jp); + +static bool +Walk(JSContext *cx, jsid id, JSObject *holder, const Value &reviver, Value *vp) +{ + JS_CHECK_RECURSION(cx, return false); + + if (!holder->getProperty(cx, id, vp)) + return false; + + JSObject *obj; + + if (vp->isObject() && !(obj = &vp->toObject())->isCallable()) { + AutoValueRooter propValue(cx); + + if(obj->isArray()) { + jsuint length = 0; + if (!js_GetLengthProperty(cx, obj, &length)) + return false; + + for (jsuint i = 0; i < length; i++) { + jsid index; + if (!js_IndexToId(cx, i, &index)) + return false; + + if (!Walk(cx, index, obj, reviver, propValue.addr())) + return false; + + if (!obj->defineProperty(cx, index, propValue.value(), NULL, NULL, JSPROP_ENUMERATE)) + return false; + } + } else { + AutoIdVector props(cx); + if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props)) + return false; + + for (size_t i = 0, len = props.length(); i < len; i++) { + jsid idName = props[i]; + if (!Walk(cx, idName, obj, reviver, propValue.addr())) + return false; + if (propValue.value().isUndefined()) { + if (!js_DeleteProperty(cx, obj, idName, propValue.addr(), false)) + return false; + } else { + if (!obj->defineProperty(cx, idName, propValue.value(), NULL, NULL, + JSPROP_ENUMERATE)) { + return false; + } + } + } + } + } + + // return reviver.call(holder, key, value); + const Value &value = *vp; + JSString *key = js_ValueToString(cx, IdToValue(id)); + if (!key) + return false; + + Value vec[2] = { StringValue(key), value }; + Value reviverResult; + if (!JS_CallFunctionValue(cx, holder, Jsvalify(reviver), + 2, Jsvalify(vec), Jsvalify(&reviverResult))) { + return false; + } + + *vp = reviverResult; + return true; +} + +static JSBool +JSONParseError(JSONParser *jp, JSContext *cx) +{ + if (!jp->suppressErrors) + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE); + return JS_FALSE; +} + +static bool +Revive(JSContext *cx, const Value &reviver, Value *vp) +{ + + JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass); + if (!obj) + return false; + + AutoObjectRooter tvr(cx, obj); + if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), + *vp, NULL, NULL, JSPROP_ENUMERATE)) { + return false; + } + + return Walk(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), obj, reviver, vp); +} + +JSONParser * +js_BeginJSONParse(JSContext *cx, Value *rootVal, bool suppressErrors /*= false*/) +{ + if (!cx) + return NULL; + + JSObject *arr = NewDenseEmptyArray(cx); + if (!arr) + return NULL; + + JSONParser *jp = cx->create(cx); + if (!jp) + return NULL; + + jp->objectStack = arr; + if (!JS_AddNamedObjectRoot(cx, &jp->objectStack, "JSON parse stack")) + goto bad; + + jp->statep = jp->stateStack; + *jp->statep = JSON_PARSE_STATE_INIT; + jp->rootVal = rootVal; + jp->suppressErrors = suppressErrors; + + return jp; + +bad: + js_FinishJSONParse(cx, jp, NullValue()); + return NULL; +} + +bool +js_FinishJSONParse(JSContext *cx, JSONParser *jp, const Value &reviver) +{ + if (!jp) + return true; + + JSBool early_ok = JS_TRUE; + + // Check for unprocessed primitives at the root. This doesn't happen for + // strings because a closing quote triggers value processing. + if ((jp->statep - jp->stateStack) == 1) { + if (*jp->statep == JSON_PARSE_STATE_KEYWORD) { + early_ok = HandleDataKeyword(cx, jp); + if (early_ok) + PopState(cx, jp); + } else if (*jp->statep == JSON_PARSE_STATE_NUMBER) { + early_ok = HandleDataNumber(cx, jp); + if (early_ok) + PopState(cx, jp); + } + } + + // This internal API is infallible, in spite of its JSBool return type. + js_RemoveRoot(cx->runtime, &jp->objectStack); + + bool ok = *jp->statep == JSON_PARSE_STATE_FINISHED; + Value *vp = jp->rootVal; + + if (!early_ok) { + ok = false; + } else if (!ok) { + JSONParseError(jp, cx); + } else if (reviver.isObject() && reviver.toObject().isCallable()) { + ok = Revive(cx, reviver, vp); + } + + cx->destroy(jp); + + return ok; +} + +static JSBool +PushState(JSContext *cx, JSONParser *jp, JSONParserState state) +{ + if (*jp->statep == JSON_PARSE_STATE_FINISHED) { + // extra input + return JSONParseError(jp, cx); + } + + jp->statep++; + if ((uint32)(jp->statep - jp->stateStack) >= JS_ARRAY_LENGTH(jp->stateStack)) { + // too deep + return JSONParseError(jp, cx); + } + + *jp->statep = state; + + return JS_TRUE; +} + +static JSBool +PopState(JSContext *cx, JSONParser *jp) +{ + jp->statep--; + if (jp->statep < jp->stateStack) { + jp->statep = jp->stateStack; + return JSONParseError(jp, cx); + } + + if (*jp->statep == JSON_PARSE_STATE_INIT) + *jp->statep = JSON_PARSE_STATE_FINISHED; + + return JS_TRUE; +} + +static JSBool +PushValue(JSContext *cx, JSONParser *jp, JSObject *parent, const Value &value) +{ + JSBool ok; + if (parent->isArray()) { + jsuint len; + ok = js_GetLengthProperty(cx, parent, &len); + if (ok) { + jsid index; + if (!js_IndexToId(cx, len, &index)) + return JS_FALSE; + ok = parent->defineProperty(cx, index, value, NULL, NULL, JSPROP_ENUMERATE); + } + } else { + ok = JS_DefineUCProperty(cx, parent, jp->objectKey.begin(), + jp->objectKey.length(), Jsvalify(value), + NULL, NULL, JSPROP_ENUMERATE); + jp->objectKey.clear(); + } + + return ok; +} + +static JSBool +PushObject(JSContext *cx, JSONParser *jp, JSObject *obj) +{ + jsuint len; + if (!js_GetLengthProperty(cx, jp->objectStack, &len)) + return JS_FALSE; + if (len >= JSON_MAX_DEPTH) + return JSONParseError(jp, cx); + + AutoObjectRooter tvr(cx, obj); + Value v = ObjectOrNullValue(obj); + + // Check if this is the root object + if (len == 0) { + *jp->rootVal = v; + // This property must be enumerable to keep the array dense + if (!jp->objectStack->defineProperty(cx, INT_TO_JSID(0), *jp->rootVal, + NULL, NULL, JSPROP_ENUMERATE)) { + return JS_FALSE; + } + return JS_TRUE; + } + + Value p; + if (!jp->objectStack->getProperty(cx, INT_TO_JSID(len - 1), &p)) + return JS_FALSE; + + JSObject *parent = &p.toObject(); + if (!PushValue(cx, jp, parent, v)) + return JS_FALSE; + + // This property must be enumerable to keep the array dense + if (!jp->objectStack->defineProperty(cx, INT_TO_JSID(len), v, + NULL, NULL, JSPROP_ENUMERATE)) { + return JS_FALSE; + } + + return JS_TRUE; +} + +static JSBool +OpenObject(JSContext *cx, JSONParser *jp) +{ + JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass); + if (!obj) + return JS_FALSE; + + return PushObject(cx, jp, obj); +} + +static JSBool +OpenArray(JSContext *cx, JSONParser *jp) +{ + // Add an array to an existing array or object + JSObject *arr = NewDenseEmptyArray(cx); + if (!arr) + return JS_FALSE; + + return PushObject(cx, jp, arr); +} + +static JSBool +CloseObject(JSContext *cx, JSONParser *jp) +{ + jsuint len; + if (!js_GetLengthProperty(cx, jp->objectStack, &len)) + return JS_FALSE; + if (!js_SetLengthProperty(cx, jp->objectStack, len - 1)) + return JS_FALSE; + + return JS_TRUE; +} + +static JSBool +CloseArray(JSContext *cx, JSONParser *jp) +{ + return CloseObject(cx, jp); +} + +static JSBool +PushPrimitive(JSContext *cx, JSONParser *jp, const Value &value) +{ + AutoValueRooter tvr(cx, value); + + jsuint len; + if (!js_GetLengthProperty(cx, jp->objectStack, &len)) + return JS_FALSE; + + if (len > 0) { + Value o; + if (!jp->objectStack->getProperty(cx, INT_TO_JSID(len - 1), &o)) + return JS_FALSE; + + return PushValue(cx, jp, &o.toObject(), value); + } + + // root value must be primitive + *jp->rootVal = value; + return JS_TRUE; +} + +static JSBool +HandleNumber(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len) +{ + const jschar *ep; + double val; + if (!js_strtod(cx, buf, buf + len, &ep, &val)) + return JS_FALSE; + if (ep != buf + len) { + // bad number input + return JSONParseError(jp, cx); + } + + return PushPrimitive(cx, jp, NumberValue(val)); +} + +static JSBool +HandleString(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len) +{ + JSString *str = js_NewStringCopyN(cx, buf, len); + if (!str) + return JS_FALSE; + + return PushPrimitive(cx, jp, StringValue(str)); +} + +static JSBool +HandleKeyword(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len) +{ + const KeywordInfo *ki = FindKeyword(buf, len); + if (!ki || ki->tokentype != TOK_PRIMARY) { + // bad keyword + return JSONParseError(jp, cx); + } + + Value keyword; + if (buf[0] == 'n') { + keyword.setNull(); + } else if (buf[0] == 't') { + keyword.setBoolean(true); + } else if (buf[0] == 'f') { + keyword.setBoolean(false); + } else { + return JSONParseError(jp, cx); + } + + return PushPrimitive(cx, jp, keyword); +} + +static JSBool +HandleDataString(JSContext *cx, JSONParser *jp) +{ + JSBool ok = HandleString(cx, jp, jp->buffer.begin(), jp->buffer.length()); + if (ok) + jp->buffer.clear(); + return ok; +} + +static JSBool +HandleDataKeyString(JSContext *cx, JSONParser *jp) +{ + JSBool ok = jp->objectKey.append(jp->buffer.begin(), jp->buffer.end()); + if (ok) + jp->buffer.clear(); + return ok; +} + +static JSBool +HandleDataNumber(JSContext *cx, JSONParser *jp) +{ + JSBool ok = HandleNumber(cx, jp, jp->buffer.begin(), jp->buffer.length()); + if (ok) + jp->buffer.clear(); + return ok; +} + +static JSBool +HandleDataKeyword(JSContext *cx, JSONParser *jp) +{ + JSBool ok = HandleKeyword(cx, jp, jp->buffer.begin(), jp->buffer.length()); + if (ok) + jp->buffer.clear(); + return ok; +} + +JSBool +js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len, + DecodingMode decodingMode) +{ + CHECK_REQUEST(cx); + + if (*jp->statep == JSON_PARSE_STATE_INIT) { + PushState(cx, jp, JSON_PARSE_STATE_VALUE); + } + + for (uint32 i = 0; i < len; i++) { + jschar c = data[i]; + switch (*jp->statep) { + case JSON_PARSE_STATE_ARRAY_INITIAL_VALUE: + if (c == ']') { + if (!PopState(cx, jp)) + return JS_FALSE; + JS_ASSERT(*jp->statep == JSON_PARSE_STATE_ARRAY_AFTER_ELEMENT); + if (!CloseArray(cx, jp) || !PopState(cx, jp)) + return JS_FALSE; + break; + } + // fall through if non-empty array or whitespace + + case JSON_PARSE_STATE_VALUE: + if (c == '"') { + *jp->statep = JSON_PARSE_STATE_STRING; + break; + } + + if (IsNumChar(c)) { + *jp->statep = JSON_PARSE_STATE_NUMBER; + if (!jp->buffer.append(c)) + return JS_FALSE; + break; + } + + if (JS7_ISLET(c)) { + *jp->statep = JSON_PARSE_STATE_KEYWORD; + if (!jp->buffer.append(c)) + return JS_FALSE; + break; + } + + if (c == '{') { + *jp->statep = JSON_PARSE_STATE_OBJECT_AFTER_PAIR; + if (!OpenObject(cx, jp) || !PushState(cx, jp, JSON_PARSE_STATE_OBJECT_INITIAL_PAIR)) + return JS_FALSE; + } else if (c == '[') { + *jp->statep = JSON_PARSE_STATE_ARRAY_AFTER_ELEMENT; + if (!OpenArray(cx, jp) || !PushState(cx, jp, JSON_PARSE_STATE_ARRAY_INITIAL_VALUE)) + return JS_FALSE; + } else if (JS_ISXMLSPACE(c)) { + // nothing to do + } else if (decodingMode == LEGACY && c == ']') { + if (!PopState(cx, jp)) + return JS_FALSE; + JS_ASSERT(*jp->statep == JSON_PARSE_STATE_ARRAY_AFTER_ELEMENT); + if (!CloseArray(cx, jp) || !PopState(cx, jp)) + return JS_FALSE; + } else { + return JSONParseError(jp, cx); + } + break; + + case JSON_PARSE_STATE_ARRAY_AFTER_ELEMENT: + if (c == ',') { + if (!PushState(cx, jp, JSON_PARSE_STATE_VALUE)) + return JS_FALSE; + } else if (c == ']') { + if (!CloseArray(cx, jp) || !PopState(cx, jp)) + return JS_FALSE; + } else if (!JS_ISXMLSPACE(c)) { + return JSONParseError(jp, cx); + } + break; + + case JSON_PARSE_STATE_OBJECT_AFTER_PAIR: + if (c == ',') { + if (!PushState(cx, jp, JSON_PARSE_STATE_OBJECT_PAIR)) + return JS_FALSE; + } else if (c == '}') { + if (!CloseObject(cx, jp) || !PopState(cx, jp)) + return JS_FALSE; + } else if (!JS_ISXMLSPACE(c)) { + return JSONParseError(jp, cx); + } + break; + + case JSON_PARSE_STATE_OBJECT_INITIAL_PAIR: + if (c == '}') { + if (!PopState(cx, jp)) + return JS_FALSE; + JS_ASSERT(*jp->statep == JSON_PARSE_STATE_OBJECT_AFTER_PAIR); + if (!CloseObject(cx, jp) || !PopState(cx, jp)) + return JS_FALSE; + break; + } + // fall through if non-empty object or whitespace + + case JSON_PARSE_STATE_OBJECT_PAIR: + if (c == '"') { + // we want to be waiting for a : when the string has been read + *jp->statep = JSON_PARSE_STATE_OBJECT_IN_PAIR; + if (!PushState(cx, jp, JSON_PARSE_STATE_STRING)) + return JS_FALSE; + } else if (JS_ISXMLSPACE(c)) { + // nothing to do + } else if (decodingMode == LEGACY && c == '}') { + if (!PopState(cx, jp)) + return JS_FALSE; + JS_ASSERT(*jp->statep == JSON_PARSE_STATE_OBJECT_AFTER_PAIR); + if (!CloseObject(cx, jp) || !PopState(cx, jp)) + return JS_FALSE; + } else { + return JSONParseError(jp, cx); + } + break; + + case JSON_PARSE_STATE_OBJECT_IN_PAIR: + if (c == ':') { + *jp->statep = JSON_PARSE_STATE_VALUE; + } else if (!JS_ISXMLSPACE(c)) { + return JSONParseError(jp, cx); + } + break; + + case JSON_PARSE_STATE_STRING: + if (c == '"') { + if (!PopState(cx, jp)) + return JS_FALSE; + if (*jp->statep == JSON_PARSE_STATE_OBJECT_IN_PAIR) { + if (!HandleDataKeyString(cx, jp)) + return JS_FALSE; + } else { + if (!HandleDataString(cx, jp)) + return JS_FALSE; + } + } else if (c == '\\') { + *jp->statep = JSON_PARSE_STATE_STRING_ESCAPE; + } else if (c <= 0x1F) { + // The JSON lexical grammer does not allow a JSONStringCharacter to be + // any of the Unicode characters U+0000 thru U+001F (control characters). + return JSONParseError(jp, cx); + } else { + if (!jp->buffer.append(c)) + return JS_FALSE; + } + break; + + case JSON_PARSE_STATE_STRING_ESCAPE: + switch (c) { + case '"': + case '\\': + case '/': + break; + case 'b' : c = '\b'; break; + case 'f' : c = '\f'; break; + case 'n' : c = '\n'; break; + case 'r' : c = '\r'; break; + case 't' : c = '\t'; break; + default : + if (c == 'u') { + jp->numHex = 0; + jp->hexChar = 0; + *jp->statep = JSON_PARSE_STATE_STRING_HEX; + continue; + } else { + return JSONParseError(jp, cx); + } + } + + if (!jp->buffer.append(c)) + return JS_FALSE; + *jp->statep = JSON_PARSE_STATE_STRING; + break; + + case JSON_PARSE_STATE_STRING_HEX: + if (('0' <= c) && (c <= '9')) { + jp->hexChar = (jp->hexChar << 4) | (c - '0'); + } else if (('a' <= c) && (c <= 'f')) { + jp->hexChar = (jp->hexChar << 4) | (c - 'a' + 0x0a); + } else if (('A' <= c) && (c <= 'F')) { + jp->hexChar = (jp->hexChar << 4) | (c - 'A' + 0x0a); + } else { + return JSONParseError(jp, cx); + } + + if (++(jp->numHex) == 4) { + if (!jp->buffer.append(jp->hexChar)) + return JS_FALSE; + jp->hexChar = 0; + jp->numHex = 0; + *jp->statep = JSON_PARSE_STATE_STRING; + } + break; + + case JSON_PARSE_STATE_KEYWORD: + if (JS7_ISLET(c)) { + if (!jp->buffer.append(c)) + return JS_FALSE; + } else { + // this character isn't part of the keyword, process it again + i--; + if (!PopState(cx, jp)) + return JS_FALSE; + + if (!HandleDataKeyword(cx, jp)) + return JS_FALSE; + } + break; + + case JSON_PARSE_STATE_NUMBER: + if (IsNumChar(c)) { + if (!jp->buffer.append(c)) + return JS_FALSE; + } else { + // this character isn't part of the number, process it again + i--; + if (!PopState(cx, jp)) + return JS_FALSE; + if (!HandleDataNumber(cx, jp)) + return JS_FALSE; + } + break; + + case JSON_PARSE_STATE_FINISHED: + if (!JS_ISXMLSPACE(c)) { + // extra input + return JSONParseError(jp, cx); + } + break; + + default: + JS_NOT_REACHED("Invalid JSON parser state"); + } + } + + return JS_TRUE; +} + +#if JS_HAS_TOSOURCE +static JSBool +json_toSource(JSContext *cx, uintN argc, Value *vp) +{ + vp->setString(ATOM_TO_STRING(CLASS_ATOM(cx, JSON))); + return JS_TRUE; +} +#endif + +static JSFunctionSpec json_static_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN(js_toSource_str, json_toSource, 0, 0), +#endif + JS_FN("parse", js_json_parse, 2, 0), + JS_FN("stringify", js_json_stringify, 3, 0), + JS_FS_END +}; + +JSObject * +js_InitJSONClass(JSContext *cx, JSObject *obj) +{ + JSObject *JSON; + + JSON = NewNonFunction(cx, &js_JSONClass, NULL, obj); + if (!JSON) + return NULL; + if (!JS_DefineProperty(cx, obj, js_JSON_str, OBJECT_TO_JSVAL(JSON), + JS_PropertyStub, JS_StrictPropertyStub, 0)) + return NULL; + + if (!JS_DefineFunctions(cx, JSON, json_static_methods)) + return NULL; + + return JSON; +} diff --git a/js/src/json.h b/js/src/json.h new file mode 100644 index 0000000..de42073 --- /dev/null +++ b/js/src/json.h @@ -0,0 +1,137 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey JSON. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert Sayre + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef json_h___ +#define json_h___ + +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jsvalue.h" +#include "jsvector.h" + +#define JSON_MAX_DEPTH 2048 +#define JSON_PARSER_BUFSIZE 1024 + +extern js::Class js_JSONClass; + +extern JSObject * +js_InitJSONClass(JSContext *cx, JSObject *obj); + +extern JSBool +js_Stringify(JSContext *cx, js::Value *vp, JSObject *replacer, + const js::Value &space, js::StringBuffer &sb); + +extern JSBool js_TryJSON(JSContext *cx, js::Value *vp); + +/* JSON parsing states; most permit leading whitespace. */ +enum JSONParserState { + /* Start of string. */ + JSON_PARSE_STATE_INIT, + + /* JSON fully processed, expecting only trailing whitespace. */ + JSON_PARSE_STATE_FINISHED, + + /* Start of JSON value. */ + JSON_PARSE_STATE_VALUE, + + /* Start of first key/value pair in object, or at }. */ + JSON_PARSE_STATE_OBJECT_INITIAL_PAIR, + + /* Start of subsequent key/value pair in object, after delimiting comma. */ + JSON_PARSE_STATE_OBJECT_PAIR, + + /* At : in key/value pair in object. */ + JSON_PARSE_STATE_OBJECT_IN_PAIR, + + /* Immediately after key/value pair in object: at , or }. */ + JSON_PARSE_STATE_OBJECT_AFTER_PAIR, + + /* Start of first element of array or at ]. */ + JSON_PARSE_STATE_ARRAY_INITIAL_VALUE, + + /* Immediately after element in array: at , or ]. */ + JSON_PARSE_STATE_ARRAY_AFTER_ELEMENT, + + + /* The following states allow no leading whitespace. */ + + /* Within string literal. */ + JSON_PARSE_STATE_STRING, + + /* At first character after \ in string literal. */ + JSON_PARSE_STATE_STRING_ESCAPE, + + /* Within numbers in \uXXXX in string literal. */ + JSON_PARSE_STATE_STRING_HEX, + + /* Within numeric literal. */ + JSON_PARSE_STATE_NUMBER, + + /* Handling keywords (only null/true/false pass validity post-check). */ + JSON_PARSE_STATE_KEYWORD +}; + +struct JSONParser; + +extern JSONParser * +js_BeginJSONParse(JSContext *cx, js::Value *rootVal, bool suppressErrors = false); + +/* Aargh, Windows. */ +#ifdef STRICT +#undef STRICT +#endif +#ifdef LEGACY +#undef LEGACY +#endif + +/* + * The type of JSON decoding to perform. Strict decoding is to-the-spec; + * legacy decoding accepts a few non-JSON syntaxes historically accepted by the + * implementation. (Full description of these deviations is deliberately + * omitted.) New users should use strict decoding rather than legacy decoding, + * as legacy decoding might be removed at a future time. + */ +enum DecodingMode { STRICT, LEGACY }; + +extern JS_FRIEND_API(JSBool) +js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len, + DecodingMode decodingMode = STRICT); + +extern bool +js_FinishJSONParse(JSContext *cx, JSONParser *jp, const js::Value &reviver); + +#endif /* json_h___ */ diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp new file mode 100644 index 0000000..37c3984 --- /dev/null +++ b/js/src/jsopcode.cpp @@ -0,0 +1,5548 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=8 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS bytecode descriptors, disassemblers, and decompilers. + */ +#ifdef HAVE_MEMORY_H +#include +#endif +#include +#include +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsarena.h" +#include "jsutil.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsiter.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsregexp.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jsstaticcheck.h" +#include "jstracer.h" +#include "jsvector.h" + +#include "jsinterpinlines.h" +#include "jsobjinlines.h" +#include "jsscriptinlines.h" +#include "jscntxtinlines.h" + +#include "jsautooplen.h" + +using namespace js; +using namespace js::gc; + +/* + * Index limit must stay within 32 bits. + */ +JS_STATIC_ASSERT(sizeof(uint32) * JS_BITS_PER_BYTE >= INDEX_LIMIT_LOG2 + 1); + +/* Verify JSOP_XXX_LENGTH constant definitions. */ +#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + JS_STATIC_ASSERT(op##_LENGTH == length); +#include "jsopcode.tbl" +#undef OPDEF + +static const char js_incop_strs[][3] = {"++", "--"}; +static const char js_for_each_str[] = "for each"; + +const JSCodeSpec js_CodeSpec[] = { +#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + {length,nuses,ndefs,prec,format}, +#include "jsopcode.tbl" +#undef OPDEF +}; + +uintN js_NumCodeSpecs = JS_ARRAY_LENGTH(js_CodeSpec); + +/* + * Each element of the array is either a source literal associated with JS + * bytecode or null. + */ +static const char *CodeToken[] = { +#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + token, +#include "jsopcode.tbl" +#undef OPDEF +}; + +#if defined(DEBUG) || defined(JS_JIT_SPEW) || defined(JS_METHODJIT_SPEW) +/* + * Array of JS bytecode names used by DEBUG-only js_Disassemble and by + * JIT debug spew. + */ +const char *js_CodeName[] = { +#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + name, +#include "jsopcode.tbl" +#undef OPDEF +}; +#endif + +/************************************************************************/ + +static ptrdiff_t +GetJumpOffset(jsbytecode *pc, jsbytecode *pc2) +{ + uint32 type; + + type = JOF_OPTYPE(*pc); + if (JOF_TYPE_IS_EXTENDED_JUMP(type)) + return GET_JUMPX_OFFSET(pc2); + return GET_JUMP_OFFSET(pc2); +} + +uintN +js_GetIndexFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, + ptrdiff_t pcoff) +{ + JSOp op; + uintN span, base; + + op = js_GetOpcode(cx, script, pc); + JS_ASSERT(js_CodeSpec[op].length >= 1 + pcoff + UINT16_LEN); + + /* + * We need to detect index base prefix. It presents when resetbase + * follows the bytecode. + */ + span = js_CodeSpec[op].length; + base = 0; + if (pc - script->code + span < script->length) { + if (pc[span] == JSOP_RESETBASE) { + base = GET_INDEXBASE(pc - JSOP_INDEXBASE_LENGTH); + } else if (pc[span] == JSOP_RESETBASE0) { + JS_ASSERT(JSOP_INDEXBASE1 <= pc[-1] || pc[-1] <= JSOP_INDEXBASE3); + base = (pc[-1] - JSOP_INDEXBASE1 + 1) << 16; + } + } + return base + GET_UINT16(pc + pcoff); +} + +uintN +js_GetVariableBytecodeLength(jsbytecode *pc) +{ + JSOp op; + uintN jmplen, ncases; + jsint low, high; + + op = (JSOp) *pc; + JS_ASSERT(js_CodeSpec[op].length == -1); + switch (op) { + case JSOP_TABLESWITCHX: + jmplen = JUMPX_OFFSET_LEN; + goto do_table; + case JSOP_TABLESWITCH: + jmplen = JUMP_OFFSET_LEN; + do_table: + /* Structure: default-jump case-low case-high case1-jump ... */ + pc += jmplen; + low = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + high = GET_JUMP_OFFSET(pc); + ncases = (uintN)(high - low + 1); + return 1 + jmplen + INDEX_LEN + INDEX_LEN + ncases * jmplen; + + case JSOP_LOOKUPSWITCHX: + jmplen = JUMPX_OFFSET_LEN; + goto do_lookup; + default: + JS_ASSERT(op == JSOP_LOOKUPSWITCH); + jmplen = JUMP_OFFSET_LEN; + do_lookup: + /* Structure: default-jump case-count (case1-value case1-jump) ... */ + pc += jmplen; + ncases = GET_UINT16(pc); + return 1 + jmplen + INDEX_LEN + ncases * (INDEX_LEN + jmplen); + } +} + +uintN +js_GetVariableStackUses(JSOp op, jsbytecode *pc) +{ + JS_ASSERT(*pc == op || *pc == JSOP_TRAP); + JS_ASSERT(js_CodeSpec[op].nuses == -1); + switch (op) { + case JSOP_POPN: + return GET_UINT16(pc); + case JSOP_LEAVEBLOCK: + return GET_UINT16(pc); + case JSOP_LEAVEBLOCKEXPR: + return GET_UINT16(pc) + 1; + default: + /* stack: fun, this, [argc arguments] */ + JS_ASSERT(op == JSOP_NEW || op == JSOP_CALL || op == JSOP_EVAL || + op == JSOP_FUNCALL || op == JSOP_FUNAPPLY); + return 2 + GET_ARGC(pc); + } +} + +uintN +js_GetEnterBlockStackDefs(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + JSObject *obj; + + JS_ASSERT(*pc == JSOP_ENTERBLOCK || *pc == JSOP_TRAP); + GET_OBJECT_FROM_BYTECODE(script, pc, 0, obj); + return OBJ_BLOCK_COUNT(cx, obj); +} + +class AutoScriptUntrapper { + JSContext *cx; + JSScript *script; + jsbytecode *origPC; + jsbytecode *newPC; + +public: + AutoScriptUntrapper(JSContext *cx, JSScript *script, jsbytecode **pc) + : cx(cx), script(script), origPC(*pc) + { + jsbytecode *newCode = js_UntrapScriptCode(cx, script); + if (newCode == script->code) { + // No change needed + newPC = origPC; + } else { + script->main += newCode - script->code; + *pc = newPC = origPC + (newCode - script->code); + script->code = newCode; + } + } + ~AutoScriptUntrapper() + { + ptrdiff_t delta = newPC - origPC; + if (delta) { + jsbytecode *oldCode = script->code - delta; + cx->free(script->code); + script->code = oldCode; + script->main -= delta; + } + } +}; + +#ifdef DEBUG + +/* If pc != NULL, includes a prefix indicating whether the PC is at the current line. */ +JS_FRIEND_API(JSBool) +js_DisassembleAtPC(JSContext *cx, JSScript *script, JSBool lines, FILE *fp, jsbytecode *pc) +{ + jsbytecode *next, *end; + uintN len; + + next = script->code; + end = next + script->length; + while (next < end) { + if (next == script->main) + fputs("main:\n", fp); + if (pc != NULL) { + if (pc == next) + fputs("--> ", fp); + else + fputs(" ", fp); + } + len = js_Disassemble1(cx, script, next, + next - script->code, + lines, fp); + if (!len) + return JS_FALSE; + next += len; + } + return JS_TRUE; +} + +JS_FRIEND_API(JSBool) +js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp) +{ + return js_DisassembleAtPC(cx, script, lines, fp, NULL); +} + +JS_FRIEND_API(JSBool) +js_DumpPC(JSContext *cx) +{ + return js_DisassembleAtPC(cx, cx->fp()->script(), true, stdout, cx->regs->pc); +} + +JSBool +js_DumpScript(JSContext *cx, JSScript *script) +{ + return js_Disassemble(cx, script, true, stdout); +} + +static bool +ToDisassemblySource(JSContext *cx, jsval v, JSAutoByteString *bytes) +{ + if (!JSVAL_IS_PRIMITIVE(v)) { + JSObject *obj = JSVAL_TO_OBJECT(v); + Class *clasp = obj->getClass(); + + if (clasp == &js_BlockClass) { + char *source = JS_sprintf_append(NULL, "depth %d {", OBJ_BLOCK_DEPTH(cx, obj)); + if (!source) + return false; + + Shape::Range r = obj->lastProperty()->all(); + while (!r.empty()) { + const Shape &shape = r.front(); + JSAutoByteString bytes; + if (!js_AtomToPrintableString(cx, JSID_TO_ATOM(shape.id), &bytes)) + return false; + + r.popFront(); + source = JS_sprintf_append(source, "%s: %d%s", + bytes.ptr(), shape.shortid, + !r.empty() ? ", " : ""); + if (!source) + return false; + } + + source = JS_sprintf_append(source, "}"); + if (!source) + return false; + bytes->initBytes(source); + return true; + } + + if (clasp == &js_FunctionClass) { + JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj); + JSString *str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT); + if (!str) + return false; + return bytes->encode(cx, str); + } + + if (clasp == &js_RegExpClass) { + AutoValueRooter tvr(cx); + if (!js_regexp_toString(cx, obj, tvr.addr())) + return false; + return bytes->encode(cx, JSVAL_TO_STRING(Jsvalify(tvr.value()))); + } + } + + return !!js_ValueToPrintable(cx, Valueify(v), bytes, true); +} + +JS_FRIEND_API(uintN) +js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, + uintN loc, JSBool lines, FILE *fp) +{ + JSOp op; + const JSCodeSpec *cs; + ptrdiff_t len, off, jmplen; + uint32 type; + JSAtom *atom; + uintN index; + JSObject *obj; + jsval v; + jsint i; + + AutoScriptUntrapper untrapper(cx, script, &pc); + + op = (JSOp)*pc; + if (op >= JSOP_LIMIT) { + char numBuf1[12], numBuf2[12]; + JS_snprintf(numBuf1, sizeof numBuf1, "%d", op); + JS_snprintf(numBuf2, sizeof numBuf2, "%d", JSOP_LIMIT); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BYTECODE_TOO_BIG, numBuf1, numBuf2); + return 0; + } + cs = &js_CodeSpec[op]; + len = (ptrdiff_t) cs->length; + fprintf(fp, "%05u:", loc); + if (lines) + fprintf(fp, "%4u", JS_PCToLineNumber(cx, script, pc)); + fprintf(fp, " %s", js_CodeName[op]); + type = JOF_TYPE(cs->format); + switch (type) { + case JOF_BYTE: + break; + + case JOF_JUMP: + case JOF_JUMPX: + off = GetJumpOffset(pc, pc); + fprintf(fp, " %u (%d)", loc + (intN) off, (intN) off); + break; + + case JOF_ATOM: + case JOF_OBJECT: + case JOF_REGEXP: + index = js_GetIndexFromBytecode(cx, script, pc, 0); + if (type == JOF_ATOM) { + if (op == JSOP_DOUBLE) { + v = Jsvalify(script->getConst(index)); + } else { + JS_GET_SCRIPT_ATOM(script, pc, index, atom); + v = ATOM_TO_JSVAL(atom); + } + } else { + if (type == JOF_OBJECT) + obj = script->getObject(index); + else + obj = script->getRegExp(index); + v = OBJECT_TO_JSVAL(obj); + } + { + JSAutoByteString bytes; + if (!ToDisassemblySource(cx, v, &bytes)) + return 0; + fprintf(fp, " %s", bytes.ptr()); + } + break; + + case JOF_GLOBAL: + atom = script->getGlobalAtom(GET_SLOTNO(pc)); + v = ATOM_TO_JSVAL(atom); + { + JSAutoByteString bytes; + if (!ToDisassemblySource(cx, v, &bytes)) + return 0; + fprintf(fp, " %s", bytes.ptr()); + } + break; + + case JOF_UINT16PAIR: + i = (jsint)GET_UINT16(pc); + fprintf(fp, " %d", i); + pc += UINT16_LEN; + /* FALL THROUGH */ + + case JOF_UINT16: + i = (jsint)GET_UINT16(pc); + goto print_int; + + case JOF_TABLESWITCH: + case JOF_TABLESWITCHX: + { + jsbytecode *pc2; + jsint i, low, high; + + jmplen = (type == JOF_TABLESWITCH) ? JUMP_OFFSET_LEN + : JUMPX_OFFSET_LEN; + pc2 = pc; + off = GetJumpOffset(pc, pc2); + pc2 += jmplen; + low = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + high = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + fprintf(fp, " defaultOffset %d low %d high %d", (intN) off, low, high); + for (i = low; i <= high; i++) { + off = GetJumpOffset(pc, pc2); + fprintf(fp, "\n\t%d: %d", i, (intN) off); + pc2 += jmplen; + } + len = 1 + pc2 - pc; + break; + } + + case JOF_LOOKUPSWITCH: + case JOF_LOOKUPSWITCHX: + { + jsbytecode *pc2; + jsatomid npairs; + + jmplen = (type == JOF_LOOKUPSWITCH) ? JUMP_OFFSET_LEN + : JUMPX_OFFSET_LEN; + pc2 = pc; + off = GetJumpOffset(pc, pc2); + pc2 += jmplen; + npairs = GET_UINT16(pc2); + pc2 += UINT16_LEN; + fprintf(fp, " offset %d npairs %u", (intN) off, (uintN) npairs); + while (npairs) { + uint16 constIndex = GET_INDEX(pc2); + pc2 += INDEX_LEN; + off = GetJumpOffset(pc, pc2); + pc2 += jmplen; + + JSAutoByteString bytes; + if (!ToDisassemblySource(cx, Jsvalify(script->getConst(constIndex)), &bytes)) + return 0; + fprintf(fp, "\n\t%s: %d", bytes.ptr(), (intN) off); + npairs--; + } + len = 1 + pc2 - pc; + break; + } + + case JOF_QARG: + fprintf(fp, " %u", GET_ARGNO(pc)); + break; + + case JOF_LOCAL: + fprintf(fp, " %u", GET_SLOTNO(pc)); + break; + + case JOF_SLOTATOM: + case JOF_SLOTOBJECT: { + fprintf(fp, " %u", GET_SLOTNO(pc)); + index = js_GetIndexFromBytecode(cx, script, pc, SLOTNO_LEN); + if (type == JOF_SLOTATOM) { + JS_GET_SCRIPT_ATOM(script, pc, index, atom); + v = ATOM_TO_JSVAL(atom); + } else { + obj = script->getObject(index); + v = OBJECT_TO_JSVAL(obj); + } + + JSAutoByteString bytes; + if (!ToDisassemblySource(cx, v, &bytes)) + return 0; + fprintf(fp, " %s", bytes.ptr()); + break; + } + + case JOF_UINT24: + JS_ASSERT(op == JSOP_UINT24 || op == JSOP_NEWARRAY); + i = (jsint)GET_UINT24(pc); + goto print_int; + + case JOF_UINT8: + i = pc[1]; + goto print_int; + + case JOF_INT8: + i = GET_INT8(pc); + goto print_int; + + case JOF_INT32: + JS_ASSERT(op == JSOP_INT32); + i = GET_INT32(pc); + print_int: + fprintf(fp, " %d", i); + break; + + default: { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) cs->format); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_UNKNOWN_FORMAT, numBuf); + return 0; + } + } + fputs("\n", fp); + return len; +} + +#endif /* DEBUG */ + +/************************************************************************/ + +/* + * Sprintf, but with unlimited and automatically allocated buffering. + */ +typedef struct Sprinter { + JSContext *context; /* context executing the decompiler */ + JSArenaPool *pool; /* string allocation pool */ + char *base; /* base address of buffer in pool */ + size_t size; /* size of buffer allocated at base */ + ptrdiff_t offset; /* offset of next free char in buffer */ +} Sprinter; + +#define INIT_SPRINTER(cx, sp, ap, off) \ + ((sp)->context = cx, (sp)->pool = ap, (sp)->base = NULL, (sp)->size = 0, \ + (sp)->offset = off) + +#define OFF2STR(sp,off) ((sp)->base + (off)) +#define STR2OFF(sp,str) ((str) - (sp)->base) +#define RETRACT(sp,str) ((sp)->offset = STR2OFF(sp, str)) + +static JSBool +SprintEnsureBuffer(Sprinter *sp, size_t len) +{ + ptrdiff_t nb; + char *base; + + nb = (sp->offset + len + 1) - sp->size; + if (nb < 0) + return JS_TRUE; + base = sp->base; + if (!base) { + JS_ARENA_ALLOCATE_CAST(base, char *, sp->pool, nb); + } else { + JS_ARENA_GROW_CAST(base, char *, sp->pool, sp->size, nb); + } + if (!base) { + js_ReportOutOfScriptQuota(sp->context); + return JS_FALSE; + } + sp->base = base; + sp->size += nb; + return JS_TRUE; +} + +static ptrdiff_t +SprintPut(Sprinter *sp, const char *s, size_t len) +{ + ptrdiff_t offset = sp->size; /* save old size */ + char *bp = sp->base; /* save old base */ + + /* Allocate space for s, including the '\0' at the end. */ + if (!SprintEnsureBuffer(sp, len)) + return -1; + + if (sp->base != bp && /* buffer was realloc'ed */ + s >= bp && s < bp + offset) { /* s was within the buffer */ + s = sp->base + (s - bp); /* this is where it lives now */ + } + + /* Advance offset and copy s into sp's buffer. */ + offset = sp->offset; + sp->offset += len; + bp = sp->base + offset; + memmove(bp, s, len); + bp[len] = 0; + return offset; +} + +static ptrdiff_t +SprintCString(Sprinter *sp, const char *s) +{ + return SprintPut(sp, s, strlen(s)); +} + +static ptrdiff_t +SprintString(Sprinter *sp, JSString *str) +{ + size_t length = str->length(); + const jschar *chars = str->getChars(sp->context); + if (!chars) + return -1; + + size_t size = js_GetDeflatedStringLength(sp->context, chars, length); + if (size == (size_t)-1 || !SprintEnsureBuffer(sp, size)) + return -1; + + ptrdiff_t offset = sp->offset; + sp->offset += size; + js_DeflateStringToBuffer(sp->context, chars, length, sp->base + offset, + &size); + sp->base[sp->offset] = 0; + return offset; +} + + +static ptrdiff_t +Sprint(Sprinter *sp, const char *format, ...) +{ + va_list ap; + char *bp; + ptrdiff_t offset; + + va_start(ap, format); + bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */ + va_end(ap); + if (!bp) { + JS_ReportOutOfMemory(sp->context); + return -1; + } + offset = SprintCString(sp, bp); + js_free(bp); + return offset; +} + +const char js_EscapeMap[] = { + '\b', 'b', + '\f', 'f', + '\n', 'n', + '\r', 'r', + '\t', 't', + '\v', 'v', + '"', '"', + '\'', '\'', + '\\', '\\', + '\0', '0' +}; + +#define DONT_ESCAPE 0x10000 + +static char * +QuoteString(Sprinter *sp, JSString *str, uint32 quote) +{ + /* Sample off first for later return value pointer computation. */ + JSBool dontEscape = (quote & DONT_ESCAPE) != 0; + jschar qc = (jschar) quote; + ptrdiff_t off = sp->offset; + if (qc && Sprint(sp, "%c", (char)qc) < 0) + return NULL; + + const jschar *s = str->getChars(sp->context); + if (!s) + return NULL; + const jschar *z = s + str->length(); + + /* Loop control variables: z points at end of string sentinel. */ + for (const jschar *t = s; t < z; s = ++t) { + /* Move t forward from s past un-quote-worthy characters. */ + jschar c = *t; + while (JS_ISPRINT(c) && c != qc && c != '\\' && c != '\t' && + !(c >> 8)) { + c = *++t; + if (t == z) + break; + } + ptrdiff_t len = t - s; + + /* Allocate space for s, including the '\0' at the end. */ + if (!SprintEnsureBuffer(sp, len)) + return NULL; + + /* Advance sp->offset and copy s into sp's buffer. */ + char *bp = sp->base + sp->offset; + sp->offset += len; + while (--len >= 0) + *bp++ = (char) *s++; + *bp = '\0'; + + if (t == z) + break; + + /* Use js_EscapeMap, \u, or \x only if necessary. */ + bool ok; + const char *e; + if (!(c >> 8) && (e = strchr(js_EscapeMap, (int)c)) != NULL) { + ok = dontEscape + ? Sprint(sp, "%c", (char)c) >= 0 + : Sprint(sp, "\\%c", e[1]) >= 0; + } else { + /* + * Use \x only if the high byte is 0 and we're in a quoted string, + * because ECMA-262 allows only \u, not \x, in Unicode identifiers + * (see bug 621814). + */ + ok = Sprint(sp, (qc && !(c >> 8)) ? "\\x%02X" : "\\u%04X", c) >= 0; + } + if (!ok) + return NULL; + } + + /* Sprint the closing quote and return the quoted string. */ + if (qc && Sprint(sp, "%c", (char)qc) < 0) + return NULL; + + /* + * If we haven't Sprint'd anything yet, Sprint an empty string so that + * the OFF2STR below gives a valid result. + */ + if (off == sp->offset && Sprint(sp, "") < 0) + return NULL; + return OFF2STR(sp, off); +} + +JSString * +js_QuoteString(JSContext *cx, JSString *str, jschar quote) +{ + void *mark; + Sprinter sprinter; + char *bytes; + JSString *escstr; + + mark = JS_ARENA_MARK(&cx->tempPool); + INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0); + bytes = QuoteString(&sprinter, str, quote); + escstr = bytes ? JS_NewStringCopyZ(cx, bytes) : NULL; + JS_ARENA_RELEASE(&cx->tempPool, mark); + return escstr; +} + +/************************************************************************/ + +struct JSPrinter { + Sprinter sprinter; /* base class state */ + JSArenaPool pool; /* string allocation pool */ + uintN indent; /* indentation in spaces */ + bool pretty; /* pretty-print: indent, use newlines */ + bool grouped; /* in parenthesized expression context */ + bool strict; /* in code marked strict */ + JSScript *script; /* script being printed */ + jsbytecode *dvgfence; /* DecompileExpression fencepost */ + jsbytecode **pcstack; /* DecompileExpression modeled stack */ + JSFunction *fun; /* interpreted function */ + jsuword *localNames; /* argument and variable names */ +}; + +JSPrinter * +js_NewPrinter(JSContext *cx, const char *name, JSFunction *fun, + uintN indent, JSBool pretty, JSBool grouped, JSBool strict) +{ + JSPrinter *jp; + + jp = (JSPrinter *) cx->malloc(sizeof(JSPrinter)); + if (!jp) + return NULL; + INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0); + JS_InitArenaPool(&jp->pool, name, 256, 1, &cx->scriptStackQuota); + jp->indent = indent; + jp->pretty = !!pretty; + jp->grouped = !!grouped; + jp->strict = !!strict; + jp->script = NULL; + jp->dvgfence = NULL; + jp->pcstack = NULL; + jp->fun = fun; + jp->localNames = NULL; + if (fun && fun->isInterpreted() && fun->script()->bindings.hasLocalNames()) { + jp->localNames = fun->script()->bindings.getLocalNameArray(cx, &jp->pool); + if (!jp->localNames) { + js_DestroyPrinter(jp); + return NULL; + } + } + return jp; +} + +void +js_DestroyPrinter(JSPrinter *jp) +{ + JS_FinishArenaPool(&jp->pool); + jp->sprinter.context->free(jp); +} + +JSString * +js_GetPrinterOutput(JSPrinter *jp) +{ + JSContext *cx; + JSString *str; + + cx = jp->sprinter.context; + if (!jp->sprinter.base) + return cx->runtime->emptyString; + str = JS_NewStringCopyZ(cx, jp->sprinter.base); + if (!str) + return NULL; + JS_FreeArenaPool(&jp->pool); + INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0); + return str; +} + +/* + * NB: Indexed by SRC_DECL_* defines from jsemit.h. + */ +static const char * const var_prefix[] = {"var ", "const ", "let "}; + +static const char * +VarPrefix(jssrcnote *sn) +{ + if (sn && (SN_TYPE(sn) == SRC_DECL || SN_TYPE(sn) == SRC_GROUPASSIGN)) { + ptrdiff_t type = js_GetSrcNoteOffset(sn, 0); + if ((uintN)type <= SRC_DECL_LET) + return var_prefix[type]; + } + return ""; +} + +int +js_printf(JSPrinter *jp, const char *format, ...) +{ + va_list ap; + char *bp, *fp; + int cc; + + if (*format == '\0') + return 0; + + va_start(ap, format); + + /* If pretty-printing, expand magic tab into a run of jp->indent spaces. */ + if (*format == '\t') { + format++; + if (jp->pretty && Sprint(&jp->sprinter, "%*s", jp->indent, "") < 0) { + va_end(ap); + return -1; + } + } + + /* Suppress newlines (must be once per format, at the end) if not pretty. */ + fp = NULL; + if (!jp->pretty && format[cc = strlen(format) - 1] == '\n') { + fp = JS_strdup(jp->sprinter.context, format); + if (!fp) { + va_end(ap); + return -1; + } + fp[cc] = '\0'; + format = fp; + } + + /* Allocate temp space, convert format, and put. */ + bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */ + if (fp) { + jp->sprinter.context->free(fp); + format = NULL; + } + if (!bp) { + JS_ReportOutOfMemory(jp->sprinter.context); + va_end(ap); + return -1; + } + + cc = strlen(bp); + if (SprintPut(&jp->sprinter, bp, (size_t)cc) < 0) + cc = -1; + js_free(bp); + + va_end(ap); + return cc; +} + +JSBool +js_puts(JSPrinter *jp, const char *s) +{ + return SprintCString(&jp->sprinter, s) >= 0; +} + +/************************************************************************/ + +typedef struct SprintStack { + Sprinter sprinter; /* sprinter for postfix to infix buffering */ + ptrdiff_t *offsets; /* stack of postfix string offsets */ + jsbytecode *opcodes; /* parallel stack of JS opcodes */ + uintN top; /* top of stack index */ + uintN inArrayInit; /* array initialiser/comprehension level */ + JSBool inGenExp; /* in generator expression */ + JSPrinter *printer; /* permanent output goes here */ +} SprintStack; + +/* + * Find the depth of the operand stack when the interpreter reaches the given + * pc in script. pcstack must have space for least script->depth elements. On + * return it will contain pointers to opcodes that populated the interpreter's + * current operand stack. + * + * This function cannot raise an exception or error. However, due to a risk of + * potential bugs when modeling the stack, the function returns -1 if it + * detects an inconsistency in the model. Such an inconsistency triggers an + * assert in a debug build. + */ +static intN +ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *pc, + jsbytecode **pcstack); + +#define FAILED_EXPRESSION_DECOMPILER ((char *) 1) + +/* + * Decompile a part of expression up to the given pc. The function returns + * NULL on out-of-memory, or the FAILED_EXPRESSION_DECOMPILER sentinel when + * the decompiler fails due to a bug and/or unimplemented feature, or the + * decompiled string on success. + */ +static char * +DecompileExpression(JSContext *cx, JSScript *script, JSFunction *fun, + jsbytecode *pc); + +/* + * Get a stacked offset from ss->sprinter.base, or if the stacked value |off| + * is negative, fetch the generating pc from printer->pcstack[-2 - off] and + * decompile the code that generated the missing value. This is used when + * reporting errors, where the model stack will lack |pcdepth| non-negative + * offsets (see DecompileExpression and DecompileCode). + * + * If the stacked offset is -1, return 0 to index the NUL padding at the start + * of ss->sprinter.base. If this happens, it means there is a decompiler bug + * to fix, but it won't violate memory safety. + */ +static ptrdiff_t +GetOff(SprintStack *ss, uintN i) +{ + ptrdiff_t off; + jsbytecode *pc; + char *bytes; + + off = ss->offsets[i]; + if (off >= 0) + return off; + + JS_ASSERT(off <= -2); + JS_ASSERT(ss->printer->pcstack); + if (off <= -2 && ss->printer->pcstack) { + pc = ss->printer->pcstack[-2 - off]; + bytes = DecompileExpression(ss->sprinter.context, ss->printer->script, + ss->printer->fun, pc); + if (!bytes) + return 0; + if (bytes != FAILED_EXPRESSION_DECOMPILER) { + off = SprintCString(&ss->sprinter, bytes); + if (off < 0) + off = 0; + ss->offsets[i] = off; + ss->sprinter.context->free(bytes); + return off; + } + if (!ss->sprinter.base && SprintPut(&ss->sprinter, "", 0) >= 0) { + memset(ss->sprinter.base, 0, ss->sprinter.offset); + ss->offsets[i] = -1; + } + } + return 0; +} + +static const char * +GetStr(SprintStack *ss, uintN i) +{ + ptrdiff_t off; + + /* + * Must call GetOff before using ss->sprinter.base, since it may be null + * until bootstrapped by GetOff. + */ + off = GetOff(ss, i); + return OFF2STR(&ss->sprinter, off); +} + +/* + * Gap between stacked strings to allow for insertion of parens and commas + * when auto-parenthesizing expressions and decompiling array initialisers. + */ +#define PAREN_SLOP (2 + 1) + +/* Fake opcodes (see jsopcode.h) must not overflow unsigned 8-bit space. */ +JS_STATIC_ASSERT(JSOP_FAKE_LIMIT <= 255); + +static void +AddParenSlop(SprintStack *ss) +{ + memset(OFF2STR(&ss->sprinter, ss->sprinter.offset), 0, PAREN_SLOP); + ss->sprinter.offset += PAREN_SLOP; +} + +static JSBool +PushOff(SprintStack *ss, ptrdiff_t off, JSOp op) +{ + uintN top; + + if (!SprintEnsureBuffer(&ss->sprinter, PAREN_SLOP)) + return JS_FALSE; + + /* ss->top points to the next free slot; be paranoid about overflow. */ + top = ss->top; + JS_ASSERT(top < StackDepth(ss->printer->script)); + if (top >= StackDepth(ss->printer->script)) { + JS_ReportOutOfMemory(ss->sprinter.context); + return JS_FALSE; + } + + /* The opcodes stack must contain real bytecodes that index js_CodeSpec. */ + ss->offsets[top] = off; + ss->opcodes[top] = jsbytecode((op == JSOP_GETPROP2) ? JSOP_GETPROP + : (op == JSOP_GETELEM2) ? JSOP_GETELEM + : op); + ss->top = ++top; + AddParenSlop(ss); + return JS_TRUE; +} + +static ptrdiff_t +PopOffPrec(SprintStack *ss, uint8 prec) +{ + uintN top; + const JSCodeSpec *topcs; + ptrdiff_t off; + + /* ss->top points to the next free slot; be paranoid about underflow. */ + top = ss->top; + JS_ASSERT(top != 0); + if (top == 0) + return 0; + + ss->top = --top; + off = GetOff(ss, top); + topcs = &js_CodeSpec[ss->opcodes[top]]; + if (topcs->prec != 0 && topcs->prec < prec) { + ss->sprinter.offset = ss->offsets[top] = off - 2; + off = Sprint(&ss->sprinter, "(%s)", OFF2STR(&ss->sprinter, off)); + } else { + ss->sprinter.offset = off; + } + return off; +} + +static const char * +PopStrPrec(SprintStack *ss, uint8 prec) +{ + ptrdiff_t off; + + off = PopOffPrec(ss, prec); + return OFF2STR(&ss->sprinter, off); +} + +static ptrdiff_t +PopOff(SprintStack *ss, JSOp op) +{ + return PopOffPrec(ss, js_CodeSpec[op].prec); +} + +static const char * +PopStr(SprintStack *ss, JSOp op) +{ + return PopStrPrec(ss, js_CodeSpec[op].prec); +} + +static inline bool +IsInitializerOp(unsigned char op) +{ + return op == JSOP_NEWINIT || op == JSOP_NEWARRAY || op == JSOP_NEWOBJECT; +} + +typedef struct TableEntry { + jsval key; + ptrdiff_t offset; + JSAtom *label; + jsint order; /* source order for stable tableswitch sort */ +} TableEntry; + +static JSBool +CompareOffsets(void *arg, const void *v1, const void *v2, int *result) +{ + ptrdiff_t offset_diff; + const TableEntry *te1 = (const TableEntry *) v1, + *te2 = (const TableEntry *) v2; + + offset_diff = te1->offset - te2->offset; + *result = (offset_diff == 0 ? te1->order - te2->order + : offset_diff < 0 ? -1 + : 1); + return JS_TRUE; +} + +static ptrdiff_t +SprintDoubleValue(Sprinter *sp, jsval v, JSOp *opp) +{ + jsdouble d; + ptrdiff_t todo; + char *s; + + JS_ASSERT(JSVAL_IS_DOUBLE(v)); + d = JSVAL_TO_DOUBLE(v); + if (JSDOUBLE_IS_NEGZERO(d)) { + todo = SprintCString(sp, "-0"); + *opp = JSOP_NEG; + } else if (!JSDOUBLE_IS_FINITE(d)) { + /* Don't use Infinity and NaN, they're mutable. */ + todo = SprintCString(sp, + JSDOUBLE_IS_NaN(d) + ? "0 / 0" + : (d < 0) + ? "1 / -0" + : "1 / 0"); + *opp = JSOP_DIV; + } else { + ToCStringBuf cbuf; + s = NumberToCString(sp->context, &cbuf, d); + if (!s) { + JS_ReportOutOfMemory(sp->context); + return -1; + } + JS_ASSERT(strcmp(s, js_Infinity_str) && + (*s != '-' || + strcmp(s + 1, js_Infinity_str)) && + strcmp(s, js_NaN_str)); + todo = Sprint(sp, s); + } + return todo; +} + +static jsbytecode * +Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop); + +static JSBool +DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength, + jsbytecode *pc, ptrdiff_t switchLength, + ptrdiff_t defaultOffset, JSBool isCondSwitch) +{ + JSContext *cx; + JSPrinter *jp; + ptrdiff_t off, off2, diff, caseExprOff, todo; + char *lval, *rval; + uintN i; + jsval key; + JSString *str; + + cx = ss->sprinter.context; + jp = ss->printer; + + /* JSOP_CONDSWITCH doesn't pop, unlike JSOP_{LOOKUP,TABLE}SWITCH. */ + off = isCondSwitch ? GetOff(ss, ss->top-1) : PopOff(ss, JSOP_NOP); + lval = OFF2STR(&ss->sprinter, off); + + js_printf(jp, "\tswitch (%s) {\n", lval); + + if (tableLength) { + diff = table[0].offset - defaultOffset; + if (diff > 0) { + jp->indent += 2; + js_printf(jp, "\t%s:\n", js_default_str); + jp->indent += 2; + if (!Decompile(ss, pc + defaultOffset, diff, JSOP_NOP)) + return JS_FALSE; + jp->indent -= 4; + } + + caseExprOff = isCondSwitch ? JSOP_CONDSWITCH_LENGTH : 0; + + for (i = 0; i < tableLength; i++) { + off = table[i].offset; + off2 = (i + 1 < tableLength) ? table[i + 1].offset : switchLength; + + key = table[i].key; + if (isCondSwitch) { + ptrdiff_t nextCaseExprOff; + + /* + * key encodes the JSOP_CASE bytecode's offset from switchtop. + * The next case expression follows immediately, unless we are + * at the last case. + */ + nextCaseExprOff = (ptrdiff_t)JSVAL_TO_INT(key); + nextCaseExprOff += js_CodeSpec[pc[nextCaseExprOff]].length; + jp->indent += 2; + if (!Decompile(ss, pc + caseExprOff, + nextCaseExprOff - caseExprOff, JSOP_NOP)) { + return JS_FALSE; + } + caseExprOff = nextCaseExprOff; + + /* Balance the stack as if this JSOP_CASE matched. */ + --ss->top; + } else { + /* + * key comes from an atom, not the decompiler, so we need to + * quote it if it's a string literal. But if table[i].label + * is non-null, key was constant-propagated and label is the + * name of the const we should show as the case label. We set + * key to undefined so this identifier is escaped, if required + * by non-ASCII characters, but not quoted, by QuoteString. + */ + todo = -1; + if (table[i].label) { + str = ATOM_TO_STRING(table[i].label); + key = JSVAL_VOID; + } else if (JSVAL_IS_DOUBLE(key)) { + JSOp junk; + + todo = SprintDoubleValue(&ss->sprinter, key, &junk); + str = NULL; + } else { + str = js_ValueToString(cx, Valueify(key)); + if (!str) + return JS_FALSE; + } + if (todo >= 0) { + rval = OFF2STR(&ss->sprinter, todo); + } else { + rval = QuoteString(&ss->sprinter, str, (jschar) + (JSVAL_IS_STRING(key) ? '"' : 0)); + if (!rval) + return JS_FALSE; + } + RETRACT(&ss->sprinter, rval); + jp->indent += 2; + js_printf(jp, "\tcase %s:\n", rval); + } + + jp->indent += 2; + if (off <= defaultOffset && defaultOffset < off2) { + diff = defaultOffset - off; + if (diff != 0) { + if (!Decompile(ss, pc + off, diff, JSOP_NOP)) + return JS_FALSE; + off = defaultOffset; + } + jp->indent -= 2; + js_printf(jp, "\t%s:\n", js_default_str); + jp->indent += 2; + } + if (!Decompile(ss, pc + off, off2 - off, JSOP_NOP)) + return JS_FALSE; + jp->indent -= 4; + + /* Re-balance as if last JSOP_CASE or JSOP_DEFAULT mismatched. */ + if (isCondSwitch) + ++ss->top; + } + } + + if (defaultOffset == switchLength) { + jp->indent += 2; + js_printf(jp, "\t%s:;\n", js_default_str); + jp->indent -= 2; + } + js_printf(jp, "\t}\n"); + + /* By the end of a JSOP_CONDSWITCH, the discriminant has been popped. */ + if (isCondSwitch) + --ss->top; + return JS_TRUE; +} + +#define LOCAL_ASSERT_CUSTOM(expr, BAD_EXIT) \ + JS_BEGIN_MACRO \ + JS_ASSERT(expr); \ + if (!(expr)) { BAD_EXIT; } \ + JS_END_MACRO + +#define LOCAL_ASSERT_RV(expr, rv) \ + LOCAL_ASSERT_CUSTOM(expr, return (rv)) + +static JSAtom * +GetArgOrVarAtom(JSPrinter *jp, uintN slot) +{ + JSAtom *name; + + LOCAL_ASSERT_RV(jp->fun, NULL); + LOCAL_ASSERT_RV(slot < jp->fun->script()->bindings.countLocalNames(), NULL); + name = JS_LOCAL_NAME_TO_ATOM(jp->localNames[slot]); +#if !JS_HAS_DESTRUCTURING + LOCAL_ASSERT_RV(name, NULL); +#endif + return name; +} + +const char * +GetLocal(SprintStack *ss, jsint i) +{ +#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, "") + + ptrdiff_t off = ss->offsets[i]; + if (off >= 0) + return OFF2STR(&ss->sprinter, off); + + /* + * We must be called from js_DecompileValueGenerator (via Decompile) when + * dereferencing a local that's undefined or null. Search script->objects + * for the block containing this local by its stack index, i. + * + * In case of destructuring's use of JSOP_GETLOCAL, however, there may be + * no such local. This could mean no blocks (no script objects at all, or + * none of the script's object literals are blocks), or the stack slot i is + * not in a block. In either case, return GetStr(ss, i). + */ + JSScript *script = ss->printer->script; + if (!JSScript::isValidOffset(script->objectsOffset)) + return GetStr(ss, i); + + for (jsatomid j = 0, n = script->objects()->length; j != n; j++) { + JSObject *obj = script->getObject(j); + if (obj->isBlock()) { + jsint depth = OBJ_BLOCK_DEPTH(cx, obj); + jsint count = OBJ_BLOCK_COUNT(cx, obj); + + if (jsuint(i - depth) < jsuint(count)) { + jsint slot = i - depth; + + for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) { + const Shape &shape = r.front(); + + if (shape.shortid == slot) { + LOCAL_ASSERT(JSID_IS_ATOM(shape.id)); + + JSAtom *atom = JSID_TO_ATOM(shape.id); + const char *rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval) + return NULL; + + RETRACT(&ss->sprinter, rval); + return rval; + } + } + + break; + } + } + } + + return GetStr(ss, i); + +#undef LOCAL_ASSERT +} + +static JSBool +IsVarSlot(JSPrinter *jp, jsbytecode *pc, jsint *indexp) +{ + uintN slot; + + slot = GET_SLOTNO(pc); + if (slot < jp->script->nfixed) { + /* The slot refers to a variable with name stored in jp->localNames. */ + *indexp = jp->fun->nargs + slot; + return JS_TRUE; + } + + /* We have a local which index is relative to the stack base. */ + slot -= jp->script->nfixed; + JS_ASSERT(slot < StackDepth(jp->script)); + *indexp = slot; + return JS_FALSE; +} + +#define LOAD_ATOM(PCOFF) \ + GET_ATOM_FROM_BYTECODE(jp->script, pc, PCOFF, atom) + +#if JS_HAS_DESTRUCTURING + +#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, NULL) +#define LOAD_OP_DATA(pc) (oplen = (cs = &js_CodeSpec[op=(JSOp)*pc])->length) + +static jsbytecode * +DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc); + +static jsbytecode * +DecompileDestructuringLHS(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, + JSBool *hole) +{ + JSContext *cx; + JSPrinter *jp; + JSOp op; + const JSCodeSpec *cs; + uintN oplen; + jsint i; + const char *lval, *xval; + ptrdiff_t todo; + JSAtom *atom; + + *hole = JS_FALSE; + cx = ss->sprinter.context; + jp = ss->printer; + LOAD_OP_DATA(pc); + + switch (op) { + case JSOP_POP: + *hole = JS_TRUE; + todo = SprintPut(&ss->sprinter, ", ", 2); + break; + + case JSOP_DUP: + pc = DecompileDestructuring(ss, pc, endpc); + if (!pc) + return NULL; + if (pc == endpc) + return pc; + LOAD_OP_DATA(pc); + lval = PopStr(ss, JSOP_NOP); + todo = SprintCString(&ss->sprinter, lval); + if (op == JSOP_POPN) + return pc; + LOCAL_ASSERT(*pc == JSOP_POP); + break; + + case JSOP_SETARG: + case JSOP_SETLOCAL: + LOCAL_ASSERT(pc[oplen] == JSOP_POP || pc[oplen] == JSOP_POPN); + /* FALL THROUGH */ + + case JSOP_SETLOCALPOP: + atom = NULL; + lval = NULL; + if (op == JSOP_SETARG) { + atom = GetArgOrVarAtom(jp, GET_SLOTNO(pc)); + LOCAL_ASSERT(atom); + } else if (IsVarSlot(jp, pc, &i)) { + atom = GetArgOrVarAtom(jp, i); + LOCAL_ASSERT(atom); + } else { + lval = GetLocal(ss, i); + } + { + JSAutoByteString bytes; + if (atom) + lval = js_AtomToPrintableString(cx, atom, &bytes); + LOCAL_ASSERT(lval); + todo = SprintCString(&ss->sprinter, lval); + } + if (op != JSOP_SETLOCALPOP) { + pc += oplen; + if (pc == endpc) + return pc; + LOAD_OP_DATA(pc); + if (op == JSOP_POPN) + return pc; + LOCAL_ASSERT(op == JSOP_POP); + } + break; + + default: + /* + * We may need to auto-parenthesize the left-most value decompiled + * here, so add back PAREN_SLOP temporarily. Then decompile until the + * opcode that would reduce the stack depth to (ss->top-1), which we + * pass to Decompile encoded as -(ss->top-1) - 1 or just -ss->top for + * the nb parameter. + */ + todo = ss->sprinter.offset; + ss->sprinter.offset = todo + PAREN_SLOP; + pc = Decompile(ss, pc, -((intN)ss->top), JSOP_NOP); + if (!pc) + return NULL; + if (pc == endpc) + return pc; + LOAD_OP_DATA(pc); + LOCAL_ASSERT(op == JSOP_ENUMELEM || op == JSOP_ENUMCONSTELEM); + xval = PopStr(ss, JSOP_NOP); + lval = PopStr(ss, JSOP_GETPROP); + ss->sprinter.offset = todo; + if (*lval == '\0') { + /* lval is from JSOP_BINDNAME, so just print xval. */ + todo = SprintCString(&ss->sprinter, xval); + } else if (*xval == '\0') { + /* xval is from JSOP_SETCALL or JSOP_BINDXMLNAME, print lval. */ + todo = SprintCString(&ss->sprinter, lval); + } else { + todo = Sprint(&ss->sprinter, + (JOF_OPMODE(ss->opcodes[ss->top+1]) == JOF_XMLNAME) + ? "%s.%s" + : "%s[%s]", + lval, xval); + } + break; + } + + if (todo < 0) + return NULL; + + LOCAL_ASSERT(pc < endpc); + pc += oplen; + return pc; +} + +/* + * Starting with a SRC_DESTRUCT-annotated JSOP_DUP, decompile a destructuring + * left-hand side object or array initialiser, including nested destructuring + * initialisers. On successful return, the decompilation will be pushed on ss + * and the return value will point to the POP or GROUP bytecode following the + * destructuring expression. + * + * At any point, if pc is equal to endpc and would otherwise advance, we stop + * immediately and return endpc. + */ +static jsbytecode * +DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc) +{ + ptrdiff_t head; + JSContext *cx; + JSPrinter *jp; + JSOp op, saveop; + const JSCodeSpec *cs; + uintN oplen; + jsint i, lasti; + jsdouble d; + const char *lval; + JSAtom *atom; + jssrcnote *sn; + JSBool hole; + + LOCAL_ASSERT(*pc == JSOP_DUP); + pc += JSOP_DUP_LENGTH; + + /* + * Set head so we can rewrite '[' to '{' as needed. Back up PAREN_SLOP + * chars so the destructuring decompilation accumulates contiguously in + * ss->sprinter starting with "[". + */ + head = SprintPut(&ss->sprinter, "[", 1); + if (head < 0 || !PushOff(ss, head, JSOP_NOP)) + return NULL; + ss->sprinter.offset -= PAREN_SLOP; + LOCAL_ASSERT(head == ss->sprinter.offset - 1); + LOCAL_ASSERT(*OFF2STR(&ss->sprinter, head) == '['); + + cx = ss->sprinter.context; + jp = ss->printer; + lasti = -1; + + while (pc < endpc) { +#if JS_HAS_DESTRUCTURING_SHORTHAND + ptrdiff_t nameoff = -1; +#endif + + LOAD_OP_DATA(pc); + saveop = op; + + switch (op) { + case JSOP_POP: + pc += oplen; + goto out; + + /* Handle the optimized number-pushing opcodes. */ + case JSOP_ZERO: d = i = 0; goto do_getelem; + case JSOP_ONE: d = i = 1; goto do_getelem; + case JSOP_UINT16: d = i = GET_UINT16(pc); goto do_getelem; + case JSOP_UINT24: d = i = GET_UINT24(pc); goto do_getelem; + case JSOP_INT8: d = i = GET_INT8(pc); goto do_getelem; + case JSOP_INT32: d = i = GET_INT32(pc); goto do_getelem; + + case JSOP_DOUBLE: + GET_DOUBLE_FROM_BYTECODE(jp->script, pc, 0, d); + LOCAL_ASSERT(JSDOUBLE_IS_FINITE(d) && !JSDOUBLE_IS_NEGZERO(d)); + i = (jsint)d; + + do_getelem: + sn = js_GetSrcNote(jp->script, pc); + pc += oplen; + if (pc == endpc) + return pc; + LOAD_OP_DATA(pc); + LOCAL_ASSERT(op == JSOP_GETELEM); + + /* Distinguish object from array by opcode or source note. */ + if (sn && SN_TYPE(sn) == SRC_INITPROP) { + *OFF2STR(&ss->sprinter, head) = '{'; + if (Sprint(&ss->sprinter, "%g: ", d) < 0) + return NULL; + } else { + /* Sanity check for the gnarly control flow above. */ + LOCAL_ASSERT(i == d); + + /* Fill in any holes (holes at the end don't matter). */ + while (++lasti < i) { + if (SprintPut(&ss->sprinter, ", ", 2) < 0) + return NULL; + } + } + break; + + case JSOP_LENGTH: + atom = cx->runtime->atomState.lengthAtom; + goto do_destructure_atom; + + case JSOP_CALLPROP: + case JSOP_GETPROP: + LOAD_ATOM(0); + do_destructure_atom: + { + *OFF2STR(&ss->sprinter, head) = '{'; +#if JS_HAS_DESTRUCTURING_SHORTHAND + nameoff = ss->sprinter.offset; +#endif + if (!QuoteString(&ss->sprinter, atom, + js_IsIdentifier(atom) ? 0 : (jschar)'\'')) { + return NULL; + } + if (SprintPut(&ss->sprinter, ": ", 2) < 0) + return NULL; + break; + } + + default: + LOCAL_ASSERT(0); + } + + pc += oplen; + if (pc == endpc) + return pc; + + /* + * Decompile the left-hand side expression whose bytecode starts at pc + * and continues for a bounded number of bytecodes or stack operations + * (and which in any event stops before endpc). + */ + pc = DecompileDestructuringLHS(ss, pc, endpc, &hole); + if (!pc) + return NULL; + +#if JS_HAS_DESTRUCTURING_SHORTHAND + if (nameoff >= 0) { + ptrdiff_t offset, initlen; + + offset = ss->sprinter.offset; + LOCAL_ASSERT(*OFF2STR(&ss->sprinter, offset) == '\0'); + initlen = offset - nameoff; + LOCAL_ASSERT(initlen >= 4); + + /* Early check to rule out odd "name: lval" length. */ + if (((size_t)initlen & 1) == 0) { + size_t namelen; + const char *name; + + /* + * Even "name: lval" string length: check for "x: x" and the + * like, and apply the shorthand if we can. + */ + namelen = (size_t)(initlen - 2) >> 1; + name = OFF2STR(&ss->sprinter, nameoff); + if (!strncmp(name + namelen, ": ", 2) && + !strncmp(name, name + namelen + 2, namelen)) { + offset -= namelen + 2; + *OFF2STR(&ss->sprinter, offset) = '\0'; + ss->sprinter.offset = offset; + } + } + } +#endif + + if (pc == endpc || *pc != JSOP_DUP) + break; + + /* + * We should stop if JSOP_DUP is either without notes or its note is + * not SRC_CONTINUE. The former happens when JSOP_DUP duplicates the + * last destructuring reference implementing an op= assignment like in + * '([t] = z).y += x'. In the latter case the note is SRC_DESTRUCT and + * means another destructuring initialiser abuts this one like in + * '[a] = [b] = c'. + */ + sn = js_GetSrcNote(jp->script, pc); + if (!sn) + break; + if (SN_TYPE(sn) != SRC_CONTINUE) { + LOCAL_ASSERT(SN_TYPE(sn) == SRC_DESTRUCT); + break; + } + + if (!hole && SprintPut(&ss->sprinter, ", ", 2) < 0) + return NULL; + + pc += JSOP_DUP_LENGTH; + } + +out: + lval = OFF2STR(&ss->sprinter, head); + if (SprintPut(&ss->sprinter, (*lval == '[') ? "]" : "}", 1) < 0) + return NULL; + return pc; +} + +static jsbytecode * +DecompileGroupAssignment(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, + jssrcnote *sn, ptrdiff_t *todop) +{ + JSOp op; + const JSCodeSpec *cs; + uintN oplen, start, end, i; + ptrdiff_t todo; + JSBool hole; + const char *rval; + + LOAD_OP_DATA(pc); + LOCAL_ASSERT(op == JSOP_PUSH || op == JSOP_GETLOCAL); + + todo = Sprint(&ss->sprinter, "%s[", VarPrefix(sn)); + if (todo < 0 || !PushOff(ss, todo, JSOP_NOP)) + return NULL; + ss->sprinter.offset -= PAREN_SLOP; + + for (;;) { + pc += oplen; + if (pc == endpc) + return pc; + pc = DecompileDestructuringLHS(ss, pc, endpc, &hole); + if (!pc) + return NULL; + if (pc == endpc) + return pc; + LOAD_OP_DATA(pc); + if (op != JSOP_PUSH && op != JSOP_GETLOCAL) + break; + if (!hole && SprintPut(&ss->sprinter, ", ", 2) < 0) + return NULL; + } + + LOCAL_ASSERT(op == JSOP_POPN); + if (SprintPut(&ss->sprinter, "] = [", 5) < 0) + return NULL; + + end = ss->top - 1; + start = end - GET_UINT16(pc); + for (i = start; i < end; i++) { + rval = GetStr(ss, i); + if (Sprint(&ss->sprinter, + (i == start) ? "%s" : ", %s", + (i == end - 1 && *rval == '\0') ? ", " : rval) < 0) { + return NULL; + } + } + + if (SprintPut(&ss->sprinter, "]", 1) < 0) + return NULL; + ss->sprinter.offset = ss->offsets[i]; + ss->top = start; + *todop = todo; + return pc; +} + +#undef LOCAL_ASSERT +#undef LOAD_OP_DATA + +#endif /* JS_HAS_DESTRUCTURING */ + +static JSBool +InitSprintStack(JSContext *cx, SprintStack *ss, JSPrinter *jp, uintN depth) +{ + size_t offsetsz, opcodesz; + void *space; + + INIT_SPRINTER(cx, &ss->sprinter, &cx->tempPool, PAREN_SLOP); + + /* Allocate the parallel (to avoid padding) offset and opcode stacks. */ + offsetsz = depth * sizeof(ptrdiff_t); + opcodesz = depth * sizeof(jsbytecode); + JS_ARENA_ALLOCATE(space, &cx->tempPool, offsetsz + opcodesz); + if (!space) { + js_ReportOutOfScriptQuota(cx); + return JS_FALSE; + } + ss->offsets = (ptrdiff_t *) space; + ss->opcodes = (jsbytecode *) ((char *)space + offsetsz); + + ss->top = ss->inArrayInit = 0; + ss->inGenExp = JS_FALSE; + ss->printer = jp; + return JS_TRUE; +} + +/* + * If nb is non-negative, decompile nb bytecodes starting at pc. Otherwise + * the decompiler starts at pc and continues until it reaches an opcode for + * which decompiling would result in the stack depth equaling -(nb + 1). + * + * The nextop parameter is either JSOP_NOP or the "next" opcode in order of + * abstract interpretation (not necessarily physically next in a bytecode + * vector). So nextop is JSOP_POP for the last operand in a comma expression, + * or JSOP_AND for the right operand of &&. + */ +static jsbytecode * +Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) +{ + JSContext *cx; + JSPrinter *jp, *jp2; + jsbytecode *startpc, *endpc, *pc2, *done; + ptrdiff_t tail, todo, len, oplen, cond, next; + JSOp op, lastop, saveop; + const JSCodeSpec *cs; + jssrcnote *sn, *sn2; + const char *lval, *rval, *xval, *fmt, *token; + uintN nuses; + jsint i, argc; + char **argv; + JSAtom *atom; + JSObject *obj; + JSFunction *fun; + JSString *str; + JSBool ok; +#if JS_HAS_XML_SUPPORT + JSBool foreach, inXML, quoteAttr; +#else +#define inXML JS_FALSE +#endif + jsval val; + + static const char exception_cookie[] = "/*EXCEPTION*/"; + static const char retsub_pc_cookie[] = "/*RETSUB_PC*/"; + static const char forelem_cookie[] = "/*FORELEM*/"; + static const char with_cookie[] = "/*WITH*/"; + static const char dot_format[] = "%s.%s"; + static const char index_format[] = "%s[%s]"; + static const char predot_format[] = "%s%s.%s"; + static const char postdot_format[] = "%s.%s%s"; + static const char preindex_format[] = "%s%s[%s]"; + static const char postindex_format[] = "%s[%s]%s"; + static const char ss_format[] = "%s%s"; + static const char sss_format[] = "%s%s%s"; + + /* Argument and variables decompilation uses the following to share code. */ + JS_STATIC_ASSERT(ARGNO_LEN == SLOTNO_LEN); + +/* + * Local macros + */ +#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, NULL) +#define DECOMPILE_CODE(pc,nb) if (!Decompile(ss, pc, nb, JSOP_NOP)) return NULL +#define NEXT_OP(pc) (((pc) + (len) == endpc) ? nextop : pc[len]) +#define TOP_STR() GetStr(ss, ss->top - 1) +#define POP_STR() PopStr(ss, op) +#define POP_STR_PREC(prec) PopStrPrec(ss, prec) + +/* + * Pop a condition expression for if/while. JSOP_IFEQ's precedence forces + * extra parens around assignment, which avoids a strict-mode warning. + */ +#define POP_COND_STR() \ + PopStr(ss, (js_CodeSpec[ss->opcodes[ss->top - 1]].format & JOF_SET) \ + ? JSOP_IFEQ \ + : JSOP_NOP) + +#define ATOM_IS_IDENTIFIER(atom) js_IsIdentifier(atom) + +/* + * Given an atom already fetched from jp->script's atom map, quote/escape its + * string appropriately into rval, and select fmt from the quoted and unquoted + * alternatives. + */ +#define GET_QUOTE_AND_FMT(qfmt, ufmt, rval) \ + JS_BEGIN_MACRO \ + jschar quote_; \ + if (!ATOM_IS_IDENTIFIER(atom)) { \ + quote_ = '\''; \ + fmt = qfmt; \ + } else { \ + quote_ = 0; \ + fmt = ufmt; \ + } \ + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), quote_); \ + if (!rval) \ + return NULL; \ + JS_END_MACRO + +#define LOAD_OBJECT(PCOFF) \ + GET_OBJECT_FROM_BYTECODE(jp->script, pc, PCOFF, obj) + +#define LOAD_FUNCTION(PCOFF) \ + GET_FUNCTION_FROM_BYTECODE(jp->script, pc, PCOFF, fun) + +#define LOAD_REGEXP(PCOFF) \ + GET_REGEXP_FROM_BYTECODE(jp->script, pc, PCOFF, obj) + +#define GET_SOURCE_NOTE_ATOM(sn, atom) \ + JS_BEGIN_MACRO \ + jsatomid atomIndex_ = (jsatomid) js_GetSrcNoteOffset((sn), 0); \ + \ + LOCAL_ASSERT(atomIndex_ < jp->script->atomMap.length); \ + (atom) = jp->script->atomMap.vector[atomIndex_]; \ + JS_END_MACRO + +/* + * Get atom from jp->script's atom map, quote/escape its string appropriately + * into rval, and select fmt from the quoted and unquoted alternatives. + */ +#define GET_ATOM_QUOTE_AND_FMT(qfmt, ufmt, rval) \ + JS_BEGIN_MACRO \ + LOAD_ATOM(0); \ + GET_QUOTE_AND_FMT(qfmt, ufmt, rval); \ + JS_END_MACRO + +/* + * Per spec, new x(y).z means (new x(y))).z. For example new (x(y).z) must + * decompile with the constructor parenthesized, but new x.z should not. The + * normal rules give x(y).z and x.z identical precedence: both are produced by + * JSOP_GETPROP. + * + * Therefore, we need to know in case JSOP_NEW whether the constructor + * expression contains any unparenthesized function calls. So when building a + * MemberExpression or CallExpression, we set ss->opcodes[n] to JSOP_CALL if + * this is true. x(y).z gets JSOP_CALL, not JSOP_GETPROP. + */ +#define PROPAGATE_CALLNESS() \ + JS_BEGIN_MACRO \ + if (ss->opcodes[ss->top - 1] == JSOP_CALL || \ + ss->opcodes[ss->top - 1] == JSOP_EVAL || \ + ss->opcodes[ss->top - 1] == JSOP_FUNCALL || \ + ss->opcodes[ss->top - 1] == JSOP_FUNAPPLY) { \ + saveop = JSOP_CALL; \ + } \ + JS_END_MACRO + + cx = ss->sprinter.context; + JS_CHECK_RECURSION(cx, return NULL); + + jp = ss->printer; + startpc = pc; + endpc = (nb < 0) ? jp->script->code + jp->script->length : pc + nb; + tail = -1; + todo = -2; /* NB: different from Sprint() error return. */ + saveop = JSOP_NOP; + sn = NULL; + rval = NULL; +#if JS_HAS_XML_SUPPORT + foreach = inXML = quoteAttr = JS_FALSE; +#endif + + while (nb < 0 || pc < endpc) { + /* + * Move saveop to lastop so prefixed bytecodes can take special action + * while sharing maximal code. Set op and saveop to the new bytecode, + * use op in POP_STR to trigger automatic parenthesization, but push + * saveop at the bottom of the loop if this op pushes. Thus op may be + * set to nop or otherwise mutated to suppress auto-parens. + */ + lastop = saveop; + op = (JSOp) *pc; + cs = &js_CodeSpec[op]; + if (cs->format & JOF_INDEXBASE) { + /* + * The decompiler uses js_GetIndexFromBytecode to get atoms and + * objects and ignores these suffix/prefix bytecodes, thus + * simplifying code that must process JSOP_GETTER/JSOP_SETTER + * prefixes. + */ + pc += cs->length; + if (pc >= endpc) + break; + op = (JSOp) *pc; + cs = &js_CodeSpec[op]; + } + saveop = op; + len = oplen = cs->length; + nuses = js_GetStackUses(cs, op, pc); + + /* + * Here it is possible that nuses > ss->top when the op has a hidden + * source note. But when nb < 0 we assume that the caller knows that + * Decompile would never meet such opcodes. + */ + if (nb < 0) { + LOCAL_ASSERT(ss->top >= nuses); + uintN ndefs = js_GetStackDefs(cx, cs, op, jp->script, pc); + if ((uintN) -(nb + 1) == ss->top - nuses + ndefs) + return pc; + } + + /* + * Save source literal associated with JS now before the following + * rewrite changes op. See bug 380197. + */ + token = CodeToken[op]; + + if (pc + oplen == jp->dvgfence) { + JSStackFrame *fp; + uint32 format, mode, type; + + /* + * Rewrite non-get ops to their "get" format if the error is in + * the bytecode at pc, so we don't decompile more than the error + * expression. + */ + fp = js_GetScriptedCaller(cx, NULL); + format = cs->format; + if (((fp && pc == fp->pc(cx)) || + (pc == startpc && nuses != 0)) && + format & (JOF_SET|JOF_DEL|JOF_INCDEC|JOF_FOR|JOF_VARPROP)) { + mode = JOF_MODE(format); + if (mode == JOF_NAME) { + /* + * JOF_NAME does not imply JOF_ATOM, so we must check for + * the QARG and QVAR format types, and translate those to + * JSOP_GETARG or JSOP_GETLOCAL appropriately, instead of + * to JSOP_NAME. + */ + type = JOF_TYPE(format); + op = (type == JOF_QARG) + ? JSOP_GETARG + : (type == JOF_LOCAL) + ? JSOP_GETLOCAL + : JSOP_NAME; + + JS_ASSERT(js_CodeSpec[op].nuses >= 0); + i = nuses - js_CodeSpec[op].nuses; + while (--i >= 0) + PopOff(ss, JSOP_NOP); + } else { + /* + * We must replace the faulting pc's bytecode with a + * corresponding JSOP_GET* code. For JSOP_SET{PROP,ELEM}, + * we must use the "2nd" form of JSOP_GET{PROP,ELEM}, to + * throw away the assignment op's right-hand operand and + * decompile it as if it were a GET of its left-hand + * operand. + */ + if (mode == JOF_PROP) { + op = (JSOp) ((format & JOF_SET) + ? JSOP_GETPROP2 + : JSOP_GETPROP); + } else if (mode == JOF_ELEM) { + op = (JSOp) ((format & JOF_SET) + ? JSOP_GETELEM2 + : JSOP_GETELEM); + } else { + /* + * Unknown mode (including mode 0) means that op is + * uncategorized for our purposes, so we must write + * per-op special case code here. + */ + switch (op) { + case JSOP_ENUMELEM: + case JSOP_ENUMCONSTELEM: + op = JSOP_GETELEM; + break; + case JSOP_GETTHISPROP: + /* + * NB: JSOP_GETTHISPROP can't fail due to |this| + * being null or undefined at runtime (beware that + * this may change for ES4). Therefore any error + * resulting from this op must be due to the value + * of the property accessed via |this|, so do not + * rewrite op to JSOP_THIS. + * + * The next two cases should not change op if + * js_DecompileValueGenerator was called from the + * the property getter. They should rewrite only + * if the base object in the arg/var/local is null + * or undefined. FIXME: bug 431569. + */ + break; + case JSOP_GETARGPROP: + op = JSOP_GETARG; + break; + case JSOP_GETLOCALPROP: + op = JSOP_GETLOCAL; + break; + case JSOP_SETXMLNAME: + op = JSOp(JSOP_GETELEM2); + break; + default: + LOCAL_ASSERT(0); + } + } + } + } + + saveop = op; + if (op >= JSOP_LIMIT) { + if (op == JSOP_GETPROP2) + saveop = JSOP_GETPROP; + else if (op == JSOP_GETELEM2) + saveop = JSOP_GETELEM; + } + LOCAL_ASSERT(js_CodeSpec[saveop].length == oplen || + JOF_TYPE(format) == JOF_SLOTATOM); + + jp->dvgfence = NULL; + } + + if (token) { + switch (nuses) { + case 2: + sn = js_GetSrcNote(jp->script, pc); + if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) { + /* + * Avoid over-parenthesizing y in x op= y based on its + * expansion: x = x op y (replace y by z = w to see the + * problem). + */ + op = (JSOp) pc[oplen]; + rval = POP_STR(); + lval = POP_STR(); + /* Print only the right operand of the assignment-op. */ + todo = SprintCString(&ss->sprinter, rval); + op = saveop; + } else if (!inXML) { + rval = POP_STR_PREC(cs->prec + !!(cs->format & JOF_LEFTASSOC)); + lval = POP_STR_PREC(cs->prec + !(cs->format & JOF_LEFTASSOC)); + todo = Sprint(&ss->sprinter, "%s %s %s", + lval, token, rval); + } else { + /* In XML, just concatenate the two operands. */ + LOCAL_ASSERT(op == JSOP_ADD); + rval = POP_STR(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, ss_format, lval, rval); + } + break; + + case 1: + rval = POP_STR(); + todo = Sprint(&ss->sprinter, ss_format, token, rval); + break; + + case 0: + todo = SprintCString(&ss->sprinter, token); + break; + + default: + todo = -2; + break; + } + } else { + switch (op) { + case JSOP_NOP: + /* + * Check for a do-while loop, a for-loop with an empty + * initializer part, a labeled statement, a function + * definition, or try/finally. + */ + sn = js_GetSrcNote(jp->script, pc); + todo = -2; + switch (sn ? SN_TYPE(sn) : SRC_NULL) { + case SRC_WHILE: + ++pc; + tail = js_GetSrcNoteOffset(sn, 0) - 1; + LOCAL_ASSERT(pc[tail] == JSOP_IFNE || + pc[tail] == JSOP_IFNEX); + js_printf(jp, "\tdo {\n"); + jp->indent += 4; + DECOMPILE_CODE(pc, tail); + jp->indent -= 4; + js_printf(jp, "\t} while (%s);\n", POP_COND_STR()); + pc += tail; + len = js_CodeSpec[*pc].length; + todo = -2; + break; + + case SRC_FOR: + rval = ""; + + do_forloop: + JS_ASSERT(SN_TYPE(sn) == SRC_FOR); + + /* Skip the JSOP_NOP or JSOP_POP bytecode. */ + pc += JSOP_NOP_LENGTH; + + /* Get the cond, next, and loop-closing tail offsets. */ + cond = js_GetSrcNoteOffset(sn, 0); + next = js_GetSrcNoteOffset(sn, 1); + tail = js_GetSrcNoteOffset(sn, 2); + + /* + * If this loop has a condition, then pc points at a goto + * targeting the condition. + */ + pc2 = pc; + if (cond != tail) { + LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX); + pc2 += (*pc == JSOP_GOTO) ? JSOP_GOTO_LENGTH : JSOP_GOTOX_LENGTH; + } + LOCAL_ASSERT(tail + GetJumpOffset(pc+tail, pc+tail) == pc2 - pc); + + /* Print the keyword and the possibly empty init-part. */ + js_printf(jp, "\tfor (%s;", rval); + + if (cond != tail) { + /* Decompile the loop condition. */ + DECOMPILE_CODE(pc + cond, tail - cond); + js_printf(jp, " %s", POP_STR()); + } + + /* Need a semicolon whether or not there was a cond. */ + js_puts(jp, ";"); + + if (next != cond) { + /* + * Decompile the loop updater. It may end in a JSOP_POP + * that we skip; or in a JSOP_POPN that we do not skip, + * followed by a JSOP_NOP (skipped as if it's a POP). + * We cope with the difference between these two cases + * by checking for stack imbalance and popping if there + * is an rval. + */ + uintN saveTop = ss->top; + + DECOMPILE_CODE(pc + next, cond - next - JSOP_POP_LENGTH); + LOCAL_ASSERT(ss->top - saveTop <= 1U); + rval = (ss->top == saveTop) + ? ss->sprinter.base + ss->sprinter.offset + : POP_STR(); + js_printf(jp, " %s", rval); + } + + /* Do the loop body. */ + js_printf(jp, ") {\n"); + jp->indent += 4; + next -= pc2 - pc; + DECOMPILE_CODE(pc2, next); + jp->indent -= 4; + js_printf(jp, "\t}\n"); + + /* Set len so pc skips over the entire loop. */ + len = tail + js_CodeSpec[pc[tail]].length; + break; + + case SRC_LABEL: + GET_SOURCE_NOTE_ATOM(sn, atom); + jp->indent -= 4; + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval) + return NULL; + RETRACT(&ss->sprinter, rval); + js_printf(jp, "\t%s:\n", rval); + jp->indent += 4; + break; + + case SRC_LABELBRACE: + GET_SOURCE_NOTE_ATOM(sn, atom); + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval) + return NULL; + RETRACT(&ss->sprinter, rval); + js_printf(jp, "\t%s: {\n", rval); + jp->indent += 4; + break; + + case SRC_ENDBRACE: + jp->indent -= 4; + js_printf(jp, "\t}\n"); + break; + + case SRC_FUNCDEF: + fun = jp->script->getFunction(js_GetSrcNoteOffset(sn, 0)); + do_function: + js_puts(jp, "\n"); + jp2 = js_NewPrinter(cx, "nested_function", fun, + jp->indent, jp->pretty, jp->grouped, + jp->strict); + if (!jp2) + return NULL; + ok = js_DecompileFunction(jp2); + if (ok && jp2->sprinter.base) + js_puts(jp, jp2->sprinter.base); + js_DestroyPrinter(jp2); + if (!ok) + return NULL; + js_puts(jp, "\n\n"); + break; + + case SRC_BRACE: + js_printf(jp, "\t{\n"); + jp->indent += 4; + len = js_GetSrcNoteOffset(sn, 0); + DECOMPILE_CODE(pc + oplen, len - oplen); + jp->indent -= 4; + js_printf(jp, "\t}\n"); + break; + + default:; + } + break; + + case JSOP_PUSH: +#if JS_HAS_DESTRUCTURING + sn = js_GetSrcNote(jp->script, pc); + if (sn && SN_TYPE(sn) == SRC_GROUPASSIGN) { + pc = DecompileGroupAssignment(ss, pc, endpc, sn, &todo); + if (!pc) + return NULL; + LOCAL_ASSERT(*pc == JSOP_POPN); + len = oplen = JSOP_POPN_LENGTH; + goto end_groupassignment; + } +#endif + /* FALL THROUGH */ + + case JSOP_BINDNAME: + case JSOP_BINDGNAME: + todo = Sprint(&ss->sprinter, ""); + break; + + case JSOP_TRY: + js_printf(jp, "\ttry {\n"); + jp->indent += 4; + todo = -2; + break; + + case JSOP_FINALLY: + jp->indent -= 4; + js_printf(jp, "\t} finally {\n"); + jp->indent += 4; + + /* + * We push push the pair of exception/restsub cookies to + * simulate the effects [gosub] or control transfer during + * exception capturing on the stack. + */ + todo = Sprint(&ss->sprinter, exception_cookie); + if (todo < 0 || !PushOff(ss, todo, op)) + return NULL; + todo = Sprint(&ss->sprinter, retsub_pc_cookie); + break; + + case JSOP_RETSUB: + rval = POP_STR(); + LOCAL_ASSERT(strcmp(rval, retsub_pc_cookie) == 0); + lval = POP_STR(); + LOCAL_ASSERT(strcmp(lval, exception_cookie) == 0); + todo = -2; + break; + + case JSOP_GOSUB: + case JSOP_GOSUBX: + /* + * JSOP_GOSUB and GOSUBX have no effect on the decompiler's + * string stack because the next op in bytecode order finds + * the stack balanced by a JSOP_RETSUB executed elsewhere. + */ + todo = -2; + break; + + case JSOP_POPN: + { + uintN newtop, oldtop; + + /* + * The compiler models operand stack depth and fixes the stack + * pointer on entry to a catch clause based on its depth model. + * The decompiler must match the code generator's model, which + * is why JSOP_FINALLY pushes a cookie that JSOP_RETSUB pops. + */ + oldtop = ss->top; + newtop = oldtop - GET_UINT16(pc); + LOCAL_ASSERT(newtop <= oldtop); + todo = -2; + + sn = js_GetSrcNote(jp->script, pc); + if (sn && SN_TYPE(sn) == SRC_HIDDEN) + break; +#if JS_HAS_DESTRUCTURING + if (sn && SN_TYPE(sn) == SRC_GROUPASSIGN) { + todo = Sprint(&ss->sprinter, "%s[] = [", + VarPrefix(sn)); + if (todo < 0) + return NULL; + for (uintN i = newtop; i < oldtop; i++) { + rval = OFF2STR(&ss->sprinter, ss->offsets[i]); + if (Sprint(&ss->sprinter, ss_format, + (i == newtop) ? "" : ", ", + (i == oldtop - 1 && *rval == '\0') + ? ", " : rval) < 0) { + return NULL; + } + } + if (SprintPut(&ss->sprinter, "]", 1) < 0) + return NULL; + + /* + * If this is an empty group assignment, we have no stack + * budget into which we can push our result string. Adjust + * ss->sprinter.offset so that our consumer can find the + * empty group assignment decompilation. + */ + if (newtop == oldtop) { + ss->sprinter.offset = todo; + } else { + /* + * Kill newtop before the end_groupassignment: label by + * retracting/popping early. Control will either jump + * to do_forloop: or do_letheadbody: or else break from + * our case JSOP_POPN: after the switch (*pc2) below. + */ + LOCAL_ASSERT(newtop < oldtop); + ss->sprinter.offset = GetOff(ss, newtop); + ss->top = newtop; + } + + end_groupassignment: + LOCAL_ASSERT(*pc == JSOP_POPN); + + /* + * Thread directly to the next opcode if we can, to handle + * the special cases of a group assignment in the first or + * last part of a for(;;) loop head, or in a let block or + * expression head. + * + * NB: todo at this point indexes space in ss->sprinter + * that is liable to be overwritten. The code below knows + * exactly how long rval lives, or else copies it down via + * SprintCString. + */ + rval = OFF2STR(&ss->sprinter, todo); + todo = -2; + pc2 = pc + oplen; + if (*pc2 == JSOP_NOP) { + sn = js_GetSrcNote(jp->script, pc2); + if (sn) { + if (SN_TYPE(sn) == SRC_FOR) { + op = JSOP_NOP; + pc = pc2; + goto do_forloop; + } + + if (SN_TYPE(sn) == SRC_DECL) { + if (ss->top == StackDepth(jp->script)) { + /* + * This must be an empty destructuring + * in the head of a let whose body block + * is also empty. + */ + pc = pc2 + JSOP_NOP_LENGTH; + len = js_GetSrcNoteOffset(sn, 0); + LOCAL_ASSERT(pc[len] == JSOP_LEAVEBLOCK); + js_printf(jp, "\tlet (%s) {\n", rval); + js_printf(jp, "\t}\n"); + break; + } + todo = SprintCString(&ss->sprinter, rval); + if (todo < 0 || !PushOff(ss, todo, JSOP_NOP)) + return NULL; + op = JSOP_POP; + pc = pc2 + JSOP_NOP_LENGTH; + goto do_letheadbody; + } + } else { + /* + * An unnannotated NOP following a POPN must be the + * third part of for(;;) loop head. If the POPN's + * immediate operand is 0, then we may have no slot + * on the sprint-stack in which to push our result + * string. In this case the result can be recovered + * at ss->sprinter.base + ss->sprinter.offset. + */ + if (GET_UINT16(pc) == 0) + break; + todo = SprintCString(&ss->sprinter, rval); + saveop = JSOP_NOP; + } + } + + /* + * If control flow reaches this point with todo still -2, + * just print rval as an expression statement. + */ + if (todo == -2) + js_printf(jp, "\t%s;\n", rval); + break; + } +#endif + if (newtop < oldtop) { + ss->sprinter.offset = GetOff(ss, newtop); + ss->top = newtop; + } + break; + } + + case JSOP_EXCEPTION: + /* The catch decompiler handles this op itself. */ + LOCAL_ASSERT(JS_FALSE); + break; + + case JSOP_POP: + /* + * By default, do not automatically parenthesize when popping + * a stacked expression decompilation. We auto-parenthesize + * only when JSOP_POP is annotated with SRC_PCDELTA, meaning + * comma operator. + */ + op = JSOP_POPV; + /* FALL THROUGH */ + + case JSOP_POPV: + sn = js_GetSrcNote(jp->script, pc); + switch (sn ? SN_TYPE(sn) : SRC_NULL) { + case SRC_FOR: + /* Force parens around 'in' expression at 'for' front. */ + if (ss->opcodes[ss->top-1] == JSOP_IN) + op = JSOP_LSH; + rval = POP_STR(); + todo = -2; + goto do_forloop; + + case SRC_PCDELTA: + /* Comma operator: use JSOP_POP for correct precedence. */ + op = JSOP_POP; + + /* Pop and save to avoid blowing stack depth budget. */ + lval = JS_strdup(cx, POP_STR()); + if (!lval) + return NULL; + + /* + * The offset tells distance to the end of the right-hand + * operand of the comma operator. + */ + done = pc + len; + pc += js_GetSrcNoteOffset(sn, 0); + len = 0; + + if (!Decompile(ss, done, pc - done, JSOP_POP)) { + cx->free((char *)lval); + return NULL; + } + + /* Pop Decompile result and print comma expression. */ + rval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s, %s", lval, rval); + cx->free((char *)lval); + break; + + case SRC_HIDDEN: + /* Hide this pop, it's from a goto in a with or for/in. */ + todo = -2; + break; + + case SRC_DECL: + /* This pop is at the end of the let block/expr head. */ + pc += JSOP_POP_LENGTH; +#if JS_HAS_DESTRUCTURING + do_letheadbody: +#endif + len = js_GetSrcNoteOffset(sn, 0); + if (pc[len] == JSOP_LEAVEBLOCK) { + js_printf(jp, "\tlet (%s) {\n", POP_STR()); + jp->indent += 4; + DECOMPILE_CODE(pc, len); + jp->indent -= 4; + js_printf(jp, "\t}\n"); + todo = -2; + } else { + LOCAL_ASSERT(pc[len] == JSOP_LEAVEBLOCKEXPR); + + lval = JS_strdup(cx, PopStr(ss, JSOP_NOP)); + if (!lval) + return NULL; + + /* Set saveop to reflect what we will push. */ + saveop = JSOP_LEAVEBLOCKEXPR; + if (!Decompile(ss, pc, len, saveop)) { + cx->free((char *)lval); + return NULL; + } + rval = PopStr(ss, JSOP_SETNAME); + todo = Sprint(&ss->sprinter, + (*rval == '{') + ? "let (%s) (%s)" + : "let (%s) %s", + lval, rval); + cx->free((char *)lval); + } + break; + + default: + /* Turn off parens around a yield statement. */ + if (ss->opcodes[ss->top-1] == JSOP_YIELD) + op = JSOP_NOP; + + rval = POP_STR(); + + /* + * Don't emit decompiler-pushed strings that are not + * handled by other opcodes. They are pushed onto the + * stack to help model the interpreter stack and should + * not appear in the decompiler's output. + */ + if (*rval != '\0' && (rval[0] != '/' || rval[1] != '*')) { + js_printf(jp, + (*rval == '{' || + (strncmp(rval, js_function_str, 8) == 0 && + rval[8] == ' ')) + ? "\t(%s);\n" + : "\t%s;\n", + rval); + } else { + LOCAL_ASSERT(*rval == '\0' || + strcmp(rval, exception_cookie) == 0); + } + todo = -2; + break; + } + sn = NULL; + break; + + case JSOP_ENTERWITH: + LOCAL_ASSERT(!js_GetSrcNote(jp->script, pc)); + rval = POP_STR(); + js_printf(jp, "\twith (%s) {\n", rval); + jp->indent += 4; + todo = Sprint(&ss->sprinter, with_cookie); + break; + + case JSOP_LEAVEWITH: + sn = js_GetSrcNote(jp->script, pc); + todo = -2; + if (sn && SN_TYPE(sn) == SRC_HIDDEN) + break; + rval = POP_STR(); + LOCAL_ASSERT(strcmp(rval, with_cookie) == 0); + jp->indent -= 4; + js_printf(jp, "\t}\n"); + break; + + case JSOP_ENTERBLOCK: + { + JSAtom **atomv, *smallv[5]; + + LOAD_OBJECT(0); + argc = OBJ_BLOCK_COUNT(cx, obj); + if ((size_t)argc <= JS_ARRAY_LENGTH(smallv)) { + atomv = smallv; + } else { + atomv = (JSAtom **) cx->malloc(argc * sizeof(JSAtom *)); + if (!atomv) + return NULL; + } + + MUST_FLOW_THROUGH("enterblock_out"); +#define LOCAL_ASSERT_OUT(expr) LOCAL_ASSERT_CUSTOM(expr, ok = JS_FALSE; \ + goto enterblock_out) + for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) { + const Shape &shape = r.front(); + + if (!shape.hasShortID()) + continue; + LOCAL_ASSERT_OUT(shape.shortid < argc); + atomv[shape.shortid] = JSID_TO_ATOM(shape.id); + } + ok = JS_TRUE; + for (i = 0; i < argc; i++) { + atom = atomv[i]; + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval || + !PushOff(ss, STR2OFF(&ss->sprinter, rval), op)) { + ok = JS_FALSE; + goto enterblock_out; + } + } + + sn = js_GetSrcNote(jp->script, pc); + switch (sn ? SN_TYPE(sn) : SRC_NULL) { +#if JS_HAS_BLOCK_SCOPE + case SRC_BRACE: + js_printf(jp, "\t{\n"); + jp->indent += 4; + len = js_GetSrcNoteOffset(sn, 0); + ok = Decompile(ss, pc + oplen, len - oplen, JSOP_NOP) + != NULL; + if (!ok) + goto enterblock_out; + jp->indent -= 4; + js_printf(jp, "\t}\n"); + break; +#endif + + case SRC_CATCH: + jp->indent -= 4; + js_printf(jp, "\t} catch ("); + + pc2 = pc; + pc += oplen; + LOCAL_ASSERT_OUT(*pc == JSOP_EXCEPTION); + pc += JSOP_EXCEPTION_LENGTH; + todo = Sprint(&ss->sprinter, exception_cookie); + if (todo < 0 || !PushOff(ss, todo, JSOP_EXCEPTION)) { + ok = JS_FALSE; + goto enterblock_out; + } + + if (*pc == JSOP_DUP) { + sn2 = js_GetSrcNote(jp->script, pc); + if (!sn2 || SN_TYPE(sn2) != SRC_DESTRUCT) { + /* + * This is a dup to save the exception for later. + * It is emitted only when the catch head contains + * an exception guard. + */ + LOCAL_ASSERT_OUT(js_GetSrcNoteOffset(sn, 0) != 0); + pc += JSOP_DUP_LENGTH; + todo = Sprint(&ss->sprinter, exception_cookie); + if (todo < 0 || + !PushOff(ss, todo, JSOP_EXCEPTION)) { + ok = JS_FALSE; + goto enterblock_out; + } + } + } + +#if JS_HAS_DESTRUCTURING + if (*pc == JSOP_DUP) { + pc = DecompileDestructuring(ss, pc, endpc); + if (!pc) { + ok = JS_FALSE; + goto enterblock_out; + } + LOCAL_ASSERT_OUT(*pc == JSOP_POP); + pc += JSOP_POP_LENGTH; + lval = PopStr(ss, JSOP_NOP); + js_puts(jp, lval); + } else { +#endif + LOCAL_ASSERT_OUT(*pc == JSOP_SETLOCALPOP); + i = GET_SLOTNO(pc) - jp->script->nfixed; + pc += JSOP_SETLOCALPOP_LENGTH; + atom = atomv[i - OBJ_BLOCK_DEPTH(cx, obj)]; + str = ATOM_TO_STRING(atom); + if (!QuoteString(&jp->sprinter, str, 0)) { + ok = JS_FALSE; + goto enterblock_out; + } +#if JS_HAS_DESTRUCTURING + } +#endif + + /* + * Pop the exception_cookie (or its dup in the case of a + * guarded catch head) off the stack now. + */ + rval = PopStr(ss, JSOP_NOP); + LOCAL_ASSERT_OUT(strcmp(rval, exception_cookie) == 0); + + len = js_GetSrcNoteOffset(sn, 0); + if (len) { + len -= pc - pc2; + LOCAL_ASSERT_OUT(len > 0); + js_printf(jp, " if "); + ok = Decompile(ss, pc, len, JSOP_NOP) != NULL; + if (!ok) + goto enterblock_out; + js_printf(jp, "%s", POP_STR()); + pc += len; + LOCAL_ASSERT_OUT(*pc == JSOP_IFEQ || *pc == JSOP_IFEQX); + pc += js_CodeSpec[*pc].length; + } + + js_printf(jp, ") {\n"); + jp->indent += 4; + len = 0; + break; + default: + break; + } + + todo = -2; + +#undef LOCAL_ASSERT_OUT + enterblock_out: + if (atomv != smallv) + cx->free(atomv); + if (!ok) + return NULL; + } + break; + + case JSOP_LEAVEBLOCK: + case JSOP_LEAVEBLOCKEXPR: + { + uintN top, depth; + + sn = js_GetSrcNote(jp->script, pc); + todo = -2; + if (op == JSOP_LEAVEBLOCKEXPR) { + LOCAL_ASSERT(SN_TYPE(sn) == SRC_PCBASE); + rval = POP_STR(); + } else if (sn) { + LOCAL_ASSERT(op == JSOP_LEAVEBLOCK); + if (SN_TYPE(sn) == SRC_HIDDEN) + break; + + /* + * This JSOP_LEAVEBLOCK must be for a catch block. If sn's + * offset does not equal the model stack depth, there must + * be a copy of the exception value on the stack due to a + * catch guard (see above, the JSOP_ENTERBLOCK + SRC_CATCH + * case code). + */ + LOCAL_ASSERT(SN_TYPE(sn) == SRC_CATCH); + if ((uintN)js_GetSrcNoteOffset(sn, 0) != ss->top) { + LOCAL_ASSERT((uintN)js_GetSrcNoteOffset(sn, 0) + == ss->top - 1); + rval = POP_STR(); + LOCAL_ASSERT(strcmp(rval, exception_cookie) == 0); + } + } + top = ss->top; + depth = GET_UINT16(pc); + LOCAL_ASSERT(top >= depth); + top -= depth; + ss->top = top; + ss->sprinter.offset = GetOff(ss, top); + if (op == JSOP_LEAVEBLOCKEXPR) + todo = SprintCString(&ss->sprinter, rval); + break; + } + + case JSOP_GETUPVAR_DBG: + case JSOP_CALLUPVAR_DBG: + case JSOP_GETFCSLOT: + case JSOP_CALLFCSLOT: + { + if (!jp->fun) { + JS_ASSERT(jp->script->savedCallerFun); + jp->fun = jp->script->getFunction(0); + } + + if (!jp->localNames) { + JS_ASSERT(fun == jp->fun); + jp->localNames = + jp->fun->script()->bindings.getLocalNameArray(cx, &jp->pool); + } + + uintN index = GET_UINT16(pc); + if (index < jp->fun->script()->bindings.countUpvars()) { + index += jp->fun->script()->bindings.countArgsAndVars(); + } else { + JSUpvarArray *uva; +#ifdef DEBUG + /* + * We must be in an eval called from jp->fun, where + * jp->script is the eval-compiled script. + * + * However, it's possible that a js_Invoke already + * pushed a frame trying to call Construct on an + * object that's not a constructor, causing us to be + * called with an intervening frame on the stack. + */ + JSStackFrame *fp = js_GetTopStackFrame(cx); + if (fp) { + while (!fp->isEvalFrame()) + fp = fp->prev(); + JS_ASSERT(fp->script() == jp->script); + JS_ASSERT(fp->prev()->fun() == jp->fun); + JS_ASSERT(jp->fun->isInterpreted()); + JS_ASSERT(jp->script != jp->fun->script()); + JS_ASSERT(JSScript::isValidOffset(jp->script->upvarsOffset)); + } +#endif + uva = jp->script->upvars(); + index = uva->vector[index].slot(); + } + atom = GetArgOrVarAtom(jp, index); + goto do_name; + } + + case JSOP_CALLLOCAL: + case JSOP_GETLOCAL: + if (IsVarSlot(jp, pc, &i)) { + atom = GetArgOrVarAtom(jp, i); + LOCAL_ASSERT(atom); + goto do_name; + } + LOCAL_ASSERT((uintN)i < ss->top); + sn = js_GetSrcNote(jp->script, pc); + +#if JS_HAS_DESTRUCTURING + if (sn && SN_TYPE(sn) == SRC_GROUPASSIGN) { + /* + * Distinguish a js_DecompileValueGenerator call that + * targets op alone, from decompilation of a full group + * assignment sequence, triggered by SRC_GROUPASSIGN + * annotating the first JSOP_GETLOCAL in the sequence. + */ + if (endpc - pc > JSOP_GETLOCAL_LENGTH || pc > startpc) { + pc = DecompileGroupAssignment(ss, pc, endpc, sn, &todo); + if (!pc) + return NULL; + LOCAL_ASSERT(*pc == JSOP_POPN); + len = oplen = JSOP_POPN_LENGTH; + goto end_groupassignment; + } + + /* Null sn to prevent bogus VarPrefix'ing below. */ + sn = NULL; + } +#endif + + rval = GetLocal(ss, i); + todo = Sprint(&ss->sprinter, ss_format, VarPrefix(sn), rval); + break; + + case JSOP_SETLOCAL: + case JSOP_SETLOCALPOP: + if (IsVarSlot(jp, pc, &i)) { + atom = GetArgOrVarAtom(jp, i); + LOCAL_ASSERT(atom); + goto do_setname; + } + lval = GetLocal(ss, i); + rval = POP_STR(); + goto do_setlval; + + case JSOP_INCLOCAL: + case JSOP_DECLOCAL: + if (IsVarSlot(jp, pc, &i)) { + atom = GetArgOrVarAtom(jp, i); + LOCAL_ASSERT(atom); + goto do_incatom; + } + lval = GetLocal(ss, i); + goto do_inclval; + + case JSOP_LOCALINC: + case JSOP_LOCALDEC: + if (IsVarSlot(jp, pc, &i)) { + atom = GetArgOrVarAtom(jp, i); + LOCAL_ASSERT(atom); + goto do_atominc; + } + lval = GetLocal(ss, i); + goto do_lvalinc; + + case JSOP_RETRVAL: + todo = -2; + break; + + case JSOP_RETURN: + LOCAL_ASSERT(jp->fun); + fun = jp->fun; + if (fun->flags & JSFUN_EXPR_CLOSURE) { + /* Turn on parens around comma-expression here. */ + op = JSOP_SETNAME; + rval = POP_STR(); + js_printf(jp, (*rval == '{') ? "(%s)%s" : ss_format, + rval, + ((fun->flags & JSFUN_LAMBDA) || !fun->atom) + ? "" + : ";"); + todo = -2; + break; + } + /* FALL THROUGH */ + + case JSOP_SETRVAL: + rval = POP_STR(); + if (*rval != '\0') + js_printf(jp, "\t%s %s;\n", js_return_str, rval); + else + js_printf(jp, "\t%s;\n", js_return_str); + todo = -2; + break; + +#if JS_HAS_GENERATORS + case JSOP_YIELD: +#if JS_HAS_GENERATOR_EXPRS + if (!ss->inGenExp || !(sn = js_GetSrcNote(jp->script, pc))) +#endif + { + /* Turn off most parens. */ + op = JSOP_SETNAME; + rval = POP_STR(); + todo = (*rval != '\0') + ? Sprint(&ss->sprinter, + (strncmp(rval, js_yield_str, 5) == 0 && + (rval[5] == ' ' || rval[5] == '\0')) + ? "%s (%s)" + : "%s %s", + js_yield_str, rval) + : SprintCString(&ss->sprinter, js_yield_str); + break; + } + +#if JS_HAS_GENERATOR_EXPRS + LOCAL_ASSERT(SN_TYPE(sn) == SRC_HIDDEN); + /* FALL THROUGH */ +#endif + + case JSOP_ARRAYPUSH: + { + uintN pos, forpos; + ptrdiff_t start; + + /* Turn off most parens. */ + op = JSOP_SETNAME; + + /* Pop the expression being pushed or yielded. */ + rval = POP_STR(); + + /* + * Skip the for loop head stacked by JSOP_FORLOCAL until we hit + * a block local slot (note empty destructuring patterns result + * in unit-count blocks). + */ + pos = ss->top; + while (pos != 0) { + op = (JSOp) ss->opcodes[--pos]; + if (op == JSOP_ENTERBLOCK) + break; + } + JS_ASSERT(op == JSOP_ENTERBLOCK); + + /* + * Here, forpos must index the space before the left-most |for| + * in the single string of accumulated |for| heads and optional + * final |if (condition)|. + */ + forpos = pos + 1; + LOCAL_ASSERT(forpos < ss->top); + + /* + * Now move pos downward over the block's local slots. Even an + * empty destructuring pattern has one (dummy) local. + */ + while (ss->opcodes[pos] == JSOP_ENTERBLOCK) { + if (pos == 0) + break; + --pos; + } + +#if JS_HAS_GENERATOR_EXPRS + if (saveop == JSOP_YIELD) { + /* + * Generator expression: decompile just rval followed by + * the string starting at forpos. Leave the result string + * in ss->offsets[0] so it can be recovered by our caller + * (the JSOP_ANONFUNOBJ with SRC_GENEXP case). Bump the + * top of stack to balance yield, which is an expression + * (so has neutral stack balance). + */ + LOCAL_ASSERT(pos == 0); + xval = OFF2STR(&ss->sprinter, ss->offsets[forpos]); + ss->sprinter.offset = PAREN_SLOP; + todo = Sprint(&ss->sprinter, ss_format, rval, xval); + if (todo < 0) + return NULL; + ss->offsets[0] = todo; + ++ss->top; + return pc; + } +#endif /* JS_HAS_GENERATOR_EXPRS */ + + /* + * Array comprehension: retract the sprinter to the beginning + * of the array initialiser and decompile "[ for ...]". + */ + JS_ASSERT(jp->script->nfixed + pos == GET_UINT16(pc)); + LOCAL_ASSERT(ss->opcodes[pos] == JSOP_NEWINIT); + + start = ss->offsets[pos]; + LOCAL_ASSERT(ss->sprinter.base[start] == '[' || + ss->sprinter.base[start] == '#'); + LOCAL_ASSERT(forpos < ss->top); + xval = OFF2STR(&ss->sprinter, ss->offsets[forpos]); + lval = OFF2STR(&ss->sprinter, start); + RETRACT(&ss->sprinter, lval); + + todo = Sprint(&ss->sprinter, sss_format, lval, rval, xval); + if (todo < 0) + return NULL; + ss->offsets[pos] = todo; + todo = -2; + break; + } +#endif /* JS_HAS_GENERATORS */ + + case JSOP_THROWING: + todo = -2; + break; + + case JSOP_THROW: + sn = js_GetSrcNote(jp->script, pc); + todo = -2; + if (sn && SN_TYPE(sn) == SRC_HIDDEN) + break; + rval = POP_STR(); + js_printf(jp, "\t%s %s;\n", js_throw_str, rval); + break; + + case JSOP_ITER: + foreach = (pc[1] & (JSITER_FOREACH | JSITER_KEYVALUE)) == + JSITER_FOREACH; + todo = -2; + break; + + case JSOP_MOREITER: + JS_NOT_REACHED("JSOP_MOREITER"); + break; + + case JSOP_ENDITER: + sn = js_GetSrcNote(jp->script, pc); + todo = -2; + if (sn && SN_TYPE(sn) == SRC_HIDDEN) + break; + (void) PopOff(ss, op); + break; + + case JSOP_GOTO: + case JSOP_GOTOX: + sn = js_GetSrcNote(jp->script, pc); + switch (sn ? SN_TYPE(sn) : SRC_NULL) { + case SRC_FOR_IN: + /* + * The loop back-edge carries +1 stack balance, for the + * flag processed by JSOP_IFNE. We do not decompile the + * JSOP_IFNE, and instead push the left-hand side of 'in' + * after the loop edge in this stack slot (the JSOP_FOR* + * opcodes' decompilers do this pushing). + */ + cond = GetJumpOffset(pc, pc); + next = js_GetSrcNoteOffset(sn, 0); + tail = js_GetSrcNoteOffset(sn, 1); + JS_ASSERT(pc[cond] == JSOP_MOREITER); + DECOMPILE_CODE(pc + oplen, next - oplen); + lval = POP_STR(); + LOCAL_ASSERT(ss->top >= 1); + + if (ss->inArrayInit || ss->inGenExp) { + rval = POP_STR(); + if (ss->top >= 1 && ss->opcodes[ss->top - 1] == JSOP_FORLOCAL) { + ss->sprinter.offset = ss->offsets[ss->top] - PAREN_SLOP; + if (Sprint(&ss->sprinter, " %s (%s in %s)", + foreach ? js_for_each_str : js_for_str, + lval, rval) < 0) { + return NULL; + } + + /* + * Do not AddParentSlop here, as we will push the + * top-most offset again, which will add paren slop + * for us. We must push to balance the stack budget + * when nesting for heads in a comprehension. + */ + todo = ss->offsets[ss->top - 1]; + } else { + todo = Sprint(&ss->sprinter, " %s (%s in %s)", + foreach ? js_for_each_str : js_for_str, + lval, rval); + } + if (todo < 0 || !PushOff(ss, todo, JSOP_FORLOCAL)) + return NULL; + DECOMPILE_CODE(pc + next, cond - next); + } else { + /* + * As above, rval or an extension of it must remain + * stacked during loop body decompilation. + */ + rval = GetStr(ss, ss->top - 1); + js_printf(jp, "\t%s (%s in %s) {\n", + foreach ? js_for_each_str : js_for_str, + lval, rval); + jp->indent += 4; + DECOMPILE_CODE(pc + next, cond - next); + jp->indent -= 4; + js_printf(jp, "\t}\n"); + } + + pc += tail; + LOCAL_ASSERT(*pc == JSOP_IFNE || *pc == JSOP_IFNEX); + len = js_CodeSpec[*pc].length; + break; + + case SRC_WHILE: + cond = GetJumpOffset(pc, pc); + tail = js_GetSrcNoteOffset(sn, 0); + DECOMPILE_CODE(pc + cond, tail - cond); + js_printf(jp, "\twhile (%s) {\n", POP_COND_STR()); + jp->indent += 4; + DECOMPILE_CODE(pc + oplen, cond - oplen); + jp->indent -= 4; + js_printf(jp, "\t}\n"); + pc += tail; + LOCAL_ASSERT(*pc == JSOP_IFNE || *pc == JSOP_IFNEX); + len = js_CodeSpec[*pc].length; + todo = -2; + break; + + case SRC_CONT2LABEL: + GET_SOURCE_NOTE_ATOM(sn, atom); + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval) + return NULL; + RETRACT(&ss->sprinter, rval); + js_printf(jp, "\tcontinue %s;\n", rval); + break; + + case SRC_CONTINUE: + js_printf(jp, "\tcontinue;\n"); + break; + + case SRC_BREAK2LABEL: + GET_SOURCE_NOTE_ATOM(sn, atom); + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval) + return NULL; + RETRACT(&ss->sprinter, rval); + js_printf(jp, "\tbreak %s;\n", rval); + break; + + case SRC_HIDDEN: + break; + + default: + js_printf(jp, "\tbreak;\n"); + break; + } + todo = -2; + break; + + case JSOP_IFEQ: + case JSOP_IFEQX: + { + JSBool elseif = JS_FALSE; + + if_again: + len = GetJumpOffset(pc, pc); + sn = js_GetSrcNote(jp->script, pc); + + switch (sn ? SN_TYPE(sn) : SRC_NULL) { + case SRC_IF: + case SRC_IF_ELSE: + rval = POP_COND_STR(); + if (ss->inArrayInit || ss->inGenExp) { + LOCAL_ASSERT(SN_TYPE(sn) == SRC_IF); + ss->sprinter.offset -= PAREN_SLOP; + if (Sprint(&ss->sprinter, " if (%s)", rval) < 0) + return NULL; + AddParenSlop(ss); + } else { + js_printf(jp, + elseif ? " if (%s) {\n" : "\tif (%s) {\n", + rval); + jp->indent += 4; + } + + if (SN_TYPE(sn) == SRC_IF) { + DECOMPILE_CODE(pc + oplen, len - oplen); + } else { + LOCAL_ASSERT(!ss->inArrayInit && !ss->inGenExp); + tail = js_GetSrcNoteOffset(sn, 0); + DECOMPILE_CODE(pc + oplen, tail - oplen); + jp->indent -= 4; + pc += tail; + LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX); + oplen = js_CodeSpec[*pc].length; + len = GetJumpOffset(pc, pc); + js_printf(jp, "\t} else"); + + /* + * If the second offset for sn is non-zero, it tells + * the distance from the goto around the else, to the + * ifeq for the if inside the else that forms an "if + * else if" chain. Thus cond spans the condition of + * the second if, so we simply decompile it and start + * over at label if_again. + */ + cond = js_GetSrcNoteOffset(sn, 1); + if (cond != 0) { + cond -= tail; + DECOMPILE_CODE(pc + oplen, cond - oplen); + pc += cond; + oplen = js_CodeSpec[*pc].length; + elseif = JS_TRUE; + goto if_again; + } + + js_printf(jp, " {\n"); + jp->indent += 4; + DECOMPILE_CODE(pc + oplen, len - oplen); + } + + if (!ss->inArrayInit && !ss->inGenExp) { + jp->indent -= 4; + js_printf(jp, "\t}\n"); + } + todo = -2; + break; + + case SRC_COND: + xval = JS_strdup(cx, POP_STR()); + if (!xval) + return NULL; + len = js_GetSrcNoteOffset(sn, 0); + DECOMPILE_CODE(pc + oplen, len - oplen); + lval = JS_strdup(cx, POP_STR()); + if (!lval) { + cx->free((void *)xval); + return NULL; + } + pc += len; + LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX); + oplen = js_CodeSpec[*pc].length; + len = GetJumpOffset(pc, pc); + DECOMPILE_CODE(pc + oplen, len - oplen); + rval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s ? %s : %s", + xval, lval, rval); + cx->free((void *)xval); + cx->free((void *)lval); + break; + + default: + break; + } + break; + } + + case JSOP_IFNE: + case JSOP_IFNEX: + LOCAL_ASSERT(0); + break; + + case JSOP_OR: + case JSOP_ORX: + xval = "||"; + + do_logical_connective: + /* Top of stack is the first clause in a disjunction (||). */ + lval = JS_strdup(cx, POP_STR()); + if (!lval) + return NULL; + done = pc + GetJumpOffset(pc, pc); + pc += len; + len = done - pc; + if (!Decompile(ss, pc, len, op)) { + cx->free((char *)lval); + return NULL; + } + rval = POP_STR(); + if (jp->pretty && + jp->indent + 4 + strlen(lval) + 4 + strlen(rval) > 75) { + rval = JS_strdup(cx, rval); + if (!rval) { + tail = -1; + } else { + todo = Sprint(&ss->sprinter, "%s %s\n", lval, xval); + tail = Sprint(&ss->sprinter, "%*s%s", + jp->indent + 4, "", rval); + cx->free((char *)rval); + } + if (tail < 0) + todo = -1; + } else { + todo = Sprint(&ss->sprinter, "%s %s %s", lval, xval, rval); + } + cx->free((char *)lval); + break; + + case JSOP_AND: + case JSOP_ANDX: + xval = "&&"; + goto do_logical_connective; + + case JSOP_FORARG: + sn = NULL; + i = GET_ARGNO(pc); + goto do_forvarslot; + + case JSOP_FORLOCAL: + sn = js_GetSrcNote(jp->script, pc); + if (!IsVarSlot(jp, pc, &i)) { + JS_ASSERT(op == JSOP_FORLOCAL); + todo = Sprint(&ss->sprinter, ss_format, VarPrefix(sn), GetStr(ss, i)); + break; + } + + do_forvarslot: + atom = GetArgOrVarAtom(jp, i); + LOCAL_ASSERT(atom); + todo = SprintCString(&ss->sprinter, VarPrefix(sn)); + if (todo < 0 || !QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0)) + return NULL; + break; + + case JSOP_FORNAME: + case JSOP_FORGNAME: + LOAD_ATOM(0); + + sn = js_GetSrcNote(jp->script, pc); + todo = SprintCString(&ss->sprinter, VarPrefix(sn)); + if (todo < 0 || !QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0)) + return NULL; + break; + + case JSOP_FORPROP: + xval = NULL; + LOAD_ATOM(0); + if (!ATOM_IS_IDENTIFIER(atom)) { + xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), + (jschar)'\''); + if (!xval) + return NULL; + } + lval = POP_STR(); + if (xval) { + JS_ASSERT(*lval); + todo = Sprint(&ss->sprinter, index_format, lval, xval); + } else { + todo = Sprint(&ss->sprinter, ss_format, lval, *lval ? "." : ""); + if (todo < 0) + return NULL; + if (!QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0)) + return NULL; + } + break; + + case JSOP_FORELEM: + todo = SprintCString(&ss->sprinter, forelem_cookie); + break; + + case JSOP_ENUMELEM: + case JSOP_ENUMCONSTELEM: + /* + * The stack has the object under the (top) index expression. + * The "rval" property id is underneath those two on the stack. + * The for loop body net and gross lengths can now be adjusted + * to account for the length of the indexing expression that + * came after JSOP_FORELEM and before JSOP_ENUMELEM. + */ + atom = NULL; + op = JSOP_NOP; /* turn off parens around xval */ + xval = POP_STR(); + op = JSOP_GETELEM; /* lval must have high precedence */ + lval = POP_STR(); + op = saveop; + rval = POP_STR(); + LOCAL_ASSERT(strcmp(rval, forelem_cookie) == 0); + if (*xval == '\0') { + todo = SprintCString(&ss->sprinter, lval); + } else { + todo = Sprint(&ss->sprinter, + (JOF_OPMODE(lastop) == JOF_XMLNAME) + ? dot_format + : index_format, + lval, xval); + } + break; + + case JSOP_GETTER: + case JSOP_SETTER: + todo = -2; + break; + + case JSOP_DUP2: + rval = GetStr(ss, ss->top-2); + todo = SprintCString(&ss->sprinter, rval); + if (todo < 0 || !PushOff(ss, todo, + (JSOp) ss->opcodes[ss->top-2])) { + return NULL; + } + /* FALL THROUGH */ + + case JSOP_DUP: +#if JS_HAS_DESTRUCTURING + sn = js_GetSrcNote(jp->script, pc); + if (sn) { + LOCAL_ASSERT(SN_TYPE(sn) == SRC_DESTRUCT); + pc = DecompileDestructuring(ss, pc, endpc); + if (!pc) + return NULL; + len = 0; + lval = POP_STR(); + op = saveop = JSOP_ENUMELEM; + rval = POP_STR(); + + if (strcmp(rval, forelem_cookie) == 0) { + todo = Sprint(&ss->sprinter, ss_format, + VarPrefix(sn), lval); + + // Skip POP so the SRC_FOR_IN code can pop for itself. + if (*pc == JSOP_POP) + len = JSOP_POP_LENGTH; + } else { + todo = Sprint(&ss->sprinter, "%s%s = %s", + VarPrefix(sn), lval, rval); + } + break; + } +#endif + + rval = GetStr(ss, ss->top-1); + saveop = (JSOp) ss->opcodes[ss->top-1]; + todo = SprintCString(&ss->sprinter, rval); + break; + + case JSOP_SETARG: + atom = GetArgOrVarAtom(jp, GET_ARGNO(pc)); + LOCAL_ASSERT(atom); + goto do_setname; + + case JSOP_SETCONST: + case JSOP_SETNAME: + case JSOP_SETGNAME: + LOAD_ATOM(0); + + do_setname: + lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!lval) + return NULL; + rval = POP_STR(); + if (op == JSOP_SETNAME || op == JSOP_SETGNAME) + (void) PopOff(ss, op); + + do_setlval: + sn = js_GetSrcNote(jp->script, pc - 1); + if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) { + todo = Sprint(&ss->sprinter, "%s %s= %s", + lval, + (lastop == JSOP_GETTER) + ? js_getter_str + : (lastop == JSOP_SETTER) + ? js_setter_str + : CodeToken[lastop], + rval); + } else { + sn = js_GetSrcNote(jp->script, pc); + todo = Sprint(&ss->sprinter, "%s%s = %s", + VarPrefix(sn), lval, rval); + } + if (op == JSOP_SETLOCALPOP) { + if (!PushOff(ss, todo, saveop)) + return NULL; + rval = POP_STR(); + LOCAL_ASSERT(*rval != '\0'); + js_printf(jp, "\t%s;\n", rval); + todo = -2; + } + break; + + case JSOP_NEW: + case JSOP_CALL: + case JSOP_EVAL: + case JSOP_FUNCALL: + case JSOP_FUNAPPLY: + argc = GET_ARGC(pc); + argv = (char **) + cx->malloc((size_t)(argc + 1) * sizeof *argv); + if (!argv) + return NULL; + + op = JSOP_SETNAME; + ok = JS_TRUE; + for (i = argc; i > 0; i--) + argv[i] = JS_strdup(cx, POP_STR()); + + /* Skip the JSOP_PUSHOBJ-created empty string. */ + LOCAL_ASSERT(ss->top >= 2); + (void) PopOff(ss, op); + + /* + * Special case: new (x(y)(z)) must be parenthesized like so. + * Same for new (x(y).z) -- contrast with new x(y).z. + * See PROPAGATE_CALLNESS. + */ + op = (JSOp) ss->opcodes[ss->top - 1]; + lval = PopStr(ss, + (saveop == JSOP_NEW && + (op == JSOP_CALL || + op == JSOP_EVAL || + op == JSOP_FUNCALL || + op == JSOP_FUNAPPLY || + (js_CodeSpec[op].format & JOF_CALLOP))) + ? JSOP_NAME + : saveop); + op = saveop; + + argv[0] = JS_strdup(cx, lval); + if (!argv[0]) + ok = JS_FALSE; + + lval = "(", rval = ")"; + if (op == JSOP_NEW) { + if (argc == 0) + lval = rval = ""; + todo = Sprint(&ss->sprinter, "%s %s%s", + js_new_str, argv[0], lval); + } else { + todo = Sprint(&ss->sprinter, ss_format, + argv[0], lval); + } + if (todo < 0) + ok = JS_FALSE; + + for (i = 1; i <= argc; i++) { + if (!argv[i] || + Sprint(&ss->sprinter, ss_format, + argv[i], (i < argc) ? ", " : "") < 0) { + ok = JS_FALSE; + break; + } + } + if (Sprint(&ss->sprinter, rval) < 0) + ok = JS_FALSE; + + for (i = 0; i <= argc; i++) + cx->free(argv[i]); + cx->free(argv); + if (!ok) + return NULL; + break; + + case JSOP_SETCALL: + todo = Sprint(&ss->sprinter, ""); + break; + + case JSOP_DELNAME: + LOAD_ATOM(0); + lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!lval) + return NULL; + RETRACT(&ss->sprinter, lval); + do_delete_lval: + todo = Sprint(&ss->sprinter, "%s %s", js_delete_str, lval); + break; + + case JSOP_DELPROP: + GET_ATOM_QUOTE_AND_FMT("%s %s[%s]", "%s %s.%s", rval); + op = JSOP_GETPROP; + lval = POP_STR(); + todo = Sprint(&ss->sprinter, fmt, js_delete_str, lval, rval); + break; + + case JSOP_DELELEM: + op = JSOP_NOP; /* turn off parens */ + xval = POP_STR(); + op = JSOP_GETPROP; + lval = POP_STR(); + if (*xval == '\0') + goto do_delete_lval; + todo = Sprint(&ss->sprinter, + (JOF_OPMODE(lastop) == JOF_XMLNAME) + ? "%s %s.%s" + : "%s %s[%s]", + js_delete_str, lval, xval); + break; + +#if JS_HAS_XML_SUPPORT + case JSOP_DELDESC: + xval = POP_STR(); + op = JSOP_GETPROP; + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s %s..%s", + js_delete_str, lval, xval); + break; +#endif + + case JSOP_TYPEOFEXPR: + case JSOP_TYPEOF: + case JSOP_VOID: + rval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s %s", + (op == JSOP_VOID) ? js_void_str : js_typeof_str, + rval); + break; + + case JSOP_INCARG: + case JSOP_DECARG: + atom = GetArgOrVarAtom(jp, GET_ARGNO(pc)); + LOCAL_ASSERT(atom); + goto do_incatom; + + case JSOP_INCNAME: + case JSOP_DECNAME: + case JSOP_INCGNAME: + case JSOP_DECGNAME: + LOAD_ATOM(0); + do_incatom: + lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!lval) + return NULL; + RETRACT(&ss->sprinter, lval); + do_inclval: + todo = Sprint(&ss->sprinter, ss_format, + js_incop_strs[!(cs->format & JOF_INC)], lval); + break; + + case JSOP_INCPROP: + case JSOP_DECPROP: + GET_ATOM_QUOTE_AND_FMT(preindex_format, predot_format, rval); + + /* + * Force precedence below the numeric literal opcodes, so that + * 42..foo or 10000..toString(16), e.g., decompile with parens + * around the left-hand side of dot. + */ + op = JSOP_GETPROP; + lval = POP_STR(); + todo = Sprint(&ss->sprinter, fmt, + js_incop_strs[!(cs->format & JOF_INC)], + lval, rval); + break; + + case JSOP_INCELEM: + case JSOP_DECELEM: + op = JSOP_NOP; /* turn off parens */ + xval = POP_STR(); + op = JSOP_GETELEM; + lval = POP_STR(); + if (*xval != '\0') { + todo = Sprint(&ss->sprinter, + (JOF_OPMODE(lastop) == JOF_XMLNAME) + ? predot_format + : preindex_format, + js_incop_strs[!(cs->format & JOF_INC)], + lval, xval); + } else { + todo = Sprint(&ss->sprinter, ss_format, + js_incop_strs[!(cs->format & JOF_INC)], lval); + } + break; + + case JSOP_ARGINC: + case JSOP_ARGDEC: + atom = GetArgOrVarAtom(jp, GET_ARGNO(pc)); + LOCAL_ASSERT(atom); + goto do_atominc; + + case JSOP_NAMEINC: + case JSOP_NAMEDEC: + case JSOP_GNAMEINC: + case JSOP_GNAMEDEC: + LOAD_ATOM(0); + do_atominc: + lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!lval) + return NULL; + RETRACT(&ss->sprinter, lval); + do_lvalinc: + todo = Sprint(&ss->sprinter, ss_format, + lval, js_incop_strs[!(cs->format & JOF_INC)]); + break; + + case JSOP_PROPINC: + case JSOP_PROPDEC: + GET_ATOM_QUOTE_AND_FMT(postindex_format, postdot_format, rval); + + /* + * Force precedence below the numeric literal opcodes, so that + * 42..foo or 10000..toString(16), e.g., decompile with parens + * around the left-hand side of dot. + */ + op = JSOP_GETPROP; + lval = POP_STR(); + todo = Sprint(&ss->sprinter, fmt, lval, rval, + js_incop_strs[!(cs->format & JOF_INC)]); + break; + + case JSOP_ELEMINC: + case JSOP_ELEMDEC: + op = JSOP_NOP; /* turn off parens */ + xval = POP_STR(); + op = JSOP_GETELEM; + lval = POP_STR(); + if (*xval != '\0') { + todo = Sprint(&ss->sprinter, + (JOF_OPMODE(lastop) == JOF_XMLNAME) + ? postdot_format + : postindex_format, + lval, xval, + js_incop_strs[!(cs->format & JOF_INC)]); + } else { + todo = Sprint(&ss->sprinter, ss_format, + lval, js_incop_strs[!(cs->format & JOF_INC)]); + } + break; + + case JSOP_LENGTH: + fmt = dot_format; + rval = js_length_str; + goto do_getprop_lval; + + case JSOP_GETPROP2: + op = JSOP_GETPROP; + (void) PopOff(ss, lastop); + /* FALL THROUGH */ + + case JSOP_CALLPROP: + case JSOP_GETPROP: + case JSOP_GETXPROP: + LOAD_ATOM(0); + + do_getprop: + GET_QUOTE_AND_FMT(index_format, dot_format, rval); + do_getprop_lval: + PROPAGATE_CALLNESS(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, fmt, lval, rval); + break; + + case JSOP_GETTHISPROP: + LOAD_ATOM(0); + GET_QUOTE_AND_FMT(index_format, dot_format, rval); + todo = Sprint(&ss->sprinter, fmt, js_this_str, rval); + break; + + case JSOP_GETARGPROP: + /* Get the name of the argument or variable. */ + i = GET_ARGNO(pc); + + do_getarg_prop: + atom = GetArgOrVarAtom(ss->printer, i); + LOCAL_ASSERT(atom); + lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!lval || !PushOff(ss, STR2OFF(&ss->sprinter, lval), op)) + return NULL; + + /* Get the name of the property. */ + LOAD_ATOM(ARGNO_LEN); + goto do_getprop; + + case JSOP_GETLOCALPROP: + if (IsVarSlot(jp, pc, &i)) + goto do_getarg_prop; + LOCAL_ASSERT((uintN)i < ss->top); + lval = GetLocal(ss, i); + if (!lval) + return NULL; + todo = SprintCString(&ss->sprinter, lval); + if (todo < 0 || !PushOff(ss, todo, op)) + return NULL; + LOAD_ATOM(2); + goto do_getprop; + + case JSOP_SETPROP: + case JSOP_SETMETHOD: + LOAD_ATOM(0); + GET_QUOTE_AND_FMT("%s[%s] %s= %s", "%s.%s %s= %s", xval); + rval = POP_STR(); + + /* + * Force precedence below the numeric literal opcodes, so that + * 42..foo or 10000..toString(16), e.g., decompile with parens + * around the left-hand side of dot. + */ + op = JSOP_GETPROP; + lval = POP_STR(); + sn = js_GetSrcNote(jp->script, pc - 1); + todo = Sprint(&ss->sprinter, fmt, lval, xval, + (sn && SN_TYPE(sn) == SRC_ASSIGNOP) + ? (lastop == JSOP_GETTER) + ? js_getter_str + : (lastop == JSOP_SETTER) + ? js_setter_str + : CodeToken[lastop] + : "", + rval); + break; + + case JSOP_GETELEM2: + op = JSOP_GETELEM; + (void) PopOff(ss, lastop); + /* FALL THROUGH */ + + case JSOP_CALLELEM: + case JSOP_GETELEM: + op = JSOP_NOP; /* turn off parens */ + xval = POP_STR(); + op = saveop; + PROPAGATE_CALLNESS(); + lval = POP_STR(); + if (*xval == '\0') { + todo = Sprint(&ss->sprinter, "%s", lval); + } else { + todo = Sprint(&ss->sprinter, + (JOF_OPMODE(lastop) == JOF_XMLNAME) + ? dot_format + : index_format, + lval, xval); + } + break; + + case JSOP_SETELEM: + rval = POP_STR(); + op = JSOP_NOP; /* turn off parens */ + xval = POP_STR(); + cs = &js_CodeSpec[ss->opcodes[ss->top]]; + op = JSOP_GETELEM; /* lval must have high precedence */ + lval = POP_STR(); + op = saveop; + if (*xval == '\0') + goto do_setlval; + sn = js_GetSrcNote(jp->script, pc - 1); + todo = Sprint(&ss->sprinter, + (JOF_MODE(cs->format) == JOF_XMLNAME) + ? "%s.%s %s= %s" + : "%s[%s] %s= %s", + lval, xval, + (sn && SN_TYPE(sn) == SRC_ASSIGNOP) + ? (lastop == JSOP_GETTER) + ? js_getter_str + : (lastop == JSOP_SETTER) + ? js_setter_str + : CodeToken[lastop] + : "", + rval); + break; + + case JSOP_ARGSUB: + i = (jsint) GET_ARGNO(pc); + todo = Sprint(&ss->sprinter, "%s[%d]", + js_arguments_str, (int) i); + break; + + case JSOP_ARGCNT: + todo = Sprint(&ss->sprinter, dot_format, + js_arguments_str, js_length_str); + break; + + case JSOP_CALLARG: + case JSOP_GETARG: + i = GET_ARGNO(pc); + atom = GetArgOrVarAtom(jp, i); +#if JS_HAS_DESTRUCTURING + if (!atom) { + todo = Sprint(&ss->sprinter, "%s[%d]", js_arguments_str, i); + break; + } +#else + LOCAL_ASSERT(atom); +#endif + goto do_name; + + case JSOP_CALLGLOBAL: + case JSOP_GETGLOBAL: + atom = jp->script->getGlobalAtom(GET_SLOTNO(pc)); + goto do_name; + + case JSOP_CALLNAME: + case JSOP_NAME: + case JSOP_GETGNAME: + case JSOP_CALLGNAME: + LOAD_ATOM(0); + do_name: + lval = ""; +#if JS_HAS_XML_SUPPORT + do_qname: +#endif + sn = js_GetSrcNote(jp->script, pc); + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), + inXML ? DONT_ESCAPE : 0); + if (!rval) + return NULL; + RETRACT(&ss->sprinter, rval); + todo = Sprint(&ss->sprinter, sss_format, + VarPrefix(sn), lval, rval); + break; + + case JSOP_UINT16: + i = (jsint) GET_UINT16(pc); + goto do_sprint_int; + + case JSOP_UINT24: + i = (jsint) GET_UINT24(pc); + goto do_sprint_int; + + case JSOP_INT8: + i = GET_INT8(pc); + goto do_sprint_int; + + case JSOP_INT32: + i = GET_INT32(pc); + do_sprint_int: + todo = Sprint(&ss->sprinter, "%d", i); + break; + + case JSOP_DOUBLE: + { + double d; + GET_DOUBLE_FROM_BYTECODE(jp->script, pc, 0, d); + val = DOUBLE_TO_JSVAL(d); + todo = SprintDoubleValue(&ss->sprinter, val, &saveop); + break; + } + + case JSOP_STRING: + LOAD_ATOM(0); + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), + inXML ? DONT_ESCAPE : '"'); + if (!rval) + return NULL; + todo = STR2OFF(&ss->sprinter, rval); + break; + + case JSOP_LAMBDA: + case JSOP_LAMBDA_FC: + case JSOP_LAMBDA_DBGFC: +#if JS_HAS_GENERATOR_EXPRS + sn = js_GetSrcNote(jp->script, pc); + if (sn && SN_TYPE(sn) == SRC_GENEXP) { + void *mark; + jsuword *innerLocalNames, *outerLocalNames; + JSScript *inner, *outer; + SprintStack ss2; + JSFunction *outerfun; + + LOAD_FUNCTION(0); + + /* + * All allocation when decompiling is LIFO, using malloc + * or, more commonly, arena-allocating from cx->tempPool. + * Therefore after InitSprintStack succeeds, we must + * release to mark before returning. + */ + mark = JS_ARENA_MARK(&cx->tempPool); + if (fun->script()->bindings.hasLocalNames()) { + innerLocalNames = + fun->script()->bindings.getLocalNameArray(cx, &cx->tempPool); + if (!innerLocalNames) + return NULL; + } else { + innerLocalNames = NULL; + } + inner = fun->script(); + if (!InitSprintStack(cx, &ss2, jp, StackDepth(inner))) { + JS_ARENA_RELEASE(&cx->tempPool, mark); + return NULL; + } + ss2.inGenExp = JS_TRUE; + + /* + * Recursively decompile this generator function as an + * un-parenthesized generator expression. The ss->inGenExp + * special case of JSOP_YIELD shares array comprehension + * decompilation code that leaves the result as the single + * string pushed on ss2. + */ + outer = jp->script; + outerfun = jp->fun; + outerLocalNames = jp->localNames; + LOCAL_ASSERT(JS_UPTRDIFF(pc, outer->code) <= outer->length); + jp->script = inner; + jp->fun = fun; + jp->localNames = innerLocalNames; + + /* + * Decompile only the main bytecode, to avoid tripping over + * new prolog ops that have stack effects. + */ + ok = Decompile(&ss2, inner->main, + inner->length - (inner->main - inner->code), + JSOP_NOP) + != NULL; + jp->script = outer; + jp->fun = outerfun; + jp->localNames = outerLocalNames; + if (!ok) { + JS_ARENA_RELEASE(&cx->tempPool, mark); + return NULL; + } + + /* + * Advance over this op and its global |this| push, and + * arrange to advance over the call to this lambda. + */ + pc += len; + if (*pc == JSOP_BLOCKCHAIN) { + pc += JSOP_BLOCKCHAIN_LENGTH; + } else { + LOCAL_ASSERT(*pc == JSOP_NULLBLOCKCHAIN); + pc += JSOP_NULLBLOCKCHAIN_LENGTH; + } + LOCAL_ASSERT(*pc == JSOP_PUSH); + pc += JSOP_PUSH_LENGTH; + LOCAL_ASSERT(*pc == JSOP_CALL); + LOCAL_ASSERT(GET_ARGC(pc) == 0); + len = JSOP_CALL_LENGTH; + + /* + * Arrange to parenthesize this genexp unless: + * + * 1. It is the complete expression consumed by a control + * flow bytecode such as JSOP_TABLESWITCH whose syntax + * always parenthesizes the controlling expression. + * 2. It is the sole argument to a function call. + * + * But if this genexp runs up against endpc, parenthesize + * regardless. (This can happen if we are called from + * DecompileExpression or recursively from case + * JSOP_{NOP,AND,OR}.) + * + * There's no special case for |if (genexp)| because the + * compiler optimizes that to |if (true)|. + */ + pc2 = pc + len; + op = JSOp(*pc2); + if (op == JSOP_TRACE || op == JSOP_NOP) + pc2 += JSOP_NOP_LENGTH; + LOCAL_ASSERT(pc2 < endpc || + endpc < outer->code + outer->length); + LOCAL_ASSERT(ss2.top == 1); + ss2.opcodes[0] = JSOP_POP; + if (pc2 == endpc) { + op = JSOP_SETNAME; + } else { + op = (JSOp) *pc2; + op = ((js_CodeSpec[op].format & JOF_PARENHEAD) || + ((js_CodeSpec[op].format & JOF_INVOKE) && GET_ARGC(pc2) == 1)) + ? JSOP_POP + : JSOP_SETNAME; + + /* + * Stack this result as if it's a name and not an + * anonymous function, so it doesn't get decompiled as + * a generator function in a getter or setter context. + * The precedence level is the same for JSOP_NAME and + * JSOP_LAMBDA. + */ + LOCAL_ASSERT(js_CodeSpec[JSOP_NAME].prec == + js_CodeSpec[saveop].prec); + saveop = JSOP_NAME; + } + + /* + * Alas, we have to malloc a copy of the result left on + * the top of ss2 because both ss and ss2 arena-allocate + * from cx's tempPool. + */ + rval = JS_strdup(cx, PopStr(&ss2, op)); + JS_ARENA_RELEASE(&cx->tempPool, mark); + if (!rval) + return NULL; + todo = SprintCString(&ss->sprinter, rval); + cx->free((void *)rval); + break; + } +#endif /* JS_HAS_GENERATOR_EXPRS */ + /* FALL THROUGH */ + + LOAD_FUNCTION(0); + { + /* + * Always parenthesize expression closures. We can't force + * saveop to a low-precedence op to arrange for auto-magic + * parenthesization without confusing getter/setter code + * that checks for JSOP_LAMBDA. + */ + bool grouped = !(fun->flags & JSFUN_EXPR_CLOSURE); + bool strict = jp->script->strictModeCode; + str = js_DecompileToString(cx, "lambda", fun, 0, + false, grouped, strict, + js_DecompileFunction); + if (!str) + return NULL; + } + sprint_string: + todo = SprintString(&ss->sprinter, str); + break; + + case JSOP_CALLEE: + JS_ASSERT(jp->fun && jp->fun->atom); + todo = SprintString(&ss->sprinter, ATOM_TO_STRING(jp->fun->atom)); + break; + + case JSOP_OBJECT: + LOAD_OBJECT(0); + str = js_ValueToSource(cx, ObjectValue(*obj)); + if (!str) + return NULL; + goto sprint_string; + + case JSOP_REGEXP: + GET_REGEXP_FROM_BYTECODE(jp->script, pc, 0, obj); + if (!js_regexp_toString(cx, obj, Valueify(&val))) + return NULL; + str = JSVAL_TO_STRING(val); + goto sprint_string; + + case JSOP_TABLESWITCH: + case JSOP_TABLESWITCHX: + { + ptrdiff_t jmplen, off, off2; + jsint j, n, low, high; + TableEntry *table, *tmp; + + sn = js_GetSrcNote(jp->script, pc); + LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH); + len = js_GetSrcNoteOffset(sn, 0); + jmplen = (op == JSOP_TABLESWITCH) ? JUMP_OFFSET_LEN + : JUMPX_OFFSET_LEN; + pc2 = pc; + off = GetJumpOffset(pc, pc2); + pc2 += jmplen; + low = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + high = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + + n = high - low + 1; + if (n == 0) { + table = NULL; + j = 0; + ok = JS_TRUE; + } else { + table = (TableEntry *) + cx->malloc((size_t)n * sizeof *table); + if (!table) + return NULL; + for (i = j = 0; i < n; i++) { + table[j].label = NULL; + off2 = GetJumpOffset(pc, pc2); + if (off2) { + sn = js_GetSrcNote(jp->script, pc2); + if (sn) { + LOCAL_ASSERT(SN_TYPE(sn) == SRC_LABEL); + GET_SOURCE_NOTE_ATOM(sn, table[j].label); + } + table[j].key = INT_TO_JSVAL(low + i); + table[j].offset = off2; + table[j].order = j; + j++; + } + pc2 += jmplen; + } + tmp = (TableEntry *) + cx->malloc((size_t)j * sizeof *table); + if (tmp) { + VOUCH_DOES_NOT_REQUIRE_STACK(); + ok = js_MergeSort(table, (size_t)j, sizeof(TableEntry), + CompareOffsets, NULL, tmp, + JS_SORTING_GENERIC); + cx->free(tmp); + } else { + ok = JS_FALSE; + } + } + + if (ok) { + ok = DecompileSwitch(ss, table, (uintN)j, pc, len, off, + JS_FALSE); + } + cx->free(table); + if (!ok) + return NULL; + todo = -2; + break; + } + + case JSOP_LOOKUPSWITCH: + case JSOP_LOOKUPSWITCHX: + { + ptrdiff_t jmplen, off, off2; + jsatomid npairs, k; + TableEntry *table; + + sn = js_GetSrcNote(jp->script, pc); + LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH); + len = js_GetSrcNoteOffset(sn, 0); + jmplen = (op == JSOP_LOOKUPSWITCH) ? JUMP_OFFSET_LEN + : JUMPX_OFFSET_LEN; + pc2 = pc; + off = GetJumpOffset(pc, pc2); + pc2 += jmplen; + npairs = GET_UINT16(pc2); + pc2 += UINT16_LEN; + + table = (TableEntry *) + cx->malloc((size_t)npairs * sizeof *table); + if (!table) + return NULL; + for (k = 0; k < npairs; k++) { + sn = js_GetSrcNote(jp->script, pc2); + if (sn) { + LOCAL_ASSERT(SN_TYPE(sn) == SRC_LABEL); + GET_SOURCE_NOTE_ATOM(sn, table[k].label); + } else { + table[k].label = NULL; + } + uint16 constIndex = GET_INDEX(pc2); + pc2 += INDEX_LEN; + off2 = GetJumpOffset(pc, pc2); + pc2 += jmplen; + table[k].key = Jsvalify(jp->script->getConst(constIndex)); + table[k].offset = off2; + } + + ok = DecompileSwitch(ss, table, (uintN)npairs, pc, len, off, + JS_FALSE); + cx->free(table); + if (!ok) + return NULL; + todo = -2; + break; + } + + case JSOP_CONDSWITCH: + { + ptrdiff_t off, off2, caseOff; + jsint ncases; + TableEntry *table; + + sn = js_GetSrcNote(jp->script, pc); + LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH); + len = js_GetSrcNoteOffset(sn, 0); + off = js_GetSrcNoteOffset(sn, 1); + + /* + * Count the cases using offsets from switch to first case, + * and case to case, stored in srcnote immediates. + */ + pc2 = pc; + off2 = off; + for (ncases = 0; off2 != 0; ncases++) { + pc2 += off2; + LOCAL_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT || + *pc2 == JSOP_CASEX || *pc2 == JSOP_DEFAULTX); + if (*pc2 == JSOP_DEFAULT || *pc2 == JSOP_DEFAULTX) { + /* End of cases, but count default as a case. */ + off2 = 0; + } else { + sn = js_GetSrcNote(jp->script, pc2); + LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_PCDELTA); + off2 = js_GetSrcNoteOffset(sn, 0); + } + } + + /* + * Allocate table and rescan the cases using their srcnotes, + * stashing each case's delta from switch top in table[i].key, + * and the distance to its statements in table[i].offset. + */ + table = (TableEntry *) + cx->malloc((size_t)ncases * sizeof *table); + if (!table) + return NULL; + pc2 = pc; + off2 = off; + for (i = 0; i < ncases; i++) { + pc2 += off2; + LOCAL_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT || + *pc2 == JSOP_CASEX || *pc2 == JSOP_DEFAULTX); + caseOff = pc2 - pc; + table[i].key = INT_TO_JSVAL((jsint) caseOff); + table[i].offset = caseOff + GetJumpOffset(pc2, pc2); + if (*pc2 == JSOP_CASE || *pc2 == JSOP_CASEX) { + sn = js_GetSrcNote(jp->script, pc2); + LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_PCDELTA); + off2 = js_GetSrcNoteOffset(sn, 0); + } + } + + /* + * Find offset of default code by fetching the default offset + * from the end of table. JSOP_CONDSWITCH always has a default + * case at the end. + */ + off = JSVAL_TO_INT(table[ncases-1].key); + pc2 = pc + off; + off += GetJumpOffset(pc2, pc2); + + ok = DecompileSwitch(ss, table, (uintN)ncases, pc, len, off, + JS_TRUE); + cx->free(table); + if (!ok) + return NULL; + todo = -2; + break; + } + + case JSOP_CASE: + case JSOP_CASEX: + { + lval = POP_STR(); + if (!lval) + return NULL; + js_printf(jp, "\tcase %s:\n", lval); + todo = -2; + break; + } + + case JSOP_DEFFUN: + case JSOP_DEFFUN_FC: + case JSOP_DEFFUN_DBGFC: + LOAD_FUNCTION(0); + todo = -2; + goto do_function; + break; + + case JSOP_TRAP: + saveop = op = JS_GetTrapOpcode(cx, jp->script, pc); + *pc = op; + cs = &js_CodeSpec[op]; + len = cs->length; + DECOMPILE_CODE(pc, len); + *pc = JSOP_TRAP; + todo = -2; + break; + + case JSOP_HOLE: + todo = SprintPut(&ss->sprinter, "", 0); + break; + + case JSOP_NEWINIT: + { + i = pc[1]; + LOCAL_ASSERT(i == JSProto_Array || i == JSProto_Object); + + todo = ss->sprinter.offset; +#if JS_HAS_SHARP_VARS + op = (JSOp)pc[len]; + if (op == JSOP_SHARPINIT) + op = (JSOp)pc[len += JSOP_SHARPINIT_LENGTH]; + if (op == JSOP_DEFSHARP) { + pc += len; + cs = &js_CodeSpec[op]; + len = cs->length; + if (Sprint(&ss->sprinter, "#%u=", + (unsigned) (jsint) GET_UINT16(pc + UINT16_LEN)) + < 0) { + return NULL; + } + } +#endif /* JS_HAS_SHARP_VARS */ + if (i == JSProto_Array) { + ++ss->inArrayInit; + if (SprintCString(&ss->sprinter, "[") < 0) + return NULL; + } else { + if (SprintCString(&ss->sprinter, "{") < 0) + return NULL; + } + break; + } + + case JSOP_NEWARRAY: + { + todo = ss->sprinter.offset; + ++ss->inArrayInit; + if (SprintCString(&ss->sprinter, "[") < 0) + return NULL; + break; + } + + case JSOP_NEWOBJECT: + { + todo = ss->sprinter.offset; + if (SprintCString(&ss->sprinter, "{") < 0) + return NULL; + break; + } + + case JSOP_ENDINIT: + { + JSBool inArray; + + op = JSOP_NOP; /* turn off parens */ + rval = POP_STR(); + sn = js_GetSrcNote(jp->script, pc); + + /* Skip any #n= prefix to find the opening bracket. */ + for (xval = rval; *xval != '[' && *xval != '{'; xval++) + continue; + inArray = (*xval == '['); + if (inArray) + --ss->inArrayInit; + todo = Sprint(&ss->sprinter, "%s%s%c", + rval, + (sn && SN_TYPE(sn) == SRC_CONTINUE) ? ", " : "", + inArray ? ']' : '}'); + break; + } + + { + JSBool isFirst; + const char *maybeComma; + + case JSOP_INITELEM: + isFirst = IsInitializerOp(ss->opcodes[ss->top - 3]); + + /* Turn off most parens. */ + op = JSOP_SETNAME; + rval = POP_STR(); + + /* Turn off all parens for xval and lval, which we control. */ + op = JSOP_NOP; + xval = POP_STR(); + lval = POP_STR(); + sn = js_GetSrcNote(jp->script, pc); + + if (sn && SN_TYPE(sn) == SRC_INITPROP) { + atom = NULL; + goto do_initprop; + } + maybeComma = isFirst ? "" : ", "; + todo = Sprint(&ss->sprinter, sss_format, + lval, + maybeComma, + rval); + break; + + case JSOP_INITPROP: + case JSOP_INITMETHOD: + LOAD_ATOM(0); + xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), + jschar(ATOM_IS_IDENTIFIER(atom) ? 0 : '\'')); + if (!xval) + return NULL; + isFirst = IsInitializerOp(ss->opcodes[ss->top - 2]); + rval = POP_STR(); + lval = POP_STR(); + /* fall through */ + + do_initprop: + maybeComma = isFirst ? "" : ", "; + if (lastop == JSOP_GETTER || lastop == JSOP_SETTER) { + const char *end = rval + strlen(rval); + + if (*rval == '(') + ++rval, --end; + LOCAL_ASSERT(strncmp(rval, js_function_str, 8) == 0); + LOCAL_ASSERT(rval[8] == ' '); + rval += 8 + 1; + LOCAL_ASSERT(*end ? *end == ')' : end[-1] == '}'); + todo = Sprint(&ss->sprinter, "%s%s%s %s%s%.*s", + lval, + maybeComma, + (lastop == JSOP_GETTER) + ? js_get_str : js_set_str, + xval, + (rval[0] != '(') ? " " : "", + end - rval, rval); + } else { + todo = Sprint(&ss->sprinter, "%s%s%s: %s", + lval, maybeComma, xval, rval); + } + break; + } + +#if JS_HAS_SHARP_VARS + case JSOP_DEFSHARP: + i = (jsint) GET_UINT16(pc + UINT16_LEN); + rval = POP_STR(); + todo = Sprint(&ss->sprinter, "#%u=%s", (unsigned) i, rval); + break; + + case JSOP_USESHARP: + i = (jsint) GET_UINT16(pc + UINT16_LEN); + todo = Sprint(&ss->sprinter, "#%u#", (unsigned) i); + break; +#endif /* JS_HAS_SHARP_VARS */ + + case JSOP_DEBUGGER: + js_printf(jp, "\tdebugger;\n"); + todo = -2; + break; + +#if JS_HAS_XML_SUPPORT + case JSOP_STARTXML: + case JSOP_STARTXMLEXPR: + inXML = op == JSOP_STARTXML; + todo = -2; + break; + + case JSOP_DEFXMLNS: + rval = POP_STR(); + js_printf(jp, "\t%s %s %s = %s;\n", + js_default_str, js_xml_str, js_namespace_str, rval); + todo = -2; + break; + + case JSOP_ANYNAME: + if (pc[JSOP_ANYNAME_LENGTH] == JSOP_TOATTRNAME) { + len += JSOP_TOATTRNAME_LENGTH; + todo = SprintPut(&ss->sprinter, "@*", 2); + } else { + todo = SprintPut(&ss->sprinter, "*", 1); + } + break; + + case JSOP_QNAMEPART: + LOAD_ATOM(0); + if (pc[JSOP_QNAMEPART_LENGTH] == JSOP_TOATTRNAME) { + saveop = JSOP_TOATTRNAME; + len += JSOP_TOATTRNAME_LENGTH; + lval = "@"; + goto do_qname; + } + goto do_name; + + case JSOP_QNAMECONST: + LOAD_ATOM(0); + rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); + if (!rval) + return NULL; + RETRACT(&ss->sprinter, rval); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s::%s", lval, rval); + break; + + case JSOP_QNAME: + rval = POP_STR(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s::[%s]", lval, rval); + break; + + case JSOP_TOATTRNAME: + op = JSOP_NOP; /* turn off parens */ + rval = POP_STR(); + todo = Sprint(&ss->sprinter, "@[%s]", rval); + break; + + case JSOP_TOATTRVAL: + todo = -2; + break; + + case JSOP_ADDATTRNAME: + rval = POP_STR(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s %s", lval, rval); + /* This gets reset by all XML tag expressions. */ + quoteAttr = JS_TRUE; + break; + + case JSOP_ADDATTRVAL: + rval = POP_STR(); + lval = POP_STR(); + if (quoteAttr) + todo = Sprint(&ss->sprinter, "%s=\"%s\"", lval, rval); + else + todo = Sprint(&ss->sprinter, "%s=%s", lval, rval); + break; + + case JSOP_BINDXMLNAME: + /* Leave the name stacked and push a dummy string. */ + todo = Sprint(&ss->sprinter, ""); + break; + + case JSOP_SETXMLNAME: + /* Pop the r.h.s., the dummy string, and the name. */ + rval = POP_STR(); + (void) PopOff(ss, op); + lval = POP_STR(); + goto do_setlval; + + case JSOP_XMLELTEXPR: + case JSOP_XMLTAGEXPR: + todo = Sprint(&ss->sprinter, "{%s}", POP_STR()); + inXML = JS_TRUE; + /* If we're an attribute value, we shouldn't quote this. */ + quoteAttr = JS_FALSE; + break; + + case JSOP_TOXMLLIST: + op = JSOP_NOP; /* turn off parens */ + todo = Sprint(&ss->sprinter, "<>%s", POP_STR()); + inXML = JS_FALSE; + break; + + case JSOP_TOXML: + case JSOP_CALLXMLNAME: + case JSOP_XMLNAME: + case JSOP_FILTER: + /* These ops indicate the end of XML expressions. */ + inXML = JS_FALSE; + todo = -2; + break; + + case JSOP_ENDFILTER: + rval = POP_STR(); + PROPAGATE_CALLNESS(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s.(%s)", lval, rval); + break; + + case JSOP_DESCENDANTS: + rval = POP_STR(); + PROPAGATE_CALLNESS(); + lval = POP_STR(); + todo = Sprint(&ss->sprinter, "%s..%s", lval, rval); + break; + + case JSOP_XMLCDATA: + LOAD_ATOM(0); + todo = SprintPut(&ss->sprinter, "sprinter, ATOM_TO_STRING(atom), + DONT_ESCAPE)) + return NULL; + SprintPut(&ss->sprinter, "]]>", 3); + break; + + case JSOP_XMLCOMMENT: + LOAD_ATOM(0); + todo = SprintPut(&ss->sprinter, "", 3); + break; + + case JSOP_XMLPI: + LOAD_ATOM(0); + rval = JS_strdup(cx, POP_STR()); + if (!rval) + return NULL; + todo = SprintPut(&ss->sprinter, "sprinter, ATOM_TO_STRING(atom), 0) && + (*rval == '\0' || + (SprintPut(&ss->sprinter, " ", 1) >= 0 && + SprintCString(&ss->sprinter, rval))); + cx->free((char *)rval); + if (!ok) + return NULL; + SprintPut(&ss->sprinter, "?>", 2); + break; + + case JSOP_GETFUNNS: + todo = SprintPut(&ss->sprinter, js_function_str, 8); + break; +#endif /* JS_HAS_XML_SUPPORT */ + + default: + todo = -2; + break; + } + } + + if (todo < 0) { + /* -2 means "don't push", -1 means reported error. */ + if (todo == -1) + return NULL; + } else { + if (!PushOff(ss, todo, saveop)) + return NULL; + } + + if (cs->format & JOF_CALLOP) { + todo = Sprint(&ss->sprinter, ""); + if (todo < 0 || !PushOff(ss, todo, saveop)) + return NULL; + } + + pc += len; + } + +/* + * Undefine local macros. + */ +#undef inXML +#undef DECOMPILE_CODE +#undef NEXT_OP +#undef TOP_STR +#undef POP_STR +#undef POP_STR_PREC +#undef LOCAL_ASSERT +#undef ATOM_IS_IDENTIFIER +#undef GET_QUOTE_AND_FMT +#undef GET_ATOM_QUOTE_AND_FMT + + return pc; +} + +static JSBool +DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len, + uintN pcdepth) +{ + uintN depth, i; + SprintStack ss; + JSContext *cx; + void *mark; + JSBool ok; + JSScript *oldscript; + char *last; + + depth = StackDepth(script); + JS_ASSERT(pcdepth <= depth); + cx = jp->sprinter.context; + + AutoScriptUntrapper untrapper(cx, script, &pc); + + /* Initialize a sprinter for use with the offset stack. */ + mark = JS_ARENA_MARK(&cx->tempPool); + ok = InitSprintStack(cx, &ss, jp, depth); + if (!ok) + goto out; + + /* + * If we are called from js_DecompileValueGenerator with a portion of + * script's bytecode that starts with a non-zero model stack depth given + * by pcdepth, attempt to initialize the missing string offsets in ss to + * |spindex| negative indexes from fp->sp for the activation fp in which + * the error arose. + * + * See js_DecompileValueGenerator for how its |spindex| parameter is used, + * and see also GetOff, which makes use of the ss.offsets[i] < -1 that are + * potentially stored below. + */ + ss.top = pcdepth; + if (pcdepth != 0) { + for (i = 0; i < pcdepth; i++) { + ss.offsets[i] = -2 - (ptrdiff_t)i; + ss.opcodes[i] = *jp->pcstack[i]; + } + } + + /* Call recursive subroutine to do the hard work. */ + oldscript = jp->script; + jp->script = script; + ok = Decompile(&ss, pc, len, JSOP_NOP) != NULL; + jp->script = oldscript; + + /* If the given code didn't empty the stack, do it now. */ + if (ok && ss.top) { + do { + last = OFF2STR(&ss.sprinter, PopOff(&ss, JSOP_POP)); + } while (ss.top > pcdepth); + js_printf(jp, "%s", last); + } + +out: + /* Free all temporary stuff allocated under this call. */ + JS_ARENA_RELEASE(&cx->tempPool, mark); + return ok; +} + +/* + * Decompile a function body, expression closure expression, or complete + * script. Start at |pc|; go to the end of |script|. Include a directive + * prologue, if appropriate. + */ +static JSBool +DecompileBody(JSPrinter *jp, JSScript *script, jsbytecode *pc) +{ + /* Print a strict mode code directive, if needed. */ + if (script->strictModeCode && !jp->strict) { + if (jp->fun && (jp->fun->flags & JSFUN_EXPR_CLOSURE)) { + /* + * We have no syntax for strict function expressions; + * at least give a hint. + */ + js_printf(jp, "\t/* use strict */ \n"); + } else { + js_printf(jp, "\t\"use strict\";\n"); + } + jp->strict = true; + } + + jsbytecode *end = script->code + script->length; + return DecompileCode(jp, script, pc, end - pc, 0); +} + +JSBool +js_DecompileScript(JSPrinter *jp, JSScript *script) +{ + return DecompileBody(jp, script, script->code); +} + +JSString * +js_DecompileToString(JSContext *cx, const char *name, JSFunction *fun, + uintN indent, JSBool pretty, JSBool grouped, JSBool strict, + JSDecompilerPtr decompiler) +{ + JSPrinter *jp; + JSString *str; + + jp = js_NewPrinter(cx, name, fun, indent, pretty, grouped, strict); + if (!jp) + return NULL; + if (decompiler(jp)) + str = js_GetPrinterOutput(jp); + else + str = NULL; + js_DestroyPrinter(jp); + return str; +} + +static const char native_code_str[] = "\t[native code]\n"; + +JSBool +js_DecompileFunctionBody(JSPrinter *jp) +{ + JSScript *script; + + JS_ASSERT(jp->fun); + JS_ASSERT(!jp->script); + if (!FUN_INTERPRETED(jp->fun)) { + js_printf(jp, native_code_str); + return JS_TRUE; + } + + script = jp->fun->u.i.script; + return DecompileBody(jp, script, script->code); +} + +JSBool +js_DecompileFunction(JSPrinter *jp) +{ + JSFunction *fun; + uintN i; + JSAtom *param; + jsbytecode *pc, *endpc; + JSBool ok; + + fun = jp->fun; + JS_ASSERT(fun); + JS_ASSERT(!jp->script); + + /* + * If pretty, conform to ECMA-262 Edition 3, 15.3.4.2, by decompiling a + * FunctionDeclaration. Otherwise, check the JSFUN_LAMBDA flag and force + * an expression by parenthesizing. + */ + if (jp->pretty) { + js_printf(jp, "\t"); + } else { + if (!jp->grouped && (fun->flags & JSFUN_LAMBDA)) + js_puts(jp, "("); + } + + js_printf(jp, "%s ", js_function_str); + if (fun->atom && !QuoteString(&jp->sprinter, ATOM_TO_STRING(fun->atom), 0)) + return JS_FALSE; + js_puts(jp, "("); + + if (!FUN_INTERPRETED(fun)) { + js_printf(jp, ") {\n"); + jp->indent += 4; + js_printf(jp, native_code_str); + jp->indent -= 4; + js_printf(jp, "\t}"); + } else { + JSScript *script = fun->u.i.script; +#if JS_HAS_DESTRUCTURING + SprintStack ss; + void *mark; +#endif + + /* Print the parameters. */ + pc = script->main; + AutoScriptUntrapper untrapper(jp->sprinter.context, script, &pc); + endpc = pc + script->length; + ok = JS_TRUE; + +#if JS_HAS_DESTRUCTURING + ss.printer = NULL; + jp->script = script; + mark = JS_ARENA_MARK(&jp->sprinter.context->tempPool); +#endif + + for (i = 0; i < fun->nargs; i++) { + if (i > 0) + js_puts(jp, ", "); + + param = GetArgOrVarAtom(jp, i); + +#if JS_HAS_DESTRUCTURING +#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, JS_FALSE) + + if (!param) { + ptrdiff_t todo; + const char *lval; + + LOCAL_ASSERT(*pc == JSOP_GETARG); + pc += JSOP_GETARG_LENGTH; + LOCAL_ASSERT(*pc == JSOP_DUP); + if (!ss.printer) { + ok = InitSprintStack(jp->sprinter.context, &ss, jp, StackDepth(script)); + if (!ok) + break; + } + pc = DecompileDestructuring(&ss, pc, endpc); + if (!pc) { + ok = JS_FALSE; + break; + } + LOCAL_ASSERT(*pc == JSOP_POP); + pc += JSOP_POP_LENGTH; + lval = PopStr(&ss, JSOP_NOP); + todo = SprintCString(&jp->sprinter, lval); + if (todo < 0) { + ok = JS_FALSE; + break; + } + continue; + } + +#undef LOCAL_ASSERT +#endif + + if (!QuoteString(&jp->sprinter, ATOM_TO_STRING(param), 0)) { + ok = JS_FALSE; + break; + } + } + +#if JS_HAS_DESTRUCTURING + jp->script = NULL; + JS_ARENA_RELEASE(&jp->sprinter.context->tempPool, mark); +#endif + if (!ok) + return JS_FALSE; + js_printf(jp, ") "); + if (!(fun->flags & JSFUN_EXPR_CLOSURE)) { + js_printf(jp, "{\n"); + jp->indent += 4; + } + + ok = DecompileBody(jp, script, pc); + if (!ok) + return JS_FALSE; + + if (!(fun->flags & JSFUN_EXPR_CLOSURE)) { + jp->indent -= 4; + js_printf(jp, "\t}"); + } + } + + if (!jp->pretty && !jp->grouped && (fun->flags & JSFUN_LAMBDA)) + js_puts(jp, ")"); + + return JS_TRUE; +} + +char * +js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in, + JSString *fallback) +{ + JSStackFrame *fp; + JSScript *script; + jsbytecode *pc; + + Value v = Valueify(v_in); + + JS_ASSERT(spindex < 0 || + spindex == JSDVG_IGNORE_STACK || + spindex == JSDVG_SEARCH_STACK); + + LeaveTrace(cx); + + if (!cx->regs || !cx->regs->fp || !cx->regs->fp->isScriptFrame()) + goto do_fallback; + + fp = cx->regs->fp; + script = fp->script(); + pc = fp->hasImacropc() ? fp->imacropc() : cx->regs->pc; + JS_ASSERT(script->code <= pc && pc < script->code + script->length); + + if (pc < script->main) + goto do_fallback; + + if (spindex != JSDVG_IGNORE_STACK) { + jsbytecode **pcstack; + + /* + * Prepare computing pcstack containing pointers to opcodes that + * populated interpreter's stack with its current content. + */ + pcstack = (jsbytecode **) + cx->malloc(StackDepth(script) * sizeof *pcstack); + if (!pcstack) + return NULL; + intN pcdepth = ReconstructPCStack(cx, script, pc, pcstack); + if (pcdepth < 0) + goto release_pcstack; + + if (spindex != JSDVG_SEARCH_STACK) { + JS_ASSERT(spindex < 0); + pcdepth += spindex; + if (pcdepth < 0) + goto release_pcstack; + pc = pcstack[pcdepth]; + } else { + /* + * We search from fp->sp to base to find the most recently + * calculated value matching v under assumption that it is + * it that caused exception, see bug 328664. + */ + Value *stackBase = fp->base(); + Value *sp = cx->regs->sp; + do { + if (sp == stackBase) { + pcdepth = -1; + goto release_pcstack; + } + } while (*--sp != v); + + /* + * The value may have come from beyond stackBase + pcdepth, meaning + * that it came from a temporary slot pushed by the interpreter or + * arguments pushed for an Invoke call. Only update pc if beneath + * stackBase + pcdepth. If above, the value may or may not be + * produced by the current pc. Since it takes a fairly contrived + * combination of calls to produce a situation where this is not + * what we want, we just use the current pc. + */ + if (sp < stackBase + pcdepth) + pc = pcstack[sp - stackBase]; + } + + release_pcstack: + cx->free(pcstack); + if (pcdepth < 0) + goto do_fallback; + } + + { + jsbytecode* basepc = cx->regs->pc; + jsbytecode* savedImacropc = fp->maybeImacropc(); + if (savedImacropc) { + JS_ASSERT(cx->hasfp()); + cx->regs->pc = savedImacropc; + fp->clearImacropc(); + } + + /* + * FIXME: bug 489843. Stack reconstruction may have returned a pc + * value *inside* an imacro; this would confuse the decompiler. + */ + char *name; + if (savedImacropc && size_t(pc - script->code) >= script->length) + name = FAILED_EXPRESSION_DECOMPILER; + else + name = DecompileExpression(cx, script, fp->maybeFun(), pc); + + if (savedImacropc) { + JS_ASSERT(cx->hasfp()); + cx->regs->pc = basepc; + fp->setImacropc(savedImacropc); + } + + if (name != FAILED_EXPRESSION_DECOMPILER) + return name; + } + + do_fallback: + if (!fallback) { + fallback = js_ValueToSource(cx, v); + if (!fallback) + return NULL; + } + size_t length = fallback->length(); + const jschar *chars = fallback->getChars(cx); + if (!chars) + return NULL; + return js_DeflateString(cx, chars, length); +} + +static char * +DecompileExpression(JSContext *cx, JSScript *script, JSFunction *fun, + jsbytecode *pc) +{ + JSOp op; + const JSCodeSpec *cs; + jsbytecode *begin, *end; + jssrcnote *sn; + ptrdiff_t len; + jsbytecode **pcstack; + intN pcdepth; + JSPrinter *jp; + char *name; + + JS_ASSERT(script->code <= pc && pc < script->code + script->length); + + pcstack = NULL; + AutoScriptUntrapper untrapper(cx, script, &pc); + op = (JSOp) *pc; + + /* None of these stack-writing ops generates novel values. */ + JS_ASSERT(op != JSOP_CASE && op != JSOP_CASEX && + op != JSOP_DUP && op != JSOP_DUP2); + + /* JSOP_PUSH is used to generate undefined for group assignment holes. */ + if (op == JSOP_PUSH) { + name = JS_strdup(cx, js_undefined_str); + goto out; + } + + /* + * |this| could convert to a very long object initialiser, so cite it by + * its keyword name instead. + */ + if (op == JSOP_THIS) { + name = JS_strdup(cx, js_this_str); + goto out; + } + + /* + * JSOP_BINDNAME is special: it generates a value, the base object of a + * reference. But if it is the generating op for a diagnostic produced by + * js_DecompileValueGenerator, the name being bound is irrelevant. Just + * fall back to the base object. + */ + if (op == JSOP_BINDNAME) { + name = FAILED_EXPRESSION_DECOMPILER; + goto out; + } + + /* NAME ops are self-contained, others require left or right context. */ + cs = &js_CodeSpec[op]; + begin = pc; + end = pc + cs->length; + switch (JOF_MODE(cs->format)) { + case JOF_PROP: + case JOF_ELEM: + case JOF_XMLNAME: + case 0: + sn = js_GetSrcNote(script, pc); + if (!sn) { + name = FAILED_EXPRESSION_DECOMPILER; + goto out; + } + switch (SN_TYPE(sn)) { + case SRC_PCBASE: + begin -= js_GetSrcNoteOffset(sn, 0); + break; + case SRC_PCDELTA: + end = begin + js_GetSrcNoteOffset(sn, 0); + begin += cs->length; + break; + default: + name = FAILED_EXPRESSION_DECOMPILER; + goto out; + } + break; + default:; + } + len = end - begin; + if (len <= 0) { + name = FAILED_EXPRESSION_DECOMPILER; + goto out; + } + + pcstack = (jsbytecode **) + cx->malloc(StackDepth(script) * sizeof *pcstack); + if (!pcstack) { + name = NULL; + goto out; + } + + MUST_FLOW_THROUGH("out"); + pcdepth = ReconstructPCStack(cx, script, begin, pcstack); + if (pcdepth < 0) { + name = FAILED_EXPRESSION_DECOMPILER; + goto out; + } + + name = NULL; + jp = js_NewPrinter(cx, "js_DecompileValueGenerator", fun, 0, + false, false, false); + if (jp) { + jp->dvgfence = end; + jp->pcstack = pcstack; + if (DecompileCode(jp, script, begin, (uintN) len, (uintN) pcdepth)) { + name = (jp->sprinter.base) ? jp->sprinter.base : (char *) ""; + name = JS_strdup(cx, name); + } + js_DestroyPrinter(jp); + } + +out: + cx->free(pcstack); + return name; +} + +uintN +js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + return ReconstructPCStack(cx, script, pc, NULL); +} + +#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, -1); + +static intN +SimulateOp(JSContext *cx, JSScript *script, JSOp op, const JSCodeSpec *cs, + jsbytecode *pc, jsbytecode **pcstack, uintN &pcdepth) +{ + uintN nuses = js_GetStackUses(cs, op, pc); + uintN ndefs = js_GetStackDefs(cx, cs, op, script, pc); + LOCAL_ASSERT(pcdepth >= nuses); + pcdepth -= nuses; + LOCAL_ASSERT(pcdepth + ndefs <= StackDepth(script)); + + /* + * Fill the slots that the opcode defines withs its pc unless it just + * reshuffles the stack. In the latter case we want to preserve the + * opcode that generated the original value. + */ + switch (op) { + default: + if (pcstack) { + for (uintN i = 0; i != ndefs; ++i) + pcstack[pcdepth + i] = pc; + } + break; + + case JSOP_CASE: + case JSOP_CASEX: + /* Keep the switch value. */ + JS_ASSERT(ndefs == 1); + break; + + case JSOP_DUP: + JS_ASSERT(ndefs == 2); + if (pcstack) + pcstack[pcdepth + 1] = pcstack[pcdepth]; + break; + + case JSOP_DUP2: + JS_ASSERT(ndefs == 4); + if (pcstack) { + pcstack[pcdepth + 2] = pcstack[pcdepth]; + pcstack[pcdepth + 3] = pcstack[pcdepth + 1]; + } + break; + + case JSOP_SWAP: + JS_ASSERT(ndefs == 2); + if (pcstack) { + jsbytecode *tmp = pcstack[pcdepth + 1]; + pcstack[pcdepth + 1] = pcstack[pcdepth]; + pcstack[pcdepth] = tmp; + } + break; + } + pcdepth += ndefs; + return pcdepth; +} + +#ifdef JS_TRACER + +#undef LOCAL_ASSERT +#define LOCAL_ASSERT(expr) LOCAL_ASSERT_CUSTOM(expr, goto failure); + +static intN +SimulateImacroCFG(JSContext *cx, JSScript *script, + uintN pcdepth, jsbytecode *pc, jsbytecode *target, + jsbytecode **pcstack) +{ + size_t nbytes = 0; + jsbytecode** tmp_pcstack = NULL; + if (pcstack) { + nbytes = StackDepth(script) * sizeof *pcstack; + tmp_pcstack = (jsbytecode **) cx->malloc(nbytes); + if (!tmp_pcstack) + return -1; + memcpy(tmp_pcstack, pcstack, nbytes); + } + + ptrdiff_t oplen; + for (; pc < target; pc += oplen) { + JSOp op = js_GetOpcode(cx, script, pc); + const JSCodeSpec *cs = &js_CodeSpec[op]; + oplen = cs->length; + if (oplen < 0) + oplen = js_GetVariableBytecodeLength(pc); + + if (SimulateOp(cx, script, op, cs, pc, tmp_pcstack, pcdepth) < 0) + goto failure; + + uint32 type = cs->format & JOF_TYPEMASK; + if (type == JOF_JUMP || type == JOF_JUMPX) { + ptrdiff_t jmpoff = (type == JOF_JUMP) ? GET_JUMP_OFFSET(pc) + : GET_JUMPX_OFFSET(pc); + LOCAL_ASSERT(jmpoff >= 0); + intN tmp_pcdepth = SimulateImacroCFG(cx, script, pcdepth, pc + jmpoff, + target, tmp_pcstack); + if (tmp_pcdepth >= 0) { + pcdepth = uintN(tmp_pcdepth); + goto success; + } + + if (op == JSOP_GOTO || op == JSOP_GOTOX) + goto failure; + } + } + + if (pc > target) + goto failure; + + LOCAL_ASSERT(pc == target); + + success: + if (tmp_pcstack) { + memcpy(pcstack, tmp_pcstack, nbytes); + cx->free(tmp_pcstack); + } + return pcdepth; + + failure: + if (tmp_pcstack) + cx->free(tmp_pcstack); + return -1; +} + +#undef LOCAL_ASSERT +#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, -1); + +static intN +ReconstructImacroPCStack(JSContext *cx, JSScript *script, + jsbytecode *imacstart, jsbytecode *target, + jsbytecode **pcstack) +{ + /* + * Begin with a recursive call back to ReconstructPCStack to pick up + * the state-of-the-world at the *start* of the imacro. + */ + JSStackFrame *fp = js_GetScriptedCaller(cx, NULL); + JS_ASSERT(fp->hasImacropc()); + intN pcdepth = ReconstructPCStack(cx, script, fp->imacropc(), pcstack); + if (pcdepth < 0) + return pcdepth; + return SimulateImacroCFG(cx, script, pcdepth, imacstart, target, pcstack); +} + +extern jsbytecode* js_GetImacroStart(jsbytecode* pc); +#endif + +static intN +ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target, + jsbytecode **pcstack) +{ + /* + * Walk forward from script->main and compute the stack depth and stack of + * operand-generating opcode PCs in pcstack. + * + * FIXME: Code to compute oplen copied from js_Disassemble1 and reduced. + * FIXME: Optimize to use last empty-stack sequence point. + */ +#ifdef JS_TRACER + jsbytecode *imacstart = js_GetImacroStart(target); + + if (imacstart) + return ReconstructImacroPCStack(cx, script, imacstart, target, pcstack); +#endif + + LOCAL_ASSERT(script->code <= target && target < script->code + script->length); + jsbytecode *pc = script->code; + uintN pcdepth = 0; + ptrdiff_t oplen; + for (; pc < target; pc += oplen) { + JSOp op = js_GetOpcode(cx, script, pc); + const JSCodeSpec *cs = &js_CodeSpec[op]; + oplen = cs->length; + if (oplen < 0) + oplen = js_GetVariableBytecodeLength(pc); + + /* + * A (C ? T : E) expression requires skipping either T (if target is in + * E) or both T and E (if target is after the whole expression) before + * adjusting pcdepth based on the JSOP_IFEQ or JSOP_IFEQX at pc that + * tests condition C. We know that the stack depth can't change from + * what it was with C on top of stack. + */ + jssrcnote *sn = js_GetSrcNote(script, pc); + if (sn && SN_TYPE(sn) == SRC_COND) { + ptrdiff_t jmpoff = js_GetSrcNoteOffset(sn, 0); + if (pc + jmpoff < target) { + pc += jmpoff; + op = js_GetOpcode(cx, script, pc); + JS_ASSERT(op == JSOP_GOTO || op == JSOP_GOTOX); + cs = &js_CodeSpec[op]; + oplen = cs->length; + JS_ASSERT(oplen > 0); + ptrdiff_t jmplen = GetJumpOffset(pc, pc); + if (pc + jmplen < target) { + oplen = (uintN) jmplen; + continue; + } + + /* + * Ok, target lies in E. Manually pop C off the model stack, + * since we have moved beyond the IFEQ now. + */ + LOCAL_ASSERT(pcdepth != 0); + --pcdepth; + } + } + + /* Ignore early-exit code, which is annotated SRC_HIDDEN. */ + if (sn && SN_TYPE(sn) == SRC_HIDDEN) + continue; + + if (SimulateOp(cx, script, op, cs, pc, pcstack, pcdepth) < 0) + return -1; + + } + LOCAL_ASSERT(pc == target); + return pcdepth; + +#undef LOCAL_ASSERT +} + +#undef LOCAL_ASSERT_RV diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h new file mode 100644 index 0000000..68cf514 --- /dev/null +++ b/js/src/jsopcode.h @@ -0,0 +1,512 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsopcode_h___ +#define jsopcode_h___ +/* + * JS bytecode definitions. + */ +#include +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jsutil.h" + +#ifdef __cplusplus +# include "jsvalue.h" +#endif + +JS_BEGIN_EXTERN_C + +/* + * JS operation bytecodes. + */ +typedef enum JSOp { +#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + op = val, +#include "jsopcode.tbl" +#undef OPDEF + JSOP_LIMIT, + + /* + * These pseudo-ops help js_DecompileValueGenerator decompile JSOP_SETNAME, + * JSOP_SETPROP, and JSOP_SETELEM, respectively. They are never stored in + * bytecode, so they don't preempt valid opcodes. + */ + JSOP_GETPROP2 = JSOP_LIMIT, + JSOP_GETELEM2 = JSOP_LIMIT + 1, + JSOP_FAKE_LIMIT = JSOP_GETELEM2 +} JSOp; + +/* + * JS bytecode formats. + */ +#define JOF_BYTE 0 /* single bytecode, no immediates */ +#define JOF_JUMP 1 /* signed 16-bit jump offset immediate */ +#define JOF_ATOM 2 /* unsigned 16-bit constant index */ +#define JOF_UINT16 3 /* unsigned 16-bit immediate operand */ +#define JOF_TABLESWITCH 4 /* table switch */ +#define JOF_LOOKUPSWITCH 5 /* lookup switch */ +#define JOF_QARG 6 /* quickened get/set function argument ops */ +#define JOF_LOCAL 7 /* var or block-local variable */ +#define JOF_SLOTATOM 8 /* uint16 slot + constant index */ +#define JOF_JUMPX 9 /* signed 32-bit jump offset immediate */ +#define JOF_TABLESWITCHX 10 /* extended (32-bit offset) table switch */ +#define JOF_LOOKUPSWITCHX 11 /* extended (32-bit offset) lookup switch */ +#define JOF_UINT24 12 /* extended unsigned 24-bit literal (index) */ +#define JOF_UINT8 13 /* uint8 immediate, e.g. top 8 bits of 24-bit + atom index */ +#define JOF_INT32 14 /* int32 immediate operand */ +#define JOF_OBJECT 15 /* unsigned 16-bit object index */ +#define JOF_SLOTOBJECT 16 /* uint16 slot index + object index */ +#define JOF_REGEXP 17 /* unsigned 16-bit regexp index */ +#define JOF_INT8 18 /* int8 immediate operand */ +#define JOF_ATOMOBJECT 19 /* uint16 constant index + object index */ +#define JOF_UINT16PAIR 20 /* pair of uint16 immediates */ +#define JOF_GLOBAL 21 /* uint16 global array index */ +#define JOF_TYPEMASK 0x001f /* mask for above immediate types */ + +#define JOF_NAME (1U<<5) /* name operation */ +#define JOF_PROP (2U<<5) /* obj.prop operation */ +#define JOF_ELEM (3U<<5) /* obj[index] operation */ +#define JOF_XMLNAME (4U<<5) /* XML name: *, a::b, @a, @a::b, etc. */ +#define JOF_VARPROP (5U<<5) /* x.prop for this, arg, var, or local x */ +#define JOF_MODEMASK (7U<<5) /* mask for above addressing modes */ +#define JOF_SET (1U<<8) /* set (i.e., assignment) operation */ +#define JOF_DEL (1U<<9) /* delete operation */ +#define JOF_DEC (1U<<10) /* decrement (--, not ++) opcode */ +#define JOF_INC (2U<<10) /* increment (++, not --) opcode */ +#define JOF_INCDEC (3U<<10) /* increment or decrement opcode */ +#define JOF_POST (1U<<12) /* postorder increment or decrement */ +#define JOF_FOR (1U<<13) /* for-in property op (akin to JOF_SET) */ +#define JOF_ASSIGNING JOF_SET /* hint for Class.resolve, used for ops + that do simplex assignment */ +#define JOF_DETECTING (1U<<14) /* object detection for JSNewResolveOp */ +#define JOF_BACKPATCH (1U<<15) /* backpatch placeholder during codegen */ +#define JOF_LEFTASSOC (1U<<16) /* left-associative operator */ +#define JOF_DECLARING (1U<<17) /* var, const, or function declaration op */ +#define JOF_INDEXBASE (1U<<18) /* atom segment base setting prefix op */ +#define JOF_CALLOP (1U<<19) /* call operation that pushes function and + this */ +#define JOF_PARENHEAD (1U<<20) /* opcode consumes value of expression in + parenthesized statement head */ +#define JOF_INVOKE (1U<<21) /* JSOP_CALL, JSOP_NEW, JSOP_EVAL */ +#define JOF_TMPSLOT (1U<<22) /* interpreter uses extra temporary slot + to root intermediate objects besides + the slots opcode uses */ +#define JOF_TMPSLOT2 (2U<<22) /* interpreter uses extra 2 temporary slot + besides the slots opcode uses */ +#define JOF_TMPSLOT3 (3U<<22) /* interpreter uses extra 3 temporary slot + besides the slots opcode uses */ +#define JOF_TMPSLOT_SHIFT 22 +#define JOF_TMPSLOT_MASK (JS_BITMASK(2) << JOF_TMPSLOT_SHIFT) + +#define JOF_SHARPSLOT (1U<<24) /* first immediate is uint16 stack slot no. + that needs fixup when in global code (see + Compiler::compileScript) */ +#define JOF_GNAME (1U<<25) /* predicted global name */ + +/* Shorthands for type from format and type from opcode. */ +#define JOF_TYPE(fmt) ((fmt) & JOF_TYPEMASK) +#define JOF_OPTYPE(op) JOF_TYPE(js_CodeSpec[op].format) + +/* Shorthands for mode from format and mode from opcode. */ +#define JOF_MODE(fmt) ((fmt) & JOF_MODEMASK) +#define JOF_OPMODE(op) JOF_MODE(js_CodeSpec[op].format) + +#define JOF_TYPE_IS_EXTENDED_JUMP(t) \ + ((unsigned)((t) - JOF_JUMPX) <= (unsigned)(JOF_LOOKUPSWITCHX - JOF_JUMPX)) + +/* + * Immediate operand getters, setters, and bounds. + */ + +/* Common uint16 immediate format helpers. */ +#define UINT16_LEN 2 +#define UINT16_HI(i) ((jsbytecode)((i) >> 8)) +#define UINT16_LO(i) ((jsbytecode)(i)) +#define GET_UINT16(pc) ((uintN)(((pc)[1] << 8) | (pc)[2])) +#define SET_UINT16(pc,i) ((pc)[1] = UINT16_HI(i), (pc)[2] = UINT16_LO(i)) +#define UINT16_LIMIT ((uintN)1 << 16) + +/* Short (2-byte signed offset) relative jump macros. */ +#define JUMP_OFFSET_LEN 2 +#define JUMP_OFFSET_HI(off) ((jsbytecode)((off) >> 8)) +#define JUMP_OFFSET_LO(off) ((jsbytecode)(off)) +#define GET_JUMP_OFFSET(pc) ((int16)GET_UINT16(pc)) +#define SET_JUMP_OFFSET(pc,off) ((pc)[1] = JUMP_OFFSET_HI(off), \ + (pc)[2] = JUMP_OFFSET_LO(off)) +#define JUMP_OFFSET_MIN ((int16)0x8000) +#define JUMP_OFFSET_MAX ((int16)0x7fff) + +/* + * When a short jump won't hold a relative offset, its 2-byte immediate offset + * operand is an unsigned index of a span-dependency record, maintained until + * code generation finishes -- after which some (but we hope not nearly all) + * span-dependent jumps must be extended (see OptimizeSpanDeps in jsemit.c). + * + * If the span-dependency record index overflows SPANDEP_INDEX_MAX, the jump + * offset will contain SPANDEP_INDEX_HUGE, indicating that the record must be + * found (via binary search) by its "before span-dependency optimization" pc + * offset (from script main entry point). + */ +#define GET_SPANDEP_INDEX(pc) ((uint16)GET_UINT16(pc)) +#define SET_SPANDEP_INDEX(pc,i) ((pc)[1] = JUMP_OFFSET_HI(i), \ + (pc)[2] = JUMP_OFFSET_LO(i)) +#define SPANDEP_INDEX_MAX ((uint16)0xfffe) +#define SPANDEP_INDEX_HUGE ((uint16)0xffff) + +/* Ultimately, if short jumps won't do, emit long (4-byte signed) offsets. */ +#define JUMPX_OFFSET_LEN 4 +#define JUMPX_OFFSET_B3(off) ((jsbytecode)((off) >> 24)) +#define JUMPX_OFFSET_B2(off) ((jsbytecode)((off) >> 16)) +#define JUMPX_OFFSET_B1(off) ((jsbytecode)((off) >> 8)) +#define JUMPX_OFFSET_B0(off) ((jsbytecode)(off)) +#define GET_JUMPX_OFFSET(pc) ((int32)(((pc)[1] << 24) | ((pc)[2] << 16) \ + | ((pc)[3] << 8) | (pc)[4])) +#define SET_JUMPX_OFFSET(pc,off)((pc)[1] = JUMPX_OFFSET_B3(off), \ + (pc)[2] = JUMPX_OFFSET_B2(off), \ + (pc)[3] = JUMPX_OFFSET_B1(off), \ + (pc)[4] = JUMPX_OFFSET_B0(off)) +#define JUMPX_OFFSET_MIN ((int32)0x80000000) +#define JUMPX_OFFSET_MAX ((int32)0x7fffffff) + +/* + * A literal is indexed by a per-script atom or object maps. Most scripts + * have relatively few literals, so the standard JOF_ATOM, JOF_OBJECT and + * JOF_REGEXP formats specifies a fixed 16 bits of immediate operand index. + * A script with more than 64K literals must wrap the bytecode into + * JSOP_INDEXBASE and JSOP_RESETBASE pair. + */ +#define INDEX_LEN 2 +#define INDEX_HI(i) ((jsbytecode)((i) >> 8)) +#define INDEX_LO(i) ((jsbytecode)(i)) +#define GET_INDEX(pc) GET_UINT16(pc) +#define SET_INDEX(pc,i) ((pc)[1] = INDEX_HI(i), (pc)[2] = INDEX_LO(i)) + +#define GET_INDEXBASE(pc) (JS_ASSERT(*(pc) == JSOP_INDEXBASE), \ + ((uintN)((pc)[1])) << 16) +#define INDEXBASE_LEN 1 + +#define UINT24_HI(i) ((jsbytecode)((i) >> 16)) +#define UINT24_MID(i) ((jsbytecode)((i) >> 8)) +#define UINT24_LO(i) ((jsbytecode)(i)) +#define GET_UINT24(pc) ((jsatomid)(((pc)[1] << 16) | \ + ((pc)[2] << 8) | \ + (pc)[3])) +#define SET_UINT24(pc,i) ((pc)[1] = UINT24_HI(i), \ + (pc)[2] = UINT24_MID(i), \ + (pc)[3] = UINT24_LO(i)) + +#define GET_INT8(pc) ((jsint)(int8)(pc)[1]) + +#define GET_INT32(pc) ((jsint)(((uint32)((pc)[1]) << 24) | \ + ((uint32)((pc)[2]) << 16) | \ + ((uint32)((pc)[3]) << 8) | \ + (uint32)(pc)[4])) +#define SET_INT32(pc,i) ((pc)[1] = (jsbytecode)((uint32)(i) >> 24), \ + (pc)[2] = (jsbytecode)((uint32)(i) >> 16), \ + (pc)[3] = (jsbytecode)((uint32)(i) >> 8), \ + (pc)[4] = (jsbytecode)(uint32)(i)) + +/* Index limit is determined by SN_3BYTE_OFFSET_FLAG, see jsemit.h. */ +#define INDEX_LIMIT_LOG2 23 +#define INDEX_LIMIT ((uint32)1 << INDEX_LIMIT_LOG2) + +/* Actual argument count operand format helpers. */ +#define ARGC_HI(argc) UINT16_HI(argc) +#define ARGC_LO(argc) UINT16_LO(argc) +#define GET_ARGC(pc) GET_UINT16(pc) +#define ARGC_LIMIT UINT16_LIMIT + +/* Synonyms for quick JOF_QARG and JOF_LOCAL bytecodes. */ +#define GET_ARGNO(pc) GET_UINT16(pc) +#define SET_ARGNO(pc,argno) SET_UINT16(pc,argno) +#define ARGNO_LEN 2 +#define ARGNO_LIMIT UINT16_LIMIT + +#define GET_SLOTNO(pc) GET_UINT16(pc) +#define SET_SLOTNO(pc,varno) SET_UINT16(pc,varno) +#define SLOTNO_LEN 2 +#define SLOTNO_LIMIT UINT16_LIMIT + +struct JSCodeSpec { + int8 length; /* length including opcode byte */ + int8 nuses; /* arity, -1 if variadic */ + int8 ndefs; /* number of stack results */ + uint8 prec; /* operator precedence */ + uint32 format; /* immediate operand format */ + +#ifdef __cplusplus + uint32 type() const { return JOF_TYPE(format); } +#endif +}; + +extern const JSCodeSpec js_CodeSpec[]; +extern uintN js_NumCodeSpecs; +extern const char *js_CodeName[]; +extern const char js_EscapeMap[]; + +/* Silence unreferenced formal parameter warnings */ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4100) +#endif + +/* + * Return a GC'ed string containing the chars in str, with any non-printing + * chars or quotes (' or " as specified by the quote argument) escaped, and + * with the quote character at the beginning and end of the result string. + */ +extern JSString * +js_QuoteString(JSContext *cx, JSString *str, jschar quote); + +/* + * JSPrinter operations, for printf style message formatting. The return + * value from js_GetPrinterOutput() is the printer's cumulative output, in + * a GC'ed string. + * + * strict is true if the context in which the output will appear has + * already been marked as strict, thus indicating that nested + * functions need not be re-marked with a strict directive. It should + * be false in the outermost printer. + */ + +extern JSPrinter * +js_NewPrinter(JSContext *cx, const char *name, JSFunction *fun, + uintN indent, JSBool pretty, JSBool grouped, JSBool strict); + +extern void +js_DestroyPrinter(JSPrinter *jp); + +extern JSString * +js_GetPrinterOutput(JSPrinter *jp); + +extern int +js_printf(JSPrinter *jp, const char *format, ...); + +extern JSBool +js_puts(JSPrinter *jp, const char *s); + +/* + * Get index operand from the bytecode using a bytecode analysis to deduce the + * the index register. This function is infallible, in spite of taking cx as + * its first parameter; it uses only cx->runtime when calling JS_GetTrapOpcode. + * The GET_*_FROM_BYTECODE macros that call it pick up cx from their caller's + * lexical environments. + */ +uintN +js_GetIndexFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, + ptrdiff_t pcoff); + +/* + * A slower version of GET_ATOM when the caller does not want to maintain + * the index segment register itself. + */ +#define GET_ATOM_FROM_BYTECODE(script, pc, pcoff, atom) \ + JS_BEGIN_MACRO \ + JS_ASSERT(*(pc) != JSOP_DOUBLE); \ + uintN index_ = js_GetIndexFromBytecode(cx, (script), (pc), (pcoff)); \ + JS_GET_SCRIPT_ATOM(script, pc, index_, atom); \ + JS_END_MACRO + +/* + * Variant for getting a double atom when we might be in an imacro. Bytecodes + * with literals that are only ever doubles must use this macro, and never use + * GET_ATOM_FROM_BYTECODE or JS_GET_SCRIPT_ATOM. + * + * Unfortunately some bytecodes such as JSOP_LOOKUPSWITCH have immediates that + * might be string or double atoms. Those opcodes cannot be used from imacros. + * See the assertions in the JSOP_DOUBLE and JSOP_LOOKUPSWTICH* opcode cases in + * jsinterp.cpp. + */ +#define GET_DOUBLE_FROM_BYTECODE(script, pc, pcoff, dbl) \ + JS_BEGIN_MACRO \ + uintN index_ = js_GetIndexFromBytecode(cx, (script), (pc), (pcoff)); \ + JS_ASSERT(index_ < (script)->consts()->length); \ + (dbl) = (script)->getConst(index_).toDouble(); \ + JS_END_MACRO + +#define GET_OBJECT_FROM_BYTECODE(script, pc, pcoff, obj) \ + JS_BEGIN_MACRO \ + uintN index_ = js_GetIndexFromBytecode(cx, (script), (pc), (pcoff)); \ + obj = (script)->getObject(index_); \ + JS_END_MACRO + +#define GET_FUNCTION_FROM_BYTECODE(script, pc, pcoff, fun) \ + JS_BEGIN_MACRO \ + uintN index_ = js_GetIndexFromBytecode(cx, (script), (pc), (pcoff)); \ + fun = (script)->getFunction(index_); \ + JS_END_MACRO + +#define GET_REGEXP_FROM_BYTECODE(script, pc, pcoff, obj) \ + JS_BEGIN_MACRO \ + uintN index_ = js_GetIndexFromBytecode(cx, (script), (pc), (pcoff)); \ + obj = (script)->getRegExp(index_); \ + JS_END_MACRO + +/* + * Get the length of variable-length bytecode like JSOP_TABLESWITCH. + */ +extern uintN +js_GetVariableBytecodeLength(jsbytecode *pc); + +/* + * Find the number of stack slots used by a variadic opcode such as JSOP_CALL + * (for such ops, JSCodeSpec.nuses is -1). + */ +extern uintN +js_GetVariableStackUses(JSOp op, jsbytecode *pc); + +/* + * Find the number of stack slots defined by JSOP_ENTERBLOCK (for this op, + * JSCodeSpec.ndefs is -1). + */ +extern uintN +js_GetEnterBlockStackDefs(JSContext *cx, JSScript *script, jsbytecode *pc); + +#ifdef __cplusplus /* Aargh, libgjs, bug 492720. */ +static JS_INLINE uintN +js_GetStackUses(const JSCodeSpec *cs, JSOp op, jsbytecode *pc) +{ + JS_ASSERT(cs == &js_CodeSpec[op]); + if (cs->nuses >= 0) + return cs->nuses; + return js_GetVariableStackUses(op, pc); +} + +static JS_INLINE uintN +js_GetStackDefs(JSContext *cx, const JSCodeSpec *cs, JSOp op, JSScript *script, + jsbytecode *pc) +{ + JS_ASSERT(cs == &js_CodeSpec[op]); + if (cs->ndefs >= 0) + return cs->ndefs; + + /* Only JSOP_ENTERBLOCK has a variable number of stack defs. */ + JS_ASSERT(op == JSOP_ENTERBLOCK); + return js_GetEnterBlockStackDefs(cx, script, pc); +} +#endif + +#ifdef DEBUG +/* + * Disassemblers, for debugging only. + */ +#include + +extern JS_FRIEND_API(JSBool) +js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp); + +extern JS_FRIEND_API(uintN) +js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc, + JSBool lines, FILE *fp); +#endif /* DEBUG */ + +/* + * Decompilers, for script, function, and expression pretty-printing. + */ +extern JSBool +js_DecompileScript(JSPrinter *jp, JSScript *script); + +extern JSBool +js_DecompileFunctionBody(JSPrinter *jp); + +extern JSBool +js_DecompileFunction(JSPrinter *jp); + +/* + * Some C++ compilers treat the language linkage (extern "C" vs. + * extern "C++") as part of function (and thus pointer-to-function) + * types. The use of this typedef (defined in "C") ensures that + * js_DecompileToString's definition (in "C++") gets matched up with + * this declaration. + */ +typedef JSBool (* JSDecompilerPtr)(JSPrinter *); + +extern JSString * +js_DecompileToString(JSContext *cx, const char *name, JSFunction *fun, + uintN indent, JSBool pretty, JSBool grouped, JSBool strict, + JSDecompilerPtr decompiler); + +/* + * Find the source expression that resulted in v, and return a newly allocated + * C-string containing it. Fall back on v's string conversion (fallback) if we + * can't find the bytecode that generated and pushed v on the operand stack. + * + * Search the current stack frame if spindex is JSDVG_SEARCH_STACK. Don't + * look for v on the stack if spindex is JSDVG_IGNORE_STACK. Otherwise, + * spindex is the negative index of v, measured from cx->fp->sp, or from a + * lower frame's sp if cx->fp is native. + * + * The caller must call JS_free on the result after a succsesful call. + */ +extern char * +js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v, + JSString *fallback); + +#define JSDVG_IGNORE_STACK 0 +#define JSDVG_SEARCH_STACK 1 + +#ifdef __cplusplus +namespace js { + +static inline char * +DecompileValueGenerator(JSContext *cx, intN spindex, const Value &v, + JSString *fallback) +{ + return js_DecompileValueGenerator(cx, spindex, Jsvalify(v), fallback); +} + +} +#endif + +/* + * Given bytecode address pc in script's main program code, return the operand + * stack depth just before (JSOp) *pc executes. + */ +extern uintN +js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc); + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +JS_END_EXTERN_C + +#endif /* jsopcode_h___ */ diff --git a/js/src/jsopcode.tbl b/js/src/jsopcode.tbl new file mode 100644 index 0000000..02229e8 --- /dev/null +++ b/js/src/jsopcode.tbl @@ -0,0 +1,618 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=0 ft=c: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JavaScript operation bytecodes. If you need to allocate a bytecode, look + * for a name of the form JSOP_UNUSED* and claim it. Otherwise, always add at + * the end of the table. + * + * When changing the bytecode, don't forget to update JSXDR_BYTECODE_VERSION! + * + * Includers must define an OPDEF macro of the following form: + * + * #define OPDEF(op,val,name,image,length,nuses,ndefs,prec,format) ... + * + * Selected arguments can be expanded in initializers. The op argument is + * expanded followed by comma in the JSOp enum (jsopcode.h), e.g. The value + * field must be dense for now, because jsopcode.c uses an OPDEF() expansion + * inside the js_CodeSpec[] initializer. + * + * Field Description + * op Bytecode name, which is the JSOp enumerator name + * value Bytecode value, which is the JSOp enumerator value + * name C string containing name for disassembler + * image C string containing "image" for pretty-printer, null if ugly + * length Number of bytes including any immediate operands + * nuses Number of stack slots consumed by bytecode, -1 if variadic + * ndefs Number of stack slots produced by bytecode, -1 if variadic + * prec Operator precedence, zero if not an operator + * format Bytecode plus immediate operand encoding format + * + * Precedence Operators Opcodes + * 1 yield w JSOP_YIELD + * 2 , JSOP_POP with SRC_PCDELTA, JSOP_RETURN + * 3 =, +=, etc. JSOP_SETNAME, etc. (all JOF_SET); + * let (...) ... and JSOP_LEAVEBLOCKEXPR + * 4 ?: JSOP_IFEQ, JSOP_IFEQX + * 5 || JSOP_OR, JSOP_ORX + * 6 && JSOP_AND, JSOP_ANDX + * 7 | JSOP_BITOR + * 8 ^ JSOP_BITXOR + * 9 & JSOP_BITAND + * 10 ==, !=, etc. JSOP_EQ, JSOP_NE, etc. + * 11 <, in, etc. JSOP_LT, JSOP_IN, etc. + * 12 <<, >>, >>> JSOP_LSH, JSOP_RSH, JSOP_URSH + * 13 +, -, etc. JSOP_ADD, JSOP_SUB, etc. + * 14 *, /, % JSOP_MUL, JSOP_DIV, JSOP_MOD + * 15 !, ~, delete, etc. JSOP_NOT, JSOP_BITNOT, JSOP_DEL*, etc. + * 16 3.14, 0, etc. JSOP_DOUBLE, JSOP_ZERO, etc. + * 17 new JSOP_NEW + * 18 x.y, f(), etc. JSOP_GETPROP, JSOP_CALL, etc. + * 19 x, null, JSOP_NAME, JSOP_NULL, etc.; + * function (...) ... and JSOP_LAMBDA + * + * The push-numeric-constant operators, JSOP_ZERO, JSOP_DOUBLE, etc., have + * lower precedence than the member operators emitted for the . operator, to + * cause the decompiler to parenthesize the . left operand, e.g. (0).foo. + * Otherwise the . could be taken as a decimal point. + * + * Let expressions are "primary" when viewed from the left, but they eat up ops + * to the right as if assignment expressions and therefore have precedence 3. + * This makes the decompiler retain the parentheses in (let (a=0) x) ? a : 0 + * but omit the superfluous ones in (let (a=0) x), a. + * + * Yield expressions must be parenthesized even in comma-expressions and + * argument lists, so they have the lowest precedence. + * + * This file is best viewed with 128 columns: +12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 + */ + +/* legend: op val name image len use def prec format */ + +/* + * Generic nop for the decompiler. + */ +OPDEF(JSOP_NOP, 0, "nop", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* Long-standing JavaScript bytecodes. */ +OPDEF(JSOP_PUSH, 1, "push", NULL, 1, 0, 1, 0, JOF_BYTE) +OPDEF(JSOP_POPV, 2, "popv", NULL, 1, 1, 0, 2, JOF_BYTE) +OPDEF(JSOP_ENTERWITH, 3, "enterwith", NULL, 1, 1, 1, 0, JOF_BYTE|JOF_PARENHEAD) +OPDEF(JSOP_LEAVEWITH, 4, "leavewith", NULL, 1, 1, 0, 0, JOF_BYTE) +OPDEF(JSOP_RETURN, 5, "return", NULL, 1, 1, 0, 2, JOF_BYTE) +OPDEF(JSOP_GOTO, 6, "goto", NULL, 3, 0, 0, 0, JOF_JUMP) +OPDEF(JSOP_IFEQ, 7, "ifeq", NULL, 3, 1, 0, 4, JOF_JUMP|JOF_DETECTING) +OPDEF(JSOP_IFNE, 8, "ifne", NULL, 3, 1, 0, 0, JOF_JUMP|JOF_PARENHEAD) + +/* Get the arguments object for the current, lightweight function activation. */ +OPDEF(JSOP_ARGUMENTS, 9, js_arguments_str, js_arguments_str, 1, 0, 1, 18, JOF_BYTE) + +/* ECMA-compliant for-in loop with argument or local loop control. */ +OPDEF(JSOP_FORARG, 10, "forarg", NULL, 3, 1, 1, 19, JOF_QARG|JOF_NAME|JOF_FOR|JOF_TMPSLOT) +OPDEF(JSOP_FORLOCAL, 11, "forlocal", NULL, 3, 1, 1, 19, JOF_LOCAL|JOF_NAME|JOF_FOR|JOF_TMPSLOT) + +/* More long-standing bytecodes. */ +OPDEF(JSOP_DUP, 12, "dup", NULL, 1, 1, 2, 0, JOF_BYTE) +OPDEF(JSOP_DUP2, 13, "dup2", NULL, 1, 2, 4, 0, JOF_BYTE) +OPDEF(JSOP_SETCONST, 14, "setconst", NULL, 3, 1, 1, 3, JOF_ATOM|JOF_NAME|JOF_SET) +OPDEF(JSOP_BITOR, 15, "bitor", "|", 1, 2, 1, 7, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_BITXOR, 16, "bitxor", "^", 1, 2, 1, 8, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_BITAND, 17, "bitand", "&", 1, 2, 1, 9, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_EQ, 18, "eq", "==", 1, 2, 1, 10, JOF_BYTE|JOF_LEFTASSOC|JOF_DETECTING) +OPDEF(JSOP_NE, 19, "ne", "!=", 1, 2, 1, 10, JOF_BYTE|JOF_LEFTASSOC|JOF_DETECTING) +OPDEF(JSOP_LT, 20, "lt", "<", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_LE, 21, "le", "<=", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_GT, 22, "gt", ">", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_GE, 23, "ge", ">=", 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_LSH, 24, "lsh", "<<", 1, 2, 1, 12, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_RSH, 25, "rsh", ">>", 1, 2, 1, 12, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_URSH, 26, "ursh", ">>>", 1, 2, 1, 12, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_ADD, 27, "add", "+", 1, 2, 1, 13, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_SUB, 28, "sub", "-", 1, 2, 1, 13, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_MUL, 29, "mul", "*", 1, 2, 1, 14, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_DIV, 30, "div", "/", 1, 2, 1, 14, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_MOD, 31, "mod", "%", 1, 2, 1, 14, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_NOT, 32, "not", "!", 1, 1, 1, 15, JOF_BYTE|JOF_DETECTING) +OPDEF(JSOP_BITNOT, 33, "bitnot", "~", 1, 1, 1, 15, JOF_BYTE) +OPDEF(JSOP_NEG, 34, "neg", "- ", 1, 1, 1, 15, JOF_BYTE) +OPDEF(JSOP_POS, 35, "pos", "+ ", 1, 1, 1, 15, JOF_BYTE) +OPDEF(JSOP_DELNAME, 36, "delname", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEL) +OPDEF(JSOP_DELPROP, 37, "delprop", NULL, 3, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_DEL) +OPDEF(JSOP_DELELEM, 38, "delelem", NULL, 1, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_DEL) +OPDEF(JSOP_TYPEOF, 39, js_typeof_str,NULL, 1, 1, 1, 15, JOF_BYTE|JOF_DETECTING) +OPDEF(JSOP_VOID, 40, js_void_str, NULL, 1, 1, 1, 15, JOF_BYTE) + +OPDEF(JSOP_INCNAME, 41, "incname", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_TMPSLOT3) +OPDEF(JSOP_INCPROP, 42, "incprop", NULL, 3, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_INC|JOF_TMPSLOT3) +OPDEF(JSOP_INCELEM, 43, "incelem", NULL, 1, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_INC|JOF_TMPSLOT2) +OPDEF(JSOP_DECNAME, 44, "decname", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_TMPSLOT3) +OPDEF(JSOP_DECPROP, 45, "decprop", NULL, 3, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_DEC|JOF_TMPSLOT3) +OPDEF(JSOP_DECELEM, 46, "decelem", NULL, 1, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_DEC|JOF_TMPSLOT2) +OPDEF(JSOP_NAMEINC, 47, "nameinc", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3) +OPDEF(JSOP_PROPINC, 48, "propinc", NULL, 3, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_INC|JOF_POST|JOF_TMPSLOT3) +OPDEF(JSOP_ELEMINC, 49, "eleminc", NULL, 1, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_INC|JOF_POST|JOF_TMPSLOT2) +OPDEF(JSOP_NAMEDEC, 50, "namedec", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3) +OPDEF(JSOP_PROPDEC, 51, "propdec", NULL, 3, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_DEC|JOF_POST|JOF_TMPSLOT3) +OPDEF(JSOP_ELEMDEC, 52, "elemdec", NULL, 1, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_DEC|JOF_POST|JOF_TMPSLOT2) + +OPDEF(JSOP_GETPROP, 53, "getprop", NULL, 3, 1, 1, 18, JOF_ATOM|JOF_PROP) +OPDEF(JSOP_SETPROP, 54, "setprop", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_GETELEM, 55, "getelem", NULL, 1, 2, 1, 18, JOF_BYTE |JOF_ELEM|JOF_LEFTASSOC) +OPDEF(JSOP_SETELEM, 56, "setelem", NULL, 1, 3, 1, 3, JOF_BYTE |JOF_ELEM|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_CALLNAME, 57, "callname", NULL, 3, 0, 2, 19, JOF_ATOM|JOF_NAME|JOF_CALLOP) +OPDEF(JSOP_CALL, 58, "call", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE) +OPDEF(JSOP_NAME, 59, "name", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_NAME) +OPDEF(JSOP_DOUBLE, 60, "double", NULL, 3, 0, 1, 16, JOF_ATOM) +OPDEF(JSOP_STRING, 61, "string", NULL, 3, 0, 1, 19, JOF_ATOM) +OPDEF(JSOP_ZERO, 62, "zero", "0", 1, 0, 1, 16, JOF_BYTE) +OPDEF(JSOP_ONE, 63, "one", "1", 1, 0, 1, 16, JOF_BYTE) +OPDEF(JSOP_NULL, 64, js_null_str, js_null_str, 1, 0, 1, 19, JOF_BYTE) +OPDEF(JSOP_THIS, 65, js_this_str, js_this_str, 1, 0, 1, 19, JOF_BYTE) +OPDEF(JSOP_FALSE, 66, js_false_str, js_false_str, 1, 0, 1, 19, JOF_BYTE) +OPDEF(JSOP_TRUE, 67, js_true_str, js_true_str, 1, 0, 1, 19, JOF_BYTE) +OPDEF(JSOP_OR, 68, "or", NULL, 3, 1, 0, 5, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC) +OPDEF(JSOP_AND, 69, "and", NULL, 3, 1, 0, 6, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC) + +/* The switch bytecodes have variable length. */ +OPDEF(JSOP_TABLESWITCH, 70, "tableswitch", NULL, -1, 1, 0, 0, JOF_TABLESWITCH|JOF_DETECTING|JOF_PARENHEAD) +OPDEF(JSOP_LOOKUPSWITCH, 71, "lookupswitch", NULL, -1, 1, 0, 0, JOF_LOOKUPSWITCH|JOF_DETECTING|JOF_PARENHEAD) + +/* New, infallible/transitive identity ops. */ +OPDEF(JSOP_STRICTEQ, 72, "stricteq", "===", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC) +OPDEF(JSOP_STRICTNE, 73, "strictne", "!==", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC) + +/* + * Host object extension: given 'o.item(i) = j', the left-hand side compiles + * JSOP_SETCALL after JSOP_CALL, JSOP_EVAL, JSOP_FUNAPPLY, or JSOP_FUNCALL. + */ +OPDEF(JSOP_SETCALL, 74, "setcall", NULL, 1, 1, 2, 18, JOF_BYTE) + +/* + * JSOP_ITER sets up a for-in or for-each-in loop using the JSITER_* flag bits + * in this op's uint8 immediate operand. It replaces the top of stack value + * with an iterator for that value. + * + * JSOP_MOREITER stores the next iterated value into cx->iterValue and pushes + * true if another value is available, and false otherwise. It is followed + * immediately by JSOP_IFNE{,X}. + * + * JSOP_ENDITER cleans up after the loop. It uses the slot above the iterator + * for temporary GC rooting. + */ +OPDEF(JSOP_ITER, 75, "iter", NULL, 2, 1, 1, 0, JOF_UINT8) +OPDEF(JSOP_MOREITER, 76, "moreiter", NULL, 1, 1, 2, 0, JOF_BYTE) +OPDEF(JSOP_ENDITER, 77, "enditer", NULL, 1, 1, 0, 0, JOF_BYTE) + +OPDEF(JSOP_FUNAPPLY, 78, "funapply", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE) +OPDEF(JSOP_SWAP, 79, "swap", NULL, 1, 2, 2, 0, JOF_BYTE) + +/* Push object literal: either an XML object or initialiser object. */ +OPDEF(JSOP_OBJECT, 80, "object", NULL, 3, 0, 1, 19, JOF_OBJECT) + +/* Pop value and discard it. */ +OPDEF(JSOP_POP, 81, "pop", NULL, 1, 1, 0, 2, JOF_BYTE) + +/* Convert value to number, for unary +. */ +OPDEF(JSOP_NEW, 82, js_new_str, NULL, 3, -1, 1, 17, JOF_UINT16|JOF_INVOKE) + +/* Trap into debugger for breakpoint, etc. */ +OPDEF(JSOP_TRAP, 83, "trap", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* Fast get/set ops for function arguments and local variables. */ +OPDEF(JSOP_GETARG, 84, "getarg", NULL, 3, 0, 1, 19, JOF_QARG |JOF_NAME) +OPDEF(JSOP_SETARG, 85, "setarg", NULL, 3, 1, 1, 3, JOF_QARG |JOF_NAME|JOF_SET) +OPDEF(JSOP_GETLOCAL, 86,"getlocal", NULL, 3, 0, 1, 19, JOF_LOCAL|JOF_NAME) +OPDEF(JSOP_SETLOCAL, 87,"setlocal", NULL, 3, 1, 1, 3, JOF_LOCAL|JOF_NAME|JOF_SET|JOF_DETECTING) + +/* Push unsigned 16-bit int constant. */ +OPDEF(JSOP_UINT16, 88, "uint16", NULL, 3, 0, 1, 16, JOF_UINT16) + +/* + * Object and array literal support. NEWINIT takes the kind of initializer + * (JSProto_Array or JSProto_Object). NEWARRAY is an array initializer + * taking the final length, which can be filled in at the start and initialized + * directly. NEWOBJECT is an object initializer taking an object with the final + * shape, which can be set at the start and slots then filled in directly. + * NEWINIT has an extra byte so it can be exchanged with NEWOBJECT during emit. + */ +OPDEF(JSOP_NEWINIT, 89, "newinit", NULL, 3, 0, 1, 19, JOF_UINT8) +OPDEF(JSOP_NEWARRAY, 90, "newarray", NULL, 4, 0, 1, 19, JOF_UINT24) +OPDEF(JSOP_NEWOBJECT, 91, "newobject", NULL, 3, 0, 1, 19, JOF_OBJECT) +OPDEF(JSOP_ENDINIT, 92, "endinit", NULL, 1, 0, 0, 19, JOF_BYTE) +OPDEF(JSOP_INITPROP, 93, "initprop", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_INITELEM, 94, "initelem", NULL, 1, 3, 1, 3, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_DEFSHARP, 95, "defsharp", NULL, 5, 0, 0, 0, JOF_UINT16PAIR|JOF_SHARPSLOT) +OPDEF(JSOP_USESHARP, 96, "usesharp", NULL, 5, 0, 1, 0, JOF_UINT16PAIR|JOF_SHARPSLOT) + +/* Fast inc/dec ops for args and locals. */ +OPDEF(JSOP_INCARG, 97, "incarg", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_INC|JOF_TMPSLOT3) +OPDEF(JSOP_DECARG, 98, "decarg", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_DEC|JOF_TMPSLOT3) +OPDEF(JSOP_ARGINC, 99, "arginc", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3) +OPDEF(JSOP_ARGDEC, 100, "argdec", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3) + +OPDEF(JSOP_INCLOCAL, 101,"inclocal", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_INC|JOF_TMPSLOT3) +OPDEF(JSOP_DECLOCAL, 102,"declocal", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_DEC|JOF_TMPSLOT3) +OPDEF(JSOP_LOCALINC, 103,"localinc", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3) +OPDEF(JSOP_LOCALDEC, 104,"localdec", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3) + +OPDEF(JSOP_IMACOP, 105,"imacop", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* ECMA-compliant for/in ops. */ +OPDEF(JSOP_FORNAME, 106,"forname", NULL, 3, 1, 1, 19, JOF_ATOM|JOF_NAME|JOF_FOR|JOF_TMPSLOT3) +OPDEF(JSOP_FORPROP, 107,"forprop", NULL, 3, 2, 1, 18, JOF_ATOM|JOF_PROP|JOF_FOR|JOF_TMPSLOT3) +OPDEF(JSOP_FORELEM, 108,"forelem", NULL, 1, 1, 2, 18, JOF_BYTE |JOF_ELEM|JOF_FOR) +OPDEF(JSOP_POPN, 109,"popn", NULL, 3, -1, 0, 0, JOF_UINT16) + +/* ECMA-compliant assignment ops. */ +OPDEF(JSOP_BINDNAME, 110,"bindname", NULL, 3, 0, 1, 0, JOF_ATOM|JOF_NAME|JOF_SET) +OPDEF(JSOP_SETNAME, 111,"setname", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING) + +/* Exception handling ops. */ +OPDEF(JSOP_THROW, 112,js_throw_str, NULL, 1, 1, 0, 0, JOF_BYTE) + +/* 'in' and 'instanceof' ops. */ +OPDEF(JSOP_IN, 113,js_in_str, js_in_str, 1, 2, 1, 11, JOF_BYTE|JOF_LEFTASSOC) +OPDEF(JSOP_INSTANCEOF,114,js_instanceof_str,js_instanceof_str,1,2,1,11,JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT) + +/* debugger op */ +OPDEF(JSOP_DEBUGGER, 115,"debugger", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* gosub/retsub for finally handling */ +OPDEF(JSOP_GOSUB, 116,"gosub", NULL, 3, 0, 0, 0, JOF_JUMP) +OPDEF(JSOP_RETSUB, 117,"retsub", NULL, 1, 2, 0, 0, JOF_BYTE) + +/* More exception handling ops. */ +OPDEF(JSOP_EXCEPTION, 118,"exception", NULL, 1, 0, 1, 0, JOF_BYTE) + +/* Embedded lineno to speedup pc->line mapping. */ +OPDEF(JSOP_LINENO, 119,"lineno", NULL, 3, 0, 0, 0, JOF_UINT16) + +/* + * ECMA-compliant switch statement ops. + * CONDSWITCH is a decompilable NOP; CASE is ===, POP, jump if true, re-push + * lval if false; and DEFAULT is POP lval and GOTO. + */ +OPDEF(JSOP_CONDSWITCH,120,"condswitch", NULL, 1, 0, 0, 0, JOF_BYTE|JOF_PARENHEAD) +OPDEF(JSOP_CASE, 121,"case", NULL, 3, 2, 1, 0, JOF_JUMP) +OPDEF(JSOP_DEFAULT, 122,"default", NULL, 3, 1, 0, 0, JOF_JUMP) + +/* + * ECMA-compliant call to eval op + */ +OPDEF(JSOP_EVAL, 123,"eval", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE) + +/* + * ECMA-compliant helper for 'for (x[i] in o)' loops. + */ +OPDEF(JSOP_ENUMELEM, 124,"enumelem", NULL, 1, 3, 0, 3, JOF_BYTE |JOF_SET|JOF_TMPSLOT) + +/* + * Getter and setter prefix bytecodes. These modify the next bytecode, either + * an assignment or a property initializer code, which then defines a property + * getter or setter. + */ +OPDEF(JSOP_GETTER, 125,js_getter_str,NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_SETTER, 126,js_setter_str,NULL, 1, 0, 0, 0, JOF_BYTE) + +/* + * Prolog bytecodes for defining function, var, and const names. + */ +OPDEF(JSOP_DEFFUN, 127,"deffun", NULL, 3, 0, 0, 0, JOF_OBJECT|JOF_DECLARING) +OPDEF(JSOP_DEFCONST, 128,"defconst", NULL, 3, 0, 0, 0, JOF_ATOM|JOF_DECLARING) +OPDEF(JSOP_DEFVAR, 129,"defvar", NULL, 3, 0, 0, 0, JOF_ATOM|JOF_DECLARING) + +/* Push a closure for a named or anonymous function expression. */ +OPDEF(JSOP_LAMBDA, 130, "lambda", NULL, 3, 0, 1, 19, JOF_OBJECT) + +/* Used for named function expression self-naming, if lightweight. */ +OPDEF(JSOP_CALLEE, 131, "callee", NULL, 1, 0, 1, 19, JOF_BYTE) + +/* + * Like JSOP_SETLOCAL, but specialized to avoid requiring JSOP_POP immediately + * after to throw away the exception value. + */ +OPDEF(JSOP_SETLOCALPOP, 132, "setlocalpop", NULL, 3, 1, 0, 3, JOF_LOCAL|JOF_NAME|JOF_SET) + +/* Pick an element from the stack. */ +OPDEF(JSOP_PICK, 133, "pick", NULL, 2, 0, 0, 0, JOF_UINT8) + +/* + * Exception handling no-op, for more economical byte-coding than SRC_TRYFIN + * srcnote-annotated JSOP_NOPs and to simply stack balance handling. + */ +OPDEF(JSOP_TRY, 134,"try", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_FINALLY, 135,"finally", NULL, 1, 0, 2, 0, JOF_BYTE) + +/* + * Get a slot from a flat closure function object that contains a snapshot of + * the closure-invariant upvar values. The immediate operand indexes the upvar + * in the function's u.i.script->upvars() array. The CALL variant computes the + * callee and this-object in preparation for a JSOP_CALL. + */ +OPDEF(JSOP_GETFCSLOT, 136,"getfcslot", NULL, 3, 0, 1, 19, JOF_UINT16|JOF_NAME) +OPDEF(JSOP_CALLFCSLOT, 137,"callfcslot", NULL, 3, 0, 2, 19, JOF_UINT16|JOF_NAME|JOF_CALLOP) + +/* + * Bytecodes that avoid making an arguments object in most cases: + * JSOP_ARGSUB gets arguments[i] from fp->argv, iff i is in [0, fp->argc-1]. + * JSOP_ARGCNT returns fp->argc. + */ +OPDEF(JSOP_ARGSUB, 138,"argsub", NULL, 3, 0, 1, 18, JOF_QARG |JOF_NAME) +OPDEF(JSOP_ARGCNT, 139,"argcnt", NULL, 1, 0, 1, 18, JOF_BYTE) + +/* + * Define a local function object as a local variable. + * The local variable's slot number is the first immediate two-byte operand. + * The function object's atom index is the second immediate operand. + */ +OPDEF(JSOP_DEFLOCALFUN, 140,"deflocalfun",NULL, 5, 0, 0, 0, JOF_SLOTOBJECT|JOF_DECLARING|JOF_TMPSLOT) + +/* Extended jumps. */ +OPDEF(JSOP_GOTOX, 141,"gotox", NULL, 5, 0, 0, 0, JOF_JUMPX) +OPDEF(JSOP_IFEQX, 142,"ifeqx", NULL, 5, 1, 0, 4, JOF_JUMPX|JOF_DETECTING) +OPDEF(JSOP_IFNEX, 143,"ifnex", NULL, 5, 1, 0, 0, JOF_JUMPX|JOF_PARENHEAD) +OPDEF(JSOP_ORX, 144,"orx", NULL, 5, 1, 0, 5, JOF_JUMPX|JOF_DETECTING) +OPDEF(JSOP_ANDX, 145,"andx", NULL, 5, 1, 0, 6, JOF_JUMPX|JOF_DETECTING) +OPDEF(JSOP_GOSUBX, 146,"gosubx", NULL, 5, 0, 0, 0, JOF_JUMPX) +OPDEF(JSOP_CASEX, 147,"casex", NULL, 5, 2, 1, 0, JOF_JUMPX) +OPDEF(JSOP_DEFAULTX, 148,"defaultx", NULL, 5, 1, 0, 0, JOF_JUMPX) +OPDEF(JSOP_TABLESWITCHX, 149,"tableswitchx",NULL, -1, 1, 0, 0, JOF_TABLESWITCHX|JOF_DETECTING|JOF_PARENHEAD) +OPDEF(JSOP_LOOKUPSWITCHX, 150,"lookupswitchx",NULL, -1, 1, 0, 0, JOF_LOOKUPSWITCHX|JOF_DETECTING|JOF_PARENHEAD) + +/* Placeholders for a real jump opcode set during backpatch chain fixup. */ +OPDEF(JSOP_BACKPATCH, 151,"backpatch",NULL, 3, 0, 0, 0, JOF_JUMP|JOF_BACKPATCH) +OPDEF(JSOP_BACKPATCH_POP, 152,"backpatch_pop",NULL, 3, 1, 0, 0, JOF_JUMP|JOF_BACKPATCH) + +/* Set pending exception from the stack, to trigger rethrow. */ +OPDEF(JSOP_THROWING, 153,"throwing", NULL, 1, 1, 0, 0, JOF_BYTE) + +/* Set and get return value pseudo-register in stack frame. */ +OPDEF(JSOP_SETRVAL, 154,"setrval", NULL, 1, 1, 0, 2, JOF_BYTE) +OPDEF(JSOP_RETRVAL, 155,"retrval", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* Free variable references that must either be found on the global or a ReferenceError */ +OPDEF(JSOP_GETGNAME, 156,"getgname", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_GNAME) +OPDEF(JSOP_SETGNAME, 157,"setgname", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_GNAME) +OPDEF(JSOP_INCGNAME, 158,"incgname", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_GNAME) +OPDEF(JSOP_DECGNAME, 159,"decgname", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_GNAME) +OPDEF(JSOP_GNAMEINC, 160,"gnameinc", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_GNAME) +OPDEF(JSOP_GNAMEDEC, 161,"gnamedec", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_GNAME) + +/* Regular expression literal requiring special "fork on exec" handling. */ +OPDEF(JSOP_REGEXP, 162,"regexp", NULL, 3, 0, 1, 19, JOF_REGEXP) + +/* XML (ECMA-357, a.k.a. "E4X") support. */ +OPDEF(JSOP_DEFXMLNS, 163,"defxmlns", NULL, 1, 1, 0, 0, JOF_BYTE) +OPDEF(JSOP_ANYNAME, 164,"anyname", NULL, 1, 0, 1, 19, JOF_BYTE|JOF_XMLNAME) +OPDEF(JSOP_QNAMEPART, 165,"qnamepart", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_XMLNAME) +OPDEF(JSOP_QNAMECONST, 166,"qnameconst", NULL, 3, 1, 1, 19, JOF_ATOM|JOF_XMLNAME) +OPDEF(JSOP_QNAME, 167,"qname", NULL, 1, 2, 1, 0, JOF_BYTE|JOF_XMLNAME) +OPDEF(JSOP_TOATTRNAME, 168,"toattrname", NULL, 1, 1, 1, 19, JOF_BYTE|JOF_XMLNAME) +OPDEF(JSOP_TOATTRVAL, 169,"toattrval", NULL, 1, 1, 1, 19, JOF_BYTE) +OPDEF(JSOP_ADDATTRNAME, 170,"addattrname",NULL, 1, 2, 1, 13, JOF_BYTE) +OPDEF(JSOP_ADDATTRVAL, 171,"addattrval", NULL, 1, 2, 1, 13, JOF_BYTE) +OPDEF(JSOP_BINDXMLNAME, 172,"bindxmlname",NULL, 1, 1, 2, 3, JOF_BYTE|JOF_SET) +OPDEF(JSOP_SETXMLNAME, 173,"setxmlname", NULL, 1, 3, 1, 3, JOF_BYTE|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_XMLNAME, 174,"xmlname", NULL, 1, 1, 1, 19, JOF_BYTE) +OPDEF(JSOP_DESCENDANTS, 175,"descendants",NULL, 1, 2, 1, 18, JOF_BYTE) +OPDEF(JSOP_FILTER, 176,"filter", NULL, 3, 1, 1, 0, JOF_JUMP) +OPDEF(JSOP_ENDFILTER, 177,"endfilter", NULL, 3, 2, 1, 18, JOF_JUMP) +OPDEF(JSOP_TOXML, 178,"toxml", NULL, 1, 1, 1, 19, JOF_BYTE) +OPDEF(JSOP_TOXMLLIST, 179,"toxmllist", NULL, 1, 1, 1, 19, JOF_BYTE) +OPDEF(JSOP_XMLTAGEXPR, 180,"xmltagexpr", NULL, 1, 1, 1, 0, JOF_BYTE) +OPDEF(JSOP_XMLELTEXPR, 181,"xmleltexpr", NULL, 1, 1, 1, 0, JOF_BYTE) +OPDEF(JSOP_NOTRACE, 182,"notrace", NULL, 3, 0, 0, 0, JOF_UINT16) +OPDEF(JSOP_XMLCDATA, 183,"xmlcdata", NULL, 3, 0, 1, 19, JOF_ATOM) +OPDEF(JSOP_XMLCOMMENT, 184,"xmlcomment", NULL, 3, 0, 1, 19, JOF_ATOM) +OPDEF(JSOP_XMLPI, 185,"xmlpi", NULL, 3, 1, 1, 19, JOF_ATOM) +OPDEF(JSOP_DELDESC, 186,"deldesc", NULL, 1, 2, 1, 15, JOF_BYTE|JOF_ELEM|JOF_DEL) + +OPDEF(JSOP_CALLPROP, 187,"callprop", NULL, 3, 1, 2, 18, JOF_ATOM|JOF_PROP|JOF_CALLOP|JOF_TMPSLOT3) + +/* + * These opcodes contain a reference to the current blockChain object. + * They are emitted directly after instructions, such as DEFFUN, that need fast access to + * the blockChain. The special NULLBLOCKCHAIN is needed because the JOF_OBJECT + * does not permit NULL object references, since it stores an index into a table of + * objects. + */ +OPDEF(JSOP_BLOCKCHAIN, 188,"blockchain", NULL, 3, 0, 0, 0, JOF_OBJECT) +OPDEF(JSOP_NULLBLOCKCHAIN,189,"nullblockchain",NULL, 1, 0, 0, 0, JOF_BYTE) + +/* + * Opcode to hold 24-bit immediate integer operands. + */ +OPDEF(JSOP_UINT24, 190,"uint24", NULL, 4, 0, 1, 16, JOF_UINT24) + +/* + * Opcodes to allow 24-bit atom or object indexes. Whenever an index exceeds + * the 16-bit limit, the index-accessing bytecode must be bracketed by + * JSOP_INDEXBASE and JSOP_RESETBASE to provide the upper bits of the index. + * See jsemit.c, EmitIndexOp. + */ +OPDEF(JSOP_INDEXBASE, 191,"indexbase", NULL, 2, 0, 0, 0, JOF_UINT8|JOF_INDEXBASE) +OPDEF(JSOP_RESETBASE, 192,"resetbase", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_RESETBASE0, 193,"resetbase0", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* + * Opcodes to help the decompiler deal with XML. + */ +OPDEF(JSOP_STARTXML, 194,"startxml", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_STARTXMLEXPR, 195,"startxmlexpr",NULL, 1, 0, 0, 0, JOF_BYTE) + +OPDEF(JSOP_CALLELEM, 196, "callelem", NULL, 1, 2, 2, 18, JOF_BYTE |JOF_ELEM|JOF_LEFTASSOC|JOF_CALLOP) + +/* + * Stop interpretation, emitted at end of script to save the threaded bytecode + * interpreter an extra branch test on every DO_NEXT_OP (see jsinterp.c). + */ +OPDEF(JSOP_STOP, 197,"stop", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* + * Get an extant property value, throwing ReferenceError if the identified + * property does not exist. + */ +OPDEF(JSOP_GETXPROP, 198,"getxprop", NULL, 3, 1, 1, 18, JOF_ATOM|JOF_PROP) + +OPDEF(JSOP_CALLXMLNAME, 199, "callxmlname", NULL, 1, 1, 2, 19, JOF_BYTE|JOF_CALLOP) + +/* + * Specialized JSOP_TYPEOF to avoid reporting undefined for typeof(0, undef). + */ +OPDEF(JSOP_TYPEOFEXPR, 200,"typeofexpr", NULL, 1, 1, 1, 15, JOF_BYTE|JOF_DETECTING) + +/* + * Block-local scope support. + */ +OPDEF(JSOP_ENTERBLOCK, 201,"enterblock", NULL, 3, 0, -1, 0, JOF_OBJECT) +OPDEF(JSOP_LEAVEBLOCK, 202,"leaveblock", NULL, 5, -1, 0, 0, JOF_UINT16) + +/* Jump to target if top of stack value is of primitive type. */ +OPDEF(JSOP_IFPRIMTOP, 203,"ifprimtop", NULL, 3, 1, 1, 0, JOF_JUMP|JOF_DETECTING) + +/* Throws a TypeError if the value at the top of the stack is not primitive. */ +OPDEF(JSOP_PRIMTOP, 204,"primtop", NULL, 2, 1, 1, 0, JOF_INT8) + +/* + * Generator and array comprehension support. + */ +OPDEF(JSOP_GENERATOR, 205,"generator", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_YIELD, 206,"yield", NULL, 1, 1, 1, 1, JOF_BYTE) +OPDEF(JSOP_ARRAYPUSH, 207,"arraypush", NULL, 3, 1, 0, 3, JOF_LOCAL) + +/* + * Get the built-in function::foo namespace and push it. + */ +OPDEF(JSOP_GETFUNNS, 208,"getfunns", NULL, 1, 0, 1, 19, JOF_BYTE) + +/* + * Variant of JSOP_ENUMELEM for destructuring const (const [a, b] = ...). + */ +OPDEF(JSOP_ENUMCONSTELEM, 209,"enumconstelem",NULL, 1, 3, 0, 3, JOF_BYTE|JOF_SET) + +/* + * Variant of JSOP_LEAVEBLOCK has a result on the stack above the locals, + * which must be moved down when the block pops. + */ +OPDEF(JSOP_LEAVEBLOCKEXPR,210,"leaveblockexpr",NULL, 5, -1, 1, 3, JOF_UINT16) + +/* + * Optimize common JSOP_{THIS,GET{ARG,LOCAL}} -> JSOP_GETPROP cliches. + */ +OPDEF(JSOP_GETTHISPROP, 211,"getthisprop", NULL, 3, 0, 1, 18, JOF_ATOM|JOF_VARPROP) +OPDEF(JSOP_GETARGPROP, 212,"getargprop", NULL, 5, 0, 1, 18, JOF_SLOTATOM|JOF_VARPROP) +OPDEF(JSOP_GETLOCALPROP, 213,"getlocalprop", NULL, 5, 0, 1, 18, JOF_SLOTATOM|JOF_VARPROP) + +/* + * Optimize atom segments 1-3. These must be followed by JSOP_RESETBASE0 after + * the opcode that they prefix. + */ +OPDEF(JSOP_INDEXBASE1, 214,"indexbase1", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE) +OPDEF(JSOP_INDEXBASE2, 215,"indexbase2", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE) +OPDEF(JSOP_INDEXBASE3, 216,"indexbase3", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE) + +OPDEF(JSOP_CALLGNAME, 217, "callgname", NULL, 3, 0, 2, 19, JOF_ATOM|JOF_NAME|JOF_CALLOP|JOF_GNAME) +OPDEF(JSOP_CALLLOCAL, 218, "calllocal", NULL, 3, 0, 2, 19, JOF_LOCAL|JOF_NAME|JOF_CALLOP) +OPDEF(JSOP_CALLARG, 219, "callarg", NULL, 3, 0, 2, 19, JOF_QARG |JOF_NAME|JOF_CALLOP) +OPDEF(JSOP_BINDGNAME, 220, "bindgname", NULL, 3, 0, 1, 0, JOF_ATOM|JOF_NAME|JOF_SET|JOF_GNAME) + +/* + * Opcodes to hold 8-bit and 32-bit immediate integer operands. + */ +OPDEF(JSOP_INT8, 221, "int8", NULL, 2, 0, 1, 16, JOF_INT8) +OPDEF(JSOP_INT32, 222, "int32", NULL, 5, 0, 1, 16, JOF_INT32) + +/* + * Get the value of the 'length' property from a stacked object. + */ +OPDEF(JSOP_LENGTH, 223, "length", NULL, 1, 1, 1, 18, JOF_BYTE|JOF_PROP) + +/* + * Push a JSVAL_HOLE value onto the stack, representing an omitted property in + * an array literal (e.g. property 0 in the array [, 1]). This opcode is used + * with the JSOP_NEWARRAY opcode. + */ +OPDEF(JSOP_HOLE, 224, "hole", NULL, 1, 0, 1, 0, JOF_BYTE) + +/* + * Variants of JSOP_{DEF{,LOCAL}FUN,LAMBDA} optimized for the flat closure case. + */ +OPDEF(JSOP_DEFFUN_FC, 225,"deffun_fc", NULL, 3, 0, 0, 0, JOF_OBJECT|JOF_DECLARING) +OPDEF(JSOP_DEFLOCALFUN_FC,226,"deflocalfun_fc",NULL, 5, 0, 0, 0, JOF_SLOTOBJECT|JOF_DECLARING|JOF_TMPSLOT) +OPDEF(JSOP_LAMBDA_FC, 227,"lambda_fc", NULL, 3, 0, 1, 19, JOF_OBJECT) + +/* + * Ensure that the value on the top of the stack is an object. The one + * argument is an error message, defined in js.msg, that takes one parameter + * (the decompilation of the primitive value). + */ +OPDEF(JSOP_OBJTOP, 228,"objtop", NULL, 3, 0, 0, 0, JOF_UINT16) + +/* This opcode stores an index that is unique to the given loop. */ +OPDEF(JSOP_TRACE, 229, "trace", NULL, 3, 0, 0, 0, JOF_UINT16) + +/* + * Debugger versions of the flat closure (_FC) ops. + */ +OPDEF(JSOP_GETUPVAR_DBG, 230,"getupvar_dbg", NULL, 3, 0, 1, 19, JOF_UINT16|JOF_NAME) +OPDEF(JSOP_CALLUPVAR_DBG, 231,"callupvar_dbg", NULL, 3, 0, 2, 19, JOF_UINT16|JOF_NAME|JOF_CALLOP) +OPDEF(JSOP_DEFFUN_DBGFC, 232,"deffun_dbgfc", NULL, 3, 0, 0, 0, JOF_OBJECT|JOF_DECLARING) +OPDEF(JSOP_DEFLOCALFUN_DBGFC,233,"deflocalfun_dbgfc",NULL, 5, 0, 0, 0, JOF_SLOTOBJECT|JOF_DECLARING|JOF_TMPSLOT) +OPDEF(JSOP_LAMBDA_DBGFC, 234,"lambda_dbgfc", NULL, 3, 0, 1, 19, JOF_OBJECT) + +/* + * Joined function object as method optimization support. + */ +OPDEF(JSOP_SETMETHOD, 235,"setmethod", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_INITMETHOD, 236,"initmethod", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_UNBRAND, 237,"unbrand", NULL, 1, 1, 1, 0, JOF_BYTE) +OPDEF(JSOP_UNBRANDTHIS, 238,"unbrandthis", NULL, 1, 0, 0, 0, JOF_BYTE) + +OPDEF(JSOP_SHARPINIT, 239,"sharpinit", NULL, 3, 0, 0, 0, JOF_UINT16|JOF_SHARPSLOT) + +/* Static binding for globals. */ +OPDEF(JSOP_GETGLOBAL, 240,"getglobal", NULL, 3, 0, 1, 19, JOF_GLOBAL|JOF_NAME) +OPDEF(JSOP_CALLGLOBAL, 241,"callglobal", NULL, 3, 0, 2, 19, JOF_GLOBAL|JOF_NAME|JOF_CALLOP) + +/* Like JSOP_FUNAPPLY but for f.call instead of f.apply. */ +OPDEF(JSOP_FUNCALL, 242,"funcall", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE) + +OPDEF(JSOP_FORGNAME, 243,"forgname", NULL, 3, 1, 1, 19, JOF_ATOM|JOF_GNAME|JOF_FOR|JOF_TMPSLOT3) diff --git a/js/src/jsopcodeinlines.h b/js/src/jsopcodeinlines.h new file mode 100644 index 0000000..0eb05d5 --- /dev/null +++ b/js/src/jsopcodeinlines.h @@ -0,0 +1,57 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Mozilla SpiderMonkey JaegerMonkey implementation + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2002-2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsautooplen.h" + +namespace js { + +/* + * Warning: this does not skip JSOP_RESETBASE* or JSOP_INDEXBASE* ops, so it is + * useful only when checking for optimization opportunities. + */ +JS_ALWAYS_INLINE jsbytecode * +AdvanceOverBlockchainOp(jsbytecode *pc) +{ + if (*pc == JSOP_NULLBLOCKCHAIN) + return pc + JSOP_NULLBLOCKCHAIN_LENGTH; + if (*pc == JSOP_BLOCKCHAIN) + return pc + JSOP_BLOCKCHAIN_LENGTH; + return pc; +} + +} diff --git a/js/src/jsoplengen.cpp b/js/src/jsoplengen.cpp new file mode 100644 index 0000000..683ea24 --- /dev/null +++ b/js/src/jsoplengen.cpp @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=8 et tw=80: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is String Switch Generator for JavaScript Keywords, + * released 2005-12-09. + * + * The Initial Developer of the Original Code is + * Igor Bukanov. + * Portions created by the Initial Developer are Copyright (C) 2005-2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include + +static const struct { + const char *name; + int length; +} pairs[] = { +#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + { #op, length } , +#include "jsopcode.tbl" +#undef OPDEF +}; + +int +main(int argc, char **argv) +{ + FILE *fp; + size_t maxNameWidth, i, nameWidth, tabStop; + int lengthGap; + + static const char prefix[] = "#define "; + static const char suffix[] = "_LENGTH"; + static const size_t tabWidth = 8; + static const size_t prefixWidth = sizeof(prefix) - 1; + static const size_t suffixWidth = sizeof(suffix) - 1; + + if (argc != 2) { + fputs("Bad usage\n", stderr); + return EXIT_FAILURE; + } + + fp = fopen(argv[1], "w"); + if (!fp) { + perror("fopen"); + return EXIT_FAILURE; + } + fputs("/*\n" + " * Automatically generated header with JS opcode length constants.\n" + " *\n" + " * Do not edit it, alter jsopcode.tbl instead.\n" + " */\n", + fp); + + /* + * Print + * + * #define name_LENGTH length + * + * with all length values aligned on the same column. The column is at the + * second character position after a tab-stop with the first position + * reserved for the minus sign of variable-length opcodes. + */ + maxNameWidth = 0; + for (i = 0; i != sizeof pairs / sizeof pairs[0]; ++i) { + nameWidth = strlen(pairs[i].name); + if (maxNameWidth < nameWidth) + maxNameWidth = nameWidth; + } + + tabStop = prefixWidth + maxNameWidth + suffixWidth + 1; + tabStop = (tabStop + tabWidth - 1) / tabWidth * tabWidth; + for (i = 0; i != sizeof pairs / sizeof pairs[0]; ++i) { + lengthGap = (int) (tabStop - prefixWidth - strlen(pairs[i].name) - + suffixWidth); + fprintf(fp, "%s%s%s%*c%2d\n", + prefix, pairs[i].name, suffix, lengthGap, ' ', + pairs[i].length); + if (ferror(fp)) { + perror("fclose"); + exit(EXIT_FAILURE); + } + } + + if (fclose(fp)) { + perror("fclose"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/js/src/jsotypes.h b/js/src/jsotypes.h new file mode 100644 index 0000000..bfc85cc --- /dev/null +++ b/js/src/jsotypes.h @@ -0,0 +1,198 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This section typedefs the old 'native' types to the new PRs. + * These definitions are scheduled to be eliminated at the earliest + * possible time. The NSPR API is implemented and documented using + * the new definitions. + */ + +/* + * Note that we test for PROTYPES_H, not JSOTYPES_H. This is to avoid + * double-definitions of scalar types such as uint32, if NSPR's + * protypes.h is also included. + */ +#ifndef PROTYPES_H +#define PROTYPES_H + +#ifdef XP_BEOS +/* BeOS defines most int types in SupportDefs.h (int8, uint8, int16, + * uint16, int32, uint32, int64, uint64), so in the interest of + * not conflicting with other definitions elsewhere we have to skip the + * #ifdef jungle below, duplicate some definitions, and do our stuff. + */ +#include + +typedef JSUintn uintn; +#ifndef _XP_Core_ +typedef JSIntn intn; +#endif + +#else + +/* SVR4 typedef of uint is commonly found on UNIX machines. */ +#ifdef XP_UNIX +#include +#else +typedef JSUintn uint; +#endif + +typedef JSUintn uintn; +typedef JSUint64 uint64; +typedef JSUint32 uint32; +typedef JSUint16 uint16; +typedef JSUint8 uint8; + +#ifndef _XP_Core_ +typedef JSIntn intn; +#endif + +/* + * On AIX 4.3, sys/inttypes.h (which is included by sys/types.h, a very + * common header file) defines the types int8, int16, int32, and int64. + * So we don't define these four types here to avoid conflicts in case + * the code also includes sys/types.h. + */ +#if defined(AIX) && defined(HAVE_SYS_INTTYPES_H) +#include +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +typedef JSInt64 int64; + +/* Explicit signed keyword for bitfield types is required. */ +/* Some compilers may treat them as unsigned without it. */ +typedef signed int int32; +typedef signed short int16; +typedef signed char int8; +#else +typedef JSInt64 int64; + +/* /usr/include/model.h on HP-UX defines int8, int16, and int32 */ +typedef JSInt32 int32; +typedef JSInt16 int16; +typedef JSInt8 int8; +#endif /* AIX && HAVE_SYS_INTTYPES_H */ + +#endif /* XP_BEOS */ + +typedef JSFloat64 float64; + +/* Re: jsbit.h */ +#define TEST_BIT JS_TEST_BIT +#define SET_BIT JS_SET_BIT +#define CLEAR_BIT JS_CLEAR_BIT + +/* Re: prarena.h->plarena.h */ +#define PRArena PLArena +#define PRArenaPool PLArenaPool +#define PRArenaStats PLArenaStats +#define PR_ARENA_ALIGN PL_ARENA_ALIGN +#define PR_INIT_ARENA_POOL PL_INIT_ARENA_POOL +#define PR_ARENA_ALLOCATE PL_ARENA_ALLOCATE +#define PR_ARENA_GROW PL_ARENA_GROW +#define PR_ARENA_MARK PL_ARENA_MARK +#define PR_CLEAR_UNUSED PL_CLEAR_UNUSED +#define PR_CLEAR_ARENA PL_CLEAR_ARENA +#define PR_ARENA_RELEASE PL_ARENA_RELEASE +#define PR_COUNT_ARENA PL_COUNT_ARENA +#define PR_ARENA_DESTROY PL_ARENA_DESTROY +#define PR_InitArenaPool PL_InitArenaPool +#define PR_FreeArenaPool PL_FreeArenaPool +#define PR_FinishArenaPool PL_FinishArenaPool +#define PR_CompactArenaPool PL_CompactArenaPool +#define PR_ArenaFinish PL_ArenaFinish +#define PR_ArenaAllocate PL_ArenaAllocate +#define PR_ArenaGrow PL_ArenaGrow +#define PR_ArenaRelease PL_ArenaRelease +#define PR_ArenaCountAllocation PL_ArenaCountAllocation +#define PR_ArenaCountInplaceGrowth PL_ArenaCountInplaceGrowth +#define PR_ArenaCountGrowth PL_ArenaCountGrowth +#define PR_ArenaCountRelease PL_ArenaCountRelease +#define PR_ArenaCountRetract PL_ArenaCountRetract + +/* Re: prevent.h->plevent.h */ +#define PREvent PLEvent +#define PREventQueue PLEventQueue +#define PR_CreateEventQueue PL_CreateEventQueue +#define PR_DestroyEventQueue PL_DestroyEventQueue +#define PR_GetEventQueueMonitor PL_GetEventQueueMonitor +#define PR_ENTER_EVENT_QUEUE_MONITOR PL_ENTER_EVENT_QUEUE_MONITOR +#define PR_EXIT_EVENT_QUEUE_MONITOR PL_EXIT_EVENT_QUEUE_MONITOR +#define PR_PostEvent PL_PostEvent +#define PR_PostSynchronousEvent PL_PostSynchronousEvent +#define PR_GetEvent PL_GetEvent +#define PR_EventAvailable PL_EventAvailable +#define PREventFunProc PLEventFunProc +#define PR_MapEvents PL_MapEvents +#define PR_RevokeEvents PL_RevokeEvents +#define PR_ProcessPendingEvents PL_ProcessPendingEvents +#define PR_WaitForEvent PL_WaitForEvent +#define PR_EventLoop PL_EventLoop +#define PR_GetEventQueueSelectFD PL_GetEventQueueSelectFD +#define PRHandleEventProc PLHandleEventProc +#define PRDestroyEventProc PLDestroyEventProc +#define PR_InitEvent PL_InitEvent +#define PR_GetEventOwner PL_GetEventOwner +#define PR_HandleEvent PL_HandleEvent +#define PR_DestroyEvent PL_DestroyEvent +#define PR_DequeueEvent PL_DequeueEvent +#define PR_GetMainEventQueue PL_GetMainEventQueue + +/* Re: prhash.h->plhash.h */ +#define PRHashEntry PLHashEntry +#define PRHashTable PLHashTable +#define PRHashNumber PLHashNumber +#define PRHashFunction PLHashFunction +#define PRHashComparator PLHashComparator +#define PRHashEnumerator PLHashEnumerator +#define PRHashAllocOps PLHashAllocOps +#define PR_NewHashTable PL_NewHashTable +#define PR_HashTableDestroy PL_HashTableDestroy +#define PR_HashTableRawLookup PL_HashTableRawLookup +#define PR_HashTableRawAdd PL_HashTableRawAdd +#define PR_HashTableRawRemove PL_HashTableRawRemove +#define PR_HashTableAdd PL_HashTableAdd +#define PR_HashTableRemove PL_HashTableRemove +#define PR_HashTableEnumerateEntries PL_HashTableEnumerateEntries +#define PR_HashTableLookup PL_HashTableLookup +#define PR_HashTableDump PL_HashTableDump +#define PR_HashString PL_HashString +#define PR_CompareStrings PL_CompareStrings +#define PR_CompareValues PL_CompareValues + +#endif /* !defined(PROTYPES_H) */ diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp new file mode 100644 index 0000000..c735970 --- /dev/null +++ b/js/src/jsparse.cpp @@ -0,0 +1,9864 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS parser. + * + * This is a recursive-descent parser for the JavaScript language specified by + * "The JavaScript 1.5 Language Specification". It uses lexical and semantic + * feedback to disambiguate non-LL(1) structures. It generates trees of nodes + * induced by the recursive parsing (not precise syntax trees, see jsparse.h). + * After tree construction, it rewrites trees to fold constants and evaluate + * compile-time expressions. Finally, it calls js_EmitTree (see jsemit.h) to + * generate bytecode. + * + * This parser attempts no error recovery. + */ +#include +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsarena.h" +#include "jsutil.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jsstaticcheck.h" +#include "jslibmath.h" +#include "jsvector.h" + +#if JS_HAS_XML_SUPPORT +#include "jsxml.h" +#endif + +#if JS_HAS_DESTRUCTURING +#include "jsdhash.h" +#endif + +#include "jsatominlines.h" +#include "jsinterpinlines.h" +#include "jsobjinlines.h" +#include "jsregexpinlines.h" +#include "jsscriptinlines.h" + +// Grr, windows.h or something under it #defines CONST... +#ifdef CONST +#undef CONST +#endif + +using namespace js; +using namespace js::gc; + +/* + * Asserts to verify assumptions behind pn_ macros. + */ +#define pn_offsetof(m) offsetof(JSParseNode, m) + +JS_STATIC_ASSERT(pn_offsetof(pn_link) == pn_offsetof(dn_uses)); +JS_STATIC_ASSERT(pn_offsetof(pn_u.name.atom) == pn_offsetof(pn_u.apair.atom)); + +#undef pn_offsetof + +/* + * Insist that the next token be of type tt, or report errno and return null. + * NB: this macro uses cx and ts from its lexical environment. + */ +#define MUST_MATCH_TOKEN_WITH_FLAGS(tt, errno, __flags) \ + JS_BEGIN_MACRO \ + if (tokenStream.getToken((__flags)) != tt) { \ + reportErrorNumber(NULL, JSREPORT_ERROR, errno); \ + return NULL; \ + } \ + JS_END_MACRO +#define MUST_MATCH_TOKEN(tt, errno) MUST_MATCH_TOKEN_WITH_FLAGS(tt, errno, 0) + +#ifdef METER_PARSENODES +static uint32 parsenodes = 0; +static uint32 maxparsenodes = 0; +static uint32 recyclednodes = 0; +#endif + +void +JSParseNode::become(JSParseNode *pn2) +{ + JS_ASSERT(!pn_defn); + JS_ASSERT(!pn2->pn_defn); + + JS_ASSERT(!pn_used); + if (pn2->pn_used) { + JSParseNode **pnup = &pn2->pn_lexdef->dn_uses; + while (*pnup != pn2) + pnup = &(*pnup)->pn_link; + *pnup = this; + pn_link = pn2->pn_link; + pn_used = true; + pn2->pn_link = NULL; + pn2->pn_used = false; + } + + pn_type = pn2->pn_type; + pn_op = pn2->pn_op; + pn_arity = pn2->pn_arity; + pn_parens = pn2->pn_parens; + pn_u = pn2->pn_u; + + /* + * If any pointers are pointing to pn2, change them to point to this + * instead, since pn2 will be cleared and probably recycled. + */ + if (PN_TYPE(this) == TOK_FUNCTION && pn_arity == PN_FUNC) { + /* Function node: fix up the pn_funbox->node back-pointer. */ + JS_ASSERT(pn_funbox->node == pn2); + pn_funbox->node = this; + } else if (pn_arity == PN_LIST && !pn_head) { + /* Empty list: fix up the pn_tail pointer. */ + JS_ASSERT(pn_count == 0); + JS_ASSERT(pn_tail == &pn2->pn_head); + pn_tail = &pn_head; + } + + pn2->clear(); +} + +void +JSParseNode::clear() +{ + pn_type = TOK_EOF; + pn_op = JSOP_NOP; + pn_used = pn_defn = false; + pn_arity = PN_NULLARY; + pn_parens = false; +} + +Parser::Parser(JSContext *cx, JSPrincipals *prin, JSStackFrame *cfp) + : js::AutoGCRooter(cx, PARSER), + context(cx), + aleFreeList(NULL), + tokenStream(cx), + principals(NULL), + callerFrame(cfp), + callerVarObj(cfp ? &cfp->varobj(cx->containingSegment(cfp)) : NULL), + nodeList(NULL), + functionCount(0), + traceListHead(NULL), + tc(NULL), + keepAtoms(cx->runtime) +{ + js::PodArrayZero(tempFreeList); + setPrincipals(prin); + JS_ASSERT_IF(cfp, cfp->isScriptFrame()); +} + +bool +Parser::init(const jschar *base, size_t length, const char *filename, uintN lineno, + JSVersion version) +{ + JSContext *cx = context; + tempPoolMark = JS_ARENA_MARK(&cx->tempPool); + if (!tokenStream.init(base, length, filename, lineno, version)) { + JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark); + return false; + } + return true; +} + +Parser::~Parser() +{ + JSContext *cx = context; + + if (principals) + JSPRINCIPALS_DROP(cx, principals); + tokenStream.close(); + JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark); +} + +void +Parser::setPrincipals(JSPrincipals *prin) +{ + JS_ASSERT(!principals); + if (prin) + JSPRINCIPALS_HOLD(context, prin); + principals = prin; +} + +JSObjectBox * +Parser::newObjectBox(JSObject *obj) +{ + JS_ASSERT(obj); + + /* + * We use JSContext.tempPool to allocate parsed objects and place them on + * a list in this Parser to ensure GC safety. Thus the tempPool arenas + * containing the entries must be alive until we are done with scanning, + * parsing and code generation for the whole script or top-level function. + */ + JSObjectBox *objbox; + JS_ARENA_ALLOCATE_TYPE(objbox, JSObjectBox, &context->tempPool); + if (!objbox) { + js_ReportOutOfScriptQuota(context); + return NULL; + } + objbox->traceLink = traceListHead; + traceListHead = objbox; + objbox->emitLink = NULL; + objbox->object = obj; + objbox->isFunctionBox = false; + return objbox; +} + +JSFunctionBox * +Parser::newFunctionBox(JSObject *obj, JSParseNode *fn, JSTreeContext *tc) +{ + JS_ASSERT(obj); + JS_ASSERT(obj->isFunction()); + + /* + * We use JSContext.tempPool to allocate parsed objects and place them on + * a list in this Parser to ensure GC safety. Thus the tempPool arenas + * containing the entries must be alive until we are done with scanning, + * parsing and code generation for the whole script or top-level function. + */ + JSFunctionBox *funbox; + JS_ARENA_ALLOCATE_TYPE(funbox, JSFunctionBox, &context->tempPool); + if (!funbox) { + js_ReportOutOfScriptQuota(context); + return NULL; + } + funbox->traceLink = traceListHead; + traceListHead = funbox; + funbox->emitLink = NULL; + funbox->object = obj; + funbox->isFunctionBox = true; + funbox->node = fn; + funbox->siblings = tc->functionList; + tc->functionList = funbox; + ++tc->parser->functionCount; + funbox->kids = NULL; + funbox->parent = tc->funbox; + funbox->methods = NULL; + new (&funbox->bindings) Bindings(context); + funbox->queued = false; + funbox->inLoop = false; + for (JSStmtInfo *stmt = tc->topStmt; stmt; stmt = stmt->down) { + if (STMT_IS_LOOP(stmt)) { + funbox->inLoop = true; + break; + } + } + funbox->level = tc->staticLevel; + funbox->tcflags = (TCF_IN_FUNCTION | (tc->flags & (TCF_COMPILE_N_GO | TCF_STRICT_MODE_CODE))); + if (tc->innermostWith) + funbox->tcflags |= TCF_IN_WITH; + return funbox; +} + +bool +JSFunctionBox::joinable() const +{ + return FUN_NULL_CLOSURE((JSFunction *) object) && + !(tcflags & (TCF_FUN_USES_ARGUMENTS | TCF_FUN_USES_OWN_NAME)); +} + +bool +JSFunctionBox::inAnyDynamicScope() const +{ + for (const JSFunctionBox *funbox = this; funbox; funbox = funbox->parent) { + if (funbox->tcflags & (TCF_IN_WITH | TCF_FUN_CALLS_EVAL)) + return true; + } + return false; +} + +bool +JSFunctionBox::shouldUnbrand(uintN methods, uintN slowMethods) const +{ + if (slowMethods != 0) { + for (const JSFunctionBox *funbox = this; funbox; funbox = funbox->parent) { + if (!(funbox->tcflags & TCF_FUN_MODULE_PATTERN)) + return true; + if (funbox->inLoop) + return true; + } + } + return false; +} + +void +Parser::trace(JSTracer *trc) +{ + JSObjectBox *objbox = traceListHead; + while (objbox) { + MarkObject(trc, *objbox->object, "parser.object"); + if (objbox->isFunctionBox) + static_cast(objbox)->bindings.trace(trc); + objbox = objbox->traceLink; + } + + for (JSTreeContext *tc = this->tc; tc; tc = tc->parent) + tc->trace(trc); +} + +/* Add |node| to |parser|'s free node list. */ +static inline void +AddNodeToFreeList(JSParseNode *pn, js::Parser *parser) +{ + /* Catch back-to-back dup recycles. */ + JS_ASSERT(pn != parser->nodeList); + + /* + * It's too hard to clear these nodes from the JSAtomLists, etc. that + * hold references to them, so we never free them. It's our caller's + * job to recognize and process these, since their children do need to + * be dealt with. + */ + JS_ASSERT(!pn->pn_used); + JS_ASSERT(!pn->pn_defn); + +#ifdef DEBUG + /* Poison the node, to catch attempts to use it without initializing it. */ + memset(pn, 0xab, sizeof(*pn)); +#endif + + pn->pn_next = parser->nodeList; + parser->nodeList = pn; + +#ifdef METER_PARSENODES + recyclednodes++; +#endif +} + +/* Add |node| to |tc|'s parser's free node list. */ +static inline void +AddNodeToFreeList(JSParseNode *pn, JSTreeContext *tc) +{ + AddNodeToFreeList(pn, tc->parser); +} + +/* + * Walk the function box list at |*funboxHead|, removing boxes for deleted + * functions and cleaning up method lists. We do this once, before + * performing function analysis, to avoid traversing possibly long function + * lists repeatedly when recycling nodes. + * + * There are actually three possible states for function boxes and their + * nodes: + * + * - Live: funbox->node points to the node, and funbox->node->pn_funbox + * points back to the funbox. + * + * - Recycled: funbox->node points to the node, but funbox->node->pn_funbox + * is NULL. When a function node is part of a tree that gets recycled, we + * must avoid corrupting any method list the node is on, so we leave the + * function node unrecycled until we call cleanFunctionList. At recycle + * time, we clear such nodes' pn_funbox pointers to indicate that they + * are deleted and should be recycled once we get here. + * + * - Mutated: funbox->node is NULL; the contents of the node itself could + * be anything. When we mutate a function node into some other kind of + * node, we lose all indication that the node was ever part of the + * function box tree; it could later be recycled, reallocated, and turned + * into anything at all. (Fortunately, method list members never get + * mutated, so we don't have to worry about that case.) + * PrepareNodeForMutation clears the node's function box's node pointer, + * disconnecting it entirely from the function box tree, and marking the + * function box to be trimmed out. + */ +void +Parser::cleanFunctionList(JSFunctionBox **funboxHead) +{ + JSFunctionBox **link = funboxHead; + while (JSFunctionBox *box = *link) { + if (!box->node) { + /* + * This funbox's parse node was mutated into something else. Drop the box, + * and stay at the same link. + */ + *link = box->siblings; + } else if (!box->node->pn_funbox) { + /* + * This funbox's parse node is ready to be recycled. Drop the box, recycle + * the node, and stay at the same link. + */ + *link = box->siblings; + AddNodeToFreeList(box->node, this); + } else { + /* The function is still live. */ + + /* First, remove nodes for deleted functions from our methods list. */ + { + JSParseNode **methodLink = &box->methods; + while (JSParseNode *method = *methodLink) { + /* Method nodes are never rewritten in place to be other kinds of nodes. */ + JS_ASSERT(method->pn_arity == PN_FUNC); + if (!method->pn_funbox) { + /* Deleted: drop the node, and stay on this link. */ + *methodLink = method->pn_link; + } else { + /* Live: keep the node, and move to the next link. */ + methodLink = &method->pn_link; + } + } + } + + /* Second, remove boxes for deleted functions from our kids list. */ + cleanFunctionList(&box->kids); + + /* Keep the box on the list, and move to the next link. */ + link = &box->siblings; + } + } +} + +namespace js { + +/* + * A work pool of JSParseNodes. The work pool is a stack, chained together + * by nodes' pn_next fields. We use this to avoid creating deep C++ stacks + * when recycling deep parse trees. + * + * Since parse nodes are probably allocated in something close to the order + * they appear in a depth-first traversal of the tree, making the work pool + * a stack should give us pretty good locality. + */ +class NodeStack { + public: + NodeStack() : top(NULL) { } + bool empty() { return top == NULL; } + void push(JSParseNode *pn) { + pn->pn_next = top; + top = pn; + } + void pushUnlessNull(JSParseNode *pn) { if (pn) push(pn); } + /* Push the children of the PN_LIST node |pn| on the stack. */ + void pushList(JSParseNode *pn) { + /* This clobbers pn->pn_head if the list is empty; should be okay. */ + *pn->pn_tail = top; + top = pn->pn_head; + } + JSParseNode *pop() { + JS_ASSERT(!empty()); + JSParseNode *hold = top; /* my kingdom for a prog1 */ + top = top->pn_next; + return hold; + } + private: + JSParseNode *top; +}; + +} /* namespace js */ + +/* + * Push the children of |pn| on |stack|. Return true if |pn| itself could be + * safely recycled, or false if it must be cleaned later (pn_used and pn_defn + * nodes, and all function nodes; see comments for + * js::Parser::cleanFunctionList). Some callers want to free |pn|; others + * (PrepareNodeForMutation) don't care about |pn|, and just need to take care of + * its children. + */ +static bool +PushNodeChildren(JSParseNode *pn, NodeStack *stack) +{ + switch (pn->pn_arity) { + case PN_FUNC: + /* + * Function nodes are linked into the function box tree, and may + * appear on method lists. Both of those lists are singly-linked, + * so trying to update them now could result in quadratic behavior + * when recycling trees containing many functions; and the lists + * can be very long. So we put off cleaning the lists up until just + * before function analysis, when we call + * js::Parser::cleanFunctionList. + * + * In fact, we can't recycle the parse node yet, either: it may + * appear on a method list, and reusing the node would corrupt + * that. Instead, we clear its pn_funbox pointer to mark it as + * deleted; js::Parser::cleanFunctionList recycles it as well. + * + * We do recycle the nodes around it, though, so we must clear + * pointers to them to avoid leaving dangling references where + * someone can find them. + */ + pn->pn_funbox = NULL; + stack->pushUnlessNull(pn->pn_body); + pn->pn_body = NULL; + return false; + + case PN_NAME: + /* + * Because used/defn nodes appear in JSAtomLists and elsewhere, we + * don't recycle them. (We'll recover their storage when we free + * the temporary arena.) However, we do recycle the nodes around + * them, so clean up the pointers to avoid dangling references. The + * top-level decls table carries references to them that later + * iterations through the compileScript loop may find, so they need + * to be neat. + * + * pn_expr and pn_lexdef share storage; the latter isn't an owning + * reference. + */ + if (!pn->pn_used) { + stack->pushUnlessNull(pn->pn_expr); + pn->pn_expr = NULL; + } + return !pn->pn_used && !pn->pn_defn; + + case PN_LIST: + stack->pushList(pn); + break; + case PN_TERNARY: + stack->pushUnlessNull(pn->pn_kid1); + stack->pushUnlessNull(pn->pn_kid2); + stack->pushUnlessNull(pn->pn_kid3); + break; + case PN_BINARY: + if (pn->pn_left != pn->pn_right) + stack->pushUnlessNull(pn->pn_left); + stack->pushUnlessNull(pn->pn_right); + break; + case PN_UNARY: + stack->pushUnlessNull(pn->pn_kid); + break; + case PN_NULLARY: + /* + * E4X function namespace nodes are PN_NULLARY, but can appear on use + * lists. + */ + return !pn->pn_used && !pn->pn_defn; + } + + return true; +} + +/* + * Prepare |pn| to be mutated in place into a new kind of node. Recycle all + * |pn|'s recyclable children (but not |pn| itself!), and disconnect it from + * metadata structures (the function box tree). + */ +static void +PrepareNodeForMutation(JSParseNode *pn, JSTreeContext *tc) +{ + if (pn->pn_arity != PN_NULLARY) { + if (pn->pn_arity == PN_FUNC) { + /* + * Since this node could be turned into anything, we can't + * ensure it won't be subsequently recycled, so we must + * disconnect it from the funbox tree entirely. + * + * Note that pn_funbox may legitimately be NULL. functionDef + * applies MakeDefIntoUse to definition nodes, which can come + * from prior iterations of the big loop in compileScript. In + * such cases, the defn nodes have been visited by the recycler + * (but not actually recycled!), and their funbox pointers + * cleared. But it's fine to mutate them into uses of some new + * definition. + */ + if (pn->pn_funbox) + pn->pn_funbox->node = NULL; + } + + /* Put |pn|'s children (but not |pn| itself) on a work stack. */ + NodeStack stack; + PushNodeChildren(pn, &stack); + /* + * For each node on the work stack, push its children on the work stack, + * and free the node if we can. + */ + while (!stack.empty()) { + pn = stack.pop(); + if (PushNodeChildren(pn, &stack)) + AddNodeToFreeList(pn, tc); + } + } +} + +/* + * Return the nodes in the subtree |pn| to the parser's free node list, for + * reallocation. + * + * Note that all functions in |pn| that are not enclosed by other functions + * in |pn| must be direct children of |tc|, because we only clean up |tc|'s + * function and method lists. You must not reach into a function and + * recycle some part of it (unless you've updated |tc|->functionList, the + * way js_FoldConstants does). + */ +static JSParseNode * +RecycleTree(JSParseNode *pn, JSTreeContext *tc) +{ + if (!pn) + return NULL; + + JSParseNode *savedNext = pn->pn_next; + + NodeStack stack; + for (;;) { + if (PushNodeChildren(pn, &stack)) + AddNodeToFreeList(pn, tc); + if (stack.empty()) + break; + pn = stack.pop(); + } + + return savedNext; +} + +/* + * Allocate a JSParseNode from tc's node freelist or, failing that, from + * cx's temporary arena. + */ +static JSParseNode * +NewOrRecycledNode(JSTreeContext *tc) +{ + JSParseNode *pn; + + pn = tc->parser->nodeList; + if (!pn) { + JSContext *cx = tc->parser->context; + + JS_ARENA_ALLOCATE_TYPE(pn, JSParseNode, &cx->tempPool); + if (!pn) + js_ReportOutOfScriptQuota(cx); + } else { + tc->parser->nodeList = pn->pn_next; + } + + if (pn) { +#ifdef METER_PARSENODES + parsenodes++; + if (parsenodes - recyclednodes > maxparsenodes) + maxparsenodes = parsenodes - recyclednodes; +#endif + pn->pn_used = pn->pn_defn = false; + memset(&pn->pn_u, 0, sizeof pn->pn_u); + pn->pn_next = NULL; + } + return pn; +} + +/* used only by static create methods of subclasses */ + +JSParseNode * +JSParseNode::create(JSParseNodeArity arity, JSTreeContext *tc) +{ + JSParseNode *pn = NewOrRecycledNode(tc); + if (!pn) + return NULL; + const Token &tok = tc->parser->tokenStream.currentToken(); + pn->init(tok.type, JSOP_NOP, arity); + pn->pn_pos = tok.pos; + return pn; +} + +JSParseNode * +JSParseNode::newBinaryOrAppend(TokenKind tt, JSOp op, JSParseNode *left, JSParseNode *right, + JSTreeContext *tc) +{ + JSParseNode *pn, *pn1, *pn2; + + if (!left || !right) + return NULL; + + /* + * Flatten a left-associative (left-heavy) tree of a given operator into + * a list, to reduce js_FoldConstants and js_EmitTree recursion. + */ + if (PN_TYPE(left) == tt && + PN_OP(left) == op && + (js_CodeSpec[op].format & JOF_LEFTASSOC)) { + if (left->pn_arity != PN_LIST) { + pn1 = left->pn_left, pn2 = left->pn_right; + left->pn_arity = PN_LIST; + left->pn_parens = false; + left->initList(pn1); + left->append(pn2); + if (tt == TOK_PLUS) { + if (pn1->pn_type == TOK_STRING) + left->pn_xflags |= PNX_STRCAT; + else if (pn1->pn_type != TOK_NUMBER) + left->pn_xflags |= PNX_CANTFOLD; + if (pn2->pn_type == TOK_STRING) + left->pn_xflags |= PNX_STRCAT; + else if (pn2->pn_type != TOK_NUMBER) + left->pn_xflags |= PNX_CANTFOLD; + } + } + left->append(right); + left->pn_pos.end = right->pn_pos.end; + if (tt == TOK_PLUS) { + if (right->pn_type == TOK_STRING) + left->pn_xflags |= PNX_STRCAT; + else if (right->pn_type != TOK_NUMBER) + left->pn_xflags |= PNX_CANTFOLD; + } + return left; + } + + /* + * Fold constant addition immediately, to conserve node space and, what's + * more, so js_FoldConstants never sees mixed addition and concatenation + * operations with more than one leading non-string operand in a PN_LIST + * generated for expressions such as 1 + 2 + "pt" (which should evaluate + * to "3pt", not "12pt"). + */ + if (tt == TOK_PLUS && + left->pn_type == TOK_NUMBER && + right->pn_type == TOK_NUMBER) { + left->pn_dval += right->pn_dval; + left->pn_pos.end = right->pn_pos.end; + RecycleTree(right, tc); + return left; + } + + pn = NewOrRecycledNode(tc); + if (!pn) + return NULL; + pn->init(tt, op, PN_BINARY); + pn->pn_pos.begin = left->pn_pos.begin; + pn->pn_pos.end = right->pn_pos.end; + pn->pn_left = left; + pn->pn_right = right; + return (BinaryNode *)pn; +} + +namespace js { + +inline void +NameNode::initCommon(JSTreeContext *tc) +{ + pn_expr = NULL; + pn_cookie.makeFree(); + pn_dflags = (!tc->topStmt || tc->topStmt->type == STMT_BLOCK) + ? PND_BLOCKCHILD + : 0; + pn_blockid = tc->blockid(); +} + +NameNode * +NameNode::create(JSAtom *atom, JSTreeContext *tc) +{ + JSParseNode *pn; + + pn = JSParseNode::create(PN_NAME, tc); + if (pn) { + pn->pn_atom = atom; + ((NameNode *)pn)->initCommon(tc); + } + return (NameNode *)pn; +} + +} /* namespace js */ + +static bool +GenerateBlockId(JSTreeContext *tc, uint32& blockid) +{ + if (tc->blockidGen == JS_BIT(20)) { + JS_ReportErrorNumber(tc->parser->context, js_GetErrorMessage, NULL, + JSMSG_NEED_DIET, "program"); + return false; + } + blockid = tc->blockidGen++; + return true; +} + +static bool +GenerateBlockIdForStmtNode(JSParseNode *pn, JSTreeContext *tc) +{ + JS_ASSERT(tc->topStmt); + JS_ASSERT(STMT_MAYBE_SCOPE(tc->topStmt)); + JS_ASSERT(pn->pn_type == TOK_LC || pn->pn_type == TOK_LEXICALSCOPE); + if (!GenerateBlockId(tc, tc->topStmt->blockid)) + return false; + pn->pn_blockid = tc->topStmt->blockid; + return true; +} + +/* + * Parse a top-level JS script. + */ +JSParseNode * +Parser::parse(JSObject *chain) +{ + /* + * Protect atoms from being collected by a GC activation, which might + * - nest on this thread due to out of memory (the so-called "last ditch" + * GC attempted within js_NewGCThing), or + * - run for any reason on another thread if this thread is suspended on + * an object lock before it finishes generating bytecode into a script + * protected from the GC by a root or a stack frame reference. + */ + JSTreeContext globaltc(this); + globaltc.setScopeChain(chain); + if (!GenerateBlockId(&globaltc, globaltc.bodyid)) + return NULL; + + JSParseNode *pn = statements(); + if (pn) { + if (!tokenStream.matchToken(TOK_EOF)) { + reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); + pn = NULL; + } else { + if (!js_FoldConstants(context, pn, &globaltc)) + pn = NULL; + } + } + return pn; +} + +JS_STATIC_ASSERT(UpvarCookie::FREE_LEVEL == JS_BITMASK(JSFB_LEVEL_BITS)); + +static inline bool +SetStaticLevel(JSTreeContext *tc, uintN staticLevel) +{ + /* + * This is a lot simpler than error-checking every UpvarCookie::set, and + * practically speaking it leaves more than enough room for upvars. + */ + if (UpvarCookie::isLevelReserved(staticLevel)) { + JS_ReportErrorNumber(tc->parser->context, js_GetErrorMessage, NULL, + JSMSG_TOO_DEEP, js_function_str); + return false; + } + tc->staticLevel = staticLevel; + return true; +} + +/* + * Compile a top-level script. + */ +Compiler::Compiler(JSContext *cx, JSPrincipals *prin, JSStackFrame *cfp) + : parser(cx, prin, cfp) +{ +} + +JSScript * +Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame, + JSPrincipals *principals, uint32 tcflags, + const jschar *chars, size_t length, + const char *filename, uintN lineno, JSVersion version, + JSString *source /* = NULL */, + uintN staticLevel /* = 0 */) +{ + JSArenaPool codePool, notePool; + TokenKind tt; + JSParseNode *pn; + JSScript *script; + bool inDirectivePrologue; +#ifdef METER_PARSENODES + void *sbrk(ptrdiff_t), *before = sbrk(0); +#endif + + JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL | TCF_NEED_MUTABLE_SCRIPT | + TCF_COMPILE_FOR_EVAL))); + + /* + * The scripted callerFrame can only be given for compile-and-go scripts + * and non-zero static level requires callerFrame. + */ + JS_ASSERT_IF(callerFrame, tcflags & TCF_COMPILE_N_GO); + JS_ASSERT_IF(staticLevel != 0, callerFrame); + + Compiler compiler(cx, principals, callerFrame); + if (!compiler.init(chars, length, filename, lineno, version)) + return NULL; + + JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode), + &cx->scriptStackQuota); + JS_InitArenaPool(¬ePool, "note", 1024, sizeof(jssrcnote), + &cx->scriptStackQuota); + + Parser &parser = compiler.parser; + TokenStream &tokenStream = parser.tokenStream; + + JSCodeGenerator cg(&parser, &codePool, ¬ePool, tokenStream.getLineno()); + if (!cg.init()) + return NULL; + + MUST_FLOW_THROUGH("out"); + + // We can specialize a bit for the given scope chain if that scope chain is the global object. + JSObject *globalObj = scopeChain && scopeChain == scopeChain->getGlobal() + ? scopeChain->getGlobal() + : NULL; + js::GlobalScope globalScope(cx, globalObj, &cg); + if (globalObj) { + JS_ASSERT(globalObj->isNative()); + JS_ASSERT((globalObj->getClass()->flags & JSCLASS_GLOBAL_FLAGS) == JSCLASS_GLOBAL_FLAGS); + } + + /* Null script early in case of error, to reduce our code footprint. */ + script = NULL; + + globalScope.cg = &cg; + cg.flags |= tcflags; + cg.setScopeChain(scopeChain); + compiler.globalScope = &globalScope; + if (!SetStaticLevel(&cg, staticLevel)) + goto out; + + /* If this is a direct call to eval, inherit the caller's strictness. */ + if (callerFrame && + callerFrame->isScriptFrame() && + callerFrame->script()->strictModeCode) { + cg.flags |= TCF_STRICT_MODE_CODE; + tokenStream.setStrictMode(); + } + + /* + * If funbox is non-null after we create the new script, callerFrame->fun + * was saved in the 0th object table entry. + */ + JSObjectBox *funbox; + funbox = NULL; + + if (tcflags & TCF_COMPILE_N_GO) { + if (source) { + /* + * Save eval program source in script->atomMap.vector[0] for the + * eval cache (see EvalCacheLookup in jsobj.cpp). + */ + JSAtom *atom = js_AtomizeString(cx, source, 0); + if (!atom || !cg.atomList.add(&parser, atom)) + goto out; + } + + if (callerFrame && callerFrame->isFunctionFrame()) { + /* + * An eval script in a caller frame needs to have its enclosing + * function captured in case it refers to an upvar, and someone + * wishes to decompile it while it's running. + */ + funbox = parser.newObjectBox(FUN_OBJECT(callerFrame->fun())); + if (!funbox) + goto out; + funbox->emitLink = cg.objectList.lastbox; + cg.objectList.lastbox = funbox; + cg.objectList.length++; + } + } + + /* + * Inline this->statements to emit as we go to save AST space. We must + * generate our script-body blockid since we aren't calling Statements. + */ + uint32 bodyid; + if (!GenerateBlockId(&cg, bodyid)) + goto out; + cg.bodyid = bodyid; + +#if JS_HAS_XML_SUPPORT + pn = NULL; + bool onlyXML; + onlyXML = true; +#endif + + inDirectivePrologue = true; + tokenStream.setOctalCharacterEscape(false); + for (;;) { + tt = tokenStream.peekToken(TSF_OPERAND); + if (tt <= TOK_EOF) { + if (tt == TOK_EOF) + break; + JS_ASSERT(tt == TOK_ERROR); + goto out; + } + + pn = parser.statement(); + if (!pn) + goto out; + JS_ASSERT(!cg.blockNode); + + if (inDirectivePrologue && !parser.recognizeDirectivePrologue(pn, &inDirectivePrologue)) + goto out; + + if (!js_FoldConstants(cx, pn, &cg)) + goto out; + + if (!parser.analyzeFunctions(&cg)) + goto out; + cg.functionList = NULL; + + if (!js_EmitTree(cx, &cg, pn)) + goto out; + +#if JS_HAS_XML_SUPPORT + if (PN_TYPE(pn) != TOK_SEMI || + !pn->pn_kid || + !TreeTypeIsXML(PN_TYPE(pn->pn_kid))) { + onlyXML = false; + } +#endif + RecycleTree(pn, &cg); + } + +#if JS_HAS_XML_SUPPORT + /* + * Prevent XML data theft via + * + * It does not cope with malformed comment hiding hacks where --> is hidden + * by C-style comments, or on a dirty line. Such cases are already broken. + */ + TSF_IN_HTML_COMMENT = 0x2000 +}; + +#define t_op u.s.op +#define t_reflags u.reflags +#define t_atom u.s.atom +#define t_atom2 u.p.atom2 +#define t_dval u.dval + +class TokenStream +{ + static const size_t ntokens = 4; /* 1 current + 2 lookahead, rounded + to power of 2 to avoid divmod by 3 */ + static const uintN ntokensMask = ntokens - 1; + + public: + typedef Vector CharBuffer; + + /* + * To construct a TokenStream, first call the constructor, which is + * infallible, then call |init|, which can fail. To destroy a TokenStream, + * first call |close| then call the destructor. If |init| fails, do not call + * |close|. + * + * This class uses JSContext.tempPool to allocate internal buffers. The + * caller should JS_ARENA_MARK before calling |init| and JS_ARENA_RELEASE + * after calling |close|. + */ + TokenStream(JSContext *); + + /* + * Create a new token stream from an input buffer. + * Return false on memory-allocation failure. + */ + bool init(const jschar *base, size_t length, const char *filename, uintN lineno, + JSVersion version); + void close(); + ~TokenStream() {} + + /* Accessors. */ + JSContext *getContext() const { return cx; } + bool onCurrentLine(const TokenPos &pos) const { return lineno == pos.end.lineno; } + const Token ¤tToken() const { return tokens[cursor]; } + const CharBuffer &getTokenbuf() const { return tokenbuf; } + const char *getFilename() const { return filename; } + uintN getLineno() const { return lineno; } + /* Note that the version and hasXML can get out of sync via setXML. */ + JSVersion versionNumber() const { return VersionNumber(version); } + JSVersion versionWithFlags() const { return version; } + bool hasAnonFunFix() const { return VersionHasAnonFunFix(version); } + bool hasXML() const { return xml || VersionShouldParseXML(versionNumber()); } + void setXML(bool enabled) { xml = enabled; } + + /* Flag methods. */ + void setStrictMode(bool enabled = true) { setFlag(enabled, TSF_STRICT_MODE_CODE); } + void setXMLTagMode(bool enabled = true) { setFlag(enabled, TSF_XMLTAGMODE); } + void setXMLOnlyMode(bool enabled = true) { setFlag(enabled, TSF_XMLONLYMODE); } + void setUnexpectedEOF(bool enabled = true) { setFlag(enabled, TSF_UNEXPECTED_EOF); } + void setOctalCharacterEscape(bool enabled = true) { setFlag(enabled, TSF_OCTAL_CHAR); } + + bool isStrictMode() { return !!(flags & TSF_STRICT_MODE_CODE); } + bool isXMLTagMode() { return !!(flags & TSF_XMLTAGMODE); } + bool isXMLOnlyMode() { return !!(flags & TSF_XMLONLYMODE); } + bool isUnexpectedEOF() { return !!(flags & TSF_UNEXPECTED_EOF); } + bool isEOF() const { return !!(flags & TSF_EOF); } + bool isError() const { return !!(flags & TSF_ERROR); } + bool hasOctalCharacterEscape() const { return flags & TSF_OCTAL_CHAR; } + + /* Mutators. */ + bool reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN errorNumber, va_list ap); + void mungeCurrentToken(TokenKind newKind) { tokens[cursor].type = newKind; } + void mungeCurrentToken(JSOp newOp) { tokens[cursor].t_op = newOp; } + void mungeCurrentToken(TokenKind newKind, JSOp newOp) { + mungeCurrentToken(newKind); + mungeCurrentToken(newOp); + } + + private: + static JSAtom *atomize(JSContext *cx, CharBuffer &cb); + + /* + * Enables flags in the associated tokenstream for the object lifetime. + * Useful for lexically-scoped flag toggles. + */ + class Flagger { + TokenStream * const parent; + uintN flags; + public: + Flagger(TokenStream *parent, uintN withFlags) : parent(parent), flags(withFlags) { + parent->flags |= flags; + } + + ~Flagger() { parent->flags &= ~flags; } + }; + friend class Flagger; + + void setFlag(bool enabled, TokenStreamFlags flag) { + if (enabled) + flags |= flag; + else + flags &= ~flag; + } + + public: + /* + * Get the next token from the stream, make it the current token, and + * return its kind. + */ + TokenKind getToken() { + /* Check for a pushed-back token resulting from mismatching lookahead. */ + while (lookahead != 0) { + JS_ASSERT(!(flags & TSF_XMLTEXTMODE)); + lookahead--; + cursor = (cursor + 1) & ntokensMask; + TokenKind tt = currentToken().type; + JS_ASSERT(!(flags & TSF_NEWLINES)); + if (tt != TOK_EOL) + return tt; + } + + /* If there was a fatal error, keep returning TOK_ERROR. */ + if (flags & TSF_ERROR) + return TOK_ERROR; + + return getTokenInternal(); + } + + /* Similar, but also sets flags. */ + TokenKind getToken(uintN withFlags) { + Flagger flagger(this, withFlags); + return getToken(); + } + + /* + * Push the last scanned token back into the stream. + */ + void ungetToken() { + JS_ASSERT(lookahead < ntokensMask); + lookahead++; + cursor = (cursor - 1) & ntokensMask; + } + + TokenKind peekToken(uintN withFlags = 0) { + Flagger flagger(this, withFlags); + if (lookahead != 0) { + JS_ASSERT(lookahead == 1); + return tokens[(cursor + lookahead) & ntokensMask].type; + } + TokenKind tt = getToken(); + ungetToken(); + return tt; + } + + TokenKind peekTokenSameLine(uintN withFlags = 0) { + Flagger flagger(this, withFlags); + if (!onCurrentLine(currentToken().pos)) + return TOK_EOL; + TokenKind tt = peekToken(TSF_NEWLINES); + return tt; + } + + /* + * Get the next token from the stream if its kind is |tt|. + */ + JSBool matchToken(TokenKind tt, uintN withFlags = 0) { + Flagger flagger(this, withFlags); + if (getToken() == tt) + return JS_TRUE; + ungetToken(); + return JS_FALSE; + } + + private: + typedef struct TokenBuf { + jschar *base; /* base of line or stream buffer */ + jschar *limit; /* limit for quick bounds check */ + jschar *ptr; /* next char to get, or slot to use */ + } TokenBuf; + + TokenKind getTokenInternal(); /* doesn't check for pushback or error flag. */ + + int32 getChar(); + int32 getCharIgnoreEOL(); + void ungetChar(int32 c); + void ungetCharIgnoreEOL(int32 c); + Token *newToken(ptrdiff_t adjust); + bool peekUnicodeEscape(int32 *c); + bool matchUnicodeEscapeIdStart(int32 *c); + bool matchUnicodeEscapeIdent(int32 *c); + JSBool peekChars(intN n, jschar *cp); + JSBool getXMLEntity(); + jschar *findEOL(); + + JSBool matchChar(int32 expect) { + int32 c = getChar(); + if (c == expect) + return JS_TRUE; + ungetChar(c); + return JS_FALSE; + } + + int32 peekChar() { + int32 c = getChar(); + ungetChar(c); + return c; + } + + void skipChars(intN n) { + while (--n >= 0) + getChar(); + } + + JSContext * const cx; + Token tokens[ntokens];/* circular token buffer */ + uintN cursor; /* index of last parsed token */ + uintN lookahead; /* count of lookahead tokens */ + uintN lineno; /* current line number */ + uintN flags; /* flags -- see above */ + jschar *linebase; /* start of current line; points into userbuf */ + jschar *prevLinebase; /* start of previous line; NULL if on the first line */ + TokenBuf userbuf; /* user input buffer */ + const char *filename; /* input filename or null */ + JSSourceHandler listener; /* callback for source; eg debugger */ + void *listenerData; /* listener 'this' data */ + void *listenerTSData;/* listener data for this TokenStream */ + CharBuffer tokenbuf; /* current token string buffer */ + bool maybeEOL[256]; /* probabilistic EOL lookup table */ + bool maybeStrSpecial[256];/* speeds up string scanning */ + JSVersion version; /* (i.e. to identify keywords) */ + bool xml; /* see JSOPTION_XML */ +}; + +} /* namespace js */ + +/* Unicode separators that are treated as line terminators, in addition to \n, \r */ +#define LINE_SEPARATOR 0x2028 +#define PARA_SEPARATOR 0x2029 + +extern void +js_CloseTokenStream(JSContext *cx, js::TokenStream *ts); + +extern JS_FRIEND_API(int) +js_fgets(char *buf, int size, FILE *file); + +namespace js { + +struct KeywordInfo { + const char *chars; /* C string with keyword text */ + TokenKind tokentype; + JSOp op; /* JSOp */ + JSVersion version; /* JSVersion */ +}; + +/* + * Returns a KeywordInfo for the specified characters, or NULL if the string is + * not a keyword. + */ +extern const KeywordInfo * +FindKeyword(const jschar *s, size_t length); + +} // namespace js + +/* + * Friend-exported API entry point to call a mapping function on each reserved + * identifier in the scanner's keyword table. + */ +typedef void (*JSMapKeywordFun)(const char *); + +/* + * Check that str forms a valid JS identifier name. The function does not + * check if str is a JS keyword. + */ +extern JSBool +js_IsIdentifier(JSLinearString *str); + +/* + * Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error + * message have const jschar* type, not const char*. + */ +#define JSREPORT_UC 0x100 + +namespace js { + +/* + * Report a compile-time error by its number. Return true for a warning, false + * for an error. When pn is not null, use it to report error's location. + * Otherwise use ts, which must not be null. + */ +bool +ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, JSParseNode *pn, uintN flags, + uintN errorNumber, ...); + +/* + * Report a condition that should elicit a warning with JSOPTION_STRICT, + * or an error if ts or tc is handling strict mode code. This function + * defers to ReportCompileErrorNumber to do the real work. Either tc + * or ts may be NULL, if there is no tree context or token stream state + * whose strictness should affect the report. + * + * One could have ReportCompileErrorNumber recognize the + * JSREPORT_STRICT_MODE_ERROR flag instead of having a separate function + * like this one. However, the strict mode code flag we need to test is + * in the JSTreeContext structure for that code; we would have to change + * the ~120 ReportCompileErrorNumber calls to pass the additional + * argument, even though many of those sites would never use it. Using + * ts's TSF_STRICT_MODE_CODE flag instead of tc's would be brittle: at some + * points ts's flags don't correspond to those of the tc relevant to the + * error. + */ +bool +ReportStrictModeError(JSContext *cx, TokenStream *ts, JSTreeContext *tc, JSParseNode *pn, + uintN errorNumber, ...); + +} /* namespace js */ + +#endif /* jsscan_h___ */ diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp new file mode 100644 index 0000000..6ad7e61 --- /dev/null +++ b/js/src/jsscope.cpp @@ -0,0 +1,1506 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS symbol tables. + */ +#include +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsarena.h" +#include "jsbit.h" +#include "jsclist.h" +#include "jsdhash.h" +#include "jsutil.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsdbgapi.h" +#include "jsfun.h" /* for JS_ARGS_LENGTH_MAX */ +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsscope.h" +#include "jsstr.h" +#include "jstracer.h" + +#include "jsdbgapiinlines.h" +#include "jsobjinlines.h" +#include "jsscopeinlines.h" + +using namespace js; +using namespace js::gc; + +uint32 +js_GenerateShape(JSRuntime *rt) +{ + uint32 shape; + + shape = JS_ATOMIC_INCREMENT(&rt->shapeGen); + JS_ASSERT(shape != 0); + if (shape >= SHAPE_OVERFLOW_BIT) { + /* + * FIXME bug 440834: The shape id space has overflowed. Currently we + * cope badly with this and schedule the GC on the every call. But + * first we make sure that increments from other threads would not + * have a chance to wrap around shapeGen to zero. + */ + rt->shapeGen = SHAPE_OVERFLOW_BIT; + shape = SHAPE_OVERFLOW_BIT; + +#ifdef JS_THREADSAFE + AutoLockGC lockIf(rt); +#endif + TriggerGC(rt); + } + return shape; +} + +uint32 +js_GenerateShape(JSContext *cx) +{ + return js_GenerateShape(cx->runtime); +} + +bool +JSObject::ensureClassReservedSlotsForEmptyObject(JSContext *cx) +{ + JS_ASSERT(nativeEmpty()); + + /* + * Subtle rule: objects that call JSObject::ensureInstanceReservedSlots + * must either: + * + * (a) never escape anywhere an ad-hoc property could be set on them; or + * + * (b) protect their instance-reserved slots with shapes, at least a custom + * empty shape with the right slotSpan member. + * + * Block objects are the only objects that fall into category (a). While + * Call objects cannot escape, they can grow ad-hoc properties via eval + * of a var declaration, or due to a function statement being evaluated, + * but they have slots mapped by compiler-created shapes, and thus (b) no + * problem predicting first ad-hoc property slot. Bound Function objects + * have a custom empty shape. + * + * (Note that Block, Call, and bound Function objects are the only native + * class objects that are allowed to call ensureInstanceReservedSlots.) + */ + uint32 nfixed = JSSLOT_FREE(getClass()); + if (nfixed > numSlots() && !allocSlots(cx, nfixed)) + return false; + + return true; +} + +#define PROPERTY_TABLE_NBYTES(n) ((n) * sizeof(Shape *)) + +#ifdef DEBUG +JS_FRIEND_DATA(JSScopeStats) js_scope_stats = {0}; + +# define METER(x) JS_ATOMIC_INCREMENT(&js_scope_stats.x) +#else +# define METER(x) ((void) 0) +#endif + +bool +PropertyTable::init(JSRuntime *rt, Shape *lastProp) +{ + /* + * Either we're creating a table for a large scope that was populated + * via property cache hit logic under JSOP_INITPROP, JSOP_SETNAME, or + * JSOP_SETPROP; or else calloc failed at least once already. In any + * event, let's try to grow, overallocating to hold at least twice the + * current population. + */ + uint32 sizeLog2 = JS_CeilingLog2(2 * entryCount); + if (sizeLog2 < MIN_SIZE_LOG2) + sizeLog2 = MIN_SIZE_LOG2; + + /* + * Use rt->calloc for memory accounting and overpressure handling + * without OOM reporting. See PropertyTable::change. + */ + entries = (Shape **) rt->calloc(JS_BIT(sizeLog2) * sizeof(Shape *)); + if (!entries) { + METER(tableAllocFails); + return false; + } + + hashShift = JS_DHASH_BITS - sizeLog2; + for (Shape::Range r = lastProp->all(); !r.empty(); r.popFront()) { + const Shape &shape = r.front(); + METER(searches); + METER(initSearches); + Shape **spp = search(shape.id, true); + + /* + * Beware duplicate args and arg vs. var conflicts: the youngest shape + * (nearest to lastProp) must win. See bug 600067. + */ + if (!SHAPE_FETCH(spp)) + SHAPE_STORE_PRESERVING_COLLISION(spp, &shape); + } + return true; +} + +bool +Shape::hashify(JSRuntime *rt) +{ + JS_ASSERT(!hasTable()); + void* mem = rt->malloc(sizeof(PropertyTable)); + if (!mem) + return false; + setTable(new(mem) PropertyTable(entryCount())); + return getTable()->init(rt, this); +} + +#ifdef DEBUG +# include "jsprf.h" +# define LIVE_SCOPE_METER(cx,expr) JS_LOCK_RUNTIME_VOID(cx->runtime,expr) +#else +# define LIVE_SCOPE_METER(cx,expr) /* nothing */ +#endif + +static inline bool +InitField(JSCompartment *comp, EmptyShape *JSCompartment:: *field, Class *clasp) +{ + if (EmptyShape *emptyShape = EmptyShape::create(comp, clasp)) { + comp->*field = emptyShape; + return true; + } + return false; +} + +/* static */ +bool +Shape::initEmptyShapes(JSCompartment *comp) +{ + /* + * NewArguments allocates dslots to have enough room for the argc of the + * particular arguments object being created. + * never mutated, it's safe to pretend to have all the slots possible. + * + * Note how the fast paths in jsinterp.cpp for JSOP_LENGTH and JSOP_GETELEM + * bypass resolution of scope properties for length and element indices on + * arguments objects. This helps ensure that any arguments object needing + * its own mutable scope (with unique shape) is a rare event. + */ + if (!InitField(comp, &JSCompartment::emptyArgumentsShape, &js_ArgumentsClass)) + return false; + + if (!InitField(comp, &JSCompartment::emptyBlockShape, &js_BlockClass)) + return false; + + /* + * Initialize the shared scope for all empty Call objects so gets for args + * and vars do not force the creation of a mutable scope for the particular + * call object being accessed. + */ + if (!InitField(comp, &JSCompartment::emptyCallShape, &js_CallClass)) + return false; + + /* A DeclEnv object holds the name binding for a named function expression. */ + if (!InitField(comp, &JSCompartment::emptyDeclEnvShape, &js_DeclEnvClass)) + return false; + + /* Non-escaping native enumerator objects share this empty scope. */ + if (!InitField(comp, &JSCompartment::emptyEnumeratorShape, &js_IteratorClass)) + return false; + + /* Same drill for With objects. */ + if (!InitField(comp, &JSCompartment::emptyWithShape, &js_WithClass)) + return false; + + return true; +} + +/* static */ +void +Shape::finishEmptyShapes(JSCompartment *comp) +{ + comp->emptyArgumentsShape = NULL; + comp->emptyBlockShape = NULL; + comp->emptyCallShape = NULL; + comp->emptyDeclEnvShape = NULL; + comp->emptyEnumeratorShape = NULL; + comp->emptyWithShape = NULL; +} + +JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4); +JS_STATIC_ASSERT(sizeof(jsid) == JS_BYTES_PER_WORD); + +#if JS_BYTES_PER_WORD == 4 +# define HASH_ID(id) ((JSHashNumber)(JSID_BITS(id))) +#elif JS_BYTES_PER_WORD == 8 +# define HASH_ID(id) ((JSHashNumber)(JSID_BITS(id)) ^ (JSHashNumber)((JSID_BITS(id)) >> 32)) +#else +# error "Unsupported configuration" +#endif + +/* + * Double hashing needs the second hash code to be relatively prime to table + * size, so we simply make hash2 odd. The inputs to multiplicative hash are + * the golden ratio, expressed as a fixed-point 32 bit fraction, and the id + * itself. + */ +#define HASH0(id) (HASH_ID(id) * JS_GOLDEN_RATIO) +#define HASH1(hash0,shift) ((hash0) >> (shift)) +#define HASH2(hash0,log2,shift) ((((hash0) << (log2)) >> (shift)) | 1) + +Shape ** +PropertyTable::search(jsid id, bool adding) +{ + JSHashNumber hash0, hash1, hash2; + int sizeLog2; + Shape *stored, *shape, **spp, **firstRemoved; + uint32 sizeMask; + + JS_ASSERT(entries); + JS_ASSERT(!JSID_IS_VOID(id)); + + /* Compute the primary hash address. */ + METER(hashes); + hash0 = HASH0(id); + hash1 = HASH1(hash0, hashShift); + spp = entries + hash1; + + /* Miss: return space for a new entry. */ + stored = *spp; + if (SHAPE_IS_FREE(stored)) { + METER(misses); + METER(hashMisses); + return spp; + } + + /* Hit: return entry. */ + shape = SHAPE_CLEAR_COLLISION(stored); + if (shape && shape->id == id) { + METER(hits); + METER(hashHits); + return spp; + } + + /* Collision: double hash. */ + sizeLog2 = JS_DHASH_BITS - hashShift; + hash2 = HASH2(hash0, sizeLog2, hashShift); + sizeMask = JS_BITMASK(sizeLog2); + +#ifdef DEBUG + jsuword collision_flag = SHAPE_COLLISION; +#endif + + /* Save the first removed entry pointer so we can recycle it if adding. */ + if (SHAPE_IS_REMOVED(stored)) { + firstRemoved = spp; + } else { + firstRemoved = NULL; + if (adding && !SHAPE_HAD_COLLISION(stored)) + SHAPE_FLAG_COLLISION(spp, shape); +#ifdef DEBUG + collision_flag &= jsuword(*spp) & SHAPE_COLLISION; +#endif + } + + for (;;) { + METER(steps); + hash1 -= hash2; + hash1 &= sizeMask; + spp = entries + hash1; + + stored = *spp; + if (SHAPE_IS_FREE(stored)) { + METER(misses); + METER(stepMisses); + return (adding && firstRemoved) ? firstRemoved : spp; + } + + shape = SHAPE_CLEAR_COLLISION(stored); + if (shape && shape->id == id) { + METER(hits); + METER(stepHits); + JS_ASSERT(collision_flag); + return spp; + } + + if (SHAPE_IS_REMOVED(stored)) { + if (!firstRemoved) + firstRemoved = spp; + } else { + if (adding && !SHAPE_HAD_COLLISION(stored)) + SHAPE_FLAG_COLLISION(spp, shape); +#ifdef DEBUG + collision_flag &= jsuword(*spp) & SHAPE_COLLISION; +#endif + } + } + + /* NOTREACHED */ + return NULL; +} + +bool +PropertyTable::change(int log2Delta, JSContext *cx) +{ + int oldlog2, newlog2; + uint32 oldsize, newsize, nbytes; + Shape **newTable, **oldTable, **spp, **oldspp, *shape; + + JS_ASSERT(entries); + + /* + * Grow, shrink, or compress by changing this->entries. Here, we prefer + * cx->runtime->calloc to js_calloc, which on OOM waits for a background + * thread to finish sweeping and retry, if appropriate. Avoid cx->calloc + * so our caller can be in charge of whether to JS_ReportOutOfMemory. + */ + oldlog2 = JS_DHASH_BITS - hashShift; + newlog2 = oldlog2 + log2Delta; + oldsize = JS_BIT(oldlog2); + newsize = JS_BIT(newlog2); + nbytes = PROPERTY_TABLE_NBYTES(newsize); + newTable = (Shape **) cx->runtime->calloc(nbytes); + if (!newTable) { + METER(tableAllocFails); + return false; + } + + /* Now that we have newTable allocated, update members. */ + hashShift = JS_DHASH_BITS - newlog2; + removedCount = 0; + oldTable = entries; + entries = newTable; + + /* Copy only live entries, leaving removed and free ones behind. */ + for (oldspp = oldTable; oldsize != 0; oldspp++) { + shape = SHAPE_FETCH(oldspp); + if (shape) { + METER(searches); + METER(changeSearches); + spp = search(shape->id, true); + JS_ASSERT(SHAPE_IS_FREE(*spp)); + *spp = shape; + } + oldsize--; + } + + /* + * Finally, free the old entries storage. Note that cx->runtime->free just + * calls js_free. Use js_free here to match PropertyTable::~PropertyTable, + * which cannot have a cx or rt parameter. + */ + js_free(oldTable); + return true; +} + +bool +PropertyTable::grow(JSContext *cx) +{ + JS_ASSERT(needsToGrow()); + + uint32 size = capacity(); + int delta = removedCount < size >> 2; + if (!delta) + METER(compresses); + else + METER(grows); + + if (!change(delta, cx) && entryCount + removedCount == size - 1) { + JS_ReportOutOfMemory(cx); + return false; + } + return true; +} + +Shape * +Shape::getChild(JSContext *cx, const js::Shape &child, Shape **listp) +{ + JS_ASSERT(!JSID_IS_VOID(child.id)); + JS_ASSERT(!child.inDictionary()); + + if (inDictionary()) { + Shape *oldShape = *listp; + PropertyTable *table = (oldShape && oldShape->hasTable()) ? oldShape->getTable() : NULL; + + /* + * Attempt to grow table if needed before extending *listp, rather than + * risking OOM under table->grow after newDictionaryShape succeeds, and + * then have to fix up *listp. + */ + if (table && table->needsToGrow() && !table->grow(cx)) + return NULL; + + if (newDictionaryShape(cx, child, listp)) { + Shape *newShape = *listp; + + JS_ASSERT(oldShape == newShape->parent); + if (table) { + /* Add newShape to the property table. */ + METER(searches); + Shape **spp = table->search(newShape->id, true); + + /* + * Beware duplicate formal parameters, allowed by ECMA-262 in + * non-strict mode. Otherwise we know that Bindings::add (our + * caller) won't pass an id already in the table to us. In the + * case of duplicate formals, the last one wins, so while we + * must not overcount entries, we must store newShape. + */ + if (!SHAPE_FETCH(spp)) + ++table->entryCount; + SHAPE_STORE_PRESERVING_COLLISION(spp, newShape); + + /* Hand the table off from oldShape to newShape. */ + oldShape->setTable(NULL); + newShape->setTable(table); + } else { + if (!newShape->hasTable()) + newShape->hashify(cx->runtime); + } + return newShape; + } + + return NULL; + } + + if ((*listp)->entryCount() >= PropertyTree::MAX_HEIGHT) { + Shape *dprop = Shape::newDictionaryList(cx, listp); + if (!dprop) + return NULL; + return dprop->getChild(cx, child, listp); + } + + Shape *shape = JS_PROPERTY_TREE(cx).getChild(cx, this, child); + if (shape) { + JS_ASSERT(shape->parent == this); + JS_ASSERT(this == *listp); + *listp = shape; + } + return shape; +} + +/* + * Get or create a property-tree or dictionary child property of parent, which + * must be lastProp if inDictionaryMode(), else parent must be one of lastProp + * or lastProp->parent. + */ +Shape * +JSObject::getChildProperty(JSContext *cx, Shape *parent, Shape &child) +{ + JS_ASSERT(!JSID_IS_VOID(child.id)); + JS_ASSERT(!child.inDictionary()); + + /* + * Aliases share another property's slot, passed in the |slot| parameter. + * Shared properties have no slot. Unshared properties that do not alias + * another property's slot allocate a slot here, but may lose it due to a + * JS_ClearScope call. + */ + if (!child.isAlias()) { + if (child.attrs & JSPROP_SHARED) { + child.slot = SHAPE_INVALID_SLOT; + } else { + /* + * We may have set slot from a nearly-matching shape, above. If so, + * we're overwriting that nearly-matching shape, so we can reuse + * its slot -- we don't need to allocate a new one. Similarly, we + * use a specific slot if provided by the caller. + */ + if (child.slot == SHAPE_INVALID_SLOT && !allocSlot(cx, &child.slot)) + return NULL; + } + } + + Shape *shape; + + if (inDictionaryMode()) { + JS_ASSERT(parent == lastProp); + if (parent->frozen()) { + parent = Shape::newDictionaryList(cx, &lastProp); + if (!parent) + return NULL; + JS_ASSERT(!parent->frozen()); + } + shape = Shape::newDictionaryShape(cx, child, &lastProp); + if (!shape) + return NULL; + } else { + shape = JS_PROPERTY_TREE(cx).getChild(cx, parent, child); + if (!shape) + return NULL; + JS_ASSERT(shape->parent == parent); + JS_ASSERT_IF(parent != lastProp, parent == lastProp->parent); + setLastProperty(shape); + } + + updateFlags(shape); + updateShape(cx); + return shape; +} + +Shape * +Shape::newDictionaryShape(JSContext *cx, const Shape &child, Shape **listp) +{ + Shape *dprop = JS_PROPERTY_TREE(cx).newShape(cx); + if (!dprop) + return NULL; + + new (dprop) Shape(child.id, child.rawGetter, child.rawSetter, child.slot, child.attrs, + (child.flags & ~FROZEN) | IN_DICTIONARY, child.shortid, + js_GenerateShape(cx), child.slotSpan); + + dprop->listp = NULL; + dprop->insertIntoDictionary(listp); + + JS_COMPARTMENT_METER(cx->compartment->liveDictModeNodes++); + return dprop; +} + +Shape * +Shape::newDictionaryList(JSContext *cx, Shape **listp) +{ + Shape *shape = *listp; + Shape *list = shape; + + Shape **childp = listp; + *childp = NULL; + + while (shape) { + JS_ASSERT_IF(!shape->frozen(), !shape->inDictionary()); + + Shape *dprop = Shape::newDictionaryShape(cx, *shape, childp); + if (!dprop) { + METER(toDictFails); + *listp = list; + return NULL; + } + + JS_ASSERT(!dprop->hasTable()); + childp = &dprop->parent; + shape = shape->parent; + } + + list = *listp; + JS_ASSERT(list->inDictionary()); + list->hashify(cx->runtime); + return list; +} + +bool +JSObject::toDictionaryMode(JSContext *cx) +{ + JS_ASSERT(!inDictionaryMode()); + if (!Shape::newDictionaryList(cx, &lastProp)) + return false; + + clearOwnShape(); + return true; +} + +/* + * Normalize stub getter and setter values for faster is-stub testing in the + * SHAPE_CALL_[GS]ETTER macros. + */ +static inline bool +NormalizeGetterAndSetter(JSContext *cx, JSObject *obj, + jsid id, uintN attrs, uintN flags, + PropertyOp &getter, + StrictPropertyOp &setter) +{ + if (setter == StrictPropertyStub) { + JS_ASSERT(!(attrs & JSPROP_SETTER)); + setter = NULL; + } + if (flags & Shape::METHOD) { + /* Here, getter is the method, a function object reference. */ + JS_ASSERT(getter); + JS_ASSERT(!setter || setter == js_watch_set); + JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); + } else { + if (getter == PropertyStub) { + JS_ASSERT(!(attrs & JSPROP_GETTER)); + getter = NULL; + } + } + + return true; +} + +#ifdef DEBUG +# define CHECK_SHAPE_CONSISTENCY(obj) obj->checkShapeConsistency() + +void +JSObject::checkShapeConsistency() +{ + static int throttle = -1; + if (throttle < 0) { + if (const char *var = getenv("JS_CHECK_SHAPE_THROTTLE")) + throttle = atoi(var); + if (throttle < 0) + throttle = 0; + } + if (throttle == 0) + return; + + JS_ASSERT(isNative()); + if (hasOwnShape()) + JS_ASSERT(objShape != lastProp->shape); + else + JS_ASSERT(objShape == lastProp->shape); + + Shape *shape = lastProp; + Shape *prev = NULL; + + if (inDictionaryMode()) { + if (shape->hasTable()) { + PropertyTable *table = shape->getTable(); + for (uint32 fslot = table->freelist; fslot != SHAPE_INVALID_SLOT; + fslot = getSlotRef(fslot).toPrivateUint32()) { + JS_ASSERT(fslot < shape->slotSpan); + } + + for (int n = throttle; --n >= 0 && shape->parent; shape = shape->parent) { + JS_ASSERT_IF(shape != lastProp, !shape->hasTable()); + + Shape **spp = table->search(shape->id, false); + JS_ASSERT(SHAPE_FETCH(spp) == shape); + } + } else { + shape = shape->parent; + for (int n = throttle; --n >= 0 && shape; shape = shape->parent) + JS_ASSERT(!shape->hasTable()); + } + + shape = lastProp; + for (int n = throttle; --n >= 0 && shape; shape = shape->parent) { + JS_ASSERT_IF(shape->slot != SHAPE_INVALID_SLOT, shape->slot < shape->slotSpan); + if (!prev) { + JS_ASSERT(shape == lastProp); + JS_ASSERT(shape->listp == &lastProp); + } else { + JS_ASSERT(shape->listp == &prev->parent); + JS_ASSERT(prev->slotSpan >= shape->slotSpan); + } + prev = shape; + } + } else { + for (int n = throttle; --n >= 0 && shape->parent; shape = shape->parent) { + if (shape->hasTable()) { + PropertyTable *table = shape->getTable(); + JS_ASSERT(shape->parent); + for (Shape::Range r(shape); !r.empty(); r.popFront()) { + Shape **spp = table->search(r.front().id, false); + JS_ASSERT(SHAPE_FETCH(spp) == &r.front()); + } + } + if (prev) { + JS_ASSERT(prev->slotSpan >= shape->slotSpan); + shape->kids.checkConsistency(prev); + } + prev = shape; + } + } +} +#else +# define CHECK_SHAPE_CONSISTENCY(obj) ((void)0) +#endif + +const Shape * +JSObject::addProperty(JSContext *cx, jsid id, + PropertyOp getter, StrictPropertyOp setter, + uint32 slot, uintN attrs, + uintN flags, intN shortid) +{ + JS_ASSERT(!JSID_IS_VOID(id)); + + if (!isExtensible()) { + reportNotExtensible(cx); + return NULL; + } + + NormalizeGetterAndSetter(cx, this, id, attrs, flags, getter, setter); + + /* Search for id with adding = true in order to claim its entry. */ + Shape **spp = nativeSearch(id, true); + JS_ASSERT(!SHAPE_FETCH(spp)); + const Shape *shape = addPropertyInternal(cx, id, getter, setter, slot, attrs, + flags, shortid, spp); + if (!shape) + return NULL; + + /* Update any watchpoints referring to this property. */ + shape = js_UpdateWatchpointsForShape(cx, this, shape); + if (!shape) + METER(wrapWatchFails); + + return shape; +} + +const Shape * +JSObject::addPropertyInternal(JSContext *cx, jsid id, + PropertyOp getter, StrictPropertyOp setter, + uint32 slot, uintN attrs, + uintN flags, intN shortid, + Shape **spp) +{ + JS_ASSERT_IF(inDictionaryMode(), !lastProp->frozen()); + + PropertyTable *table = NULL; + if (!inDictionaryMode()) { + if (lastProp->entryCount() >= PropertyTree::MAX_HEIGHT) { + if (!toDictionaryMode(cx)) + return NULL; + spp = nativeSearch(id, true); + table = lastProp->getTable(); + } + } else if (lastProp->hasTable()) { + table = lastProp->getTable(); + if (table->needsToGrow()) { + if (!table->grow(cx)) + return NULL; + + METER(searches); + METER(changeSearches); + spp = table->search(id, true); + JS_ASSERT(!SHAPE_FETCH(spp)); + } + } + + /* Find or create a property tree node labeled by our arguments. */ + const Shape *shape; + { + Shape child(id, getter, setter, slot, attrs, flags, shortid); + shape = getChildProperty(cx, lastProp, child); + } + + if (shape) { + JS_ASSERT(shape == lastProp); + + if (table) { + /* Store the tree node pointer in the table entry for id. */ + SHAPE_STORE_PRESERVING_COLLISION(spp, shape); + ++table->entryCount; + + /* Pass the table along to the new lastProp, namely shape. */ + JS_ASSERT(shape->parent->getTable() == table); + shape->parent->setTable(NULL); + shape->setTable(table); + } +#ifdef DEBUG + LIVE_SCOPE_METER(cx, ++cx->runtime->liveObjectProps); +#endif + CHECK_SHAPE_CONSISTENCY(this); + METER(adds); + return shape; + } + + CHECK_SHAPE_CONSISTENCY(this); + METER(addFails); + return NULL; +} + +/* + * Check and adjust the new attributes for the shape to make sure that our + * slot access optimizations are sound. It is responsibility of the callers to + * enforce all restrictions from ECMA-262 v5 8.12.9 [[DefineOwnProperty]]. + */ +inline bool +CheckCanChangeAttrs(JSContext *cx, JSObject *obj, const Shape *shape, uintN *attrsp) +{ + if (shape->configurable()) + return true; + + /* A permanent property must stay permanent. */ + *attrsp |= JSPROP_PERMANENT; + + /* Reject attempts to remove a slot from the permanent data property. */ + if (shape->isDataDescriptor() && shape->hasSlot() && + (*attrsp & (JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED))) { + obj->reportNotConfigurable(cx, shape->id); + return false; + } + + return true; +} + +const Shape * +JSObject::putProperty(JSContext *cx, jsid id, + PropertyOp getter, StrictPropertyOp setter, + uint32 slot, uintN attrs, + uintN flags, intN shortid) +{ + JS_ASSERT(!JSID_IS_VOID(id)); + + /* + * Horrid non-strict eval, debuggers, and |default xml namespace ...| may + * extend Call objects. + */ + if (lastProp->frozen()) { + if (!Shape::newDictionaryList(cx, &lastProp)) + return NULL; + JS_ASSERT(!lastProp->frozen()); + } + + NormalizeGetterAndSetter(cx, this, id, attrs, flags, getter, setter); + + /* Search for id in order to claim its entry if table has been allocated. */ + Shape **spp = nativeSearch(id, true); + Shape *shape = SHAPE_FETCH(spp); + if (!shape) { + /* + * You can't add properties to a non-extensible object, but you can change + * attributes of properties in such objects. + */ + if (!isExtensible()) { + reportNotExtensible(cx); + return NULL; + } + + const Shape *newShape = + addPropertyInternal(cx, id, getter, setter, slot, attrs, flags, shortid, spp); + if (!newShape) + return NULL; + newShape = js_UpdateWatchpointsForShape(cx, this, newShape); + if (!newShape) + METER(wrapWatchFails); + return newShape; + } + + /* Property exists: search must have returned a valid *spp. */ + JS_ASSERT(!SHAPE_IS_REMOVED(*spp)); + + if (!CheckCanChangeAttrs(cx, this, shape, &attrs)) + return NULL; + + /* + * If the caller wants to allocate a slot, but doesn't care which slot, + * copy the existing shape's slot into slot so we can match shape, if all + * other members match. + */ + bool hadSlot = !shape->isAlias() && shape->hasSlot(); + uint32 oldSlot = shape->slot; + if (!(attrs & JSPROP_SHARED) && slot == SHAPE_INVALID_SLOT && hadSlot) + slot = oldSlot; + + /* + * Now that we've possibly preserved slot, check whether all members match. + * If so, this is a redundant "put" and we can return without more work. + */ + if (shape->matchesParamsAfterId(getter, setter, slot, attrs, flags, shortid)) { + METER(redundantPuts); + return shape; + } + + /* + * Overwriting a non-last property requires switching to dictionary mode. + * The shape tree is shared immutable, and we can't removeProperty and then + * addPropertyInternal because a failure under add would lose data. + */ + if (shape != lastProp && !inDictionaryMode()) { + if (!toDictionaryMode(cx)) + return NULL; + spp = nativeSearch(shape->id); + shape = SHAPE_FETCH(spp); + } + + /* + * Now that we have passed the lastProp->frozen() check at the top of this + * method, and the non-last-property conditioning just above, we are ready + * to overwrite. + * + * Optimize the case of a non-frozen dictionary-mode object based on the + * property that dictionaries exclusively own their mutable shape structs, + * each of which has a unique shape number (not shared via a shape tree). + * + * This is more than an optimization: it is required to preserve for-in + * enumeration order (see bug 601399). + */ + if (inDictionaryMode()) { + /* FIXME bug 593129 -- slot allocation and JSObject *this must move out of here! */ + if (slot == SHAPE_INVALID_SLOT && !(attrs & JSPROP_SHARED) && !(flags & Shape::ALIAS)) { + if (!allocSlot(cx, &slot)) + return NULL; + } + + shape->slot = slot; + if (slot != SHAPE_INVALID_SLOT && slot >= shape->slotSpan) { + shape->slotSpan = slot + 1; + + for (Shape *temp = lastProp; temp != shape; temp = temp->parent) { + if (temp->slotSpan <= slot) + temp->slotSpan = slot + 1; + } + } + + shape->rawGetter = getter; + shape->rawSetter = setter; + shape->attrs = uint8(attrs); + shape->flags = flags | Shape::IN_DICTIONARY; + shape->shortid = int16(shortid); + + /* + * We are done updating shape and lastProp. Now we may need to update + * flags and we will need to update objShape, which is no longer "own". + * In the last non-dictionary property case in the else clause just + * below, getChildProperty handles this for us. First update flags. + */ + updateFlags(shape); + + /* + * We have just mutated shape in place, but nothing caches it based on + * shape->shape unless shape is lastProp and !hasOwnShape()). Therefore + * we regenerate only lastProp->shape. We will clearOwnShape(), which + * sets objShape to lastProp->shape. + */ + lastProp->shape = js_GenerateShape(cx); + clearOwnShape(); + } else { + /* + * Updating lastProp in a non-dictionary-mode object. Such objects + * share their shapes via a tree rooted at a prototype emptyShape, or + * perhaps a well-known compartment-wide singleton emptyShape. + * + * If any shape in the tree has a property hashtable, it is shared and + * immutable too, therefore we must not update *spp. + */ + JS_ASSERT(shape == lastProp); + removeLastProperty(); + + /* Find or create a property tree node labeled by our arguments. */ + Shape child(id, getter, setter, slot, attrs, flags, shortid); + + Shape *newShape = getChildProperty(cx, lastProp, child); + if (!newShape) { + setLastProperty(shape); + CHECK_SHAPE_CONSISTENCY(this); + METER(putFails); + return NULL; + } + + shape = newShape; + } + + /* + * Can't fail now, so free the previous incarnation's slot if the new shape + * has no slot. But we do not need to free oldSlot (and must not, as trying + * to will botch an assertion in JSObject::freeSlot) if the new lastProp + * (shape here) has a slotSpan that does not cover it. + */ + if (hadSlot && !shape->hasSlot()) { + if (oldSlot < shape->slotSpan) + freeSlot(cx, oldSlot); +#ifdef DEBUG + else + getSlotRef(oldSlot).setUndefined(); +#endif + JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals); + } + + CHECK_SHAPE_CONSISTENCY(this); + METER(puts); + + const Shape *newShape = js_UpdateWatchpointsForShape(cx, this, shape); + if (!newShape) + METER(wrapWatchFails); + return newShape; +} + +const Shape * +JSObject::changeProperty(JSContext *cx, const Shape *shape, uintN attrs, uintN mask, + PropertyOp getter, StrictPropertyOp setter) +{ + JS_ASSERT_IF(inDictionaryMode(), !lastProp->frozen()); + JS_ASSERT(!JSID_IS_VOID(shape->id)); + JS_ASSERT(nativeContains(*shape)); + + attrs |= shape->attrs & mask; + + /* Allow only shared (slotless) => unshared (slotful) transition. */ + JS_ASSERT(!((attrs ^ shape->attrs) & JSPROP_SHARED) || + !(attrs & JSPROP_SHARED)); + + /* Don't allow method properties to be changed to have a getter. */ + JS_ASSERT_IF(getter != shape->rawGetter, !shape->isMethod()); + + if (getter == PropertyStub) + getter = NULL; + if (setter == StrictPropertyStub) + setter = NULL; + + if (!CheckCanChangeAttrs(cx, this, shape, &attrs)) + return NULL; + + if (shape->attrs == attrs && shape->getter() == getter && shape->setter() == setter) + return shape; + + const Shape *newShape; + + /* + * Dictionary-mode objects exclusively own their mutable shape structs, so + * we simply modify in place. + */ + if (inDictionaryMode()) { + /* FIXME bug 593129 -- slot allocation and JSObject *this must move out of here! */ + uint32 slot = shape->slot; + if (slot == SHAPE_INVALID_SLOT && !(attrs & JSPROP_SHARED) && !(flags & Shape::ALIAS)) { + if (!allocSlot(cx, &slot)) + return NULL; + } + + Shape *mutableShape = const_cast(shape); + mutableShape->slot = slot; + if (slot != SHAPE_INVALID_SLOT && slot >= shape->slotSpan) { + mutableShape->slotSpan = slot + 1; + + for (Shape *temp = lastProp; temp != shape; temp = temp->parent) { + if (temp->slotSpan <= slot) + temp->slotSpan = slot + 1; + } + } + + mutableShape->rawGetter = getter; + mutableShape->rawSetter = setter; + mutableShape->attrs = uint8(attrs); + + updateFlags(shape); + + /* See the corresponding code in putProperty. */ + lastProp->shape = js_GenerateShape(cx); + clearOwnShape(); + + shape = js_UpdateWatchpointsForShape(cx, this, shape); + if (!shape) { + METER(wrapWatchFails); + return NULL; + } + JS_ASSERT(shape == mutableShape); + newShape = mutableShape; + } else if (shape == lastProp) { + Shape child(shape->id, getter, setter, shape->slot, attrs, shape->flags, shape->shortid); + + newShape = getChildProperty(cx, shape->parent, child); +#ifdef DEBUG + if (newShape) { + JS_ASSERT(newShape == lastProp); + if (newShape->hasTable()) { + Shape **spp = nativeSearch(shape->id); + JS_ASSERT(SHAPE_FETCH(spp) == newShape); + } + } +#endif + } else { + /* + * Let JSObject::putProperty handle this |overwriting| case, including + * the conservation of shape->slot (if it's valid). We must not call + * removeProperty because it will free an allocated shape->slot, and + * putProperty won't re-allocate it. + */ + Shape child(shape->id, getter, setter, shape->slot, attrs, shape->flags, shape->shortid); + newShape = putProperty(cx, child.id, child.rawGetter, child.rawSetter, child.slot, + child.attrs, child.flags, child.shortid); +#ifdef DEBUG + if (newShape) + METER(changePuts); +#endif + } + +#ifdef DEBUG + CHECK_SHAPE_CONSISTENCY(this); + if (newShape) + METER(changes); + else + METER(changeFails); +#endif + return newShape; +} + +bool +JSObject::removeProperty(JSContext *cx, jsid id) +{ + Shape **spp = nativeSearch(id); + Shape *shape = SHAPE_FETCH(spp); + if (!shape) { + METER(uselessRemoves); + return true; + } + + /* First, if shape is unshared and not has a slot, free its slot number. */ + bool addedToFreelist = false; + bool hadSlot = !shape->isAlias() && shape->hasSlot(); + if (hadSlot) { + addedToFreelist = freeSlot(cx, shape->slot); + JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals); + } + + + /* If shape is not the last property added, switch to dictionary mode. */ + if (shape != lastProp && !inDictionaryMode()) { + if (!toDictionaryMode(cx)) + return false; + spp = nativeSearch(shape->id); + shape = SHAPE_FETCH(spp); + } + + /* + * A dictionary-mode object owns mutable, unique shapes on a non-circular + * doubly linked list, optionally hashed by lastProp->table. So we can edit + * the list and hash in place. + */ + if (inDictionaryMode()) { + PropertyTable *table = lastProp->hasTable() ? lastProp->getTable() : NULL; + + if (SHAPE_HAD_COLLISION(*spp)) { + JS_ASSERT(table); + *spp = SHAPE_REMOVED; + ++table->removedCount; + --table->entryCount; + } else { + METER(removeFrees); + if (table) { + *spp = NULL; + --table->entryCount; + +#ifdef DEBUG + /* + * Check the consistency of the table but limit the number of + * checks not to alter significantly the complexity of the + * delete in debug builds, see bug 534493. + */ + const Shape *aprop = lastProp; + for (int n = 50; --n >= 0 && aprop->parent; aprop = aprop->parent) + JS_ASSERT_IF(aprop != shape, nativeContains(*aprop)); +#endif + } + } + + /* + * Remove shape from its non-circular doubly linked list, setting this + * object's OWN_SHAPE flag so the updateShape(cx) further below will + * generate a fresh shape id for this object, distinct from the id of + * any shape in the list. We need a fresh shape for all deletions, even + * of lastProp. Otherwise, a shape number could replay and caches might + * return get deleted DictionaryShapes! See bug 595365. + */ + flags |= OWN_SHAPE; + + Shape *oldLastProp = lastProp; + shape->removeFromDictionary(this); + if (table) { + if (shape == oldLastProp) { + JS_ASSERT(shape->getTable() == table); + JS_ASSERT(shape->parent == lastProp); + JS_ASSERT(shape->slotSpan >= lastProp->slotSpan); + JS_ASSERT_IF(hadSlot, shape->slot + 1 <= shape->slotSpan); + + /* + * Maintain slot freelist consistency. The only constraint we + * have is that slot numbers on the freelist are less than + * lastProp->slotSpan. Thus, if the freelist is non-empty, + * then lastProp->slotSpan may not decrease. + */ + if (table->freelist != SHAPE_INVALID_SLOT) { + lastProp->slotSpan = shape->slotSpan; + + /* Add the slot to the freelist if it wasn't added in freeSlot. */ + if (hadSlot && !addedToFreelist) { + getSlotRef(shape->slot).setPrivateUint32(table->freelist); + table->freelist = shape->slot; + } + } + } + + /* Hand off table from old to new lastProp. */ + oldLastProp->setTable(NULL); + lastProp->setTable(table); + } + } else { + /* + * Non-dictionary-mode property tables are shared immutables, so all we + * need do is retract lastProp and we'll either get or else lazily make + * via a later hashify the exact table for the new property lineage. + */ + JS_ASSERT(shape == lastProp); + removeLastProperty(); + + /* + * Revert to fixed slots if this was the first dynamically allocated slot, + * preserving invariant that objects with the same shape use the fixed + * slots in the same way. + */ + size_t fixed = numFixedSlots(); + if (shape->slot == fixed) { + JS_ASSERT_IF(!lastProp->isEmptyShape() && lastProp->hasSlot(), + lastProp->slot == fixed - 1); + revertToFixedSlots(cx); + } + } + updateShape(cx); + + /* On the way out, consider shrinking table if its load factor is <= .25. */ + if (lastProp->hasTable()) { + PropertyTable *table = lastProp->getTable(); + uint32 size = table->capacity(); + if (size > PropertyTable::MIN_SIZE && table->entryCount <= size >> 2) { + METER(shrinks); + (void) table->change(-1, cx); + } + } + + CHECK_SHAPE_CONSISTENCY(this); + LIVE_SCOPE_METER(cx, --cx->runtime->liveObjectProps); + METER(removes); + return true; +} + +void +JSObject::clear(JSContext *cx) +{ + LIVE_SCOPE_METER(cx, cx->runtime->liveObjectProps -= propertyCount()); + + Shape *shape = lastProp; + JS_ASSERT(inDictionaryMode() == shape->inDictionary()); + + while (shape->parent) { + shape = shape->parent; + JS_ASSERT(inDictionaryMode() == shape->inDictionary()); + } + JS_ASSERT(shape->isEmptyShape()); + + if (inDictionaryMode()) + shape->listp = &lastProp; + + /* + * Revert to fixed slots if we have cleared below the first dynamically + * allocated slot, preserving invariant that objects with the same shape + * use the fixed slots in the same way. + */ + if (hasSlotsArray() && JSSLOT_FREE(getClass()) <= numFixedSlots()) + revertToFixedSlots(cx); + + /* + * We have rewound to a uniquely-shaped empty scope, so we don't need an + * override for this object's shape. + */ + clearOwnShape(); + setMap(shape); + + LeaveTraceIfGlobalObject(cx, this); + JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals); + CHECK_SHAPE_CONSISTENCY(this); +} + +void +JSObject::generateOwnShape(JSContext *cx) +{ +#ifdef JS_TRACER + JS_ASSERT_IF(!parent && JS_ON_TRACE(cx), JS_TRACE_MONITOR_ON_TRACE(cx)->bailExit); + LeaveTraceIfGlobalObject(cx, this); + + /* + * If we are recording, here is where we forget already-guarded shapes. + * Any subsequent property operation upon object on the trace currently + * being recorded will re-guard (and re-memoize). + */ + if (TraceRecorder *tr = TRACE_RECORDER(cx)) + tr->forgetGuardedShapesForObject(this); +#endif + + setOwnShape(js_GenerateShape(cx)); +} + +void +JSObject::deletingShapeChange(JSContext *cx, const Shape &shape) +{ + JS_ASSERT(!JSID_IS_VOID(shape.id)); + generateOwnShape(cx); +} + +const Shape * +JSObject::methodShapeChange(JSContext *cx, const Shape &shape) +{ + const Shape *result = &shape; + + JS_ASSERT(!JSID_IS_VOID(shape.id)); + if (shape.isMethod()) { +#ifdef DEBUG + const Value &prev = nativeGetSlot(shape.slot); + JS_ASSERT(&shape.methodObject() == &prev.toObject()); + JS_ASSERT(canHaveMethodBarrier()); + JS_ASSERT(hasMethodBarrier()); + JS_ASSERT(!shape.rawSetter || shape.rawSetter == js_watch_set); +#endif + + /* + * Pass null to make a stub getter, but pass along shape.rawSetter to + * preserve watchpoints. Clear Shape::METHOD from flags as we are + * despecializing from a method memoized in the property tree to a + * plain old function-valued property. + */ + result = putProperty(cx, shape.id, NULL, shape.rawSetter, shape.slot, + shape.attrs, + shape.getFlags() & ~Shape::METHOD, + shape.shortid); + if (!result) + return NULL; + } + + if (branded()) { + uintN thrashCount = getMethodThrashCount(); + if (thrashCount < JSObject::METHOD_THRASH_COUNT_MAX) { + ++thrashCount; + setMethodThrashCount(thrashCount); + if (thrashCount == JSObject::METHOD_THRASH_COUNT_MAX) { + unbrand(cx); + return result; + } + } + } + + generateOwnShape(cx); + return result; +} + +bool +JSObject::methodShapeChange(JSContext *cx, uint32 slot) +{ + if (!hasMethodBarrier()) { + generateOwnShape(cx); + } else { + for (Shape::Range r = lastProp->all(); !r.empty(); r.popFront()) { + const Shape &shape = r.front(); + JS_ASSERT(!JSID_IS_VOID(shape.id)); + if (shape.slot == slot) + return methodShapeChange(cx, shape) != NULL; + } + } + return true; +} + +void +JSObject::protoShapeChange(JSContext *cx) +{ + generateOwnShape(cx); +} + +void +JSObject::shadowingShapeChange(JSContext *cx, const Shape &shape) +{ + JS_ASSERT(!JSID_IS_VOID(shape.id)); + generateOwnShape(cx); +} + +bool +JSObject::globalObjectOwnShapeChange(JSContext *cx) +{ + generateOwnShape(cx); + return !js_IsPropertyCacheDisabled(cx); +} + +#ifdef DEBUG +static void +PrintPropertyGetterOrSetter(JSTracer *trc, char *buf, size_t bufsize) +{ + Shape *shape; + jsid id; + size_t n; + const char *name; + + JS_ASSERT(trc->debugPrinter == PrintPropertyGetterOrSetter); + shape = (Shape *)trc->debugPrintArg; + id = shape->id; + JS_ASSERT(!JSID_IS_VOID(id)); + name = trc->debugPrintIndex ? js_setter_str : js_getter_str; + + if (JSID_IS_ATOM(id)) { + n = PutEscapedString(buf, bufsize, JSID_TO_ATOM(id), 0); + if (n < bufsize) + JS_snprintf(buf + n, bufsize - n, " %s", name); + } else if (JSID_IS_INT(shape->id)) { + JS_snprintf(buf, bufsize, "%d %s", JSID_TO_INT(id), name); + } else { + JS_snprintf(buf, bufsize, " %s", name); + } +} + +static void +PrintPropertyMethod(JSTracer *trc, char *buf, size_t bufsize) +{ + Shape *shape; + jsid id; + size_t n; + + JS_ASSERT(trc->debugPrinter == PrintPropertyMethod); + shape = (Shape *)trc->debugPrintArg; + id = shape->id; + JS_ASSERT(!JSID_IS_VOID(id)); + + JS_ASSERT(JSID_IS_ATOM(id)); + n = PutEscapedString(buf, bufsize, JSID_TO_ATOM(id), 0); + if (n < bufsize) + JS_snprintf(buf + n, bufsize - n, " method"); +} +#endif + +void +Shape::trace(JSTracer *trc) const +{ + if (IS_GC_MARKING_TRACER(trc)) + mark(); + + MarkId(trc, id, "id"); + + if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) { + if ((attrs & JSPROP_GETTER) && rawGetter) { + JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, this, 0); + Mark(trc, getterObject()); + } + if ((attrs & JSPROP_SETTER) && rawSetter) { + JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, this, 1); + Mark(trc, setterObject()); + } + } + + if (isMethod()) { + JS_SET_TRACING_DETAILS(trc, PrintPropertyMethod, this, 0); + Mark(trc, &methodObject()); + } +} diff --git a/js/src/jsscope.h b/js/src/jsscope.h new file mode 100644 index 0000000..99aefa1 --- /dev/null +++ b/js/src/jsscope.h @@ -0,0 +1,924 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsscope_h___ +#define jsscope_h___ +/* + * JS symbol tables. + */ +#include +#ifdef DEBUG +#include +#endif + +#include "jstypes.h" +#include "jscntxt.h" +#include "jscompartment.h" +#include "jshashtable.h" +#include "jsobj.h" +#include "jsprvtd.h" +#include "jspubtd.h" +#include "jspropertytree.h" +#include "jsstrinlines.h" + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4800) +#pragma warning(push) +#pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */ +#endif + +/* + * Given P independent, non-unique properties each of size S words mapped by + * all scopes in a runtime, construct a property tree of N nodes each of size + * S+L words (L for tree linkage). A nominal L value is 2 for leftmost-child + * and right-sibling links. We hope that the N < P by enough that the space + * overhead of L, and the overhead of scope entries pointing at property tree + * nodes, is worth it. + * + * The tree construction goes as follows. If any empty scope in the runtime + * has a property X added to it, find or create a node under the tree root + * labeled X, and set obj->lastProp to point at that node. If any non-empty + * scope whose most recently added property is labeled Y has another property + * labeled Z added, find or create a node for Z under the node that was added + * for Y, and set obj->lastProp to point at that node. + * + * A property is labeled by its members' values: id, getter, setter, slot, + * attributes, tiny or short id, and a field telling for..in order. Note that + * labels are not unique in the tree, but they are unique among a node's kids + * (barring rare and benign multi-threaded race condition outcomes, see below) + * and along any ancestor line from the tree root to a given leaf node (except + * for the hard case of duplicate formal parameters to a function). + * + * Thus the root of the tree represents all empty scopes, and the first ply + * of the tree represents all scopes containing one property, etc. Each node + * in the tree can stand for any number of scopes having the same ordered set + * of properties, where that node was the last added to the scope. (We need + * not store the root of the tree as a node, and do not -- all we need are + * links to its kids.) + * + * Sidebar on for..in loop order: ECMA requires no particular order, but this + * implementation has promised and delivered property definition order, and + * compatibility is king. We could use an order number per property, which + * would require a sort in js_Enumerate, and an entry order generation number + * per scope. An order number beats a list, which should be doubly-linked for + * O(1) delete. An even better scheme is to use a parent link in the property + * tree, so that the ancestor line can be iterated from obj->lastProp when + * filling in a JSIdArray from back to front. This parent link also helps the + * GC to sweep properties iteratively. + * + * What if a property Y is deleted from a scope? If Y is the last property in + * the scope, we simply adjust the scope's lastProp member after we remove the + * scope's hash-table entry pointing at that property node. The parent link + * mentioned in the for..in sidebar above makes this adjustment O(1). But if + * Y comes between X and Z in the scope, then we might have to "fork" the tree + * at X, leaving X->Y->Z in case other scopes have those properties added in + * that order; and to finish the fork, we'd add a node labeled Z with the path + * X->Z, if it doesn't exist. This could lead to lots of extra nodes, and to + * O(n^2) growth when deleting lots of properties. + * + * Rather, for O(1) growth all around, we should share the path X->Y->Z among + * scopes having those three properties added in that order, and among scopes + * having only X->Z where Y was deleted. All such scopes have a lastProp that + * points to the Z child of Y. But a scope in which Y was deleted does not + * have a table entry for Y, and when iterating that scope by traversing the + * ancestor line from Z, we will have to test for a table entry for each node, + * skipping nodes that lack entries. + * + * What if we add Y again? X->Y->Z->Y is wrong and we'll enumerate Y twice. + * Therefore we must fork in such a case if not earlier, or do something else. + * We used to fork on the theory that set after delete is rare, but the Web is + * a harsh mistress, and we now convert the scope to a "dictionary" on first + * delete, to avoid O(n^2) growth in the property tree. + * + * What about thread safety? If the property tree operations done by requests + * are find-node and insert-node, then the only hazard is duplicate insertion. + * This is harmless except for minor bloat. When all requests have ended or + * been suspended, the GC is free to sweep the tree after marking all nodes + * reachable from scopes, performing remove-node operations as needed. + * + * Is the property tree worth it compared to property storage in each table's + * entries? To decide, we must find the relation <> between the words used + * with a property tree and the words required without a tree. + * + * Model all scopes as one super-scope of capacity T entries (T a power of 2). + * Let alpha be the load factor of this double hash-table. With the property + * tree, each entry in the table is a word-sized pointer to a node that can be + * shared by many scopes. But all such pointers are overhead compared to the + * situation without the property tree, where the table stores property nodes + * directly, as entries each of size S words. With the property tree, we need + * L=2 extra words per node for siblings and kids pointers. Without the tree, + * (1-alpha)*S*T words are wasted on free or removed sentinel-entries required + * by double hashing. + * + * Therefore, + * + * (property tree) <> (no property tree) + * N*(S+L) + T <> S*T + * N*(S+L) + T <> P*S + (1-alpha)*S*T + * N*(S+L) + alpha*T + (1-alpha)*T <> P*S + (1-alpha)*S*T + * + * Note that P is alpha*T by definition, so + * + * N*(S+L) + P + (1-alpha)*T <> P*S + (1-alpha)*S*T + * N*(S+L) <> P*S - P + (1-alpha)*S*T - (1-alpha)*T + * N*(S+L) <> (P + (1-alpha)*T) * (S-1) + * N*(S+L) <> (P + (1-alpha)*P/alpha) * (S-1) + * N*(S+L) <> P * (1/alpha) * (S-1) + * + * Let N = P*beta for a compression ratio beta, beta <= 1: + * + * P*beta*(S+L) <> P * (1/alpha) * (S-1) + * beta*(S+L) <> (S-1)/alpha + * beta <> (S-1)/((S+L)*alpha) + * + * For S = 6 (32-bit architectures) and L = 2, the property tree wins iff + * + * beta < 5/(8*alpha) + * + * We ensure that alpha <= .75, so the property tree wins if beta < .83_. An + * average beta from recent Mozilla browser startups was around .6. + * + * Can we reduce L? Observe that the property tree degenerates into a list of + * lists if at most one property Y follows X in all scopes. In or near such a + * case, we waste a word on the right-sibling link outside of the root ply of + * the tree. Note also that the root ply tends to be large, so O(n^2) growth + * searching it is likely, indicating the need for hashing (but with increased + * thread safety costs). + * + * If only K out of N nodes in the property tree have more than one child, we + * could eliminate the sibling link and overlay a children list or hash-table + * pointer on the leftmost-child link (which would then be either null or an + * only-child link; the overlay could be tagged in the low bit of the pointer, + * or flagged elsewhere in the property tree node, although such a flag must + * not be considered when comparing node labels during tree search). + * + * For such a system, L = 1 + (K * averageChildrenTableSize) / N instead of 2. + * If K << N, L approaches 1 and the property tree wins if beta < .95. + * + * We observe that fan-out below the root ply of the property tree appears to + * have extremely low degree (see the MeterPropertyTree code that histograms + * child-counts in jsscope.c), so instead of a hash-table we use a linked list + * of child node pointer arrays ("kid chunks"). The details are isolated in + * jspropertytree.h/.cpp; others must treat js::Shape.kids as opaque. + * + * One final twist (can you stand it?): the vast majority (~95% or more) of + * scopes are looked up fewer than three times; in these cases, initializing + * scope->table isn't worth it. So instead of always allocating scope->table, + * we leave it null while initializing all the other scope members as if it + * were non-null and minimal-length. Until a scope is searched + * MAX_LINEAR_SEARCHES times, we use linear search from obj->lastProp to find a + * given id, and save on the time and space overhead of creating a hash table. + */ + +#define SHAPE_INVALID_SLOT 0xffffffff + +namespace js { + +/* + * Shapes use multiplicative hashing, _a la_ jsdhash.[ch], but specialized to + * minimize footprint. But if a Shape lineage has been searched fewer than + * MAX_LINEAR_SEARCHES times, we use linear search and avoid allocating + * scope->table. + */ +struct PropertyTable { + static const uint32 MAX_LINEAR_SEARCHES = 7; + static const uint32 MIN_SIZE_LOG2 = 4; + static const uint32 MIN_SIZE = JS_BIT(MIN_SIZE_LOG2); + + int hashShift; /* multiplicative hash shift */ + + uint32 entryCount; /* number of entries in table */ + uint32 removedCount; /* removed entry sentinels in table */ + uint32 freelist; /* SHAPE_INVALID_SLOT or head of slot + freelist in owning dictionary-mode + object */ + js::Shape **entries; /* table of ptrs to shared tree nodes */ + + PropertyTable(uint32 nentries) + : hashShift(JS_DHASH_BITS - MIN_SIZE_LOG2), + entryCount(nentries), + removedCount(0), + freelist(SHAPE_INVALID_SLOT) + { + /* NB: entries is set by init, which must be called. */ + } + + ~PropertyTable() { + js_free(entries); + } + + /* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */ + uint32 capacity() const { return JS_BIT(JS_DHASH_BITS - hashShift); } + + /* Whether we need to grow. We want to do this if the load factor is >= 0.75 */ + bool needsToGrow() const { + uint32 size = capacity(); + return entryCount + removedCount >= size - (size >> 2); + } + + /* + * Try to grow the table. On failure, reports out of memory on cx + * and returns false. This will make any extant pointers into the + * table invalid. Don't call this unless needsToGrow() is true. + */ + bool grow(JSContext *cx); + + /* + * NB: init and change are fallible but do not report OOM, so callers can + * cope or ignore. They do however use JSRuntime's calloc method in order + * to update the malloc counter on success. + */ + bool init(JSRuntime *rt, js::Shape *lastProp); + bool change(int log2Delta, JSContext *cx); + js::Shape **search(jsid id, bool adding); +}; + +} /* namespace js */ + +struct JSObject; + +namespace js { + +class PropertyTree; + +static inline PropertyOp +CastAsPropertyOp(js::Class *clasp) +{ + return JS_DATA_TO_FUNC_PTR(PropertyOp, clasp); +} + +/* + * Reuse the API-only JSPROP_INDEX attribute to mean shadowability. + */ +#define JSPROP_SHADOWABLE JSPROP_INDEX + +struct Shape : public JSObjectMap +{ + friend struct ::JSObject; + friend struct ::JSFunction; + friend class js::PropertyTree; + friend class js::Bindings; + friend bool IsShapeAboutToBeFinalized(JSContext *cx, const js::Shape *shape); + + /* + * numLinearSearches starts at zero and is incremented initially on each + * search() call. Once numLinearSearches reaches MAX_LINEAR_SEARCHES + * (which is a small integer), the table is created on the next search() + * call, and the table pointer will be easily distinguishable from a small + * integer. The table can also be created when hashifying for dictionary + * mode. + */ + union { + mutable size_t numLinearSearches; + mutable js::PropertyTable *table; + }; + + public: + inline void freeTable(JSContext *cx); + + static bool initEmptyShapes(JSCompartment *comp); + static void finishEmptyShapes(JSCompartment *comp); + + jsid id; + +#ifdef DEBUG + JSCompartment *compartment; +#endif + + protected: + union { + js::PropertyOp rawGetter; /* getter and setter hooks or objects */ + JSObject *getterObj; /* user-defined callable "get" object or + null if shape->hasGetterValue(); or + joined function object if METHOD flag + is set. */ + js::Class *clasp; /* prototype class for empty scope */ + }; + + union { + js::StrictPropertyOp rawSetter;/* getter is JSObject* and setter is 0 + if shape->isMethod() */ + JSObject *setterObj; /* user-defined callable "set" object or + null if shape->hasSetterValue() */ + }; + + public: + uint32 slot; /* abstract index in object slots */ + private: + uint8 attrs; /* attributes, see jsapi.h JSPROP_* */ + mutable uint8 flags; /* flags, see below for defines */ + public: + int16 shortid; /* tinyid, or local arg/var index */ + + protected: + mutable js::Shape *parent; /* parent node, reverse for..in order */ + union { + mutable js::KidsPointer kids; /* null, single child, or a tagged ptr + to many-kids data structure */ + mutable js::Shape **listp; /* dictionary list starting at lastProp + has a double-indirect back pointer, + either to shape->parent if not last, + else to obj->lastProp */ + }; + + static inline js::Shape **search(JSRuntime *rt, js::Shape **startp, jsid id, + bool adding = false); + static js::Shape *newDictionaryShape(JSContext *cx, const js::Shape &child, js::Shape **listp); + static js::Shape *newDictionaryList(JSContext *cx, js::Shape **listp); + + inline void removeFromDictionary(JSObject *obj) const; + inline void insertIntoDictionary(js::Shape **dictp); + + js::Shape *getChild(JSContext *cx, const js::Shape &child, js::Shape **listp); + + bool hashify(JSRuntime *rt); + + bool hasTable() const { + /* A valid pointer should be much bigger than MAX_LINEAR_SEARCHES. */ + return numLinearSearches > PropertyTable::MAX_LINEAR_SEARCHES; + } + + js::PropertyTable *getTable() const { + JS_ASSERT(hasTable()); + return table; + } + + void setTable(js::PropertyTable *t) const { + JS_ASSERT_IF(t && t->freelist != SHAPE_INVALID_SLOT, t->freelist < slotSpan); + table = t; + } + + /* + * Setter for parent. The challenge is to maintain JSObjectMap::slotSpan in + * the face of arbitrary slot order. + * + * By induction, an empty shape has a slotSpan member correctly computed as + * JSCLASS_FREE(clasp) -- see EmptyShape's constructor in jsscopeinlines.h. + * This is the basis case, where p is null. + * + * Any child shape, whether in a shape tree or in a dictionary list, must + * have a slotSpan either one greater than its slot value (if the child's + * slot is SHAPE_INVALID_SLOT, this will yield 0; the static assertion + * below enforces this), or equal to its parent p's slotSpan, whichever is + * greater. This is the inductive step. + * + * If we maintained shape paths such that parent slot was always one less + * than child slot, possibly with an exception for SHAPE_INVALID_SLOT slot + * values where we would use another way of computing slotSpan based on the + * PropertyTable (as JSC does), then we would not need to store slotSpan in + * Shape (to be precise, in its base struct, JSobjectMap). + * + * But we currently scramble slots along shape paths due to resolve-based + * creation of shapes mapping reserved slots, and we do not have the needed + * PropertyTable machinery to use as an alternative when parent slot is not + * one less than child slot. This machinery is neither simple nor free, as + * it must involve creating a table for any slot-less transition and then + * pinning the table to its shape. + * + * Use of 'delete' can scramble slots along the shape lineage too, although + * it always switches the target object to dictionary mode, so the cost of + * a pinned table is less onerous. + * + * Note that allocating a uint32 slotSpan member in JSObjectMap takes no + * net extra space on 64-bit targets (it packs with shape). And on 32-bit + * targets, adding slotSpan to JSObjectMap takes no gross extra space, + * because Shape rounds up to an even number of 32-bit words (required for + * GC-thing and js::Value allocation in any event) on 32-bit targets. + * + * So in terms of space, we can afford to maintain both slotSpan and slot, + * but it might be better if we eliminated slotSpan using slot combined + * with an auxiliary mechanism based on table. + */ + void setParent(js::Shape *p) { + JS_STATIC_ASSERT(uint32(SHAPE_INVALID_SLOT) == ~uint32(0)); + if (p) + slotSpan = JS_MAX(p->slotSpan, slot + 1); + JS_ASSERT(slotSpan < JSObject::NSLOTS_LIMIT); + parent = p; + } + + void insertFree(js::Shape **freep) { +#ifdef DEBUG + memset(this, JS_FREE_PATTERN, sizeof *this); +#endif + id = JSID_VOID; + parent = *freep; + if (parent) + parent->listp = &parent; + listp = freep; + *freep = this; + } + + void removeFree() { + JS_ASSERT(JSID_IS_VOID(id)); + *listp = parent; + if (parent) + parent->listp = listp; + } + + public: + const js::Shape *previous() const { + return parent; + } + + class Range { + protected: + friend struct Shape; + + const Shape *cursor; + const Shape *end; + + public: + Range(const Shape *shape) : cursor(shape) { } + + bool empty() const { + JS_ASSERT_IF(!cursor->parent, JSID_IS_EMPTY(cursor->id)); + return !cursor->parent; + } + + const Shape &front() const { + JS_ASSERT(!empty()); + return *cursor; + } + + void popFront() { + JS_ASSERT(!empty()); + cursor = cursor->parent; + } + }; + + Range all() const { + return Range(this); + } + + protected: + /* + * Implementation-private bits stored in shape->flags. See public: enum {} + * flags further below, which were allocated FCFS over time, so interleave + * with these bits. + */ + enum { + /* GC mark flag. */ + MARK = 0x01, + + SHARED_EMPTY = 0x02, + + /* + * Set during a shape-regenerating GC if the shape has already been + * regenerated. + */ + SHAPE_REGEN = 0x04, + + /* Property stored in per-object dictionary, not shared property tree. */ + IN_DICTIONARY = 0x08, + + /* Prevent unwanted mutation of shared Bindings::lastBinding nodes. */ + FROZEN = 0x10 + }; + + Shape(jsid id, js::PropertyOp getter, js::StrictPropertyOp setter, uint32 slot, uintN attrs, + uintN flags, intN shortid, uint32 shape = INVALID_SHAPE, uint32 slotSpan = 0); + + /* Used by EmptyShape (see jsscopeinlines.h). */ + Shape(JSCompartment *comp, Class *aclasp); + + bool marked() const { return (flags & MARK) != 0; } + void mark() const { flags |= MARK; } + void clearMark() { flags &= ~MARK; } + + bool hasRegenFlag() const { return (flags & SHAPE_REGEN) != 0; } + void setRegenFlag() { flags |= SHAPE_REGEN; } + void clearRegenFlag() { flags &= ~SHAPE_REGEN; } + + bool inDictionary() const { return (flags & IN_DICTIONARY) != 0; } + bool frozen() const { return (flags & FROZEN) != 0; } + void setFrozen() { flags |= FROZEN; } + + bool isEmptyShape() const { JS_ASSERT_IF(!parent, JSID_IS_EMPTY(id)); return !parent; } + + public: + /* Public bits stored in shape->flags. */ + enum { + ALIAS = 0x20, + HAS_SHORTID = 0x40, + METHOD = 0x80, + PUBLIC_FLAGS = ALIAS | HAS_SHORTID | METHOD + }; + + uintN getFlags() const { return flags & PUBLIC_FLAGS; } + bool isAlias() const { return (flags & ALIAS) != 0; } + bool hasShortID() const { return (flags & HAS_SHORTID) != 0; } + bool isMethod() const { return (flags & METHOD) != 0; } + + JSObject &methodObject() const { JS_ASSERT(isMethod()); return *getterObj; } + + js::PropertyOp getter() const { return rawGetter; } + bool hasDefaultGetter() const { return !rawGetter; } + js::PropertyOp getterOp() const { JS_ASSERT(!hasGetterValue()); return rawGetter; } + JSObject *getterObject() const { JS_ASSERT(hasGetterValue()); return getterObj; } + + // Per ES5, decode null getterObj as the undefined value, which encodes as null. + js::Value getterValue() const { + JS_ASSERT(hasGetterValue()); + return getterObj ? js::ObjectValue(*getterObj) : js::UndefinedValue(); + } + + js::Value getterOrUndefined() const { + return hasGetterValue() && getterObj ? js::ObjectValue(*getterObj) : js::UndefinedValue(); + } + + js::StrictPropertyOp setter() const { return rawSetter; } + bool hasDefaultSetter() const { return !rawSetter; } + js::StrictPropertyOp setterOp() const { JS_ASSERT(!hasSetterValue()); return rawSetter; } + JSObject *setterObject() const { JS_ASSERT(hasSetterValue()); return setterObj; } + + // Per ES5, decode null setterObj as the undefined value, which encodes as null. + js::Value setterValue() const { + JS_ASSERT(hasSetterValue()); + return setterObj ? js::ObjectValue(*setterObj) : js::UndefinedValue(); + } + + js::Value setterOrUndefined() const { + return hasSetterValue() && setterObj ? js::ObjectValue(*setterObj) : js::UndefinedValue(); + } + + inline JSDHashNumber hash() const; + inline bool matches(const js::Shape *p) const; + inline bool matchesParamsAfterId(js::PropertyOp agetter, js::StrictPropertyOp asetter, + uint32 aslot, uintN aattrs, uintN aflags, + intN ashortid) const; + + bool get(JSContext* cx, JSObject *receiver, JSObject *obj, JSObject *pobj, js::Value* vp) const; + bool set(JSContext* cx, JSObject *obj, bool strict, js::Value* vp) const; + + inline bool isSharedPermanent() const; + + void trace(JSTracer *trc) const; + + bool hasSlot() const { return (attrs & JSPROP_SHARED) == 0; } + + uint8 attributes() const { return attrs; } + bool configurable() const { return (attrs & JSPROP_PERMANENT) == 0; } + bool enumerable() const { return (attrs & JSPROP_ENUMERATE) != 0; } + bool writable() const { + // JS_ASSERT(isDataDescriptor()); + return (attrs & JSPROP_READONLY) == 0; + } + bool hasGetterValue() const { return attrs & JSPROP_GETTER; } + bool hasSetterValue() const { return attrs & JSPROP_SETTER; } + + bool hasDefaultGetterOrIsMethod() const { + return hasDefaultGetter() || isMethod(); + } + + bool isDataDescriptor() const { + return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) == 0; + } + bool isAccessorDescriptor() const { + return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) != 0; + } + + /* + * For ES5 compatibility, we allow properties with JSPropertyOp-flavored + * setters to be shadowed when set. The "own" property thereby created in + * the directly referenced object will have the same getter and setter as + * the prototype property. See bug 552432. + */ + bool shadowable() const { + JS_ASSERT_IF(isDataDescriptor(), writable()); + return hasSlot() || (attrs & JSPROP_SHADOWABLE); + } + + uint32 entryCount() const { + if (hasTable()) + return getTable()->entryCount; + + const js::Shape *shape = this; + uint32 count = 0; + for (js::Shape::Range r = shape->all(); !r.empty(); r.popFront()) + ++count; + return count; + } + +#ifdef DEBUG + void dump(JSContext *cx, FILE *fp) const; + void dumpSubtree(JSContext *cx, int level, FILE *fp) const; +#endif +}; + +struct EmptyShape : public js::Shape +{ + EmptyShape(JSCompartment *comp, js::Class *aclasp); + + js::Class *getClass() const { return clasp; }; + + static EmptyShape *create(JSCompartment *comp, js::Class *clasp) { + js::Shape *eprop = comp->propertyTree.newShapeUnchecked(); + if (!eprop) + return NULL; + return new (eprop) EmptyShape(comp, clasp); + } + + static EmptyShape *create(JSContext *cx, js::Class *clasp) { + js::Shape *eprop = JS_PROPERTY_TREE(cx).newShape(cx); + if (!eprop) + return NULL; + return new (eprop) EmptyShape(cx->compartment, clasp); + } +}; + +} /* namespace js */ + +/* js::Shape pointer tag bit indicating a collision. */ +#define SHAPE_COLLISION (jsuword(1)) +#define SHAPE_REMOVED ((js::Shape *) SHAPE_COLLISION) + +/* Macros to get and set shape pointer values and collision flags. */ +#define SHAPE_IS_FREE(shape) ((shape) == NULL) +#define SHAPE_IS_REMOVED(shape) ((shape) == SHAPE_REMOVED) +#define SHAPE_IS_LIVE(shape) ((shape) > SHAPE_REMOVED) +#define SHAPE_FLAG_COLLISION(spp,shape) (*(spp) = (js::Shape *) \ + (jsuword(shape) | SHAPE_COLLISION)) +#define SHAPE_HAD_COLLISION(shape) (jsuword(shape) & SHAPE_COLLISION) +#define SHAPE_FETCH(spp) SHAPE_CLEAR_COLLISION(*(spp)) + +#define SHAPE_CLEAR_COLLISION(shape) \ + ((js::Shape *) (jsuword(shape) & ~SHAPE_COLLISION)) + +#define SHAPE_STORE_PRESERVING_COLLISION(spp, shape) \ + (*(spp) = (js::Shape *) (jsuword(shape) | SHAPE_HAD_COLLISION(*(spp)))) + +inline js::Shape ** +JSObject::nativeSearch(jsid id, bool adding) +{ + return js::Shape::search(compartment()->rt, &lastProp, id, adding); +} + +inline const js::Shape * +JSObject::nativeLookup(jsid id) +{ + JS_ASSERT(isNative()); + return SHAPE_FETCH(nativeSearch(id)); +} + +inline bool +JSObject::nativeContains(jsid id) +{ + return nativeLookup(id) != NULL; +} + +inline bool +JSObject::nativeContains(const js::Shape &shape) +{ + return nativeLookup(shape.id) == &shape; +} + +inline const js::Shape * +JSObject::lastProperty() const +{ + JS_ASSERT(isNative()); + JS_ASSERT(!JSID_IS_VOID(lastProp->id)); + return lastProp; +} + +inline bool +JSObject::nativeEmpty() const +{ + return lastProperty()->isEmptyShape(); +} + +inline bool +JSObject::inDictionaryMode() const +{ + return lastProperty()->inDictionary(); +} + +inline uint32 +JSObject::propertyCount() const +{ + return lastProperty()->entryCount(); +} + +inline bool +JSObject::hasPropertyTable() const +{ + return lastProperty()->hasTable(); +} + +/* + * FIXME: shape must not be null, should use a reference here and other places. + */ +inline void +JSObject::setLastProperty(const js::Shape *shape) +{ + JS_ASSERT(!inDictionaryMode()); + JS_ASSERT(!JSID_IS_VOID(shape->id)); + JS_ASSERT_IF(lastProp, !JSID_IS_VOID(lastProp->id)); + JS_ASSERT(shape->compartment == compartment()); + + lastProp = const_cast(shape); +} + +inline void +JSObject::removeLastProperty() +{ + JS_ASSERT(!inDictionaryMode()); + JS_ASSERT(!JSID_IS_VOID(lastProp->parent->id)); + + lastProp = lastProp->parent; +} + +namespace js { + +inline void +Shape::removeFromDictionary(JSObject *obj) const +{ + JS_ASSERT(!frozen()); + JS_ASSERT(inDictionary()); + JS_ASSERT(obj->inDictionaryMode()); + JS_ASSERT(listp); + JS_ASSERT(!JSID_IS_VOID(id)); + + JS_ASSERT(obj->lastProp->inDictionary()); + JS_ASSERT(obj->lastProp->listp == &obj->lastProp); + JS_ASSERT_IF(obj->lastProp != this, !JSID_IS_VOID(obj->lastProp->id)); + JS_ASSERT_IF(obj->lastProp->parent, !JSID_IS_VOID(obj->lastProp->parent->id)); + + if (parent) + parent->listp = listp; + *listp = parent; + listp = NULL; +} + +inline void +Shape::insertIntoDictionary(js::Shape **dictp) +{ + /* + * Don't assert inDictionaryMode() here because we may be called from + * JSObject::toDictionaryMode via JSObject::newDictionaryShape. + */ + JS_ASSERT(inDictionary()); + JS_ASSERT(!listp); + JS_ASSERT(!JSID_IS_VOID(id)); + + JS_ASSERT_IF(*dictp, !(*dictp)->frozen()); + JS_ASSERT_IF(*dictp, (*dictp)->inDictionary()); + JS_ASSERT_IF(*dictp, (*dictp)->listp == dictp); + JS_ASSERT_IF(*dictp, !JSID_IS_VOID((*dictp)->id)); + + setParent(*dictp); + if (parent) + parent->listp = &parent; + listp = dictp; + *dictp = this; +} + +} /* namespace js */ + +/* + * If SHORTID is set in shape->flags, we use shape->shortid rather + * than id when calling shape's getter or setter. + */ +#define SHAPE_USERID(shape) \ + ((shape)->hasShortID() ? INT_TO_JSID((shape)->shortid) \ + : (shape)->id) + +extern uint32 +js_GenerateShape(JSRuntime *rt); + +extern uint32 +js_GenerateShape(JSContext *cx); + +#ifdef DEBUG +struct JSScopeStats { + jsrefcount searches; + jsrefcount hits; + jsrefcount misses; + jsrefcount hashes; + jsrefcount hashHits; + jsrefcount hashMisses; + jsrefcount steps; + jsrefcount stepHits; + jsrefcount stepMisses; + jsrefcount initSearches; + jsrefcount changeSearches; + jsrefcount tableAllocFails; + jsrefcount toDictFails; + jsrefcount wrapWatchFails; + jsrefcount adds; + jsrefcount addFails; + jsrefcount puts; + jsrefcount redundantPuts; + jsrefcount putFails; + jsrefcount changes; + jsrefcount changePuts; + jsrefcount changeFails; + jsrefcount compresses; + jsrefcount grows; + jsrefcount removes; + jsrefcount removeFrees; + jsrefcount uselessRemoves; + jsrefcount shrinks; +}; + +extern JS_FRIEND_DATA(JSScopeStats) js_scope_stats; + +# define METER(x) JS_ATOMIC_INCREMENT(&js_scope_stats.x) +#else +# define METER(x) /* nothing */ +#endif + +namespace js { + +JS_ALWAYS_INLINE js::Shape ** +Shape::search(JSRuntime *rt, js::Shape **startp, jsid id, bool adding) +{ + js::Shape *start = *startp; + METER(searches); + + if (start->hasTable()) + return start->getTable()->search(id, adding); + + if (start->numLinearSearches == PropertyTable::MAX_LINEAR_SEARCHES) { + if (start->hashify(rt)) + return start->getTable()->search(id, adding); + /* OOM! Don't increment numLinearSearches, to keep hasTable() false. */ + JS_ASSERT(!start->hasTable()); + } else { + JS_ASSERT(start->numLinearSearches < PropertyTable::MAX_LINEAR_SEARCHES); + start->numLinearSearches++; + } + + /* + * Not enough searches done so far to justify hashing: search linearly + * from *startp. + * + * We don't use a Range here, or stop at null parent (the empty shape + * at the end), to avoid an extra load per iteration just to save a + * load and id test at the end (when missing). + */ + js::Shape **spp; + for (spp = startp; js::Shape *shape = *spp; spp = &shape->parent) { + if (shape->id == id) { + METER(hits); + return spp; + } + } + METER(misses); + return spp; +} + +#undef METER + +inline bool +Shape::isSharedPermanent() const +{ + return (~attrs & (JSPROP_SHARED | JSPROP_PERMANENT)) == 0; +} + +} // namespace js + +#ifdef _MSC_VER +#pragma warning(pop) +#pragma warning(pop) +#endif + +#endif /* jsscope_h___ */ diff --git a/js/src/jsscopeinlines.h b/js/src/jsscopeinlines.h new file mode 100644 index 0000000..825b9a9 --- /dev/null +++ b/js/src/jsscopeinlines.h @@ -0,0 +1,297 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsscopeinlines_h___ +#define jsscopeinlines_h___ + +#include +#include "jsbool.h" +#include "jscntxt.h" +#include "jsdbgapi.h" +#include "jsfun.h" +#include "jsobj.h" +#include "jsscope.h" + +#include "jscntxtinlines.h" + +inline void +js::Shape::freeTable(JSContext *cx) +{ + if (hasTable()) { + cx->destroy(getTable()); + setTable(NULL); + } +} + +inline js::EmptyShape * +JSObject::getEmptyShape(JSContext *cx, js::Class *aclasp, + /* gc::FinalizeKind */ unsigned kind) +{ + JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST); + int i = kind - js::gc::FINALIZE_OBJECT0; + + if (!emptyShapes) { + emptyShapes = (js::EmptyShape**) + cx->calloc(sizeof(js::EmptyShape*) * js::gc::JS_FINALIZE_OBJECT_LIMIT); + if (!emptyShapes) + return NULL; + + /* + * Always fill in emptyShapes[0], so canProvideEmptyShape works. + * Other empty shapes are filled in lazily. + */ + emptyShapes[0] = js::EmptyShape::create(cx, aclasp); + if (!emptyShapes[0]) { + cx->free(emptyShapes); + emptyShapes = NULL; + return NULL; + } + } + + JS_ASSERT(aclasp == emptyShapes[0]->getClass()); + + if (!emptyShapes[i]) { + emptyShapes[i] = js::EmptyShape::create(cx, aclasp); + if (!emptyShapes[i]) + return NULL; + } + + return emptyShapes[i]; +} + +inline bool +JSObject::canProvideEmptyShape(js::Class *aclasp) +{ + return !emptyShapes || emptyShapes[0]->getClass() == aclasp; +} + +inline void +JSObject::updateShape(JSContext *cx) +{ + JS_ASSERT(isNative()); + js::LeaveTraceIfGlobalObject(cx, this); + if (hasOwnShape()) + setOwnShape(js_GenerateShape(cx)); + else + objShape = lastProp->shape; +} + +inline void +JSObject::updateFlags(const js::Shape *shape, bool isDefinitelyAtom) +{ + jsuint index; + if (!isDefinitelyAtom && js_IdIsIndex(shape->id, &index)) + setIndexed(); + + if (shape->isMethod()) + setMethodBarrier(); +} + +inline void +JSObject::extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom) +{ + setLastProperty(shape); + updateFlags(shape, isDefinitelyAtom); + updateShape(cx); +} + +inline void +JSObject::trace(JSTracer *trc) +{ + if (!isNative()) + return; + + JSContext *cx = trc->context; + js::Shape *shape = lastProp; + + if (IS_GC_MARKING_TRACER(trc) && cx->runtime->gcRegenShapes) { + /* + * Either this object has its own shape, which must be regenerated, or + * it must have the same shape as lastProp. + */ + if (!shape->hasRegenFlag()) { + shape->shape = js_RegenerateShapeForGC(cx->runtime); + shape->setRegenFlag(); + } + + uint32 newShape = shape->shape; + if (hasOwnShape()) { + newShape = js_RegenerateShapeForGC(cx->runtime); + JS_ASSERT(newShape != shape->shape); + } + objShape = newShape; + } + + /* Trace our property tree or dictionary ancestor line. */ + do { + shape->trace(trc); + } while ((shape = shape->parent) != NULL); +} + +namespace js { + +inline +Shape::Shape(jsid id, js::PropertyOp getter, js::StrictPropertyOp setter, uint32 slot, uintN attrs, + uintN flags, intN shortid, uint32 shape, uint32 slotSpan) + : JSObjectMap(shape, slotSpan), + numLinearSearches(0), id(id), rawGetter(getter), rawSetter(setter), slot(slot), + attrs(uint8(attrs)), flags(uint8(flags)), shortid(int16(shortid)), parent(NULL) +{ + JS_ASSERT_IF(slotSpan != SHAPE_INVALID_SLOT, slotSpan < JSObject::NSLOTS_LIMIT); + JS_ASSERT_IF(getter && (attrs & JSPROP_GETTER), getterObj->isCallable()); + JS_ASSERT_IF(setter && (attrs & JSPROP_SETTER), setterObj->isCallable()); + kids.setNull(); +} + +inline +Shape::Shape(JSCompartment *comp, Class *aclasp) + : JSObjectMap(js_GenerateShape(comp->rt), JSSLOT_FREE(aclasp)), + numLinearSearches(0), + id(JSID_EMPTY), + clasp(aclasp), + rawSetter(NULL), + slot(SHAPE_INVALID_SLOT), + attrs(0), + flags(SHARED_EMPTY), + shortid(0), + parent(NULL) +{ + kids.setNull(); +} + +inline JSDHashNumber +Shape::hash() const +{ + JSDHashNumber hash = 0; + + /* Accumulate from least to most random so the low bits are most random. */ + JS_ASSERT_IF(isMethod(), !rawSetter || rawSetter == js_watch_set); + if (rawGetter) + hash = JS_ROTATE_LEFT32(hash, 4) ^ jsuword(rawGetter); + if (rawSetter) + hash = JS_ROTATE_LEFT32(hash, 4) ^ jsuword(rawSetter); + hash = JS_ROTATE_LEFT32(hash, 4) ^ (flags & PUBLIC_FLAGS); + hash = JS_ROTATE_LEFT32(hash, 4) ^ attrs; + hash = JS_ROTATE_LEFT32(hash, 4) ^ shortid; + hash = JS_ROTATE_LEFT32(hash, 4) ^ slot; + hash = JS_ROTATE_LEFT32(hash, 4) ^ JSID_BITS(id); + return hash; +} + +inline bool +Shape::matches(const js::Shape *other) const +{ + JS_ASSERT(!JSID_IS_VOID(id)); + JS_ASSERT(!JSID_IS_VOID(other->id)); + return id == other->id && + matchesParamsAfterId(other->rawGetter, other->rawSetter, other->slot, other->attrs, + other->flags, other->shortid); +} + +inline bool +Shape::matchesParamsAfterId(js::PropertyOp agetter, js::StrictPropertyOp asetter, uint32 aslot, + uintN aattrs, uintN aflags, intN ashortid) const +{ + JS_ASSERT(!JSID_IS_VOID(id)); + return rawGetter == agetter && + rawSetter == asetter && + slot == aslot && + attrs == aattrs && + ((flags ^ aflags) & PUBLIC_FLAGS) == 0 && + shortid == ashortid; +} + +inline bool +Shape::get(JSContext* cx, JSObject *receiver, JSObject* obj, JSObject *pobj, js::Value* vp) const +{ + JS_ASSERT(!JSID_IS_VOID(this->id)); + JS_ASSERT(!hasDefaultGetter()); + + if (hasGetterValue()) { + JS_ASSERT(!isMethod()); + js::Value fval = getterValue(); + return js::ExternalGetOrSet(cx, receiver, id, fval, JSACC_READ, 0, 0, vp); + } + + if (isMethod()) { + vp->setObject(methodObject()); + return pobj->methodReadBarrier(cx, *this, vp); + } + + /* + * |with (it) color;| ends up here, as do XML filter-expressions. + * Avoid exposing the With object to native getters. + */ + if (obj->getClass() == &js_WithClass) + obj = js_UnwrapWithObject(cx, obj); + return js::CallJSPropertyOp(cx, getterOp(), obj, SHAPE_USERID(this), vp); +} + +inline bool +Shape::set(JSContext* cx, JSObject* obj, bool strict, js::Value* vp) const +{ + JS_ASSERT_IF(hasDefaultSetter(), hasGetterValue()); + + if (attrs & JSPROP_SETTER) { + js::Value fval = setterValue(); + return js::ExternalGetOrSet(cx, obj, id, fval, JSACC_WRITE, 1, vp, vp); + } + + if (attrs & JSPROP_GETTER) + return js_ReportGetterOnlyAssignment(cx); + + /* See the comment in js::Shape::get as to why we check for With. */ + if (obj->getClass() == &js_WithClass) + obj = js_UnwrapWithObject(cx, obj); + return js::CallJSPropertyOpSetter(cx, setterOp(), obj, SHAPE_USERID(this), strict, vp); +} + +inline +EmptyShape::EmptyShape(JSCompartment *comp, js::Class *aclasp) + : js::Shape(comp, aclasp) +{ +#ifdef DEBUG + if (comp->rt->meterEmptyShapes()) + comp->emptyShapes.put(this); +#endif +} + +} /* namespace js */ + +#endif /* jsscopeinlines_h___ */ diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp new file mode 100644 index 0000000..1198ef4 --- /dev/null +++ b/js/src/jsscript.cpp @@ -0,0 +1,2018 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS script operations. + */ +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsutil.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsatom.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsdbgapi.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jstracer.h" +#if JS_HAS_XDR +#include "jsxdrapi.h" +#endif +#include "methodjit/MethodJIT.h" + +#include "jsinterpinlines.h" +#include "jsobjinlines.h" +#include "jsscriptinlines.h" + +using namespace js; +using namespace js::gc; + +namespace js { + +BindingKind +Bindings::lookup(JSContext *cx, JSAtom *name, uintN *indexp) const +{ + JS_ASSERT(lastBinding); + + Shape *shape = + SHAPE_FETCH(Shape::search(cx->runtime, const_cast(&lastBinding), + ATOM_TO_JSID(name))); + if (!shape) + return NONE; + + if (indexp) + *indexp = shape->shortid; + + if (shape->getter() == GetCallArg) + return ARGUMENT; + if (shape->getter() == GetCallUpvar) + return UPVAR; + + return shape->writable() ? VARIABLE : CONSTANT; +} + +bool +Bindings::add(JSContext *cx, JSAtom *name, BindingKind kind) +{ + JS_ASSERT(lastBinding); + + /* + * We still follow 10.2.3 of ES3 and make argument and variable properties + * of the Call objects enumerable. ES5 reformulated all of its Clause 10 to + * avoid objects as activations, something we should do too. + */ + uintN attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED; + + uint16 *indexp; + PropertyOp getter; + StrictPropertyOp setter; + uint32 slot = JSObject::CALL_RESERVED_SLOTS; + + if (kind == ARGUMENT) { + JS_ASSERT(nvars == 0); + JS_ASSERT(nupvars == 0); + indexp = &nargs; + getter = GetCallArg; + setter = SetCallArg; + slot += nargs; + } else if (kind == UPVAR) { + indexp = &nupvars; + getter = GetCallUpvar; + setter = SetCallUpvar; + slot = SHAPE_INVALID_SLOT; + } else { + JS_ASSERT(kind == VARIABLE || kind == CONSTANT); + JS_ASSERT(nupvars == 0); + + indexp = &nvars; + getter = GetCallVar; + setter = SetCallVar; + if (kind == CONSTANT) + attrs |= JSPROP_READONLY; + slot += nargs + nvars; + } + + if (*indexp == BINDING_COUNT_LIMIT) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + (kind == ARGUMENT) + ? JSMSG_TOO_MANY_FUN_ARGS + : JSMSG_TOO_MANY_LOCALS); + return false; + } + + jsid id; + if (!name) { + JS_ASSERT(kind == ARGUMENT); /* destructuring */ + id = INT_TO_JSID(nargs); + } else { + id = ATOM_TO_JSID(name); + } + + Shape child(id, getter, setter, slot, attrs, Shape::HAS_SHORTID, *indexp); + + Shape *shape = lastBinding->getChild(cx, child, &lastBinding); + if (!shape) + return false; + + JS_ASSERT(lastBinding == shape); + ++*indexp; + return true; +} + +jsuword * +Bindings::getLocalNameArray(JSContext *cx, JSArenaPool *pool) +{ + JS_ASSERT(lastBinding); + + JS_ASSERT(hasLocalNames()); + + uintN n = countLocalNames(); + jsuword *names; + + JS_ASSERT(SIZE_MAX / size_t(n) > sizeof *names); + JS_ARENA_ALLOCATE_CAST(names, jsuword *, pool, size_t(n) * sizeof *names); + if (!names) { + js_ReportOutOfScriptQuota(cx); + return NULL; + } + +#ifdef DEBUG + for (uintN i = 0; i != n; i++) + names[i] = 0xdeadbeef; +#endif + + for (Shape::Range r = lastBinding; !r.empty(); r.popFront()) { + const Shape &shape = r.front(); + uintN index = uint16(shape.shortid); + jsuword constFlag = 0; + + if (shape.getter() == GetCallArg) { + JS_ASSERT(index < nargs); + } else if (shape.getter() == GetCallUpvar) { + JS_ASSERT(index < nupvars); + index += nargs + nvars; + } else { + JS_ASSERT(index < nvars); + index += nargs; + if (!shape.writable()) + constFlag = 1; + } + + JSAtom *atom; + if (JSID_IS_ATOM(shape.id)) { + atom = JSID_TO_ATOM(shape.id); + } else { + JS_ASSERT(JSID_IS_INT(shape.id)); + JS_ASSERT(shape.getter() == GetCallArg); + atom = NULL; + } + + names[index] = jsuword(atom); + } + +#ifdef DEBUG + for (uintN i = 0; i != n; i++) + JS_ASSERT(names[i] != 0xdeadbeef); +#endif + return names; +} + +const Shape * +Bindings::lastArgument() const +{ + JS_ASSERT(lastBinding); + + const js::Shape *shape = lastVariable(); + if (nvars > 0) { + while (shape->previous() && shape->getter() != GetCallArg) + shape = shape->previous(); + } + return shape; +} + +const Shape * +Bindings::lastVariable() const +{ + JS_ASSERT(lastBinding); + + const js::Shape *shape = lastUpvar(); + if (nupvars > 0) { + while (shape->getter() == GetCallUpvar) + shape = shape->previous(); + } + return shape; +} + +const Shape * +Bindings::lastUpvar() const +{ + JS_ASSERT(lastBinding); + return lastBinding; +} + +int +Bindings::sharpSlotBase(JSContext *cx) +{ + JS_ASSERT(lastBinding); +#if JS_HAS_SHARP_VARS + if (JSAtom *name = js_Atomize(cx, "#array", 6, 0)) { + uintN index = uintN(-1); +#ifdef DEBUG + BindingKind kind = +#endif + lookup(cx, name, &index); + JS_ASSERT(kind == VARIABLE); + return int(index); + } +#endif + return -1; +} + +void +Bindings::makeImmutable() +{ + JS_ASSERT(lastBinding); + Shape *shape = lastBinding; + if (shape->inDictionary()) { + do { + JS_ASSERT(!shape->frozen()); + shape->setFrozen(); + } while ((shape = shape->parent) != NULL); + } +} + +void +Bindings::trace(JSTracer *trc) +{ + for (const Shape *shape = lastBinding; shape; shape = shape->previous()) + shape->trace(trc); +} + +} /* namespace js */ + +#if JS_HAS_XDR + +enum ScriptBits { + NoScriptRval, + SavedCallerFun, + HasSharps, + StrictModeCode, + UsesEval, + UsesArguments +}; + +JSBool +js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic) +{ + JSScript *oldscript; + JSBool ok; + jsbytecode *code; + uint32 length, lineno, nslots; + uint32 natoms, nsrcnotes, ntrynotes, nobjects, nregexps, nconsts, i; + uint32 prologLength, version, encodedClosedCount; + uint16 nClosedArgs = 0, nClosedVars = 0; + JSPrincipals *principals; + uint32 encodeable; + JSBool filenameWasSaved; + jssrcnote *sn; + JSSecurityCallbacks *callbacks; + uint32 scriptBits = 0; + + JSContext *cx = xdr->cx; + JSScript *script = *scriptp; + nsrcnotes = ntrynotes = natoms = nobjects = nregexps = nconsts = 0; + filenameWasSaved = JS_FALSE; + jssrcnote *notes = NULL; + + /* Should not XDR scripts optimized for a single global object. */ + JS_ASSERT_IF(script, !JSScript::isValidOffset(script->globalsOffset)); + + uint32 magic; + if (xdr->mode == JSXDR_ENCODE) + magic = JSXDR_MAGIC_SCRIPT_CURRENT; + if (!JS_XDRUint32(xdr, &magic)) + return JS_FALSE; + if (magic != JSXDR_MAGIC_SCRIPT_CURRENT) { + /* We do not provide binary compatibility with older scripts. */ + if (!hasMagic) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_SCRIPT_MAGIC); + return JS_FALSE; + } + *hasMagic = JS_FALSE; + return JS_TRUE; + } + if (hasMagic) + *hasMagic = JS_TRUE; + + /* XDR arguments, local vars, and upvars. */ + uint16 nargs, nvars, nupvars; +#if defined(DEBUG) || defined(__GNUC__) /* quell GCC overwarning */ + nargs = nvars = nupvars = Bindings::BINDING_COUNT_LIMIT; +#endif + uint32 argsVars, paddingUpvars; + if (xdr->mode == JSXDR_ENCODE) { + nargs = script->bindings.countArgs(); + nvars = script->bindings.countVars(); + nupvars = script->bindings.countUpvars(); + argsVars = (nargs << 16) | nvars; + paddingUpvars = nupvars; + } + if (!JS_XDRUint32(xdr, &argsVars) || !JS_XDRUint32(xdr, &paddingUpvars)) + return false; + if (xdr->mode == JSXDR_DECODE) { + nargs = argsVars >> 16; + nvars = argsVars & 0xFFFF; + JS_ASSERT((paddingUpvars >> 16) == 0); + nupvars = paddingUpvars & 0xFFFF; + } + JS_ASSERT(nargs != Bindings::BINDING_COUNT_LIMIT); + JS_ASSERT(nvars != Bindings::BINDING_COUNT_LIMIT); + JS_ASSERT(nupvars != Bindings::BINDING_COUNT_LIMIT); + + Bindings bindings(cx); + AutoBindingsRooter rooter(cx, bindings); + uint32 nameCount = nargs + nvars + nupvars; + if (nameCount > 0) { + struct AutoMark { + JSArenaPool * const pool; + void * const mark; + AutoMark(JSArenaPool *pool) : pool(pool), mark(JS_ARENA_MARK(pool)) { } + ~AutoMark() { + JS_ARENA_RELEASE(pool, mark); + } + } automark(&cx->tempPool); + + /* + * To xdr the names we prefix the names with a bitmap descriptor and + * then xdr the names as strings. For argument names (indexes below + * nargs) the corresponding bit in the bitmap is unset when the name + * is null. Such null names are not encoded or decoded. For variable + * names (indexes starting from nargs) bitmap's bit is set when the + * name is declared as const, not as ordinary var. + * */ + uintN bitmapLength = JS_HOWMANY(nameCount, JS_BITS_PER_UINT32); + uint32 *bitmap; + JS_ARENA_ALLOCATE_CAST(bitmap, uint32 *, &cx->tempPool, + bitmapLength * sizeof *bitmap); + if (!bitmap) { + js_ReportOutOfScriptQuota(cx); + return false; + } + + jsuword *names; + if (xdr->mode == JSXDR_ENCODE) { + names = script->bindings.getLocalNameArray(cx, &cx->tempPool); + if (!names) + return false; + PodZero(bitmap, bitmapLength); + for (uintN i = 0; i < nameCount; i++) { + if (i < nargs + ? JS_LOCAL_NAME_TO_ATOM(names[i]) != NULL + : JS_LOCAL_NAME_IS_CONST(names[i])) + { + bitmap[i >> JS_BITS_PER_UINT32_LOG2] |= JS_BIT(i & (JS_BITS_PER_UINT32 - 1)); + } + } + } +#ifdef __GNUC__ + else { + names = NULL; /* quell GCC uninitialized warning */ + } +#endif + for (uintN i = 0; i < bitmapLength; ++i) { + if (!JS_XDRUint32(xdr, &bitmap[i])) + return false; + } + + for (uintN i = 0; i < nameCount; i++) { + if (i < nargs && + !(bitmap[i >> JS_BITS_PER_UINT32_LOG2] & JS_BIT(i & (JS_BITS_PER_UINT32 - 1)))) + { + if (xdr->mode == JSXDR_DECODE) { + uint16 dummy; + if (!bindings.addDestructuring(cx, &dummy)) + return false; + } else { + JS_ASSERT(!JS_LOCAL_NAME_TO_ATOM(names[i])); + } + continue; + } + + JSAtom *name; + if (xdr->mode == JSXDR_ENCODE) + name = JS_LOCAL_NAME_TO_ATOM(names[i]); + if (!js_XDRAtom(xdr, &name)) + return false; + if (xdr->mode == JSXDR_DECODE) { + BindingKind kind = (i < nargs) + ? ARGUMENT + : (i < uintN(nargs + nvars)) + ? (bitmap[i >> JS_BITS_PER_UINT32_LOG2] & + JS_BIT(i & (JS_BITS_PER_UINT32 - 1)) + ? CONSTANT + : VARIABLE) + : UPVAR; + if (!bindings.add(cx, name, kind)) + return false; + } + } + + if (xdr->mode == JSXDR_DECODE) + bindings.makeImmutable(); + } + + if (xdr->mode == JSXDR_ENCODE) + length = script->length; + if (!JS_XDRUint32(xdr, &length)) + return JS_FALSE; + + if (xdr->mode == JSXDR_ENCODE) { + prologLength = script->main - script->code; + JS_ASSERT(script->getVersion() != JSVERSION_UNKNOWN); + version = (uint32)script->getVersion() | (script->nfixed << 16); + lineno = (uint32)script->lineno; + nslots = (uint32)script->nslots; + nslots = (uint32)((script->staticLevel << 16) | script->nslots); + natoms = (uint32)script->atomMap.length; + + /* Count the srcnotes, keeping notes pointing at the first one. */ + notes = script->notes(); + for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) + continue; + nsrcnotes = sn - notes; + nsrcnotes++; /* room for the terminator */ + + if (JSScript::isValidOffset(script->objectsOffset)) + nobjects = script->objects()->length; + if (JSScript::isValidOffset(script->upvarsOffset)) + JS_ASSERT(script->bindings.countUpvars() == script->upvars()->length); + if (JSScript::isValidOffset(script->regexpsOffset)) + nregexps = script->regexps()->length; + if (JSScript::isValidOffset(script->trynotesOffset)) + ntrynotes = script->trynotes()->length; + if (JSScript::isValidOffset(script->constOffset)) + nconsts = script->consts()->length; + + nClosedArgs = script->nClosedArgs; + nClosedVars = script->nClosedVars; + encodedClosedCount = (nClosedArgs << 16) | nClosedVars; + + if (script->noScriptRval) + scriptBits |= (1 << NoScriptRval); + if (script->savedCallerFun) + scriptBits |= (1 << SavedCallerFun); + if (script->hasSharps) + scriptBits |= (1 << HasSharps); + if (script->strictModeCode) + scriptBits |= (1 << StrictModeCode); + if (script->usesEval) + scriptBits |= (1 << UsesEval); + if (script->usesArguments) + scriptBits |= (1 << UsesArguments); + JS_ASSERT(!script->compileAndGo); + JS_ASSERT(!script->hasSingletons); + } + + if (!JS_XDRUint32(xdr, &prologLength)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &version)) + return JS_FALSE; + + /* + * To fuse allocations, we need srcnote, atom, objects, regexp, and trynote + * counts early. + */ + if (!JS_XDRUint32(xdr, &natoms)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &nsrcnotes)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &ntrynotes)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &nobjects)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &nregexps)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &nconsts)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &encodedClosedCount)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, &scriptBits)) + return JS_FALSE; + + AutoScriptRooter tvr(cx, NULL); + + if (xdr->mode == JSXDR_DECODE) { + nClosedArgs = encodedClosedCount >> 16; + nClosedVars = encodedClosedCount & 0xFFFF; + + /* Note: version is packed into the 32b space with another 16b value. */ + JSVersion version_ = JSVersion(version & JS_BITMASK(16)); + JS_ASSERT((version_ & VersionFlags::FULL_MASK) == uintN(version_)); + script = JSScript::NewScript(cx, length, nsrcnotes, natoms, nobjects, nupvars, + nregexps, ntrynotes, nconsts, 0, nClosedArgs, + nClosedVars, version_); + if (!script) + return JS_FALSE; + + script->bindings.transfer(cx, &bindings); + + script->main += prologLength; + script->nfixed = uint16(version >> 16); + + /* If we know nsrcnotes, we allocated space for notes in script. */ + notes = script->notes(); + *scriptp = script; + tvr.setScript(script); + + if (scriptBits & (1 << NoScriptRval)) + script->noScriptRval = true; + if (scriptBits & (1 << SavedCallerFun)) + script->savedCallerFun = true; + if (scriptBits & (1 << HasSharps)) + script->hasSharps = true; + if (scriptBits & (1 << StrictModeCode)) + script->strictModeCode = true; + if (scriptBits & (1 << UsesEval)) + script->usesEval = true; + if (scriptBits & (1 << UsesArguments)) + script->usesArguments = true; + } + + /* + * Control hereafter must goto error on failure, in order for the + * DECODE case to destroy script. + */ + oldscript = xdr->script; + code = script->code; + if (xdr->mode == JSXDR_ENCODE) { + code = js_UntrapScriptCode(cx, script); + if (!code) + goto error; + } + + xdr->script = script; + ok = JS_XDRBytes(xdr, (char *) code, length * sizeof(jsbytecode)); + + if (code != script->code) + cx->free(code); + + if (!ok) + goto error; + + if (!JS_XDRBytes(xdr, (char *)notes, nsrcnotes * sizeof(jssrcnote)) || + !JS_XDRCStringOrNull(xdr, (char **)&script->filename) || + !JS_XDRUint32(xdr, &lineno) || + !JS_XDRUint32(xdr, &nslots)) { + goto error; + } + + callbacks = JS_GetSecurityCallbacks(cx); + if (xdr->mode == JSXDR_ENCODE) { + principals = script->principals; + encodeable = callbacks && callbacks->principalsTranscoder; + if (!JS_XDRUint32(xdr, &encodeable)) + goto error; + if (encodeable && + !callbacks->principalsTranscoder(xdr, &principals)) { + goto error; + } + } else { + if (!JS_XDRUint32(xdr, &encodeable)) + goto error; + if (encodeable) { + if (!(callbacks && callbacks->principalsTranscoder)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_DECODE_PRINCIPALS); + goto error; + } + if (!callbacks->principalsTranscoder(xdr, &principals)) + goto error; + script->principals = principals; + } + } + + if (xdr->mode == JSXDR_DECODE) { + const char *filename = script->filename; + if (filename) { + filename = js_SaveScriptFilename(cx, filename); + if (!filename) + goto error; + cx->free((void *) script->filename); + script->filename = filename; + filenameWasSaved = JS_TRUE; + } + script->lineno = (uintN)lineno; + script->nslots = (uint16)nslots; + script->staticLevel = (uint16)(nslots >> 16); + + } + + for (i = 0; i != natoms; ++i) { + if (!js_XDRAtom(xdr, &script->atomMap.vector[i])) + goto error; + } + + /* + * Here looping from 0-to-length to xdr objects is essential. It ensures + * that block objects from the script->objects array will be written and + * restored in the outer-to-inner order. js_XDRBlockObject relies on this + * to restore the parent chain. + */ + for (i = 0; i != nobjects; ++i) { + JSObject **objp = &script->objects()->vector[i]; + uint32 isBlock; + if (xdr->mode == JSXDR_ENCODE) { + Class *clasp = (*objp)->getClass(); + JS_ASSERT(clasp == &js_FunctionClass || + clasp == &js_BlockClass); + isBlock = (clasp == &js_BlockClass) ? 1 : 0; + } + if (!JS_XDRUint32(xdr, &isBlock)) + goto error; + if (isBlock == 0) { + if (!js_XDRFunctionObject(xdr, objp)) + goto error; + } else { + JS_ASSERT(isBlock == 1); + if (!js_XDRBlockObject(xdr, objp)) + goto error; + } + } + for (i = 0; i != nupvars; ++i) { + if (!JS_XDRUint32(xdr, reinterpret_cast(&script->upvars()->vector[i]))) + goto error; + } + for (i = 0; i != nregexps; ++i) { + if (!js_XDRRegExpObject(xdr, &script->regexps()->vector[i])) + goto error; + } + for (i = 0; i != nClosedArgs; ++i) { + if (!JS_XDRUint32(xdr, &script->closedSlots[i])) + goto error; + } + for (i = 0; i != nClosedVars; ++i) { + if (!JS_XDRUint32(xdr, &script->closedSlots[nClosedArgs + i])) + goto error; + } + + if (ntrynotes != 0) { + /* + * We combine tn->kind and tn->stackDepth when serializing as XDR is not + * efficient when serializing small integer types. + */ + JSTryNote *tn, *tnfirst; + uint32 kindAndDepth; + JS_STATIC_ASSERT(sizeof(tn->kind) == sizeof(uint8)); + JS_STATIC_ASSERT(sizeof(tn->stackDepth) == sizeof(uint16)); + + tnfirst = script->trynotes()->vector; + JS_ASSERT(script->trynotes()->length == ntrynotes); + tn = tnfirst + ntrynotes; + do { + --tn; + if (xdr->mode == JSXDR_ENCODE) { + kindAndDepth = ((uint32)tn->kind << 16) + | (uint32)tn->stackDepth; + } + if (!JS_XDRUint32(xdr, &kindAndDepth) || + !JS_XDRUint32(xdr, &tn->start) || + !JS_XDRUint32(xdr, &tn->length)) { + goto error; + } + if (xdr->mode == JSXDR_DECODE) { + tn->kind = (uint8)(kindAndDepth >> 16); + tn->stackDepth = (uint16)kindAndDepth; + } + } while (tn != tnfirst); + } + + for (i = 0; i != nconsts; ++i) { + if (!JS_XDRValue(xdr, Jsvalify(&script->consts()->vector[i]))) + goto error; + } + + xdr->script = oldscript; + return JS_TRUE; + + error: + if (xdr->mode == JSXDR_DECODE) { + if (script->filename && !filenameWasSaved) { + cx->free((void *) script->filename); + script->filename = NULL; + } + js_DestroyScript(cx, script); + *scriptp = NULL; + } + xdr->script = oldscript; + return JS_FALSE; +} + +#endif /* JS_HAS_XDR */ + +static void +script_finalize(JSContext *cx, JSObject *obj) +{ + JSScript *script = (JSScript *) obj->getPrivate(); + if (script) + js_DestroyScriptFromGC(cx, script); +} + +static void +script_trace(JSTracer *trc, JSObject *obj) +{ + JSScript *script = (JSScript *) obj->getPrivate(); + if (script) + js_TraceScript(trc, script); +} + +Class js_ScriptClass = { + "Script", + JSCLASS_HAS_PRIVATE | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub, + script_finalize, + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + JS_CLASS_TRACE(script_trace) +}; + +/* + * Shared script filename management. + */ +static int +js_compare_strings(const void *k1, const void *k2) +{ + return strcmp((const char *) k1, (const char *) k2) == 0; +} + +/* NB: This struct overlays JSHashEntry -- see jshash.h, do not reorganize. */ +typedef struct ScriptFilenameEntry { + JSHashEntry *next; /* hash chain linkage */ + JSHashNumber keyHash; /* key hash function result */ + const void *key; /* ptr to filename, below */ + uint32 flags; /* user-defined filename prefix flags */ + JSPackedBool mark; /* GC mark flag */ + char filename[3]; /* two or more bytes, NUL-terminated */ +} ScriptFilenameEntry; + +static void * +js_alloc_table_space(void *priv, size_t size) +{ + return js_malloc(size); +} + +static void +js_free_table_space(void *priv, void *item, size_t size) +{ + js_free(item); +} + +static JSHashEntry * +js_alloc_sftbl_entry(void *priv, const void *key) +{ + size_t nbytes = offsetof(ScriptFilenameEntry, filename) + + strlen((const char *) key) + 1; + + return (JSHashEntry *) js_malloc(JS_MAX(nbytes, sizeof(JSHashEntry))); +} + +static void +js_free_sftbl_entry(void *priv, JSHashEntry *he, uintN flag) +{ + if (flag != HT_FREE_ENTRY) + return; + js_free(he); +} + +static JSHashAllocOps sftbl_alloc_ops = { + js_alloc_table_space, js_free_table_space, + js_alloc_sftbl_entry, js_free_sftbl_entry +}; + +static void +FinishRuntimeScriptState(JSRuntime *rt) +{ + if (rt->scriptFilenameTable) { + JS_HashTableDestroy(rt->scriptFilenameTable); + rt->scriptFilenameTable = NULL; + } +#ifdef JS_THREADSAFE + if (rt->scriptFilenameTableLock) { + JS_DESTROY_LOCK(rt->scriptFilenameTableLock); + rt->scriptFilenameTableLock = NULL; + } +#endif +} + +JSBool +js_InitRuntimeScriptState(JSRuntime *rt) +{ +#ifdef JS_THREADSAFE + JS_ASSERT(!rt->scriptFilenameTableLock); + rt->scriptFilenameTableLock = JS_NEW_LOCK(); + if (!rt->scriptFilenameTableLock) + return JS_FALSE; +#endif + JS_ASSERT(!rt->scriptFilenameTable); + rt->scriptFilenameTable = + JS_NewHashTable(16, JS_HashString, js_compare_strings, NULL, + &sftbl_alloc_ops, NULL); + if (!rt->scriptFilenameTable) { + FinishRuntimeScriptState(rt); /* free lock if threadsafe */ + return JS_FALSE; + } + JS_INIT_CLIST(&rt->scriptFilenamePrefixes); + return JS_TRUE; +} + +typedef struct ScriptFilenamePrefix { + JSCList links; /* circular list linkage for easy deletion */ + const char *name; /* pointer to pinned ScriptFilenameEntry string */ + size_t length; /* prefix string length, precomputed */ + uint32 flags; /* user-defined flags to inherit from this prefix */ +} ScriptFilenamePrefix; + +void +js_FreeRuntimeScriptState(JSRuntime *rt) +{ + if (!rt->scriptFilenameTable) + return; + + while (!JS_CLIST_IS_EMPTY(&rt->scriptFilenamePrefixes)) { + ScriptFilenamePrefix *sfp = (ScriptFilenamePrefix *) + rt->scriptFilenamePrefixes.next; + JS_REMOVE_LINK(&sfp->links); + js_free(sfp); + } + FinishRuntimeScriptState(rt); +} + +#ifdef DEBUG_brendan +#define DEBUG_SFTBL +#endif +#ifdef DEBUG_SFTBL +size_t sftbl_savings = 0; +#endif + +static ScriptFilenameEntry * +SaveScriptFilename(JSRuntime *rt, const char *filename, uint32 flags) +{ + JSHashTable *table; + JSHashNumber hash; + JSHashEntry **hep; + ScriptFilenameEntry *sfe; + size_t length; + JSCList *head, *link; + ScriptFilenamePrefix *sfp; + + table = rt->scriptFilenameTable; + hash = JS_HashString(filename); + hep = JS_HashTableRawLookup(table, hash, filename); + sfe = (ScriptFilenameEntry *) *hep; +#ifdef DEBUG_SFTBL + if (sfe) + sftbl_savings += strlen(sfe->filename); +#endif + + if (!sfe) { + sfe = (ScriptFilenameEntry *) + JS_HashTableRawAdd(table, hep, hash, filename, NULL); + if (!sfe) + return NULL; + sfe->key = strcpy(sfe->filename, filename); + sfe->flags = 0; + sfe->mark = JS_FALSE; + } + + /* If saving a prefix, add it to the set in rt->scriptFilenamePrefixes. */ + if (flags != 0) { + /* Search in case filename was saved already; we must be idempotent. */ + sfp = NULL; + length = strlen(filename); + for (head = link = &rt->scriptFilenamePrefixes; + link->next != head; + link = link->next) { + /* Lag link behind sfp to insert in non-increasing length order. */ + sfp = (ScriptFilenamePrefix *) link->next; + if (!strcmp(sfp->name, filename)) + break; + if (sfp->length <= length) { + sfp = NULL; + break; + } + sfp = NULL; + } + + if (!sfp) { + /* No such prefix: add one now. */ + sfp = (ScriptFilenamePrefix *) js_malloc(sizeof(ScriptFilenamePrefix)); + if (!sfp) + return NULL; + JS_INSERT_AFTER(&sfp->links, link); + sfp->name = sfe->filename; + sfp->length = length; + sfp->flags = 0; + } + + /* + * Accumulate flags in both sfe and sfp: sfe for later access from the + * JS_GetScriptedCallerFilenameFlags debug-API, and sfp so that longer + * filename entries can inherit by prefix. + */ + sfe->flags |= flags; + sfp->flags |= flags; + } + +#ifdef DEBUG + if (rt->functionMeterFilename) { + size_t len = strlen(sfe->filename); + if (len >= sizeof rt->lastScriptFilename) + len = sizeof rt->lastScriptFilename - 1; + memcpy(rt->lastScriptFilename, sfe->filename, len); + rt->lastScriptFilename[len] = '\0'; + } +#endif + + return sfe; +} + +const char * +js_SaveScriptFilename(JSContext *cx, const char *filename) +{ + JSRuntime *rt; + ScriptFilenameEntry *sfe; + JSCList *head, *link; + ScriptFilenamePrefix *sfp; + + rt = cx->runtime; + JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock); + sfe = SaveScriptFilename(rt, filename, 0); + if (!sfe) { + JS_RELEASE_LOCK(rt->scriptFilenameTableLock); + JS_ReportOutOfMemory(cx); + return NULL; + } + + /* + * Try to inherit flags by prefix. We assume there won't be more than a + * few (dozen! ;-) prefixes, so linear search is tolerable. + * XXXbe every time I've assumed that in the JS engine, I've been wrong! + */ + for (head = &rt->scriptFilenamePrefixes, link = head->next; + link != head; + link = link->next) { + sfp = (ScriptFilenamePrefix *) link; + if (!strncmp(sfp->name, filename, sfp->length)) { + sfe->flags |= sfp->flags; + break; + } + } + JS_RELEASE_LOCK(rt->scriptFilenameTableLock); + return sfe->filename; +} + +const char * +js_SaveScriptFilenameRT(JSRuntime *rt, const char *filename, uint32 flags) +{ + ScriptFilenameEntry *sfe; + + /* This may be called very early, via the jsdbgapi.h entry point. */ + if (!rt->scriptFilenameTable && !js_InitRuntimeScriptState(rt)) + return NULL; + + JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock); + sfe = SaveScriptFilename(rt, filename, flags); + JS_RELEASE_LOCK(rt->scriptFilenameTableLock); + if (!sfe) + return NULL; + + return sfe->filename; +} + +/* + * Back up from a saved filename by its offset within its hash table entry. + */ +#define FILENAME_TO_SFE(fn) \ + ((ScriptFilenameEntry *) ((fn) - offsetof(ScriptFilenameEntry, filename))) + +/* + * The sfe->key member, redundant given sfe->filename but required by the old + * jshash.c code, here gives us a useful sanity check. This assertion will + * very likely botch if someone tries to mark a string that wasn't allocated + * as an sfe->filename. + */ +#define ASSERT_VALID_SFE(sfe) JS_ASSERT((sfe)->key == (sfe)->filename) + +uint32 +js_GetScriptFilenameFlags(const char *filename) +{ + ScriptFilenameEntry *sfe; + + sfe = FILENAME_TO_SFE(filename); + ASSERT_VALID_SFE(sfe); + return sfe->flags; +} + +void +js_MarkScriptFilename(const char *filename) +{ + ScriptFilenameEntry *sfe; + + sfe = FILENAME_TO_SFE(filename); + ASSERT_VALID_SFE(sfe); + sfe->mark = JS_TRUE; +} + +static intN +js_script_filename_marker(JSHashEntry *he, intN i, void *arg) +{ + ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he; + + sfe->mark = JS_TRUE; + return HT_ENUMERATE_NEXT; +} + +void +js_MarkScriptFilenames(JSRuntime *rt) +{ + JSCList *head, *link; + ScriptFilenamePrefix *sfp; + + if (!rt->scriptFilenameTable) + return; + + if (rt->gcKeepAtoms) { + JS_HashTableEnumerateEntries(rt->scriptFilenameTable, + js_script_filename_marker, + rt); + } + for (head = &rt->scriptFilenamePrefixes, link = head->next; + link != head; + link = link->next) { + sfp = (ScriptFilenamePrefix *) link; + js_MarkScriptFilename(sfp->name); + } +} + +static intN +js_script_filename_sweeper(JSHashEntry *he, intN i, void *arg) +{ + ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he; + + if (!sfe->mark) + return HT_ENUMERATE_REMOVE; + sfe->mark = JS_FALSE; + return HT_ENUMERATE_NEXT; +} + +void +js_SweepScriptFilenames(JSRuntime *rt) +{ + if (!rt->scriptFilenameTable) + return; + + /* + * JS_HashTableEnumerateEntries shrinks the table if many entries are + * removed preventing wasting memory on a too sparse table. + */ + JS_HashTableEnumerateEntries(rt->scriptFilenameTable, + js_script_filename_sweeper, + rt); +#ifdef DEBUG_notme +#ifdef DEBUG_SFTBL + printf("script filename table savings so far: %u\n", sftbl_savings); +#endif +#endif +} + +/* + * JSScript data structures memory alignment: + * + * JSScript + * JSObjectArray script objects' descriptor if JSScript.objectsOffset != 0, + * use script->objects() to access it. + * JSObjectArray script regexps' descriptor if JSScript.regexpsOffset != 0, + * use script->regexps() to access it. + * JSTryNoteArray script try notes' descriptor if JSScript.tryNotesOffset + * != 0, use script->trynotes() to access it. + * JSAtom *a[] array of JSScript.atomMap.length atoms pointed by + * JSScript.atomMap.vector if any. + * JSObject *o[] array of script->objects()->length objects if any + * pointed by script->objects()->vector. + * JSObject *r[] array of script->regexps()->length regexps if any + * pointed by script->regexps()->vector. + * JSTryNote t[] array of script->trynotes()->length try notes if any + * pointed by script->trynotes()->vector. + * jsbytecode b[] script bytecode pointed by JSScript.code. + * jssrcnote s[] script source notes, use script->notes() to access it + * + * The alignment avoids gaps between entries as alignment requirement for each + * subsequent structure or array is the same or divides the alignment + * requirement for the previous one. + * + * The followings asserts checks that assuming that the alignment requirement + * for JSObjectArray and JSTryNoteArray are sizeof(void *) and for JSTryNote + * it is sizeof(uint32) as the structure consists of 3 uint32 fields. + */ +JS_STATIC_ASSERT(sizeof(JSScript) % sizeof(void *) == 0); +JS_STATIC_ASSERT(sizeof(JSObjectArray) % sizeof(void *) == 0); +JS_STATIC_ASSERT(sizeof(JSTryNoteArray) == sizeof(JSObjectArray)); +JS_STATIC_ASSERT(sizeof(JSAtom *) == sizeof(JSObject *)); +JS_STATIC_ASSERT(sizeof(JSObject *) % sizeof(uint32) == 0); +JS_STATIC_ASSERT(sizeof(JSTryNote) == 3 * sizeof(uint32)); +JS_STATIC_ASSERT(sizeof(uint32) % sizeof(jsbytecode) == 0); +JS_STATIC_ASSERT(sizeof(jsbytecode) % sizeof(jssrcnote) == 0); + +/* + * Check that uint8 offsets is enough to reach any optional array allocated + * after JSScript. For that we check that the maximum possible offset for + * JSConstArray, that last optional array, still fits 1 byte and do not + * coincide with INVALID_OFFSET. + */ +JS_STATIC_ASSERT(sizeof(JSObjectArray) + + sizeof(JSUpvarArray) + + sizeof(JSObjectArray) + + sizeof(JSTryNoteArray) + + sizeof(js::GlobalSlotArray) + < JSScript::INVALID_OFFSET); +JS_STATIC_ASSERT(JSScript::INVALID_OFFSET <= 255); + +JSScript * +JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms, + uint32 nobjects, uint32 nupvars, uint32 nregexps, + uint32 ntrynotes, uint32 nconsts, uint32 nglobals, + uint16 nClosedArgs, uint16 nClosedVars, JSVersion version) +{ + size_t size, vectorSize; + JSScript *script; + uint8 *cursor; + unsigned constPadding = 0; + + uint32 totalClosed = nClosedArgs + nClosedVars; + + size = sizeof(JSScript) + + sizeof(JSAtom *) * natoms; + + if (nobjects != 0) + size += sizeof(JSObjectArray) + nobjects * sizeof(JSObject *); + if (nupvars != 0) + size += sizeof(JSUpvarArray) + nupvars * sizeof(uint32); + if (nregexps != 0) + size += sizeof(JSObjectArray) + nregexps * sizeof(JSObject *); + if (ntrynotes != 0) + size += sizeof(JSTryNoteArray) + ntrynotes * sizeof(JSTryNote); + if (nglobals != 0) + size += sizeof(GlobalSlotArray) + nglobals * sizeof(GlobalSlotArray::Entry); + if (totalClosed != 0) + size += totalClosed * sizeof(uint32); + + if (nconsts != 0) { + size += sizeof(JSConstArray); + /* + * Calculate padding assuming that consts go after the other arrays, + * but before the bytecode and source notes. + */ + constPadding = (8 - (size % 8)) % 8; + size += constPadding + nconsts * sizeof(Value); + } + + size += length * sizeof(jsbytecode) + + nsrcnotes * sizeof(jssrcnote); + + script = (JSScript *) cx->malloc(size); + if (!script) + return NULL; + + PodZero(script); + script->length = length; + script->version = version; + new (&script->bindings) Bindings(cx); + + uint8 *scriptEnd = reinterpret_cast(script + 1); + + cursor = scriptEnd; + if (nobjects != 0) { + script->objectsOffset = (uint8)(cursor - scriptEnd); + cursor += sizeof(JSObjectArray); + } else { + script->objectsOffset = JSScript::INVALID_OFFSET; + } + if (nupvars != 0) { + script->upvarsOffset = (uint8)(cursor - scriptEnd); + cursor += sizeof(JSUpvarArray); + } else { + script->upvarsOffset = JSScript::INVALID_OFFSET; + } + if (nregexps != 0) { + script->regexpsOffset = (uint8)(cursor - scriptEnd); + cursor += sizeof(JSObjectArray); + } else { + script->regexpsOffset = JSScript::INVALID_OFFSET; + } + if (ntrynotes != 0) { + script->trynotesOffset = (uint8)(cursor - scriptEnd); + cursor += sizeof(JSTryNoteArray); + } else { + script->trynotesOffset = JSScript::INVALID_OFFSET; + } + if (nglobals != 0) { + script->globalsOffset = (uint8)(cursor - scriptEnd); + cursor += sizeof(GlobalSlotArray); + } else { + script->globalsOffset = JSScript::INVALID_OFFSET; + } + JS_ASSERT(cursor - scriptEnd < 0xFF); + if (nconsts != 0) { + script->constOffset = (uint8)(cursor - scriptEnd); + cursor += sizeof(JSConstArray); + } else { + script->constOffset = JSScript::INVALID_OFFSET; + } + + JS_STATIC_ASSERT(sizeof(JSObjectArray) + + sizeof(JSUpvarArray) + + sizeof(JSObjectArray) + + sizeof(JSTryNoteArray) + + sizeof(GlobalSlotArray) < 0xFF); + + if (natoms != 0) { + script->atomMap.length = natoms; + script->atomMap.vector = (JSAtom **)cursor; + vectorSize = natoms * sizeof(script->atomMap.vector[0]); + + /* + * Clear object map's vector so the GC tracing can run when not yet + * all atoms are copied to the array. + */ + memset(cursor, 0, vectorSize); + cursor += vectorSize; + } + + if (nobjects != 0) { + script->objects()->length = nobjects; + script->objects()->vector = (JSObject **)cursor; + vectorSize = nobjects * sizeof(script->objects()->vector[0]); + memset(cursor, 0, vectorSize); + cursor += vectorSize; + } + + if (nregexps != 0) { + script->regexps()->length = nregexps; + script->regexps()->vector = (JSObject **)cursor; + vectorSize = nregexps * sizeof(script->regexps()->vector[0]); + memset(cursor, 0, vectorSize); + cursor += vectorSize; + } + + if (ntrynotes != 0) { + script->trynotes()->length = ntrynotes; + script->trynotes()->vector = (JSTryNote *)cursor; + vectorSize = ntrynotes * sizeof(script->trynotes()->vector[0]); +#ifdef DEBUG + memset(cursor, 0, vectorSize); +#endif + cursor += vectorSize; + } + + if (nglobals != 0) { + script->globals()->length = nglobals; + script->globals()->vector = (GlobalSlotArray::Entry *)cursor; + vectorSize = nglobals * sizeof(script->globals()->vector[0]); + cursor += vectorSize; + } + + if (totalClosed != 0) { + script->nClosedArgs = nClosedArgs; + script->nClosedVars = nClosedVars; + script->closedSlots = (uint32 *)cursor; + cursor += totalClosed * sizeof(uint32); + } + + /* + * NB: We allocate the vector of uint32 upvar cookies after all vectors of + * pointers, to avoid misalignment on 64-bit platforms. See bug 514645. + */ + if (nupvars != 0) { + script->upvars()->length = nupvars; + script->upvars()->vector = reinterpret_cast(cursor); + vectorSize = nupvars * sizeof(script->upvars()->vector[0]); + memset(cursor, 0, vectorSize); + cursor += vectorSize; + } + + /* Must go after other arrays; see constPadding definition. */ + if (nconsts != 0) { + cursor += constPadding; + script->consts()->length = nconsts; + script->consts()->vector = (Value *)cursor; + JS_ASSERT((size_t)cursor % sizeof(double) == 0); + vectorSize = nconsts * sizeof(script->consts()->vector[0]); + memset(cursor, 0, vectorSize); + cursor += vectorSize; + } + + script->code = script->main = (jsbytecode *)cursor; + JS_ASSERT(cursor + + length * sizeof(jsbytecode) + + nsrcnotes * sizeof(jssrcnote) == + (uint8 *)script + size); + + script->compartment = cx->compartment; +#ifdef CHECK_SCRIPT_OWNER + script->owner = cx->thread; +#endif + + JS_APPEND_LINK(&script->links, &cx->compartment->scripts); + JS_ASSERT(script->getVersion() == version); + return script; +} + +JSScript * +JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg) +{ + uint32 mainLength, prologLength, nsrcnotes, nfixed; + JSScript *script; + const char *filename; + JSFunction *fun; + + /* The counts of indexed things must be checked during code generation. */ + JS_ASSERT(cg->atomList.count <= INDEX_LIMIT); + JS_ASSERT(cg->objectList.length <= INDEX_LIMIT); + JS_ASSERT(cg->regexpList.length <= INDEX_LIMIT); + + mainLength = CG_OFFSET(cg); + prologLength = CG_PROLOG_OFFSET(cg); + + CG_COUNT_FINAL_SRCNOTES(cg, nsrcnotes); + uint16 nClosedArgs = uint16(cg->closedArgs.length()); + JS_ASSERT(nClosedArgs == cg->closedArgs.length()); + uint16 nClosedVars = uint16(cg->closedVars.length()); + JS_ASSERT(nClosedVars == cg->closedVars.length()); + script = NewScript(cx, prologLength + mainLength, nsrcnotes, + cg->atomList.count, cg->objectList.length, + cg->upvarList.count, cg->regexpList.length, + cg->ntrynotes, cg->constList.length(), + cg->globalUses.length(), nClosedArgs, nClosedVars, cg->version()); + if (!script) + return NULL; + + /* Now that we have script, error control flow must go to label bad. */ + script->main += prologLength; + memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode)); + memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode)); + nfixed = cg->inFunction() + ? cg->bindings.countVars() + : cg->sharpSlots(); + JS_ASSERT(nfixed < SLOTNO_LIMIT); + script->nfixed = (uint16) nfixed; + js_InitAtomMap(cx, &script->atomMap, &cg->atomList); + + filename = cg->parser->tokenStream.getFilename(); + if (filename) { + script->filename = js_SaveScriptFilename(cx, filename); + if (!script->filename) + goto bad; + } + script->lineno = cg->firstLine; + if (script->nfixed + cg->maxStackDepth >= JS_BIT(16)) { + ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, JSMSG_NEED_DIET, "script"); + goto bad; + } + script->nslots = script->nfixed + cg->maxStackDepth; + script->staticLevel = uint16(cg->staticLevel); + script->principals = cg->parser->principals; + if (script->principals) + JSPRINCIPALS_HOLD(cx, script->principals); + + if (!js_FinishTakingSrcNotes(cx, cg, script->notes())) + goto bad; + if (cg->ntrynotes != 0) + js_FinishTakingTryNotes(cg, script->trynotes()); + if (cg->objectList.length != 0) + cg->objectList.finish(script->objects()); + if (cg->regexpList.length != 0) + cg->regexpList.finish(script->regexps()); + if (cg->constList.length() != 0) + cg->constList.finish(script->consts()); + if (cg->flags & TCF_NO_SCRIPT_RVAL) + script->noScriptRval = true; + if (cg->hasSharps()) + script->hasSharps = true; + if (cg->flags & TCF_STRICT_MODE_CODE) + script->strictModeCode = true; + if (cg->flags & TCF_COMPILE_N_GO) + script->compileAndGo = true; + if (cg->callsEval()) + script->usesEval = true; + if (cg->flags & TCF_FUN_USES_ARGUMENTS) + script->usesArguments = true; + if (cg->flags & TCF_HAS_SINGLETONS) + script->hasSingletons = true; + + if (cg->upvarList.count != 0) { + JS_ASSERT(cg->upvarList.count <= cg->upvarMap.length); + memcpy(script->upvars()->vector, cg->upvarMap.vector, + cg->upvarList.count * sizeof(uint32)); + cg->upvarList.clear(); + cx->free(cg->upvarMap.vector); + cg->upvarMap.vector = NULL; + } + + if (cg->globalUses.length()) { + memcpy(script->globals()->vector, &cg->globalUses[0], + cg->globalUses.length() * sizeof(GlobalSlotArray::Entry)); + } + + if (script->nClosedArgs) + memcpy(script->closedSlots, &cg->closedArgs[0], script->nClosedArgs * sizeof(uint32)); + if (script->nClosedVars) { + memcpy(&script->closedSlots[script->nClosedArgs], &cg->closedVars[0], + script->nClosedVars * sizeof(uint32)); + } + + cg->bindings.makeImmutable(); + script->bindings.transfer(cx, &cg->bindings); + + /* + * We initialize fun->u.script to be the script constructed above + * so that the debugger has a valid FUN_SCRIPT(fun). + */ + fun = NULL; + if (cg->inFunction()) { + fun = cg->fun(); + JS_ASSERT(fun->isInterpreted()); + JS_ASSERT(!fun->script()); +#ifdef DEBUG + if (JSScript::isValidOffset(script->upvarsOffset)) + JS_ASSERT(script->upvars()->length == script->bindings.countUpvars()); + else + JS_ASSERT(script->bindings.countUpvars() == 0); +#endif + fun->u.i.script = script; +#ifdef CHECK_SCRIPT_OWNER + script->owner = NULL; +#endif + if (cg->flags & TCF_FUN_HEAVYWEIGHT) + fun->flags |= JSFUN_HEAVYWEIGHT; + } + + /* Tell the debugger about this compiled script. */ + js_CallNewScriptHook(cx, script, fun); +#ifdef DEBUG + { + jsrefcount newEmptyLive, newLive, newTotal; + if (script->isEmpty()) { + newEmptyLive = JS_RUNTIME_METER(cx->runtime, liveEmptyScripts); + newLive = cx->runtime->liveScripts; + newTotal = + JS_RUNTIME_METER(cx->runtime, totalEmptyScripts) + cx->runtime->totalScripts; + } else { + newEmptyLive = cx->runtime->liveEmptyScripts; + newLive = JS_RUNTIME_METER(cx->runtime, liveScripts); + newTotal = + cx->runtime->totalEmptyScripts + JS_RUNTIME_METER(cx->runtime, totalScripts); + } + + jsrefcount oldHigh = cx->runtime->highWaterLiveScripts; + if (newEmptyLive + newLive > oldHigh) { + JS_ATOMIC_SET(&cx->runtime->highWaterLiveScripts, newEmptyLive + newLive); + if (getenv("JS_DUMP_LIVE_SCRIPTS")) { + fprintf(stderr, "high water script count: %d empty, %d not (total %d)\n", + newEmptyLive, newLive, newTotal); + } + } + } +#endif + + return script; + +bad: + js_DestroyScript(cx, script); + return NULL; +} + +JS_FRIEND_API(void) +js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun) +{ + JSNewScriptHook hook; + + hook = cx->debugHooks->newScriptHook; + if (hook) { + AutoKeepAtoms keep(cx->runtime); + hook(cx, script->filename, script->lineno, script, fun, + cx->debugHooks->newScriptHookData); + } +} + +void +js_CallDestroyScriptHook(JSContext *cx, JSScript *script) +{ + JSDestroyScriptHook hook; + + hook = cx->debugHooks->destroyScriptHook; + if (hook) + hook(cx, script, cx->debugHooks->destroyScriptHookData); + JS_ClearScriptTraps(cx, script); +} + +static void +DestroyScript(JSContext *cx, JSScript *script) +{ +#ifdef DEBUG + if (script->isEmpty()) + JS_RUNTIME_UNMETER(cx->runtime, liveEmptyScripts); + else + JS_RUNTIME_UNMETER(cx->runtime, liveScripts); +#endif + + if (script->principals) + JSPRINCIPALS_DROP(cx, script->principals); + + if (JS_GSN_CACHE(cx).code == script->code) + JS_PURGE_GSN_CACHE(cx); + + /* + * Worry about purging the property cache and any compiled traces related + * to its bytecode if this script is being destroyed from JS_DestroyScript + * or equivalent according to a mandatory "New/Destroy" protocol. + * + * The GC purges all property caches when regenerating shapes upon shape + * generator overflow, so no need in that event to purge just the entries + * for this script. + * + * The GC purges trace-JITted code on every GC activation, not just when + * regenerating shapes, so we don't have to purge fragments if the GC is + * currently running. + * + * JS_THREADSAFE note: The code below purges only the current thread's + * property cache, so a script not owned by a function or object, which + * hands off lifetime management for that script to the GC, must be used by + * only one thread over its lifetime. + * + * This should be an API-compatible change, since a script is never safe + * against premature GC if shared among threads without a rooted object + * wrapping it to protect the script's mapped atoms against GC. We use + * script->owner to enforce this requirement via assertions. + */ +#ifdef CHECK_SCRIPT_OWNER + JS_ASSERT_IF(cx->runtime->gcRunning, !script->owner); +#endif + + /* FIXME: bug 506341; would like to do this only if regenerating shapes. */ + if (!cx->runtime->gcRunning) { + JS_PROPERTY_CACHE(cx).purgeForScript(cx, script); + +#ifdef CHECK_SCRIPT_OWNER + JS_ASSERT(script->owner == cx->thread); +#endif + } + +#ifdef JS_TRACER + PurgeScriptFragments(&script->compartment->traceMonitor, script); +#endif + +#if defined(JS_METHODJIT) + mjit::ReleaseScriptCode(cx, script); +#endif + JS_REMOVE_LINK(&script->links); + + cx->free(script); +} + +void +js_DestroyScript(JSContext *cx, JSScript *script) +{ + JS_ASSERT(!cx->runtime->gcRunning); + js_CallDestroyScriptHook(cx, script); + DestroyScript(cx, script); +} + +void +js_DestroyScriptFromGC(JSContext *cx, JSScript *script) +{ + JS_ASSERT(cx->runtime->gcRunning); + js_CallDestroyScriptHook(cx, script); + DestroyScript(cx, script); +} + +void +js_DestroyCachedScript(JSContext *cx, JSScript *script) +{ + JS_ASSERT(cx->runtime->gcRunning); + DestroyScript(cx, script); +} + +void +js_TraceScript(JSTracer *trc, JSScript *script) +{ + JSAtomMap *map = &script->atomMap; + MarkAtomRange(trc, map->length, map->vector, "atomMap"); + + if (JSScript::isValidOffset(script->objectsOffset)) { + JSObjectArray *objarray = script->objects(); + uintN i = objarray->length; + do { + --i; + if (objarray->vector[i]) { + JS_SET_TRACING_INDEX(trc, "objects", i); + Mark(trc, objarray->vector[i]); + } + } while (i != 0); + } + + if (JSScript::isValidOffset(script->regexpsOffset)) { + JSObjectArray *objarray = script->regexps(); + uintN i = objarray->length; + do { + --i; + if (objarray->vector[i]) { + JS_SET_TRACING_INDEX(trc, "regexps", i); + Mark(trc, objarray->vector[i]); + } + } while (i != 0); + } + + if (JSScript::isValidOffset(script->constOffset)) { + JSConstArray *constarray = script->consts(); + MarkValueRange(trc, constarray->length, constarray->vector, "consts"); + } + + if (script->u.object) { + JS_SET_TRACING_NAME(trc, "object"); + Mark(trc, script->u.object); + } + + if (IS_GC_MARKING_TRACER(trc) && script->filename) + js_MarkScriptFilename(script->filename); + + script->bindings.trace(trc); +} + +JSObject * +js_NewScriptObject(JSContext *cx, JSScript *script) +{ + AutoScriptRooter root(cx, script); + + JS_ASSERT(!script->u.object); + + JSObject *obj = NewNonFunction(cx, &js_ScriptClass, NULL, NULL); + if (!obj) + return NULL; + obj->setPrivate(script); + script->u.object = obj; + + /* + * Clear the object's proto, to avoid entraining stuff. Once we no longer use the parent + * for security checks, then we can clear the parent, too. + */ + obj->clearProto(); + +#ifdef CHECK_SCRIPT_OWNER + script->owner = NULL; +#endif + + return obj; +} + +typedef struct GSNCacheEntry { + JSDHashEntryHdr hdr; + jsbytecode *pc; + jssrcnote *sn; +} GSNCacheEntry; + +#define GSN_CACHE_THRESHOLD 100 + +void +js_PurgeGSNCache(JSGSNCache *cache) +{ + cache->code = NULL; + if (cache->table.ops) { + JS_DHashTableFinish(&cache->table); + cache->table.ops = NULL; + } + GSN_CACHE_METER(cache, purges); +} + +jssrcnote * +js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + ptrdiff_t target, offset; + GSNCacheEntry *entry; + jssrcnote *sn, *result; + uintN nsrcnotes; + + + target = pc - script->code; + if ((uint32)target >= script->length) + return NULL; + + if (JS_GSN_CACHE(cx).code == script->code) { + JS_METER_GSN_CACHE(cx, hits); + entry = (GSNCacheEntry *) + JS_DHashTableOperate(&JS_GSN_CACHE(cx).table, pc, + JS_DHASH_LOOKUP); + return entry->sn; + } + + JS_METER_GSN_CACHE(cx, misses); + offset = 0; + for (sn = script->notes(); ; sn = SN_NEXT(sn)) { + if (SN_IS_TERMINATOR(sn)) { + result = NULL; + break; + } + offset += SN_DELTA(sn); + if (offset == target && SN_IS_GETTABLE(sn)) { + result = sn; + break; + } + } + + if (JS_GSN_CACHE(cx).code != script->code && + script->length >= GSN_CACHE_THRESHOLD) { + JS_PURGE_GSN_CACHE(cx); + nsrcnotes = 0; + for (sn = script->notes(); !SN_IS_TERMINATOR(sn); + sn = SN_NEXT(sn)) { + if (SN_IS_GETTABLE(sn)) + ++nsrcnotes; + } + if (!JS_DHashTableInit(&JS_GSN_CACHE(cx).table, JS_DHashGetStubOps(), + NULL, sizeof(GSNCacheEntry), + JS_DHASH_DEFAULT_CAPACITY(nsrcnotes))) { + JS_GSN_CACHE(cx).table.ops = NULL; + } else { + pc = script->code; + for (sn = script->notes(); !SN_IS_TERMINATOR(sn); + sn = SN_NEXT(sn)) { + pc += SN_DELTA(sn); + if (SN_IS_GETTABLE(sn)) { + entry = (GSNCacheEntry *) + JS_DHashTableOperate(&JS_GSN_CACHE(cx).table, pc, + JS_DHASH_ADD); + entry->pc = pc; + entry->sn = sn; + } + } + JS_GSN_CACHE(cx).code = script->code; + JS_METER_GSN_CACHE(cx, fills); + } + } + + return result; +} + +uintN +js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp) +{ + return js_PCToLineNumber(cx, fp->script(), + fp->hasImacropc() ? fp->imacropc() : fp->pc(cx)); +} + +uintN +js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + JSOp op; + JSFunction *fun; + uintN lineno; + ptrdiff_t offset, target; + jssrcnote *sn; + JSSrcNoteType type; + + /* Cope with JSStackFrame.pc value prior to entering js_Interpret. */ + if (!pc) + return 0; + + /* + * Special case: function definition needs no line number note because + * the function's script contains its starting line number. + */ + op = js_GetOpcode(cx, script, pc); + if (js_CodeSpec[op].format & JOF_INDEXBASE) + pc += js_CodeSpec[op].length; + if (*pc == JSOP_DEFFUN) { + GET_FUNCTION_FROM_BYTECODE(script, pc, 0, fun); + return fun->u.i.script->lineno; + } + + /* + * General case: walk through source notes accumulating their deltas, + * keeping track of line-number notes, until we pass the note for pc's + * offset within script->code. + */ + lineno = script->lineno; + offset = 0; + target = pc - script->code; + for (sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { + offset += SN_DELTA(sn); + type = (JSSrcNoteType) SN_TYPE(sn); + if (type == SRC_SETLINE) { + if (offset <= target) + lineno = (uintN) js_GetSrcNoteOffset(sn, 0); + } else if (type == SRC_NEWLINE) { + if (offset <= target) + lineno++; + } + if (offset > target) + break; + } + return lineno; +} + +/* The line number limit is the same as the jssrcnote offset limit. */ +#define SN_LINE_LIMIT (SN_3BYTE_OFFSET_FLAG << 16) + +jsbytecode * +js_LineNumberToPC(JSScript *script, uintN target) +{ + ptrdiff_t offset, best; + uintN lineno, bestdiff, diff; + jssrcnote *sn; + JSSrcNoteType type; + + offset = 0; + best = -1; + lineno = script->lineno; + bestdiff = SN_LINE_LIMIT; + for (sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { + /* + * Exact-match only if offset is not in the prolog; otherwise use + * nearest greater-or-equal line number match. + */ + if (lineno == target && script->code + offset >= script->main) + goto out; + if (lineno >= target) { + diff = lineno - target; + if (diff < bestdiff) { + bestdiff = diff; + best = offset; + } + } + offset += SN_DELTA(sn); + type = (JSSrcNoteType) SN_TYPE(sn); + if (type == SRC_SETLINE) { + lineno = (uintN) js_GetSrcNoteOffset(sn, 0); + } else if (type == SRC_NEWLINE) { + lineno++; + } + } + if (best >= 0) + offset = best; +out: + return script->code + offset; +} + +JS_FRIEND_API(uintN) +js_GetScriptLineExtent(JSScript *script) +{ + uintN lineno; + jssrcnote *sn; + JSSrcNoteType type; + + lineno = script->lineno; + for (sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { + type = (JSSrcNoteType) SN_TYPE(sn); + if (type == SRC_SETLINE) { + lineno = (uintN) js_GetSrcNoteOffset(sn, 0); + } else if (type == SRC_NEWLINE) { + lineno++; + } + } + return 1 + lineno - script->lineno; +} + +class DisablePrincipalsTranscoding { + JSSecurityCallbacks *callbacks; + JSPrincipalsTranscoder temp; + + public: + DisablePrincipalsTranscoding(JSContext *cx) + : callbacks(JS_GetRuntimeSecurityCallbacks(cx->runtime)), + temp(NULL) + { + if (callbacks) { + temp = callbacks->principalsTranscoder; + callbacks->principalsTranscoder = NULL; + } + } + + ~DisablePrincipalsTranscoding() { + if (callbacks) + callbacks->principalsTranscoder = temp; + } +}; + +JSScript * +js_CloneScript(JSContext *cx, JSScript *script) +{ + JS_ASSERT(cx->compartment != script->compartment); + JS_ASSERT(script->compartment); + + // serialize script + JSXDRState *w = JS_XDRNewMem(cx, JSXDR_ENCODE); + if (!w) + return NULL; + + // we don't want gecko to transcribe our principals for us + DisablePrincipalsTranscoding disable(cx); + + if (!js_XDRScript(w, &script, NULL)) { + JS_XDRDestroy(w); + return NULL; + } + + uint32 nbytes; + void *p = JS_XDRMemGetData(w, &nbytes); + if (!p) { + JS_XDRDestroy(w); + return NULL; + } + + // de-serialize script + JSXDRState *r = JS_XDRNewMem(cx, JSXDR_DECODE); + if (!r) { + JS_XDRDestroy(w); + return NULL; + } + + // Hand p off from w to r. Don't want them to share the data + // mem, lest they both try to free it in JS_XDRDestroy + JS_XDRMemSetData(r, p, nbytes); + JS_XDRMemSetData(w, NULL, 0); + + if (!js_XDRScript(r, &script, NULL)) + return NULL; + + JS_XDRDestroy(r); + JS_XDRDestroy(w); + + // set the proper principals for the script + script->principals = script->compartment->principals; + if (script->principals) + JSPRINCIPALS_HOLD(cx, script->principals); + + return script; +} + +void +JSScript::copyClosedSlotsTo(JSScript *other) +{ + memcpy(other->closedSlots, closedSlots, nClosedArgs + nClosedVars); +} diff --git a/js/src/jsscript.h b/js/src/jsscript.h new file mode 100644 index 0000000..a1c3717 --- /dev/null +++ b/js/src/jsscript.h @@ -0,0 +1,750 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=79 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsscript_h___ +#define jsscript_h___ +/* + * JS script descriptor. + */ +#include "jsatom.h" +#include "jsprvtd.h" +#include "jsdbgapi.h" +#include "jsclist.h" + +/* + * Type of try note associated with each catch or finally block, and also with + * for-in loops. + */ +typedef enum JSTryNoteKind { + JSTRY_CATCH, + JSTRY_FINALLY, + JSTRY_ITER +} JSTryNoteKind; + +namespace js { + +/* + * Indicates a location in the stack that an upvar value can be retrieved from + * as a two tuple of (level, slot). + * + * Some existing client code uses the level value as a delta, or level "skip" + * quantity. We could probably document that through use of more types at some + * point in the future. + * + * Existing XDR code wants this to be backed by a 32b integer for serialization, + * so we oblige. + * + * TODO: consider giving more bits to the slot value and takings ome from the level. + */ +class UpvarCookie +{ + uint32 value; + + static const uint32 FREE_VALUE = 0xfffffffful; + + void checkInvariants() { + JS_STATIC_ASSERT(sizeof(UpvarCookie) == sizeof(uint32)); + JS_STATIC_ASSERT(UPVAR_LEVEL_LIMIT < FREE_LEVEL); + } + + public: + /* + * All levels above-and-including FREE_LEVEL are reserved so that + * FREE_VALUE can be used as a special value. + */ + static const uint16 FREE_LEVEL = 0x3fff; + + /* + * If a function has a higher static level than this limit, we will not + * optimize it using UPVAR opcodes. + */ + static const uint16 UPVAR_LEVEL_LIMIT = 16; + static const uint16 CALLEE_SLOT = 0xffff; + static bool isLevelReserved(uint16 level) { return level >= FREE_LEVEL; } + + bool isFree() const { return value == FREE_VALUE; } + uint32 asInteger() const { return value; } + /* isFree check should be performed before using these accessors. */ + uint16 level() const { JS_ASSERT(!isFree()); return uint16(value >> 16); } + uint16 slot() const { JS_ASSERT(!isFree()); return uint16(value); } + + void set(const UpvarCookie &other) { set(other.level(), other.slot()); } + void set(uint16 newLevel, uint16 newSlot) { value = (uint32(newLevel) << 16) | newSlot; } + void makeFree() { set(0xffff, 0xffff); JS_ASSERT(isFree()); } + void fromInteger(uint32 u32) { value = u32; } +}; + +} + +/* + * Exception handling record. + */ +struct JSTryNote { + uint8 kind; /* one of JSTryNoteKind */ + uint8 padding; /* explicit padding on uint16 boundary */ + uint16 stackDepth; /* stack depth upon exception handler entry */ + uint32 start; /* start of the try statement or for-in loop + relative to script->main */ + uint32 length; /* length of the try statement or for-in loop */ +}; + +typedef struct JSTryNoteArray { + JSTryNote *vector; /* array of indexed try notes */ + uint32 length; /* count of indexed try notes */ +} JSTryNoteArray; + +typedef struct JSObjectArray { + JSObject **vector; /* array of indexed objects */ + uint32 length; /* count of indexed objects */ +} JSObjectArray; + +typedef struct JSUpvarArray { + js::UpvarCookie *vector; /* array of indexed upvar cookies */ + uint32 length; /* count of indexed upvar cookies */ +} JSUpvarArray; + +typedef struct JSConstArray { + js::Value *vector; /* array of indexed constant values */ + uint32 length; +} JSConstArray; + +struct JSArenaPool; + +namespace js { + +struct GlobalSlotArray { + struct Entry { + uint32 atomIndex; /* index into atom table */ + uint32 slot; /* global obj slot number */ + }; + Entry *vector; + uint32 length; +}; + +struct Shape; + +enum BindingKind { NONE, ARGUMENT, VARIABLE, CONSTANT, UPVAR }; + +/* + * Formal parameters, local variables, and upvars are stored in a shape tree + * path encapsulated within this class. This class represents bindings for + * both function and top-level scripts (the latter is needed to track names in + * strict mode eval code, to give such code its own lexical environment). + */ +class Bindings { + js::Shape *lastBinding; + uint16 nargs; + uint16 nvars; + uint16 nupvars; + + public: + inline Bindings(JSContext *cx); + + /* + * Transfers ownership of bindings data from bindings into this fresh + * Bindings instance. Once such a transfer occurs, the old bindings must + * not be used again. + */ + inline void transfer(JSContext *cx, Bindings *bindings); + + /* + * Clones bindings data from bindings, which must be immutable, into this + * fresh Bindings instance. A Bindings instance may be cloned multiple + * times. + */ + inline void clone(JSContext *cx, Bindings *bindings); + + uint16 countArgs() const { return nargs; } + uint16 countVars() const { return nvars; } + uint16 countUpvars() const { return nupvars; } + + uintN countArgsAndVars() const { return nargs + nvars; } + + uintN countLocalNames() const { return nargs + nvars + nupvars; } + + bool hasUpvars() const { return nupvars > 0; } + bool hasLocalNames() const { return countLocalNames() > 0; } + + /* Returns the shape lineage generated for these bindings. */ + inline const js::Shape *lastShape() const; + + enum { + /* + * A script may have no more than this many arguments, variables, or + * upvars. + */ + BINDING_COUNT_LIMIT = 0xFFFF + }; + + /* + * Add a local binding for the given name, of the given type, for the code + * being compiled. If fun is non-null, this binding set is being created + * for that function, so adjust corresponding metadata in that function + * while adding. Otherwise this set must correspond to a top-level script. + * + * A binding may be added twice with different kinds; the last one for a + * given name prevails. (We preserve both bindings for the decompiler, + * which must deal with such cases.) Pass null for name when indicating a + * destructuring argument. Return true on success. + * + * The parser builds shape paths for functions, usable by Call objects at + * runtime, by calling an "add" method. All ARGUMENT bindings must be added + * before before any VARIABLE or CONSTANT bindings, which themselves must + * be added before all UPVAR bindings. + */ + bool add(JSContext *cx, JSAtom *name, BindingKind kind); + + /* Convenience specializations. */ + bool addVariable(JSContext *cx, JSAtom *name) { + return add(cx, name, VARIABLE); + } + bool addConstant(JSContext *cx, JSAtom *name) { + return add(cx, name, CONSTANT); + } + bool addUpvar(JSContext *cx, JSAtom *name) { + return add(cx, name, UPVAR); + } + bool addArgument(JSContext *cx, JSAtom *name, uint16 *slotp) { + JS_ASSERT(name != NULL); /* not destructuring */ + *slotp = nargs; + return add(cx, name, ARGUMENT); + } + bool addDestructuring(JSContext *cx, uint16 *slotp) { + *slotp = nargs; + return add(cx, NULL, ARGUMENT); + } + + /* + * Look up an argument or variable name, returning its kind when found or + * NONE when no such name exists. When indexp is not null and the name + * exists, *indexp will receive the index of the corresponding argument or + * variable. + */ + BindingKind lookup(JSContext *cx, JSAtom *name, uintN *indexp) const; + + /* Convenience method to check for any binding for a name. */ + bool hasBinding(JSContext *cx, JSAtom *name) const { + return lookup(cx, name, NULL) != NONE; + } + + /* + * Function and macros to work with local names as an array of words. + * getLocalNameArray returns the array, or null if we are out of memory. + * This function must be called only when hasLocalNames(). + * + * The supplied pool is used to allocate the returned array, so the caller + * is obligated to mark and release to free it. + * + * The elements of the array with index less than nargs correspond to the + * the names of arguments. An index >= nargs addresses a var binding. Use + * JS_LOCAL_NAME_TO_ATOM to convert array's element to an atom pointer. + * This pointer can be null when the element is for an argument + * corresponding to a destructuring pattern. + * + * If nameWord does not name an argument, use JS_LOCAL_NAME_IS_CONST to + * check if nameWord corresponds to the const declaration. + */ + jsuword * + getLocalNameArray(JSContext *cx, JSArenaPool *pool); + + /* + * Returns the slot where the sharp array is stored, or a value < 0 if no + * sharps are present or in case of failure. + */ + int sharpSlotBase(JSContext *cx); + + /* + * Protect stored bindings from mutation. Subsequent attempts to add + * bindings will copy the existing bindings before adding to them, allowing + * the original bindings to be safely shared. + */ + void makeImmutable(); + + /* + * These methods provide direct access to the shape path normally + * encapsulated by js::Bindings. These methods may be used to make a + * Shape::Range for iterating over the relevant shapes from youngest to + * oldest (i.e., last or right-most to first or left-most in source order). + * + * Sometimes iteration order must be from oldest to youngest, however. For + * such cases, use js::Bindings::getLocalNameArray. The RAII class + * js::AutoLocalNameArray, defined in jscntxt.h, should be used where + * possible instead of direct calls to getLocalNameArray. + */ + const js::Shape *lastArgument() const; + const js::Shape *lastVariable() const; + const js::Shape *lastUpvar() const; + + void trace(JSTracer *trc); +}; + +} /* namespace js */ + +#define JS_OBJECT_ARRAY_SIZE(length) \ + (offsetof(JSObjectArray, vector) + sizeof(JSObject *) * (length)) + +#if defined DEBUG && defined JS_THREADSAFE +# define CHECK_SCRIPT_OWNER 1 +#endif + +#ifdef JS_METHODJIT +namespace JSC { + class ExecutablePool; +} + +#define JS_UNJITTABLE_SCRIPT (reinterpret_cast(1)) + +enum JITScriptStatus { + JITScript_None, + JITScript_Invalid, + JITScript_Valid +}; + +namespace js { +namespace mjit { + +struct JITScript; + +} +} +#endif + +struct JSScript { + /* + * Two successively less primitive ways to make a new JSScript. The first + * does *not* call a non-null cx->runtime->newScriptHook -- only the second, + * NewScriptFromCG, calls this optional debugger hook. + * + * The NewScript function can't know whether the script it creates belongs + * to a function, or is top-level or eval code, but the debugger wants access + * to the newly made script's function, if any -- so callers of NewScript + * are responsible for notifying the debugger after successfully creating any + * kind (function or other) of new JSScript. + */ + static JSScript *NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms, + uint32 nobjects, uint32 nupvars, uint32 nregexps, + uint32 ntrynotes, uint32 nconsts, uint32 nglobals, + uint16 nClosedArgs, uint16 nClosedVars, JSVersion version); + + static JSScript *NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg); + + /* FIXME: bug 586181 */ + JSCList links; /* Links for compartment script list */ + jsbytecode *code; /* bytecodes and their immediate operands */ + uint32 length; /* length of code vector */ + + private: + uint16 version; /* JS version under which script was compiled */ + + size_t callCount_; /* Number of times the script has been called. */ + + public: + uint16 nfixed; /* number of slots besides stack operands in + slot array */ + + /* + * Offsets to various array structures from the end of this script, or + * JSScript::INVALID_OFFSET if the array has length 0. + */ + uint8 objectsOffset; /* offset to the array of nested function, + block, scope, xml and one-time regexps + objects */ + uint8 upvarsOffset; /* offset of the array of display ("up") + closure vars */ + uint8 regexpsOffset; /* offset to the array of to-be-cloned + regexps */ + uint8 trynotesOffset; /* offset to the array of try notes */ + uint8 globalsOffset; /* offset to the array of global slots */ + uint8 constOffset; /* offset to the array of constants */ + + bool noScriptRval:1; /* no need for result value of last + expression statement */ + bool savedCallerFun:1; /* object 0 is caller function */ + bool hasSharps:1; /* script uses sharp variables */ + bool strictModeCode:1; /* code is in strict mode */ + bool compileAndGo:1; /* script was compiled with TCF_COMPILE_N_GO */ + bool usesEval:1; /* script uses eval() */ + bool usesArguments:1; /* script uses arguments */ + bool warnedAboutTwoArgumentEval:1; /* have warned about use of + obsolete eval(s, o) in + this script */ + bool hasSingletons:1; /* script has singleton objects */ +#ifdef JS_METHODJIT + bool debugMode:1; /* script was compiled in debug mode */ + bool singleStepMode:1; /* compile script in single-step mode */ +#endif + + jsbytecode *main; /* main entry point, after predef'ing prolog */ + JSAtomMap atomMap; /* maps immediate index to literal struct */ + JSCompartment *compartment; /* compartment the script was compiled for */ + const char *filename; /* source filename or null */ + uint32 lineno; /* base line number of script */ + uint16 nslots; /* vars plus maximum stack depth */ + uint16 staticLevel;/* static level for display maintenance */ + uint16 nClosedArgs; /* number of args which are closed over. */ + uint16 nClosedVars; /* number of vars which are closed over. */ + js::Bindings bindings; /* names of top-level variables in this script + (and arguments if this is a function script) */ + JSPrincipals *principals;/* principals for this script */ + union { + /* + * A script object of class js_ScriptClass, to ensure the script is GC'd. + * - All scripts returned by JSAPI functions (JS_CompileScript, + * JS_CompileFile, etc.) have these objects. + * - Function scripts never have script objects; such scripts are owned + * by their function objects. + * - Temporary scripts created by obj_eval, JS_EvaluateScript, and + * similar functions never have these objects; such scripts are + * explicitly destroyed by the code that created them. + * Debugging API functions (JSDebugHooks::newScriptHook; + * JS_GetFunctionScript) may reveal sans-script-object Function and + * temporary scripts to clients, but clients must never call + * JS_NewScriptObject on such scripts: doing so would double-free them, + * once from the explicit call to js_DestroyScript, and once when the + * script object is garbage collected. + */ + JSObject *object; + JSScript *nextToGC; /* next to GC in rt->scriptsToGC list */ + } u; + +#ifdef CHECK_SCRIPT_OWNER + JSThread *owner; /* for thread-safe life-cycle assertions */ +#endif + + uint32 *closedSlots; /* vector of closed slots; args first, then vars. */ + + public: +#ifdef JS_METHODJIT + // Fast-cached pointers to make calls faster. These are also used to + // quickly test whether there is JIT code; a NULL value means no + // compilation has been attempted. A JS_UNJITTABLE_SCRIPT value means + // compilation failed. Any value is the arity-check entry point. + void *jitArityCheckNormal; + void *jitArityCheckCtor; + + js::mjit::JITScript *jitNormal; /* Extra JIT info for normal scripts */ + js::mjit::JITScript *jitCtor; /* Extra JIT info for constructors */ + + bool hasJITCode() { + return jitNormal || jitCtor; + } + + // These methods are implemented in MethodJIT.h. + inline void **nativeMap(bool constructing); + inline void *maybeNativeCodeForPC(bool constructing, jsbytecode *pc); + inline void *nativeCodeForPC(bool constructing, jsbytecode *pc); + + js::mjit::JITScript *getJIT(bool constructing) { + return constructing ? jitCtor : jitNormal; + } + + size_t callCount() const { return callCount_; } + size_t incCallCount() { return ++callCount_; } + + JITScriptStatus getJITStatus(bool constructing) { + void *addr = constructing ? jitArityCheckCtor : jitArityCheckNormal; + if (addr == NULL) + return JITScript_None; + if (addr == JS_UNJITTABLE_SCRIPT) + return JITScript_Invalid; + return JITScript_Valid; + } +#endif + + /* Script notes are allocated right after the code. */ + jssrcnote *notes() { return (jssrcnote *)(code + length); } + + static const uint8 INVALID_OFFSET = 0xFF; + static bool isValidOffset(uint8 offset) { return offset != INVALID_OFFSET; } + + JSObjectArray *objects() { + JS_ASSERT(isValidOffset(objectsOffset)); + return (JSObjectArray *)((uint8 *) (this + 1) + objectsOffset); + } + + JSUpvarArray *upvars() { + JS_ASSERT(isValidOffset(upvarsOffset)); + return (JSUpvarArray *) ((uint8 *) (this + 1) + upvarsOffset); + } + + JSObjectArray *regexps() { + JS_ASSERT(isValidOffset(regexpsOffset)); + return (JSObjectArray *) ((uint8 *) (this + 1) + regexpsOffset); + } + + JSTryNoteArray *trynotes() { + JS_ASSERT(isValidOffset(trynotesOffset)); + return (JSTryNoteArray *) ((uint8 *) (this + 1) + trynotesOffset); + } + + js::GlobalSlotArray *globals() { + JS_ASSERT(isValidOffset(globalsOffset)); + return (js::GlobalSlotArray *) ((uint8 *) (this + 1) + globalsOffset); + } + + JSConstArray *consts() { + JS_ASSERT(isValidOffset(constOffset)); + return (JSConstArray *) ((uint8 *) (this + 1) + constOffset); + } + + JSAtom *getAtom(size_t index) { + JS_ASSERT(index < atomMap.length); + return atomMap.vector[index]; + } + + JSObject *getObject(size_t index) { + JSObjectArray *arr = objects(); + JS_ASSERT(index < arr->length); + return arr->vector[index]; + } + + uint32 getGlobalSlot(size_t index) { + js::GlobalSlotArray *arr = globals(); + JS_ASSERT(index < arr->length); + return arr->vector[index].slot; + } + + JSAtom *getGlobalAtom(size_t index) { + js::GlobalSlotArray *arr = globals(); + JS_ASSERT(index < arr->length); + return getAtom(arr->vector[index].atomIndex); + } + + JSVersion getVersion() const { + return JSVersion(version); + } + + inline JSFunction *getFunction(size_t index); + + inline JSObject *getRegExp(size_t index); + + const js::Value &getConst(size_t index) { + JSConstArray *arr = consts(); + JS_ASSERT(index < arr->length); + return arr->vector[index]; + } + + /* + * The isEmpty method tells whether this script has code that computes any + * result (not return value, result AKA normal completion value) other than + * JSVAL_VOID, or any other effects. + */ + inline bool isEmpty() const; + + uint32 getClosedArg(uint32 index) { + JS_ASSERT(index < nClosedArgs); + return closedSlots[index]; + } + + uint32 getClosedVar(uint32 index) { + JS_ASSERT(index < nClosedVars); + return closedSlots[nClosedArgs + index]; + } + + void copyClosedSlotsTo(JSScript *other); +}; + +#define SHARP_NSLOTS 2 /* [#array, #depth] slots if the script + uses sharp variables */ + +static JS_INLINE uintN +StackDepth(JSScript *script) +{ + return script->nslots - script->nfixed; +} + +/* + * If pc_ does not point within script_'s bytecode, then it must point into an + * imacro body, so we use cx->runtime common atoms instead of script_'s atoms. + * This macro uses cx from its callers' environments in the pc-in-imacro case. + */ +#define JS_GET_SCRIPT_ATOM(script_, pc_, index, atom) \ + JS_BEGIN_MACRO \ + if ((pc_) < (script_)->code || \ + (script_)->code + (script_)->length <= (pc_)) { \ + JS_ASSERT((size_t)(index) < js_common_atom_count); \ + (atom) = COMMON_ATOMS_START(&cx->runtime->atomState)[index]; \ + } else { \ + (atom) = script_->getAtom(index); \ + } \ + JS_END_MACRO + +extern JS_FRIEND_DATA(js::Class) js_ScriptClass; + +extern JSObject * +js_InitScriptClass(JSContext *cx, JSObject *obj); + +/* + * On first new context in rt, initialize script runtime state, specifically + * the script filename table and its lock. + */ +extern JSBool +js_InitRuntimeScriptState(JSRuntime *rt); + +/* + * On JS_DestroyRuntime(rt), forcibly free script filename prefixes and any + * script filename table entries that have not been GC'd. + * + * This allows script filename prefixes to outlive any context in rt. + */ +extern void +js_FreeRuntimeScriptState(JSRuntime *rt); + +extern const char * +js_SaveScriptFilename(JSContext *cx, const char *filename); + +extern const char * +js_SaveScriptFilenameRT(JSRuntime *rt, const char *filename, uint32 flags); + +extern uint32 +js_GetScriptFilenameFlags(const char *filename); + +extern void +js_MarkScriptFilename(const char *filename); + +extern void +js_MarkScriptFilenames(JSRuntime *rt); + +extern void +js_SweepScriptFilenames(JSRuntime *rt); + +/* + * New-script-hook calling is factored from js_NewScriptFromCG so that it + * and callers of js_XDRScript can share this code. In the case of callers + * of js_XDRScript, the hook should be invoked only after successful decode + * of any owning function (the fun parameter) or script object (null fun). + */ +extern JS_FRIEND_API(void) +js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun); + +extern void +js_CallDestroyScriptHook(JSContext *cx, JSScript *script); + +/* + * The function must be used only outside the GC for a script that was run + * only on the current thread. + */ +extern void +js_DestroyScript(JSContext *cx, JSScript *script); + +extern void +js_DestroyScriptFromGC(JSContext *cx, JSScript *script); + +/* + * Script objects may be cached and reused, in which case their JSD-visible + * lifetimes may be shorter than their actual lifetimes. Destroy one such + * script for real as part of a GC pass. From JSD's point of view, the script + * is already dead. + */ +extern void +js_DestroyCachedScript(JSContext *cx, JSScript *script); + +extern void +js_TraceScript(JSTracer *trc, JSScript *script); + +extern JSObject * +js_NewScriptObject(JSContext *cx, JSScript *script); + +/* + * To perturb as little code as possible, we introduce a js_GetSrcNote lookup + * cache without adding an explicit cx parameter. Thus js_GetSrcNote becomes + * a macro that uses cx from its calls' lexical environments. + */ +#define js_GetSrcNote(script,pc) js_GetSrcNoteCached(cx, script, pc) + +extern jssrcnote * +js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc); + +/* + * NOTE: use js_FramePCToLineNumber(cx, fp) when you have an active fp, in + * preference to js_PCToLineNumber (cx, fp->script fp->regs->pc), because + * fp->imacpc may be non-null, indicating an active imacro. + */ +extern uintN +js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp); + +extern uintN +js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc); + +extern jsbytecode * +js_LineNumberToPC(JSScript *script, uintN lineno); + +extern JS_FRIEND_API(uintN) +js_GetScriptLineExtent(JSScript *script); + +static JS_INLINE JSOp +js_GetOpcode(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + JSOp op = (JSOp) *pc; + if (op == JSOP_TRAP) + op = JS_GetTrapOpcode(cx, script, pc); + return op; +} + +extern JSScript * +js_CloneScript(JSContext *cx, JSScript *script); + +/* + * If magic is non-null, js_XDRScript succeeds on magic number mismatch but + * returns false in *magic; it reflects a match via a true *magic out param. + * If magic is null, js_XDRScript returns false on bad magic number errors, + * which it reports. + * + * NB: after a successful JSXDR_DECODE, js_XDRScript callers must do any + * required subsequent set-up of owning function or script object and then call + * js_CallNewScriptHook. + */ +extern JSBool +js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic); + +inline bool +JSObject::isScript() const +{ + return getClass() == &js_ScriptClass; +} + +inline JSScript * +JSObject::getScript() const +{ + JS_ASSERT(isScript()); + return static_cast(getPrivate()); +} + +#endif /* jsscript_h___ */ diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h new file mode 100644 index 0000000..fb99164 --- /dev/null +++ b/js/src/jsscriptinlines.h @@ -0,0 +1,131 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=79 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey JavaScript engine. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jason Orendorff + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsscriptinlines_h___ +#define jsscriptinlines_h___ + +#include "jscntxt.h" +#include "jsfun.h" +#include "jsopcode.h" +#include "jsregexp.h" +#include "jsscript.h" +#include "jsscope.h" + +namespace js { + +inline +Bindings::Bindings(JSContext *cx) + : lastBinding(cx->compartment->emptyCallShape), nargs(0), nvars(0), nupvars(0) +{ +} + +inline void +Bindings::transfer(JSContext *cx, Bindings *bindings) +{ + JS_ASSERT(lastBinding == cx->compartment->emptyCallShape); + + *this = *bindings; +#ifdef DEBUG + bindings->lastBinding = NULL; +#endif + + /* Preserve back-pointer invariants across the lastBinding transfer. */ + if (lastBinding->inDictionary()) + lastBinding->listp = &this->lastBinding; +} + +inline void +Bindings::clone(JSContext *cx, Bindings *bindings) +{ + JS_ASSERT(lastBinding == cx->compartment->emptyCallShape); + + /* + * Non-dictionary bindings are fine to share, as are dictionary bindings if + * they're copy-on-modification. + */ + JS_ASSERT(!bindings->lastBinding->inDictionary() || bindings->lastBinding->frozen()); + + *this = *bindings; +} + +const Shape * +Bindings::lastShape() const +{ + JS_ASSERT(lastBinding); + JS_ASSERT_IF(lastBinding->inDictionary(), lastBinding->frozen()); + return lastBinding; +} + +} // namespace js + +inline JSFunction * +JSScript::getFunction(size_t index) +{ + JSObject *funobj = getObject(index); + JS_ASSERT(funobj->isFunction()); + JS_ASSERT(funobj == (JSObject *) funobj->getPrivate()); + JSFunction *fun = (JSFunction *) funobj; + JS_ASSERT(FUN_INTERPRETED(fun)); + return fun; +} + +inline JSObject * +JSScript::getRegExp(size_t index) +{ + JSObjectArray *arr = regexps(); + JS_ASSERT((uint32) index < arr->length); + JSObject *obj = arr->vector[index]; + JS_ASSERT(obj->getClass() == &js_RegExpClass); + return obj; +} + +inline bool +JSScript::isEmpty() const +{ + if (length > 3) + return false; + + jsbytecode *pc = code; + if (noScriptRval && JSOp(*pc) == JSOP_FALSE) + ++pc; + return JSOp(*pc) == JSOP_STOP; +} + +#endif /* jsscriptinlines_h___ */ diff --git a/js/src/jsshell.msg b/js/src/jsshell.msg new file mode 100644 index 0000000..c77a9a7 --- /dev/null +++ b/js/src/jsshell.msg @@ -0,0 +1,58 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + Error messages for JSShell. See js.msg for format. +*/ + +MSG_DEF(JSSMSG_NOT_AN_ERROR, 0, 0, JSEXN_NONE, "") +MSG_DEF(JSSMSG_CANT_OPEN, 1, 2, JSEXN_NONE, "can't open {0}: {1}") +MSG_DEF(JSSMSG_TRAP_USAGE, 2, 0, JSEXN_NONE, "usage: trap [fun] [pc] expr") +MSG_DEF(JSSMSG_LINE2PC_USAGE, 3, 0, JSEXN_NONE, "usage: line2pc [fun] line") +MSG_DEF(JSSMSG_FILE_SCRIPTS_ONLY, 4, 0, JSEXN_NONE, "only works on JS scripts read from files") +MSG_DEF(JSSMSG_UNEXPECTED_EOF, 5, 1, JSEXN_NONE, "unexpected EOF in {0}") +MSG_DEF(JSSMSG_DOEXP_USAGE, 6, 0, JSEXN_NONE, "usage: doexp obj id") +MSG_DEF(JSSMSG_SCRIPTS_ONLY, 7, 0, JSEXN_NONE, "only works on scripts") +MSG_DEF(JSSMSG_NOT_ENOUGH_ARGS, 8, 1, JSEXN_NONE, "{0}: not enough arguments") +MSG_DEF(JSSMSG_TOO_MANY_ARGS, 9, 1, JSEXN_NONE, "{0}: too many arguments") +MSG_DEF(JSSMSG_ASSERT_EQ_FAILED, 10, 2, JSEXN_NONE, "Assertion failed: got {0}, expected {1}") +MSG_DEF(JSSMSG_ASSERT_EQ_FAILED_MSG, 11, 3, JSEXN_NONE, "Assertion failed: got {0}, expected {1}: {2}") +MSG_DEF(JSSMSG_INVALID_ARGS, 12, 1, JSEXN_NONE, "{0}: invalid arguments") +MSG_DEF(JSSMSG_ASSERT_JIT_FAILED, 13, 0, JSEXN_NONE, "unexpected failure to JIT") +MSG_DEF(JSSMSG_BAD_ALIGNMENT, 14, 0, JSEXN_NONE, "serialized data must be 8-byte-aligned") diff --git a/js/src/jsstack.js b/js/src/jsstack.js new file mode 100644 index 0000000..16ab957 --- /dev/null +++ b/js/src/jsstack.js @@ -0,0 +1,375 @@ +/* + * Check that only JS_REQUIRES_STACK/JS_FORCES_STACK functions, and functions + * that have called a JS_FORCES_STACK function, access cx->fp directly or + * indirectly. + */ + +require({ after_gcc_pass: 'cfg' }); +include('gcc_util.js'); +include('unstable/adts.js'); +include('unstable/analysis.js'); +include('unstable/lazy_types.js'); +include('unstable/esp.js'); + +var Zero_NonZero = {}; +include('unstable/zero_nonzero.js', Zero_NonZero); + +// Tell MapFactory we don't need multimaps (a speed optimization). +MapFactory.use_injective = true; + +/* + * There are two regions in the program: RED and GREEN. Functions and member + * variables may be declared RED in the C++ source. GREEN is the default. + * + * RED signals danger. A GREEN part of a function must not call a RED function + * or access a RED member. + * + * The body of a RED function is all red. The body of a GREEN function is all + * GREEN by default, but parts dominated by a call to a TURN_RED function are + * red. This way GREEN functions can safely access RED stuff by calling a + * TURN_RED function as preparation. + * + * The analysis does not attempt to prove anything about the body of a TURN_RED + * function. (Both annotations are trusted; only unannotated code is checked + * for errors.) + */ +const RED = 'JS_REQUIRES_STACK'; +const TURN_RED = 'JS_FORCES_STACK'; +const IGNORE_ERRORS = 'JS_IGNORE_STACK'; + +function attrs(tree) { + let a = DECL_P(tree) ? DECL_ATTRIBUTES(tree) : TYPE_ATTRIBUTES(tree); + return translate_attributes(a); +} + +function hasUserAttribute(tree, attrname) { + let attributes = attrs(tree); + if (attributes) { + for (let i = 0; i < attributes.length; i++) { + let attr = attributes[i]; + if (attr.name == 'user' && attr.value.length == 1 && attr.value[0] == attrname) + return true; + } + } + return false; +} + +function process_tree_type(d) +{ + let t = dehydra_convert(d); + if (t.isFunction) + return; + + if (t.typedef !== undefined) + if (isRed(TYPE_NAME(d))) + warning("Typedef declaration is annotated JS_REQUIRES_STACK: the annotation should be on the type itself", t.loc); + + if (hasAttribute(t, RED)) { + warning("Non-function is annotated JS_REQUIRES_STACK", t.loc); + return; + } + + for (let st = t; st !== undefined && st.isPointer; st = st.type) { + if (hasAttribute(st, RED)) { + warning("Non-function is annotated JS_REQUIRES_STACK", t.loc); + return; + } + + if (st.parameters) + return; + } +} + +function process_tree_decl(d) +{ + // For VAR_DECLs, walk the DECL_INITIAL looking for bad assignments + if (TREE_CODE(d) != VAR_DECL) + return; + + let i = DECL_INITIAL(d); + if (!i) + return; + + assignCheck(i, TREE_TYPE(d), function() { return location_of(d); }); + + functionPointerWalk(i, d); +} + +/* + * x is an expression or decl. These functions assume that + */ +function isRed(x) { return hasUserAttribute(x, RED); } +function isTurnRed(x) { return hasUserAttribute(x, TURN_RED); } + +function process_tree(fndecl) +{ + if (hasUserAttribute(fndecl, IGNORE_ERRORS)) + return; + + if (!(isRed(fndecl) || isTurnRed(fndecl))) { + // Ordinarily a user of ESP runs the analysis, then generates output based + // on the results. But in our case (a) we need sub-basic-block resolution, + // which ESP doesn't keep; (b) it so happens that even though ESP can + // iterate over blocks multiple times, in our case that won't cause + // spurious output. (It could cause us to the same error message each time + // through--but that's easily avoided.) Therefore we generate the output + // while the ESP analysis is running. + let a = new RedGreenCheck(fndecl, 0); + if (a.hasRed) + a.run(); + } + + functionPointerCheck(fndecl); +} + +function RedGreenCheck(fndecl, trace) { + //print("RedGreenCheck: " + fndecl.toCString()); + this._fndecl = fndecl; + + // Tell ESP that fndecl is a "property variable". This makes ESP track it in + // a flow-sensitive way. The variable will be 1 in RED regions and "don't + // know" in GREEN regions. (We are technically lying to ESP about fndecl + // being a variable--what we really want is a synthetic variable indicating + // RED/GREEN state, but ESP operates on GCC decl nodes.) + this._state_var_decl = fndecl; + let state_var = new ESP.PropVarSpec(this._state_var_decl, true, undefined); + + // Call base class constructor. + let cfg = function_decl_cfg(fndecl); + ESP.Analysis.apply(this, [cfg, [state_var], Zero_NonZero.meet, trace]); + this.join = Zero_NonZero.join; + + // Preprocess all instructions in the cfg to determine whether this analysis + // is necessary and gather some information we'll use later. + // + // Each isn may include a function call, an assignment, and/or some reads. + // Using walk_tree to walk the isns is a little crazy but robust. + // + this.hasRed = false; + let self = this; // Allow our 'this' to be accessed inside closure + for (let bb in cfg_bb_iterator(cfg)) { + for (let isn in bb_isn_iterator(bb)) { + // Treehydra objects don't support reading never-defined properties + // as undefined, so we have to explicitly initialize anything we want + // to check for later. + isn.redInfo = undefined; + walk_tree(isn, function(t, stack) { + function getLocation(skiptop) { + if (!skiptop) { + let loc = location_of(t); + if (loc !== undefined) + return loc; + } + + for (let i = stack.length - 1; i >= 0; --i) { + let loc = location_of(stack[i]); + if (loc !== undefined) + return loc; + } + return location_of(fndecl); + } + + switch (TREE_CODE(t)) { + case FIELD_DECL: + if (isRed(t)) { + let varName = dehydra_convert(t).name; + // location_of(t) is the location of the declaration. + isn.redInfo = ["cannot access JS_REQUIRES_STACK variable " + varName, + getLocation(true)]; + self.hasRed = true; + } + break; + case GIMPLE_CALL: + { + let callee = gimple_call_fndecl(t); + if (callee) { + if (isRed(callee)) { + let calleeName = dehydra_convert(callee).name; + isn.redInfo = ["cannot call JS_REQUIRES_STACK function " + calleeName, + getLocation(false)]; + self.hasRed = true; + } else if (isTurnRed(callee)) { + isn.turnRed = true; + } + } + else { + let fntype = TREE_CHECK( + TREE_TYPE( // the function type + TREE_TYPE( // the function pointer type + gimple_call_fn(t) + ) + ), + FUNCTION_TYPE, METHOD_TYPE); + if (isRed(fntype)) { + isn.redInfo = ["cannot call JS_REQUIRES_STACK function pointer", + getLocation(false)]; + self.hasRed = true; + } + else if (isTurnRed(fntype)) { + isn.turnRed = true; + } + } + } + break; + } + }); + } + } + + // Initialize mixin for infeasible-path elimination. + this._zeroNonzero = new Zero_NonZero.Zero_NonZero(); +} + +RedGreenCheck.prototype = new ESP.Analysis; + +RedGreenCheck.prototype.flowStateCond = function(isn, truth, state) { + // forward event to mixin + this._zeroNonzero.flowStateCond(isn, truth, state); +}; + +RedGreenCheck.prototype.flowState = function(isn, state) { + // forward event to mixin + //try { // The try/catch here is a workaround for some baffling bug in zero_nonzero. + this._zeroNonzero.flowState(isn, state); + //} catch (exc) { + // warning(exc, location_of(isn)); + // warning("(Remove the workaround in jsstack.js and recompile to get a JS stack trace.)", + // location_of(isn)); + //} + let stackState = state.get(this._state_var_decl); + let green = stackState != 1 && stackState != ESP.NOT_REACHED; + let redInfo = isn.redInfo; + if (green && redInfo) { + warning(redInfo[0], redInfo[1]); + isn.redInfo = undefined; // avoid duplicate messages about this instruction + } + + // If we call a TURNS_RED function, it doesn't take effect until after the + // whole isn finishes executing (the most conservative rule). + if (isn.turnRed) + state.assignValue(this._state_var_decl, 1, isn); +}; + +function followTypedefs(type) +{ + while (type.typedef !== undefined) + type = type.typedef; + return type; +} + +function assignCheck(source, destType, locfunc) +{ + if (TREE_CODE(destType) != POINTER_TYPE) + return; + + let destCode = TREE_CODE(TREE_TYPE(destType)); + if (destCode != FUNCTION_TYPE && destCode != METHOD_TYPE) + return; + + if (isRed(TREE_TYPE(destType))) + return; + + while (TREE_CODE(source) == NOP_EXPR) + source = source.operands()[0]; + + // The destination is a green function pointer + + if (TREE_CODE(source) == ADDR_EXPR) { + let sourcefn = source.operands()[0]; + + // oddly enough, SpiderMonkey assigns the address of something that's not + // a function to a function pointer as part of the API! See JS_TN + if (TREE_CODE(sourcefn) != FUNCTION_DECL) + return; + + if (isRed(sourcefn)) + warning("Assigning non-JS_REQUIRES_STACK function pointer from JS_REQUIRES_STACK function " + dehydra_convert(sourcefn).name, locfunc()); + } else if (TREE_TYPE(source).tree_code() == POINTER_TYPE) { + let sourceType = TREE_TYPE(TREE_TYPE(source)); + switch (TREE_CODE(sourceType)) { + case FUNCTION_TYPE: + case METHOD_TYPE: + if (isRed(sourceType)) + warning("Assigning non-JS_REQUIRES_STACK function pointer from JS_REQUIRES_STACK function pointer", locfunc()); + break; + } + } +} + +/** + * A type checker which verifies that a red function pointer is never converted + * to a green function pointer. + */ + +function functionPointerWalk(t, baseloc) +{ + walk_tree(t, function(t, stack) { + function getLocation(skiptop) { + if (!skiptop) { + let loc = location_of(t); + if (loc !== undefined) + return loc; + } + + for (let i = stack.length - 1; i >= 0; --i) { + let loc = location_of(stack[i]); + if (loc !== undefined) + return loc; + } + return location_of(baseloc); + } + + switch (TREE_CODE(t)) { + case GIMPLE_ASSIGN: { + let [dest, source] = t.operands(); + assignCheck(source, TREE_TYPE(dest), getLocation); + break; + } + case CONSTRUCTOR: { + let ttype = TREE_TYPE(t); + switch (TREE_CODE(ttype)) { + case RECORD_TYPE: + case UNION_TYPE: { + for each (let ce in VEC_iterate(CONSTRUCTOR_ELTS(t))) + assignCheck(ce.value, TREE_TYPE(ce.index), getLocation); + break; + } + case ARRAY_TYPE: { + let eltype = TREE_TYPE(ttype); + for each (let ce in VEC_iterate(CONSTRUCTOR_ELTS(t))) + assignCheck(ce.value, eltype, getLocation); + break; + } + case LANG_TYPE: + // these can be safely ignored + break; + default: + warning("Unexpected type in initializer: " + TREE_CODE(TREE_TYPE(t)), getLocation()); + } + break; + } + case GIMPLE_CALL: { + // Check that the arguments to a function and the declared types + // of those arguments are compatible. + let ops = t.operands(); + let funcType = TREE_TYPE( // function type + TREE_TYPE(ops[1])); // function pointer type + let argTypes = [t for (t in function_type_args(funcType))]; + for (let i = argTypes.length - 1; i >= 0; --i) { + let destType = argTypes[i]; + let source = ops[i + 3]; + assignCheck(source, destType, getLocation); + } + break; + } + } + }); +} + +function functionPointerCheck(fndecl) +{ + let cfg = function_decl_cfg(fndecl); + for (let bb in cfg_bb_iterator(cfg)) + for (let isn in bb_isn_iterator(bb)) + functionPointerWalk(isn, fndecl); +} diff --git a/js/src/jsstaticcheck.h b/js/src/jsstaticcheck.h new file mode 100644 index 0000000..c605d2f --- /dev/null +++ b/js/src/jsstaticcheck.h @@ -0,0 +1,125 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsstaticcheck_h___ +#define jsstaticcheck_h___ + +#ifdef NS_STATIC_CHECKING +/* + * Trigger a control flow check to make sure that code flows through label + */ +inline __attribute__ ((unused)) void MUST_FLOW_THROUGH(const char *label) { +} + +/* avoid unused goto-label warnings */ +#define MUST_FLOW_LABEL(label) goto label; label: + +inline JS_FORCES_STACK void VOUCH_DOES_NOT_REQUIRE_STACK() {} + +inline JS_FORCES_STACK void +JS_ASSERT_NOT_ON_TRACE(JSContext *cx) +{ + JS_ASSERT(!JS_ON_TRACE(cx)); +} + +#else +#define MUST_FLOW_THROUGH(label) ((void) 0) +#define MUST_FLOW_LABEL(label) +#define VOUCH_DOES_NOT_REQUIRE_STACK() ((void) 0) +#define JS_ASSERT_NOT_ON_TRACE(cx) JS_ASSERT(!JS_ON_TRACE(cx)) +#endif +#define VOUCH_HAVE_STACK VOUCH_DOES_NOT_REQUIRE_STACK + +/* sixgill annotation defines */ + +/* Avoid name collision if included with other headers defining annotations. */ +#ifndef HAVE_STATIC_ANNOTATIONS +#define HAVE_STATIC_ANNOTATIONS + +#ifdef XGILL_PLUGIN + +#define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND))) +#define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND))) +#define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND))) +#define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND))) +#define STATIC_INVARIANT(COND) __attribute__((invariant(#COND))) +#define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND))) + +/* Used to make identifiers for assert/assume annotations in a function. */ +#define STATIC_PASTE2(X,Y) X ## Y +#define STATIC_PASTE1(X,Y) STATIC_PASTE2(X,Y) + +#define STATIC_ASSERT(COND) \ + JS_BEGIN_MACRO \ + __attribute__((assert_static(#COND), unused)) \ + int STATIC_PASTE1(assert_static_, __COUNTER__); \ + JS_END_MACRO + +#define STATIC_ASSUME(COND) \ + JS_BEGIN_MACRO \ + __attribute__((assume_static(#COND), unused)) \ + int STATIC_PASTE1(assume_static_, __COUNTER__); \ + JS_END_MACRO + +#define STATIC_ASSERT_RUNTIME(COND) \ + JS_BEGIN_MACRO \ + __attribute__((assert_static_runtime(#COND), unused)) \ + int STATIC_PASTE1(assert_static_runtime_, __COUNTER__); \ + JS_END_MACRO + +#else /* XGILL_PLUGIN */ + +#define STATIC_PRECONDITION(COND) /* nothing */ +#define STATIC_PRECONDITION_ASSUME(COND) /* nothing */ +#define STATIC_POSTCONDITION(COND) /* nothing */ +#define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */ +#define STATIC_INVARIANT(COND) /* nothing */ +#define STATIC_INVARIANT_ASSUME(COND) /* nothing */ + +#define STATIC_ASSERT(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO +#define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO +#define STATIC_ASSERT_RUNTIME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO + +#endif /* XGILL_PLUGIN */ + +#define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference()) + +#endif /* HAVE_STATIC_ANNOTATIONS */ + +#endif /* jsstaticcheck_h___ */ diff --git a/js/src/jsstdint.h b/js/src/jsstdint.h new file mode 100644 index 0000000..446a873 --- /dev/null +++ b/js/src/jsstdint.h @@ -0,0 +1,122 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Jim Blandy + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This header provides definitions for the types we use, + * even on systems that lack . + * + * NOTE: This header should only be included in private SpiderMonkey + * code; public headers should use only the JS{Int,Uint}N types; see + * the comment for them in "jsinttypes.h". + * + * At the moment, these types are not widely used within SpiderMonkey; + * this file is meant to make existing uses portable, and to allow us + * to transition portably to using them more, if desired. + */ + +#ifndef jsstdint_h___ +#define jsstdint_h___ + +#include "jsinttypes.h" + +/* If we have a working stdint.h, then jsinttypes.h has already + defined the standard integer types. Otherwise, define the standard + names in terms of the 'JS' types. */ +#if ! defined(JS_HAVE_STDINT_H) && \ + ! defined(JS_SYS_TYPES_H_DEFINES_EXACT_SIZE_TYPES) + +typedef JSInt8 int8_t; +typedef JSInt16 int16_t; +typedef JSInt32 int32_t; +typedef JSInt64 int64_t; + +typedef JSUint8 uint8_t; +typedef JSUint16 uint16_t; +typedef JSUint32 uint32_t; +typedef JSUint64 uint64_t; + +/* Suppress other, conflicting attempts to define stdint-bits. */ +#define _STDINT_H + +/* If JS_STDDEF_H_HAS_INTPTR_T or JS_CRTDEFS_H_HAS_INTPTR_T are + defined, then jsinttypes.h included the given header, which + introduced definitions for intptr_t and uintptr_t. Otherwise, + define the standard names in terms of the 'JS' types. */ +#if !defined(JS_STDDEF_H_HAS_INTPTR_T) && !defined(JS_CRTDEFS_H_HAS_INTPTR_T) +typedef JSIntPtr intptr_t; +typedef JSUintPtr uintptr_t; +#endif + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) + +#define INT8_MAX 127 +#define INT8_MIN (-INT8_MAX - 1) +#define INT16_MAX 32767 +#define INT16_MIN (-INT16_MAX - 1) +#define INT32_MAX 2147483647 +#define INT32_MIN (-INT32_MAX - 1) +#define INT64_MAX 9223372036854775807LL +#define INT64_MIN (-INT64_MAX - 1) + +#define UINT8_MAX 255 +#define UINT16_MAX 65535 +#define UINT32_MAX 4294967295U +#define UINT64_MAX 18446744073709551615ULL + +/* + * These are technically wrong as they can't be used in the preprocessor, but + * we would require compiler assistance, and at the moment we don't need + * preprocessor-correctness. + */ +#ifdef _MSC_VER +#undef SIZE_MAX +#endif + +#define INTPTR_MAX ((intptr_t) (UINTPTR_MAX >> 1)) +#define INTPTR_MIN (intptr_t(uintptr_t(INTPTR_MAX) + uintptr_t(1))) +#define UINTPTR_MAX ((uintptr_t) -1) +#define SIZE_MAX UINTPTR_MAX +#define PTRDIFF_MAX INTPTR_MAX +#define PTRDIFF_MIN INTPTR_MIN + +#endif /* !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) */ + +#endif /* JS_HAVE_STDINT_H */ + +#endif /* jsstdint_h___ */ diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp new file mode 100644 index 0000000..cb5c87d --- /dev/null +++ b/js/src/jsstr.cpp @@ -0,0 +1,5967 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS string type implementation. + * + * In order to avoid unnecessary js_LockGCThing/js_UnlockGCThing calls, these + * native methods store strings (possibly newborn) converted from their 'this' + * parameter and arguments on the stack: 'this' conversions at argv[-1], arg + * conversions at their index (argv[0], argv[1]). This is a legitimate method + * of rooting things that might lose their newborn root due to subsequent GC + * allocations in the same native method. + */ +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsutil.h" +#include "jshash.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsfun.h" /* for JS_ARGS_LENGTH_MAX */ +#include "jsgc.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsregexp.h" +#include "jsscope.h" +#include "jsstaticcheck.h" +#include "jsstr.h" +#include "jsbit.h" +#include "jsvector.h" +#include "jsversion.h" + +#include "jscntxtinlines.h" +#include "jsinterpinlines.h" +#include "jsobjinlines.h" +#include "jsregexpinlines.h" +#include "jsstrinlines.h" +#include "jsautooplen.h" // generated headers last + +using namespace js; +using namespace js::gc; + +JS_STATIC_ASSERT(size_t(JSString::MAX_LENGTH) <= size_t(JSVAL_INT_MAX)); +JS_STATIC_ASSERT(JSString::MAX_LENGTH <= JSVAL_INT_MAX); + +const jschar * +js_GetStringChars(JSContext *cx, JSString *str) +{ + if (!js_MakeStringImmutable(cx, str)) + return NULL; + return str->flatChars(); +} + +static JS_ALWAYS_INLINE size_t +RopeCapacityFor(size_t length) +{ + static const size_t ROPE_DOUBLING_MAX = 1024 * 1024; + + /* + * Grow by 12.5% if the buffer is very large. Otherwise, round up to the + * next power of 2. This is similar to what we do with arrays; see + * JSObject::ensureDenseArrayElements. + */ + if (length > ROPE_DOUBLING_MAX) + return length + (length / 8); + return RoundUpPow2(length); +} + +static JS_ALWAYS_INLINE jschar * +AllocChars(JSContext *maybecx, size_t wholeCapacity) +{ + /* +1 for the null char at the end. */ + JS_STATIC_ASSERT(JSString::MAX_LENGTH * sizeof(jschar) < UINT32_MAX); + size_t bytes = (wholeCapacity + 1) * sizeof(jschar); + if (maybecx) + return (jschar *)maybecx->malloc(bytes); + return (jschar *)js_malloc(bytes); +} + +const jschar * +JSString::flatten(JSContext *maybecx) +{ + JS_ASSERT(isRope()); + + /* + * Perform a depth-first dag traversal, splatting each node's characters + * into a contiguous buffer. Visit each rope node three times: + * 1. record position in the buffer and recurse into left child; + * 2. recurse into the right child; + * 3. transform the node into a dependent string. + * To avoid maintaining a stack, tree nodes are mutated to indicate how + * many times they have been visited. Since ropes can be dags, a node may + * be encountered multiple times during traversal. However, step 3 above + * leaves a valid dependent string, so everythings works out. This + * algorithm is homomorphic to TypedMarker(JSTracer *, JSString *). + * + * While ropes avoid all sorts of quadratic cases with string + * concatenation, they can't help when ropes are immediately flattened. + * One idiomatic case that we'd like to keep linear (and has traditionally + * been linear in SM and other JS engines) is: + * + * while (...) { + * s += ... + * s.flatten + * } + * + * To do this, when the buffer for a to-be-flattened rope is allocated, the + * allocation size is rounded up. Then, if the resulting flat string is the + * left-hand side of a new rope that gets flattened and there is enough + * capacity, the rope is flattened into the same buffer, thereby avoiding + * copying the left-hand side. Clearing the 'extensible' bit turns off this + * optimization. This is necessary, e.g., when the JSAPI hands out the raw + * null-terminated char array of a flat string. + * + * N.B. This optimization can create chains of dependent strings. + */ + const size_t wholeLength = length(); + size_t wholeCapacity; + jschar *wholeChars; + JSString *str = this; + jschar *pos; + + if (u.left->isExtensible() && u.left->s.capacity >= wholeLength) { + wholeCapacity = u.left->s.capacity; + wholeChars = const_cast(u.left->u.chars); + pos = wholeChars + u.left->length(); + u.left->finishTraversalConversion(this, wholeChars, pos); + goto visit_right_child; + } + + wholeCapacity = RopeCapacityFor(wholeLength); + wholeChars = AllocChars(maybecx, wholeCapacity); + if (!wholeChars) + return NULL; + + if (maybecx) + maybecx->runtime->stringMemoryUsed += wholeLength * 2; + pos = wholeChars; + first_visit_node: { + JSString *left = str->u.left; /* Read before clobbered. */ + str->u.chars = pos; + if (left->isRope()) { + left->s.parent = str; /* Return to this when 'left' done, */ + left->lengthAndFlags = 0x200; /* but goto visit_right_child. */ + str = left; + goto first_visit_node; + } + size_t len = left->length(); + PodCopy(pos, left->u.chars, len); + pos += len; + } + visit_right_child: { + JSString *right = str->s.right; + if (right->isRope()) { + right->s.parent = str; /* Return to this node when 'right' done, */ + right->lengthAndFlags = 0x300; /* but goto finish_node. */ + str = right; + goto first_visit_node; + } + size_t len = right->length(); + PodCopy(pos, right->u.chars, len); + pos += len; + } + finish_node: { + if (str == this) { + JS_ASSERT(pos == wholeChars + wholeLength); + *pos = '\0'; + initFlatExtensible(wholeChars, wholeLength, wholeCapacity); + return wholeChars; + } + size_t progress = str->lengthAndFlags; /* Read before clobbered. */ + JSString *parent = str->s.parent; + str->finishTraversalConversion(this, wholeChars, pos); + str = parent; + if (progress == 0x200) + goto visit_right_child; + goto finish_node; + } +} + +JS_STATIC_ASSERT(JSExternalString::TYPE_LIMIT == 8); +JSStringFinalizeOp JSExternalString::str_finalizers[JSExternalString::TYPE_LIMIT] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +#ifdef JS_TRACER + +JSBool JS_FASTCALL +js_Flatten(JSContext *cx, JSString* str) +{ + return !!str->flatten(cx); +} +JS_DEFINE_CALLINFO_2(extern, BOOL, js_Flatten, CONTEXT, STRING, 0, nanojit::ACCSET_STORE_ANY) + +#endif /* !JS_TRACER */ + +JSString * JS_FASTCALL +js_ConcatStrings(JSContext *cx, JSString *left, JSString *right) +{ + JS_ASSERT_IF(!JSString::isStatic(left) && !left->isAtomized(), + left->asCell()->compartment() == cx->compartment); + JS_ASSERT_IF(!JSString::isStatic(right) && !right->isAtomized(), + right->asCell()->compartment() == cx->compartment); + + size_t leftLen = left->length(); + if (leftLen == 0) + return right; + + size_t rightLen = right->length(); + if (rightLen == 0) + return left; + + size_t wholeLength = leftLen + rightLen; + + if (JSShortString::fitsIntoShortString(wholeLength)) { + JSShortString *shortStr = js_NewGCShortString(cx); + if (!shortStr) + return NULL; + const jschar *leftChars = left->getChars(cx); + if (!leftChars) + return NULL; + const jschar *rightChars = right->getChars(cx); + if (!rightChars) + return NULL; + + jschar *buf = shortStr->init(wholeLength); + js_short_strncpy(buf, leftChars, leftLen); + js_short_strncpy(buf + leftLen, rightChars, rightLen); + buf[wholeLength] = 0; + return shortStr->header(); + } + + if (wholeLength > JSString::MAX_LENGTH) { + if (JS_ON_TRACE(cx)) { + if (!CanLeaveTrace(cx)) + return NULL; + LeaveTrace(cx); + } + js_ReportAllocationOverflow(cx); + return NULL; + } + + JSString *newRoot = js_NewGCString(cx); + if (!newRoot) + return NULL; + + newRoot->initRopeNode(left, right, wholeLength); + return newRoot; +} + +const jschar * +JSString::undepend(JSContext *cx) +{ + size_t n, size; + jschar *s; + + if (!ensureLinear(cx)) + return NULL; + + if (isDependent()) { + n = dependentLength(); + size = (n + 1) * sizeof(jschar); + s = (jschar *) cx->malloc(size); + if (!s) + return NULL; + + cx->runtime->stringMemoryUsed += size; + js_strncpy(s, dependentChars(), n); + s[n] = 0; + initFlat(s, n); + +#ifdef DEBUG + { + JSRuntime *rt = cx->runtime; + JS_RUNTIME_UNMETER(rt, liveDependentStrings); + JS_RUNTIME_UNMETER(rt, totalDependentStrings); + JS_LOCK_RUNTIME_VOID(rt, + (rt->strdepLengthSum -= (double)n, + rt->strdepLengthSquaredSum -= (double)n * (double)n)); + } +#endif + } + + return flatChars(); +} + +JSBool +js_MakeStringImmutable(JSContext *cx, JSString *str) +{ + /* + * Flattening a rope may result in a dependent string, so we need to flatten + * before undepending the string. + */ + if (!str->isFlat() && !str->undepend(cx)) { + JS_RUNTIME_METER(cx->runtime, badUndependStrings); + return JS_FALSE; + } + str->flatClearExtensible(); + return JS_TRUE; +} + +static JSLinearString * +ArgToRootedString(JSContext *cx, uintN argc, Value *vp, uintN arg) +{ + if (arg >= argc) + return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + vp += 2 + arg; + + if (vp->isObject() && !DefaultValue(cx, &vp->toObject(), JSTYPE_STRING, vp)) + return NULL; + + JSLinearString *str; + if (vp->isString()) { + str = vp->toString()->ensureLinear(cx); + } else if (vp->isBoolean()) { + str = ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[ + (int)vp->toBoolean()]); + } else if (vp->isNull()) { + str = ATOM_TO_STRING(cx->runtime->atomState.nullAtom); + } else if (vp->isUndefined()) { + str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + } + else { + str = NumberToString(cx, vp->toNumber()); + if (!str) + return NULL; + vp->setString(str); + } + return str; +} + +/* + * Forward declarations for URI encode/decode and helper routines + */ +static JSBool +str_decodeURI(JSContext *cx, uintN argc, Value *vp); + +static JSBool +str_decodeURI_Component(JSContext *cx, uintN argc, Value *vp); + +static JSBool +str_encodeURI(JSContext *cx, uintN argc, Value *vp); + +static JSBool +str_encodeURI_Component(JSContext *cx, uintN argc, Value *vp); + +static const uint32 OVERLONG_UTF8 = UINT32_MAX; + +static uint32 +Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length); + +/* + * Contributions from the String class to the set of methods defined for the + * global object. escape and unescape used to be defined in the Mocha library, + * but as ECMA decided to spec them, they've been moved to the core engine + * and made ECMA-compliant. (Incomplete escapes are interpreted as literal + * characters by unescape.) + */ + +/* + * Stuff to emulate the old libmocha escape, which took a second argument + * giving the type of escape to perform. Retained for compatibility, and + * copied here to avoid reliance on net.h, mkparse.c/NET_EscapeBytes. + */ + +#define URL_XALPHAS ((uint8) 1) +#define URL_XPALPHAS ((uint8) 2) +#define URL_PATH ((uint8) 4) + +static const uint8 urlCharType[256] = +/* Bit 0 xalpha -- the alphas + * Bit 1 xpalpha -- as xalpha but + * converts spaces to plus and plus to %20 + * Bit 2 ... path -- as xalphas but doesn't escape '/' + */ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */ + 0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4, /* 2x !"#$%&'()*+,-./ */ + 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */ + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */ + 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */ + 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */ + 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0, /* 7X pqrstuvwxyz{\}~ DEL */ + 0, }; + +/* This matches the ECMA escape set when mask is 7 (default.) */ + +#define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask)) + +/* See ECMA-262 Edition 3 B.2.1 */ +JSBool +js_str_escape(JSContext *cx, uintN argc, Value *vp, Value *rval) +{ + const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + jsint mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH; + if (argc > 1) { + double d; + if (!ValueToNumber(cx, vp[3], &d)) + return JS_FALSE; + if (!JSDOUBLE_IS_FINITE(d) || + (mask = (jsint)d) != d || + mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH)) + { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) mask); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_STRING_MASK, numBuf); + return JS_FALSE; + } + } + + JSLinearString *str = ArgToRootedString(cx, argc, vp, 0); + if (!str) + return JS_FALSE; + + size_t length = str->length(); + const jschar *chars = str->chars(); + + /* Take a first pass and see how big the result string will need to be. */ + size_t newlength = length; + for (size_t i = 0; i < length; i++) { + jschar ch; + if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) + continue; + if (ch < 256) { + if (mask == URL_XPALPHAS && ch == ' ') + continue; /* The character will be encoded as '+' */ + newlength += 2; /* The character will be encoded as %XX */ + } else { + newlength += 5; /* The character will be encoded as %uXXXX */ + } + + /* + * This overflow test works because newlength is incremented by at + * most 5 on each iteration. + */ + if (newlength < length) { + js_ReportAllocationOverflow(cx); + return JS_FALSE; + } + } + + if (newlength >= ~(size_t)0 / sizeof(jschar)) { + js_ReportAllocationOverflow(cx); + return JS_FALSE; + } + + jschar *newchars = (jschar *) cx->malloc((newlength + 1) * sizeof(jschar)); + if (!newchars) + return JS_FALSE; + size_t i, ni; + for (i = 0, ni = 0; i < length; i++) { + jschar ch; + if ((ch = chars[i]) < 128 && IS_OK(ch, mask)) { + newchars[ni++] = ch; + } else if (ch < 256) { + if (mask == URL_XPALPHAS && ch == ' ') { + newchars[ni++] = '+'; /* convert spaces to pluses */ + } else { + newchars[ni++] = '%'; + newchars[ni++] = digits[ch >> 4]; + newchars[ni++] = digits[ch & 0xF]; + } + } else { + newchars[ni++] = '%'; + newchars[ni++] = 'u'; + newchars[ni++] = digits[ch >> 12]; + newchars[ni++] = digits[(ch & 0xF00) >> 8]; + newchars[ni++] = digits[(ch & 0xF0) >> 4]; + newchars[ni++] = digits[ch & 0xF]; + } + } + JS_ASSERT(ni == newlength); + newchars[newlength] = 0; + + JSString *retstr = js_NewString(cx, newchars, newlength); + if (!retstr) { + cx->free(newchars); + return JS_FALSE; + } + rval->setString(retstr); + return JS_TRUE; +} +#undef IS_OK + +static JSBool +str_escape(JSContext *cx, uintN argc, Value *vp) +{ + return js_str_escape(cx, argc, vp, vp); +} + +/* See ECMA-262 Edition 3 B.2.2 */ +static JSBool +str_unescape(JSContext *cx, uintN argc, Value *vp) +{ + JSLinearString *str = ArgToRootedString(cx, argc, vp, 0); + if (!str) + return false; + + size_t length = str->length(); + const jschar *chars = str->chars(); + + /* Don't bother allocating less space for the new string. */ + jschar *newchars = (jschar *) cx->malloc((length + 1) * sizeof(jschar)); + if (!newchars) + return false; + size_t ni = 0, i = 0; + while (i < length) { + jschar ch = chars[i++]; + if (ch == '%') { + if (i + 1 < length && + JS7_ISHEX(chars[i]) && JS7_ISHEX(chars[i + 1])) + { + ch = JS7_UNHEX(chars[i]) * 16 + JS7_UNHEX(chars[i + 1]); + i += 2; + } else if (i + 4 < length && chars[i] == 'u' && + JS7_ISHEX(chars[i + 1]) && JS7_ISHEX(chars[i + 2]) && + JS7_ISHEX(chars[i + 3]) && JS7_ISHEX(chars[i + 4])) + { + ch = (((((JS7_UNHEX(chars[i + 1]) << 4) + + JS7_UNHEX(chars[i + 2])) << 4) + + JS7_UNHEX(chars[i + 3])) << 4) + + JS7_UNHEX(chars[i + 4]); + i += 5; + } + } + newchars[ni++] = ch; + } + newchars[ni] = 0; + + JSString *retstr = js_NewString(cx, newchars, ni); + if (!retstr) { + cx->free(newchars); + return JS_FALSE; + } + vp->setString(retstr); + return JS_TRUE; +} + +#if JS_HAS_UNEVAL +static JSBool +str_uneval(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str; + + str = js_ValueToSource(cx, argc != 0 ? vp[2] : UndefinedValue()); + if (!str) + return JS_FALSE; + vp->setString(str); + return JS_TRUE; +} +#endif + +const char js_escape_str[] = "escape"; +const char js_unescape_str[] = "unescape"; +#if JS_HAS_UNEVAL +const char js_uneval_str[] = "uneval"; +#endif +const char js_decodeURI_str[] = "decodeURI"; +const char js_encodeURI_str[] = "encodeURI"; +const char js_decodeURIComponent_str[] = "decodeURIComponent"; +const char js_encodeURIComponent_str[] = "encodeURIComponent"; + +static JSFunctionSpec string_functions[] = { + JS_FN(js_escape_str, str_escape, 1,0), + JS_FN(js_unescape_str, str_unescape, 1,0), +#if JS_HAS_UNEVAL + JS_FN(js_uneval_str, str_uneval, 1,0), +#endif + JS_FN(js_decodeURI_str, str_decodeURI, 1,0), + JS_FN(js_encodeURI_str, str_encodeURI, 1,0), + JS_FN(js_decodeURIComponent_str, str_decodeURI_Component, 1,0), + JS_FN(js_encodeURIComponent_str, str_encodeURI_Component, 1,0), + + JS_FS_END +}; + +jschar js_empty_ucstr[] = {0}; +JSSubString js_EmptySubString = {0, js_empty_ucstr}; + +static JSBool +str_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + JSString *str; + + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + if (obj->getClass() == &js_StringClass) { + /* Follow ECMA-262 by fetching intrinsic length of our string. */ + str = obj->getPrimitiveThis().toString(); + } else { + /* Preserve compatibility: convert obj to a string primitive. */ + str = js_ValueToString(cx, ObjectValue(*obj)); + if (!str) + return JS_FALSE; + } + + vp->setInt32(str->length()); + } + + return JS_TRUE; +} + +#define STRING_ELEMENT_ATTRS (JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT) + +static JSBool +str_enumerate(JSContext *cx, JSObject *obj) +{ + JSString *str, *str1; + size_t i, length; + + str = obj->getPrimitiveThis().toString(); + + length = str->length(); + for (i = 0; i < length; i++) { + str1 = js_NewDependentString(cx, str, i, 1); + if (!str1) + return JS_FALSE; + if (!obj->defineProperty(cx, INT_TO_JSID(i), StringValue(str1), + PropertyStub, StrictPropertyStub, + STRING_ELEMENT_ATTRS)) { + return JS_FALSE; + } + } + + return obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), + UndefinedValue(), NULL, NULL, + JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED); +} + +static JSBool +str_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, + JSObject **objp) +{ + if (!JSID_IS_INT(id)) + return JS_TRUE; + + JSString *str = obj->getPrimitiveThis().toString(); + + jsint slot = JSID_TO_INT(id); + if ((size_t)slot < str->length()) { + JSString *str1 = JSString::getUnitString(cx, str, size_t(slot)); + if (!str1) + return JS_FALSE; + if (!obj->defineProperty(cx, id, StringValue(str1), NULL, NULL, + STRING_ELEMENT_ATTRS)) { + return JS_FALSE; + } + *objp = obj; + } + return JS_TRUE; +} + +Class js_StringClass = { + js_String_str, + JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_NEW_RESOLVE | + JSCLASS_HAS_CACHED_PROTO(JSProto_String), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + str_getProperty, + StrictPropertyStub, /* setProperty */ + str_enumerate, + (JSResolveOp)str_resolve, + ConvertStub +}; + +/* + * Returns a JSString * for the |this| value associated with vp, or throws a + * TypeError if |this| is null or undefined. This algorithm is the same as + * calling CheckObjectCoercible(this), then returning ToString(this), as all + * String.prototype.* methods do. + */ +static JS_ALWAYS_INLINE JSString * +ThisToStringForStringProto(JSContext *cx, Value *vp) +{ + if (vp[1].isString()) + return vp[1].toString(); + + if (vp[1].isObject()) { + JSObject *obj = &vp[1].toObject(); + if (obj->getClass() == &js_StringClass && + ClassMethodIsNative(cx, obj, + &js_StringClass, + ATOM_TO_JSID(cx->runtime->atomState.toStringAtom), + js_str_toString)) + { + vp[1] = obj->getPrimitiveThis(); + return vp[1].toString(); + } + } else if (vp[1].isNullOrUndefined()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO, + vp[1].isNull() ? "null" : "undefined", "object"); + return NULL; + } + + JSString *str = js_ValueToString(cx, vp[1]); + if (!str) + return NULL; + vp[1].setString(str); + return str; +} + +#if JS_HAS_TOSOURCE + +/* + * String.prototype.quote is generic (as are most string methods), unlike + * toSource, toString, and valueOf. + */ +static JSBool +str_quote(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + str = js_QuoteString(cx, str, '"'); + if (!str) + return false; + vp->setString(str); + return true; +} + +static JSBool +str_toSource(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str; + if (!GetPrimitiveThis(cx, vp, &str)) + return false; + + str = js_QuoteString(cx, str, '"'); + if (!str) + return false; + + char buf[16]; + size_t j = JS_snprintf(buf, sizeof buf, "(new String("); + + JS::Anchor anchor(str); + size_t k = str->length(); + const jschar *s = str->getChars(cx); + if (!s) + return false; + + size_t n = j + k + 2; + jschar *t = (jschar *) cx->malloc((n + 1) * sizeof(jschar)); + if (!t) + return false; + + size_t i; + for (i = 0; i < j; i++) + t[i] = buf[i]; + for (j = 0; j < k; i++, j++) + t[i] = s[j]; + t[i++] = ')'; + t[i++] = ')'; + t[i] = 0; + + str = js_NewString(cx, t, n); + if (!str) { + cx->free(t); + return false; + } + vp->setString(str); + return true; +} + +#endif /* JS_HAS_TOSOURCE */ + +JSBool +js_str_toString(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str; + if (!GetPrimitiveThis(cx, vp, &str)) + return false; + vp->setString(str); + return true; +} + +/* + * Java-like string native methods. + */ + +JS_ALWAYS_INLINE bool +ValueToIntegerRange(JSContext *cx, const Value &v, int32 *out) +{ + if (v.isInt32()) { + *out = v.toInt32(); + } else { + double d; + + if (!ValueToNumber(cx, v, &d)) + return false; + + d = js_DoubleToInteger(d); + if (d > INT32_MAX) + *out = INT32_MAX; + else if (d < INT32_MIN) + *out = INT32_MIN; + else + *out = int32(d); + } + + return true; +} + +static JSBool +str_substring(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + + int32 length, begin, end; + if (argc > 0) { + end = length = int32(str->length()); + + if (!ValueToIntegerRange(cx, vp[2], &begin)) + return false; + + if (begin < 0) + begin = 0; + else if (begin > length) + begin = length; + + if (argc > 1 && !vp[3].isUndefined()) { + if (!ValueToIntegerRange(cx, vp[3], &end)) + return false; + + if (end > length) { + end = length; + } else { + if (end < 0) + end = 0; + if (end < begin) { + int32_t tmp = begin; + begin = end; + end = tmp; + } + } + } + + str = js_NewDependentString(cx, str, size_t(begin), size_t(end - begin)); + if (!str) + return false; + } + + vp->setString(str); + return true; +} + +JSString* JS_FASTCALL +js_toLowerCase(JSContext *cx, JSString *str) +{ + size_t n = str->length(); + const jschar *s = str->getChars(cx); + if (!s) + return NULL; + + jschar *news = (jschar *) cx->malloc((n + 1) * sizeof(jschar)); + if (!news) + return NULL; + for (size_t i = 0; i < n; i++) + news[i] = JS_TOLOWER(s[i]); + news[n] = 0; + str = js_NewString(cx, news, n); + if (!str) { + cx->free(news); + return NULL; + } + return str; +} + +static JSBool +str_toLowerCase(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + str = js_toLowerCase(cx, str); + if (!str) + return false; + vp->setString(str); + return true; +} + +static JSBool +str_toLocaleLowerCase(JSContext *cx, uintN argc, Value *vp) +{ + /* + * Forcefully ignore the first (or any) argument and return toLowerCase(), + * ECMA has reserved that argument, presumably for defining the locale. + */ + if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) { + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + return cx->localeCallbacks->localeToLowerCase(cx, str, Jsvalify(vp)); + } + + return str_toLowerCase(cx, 0, vp); +} + +JSString* JS_FASTCALL +js_toUpperCase(JSContext *cx, JSString *str) +{ + size_t n = str->length(); + const jschar *s = str->getChars(cx); + if (!s) + return NULL; + jschar *news = (jschar *) cx->malloc((n + 1) * sizeof(jschar)); + if (!news) + return NULL; + for (size_t i = 0; i < n; i++) + news[i] = JS_TOUPPER(s[i]); + news[n] = 0; + str = js_NewString(cx, news, n); + if (!str) { + cx->free(news); + return NULL; + } + return str; +} + +static JSBool +str_toUpperCase(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + str = js_toUpperCase(cx, str); + if (!str) + return false; + vp->setString(str); + return true; +} + +static JSBool +str_toLocaleUpperCase(JSContext *cx, uintN argc, Value *vp) +{ + /* + * Forcefully ignore the first (or any) argument and return toUpperCase(), + * ECMA has reserved that argument, presumably for defining the locale. + */ + if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) { + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + return cx->localeCallbacks->localeToUpperCase(cx, str, Jsvalify(vp)); + } + + return str_toUpperCase(cx, 0, vp); +} + +static JSBool +str_localeCompare(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + + if (argc == 0) { + vp->setInt32(0); + } else { + JSString *thatStr = js_ValueToString(cx, vp[2]); + if (!thatStr) + return false; + if (cx->localeCallbacks && cx->localeCallbacks->localeCompare) { + vp[2].setString(thatStr); + return cx->localeCallbacks->localeCompare(cx, str, thatStr, Jsvalify(vp)); + } + int32 result; + if (!CompareStrings(cx, str, thatStr, &result)) + return false; + vp->setInt32(result); + } + return true; +} + +JSBool +js_str_charAt(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str; + jsint i; + jsdouble d; + + if (vp[1].isString() && argc != 0 && vp[2].isInt32()) { + str = vp[1].toString(); + i = vp[2].toInt32(); + if ((size_t)i >= str->length()) + goto out_of_range; + } else { + str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + + if (argc == 0) { + d = 0.0; + } else { + if (!ValueToNumber(cx, vp[2], &d)) + return false; + d = js_DoubleToInteger(d); + } + + if (d < 0 || str->length() <= d) + goto out_of_range; + i = (jsint) d; + } + + str = JSString::getUnitString(cx, str, size_t(i)); + if (!str) + return false; + vp->setString(str); + return true; + + out_of_range: + vp->setString(cx->runtime->emptyString); + return true; +} + +JSBool +js_str_charCodeAt(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str; + jsint i; + if (vp[1].isString() && argc != 0 && vp[2].isInt32()) { + str = vp[1].toString(); + i = vp[2].toInt32(); + if ((size_t)i >= str->length()) + goto out_of_range; + } else { + str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + + double d; + if (argc == 0) { + d = 0.0; + } else { + if (!ValueToNumber(cx, vp[2], &d)) + return false; + d = js_DoubleToInteger(d); + } + + if (d < 0 || str->length() <= d) + goto out_of_range; + i = (jsint) d; + } + + const jschar *chars; + chars = str->getChars(cx); + if (!chars) + return false; + + vp->setInt32(chars[i]); + return true; + +out_of_range: + vp->setDouble(js_NaN); + return true; +} + +jsint +js_BoyerMooreHorspool(const jschar *text, jsuint textlen, + const jschar *pat, jsuint patlen) +{ + uint8 skip[sBMHCharSetSize]; + + JS_ASSERT(0 < patlen && patlen <= sBMHPatLenMax); + for (jsuint i = 0; i < sBMHCharSetSize; i++) + skip[i] = (uint8)patlen; + jsuint m = patlen - 1; + for (jsuint i = 0; i < m; i++) { + jschar c = pat[i]; + if (c >= sBMHCharSetSize) + return sBMHBadPattern; + skip[c] = (uint8)(m - i); + } + jschar c; + for (jsuint k = m; + k < textlen; + k += ((c = text[k]) >= sBMHCharSetSize) ? patlen : skip[c]) { + for (jsuint i = k, j = m; ; i--, j--) { + if (text[i] != pat[j]) + break; + if (j == 0) + return static_cast(i); /* safe: max string size */ + } + } + return -1; +} + +struct MemCmp { + typedef jsuint Extent; + static JS_ALWAYS_INLINE Extent computeExtent(const jschar *, jsuint patlen) { + return (patlen - 1) * sizeof(jschar); + } + static JS_ALWAYS_INLINE bool match(const jschar *p, const jschar *t, Extent extent) { + return memcmp(p, t, extent) == 0; + } +}; + +struct ManualCmp { + typedef const jschar *Extent; + static JS_ALWAYS_INLINE Extent computeExtent(const jschar *pat, jsuint patlen) { + return pat + patlen; + } + static JS_ALWAYS_INLINE bool match(const jschar *p, const jschar *t, Extent extent) { + for (; p != extent; ++p, ++t) { + if (*p != *t) + return false; + } + return true; + } +}; + +template +static jsint +UnrolledMatch(const jschar *text, jsuint textlen, const jschar *pat, jsuint patlen) +{ + JS_ASSERT(patlen > 0 && textlen > 0); + const jschar *textend = text + textlen - (patlen - 1); + const jschar p0 = *pat; + const jschar *const patNext = pat + 1; + const typename InnerMatch::Extent extent = InnerMatch::computeExtent(pat, patlen); + uint8 fixup; + + const jschar *t = text; + switch ((textend - t) & 7) { + case 0: if (*t++ == p0) { fixup = 8; goto match; } + case 7: if (*t++ == p0) { fixup = 7; goto match; } + case 6: if (*t++ == p0) { fixup = 6; goto match; } + case 5: if (*t++ == p0) { fixup = 5; goto match; } + case 4: if (*t++ == p0) { fixup = 4; goto match; } + case 3: if (*t++ == p0) { fixup = 3; goto match; } + case 2: if (*t++ == p0) { fixup = 2; goto match; } + case 1: if (*t++ == p0) { fixup = 1; goto match; } + } + while (t != textend) { + if (t[0] == p0) { t += 1; fixup = 8; goto match; } + if (t[1] == p0) { t += 2; fixup = 7; goto match; } + if (t[2] == p0) { t += 3; fixup = 6; goto match; } + if (t[3] == p0) { t += 4; fixup = 5; goto match; } + if (t[4] == p0) { t += 5; fixup = 4; goto match; } + if (t[5] == p0) { t += 6; fixup = 3; goto match; } + if (t[6] == p0) { t += 7; fixup = 2; goto match; } + if (t[7] == p0) { t += 8; fixup = 1; goto match; } + t += 8; + continue; + do { + if (*t++ == p0) { + match: + if (!InnerMatch::match(patNext, t, extent)) + goto failed_match; + return t - text - 1; + } + failed_match:; + } while (--fixup > 0); + } + return -1; +} + +static JS_ALWAYS_INLINE jsint +StringMatch(const jschar *text, jsuint textlen, + const jschar *pat, jsuint patlen) +{ + if (patlen == 0) + return 0; + if (textlen < patlen) + return -1; + +#if defined(__i386__) || defined(_M_IX86) || defined(__i386) + /* + * Given enough registers, the unrolled loop below is faster than the + * following loop. 32-bit x86 does not have enough registers. + */ + if (patlen == 1) { + const jschar p0 = *pat; + for (const jschar *c = text, *end = text + textlen; c != end; ++c) { + if (*c == p0) + return c - text; + } + return -1; + } +#endif + + /* + * If the text or pattern string is short, BMH will be more expensive than + * the basic linear scan due to initialization cost and a more complex loop + * body. While the correct threshold is input-dependent, we can make a few + * conservative observations: + * - When |textlen| is "big enough", the initialization time will be + * proportionally small, so the worst-case slowdown is minimized. + * - When |patlen| is "too small", even the best case for BMH will be + * slower than a simple scan for large |textlen| due to the more complex + * loop body of BMH. + * From this, the values for "big enough" and "too small" are determined + * empirically. See bug 526348. + */ + if (textlen >= 512 && patlen >= 11 && patlen <= sBMHPatLenMax) { + jsint index = js_BoyerMooreHorspool(text, textlen, pat, patlen); + if (index != sBMHBadPattern) + return index; + } + + /* + * For big patterns with large potential overlap we want the SIMD-optimized + * speed of memcmp. For small patterns, a simple loop is faster. + * + * FIXME: Linux memcmp performance is sad and the manual loop is faster. + */ + return +#if !defined(__linux__) + patlen > 128 ? UnrolledMatch(text, textlen, pat, patlen) + : +#endif + UnrolledMatch(text, textlen, pat, patlen); +} + +static const size_t sRopeMatchThresholdRatioLog2 = 5; + +/* + * RopeMatch takes the text to search, the patern to search for in the text. + * RopeMatch returns false on OOM and otherwise returns the match index through + * the 'match' outparam (-1 for not found). + */ +static bool +RopeMatch(JSContext *cx, JSString *textstr, const jschar *pat, jsuint patlen, jsint *match) +{ + JS_ASSERT(textstr->isRope()); + + if (patlen == 0) { + *match = 0; + return true; + } + if (textstr->length() < patlen) { + *match = -1; + return true; + } + + /* + * List of leaf nodes in the rope. If we run out of memory when trying to + * append to this list, we can still fall back to StringMatch, so use the + * system allocator so we don't report OOM in that case. + */ + Vector strs; + + /* + * We don't want to do rope matching if there is a poor node-to-char ratio, + * since this means spending a lot of time in the match loop below. We also + * need to build the list of leaf nodes. Do both here: iterate over the + * nodes so long as there are not too many. + */ + { + size_t textstrlen = textstr->length(); + size_t threshold = textstrlen >> sRopeMatchThresholdRatioLog2; + StringSegmentRange r(cx); + if (!r.init(textstr)) + return false; + while (!r.empty()) { + if (threshold-- == 0 || !strs.append(r.front())) { + const jschar *chars = textstr->getChars(cx); + if (!chars) + return false; + *match = StringMatch(chars, textstrlen, pat, patlen); + return true; + } + if (!r.popFront()) + return false; + } + } + + /* Absolute offset from the beginning of the logical string textstr. */ + jsint pos = 0; + + // TODO: consider branching to a simple loop if patlen == 1 + + for (JSString **outerp = strs.begin(); outerp != strs.end(); ++outerp) { + /* First try to match without spanning two nodes. */ + JSString *outer = *outerp; + const jschar *chars = outer->nonRopeChars(); + size_t len = outer->length(); + jsint matchResult = StringMatch(chars, len, pat, patlen); + if (matchResult != -1) { + *match = pos + matchResult; + return true; + } + + /* Test the overlap. */ + JSString **innerp = outerp; + + /* + * Start searching at the first place where StringMatch wouldn't have + * found the match. + */ + const jschar *const text = chars + (patlen > len ? 0 : len - patlen + 1); + const jschar *const textend = chars + len; + const jschar p0 = *pat; + const jschar *const p1 = pat + 1; + const jschar *const patend = pat + patlen; + for (const jschar *t = text; t != textend; ) { + if (*t++ != p0) + continue; + const jschar *ttend = textend; + for (const jschar *pp = p1, *tt = t; pp != patend; ++pp, ++tt) { + while (tt == ttend) { + if (++innerp == strs.end()) { + *match = -1; + return true; + } + JSString *inner = *innerp; + tt = inner->nonRopeChars(); + ttend = tt + inner->length(); + } + if (*pp != *tt) + goto break_continue; + } + + /* Matched! */ + *match = pos + (t - chars) - 1; /* -1 because of *t++ above */ + return true; + + break_continue:; + } + + pos += len; + } + + *match = -1; + return true; +} + +static JSBool +str_indexOf(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + + JSLinearString *patstr = ArgToRootedString(cx, argc, vp, 0); + if (!patstr) + return false; + + jsuint textlen = str->length(); + const jschar *text = str->getChars(cx); + if (!text) + return false; + + jsuint patlen = patstr->length(); + const jschar *pat = patstr->chars(); + + jsuint start; + if (argc > 1) { + if (vp[3].isInt32()) { + jsint i = vp[3].toInt32(); + if (i <= 0) { + start = 0; + } else if (jsuint(i) > textlen) { + start = textlen; + textlen = 0; + } else { + start = i; + text += start; + textlen -= start; + } + } else { + jsdouble d; + if (!ValueToNumber(cx, vp[3], &d)) + return JS_FALSE; + d = js_DoubleToInteger(d); + if (d <= 0) { + start = 0; + } else if (d > textlen) { + start = textlen; + textlen = 0; + } else { + start = (jsint)d; + text += start; + textlen -= start; + } + } + } else { + start = 0; + } + + jsint match = StringMatch(text, textlen, pat, patlen); + vp->setInt32((match == -1) ? -1 : start + match); + return true; +} + +static JSBool +str_lastIndexOf(JSContext *cx, uintN argc, Value *vp) +{ + JSString *textstr = ThisToStringForStringProto(cx, vp); + if (!textstr) + return false; + size_t textlen = textstr->length(); + const jschar *text = textstr->getChars(cx); + if (!text) + return false; + + JSLinearString *patstr = ArgToRootedString(cx, argc, vp, 0); + if (!patstr) + return false; + + size_t patlen = patstr->length(); + const jschar *pat = patstr->chars(); + + jsint i = textlen - patlen; // Start searching here + if (i < 0) { + vp->setInt32(-1); + return true; + } + + if (argc > 1) { + if (vp[3].isInt32()) { + jsint j = vp[3].toInt32(); + if (j <= 0) + i = 0; + else if (j < i) + i = j; + } else { + double d; + if (!ValueToNumber(cx, vp[3], &d)) + return false; + if (!JSDOUBLE_IS_NaN(d)) { + d = js_DoubleToInteger(d); + if (d <= 0) + i = 0; + else if (d < i) + i = (jsint)d; + } + } + } + + if (patlen == 0) { + vp->setInt32(i); + return true; + } + + const jschar *t = text + i; + const jschar *textend = text - 1; + const jschar p0 = *pat; + const jschar *patNext = pat + 1; + const jschar *patEnd = pat + patlen; + + for (; t != textend; --t) { + if (*t == p0) { + const jschar *t1 = t + 1; + for (const jschar *p1 = patNext; p1 != patEnd; ++p1, ++t1) { + if (*t1 != *p1) + goto break_continue; + } + vp->setInt32(t - text); + return true; + } + break_continue:; + } + + vp->setInt32(-1); + return true; +} + +static JSBool +js_TrimString(JSContext *cx, Value *vp, JSBool trimLeft, JSBool trimRight) +{ + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + size_t length = str->length(); + const jschar *chars = str->getChars(cx); + if (!chars) + return false; + + size_t begin = 0; + size_t end = length; + + if (trimLeft) { + while (begin < length && JS_ISSPACE(chars[begin])) + ++begin; + } + + if (trimRight) { + while (end > begin && JS_ISSPACE(chars[end-1])) + --end; + } + + str = js_NewDependentString(cx, str, begin, end - begin); + if (!str) + return false; + + vp->setString(str); + return true; +} + +static JSBool +str_trim(JSContext *cx, uintN argc, Value *vp) +{ + return js_TrimString(cx, vp, JS_TRUE, JS_TRUE); +} + +static JSBool +str_trimLeft(JSContext *cx, uintN argc, Value *vp) +{ + return js_TrimString(cx, vp, JS_TRUE, JS_FALSE); +} + +static JSBool +str_trimRight(JSContext *cx, uintN argc, Value *vp) +{ + return js_TrimString(cx, vp, JS_FALSE, JS_TRUE); +} + +/* + * Perl-inspired string functions. + */ + +/* Result of a successfully performed flat match. */ +class FlatMatch +{ + JSLinearString *patstr; + const jschar *pat; + size_t patlen; + int32 match_; + + friend class RegExpGuard; + + public: + FlatMatch() : patstr(NULL) {} /* Old GCC wants this initialization. */ + JSString *pattern() const { return patstr; } + size_t patternLength() const { return patlen; } + + /* + * Note: The match is -1 when the match is performed successfully, + * but no match is found. + */ + int32 match() const { return match_; } +}; + +/* A regexp and optional associated object. */ +class RegExpPair +{ + AutoRefCount re_; + JSObject *reobj_; + + explicit RegExpPair(RegExpPair &); + + public: + explicit RegExpPair(JSContext *cx) : re_(cx) {} + + void reset(JSObject &obj) { + reobj_ = &obj; + RegExp *re = RegExp::extractFrom(reobj_); + JS_ASSERT(re); + re_.reset(NeedsIncRef(re)); + } + + void reset(AlreadyIncRefed re) { + reobj_ = NULL; + re_.reset(re); + } + + /* Note: May be null. */ + JSObject *reobj() const { return reobj_; } + bool hasRegExp() const { return !re_.null(); } + RegExp &re() const { JS_ASSERT(hasRegExp()); return *re_; } +}; + +/* + * RegExpGuard factors logic out of String regexp operations. + * + * @param optarg Indicates in which argument position RegExp + * flags will be found, if present. This is a Mozilla + * extension and not part of any ECMA spec. + */ +class RegExpGuard +{ + RegExpGuard(const RegExpGuard &); + void operator=(const RegExpGuard &); + + JSContext *cx; + RegExpPair rep; + FlatMatch fm; + + /* + * Upper bound on the number of characters we are willing to potentially + * waste on searching for RegExp meta-characters. + */ + static const size_t MAX_FLAT_PAT_LEN = 256; + + static JSString *flattenPattern(JSContext *cx, JSLinearString *patstr) { + StringBuffer sb(cx); + if (!sb.reserve(patstr->length())) + return NULL; + + static const jschar ESCAPE_CHAR = '\\'; + const jschar *chars = patstr->chars(); + size_t len = patstr->length(); + for (const jschar *it = chars; it != chars + len; ++it) { + if (RegExp::isMetaChar(*it)) { + if (!sb.append(ESCAPE_CHAR) || !sb.append(*it)) + return NULL; + } else { + if (!sb.append(*it)) + return NULL; + } + } + return sb.finishString(); + } + + public: + explicit RegExpGuard(JSContext *cx) : cx(cx), rep(cx) {} + ~RegExpGuard() {} + + /* init must succeed in order to call tryFlatMatch or normalizeRegExp. */ + bool + init(uintN argc, Value *vp) + { + if (argc != 0 && VALUE_IS_REGEXP(cx, vp[2])) { + rep.reset(vp[2].toObject()); + } else { + fm.patstr = ArgToRootedString(cx, argc, vp, 0); + if (!fm.patstr) + return false; + } + return true; + } + + /* + * Attempt to match |patstr| to |textstr|. A flags argument, metachars in the + * pattern string, or a lengthy pattern string can thwart this process. + * + * @param checkMetaChars Look for regexp metachars in the pattern string. + * @return Whether flat matching could be used. + * + * N.B. tryFlatMatch returns NULL on OOM, so the caller must check cx->isExceptionPending(). + */ + const FlatMatch * + tryFlatMatch(JSContext *cx, JSString *textstr, uintN optarg, uintN argc, + bool checkMetaChars = true) + { + if (rep.hasRegExp()) + return NULL; + + fm.pat = fm.patstr->chars(); + fm.patlen = fm.patstr->length(); + + if (optarg < argc) + return NULL; + + if (checkMetaChars && + (fm.patlen > MAX_FLAT_PAT_LEN || RegExp::hasMetaChars(fm.pat, fm.patlen))) { + return NULL; + } + + /* + * textstr could be a rope, so we want to avoid flattening it for as + * long as possible. + */ + if (textstr->isRope()) { + if (!RopeMatch(cx, textstr, fm.pat, fm.patlen, &fm.match_)) + return NULL; + } else { + const jschar *text = textstr->nonRopeChars(); + size_t textlen = textstr->length(); + fm.match_ = StringMatch(text, textlen, fm.pat, fm.patlen); + } + return &fm; + } + + /* If the pattern is not already a regular expression, make it so. */ + const RegExpPair * + normalizeRegExp(bool flat, uintN optarg, uintN argc, Value *vp) + { + if (rep.hasRegExp()) + return &rep; + + /* Build RegExp from pattern string. */ + JSString *opt; + if (optarg < argc) { + opt = js_ValueToString(cx, vp[2 + optarg]); + if (!opt) + return NULL; + } else { + opt = NULL; + } + + JSString *patstr; + if (flat) { + patstr = flattenPattern(cx, fm.patstr); + if (!patstr) + return false; + } else { + patstr = fm.patstr; + } + JS_ASSERT(patstr); + + AlreadyIncRefed re = RegExp::createFlagged(cx, patstr, opt); + if (!re) + return NULL; + rep.reset(re); + return &rep; + } + +#if DEBUG + bool hasRegExpPair() const { return rep.hasRegExp(); } +#endif +}; + +/* js_ExecuteRegExp indicates success in two ways, based on the 'test' flag. */ +static JS_ALWAYS_INLINE bool +Matched(bool test, const Value &v) +{ + return test ? v.isTrue() : !v.isNull(); +} + +typedef bool (*DoMatchCallback)(JSContext *cx, RegExpStatics *res, size_t count, void *data); + +/* + * BitOR-ing these flags allows the DoMatch caller to control when how the + * RegExp engine is called and when callbacks are fired. + */ +enum MatchControlFlags { + TEST_GLOBAL_BIT = 0x1, /* use RegExp.test for global regexps */ + TEST_SINGLE_BIT = 0x2, /* use RegExp.test for non-global regexps */ + CALLBACK_ON_SINGLE_BIT = 0x4, /* fire callback on non-global match */ + + MATCH_ARGS = TEST_GLOBAL_BIT, + MATCHALL_ARGS = CALLBACK_ON_SINGLE_BIT, + REPLACE_ARGS = TEST_GLOBAL_BIT | TEST_SINGLE_BIT | CALLBACK_ON_SINGLE_BIT +}; + +/* Factor out looping and matching logic. */ +static bool +DoMatch(JSContext *cx, RegExpStatics *res, Value *vp, JSString *str, const RegExpPair &rep, + DoMatchCallback callback, void *data, MatchControlFlags flags) +{ + RegExp &re = rep.re(); + if (re.global()) { + /* global matching ('g') */ + bool testGlobal = flags & TEST_GLOBAL_BIT; + if (rep.reobj()) + rep.reobj()->zeroRegExpLastIndex(); + for (size_t count = 0, i = 0, length = str->length(); i <= length; ++count) { + if (!re.execute(cx, res, str, &i, testGlobal, vp)) + return false; + if (!Matched(testGlobal, *vp)) + break; + if (!callback(cx, res, count, data)) + return false; + if (!res->matched()) + ++i; + } + } else { + /* single match */ + bool testSingle = !!(flags & TEST_SINGLE_BIT), + callbackOnSingle = !!(flags & CALLBACK_ON_SINGLE_BIT); + size_t i = 0; + if (!re.execute(cx, res, str, &i, testSingle, vp)) + return false; + if (callbackOnSingle && Matched(testSingle, *vp) && !callback(cx, res, 0, data)) + return false; + } + return true; +} + +static bool +BuildFlatMatchArray(JSContext *cx, JSString *textstr, const FlatMatch &fm, Value *vp) +{ + if (fm.match() < 0) { + vp->setNull(); + return true; + } + + /* For this non-global match, produce a RegExp.exec-style array. */ + JSObject *obj = NewSlowEmptyArray(cx); + if (!obj) + return false; + vp->setObject(*obj); + + return obj->defineProperty(cx, INT_TO_JSID(0), StringValue(fm.pattern())) && + obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.indexAtom), + Int32Value(fm.match())) && + obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.inputAtom), + StringValue(textstr)); +} + +typedef JSObject **MatchArgType; + +/* + * DoMatch will only callback on global matches, hence this function builds + * only the "array of matches" returned by match on global regexps. + */ +static bool +MatchCallback(JSContext *cx, RegExpStatics *res, size_t count, void *p) +{ + JS_ASSERT(count <= JSID_INT_MAX); /* by max string length */ + + JSObject *&arrayobj = *static_cast(p); + if (!arrayobj) { + arrayobj = NewDenseEmptyArray(cx); + if (!arrayobj) + return false; + } + + Value v; + if (!res->createLastMatch(cx, &v)) + return false; + + JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING); + return !!arrayobj->setProperty(cx, INT_TO_JSID(count), &v, false); +} + +static JSBool +str_match(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + + RegExpGuard g(cx); + if (!g.init(argc, vp)) + return false; + if (const FlatMatch *fm = g.tryFlatMatch(cx, str, 1, argc)) + return BuildFlatMatchArray(cx, str, *fm, vp); + if (cx->isExceptionPending()) /* from tryFlatMatch */ + return false; + + const RegExpPair *rep = g.normalizeRegExp(false, 1, argc, vp); + if (!rep) + return false; + + AutoObjectRooter array(cx); + MatchArgType arg = array.addr(); + RegExpStatics *res = cx->regExpStatics(); + if (!DoMatch(cx, res, vp, str, *rep, MatchCallback, arg, MATCH_ARGS)) + return false; + + /* When not global, DoMatch will leave |RegExp.exec()| in *vp. */ + if (rep->re().global()) + vp->setObjectOrNull(array.object()); + return true; +} + +static JSBool +str_search(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + + RegExpGuard g(cx); + if (!g.init(argc, vp)) + return false; + if (const FlatMatch *fm = g.tryFlatMatch(cx, str, 1, argc)) { + vp->setInt32(fm->match()); + return true; + } + if (cx->isExceptionPending()) /* from tryFlatMatch */ + return false; + const RegExpPair *rep = g.normalizeRegExp(false, 1, argc, vp); + if (!rep) + return false; + + RegExpStatics *res = cx->regExpStatics(); + size_t i = 0; + if (!rep->re().execute(cx, res, str, &i, true, vp)) + return false; + + if (vp->isTrue()) + vp->setInt32(res->matchStart()); + else + vp->setInt32(-1); + return true; +} + +struct ReplaceData +{ + ReplaceData(JSContext *cx) + : g(cx), sb(cx) + {} + + JSString *str; /* 'this' parameter object as a string */ + RegExpGuard g; /* regexp parameter object and private data */ + JSObject *lambda; /* replacement function object or null */ + JSObject *elembase; /* object for function(a){return b[a]} replace */ + JSLinearString *repstr; /* replacement string */ + const jschar *dollar; /* null or pointer to first $ in repstr */ + const jschar *dollarEnd; /* limit pointer for js_strchr_limit */ + jsint leftIndex; /* left context index in str->chars */ + JSSubString dollarStr; /* for "$$" InterpretDollar result */ + bool calledBack; /* record whether callback has been called */ + InvokeSessionGuard session; /* arguments for repeated lambda Invoke call */ + InvokeArgsGuard singleShot; /* arguments for single lambda Invoke call */ + StringBuffer sb; /* buffer built during DoMatch */ +}; + +static bool +InterpretDollar(JSContext *cx, RegExpStatics *res, const jschar *dp, const jschar *ep, + ReplaceData &rdata, JSSubString *out, size_t *skip) +{ + JS_ASSERT(*dp == '$'); + + /* If there is only a dollar, bail now */ + if (dp + 1 >= ep) + return false; + + /* Interpret all Perl match-induced dollar variables. */ + jschar dc = dp[1]; + if (JS7_ISDEC(dc)) { + /* ECMA-262 Edition 3: 1-9 or 01-99 */ + uintN num = JS7_UNDEC(dc); + if (num > res->parenCount()) + return false; + + const jschar *cp = dp + 2; + if (cp < ep && (dc = *cp, JS7_ISDEC(dc))) { + uintN tmp = 10 * num + JS7_UNDEC(dc); + if (tmp <= res->parenCount()) { + cp++; + num = tmp; + } + } + if (num == 0) + return false; + + *skip = cp - dp; + + JS_ASSERT(num <= res->parenCount()); + + /* + * Note: we index to get the paren with the (1-indexed) pair + * number, as opposed to a (0-indexed) paren number. + */ + res->getParen(num, out); + return true; + } + + *skip = 2; + switch (dc) { + case '$': + rdata.dollarStr.chars = dp; + rdata.dollarStr.length = 1; + *out = rdata.dollarStr; + return true; + case '&': + res->getLastMatch(out); + return true; + case '+': + res->getLastParen(out); + return true; + case '`': + res->getLeftContext(out); + return true; + case '\'': + res->getRightContext(out); + return true; + } + return false; +} + +static bool +FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t *sizep) +{ + JSObject *base = rdata.elembase; + if (base) { + /* + * The base object is used when replace was passed a lambda which looks like + * 'function(a) { return b[a]; }' for the base object b. b will not change + * in the course of the replace unless we end up making a scripted call due + * to accessing a scripted getter or a value with a scripted toString. + */ + JS_ASSERT(rdata.lambda); + JS_ASSERT(!base->getOps()->lookupProperty); + JS_ASSERT(!base->getOps()->getProperty); + + Value match; + if (!res->createLastMatch(cx, &match)) + return false; + JSString *str = match.toString(); + + JSAtom *atom; + if (str->isAtomized()) { + atom = STRING_TO_ATOM(str); + } else { + atom = js_AtomizeString(cx, str, 0); + if (!atom) + return false; + } + jsid id = ATOM_TO_JSID(atom); + + JSObject *holder; + JSProperty *prop = NULL; + if (js_LookupPropertyWithFlags(cx, base, id, JSRESOLVE_QUALIFIED, &holder, &prop) < 0) + return false; + + /* Only handle the case where the property exists and is on this object. */ + if (prop && holder == base) { + Shape *shape = (Shape *) prop; + if (shape->slot != SHAPE_INVALID_SLOT && shape->hasDefaultGetter()) { + Value value = base->getSlot(shape->slot); + if (value.isString()) { + rdata.repstr = value.toString()->ensureLinear(cx); + if (!rdata.repstr) + return false; + *sizep = rdata.repstr->length(); + return true; + } + } + } + + /* + * Couldn't handle this property, fall through and despecialize to the + * general lambda case. + */ + rdata.elembase = NULL; + } + + JSObject *lambda = rdata.lambda; + if (lambda) { + /* + * In the lambda case, not only do we find the replacement string's + * length, we compute repstr and return it via rdata for use within + * DoReplace. The lambda is called with arguments ($&, $1, $2, ..., + * index, input), i.e., all the properties of a regexp match array. + * For $&, etc., we must create string jsvals from cx->regExpStatics. + * We grab up stack space to keep the newborn strings GC-rooted. + */ + uintN p = res->parenCount(); + uintN argc = 1 + p + 2; + + InvokeSessionGuard &session = rdata.session; + if (!session.started()) { + Value lambdav = ObjectValue(*lambda); + if (!session.start(cx, lambdav, UndefinedValue(), argc)) + return false; + } + + PreserveRegExpStatics staticsGuard(res); + if (!staticsGuard.init(cx)) + return false; + + /* Push $&, $1, $2, ... */ + uintN argi = 0; + if (!res->createLastMatch(cx, &session[argi++])) + return false; + + for (size_t i = 0; i < res->parenCount(); ++i) { + if (!res->createParen(cx, i + 1, &session[argi++])) + return false; + } + + /* Push match index and input string. */ + session[argi++].setInt32(res->matchStart()); + session[argi].setString(rdata.str); + + if (!session.invoke(cx)) + return false; + + /* root repstr: rdata is on the stack, so scanned by conservative gc. */ + JSString *repstr = ValueToString_TestForStringInline(cx, session.rval()); + if (!repstr) + return false; + rdata.repstr = repstr->ensureLinear(cx); + if (!rdata.repstr) + return false; + *sizep = rdata.repstr->length(); + return true; + } + + JSString *repstr = rdata.repstr; + size_t replen = repstr->length(); + for (const jschar *dp = rdata.dollar, *ep = rdata.dollarEnd; dp; + dp = js_strchr_limit(dp, '$', ep)) { + JSSubString sub; + size_t skip; + if (InterpretDollar(cx, res, dp, ep, rdata, &sub, &skip)) { + replen += sub.length - skip; + dp += skip; + } else { + dp++; + } + } + *sizep = replen; + return true; +} + +/* + * Precondition: |rdata.sb| already has necessary growth space reserved (as + * derived from FindReplaceLength). + */ +static void +DoReplace(JSContext *cx, RegExpStatics *res, ReplaceData &rdata) +{ + JSLinearString *repstr = rdata.repstr; + const jschar *cp; + const jschar *bp = cp = repstr->chars(); + + const jschar *dp = rdata.dollar; + const jschar *ep = rdata.dollarEnd; + for (; dp; dp = js_strchr_limit(dp, '$', ep)) { + /* Move one of the constant portions of the replacement value. */ + size_t len = dp - cp; + JS_ALWAYS_TRUE(rdata.sb.append(cp, len)); + cp = dp; + + JSSubString sub; + size_t skip; + if (InterpretDollar(cx, res, dp, ep, rdata, &sub, &skip)) { + len = sub.length; + JS_ALWAYS_TRUE(rdata.sb.append(sub.chars, len)); + cp += skip; + dp += skip; + } else { + dp++; + } + } + JS_ALWAYS_TRUE(rdata.sb.append(cp, repstr->length() - (cp - bp))); +} + +static bool +ReplaceRegExpCallback(JSContext *cx, RegExpStatics *res, size_t count, void *p) +{ + ReplaceData &rdata = *static_cast(p); + + rdata.calledBack = true; + JSLinearString *str = rdata.str->assertIsLinear(); /* flattened for regexp */ + size_t leftoff = rdata.leftIndex; + const jschar *left = str->chars() + leftoff; + size_t leftlen = res->matchStart() - leftoff; + rdata.leftIndex = res->matchLimit(); + + size_t replen = 0; /* silence 'unused' warning */ + if (!FindReplaceLength(cx, res, rdata, &replen)) + return false; + + size_t growth = leftlen + replen; + if (!rdata.sb.reserve(rdata.sb.length() + growth)) + return false; + JS_ALWAYS_TRUE(rdata.sb.append(left, leftlen)); /* skipped-over portion of the search value */ + DoReplace(cx, res, rdata); + return true; +} + +static bool +BuildFlatReplacement(JSContext *cx, JSString *textstr, JSString *repstr, + const FlatMatch &fm, Value *vp) +{ + RopeBuilder builder(cx); + size_t match = fm.match(); + size_t matchEnd = match + fm.patternLength(); + + if (textstr->isRope()) { + /* + * If we are replacing over a rope, avoid flattening it by iterating + * through it, building a new rope. + */ + StringSegmentRange r(cx); + if (!r.init(textstr)) + return false; + size_t pos = 0; + while (!r.empty()) { + JSString *str = r.front(); + size_t len = str->length(); + size_t strEnd = pos + len; + if (pos < matchEnd && strEnd > match) { + /* + * We need to special-case any part of the rope that overlaps + * with the replacement string. + */ + if (match >= pos) { + /* + * If this part of the rope overlaps with the left side of + * the pattern, then it must be the only one to overlap with + * the first character in the pattern, so we include the + * replacement string here. + */ + JSString *leftSide = js_NewDependentString(cx, str, 0, match - pos); + if (!leftSide || + !builder.append(leftSide) || + !builder.append(repstr)) { + return false; + } + } + + /* + * If str runs off the end of the matched string, append the + * last part of str. + */ + if (strEnd > matchEnd) { + JSString *rightSide = js_NewDependentString(cx, str, matchEnd - pos, + strEnd - matchEnd); + if (!rightSide || !builder.append(rightSide)) + return false; + } + } else { + if (!builder.append(str)) + return false; + } + pos += str->length(); + if (!r.popFront()) + return false; + } + } else { + JSString *leftSide = js_NewDependentString(cx, textstr, 0, match); + if (!leftSide) + return false; + JSString *rightSide = js_NewDependentString(cx, textstr, match + fm.patternLength(), + textstr->length() - match - fm.patternLength()); + if (!rightSide || + !builder.append(leftSide) || + !builder.append(repstr) || + !builder.append(rightSide)) { + return false; + } + } + + vp->setString(builder.result()); + return true; +} + +/* + * Perform a linear-scan dollar substitution on the replacement text, + * constructing a result string that looks like: + * + * newstring = string[:matchStart] + dollarSub(replaceValue) + string[matchLimit:] + */ +static inline bool +BuildDollarReplacement(JSContext *cx, JSString *textstrArg, JSLinearString *repstr, + const jschar *firstDollar, const FlatMatch &fm, Value *vp) +{ + JSLinearString *textstr = textstrArg->ensureLinear(cx); + if (!textstr) + return NULL; + + JS_ASSERT(repstr->chars() <= firstDollar && firstDollar < repstr->chars() + repstr->length()); + size_t matchStart = fm.match(); + size_t matchLimit = matchStart + fm.patternLength(); + + /* + * Most probably: + * + * len(newstr) >= len(orig) - len(match) + len(replacement) + * + * Note that dollar vars _could_ make the resulting text smaller than this. + */ + StringBuffer newReplaceChars(cx); + if (!newReplaceChars.reserve(textstr->length() - fm.patternLength() + repstr->length())) + return false; + + /* Move the pre-dollar chunk in bulk. */ + JS_ALWAYS_TRUE(newReplaceChars.append(repstr->chars(), firstDollar)); + + /* Move the rest char-by-char, interpreting dollars as we encounter them. */ +#define ENSURE(__cond) if (!(__cond)) return false; + const jschar *repstrLimit = repstr->chars() + repstr->length(); + for (const jschar *it = firstDollar; it < repstrLimit; ++it) { + if (*it != '$' || it == repstrLimit - 1) { + ENSURE(newReplaceChars.append(*it)); + continue; + } + + switch (*(it + 1)) { + case '$': /* Eat one of the dollars. */ + ENSURE(newReplaceChars.append(*it)); + break; + case '&': + ENSURE(newReplaceChars.append(textstr->chars() + matchStart, + textstr->chars() + matchLimit)); + break; + case '`': + ENSURE(newReplaceChars.append(textstr->chars(), textstr->chars() + matchStart)); + break; + case '\'': + ENSURE(newReplaceChars.append(textstr->chars() + matchLimit, + textstr->chars() + textstr->length())); + break; + default: /* The dollar we saw was not special (no matter what its mother told it). */ + ENSURE(newReplaceChars.append(*it)); + continue; + } + ++it; /* We always eat an extra char in the above switch. */ + } + + JSString *leftSide = js_NewDependentString(cx, textstr, 0, matchStart); + ENSURE(leftSide); + + JSString *newReplace = newReplaceChars.finishString(); + ENSURE(newReplace); + + JS_ASSERT(textstr->length() >= matchLimit); + JSString *rightSide = js_NewDependentString(cx, textstr, matchLimit, + textstr->length() - matchLimit); + ENSURE(rightSide); + + RopeBuilder builder(cx); + ENSURE(builder.append(leftSide) && + builder.append(newReplace) && + builder.append(rightSide)); +#undef ENSURE + + vp->setString(builder.result()); + return true; +} + +static inline bool +str_replace_regexp(JSContext *cx, uintN argc, Value *vp, ReplaceData &rdata) +{ + const RegExpPair *rep = rdata.g.normalizeRegExp(true, 2, argc, vp); + if (!rep) + return false; + + rdata.leftIndex = 0; + rdata.calledBack = false; + + RegExpStatics *res = cx->regExpStatics(); + if (!DoMatch(cx, res, vp, rdata.str, *rep, ReplaceRegExpCallback, &rdata, REPLACE_ARGS)) + return false; + + if (!rdata.calledBack) { + /* Didn't match, so the string is unmodified. */ + vp->setString(rdata.str); + return true; + } + + JSSubString sub; + res->getRightContext(&sub); + if (!rdata.sb.append(sub.chars, sub.length)) + return false; + + JSString *retstr = rdata.sb.finishString(); + if (!retstr) + return false; + + vp->setString(retstr); + return true; +} + +static inline bool +str_replace_flat_lambda(JSContext *cx, uintN argc, Value *vp, ReplaceData &rdata, + const FlatMatch &fm) +{ + JS_ASSERT(fm.match() >= 0); + LeaveTrace(cx); + + JSString *matchStr = js_NewDependentString(cx, rdata.str, fm.match(), fm.patternLength()); + if (!matchStr) + return false; + + /* lambda(matchStr, matchStart, textstr) */ + static const uint32 lambdaArgc = 3; + if (!cx->stack().pushInvokeArgs(cx, lambdaArgc, &rdata.singleShot)) + return false; + + CallArgs &args = rdata.singleShot; + args.callee().setObject(*rdata.lambda); + args.thisv().setUndefined(); + + Value *sp = args.argv(); + sp[0].setString(matchStr); + sp[1].setInt32(fm.match()); + sp[2].setString(rdata.str); + + if (!Invoke(cx, rdata.singleShot, 0)) + return false; + + JSString *repstr = js_ValueToString(cx, args.rval()); + if (!repstr) + return false; + + JSString *leftSide = js_NewDependentString(cx, rdata.str, 0, fm.match()); + if (!leftSide) + return false; + + size_t matchLimit = fm.match() + fm.patternLength(); + JSString *rightSide = js_NewDependentString(cx, rdata.str, matchLimit, + rdata.str->length() - matchLimit); + if (!rightSide) + return false; + + RopeBuilder builder(cx); + if (!(builder.append(leftSide) && + builder.append(repstr) && + builder.append(rightSide))) { + return false; + } + + vp->setString(builder.result()); + return true; +} + +JSBool +js::str_replace(JSContext *cx, uintN argc, Value *vp) +{ + ReplaceData rdata(cx); + rdata.str = ThisToStringForStringProto(cx, vp); + if (!rdata.str) + return false; + static const uint32 optarg = 2; + + /* Extract replacement string/function. */ + if (argc >= optarg && js_IsCallable(vp[3])) { + rdata.lambda = &vp[3].toObject(); + rdata.elembase = NULL; + rdata.repstr = NULL; + rdata.dollar = rdata.dollarEnd = NULL; + + if (rdata.lambda->isFunction()) { + JSFunction *fun = rdata.lambda->getFunctionPrivate(); + if (fun->isInterpreted()) { + /* + * Pattern match the script to check if it is is indexing into a + * particular object, e.g. 'function(a) { return b[a]; }'. Avoid + * calling the script in such cases, which are used by javascript + * packers (particularly the popular Dean Edwards packer) to efficiently + * encode large scripts. We only handle the code patterns generated + * by such packers here. + */ + JSScript *script = fun->u.i.script; + jsbytecode *pc = script->code; + + Value table = UndefinedValue(); + if (JSOp(*pc) == JSOP_GETFCSLOT) { + table = rdata.lambda->getFlatClosureUpvar(GET_UINT16(pc)); + pc += JSOP_GETFCSLOT_LENGTH; + } + + if (table.isObject() && + JSOp(*pc) == JSOP_GETARG && GET_SLOTNO(pc) == 0 && + JSOp(*(pc + JSOP_GETARG_LENGTH)) == JSOP_GETELEM && + JSOp(*(pc + JSOP_GETARG_LENGTH + JSOP_GETELEM_LENGTH)) == JSOP_RETURN) { + Class *clasp = table.toObject().getClass(); + if (clasp->isNative() && + !clasp->ops.lookupProperty && + !clasp->ops.getProperty) { + rdata.elembase = &table.toObject(); + } + } + } + } + } else { + rdata.lambda = NULL; + rdata.elembase = NULL; + rdata.repstr = ArgToRootedString(cx, argc, vp, 1); + if (!rdata.repstr) + return false; + + /* We're about to store pointers into the middle of our string. */ + if (!js_MakeStringImmutable(cx, rdata.repstr)) + return false; + rdata.dollarEnd = rdata.repstr->chars() + rdata.repstr->length(); + rdata.dollar = js_strchr_limit(rdata.repstr->chars(), '$', + rdata.dollarEnd); + } + + if (!rdata.g.init(argc, vp)) + return false; + + /* + * Unlike its |String.prototype| brethren, |replace| doesn't convert + * its input to a regular expression. (Even if it contains metachars.) + * + * However, if the user invokes our (non-standard) |flags| argument + * extension then we revert to creating a regular expression. Note that + * this is observable behavior through the side-effect mutation of the + * |RegExp| statics. + */ + + const FlatMatch *fm = rdata.g.tryFlatMatch(cx, rdata.str, optarg, argc, false); + if (!fm) { + if (cx->isExceptionPending()) /* oom in RopeMatch in tryFlatMatch */ + return false; + JS_ASSERT_IF(!rdata.g.hasRegExpPair(), argc > optarg); + return str_replace_regexp(cx, argc, vp, rdata); + } + + if (fm->match() < 0) { + vp->setString(rdata.str); + return true; + } + + if (rdata.lambda) + return str_replace_flat_lambda(cx, argc, vp, rdata, *fm); + + /* + * Note: we could optimize the text.length == pattern.length case if we wanted, + * even in the presence of dollar metachars. + */ + if (rdata.dollar) + return BuildDollarReplacement(cx, rdata.str, rdata.repstr, rdata.dollar, *fm, vp); + + return BuildFlatReplacement(cx, rdata.str, rdata.repstr, *fm, vp); +} + +/* + * Subroutine used by str_split to find the next split point in str, starting + * at offset *ip and looking either for the separator substring given by sep, or + * for the next re match. In the re case, return the matched separator in *sep, + * and the possibly updated offset in *ip. + * + * Return -2 on error, -1 on end of string, >= 0 for a valid index of the next + * separator occurrence if found, or str->length if no separator is found. + */ +static jsint +find_split(JSContext *cx, RegExpStatics *res, JSString *str, js::RegExp *re, jsint *ip, + JSSubString *sep) +{ + /* + * Stop if past end of string. If at end of string, we will compare the + * null char stored there (by js_NewString*) to sep->chars[j] in the while + * loop at the end of this function, so that + * + * "ab,".split(',') => ["ab", ""] + * + * and the resulting array converts back to the string "ab," for symmetry. + * However, we ape Perl and do this only if there is a sufficiently large + * limit argument (see str_split). + */ + jsint i = *ip; + size_t length = str->length(); + if ((size_t)i > length) + return -1; + + const jschar *chars = str->getChars(cx); + if (!chars) + return -2; + + /* + * Match a regular expression against the separator at or above index i. + * Call js_ExecuteRegExp with true for the test argument. On successful + * match, get the separator from cx->regExpStatics.lastMatch. + */ + if (re) { + size_t index; + Value rval; + + again: + /* JS1.2 deviated from Perl by never matching at end of string. */ + index = (size_t)i; + if (!re->execute(cx, res, str, &index, true, &rval)) + return -2; + if (!rval.isTrue()) { + /* Mismatch: ensure our caller advances i past end of string. */ + sep->length = 1; + return length; + } + i = (jsint)index; + JS_ASSERT(sep); + res->getLastMatch(sep); + if (sep->length == 0) { + /* + * Empty string match: never split on an empty match at the start + * of a find_split cycle. Same rule as for an empty global match + * in DoMatch. + */ + if (i == *ip) { + /* + * "Bump-along" to avoid sticking at an empty match, but don't + * bump past end of string -- our caller must do that by adding + * sep->length to our return value. + */ + if ((size_t)i == length) + return -1; + i++; + goto again; + } + if ((size_t)i == length) { + /* + * If there was a trivial zero-length match at the end of the + * split, then we shouldn't output the matched string at the end + * of the split array. See ECMA-262 Ed. 3, 15.5.4.14, Step 15. + */ + sep->chars = NULL; + } + } + JS_ASSERT((size_t)i >= sep->length); + return i - sep->length; + } + + /* + * Special case: if sep is the empty string, split str into one character + * substrings. Let our caller worry about whether to split once at end of + * string into an empty substring. + */ + if (sep->length == 0) + return ((size_t)i == length) ? -1 : i + 1; + + /* + * Now that we know sep is non-empty, search starting at i in str for an + * occurrence of all of sep's chars. If we find them, return the index of + * the first separator char. Otherwise, return length. + */ + jsint match = StringMatch(chars + i, length - i, sep->chars, sep->length); + return match == -1 ? length : match + i; +} + +static JSBool +str_split(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + + if (argc == 0) { + Value v = StringValue(str); + JSObject *aobj = NewDenseCopiedArray(cx, 1, &v); + if (!aobj) + return false; + vp->setObject(*aobj); + return true; + } + + RegExp *re; + JSSubString *sep, tmp; + if (VALUE_IS_REGEXP(cx, vp[2])) { + re = static_cast(vp[2].toObject().getPrivate()); + sep = &tmp; + + /* Set a magic value so we can detect a successful re match. */ + sep->chars = NULL; + sep->length = 0; + } else { + JSString *sepstr = js_ValueToString(cx, vp[2]); + if (!sepstr) + return false; + vp[2].setString(sepstr); + + /* + * Point sep at a local copy of sepstr's header because find_split + * will modify sep->length. + */ + tmp.length = sepstr->length(); + tmp.chars = sepstr->getChars(cx); + if (!tmp.chars) + return false; + re = NULL; + sep = &tmp; + } + + /* Use the second argument as the split limit, if given. */ + uint32 limit = 0; /* Avoid warning. */ + bool limited = (argc > 1) && !vp[3].isUndefined(); + if (limited) { + jsdouble d; + if (!ValueToNumber(cx, vp[3], &d)) + return false; + + /* Clamp limit between 0 and 1 + string length. */ + limit = js_DoubleToECMAUint32(d); + if (limit > str->length()) + limit = 1 + str->length(); + } + + AutoValueVector splits(cx); + + RegExpStatics *res = cx->regExpStatics(); + jsint i, j; + uint32 len = i = 0; + while ((j = find_split(cx, res, str, re, &i, sep)) >= 0) { + if (limited && len >= limit) + break; + + JSString *sub = js_NewDependentString(cx, str, i, size_t(j - i)); + if (!sub || !splits.append(StringValue(sub))) + return false; + len++; + + /* + * Imitate perl's feature of including parenthesized substrings that + * matched part of the delimiter in the new array, after the split + * substring that was delimited. + */ + if (re && sep->chars) { + for (uintN num = 0; num < res->parenCount(); num++) { + if (limited && len >= limit) + break; + JSSubString parsub; + res->getParen(num + 1, &parsub); + sub = js_NewStringCopyN(cx, parsub.chars, parsub.length); + if (!sub || !splits.append(StringValue(sub))) + return false; + len++; + } + sep->chars = NULL; + } + i = j + sep->length; + } + + if (j == -2) + return false; + + JSObject *aobj = NewDenseCopiedArray(cx, splits.length(), splits.begin()); + if (!aobj) + return false; + vp->setObject(*aobj); + return true; +} + +#if JS_HAS_PERL_SUBSTR +static JSBool +str_substr(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + + int32 length, len, begin; + if (argc > 0) { + length = int32(str->length()); + if (!ValueToIntegerRange(cx, vp[2], &begin)) + return false; + + if (begin >= length) { + str = cx->runtime->emptyString; + goto out; + } + if (begin < 0) { + begin += length; /* length + INT_MIN will always be less then 0 */ + if (begin < 0) + begin = 0; + } + + if (argc == 1 || vp[3].isUndefined()) { + len = length - begin; + } else { + if (!ValueToIntegerRange(cx, vp[3], &len)) + return false; + + if (len <= 0) { + str = cx->runtime->emptyString; + goto out; + } + + if (uint32(length) < uint32(begin + len)) + len = length - begin; + } + + str = js_NewDependentString(cx, str, size_t(begin), size_t(len)); + if (!str) + return false; + } + +out: + vp->setString(str); + return true; +} +#endif /* JS_HAS_PERL_SUBSTR */ + +/* + * Python-esque sequence operations. + */ +static JSBool +str_concat(JSContext *cx, uintN argc, Value *vp) +{ + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + + /* Set vp (aka rval) early to handle the argc == 0 case. */ + vp->setString(str); + + Value *argv; + uintN i; + for (i = 0, argv = vp + 2; i < argc; i++) { + JSString *str2 = js_ValueToString(cx, argv[i]); + if (!str2) + return false; + argv[i].setString(str2); + + str = js_ConcatStrings(cx, str, str2); + if (!str) + return false; + vp->setString(str); + } + + return true; +} + +static JSBool +str_slice(JSContext *cx, uintN argc, Value *vp) +{ + if (argc == 1 && vp[1].isString() && vp[2].isInt32()) { + size_t begin, end, length; + + JSString *str = vp[1].toString(); + begin = vp[2].toInt32(); + end = str->length(); + if (begin <= end) { + length = end - begin; + if (length == 0) { + str = cx->runtime->emptyString; + } else { + str = (length == 1) + ? JSString::getUnitString(cx, str, begin) + : js_NewDependentString(cx, str, begin, length); + if (!str) + return JS_FALSE; + } + vp->setString(str); + return JS_TRUE; + } + } + + JSString *str = ThisToStringForStringProto(cx, vp); + if (!str) + return false; + + if (argc != 0) { + double begin, end, length; + + if (!ValueToNumber(cx, vp[2], &begin)) + return JS_FALSE; + begin = js_DoubleToInteger(begin); + length = str->length(); + if (begin < 0) { + begin += length; + if (begin < 0) + begin = 0; + } else if (begin > length) { + begin = length; + } + + if (argc == 1 || vp[3].isUndefined()) { + end = length; + } else { + if (!ValueToNumber(cx, vp[3], &end)) + return JS_FALSE; + end = js_DoubleToInteger(end); + if (end < 0) { + end += length; + if (end < 0) + end = 0; + } else if (end > length) { + end = length; + } + if (end < begin) + end = begin; + } + + str = js_NewDependentString(cx, str, + (size_t)begin, + (size_t)(end - begin)); + if (!str) + return JS_FALSE; + } + vp->setString(str); + return JS_TRUE; +} + +#if JS_HAS_STR_HTML_HELPERS +/* + * HTML composition aids. + */ +static bool +tagify(JSContext *cx, const char *begin, JSLinearString *param, const char *end, + Value *vp) +{ + JSString *thisstr = ThisToStringForStringProto(cx, vp); + if (!thisstr) + return false; + JSLinearString *str = thisstr->ensureLinear(cx); + if (!str) + return false; + + if (!end) + end = begin; + + size_t beglen = strlen(begin); + size_t taglen = 1 + beglen + 1; /* '' */ + size_t parlen = 0; /* Avoid warning. */ + if (param) { + parlen = param->length(); + taglen += 2 + parlen + 1; /* '="param"' */ + } + size_t endlen = strlen(end); + taglen += str->length() + 2 + endlen + 1; /* 'str' */ + + if (taglen >= ~(size_t)0 / sizeof(jschar)) { + js_ReportAllocationOverflow(cx); + return false; + } + + jschar *tagbuf = (jschar *) cx->malloc((taglen + 1) * sizeof(jschar)); + if (!tagbuf) + return false; + + size_t j = 0; + tagbuf[j++] = '<'; + for (size_t i = 0; i < beglen; i++) + tagbuf[j++] = (jschar)begin[i]; + if (param) { + tagbuf[j++] = '='; + tagbuf[j++] = '"'; + js_strncpy(&tagbuf[j], param->chars(), parlen); + j += parlen; + tagbuf[j++] = '"'; + } + tagbuf[j++] = '>'; + + js_strncpy(&tagbuf[j], str->chars(), str->length()); + j += str->length(); + tagbuf[j++] = '<'; + tagbuf[j++] = '/'; + for (size_t i = 0; i < endlen; i++) + tagbuf[j++] = (jschar)end[i]; + tagbuf[j++] = '>'; + JS_ASSERT(j == taglen); + tagbuf[j] = 0; + + JSString *retstr = js_NewString(cx, tagbuf, taglen); + if (!retstr) { + js_free((char *)tagbuf); + return false; + } + vp->setString(retstr); + return true; +} + +static JSBool +tagify_value(JSContext *cx, uintN argc, Value *vp, + const char *begin, const char *end) +{ + JSLinearString *param = ArgToRootedString(cx, argc, vp, 0); + if (!param) + return JS_FALSE; + return tagify(cx, begin, param, end, vp); +} + +static JSBool +str_bold(JSContext *cx, uintN argc, Value *vp) +{ + return tagify(cx, "b", NULL, NULL, vp); +} + +static JSBool +str_italics(JSContext *cx, uintN argc, Value *vp) +{ + return tagify(cx, "i", NULL, NULL, vp); +} + +static JSBool +str_fixed(JSContext *cx, uintN argc, Value *vp) +{ + return tagify(cx, "tt", NULL, NULL, vp); +} + +static JSBool +str_fontsize(JSContext *cx, uintN argc, Value *vp) +{ + return tagify_value(cx, argc, vp, "font size", "font"); +} + +static JSBool +str_fontcolor(JSContext *cx, uintN argc, Value *vp) +{ + return tagify_value(cx, argc, vp, "font color", "font"); +} + +static JSBool +str_link(JSContext *cx, uintN argc, Value *vp) +{ + return tagify_value(cx, argc, vp, "a href", "a"); +} + +static JSBool +str_anchor(JSContext *cx, uintN argc, Value *vp) +{ + return tagify_value(cx, argc, vp, "a name", "a"); +} + +static JSBool +str_strike(JSContext *cx, uintN argc, Value *vp) +{ + return tagify(cx, "strike", NULL, NULL, vp); +} + +static JSBool +str_small(JSContext *cx, uintN argc, Value *vp) +{ + return tagify(cx, "small", NULL, NULL, vp); +} + +static JSBool +str_big(JSContext *cx, uintN argc, Value *vp) +{ + return tagify(cx, "big", NULL, NULL, vp); +} + +static JSBool +str_blink(JSContext *cx, uintN argc, Value *vp) +{ + return tagify(cx, "blink", NULL, NULL, vp); +} + +static JSBool +str_sup(JSContext *cx, uintN argc, Value *vp) +{ + return tagify(cx, "sup", NULL, NULL, vp); +} + +static JSBool +str_sub(JSContext *cx, uintN argc, Value *vp) +{ + return tagify(cx, "sub", NULL, NULL, vp); +} +#endif /* JS_HAS_STR_HTML_HELPERS */ + +#ifdef JS_TRACER +JSString* FASTCALL +js_String_getelem(JSContext* cx, JSString* str, int32 i) +{ + if ((size_t)i >= str->length()) + return NULL; + return JSString::getUnitString(cx, str, size_t(i)); +} +#endif + +JS_DEFINE_TRCINFO_1(str_concat, + (3, (extern, STRING_RETRY, js_ConcatStrings, CONTEXT, THIS_STRING, STRING, + 1, nanojit::ACCSET_NONE))) + +static JSFunctionSpec string_methods[] = { +#if JS_HAS_TOSOURCE + JS_FN("quote", str_quote, 0,JSFUN_GENERIC_NATIVE), + JS_FN(js_toSource_str, str_toSource, 0,0), +#endif + + /* Java-like methods. */ + JS_FN(js_toString_str, js_str_toString, 0,0), + JS_FN(js_valueOf_str, js_str_toString, 0,0), + JS_FN(js_toJSON_str, js_str_toString, 0,0), + JS_FN("substring", str_substring, 2,JSFUN_GENERIC_NATIVE), + JS_FN("toLowerCase", str_toLowerCase, 0,JSFUN_GENERIC_NATIVE), + JS_FN("toUpperCase", str_toUpperCase, 0,JSFUN_GENERIC_NATIVE), + JS_FN("charAt", js_str_charAt, 1,JSFUN_GENERIC_NATIVE), + JS_FN("charCodeAt", js_str_charCodeAt, 1,JSFUN_GENERIC_NATIVE), + JS_FN("indexOf", str_indexOf, 1,JSFUN_GENERIC_NATIVE), + JS_FN("lastIndexOf", str_lastIndexOf, 1,JSFUN_GENERIC_NATIVE), + JS_FN("trim", str_trim, 0,JSFUN_GENERIC_NATIVE), + JS_FN("trimLeft", str_trimLeft, 0,JSFUN_GENERIC_NATIVE), + JS_FN("trimRight", str_trimRight, 0,JSFUN_GENERIC_NATIVE), + JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,JSFUN_GENERIC_NATIVE), + JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,JSFUN_GENERIC_NATIVE), + JS_FN("localeCompare", str_localeCompare, 1,JSFUN_GENERIC_NATIVE), + + /* Perl-ish methods (search is actually Python-esque). */ + JS_FN("match", str_match, 1,JSFUN_GENERIC_NATIVE), + JS_FN("search", str_search, 1,JSFUN_GENERIC_NATIVE), + JS_FN("replace", str_replace, 2,JSFUN_GENERIC_NATIVE), + JS_FN("split", str_split, 2,JSFUN_GENERIC_NATIVE), +#if JS_HAS_PERL_SUBSTR + JS_FN("substr", str_substr, 2,JSFUN_GENERIC_NATIVE), +#endif + + /* Python-esque sequence methods. */ + JS_TN("concat", str_concat, 1,JSFUN_GENERIC_NATIVE, &str_concat_trcinfo), + JS_FN("slice", str_slice, 2,JSFUN_GENERIC_NATIVE), + + /* HTML string methods. */ +#if JS_HAS_STR_HTML_HELPERS + JS_FN("bold", str_bold, 0,0), + JS_FN("italics", str_italics, 0,0), + JS_FN("fixed", str_fixed, 0,0), + JS_FN("fontsize", str_fontsize, 1,0), + JS_FN("fontcolor", str_fontcolor, 1,0), + JS_FN("link", str_link, 1,0), + JS_FN("anchor", str_anchor, 1,0), + JS_FN("strike", str_strike, 0,0), + JS_FN("small", str_small, 0,0), + JS_FN("big", str_big, 0,0), + JS_FN("blink", str_blink, 0,0), + JS_FN("sup", str_sup, 0,0), + JS_FN("sub", str_sub, 0,0), +#endif + + JS_FS_END +}; + +/* + * Set up some tools to make it easier to generate large tables. After constant + * folding, for each n, Rn(0) is the comma-separated list R(0), R(1), ..., R(2^n-1). + * Similary, Rn(k) (for any k and n) generates the list R(k), R(k+1), ..., R(k+2^n-1). + * To use this, define R appropriately, then use Rn(0) (for some value of n), then + * undefine R. + */ +#define R2(n) R(n), R((n) + (1 << 0)), R((n) + (2 << 0)), R((n) + (3 << 0)) +#define R4(n) R2(n), R2((n) + (1 << 2)), R2((n) + (2 << 2)), R2((n) + (3 << 2)) +#define R6(n) R4(n), R4((n) + (1 << 4)), R4((n) + (2 << 4)), R4((n) + (3 << 4)) +#define R8(n) R6(n), R6((n) + (1 << 6)), R6((n) + (2 << 6)), R6((n) + (3 << 6)) +#define R10(n) R8(n), R8((n) + (1 << 8)), R8((n) + (2 << 8)), R8((n) + (3 << 8)) +#define R12(n) R10(n), R10((n) + (1 << 10)), R10((n) + (2 << 10)), R10((n) + (3 << 10)) + +#define R3(n) R2(n), R2((n) + (1 << 2)) +#define R7(n) R6(n), R6((n) + (1 << 6)) + +#define BUILD_LENGTH_AND_FLAGS(length, flags) \ + (((length) << JSString::LENGTH_SHIFT) | (flags)) + +/* + * Declare unit strings. Pack the string data itself into the mInlineChars + * place in the header. + */ +#define R(c) { \ + BUILD_LENGTH_AND_FLAGS(1, JSString::FLAT | JSString::ATOMIZED), \ + { (jschar *)(((char *)(unitStringTable + (c))) + \ + offsetof(JSString, inlineStorage)) }, \ + { {(c), 0x00} } } + +#ifdef __SUNPRO_CC +#pragma pack(8) +#else +#pragma pack(push, 8) +#endif + +const JSString JSString::unitStringTable[] +#ifdef __GNUC__ +__attribute__ ((aligned (8))) +#endif += { R8(0) }; + +#ifdef __SUNPRO_CC +#pragma pack(0) +#else +#pragma pack(pop) +#endif + +#undef R + +/* + * Declare length-2 strings. We only store strings where both characters are + * alphanumeric. The lower 10 short chars are the numerals, the next 26 are + * the lowercase letters, and the next 26 are the uppercase letters. + */ +#define TO_SMALL_CHAR(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' : \ + (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 10 : \ + (c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 36 : \ + JSString::INVALID_SMALL_CHAR) + +#define R TO_SMALL_CHAR + +const JSString::SmallChar JSString::toSmallChar[] = { R7(0) }; + +#undef R + +/* + * This is used when we generate our table of short strings, so the compiler is + * happier if we use |c| as few times as possible. + */ +#define FROM_SMALL_CHAR(c) ((c) + ((c) < 10 ? '0' : \ + (c) < 36 ? 'a' - 10 : \ + 'A' - 36)) +#define R FROM_SMALL_CHAR + +const jschar JSString::fromSmallChar[] = { R6(0) }; + +#undef R + +/* + * For code-generation ease, length-2 strings are encoded as 12-bit int values, + * where the upper 6 bits is the first character and the lower 6 bits is the + * second character. + */ +#define R(c) { \ + BUILD_LENGTH_AND_FLAGS(2, JSString::FLAT | JSString::ATOMIZED), \ + { (jschar *)(((char *)(length2StringTable + (c))) + \ + offsetof(JSString, inlineStorage)) }, \ + { {FROM_SMALL_CHAR((c) >> 6), FROM_SMALL_CHAR((c) & 0x3F), 0x00} } } + +#ifdef __SUNPRO_CC +#pragma pack(8) +#else +#pragma pack(push, 8) +#endif + +const JSString JSString::length2StringTable[] +#ifdef __GNUC__ +__attribute__ ((aligned (8))) +#endif += { R12(0) }; + +#ifdef __SUNPRO_CC +#pragma pack(0) +#else +#pragma pack(pop) +#endif + +#undef R + +/* + * Declare int strings. Only int strings from 100 to 255 actually have to be + * generated, since the rest are either unit strings or length-2 strings. To + * avoid the runtime cost of figuring out where to look for the string for a + * particular integer, we precompute a table of JSString*s which refer to the + * correct location of the int string. + */ +#define R(c) { \ + BUILD_LENGTH_AND_FLAGS(3, JSString::FLAT | JSString::ATOMIZED), \ + { (jschar *)(((char *)(hundredStringTable + ((c) - 100))) + \ + offsetof(JSString, inlineStorage)) }, \ + { {((c) / 100) + '0', ((c) / 10 % 10) + '0', ((c) % 10) + '0', 0x00} } } + + +JS_STATIC_ASSERT(100 + (1 << 7) + (1 << 4) + (1 << 3) + (1 << 2) == 256); + +#ifdef __SUNPRO_CC +#pragma pack(8) +#else +#pragma pack(push, 8) +#endif + +const JSString JSString::hundredStringTable[] +#ifdef __GNUC__ +__attribute__ ((aligned (8))) +#endif += { R7(100), /* 100 through 227 */ + R4(100 + (1 << 7)), /* 228 through 243 */ + R3(100 + (1 << 7) + (1 << 4)), /* 244 through 251 */ + R2(100 + (1 << 7) + (1 << 4) + (1 << 3)) /* 252 through 255 */ +}; + +#undef R + +#define R(c) ((c) < 10 ? JSString::unitStringTable + ((c) + '0') : \ + (c) < 100 ? JSString::length2StringTable + \ + ((size_t)TO_SMALL_CHAR(((c) / 10) + '0') << 6) + \ + TO_SMALL_CHAR(((c) % 10) + '0') : \ + JSString::hundredStringTable + ((c) - 100)) + +const JSString *const JSString::intStringTable[] = { R8(0) }; + +#undef R + +#ifdef __SUNPRO_CC +#pragma pack(0) +#else +#pragma pack(pop) +#endif + +#undef R2 +#undef R4 +#undef R6 +#undef R8 +#undef R10 +#undef R12 + +#undef R3 +#undef R7 + +JSBool +js_String(JSContext *cx, uintN argc, Value *vp) +{ + Value *argv = vp + 2; + + JSString *str; + if (argc > 0) { + str = js_ValueToString(cx, argv[0]); + if (!str) + return false; + } else { + str = cx->runtime->emptyString; + } + + if (IsConstructing(vp)) { + JSObject *obj = NewBuiltinClassInstance(cx, &js_StringClass); + if (!obj) + return false; + obj->setPrimitiveThis(StringValue(str)); + vp->setObject(*obj); + } else { + vp->setString(str); + } + return true; +} + +static JSBool +str_fromCharCode(JSContext *cx, uintN argc, Value *vp) +{ + Value *argv; + uintN i; + jschar *chars; + JSString *str; + + argv = vp + 2; + JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX); + if (argc == 1) { + uint16_t code; + if (!ValueToUint16(cx, argv[0], &code)) + return JS_FALSE; + if (code < UNIT_STRING_LIMIT) { + str = JSString::unitString(code); + if (!str) + return JS_FALSE; + vp->setString(str); + return JS_TRUE; + } + argv[0].setInt32(code); + } + chars = (jschar *) cx->malloc((argc + 1) * sizeof(jschar)); + if (!chars) + return JS_FALSE; + for (i = 0; i < argc; i++) { + uint16_t code; + if (!ValueToUint16(cx, argv[i], &code)) { + cx->free(chars); + return JS_FALSE; + } + chars[i] = (jschar)code; + } + chars[i] = 0; + str = js_NewString(cx, chars, argc); + if (!str) { + cx->free(chars); + return JS_FALSE; + } + vp->setString(str); + return JS_TRUE; +} + +#ifdef JS_TRACER +static JSString* FASTCALL +String_fromCharCode(JSContext* cx, int32 i) +{ + JS_ASSERT(JS_ON_TRACE(cx)); + jschar c = (jschar)i; + if (c < UNIT_STRING_LIMIT) + return JSString::unitString(c); + return js_NewStringCopyN(cx, &c, 1); +} +#endif + +JS_DEFINE_TRCINFO_1(str_fromCharCode, + (2, (static, STRING_RETRY, String_fromCharCode, CONTEXT, INT32, 1, nanojit::ACCSET_NONE))) + +static JSFunctionSpec string_static_methods[] = { + JS_TN("fromCharCode", str_fromCharCode, 1, 0, &str_fromCharCode_trcinfo), + JS_FS_END +}; + +JSObject * +js_InitStringClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto; + + /* Define the escape, unescape functions in the global object. */ + if (!JS_DefineFunctions(cx, obj, string_functions)) + return NULL; + + proto = js_InitClass(cx, obj, NULL, &js_StringClass, js_String, 1, + NULL, string_methods, + NULL, string_static_methods); + if (!proto) + return NULL; + proto->setPrimitiveThis(StringValue(cx->runtime->emptyString)); + if (!js_DefineNativeProperty(cx, proto, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), + UndefinedValue(), NULL, NULL, + JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0, + NULL)) { + return JS_FALSE; + } + + return proto; +} + +JSFlatString * +js_NewString(JSContext *cx, jschar *chars, size_t length) +{ + JSString *str; + + if (length > JSString::MAX_LENGTH) { + if (JS_ON_TRACE(cx)) { + /* + * If we can't leave the trace, signal OOM condition, otherwise + * exit from trace before throwing. + */ + if (!CanLeaveTrace(cx)) + return NULL; + + LeaveTrace(cx); + } + js_ReportAllocationOverflow(cx); + return NULL; + } + + str = js_NewGCString(cx); + if (!str) + return NULL; + str->initFlat(chars, length); + cx->runtime->stringMemoryUsed += length * 2; +#ifdef DEBUG + { + JSRuntime *rt = cx->runtime; + JS_RUNTIME_METER(rt, liveStrings); + JS_RUNTIME_METER(rt, totalStrings); + JS_LOCK_RUNTIME_VOID(rt, + (rt->lengthSum += (double)length, + rt->lengthSquaredSum += (double)length * (double)length)); + } +#endif + return str->assertIsFlat(); +} + +static JS_ALWAYS_INLINE JSFlatString * +NewShortString(JSContext *cx, const jschar *chars, size_t length) +{ + JS_ASSERT(JSShortString::fitsIntoShortString(length)); + JSShortString *str = js_NewGCShortString(cx); + if (!str) + return NULL; + jschar *storage = str->init(length); + js_short_strncpy(storage, chars, length); + storage[length] = 0; + return str->header()->assertIsFlat(); +} + +static JSFlatString * +NewShortString(JSContext *cx, const char *chars, size_t length) +{ + JS_ASSERT(JSShortString::fitsIntoShortString(length)); + JSShortString *str = js_NewGCShortString(cx); + if (!str) + return NULL; + jschar *storage = str->init(length); + + if (js_CStringsAreUTF8) { +#ifdef DEBUG + size_t oldLength = length; +#endif + if (!js_InflateStringToBuffer(cx, chars, length, storage, &length)) + return NULL; + JS_ASSERT(length <= oldLength); + storage[length] = 0; + str->resetLength(length); + } else { + size_t n = length; + jschar *p = storage; + while (n--) + *p++ = (unsigned char)*chars++; + *p = 0; + } + return str->header()->assertIsFlat(); +} + +static const size_t sMinWasteSize = 16; + +JSFlatString * +StringBuffer::finishString() +{ + JSContext *cx = context(); + if (cb.empty()) + return ATOM_TO_STRING(cx->runtime->atomState.emptyAtom); + + size_t length = cb.length(); + if (!checkLength(length)) + return NULL; + + JS_STATIC_ASSERT(JSShortString::MAX_SHORT_STRING_LENGTH < CharBuffer::InlineLength); + if (JSShortString::fitsIntoShortString(length)) + return NewShortString(cx, cb.begin(), length); + + if (!cb.append('\0')) + return NULL; + + size_t capacity = cb.capacity(); + + jschar *buf = cb.extractRawBuffer(); + if (!buf) + return NULL; + + /* For medium/big buffers, avoid wasting more than 1/4 of the memory. */ + JS_ASSERT(capacity >= length); + if (capacity > sMinWasteSize && capacity - length > (length >> 2)) { + size_t bytes = sizeof(jschar) * (length + 1); + jschar *tmp = (jschar *)cx->realloc(buf, bytes); + if (!tmp) { + cx->free(buf); + return NULL; + } + buf = tmp; + } + + JSFlatString *str = js_NewString(cx, buf, length); + if (!str) + cx->free(buf); + return str; +} + +JSLinearString * +js_NewDependentString(JSContext *cx, JSString *baseArg, size_t start, + size_t length) +{ + JSString *ds; + + if (length == 0) + return cx->runtime->emptyString; + + JSLinearString *base = baseArg->ensureLinear(cx); + if (!base) + return NULL; + + if (start == 0 && length == base->length()) + return base; + + const jschar *chars = base->chars() + start; + + JSLinearString *staticStr = JSString::lookupStaticString(chars, length); + if (staticStr) + return staticStr; + + /* Try to avoid long chains of dependent strings. */ + while (base->isDependent()) + base = base->dependentBase(); + + JS_ASSERT(base->isFlat()); + + ds = js_NewGCString(cx); + if (!ds) + return NULL; + ds->initDependent(base, chars, length); +#ifdef DEBUG + { + JSRuntime *rt = cx->runtime; + JS_RUNTIME_METER(rt, liveDependentStrings); + JS_RUNTIME_METER(rt, totalDependentStrings); + JS_RUNTIME_METER(rt, liveStrings); + JS_RUNTIME_METER(rt, totalStrings); + JS_LOCK_RUNTIME_VOID(rt, + (rt->strdepLengthSum += (double)length, + rt->strdepLengthSquaredSum += (double)length * (double)length)); + JS_LOCK_RUNTIME_VOID(rt, + (rt->lengthSum += (double)length, + rt->lengthSquaredSum += (double)length * (double)length)); + } +#endif + return ds->assertIsLinear(); +} + +#ifdef DEBUG +#include + +void printJSStringStats(JSRuntime *rt) +{ + double mean, sigma; + + mean = JS_MeanAndStdDev(rt->totalStrings, rt->lengthSum, + rt->lengthSquaredSum, &sigma); + + fprintf(stderr, "%lu total strings, mean length %g (sigma %g)\n", + (unsigned long)rt->totalStrings, mean, sigma); + + mean = JS_MeanAndStdDev(rt->totalDependentStrings, rt->strdepLengthSum, + rt->strdepLengthSquaredSum, &sigma); + + fprintf(stderr, "%lu total dependent strings, mean length %g (sigma %g)\n", + (unsigned long)rt->totalDependentStrings, mean, sigma); +} +#endif + +JSFlatString * +js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n) +{ + if (JSShortString::fitsIntoShortString(n)) + return NewShortString(cx, s, n); + + jschar *news = (jschar *) cx->malloc((n + 1) * sizeof(jschar)); + if (!news) + return NULL; + js_strncpy(news, s, n); + news[n] = 0; + JSFlatString *str = js_NewString(cx, news, n); + if (!str) + cx->free(news); + return str; +} + +JSFlatString * +js_NewStringCopyN(JSContext *cx, const char *s, size_t n) +{ + if (JSShortString::fitsIntoShortString(n)) + return NewShortString(cx, s, n); + + jschar *chars = js_InflateString(cx, s, &n); + if (!chars) + return NULL; + JSFlatString *str = js_NewString(cx, chars, n); + if (!str) + cx->free(chars); + return str; +} + +JSFlatString * +js_NewStringCopyZ(JSContext *cx, const jschar *s) +{ + size_t n = js_strlen(s); + if (JSShortString::fitsIntoShortString(n)) + return NewShortString(cx, s, n); + + size_t m = (n + 1) * sizeof(jschar); + jschar *news = (jschar *) cx->malloc(m); + if (!news) + return NULL; + memcpy(news, s, m); + JSFlatString *str = js_NewString(cx, news, n); + if (!str) + cx->free(news); + return str; +} + +JSFlatString * +js_NewStringCopyZ(JSContext *cx, const char *s) +{ + return js_NewStringCopyN(cx, s, strlen(s)); +} + +const char * +js_ValueToPrintable(JSContext *cx, const Value &v, JSAutoByteString *bytes, bool asSource) +{ + JSString *str; + + str = (asSource ? js_ValueToSource : js_ValueToString)(cx, v); + if (!str) + return NULL; + str = js_QuoteString(cx, str, 0); + if (!str) + return NULL; + return bytes->encode(cx, str); +} + +JSString * +js_ValueToString(JSContext *cx, const Value &arg) +{ + Value v = arg; + if (v.isObject() && !DefaultValue(cx, &v.toObject(), JSTYPE_STRING, &v)) + return NULL; + + JSString *str; + if (v.isString()) { + str = v.toString(); + } else if (v.isInt32()) { + str = js_IntToString(cx, v.toInt32()); + } else if (v.isDouble()) { + str = js_NumberToString(cx, v.toDouble()); + } else if (v.isBoolean()) { + str = js_BooleanToString(cx, v.toBoolean()); + } else if (v.isNull()) { + str = ATOM_TO_STRING(cx->runtime->atomState.nullAtom); + } else { + str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + } + return str; +} + +/* This function implements E-262-3 section 9.8, toString. */ +bool +js::ValueToStringBuffer(JSContext *cx, const Value &arg, StringBuffer &sb) +{ + Value v = arg; + if (v.isObject() && !DefaultValue(cx, &v.toObject(), JSTYPE_STRING, &v)) + return false; + + if (v.isString()) { + JSString *str = v.toString(); + size_t length = str->length(); + const jschar *chars = str->getChars(cx); + if (!chars) + return false; + return sb.append(chars, length); + } + if (v.isNumber()) + return NumberValueToStringBuffer(cx, v, sb); + if (v.isBoolean()) + return BooleanToStringBuffer(cx, v.toBoolean(), sb); + if (v.isNull()) + return sb.append(cx->runtime->atomState.nullAtom); + JS_ASSERT(v.isUndefined()); + return sb.append(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); +} + +JS_FRIEND_API(JSString *) +js_ValueToSource(JSContext *cx, const Value &v) +{ + if (v.isUndefined()) + return ATOM_TO_STRING(cx->runtime->atomState.void0Atom); + if (v.isString()) + return js_QuoteString(cx, v.toString(), '"'); + if (v.isPrimitive()) { + /* Special case to preserve negative zero, _contra_ toString. */ + if (v.isDouble() && JSDOUBLE_IS_NEGZERO(v.toDouble())) { + /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */ + static const jschar js_negzero_ucNstr[] = {'-', '0'}; + + return js_NewStringCopyN(cx, js_negzero_ucNstr, 2); + } + return js_ValueToString(cx, v); + } + + JSAtom *atom = cx->runtime->atomState.toSourceAtom; + AutoValueRooter tvr(cx); + if (!js_TryMethod(cx, &v.toObject(), atom, 0, NULL, tvr.addr())) + return NULL; + return js_ValueToString(cx, tvr.value()); +} + +namespace js { + +/* + * str is not necessarily a GC thing here. + */ +static JS_ALWAYS_INLINE bool +EqualStringsTail(JSLinearString *str1, size_t length1, JSLinearString *str2) +{ + const jschar *s1 = str1->chars(); + const jschar *s1end = s1 + length1; + const jschar *s2 = str2->chars(); + do { + if (*s1 != *s2) { + return false; + } + ++s1, ++s2; + } while (s1 != s1end); + + return true; +} + +bool +EqualStrings(JSContext *cx, JSString *str1, JSString *str2, JSBool *result) +{ + if (str1 == str2) { + *result = true; + return true; + } + + size_t length1 = str1->length(); + if (length1 != str2->length()) { + *result = false; + return true; + } + + if (length1 == 0) { + *result = true; + return true; + } + + JSLinearString *linear1 = str1->ensureLinear(cx); + if (!linear1) + return false; + JSLinearString *linear2 = str2->ensureLinear(cx); + if (!linear2) + return false; + + *result = EqualStringsTail(linear1, length1, linear2); + return true; +} + +bool +EqualStrings(JSLinearString *str1, JSLinearString *str2) +{ + if (str1 == str2) + return true; + + size_t length1 = str1->length(); + if (length1 != str2->length()) + return false; + + if (length1 == 0) + return true; + + return EqualStringsTail(str1, length1, str2); +} + +} /* namespace js */ + +JSBool JS_FASTCALL +js_EqualStringsOnTrace(JSContext *cx, JSString *str1, JSString *str2) +{ + JSBool result; + return EqualStrings(cx, str1, str2, &result) ? result : JS_NEITHER; +} +JS_DEFINE_CALLINFO_3(extern, BOOL, js_EqualStringsOnTrace, + CONTEXT, STRING, STRING, 1, nanojit::ACCSET_NONE) + +namespace js { + +static bool +CompareStringsImpl(JSContext *cx, JSString *str1, JSString *str2, int32 *result) +{ + JS_ASSERT(str1); + JS_ASSERT(str2); + + if (str1 == str2) { + *result = 0; + return true; + } + + size_t l1 = str1->length(); + const jschar *s1 = str1->getChars(cx); + if (!s1) + return false; + + size_t l2 = str2->length(); + const jschar *s2 = str2->getChars(cx); + if (!s2) + return false; + + size_t n = JS_MIN(l1, l2); + for (size_t i = 0; i < n; i++) { + if (int32 cmp = s1[i] - s2[i]) { + *result = cmp; + return true; + } + } + *result = (int32)(l1 - l2); + return true; +} + +bool +CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result) +{ + return CompareStringsImpl(cx, str1, str2, result); +} + +} /* namespace js */ + +int32 JS_FASTCALL +js_CompareStringsOnTrace(JSContext *cx, JSString *str1, JSString *str2) +{ + int32 result; + if (!CompareStringsImpl(cx, str1, str2, &result)) + return INT32_MIN; + JS_ASSERT(result != INT32_MIN); + return result; +} +JS_DEFINE_CALLINFO_3(extern, INT32, js_CompareStringsOnTrace, + CONTEXT, STRING, STRING, 1, nanojit::ACCSET_NONE) + +namespace js { + +bool +StringEqualsAscii(JSLinearString *str, const char *asciiBytes) +{ + size_t length = strlen(asciiBytes); +#ifdef DEBUG + for (size_t i = 0; i != length; ++i) + JS_ASSERT(unsigned(asciiBytes[i]) <= 127); +#endif + if (length != str->length()) + return false; + const jschar *chars = str->chars(); + for (size_t i = 0; i != length; ++i) { + if (unsigned(asciiBytes[i]) != unsigned(chars[i])) + return false; + } + return true; +} + +} /* namespacejs */ + +size_t +js_strlen(const jschar *s) +{ + const jschar *t; + + for (t = s; *t != 0; t++) + continue; + return (size_t)(t - s); +} + +jschar * +js_strchr(const jschar *s, jschar c) +{ + while (*s != 0) { + if (*s == c) + return (jschar *)s; + s++; + } + return NULL; +} + +jschar * +js_strchr_limit(const jschar *s, jschar c, const jschar *limit) +{ + while (s < limit) { + if (*s == c) + return (jschar *)s; + s++; + } + return NULL; +} + +jschar * +js_InflateString(JSContext *cx, const char *bytes, size_t *lengthp) +{ + size_t nbytes, nchars, i; + jschar *chars; +#ifdef DEBUG + JSBool ok; +#endif + + nbytes = *lengthp; + if (js_CStringsAreUTF8) { + if (!js_InflateStringToBuffer(cx, bytes, nbytes, NULL, &nchars)) + goto bad; + chars = (jschar *) cx->malloc((nchars + 1) * sizeof (jschar)); + if (!chars) + goto bad; +#ifdef DEBUG + ok = +#endif + js_InflateStringToBuffer(cx, bytes, nbytes, chars, &nchars); + JS_ASSERT(ok); + } else { + nchars = nbytes; + chars = (jschar *) cx->malloc((nchars + 1) * sizeof(jschar)); + if (!chars) + goto bad; + for (i = 0; i < nchars; i++) + chars[i] = (unsigned char) bytes[i]; + } + *lengthp = nchars; + chars[nchars] = 0; + return chars; + + bad: + /* + * For compatibility with callers of JS_DecodeBytes we must zero lengthp + * on errors. + */ + *lengthp = 0; + return NULL; +} + +/* + * May be called with null cx. + */ +char * +js_DeflateString(JSContext *cx, const jschar *chars, size_t nchars) +{ + size_t nbytes, i; + char *bytes; +#ifdef DEBUG + JSBool ok; +#endif + + if (js_CStringsAreUTF8) { + nbytes = js_GetDeflatedStringLength(cx, chars, nchars); + if (nbytes == (size_t) -1) + return NULL; + bytes = (char *) (cx ? cx->malloc(nbytes + 1) : js_malloc(nbytes + 1)); + if (!bytes) + return NULL; +#ifdef DEBUG + ok = +#endif + js_DeflateStringToBuffer(cx, chars, nchars, bytes, &nbytes); + JS_ASSERT(ok); + } else { + nbytes = nchars; + bytes = (char *) (cx ? cx->malloc(nbytes + 1) : js_malloc(nbytes + 1)); + if (!bytes) + return NULL; + for (i = 0; i < nbytes; i++) + bytes[i] = (char) chars[i]; + } + bytes[nbytes] = 0; + return bytes; +} + +size_t +js_GetDeflatedStringLength(JSContext *cx, const jschar *chars, size_t nchars) +{ + if (!js_CStringsAreUTF8) + return nchars; + + return js_GetDeflatedUTF8StringLength(cx, chars, nchars); +} + +/* + * May be called with null cx through public API, see below. + */ +size_t +js_GetDeflatedUTF8StringLength(JSContext *cx, const jschar *chars, size_t nchars) +{ + size_t nbytes; + const jschar *end; + uintN c, c2; + char buffer[10]; + + nbytes = nchars; + for (end = chars + nchars; chars != end; chars++) { + c = *chars; + if (c < 0x80) + continue; + if (0xD800 <= c && c <= 0xDFFF) { + /* Surrogate pair. */ + chars++; + + /* nbytes sets 1 length since this is surrogate pair. */ + nbytes--; + if (c >= 0xDC00 || chars == end) + goto bad_surrogate; + c2 = *chars; + if (c2 < 0xDC00 || c2 > 0xDFFF) + goto bad_surrogate; + c = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000; + } + c >>= 11; + nbytes++; + while (c) { + c >>= 5; + nbytes++; + } + } + return nbytes; + + bad_surrogate: + if (cx) { + JS_snprintf(buffer, 10, "0x%x", c); + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, + NULL, JSMSG_BAD_SURROGATE_CHAR, buffer); + } + return (size_t) -1; +} + +JSBool +js_DeflateStringToBuffer(JSContext *cx, const jschar *src, size_t srclen, + char *dst, size_t *dstlenp) +{ + size_t dstlen, i; + + dstlen = *dstlenp; + if (!js_CStringsAreUTF8) { + if (srclen > dstlen) { + for (i = 0; i < dstlen; i++) + dst[i] = (char) src[i]; + if (cx) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BUFFER_TOO_SMALL); + } + return JS_FALSE; + } + for (i = 0; i < srclen; i++) + dst[i] = (char) src[i]; + *dstlenp = srclen; + return JS_TRUE; + } + + return js_DeflateStringToUTF8Buffer(cx, src, srclen, dst, dstlenp); +} + +JSBool +js_DeflateStringToUTF8Buffer(JSContext *cx, const jschar *src, size_t srclen, + char *dst, size_t *dstlenp) +{ + size_t dstlen, i, origDstlen, utf8Len; + jschar c, c2; + uint32 v; + uint8 utf8buf[6]; + + dstlen = *dstlenp; + origDstlen = dstlen; + while (srclen) { + c = *src++; + srclen--; + if ((c >= 0xDC00) && (c <= 0xDFFF)) + goto badSurrogate; + if (c < 0xD800 || c > 0xDBFF) { + v = c; + } else { + if (srclen < 1) + goto badSurrogate; + c2 = *src; + if ((c2 < 0xDC00) || (c2 > 0xDFFF)) + goto badSurrogate; + src++; + srclen--; + v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000; + } + if (v < 0x0080) { + /* no encoding necessary - performance hack */ + if (dstlen == 0) + goto bufferTooSmall; + *dst++ = (char) v; + utf8Len = 1; + } else { + utf8Len = js_OneUcs4ToUtf8Char(utf8buf, v); + if (utf8Len > dstlen) + goto bufferTooSmall; + for (i = 0; i < utf8Len; i++) + *dst++ = (char) utf8buf[i]; + } + dstlen -= utf8Len; + } + *dstlenp = (origDstlen - dstlen); + return JS_TRUE; + +badSurrogate: + *dstlenp = (origDstlen - dstlen); + /* Delegate error reporting to the measurement function. */ + if (cx) + js_GetDeflatedStringLength(cx, src - 1, srclen + 1); + return JS_FALSE; + +bufferTooSmall: + *dstlenp = (origDstlen - dstlen); + if (cx) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BUFFER_TOO_SMALL); + } + return JS_FALSE; +} + +JSBool +js_InflateStringToBuffer(JSContext *cx, const char *src, size_t srclen, + jschar *dst, size_t *dstlenp) +{ + size_t dstlen, i; + + if (!js_CStringsAreUTF8) { + if (dst) { + dstlen = *dstlenp; + if (srclen > dstlen) { + for (i = 0; i < dstlen; i++) + dst[i] = (unsigned char) src[i]; + if (cx) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BUFFER_TOO_SMALL); + } + return JS_FALSE; + } + for (i = 0; i < srclen; i++) + dst[i] = (unsigned char) src[i]; + } + *dstlenp = srclen; + return JS_TRUE; + } + + return js_InflateUTF8StringToBuffer(cx, src, srclen, dst, dstlenp); +} + +JSBool +js_InflateUTF8StringToBuffer(JSContext *cx, const char *src, size_t srclen, + jschar *dst, size_t *dstlenp) +{ + size_t dstlen, origDstlen, offset, j, n; + uint32 v; + + dstlen = dst ? *dstlenp : (size_t) -1; + origDstlen = dstlen; + offset = 0; + + while (srclen) { + v = (uint8) *src; + n = 1; + if (v & 0x80) { + while (v & (0x80 >> n)) + n++; + if (n > srclen) + goto bufferTooSmall; + if (n == 1 || n > 4) + goto badCharacter; + for (j = 1; j < n; j++) { + if ((src[j] & 0xC0) != 0x80) + goto badCharacter; + } + v = Utf8ToOneUcs4Char((uint8 *)src, n); + if (v >= 0x10000) { + v -= 0x10000; + if (v > 0xFFFFF || dstlen < 2) { + *dstlenp = (origDstlen - dstlen); + if (cx) { + char buffer[10]; + JS_snprintf(buffer, 10, "0x%x", v + 0x10000); + JS_ReportErrorFlagsAndNumber(cx, + JSREPORT_ERROR, + js_GetErrorMessage, NULL, + JSMSG_UTF8_CHAR_TOO_LARGE, + buffer); + } + return JS_FALSE; + } + if (dst) { + *dst++ = (jschar)((v >> 10) + 0xD800); + v = (jschar)((v & 0x3FF) + 0xDC00); + } + dstlen--; + } + } + if (!dstlen) + goto bufferTooSmall; + if (dst) + *dst++ = (jschar) v; + dstlen--; + offset += n; + src += n; + srclen -= n; + } + *dstlenp = (origDstlen - dstlen); + return JS_TRUE; + +badCharacter: + *dstlenp = (origDstlen - dstlen); + if (cx) { + char buffer[10]; + JS_snprintf(buffer, 10, "%d", offset); + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, + js_GetErrorMessage, NULL, + JSMSG_MALFORMED_UTF8_CHAR, + buffer); + } + return JS_FALSE; + +bufferTooSmall: + *dstlenp = (origDstlen - dstlen); + if (cx) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BUFFER_TOO_SMALL); + } + return JS_FALSE; +} + +/* + * From java.lang.Character.java: + * + * The character properties are currently encoded into 32 bits in the + * following manner: + * + * 10 bits signed offset used for converting case + * 1 bit if 1, adding the signed offset converts the character to + * lowercase + * 1 bit if 1, subtracting the signed offset converts the character to + * uppercase + * 1 bit if 1, character has a titlecase equivalent (possibly itself) + * 3 bits 0 may not be part of an identifier + * 1 ignorable control; may continue a Unicode identifier or JS + * identifier + * 2 may continue a JS identifier but not a Unicode identifier + * (unused) + * 3 may continue a Unicode identifier or JS identifier + * 4 is a JS whitespace character + * 5 may start or continue a JS identifier; + * may continue but not start a Unicode identifier (_) + * 6 may start or continue a JS identifier but not a Unicode + * identifier ($) + * 7 may start or continue a Unicode identifier or JS identifier + * Thus: + * 5, 6, 7 may start a JS identifier + * 1, 2, 3, 5, 6, 7 may continue a JS identifier + * 7 may start a Unicode identifier + * 1, 3, 5, 7 may continue a Unicode identifier + * 1 is ignorable within an identifier + * 4 is JS whitespace + * 2 bits 0 this character has no numeric property + * 1 adding the digit offset to the character code and then + * masking with 0x1F will produce the desired numeric value + * 2 this character has a "strange" numeric value + * 3 a JS supradecimal digit: adding the digit offset to the + * character code, then masking with 0x1F, then adding 10 + * will produce the desired numeric value + * 5 bits digit offset + * 1 bit XML 1.0 name start character + * 1 bit XML 1.0 name character + * 2 bits reserved for future use + * 5 bits character type + */ + +/* The X table has 1024 entries for a total of 1024 bytes. */ + +const uint8 js_X[] = { + 0, 1, 2, 3, 4, 5, 6, 7, /* 0x0000 */ + 8, 9, 10, 11, 12, 13, 14, 15, /* 0x0200 */ + 16, 17, 18, 19, 20, 21, 22, 23, /* 0x0400 */ + 24, 25, 26, 27, 28, 28, 28, 28, /* 0x0600 */ + 28, 28, 28, 28, 29, 30, 31, 32, /* 0x0800 */ + 33, 34, 35, 36, 37, 38, 39, 40, /* 0x0A00 */ + 41, 42, 43, 44, 45, 46, 28, 28, /* 0x0C00 */ + 47, 48, 49, 50, 51, 52, 53, 28, /* 0x0E00 */ + 28, 28, 54, 55, 56, 57, 58, 59, /* 0x1000 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1200 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1400 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1600 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1800 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1A00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x1C00 */ + 60, 60, 61, 62, 63, 64, 65, 66, /* 0x1E00 */ + 67, 68, 69, 70, 71, 72, 73, 74, /* 0x2000 */ + 75, 75, 75, 76, 77, 78, 28, 28, /* 0x2200 */ + 79, 80, 81, 82, 83, 83, 84, 85, /* 0x2400 */ + 86, 85, 28, 28, 87, 88, 89, 28, /* 0x2600 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2800 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2A00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2C00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x2E00 */ + 90, 91, 92, 93, 94, 56, 95, 28, /* 0x3000 */ + 96, 97, 98, 99, 83, 100, 83, 101, /* 0x3200 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3400 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3600 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3800 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3A00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3C00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x3E00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4000 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4200 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4400 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4600 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4800 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4A00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0x4C00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x4E00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5400 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5600 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5800 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5A00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5C00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x5E00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6400 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6600 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6800 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6A00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6C00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x6E00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7400 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7600 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7800 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7A00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7C00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x7E00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8400 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8600 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8800 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8A00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8C00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x8E00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9400 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9600 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9800 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9A00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0x9C00 */ + 56, 56, 56, 56, 56, 56, 102, 28, /* 0x9E00 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA000 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA200 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA400 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA600 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0xA800 */ + 28, 28, 28, 28, 28, 28, 28, 28, /* 0xAA00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAC00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xAE00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB400 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB600 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xB800 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBA00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBC00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xBE00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC400 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC600 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xC800 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCA00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCC00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xCE00 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD000 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD200 */ + 56, 56, 56, 56, 56, 56, 56, 56, /* 0xD400 */ + 56, 56, 56, 56, 56, 56, 103, 28, /* 0xD600 */ +104, 104, 104, 104, 104, 104, 104, 104, /* 0xD800 */ +104, 104, 104, 104, 104, 104, 104, 104, /* 0xDA00 */ +104, 104, 104, 104, 104, 104, 104, 104, /* 0xDC00 */ +104, 104, 104, 104, 104, 104, 104, 104, /* 0xDE00 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xE000 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xE200 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xE400 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xE600 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xE800 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xEA00 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xEC00 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xEE00 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xF000 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xF200 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xF400 */ +105, 105, 105, 105, 105, 105, 105, 105, /* 0xF600 */ +105, 105, 105, 105, 56, 56, 56, 56, /* 0xF800 */ +106, 28, 28, 28, 107, 108, 109, 110, /* 0xFA00 */ + 56, 56, 56, 56, 111, 112, 113, 114, /* 0xFC00 */ +115, 116, 56, 117, 118, 119, 120, 121 /* 0xFE00 */ +}; + +/* The Y table has 7808 entries for a total of 7808 bytes. */ + +const uint8 js_Y[] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ + 0, 1, 1, 1, 1, 1, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ + 2, 3, 3, 3, 4, 3, 3, 3, /* 0 */ + 5, 6, 3, 7, 3, 8, 3, 3, /* 0 */ + 9, 9, 9, 9, 9, 9, 9, 9, /* 0 */ + 9, 9, 3, 3, 7, 7, 7, 3, /* 0 */ + 3, 10, 10, 10, 10, 10, 10, 10, /* 1 */ + 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */ + 10, 10, 10, 10, 10, 10, 10, 10, /* 1 */ + 10, 10, 10, 5, 3, 6, 11, 12, /* 1 */ + 11, 13, 13, 13, 13, 13, 13, 13, /* 1 */ + 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */ + 13, 13, 13, 13, 13, 13, 13, 13, /* 1 */ + 13, 13, 13, 5, 7, 6, 7, 0, /* 1 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 2, 3, 4, 4, 4, 4, 15, 15, /* 2 */ + 11, 15, 16, 5, 7, 8, 15, 11, /* 2 */ + 15, 7, 17, 17, 11, 16, 15, 3, /* 2 */ + 11, 18, 16, 6, 19, 19, 19, 3, /* 2 */ + 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */ + 20, 20, 20, 20, 20, 20, 20, 20, /* 3 */ + 20, 20, 20, 20, 20, 20, 20, 7, /* 3 */ + 20, 20, 20, 20, 20, 20, 20, 16, /* 3 */ + 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */ + 21, 21, 21, 21, 21, 21, 21, 21, /* 3 */ + 21, 21, 21, 21, 21, 21, 21, 7, /* 3 */ + 21, 21, 21, 21, 21, 21, 21, 22, /* 3 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 4 */ + 25, 26, 23, 24, 23, 24, 23, 24, /* 4 */ + 16, 23, 24, 23, 24, 23, 24, 23, /* 4 */ + 24, 23, 24, 23, 24, 23, 24, 23, /* 5 */ + 24, 16, 23, 24, 23, 24, 23, 24, /* 5 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 5 */ + 27, 23, 24, 23, 24, 23, 24, 28, /* 5 */ + 16, 29, 23, 24, 23, 24, 30, 23, /* 6 */ + 24, 31, 31, 23, 24, 16, 32, 32, /* 6 */ + 33, 23, 24, 31, 34, 16, 35, 36, /* 6 */ + 23, 24, 16, 16, 35, 37, 16, 38, /* 6 */ + 23, 24, 23, 24, 23, 24, 38, 23, /* 6 */ + 24, 39, 40, 16, 23, 24, 39, 23, /* 6 */ + 24, 41, 41, 23, 24, 23, 24, 42, /* 6 */ + 23, 24, 16, 40, 23, 24, 40, 40, /* 6 */ + 40, 40, 40, 40, 43, 44, 45, 43, /* 7 */ + 44, 45, 43, 44, 45, 23, 24, 23, /* 7 */ + 24, 23, 24, 23, 24, 23, 24, 23, /* 7 */ + 24, 23, 24, 23, 24, 16, 23, 24, /* 7 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 7 */ + 16, 43, 44, 45, 23, 24, 46, 46, /* 7 */ + 46, 46, 23, 24, 23, 24, 23, 24, /* 7 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 8 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 8 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 9 */ + 16, 16, 16, 47, 48, 16, 49, 49, /* 9 */ + 50, 50, 16, 51, 16, 16, 16, 16, /* 9 */ + 49, 16, 16, 52, 16, 16, 16, 16, /* 9 */ + 53, 54, 16, 16, 16, 16, 16, 54, /* 9 */ + 16, 16, 55, 16, 16, 16, 16, 16, /* 9 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 9 */ + 16, 16, 16, 56, 16, 16, 16, 16, /* 10 */ + 56, 16, 57, 57, 16, 16, 16, 16, /* 10 */ + 16, 16, 58, 16, 16, 16, 16, 16, /* 10 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 10 */ + 16, 46, 46, 46, 46, 46, 46, 46, /* 10 */ + 59, 59, 59, 59, 59, 59, 59, 59, /* 10 */ + 59, 11, 11, 59, 59, 59, 59, 59, /* 10 */ + 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */ + 11, 11, 11, 11, 11, 11, 11, 11, /* 11 */ + 59, 59, 11, 11, 11, 11, 11, 11, /* 11 */ + 11, 11, 11, 11, 11, 11, 11, 46, /* 11 */ + 59, 59, 59, 59, 59, 11, 11, 11, /* 11 */ + 11, 11, 46, 46, 46, 46, 46, 46, /* 11 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 11 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 12 */ + 60, 60, 60, 60, 60, 60, 46, 46, /* 13 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */ + 60, 60, 46, 46, 46, 46, 46, 46, /* 13 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 13 */ + 46, 46, 46, 46, 3, 3, 46, 46, /* 13 */ + 46, 46, 59, 46, 46, 46, 3, 46, /* 13 */ + 46, 46, 46, 46, 11, 11, 61, 3, /* 14 */ + 62, 62, 62, 46, 63, 46, 64, 64, /* 14 */ + 16, 20, 20, 20, 20, 20, 20, 20, /* 14 */ + 20, 20, 20, 20, 20, 20, 20, 20, /* 14 */ + 20, 20, 46, 20, 20, 20, 20, 20, /* 14 */ + 20, 20, 20, 20, 65, 66, 66, 66, /* 14 */ + 16, 21, 21, 21, 21, 21, 21, 21, /* 14 */ + 21, 21, 21, 21, 21, 21, 21, 21, /* 14 */ + 21, 21, 16, 21, 21, 21, 21, 21, /* 15 */ + 21, 21, 21, 21, 67, 68, 68, 46, /* 15 */ + 69, 70, 38, 38, 38, 71, 72, 46, /* 15 */ + 46, 46, 38, 46, 38, 46, 38, 46, /* 15 */ + 38, 46, 23, 24, 23, 24, 23, 24, /* 15 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 15 */ + 73, 74, 16, 40, 46, 46, 46, 46, /* 15 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 15 */ + 46, 75, 75, 75, 75, 75, 75, 75, /* 16 */ + 75, 75, 75, 75, 75, 46, 75, 75, /* 16 */ + 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */ + 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */ + 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */ + 20, 20, 20, 20, 20, 20, 20, 20, /* 16 */ + 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */ + 21, 21, 21, 21, 21, 21, 21, 21, /* 16 */ + 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */ + 21, 21, 21, 21, 21, 21, 21, 21, /* 17 */ + 46, 74, 74, 74, 74, 74, 74, 74, /* 17 */ + 74, 74, 74, 74, 74, 46, 74, 74, /* 17 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 17 */ + 23, 24, 15, 60, 60, 60, 60, 46, /* 18 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 18 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 18 */ + 40, 23, 24, 23, 24, 46, 46, 23, /* 19 */ + 24, 46, 46, 23, 24, 46, 46, 46, /* 19 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 19 */ + 23, 24, 23, 24, 46, 46, 23, 24, /* 19 */ + 23, 24, 23, 24, 23, 24, 46, 46, /* 19 */ + 23, 24, 46, 46, 46, 46, 46, 46, /* 19 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 20 */ + 46, 76, 76, 76, 76, 76, 76, 76, /* 20 */ + 76, 76, 76, 76, 76, 76, 76, 76, /* 20 */ + 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */ + 76, 76, 76, 76, 76, 76, 76, 76, /* 21 */ + 76, 76, 76, 76, 76, 76, 76, 46, /* 21 */ + 46, 59, 3, 3, 3, 3, 3, 3, /* 21 */ + 46, 77, 77, 77, 77, 77, 77, 77, /* 21 */ + 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */ + 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */ + 77, 77, 77, 77, 77, 77, 77, 77, /* 21 */ + 77, 77, 77, 77, 77, 77, 77, 16, /* 22 */ + 46, 3, 46, 46, 46, 46, 46, 46, /* 22 */ + 46, 60, 60, 60, 60, 60, 60, 60, /* 22 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */ + 60, 60, 46, 60, 60, 60, 60, 60, /* 22 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 22 */ + 60, 60, 46, 60, 60, 60, 3, 60, /* 22 */ + 3, 60, 60, 3, 60, 46, 46, 46, /* 23 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 23 */ + 40, 40, 40, 46, 46, 46, 46, 46, /* 23 */ + 40, 40, 40, 3, 3, 46, 46, 46, /* 23 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 23 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */ + 46, 46, 46, 46, 3, 46, 46, 46, /* 24 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 24 */ + 46, 46, 46, 3, 46, 46, 46, 3, /* 24 */ + 46, 40, 40, 40, 40, 40, 40, 40, /* 24 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 24 */ + 40, 40, 40, 46, 46, 46, 46, 46, /* 24 */ + 59, 40, 40, 40, 40, 40, 40, 40, /* 25 */ + 40, 40, 40, 60, 60, 60, 60, 60, /* 25 */ + 60, 60, 60, 46, 46, 46, 46, 46, /* 25 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 25 */ + 78, 78, 78, 78, 78, 78, 78, 78, /* 25 */ + 78, 78, 3, 3, 3, 3, 46, 46, /* 25 */ + 60, 40, 40, 40, 40, 40, 40, 40, /* 25 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 25 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 26 */ + 46, 46, 40, 40, 40, 40, 40, 46, /* 26 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 27 */ + 40, 40, 40, 40, 40, 40, 40, 46, /* 27 */ + 40, 40, 40, 40, 3, 40, 60, 60, /* 27 */ + 60, 60, 60, 60, 60, 79, 79, 60, /* 27 */ + 60, 60, 60, 60, 60, 59, 59, 60, /* 27 */ + 60, 15, 60, 60, 60, 60, 46, 46, /* 27 */ + 9, 9, 9, 9, 9, 9, 9, 9, /* 27 */ + 9, 9, 46, 46, 46, 46, 46, 46, /* 27 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 28 */ + 46, 60, 60, 80, 46, 40, 40, 40, /* 29 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 29 */ + 40, 40, 46, 46, 60, 40, 80, 80, /* 29 */ + 80, 60, 60, 60, 60, 60, 60, 60, /* 30 */ + 60, 80, 80, 80, 80, 60, 46, 46, /* 30 */ + 15, 60, 60, 60, 60, 46, 46, 46, /* 30 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 30 */ + 40, 40, 60, 60, 3, 3, 81, 81, /* 30 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 30 */ + 3, 46, 46, 46, 46, 46, 46, 46, /* 30 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 30 */ + 46, 60, 80, 80, 46, 40, 40, 40, /* 31 */ + 40, 40, 40, 40, 40, 46, 46, 40, /* 31 */ + 40, 46, 46, 40, 40, 40, 40, 40, /* 31 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 31 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 31 */ + 40, 46, 40, 46, 46, 46, 40, 40, /* 31 */ + 40, 40, 46, 46, 60, 46, 80, 80, /* 31 */ + 80, 60, 60, 60, 60, 46, 46, 80, /* 32 */ + 80, 46, 46, 80, 80, 60, 46, 46, /* 32 */ + 46, 46, 46, 46, 46, 46, 46, 80, /* 32 */ + 46, 46, 46, 46, 40, 40, 46, 40, /* 32 */ + 40, 40, 60, 60, 46, 46, 81, 81, /* 32 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 32 */ + 40, 40, 4, 4, 82, 82, 82, 82, /* 32 */ + 19, 83, 15, 46, 46, 46, 46, 46, /* 32 */ + 46, 46, 60, 46, 46, 40, 40, 40, /* 33 */ + 40, 40, 40, 46, 46, 46, 46, 40, /* 33 */ + 40, 46, 46, 40, 40, 40, 40, 40, /* 33 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 33 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 33 */ + 40, 46, 40, 40, 46, 40, 40, 46, /* 33 */ + 40, 40, 46, 46, 60, 46, 80, 80, /* 33 */ + 80, 60, 60, 46, 46, 46, 46, 60, /* 34 */ + 60, 46, 46, 60, 60, 60, 46, 46, /* 34 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */ + 46, 40, 40, 40, 40, 46, 40, 46, /* 34 */ + 46, 46, 46, 46, 46, 46, 81, 81, /* 34 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 34 */ + 60, 60, 40, 40, 40, 46, 46, 46, /* 34 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 34 */ + 46, 60, 60, 80, 46, 40, 40, 40, /* 35 */ + 40, 40, 40, 40, 46, 40, 46, 40, /* 35 */ + 40, 40, 46, 40, 40, 40, 40, 40, /* 35 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 35 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 35 */ + 40, 46, 40, 40, 46, 40, 40, 40, /* 35 */ + 40, 40, 46, 46, 60, 40, 80, 80, /* 35 */ + 80, 60, 60, 60, 60, 60, 46, 60, /* 36 */ + 60, 80, 46, 80, 80, 60, 46, 46, /* 36 */ + 15, 46, 46, 46, 46, 46, 46, 46, /* 36 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */ + 40, 46, 46, 46, 46, 46, 81, 81, /* 36 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 36 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 36 */ + 46, 60, 80, 80, 46, 40, 40, 40, /* 37 */ + 40, 40, 40, 40, 40, 46, 46, 40, /* 37 */ + 40, 46, 46, 40, 40, 40, 40, 40, /* 37 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 37 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 37 */ + 40, 46, 40, 40, 46, 46, 40, 40, /* 37 */ + 40, 40, 46, 46, 60, 40, 80, 60, /* 37 */ + 80, 60, 60, 60, 46, 46, 46, 80, /* 38 */ + 80, 46, 46, 80, 80, 60, 46, 46, /* 38 */ + 46, 46, 46, 46, 46, 46, 60, 80, /* 38 */ + 46, 46, 46, 46, 40, 40, 46, 40, /* 38 */ + 40, 40, 46, 46, 46, 46, 81, 81, /* 38 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 38 */ + 15, 46, 46, 46, 46, 46, 46, 46, /* 38 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 38 */ + 46, 46, 60, 80, 46, 40, 40, 40, /* 39 */ + 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */ + 40, 46, 40, 40, 40, 40, 46, 46, /* 39 */ + 46, 40, 40, 46, 40, 46, 40, 40, /* 39 */ + 46, 46, 46, 40, 40, 46, 46, 46, /* 39 */ + 40, 40, 40, 46, 46, 46, 40, 40, /* 39 */ + 40, 40, 40, 40, 40, 40, 46, 40, /* 39 */ + 40, 40, 46, 46, 46, 46, 80, 80, /* 39 */ + 60, 80, 80, 46, 46, 46, 80, 80, /* 40 */ + 80, 46, 80, 80, 80, 60, 46, 46, /* 40 */ + 46, 46, 46, 46, 46, 46, 46, 80, /* 40 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */ + 46, 46, 46, 46, 46, 46, 46, 81, /* 40 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 40 */ + 84, 19, 19, 46, 46, 46, 46, 46, /* 40 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 40 */ + 46, 80, 80, 80, 46, 40, 40, 40, /* 41 */ + 40, 40, 40, 40, 40, 46, 40, 40, /* 41 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 41 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 41 */ + 40, 40, 40, 40, 46, 40, 40, 40, /* 41 */ + 40, 40, 46, 46, 46, 46, 60, 60, /* 41 */ + 60, 80, 80, 80, 80, 46, 60, 60, /* 42 */ + 60, 46, 60, 60, 60, 60, 46, 46, /* 42 */ + 46, 46, 46, 46, 46, 60, 60, 46, /* 42 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */ + 40, 40, 46, 46, 46, 46, 81, 81, /* 42 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 42 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 42 */ + 46, 46, 80, 80, 46, 40, 40, 40, /* 43 */ + 40, 40, 40, 40, 40, 46, 40, 40, /* 43 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 43 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 43 */ + 40, 40, 40, 40, 46, 40, 40, 40, /* 43 */ + 40, 40, 46, 46, 46, 46, 80, 60, /* 43 */ + 80, 80, 80, 80, 80, 46, 60, 80, /* 44 */ + 80, 46, 80, 80, 60, 60, 46, 46, /* 44 */ + 46, 46, 46, 46, 46, 80, 80, 46, /* 44 */ + 46, 46, 46, 46, 46, 46, 40, 46, /* 44 */ + 40, 40, 46, 46, 46, 46, 81, 81, /* 44 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 44 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 44 */ + 46, 46, 80, 80, 46, 40, 40, 40, /* 45 */ + 40, 40, 40, 40, 40, 46, 40, 40, /* 45 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */ + 40, 46, 40, 40, 40, 40, 40, 40, /* 45 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 45 */ + 40, 40, 46, 46, 46, 46, 80, 80, /* 45 */ + 80, 60, 60, 60, 46, 46, 80, 80, /* 46 */ + 80, 46, 80, 80, 80, 60, 46, 46, /* 46 */ + 46, 46, 46, 46, 46, 46, 46, 80, /* 46 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */ + 40, 40, 46, 46, 46, 46, 81, 81, /* 46 */ + 81, 81, 81, 81, 81, 81, 81, 81, /* 46 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 46 */ + 46, 40, 40, 40, 40, 40, 40, 40, /* 47 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 47 */ + 40, 40, 40, 40, 40, 40, 40, 3, /* 47 */ + 40, 60, 40, 40, 60, 60, 60, 60, /* 47 */ + 60, 60, 60, 46, 46, 46, 46, 4, /* 47 */ + 40, 40, 40, 40, 40, 40, 59, 60, /* 48 */ + 60, 60, 60, 60, 60, 60, 60, 15, /* 48 */ + 9, 9, 9, 9, 9, 9, 9, 9, /* 48 */ + 9, 9, 3, 3, 46, 46, 46, 46, /* 48 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 48 */ + 46, 40, 40, 46, 40, 46, 46, 40, /* 49 */ + 40, 46, 40, 46, 46, 40, 46, 46, /* 49 */ + 46, 46, 46, 46, 40, 40, 40, 40, /* 49 */ + 46, 40, 40, 40, 40, 40, 40, 40, /* 49 */ + 46, 40, 40, 40, 46, 40, 46, 40, /* 49 */ + 46, 46, 40, 40, 46, 40, 40, 3, /* 49 */ + 40, 60, 40, 40, 60, 60, 60, 60, /* 49 */ + 60, 60, 46, 60, 60, 40, 46, 46, /* 49 */ + 40, 40, 40, 40, 40, 46, 59, 46, /* 50 */ + 60, 60, 60, 60, 60, 60, 46, 46, /* 50 */ + 9, 9, 9, 9, 9, 9, 9, 9, /* 50 */ + 9, 9, 46, 46, 40, 40, 46, 46, /* 50 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 50 */ + 15, 15, 15, 15, 3, 3, 3, 3, /* 51 */ + 3, 3, 3, 3, 3, 3, 3, 3, /* 51 */ + 3, 3, 3, 15, 15, 15, 15, 15, /* 51 */ + 60, 60, 15, 15, 15, 15, 15, 15, /* 51 */ + 78, 78, 78, 78, 78, 78, 78, 78, /* 51 */ + 78, 78, 85, 85, 85, 85, 85, 85, /* 51 */ + 85, 85, 85, 85, 15, 60, 15, 60, /* 51 */ + 15, 60, 5, 6, 5, 6, 80, 80, /* 51 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */ + 46, 40, 40, 40, 40, 40, 40, 40, /* 52 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 52 */ + 40, 40, 46, 46, 46, 46, 46, 46, /* 52 */ + 46, 60, 60, 60, 60, 60, 60, 60, /* 52 */ + 60, 60, 60, 60, 60, 60, 60, 80, /* 52 */ + 60, 60, 60, 60, 60, 3, 60, 60, /* 53 */ + 60, 60, 60, 60, 46, 46, 46, 46, /* 53 */ + 60, 60, 60, 60, 60, 60, 46, 60, /* 53 */ + 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 53 */ + 60, 60, 60, 60, 60, 60, 46, 46, /* 53 */ + 46, 60, 60, 60, 60, 60, 60, 60, /* 53 */ + 46, 60, 46, 46, 46, 46, 46, 46, /* 53 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 54 */ + 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */ + 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */ + 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */ + 76, 76, 76, 76, 76, 76, 76, 76, /* 54 */ + 76, 76, 76, 76, 76, 76, 46, 46, /* 55 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 55 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 55 */ + 16, 16, 16, 16, 16, 16, 16, 46, /* 55 */ + 46, 46, 46, 3, 46, 46, 46, 46, /* 55 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 56 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */ + 40, 40, 46, 46, 46, 46, 46, 40, /* 57 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 57 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */ + 40, 40, 40, 46, 46, 46, 46, 46, /* 58 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 58 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 59 */ + 40, 40, 46, 46, 46, 46, 46, 46, /* 59 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 60 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */ + 23, 24, 23, 24, 23, 24, 16, 16, /* 61 */ + 16, 16, 16, 16, 46, 46, 46, 46, /* 61 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 61 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */ + 23, 24, 23, 24, 23, 24, 23, 24, /* 62 */ + 23, 24, 46, 46, 46, 46, 46, 46, /* 62 */ + 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */ + 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */ + 86, 86, 86, 86, 86, 86, 46, 46, /* 63 */ + 87, 87, 87, 87, 87, 87, 46, 46, /* 63 */ + 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */ + 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */ + 86, 86, 86, 86, 86, 86, 86, 86, /* 63 */ + 87, 87, 87, 87, 87, 87, 87, 87, /* 63 */ + 86, 86, 86, 86, 86, 86, 46, 46, /* 64 */ + 87, 87, 87, 87, 87, 87, 46, 46, /* 64 */ + 16, 86, 16, 86, 16, 86, 16, 86, /* 64 */ + 46, 87, 46, 87, 46, 87, 46, 87, /* 64 */ + 86, 86, 86, 86, 86, 86, 86, 86, /* 64 */ + 87, 87, 87, 87, 87, 87, 87, 87, /* 64 */ + 88, 88, 89, 89, 89, 89, 90, 90, /* 64 */ + 91, 91, 92, 92, 93, 93, 46, 46, /* 64 */ + 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */ + 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */ + 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */ + 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */ + 86, 86, 86, 86, 86, 86, 86, 86, /* 65 */ + 87, 87, 87, 87, 87, 87, 87, 87, /* 65 */ + 86, 86, 16, 94, 16, 46, 16, 16, /* 65 */ + 87, 87, 95, 95, 96, 11, 38, 11, /* 65 */ + 11, 11, 16, 94, 16, 46, 16, 16, /* 66 */ + 97, 97, 97, 97, 96, 11, 11, 11, /* 66 */ + 86, 86, 16, 16, 46, 46, 16, 16, /* 66 */ + 87, 87, 98, 98, 46, 11, 11, 11, /* 66 */ + 86, 86, 16, 16, 16, 99, 16, 16, /* 66 */ + 87, 87, 100, 100, 101, 11, 11, 11, /* 66 */ + 46, 46, 16, 94, 16, 46, 16, 16, /* 66 */ +102, 102, 103, 103, 96, 11, 11, 46, /* 66 */ + 2, 2, 2, 2, 2, 2, 2, 2, /* 67 */ + 2, 2, 2, 2, 104, 104, 104, 104, /* 67 */ + 8, 8, 8, 8, 8, 8, 3, 3, /* 67 */ + 5, 6, 5, 5, 5, 6, 5, 5, /* 67 */ + 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */ +105, 106, 104, 104, 104, 104, 104, 46, /* 67 */ + 3, 3, 3, 3, 3, 3, 3, 3, /* 67 */ + 3, 5, 6, 3, 3, 3, 3, 12, /* 67 */ + 12, 3, 3, 3, 7, 5, 6, 46, /* 68 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 68 */ + 46, 46, 104, 104, 104, 104, 104, 104, /* 68 */ + 17, 46, 46, 46, 17, 17, 17, 17, /* 68 */ + 17, 17, 7, 7, 7, 5, 6, 16, /* 68 */ +107, 107, 107, 107, 107, 107, 107, 107, /* 69 */ +107, 107, 7, 7, 7, 5, 6, 46, /* 69 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */ + 4, 4, 4, 4, 4, 4, 4, 4, /* 69 */ + 4, 4, 4, 4, 46, 46, 46, 46, /* 69 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 69 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */ + 60, 60, 60, 60, 60, 60, 60, 60, /* 70 */ + 60, 60, 60, 60, 60, 79, 79, 79, /* 70 */ + 79, 60, 46, 46, 46, 46, 46, 46, /* 70 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 70 */ + 15, 15, 38, 15, 15, 15, 15, 38, /* 71 */ + 15, 15, 16, 38, 38, 38, 16, 16, /* 71 */ + 38, 38, 38, 16, 15, 38, 15, 15, /* 71 */ + 38, 38, 38, 38, 38, 38, 15, 15, /* 71 */ + 15, 15, 15, 15, 38, 15, 38, 15, /* 71 */ + 38, 15, 38, 38, 38, 38, 16, 16, /* 71 */ + 38, 38, 15, 38, 16, 40, 40, 40, /* 71 */ + 40, 46, 46, 46, 46, 46, 46, 46, /* 71 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 72 */ + 46, 46, 46, 19, 19, 19, 19, 19, /* 72 */ + 19, 19, 19, 19, 19, 19, 19, 108, /* 72 */ +109, 109, 109, 109, 109, 109, 109, 109, /* 72 */ +109, 109, 109, 109, 110, 110, 110, 110, /* 72 */ +111, 111, 111, 111, 111, 111, 111, 111, /* 72 */ +111, 111, 111, 111, 112, 112, 112, 112, /* 72 */ +113, 113, 113, 46, 46, 46, 46, 46, /* 73 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 73 */ + 7, 7, 7, 7, 7, 15, 15, 15, /* 73 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 73 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */ + 15, 15, 7, 15, 7, 15, 15, 15, /* 74 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 74 */ + 15, 15, 15, 46, 46, 46, 46, 46, /* 74 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 74 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 75 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 76 */ + 7, 7, 46, 46, 46, 46, 46, 46, /* 76 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 76 */ + 15, 46, 15, 15, 15, 15, 15, 15, /* 77 */ + 7, 7, 7, 7, 15, 15, 15, 15, /* 77 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */ + 7, 7, 15, 15, 15, 15, 15, 15, /* 77 */ + 15, 5, 6, 15, 15, 15, 15, 15, /* 77 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 77 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 78 */ + 15, 15, 15, 46, 46, 46, 46, 46, /* 78 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 79 */ + 15, 15, 15, 15, 15, 46, 46, 46, /* 79 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 79 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 80 */ + 15, 15, 15, 46, 46, 46, 46, 46, /* 80 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 80 */ +114, 114, 114, 114, 114, 114, 114, 114, /* 80 */ +114, 114, 114, 114, 114, 114, 114, 114, /* 80 */ +114, 114, 114, 114, 82, 82, 82, 82, /* 80 */ + 82, 82, 82, 82, 82, 82, 82, 82, /* 80 */ + 82, 82, 82, 82, 82, 82, 82, 82, /* 81 */ +115, 115, 115, 115, 115, 115, 115, 115, /* 81 */ +115, 115, 115, 115, 115, 115, 115, 115, /* 81 */ +115, 115, 115, 115, 15, 15, 15, 15, /* 81 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 81 */ + 15, 15, 15, 15, 15, 15, 116, 116, /* 81 */ +116, 116, 116, 116, 116, 116, 116, 116, /* 81 */ +116, 116, 116, 116, 116, 116, 116, 116, /* 82 */ +116, 116, 116, 116, 116, 116, 116, 116, /* 82 */ +117, 117, 117, 117, 117, 117, 117, 117, /* 82 */ +117, 117, 117, 117, 117, 117, 117, 117, /* 82 */ +117, 117, 117, 117, 117, 117, 117, 117, /* 82 */ +117, 117, 118, 46, 46, 46, 46, 46, /* 82 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 82 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 83 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */ + 15, 15, 15, 15, 15, 15, 46, 46, /* 84 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 84 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 84 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 85 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 85 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */ + 15, 15, 15, 15, 46, 46, 46, 46, /* 86 */ + 46, 46, 15, 15, 15, 15, 15, 15, /* 86 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 86 */ + 46, 15, 15, 15, 15, 46, 15, 15, /* 87 */ + 15, 15, 46, 46, 15, 15, 15, 15, /* 87 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */ + 46, 15, 15, 15, 15, 15, 15, 15, /* 87 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 87 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 88 */ + 15, 15, 15, 15, 46, 15, 46, 15, /* 88 */ + 15, 15, 15, 46, 46, 46, 15, 46, /* 88 */ + 15, 15, 15, 15, 15, 15, 15, 46, /* 88 */ + 46, 15, 15, 15, 15, 15, 15, 15, /* 88 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 88 */ + 46, 46, 46, 46, 46, 46, 119, 119, /* 88 */ +119, 119, 119, 119, 119, 119, 119, 119, /* 88 */ +114, 114, 114, 114, 114, 114, 114, 114, /* 89 */ +114, 114, 83, 83, 83, 83, 83, 83, /* 89 */ + 83, 83, 83, 83, 15, 46, 46, 46, /* 89 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 89 */ + 46, 15, 15, 15, 15, 15, 15, 15, /* 89 */ + 15, 15, 15, 15, 15, 15, 15, 46, /* 89 */ + 2, 3, 3, 3, 15, 59, 3, 120, /* 90 */ + 5, 6, 5, 6, 5, 6, 5, 6, /* 90 */ + 5, 6, 15, 15, 5, 6, 5, 6, /* 90 */ + 5, 6, 5, 6, 8, 5, 6, 5, /* 90 */ + 15, 121, 121, 121, 121, 121, 121, 121, /* 90 */ +121, 121, 60, 60, 60, 60, 60, 60, /* 90 */ + 8, 59, 59, 59, 59, 59, 15, 15, /* 90 */ + 46, 46, 46, 46, 46, 46, 46, 15, /* 90 */ + 46, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 91 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */ + 40, 40, 40, 40, 40, 46, 46, 46, /* 92 */ + 46, 60, 60, 59, 59, 59, 59, 46, /* 92 */ + 46, 40, 40, 40, 40, 40, 40, 40, /* 92 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 92 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 93 */ + 40, 40, 40, 3, 59, 59, 59, 46, /* 93 */ + 46, 46, 46, 46, 46, 40, 40, 40, /* 94 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */ + 40, 40, 40, 40, 40, 46, 46, 46, /* 94 */ + 46, 40, 40, 40, 40, 40, 40, 40, /* 94 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 94 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 95 */ + 40, 40, 40, 40, 40, 40, 40, 46, /* 95 */ + 15, 15, 85, 85, 85, 85, 15, 15, /* 95 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 95 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 95 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */ + 15, 15, 15, 15, 15, 46, 46, 46, /* 96 */ + 85, 85, 85, 85, 85, 85, 85, 85, /* 96 */ + 85, 85, 15, 15, 15, 15, 15, 15, /* 96 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 96 */ + 15, 15, 15, 15, 46, 46, 46, 46, /* 97 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 97 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 97 */ + 15, 15, 15, 15, 46, 46, 46, 15, /* 97 */ +114, 114, 114, 114, 114, 114, 114, 114, /* 98 */ +114, 114, 15, 15, 15, 15, 15, 15, /* 98 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 98 */ + 15, 46, 46, 46, 46, 46, 46, 46, /* 98 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 98 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */ + 15, 15, 15, 15, 46, 46, 46, 46, /* 99 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 99 */ + 15, 15, 15, 15, 15, 15, 15, 46, /* 99 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 100 */ + 15, 15, 15, 15, 15, 15, 15, 46, /* 100 */ + 46, 46, 46, 15, 15, 15, 15, 15, /* 100 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */ + 15, 15, 15, 15, 15, 15, 46, 46, /* 101 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 101 */ + 15, 15, 15, 15, 15, 15, 15, 46, /* 101 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 102 */ + 40, 40, 40, 40, 40, 40, 46, 46, /* 102 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 102 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 103 */ + 40, 40, 40, 40, 46, 46, 46, 46, /* 103 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 103 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +122, 122, 122, 122, 122, 122, 122, 122, /* 104 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ +123, 123, 123, 123, 123, 123, 123, 123, /* 105 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 106 */ + 40, 40, 40, 40, 40, 40, 46, 46, /* 106 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 106 */ + 16, 16, 16, 16, 16, 16, 16, 46, /* 107 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 107 */ + 46, 46, 46, 16, 16, 16, 16, 16, /* 107 */ + 46, 46, 46, 46, 46, 46, 60, 40, /* 107 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 107 */ + 40, 7, 40, 40, 40, 40, 40, 40, /* 107 */ + 40, 40, 40, 40, 40, 40, 40, 46, /* 107 */ + 40, 40, 40, 40, 40, 46, 40, 46, /* 107 */ + 40, 40, 46, 40, 40, 46, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 108 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 109 */ + 40, 40, 46, 46, 46, 46, 46, 46, /* 109 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 109 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 110 */ + 46, 46, 46, 40, 40, 40, 40, 40, /* 110 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 110 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 111 */ + 40, 40, 40, 40, 40, 40, 5, 6, /* 111 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 112 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 112 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */ + 46, 46, 40, 40, 40, 40, 40, 40, /* 113 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 113 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 114 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 114 */ + 40, 40, 40, 40, 46, 46, 46, 46, /* 114 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */ + 60, 60, 60, 60, 46, 46, 46, 46, /* 115 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 115 */ + 3, 8, 8, 12, 12, 5, 6, 5, /* 115 */ + 6, 5, 6, 5, 6, 5, 6, 5, /* 115 */ + 6, 5, 6, 5, 6, 46, 46, 46, /* 116 */ + 46, 3, 3, 3, 3, 12, 12, 12, /* 116 */ + 3, 3, 3, 46, 3, 3, 3, 3, /* 116 */ + 8, 5, 6, 5, 6, 5, 6, 3, /* 116 */ + 3, 3, 7, 8, 7, 7, 7, 46, /* 116 */ + 3, 4, 3, 3, 46, 46, 46, 46, /* 116 */ + 40, 40, 40, 46, 40, 46, 40, 40, /* 116 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 116 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 117 */ + 40, 40, 40, 40, 40, 46, 46, 104, /* 117 */ + 46, 3, 3, 3, 4, 3, 3, 3, /* 118 */ + 5, 6, 3, 7, 3, 8, 3, 3, /* 118 */ + 9, 9, 9, 9, 9, 9, 9, 9, /* 118 */ + 9, 9, 3, 3, 7, 7, 7, 3, /* 118 */ + 3, 10, 10, 10, 10, 10, 10, 10, /* 118 */ + 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */ + 10, 10, 10, 10, 10, 10, 10, 10, /* 118 */ + 10, 10, 10, 5, 3, 6, 11, 12, /* 118 */ + 11, 13, 13, 13, 13, 13, 13, 13, /* 119 */ + 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */ + 13, 13, 13, 13, 13, 13, 13, 13, /* 119 */ + 13, 13, 13, 5, 7, 6, 7, 46, /* 119 */ + 46, 3, 5, 6, 3, 3, 40, 40, /* 119 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */ + 59, 40, 40, 40, 40, 40, 40, 40, /* 119 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 119 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */ + 40, 40, 40, 40, 40, 40, 59, 59, /* 120 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */ + 40, 40, 40, 40, 40, 40, 40, 40, /* 120 */ + 40, 40, 40, 40, 40, 40, 40, 46, /* 120 */ + 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */ + 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */ + 46, 46, 40, 40, 40, 40, 40, 40, /* 121 */ + 46, 46, 40, 40, 40, 46, 46, 46, /* 121 */ + 4, 4, 7, 11, 15, 4, 4, 46, /* 121 */ + 7, 7, 7, 7, 7, 15, 15, 46, /* 121 */ + 46, 46, 46, 46, 46, 46, 46, 46, /* 121 */ + 46, 46, 46, 46, 46, 15, 46, 46 /* 121 */ +}; + +/* The A table has 124 entries for a total of 496 bytes. */ + +const uint32 js_A[] = { +0x0001000F, /* 0 Cc, ignorable */ +0x0004000F, /* 1 Cc, whitespace */ +0x0004000C, /* 2 Zs, whitespace */ +0x00000018, /* 3 Po */ +0x0006001A, /* 4 Sc, currency */ +0x00000015, /* 5 Ps */ +0x00000016, /* 6 Pe */ +0x00000019, /* 7 Sm */ +0x00000014, /* 8 Pd */ +0x00036089, /* 9 Nd, identifier part, decimal 16 */ +0x0827FF81, /* 10 Lu, hasLower (add 32), identifier start, supradecimal 31 */ +0x0000001B, /* 11 Sk */ +0x00050017, /* 12 Pc, underscore */ +0x0817FF82, /* 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 */ +0x0000000C, /* 14 Zs */ +0x0000001C, /* 15 So */ +0x00070182, /* 16 Ll, identifier start */ +0x0000600B, /* 17 No, decimal 16 */ +0x0000500B, /* 18 No, decimal 8 */ +0x0000800B, /* 19 No, strange */ +0x08270181, /* 20 Lu, hasLower (add 32), identifier start */ +0x08170182, /* 21 Ll, hasUpper (subtract 32), identifier start */ +0xE1D70182, /* 22 Ll, hasUpper (subtract -121), identifier start */ +0x00670181, /* 23 Lu, hasLower (add 1), identifier start */ +0x00570182, /* 24 Ll, hasUpper (subtract 1), identifier start */ +0xCE670181, /* 25 Lu, hasLower (add -199), identifier start */ +0x3A170182, /* 26 Ll, hasUpper (subtract 232), identifier start */ +0xE1E70181, /* 27 Lu, hasLower (add -121), identifier start */ +0x4B170182, /* 28 Ll, hasUpper (subtract 300), identifier start */ +0x34A70181, /* 29 Lu, hasLower (add 210), identifier start */ +0x33A70181, /* 30 Lu, hasLower (add 206), identifier start */ +0x33670181, /* 31 Lu, hasLower (add 205), identifier start */ +0x32A70181, /* 32 Lu, hasLower (add 202), identifier start */ +0x32E70181, /* 33 Lu, hasLower (add 203), identifier start */ +0x33E70181, /* 34 Lu, hasLower (add 207), identifier start */ +0x34E70181, /* 35 Lu, hasLower (add 211), identifier start */ +0x34670181, /* 36 Lu, hasLower (add 209), identifier start */ +0x35670181, /* 37 Lu, hasLower (add 213), identifier start */ +0x00070181, /* 38 Lu, identifier start */ +0x36A70181, /* 39 Lu, hasLower (add 218), identifier start */ +0x00070185, /* 40 Lo, identifier start */ +0x36670181, /* 41 Lu, hasLower (add 217), identifier start */ +0x36E70181, /* 42 Lu, hasLower (add 219), identifier start */ +0x00AF0181, /* 43 Lu, hasLower (add 2), hasTitle, identifier start */ +0x007F0183, /* 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start */ +0x009F0182, /* 45 Ll, hasUpper (subtract 2), hasTitle, identifier start */ +0x00000000, /* 46 unassigned */ +0x34970182, /* 47 Ll, hasUpper (subtract 210), identifier start */ +0x33970182, /* 48 Ll, hasUpper (subtract 206), identifier start */ +0x33570182, /* 49 Ll, hasUpper (subtract 205), identifier start */ +0x32970182, /* 50 Ll, hasUpper (subtract 202), identifier start */ +0x32D70182, /* 51 Ll, hasUpper (subtract 203), identifier start */ +0x33D70182, /* 52 Ll, hasUpper (subtract 207), identifier start */ +0x34570182, /* 53 Ll, hasUpper (subtract 209), identifier start */ +0x34D70182, /* 54 Ll, hasUpper (subtract 211), identifier start */ +0x35570182, /* 55 Ll, hasUpper (subtract 213), identifier start */ +0x36970182, /* 56 Ll, hasUpper (subtract 218), identifier start */ +0x36570182, /* 57 Ll, hasUpper (subtract 217), identifier start */ +0x36D70182, /* 58 Ll, hasUpper (subtract 219), identifier start */ +0x00070084, /* 59 Lm, identifier start */ +0x00030086, /* 60 Mn, identifier part */ +0x09A70181, /* 61 Lu, hasLower (add 38), identifier start */ +0x09670181, /* 62 Lu, hasLower (add 37), identifier start */ +0x10270181, /* 63 Lu, hasLower (add 64), identifier start */ +0x0FE70181, /* 64 Lu, hasLower (add 63), identifier start */ +0x09970182, /* 65 Ll, hasUpper (subtract 38), identifier start */ +0x09570182, /* 66 Ll, hasUpper (subtract 37), identifier start */ +0x10170182, /* 67 Ll, hasUpper (subtract 64), identifier start */ +0x0FD70182, /* 68 Ll, hasUpper (subtract 63), identifier start */ +0x0F970182, /* 69 Ll, hasUpper (subtract 62), identifier start */ +0x0E570182, /* 70 Ll, hasUpper (subtract 57), identifier start */ +0x0BD70182, /* 71 Ll, hasUpper (subtract 47), identifier start */ +0x0D970182, /* 72 Ll, hasUpper (subtract 54), identifier start */ +0x15970182, /* 73 Ll, hasUpper (subtract 86), identifier start */ +0x14170182, /* 74 Ll, hasUpper (subtract 80), identifier start */ +0x14270181, /* 75 Lu, hasLower (add 80), identifier start */ +0x0C270181, /* 76 Lu, hasLower (add 48), identifier start */ +0x0C170182, /* 77 Ll, hasUpper (subtract 48), identifier start */ +0x00034089, /* 78 Nd, identifier part, decimal 0 */ +0x00000087, /* 79 Me */ +0x00030088, /* 80 Mc, identifier part */ +0x00037489, /* 81 Nd, identifier part, decimal 26 */ +0x00005A0B, /* 82 No, decimal 13 */ +0x00006E0B, /* 83 No, decimal 23 */ +0x0000740B, /* 84 No, decimal 26 */ +0x0000000B, /* 85 No */ +0xFE170182, /* 86 Ll, hasUpper (subtract -8), identifier start */ +0xFE270181, /* 87 Lu, hasLower (add -8), identifier start */ +0xED970182, /* 88 Ll, hasUpper (subtract -74), identifier start */ +0xEA970182, /* 89 Ll, hasUpper (subtract -86), identifier start */ +0xE7170182, /* 90 Ll, hasUpper (subtract -100), identifier start */ +0xE0170182, /* 91 Ll, hasUpper (subtract -128), identifier start */ +0xE4170182, /* 92 Ll, hasUpper (subtract -112), identifier start */ +0xE0970182, /* 93 Ll, hasUpper (subtract -126), identifier start */ +0xFDD70182, /* 94 Ll, hasUpper (subtract -9), identifier start */ +0xEDA70181, /* 95 Lu, hasLower (add -74), identifier start */ +0xFDE70181, /* 96 Lu, hasLower (add -9), identifier start */ +0xEAA70181, /* 97 Lu, hasLower (add -86), identifier start */ +0xE7270181, /* 98 Lu, hasLower (add -100), identifier start */ +0xFE570182, /* 99 Ll, hasUpper (subtract -7), identifier start */ +0xE4270181, /* 100 Lu, hasLower (add -112), identifier start */ +0xFE670181, /* 101 Lu, hasLower (add -7), identifier start */ +0xE0270181, /* 102 Lu, hasLower (add -128), identifier start */ +0xE0A70181, /* 103 Lu, hasLower (add -126), identifier start */ +0x00010010, /* 104 Cf, ignorable */ +0x0004000D, /* 105 Zl, whitespace */ +0x0004000E, /* 106 Zp, whitespace */ +0x0000400B, /* 107 No, decimal 0 */ +0x0000440B, /* 108 No, decimal 2 */ +0x0427438A, /* 109 Nl, hasLower (add 16), identifier start, decimal 1 */ +0x0427818A, /* 110 Nl, hasLower (add 16), identifier start, strange */ +0x0417638A, /* 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 */ +0x0417818A, /* 112 Nl, hasUpper (subtract 16), identifier start, strange */ +0x0007818A, /* 113 Nl, identifier start, strange */ +0x0000420B, /* 114 No, decimal 1 */ +0x0000720B, /* 115 No, decimal 25 */ +0x06A0001C, /* 116 So, hasLower (add 26) */ +0x0690001C, /* 117 So, hasUpper (subtract 26) */ +0x00006C0B, /* 118 No, decimal 22 */ +0x0000560B, /* 119 No, decimal 11 */ +0x0007738A, /* 120 Nl, identifier start, decimal 25 */ +0x0007418A, /* 121 Nl, identifier start, decimal 0 */ +0x00000013, /* 122 Cs */ +0x00000012 /* 123 Co */ +}; + +const jschar js_uriReservedPlusPound_ucstr[] = + {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#', 0}; +const jschar js_uriUnescaped_ucstr[] = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '-', '_', '.', '!', '~', '*', '\'', '(', ')', 0}; + +/* + * This table allows efficient testing for the regular expression \w which is + * defined by ECMA-262 15.10.2.6 to be [0-9A-Z_a-z]. + */ +const bool js_alnum[] = { +/* 0 1 2 3 4 5 5 7 8 9 */ +/* 0 */ false, false, false, false, false, false, false, false, false, false, +/* 1 */ false, false, false, false, false, false, false, false, false, false, +/* 2 */ false, false, false, false, false, false, false, false, false, false, +/* 3 */ false, false, false, false, false, false, false, false, false, false, +/* 4 */ false, false, false, false, false, false, false, false, true, true, +/* 5 */ true, true, true, true, true, true, true, true, false, false, +/* 6 */ false, false, false, false, false, true, true, true, true, true, +/* 7 */ true, true, true, true, true, true, true, true, true, true, +/* 8 */ true, true, true, true, true, true, true, true, true, true, +/* 9 */ true, false, false, false, false, true, false, true, true, true, +/* 10 */ true, true, true, true, true, true, true, true, true, true, +/* 11 */ true, true, true, true, true, true, true, true, true, true, +/* 12 */ true, true, true, false, false, false, false, false +}; + +#define URI_CHUNK 64U + +static inline bool +TransferBufferToString(JSContext *cx, StringBuffer &sb, Value *rval) +{ + JSString *str = sb.finishString(); + if (!str) + return false; + rval->setString(str); + return true;; +} + +/* + * ECMA 3, 15.1.3 URI Handling Function Properties + * + * The following are implementations of the algorithms + * given in the ECMA specification for the hidden functions + * 'Encode' and 'Decode'. + */ +static JSBool +Encode(JSContext *cx, JSString *str, const jschar *unescapedSet, + const jschar *unescapedSet2, Value *rval) +{ + static const char HexDigits[] = "0123456789ABCDEF"; /* NB: uppercase */ + + size_t length = str->length(); + const jschar *chars = str->getChars(cx); + if (!chars) + return JS_FALSE; + + if (length == 0) { + rval->setString(cx->runtime->emptyString); + return JS_TRUE; + } + + StringBuffer sb(cx); + jschar hexBuf[4]; + hexBuf[0] = '%'; + hexBuf[3] = 0; + for (size_t k = 0; k < length; k++) { + jschar c = chars[k]; + if (js_strchr(unescapedSet, c) || + (unescapedSet2 && js_strchr(unescapedSet2, c))) { + if (!sb.append(c)) + return JS_FALSE; + } else { + if ((c >= 0xDC00) && (c <= 0xDFFF)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_URI, NULL); + return JS_FALSE; + } + uint32 v; + if (c < 0xD800 || c > 0xDBFF) { + v = c; + } else { + k++; + if (k == length) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_URI, NULL); + return JS_FALSE; + } + jschar c2 = chars[k]; + if ((c2 < 0xDC00) || (c2 > 0xDFFF)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_URI, NULL); + return JS_FALSE; + } + v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000; + } + uint8 utf8buf[4]; + size_t L = js_OneUcs4ToUtf8Char(utf8buf, v); + for (size_t j = 0; j < L; j++) { + hexBuf[1] = HexDigits[utf8buf[j] >> 4]; + hexBuf[2] = HexDigits[utf8buf[j] & 0xf]; + if (!sb.append(hexBuf, 3)) + return JS_FALSE; + } + } + } + + return TransferBufferToString(cx, sb, rval); +} + +static JSBool +Decode(JSContext *cx, JSString *str, const jschar *reservedSet, Value *rval) +{ + size_t length = str->length(); + const jschar *chars = str->getChars(cx); + if (!chars) + return JS_FALSE; + + if (length == 0) { + rval->setString(cx->runtime->emptyString); + return JS_TRUE; + } + + StringBuffer sb(cx); + for (size_t k = 0; k < length; k++) { + jschar c = chars[k]; + if (c == '%') { + size_t start = k; + if ((k + 2) >= length) + goto report_bad_uri; + if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2])) + goto report_bad_uri; + jsuint B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]); + k += 2; + if (!(B & 0x80)) { + c = (jschar)B; + } else { + intN n = 1; + while (B & (0x80 >> n)) + n++; + if (n == 1 || n > 4) + goto report_bad_uri; + uint8 octets[4]; + octets[0] = (uint8)B; + if (k + 3 * (n - 1) >= length) + goto report_bad_uri; + for (intN j = 1; j < n; j++) { + k++; + if (chars[k] != '%') + goto report_bad_uri; + if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2])) + goto report_bad_uri; + B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]); + if ((B & 0xC0) != 0x80) + goto report_bad_uri; + k += 2; + octets[j] = (char)B; + } + uint32 v = Utf8ToOneUcs4Char(octets, n); + if (v >= 0x10000) { + v -= 0x10000; + if (v > 0xFFFFF) + goto report_bad_uri; + c = (jschar)((v & 0x3FF) + 0xDC00); + jschar H = (jschar)((v >> 10) + 0xD800); + if (!sb.append(H)) + return JS_FALSE; + } else { + c = (jschar)v; + } + } + if (js_strchr(reservedSet, c)) { + if (!sb.append(chars + start, k - start + 1)) + return JS_FALSE; + } else { + if (!sb.append(c)) + return JS_FALSE; + } + } else { + if (!sb.append(c)) + return JS_FALSE; + } + } + + return TransferBufferToString(cx, sb, rval); + + report_bad_uri: + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_URI); + /* FALL THROUGH */ + + return JS_FALSE; +} + +static JSBool +str_decodeURI(JSContext *cx, uintN argc, Value *vp) +{ + JSLinearString *str = ArgToRootedString(cx, argc, vp, 0); + if (!str) + return JS_FALSE; + return Decode(cx, str, js_uriReservedPlusPound_ucstr, vp); +} + +static JSBool +str_decodeURI_Component(JSContext *cx, uintN argc, Value *vp) +{ + JSLinearString *str = ArgToRootedString(cx, argc, vp, 0); + if (!str) + return JS_FALSE; + return Decode(cx, str, js_empty_ucstr, vp); +} + +static JSBool +str_encodeURI(JSContext *cx, uintN argc, Value *vp) +{ + JSLinearString *str = ArgToRootedString(cx, argc, vp, 0); + if (!str) + return JS_FALSE; + return Encode(cx, str, js_uriReservedPlusPound_ucstr, js_uriUnescaped_ucstr, + vp); +} + +static JSBool +str_encodeURI_Component(JSContext *cx, uintN argc, Value *vp) +{ + JSLinearString *str = ArgToRootedString(cx, argc, vp, 0); + if (!str) + return JS_FALSE; + return Encode(cx, str, js_uriUnescaped_ucstr, NULL, vp); +} + +/* + * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at + * least 4 bytes long. Return the number of UTF-8 bytes of data written. + */ +int +js_OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char) +{ + int utf8Length = 1; + + JS_ASSERT(ucs4Char <= 0x10FFFF); + if (ucs4Char < 0x80) { + *utf8Buffer = (uint8)ucs4Char; + } else { + int i; + uint32 a = ucs4Char >> 11; + utf8Length = 2; + while (a) { + a >>= 5; + utf8Length++; + } + i = utf8Length; + while (--i) { + utf8Buffer[i] = (uint8)((ucs4Char & 0x3F) | 0x80); + ucs4Char >>= 6; + } + *utf8Buffer = (uint8)(0x100 - (1 << (8-utf8Length)) + ucs4Char); + } + return utf8Length; +} + +/* + * Convert a utf8 character sequence into a UCS-4 character and return that + * character. It is assumed that the caller already checked that the sequence + * is valid. + */ +static uint32 +Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length) +{ + uint32 ucs4Char; + uint32 minucs4Char; + /* from Unicode 3.1, non-shortest form is illegal */ + static const uint32 minucs4Table[] = { + 0x00000080, 0x00000800, 0x00010000 + }; + + JS_ASSERT(utf8Length >= 1 && utf8Length <= 4); + if (utf8Length == 1) { + ucs4Char = *utf8Buffer; + JS_ASSERT(!(ucs4Char & 0x80)); + } else { + JS_ASSERT((*utf8Buffer & (0x100 - (1 << (7-utf8Length)))) == + (0x100 - (1 << (8-utf8Length)))); + ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1); + minucs4Char = minucs4Table[utf8Length-2]; + while (--utf8Length) { + JS_ASSERT((*utf8Buffer & 0xC0) == 0x80); + ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F); + } + if (JS_UNLIKELY(ucs4Char < minucs4Char)) { + ucs4Char = OVERLONG_UTF8; + } else if (ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) { + ucs4Char = 0xFFFD; + } + } + return ucs4Char; +} + +namespace js { + +size_t +PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp, JSLinearString *str, uint32 quote) +{ + enum { + STOP, FIRST_QUOTE, LAST_QUOTE, CHARS, ESCAPE_START, ESCAPE_MORE + } state; + + JS_ASSERT(quote == 0 || quote == '\'' || quote == '"'); + JS_ASSERT_IF(!buffer, bufferSize == 0); + JS_ASSERT_IF(fp, !buffer); + + if (bufferSize == 0) + buffer = NULL; + else + bufferSize--; + + const jschar *chars = str->chars(); + const jschar *charsEnd = chars + str->length(); + size_t n = 0; + state = FIRST_QUOTE; + uintN shift = 0; + uintN hex = 0; + uintN u = 0; + char c = 0; /* to quell GCC warnings */ + + for (;;) { + switch (state) { + case STOP: + goto stop; + case FIRST_QUOTE: + state = CHARS; + goto do_quote; + case LAST_QUOTE: + state = STOP; + do_quote: + if (quote == 0) + continue; + c = (char)quote; + break; + case CHARS: + if (chars == charsEnd) { + state = LAST_QUOTE; + continue; + } + u = *chars++; + if (u < ' ') { + if (u != 0) { + const char *escape = strchr(js_EscapeMap, (int)u); + if (escape) { + u = escape[1]; + goto do_escape; + } + } + goto do_hex_escape; + } + if (u < 127) { + if (u == quote || u == '\\') + goto do_escape; + c = (char)u; + } else if (u < 0x100) { + goto do_hex_escape; + } else { + shift = 16; + hex = u; + u = 'u'; + goto do_escape; + } + break; + do_hex_escape: + shift = 8; + hex = u; + u = 'x'; + do_escape: + c = '\\'; + state = ESCAPE_START; + break; + case ESCAPE_START: + JS_ASSERT(' ' <= u && u < 127); + c = (char)u; + state = ESCAPE_MORE; + break; + case ESCAPE_MORE: + if (shift == 0) { + state = CHARS; + continue; + } + shift -= 4; + u = 0xF & (hex >> shift); + c = (char)(u + (u < 10 ? '0' : 'A' - 10)); + break; + } + if (buffer) { + JS_ASSERT(n <= bufferSize); + if (n != bufferSize) { + buffer[n] = c; + } else { + buffer[n] = '\0'; + buffer = NULL; + } + } else if (fp) { + if (fputc(c, fp) < 0) + return size_t(-1); + } + n++; + } + stop: + if (buffer) + buffer[n] = '\0'; + return n; +} + +} /* namespace js */ diff --git a/js/src/jsstr.h b/js/src/jsstr.h new file mode 100644 index 0000000..275f989 --- /dev/null +++ b/js/src/jsstr.h @@ -0,0 +1,1077 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsstr_h___ +#define jsstr_h___ +/* + * JS string type implementation. + * + * A JS string is a counted array of unicode characters. To support handoff + * of API client memory, the chars are allocated separately from the length, + * necessitating a pointer after the count, to form a separately allocated + * string descriptor. String descriptors are GC'ed, while their chars are + * allocated from the malloc heap. + */ +#include +#include "jsapi.h" +#include "jsprvtd.h" +#include "jshashtable.h" +#include "jslock.h" +#include "jsobj.h" +#include "jsvalue.h" +#include "jscell.h" + +enum { + UNIT_STRING_LIMIT = 256U, + SMALL_CHAR_LIMIT = 128U, /* Bigger chars cannot be in a length-2 string. */ + NUM_SMALL_CHARS = 64U, + INT_STRING_LIMIT = 256U, + NUM_HUNDRED_STRINGS = 156U +}; + +extern jschar * +js_GetDependentStringChars(JSString *str); + +extern JSString * JS_FASTCALL +js_ConcatStrings(JSContext *cx, JSString *left, JSString *right); + +JS_STATIC_ASSERT(JS_BITS_PER_WORD >= 32); + +struct JSRopeBufferInfo { + /* Number of jschars we can hold, not including null terminator. */ + size_t capacity; +}; + +/* Forward declaration for friending. */ +namespace js { namespace mjit { + class Compiler; +}} + +struct JSLinearString; + +/* + * The GC-thing "string" type. + * + * In FLAT strings, the mChars field points to a flat character array owned by + * its GC-thing descriptor. The array is terminated at index length by a zero + * character and the size of the array in bytes is + * (length + 1) * sizeof(jschar). The terminator is purely a backstop, in case + * the chars pointer flows out to native code that requires \u0000 termination. + * + * A flat string with the ATOMIZED flag means that the string is hashed as + * an atom. This flag is used to avoid re-hashing the already-atomized string. + * + * A flat string with the EXTENSIBLE flag means that the string may change into + * a dependent string as part of an optimization with js_ConcatStrings: + * extending |str1 = "abc"| with the character |str2 = str1 + "d"| will place + * "d" in the extra capacity from |str1|, make that the buffer for |str2|, and + * turn |str1| into a dependent string of |str2|. + * + * Flat strings without the EXTENSIBLE flag can be safely accessed by multiple + * threads. + * + * When the string is DEPENDENT, the string depends on characters of another + * string strongly referenced by the base field. The base member may point to + * another dependent string if chars() has not been called yet. + * + * When a string is a ROPE, it represents the lazy concatenation of other + * strings. In general, the nodes reachable from any rope form a dag. + * + * To allow static type-based checking that a given JSString* always points + * to a flat or non-rope string, the JSFlatString and JSLinearString types may + * be used. Instead of casting, callers should use ensureX() and assertIsX(). + */ +struct JSString +{ + friend class js::TraceRecorder; + friend class js::mjit::Compiler; + + friend JSAtom *js_AtomizeString(JSContext *cx, JSString *str, uintN flags); + + /* + * Not private because we want to be able to use static initializers for + * them. Don't use these directly! FIXME bug 614459. + */ + size_t lengthAndFlags; /* in all strings */ + union { + const jschar *chars; /* in non-rope strings */ + JSString *left; /* in rope strings */ + } u; + union { + jschar inlineStorage[4]; /* in short strings */ + struct { + union { + JSString *right; /* in rope strings */ + JSString *base; /* in dependent strings */ + size_t capacity; /* in extensible flat strings */ + }; + union { + JSString *parent; /* temporarily used during flatten */ + size_t reserved; /* may use for bug 615290 */ + }; + } s; + size_t externalStringType; /* in external strings */ + }; + + /* + * The lengthAndFlags field in string headers has data arranged in the + * following way: + * + * [ length (bits 4-31) ][ flags (bits 2-3) ][ type (bits 0-1) ] + * + * The length is packed in lengthAndFlags, even in string types that don't + * need 3 other fields, to make the length check simpler. + * + * When the string type is FLAT, the flags can contain ATOMIZED or + * EXTENSIBLE. + */ + static const size_t TYPE_FLAGS_MASK = JS_BITMASK(4); + static const size_t LENGTH_SHIFT = 4; + + static const size_t TYPE_MASK = JS_BITMASK(2); + static const size_t FLAT = 0x0; + static const size_t DEPENDENT = 0x1; + static const size_t ROPE = 0x2; + + /* Allow checking 1 bit for dependent/rope strings. */ + static const size_t DEPENDENT_BIT = JS_BIT(0); + static const size_t ROPE_BIT = JS_BIT(1); + + static const size_t ATOMIZED = JS_BIT(2); + static const size_t EXTENSIBLE = JS_BIT(3); + + + size_t buildLengthAndFlags(size_t length, size_t flags) { + return (length << LENGTH_SHIFT) | flags; + } + + inline js::gc::Cell *asCell() { + return reinterpret_cast(this); + } + + inline js::gc::FreeCell *asFreeCell() { + return reinterpret_cast(this); + } + + /* + * Generous but sane length bound; the "-1" is there for comptibility with + * OOM tests. + */ + static const size_t MAX_LENGTH = (1 << 28) - 1; + + JS_ALWAYS_INLINE bool isDependent() const { + return lengthAndFlags & DEPENDENT_BIT; + } + + JS_ALWAYS_INLINE bool isFlat() const { + return (lengthAndFlags & TYPE_MASK) == FLAT; + } + + JS_ALWAYS_INLINE bool isExtensible() const { + JS_ASSERT_IF(lengthAndFlags & EXTENSIBLE, isFlat()); + return lengthAndFlags & EXTENSIBLE; + } + + JS_ALWAYS_INLINE bool isAtomized() const { + JS_ASSERT_IF(lengthAndFlags & ATOMIZED, isFlat()); + return lengthAndFlags & ATOMIZED; + } + + JS_ALWAYS_INLINE bool isRope() const { + return lengthAndFlags & ROPE_BIT; + } + + JS_ALWAYS_INLINE size_t length() const { + return lengthAndFlags >> LENGTH_SHIFT; + } + + JS_ALWAYS_INLINE bool empty() const { + return lengthAndFlags <= TYPE_FLAGS_MASK; + } + + /* This can fail by returning null and reporting an error on cx. */ + JS_ALWAYS_INLINE const jschar *getChars(JSContext *cx) { + if (isRope()) + return flatten(cx); + return nonRopeChars(); + } + + /* This can fail by returning null and reporting an error on cx. */ + JS_ALWAYS_INLINE const jschar *getCharsZ(JSContext *cx) { + if (!isFlat()) + return undepend(cx); + return flatChars(); + } + + JS_ALWAYS_INLINE void initFlatNotTerminated(jschar *chars, size_t length) { + JS_ASSERT(length <= MAX_LENGTH); + JS_ASSERT(!isStatic(this)); + lengthAndFlags = buildLengthAndFlags(length, FLAT); + u.chars = chars; + } + + /* Specific flat string initializer and accessor methods. */ + JS_ALWAYS_INLINE void initFlat(jschar *chars, size_t length) { + initFlatNotTerminated(chars, length); + JS_ASSERT(chars[length] == jschar(0)); + } + + JS_ALWAYS_INLINE void initShortString(const jschar *chars, size_t length) { + JS_ASSERT(length <= MAX_LENGTH); + JS_ASSERT(chars >= inlineStorage && chars < (jschar *)(this + 2)); + JS_ASSERT(!isStatic(this)); + lengthAndFlags = buildLengthAndFlags(length, FLAT); + u.chars = chars; + } + + JS_ALWAYS_INLINE void initFlatExtensible(jschar *chars, size_t length, size_t cap) { + JS_ASSERT(length <= MAX_LENGTH); + JS_ASSERT(chars[length] == jschar(0)); + JS_ASSERT(!isStatic(this)); + lengthAndFlags = buildLengthAndFlags(length, FLAT | EXTENSIBLE); + u.chars = chars; + s.capacity = cap; + } + + JS_ALWAYS_INLINE JSFlatString *assertIsFlat() { + JS_ASSERT(isFlat()); + return reinterpret_cast(this); + } + + JS_ALWAYS_INLINE const jschar *flatChars() const { + JS_ASSERT(isFlat()); + return u.chars; + } + + JS_ALWAYS_INLINE size_t flatLength() const { + JS_ASSERT(isFlat()); + return length(); + } + + inline void flatSetAtomized() { + JS_ASSERT(isFlat()); + JS_ASSERT(!isStatic(this)); + lengthAndFlags |= ATOMIZED; + } + + inline void flatClearExtensible() { + /* + * N.B. This may be called on static strings, which may be in read-only + * memory, so we cannot unconditionally apply the mask. + */ + JS_ASSERT(isFlat()); + if (lengthAndFlags & EXTENSIBLE) + lengthAndFlags &= ~EXTENSIBLE; + } + + /* + * The chars pointer should point somewhere inside the buffer owned by base. + * The caller still needs to pass base for GC purposes. + */ + inline void initDependent(JSString *base, const jschar *chars, size_t length) { + JS_ASSERT(!isStatic(this)); + JS_ASSERT(base->isFlat()); + JS_ASSERT(chars >= base->flatChars() && chars < base->flatChars() + base->length()); + JS_ASSERT(length <= base->length() - (chars - base->flatChars())); + lengthAndFlags = buildLengthAndFlags(length, DEPENDENT); + u.chars = chars; + s.base = base; + } + + inline JSLinearString *dependentBase() const { + JS_ASSERT(isDependent()); + return s.base->assertIsLinear(); + } + + JS_ALWAYS_INLINE const jschar *dependentChars() { + JS_ASSERT(isDependent()); + return u.chars; + } + + inline size_t dependentLength() const { + JS_ASSERT(isDependent()); + return length(); + } + + const jschar *undepend(JSContext *cx); + + const jschar *nonRopeChars() const { + JS_ASSERT(!isRope()); + return u.chars; + } + + /* Rope-related initializers and accessors. */ + inline void initRopeNode(JSString *left, JSString *right, size_t length) { + JS_ASSERT(left->length() + right->length() == length); + lengthAndFlags = buildLengthAndFlags(length, ROPE); + u.left = left; + s.right = right; + } + + inline JSString *ropeLeft() const { + JS_ASSERT(isRope()); + return u.left; + } + + inline JSString *ropeRight() const { + JS_ASSERT(isRope()); + return s.right; + } + + inline void finishTraversalConversion(JSString *base, const jschar *baseBegin, const jschar *end) { + JS_ASSERT(baseBegin <= u.chars && u.chars <= end); + lengthAndFlags = buildLengthAndFlags(end - u.chars, DEPENDENT); + s.base = base; + } + + const jschar *flatten(JSContext *maybecx); + + JSLinearString *ensureLinear(JSContext *cx) { + if (isRope() && !flatten(cx)) + return NULL; + return reinterpret_cast(this); + } + + bool isLinear() const { + return !isRope(); + } + + JSLinearString *assertIsLinear() { + JS_ASSERT(isLinear()); + return reinterpret_cast(this); + } + + typedef uint8 SmallChar; + + static inline bool fitsInSmallChar(jschar c) { + return c < SMALL_CHAR_LIMIT && toSmallChar[c] != INVALID_SMALL_CHAR; + } + + static inline bool isUnitString(void *ptr) { + jsuword delta = reinterpret_cast(ptr) - + reinterpret_cast(unitStringTable); + if (delta >= UNIT_STRING_LIMIT * sizeof(JSString)) + return false; + + /* If ptr points inside the static array, it must be well-aligned. */ + JS_ASSERT(delta % sizeof(JSString) == 0); + return true; + } + + static inline bool isLength2String(void *ptr) { + jsuword delta = reinterpret_cast(ptr) - + reinterpret_cast(length2StringTable); + if (delta >= NUM_SMALL_CHARS * NUM_SMALL_CHARS * sizeof(JSString)) + return false; + + /* If ptr points inside the static array, it must be well-aligned. */ + JS_ASSERT(delta % sizeof(JSString) == 0); + return true; + } + + static inline bool isHundredString(void *ptr) { + jsuword delta = reinterpret_cast(ptr) - + reinterpret_cast(hundredStringTable); + if (delta >= NUM_HUNDRED_STRINGS * sizeof(JSString)) + return false; + + /* If ptr points inside the static array, it must be well-aligned. */ + JS_ASSERT(delta % sizeof(JSString) == 0); + return true; + } + + static inline bool isStatic(void *ptr) { + return isUnitString(ptr) || isLength2String(ptr) || isHundredString(ptr); + } + +#ifdef __SUNPRO_CC +#pragma align 8 (__1cIJSStringPunitStringTable_, __1cIJSStringSlength2StringTable_, __1cIJSStringShundredStringTable_) +#endif + + static const SmallChar INVALID_SMALL_CHAR = -1; + + static const jschar fromSmallChar[]; + static const SmallChar toSmallChar[]; + static const JSString unitStringTable[]; + static const JSString length2StringTable[]; + static const JSString hundredStringTable[]; + /* + * Since int strings can be unit strings, length-2 strings, or hundred + * strings, we keep a table to map from integer to the correct string. + */ + static const JSString *const intStringTable[]; + + static JSFlatString *unitString(jschar c); + static JSLinearString *getUnitString(JSContext *cx, JSString *str, size_t index); + static JSFlatString *length2String(jschar c1, jschar c2); + static JSFlatString *length2String(uint32 i); + static JSFlatString *intString(jsint i); + + static JSFlatString *lookupStaticString(const jschar *chars, size_t length); + + JS_ALWAYS_INLINE void finalize(JSContext *cx); + + static size_t offsetOfLengthAndFlags() { + return offsetof(JSString, lengthAndFlags); + } + + static size_t offsetOfChars() { + return offsetof(JSString, u.chars); + } + + static void staticAsserts() { + JS_STATIC_ASSERT(((JSString::MAX_LENGTH << JSString::LENGTH_SHIFT) >> + JSString::LENGTH_SHIFT) == JSString::MAX_LENGTH); + } +}; + +/* + * A "linear" string may or may not be null-terminated, but it provides + * infallible access to a linear array of characters. Namely, this means the + * string is not a rope. + */ +struct JSLinearString : JSString +{ + const jschar *chars() const { return JSString::nonRopeChars(); } +}; + +JS_STATIC_ASSERT(sizeof(JSLinearString) == sizeof(JSString)); + +/* + * A linear string where, additionally, chars()[length()] == '\0'. Namely, this + * means the string is not a dependent string or rope. + */ +struct JSFlatString : JSLinearString +{ + const jschar *charsZ() const { return chars(); } +}; + +JS_STATIC_ASSERT(sizeof(JSFlatString) == sizeof(JSString)); + +/* + * A flat string which has been "atomized", i.e., that is a unique string among + * other atomized strings and therefore allows equality via pointer comparison. + */ +struct JSAtom : JSFlatString +{ +}; + +struct JSExternalString : JSString +{ + static const uintN TYPE_LIMIT = 8; + static JSStringFinalizeOp str_finalizers[TYPE_LIMIT]; + + static intN changeFinalizer(JSStringFinalizeOp oldop, + JSStringFinalizeOp newop) { + for (uintN i = 0; i != JS_ARRAY_LENGTH(str_finalizers); i++) { + if (str_finalizers[i] == oldop) { + str_finalizers[i] = newop; + return intN(i); + } + } + return -1; + } + + void finalize(JSContext *cx); + void finalize(); +}; + +JS_STATIC_ASSERT(sizeof(JSString) == sizeof(JSExternalString)); + +/* + * Short strings should be created in cases where it's worthwhile to avoid + * mallocing the string buffer for a small string. We keep 2 string headers' + * worth of space in short strings so that more strings can be stored this way. + */ +class JSShortString : public js::gc::Cell +{ + JSString mHeader; + JSString mDummy; + + public: + /* + * Set the length of the string, and return a buffer for the caller to write + * to. This buffer must be written immediately, and should not be modified + * afterward. + */ + inline jschar *init(size_t length) { + JS_ASSERT(length <= MAX_SHORT_STRING_LENGTH); + mHeader.initShortString(mHeader.inlineStorage, length); + return mHeader.inlineStorage; + } + + inline jschar *getInlineStorageBeforeInit() { + return mHeader.inlineStorage; + } + + inline void initAtOffsetInBuffer(jschar *p, size_t length) { + JS_ASSERT(p >= mHeader.inlineStorage && p < mHeader.inlineStorage + MAX_SHORT_STRING_LENGTH); + mHeader.initShortString(p, length); + } + + inline void resetLength(size_t length) { + mHeader.initShortString(mHeader.flatChars(), length); + } + + inline JSString *header() { + return &mHeader; + } + + static const size_t FREE_STRING_WORDS = 2; + + static const size_t MAX_SHORT_STRING_LENGTH = + ((sizeof(JSString) + FREE_STRING_WORDS * sizeof(size_t)) / sizeof(jschar)) - 1; + + static inline bool fitsIntoShortString(size_t length) { + return length <= MAX_SHORT_STRING_LENGTH; + } + + JS_ALWAYS_INLINE void finalize(JSContext *cx); + + static void staticAsserts() { + JS_STATIC_ASSERT(offsetof(JSString, inlineStorage) == + sizeof(JSString) - JSShortString::FREE_STRING_WORDS * sizeof(void *)); + JS_STATIC_ASSERT(offsetof(JSShortString, mDummy) == sizeof(JSString)); + JS_STATIC_ASSERT(offsetof(JSString, inlineStorage) + + sizeof(jschar) * (JSShortString::MAX_SHORT_STRING_LENGTH + 1) == + sizeof(JSShortString)); + } +}; + +namespace js { + +class StringBuffer; + +/* + * When an algorithm does not need a string represented as a single linear + * array of characters, this range utility may be used to traverse the string a + * sequence of linear arrays of characters. This avoids flattening ropes. + * + * Implemented in jsstrinlines.h. + */ +class StringSegmentRange; +class MutatingRopeSegmentRange; + +/* + * Utility for building a rope (lazy concatenation) of strings. + */ +class RopeBuilder; + +} /* namespace js */ + +extern const jschar * +js_GetStringChars(JSContext *cx, JSString *str); + +extern const jschar * +js_UndependString(JSContext *cx, JSString *str); + +extern JSBool +js_MakeStringImmutable(JSContext *cx, JSString *str); + +extern JSString * JS_FASTCALL +js_toLowerCase(JSContext *cx, JSString *str); + +extern JSString * JS_FASTCALL +js_toUpperCase(JSContext *cx, JSString *str); + +struct JSSubString { + size_t length; + const jschar *chars; +}; + +extern jschar js_empty_ucstr[]; +extern JSSubString js_EmptySubString; + +/* Unicode character attribute lookup tables. */ +extern const uint8 js_X[]; +extern const uint8 js_Y[]; +extern const uint32 js_A[]; + +/* Enumerated Unicode general category types. */ +typedef enum JSCharType { + JSCT_UNASSIGNED = 0, + JSCT_UPPERCASE_LETTER = 1, + JSCT_LOWERCASE_LETTER = 2, + JSCT_TITLECASE_LETTER = 3, + JSCT_MODIFIER_LETTER = 4, + JSCT_OTHER_LETTER = 5, + JSCT_NON_SPACING_MARK = 6, + JSCT_ENCLOSING_MARK = 7, + JSCT_COMBINING_SPACING_MARK = 8, + JSCT_DECIMAL_DIGIT_NUMBER = 9, + JSCT_LETTER_NUMBER = 10, + JSCT_OTHER_NUMBER = 11, + JSCT_SPACE_SEPARATOR = 12, + JSCT_LINE_SEPARATOR = 13, + JSCT_PARAGRAPH_SEPARATOR = 14, + JSCT_CONTROL = 15, + JSCT_FORMAT = 16, + JSCT_PRIVATE_USE = 18, + JSCT_SURROGATE = 19, + JSCT_DASH_PUNCTUATION = 20, + JSCT_START_PUNCTUATION = 21, + JSCT_END_PUNCTUATION = 22, + JSCT_CONNECTOR_PUNCTUATION = 23, + JSCT_OTHER_PUNCTUATION = 24, + JSCT_MATH_SYMBOL = 25, + JSCT_CURRENCY_SYMBOL = 26, + JSCT_MODIFIER_SYMBOL = 27, + JSCT_OTHER_SYMBOL = 28 +} JSCharType; + +/* Character classifying and mapping macros, based on java.lang.Character. */ +#define JS_CCODE(c) (js_A[js_Y[(js_X[(uint16)(c)>>6]<<6)|((c)&0x3F)]]) +#define JS_CTYPE(c) (JS_CCODE(c) & 0x1F) + +#define JS_ISALPHA(c) ((((1 << JSCT_UPPERCASE_LETTER) | \ + (1 << JSCT_LOWERCASE_LETTER) | \ + (1 << JSCT_TITLECASE_LETTER) | \ + (1 << JSCT_MODIFIER_LETTER) | \ + (1 << JSCT_OTHER_LETTER)) \ + >> JS_CTYPE(c)) & 1) + +#define JS_ISALNUM(c) ((((1 << JSCT_UPPERCASE_LETTER) | \ + (1 << JSCT_LOWERCASE_LETTER) | \ + (1 << JSCT_TITLECASE_LETTER) | \ + (1 << JSCT_MODIFIER_LETTER) | \ + (1 << JSCT_OTHER_LETTER) | \ + (1 << JSCT_DECIMAL_DIGIT_NUMBER)) \ + >> JS_CTYPE(c)) & 1) + +/* A unicode letter, suitable for use in an identifier. */ +#define JS_ISLETTER(c) ((((1 << JSCT_UPPERCASE_LETTER) | \ + (1 << JSCT_LOWERCASE_LETTER) | \ + (1 << JSCT_TITLECASE_LETTER) | \ + (1 << JSCT_MODIFIER_LETTER) | \ + (1 << JSCT_OTHER_LETTER) | \ + (1 << JSCT_LETTER_NUMBER)) \ + >> JS_CTYPE(c)) & 1) + +/* + * 'IdentifierPart' from ECMA grammar, is Unicode letter or combining mark or + * digit or connector punctuation. + */ +#define JS_ISIDPART(c) ((((1 << JSCT_UPPERCASE_LETTER) | \ + (1 << JSCT_LOWERCASE_LETTER) | \ + (1 << JSCT_TITLECASE_LETTER) | \ + (1 << JSCT_MODIFIER_LETTER) | \ + (1 << JSCT_OTHER_LETTER) | \ + (1 << JSCT_LETTER_NUMBER) | \ + (1 << JSCT_NON_SPACING_MARK) | \ + (1 << JSCT_COMBINING_SPACING_MARK) | \ + (1 << JSCT_DECIMAL_DIGIT_NUMBER) | \ + (1 << JSCT_CONNECTOR_PUNCTUATION)) \ + >> JS_CTYPE(c)) & 1) + +/* Unicode control-format characters, ignored in input */ +#define JS_ISFORMAT(c) (((1 << JSCT_FORMAT) >> JS_CTYPE(c)) & 1) + +/* + * This table is used in JS_ISWORD. The definition has external linkage to + * allow the raw table data to be used in the regular expression compiler. + */ +extern const bool js_alnum[]; + +/* + * This macro performs testing for the regular expression word class \w, which + * is defined by ECMA-262 15.10.2.6 to be [0-9A-Z_a-z]. If we want a + * Unicode-friendlier definition of "word", we should rename this macro to + * something regexp-y. + */ +#define JS_ISWORD(c) ((c) < 128 && js_alnum[(c)]) + +#define JS_ISIDSTART(c) (JS_ISLETTER(c) || (c) == '_' || (c) == '$') +#define JS_ISIDENT(c) (JS_ISIDPART(c) || (c) == '_' || (c) == '$') + +#define JS_ISXMLSPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || \ + (c) == '\n') +#define JS_ISXMLNSSTART(c) ((JS_CCODE(c) & 0x00000100) || (c) == '_') +#define JS_ISXMLNS(c) ((JS_CCODE(c) & 0x00000080) || (c) == '.' || \ + (c) == '-' || (c) == '_') +#define JS_ISXMLNAMESTART(c) (JS_ISXMLNSSTART(c) || (c) == ':') +#define JS_ISXMLNAME(c) (JS_ISXMLNS(c) || (c) == ':') + +#define JS_ISDIGIT(c) (JS_CTYPE(c) == JSCT_DECIMAL_DIGIT_NUMBER) + +const jschar BYTE_ORDER_MARK = 0xFEFF; +const jschar NO_BREAK_SPACE = 0x00A0; + +static inline bool +JS_ISSPACE(jschar c) +{ + unsigned w = c; + + if (w < 256) + return (w <= ' ' && (w == ' ' || (9 <= w && w <= 0xD))) || w == NO_BREAK_SPACE; + + return w == BYTE_ORDER_MARK || (JS_CCODE(w) & 0x00070000) == 0x00040000; +} + +#define JS_ISPRINT(c) ((c) < 128 && isprint(c)) + +#define JS_ISUPPER(c) (JS_CTYPE(c) == JSCT_UPPERCASE_LETTER) +#define JS_ISLOWER(c) (JS_CTYPE(c) == JSCT_LOWERCASE_LETTER) + +#define JS_TOUPPER(c) ((jschar) ((JS_CCODE(c) & 0x00100000) \ + ? (c) - ((int32)JS_CCODE(c) >> 22) \ + : (c))) +#define JS_TOLOWER(c) ((jschar) ((JS_CCODE(c) & 0x00200000) \ + ? (c) + ((int32)JS_CCODE(c) >> 22) \ + : (c))) + +/* + * Shorthands for ASCII (7-bit) decimal and hex conversion. + * Manually inline isdigit for performance; MSVC doesn't do this for us. + */ +#define JS7_ISDEC(c) ((((unsigned)(c)) - '0') <= 9) +#define JS7_UNDEC(c) ((c) - '0') +#define JS7_ISHEX(c) ((c) < 128 && isxdigit(c)) +#define JS7_UNHEX(c) (uintN)(JS7_ISDEC(c) ? (c) - '0' : 10 + tolower(c) - 'a') +#define JS7_ISLET(c) ((c) < 128 && isalpha(c)) + +/* Initialize the String class, returning its prototype object. */ +extern js::Class js_StringClass; + +inline bool +JSObject::isString() const +{ + return getClass() == &js_StringClass; +} + +extern JSObject * +js_InitStringClass(JSContext *cx, JSObject *obj); + +extern const char js_escape_str[]; +extern const char js_unescape_str[]; +extern const char js_uneval_str[]; +extern const char js_decodeURI_str[]; +extern const char js_encodeURI_str[]; +extern const char js_decodeURIComponent_str[]; +extern const char js_encodeURIComponent_str[]; + +/* GC-allocate a string descriptor for the given malloc-allocated chars. */ +extern JSFlatString * +js_NewString(JSContext *cx, jschar *chars, size_t length); + +extern JSLinearString * +js_NewDependentString(JSContext *cx, JSString *base, size_t start, + size_t length); + +/* Copy a counted string and GC-allocate a descriptor for it. */ +extern JSFlatString * +js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n); + +extern JSFlatString * +js_NewStringCopyN(JSContext *cx, const char *s, size_t n); + +/* Copy a C string and GC-allocate a descriptor for it. */ +extern JSFlatString * +js_NewStringCopyZ(JSContext *cx, const jschar *s); + +extern JSFlatString * +js_NewStringCopyZ(JSContext *cx, const char *s); + +/* + * Convert a value to a printable C string. + */ +extern const char * +js_ValueToPrintable(JSContext *cx, const js::Value &, + JSAutoByteString *bytes, bool asSource = false); + +/* + * Convert a value to a string, returning null after reporting an error, + * otherwise returning a new string reference. + */ +extern JSString * +js_ValueToString(JSContext *cx, const js::Value &v); + +namespace js { + +/* + * Most code that calls js_ValueToString knows the value is (probably) not a + * string, so it does not make sense to put this inline fast path into + * js_ValueToString. + */ +static JS_ALWAYS_INLINE JSString * +ValueToString_TestForStringInline(JSContext *cx, const Value &v) +{ + if (v.isString()) + return v.toString(); + return js_ValueToString(cx, v); +} + +/* + * This function implements E-262-3 section 9.8, toString. Convert the given + * value to a string of jschars appended to the given buffer. On error, the + * passed buffer may have partial results appended. + */ +extern bool +ValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb); + +} /* namespace js */ + +/* + * Convert a value to its source expression, returning null after reporting + * an error, otherwise returning a new string reference. + */ +extern JS_FRIEND_API(JSString *) +js_ValueToSource(JSContext *cx, const js::Value &v); + +/* + * Compute a hash function from str. The caller can call this function even if + * str is not a GC-allocated thing. + */ +inline uint32 +js_HashString(JSLinearString *str) +{ + const jschar *s = str->chars(); + size_t n = str->length(); + uint32 h; + for (h = 0; n; s++, n--) + h = JS_ROTATE_LEFT32(h, 4) ^ *s; + return h; +} + +namespace js { + +/* + * Test if strings are equal. The caller can call the function even if str1 + * or str2 are not GC-allocated things. + */ +extern bool +EqualStrings(JSContext *cx, JSString *str1, JSString *str2, JSBool *result); + +/* EqualStrings is infallible on linear strings. */ +extern bool +EqualStrings(JSLinearString *str1, JSLinearString *str2); + +/* + * Return less than, equal to, or greater than zero depending on whether + * str1 is less than, equal to, or greater than str2. + */ +extern bool +CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result); + +/* + * Return true if the string matches the given sequence of ASCII bytes. + */ +extern bool +StringEqualsAscii(JSLinearString *str, const char *asciiBytes); + +} /* namespacejs */ + +/* + * Boyer-Moore-Horspool superlinear search for pat:patlen in text:textlen. + * The patlen argument must be positive and no greater than sBMHPatLenMax. + * + * Return the index of pat in text, or -1 if not found. + */ +static const jsuint sBMHCharSetSize = 256; /* ISO-Latin-1 */ +static const jsuint sBMHPatLenMax = 255; /* skip table element is uint8 */ +static const jsint sBMHBadPattern = -2; /* return value if pat is not ISO-Latin-1 */ + +extern jsint +js_BoyerMooreHorspool(const jschar *text, jsuint textlen, + const jschar *pat, jsuint patlen); + +extern size_t +js_strlen(const jschar *s); + +extern jschar * +js_strchr(const jschar *s, jschar c); + +extern jschar * +js_strchr_limit(const jschar *s, jschar c, const jschar *limit); + +#define js_strncpy(t, s, n) memcpy((t), (s), (n) * sizeof(jschar)) + +inline void +js_short_strncpy(jschar *dest, const jschar *src, size_t num) +{ + /* + * It isn't strictly necessary here for |num| to be small, but this function + * is currently only called on buffers for short strings. + */ + JS_ASSERT(JSShortString::fitsIntoShortString(num)); + for (size_t i = 0; i < num; i++) + dest[i] = src[i]; +} + +/* + * Return s advanced past any Unicode white space characters. + */ +static inline const jschar * +js_SkipWhiteSpace(const jschar *s, const jschar *end) +{ + JS_ASSERT(s <= end); + while (s != end && JS_ISSPACE(*s)) + s++; + return s; +} + +/* + * Inflate bytes to JS chars and vice versa. Report out of memory via cx and + * return null on error, otherwise return the jschar or byte vector that was + * JS_malloc'ed. length is updated to the length of the new string in jschars. + */ +extern jschar * +js_InflateString(JSContext *cx, const char *bytes, size_t *length); + +extern char * +js_DeflateString(JSContext *cx, const jschar *chars, size_t length); + +/* + * Inflate bytes to JS chars into a buffer. 'chars' must be large enough for + * 'length' jschars. The buffer is NOT null-terminated. The destination length + * must be be initialized with the buffer size and will contain on return the + * number of copied chars. Conversion behavior depends on js_CStringsAreUTF8. + */ +extern JSBool +js_InflateStringToBuffer(JSContext *cx, const char *bytes, size_t length, + jschar *chars, size_t *charsLength); + +/* + * Same as js_InflateStringToBuffer, but always treats 'bytes' as UTF-8. + */ +extern JSBool +js_InflateUTF8StringToBuffer(JSContext *cx, const char *bytes, size_t length, + jschar *chars, size_t *charsLength); + +/* + * Get number of bytes in the deflated sequence of characters. Behavior depends + * on js_CStringsAreUTF8. + */ +extern size_t +js_GetDeflatedStringLength(JSContext *cx, const jschar *chars, + size_t charsLength); + +/* + * Same as js_GetDeflatedStringLength, but always treats the result as UTF-8. + */ +extern size_t +js_GetDeflatedUTF8StringLength(JSContext *cx, const jschar *chars, + size_t charsLength); + +/* + * Deflate JS chars to bytes into a buffer. 'bytes' must be large enough for + * 'length chars. The buffer is NOT null-terminated. The destination length + * must to be initialized with the buffer size and will contain on return the + * number of copied bytes. Conversion behavior depends on js_CStringsAreUTF8. + */ +extern JSBool +js_DeflateStringToBuffer(JSContext *cx, const jschar *chars, + size_t charsLength, char *bytes, size_t *length); + +/* + * Same as js_DeflateStringToBuffer, but always treats 'bytes' as UTF-8. + */ +extern JSBool +js_DeflateStringToUTF8Buffer(JSContext *cx, const jschar *chars, + size_t charsLength, char *bytes, size_t *length); + +/* Export a few natives and a helper to other files in SpiderMonkey. */ +extern JSBool +js_str_escape(JSContext *cx, uintN argc, js::Value *argv, js::Value *rval); + +/* + * The String.prototype.replace fast-native entry point is exported for joined + * function optimization in js{interp,tracer}.cpp. + */ +namespace js { +extern JSBool +str_replace(JSContext *cx, uintN argc, js::Value *vp); +} + +extern JSBool +js_str_toString(JSContext *cx, uintN argc, js::Value *vp); + +extern JSBool +js_str_charAt(JSContext *cx, uintN argc, js::Value *vp); + +extern JSBool +js_str_charCodeAt(JSContext *cx, uintN argc, js::Value *vp); + +/* + * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at + * least 6 bytes long. Return the number of UTF-8 bytes of data written. + */ +extern int +js_OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char); + +namespace js { + +extern size_t +PutEscapedStringImpl(char *buffer, size_t size, FILE *fp, JSLinearString *str, uint32 quote); + +/* + * Write str into buffer escaping any non-printable or non-ASCII character + * using \escapes for JS string literals. + * Guarantees that a NUL is at the end of the buffer unless size is 0. Returns + * the length of the written output, NOT including the NUL. Thus, a return + * value of size or more means that the output was truncated. If buffer + * is null, just returns the length of the output. If quote is not 0, it must + * be a single or double quote character that will quote the output. +*/ +inline size_t +PutEscapedString(char *buffer, size_t size, JSLinearString *str, uint32 quote) +{ + size_t n = PutEscapedStringImpl(buffer, size, NULL, str, quote); + + /* PutEscapedStringImpl can only fail with a file. */ + JS_ASSERT(n != size_t(-1)); + return n; +} + +/* + * Write str into file escaping any non-printable or non-ASCII character. + * If quote is not 0, it must be a single or double quote character that + * will quote the output. +*/ +inline bool +FileEscapedString(FILE *fp, JSLinearString *str, uint32 quote) +{ + return PutEscapedStringImpl(NULL, 0, fp, str, quote) != size_t(-1); +} + +} /* namespace js */ + +extern JSBool +js_String(JSContext *cx, uintN argc, js::Value *vp); + +#endif /* jsstr_h___ */ diff --git a/js/src/jsstrinlines.h b/js/src/jsstrinlines.h new file mode 100644 index 0000000..8742df3 --- /dev/null +++ b/js/src/jsstrinlines.h @@ -0,0 +1,423 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsstrinlines_h___ +#define jsstrinlines_h___ + +#include "jsstr.h" +#include "jscntxtinlines.h" + +namespace js { + +static inline bool +CheckStringLength(JSContext *cx, size_t length) +{ + if (JS_UNLIKELY(length > JSString::MAX_LENGTH)) { + js_ReportAllocationOverflow(cx); + return false; + } + + return true; +} + +/* + * String builder that eagerly checks for over-allocation past the maximum + * string length. + * + * Note: over-allocation is not checked for when using the infallible + * |replaceRawBuffer|, so the implementation of |finishString| also must check + * for over-allocation. + */ +class StringBuffer +{ + typedef Vector CharBuffer; + CharBuffer cb; + + static inline bool checkLength(JSContext *cx, size_t length); + inline bool checkLength(size_t length); + JSContext *context() const { return cb.allocPolicy().context(); } + + public: + explicit inline StringBuffer(JSContext *cx); + bool reserve(size_t len); + bool resize(size_t len); + bool append(const jschar c); + bool append(const jschar *chars, size_t len); + bool append(const jschar *begin, const jschar *end); + bool append(JSString *str); + bool append(JSAtom *atom); + bool appendN(const jschar c, size_t n); + bool appendInflated(const char *cstr, size_t len); + JSAtom *atomize(uintN flags = 0); + static JSAtom *atomize(JSContext *cx, const CharBuffer &cb, uintN flags = 0); + static JSAtom *atomize(JSContext *cx, const jschar *begin, size_t length, uintN flags = 0); + + void replaceRawBuffer(jschar *chars, size_t len) { cb.replaceRawBuffer(chars, len); } + jschar *begin() { return cb.begin(); } + jschar *end() { return cb.end(); } + const jschar *begin() const { return cb.begin(); } + const jschar *end() const { return cb.end(); } + bool empty() const { return cb.empty(); } + inline jsint length() const; + + /* + * Produces a string, resetting the buffer to an empty state. + * This method takes responsibility for adding the terminating '\0' + * required by js_NewString. + */ + JSFlatString *finishString(); + + template + bool append(const char (&array)[ArrayLength]) { + return cb.append(array, array + ArrayLength - 1); /* No trailing '\0'. */ + } +}; + +inline +StringBuffer::StringBuffer(JSContext *cx) + : cb(cx) +{} + +inline bool +StringBuffer::reserve(size_t len) +{ + if (!checkLength(len)) + return false; + return cb.reserve(len); +} + +inline bool +StringBuffer::resize(size_t len) +{ + if (!checkLength(len)) + return false; + return cb.resize(len); +} + +inline bool +StringBuffer::append(const jschar c) +{ + if (!checkLength(cb.length() + 1)) + return false; + return cb.append(c); +} + +inline bool +StringBuffer::append(const jschar *chars, size_t len) +{ + if (!checkLength(cb.length() + len)) + return false; + return cb.append(chars, len); +} + +inline bool +StringBuffer::append(const jschar *begin, const jschar *end) +{ + if (!checkLength(cb.length() + (end - begin))) + return false; + return cb.append(begin, end); +} + +inline bool +StringBuffer::append(JSString *str) +{ + JSLinearString *linear = str->ensureLinear(context()); + size_t strLen = linear->length(); + if (!checkLength(cb.length() + strLen)) + return false; + return cb.append(linear->chars(), strLen); +} + +inline bool +StringBuffer::append(JSAtom *atom) +{ + size_t strLen = atom->length(); + if (!checkLength(cb.length() + strLen)) + return false; + return cb.append(atom->chars(), strLen); +} + +inline bool +StringBuffer::appendN(const jschar c, size_t n) +{ + if (!checkLength(cb.length() + n)) + return false; + return cb.appendN(c, n); +} + +inline bool +StringBuffer::appendInflated(const char *cstr, size_t cstrlen) +{ + size_t lengthBefore = length(); + if (!cb.growByUninitialized(cstrlen)) + return false; +#if DEBUG + size_t oldcstrlen = cstrlen; + bool ok = +#endif + js_InflateStringToBuffer(context(), cstr, cstrlen, begin() + lengthBefore, &cstrlen); + JS_ASSERT(ok && oldcstrlen == cstrlen); + return true; +} + +inline jsint +StringBuffer::length() const +{ + JS_STATIC_ASSERT(jsint(JSString::MAX_LENGTH) == JSString::MAX_LENGTH); + JS_ASSERT(cb.length() <= JSString::MAX_LENGTH); + return jsint(cb.length()); +} + +inline bool +StringBuffer::checkLength(size_t length) +{ + return CheckStringLength(context(), length); +} + +} /* namespace js */ + +inline JSFlatString * +JSString::unitString(jschar c) +{ + JS_ASSERT(c < UNIT_STRING_LIMIT); + return const_cast(&unitStringTable[c])->assertIsFlat(); +} + +inline JSLinearString * +JSString::getUnitString(JSContext *cx, JSString *str, size_t index) +{ + JS_ASSERT(index < str->length()); + const jschar *chars = str->getChars(cx); + if (!chars) + return NULL; + jschar c = chars[index]; + if (c < UNIT_STRING_LIMIT) + return unitString(c); + return js_NewDependentString(cx, str, index, 1); +} + +inline JSFlatString * +JSString::length2String(jschar c1, jschar c2) +{ + JS_ASSERT(fitsInSmallChar(c1)); + JS_ASSERT(fitsInSmallChar(c2)); + return const_cast ( + &length2StringTable[(((size_t)toSmallChar[c1]) << 6) + toSmallChar[c2]] + )->assertIsFlat(); +} + +inline JSFlatString * +JSString::length2String(uint32 i) +{ + JS_ASSERT(i < 100); + return length2String('0' + i / 10, '0' + i % 10); +} + +inline JSFlatString * +JSString::intString(jsint i) +{ + jsuint u = jsuint(i); + JS_ASSERT(u < INT_STRING_LIMIT); + return const_cast(JSString::intStringTable[u])->assertIsFlat(); +} + +/* Get a static atomized string for chars if possible. */ +inline JSFlatString * +JSString::lookupStaticString(const jschar *chars, size_t length) +{ + if (length == 1) { + if (chars[0] < UNIT_STRING_LIMIT) + return unitString(chars[0]); + } + + if (length == 2) { + if (fitsInSmallChar(chars[0]) && fitsInSmallChar(chars[1])) + return length2String(chars[0], chars[1]); + } + + /* + * Here we know that JSString::intStringTable covers only 256 (or at least + * not 1000 or more) chars. We rely on order here to resolve the unit vs. + * int string/length-2 string atom identity issue by giving priority to unit + * strings for "0" through "9" and length-2 strings for "10" through "99". + */ + JS_STATIC_ASSERT(INT_STRING_LIMIT <= 999); + if (length == 3) { + if ('1' <= chars[0] && chars[0] <= '9' && + '0' <= chars[1] && chars[1] <= '9' && + '0' <= chars[2] && chars[2] <= '9') { + jsint i = (chars[0] - '0') * 100 + + (chars[1] - '0') * 10 + + (chars[2] - '0'); + + if (jsuint(i) < INT_STRING_LIMIT) + return intString(i); + } + } + + return NULL; +} + +inline void +JSString::finalize(JSContext *cx) { + JS_ASSERT(!JSString::isStatic(this)); + JS_RUNTIME_UNMETER(cx->runtime, liveStrings); + if (isDependent()) { + JS_RUNTIME_UNMETER(cx->runtime, liveDependentStrings); + } else if (isFlat()) { + /* + * flatChars for stillborn string is null, but cx->free checks + * for a null pointer on its own. + */ + cx->runtime->stringMemoryUsed -= length() * 2; + cx->free(const_cast(flatChars())); + } +} + +inline void +JSShortString::finalize(JSContext *cx) +{ + JS_ASSERT(!JSString::isStatic(&mHeader)); + JS_ASSERT(mHeader.isFlat()); + JS_RUNTIME_UNMETER(cx->runtime, liveStrings); +} + +inline void +JSExternalString::finalize(JSContext *cx) +{ + JS_ASSERT(unsigned(externalStringType) < JS_ARRAY_LENGTH(str_finalizers)); + JS_ASSERT(!isStatic(this)); + JS_ASSERT(isFlat()); + JS_RUNTIME_UNMETER(cx->runtime, liveStrings); + + /* A stillborn string has null chars. */ + jschar *chars = const_cast(flatChars()); + if (!chars) + return; + JSStringFinalizeOp finalizer = str_finalizers[externalStringType]; + if (finalizer) + finalizer(cx, this); +} + +inline void +JSExternalString::finalize() +{ + JS_ASSERT(unsigned(externalStringType) < JS_ARRAY_LENGTH(str_finalizers)); + JSStringFinalizeOp finalizer = str_finalizers[externalStringType]; + if (finalizer) { + /* + * Assume that the finalizer for the permanently interned + * string knows how to deal with null context. + */ + finalizer(NULL, this); + } +} + +namespace js { + +class RopeBuilder { + JSContext *cx; + JSString *res; + + public: + RopeBuilder(JSContext *cx) + : cx(cx), res(cx->runtime->emptyString) + {} + + inline bool append(JSString *str) { + res = js_ConcatStrings(cx, res, str); + return !!res; + } + + inline JSString *result() { + return res; + } +}; + +class StringSegmentRange +{ + /* + * If malloc() shows up in any profiles from this vector, we can add a new + * StackAllocPolicy which stashes a reusable freed-at-gc buffer in the cx. + */ + Vector stack; + JSString *cur; + + bool settle(JSString *str) { + while (str->isRope()) { + if (!stack.append(str->ropeRight())) + return false; + str = str->ropeLeft(); + } + cur = str; + return true; + } + + public: + StringSegmentRange(JSContext *cx) + : stack(cx), cur(NULL) + {} + + JS_WARN_UNUSED_RESULT bool init(JSString *str) { + JS_ASSERT(stack.empty()); + return settle(str); + } + + bool empty() const { + return cur == NULL; + } + + JSString *front() const { + JS_ASSERT(!cur->isRope()); + return cur; + } + + JS_WARN_UNUSED_RESULT bool popFront() { + JS_ASSERT(!empty()); + if (stack.empty()) { + cur = NULL; + return true; + } + return settle(stack.popCopy()); + } +}; + +} /* namespace js */ + +#endif /* jsstrinlines_h___ */ diff --git a/js/src/jstl.h b/js/src/jstl.h new file mode 100644 index 0000000..36e90f1 --- /dev/null +++ b/js/src/jstl.h @@ -0,0 +1,495 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * July 16, 2009. + * + * The Initial Developer of the Original Code is + * the Mozilla Corporation. + * + * Contributor(s): + * Luke Wagner + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jstl_h_ +#define jstl_h_ + +#include "jsbit.h" +#include "jsstaticcheck.h" + +#include +#include + +/* Gross special case for Gecko, which defines malloc/calloc/free. */ +#ifdef mozilla_mozalloc_macro_wrappers_h +# define JSSTL_UNDEFD_MOZALLOC_WRAPPERS +/* The "anti-header" */ +# include "mozilla/mozalloc_undef_macro_wrappers.h" +#endif + +namespace js { + +/* JavaScript Template Library. */ +namespace tl { + +/* Compute min/max/clamp. */ +template struct Min { + static const size_t result = i < j ? i : j; +}; +template struct Max { + static const size_t result = i > j ? i : j; +}; +template struct Clamp { + static const size_t result = i < min ? min : (i > max ? max : i); +}; + +/* Compute x^y. */ +template struct Pow { + static const size_t result = x * Pow::result; +}; +template struct Pow { + static const size_t result = 1; +}; + +/* Compute floor(log2(i)). */ +template struct FloorLog2 { + static const size_t result = 1 + FloorLog2::result; +}; +template <> struct FloorLog2<0> { /* Error */ }; +template <> struct FloorLog2<1> { static const size_t result = 0; }; + +/* Compute ceiling(log2(i)). */ +template struct CeilingLog2 { + static const size_t result = FloorLog2<2 * i - 1>::result; +}; + +/* Round up to the nearest power of 2. */ +template struct RoundUpPow2 { + static const size_t result = 1u << CeilingLog2::result; +}; +template <> struct RoundUpPow2<0> { + static const size_t result = 1; +}; + +/* Compute the number of bits in the given unsigned type. */ +template struct BitSize { + static const size_t result = sizeof(T) * JS_BITS_PER_BYTE; +}; + +/* Allow Assertions by only including the 'result' typedef if 'true'. */ +template struct StaticAssert {}; +template <> struct StaticAssert { typedef int result; }; + +/* Boolean test for whether two types are the same. */ +template struct IsSameType { + static const bool result = false; +}; +template struct IsSameType { + static const bool result = true; +}; + +/* + * Produce an N-bit mask, where N <= BitSize::result. Handle the + * language-undefined edge case when N = BitSize::result. + */ +template struct NBitMask { + typedef typename StaticAssert::result>::result _; + static const size_t result = (size_t(1) << N) - 1; +}; +template <> struct NBitMask::result> { + static const size_t result = size_t(-1); +}; + +/* + * For the unsigned integral type size_t, compute a mask M for N such that + * for all X, !(X & M) implies X * N will not overflow (w.r.t size_t) + */ +template struct MulOverflowMask { + static const size_t result = + ~NBitMask::result - CeilingLog2::result>::result; +}; +template <> struct MulOverflowMask<0> { /* Error */ }; +template <> struct MulOverflowMask<1> { static const size_t result = 0; }; + +/* + * Generate a mask for T such that if (X & sUnsafeRangeSizeMask), an X-sized + * array of T's is big enough to cause a ptrdiff_t overflow when subtracting + * a pointer to the end of the array from the beginning. + */ +template struct UnsafeRangeSizeMask { + /* + * The '2' factor means the top bit is clear, sizeof(T) converts from + * units of elements to bytes. + */ + static const size_t result = MulOverflowMask<2 * sizeof(T)>::result; +}; + +/* Return T stripped of any const-ness. */ +template struct StripConst { typedef T result; }; +template struct StripConst { typedef T result; }; + +/* + * Traits class for identifying POD types. Until C++0x, there is no automatic + * way to detect PODs, so for the moment it is done manually. + */ +template struct IsPodType { static const bool result = false; }; +template <> struct IsPodType { static const bool result = true; }; +template <> struct IsPodType { static const bool result = true; }; +template <> struct IsPodType { static const bool result = true; }; +template <> struct IsPodType { static const bool result = true; }; +template <> struct IsPodType { static const bool result = true; }; +template <> struct IsPodType { static const bool result = true; }; +template <> struct IsPodType { static const bool result = true; }; +template <> struct IsPodType { static const bool result = true; }; +template <> struct IsPodType { static const bool result = true; }; +template <> struct IsPodType { static const bool result = true; }; +template <> struct IsPodType { static const bool result = true; }; + +/* Return the size/end of an array without using macros. */ +template inline T *ArraySize(T (&)[N]) { return N; } +template inline T *ArrayEnd(T (&arr)[N]) { return arr + N; } + +} /* namespace tl */ + +/* Useful for implementing containers that assert non-reentrancy */ +class ReentrancyGuard +{ + /* ReentrancyGuard is not copyable. */ + ReentrancyGuard(const ReentrancyGuard &); + void operator=(const ReentrancyGuard &); + +#ifdef DEBUG + bool &entered; +#endif + public: + template +#ifdef DEBUG + ReentrancyGuard(T &obj) + : entered(obj.entered) +#else + ReentrancyGuard(T &/*obj*/) +#endif + { +#ifdef DEBUG + JS_ASSERT(!entered); + entered = true; +#endif + } + ~ReentrancyGuard() + { +#ifdef DEBUG + entered = false; +#endif + } +}; + +/* + * Round x up to the nearest power of 2. This function assumes that the most + * significant bit of x is not set, which would lead to overflow. + */ +STATIC_POSTCONDITION_ASSUME(return >= x) +JS_ALWAYS_INLINE size_t +RoundUpPow2(size_t x) +{ + size_t log2 = JS_CEILING_LOG2W(x); + JS_ASSERT(log2 < tl::BitSize::result); + size_t result = size_t(1) << log2; + return result; +} + +/* + * Safely subtract two pointers when it is known that end > begin. This avoids + * the common compiler bug that if (size_t(end) - size_t(begin)) has the MSB + * set, the unsigned subtraction followed by right shift will produce -1, or + * size_t(-1), instead of the real difference. + */ +template +JS_ALWAYS_INLINE size_t +PointerRangeSize(T *begin, T *end) +{ + return (size_t(end) - size_t(begin)) / sizeof(T); +} + +/* + * Allocation policies. These model the concept: + * - public copy constructor, assignment, destructor + * - void *malloc(size_t) + * Responsible for OOM reporting on NULL return value. + * - void *realloc(size_t) + * Responsible for OOM reporting on NULL return value. + * - void free(void *) + * - reportAllocOverflow() + * Called on overflow before the container returns NULL. + */ + +/* Policy for using system memory functions and doing no error reporting. */ +class SystemAllocPolicy +{ + public: + void *malloc(size_t bytes) { return js_malloc(bytes); } + void *realloc(void *p, size_t bytes) { return js_realloc(p, bytes); } + void free(void *p) { js_free(p); } + void reportAllocOverflow() const {} +}; + +/* + * This utility pales in comparison to Boost's aligned_storage. The utility + * simply assumes that JSUint64 is enough alignment for anyone. This may need + * to be extended one day... + * + * As an important side effect, pulling the storage into this template is + * enough obfuscation to confuse gcc's strict-aliasing analysis into not giving + * false negatives when we cast from the char buffer to whatever type we've + * constructed using the bytes. + */ +template +struct AlignedStorage +{ + union U { + char bytes[nbytes]; + uint64 _; + } u; + + const void *addr() const { return u.bytes; } + void *addr() { return u.bytes; } +}; + +template +struct AlignedStorage2 +{ + union U { + char bytes[sizeof(T)]; + uint64 _; + } u; + + const T *addr() const { return (const T *)u.bytes; } + T *addr() { return (T *)u.bytes; } +}; + +/* + * Small utility for lazily constructing objects without using dynamic storage. + * When a LazilyConstructed is constructed, it is |empty()|, i.e., no value + * of T has been constructed and no T destructor will be called when the + * LazilyConstructed is destroyed. Upon calling |construct|, a T object will + * be constructed with the given arguments and that object will be destroyed + * when the owning LazilyConstructed is destroyed. + * + * N.B. GCC seems to miss some optimizations with LazilyConstructed and may + * generate extra branches/loads/stores. Use with caution on hot paths. + */ +template +class LazilyConstructed +{ + AlignedStorage2 storage; + bool constructed; + + T &asT() { return *storage.addr(); } + + public: + LazilyConstructed() { constructed = false; } + ~LazilyConstructed() { if (constructed) asT().~T(); } + + bool empty() const { return !constructed; } + + void construct() { + JS_ASSERT(!constructed); + new(storage.addr()) T(); + constructed = true; + } + + template + void construct(const T1 &t1) { + JS_ASSERT(!constructed); + new(storage.addr()) T(t1); + constructed = true; + } + + template + void construct(const T1 &t1, const T2 &t2) { + JS_ASSERT(!constructed); + new(storage.addr()) T(t1, t2); + constructed = true; + } + + template + void construct(const T1 &t1, const T2 &t2, const T3 &t3) { + JS_ASSERT(!constructed); + new(storage.addr()) T(t1, t2, t3); + constructed = true; + } + + template + void construct(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4) { + JS_ASSERT(!constructed); + new(storage.addr()) T(t1, t2, t3, t4); + constructed = true; + } + + T *addr() { + JS_ASSERT(constructed); + return &asT(); + } + + T &ref() { + JS_ASSERT(constructed); + return asT(); + } + + void destroy() { + ref().~T(); + constructed = false; + } +}; + + +/* + * N.B. GCC seems to miss some optimizations with Conditionally and may + * generate extra branches/loads/stores. Use with caution on hot paths. + */ +template +class Conditionally { + LazilyConstructed t; + + public: + Conditionally(bool b) { if (b) t.construct(); } + + template + Conditionally(bool b, const T1 &t1) { if (b) t.construct(t1); } + + template + Conditionally(bool b, const T1 &t1, const T2 &t2) { if (b) t.construct(t1, t2); } +}; + +template +class AlignedPtrAndFlag +{ + uintptr_t bits; + + public: + AlignedPtrAndFlag(T *t, bool flag) { + JS_ASSERT((uintptr_t(t) & 1) == 0); + bits = uintptr_t(t) | uintptr_t(flag); + } + + T *ptr() const { + return (T *)(bits & ~uintptr_t(1)); + } + + bool flag() const { + return (bits & 1) != 0; + } + + void setPtr(T *t) { + JS_ASSERT((uintptr_t(t) & 1) == 0); + bits = uintptr_t(t) | uintptr_t(flag()); + } + + void setFlag() { + bits |= 1; + } + + void unsetFlag() { + bits &= ~uintptr_t(1); + } + + void set(T *t, bool flag) { + JS_ASSERT((uintptr_t(t) & 1) == 0); + bits = uintptr_t(t) | flag; + } +}; + +template +static inline void +Reverse(T *beg, T *end) +{ + while (beg != end) { + if (--end == beg) + return; + T tmp = *beg; + *beg = *end; + *end = tmp; + ++beg; + } +} + +template +static inline T * +Find(T *beg, T *end, const T &v) +{ + for (T *p = beg; p != end; ++p) { + if (*p == v) + return p; + } + return end; +} + +template +static inline typename Container::ElementType * +Find(Container &c, const typename Container::ElementType &v) +{ + return Find(c.begin(), c.end(), v); +} + +template +void +ForEach(InputIterT begin, InputIterT end, CallableT f) +{ + for (; begin != end; ++begin) + f(*begin); +} + +template +static inline T +Min(T t1, T t2) +{ + return t1 < t2 ? t1 : t2; +} + +template +static inline T +Max(T t1, T t2) +{ + return t1 > t2 ? t1 : t2; +} + +/* Allows a const variable to be initialized after its declaration. */ +template +static T& +InitConst(const T &t) +{ + return const_cast(t); +} + +} /* namespace js */ + +#ifdef JSSTL_UNDEFD_MOZALLOC_WRAPPERS +# include "mozilla/mozalloc_macro_wrappers.h" +#endif + +#endif /* jstl_h_ */ diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp new file mode 100644 index 0000000..488acd4 --- /dev/null +++ b/js/src/jstracer.cpp @@ -0,0 +1,17588 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * Andreas Gal + * Mike Shaver + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsstdint.h" +#include "jsbit.h" // low-level (NSPR-based) headers next +#include "jsprf.h" +#include // standard headers next + +#if defined(_MSC_VER) || defined(__MINGW32__) +#include +#ifdef _MSC_VER +#define alloca _alloca +#endif +#endif +#ifdef SOLARIS +#include +#endif +#include + +#include "nanojit/nanojit.h" +#include "jsapi.h" // higher-level library and API headers +#include "jsarray.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jscompartment.h" +#include "jsdate.h" +#include "jsdbgapi.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsinterp.h" +#include "jsiter.h" +#include "jsmath.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsregexp.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstaticcheck.h" +#include "jstl.h" +#include "jstracer.h" +#include "jsxml.h" +#include "jstypedarray.h" + +#include "jsatominlines.h" +#include "jscntxtinlines.h" +#include "jsfuninlines.h" +#include "jsinterpinlines.h" +#include "jspropertycacheinlines.h" +#include "jsobjinlines.h" +#include "jsscopeinlines.h" +#include "jsscriptinlines.h" +#include "jscntxtinlines.h" +#include "jsopcodeinlines.h" + +#ifdef JS_METHODJIT +#include "methodjit/MethodJIT.h" +#endif + +#include "jsautooplen.h" // generated headers last +#include "imacros.c.out" + +#if defined(NANOJIT_ARM) && defined(__GNUC__) && defined(AVMPLUS_LINUX) +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#ifdef DEBUG +namespace js { +static const char* +getExitName(ExitType type) +{ + static const char* exitNames[] = + { + #define MAKE_EXIT_STRING(x) #x, + JS_TM_EXITCODES(MAKE_EXIT_STRING) + #undef MAKE_EXIT_STRING + NULL + }; + + JS_ASSERT(type < TOTAL_EXIT_TYPES); + + return exitNames[type]; +} +} +#endif /* DEBUG */ + +namespace nanojit { +using namespace js; +using namespace js::gc; +using namespace js::tjit; + +/* + * This macro is just like JS_NOT_REACHED but it exists in non-debug builds + * too. Its presence indicates shortcomings in jstracer's handling of some + * OOM situations: + * - OOM failures in constructors, which lack a return value to pass back a + * failure code (though it can and should be done indirectly). + * - OOM failures in the "infallible" allocators used for Nanojit. + * + * FIXME: bug 624590 is open to fix these problems. + */ +#define OUT_OF_MEMORY_ABORT(msg) JS_Assert(msg, __FILE__, __LINE__); + +/* Implement embedder-specific nanojit members. */ + +/* + * Nanojit requires infallible allocations most of the time. We satisfy this + * by reserving some space in each allocator which is used as a fallback if + * js_calloc() fails. Ideallly this reserve space should be big enough to + * allow for all infallible requests made to the allocator until the next OOM + * check occurs, but it turns out that's impossible to guarantee (though it + * should be unlikely). So we abort if the reserve runs out; this is better + * than allowing memory errors to occur. + * + * The space calculations are as follows... between OOM checks, each + * VMAllocator can do (ie. has been seen to do) the following maximum + * allocations on 64-bits: + * + * - dataAlloc: 31 minimum-sized chunks (MIN_CHUNK_SZB) in assm->compile() + * (though arbitrarily more could occur due to LabelStateMap additions done + * when handling labels): 62,248 bytes. This one is the most likely to + * overflow. + * + * - traceAlloc: 1 minimum-sized chunk: 2,008 bytes. + * + * - tempAlloc: 1 LIR code chunk (CHUNK_SZB) and 5 minimum-sized chunks for + * sundry small allocations: 18,048 bytes. + * + * The reserve sizes are chosen by exceeding this by a reasonable amount. + * Reserves for 32-bits are slightly more than half, because most of the + * allocated space is used to hold pointers. + * + * FIXME: Bug 624590 is open to get rid of all this. + */ +static const size_t DataReserveSize = 12500 * sizeof(uintptr_t); +static const size_t TraceReserveSize = 5000 * sizeof(uintptr_t); +static const size_t TempReserveSize = 1000 * sizeof(uintptr_t); + +void* +nanojit::Allocator::allocChunk(size_t nbytes, bool fallible) +{ + VMAllocator *vma = (VMAllocator*)this; + /* + * Nb: it's conceivable that request 1 might fail (in which case + * mOutOfMemory will be set) and then request 2 succeeds. The subsequent + * OOM check will still fail, which is what we want, and the success of + * request 2 makes it less likely that the reserve space will overflow. + */ + void *p = js_calloc(nbytes); + if (p) { + vma->mSize += nbytes; + } else { + vma->mOutOfMemory = true; + if (!fallible) { + p = (void *)vma->mReserveCurr; + vma->mReserveCurr += nbytes; + if (vma->mReserveCurr > vma->mReserveLimit) + OUT_OF_MEMORY_ABORT("nanojit::Allocator::allocChunk: out of memory"); + memset(p, 0, nbytes); + vma->mSize += nbytes; + } + } + return p; +} + +void +nanojit::Allocator::freeChunk(void *p) { + VMAllocator *vma = (VMAllocator*)this; + if (p < vma->mReserve || uintptr_t(p) >= vma->mReserveLimit) + js_free(p); +} + +void +nanojit::Allocator::postReset() { + VMAllocator *vma = (VMAllocator*)this; + vma->mOutOfMemory = false; + vma->mSize = 0; + vma->mReserveCurr = uintptr_t(vma->mReserve); +} + +int +StackFilter::getTop(LIns* guard) +{ + VMSideExit* e = (VMSideExit*)guard->record()->exit; + return e->sp_adj; +} + +#if defined NJ_VERBOSE +static void +formatGuardExit(InsBuf *buf, LIns *ins) +{ + VMSideExit *x = (VMSideExit *)ins->record()->exit; + RefBuf b1; + if (LogController.lcbits & LC_FragProfile) + VMPI_snprintf(b1.buf, b1.len, " (GuardID=%03d)", ins->record()->profGuardID); + else + b1.buf[0] = '\0'; + VMPI_snprintf(buf->buf, buf->len, + " -> exit=%p pc=%p imacpc=%p sp%+ld rp%+ld %s%s", + (void *)x, + (void *)x->pc, + (void *)x->imacpc, + (long int)x->sp_adj, + (long int)x->rp_adj, + getExitName(x->exitType), + b1.buf); +} + +void +LInsPrinter::formatGuard(InsBuf *buf, LIns *ins) +{ + RefBuf b1, b2; + InsBuf b3; + formatGuardExit(&b3, ins); + VMPI_snprintf(buf->buf, buf->len, + "%s: %s %s%s", + formatRef(&b1, ins), + lirNames[ins->opcode()], + ins->oprnd1() ? formatRef(&b2, ins->oprnd1()) : "", + b3.buf); +} + +void +LInsPrinter::formatGuardXov(InsBuf *buf, LIns *ins) +{ + RefBuf b1, b2, b3; + InsBuf b4; + formatGuardExit(&b4, ins); + VMPI_snprintf(buf->buf, buf->len, + "%s = %s %s, %s%s", + formatRef(&b1, ins), + lirNames[ins->opcode()], + formatRef(&b2, ins->oprnd1()), + formatRef(&b3, ins->oprnd2()), + b4.buf); +} + +const char* +nanojit::LInsPrinter::accNames[] = { + "state", // (1 << 0) == ACCSET_STATE + "sp", // (1 << 1) == ACCSET_STACK + "rp", // (1 << 2) == ACCSET_RSTACK + "cx", // (1 << 3) == ACCSET_CX + "tm", // (1 << 4) == ACCSET_TM + "eos", // (1 << 5) == ACCSET_EOS + "alloc", // (1 << 6) == ACCSET_ALLOC + "regs", // (1 << 7) == ACCSET_FRAMEREGS + "sf", // (1 << 8) == ACCSET_STACKFRAME + "rt", // (1 << 9) == ACCSET_RUNTIME + + "objclasp", // (1 << 10) == ACCSET_OBJ_CLASP + "objflags", // (1 << 11) == ACCSET_OBJ_FLAGS + "objshape", // (1 << 12) == ACCSET_OBJ_SHAPE + "objproto", // (1 << 13) == ACCSET_OBJ_PROTO + "objparent", // (1 << 14) == ACCSET_OBJ_PARENT + "objprivate", // (1 << 15) == ACCSET_OBJ_PRIVATE + "objcapacity", // (1 << 16) == ACCSET_OBJ_CAPACITY + "objslots", // (1 << 17) == ACCSET_OBJ_SLOTS + + "slots", // (1 << 18) == ACCSET_SLOTS + "tarray", // (1 << 19) == ACCSET_TARRAY + "tdata", // (1 << 20) == ACCSET_TARRAY_DATA + "iter", // (1 << 21) == ACCSET_ITER + "iterprops", // (1 << 22) == ACCSET_ITER_PROPS + "str", // (1 << 23) == ACCSET_STRING + "strmchars", // (1 << 24) == ACCSET_STRING_MCHARS + "typemap", // (1 << 25) == ACCSET_TYPEMAP + "fcslots", // (1 << 26) == ACCSET_FCSLOTS + "argsdata", // (1 << 27) == ACCSET_ARGS_DATA + + "?!" // this entry should never be used, have it just in case +}; + +JS_STATIC_ASSERT(JS_ARRAY_LENGTH(nanojit::LInsPrinter::accNames) == TM_NUM_USED_ACCS + 1); +#endif + +} /* namespace nanojit */ + +JS_DEFINE_CALLINFO_2(extern, STRING, js_IntToString, CONTEXT, INT32, 1, nanojit::ACCSET_NONE) + +namespace js { + +using namespace nanojit; + +#if JS_HAS_XML_SUPPORT +#define RETURN_VALUE_IF_XML(val, ret) \ + JS_BEGIN_MACRO \ + if (!val.isPrimitive() && val.toObject().isXML()) \ + RETURN_VALUE("xml detected", ret); \ + JS_END_MACRO +#else +#define RETURN_IF_XML(val, ret) ((void) 0) +#endif + +#define RETURN_IF_XML_A(val) RETURN_VALUE_IF_XML(val, ARECORD_STOP) +#define RETURN_IF_XML(val) RETURN_VALUE_IF_XML(val, RECORD_STOP) + +JS_STATIC_ASSERT(sizeof(JSValueType) == 1); +JS_STATIC_ASSERT(offsetof(TraceNativeStorage, stack_global_buf) % 16 == 0); + +/* Map to translate a type tag into a printable representation. */ +#ifdef DEBUG +static char +TypeToChar(JSValueType type) +{ + switch (type) { + case JSVAL_TYPE_DOUBLE: return 'D'; + case JSVAL_TYPE_INT32: return 'I'; + case JSVAL_TYPE_STRING: return 'S'; + case JSVAL_TYPE_OBJECT: return '!'; + case JSVAL_TYPE_BOOLEAN: return 'B'; + case JSVAL_TYPE_NULL: return 'N'; + case JSVAL_TYPE_UNDEFINED: return 'U'; + case JSVAL_TYPE_MAGIC: return 'M'; + case JSVAL_TYPE_FUNOBJ: return 'F'; + case JSVAL_TYPE_NONFUNOBJ: return 'O'; + case JSVAL_TYPE_BOXED: return '#'; + case JSVAL_TYPE_STRORNULL: return 's'; + case JSVAL_TYPE_OBJORNULL: return 'o'; + } + return '?'; +} + +static char +ValueToTypeChar(const Value &v) +{ + if (v.isInt32()) return 'I'; + if (v.isDouble()) return 'D'; + if (v.isString()) return 'S'; + if (v.isObject()) return v.toObject().isFunction() ? 'F' : 'O'; + if (v.isBoolean()) return 'B'; + if (v.isNull()) return 'N'; + if (v.isUndefined()) return 'U'; + if (v.isMagic()) return 'M'; + return '?'; +} +#endif + + +/* Blacklist parameters. */ + +/* + * Number of iterations of a loop where we start tracing. That is, we don't + * start tracing until the beginning of the HOTLOOP-th iteration. + */ +#define HOTLOOP 8 + +/* Attempt recording this many times before blacklisting permanently. */ +#define BL_ATTEMPTS 2 + +/* Skip this many hits before attempting recording again, after an aborted attempt. */ +#define BL_BACKOFF 32 + +/* + * If, after running a trace CHECK_LOOP_ITERS times, it hasn't done MIN_LOOP_ITERS + * iterations, we blacklist it. +*/ +#define MIN_LOOP_ITERS 200 +#define LOOP_CHECK_ITERS 10 + +#ifdef DEBUG +#define LOOP_COUNT_MAX 100000000 +#else +#define LOOP_COUNT_MAX MIN_LOOP_ITERS +#endif + +/* Number of times we wait to exit on a side exit before we try to extend the tree. */ +#define HOTEXIT 1 + +/* Number of times we try to extend the tree along a side exit. */ +#define MAXEXIT 3 + +/* Maximum number of peer trees allowed. */ +#define MAXPEERS 9 + +/* Max call depths for inlining. */ +#define MAX_CALLDEPTH 10 + +/* Max number of slots in a table-switch. */ +#define MAX_TABLE_SWITCH 256 + +/* Max memory needed to rebuild the interpreter stack when falling off trace. */ +#define MAX_INTERP_STACK_BYTES \ + (MAX_NATIVE_STACK_SLOTS * sizeof(Value) + \ + MAX_CALL_STACK_ENTRIES * sizeof(JSInlineFrame) + \ + sizeof(JSInlineFrame)) /* possibly slow native frame at top of stack */ + +/* Max number of branches per tree. */ +#define MAX_BRANCHES 32 + +#define CHECK_STATUS(expr) \ + JS_BEGIN_MACRO \ + RecordingStatus _status = (expr); \ + if (_status != RECORD_CONTINUE) \ + return _status; \ + JS_END_MACRO + +#define CHECK_STATUS_A(expr) \ + JS_BEGIN_MACRO \ + AbortableRecordingStatus _status = InjectStatus((expr)); \ + if (_status != ARECORD_CONTINUE) \ + return _status; \ + JS_END_MACRO + +#ifdef JS_JIT_SPEW +#define RETURN_VALUE(msg, value) \ + JS_BEGIN_MACRO \ + debug_only_printf(LC_TMAbort, "trace stopped: %d: %s\n", __LINE__, (msg)); \ + return (value); \ + JS_END_MACRO +#else +#define RETURN_VALUE(msg, value) return (value) +#endif + +#define RETURN_STOP(msg) RETURN_VALUE(msg, RECORD_STOP) +#define RETURN_STOP_A(msg) RETURN_VALUE(msg, ARECORD_STOP) +#define RETURN_ERROR(msg) RETURN_VALUE(msg, RECORD_ERROR) +#define RETURN_ERROR_A(msg) RETURN_VALUE(msg, ARECORD_ERROR) + +#ifdef JS_JIT_SPEW +struct __jitstats { +#define JITSTAT(x) uint64 x; +#include "jitstats.tbl" +#undef JITSTAT +} jitstats = { 0LL, }; + +JS_STATIC_ASSERT(sizeof(jitstats) % sizeof(uint64) == 0); + +enum jitstat_ids { +#define JITSTAT(x) STAT ## x ## ID, +#include "jitstats.tbl" +#undef JITSTAT + STAT_IDS_TOTAL +}; + +static JSBool +jitstats_getOnTrace(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + *vp = BOOLEAN_TO_JSVAL(JS_ON_TRACE(cx)); + return true; +} + +static JSPropertySpec jitstats_props[] = { +#define JITSTAT(x) { #x, STAT ## x ## ID, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT }, +#include "jitstats.tbl" +#undef JITSTAT + { "onTrace", 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT, jitstats_getOnTrace, NULL }, + { 0 } +}; + +static JSBool +jitstats_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + int index = -1; + + if (JSID_IS_STRING(id)) { + JSAtom* str = JSID_TO_ATOM(id); + if (StringEqualsAscii(str, "HOTLOOP")) { + *vp = INT_TO_JSVAL(HOTLOOP); + return JS_TRUE; + } + +#ifdef JS_METHODJIT + if (StringEqualsAscii(str, "profiler")) { + *vp = BOOLEAN_TO_JSVAL(cx->profilingEnabled); + return JS_TRUE; + } +#endif + } + + if (JSID_IS_INT(id)) + index = JSID_TO_INT(id); + + uint64 result = 0; + switch (index) { +#define JITSTAT(x) case STAT ## x ## ID: result = jitstats.x; break; +#include "jitstats.tbl" +#undef JITSTAT + default: + *vp = JSVAL_VOID; + return JS_TRUE; + } + + if (result < JSVAL_INT_MAX) { + *vp = INT_TO_JSVAL(jsint(result)); + return JS_TRUE; + } + char retstr[64]; + JS_snprintf(retstr, sizeof retstr, "%llu", result); + *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, retstr)); + return JS_TRUE; +} + +JSClass jitstats_class = { + "jitstats", + 0, + JS_PropertyStub, JS_PropertyStub, + jitstats_getProperty, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, + JS_ConvertStub, NULL, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +void +InitJITStatsClass(JSContext *cx, JSObject *glob) +{ + JS_InitClass(cx, glob, NULL, &jitstats_class, NULL, 0, jitstats_props, NULL, NULL, NULL); +} + +#define AUDIT(x) (jitstats.x++) +#else +#define AUDIT(x) ((void)0) +#endif /* JS_JIT_SPEW */ + +static avmplus::AvmCore s_core = avmplus::AvmCore(); +static avmplus::AvmCore* core = &s_core; + +#ifdef JS_JIT_SPEW +static void +DumpPeerStability(TraceMonitor* tm, const void* ip, JSObject* globalObj, uint32 globalShape, uint32 argc); +#endif + +/* + * We really need a better way to configure the JIT. Shaver, where is + * my fancy JIT object? + * + * NB: this is raced on, if jstracer.cpp should ever be running MT. + * I think it's harmless tho. + */ +static bool did_we_check_processor_features = false; + +/* ------ Debug logging control ------ */ + +/* + * All the logging control stuff lives in here. It is shared between + * all threads, but I think that's OK. + */ +LogControl LogController; + +#ifdef JS_JIT_SPEW + +/* + * NB: this is raced on too, if jstracer.cpp should ever be running MT. + * Also harmless. + */ +static bool did_we_set_up_debug_logging = false; + +static void +InitJITLogController() +{ + char *tm, *tmf; + uint32_t bits; + + LogController.lcbits = 0; + + tm = getenv("TRACEMONKEY"); + if (tm) { + fflush(NULL); + printf( + "The environment variable $TRACEMONKEY has been replaced by $TMFLAGS.\n" + "Try 'TMFLAGS=help js -j' for a list of options.\n" + ); + exit(0); + } + + tmf = getenv("TMFLAGS"); + if (!tmf) return; + + /* Using strstr() is really a cheap hack as far as flag decoding goes. */ + if (strstr(tmf, "help")) { + fflush(NULL); + printf( + "usage: TMFLAGS=option,option,option,... where options can be:\n" + "\n" + " help show this message\n" + " ------ options for jstracer & jsregexp ------\n" + " minimal ultra-minimalist output; try this first\n" + " full everything except 'treevis' and 'fragprofile'\n" + " tracer tracer lifetime (FIXME:better description)\n" + " recorder trace recording stuff (FIXME:better description)\n" + " abort show trace recording aborts\n" + " stats show trace recording stats\n" + " regexp show compilation & entry for regexps\n" + " profiler show loop profiles as they are profiled\n" + " treevis spew that tracevis/tree.py can parse\n" + " ------ options for Nanojit ------\n" + " fragprofile count entries and exits for each fragment\n" + " liveness show LIR liveness at start of reader pipeline\n" + " readlir show LIR as it enters the reader pipeline\n" + " aftersf show LIR after StackFilter\n" + " afterdce show LIR after dead code elimination\n" + " native show native code (interleaved with 'afterdce')\n" + " nativebytes show native code bytes in 'native' output\n" + " regalloc show regalloc state in 'native' output\n" + " activation show activation state in 'native' output\n" + "\n" + ); + exit(0); + /*NOTREACHED*/ + } + + bits = 0; + + /* flags for jstracer.cpp */ + if (strstr(tmf, "minimal") || strstr(tmf, "full")) bits |= LC_TMMinimal; + if (strstr(tmf, "tracer") || strstr(tmf, "full")) bits |= LC_TMTracer; + if (strstr(tmf, "recorder") || strstr(tmf, "full")) bits |= LC_TMRecorder; + if (strstr(tmf, "abort") || strstr(tmf, "full")) bits |= LC_TMAbort; + if (strstr(tmf, "stats") || strstr(tmf, "full")) bits |= LC_TMStats; + if (strstr(tmf, "profiler") || strstr(tmf, "full")) bits |= LC_TMProfiler; + if (strstr(tmf, "treevis")) bits |= LC_TMTreeVis; + + /* flags for nanojit */ + if (strstr(tmf, "fragprofile")) bits |= LC_FragProfile; + if (strstr(tmf, "liveness") || strstr(tmf, "full")) bits |= LC_Liveness; + if (strstr(tmf, "readlir") || strstr(tmf, "full")) bits |= LC_ReadLIR; + if (strstr(tmf, "aftersf") || strstr(tmf, "full")) bits |= LC_AfterSF; + if (strstr(tmf, "afterdce") || strstr(tmf, "full")) bits |= LC_AfterDCE; + if (strstr(tmf, "native") || strstr(tmf, "full")) bits |= LC_Native; + if (strstr(tmf, "nativebytes")|| strstr(tmf, "full")) bits |= LC_Bytes; + if (strstr(tmf, "regalloc") || strstr(tmf, "full")) bits |= LC_RegAlloc; + if (strstr(tmf, "activation") || strstr(tmf, "full")) bits |= LC_Activation; + + LogController.lcbits = bits; + return; + +} +#endif + +/* ------------------ Frag-level profiling support ------------------ */ + +#ifdef JS_JIT_SPEW + +/* + * All the allocations done by this profile data-collection and + * display machinery, are done in TraceMonitor::profAlloc. That is + * emptied out at the end of FinishJIT. It has a lifetime from + * InitJIT to FinishJIT, which exactly matches the span + * js_FragProfiling_init to js_FragProfiling_showResults. + */ +template +static +Seq* reverseInPlace(Seq* seq) +{ + Seq* prev = NULL; + Seq* curr = seq; + while (curr) { + Seq* next = curr->tail; + curr->tail = prev; + prev = curr; + curr = next; + } + return prev; +} + +// The number of top blocks to show in the profile +#define N_TOP_BLOCKS 50 + +// Contains profile info for a single guard +struct GuardPI { + uint32_t guardID; // identifying number + uint32_t count; // count. +}; + +struct FragPI { + uint32_t count; // entry count for this Fragment + uint32_t nStaticExits; // statically: the number of exits + size_t nCodeBytes; // statically: the number of insn bytes in the main fragment + size_t nExitBytes; // statically: the number of insn bytes in the exit paths + Seq* guards; // guards, each with its own count + uint32_t largestGuardID; // that exists in .guards +}; + +void +FragProfiling_FragFinalizer(Fragment* f, TraceMonitor* tm) +{ + // Recover profiling data from 'f', which is logically at the end + // of its useful lifetime. + if (!(LogController.lcbits & LC_FragProfile)) + return; + + NanoAssert(f); + // Valid profFragIDs start at 1 + NanoAssert(f->profFragID >= 1); + // Should be called exactly once per Fragment. This will assert if + // you issue the same FragID to more than one Fragment. + NanoAssert(!tm->profTab->containsKey(f->profFragID)); + + FragPI pi = { f->profCount, + f->nStaticExits, + f->nCodeBytes, + f->nExitBytes, + NULL, 0 }; + + // Begin sanity check on the guards + SeqBuilder guardsBuilder(*tm->profAlloc); + GuardRecord* gr; + uint32_t nGs = 0; + uint32_t sumOfDynExits = 0; + for (gr = f->guardsForFrag; gr; gr = gr->nextInFrag) { + nGs++; + // Also copy the data into our auxiliary structure. + // f->guardsForFrag is in reverse order, and so this + // copy preserves that ordering (->add adds at end). + // Valid profGuardIDs start at 1. + NanoAssert(gr->profGuardID > 0); + sumOfDynExits += gr->profCount; + GuardPI gpi = { gr->profGuardID, gr->profCount }; + guardsBuilder.add(gpi); + if (gr->profGuardID > pi.largestGuardID) + pi.largestGuardID = gr->profGuardID; + } + pi.guards = guardsBuilder.get(); + // And put the guard list in forwards order + pi.guards = reverseInPlace(pi.guards); + + // Why is this so? Because nGs is the number of guards + // at the time the LIR was generated, whereas f->nStaticExits + // is the number of them observed by the time it makes it + // through to the assembler. It can be the case that LIR + // optimisation removes redundant guards; hence we expect + // nGs to always be the same or higher. + NanoAssert(nGs >= f->nStaticExits); + + // Also we can assert that the sum of the exit counts + // can't exceed the entry count. It'd be nice to assert that + // they are exactly equal, but we can't because we don't know + // how many times we got to the end of the trace. + NanoAssert(f->profCount >= sumOfDynExits); + + // End sanity check on guards + + tm->profTab->put(f->profFragID, pi); +} + +static void +FragProfiling_showResults(TraceMonitor* tm) +{ + uint32_t topFragID[N_TOP_BLOCKS]; + FragPI topPI[N_TOP_BLOCKS]; + uint64_t totCount = 0, cumulCount; + uint32_t totSE = 0; + size_t totCodeB = 0, totExitB = 0; + PodArrayZero(topFragID); + PodArrayZero(topPI); + FragStatsMap::Iter iter(*tm->profTab); + while (iter.next()) { + uint32_t fragID = iter.key(); + FragPI pi = iter.value(); + uint32_t count = pi.count; + totCount += (uint64_t)count; + /* Find the rank for this entry, in tops */ + int r = N_TOP_BLOCKS-1; + while (true) { + if (r == -1) + break; + if (topFragID[r] == 0) { + r--; + continue; + } + if (count > topPI[r].count) { + r--; + continue; + } + break; + } + r++; + NanoAssert(r >= 0 && r <= N_TOP_BLOCKS); + /* This entry should be placed at topPI[r], and entries + at higher numbered slots moved up one. */ + if (r < N_TOP_BLOCKS) { + for (int s = N_TOP_BLOCKS-1; s > r; s--) { + topFragID[s] = topFragID[s-1]; + topPI[s] = topPI[s-1]; + } + topFragID[r] = fragID; + topPI[r] = pi; + } + } + + LogController.printf( + "\n----------------- Per-fragment execution counts ------------------\n"); + LogController.printf( + "\nTotal count = %llu\n\n", (unsigned long long int)totCount); + + LogController.printf( + " Entry counts Entry counts ----- Static -----\n"); + LogController.printf( + " ------Self------ ----Cumulative--- Exits Cbytes Xbytes FragID\n"); + LogController.printf("\n"); + + if (totCount == 0) + totCount = 1; /* avoid division by zero */ + cumulCount = 0; + int r; + for (r = 0; r < N_TOP_BLOCKS; r++) { + if (topFragID[r] == 0) + break; + cumulCount += (uint64_t)topPI[r].count; + LogController.printf("%3d: %5.2f%% %9u %6.2f%% %9llu" + " %3d %5u %5u %06u\n", + r, + (double)topPI[r].count * 100.0 / (double)totCount, + topPI[r].count, + (double)cumulCount * 100.0 / (double)totCount, + (unsigned long long int)cumulCount, + topPI[r].nStaticExits, + (unsigned int)topPI[r].nCodeBytes, + (unsigned int)topPI[r].nExitBytes, + topFragID[r]); + totSE += (uint32_t)topPI[r].nStaticExits; + totCodeB += topPI[r].nCodeBytes; + totExitB += topPI[r].nExitBytes; + } + LogController.printf("\nTotal displayed code bytes = %u, " + "exit bytes = %u\n" + "Total displayed static exits = %d\n\n", + (unsigned int)totCodeB, (unsigned int)totExitB, totSE); + + LogController.printf("Analysis by exit counts\n\n"); + + for (r = 0; r < N_TOP_BLOCKS; r++) { + if (topFragID[r] == 0) + break; + LogController.printf("FragID=%06u, total count %u:\n", topFragID[r], + topPI[r].count); + uint32_t madeItToEnd = topPI[r].count; + uint32_t totThisFrag = topPI[r].count; + if (totThisFrag == 0) + totThisFrag = 1; + GuardPI gpi; + // visit the guards, in forward order + for (Seq* guards = topPI[r].guards; guards; guards = guards->tail) { + gpi = (*guards).head; + if (gpi.count == 0) + continue; + madeItToEnd -= gpi.count; + LogController.printf(" GuardID=%03u %7u (%5.2f%%)\n", + gpi.guardID, gpi.count, + 100.0 * (double)gpi.count / (double)totThisFrag); + } + LogController.printf(" Looped (%03u) %7u (%5.2f%%)\n", + topPI[r].largestGuardID+1, + madeItToEnd, + 100.0 * (double)madeItToEnd / (double)totThisFrag); + NanoAssert(madeItToEnd <= topPI[r].count); // else unsigned underflow + LogController.printf("\n"); + } + + tm->profTab = NULL; +} + +#endif + +/* ----------------------------------------------------------------- */ + +#ifdef DEBUG +static JSBool FASTCALL +PrintOnTrace(char* format, uint32 argc, double *argv) +{ + union { + struct { + uint32 lo; + uint32 hi; + } i; + double d; + char *cstr; + JSObject *o; + JSString *s; + } u; + +#define GET_ARG() JS_BEGIN_MACRO \ + if (argi >= argc) { \ + fprintf(out, "[too few args for format]"); \ + break; \ +} \ + u.d = argv[argi++]; \ + JS_END_MACRO + + FILE *out = stderr; + + uint32 argi = 0; + for (char *p = format; *p; ++p) { + if (*p != '%') { + putc(*p, out); + continue; + } + char ch = *++p; + if (!ch) { + fprintf(out, "[trailing %%]"); + continue; + } + + switch (ch) { + case 'a': + GET_ARG(); + fprintf(out, "[%u:%u 0x%x:0x%x %f]", u.i.lo, u.i.hi, u.i.lo, u.i.hi, u.d); + break; + case 'd': + GET_ARG(); + fprintf(out, "%d", u.i.lo); + break; + case 'u': + GET_ARG(); + fprintf(out, "%u", u.i.lo); + break; + case 'x': + GET_ARG(); + fprintf(out, "%x", u.i.lo); + break; + case 'f': + GET_ARG(); + fprintf(out, "%f", u.d); + break; + case 'o': + GET_ARG(); + js_DumpObject(u.o); + break; + case 's': + GET_ARG(); + { + size_t length = u.s->length(); + // protect against massive spew if u.s is a bad pointer. + if (length > 1 << 16) + length = 1 << 16; + if (u.s->isRope()) { + fprintf(out, ""); + break; + } + const jschar *chars = u.s->nonRopeChars(); + for (unsigned i = 0; i < length; ++i) { + jschar co = chars[i]; + if (co < 128) + putc(co, out); + else if (co < 256) + fprintf(out, "\\u%02x", co); + else + fprintf(out, "\\u%04x", co); + } + } + break; + case 'S': + GET_ARG(); + fprintf(out, "%s", u.cstr); + break; + case 'v': { + GET_ARG(); + Value *v = (Value *) u.i.lo; + js_DumpValue(*v); + break; + } + default: + fprintf(out, "[invalid %%%c]", *p); + } + } + +#undef GET_ARG + + return JS_TRUE; +} + +JS_DEFINE_CALLINFO_3(extern, BOOL, PrintOnTrace, CHARPTR, UINT32, DOUBLEPTR, 0, ACCSET_STORE_ANY) + +// This version is not intended to be called directly: usually it is easier to +// use one of the other overloads. +void +TraceRecorder::tprint(const char *format, int count, nanojit::LIns *insa[]) +{ + size_t size = strlen(format) + 1; + char* data = (char*) traceMonitor->traceAlloc->alloc(size); + memcpy(data, format, size); + + double *args = (double*) traceMonitor->traceAlloc->alloc(count * sizeof(double)); + LIns* argsp_ins = w.nameImmpNonGC(args); + for (int i = 0; i < count; ++i) + w.stTprintArg(insa, argsp_ins, i); + + LIns* args_ins[] = { w.nameImmpNonGC(args), w.nameImmi(count), w.nameImmpNonGC(data) }; + LIns* call_ins = w.call(&PrintOnTrace_ci, args_ins); + guard(false, w.eqi0(call_ins), MISMATCH_EXIT); +} + +// Generate a 'printf'-type call from trace for debugging. +void +TraceRecorder::tprint(const char *format) +{ + LIns* insa[] = { NULL }; + tprint(format, 0, insa); +} + +void +TraceRecorder::tprint(const char *format, LIns *ins) +{ + LIns* insa[] = { ins }; + tprint(format, 1, insa); +} + +void +TraceRecorder::tprint(const char *format, LIns *ins1, LIns *ins2) +{ + LIns* insa[] = { ins1, ins2 }; + tprint(format, 2, insa); +} + +void +TraceRecorder::tprint(const char *format, LIns *ins1, LIns *ins2, LIns *ins3) +{ + LIns* insa[] = { ins1, ins2, ins3 }; + tprint(format, 3, insa); +} + +void +TraceRecorder::tprint(const char *format, LIns *ins1, LIns *ins2, LIns *ins3, LIns *ins4) +{ + LIns* insa[] = { ins1, ins2, ins3, ins4 }; + tprint(format, 4, insa); +} + +void +TraceRecorder::tprint(const char *format, LIns *ins1, LIns *ins2, LIns *ins3, LIns *ins4, + LIns *ins5) +{ + LIns* insa[] = { ins1, ins2, ins3, ins4, ins5 }; + tprint(format, 5, insa); +} + +void +TraceRecorder::tprint(const char *format, LIns *ins1, LIns *ins2, LIns *ins3, LIns *ins4, + LIns *ins5, LIns *ins6) +{ + LIns* insa[] = { ins1, ins2, ins3, ins4, ins5, ins6 }; + tprint(format, 6, insa); +} +#endif + +Tracker::Tracker() +{ + pagelist = NULL; +} + +Tracker::~Tracker() +{ + clear(); +} + +inline jsuword +Tracker::getTrackerPageBase(const void* v) const +{ + return jsuword(v) & ~TRACKER_PAGE_MASK; +} + +inline jsuword +Tracker::getTrackerPageOffset(const void* v) const +{ + return (jsuword(v) & TRACKER_PAGE_MASK) >> 2; +} + +struct Tracker::TrackerPage* +Tracker::findTrackerPage(const void* v) const +{ + jsuword base = getTrackerPageBase(v); + struct Tracker::TrackerPage* p = pagelist; + while (p) { + if (p->base == base) + return p; + p = p->next; + } + return NULL; +} + +struct Tracker::TrackerPage* +Tracker::addTrackerPage(const void* v) +{ + jsuword base = getTrackerPageBase(v); + struct TrackerPage* p = (struct TrackerPage*) js_calloc(sizeof(*p)); + p->base = base; + p->next = pagelist; + pagelist = p; + return p; +} + +void +Tracker::clear() +{ + while (pagelist) { + TrackerPage* p = pagelist; + pagelist = pagelist->next; + js_free(p); + } +} + +bool +Tracker::has(const void *v) const +{ + return get(v) != NULL; +} + +LIns* +Tracker::get(const void* v) const +{ + struct Tracker::TrackerPage* p = findTrackerPage(v); + if (!p) + return NULL; + return p->map[getTrackerPageOffset(v)]; +} + +void +Tracker::set(const void* v, LIns* i) +{ + struct Tracker::TrackerPage* p = findTrackerPage(v); + if (!p) + p = addTrackerPage(v); + p->map[getTrackerPageOffset(v)] = i; +} + +static inline bool +hasInt32Repr(const Value &v) +{ + if (!v.isNumber()) + return false; + if (v.isInt32()) + return true; + int32_t _; + return JSDOUBLE_IS_INT32(v.toDouble(), &_); +} + +static inline jsint +asInt32(const Value &v) +{ + JS_ASSERT(v.isNumber()); + if (v.isInt32()) + return v.toInt32(); +#ifdef DEBUG + int32_t _; + JS_ASSERT(JSDOUBLE_IS_INT32(v.toDouble(), &_)); +#endif + return jsint(v.toDouble()); +} + +/* + * Return JSVAL_TYPE_DOUBLE for all numbers (int and double). Split + * JSVAL_TYPE_OBJECT into JSVAL_TYPE_FUNOBJ and JSVAL_TYPE_NONFUNOBJ. + * Otherwise, just return the value's type. + */ +static inline JSValueType +getPromotedType(const Value &v) +{ + if (v.isNumber()) + return JSVAL_TYPE_DOUBLE; + if (v.isObject()) + return v.toObject().isFunction() ? JSVAL_TYPE_FUNOBJ : JSVAL_TYPE_NONFUNOBJ; + return v.extractNonDoubleObjectTraceType(); +} + +/* + * Return JSVAL_TYPE_INT32 for all whole numbers that fit into signed 32-bit. + * Split JSVAL_TYPE_OBJECT into JSVAL_TYPE_FUNOBJ and JSVAL_TYPE_NONFUNOBJ. + * Otherwise, just return the value's type. + */ +static inline JSValueType +getCoercedType(const Value &v) +{ + if (v.isNumber()) { + int32_t _; + return (v.isInt32() || JSDOUBLE_IS_INT32(v.toDouble(), &_)) + ? JSVAL_TYPE_INT32 + : JSVAL_TYPE_DOUBLE; + } + if (v.isObject()) + return v.toObject().isFunction() ? JSVAL_TYPE_FUNOBJ : JSVAL_TYPE_NONFUNOBJ; + return v.extractNonDoubleObjectTraceType(); +} + +static inline JSValueType +getFrameObjPtrTraceType(void *p, JSStackFrame *fp) +{ + if (p == fp->addressOfScopeChain()) { + JS_ASSERT(*(JSObject **)p != NULL); + return JSVAL_TYPE_NONFUNOBJ; + } + JS_ASSERT(p == fp->addressOfArgs()); + return fp->hasArgsObj() ? JSVAL_TYPE_NONFUNOBJ : JSVAL_TYPE_NULL; +} + +static inline bool +isFrameObjPtrTraceType(JSValueType t) +{ + return t == JSVAL_TYPE_NULL || t == JSVAL_TYPE_NONFUNOBJ; +} + +/* Constant seed and accumulate step borrowed from the DJB hash. */ + +const uintptr_t ORACLE_MASK = ORACLE_SIZE - 1; +JS_STATIC_ASSERT((ORACLE_MASK & ORACLE_SIZE) == 0); + +const uintptr_t FRAGMENT_TABLE_MASK = FRAGMENT_TABLE_SIZE - 1; +JS_STATIC_ASSERT((FRAGMENT_TABLE_MASK & FRAGMENT_TABLE_SIZE) == 0); + +const uintptr_t HASH_SEED = 5381; + +static inline void +HashAccum(uintptr_t& h, uintptr_t i, uintptr_t mask) +{ + h = ((h << 5) + h + (mask & i)) & mask; +} + +static JS_REQUIRES_STACK inline int +StackSlotHash(JSContext* cx, unsigned slot, const void* pc) +{ + uintptr_t h = HASH_SEED; + HashAccum(h, uintptr_t(cx->fp()->script()), ORACLE_MASK); + HashAccum(h, uintptr_t(pc), ORACLE_MASK); + HashAccum(h, uintptr_t(slot), ORACLE_MASK); + return int(h); +} + +static JS_REQUIRES_STACK inline int +GlobalSlotHash(JSContext* cx, unsigned slot) +{ + uintptr_t h = HASH_SEED; + JSStackFrame* fp = cx->fp(); + + while (fp->prev()) + fp = fp->prev(); + + HashAccum(h, uintptr_t(fp->maybeScript()), ORACLE_MASK); + HashAccum(h, uintptr_t(fp->scopeChain().getGlobal()->shape()), ORACLE_MASK); + HashAccum(h, uintptr_t(slot), ORACLE_MASK); + return int(h); +} + +static inline int +PCHash(jsbytecode* pc) +{ + return int(uintptr_t(pc) & ORACLE_MASK); +} + +Oracle::Oracle() +{ + /* Grow the oracle bitsets to their (fixed) size here, once. */ + _stackDontDemote.set(ORACLE_SIZE-1); + _globalDontDemote.set(ORACLE_SIZE-1); + clear(); +} + +/* Tell the oracle that a certain global variable should not be demoted. */ +JS_REQUIRES_STACK void +Oracle::markGlobalSlotUndemotable(JSContext* cx, unsigned slot) +{ + _globalDontDemote.set(GlobalSlotHash(cx, slot)); +} + +/* Consult with the oracle whether we shouldn't demote a certain global variable. */ +JS_REQUIRES_STACK bool +Oracle::isGlobalSlotUndemotable(JSContext* cx, unsigned slot) const +{ + return _globalDontDemote.get(GlobalSlotHash(cx, slot)); +} + +/* Tell the oracle that a certain slot at a certain stack slot should not be demoted. */ +JS_REQUIRES_STACK void +Oracle::markStackSlotUndemotable(JSContext* cx, unsigned slot, const void* pc) +{ + _stackDontDemote.set(StackSlotHash(cx, slot, pc)); +} + +JS_REQUIRES_STACK void +Oracle::markStackSlotUndemotable(JSContext* cx, unsigned slot) +{ + markStackSlotUndemotable(cx, slot, cx->regs->pc); +} + +/* Consult with the oracle whether we shouldn't demote a certain slot. */ +JS_REQUIRES_STACK bool +Oracle::isStackSlotUndemotable(JSContext* cx, unsigned slot, const void* pc) const +{ + return _stackDontDemote.get(StackSlotHash(cx, slot, pc)); +} + +JS_REQUIRES_STACK bool +Oracle::isStackSlotUndemotable(JSContext* cx, unsigned slot) const +{ + return isStackSlotUndemotable(cx, slot, cx->regs->pc); +} + +/* Tell the oracle that a certain slot at a certain bytecode location should not be demoted. */ +void +Oracle::markInstructionUndemotable(jsbytecode* pc) +{ + _pcDontDemote.set(PCHash(pc)); +} + +/* Consult with the oracle whether we shouldn't demote a certain bytecode location. */ +bool +Oracle::isInstructionUndemotable(jsbytecode* pc) const +{ + return _pcDontDemote.get(PCHash(pc)); +} + +/* Tell the oracle that the instruction at bytecode location should use a stronger (slower) test for -0. */ +void +Oracle::markInstructionSlowZeroTest(jsbytecode* pc) +{ + _pcSlowZeroTest.set(PCHash(pc)); +} + +/* Consult with the oracle whether we should use a stronger (slower) test for -0. */ +bool +Oracle::isInstructionSlowZeroTest(jsbytecode* pc) const +{ + return _pcSlowZeroTest.get(PCHash(pc)); +} + +void +Oracle::clearDemotability() +{ + _stackDontDemote.reset(); + _globalDontDemote.reset(); + _pcDontDemote.reset(); + _pcSlowZeroTest.reset(); +} + +JS_REQUIRES_STACK void +TraceRecorder::markSlotUndemotable(LinkableFragment* f, unsigned slot) +{ + if (slot < f->nStackTypes) { + traceMonitor->oracle->markStackSlotUndemotable(cx, slot); + return; + } + + uint16* gslots = f->globalSlots->data(); + traceMonitor->oracle->markGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); +} + +JS_REQUIRES_STACK void +TraceRecorder::markSlotUndemotable(LinkableFragment* f, unsigned slot, const void* pc) +{ + if (slot < f->nStackTypes) { + traceMonitor->oracle->markStackSlotUndemotable(cx, slot, pc); + return; + } + + uint16* gslots = f->globalSlots->data(); + traceMonitor->oracle->markGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); +} + +static JS_REQUIRES_STACK bool +IsSlotUndemotable(Oracle* oracle, JSContext* cx, LinkableFragment* f, unsigned slot, const void* ip) +{ + if (slot < f->nStackTypes) + return !oracle || oracle->isStackSlotUndemotable(cx, slot, ip); + + uint16* gslots = f->globalSlots->data(); + return !oracle || oracle->isGlobalSlotUndemotable(cx, gslots[slot - f->nStackTypes]); +} + +class FrameInfoCache +{ + struct HashPolicy + { + typedef FrameInfo *Lookup; + static HashNumber hash(const FrameInfo* fi) { + size_t len = sizeof(FrameInfo) + fi->callerHeight * sizeof(JSValueType); + HashNumber h = 0; + const unsigned char *s = (const unsigned char*)fi; + for (size_t i = 0; i < len; i++, s++) + h = JS_ROTATE_LEFT32(h, 4) ^ *s; + return h; + } + + static bool match(const FrameInfo* fi1, const FrameInfo* fi2) { + if (memcmp(fi1, fi2, sizeof(FrameInfo)) != 0) + return false; + return memcmp(fi1->get_typemap(), fi2->get_typemap(), + fi1->callerHeight * sizeof(JSValueType)) == 0; + } + }; + + typedef HashSet FrameSet; + + FrameSet set; + VMAllocator *allocator; + + public: + + FrameInfoCache(VMAllocator *allocator); + + void reset() { + set.clear(); + } + + FrameInfo *memoize(FrameInfo *fi) { + FrameSet::AddPtr p = set.lookupForAdd(fi); + if (!p) { + FrameInfo* n = (FrameInfo*) + allocator->alloc(sizeof(FrameInfo) + fi->callerHeight * sizeof(JSValueType)); + memcpy(n, fi, sizeof(FrameInfo) + fi->callerHeight * sizeof(JSValueType)); + if (!set.add(p, n)) + return NULL; + } + + return *p; + } +}; + +FrameInfoCache::FrameInfoCache(VMAllocator *allocator) + : allocator(allocator) +{ + if (!set.init()) + OUT_OF_MEMORY_ABORT("FrameInfoCache::FrameInfoCache(): out of memory"); +} + +#define PC_HASH_COUNT 1024 + +static void +Blacklist(jsbytecode* pc) +{ + AUDIT(blacklisted); + JS_ASSERT(*pc == JSOP_TRACE || *pc == JSOP_NOTRACE); + *pc = JSOP_NOTRACE; +} + +static void +Unblacklist(JSScript *script, jsbytecode *pc) +{ + JS_ASSERT(*pc == JSOP_NOTRACE || *pc == JSOP_TRACE); + if (*pc == JSOP_NOTRACE) { + *pc = JSOP_TRACE; + +#ifdef JS_METHODJIT + /* This code takes care of unblacklisting in the method JIT. */ + js::mjit::ResetTraceHint(script, pc, GET_UINT16(pc), false); +#endif + } +} + +static bool +IsBlacklisted(jsbytecode* pc) +{ + if (*pc == JSOP_NOTRACE) + return true; + if (*pc == JSOP_CALL) + return *(pc + JSOP_CALL_LENGTH) == JSOP_NOTRACE; + return false; +} + +static void +Backoff(TraceMonitor *tm, jsbytecode* pc, Fragment* tree = NULL) +{ + /* N.B. This code path cannot assume the recorder is/is not alive. */ + RecordAttemptMap &table = *tm->recordAttempts; + if (RecordAttemptMap::AddPtr p = table.lookupForAdd(pc)) { + if (p->value++ > (BL_ATTEMPTS * MAXPEERS)) { + p->value = 0; + Blacklist(pc); + return; + } + } else { + table.add(p, pc, 0); + } + + if (tree) { + tree->hits() -= BL_BACKOFF; + + /* + * In case there is no entry or no table (due to OOM) or some + * serious imbalance in the recording-attempt distribution on a + * multitree, give each tree another chance to blacklist here as + * well. + */ + if (++tree->recordAttempts > BL_ATTEMPTS) + Blacklist(pc); + } +} + +static void +ResetRecordingAttempts(TraceMonitor *tm, jsbytecode* pc) +{ + RecordAttemptMap &table = *tm->recordAttempts; + if (RecordAttemptMap::Ptr p = table.lookup(pc)) + p->value = 0; +} + +static inline size_t +FragmentHash(const void *ip, JSObject* globalObj, uint32 globalShape, uint32 argc) +{ + uintptr_t h = HASH_SEED; + HashAccum(h, uintptr_t(ip), FRAGMENT_TABLE_MASK); + HashAccum(h, uintptr_t(globalObj), FRAGMENT_TABLE_MASK); + HashAccum(h, uintptr_t(globalShape), FRAGMENT_TABLE_MASK); + HashAccum(h, uintptr_t(argc), FRAGMENT_TABLE_MASK); + return size_t(h); +} + +static void +RawLookupFirstPeer(TraceMonitor* tm, const void *ip, JSObject* globalObj, + uint32 globalShape, uint32 argc, + TreeFragment*& firstInBucket, TreeFragment**& prevTreeNextp) +{ + size_t h = FragmentHash(ip, globalObj, globalShape, argc); + TreeFragment** ppf = &tm->vmfragments[h]; + firstInBucket = *ppf; + for (; TreeFragment* pf = *ppf; ppf = &pf->next) { + if (pf->globalObj == globalObj && + pf->globalShape == globalShape && + pf->ip == ip && + pf->argc == argc) { + prevTreeNextp = ppf; + return; + } + } + prevTreeNextp = ppf; + return; +} + +static TreeFragment* +LookupLoop(TraceMonitor* tm, const void *ip, JSObject* globalObj, + uint32 globalShape, uint32 argc) +{ + TreeFragment *_, **prevTreeNextp; + RawLookupFirstPeer(tm, ip, globalObj, globalShape, argc, _, prevTreeNextp); + return *prevTreeNextp; +} + +static TreeFragment* +LookupOrAddLoop(TraceMonitor* tm, const void *ip, JSObject* globalObj, + uint32 globalShape, uint32 argc) +{ + TreeFragment *firstInBucket, **prevTreeNextp; + RawLookupFirstPeer(tm, ip, globalObj, globalShape, argc, firstInBucket, prevTreeNextp); + if (TreeFragment *f = *prevTreeNextp) + return f; + + verbose_only( + uint32_t profFragID = (LogController.lcbits & LC_FragProfile) + ? (++(tm->lastFragID)) : 0; + ) + TreeFragment* f = new (*tm->dataAlloc) TreeFragment(ip, tm->dataAlloc, tm->oracle, + globalObj, globalShape, + argc verbose_only(, profFragID)); + f->root = f; /* f is the root of a new tree */ + *prevTreeNextp = f; /* insert f at the end of the vmfragments bucket-list */ + f->next = NULL; + f->first = f; /* initialize peer-list at f */ + f->peer = NULL; + return f; +} + +static TreeFragment* +AddNewPeerToPeerList(TraceMonitor* tm, TreeFragment* peer) +{ + JS_ASSERT(peer); + verbose_only( + uint32_t profFragID = (LogController.lcbits & LC_FragProfile) + ? (++(tm->lastFragID)) : 0; + ) + TreeFragment* f = new (*tm->dataAlloc) TreeFragment(peer->ip, tm->dataAlloc, tm->oracle, + peer->globalObj, peer->globalShape, + peer->argc verbose_only(, profFragID)); + f->root = f; /* f is the root of a new tree */ + f->first = peer->first; /* add f to peer list */ + f->peer = peer->peer; + peer->peer = f; + /* only the |first| Fragment of a peer list needs a valid |next| field */ + debug_only(f->next = (TreeFragment*)0xcdcdcdcd); + return f; +} + +JS_REQUIRES_STACK void +TreeFragment::initialize(JSContext* cx, SlotList *globalSlots, bool speculate) +{ + this->dependentTrees.clear(); + this->linkedTrees.clear(); + this->globalSlots = globalSlots; + + /* Capture the coerced type of each active slot in the type map. */ + this->typeMap.captureTypes(cx, globalObj, *globalSlots, 0 /* callDepth */, speculate); + this->nStackTypes = this->typeMap.length() - globalSlots->length(); + this->spOffsetAtEntry = cx->regs->sp - cx->fp()->base(); + +#ifdef DEBUG + this->treeFileName = cx->fp()->script()->filename; + this->treeLineNumber = js_FramePCToLineNumber(cx, cx->fp()); + this->treePCOffset = FramePCOffset(cx, cx->fp()); +#endif + this->script = cx->fp()->script(); + this->gcthings.clear(); + this->shapes.clear(); + this->unstableExits = NULL; + this->sideExits.clear(); + + /* Determine the native frame layout at the entry point. */ + this->nativeStackBase = (nStackTypes - (cx->regs->sp - cx->fp()->base())) * + sizeof(double); + this->maxNativeStackSlots = nStackTypes; + this->maxCallDepth = 0; + this->execs = 0; + this->iters = 0; +} + +UnstableExit* +TreeFragment::removeUnstableExit(VMSideExit* exit) +{ + /* Now erase this exit from the unstable exit list. */ + UnstableExit** tail = &this->unstableExits; + for (UnstableExit* uexit = this->unstableExits; uexit != NULL; uexit = uexit->next) { + if (uexit->exit == exit) { + *tail = uexit->next; + return *tail; + } + tail = &uexit->next; + } + JS_NOT_REACHED("exit not in unstable exit list"); + return NULL; +} + +#ifdef DEBUG +static void +AssertTreeIsUnique(TraceMonitor* tm, TreeFragment* f) +{ + JS_ASSERT(f->root == f); + + /* + * Check for duplicate entry type maps. This is always wrong and hints at + * trace explosion since we are trying to stabilize something without + * properly connecting peer edges. + */ + for (TreeFragment* peer = LookupLoop(tm, f->ip, f->globalObj, f->globalShape, f->argc); + peer != NULL; + peer = peer->peer) { + if (!peer->code() || peer == f) + continue; + JS_ASSERT(!f->typeMap.matches(peer->typeMap)); + } +} +#endif + +static void +AttemptCompilation(TraceMonitor *tm, JSObject* globalObj, + JSScript* script, jsbytecode* pc, uint32 argc) +{ + /* If we already permanently blacklisted the location, undo that. */ + Unblacklist(script, pc); + ResetRecordingAttempts(tm, pc); + + /* Breathe new life into all peer fragments at the designated loop header. */ + TreeFragment* f = LookupLoop(tm, pc, globalObj, globalObj->shape(), argc); + if (!f) { + /* + * If the global object's shape changed, we can't easily find the + * corresponding loop header via a hash table lookup. In this + * we simply bail here and hope that the fragment has another + * outstanding compilation attempt. This case is extremely rare. + */ + return; + } + JS_ASSERT(f->root == f); + f = f->first; + while (f) { + JS_ASSERT(f->root == f); + --f->recordAttempts; + f->hits() = HOTLOOP; + f = f->peer; + } +} + +static const CallInfo * +fcallinfo(LIns *ins) +{ + return ins->isop(LIR_calld) ? ins->callInfo() : NULL; +} + +/* + * Determine whether this operand is guaranteed to not overflow the specified + * integer operation. + */ +static void +ChecksRequired(LOpcode op, LIns* op1, LIns* op2, + bool* needsOverflowCheck, bool* needsNegZeroCheck) +{ + Interval x = Interval::of(op1, 3); + Interval y = Interval::of(op2, 3); + Interval z(0, 0); + + switch (op) { + case LIR_addi: + z = Interval::add(x, y); + *needsNegZeroCheck = false; + break; + + case LIR_subi: + z = Interval::sub(x, y); + *needsNegZeroCheck = false; + break; + + case LIR_muli: { + z = Interval::mul(x, y); + // A would-be negative zero result can only occur if we have + // mul(0, -n) or mul(-n, 0), where n != 0. In particular, a multiply + // where one operand is a positive immediate cannot result in negative + // zero. + // + // This assumes that -0 cannot be an operand; if one had occurred we + // would have already exited the trace in order to promote the + // computation back to doubles. + *needsNegZeroCheck = (x.canBeZero() && y.canBeNegative()) || + (y.canBeZero() && x.canBeNegative()); + break; + } + + default: + JS_NOT_REACHED("needsOverflowCheck"); + } + + *needsOverflowCheck = z.hasOverflowed; +} + +/* + * JSStackFrame::numActualArgs is only defined for function frames. Since the + * actual arguments of the entry frame are kept on trace, argc is included in + * the tuple identifying a fragment so that two fragments for the same loop but + * recorded with different number of actual arguments are treated as two + * completely separate trees. For this particular use, we define the number of + * actuals for global and eval frames to be 0. + */ +static inline uintN +entryFrameArgc(JSContext *cx) +{ + JSStackFrame *fp = cx->fp(); + return fp->isGlobalFrame() || fp->isEvalFrame() ? 0 : fp->numActualArgs(); +} + +template +static JS_REQUIRES_STACK JS_ALWAYS_INLINE bool +VisitStackAndArgs(Visitor &visitor, JSStackFrame *fp, JSStackFrame *next, Value *stack) +{ + if (JS_LIKELY(!next->hasOverflowArgs())) + return visitor.visitStackSlots(stack, next->formalArgsEnd() - stack, fp); + + /* + * In the case of nactual > nformal, the formals are copied by the VM onto + * the top of the stack. We only want to mark the formals once, so we + * carefully mark only the canonical actual arguments (as defined by + * JSStackFrame::canonicalActualArg). + */ + uintN nactual = next->numActualArgs(); + Value *actuals = next->actualArgs(); + size_t nstack = (actuals - 2 /* callee,this */) - stack; + if (!visitor.visitStackSlots(stack, nstack, fp)) + return false; + uintN nformal = next->numFormalArgs(); + Value *formals = next->formalArgs(); + if (!visitor.visitStackSlots(formals - 2, 2 + nformal, fp)) + return false; + return visitor.visitStackSlots(actuals + nformal, nactual - nformal, fp); +} + +/* + * Visit the values in the given JSStackFrame that the tracer cares about. This + * visitor function is (implicitly) the primary definition of the native stack + * area layout. There are a few other independent pieces of code that must be + * maintained to assume the same layout. They are marked like this: + * + * Duplicate native stack layout computation: see VisitFrameSlots header comment. + */ +template +static JS_REQUIRES_STACK bool +VisitFrameSlots(Visitor &visitor, JSContext *cx, unsigned depth, JSStackFrame *fp, + JSStackFrame *next) +{ + JS_ASSERT_IF(!next, cx->fp() == fp); + + if (depth > 0 && !VisitFrameSlots(visitor, cx, depth-1, fp->prev(), fp)) + return false; + + if (depth == 0) { + if (fp->isGlobalFrame()) { + visitor.setStackSlotKind("global"); + Value *base = fp->slots() + fp->globalScript()->nfixed; + if (next) + return VisitStackAndArgs(visitor, fp, next, base); + return visitor.visitStackSlots(base, cx->regs->sp - base, fp); + } + + if (JS_UNLIKELY(fp->isEvalFrame())) { + visitor.setStackSlotKind("eval"); + if (!visitor.visitStackSlots(&fp->calleeValue(), 2, fp)) + return false; + } else { + /* + * Only the bottom function frame must visit its arguments; for all + * other frames, arguments are visited by the prev-frame. + */ + visitor.setStackSlotKind("args"); + uintN nformal = fp->numFormalArgs(); + if (!visitor.visitStackSlots(fp->formalArgs() - 2, 2 + nformal, fp)) + return false; + if (JS_UNLIKELY(fp->hasOverflowArgs())) { + if (!visitor.visitStackSlots(fp->actualArgs() + nformal, + fp->numActualArgs() - nformal, fp)) + return false; + } + } + } + + JS_ASSERT(fp->isFunctionFrame()); + + /* + * We keep two members of JSStackFrame on trace: the args obj pointer and + * the scope chain pointer. The visitor must take care not to treat these + * as js::Value-typed variables, since they are unboxed pointers. + * Moreover, JSStackFrame compresses the args obj pointer with nactual, so + * fp->addressOfArgs() is not really a JSObject**: the visitor must treat + * !fp->hasArgsObj() as a null args obj pointer. Hence, visitFrameObjPtr + * is only passed a void *. + */ + visitor.setStackSlotKind("arguments"); + if (!visitor.visitFrameObjPtr(fp->addressOfArgs(), fp)) + return false; + visitor.setStackSlotKind("scopeChain"); + if (!visitor.visitFrameObjPtr(fp->addressOfScopeChain(), fp)) + return false; + + visitor.setStackSlotKind("slots"); + if (next) + return VisitStackAndArgs(visitor, fp, next, fp->slots()); + return visitor.visitStackSlots(fp->slots(), cx->regs->sp - fp->slots(), fp); +} + +// Number of native frame slots used for 'special' values between args and vars. +// Currently the two values are |arguments| (args object) and |scopeChain|. +const int SPECIAL_FRAME_SLOTS = 2; + +template +static JS_REQUIRES_STACK JS_ALWAYS_INLINE bool +VisitStackSlots(Visitor &visitor, JSContext *cx, unsigned callDepth) +{ + return VisitFrameSlots(visitor, cx, callDepth, cx->fp(), NULL); +} + +template +static JS_REQUIRES_STACK JS_ALWAYS_INLINE void +VisitGlobalSlots(Visitor &visitor, JSContext *cx, JSObject *globalObj, + unsigned ngslots, uint16 *gslots) +{ + for (unsigned n = 0; n < ngslots; ++n) { + unsigned slot = gslots[n]; + visitor.visitGlobalSlot(&globalObj->getSlotRef(slot), n, slot); + } +} + +class AdjustCallerTypeVisitor; + +template +static JS_REQUIRES_STACK JS_ALWAYS_INLINE void +VisitGlobalSlots(Visitor &visitor, JSContext *cx, SlotList &gslots) +{ + VisitGlobalSlots(visitor, cx, cx->fp()->scopeChain().getGlobal(), + gslots.length(), gslots.data()); +} + + +template +static JS_REQUIRES_STACK JS_ALWAYS_INLINE void +VisitSlots(Visitor& visitor, JSContext* cx, JSObject* globalObj, + unsigned callDepth, unsigned ngslots, uint16* gslots) +{ + if (VisitStackSlots(visitor, cx, callDepth)) + VisitGlobalSlots(visitor, cx, globalObj, ngslots, gslots); +} + +template +static JS_REQUIRES_STACK JS_ALWAYS_INLINE void +VisitSlots(Visitor& visitor, JSContext* cx, unsigned callDepth, + unsigned ngslots, uint16* gslots) +{ + VisitSlots(visitor, cx, cx->fp()->scopeChain().getGlobal(), + callDepth, ngslots, gslots); +} + +template +static JS_REQUIRES_STACK JS_ALWAYS_INLINE void +VisitSlots(Visitor &visitor, JSContext *cx, JSObject *globalObj, + unsigned callDepth, const SlotList& slots) +{ + VisitSlots(visitor, cx, globalObj, callDepth, slots.length(), + slots.data()); +} + +template +static JS_REQUIRES_STACK JS_ALWAYS_INLINE void +VisitSlots(Visitor &visitor, JSContext *cx, unsigned callDepth, + const SlotList& slots) +{ + VisitSlots(visitor, cx, cx->fp()->scopeChain().getGlobal(), + callDepth, slots.length(), slots.data()); +} + + +class SlotVisitorBase { +#if defined JS_JIT_SPEW +protected: + char const *mStackSlotKind; +public: + SlotVisitorBase() : mStackSlotKind(NULL) {} + JS_ALWAYS_INLINE const char *stackSlotKind() { return mStackSlotKind; } + JS_ALWAYS_INLINE void setStackSlotKind(char const *k) { + mStackSlotKind = k; + } +#else +public: + JS_ALWAYS_INLINE const char *stackSlotKind() { return NULL; } + JS_ALWAYS_INLINE void setStackSlotKind(char const *k) {} +#endif +}; + +struct CountSlotsVisitor : public SlotVisitorBase +{ + unsigned mCount; + bool mDone; + const void* mStop; +public: + JS_ALWAYS_INLINE CountSlotsVisitor(const void* stop = NULL) : + mCount(0), + mDone(false), + mStop(stop) + {} + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { + if (mDone) + return false; + if (mStop && size_t(((const Value *)mStop) - vp) < count) { + mCount += size_t(((const Value *)mStop) - vp); + mDone = true; + return false; + } + mCount += count; + return true; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(void* p, JSStackFrame* fp) { + if (mDone) + return false; + if (mStop && mStop == p) { + mDone = true; + return false; + } + mCount++; + return true; + } + + JS_ALWAYS_INLINE unsigned count() { + return mCount; + } + + JS_ALWAYS_INLINE bool stopped() { + return mDone; + } +}; + +static JS_REQUIRES_STACK JS_ALWAYS_INLINE unsigned +CountStackAndArgs(JSStackFrame *next, Value *stack) +{ + if (JS_LIKELY(!next->hasOverflowArgs())) + return (Value *)next - stack; + size_t nvals = (next->formalArgs() - 2 /* callee, this */) - stack; + JS_ASSERT(nvals == unsigned((next->actualArgs() - 2) - stack) + (2 + next->numActualArgs())); + return nvals; +} + +static JS_ALWAYS_INLINE uintN +NumSlotsBeforeFixed(JSStackFrame *fp) +{ + uintN numArgs = fp->isEvalFrame() ? 0 : Max(fp->numActualArgs(), fp->numFormalArgs()); + return 2 + numArgs + SPECIAL_FRAME_SLOTS; +} + +/* + * Calculate the total number of native frame slots we need from this frame all + * the way back to the entry frame, including the current stack usage. + * + * Duplicate native stack layout computation: see VisitFrameSlots header comment. + */ +JS_REQUIRES_STACK unsigned +NativeStackSlots(JSContext *cx, unsigned callDepth) +{ + JSStackFrame *fp = cx->fp(); + JSStackFrame *next = NULL; + unsigned slots = 0; + unsigned depth = callDepth; + + for (; depth > 0; --depth, next = fp, fp = fp->prev()) { + JS_ASSERT(fp->isFunctionFrame() && !fp->isEvalFrame()); + slots += SPECIAL_FRAME_SLOTS; + if (next) + slots += CountStackAndArgs(next, fp->slots()); + else + slots += cx->regs->sp - fp->slots(); + } + + Value *start; + if (fp->isGlobalFrame()) { + start = fp->slots() + fp->globalScript()->nfixed; + } else { + start = fp->slots(); + slots += NumSlotsBeforeFixed(fp); + } + if (next) + slots += CountStackAndArgs(next, start); + else + slots += cx->regs->sp - start; + +#ifdef DEBUG + CountSlotsVisitor visitor; + VisitStackSlots(visitor, cx, callDepth); + JS_ASSERT(visitor.count() == slots && !visitor.stopped()); +#endif + return slots; +} + +class CaptureTypesVisitor : public SlotVisitorBase +{ + JSContext* mCx; + JSValueType* mTypeMap; + JSValueType* mPtr; + Oracle * mOracle; + +public: + JS_ALWAYS_INLINE CaptureTypesVisitor(JSContext* cx, Oracle *oracle, + JSValueType* typeMap, bool speculate) + : mCx(cx), + mTypeMap(typeMap), + mPtr(typeMap), + mOracle(speculate ? oracle : NULL) + {} + + JS_REQUIRES_STACK JS_ALWAYS_INLINE void + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { + JSValueType type = getCoercedType(*vp); + if (type == JSVAL_TYPE_INT32 && (!mOracle || mOracle->isGlobalSlotUndemotable(mCx, slot))) + type = JSVAL_TYPE_DOUBLE; + JS_ASSERT(type != JSVAL_TYPE_BOXED); + debug_only_printf(LC_TMTracer, + "capture type global%d: %c\n", + n, TypeToChar(type)); + *mPtr++ = type; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitStackSlots(Value *vp, int count, JSStackFrame* fp) { + for (int i = 0; i < count; ++i) { + JSValueType type = getCoercedType(vp[i]); + if (type == JSVAL_TYPE_INT32 && (!mOracle || mOracle->isStackSlotUndemotable(mCx, length()))) + type = JSVAL_TYPE_DOUBLE; + JS_ASSERT(type != JSVAL_TYPE_BOXED); + debug_only_printf(LC_TMTracer, + "capture type %s%d: %c\n", + stackSlotKind(), i, TypeToChar(type)); + *mPtr++ = type; + } + return true; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(void* p, JSStackFrame* fp) { + JSValueType type = getFrameObjPtrTraceType(p, fp); + debug_only_printf(LC_TMTracer, + "capture type %s%d: %c\n", + stackSlotKind(), 0, TypeToChar(type)); + *mPtr++ = type; + return true; + } + + JS_ALWAYS_INLINE uintptr_t length() { + return mPtr - mTypeMap; + } +}; + +void +TypeMap::set(unsigned stackSlots, unsigned ngslots, + const JSValueType* stackTypeMap, const JSValueType* globalTypeMap) +{ + setLength(ngslots + stackSlots); + memcpy(data(), stackTypeMap, stackSlots * sizeof(JSValueType)); + memcpy(data() + stackSlots, globalTypeMap, ngslots * sizeof(JSValueType)); +} + +/* + * Capture the type map for the selected slots of the global object and currently pending + * stack frames. + */ +JS_REQUIRES_STACK void +TypeMap::captureTypes(JSContext* cx, JSObject* globalObj, SlotList& slots, unsigned callDepth, + bool speculate) +{ + setLength(NativeStackSlots(cx, callDepth) + slots.length()); + CaptureTypesVisitor visitor(cx, oracle, data(), speculate); + VisitSlots(visitor, cx, globalObj, callDepth, slots); + JS_ASSERT(visitor.length() == length()); +} + +JS_REQUIRES_STACK void +TypeMap::captureMissingGlobalTypes(JSContext* cx, + JSObject* globalObj, SlotList& slots, unsigned stackSlots, + bool speculate) +{ + unsigned oldSlots = length() - stackSlots; + int diff = slots.length() - oldSlots; + JS_ASSERT(diff >= 0); + setLength(length() + diff); + CaptureTypesVisitor visitor(cx, oracle, data() + stackSlots + oldSlots, speculate); + VisitGlobalSlots(visitor, cx, globalObj, diff, slots.data() + oldSlots); +} + +/* Compare this type map to another one and see whether they match. */ +bool +TypeMap::matches(TypeMap& other) const +{ + if (length() != other.length()) + return false; + return !memcmp(data(), other.data(), length()); +} + +void +TypeMap::fromRaw(JSValueType* other, unsigned numSlots) +{ + unsigned oldLength = length(); + setLength(length() + numSlots); + for (unsigned i = 0; i < numSlots; i++) + get(oldLength + i) = other[i]; +} + +/* + * Use the provided storage area to create a new type map that contains the + * partial type map with the rest of it filled up from the complete type + * map. + */ +static void +MergeTypeMaps(JSValueType** partial, unsigned* plength, JSValueType* complete, unsigned clength, JSValueType* mem) +{ + unsigned l = *plength; + JS_ASSERT(l < clength); + memcpy(mem, *partial, l * sizeof(JSValueType)); + memcpy(mem + l, complete + l, (clength - l) * sizeof(JSValueType)); + *partial = mem; + *plength = clength; +} + +/* + * Specializes a tree to any specifically missing globals, including any + * dependent trees. + */ +static JS_REQUIRES_STACK void +SpecializeTreesToLateGlobals(JSContext* cx, TreeFragment* root, JSValueType* globalTypeMap, + unsigned numGlobalSlots) +{ + for (unsigned i = root->nGlobalTypes(); i < numGlobalSlots; i++) + root->typeMap.add(globalTypeMap[i]); + + JS_ASSERT(root->nGlobalTypes() == numGlobalSlots); + + for (unsigned i = 0; i < root->dependentTrees.length(); i++) { + TreeFragment* tree = root->dependentTrees[i]; + if (tree->code() && tree->nGlobalTypes() < numGlobalSlots) + SpecializeTreesToLateGlobals(cx, tree, globalTypeMap, numGlobalSlots); + } + for (unsigned i = 0; i < root->linkedTrees.length(); i++) { + TreeFragment* tree = root->linkedTrees[i]; + if (tree->code() && tree->nGlobalTypes() < numGlobalSlots) + SpecializeTreesToLateGlobals(cx, tree, globalTypeMap, numGlobalSlots); + } +} + +/* Specializes a tree to any missing globals, including any dependent trees. */ +static JS_REQUIRES_STACK void +SpecializeTreesToMissingGlobals(JSContext* cx, JSObject* globalObj, TreeFragment* root) +{ + /* If we already have a bunch of peer trees, try to be as generic as possible. */ + size_t count = 0; + for (TreeFragment *f = root->first; f; f = f->peer, ++count); + bool speculate = count < MAXPEERS-1; + + root->typeMap.captureMissingGlobalTypes(cx, globalObj, *root->globalSlots, root->nStackTypes, + speculate); + JS_ASSERT(root->globalSlots->length() == root->typeMap.length() - root->nStackTypes); + + SpecializeTreesToLateGlobals(cx, root, root->globalTypeMap(), root->nGlobalTypes()); +} + +static void +ResetJITImpl(JSContext* cx, TraceMonitor *tm); + +#ifdef MOZ_TRACEVIS +static JS_INLINE void +ResetJIT(JSContext* cx, TraceMonitor *tm, TraceVisFlushReason r) +{ + LogTraceVisEvent(cx, S_RESET, r); + ResetJITImpl(cx, tm); +} +#else +# define ResetJIT(cx, tm, reason) ResetJITImpl(cx, tm) +#endif + +void +FlushJITCache(JSContext *cx, TraceMonitor *tm) +{ + ResetJIT(cx, tm, FR_OOM); +} + +static void +TrashTree(TreeFragment* f); + +JS_REQUIRES_STACK +TraceRecorder::TraceRecorder(JSContext* cx, TraceMonitor *tm, + VMSideExit* anchor, VMFragment* fragment, + unsigned stackSlots, unsigned ngslots, JSValueType* typeMap, + VMSideExit* innermost, JSScript* outerScript, jsbytecode* outerPC, + uint32 outerArgc, bool speculate) + : cx(cx), + traceMonitor(tm), + oracle(speculate ? tm->oracle : NULL), + fragment(fragment), + tree(fragment->root), + globalObj(tree->globalObj), + outerScript(outerScript), + outerPC(outerPC), + outerArgc(outerArgc), + anchor(anchor), + cx_ins(NULL), + eos_ins(NULL), + eor_ins(NULL), + loopLabel(NULL), + importTypeMap(&tempAlloc(), tm->oracle), + lirbuf(new (tempAlloc()) LirBuffer(tempAlloc())), + mark(*traceMonitor->traceAlloc), + numSideExitsBefore(tree->sideExits.length()), + tracker(), + nativeFrameTracker(), + global_slots(NULL), + callDepth(anchor ? anchor->calldepth : 0), + atoms(FrameAtomBase(cx, cx->fp())), + consts(JSScript::isValidOffset(cx->fp()->script()->constOffset) + ? cx->fp()->script()->consts()->vector + : NULL), + strictModeCode_ins(NULL), + cfgMerges(&tempAlloc()), + trashSelf(false), + whichTreesToTrash(&tempAlloc()), + guardedShapeTable(cx), + initDepth(0), + hadNewInit(false), +#ifdef DEBUG + addPropShapeBefore(NULL), +#endif + rval_ins(NULL), + native_rval_ins(NULL), + newobj_ins(NULL), + pendingSpecializedNative(NULL), + pendingUnboxSlot(NULL), + pendingGuardCondition(NULL), + pendingGlobalSlotsToSet(cx), + pendingLoop(true), + generatedSpecializedNative(), + tempTypeMap(cx), + w(&tempAlloc(), lirbuf) +{ + JS_ASSERT(globalObj == cx->fp()->scopeChain().getGlobal()); + JS_ASSERT(globalObj->hasOwnShape()); + JS_ASSERT(cx->regs->pc == (jsbytecode*)fragment->ip); + +#ifdef JS_METHODJIT + if (TRACE_PROFILER(cx)) + AbortProfiling(cx); +#endif + + JS_ASSERT(JS_THREAD_DATA(cx)->onTraceCompartment == NULL); + JS_ASSERT(JS_THREAD_DATA(cx)->profilingCompartment == NULL); + JS_ASSERT(JS_THREAD_DATA(cx)->recordingCompartment == NULL); + JS_THREAD_DATA(cx)->recordingCompartment = cx->compartment; + +#ifdef DEBUG + lirbuf->printer = new (tempAlloc()) LInsPrinter(tempAlloc(), TM_NUM_USED_ACCS); +#endif + + /* + * Reset the fragment state we care about in case we got a recycled + * fragment. This includes resetting any profiling data we might have + * accumulated. + */ + fragment->lastIns = NULL; + fragment->setCode(NULL); + fragment->lirbuf = lirbuf; + verbose_only( fragment->profCount = 0; ) + verbose_only( fragment->nStaticExits = 0; ) + verbose_only( fragment->nCodeBytes = 0; ) + verbose_only( fragment->nExitBytes = 0; ) + verbose_only( fragment->guardNumberer = 1; ) + verbose_only( fragment->guardsForFrag = NULL; ) + verbose_only( fragment->loopLabel = NULL; ) + + /* + * Don't change fragment->profFragID, though. Once the identity of the + * Fragment is set up (for profiling purposes), we can't change it. + */ + + if (!guardedShapeTable.init()) + OUT_OF_MEMORY_ABORT("TraceRecorder::TraceRecorder: out of memory"); + +#ifdef JS_JIT_SPEW + debug_only_print0(LC_TMMinimal, "\n"); + debug_only_printf(LC_TMMinimal, "Recording starting from %s:%u@%u (FragID=%06u)\n", + tree->treeFileName, tree->treeLineNumber, tree->treePCOffset, + fragment->profFragID); + + debug_only_printf(LC_TMTracer, "globalObj=%p, shape=%d\n", + (void*)this->globalObj, this->globalObj->shape()); + debug_only_printf(LC_TMTreeVis, "TREEVIS RECORD FRAG=%p ANCHOR=%p\n", (void*)fragment, + (void*)anchor); +#endif + + /* This creates the LIR writer pipeline. */ + w.init(&LogController); + + w.start(); + + for (int i = 0; i < NumSavedRegs; ++i) + w.paramp(i, 1); +#ifdef DEBUG + for (int i = 0; i < NumSavedRegs; ++i) + w.name(lirbuf->savedRegs[i], regNames[REGNUM(Assembler::savedRegs[i])]); +#endif + + lirbuf->state = w.name(w.paramp(0, 0), "state"); + + if (fragment == fragment->root) { + w.comment("begin-loop"); + InitConst(loopLabel) = w.label(); + } + w.comment("begin-setup"); + + // if profiling, drop a label, so the assembler knows to put a + // frag-entry-counter increment at this point. If there's a + // loopLabel, use that; else we'll have to make a dummy label + // especially for this purpose. + verbose_only( if (LogController.lcbits & LC_FragProfile) { + LIns* entryLabel = NULL; + if (fragment == fragment->root) { + entryLabel = loopLabel; + } else { + entryLabel = w.label(); + } + NanoAssert(entryLabel); + NanoAssert(!fragment->loopLabel); + fragment->loopLabel = entryLabel; + }) + + lirbuf->sp = w.name(w.ldpStateField(sp), "sp"); + lirbuf->rp = w.name(w.ldpStateField(rp), "rp"); + InitConst(cx_ins) = w.name(w.ldpStateField(cx), "cx"); + InitConst(eos_ins) = w.name(w.ldpStateField(eos), "eos"); + InitConst(eor_ins) = w.name(w.ldpStateField(eor), "eor"); + + strictModeCode_ins = w.name(w.immi(cx->fp()->script()->strictModeCode), "strict"); + + /* If we came from exit, we might not have enough global types. */ + if (tree->globalSlots->length() > tree->nGlobalTypes()) + SpecializeTreesToMissingGlobals(cx, globalObj, tree); + + /* read into registers all values on the stack and all globals we know so far */ + import(tree, lirbuf->sp, stackSlots, ngslots, callDepth, typeMap); + + if (fragment == fragment->root) { + /* + * We poll the operation callback request flag. It is updated asynchronously whenever + * the callback is to be invoked. We can use w.nameImmpNonGC here as JIT-ed code is per + * thread and cannot outlive the corresponding JSThreadData. + */ + w.comment("begin-interruptFlags-check"); + /* FIXME: See bug 621140 for moving interruptCounter to the compartment. */ +#ifdef JS_THREADSAFE + void *interrupt = (void*) &cx->runtime->interruptCounter; +#else + void *interrupt = (void*) &JS_THREAD_DATA(cx)->interruptFlags; +#endif + LIns* flagptr = w.nameImmpNonGC(interrupt); + LIns* x = w.ldiVolatile(flagptr); + guard(true, w.eqi0(x), TIMEOUT_EXIT); + w.comment("end-interruptFlags-check"); + + /* + * Count the number of iterations run by a trace, so that we can blacklist if + * the trace runs too few iterations to be worthwhile. Do this only if the methodjit + * is on--otherwise we must try to trace as much as possible. + */ +#ifdef JS_METHODJIT + if (cx->methodJitEnabled) { + w.comment("begin-count-loop-iterations"); + LIns* counterPtr = w.nameImmpNonGC((void *) &traceMonitor->iterationCounter); + LIns* counterValue = w.ldiVolatile(counterPtr); + LIns* test = w.ltiN(counterValue, LOOP_COUNT_MAX); + LIns *branch = w.jfUnoptimizable(test); + /* + * stiVolatile() uses ACCSET_STORE_ANY; If LICM is implemented + * (bug 545406) this counter will need its own region. + */ + w.stiVolatile(w.addi(counterValue, w.immi(1)), counterPtr); + w.label(branch); + w.comment("end-count-loop-iterations"); + } +#endif + } + + /* + * If we are attached to a tree call guard, make sure the guard the inner + * tree exited from is what we expect it to be. + */ + if (anchor && anchor->exitType == NESTED_EXIT) { + LIns* nested_ins = w.ldpStateField(outermostTreeExitGuard); + guard(true, w.eqp(nested_ins, w.nameImmpNonGC(innermost)), NESTED_EXIT); + } + + w.comment("end-setup"); +} + +TraceRecorder::~TraceRecorder() +{ + /* Should already have been adjusted by callers before calling delete. */ + JS_ASSERT(traceMonitor->recorder != this); + + JS_ASSERT(JS_THREAD_DATA(cx)->profilingCompartment == NULL); + JS_ASSERT(&JS_THREAD_DATA(cx)->recordingCompartment->traceMonitor == traceMonitor); + JS_THREAD_DATA(cx)->recordingCompartment = NULL; + + if (trashSelf) + TrashTree(fragment->root); + + for (unsigned int i = 0; i < whichTreesToTrash.length(); i++) + TrashTree(whichTreesToTrash[i]); + + /* Purge the tempAlloc used during recording. */ + tempAlloc().reset(); + + forgetGuardedShapes(); +} + +inline bool +TraceMonitor::outOfMemory() const +{ + return dataAlloc->outOfMemory() || + tempAlloc->outOfMemory() || + traceAlloc->outOfMemory(); +} + +/* + * This function destroys the recorder after a successful recording, possibly + * starting a suspended outer recorder. + */ +AbortableRecordingStatus +TraceRecorder::finishSuccessfully() +{ + JS_ASSERT(!traceMonitor->profile); + JS_ASSERT(traceMonitor->recorder == this); + JS_ASSERT(fragment->lastIns && fragment->code()); + + AUDIT(traceCompleted); + mark.commit(); + + /* Grab local copies of members needed after destruction of |this|. */ + JSContext* localcx = cx; + TraceMonitor* localtm = traceMonitor; + + localtm->recorder = NULL; + /* We can't (easily) use js_delete() here because the constructor is private. */ + this->~TraceRecorder(); + js_free(this); + + /* Catch OOM that occurred during recording. */ + if (localtm->outOfMemory() || OverfullJITCache(localcx, localtm)) { + ResetJIT(localcx, localtm, FR_OOM); + return ARECORD_ABORTED; + } + return ARECORD_COMPLETED; +} + +/* This function aborts a recorder and any pending outer recorders. */ +JS_REQUIRES_STACK TraceRecorder::AbortResult +TraceRecorder::finishAbort(const char* reason) +{ + JS_ASSERT(!traceMonitor->profile); + JS_ASSERT(traceMonitor->recorder == this); + + AUDIT(recorderAborted); +#ifdef DEBUG + debug_only_printf(LC_TMMinimal | LC_TMAbort, + "Abort recording of tree %s:%d@%d at %s:%d@%d: %s.\n", + tree->treeFileName, + tree->treeLineNumber, + tree->treePCOffset, + cx->fp()->script()->filename, + js_FramePCToLineNumber(cx, cx->fp()), + FramePCOffset(cx, cx->fp()), + reason); +#endif + Backoff(traceMonitor, (jsbytecode*) fragment->root->ip, fragment->root); + + /* + * If this is the primary trace and we didn't succeed compiling, trash the + * tree. Otherwise, remove the VMSideExits we added while recording, which + * are about to be invalid. + * + * BIG FAT WARNING: resetting the length is only a valid strategy as long as + * there may be only one recorder active for a single TreeInfo at a time. + * Otherwise, we may be throwing away another recorder's valid side exits. + */ + if (fragment->root == fragment) { + TrashTree(fragment->toTreeFragment()); + } else { + JS_ASSERT(numSideExitsBefore <= fragment->root->sideExits.length()); + fragment->root->sideExits.setLength(numSideExitsBefore); + } + + /* Grab local copies of members needed after destruction of |this|. */ + JSContext* localcx = cx; + TraceMonitor* localtm = traceMonitor; + + localtm->recorder = NULL; + /* We can't (easily) use js_delete() here because the constructor is private. */ + this->~TraceRecorder(); + js_free(this); + + /* Catch OOM that occurred during recording. */ + if (localtm->outOfMemory() || OverfullJITCache(localcx, localtm)) { + ResetJIT(localcx, localtm, FR_OOM); + return JIT_RESET; + } + return NORMAL_ABORT; +} + +inline LIns* +TraceRecorder::w_immpObjGC(JSObject* obj) +{ + JS_ASSERT(obj); + tree->gcthings.addUnique(ObjectValue(*obj)); + return w.immpNonGC((void*)obj); +} + +inline LIns* +TraceRecorder::w_immpFunGC(JSFunction* fun) +{ + JS_ASSERT(fun); + tree->gcthings.addUnique(ObjectValue(*fun)); + return w.immpNonGC((void*)fun); +} + +inline LIns* +TraceRecorder::w_immpStrGC(JSString* str) +{ + JS_ASSERT(str); + tree->gcthings.addUnique(StringValue(str)); + return w.immpNonGC((void*)str); +} + +inline LIns* +TraceRecorder::w_immpShapeGC(const Shape* shape) +{ + JS_ASSERT(shape); + tree->shapes.addUnique(shape); + return w.immpNonGC((void*)shape); +} + +inline LIns* +TraceRecorder::w_immpIdGC(jsid id) +{ + if (JSID_IS_GCTHING(id)) + tree->gcthings.addUnique(IdToValue(id)); + return w.immpNonGC((void*)JSID_BITS(id)); +} + +ptrdiff_t +TraceRecorder::nativeGlobalSlot(const Value* p) const +{ + JS_ASSERT(isGlobal(p)); + return ptrdiff_t(p - globalObj->slots); +} + +/* Determine the offset in the native global frame for a jsval we track. */ +ptrdiff_t +TraceRecorder::nativeGlobalOffset(const Value* p) const +{ + return nativeGlobalSlot(p) * sizeof(double); +} + +/* Determine whether a value is a global stack slot. */ +bool +TraceRecorder::isGlobal(const Value* p) const +{ + return (size_t(p - globalObj->slots) < globalObj->numSlots()); +} + +bool +TraceRecorder::isVoidPtrGlobal(const void* p) const +{ + return isGlobal((const Value *)p); +} + +/* + * Return the offset in the native stack for the given jsval. More formally, + * |p| must be the address of a jsval that is represented in the native stack + * area. The return value is the offset, from TracerState::stackBase, in bytes, + * where the native representation of |*p| is stored. To get the offset + * relative to TracerState::sp, subtract TreeFragment::nativeStackBase. + */ +JS_REQUIRES_STACK ptrdiff_t +TraceRecorder::nativeStackOffsetImpl(const void* p) const +{ + CountSlotsVisitor visitor(p); + VisitStackSlots(visitor, cx, callDepth); + size_t offset = visitor.count() * sizeof(double); + + /* + * If it's not in a pending frame, it must be on the stack of the current + * frame above sp but below fp->slots() + script->nslots. + */ + if (!visitor.stopped()) { + const Value *vp = (const Value *)p; + JS_ASSERT(size_t(vp - cx->fp()->slots()) < cx->fp()->numSlots()); + offset += size_t(vp - cx->regs->sp) * sizeof(double); + } + return offset; +} + +JS_REQUIRES_STACK inline ptrdiff_t +TraceRecorder::nativeStackOffset(const Value* p) const +{ + return nativeStackOffsetImpl(p); +} + +JS_REQUIRES_STACK inline ptrdiff_t +TraceRecorder::nativeStackSlotImpl(const void* p) const +{ + return nativeStackOffsetImpl(p) / sizeof(double); +} + +JS_REQUIRES_STACK inline ptrdiff_t +TraceRecorder::nativeStackSlot(const Value* p) const +{ + return nativeStackSlotImpl(p); +} + +/* + * Return the offset, from TracerState:sp, for the given jsval. Shorthand for: + * -TreeFragment::nativeStackBase + nativeStackOffset(p). + */ +inline JS_REQUIRES_STACK ptrdiff_t +TraceRecorder::nativespOffsetImpl(const void* p) const +{ + return -tree->nativeStackBase + nativeStackOffsetImpl(p); +} + +inline JS_REQUIRES_STACK ptrdiff_t +TraceRecorder::nativespOffset(const Value* p) const +{ + return nativespOffsetImpl(p); +} + +/* Track the maximum number of native frame slots we need during execution. */ +inline void +TraceRecorder::trackNativeStackUse(unsigned slots) +{ + if (slots > tree->maxNativeStackSlots) + tree->maxNativeStackSlots = slots; +} + +/* + * Unbox a jsval into a slot. Slots are wide enough to hold double values + * directly (instead of storing a pointer to them). We assert instead of + * type checking. The caller must ensure the types are compatible. + */ +static inline void +ValueToNative(const Value &v, JSValueType type, double* slot) +{ + JS_ASSERT(type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET); + if (type > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET) + v.unboxNonDoubleTo((uint64 *)slot); + else if (type == JSVAL_TYPE_INT32) + *(int32_t *)slot = v.isInt32() ? v.toInt32() : (int32_t)v.toDouble(); + else + *(double *)slot = v.toNumber(); + +#ifdef DEBUG + int32_t _; + switch (type) { + case JSVAL_TYPE_NONFUNOBJ: { + JS_ASSERT(!IsFunctionObject(v)); + debug_only_printf(LC_TMTracer, + "object<%p:%s> ", (void*)*(JSObject **)slot, + v.toObject().getClass()->name); + return; + } + + case JSVAL_TYPE_INT32: + JS_ASSERT(v.isInt32() || (v.isDouble() && JSDOUBLE_IS_INT32(v.toDouble(), &_))); + debug_only_printf(LC_TMTracer, "int<%d> ", *(jsint *)slot); + return; + + case JSVAL_TYPE_DOUBLE: + JS_ASSERT(v.isNumber()); + debug_only_printf(LC_TMTracer, "double<%g> ", *(jsdouble *)slot); + return; + + case JSVAL_TYPE_BOXED: + JS_NOT_REACHED("found jsval type in an entry type map"); + return; + + case JSVAL_TYPE_STRING: + JS_ASSERT(v.isString()); + debug_only_printf(LC_TMTracer, "string<%p> ", (void*)*(JSString**)slot); + return; + + case JSVAL_TYPE_NULL: + JS_ASSERT(v.isNull()); + debug_only_print0(LC_TMTracer, "null "); + return; + + case JSVAL_TYPE_BOOLEAN: + JS_ASSERT(v.isBoolean()); + debug_only_printf(LC_TMTracer, "special<%d> ", *(JSBool*)slot); + return; + + case JSVAL_TYPE_UNDEFINED: + JS_ASSERT(v.isUndefined()); + debug_only_print0(LC_TMTracer, "undefined "); + return; + + case JSVAL_TYPE_MAGIC: + JS_ASSERT(v.isMagic()); + debug_only_print0(LC_TMTracer, "hole "); + return; + + case JSVAL_TYPE_FUNOBJ: { + JS_ASSERT(IsFunctionObject(v)); + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, &v.toObject()); +#if defined JS_JIT_SPEW + if (LogController.lcbits & LC_TMTracer) { + char funName[40]; + if (fun->atom) + JS_PutEscapedFlatString(funName, sizeof funName, ATOM_TO_STRING(fun->atom), 0); + else + strcpy(funName, "unnamed"); + LogController.printf("function<%p:%s> ", (void*)*(JSObject **)slot, funName); + } +#endif + return; + } + default: + JS_NOT_REACHED("unexpected type"); + break; + } +#endif +} + +void +TraceMonitor::flush() +{ + /* flush should only be called after all recorders have been aborted. */ + JS_ASSERT(!recorder); + JS_ASSERT(!profile); + AUDIT(cacheFlushed); + + // recover profiling data from expiring Fragments + verbose_only( + for (size_t i = 0; i < FRAGMENT_TABLE_SIZE; ++i) { + for (TreeFragment *f = vmfragments[i]; f; f = f->next) { + JS_ASSERT(f->root == f); + for (TreeFragment *p = f; p; p = p->peer) + FragProfiling_FragFinalizer(p, this); + } + } + ) + + verbose_only( + for (Seq* f = branches; f; f = f->tail) + FragProfiling_FragFinalizer(f->head, this); + ) + + flushEpoch++; + +#ifdef JS_METHODJIT + if (loopProfiles) { + for (LoopProfileMap::Enum e(*loopProfiles); !e.empty(); e.popFront()) { + jsbytecode *pc = e.front().key; + LoopProfile *prof = e.front().value; + /* This code takes care of resetting all methodjit state. */ + js::mjit::ResetTraceHint(prof->entryScript, pc, GET_UINT16(pc), true); + } + } +#endif + + frameCache->reset(); + dataAlloc->reset(); + traceAlloc->reset(); + codeAlloc->reset(); + tempAlloc->reset(); + oracle->clear(); + loopProfiles->clear(); + + for (size_t i = 0; i < MONITOR_N_GLOBAL_STATES; ++i) { + globalStates[i].globalShape = -1; + globalStates[i].globalSlots = new (*dataAlloc) SlotList(dataAlloc); + } + + assembler = new (*dataAlloc) Assembler(*codeAlloc, *dataAlloc, *dataAlloc, core, + &LogController, avmplus::AvmCore::config); + verbose_only( branches = NULL; ) + + PodArrayZero(vmfragments); + tracedScripts.clear(); + + needFlush = JS_FALSE; +} + +inline bool +IsShapeAboutToBeFinalized(JSContext *cx, const js::Shape *shape) +{ + JSRuntime *rt = cx->runtime; + if (rt->gcCurrentCompartment != NULL) + return false; + + return !shape->marked(); +} + +inline bool +HasUnreachableGCThings(JSContext *cx, TreeFragment *f) +{ + /* + * We do not check here for dead scripts as JSScript is not a GC thing. + * Instead PurgeScriptFragments is used to remove dead script fragments. + * See bug 584860. + */ + if (IsAboutToBeFinalized(cx, f->globalObj)) + return true; + Value* vp = f->gcthings.data(); + for (unsigned len = f->gcthings.length(); len; --len) { + Value &v = *vp++; + JS_ASSERT(v.isMarkable()); + if (IsAboutToBeFinalized(cx, v.toGCThing())) + return true; + } + const Shape** shapep = f->shapes.data(); + for (unsigned len = f->shapes.length(); len; --len) { + const Shape* shape = *shapep++; + if (IsShapeAboutToBeFinalized(cx, shape)) + return true; + } + return false; +} + +void +TraceMonitor::sweep(JSContext *cx) +{ + JS_ASSERT(!ontrace()); + debug_only_print0(LC_TMTracer, "Purging fragments with dead things"); + + bool shouldAbortRecording = false; + TreeFragment *recorderTree = NULL; + if (recorder) { + recorderTree = recorder->getTree(); + shouldAbortRecording = HasUnreachableGCThings(cx, recorderTree); + } + + for (size_t i = 0; i < FRAGMENT_TABLE_SIZE; ++i) { + TreeFragment** fragp = &vmfragments[i]; + while (TreeFragment* frag = *fragp) { + TreeFragment* peer = frag; + do { + if (HasUnreachableGCThings(cx, peer)) + break; + peer = peer->peer; + } while (peer); + if (peer) { + debug_only_printf(LC_TMTracer, + "TreeFragment peer %p has dead gc thing." + "Disconnecting tree %p with ip %p\n", + (void *) peer, (void *) frag, frag->ip); + JS_ASSERT(frag->root == frag); + *fragp = frag->next; + do { + verbose_only( FragProfiling_FragFinalizer(frag, this); ); + if (recorderTree == frag) + shouldAbortRecording = true; + TrashTree(frag); + frag = frag->peer; + } while (frag); + } else { + fragp = &frag->next; + } + } + } + + if (shouldAbortRecording) + recorder->finishAbort("dead GC things"); +} + +void +TraceMonitor::mark(JSTracer *trc) +{ + TracerState* state = tracerState; + while (state) { + if (state->nativeVp) + MarkValueRange(trc, state->nativeVpLen, state->nativeVp, "nativeVp"); + state = state->prev; + } +} + +/* + * Box a value from the native stack back into the Value format. + */ +static inline void +NativeToValue(JSContext* cx, Value& v, JSValueType type, double* slot) +{ + if (type == JSVAL_TYPE_DOUBLE) { + v.setNumber(*slot); + } else if (JS_LIKELY(type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET)) { + v.boxNonDoubleFrom(type, (uint64 *)slot); + } else if (type == JSVAL_TYPE_STRORNULL) { + JSString *str = *(JSString **)slot; + v = str ? StringValue(str) : NullValue(); + } else if (type == JSVAL_TYPE_OBJORNULL) { + JSObject *obj = *(JSObject **)slot; + v = obj ? ObjectValue(*obj) : NullValue(); + } else { + JS_ASSERT(type == JSVAL_TYPE_BOXED); + JS_STATIC_ASSERT(sizeof(Value) == sizeof(double)); + v = *(Value *)slot; + } + +#ifdef DEBUG + switch (type) { + case JSVAL_TYPE_NONFUNOBJ: + JS_ASSERT(!IsFunctionObject(v)); + debug_only_printf(LC_TMTracer, + "object<%p:%s> ", + (void*) &v.toObject(), + v.toObject().getClass()->name); + break; + case JSVAL_TYPE_INT32: + debug_only_printf(LC_TMTracer, "int<%d> ", v.toInt32()); + break; + case JSVAL_TYPE_DOUBLE: + debug_only_printf(LC_TMTracer, "double<%g> ", v.toNumber()); + break; + case JSVAL_TYPE_STRING: + debug_only_printf(LC_TMTracer, "string<%p> ", (void*)v.toString()); + break; + case JSVAL_TYPE_NULL: + JS_ASSERT(v.isNull()); + debug_only_print0(LC_TMTracer, "null "); + break; + case JSVAL_TYPE_BOOLEAN: + debug_only_printf(LC_TMTracer, "bool<%d> ", v.toBoolean()); + break; + case JSVAL_TYPE_UNDEFINED: + JS_ASSERT(v.isUndefined()); + debug_only_print0(LC_TMTracer, "undefined "); + break; + case JSVAL_TYPE_MAGIC: + debug_only_printf(LC_TMTracer, "magic<%d> ", v.whyMagic()); + break; + case JSVAL_TYPE_FUNOBJ: + JS_ASSERT(IsFunctionObject(v)); +#if defined JS_JIT_SPEW + if (LogController.lcbits & LC_TMTracer) { + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, &v.toObject()); + char funName[40]; + if (fun->atom) + JS_PutEscapedFlatString(funName, sizeof funName, ATOM_TO_STRING(fun->atom), 0); + else + strcpy(funName, "unnamed"); + LogController.printf("function<%p:%s> ", (void*) &v.toObject(), funName); + } +#endif + break; + case JSVAL_TYPE_STRORNULL: + debug_only_printf(LC_TMTracer, "nullablestr<%p> ", v.isNull() ? NULL : (void *)v.toString()); + break; + case JSVAL_TYPE_OBJORNULL: + debug_only_printf(LC_TMTracer, "nullablestr<%p> ", v.isNull() ? NULL : (void *)&v.toObject()); + break; + case JSVAL_TYPE_BOXED: + debug_only_printf(LC_TMTracer, "box<%llx> ", (long long unsigned int)v.asRawBits()); + break; + default: + JS_NOT_REACHED("unexpected type"); + break; + } +#endif +} + +void +ExternNativeToValue(JSContext* cx, Value& v, JSValueType type, double* slot) +{ + return NativeToValue(cx, v, type, slot); +} + +class BuildNativeFrameVisitor : public SlotVisitorBase +{ + JSContext *mCx; + JSValueType *mTypeMap; + double *mGlobal; + double *mStack; +public: + BuildNativeFrameVisitor(JSContext *cx, + JSValueType *typemap, + double *global, + double *stack) : + mCx(cx), + mTypeMap(typemap), + mGlobal(global), + mStack(stack) + {} + + JS_REQUIRES_STACK JS_ALWAYS_INLINE void + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { + debug_only_printf(LC_TMTracer, "global%d: ", n); + ValueToNative(*vp, *mTypeMap++, &mGlobal[slot]); + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitStackSlots(Value *vp, int count, JSStackFrame* fp) { + for (int i = 0; i < count; ++i) { + debug_only_printf(LC_TMTracer, "%s%d: ", stackSlotKind(), i); + ValueToNative(*vp++, *mTypeMap++, mStack++); + } + return true; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(void* p, JSStackFrame* fp) { + debug_only_printf(LC_TMTracer, "%s%d: ", stackSlotKind(), 0); + if (p == fp->addressOfScopeChain()) + *(JSObject **)mStack = &fp->scopeChain(); + else + *(JSObject **)mStack = fp->hasArgsObj() ? &fp->argsObj() : NULL; +#ifdef DEBUG + if (*mTypeMap == JSVAL_TYPE_NULL) { + JS_ASSERT(*(JSObject **)mStack == NULL); + debug_only_print0(LC_TMTracer, "null "); + } else { + JS_ASSERT(*mTypeMap == JSVAL_TYPE_NONFUNOBJ); + JS_ASSERT(!(*(JSObject **)p)->isFunction()); + debug_only_printf(LC_TMTracer, + "object<%p:%s> ", *(void **)p, + (*(JSObject **)p)->getClass()->name); + } +#endif + mTypeMap++; + mStack++; + return true; + } +}; + +static JS_REQUIRES_STACK void +BuildNativeFrame(JSContext *cx, JSObject *globalObj, unsigned callDepth, + unsigned ngslots, uint16 *gslots, + JSValueType *typeMap, double *global, double *stack) +{ + BuildNativeFrameVisitor visitor(cx, typeMap, global, stack); + VisitSlots(visitor, cx, globalObj, callDepth, ngslots, gslots); + debug_only_print0(LC_TMTracer, "\n"); +} + +class FlushNativeGlobalFrameVisitor : public SlotVisitorBase +{ + JSContext *mCx; + JSValueType *mTypeMap; + double *mGlobal; +public: + FlushNativeGlobalFrameVisitor(JSContext *cx, + JSValueType *typeMap, + double *global) : + mCx(cx), + mTypeMap(typeMap), + mGlobal(global) + {} + + JS_REQUIRES_STACK JS_ALWAYS_INLINE void + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { + debug_only_printf(LC_TMTracer, "global%d=", n); + JS_ASSERT(JS_THREAD_DATA(mCx)->waiveGCQuota); + NativeToValue(mCx, *vp, *mTypeMap++, &mGlobal[slot]); + } +}; + +class FlushNativeStackFrameVisitor : public SlotVisitorBase +{ + JSContext *mCx; + const JSValueType *mInitTypeMap; + const JSValueType *mTypeMap; + double *mStack; +public: + FlushNativeStackFrameVisitor(JSContext *cx, + const JSValueType *typeMap, + double *stack) : + mCx(cx), + mInitTypeMap(typeMap), + mTypeMap(typeMap), + mStack(stack) + {} + + const JSValueType* getTypeMap() + { + return mTypeMap; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { + JS_ASSERT(JS_THREAD_DATA(mCx)->waiveGCQuota); + for (size_t i = 0; i < count; ++i) { + debug_only_printf(LC_TMTracer, "%s%u=", stackSlotKind(), unsigned(i)); + NativeToValue(mCx, *vp, *mTypeMap, mStack); + vp++; + mTypeMap++; + mStack++; + } + return true; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(void* p, JSStackFrame* fp) { + JS_ASSERT(JS_THREAD_DATA(mCx)->waiveGCQuota); + debug_only_printf(LC_TMTracer, "%s%u=", stackSlotKind(), 0); + JSObject *frameobj = *(JSObject **)mStack; + JS_ASSERT((frameobj == NULL) == (*mTypeMap == JSVAL_TYPE_NULL)); + if (p == fp->addressOfArgs()) { + if (frameobj) { + JS_ASSERT_IF(fp->hasArgsObj(), frameobj == &fp->argsObj()); + fp->setArgsObj(*frameobj); + JS_ASSERT(frameobj->isArguments()); + if (frameobj->isNormalArguments()) + frameobj->setPrivate(fp); + else + JS_ASSERT(!frameobj->getPrivate()); + debug_only_printf(LC_TMTracer, + "argsobj<%p> ", + (void *)frameobj); + } else { + JS_ASSERT(!fp->hasArgsObj()); + debug_only_print0(LC_TMTracer, + "argsobj "); + } + /* else, SynthesizeFrame has initialized fp->args.nactual */ + } else { + JS_ASSERT(p == fp->addressOfScopeChain()); + if (frameobj->isCall() && + !frameobj->getPrivate() && + fp->maybeCallee() == frameobj->getCallObjCallee()) + { + JS_ASSERT(&fp->scopeChain() == JSStackFrame::sInvalidScopeChain); + frameobj->setPrivate(fp); + fp->setScopeChainAndCallObj(*frameobj); + } else { + fp->setScopeChainNoCallObj(*frameobj); + } + debug_only_printf(LC_TMTracer, + "scopechain<%p> ", + (void *)frameobj); + } +#ifdef DEBUG + JSValueType type = *mTypeMap; + if (type == JSVAL_TYPE_NULL) { + debug_only_print0(LC_TMTracer, "null "); + } else { + JS_ASSERT(type == JSVAL_TYPE_NONFUNOBJ); + JS_ASSERT(!frameobj->isFunction()); + debug_only_printf(LC_TMTracer, + "object<%p:%s> ", + *(void **)p, + frameobj->getClass()->name); + } +#endif + mTypeMap++; + mStack++; + return true; + } +}; + +/* Box the given native frame into a JS frame. This is infallible. */ +static JS_REQUIRES_STACK void +FlushNativeGlobalFrame(JSContext *cx, JSObject *globalObj, double *global, unsigned ngslots, + uint16 *gslots, JSValueType *typemap) +{ + FlushNativeGlobalFrameVisitor visitor(cx, typemap, global); + VisitGlobalSlots(visitor, cx, globalObj, ngslots, gslots); + debug_only_print0(LC_TMTracer, "\n"); +} + +/* + * Returns the number of values on the native stack, excluding the innermost + * frame. This walks all FrameInfos on the native frame stack and sums the + * slot usage of each frame. + */ +static int32 +StackDepthFromCallStack(TracerState* state, uint32 callDepth) +{ + int32 nativeStackFramePos = 0; + + // Duplicate native stack layout computation: see VisitFrameSlots header comment. + for (FrameInfo** fip = state->callstackBase; fip < state->rp + callDepth; fip++) + nativeStackFramePos += (*fip)->callerHeight; + return nativeStackFramePos; +} + +/* + * Generic function to read upvars on trace from slots of active frames. + * T Traits type parameter. Must provide static functions: + * interp_get(fp, slot) Read the value out of an interpreter frame. + * native_slot(argc, slot) Return the position of the desired value in the on-trace + * stack frame (with position 0 being callee). + * + * upvarLevel Static level of the function containing the upvar definition + * slot Identifies the value to get. The meaning is defined by the traits type. + * callDepth Call depth of current point relative to trace entry + */ +template +inline JSValueType +GetUpvarOnTrace(JSContext* cx, uint32 upvarLevel, int32 slot, uint32 callDepth, double* result) +{ + TracerState* state = JS_TRACE_MONITOR_ON_TRACE(cx)->tracerState; + FrameInfo** fip = state->rp + callDepth; + + /* + * First search the FrameInfo call stack for an entry containing our + * upvar, namely one with level == upvarLevel. The first FrameInfo is a + * transition from the entry frame to some callee. However, it is not + * known (from looking at the FrameInfo) whether the entry frame had a + * callee. Rather than special-case this or insert more logic into the + * loop, instead just stop before that FrameInfo (i.e. |> base| instead of + * |>= base|), and let the code after the loop handle it. + */ + int32 stackOffset = StackDepthFromCallStack(state, callDepth); + while (--fip > state->callstackBase) { + FrameInfo* fi = *fip; + + /* + * The loop starts aligned to the top of the stack, so move down to the first meaningful + * callee. Then read the callee directly from the frame. + */ + stackOffset -= fi->callerHeight; + JSObject* callee = *(JSObject**)(&state->stackBase[stackOffset]); + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, callee); + uintN calleeLevel = fun->u.i.script->staticLevel; + if (calleeLevel == upvarLevel) { + /* + * Now find the upvar's value in the native stack. stackOffset is + * the offset of the start of the activation record corresponding + * to *fip in the native stack. + */ + uint32 native_slot = T::native_slot(fi->callerArgc, slot); + *result = state->stackBase[stackOffset + native_slot]; + return fi->get_typemap()[native_slot]; + } + } + + // Next search the trace entry frame, which is not in the FrameInfo stack. + if (state->outermostTree->script->staticLevel == upvarLevel) { + uint32 argc = state->outermostTree->argc; + uint32 native_slot = T::native_slot(argc, slot); + *result = state->stackBase[native_slot]; + return state->callstackBase[0]->get_typemap()[native_slot]; + } + + /* + * If we did not find the upvar in the frames for the active traces, + * then we simply get the value from the interpreter state. + */ + JS_ASSERT(upvarLevel < UpvarCookie::UPVAR_LEVEL_LIMIT); + JSStackFrame* fp = cx->findFrameAtLevel(upvarLevel); + Value v = T::interp_get(fp, slot); + JSValueType type = getCoercedType(v); + ValueToNative(v, type, result); + return type; +} + +// For this traits type, 'slot' is the argument index, which may be -2 for callee. +struct UpvarArgTraits { + static Value interp_get(JSStackFrame* fp, int32 slot) { + return fp->formalArg(slot); + } + + static uint32 native_slot(uint32 argc, int32 slot) { + return 2 /*callee,this*/ + slot; + } +}; + +uint32 JS_FASTCALL +GetUpvarArgOnTrace(JSContext* cx, uint32 upvarLevel, int32 slot, uint32 callDepth, double* result) +{ + return GetUpvarOnTrace(cx, upvarLevel, slot, callDepth, result); +} + +// For this traits type, 'slot' is an index into the local slots array. +struct UpvarVarTraits { + static Value interp_get(JSStackFrame* fp, int32 slot) { + return fp->slots()[slot]; + } + + static uint32 native_slot(uint32 argc, int32 slot) { + return 4 /*callee,this,arguments,scopeChain*/ + argc + slot; + } +}; + +uint32 JS_FASTCALL +GetUpvarVarOnTrace(JSContext* cx, uint32 upvarLevel, int32 slot, uint32 callDepth, double* result) +{ + return GetUpvarOnTrace(cx, upvarLevel, slot, callDepth, result); +} + +/* + * For this traits type, 'slot' is an index into the stack area (within slots, + * after nfixed) of a frame with no function. (On trace, the top-level frame is + * the only one that can have no function.) + */ +struct UpvarStackTraits { + static Value interp_get(JSStackFrame* fp, int32 slot) { + return fp->slots()[slot + fp->numFixed()]; + } + + static uint32 native_slot(uint32 argc, int32 slot) { + /* + * Locals are not imported by the tracer when the frame has no + * function, so we do not add fp->getFixedCount(). + */ + JS_ASSERT(argc == 0); + return slot; + } +}; + +uint32 JS_FASTCALL +GetUpvarStackOnTrace(JSContext* cx, uint32 upvarLevel, int32 slot, uint32 callDepth, + double* result) +{ + return GetUpvarOnTrace(cx, upvarLevel, slot, callDepth, result); +} + +// Parameters needed to access a value from a closure on trace. +struct ClosureVarInfo +{ + uint32 slot; +#ifdef DEBUG + uint32 callDepth; +#endif +}; + +/* + * Generic function to read upvars from Call objects of active heavyweight functions. + * call Callee Function object in which the upvar is accessed. + */ +template +inline uint32 +GetFromClosure(JSContext* cx, JSObject* call, const ClosureVarInfo* cv, double* result) +{ + JS_ASSERT(call->isCall()); + +#ifdef DEBUG + TracerState* state = JS_TRACE_MONITOR_ON_TRACE(cx)->tracerState; + FrameInfo** fip = state->rp + cv->callDepth; + int32 stackOffset = StackDepthFromCallStack(state, cv->callDepth); + while (--fip > state->callstackBase) { + FrameInfo* fi = *fip; + + /* + * The loop starts aligned to the top of the stack, so move down to the first meaningful + * callee. Then read the callee directly from the frame. + */ + stackOffset -= fi->callerHeight; + JSObject* callee = *(JSObject**)(&state->stackBase[stackOffset]); + if (callee == call) { + // This is not reachable as long as the tracer guards on the identity of the callee's + // parent when making a call: + // + // - We can only reach this point if we execute JSOP_LAMBDA on trace, then call the + // function created by the lambda, and then execute a JSOP_NAME on trace. + // - Each time we execute JSOP_LAMBDA we get a function with a different parent. + // - When we execute the call to the new function, we exit trace because the parent + // is different. + JS_NOT_REACHED("JSOP_NAME variable found in outer trace"); + } + } +#endif + + // We already guarded on trace that we aren't touching an outer tree's entry frame + VOUCH_DOES_NOT_REQUIRE_STACK(); + JSStackFrame* fp = (JSStackFrame*) call->getPrivate(); + JS_ASSERT(fp != cx->fp()); + + Value v; + if (fp) { + v = T::get_slot(fp, cv->slot); + } else { + /* + * Get the value from the object. We know we have a Call object, and + * that our slot index is fine, so don't monkey around with calling the + * property getter (which just looks in the slot) or calling + * js_GetReservedSlot. Just get the slot directly. Note the static + * asserts in jsfun.cpp which make sure Call objects use slots. + */ + JS_ASSERT(cv->slot < T::slot_count(call)); + v = T::get_slot(call, cv->slot); + } + JSValueType type = getCoercedType(v); + ValueToNative(v, type, result); + return type; +} + +struct ArgClosureTraits +{ + // Get the right frame slots to use our slot index with. + // See also UpvarArgTraits. + static inline Value get_slot(JSStackFrame* fp, unsigned slot) { + JS_ASSERT(slot < fp->numFormalArgs()); + return fp->formalArg(slot); + } + + // Get the right object slots to use our slot index with. + static inline Value get_slot(JSObject* obj, unsigned slot) { + return obj->getSlot(slot_offset(obj) + slot); + } + + // Get the offset of our object slots from the object's slots pointer. + static inline uint32 slot_offset(JSObject* obj) { + return JSObject::CALL_RESERVED_SLOTS; + } + + // Get the maximum slot index of this type that should be allowed + static inline uint16 slot_count(JSObject* obj) { + return obj->getCallObjCalleeFunction()->nargs; + } + +private: + ArgClosureTraits(); +}; + +uint32 JS_FASTCALL +GetClosureArg(JSContext* cx, JSObject* callee, const ClosureVarInfo* cv, double* result) +{ + return GetFromClosure(cx, callee, cv, result); +} + +struct VarClosureTraits +{ + // See also UpvarVarTraits. + static inline Value get_slot(JSStackFrame* fp, unsigned slot) { + JS_ASSERT(slot < fp->fun()->script()->bindings.countVars()); + return fp->slots()[slot]; + } + + static inline Value get_slot(JSObject* obj, unsigned slot) { + return obj->getSlot(slot_offset(obj) + slot); + } + + static inline uint32 slot_offset(JSObject* obj) { + return JSObject::CALL_RESERVED_SLOTS + + obj->getCallObjCalleeFunction()->nargs; + } + + static inline uint16 slot_count(JSObject* obj) { + return obj->getCallObjCalleeFunction()->script()->bindings.countVars(); + } + +private: + VarClosureTraits(); +}; + +uint32 JS_FASTCALL +GetClosureVar(JSContext* cx, JSObject* callee, const ClosureVarInfo* cv, double* result) +{ + return GetFromClosure(cx, callee, cv, result); +} + +/** + * Box the given native stack frame into the virtual machine stack. This + * is infallible. + * + * @param callDepth the distance between the entry frame into our trace and + * cx->fp() when we make this call. If this is not called as a + * result of a nested exit, callDepth is 0. + * @param mp an array of JSValueType that indicate what the types of the things + * on the stack are. + * @param np pointer to the native stack. We want to copy values from here to + * the JS stack as needed. + * @return the number of things we popped off of np. + */ +static JS_REQUIRES_STACK int +FlushNativeStackFrame(JSContext* cx, unsigned callDepth, const JSValueType* mp, double* np) +{ + /* Root all string and object references first (we don't need to call the GC for this). */ + FlushNativeStackFrameVisitor visitor(cx, mp, np); + VisitStackSlots(visitor, cx, callDepth); + + debug_only_print0(LC_TMTracer, "\n"); + return visitor.getTypeMap() - mp; +} + +/* Emit load instructions onto the trace that read the initial stack state. */ +JS_REQUIRES_STACK void +TraceRecorder::importImpl(Address addr, const void* p, JSValueType t, + const char *prefix, uintN index, JSStackFrame *fp) +{ + LIns* ins; + if (t == JSVAL_TYPE_INT32) { /* demoted */ + JS_ASSERT(hasInt32Repr(*(const Value *)p)); + + /* + * Ok, we have a valid demotion attempt pending, so insert an integer + * read and promote it to double since all arithmetic operations expect + * to see doubles on entry. The first op to use this slot will emit a + * d2i cast which will cancel out the i2d we insert here. + */ + ins = w.ldi(addr); + ins = w.i2d(ins); + } else { + JS_ASSERT_IF(t != JSVAL_TYPE_BOXED && !isFrameObjPtrTraceType(t), + ((const Value *)p)->isNumber() == (t == JSVAL_TYPE_DOUBLE)); + if (t == JSVAL_TYPE_DOUBLE) { + ins = w.ldd(addr); + } else if (t == JSVAL_TYPE_BOOLEAN) { + ins = w.ldi(addr); + } else if (t == JSVAL_TYPE_UNDEFINED) { + ins = w.immiUndefined(); + } else if (t == JSVAL_TYPE_MAGIC) { + ins = w.ldi(addr); + } else { + ins = w.ldp(addr); + } + } + checkForGlobalObjectReallocation(); + tracker.set(p, ins); + +#ifdef DEBUG + char name[64]; + JS_ASSERT(strlen(prefix) < 11); + void* mark = NULL; + jsuword* localNames = NULL; + const char* funName = NULL; + JSAutoByteString funNameBytes; + if (*prefix == 'a' || *prefix == 'v') { + mark = JS_ARENA_MARK(&cx->tempPool); + JSFunction *fun = fp->fun(); + Bindings &bindings = fun->script()->bindings; + if (bindings.hasLocalNames()) + localNames = bindings.getLocalNameArray(cx, &cx->tempPool); + funName = fun->atom + ? js_AtomToPrintableString(cx, fun->atom, &funNameBytes) + : ""; + } + if (!strcmp(prefix, "argv")) { + if (index < fp->numFormalArgs()) { + JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(localNames[index]); + JSAutoByteString atomBytes; + JS_snprintf(name, sizeof name, "$%s.%s", funName, + js_AtomToPrintableString(cx, atom, &atomBytes)); + } else { + JS_snprintf(name, sizeof name, "$%s.", funName, index); + } + } else if (!strcmp(prefix, "vars")) { + JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(localNames[fp->numFormalArgs() + index]); + JSAutoByteString atomBytes; + JS_snprintf(name, sizeof name, "$%s.%s", funName, + js_AtomToPrintableString(cx, atom, &atomBytes)); + } else { + JS_snprintf(name, sizeof name, "$%s%d", prefix, index); + } + + if (mark) + JS_ARENA_RELEASE(&cx->tempPool, mark); + w.name(ins, name); + + debug_only_printf(LC_TMTracer, "import vp=%p name=%s type=%c\n", + p, name, TypeToChar(t)); +#endif +} + +JS_REQUIRES_STACK void +TraceRecorder::import(Address addr, const Value* p, JSValueType t, + const char *prefix, uintN index, JSStackFrame *fp) +{ + return importImpl(addr, p, t, prefix, index, fp); +} + +class ImportBoxedStackSlotVisitor : public SlotVisitorBase +{ + TraceRecorder &mRecorder; + LIns *mBase; + ptrdiff_t mStackOffset; + JSValueType *mTypemap; + JSStackFrame *mFp; +public: + ImportBoxedStackSlotVisitor(TraceRecorder &recorder, + LIns *base, + ptrdiff_t stackOffset, + JSValueType *typemap) : + mRecorder(recorder), + mBase(base), + mStackOffset(stackOffset), + mTypemap(typemap) + {} + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { + for (size_t i = 0; i < count; ++i) { + if (*mTypemap == JSVAL_TYPE_BOXED) { + mRecorder.import(StackAddress(mBase, mStackOffset), vp, JSVAL_TYPE_BOXED, + "jsval", i, fp); + LIns *vp_ins = mRecorder.unbox_value(*vp, + StackAddress(mBase, mStackOffset), + mRecorder.copy(mRecorder.anchor)); + mRecorder.set(vp, vp_ins); + } + vp++; + mTypemap++; + mStackOffset += sizeof(double); + } + return true; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(void* p, JSStackFrame *fp) { + JS_ASSERT(*mTypemap != JSVAL_TYPE_BOXED); + mTypemap++; + mStackOffset += sizeof(double); + return true; + } +}; + +JS_REQUIRES_STACK void +TraceRecorder::import(TreeFragment* tree, LIns* sp, unsigned stackSlots, unsigned ngslots, + unsigned callDepth, JSValueType* typeMap) +{ + /* + * If we get a partial list that doesn't have all the types (i.e. recording + * from a side exit that was recorded but we added more global slots + * later), merge the missing types from the entry type map. This is safe + * because at the loop edge we verify that we have compatible types for all + * globals (entry type and loop edge type match). While a different trace + * of the tree might have had a guard with a different type map for these + * slots we just filled in here (the guard we continue from didn't know + * about them), since we didn't take that particular guard the only way we + * could have ended up here is if that other trace had at its end a + * compatible type distribution with the entry map. Since that's exactly + * what we used to fill in the types our current side exit didn't provide, + * this is always safe to do. + */ + + JSValueType* globalTypeMap = typeMap + stackSlots; + unsigned length = tree->nGlobalTypes(); + + /* + * This is potentially the typemap of the side exit and thus shorter than + * the tree's global type map. + */ + if (ngslots < length) { + MergeTypeMaps(&globalTypeMap /* out param */, &ngslots /* out param */, + tree->globalTypeMap(), length, + (JSValueType*)alloca(sizeof(JSValueType) * length)); + } + JS_ASSERT(ngslots == tree->nGlobalTypes()); + + /* + * Check whether there are any values on the stack we have to unbox and do + * that first before we waste any time fetching the state from the stack. + */ + ImportBoxedStackSlotVisitor boxedStackVisitor(*this, sp, -tree->nativeStackBase, typeMap); + VisitStackSlots(boxedStackVisitor, cx, callDepth); + + /* + * Remember the import type map so we can lazily import later whatever + * we need. + */ + importTypeMap.set(importStackSlots = stackSlots, + importGlobalSlots = ngslots, + typeMap, globalTypeMap); +} + +JS_REQUIRES_STACK bool +TraceRecorder::isValidSlot(JSObject *obj, const Shape* shape) +{ + uint32 setflags = (js_CodeSpec[*cx->regs->pc].format & (JOF_SET | JOF_INCDEC | JOF_FOR)); + + if (setflags) { + if (!shape->hasDefaultSetter()) + RETURN_VALUE("non-stub setter", false); + if (!shape->writable()) + RETURN_VALUE("writing to a read-only property", false); + } + + /* This check applies even when setflags == 0. */ + if (setflags != JOF_SET && !shape->hasDefaultGetter()) { + JS_ASSERT(!shape->isMethod()); + RETURN_VALUE("non-stub getter", false); + } + + if (!obj->containsSlot(shape->slot)) + RETURN_VALUE("invalid-slot obj property", false); + + return true; +} + +/* Lazily import a global slot if we don't already have it in the tracker. */ +JS_REQUIRES_STACK void +TraceRecorder::importGlobalSlot(unsigned slot) +{ + JS_ASSERT(slot == uint16(slot)); + JS_ASSERT(globalObj->numSlots() <= MAX_GLOBAL_SLOTS); + + Value* vp = &globalObj->getSlotRef(slot); + JS_ASSERT(!known(vp)); + + /* Add the slot to the list of interned global slots. */ + JSValueType type; + int index = tree->globalSlots->offsetOf(uint16(slot)); + if (index == -1) { + type = getCoercedType(*vp); + if (type == JSVAL_TYPE_INT32 && (!oracle || oracle->isGlobalSlotUndemotable(cx, slot))) + type = JSVAL_TYPE_DOUBLE; + index = (int)tree->globalSlots->length(); + tree->globalSlots->add(uint16(slot)); + tree->typeMap.add(type); + SpecializeTreesToMissingGlobals(cx, globalObj, tree); + JS_ASSERT(tree->nGlobalTypes() == tree->globalSlots->length()); + } else { + type = importTypeMap[importStackSlots + index]; + } + import(EosAddress(eos_ins, slot * sizeof(double)), vp, type, "global", index, NULL); +} + +/* Lazily import a global slot if we don't already have it in the tracker. */ +JS_REQUIRES_STACK bool +TraceRecorder::lazilyImportGlobalSlot(unsigned slot) +{ + if (slot != uint16(slot)) /* we use a table of 16-bit ints, bail out if that's not enough */ + return false; + /* + * If the global object grows too large, alloca in ExecuteTree might fail, + * so abort tracing on global objects with unreasonably many slots. + */ + if (globalObj->numSlots() > MAX_GLOBAL_SLOTS) + return false; + Value* vp = &globalObj->getSlotRef(slot); + if (known(vp)) + return true; /* we already have it */ + importGlobalSlot(slot); + return true; +} + +/* Write back a value onto the stack or global frames. */ +LIns* +TraceRecorder::writeBack(LIns* ins, LIns* base, ptrdiff_t offset, bool shouldDemoteToInt32) +{ + /* + * Sink all type casts targeting the stack into the side exit by simply storing the original + * (uncasted) value. Each guard generates the side exit map based on the types of the + * last stores to every stack location, so it's safe to not perform them on-trace. + */ + JS_ASSERT(base == lirbuf->sp || base == eos_ins); + if (shouldDemoteToInt32 && IsPromotedInt32(ins)) + ins = w.demoteToInt32(ins); + + Address addr; + if (base == lirbuf->sp) { + addr = StackAddress(base, offset); + } else { + addr = EosAddress(base, offset); + unsigned slot = unsigned(offset / sizeof(double)); + (void)pendingGlobalSlotsToSet.append(slot); /* OOM is safe. */ + } + return w.st(ins, addr); +} + +/* Update the tracker, then issue a write back store. */ +JS_REQUIRES_STACK void +TraceRecorder::setImpl(void* p, LIns* i, bool shouldDemoteToInt32) +{ + JS_ASSERT(i != NULL); + checkForGlobalObjectReallocation(); + tracker.set(p, i); + + /* + * If we are writing to this location for the first time, calculate the + * offset into the native frame manually. Otherwise just look up the last + * load or store associated with the same source address (p) and use the + * same offset/base. + */ + LIns* x = nativeFrameTracker.get(p); + if (!x) { + if (isVoidPtrGlobal(p)) + x = writeBack(i, eos_ins, nativeGlobalOffset((Value *)p), shouldDemoteToInt32); + else + x = writeBack(i, lirbuf->sp, nativespOffsetImpl(p), shouldDemoteToInt32); + nativeFrameTracker.set(p, x); + } else { +#if defined NANOJIT_64BIT + JS_ASSERT( x->isop(LIR_stq) || x->isop(LIR_sti) || x->isop(LIR_std)); +#else + JS_ASSERT( x->isop(LIR_sti) || x->isop(LIR_std)); +#endif + + ptrdiff_t disp; + LIns *base = x->oprnd2(); + if (base->isop(LIR_addp) && base->oprnd2()->isImmP()) { + disp = ptrdiff_t(base->oprnd2()->immP()); + base = base->oprnd1(); + } else { + disp = x->disp(); + } + + JS_ASSERT(base == lirbuf->sp || base == eos_ins); + JS_ASSERT(disp == ((base == lirbuf->sp) + ? nativespOffsetImpl(p) + : nativeGlobalOffset((Value *)p))); + + writeBack(i, base, disp, shouldDemoteToInt32); + } +} + +JS_REQUIRES_STACK inline void +TraceRecorder::set(Value* p, LIns* i, bool shouldDemoteToInt32) +{ + return setImpl(p, i, shouldDemoteToInt32); +} + +JS_REQUIRES_STACK void +TraceRecorder::setFrameObjPtr(void* p, LIns* i, bool shouldDemoteToInt32) +{ + JS_ASSERT(isValidFrameObjPtr(p)); + return setImpl(p, i, shouldDemoteToInt32); +} + +JS_REQUIRES_STACK LIns* +TraceRecorder::attemptImport(const Value* p) +{ + if (LIns* i = getFromTracker(p)) + return i; + + /* If the variable was not known, it could require a lazy import. */ + CountSlotsVisitor countVisitor(p); + VisitStackSlots(countVisitor, cx, callDepth); + + if (countVisitor.stopped() || size_t(p - cx->fp()->slots()) < cx->fp()->numSlots()) + return get(p); + + return NULL; +} + +inline nanojit::LIns* +TraceRecorder::getFromTrackerImpl(const void* p) +{ + checkForGlobalObjectReallocation(); + return tracker.get(p); +} + +inline nanojit::LIns* +TraceRecorder::getFromTracker(const Value* p) +{ + return getFromTrackerImpl(p); +} + +JS_REQUIRES_STACK LIns* +TraceRecorder::getImpl(const void *p) +{ + LIns* x = getFromTrackerImpl(p); + if (x) + return x; + if (isVoidPtrGlobal(p)) { + unsigned slot = nativeGlobalSlot((const Value *)p); + JS_ASSERT(tree->globalSlots->offsetOf(uint16(slot)) != -1); + importGlobalSlot(slot); + } else { + unsigned slot = nativeStackSlotImpl(p); + JSValueType type = importTypeMap[slot]; + importImpl(StackAddress(lirbuf->sp, -tree->nativeStackBase + slot * sizeof(jsdouble)), + p, type, "stack", slot, cx->fp()); + } + JS_ASSERT(knownImpl(p)); + return tracker.get(p); +} + +JS_REQUIRES_STACK LIns* +TraceRecorder::get(const Value *p) +{ + return getImpl(p); +} + +#ifdef DEBUG +bool +TraceRecorder::isValidFrameObjPtr(void *p) +{ + JSStackFrame *fp = cx->fp(); + for (; fp; fp = fp->prev()) { + if (fp->addressOfScopeChain() == p || fp->addressOfArgs() == p) + return true; + } + return false; +} +#endif + +JS_REQUIRES_STACK LIns* +TraceRecorder::getFrameObjPtr(void *p) +{ + JS_ASSERT(isValidFrameObjPtr(p)); + return getImpl(p); +} + +JS_REQUIRES_STACK LIns* +TraceRecorder::addr(Value* p) +{ + return isGlobal(p) + ? w.addp(eos_ins, w.nameImmw(nativeGlobalOffset(p))) + : w.addp(lirbuf->sp, w.nameImmw(nativespOffset(p))); +} + +JS_REQUIRES_STACK inline bool +TraceRecorder::knownImpl(const void* p) +{ + checkForGlobalObjectReallocation(); + return tracker.has(p); +} + +JS_REQUIRES_STACK inline bool +TraceRecorder::known(const Value* vp) +{ + return knownImpl(vp); +} + +JS_REQUIRES_STACK inline bool +TraceRecorder::known(JSObject** p) +{ + return knownImpl(p); +} + +/* + * The slots of the global object are sometimes reallocated by the interpreter. + * This function check for that condition and re-maps the entries of the tracker + * accordingly. + */ +JS_REQUIRES_STACK void +TraceRecorder::checkForGlobalObjectReallocationHelper() +{ + debug_only_print0(LC_TMTracer, "globalObj->slots relocated, updating tracker\n"); + Value* src = global_slots; + Value* dst = globalObj->getSlots(); + jsuint length = globalObj->capacity; + LIns** map = (LIns**)alloca(sizeof(LIns*) * length); + for (jsuint n = 0; n < length; ++n) { + map[n] = tracker.get(src); + tracker.set(src++, NULL); + } + for (jsuint n = 0; n < length; ++n) + tracker.set(dst++, map[n]); + global_slots = globalObj->getSlots(); +} + +/* Determine whether the current branch is a loop edge (taken or not taken). */ +static JS_REQUIRES_STACK bool +IsLoopEdge(jsbytecode* pc, jsbytecode* header) +{ + switch (*pc) { + case JSOP_IFEQ: + case JSOP_IFNE: + return ((pc + GET_JUMP_OFFSET(pc)) == header); + case JSOP_IFEQX: + case JSOP_IFNEX: + return ((pc + GET_JUMPX_OFFSET(pc)) == header); + default: + JS_ASSERT((*pc == JSOP_AND) || (*pc == JSOP_ANDX) || + (*pc == JSOP_OR) || (*pc == JSOP_ORX)); + } + return false; +} + +class AdjustCallerGlobalTypesVisitor : public SlotVisitorBase +{ + TraceRecorder &mRecorder; + JSContext *mCx; + nanojit::LirBuffer *mLirbuf; + JSValueType *mTypeMap; +public: + AdjustCallerGlobalTypesVisitor(TraceRecorder &recorder, + JSValueType *typeMap) : + mRecorder(recorder), + mCx(mRecorder.cx), + mLirbuf(mRecorder.lirbuf), + mTypeMap(typeMap) + {} + + JSValueType* getTypeMap() + { + return mTypeMap; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE void + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { + LIns *ins = mRecorder.get(vp); + bool isPromote = IsPromotedInt32(ins); + if (isPromote && *mTypeMap == JSVAL_TYPE_DOUBLE) { + mRecorder.w.st(mRecorder.get(vp), + EosAddress(mRecorder.eos_ins, mRecorder.nativeGlobalOffset(vp))); + /* + * Aggressively undo speculation so the inner tree will compile + * if this fails. + */ + mRecorder.traceMonitor->oracle->markGlobalSlotUndemotable(mCx, slot); + } + JS_ASSERT(!(!isPromote && *mTypeMap == JSVAL_TYPE_INT32)); + ++mTypeMap; + } +}; + +class AdjustCallerStackTypesVisitor : public SlotVisitorBase +{ + TraceRecorder &mRecorder; + JSContext *mCx; + nanojit::LirBuffer *mLirbuf; + unsigned mSlotnum; + JSValueType *mTypeMap; +public: + AdjustCallerStackTypesVisitor(TraceRecorder &recorder, + JSValueType *typeMap) : + mRecorder(recorder), + mCx(mRecorder.cx), + mLirbuf(mRecorder.lirbuf), + mSlotnum(0), + mTypeMap(typeMap) + {} + + JSValueType* getTypeMap() + { + return mTypeMap; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { + /* N.B. vp may actually point to a JSObject*. */ + for (size_t i = 0; i < count; ++i) { + LIns *ins = mRecorder.get(vp); + bool isPromote = IsPromotedInt32(ins); + if (isPromote && *mTypeMap == JSVAL_TYPE_DOUBLE) { + mRecorder.w.st(ins, StackAddress(mLirbuf->sp, mRecorder.nativespOffset(vp))); + /* + * Aggressively undo speculation so the inner tree will compile + * if this fails. + */ + mRecorder.traceMonitor->oracle->markStackSlotUndemotable(mCx, mSlotnum); + } + JS_ASSERT(!(!isPromote && *mTypeMap == JSVAL_TYPE_INT32)); + ++vp; + ++mTypeMap; + ++mSlotnum; + } + return true; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(void* p, JSStackFrame* fp) { + JS_ASSERT(*mTypeMap != JSVAL_TYPE_BOXED); + ++mTypeMap; + ++mSlotnum; + return true; + } +}; + +/* + * Promote slots if necessary to match the called tree's type map. This + * function is infallible and must only be called if we are certain that it is + * possible to reconcile the types for each slot in the inner and outer trees. + */ +JS_REQUIRES_STACK void +TraceRecorder::adjustCallerTypes(TreeFragment* f) +{ + AdjustCallerGlobalTypesVisitor globalVisitor(*this, f->globalTypeMap()); + VisitGlobalSlots(globalVisitor, cx, *tree->globalSlots); + + AdjustCallerStackTypesVisitor stackVisitor(*this, f->stackTypeMap()); + VisitStackSlots(stackVisitor, cx, 0); + + JS_ASSERT(f == f->root); +} + +JS_REQUIRES_STACK inline JSValueType +TraceRecorder::determineSlotType(Value* vp) +{ + if (vp->isNumber()) { + LIns *i = getFromTracker(vp); + JSValueType t; + if (i) { + t = IsPromotedInt32(i) ? JSVAL_TYPE_INT32 : JSVAL_TYPE_DOUBLE; + } else if (isGlobal(vp)) { + int offset = tree->globalSlots->offsetOf(uint16(nativeGlobalSlot(vp))); + JS_ASSERT(offset != -1); + t = importTypeMap[importStackSlots + offset]; + } else { + t = importTypeMap[nativeStackSlot(vp)]; + } + JS_ASSERT_IF(t == JSVAL_TYPE_INT32, hasInt32Repr(*vp)); + return t; + } + + if (vp->isObject()) + return vp->toObject().isFunction() ? JSVAL_TYPE_FUNOBJ : JSVAL_TYPE_NONFUNOBJ; + return vp->extractNonDoubleObjectTraceType(); +} + +class DetermineTypesVisitor : public SlotVisitorBase +{ + TraceRecorder &mRecorder; + JSValueType *mTypeMap; +public: + DetermineTypesVisitor(TraceRecorder &recorder, + JSValueType *typeMap) : + mRecorder(recorder), + mTypeMap(typeMap) + {} + + JS_REQUIRES_STACK JS_ALWAYS_INLINE void + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { + *mTypeMap++ = mRecorder.determineSlotType(vp); + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { + for (size_t i = 0; i < count; ++i) + *mTypeMap++ = mRecorder.determineSlotType(vp++); + return true; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(void* p, JSStackFrame* fp) { + *mTypeMap++ = getFrameObjPtrTraceType(p, fp); + return true; + } + + JSValueType* getTypeMap() + { + return mTypeMap; + } +}; + +#if defined JS_JIT_SPEW +JS_REQUIRES_STACK static void +TreevisLogExit(JSContext* cx, VMSideExit* exit) +{ + debug_only_printf(LC_TMTreeVis, "TREEVIS ADDEXIT EXIT=%p TYPE=%s FRAG=%p PC=%p FILE=\"%s\"" + " LINE=%d OFFS=%d", (void*)exit, getExitName(exit->exitType), + (void*)exit->from, (void*)cx->regs->pc, cx->fp()->script()->filename, + js_FramePCToLineNumber(cx, cx->fp()), FramePCOffset(cx, cx->fp())); + debug_only_print0(LC_TMTreeVis, " STACK=\""); + for (unsigned i = 0; i < exit->numStackSlots; i++) + debug_only_printf(LC_TMTreeVis, "%c", TypeToChar(exit->stackTypeMap()[i])); + debug_only_print0(LC_TMTreeVis, "\" GLOBALS=\""); + for (unsigned i = 0; i < exit->numGlobalSlots; i++) + debug_only_printf(LC_TMTreeVis, "%c", TypeToChar(exit->globalTypeMap()[i])); + debug_only_print0(LC_TMTreeVis, "\"\n"); +} +#endif + +JS_REQUIRES_STACK VMSideExit* +TraceRecorder::snapshot(ExitType exitType) +{ + JSStackFrame* const fp = cx->fp(); + JSFrameRegs* const regs = cx->regs; + jsbytecode* pc = regs->pc; + + /* + * Check for a return-value opcode that needs to restart at the next + * instruction. + */ + const JSCodeSpec& cs = js_CodeSpec[*pc]; + + /* + * When calling a _FAIL native, make the snapshot's pc point to the next + * instruction after the CALL or APPLY. Even on failure, a _FAIL native + * must not be called again from the interpreter. + */ + bool resumeAfter = (pendingSpecializedNative && + JSTN_ERRTYPE(pendingSpecializedNative) == FAIL_STATUS); + if (resumeAfter) { + JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_FUNAPPLY || *pc == JSOP_FUNCALL || + *pc == JSOP_NEW || *pc == JSOP_SETPROP || *pc == JSOP_SETNAME); + pc += cs.length; + regs->pc = pc; + MUST_FLOW_THROUGH("restore_pc"); + } + + /* + * Generate the entry map for the (possibly advanced) pc and stash it in + * the trace. + */ + unsigned stackSlots = NativeStackSlots(cx, callDepth); + + /* + * It's sufficient to track the native stack use here since all stores + * above the stack watermark defined by guards are killed. + */ + trackNativeStackUse(stackSlots + 1); + + /* Capture the type map into a temporary location. */ + unsigned ngslots = tree->globalSlots->length(); + unsigned typemap_size = (stackSlots + ngslots) * sizeof(JSValueType); + + /* Use the recorder-local temporary type map. */ + JSValueType* typemap = NULL; + if (tempTypeMap.resize(typemap_size)) + typemap = tempTypeMap.begin(); /* crash if resize() fails. */ + + /* + * Determine the type of a store by looking at the current type of the + * actual value the interpreter is using. For numbers we have to check what + * kind of store we used last (integer or double) to figure out what the + * side exit show reflect in its typemap. + */ + DetermineTypesVisitor detVisitor(*this, typemap); + VisitSlots(detVisitor, cx, callDepth, ngslots, + tree->globalSlots->data()); + JS_ASSERT(unsigned(detVisitor.getTypeMap() - typemap) == + ngslots + stackSlots); + + /* + * If this snapshot is for a side exit that leaves a boxed Value result on + * the stack, make a note of this in the typemap. Examples include the + * builtinStatus guard after calling a _FAIL builtin, a JSFastNative, or + * GetPropertyByName; and the type guard in unbox_value after such a call + * (also at the beginning of a trace branched from such a type guard). + */ + if (pendingUnboxSlot || + (pendingSpecializedNative && (pendingSpecializedNative->flags & JSTN_UNBOX_AFTER))) { + unsigned pos = stackSlots - 1; + if (pendingUnboxSlot == cx->regs->sp - 2) + pos = stackSlots - 2; + typemap[pos] = JSVAL_TYPE_BOXED; + } else if (pendingSpecializedNative && + (pendingSpecializedNative->flags & JSTN_RETURN_NULLABLE_STR)) { + typemap[stackSlots - 1] = JSVAL_TYPE_STRORNULL; + } else if (pendingSpecializedNative && + (pendingSpecializedNative->flags & JSTN_RETURN_NULLABLE_OBJ)) { + typemap[stackSlots - 1] = JSVAL_TYPE_OBJORNULL; + } + + /* Now restore the the original pc (after which early returns are ok). */ + if (resumeAfter) { + MUST_FLOW_LABEL(restore_pc); + regs->pc = pc - cs.length; + } else { + /* + * If we take a snapshot on a goto, advance to the target address. This + * avoids inner trees returning on a break goto, which the outer + * recorder then would confuse with a break in the outer tree. + */ + if (*pc == JSOP_GOTO) + pc += GET_JUMP_OFFSET(pc); + else if (*pc == JSOP_GOTOX) + pc += GET_JUMPX_OFFSET(pc); + } + + /* + * Check if we already have a matching side exit; if so we can return that + * side exit instead of creating a new one. + */ + VMSideExit** exits = tree->sideExits.data(); + unsigned nexits = tree->sideExits.length(); + if (exitType == LOOP_EXIT) { + for (unsigned n = 0; n < nexits; ++n) { + VMSideExit* e = exits[n]; + if (e->pc == pc && (e->imacpc == fp->maybeImacropc()) && + ngslots == e->numGlobalSlots && + !memcmp(exits[n]->fullTypeMap(), typemap, typemap_size)) { + AUDIT(mergedLoopExits); +#if defined JS_JIT_SPEW + TreevisLogExit(cx, e); +#endif + return e; + } + } + } + + /* We couldn't find a matching side exit, so create a new one. */ + VMSideExit* exit = (VMSideExit*) + traceAlloc().alloc(sizeof(VMSideExit) + (stackSlots + ngslots) * sizeof(JSValueType)); + + /* Setup side exit structure. */ + exit->from = fragment; + exit->calldepth = callDepth; + exit->numGlobalSlots = ngslots; + exit->numStackSlots = stackSlots; + exit->numStackSlotsBelowCurrentFrame = cx->fp()->isFunctionFrame() ? + nativeStackOffset(&cx->fp()->calleeValue()) / sizeof(double) : + 0; + exit->exitType = exitType; + exit->pc = pc; + exit->imacpc = fp->maybeImacropc(); + exit->sp_adj = (stackSlots * sizeof(double)) - tree->nativeStackBase; + exit->rp_adj = exit->calldepth * sizeof(FrameInfo*); + exit->lookupFlags = js_InferFlags(cx, 0); + memcpy(exit->fullTypeMap(), typemap, typemap_size); + +#if defined JS_JIT_SPEW + TreevisLogExit(cx, exit); +#endif + return exit; +} + +JS_REQUIRES_STACK GuardRecord* +TraceRecorder::createGuardRecord(VMSideExit* exit) +{ +#ifdef JS_JIT_SPEW + // For debug builds, place the guard records in a longer lasting + // pool. This is because the fragment profiler will look at them + // relatively late in the day, after they would have been freed, + // in some cases, had they been allocated in traceAlloc(). + GuardRecord* gr = new (dataAlloc()) GuardRecord(); +#else + // The standard place (for production builds). + GuardRecord* gr = new (traceAlloc()) GuardRecord(); +#endif + + gr->exit = exit; + exit->addGuard(gr); + + // gr->profCount is calloc'd to zero + verbose_only( + gr->profGuardID = fragment->guardNumberer++; + gr->nextInFrag = fragment->guardsForFrag; + fragment->guardsForFrag = gr; + ) + + return gr; +} + +/* Test if 'ins' is in a form that can be used as a guard/branch condition. */ +static bool +isCond(LIns* ins) +{ + return ins->isCmp() || ins->isImmI(0) || ins->isImmI(1); +} + +/* Ensure 'ins' is in a form suitable for a guard/branch condition. */ +void +TraceRecorder::ensureCond(LIns** ins, bool* cond) +{ + if (!isCond(*ins)) { + *cond = !*cond; + *ins = (*ins)->isI() ? w.eqi0(*ins) : w.eqp0(*ins); + } +} + +/* + * Emit a guard for condition (cond), expecting to evaluate to boolean result + * (expected) and using the supplied side exit if the condition doesn't hold. + * + * Callers shouldn't generate guards that always exit (which can occur due to + * optimization of the guard condition) because it's bad for both compile-time + * speed (all the code generated after the guard is dead) and run-time speed + * (fragment that always exit are slow). This function has two modes for + * handling an always-exit guard; which mode is used depends on the value of + * abortIfAlwaysExits: + * + * - abortIfAlwaysExits == false: This is the default mode. If the guard + * will always exit, we assert (in debug builds) as a signal that we are + * generating bad traces. (In optimized builds that lack assertions the + * guard will be generated correctly, so the code will be slow but safe.) In + * this mode, the caller is responsible for not generating an always-exit + * guard. The return value will always be RECORD_CONTINUE, so the caller + * need not check it. + * + * - abortIfAlwaysExits == true: If the guard will always exit, we abort + * recording and return RECORD_STOP; otherwise we generate the guard + * normally and return RECORD_CONTINUE. This mode can be used when the + * caller doesn't know ahead of time whether the guard will always exit. In + * this mode, the caller must check the return value. + */ +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::guard(bool expected, LIns* cond, VMSideExit* exit, + bool abortIfAlwaysExits/* = false */) +{ + if (exit->exitType == LOOP_EXIT) + tree->sideExits.add(exit); + + JS_ASSERT(isCond(cond)); + + if ((cond->isImmI(0) && expected) || (cond->isImmI(1) && !expected)) { + if (abortIfAlwaysExits) { + /* The guard always exits, the caller must check for an abort. */ + RETURN_STOP("Constantly false guard detected"); + } + /* + * If you hit this assertion, first decide if you want recording to + * abort in the case where the guard always exits. If not, find a way + * to detect that case and avoid calling guard(). Otherwise, change + * the invocation of guard() so it passes in abortIfAlwaysExits=true, + * and have the caller check the return value, eg. using + * CHECK_STATUS(). (In optimized builds, we'll fall through to the + * insGuard() below and an always-exits guard will be inserted, which + * is correct but sub-optimal.) + */ + JS_NOT_REACHED("unexpected constantly false guard detected"); + } + + /* + * Nb: if the guard is never taken, no instruction will be created and + * insGuard() will return NULL. This is a good thing. + */ + GuardRecord* guardRec = createGuardRecord(exit); + expected ? w.xf(cond, guardRec) : w.xt(cond, guardRec); + return RECORD_CONTINUE; +} + +/* + * Emit a guard for condition (cond), expecting to evaluate to boolean result + * (expected) and generate a side exit with type exitType to jump to if the + * condition does not hold. + */ +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::guard(bool expected, LIns* cond, ExitType exitType, + bool abortIfAlwaysExits/* = false */) +{ + return guard(expected, cond, snapshot(exitType), abortIfAlwaysExits); +} + +/* + * Emit a guard a 32-bit integer arithmetic operation op(d0, d1) and + * using the supplied side exit if it overflows. + */ +JS_REQUIRES_STACK LIns* +TraceRecorder::guard_xov(LOpcode op, LIns* d0, LIns* d1, VMSideExit* exit) +{ + JS_ASSERT(exit->exitType == OVERFLOW_EXIT); + + GuardRecord* guardRec = createGuardRecord(exit); + switch (op) { + case LIR_addi: + return w.addxovi(d0, d1, guardRec); + case LIR_subi: + return w.subxovi(d0, d1, guardRec); + case LIR_muli: + return w.mulxovi(d0, d1, guardRec); + default: + break; + } + JS_NOT_REACHED("unexpected opcode"); + return NULL; +} + +JS_REQUIRES_STACK VMSideExit* +TraceRecorder::copy(VMSideExit* copy) +{ + size_t typemap_size = copy->numGlobalSlots + copy->numStackSlots; + VMSideExit* exit = (VMSideExit*) + traceAlloc().alloc(sizeof(VMSideExit) + typemap_size * sizeof(JSValueType)); + + /* Copy side exit structure. */ + memcpy(exit, copy, sizeof(VMSideExit) + typemap_size * sizeof(JSValueType)); + exit->guards = NULL; + exit->from = fragment; + exit->target = NULL; + + if (exit->exitType == LOOP_EXIT) + tree->sideExits.add(exit); +#if defined JS_JIT_SPEW + TreevisLogExit(cx, exit); +#endif + return exit; +} + +/* + * Determine whether any context associated with the same thread as cx is + * executing native code. + */ +static inline bool +ProhibitFlush(TraceMonitor *tm) +{ + return !!tm->tracerState; // don't flush if we're running a trace +} + +static void +ResetJITImpl(JSContext* cx, TraceMonitor* tm) +{ + if (!cx->traceJitEnabled) + return; + debug_only_print0(LC_TMTracer, "Flushing cache.\n"); + if (tm->recorder) { + JS_ASSERT_NOT_ON_TRACE(cx); + AbortRecording(cx, "flush cache"); + } +#if JS_METHODJIT + if (tm->profile) + AbortProfiling(cx); +#endif + if (ProhibitFlush(tm)) { + debug_only_print0(LC_TMTracer, "Deferring JIT flush due to deep bail.\n"); + tm->needFlush = JS_TRUE; + return; + } + tm->flush(); +} + +/* Compile the current fragment. */ +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::compile() +{ +#ifdef MOZ_TRACEVIS + TraceVisStateObj tvso(cx, S_COMPILE); +#endif + + if (traceMonitor->needFlush) { + ResetJIT(cx, traceMonitor, FR_DEEP_BAIL); + return ARECORD_ABORTED; + } + if (tree->maxNativeStackSlots >= MAX_NATIVE_STACK_SLOTS) { + debug_only_print0(LC_TMTracer, "Blacklist: excessive stack use.\n"); + Blacklist((jsbytecode*)tree->ip); + return ARECORD_STOP; + } + if (anchor && anchor->exitType != CASE_EXIT) + ++tree->branchCount; + if (outOfMemory()) + return ARECORD_STOP; + + /* :TODO: windows support */ +#if defined DEBUG && !defined WIN32 + /* Associate a filename and line number with the fragment. */ + const char* filename = cx->fp()->script()->filename; + char* label = (char*)js_malloc((filename ? strlen(filename) : 7) + 16); + if (label) { + sprintf(label, "%s:%u", filename ? filename : "", + js_FramePCToLineNumber(cx, cx->fp())); + lirbuf->printer->addrNameMap->addAddrRange(fragment, sizeof(Fragment), 0, label); + js_free(label); + } +#endif + + Assembler *assm = traceMonitor->assembler; + JS_ASSERT(!assm->error()); + assm->compile(fragment, tempAlloc(), /*optimize*/true verbose_only(, lirbuf->printer)); + + if (assm->error()) { + assm->setError(nanojit::None); + debug_only_print0(LC_TMTracer, "Blacklisted: error during compilation\n"); + Blacklist((jsbytecode*)tree->ip); + return ARECORD_STOP; + } + + if (outOfMemory()) + return ARECORD_STOP; + ResetRecordingAttempts(traceMonitor, (jsbytecode*)fragment->ip); + ResetRecordingAttempts(traceMonitor, (jsbytecode*)tree->ip); + if (anchor) { +#ifdef NANOJIT_IA32 + if (anchor->exitType == CASE_EXIT) + assm->patch(anchor, anchor->switchInfo); + else +#endif + assm->patch(anchor); + } + JS_ASSERT(fragment->code()); + JS_ASSERT_IF(fragment == fragment->root, fragment->root == tree); + + return ARECORD_CONTINUE; +} + +static void +JoinPeers(Assembler* assm, VMSideExit* exit, TreeFragment* target) +{ + exit->target = target; + assm->patch(exit); + + debug_only_printf(LC_TMTreeVis, "TREEVIS JOIN ANCHOR=%p FRAG=%p\n", (void*)exit, (void*)target); + + if (exit->root() == target) + return; + + target->dependentTrees.addUnique(exit->root()); + exit->root()->linkedTrees.addUnique(target); +} + +/* Results of trying to connect an arbitrary type A with arbitrary type B */ +enum TypeCheckResult +{ + TypeCheck_Okay, /* Okay: same type */ + TypeCheck_Promote, /* Okay: Type A needs d2i() */ + TypeCheck_Demote, /* Okay: Type A needs i2d() */ + TypeCheck_Undemote, /* Bad: Slot is undemotable */ + TypeCheck_Bad /* Bad: incompatible types */ +}; + +class SlotMap : public SlotVisitorBase +{ + public: + struct SlotInfo + { + SlotInfo() + : vp(NULL), isPromotedInt32(false), lastCheck(TypeCheck_Bad) + {} + SlotInfo(Value* vp, bool isPromotedInt32) + : vp(vp), isPromotedInt32(isPromotedInt32), lastCheck(TypeCheck_Bad), + type(getCoercedType(*vp)) + {} + SlotInfo(JSValueType t) + : vp(NULL), isPromotedInt32(false), lastCheck(TypeCheck_Bad), type(t) + {} + SlotInfo(Value* vp, JSValueType t) + : vp(vp), isPromotedInt32(t == JSVAL_TYPE_INT32), lastCheck(TypeCheck_Bad), type(t) + {} + void *vp; + bool isPromotedInt32; + TypeCheckResult lastCheck; + JSValueType type; + }; + + SlotMap(TraceRecorder& rec) + : mRecorder(rec), + mCx(rec.cx), + slots(NULL) + { + } + + virtual ~SlotMap() + { + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE void + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) + { + addSlot(vp); + } + + JS_ALWAYS_INLINE SlotMap::SlotInfo& + operator [](unsigned i) + { + return slots[i]; + } + + JS_ALWAYS_INLINE SlotMap::SlotInfo& + get(unsigned i) + { + return slots[i]; + } + + JS_ALWAYS_INLINE unsigned + length() + { + return slots.length(); + } + + /** + * Possible return states: + * + * TypeConsensus_Okay: All types are compatible. Caller must go through slot list and handle + * promote/demotes. + * TypeConsensus_Bad: Types are not compatible. Individual type check results are undefined. + * TypeConsensus_Undemotes: Types would be compatible if slots were marked as undemotable + * before recording began. Caller can go through slot list and mark + * such slots as undemotable. + */ + JS_REQUIRES_STACK TypeConsensus + checkTypes(LinkableFragment* f) + { + if (length() != f->typeMap.length()) + return TypeConsensus_Bad; + + bool has_undemotes = false; + for (unsigned i = 0; i < length(); i++) { + TypeCheckResult result = checkType(i, f->typeMap[i]); + if (result == TypeCheck_Bad) + return TypeConsensus_Bad; + if (result == TypeCheck_Undemote) + has_undemotes = true; + slots[i].lastCheck = result; + } + if (has_undemotes) + return TypeConsensus_Undemotes; + return TypeConsensus_Okay; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE void + addSlot(Value* vp) + { + bool isPromotedInt32 = false; + if (vp->isNumber()) { + if (LIns* i = mRecorder.getFromTracker(vp)) { + isPromotedInt32 = IsPromotedInt32(i); + } else if (mRecorder.isGlobal(vp)) { + int offset = mRecorder.tree->globalSlots->offsetOf(uint16(mRecorder.nativeGlobalSlot(vp))); + JS_ASSERT(offset != -1); + isPromotedInt32 = mRecorder.importTypeMap[mRecorder.importStackSlots + offset] == + JSVAL_TYPE_INT32; + } else { + isPromotedInt32 = mRecorder.importTypeMap[mRecorder.nativeStackSlot(vp)] == + JSVAL_TYPE_INT32; + } + } + slots.add(SlotInfo(vp, isPromotedInt32)); + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE void + addSlot(JSValueType t) + { + slots.add(SlotInfo(NULL, t)); + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE void + addSlot(Value *vp, JSValueType t) + { + slots.add(SlotInfo(vp, t)); + } + + JS_REQUIRES_STACK void + markUndemotes() + { + for (unsigned i = 0; i < length(); i++) { + if (get(i).lastCheck == TypeCheck_Undemote) + mRecorder.markSlotUndemotable(mRecorder.tree, i); + } + } + + JS_REQUIRES_STACK virtual void + adjustTypes() + { + for (unsigned i = 0; i < length(); i++) + adjustType(get(i)); + } + + protected: + JS_REQUIRES_STACK virtual void + adjustType(SlotInfo& info) { + JS_ASSERT(info.lastCheck != TypeCheck_Undemote && info.lastCheck != TypeCheck_Bad); +#ifdef DEBUG + if (info.lastCheck == TypeCheck_Promote) { + JS_ASSERT(info.type == JSVAL_TYPE_INT32 || info.type == JSVAL_TYPE_DOUBLE); + /* + * This should only happen if the slot has a trivial conversion, i.e. + * IsPromotedInt32() is true. We check this. + * + * Note that getFromTracker() will return NULL if the slot was + * never used, in which case we don't do the check. We could + * instead called mRecorder.get(info.vp) and always check, but + * get() has side-effects, which is not good in an assertion. + * Not checking unused slots isn't so bad. + */ + LIns* ins = mRecorder.getFromTrackerImpl(info.vp); + JS_ASSERT_IF(ins, IsPromotedInt32(ins)); + } else +#endif + if (info.lastCheck == TypeCheck_Demote) { + JS_ASSERT(info.type == JSVAL_TYPE_INT32 || info.type == JSVAL_TYPE_DOUBLE); + JS_ASSERT(mRecorder.getImpl(info.vp)->isD()); + + /* Never demote this final i2d. */ + mRecorder.setImpl(info.vp, mRecorder.getImpl(info.vp), false); + } + } + + private: + TypeCheckResult + checkType(unsigned i, JSValueType t) + { + debug_only_printf(LC_TMTracer, + "checkType slot %d: interp=%c typemap=%c isNum=%d isPromotedInt32=%d\n", + i, + TypeToChar(slots[i].type), + TypeToChar(t), + slots[i].type == JSVAL_TYPE_INT32 || slots[i].type == JSVAL_TYPE_DOUBLE, + slots[i].isPromotedInt32); + switch (t) { + case JSVAL_TYPE_INT32: + if (slots[i].type != JSVAL_TYPE_INT32 && slots[i].type != JSVAL_TYPE_DOUBLE) + return TypeCheck_Bad; /* Not a number? Type mismatch. */ + /* This is always a type mismatch, we can't close a double to an int. */ + if (!slots[i].isPromotedInt32) + return TypeCheck_Undemote; + /* Looks good, slot is an int32, the last instruction should be promotable. */ + JS_ASSERT_IF(slots[i].vp, + hasInt32Repr(*(const Value *)slots[i].vp) && slots[i].isPromotedInt32); + return slots[i].vp ? TypeCheck_Promote : TypeCheck_Okay; + case JSVAL_TYPE_DOUBLE: + if (slots[i].type != JSVAL_TYPE_INT32 && slots[i].type != JSVAL_TYPE_DOUBLE) + return TypeCheck_Bad; /* Not a number? Type mismatch. */ + if (slots[i].isPromotedInt32) + return slots[i].vp ? TypeCheck_Demote : TypeCheck_Bad; + return TypeCheck_Okay; + default: + return slots[i].type == t ? TypeCheck_Okay : TypeCheck_Bad; + } + JS_NOT_REACHED("shouldn't fall through type check switch"); + } + protected: + TraceRecorder& mRecorder; + JSContext* mCx; + Queue slots; +}; + +class DefaultSlotMap : public SlotMap +{ + public: + DefaultSlotMap(TraceRecorder& tr) : SlotMap(tr) + { + } + + virtual ~DefaultSlotMap() + { + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) + { + for (size_t i = 0; i < count; i++) + addSlot(&vp[i]); + return true; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(void* p, JSStackFrame* fp) + { + addSlot(getFrameObjPtrTraceType(p, fp)); + return true; + } +}; + +JS_REQUIRES_STACK TypeConsensus +TraceRecorder::selfTypeStability(SlotMap& slotMap) +{ + debug_only_printf(LC_TMTracer, "Checking type stability against self=%p\n", (void*)fragment); + TypeConsensus consensus = slotMap.checkTypes(tree); + + /* Best case: loop jumps back to its own header */ + if (consensus == TypeConsensus_Okay) + return TypeConsensus_Okay; + + /* + * If the only thing keeping this loop from being stable is undemotions, then mark relevant + * slots as undemotable. + */ + if (consensus == TypeConsensus_Undemotes) + slotMap.markUndemotes(); + + return consensus; +} + +JS_REQUIRES_STACK TypeConsensus +TraceRecorder::peerTypeStability(SlotMap& slotMap, const void* ip, TreeFragment** pPeer) +{ + JS_ASSERT(tree->first == LookupLoop(traceMonitor, ip, tree->globalObj, tree->globalShape, tree->argc)); + + /* See if there are any peers that would make this stable */ + bool onlyUndemotes = false; + for (TreeFragment *peer = tree->first; peer != NULL; peer = peer->peer) { + if (!peer->code() || peer == fragment) + continue; + debug_only_printf(LC_TMTracer, "Checking type stability against peer=%p\n", (void*)peer); + TypeConsensus consensus = slotMap.checkTypes(peer); + if (consensus == TypeConsensus_Okay) { + *pPeer = peer; + /* + * Return this even though there will be linkage; the trace itself is not stable. + * Caller should inspect ppeer to check for a compatible peer. + */ + return TypeConsensus_Okay; + } + if (consensus == TypeConsensus_Undemotes) + onlyUndemotes = true; + } + + return onlyUndemotes ? TypeConsensus_Undemotes : TypeConsensus_Bad; +} + +/* + * Complete and compile a trace and link it to the existing tree if + * appropriate. Returns ARECORD_ABORTED or ARECORD_STOP, depending on whether + * the recorder was deleted. Outparam is always set. + */ +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::closeLoop() +{ + VMSideExit *exit = snapshot(UNSTABLE_LOOP_EXIT); + + DefaultSlotMap slotMap(*this); + VisitSlots(slotMap, cx, 0, *tree->globalSlots); + + /* + * We should have arrived back at the loop header, and hence we don't want + * to be in an imacro here and the opcode should be either JSOP_TRACE or, in + * case this loop was blacklisted in the meantime, JSOP_NOTRACE. + */ + JS_ASSERT(*cx->regs->pc == JSOP_TRACE || *cx->regs->pc == JSOP_NOTRACE); + JS_ASSERT(!cx->fp()->hasImacropc()); + + if (callDepth != 0) { + debug_only_print0(LC_TMTracer, + "Blacklisted: stack depth mismatch, possible recursion.\n"); + Blacklist((jsbytecode*)tree->ip); + trashSelf = true; + return ARECORD_STOP; + } + + JS_ASSERT(exit->numStackSlots == tree->nStackTypes); + JS_ASSERT(fragment->root == tree); + JS_ASSERT(!trashSelf); + + TreeFragment* peer = NULL; + + TypeConsensus consensus = selfTypeStability(slotMap); + if (consensus != TypeConsensus_Okay) { + TypeConsensus peerConsensus = peerTypeStability(slotMap, tree->ip, &peer); + /* If there was a semblance of a stable peer (even if not linkable), keep the result. */ + if (peerConsensus != TypeConsensus_Bad) + consensus = peerConsensus; + } + +#if DEBUG + if (consensus != TypeConsensus_Okay || peer) + AUDIT(unstableLoopVariable); +#endif + + /* + * This exit is indeed linkable to something now. Process any promote or + * demotes that are pending in the slot map. + */ + if (consensus == TypeConsensus_Okay) + slotMap.adjustTypes(); + + if (consensus != TypeConsensus_Okay || peer) { + fragment->lastIns = w.x(createGuardRecord(exit)); + + /* If there is a peer, there must have been an "Okay" consensus. */ + JS_ASSERT_IF(peer, consensus == TypeConsensus_Okay); + + /* Compile as a type-unstable loop, and hope for a connection later. */ + if (!peer) { + /* + * If such a fragment does not exist, let's compile the loop ahead + * of time anyway. Later, if the loop becomes type stable, we will + * connect these two fragments together. + */ + debug_only_print0(LC_TMTracer, + "Trace has unstable loop variable with no stable peer, " + "compiling anyway.\n"); + UnstableExit* uexit = new (traceAlloc()) UnstableExit; + uexit->fragment = fragment; + uexit->exit = exit; + uexit->next = tree->unstableExits; + tree->unstableExits = uexit; + } else { + JS_ASSERT(peer->code()); + exit->target = peer; + debug_only_printf(LC_TMTracer, + "Joining type-unstable trace to target fragment %p.\n", + (void*)peer); + peer->dependentTrees.addUnique(tree); + tree->linkedTrees.addUnique(peer); + } + } else { + exit->exitType = LOOP_EXIT; + debug_only_printf(LC_TMTreeVis, "TREEVIS CHANGEEXIT EXIT=%p TYPE=%s\n", (void*)exit, + getExitName(LOOP_EXIT)); + + JS_ASSERT((fragment == fragment->root) == !!loopLabel); + if (loopLabel) { + w.j(loopLabel); + w.comment("end-loop"); + w.livep(lirbuf->state); + } + + exit->target = tree; + /* + * This guard is dead code. However, it must be present because it + * can keep alive values on the stack. Without it, StackFilter can + * remove some stack stores that it shouldn't. See bug 582766 comment + * 19. + */ + fragment->lastIns = w.x(createGuardRecord(exit)); + } + + CHECK_STATUS_A(compile()); + + debug_only_printf(LC_TMTreeVis, "TREEVIS CLOSELOOP EXIT=%p PEER=%p\n", (void*)exit, (void*)peer); + + JS_ASSERT(LookupLoop(traceMonitor, tree->ip, tree->globalObj, tree->globalShape, tree->argc) == + tree->first); + JS_ASSERT(tree->first); + + peer = tree->first; + joinEdgesToEntry(peer); + + debug_only_stmt(DumpPeerStability(traceMonitor, peer->ip, peer->globalObj, + peer->globalShape, peer->argc);) + + debug_only_print0(LC_TMTracer, + "updating specializations on dependent and linked trees\n"); + if (tree->code()) + SpecializeTreesToMissingGlobals(cx, globalObj, tree); + + /* + * If this is a newly formed tree, and the outer tree has not been compiled yet, we + * should try to compile the outer tree again. + */ + if (outerPC) + AttemptCompilation(traceMonitor, globalObj, outerScript, outerPC, outerArgc); +#ifdef JS_JIT_SPEW + debug_only_printf(LC_TMMinimal, + "Recording completed at %s:%u@%u via closeLoop (FragID=%06u)\n", + cx->fp()->script()->filename, + js_FramePCToLineNumber(cx, cx->fp()), + FramePCOffset(cx, cx->fp()), + fragment->profFragID); + debug_only_print0(LC_TMMinimal, "\n"); +#endif + + return finishSuccessfully(); +} + +static void +FullMapFromExit(TypeMap& typeMap, VMSideExit* exit) +{ + typeMap.setLength(0); + typeMap.fromRaw(exit->stackTypeMap(), exit->numStackSlots); + typeMap.fromRaw(exit->globalTypeMap(), exit->numGlobalSlots); + /* Include globals that were later specialized at the root of the tree. */ + if (exit->numGlobalSlots < exit->root()->nGlobalTypes()) { + typeMap.fromRaw(exit->root()->globalTypeMap() + exit->numGlobalSlots, + exit->root()->nGlobalTypes() - exit->numGlobalSlots); + } +} + +static JS_REQUIRES_STACK TypeConsensus +TypeMapLinkability(JSContext* cx, TraceMonitor *tm, const TypeMap& typeMap, TreeFragment* peer) +{ + const TypeMap& peerMap = peer->typeMap; + unsigned minSlots = JS_MIN(typeMap.length(), peerMap.length()); + TypeConsensus consensus = TypeConsensus_Okay; + for (unsigned i = 0; i < minSlots; i++) { + if (typeMap[i] == peerMap[i]) + continue; + if (typeMap[i] == JSVAL_TYPE_INT32 && peerMap[i] == JSVAL_TYPE_DOUBLE && + IsSlotUndemotable(tm->oracle, cx, peer, i, peer->ip)) { + consensus = TypeConsensus_Undemotes; + } else { + return TypeConsensus_Bad; + } + } + return consensus; +} + +JS_REQUIRES_STACK unsigned +TraceRecorder::findUndemotesInTypemaps(const TypeMap& typeMap, LinkableFragment* f, + Queue& undemotes) +{ + undemotes.setLength(0); + unsigned minSlots = JS_MIN(typeMap.length(), f->typeMap.length()); + for (unsigned i = 0; i < minSlots; i++) { + if (typeMap[i] == JSVAL_TYPE_INT32 && f->typeMap[i] == JSVAL_TYPE_DOUBLE) { + undemotes.add(i); + } else if (typeMap[i] != f->typeMap[i]) { + return 0; + } + } + for (unsigned i = 0; i < undemotes.length(); i++) + markSlotUndemotable(f, undemotes[i]); + return undemotes.length(); +} + +JS_REQUIRES_STACK void +TraceRecorder::joinEdgesToEntry(TreeFragment* peer_root) +{ + if (fragment->root != fragment) + return; + + TypeMap typeMap(NULL, traceMonitor->oracle); + Queue undemotes(NULL); + + for (TreeFragment* peer = peer_root; peer; peer = peer->peer) { + if (!peer->code()) + continue; + UnstableExit* uexit = peer->unstableExits; + while (uexit != NULL) { + /* Build the full typemap for this unstable exit */ + FullMapFromExit(typeMap, uexit->exit); + /* Check its compatibility against this tree */ + TypeConsensus consensus = TypeMapLinkability(cx, traceMonitor, typeMap, tree); + JS_ASSERT_IF(consensus == TypeConsensus_Okay, peer != fragment); + if (consensus == TypeConsensus_Okay) { + debug_only_printf(LC_TMTracer, + "Joining type-stable trace to target exit %p->%p.\n", + (void*)uexit->fragment, (void*)uexit->exit); + + /* + * See bug 531513. Before linking these trees, make sure the + * peer's dependency graph is up to date. + */ + TreeFragment* from = uexit->exit->root(); + if (from->nGlobalTypes() < tree->nGlobalTypes()) { + SpecializeTreesToLateGlobals(cx, from, tree->globalTypeMap(), + tree->nGlobalTypes()); + } + + /* It's okay! Link together and remove the unstable exit. */ + JS_ASSERT(tree == fragment); + JoinPeers(traceMonitor->assembler, uexit->exit, tree); + uexit = peer->removeUnstableExit(uexit->exit); + } else { + /* Check for int32->double slots that suggest trashing. */ + if (findUndemotesInTypemaps(typeMap, tree, undemotes)) { + JS_ASSERT(peer == uexit->fragment->root); + if (fragment == peer) + trashSelf = true; + else + whichTreesToTrash.addUnique(uexit->fragment->root); + break; + } + uexit = uexit->next; + } + } + } +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::endLoop() +{ + return endLoop(snapshot(LOOP_EXIT)); +} + +/* Emit an always-exit guard and compile the tree (used for break statements. */ +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::endLoop(VMSideExit* exit) +{ + JS_ASSERT(fragment->root == tree); + + if (callDepth != 0) { + debug_only_print0(LC_TMTracer, "Blacklisted: stack depth mismatch, possible recursion.\n"); + Blacklist((jsbytecode*)tree->ip); + trashSelf = true; + return ARECORD_STOP; + } + + fragment->lastIns = w.x(createGuardRecord(exit)); + + CHECK_STATUS_A(compile()); + + debug_only_printf(LC_TMTreeVis, "TREEVIS ENDLOOP EXIT=%p\n", (void*)exit); + + JS_ASSERT(LookupLoop(traceMonitor, tree->ip, tree->globalObj, tree->globalShape, tree->argc) == + tree->first); + + joinEdgesToEntry(tree->first); + + debug_only_stmt(DumpPeerStability(traceMonitor, tree->ip, tree->globalObj, + tree->globalShape, tree->argc);) + + /* + * Note: this must always be done, in case we added new globals on trace + * and haven't yet propagated those to linked and dependent trees. + */ + debug_only_print0(LC_TMTracer, + "updating specializations on dependent and linked trees\n"); + if (tree->code()) + SpecializeTreesToMissingGlobals(cx, globalObj, fragment->root); + + /* + * If this is a newly formed tree, and the outer tree has not been compiled + * yet, we should try to compile the outer tree again. + */ + if (outerPC) + AttemptCompilation(traceMonitor, globalObj, outerScript, outerPC, outerArgc); +#ifdef JS_JIT_SPEW + debug_only_printf(LC_TMMinimal, + "Recording completed at %s:%u@%u via endLoop (FragID=%06u)\n", + cx->fp()->script()->filename, + js_FramePCToLineNumber(cx, cx->fp()), + FramePCOffset(cx, cx->fp()), + fragment->profFragID); + debug_only_print0(LC_TMTracer, "\n"); +#endif + + return finishSuccessfully(); +} + +/* Emit code to adjust the stack to match the inner tree's stack expectations. */ +JS_REQUIRES_STACK void +TraceRecorder::prepareTreeCall(TreeFragment* inner) +{ + VMSideExit* exit = snapshot(OOM_EXIT); + + /* + * The inner tree expects to be called from the current frame. If the outer + * tree (this trace) is currently inside a function inlining code + * (calldepth > 0), we have to advance the native stack pointer such that + * we match what the inner trace expects to see. We move it back when we + * come out of the inner tree call. + */ + if (callDepth > 0) { + /* + * Calculate the amount we have to lift the native stack pointer by to + * compensate for any outer frames that the inner tree doesn't expect + * but the outer tree has. + */ + ptrdiff_t sp_adj = nativeStackOffset(&cx->fp()->calleeValue()); + + /* Calculate the amount we have to lift the call stack by. */ + ptrdiff_t rp_adj = callDepth * sizeof(FrameInfo*); + + /* + * Guard that we have enough stack space for the tree we are trying to + * call on top of the new value for sp. + */ + debug_only_printf(LC_TMTracer, + "sp_adj=%lld outer=%lld inner=%lld\n", + (long long int)sp_adj, + (long long int)tree->nativeStackBase, + (long long int)inner->nativeStackBase); + ptrdiff_t sp_offset = + - tree->nativeStackBase /* rebase sp to beginning of outer tree's stack */ + + sp_adj /* adjust for stack in outer frame inner tree can't see */ + + inner->maxNativeStackSlots * sizeof(double); /* plus the inner tree's stack */ + LIns* sp_top = w.addp(lirbuf->sp, w.nameImmw(sp_offset)); + guard(true, w.ltp(sp_top, eos_ins), exit); + + /* Guard that we have enough call stack space. */ + ptrdiff_t rp_offset = rp_adj + inner->maxCallDepth * sizeof(FrameInfo*); + LIns* rp_top = w.addp(lirbuf->rp, w.nameImmw(rp_offset)); + guard(true, w.ltp(rp_top, eor_ins), exit); + + sp_offset = + - tree->nativeStackBase /* rebase sp to beginning of outer tree's stack */ + + sp_adj /* adjust for stack in outer frame inner tree can't see */ + + inner->nativeStackBase; /* plus the inner tree's stack base */ + /* We have enough space, so adjust sp and rp to their new level. */ + w.stStateField(w.addp(lirbuf->sp, w.nameImmw(sp_offset)), sp); + w.stStateField(w.addp(lirbuf->rp, w.nameImmw(rp_adj)), rp); + } + + /* + * The inner tree will probably access stack slots. So tell nanojit not to + * discard or defer stack writes before emitting the call tree code. + * + * (The ExitType of this snapshot is nugatory. The exit can't be taken.) + */ + w.xbarrier(createGuardRecord(exit)); +} + +class ClearSlotsVisitor : public SlotVisitorBase +{ + Tracker &tracker; + public: + ClearSlotsVisitor(Tracker &tracker) + : tracker(tracker) + {} + + JS_ALWAYS_INLINE bool + visitStackSlots(Value *vp, size_t count, JSStackFrame *) { + for (Value *vpend = vp + count; vp != vpend; ++vp) + tracker.set(vp, NULL); + return true; + } + + JS_ALWAYS_INLINE bool + visitFrameObjPtr(void *p, JSStackFrame *) { + tracker.set(p, NULL); + return true; + } +}; + +static unsigned +BuildGlobalTypeMapFromInnerTree(Queue& typeMap, VMSideExit* inner) +{ +#if defined DEBUG + unsigned initialSlots = typeMap.length(); +#endif + /* First, use the innermost exit's global typemap. */ + typeMap.add(inner->globalTypeMap(), inner->numGlobalSlots); + + /* Add missing global types from the innermost exit's tree. */ + TreeFragment* innerFrag = inner->root(); + unsigned slots = inner->numGlobalSlots; + if (slots < innerFrag->nGlobalTypes()) { + typeMap.add(innerFrag->globalTypeMap() + slots, innerFrag->nGlobalTypes() - slots); + slots = innerFrag->nGlobalTypes(); + } + JS_ASSERT(typeMap.length() - initialSlots == slots); + return slots; +} + +/* Record a call to an inner tree. */ +JS_REQUIRES_STACK void +TraceRecorder::emitTreeCall(TreeFragment* inner, VMSideExit* exit) +{ + /* Invoke the inner tree. */ + LIns* args[] = { lirbuf->state }; /* reverse order */ + /* Construct a call info structure for the target tree. */ + CallInfo* ci = new (traceAlloc()) CallInfo(); + ci->_address = uintptr_t(inner->code()); + JS_ASSERT(ci->_address); + ci->_typesig = CallInfo::typeSig1(ARGTYPE_P, ARGTYPE_P); + ci->_isPure = 0; + ci->_storeAccSet = ACCSET_STORE_ANY; + ci->_abi = ABI_FASTCALL; +#ifdef DEBUG + ci->_name = "fragment"; +#endif + LIns* rec = w.call(ci, args); + LIns* lr = w.ldpGuardRecordExit(rec); + LIns* nested = w.jtUnoptimizable(w.eqiN(w.ldiVMSideExitField(lr, exitType), NESTED_EXIT)); + + /* + * If the tree exits on a regular (non-nested) guard, keep updating lastTreeExitGuard + * with that guard. If we mismatch on a tree call guard, this will contain the last + * non-nested guard we encountered, which is the innermost loop or branch guard. + */ + w.stStateField(lr, lastTreeExitGuard); + LIns* done1 = w.j(NULL); + + /* + * The tree exited on a nested guard. This only occurs once a tree call guard mismatches + * and we unwind the tree call stack. We store the first (innermost) tree call guard in state + * and we will try to grow the outer tree the failing call was in starting at that guard. + */ + w.label(nested); + LIns* done2 = w.jfUnoptimizable(w.eqp0(w.ldpStateField(lastTreeCallGuard))); + w.stStateField(lr, lastTreeCallGuard); + w.stStateField(w.addp(w.ldpStateField(rp), + w.i2p(w.lshiN(w.ldiVMSideExitField(lr, calldepth), + sizeof(void*) == 4 ? 2 : 3))), + rpAtLastTreeCall); + w.label(done1, done2); + + /* + * Keep updating outermostTreeExit so that TracerState always contains the most recent + * side exit. + */ + w.stStateField(lr, outermostTreeExitGuard); + + /* Read back all registers, in case the called tree changed any of them. */ +#ifdef DEBUG + JSValueType* map; + size_t i; + map = exit->globalTypeMap(); + for (i = 0; i < exit->numGlobalSlots; i++) + JS_ASSERT(map[i] != JSVAL_TYPE_BOXED); + map = exit->stackTypeMap(); + for (i = 0; i < exit->numStackSlots; i++) + JS_ASSERT(map[i] != JSVAL_TYPE_BOXED); +#endif + + /* The inner tree may modify currently-tracked upvars, so flush everything. */ + ClearSlotsVisitor visitor(tracker); + VisitStackSlots(visitor, cx, callDepth); + SlotList& gslots = *tree->globalSlots; + for (unsigned i = 0; i < gslots.length(); i++) { + unsigned slot = gslots[i]; + Value* vp = &globalObj->getSlotRef(slot); + tracker.set(vp, NULL); + } + + /* Set stack slots from the innermost frame. */ + importTypeMap.setLength(NativeStackSlots(cx, callDepth)); + unsigned startOfInnerFrame = importTypeMap.length() - exit->numStackSlots; + for (unsigned i = 0; i < exit->numStackSlots; i++) + importTypeMap[startOfInnerFrame + i] = exit->stackTypeMap()[i]; + importStackSlots = importTypeMap.length(); + JS_ASSERT(importStackSlots == NativeStackSlots(cx, callDepth)); + + /* + * Bug 502604 - It is illegal to extend from the outer typemap without + * first extending from the inner. Make a new typemap here. + */ + BuildGlobalTypeMapFromInnerTree(importTypeMap, exit); + + importGlobalSlots = importTypeMap.length() - importStackSlots; + JS_ASSERT(importGlobalSlots == tree->globalSlots->length()); + + /* Restore sp and rp to their original values (we still have them in a register). */ + if (callDepth > 0) { + w.stStateField(lirbuf->sp, sp); + w.stStateField(lirbuf->rp, rp); + } + + /* + * Guard that we come out of the inner tree along the same side exit we came out when + * we called the inner tree at recording time. + */ + VMSideExit* nestedExit = snapshot(NESTED_EXIT); + JS_ASSERT(exit->exitType == LOOP_EXIT); + guard(true, w.eqp(lr, w.nameImmpNonGC(exit)), nestedExit); + debug_only_printf(LC_TMTreeVis, "TREEVIS TREECALL INNER=%p EXIT=%p GUARD=%p\n", (void*)inner, + (void*)nestedExit, (void*)exit); + + /* Register us as a dependent tree of the inner tree. */ + inner->dependentTrees.addUnique(fragment->root); + tree->linkedTrees.addUnique(inner); +} + +/* Add a if/if-else control-flow merge point to the list of known merge points. */ +JS_REQUIRES_STACK void +TraceRecorder::trackCfgMerges(jsbytecode* pc) +{ + /* If we hit the beginning of an if/if-else, then keep track of the merge point after it. */ + JS_ASSERT((*pc == JSOP_IFEQ) || (*pc == JSOP_IFEQX)); + jssrcnote* sn = js_GetSrcNote(cx->fp()->script(), pc); + if (sn != NULL) { + if (SN_TYPE(sn) == SRC_IF) { + cfgMerges.add((*pc == JSOP_IFEQ) + ? pc + GET_JUMP_OFFSET(pc) + : pc + GET_JUMPX_OFFSET(pc)); + } else if (SN_TYPE(sn) == SRC_IF_ELSE) + cfgMerges.add(pc + js_GetSrcNoteOffset(sn, 0)); + } +} + +/* + * Invert the direction of the guard if this is a loop edge that is not + * taken (thin loop). + */ +JS_REQUIRES_STACK void +TraceRecorder::emitIf(jsbytecode* pc, bool cond, LIns* x) +{ + ExitType exitType; + JS_ASSERT(isCond(x)); + if (IsLoopEdge(pc, (jsbytecode*)tree->ip)) { + exitType = LOOP_EXIT; + + /* + * If we are about to walk out of the loop, generate code for the + * inverse loop condition, pretending we recorded the case that stays + * on trace. + */ + if ((*pc == JSOP_IFEQ || *pc == JSOP_IFEQX) == cond) { + JS_ASSERT(*pc == JSOP_IFNE || *pc == JSOP_IFNEX || *pc == JSOP_IFEQ || *pc == JSOP_IFEQX); + debug_only_print0(LC_TMTracer, + "Walking out of the loop, terminating it anyway.\n"); + cond = !cond; + } + + /* + * Conditional guards do not have to be emitted if the condition is + * constant. We make a note whether the loop condition is true or false + * here, so we later know whether to emit a loop edge or a loop end. + */ + if (x->isImmI()) { + pendingLoop = (x->immI() == int32(cond)); + return; + } + } else { + exitType = BRANCH_EXIT; + } + if (!x->isImmI()) + guard(cond, x, exitType); +} + +/* Emit code for a fused IFEQ/IFNE. */ +JS_REQUIRES_STACK void +TraceRecorder::fuseIf(jsbytecode* pc, bool cond, LIns* x) +{ + if (*pc == JSOP_IFEQ || *pc == JSOP_IFNE) { + emitIf(pc, cond, x); + if (*pc == JSOP_IFEQ) + trackCfgMerges(pc); + } +} + +/* Check whether we have reached the end of the trace. */ +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::checkTraceEnd(jsbytecode *pc) +{ + if (IsLoopEdge(pc, (jsbytecode*)tree->ip)) { + /* + * If we compile a loop, the trace should have a zero stack balance at + * the loop edge. Currently we are parked on a comparison op or + * IFNE/IFEQ, so advance pc to the loop header and adjust the stack + * pointer and pretend we have reached the loop header. + */ + if (pendingLoop) { + JS_ASSERT(!cx->fp()->hasImacropc() && (pc == cx->regs->pc || pc == cx->regs->pc + 1)); + JSFrameRegs orig = *cx->regs; + + cx->regs->pc = (jsbytecode*)tree->ip; + cx->regs->sp = cx->fp()->base() + tree->spOffsetAtEntry; + + JSContext* localcx = cx; + AbortableRecordingStatus ars = closeLoop(); + *localcx->regs = orig; + return ars; + } + + return endLoop(); + } + return ARECORD_CONTINUE; +} + +/* + * Check whether the shape of the global object has changed. The return value + * indicates whether the recorder is still active. If 'false', any active + * recording has been aborted and the JIT may have been reset. + */ +static JS_REQUIRES_STACK bool +CheckGlobalObjectShape(JSContext* cx, TraceMonitor* tm, JSObject* globalObj, + uint32 *shape = NULL, SlotList** slots = NULL) +{ + if (tm->needFlush) { + ResetJIT(cx, tm, FR_DEEP_BAIL); + return false; + } + + if (globalObj->numSlots() > MAX_GLOBAL_SLOTS) { + if (tm->recorder) + AbortRecording(cx, "too many slots in global object"); + return false; + } + + /* + * The global object must have a unique shape. That way, if an operand + * isn't the global at record time, a shape guard suffices to ensure + * that it isn't the global at run time. + */ + if (!globalObj->hasOwnShape()) { + if (!globalObj->globalObjectOwnShapeChange(cx)) { + debug_only_print0(LC_TMTracer, + "Can't record: failed to give globalObj a unique shape.\n"); + return false; + } + } + + uint32 globalShape = globalObj->shape(); + + if (tm->recorder) { + TreeFragment* root = tm->recorder->getFragment()->root; + + /* Check the global shape matches the recorder's treeinfo's shape. */ + if (globalObj != root->globalObj || globalShape != root->globalShape) { + AUDIT(globalShapeMismatchAtEntry); + debug_only_printf(LC_TMTracer, + "Global object/shape mismatch (%p/%u vs. %p/%u), flushing cache.\n", + (void*)globalObj, globalShape, (void*)root->globalObj, + root->globalShape); + Backoff(tm, (jsbytecode*) root->ip); + ResetJIT(cx, tm, FR_GLOBAL_SHAPE_MISMATCH); + return false; + } + if (shape) + *shape = globalShape; + if (slots) + *slots = root->globalSlots; + return true; + } + + /* No recorder, search for a tracked global-state (or allocate one). */ + for (size_t i = 0; i < MONITOR_N_GLOBAL_STATES; ++i) { + GlobalState &state = tm->globalStates[i]; + + if (state.globalShape == uint32(-1)) { + state.globalObj = globalObj; + state.globalShape = globalShape; + JS_ASSERT(state.globalSlots); + JS_ASSERT(state.globalSlots->length() == 0); + } + + if (state.globalObj == globalObj && state.globalShape == globalShape) { + if (shape) + *shape = globalShape; + if (slots) + *slots = state.globalSlots; + return true; + } + } + + /* No currently-tracked-global found and no room to allocate, abort. */ + AUDIT(globalShapeMismatchAtEntry); + debug_only_printf(LC_TMTracer, + "No global slotlist for global shape %u, flushing cache.\n", + globalShape); + ResetJIT(cx, tm, FR_GLOBALS_FULL); + return false; +} + +/* + * Return whether or not the recorder could be started. If 'false', the JIT has + * been reset in response to an OOM. + */ +bool JS_REQUIRES_STACK +TraceRecorder::startRecorder(JSContext* cx, TraceMonitor *tm, VMSideExit* anchor, VMFragment* f, + unsigned stackSlots, unsigned ngslots, + JSValueType* typeMap, VMSideExit* expectedInnerExit, + JSScript* outerScript, jsbytecode* outerPC, uint32 outerArgc, + bool speculate) +{ + JS_ASSERT(!tm->needFlush); + JS_ASSERT_IF(cx->fp()->hasImacropc(), f->root != f); + + /* We can't (easily) use js_new() here because the constructor is private. */ + void *memory = js_malloc(sizeof(TraceRecorder)); + tm->recorder = memory + ? new(memory) TraceRecorder(cx, tm, anchor, f, stackSlots, ngslots, typeMap, + expectedInnerExit, outerScript, outerPC, outerArgc, + speculate) + : NULL; + + if (!tm->recorder || tm->outOfMemory() || OverfullJITCache(cx, tm)) { + ResetJIT(cx, tm, FR_OOM); + return false; + } + + return true; +} + +static void +TrashTree(TreeFragment* f) +{ + JS_ASSERT(f == f->root); + debug_only_printf(LC_TMTreeVis, "TREEVIS TRASH FRAG=%p\n", (void*)f); + + if (!f->code()) + return; + AUDIT(treesTrashed); + debug_only_print0(LC_TMTracer, "Trashing tree info.\n"); + f->setCode(NULL); + TreeFragment** data = f->dependentTrees.data(); + unsigned length = f->dependentTrees.length(); + for (unsigned n = 0; n < length; ++n) + TrashTree(data[n]); + data = f->linkedTrees.data(); + length = f->linkedTrees.length(); + for (unsigned n = 0; n < length; ++n) + TrashTree(data[n]); +} + +static void +SynthesizeFrame(JSContext* cx, const FrameInfo& fi, JSObject* callee) +{ + VOUCH_DOES_NOT_REQUIRE_STACK(); + + /* Assert that we have a correct sp distance from cx->fp()->slots in fi. */ + JSStackFrame* const fp = cx->fp(); + JS_ASSERT_IF(!fi.imacpc, + js_ReconstructStackDepth(cx, fp->script(), fi.pc) == + uintN(fi.spdist - fp->numFixed())); + + /* Use the just-flushed prev-frame to get the callee function. */ + JSFunction* newfun = callee->getFunctionPrivate(); + JSScript* newscript = newfun->script(); + + /* Fill in the prev-frame's sp. */ + JSFrameRegs *regs = cx->regs; + regs->sp = fp->slots() + fi.spdist; + regs->pc = fi.pc; + if (fi.imacpc) + fp->setImacropc(fi.imacpc); + + /* Set argc/flags then mimic JSOP_CALL. */ + uintN argc = fi.get_argc(); + uint32 flags = fi.is_constructing () + ? JSFRAME_CONSTRUCTING | JSFRAME_CONSTRUCTING + : 0; + + /* Get pointer to new/frame/slots, prepare arguments. */ + StackSpace &stack = cx->stack(); + JSStackFrame *newfp = stack.getInlineFrame(cx, regs->sp, argc, newfun, + newscript, &flags); + + /* Initialize frame; do not need to initialize locals. */ + newfp->initCallFrame(cx, *callee, newfun, argc, flags); + +#ifdef DEBUG + /* The stack is conservatively marked, so we can leave non-canonical args uninitialized. */ + if (newfp->hasOverflowArgs()) { + Value *beg = newfp->actualArgs() - 2; + Value *end = newfp->actualArgs() + newfp->numFormalArgs(); + for (Value *p = beg; p != end; ++p) + p->setMagic(JS_ARG_POISON); + } + + /* These should be initialized by FlushNativeStackFrame. */ + newfp->thisValue().setMagic(JS_THIS_POISON); + newfp->setScopeChainNoCallObj(*JSStackFrame::sInvalidScopeChain); +#endif + + /* Officially push the frame. */ + stack.pushInlineFrame(cx, newscript, newfp, cx->regs); + + /* Call object will be set by FlushNativeStackFrame. */ + + /* Call the debugger hook if present. */ + JSInterpreterHook hook = cx->debugHooks->callHook; + if (hook) { + newfp->setHookData(hook(cx, newfp, JS_TRUE, 0, + cx->debugHooks->callHookData)); + } +} + +static JS_REQUIRES_STACK bool +RecordTree(JSContext* cx, TraceMonitor* tm, TreeFragment* first, + JSScript* outerScript, jsbytecode* outerPC, + uint32 outerArgc, SlotList* globalSlots) +{ + /* Try to find an unused peer fragment, or allocate a new one. */ + JS_ASSERT(first->first == first); + TreeFragment* f = NULL; + size_t count = 0; + for (TreeFragment* peer = first; peer; peer = peer->peer, ++count) { + if (!peer->code()) + f = peer; + } + if (!f) + f = AddNewPeerToPeerList(tm, first); + JS_ASSERT(f->root == f); + + /* Disable speculation if we are starting to accumulate a lot of trees. */ + bool speculate = count < MAXPEERS-1; + + /* save a local copy for use after JIT flush */ + const void* localRootIP = f->root->ip; + + /* Make sure the global type map didn't change on us. */ + if (!CheckGlobalObjectShape(cx, tm, f->globalObj)) { + Backoff(tm, (jsbytecode*) localRootIP); + return false; + } + + AUDIT(recorderStarted); + + if (tm->outOfMemory() || + OverfullJITCache(cx, tm) || + !tm->tracedScripts.put(cx->fp()->script())) + { + if (!OverfullJITCache(cx, tm)) + js_ReportOutOfMemory(cx); + Backoff(tm, (jsbytecode*) f->root->ip); + ResetJIT(cx, tm, FR_OOM); + debug_only_print0(LC_TMTracer, + "Out of memory recording new tree, flushing cache.\n"); + return false; + } + + JS_ASSERT(!f->code()); + + f->initialize(cx, globalSlots, speculate); + +#ifdef DEBUG + AssertTreeIsUnique(tm, f); +#endif +#ifdef JS_JIT_SPEW + debug_only_printf(LC_TMTreeVis, "TREEVIS CREATETREE ROOT=%p PC=%p FILE=\"%s\" LINE=%d OFFS=%d", + (void*)f, f->ip, f->treeFileName, f->treeLineNumber, + FramePCOffset(cx, cx->fp())); + debug_only_print0(LC_TMTreeVis, " STACK=\""); + for (unsigned i = 0; i < f->nStackTypes; i++) + debug_only_printf(LC_TMTreeVis, "%c", TypeToChar(f->typeMap[i])); + debug_only_print0(LC_TMTreeVis, "\" GLOBALS=\""); + for (unsigned i = 0; i < f->nGlobalTypes(); i++) + debug_only_printf(LC_TMTreeVis, "%c", TypeToChar(f->typeMap[f->nStackTypes + i])); + debug_only_print0(LC_TMTreeVis, "\"\n"); +#endif + + /* Recording primary trace. */ + return TraceRecorder::startRecorder(cx, tm, NULL, f, f->nStackTypes, + f->globalSlots->length(), + f->typeMap.data(), NULL, + outerScript, outerPC, outerArgc, speculate); +} + +static JS_REQUIRES_STACK TypeConsensus +FindLoopEdgeTarget(JSContext* cx, TraceMonitor* tm, VMSideExit* exit, TreeFragment** peerp) +{ + TreeFragment* from = exit->root(); + + JS_ASSERT(from->code()); + Oracle* oracle = tm->oracle; + + TypeMap typeMap(NULL, oracle); + FullMapFromExit(typeMap, exit); + JS_ASSERT(typeMap.length() - exit->numStackSlots == from->nGlobalTypes()); + + /* Mark all double slots as undemotable */ + uint16* gslots = from->globalSlots->data(); + for (unsigned i = 0; i < typeMap.length(); i++) { + if (typeMap[i] == JSVAL_TYPE_DOUBLE) { + if (i < from->nStackTypes) + oracle->markStackSlotUndemotable(cx, i, from->ip); + else if (i >= exit->numStackSlots) + oracle->markGlobalSlotUndemotable(cx, gslots[i - exit->numStackSlots]); + } + } + + JS_ASSERT(exit->exitType == UNSTABLE_LOOP_EXIT); + + TreeFragment* firstPeer = from->first; + + for (TreeFragment* peer = firstPeer; peer; peer = peer->peer) { + if (!peer->code()) + continue; + JS_ASSERT(peer->argc == from->argc); + JS_ASSERT(exit->numStackSlots == peer->nStackTypes); + TypeConsensus consensus = TypeMapLinkability(cx, tm, typeMap, peer); + if (consensus == TypeConsensus_Okay || consensus == TypeConsensus_Undemotes) { + *peerp = peer; + return consensus; + } + } + + return TypeConsensus_Bad; +} + +static JS_REQUIRES_STACK bool +AttemptToStabilizeTree(JSContext* cx, TraceMonitor* tm, JSObject* globalObj, VMSideExit* exit, + JSScript* outerScript, jsbytecode* outerPC, uint32 outerArgc) +{ + if (tm->needFlush) { + ResetJIT(cx, tm, FR_DEEP_BAIL); + return false; + } + + TreeFragment* from = exit->root(); + + TreeFragment* peer = NULL; + TypeConsensus consensus = FindLoopEdgeTarget(cx, tm, exit, &peer); + if (consensus == TypeConsensus_Okay) { + JS_ASSERT(from->globalSlots == peer->globalSlots); + JS_ASSERT_IF(exit->exitType == UNSTABLE_LOOP_EXIT, + from->nStackTypes == peer->nStackTypes); + JS_ASSERT(exit->numStackSlots == peer->nStackTypes); + /* Patch this exit to its peer */ + JoinPeers(tm->assembler, exit, peer); + /* + * Update peer global types. The |from| fragment should already be updated because it on + * the execution path, and somehow connected to the entry trace. + */ + if (peer->nGlobalTypes() < peer->globalSlots->length()) + SpecializeTreesToMissingGlobals(cx, globalObj, peer); + JS_ASSERT(from->nGlobalTypes() == from->globalSlots->length()); + /* This exit is no longer unstable, so remove it. */ + if (exit->exitType == UNSTABLE_LOOP_EXIT) + from->removeUnstableExit(exit); + debug_only_stmt(DumpPeerStability(tm, peer->ip, globalObj, from->globalShape, from->argc);) + return false; + } else if (consensus == TypeConsensus_Undemotes) { + /* The original tree is unconnectable, so trash it. */ + TrashTree(peer); + return false; + } + + SlotList *globalSlots = from->globalSlots; + + JS_ASSERT(from == from->root); + + /* If this tree has been blacklisted, don't try to record a new one. */ + if (*(jsbytecode*)from->ip == JSOP_NOTRACE) + return false; + + return RecordTree(cx, tm, from->first, outerScript, outerPC, outerArgc, globalSlots); +} + +static JS_REQUIRES_STACK VMFragment* +CreateBranchFragment(JSContext* cx, TraceMonitor* tm, TreeFragment* root, VMSideExit* anchor) +{ + verbose_only( + uint32_t profFragID = (LogController.lcbits & LC_FragProfile) + ? (++(tm->lastFragID)) : 0; + ) + + VMFragment* f = new (*tm->dataAlloc) VMFragment(cx->regs->pc verbose_only(, profFragID)); + + debug_only_printf(LC_TMTreeVis, "TREEVIS CREATEBRANCH ROOT=%p FRAG=%p PC=%p FILE=\"%s\"" + " LINE=%d ANCHOR=%p OFFS=%d\n", + (void*)root, (void*)f, (void*)cx->regs->pc, cx->fp()->script()->filename, + js_FramePCToLineNumber(cx, cx->fp()), (void*)anchor, + FramePCOffset(cx, cx->fp())); + verbose_only( tm->branches = new (*tm->dataAlloc) Seq(f, tm->branches); ) + + f->root = root; + if (anchor) + anchor->target = f; + return f; +} + +static JS_REQUIRES_STACK bool +AttemptToExtendTree(JSContext* cx, TraceMonitor* tm, VMSideExit* anchor, VMSideExit* exitedFrom, + JSScript *outerScript, jsbytecode* outerPC +#ifdef MOZ_TRACEVIS + , TraceVisStateObj* tvso = NULL +#endif + ) +{ + JS_ASSERT(!tm->recorder); + + if (tm->needFlush) { + ResetJIT(cx, tm, FR_DEEP_BAIL); +#ifdef MOZ_TRACEVIS + if (tvso) tvso->r = R_FAIL_EXTEND_FLUSH; +#endif + return false; + } + + TreeFragment* f = anchor->root(); + JS_ASSERT(f->code()); + + /* + * Don't grow trees above a certain size to avoid code explosion due to + * tail duplication. + */ + if (f->branchCount >= MAX_BRANCHES) { +#ifdef JS_METHODJIT + if (cx->methodJitEnabled && cx->profilingEnabled) + Blacklist((jsbytecode *)f->ip); +#endif +#ifdef MOZ_TRACEVIS + if (tvso) tvso->r = R_FAIL_EXTEND_MAX_BRANCHES; +#endif + return false; + } + + VMFragment* c = (VMFragment*)anchor->target; + if (!c) { + c = CreateBranchFragment(cx, tm, f, anchor); + } else { + /* + * If we are recycling a fragment, it might have a different ip so reset it + * here. This can happen when attaching a branch to a NESTED_EXIT, which + * might extend along separate paths (i.e. after the loop edge, and after a + * return statement). + */ + c->ip = cx->regs->pc; + JS_ASSERT(c->root == f); + } + + debug_only_printf(LC_TMTracer, + "trying to attach another branch to the tree (hits = %d)\n", c->hits()); + + int32_t& hits = c->hits(); + int32_t maxHits = HOTEXIT + MAXEXIT; + if (anchor->exitType == CASE_EXIT) + maxHits *= anchor->switchInfo->count; + if (outerPC || (hits++ >= HOTEXIT && hits <= maxHits)) { + /* start tracing secondary trace from this point */ + unsigned stackSlots; + unsigned ngslots; + JSValueType* typeMap; + TypeMap fullMap(NULL, tm->oracle); + if (!exitedFrom) { + /* + * If we are coming straight from a simple side exit, just use that + * exit's type map as starting point. + */ + ngslots = anchor->numGlobalSlots; + stackSlots = anchor->numStackSlots; + typeMap = anchor->fullTypeMap(); + } else { + /* + * If we side-exited on a loop exit and continue on a nesting + * guard, the nesting guard (anchor) has the type information for + * everything below the current scope, and the actual guard we + * exited from has the types for everything in the current scope + * (and whatever it inlined). We have to merge those maps here. + */ + VMSideExit* e1 = anchor; + VMSideExit* e2 = exitedFrom; + fullMap.add(e1->stackTypeMap(), e1->numStackSlotsBelowCurrentFrame); + fullMap.add(e2->stackTypeMap(), e2->numStackSlots); + stackSlots = fullMap.length(); + ngslots = BuildGlobalTypeMapFromInnerTree(fullMap, e2); + JS_ASSERT(ngslots >= e1->numGlobalSlots); // inner tree must have all globals + JS_ASSERT(ngslots == fullMap.length() - stackSlots); + typeMap = fullMap.data(); + } + JS_ASSERT(ngslots >= anchor->numGlobalSlots); + bool rv = TraceRecorder::startRecorder(cx, tm, anchor, c, stackSlots, ngslots, typeMap, + exitedFrom, outerScript, outerPC, f->argc, + hits < maxHits); +#ifdef MOZ_TRACEVIS + if (!rv && tvso) + tvso->r = R_FAIL_EXTEND_START; +#endif + return rv; + } +#ifdef MOZ_TRACEVIS + if (tvso) tvso->r = R_FAIL_EXTEND_COLD; +#endif + return false; +} + +static JS_REQUIRES_STACK bool +ExecuteTree(JSContext* cx, TraceMonitor* tm, TreeFragment* f, uintN& inlineCallCount, + VMSideExit** innermostNestedGuardp, VMSideExit** lrp); + +static inline MonitorResult +RecordingIfTrue(bool b) +{ + return b ? MONITOR_RECORDING : MONITOR_NOT_RECORDING; +} + +/* + * A postcondition of recordLoopEdge is that if recordLoopEdge does not return + * MONITOR_RECORDING, the recording has been aborted. + */ +JS_REQUIRES_STACK MonitorResult +TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount) +{ + TraceMonitor* tm = r->traceMonitor; + + /* Process needFlush and deep abort requests. */ + if (tm->needFlush) { + ResetJIT(cx, tm, FR_DEEP_BAIL); + return MONITOR_NOT_RECORDING; + } + + JS_ASSERT(r->fragment && !r->fragment->lastIns); + TreeFragment* root = r->fragment->root; + TreeFragment* first = LookupOrAddLoop(tm, cx->regs->pc, root->globalObj, + root->globalShape, entryFrameArgc(cx)); + + /* + * Make sure the shape of the global object still matches (this might flush + * the JIT cache). + */ + JSObject* globalObj = cx->fp()->scopeChain().getGlobal(); + uint32 globalShape = -1; + SlotList* globalSlots = NULL; + if (!CheckGlobalObjectShape(cx, tm, globalObj, &globalShape, &globalSlots)) { + JS_ASSERT(!tm->recorder); + return MONITOR_NOT_RECORDING; + } + + debug_only_printf(LC_TMTracer, + "Looking for type-compatible peer (%s:%d@%d)\n", + cx->fp()->script()->filename, + js_FramePCToLineNumber(cx, cx->fp()), + FramePCOffset(cx, cx->fp())); + + // Find a matching inner tree. If none can be found, compile one. + TreeFragment* f = r->findNestedCompatiblePeer(first); + if (!f || !f->code()) { + AUDIT(noCompatInnerTrees); + + TreeFragment* outerFragment = root; + JSScript* outerScript = outerFragment->script; + jsbytecode* outerPC = (jsbytecode*) outerFragment->ip; + uint32 outerArgc = outerFragment->argc; + JS_ASSERT(entryFrameArgc(cx) == first->argc); + + if (AbortRecording(cx, "No compatible inner tree") == JIT_RESET) + return MONITOR_NOT_RECORDING; + + return RecordingIfTrue(RecordTree(cx, tm, first, + outerScript, outerPC, outerArgc, globalSlots)); + } + + AbortableRecordingStatus status = r->attemptTreeCall(f, inlineCallCount); + if (status == ARECORD_CONTINUE) + return MONITOR_RECORDING; + if (status == ARECORD_ERROR) { + if (tm->recorder) + AbortRecording(cx, "Error returned while recording loop edge"); + return MONITOR_ERROR; + } + JS_ASSERT(status == ARECORD_ABORTED && !tm->recorder); + return MONITOR_NOT_RECORDING; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::attemptTreeCall(TreeFragment* f, uintN& inlineCallCount) +{ + adjustCallerTypes(f); + prepareTreeCall(f); + +#ifdef DEBUG + uintN oldInlineCallCount = inlineCallCount; +#endif + + JSContext *localCx = cx; + TraceMonitor *localtm = traceMonitor; + + // Refresh the import type map so the tracker can reimport values after the + // call with their correct types. The inner tree must not change the type of + // any variable in a frame above the current one (i.e., upvars). + // + // Note that DetermineTypesVisitor may call determineSlotType, which may + // read from the (current, stale) import type map, but this is safe here. + // The reason is that determineSlotType will read the import type map only + // if there is not a tracker instruction for that value, which means that + // value has not been written yet, so that type map entry is up to date. + importTypeMap.setLength(NativeStackSlots(cx, callDepth)); + DetermineTypesVisitor visitor(*this, importTypeMap.data()); + VisitStackSlots(visitor, cx, callDepth); + + VMSideExit* innermostNestedGuard = NULL; + VMSideExit* lr; + bool ok = ExecuteTree(cx, traceMonitor, f, inlineCallCount, &innermostNestedGuard, &lr); + + /* + * If ExecuteTree reentered the interpreter, it may have killed |this| + * and/or caused an error, which must be propagated. + */ + JS_ASSERT_IF(localtm->recorder, localtm->recorder == this); + if (!ok) + return ARECORD_ERROR; + if (!localtm->recorder) + return ARECORD_ABORTED; + + if (!lr) { + AbortRecording(cx, "Couldn't call inner tree"); + return ARECORD_ABORTED; + } + + TreeFragment* outerFragment = tree; + JSScript* outerScript = outerFragment->script; + jsbytecode* outerPC = (jsbytecode*) outerFragment->ip; + switch (lr->exitType) { + case LOOP_EXIT: + /* If the inner tree exited on an unknown loop exit, grow the tree around it. */ + if (innermostNestedGuard) { + if (AbortRecording(cx, "Inner tree took different side exit, abort current " + "recording and grow nesting tree") == JIT_RESET) { + return ARECORD_ABORTED; + } + return AttemptToExtendTree(localCx, localtm, + innermostNestedGuard, lr, outerScript, outerPC) + ? ARECORD_CONTINUE + : ARECORD_ABORTED; + } + + JS_ASSERT(oldInlineCallCount == inlineCallCount); + + /* Emit a call to the inner tree and continue recording the outer tree trace. */ + emitTreeCall(f, lr); + return ARECORD_CONTINUE; + + case UNSTABLE_LOOP_EXIT: + { + /* Abort recording so the inner loop can become type stable. */ + JSObject* _globalObj = globalObj; + if (AbortRecording(cx, "Inner tree is trying to stabilize, " + "abort outer recording") == JIT_RESET) { + return ARECORD_ABORTED; + } + return AttemptToStabilizeTree(localCx, localtm, _globalObj, lr, outerScript, outerPC, + outerFragment->argc) + ? ARECORD_CONTINUE + : ARECORD_ABORTED; + } + + case MUL_ZERO_EXIT: + case OVERFLOW_EXIT: + if (lr->exitType == MUL_ZERO_EXIT) + traceMonitor->oracle->markInstructionSlowZeroTest(cx->regs->pc); + else + traceMonitor->oracle->markInstructionUndemotable(cx->regs->pc); + /* FALL THROUGH */ + case BRANCH_EXIT: + case CASE_EXIT: + /* Abort recording the outer tree, extend the inner tree. */ + if (AbortRecording(cx, "Inner tree is trying to grow, " + "abort outer recording") == JIT_RESET) { + return ARECORD_ABORTED; + } + return AttemptToExtendTree(localCx, localtm, lr, NULL, outerScript, outerPC) + ? ARECORD_CONTINUE + : ARECORD_ABORTED; + + case NESTED_EXIT: + JS_NOT_REACHED("NESTED_EXIT should be replaced by innermost side exit"); + default: + debug_only_printf(LC_TMTracer, "exit_type=%s\n", getExitName(lr->exitType)); + AbortRecording(cx, "Inner tree not suitable for calling"); + return ARECORD_ABORTED; + } +} + +static inline bool +IsEntryTypeCompatible(const Value &v, JSValueType type) +{ + bool ok; + + JS_ASSERT(type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET); + JS_ASSERT(type != JSVAL_TYPE_OBJECT); /* JSVAL_TYPE_OBJECT does not belong in a type map */ + + if (v.isInt32()) { + ok = (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_DOUBLE); + + } else if (v.isDouble()) { + int32_t _; + ok = (type == JSVAL_TYPE_DOUBLE) || + (type == JSVAL_TYPE_INT32 && JSDOUBLE_IS_INT32(v.toDouble(), &_)); + + } else if (v.isObject()) { + ok = v.toObject().isFunction() + ? type == JSVAL_TYPE_FUNOBJ + : type == JSVAL_TYPE_NONFUNOBJ; + + } else { + ok = v.extractNonDoubleObjectTraceType() == type; + } +#ifdef DEBUG + char ttag = TypeToChar(type); + char vtag = ValueToTypeChar(v); + debug_only_printf(LC_TMTracer, "%c/%c ", vtag, ttag); + if (!ok) + debug_only_printf(LC_TMTracer, "%s", "(incompatible types)"); +#endif + return ok; +} + +static inline bool +IsFrameObjPtrTypeCompatible(void *p, JSStackFrame *fp, JSValueType type) +{ + debug_only_printf(LC_TMTracer, "%c/%c ", TypeToChar(type), + (p == fp->addressOfScopeChain() || fp->hasArgsObj()) + ? TypeToChar(JSVAL_TYPE_NONFUNOBJ) + : TypeToChar(JSVAL_TYPE_NULL)); + if (p == fp->addressOfScopeChain()) + return type == JSVAL_TYPE_NONFUNOBJ; + JS_ASSERT(p == fp->addressOfArgs()); + JS_ASSERT(type == JSVAL_TYPE_NONFUNOBJ || type == JSVAL_TYPE_NULL); + return fp->hasArgsObj() == (type == JSVAL_TYPE_NONFUNOBJ); +} + +class TypeCompatibilityVisitor : public SlotVisitorBase +{ + TraceRecorder &mRecorder; + JSContext *mCx; + Oracle *mOracle; + JSValueType *mTypeMap; + unsigned mStackSlotNum; + bool mOk; +public: + TypeCompatibilityVisitor (TraceRecorder &recorder, + JSValueType *typeMap) : + mRecorder(recorder), + mCx(mRecorder.cx), + mOracle(recorder.traceMonitor->oracle), + mTypeMap(typeMap), + mStackSlotNum(0), + mOk(true) + {} + + JS_REQUIRES_STACK JS_ALWAYS_INLINE void + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { + debug_only_printf(LC_TMTracer, "global%d=", n); + if (!IsEntryTypeCompatible(*vp, *mTypeMap)) { + mOk = false; + } else if (!IsPromotedInt32(mRecorder.get(vp)) && *mTypeMap == JSVAL_TYPE_INT32) { + mOracle->markGlobalSlotUndemotable(mCx, slot); + mOk = false; + } else if (vp->isInt32() && *mTypeMap == JSVAL_TYPE_DOUBLE) { + mOracle->markGlobalSlotUndemotable(mCx, slot); + } + mTypeMap++; + } + + /* + * For the below two methods, one may be inclined to 'return false' early + * when mOk is set to 'false'. Don't do that. It is very important to run + * through the whole list to let all mis-matching slots get marked + * undemotable in the oracle. + */ + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { + for (size_t i = 0; i < count; ++i) { + debug_only_printf(LC_TMTracer, "%s%u=", stackSlotKind(), unsigned(i)); + if (!IsEntryTypeCompatible(*vp, *mTypeMap)) { + mOk = false; + } else if (!IsPromotedInt32(mRecorder.get(vp)) && *mTypeMap == JSVAL_TYPE_INT32) { + mOracle->markStackSlotUndemotable(mCx, mStackSlotNum); + mOk = false; + } else if (vp->isInt32() && *mTypeMap == JSVAL_TYPE_DOUBLE) { + mOracle->markStackSlotUndemotable(mCx, mStackSlotNum); + } + vp++; + mTypeMap++; + mStackSlotNum++; + } + return true; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(void* p, JSStackFrame* fp) { + debug_only_printf(LC_TMTracer, "%s%u=", stackSlotKind(), 0); + if (!IsFrameObjPtrTypeCompatible(p, fp, *mTypeMap)) + mOk = false; + mTypeMap++; + mStackSlotNum++; + return true; + } + + bool isOk() { + return mOk; + } +}; + +JS_REQUIRES_STACK TreeFragment* +TraceRecorder::findNestedCompatiblePeer(TreeFragment* f) +{ + unsigned int ngslots = tree->globalSlots->length(); + + for (; f != NULL; f = f->peer) { + if (!f->code()) + continue; + + debug_only_printf(LC_TMTracer, "checking nested types %p: ", (void*)f); + + if (ngslots > f->nGlobalTypes()) + SpecializeTreesToMissingGlobals(cx, globalObj, f); + + /* + * Determine whether the typemap of the inner tree matches the outer + * tree's current state. If the inner tree expects an integer, but the + * outer tree doesn't guarantee an integer for that slot, we mark the + * slot undemotable and mismatch here. This will force a new tree to be + * compiled that accepts a double for the slot. If the inner tree + * expects a double, but the outer tree has an integer, we can proceed, + * but we mark the location undemotable. + */ + TypeCompatibilityVisitor visitor(*this, f->typeMap.data()); + VisitSlots(visitor, cx, 0, *tree->globalSlots); + + debug_only_printf(LC_TMTracer, " %s\n", visitor.isOk() ? "match" : ""); + if (visitor.isOk()) + return f; + } + + return NULL; +} + +class CheckEntryTypeVisitor : public SlotVisitorBase +{ + bool mOk; + JSValueType *mTypeMap; +public: + CheckEntryTypeVisitor(JSValueType *typeMap) : + mOk(true), + mTypeMap(typeMap) + {} + + JS_ALWAYS_INLINE void checkSlot(const Value &v, char const *name, int i) { + debug_only_printf(LC_TMTracer, "%s%d=", name, i); + JS_ASSERT(*(uint8_t*)mTypeMap != 0xCD); + mOk = IsEntryTypeCompatible(v, *mTypeMap++); + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE void + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { + if (mOk) + checkSlot(*vp, "global", n); + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { + for (size_t i = 0; i < count; ++i) { + if (!mOk) + break; + checkSlot(*vp++, stackSlotKind(), i); + } + return mOk; + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(void* p, JSStackFrame *fp) { + debug_only_printf(LC_TMTracer, "%s%d=", stackSlotKind(), 0); + JS_ASSERT(*(uint8_t*)mTypeMap != 0xCD); + return mOk = IsFrameObjPtrTypeCompatible(p, fp, *mTypeMap++); + } + + bool isOk() { + return mOk; + } +}; + +/** + * Check if types are usable for trace execution. + * + * @param cx Context. + * @param f Tree of peer we're testing. + * @return True if compatible (with or without demotions), false otherwise. + */ +static JS_REQUIRES_STACK bool +CheckEntryTypes(JSContext* cx, JSObject* globalObj, TreeFragment* f) +{ + unsigned int ngslots = f->globalSlots->length(); + + JS_ASSERT(f->nStackTypes == NativeStackSlots(cx, 0)); + + if (ngslots > f->nGlobalTypes()) + SpecializeTreesToMissingGlobals(cx, globalObj, f); + + JS_ASSERT(f->typeMap.length() == NativeStackSlots(cx, 0) + ngslots); + JS_ASSERT(f->typeMap.length() == f->nStackTypes + ngslots); + JS_ASSERT(f->nGlobalTypes() == ngslots); + + CheckEntryTypeVisitor visitor(f->typeMap.data()); + VisitSlots(visitor, cx, 0, *f->globalSlots); + + debug_only_print0(LC_TMTracer, "\n"); + return visitor.isOk(); +} + +/** + * Find an acceptable entry tree given a PC. + * + * @param cx Context. + * @param globalObj Global object. + * @param f First peer fragment. + * @param nodemote If true, will try to find a peer that does not require demotion. + * @out count Number of fragments consulted. + */ +static JS_REQUIRES_STACK TreeFragment* +FindVMCompatiblePeer(JSContext* cx, JSObject* globalObj, TreeFragment* f, uintN& count) +{ + count = 0; + for (; f != NULL; f = f->peer) { + if (!f->code()) + continue; + debug_only_printf(LC_TMTracer, + "checking vm types %p (ip: %p): ", (void*)f, f->ip); + if (CheckEntryTypes(cx, globalObj, f)) + return f; + ++count; + } + return NULL; +} + +/* + * For the native stacks and global frame, reuse the storage in |tm->storage|. + * This reuse depends on the invariant that only one trace uses |tm->storage| + * at a time. This is subtly correct in case of deep bail; see the comment + * about "clobbering deep bails" in DeepBail. + */ +JS_ALWAYS_INLINE +TracerState::TracerState(JSContext* cx, TraceMonitor* tm, TreeFragment* f, + uintN& inlineCallCount, VMSideExit** innermostNestedGuardp) + : cx(cx), + traceMonitor(tm), + stackBase(tm->storage->stack()), + sp(stackBase + f->nativeStackBase / sizeof(double)), + eos(tm->storage->global()), + callstackBase(tm->storage->callstack()), + sor(callstackBase), + rp(callstackBase), + eor(callstackBase + JS_MIN(MAX_CALL_STACK_ENTRIES, + JS_MAX_INLINE_CALL_COUNT - inlineCallCount)), + lastTreeExitGuard(NULL), + lastTreeCallGuard(NULL), + rpAtLastTreeCall(NULL), + outermostTree(f), + inlineCallCountp(&inlineCallCount), + innermostNestedGuardp(innermostNestedGuardp), +#ifdef EXECUTE_TREE_TIMER + startTime(rdtsc()), +#endif + builtinStatus(0), + nativeVp(NULL) +{ + JS_ASSERT(!tm->tracecx); + tm->tracecx = cx; + prev = tm->tracerState; + tm->tracerState = this; + +#ifdef JS_METHODJIT + if (TRACE_PROFILER(cx)) + AbortProfiling(cx); +#endif + + JS_ASSERT(JS_THREAD_DATA(cx)->onTraceCompartment == NULL); + JS_ASSERT(JS_THREAD_DATA(cx)->recordingCompartment == NULL || + JS_THREAD_DATA(cx)->recordingCompartment == cx->compartment); + JS_ASSERT(JS_THREAD_DATA(cx)->profilingCompartment == NULL); + JS_THREAD_DATA(cx)->onTraceCompartment = cx->compartment; + + JS_ASSERT(eos == stackBase + MAX_NATIVE_STACK_SLOTS); + JS_ASSERT(sp < eos); + + /* + * inlineCallCount has already been incremented, if being invoked from + * EnterFrame. It is okay to have a 0-frame restriction since the JIT + * might not need any frames. + */ + JS_ASSERT(inlineCallCount <= JS_MAX_INLINE_CALL_COUNT); + +#ifdef DEBUG + /* + * Cannot 0xCD-fill global frame since it may overwrite a bailed outer + * ExecuteTree's 0xdeadbeefdeadbeef marker. + */ + memset(tm->storage->stack(), 0xCD, MAX_NATIVE_STACK_SLOTS * sizeof(double)); + memset(tm->storage->callstack(), 0xCD, MAX_CALL_STACK_ENTRIES * sizeof(FrameInfo*)); +#endif +} + +JS_ALWAYS_INLINE +TracerState::~TracerState() +{ + JS_ASSERT(!nativeVp); + + if (traceMonitor->tracecx) { + /* If we didn't already deep-bail... */ + JS_ASSERT(JS_THREAD_DATA(cx)->recordingCompartment == NULL || + JS_THREAD_DATA(cx)->recordingCompartment == cx->compartment); + JS_ASSERT(JS_THREAD_DATA(cx)->profilingCompartment == NULL); + JS_ASSERT(JS_THREAD_DATA(cx)->onTraceCompartment == cx->compartment); + JS_THREAD_DATA(cx)->onTraceCompartment = NULL; + } + + traceMonitor->tracerState = prev; + traceMonitor->tracecx = NULL; +} + +/* Call |f|, return the exit taken. */ +static JS_ALWAYS_INLINE VMSideExit* +ExecuteTrace(JSContext* cx, TraceMonitor* tm, Fragment* f, TracerState& state) +{ + JS_ASSERT(!tm->bailExit); +#ifdef JS_METHODJIT + JS_ASSERT(!TRACE_PROFILER(cx)); +#endif + union { NIns *code; GuardRecord* (FASTCALL *func)(TracerState*); } u; + u.code = f->code(); + GuardRecord* rec; +#if defined(JS_NO_FASTCALL) && defined(NANOJIT_IA32) + SIMULATE_FASTCALL(rec, state, NULL, u.func); +#else + rec = u.func(&state); +#endif + JS_ASSERT(!tm->bailExit); + return (VMSideExit*)rec->exit; +} + +/* Check whether our assumptions about the incoming scope-chain are upheld. */ +static JS_REQUIRES_STACK JS_ALWAYS_INLINE bool +ScopeChainCheck(JSContext* cx, TreeFragment* f) +{ + JS_ASSERT(f->globalObj == cx->fp()->scopeChain().getGlobal()); + + /* + * The JIT records and expects to execute with two scope-chain + * assumptions baked-in: + * + * 1. That the bottom of the scope chain is global, in the sense of + * JSCLASS_IS_GLOBAL. + * + * 2. That the scope chain between fp and the global is free of + * "unusual" native objects such as HTML forms or other funny + * things. + * + * #2 is checked here while following the scope-chain links, via + * js_IsCacheableNonGlobalScope, which consults a whitelist of known + * class types; once a global is found, it's checked for #1. Failing + * either check causes an early return from execution. + */ + JSObject* child = &cx->fp()->scopeChain(); + while (JSObject* parent = child->getParent()) { + if (!IsCacheableNonGlobalScope(child)) { + debug_only_print0(LC_TMTracer,"Blacklist: non-cacheable object on scope chain.\n"); + Blacklist((jsbytecode*) f->root->ip); + return false; + } + child = parent; + } + JS_ASSERT(child == f->globalObj); + + if (!f->globalObj->isGlobal()) { + debug_only_print0(LC_TMTracer, "Blacklist: non-global at root of scope chain.\n"); + Blacklist((jsbytecode*) f->root->ip); + return false; + } + + return true; +} + +enum LEAVE_TREE_STATUS { + NO_DEEP_BAIL = 0, + DEEP_BAILED = 1 +}; + +static LEAVE_TREE_STATUS +LeaveTree(TraceMonitor *tm, TracerState&, VMSideExit *lr); + +/* Return false if the interpreter should goto error. */ +static JS_REQUIRES_STACK bool +ExecuteTree(JSContext* cx, TraceMonitor* tm, TreeFragment* f, uintN& inlineCallCount, + VMSideExit** innermostNestedGuardp, VMSideExit **lrp) +{ +#ifdef MOZ_TRACEVIS + TraceVisStateObj tvso(cx, S_EXECUTE); +#endif + JS_ASSERT(f->root == f && f->code()); + + if (!ScopeChainCheck(cx, f) || !cx->stack().ensureEnoughSpaceToEnterTrace() || + inlineCallCount + f->maxCallDepth > JS_MAX_INLINE_CALL_COUNT) { + *lrp = NULL; + return true; + } + + /* Make sure the global object is sane. */ + JS_ASSERT(f->globalObj->numSlots() <= MAX_GLOBAL_SLOTS); + JS_ASSERT(f->nGlobalTypes() == f->globalSlots->length()); + JS_ASSERT_IF(f->globalSlots->length() != 0, + f->globalObj->shape() == f->globalShape); + + /* Initialize trace state. */ + TracerState state(cx, tm, f, inlineCallCount, innermostNestedGuardp); + double* stack = tm->storage->stack(); + double* global = tm->storage->global(); + JSObject* globalObj = f->globalObj; + unsigned ngslots = f->globalSlots->length(); + uint16* gslots = f->globalSlots->data(); + + BuildNativeFrame(cx, globalObj, 0 /* callDepth */, ngslots, gslots, + f->typeMap.data(), global, stack); + + AUDIT(traceTriggered); + debug_only_printf(LC_TMTracer, "entering trace at %s:%u@%u, execs: %u code: %p\n", + cx->fp()->script()->filename, + js_FramePCToLineNumber(cx, cx->fp()), + FramePCOffset(cx, cx->fp()), + f->execs, + f->code()); + + debug_only_stmt(uint32 globalSlots = globalObj->numSlots();) + debug_only_stmt(*(uint64*)&tm->storage->global()[globalSlots] = 0xdeadbeefdeadbeefLL;) + + /* Execute trace. */ + tm->iterationCounter = 0; + debug_only(int64 t0 = PRMJ_Now();) +#ifdef MOZ_TRACEVIS + VMSideExit* lr = (TraceVisStateObj(cx, S_NATIVE), ExecuteTrace(cx, tm, f, state)); +#else + VMSideExit* lr = ExecuteTrace(cx, tm, f, state); +#endif + debug_only(int64 t1 = PRMJ_Now();) + + JS_ASSERT_IF(lr->exitType == LOOP_EXIT, !lr->calldepth); + + /* Restore interpreter state. */ +#ifdef DEBUG + LEAVE_TREE_STATUS lts = +#endif + LeaveTree(tm, state, lr); +#ifdef DEBUG + JS_ASSERT_IF(lts == NO_DEEP_BAIL, + *(uint64*)&tm->storage->global()[globalSlots] == 0xdeadbeefdeadbeefLL); +#endif + + *lrp = state.innermost; + bool ok = !(state.builtinStatus & BUILTIN_ERROR); + JS_ASSERT_IF(cx->isExceptionPending(), !ok); + + size_t iters = tm->iterationCounter; + + f->execs++; + f->iters += iters; + +#ifdef DEBUG + JSStackFrame *fp = cx->fp(); + const char *prefix = ""; + if (iters == LOOP_COUNT_MAX) + prefix = ">"; + debug_only_printf(LC_TMMinimal, " [%.3f ms] Tree at line %u executed for %s%u iterations;" + " executed %u times; leave for %s at %s:%u (%s)\n", + double(t1-t0) / PRMJ_USEC_PER_MSEC, + f->treeLineNumber, prefix, (uintN)iters, f->execs, + getExitName(lr->exitType), + fp->script()->filename, + js_FramePCToLineNumber(cx, fp), + js_CodeName[fp->hasImacropc() ? *fp->imacropc() : *cx->regs->pc]); +#endif + +#ifdef JS_METHODJIT + if (cx->methodJitEnabled) { + if (lr->exitType == LOOP_EXIT && f->iters < MIN_LOOP_ITERS + && f->execs >= LOOP_CHECK_ITERS) + { + debug_only_printf(LC_TMMinimal, " Blacklisting at line %u (executed only %d iters)\n", + f->treeLineNumber, f->iters); + Blacklist((jsbytecode *)f->ip); + } + } +#endif + return ok; +} + +class Guardian { + bool *flagp; +public: + Guardian(bool *flagp) { + this->flagp = flagp; + JS_ASSERT(!*flagp); + *flagp = true; + } + + ~Guardian() { + JS_ASSERT(*flagp); + *flagp = false; + } +}; + +static JS_FORCES_STACK LEAVE_TREE_STATUS +LeaveTree(TraceMonitor *tm, TracerState& state, VMSideExit* lr) +{ + VOUCH_DOES_NOT_REQUIRE_STACK(); + + JSContext* cx = state.cx; + + /* Temporary waive the soft GC quota to make sure LeaveTree() doesn't fail. */ + Guardian waiver(&JS_THREAD_DATA(cx)->waiveGCQuota); + + FrameInfo** callstack = state.callstackBase; + double* stack = state.stackBase; + + /* + * Except if we find that this is a nested bailout, the guard the call + * returned is the one we have to use to adjust pc and sp. + */ + VMSideExit* innermost = lr; + + /* + * While executing a tree we do not update state.sp and state.rp even if + * they grow. Instead, guards tell us by how much sp and rp should be + * incremented in case of a side exit. When calling a nested tree, however, + * we actively adjust sp and rp. If we have such frames from outer trees on + * the stack, then rp will have been adjusted. Before we can process the + * stack of the frames of the tree we directly exited from, we have to + * first work our way through the outer frames and generate interpreter + * frames for them. Once the call stack (rp) is empty, we can process the + * final frames (which again are not directly visible and only the guard we + * exited on will tells us about). + */ + FrameInfo** rp = (FrameInfo**)state.rp; + if (lr->exitType == NESTED_EXIT) { + VMSideExit* nested = state.lastTreeCallGuard; + if (!nested) { + /* + * If lastTreeCallGuard is not set in state, we only have a single + * level of nesting in this exit, so lr itself is the innermost and + * outermost nested guard, and hence we set nested to lr. The + * calldepth of the innermost guard is not added to state.rp, so we + * do it here manually. For a nesting depth greater than 1 the + * call tree code already added the innermost guard's calldepth + * to state.rpAtLastTreeCall. + */ + nested = lr; + rp += lr->calldepth; + } else { + /* + * During unwinding state.rp gets overwritten at every step and we + * restore it here to its state at the innermost nested guard. The + * builtin already added the calldepth of that innermost guard to + * rpAtLastTreeCall. + */ + rp = (FrameInfo**)state.rpAtLastTreeCall; + } + innermost = state.lastTreeExitGuard; + if (state.innermostNestedGuardp) + *state.innermostNestedGuardp = nested; + JS_ASSERT(nested); + JS_ASSERT(nested->exitType == NESTED_EXIT); + JS_ASSERT(state.lastTreeExitGuard); + JS_ASSERT(state.lastTreeExitGuard->exitType != NESTED_EXIT); + } + + int32_t bs = state.builtinStatus; + bool bailed = innermost->exitType == STATUS_EXIT && (bs & BUILTIN_BAILED); + if (bailed) { + /* + * Deep-bail case. + * + * A _FAIL native already called LeaveTree once. At that time we + * reconstructed the interpreter stack, in pre-call state, with pc + * pointing to the op that triggered the call. Then we continued in + * native code. + */ + if (!(bs & BUILTIN_ERROR)) { + /* + * The builtin or native deep-bailed but finished successfully + * (no exception or error). + * + * After it returned, the JIT code stored the results of the + * builtin or native at the top of the native stack and then + * immediately flunked the guard on state->builtinStatus. + * + * Now LeaveTree has been called again from the tail of + * ExecuteTree. We are about to return to the interpreter. Adjust + * the top stack frame to resume on the next op. + */ + JSFrameRegs* regs = cx->regs; + JSOp op = (JSOp) *regs->pc; + + /* + * JSOP_SETELEM can be coalesced with a JSOP_POP in the interpeter. + * Since this doesn't re-enter the recorder, the post-state snapshot + * is invalid. Fix it up here. + */ + if (op == JSOP_SETELEM && JSOp(regs->pc[JSOP_SETELEM_LENGTH]) == JSOP_POP) { + regs->sp -= js_CodeSpec[JSOP_SETELEM].nuses; + regs->sp += js_CodeSpec[JSOP_SETELEM].ndefs; + regs->pc += JSOP_SETELEM_LENGTH; + op = JSOP_POP; + } + + const JSCodeSpec& cs = js_CodeSpec[op]; + regs->sp -= (cs.format & JOF_INVOKE) ? GET_ARGC(regs->pc) + 2 : cs.nuses; + regs->sp += cs.ndefs; + regs->pc += cs.length; + JS_ASSERT_IF(!cx->fp()->hasImacropc(), + cx->fp()->slots() + cx->fp()->numFixed() + + js_ReconstructStackDepth(cx, cx->fp()->script(), regs->pc) == + regs->sp); + + /* + * If there's a tree call around the point that we deep exited at, + * then state.sp and state.rp were restored to their original + * values before the tree call and sp might be less than deepBailSp, + * which we sampled when we were told to deep bail. + */ + JS_ASSERT(state.deepBailSp >= state.stackBase && state.sp <= state.deepBailSp); + + /* + * As explained above, the JIT code stored a result value or values + * on the native stack. Transfer them to the interpreter stack now. + * (Some opcodes, like JSOP_CALLELEM, produce two values, hence the + * loop.) + */ + JSValueType* typeMap = innermost->stackTypeMap(); + for (int i = 1; i <= cs.ndefs; i++) { + NativeToValue(cx, + regs->sp[-i], + typeMap[innermost->numStackSlots - i], + (jsdouble *) state.deepBailSp + + innermost->sp_adj / sizeof(jsdouble) - i); + } + } + return DEEP_BAILED; + } + + while (callstack < rp) { + FrameInfo* fi = *callstack; + /* Peek at the callee native slot in the not-yet-synthesized prev frame. */ + JSObject* callee = *(JSObject**)&stack[fi->callerHeight]; + + /* + * Flush the slots for cx->fp() (which will become cx->fp()->prev after + * SynthesizeFrame). Since a frame's arguments (including callee + * and thisv) are part of the frame, we only want to flush up to the + * next frame's arguments, so set cx->regs->sp to to not include said + * arguments. The upcoming call to SynthesizeFrame will reset regs->sp + * to its correct value. + */ + cx->regs->sp = cx->fp()->slots() + (fi->spdist - (2 + fi->get_argc())); + int slots = FlushNativeStackFrame(cx, 0 /* callDepth */, fi->get_typemap(), stack); + + /* Finish initializing cx->fp() and push a new cx->fp(). */ + SynthesizeFrame(cx, *fi, callee); +#ifdef DEBUG + JSStackFrame* fp = cx->fp(); + debug_only_printf(LC_TMTracer, + "synthesized deep frame for %s:%u@%u, slots=%d, fi=%p\n", + fp->script()->filename, + js_FramePCToLineNumber(cx, fp), + FramePCOffset(cx, fp), + slots, + (void*)*callstack); +#endif + /* + * Keep track of the additional frames we put on the interpreter stack + * and the native stack slots we consumed. + */ + ++*state.inlineCallCountp; + ++callstack; + stack += slots; + } + + /* + * We already synthesized the frames around the innermost guard. Here we + * just deal with additional frames inside the tree we are bailing out + * from. + */ + JS_ASSERT(rp == callstack); + unsigned calldepth = innermost->calldepth; + unsigned calleeOffset = 0; + for (unsigned n = 0; n < calldepth; ++n) { + /* Peek at the callee native slot in the not-yet-synthesized prev frame. */ + calleeOffset += callstack[n]->callerHeight; + JSObject* callee = *(JSObject**)&stack[calleeOffset]; + + /* Reconstruct the frame. */ + SynthesizeFrame(cx, *callstack[n], callee); + ++*state.inlineCallCountp; +#ifdef DEBUG + JSStackFrame* fp = cx->fp(); + debug_only_printf(LC_TMTracer, + "synthesized shallow frame for %s:%u@%u\n", + fp->script()->filename, js_FramePCToLineNumber(cx, fp), + FramePCOffset(cx, fp)); +#endif + } + + /* + * Adjust sp and pc relative to the tree we exited from (not the tree we + * entered into). These are our final values for sp and pc since + * SynthesizeFrame has already taken care of all frames in between. + */ + JSStackFrame* const fp = cx->fp(); + + /* + * If we are not exiting from an inlined frame, the state->sp is spbase. + * Otherwise spbase is whatever slots frames around us consume. + */ + cx->regs->pc = innermost->pc; + if (innermost->imacpc) + fp->setImacropc(innermost->imacpc); + else + fp->clearImacropc(); + + /* + * Set cx->regs->regs for the top frame. Since the top frame does not have a + * FrameInfo (a FrameInfo is only pushed for calls), we basically need to + * compute the offset from fp->slots() to the top of the stack based on the + * number of native slots allocated for this function. + * + * Duplicate native stack layout computation: see VisitFrameSlots header comment. + */ + uintN slotOffset = innermost->numStackSlots - innermost->numStackSlotsBelowCurrentFrame; + if (fp->isGlobalFrame()) { + /* Global nfixed slots are not kept on the native stack, so add them back. */ + slotOffset += fp->globalScript()->nfixed; + } else { + /* A frame's native slots includes args and frame ptrs, so strip them off. */ + slotOffset -= NumSlotsBeforeFixed(fp); + } + cx->regs->sp = fp->slots() + slotOffset; + + /* Assert that we computed sp correctly. */ + JS_ASSERT_IF(!fp->hasImacropc(), + fp->slots() + fp->numFixed() + + js_ReconstructStackDepth(cx, fp->script(), cx->regs->pc) == cx->regs->sp); + +#ifdef EXECUTE_TREE_TIMER + uint64 cycles = rdtsc() - state.startTime; +#elif defined(JS_JIT_SPEW) + uint64 cycles = 0; +#endif + debug_only_printf(LC_TMTracer, + "leaving trace at %s:%u@%u, op=%s, lr=%p, exitType=%s, sp=%lld, " + "calldepth=%d, cycles=%llu\n", + fp->script()->filename, + js_FramePCToLineNumber(cx, fp), + FramePCOffset(cx, fp), + js_CodeName[fp->hasImacropc() ? *fp->imacropc() : *cx->regs->pc], + (void*)lr, + getExitName(lr->exitType), + (long long int)(cx->regs->sp - fp->base()), + calldepth, + (unsigned long long int)cycles); + +#ifdef DEBUG + int slots = +#endif + FlushNativeStackFrame(cx, innermost->calldepth, innermost->stackTypeMap(), stack); + JS_ASSERT(unsigned(slots) == innermost->numStackSlots); + + /* + * If this trace is part of a tree, later branches might have added + * additional globals for which we don't have any type information + * available in the side exit. We merge in this information from the entry + * type-map. See also the comment in the constructor of TraceRecorder + * regarding why this is always safe to do. + */ + TreeFragment* outermostTree = state.outermostTree; + uint16* gslots = outermostTree->globalSlots->data(); + unsigned ngslots = outermostTree->globalSlots->length(); + JS_ASSERT(ngslots == outermostTree->nGlobalTypes()); + JSValueType* globalTypeMap; + + /* Are there enough globals? */ + TypeMap& typeMap = *tm->cachedTempTypeMap; + typeMap.clear(); + if (innermost->numGlobalSlots == ngslots) { + /* Yes. This is the ideal fast path. */ + globalTypeMap = innermost->globalTypeMap(); + } else { + /* + * No. Merge the typemap of the innermost entry and exit together. This + * should always work because it is invalid for nested trees or linked + * trees to have incompatible types. Thus, whenever a new global type + * is lazily added into a tree, all dependent and linked trees are + * immediately specialized (see bug 476653). + */ + JS_ASSERT(innermost->root()->nGlobalTypes() == ngslots); + JS_ASSERT(innermost->root()->nGlobalTypes() > innermost->numGlobalSlots); + typeMap.ensure(ngslots); +#ifdef DEBUG + unsigned check_ngslots = +#endif + BuildGlobalTypeMapFromInnerTree(typeMap, innermost); + JS_ASSERT(check_ngslots == ngslots); + globalTypeMap = typeMap.data(); + } + + /* Write back interned globals. */ + JS_ASSERT(state.eos == state.stackBase + MAX_NATIVE_STACK_SLOTS); + JSObject* globalObj = outermostTree->globalObj; + FlushNativeGlobalFrame(cx, globalObj, state.eos, ngslots, gslots, globalTypeMap); + +#ifdef JS_JIT_SPEW + if (innermost->exitType != TIMEOUT_EXIT) + AUDIT(sideExitIntoInterpreter); + else + AUDIT(timeoutIntoInterpreter); +#endif + + state.innermost = innermost; + return NO_DEEP_BAIL; +} + +static jsbytecode * +GetLoopBottom(JSContext *cx, jsbytecode *pc) +{ + JS_ASSERT(*pc == JSOP_TRACE || *pc == JSOP_NOTRACE); + JSScript *script = cx->fp()->script(); + jssrcnote *sn = js_GetSrcNote(script, pc); + if (!sn) + return NULL; + return pc + js_GetSrcNoteOffset(sn, 0); +} + +JS_ALWAYS_INLINE void +TraceRecorder::assertInsideLoop() +{ +#ifdef DEBUG + /* Asserts at callDepth == 0 will catch problems at the call op. */ + if (callDepth > 0) + return; + + jsbytecode *pc = cx->regs->fp->hasImacropc() ? cx->regs->fp->imacropc() : cx->regs->pc; + jsbytecode *beg = (jsbytecode *)tree->ip; + jsbytecode *end = GetLoopBottom(cx, beg); + + /* + * In some cases (continue in a while loop), we jump to the goto + * immediately preceeding a loop (the one that jumps to the loop + * condition). + */ + JS_ASSERT(pc >= beg - JSOP_GOTO_LENGTH && pc <= end); +#endif +} + +JS_REQUIRES_STACK MonitorResult +RecordLoopEdge(JSContext* cx, TraceMonitor* tm, uintN& inlineCallCount) +{ +#ifdef MOZ_TRACEVIS + TraceVisStateObj tvso(cx, S_MONITOR); +#endif + + /* Is the recorder currently active? */ + if (tm->recorder) { + tm->recorder->assertInsideLoop(); + jsbytecode* pc = cx->regs->pc; + if (pc == tm->recorder->tree->ip) { + AbortableRecordingStatus status = tm->recorder->closeLoop(); + if (status != ARECORD_COMPLETED) { + if (tm->recorder) + AbortRecording(cx, "closeLoop failed"); + return MONITOR_NOT_RECORDING; + } + } else { + MonitorResult r = TraceRecorder::recordLoopEdge(cx, tm->recorder, inlineCallCount); + JS_ASSERT((r == MONITOR_RECORDING) == (tm->recorder != NULL)); + if (r == MONITOR_RECORDING || r == MONITOR_ERROR) + return r; + + /* + * recordLoopEdge will invoke an inner tree if we have a matching + * one. If we arrive here, that tree didn't run to completion and + * instead we mis-matched or the inner tree took a side exit other than + * the loop exit. We are thus no longer guaranteed to be parked on the + * same loop header RecordLoopEdge was called for. In fact, this + * might not even be a loop header at all. Hence if the program counter + * no longer hovers over the inner loop header, return to the + * interpreter and do not attempt to trigger or record a new tree at + * this location. + */ + if (pc != cx->regs->pc) { +#ifdef MOZ_TRACEVIS + tvso.r = R_INNER_SIDE_EXIT; +#endif + return MONITOR_NOT_RECORDING; + } + } + } + JS_ASSERT(!tm->recorder); + + /* + * Make sure the shape of the global object still matches (this might flush + * the JIT cache). + */ + JSObject* globalObj = cx->fp()->scopeChain().getGlobal(); + uint32 globalShape = -1; + SlotList* globalSlots = NULL; + + if (!CheckGlobalObjectShape(cx, tm, globalObj, &globalShape, &globalSlots)) { + Backoff(tm, cx->regs->pc); + return MONITOR_NOT_RECORDING; + } + + /* Do not enter the JIT code with a pending operation callback. */ + if (JS_THREAD_DATA(cx)->interruptFlags) { +#ifdef MOZ_TRACEVIS + tvso.r = R_CALLBACK_PENDING; +#endif + return MONITOR_NOT_RECORDING; + } + + jsbytecode* pc = cx->regs->pc; + uint32 argc = entryFrameArgc(cx); + + TreeFragment* f = LookupOrAddLoop(tm, pc, globalObj, globalShape, argc); + + /* + * If we have no code in the anchor and no peers, we definitively won't be + * able to activate any trees, so start compiling. + */ + if (!f->code() && !f->peer) { + record: + if (++f->hits() < HOTLOOP) { +#ifdef MOZ_TRACEVIS + tvso.r = f->hits() < 1 ? R_BACKED_OFF : R_COLD; +#endif + return MONITOR_NOT_RECORDING; + } + + if (!ScopeChainCheck(cx, f)) { +#ifdef MOZ_TRACEVIS + tvso.r = R_FAIL_SCOPE_CHAIN_CHECK; +#endif + return MONITOR_NOT_RECORDING; + } + + /* + * We can give RecordTree the root peer. If that peer is already taken, + * it will walk the peer list and find us a free slot or allocate a new + * tree if needed. + */ + bool rv = RecordTree(cx, tm, f->first, NULL, NULL, 0, globalSlots); +#ifdef MOZ_TRACEVIS + if (!rv) + tvso.r = R_FAIL_RECORD_TREE; +#endif + return RecordingIfTrue(rv); + } + + debug_only_printf(LC_TMTracer, + "Looking for compat peer %d@%d, from %p (ip: %p)\n", + js_FramePCToLineNumber(cx, cx->fp()), + FramePCOffset(cx, cx->fp()), (void*)f, f->ip); + + uintN count; + TreeFragment* match = FindVMCompatiblePeer(cx, globalObj, f, count); + if (!match) { + if (count < MAXPEERS) + goto record; + + /* + * If we hit the max peers ceiling, don't try to lookup fragments all + * the time. That's expensive. This must be a rather type-unstable loop. + */ + debug_only_print0(LC_TMTracer, "Blacklisted: too many peer trees.\n"); + Blacklist((jsbytecode*) f->root->ip); +#ifdef MOZ_TRACEVIS + tvso.r = R_MAX_PEERS; +#endif + return MONITOR_NOT_RECORDING; + } + + VMSideExit* lr = NULL; + VMSideExit* innermostNestedGuard = NULL; + + if (!ExecuteTree(cx, tm, match, inlineCallCount, &innermostNestedGuard, &lr)) + return MONITOR_ERROR; + + if (!lr) { +#ifdef MOZ_TRACEVIS + tvso.r = R_FAIL_EXECUTE_TREE; +#endif + return MONITOR_NOT_RECORDING; + } + + /* + * If we exit on a branch, or on a tree call guard, try to grow the inner + * tree (in case of a branch exit), or the tree nested around the tree we + * exited from (in case of the tree call guard). + */ + bool rv; + switch (lr->exitType) { + case UNSTABLE_LOOP_EXIT: + rv = AttemptToStabilizeTree(cx, tm, globalObj, lr, NULL, NULL, 0); +#ifdef MOZ_TRACEVIS + if (!rv) + tvso.r = R_FAIL_STABILIZE; +#endif + return RecordingIfTrue(rv); + + case MUL_ZERO_EXIT: + case OVERFLOW_EXIT: + if (lr->exitType == MUL_ZERO_EXIT) + tm->oracle->markInstructionSlowZeroTest(cx->regs->pc); + else + tm->oracle->markInstructionUndemotable(cx->regs->pc); + /* FALL THROUGH */ + case BRANCH_EXIT: + case CASE_EXIT: + rv = AttemptToExtendTree(cx, tm, lr, NULL, NULL, NULL +#ifdef MOZ_TRACEVIS + , &tvso +#endif + ); + return RecordingIfTrue(rv); + + case LOOP_EXIT: + if (innermostNestedGuard) { + rv = AttemptToExtendTree(cx, tm, innermostNestedGuard, lr, NULL, NULL +#ifdef MOZ_TRACEVIS + , &tvso +#endif + ); + return RecordingIfTrue(rv); + } +#ifdef MOZ_TRACEVIS + tvso.r = R_NO_EXTEND_OUTER; +#endif + return MONITOR_NOT_RECORDING; + +#ifdef MOZ_TRACEVIS + case MISMATCH_EXIT: + tvso.r = R_MISMATCH_EXIT; + return MONITOR_NOT_RECORDING; + case OOM_EXIT: + tvso.r = R_OOM_EXIT; + return MONITOR_NOT_RECORDING; + case TIMEOUT_EXIT: + tvso.r = R_TIMEOUT_EXIT; + return MONITOR_NOT_RECORDING; + case DEEP_BAIL_EXIT: + tvso.r = R_DEEP_BAIL_EXIT; + return MONITOR_NOT_RECORDING; + case STATUS_EXIT: + tvso.r = R_STATUS_EXIT; + return MONITOR_NOT_RECORDING; +#endif + + default: + /* + * No, this was an unusual exit (i.e. out of memory/GC), so just resume + * interpretation. + */ +#ifdef MOZ_TRACEVIS + tvso.r = R_OTHER_EXIT; +#endif + return MONITOR_NOT_RECORDING; + } +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::monitorRecording(JSOp op) +{ + JS_ASSERT(!addPropShapeBefore); + + JS_ASSERT(traceMonitor == &cx->compartment->traceMonitor); + + TraceMonitor &localtm = *traceMonitor; + debug_only_stmt( JSContext *localcx = cx; ) + assertInsideLoop(); + JS_ASSERT(!localtm.profile); + + /* Process needFlush requests now. */ + if (localtm.needFlush) { + ResetJIT(cx, &localtm, FR_DEEP_BAIL); + return ARECORD_ABORTED; + } + JS_ASSERT(!fragment->lastIns); + + /* + * Clear one-shot state used to communicate between record_JSOP_CALL and post- + * opcode-case-guts record hook (record_NativeCallComplete). + */ + pendingSpecializedNative = NULL; + newobj_ins = NULL; + pendingGlobalSlotsToSet.clear(); + + /* Handle one-shot request from finishGetProp or INSTANCEOF to snapshot post-op state and guard. */ + if (pendingGuardCondition) { + LIns* cond = pendingGuardCondition; + bool expected = true; + + /* Put 'cond' in a form suitable for a guard/branch condition if it's not already. */ + ensureCond(&cond, &expected); + guard(expected, cond, STATUS_EXIT); + pendingGuardCondition = NULL; + } + + /* Handle one-shot request to unbox the result of a property get or ObjectToIterator. */ + if (pendingUnboxSlot) { + LIns* val_ins = get(pendingUnboxSlot); + /* + * We need to know from where to unbox the value. Since pendingUnboxSlot + * is only set in finishGetProp, we can depend on LIns* tracked for + * pendingUnboxSlot to have this information. + */ + LIns* unboxed_ins = unbox_value(*pendingUnboxSlot, + AnyAddress(val_ins->oprnd1(), val_ins->disp()), + snapshot(BRANCH_EXIT)); + set(pendingUnboxSlot, unboxed_ins); + pendingUnboxSlot = 0; + } + + debug_only_stmt( + if (LogController.lcbits & LC_TMRecorder) { + debug_only_print0(LC_TMRecorder, "\n"); + js_Disassemble1(cx, cx->fp()->script(), cx->regs->pc, + cx->fp()->hasImacropc() + ? 0 : cx->regs->pc - cx->fp()->script()->code, + !cx->fp()->hasImacropc(), stdout); + } + ) + + /* + * If op is not a break or a return from a loop, continue recording and + * follow the trace. We check for imacro-calling bytecodes inside each + * switch case to resolve the if (JSOP_IS_IMACOP(x)) conditions at compile + * time. + */ + + AbortableRecordingStatus status; +#ifdef DEBUG + bool wasInImacro = (cx->fp()->hasImacropc()); +#endif + switch (op) { + default: + AbortRecording(cx, "unsupported opcode"); + status = ARECORD_ERROR; + break; +# define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + case op: \ + w.comment(#op); \ + status = this->record_##op(); \ + break; +# include "jsopcode.tbl" +# undef OPDEF + } + + /* N.B. |this| may have been deleted. */ + + if (!JSOP_IS_IMACOP(op)) { + JS_ASSERT(status != ARECORD_IMACRO); + JS_ASSERT_IF(!wasInImacro, !localcx->fp()->hasImacropc()); + } + + if (localtm.recorder) { + JS_ASSERT(status != ARECORD_ABORTED); + JS_ASSERT(localtm.recorder == this); + + /* |this| recorder completed, but a new one started; keep recording. */ + if (status == ARECORD_COMPLETED) + return ARECORD_CONTINUE; + + /* Handle lazy aborts; propagate the 'error' status. */ + if (StatusAbortsRecorderIfActive(status)) { + AbortRecording(cx, js_CodeName[op]); + return status == ARECORD_ERROR ? ARECORD_ERROR : ARECORD_ABORTED; + } + + if (outOfMemory() || OverfullJITCache(cx, &localtm)) { + ResetJIT(cx, &localtm, FR_OOM); + + /* + * If the status returned was ARECORD_IMACRO, then we just + * changed cx->regs, we need to tell the interpreter to sync + * its local variables. + */ + return status == ARECORD_IMACRO ? ARECORD_IMACRO_ABORTED : ARECORD_ABORTED; + } + } else { + JS_ASSERT(status == ARECORD_COMPLETED || + status == ARECORD_ABORTED || + status == ARECORD_ERROR); + } + return status; +} + +JS_REQUIRES_STACK TraceRecorder::AbortResult +AbortRecording(JSContext* cx, const char* reason) +{ +#ifdef DEBUG + JS_ASSERT(TRACE_RECORDER(cx)); + return TRACE_RECORDER(cx)->finishAbort(reason); +#else + return TRACE_RECORDER(cx)->finishAbort("[no reason]"); +#endif +} + +#if defined NANOJIT_IA32 +static bool +CheckForSSE2() +{ + char *c = getenv("X86_FORCE_SSE2"); + if (c) + return (!strcmp(c, "true") || + !strcmp(c, "1") || + !strcmp(c, "yes")); + + int features = 0; +#if defined _MSC_VER + __asm + { + pushad + mov eax, 1 + cpuid + mov features, edx + popad + } +#elif defined __GNUC__ + asm("xchg %%esi, %%ebx\n" /* we can't clobber ebx on gcc (PIC register) */ + "mov $0x01, %%eax\n" + "cpuid\n" + "mov %%edx, %0\n" + "xchg %%esi, %%ebx\n" + : "=m" (features) + : /* We have no inputs */ + : "%eax", "%esi", "%ecx", "%edx" + ); +#elif defined __SUNPRO_C || defined __SUNPRO_CC + asm("push %%ebx\n" + "mov $0x01, %%eax\n" + "cpuid\n" + "pop %%ebx\n" + : "=d" (features) + : /* We have no inputs */ + : "%eax", "%ecx" + ); +#endif + return (features & (1<<26)) != 0; +} +#endif + +#if defined(NANOJIT_ARM) + +#if defined(_MSC_VER) && defined(WINCE) + +// these come in from jswince.asm +extern "C" int js_arm_try_armv5_op(); +extern "C" int js_arm_try_armv6_op(); +extern "C" int js_arm_try_armv7_op(); +extern "C" int js_arm_try_vfp_op(); + +static unsigned int +arm_check_arch() +{ + unsigned int arch = 4; + __try { + js_arm_try_armv5_op(); + arch = 5; + js_arm_try_armv6_op(); + arch = 6; + js_arm_try_armv7_op(); + arch = 7; + } __except(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) { + } + return arch; +} + +static bool +arm_check_vfp() +{ +#ifdef WINCE_WINDOWS_MOBILE + return false; +#else + bool ret = false; + __try { + js_arm_try_vfp_op(); + ret = true; + } __except(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) { + ret = false; + } + return ret; +#endif +} + +#define HAVE_ENABLE_DISABLE_DEBUGGER_EXCEPTIONS 1 + +/* See "Suppressing Exception Notifications while Debugging", at + * http://msdn.microsoft.com/en-us/library/ms924252.aspx + */ +static void +disable_debugger_exceptions() +{ + // 2 == TLSSLOT_KERNEL + DWORD kctrl = (DWORD) TlsGetValue(2); + // 0x12 = TLSKERN_NOFAULT | TLSKERN_NOFAULTMSG + kctrl |= 0x12; + TlsSetValue(2, (LPVOID) kctrl); +} + +static void +enable_debugger_exceptions() +{ + // 2 == TLSSLOT_KERNEL + DWORD kctrl = (DWORD) TlsGetValue(2); + // 0x12 = TLSKERN_NOFAULT | TLSKERN_NOFAULTMSG + kctrl &= ~0x12; + TlsSetValue(2, (LPVOID) kctrl); +} + +#elif defined(__GNUC__) && defined(AVMPLUS_LINUX) + +// Assume ARMv4 by default. +static unsigned int arm_arch = 4; +static bool arm_has_vfp = false; +static bool arm_has_neon = false; +static bool arm_has_iwmmxt = false; +static bool arm_tests_initialized = false; + +#ifdef ANDROID +// we're actually reading /proc/cpuinfo, but oh well +static void +arm_read_auxv() +{ + char buf[1024]; + char* pos; + const char* ver_token = "CPU architecture: "; + FILE* f = fopen("/proc/cpuinfo", "r"); + fread(buf, sizeof(char), 1024, f); + fclose(f); + pos = strstr(buf, ver_token); + if (pos) { + int ver = *(pos + strlen(ver_token)) - '0'; + arm_arch = ver; + } + arm_has_neon = strstr(buf, "neon") != NULL; + arm_has_vfp = strstr(buf, "vfp") != NULL; + arm_has_iwmmxt = strstr(buf, "iwmmxt") != NULL; + arm_tests_initialized = true; +} + +#else + +static void +arm_read_auxv() +{ + int fd; + Elf32_auxv_t aux; + + fd = open("/proc/self/auxv", O_RDONLY); + if (fd > 0) { + while (read(fd, &aux, sizeof(Elf32_auxv_t))) { + if (aux.a_type == AT_HWCAP) { + uint32_t hwcap = aux.a_un.a_val; + if (getenv("ARM_FORCE_HWCAP")) + hwcap = strtoul(getenv("ARM_FORCE_HWCAP"), NULL, 0); + else if (getenv("_SBOX_DIR")) + continue; // Ignore the rest, if we're running in scratchbox + // hardcode these values to avoid depending on specific versions + // of the hwcap header, e.g. HWCAP_NEON + arm_has_vfp = (hwcap & 64) != 0; + arm_has_iwmmxt = (hwcap & 512) != 0; + // this flag is only present on kernel 2.6.29 + arm_has_neon = (hwcap & 4096) != 0; + } else if (aux.a_type == AT_PLATFORM) { + const char *plat = (const char*) aux.a_un.a_val; + if (getenv("ARM_FORCE_PLATFORM")) + plat = getenv("ARM_FORCE_PLATFORM"); + else if (getenv("_SBOX_DIR")) + continue; // Ignore the rest, if we're running in scratchbox + // The platform string has the form "v[0-9][lb]". The "l" or "b" indicate little- + // or big-endian variants and the digit indicates the version of the platform. + // We can only accept ARMv4 and above, but allow anything up to ARMv9 for future + // processors. Architectures newer than ARMv7 are assumed to be + // backwards-compatible with ARMv7. + if ((plat[0] == 'v') && + (plat[1] >= '4') && (plat[1] <= '9') && + ((plat[2] == 'l') || (plat[2] == 'b'))) + { + arm_arch = plat[1] - '0'; + } + } + } + close (fd); + + // if we don't have 2.6.29, we have to do this hack; set + // the env var to trust HWCAP. + if (!getenv("ARM_TRUST_HWCAP") && (arm_arch >= 7)) + arm_has_neon = true; + } + + arm_tests_initialized = true; +} + +#endif + +static unsigned int +arm_check_arch() +{ + if (!arm_tests_initialized) + arm_read_auxv(); + + return arm_arch; +} + +static bool +arm_check_vfp() +{ + if (!arm_tests_initialized) + arm_read_auxv(); + + return arm_has_vfp; +} + +#else +#warning Not sure how to check for architecture variant on your platform. Assuming ARMv4. +static unsigned int +arm_check_arch() { return 4; } +static bool +arm_check_vfp() { return false; } +#endif + +#ifndef HAVE_ENABLE_DISABLE_DEBUGGER_EXCEPTIONS +static void +enable_debugger_exceptions() { } +static void +disable_debugger_exceptions() { } +#endif + +#endif /* NANOJIT_ARM */ + +#define K *1024 +#define M K K +#define G K M + +void +SetMaxCodeCacheBytes(JSContext* cx, uint32 bytes) +{ + if (bytes > 1 G) + bytes = 1 G; + if (bytes < 128 K) + bytes = 128 K; + JS_THREAD_DATA(cx)->maxCodeCacheBytes = bytes; +} + +bool +InitJIT(TraceMonitor *tm) +{ +#if defined JS_JIT_SPEW + tm->profAlloc = NULL; + /* Set up debug logging. */ + if (!did_we_set_up_debug_logging) { + InitJITLogController(); + did_we_set_up_debug_logging = true; + } + /* Set up fragprofiling, if required. */ + if (LogController.lcbits & LC_FragProfile) { + tm->profAlloc = js_new((char*)NULL, 0); /* no reserve needed in debug builds */ + if (!tm->profAlloc) + goto error; + tm->profTab = new (*tm->profAlloc) FragStatsMap(*tm->profAlloc); + } + tm->lastFragID = 0; +#else + PodZero(&LogController); +#endif + + if (!did_we_check_processor_features) { +#if defined NANOJIT_IA32 + avmplus::AvmCore::config.i386_use_cmov = + avmplus::AvmCore::config.i386_sse2 = CheckForSSE2(); + avmplus::AvmCore::config.i386_fixed_esp = true; +#endif +#if defined NANOJIT_ARM + + disable_debugger_exceptions(); + + bool arm_vfp = arm_check_vfp(); + unsigned int arm_arch = arm_check_arch(); + + enable_debugger_exceptions(); + + avmplus::AvmCore::config.arm_vfp = arm_vfp; + avmplus::AvmCore::config.soft_float = !arm_vfp; + avmplus::AvmCore::config.arm_arch = arm_arch; + + // Sanity-check the configuration detection. + // * We don't understand architectures prior to ARMv4. + JS_ASSERT(arm_arch >= 4); +#endif + did_we_check_processor_features = true; + } + + #define CHECK_ALLOC(lhs, rhs) \ + do { lhs = (rhs); if (!lhs) goto error; } while (0) + + CHECK_ALLOC(tm->oracle, js_new()); + + tm->profile = NULL; + + CHECK_ALLOC(tm->recordAttempts, js_new()); + if (!tm->recordAttempts->init(PC_HASH_COUNT)) + goto error; + + CHECK_ALLOC(tm->loopProfiles, js_new()); + if (!tm->loopProfiles->init(PC_HASH_COUNT)) + goto error; + + tm->flushEpoch = 0; + + char *dataReserve, *traceReserve, *tempReserve; + CHECK_ALLOC(dataReserve, (char *)js_malloc(DataReserveSize)); + CHECK_ALLOC(traceReserve, (char *)js_malloc(TraceReserveSize)); + CHECK_ALLOC(tempReserve, (char *)js_malloc(TempReserveSize)); + CHECK_ALLOC(tm->dataAlloc, js_new(dataReserve, DataReserveSize)); + CHECK_ALLOC(tm->traceAlloc, js_new(traceReserve, TraceReserveSize)); + CHECK_ALLOC(tm->tempAlloc, js_new(tempReserve, TempReserveSize)); + CHECK_ALLOC(tm->codeAlloc, js_new()); + CHECK_ALLOC(tm->frameCache, js_new(tm->dataAlloc)); + CHECK_ALLOC(tm->storage, js_new()); + CHECK_ALLOC(tm->cachedTempTypeMap, js_new((Allocator*)NULL, tm->oracle)); + tm->flush(); + verbose_only( tm->branches = NULL; ) + +#if !defined XP_WIN + debug_only(PodZero(&jitstats)); +#endif + +#ifdef JS_JIT_SPEW + /* Architecture properties used by test cases. */ + jitstats.archIsIA32 = 0; + jitstats.archIs64BIT = 0; + jitstats.archIsARM = 0; + jitstats.archIsSPARC = 0; + jitstats.archIsPPC = 0; +#if defined NANOJIT_IA32 + jitstats.archIsIA32 = 1; +#endif +#if defined NANOJIT_64BIT + jitstats.archIs64BIT = 1; +#endif +#if defined NANOJIT_ARM + jitstats.archIsARM = 1; +#endif +#if defined NANOJIT_SPARC + jitstats.archIsSPARC = 1; +#endif +#if defined NANOJIT_PPC + jitstats.archIsPPC = 1; +#endif +#if defined NANOJIT_X64 + jitstats.archIsAMD64 = 1; +#endif +#endif + + if (!tm->tracedScripts.init()) + goto error; + return true; + +error: + /* On error, don't rely on the compartment destructor being called. */ + FinishJIT(tm); + return false; +} + +/* + * NB: FinishJIT needs to work even when InitJIT fails. Each pointer must be + * checked before it's dereferenced, as it may not have been allocated. + */ +void +FinishJIT(TraceMonitor *tm) +{ + JS_ASSERT(!tm->recorder); + JS_ASSERT(!tm->profile); + +#ifdef JS_JIT_SPEW + if (jitstats.recorderStarted) { + char sep = ':'; + debug_only_print0(LC_TMStats, "recorder"); +#define RECORDER_JITSTAT(_ident, _name) \ + debug_only_printf(LC_TMStats, "%c " _name "(%llu)", sep, \ + (unsigned long long int)jitstats._ident); \ + sep = ','; +#define JITSTAT(x) /* nothing */ +#include "jitstats.tbl" +#undef JITSTAT +#undef RECORDER_JITSTAT + debug_only_print0(LC_TMStats, "\n"); + + sep = ':'; + debug_only_print0(LC_TMStats, "monitor"); +#define MONITOR_JITSTAT(_ident, _name) \ + debug_only_printf(LC_TMStats, "%c " _name "(%llu)", sep, \ + (unsigned long long int)jitstats._ident); \ + sep = ','; +#define JITSTAT(x) /* nothing */ +#include "jitstats.tbl" +#undef JITSTAT +#undef MONITOR_JITSTAT + debug_only_print0(LC_TMStats, "\n"); + } +#endif + + js_delete(tm->recordAttempts); + js_delete(tm->loopProfiles); + js_delete(tm->oracle); + +#ifdef DEBUG + // Recover profiling data from expiring Fragments, and display + // final results. + if (LogController.lcbits & LC_FragProfile) { + + for (Seq* f = tm->branches; f; f = f->tail) + FragProfiling_FragFinalizer(f->head, tm); + + for (size_t i = 0; i < FRAGMENT_TABLE_SIZE; ++i) { + for (TreeFragment *f = tm->vmfragments[i]; f; f = f->next) { + JS_ASSERT(f->root == f); + for (TreeFragment *p = f; p; p = p->peer) + FragProfiling_FragFinalizer(p, tm); + } + } + + if (tm->profTab) + FragProfiling_showResults(tm); + js_delete(tm->profAlloc); + + } else { + NanoAssert(!tm->profTab); + NanoAssert(!tm->profAlloc); + } +#endif + + PodArrayZero(tm->vmfragments); + + js_delete(tm->frameCache); + tm->frameCache = NULL; + + js_delete(tm->codeAlloc); + tm->codeAlloc = NULL; + + js_delete(tm->dataAlloc); + tm->dataAlloc = NULL; + + js_delete(tm->traceAlloc); + tm->traceAlloc = NULL; + + js_delete(tm->tempAlloc); + tm->tempAlloc = NULL; + + js_delete(tm->storage); + tm->storage = NULL; + + js_delete(tm->cachedTempTypeMap); + tm->cachedTempTypeMap = NULL; +} + +JS_REQUIRES_STACK void +PurgeScriptFragments(TraceMonitor* tm, JSScript* script) +{ + debug_only_printf(LC_TMTracer, + "Purging fragments for JSScript %p.\n", (void*)script); + + /* A recorder script is being evaluated and can not be destroyed or GC-ed. */ + JS_ASSERT_IF(tm->recorder, + JS_UPTRDIFF(tm->recorder->getTree()->ip, script->code) >= script->length); + + for (LoopProfileMap::Enum e(*tm->loopProfiles); !e.empty(); e.popFront()) { + if (JS_UPTRDIFF(e.front().key, script->code) < script->length) + e.removeFront(); + } + + TracedScriptSet::Ptr found = tm->tracedScripts.lookup(script); + if (!found) + return; + tm->tracedScripts.remove(found); + + for (size_t i = 0; i < FRAGMENT_TABLE_SIZE; ++i) { + TreeFragment** fragp = &tm->vmfragments[i]; + while (TreeFragment* frag = *fragp) { + if (JS_UPTRDIFF(frag->ip, script->code) < script->length) { + /* This fragment is associated with the script. */ + debug_only_printf(LC_TMTracer, + "Disconnecting TreeFragment %p " + "with ip %p, in range [%p,%p).\n", + (void*)frag, frag->ip, script->code, + script->code + script->length); + + JS_ASSERT(frag->root == frag); + *fragp = frag->next; + do { + verbose_only( FragProfiling_FragFinalizer(frag, tm); ) + TrashTree(frag); + } while ((frag = frag->peer) != NULL); + continue; + } + fragp = &frag->next; + } + } + + RecordAttemptMap &table = *tm->recordAttempts; + for (RecordAttemptMap::Enum e(table); !e.empty(); e.popFront()) { + if (JS_UPTRDIFF(e.front().key, script->code) < script->length) + e.removeFront(); + } +} + +bool +OverfullJITCache(JSContext *cx, TraceMonitor* tm) +{ + /* + * You might imagine the outOfMemory flag on the allocator is sufficient + * to model the notion of "running out of memory", but there are actually + * two separate issues involved: + * + * 1. The process truly running out of memory: malloc() or mmap() + * failed. + * + * 2. The limit we put on the "intended size" of the tracemonkey code + * cache, in pages, has been exceeded. + * + * Condition 1 doesn't happen very often, but we're obliged to try to + * safely shut down and signal the rest of spidermonkey when it + * does. Condition 2 happens quite regularly. + * + * Presently, the code in this file doesn't check the outOfMemory condition + * often enough, and frequently misuses the unchecked results of + * lirbuffer insertions on the assumption that it will notice the + * outOfMemory flag "soon enough" when it returns to the monitorRecording + * function. This turns out to be a false assumption if we use outOfMemory + * to signal condition 2: we regularly provoke "passing our intended + * size" and regularly fail to notice it in time to prevent writing + * over the end of an artificially self-limited LIR buffer. + * + * To mitigate, though not completely solve, this problem, we're + * modeling the two forms of memory exhaustion *separately* for the + * time being: condition 1 is handled by the outOfMemory flag inside + * nanojit, and condition 2 is being handled independently *here*. So + * we construct our allocators to use all available memory they like, + * and only report outOfMemory to us when there is literally no OS memory + * left. Merely purging our cache when we hit our highwater mark is + * handled by the (few) callers of this function. + * + */ + jsuint maxsz = JS_THREAD_DATA(cx)->maxCodeCacheBytes; + return (tm->codeAlloc->size() + tm->dataAlloc->size() + tm->traceAlloc->size() > maxsz); +} + +JS_FORCES_STACK JS_FRIEND_API(void) +DeepBail(JSContext *cx) +{ + JS_ASSERT(JS_ON_TRACE(cx)); + + /* + * Exactly one context on the current thread is on trace. Find out which + * one. (Most callers cannot guarantee that it's cx.) + */ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + JS_ASSERT(JS_THREAD_DATA(cx)->profilingCompartment == NULL); + JS_THREAD_DATA(cx)->onTraceCompartment = NULL; + + /* It's a bug if a non-FAIL_STATUS builtin gets here. */ + JS_ASSERT(tm->bailExit); + + tm->tracecx = NULL; + debug_only_print0(LC_TMTracer, "Deep bail.\n"); + LeaveTree(tm, *tm->tracerState, tm->bailExit); + tm->bailExit = NULL; + + TracerState* state = tm->tracerState; + state->builtinStatus |= BUILTIN_BAILED; + + /* + * Between now and the LeaveTree in ExecuteTree, |tm->storage| may be + * reused if another trace executes before the currently executing native + * returns. If this happens, at least some of the native stack will be + * clobbered, potentially all of it. This is called a clobbering deep bail. + * + * The nested trace will complete before we return to the deep-bailed one, + * hence the invariant is maintained that only one trace uses |tm->storage| + * at a time. + * + * When we return to the deep-bailed trace, it will very soon reach a + * STATUS_EXIT guard and bail out. Most of the native stack will just be + * thrown away. However, LeaveTree will copy a few slots from the top of + * the native stack to the interpreter stack--only those slots written by + * the current bytecode instruction. To make sure LeaveTree has correct + * data to copy from the native stack to the operand stack, we have this + * rule: every caller of enterDeepBailCall must ensure that between the + * deep bail call and the STATUS_EXIT guard, all those slots are written. + * + * The rule is a bit subtle. For example, JSOP_MOREITER uses a slot which + * it never writes to; in order to satisfy the above rule, + * record_JSOP_MOREITER emits code to write the value back to the slot + * anyway. + */ + state->deepBailSp = state->sp; +} + +JS_REQUIRES_STACK Value& +TraceRecorder::argval(unsigned n) const +{ + JS_ASSERT(n < cx->fp()->numFormalArgs()); + return cx->fp()->formalArg(n); +} + +JS_REQUIRES_STACK Value& +TraceRecorder::varval(unsigned n) const +{ + JS_ASSERT(n < cx->fp()->numSlots()); + return cx->fp()->slots()[n]; +} + +JS_REQUIRES_STACK Value& +TraceRecorder::stackval(int n) const +{ + return cx->regs->sp[n]; +} + +JS_REQUIRES_STACK void +TraceRecorder::updateAtoms() +{ + JSScript *script = cx->fp()->script(); + atoms = FrameAtomBase(cx, cx->fp()); + consts = (cx->fp()->hasImacropc() || !JSScript::isValidOffset(script->constOffset)) + ? 0 + : script->consts()->vector; + strictModeCode_ins = w.name(w.immi(script->strictModeCode), "strict"); +} + +JS_REQUIRES_STACK void +TraceRecorder::updateAtoms(JSScript *script) +{ + atoms = script->atomMap.vector; + consts = JSScript::isValidOffset(script->constOffset) ? script->consts()->vector : 0; + strictModeCode_ins = w.name(w.immi(script->strictModeCode), "strict"); +} + +/* + * Generate LIR to compute the scope chain. + */ +JS_REQUIRES_STACK LIns* +TraceRecorder::scopeChain() +{ + return cx->fp()->isFunctionFrame() + ? getFrameObjPtr(cx->fp()->addressOfScopeChain()) + : entryScopeChain(); +} + +/* + * Generate LIR to compute the scope chain on entry to the trace. This is + * generally useful only for getting to the global object, because only + * the global object is guaranteed to be present. + */ +JS_REQUIRES_STACK LIns* +TraceRecorder::entryScopeChain() const +{ + return w.ldpStackFrameScopeChain(entryFrameIns()); +} + +/* + * Generate LIR to compute the stack frame on entry to the trace. + */ +JS_REQUIRES_STACK LIns* +TraceRecorder::entryFrameIns() const +{ + return w.ldpFrameFp(w.ldpContextField(regs)); +} + +/* + * Return the frame of a call object if that frame is part of the current + * trace. |depthp| is an optional outparam: if it is non-null, it will be + * filled in with the depth of the call object's frame relevant to cx->fp(). + */ +JS_REQUIRES_STACK JSStackFrame* +TraceRecorder::frameIfInRange(JSObject* obj, unsigned* depthp) const +{ + JSStackFrame* ofp = (JSStackFrame*) obj->getPrivate(); + JSStackFrame* fp = cx->fp(); + for (unsigned depth = 0; depth <= callDepth; ++depth) { + if (fp == ofp) { + if (depthp) + *depthp = depth; + return ofp; + } + if (!(fp = fp->prev())) + break; + } + return NULL; +} + +JS_DEFINE_CALLINFO_4(extern, UINT32, GetClosureVar, CONTEXT, OBJECT, CVIPTR, DOUBLEPTR, + 0, ACCSET_STORE_ANY) +JS_DEFINE_CALLINFO_4(extern, UINT32, GetClosureArg, CONTEXT, OBJECT, CVIPTR, DOUBLEPTR, + 0, ACCSET_STORE_ANY) + +/* + * Search the scope chain for a property lookup operation at the current PC and + * generate LIR to access the given property. Return RECORD_CONTINUE on success, + * otherwise abort and return RECORD_STOP. There are 3 outparams: + * + * vp the address of the current property value + * ins LIR instruction representing the property value on trace + * NameResult describes how to look up name; see comment for NameResult in jstracer.h + */ +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::scopeChainProp(JSObject* chainHead, Value*& vp, LIns*& ins, NameResult& nr, + JSObject** scopeObjp) +{ + JS_ASSERT(chainHead == &cx->fp()->scopeChain()); + JS_ASSERT(chainHead != globalObj); + + TraceMonitor &localtm = *traceMonitor; + + JSAtom* atom = atoms[GET_INDEX(cx->regs->pc)]; + JSObject* obj2; + JSProperty* prop; + JSObject *obj = chainHead; + if (!js_FindProperty(cx, ATOM_TO_JSID(atom), &obj, &obj2, &prop)) + RETURN_ERROR_A("error in js_FindProperty"); + + /* js_FindProperty can reenter the interpreter and kill |this|. */ + if (!localtm.recorder) + return ARECORD_ABORTED; + + if (!prop) + RETURN_STOP_A("failed to find name in non-global scope chain"); + + if (scopeObjp) + *scopeObjp = obj; + + if (obj == globalObj) { + // Even if the property is on the global object, we must guard against + // the creation of properties that shadow the property in the middle + // of the scope chain. + LIns *head_ins; + if (cx->fp()->isFunctionFrame()) { + // Skip any Call object when inside a function. Any reference to a + // Call name the compiler resolves statically and we do not need + // to match shapes of the Call objects. + chainHead = cx->fp()->callee().getParent(); + head_ins = w.ldpObjParent(get(&cx->fp()->calleeValue())); + } else { + head_ins = scopeChain(); + } + LIns *obj_ins; + CHECK_STATUS_A(traverseScopeChain(chainHead, head_ins, obj, obj_ins)); + + if (obj2 != obj) + RETURN_STOP_A("prototype property"); + + Shape* shape = (Shape*) prop; + if (!isValidSlot(obj, shape)) + return ARECORD_STOP; + if (!lazilyImportGlobalSlot(shape->slot)) + RETURN_STOP_A("lazy import of global slot failed"); + vp = &obj->getSlotRef(shape->slot); + ins = get(vp); + nr.tracked = true; + return ARECORD_CONTINUE; + } + + if (obj == obj2 && obj->isCall()) { + AbortableRecordingStatus status = + InjectStatus(callProp(obj, prop, ATOM_TO_JSID(atom), vp, ins, nr)); + return status; + } + + RETURN_STOP_A("fp->scopeChain is not global or active call object"); +} + +/* + * Generate LIR to access a property of a Call object. + */ +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, Value*& vp, + LIns*& ins, NameResult& nr) +{ + Shape *shape = (Shape*) prop; + + JSOp op = JSOp(*cx->regs->pc); + uint32 setflags = (js_CodeSpec[op].format & (JOF_SET | JOF_INCDEC | JOF_FOR)); + if (setflags && !shape->writable()) + RETURN_STOP("writing to a read-only property"); + + uintN slot = uint16(shape->shortid); + + vp = NULL; + JSStackFrame* cfp = (JSStackFrame*) obj->getPrivate(); + if (cfp) { + if (shape->getterOp() == GetCallArg) { + JS_ASSERT(slot < cfp->numFormalArgs()); + vp = &cfp->formalArg(slot); + nr.v = *vp; + } else if (shape->getterOp() == GetCallVar || + shape->getterOp() == GetCallVarChecked) { + JS_ASSERT(slot < cfp->numSlots()); + vp = &cfp->slots()[slot]; + nr.v = *vp; + } else { + RETURN_STOP("dynamic property of Call object"); + } + + // Now assert that our use of shape->shortid was in fact kosher. + JS_ASSERT(shape->hasShortID()); + + if (frameIfInRange(obj)) { + // At this point we are guaranteed to be looking at an active call oject + // whose properties are stored in the corresponding JSStackFrame. + ins = get(vp); + nr.tracked = true; + return RECORD_CONTINUE; + } + } else { + // Call objects do not yet have shape->isMethod() properties, but they + // should. See bug 514046, for which this code is future-proof. Remove + // this comment when that bug is fixed (so, FIXME: 514046). +#ifdef DEBUG + JSBool rv = +#endif + js_GetPropertyHelper(cx, obj, shape->id, + (op == JSOP_CALLNAME) + ? JSGET_NO_METHOD_BARRIER + : JSGET_METHOD_BARRIER, + &nr.v); + JS_ASSERT(rv); + } + + LIns* obj_ins; + JSObject* parent = cx->fp()->callee().getParent(); + LIns* parent_ins = w.ldpObjParent(get(&cx->fp()->calleeValue())); + CHECK_STATUS(traverseScopeChain(parent, parent_ins, obj, obj_ins)); + + if (!cfp) { + // Because the parent guard in guardCallee ensures this Call object + // will be the same object now and on trace, and because once a Call + // object loses its frame it never regains one, on trace we will also + // have a null private in the Call object. So all we need to do is + // write the value to the Call object's slot. + if (shape->getterOp() == GetCallArg) { + JS_ASSERT(slot < ArgClosureTraits::slot_count(obj)); + slot += ArgClosureTraits::slot_offset(obj); + } else if (shape->getterOp() == GetCallVar || + shape->getterOp() == GetCallVarChecked) { + JS_ASSERT(slot < VarClosureTraits::slot_count(obj)); + slot += VarClosureTraits::slot_offset(obj); + } else { + RETURN_STOP("dynamic property of Call object"); + } + + // Now assert that our use of shape->shortid was in fact kosher. + JS_ASSERT(shape->hasShortID()); + + ins = unbox_slot(obj, obj_ins, slot, snapshot(BRANCH_EXIT)); + } else { + ClosureVarInfo* cv = new (traceAlloc()) ClosureVarInfo(); + cv->slot = slot; +#ifdef DEBUG + cv->callDepth = callDepth; +#endif + + // Even though the frame is out of range, later we might be called as an + // inner trace such that the target variable is defined in the outer trace + // entry frame. For simplicity, we just fall off trace. + guard(false, + w.eqp(entryFrameIns(), w.ldpObjPrivate(obj_ins)), + MISMATCH_EXIT); + + LIns* outp = w.allocp(sizeof(double)); + LIns* args[] = { + outp, + w.nameImmpNonGC(cv), + obj_ins, + cx_ins + }; + const CallInfo* ci; + if (shape->getterOp() == GetCallArg) { + ci = &GetClosureArg_ci; + } else if (shape->getterOp() == GetCallVar || + shape->getterOp() == GetCallVarChecked) { + ci = &GetClosureVar_ci; + } else { + RETURN_STOP("dynamic property of Call object"); + } + + // Now assert that our use of shape->shortid was in fact kosher. + JS_ASSERT(shape->hasShortID()); + + LIns* call_ins = w.call(ci, args); + + JSValueType type = getCoercedType(nr.v); + guard(true, + w.name(w.eqi(call_ins, w.immi(type)), "guard(type-stable name access)"), + BRANCH_EXIT); + ins = stackLoad(AllocSlotsAddress(outp), type); + } + nr.tracked = false; + nr.obj = obj; + nr.obj_ins = obj_ins; + nr.shape = shape; + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK LIns* +TraceRecorder::arg(unsigned n) +{ + return get(&argval(n)); +} + +JS_REQUIRES_STACK void +TraceRecorder::arg(unsigned n, LIns* i) +{ + set(&argval(n), i); +} + +JS_REQUIRES_STACK LIns* +TraceRecorder::var(unsigned n) +{ + return get(&varval(n)); +} + +JS_REQUIRES_STACK void +TraceRecorder::var(unsigned n, LIns* i) +{ + set(&varval(n), i); +} + +JS_REQUIRES_STACK LIns* +TraceRecorder::stack(int n) +{ + return get(&stackval(n)); +} + +JS_REQUIRES_STACK void +TraceRecorder::stack(int n, LIns* i) +{ + set(&stackval(n), i); +} + +/* Leave trace iff one operand is negative and the other is non-negative. */ +JS_REQUIRES_STACK void +TraceRecorder::guardNonNeg(LIns* d0, LIns* d1, VMSideExit* exit) +{ + if (d0->isImmI()) + JS_ASSERT(d0->immI() >= 0); + else + guard(false, w.ltiN(d0, 0), exit); + + if (d1->isImmI()) + JS_ASSERT(d1->immI() >= 0); + else + guard(false, w.ltiN(d1, 0), exit); +} + +JS_REQUIRES_STACK LIns* +TraceRecorder::alu(LOpcode v, jsdouble v0, jsdouble v1, LIns* s0, LIns* s1) +{ + /* + * To even consider this operation for demotion, both operands have to be + * integers and the oracle must not give us a negative hint for the + * instruction. + */ + if (!oracle || oracle->isInstructionUndemotable(cx->regs->pc) || + !IsPromotedInt32(s0) || !IsPromotedInt32(s1)) { + out: + if (v == LIR_modd) { + LIns* args[] = { s1, s0 }; + return w.call(&js_dmod_ci, args); + } + LIns* result = w.ins2(v, s0, s1); + JS_ASSERT_IF(s0->isImmD() && s1->isImmD(), result->isImmD()); + return result; + } + + jsdouble r; + switch (v) { + case LIR_addd: + r = v0 + v1; + break; + case LIR_subd: + r = v0 - v1; + break; + case LIR_muld: + r = v0 * v1; + if (r == 0.0 && (v0 < 0.0 || v1 < 0.0)) + goto out; + break; +#if defined NANOJIT_IA32 || defined NANOJIT_X64 + case LIR_divd: + if (v1 == 0) + goto out; + r = v0 / v1; + break; + case LIR_modd: + if (v0 < 0 || v1 == 0 || (s1->isImmD() && v1 < 0)) + goto out; + r = js_dmod(v0, v1); + break; +#endif + default: + goto out; + } + + /* + * The result must be an integer at record time, otherwise there is no + * point in trying to demote it. + */ + if (jsint(r) != r || JSDOUBLE_IS_NEGZERO(r)) + goto out; + + LIns* d0 = w.demoteToInt32(s0); + LIns* d1 = w.demoteToInt32(s1); + + /* + * Speculatively emit an integer operation, betting that at runtime we + * will get integer results again. + */ + VMSideExit* exit = NULL; + LIns* result; + switch (v) { +#if defined NANOJIT_IA32 || defined NANOJIT_X64 + case LIR_divd: + if (d0->isImmI() && d1->isImmI()) + return w.i2d(w.immi(jsint(r))); + + exit = snapshot(OVERFLOW_EXIT); + + /* + * If the divisor is greater than zero its always safe to execute + * the division. If not, we have to make sure we are not running + * into -2147483648 / -1, because it can raise an overflow exception. + */ + if (!d1->isImmI()) { + if (MaybeBranch mbr = w.jt(w.gtiN(d1, 0))) { + guard(false, w.eqi0(d1), exit); + guard(true, w.eqi0(w.andi(w.eqiN(d0, 0x80000000), + w.eqiN(d1, -1))), exit); + w.label(mbr); + } + } else { + if (d1->immI() == -1) + guard(false, w.eqiN(d0, 0x80000000), exit); + } + v = LIR_divi; + result = w.divi(d0, d1); + + /* As long as the modulus is zero, the result is an integer. */ + guard(true, w.eqi0(w.modi(result)), exit); + + /* Don't lose a -0. */ + guard(false, w.eqi0(result), exit); + break; + + case LIR_modd: { + if (d0->isImmI() && d1->isImmI()) + return w.i2d(w.immi(jsint(r))); + + exit = snapshot(OVERFLOW_EXIT); + + /* Make sure we don't trigger division by zero at runtime. */ + if (!d1->isImmI()) + guard(false, w.eqi0(d1), exit); + v = LIR_modi; + result = w.modi(w.divi(d0, d1)); + + /* If the result is not 0, it is always within the integer domain. */ + if (MaybeBranch mbr = w.jf(w.eqi0(result))) { + /* + * If the result is zero, we must exit if the lhs is negative since + * the result is -0 in this case, which is not in the integer domain. + */ + guard(false, w.ltiN(d0, 0), exit); + w.label(mbr); + } + break; + } +#endif + + default: + v = arithOpcodeD2I(v); + JS_ASSERT(v == LIR_addi || v == LIR_muli || v == LIR_subi); + + /* + * If the operands guarantee that the result will be an integer (e.g. + * z = x * y with 0 <= (x|y) <= 0xffff guarantees z <= fffe0001), we + * don't have to guard against an overflow. Otherwise we emit a guard + * that will inform the oracle and cause a non-demoted trace to be + * attached that uses floating-point math for this operation. + */ + bool needsOverflowCheck = true, needsNegZeroCheck = true; + ChecksRequired(v, d0, d1, &needsOverflowCheck, &needsNegZeroCheck); + if (needsOverflowCheck) { + exit = snapshot(OVERFLOW_EXIT); + result = guard_xov(v, d0, d1, exit); + } else { + result = w.ins2(v, d0, d1); + } + if (needsNegZeroCheck) { + JS_ASSERT(v == LIR_muli); + /* + * Make sure we don't lose a -0. We exit if the result is zero and if + * either operand is negative. We start out using a weaker guard, checking + * if either argument is negative. If this ever fails, we recompile with + * a stronger, but slower, guard. + */ + if (v0 < 0.0 || v1 < 0.0 + || !oracle || oracle->isInstructionSlowZeroTest(cx->regs->pc)) + { + if (!exit) + exit = snapshot(OVERFLOW_EXIT); + + guard(true, + w.eqi0(w.andi(w.eqi0(result), + w.ori(w.ltiN(d0, 0), + w.ltiN(d1, 0)))), + exit); + } else { + guardNonNeg(d0, d1, snapshot(MUL_ZERO_EXIT)); + } + } + break; + } + JS_ASSERT_IF(d0->isImmI() && d1->isImmI(), result->isImmI(jsint(r))); + return w.i2d(result); +} + +LIns* +TraceRecorder::d2i(LIns* d, bool resultCanBeImpreciseIfFractional) +{ + if (d->isImmD()) + return w.immi(js_DoubleToECMAInt32(d->immD())); + if (d->isop(LIR_i2d) || d->isop(LIR_ui2d)) { + // The d2i(i2d(i)) case is obviously a no-op. (Unlike i2d(d2i(d))!) + // The d2i(ui2d(ui)) case is less obvious, but it is also a no-op. + // For example, 4294967295U has the bit pattern 0xffffffff, and + // d2i(ui2d(4294967295U)) is -1, which also has the bit pattern + // 0xffffffff. Another way to think about it: d2i(ui2d(ui)) is + // equivalent to ui2i(ui); ui2i doesn't exist, but it would be a + // no-op if it did. + // (Note that the above reasoning depends on the fact that d2i() + // always succeeds, ie. it never aborts). + return d->oprnd1(); + } + if (d->isop(LIR_addd) || d->isop(LIR_subd)) { + // If 'i32ad' and 'i32bd' are integral doubles that fit in int32s, and + // 'i32ai' and 'i32bi' are int32s with the equivalent values, then + // this is true: + // + // d2i(addd(i32ad, i32bd)) == addi(i32ai, i32bi) + // + // If the RHS doesn't overflow, this is obvious. If it does overflow, + // the result will truncate. And the LHS will truncate in exactly the + // same way. So they're always equal. + LIns* lhs = d->oprnd1(); + LIns* rhs = d->oprnd2(); + if (IsPromotedInt32(lhs) && IsPromotedInt32(rhs)) + return w.ins2(arithOpcodeD2I(d->opcode()), w.demoteToInt32(lhs), w.demoteToInt32(rhs)); + } + if (d->isCall()) { + const CallInfo* ci = d->callInfo(); + if (ci == &js_UnboxDouble_ci) { +#if JS_BITS_PER_WORD == 32 + LIns *tag_ins = d->callArgN(0); + LIns *payload_ins = d->callArgN(1); + LIns* args[] = { payload_ins, tag_ins }; + return w.call(&js_UnboxInt32_ci, args); +#else + LIns* val_ins = d->callArgN(0); + LIns* args[] = { val_ins }; + return w.call(&js_UnboxInt32_ci, args); +#endif + } + if (ci == &js_StringToNumber_ci) { + LIns* ok_ins = w.allocp(sizeof(JSBool)); + LIns* args[] = { ok_ins, d->callArgN(1), d->callArgN(0) }; + LIns* ret_ins = w.call(&js_StringToInt32_ci, args); + guard(false, + w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"), + OOM_EXIT); + return ret_ins; + } + } + return resultCanBeImpreciseIfFractional + ? w.rawD2i(d) + : w.call(&js_DoubleToInt32_ci, &d); +} + +LIns* +TraceRecorder::d2u(LIns* d) +{ + if (d->isImmD()) + return w.immi(js_DoubleToECMAUint32(d->immD())); + if (d->isop(LIR_i2d) || d->isop(LIR_ui2d)) + return d->oprnd1(); + return w.call(&js_DoubleToUint32_ci, &d); +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::makeNumberInt32(LIns* d, LIns** out) +{ + JS_ASSERT(d->isD()); + if (IsPromotedInt32(d)) { + *out = w.demoteToInt32(d); + return RECORD_CONTINUE; + } + + // This means "convert double to int if it's integral, otherwise + // exit". We first convert the double to an int, then convert it back + // and exit if the two doubles don't match. If 'f' is a non-integral + // immediate we'll end up aborting. + *out = d2i(d, /* resultCanBeImpreciseIfFractional = */true); + return guard(true, w.eqd(d, w.i2d(*out)), MISMATCH_EXIT, /* abortIfAlwaysExits = */true); +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::makeNumberUint32(LIns* d, LIns** out) +{ + JS_ASSERT(d->isD()); + if (IsPromotedUint32(d)) { + *out = w.demoteToUint32(d); + return RECORD_CONTINUE; + } + + // This means "convert double to uint if it's integral, otherwise + // exit". We first convert the double to an unsigned int, then + // convert it back and exit if the two doubles don't match. If + // 'f' is a non-integral immediate we'll end up aborting. + *out = d2u(d); + return guard(true, w.eqd(d, w.ui2d(*out)), MISMATCH_EXIT, /* abortIfAlwaysExits = */true); +} + +JS_REQUIRES_STACK LIns* +TraceRecorder::stringify(const Value& v) +{ + LIns* v_ins = get(&v); + if (v.isString()) + return v_ins; + + LIns* args[] = { v_ins, cx_ins }; + const CallInfo* ci; + if (v.isNumber()) { + ci = &js_NumberToString_ci; + } else if (v.isUndefined()) { + return w.immpAtomGC(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + } else if (v.isBoolean()) { + ci = &js_BooleanIntToString_ci; + } else { + /* + * Callers must deal with non-primitive (non-null object) values by + * calling an imacro. We don't try to guess about which imacro, with + * what valueOf hint, here. + */ + JS_ASSERT(v.isNull()); + return w.immpAtomGC(cx->runtime->atomState.nullAtom); + } + + v_ins = w.call(ci, args); + guard(false, w.eqp0(v_ins), OOM_EXIT); + return v_ins; +} + +JS_REQUIRES_STACK bool +TraceRecorder::canCallImacro() const +{ + /* We cannot nest imacros. */ + return !cx->fp()->hasImacropc(); +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::callImacro(jsbytecode* imacro) +{ + return canCallImacro() ? callImacroInfallibly(imacro) : RECORD_STOP; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::callImacroInfallibly(jsbytecode* imacro) +{ + JSStackFrame* fp = cx->fp(); + JS_ASSERT(!fp->hasImacropc()); + JSFrameRegs* regs = cx->regs; + fp->setImacropc(regs->pc); + regs->pc = imacro; + updateAtoms(); + return RECORD_IMACRO; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::ifop() +{ + Value& v = stackval(-1); + LIns* v_ins = get(&v); + bool cond; + LIns* x; + + if (v.isNull() || v.isUndefined()) { + cond = false; + x = w.immi(0); + } else if (!v.isPrimitive()) { + cond = true; + x = w.immi(1); + } else if (v.isBoolean()) { + /* Test for boolean is true, negate later if we are testing for false. */ + cond = v.isTrue(); + x = w.eqiN(v_ins, 1); + } else if (v.isNumber()) { + jsdouble d = v.toNumber(); + cond = !JSDOUBLE_IS_NaN(d) && d; + x = w.eqi0(w.eqi0(w.andi(w.eqd(v_ins, v_ins), w.eqi0(w.eqd0(v_ins))))); + } else if (v.isString()) { + cond = v.toString()->length() != 0; + x = w.eqi0(w.eqp0(w.getStringLength(v_ins))); + } else { + JS_NOT_REACHED("ifop"); + return ARECORD_STOP; + } + + jsbytecode* pc = cx->regs->pc; + emitIf(pc, cond, x); + return checkTraceEnd(pc); +} + +#ifdef NANOJIT_IA32 +/* + * Record LIR for a tableswitch or tableswitchx op. We record LIR only the + * "first" time we hit the op. Later, when we start traces after exiting that + * trace, we just patch. + */ +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::tableswitch() +{ + Value& v = stackval(-1); + + /* No need to guard if the condition can't match any of the cases. */ + if (!v.isNumber()) + return ARECORD_CONTINUE; + + /* No need to guard if the condition is constant. */ + LIns* v_ins = d2i(get(&v)); + if (v_ins->isImmI()) + return ARECORD_CONTINUE; + + jsbytecode* pc = cx->regs->pc; + /* Starting a new trace after exiting a trace via switch. */ + if (anchor && + (anchor->exitType == CASE_EXIT || anchor->exitType == DEFAULT_EXIT) && + fragment->ip == pc) { + return ARECORD_CONTINUE; + } + + /* Decode jsop. */ + jsint low, high; + if (*pc == JSOP_TABLESWITCH) { + pc += JUMP_OFFSET_LEN; + low = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + high = GET_JUMP_OFFSET(pc); + } else { + pc += JUMPX_OFFSET_LEN; + low = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + high = GET_JUMP_OFFSET(pc); + } + + /* + * If there are no cases, this is a no-op. The default case immediately + * follows in the bytecode and is always taken, so we need no special + * action to handle it. + */ + int count = high + 1 - low; + JS_ASSERT(count >= 0); + if (count == 0) + return ARECORD_CONTINUE; + + /* Cap maximum table-switch size for modesty. */ + if (count > MAX_TABLE_SWITCH) + return InjectStatus(switchop()); + + /* Generate switch LIR. */ + SwitchInfo* si = new (traceAlloc()) SwitchInfo(); + si->count = count; + si->table = 0; + si->index = (uint32) -1; + LIns* diff = w.subi(v_ins, w.immi(low)); + LIns* cmp = w.ltui(diff, w.immi(si->count)); + guard(true, cmp, DEFAULT_EXIT); + // We use AnyAddress; it's imprecise but this case is rare and not worth its + // own access region. + w.st(diff, AnyAddress(w.immpNonGC(&si->index))); + VMSideExit* exit = snapshot(CASE_EXIT); + exit->switchInfo = si; + LIns* guardIns = w.xtbl(diff, createGuardRecord(exit)); + fragment->lastIns = guardIns; + CHECK_STATUS_A(compile()); + return finishSuccessfully(); +} +#endif + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::switchop() +{ + Value& v = stackval(-1); + LIns* v_ins = get(&v); + + /* No need to guard if the condition is constant. */ + if (v_ins->isImmAny()) + return RECORD_CONTINUE; + if (v.isNumber()) { + jsdouble d = v.toNumber(); + guard(true, + w.name(w.eqd(v_ins, w.immd(d)), "guard(switch on numeric)"), + BRANCH_EXIT, + /* abortIfAlwaysExits = */true); + } else if (v.isString()) { + LIns* args[] = { w.immpStrGC(v.toString()), v_ins, cx_ins }; + LIns* equal_rval = w.call(&js_EqualStringsOnTrace_ci, args); + guard(false, + w.name(w.eqiN(equal_rval, JS_NEITHER), "guard(oom)"), + OOM_EXIT); + guard(false, + w.name(w.eqi0(equal_rval), "guard(switch on string)"), + BRANCH_EXIT); + } else if (v.isBoolean()) { + guard(true, + w.name(w.eqi(v_ins, w.immi(v.isTrue())), "guard(switch on boolean)"), + BRANCH_EXIT); + } else if (v.isUndefined()) { + // This is a unit type, so no guard is needed. + } else { + RETURN_STOP("switch on object or null"); + } + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::inc(Value& v, jsint incr, bool pre) +{ + LIns* v_ins = get(&v); + Value dummy; + CHECK_STATUS(inc(v, v_ins, dummy, incr, pre)); + set(&v, v_ins); + return RECORD_CONTINUE; +} + +/* + * On exit, v_ins is the incremented unboxed value, and the appropriate value + * (pre- or post-increment as described by pre) is stacked. v_out is set to + * the value corresponding to v_ins. + */ +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::inc(const Value &v, LIns*& v_ins, Value &v_out, jsint incr, bool pre) +{ + LIns* v_after; + CHECK_STATUS(incHelper(v, v_ins, v_out, v_after, incr)); + + const JSCodeSpec& cs = js_CodeSpec[*cx->regs->pc]; + JS_ASSERT(cs.ndefs == 1); + stack(-cs.nuses, pre ? v_after : v_ins); + v_ins = v_after; + return RECORD_CONTINUE; +} + +/* + * Do an increment operation without storing anything to the stack. + * + * v_after is an out param whose value corresponds to the instruction the + * v_ins_after out param gets set to. + */ +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::incHelper(const Value &v, LIns*& v_ins, Value &v_after, + LIns*& v_ins_after, jsint incr) +{ + // FIXME: Bug 606071 on making this work for objects. + if (!v.isPrimitive()) + RETURN_STOP("can inc primitives only"); + + // We need to modify |v_ins| the same way relational() modifies + // its RHS and LHS. + if (v.isUndefined()) { + v_ins_after = w.immd(js_NaN); + v_after.setDouble(js_NaN); + v_ins = w.immd(js_NaN); + } else if (v.isNull()) { + v_ins_after = w.immd(incr); + v_after.setDouble(incr); + v_ins = w.immd(0.0); + } else { + if (v.isBoolean()) { + v_ins = w.i2d(v_ins); + } else if (v.isString()) { + LIns* ok_ins = w.allocp(sizeof(JSBool)); + LIns* args[] = { ok_ins, v_ins, cx_ins }; + v_ins = w.call(&js_StringToNumber_ci, args); + guard(false, + w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"), + OOM_EXIT); + } else { + JS_ASSERT(v.isNumber()); + } + + jsdouble num; + AutoValueRooter tvr(cx); + *tvr.addr() = v; + ValueToNumber(cx, tvr.value(), &num); + v_ins_after = alu(LIR_addd, num, incr, v_ins, w.immd(incr)); + v_after.setDouble(num + incr); + } + + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::incProp(jsint incr, bool pre) +{ + Value& l = stackval(-1); + if (l.isPrimitive()) + RETURN_STOP_A("incProp on primitive"); + + JSObject* obj = &l.toObject(); + LIns* obj_ins = get(&l); + + uint32 slot; + LIns* v_ins; + CHECK_STATUS_A(prop(obj, obj_ins, &slot, &v_ins, NULL)); + + if (slot == SHAPE_INVALID_SLOT) + RETURN_STOP_A("incProp on invalid slot"); + + Value& v = obj->getSlotRef(slot); + Value v_after; + CHECK_STATUS_A(inc(v, v_ins, v_after, incr, pre)); + + LIns* slots_ins = NULL; + stobj_set_slot(obj, obj_ins, slot, slots_ins, v_after, v_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::incElem(jsint incr, bool pre) +{ + Value& r = stackval(-1); + Value& l = stackval(-2); + Value* vp; + LIns* v_ins; + LIns* addr_ins; + + if (!l.isPrimitive() && l.toObject().isDenseArray() && r.isInt32()) { + guardDenseArray(get(&l), MISMATCH_EXIT); + CHECK_STATUS(denseArrayElement(l, r, vp, v_ins, addr_ins, snapshot(BRANCH_EXIT))); + if (!addr_ins) // if we read a hole, abort + return RECORD_STOP; + Value v_after; + CHECK_STATUS(inc(*vp, v_ins, v_after, incr, pre)); + box_value_into(v_after, v_ins, DSlotsAddress(addr_ins)); + return RECORD_CONTINUE; + } + + return callImacro((incr == 1) + ? pre ? incelem_imacros.incelem : incelem_imacros.eleminc + : pre ? decelem_imacros.decelem : decelem_imacros.elemdec); +} + +static bool +EvalCmp(LOpcode op, double l, double r) +{ + bool cond; + switch (op) { + case LIR_eqd: + cond = (l == r); + break; + case LIR_ltd: + cond = l < r; + break; + case LIR_gtd: + cond = l > r; + break; + case LIR_led: + cond = l <= r; + break; + case LIR_ged: + cond = l >= r; + break; + default: + JS_NOT_REACHED("unexpected comparison op"); + return false; + } + return cond; +} + +static bool +EvalCmp(JSContext *cx, LOpcode op, JSString* l, JSString* r, JSBool *ret) +{ + if (op == LIR_eqd) + return EqualStrings(cx, l, r, ret); + JSBool cmp; + if (!CompareStrings(cx, l, r, &cmp)) + return false; + *ret = EvalCmp(op, cmp, 0); + return true; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::strictEquality(bool equal, bool cmpCase) +{ + Value& r = stackval(-1); + Value& l = stackval(-2); + LIns* l_ins = get(&l); + LIns* r_ins = get(&r); + LIns* x; + JSBool cond; + + JSValueType ltag = getPromotedType(l); + if (ltag != getPromotedType(r)) { + cond = !equal; + x = w.immi(cond); + } else if (ltag == JSVAL_TYPE_STRING) { + LIns* args[] = { r_ins, l_ins, cx_ins }; + LIns* equal_ins = w.call(&js_EqualStringsOnTrace_ci, args); + guard(false, + w.name(w.eqiN(equal_ins, JS_NEITHER), "guard(oom)"), + OOM_EXIT); + x = w.eqiN(equal_ins, equal); + if (!EqualStrings(cx, l.toString(), r.toString(), &cond)) + RETURN_ERROR("oom"); + } else { + if (ltag == JSVAL_TYPE_DOUBLE) + x = w.eqd(l_ins, r_ins); + else if (ltag == JSVAL_TYPE_NULL || ltag == JSVAL_TYPE_NONFUNOBJ || ltag == JSVAL_TYPE_FUNOBJ) + x = w.eqp(l_ins, r_ins); + else + x = w.eqi(l_ins, r_ins); + if (!equal) + x = w.eqi0(x); + cond = (ltag == JSVAL_TYPE_DOUBLE) + ? l.toNumber() == r.toNumber() + : l == r; + } + cond = (!!cond == equal); + + if (cmpCase) { + /* Only guard if the same path may not always be taken. */ + if (!x->isImmI()) + guard(cond, x, BRANCH_EXIT); + return RECORD_CONTINUE; + } + + set(&l, x); + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::equality(bool negate, bool tryBranchAfterCond) +{ + Value& rval = stackval(-1); + Value& lval = stackval(-2); + LIns* l_ins = get(&lval); + LIns* r_ins = get(&rval); + + return equalityHelper(lval, rval, l_ins, r_ins, negate, tryBranchAfterCond, lval); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::equalityHelper(Value& l, Value& r, LIns* l_ins, LIns* r_ins, + bool negate, bool tryBranchAfterCond, + Value& rval) +{ + LOpcode op = LIR_eqi; + JSBool cond; + LIns* args[] = { NULL, NULL, NULL }; + + /* + * The if chain below closely mirrors that found in 11.9.3, in general + * deviating from that ordering of ifs only to account for SpiderMonkey's + * conflation of booleans and undefined and for the possibility of + * confusing objects and null. Note carefully the spec-mandated recursion + * in the final else clause, which terminates because Number == T recurs + * only if T is Object, but that must recur again to convert Object to + * primitive, and ToPrimitive throws if the object cannot be converted to + * a primitive value (which would terminate recursion). + */ + + if (getPromotedType(l) == getPromotedType(r)) { + if (l.isUndefined() || l.isNull()) { + cond = true; + if (l.isNull()) + op = LIR_eqp; + } else if (l.isObject()) { + if (l.toObject().getClass()->ext.equality) + RETURN_STOP_A("Can't trace extended class equality operator"); + LIns* flags_ins = w.ldiObjFlags(l_ins); + LIns* flag_ins = w.andi(flags_ins, w.nameImmui(JSObject::HAS_EQUALITY)); + guard(true, w.eqi0(flag_ins), BRANCH_EXIT); + + op = LIR_eqp; + cond = (l == r); + } else if (l.isBoolean()) { + JS_ASSERT(r.isBoolean()); + cond = (l == r); + } else if (l.isString()) { + JSString *l_str = l.toString(); + JSString *r_str = r.toString(); + if (!l_str->isRope() && !r_str->isRope() && l_str->length() == 1 && r_str->length() == 1) { + VMSideExit *exit = snapshot(BRANCH_EXIT); + LIns *c = w.immw(1); + guard(true, w.eqp(w.getStringLength(l_ins), c), exit); + guard(true, w.eqp(w.getStringLength(r_ins), c), exit); + l_ins = w.getStringChar(l_ins, w.immpNonGC(0)); + r_ins = w.getStringChar(r_ins, w.immpNonGC(0)); + } else { + args[0] = r_ins, args[1] = l_ins, args[2] = cx_ins; + LIns *equal_ins = w.call(&js_EqualStringsOnTrace_ci, args); + guard(false, + w.name(w.eqiN(equal_ins, JS_NEITHER), "guard(oom)"), + OOM_EXIT); + l_ins = equal_ins; + r_ins = w.immi(1); + } + if (!EqualStrings(cx, l.toString(), r.toString(), &cond)) + RETURN_ERROR_A("oom"); + } else { + JS_ASSERT(l.isNumber() && r.isNumber()); + cond = (l.toNumber() == r.toNumber()); + op = LIR_eqd; + } + } else if (l.isNull() && r.isUndefined()) { + l_ins = w.immiUndefined(); + cond = true; + } else if (l.isUndefined() && r.isNull()) { + r_ins = w.immiUndefined(); + cond = true; + } else if (l.isNumber() && r.isString()) { + LIns* ok_ins = w.allocp(sizeof(JSBool)); + args[0] = ok_ins, args[1] = r_ins, args[2] = cx_ins; + r_ins = w.call(&js_StringToNumber_ci, args); + guard(false, + w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"), + OOM_EXIT); + JSBool ok; + double d = js_StringToNumber(cx, r.toString(), &ok); + if (!ok) + RETURN_ERROR_A("oom"); + cond = (l.toNumber() == d); + op = LIR_eqd; + } else if (l.isString() && r.isNumber()) { + LIns* ok_ins = w.allocp(sizeof(JSBool)); + args[0] = ok_ins, args[1] = l_ins, args[2] = cx_ins; + l_ins = w.call(&js_StringToNumber_ci, args); + guard(false, + w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"), + OOM_EXIT); + JSBool ok; + double d = js_StringToNumber(cx, l.toString(), &ok); + if (!ok) + RETURN_ERROR_A("oom"); + cond = (d == r.toNumber()); + op = LIR_eqd; + } else { + // Below we may assign to l or r, which modifies the interpreter state. + // This is fine as long as we also update the tracker. + if (l.isBoolean()) { + l_ins = w.i2d(l_ins); + set(&l, l_ins); + l.setInt32(l.isTrue()); + return equalityHelper(l, r, l_ins, r_ins, negate, + tryBranchAfterCond, rval); + } + if (r.isBoolean()) { + r_ins = w.i2d(r_ins); + set(&r, r_ins); + r.setInt32(r.isTrue()); + return equalityHelper(l, r, l_ins, r_ins, negate, + tryBranchAfterCond, rval); + } + if ((l.isString() || l.isNumber()) && !r.isPrimitive()) { + CHECK_STATUS_A(guardNativeConversion(r)); + return InjectStatus(callImacro(equality_imacros.any_obj)); + } + if (!l.isPrimitive() && (r.isString() || r.isNumber())) { + CHECK_STATUS_A(guardNativeConversion(l)); + return InjectStatus(callImacro(equality_imacros.obj_any)); + } + + l_ins = w.immi(0); + r_ins = w.immi(1); + cond = false; + } + + /* If the operands aren't numbers, compare them as integers. */ + LIns* x = w.ins2(op, l_ins, r_ins); + if (negate) { + x = w.eqi0(x); + cond = !cond; + } + + jsbytecode* pc = cx->regs->pc; + + /* + * Don't guard if the same path is always taken. If it isn't, we have to + * fuse comparisons and the following branch, because the interpreter does + * that. + */ + if (tryBranchAfterCond) + fuseIf(pc + 1, cond, x); + + /* + * There is no need to write out the result of this comparison if the trace + * ends on this operation. + */ + if (pc[1] == JSOP_IFNE || pc[1] == JSOP_IFEQ) + CHECK_STATUS_A(checkTraceEnd(pc + 1)); + + /* + * We update the stack after the guard. This is safe since the guard bails + * out at the comparison and the interpreter will therefore re-execute the + * comparison. This way the value of the condition doesn't have to be + * calculated and saved on the stack in most cases. + */ + set(&rval, x); + + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond) +{ + Value& r = stackval(-1); + Value& l = stackval(-2); + LIns* x = NULL; + JSBool cond; + LIns* l_ins = get(&l); + LIns* r_ins = get(&r); + bool fp = false; + jsdouble lnum, rnum; + + /* + * 11.8.5 if either argument is an object with a function-valued valueOf + * property; if both arguments are objects with non-function-valued valueOf + * properties, abort. + */ + if (!l.isPrimitive()) { + CHECK_STATUS_A(guardNativeConversion(l)); + if (!r.isPrimitive()) { + CHECK_STATUS_A(guardNativeConversion(r)); + return InjectStatus(callImacro(binary_imacros.obj_obj)); + } + return InjectStatus(callImacro(binary_imacros.obj_any)); + } + if (!r.isPrimitive()) { + CHECK_STATUS_A(guardNativeConversion(r)); + return InjectStatus(callImacro(binary_imacros.any_obj)); + } + + /* 11.8.5 steps 3, 16-21. */ + if (l.isString() && r.isString()) { + LIns* args[] = { r_ins, l_ins, cx_ins }; + LIns* result_ins = w.call(&js_CompareStringsOnTrace_ci, args); + guard(false, + w.name(w.eqiN(result_ins, INT32_MIN), "guard(oom)"), + OOM_EXIT); + l_ins = result_ins; + r_ins = w.immi(0); + if (!EvalCmp(cx, op, l.toString(), r.toString(), &cond)) + RETURN_ERROR_A("oom"); + goto do_comparison; + } + + /* 11.8.5 steps 4-5. */ + if (!l.isNumber()) { + if (l.isBoolean()) { + l_ins = w.i2d(l_ins); + } else if (l.isUndefined()) { + l_ins = w.immd(js_NaN); + } else if (l.isString()) { + LIns* ok_ins = w.allocp(sizeof(JSBool)); + LIns* args[] = { ok_ins, l_ins, cx_ins }; + l_ins = w.call(&js_StringToNumber_ci, args); + guard(false, + w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"), + OOM_EXIT); + } else if (l.isNull()) { + l_ins = w.immd(0.0); + } else { + JS_NOT_REACHED("JSVAL_IS_NUMBER if int/double, objects should " + "have been handled at start of method"); + RETURN_STOP_A("safety belt"); + } + } + if (!r.isNumber()) { + if (r.isBoolean()) { + r_ins = w.i2d(r_ins); + } else if (r.isUndefined()) { + r_ins = w.immd(js_NaN); + } else if (r.isString()) { + LIns* ok_ins = w.allocp(sizeof(JSBool)); + LIns* args[] = { ok_ins, r_ins, cx_ins }; + r_ins = w.call(&js_StringToNumber_ci, args); + guard(false, + w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"), + OOM_EXIT); + } else if (r.isNull()) { + r_ins = w.immd(0.0); + } else { + JS_NOT_REACHED("JSVAL_IS_NUMBER if int/double, objects should " + "have been handled at start of method"); + RETURN_STOP_A("safety belt"); + } + } + { + AutoValueRooter tvr(cx); + *tvr.addr() = l; + ValueToNumber(cx, tvr.value(), &lnum); + *tvr.addr() = r; + ValueToNumber(cx, tvr.value(), &rnum); + } + cond = EvalCmp(op, lnum, rnum); + fp = true; + + /* 11.8.5 steps 6-15. */ + do_comparison: + /* + * If the result is not a number or it's not a quad, we must use an integer + * compare. + */ + if (!fp) { + JS_ASSERT(isCmpDOpcode(op)); + op = cmpOpcodeD2I(op); + } + x = w.ins2(op, l_ins, r_ins); + + jsbytecode* pc = cx->regs->pc; + + /* + * Don't guard if the same path is always taken. If it isn't, we have to + * fuse comparisons and the following branch, because the interpreter does + * that. + */ + if (tryBranchAfterCond) + fuseIf(pc + 1, cond, x); + + /* + * There is no need to write out the result of this comparison if the trace + * ends on this operation. + */ + if (pc[1] == JSOP_IFNE || pc[1] == JSOP_IFEQ) + CHECK_STATUS_A(checkTraceEnd(pc + 1)); + + /* + * We update the stack after the guard. This is safe since the guard bails + * out at the comparison and the interpreter will therefore re-execute the + * comparison. This way the value of the condition doesn't have to be + * calculated and saved on the stack in most cases. + */ + set(&l, x); + + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::unary(LOpcode op) +{ + Value& v = stackval(-1); + bool intop = retTypes[op] == LTy_I; + if (v.isNumber()) { + LIns* a = get(&v); + if (intop) + a = d2i(a); + a = w.ins1(op, a); + if (intop) + a = w.i2d(a); + set(&v, a); + return RECORD_CONTINUE; + } + return RECORD_STOP; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::binary(LOpcode op) +{ + Value& r = stackval(-1); + Value& l = stackval(-2); + + if (!l.isPrimitive()) { + CHECK_STATUS(guardNativeConversion(l)); + if (!r.isPrimitive()) { + CHECK_STATUS(guardNativeConversion(r)); + return callImacro(binary_imacros.obj_obj); + } + return callImacro(binary_imacros.obj_any); + } + if (!r.isPrimitive()) { + CHECK_STATUS(guardNativeConversion(r)); + return callImacro(binary_imacros.any_obj); + } + + bool intop = retTypes[op] == LTy_I; + LIns* a = get(&l); + LIns* b = get(&r); + + bool leftIsNumber = l.isNumber(); + jsdouble lnum = leftIsNumber ? l.toNumber() : 0; + + bool rightIsNumber = r.isNumber(); + jsdouble rnum = rightIsNumber ? r.toNumber() : 0; + + if (l.isString()) { + NanoAssert(op != LIR_addd); // LIR_addd/IS_STRING case handled by record_JSOP_ADD() + LIns* ok_ins = w.allocp(sizeof(JSBool)); + LIns* args[] = { ok_ins, a, cx_ins }; + a = w.call(&js_StringToNumber_ci, args); + guard(false, + w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"), + OOM_EXIT); + JSBool ok; + lnum = js_StringToNumber(cx, l.toString(), &ok); + if (!ok) + RETURN_ERROR("oom"); + leftIsNumber = true; + } + if (r.isString()) { + NanoAssert(op != LIR_addd); // LIR_addd/IS_STRING case handled by record_JSOP_ADD() + LIns* ok_ins = w.allocp(sizeof(JSBool)); + LIns* args[] = { ok_ins, b, cx_ins }; + b = w.call(&js_StringToNumber_ci, args); + guard(false, + w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"), + OOM_EXIT); + JSBool ok; + rnum = js_StringToNumber(cx, r.toString(), &ok); + if (!ok) + RETURN_ERROR("oom"); + rightIsNumber = true; + } + if (l.isBoolean()) { + a = w.i2d(a); + lnum = l.toBoolean(); + leftIsNumber = true; + } else if (l.isUndefined()) { + a = w.immd(js_NaN); + lnum = js_NaN; + leftIsNumber = true; + } + if (r.isBoolean()) { + b = w.i2d(b); + rnum = r.toBoolean(); + rightIsNumber = true; + } else if (r.isUndefined()) { + b = w.immd(js_NaN); + rnum = js_NaN; + rightIsNumber = true; + } + if (leftIsNumber && rightIsNumber) { + if (intop) { + a = (op == LIR_rshui) ? d2u(a) : d2i(a); + b = d2i(b); + } + a = alu(op, lnum, rnum, a, b); + if (intop) + a = (op == LIR_rshui) ? w.ui2d(a) : w.i2d(a); + set(&l, a); + return RECORD_CONTINUE; + } + return RECORD_STOP; +} + +#if defined DEBUG_notme && defined XP_UNIX +#include + +static FILE* shapefp = NULL; + +static void +DumpShape(JSObject* obj, const char* prefix) +{ + if (!shapefp) { + shapefp = fopen("/tmp/shapes.dump", "w"); + if (!shapefp) + return; + } + + fprintf(shapefp, "\n%s: shape %u flags %x\n", prefix, obj->shape(), obj->flags); + for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) { + const Shape &shape = r.front(); + + if (JSID_IS_ATOM(shape.id)) { + putc(' ', shapefp); + JS_PutString(JSID_TO_STRING(shape.id), shapefp); + } else { + JS_ASSERT(!JSID_IS_OBJECT(shape.id)); + fprintf(shapefp, " %d", JSID_TO_INT(shape.id)); + } + fprintf(shapefp, " %u %p %p %x %x %d\n", + shape.slot, shape.getter, shape.setter, shape.attrs, shape.flags, shape.shortid); + } + fflush(shapefp); +} + +void +TraceRecorder::dumpGuardedShapes(const char* prefix) +{ + for (GuardedShapeTable::Range r = guardedShapeTable.all(); !r.empty(); r.popFront()) + DumpShape(r.front().value, prefix); +} +#endif /* DEBUG_notme && XP_UNIX */ + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::guardShape(LIns* obj_ins, JSObject* obj, uint32 shape, const char* guardName, + VMSideExit* exit) +{ + // Test (with add if missing) for a remembered guard for (obj_ins, obj). + GuardedShapeTable::AddPtr p = guardedShapeTable.lookupForAdd(obj_ins); + if (p) { + JS_ASSERT(p->value == obj); + return RECORD_CONTINUE; + } + if (!guardedShapeTable.add(p, obj_ins, obj)) + return RECORD_ERROR; + + if (obj == globalObj) { + // In this case checking object identity is equivalent and faster. + guard(true, + w.name(w.eqp(obj_ins, w.immpObjGC(globalObj)), "guard_global"), + exit); + return RECORD_CONTINUE; + } + +#if defined DEBUG_notme && defined XP_UNIX + DumpShape(obj, "guard"); + fprintf(shapefp, "for obj_ins %p\n", obj_ins); +#endif + + // Finally, emit the shape guard. + guard(true, w.name(w.eqiN(w.ldiObjShape(obj_ins), shape), guardName), exit); + return RECORD_CONTINUE; +} + +void +TraceRecorder::forgetGuardedShapesForObject(JSObject* obj) +{ + for (GuardedShapeTable::Enum e(guardedShapeTable); !e.empty(); e.popFront()) { + if (e.front().value == obj) { +#if defined DEBUG_notme && defined XP_UNIX + DumpShape(entry->obj, "forget"); +#endif + e.removeFront(); + } + } +} + +void +TraceRecorder::forgetGuardedShapes() +{ +#if defined DEBUG_notme && defined XP_UNIX + dumpGuardedShapes("forget-all"); +#endif + guardedShapeTable.clear(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2, PCVal& pcval) +{ + jsbytecode* pc = cx->regs->pc; + JS_ASSERT(*pc != JSOP_INITPROP && *pc != JSOP_INITMETHOD && + *pc != JSOP_SETNAME && *pc != JSOP_SETPROP && *pc != JSOP_SETMETHOD); + + // Mimic the interpreter's special case for dense arrays by skipping up one + // hop along the proto chain when accessing a named (not indexed) property, + // typically to find Array.prototype methods. + JSObject* aobj = obj; + if (obj->isDenseArray()) { + guardDenseArray(obj_ins, BRANCH_EXIT); + aobj = obj->getProto(); + obj_ins = w.ldpObjProto(obj_ins); + } + + if (!aobj->isNative()) + RETURN_STOP_A("non-native object"); + + JSAtom* atom; + PropertyCacheEntry* entry; + JS_PROPERTY_CACHE(cx).test(cx, pc, aobj, obj2, entry, atom); + if (atom) { + // Miss: pre-fill the cache for the interpreter, as well as for our needs. + // FIXME: bug 458271. + jsid id = ATOM_TO_JSID(atom); + + // The lookup below may change object shapes. + forgetGuardedShapes(); + + JSProperty* prop; + if (JOF_OPMODE(*pc) == JOF_NAME) { + JS_ASSERT(aobj == obj); + + TraceMonitor &localtm = *traceMonitor; + entry = js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop); + if (!entry) + RETURN_ERROR_A("error in js_FindPropertyHelper"); + + /* js_FindPropertyHelper can reenter the interpreter and kill |this|. */ + if (!localtm.recorder) + return ARECORD_ABORTED; + + if (entry == JS_NO_PROP_CACHE_FILL) + RETURN_STOP_A("cannot cache name"); + } else { + TraceMonitor &localtm = *traceMonitor; + int protoIndex = js_LookupPropertyWithFlags(cx, aobj, id, + cx->resolveFlags, + &obj2, &prop); + + if (protoIndex < 0) + RETURN_ERROR_A("error in js_LookupPropertyWithFlags"); + + /* js_LookupPropertyWithFlags can reenter the interpreter and kill |this|. */ + if (!localtm.recorder) + return ARECORD_ABORTED; + + if (prop) { + if (!obj2->isNative()) + RETURN_STOP_A("property found on non-native object"); + entry = JS_PROPERTY_CACHE(cx).fill(cx, aobj, 0, protoIndex, obj2, + (Shape*) prop); + JS_ASSERT(entry); + if (entry == JS_NO_PROP_CACHE_FILL) + entry = NULL; + } + + } + + if (!prop) { + // Propagate obj from js_FindPropertyHelper to record_JSOP_BINDNAME + // via our obj2 out-parameter. If we are recording JSOP_SETNAME and + // the global it's assigning does not yet exist, create it. + obj2 = obj; + + // Use a null pcval to return "no such property" to our caller. + pcval.setNull(); + return ARECORD_CONTINUE; + } + + if (!entry) + RETURN_STOP_A("failed to fill property cache"); + } + +#ifdef JS_THREADSAFE + // There's a potential race in any JS_THREADSAFE embedding that's nuts + // enough to share mutable objects on the scope or proto chain, but we + // don't care about such insane embeddings. Anyway, the (scope, proto) + // entry->vcap coordinates must reach obj2 from aobj at this point. + JS_ASSERT(cx->thread->data.requestDepth); +#endif + + return InjectStatus(guardPropertyCacheHit(obj_ins, aobj, obj2, entry, pcval)); +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::guardPropertyCacheHit(LIns* obj_ins, + JSObject* aobj, + JSObject* obj2, + PropertyCacheEntry* entry, + PCVal& pcval) +{ + VMSideExit* exit = snapshot(BRANCH_EXIT); + + uint32 vshape = entry->vshape(); + + // Special case for the global object, which may be aliased to get a property value. + // To catch cross-global property accesses we must check against globalObj identity. + // But a JOF_NAME mode opcode needs no guard, as we ensure the global object's shape + // never changes, and name ops can't reach across a global object ('with' aborts). + if (aobj == globalObj) { + if (entry->adding()) + RETURN_STOP("adding a property to the global object"); + + JSOp op = js_GetOpcode(cx, cx->fp()->script(), cx->regs->pc); + if (JOF_OPMODE(op) != JOF_NAME) { + guard(true, + w.name(w.eqp(obj_ins, w.immpObjGC(globalObj)), "guard_global"), + exit); + } + } else { + CHECK_STATUS(guardShape(obj_ins, aobj, entry->kshape, "guard_kshape", exit)); + } + + if (entry->adding()) { + LIns *vshape_ins = + w.ldiRuntimeProtoHazardShape(w.ldpConstContextField(runtime)); + + guard(true, + w.name(w.eqiN(vshape_ins, vshape), "guard_protoHazardShape"), + BRANCH_EXIT); + } + + // For any hit that goes up the scope and/or proto chains, we will need to + // guard on the shape of the object containing the property. + if (entry->vcapTag() >= 1) { + JS_ASSERT(obj2->shape() == vshape); + if (obj2 == globalObj) + RETURN_STOP("hitting the global object via a prototype chain"); + + LIns* obj2_ins; + if (entry->vcapTag() == 1) { + // Duplicate the special case in PropertyCache::test. + obj2_ins = w.ldpObjProto(obj_ins); + guard(false, w.eqp0(obj2_ins), exit); + } else { + obj2_ins = w.immpObjGC(obj2); + } + CHECK_STATUS(guardShape(obj2_ins, obj2, vshape, "guard_vshape", exit)); + } + + pcval = entry->vword; + return RECORD_CONTINUE; +} + +void +TraceRecorder::stobj_set_fslot(LIns *obj_ins, unsigned slot, const Value &v, LIns* v_ins) +{ + box_value_into(v, v_ins, FSlotsAddress(obj_ins, slot)); +} + +void +TraceRecorder::stobj_set_dslot(LIns *obj_ins, unsigned slot, LIns*& slots_ins, + const Value &v, LIns* v_ins) +{ + if (!slots_ins) + slots_ins = w.ldpObjSlots(obj_ins); + box_value_into(v, v_ins, DSlotsAddress(slots_ins, slot)); +} + +void +TraceRecorder::stobj_set_slot(JSObject *obj, LIns* obj_ins, unsigned slot, LIns*& slots_ins, + const Value &v, LIns* v_ins) +{ + /* + * A shape guard must have already been generated for obj, which will + * ensure that future objects have the same number of fixed slots. + */ + if (!obj->hasSlotsArray()) { + JS_ASSERT(slot < obj->numSlots()); + stobj_set_fslot(obj_ins, slot, v, v_ins); + } else { + stobj_set_dslot(obj_ins, slot, slots_ins, v, v_ins); + } +} + +LIns* +TraceRecorder::unbox_slot(JSObject *obj, LIns *obj_ins, uint32 slot, VMSideExit *exit) +{ + /* Same guarantee about fixed slots as stobj_set_slot. */ + Address addr = (!obj->hasSlotsArray()) + ? (Address)FSlotsAddress(obj_ins, slot) + : (Address)DSlotsAddress(w.ldpObjSlots(obj_ins), slot); + + return unbox_value(obj->getSlot(slot), addr, exit); +} + +#if JS_BITS_PER_WORD == 32 + +void +TraceRecorder::box_undefined_into(Address addr) +{ + w.stiValueTag(w.nameImmui(JSVAL_TAG_UNDEFINED), addr); + w.stiValuePayload(w.immi(0), addr); +} + +void +TraceRecorder::box_null_into(Address addr) +{ + w.stiValueTag(w.nameImmui(JSVAL_TAG_NULL), addr); + w.stiValuePayload(w.immi(0), addr); +} + +inline LIns* +TraceRecorder::unbox_number_as_double(Address addr, LIns *tag_ins, VMSideExit *exit) +{ + guard(true, w.leui(tag_ins, w.nameImmui(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET)), exit); + LIns *val_ins = w.ldiValuePayload(addr); + LIns* args[] = { val_ins, tag_ins }; + return w.call(&js_UnboxDouble_ci, args); +} + +inline LIns* +TraceRecorder::unbox_non_double_object(Address addr, LIns* tag_ins, + JSValueType type, VMSideExit* exit) +{ + LIns *val_ins; + if (type == JSVAL_TYPE_UNDEFINED) { + val_ins = w.immiUndefined(); + } else if (type == JSVAL_TYPE_NULL) { + val_ins = w.immpNull(); + } else { + JS_ASSERT(type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_OBJECT || + type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_BOOLEAN || + type == JSVAL_TYPE_MAGIC); + val_ins = w.ldiValuePayload(addr); + } + + guard(true, w.eqi(tag_ins, w.nameImmui(JSVAL_TYPE_TO_TAG(type))), exit); + return val_ins; +} + +LIns* +TraceRecorder::unbox_object(Address addr, LIns* tag_ins, JSValueType type, VMSideExit* exit) +{ + JS_ASSERT(type == JSVAL_TYPE_FUNOBJ || type == JSVAL_TYPE_NONFUNOBJ); + guard(true, w.name(w.eqi(tag_ins, w.nameImmui(JSVAL_TAG_OBJECT)), "isObj"), exit); + LIns *payload_ins = w.ldiValuePayload(addr); + if (type == JSVAL_TYPE_FUNOBJ) + guardClass(payload_ins, &js_FunctionClass, exit, LOAD_NORMAL); + else + guardNotClass(payload_ins, &js_FunctionClass, exit, LOAD_NORMAL); + return payload_ins; +} + +LIns* +TraceRecorder::unbox_value(const Value &v, Address addr, VMSideExit *exit, bool force_double) +{ + LIns *tag_ins = w.ldiValueTag(addr); + + if (v.isNumber() && force_double) + return unbox_number_as_double(addr, tag_ins, exit); + + if (v.isInt32()) { + guard(true, w.name(w.eqi(tag_ins, w.nameImmui(JSVAL_TAG_INT32)), "isInt"), exit); + return w.i2d(w.ldiValuePayload(addr)); + } + + if (v.isDouble()) { + guard(true, w.name(w.ltui(tag_ins, w.nameImmui(JSVAL_TAG_CLEAR)), "isDouble"), exit); + return w.ldd(addr); + } + + if (v.isObject()) { + JSValueType type = v.toObject().isFunction() ? JSVAL_TYPE_FUNOBJ : JSVAL_TYPE_NONFUNOBJ; + return unbox_object(addr, tag_ins, type, exit); + } + + JSValueType type = v.extractNonDoubleObjectTraceType(); + return unbox_non_double_object(addr, tag_ins, type, exit); +} + +void +TraceRecorder::unbox_any_object(Address addr, LIns **obj_ins, LIns **is_obj_ins) +{ + LIns *tag_ins = w.ldiValueTag(addr); + *is_obj_ins = w.eqi(tag_ins, w.nameImmui(JSVAL_TAG_OBJECT)); + *obj_ins = w.ldiValuePayload(addr); +} + +LIns* +TraceRecorder::is_boxed_true(Address addr) +{ + LIns *tag_ins = w.ldiValueTag(addr); + LIns *bool_ins = w.eqi(tag_ins, w.nameImmui(JSVAL_TAG_BOOLEAN)); + LIns *payload_ins = w.ldiValuePayload(addr); + return w.gtiN(w.andi(bool_ins, payload_ins), 0); +} + +LIns* +TraceRecorder::is_boxed_magic(Address addr, JSWhyMagic why) +{ + LIns *tag_ins = w.ldiValueTag(addr); + return w.eqi(tag_ins, w.nameImmui(JSVAL_TAG_MAGIC)); +} + +void +TraceRecorder::box_value_into(const Value &v, LIns *v_ins, Address addr) +{ + if (v.isNumber()) { + JS_ASSERT(v_ins->isD()); + if (fcallinfo(v_ins) == &js_UnboxDouble_ci) { + w.stiValueTag(v_ins->callArgN(0), addr); + w.stiValuePayload(v_ins->callArgN(1), addr); + } else if (IsPromotedInt32(v_ins)) { + LIns *int_ins = w.demoteToInt32(v_ins); + w.stiValueTag(w.nameImmui(JSVAL_TAG_INT32), addr); + w.stiValuePayload(int_ins, addr); + } else { + w.std(v_ins, addr); + } + return; + } + + if (v.isUndefined()) { + box_undefined_into(addr); + } else if (v.isNull()) { + box_null_into(addr); + } else { + JSValueTag tag = v.isObject() ? JSVAL_TAG_OBJECT : v.extractNonDoubleObjectTraceTag(); + w.stiValueTag(w.nameImmui(tag), addr); + w.stiValuePayload(v_ins, addr); + } +} + +LIns* +TraceRecorder::box_value_for_native_call(const Value &v, LIns *v_ins) +{ + return box_value_into_alloc(v, v_ins); +} + +#elif JS_BITS_PER_WORD == 64 + +void +TraceRecorder::box_undefined_into(Address addr) +{ + w.stq(w.nameImmq(JSVAL_BITS(JSVAL_VOID)), addr); +} + +inline LIns * +TraceRecorder::non_double_object_value_has_type(LIns *v_ins, JSValueType type) +{ + return w.eqi(w.q2i(w.rshuqN(v_ins, JSVAL_TAG_SHIFT)), + w.nameImmui(JSVAL_TYPE_TO_TAG(type))); +} + +inline LIns * +TraceRecorder::unpack_ptr(LIns *v_ins) +{ + return w.andq(v_ins, w.nameImmq(JSVAL_PAYLOAD_MASK)); +} + +inline LIns * +TraceRecorder::unbox_number_as_double(LIns *v_ins, VMSideExit *exit) +{ + guard(true, + w.ltuq(v_ins, w.nameImmq(JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET)), + exit); + LIns* args[] = { v_ins }; + return w.call(&js_UnboxDouble_ci, args); +} + +inline nanojit::LIns* +TraceRecorder::unbox_non_double_object(LIns* v_ins, JSValueType type, VMSideExit* exit) +{ + JS_ASSERT(type <= JSVAL_UPPER_INCL_TYPE_OF_VALUE_SET); + LIns *unboxed_ins; + if (type == JSVAL_TYPE_UNDEFINED) { + unboxed_ins = w.immiUndefined(); + } else if (type == JSVAL_TYPE_NULL) { + unboxed_ins = w.immpNull(); + } else if (type >= JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET) { + unboxed_ins = unpack_ptr(v_ins); + } else { + JS_ASSERT(type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN || type == JSVAL_TYPE_MAGIC); + unboxed_ins = w.q2i(v_ins); + } + + guard(true, non_double_object_value_has_type(v_ins, type), exit); + return unboxed_ins; +} + +LIns* +TraceRecorder::unbox_object(LIns* v_ins, JSValueType type, VMSideExit* exit) +{ + JS_STATIC_ASSERT(JSVAL_TYPE_OBJECT == JSVAL_UPPER_INCL_TYPE_OF_VALUE_SET); + JS_ASSERT(type == JSVAL_TYPE_FUNOBJ || type == JSVAL_TYPE_NONFUNOBJ); + guard(true, + w.geuq(v_ins, w.nameImmq(JSVAL_SHIFTED_TAG_OBJECT)), + exit); + v_ins = unpack_ptr(v_ins); + if (type == JSVAL_TYPE_FUNOBJ) + guardClass(v_ins, &js_FunctionClass, exit, LOAD_NORMAL); + else + guardNotClass(v_ins, &js_FunctionClass, exit, LOAD_NORMAL); + return v_ins; +} + +LIns* +TraceRecorder::unbox_value(const Value &v, Address addr, VMSideExit *exit, bool force_double) +{ + LIns *v_ins = w.ldq(addr); + + if (v.isNumber() && force_double) + return unbox_number_as_double(v_ins, exit); + + if (v.isInt32()) { + guard(true, non_double_object_value_has_type(v_ins, JSVAL_TYPE_INT32), exit); + return w.i2d(w.q2i(v_ins)); + } + + if (v.isDouble()) { + guard(true, w.leuq(v_ins, w.nameImmq(JSVAL_SHIFTED_TAG_MAX_DOUBLE)), exit); + return w.qasd(v_ins); + } + + if (v.isObject()) { + JSValueType type = v.toObject().isFunction() ? JSVAL_TYPE_FUNOBJ : JSVAL_TYPE_NONFUNOBJ; + return unbox_object(v_ins, type, exit); + } + + JSValueType type = v.extractNonDoubleObjectTraceType(); + return unbox_non_double_object(v_ins, type, exit); +} + +void +TraceRecorder::unbox_any_object(Address addr, LIns **obj_ins, LIns **is_obj_ins) +{ + JS_STATIC_ASSERT(JSVAL_TYPE_OBJECT == JSVAL_UPPER_INCL_TYPE_OF_VALUE_SET); + LIns *v_ins = w.ldq(addr); + *is_obj_ins = w.geuq(v_ins, w.nameImmq(JSVAL_TYPE_OBJECT)); + *obj_ins = unpack_ptr(v_ins); +} + +LIns* +TraceRecorder::is_boxed_true(Address addr) +{ + LIns *v_ins = w.ldq(addr); + return w.eqq(v_ins, w.immq(JSVAL_BITS(JSVAL_TRUE))); +} + +LIns* +TraceRecorder::is_boxed_magic(Address addr, JSWhyMagic why) +{ + LIns *v_ins = w.ldq(addr); + return w.eqq(v_ins, w.nameImmq(BUILD_JSVAL(JSVAL_TAG_MAGIC, why))); +} + +LIns* +TraceRecorder::box_value_for_native_call(const Value &v, LIns *v_ins) +{ + if (v.isNumber()) { + JS_ASSERT(v_ins->isD()); + if (fcallinfo(v_ins) == &js_UnboxDouble_ci) + return v_ins->callArgN(0); + if (IsPromotedInt32(v_ins)) { + return w.orq(w.ui2uq(w.demoteToInt32(v_ins)), + w.nameImmq(JSVAL_SHIFTED_TAG_INT32)); + } + return w.dasq(v_ins); + } + + if (v.isNull()) + return w.nameImmq(JSVAL_BITS(JSVAL_NULL)); + if (v.isUndefined()) + return w.nameImmq(JSVAL_BITS(JSVAL_VOID)); + + JSValueTag tag = v.isObject() ? JSVAL_TAG_OBJECT : v.extractNonDoubleObjectTraceTag(); + uint64 shiftedTag = ((uint64)tag) << JSVAL_TAG_SHIFT; + LIns *shiftedTag_ins = w.nameImmq(shiftedTag); + + if (v.hasPtrPayload()) + return w.orq(v_ins, shiftedTag_ins); + return w.orq(w.ui2uq(v_ins), shiftedTag_ins); +} + +void +TraceRecorder::box_value_into(const Value &v, LIns *v_ins, Address addr) +{ + LIns *boxed_ins = box_value_for_native_call(v, v_ins); + w.st(boxed_ins, addr); +} + +#endif /* JS_BITS_PER_WORD */ + +LIns* +TraceRecorder::box_value_into_alloc(const Value &v, LIns *v_ins) +{ + LIns *alloc_ins = w.allocp(sizeof(Value)); + box_value_into(v, v_ins, AllocSlotsAddress(alloc_ins)); + return alloc_ins; +} + +LIns* +TraceRecorder::is_string_id(LIns *id_ins) +{ + return w.eqp0(w.andp(id_ins, w.nameImmw(JSID_TYPE_MASK))); +} + +LIns * +TraceRecorder::unbox_string_id(LIns *id_ins) +{ + JS_STATIC_ASSERT(JSID_TYPE_STRING == 0); + return id_ins; +} + +LIns * +TraceRecorder::unbox_int_id(LIns *id_ins) +{ + return w.rshiN(w.p2i(id_ins), 1); +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::getThis(LIns*& this_ins) +{ + JSStackFrame *fp = cx->fp(); + + if (fp->isGlobalFrame()) { + // Top-level code. It is an invariant of the interpreter that fp->thisv + // is non-null. Furthermore, we would not be recording if globalObj + // were not at the end of the scope chain, so `this` can only be one + // object, which we can burn into the trace. + JS_ASSERT(!fp->thisValue().isPrimitive()); + +#ifdef DEBUG + JSObject *obj = globalObj->thisObject(cx); + if (!obj) + RETURN_ERROR("thisObject hook failed"); + JS_ASSERT(&fp->thisValue().toObject() == obj); +#endif + + this_ins = w.immpObjGC(&fp->thisValue().toObject()); + return RECORD_CONTINUE; + } + + JS_ASSERT(fp->callee().getGlobal() == globalObj); + Value& thisv = fp->thisValue(); + + if (thisv.isObject() || fp->fun()->inStrictMode()) { + /* + * fp->thisValue() has already been computed. Since the + * type-specialization of traces distinguishes between computed and + * uncomputed |this|, the same will be true at run time (or we + * won't get this far). + */ + this_ins = get(&fp->thisValue()); + return RECORD_CONTINUE; + } + + /* Don't bother tracing calls on wrapped primitive |this| values. */ + if (!thisv.isNullOrUndefined()) + RETURN_STOP("wrapping primitive |this|"); + + /* + * Compute 'this' now. The result is globalObj->thisObject(), which is + * trace-constant. getThisObject writes back to fp->thisValue(), so do + * the same on trace. + */ + if (!fp->computeThis(cx)) + RETURN_ERROR("computeThis failed"); + + /* thisv is a reference, so it'll see the newly computed |this|. */ + this_ins = w.immpObjGC(globalObj); + set(&thisv, this_ins); + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK void +TraceRecorder::guardClassHelper(bool cond, LIns* obj_ins, Class* clasp, VMSideExit* exit, + LoadQual loadQual) +{ + LIns* class_ins = w.ldpObjClasp(obj_ins, loadQual); + +#ifdef JS_JIT_SPEW + char namebuf[32]; + JS_snprintf(namebuf, sizeof namebuf, "%s_clasp", clasp->name); + LIns* clasp_ins = w.name(w.immpNonGC(clasp), namebuf); + JS_snprintf(namebuf, sizeof namebuf, "guard(class is %s)", clasp->name); + LIns* cmp_ins = w.name(w.eqp(class_ins, clasp_ins), namebuf); +#else + LIns* clasp_ins = w.immpNonGC(clasp); + LIns* cmp_ins = w.eqp(class_ins, clasp_ins); +#endif + guard(cond, cmp_ins, exit); +} + +JS_REQUIRES_STACK void +TraceRecorder::guardClass(LIns* obj_ins, Class* clasp, VMSideExit* exit, LoadQual loadQual) +{ + guardClassHelper(true, obj_ins, clasp, exit, loadQual); +} + +JS_REQUIRES_STACK void +TraceRecorder::guardNotClass(LIns* obj_ins, Class* clasp, VMSideExit* exit, LoadQual loadQual) +{ + guardClassHelper(false, obj_ins, clasp, exit, loadQual); +} + +JS_REQUIRES_STACK void +TraceRecorder::guardDenseArray(LIns* obj_ins, ExitType exitType) +{ + guardClass(obj_ins, &js_ArrayClass, snapshot(exitType), LOAD_NORMAL); +} + +JS_REQUIRES_STACK void +TraceRecorder::guardDenseArray(LIns* obj_ins, VMSideExit* exit) +{ + guardClass(obj_ins, &js_ArrayClass, exit, LOAD_NORMAL); +} + +JS_REQUIRES_STACK bool +TraceRecorder::guardHasPrototype(JSObject* obj, LIns* obj_ins, + JSObject** pobj, LIns** pobj_ins, + VMSideExit* exit) +{ + *pobj = obj->getProto(); + *pobj_ins = w.ldpObjProto(obj_ins); + + bool cond = *pobj == NULL; + guard(cond, w.name(w.eqp0(*pobj_ins), "guard(proto-not-null)"), exit); + return !cond; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::guardPrototypeHasNoIndexedProperties(JSObject* obj, LIns* obj_ins, VMSideExit *exit) +{ + /* + * Guard that no object along the prototype chain has any indexed + * properties which might become visible through holes in the array. + */ + if (js_PrototypeHasIndexedProperties(cx, obj)) + return RECORD_STOP; + + JS_ASSERT(obj->isDenseArray()); + + /* + * Changing __proto__ on a dense array makes it slow, so we can just bake in + * the current prototype as the first prototype to test. This avoids an + * extra load when running the trace. + */ + obj = obj->getProto(); + JS_ASSERT(obj); + + obj_ins = w.immpObjGC(obj); + + /* + * Changing __proto__ on a native object changes its shape, and adding + * indexed properties changes shapes too. And non-native objects never pass + * shape guards. So it's enough to just guard on shapes up the proto chain; + * any change to the proto chain length will make us fail a guard before we + * run off the end of the proto chain. + */ + do { + CHECK_STATUS(guardShape(obj_ins, obj, obj->shape(), "guard(shape)", exit)); + obj = obj->getProto(); + obj_ins = w.ldpObjProto(obj_ins); + } while (obj); + + return RECORD_CONTINUE; +} + +/* + * Guard that the object stored in v has the ECMA standard [[DefaultValue]] + * method. Several imacros require this. + */ +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::guardNativeConversion(Value& v) +{ + JSObject* obj = &v.toObject(); + LIns* obj_ins = get(&v); + + ConvertOp convert = obj->getClass()->convert; + if (convert != Valueify(JS_ConvertStub) && convert != js_TryValueOf) + RETURN_STOP("operand has convert hook"); + + VMSideExit* exit = snapshot(BRANCH_EXIT); + if (obj->isNative()) { + // The common case. Guard on shape rather than class because it'll + // often be free: we're about to do a shape guard anyway to get the + // .valueOf property of this object, and this guard will be cached. + CHECK_STATUS(guardShape(obj_ins, obj, obj->shape(), + "guardNativeConversion", exit)); + } else { + // We could specialize to guard on just JSClass.convert, but a mere + // class guard is simpler and slightly faster. + guardClass(obj_ins, obj->getClass(), snapshot(MISMATCH_EXIT), LOAD_NORMAL); + } + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK void +TraceRecorder::clearReturningFrameFromNativeTracker() +{ + /* + * Clear all tracker entries associated with the frame for the same reason + * described in record_EnterFrame. Reuse the generic visitor to avoid + * duplicating logic. The generic visitor stops at 'sp', whereas we need to + * clear up to script->nslots, so finish the job manually. + */ + ClearSlotsVisitor visitor(nativeFrameTracker); + VisitStackSlots(visitor, cx, 0); + Value *vp = cx->regs->sp; + Value *vpend = cx->fp()->slots() + cx->fp()->script()->nslots; + for (; vp < vpend; ++vp) + nativeFrameTracker.set(vp, NULL); +} + +class BoxArg +{ + public: + BoxArg(TraceRecorder *tr, Address addr) + : tr(tr), addr(addr) {} + TraceRecorder *tr; + Address addr; + void operator()(uintN argi, Value *src) { + tr->box_value_into(*src, tr->get(src), OffsetAddress(addr, argi * sizeof(Value))); + } +}; + +/* + * If we have created an |arguments| object for the frame, we must copy the + * argument values into the object as properties in case it is used after + * this frame returns. + */ +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::putActivationObjects() +{ + JSStackFrame *const fp = cx->fp(); + bool have_args = fp->hasArgsObj() && !fp->argsObj().isStrictArguments(); + bool have_call = fp->isFunctionFrame() && fp->fun()->isHeavyweight(); + + if (!have_args && !have_call) + return ARECORD_CONTINUE; + + if (have_args && !fp->script()->usesArguments) { + /* + * have_args is true, so |arguments| has been accessed, but + * usesArguments is false, so there's no statically visible access. + * It must have been a dodgy access like |f["arguments"]|; just + * abort. (In the case where the record-time property name is not + * "arguments" but a later run-time property name is, we wouldn't have + * emitted the call to js_PutArgumentsOnTrace(), and js_GetArgsValue() + * will deep bail asking for the top JSStackFrame.) + */ + RETURN_STOP_A("dodgy arguments access"); + } + + uintN nformal = fp->numFormalArgs(); + uintN nactual = fp->numActualArgs(); + uintN nargs = have_args && have_call ? Max(nformal, nactual) + : have_args ? nactual : nformal; + + LIns *args_ins; + if (nargs > 0) { + args_ins = w.allocp(nargs * sizeof(Value)); + /* Don't copy all the actuals if we are only boxing for the callobj. */ + Address addr = AllocSlotsAddress(args_ins); + if (nargs == nactual) + fp->forEachCanonicalActualArg(BoxArg(this, addr)); + else + fp->forEachFormalArg(BoxArg(this, addr)); + } else { + args_ins = w.immpNonGC(0); + } + + if (have_args) { + LIns* argsobj_ins = getFrameObjPtr(fp->addressOfArgs()); + LIns* args[] = { args_ins, argsobj_ins, cx_ins }; + w.call(&js_PutArgumentsOnTrace_ci, args); + } + + if (have_call) { + int nslots = fp->fun()->script()->bindings.countVars(); + LIns* slots_ins; + if (nslots) { + slots_ins = w.allocp(sizeof(Value) * nslots); + for (int i = 0; i < nslots; ++i) { + box_value_into(fp->slots()[i], get(&fp->slots()[i]), + AllocSlotsAddress(slots_ins, i)); + } + } else { + slots_ins = w.immpNonGC(0); + } + + LIns* scopeChain_ins = getFrameObjPtr(fp->addressOfScopeChain()); + LIns* args[] = { slots_ins, w.nameImmi(nslots), args_ins, + w.nameImmi(fp->numFormalArgs()), scopeChain_ins, cx_ins }; + w.call(&js_PutCallObjectOnTrace_ci, args); + } + + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_EnterFrame() +{ + JSStackFrame* const fp = cx->fp(); + + if (++callDepth >= MAX_CALLDEPTH) + RETURN_STOP_A("exceeded maximum call depth"); + + debug_only_stmt(JSAutoByteString funBytes); + debug_only_printf(LC_TMTracer, "EnterFrame %s, callDepth=%d\n", + cx->fp()->fun()->atom ? + js_AtomToPrintableString(cx, cx->fp()->fun()->atom, &funBytes) : + "", + callDepth); + debug_only_stmt( + if (LogController.lcbits & LC_TMRecorder) { + js_Disassemble(cx, cx->fp()->script(), JS_TRUE, stdout); + debug_only_print0(LC_TMTracer, "----\n"); + } + ) + LIns* void_ins = w.immiUndefined(); + + // Before we enter this frame, we need to clear out any dangling insns left + // in the tracer. While we also clear when returning from a function, it is + // possible to have the following sequence of stack usage: + // + // [fp1]***************** push + // [fp1]***** pop + // [fp1]*****[fp2] call + // [fp1]*****[fp2]*** push + // + // Duplicate native stack layout computation: see VisitFrameSlots header comment. + + // args: carefully copy stack layout + uintN nactual = fp->numActualArgs(); + uintN nformal = fp->numFormalArgs(); + if (nactual < nformal) { + // Fill in missing with void. + JS_ASSERT(fp->actualArgs() == fp->formalArgs()); + Value *beg = fp->formalArgs() + nactual; + Value *end = fp->formalArgsEnd(); + for (Value *vp = beg; vp != end; ++vp) { + nativeFrameTracker.set(vp, NULL); + set(vp, void_ins); + } + } else if (nactual > nformal) { + // Although the VM clones the formal args to the top of the stack, due + // to the fact that we only track the canonical arguments (in argument + // order), the native stack offset of the arguments doesn't change. The + // only thing that changes is which js::Value* in the tracker maps to + // that slot. Thus, all we need to do here is fixup the trackers, not + // emit any actual copying on trace. + JS_ASSERT(fp->actualArgs() != fp->formalArgs()); + JS_ASSERT(fp->hasOverflowArgs()); + Value *srcbeg = fp->actualArgs() - 2; + Value *srcend = fp->actualArgs() + nformal; + Value *dstbeg = fp->formalArgs() - 2; + for (Value *src = srcbeg, *dst = dstbeg; src != srcend; ++src, ++dst) { + nativeFrameTracker.set(dst, NULL); + tracker.set(dst, tracker.get(src)); + nativeFrameTracker.set(src, NULL); + tracker.set(src, NULL); + } + } + + // argsObj: clear and set to null + nativeFrameTracker.set(fp->addressOfArgs(), NULL); + setFrameObjPtr(fp->addressOfArgs(), w.immpNull()); + + // scopeChain: clear, initialize before snapshot, set below + nativeFrameTracker.set(fp->addressOfScopeChain(), NULL); + setFrameObjPtr(fp->addressOfScopeChain(), w.immpNull()); + + // nfixed: clear and set to undefined + Value *vp = fp->slots(); + Value *vpstop = vp + fp->numFixed(); + for (; vp < vpstop; ++vp) { + nativeFrameTracker.set(vp, NULL); + set(vp, void_ins); + } + + // nfixed to nslots: clear + vp = fp->base(); + vpstop = fp->slots() + fp->numSlots(); + for (; vp < vpstop; ++vp) + nativeFrameTracker.set(vp, NULL); + + LIns* callee_ins = get(&cx->fp()->calleeValue()); + LIns* scopeChain_ins = w.ldpObjParent(callee_ins); + + // set scopeChain for real + if (cx->fp()->fun()->isHeavyweight()) { + if (js_IsNamedLambda(cx->fp()->fun())) + RETURN_STOP_A("can't call named lambda heavyweight on trace"); + + LIns* fun_ins = w.nameImmpNonGC(cx->fp()->fun()); + + LIns* args[] = { scopeChain_ins, callee_ins, fun_ins, cx_ins }; + LIns* call_ins = w.call(&js_CreateCallObjectOnTrace_ci, args); + guard(false, w.eqp0(call_ins), OOM_EXIT); + + setFrameObjPtr(fp->addressOfScopeChain(), call_ins); + } else { + setFrameObjPtr(fp->addressOfScopeChain(), scopeChain_ins); + } + + /* Try inlining one level in case this recursion doesn't go too deep. */ + if (fp->script() == fp->prev()->script() && + fp->prev()->prev() && fp->prev()->prev()->script() == fp->script()) { + RETURN_STOP_A("recursion started inlining"); + } + + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_LeaveFrame() +{ + debug_only_stmt(JSStackFrame *fp = cx->fp();) + + JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, fp->script(), + cx->regs->pc)].length == JSOP_CALL_LENGTH); + + if (callDepth-- <= 0) + RETURN_STOP_A("returned out of a loop we started tracing"); + + // LeaveFrame gets called after the interpreter popped the frame and + // stored rval, so cx->fp() not cx->fp()->prev, and -1 not 0. + updateAtoms(); + set(&stackval(-1), rval_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_PUSH() +{ + stack(0, w.immiUndefined()); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_POPV() +{ + Value& rval = stackval(-1); + + // Store it in cx->fp()->rval. NB: Tricky dependencies. cx->fp() is the right + // frame because POPV appears only in global and eval code and we don't + // trace JSOP_EVAL or leaving the frame where tracing started. + LIns *fp_ins = entryFrameIns(); + box_value_into(rval, get(&rval), StackFrameAddress(fp_ins, + JSStackFrame::offsetOfReturnValue())); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ENTERWITH() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_LEAVEWITH() +{ + return ARECORD_STOP; +} + +static JSBool JS_FASTCALL +functionProbe(JSContext *cx, JSFunction *fun, int enter) +{ +#ifdef MOZ_TRACE_JSCALLS + JSScript *script = fun ? FUN_SCRIPT(fun) : NULL; + if (enter > 0) + Probes::enterJSFun(cx, fun, script, enter); + else + Probes::exitJSFun(cx, fun, script, enter); +#endif + return true; +} + +JS_DEFINE_CALLINFO_3(static, BOOL, functionProbe, CONTEXT, FUNCTION, INT32, 0, ACCSET_ALL) + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_RETURN() +{ + /* A return from callDepth 0 terminates the current loop, except for recursion. */ + if (callDepth == 0) { + AUDIT(returnLoopExits); + return endLoop(); + } + + CHECK_STATUS_A(putActivationObjects()); + + if (Probes::callTrackingActive(cx)) { + LIns* args[] = { w.immi(0), w.nameImmpNonGC(cx->fp()->fun()), cx_ins }; + LIns* call_ins = w.call(&functionProbe_ci, args); + guard(false, w.eqi0(call_ins), MISMATCH_EXIT); + } + + /* If we inlined this function call, make the return value available to the caller code. */ + Value& rval = stackval(-1); + JSStackFrame *fp = cx->fp(); + if (fp->isConstructing() && rval.isPrimitive()) { + rval_ins = get(&fp->thisValue()); + } else { + rval_ins = get(&rval); + } + debug_only_stmt(JSAutoByteString funBytes); + debug_only_printf(LC_TMTracer, + "returning from %s\n", + fp->fun()->atom ? + js_AtomToPrintableString(cx, fp->fun()->atom, &funBytes) : + ""); + clearReturningFrameFromNativeTracker(); + + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GOTO() +{ + /* + * If we hit a break or a continue to an outer loop, end the loop and + * generate an always-taken loop exit guard. For other downward gotos + * (like if/else) continue recording. + */ + jssrcnote* sn = js_GetSrcNote(cx->fp()->script(), cx->regs->pc); + + if (sn) { + if (SN_TYPE(sn) == SRC_BREAK) { + AUDIT(breakLoopExits); + return endLoop(); + } + + /* + * Tracing labeled break isn't impossible, but does require potentially + * fixing up the block chain. See bug 616119. + */ + if (SN_TYPE(sn) == SRC_BREAK2LABEL || SN_TYPE(sn) == SRC_CONT2LABEL) + RETURN_STOP_A("labeled break"); + } + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_IFEQ() +{ + trackCfgMerges(cx->regs->pc); + return ifop(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_IFNE() +{ + return ifop(); +} + +LIns* +TraceRecorder::newArguments(LIns* callee_ins) +{ + LIns* global_ins = w.immpObjGC(globalObj); + LIns* argc_ins = w.nameImmi(cx->fp()->numActualArgs()); + + LIns* args[] = { callee_ins, argc_ins, global_ins, cx_ins }; + LIns* argsobj_ins = w.call(&js_NewArgumentsOnTrace_ci, args); + guard(false, w.eqp0(argsobj_ins), OOM_EXIT); + + return argsobj_ins; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ARGUMENTS() +{ + JSStackFrame* const fp = cx->fp(); + + /* In an eval, 'arguments' will be a BINDNAME, which we don't trace. */ + JS_ASSERT(!fp->isEvalFrame()); + + if (fp->hasOverriddenArgs()) + RETURN_STOP_A("Can't trace |arguments| if |arguments| is assigned to"); + if (fp->fun()->inStrictMode()) + RETURN_STOP_A("Can't trace strict-mode arguments"); + + LIns* a_ins = getFrameObjPtr(fp->addressOfArgs()); + LIns* args_ins; + LIns* callee_ins = get(&fp->calleeValue()); + if (a_ins->isImmP()) { + // |arguments| is set to 0 by EnterFrame on this trace, so call to create it. + args_ins = newArguments(callee_ins); + } else { + // Generate LIR to create arguments only if it has not already been created. + + LIns* mem_ins = w.allocp(sizeof(JSObject *)); + + LIns* isZero_ins = w.eqp0(a_ins); + if (isZero_ins->isImmI(0)) { + w.stAlloc(a_ins, mem_ins); + } else if (isZero_ins->isImmI(1)) { + LIns* call_ins = newArguments(callee_ins); + w.stAlloc(call_ins, mem_ins); + } else { + LIns* br1 = w.jtUnoptimizable(isZero_ins); + w.stAlloc(a_ins, mem_ins); + LIns* br2 = w.j(NULL); + w.label(br1); + + LIns* call_ins = newArguments(callee_ins); + w.stAlloc(call_ins, mem_ins); + w.label(br2); + } + args_ins = w.ldpAlloc(mem_ins); + } + + stack(0, args_ins); + setFrameObjPtr(fp->addressOfArgs(), args_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DUP() +{ + stack(0, get(&stackval(-1))); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DUP2() +{ + stack(0, get(&stackval(-2))); + stack(1, get(&stackval(-1))); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SWAP() +{ + Value& l = stackval(-2); + Value& r = stackval(-1); + LIns* l_ins = get(&l); + LIns* r_ins = get(&r); + set(&r, l_ins); + set(&l, r_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_PICK() +{ + Value* sp = cx->regs->sp; + jsint n = cx->regs->pc[1]; + JS_ASSERT(sp - (n+1) >= cx->fp()->base()); + LIns* top = get(sp - (n+1)); + for (jsint i = 0; i < n; ++i) + set(sp - (n+1) + i, get(sp - n + i)); + set(&sp[-1], top); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SETCONST() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_BITOR() +{ + return InjectStatus(binary(LIR_ori)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_BITXOR() +{ + return InjectStatus(binary(LIR_xori)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_BITAND() +{ + return InjectStatus(binary(LIR_andi)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_EQ() +{ + return equality(false, true); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_NE() +{ + return equality(true, true); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_LT() +{ + return relational(LIR_ltd, true); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_LE() +{ + return relational(LIR_led, true); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GT() +{ + return relational(LIR_gtd, true); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GE() +{ + return relational(LIR_ged, true); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_LSH() +{ + return InjectStatus(binary(LIR_lshi)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_RSH() +{ + return InjectStatus(binary(LIR_rshi)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_URSH() +{ + return InjectStatus(binary(LIR_rshui)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ADD() +{ + Value& r = stackval(-1); + Value& l = stackval(-2); + + if (!l.isPrimitive()) { + CHECK_STATUS_A(guardNativeConversion(l)); + if (!r.isPrimitive()) { + CHECK_STATUS_A(guardNativeConversion(r)); + return InjectStatus(callImacro(add_imacros.obj_obj)); + } + return InjectStatus(callImacro(add_imacros.obj_any)); + } + if (!r.isPrimitive()) { + CHECK_STATUS_A(guardNativeConversion(r)); + return InjectStatus(callImacro(add_imacros.any_obj)); + } + + if (l.isString() || r.isString()) { + LIns* args[] = { stringify(r), stringify(l), cx_ins }; + LIns* concat = w.call(&js_ConcatStrings_ci, args); + guard(false, w.eqp0(concat), OOM_EXIT); + set(&l, concat); + return ARECORD_CONTINUE; + } + + return InjectStatus(binary(LIR_addd)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SUB() +{ + return InjectStatus(binary(LIR_subd)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_MUL() +{ + return InjectStatus(binary(LIR_muld)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DIV() +{ + return InjectStatus(binary(LIR_divd)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_MOD() +{ + return InjectStatus(binary(LIR_modd)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_NOT() +{ + Value& v = stackval(-1); + if (v.isBoolean() || v.isUndefined()) { + set(&v, w.eqi0(w.eqiN(get(&v), 1))); + return ARECORD_CONTINUE; + } + if (v.isNumber()) { + LIns* v_ins = get(&v); + set(&v, w.ori(w.eqd0(v_ins), w.eqi0(w.eqd(v_ins, v_ins)))); + return ARECORD_CONTINUE; + } + if (v.isObjectOrNull()) { + set(&v, w.eqp0(get(&v))); + return ARECORD_CONTINUE; + } + JS_ASSERT(v.isString()); + set(&v, w.eqp0(w.getStringLength(get(&v)))); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_BITNOT() +{ + return InjectStatus(unary(LIR_noti)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_NEG() +{ + Value& v = stackval(-1); + + if (!v.isPrimitive()) { + CHECK_STATUS_A(guardNativeConversion(v)); + return InjectStatus(callImacro(unary_imacros.sign)); + } + + if (v.isNumber()) { + LIns* a = get(&v); + + /* + * If we're a promoted integer, we have to watch out for 0s since -0 is + * a double. Only follow this path if we're not an integer that's 0 and + * we're not a double that's zero. + */ + if (oracle && + !oracle->isInstructionUndemotable(cx->regs->pc) && + IsPromotedInt32(a) && + (!v.isInt32() || v.toInt32() != 0) && + (!v.isDouble() || v.toDouble() != 0) && + -v.toNumber() == (int)-v.toNumber()) + { + VMSideExit* exit = snapshot(OVERFLOW_EXIT); + a = guard_xov(LIR_subi, w.immi(0), w.demoteToInt32(a), exit); + if (!a->isImmI() && a->isop(LIR_subxovi)) { + guard(false, w.eqiN(a, 0), exit); // make sure we don't lose a -0 + } + a = w.i2d(a); + } else { + a = w.negd(a); + } + + set(&v, a); + return ARECORD_CONTINUE; + } + + if (v.isNull()) { + set(&v, w.immd(-0.0)); + return ARECORD_CONTINUE; + } + + if (v.isUndefined()) { + set(&v, w.immd(js_NaN)); + return ARECORD_CONTINUE; + } + + if (v.isString()) { + LIns* ok_ins = w.allocp(sizeof(JSBool)); + LIns* args[] = { ok_ins, get(&v), cx_ins }; + LIns* num_ins = w.call(&js_StringToNumber_ci, args); + guard(false, + w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"), + OOM_EXIT); + set(&v, w.negd(num_ins)); + return ARECORD_CONTINUE; + } + + JS_ASSERT(v.isBoolean()); + set(&v, w.negd(w.i2d(get(&v)))); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_POS() +{ + Value& v = stackval(-1); + + if (!v.isPrimitive()) { + CHECK_STATUS_A(guardNativeConversion(v)); + return InjectStatus(callImacro(unary_imacros.sign)); + } + + if (v.isNumber()) + return ARECORD_CONTINUE; + + if (v.isNull()) { + set(&v, w.immd(0)); + return ARECORD_CONTINUE; + } + if (v.isUndefined()) { + set(&v, w.immd(js_NaN)); + return ARECORD_CONTINUE; + } + + if (v.isString()) { + LIns* ok_ins = w.allocp(sizeof(JSBool)); + LIns* args[] = { ok_ins, get(&v), cx_ins }; + LIns* num_ins = w.call(&js_StringToNumber_ci, args); + guard(false, + w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"), + OOM_EXIT); + set(&v, num_ins); + return ARECORD_CONTINUE; + } + + JS_ASSERT(v.isBoolean()); + set(&v, w.i2d(get(&v))); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_PRIMTOP() +{ + // Either this opcode does nothing or we couldn't have traced here, because + // we'd have thrown an exception -- so do nothing if we actually hit this. + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_OBJTOP() +{ + Value& v = stackval(-1); + RETURN_IF_XML_A(v); + return ARECORD_CONTINUE; +} + +RecordingStatus +TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins) +{ + // ctor must be a function created via js_InitClass. +#ifdef DEBUG + Class *clasp = FUN_CLASP(GET_FUNCTION_PRIVATE(cx, ctor)); + JS_ASSERT(clasp); + + TraceMonitor &localtm = *traceMonitor; +#endif + + Value pval; + if (!ctor->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &pval)) + RETURN_ERROR("error getting prototype from constructor"); + + // ctor.prototype is a permanent data property, so this lookup cannot have + // deep-aborted. + JS_ASSERT(localtm.recorder); + +#ifdef DEBUG + JSBool ok, found; + uintN attrs; + ok = JS_GetPropertyAttributes(cx, ctor, js_class_prototype_str, &attrs, &found); + JS_ASSERT(ok); + JS_ASSERT(found); + JS_ASSERT((~attrs & (JSPROP_READONLY | JSPROP_PERMANENT)) == 0); +#endif + + // Since ctor was built by js_InitClass, we can assert (rather than check) + // that pval is usable. + JS_ASSERT(!pval.isPrimitive()); + JSObject *proto = &pval.toObject(); + JS_ASSERT_IF(clasp != &js_ArrayClass, proto->emptyShapes[0]->getClass() == clasp); + + proto_ins = w.immpObjGC(proto); + return RECORD_CONTINUE; +} + +RecordingStatus +TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins) +{ +#ifdef DEBUG + TraceMonitor &localtm = *traceMonitor; +#endif + + JSObject* proto; + if (!js_GetClassPrototype(cx, globalObj, key, &proto)) + RETURN_ERROR("error in js_GetClassPrototype"); + + // This should not have reentered. + JS_ASSERT(localtm.recorder); + +#ifdef DEBUG + /* Double-check that a native proto has a matching emptyShape. */ + if (key != JSProto_Array) { + JS_ASSERT(proto->isNative()); + JS_ASSERT(proto->emptyShapes); + EmptyShape *empty = proto->emptyShapes[0]; + JS_ASSERT(empty); + JS_ASSERT(JSCLASS_CACHED_PROTO_KEY(empty->getClass()) == key); + } +#endif + + proto_ins = w.immpObjGC(proto); + return RECORD_CONTINUE; +} + +#define IGNORE_NATIVE_CALL_COMPLETE_CALLBACK ((JSSpecializedNative*)1) + +RecordingStatus +TraceRecorder::newString(JSObject* ctor, uint32 argc, Value* argv, Value* rval) +{ + JS_ASSERT(argc == 1); + + if (!argv[0].isPrimitive()) { + CHECK_STATUS(guardNativeConversion(argv[0])); + return callImacro(new_imacros.String); + } + + LIns* proto_ins; + CHECK_STATUS(getClassPrototype(ctor, proto_ins)); + + LIns* args[] = { stringify(argv[0]), proto_ins, cx_ins }; + LIns* obj_ins = w.call(&js_String_tn_ci, args); + guard(false, w.eqp0(obj_ins), OOM_EXIT); + + set(rval, obj_ins); + pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK; + return RECORD_CONTINUE; +} + +RecordingStatus +TraceRecorder::newArray(JSObject* ctor, uint32 argc, Value* argv, Value* rval) +{ + LIns *proto_ins; + CHECK_STATUS(getClassPrototype(ctor, proto_ins)); + + LIns *arr_ins; + if (argc == 0) { + LIns *args[] = { proto_ins, cx_ins }; + arr_ins = w.call(&js::NewDenseEmptyArray_ci, args); + guard(false, w.eqp0(arr_ins), OOM_EXIT); + + } else if (argc == 1 && argv[0].isNumber()) { + /* Abort on RangeError if the double doesn't fit in a uint. */ + LIns *len_ins; + CHECK_STATUS(makeNumberUint32(get(argv), &len_ins)); + LIns *args[] = { proto_ins, len_ins, cx_ins }; + arr_ins = w.call(&js::NewDenseUnallocatedArray_ci, args); + guard(false, w.eqp0(arr_ins), OOM_EXIT); + + } else { + LIns *args[] = { proto_ins, w.nameImmi(argc), cx_ins }; + arr_ins = w.call(&js::NewDenseAllocatedArray_ci, args); + guard(false, w.eqp0(arr_ins), OOM_EXIT); + + // arr->slots[i] = box_jsval(vp[i]); for i in 0..argc + LIns *slots_ins = NULL; + for (uint32 i = 0; i < argc && !outOfMemory(); i++) { + stobj_set_dslot(arr_ins, i, slots_ins, argv[i], get(&argv[i])); + } + } + + set(rval, arr_ins); + pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK; + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK void +TraceRecorder::propagateFailureToBuiltinStatus(LIns* ok_ins, LIns*& status_ins) +{ + /* + * Check the boolean return value (ok_ins) of a native JSNative, + * JSFastNative, or JSPropertyOp hook for failure. On failure, set the + * BUILTIN_ERROR bit of cx->builtinStatus. + * + * If the return value (ok_ins) is true, status' == status. Otherwise + * status' = status | BUILTIN_ERROR. We calculate (rval&1)^1, which is 1 + * if rval is JS_FALSE (error), and then shift that by 1, which is the log2 + * of BUILTIN_ERROR. + */ + JS_STATIC_ASSERT(((JS_TRUE & 1) ^ 1) << 1 == 0); + JS_STATIC_ASSERT(((JS_FALSE & 1) ^ 1) << 1 == BUILTIN_ERROR); + status_ins = w.ori(status_ins, w.lshiN(w.xoriN(w.andiN(ok_ins, 1), 1), 1)); + w.stStateField(status_ins, builtinStatus); +} + +JS_REQUIRES_STACK void +TraceRecorder::emitNativePropertyOp(const Shape* shape, LIns* obj_ins, + bool setflag, LIns* addr_boxed_val_ins) +{ + JS_ASSERT(addr_boxed_val_ins->isop(LIR_allocp)); + JS_ASSERT(setflag ? !shape->hasSetterValue() : !shape->hasGetterValue()); + JS_ASSERT(setflag ? !shape->hasDefaultSetter() : !shape->hasDefaultGetterOrIsMethod()); + + enterDeepBailCall(); + + w.stStateField(addr_boxed_val_ins, nativeVp); + w.stStateField(w.immi(1), nativeVpLen); + + CallInfo* ci = new (traceAlloc()) CallInfo(); + /* Setters and getters have their initial arguments in common. */ + LIns* possibleArgs[] = { NULL, NULL, w.immpIdGC(SHAPE_USERID(shape)), obj_ins, cx_ins }; + LIns** args; + if (setflag) { + ci->_address = uintptr_t(shape->setterOp()); + ci->_typesig = CallInfo::typeSig5(ARGTYPE_I, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_B, + ARGTYPE_P); + possibleArgs[0] = addr_boxed_val_ins; + possibleArgs[1] = strictModeCode_ins; + args = possibleArgs; + } else { + ci->_address = uintptr_t(shape->getterOp()); + ci->_typesig = CallInfo::typeSig4(ARGTYPE_I, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P); + possibleArgs[1] = addr_boxed_val_ins; + args = possibleArgs + 1; + } + ci->_isPure = 0; + ci->_storeAccSet = ACCSET_STORE_ANY; + ci->_abi = ABI_CDECL; +#ifdef DEBUG + ci->_name = "JSPropertyOp"; +#endif + LIns* ok_ins = w.call(ci, args); + + // Cleanup. Immediately clear nativeVp before we might deep bail. + w.stStateField(w.immpNull(), nativeVp); + leaveDeepBailCall(); + + // Guard that the call succeeded and builtinStatus is still 0. + // If the native op succeeds but we deep-bail here, the result value is + // lost! Therefore this can only be used for setters of shared properties. + // In that case we ignore the result value anyway. + LIns* status_ins = w.ldiStateField(builtinStatus); + propagateFailureToBuiltinStatus(ok_ins, status_ins); + guard(true, w.eqi0(status_ins), STATUS_EXIT); +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::emitNativeCall(JSSpecializedNative* sn, uintN argc, LIns* args[], bool rooted) +{ + if (JSTN_ERRTYPE(sn) == FAIL_STATUS) { + // This needs to capture the pre-call state of the stack. So do not set + // pendingSpecializedNative before taking this snapshot. + JS_ASSERT(!pendingSpecializedNative); + + // Take snapshot for DeepBail and store it in tm->bailExit. + enterDeepBailCall(); + } + + LIns* res_ins = w.call(sn->builtin, args); + + // Immediately unroot the vp as soon we return since we might deep bail next. + if (rooted) + w.stStateField(w.immpNull(), nativeVp); + + rval_ins = res_ins; + switch (JSTN_ERRTYPE(sn)) { + case FAIL_NULL: + guard(false, w.eqp0(res_ins), OOM_EXIT); + break; + case FAIL_NEG: + res_ins = w.i2d(res_ins); + guard(false, w.ltdN(res_ins, 0), OOM_EXIT); + break; + case FAIL_NEITHER: + guard(false, w.eqiN(res_ins, JS_NEITHER), OOM_EXIT); + break; + default:; + } + + set(&stackval(0 - (2 + argc)), res_ins); + + /* + * The return value will be processed by NativeCallComplete since + * we have to know the actual return value type for calls that return + * jsval. + */ + pendingSpecializedNative = sn; + + return RECORD_CONTINUE; +} + +/* + * Check whether we have a specialized implementation for this native + * invocation. + */ +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::callSpecializedNative(JSNativeTraceInfo *trcinfo, uintN argc, + bool constructing) +{ + JSStackFrame* const fp = cx->fp(); + jsbytecode *pc = cx->regs->pc; + + Value& fval = stackval(0 - (2 + argc)); + Value& tval = stackval(0 - (1 + argc)); + + LIns* this_ins = get(&tval); + + LIns* args[nanojit::MAXARGS]; + JSSpecializedNative *sn = trcinfo->specializations; + JS_ASSERT(sn); + do { + if (((sn->flags & JSTN_CONSTRUCTOR) != 0) != constructing) + continue; + + uintN knownargc = strlen(sn->argtypes); + if (argc != knownargc) + continue; + + intN prefixc = strlen(sn->prefix); + JS_ASSERT(prefixc <= 3); + LIns** argp = &args[argc + prefixc - 1]; + char argtype; + +#if defined DEBUG + memset(args, 0xCD, sizeof(args)); +#endif + + uintN i; + for (i = prefixc; i--; ) { + argtype = sn->prefix[i]; + if (argtype == 'C') { + *argp = cx_ins; + } else if (argtype == 'T') { /* this, as an object */ + if (tval.isPrimitive()) + goto next_specialization; + *argp = this_ins; + } else if (argtype == 'S') { /* this, as a string */ + if (!tval.isString()) + goto next_specialization; + *argp = this_ins; + } else if (argtype == 'f') { + *argp = w.immpObjGC(&fval.toObject()); + } else if (argtype == 'p') { + CHECK_STATUS(getClassPrototype(&fval.toObject(), *argp)); + } else if (argtype == 'R') { + *argp = w.nameImmpNonGC(cx->runtime); + } else if (argtype == 'P') { + // FIXME: Set pc to imacpc when recording JSOP_CALL inside the + // JSOP_GETELEM imacro (bug 476559). + if ((*pc == JSOP_CALL) && + fp->hasImacropc() && *fp->imacropc() == JSOP_GETELEM) + *argp = w.nameImmpNonGC(fp->imacropc()); + else + *argp = w.nameImmpNonGC(pc); + } else if (argtype == 'D') { /* this, as a number */ + if (!tval.isNumber()) + goto next_specialization; + *argp = this_ins; + } else if (argtype == 'M') { + MathCache *mathCache = GetMathCache(cx); + if (!mathCache) + return RECORD_ERROR; + *argp = w.nameImmpNonGC(mathCache); + } else { + JS_NOT_REACHED("unknown prefix arg type"); + } + argp--; + } + + for (i = knownargc; i--; ) { + Value& arg = stackval(0 - (i + 1)); + *argp = get(&arg); + + argtype = sn->argtypes[i]; + if (argtype == 'd' || argtype == 'i') { + if (!arg.isNumber()) + goto next_specialization; + if (argtype == 'i') + *argp = d2i(*argp); + } else if (argtype == 'o') { + if (arg.isPrimitive()) + goto next_specialization; + } else if (argtype == 's') { + if (!arg.isString()) + goto next_specialization; + } else if (argtype == 'r') { + if (!VALUE_IS_REGEXP(cx, arg)) + goto next_specialization; + } else if (argtype == 'f') { + if (!IsFunctionObject(arg)) + goto next_specialization; + } else if (argtype == 'v') { + *argp = box_value_for_native_call(arg, *argp); + } else { + goto next_specialization; + } + argp--; + } +#if defined DEBUG + JS_ASSERT(args[0] != (LIns *)0xcdcdcdcd); +#endif + return emitNativeCall(sn, argc, args, false); + +next_specialization:; + } while ((sn++)->flags & JSTN_MORE); + + return RECORD_STOP; +} + +static JSBool FASTCALL +ceilReturningInt(jsdouble x, int32 *out) +{ + jsdouble r = js_math_ceil_impl(x); + return JSDOUBLE_IS_INT32(r, out); +} + +static JSBool FASTCALL +floorReturningInt(jsdouble x, int32 *out) +{ + jsdouble r = js_math_floor_impl(x); + return JSDOUBLE_IS_INT32(r, out); +} + +static JSBool FASTCALL +roundReturningInt(jsdouble x, int32 *out) +{ + jsdouble r = js_math_round_impl(x); + return JSDOUBLE_IS_INT32(r, out); +} + +/* + * These functions store into their second argument, so they need to + * be annotated accordingly. To be future-proof, we use ACCSET_STORE_ANY + * so that new callers don't have to remember to update the annotation. + */ +JS_DEFINE_CALLINFO_2(static, BOOL, ceilReturningInt, DOUBLE, INT32PTR, 0, ACCSET_STORE_ANY) +JS_DEFINE_CALLINFO_2(static, BOOL, floorReturningInt, DOUBLE, INT32PTR, 0, ACCSET_STORE_ANY) +JS_DEFINE_CALLINFO_2(static, BOOL, roundReturningInt, DOUBLE, INT32PTR, 0, ACCSET_STORE_ANY) + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::callFloatReturningInt(uintN argc, const nanojit::CallInfo *ci) +{ + Value& arg = stackval(-1); + LIns* resptr_ins = w.allocp(sizeof(int32)); + LIns* args[] = { resptr_ins, get(&arg) }; + LIns* fits_ins = w.call(ci, args); + + guard(false, w.eqi0(fits_ins), OVERFLOW_EXIT); + + LIns* res_ins = w.ldiAlloc(resptr_ins); + + set(&stackval(0 - (2 + argc)), w.i2d(res_ins)); + + pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK; + + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::callNative(uintN argc, JSOp mode) +{ + LIns* args[5]; + + JS_ASSERT(mode == JSOP_CALL || mode == JSOP_NEW || mode == JSOP_FUNAPPLY || + mode == JSOP_FUNCALL); + + Value* vp = &stackval(0 - (2 + argc)); + JSObject* funobj = &vp[0].toObject(); + JSFunction* fun = funobj->getFunctionPrivate(); + JS_ASSERT(fun->isNative()); + Native native = fun->u.n.native; + + switch (argc) { + case 1: + if (vp[2].isNumber() && mode == JSOP_CALL) { + if (native == js_math_ceil || native == js_math_floor || native == js_math_round) { + LIns* a = get(&vp[2]); + int32 result; + if (IsPromotedInt32OrUint32(a)) { + set(&vp[0], a); + pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK; + return RECORD_CONTINUE; + } + if (native == js_math_floor) { + if (floorReturningInt(vp[2].toNumber(), &result)) + return callFloatReturningInt(argc, &floorReturningInt_ci); + } else if (native == js_math_ceil) { + if (ceilReturningInt(vp[2].toNumber(), &result)) + return callFloatReturningInt(argc, &ceilReturningInt_ci); + } else if (native == js_math_round) { + if (roundReturningInt(vp[2].toNumber(), &result)) + return callFloatReturningInt(argc, &roundReturningInt_ci); + } + } else if (native == js_math_abs) { + LIns* a = get(&vp[2]); + if (IsPromotedInt32(a) && vp[2].toNumber() != INT_MIN) { + a = w.demoteToInt32(a); + /* abs(INT_MIN) can't be done using integers; exit if we see it. */ + LIns* intMin_ins = w.name(w.immi(0x80000000), "INT_MIN"); + LIns* isIntMin_ins = w.name(w.eqi(a, intMin_ins), "isIntMin"); + guard(false, isIntMin_ins, MISMATCH_EXIT); + LIns* neg_ins = w.negi(a); + LIns* isNeg_ins = w.name(w.ltiN(a, 0), "isNeg"); + LIns* abs_ins = w.name(w.cmovi(isNeg_ins, neg_ins, a), "abs"); + set(&vp[0], w.i2d(abs_ins)); + pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK; + return RECORD_CONTINUE; + } + } + if (vp[1].isString()) { + JSString *str = vp[1].toString(); + if (native == js_str_charAt) { + jsdouble i = vp[2].toNumber(); + if (JSDOUBLE_IS_NaN(i)) + i = 0; + if (i < 0 || i >= str->length()) + RETURN_STOP("charAt out of bounds"); + LIns* str_ins = get(&vp[1]); + LIns* idx_ins = get(&vp[2]); + LIns* char_ins; + CHECK_STATUS(getCharAt(str, str_ins, idx_ins, mode, &char_ins)); + set(&vp[0], char_ins); + pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK; + return RECORD_CONTINUE; + } else if (native == js_str_charCodeAt) { + jsdouble i = vp[2].toNumber(); + if (JSDOUBLE_IS_NaN(i)) + i = 0; + if (i < 0 || i >= str->length()) + RETURN_STOP("charCodeAt out of bounds"); + LIns* str_ins = get(&vp[1]); + LIns* idx_ins = get(&vp[2]); + LIns* charCode_ins; + CHECK_STATUS(getCharCodeAt(str, str_ins, idx_ins, &charCode_ins)); + set(&vp[0], charCode_ins); + pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK; + return RECORD_CONTINUE; + } + } + } else if (vp[2].isString() && mode == JSOP_CALL) { + if (native == js_regexp_exec) { + jsbytecode *pc = cx->regs->pc; + /* + * If we see any of these sequences, the result is unused: + * - call / pop + * - call / trace / pop + * + * If we see any of these sequences, the result is only tested for nullness: + * - call / ifeq + * - call / trace / ifeq + * - call / not / ifeq + * - call / trace / not / ifeq + * + * In either case, we replace the call to RegExp.exec() on the + * stack with a call to RegExp.test() because "r.exec(s) != + * null" is equivalent to "r.test(s)". This avoids building + * the result array, which can be expensive. This requires + * that RegExp.prototype.test() hasn't been changed; we check this. + */ + if (pc[0] == JSOP_CALL) { + if ((pc[JSOP_CALL_LENGTH] == JSOP_POP) || + (pc[JSOP_CALL_LENGTH] == JSOP_TRACE && + pc[JSOP_CALL_LENGTH + JSOP_TRACE_LENGTH] == JSOP_POP) || + (pc[JSOP_CALL_LENGTH] == JSOP_IFEQ) || + (pc[JSOP_CALL_LENGTH] == JSOP_TRACE && + pc[JSOP_CALL_LENGTH + JSOP_TRACE_LENGTH] == JSOP_IFEQ) || + (pc[JSOP_CALL_LENGTH] == JSOP_NOT && + pc[JSOP_CALL_LENGTH + JSOP_NOT_LENGTH] == JSOP_IFEQ) || + (pc[JSOP_CALL_LENGTH] == JSOP_TRACE && + pc[JSOP_CALL_LENGTH + JSOP_TRACE_LENGTH] == JSOP_NOT && + pc[JSOP_CALL_LENGTH + JSOP_TRACE_LENGTH + JSOP_NOT_LENGTH] == JSOP_IFEQ)) + { + JSObject* proto; + jsid id = ATOM_TO_JSID(cx->runtime->atomState.testAtom); + /* Get RegExp.prototype.test() and check it hasn't been changed. */ + if (js_GetClassPrototype(cx, NULL, JSProto_RegExp, &proto)) { + if (JSObject *tmp = HasNativeMethod(proto, id, js_regexp_test)) { + vp[0] = ObjectValue(*tmp); + funobj = tmp; + fun = tmp->getFunctionPrivate(); + native = js_regexp_test; + } + } + } + } + } + } + break; + + case 2: + if (vp[2].isNumber() && vp[3].isNumber() && mode == JSOP_CALL && + (native == js_math_min || native == js_math_max)) { + LIns* a = get(&vp[2]); + LIns* b = get(&vp[3]); + if (IsPromotedInt32(a) && IsPromotedInt32(b)) { + a = w.demoteToInt32(a); + b = w.demoteToInt32(b); + LIns* cmp = (native == js_math_min) ? w.lti(a, b) : w.gti(a, b); + set(&vp[0], w.i2d(w.cmovi(cmp, a, b))); + pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK; + return RECORD_CONTINUE; + } + if (IsPromotedUint32(a) && IsPromotedUint32(b)) { + a = w.demoteToUint32(a); + b = w.demoteToUint32(b); + LIns* cmp = (native == js_math_min) ? w.ltui(a, b) : w.gtui(a, b); + set(&vp[0], w.ui2d(w.cmovi(cmp, a, b))); + pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK; + return RECORD_CONTINUE; + } + } + break; + } + + if (fun->flags & JSFUN_TRCINFO) { + JSNativeTraceInfo *trcinfo = FUN_TRCINFO(fun); + JS_ASSERT(trcinfo && fun->u.n.native == trcinfo->native); + + /* Try to call a type specialized version of the native. */ + if (trcinfo->specializations) { + RecordingStatus status = callSpecializedNative(trcinfo, argc, mode == JSOP_NEW); + if (status != RECORD_STOP) + return status; + } + } + + if (native == js_fun_apply || native == js_fun_call) + RETURN_STOP("trying to call native apply or call"); + + // Allocate the vp vector and emit code to root it. + uintN vplen = 2 + argc; + LIns* invokevp_ins = w.allocp(vplen * sizeof(Value)); + + // vp[0] is the callee. + box_value_into(vp[0], w.immpObjGC(funobj), AllocSlotsAddress(invokevp_ins)); + + // Calculate |this|. + LIns* this_ins; + if (mode == JSOP_NEW) { + Class* clasp = fun->u.n.clasp; + JS_ASSERT(clasp != &js_SlowArrayClass); + if (!clasp) + clasp = &js_ObjectClass; + JS_ASSERT(((jsuword) clasp & 3) == 0); + + // Abort on |new Function|. (FIXME: This restriction might not + // unnecessary now that the constructor creates the new function object + // itself.) + if (clasp == &js_FunctionClass) + RETURN_STOP("new Function"); + + if (!clasp->isNative()) + RETURN_STOP("new with non-native ops"); + + // Don't trace |new Math.sin(0)|. + if (!fun->isConstructor()) + RETURN_STOP("new with non-constructor native function"); + + vp[1].setMagicWithObjectOrNullPayload(NULL); + newobj_ins = w.immpMagicNull(); + + /* Treat this as a regular call, the constructor will behave correctly. */ + mode = JSOP_CALL; + this_ins = newobj_ins; + } else { + this_ins = get(&vp[1]); + } + set(&vp[1], this_ins); + box_value_into(vp[1], this_ins, AllocSlotsAddress(invokevp_ins, 1)); + + // Populate argv. + for (uintN n = 2; n < 2 + argc; n++) { + box_value_into(vp[n], get(&vp[n]), AllocSlotsAddress(invokevp_ins, n)); + // For a very long argument list we might run out of LIR space, so + // check inside the loop. + if (outOfMemory()) + RETURN_STOP("out of memory in argument list"); + } + + // Populate extra slots, including the return value slot for a slow native. + if (2 + argc < vplen) { + for (uintN n = 2 + argc; n < vplen; n++) { + box_undefined_into(AllocSlotsAddress(invokevp_ins, n)); + if (outOfMemory()) + RETURN_STOP("out of memory in extra slots"); + } + } + + // Set up arguments for the JSNative or JSFastNative. + if (mode == JSOP_NEW) + RETURN_STOP("untraceable fast native constructor"); + native_rval_ins = invokevp_ins; + args[0] = invokevp_ins; + args[1] = w.immi(argc); + args[2] = cx_ins; + uint32 typesig = CallInfo::typeSig3(ARGTYPE_I, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P); + + // Generate CallInfo and a JSSpecializedNative structure on the fly. + // Do not use JSTN_UNBOX_AFTER for mode JSOP_NEW because + // record_NativeCallComplete unboxes the result specially. + + CallInfo* ci = new (traceAlloc()) CallInfo(); + ci->_address = uintptr_t(fun->u.n.native); + ci->_isPure = 0; + ci->_storeAccSet = ACCSET_STORE_ANY; + ci->_abi = ABI_CDECL; + ci->_typesig = typesig; +#ifdef DEBUG + ci->_name = js_anonymous_str; + if (fun->atom) { + JSAutoByteString bytes(cx, ATOM_TO_STRING(fun->atom)); + if (!!bytes) { + size_t n = strlen(bytes.ptr()) + 1; + char *buffer = new (traceAlloc()) char[n]; + memcpy(buffer, bytes.ptr(), n); + ci->_name = buffer; + } + } + #endif + + // Generate a JSSpecializedNative structure on the fly. + generatedSpecializedNative.builtin = ci; + generatedSpecializedNative.flags = FAIL_STATUS | ((mode == JSOP_NEW) + ? JSTN_CONSTRUCTOR + : JSTN_UNBOX_AFTER); + generatedSpecializedNative.prefix = NULL; + generatedSpecializedNative.argtypes = NULL; + + // We only have to ensure that the values we wrote into the stack buffer + // are rooted if we actually make it to the call, so only set nativeVp and + // nativeVpLen immediately before emitting the call code. This way we avoid + // leaving trace with a bogus nativeVp because we fall off trace while unboxing + // values into the stack buffer. + w.stStateField(w.nameImmi(vplen), nativeVpLen); + w.stStateField(invokevp_ins, nativeVp); + + // argc is the original argc here. It is used to calculate where to place + // the return value. + return emitNativeCall(&generatedSpecializedNative, argc, args, true); +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::functionCall(uintN argc, JSOp mode) +{ + Value& fval = stackval(0 - (2 + argc)); + JS_ASSERT(&fval >= cx->fp()->base()); + + if (!IsFunctionObject(fval)) + RETURN_STOP("callee is not a function"); + + Value& tval = stackval(0 - (1 + argc)); + + /* + * If callee is not constant, it's a shapeless call and we have to guard + * explicitly that we will get this callee again at runtime. + */ + if (!get(&fval)->isImmP()) + CHECK_STATUS(guardCallee(fval)); + + /* + * Require that the callee be a function object, to avoid guarding on its + * class here. We know if the callee and this were pushed by JSOP_CALLNAME + * or JSOP_CALLPROP that callee is a *particular* function, since these hit + * the property cache and guard on the object (this) in which the callee + * was found. So it's sufficient to test here that the particular function + * is interpreted, not guard on that condition. + * + * Bytecode sequences that push shapeless callees must guard on the callee + * class being Function and the function being interpreted. + */ + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, &fval.toObject()); + + if (Probes::callTrackingActive(cx)) { + JSScript *script = FUN_SCRIPT(fun); + if (!script || !script->isEmpty()) { + LIns* args[] = { w.immi(1), w.nameImmpNonGC(fun), cx_ins }; + LIns* call_ins = w.call(&functionProbe_ci, args); + guard(false, w.eqi0(call_ins), MISMATCH_EXIT); + } + } + + if (FUN_INTERPRETED(fun)) + return interpretedFunctionCall(fval, fun, argc, mode == JSOP_NEW); + + Native native = fun->maybeNative(); + Value* argv = &tval + 1; + if (native == js_Array) + return newArray(&fval.toObject(), argc, argv, &fval); + if (native == js_String && argc == 1) { + if (mode == JSOP_NEW) + return newString(&fval.toObject(), 1, argv, &fval); + if (!argv[0].isPrimitive()) { + CHECK_STATUS(guardNativeConversion(argv[0])); + return callImacro(call_imacros.String); + } + set(&fval, stringify(argv[0])); + pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK; + return RECORD_CONTINUE; + } + + RecordingStatus rs = callNative(argc, mode); + if (Probes::callTrackingActive(cx)) { + LIns* args[] = { w.immi(0), w.nameImmpNonGC(fun), cx_ins }; + LIns* call_ins = w.call(&functionProbe_ci, args); + guard(false, w.eqi0(call_ins), MISMATCH_EXIT); + } + return rs; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_NEW() +{ + uintN argc = GET_ARGC(cx->regs->pc); + cx->assertValidStackDepth(argc + 2); + return InjectStatus(functionCall(argc, JSOP_NEW)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DELNAME() +{ + return ARECORD_STOP; +} + +static JSBool JS_FASTCALL +DeleteIntKey(JSContext* cx, JSObject* obj, int32 i, JSBool strict) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + LeaveTraceIfGlobalObject(cx, obj); + LeaveTraceIfArgumentsObject(cx, obj); + Value v = BooleanValue(false); + jsid id; + if (INT_FITS_IN_JSID(i)) { + id = INT_TO_JSID(i); + } else { + if (!js_ValueToStringId(cx, Int32Value(i), &id)) { + SetBuiltinError(tm); + return false; + } + } + + if (!obj->deleteProperty(cx, id, &v, strict)) + SetBuiltinError(tm); + return v.toBoolean(); +} +JS_DEFINE_CALLINFO_4(extern, BOOL_FAIL, DeleteIntKey, CONTEXT, OBJECT, INT32, BOOL, + 0, ACCSET_STORE_ANY) + +static JSBool JS_FASTCALL +DeleteStrKey(JSContext* cx, JSObject* obj, JSString* str, JSBool strict) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + LeaveTraceIfGlobalObject(cx, obj); + LeaveTraceIfArgumentsObject(cx, obj); + Value v = BooleanValue(false); + jsid id; + + /* + * NB: JSOP_DELPROP does not need js_ValueToStringId to atomize, but (see + * jsatominlines.h) that helper early-returns if the computed property name + * string is already atomized, and we are *not* on a perf-critical path! + */ + if (!js_ValueToStringId(cx, StringValue(str), &id) || !obj->deleteProperty(cx, id, &v, strict)) + SetBuiltinError(tm); + return v.toBoolean(); +} +JS_DEFINE_CALLINFO_4(extern, BOOL_FAIL, DeleteStrKey, CONTEXT, OBJECT, STRING, BOOL, + 0, ACCSET_STORE_ANY) + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DELPROP() +{ + Value& lval = stackval(-1); + if (lval.isPrimitive()) + RETURN_STOP_A("JSOP_DELPROP on primitive base expression"); + if (&lval.toObject() == globalObj) + RETURN_STOP_A("JSOP_DELPROP on global property"); + + JSAtom* atom = atoms[GET_INDEX(cx->regs->pc)]; + + enterDeepBailCall(); + LIns* args[] = { strictModeCode_ins, w.immpAtomGC(atom), get(&lval), cx_ins }; + LIns* rval_ins = w.call(&DeleteStrKey_ci, args); + + LIns* status_ins = w.ldiStateField(builtinStatus); + pendingGuardCondition = w.eqi0(status_ins); + leaveDeepBailCall(); + + set(&lval, rval_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DELELEM() +{ + Value& lval = stackval(-2); + if (lval.isPrimitive()) + RETURN_STOP_A("JSOP_DELELEM on primitive base expression"); + if (&lval.toObject() == globalObj) + RETURN_STOP_A("JSOP_DELELEM on global property"); + if (lval.toObject().isArguments()) + RETURN_STOP_A("JSOP_DELELEM on the |arguments| object"); + + Value& idx = stackval(-1); + LIns* rval_ins; + + enterDeepBailCall(); + if (hasInt32Repr(idx)) { + LIns* num_ins; + CHECK_STATUS_A(makeNumberInt32(get(&idx), &num_ins)); + LIns* args[] = { strictModeCode_ins, num_ins, get(&lval), cx_ins }; + rval_ins = w.call(&DeleteIntKey_ci, args); + } else if (idx.isString()) { + LIns* args[] = { strictModeCode_ins, get(&idx), get(&lval), cx_ins }; + rval_ins = w.call(&DeleteStrKey_ci, args); + } else { + RETURN_STOP_A("JSOP_DELELEM on non-int, non-string index"); + } + + LIns* status_ins = w.ldiStateField(builtinStatus); + pendingGuardCondition = w.eqi0(status_ins); + leaveDeepBailCall(); + + set(&lval, rval_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_TYPEOF() +{ + Value& r = stackval(-1); + LIns* type; + if (r.isString()) { + type = w.immpAtomGC(cx->runtime->atomState.typeAtoms[JSTYPE_STRING]); + } else if (r.isNumber()) { + type = w.immpAtomGC(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]); + } else if (r.isUndefined()) { + type = w.immpAtomGC(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + } else if (r.isBoolean()) { + type = w.immpAtomGC(cx->runtime->atomState.typeAtoms[JSTYPE_BOOLEAN]); + } else if (r.isNull()) { + type = w.immpAtomGC(cx->runtime->atomState.typeAtoms[JSTYPE_OBJECT]); + } else { + if (r.toObject().isFunction()) { + type = w.immpAtomGC(cx->runtime->atomState.typeAtoms[JSTYPE_FUNCTION]); + } else { + LIns* args[] = { get(&r), cx_ins }; + type = w.call(&js_TypeOfObject_ci, args); + } + } + set(&r, type); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_VOID() +{ + stack(-1, w.immiUndefined()); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INCNAME() +{ + return incName(1); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INCPROP() +{ + return incProp(1); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INCELEM() +{ + return InjectStatus(incElem(1)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DECNAME() +{ + return incName(-1); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DECPROP() +{ + return incProp(-1); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DECELEM() +{ + return InjectStatus(incElem(-1)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::incName(jsint incr, bool pre) +{ + Value* vp; + LIns* v_ins; + LIns* v_ins_after; + NameResult nr; + + CHECK_STATUS_A(name(vp, v_ins, nr)); + Value v = nr.tracked ? *vp : nr.v; + Value v_after; + CHECK_STATUS_A(incHelper(v, v_ins, v_after, v_ins_after, incr)); + LIns* v_ins_result = pre ? v_ins_after : v_ins; + if (nr.tracked) { + set(vp, v_ins_after); + stack(0, v_ins_result); + return ARECORD_CONTINUE; + } + + if (!nr.obj->isCall()) + RETURN_STOP_A("incName on unsupported object class"); + + CHECK_STATUS_A(setCallProp(nr.obj, nr.obj_ins, nr.shape, v_ins_after, v_after)); + stack(0, v_ins_result); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_NAMEINC() +{ + return incName(1, false); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_PROPINC() +{ + return incProp(1, false); +} + +// XXX consolidate with record_JSOP_GETELEM code... +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ELEMINC() +{ + return InjectStatus(incElem(1, false)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_NAMEDEC() +{ + return incName(-1, false); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_PROPDEC() +{ + return incProp(-1, false); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ELEMDEC() +{ + return InjectStatus(incElem(-1, false)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GETPROP() +{ + return getProp(stackval(-1)); +} + +/* + * If possible, lookup obj[id] without calling any resolve hooks or touching + * any non-native objects, store the results in *pobjp and *shapep (NULL if no + * such property exists), and return true. + * + * If a safe lookup is not possible, return false; *pobjp and *shapep are + * undefined. + */ +static bool +SafeLookup(JSContext *cx, JSObject* obj, jsid id, JSObject** pobjp, const Shape** shapep) +{ + do { + // Avoid non-native lookupProperty hooks. + if (obj->getOps()->lookupProperty) + return false; + + if (const Shape *shape = obj->nativeLookup(id)) { + *pobjp = obj; + *shapep = shape; + return true; + } + + // Avoid resolve hooks. + if (obj->getClass()->resolve != JS_ResolveStub) + return false; + } while ((obj = obj->getProto()) != NULL); + *pobjp = NULL; + *shapep = NULL; + return true; +} + +/* + * Lookup the property for the SETPROP/SETNAME/SETMETHOD instruction at pc. + * Emit guards to ensure that the result at run time is the same. + */ +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::lookupForSetPropertyOp(JSObject* obj, LIns* obj_ins, jsid id, + bool* safep, JSObject** pobjp, const Shape** shapep) +{ + // We could consult the property cache here, but the contract for + // PropertyCache::testForSet is intricate enough that it's a lot less code + // to do a SafeLookup. + *safep = SafeLookup(cx, obj, id, pobjp, shapep); + if (!*safep) + return RECORD_CONTINUE; + + VMSideExit *exit = snapshot(BRANCH_EXIT); + if (*shapep) { + CHECK_STATUS(guardShape(obj_ins, obj, obj->shape(), "guard_kshape", exit)); + if (obj != *pobjp && *pobjp != globalObj) { + CHECK_STATUS(guardShape(w.immpObjGC(*pobjp), *pobjp, (*pobjp)->shape(), + "guard_vshape", exit)); + } + } else { + for (;;) { + if (obj != globalObj) + CHECK_STATUS(guardShape(obj_ins, obj, obj->shape(), "guard_proto_chain", exit)); + obj = obj->getProto(); + if (!obj) + break; + obj_ins = w.immpObjGC(obj); + } + } + return RECORD_CONTINUE; +} + +static JSBool FASTCALL +MethodWriteBarrier(JSContext* cx, JSObject* obj, uint32 slot, const Value* v) +{ +#ifdef DEBUG + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); +#endif + + bool ok = obj->methodWriteBarrier(cx, slot, *v); + JS_ASSERT(WasBuiltinSuccessful(tm)); + return ok; +} +JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, MethodWriteBarrier, CONTEXT, OBJECT, UINT32, CVALUEPTR, + 0, ACCSET_STORE_ANY) + +/* Emit a specialized, inlined copy of js_NativeSet. */ +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, const Shape* shape, + const Value &v, LIns* v_ins) +{ + uint32 slot = shape->slot; + JS_ASSERT((slot != SHAPE_INVALID_SLOT) == shape->hasSlot()); + JS_ASSERT_IF(shape->hasSlot(), obj->nativeContains(*shape)); + + /* + * We do not trace assignment to properties that have both a non-default + * setter and a slot, for several reasons. + * + * First, that would require sampling rt->propertyRemovals before and after + * (see js_NativeSet), and even more code to handle the case where the two + * samples differ. A mere guard is not enough, because you can't just bail + * off trace in the middle of a property assignment without storing the + * value and making the stack right. + * + * If obj is the global object, there are two additional problems. We would + * have to emit still more code to store the result in the object (not the + * native global frame) if the setter returned successfully after + * deep-bailing. And we would have to cope if the run-time type of the + * setter's return value differed from the record-time type of v, in which + * case unboxing would fail and, having called a native setter, we could + * not just retry the instruction in the interpreter. + * + * If obj is branded, we would have a similar problem recovering from a + * failed call to MethodWriteBarrier. + */ + if (!shape->hasDefaultSetter() && slot != SHAPE_INVALID_SLOT) + RETURN_STOP("can't trace set of property with setter and slot"); + + // These two cases are strict-mode errors and can't be traced. + if (shape->hasGetterValue() && shape->hasDefaultSetter()) + RETURN_STOP("can't set a property that has only a getter"); + if (shape->isDataDescriptor() && !shape->writable()) + RETURN_STOP("can't assign to readonly property"); + + // Call the setter, if any. + if (!shape->hasDefaultSetter()) { + if (shape->hasSetterValue()) + RETURN_STOP("can't trace JavaScript function setter yet"); + emitNativePropertyOp(shape, obj_ins, true, box_value_into_alloc(v, v_ins)); + } + + if (slot != SHAPE_INVALID_SLOT) { + if (obj->brandedOrHasMethodBarrier()) { + if (obj == globalObj) { + // Because the trace is type-specialized to the global object's + // slots, no run-time check is needed. Avoid recording a global + // shape change, though. + JS_ASSERT(obj->nativeContains(*shape)); + if (IsFunctionObject(obj->getSlot(slot))) + RETURN_STOP("can't trace set of function-valued global property"); + } else { + // Setting a function-valued property might need to rebrand the + // object. Call the method write barrier. Note that even if the + // property is not function-valued now, it might be on trace. + enterDeepBailCall(); + LIns* args[] = {box_value_into_alloc(v, v_ins), w.immi(slot), obj_ins, cx_ins}; + LIns* ok_ins = w.call(&MethodWriteBarrier_ci, args); + guard(false, w.eqi0(ok_ins), OOM_EXIT); + leaveDeepBailCall(); + } + } + + // Store the value. + if (obj == globalObj) { + if (!lazilyImportGlobalSlot(slot)) + RETURN_STOP("lazy import of global slot failed"); + set(&obj->getSlotRef(slot), v_ins); + } else { + LIns* slots_ins = NULL; + stobj_set_slot(obj, obj_ins, slot, slots_ins, v, v_ins); + } + } + + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::addDataProperty(JSObject* obj) +{ + if (!obj->isExtensible()) + RETURN_STOP("assignment adds property to non-extensible object"); + + // If obj is the global, the global shape is about to change. Note also + // that since we do not record this case, SETNAME and SETPROP are identical + // as far as the tracer is concerned. (js_CheckUndeclaredVarAssignment + // distinguishes the two, in the interpreter.) + if (obj == globalObj) + RETURN_STOP("set new property of global object"); // global shape change + + // js_AddProperty does not call the addProperty hook. + Class* clasp = obj->getClass(); + if (clasp->addProperty != Valueify(JS_PropertyStub)) + RETURN_STOP("set new property of object with addProperty hook"); + + // See comment in TR::nativeSet about why we do not support setting a + // property that has both a setter and a slot. + if (clasp->setProperty != Valueify(JS_StrictPropertyStub)) + RETURN_STOP("set new property with setter and slot"); + +#ifdef DEBUG + addPropShapeBefore = obj->lastProperty(); +#endif + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_AddProperty(JSObject *obj) +{ + Value& objv = stackval(-2); + JS_ASSERT(&objv.toObject() == obj); + LIns* obj_ins = get(&objv); + Value& v = stackval(-1); + LIns* v_ins = get(&v); + const Shape* shape = obj->lastProperty(); + + if (!shape->hasDefaultSetter()) { + JS_ASSERT(IsWatchedProperty(cx, shape)); + RETURN_STOP_A("assignment adds property with watchpoint"); + } + +#ifdef DEBUG + JS_ASSERT(addPropShapeBefore); + if (obj->inDictionaryMode()) + JS_ASSERT(shape->previous()->matches(addPropShapeBefore)); + else + JS_ASSERT(shape->previous() == addPropShapeBefore); + JS_ASSERT(shape->isDataDescriptor()); + JS_ASSERT(shape->hasDefaultSetter()); + addPropShapeBefore = NULL; +#endif + + if (obj->inDictionaryMode()) + RETURN_STOP_A("assignment adds property to dictionary"); // FIXME: bug 625900 + + // On trace, call js_Add{,Atom}Property to do the dirty work. + LIns* args[] = { w.immpShapeGC(shape), obj_ins, cx_ins }; + jsbytecode op = *cx->regs->pc; + bool isDefinitelyAtom = (op == JSOP_SETPROP); + const CallInfo *ci = isDefinitelyAtom ? &js_AddAtomProperty_ci : &js_AddProperty_ci; + LIns* ok_ins = w.call(ci, args); + guard(false, w.eqi0(ok_ins), OOM_EXIT); + + // Box the value and store it in the new slot. + CHECK_STATUS_A(InjectStatus(nativeSet(obj, obj_ins, shape, v, v_ins))); + + // Finish off a SET instruction by moving sp[-1] to sp[-2]. + if (op == JSOP_SETPROP || op == JSOP_SETNAME || op == JSOP_SETMETHOD) + set(&objv, v_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::setUpwardTrackedVar(Value* stackVp, const Value &v, LIns* v_ins) +{ + JSValueType stackT = determineSlotType(stackVp); + JSValueType otherT = getCoercedType(v); + + bool promote = true; + + if (stackT != otherT) { + if (stackT == JSVAL_TYPE_DOUBLE && otherT == JSVAL_TYPE_INT32 && IsPromotedInt32(v_ins)) + promote = false; + else + RETURN_STOP("can't trace this upvar mutation"); + } + + set(stackVp, v_ins, promote); + + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, const Shape *shape, + LIns *v_ins, const Value &v) +{ + // Set variables in on-trace-stack call objects by updating the tracker. + JSStackFrame *fp = frameIfInRange(callobj); + if (fp) { + if (shape->setterOp() == SetCallArg) { + JS_ASSERT(shape->hasShortID()); + uintN slot = uint16(shape->shortid); + Value *vp2 = &fp->formalArg(slot); + CHECK_STATUS(setUpwardTrackedVar(vp2, v, v_ins)); + return RECORD_CONTINUE; + } + if (shape->setterOp() == SetCallVar) { + JS_ASSERT(shape->hasShortID()); + uintN slot = uint16(shape->shortid); + Value *vp2 = &fp->slots()[slot]; + CHECK_STATUS(setUpwardTrackedVar(vp2, v, v_ins)); + return RECORD_CONTINUE; + } + RETURN_STOP("can't trace special CallClass setter"); + } + + if (!callobj->getPrivate()) { + // Because the parent guard in guardCallee ensures this Call object + // will be the same object now and on trace, and because once a Call + // object loses its frame it never regains one, on trace we will also + // have a null private in the Call object. So all we need to do is + // write the value to the Call object's slot. + intN slot = uint16(shape->shortid); + if (shape->setterOp() == SetCallArg) { + JS_ASSERT(slot < ArgClosureTraits::slot_count(callobj)); + slot += ArgClosureTraits::slot_offset(callobj); + } else if (shape->setterOp() == SetCallVar) { + JS_ASSERT(slot < VarClosureTraits::slot_count(callobj)); + slot += VarClosureTraits::slot_offset(callobj); + } else { + RETURN_STOP("can't trace special CallClass setter"); + } + + // Now assert that the shortid get we did above was ok. Have to do it + // after the RETURN_STOP above, since in that case we may in fact not + // have a valid shortid; but we don't use it in that case anyway. + JS_ASSERT(shape->hasShortID()); + + LIns* slots_ins = NULL; + stobj_set_dslot(callobj_ins, slot, slots_ins, v, v_ins); + return RECORD_CONTINUE; + } + + // This is the hard case: we have a JSStackFrame private, but it's not in + // range. During trace execution we may or may not have a JSStackFrame + // anymore. Call the standard builtins, which handle that situation. + + // Set variables in off-trace-stack call objects by calling standard builtins. + const CallInfo* ci = NULL; + if (shape->setterOp() == SetCallArg) + ci = &js_SetCallArg_ci; + else if (shape->setterOp() == SetCallVar) + ci = &js_SetCallVar_ci; + else + RETURN_STOP("can't trace special CallClass setter"); + + // Even though the frame is out of range, later we might be called as an + // inner trace such that the target variable is defined in the outer trace + // entry frame. For simplicity, we just fall off trace. + guard(false, + w.eqp(entryFrameIns(), w.ldpObjPrivate(callobj_ins)), + MISMATCH_EXIT); + + LIns* args[] = { + box_value_for_native_call(v, v_ins), + w.nameImmw(JSID_BITS(SHAPE_USERID(shape))), + callobj_ins, + cx_ins + }; + LIns* call_ins = w.call(ci, args); + guard(false, w.name(w.eqi0(call_ins), "guard(set upvar)"), STATUS_EXIT); + + return RECORD_CONTINUE; +} + +/* + * Emit a specialized, inlined copy of js_SetPropertyHelper for the current + * instruction. On success, *deferredp is true if a call to record_AddProperty + * is expected. + */ +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::setProperty(JSObject* obj, LIns* obj_ins, const Value &v, LIns* v_ins, + bool* deferredp) +{ + *deferredp = false; + + JSAtom *atom = atoms[GET_INDEX(cx->regs->pc)]; + jsid id = ATOM_TO_JSID(atom); + + if (obj->getOps()->setProperty) + RETURN_STOP("non-native object"); // FIXME: bug 625900 + + bool safe; + JSObject* pobj; + const Shape* shape; + CHECK_STATUS(lookupForSetPropertyOp(obj, obj_ins, id, &safe, &pobj, &shape)); + if (!safe) + RETURN_STOP("setprop: lookup fail"); // FIXME: bug 625900 + + // Handle Call objects specially. The Call objects we create on trace are + // not fully populated until we leave trace. Calling the setter on such an + // object wouldn't work. + if (obj->isCall()) + return setCallProp(obj, obj_ins, shape, v_ins, v); + + // Handle setting a property that is not found on obj or anywhere on its + // the prototype chain. + if (!shape) { + *deferredp = true; + return addDataProperty(obj); + } + + // Check whether we can assign to/over the existing property. + if (shape->isAccessorDescriptor()) { + if (shape->hasDefaultSetter()) + RETURN_STOP("setting accessor property with no setter"); + } else if (!shape->writable()) { + RETURN_STOP("setting readonly data property"); + } + + // Handle setting an existing own property. + if (pobj == obj) { + if (*cx->regs->pc == JSOP_SETMETHOD) { + if (shape->isMethod() && &shape->methodObject() == &v.toObject()) + return RECORD_CONTINUE; + RETURN_STOP("setmethod: property exists"); + } + return nativeSet(obj, obj_ins, shape, v, v_ins); + } + + // If shape is an inherited non-SHARED property, we will add a new, + // shadowing data property. + if (shape->hasSlot()) { + // Avoid being tripped up by legacy special case for shortids, where + // the new shadowing data property inherits the setter. + if (shape->hasShortID() && !shape->hasDefaultSetter()) + RETURN_STOP("shadowing assignment with shortid"); + *deferredp = true; + return addDataProperty(obj); + } + + // Handle setting an inherited SHARED property. + // If it has the default setter, the assignment is a no-op. + if (shape->hasDefaultSetter() && !shape->hasGetterValue()) + return RECORD_CONTINUE; + return nativeSet(obj, obj_ins, shape, v, v_ins); +} + +/* Record a JSOP_SET{PROP,NAME,METHOD} instruction. */ +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::recordSetPropertyOp() +{ + Value& l = stackval(-2); + if (!l.isObject()) + RETURN_STOP("set property of primitive"); + JSObject* obj = &l.toObject(); + LIns* obj_ins = get(&l); + + Value& r = stackval(-1); + LIns* r_ins = get(&r); + + bool deferred; + CHECK_STATUS(setProperty(obj, obj_ins, r, r_ins, &deferred)); + + // Finish off a SET instruction by moving sp[-1] to sp[-2]. But if + // record_AddProperty is going be called, we're not done with sp[-2] yet, + // so delay this move until the end of record_AddProperty. + if (!deferred) + set(&l, r_ins); + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SETPROP() +{ + return InjectStatus(recordSetPropertyOp()); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SETMETHOD() +{ + return InjectStatus(recordSetPropertyOp()); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SETNAME() +{ + return InjectStatus(recordSetPropertyOp()); +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::recordInitPropertyOp(jsbytecode op) +{ + Value& l = stackval(-2); + JSObject* obj = &l.toObject(); + LIns* obj_ins = get(&l); + JS_ASSERT(obj->getClass() == &js_ObjectClass); + + Value& v = stackval(-1); + LIns* v_ins = get(&v); + + JSAtom* atom = atoms[GET_INDEX(cx->regs->pc)]; + jsid id = js_CheckForStringIndex(ATOM_TO_JSID(atom)); + + // If obj already has this property (because JSOP_NEWOBJECT already set its + // shape or because the id appears more than once in the initializer), just + // set it. The existing property can't be an accessor property: we wouldn't + // get here, as JSOP_SETTER can't be recorded. + if (const Shape* shape = obj->nativeLookup(id)) { + // Don't assign a bare (non-cloned) function to an ordinary or method + // property. The opposite case, assigning some other value to a method, + // is OK. nativeSet emits code that trips the write barrier. + if (op == JSOP_INITMETHOD) + RETURN_STOP("initmethod: property exists"); + JS_ASSERT(shape->isDataDescriptor()); + JS_ASSERT(shape->hasSlot()); + JS_ASSERT(shape->hasDefaultSetter()); + return nativeSet(obj, obj_ins, shape, v, v_ins); + } + + // Duplicate the interpreter's special treatment of __proto__. Unlike the + // SET opcodes, JSOP_INIT{PROP,METHOD} do not write to the stack. + if (atom == cx->runtime->atomState.protoAtom) { + bool deferred; + return setProperty(obj, obj_ins, v, v_ins, &deferred); + } + + // Define a new property. + return addDataProperty(obj); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INITPROP() +{ + return InjectStatus(recordInitPropertyOp(JSOP_INITPROP)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INITMETHOD() +{ + return InjectStatus(recordInitPropertyOp(JSOP_INITMETHOD)); +} + +JS_REQUIRES_STACK VMSideExit* +TraceRecorder::enterDeepBailCall() +{ + // Take snapshot for DeepBail and store it in tm->bailExit. + VMSideExit* exit = snapshot(DEEP_BAIL_EXIT); + w.stTraceMonitorField(w.nameImmpNonGC(exit), bailExit); + + // Tell nanojit not to discard or defer stack writes before this call. + w.xbarrier(createGuardRecord(exit)); + + // Forget about guarded shapes, since deep bailers can reshape the world. + forgetGuardedShapes(); + return exit; +} + +JS_REQUIRES_STACK void +TraceRecorder::leaveDeepBailCall() +{ + // Keep tm->bailExit null when it's invalid. + w.stTraceMonitorField(w.immpNull(), bailExit); +} + +JS_REQUIRES_STACK void +TraceRecorder::finishGetProp(LIns* obj_ins, LIns* vp_ins, LIns* ok_ins, Value* outp) +{ + // Store the boxed result (and this-object, if JOF_CALLOP) before the + // guard. The deep-bail case requires this. If the property get fails, + // these slots will be ignored anyway. + // N.B. monitorRecording expects get(outp)->isLoad() + JS_ASSERT(vp_ins->isop(LIR_allocp)); + LIns* result_ins = w.lddAlloc(vp_ins); + set(outp, result_ins); + if (js_CodeSpec[*cx->regs->pc].format & JOF_CALLOP) + set(outp + 1, obj_ins); + + // We need to guard on ok_ins, but this requires a snapshot of the state + // after this op. monitorRecording will do it for us. + pendingGuardCondition = ok_ins; + + // Note there is a boxed result sitting on the stack. The caller must leave + // it there for the time being, since the return type is not yet + // known. monitorRecording will emit the code to unbox it. + pendingUnboxSlot = outp; +} + +static inline bool +RootedStringToId(JSContext* cx, JSString** namep, jsid* idp) +{ + JSString* name = *namep; + if (name->isAtomized()) { + *idp = INTERNED_STRING_TO_JSID(name); + return true; + } + + JSAtom* atom = js_AtomizeString(cx, name, 0); + if (!atom) + return false; + *namep = ATOM_TO_STRING(atom); /* write back to GC root */ + *idp = ATOM_TO_JSID(atom); + return true; +} + +static const size_t PIC_TABLE_ENTRY_COUNT = 32; + +struct PICTableEntry +{ + jsid id; + uint32 shape; + uint32 slot; +}; + +struct PICTable +{ + PICTable() : entryCount(0) {} + + PICTableEntry entries[PIC_TABLE_ENTRY_COUNT]; + uint32 entryCount; + + bool scan(uint32 shape, jsid id, uint32 *slotOut) { + for (size_t i = 0; i < entryCount; ++i) { + PICTableEntry &entry = entries[i]; + if (entry.shape == shape && entry.id == id) { + *slotOut = entry.slot; + return true; + } + } + return false; + } + + void update(uint32 shape, jsid id, uint32 slot) { + if (entryCount >= PIC_TABLE_ENTRY_COUNT) + return; + PICTableEntry &newEntry = entries[entryCount++]; + newEntry.shape = shape; + newEntry.id = id; + newEntry.slot = slot; + } +}; + +static JSBool FASTCALL +GetPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, Value* vp, PICTable *picTable) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + LeaveTraceIfGlobalObject(cx, obj); + + jsid id; + if (!RootedStringToId(cx, namep, &id)) { + SetBuiltinError(tm); + return false; + } + + /* Delegate to the op, if present. */ + PropertyIdOp op = obj->getOps()->getProperty; + if (op) { + bool result = op(cx, obj, obj, id, vp); + if (!result) + SetBuiltinError(tm); + return WasBuiltinSuccessful(tm); + } + + /* Try to hit in the cache. */ + uint32 slot; + if (picTable->scan(obj->shape(), id, &slot)) { + *vp = obj->getSlot(slot); + return WasBuiltinSuccessful(tm); + } + + const Shape *shape; + JSObject *holder; + if (!js_GetPropertyHelperWithShape(cx, obj, obj, id, JSGET_METHOD_BARRIER, vp, &shape, + &holder)) { + SetBuiltinError(tm); + return false; + } + + /* Only update the table when the object is the holder of the property. */ + if (obj == holder && shape->hasSlot() && shape->hasDefaultGetter()) { + /* + * Note: we insert the non-normalized id into the table so you don't need to + * normalize it before hitting in the table (faster lookup). + */ + picTable->update(obj->shape(), id, shape->slot); + } + + return WasBuiltinSuccessful(tm); +} +JS_DEFINE_CALLINFO_5(static, BOOL_FAIL, GetPropertyByName, CONTEXT, OBJECT, STRINGPTR, VALUEPTR, + PICTABLE, + 0, ACCSET_STORE_ANY) + +// Convert the value in a slot to a string and store the resulting string back +// in the slot (typically in order to root it). +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::primitiveToStringInPlace(Value* vp) +{ + Value v = *vp; + JS_ASSERT(v.isPrimitive()); + + if (!v.isString()) { + // v is not a string. Turn it into one. js_ValueToString is safe + // because v is not an object. +#ifdef DEBUG + TraceMonitor *localtm = traceMonitor; +#endif + JSString *str = js_ValueToString(cx, v); + JS_ASSERT(localtm->recorder == this); + if (!str) + RETURN_ERROR("failed to stringify element id"); + v.setString(str); + set(vp, stringify(*vp)); + + // Write the string back to the stack to save the interpreter some work + // and to ensure snapshots get the correct type for this slot. + *vp = v; + } + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::getPropertyByName(LIns* obj_ins, Value* idvalp, Value* outp) +{ + CHECK_STATUS(primitiveToStringInPlace(idvalp)); + enterDeepBailCall(); + + // Call GetPropertyByName. The vp parameter points to stack because this is + // what the interpreter currently does. obj and id are rooted on the + // interpreter stack, but the slot at vp is not a root. + LIns* vp_ins = w.name(w.allocp(sizeof(Value)), "vp"); + LIns* idvalp_ins = w.name(addr(idvalp), "idvalp"); + PICTable *picTable = new (traceAlloc()) PICTable(); + LIns* pic_ins = w.nameImmpNonGC(picTable); + LIns* args[] = {pic_ins, vp_ins, idvalp_ins, obj_ins, cx_ins}; + LIns* ok_ins = w.call(&GetPropertyByName_ci, args); + + // GetPropertyByName can assign to *idvalp, so the tracker has an incorrect + // entry for that address. Correct it. (If the value in the address is + // never used again, the usual case, Nanojit will kill this load.) + // The Address could be made more precise with some effort (idvalp_ins may + // be a stack location), but it's not worth it because this case is rare. + tracker.set(idvalp, w.ldp(AnyAddress(idvalp_ins))); + + finishGetProp(obj_ins, vp_ins, ok_ins, outp); + leaveDeepBailCall(); + return RECORD_CONTINUE; +} + +static JSBool FASTCALL +GetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, Value* vp) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + LeaveTraceIfGlobalObject(cx, obj); + + AutoIdRooter idr(cx); + if (!js_Int32ToId(cx, index, idr.addr()) || !obj->getProperty(cx, idr.id(), vp)) { + SetBuiltinError(tm); + return JS_FALSE; + } + return WasBuiltinSuccessful(tm); +} +JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyByIndex, CONTEXT, OBJECT, INT32, VALUEPTR, 0, + ACCSET_STORE_ANY) + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::getPropertyByIndex(LIns* obj_ins, LIns* index_ins, Value* outp) +{ + CHECK_STATUS(makeNumberInt32(index_ins, &index_ins)); + + // See note in getPropertyByName about vp. + enterDeepBailCall(); + LIns* vp_ins = w.name(w.allocp(sizeof(Value)), "vp"); + LIns* args[] = {vp_ins, index_ins, obj_ins, cx_ins}; + LIns* ok_ins = w.call(&GetPropertyByIndex_ci, args); + finishGetProp(obj_ins, vp_ins, ok_ins, outp); + leaveDeepBailCall(); + return RECORD_CONTINUE; +} + +static JSBool FASTCALL +GetPropertyById(JSContext* cx, JSObject* obj, jsid id, Value* vp) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + LeaveTraceIfGlobalObject(cx, obj); + if (!obj->getProperty(cx, id, vp)) { + SetBuiltinError(tm); + return JS_FALSE; + } + return WasBuiltinSuccessful(tm); +} +JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyById, CONTEXT, OBJECT, JSID, VALUEPTR, + 0, ACCSET_STORE_ANY) + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::getPropertyById(LIns* obj_ins, Value* outp) +{ + // Find the atom. + JSAtom* atom; + jsbytecode* pc = cx->regs->pc; + const JSCodeSpec& cs = js_CodeSpec[*pc]; + if (*pc == JSOP_LENGTH) { + atom = cx->runtime->atomState.lengthAtom; + } else if (JOF_TYPE(cs.format) == JOF_ATOM) { + atom = atoms[GET_INDEX(pc)]; + } else { + JS_ASSERT(JOF_TYPE(cs.format) == JOF_SLOTATOM); + atom = atoms[GET_INDEX(pc + SLOTNO_LEN)]; + } + + JS_STATIC_ASSERT(sizeof(jsid) == sizeof(void *)); + jsid id = ATOM_TO_JSID(atom); + + // Call GetPropertyById. See note in getPropertyByName about vp. + enterDeepBailCall(); + LIns* vp_ins = w.name(w.allocp(sizeof(Value)), "vp"); + LIns* args[] = {vp_ins, w.nameImmw(JSID_BITS(id)), obj_ins, cx_ins}; + LIns* ok_ins = w.call(&GetPropertyById_ci, args); + finishGetProp(obj_ins, vp_ins, ok_ins, outp); + leaveDeepBailCall(); + return RECORD_CONTINUE; +} + +/* Manually inlined, specialized copy of js_NativeGet. */ +static JSBool FASTCALL +GetPropertyWithNativeGetter(JSContext* cx, JSObject* obj, Shape* shape, Value* vp) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + LeaveTraceIfGlobalObject(cx, obj); + +#ifdef DEBUG + JSObject* pobj; + const Shape* shape2; + JS_ASSERT_IF(SafeLookup(cx, obj, shape->id, &pobj, &shape2), shape == shape2); +#endif + + // Shape::get contains a special case for With objects. We can elide it + // here because With objects are, we claim, never on the operand stack + // while recording. + JS_ASSERT(obj->getClass() != &js_WithClass); + + vp->setUndefined(); + if (!shape->getterOp()(cx, obj, SHAPE_USERID(shape), vp)) { + SetBuiltinError(tm); + return JS_FALSE; + } + return WasBuiltinSuccessful(tm); +} +JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyWithNativeGetter, + CONTEXT, OBJECT, SHAPE, VALUEPTR, 0, ACCSET_STORE_ANY) + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::getPropertyWithNativeGetter(LIns* obj_ins, const Shape* shape, Value* outp) +{ + JS_ASSERT(!shape->hasGetterValue()); + JS_ASSERT(shape->slot == SHAPE_INVALID_SLOT); + JS_ASSERT(!shape->hasDefaultGetterOrIsMethod()); + + // Call GetPropertyWithNativeGetter. See note in getPropertyByName about vp. + // FIXME - We should call the getter directly. Using a builtin function for + // now because it buys some extra asserts. See bug 508310. + enterDeepBailCall(); + LIns* vp_ins = w.name(w.allocp(sizeof(Value)), "vp"); + LIns* args[] = {vp_ins, w.nameImmpNonGC(shape), obj_ins, cx_ins}; + LIns* ok_ins = w.call(&GetPropertyWithNativeGetter_ci, args); + finishGetProp(obj_ins, vp_ins, ok_ins, outp); + leaveDeepBailCall(); + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::getPropertyWithScriptGetter(JSObject *obj, LIns* obj_ins, const Shape* shape) +{ + if (!canCallImacro()) + RETURN_STOP("cannot trace script getter, already in imacro"); + + // Rearrange the stack in preparation for the imacro, taking care to adjust + // the interpreter state and the tracker in the same way. This adjustment + // is noted in imacros.jsasm with .fixup tags. + Value getter = shape->getterValue(); + Value*& sp = cx->regs->sp; + switch (*cx->regs->pc) { + case JSOP_GETPROP: + sp++; + sp[-1] = sp[-2]; + set(&sp[-1], get(&sp[-2])); + sp[-2] = getter; + set(&sp[-2], w.immpObjGC(&getter.toObject())); + return callImacroInfallibly(getprop_imacros.scriptgetter); + + case JSOP_CALLPROP: + sp += 2; + sp[-2] = getter; + set(&sp[-2], w.immpObjGC(&getter.toObject())); + sp[-1] = sp[-3]; + set(&sp[-1], get(&sp[-3])); + return callImacroInfallibly(callprop_imacros.scriptgetter); + + case JSOP_GETTHISPROP: + case JSOP_GETARGPROP: + case JSOP_GETLOCALPROP: + sp += 2; + sp[-2] = getter; + set(&sp[-2], w.immpObjGC(&getter.toObject())); + sp[-1] = ObjectValue(*obj); + set(&sp[-1], obj_ins); + return callImacroInfallibly(getthisprop_imacros.scriptgetter); + + default: + RETURN_STOP("cannot trace script getter for this opcode"); + } +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::getCharCodeAt(JSString *str, LIns* str_ins, LIns* idx_ins, LIns** out) +{ + CHECK_STATUS(makeNumberInt32(idx_ins, &idx_ins)); + idx_ins = w.ui2p(idx_ins); + LIns *lengthAndFlags_ins = w.ldpStringLengthAndFlags(str_ins); + if (MaybeBranch mbr = w.jt(w.eqp0(w.andp(lengthAndFlags_ins, w.nameImmw(JSString::ROPE_BIT))))) + { + LIns *args[] = { str_ins, cx_ins }; + LIns *ok_ins = w.call(&js_Flatten_ci, args); + guard(false, w.eqi0(ok_ins), OOM_EXIT); + w.label(mbr); + } + + guard(true, + w.ltup(idx_ins, w.rshupN(lengthAndFlags_ins, JSString::LENGTH_SHIFT)), + snapshot(MISMATCH_EXIT)); + *out = w.i2d(w.getStringChar(str_ins, idx_ins)); + return RECORD_CONTINUE; +} + +JS_STATIC_ASSERT(sizeof(JSString) == 16 || sizeof(JSString) == 32); + + +JS_REQUIRES_STACK LIns* +TraceRecorder::getUnitString(LIns* str_ins, LIns* idx_ins) +{ + LIns *ch_ins = w.getStringChar(str_ins, idx_ins); + guard(true, w.ltuiN(ch_ins, UNIT_STRING_LIMIT), MISMATCH_EXIT); + return w.addp(w.nameImmpNonGC(JSString::unitStringTable), + w.lshpN(w.ui2p(ch_ins), (sizeof(JSString) == 16) ? 4 : 5)); +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::getCharAt(JSString *str, LIns* str_ins, LIns* idx_ins, JSOp mode, LIns** out) +{ + CHECK_STATUS(makeNumberInt32(idx_ins, &idx_ins)); + idx_ins = w.ui2p(idx_ins); + LIns *lengthAndFlags_ins = w.ldpStringLengthAndFlags(str_ins); + if (MaybeBranch mbr = w.jt(w.eqp0(w.andp(lengthAndFlags_ins, + w.nameImmw(JSString::ROPE_BIT))))) + { + LIns *args[] = { str_ins, cx_ins }; + LIns *ok_ins = w.call(&js_Flatten_ci, args); + guard(false, w.eqi0(ok_ins), OOM_EXIT); + w.label(mbr); + } + + LIns* inRange = w.ltup(idx_ins, w.rshupN(lengthAndFlags_ins, JSString::LENGTH_SHIFT)); + + if (mode == JSOP_GETELEM) { + guard(true, inRange, MISMATCH_EXIT); + + *out = getUnitString(str_ins, idx_ins); + } else { + LIns *phi_ins = w.allocp(sizeof(JSString *)); + w.stAlloc(w.nameImmpNonGC(cx->runtime->emptyString), phi_ins); + + if (MaybeBranch mbr = w.jf(inRange)) { + LIns *unitstr_ins = getUnitString(str_ins, idx_ins); + w.stAlloc(unitstr_ins, phi_ins); + w.label(mbr); + } + *out = w.ldpAlloc(phi_ins); + } + return RECORD_CONTINUE; +} + +// Typed array tracing depends on EXPANDED_LOADSTORE and F2I +#if NJ_EXPANDED_LOADSTORE_SUPPORTED && NJ_F2I_SUPPORTED +static bool OkToTraceTypedArrays = true; +#else +static bool OkToTraceTypedArrays = false; +#endif + +JS_REQUIRES_STACK void +TraceRecorder::guardNotHole(LIns *argsobj_ins, LIns *idx_ins) +{ + // vp = &argsobj->slots[JSSLOT_ARGS_DATA].slots[idx] + LIns* argsData_ins = w.getObjPrivatizedSlot(argsobj_ins, JSObject::JSSLOT_ARGS_DATA); + LIns* slotOffset_ins = w.addp(w.nameImmw(offsetof(ArgumentsData, slots)), + w.ui2p(w.muliN(idx_ins, sizeof(Value)))); + LIns* vp_ins = w.addp(argsData_ins, slotOffset_ins); + + guard(false, + w.name(is_boxed_magic(ArgsSlotOffsetAddress(vp_ins), JS_ARGS_HOLE), + "guard(not deleted arg)"), + MISMATCH_EXIT); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GETELEM() +{ + bool call = *cx->regs->pc == JSOP_CALLELEM; + + Value& idx = stackval(-1); + Value& lval = stackval(-2); + + LIns* obj_ins = get(&lval); + LIns* idx_ins = get(&idx); + + // Special case for array-like access of strings. + if (lval.isString() && hasInt32Repr(idx)) { + if (call) + RETURN_STOP_A("JSOP_CALLELEM on a string"); + int i = asInt32(idx); + if (size_t(i) >= lval.toString()->length()) + RETURN_STOP_A("Invalid string index in JSOP_GETELEM"); + LIns* char_ins; + CHECK_STATUS_A(getCharAt(lval.toString(), obj_ins, idx_ins, JSOP_GETELEM, &char_ins)); + set(&lval, char_ins); + return ARECORD_CONTINUE; + } + + if (lval.isPrimitive()) + RETURN_STOP_A("JSOP_GETLEM on a primitive"); + RETURN_IF_XML_A(lval); + + JSObject* obj = &lval.toObject(); + if (obj == globalObj) + RETURN_STOP_A("JSOP_GETELEM on global"); + LIns* v_ins; + + /* Property access using a string name or something we have to stringify. */ + if (!idx.isInt32()) { + if (!idx.isPrimitive()) + RETURN_STOP_A("object used as index"); + + return InjectStatus(getPropertyByName(obj_ins, &idx, &lval)); + } + + if (obj->isArguments()) { + // Don't even try to record if out of range or reading a deleted arg + int32 int_idx = idx.toInt32(); + if (int_idx < 0 || int_idx >= (int32)obj->getArgsInitialLength()) + RETURN_STOP_A("cannot trace arguments with out of range index"); + if (obj->getArgsElement(int_idx).isMagic(JS_ARGS_HOLE)) + RETURN_STOP_A("reading deleted args element"); + + // Only trace reading arguments out of active, tracked frame + unsigned depth; + JSStackFrame *afp = guardArguments(obj, obj_ins, &depth); + if (afp) { + Value* vp = &afp->canonicalActualArg(int_idx); + if (idx_ins->isImmD()) { + JS_ASSERT(int_idx == (int32)idx_ins->immD()); + guardNotHole(obj_ins, w.nameImmi(int_idx)); + v_ins = get(vp); + } else { + // If the index is not a constant expression, we generate LIR to load the value from + // the native stack area. The guard on js_ArgumentClass above ensures the up-to-date + // value has been written back to the native stack area. + CHECK_STATUS_A(makeNumberInt32(idx_ins, &idx_ins)); + + /* + * For small nactual, + * 0 <= int_idx < nactual iff unsigned(int_idx) < unsigned(nactual). + */ + guard(true, + w.name(w.ltui(idx_ins, w.nameImmui(afp->numActualArgs())), + "guard(upvar index in range)"), + MISMATCH_EXIT); + + guardNotHole(obj_ins, idx_ins); + + JSValueType type = getCoercedType(*vp); + + // Guard that the argument has the same type on trace as during recording. + LIns* typemap_ins; + if (depth == 0) { + // In this case, we are in the same frame where the arguments object was created. + // The entry type map is not necessarily up-to-date, so we capture a new type map + // for this point in the code. + unsigned stackSlots = NativeStackSlots(cx, 0 /* callDepth */); + JSValueType* typemap = new (traceAlloc()) JSValueType[stackSlots]; + DetermineTypesVisitor detVisitor(*this, typemap); + VisitStackSlots(detVisitor, cx, 0); + typemap_ins = w.nameImmpNonGC(typemap + 2 /* callee, this */); + } else { + // In this case, we are in a deeper frame from where the arguments object was + // created. The type map at the point of the call out from the creation frame + // is accurate. + // Note: this relies on the assumption that we abort on setting an element of + // an arguments object in any deeper frame. + LIns* fip_ins = w.ldpRstack(lirbuf->rp, (callDepth-depth)*sizeof(FrameInfo*)); + typemap_ins = w.addp(fip_ins, w.nameImmw(sizeof(FrameInfo) + 2/*callee,this*/ * sizeof(JSValueType))); + } + + LIns* type_ins = w.lduc2uiConstTypeMapEntry(typemap_ins, idx_ins); + guard(true, + w.name(w.eqi(type_ins, w.immi(type)), "guard(type-stable upvar)"), + BRANCH_EXIT); + + // Read the value out of the native stack area. + size_t stackOffset = nativespOffset(&afp->canonicalActualArg(0)); + LIns* args_addr_ins = w.addp(lirbuf->sp, w.nameImmw(stackOffset)); + LIns* argi_addr_ins = w.addp(args_addr_ins, + w.ui2p(w.muli(idx_ins, w.nameImmi(sizeof(double))))); + + // The Address could be more precise, but ValidateWriter + // doesn't recognise the complex expression involving 'sp' as + // an stack access, and it's not worth the effort to be + // more precise because this case is rare. + v_ins = stackLoad(AnyAddress(argi_addr_ins), type); + } + JS_ASSERT(v_ins); + set(&lval, v_ins); + if (call) + set(&idx, obj_ins); + return ARECORD_CONTINUE; + } + RETURN_STOP_A("can't reach arguments object's frame"); + } + + if (obj->isDenseArray()) { + // Fast path for dense arrays accessed with a integer index. + Value* vp; + LIns* addr_ins; + + VMSideExit* branchExit = snapshot(BRANCH_EXIT); + guardDenseArray(obj_ins, branchExit); + CHECK_STATUS_A(denseArrayElement(lval, idx, vp, v_ins, addr_ins, branchExit)); + set(&lval, v_ins); + if (call) + set(&idx, obj_ins); + return ARECORD_CONTINUE; + } + + if (OkToTraceTypedArrays && js_IsTypedArray(obj)) { + // Fast path for typed arrays accessed with a integer index. + Value* vp; + guardClass(obj_ins, obj->getClass(), snapshot(BRANCH_EXIT), LOAD_CONST); + CHECK_STATUS_A(typedArrayElement(lval, idx, vp, v_ins)); + set(&lval, v_ins); + if (call) + set(&idx, obj_ins); + return ARECORD_CONTINUE; + } + + return InjectStatus(getPropertyByIndex(obj_ins, idx_ins, &lval)); +} + +/* Functions used by JSOP_SETELEM */ + +static JSBool FASTCALL +SetPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, Value* vp, JSBool strict) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + LeaveTraceIfGlobalObject(cx, obj); + + jsid id; + if (!RootedStringToId(cx, namep, &id) || !obj->setProperty(cx, id, vp, strict)) { + SetBuiltinError(tm); + return false; + } + return WasBuiltinSuccessful(tm); +} +JS_DEFINE_CALLINFO_5(static, BOOL_FAIL, SetPropertyByName, + CONTEXT, OBJECT, STRINGPTR, VALUEPTR, BOOL, + 0, ACCSET_STORE_ANY) + +static JSBool FASTCALL +InitPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, ValueArgType arg) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + LeaveTraceIfGlobalObject(cx, obj); + + jsid id; + if (!RootedStringToId(cx, namep, &id) || + !obj->defineProperty(cx, id, ValueArgToConstRef(arg), NULL, NULL, JSPROP_ENUMERATE)) { + SetBuiltinError(tm); + return JS_FALSE; + } + return WasBuiltinSuccessful(tm); +} +JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, InitPropertyByName, CONTEXT, OBJECT, STRINGPTR, VALUE, + 0, ACCSET_STORE_ANY) + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::initOrSetPropertyByName(LIns* obj_ins, Value* idvalp, Value* rvalp, bool init) +{ + CHECK_STATUS(primitiveToStringInPlace(idvalp)); + + if (init) { + LIns* v_ins = box_value_for_native_call(*rvalp, get(rvalp)); + enterDeepBailCall(); + LIns* idvalp_ins = w.name(addr(idvalp), "idvalp"); + LIns* args[] = {v_ins, idvalp_ins, obj_ins, cx_ins}; + pendingGuardCondition = w.call(&InitPropertyByName_ci, args); + } else { + // See note in getPropertyByName about vp. + LIns* vp_ins = box_value_into_alloc(*rvalp, get(rvalp)); + enterDeepBailCall(); + LIns* idvalp_ins = w.name(addr(idvalp), "idvalp"); + LIns* args[] = { strictModeCode_ins, vp_ins, idvalp_ins, obj_ins, cx_ins }; + pendingGuardCondition = w.call(&SetPropertyByName_ci, args); + } + + leaveDeepBailCall(); + return RECORD_CONTINUE; +} + +static JSBool FASTCALL +SetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, Value* vp, JSBool strict) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + LeaveTraceIfGlobalObject(cx, obj); + + AutoIdRooter idr(cx); + if (!js_Int32ToId(cx, index, idr.addr()) || !obj->setProperty(cx, idr.id(), vp, strict)) { + SetBuiltinError(tm); + return false; + } + return WasBuiltinSuccessful(tm); +} +JS_DEFINE_CALLINFO_5(static, BOOL_FAIL, SetPropertyByIndex, CONTEXT, OBJECT, INT32, VALUEPTR, BOOL, + 0, ACCSET_STORE_ANY) + +static JSBool FASTCALL +InitPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, ValueArgType arg) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + LeaveTraceIfGlobalObject(cx, obj); + + AutoIdRooter idr(cx); + if (!js_Int32ToId(cx, index, idr.addr()) || + !obj->defineProperty(cx, idr.id(), ValueArgToConstRef(arg), NULL, NULL, JSPROP_ENUMERATE)) { + SetBuiltinError(tm); + return JS_FALSE; + } + return WasBuiltinSuccessful(tm); +} +JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, InitPropertyByIndex, CONTEXT, OBJECT, INT32, VALUE, + 0, ACCSET_STORE_ANY) + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::initOrSetPropertyByIndex(LIns* obj_ins, LIns* index_ins, Value* rvalp, bool init) +{ + CHECK_STATUS(makeNumberInt32(index_ins, &index_ins)); + + if (init) { + LIns* rval_ins = box_value_for_native_call(*rvalp, get(rvalp)); + enterDeepBailCall(); + LIns* args[] = {rval_ins, index_ins, obj_ins, cx_ins}; + pendingGuardCondition = w.call(&InitPropertyByIndex_ci, args); + } else { + // See note in getPropertyByName about vp. + LIns* vp_ins = box_value_into_alloc(*rvalp, get(rvalp)); + enterDeepBailCall(); + LIns* args[] = {strictModeCode_ins, vp_ins, index_ins, obj_ins, cx_ins}; + pendingGuardCondition = w.call(&SetPropertyByIndex_ci, args); + } + + leaveDeepBailCall(); + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex) +{ + Value& v = stackval(v_spindex); + Value& idx = stackval(idx_spindex); + Value& lval = stackval(lval_spindex); + + if (lval.isPrimitive()) + RETURN_STOP_A("left JSOP_SETELEM operand is not an object"); + RETURN_IF_XML_A(lval); + + JSObject* obj = &lval.toObject(); + LIns* obj_ins = get(&lval); + LIns* idx_ins = get(&idx); + LIns* v_ins = get(&v); + + if (obj->isArguments()) + RETURN_STOP_A("can't trace setting elements of the |arguments| object"); + + if (obj == globalObj) + RETURN_STOP_A("can't trace setting elements on the global object"); + + if (!idx.isInt32()) { + if (!idx.isPrimitive()) + RETURN_STOP_A("non-primitive index"); + CHECK_STATUS_A(initOrSetPropertyByName(obj_ins, &idx, &v, + *cx->regs->pc == JSOP_INITELEM)); + } else if (OkToTraceTypedArrays && js_IsTypedArray(obj)) { + // Fast path: assigning to element of typed array. + VMSideExit* branchExit = snapshot(BRANCH_EXIT); + + // Ensure array is a typed array and is the same type as what was written + guardClass(obj_ins, obj->getClass(), branchExit, LOAD_CONST); + + js::TypedArray* tarray = js::TypedArray::fromJSObject(obj); + + LIns* priv_ins = w.ldpObjPrivate(obj_ins); + + // The index was on the stack and is therefore a LIR float; force it to + // be an integer. + CHECK_STATUS_A(makeNumberInt32(idx_ins, &idx_ins)); + + // Ensure idx >= 0 && idx < length (by using uint32) + CHECK_STATUS_A(guard(true, + w.name(w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)), + "inRange"), + OVERFLOW_EXIT, /* abortIfAlwaysExits = */true)); + + // We're now ready to store + LIns* data_ins = w.ldpConstTypedArrayData(priv_ins); + LIns* pidx_ins = w.ui2p(idx_ins); + LIns* typed_v_ins = v_ins; + + // If it's not a number, convert objects to NaN, + // null to 0, and call StringToNumber or BooleanOrUndefinedToNumber + // for those. + if (!v.isNumber()) { + if (v.isNull()) { + typed_v_ins = w.immd(0); + } else if (v.isUndefined()) { + typed_v_ins = w.immd(js_NaN); + } else if (v.isString()) { + LIns* ok_ins = w.allocp(sizeof(JSBool)); + LIns* args[] = { ok_ins, typed_v_ins, cx_ins }; + typed_v_ins = w.call(&js_StringToNumber_ci, args); + guard(false, + w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"), + OOM_EXIT); + } else if (v.isBoolean()) { + JS_ASSERT(v.isBoolean()); + typed_v_ins = w.i2d(typed_v_ins); + } else { + typed_v_ins = w.immd(js_NaN); + } + } + + switch (tarray->type) { + case js::TypedArray::TYPE_INT8: + case js::TypedArray::TYPE_INT16: + case js::TypedArray::TYPE_INT32: + typed_v_ins = d2i(typed_v_ins); + break; + case js::TypedArray::TYPE_UINT8: + case js::TypedArray::TYPE_UINT16: + case js::TypedArray::TYPE_UINT32: + typed_v_ins = d2u(typed_v_ins); + break; + case js::TypedArray::TYPE_UINT8_CLAMPED: + if (IsPromotedInt32(typed_v_ins)) { + typed_v_ins = w.demoteToInt32(typed_v_ins); + typed_v_ins = w.cmovi(w.ltiN(typed_v_ins, 0), + w.immi(0), + w.cmovi(w.gtiN(typed_v_ins, 0xff), + w.immi(0xff), + typed_v_ins)); + } else { + typed_v_ins = w.call(&js_TypedArray_uint8_clamp_double_ci, &typed_v_ins); + } + break; + case js::TypedArray::TYPE_FLOAT32: + case js::TypedArray::TYPE_FLOAT64: + // Do nothing, this is already a float + break; + default: + JS_NOT_REACHED("Unknown typed array type in tracer"); + } + + switch (tarray->type) { + case js::TypedArray::TYPE_INT8: + case js::TypedArray::TYPE_UINT8_CLAMPED: + case js::TypedArray::TYPE_UINT8: + w.sti2cTypedArrayElement(typed_v_ins, data_ins, pidx_ins); + break; + case js::TypedArray::TYPE_INT16: + case js::TypedArray::TYPE_UINT16: + w.sti2sTypedArrayElement(typed_v_ins, data_ins, pidx_ins); + break; + case js::TypedArray::TYPE_INT32: + case js::TypedArray::TYPE_UINT32: + w.stiTypedArrayElement(typed_v_ins, data_ins, pidx_ins); + break; + case js::TypedArray::TYPE_FLOAT32: + w.std2fTypedArrayElement(typed_v_ins, data_ins, pidx_ins); + break; + case js::TypedArray::TYPE_FLOAT64: + w.stdTypedArrayElement(typed_v_ins, data_ins, pidx_ins); + break; + default: + JS_NOT_REACHED("Unknown typed array type in tracer"); + } + } else if (idx.toInt32() < 0 || !obj->isDenseArray()) { + CHECK_STATUS_A(initOrSetPropertyByIndex(obj_ins, idx_ins, &v, + *cx->regs->pc == JSOP_INITELEM)); + } else { + // Fast path: assigning to element of dense array. + VMSideExit* branchExit = snapshot(BRANCH_EXIT); + VMSideExit* mismatchExit = snapshot(MISMATCH_EXIT); + + // Make sure the array is actually dense. + if (!obj->isDenseArray()) + return ARECORD_STOP; + guardDenseArray(obj_ins, branchExit); + + // The index was on the stack and is therefore a LIR float. Force it to + // be an integer. + CHECK_STATUS_A(makeNumberInt32(idx_ins, &idx_ins)); + + if (!js_EnsureDenseArrayCapacity(cx, obj, idx.toInt32())) + RETURN_STOP_A("couldn't ensure dense array capacity for setelem"); + + // Grow the array if the index exceeds the capacity. This happens + // rarely, eg. less than 1% of the time in SunSpider. + LIns* capacity_ins = w.ldiDenseArrayCapacity(obj_ins); + /* + * It's important that CSE works across this control-flow diamond + * because it really helps series of interleaved GETELEM and SETELEM + * operations. Likewise with the diamond below. + */ + w.pauseAddingCSEValues(); + if (MaybeBranch mbr = w.jt(w.name(w.ltui(idx_ins, capacity_ins), "inRange"))) { + LIns* args[] = { idx_ins, obj_ins, cx_ins }; + LIns* res_ins = w.call(&js_EnsureDenseArrayCapacity_ci, args); + guard(false, w.eqi0(res_ins), mismatchExit); + w.label(mbr); + } + w.resumeAddingCSEValues(); + + // Get the address of the element. + LIns *elemp_ins = w.name(w.getDslotAddress(obj_ins, idx_ins), "elemp"); + + // If we are overwriting a hole: + // - Guard that we don't have any indexed properties along the prototype chain. + // - Check if the length has changed; if so, update it to index+1. + // This happens moderately often, eg. close to 10% of the time in + // SunSpider, and for some benchmarks it's close to 100%. + Address dslotAddr = DSlotsAddress(elemp_ins); + LIns* isHole_ins = w.name(is_boxed_magic(dslotAddr, JS_ARRAY_HOLE), + "isHole"); + w.pauseAddingCSEValues(); + if (MaybeBranch mbr1 = w.jf(isHole_ins)) { + /* + * It's important that this use branchExit, not mismatchExit, since + * changes to shapes should just mean we compile a new branch, not + * throw the whole trace away. + */ + CHECK_STATUS_A(guardPrototypeHasNoIndexedProperties(obj, obj_ins, branchExit)); + LIns* length_ins = w.lduiObjPrivate(obj_ins); + if (MaybeBranch mbr2 = w.jt(w.ltui(idx_ins, length_ins))) { + LIns* newLength_ins = w.name(w.addiN(idx_ins, 1), "newLength"); + w.stuiObjPrivate(obj_ins, newLength_ins); + w.label(mbr2); + } + w.label(mbr1); + } + w.resumeAddingCSEValues(); + + // Right, actually set the element. + box_value_into(v, v_ins, dslotAddr); + } + + jsbytecode* pc = cx->regs->pc; + if (*pc == JSOP_SETELEM && pc[JSOP_SETELEM_LENGTH] != JSOP_POP) + set(&lval, v_ins); + + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SETELEM() +{ + return setElem(-3, -2, -1); +} + +static JSBool FASTCALL +CheckSameGlobal(JSObject *obj, JSObject *globalObj) +{ + return obj->getGlobal() == globalObj; +} +JS_DEFINE_CALLINFO_2(static, BOOL, CheckSameGlobal, OBJECT, OBJECT, 0, ACCSET_STORE_ANY) + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_CALLNAME() +{ + JSObject* scopeObj = &cx->fp()->scopeChain(); + LIns *funobj_ins; + JSObject *funobj; + if (scopeObj != globalObj) { + Value* vp; + NameResult nr; + CHECK_STATUS_A(scopeChainProp(scopeObj, vp, funobj_ins, nr, &scopeObj)); + if (!nr.tracked) + vp = &nr.v; + if (!vp->isObject()) + RETURN_STOP_A("callee is not an object"); + funobj = &vp->toObject(); + if (!funobj->isFunction()) + RETURN_STOP_A("callee is not a function"); + } else { + LIns* obj_ins = w.immpObjGC(globalObj); + JSObject* obj2; + PCVal pcval; + + CHECK_STATUS_A(test_property_cache(scopeObj, obj_ins, obj2, pcval)); + + if (pcval.isNull() || !pcval.isFunObj()) + RETURN_STOP_A("callee is not a function"); + + funobj = &pcval.toFunObj(); + funobj_ins = w.immpObjGC(funobj); + } + + // Detect crossed globals early. The interpreter could decide to compute + // a non-Undefined |this| value, and we want to make sure that we'll (1) + // abort in this case, and (2) bail out early if a callee will need special + // |this| computation. Note that if (scopeObj != globalObj), + // scopeChainProp() guarantees that scopeObj is a cacheable scope. + if (scopeObj == globalObj) { + JSFunction *fun = funobj->getFunctionPrivate(); + if (!fun->isInterpreted() || !fun->inStrictMode()) { + if (funobj->getGlobal() != globalObj) + RETURN_STOP_A("callee crosses globals"); + + // If the funobj is not constant, we need may a guard that the + // callee will not cross globals. This is only the case for non- + // compile-and-go trees. + if (!funobj_ins->isImmP() && !tree->script->compileAndGo) { + LIns* args[] = { w.immpObjGC(globalObj), funobj_ins }; + guard(false, w.eqi0(w.call(&CheckSameGlobal_ci, args)), MISMATCH_EXIT); + } + } + } + + stack(0, funobj_ins); + stack(1, w.immiUndefined()); + return ARECORD_CONTINUE; +} + +JS_DEFINE_CALLINFO_5(extern, UINT32, GetUpvarArgOnTrace, CONTEXT, UINT32, INT32, UINT32, + DOUBLEPTR, 0, ACCSET_STORE_ANY) +JS_DEFINE_CALLINFO_5(extern, UINT32, GetUpvarVarOnTrace, CONTEXT, UINT32, INT32, UINT32, + DOUBLEPTR, 0, ACCSET_STORE_ANY) +JS_DEFINE_CALLINFO_5(extern, UINT32, GetUpvarStackOnTrace, CONTEXT, UINT32, INT32, UINT32, + DOUBLEPTR, 0, ACCSET_STORE_ANY) + +/* + * Record LIR to get the given upvar. Return the LIR instruction for the upvar + * value. NULL is returned only on a can't-happen condition with an invalid + * typemap. The value of the upvar is returned as v. + */ +JS_REQUIRES_STACK LIns* +TraceRecorder::upvar(JSScript* script, JSUpvarArray* uva, uintN index, Value& v) +{ + /* + * Try to find the upvar in the current trace's tracker. For &vr to be + * the address of the jsval found in js::GetUpvar, we must initialize + * vr directly with the result, so it is a reference to the same location. + * It does not work to assign the result to v, because v is an already + * existing reference that points to something else. + */ + UpvarCookie cookie = uva->vector[index]; + const Value& vr = GetUpvar(cx, script->staticLevel, cookie); + v = vr; + + if (LIns* ins = attemptImport(&vr)) + return ins; + + /* + * The upvar is not in the current trace, so get the upvar value exactly as + * the interpreter does and unbox. + */ + uint32 level = script->staticLevel - cookie.level(); + uint32 cookieSlot = cookie.slot(); + JSStackFrame* fp = cx->findFrameAtLevel(level); + const CallInfo* ci; + int32 slot; + if (!fp->isFunctionFrame() || fp->isEvalFrame()) { + ci = &GetUpvarStackOnTrace_ci; + slot = cookieSlot; + } else if (cookieSlot < fp->numFormalArgs()) { + ci = &GetUpvarArgOnTrace_ci; + slot = cookieSlot; + } else if (cookieSlot == UpvarCookie::CALLEE_SLOT) { + ci = &GetUpvarArgOnTrace_ci; + slot = -2; + } else { + ci = &GetUpvarVarOnTrace_ci; + slot = cookieSlot - fp->numFormalArgs(); + } + + LIns* outp = w.allocp(sizeof(double)); + LIns* args[] = { + outp, + w.nameImmi(callDepth), + w.nameImmi(slot), + w.nameImmi(level), + cx_ins + }; + LIns* call_ins = w.call(ci, args); + JSValueType type = getCoercedType(v); + guard(true, + w.name(w.eqi(call_ins, w.immi(type)), "guard(type-stable upvar)"), + BRANCH_EXIT); + return stackLoad(AllocSlotsAddress(outp), type); +} + +/* + * Generate LIR to load a value from the native stack. This method ensures that + * the correct LIR load operator is used. + */ +LIns* +TraceRecorder::stackLoad(Address addr, uint8 type) +{ + switch (type) { + case JSVAL_TYPE_DOUBLE: + return w.ldd(addr); + case JSVAL_TYPE_NONFUNOBJ: + case JSVAL_TYPE_STRING: + case JSVAL_TYPE_FUNOBJ: + case JSVAL_TYPE_NULL: + return w.ldp(addr); + case JSVAL_TYPE_INT32: + return w.i2d(w.ldi(addr)); + case JSVAL_TYPE_BOOLEAN: + case JSVAL_TYPE_UNDEFINED: + case JSVAL_TYPE_MAGIC: + return w.ldi(addr); + case JSVAL_TYPE_BOXED: + default: + JS_NOT_REACHED("found jsval type in an upvar type map entry"); + return NULL; + } +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GETFCSLOT() +{ + JSObject& callee = cx->fp()->callee(); + LIns* callee_ins = get(&cx->fp()->calleeValue()); + + LIns* upvars_ins = w.getObjPrivatizedSlot(callee_ins, JSObject::JSSLOT_FLAT_CLOSURE_UPVARS); + + unsigned index = GET_UINT16(cx->regs->pc); + LIns *v_ins = unbox_value(callee.getFlatClosureUpvar(index), + FCSlotsAddress(upvars_ins, index), + snapshot(BRANCH_EXIT)); + stack(0, v_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_CALLFCSLOT() +{ + CHECK_STATUS_A(record_JSOP_GETFCSLOT()); + stack(1, w.immiUndefined()); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::guardCallee(Value& callee) +{ + JSObject& callee_obj = callee.toObject(); + JS_ASSERT(callee_obj.isFunction()); + JSFunction* callee_fun = (JSFunction*) callee_obj.getPrivate(); + + /* + * First, guard on the callee's function (JSFunction*) identity. This is + * necessary since tracing always inlines function calls. But note that + * TR::functionCall avoids calling TR::guardCallee for constant methods + * (those hit in the property cache from JSOP_CALLPROP). + */ + VMSideExit* branchExit = snapshot(BRANCH_EXIT); + LIns* callee_ins = get(&callee); + tree->gcthings.addUnique(callee); + + guard(true, + w.eqp(w.ldpObjPrivate(callee_ins), w.nameImmpNonGC(callee_fun)), + branchExit); + + /* + * Second, consider guarding on the parent scope of the callee. + * + * As long as we guard on parent scope, we are guaranteed when recording + * variable accesses for a Call object having no private data that we can + * emit code that avoids checking for an active JSStackFrame for the Call + * object (which would hold fresh variable values -- the Call object's + * slots would be stale until the stack frame is popped). This is because + * Call objects can't pick up a new stack frame in their private slot once + * they have none. TR::callProp and TR::setCallProp depend on this fact and + * document where; if this guard is removed make sure to fix those methods. + * Search for the "parent guard" comments in them. + * + * In general, a loop in an escaping function scoped by Call objects could + * be traced before the function has returned, and the trace then triggered + * after, or vice versa. The function must escape, i.e., be a "funarg", or + * else there's no need to guard callee parent at all. So once we know (by + * static analysis) that a function may escape, we cannot avoid guarding on + * either the private data of the Call object or the Call object itself, if + * we wish to optimize for the particular deactivated stack frame (null + * private data) case as noted above. + */ + if (callee_fun->isInterpreted() && + (!FUN_NULL_CLOSURE(callee_fun) || callee_fun->script()->bindings.hasUpvars())) { + JSObject* parent = callee_obj.getParent(); + + if (parent != globalObj) { + if (!parent->isCall()) + RETURN_STOP("closure scoped by neither the global object nor a Call object"); + + guard(true, + w.eqp(w.ldpObjParent(callee_ins), w.immpObjGC(parent)), + branchExit); + } + } + return RECORD_CONTINUE; +} + +/* + * Prepare the given |arguments| object to be accessed on trace. If the return + * value is non-NULL, then the given |arguments| object refers to a frame on + * the current trace and is guaranteed to refer to the same frame on trace for + * all later executions. + */ +JS_REQUIRES_STACK JSStackFrame * +TraceRecorder::guardArguments(JSObject *obj, LIns* obj_ins, unsigned *depthp) +{ + JS_ASSERT(obj->isArguments()); + + JSStackFrame *afp = frameIfInRange(obj, depthp); + if (!afp) + return NULL; + + VMSideExit *exit = snapshot(MISMATCH_EXIT); + guardClass(obj_ins, obj->getClass(), exit, LOAD_CONST); + + LIns* args_ins = getFrameObjPtr(afp->addressOfArgs()); + LIns* cmp = w.eqp(args_ins, obj_ins); + guard(true, cmp, exit); + return afp; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::createThis(JSObject& ctor, LIns* ctor_ins, LIns** thisobj_insp) +{ + JS_ASSERT(ctor.getFunctionPrivate()->isInterpreted()); + if (ctor.getFunctionPrivate()->isFunctionPrototype()) + RETURN_STOP("new Function.prototype"); + if (ctor.isBoundFunction()) + RETURN_STOP("new applied to bound function"); + + // Given the above conditions, ctor.prototype is a non-configurable data + // property with a slot. + const Shape *shape = LookupInterpretedFunctionPrototype(cx, &ctor); + if (!shape) + RETURN_ERROR("new f: error resolving f.prototype"); + + // At run time ctor might be a different instance of the same function. Its + // .prototype property might not be resolved yet. Guard on the function + // object's shape to make sure .prototype is there. + // + // However, if ctor_ins is constant, which is usual, we don't need to + // guard: .prototype is non-configurable, and an object's non-configurable + // data properties always stay in the same slot for the life of the object. + if (!ctor_ins->isImmP()) + guardShape(ctor_ins, &ctor, ctor.shape(), "ctor_shape", snapshot(MISMATCH_EXIT)); + + // Pass the slot of ctor.prototype to js_CreateThisFromTrace. We can only + // bake the slot into the trace, not the value, since .prototype is + // writable. + uintN protoSlot = shape->slot; + LIns* args[] = { w.nameImmw(protoSlot), ctor_ins, cx_ins }; + *thisobj_insp = w.call(&js_CreateThisFromTrace_ci, args); + guard(false, w.eqp0(*thisobj_insp), OOM_EXIT); + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::interpretedFunctionCall(Value& fval, JSFunction* fun, uintN argc, bool constructing) +{ + /* + * The function's identity (JSFunction and therefore JSScript) is guarded, + * so we can optimize away the function call if the corresponding script is + * empty. No need to worry about crossing globals or relocating argv, even, + * in this case! + */ + if (fun->script()->isEmpty()) { + LIns* rval_ins; + if (constructing) + CHECK_STATUS(createThis(fval.toObject(), get(&fval), &rval_ins)); + else + rval_ins = w.immiUndefined(); + stack(-2 - argc, rval_ins); + return RECORD_CONTINUE; + } + + if (fval.toObject().getGlobal() != globalObj) + RETURN_STOP("JSOP_CALL or JSOP_NEW crosses global scopes"); + + JSStackFrame* const fp = cx->fp(); + + if (constructing) { + LIns* thisobj_ins; + CHECK_STATUS(createThis(fval.toObject(), get(&fval), &thisobj_ins)); + stack(-int(argc) - 1, thisobj_ins); + } + + // Generate a type map for the outgoing frame and stash it in the LIR + unsigned stackSlots = NativeStackSlots(cx, 0 /* callDepth */); + FrameInfo* fi = (FrameInfo*) + tempAlloc().alloc(sizeof(FrameInfo) + stackSlots * sizeof(JSValueType)); + JSValueType* typemap = (JSValueType*)(fi + 1); + + DetermineTypesVisitor detVisitor(*this, typemap); + VisitStackSlots(detVisitor, cx, 0); + + JS_ASSERT(argc < FrameInfo::CONSTRUCTING_FLAG); + + tree->gcthings.addUnique(fval); + fi->pc = cx->regs->pc; + fi->imacpc = fp->maybeImacropc(); + fi->spdist = cx->regs->sp - fp->slots(); + fi->set_argc(uint16(argc), constructing); + fi->callerHeight = stackSlots - (2 + argc); + fi->callerArgc = fp->isGlobalFrame() || fp->isEvalFrame() ? 0 : fp->numActualArgs(); + + if (callDepth >= tree->maxCallDepth) + tree->maxCallDepth = callDepth + 1; + + fi = traceMonitor->frameCache->memoize(fi); + if (!fi) + RETURN_STOP("out of memory"); + w.stRstack(w.nameImmpNonGC(fi), lirbuf->rp, callDepth * sizeof(FrameInfo*)); + +#if defined JS_JIT_SPEW + debug_only_printf(LC_TMTracer, "iFC frameinfo=%p, stack=%d, map=", (void*)fi, + fi->callerHeight); + for (unsigned i = 0; i < fi->callerHeight; i++) + debug_only_printf(LC_TMTracer, "%c", TypeToChar(fi->get_typemap()[i])); + debug_only_print0(LC_TMTracer, "\n"); +#endif + + updateAtoms(fun->u.i.script); + return RECORD_CONTINUE; +} + +/* + * We implement JSOP_FUNAPPLY/JSOP_FUNCALL using imacros + */ +static inline JSOp +GetCallMode(JSStackFrame *fp) +{ + if (fp->hasImacropc()) { + JSOp op = (JSOp) *fp->imacropc(); + if (op == JSOP_FUNAPPLY || op == JSOP_FUNCALL) + return op; + } + return JSOP_CALL; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_CALL() +{ + uintN argc = GET_ARGC(cx->regs->pc); + cx->assertValidStackDepth(argc + 2); + return InjectStatus(functionCall(argc, GetCallMode(cx->fp()))); +} + +static jsbytecode* funapply_imacro_table[] = { + funapply_imacros.apply0, + funapply_imacros.apply1, + funapply_imacros.apply2, + funapply_imacros.apply3, + funapply_imacros.apply4, + funapply_imacros.apply5, + funapply_imacros.apply6, + funapply_imacros.apply7, + funapply_imacros.apply8 +}; + +static jsbytecode* funcall_imacro_table[] = { + funcall_imacros.call0, + funcall_imacros.call1, + funcall_imacros.call2, + funcall_imacros.call3, + funcall_imacros.call4, + funcall_imacros.call5, + funcall_imacros.call6, + funcall_imacros.call7, + funcall_imacros.call8 +}; + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_FUNCALL() +{ + return record_JSOP_FUNAPPLY(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_FUNAPPLY() +{ + jsbytecode *pc = cx->regs->pc; + uintN argc = GET_ARGC(pc); + cx->assertValidStackDepth(argc + 2); + + Value* vp = cx->regs->sp - (argc + 2); + jsuint length = 0; + JSObject* aobj = NULL; + LIns* aobj_ins = NULL; + + JS_ASSERT(!cx->fp()->hasImacropc()); + + if (!IsFunctionObject(vp[0])) + return record_JSOP_CALL(); + RETURN_IF_XML_A(vp[0]); + + JSObject* obj = &vp[0].toObject(); + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, obj); + if (FUN_INTERPRETED(fun)) + return record_JSOP_CALL(); + + bool apply = fun->u.n.native == js_fun_apply; + if (!apply && fun->u.n.native != js_fun_call) + return record_JSOP_CALL(); + + /* + * We don't trace apply and call with a primitive 'this', which is the + * first positional parameter, unless 'this' is null. That's ok. + */ + if (argc > 0 && !vp[2].isObjectOrNull()) + return record_JSOP_CALL(); + + /* + * Guard on the identity of this, which is the function we are applying. + */ + if (!IsFunctionObject(vp[1])) + RETURN_STOP_A("callee is not a function"); + CHECK_STATUS_A(guardCallee(vp[1])); + + if (apply && argc >= 2) { + if (argc != 2) + RETURN_STOP_A("apply with excess arguments"); + if (vp[3].isPrimitive()) + RETURN_STOP_A("arguments parameter of apply is primitive"); + aobj = &vp[3].toObject(); + aobj_ins = get(&vp[3]); + + /* + * We trace dense arrays and arguments objects. The code we generate + * for apply uses imacros to handle a specific number of arguments. + */ + if (aobj->isDenseArray()) { + guardDenseArray(aobj_ins, MISMATCH_EXIT); + length = aobj->getArrayLength(); + guard(true, + w.eqiN(w.lduiObjPrivate(aobj_ins), length), + BRANCH_EXIT); + } else if (aobj->isArguments()) { + unsigned depth; + JSStackFrame *afp = guardArguments(aobj, aobj_ins, &depth); + if (!afp) + RETURN_STOP_A("can't reach arguments object's frame"); + if (aobj->isArgsLengthOverridden()) + RETURN_STOP_A("can't trace arguments with overridden length"); + guardArgsLengthNotAssigned(aobj_ins); + length = afp->numActualArgs(); + } else { + RETURN_STOP_A("arguments parameter of apply is not a dense array or argments object"); + } + + if (length >= JS_ARRAY_LENGTH(funapply_imacro_table)) + RETURN_STOP_A("too many arguments to apply"); + + return InjectStatus(callImacro(funapply_imacro_table[length])); + } + + if (argc >= JS_ARRAY_LENGTH(funcall_imacro_table)) + RETURN_STOP_A("too many arguments to call"); + + return InjectStatus(callImacro(funcall_imacro_table[argc])); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_NativeCallComplete() +{ + if (pendingSpecializedNative == IGNORE_NATIVE_CALL_COMPLETE_CALLBACK) + return ARECORD_CONTINUE; + +#ifdef DEBUG + JS_ASSERT(pendingSpecializedNative); + jsbytecode* pc = cx->regs->pc; + JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_FUNCALL || *pc == JSOP_FUNAPPLY || + *pc == JSOP_NEW || *pc == JSOP_SETPROP); +#endif + + Value& v = stackval(-1); + LIns* v_ins = get(&v); + + /* + * At this point the generated code has already called the native function + * and we can no longer fail back to the original pc location (JSOP_CALL) + * because that would cause the interpreter to re-execute the native + * function, which might have side effects. + * + * Instead, the snapshot() call below sees that we are currently parked on + * a traceable native's JSOP_CALL instruction, and it will advance the pc + * to restore by the length of the current opcode. If the native's return + * type is jsval, snapshot() will also indicate in the type map that the + * element on top of the stack is a boxed value which doesn't need to be + * boxed if the type guard generated by unbox_value() fails. + */ + + if (JSTN_ERRTYPE(pendingSpecializedNative) == FAIL_STATUS) { + leaveDeepBailCall(); + + LIns* status = w.ldiStateField(builtinStatus); + if (pendingSpecializedNative == &generatedSpecializedNative) { + LIns* ok_ins = v_ins; + + /* + * If we run a generic traceable native, the return value is in the argument + * vector for native function calls. The actual return value of the native is a JSBool + * indicating the error status. + */ + + Address nativeRvalAddr = AllocSlotsAddress(native_rval_ins); + if (pendingSpecializedNative->flags & JSTN_CONSTRUCTOR) { + LIns *cond_ins; + LIns *x; + + // v_ins := the object payload from native_rval_ins + // cond_ins := true if native_rval_ins contains a JSObject* + unbox_any_object(nativeRvalAddr, &v_ins, &cond_ins); + // x := v_ins if native_rval_ins contains a JSObject*, NULL otherwise + x = w.cmovp(cond_ins, v_ins, w.immw(0)); + // v_ins := newobj_ins if native_rval_ins doesn't contain a JSObject*, + // the object payload from native_rval_ins otherwise + v_ins = w.cmovp(w.eqp0(x), newobj_ins, x); + } else { + v_ins = w.ldd(nativeRvalAddr); + } + set(&v, v_ins); + + propagateFailureToBuiltinStatus(ok_ins, status); + } + guard(true, w.eqi0(status), STATUS_EXIT); + } + + if (pendingSpecializedNative->flags & JSTN_UNBOX_AFTER) { + /* + * If we side exit on the unboxing code due to a type change, make sure that the boxed + * value is actually currently associated with that location, and that we are talking + * about the top of the stack here, which is where we expected boxed values. + */ + JS_ASSERT(&v == &cx->regs->sp[-1] && get(&v) == v_ins); + set(&v, unbox_value(v, AllocSlotsAddress(native_rval_ins), snapshot(BRANCH_EXIT))); + } else if (pendingSpecializedNative->flags & + (JSTN_RETURN_NULLABLE_STR | JSTN_RETURN_NULLABLE_OBJ)) { + guard(v.isNull(), + w.name(w.eqp0(v_ins), "guard(nullness)"), + BRANCH_EXIT); + } else if (JSTN_ERRTYPE(pendingSpecializedNative) == FAIL_NEG) { + /* Already added i2d in functionCall. */ + JS_ASSERT(v.isNumber()); + } else { + /* Convert the result to double if the builtin returns int32. */ + if (v.isNumber() && + pendingSpecializedNative->builtin->returnType() == ARGTYPE_I) { + set(&v, w.i2d(v_ins)); + } + } + + // We'll null pendingSpecializedNative in monitorRecording, on the next op + // cycle. There must be a next op since the stack is non-empty. + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::name(Value*& vp, LIns*& ins, NameResult& nr) +{ + JSObject* obj = &cx->fp()->scopeChain(); + JSOp op = JSOp(*cx->regs->pc); + if (js_CodeSpec[op].format & JOF_GNAME) + obj = obj->getGlobal(); + if (obj != globalObj) + return scopeChainProp(obj, vp, ins, nr); + + /* Can't use prop here, because we don't want unboxing from global slots. */ + LIns* obj_ins = w.immpObjGC(globalObj); + uint32 slot; + + JSObject* obj2; + PCVal pcval; + + /* + * Property cache ensures that we are dealing with an existing property, + * and guards the shape for us. + */ + CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval)); + + /* Abort if property doesn't exist (interpreter will report an error.) */ + if (pcval.isNull()) + RETURN_STOP_A("named property not found"); + + /* Insist on obj being the directly addressed object. */ + if (obj2 != obj) + RETURN_STOP_A("name() hit prototype chain"); + + /* Don't trace getter or setter calls, our caller wants a direct slot. */ + if (pcval.isShape()) { + const Shape* shape = pcval.toShape(); + if (!isValidSlot(obj, shape)) + RETURN_STOP_A("name() not accessing a valid slot"); + slot = shape->slot; + } else { + if (!pcval.isSlot()) + RETURN_STOP_A("PCE is not a slot"); + slot = pcval.toSlot(); + } + + if (!lazilyImportGlobalSlot(slot)) + RETURN_STOP_A("lazy import of global slot failed"); + + vp = &obj->getSlotRef(slot); + ins = get(vp); + nr.tracked = true; + return ARECORD_CONTINUE; +} + +static JSObject* FASTCALL +MethodReadBarrier(JSContext* cx, JSObject* obj, Shape* shape, JSObject* funobj) +{ + Value v = ObjectValue(*funobj); + AutoValueRooter tvr(cx, v); + + if (!obj->methodReadBarrier(cx, *shape, tvr.addr())) + return NULL; + return &tvr.value().toObject(); +} +JS_DEFINE_CALLINFO_4(static, OBJECT_FAIL, MethodReadBarrier, CONTEXT, OBJECT, SHAPE, OBJECT, + 0, ACCSET_STORE_ANY) + +/* + * Get a property. The current opcode has JOF_ATOM. + * + * There are two modes. The caller must pass nonnull pointers for either outp + * or both slotp and v_insp. In the latter case, we require a plain old + * property with a slot; if the property turns out to be anything else, abort + * tracing (rather than emit a call to a native getter or GetAnyProperty). + */ +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, Value *outp) +{ + /* + * Insist that obj have js_SetProperty as its set object-op. This suffices + * to prevent a rogue obj from being used on-trace (loaded via obj_ins), + * because we will guard on shape (or else global object identity) and any + * object not having the same op must have a different class, and therefore + * must differ in its shape (or not be the global object). + */ + if (!obj->isDenseArray() && obj->getOps()->getProperty) + RETURN_STOP_A("non-dense-array, non-native js::ObjectOps::getProperty"); + + JS_ASSERT((slotp && v_insp && !outp) || (!slotp && !v_insp && outp)); + + /* + * Property cache ensures that we are dealing with an existing property, + * and guards the shape for us. + */ + JSObject* obj2; + PCVal pcval; + CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval)); + + /* Check for nonexistent property reference, which results in undefined. */ + if (pcval.isNull()) { + if (slotp) + RETURN_STOP_A("property not found"); + + /* + * We could specialize to guard on just JSClass.getProperty, but a mere + * class guard is simpler and slightly faster. + */ + if (obj->getClass()->getProperty != Valueify(JS_PropertyStub)) { + RETURN_STOP_A("can't trace through access to undefined property if " + "JSClass.getProperty hook isn't stubbed"); + } + guardClass(obj_ins, obj->getClass(), snapshot(MISMATCH_EXIT), LOAD_NORMAL); + + /* + * This trace will be valid as long as neither the object nor any object + * on its prototype chain changes shape. + * + * FIXME: This loop can become a single shape guard once bug 497789 has + * been fixed. + */ + VMSideExit* exit = snapshot(BRANCH_EXIT); + do { + if (obj->isNative()) { + CHECK_STATUS_A(guardShape(obj_ins, obj, obj->shape(), "guard(shape)", exit)); + } else if (obj->isDenseArray()) { + guardDenseArray(obj_ins, exit); + } else { + RETURN_STOP_A("non-native object involved in undefined property access"); + } + } while (guardHasPrototype(obj, obj_ins, &obj, &obj_ins, exit)); + + set(outp, w.immiUndefined()); + return ARECORD_CONTINUE; + } + + return InjectStatus(propTail(obj, obj_ins, obj2, pcval, slotp, v_insp, outp)); +} + +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, PCVal pcval, + uint32 *slotp, LIns** v_insp, Value *outp) +{ + const JSCodeSpec& cs = js_CodeSpec[*cx->regs->pc]; + uint32 setflags = (cs.format & (JOF_INCDEC | JOF_FOR)); + JS_ASSERT(!(cs.format & JOF_SET)); + + const Shape* shape; + uint32 slot; + bool isMethod; + + if (pcval.isShape()) { + shape = pcval.toShape(); + JS_ASSERT(obj2->nativeContains(*shape)); + + if (setflags && !shape->hasDefaultSetter()) + RETURN_STOP("non-stub setter"); + if (setflags && !shape->writable()) + RETURN_STOP("writing to a readonly property"); + if (!shape->hasDefaultGetterOrIsMethod()) { + if (slotp) + RETURN_STOP("can't trace non-stub getter for this opcode"); + if (shape->hasGetterValue()) + return getPropertyWithScriptGetter(obj, obj_ins, shape); + if (shape->slot == SHAPE_INVALID_SLOT) + return getPropertyWithNativeGetter(obj_ins, shape, outp); + return getPropertyById(obj_ins, outp); + } + if (!obj2->containsSlot(shape->slot)) + RETURN_STOP("no valid slot"); + slot = shape->slot; + isMethod = shape->isMethod(); + JS_ASSERT_IF(isMethod, obj2->hasMethodBarrier()); + } else { + if (!pcval.isSlot()) + RETURN_STOP("PCE is not a slot"); + slot = pcval.toSlot(); + shape = NULL; + isMethod = false; + } + + /* We have a slot. Check whether it is direct or in a prototype. */ + if (obj2 != obj) { + if (setflags) + RETURN_STOP("JOF_INCDEC|JOF_FOR opcode hit prototype chain"); + + /* + * We're getting a prototype property. Two cases: + * + * 1. If obj2 is obj's immediate prototype we must walk up from obj, + * since direct and immediate-prototype cache hits key on obj's shape, + * not its identity. + * + * 2. Otherwise obj2 is higher up the prototype chain and we've keyed + * on obj's identity, and since setting __proto__ reshapes all objects + * along the old prototype chain, then provided we shape-guard obj2, + * we can "teleport" directly to obj2 by embedding it as a constant + * (this constant object instruction will be CSE'ed with the constant + * emitted by test_property_cache, whose shape is guarded). + */ + obj_ins = (obj2 == obj->getProto()) ? w.ldpObjProto(obj_ins) : w.immpObjGC(obj2); + obj = obj2; + } + + LIns* v_ins; + if (obj2 == globalObj) { + if (isMethod) + RETURN_STOP("get global method"); + if (!lazilyImportGlobalSlot(slot)) + RETURN_STOP("lazy import of global slot failed"); + v_ins = get(&globalObj->getSlotRef(slot)); + } else { + v_ins = unbox_slot(obj, obj_ins, slot, snapshot(BRANCH_EXIT)); + } + + /* + * Joined function object stored as a method must be cloned when extracted + * as a property value other than a callee. Note that shapes cover method + * value as well as other property attributes and order, so this condition + * is trace-invariant. + * + * We do not impose the method read barrier if in an imacro, assuming any + * property gets it does (e.g., for 'toString' from JSOP_NEW) will not be + * leaked to the calling script. + */ + if (isMethod && !cx->fp()->hasImacropc()) { + enterDeepBailCall(); + LIns* args[] = { v_ins, w.immpShapeGC(shape), obj_ins, cx_ins }; + v_ins = w.call(&MethodReadBarrier_ci, args); + leaveDeepBailCall(); + } + + if (slotp) { + *slotp = slot; + *v_insp = v_ins; + } + if (outp) + set(outp, v_ins); + return RECORD_CONTINUE; +} + +/* + * When we end up with a hole, read it as undefined, and make sure to set + * addr_ins to null. + */ +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::denseArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_ins, + LIns*& addr_ins, VMSideExit* branchExit) +{ + JS_ASSERT(oval.isObject() && ival.isInt32()); + + JSObject* obj = &oval.toObject(); + LIns* obj_ins = get(&oval); + jsint idx = ival.toInt32(); + LIns* idx_ins; + CHECK_STATUS(makeNumberInt32(get(&ival), &idx_ins)); + + /* + * Arrays have both a length and a capacity, but we only need to check + * |index < capacity|; in the case where |length < index < capacity| + * the entries [length..capacity-1] will have already been marked as + * holes by resizeDenseArrayElements() so we can read them and get + * the correct value. + */ + LIns* capacity_ins = w.ldiDenseArrayCapacity(obj_ins); + jsuint capacity = obj->getDenseArrayCapacity(); + bool within = (jsuint(idx) < capacity); + if (!within) { + /* If not idx < capacity, stay on trace (and read value as undefined). */ + guard(true, w.geui(idx_ins, capacity_ins), branchExit); + + CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, snapshot(MISMATCH_EXIT))); + + v_ins = w.immiUndefined(); + addr_ins = NULL; + return RECORD_CONTINUE; + } + + /* Guard that index is within capacity. */ + guard(true, w.name(w.ltui(idx_ins, capacity_ins), "inRange"), branchExit); + + /* Load the value and guard on its type to unbox it. */ + vp = &obj->slots[jsuint(idx)]; + JS_ASSERT(sizeof(Value) == 8); // The |3| in the following statement requires this. + addr_ins = w.name(w.getDslotAddress(obj_ins, idx_ins), "elemp"); + v_ins = unbox_value(*vp, DSlotsAddress(addr_ins), branchExit); + + /* Don't let the hole value escape. Turn it into an undefined. */ + if (vp->isMagic()) { + CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, snapshot(MISMATCH_EXIT))); + v_ins = w.immiUndefined(); + addr_ins = NULL; + } + return RECORD_CONTINUE; +} + +/* See comments in TypedArrayTemplate::copyIndexToValue. */ +LIns * +TraceRecorder::canonicalizeNaNs(LIns *dval_ins) +{ + /* NaNs are the only floating point values that do not == themselves. */ + LIns *isnonnan_ins = w.eqd(dval_ins, dval_ins); + return w.cmovd(isnonnan_ins, dval_ins, w.immd(js_NaN)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::typedArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_ins) +{ + JS_ASSERT(oval.isObject() && ival.isInt32()); + + JSObject* obj = &oval.toObject(); + LIns* obj_ins = get(&oval); + jsint idx = ival.toInt32(); + LIns* idx_ins; + CHECK_STATUS_A(makeNumberInt32(get(&ival), &idx_ins)); + LIns* pidx_ins = w.ui2p(idx_ins); + + js::TypedArray* tarray = js::TypedArray::fromJSObject(obj); + JS_ASSERT(tarray); + + /* priv_ins will load the TypedArray* */ + LIns* priv_ins = w.ldpObjPrivate(obj_ins); + + /* for out-of-range, do the same thing that the interpreter does, which is return undefined */ + if ((jsuint) idx >= tarray->length) { + CHECK_STATUS_A(guard(false, + w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)), + BRANCH_EXIT, + /* abortIfAlwaysExits = */true)); + v_ins = w.immiUndefined(); + return ARECORD_CONTINUE; + } + + /* + * Ensure idx < length + * + * NOTE! mLength is uint32, but it's guaranteed to fit in a Value + * int, so we can treat it as either signed or unsigned. + * If the index happens to be negative, when it's treated as + * unsigned it'll be a very large int, and thus won't be less than + * length. + */ + guard(true, + w.name(w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)), "inRange"), + BRANCH_EXIT); + + /* We are now ready to load. Do a different type of load + * depending on what type of thing we're loading. */ + LIns* data_ins = w.ldpConstTypedArrayData(priv_ins); + + switch (tarray->type) { + case js::TypedArray::TYPE_INT8: + v_ins = w.i2d(w.ldc2iTypedArrayElement(data_ins, pidx_ins)); + break; + case js::TypedArray::TYPE_UINT8: + case js::TypedArray::TYPE_UINT8_CLAMPED: + // i2d on purpose here: it's safe, because an 8-bit uint is guaranteed + // to fit in a 32-bit int, and i2d gets more optimization than ui2d. + v_ins = w.i2d(w.lduc2uiTypedArrayElement(data_ins, pidx_ins)); + break; + case js::TypedArray::TYPE_INT16: + v_ins = w.i2d(w.lds2iTypedArrayElement(data_ins, pidx_ins)); + break; + case js::TypedArray::TYPE_UINT16: + // i2d on purpose here: it's safe, because a 16-bit uint is guaranteed + // to fit in a 32-bit int, and i2d gets more optimization than ui2d. + v_ins = w.i2d(w.ldus2uiTypedArrayElement(data_ins, pidx_ins)); + break; + case js::TypedArray::TYPE_INT32: + v_ins = w.i2d(w.ldiTypedArrayElement(data_ins, pidx_ins)); + break; + case js::TypedArray::TYPE_UINT32: + v_ins = w.ui2d(w.ldiTypedArrayElement(data_ins, pidx_ins)); + break; + case js::TypedArray::TYPE_FLOAT32: + v_ins = canonicalizeNaNs(w.ldf2dTypedArrayElement(data_ins, pidx_ins)); + break; + case js::TypedArray::TYPE_FLOAT64: + v_ins = canonicalizeNaNs(w.lddTypedArrayElement(data_ins, pidx_ins)); + break; + default: + JS_NOT_REACHED("Unknown typed array type in tracer"); + } + + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::getProp(JSObject* obj, LIns* obj_ins) +{ + JSOp op = JSOp(*cx->regs->pc); + const JSCodeSpec& cs = js_CodeSpec[op]; + + JS_ASSERT(cs.ndefs == 1); + return prop(obj, obj_ins, NULL, NULL, &stackval(-cs.nuses)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::getProp(Value& v) +{ + if (v.isPrimitive()) + RETURN_STOP_A("primitive lhs"); + + return getProp(&v.toObject(), get(&v)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_NAME() +{ + Value* vp; + LIns* v_ins; + NameResult nr; + CHECK_STATUS_A(name(vp, v_ins, nr)); + stack(0, v_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DOUBLE() +{ + double d = consts[GET_INDEX(cx->regs->pc)].toDouble(); + stack(0, w.immd(d)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_STRING() +{ + JSAtom* atom = atoms[GET_INDEX(cx->regs->pc)]; + stack(0, w.immpAtomGC(atom)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ZERO() +{ + stack(0, w.immd(0)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ONE() +{ + stack(0, w.immd(1)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_NULL() +{ + stack(0, w.immpNull()); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_THIS() +{ + LIns* this_ins; + CHECK_STATUS_A(getThis(this_ins)); + stack(0, this_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_FALSE() +{ + stack(0, w.immi(0)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_TRUE() +{ + stack(0, w.immi(1)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_OR() +{ + return ifop(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_AND() +{ + return ifop(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_TABLESWITCH() +{ +#ifdef NANOJIT_IA32 + /* Handle tableswitches specially -- prepare a jump table if needed. */ + return tableswitch(); +#else + return InjectStatus(switchop()); +#endif +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_LOOKUPSWITCH() +{ + return InjectStatus(switchop()); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_STRICTEQ() +{ + CHECK_STATUS_A(strictEquality(true, false)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_STRICTNE() +{ + CHECK_STATUS_A(strictEquality(false, false)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_OBJECT() +{ + JSStackFrame* const fp = cx->fp(); + JSScript* script = fp->script(); + unsigned index = atoms - script->atomMap.vector + GET_INDEX(cx->regs->pc); + + JSObject* obj; + obj = script->getObject(index); + stack(0, w.immpObjGC(obj)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_POP() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_TRAP() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GETARG() +{ + stack(0, arg(GET_ARGNO(cx->regs->pc))); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SETARG() +{ + arg(GET_ARGNO(cx->regs->pc), stack(-1)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GETLOCAL() +{ + stack(0, var(GET_SLOTNO(cx->regs->pc))); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SETLOCAL() +{ + var(GET_SLOTNO(cx->regs->pc), stack(-1)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_UINT16() +{ + stack(0, w.immd(GET_UINT16(cx->regs->pc))); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_NEWINIT() +{ + initDepth++; + hadNewInit = true; + + JSProtoKey key = JSProtoKey(cx->regs->pc[1]); + + LIns* proto_ins; + CHECK_STATUS_A(getClassPrototype(key, proto_ins)); + + LIns *v_ins; + if (key == JSProto_Array) { + LIns *args[] = { proto_ins, cx_ins }; + v_ins = w.call(&NewDenseEmptyArray_ci, args); + } else { + LIns *args[] = { w.immpNull(), proto_ins, cx_ins }; + v_ins = w.call(&js_InitializerObject_ci, args); + } + guard(false, w.eqp0(v_ins), OOM_EXIT); + stack(0, v_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_NEWARRAY() +{ + initDepth++; + + LIns* proto_ins; + CHECK_STATUS_A(getClassPrototype(JSProto_Array, proto_ins)); + + unsigned count = GET_UINT24(cx->regs->pc); + LIns *args[] = { proto_ins, w.immi(count), cx_ins }; + LIns *v_ins = w.call(&NewDenseAllocatedArray_ci, args); + + guard(false, w.eqp0(v_ins), OOM_EXIT); + stack(0, v_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_NEWOBJECT() +{ + initDepth++; + + LIns* proto_ins; + CHECK_STATUS_A(getClassPrototype(JSProto_Object, proto_ins)); + + JSObject* baseobj = cx->fp()->script()->getObject(getFullIndex(0)); + + LIns *args[] = { w.immpObjGC(baseobj), proto_ins, cx_ins }; + LIns *v_ins = w.call(&js_InitializerObject_ci, args); + + guard(false, w.eqp0(v_ins), OOM_EXIT); + stack(0, v_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ENDINIT() +{ + initDepth--; + if (initDepth == 0) + hadNewInit = false; + +#ifdef DEBUG + Value& v = stackval(-1); + JS_ASSERT(!v.isPrimitive()); +#endif + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INITELEM() +{ + Value& v = stackval(-1); + Value& idx = stackval(-2); + Value& lval = stackval(-3); + + // The object is either a dense Array or an Object. Only handle the dense case here. + // Also skip array initializers which might be unoptimized NEWINIT initializers. + if (!lval.toObject().isDenseArray() || hadNewInit) + return setElem(-3, -2, -1); + + // The index is always the same constant integer. + JS_ASSERT(idx.isInt32()); + + // Nothing to do for holes, the array's length has already been set. + if (v.isMagic(JS_ARRAY_HOLE)) + return ARECORD_CONTINUE; + + LIns* obj_ins = get(&lval); + LIns* v_ins = get(&v); + + // Set the element. + LIns *slots_ins = w.ldpObjSlots(obj_ins); + box_value_into(v, v_ins, DSlotsAddress(slots_ins, idx.toInt32())); + + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DEFSHARP() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_USESHARP() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INCARG() +{ + return InjectStatus(inc(argval(GET_ARGNO(cx->regs->pc)), 1)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INCLOCAL() +{ + return InjectStatus(inc(varval(GET_SLOTNO(cx->regs->pc)), 1)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DECARG() +{ + return InjectStatus(inc(argval(GET_ARGNO(cx->regs->pc)), -1)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DECLOCAL() +{ + return InjectStatus(inc(varval(GET_SLOTNO(cx->regs->pc)), -1)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ARGINC() +{ + return InjectStatus(inc(argval(GET_ARGNO(cx->regs->pc)), 1, false)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_LOCALINC() +{ + return InjectStatus(inc(varval(GET_SLOTNO(cx->regs->pc)), 1, false)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ARGDEC() +{ + return InjectStatus(inc(argval(GET_ARGNO(cx->regs->pc)), -1, false)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_LOCALDEC() +{ + return InjectStatus(inc(varval(GET_SLOTNO(cx->regs->pc)), -1, false)); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_IMACOP() +{ + JS_ASSERT(cx->fp()->hasImacropc()); + return ARECORD_CONTINUE; +} + +static JSBool FASTCALL +ObjectToIterator(JSContext* cx, JSObject *obj, int32 flags, Value* vp) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + vp->setObject(*obj); + bool ok = js_ValueToIterator(cx, flags, vp); + if (!ok) { + SetBuiltinError(tm); + return false; + } + return WasBuiltinSuccessful(tm); +} +JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, ObjectToIterator, CONTEXT, OBJECT, INT32, VALUEPTR, + 0, ACCSET_STORE_ANY) + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ITER() +{ + Value& v = stackval(-1); + if (v.isPrimitive()) + RETURN_STOP_A("for-in on a primitive value"); + + RETURN_IF_XML_A(v); + + LIns *obj_ins = get(&v); + jsuint flags = cx->regs->pc[1]; + + enterDeepBailCall(); + + LIns* vp_ins = w.allocp(sizeof(Value)); + LIns* args[] = { vp_ins, w.immi(flags), obj_ins, cx_ins }; + LIns* ok_ins = w.call(&ObjectToIterator_ci, args); + + // We need to guard on ok_ins, but this requires a snapshot of the state + // after this op. monitorRecording will do it for us. + pendingGuardCondition = ok_ins; + + // ObjectToIterator can deep-bail without throwing, leaving a value of + // unknown type in *vp (it can be either a function or a non-function + // object). Use the same mechanism as finishGetProp to arrange for + // LeaveTree to deal with this value. + pendingUnboxSlot = cx->regs->sp - 1; + set(pendingUnboxSlot, w.name(w.lddAlloc(vp_ins), "iterval")); + + leaveDeepBailCall(); + + return ARECORD_CONTINUE; +} + +static JSBool FASTCALL +IteratorMore(JSContext *cx, JSObject *iterobj, Value *vp) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + if (!js_IteratorMore(cx, iterobj, vp)) { + SetBuiltinError(tm); + return false; + } + return WasBuiltinSuccessful(tm); +} +JS_DEFINE_CALLINFO_3(extern, BOOL_FAIL, IteratorMore, CONTEXT, OBJECT, VALUEPTR, + 0, ACCSET_STORE_ANY) + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_MOREITER() +{ + Value& iterobj_val = stackval(-1); + if (iterobj_val.isPrimitive()) + RETURN_STOP_A("for-in on a primitive value"); + + RETURN_IF_XML_A(iterobj_val); + + JSObject* iterobj = &iterobj_val.toObject(); + LIns* iterobj_ins = get(&iterobj_val); + LIns* cond_ins; + + /* + * JSOP_FOR* already guards on this, but in certain rare cases we might + * record misformed loop traces. Note that it's not necessary to guard on + * ni->flags (nor do we in unboxNextValue), because the different + * iteration type will guarantee a different entry typemap. + */ + if (iterobj->hasClass(&js_IteratorClass)) { + guardClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); + + NativeIterator *ni = (NativeIterator *) iterobj->getPrivate(); + if (ni->isKeyIter()) { + LIns *ni_ins = w.ldpObjPrivate(iterobj_ins); + LIns *cursor_ins = w.ldpIterCursor(ni_ins); + LIns *end_ins = w.ldpIterEnd(ni_ins); + + cond_ins = w.ltp(cursor_ins, end_ins); + stack(0, cond_ins); + return ARECORD_CONTINUE; + } + } else { + guardNotClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); + } + + enterDeepBailCall(); + + LIns* vp_ins = w.allocp(sizeof(Value)); + LIns* args[] = { vp_ins, iterobj_ins, cx_ins }; + pendingGuardCondition = w.call(&IteratorMore_ci, args); + + leaveDeepBailCall(); + + cond_ins = is_boxed_true(AllocSlotsAddress(vp_ins)); + stack(0, cond_ins); + + // Write this value back even though we haven't changed it. + // See the comment in DeepBail about "clobbering deep bails". + stack(-1, iterobj_ins); + + return ARECORD_CONTINUE; +} + +static JSBool FASTCALL +CloseIterator(JSContext *cx, JSObject *iterobj) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + if (!js_CloseIterator(cx, iterobj)) { + SetBuiltinError(tm); + return false; + } + return WasBuiltinSuccessful(tm); +} +JS_DEFINE_CALLINFO_2(extern, BOOL_FAIL, CloseIterator, CONTEXT, OBJECT, 0, ACCSET_STORE_ANY) + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ENDITER() +{ + JS_ASSERT(!stackval(-1).isPrimitive()); + + enterDeepBailCall(); + + LIns* args[] = { stack(-1), cx_ins }; + LIns* ok_ins = w.call(&CloseIterator_ci, args); + + // We need to guard on ok_ins, but this requires a snapshot of the state + // after this op. monitorRecording will do it for us. + pendingGuardCondition = ok_ins; + + leaveDeepBailCall(); + + return ARECORD_CONTINUE; +} + +#if JS_BITS_PER_WORD == 32 +JS_REQUIRES_STACK void +TraceRecorder::storeMagic(JSWhyMagic why, Address addr) +{ + w.stiValuePayload(w.immpMagicWhy(why), addr); + w.stiValueTag(w.immpMagicWhy(JSVAL_TAG_MAGIC), addr); +} +#elif JS_BITS_PER_WORD == 64 +JS_REQUIRES_STACK void +TraceRecorder::storeMagic(JSWhyMagic why, Address addr) +{ + LIns *magic = w.nameImmq(BUILD_JSVAL(JSVAL_TAG_MAGIC, why)); + w.stq(magic, addr); +} +#endif + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::unboxNextValue(LIns* &v_ins) +{ + Value &iterobj_val = stackval(-1); + JSObject *iterobj = &iterobj_val.toObject(); + LIns* iterobj_ins = get(&iterobj_val); + + if (iterobj->hasClass(&js_IteratorClass)) { + guardClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); + NativeIterator *ni = (NativeIterator *) iterobj->getPrivate(); + + LIns *ni_ins = w.ldpObjPrivate(iterobj_ins); + LIns *cursor_ins = w.ldpIterCursor(ni_ins); + + /* Emit code to stringify the id if necessary. */ + Address cursorAddr = IterPropsAddress(cursor_ins); + if (ni->isKeyIter()) { + /* Read the next id from the iterator. */ + jsid id = *ni->current(); + LIns *id_ins = w.name(w.ldp(cursorAddr), "id"); + + /* + * Most iterations over object properties never have to actually deal with + * any numeric properties, so we guard here instead of branching. + */ + guard(JSID_IS_STRING(id), is_string_id(id_ins), BRANCH_EXIT); + + if (JSID_IS_STRING(id)) { + v_ins = unbox_string_id(id_ins); + } else if (JSID_IS_INT(id)) { + /* id is an integer, convert to a string. */ + LIns *id_to_int_ins = unbox_int_id(id_ins); + LIns* args[] = { id_to_int_ins, cx_ins }; + v_ins = w.call(&js_IntToString_ci, args); + guard(false, w.eqp0(v_ins), OOM_EXIT); + } else { +#if JS_HAS_XML_SUPPORT + JS_ASSERT(JSID_IS_OBJECT(id)); + JS_ASSERT(JSID_TO_OBJECT(id)->isXMLId()); + RETURN_STOP_A("iterated over a property with an XML id"); +#else + JS_NEVER_REACHED("unboxNextValue"); +#endif + } + + /* Increment the cursor by one jsid and store it back. */ + cursor_ins = w.addp(cursor_ins, w.nameImmw(sizeof(jsid))); + w.stpIterCursor(cursor_ins, ni_ins); + return ARECORD_CONTINUE; + } + } else { + guardNotClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); + } + + + Address iterValueAddr = CxAddress(iterValue); + v_ins = unbox_value(cx->iterValue, iterValueAddr, snapshot(BRANCH_EXIT)); + storeMagic(JS_NO_ITER_VALUE, iterValueAddr); + + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_FORNAME() +{ + Value* vp; + LIns* x_ins; + NameResult nr; + CHECK_STATUS_A(name(vp, x_ins, nr)); + if (!nr.tracked) + RETURN_STOP_A("forname on non-tracked value not supported"); + LIns* v_ins; + CHECK_STATUS_A(unboxNextValue(v_ins)); + set(vp, v_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_FORGNAME() +{ + return record_JSOP_FORNAME(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_FORPROP() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_FORELEM() +{ + LIns* v_ins; + CHECK_STATUS_A(unboxNextValue(v_ins)); + stack(0, v_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_FORARG() +{ + LIns* v_ins; + CHECK_STATUS_A(unboxNextValue(v_ins)); + arg(GET_ARGNO(cx->regs->pc), v_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_FORLOCAL() +{ + LIns* v_ins; + CHECK_STATUS_A(unboxNextValue(v_ins)); + var(GET_SLOTNO(cx->regs->pc), v_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_POPN() +{ + return ARECORD_CONTINUE; +} + +static inline bool +IsFindableCallObj(JSObject *obj) +{ + return obj->isCall() && + (obj->callIsForEval() || obj->getCallObjCalleeFunction()->isHeavyweight()); +} + +/* + * Generate LIR to reach |obj2| from |obj| by traversing the scope chain. The + * generated code also ensures that any call objects found have not changed shape. + * + * obj starting object + * obj_ins LIR instruction representing obj + * targetObj end object for traversal + * targetIns [out] LIR instruction representing obj2 + */ +JS_REQUIRES_STACK RecordingStatus +TraceRecorder::traverseScopeChain(JSObject *obj, LIns *obj_ins, JSObject *targetObj, + LIns *&targetIns) +{ + VMSideExit* exit = NULL; + + /* + * Scope chains are often left "incomplete", and reified lazily when + * necessary, since doing so is expensive. When creating null and flat + * closures on trace (the only kinds supported), the global object is + * hardcoded as the parent, since reifying the scope chain on trace + * would be extremely difficult. This is because block objects need frame + * pointers, which do not exist on trace, and thus would require magic + * similar to arguments objects or reification of stack frames. Luckily, + * for null and flat closures, these blocks are unnecessary. + * + * The problem, as exposed by bug 523793, is that this means creating a + * fixed traversal on trace can be inconsistent with the shorter scope + * chain used when executing a trace. To address this, perform an initial + * sweep of the scope chain to make sure that if there is a heavyweight + * function with a call object, and there is also a block object, the + * trace is safely aborted. + * + * If there is no call object, we must have arrived at the global object, + * and can bypass the scope chain traversal completely. + */ + bool foundCallObj = false; + bool foundBlockObj = false; + JSObject* searchObj = obj; + + for (;;) { + if (searchObj != globalObj) { + if (searchObj->isBlock()) + foundBlockObj = true; + else if (IsFindableCallObj(searchObj)) + foundCallObj = true; + } + + if (searchObj == targetObj) + break; + + searchObj = searchObj->getParent(); + if (!searchObj) + RETURN_STOP("cannot traverse this scope chain on trace"); + } + + if (!foundCallObj) { + JS_ASSERT(targetObj == globalObj); + targetIns = w.nameImmpNonGC(globalObj); + return RECORD_CONTINUE; + } + + if (foundBlockObj) + RETURN_STOP("cannot traverse this scope chain on trace"); + + /* There was a call object, or should be a call object now. */ + for (;;) { + if (obj != globalObj) { + if (!IsCacheableNonGlobalScope(obj)) + RETURN_STOP("scope chain lookup crosses non-cacheable object"); + + // We must guard on the shape of all call objects for heavyweight functions + // that we traverse on the scope chain: if the shape changes, a variable with + // the same name may have been inserted in the scope chain. + if (IsFindableCallObj(obj)) { + if (!exit) + exit = snapshot(BRANCH_EXIT); + guard(true, + w.name(w.eqiN(w.ldiObjShape(obj_ins), obj->shape()), "guard_shape"), + exit); + } + } + + JS_ASSERT(!obj->isBlock()); + + if (obj == targetObj) + break; + + obj = obj->getParent(); + obj_ins = w.ldpObjParent(obj_ins); + } + + targetIns = obj_ins; + return RECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_BINDNAME() +{ + TraceMonitor *localtm = traceMonitor; + JSStackFrame* const fp = cx->fp(); + JSObject *obj; + + if (!fp->isFunctionFrame()) { + obj = &fp->scopeChain(); + +#ifdef DEBUG + JSStackFrame *fp2 = fp; +#endif + + /* + * In global code, fp->scopeChain can only contain blocks whose values + * are still on the stack. We never use BINDNAME to refer to these. + */ + while (obj->isBlock()) { + // The block's values are still on the stack. +#ifdef DEBUG + // NB: fp2 can't be a generator frame, because !fp->hasFunction. + while (obj->getPrivate() != fp2) { + JS_ASSERT(fp2->isEvalOrDebuggerFrame()); + fp2 = fp2->prev(); + if (!fp2) + JS_NOT_REACHED("bad stack frame"); + } +#endif + obj = obj->getParent(); + // Blocks always have parents. + JS_ASSERT(obj); + } + + /* + * If this is a strict mode eval frame, we will have a Call object for + * it. For now just don't trace this case. + */ + if (obj != globalObj) { + JS_ASSERT(obj->isCall()); + JS_ASSERT(obj->callIsForEval()); + RETURN_STOP_A("BINDNAME within strict eval code"); + } + + /* + * The trace is specialized to this global object. Furthermore, we know + * it is the sole 'global' object on the scope chain: we set globalObj + * to the scope chain element with no parent, and we reached it + * starting from the function closure or the current scopeChain, so + * there is nothing inner to it. Therefore this must be the right base + * object. + */ + stack(0, w.immpObjGC(obj)); + return ARECORD_CONTINUE; + } + + // We can't trace BINDNAME in functions that contain direct calls to eval, + // as they might add bindings which previously-traced references would have + // to see. + if (JSFUN_HEAVYWEIGHT_TEST(fp->fun()->flags)) + RETURN_STOP_A("BINDNAME in heavyweight function."); + + // We don't have the scope chain on trace, so instead we get a start object + // that is on the scope chain and doesn't skip the target object (the one + // that contains the property). + Value *callee = &cx->fp()->calleeValue(); + obj = callee->toObject().getParent(); + if (obj == globalObj) { + stack(0, w.immpObjGC(obj)); + return ARECORD_CONTINUE; + } + LIns *obj_ins = w.ldpObjParent(get(callee)); + + // Find the target object. + JSAtom *atom = atoms[GET_INDEX(cx->regs->pc)]; + jsid id = ATOM_TO_JSID(atom); + JSObject *obj2 = js_FindIdentifierBase(cx, &fp->scopeChain(), id); + if (!obj2) + RETURN_ERROR_A("error in js_FindIdentifierBase"); + if (!localtm->recorder) + return ARECORD_ABORTED; + if (obj2 != globalObj && !obj2->isCall()) + RETURN_STOP_A("BINDNAME on non-global, non-call object"); + + // Generate LIR to get to the target object from the start object. + LIns *obj2_ins; + CHECK_STATUS_A(traverseScopeChain(obj, obj_ins, obj2, obj2_ins)); + + // If |obj2| is the global object, we can refer to it directly instead of walking up + // the scope chain. There may still be guards on intervening call objects. + stack(0, obj2 == globalObj ? w.immpObjGC(obj2) : obj2_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_THROW() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_IN() +{ + Value& rval = stackval(-1); + Value& lval = stackval(-2); + + if (rval.isPrimitive()) + RETURN_STOP_A("JSOP_IN on non-object right operand"); + JSObject* obj = &rval.toObject(); + LIns* obj_ins = get(&rval); + + jsid id; + LIns* x; + if (lval.isInt32()) { + if (!js_Int32ToId(cx, lval.toInt32(), &id)) + RETURN_ERROR_A("OOM converting left operand of JSOP_IN to string"); + + if (obj->isDenseArray()) { + // Fast path for dense arrays + VMSideExit* branchExit = snapshot(BRANCH_EXIT); + guardDenseArray(obj_ins, branchExit); + + // If our proto has indexed props, all bets are off on our + // "false" values and out-of-bounds access. Just guard on + // that. + CHECK_STATUS_A(guardPrototypeHasNoIndexedProperties(obj, obj_ins, + snapshot(MISMATCH_EXIT))); + + LIns* idx_ins; + CHECK_STATUS_A(makeNumberInt32(get(&lval), &idx_ins)); + idx_ins = w.name(idx_ins, "index"); + LIns* capacity_ins = w.ldiDenseArrayCapacity(obj_ins); + LIns* inRange = w.ltui(idx_ins, capacity_ins); + + if (jsuint(lval.toInt32()) < obj->getDenseArrayCapacity()) { + guard(true, inRange, branchExit); + + LIns *elem_ins = w.getDslotAddress(obj_ins, idx_ins); + // Need to make sure we don't have a hole + LIns *is_hole_ins = + is_boxed_magic(DSlotsAddress(elem_ins), JS_ARRAY_HOLE); + + // Set x to true (index in our array) if is_hole_ins == 0 + x = w.eqi0(is_hole_ins); + } else { + guard(false, inRange, branchExit); + x = w.nameImmi(0); + } + } else { + LIns* num_ins; + CHECK_STATUS_A(makeNumberInt32(get(&lval), &num_ins)); + LIns* args[] = { num_ins, obj_ins, cx_ins }; + x = w.call(&js_HasNamedPropertyInt32_ci, args); + } + } else if (lval.isString()) { + if (!js_ValueToStringId(cx, lval, &id)) + RETURN_ERROR_A("left operand of JSOP_IN didn't convert to a string-id"); + LIns* args[] = { get(&lval), obj_ins, cx_ins }; + x = w.call(&js_HasNamedProperty_ci, args); + } else { + RETURN_STOP_A("string or integer expected"); + } + + guard(false, w.eqiN(x, JS_NEITHER), OOM_EXIT); + x = w.eqiN(x, 1); + + TraceMonitor &localtm = *traceMonitor; + + JSObject* obj2; + JSProperty* prop; + JSBool ok = obj->lookupProperty(cx, id, &obj2, &prop); + + if (!ok) + RETURN_ERROR_A("obj->lookupProperty failed in JSOP_IN"); + + /* lookupProperty can reenter the interpreter and kill |this|. */ + if (!localtm.recorder) + return ARECORD_ABORTED; + + bool cond = prop != NULL; + + /* + * The interpreter fuses comparisons and the following branch, so we have + * to do that here as well. + */ + jsbytecode *pc = cx->regs->pc; + fuseIf(pc + 1, cond, x); + + /* If the branch was to a loop header, we may need to close it. */ + if (pc[1] == JSOP_IFNE || pc[1] == JSOP_IFEQ) + CHECK_STATUS_A(checkTraceEnd(pc + 1)); + + /* + * We update the stack after the guard. This is safe since the guard bails + * out at the comparison and the interpreter will therefore re-execute the + * comparison. This way the value of the condition doesn't have to be + * calculated and saved on the stack in most cases. + */ + set(&lval, x); + return ARECORD_CONTINUE; +} + +static JSBool FASTCALL +HasInstanceOnTrace(JSContext* cx, JSObject* ctor, ValueArgType arg) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx); + + const Value &argref = ValueArgToConstRef(arg); + JSBool result = JS_FALSE; + if (!HasInstance(cx, ctor, &argref, &result)) + SetBuiltinError(tm); + return result; +} +JS_DEFINE_CALLINFO_3(static, BOOL_FAIL, HasInstanceOnTrace, CONTEXT, OBJECT, VALUE, + 0, ACCSET_STORE_ANY) + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INSTANCEOF() +{ + // If the rhs isn't an object, we are headed for a TypeError. + Value& ctor = stackval(-1); + if (ctor.isPrimitive()) + RETURN_STOP_A("non-object on rhs of instanceof"); + + Value& val = stackval(-2); + LIns* val_ins = box_value_for_native_call(val, get(&val)); + + enterDeepBailCall(); + LIns* args[] = {val_ins, get(&ctor), cx_ins}; + stack(-2, w.call(&HasInstanceOnTrace_ci, args)); + LIns* status_ins = w.ldiStateField(builtinStatus); + pendingGuardCondition = w.eqi0(status_ins); + leaveDeepBailCall(); + + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DEBUGGER() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GOSUB() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_RETSUB() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_EXCEPTION() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_LINENO() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_BLOCKCHAIN() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_NULLBLOCKCHAIN() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_CONDSWITCH() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_CASE() +{ + CHECK_STATUS_A(strictEquality(true, true)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DEFAULT() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_EVAL() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ENUMELEM() +{ + /* + * To quote from jsinterp.cpp's JSOP_ENUMELEM case: + * Funky: the value to set is under the [obj, id] pair. + */ + return setElem(-2, -1, -3); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GETTER() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SETTER() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DEFFUN() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DEFFUN_FC() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DEFCONST() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DEFVAR() +{ + return ARECORD_STOP; +} + +jsatomid +TraceRecorder::getFullIndex(ptrdiff_t pcoff) +{ + jsatomid index = GET_INDEX(cx->regs->pc + pcoff); + index += atoms - cx->fp()->script()->atomMap.vector; + return index; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_LAMBDA() +{ + JSFunction* fun; + fun = cx->fp()->script()->getFunction(getFullIndex()); + + if (FUN_NULL_CLOSURE(fun) && FUN_OBJECT(fun)->getParent() != globalObj) + RETURN_STOP_A("Null closure function object parent must be global object"); + + /* + * Emit code to clone a null closure parented by this recorder's global + * object, in order to preserve function object evaluation rules observable + * via identity and mutation. But don't clone if our result is consumed by + * JSOP_SETMETHOD or JSOP_INITMETHOD, since we optimize away the clone for + * these combinations and clone only if the "method value" escapes. + * + * See jsinterp.cpp, the JSOP_LAMBDA null closure case. The JSOP_SETMETHOD and + * JSOP_INITMETHOD logic governing the early ARECORD_CONTINUE returns below + * must agree with the corresponding break-from-do-while(0) logic there. + */ + if (FUN_NULL_CLOSURE(fun) && FUN_OBJECT(fun)->getParent() == &cx->fp()->scopeChain()) { + jsbytecode *pc2 = AdvanceOverBlockchainOp(cx->regs->pc + JSOP_LAMBDA_LENGTH); + JSOp op2 = JSOp(*pc2); + + if (op2 == JSOP_INITMETHOD) { + stack(0, w.immpObjGC(FUN_OBJECT(fun))); + return ARECORD_CONTINUE; + } + + if (op2 == JSOP_SETMETHOD) { + Value lval = stackval(-1); + + if (!lval.isPrimitive() && lval.toObject().canHaveMethodBarrier()) { + stack(0, w.immpObjGC(FUN_OBJECT(fun))); + return ARECORD_CONTINUE; + } + } else if (fun->joinable()) { + if (op2 == JSOP_CALL) { + /* + * Array.prototype.sort and String.prototype.replace are + * optimized as if they are special form. We know that they + * won't leak the joined function object in obj, therefore + * we don't need to clone that compiler- created function + * object for identity/mutation reasons. + */ + int iargc = GET_ARGC(pc2); + + /* + * Note that we have not yet pushed obj as the final argument, + * so regs.sp[1 - (iargc + 2)], and not regs.sp[-(iargc + 2)], + * is the callee for this JSOP_CALL. + */ + const Value &cref = cx->regs->sp[1 - (iargc + 2)]; + JSObject *callee; + + if (IsFunctionObject(cref, &callee)) { + JSFunction *calleeFun = callee->getFunctionPrivate(); + Native native = calleeFun->maybeNative(); + + if ((iargc == 1 && native == array_sort) || + (iargc == 2 && native == str_replace)) { + stack(0, w.immpObjGC(FUN_OBJECT(fun))); + return ARECORD_CONTINUE; + } + } + } else if (op2 == JSOP_NULL) { + pc2 += JSOP_NULL_LENGTH; + op2 = JSOp(*pc2); + + if (op2 == JSOP_CALL && GET_ARGC(pc2) == 0) { + stack(0, w.immpObjGC(FUN_OBJECT(fun))); + return ARECORD_CONTINUE; + } + } + } + + LIns *proto_ins; + CHECK_STATUS_A(getClassPrototype(JSProto_Function, proto_ins)); + + LIns* args[] = { w.immpObjGC(globalObj), proto_ins, w.immpFunGC(fun), cx_ins }; + LIns* x = w.call(&js_NewNullClosure_ci, args); + stack(0, x); + return ARECORD_CONTINUE; + } + + if (GetBlockChainFast(cx, cx->fp(), JSOP_LAMBDA, JSOP_LAMBDA_LENGTH)) + RETURN_STOP_A("Unable to trace creating lambda in let"); + + LIns *proto_ins; + CHECK_STATUS_A(getClassPrototype(JSProto_Function, proto_ins)); + LIns* scopeChain_ins = scopeChain(); + JS_ASSERT(scopeChain_ins); + LIns* args[] = { proto_ins, scopeChain_ins, w.nameImmpNonGC(fun), cx_ins }; + LIns* call_ins = w.call(&js_CloneFunctionObject_ci, args); + guard(false, + w.name(w.eqp0(call_ins), "guard(js_CloneFunctionObject)"), + OOM_EXIT); + stack(0, call_ins); + + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_LAMBDA_FC() +{ + JSFunction* fun; + fun = cx->fp()->script()->getFunction(getFullIndex()); + + if (FUN_OBJECT(fun)->getParent() != globalObj) + return ARECORD_STOP; + + if (GetBlockChainFast(cx, cx->fp(), JSOP_LAMBDA_FC, JSOP_LAMBDA_FC_LENGTH)) + RETURN_STOP_A("Unable to trace creating lambda in let"); + + LIns* args[] = { scopeChain(), w.immpFunGC(fun), cx_ins }; + LIns* closure_ins = w.call(&js_AllocFlatClosure_ci, args); + guard(false, + w.name(w.eqp(closure_ins, w.immpNull()), "guard(js_AllocFlatClosure)"), + OOM_EXIT); + + JSScript *script = fun->script(); + if (script->bindings.hasUpvars()) { + JSUpvarArray *uva = script->upvars(); + LIns* upvars_ins = w.getObjPrivatizedSlot(closure_ins, + JSObject::JSSLOT_FLAT_CLOSURE_UPVARS); + + for (uint32 i = 0, n = uva->length; i < n; i++) { + Value v; + LIns* v_ins = upvar(script, uva, i, v); + if (!v_ins) + return ARECORD_STOP; + + box_value_into(v, v_ins, FCSlotsAddress(upvars_ins, i)); + } + } + + stack(0, closure_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_CALLEE() +{ + stack(0, get(&cx->fp()->calleeValue())); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SETLOCALPOP() +{ + var(GET_SLOTNO(cx->regs->pc), stack(-1)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_IFPRIMTOP() +{ + // Traces are type-specialized, including null vs. object, so we need do + // nothing here. The upstream unbox_value called after valueOf or toString + // from an imacro (e.g.) will fork the trace for us, allowing us to just + // follow along mindlessly :-). + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SETCALL() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_TRY() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_FINALLY() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_NOP() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ARGSUB() +{ + JSStackFrame* const fp = cx->fp(); + + /* + * The arguments object or its absence in the frame is part of the typemap, + * so a record-time check suffices here. We don't bother tracing ARGSUB in + * the case of an arguments object exising, because ARGSUB and to a lesser + * extent ARGCNT are emitted to avoid arguments object creation. + */ + if (!fp->hasArgsObj() && !fp->fun()->isHeavyweight()) { + uintN slot = GET_ARGNO(cx->regs->pc); + if (slot >= fp->numActualArgs()) + RETURN_STOP_A("can't trace out-of-range arguments"); + + stack(0, get(&cx->fp()->canonicalActualArg(slot))); + return ARECORD_CONTINUE; + } + RETURN_STOP_A("can't trace JSOP_ARGSUB hard case"); +} + +JS_REQUIRES_STACK LIns* +TraceRecorder::guardArgsLengthNotAssigned(LIns* argsobj_ins) +{ + // The following implements JSObject::isArgsLengthOverridden on trace. + // ARGS_LENGTH_OVERRIDDEN_BIT is set if length was overridden. + LIns *len_ins = w.getArgsLength(argsobj_ins); + LIns *ovr_ins = w.andi(len_ins, w.nameImmi(JSObject::ARGS_LENGTH_OVERRIDDEN_BIT)); + guard(true, w.eqi0(ovr_ins), MISMATCH_EXIT); + return len_ins; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ARGCNT() +{ + JSStackFrame * const fp = cx->fp(); + + if (fp->fun()->flags & JSFUN_HEAVYWEIGHT) + RETURN_STOP_A("can't trace heavyweight JSOP_ARGCNT"); + + // argc is fixed on trace, so ideally we would simply generate LIR for + // constant argc. But the user can mutate arguments.length in the + // interpreter, so we have to check for that in the trace entry frame. + // We also have to check that arguments.length has not been mutated + // at record time, because if so we will generate incorrect constant + // LIR, which will assert in alu(). + if (fp->hasArgsObj() && fp->argsObj().isArgsLengthOverridden()) + RETURN_STOP_A("can't trace JSOP_ARGCNT if arguments.length has been modified"); + LIns *a_ins = getFrameObjPtr(fp->addressOfArgs()); + if (callDepth == 0) { + if (MaybeBranch mbr = w.jt(w.eqp0(a_ins))) { + guardArgsLengthNotAssigned(a_ins); + w.label(mbr); + } + } + stack(0, w.immd(fp->numActualArgs())); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_DefLocalFunSetSlot(uint32 slot, JSObject* obj) +{ + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, obj); + + if (FUN_NULL_CLOSURE(fun) && FUN_OBJECT(fun)->getParent() == globalObj) { + LIns *proto_ins; + CHECK_STATUS_A(getClassPrototype(JSProto_Function, proto_ins)); + + LIns* args[] = { w.immpObjGC(globalObj), proto_ins, w.immpFunGC(fun), cx_ins }; + LIns* x = w.call(&js_NewNullClosure_ci, args); + var(slot, x); + return ARECORD_CONTINUE; + } + + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DEFLOCALFUN() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DEFLOCALFUN_FC() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GOTOX() +{ + return record_JSOP_GOTO(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_IFEQX() +{ + return record_JSOP_IFEQ(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_IFNEX() +{ + return record_JSOP_IFNE(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ORX() +{ + return record_JSOP_OR(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ANDX() +{ + return record_JSOP_AND(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GOSUBX() +{ + return record_JSOP_GOSUB(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_CASEX() +{ + CHECK_STATUS_A(strictEquality(true, true)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DEFAULTX() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_TABLESWITCHX() +{ + return record_JSOP_TABLESWITCH(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_LOOKUPSWITCHX() +{ + return InjectStatus(switchop()); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_BACKPATCH() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_BACKPATCH_POP() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_THROWING() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SETRVAL() +{ + // If we implement this, we need to update JSOP_STOP. + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_RETRVAL() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_REGEXP() +{ + JSStackFrame* const fp = cx->fp(); + JSScript* script = fp->script(); + unsigned index = atoms - script->atomMap.vector + GET_INDEX(cx->regs->pc); + + LIns* proto_ins; + CHECK_STATUS_A(getClassPrototype(JSProto_RegExp, proto_ins)); + + LIns* args[] = { + proto_ins, + w.immpObjGC(script->getRegExp(index)), + cx_ins + }; + LIns* regex_ins = w.call(&js_CloneRegExpObject_ci, args); + guard(false, w.eqp0(regex_ins), OOM_EXIT); + + stack(0, regex_ins); + return ARECORD_CONTINUE; +} + +// begin JS_HAS_XML_SUPPORT + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DEFXMLNS() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ANYNAME() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_QNAMEPART() +{ + return record_JSOP_STRING(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_QNAMECONST() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_QNAME() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_TOATTRNAME() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_TOATTRVAL() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ADDATTRNAME() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ADDATTRVAL() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_BINDXMLNAME() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SETXMLNAME() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_XMLNAME() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DESCENDANTS() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_FILTER() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ENDFILTER() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_TOXML() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_TOXMLLIST() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_XMLTAGEXPR() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_XMLELTEXPR() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_XMLCDATA() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_XMLCOMMENT() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_XMLPI() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GETFUNNS() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_STARTXML() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_STARTXMLEXPR() +{ + return ARECORD_STOP; +} + +// end JS_HAS_XML_SUPPORT + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_CALLPROP() +{ + Value& l = stackval(-1); + JSObject* obj; + LIns* obj_ins; + LIns* this_ins; + if (!l.isPrimitive()) { + obj = &l.toObject(); + obj_ins = get(&l); + this_ins = obj_ins; // |this| for subsequent call + } else { + JSProtoKey protoKey; + debug_only_stmt(const char* protoname = NULL;) + if (l.isString()) { + protoKey = JSProto_String; + debug_only_stmt(protoname = "String.prototype";) + } else if (l.isNumber()) { + protoKey = JSProto_Number; + debug_only_stmt(protoname = "Number.prototype";) + } else if (l.isBoolean()) { + protoKey = JSProto_Boolean; + debug_only_stmt(protoname = "Boolean.prototype";) + } else { + JS_ASSERT(l.isNull() || l.isUndefined()); + RETURN_STOP_A("callprop on null or void"); + } + + if (!js_GetClassPrototype(cx, NULL, protoKey, &obj)) + RETURN_ERROR_A("GetClassPrototype failed!"); + + obj_ins = w.immpObjGC(obj); + debug_only_stmt(obj_ins = w.name(obj_ins, protoname);) + this_ins = get(&l); // use primitive as |this| + } + + JSObject* obj2; + PCVal pcval; + CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval)); + + if (pcval.isNull()) + RETURN_STOP_A("callprop of missing method"); + + if (pcval.isFunObj()) { + if (l.isPrimitive()) { + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, &pcval.toFunObj()); + if (fun->isInterpreted() && !fun->inStrictMode()) + RETURN_STOP_A("callee does not accept primitive |this|"); + } + set(&l, w.immpObjGC(&pcval.toFunObj())); + } else { + if (l.isPrimitive()) + RETURN_STOP_A("callprop of primitive method"); + JS_ASSERT_IF(pcval.isShape(), !pcval.toShape()->isMethod()); + CHECK_STATUS_A(propTail(obj, obj_ins, obj2, pcval, NULL, NULL, &l)); + } + stack(0, this_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DELDESC() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_UINT24() +{ + stack(0, w.immd(GET_UINT24(cx->regs->pc))); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INDEXBASE() +{ + atoms += GET_INDEXBASE(cx->regs->pc); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_RESETBASE() +{ + updateAtoms(); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_RESETBASE0() +{ + updateAtoms(); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_CALLELEM() +{ + return record_JSOP_GETELEM(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_STOP() +{ + JSStackFrame *fp = cx->fp(); + + /* A return from callDepth 0 terminates the current loop, except for recursion. */ + if (callDepth == 0 && !fp->hasImacropc()) { + AUDIT(returnLoopExits); + return endLoop(); + } + + if (fp->hasImacropc()) { + /* + * End of imacro, so return true to the interpreter immediately. The + * interpreter's JSOP_STOP case will return from the imacro, back to + * the pc after the calling op, still in the same JSStackFrame. + */ + updateAtoms(fp->script()); + return ARECORD_CONTINUE; + } + + CHECK_STATUS_A(putActivationObjects()); + + if (Probes::callTrackingActive(cx)) { + LIns* args[] = { w.immi(0), w.nameImmpNonGC(cx->fp()->fun()), cx_ins }; + LIns* call_ins = w.call(&functionProbe_ci, args); + guard(false, w.eqi0(call_ins), MISMATCH_EXIT); + } + + /* + * We know falling off the end of a constructor returns the new object that + * was passed in via fp->argv[-1], while falling off the end of a function + * returns undefined. + * + * NB: we do not support script rval (eval, API users who want the result + * of the last expression-statement, debugger API calls). + */ + if (fp->isConstructing()) { + rval_ins = get(&fp->thisValue()); + } else { + rval_ins = w.immiUndefined(); + } + clearReturningFrameFromNativeTracker(); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GETXPROP() +{ + Value& l = stackval(-1); + if (l.isPrimitive()) + RETURN_STOP_A("primitive-this for GETXPROP?"); + + Value* vp; + LIns* v_ins; + NameResult nr; + CHECK_STATUS_A(name(vp, v_ins, nr)); + stack(-1, v_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_CALLXMLNAME() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_TYPEOFEXPR() +{ + return record_JSOP_TYPEOF(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ENTERBLOCK() +{ + JSObject* obj; + obj = cx->fp()->script()->getObject(getFullIndex(0)); + + LIns* void_ins = w.immiUndefined(); + for (int i = 0, n = OBJ_BLOCK_COUNT(cx, obj); i < n; i++) + stack(i, void_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_LEAVEBLOCK() +{ + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GENERATOR() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_YIELD() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ARRAYPUSH() +{ + uint32_t slot = GET_UINT16(cx->regs->pc); + JS_ASSERT(cx->fp()->numFixed() <= slot); + JS_ASSERT(cx->fp()->slots() + slot < cx->regs->sp - 1); + Value &arrayval = cx->fp()->slots()[slot]; + JS_ASSERT(arrayval.isObject()); + LIns *array_ins = get(&arrayval); + Value &elt = stackval(-1); + LIns *elt_ins = box_value_for_native_call(elt, get(&elt)); + + enterDeepBailCall(); + + LIns *args[] = { elt_ins, array_ins, cx_ins }; + pendingGuardCondition = w.call(&js_ArrayCompPush_tn_ci, args); + + leaveDeepBailCall(); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_ENUMCONSTELEM() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_LEAVEBLOCKEXPR() +{ + LIns* v_ins = stack(-1); + int n = -1 - GET_UINT16(cx->regs->pc); + stack(n, v_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GETTHISPROP() +{ + LIns* this_ins; + + CHECK_STATUS_A(getThis(this_ins)); + + /* + * It's safe to just use cx->fp->thisValue() here because getThis() returns + * ARECORD_STOP or ARECORD_ERROR if thisv is not available. + */ + const Value &thisv = cx->fp()->thisValue(); + if (!thisv.isObject()) + RETURN_STOP_A("primitive this for GETTHISPROP"); + + CHECK_STATUS_A(getProp(&thisv.toObject(), this_ins)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GETARGPROP() +{ + return getProp(argval(GET_ARGNO(cx->regs->pc))); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GETLOCALPROP() +{ + return getProp(varval(GET_SLOTNO(cx->regs->pc))); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INDEXBASE1() +{ + atoms += 1 << 16; + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INDEXBASE2() +{ + atoms += 2 << 16; + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INDEXBASE3() +{ + atoms += 3 << 16; + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_CALLLOCAL() +{ + uintN slot = GET_SLOTNO(cx->regs->pc); + stack(0, var(slot)); + stack(1, w.immiUndefined()); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_CALLARG() +{ + uintN slot = GET_ARGNO(cx->regs->pc); + stack(0, arg(slot)); + stack(1, w.immiUndefined()); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_BINDGNAME() +{ + stack(0, w.immpObjGC(globalObj)); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INT8() +{ + stack(0, w.immd(GET_INT8(cx->regs->pc))); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INT32() +{ + stack(0, w.immd(GET_INT32(cx->regs->pc))); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_LENGTH() +{ + Value& l = stackval(-1); + if (l.isPrimitive()) { + if (!l.isString()) + RETURN_STOP_A("non-string primitive JSOP_LENGTH unsupported"); + set(&l, w.i2d(w.p2i(w.getStringLength(get(&l))))); + return ARECORD_CONTINUE; + } + + JSObject* obj = &l.toObject(); + LIns* obj_ins = get(&l); + + if (obj->isArguments()) { + unsigned depth; + JSStackFrame *afp = guardArguments(obj, obj_ins, &depth); + if (!afp) + RETURN_STOP_A("can't reach arguments object's frame"); + + // We must both check at record time and guard at run time that + // arguments.length has not been reassigned, redefined or deleted. + if (obj->isArgsLengthOverridden()) + RETURN_STOP_A("can't trace JSOP_ARGCNT if arguments.length has been modified"); + LIns* slot_ins = guardArgsLengthNotAssigned(obj_ins); + + // slot_ins is the value from the slot; right-shift to get the length + // (see JSObject::getArgsInitialLength in jsfun.cpp). + LIns* v_ins = w.i2d(w.rshiN(slot_ins, JSObject::ARGS_PACKED_BITS_COUNT)); + set(&l, v_ins); + return ARECORD_CONTINUE; + } + + LIns* v_ins; + if (obj->isArray()) { + if (obj->isDenseArray()) { + guardDenseArray(obj_ins, BRANCH_EXIT); + } else { + JS_ASSERT(obj->isSlowArray()); + guardClass(obj_ins, &js_SlowArrayClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); + } + v_ins = w.lduiObjPrivate(obj_ins); + if (obj->getArrayLength() <= JSVAL_INT_MAX) { + guard(true, w.leui(v_ins, w.immi(JSVAL_INT_MAX)), BRANCH_EXIT); + v_ins = w.i2d(v_ins); + } else { + v_ins = w.ui2d(v_ins); + } + } else if (OkToTraceTypedArrays && js_IsTypedArray(obj)) { + // Ensure array is a typed array and is the same type as what was written + guardClass(obj_ins, obj->getClass(), snapshot(BRANCH_EXIT), LOAD_NORMAL); + v_ins = w.i2d(w.ldiConstTypedArrayLength(w.ldpObjPrivate(obj_ins))); + } else { + if (!obj->isNative()) + RETURN_STOP_A("can't trace length property access on non-array, non-native object"); + return getProp(obj, obj_ins); + } + set(&l, v_ins); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_HOLE() +{ + stack(0, w.immpMagicWhy(JS_ARRAY_HOLE)); + return ARECORD_CONTINUE; +} + +AbortableRecordingStatus +TraceRecorder::record_JSOP_TRACE() +{ + return ARECORD_CONTINUE; +} + +AbortableRecordingStatus +TraceRecorder::record_JSOP_NOTRACE() +{ + return ARECORD_CONTINUE; +} + +JSBool FASTCALL +js_Unbrand(JSContext *cx, JSObject *obj) +{ + return obj->unbrand(cx); +} + +JS_DEFINE_CALLINFO_2(extern, BOOL, js_Unbrand, CONTEXT, OBJECT, 0, ACCSET_STORE_ANY) + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_UNBRAND() +{ + LIns* args_ins[] = { stack(-1), cx_ins }; + LIns* call_ins = w.call(&js_Unbrand_ci, args_ins); + guard(false, w.eqi0(call_ins), OOM_EXIT); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_UNBRANDTHIS() +{ + /* In case of primitive this, do nothing. */ + JSStackFrame *fp = cx->fp(); + if (fp->fun()->inStrictMode() && !fp->thisValue().isObject()) + return ARECORD_CONTINUE; + + LIns* this_ins; + RecordingStatus status = getThis(this_ins); + if (status != RECORD_CONTINUE) + return InjectStatus(status); + + LIns* args_ins[] = { this_ins, cx_ins }; + LIns* call_ins = w.call(&js_Unbrand_ci, args_ins); + guard(false, w.eqi0(call_ins), OOM_EXIT); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SHARPINIT() +{ + return ARECORD_STOP; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GETGLOBAL() +{ + uint32 slot = cx->fp()->script()->getGlobalSlot(GET_SLOTNO(cx->regs->pc)); + if (!lazilyImportGlobalSlot(slot)) + RETURN_STOP_A("lazy import of global slot failed"); + + stack(0, get(&globalObj->getSlotRef(slot))); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_CALLGLOBAL() +{ + uint32 slot = cx->fp()->script()->getGlobalSlot(GET_SLOTNO(cx->regs->pc)); + if (!lazilyImportGlobalSlot(slot)) + RETURN_STOP_A("lazy import of global slot failed"); + + Value &v = globalObj->getSlotRef(slot); + stack(0, get(&v)); + stack(1, w.immiUndefined()); + return ARECORD_CONTINUE; +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GETGNAME() +{ + return record_JSOP_NAME(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_SETGNAME() +{ + return record_JSOP_SETNAME(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GNAMEDEC() +{ + return record_JSOP_NAMEDEC(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_GNAMEINC() +{ + return record_JSOP_NAMEINC(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_DECGNAME() +{ + return record_JSOP_DECNAME(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_INCGNAME() +{ + return record_JSOP_INCNAME(); +} + +JS_REQUIRES_STACK AbortableRecordingStatus +TraceRecorder::record_JSOP_CALLGNAME() +{ + return record_JSOP_CALLNAME(); +} + +#define DBG_STUB(OP) \ + JS_REQUIRES_STACK AbortableRecordingStatus \ + TraceRecorder::record_##OP() \ + { \ + RETURN_STOP_A("can't trace " #OP); \ + } + +DBG_STUB(JSOP_GETUPVAR_DBG) +DBG_STUB(JSOP_CALLUPVAR_DBG) +DBG_STUB(JSOP_DEFFUN_DBGFC) +DBG_STUB(JSOP_DEFLOCALFUN_DBGFC) +DBG_STUB(JSOP_LAMBDA_DBGFC) + +#ifdef JS_JIT_SPEW +/* + * Print information about entry typemaps and unstable exits for all peers + * at a PC. + */ +void +DumpPeerStability(TraceMonitor* tm, const void* ip, JSObject* globalObj, uint32 globalShape, + uint32 argc) +{ + TreeFragment* f; + bool looped = false; + unsigned length = 0; + + for (f = LookupLoop(tm, ip, globalObj, globalShape, argc); f != NULL; f = f->peer) { + if (!f->code()) + continue; + debug_only_printf(LC_TMRecorder, "Stability of fragment %p:\nENTRY STACK=", (void*)f); + if (looped) + JS_ASSERT(f->nStackTypes == length); + for (unsigned i = 0; i < f->nStackTypes; i++) + debug_only_printf(LC_TMRecorder, "%c", TypeToChar(f->stackTypeMap()[i])); + debug_only_print0(LC_TMRecorder, " GLOBALS="); + for (unsigned i = 0; i < f->nGlobalTypes(); i++) + debug_only_printf(LC_TMRecorder, "%c", TypeToChar(f->globalTypeMap()[i])); + debug_only_print0(LC_TMRecorder, "\n"); + UnstableExit* uexit = f->unstableExits; + while (uexit != NULL) { + debug_only_print0(LC_TMRecorder, "EXIT "); + JSValueType* m = uexit->exit->fullTypeMap(); + debug_only_print0(LC_TMRecorder, "STACK="); + for (unsigned i = 0; i < uexit->exit->numStackSlots; i++) + debug_only_printf(LC_TMRecorder, "%c", TypeToChar(m[i])); + debug_only_print0(LC_TMRecorder, " GLOBALS="); + for (unsigned i = 0; i < uexit->exit->numGlobalSlots; i++) { + debug_only_printf(LC_TMRecorder, "%c", + TypeToChar(m[uexit->exit->numStackSlots + i])); + } + debug_only_print0(LC_TMRecorder, "\n"); + uexit = uexit->next; + } + length = f->nStackTypes; + looped = true; + } +} +#endif + +#ifdef MOZ_TRACEVIS + +FILE* traceVisLogFile = NULL; +JSHashTable *traceVisScriptTable = NULL; + +JS_FRIEND_API(bool) +StartTraceVis(const char* filename = "tracevis.dat") +{ + if (traceVisLogFile) { + // If we're currently recording, first we must stop. + StopTraceVis(); + } + + traceVisLogFile = fopen(filename, "wb"); + if (!traceVisLogFile) + return false; + + return true; +} + +JS_FRIEND_API(JSBool) +StartTraceVisNative(JSContext *cx, uintN argc, jsval *vp) +{ + JSBool ok; + + if (argc > 0 && JSVAL_IS_STRING(JS_ARGV(cx, vp)[0])) { + JSString *str = JSVAL_TO_STRING(JS_ARGV(cx, vp)[0]); + char *filename = js_DeflateString(cx, str->chars(), str->length()); + if (!filename) + goto error; + ok = StartTraceVis(filename); + cx->free(filename); + } else { + ok = StartTraceVis(); + } + + if (ok) { + fprintf(stderr, "started TraceVis recording\n"); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return true; + } + + error: + JS_ReportError(cx, "failed to start TraceVis recording"); + return false; +} + +JS_FRIEND_API(bool) +StopTraceVis() +{ + if (!traceVisLogFile) + return false; + + fclose(traceVisLogFile); // not worth checking the result + traceVisLogFile = NULL; + + return true; +} + +JS_FRIEND_API(JSBool) +StopTraceVisNative(JSContext *cx, uintN argc, jsval *vp) +{ + JSBool ok = StopTraceVis(); + + if (ok) { + fprintf(stderr, "stopped TraceVis recording\n"); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + } else { + JS_ReportError(cx, "TraceVis isn't running"); + } + + return ok; +} + +#endif /* MOZ_TRACEVIS */ + +JS_REQUIRES_STACK void +TraceRecorder::captureStackTypes(unsigned callDepth, JSValueType* typeMap) +{ + CaptureTypesVisitor capVisitor(cx, traceMonitor->oracle, typeMap, !!oracle); + VisitStackSlots(capVisitor, cx, callDepth); +} + +JS_REQUIRES_STACK void +TraceRecorder::determineGlobalTypes(JSValueType* typeMap) +{ + DetermineTypesVisitor detVisitor(*this, typeMap); + VisitGlobalSlots(detVisitor, cx, *tree->globalSlots); +} + +#ifdef JS_METHODJIT + +class AutoRetBlacklist +{ + jsbytecode* pc; + bool* blacklist; + + public: + AutoRetBlacklist(jsbytecode* pc, bool* blacklist) + : pc(pc), blacklist(blacklist) + { } + + ~AutoRetBlacklist() + { + *blacklist = IsBlacklisted(pc); + } +}; + +JS_REQUIRES_STACK TracePointAction +RecordTracePoint(JSContext* cx, TraceMonitor* tm, + uintN& inlineCallCount, bool* blacklist, bool execAllowed) +{ + JSStackFrame* fp = cx->fp(); + jsbytecode* pc = cx->regs->pc; + + JS_ASSERT(!tm->recorder); + JS_ASSERT(!tm->profile); + + JSObject* globalObj = cx->fp()->scopeChain().getGlobal(); + uint32 globalShape = -1; + SlotList* globalSlots = NULL; + + AutoRetBlacklist autoRetBlacklist(pc, blacklist); + + if (!CheckGlobalObjectShape(cx, tm, globalObj, &globalShape, &globalSlots)) { + Backoff(tm, pc); + return TPA_Nothing; + } + + uint32 argc = entryFrameArgc(cx); + TreeFragment* tree = LookupOrAddLoop(tm, pc, globalObj, globalShape, argc); + + debug_only_printf(LC_TMTracer, + "Looking for compat peer %d@%d, from %p (ip: %p)\n", + js_FramePCToLineNumber(cx, cx->fp()), + FramePCOffset(cx, cx->fp()), (void*)tree, tree->ip); + + if (tree->code() || tree->peer) { + uintN count; + TreeFragment* match = FindVMCompatiblePeer(cx, globalObj, tree, count); + if (match) { + VMSideExit* lr = NULL; + VMSideExit* innermostNestedGuard = NULL; + + if (!execAllowed) { + /* We've already compiled a trace for it, but we don't want to use that trace. */ + Blacklist((jsbytecode*)tree->root->ip); + return TPA_Nothing; + } + + /* Best case - just go and execute. */ + if (!ExecuteTree(cx, tm, match, inlineCallCount, &innermostNestedGuard, &lr)) + return TPA_Error; + + if (!lr) + return TPA_Nothing; + + switch (lr->exitType) { + case UNSTABLE_LOOP_EXIT: + if (!AttemptToStabilizeTree(cx, tm, globalObj, lr, NULL, NULL, 0)) + return TPA_RanStuff; + break; + + case MUL_ZERO_EXIT: + case OVERFLOW_EXIT: + if (lr->exitType == MUL_ZERO_EXIT) + tm->oracle->markInstructionSlowZeroTest(cx->regs->pc); + else + tm->oracle->markInstructionUndemotable(cx->regs->pc); + /* FALL THROUGH */ + case BRANCH_EXIT: + case CASE_EXIT: + if (!AttemptToExtendTree(cx, tm, lr, NULL, NULL, NULL)) + return TPA_RanStuff; + break; + + case LOOP_EXIT: + if (!innermostNestedGuard) + return TPA_RanStuff; + if (!AttemptToExtendTree(cx, tm, innermostNestedGuard, lr, NULL, NULL)) + return TPA_RanStuff; + break; + + default: + return TPA_RanStuff; + } + + JS_ASSERT(tm->recorder); + + goto interpret; + } + + if (count >= MAXPEERS) { + debug_only_print0(LC_TMTracer, "Blacklisted: too many peer trees.\n"); + Blacklist((jsbytecode*)tree->root->ip); + return TPA_Nothing; + } + } + + if (++tree->hits() < HOTLOOP) + return TPA_Nothing; + if (!ScopeChainCheck(cx, tree)) + return TPA_Nothing; + if (!RecordTree(cx, tm, tree->first, NULL, NULL, 0, globalSlots)) + return TPA_Nothing; + + interpret: + JS_ASSERT(tm->recorder); + + /* Locked and loaded with a recorder. Ask the interperter to go run some code. */ + if (!Interpret(cx, fp, inlineCallCount, JSINTERP_RECORD)) + return TPA_Error; + + JS_ASSERT(!cx->isExceptionPending()); + + return TPA_RanStuff; +} + +LoopProfile::LoopProfile(TraceMonitor *tm, JSStackFrame *entryfp, + jsbytecode *top, jsbytecode *bottom) + : traceMonitor(tm), + entryScript(entryfp->script()), + entryfp(entryfp), + top(top), + bottom(bottom), + hits(0), + undecided(false), + unprofitable(false) +{ + reset(); +} + +void +LoopProfile::reset() +{ + profiled = false; + traceOK = false; + numAllOps = 0; + numSelfOps = 0; + numSelfOpsMult = 0; + branchMultiplier = 1; + shortLoop = false; + maybeShortLoop = false; + numInnerLoops = 0; + loopStackDepth = 0; + sp = 0; + + PodArrayZero(allOps); + PodArrayZero(selfOps); +} + +MonitorResult +LoopProfile::profileLoopEdge(JSContext* cx, uintN& inlineCallCount) +{ + if (cx->regs->pc == top) { + debug_only_print0(LC_TMProfiler, "Profiling complete (edge)\n"); + decide(cx); + } else { + /* Record an inner loop invocation. */ + JSStackFrame *fp = cx->fp(); + jsbytecode *pc = cx->regs->pc; + bool found = false; + + /* We started with the most deeply nested one first, since it gets hit most often.*/ + for (int i = int(numInnerLoops)-1; i >= 0; i--) { + if (innerLoops[i].entryfp == fp && innerLoops[i].top == pc) { + innerLoops[i].iters++; + found = true; + break; + } + } + + if (!found && numInnerLoops < PROFILE_MAX_INNER_LOOPS) + innerLoops[numInnerLoops++] = InnerLoop(fp, pc, NULL); + } + + return MONITOR_NOT_RECORDING; +} + + +static const uintN PROFILE_HOTLOOP = 61; +static const uintN MAX_PROFILE_OPS = 4096; + +static jsbytecode * +GetLoopBottom(JSContext *cx) +{ + return GetLoopBottom(cx, cx->regs->pc); +} + +static LoopProfile * +LookupOrAddProfile(JSContext *cx, TraceMonitor *tm, void** traceData, uintN *traceEpoch) +{ + LoopProfile *prof; + + /* + * We try to keep a pointer to the loop profile inside the TRACE IC. + * We also keep a pointer inside a hashtable for when we need to + * look up nested loops (or when ICs are disabled). + * + * Memory for the profile is allocated in the dataAlloc for the + * trace monitor. Since this thing can get flushed periodically, + * we use epochs to decide if the profile in the MIC is valid, as + * follows. Every time the trace monitor is flushed, + * |tm->flushEpoch| is incremented. When storing the profile in + * the IC, we store the current |tm->flushEpoch| along with it. + * Before pulling a profile out of the IC, we check that its + * stored epoch is still up-to-date with |tm->flushEpoch|. + * This ensures that no flush has happened in between. + */ + +#if JS_MONOIC + if (*traceData && *traceEpoch == tm->flushEpoch) { + prof = (LoopProfile *)*traceData; + } else { + jsbytecode* pc = cx->regs->pc; + jsbytecode* bottom = GetLoopBottom(cx); + if (!bottom) + return NULL; + prof = new (*tm->dataAlloc) LoopProfile(tm, cx->fp(), pc, bottom); + *traceData = prof; + *traceEpoch = tm->flushEpoch; + tm->loopProfiles->put(pc, prof); + } +#else + LoopProfileMap &table = *tm->loopProfiles; + jsbytecode* pc = cx->regs->pc; + if (LoopProfileMap::AddPtr p = table.lookupForAdd(pc)) { + prof = p->value; + } else { + jsbytecode* bottom = GetLoopBottom(cx); + if (!bottom) + return NULL; + prof = new (*tm->dataAlloc) LoopProfile(tm, cx->fp(), pc, bottom); + table.add(p, pc, prof); + } +#endif + + return prof; +} + +static LoopProfile * +LookupLoopProfile(TraceMonitor *tm, jsbytecode *pc) +{ + LoopProfileMap &table = *tm->loopProfiles; + if (LoopProfileMap::Ptr p = table.lookup(pc)) { + JS_ASSERT(p->value->top == pc); + return p->value; + } else + return NULL; +} + +void +LoopProfile::stopProfiling(JSContext *cx) +{ + JS_ASSERT(JS_THREAD_DATA(cx)->recordingCompartment == NULL); + JS_THREAD_DATA(cx)->profilingCompartment = NULL; + + traceMonitor->profile = NULL; +} + +JS_REQUIRES_STACK TracePointAction +MonitorTracePoint(JSContext *cx, uintN& inlineCallCount, bool* blacklist, + void** traceData, uintN *traceEpoch, uint32 *loopCounter, uint32 hits) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_FROM_CONTEXT(cx); + + if (!cx->profilingEnabled) + return RecordTracePoint(cx, tm, inlineCallCount, blacklist, true); + + *blacklist = false; + + /* + * This is the only place where we check for re-entering the profiler. + * The assumption is that MonitorTracePoint is the only place where we + * start profiling. When we do so, we enter an interpreter frame with + * JSINTERP_PROFILE mode. All other entry points to the profiler check + * that the interpreter mode is JSINTERP_PROFILE. If it isn't, they + * don't profile. + */ + if (TRACE_PROFILER(cx)) + return TPA_Nothing; + + jsbytecode* pc = cx->regs->pc; + LoopProfile *prof = LookupOrAddProfile(cx, tm, traceData, traceEpoch); + if (!prof) { + *blacklist = true; + return TPA_Nothing; + } + + prof->hits += hits; + if (prof->hits < PROFILE_HOTLOOP) + return TPA_Nothing; + + AutoRetBlacklist autoRetBlacklist(cx->regs->pc, blacklist); + + if (prof->profiled) { + if (prof->traceOK) { + return RecordTracePoint(cx, tm, inlineCallCount, blacklist, prof->execOK); + } else { + return TPA_Nothing; + } + } + + debug_only_printf(LC_TMProfiler, "Profiling at line %d\n", + js_FramePCToLineNumber(cx, cx->fp())); + + tm->profile = prof; + + JS_ASSERT(JS_THREAD_DATA(cx)->profilingCompartment == NULL); + JS_ASSERT(JS_THREAD_DATA(cx)->recordingCompartment == NULL); + JS_THREAD_DATA(cx)->profilingCompartment = cx->compartment; + + if (!Interpret(cx, cx->fp(), inlineCallCount, JSINTERP_PROFILE)) + return TPA_Error; + + JS_ASSERT(!cx->isExceptionPending()); + + /* Look it up again since a reset may have happened during Interpret. */ + prof = LookupLoopProfile(tm, pc); + if (prof && prof->undecided) { + *loopCounter = 3000; + prof->reset(); + } + + return TPA_RanStuff; +} + +/* + * Returns true if pc is within the given loop. + * If we're in a different script, then we must have come from + * a call instruction within the loop (since we check if we're within + * the loop before each instruction) so we're still in the loop. + */ +template +static inline bool +PCWithinLoop(JSStackFrame *fp, jsbytecode *pc, T& loop) +{ + return fp > loop.entryfp || (fp == loop.entryfp && pc >= loop.top && pc <= loop.bottom); +} + +LoopProfile::ProfileAction +LoopProfile::profileOperation(JSContext* cx, JSOp op) +{ + TraceMonitor* tm = JS_TRACE_MONITOR_FROM_CONTEXT(cx); + + JS_ASSERT(tm == traceMonitor); + JS_ASSERT(&entryScript->compartment->traceMonitor == tm); + + if (profiled) { + stopProfiling(cx); + return ProfComplete; + } + + jsbytecode *pc = cx->regs->pc; + JSStackFrame *fp = cx->fp(); + JSScript *script = fp->script(); + + if (!PCWithinLoop(fp, pc, *this)) { + debug_only_printf(LC_TMProfiler, "Profiling complete (loop exit) at line %u\n", + js_FramePCToLineNumber(cx, cx->fp())); + tm->profile->decide(cx); + stopProfiling(cx); + return ProfComplete; + } + + while (loopStackDepth > 0 && !PCWithinLoop(fp, pc, loopStack[loopStackDepth-1])) { + debug_only_print0(LC_TMProfiler, "Profiler: Exiting inner loop\n"); + loopStackDepth--; + } + + if (op == JSOP_TRACE || op == JSOP_NOTRACE) { + if (pc != top && (loopStackDepth == 0 || pc != loopStack[loopStackDepth-1].top)) { + if (loopStackDepth == PROFILE_MAX_INNER_LOOPS) { + debug_only_print0(LC_TMProfiler, "Profiling complete (maxnest)\n"); + tm->profile->decide(cx); + stopProfiling(cx); + return ProfComplete; + } + + debug_only_printf(LC_TMProfiler, "Profiler: Entering inner loop at line %d\n", + js_FramePCToLineNumber(cx, cx->fp())); + loopStack[loopStackDepth++] = InnerLoop(fp, pc, GetLoopBottom(cx)); + } + } + + numAllOps++; + if (loopStackDepth == 0) { + numSelfOps++; + numSelfOpsMult += branchMultiplier; + } + + if (op == JSOP_ADD || op == JSOP_SUB || op == JSOP_MUL || op == JSOP_DIV) { + Value& v1 = cx->regs->sp[-1]; + Value& v2 = cx->regs->sp[-2]; + + /* If either operand is a double, treat it as a floating-point op. */ + if (v1.isDouble() || v2.isDouble()) + increment(OP_FLOAT); + else if (v1.isInt32() || v2.isInt32()) + increment(OP_INT); + } + + if (op == JSOP_EQ || op == JSOP_NE) + increment(OP_EQ); + + if (op == JSOP_BITOR || op == JSOP_BITXOR || op == JSOP_BITAND + || op == JSOP_LSH || op == JSOP_RSH || op == JSOP_URSH || op == JSOP_BITNOT) + { + increment(OP_BIT); + } + + if (op == JSOP_EVAL) + increment(OP_EVAL); + + if (op == JSOP_NEW) + increment(OP_NEW); + + if (op == JSOP_GETELEM || op == JSOP_SETELEM) { + Value& lval = cx->regs->sp[op == JSOP_GETELEM ? -2 : -3]; + if (lval.isObject() && js_IsTypedArray(&lval.toObject())) + increment(OP_TYPED_ARRAY); + else if (lval.isObject() && lval.toObject().isDenseArray() && op == JSOP_GETELEM) + increment(OP_ARRAY_READ); + } + + if (op == JSOP_CALL) { + increment(OP_CALL); + + uintN argc = GET_ARGC(cx->regs->pc); + Value &v = cx->regs->sp[-((int)argc + 2)]; + JSObject *callee; + if (IsFunctionObject(v, &callee)) { + JSFunction *fun = callee->getFunctionPrivate(); + if (fun->isInterpreted()) { + if (cx->fp()->isFunctionFrame() && fun == cx->fp()->fun()) + increment(OP_RECURSIVE); + } else { + js::Native native = fun->u.n.native; + if (js_IsMathFunction(JS_JSVALIFY_NATIVE(native))) + increment(OP_FLOAT); + } + } + } + + if (op == JSOP_CALLPROP && loopStackDepth == 0) + branchMultiplier *= mjit::GetCallTargetCount(script, pc); + + if (op == JSOP_TABLESWITCH) { + jsint low = GET_JUMP_OFFSET(pc + JUMP_OFFSET_LEN); + jsint high = GET_JUMP_OFFSET(pc + JUMP_OFFSET_LEN*2); + branchMultiplier *= high - low + 1; + } + + if (op == JSOP_LOOKUPSWITCH) + branchMultiplier *= GET_UINT16(pc + JUMP_OFFSET_LEN); + + if (numAllOps >= MAX_PROFILE_OPS) { + debug_only_print0(LC_TMProfiler, "Profiling complete (maxops)\n"); + tm->profile->decide(cx); + stopProfiling(cx); + return ProfComplete; + } + + /* These are the places where the interpreter skips over branches. */ + jsbytecode *testPC = cx->regs->pc; + if (op == JSOP_EQ || op == JSOP_NE || op == JSOP_LT || op == JSOP_GT + || op == JSOP_LE || op == JSOP_GE || op == JSOP_IN || op == JSOP_MOREITER) + { + const JSCodeSpec *cs = &js_CodeSpec[op]; + ptrdiff_t oplen = cs->length; + JS_ASSERT(oplen != -1); + + if (cx->regs->pc - script->code + oplen < ptrdiff_t(script->length)) + if (cx->regs->pc[oplen] == JSOP_IFEQ || cx->regs->pc[oplen] == JSOP_IFNE) + testPC = cx->regs->pc + oplen; + } + + /* Check if we're exiting the loop being profiled. */ + JSOp testOp = js_GetOpcode(cx, script, testPC); + if (testOp == JSOP_IFEQ || testOp == JSOP_IFNE || testOp == JSOP_GOTO + || testOp == JSOP_AND || testOp == JSOP_OR) + { + ptrdiff_t len = GET_JUMP_OFFSET(testPC); + if (testPC + len == top && (op == JSOP_LT || op == JSOP_LE)) { + StackValue v = stackAt(-1); + if (v.hasValue && v.value < 8) + shortLoop = true; + } + + if (testPC + len == top && (op == JSOP_LT || op == JSOP_LE) + && cx->regs->sp[-2].isInt32() && cx->regs->sp[-2].toInt32() < 16) + { + maybeShortLoop = true; + } + + if (testOp != JSOP_GOTO && len > 0) { + bool isConst; + if (testOp == JSOP_IFEQ || testOp == JSOP_IFNE) + isConst = stackAt(-1).isConst && stackAt(-2).isConst; + else + isConst = stackAt(-1).isConst; + + increment(OP_FWDJUMP); + if (loopStackDepth == 0 && !isConst) + branchMultiplier *= 2; + } + } + + if (op == JSOP_INT8) { + stackPush(StackValue(true, GET_INT8(cx->regs->pc))); + } else if (op == JSOP_STRING) { + stackPush(StackValue(true)); + } else if (op == JSOP_TYPEOF || op == JSOP_TYPEOFEXPR) { + stackPush(StackValue(true)); + } else if (op == JSOP_EQ || op == JSOP_NE) { + StackValue v1 = stackAt(-1); + StackValue v2 = stackAt(-2); + stackPush(StackValue(v1.isConst && v2.isConst)); + } else if (op == JSOP_AND) { + bool b = !!js_ValueToBoolean(cx->regs->sp[-1]); + StackValue v = stackAt(-1); + if (b) + stackPop(); + } else { + stackClear(); + } + + return ProfContinue; +} + +/* + * Returns true if the loop would probably take a long time to + * compile. + */ +bool +LoopProfile::isCompilationExpensive(JSContext *cx, uintN depth) +{ + if (depth == 0) + return true; + + if (!profiled) + return false; + + /* Too many ops to compile? */ + if (numSelfOps == MAX_PROFILE_OPS) + return true; + + /* Is the code too branchy? */ + if (numSelfOpsMult > numSelfOps*100000) + return true; + + /* Ensure that inner loops aren't too expensive. */ + for (uintN i=0; iisCompilationExpensive(cx, depth-1)) + return true; + } + + return false; +} + +/* + * This function recognizes loops that are short and that contain + * jumps. The tracer does badly with these loops because it + * needs to do a lot of side exits, which are somewhat + * expensive. + */ +bool +LoopProfile::isCompilationUnprofitable(JSContext *cx, uintN goodOps) +{ + if (!profiled) + return false; + + if (goodOps <= 22 && allOps[OP_FWDJUMP]) + return true; + + /* Ensure that inner loops aren't fleeting. */ + for (uintN i=0; iunprofitable) + return true; + } + + return false; +} + +/* After profiling is done, this method decides whether to trace the loop. */ +void +LoopProfile::decide(JSContext *cx) +{ + bool wasUndecided = undecided; + bool wasTraceOK = traceOK; + + profiled = true; + traceOK = false; + undecided = false; + +#ifdef DEBUG + uintN line = js_PCToLineNumber(cx, entryScript, top); + + debug_only_printf(LC_TMProfiler, "LOOP %s:%d\n", entryScript->filename, line); + + for (uintN i=0; ientryScript, prof->top); + debug_only_printf(LC_TMProfiler, "NESTED %s:%d (%d iters)\n", + prof->entryScript->filename, line, loop.iters); + } + } + debug_only_printf(LC_TMProfiler, "FEATURE float %d\n", allOps[OP_FLOAT]); + debug_only_printf(LC_TMProfiler, "FEATURE int %d\n", allOps[OP_INT]); + debug_only_printf(LC_TMProfiler, "FEATURE bit %d\n", allOps[OP_BIT]); + debug_only_printf(LC_TMProfiler, "FEATURE equality %d\n", allOps[OP_EQ]); + debug_only_printf(LC_TMProfiler, "FEATURE eval %d\n", allOps[OP_EVAL]); + debug_only_printf(LC_TMProfiler, "FEATURE new %d\n", allOps[OP_NEW]); + debug_only_printf(LC_TMProfiler, "FEATURE call %d\n", allOps[OP_CALL]); + debug_only_printf(LC_TMProfiler, "FEATURE arrayread %d\n", allOps[OP_ARRAY_READ]); + debug_only_printf(LC_TMProfiler, "FEATURE typedarray %d\n", allOps[OP_TYPED_ARRAY]); + debug_only_printf(LC_TMProfiler, "FEATURE fwdjump %d\n", allOps[OP_FWDJUMP]); + debug_only_printf(LC_TMProfiler, "FEATURE recursive %d\n", allOps[OP_RECURSIVE]); + debug_only_printf(LC_TMProfiler, "FEATURE shortLoop %d\n", shortLoop); + debug_only_printf(LC_TMProfiler, "FEATURE maybeShortLoop %d\n", maybeShortLoop); + debug_only_printf(LC_TMProfiler, "FEATURE numAllOps %d\n", numAllOps); + debug_only_printf(LC_TMProfiler, "FEATURE selfOps %d\n", numSelfOps); + debug_only_printf(LC_TMProfiler, "FEATURE selfOpsMult %g\n", numSelfOpsMult); +#endif + + if (count(OP_RECURSIVE)) { + debug_only_print0(LC_TMProfiler, "NOTRACE: recursive\n"); + } else if (count(OP_EVAL)) { + debug_only_print0(LC_TMProfiler, "NOTRACE: eval\n"); + } else if (numInnerLoops > 7) { + debug_only_print0(LC_TMProfiler, "NOTRACE: >3 inner loops\n"); + } else if (shortLoop) { + debug_only_print0(LC_TMProfiler, "NOTRACE: short\n"); + } else if (isCompilationExpensive(cx, 4)) { + debug_only_print0(LC_TMProfiler, "NOTRACE: expensive\n"); + } else if (maybeShortLoop && numInnerLoops < 2) { + if (wasUndecided) { + debug_only_print0(LC_TMProfiler, "NOTRACE: maybe short\n"); + } else { + debug_only_print0(LC_TMProfiler, "UNDECIDED: maybe short\n"); + undecided = true; /* Profile the loop again to see if it's still short. */ + } + } else { + uintN goodOps = 0; + + /* The tracer handles these ops well because of type specialization. */ + goodOps += count(OP_FLOAT)*10 + count(OP_BIT)*11 + count(OP_INT)*5 + count(OP_EQ)*15; + + /* The tracer handles these ops well because of inlining. */ + goodOps += (count(OP_CALL) + count(OP_NEW))*20; + + /* The tracer specialized typed array access. */ + goodOps += count(OP_TYPED_ARRAY)*10; + + /* The methodjit is faster at array writes, but the tracer is faster for reads. */ + goodOps += count(OP_ARRAY_READ)*15; + + debug_only_printf(LC_TMProfiler, "FEATURE goodOps %u\n", goodOps); + + unprofitable = isCompilationUnprofitable(cx, goodOps); + if (unprofitable) + debug_only_print0(LC_TMProfiler, "NOTRACE: unprofitable\n"); + else if (goodOps >= numAllOps) + traceOK = true; + } + + debug_only_printf(LC_TMProfiler, "TRACE %s:%d = %d\n", entryScript->filename, line, traceOK); + + if (traceOK) { + /* Unblacklist the inner loops. */ + for (uintN i=0; itraceOK = true; + if (IsBlacklisted(loop.top)) { + debug_only_printf(LC_TMProfiler, "Unblacklisting at %d\n", + js_PCToLineNumber(cx, prof->entryScript, loop.top)); + Unblacklist(prof->entryScript, loop.top); + } + } + } + } + + execOK = traceOK; + traceOK = wasTraceOK || traceOK; + + if (!traceOK && !undecided) { + debug_only_printf(LC_TMProfiler, "Blacklisting at %d\n", line); + Blacklist(top); + } + + debug_only_print0(LC_TMProfiler, "\n"); +} + +JS_REQUIRES_STACK MonitorResult +MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, JSInterpMode interpMode) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_FROM_CONTEXT(cx); + if (interpMode == JSINTERP_PROFILE && tm->profile) + return tm->profile->profileLoopEdge(cx, inlineCallCount); + else + return RecordLoopEdge(cx, tm, inlineCallCount); +} + +void +AbortProfiling(JSContext *cx) +{ + JS_ASSERT(TRACE_PROFILER(cx)); + LoopProfile *prof = TRACE_PROFILER(cx); + + debug_only_print0(LC_TMProfiler, "Profiling complete (aborted)\n"); + prof->profiled = true; + prof->traceOK = false; + prof->execOK = false; + prof->stopProfiling(cx); +} + +#else /* JS_METHODJIT */ + +JS_REQUIRES_STACK MonitorResult +MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, JSInterpMode interpMode) +{ + TraceMonitor *tm = JS_TRACE_MONITOR_FROM_CONTEXT(cx); + return RecordLoopEdge(cx, tm, inlineCallCount); +} + +#endif /* JS_METHODJIT */ + +uint32 +GetHotloop(JSContext *cx) +{ +#ifdef JS_METHODJIT + if (cx->profilingEnabled) + return PROFILE_HOTLOOP; + else +#endif + return 1; +} + +} /* namespace js */ + diff --git a/js/src/jstracer.h b/js/src/jstracer.h new file mode 100644 index 0000000..76921cc --- /dev/null +++ b/js/src/jstracer.h @@ -0,0 +1,1895 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * Andreas Gal + * Mike Shaver + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jstracer_h___ +#define jstracer_h___ + +#ifdef JS_TRACER + +#include "jstypes.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsdhash.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsvector.h" +#include "jscompartment.h" +#include "Writer.h" + +namespace js { + +template +class Queue { + T* _data; + unsigned _len; + unsigned _max; + nanojit::Allocator* alloc; + +public: + void ensure(unsigned size) { + if (_max > size) + return; + if (!_max) + _max = 8; + _max = JS_MAX(_max * 2, size); + if (alloc) { + T* tmp = new (*alloc) T[_max]; + memcpy(tmp, _data, _len * sizeof(T)); + _data = tmp; + } else { + _data = (T*)js_realloc(_data, _max * sizeof(T)); + } +#if defined(DEBUG) + memset(&_data[_len], 0xcd, _max - _len); +#endif + } + + Queue(nanojit::Allocator* alloc) + : alloc(alloc) + { + this->_max = + this->_len = 0; + this->_data = NULL; + } + + ~Queue() { + if (!alloc) + js_free(_data); + } + + bool contains(T a) { + for (unsigned n = 0; n < _len; ++n) { + if (_data[n] == a) + return true; + } + return false; + } + + void add(T a) { + ensure(_len + 1); + JS_ASSERT(_len <= _max); + _data[_len++] = a; + } + + void add(T* chunk, unsigned size) { + ensure(_len + size); + JS_ASSERT(_len <= _max); + memcpy(&_data[_len], chunk, size * sizeof(T)); + _len += size; + } + + void addUnique(T a) { + if (!contains(a)) + add(a); + } + + void setLength(unsigned len) { + ensure(len + 1); + _len = len; + } + + void clear() { + _len = 0; + } + + T & get(unsigned i) { + JS_ASSERT(i < length()); + return _data[i]; + } + + const T & get(unsigned i) const { + JS_ASSERT(i < length()); + return _data[i]; + } + + T & operator [](unsigned i) { + return get(i); + } + + const T & operator [](unsigned i) const { + return get(i); + } + + unsigned length() const { + return _len; + } + + T* data() const { + return _data; + } + + int offsetOf(T slot) { + T* p = _data; + unsigned n = 0; + for (n = 0; n < _len; ++n) + if (*p++ == slot) + return n; + return -1; + } + +}; + +/* + * Tracker is used to keep track of values being manipulated by the interpreter + * during trace recording. It maps opaque, 4-byte aligned address to LIns pointers. + * pointers. To do this efficiently, we observe that the addresses of jsvals + * living in the interpreter tend to be aggregated close to each other - + * usually on the same page (where a tracker page doesn't have to be the same + * size as the OS page size, but it's typically similar). The Tracker + * consists of a linked-list of structures representing a memory page, which + * are created on-demand as memory locations are used. + * + * For every address, first we split it into two parts: upper bits which + * represent the "base", and lower bits which represent an offset against the + * base. For the offset, we then right-shift it by two because the bottom two + * bits of a 4-byte aligned address are always zero. The mapping then + * becomes: + * + * page = page in pagelist such that Base(address) == page->base, + * page->map[Offset(address)] + */ +class Tracker { + #define TRACKER_PAGE_SZB 4096 + #define TRACKER_PAGE_ENTRIES (TRACKER_PAGE_SZB >> 2) // each slot is 4 bytes + #define TRACKER_PAGE_MASK jsuword(TRACKER_PAGE_SZB - 1) + + struct TrackerPage { + struct TrackerPage* next; + jsuword base; + nanojit::LIns* map[TRACKER_PAGE_ENTRIES]; + }; + struct TrackerPage* pagelist; + + jsuword getTrackerPageBase(const void* v) const; + jsuword getTrackerPageOffset(const void* v) const; + struct TrackerPage* findTrackerPage(const void* v) const; + struct TrackerPage* addTrackerPage(const void* v); +public: + Tracker(); + ~Tracker(); + + bool has(const void* v) const; + nanojit::LIns* get(const void* v) const; + void set(const void* v, nanojit::LIns* ins); + void clear(); +}; + +class VMFragment : public nanojit::Fragment { +public: + VMFragment(const void* _ip verbose_only(, uint32_t profFragID)) + : Fragment(_ip verbose_only(, profFragID)) + {} + + /* + * If this is anchored off a TreeFragment, this points to that tree fragment. + * Otherwise, it is |this|. + */ + TreeFragment* root; + + TreeFragment* toTreeFragment(); +}; + +#ifdef NJ_NO_VARIADIC_MACROS + +#define debug_only_stmt(action) /* */ +static void debug_only_printf(int mask, const char *fmt, ...) JS_BEGIN_MACRO JS_END_MACRO +#define debug_only_print0(mask, str) JS_BEGIN_MACRO JS_END_MACRO + +#elif defined(JS_JIT_SPEW) + +// Top level logging controller object. +extern nanojit::LogControl LogController; + +// Top level profiling hook, needed to harvest profile info from Fragments +// whose logical lifetime is about to finish +extern void FragProfiling_FragFinalizer(nanojit::Fragment* f, TraceMonitor*); + +#define debug_only_stmt(stmt) \ + stmt + +#define debug_only_printf(mask, fmt, ...) \ + JS_BEGIN_MACRO \ + if ((LogController.lcbits & (mask)) > 0) { \ + LogController.printf(fmt, __VA_ARGS__); \ + fflush(stdout); \ + } \ + JS_END_MACRO + +#define debug_only_print0(mask, str) \ + JS_BEGIN_MACRO \ + if ((LogController.lcbits & (mask)) > 0) { \ + LogController.printf("%s", str); \ + fflush(stdout); \ + } \ + JS_END_MACRO + +#else + +#define debug_only_stmt(action) /* */ +#define debug_only_printf(mask, fmt, ...) JS_BEGIN_MACRO JS_END_MACRO +#define debug_only_print0(mask, str) JS_BEGIN_MACRO JS_END_MACRO + +#endif + +/* + * The oracle keeps track of hit counts for program counter locations, as + * well as slots that should not be demoted to int because we know them to + * overflow or they result in type-unstable traces. We are using simple + * hash tables. Collisions lead to loss of optimization (demotable slots + * are not demoted, etc.) but have no correctness implications. + */ +#define ORACLE_SIZE 4096 + +class Oracle { + avmplus::BitSet _stackDontDemote; + avmplus::BitSet _globalDontDemote; + avmplus::BitSet _pcDontDemote; + avmplus::BitSet _pcSlowZeroTest; +public: + Oracle(); + + JS_REQUIRES_STACK void markGlobalSlotUndemotable(JSContext* cx, unsigned slot); + JS_REQUIRES_STACK bool isGlobalSlotUndemotable(JSContext* cx, unsigned slot) const; + JS_REQUIRES_STACK void markStackSlotUndemotable(JSContext* cx, unsigned slot); + JS_REQUIRES_STACK void markStackSlotUndemotable(JSContext* cx, unsigned slot, const void* pc); + JS_REQUIRES_STACK bool isStackSlotUndemotable(JSContext* cx, unsigned slot) const; + JS_REQUIRES_STACK bool isStackSlotUndemotable(JSContext* cx, unsigned slot, const void* pc) const; + void markInstructionUndemotable(jsbytecode* pc); + bool isInstructionUndemotable(jsbytecode* pc) const; + void markInstructionSlowZeroTest(jsbytecode* pc); + bool isInstructionSlowZeroTest(jsbytecode* pc) const; + + void clearDemotability(); + void clear() { + clearDemotability(); + } +}; + +typedef Queue SlotList; + +class TypeMap : public Queue { + Oracle *oracle; +public: + TypeMap(nanojit::Allocator* alloc, Oracle *oracle) + : Queue(alloc), + oracle(oracle) + {} + void set(unsigned stackSlots, unsigned ngslots, + const JSValueType* stackTypeMap, const JSValueType* globalTypeMap); + JS_REQUIRES_STACK void captureTypes(JSContext* cx, JSObject* globalObj, SlotList& slots, unsigned callDepth, + bool speculate); + JS_REQUIRES_STACK void captureMissingGlobalTypes(JSContext* cx, JSObject* globalObj, SlotList& slots, + unsigned stackSlots, bool speculate); + bool matches(TypeMap& other) const; + void fromRaw(JSValueType* other, unsigned numSlots); +}; + +#define JS_TM_EXITCODES(_) \ + /* \ + * An exit at a possible branch-point in the trace at which to attach a \ + * future secondary trace. Therefore the recorder must generate different \ + * code to handle the other outcome of the branch condition from the \ + * primary trace's outcome. \ + */ \ + _(BRANCH) \ + /* \ + * Exit at a tableswitch via a numbered case. \ + */ \ + _(CASE) \ + /* \ + * Exit at a tableswitch via the default case. \ + */ \ + _(DEFAULT) \ + _(LOOP) \ + _(NESTED) \ + /* \ + * An exit from a trace because a condition relied upon at recording time \ + * no longer holds, where the alternate path of execution is so rare or \ + * difficult to address in native code that it is not traced at all, e.g. \ + * negative array index accesses, which differ from positive indexes in \ + * that they require a string-based property lookup rather than a simple \ + * memory access. \ + */ \ + _(MISMATCH) \ + /* \ + * A specialization of MISMATCH_EXIT to handle allocation failures. \ + */ \ + _(OOM) \ + _(OVERFLOW) \ + _(MUL_ZERO) \ + _(UNSTABLE_LOOP) \ + _(TIMEOUT) \ + _(DEEP_BAIL) \ + _(STATUS) + +enum ExitType { + #define MAKE_EXIT_CODE(x) x##_EXIT, + JS_TM_EXITCODES(MAKE_EXIT_CODE) + #undef MAKE_EXIT_CODE + TOTAL_EXIT_TYPES +}; + +struct FrameInfo; + +struct VMSideExit : public nanojit::SideExit +{ + jsbytecode* pc; + jsbytecode* imacpc; + intptr_t sp_adj; + intptr_t rp_adj; + int32_t calldepth; + uint32 numGlobalSlots; + uint32 numStackSlots; + uint32 numStackSlotsBelowCurrentFrame; + ExitType exitType; + uintN lookupFlags; + unsigned hitcount; + + inline JSValueType* stackTypeMap() { + return (JSValueType*)(this + 1); + } + + inline JSValueType& stackType(unsigned i) { + JS_ASSERT(i < numStackSlots); + return stackTypeMap()[i]; + } + + inline JSValueType* globalTypeMap() { + return (JSValueType*)(this + 1) + this->numStackSlots; + } + + inline JSValueType* fullTypeMap() { + return stackTypeMap(); + } + + inline VMFragment* fromFrag() { + return (VMFragment*)from; + } + + inline TreeFragment* root() { + return fromFrag()->root; + } +}; + +class VMAllocator : public nanojit::Allocator +{ + +public: + VMAllocator(char* reserve, size_t reserveSize) + : mOutOfMemory(false), mSize(0), mReserve(reserve), + mReserveCurr(uintptr_t(reserve)), mReserveLimit(uintptr_t(reserve + reserveSize)) + {} + + ~VMAllocator() { + js_free(mReserve); + } + + size_t size() { + return mSize; + } + + bool outOfMemory() { + return mOutOfMemory; + } + + struct Mark + { + VMAllocator& vma; + bool committed; + nanojit::Allocator::Chunk* saved_chunk; + char* saved_top; + char* saved_limit; + size_t saved_size; + + Mark(VMAllocator& vma) : + vma(vma), + committed(false), + saved_chunk(vma.current_chunk), + saved_top(vma.current_top), + saved_limit(vma.current_limit), + saved_size(vma.mSize) + {} + + ~Mark() + { + if (!committed) + vma.rewind(*this); + } + + void commit() { committed = true; } + }; + + void rewind(const Mark& m) { + while (current_chunk != m.saved_chunk) { + Chunk *prev = current_chunk->prev; + freeChunk(current_chunk); + current_chunk = prev; + } + current_top = m.saved_top; + current_limit = m.saved_limit; + mSize = m.saved_size; + memset(current_top, 0, current_limit - current_top); + } + + bool mOutOfMemory; + size_t mSize; + + /* See nanojit::Allocator::allocChunk() for details on these. */ + char* mReserve; + uintptr_t mReserveCurr; + uintptr_t mReserveLimit; +}; + +struct FrameInfo { + JSObject* block; // caller block chain head + jsbytecode* pc; // caller fp->regs->pc + jsbytecode* imacpc; // caller fp->imacpc + uint32 spdist; // distance from fp->slots to fp->regs->sp at JSOP_CALL + + /* + * Bit 15 (0x8000) is a flag that is set if constructing (called through new). + * Bits 0-14 are the actual argument count. This may be less than fun->nargs. + * NB: This is argc for the callee, not the caller. + */ + uint32 argc; + + /* + * Number of stack slots in the caller, not counting slots pushed when + * invoking the callee. That is, slots after JSOP_CALL completes but + * without the return value. This is also equal to the number of slots + * between fp->prev->argv[-2] (calleR fp->callee) and fp->argv[-2] + * (calleE fp->callee). + */ + uint32 callerHeight; + + /* argc of the caller */ + uint32 callerArgc; + + // Safer accessors for argc. + enum { CONSTRUCTING_FLAG = 0x10000 }; + void set_argc(uint16 argc, bool constructing) { + this->argc = uint32(argc) | (constructing ? CONSTRUCTING_FLAG: 0); + } + uint16 get_argc() const { return uint16(argc & ~CONSTRUCTING_FLAG); } + bool is_constructing() const { return (argc & CONSTRUCTING_FLAG) != 0; } + + // The typemap just before the callee is called. + JSValueType* get_typemap() { return (JSValueType*) (this+1); } + const JSValueType* get_typemap() const { return (JSValueType*) (this+1); } +}; + +struct UnstableExit +{ + VMFragment* fragment; + VMSideExit* exit; + UnstableExit* next; +}; + +struct LinkableFragment : public VMFragment +{ + LinkableFragment(const void* _ip, nanojit::Allocator* alloc, Oracle *oracle + verbose_only(, uint32_t profFragID)) + : VMFragment(_ip verbose_only(, profFragID)), typeMap(alloc, oracle), nStackTypes(0) + { } + + uint32 branchCount; + TypeMap typeMap; + unsigned nStackTypes; + unsigned spOffsetAtEntry; + SlotList* globalSlots; +}; + +/* + * argc is cx->fp->argc at the trace loop header, i.e., the number of arguments + * pushed for the innermost JS frame. This is required as part of the fragment + * key because the fragment will write those arguments back to the interpreter + * stack when it exits, using its typemap, which implicitly incorporates a + * given value of argc. Without this feature, a fragment could be called as an + * inner tree with two different values of argc, and entry type checking or + * exit frame synthesis could crash. + */ +struct TreeFragment : public LinkableFragment +{ + TreeFragment(const void* _ip, nanojit::Allocator* alloc, Oracle *oracle, JSObject* _globalObj, + uint32 _globalShape, uint32 _argc verbose_only(, uint32_t profFragID)): + LinkableFragment(_ip, alloc, oracle verbose_only(, profFragID)), + first(NULL), + next(NULL), + peer(NULL), + globalObj(_globalObj), + globalShape(_globalShape), + argc(_argc), + dependentTrees(alloc), + linkedTrees(alloc), + sideExits(alloc), + gcthings(alloc), + shapes(alloc) + { } + + TreeFragment* first; + TreeFragment* next; + TreeFragment* peer; + JSObject* globalObj; + uint32 globalShape; + uint32 argc; + /* Dependent trees must be trashed if this tree dies, and updated on missing global types */ + Queue dependentTrees; + /* Linked trees must be updated on missing global types, but are not dependent */ + Queue linkedTrees; +#ifdef DEBUG + const char* treeFileName; + uintN treeLineNumber; + uintN treePCOffset; +#endif + JSScript* script; + UnstableExit* unstableExits; + Queue sideExits; + ptrdiff_t nativeStackBase; + unsigned maxCallDepth; + /* All embedded GC things are registered here so the GC can scan them. */ + Queue gcthings; + Queue shapes; + unsigned maxNativeStackSlots; + /* Gives the number of times we have entered this trace. */ + uintN execs; + /* Gives the total number of iterations executed by the trace (up to a limit). */ + uintN iters; + + inline unsigned nGlobalTypes() { + return typeMap.length() - nStackTypes; + } + inline JSValueType* globalTypeMap() { + return typeMap.data() + nStackTypes; + } + inline JSValueType* stackTypeMap() { + return typeMap.data(); + } + + JS_REQUIRES_STACK void initialize(JSContext* cx, SlotList *globalSlots, bool speculate); + UnstableExit* removeUnstableExit(VMSideExit* exit); +}; + +inline TreeFragment* +VMFragment::toTreeFragment() +{ + JS_ASSERT(root == this); + return static_cast(this); +} + +enum MonitorResult { + MONITOR_RECORDING, + MONITOR_NOT_RECORDING, + MONITOR_ERROR +}; + +const uintN PROFILE_MAX_INNER_LOOPS = 8; +const uintN PROFILE_MAX_STACK = 6; + +/* + * A loop profile keeps track of the instruction mix of a hot loop. We use this + * information to predict whether tracing would be beneficial for the loop. + */ +class LoopProfile +{ +public: + /* Instructions are divided into a few categories. */ + enum OpKind { + OP_FLOAT, // Floating point arithmetic + OP_INT, // Integer arithmetic + OP_BIT, // Bit operations + OP_EQ, // == and != + OP_EVAL, // Calls to eval() + OP_CALL, // JSOP_CALL instructions + OP_FWDJUMP, // Jumps with positive delta + OP_NEW, // JSOP_NEW instructions + OP_RECURSIVE, // Recursive calls + OP_ARRAY_READ, // Reads from dense arrays + OP_TYPED_ARRAY, // Accesses to typed arrays + OP_LIMIT + }; + + /* The TraceMonitor for which we're profiling. */ + TraceMonitor *traceMonitor; + + /* The script in which the loop header lives. */ + JSScript *entryScript; + + /* The stack frame where we started profiling. Only valid while profiling! */ + JSStackFrame *entryfp; + + /* The bytecode locations of the loop header and the back edge. */ + jsbytecode *top, *bottom; + + /* Number of times we have seen this loop executed; used to decide when to profile. */ + uintN hits; + + /* Whether we have run a complete profile of the loop. */ + bool profiled; + + /* Sometimes we can't decide in one profile run whether to trace, so we set undecided. */ + bool undecided; + + /* If we have profiled the loop, this saves the decision of whether to trace it. */ + bool traceOK; + + /* Memoized value of isCompilationUnprofitable. */ + bool unprofitable; + + /* + * Sometimes loops are not good tracing opportunities, but they are nested inside + * loops that we want to trace. In that case, we set their traceOK flag to true, + * but we set execOK to false. That way, the loop is traced so that it can be + * integrated into the outer trace. But we never execute the trace on its only. + */ + bool execOK; + + /* Instruction mix for the loop and total number of instructions. */ + uintN allOps[OP_LIMIT]; + uintN numAllOps; + + /* Instruction mix and total for the loop, excluding nested inner loops. */ + uintN selfOps[OP_LIMIT]; + uintN numSelfOps; + + /* + * A prediction of the number of instructions we would have to compile + * for the loop. This takes into account the fact that a branch may cause us to + * compile every instruction after it twice. Polymorphic calls are + * treated as n-way branches. + */ + double numSelfOpsMult; + + /* + * This keeps track of the number of times that every succeeding instruction + * in the trace will have to be compiled. Every time we hit a branch, we + * double this number. Polymorphic calls multiply it by n (for n-way + * polymorphism). + */ + double branchMultiplier; + + /* Set to true if the loop is short (i.e., has fewer than 8 iterations). */ + bool shortLoop; + + /* Set to true if the loop may be short (has few iterations at profiling time). */ + bool maybeShortLoop; + + /* + * When we hit a nested loop while profiling, we record where it occurs + * and how many iterations we execute it. + */ + struct InnerLoop { + JSStackFrame *entryfp; + jsbytecode *top, *bottom; + uintN iters; + + InnerLoop() {} + InnerLoop(JSStackFrame *entryfp, jsbytecode *top, jsbytecode *bottom) + : entryfp(entryfp), top(top), bottom(bottom), iters(0) {} + }; + + /* These two variables track all the inner loops seen while profiling (up to a limit). */ + InnerLoop innerLoops[PROFILE_MAX_INNER_LOOPS]; + uintN numInnerLoops; + + /* + * These two variables track the loops that we are currently nested + * inside while profiling. Loops get popped off here when they exit. + */ + InnerLoop loopStack[PROFILE_MAX_INNER_LOOPS]; + uintN loopStackDepth; + + /* + * These fields keep track of values on the JS stack. If the stack grows larger + * than PROFILE_MAX_STACK, we continue to track sp, but we return conservative results + * for stackTop(). + */ + struct StackValue { + bool isConst; + bool hasValue; + int value; + + StackValue() : isConst(false), hasValue(false) {} + StackValue(bool isConst) : isConst(isConst), hasValue(false) {} + StackValue(bool isConst, int value) : isConst(isConst), hasValue(true), value(value) {} + }; + StackValue stack[PROFILE_MAX_STACK]; + uintN sp; + + inline void stackClear() { sp = 0; } + + inline void stackPush(const StackValue &v) { + if (sp < PROFILE_MAX_STACK) + stack[sp++] = v; + else + stackClear(); + } + + inline void stackPop() { if (sp > 0) sp--; } + + inline StackValue stackAt(int pos) { + pos += sp; + if (pos >= 0 && uintN(pos) < PROFILE_MAX_STACK) + return stack[pos]; + else + return StackValue(false); + } + + LoopProfile(TraceMonitor *tm, JSStackFrame *entryfp, jsbytecode *top, jsbytecode *bottom); + + void reset(); + + enum ProfileAction { + ProfContinue, + ProfComplete + }; + + /* These two functions track the instruction mix. */ + inline void increment(OpKind kind) + { + allOps[kind]++; + if (loopStackDepth == 0) + selfOps[kind]++; + } + + inline uintN count(OpKind kind) { return allOps[kind]; } + + /* Called for every back edge being profiled. */ + MonitorResult profileLoopEdge(JSContext* cx, uintN& inlineCallCount); + + /* Called for every instruction being profiled. */ + ProfileAction profileOperation(JSContext *cx, JSOp op); + + /* Once a loop's profile is done, these decide whether it should be traced. */ + bool isCompilationExpensive(JSContext *cx, uintN depth); + bool isCompilationUnprofitable(JSContext *cx, uintN goodOps); + void decide(JSContext *cx); + + void stopProfiling(JSContext *cx); +}; + +/* + * BUILTIN_NO_FIXUP_NEEDED indicates that after the initial LeaveTree of a deep + * bail, the builtin call needs no further fixup when the trace exits and calls + * LeaveTree the second time. + */ +typedef enum BuiltinStatus { + BUILTIN_BAILED = 1, + BUILTIN_ERROR = 2 +} BuiltinStatus; + +static JS_INLINE void +SetBuiltinError(TraceMonitor *tm) +{ + tm->tracerState->builtinStatus |= BUILTIN_ERROR; +} + +static JS_INLINE bool +WasBuiltinSuccessful(TraceMonitor *tm) +{ + return tm->tracerState->builtinStatus == 0; +} + +#ifdef DEBUG_RECORDING_STATUS_NOT_BOOL +/* #define DEBUG_RECORDING_STATUS_NOT_BOOL to detect misuses of RecordingStatus */ +struct RecordingStatus { + int code; + bool operator==(RecordingStatus &s) { return this->code == s.code; }; + bool operator!=(RecordingStatus &s) { return this->code != s.code; }; +}; +enum RecordingStatusCodes { + RECORD_ERROR_code = 0, + RECORD_STOP_code = 1, + + RECORD_CONTINUE_code = 3, + RECORD_IMACRO_code = 4 +}; +RecordingStatus RECORD_CONTINUE = { RECORD_CONTINUE_code }; +RecordingStatus RECORD_STOP = { RECORD_STOP_code }; +RecordingStatus RECORD_IMACRO = { RECORD_IMACRO_code }; +RecordingStatus RECORD_ERROR = { RECORD_ERROR_code }; + +struct AbortableRecordingStatus { + int code; + bool operator==(AbortableRecordingStatus &s) { return this->code == s.code; }; + bool operator!=(AbortableRecordingStatus &s) { return this->code != s.code; }; +}; +enum AbortableRecordingStatusCodes { + ARECORD_ERROR_code = 0, + ARECORD_STOP_code = 1, + ARECORD_ABORTED_code = 2, + ARECORD_CONTINUE_code = 3, + ARECORD_IMACRO_code = 4, + ARECORD_IMACRO_ABORTED_code = 5, + ARECORD_COMPLETED_code = 6 +}; +AbortableRecordingStatus ARECORD_ERROR = { ARECORD_ERROR_code }; +AbortableRecordingStatus ARECORD_STOP = { ARECORD_STOP_code }; +AbortableRecordingStatus ARECORD_CONTINUE = { ARECORD_CONTINUE_code }; +AbortableRecordingStatus ARECORD_IMACRO = { ARECORD_IMACRO_code }; +AbortableRecordingStatus ARECORD_IMACRO_ABORTED = { ARECORD_IMACRO_ABORTED_code }; +AbortableRecordingStatus ARECORD_ABORTED = { ARECORD_ABORTED_code }; +AbortableRecordingStatus ARECORD_COMPLETED = { ARECORD_COMPLETED_code }; + +static inline AbortableRecordingStatus +InjectStatus(RecordingStatus rs) +{ + AbortableRecordingStatus ars = { rs.code }; + return ars; +} +static inline AbortableRecordingStatus +InjectStatus(AbortableRecordingStatus ars) +{ + return ars; +} + +static inline bool +StatusAbortsRecorderIfActive(AbortableRecordingStatus ars) +{ + return ars == ARECORD_ERROR || ars == ARECORD_STOP; +} +#else + +/* + * Normally, during recording, when the recorder cannot continue, it returns + * ARECORD_STOP to indicate that recording should be aborted by the top-level + * recording function. However, if the recorder reenters the interpreter (e.g., + * when executing an inner loop), there will be an immediate abort. This + * condition must be carefully detected and propagated out of all nested + * recorder calls lest the now-invalid TraceRecorder object be accessed + * accidentally. This condition is indicated by the ARECORD_ABORTED value. + * + * The AbortableRecordingStatus enumeration represents the general set of + * possible results of calling a recorder function. Functions that cannot + * possibly return ARECORD_ABORTED may statically guarantee this to the caller + * using the RecordingStatus enumeration. Ideally, C++ would allow subtyping + * of enumerations, but it doesn't. To simulate subtype conversion manually, + * code should call InjectStatus to inject a value of the restricted set into a + * value of the general set. + */ + +enum RecordingStatus { + RECORD_STOP = 0, // Recording should be aborted at the top-level + // call to the recorder. + RECORD_ERROR = 1, // Recording should be aborted at the top-level + // call to the recorder and the interpreter should + // goto error + RECORD_CONTINUE = 2, // Continue recording. + RECORD_IMACRO = 3 // Entered imacro; continue recording. + // Only JSOP_IS_IMACOP opcodes may return this. +}; + +enum AbortableRecordingStatus { + ARECORD_STOP = 0, // see RECORD_STOP + ARECORD_ERROR = 1, // Recording may or may not have been aborted. + // Recording should be aborted at the top-level + // if it has not already been and the interpreter + // should goto error + ARECORD_CONTINUE = 2, // see RECORD_CONTINUE + ARECORD_IMACRO = 3, // see RECORD_IMACRO + ARECORD_IMACRO_ABORTED = 4, // see comment in TR::monitorRecording. + ARECORD_ABORTED = 5, // Recording has already been aborted; the + // interpreter should continue executing + ARECORD_COMPLETED = 6 // Recording completed successfully, the + // trace recorder has been deleted +}; + +static JS_ALWAYS_INLINE AbortableRecordingStatus +InjectStatus(RecordingStatus rs) +{ + return static_cast(rs); +} + +static JS_ALWAYS_INLINE AbortableRecordingStatus +InjectStatus(AbortableRecordingStatus ars) +{ + return ars; +} + +/* + * Return whether the recording status requires the current recording session + * to be deleted. ERROR means the recording session should be deleted if it + * hasn't already. ABORTED and COMPLETED indicate the recording session is + * already deleted, so they return 'false'. + */ +static JS_ALWAYS_INLINE bool +StatusAbortsRecorderIfActive(AbortableRecordingStatus ars) +{ + return ars <= ARECORD_ERROR; +} +#endif + +class SlotMap; +class SlurpInfo; + +/* Results of trying to compare two typemaps together */ +enum TypeConsensus +{ + TypeConsensus_Okay, /* Two typemaps are compatible */ + TypeConsensus_Undemotes, /* Not compatible now, but would be with pending undemotes. */ + TypeConsensus_Bad /* Typemaps are not compatible */ +}; + +enum TracePointAction { + TPA_Nothing, + TPA_RanStuff, + TPA_Recorded, + TPA_Error +}; + +typedef HashMap GuardedShapeTable; + +#ifdef DEBUG +# define AbortRecording(cx, reason) AbortRecordingImpl(cx, reason) +#else +# define AbortRecording(cx, reason) AbortRecordingImpl(cx) +#endif + +void +AbortProfiling(JSContext *cx); + +class TraceRecorder +{ + /*************************************************************** Recording session constants */ + + /* The context in which recording started. */ + JSContext* const cx; + + /* Cached value of JS_TRACE_MONITOR(cx). */ + TraceMonitor* const traceMonitor; + + /* Cached oracle keeps track of hit counts for program counter locations */ + Oracle* oracle; + + /* The Fragment being recorded by this recording session. */ + VMFragment* const fragment; + + /* The root fragment representing the tree. */ + TreeFragment* const tree; + + /* The global object from the start of recording until now. */ + JSObject* const globalObj; + + /* If non-null, the script of outer loop aborted to start recording this loop. */ + JSScript* const outerScript; + + /* If non-null, the pc of the outer loop aborted to start recording this loop. */ + jsbytecode* const outerPC; + + /* If |outerPC|, the argc to use when looking up |outerPC| in the fragments table. */ + uint32 const outerArgc; + + /* If non-null, the side exit from which we are growing. */ + VMSideExit* const anchor; + + /* Instructions yielding the corresponding trace-const members of TracerState. */ + nanojit::LIns* const cx_ins; + nanojit::LIns* const eos_ins; + nanojit::LIns* const eor_ins; + nanojit::LIns* const loopLabel; + + /* Lazy slot import state. */ + unsigned importStackSlots; + unsigned importGlobalSlots; + TypeMap importTypeMap; + + /* + * The LirBuffer used to supply memory to our LirWriter pipeline. Also contains the most recent + * instruction for {sp, rp, state}. Also contains names for debug JIT spew. Should be split. + */ + nanojit::LirBuffer* const lirbuf; + + /* + * Remembers traceAlloc state before recording started; automatically rewinds when mark is + * destroyed on a failed compilation. + */ + VMAllocator::Mark mark; + + /* Remembers the number of sideExits in treeInfo before recording started. */ + const unsigned numSideExitsBefore; + + /*********************************************************** Recording session mutable state */ + + /* Maps interpreter stack values to the instruction generating that value. */ + Tracker tracker; + + /* Maps interpreter stack values to the instruction writing back to the native stack. */ + Tracker nativeFrameTracker; + + /* The start of the global object's slots we assume for the trackers. */ + Value* global_slots; + + /* The number of interpreted calls entered (and not yet left) since recording began. */ + unsigned callDepth; + + /* The current atom table, mirroring the interpreter loop's variable of the same name. */ + JSAtom** atoms; + Value* consts; + + /* An instruction yielding the current script's strict mode code flag. */ + nanojit::LIns* strictModeCode_ins; + + /* FIXME: Dead, but soon to be used for something or other. */ + Queue cfgMerges; + + /* Indicates whether the current tree should be trashed when the recording session ends. */ + bool trashSelf; + + /* A list of trees to trash at the end of the recording session. */ + Queue whichTreesToTrash; + + /* The set of objects whose shapes already have been guarded. */ + GuardedShapeTable guardedShapeTable; + + /* Current initializer depth, and whether any of the initializers are unoptimized NEWINIT. */ + int initDepth; + bool hadNewInit; + +#ifdef DEBUG + /* + * If we are expecting a record_AddProperty callback for this instruction, + * the shape of the object before adding the data property. Else NULL. + */ + const js::Shape* addPropShapeBefore; +#endif + + /***************************************** Temporal state hoisted into the recording session */ + + /* Carry the return value from a STOP/RETURN to the subsequent record_LeaveFrame. */ + nanojit::LIns* rval_ins; + + /* Carry the return value from a native call to the record_NativeCallComplete. */ + nanojit::LIns* native_rval_ins; + + /* Carry the return value of js_CreateThis to record_NativeCallComplete. */ + nanojit::LIns* newobj_ins; + + /* Carry the JSSpecializedNative used to generate a call to record_NativeCallComplete. */ + JSSpecializedNative* pendingSpecializedNative; + + /* Carry whether this is a jsval on the native stack from finishGetProp to monitorRecording. */ + Value* pendingUnboxSlot; + + /* Carry a guard condition to the beginning of the next monitorRecording. */ + nanojit::LIns* pendingGuardCondition; + + /* See AbortRecordingIfUnexpectedGlobalWrite. */ + js::Vector pendingGlobalSlotsToSet; + + /* Carry whether we have an always-exit from emitIf to checkTraceEnd. */ + bool pendingLoop; + + /* Temporary JSSpecializedNative used to describe non-specialized fast natives. */ + JSSpecializedNative generatedSpecializedNative; + + /* Temporary JSValueType array used to construct temporary typemaps. */ + js::Vector tempTypeMap; + + /* Used to generate LIR. Has a short name because it's used a lot. */ + tjit::Writer w; + + /************************************************************* 10 bajillion member functions */ + + /* + * These would be in Writer if they didn't modify TraceRecorder state. + * They are invoked the via macros below that make them look like they are + * part of Writer (hence the "w_" prefix, which looks like "w."). + */ + nanojit::LIns* w_immpObjGC(JSObject* obj); + nanojit::LIns* w_immpFunGC(JSFunction* fun); + nanojit::LIns* w_immpStrGC(JSString* str); + nanojit::LIns* w_immpShapeGC(const js::Shape* shape); + nanojit::LIns* w_immpIdGC(jsid id); + + #define immpObjGC(obj) name(w_immpObjGC(obj), #obj) + #define immpFunGC(fun) name(w_immpFunGC(fun), #fun) + #define immpStrGC(str) name(w_immpStrGC(str), #str) + #define immpAtomGC(atom) name(w_immpStrGC(ATOM_TO_STRING(atom)), "ATOM_TO_STRING(" #atom ")") + #define immpShapeGC(shape) name(w_immpShapeGC(shape), #shape) + #define immpIdGC(id) name(w_immpIdGC(id), #id) + + /* + * Examines current interpreter state to record information suitable for returning to the + * interpreter through a side exit of the given type. + */ + JS_REQUIRES_STACK VMSideExit* snapshot(ExitType exitType); + + /* + * Creates a separate but identical copy of the given side exit, allowing the guards associated + * with each to be entirely separate even after subsequent patching. + */ + JS_REQUIRES_STACK VMSideExit* copy(VMSideExit* exit); + + /* + * Creates an instruction whose payload is a GuardRecord for the given exit. The instruction + * is suitable for use as the final argument of a single call to LirBuffer::insGuard; do not + * reuse the returned value. + */ + JS_REQUIRES_STACK nanojit::GuardRecord* createGuardRecord(VMSideExit* exit); + + JS_REQUIRES_STACK JS_INLINE void markSlotUndemotable(LinkableFragment* f, unsigned slot); + + JS_REQUIRES_STACK JS_INLINE void markSlotUndemotable(LinkableFragment* f, unsigned slot, const void* pc); + + JS_REQUIRES_STACK unsigned findUndemotesInTypemaps(const TypeMap& typeMap, LinkableFragment* f, + Queue& undemotes); + + JS_REQUIRES_STACK void assertDownFrameIsConsistent(VMSideExit* anchor, FrameInfo* fi); + + JS_REQUIRES_STACK void captureStackTypes(unsigned callDepth, JSValueType* typeMap); + + bool isVoidPtrGlobal(const void* p) const; + bool isGlobal(const Value* p) const; + ptrdiff_t nativeGlobalSlot(const Value *p) const; + ptrdiff_t nativeGlobalOffset(const Value* p) const; + JS_REQUIRES_STACK ptrdiff_t nativeStackOffsetImpl(const void* p) const; + JS_REQUIRES_STACK ptrdiff_t nativeStackOffset(const Value* p) const; + JS_REQUIRES_STACK ptrdiff_t nativeStackSlotImpl(const void* p) const; + JS_REQUIRES_STACK ptrdiff_t nativeStackSlot(const Value* p) const; + JS_REQUIRES_STACK ptrdiff_t nativespOffsetImpl(const void* p) const; + JS_REQUIRES_STACK ptrdiff_t nativespOffset(const Value* p) const; + JS_REQUIRES_STACK void importImpl(tjit::Address addr, const void* p, JSValueType t, + const char *prefix, uintN index, JSStackFrame *fp); + JS_REQUIRES_STACK void import(tjit::Address addr, const Value* p, JSValueType t, + const char *prefix, uintN index, JSStackFrame *fp); + JS_REQUIRES_STACK void import(TreeFragment* tree, nanojit::LIns* sp, unsigned stackSlots, + unsigned callDepth, unsigned ngslots, JSValueType* typeMap); + void trackNativeStackUse(unsigned slots); + + JS_REQUIRES_STACK bool isValidSlot(JSObject *obj, const js::Shape* shape); + JS_REQUIRES_STACK bool lazilyImportGlobalSlot(unsigned slot); + JS_REQUIRES_STACK void importGlobalSlot(unsigned slot); + + void ensureCond(nanojit::LIns** ins, bool* cond); + + JS_REQUIRES_STACK RecordingStatus guard(bool expected, nanojit::LIns* cond, ExitType exitType, + bool abortIfAlwaysExits = false); + JS_REQUIRES_STACK RecordingStatus guard(bool expected, nanojit::LIns* cond, VMSideExit* exit, + bool abortIfAlwaysExits = false); + JS_REQUIRES_STACK nanojit::LIns* guard_xov(nanojit::LOpcode op, nanojit::LIns* d0, + nanojit::LIns* d1, VMSideExit* exit); + + nanojit::LIns* writeBack(nanojit::LIns* i, nanojit::LIns* base, ptrdiff_t offset, + bool shouldDemoteToInt32); + +#ifdef DEBUG + bool isValidFrameObjPtr(void *obj); +#endif + void assertInsideLoop(); + + JS_REQUIRES_STACK void setImpl(void* p, nanojit::LIns* l, bool shouldDemoteToInt32 = true); + JS_REQUIRES_STACK void set(Value* p, nanojit::LIns* l, bool shouldDemoteToInt32 = true); + JS_REQUIRES_STACK void setFrameObjPtr(void* p, nanojit::LIns* l, + bool shouldDemoteToInt32 = true); + nanojit::LIns* getFromTrackerImpl(const void *p); + nanojit::LIns* getFromTracker(const Value* p); + JS_REQUIRES_STACK nanojit::LIns* getImpl(const void* p); + JS_REQUIRES_STACK nanojit::LIns* get(const Value* p); + JS_REQUIRES_STACK nanojit::LIns* getFrameObjPtr(void* p); + JS_REQUIRES_STACK nanojit::LIns* attemptImport(const Value* p); + JS_REQUIRES_STACK nanojit::LIns* addr(Value* p); + + JS_REQUIRES_STACK bool knownImpl(const void* p); + JS_REQUIRES_STACK bool known(const Value* p); + JS_REQUIRES_STACK bool known(JSObject** p); + /* + * The slots of the global object are sometimes reallocated by the + * interpreter. This function checks for that condition and re-maps the + * entries of the tracker accordingly. + */ + JS_REQUIRES_STACK void checkForGlobalObjectReallocation() { + if (global_slots != globalObj->getSlots()) + checkForGlobalObjectReallocationHelper(); + } + JS_REQUIRES_STACK void checkForGlobalObjectReallocationHelper(); + + JS_REQUIRES_STACK TypeConsensus selfTypeStability(SlotMap& smap); + JS_REQUIRES_STACK TypeConsensus peerTypeStability(SlotMap& smap, const void* ip, + TreeFragment** peer); + + JS_REQUIRES_STACK Value& argval(unsigned n) const; + JS_REQUIRES_STACK Value& varval(unsigned n) const; + JS_REQUIRES_STACK Value& stackval(int n) const; + + JS_REQUIRES_STACK void updateAtoms(); + JS_REQUIRES_STACK void updateAtoms(JSScript *script); + + struct NameResult { + // |tracked| is true iff the result of the name lookup is a variable that + // is already in the tracker. The rest of the fields are set only if + // |tracked| is false. + bool tracked; + Value v; // current property value + JSObject *obj; // Call object where name was found + nanojit::LIns *obj_ins; // LIR value for obj + js::Shape *shape; // shape name was resolved to + }; + + JS_REQUIRES_STACK nanojit::LIns* scopeChain(); + JS_REQUIRES_STACK nanojit::LIns* entryScopeChain() const; + JS_REQUIRES_STACK nanojit::LIns* entryFrameIns() const; + JS_REQUIRES_STACK JSStackFrame* frameIfInRange(JSObject* obj, unsigned* depthp = NULL) const; + JS_REQUIRES_STACK RecordingStatus traverseScopeChain(JSObject *obj, nanojit::LIns *obj_ins, JSObject *obj2, nanojit::LIns *&obj2_ins); + JS_REQUIRES_STACK AbortableRecordingStatus scopeChainProp(JSObject* obj, Value*& vp, nanojit::LIns*& ins, NameResult& nr, JSObject **scopeObjp = NULL); + JS_REQUIRES_STACK RecordingStatus callProp(JSObject* obj, JSProperty* shape, jsid id, Value*& vp, nanojit::LIns*& ins, NameResult& nr); + + JS_REQUIRES_STACK nanojit::LIns* arg(unsigned n); + JS_REQUIRES_STACK void arg(unsigned n, nanojit::LIns* i); + JS_REQUIRES_STACK nanojit::LIns* var(unsigned n); + JS_REQUIRES_STACK void var(unsigned n, nanojit::LIns* i); + JS_REQUIRES_STACK nanojit::LIns* upvar(JSScript* script, JSUpvarArray* uva, uintN index, Value& v); + nanojit::LIns* stackLoad(tjit::Address addr, uint8 type); + JS_REQUIRES_STACK nanojit::LIns* stack(int n); + JS_REQUIRES_STACK void stack(int n, nanojit::LIns* i); + + JS_REQUIRES_STACK void guardNonNeg(nanojit::LIns* d0, nanojit::LIns* d1, VMSideExit* exit); + JS_REQUIRES_STACK nanojit::LIns* alu(nanojit::LOpcode op, jsdouble v0, jsdouble v1, + nanojit::LIns* s0, nanojit::LIns* s1); + + nanojit::LIns* d2i(nanojit::LIns* f, bool resultCanBeImpreciseIfFractional = false); + nanojit::LIns* d2u(nanojit::LIns* d); + JS_REQUIRES_STACK RecordingStatus makeNumberInt32(nanojit::LIns* d, nanojit::LIns** num_ins); + JS_REQUIRES_STACK RecordingStatus makeNumberUint32(nanojit::LIns* d, nanojit::LIns** num_ins); + JS_REQUIRES_STACK nanojit::LIns* stringify(const Value& v); + + JS_REQUIRES_STACK nanojit::LIns* newArguments(nanojit::LIns* callee_ins); + + JS_REQUIRES_STACK bool canCallImacro() const; + JS_REQUIRES_STACK RecordingStatus callImacro(jsbytecode* imacro); + JS_REQUIRES_STACK RecordingStatus callImacroInfallibly(jsbytecode* imacro); + + JS_REQUIRES_STACK AbortableRecordingStatus ifop(); + JS_REQUIRES_STACK RecordingStatus switchop(); +#ifdef NANOJIT_IA32 + JS_REQUIRES_STACK AbortableRecordingStatus tableswitch(); +#endif + JS_REQUIRES_STACK RecordingStatus inc(Value& v, jsint incr, bool pre = true); + JS_REQUIRES_STACK RecordingStatus inc(const Value &v, nanojit::LIns*& v_ins, + Value &v_out, jsint incr, + bool pre = true); + JS_REQUIRES_STACK RecordingStatus incHelper(const Value &v, nanojit::LIns*& v_ins, + Value &v_after, + nanojit::LIns*& v_ins_after, + jsint incr); + JS_REQUIRES_STACK AbortableRecordingStatus incProp(jsint incr, bool pre = true); + JS_REQUIRES_STACK RecordingStatus incElem(jsint incr, bool pre = true); + JS_REQUIRES_STACK AbortableRecordingStatus incName(jsint incr, bool pre = true); + + JS_REQUIRES_STACK RecordingStatus strictEquality(bool equal, bool cmpCase); + JS_REQUIRES_STACK AbortableRecordingStatus equality(bool negate, bool tryBranchAfterCond); + JS_REQUIRES_STACK AbortableRecordingStatus equalityHelper(Value& l, Value& r, + nanojit::LIns* l_ins, nanojit::LIns* r_ins, + bool negate, bool tryBranchAfterCond, + Value& rval); + JS_REQUIRES_STACK AbortableRecordingStatus relational(nanojit::LOpcode op, bool tryBranchAfterCond); + + JS_REQUIRES_STACK RecordingStatus unary(nanojit::LOpcode op); + JS_REQUIRES_STACK RecordingStatus binary(nanojit::LOpcode op); + + JS_REQUIRES_STACK RecordingStatus guardShape(nanojit::LIns* obj_ins, JSObject* obj, + uint32 shape, const char* name, VMSideExit* exit); + +#if defined DEBUG_notme && defined XP_UNIX + void dumpGuardedShapes(const char* prefix); +#endif + + void forgetGuardedShapes(); + + JS_REQUIRES_STACK AbortableRecordingStatus test_property_cache(JSObject* obj, nanojit::LIns* obj_ins, + JSObject*& obj2, PCVal& pcval); + JS_REQUIRES_STACK RecordingStatus guardPropertyCacheHit(nanojit::LIns* obj_ins, + JSObject* aobj, + JSObject* obj2, + PropertyCacheEntry* entry, + PCVal& pcval); + + void stobj_set_fslot(nanojit::LIns *obj_ins, unsigned slot, const Value &v, + nanojit::LIns* v_ins); + void stobj_set_dslot(nanojit::LIns *obj_ins, unsigned slot, + nanojit::LIns*& slots_ins, const Value &v, nanojit::LIns* v_ins); + void stobj_set_slot(JSObject *obj, nanojit::LIns* obj_ins, unsigned slot, + nanojit::LIns*& slots_ins, const Value &v, nanojit::LIns* v_ins); + + nanojit::LIns* unbox_slot(JSObject *obj, nanojit::LIns *obj_ins, uint32 slot, + VMSideExit *exit); + + JS_REQUIRES_STACK AbortableRecordingStatus name(Value*& vp, nanojit::LIns*& ins, NameResult& nr); + JS_REQUIRES_STACK AbortableRecordingStatus prop(JSObject* obj, nanojit::LIns* obj_ins, + uint32 *slotp, nanojit::LIns** v_insp, + Value* outp); + JS_REQUIRES_STACK RecordingStatus propTail(JSObject* obj, nanojit::LIns* obj_ins, + JSObject* obj2, PCVal pcval, + uint32 *slotp, nanojit::LIns** v_insp, + Value* outp); + JS_REQUIRES_STACK RecordingStatus denseArrayElement(Value& oval, Value& idx, Value*& vp, + nanojit::LIns*& v_ins, + nanojit::LIns*& addr_ins, + VMSideExit* exit); + JS_REQUIRES_STACK nanojit::LIns *canonicalizeNaNs(nanojit::LIns *dval_ins); + JS_REQUIRES_STACK AbortableRecordingStatus typedArrayElement(Value& oval, Value& idx, Value*& vp, + nanojit::LIns*& v_ins); + JS_REQUIRES_STACK AbortableRecordingStatus getProp(JSObject* obj, nanojit::LIns* obj_ins); + JS_REQUIRES_STACK AbortableRecordingStatus getProp(Value& v); + JS_REQUIRES_STACK RecordingStatus getThis(nanojit::LIns*& this_ins); + + JS_REQUIRES_STACK void storeMagic(JSWhyMagic why, tjit::Address addr); + JS_REQUIRES_STACK AbortableRecordingStatus unboxNextValue(nanojit::LIns* &v_ins); + + JS_REQUIRES_STACK VMSideExit* enterDeepBailCall(); + JS_REQUIRES_STACK void leaveDeepBailCall(); + + JS_REQUIRES_STACK RecordingStatus primitiveToStringInPlace(Value* vp); + JS_REQUIRES_STACK void finishGetProp(nanojit::LIns* obj_ins, nanojit::LIns* vp_ins, + nanojit::LIns* ok_ins, Value* outp); + JS_REQUIRES_STACK RecordingStatus getPropertyByName(nanojit::LIns* obj_ins, Value* idvalp, + Value* outp); + JS_REQUIRES_STACK RecordingStatus getPropertyByIndex(nanojit::LIns* obj_ins, + nanojit::LIns* index_ins, Value* outp); + JS_REQUIRES_STACK RecordingStatus getPropertyById(nanojit::LIns* obj_ins, Value* outp); + JS_REQUIRES_STACK RecordingStatus getPropertyWithNativeGetter(nanojit::LIns* obj_ins, + const js::Shape* shape, + Value* outp); + JS_REQUIRES_STACK RecordingStatus getPropertyWithScriptGetter(JSObject *obj, + nanojit::LIns* obj_ins, + const js::Shape* shape); + + JS_REQUIRES_STACK RecordingStatus getCharCodeAt(JSString *str, + nanojit::LIns* str_ins, nanojit::LIns* idx_ins, + nanojit::LIns** out_ins); + JS_REQUIRES_STACK nanojit::LIns* getUnitString(nanojit::LIns* str_ins, nanojit::LIns* idx_ins); + JS_REQUIRES_STACK RecordingStatus getCharAt(JSString *str, + nanojit::LIns* str_ins, nanojit::LIns* idx_ins, + JSOp mode, nanojit::LIns** out_ins); + + JS_REQUIRES_STACK RecordingStatus initOrSetPropertyByName(nanojit::LIns* obj_ins, + Value* idvalp, Value* rvalp, + bool init); + JS_REQUIRES_STACK RecordingStatus initOrSetPropertyByIndex(nanojit::LIns* obj_ins, + nanojit::LIns* index_ins, + Value* rvalp, bool init); + JS_REQUIRES_STACK AbortableRecordingStatus setElem(int lval_spindex, int idx_spindex, + int v_spindex); + + JS_REQUIRES_STACK RecordingStatus lookupForSetPropertyOp(JSObject* obj, nanojit::LIns* obj_ins, + jsid id, bool* safep, + JSObject** pobjp, + const js::Shape** shapep); + JS_REQUIRES_STACK RecordingStatus nativeSet(JSObject* obj, nanojit::LIns* obj_ins, + const js::Shape* shape, + const Value& v, nanojit::LIns* v_ins); + JS_REQUIRES_STACK RecordingStatus addDataProperty(JSObject* obj); + JS_REQUIRES_STACK RecordingStatus setCallProp(JSObject* callobj, nanojit::LIns* callobj_ins, + const js::Shape* shape, nanojit::LIns* v_ins, + const Value& v); + JS_REQUIRES_STACK RecordingStatus setProperty(JSObject* obj, nanojit::LIns* obj_ins, + const Value& v, nanojit::LIns* v_ins, + bool* deferredp); + JS_REQUIRES_STACK RecordingStatus recordSetPropertyOp(); + JS_REQUIRES_STACK RecordingStatus recordInitPropertyOp(jsbytecode op); + + void box_undefined_into(tjit::Address addr); +#if JS_BITS_PER_WORD == 32 + void box_null_into(tjit::Address addr); + nanojit::LIns* unbox_number_as_double(tjit::Address addr, nanojit::LIns* tag_ins, + VMSideExit* exit); + nanojit::LIns* unbox_object(tjit::Address addr, nanojit::LIns* tag_ins, JSValueType type, + VMSideExit* exit); + nanojit::LIns* unbox_non_double_object(tjit::Address addr, nanojit::LIns* tag_ins, + JSValueType type, VMSideExit* exit); +#elif JS_BITS_PER_WORD == 64 + nanojit::LIns* non_double_object_value_has_type(nanojit::LIns* v_ins, JSValueType type); + nanojit::LIns* unpack_ptr(nanojit::LIns* v_ins); + nanojit::LIns* unbox_number_as_double(nanojit::LIns* v_ins, VMSideExit* exit); + nanojit::LIns* unbox_object(nanojit::LIns* v_ins, JSValueType type, VMSideExit* exit); + nanojit::LIns* unbox_non_double_object(nanojit::LIns* v_ins, JSValueType type, VMSideExit* exit); +#endif + + nanojit::LIns* unbox_value(const Value& v, tjit::Address addr, VMSideExit* exit, + bool force_double=false); + void unbox_any_object(tjit::Address addr, nanojit::LIns** obj_ins, nanojit::LIns** is_obj_ins); + nanojit::LIns* is_boxed_true(tjit::Address addr); + nanojit::LIns* is_boxed_magic(tjit::Address addr, JSWhyMagic why); + + nanojit::LIns* is_string_id(nanojit::LIns* id_ins); + nanojit::LIns* unbox_string_id(nanojit::LIns* id_ins); + nanojit::LIns* unbox_int_id(nanojit::LIns* id_ins); + + /* Box a slot on trace into the given address at the given offset. */ + void box_value_into(const Value& v, nanojit::LIns* v_ins, tjit::Address addr); + + /* + * Box a slot so that it may be passed with value semantics to a native. On + * 32-bit, this currently means boxing the value into insAlloc'd memory and + * returning the address which is passed as a Value*. On 64-bit, this + * currently means returning the boxed value which is passed as a jsval. + */ + nanojit::LIns* box_value_for_native_call(const Value& v, nanojit::LIns* v_ins); + + /* Box a slot into insAlloc'd memory. */ + nanojit::LIns* box_value_into_alloc(const Value& v, nanojit::LIns* v_ins); + + JS_REQUIRES_STACK void guardClassHelper(bool cond, nanojit::LIns* obj_ins, Class* clasp, + VMSideExit* exit, nanojit::LoadQual loadQual); + JS_REQUIRES_STACK void guardClass(nanojit::LIns* obj_ins, Class* clasp, + VMSideExit* exit, nanojit::LoadQual loadQual); + JS_REQUIRES_STACK void guardNotClass(nanojit::LIns* obj_ins, Class* clasp, + VMSideExit* exit, nanojit::LoadQual loadQual); + JS_REQUIRES_STACK void guardDenseArray(nanojit::LIns* obj_ins, ExitType exitType); + JS_REQUIRES_STACK void guardDenseArray(nanojit::LIns* obj_ins, VMSideExit* exit); + JS_REQUIRES_STACK bool guardHasPrototype(JSObject* obj, nanojit::LIns* obj_ins, + JSObject** pobj, nanojit::LIns** pobj_ins, + VMSideExit* exit); + JS_REQUIRES_STACK RecordingStatus guardPrototypeHasNoIndexedProperties(JSObject* obj, + nanojit::LIns* obj_ins, + VMSideExit* exit); + JS_REQUIRES_STACK RecordingStatus guardNativeConversion(Value& v); + JS_REQUIRES_STACK void clearReturningFrameFromNativeTracker(); + JS_REQUIRES_STACK AbortableRecordingStatus putActivationObjects(); + JS_REQUIRES_STACK RecordingStatus createThis(JSObject& ctor, nanojit::LIns* ctor_ins, + nanojit::LIns** thisobj_insp); + JS_REQUIRES_STACK RecordingStatus guardCallee(Value& callee); + JS_REQUIRES_STACK JSStackFrame *guardArguments(JSObject *obj, nanojit::LIns* obj_ins, + unsigned *depthp); + JS_REQUIRES_STACK nanojit::LIns* guardArgsLengthNotAssigned(nanojit::LIns* argsobj_ins); + JS_REQUIRES_STACK void guardNotHole(nanojit::LIns* argsobj_ins, nanojit::LIns* ids_ins); + JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSObject* ctor, + nanojit::LIns*& proto_ins); + JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSProtoKey key, + nanojit::LIns*& proto_ins); + JS_REQUIRES_STACK RecordingStatus newArray(JSObject* ctor, uint32 argc, Value* argv, + Value* rval); + JS_REQUIRES_STACK RecordingStatus newString(JSObject* ctor, uint32 argc, Value* argv, + Value* rval); + JS_REQUIRES_STACK RecordingStatus interpretedFunctionCall(Value& fval, JSFunction* fun, + uintN argc, bool constructing); + JS_REQUIRES_STACK void propagateFailureToBuiltinStatus(nanojit::LIns *ok_ins, + nanojit::LIns *&status_ins); + JS_REQUIRES_STACK RecordingStatus emitNativeCall(JSSpecializedNative* sn, uintN argc, + nanojit::LIns* args[], bool rooted); + JS_REQUIRES_STACK void emitNativePropertyOp(const js::Shape* shape, + nanojit::LIns* obj_ins, + bool setflag, + nanojit::LIns* addr_boxed_val_ins); + JS_REQUIRES_STACK RecordingStatus callSpecializedNative(JSNativeTraceInfo* trcinfo, uintN argc, + bool constructing); + JS_REQUIRES_STACK RecordingStatus callNative(uintN argc, JSOp mode); + JS_REQUIRES_STACK RecordingStatus callFloatReturningInt(uintN argc, + const nanojit::CallInfo *ci); + JS_REQUIRES_STACK RecordingStatus functionCall(uintN argc, JSOp mode); + + JS_REQUIRES_STACK void trackCfgMerges(jsbytecode* pc); + JS_REQUIRES_STACK void emitIf(jsbytecode* pc, bool cond, nanojit::LIns* x); + JS_REQUIRES_STACK void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x); + JS_REQUIRES_STACK AbortableRecordingStatus checkTraceEnd(jsbytecode* pc); + + AbortableRecordingStatus hasMethod(JSObject* obj, jsid id, bool& found); + JS_REQUIRES_STACK AbortableRecordingStatus hasIteratorMethod(JSObject* obj, bool& found); + + JS_REQUIRES_STACK jsatomid getFullIndex(ptrdiff_t pcoff = 0); + + JS_REQUIRES_STACK JSValueType determineSlotType(Value* vp); + + JS_REQUIRES_STACK RecordingStatus setUpwardTrackedVar(Value* stackVp, const Value& v, + nanojit::LIns* v_ins); + + JS_REQUIRES_STACK AbortableRecordingStatus compile(); + JS_REQUIRES_STACK AbortableRecordingStatus closeLoop(); + JS_REQUIRES_STACK AbortableRecordingStatus endLoop(); + JS_REQUIRES_STACK AbortableRecordingStatus endLoop(VMSideExit* exit); + JS_REQUIRES_STACK void joinEdgesToEntry(TreeFragment* peer_root); + JS_REQUIRES_STACK void adjustCallerTypes(TreeFragment* f); + JS_REQUIRES_STACK void prepareTreeCall(TreeFragment* inner); + JS_REQUIRES_STACK void emitTreeCall(TreeFragment* inner, VMSideExit* exit); + JS_REQUIRES_STACK void determineGlobalTypes(JSValueType* typeMap); + JS_REQUIRES_STACK VMSideExit* downSnapshot(FrameInfo* downFrame); + JS_REQUIRES_STACK TreeFragment* findNestedCompatiblePeer(TreeFragment* f); + JS_REQUIRES_STACK AbortableRecordingStatus attemptTreeCall(TreeFragment* inner, + uintN& inlineCallCount); + + static JS_REQUIRES_STACK MonitorResult recordLoopEdge(JSContext* cx, TraceRecorder* r, + uintN& inlineCallCount); + + /* Allocators associated with this recording session. */ + VMAllocator& tempAlloc() const { return *traceMonitor->tempAlloc; } + VMAllocator& traceAlloc() const { return *traceMonitor->traceAlloc; } + VMAllocator& dataAlloc() const { return *traceMonitor->dataAlloc; } + + /* Member declarations for each opcode, to be called before interpreting the opcode. */ +#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ + JS_REQUIRES_STACK AbortableRecordingStatus record_##op(); +# include "jsopcode.tbl" +#undef OPDEF + + JS_REQUIRES_STACK + TraceRecorder(JSContext* cx, TraceMonitor *tm, VMSideExit*, VMFragment*, + unsigned stackSlots, unsigned ngslots, JSValueType* typeMap, + VMSideExit* expectedInnerExit, JSScript* outerScript, jsbytecode* outerPC, + uint32 outerArgc, bool speculate); + + /* The destructor should only be called through finish*, not directly. */ + ~TraceRecorder(); + JS_REQUIRES_STACK AbortableRecordingStatus finishSuccessfully(); + + enum AbortResult { NORMAL_ABORT, JIT_RESET }; + JS_REQUIRES_STACK AbortResult finishAbort(const char* reason); + + friend class ImportBoxedStackSlotVisitor; + friend class ImportUnboxedStackSlotVisitor; + friend class ImportGlobalSlotVisitor; + friend class AdjustCallerGlobalTypesVisitor; + friend class AdjustCallerStackTypesVisitor; + friend class TypeCompatibilityVisitor; + friend class ImportFrameSlotsVisitor; + friend class SlotMap; + friend class DefaultSlotMap; + friend class DetermineTypesVisitor; + friend class RecursiveSlotMap; + friend class UpRecursiveSlotMap; + friend MonitorResult RecordLoopEdge(JSContext*, TraceMonitor*, uintN&); + friend TracePointAction RecordTracePoint(JSContext*, TraceMonitor*, uintN &inlineCallCount, + bool *blacklist); + friend AbortResult AbortRecording(JSContext*, const char*); + friend class BoxArg; + friend void TraceMonitor::sweep(JSContext *cx); + + public: + static bool JS_REQUIRES_STACK + startRecorder(JSContext*, TraceMonitor *, VMSideExit*, VMFragment*, + unsigned stackSlots, unsigned ngslots, JSValueType* typeMap, + VMSideExit* expectedInnerExit, JSScript* outerScript, jsbytecode* outerPC, + uint32 outerArgc, bool speculate); + + /* Accessors. */ + VMFragment* getFragment() const { return fragment; } + TreeFragment* getTree() const { return tree; } + bool outOfMemory() const { return traceMonitor->outOfMemory(); } + Oracle* getOracle() const { return oracle; } + JSObject* getGlobal() const { return globalObj; } + + /* Entry points / callbacks from the interpreter. */ + JS_REQUIRES_STACK AbortableRecordingStatus monitorRecording(JSOp op); + JS_REQUIRES_STACK AbortableRecordingStatus record_EnterFrame(); + JS_REQUIRES_STACK AbortableRecordingStatus record_LeaveFrame(); + JS_REQUIRES_STACK AbortableRecordingStatus record_AddProperty(JSObject *obj); + JS_REQUIRES_STACK AbortableRecordingStatus record_DefLocalFunSetSlot(uint32 slot, + JSObject* obj); + JS_REQUIRES_STACK AbortableRecordingStatus record_NativeCallComplete(); + void forgetGuardedShapesForObject(JSObject* obj); + + bool globalSetExpected(unsigned slot) { + unsigned *pi = Find(pendingGlobalSlotsToSet, slot); + if (pi == pendingGlobalSlotsToSet.end()) { + /* + * Do slot arithmetic manually to avoid getSlotRef assertions which + * do not need to be satisfied for this purpose. + */ + Value *vp = globalObj->getSlots() + slot; + + /* If this global is definitely being tracked, then the write is unexpected. */ + if (tracker.has(vp)) + return false; + + /* + * Otherwise, only abort if the global is not present in the + * import typemap. Just deep aborting false here is not acceptable, + * because the recorder does not guard on every operation that + * could lazily resolve. Since resolving adds properties to + * reserved slots, the tracer will never have imported them. + */ + return tree->globalSlots->offsetOf((uint16)nativeGlobalSlot(vp)) == -1; + } + pendingGlobalSlotsToSet.erase(pi); + return true; + } + +#ifdef DEBUG + /* Debug printing functionality to emit printf() on trace. */ + JS_REQUIRES_STACK void tprint(const char *format, int count, nanojit::LIns *insa[]); + JS_REQUIRES_STACK void tprint(const char *format); + JS_REQUIRES_STACK void tprint(const char *format, nanojit::LIns *ins); + JS_REQUIRES_STACK void tprint(const char *format, nanojit::LIns *ins1, + nanojit::LIns *ins2); + JS_REQUIRES_STACK void tprint(const char *format, nanojit::LIns *ins1, + nanojit::LIns *ins2, nanojit::LIns *ins3); + JS_REQUIRES_STACK void tprint(const char *format, nanojit::LIns *ins1, + nanojit::LIns *ins2, nanojit::LIns *ins3, + nanojit::LIns *ins4); + JS_REQUIRES_STACK void tprint(const char *format, nanojit::LIns *ins1, + nanojit::LIns *ins2, nanojit::LIns *ins3, + nanojit::LIns *ins4, nanojit::LIns *ins5); + JS_REQUIRES_STACK void tprint(const char *format, nanojit::LIns *ins1, + nanojit::LIns *ins2, nanojit::LIns *ins3, + nanojit::LIns *ins4, nanojit::LIns *ins5, + nanojit::LIns *ins6); +#endif +}; + +#define TRACING_ENABLED(cx) ((cx)->traceJitEnabled) +#define REGEX_JIT_ENABLED(cx) ((cx)->traceJitEnabled || (cx)->methodJitEnabled) + +#define JSOP_IN_RANGE(op,lo,hi) (uintN((op) - (lo)) <= uintN((hi) - (lo))) +#define JSOP_IS_BINARY(op) JSOP_IN_RANGE(op, JSOP_BITOR, JSOP_MOD) +#define JSOP_IS_UNARY(op) JSOP_IN_RANGE(op, JSOP_NEG, JSOP_POS) +#define JSOP_IS_EQUALITY(op) JSOP_IN_RANGE(op, JSOP_EQ, JSOP_NE) + +#define TRACE_ARGS_(x,args) \ + JS_BEGIN_MACRO \ + if (TraceRecorder* tr_ = TRACE_RECORDER(cx)) { \ + AbortableRecordingStatus status = tr_->record_##x args; \ + if (StatusAbortsRecorderIfActive(status)) { \ + if (TRACE_RECORDER(cx)) { \ + JS_ASSERT(TRACE_RECORDER(cx) == tr_); \ + AbortRecording(cx, #x); \ + } \ + if (status == ARECORD_ERROR) \ + goto error; \ + } \ + JS_ASSERT(status != ARECORD_IMACRO); \ + } \ + JS_END_MACRO + +#define TRACE_ARGS(x,args) TRACE_ARGS_(x, args) +#define TRACE_0(x) TRACE_ARGS(x, ()) +#define TRACE_1(x,a) TRACE_ARGS(x, (a)) +#define TRACE_2(x,a,b) TRACE_ARGS(x, (a, b)) + +extern JS_REQUIRES_STACK MonitorResult +MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, JSInterpMode interpMode); + +extern JS_REQUIRES_STACK TracePointAction +RecordTracePoint(JSContext*, uintN& inlineCallCount, bool* blacklist); + +extern JS_REQUIRES_STACK TracePointAction +MonitorTracePoint(JSContext*, uintN& inlineCallCount, bool* blacklist, + void** traceData, uintN *traceEpoch, uint32 *loopCounter, uint32 hits); + +extern JS_REQUIRES_STACK TraceRecorder::AbortResult +AbortRecording(JSContext* cx, const char* reason); + +extern bool +InitJIT(TraceMonitor *tm); + +extern void +FinishJIT(TraceMonitor *tm); + +extern void +PurgeScriptFragments(TraceMonitor* tm, JSScript* script); + +extern bool +OverfullJITCache(JSContext *cx, TraceMonitor* tm); + +extern void +FlushJITCache(JSContext* cx, TraceMonitor* tm); + +extern JSObject * +GetBuiltinFunction(JSContext *cx, uintN index); + +extern void +SetMaxCodeCacheBytes(JSContext* cx, uint32 bytes); + +extern void +ExternNativeToValue(JSContext* cx, Value& v, JSValueType type, double* slot); + +#ifdef MOZ_TRACEVIS + +extern JS_FRIEND_API(bool) +StartTraceVis(const char* filename); + +extern JS_FRIEND_API(JSBool) +StartTraceVisNative(JSContext *cx, uintN argc, jsval *vp); + +extern JS_FRIEND_API(bool) +StopTraceVis(); + +extern JS_FRIEND_API(JSBool) +StopTraceVisNative(JSContext *cx, uintN argc, jsval *vp); + +/* Must contain no more than 16 items. */ +enum TraceVisState { + // Special: means we returned from current activity to last + S_EXITLAST, + // Activities + S_INTERP, + S_MONITOR, + S_RECORD, + S_COMPILE, + S_EXECUTE, + S_NATIVE, + // Events: these all have (bit 3) == 1. + S_RESET = 8 +}; + +/* Reason for an exit to the interpreter. */ +enum TraceVisExitReason { + R_NONE, + R_ABORT, + /* Reasons in MonitorLoopEdge */ + R_INNER_SIDE_EXIT, + R_DOUBLES, + R_CALLBACK_PENDING, + R_OOM_GETANCHOR, + R_BACKED_OFF, + R_COLD, + R_FAIL_RECORD_TREE, + R_MAX_PEERS, + R_FAIL_EXECUTE_TREE, + R_FAIL_STABILIZE, + R_FAIL_EXTEND_FLUSH, + R_FAIL_EXTEND_MAX_BRANCHES, + R_FAIL_EXTEND_START, + R_FAIL_EXTEND_COLD, + R_FAIL_SCOPE_CHAIN_CHECK, + R_NO_EXTEND_OUTER, + R_MISMATCH_EXIT, + R_OOM_EXIT, + R_TIMEOUT_EXIT, + R_DEEP_BAIL_EXIT, + R_STATUS_EXIT, + R_OTHER_EXIT +}; + +enum TraceVisFlushReason { + FR_DEEP_BAIL, + FR_OOM, + FR_GLOBAL_SHAPE_MISMATCH, + FR_GLOBALS_FULL +}; + +const unsigned long long MS64_MASK = 0xfull << 60; +const unsigned long long MR64_MASK = 0x1full << 55; +const unsigned long long MT64_MASK = ~(MS64_MASK | MR64_MASK); + +extern FILE* traceVisLogFile; +extern JSHashTable *traceVisScriptTable; + +extern JS_FRIEND_API(void) +StoreTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r); + +static inline void +LogTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r) +{ + if (traceVisLogFile) { + unsigned long long sllu = s; + unsigned long long rllu = r; + unsigned long long d = (sllu << 60) | (rllu << 55) | (rdtsc() & MT64_MASK); + fwrite(&d, sizeof(d), 1, traceVisLogFile); + } + if (traceVisScriptTable) { + StoreTraceVisState(cx, s, r); + } +} + +/* + * Although this runs the same code as LogTraceVisState, it is a separate + * function because the meaning of the log entry is different. Also, the entry + * formats may diverge someday. + */ +static inline void +LogTraceVisEvent(JSContext *cx, TraceVisState s, TraceVisFlushReason r) +{ + LogTraceVisState(cx, s, (TraceVisExitReason) r); +} + +static inline void +EnterTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r) +{ + LogTraceVisState(cx, s, r); +} + +static inline void +ExitTraceVisState(JSContext *cx, TraceVisExitReason r) +{ + LogTraceVisState(cx, S_EXITLAST, r); +} + +struct TraceVisStateObj { + TraceVisExitReason r; + JSContext *mCx; + + inline TraceVisStateObj(JSContext *cx, TraceVisState s) : r(R_NONE) + { + EnterTraceVisState(cx, s, R_NONE); + mCx = cx; + } + inline ~TraceVisStateObj() + { + ExitTraceVisState(mCx, r); + } +}; + +#endif /* MOZ_TRACEVIS */ + +} /* namespace js */ + +#else /* !JS_TRACER */ + +#define TRACE_0(x) ((void)0) +#define TRACE_1(x,a) ((void)0) +#define TRACE_2(x,a,b) ((void)0) + +#endif /* !JS_TRACER */ + +namespace js { + +/* + * While recording, the slots of the global object may change payload or type. + * This is fine as long as the recorder expects this change (and therefore has + * generated the corresponding LIR, snapshots, etc). The recorder indicates + * that it expects a write to a global slot by setting pendingGlobalSlotsToSet + * in the recorder, before the write is made by the interpreter, and clearing + * pendingGlobalSlotsToSet before recording the next op. Any global slot write + * that has not been whitelisted in this manner is therefore unexpected and, if + * the global slot is actually being tracked, recording must be aborted. + */ +static JS_INLINE void +AbortRecordingIfUnexpectedGlobalWrite(JSContext *cx, JSObject *obj, unsigned slot) +{ +#ifdef JS_TRACER + if (TraceRecorder *tr = TRACE_RECORDER(cx)) { + if (obj == tr->getGlobal() && !tr->globalSetExpected(slot)) + AbortRecording(cx, "Global slot written outside tracer supervision"); + } +#endif +} + +} /* namespace js */ + +#endif /* jstracer_h___ */ diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp new file mode 100644 index 0000000..8975fb1 --- /dev/null +++ b/js/src/jstypedarray.cpp @@ -0,0 +1,1754 @@ +/* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */ +/* vim: set ts=40 sw=4 et tw=99: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla WebGL impl + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Vladimir Vukicevic + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include + +#include "jstypes.h" +#include "jsstdint.h" +#include "jsutil.h" +#include "jshash.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsversion.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsstaticcheck.h" +#include "jsbit.h" +#include "jsvector.h" +#include "jstypedarray.h" + +#include "jsobjinlines.h" + +using namespace js; +using namespace js::gc; + +static bool +ValueIsLength(JSContext *cx, const Value &v, jsuint *len) +{ + if (v.isInt32()) { + int32_t i = v.toInt32(); + if (i < 0) + return false; + *len = i; + return true; + } + + if (v.isDouble()) { + jsdouble d = v.toDouble(); + if (JSDOUBLE_IS_NaN(d)) + return false; + + jsuint length = jsuint(d); + if (d != jsdouble(length)) + return false; + + *len = length; + return true; + } + + return false; +} + +/* + * ArrayBuffer + * + * This class holds the underlying raw buffer that the TypedArray classes + * access. It can be created explicitly and passed to a TypedArray, or + * can be created implicitly by constructing a TypedArray with a size. + */ +ArrayBuffer * +ArrayBuffer::fromJSObject(JSObject *obj) +{ + while (!js_IsArrayBuffer(obj)) + obj = obj->getProto(); + return reinterpret_cast(obj->getPrivate()); +} + +JSBool +ArrayBuffer::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + ArrayBuffer *abuf = ArrayBuffer::fromJSObject(obj); + if (abuf) + vp->setInt32(jsint(abuf->byteLength)); + return true; +} + +void +ArrayBuffer::class_finalize(JSContext *cx, JSObject *obj) +{ + ArrayBuffer *abuf = ArrayBuffer::fromJSObject(obj); + if (abuf) { + abuf->freeStorage(cx); + cx->destroy(abuf); + } +} + +/* + * new ArrayBuffer(byteLength) + */ +JSBool +ArrayBuffer::class_constructor(JSContext *cx, uintN argc, Value *vp) +{ + int32 nbytes = 0; + if (argc > 0 && !ValueToECMAInt32(cx, vp[2], &nbytes)) + return false; + + JSObject *bufobj = create(cx, nbytes); + if (!bufobj) + return false; + vp->setObject(*bufobj); + return true; +} + +JSObject * +ArrayBuffer::create(JSContext *cx, int32 nbytes) +{ + JSObject *obj = NewBuiltinClassInstance(cx, &ArrayBuffer::jsclass); + if (!obj) + return NULL; + + if (nbytes < 0) { + /* + * We're just not going to support arrays that are bigger than what will fit + * as an integer value; if someone actually ever complains (validly), then we + * can fix. + */ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH); + return NULL; + } + + ArrayBuffer *abuf = cx->create(); + if (!abuf) + return NULL; + + if (!abuf->allocateStorage(cx, nbytes)) { + cx->destroy(abuf); + return NULL; + } + + obj->setPrivate(abuf); + return obj; +} + +bool +ArrayBuffer::allocateStorage(JSContext *cx, uint32 nbytes) +{ + JS_ASSERT(data == 0); + + if (nbytes) { + data = cx->calloc(nbytes); + if (!data) + return false; + } + + byteLength = nbytes; + return true; +} + +void +ArrayBuffer::freeStorage(JSContext *cx) +{ + if (data) { + cx->free(data); +#ifdef DEBUG + // the destructor asserts that data is 0 in debug builds + data = NULL; +#endif + } +} + +ArrayBuffer::~ArrayBuffer() +{ + JS_ASSERT(data == NULL); +} + +/* + * TypedArray + * + * The non-templated base class for the specific typed implementations. + * This class holds all the member variables that are used by + * the subclasses. + */ + +TypedArray * +TypedArray::fromJSObject(JSObject *obj) +{ + while (!js_IsTypedArray(obj)) + obj = obj->getProto(); + return reinterpret_cast(obj->getPrivate()); +} + +inline bool +TypedArray::isArrayIndex(JSContext *cx, jsid id, jsuint *ip) +{ + jsuint index; + if (js_IdIsIndex(id, &index) && index < length) { + if (ip) + *ip = index; + return true; + } + + return false; +} + +typedef Value (* TypedArrayPropertyGetter)(TypedArray *tarray); + +template +class TypedArrayGetter { + public: + static inline bool get(JSContext *cx, JSObject *obj, jsid id, Value *vp) { + do { + if (js_IsTypedArray(obj)) { + TypedArray *tarray = TypedArray::fromJSObject(obj); + if (tarray) + *vp = Get(tarray); + return true; + } + } while ((obj = obj->getProto()) != NULL); + return true; + } +}; + +inline Value +getBuffer(TypedArray *tarray) +{ + return ObjectValue(*tarray->bufferJS); +} + +JSBool +TypedArray::prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + return TypedArrayGetter::get(cx, obj, id, vp); +} + +inline Value +getByteOffset(TypedArray *tarray) +{ + return Int32Value(tarray->byteOffset); +} + +JSBool +TypedArray::prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + return TypedArrayGetter::get(cx, obj, id, vp); +} + +inline Value +getByteLength(TypedArray *tarray) +{ + return Int32Value(tarray->byteLength); +} + +JSBool +TypedArray::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + return TypedArrayGetter::get(cx, obj, id, vp); +} + +inline Value +getLength(TypedArray *tarray) +{ + return Int32Value(tarray->length); +} + +JSBool +TypedArray::prop_getLength(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + return TypedArrayGetter::get(cx, obj, id, vp); +} + +JSBool +TypedArray::obj_lookupProperty(JSContext *cx, JSObject *obj, jsid id, + JSObject **objp, JSProperty **propp) +{ + TypedArray *tarray = fromJSObject(obj); + JS_ASSERT(tarray); + + if (tarray->isArrayIndex(cx, id)) { + *propp = (JSProperty *) 1; /* non-null to indicate found */ + *objp = obj; + return true; + } + + JSObject *proto = obj->getProto(); + if (!proto) { + *objp = NULL; + *propp = NULL; + return true; + } + + return proto->lookupProperty(cx, id, objp, propp); +} + +void +TypedArray::obj_trace(JSTracer *trc, JSObject *obj) +{ + TypedArray *tarray = fromJSObject(obj); + JS_ASSERT(tarray); + MarkObject(trc, *tarray->bufferJS, "typedarray.buffer"); +} + +JSBool +TypedArray::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +{ + *attrsp = (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) + ? JSPROP_PERMANENT | JSPROP_READONLY + : JSPROP_PERMANENT | JSPROP_ENUMERATE; + return true; +} + +JSBool +TypedArray::obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_SET_ARRAY_ATTRS); + return false; +} + +/* Helper clamped uint8 type */ + +int32 JS_FASTCALL +js_TypedArray_uint8_clamp_double(const double x) +{ + // Not < so that NaN coerces to 0 + if (!(x >= 0)) + return 0; + + if (x > 255) + return 255; + + jsdouble toTruncate = x + 0.5; + JSUint8 y = JSUint8(toTruncate); + + /* + * now val is rounded to nearest, ties rounded up. We want + * rounded to nearest ties to even, so check whether we had a + * tie. + */ + if (y == toTruncate) { + /* + * It was a tie (since adding 0.5 gave us the exact integer + * we want). Since we rounded up, we either already have an + * even number or we have an odd number but the number we + * want is one less. So just unconditionally masking out the + * ones bit should do the trick to get us the value we + * want. + */ + return (y & ~1); + } + + return y; +} + +JS_DEFINE_CALLINFO_1(extern, INT32, js_TypedArray_uint8_clamp_double, DOUBLE, + 1, nanojit::ACCSET_NONE) + + +struct uint8_clamped { + uint8 val; + + uint8_clamped() { } + uint8_clamped(const uint8_clamped& other) : val(other.val) { } + + // invoke our assignment helpers for constructor conversion + uint8_clamped(uint8 x) { *this = x; } + uint8_clamped(uint16 x) { *this = x; } + uint8_clamped(uint32 x) { *this = x; } + uint8_clamped(int8 x) { *this = x; } + uint8_clamped(int16 x) { *this = x; } + uint8_clamped(int32 x) { *this = x; } + uint8_clamped(jsdouble x) { *this = x; } + + inline uint8_clamped& operator= (const uint8_clamped& x) { + val = x.val; + return *this; + } + + inline uint8_clamped& operator= (uint8 x) { + val = x; + return *this; + } + + inline uint8_clamped& operator= (uint16 x) { + val = (x > 255) ? 255 : uint8(x); + return *this; + } + + inline uint8_clamped& operator= (uint32 x) { + val = (x > 255) ? 255 : uint8(x); + return *this; + } + + inline uint8_clamped& operator= (int8 x) { + val = (x >= 0) ? uint8(x) : 0; + return *this; + } + + inline uint8_clamped& operator= (int16 x) { + val = (x >= 0) + ? ((x < 255) + ? uint8(x) + : 255) + : 0; + return *this; + } + + inline uint8_clamped& operator= (int32 x) { + val = (x >= 0) + ? ((x < 255) + ? uint8(x) + : 255) + : 0; + return *this; + } + + inline uint8_clamped& operator= (const jsdouble x) { + val = uint8(js_TypedArray_uint8_clamp_double(x)); + return *this; + } + + inline operator uint8() const { + return val; + } +}; + +/* Make sure the compiler isn't doing some funky stuff */ +JS_STATIC_ASSERT(sizeof(uint8_clamped) == 1); + +template static inline const int TypeIDOfType(); +template<> inline const int TypeIDOfType() { return TypedArray::TYPE_INT8; } +template<> inline const int TypeIDOfType() { return TypedArray::TYPE_UINT8; } +template<> inline const int TypeIDOfType() { return TypedArray::TYPE_INT16; } +template<> inline const int TypeIDOfType() { return TypedArray::TYPE_UINT16; } +template<> inline const int TypeIDOfType() { return TypedArray::TYPE_INT32; } +template<> inline const int TypeIDOfType() { return TypedArray::TYPE_UINT32; } +template<> inline const int TypeIDOfType() { return TypedArray::TYPE_FLOAT32; } +template<> inline const int TypeIDOfType() { return TypedArray::TYPE_FLOAT64; } +template<> inline const int TypeIDOfType() { return TypedArray::TYPE_UINT8_CLAMPED; } + +template static inline const bool TypeIsUnsigned() { return false; } +template<> inline const bool TypeIsUnsigned() { return true; } +template<> inline const bool TypeIsUnsigned() { return true; } +template<> inline const bool TypeIsUnsigned() { return true; } + +template static inline const bool TypeIsFloatingPoint() { return false; } +template<> inline const bool TypeIsFloatingPoint() { return true; } +template<> inline const bool TypeIsFloatingPoint() { return true; } + +template class TypedArrayTemplate; + +typedef TypedArrayTemplate Int8Array; +typedef TypedArrayTemplate Uint8Array; +typedef TypedArrayTemplate Int16Array; +typedef TypedArrayTemplate Uint16Array; +typedef TypedArrayTemplate Int32Array; +typedef TypedArrayTemplate Uint32Array; +typedef TypedArrayTemplate Float32Array; +typedef TypedArrayTemplate Float64Array; +typedef TypedArrayTemplate Uint8ClampedArray; + +template +class TypedArrayTemplate + : public TypedArray +{ + public: + typedef NativeType ThisType; + typedef TypedArrayTemplate ThisTypeArray; + static const int ArrayTypeID() { return TypeIDOfType(); } + static const bool ArrayTypeIsUnsigned() { return TypeIsUnsigned(); } + static const bool ArrayTypeIsFloatingPoint() { return TypeIsFloatingPoint(); } + + static JSFunctionSpec jsfuncs[]; + + static inline Class *slowClass() + { + return &TypedArray::slowClasses[ArrayTypeID()]; + } + + static inline Class *fastClass() + { + return &TypedArray::fastClasses[ArrayTypeID()]; + } + + static JSBool + obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp) + { + ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj); + JS_ASSERT(tarray); + + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + vp->setNumber(tarray->length); + return true; + } + + jsuint index; + if (tarray->isArrayIndex(cx, id, &index)) { + // this inline function is specialized for each type + tarray->copyIndexToValue(cx, index, vp); + } else { + JSObject *obj2; + JSProperty *prop; + const Shape *shape; + + JSObject *proto = obj->getProto(); + if (!proto) { + vp->setUndefined(); + return true; + } + + vp->setUndefined(); + if (js_LookupPropertyWithFlags(cx, proto, id, cx->resolveFlags, &obj2, &prop) < 0) + return false; + + if (prop) { + if (obj2->isNative()) { + shape = (Shape *) prop; + if (!js_NativeGet(cx, obj, obj2, shape, JSGET_METHOD_BARRIER, vp)) + return false; + } + } + } + + return true; + } + + static JSBool + obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) + { + ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj); + JS_ASSERT(tarray); + + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + vp->setNumber(tarray->length); + return true; + } + + jsuint index; + // We can't just chain to js_SetProperty, because we're not a normal object. + if (!tarray->isArrayIndex(cx, id, &index)) { +#if 0 + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_INDEX); + return false; +#endif + // Silent ignore is better than an exception here, because + // at some point we may want to support other properties on + // these objects. This is especially true when these arrays + // are used to implement HTML Canvas 2D's PixelArray objects, + // which used to be plain old arrays. + vp->setUndefined(); + return true; + } + + if (vp->isInt32()) { + tarray->setIndex(index, NativeType(vp->toInt32())); + return true; + } + + jsdouble d; + + if (vp->isDouble()) { + d = vp->toDouble(); + } else if (vp->isNull()) { + d = 0.0f; + } else if (vp->isPrimitive()) { + JS_ASSERT(vp->isString() || vp->isUndefined() || vp->isBoolean()); + if (vp->isString()) { + // note that ValueToNumber will always succeed with a string arg + ValueToNumber(cx, *vp, &d); + } else if (vp->isUndefined()) { + d = js_NaN; + } else { + d = (double) vp->toBoolean(); + } + } else { + // non-primitive assignments become NaN or 0 (for float/int arrays) + d = js_NaN; + } + + // If the array is an integer array, we only handle up to + // 32-bit ints from this point on. if we want to handle + // 64-bit ints, we'll need some changes. + + // Assign based on characteristics of the destination type + if (ArrayTypeIsFloatingPoint()) { + tarray->setIndex(index, NativeType(d)); + } else if (ArrayTypeIsUnsigned()) { + JS_ASSERT(sizeof(NativeType) <= 4); + uint32 n = js_DoubleToECMAUint32(d); + tarray->setIndex(index, NativeType(n)); + } else if (ArrayTypeID() == TypedArray::TYPE_UINT8_CLAMPED) { + // The uint8_clamped type has a special rounding converter + // for doubles. + tarray->setIndex(index, NativeType(d)); + } else { + JS_ASSERT(sizeof(NativeType) <= 4); + int32 n = js_DoubleToECMAInt32(d); + tarray->setIndex(index, NativeType(n)); + } + + return true; + } + + static JSBool + obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v, + PropertyOp getter, StrictPropertyOp setter, uintN attrs) + { + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) + return true; + + Value tmp = *v; + return obj_setProperty(cx, obj, id, &tmp, false); + } + + static JSBool + obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) + { + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + rval->setBoolean(false); + return true; + } + + TypedArray *tarray = TypedArray::fromJSObject(obj); + JS_ASSERT(tarray); + + if (tarray->isArrayIndex(cx, id)) { + rval->setBoolean(false); + return true; + } + + rval->setBoolean(true); + return true; + } + + static JSBool + obj_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + Value *statep, jsid *idp) + { + ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj); + JS_ASSERT(tarray); + + /* + * Iteration is "length" (if JSENUMERATE_INIT_ALL), then [0, length). + * *statep is JSVAL_TRUE if enumerating "length" and + * JSVAL_TO_INT(index) when enumerating index. + */ + switch (enum_op) { + case JSENUMERATE_INIT_ALL: + statep->setBoolean(true); + if (idp) + *idp = INT_TO_JSID(tarray->length + 1); + break; + + case JSENUMERATE_INIT: + statep->setInt32(0); + if (idp) + *idp = INT_TO_JSID(tarray->length); + break; + + case JSENUMERATE_NEXT: + if (statep->isTrue()) { + *idp = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); + statep->setInt32(0); + } else { + uint32 index = statep->toInt32(); + if (index < uint32(tarray->length)) { + *idp = INT_TO_JSID(index); + statep->setInt32(index + 1); + } else { + JS_ASSERT(index == tarray->length); + statep->setNull(); + } + } + break; + + case JSENUMERATE_DESTROY: + statep->setNull(); + break; + } + + return true; + } + + static JSType + obj_typeOf(JSContext *cx, JSObject *obj) + { + return JSTYPE_OBJECT; + } + + static JSObject * + createTypedArray(JSContext *cx, JSObject *bufobj, uint32 byteOffset, uint32 len) + { + JSObject *obj = NewBuiltinClassInstance(cx, slowClass()); + if (!obj) + return NULL; + + ThisTypeArray *tarray = cx->create(bufobj, byteOffset, len); + if (!tarray) + return NULL; + + JS_ASSERT(obj->getClass() == slowClass()); + obj->setSharedNonNativeMap(); + obj->clasp = fastClass(); + obj->setPrivate(tarray); + + // FIXME Bug 599008: make it ok to call preventExtensions here. + obj->flags |= JSObject::NOT_EXTENSIBLE; + + return obj; + } + + /* + * new [Type]Array(length) + * new [Type]Array(otherTypedArray) + * new [Type]Array(JSArray) + * new [Type]Array(ArrayBuffer, [optional] byteOffset, [optional] length) + */ + static JSBool + class_constructor(JSContext *cx, uintN argc, Value *vp) + { + /* N.B. this is a constructor for slowClass, not fastClass! */ + JSObject *obj = create(cx, argc, JS_ARGV(cx, vp)); + if (!obj) + return false; + vp->setObject(*obj); + return true; + } + + static JSObject * + create(JSContext *cx, uintN argc, Value *argv) + { + /* N.B. there may not be an argv[-2]/argv[-1]. */ + + /* () or (number) */ + jsuint len = 0; + if (argc == 0 || ValueIsLength(cx, argv[0], &len)) { + JSObject *bufobj = createBufferWithSizeAndCount(cx, len); + if (!bufobj) + return NULL; + + return createTypedArray(cx, bufobj, 0, len); + } + + /* (not an object) */ + if (!argv[0].isObject()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return NULL; + } + + JSObject *dataObj = &argv[0].toObject(); + + /* (typedArray) */ + if (js_IsTypedArray(dataObj)) { + TypedArray *otherTypedArray = TypedArray::fromJSObject(dataObj); + JS_ASSERT(otherTypedArray); + + uint32 len = otherTypedArray->length; + JSObject *bufobj = createBufferWithSizeAndCount(cx, len); + if (!bufobj) + return NULL; + + JSObject *obj = createTypedArray(cx, bufobj, 0, len); + if (!obj || !copyFrom(cx, obj, otherTypedArray, 0)) + return NULL; + return obj; + } + + /* (obj, byteOffset, length). */ + int32_t byteOffset = -1; + int32_t length = -1; + + if (argc > 1) { + if (!ValueToInt32(cx, argv[1], &byteOffset)) + return NULL; + if (byteOffset < 0) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "1"); + return NULL; + } + + if (argc > 2) { + if (!ValueToInt32(cx, argv[2], &length)) + return NULL; + if (length < 0) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "2"); + return NULL; + } + } + } + + /* (obj, byteOffset, length) */ + return createTypedArrayWithOffsetLength(cx, dataObj, byteOffset, length); + } + + static void + class_finalize(JSContext *cx, JSObject *obj) + { + ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj); + if (tarray) + cx->destroy(tarray); + } + + /* subarray(start[, end]) */ + static JSBool + fun_subarray(JSContext *cx, uintN argc, Value *vp) + { + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!InstanceOf(cx, obj, ThisTypeArray::fastClass(), vp + 2)) + return false; + + if (obj->getClass() != fastClass()) { + // someone tried to apply this subarray() to the wrong class + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_METHOD, + fastClass()->name, "subarray", obj->getClass()->name); + return false; + } + + ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj); + if (!tarray) + return true; + + // these are the default values + int32_t begin = 0, end = tarray->length; + int32_t length = int32(tarray->length); + + if (argc > 0) { + Value *argv = JS_ARGV(cx, vp); + if (!ValueToInt32(cx, argv[0], &begin)) + return false; + if (begin < 0) { + begin += length; + if (begin < 0) + begin = 0; + } else if (begin > length) { + begin = length; + } + + if (argc > 1) { + if (!ValueToInt32(cx, argv[1], &end)) + return false; + if (end < 0) { + end += length; + if (end < 0) + end = 0; + } else if (end > length) { + end = length; + } + } + } + + if (begin > end) + begin = end; + + JSObject *nobj = createSubarray(cx, tarray, begin, end); + if (!nobj) + return false; + vp->setObject(*nobj); + return true; + } + + /* set(array[, offset]) */ + static JSBool + fun_set(JSContext *cx, uintN argc, Value *vp) + { + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!InstanceOf(cx, obj, ThisTypeArray::fastClass(), vp + 2)) + return false; + + if (obj->getClass() != fastClass()) { + // someone tried to apply this set() to the wrong class + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_METHOD, + fastClass()->name, "set", obj->getClass()->name); + return false; + } + + ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj); + if (!tarray) + return true; + + // these are the default values + int32_t off = 0; + + Value *argv = JS_ARGV(cx, vp); + if (argc > 1) { + if (!ValueToInt32(cx, argv[1], &off)) + return false; + + if (off < 0 || uint32_t(off) > tarray->length) { + // the given offset is bogus + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return false; + } + } + + uint32 offset(off); + + // first arg must be either a typed array or a JS array + if (argc == 0 || !argv[0].isObject()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return false; + } + + JSObject *arg0 = argv[0].toObjectOrNull(); + if (js_IsTypedArray(arg0)) { + TypedArray *src = TypedArray::fromJSObject(arg0); + if (!src || + src->length > tarray->length - offset) + { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return false; + } + + if (!copyFrom(cx, obj, src, offset)) + return false; + } else { + jsuint len; + if (!js_GetLengthProperty(cx, arg0, &len)) + return false; + + // avoid overflow; we know that offset <= length + if (len > tarray->length - offset) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return false; + } + + if (!copyFrom(cx, obj, arg0, len, offset)) + return false; + } + + vp->setUndefined(); + return true; + } + + static ThisTypeArray * + fromJSObject(JSObject *obj) + { + JS_ASSERT(obj->getClass() == fastClass()); + return reinterpret_cast(obj->getPrivate()); + } + + public: + TypedArrayTemplate(JSObject *bufobj, uint32 byteOffset, uint32 len) + { + JS_ASSERT(bufobj->getClass() == &ArrayBuffer::jsclass); + + type = ArrayTypeID(); + bufferJS = bufobj; + buffer = ArrayBuffer::fromJSObject(bufobj); + + this->byteOffset = byteOffset; + + JS_ASSERT(byteOffset <= buffer->byteLength); + this->data = buffer->offsetData(byteOffset); + JS_ASSERT(buffer->data <= this->data); + JS_ASSERT(this->data <= buffer->offsetData(buffer->byteLength)); + + this->byteLength = len * sizeof(NativeType); + JS_ASSERT(buffer->byteLength - byteOffset >= this->byteLength); + + this->length = len; + } + + static JSObject * + createTypedArrayWithOffsetLength(JSContext *cx, JSObject *other, + int32 byteOffsetInt, int32 lengthInt) + { + JS_ASSERT(!js_IsTypedArray(other)); + + /* Handle creation from an ArrayBuffer not ArrayBuffer.prototype. */ + ArrayBuffer *abuf; + if (other->getClass() == &ArrayBuffer::jsclass && + ((abuf = ArrayBuffer::fromJSObject(other)) != NULL)) { + uint32 boffset = (byteOffsetInt < 0) ? 0 : uint32(byteOffsetInt); + + if (boffset > abuf->byteLength || boffset % sizeof(NativeType) != 0) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return NULL; // invalid byteOffset + } + + uint32 len; + if (lengthInt < 0) { + len = (abuf->byteLength - boffset) / sizeof(NativeType); + if (len * sizeof(NativeType) != (abuf->byteLength - boffset)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return NULL; // given byte array doesn't map exactly to sizeof(NativeType)*N + } + } else { + len = (uint32) lengthInt; + } + + // Go slowly and check for overflow. + uint32 arrayByteLength = len*sizeof(NativeType); + if (uint32(len) >= INT32_MAX / sizeof(NativeType) || + uint32(boffset) >= INT32_MAX - arrayByteLength) + { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return NULL; // overflow occurred along the way when calculating boffset+len*sizeof(NativeType) + } + + if (arrayByteLength + boffset > abuf->byteLength) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_TYPED_ARRAY_BAD_ARGS); + return NULL; // boffset+len is too big for the arraybuffer + } + + return createTypedArray(cx, other, boffset, len); + } + + /* + * Otherwise create a new typed array and copy len properties from the + * object. + */ + jsuint len; + if (!js_GetLengthProperty(cx, other, &len)) + return NULL; + + JSObject *bufobj = createBufferWithSizeAndCount(cx, len); + if (!bufobj) + return NULL; + + JSObject *obj = createTypedArray(cx, bufobj, 0, len); + if (!obj || !copyFrom(cx, obj, other, len)) + return NULL; + return obj; + } + + const NativeType + getIndex(uint32 index) const + { + return *(static_cast(data) + index); + } + + void + setIndex(uint32 index, NativeType val) + { + *(static_cast(data) + index) = val; + } + + inline void copyIndexToValue(JSContext *cx, uint32 index, Value *vp); + + static JSObject * + createSubarray(JSContext *cx, ThisTypeArray *tarray, uint32 begin, uint32 end) + { + JS_ASSERT(tarray); + + JS_ASSERT(0 <= begin); + JS_ASSERT(begin <= tarray->length); + JS_ASSERT(0 <= end); + JS_ASSERT(end <= tarray->length); + + JSObject *bufobj = tarray->bufferJS; + JS_ASSERT(bufobj); + + JS_ASSERT(begin <= end); + uint32 length = end - begin; + + JS_ASSERT(begin < UINT32_MAX / sizeof(NativeType)); + uint32 byteOffset = begin * sizeof(NativeType); + + return createTypedArray(cx, bufobj, byteOffset, length); + } + + protected: + static NativeType + nativeFromValue(JSContext *cx, const Value &v) + { + if (v.isInt32()) + return NativeType(v.toInt32()); + + if (v.isDouble()) { + double d = v.toDouble(); + if (!ArrayTypeIsFloatingPoint() && JS_UNLIKELY(JSDOUBLE_IS_NaN(d))) + return NativeType(int32(0)); + if (TypeIsFloatingPoint()) + return NativeType(d); + if (TypeIsUnsigned()) + return NativeType(js_DoubleToECMAUint32(d)); + return NativeType(js_DoubleToECMAInt32(d)); + } + + if (v.isPrimitive() && !v.isMagic()) { + jsdouble dval; + ValueToNumber(cx, v, &dval); + return NativeType(dval); + } + + if (ArrayTypeIsFloatingPoint()) + return NativeType(js_NaN); + + return NativeType(int32(0)); + } + + static bool + copyFrom(JSContext *cx, JSObject *thisTypedArrayObj, + JSObject *ar, jsuint len, jsuint offset = 0) + { + ThisTypeArray *thisTypedArray = fromJSObject(thisTypedArrayObj); + JS_ASSERT(thisTypedArray); + + JS_ASSERT(offset <= thisTypedArray->length); + JS_ASSERT(len <= thisTypedArray->length - offset); + NativeType *dest = static_cast(thisTypedArray->data) + offset; + + if (ar->isDenseArray() && ar->getDenseArrayCapacity() >= len) { + JS_ASSERT(ar->getArrayLength() == len); + + Value *src = ar->getDenseArrayElements(); + + for (uintN i = 0; i < len; ++i) + *dest++ = nativeFromValue(cx, *src++); + } else { + // slow path + Value v; + + for (uintN i = 0; i < len; ++i) { + if (!ar->getProperty(cx, INT_TO_JSID(i), &v)) + return false; + *dest++ = nativeFromValue(cx, v); + } + } + + return true; + } + + static bool + copyFrom(JSContext *cx, JSObject *thisTypedArrayObj, TypedArray *tarray, jsuint offset) + { + ThisTypeArray *thisTypedArray = fromJSObject(thisTypedArrayObj); + JS_ASSERT(thisTypedArray); + + JS_ASSERT(offset <= thisTypedArray->length); + JS_ASSERT(tarray->length <= thisTypedArray->length - offset); + if (tarray->buffer == thisTypedArray->buffer) + return thisTypedArray->copyFromWithOverlap(cx, tarray, offset); + + NativeType *dest = static_cast(thisTypedArray->data) + offset; + + if (tarray->type == thisTypedArray->type) { + memcpy(dest, tarray->data, tarray->byteLength); + return true; + } + + uintN srclen = tarray->length; + switch (tarray->type) { + case TypedArray::TYPE_INT8: { + int8 *src = static_cast(tarray->data); + for (uintN i = 0; i < srclen; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_UINT8: + case TypedArray::TYPE_UINT8_CLAMPED: { + uint8 *src = static_cast(tarray->data); + for (uintN i = 0; i < srclen; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_INT16: { + int16 *src = static_cast(tarray->data); + for (uintN i = 0; i < srclen; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_UINT16: { + uint16 *src = static_cast(tarray->data); + for (uintN i = 0; i < srclen; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_INT32: { + int32 *src = static_cast(tarray->data); + for (uintN i = 0; i < srclen; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_UINT32: { + uint32 *src = static_cast(tarray->data); + for (uintN i = 0; i < srclen; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_FLOAT32: { + float *src = static_cast(tarray->data); + for (uintN i = 0; i < srclen; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_FLOAT64: { + double *src = static_cast(tarray->data); + for (uintN i = 0; i < srclen; ++i) + *dest++ = NativeType(*src++); + break; + } + default: + JS_NOT_REACHED("copyFrom with a TypedArray of unknown type"); + break; + } + + return true; + } + + bool + copyFromWithOverlap(JSContext *cx, TypedArray *tarray, jsuint offset) + { + JS_ASSERT(offset <= length); + + NativeType *dest = static_cast(data) + offset; + + if (tarray->type == type) { + memmove(dest, tarray->data, tarray->byteLength); + return true; + } + + // We have to make a copy of the source array here, since + // there's overlap, and we have to convert types. + void *srcbuf = cx->malloc(tarray->byteLength); + if (!srcbuf) + return false; + memcpy(srcbuf, tarray->data, tarray->byteLength); + + switch (tarray->type) { + case TypedArray::TYPE_INT8: { + int8 *src = (int8*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_UINT8: + case TypedArray::TYPE_UINT8_CLAMPED: { + uint8 *src = (uint8*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_INT16: { + int16 *src = (int16*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_UINT16: { + uint16 *src = (uint16*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_INT32: { + int32 *src = (int32*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_UINT32: { + uint32 *src = (uint32*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_FLOAT32: { + float *src = (float*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + case TypedArray::TYPE_FLOAT64: { + double *src = (double*) srcbuf; + for (uintN i = 0; i < tarray->length; ++i) + *dest++ = NativeType(*src++); + break; + } + default: + JS_NOT_REACHED("copyFromWithOverlap with a TypedArray of unknown type"); + break; + } + + js_free(srcbuf); + return true; + } + + static JSObject * + createBufferWithSizeAndCount(JSContext *cx, uint32 count) + { + size_t size = sizeof(NativeType); + if (size != 0 && count >= INT32_MAX / size) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_NEED_DIET, "size and count"); + return false; + } + + int32 bytelen = size * count; + return ArrayBuffer::create(cx, bytelen); + } +}; + +// this default implementation is only valid for integer types +// less than 32-bits in size. +template +void +TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, Value *vp) +{ + JS_STATIC_ASSERT(sizeof(NativeType) < 4); + + vp->setInt32(getIndex(index)); +} + +// and we need to specialize for 32-bit integers and floats +template<> +void +TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, Value *vp) +{ + int32 val = getIndex(index); + vp->setInt32(val); +} + +template<> +void +TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, Value *vp) +{ + uint32 val = getIndex(index); + vp->setNumber(val); +} + +template<> +void +TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, Value *vp) +{ + float val = getIndex(index); + double dval = val; + + /* + * Doubles in typed arrays could be typed-punned arrays of integers. This + * could allow user code to break the engine-wide invariant that only + * canonical nans are stored into jsvals, which means user code could + * confuse the engine into interpreting a double-typed jsval as an + * object-typed jsval. + * + * This could be removed for platforms/compilers known to convert a 32-bit + * non-canonical nan to a 64-bit canonical nan. + */ + if (JS_UNLIKELY(JSDOUBLE_IS_NaN(dval))) + dval = js_NaN; + + vp->setDouble(dval); +} + +template<> +void +TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, Value *vp) +{ + double val = getIndex(index); + + /* + * Doubles in typed arrays could be typed-punned arrays of integers. This + * could allow user code to break the engine-wide invariant that only + * canonical nans are stored into jsvals, which means user code could + * confuse the engine into interpreting a double-typed jsval as an + * object-typed jsval. + */ + if (JS_UNLIKELY(JSDOUBLE_IS_NaN(val))) + val = js_NaN; + + vp->setDouble(val); +} + +/*** + *** JS impl + ***/ + +/* + * ArrayBuffer (base) + */ + +Class ArrayBuffer::jsclass = { + "ArrayBuffer", + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub, + ArrayBuffer::class_finalize, +}; + +JSPropertySpec ArrayBuffer::jsprops[] = { + { "byteLength", + -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY, + Jsvalify(ArrayBuffer::prop_getByteLength), JS_StrictPropertyStub }, + {0,0,0,0,0} +}; + +/* + * shared TypedArray + */ + +JSPropertySpec TypedArray::jsprops[] = { + { js_length_str, + -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY, + Jsvalify(TypedArray::prop_getLength), JS_StrictPropertyStub }, + { "byteLength", + -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY, + Jsvalify(TypedArray::prop_getByteLength), JS_StrictPropertyStub }, + { "byteOffset", + -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY, + Jsvalify(TypedArray::prop_getByteOffset), JS_StrictPropertyStub }, + { "buffer", + -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY, + Jsvalify(TypedArray::prop_getBuffer), JS_StrictPropertyStub }, + {0,0,0,0,0} +}; + +/* + * TypedArray boilerplate + */ + +#define IMPL_TYPED_ARRAY_STATICS(_typedArray) \ +template<> JSFunctionSpec _typedArray::jsfuncs[] = { \ + JS_FN("subarray", _typedArray::fun_subarray, 2, 0), \ + JS_FN("set", _typedArray::fun_set, 2, 0), \ + JS_FS_END \ +} + +#define IMPL_TYPED_ARRAY_SLOW_CLASS(_typedArray) \ +{ \ + #_typedArray, \ + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray), \ + PropertyStub, /* addProperty */ \ + PropertyStub, /* delProperty */ \ + PropertyStub, /* getProperty */ \ + StrictPropertyStub, /* setProperty */ \ + EnumerateStub, \ + ResolveStub, \ + ConvertStub, \ + FinalizeStub \ +} + +#define IMPL_TYPED_ARRAY_FAST_CLASS(_typedArray) \ +{ \ + #_typedArray, \ + Class::NON_NATIVE | JSCLASS_HAS_PRIVATE, \ + PropertyStub, /* addProperty */ \ + PropertyStub, /* delProperty */ \ + PropertyStub, /* getProperty */ \ + StrictPropertyStub, /* setProperty */ \ + EnumerateStub, \ + ResolveStub, \ + ConvertStub, \ + _typedArray::class_finalize, \ + NULL, /* reserved0 */ \ + NULL, /* checkAccess */ \ + NULL, /* call */ \ + NULL, /* construct */ \ + NULL, /* xdrObject */ \ + NULL, /* hasInstance */ \ + NULL, /* mark */ \ + JS_NULL_CLASS_EXT, \ + { \ + _typedArray::obj_lookupProperty, \ + _typedArray::obj_defineProperty, \ + _typedArray::obj_getProperty, \ + _typedArray::obj_setProperty, \ + _typedArray::obj_getAttributes, \ + _typedArray::obj_setAttributes, \ + _typedArray::obj_deleteProperty, \ + _typedArray::obj_enumerate, \ + _typedArray::obj_typeOf, \ + _typedArray::obj_trace, \ + NULL, /* thisObject */ \ + NULL, /* clear */ \ + } \ +} + +#define INIT_TYPED_ARRAY_CLASS(_typedArray,_type) \ +do { \ + proto = js_InitClass(cx, obj, NULL, \ + &TypedArray::slowClasses[TypedArray::_type], \ + _typedArray::class_constructor, 3, \ + _typedArray::jsprops, \ + _typedArray::jsfuncs, \ + NULL, NULL); \ + if (!proto) \ + return NULL; \ + JSObject *ctor = JS_GetConstructor(cx, proto); \ + if (!ctor || \ + !JS_DefineProperty(cx, ctor, "BYTES_PER_ELEMENT", \ + INT_TO_JSVAL(sizeof(_typedArray::ThisType)), \ + JS_PropertyStub, JS_StrictPropertyStub, \ + JSPROP_PERMANENT | JSPROP_READONLY) || \ + !JS_DefineProperty(cx, proto, "BYTES_PER_ELEMENT", \ + INT_TO_JSVAL(sizeof(_typedArray::ThisType)), \ + JS_PropertyStub, JS_StrictPropertyStub, \ + JSPROP_PERMANENT | JSPROP_READONLY)) \ + { \ + return NULL; \ + } \ + proto->setPrivate(0); \ +} while (0) + +IMPL_TYPED_ARRAY_STATICS(Int8Array); +IMPL_TYPED_ARRAY_STATICS(Uint8Array); +IMPL_TYPED_ARRAY_STATICS(Int16Array); +IMPL_TYPED_ARRAY_STATICS(Uint16Array); +IMPL_TYPED_ARRAY_STATICS(Int32Array); +IMPL_TYPED_ARRAY_STATICS(Uint32Array); +IMPL_TYPED_ARRAY_STATICS(Float32Array); +IMPL_TYPED_ARRAY_STATICS(Float64Array); +IMPL_TYPED_ARRAY_STATICS(Uint8ClampedArray); + +Class TypedArray::fastClasses[TYPE_MAX] = { + IMPL_TYPED_ARRAY_FAST_CLASS(Int8Array), + IMPL_TYPED_ARRAY_FAST_CLASS(Uint8Array), + IMPL_TYPED_ARRAY_FAST_CLASS(Int16Array), + IMPL_TYPED_ARRAY_FAST_CLASS(Uint16Array), + IMPL_TYPED_ARRAY_FAST_CLASS(Int32Array), + IMPL_TYPED_ARRAY_FAST_CLASS(Uint32Array), + IMPL_TYPED_ARRAY_FAST_CLASS(Float32Array), + IMPL_TYPED_ARRAY_FAST_CLASS(Float64Array), + IMPL_TYPED_ARRAY_FAST_CLASS(Uint8ClampedArray) +}; + +Class TypedArray::slowClasses[TYPE_MAX] = { + IMPL_TYPED_ARRAY_SLOW_CLASS(Int8Array), + IMPL_TYPED_ARRAY_SLOW_CLASS(Uint8Array), + IMPL_TYPED_ARRAY_SLOW_CLASS(Int16Array), + IMPL_TYPED_ARRAY_SLOW_CLASS(Uint16Array), + IMPL_TYPED_ARRAY_SLOW_CLASS(Int32Array), + IMPL_TYPED_ARRAY_SLOW_CLASS(Uint32Array), + IMPL_TYPED_ARRAY_SLOW_CLASS(Float32Array), + IMPL_TYPED_ARRAY_SLOW_CLASS(Float64Array), + IMPL_TYPED_ARRAY_SLOW_CLASS(Uint8ClampedArray) +}; + +JS_FRIEND_API(JSObject *) +js_InitTypedArrayClasses(JSContext *cx, JSObject *obj) +{ + /* Idempotency required: we initialize several things, possibly lazily. */ + JSObject *stop; + if (!js_GetClassObject(cx, obj, JSProto_ArrayBuffer, &stop)) + return NULL; + if (stop) + return stop; + + JSObject *proto; + + INIT_TYPED_ARRAY_CLASS(Int8Array,TYPE_INT8); + INIT_TYPED_ARRAY_CLASS(Uint8Array,TYPE_UINT8); + INIT_TYPED_ARRAY_CLASS(Int16Array,TYPE_INT16); + INIT_TYPED_ARRAY_CLASS(Uint16Array,TYPE_UINT16); + INIT_TYPED_ARRAY_CLASS(Int32Array,TYPE_INT32); + INIT_TYPED_ARRAY_CLASS(Uint32Array,TYPE_UINT32); + INIT_TYPED_ARRAY_CLASS(Float32Array,TYPE_FLOAT32); + INIT_TYPED_ARRAY_CLASS(Float64Array,TYPE_FLOAT64); + INIT_TYPED_ARRAY_CLASS(Uint8ClampedArray,TYPE_UINT8_CLAMPED); + + proto = js_InitClass(cx, obj, NULL, &ArrayBuffer::jsclass, + ArrayBuffer::class_constructor, 1, + ArrayBuffer::jsprops, NULL, NULL, NULL); + if (!proto) + return NULL; + + proto->setPrivate(NULL); + return proto; +} + +JS_FRIEND_API(JSBool) +js_IsArrayBuffer(JSObject *obj) +{ + JS_ASSERT(obj); + return obj->getClass() == &ArrayBuffer::jsclass; +} + +JS_FRIEND_API(JSBool) +js_IsTypedArray(JSObject *obj) +{ + JS_ASSERT(obj); + Class *clasp = obj->getClass(); + return clasp >= &TypedArray::fastClasses[0] && + clasp < &TypedArray::fastClasses[TypedArray::TYPE_MAX]; +} + +JS_FRIEND_API(JSObject *) +js_CreateArrayBuffer(JSContext *cx, jsuint nbytes) +{ + return ArrayBuffer::create(cx, nbytes); +} + +static inline JSObject * +TypedArrayConstruct(JSContext *cx, jsint atype, uintN argc, Value *argv) +{ + switch (atype) { + case TypedArray::TYPE_INT8: + return Int8Array::create(cx, argc, argv); + + case TypedArray::TYPE_UINT8: + return Uint8Array::create(cx, argc, argv); + + case TypedArray::TYPE_INT16: + return Int16Array::create(cx, argc, argv); + + case TypedArray::TYPE_UINT16: + return Uint16Array::create(cx, argc, argv); + + case TypedArray::TYPE_INT32: + return Int32Array::create(cx, argc, argv); + + case TypedArray::TYPE_UINT32: + return Uint32Array::create(cx, argc, argv); + + case TypedArray::TYPE_FLOAT32: + return Float32Array::create(cx, argc, argv); + + case TypedArray::TYPE_FLOAT64: + return Float64Array::create(cx, argc, argv); + + case TypedArray::TYPE_UINT8_CLAMPED: + return Uint8ClampedArray::create(cx, argc, argv); + + default: + JS_NOT_REACHED("shouldn't have gotten here"); + return false; + } +} + +JS_FRIEND_API(JSObject *) +js_CreateTypedArray(JSContext *cx, jsint atype, jsuint nelements) +{ + JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX); + + Value nelems = Int32Value(nelements); + return TypedArrayConstruct(cx, atype, 1, &nelems); +} + +JS_FRIEND_API(JSObject *) +js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg) +{ + JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX); + + Value arrval = ObjectValue(*arrayArg); + return TypedArrayConstruct(cx, atype, 1, &arrval); +} + +JS_FRIEND_API(JSObject *) +js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg, + jsint byteoffset, jsint length) +{ + JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX); + JS_ASSERT(bufArg && ArrayBuffer::fromJSObject(bufArg)); + JS_ASSERT_IF(byteoffset < 0, length < 0); + + Value vals[4]; + + int argc = 1; + vals[0].setObject(*bufArg); + + if (byteoffset >= 0) { + vals[argc].setInt32(byteoffset); + argc++; + } + + if (length >= 0) { + vals[argc].setInt32(length); + argc++; + } + + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); + return TypedArrayConstruct(cx, atype, argc, &vals[0]); +} + +JS_FRIEND_API(JSBool) +js_ReparentTypedArrayToScope(JSContext *cx, JSObject *obj, JSObject *scope) +{ + JS_ASSERT(obj); + + scope = JS_GetGlobalForObject(cx, scope); + if (!scope) + return JS_FALSE; + + if (!js_IsTypedArray(obj)) + return JS_FALSE; + + TypedArray *typedArray = TypedArray::fromJSObject(obj); + + JSObject *buffer = typedArray->bufferJS; + JS_ASSERT(js_IsArrayBuffer(buffer)); + + JSObject *proto; + JSProtoKey key = + JSCLASS_CACHED_PROTO_KEY(&TypedArray::slowClasses[typedArray->type]); + if (!js_GetClassPrototype(cx, scope, key, &proto)) + return JS_FALSE; + + obj->setProto(proto); + obj->setParent(scope); + + key = JSCLASS_CACHED_PROTO_KEY(&ArrayBuffer::jsclass); + if (!js_GetClassPrototype(cx, scope, key, &proto)) + return JS_FALSE; + + buffer->setProto(proto); + buffer->setParent(scope); + + return JS_TRUE; +} diff --git a/js/src/jstypedarray.h b/js/src/jstypedarray.h new file mode 100644 index 0000000..953914d --- /dev/null +++ b/js/src/jstypedarray.h @@ -0,0 +1,237 @@ +/* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */ +/* vim: set ts=40 sw=4 et tw=99: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla WebGL impl + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Vladimir Vukicevic + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jstypedarray_h +#define jstypedarray_h + +#include "jsapi.h" +#include "jsvalue.h" + +typedef struct JSProperty JSProperty; + +namespace js { + +/* + * ArrayBuffer + * + * This class holds the underlying raw buffer that the TypedArray + * subclasses access. It can be created explicitly and passed to a + * TypedArray subclass, or can be created implicitly by constructing a + * TypedArray with a size. + */ +struct JS_FRIEND_API(ArrayBuffer) { + static Class jsclass; + static JSPropertySpec jsprops[]; + + static JSBool prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp); + static void class_finalize(JSContext *cx, JSObject *obj); + + static JSBool class_constructor(JSContext *cx, uintN argc, Value *vp); + + static JSObject *create(JSContext *cx, int32 nbytes); + + static ArrayBuffer *fromJSObject(JSObject *obj); + + ArrayBuffer() + : data(0), byteLength() + { + } + + ~ArrayBuffer(); + + bool allocateStorage(JSContext *cx, uint32 bytes); + void freeStorage(JSContext *cx); + + void *offsetData(uint32 offs) { + return (void*) (((intptr_t)data) + offs); + } + + void *data; + uint32 byteLength; +}; + +/* + * TypedArray + * + * The non-templated base class for the specific typed implementations. + * This class holds all the member variables that are used by + * the subclasses. + */ + +struct JS_FRIEND_API(TypedArray) { + enum { + TYPE_INT8 = 0, + TYPE_UINT8, + TYPE_INT16, + TYPE_UINT16, + TYPE_INT32, + TYPE_UINT32, + TYPE_FLOAT32, + TYPE_FLOAT64, + + /* + * Special type that's a uint8, but assignments are clamped to 0 .. 255. + * Treat the raw data type as a uint8. + */ + TYPE_UINT8_CLAMPED, + + TYPE_MAX + }; + + // and MUST NOT be used to construct new objects. + static Class fastClasses[TYPE_MAX]; + + // These are the slow/original classes, used + // fo constructing new objects + static Class slowClasses[TYPE_MAX]; + + static JSPropertySpec jsprops[]; + + static TypedArray *fromJSObject(JSObject *obj); + + static JSBool prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp); + static JSBool prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp); + static JSBool prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp); + static JSBool prop_getLength(JSContext *cx, JSObject *obj, jsid id, Value *vp); + + static JSBool obj_lookupProperty(JSContext *cx, JSObject *obj, jsid id, + JSObject **objp, JSProperty **propp); + + static void obj_trace(JSTracer *trc, JSObject *obj); + + static JSBool obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); + + static JSBool obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); + + static int32 lengthOffset() { return offsetof(TypedArray, length); } + static int32 dataOffset() { return offsetof(TypedArray, data); } + static int32 typeOffset() { return offsetof(TypedArray, type); } + + public: + TypedArray() : buffer(0) { } + + bool isArrayIndex(JSContext *cx, jsid id, jsuint *ip = NULL); + bool valid() { return buffer != 0; } + + ArrayBuffer *buffer; + JSObject *bufferJS; + uint32 byteOffset; + uint32 byteLength; + uint32 length; + uint32 type; + + void *data; + + inline int slotWidth() const { + switch (type) { + case js::TypedArray::TYPE_INT8: + case js::TypedArray::TYPE_UINT8: + case js::TypedArray::TYPE_UINT8_CLAMPED: + return 1; + case js::TypedArray::TYPE_INT16: + case js::TypedArray::TYPE_UINT16: + return 2; + case js::TypedArray::TYPE_INT32: + case js::TypedArray::TYPE_UINT32: + case js::TypedArray::TYPE_FLOAT32: + return 4; + case js::TypedArray::TYPE_FLOAT64: + return 8; + default: + JS_NOT_REACHED("invalid typed array"); + return 0; + } + } +}; + +} // namespace js + +/* Friend API methods */ + +JS_FRIEND_API(JSObject *) +js_InitTypedArrayClasses(JSContext *cx, JSObject *obj); + +JS_FRIEND_API(JSBool) +js_IsTypedArray(JSObject *obj); + +JS_FRIEND_API(JSBool) +js_IsArrayBuffer(JSObject *obj); + +JS_FRIEND_API(JSObject *) +js_CreateArrayBuffer(JSContext *cx, jsuint nbytes); + +/* + * Create a new typed array of type atype (one of the TypedArray + * enumerant values above), with nelements elements. + */ +JS_FRIEND_API(JSObject *) +js_CreateTypedArray(JSContext *cx, jsint atype, jsuint nelements); + +/* + * Create a new typed array of type atype (one of the TypedArray + * enumerant values above), and copy in values from the given JSObject, + * which must either be a typed array or an array-like object. + */ +JS_FRIEND_API(JSObject *) +js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg); + +/* + * Create a new typed array of type atype (one of the TypedArray + * enumerant values above), using a given ArrayBuffer for storage. + * The byteoffset and length values are optional; if -1 is passed, an + * offset of 0 and enough elements to use up the remainder of the byte + * array are used as the default values. + */ +JS_FRIEND_API(JSObject *) +js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg, + jsint byteoffset, jsint length); + +/* + * Reparent a typed array to a new scope. This should only be used to reparent + * a typed array that does not share its underlying ArrayBuffer with another + * typed array to avoid having a parent mismatch with the other typed array and + * its ArrayBuffer. + */ +JS_FRIEND_API(JSBool) +js_ReparentTypedArrayToScope(JSContext *cx, JSObject *obj, JSObject *scope); + +extern int32 JS_FASTCALL +js_TypedArray_uint8_clamp_double(const double x); + +#endif /* jstypedarray_h */ diff --git a/js/src/jstypes.h b/js/src/jstypes.h new file mode 100644 index 0000000..c2103d8 --- /dev/null +++ b/js/src/jstypes.h @@ -0,0 +1,507 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +** File: jstypes.h +** Description: Definitions of NSPR's basic types +** +** Prototypes and macros used to make up for deficiencies in ANSI environments +** that we have found. +** +** Since we do not wrap and all the other standard headers, authors +** of portable code will not know in general that they need these definitions. +** Instead of requiring these authors to find the dependent uses in their code +** and take the following steps only in those C files, we take steps once here +** for all C files. +**/ + +#ifndef jstypes_h___ +#define jstypes_h___ + +#include +#include "js-config.h" + +/*********************************************************************** +** MACROS: JS_EXTERN_API +** JS_EXPORT_API +** DESCRIPTION: +** These are only for externally visible routines and globals. For +** internal routines, just use "extern" for type checking and that +** will not export internal cross-file or forward-declared symbols. +** Define a macro for declaring procedures return types. We use this to +** deal with windoze specific type hackery for DLL definitions. Use +** JS_EXTERN_API when the prototype for the method is declared. Use +** JS_EXPORT_API for the implementation of the method. +** +** Example: +** in dowhim.h +** JS_EXTERN_API( void ) DoWhatIMean( void ); +** in dowhim.c +** JS_EXPORT_API( void ) DoWhatIMean( void ) { return; } +** +** +***********************************************************************/ + +#define DEFINE_LOCAL_CLASS_OF_STATIC_FUNCTION(Name) class Name + +#if defined(WIN32) || defined(XP_OS2) + +/* These also work for __MWERKS__ */ +# define JS_EXTERN_API(__type) extern __declspec(dllexport) __type +# define JS_EXPORT_API(__type) __declspec(dllexport) __type +# define JS_EXTERN_DATA(__type) extern __declspec(dllexport) __type +# define JS_EXPORT_DATA(__type) __declspec(dllexport) __type + +#elif defined(__SYMBIAN32__) + +# define JS_EXTERN_API(__type) extern EXPORT_C __type +# define JS_EXPORT_API(__type) EXPORT_C __type +# define JS_EXTERN_DATA(__type) extern EXPORT_C __type +# define JS_EXPORT_DATA(__type) EXPORT_C __type + +#else /* Unix */ + +# ifdef HAVE_VISIBILITY_ATTRIBUTE +# define JS_EXTERNAL_VIS __attribute__((visibility ("default"))) +# if defined(__GNUC__) && __GNUC__ <= 4 && __GNUC_MINOR__ < 5 + /* + * GCC wrongly produces a warning when a type with hidden visibility + * (e.g. js::Value) is a member of a local class of a static function. + * This is apparently fixed with GCC 4.5 and above. See: + * + * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40145. + */ +# undef DEFINE_LOCAL_CLASS_OF_STATIC_FUNCTION +# define DEFINE_LOCAL_CLASS_OF_STATIC_FUNCTION(Name) class __attribute__((visibility ("hidden"))) Name +# endif +# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# define JS_EXTERNAL_VIS __global +# else +# define JS_EXTERNAL_VIS +# endif + +# define JS_EXTERN_API(__type) extern JS_EXTERNAL_VIS __type +# define JS_EXPORT_API(__type) JS_EXTERNAL_VIS __type +# define JS_EXTERN_DATA(__type) extern JS_EXTERNAL_VIS __type +# define JS_EXPORT_DATA(__type) JS_EXTERNAL_VIS __type + +#endif + +#ifdef _WIN32 +# if defined(__MWERKS__) || defined(__GNUC__) +# define JS_IMPORT_API(__x) __x +# else +# define JS_IMPORT_API(__x) __declspec(dllimport) __x +# endif +#elif defined(XP_OS2) +# define JS_IMPORT_API(__x) __declspec(dllimport) __x +#elif defined(__SYMBIAN32__) +# define JS_IMPORT_API(__x) IMPORT_C __x +#else +# define JS_IMPORT_API(__x) JS_EXPORT_API (__x) +#endif + +#if defined(_WIN32) && !defined(__MWERKS__) +# define JS_IMPORT_DATA(__x) __declspec(dllimport) __x +#elif defined(XP_OS2) +# define JS_IMPORT_DATA(__x) __declspec(dllimport) __x +#elif defined(__SYMBIAN32__) +# if defined(__CW32__) +# define JS_IMPORT_DATA(__x) __declspec(dllimport) __x +# else +# define JS_IMPORT_DATA(__x) IMPORT_C __x +# endif +#else +# define JS_IMPORT_DATA(__x) JS_EXPORT_DATA (__x) +#endif + +/* + * The linkage of JS API functions differs depending on whether the file is + * used within the JS library or not. Any source file within the JS + * interpreter should define EXPORT_JS_API whereas any client of the library + * should not. STATIC_JS_API is used to build JS as a static library. + */ +#if defined(STATIC_JS_API) + +# define JS_PUBLIC_API(t) t +# define JS_PUBLIC_DATA(t) t + +#elif defined(EXPORT_JS_API) || defined(STATIC_EXPORTABLE_JS_API) + +# define JS_PUBLIC_API(t) JS_EXPORT_API(t) +# define JS_PUBLIC_DATA(t) JS_EXPORT_DATA(t) + +#else + +# define JS_PUBLIC_API(t) JS_IMPORT_API(t) +# define JS_PUBLIC_DATA(t) JS_IMPORT_DATA(t) + +#endif + +#define JS_FRIEND_API(t) JS_PUBLIC_API(t) +#define JS_FRIEND_DATA(t) JS_PUBLIC_DATA(t) + +#if defined(_MSC_VER) && defined(_M_IX86) +#define JS_FASTCALL __fastcall +#elif defined(__GNUC__) && defined(__i386__) && \ + ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +#define JS_FASTCALL __attribute__((fastcall)) +#else +#define JS_FASTCALL +#define JS_NO_FASTCALL +#endif + +#ifndef JS_INLINE +# if defined __cplusplus +# define JS_INLINE inline +# elif defined _MSC_VER +# define JS_INLINE __inline +# elif defined __GNUC__ +# define JS_INLINE __inline__ +# else +# define JS_INLINE inline +# endif +#endif + +#ifndef JS_ALWAYS_INLINE +# if defined DEBUG +# define JS_ALWAYS_INLINE JS_INLINE +# elif defined _MSC_VER +# define JS_ALWAYS_INLINE __forceinline +# elif defined __GNUC__ +# define JS_ALWAYS_INLINE __attribute__((always_inline)) JS_INLINE +# else +# define JS_ALWAYS_INLINE JS_INLINE +# endif +#endif + +#ifndef JS_NEVER_INLINE +# if defined _MSC_VER +# define JS_NEVER_INLINE __declspec(noinline) +# elif defined __GNUC__ +# define JS_NEVER_INLINE __attribute__((noinline)) +# else +# define JS_NEVER_INLINE +# endif +#endif + +#ifndef JS_WARN_UNUSED_RESULT +# if defined __GNUC__ +# define JS_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define JS_WARN_UNUSED_RESULT +# endif +#endif + +#ifdef NS_STATIC_CHECKING +/* + * Attributes for static analysis. Functions declared with JS_REQUIRES_STACK + * always have a valid cx->fp and can access it freely. Other functions can + * access cx->fp only after calling a function that "forces" the stack + * (i.e. lazily instantiates it as needed). + */ +# define JS_REQUIRES_STACK __attribute__((user("JS_REQUIRES_STACK"))) +# define JS_FORCES_STACK __attribute__((user("JS_FORCES_STACK"))) +/* + * Skip the JS_REQUIRES_STACK analysis within functions with this annotation. + */ +# define JS_IGNORE_STACK __attribute__((user("JS_IGNORE_STACK"))) +#else +# define JS_REQUIRES_STACK +# define JS_FORCES_STACK +# define JS_IGNORE_STACK +#endif + +/*********************************************************************** +** MACROS: JS_BEGIN_MACRO +** JS_END_MACRO +** DESCRIPTION: +** Macro body brackets so that macros with compound statement definitions +** behave syntactically more like functions when called. +***********************************************************************/ +#define JS_BEGIN_MACRO do { + +#if defined(_MSC_VER) && _MSC_VER >= 1400 +# define JS_END_MACRO \ + } __pragma(warning(push)) __pragma(warning(disable:4127)) \ + while (0) __pragma(warning(pop)) +#else +# define JS_END_MACRO } while (0) +#endif + +/*********************************************************************** +** MACROS: JS_BEGIN_EXTERN_C +** JS_END_EXTERN_C +** DESCRIPTION: +** Macro shorthands for conditional C++ extern block delimiters. +***********************************************************************/ +#ifdef __cplusplus + +# define JS_BEGIN_EXTERN_C extern "C" { +# define JS_END_EXTERN_C } + +#else + +# define JS_BEGIN_EXTERN_C +# define JS_END_EXTERN_C + +#endif + +/*********************************************************************** +** MACROS: JS_BIT +** JS_BITMASK +** DESCRIPTION: +** Bit masking macros. XXX n must be <= 31 to be portable +***********************************************************************/ +#define JS_BIT(n) ((JSUint32)1 << (n)) +#define JS_BITMASK(n) (JS_BIT(n) - 1) + +/*********************************************************************** +** MACROS: JS_HOWMANY +** JS_ROUNDUP +** JS_MIN +** JS_MAX +** DESCRIPTION: +** Commonly used macros for operations on compatible types. +***********************************************************************/ +#define JS_HOWMANY(x,y) (((x)+(y)-1)/(y)) +#define JS_ROUNDUP(x,y) (JS_HOWMANY(x,y)*(y)) +#define JS_MIN(x,y) ((x)<(y)?(x):(y)) +#define JS_MAX(x,y) ((x)>(y)?(x):(y)) + +#ifdef _MSC_VER +# include "jscpucfg.h" /* We can't auto-detect MSVC configuration */ +# if _MSC_VER < 1400 +# define NJ_NO_VARIADIC_MACROS +# endif +#else +# include "jsautocfg.h" /* Use auto-detected configuration */ +#endif + +/* + * Define JS_64BIT iff we are building in an environment with 64-bit + * addresses. + */ +#ifdef _MSC_VER +# if defined(_M_X64) || defined(_M_AMD64) +# define JS_64BIT +# endif +#elif defined(__GNUC__) +# ifdef __x86_64__ +# define JS_64BIT +# endif +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# ifdef __x86_64 +# define JS_64BIT +# endif +#else +# error "Implement me" +#endif + + +#include "jsinttypes.h" + +JS_BEGIN_EXTERN_C + +/************************************************************************ +** TYPES: JSUintn +** JSIntn +** DESCRIPTION: +** The JSIntn types are most appropriate for automatic variables. They are +** guaranteed to be at least 16 bits, though various architectures may +** define them to be wider (e.g., 32 or even 64 bits). These types are +** never valid for fields of a structure. +************************************************************************/ + +typedef int JSIntn; +typedef unsigned int JSUintn; + +/************************************************************************ +** TYPES: JSFloat64 +** DESCRIPTION: +** NSPR's floating point type is always 64 bits. +************************************************************************/ +typedef double JSFloat64; + +/************************************************************************ +** TYPES: JSSize +** DESCRIPTION: +** A type for representing the size of objects. +************************************************************************/ +typedef size_t JSSize; + +/************************************************************************ +** TYPES: JSPtrDiff +** DESCRIPTION: +** A type for pointer difference. Variables of this type are suitable +** for storing a pointer or pointer sutraction. +************************************************************************/ +typedef ptrdiff_t JSPtrdiff; + +/************************************************************************ +** TYPES: JSUptrdiff +** DESCRIPTION: +** A type for pointer difference. Variables of this type are suitable +** for storing a pointer or pointer sutraction. +************************************************************************/ +typedef JSUintPtr JSUptrdiff; + +/************************************************************************ +** TYPES: JSBool +** DESCRIPTION: +** Use JSBool for variables and parameter types. Use JS_FALSE and JS_TRUE +** for clarity of target type in assignments and actual arguments. Use +** 'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans +** just as you would C int-valued conditions. +************************************************************************/ +typedef JSIntn JSBool; +#define JS_TRUE (JSIntn)1 +#define JS_FALSE (JSIntn)0 +/* +** Special: JS_NEITHER is used by the tracer to have tri-state booleans. +** This should not be used in new code. +*/ +#define JS_NEITHER (JSIntn)2 + +/************************************************************************ +** TYPES: JSPackedBool +** DESCRIPTION: +** Use JSPackedBool within structs where bitfields are not desireable +** but minimum and consistent overhead matters. +************************************************************************/ +typedef JSUint8 JSPackedBool; + +/* +** A JSWord is an integer that is the same size as a void* +*/ +typedef JSIntPtr JSWord; +typedef JSUintPtr JSUword; + +#include "jsotypes.h" + +/*********************************************************************** +** MACROS: JS_LIKELY +** JS_UNLIKELY +** DESCRIPTION: +** These macros allow you to give a hint to the compiler about branch +** probability so that it can better optimize. Use them like this: +** +** if (JS_LIKELY(v == 1)) { +** ... expected code path ... +** } +** +** if (JS_UNLIKELY(v == 0)) { +** ... non-expected code path ... +** } +** +***********************************************************************/ +#if defined(__GNUC__) && (__GNUC__ > 2) + +# define JS_LIKELY(x) (__builtin_expect((x), 1)) +# define JS_UNLIKELY(x) (__builtin_expect((x), 0)) + +#else + +# define JS_LIKELY(x) (x) +# define JS_UNLIKELY(x) (x) + +#endif + +/*********************************************************************** +** MACROS: JS_ARRAY_LENGTH +** JS_ARRAY_END +** DESCRIPTION: +** Macros to get the number of elements and the pointer to one past the +** last element of a C array. Use them like this: +** +** jschar buf[10], *s; +** JSString *str; +** ... +** for (s = buf; s != JS_ARRAY_END(buf); ++s) *s = ...; +** ... +** str = JS_NewStringCopyN(cx, buf, JS_ARRAY_LENGTH(buf)); +** ... +** +***********************************************************************/ + +#define JS_ARRAY_LENGTH(array) (sizeof (array) / sizeof (array)[0]) +#define JS_ARRAY_END(array) ((array) + JS_ARRAY_LENGTH(array)) + +#define JS_BITS_PER_BYTE 8 +#define JS_BITS_PER_BYTE_LOG2 3 + +#define JS_BITS_PER_WORD (JS_BITS_PER_BYTE * JS_BYTES_PER_WORD) +#define JS_BITS_PER_DOUBLE (JS_BITS_PER_BYTE * JS_BYTES_PER_DOUBLE) + +/*********************************************************************** +** MACROS: JS_FUNC_TO_DATA_PTR +** JS_DATA_TO_FUNC_PTR +** DESCRIPTION: +** Macros to convert between function and data pointers assuming that +** they have the same size. Use them like this: +** +** JSPropertyOp nativeGetter; +** JSObject *scriptedGetter; +** ... +** scriptedGetter = JS_FUNC_TO_DATA_PTR(JSObject *, nativeGetter); +** ... +** nativeGetter = JS_DATA_TO_FUNC_PTR(JSPropertyOp, scriptedGetter); +** +***********************************************************************/ + +#ifdef __GNUC__ +# define JS_FUNC_TO_DATA_PTR(type, fun) (__extension__ (type) (size_t) (fun)) +# define JS_DATA_TO_FUNC_PTR(type, ptr) (__extension__ (type) (size_t) (ptr)) +#else +/* Use an extra (void *) cast for MSVC. */ +# define JS_FUNC_TO_DATA_PTR(type, fun) ((type) (void *) (fun)) +# define JS_DATA_TO_FUNC_PTR(type, ptr) ((type) (void *) (ptr)) +#endif + +#ifdef __GNUC__ +# define JS_EXTENSION __extension__ +# define JS_EXTENSION_(s) __extension__ ({ s; }) +#else +# define JS_EXTENSION +# define JS_EXTENSION_(s) s +#endif + +JS_END_EXTERN_C + +#endif /* jstypes_h___ */ diff --git a/js/src/jsutil.cpp b/js/src/jsutil.cpp new file mode 100644 index 0000000..dc66ab6 --- /dev/null +++ b/js/src/jsutil.cpp @@ -0,0 +1,379 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * PR assertion checker. + */ +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsutil.h" + +#ifdef WIN32 +# include "jswin.h" +#else +# include +#endif + +using namespace js; + +/* + * Checks the assumption that JS_FUNC_TO_DATA_PTR and JS_DATA_TO_FUNC_PTR + * macros uses to implement casts between function and data pointers. + */ +JS_STATIC_ASSERT(sizeof(void *) == sizeof(void (*)())); + +JS_PUBLIC_API(void) JS_Assert(const char *s, const char *file, JSIntn ln) +{ + fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln); + fflush(stderr); +#if defined(WIN32) + /* + * We used to call DebugBreak() on Windows, but amazingly, it causes + * the MSVS 2010 debugger not to be able to recover a call stack. + */ + *((int *) NULL) = 0; + exit(3); +#elif defined(__APPLE__) + /* + * On Mac OS X, Breakpad ignores signals. Only real Mach exceptions are + * trapped. + */ + *((int *) NULL) = 0; /* To continue from here in GDB: "return" then "continue". */ + raise(SIGABRT); /* In case above statement gets nixed by the optimizer. */ +#else + raise(SIGABRT); /* To continue from here in GDB: "signal 0". */ +#endif +} + +#ifdef JS_BASIC_STATS + +#include +#include +#include "jscompat.h" +#include "jsbit.h" + +/* + * Histogram bins count occurrences of values <= the bin label, as follows: + * + * linear: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or more + * 2**x: 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 or more + * 10**x: 0, 1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 or more + * + * We wish to count occurrences of 0 and 1 values separately, always. + */ +static uint32 +BinToVal(uintN logscale, uintN bin) +{ + JS_ASSERT(bin <= 10); + if (bin <= 1 || logscale == 0) + return bin; + --bin; + if (logscale == 2) + return JS_BIT(bin); + JS_ASSERT(logscale == 10); + return (uint32) pow(10.0, (double) bin); +} + +static uintN +ValToBin(uintN logscale, uint32 val) +{ + uintN bin; + + if (val <= 1) + return val; + bin = (logscale == 10) + ? (uintN) ceil(log10((double) val)) + : (logscale == 2) + ? (uintN) JS_CeilingLog2(val) + : val; + return JS_MIN(bin, 10); +} + +void +JS_BasicStatsAccum(JSBasicStats *bs, uint32 val) +{ + uintN oldscale, newscale, bin; + double mean; + + ++bs->num; + if (bs->max < val) + bs->max = val; + bs->sum += val; + bs->sqsum += (double)val * val; + + oldscale = bs->logscale; + if (oldscale != 10) { + mean = bs->sum / bs->num; + if (bs->max > 16 && mean > 8) { + newscale = (bs->max > 1e6 && mean > 1000) ? 10 : 2; + if (newscale != oldscale) { + uint32 newhist[11], newbin; + + PodArrayZero(newhist); + for (bin = 0; bin <= 10; bin++) { + newbin = ValToBin(newscale, BinToVal(oldscale, bin)); + newhist[newbin] += bs->hist[bin]; + } + memcpy(bs->hist, newhist, sizeof bs->hist); + bs->logscale = newscale; + } + } + } + + bin = ValToBin(bs->logscale, val); + ++bs->hist[bin]; +} + +double +JS_MeanAndStdDev(uint32 num, double sum, double sqsum, double *sigma) +{ + double var; + + if (num == 0 || sum == 0) { + *sigma = 0; + return 0; + } + + var = num * sqsum - sum * sum; + if (var < 0 || num == 1) + var = 0; + else + var /= (double)num * (num - 1); + + /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */ + *sigma = (var != 0) ? sqrt(var) : 0; + return sum / num; +} + +void +JS_DumpBasicStats(JSBasicStats *bs, const char *title, FILE *fp) +{ + double mean, sigma; + + mean = JS_MeanAndStdDevBS(bs, &sigma); + fprintf(fp, "\nmean %s %g, std. deviation %g, max %lu\n", + title, mean, sigma, (unsigned long) bs->max); + JS_DumpHistogram(bs, fp); +} + +void +JS_DumpHistogram(JSBasicStats *bs, FILE *fp) +{ + uintN bin; + uint32 cnt, max; + double sum, mean; + + for (bin = 0, max = 0, sum = 0; bin <= 10; bin++) { + cnt = bs->hist[bin]; + if (max < cnt) + max = cnt; + sum += cnt; + } + mean = sum / cnt; + for (bin = 0; bin <= 10; bin++) { + uintN val = BinToVal(bs->logscale, bin); + uintN end = (bin == 10) ? 0 : BinToVal(bs->logscale, bin + 1); + cnt = bs->hist[bin]; + if (val + 1 == end) + fprintf(fp, " [%6u]", val); + else if (end != 0) + fprintf(fp, "[%6u, %6u]", val, end - 1); + else + fprintf(fp, "[%6u, +inf]", val); + fprintf(fp, ": %8u ", cnt); + if (cnt != 0) { + if (max > 1e6 && mean > 1e3) + cnt = (uint32) ceil(log10((double) cnt)); + else if (max > 16 && mean > 8) + cnt = JS_CeilingLog2(cnt); + for (uintN i = 0; i < cnt; i++) + putc('*', fp); + } + putc('\n', fp); + } +} + +#endif /* JS_BASIC_STATS */ + +#if defined(DEBUG_notme) && defined(XP_UNIX) + +#define __USE_GNU 1 +#include +#include +#include "jshash.h" +#include "jsprf.h" + +JSCallsite js_calltree_root = {0, NULL, NULL, 0, NULL, NULL, NULL, NULL}; + +static JSCallsite * +CallTree(void **bp) +{ + void **bpup, **bpdown, *pc; + JSCallsite *parent, *site, **csp; + Dl_info info; + int ok, offset; + const char *symbol; + char *method; + + /* Reverse the stack frame list to avoid recursion. */ + bpup = NULL; + for (;;) { + bpdown = (void**) bp[0]; + bp[0] = (void*) bpup; + if ((void**) bpdown[0] < bpdown) + break; + bpup = bp; + bp = bpdown; + } + + /* Reverse the stack again, finding and building a path in the tree. */ + parent = &js_calltree_root; + do { + bpup = (void**) bp[0]; + bp[0] = (void*) bpdown; + pc = bp[1]; + + csp = &parent->kids; + while ((site = *csp) != NULL) { + if (site->pc == (uint32)pc) { + /* Put the most recently used site at the front of siblings. */ + *csp = site->siblings; + site->siblings = parent->kids; + parent->kids = site; + + /* Site already built -- go up the stack. */ + goto upward; + } + csp = &site->siblings; + } + + /* Check for recursion: see if pc is on our ancestor line. */ + for (site = parent; site; site = site->parent) { + if (site->pc == (uint32)pc) + goto upward; + } + + /* + * Not in tree at all: let's find our symbolic callsite info. + * XXX static syms are masked by nearest lower global + */ + info.dli_fname = info.dli_sname = NULL; + ok = dladdr(pc, &info); + if (ok < 0) { + fprintf(stderr, "dladdr failed!\n"); + return NULL; + } + +/* XXXbe sub 0x08040000? or something, see dbaron bug with tenthumbs comment */ + symbol = info.dli_sname; + offset = (char*)pc - (char*)info.dli_fbase; + method = symbol + ? strdup(symbol) + : JS_smprintf("%s+%X", + info.dli_fname ? info.dli_fname : "main", + offset); + if (!method) + return NULL; + + /* Create a new callsite record. */ + site = (JSCallsite *) js_malloc(sizeof(JSCallsite)); + if (!site) + return NULL; + + /* Insert the new site into the tree. */ + site->pc = (uint32)pc; + site->name = method; + site->library = info.dli_fname; + site->offset = offset; + site->parent = parent; + site->siblings = parent->kids; + parent->kids = site; + site->kids = NULL; + + upward: + parent = site; + bpdown = bp; + bp = bpup; + } while (bp); + + return site; +} + +JS_FRIEND_API(JSCallsite *) +JS_Backtrace(int skip) +{ + void **bp, **bpdown; + + /* Stack walking code adapted from Kipp's "leaky". */ +#if defined(__i386) + __asm__( "movl %%ebp, %0" : "=g"(bp)); +#elif defined(__x86_64__) + __asm__( "movq %%rbp, %0" : "=g"(bp)); +#else + /* + * It would be nice if this worked uniformly, but at least on i386 and + * x86_64, it stopped working with gcc 4.1, because it points to the + * end of the saved registers instead of the start. + */ + bp = (void**) __builtin_frame_address(0); +#endif + while (--skip >= 0) { + bpdown = (void**) *bp++; + if (bpdown < bp) + break; + bp = bpdown; + } + + return CallTree(bp); +} + +JS_FRIEND_API(void) +JS_DumpBacktrace(JSCallsite *trace) +{ + while (trace) { + fprintf(stdout, "%s [%s +0x%X]\n", trace->name, trace->library, + trace->offset); + trace = trace->parent; + } +} + +#endif /* defined(DEBUG_notme) && defined(XP_UNIX) */ diff --git a/js/src/jsutil.h b/js/src/jsutil.h new file mode 100644 index 0000000..9da2674 --- /dev/null +++ b/js/src/jsutil.h @@ -0,0 +1,469 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * PR assertion checker. + */ + +#ifndef jsutil_h___ +#define jsutil_h___ + +#include "jstypes.h" +#include +#include + +JS_BEGIN_EXTERN_C + +/* + * JS_Assert is present even in release builds, for the benefit of applications + * that build DEBUG and link against a non-DEBUG SpiderMonkey library. + */ +extern JS_PUBLIC_API(void) +JS_Assert(const char *s, const char *file, JSIntn ln); + +#define JS_CRASH_UNLESS(__cond) \ + JS_BEGIN_MACRO \ + if (!(__cond)) { \ + *(int *)(uintptr_t)0xccadbeef = 0; \ + ((void(*)())0)(); /* More reliable, but doesn't say CCADBEEF */ \ + } \ + JS_END_MACRO + +#ifdef DEBUG + +#define JS_ASSERT(expr) \ + ((expr) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__)) + +#define JS_ASSERT_IF(cond, expr) \ + ((!(cond) || (expr)) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__)) + +#define JS_NOT_REACHED(reason) \ + JS_Assert(reason, __FILE__, __LINE__) + +#define JS_ALWAYS_TRUE(expr) JS_ASSERT(expr) + +#define JS_ALWAYS_FALSE(expr) JS_ASSERT(!(expr)) + +# ifdef JS_THREADSAFE +# define JS_THREADSAFE_ASSERT(expr) JS_ASSERT(expr) +# else +# define JS_THREADSAFE_ASSERT(expr) ((void) 0) +# endif + +#else + +#define JS_ASSERT(expr) ((void) 0) +#define JS_ASSERT_IF(cond,expr) ((void) 0) +#define JS_NOT_REACHED(reason) +#define JS_ALWAYS_TRUE(expr) ((void) (expr)) +#define JS_ALWAYS_FALSE(expr) ((void) (expr)) +#define JS_THREADSAFE_ASSERT(expr) ((void) 0) + +#endif /* defined(DEBUG) */ + +/* + * Compile-time assert. "cond" must be a constant expression. + * The macro can be used only in places where an "extern" declaration is + * allowed. + */ + +#ifdef __SUNPRO_CC +/* + * Sun Studio C++ compiler has a bug + * "sizeof expression not accepted as size of array parameter" + * It happens when js_static_assert() function is declared inside functions. + * The bug number is 6688515. It is not public yet. + * Therefore, for Sun Studio, declare js_static_assert as an array instead. + */ +#define JS_STATIC_ASSERT(cond) extern char js_static_assert[(cond) ? 1 : -1] +#else +#ifdef __COUNTER__ + #define JS_STATIC_ASSERT_GLUE1(x,y) x##y + #define JS_STATIC_ASSERT_GLUE(x,y) JS_STATIC_ASSERT_GLUE1(x,y) + #define JS_STATIC_ASSERT(cond) \ + typedef int JS_STATIC_ASSERT_GLUE(js_static_assert, __COUNTER__)[(cond) ? 1 : -1] +#else + #define JS_STATIC_ASSERT(cond) extern void js_static_assert(int arg[(cond) ? 1 : -1]) +#endif +#endif + +#define JS_STATIC_ASSERT_IF(cond, expr) JS_STATIC_ASSERT(!(cond) || (expr)) + +/* + * Abort the process in a non-graceful manner. This will cause a core file, + * call to the debugger or other moral equivalent as well as causing the + * entire process to stop. + */ +extern JS_PUBLIC_API(void) JS_Abort(void); + +#ifdef DEBUG +# define JS_BASIC_STATS 1 +#endif + +#ifdef DEBUG_brendan +# define JS_SCOPE_DEPTH_METER 1 +#endif + +#ifdef JS_BASIC_STATS + +#include + +typedef struct JSBasicStats { + uint32 num; + uint32 max; + double sum; + double sqsum; + uint32 logscale; /* logarithmic scale: 0 (linear), 2, 10 */ + uint32 hist[11]; +} JSBasicStats; + +#define JS_INIT_STATIC_BASIC_STATS {0,0,0,0,0,{0,0,0,0,0,0,0,0,0,0,0}} +#define JS_BASIC_STATS_INIT(bs) memset((bs), 0, sizeof(JSBasicStats)) + +#define JS_BASIC_STATS_ACCUM(bs,val) \ + JS_BasicStatsAccum(bs, val) + +#define JS_MeanAndStdDevBS(bs,sigma) \ + JS_MeanAndStdDev((bs)->num, (bs)->sum, (bs)->sqsum, sigma) + +extern void +JS_BasicStatsAccum(JSBasicStats *bs, uint32 val); + +extern double +JS_MeanAndStdDev(uint32 num, double sum, double sqsum, double *sigma); + +extern void +JS_DumpBasicStats(JSBasicStats *bs, const char *title, FILE *fp); + +extern void +JS_DumpHistogram(JSBasicStats *bs, FILE *fp); + +#else + +#define JS_BASIC_STATS_ACCUM(bs,val) /* nothing */ + +#endif /* JS_BASIC_STATS */ + + +#if defined(DEBUG_notme) && defined(XP_UNIX) + +typedef struct JSCallsite JSCallsite; + +struct JSCallsite { + uint32 pc; + char *name; + const char *library; + int offset; + JSCallsite *parent; + JSCallsite *siblings; + JSCallsite *kids; + void *handy; +}; + +extern JS_FRIEND_API(JSCallsite *) +JS_Backtrace(int skip); + +extern JS_FRIEND_API(void) +JS_DumpBacktrace(JSCallsite *trace); +#endif + +#if defined JS_USE_CUSTOM_ALLOCATOR + +#include "jscustomallocator.h" + +#else + +static JS_INLINE void* js_malloc(size_t bytes) { + return malloc(bytes); +} + +static JS_INLINE void* js_calloc(size_t bytes) { + return calloc(bytes, 1); +} + +static JS_INLINE void* js_realloc(void* p, size_t bytes) { + return realloc(p, bytes); +} + +static JS_INLINE void js_free(void* p) { + free(p); +} +#endif/* JS_USE_CUSTOM_ALLOCATOR */ + +JS_END_EXTERN_C + +#ifdef __cplusplus + +/* + * Using vanilla new/new[] is unsafe in SpiderMonkey because they throw on + * failure instead of returning NULL, which is what SpiderMonkey expects. + * js_new()/js_array_new() should be used instead, and memory allocated with + * them should be deallocated with js_delete()/js_array_delete(). + * + * If you have a class with a private constructor or destructor, you can + * make js_new/js_delete a friend. This can be fiddly, and the interaction of + * template functions, friend functions and namespaces can overwhelm even + * modern compilers. Manual inlining is probably easier. + * + * (If you're wondering why we can't just use the 'nothrow' variant of + * new/new[], it's because we want to mediate *all* allocations within + * SpiderMonkey, to satisfy any embedders using JS_USE_CUSTOM_ALLOCATOR.) + */ + +#define JS_NEW_BODY(t, parms) \ + void *memory = js_malloc(sizeof(t)); \ + return memory ? new(memory) t parms : NULL; + +template +JS_ALWAYS_INLINE T *js_new() { + JS_NEW_BODY(T, ()) +} + +template +JS_ALWAYS_INLINE T *js_new(const P1 &p1) { + JS_NEW_BODY(T, (p1)) +} + +template +JS_ALWAYS_INLINE T *js_new(const P1 &p1, const P2 &p2) { + JS_NEW_BODY(T, (p1, p2)) +} + +template +JS_ALWAYS_INLINE T *js_new(const P1 &p1, const P2 &p2, const P3 &p3) { + JS_NEW_BODY(T, (p1, p2, p3)) +} + +template +JS_ALWAYS_INLINE T *js_new(const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) { + JS_NEW_BODY(T, (p1, p2, p3, p4)) +} + +/* ...add additional js_new()s as necessary... */ + +#undef JS_NEW_BODY + +template +JS_ALWAYS_INLINE void js_delete(T *p) { + if (p) { + p->~T(); + js_free(p); + } +} + +static const int JSMinAlignment = 8; + +template +JS_ALWAYS_INLINE T *js_array_new(size_t n) { + /* The length is stored just before the vector memory. */ + uint64 numBytes64 = uint64(JSMinAlignment) + uint64(sizeof(T)) * uint64(n); + size_t numBytes = size_t(numBytes64); + if (numBytes64 != numBytes) { + JS_ASSERT(0); /* we want to know if this happens in debug builds */ + return NULL; + } + void *memory = js_malloc(numBytes); + if (!memory) + return NULL; + *(size_t *)memory = n; + memory = (void*)(uintptr_t(memory) + JSMinAlignment); + return new(memory) T[n]; +} + +template +JS_ALWAYS_INLINE void js_array_delete(T *p) { + if (p) { + void* p0 = (void *)(uintptr_t(p) - JSMinAlignment); + size_t n = *(size_t *)p0; + for (size_t i = 0; i < n; i++) + (p + i)->~T(); + js_free(p0); + } +} + +/** + * The following classes are designed to cause assertions to detect + * inadvertent use of guard objects as temporaries. In other words, + * when we have a guard object whose only purpose is its constructor and + * destructor (and is never otherwise referenced), the intended use + * might be: + * JSAutoTempValueRooter tvr(cx, 1, &val); + * but is is easy to accidentally write: + * JSAutoTempValueRooter(cx, 1, &val); + * which compiles just fine, but runs the destructor well before the + * intended time. + * + * They work by adding (#ifdef DEBUG) an additional parameter to the + * guard object's constructor, with a default value, so that users of + * the guard object's API do not need to do anything. The default value + * of this parameter is a temporary object. C++ (ISO/IEC 14882:1998), + * section 12.2 [class.temporary], clauses 4 and 5 seem to assume a + * guarantee that temporaries are destroyed in the reverse of their + * construction order, but I actually can't find a statement that that + * is true in the general case (beyond the two specific cases mentioned + * there). However, it seems to be true. + * + * These classes are intended to be used only via the macros immediately + * below them: + * JS_DECL_USE_GUARD_OBJECT_NOTIFIER declares (ifdef DEBUG) a member + * variable, and should be put where a declaration of a private + * member variable would be placed. + * JS_GUARD_OBJECT_NOTIFIER_PARAM should be placed at the end of the + * parameters to each constructor of the guard object; it declares + * (ifdef DEBUG) an additional parameter. + * JS_GUARD_OBJECT_NOTIFIER_INIT is a statement that belongs in each + * constructor. It uses the parameter declared by + * JS_GUARD_OBJECT_NOTIFIER_PARAM. + */ +#ifdef DEBUG +class JSGuardObjectNotifier +{ +private: + bool* mStatementDone; +public: + JSGuardObjectNotifier() : mStatementDone(NULL) {} + + ~JSGuardObjectNotifier() { + *mStatementDone = true; + } + + void setStatementDone(bool *aStatementDone) { + mStatementDone = aStatementDone; + } +}; + +class JSGuardObjectNotificationReceiver +{ +private: + bool mStatementDone; +public: + JSGuardObjectNotificationReceiver() : mStatementDone(false) {} + + ~JSGuardObjectNotificationReceiver() { + /* + * Assert that the guard object was not used as a temporary. + * (Note that this assert might also fire if Init is not called + * because the guard object's implementation is not using the + * above macros correctly.) + */ + JS_ASSERT(mStatementDone); + } + + void Init(const JSGuardObjectNotifier &aNotifier) { + /* + * aNotifier is passed as a const reference so that we can pass a + * temporary, but we really intend it as non-const + */ + const_cast(aNotifier). + setStatementDone(&mStatementDone); + } +}; + +#define JS_DECL_USE_GUARD_OBJECT_NOTIFIER \ + JSGuardObjectNotificationReceiver _mCheckNotUsedAsTemporary; +#define JS_GUARD_OBJECT_NOTIFIER_PARAM \ + , const JSGuardObjectNotifier& _notifier = JSGuardObjectNotifier() +#define JS_GUARD_OBJECT_NOTIFIER_PARAM0 \ + const JSGuardObjectNotifier& _notifier = JSGuardObjectNotifier() +#define JS_GUARD_OBJECT_NOTIFIER_INIT \ + JS_BEGIN_MACRO _mCheckNotUsedAsTemporary.Init(_notifier); JS_END_MACRO + +#else /* defined(DEBUG) */ + +#define JS_DECL_USE_GUARD_OBJECT_NOTIFIER +#define JS_GUARD_OBJECT_NOTIFIER_PARAM +#define JS_GUARD_OBJECT_NOTIFIER_PARAM0 +#define JS_GUARD_OBJECT_NOTIFIER_INIT JS_BEGIN_MACRO JS_END_MACRO + +#endif /* !defined(DEBUG) */ + +namespace js { + +template +JS_ALWAYS_INLINE static void +PodZero(T *t) +{ + memset(t, 0, sizeof(T)); +} + +template +JS_ALWAYS_INLINE static void +PodZero(T *t, size_t nelem) +{ + memset(t, 0, nelem * sizeof(T)); +} + +/* + * Arrays implicitly convert to pointers to their first element, which is + * dangerous when combined with the above PodZero definitions. Adding an + * overload for arrays is ambiguous, so we need another identifier. The + * ambiguous overload is left to catch mistaken uses of PodZero; if you get a + * compile error involving PodZero and array types, use PodArrayZero instead. + */ +template static void PodZero(T (&)[N]); /* undefined */ +template static void PodZero(T (&)[N], size_t); /* undefined */ + +template +JS_ALWAYS_INLINE static void +PodArrayZero(T (&t)[N]) +{ + memset(t, 0, N * sizeof(T)); +} + +template +JS_ALWAYS_INLINE static void +PodCopy(T *dst, const T *src, size_t nelem) +{ + /* Cannot find portable word-sized abs(). */ + JS_ASSERT_IF(dst >= src, size_t(dst - src) >= nelem); + JS_ASSERT_IF(src >= dst, size_t(src - dst) >= nelem); + + if (nelem < 128) { + for (const T *srcend = src + nelem; src != srcend; ++src, ++dst) + *dst = *src; + } else { + memcpy(dst, src, nelem * sizeof(T)); + } +} + +} /* namespace js */ + +#endif /* defined(__cplusplus) */ + +#endif /* jsutil_h___ */ diff --git a/js/src/jsval.h b/js/src/jsval.h new file mode 100644 index 0000000..f629862 --- /dev/null +++ b/js/src/jsval.h @@ -0,0 +1,831 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * June 30, 2010 + * + * The Initial Developer of the Original Code is + * the Mozilla Corporation. + * + * Contributor(s): + * Luke Wagner + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsvalimpl_h__ +#define jsvalimpl_h__ +/* + * JS value implementation details for operations on jsval and jsid. + * Embeddings should not rely on any of the definitions in this file. For a + * description of the value representation and the engine-internal C++ value + * interface, js::Value, see jsvalue.h. + */ +#include "jsutil.h" + +JS_BEGIN_EXTERN_C + +/* + * Try to get jsvals 64-bit aligned. We could almost assert that all values are + * aligned, but MSVC and GCC occasionally break alignment. + */ +#ifdef __GNUC__ +# define JSVAL_ALIGNMENT __attribute__((aligned (8))) +#elif defined(_MSC_VER) + /* + * Structs can be aligned with MSVC, but not if they are used as parameters, + * so we just don't try to align. + */ +# define JSVAL_ALIGNMENT +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# define JSVAL_ALIGNMENT +#endif + +#if JS_BITS_PER_WORD == 64 +# define JSVAL_TAG_SHIFT 47 +#endif + +/* + * We try to use enums so that printing a jsval_layout in the debugger shows + * nice symbolic type tags, however we can only do this when we can force the + * underlying type of the enum to be the desired size. + */ +#if defined(__cplusplus) && !defined(__SUNPRO_CC) + +#if defined(_MSC_VER) +# define JS_ENUM_HEADER(id, type) enum id : type +# define JS_ENUM_MEMBER(id, type, value) id = (type)value, +# define JS_LAST_ENUM_MEMBER(id, type, value) id = (type)value +# define JS_ENUM_FOOTER(id) +#else +# define JS_ENUM_HEADER(id, type) enum id +# define JS_ENUM_MEMBER(id, type, value) id = (type)value, +# define JS_LAST_ENUM_MEMBER(id, type, value) id = (type)value +# define JS_ENUM_FOOTER(id) __attribute__((packed)) +#endif + +/* Remember to propagate changes to the C defines below. */ +JS_ENUM_HEADER(JSValueType, uint8) +{ + JSVAL_TYPE_DOUBLE = 0x00, + JSVAL_TYPE_INT32 = 0x01, + JSVAL_TYPE_UNDEFINED = 0x02, + JSVAL_TYPE_BOOLEAN = 0x03, + JSVAL_TYPE_MAGIC = 0x04, + JSVAL_TYPE_STRING = 0x05, + JSVAL_TYPE_NULL = 0x06, + JSVAL_TYPE_OBJECT = 0x07, + + /* The below types never appear in a jsval; they are only used in tracing. */ + + JSVAL_TYPE_NONFUNOBJ = 0x57, + JSVAL_TYPE_FUNOBJ = 0x67, + + JSVAL_TYPE_STRORNULL = 0x97, + JSVAL_TYPE_OBJORNULL = 0x98, + + JSVAL_TYPE_BOXED = 0x99 +} JS_ENUM_FOOTER(JSValueType); + +JS_STATIC_ASSERT(sizeof(JSValueType) == 1); + +#if JS_BITS_PER_WORD == 32 + +/* Remember to propagate changes to the C defines below. */ +JS_ENUM_HEADER(JSValueTag, uint32) +{ + JSVAL_TAG_CLEAR = 0xFFFF0000, + JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32, + JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED, + JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING, + JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN, + JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC, + JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, + JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT +} JS_ENUM_FOOTER(JSValueTag); + +JS_STATIC_ASSERT(sizeof(JSValueTag) == 4); + +#elif JS_BITS_PER_WORD == 64 + +/* Remember to propagate changes to the C defines below. */ +JS_ENUM_HEADER(JSValueTag, uint32) +{ + JSVAL_TAG_MAX_DOUBLE = 0x1FFF0, + JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32, + JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED, + JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING, + JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN, + JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC, + JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, + JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT +} JS_ENUM_FOOTER(JSValueTag); + +JS_STATIC_ASSERT(sizeof(JSValueTag) == sizeof(uint32)); + +JS_ENUM_HEADER(JSValueShiftedTag, uint64) +{ + JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF), + JSVAL_SHIFTED_TAG_INT32 = (((uint64)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_STRING = (((uint64)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_MAGIC = (((uint64)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_NULL = (((uint64)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_OBJECT = (((uint64)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) +} JS_ENUM_FOOTER(JSValueShiftedTag); + +JS_STATIC_ASSERT(sizeof(JSValueShiftedTag) == sizeof(uint64)); + +#endif + +#else /* defined(__cplusplus) */ + +typedef uint8 JSValueType; +#define JSVAL_TYPE_DOUBLE ((uint8)0x00) +#define JSVAL_TYPE_INT32 ((uint8)0x01) +#define JSVAL_TYPE_UNDEFINED ((uint8)0x02) +#define JSVAL_TYPE_BOOLEAN ((uint8)0x03) +#define JSVAL_TYPE_MAGIC ((uint8)0x04) +#define JSVAL_TYPE_STRING ((uint8)0x05) +#define JSVAL_TYPE_NULL ((uint8)0x06) +#define JSVAL_TYPE_OBJECT ((uint8)0x07) +#define JSVAL_TYPE_NONFUNOBJ ((uint8)0x57) +#define JSVAL_TYPE_FUNOBJ ((uint8)0x67) +#define JSVAL_TYPE_STRORNULL ((uint8)0x97) +#define JSVAL_TYPE_OBJORNULL ((uint8)0x98) +#define JSVAL_TYPE_BOXED ((uint8)0x99) +#define JSVAL_TYPE_UNINITIALIZED ((uint8)0xcd) + +#if JS_BITS_PER_WORD == 32 + +typedef uint32 JSValueTag; +#define JSVAL_TAG_CLEAR ((uint32)(0xFFFF0000)) +#define JSVAL_TAG_INT32 ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32)) +#define JSVAL_TAG_UNDEFINED ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED)) +#define JSVAL_TAG_STRING ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING)) +#define JSVAL_TAG_BOOLEAN ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN)) +#define JSVAL_TAG_MAGIC ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC)) +#define JSVAL_TAG_NULL ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL)) +#define JSVAL_TAG_OBJECT ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT)) + +#elif JS_BITS_PER_WORD == 64 + +typedef uint32 JSValueTag; +#define JSVAL_TAG_MAX_DOUBLE ((uint32)(0x1FFF0)) +#define JSVAL_TAG_INT32 (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32) +#define JSVAL_TAG_UNDEFINED (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED) +#define JSVAL_TAG_STRING (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING) +#define JSVAL_TAG_BOOLEAN (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN) +#define JSVAL_TAG_MAGIC (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC) +#define JSVAL_TAG_NULL (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL) +#define JSVAL_TAG_OBJECT (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT) + +typedef uint64 JSValueShiftedTag; +#define JSVAL_SHIFTED_TAG_MAX_DOUBLE ((((uint64)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF) +#define JSVAL_SHIFTED_TAG_INT32 (((uint64)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_UNDEFINED (((uint64)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_STRING (((uint64)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_BOOLEAN (((uint64)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_MAGIC (((uint64)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_NULL (((uint64)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_OBJECT (((uint64)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) + +#endif /* JS_BITS_PER_WORD */ +#endif /* defined(__cplusplus) && !defined(__SUNPRO_CC) */ + +#define JSVAL_LOWER_INCL_TYPE_OF_OBJ_OR_NULL_SET JSVAL_TYPE_NULL +#define JSVAL_UPPER_EXCL_TYPE_OF_PRIMITIVE_SET JSVAL_TYPE_OBJECT +#define JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET JSVAL_TYPE_INT32 +#define JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET JSVAL_TYPE_MAGIC +#define JSVAL_UPPER_INCL_TYPE_OF_VALUE_SET JSVAL_TYPE_OBJECT +#define JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET JSVAL_TYPE_FUNOBJ + +#if JS_BITS_PER_WORD == 32 + +#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) + +#define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL +#define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT +#define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 +#define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING + +#elif JS_BITS_PER_WORD == 64 + +#define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL +#define JSVAL_TAG_MASK 0xFFFF800000000000LL +#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type))) +#define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT) + +#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL +#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT +#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED +#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_PTR_PAYLOAD_SET JSVAL_SHIFTED_TAG_MAGIC +#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING + +#endif /* JS_BITS_PER_WORD */ + +typedef enum JSWhyMagic +{ + JS_ARRAY_HOLE, /* a hole in a dense array */ + JS_ARGS_HOLE, /* a hole in the args object's array */ + JS_NATIVE_ENUMERATE, /* indicates that a custom enumerate hook forwarded + * to js_Enumerate, which really means the object can be + * enumerated like a native object. */ + JS_NO_ITER_VALUE, /* there is not a pending iterator value */ + JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */ + JS_NO_CONSTANT, /* compiler sentinel value */ + JS_THIS_POISON, /* used in debug builds to catch tracing errors */ + JS_ARG_POISON, /* used in debug builds to catch tracing errors */ + JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */ + JS_GENERIC_MAGIC /* for local use */ +} JSWhyMagic; + +typedef struct JSString JSString; +typedef struct JSFlatString JSFlatString; +typedef struct JSObject JSObject; + +#if defined(IS_LITTLE_ENDIAN) +# if JS_BITS_PER_WORD == 32 +typedef union jsval_layout +{ + uint64 asBits; + struct { + union { + int32 i32; + uint32 u32; + JSBool boo; + JSString *str; + JSObject *obj; + void *ptr; + JSWhyMagic why; + jsuword word; + } payload; + JSValueTag tag; + } s; + double asDouble; + void *asPtr; +} jsval_layout; +# elif JS_BITS_PER_WORD == 64 +typedef union jsval_layout +{ + uint64 asBits; +#if (!defined(_WIN64) && defined(__cplusplus)) + /* MSVC does not pack these correctly :-( */ + struct { + uint64 payload47 : 47; + JSValueTag tag : 17; + } debugView; +#endif + struct { + union { + int32 i32; + uint32 u32; + JSWhyMagic why; + jsuword word; + } payload; + } s; + double asDouble; + void *asPtr; +} jsval_layout; +# endif /* JS_BITS_PER_WORD */ +#else /* defined(IS_LITTLE_ENDIAN) */ +# if JS_BITS_PER_WORD == 32 +typedef union jsval_layout +{ + uint64 asBits; + struct { + JSValueTag tag; + union { + int32 i32; + uint32 u32; + JSBool boo; + JSString *str; + JSObject *obj; + void *ptr; + JSWhyMagic why; + jsuword word; + } payload; + } s; + double asDouble; + void *asPtr; +} jsval_layout; +# elif JS_BITS_PER_WORD == 64 +typedef union jsval_layout +{ + uint64 asBits; + struct { + JSValueTag tag : 17; + uint64 payload47 : 47; + } debugView; + struct { + union { + int32 i32; + uint32 u32; + JSWhyMagic why; + } payload; + } s; + double asDouble; + void *asPtr; +} jsval_layout; +# endif /* JS_BITS_PER_WORD */ +#endif /* defined(IS_LITTLE_ENDIAN) */ + +#if JS_BITS_PER_WORD == 32 + +/* + * N.B. GCC, in some but not all cases, chooses to emit signed comparison of + * JSValueTag even though its underlying type has been forced to be uint32. + * Thus, all comparisons should explicitly cast operands to uint32. + */ + +#define BUILD_JSVAL(tag, payload) \ + ((((uint64)(uint32)(tag)) << 32) | (uint32)(payload)) + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_DOUBLE_IMPL(jsval_layout l) +{ + return (uint32)l.s.tag <= (uint32)JSVAL_TAG_CLEAR; +} + +static JS_ALWAYS_INLINE jsval_layout +DOUBLE_TO_JSVAL_IMPL(double d) +{ + jsval_layout l; + l.asDouble = d; + JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_INT32_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_INT32; +} + +static JS_ALWAYS_INLINE int32 +JSVAL_TO_INT32_IMPL(jsval_layout l) +{ + return l.s.payload.i32; +} + +static JS_ALWAYS_INLINE jsval_layout +INT32_TO_JSVAL_IMPL(int32 i) +{ + jsval_layout l; + l.s.tag = JSVAL_TAG_INT32; + l.s.payload.i32 = i; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_NUMBER_IMPL(jsval_layout l) +{ + JSValueTag tag = l.s.tag; + JS_ASSERT(tag != JSVAL_TAG_CLEAR); + return (uint32)tag <= (uint32)JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_UNDEFINED; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_STRING_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_STRING; +} + +static JS_ALWAYS_INLINE jsval_layout +STRING_TO_JSVAL_IMPL(JSString *str) +{ + jsval_layout l; + JS_ASSERT(str); + l.s.tag = JSVAL_TAG_STRING; + l.s.payload.str = str; + return l; +} + +static JS_ALWAYS_INLINE JSString * +JSVAL_TO_STRING_IMPL(jsval_layout l) +{ + return l.s.payload.str; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_BOOLEAN; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) +{ + return l.s.payload.boo; +} + +static JS_ALWAYS_INLINE jsval_layout +BOOLEAN_TO_JSVAL_IMPL(JSBool b) +{ + jsval_layout l; + l.s.tag = JSVAL_TAG_BOOLEAN; + l.s.payload.boo = b; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_MAGIC_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_MAGIC; +} + +static JS_ALWAYS_INLINE JSObject * +MAGIC_JSVAL_TO_OBJECT_OR_NULL_IMPL(jsval_layout l) +{ + JS_ASSERT(JSVAL_IS_MAGIC_IMPL(l)); + return l.s.payload.obj; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_OBJECT_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_OBJECT; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) +{ + return (uint32)l.s.tag < (uint32)JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) +{ + JS_ASSERT((uint32)l.s.tag <= (uint32)JSVAL_TAG_OBJECT); + return (uint32)l.s.tag >= (uint32)JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET; +} + +static JS_ALWAYS_INLINE JSObject * +JSVAL_TO_OBJECT_IMPL(jsval_layout l) +{ + return l.s.payload.obj; +} + +static JS_ALWAYS_INLINE jsval_layout +OBJECT_TO_JSVAL_IMPL(JSObject *obj) +{ + jsval_layout l; + JS_ASSERT(obj); + l.s.tag = JSVAL_TAG_OBJECT; + l.s.payload.obj = obj; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_NULL_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_NULL; +} + +static JS_ALWAYS_INLINE jsval_layout +PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr) +{ + jsval_layout l; + JS_ASSERT(((uint32)ptr & 1) == 0); + l.s.tag = (JSValueTag)0; + l.s.payload.ptr = ptr; + JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); + return l; +} + +static JS_ALWAYS_INLINE void * +JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) +{ + return l.s.payload.ptr; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_GCTHING_IMPL(jsval_layout l) +{ + /* gcc sometimes generates signed < without explicit casts. */ + return (uint32)l.s.tag >= (uint32)JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET; +} + +static JS_ALWAYS_INLINE void * +JSVAL_TO_GCTHING_IMPL(jsval_layout l) +{ + return l.s.payload.ptr; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_TRACEABLE_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_STRING || l.s.tag == JSVAL_TAG_OBJECT; +} + +static JS_ALWAYS_INLINE uint32 +JSVAL_TRACE_KIND_IMPL(jsval_layout l) +{ + return (uint32)(JSBool)JSVAL_IS_STRING_IMPL(l); +} + +#elif JS_BITS_PER_WORD == 64 + +#define BUILD_JSVAL(tag, payload) \ + ((((uint64)(uint32)(tag)) << JSVAL_TAG_SHIFT) | (payload)) + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_DOUBLE_IMPL(jsval_layout l) +{ + return l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE; +} + +static JS_ALWAYS_INLINE jsval_layout +DOUBLE_TO_JSVAL_IMPL(double d) +{ + jsval_layout l; + l.asDouble = d; + JS_ASSERT(l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE); + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_INT32_IMPL(jsval_layout l) +{ + return (uint32)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_INT32; +} + +static JS_ALWAYS_INLINE int32 +JSVAL_TO_INT32_IMPL(jsval_layout l) +{ + return (int32)l.asBits; +} + +static JS_ALWAYS_INLINE jsval_layout +INT32_TO_JSVAL_IMPL(int32 i32) +{ + jsval_layout l; + l.asBits = ((uint64)(uint32)i32) | JSVAL_SHIFTED_TAG_INT32; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_NUMBER_IMPL(jsval_layout l) +{ + return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) +{ + return l.asBits == JSVAL_SHIFTED_TAG_UNDEFINED; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_STRING_IMPL(jsval_layout l) +{ + return (uint32)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING; +} + +static JS_ALWAYS_INLINE jsval_layout +STRING_TO_JSVAL_IMPL(JSString *str) +{ + jsval_layout l; + uint64 strBits = (uint64)str; + JS_ASSERT(str); + JS_ASSERT((strBits >> JSVAL_TAG_SHIFT) == 0); + l.asBits = strBits | JSVAL_SHIFTED_TAG_STRING; + return l; +} + +static JS_ALWAYS_INLINE JSString * +JSVAL_TO_STRING_IMPL(jsval_layout l) +{ + return (JSString *)(l.asBits & JSVAL_PAYLOAD_MASK); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) +{ + return (uint32)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) +{ + return (JSBool)l.asBits; +} + +static JS_ALWAYS_INLINE jsval_layout +BOOLEAN_TO_JSVAL_IMPL(JSBool b) +{ + jsval_layout l; + l.asBits = ((uint64)(uint32)b) | JSVAL_SHIFTED_TAG_BOOLEAN; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_MAGIC_IMPL(jsval_layout l) +{ + return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC; +} + +static JS_ALWAYS_INLINE JSObject * +MAGIC_JSVAL_TO_OBJECT_OR_NULL_IMPL(jsval_layout l) +{ + uint64 ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; + JS_ASSERT(JSVAL_IS_MAGIC_IMPL(l)); + JS_ASSERT((ptrBits >> JSVAL_TAG_SHIFT) == 0); + return (JSObject *)ptrBits; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) +{ + return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_OBJECT_IMPL(jsval_layout l) +{ + JS_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_SHIFTED_TAG_OBJECT); + return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) +{ + JS_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); + return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET; +} + +static JS_ALWAYS_INLINE JSObject * +JSVAL_TO_OBJECT_IMPL(jsval_layout l) +{ + uint64 ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; + JS_ASSERT((ptrBits & 0x7) == 0); + return (JSObject *)ptrBits; +} + +static JS_ALWAYS_INLINE jsval_layout +OBJECT_TO_JSVAL_IMPL(JSObject *obj) +{ + jsval_layout l; + uint64 objBits = (uint64)obj; + JS_ASSERT(obj); + JS_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0); + l.asBits = objBits | JSVAL_SHIFTED_TAG_OBJECT; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_NULL_IMPL(jsval_layout l) +{ + return l.asBits == JSVAL_SHIFTED_TAG_NULL; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_GCTHING_IMPL(jsval_layout l) +{ + return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET; +} + +static JS_ALWAYS_INLINE void * +JSVAL_TO_GCTHING_IMPL(jsval_layout l) +{ + uint64 ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; + JS_ASSERT((ptrBits & 0x7) == 0); + return (void *)ptrBits; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_TRACEABLE_IMPL(jsval_layout l) +{ + return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l); +} + +static JS_ALWAYS_INLINE uint32 +JSVAL_TRACE_KIND_IMPL(jsval_layout l) +{ + return (uint32)(JSBool)!(JSVAL_IS_OBJECT_IMPL(l)); +} + +static JS_ALWAYS_INLINE jsval_layout +PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr) +{ + jsval_layout l; + uint64 ptrBits = (uint64)ptr; + JS_ASSERT((ptrBits & 1) == 0); + l.asBits = ptrBits >> 1; + JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); + return l; +} + +static JS_ALWAYS_INLINE void * +JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) +{ + JS_ASSERT((l.asBits & 0x8000000000000000LL) == 0); + return (void *)(l.asBits << 1); +} + +#endif + +static JS_ALWAYS_INLINE double +JS_CANONICALIZE_NAN(double d) +{ + if (JS_UNLIKELY(d != d)) { + jsval_layout l; + l.asBits = 0x7FF8000000000000LL; + return l.asDouble; + } + return d; +} + +/* See JS_USE_JSVAL_JSID_STRUCT_TYPES comment in jsapi.h. */ +#if defined(DEBUG) && !defined(JS_NO_JSVAL_JSID_STRUCT_TYPES) +# define JS_USE_JSVAL_JSID_STRUCT_TYPES +#endif + +#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES + +typedef JSVAL_ALIGNMENT jsval_layout jsval; +typedef struct jsid { size_t asBits; } jsid; + +#if defined(__cplusplus) +extern "C++" +{ + static JS_ALWAYS_INLINE bool + operator==(jsid lhs, jsid rhs) + { + return lhs.asBits == rhs.asBits; + } + + static JS_ALWAYS_INLINE bool + operator!=(jsid lhs, jsid rhs) + { + return lhs.asBits != rhs.asBits; + } + + static JS_ALWAYS_INLINE bool + operator==(jsval lhs, jsval rhs) + { + return lhs.asBits == rhs.asBits; + } + + static JS_ALWAYS_INLINE bool + operator!=(jsval lhs, jsval rhs) + { + return lhs.asBits != rhs.asBits; + } +} +# endif /* defined(__cplusplus) */ + +/* Internal helper macros */ +#define JSVAL_BITS(v) ((v).asBits) +#define JSVAL_FROM_LAYOUT(l) (l) +#define IMPL_TO_JSVAL(v) (v) +#define JSID_BITS(id) ((id).asBits) + +#else /* defined(JS_USE_JSVAL_JSID_STRUCT_TYPES) */ + +/* Use different primitive types so overloading works. */ +typedef JSVAL_ALIGNMENT uint64 jsval; +typedef ptrdiff_t jsid; + +/* Internal helper macros */ +#define JSVAL_BITS(v) (v) +#define JSVAL_FROM_LAYOUT(l) ((l).asBits) +#define IMPL_TO_JSVAL(v) ((v).asBits) +#define JSID_BITS(id) (id) + +#endif /* defined(JS_USE_JSVAL_JSID_STRUCT_TYPES) */ + +JS_END_EXTERN_C + +#endif /* jsvalimpl_h__ */ diff --git a/js/src/jsvalue.h b/js/src/jsvalue.h new file mode 100644 index 0000000..7baa2c4 --- /dev/null +++ b/js/src/jsvalue.h @@ -0,0 +1,1239 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * June 30, 2010 + * + * The Initial Developer of the Original Code is + * the Mozilla Corporation. + * + * Contributor(s): + * Luke Wagner + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsvalue_h__ +#define jsvalue_h__ +/* + * Private value interface. + */ +#include "jsprvtd.h" +#include "jsstdint.h" + +/* + * js::Value is a C++-ified version of jsval that provides more information and + * helper functions than the basic jsval interface exposed by jsapi.h. A few + * general notes on js::Value: + * + * - Since js::Value and jsval have the same representation, values of these + * types, function pointer types differing only in these types, and structs + * differing only in these types can be converted back and forth at no cost + * using the Jsvalify() and Valueify(). See Jsvalify comment below. + * + * - js::Value has setX() and isX() members for X in + * + * { Int32, Double, String, Boolean, Undefined, Null, Object, Magic } + * + * js::Value also contains toX() for each of the non-singleton types. + * + * - Magic is a singleton type whose payload contains a JSWhyMagic "reason" for + * the magic value. By providing JSWhyMagic values when creating and checking + * for magic values, it is possible to assert, at runtime, that only magic + * values with the expected reason flow through a particular value. For + * example, if cx->exception has a magic value, the reason must be + * JS_GENERATOR_CLOSING. + * + * - A key difference between jsval and js::Value is that js::Value gives null + * a separate type. Thus + * + * JSVAL_IS_OBJECT(v) === v.isObjectOrNull() + * !JSVAL_IS_PRIMITIVE(v) === v.isObject() + * + * To help prevent mistakenly boxing a nullable JSObject* as an object, + * Value::setObject takes a JSObject&. (Conversely, Value::asObject returns a + * JSObject&. A convenience member Value::setObjectOrNull is provided. + * + * - JSVAL_VOID is the same as the singleton value of the Undefined type. + * + * - Note that js::Value is always 64-bit. Thus, on 32-bit user code should + * avoid copying jsval/js::Value as much as possible, preferring to pass by + * const Value &. + */ + +/******************************************************************************/ + +/* To avoid a circular dependency, pull in the necessary pieces of jsnum.h. */ + +#include +#if defined(XP_WIN) || defined(XP_OS2) +#include +#endif +#ifdef SOLARIS +#include +#endif + +static inline int +JSDOUBLE_IS_NEGZERO(jsdouble d) +{ +#ifdef WIN32 + return (d == 0 && (_fpclass(d) & _FPCLASS_NZ)); +#elif defined(SOLARIS) + return (d == 0 && copysign(1, d) < 0); +#else + return (d == 0 && signbit(d)); +#endif +} + +static inline bool +JSDOUBLE_IS_INT32(jsdouble d, int32_t* pi) +{ + if (JSDOUBLE_IS_NEGZERO(d)) + return false; + return d == (*pi = int32_t(d)); +} + +/******************************************************************************/ + +/* Additional value operations used in js::Value but not in jsapi.h. */ + +#if JS_BITS_PER_WORD == 32 + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32 i32) +{ + return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b) +{ + return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == b); +} + +static JS_ALWAYS_INLINE jsval_layout +MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) +{ + jsval_layout l; + l.s.tag = JSVAL_TAG_MAGIC; + l.s.payload.why = why; + return l; +} + +static JS_ALWAYS_INLINE jsval_layout +MAGIC_TO_JSVAL_IMPL(JSObject *obj) +{ + jsval_layout l; + l.s.tag = JSVAL_TAG_MAGIC; + l.s.payload.obj = obj; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) +{ + JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag; + return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR); +} + +static JS_ALWAYS_INLINE jsval_layout +PRIVATE_UINT32_TO_JSVAL_IMPL(uint32 ui) +{ + jsval_layout l; + l.s.tag = (JSValueTag)0; + l.s.payload.u32 = ui; + JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); + return l; +} + +static JS_ALWAYS_INLINE uint32 +JSVAL_TO_PRIVATE_UINT32_IMPL(jsval_layout l) +{ + return l.s.payload.u32; +} + +static JS_ALWAYS_INLINE JSValueType +JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) +{ + uint32 type = l.s.tag & 0xF; + JS_ASSERT(type > JSVAL_TYPE_DOUBLE); + return (JSValueType)type; +} + +static JS_ALWAYS_INLINE JSValueTag +JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(jsval_layout l) +{ + JSValueTag tag = l.s.tag; + JS_ASSERT(tag >= JSVAL_TAG_INT32); + return tag; +} + +#ifdef __cplusplus +JS_STATIC_ASSERT((JSVAL_TYPE_NONFUNOBJ & 0xF) == JSVAL_TYPE_OBJECT); +JS_STATIC_ASSERT((JSVAL_TYPE_FUNOBJ & 0xF) == JSVAL_TYPE_OBJECT); +#endif + +static JS_ALWAYS_INLINE jsval_layout +BOX_NON_DOUBLE_JSVAL(JSValueType type, uint64 *slot) +{ + jsval_layout l; + JS_ASSERT(type > JSVAL_TYPE_DOUBLE && type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET); + JS_ASSERT_IF(type == JSVAL_TYPE_STRING || + type == JSVAL_TYPE_OBJECT || + type == JSVAL_TYPE_NONFUNOBJ || + type == JSVAL_TYPE_FUNOBJ, + *(uint32 *)slot != 0); + l.s.tag = JSVAL_TYPE_TO_TAG(type & 0xF); + /* A 32-bit value in a 64-bit slot always occupies the low-addressed end. */ + l.s.payload.u32 = *(uint32 *)slot; + return l; +} + +static JS_ALWAYS_INLINE void +UNBOX_NON_DOUBLE_JSVAL(jsval_layout l, uint64 *out) +{ + JS_ASSERT(!JSVAL_IS_DOUBLE_IMPL(l)); + *(uint32 *)out = l.s.payload.u32; +} + +#elif JS_BITS_PER_WORD == 64 + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32 i32) +{ + return l.asBits == (((uint64)(uint32)i32) | JSVAL_SHIFTED_TAG_INT32); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b) +{ + return l.asBits == (((uint64)(uint32)b) | JSVAL_SHIFTED_TAG_BOOLEAN); +} + +static JS_ALWAYS_INLINE jsval_layout +MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) +{ + jsval_layout l; + l.asBits = ((uint64)(uint32)why) | JSVAL_SHIFTED_TAG_MAGIC; + return l; +} + +static JS_ALWAYS_INLINE jsval_layout +MAGIC_TO_JSVAL_IMPL(JSObject *obj) +{ + jsval_layout l; + l.asBits = ((uint64)obj) | JSVAL_SHIFTED_TAG_MAGIC; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) +{ + uint64 lbits = lhs.asBits, rbits = rhs.asBits; + return (lbits <= JSVAL_TAG_MAX_DOUBLE && rbits <= JSVAL_TAG_MAX_DOUBLE) || + (((lbits ^ rbits) & 0xFFFF800000000000LL) == 0); +} + +static JS_ALWAYS_INLINE jsval_layout +PRIVATE_UINT32_TO_JSVAL_IMPL(uint32 ui) +{ + jsval_layout l; + l.asBits = (uint64)ui; + JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); + return l; +} + +static JS_ALWAYS_INLINE uint32 +JSVAL_TO_PRIVATE_UINT32_IMPL(jsval_layout l) +{ + JS_ASSERT((l.asBits >> 32) == 0); + return (uint32)l.asBits; +} + +static JS_ALWAYS_INLINE JSValueType +JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) +{ + uint64 type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF; + JS_ASSERT(type > JSVAL_TYPE_DOUBLE); + return (JSValueType)type; +} + +static JS_ALWAYS_INLINE JSValueTag +JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(jsval_layout l) +{ + uint64 tag = l.asBits >> JSVAL_TAG_SHIFT; + JS_ASSERT(tag > JSVAL_TAG_MAX_DOUBLE); + return (JSValueTag)tag; +} + +#ifdef __cplusplus +JS_STATIC_ASSERT(offsetof(jsval_layout, s.payload) == 0); +JS_STATIC_ASSERT((JSVAL_TYPE_NONFUNOBJ & 0xF) == JSVAL_TYPE_OBJECT); +JS_STATIC_ASSERT((JSVAL_TYPE_FUNOBJ & 0xF) == JSVAL_TYPE_OBJECT); +#endif + +static JS_ALWAYS_INLINE jsval_layout +BOX_NON_DOUBLE_JSVAL(JSValueType type, uint64 *slot) +{ + /* N.B. for 32-bit payloads, the high 32 bits of the slot are trash. */ + jsval_layout l; + JS_ASSERT(type > JSVAL_TYPE_DOUBLE && type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET); + uint32 isI32 = (uint32)(type < JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET); + uint32 shift = isI32 * 32; + uint64 mask = ((uint64)-1) >> shift; + uint64 payload = *slot & mask; + JS_ASSERT_IF(type == JSVAL_TYPE_STRING || + type == JSVAL_TYPE_OBJECT || + type == JSVAL_TYPE_NONFUNOBJ || + type == JSVAL_TYPE_FUNOBJ, + payload != 0); + l.asBits = payload | JSVAL_TYPE_TO_SHIFTED_TAG(type & 0xF); + return l; +} + +static JS_ALWAYS_INLINE void +UNBOX_NON_DOUBLE_JSVAL(jsval_layout l, uint64 *out) +{ + JS_ASSERT(!JSVAL_IS_DOUBLE_IMPL(l)); + *out = (l.asBits & JSVAL_PAYLOAD_MASK); +} + +#endif + +/******************************************************************************/ + +namespace js { + +class Value +{ + public: + /* + * N.B. the default constructor leaves Value unitialized. Adding a default + * constructor prevents Value from being stored in a union. + */ + + /*** Mutatators ***/ + + JS_ALWAYS_INLINE + void setNull() { + data.asBits = JSVAL_BITS(JSVAL_NULL); + } + + JS_ALWAYS_INLINE + void setUndefined() { + data.asBits = JSVAL_BITS(JSVAL_VOID); + } + + JS_ALWAYS_INLINE + void setInt32(int32 i) { + data = INT32_TO_JSVAL_IMPL(i); + } + + JS_ALWAYS_INLINE + int32 &getInt32Ref() { + JS_ASSERT(isInt32()); + return data.s.payload.i32; + } + + JS_ALWAYS_INLINE + void setDouble(double d) { + data = DOUBLE_TO_JSVAL_IMPL(d); + } + + JS_ALWAYS_INLINE + double &getDoubleRef() { + JS_ASSERT(isDouble()); + return data.asDouble; + } + + JS_ALWAYS_INLINE + void setString(JSString *str) { + data = STRING_TO_JSVAL_IMPL(str); + } + + JS_ALWAYS_INLINE + void setObject(JSObject &obj) { + data = OBJECT_TO_JSVAL_IMPL(&obj); + } + + JS_ALWAYS_INLINE + void setBoolean(bool b) { + data = BOOLEAN_TO_JSVAL_IMPL(b); + } + + JS_ALWAYS_INLINE + void setMagic(JSWhyMagic why) { + data = MAGIC_TO_JSVAL_IMPL(why); + } + + JS_ALWAYS_INLINE + void setMagicWithObjectOrNullPayload(JSObject *obj) { + data = MAGIC_TO_JSVAL_IMPL(obj); + } + + JS_ALWAYS_INLINE + JSObject *getMagicObjectOrNullPayload() const { + return MAGIC_JSVAL_TO_OBJECT_OR_NULL_IMPL(data); + } + + JS_ALWAYS_INLINE + void setNumber(uint32 ui) { + if (ui > JSVAL_INT_MAX) + setDouble((double)ui); + else + setInt32((int32)ui); + } + + JS_ALWAYS_INLINE + void setNumber(double d) { + int32_t i; + if (JSDOUBLE_IS_INT32(d, &i)) + setInt32(i); + else + setDouble(d); + } + + JS_ALWAYS_INLINE + void setObjectOrNull(JSObject *arg) { + if (arg) + setObject(*arg); + else + setNull(); + } + + JS_ALWAYS_INLINE + void setObjectOrUndefined(JSObject *arg) { + if (arg) + setObject(*arg); + else + setUndefined(); + } + + JS_ALWAYS_INLINE + void swap(Value &rhs) { + uint64 tmp = rhs.data.asBits; + rhs.data.asBits = data.asBits; + data.asBits = tmp; + } + + /*** Value type queries ***/ + + JS_ALWAYS_INLINE + bool isUndefined() const { + return JSVAL_IS_UNDEFINED_IMPL(data); + } + + JS_ALWAYS_INLINE + bool isNull() const { + return JSVAL_IS_NULL_IMPL(data); + } + + JS_ALWAYS_INLINE + bool isNullOrUndefined() const { + return isNull() || isUndefined(); + } + + JS_ALWAYS_INLINE + bool isInt32() const { + return JSVAL_IS_INT32_IMPL(data); + } + + JS_ALWAYS_INLINE + bool isInt32(int32 i32) const { + return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32); + } + + JS_ALWAYS_INLINE + bool isDouble() const { + return JSVAL_IS_DOUBLE_IMPL(data); + } + + JS_ALWAYS_INLINE + bool isNumber() const { + return JSVAL_IS_NUMBER_IMPL(data); + } + + JS_ALWAYS_INLINE + bool isString() const { + return JSVAL_IS_STRING_IMPL(data); + } + + JS_ALWAYS_INLINE + bool isObject() const { + return JSVAL_IS_OBJECT_IMPL(data); + } + + JS_ALWAYS_INLINE + bool isPrimitive() const { + return JSVAL_IS_PRIMITIVE_IMPL(data); + } + + JS_ALWAYS_INLINE + bool isObjectOrNull() const { + return JSVAL_IS_OBJECT_OR_NULL_IMPL(data); + } + + JS_ALWAYS_INLINE + bool isGCThing() const { + return JSVAL_IS_GCTHING_IMPL(data); + } + + JS_ALWAYS_INLINE + bool isBoolean() const { + return JSVAL_IS_BOOLEAN_IMPL(data); + } + + JS_ALWAYS_INLINE + bool isTrue() const { + return JSVAL_IS_SPECIFIC_BOOLEAN(data, true); + } + + JS_ALWAYS_INLINE + bool isFalse() const { + return JSVAL_IS_SPECIFIC_BOOLEAN(data, false); + } + + JS_ALWAYS_INLINE + bool isMagic() const { + return JSVAL_IS_MAGIC_IMPL(data); + } + + JS_ALWAYS_INLINE + bool isMagic(JSWhyMagic why) const { + JS_ASSERT_IF(isMagic(), data.s.payload.why == why); + return JSVAL_IS_MAGIC_IMPL(data); + } + +#if JS_BITS_PER_WORD == 64 + JS_ALWAYS_INLINE + bool hasPtrPayload() const { + return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_PTR_PAYLOAD_SET; + } +#endif + + JS_ALWAYS_INLINE + bool isMarkable() const { + return JSVAL_IS_TRACEABLE_IMPL(data); + } + + JS_ALWAYS_INLINE + int32 gcKind() const { + JS_ASSERT(isMarkable()); + return JSVAL_TRACE_KIND_IMPL(data); + } + +#ifdef DEBUG + JS_ALWAYS_INLINE + JSWhyMagic whyMagic() const { + JS_ASSERT(isMagic()); + return data.s.payload.why; + } +#endif + + /*** Comparison ***/ + + JS_ALWAYS_INLINE + bool operator==(const Value &rhs) const { + return data.asBits == rhs.data.asBits; + } + + JS_ALWAYS_INLINE + bool operator!=(const Value &rhs) const { + return data.asBits != rhs.data.asBits; + } + + /* This function used to be inlined here, but this triggered a gcc bug + due to SameType being used in a template method. + See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38850 */ + friend bool SameType(const Value &lhs, const Value &rhs); + + /*** Extract the value's typed payload ***/ + + JS_ALWAYS_INLINE + int32 toInt32() const { + JS_ASSERT(isInt32()); + return JSVAL_TO_INT32_IMPL(data); + } + + JS_ALWAYS_INLINE + double toDouble() const { + JS_ASSERT(isDouble()); + return data.asDouble; + } + + JS_ALWAYS_INLINE + double toNumber() const { + JS_ASSERT(isNumber()); + return isDouble() ? toDouble() : double(toInt32()); + } + + JS_ALWAYS_INLINE + JSString *toString() const { + JS_ASSERT(isString()); + return JSVAL_TO_STRING_IMPL(data); + } + + JS_ALWAYS_INLINE + JSObject &toObject() const { + JS_ASSERT(isObject()); + return *JSVAL_TO_OBJECT_IMPL(data); + } + + JS_ALWAYS_INLINE + JSObject *toObjectOrNull() const { + JS_ASSERT(isObjectOrNull()); + return JSVAL_TO_OBJECT_IMPL(data); + } + + JS_ALWAYS_INLINE + void *toGCThing() const { + JS_ASSERT(isGCThing()); + return JSVAL_TO_GCTHING_IMPL(data); + } + + JS_ALWAYS_INLINE + bool toBoolean() const { + JS_ASSERT(isBoolean()); + return JSVAL_TO_BOOLEAN_IMPL(data); + } + + JS_ALWAYS_INLINE + uint32 payloadAsRawUint32() const { + JS_ASSERT(!isDouble()); + return data.s.payload.u32; + } + + JS_ALWAYS_INLINE + uint64 asRawBits() const { + return data.asBits; + } + + /* + * In the extract/box/unbox functions below, "NonDouble" means this + * functions must not be called on a value that is a double. This allows + * these operations to be implemented more efficiently, since doubles + * generally already require special handling by the caller. + */ + JS_ALWAYS_INLINE + JSValueType extractNonDoubleType() const { + return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data); + } + + JS_ALWAYS_INLINE + JSValueTag extractNonDoubleTag() const { + return JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(data); + } + + JS_ALWAYS_INLINE + void unboxNonDoubleTo(uint64 *out) const { + UNBOX_NON_DOUBLE_JSVAL(data, out); + } + + JS_ALWAYS_INLINE + void boxNonDoubleFrom(JSValueType type, uint64 *out) { + data = BOX_NON_DOUBLE_JSVAL(type, out); + } + + /* + * The trace-jit specializes JSVAL_TYPE_OBJECT into JSVAL_TYPE_FUNOBJ and + * JSVAL_TYPE_NONFUNOBJ. Since these two operations just return the type of + * a value, the caller must handle JSVAL_TYPE_OBJECT separately. + */ + JS_ALWAYS_INLINE + JSValueType extractNonDoubleObjectTraceType() const { + JS_ASSERT(!isObject()); + return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data); + } + + JS_ALWAYS_INLINE + JSValueTag extractNonDoubleObjectTraceTag() const { + JS_ASSERT(!isObject()); + return JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(data); + } + + /* + * Private API + * + * Private setters/getters allow the caller to read/write arbitrary types + * that fit in the 64-bit payload. It is the caller's responsibility, after + * storing to a value with setPrivateX to read only using getPrivateX. + * Privates values are given a type type which ensures they are not marked. + */ + + JS_ALWAYS_INLINE + void setPrivate(void *ptr) { + data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr); + } + + JS_ALWAYS_INLINE + void *toPrivate() const { + JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(data)); + return JSVAL_TO_PRIVATE_PTR_IMPL(data); + } + + JS_ALWAYS_INLINE + void setPrivateUint32(uint32 ui) { + data = PRIVATE_UINT32_TO_JSVAL_IMPL(ui); + } + + JS_ALWAYS_INLINE + uint32 toPrivateUint32() const { + JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(data)); + return JSVAL_TO_PRIVATE_UINT32_IMPL(data); + } + + JS_ALWAYS_INLINE + uint32 &getPrivateUint32Ref() { + JS_ASSERT(isDouble()); + return data.s.payload.u32; + } + + /* + * An unmarked value is just a void* cast as a Value. Thus, the Value is + * not safe for GC and must not be marked. This API avoids raw casts + * and the ensuing strict-aliasing warnings. + */ + + JS_ALWAYS_INLINE + void setUnmarkedPtr(void *ptr) { + data.asPtr = ptr; + } + + JS_ALWAYS_INLINE + void *toUnmarkedPtr() const { + return data.asPtr; + } + + const jsuword *payloadWord() const { + return &data.s.payload.word; + } + + private: + void staticAssertions() { + JS_STATIC_ASSERT(sizeof(JSValueType) == 1); + JS_STATIC_ASSERT(sizeof(JSValueTag) == 4); + JS_STATIC_ASSERT(sizeof(JSBool) == 4); + JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4); + JS_STATIC_ASSERT(sizeof(jsval) == 8); + } + + jsval_layout data; +} JSVAL_ALIGNMENT; + +JS_ALWAYS_INLINE bool +SameType(const Value &lhs, const Value &rhs) +{ + return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data); +} + +static JS_ALWAYS_INLINE Value +NullValue() +{ + Value v; + v.setNull(); + return v; +} + +static JS_ALWAYS_INLINE Value +UndefinedValue() +{ + Value v; + v.setUndefined(); + return v; +} + +static JS_ALWAYS_INLINE Value +Int32Value(int32 i32) +{ + Value v; + v.setInt32(i32); + return v; +} + +static JS_ALWAYS_INLINE Value +DoubleValue(double dbl) +{ + Value v; + v.setDouble(dbl); + return v; +} + +static JS_ALWAYS_INLINE Value +StringValue(JSString *str) +{ + Value v; + v.setString(str); + return v; +} + +static JS_ALWAYS_INLINE Value +BooleanValue(bool boo) +{ + Value v; + v.setBoolean(boo); + return v; +} + +static JS_ALWAYS_INLINE Value +ObjectValue(JSObject &obj) +{ + Value v; + v.setObject(obj); + return v; +} + +static JS_ALWAYS_INLINE Value +MagicValue(JSWhyMagic why) +{ + Value v; + v.setMagic(why); + return v; +} + +static JS_ALWAYS_INLINE Value +NumberValue(double dbl) +{ + Value v; + v.setNumber(dbl); + return v; +} + +static JS_ALWAYS_INLINE Value +ObjectOrNullValue(JSObject *obj) +{ + Value v; + v.setObjectOrNull(obj); + return v; +} + +static JS_ALWAYS_INLINE Value +PrivateValue(void *ptr) +{ + Value v; + v.setPrivate(ptr); + return v; +} + +static JS_ALWAYS_INLINE void +ClearValueRange(Value *vec, uintN len, bool useHoles) +{ + if (useHoles) { + for (uintN i = 0; i < len; i++) + vec[i].setMagic(JS_ARRAY_HOLE); + } else { + for (uintN i = 0; i < len; i++) + vec[i].setUndefined(); + } +} + +/******************************************************************************/ + +/* + * As asserted above, js::Value and jsval are layout equivalent. This means: + * - an instance of jsval may be reinterpreted as a js::Value and vice versa; + * - a pointer to a function taking jsval arguments may be reinterpreted as a + * function taking the same arguments, s/jsval/js::Value/, and vice versa; + * - a struct containing jsval members may be reinterpreted as a struct with + * the same members, s/jsval/js::Value/, and vice versa. + * + * To prevent widespread conversion using casts, which would effectively + * disable the C++ typesystem in places where we want it, a set of safe + * conversions between known-equivalent types is provided below. Given a type + * JsvalT expressedin terms of jsval and an equivalent type ValueT expressed in + * terms of js::Value, instances may be converted back and forth using: + * + * JsvalT *x = ... + * ValueT *y = js::Valueify(x); + * JsvalT *z = js::Jsvalify(y); + * assert(x == z); + * + * Conversions between references is also provided for some types. If it seems + * like a cast is needed to convert between jsval/js::Value, consider adding a + * new safe overload to Jsvalify/Valueify. + */ + +static inline jsval * Jsvalify(Value *v) { return (jsval *)v; } +static inline const jsval * Jsvalify(const Value *v) { return (const jsval *)v; } +static inline jsval & Jsvalify(Value &v) { return (jsval &)v; } +static inline const jsval & Jsvalify(const Value &v) { return (const jsval &)v; } +static inline Value * Valueify(jsval *v) { return (Value *)v; } +static inline const Value * Valueify(const jsval *v) { return (const Value *)v; } +static inline Value ** Valueify(jsval **v) { return (Value **)v; } +static inline Value & Valueify(jsval &v) { return (Value &)v; } +static inline const Value & Valueify(const jsval &v) { return (const Value &)v; } + +struct Class; + +typedef JSBool +(* Native)(JSContext *cx, uintN argc, Value *vp); +typedef JSBool +(* PropertyOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp); +typedef JSBool +(* StrictPropertyOp)(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp); +typedef JSBool +(* ConvertOp)(JSContext *cx, JSObject *obj, JSType type, Value *vp); +typedef JSBool +(* NewEnumerateOp)(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + Value *statep, jsid *idp); +typedef JSBool +(* HasInstanceOp)(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp); +typedef JSBool +(* CheckAccessOp)(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, + Value *vp); +typedef JSBool +(* EqualityOp)(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp); +typedef JSBool +(* DefinePropOp)(JSContext *cx, JSObject *obj, jsid id, const Value *value, + PropertyOp getter, StrictPropertyOp setter, uintN attrs); +typedef JSBool +(* PropertyIdOp)(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp); +typedef JSBool +(* StrictPropertyIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict); +typedef JSBool +(* DeleteIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict); +typedef JSBool +(* CallOp)(JSContext *cx, uintN argc, Value *vp); +typedef JSBool +(* LookupPropOp)(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + JSProperty **propp); +typedef JSBool +(* AttributesOp)(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); +typedef JSType +(* TypeOfOp)(JSContext *cx, JSObject *obj); +typedef void +(* TraceOp)(JSTracer *trc, JSObject *obj); +typedef JSObject * +(* ObjectOp)(JSContext *cx, JSObject *obj); +typedef void +(* FinalizeOp)(JSContext *cx, JSObject *obj); + +class AutoIdVector; + +/* + * Prepare to make |obj| non-extensible; in particular, fully resolve its properties. + * On error, return false. + * If |obj| is now ready to become non-extensible, set |*fixed| to true and return true. + * If |obj| refuses to become non-extensible, set |*fixed| to false and return true; the + * caller will throw an appropriate error. + */ +typedef JSBool +(* FixOp)(JSContext *cx, JSObject *obj, bool *fixed, AutoIdVector *props); + +static inline Native Valueify(JSNative f) { return (Native)f; } +static inline JSNative Jsvalify(Native f) { return (JSNative)f; } +static inline PropertyOp Valueify(JSPropertyOp f) { return (PropertyOp)f; } +static inline JSPropertyOp Jsvalify(PropertyOp f) { return (JSPropertyOp)f; } +static inline StrictPropertyOp Valueify(JSStrictPropertyOp f) { return (StrictPropertyOp)f; } +static inline JSStrictPropertyOp Jsvalify(StrictPropertyOp f) { return (JSStrictPropertyOp)f; } +static inline ConvertOp Valueify(JSConvertOp f) { return (ConvertOp)f; } +static inline JSConvertOp Jsvalify(ConvertOp f) { return (JSConvertOp)f; } +static inline NewEnumerateOp Valueify(JSNewEnumerateOp f) { return (NewEnumerateOp)f; } +static inline JSNewEnumerateOp Jsvalify(NewEnumerateOp f) { return (JSNewEnumerateOp)f; } +static inline HasInstanceOp Valueify(JSHasInstanceOp f) { return (HasInstanceOp)f; } +static inline JSHasInstanceOp Jsvalify(HasInstanceOp f) { return (JSHasInstanceOp)f; } +static inline CheckAccessOp Valueify(JSCheckAccessOp f) { return (CheckAccessOp)f; } +static inline JSCheckAccessOp Jsvalify(CheckAccessOp f) { return (JSCheckAccessOp)f; } +static inline EqualityOp Valueify(JSEqualityOp f); /* Same type as JSHasInstanceOp */ +static inline JSEqualityOp Jsvalify(EqualityOp f); /* Same type as HasInstanceOp */ + +static const PropertyOp PropertyStub = (PropertyOp)JS_PropertyStub; +static const StrictPropertyOp StrictPropertyStub = (StrictPropertyOp)JS_StrictPropertyStub; +static const JSEnumerateOp EnumerateStub = JS_EnumerateStub; +static const JSResolveOp ResolveStub = JS_ResolveStub; +static const ConvertOp ConvertStub = (ConvertOp)JS_ConvertStub; +static const JSFinalizeOp FinalizeStub = JS_FinalizeStub; + +#define JS_CLASS_MEMBERS \ + const char *name; \ + uint32 flags; \ + \ + /* Mandatory non-null function pointer members. */ \ + PropertyOp addProperty; \ + PropertyOp delProperty; \ + PropertyOp getProperty; \ + StrictPropertyOp setProperty; \ + JSEnumerateOp enumerate; \ + JSResolveOp resolve; \ + ConvertOp convert; \ + JSFinalizeOp finalize; \ + \ + /* Optionally non-null members start here. */ \ + JSClassInternal reserved0; \ + CheckAccessOp checkAccess; \ + Native call; \ + Native construct; \ + JSXDRObjectOp xdrObject; \ + HasInstanceOp hasInstance; \ + JSMarkOp mark + + +/* + * The helper struct to measure the size of JS_CLASS_MEMBERS to know how much + * we have to padd js::Class to match the size of JSClass; + */ +struct ClassSizeMeasurement { + JS_CLASS_MEMBERS; +}; + +struct ClassExtension { + EqualityOp equality; + JSObjectOp outerObject; + JSObjectOp innerObject; + JSIteratorOp iteratorObject; + void *unused; +}; + +#define JS_NULL_CLASS_EXT {NULL,NULL,NULL,NULL,NULL} + +struct ObjectOps { + js::LookupPropOp lookupProperty; + js::DefinePropOp defineProperty; + js::PropertyIdOp getProperty; + js::StrictPropertyIdOp setProperty; + js::AttributesOp getAttributes; + js::AttributesOp setAttributes; + js::DeleteIdOp deleteProperty; + js::NewEnumerateOp enumerate; + js::TypeOfOp typeOf; + js::TraceOp trace; + js::FixOp fix; + js::ObjectOp thisObject; + js::FinalizeOp clear; +}; + +#define JS_NULL_OBJECT_OPS {NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL} + +struct Class { + JS_CLASS_MEMBERS; + ClassExtension ext; + ObjectOps ops; + uint8 pad[sizeof(JSClass) - sizeof(ClassSizeMeasurement) - + sizeof(ClassExtension) - sizeof(ObjectOps)]; + + /* Class is not native and its map is not a scope. */ + static const uint32 NON_NATIVE = JSCLASS_INTERNAL_FLAG2; + + bool isNative() const { + return !(flags & NON_NATIVE); + } +}; + +JS_STATIC_ASSERT(offsetof(JSClass, name) == offsetof(Class, name)); +JS_STATIC_ASSERT(offsetof(JSClass, flags) == offsetof(Class, flags)); +JS_STATIC_ASSERT(offsetof(JSClass, addProperty) == offsetof(Class, addProperty)); +JS_STATIC_ASSERT(offsetof(JSClass, delProperty) == offsetof(Class, delProperty)); +JS_STATIC_ASSERT(offsetof(JSClass, getProperty) == offsetof(Class, getProperty)); +JS_STATIC_ASSERT(offsetof(JSClass, setProperty) == offsetof(Class, setProperty)); +JS_STATIC_ASSERT(offsetof(JSClass, enumerate) == offsetof(Class, enumerate)); +JS_STATIC_ASSERT(offsetof(JSClass, resolve) == offsetof(Class, resolve)); +JS_STATIC_ASSERT(offsetof(JSClass, convert) == offsetof(Class, convert)); +JS_STATIC_ASSERT(offsetof(JSClass, finalize) == offsetof(Class, finalize)); +JS_STATIC_ASSERT(offsetof(JSClass, reserved0) == offsetof(Class, reserved0)); +JS_STATIC_ASSERT(offsetof(JSClass, checkAccess) == offsetof(Class, checkAccess)); +JS_STATIC_ASSERT(offsetof(JSClass, call) == offsetof(Class, call)); +JS_STATIC_ASSERT(offsetof(JSClass, construct) == offsetof(Class, construct)); +JS_STATIC_ASSERT(offsetof(JSClass, xdrObject) == offsetof(Class, xdrObject)); +JS_STATIC_ASSERT(offsetof(JSClass, hasInstance) == offsetof(Class, hasInstance)); +JS_STATIC_ASSERT(offsetof(JSClass, mark) == offsetof(Class, mark)); +JS_STATIC_ASSERT(sizeof(JSClass) == sizeof(Class)); + +struct PropertyDescriptor { + JSObject *obj; + uintN attrs; + PropertyOp getter; + StrictPropertyOp setter; + Value value; + uintN shortid; +}; +JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, obj) == offsetof(PropertyDescriptor, obj)); +JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, attrs) == offsetof(PropertyDescriptor, attrs)); +JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, getter) == offsetof(PropertyDescriptor, getter)); +JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, setter) == offsetof(PropertyDescriptor, setter)); +JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, value) == offsetof(PropertyDescriptor, value)); +JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, shortid) == offsetof(PropertyDescriptor, shortid)); +JS_STATIC_ASSERT(sizeof(JSPropertyDescriptor) == sizeof(PropertyDescriptor)); + +static JS_ALWAYS_INLINE JSClass * Jsvalify(Class *c) { return (JSClass *)c; } +static JS_ALWAYS_INLINE Class * Valueify(JSClass *c) { return (Class *)c; } +static JS_ALWAYS_INLINE JSPropertyDescriptor * Jsvalify(PropertyDescriptor *p) { return (JSPropertyDescriptor *) p; } +static JS_ALWAYS_INLINE PropertyDescriptor * Valueify(JSPropertyDescriptor *p) { return (PropertyDescriptor *) p; } + +/******************************************************************************/ + +/* + * Any cast-via-function-call, inlined or not, will cause initialization to + * happen at startup, rather than statically, so just cast in release builds. + */ +#ifdef DEBUG + +# define JS_VALUEIFY(type, v) js::Valueify(v) +# define JS_JSVALIFY(type, v) js::Jsvalify(v) + +static inline JSNative JsvalifyNative(Native n) { return (JSNative)n; } +static inline JSNative JsvalifyNative(JSNative n) { return n; } +static inline Native ValueifyNative(JSNative n) { return (Native)n; } +static inline Native ValueifyNative(Native n) { return n; } + +# define JS_VALUEIFY_NATIVE(n) js::ValueifyNative(n) +# define JS_JSVALIFY_NATIVE(n) js::JsvalifyNative(n) + +#else + +# define JS_VALUEIFY(type, v) ((type)(v)) +# define JS_JSVALIFY(type, v) ((type)(v)) + +# define JS_VALUEIFY_NATIVE(n) ((js::Native)(n)) +# define JS_JSVALIFY_NATIVE(n) ((JSNative)(n)) + +#endif + +/* + * JSFunctionSpec uses JSAPI jsval in function signatures whereas the engine + * uses js::Value. To avoid widespread (JSNative) casting, have JS_FN perfom a + * type-safe cast. + */ +#undef JS_FN +#define JS_FN(name,call,nargs,flags) \ + {name, JS_JSVALIFY_NATIVE(call), nargs, (flags) | JSFUN_STUB_GSOPS} + +/******************************************************************************/ + +/* + * In some cases (quickstubs) we want to take a value in whatever manner is + * appropriate for the architecture and normalize to a const js::Value &. On + * x64, passing a js::Value may cause the to unnecessarily be passed through + * memory instead of registers, so jsval, which is a builtin uint64 is used. + */ +#if JS_BITS_PER_WORD == 32 +typedef const js::Value *ValueArgType; + +static JS_ALWAYS_INLINE const js::Value & +ValueArgToConstRef(const js::Value *arg) +{ + return *arg; +} + +#elif JS_BITS_PER_WORD == 64 +typedef js::Value ValueArgType; + +static JS_ALWAYS_INLINE const Value & +ValueArgToConstRef(const Value &v) +{ + return v; +} +#endif + +/******************************************************************************/ + +static JS_ALWAYS_INLINE void +MakeRangeGCSafe(Value *vec, size_t len) +{ + PodZero(vec, len); +} + +static JS_ALWAYS_INLINE void +MakeRangeGCSafe(Value *beg, Value *end) +{ + PodZero(beg, end - beg); +} + +static JS_ALWAYS_INLINE void +MakeRangeGCSafe(jsid *beg, jsid *end) +{ + for (jsid *id = beg; id != end; ++id) + *id = INT_TO_JSID(0); +} + +static JS_ALWAYS_INLINE void +MakeRangeGCSafe(jsid *vec, size_t len) +{ + MakeRangeGCSafe(vec, vec + len); +} + +static JS_ALWAYS_INLINE void +MakeRangeGCSafe(const Shape **beg, const Shape **end) +{ + PodZero(beg, end - beg); +} + +static JS_ALWAYS_INLINE void +MakeRangeGCSafe(const Shape **vec, size_t len) +{ + PodZero(vec, len); +} + +static JS_ALWAYS_INLINE void +SetValueRangeToUndefined(Value *beg, Value *end) +{ + for (Value *v = beg; v != end; ++v) + v->setUndefined(); +} + +static JS_ALWAYS_INLINE void +SetValueRangeToUndefined(Value *vec, size_t len) +{ + SetValueRangeToUndefined(vec, vec + len); +} + +static JS_ALWAYS_INLINE void +SetValueRangeToNull(Value *beg, Value *end) +{ + for (Value *v = beg; v != end; ++v) + v->setNull(); +} + +static JS_ALWAYS_INLINE void +SetValueRangeToNull(Value *vec, size_t len) +{ + SetValueRangeToNull(vec, vec + len); +} + +/* + * To really poison a set of values, using 'magic' or 'undefined' isn't good + * enough since often these will just be ignored by buggy code (see bug 629974) + * in debug builds and crash in release builds. Instead, we use a safe-for-crash + * pointer. + */ +static JS_ALWAYS_INLINE void +Debug_SetValueRangeToCrashOnTouch(Value *beg, Value *end) +{ +#ifdef DEBUG + for (Value *v = beg; v != end; ++v) + v->setObject(*reinterpret_cast(0x42)); +#endif +} + +static JS_ALWAYS_INLINE void +Debug_SetValueRangeToCrashOnTouch(Value *vec, size_t len) +{ +#ifdef DEBUG + Debug_SetValueRangeToCrashOnTouch(vec, vec + len); +#endif +} + +} /* namespace js */ +#endif /* jsvalue_h__ */ diff --git a/js/src/jsvector.h b/js/src/jsvector.h new file mode 100644 index 0000000..ab432ba --- /dev/null +++ b/js/src/jsvector.h @@ -0,0 +1,759 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * June 12, 2009. + * + * The Initial Developer of the Original Code is + * the Mozilla Corporation. + * + * Contributor(s): + * Luke Wagner + * Nicholas Nethercote + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsvector_h_ +#define jsvector_h_ + +#include "jstl.h" +#include "jsprvtd.h" + +/* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4345) +#endif + +/* Gross special case for Gecko, which defines malloc/calloc/free. */ +#ifdef mozilla_mozalloc_macro_wrappers_h +# define JSVECTOR_UNDEFD_MOZALLOC_WRAPPERS +# include "mozilla/mozalloc_undef_macro_wrappers.h" +#endif + +namespace js { + +/* + * This template class provides a default implementation for vector operations + * when the element type is not known to be a POD, as judged by IsPodType. + */ +template +struct VectorImpl +{ + /* Destroys constructed objects in the range [begin, end). */ + static inline void destroy(T *begin, T *end) { + for (T *p = begin; p != end; ++p) + p->~T(); + } + + /* Constructs objects in the uninitialized range [begin, end). */ + static inline void initialize(T *begin, T *end) { + for (T *p = begin; p != end; ++p) + new(p) T(); + } + + /* + * Copy-constructs objects in the uninitialized range + * [dst, dst+(srcend-srcbeg)) from the range [srcbeg, srcend). + */ + template + static inline void copyConstruct(T *dst, const U *srcbeg, const U *srcend) { + for (const U *p = srcbeg; p != srcend; ++p, ++dst) + new(dst) T(*p); + } + + /* + * Copy-constructs objects in the uninitialized range [dst, dst+n) from the + * same object u. + */ + template + static inline void copyConstructN(T *dst, size_t n, const U &u) { + for (T *end = dst + n; dst != end; ++dst) + new(dst) T(u); + } + + /* + * Grows the given buffer to have capacity newcap, preserving the objects + * constructed in the range [begin, end) and updating v. Assumes that (1) + * newcap has not overflowed, and (2) multiplying newcap by sizeof(T) will + * not overflow. + */ + static inline bool growTo(Vector &v, size_t newcap) { + JS_ASSERT(!v.usingInlineStorage()); + T *newbuf = reinterpret_cast(v.malloc(newcap * sizeof(T))); + if (!newbuf) + return false; + for (T *dst = newbuf, *src = v.beginNoCheck(); src != v.endNoCheck(); ++dst, ++src) + new(dst) T(*src); + VectorImpl::destroy(v.beginNoCheck(), v.endNoCheck()); + v.free(v.mBegin); + v.mBegin = newbuf; + /* v.mLength is unchanged. */ + v.mCapacity = newcap; + return true; + } +}; + +/* + * This partial template specialization provides a default implementation for + * vector operations when the element type is known to be a POD, as judged by + * IsPodType. + */ +template +struct VectorImpl +{ + static inline void destroy(T *, T *) {} + + static inline void initialize(T *begin, T *end) { + /* + * You would think that memset would be a big win (or even break even) + * when we know T is a POD. But currently it's not. This is probably + * because |append| tends to be given small ranges and memset requires + * a function call that doesn't get inlined. + * + * memset(begin, 0, sizeof(T) * (end-begin)); + */ + for (T *p = begin; p != end; ++p) + new(p) T(); + } + + template + static inline void copyConstruct(T *dst, const U *srcbeg, const U *srcend) { + /* + * See above memset comment. Also, notice that copyConstruct is + * currently templated (T != U), so memcpy won't work without + * requiring T == U. + * + * memcpy(dst, srcbeg, sizeof(T) * (srcend - srcbeg)); + */ + for (const U *p = srcbeg; p != srcend; ++p, ++dst) + *dst = *p; + } + + static inline void copyConstructN(T *dst, size_t n, const T &t) { + for (T *p = dst, *end = dst + n; p != end; ++p) + *p = t; + } + + static inline bool growTo(Vector &v, size_t newcap) { + JS_ASSERT(!v.usingInlineStorage()); + size_t bytes = sizeof(T) * newcap; + T *newbuf = reinterpret_cast(v.realloc(v.mBegin, bytes)); + if (!newbuf) + return false; + v.mBegin = newbuf; + /* v.mLength is unchanged. */ + v.mCapacity = newcap; + return true; + } +}; + +/* + * JS-friendly, STL-like container providing a short-lived, dynamic buffer. + * Vector calls the constructors/destructors of all elements stored in + * its internal buffer, so non-PODs may be safely used. Additionally, + * Vector will store the first N elements in-place before resorting to + * dynamic allocation. + * + * T requirements: + * - default and copy constructible, assignable, destructible + * - operations do not throw + * N requirements: + * - any value, however, N is clamped to min/max values + * AllocPolicy: + * - see "Allocation policies" in jstl.h (default ContextAllocPolicy) + * + * N.B: Vector is not reentrant: T member functions called during Vector member + * functions must not call back into the same object. + */ +template +class Vector : AllocPolicy +{ + /* utilities */ + + static const bool sElemIsPod = tl::IsPodType::result; + typedef VectorImpl Impl; + friend struct VectorImpl; + + bool calculateNewCapacity(size_t curLength, size_t lengthInc, size_t &newCap); + bool growStorageBy(size_t lengthInc); + bool growHeapStorageBy(size_t lengthInc); + bool convertToHeapStorage(size_t lengthInc); + + template inline bool growByImpl(size_t inc); + + /* magic constants */ + + static const int sMaxInlineBytes = 1024; + + /* compute constants */ + + static const size_t sInlineCapacity = + tl::Min::result; + + /* Calculate inline buffer size; avoid 0-sized array. */ + static const size_t sInlineBytes = + tl::Max<1, sInlineCapacity * sizeof(T)>::result; + + /* member data */ + + /* + * Pointer to the buffer, be it inline or heap-allocated. Only [mBegin, + * mBegin + mLength) hold valid constructed T objects. The range [mBegin + + * mLength, mBegin + mCapacity) holds uninitialized memory. + */ + T *mBegin; + size_t mLength; /* Number of elements in the Vector. */ + size_t mCapacity; /* Max number of elements storable in the Vector without resizing. */ + + AlignedStorage storage; + +#ifdef DEBUG + friend class ReentrancyGuard; + bool entered; +#endif + + Vector(const Vector &); + Vector &operator=(const Vector &); + + /* private accessors */ + + bool usingInlineStorage() const { + return mBegin == (T *)storage.addr(); + } + + T *beginNoCheck() const { + return mBegin; + } + + T *endNoCheck() { + return mBegin + mLength; + } + + const T *endNoCheck() const { + return mBegin + mLength; + } + + public: + typedef T ElementType; + + Vector(AllocPolicy = AllocPolicy()); + ~Vector(); + + /* accessors */ + + const AllocPolicy &allocPolicy() const { + return *this; + } + + enum { InlineLength = N }; + + size_t length() const { + return mLength; + } + + bool empty() const { + return mLength == 0; + } + + size_t capacity() const { + return mCapacity; + } + + T *begin() const { + JS_ASSERT(!entered); + return mBegin; + } + + T *end() { + JS_ASSERT(!entered); + return mBegin + mLength; + } + + const T *end() const { + JS_ASSERT(!entered); + return mBegin + mLength; + } + + T &operator[](size_t i) { + JS_ASSERT(!entered && i < mLength); + return begin()[i]; + } + + const T &operator[](size_t i) const { + JS_ASSERT(!entered && i < mLength); + return begin()[i]; + } + + T &back() { + JS_ASSERT(!entered && !empty()); + return *(end() - 1); + } + + const T &back() const { + JS_ASSERT(!entered && !empty()); + return *(end() - 1); + } + + /* mutators */ + + /* If reserve(length() + N) succeeds, the N next appends are guaranteed to succeed. */ + bool reserve(size_t capacity); + + /* Destroy elements in the range [begin() + incr, end()). */ + void shrinkBy(size_t incr); + + /* Grow the vector by incr elements. */ + bool growBy(size_t incr); + + /* Call shrinkBy or growBy based on whether newSize > length(). */ + bool resize(size_t newLength); + + /* Leave new elements as uninitialized memory. */ + bool growByUninitialized(size_t incr); + bool resizeUninitialized(size_t newLength); + + void clear(); + + bool append(const T &t); + bool appendN(const T &t, size_t n); + template bool append(const U *begin, const U *end); + template bool append(const U *begin, size_t length); + template bool append(const Vector &other); + + void popBack(); + + T popCopy(); + + /* + * Transfers ownership of the internal buffer used by Vector to the caller. + * After this call, the Vector is empty. Since the returned buffer may need + * to be allocated (if the elements are currently stored in-place), the + * call can fail, returning NULL. + * + * N.B. Although a T*, only the range [0, length()) is constructed. + */ + T *extractRawBuffer(); + + /* + * Transfer ownership of an array of objects into the Vector. + * N.B. This call assumes that there are no uninitialized elements in the + * passed array. + */ + void replaceRawBuffer(T *p, size_t length); + + /* + * Places |val| at position |p|, shifting existing elements + * from |p| onward one position higher. + */ + bool insert(T *p, const T &val); + + /* + * Removes the element |t|, which must fall in the bounds [begin, end), + * shifting existing elements from |t + 1| onward one position lower. + */ + void erase(T *t); +}; + +/* This does the re-entrancy check plus several other sanity checks. */ +#define REENTRANCY_GUARD_ET_AL \ + ReentrancyGuard g(*this); \ + JS_ASSERT_IF(usingInlineStorage(), mCapacity == sInlineCapacity); \ + JS_ASSERT(mLength <= mCapacity) + +/* Vector Implementation */ + +template +JS_ALWAYS_INLINE +Vector::Vector(AllocPolicy ap) + : AllocPolicy(ap), mBegin((T *)storage.addr()), mLength(0), + mCapacity(sInlineCapacity) +#ifdef DEBUG + , entered(false) +#endif +{} + +template +JS_ALWAYS_INLINE +Vector::~Vector() +{ + REENTRANCY_GUARD_ET_AL; + Impl::destroy(beginNoCheck(), endNoCheck()); + if (!usingInlineStorage()) + this->free(beginNoCheck()); +} + +/* + * Calculate a new capacity that is at least lengthInc greater than + * curLength and check for overflow. + */ +template +STATIC_POSTCONDITION(!return || newCap >= curLength + lengthInc) +inline bool +Vector::calculateNewCapacity(size_t curLength, size_t lengthInc, + size_t &newCap) +{ + size_t newMinCap = curLength + lengthInc; + + /* + * Check for overflow in the above addition, below CEILING_LOG2, and later + * multiplication by sizeof(T). + */ + if (newMinCap < curLength || + newMinCap & tl::MulOverflowMask<2 * sizeof(T)>::result) { + this->reportAllocOverflow(); + return false; + } + + /* Round up to next power of 2. */ + newCap = RoundUpPow2(newMinCap); + + /* + * Do not allow a buffer large enough that the expression ((char *)end() - + * (char *)begin()) overflows ptrdiff_t. See Bug 510319. + */ + if (newCap & tl::UnsafeRangeSizeMask::result) { + this->reportAllocOverflow(); + return false; + } + return true; +} + +/* + * This function will grow the current heap capacity to have capacity + * (mLength + lengthInc) and fail on OOM or integer overflow. + */ +template +JS_ALWAYS_INLINE bool +Vector::growHeapStorageBy(size_t lengthInc) +{ + JS_ASSERT(!usingInlineStorage()); + size_t newCap; + return calculateNewCapacity(mLength, lengthInc, newCap) && + Impl::growTo(*this, newCap); +} + +/* + * This function will create a new heap buffer with capacity (mLength + + * lengthInc()), move all elements in the inline buffer to this new buffer, + * and fail on OOM or integer overflow. + */ +template +inline bool +Vector::convertToHeapStorage(size_t lengthInc) +{ + JS_ASSERT(usingInlineStorage()); + size_t newCap; + if (!calculateNewCapacity(mLength, lengthInc, newCap)) + return false; + + /* Allocate buffer. */ + T *newBuf = reinterpret_cast(this->malloc(newCap * sizeof(T))); + if (!newBuf) + return false; + + /* Copy inline elements into heap buffer. */ + Impl::copyConstruct(newBuf, beginNoCheck(), endNoCheck()); + Impl::destroy(beginNoCheck(), endNoCheck()); + + /* Switch in heap buffer. */ + mBegin = newBuf; + /* mLength is unchanged. */ + mCapacity = newCap; + return true; +} + +template +JS_NEVER_INLINE bool +Vector::growStorageBy(size_t incr) +{ + JS_ASSERT(mLength + incr > mCapacity); + return usingInlineStorage() + ? convertToHeapStorage(incr) + : growHeapStorageBy(incr); +} + +template +inline bool +Vector::reserve(size_t request) +{ + REENTRANCY_GUARD_ET_AL; + if (request > mCapacity) + return growStorageBy(request - mLength); + return true; +} + +template +inline void +Vector::shrinkBy(size_t incr) +{ + REENTRANCY_GUARD_ET_AL; + JS_ASSERT(incr <= mLength); + Impl::destroy(endNoCheck() - incr, endNoCheck()); + mLength -= incr; +} + +template +template +JS_ALWAYS_INLINE bool +Vector::growByImpl(size_t incr) +{ + REENTRANCY_GUARD_ET_AL; + if (incr > mCapacity - mLength && !growStorageBy(incr)) + return false; + + JS_ASSERT(mLength + incr <= mCapacity); + T *newend = endNoCheck() + incr; + if (InitNewElems) + Impl::initialize(endNoCheck(), newend); + mLength += incr; + return true; +} + +template +JS_ALWAYS_INLINE bool +Vector::growBy(size_t incr) +{ + return growByImpl(incr); +} + +template +JS_ALWAYS_INLINE bool +Vector::growByUninitialized(size_t incr) +{ + return growByImpl(incr); +} + +template +STATIC_POSTCONDITION(!return || ubound(this->begin()) >= newLength) +inline bool +Vector::resize(size_t newLength) +{ + size_t curLength = mLength; + if (newLength > curLength) + return growBy(newLength - curLength); + shrinkBy(curLength - newLength); + return true; +} + +template +JS_ALWAYS_INLINE bool +Vector::resizeUninitialized(size_t newLength) +{ + size_t curLength = mLength; + if (newLength > curLength) + return growByUninitialized(newLength - curLength); + shrinkBy(curLength - newLength); + return true; +} + +template +inline void +Vector::clear() +{ + REENTRANCY_GUARD_ET_AL; + Impl::destroy(beginNoCheck(), endNoCheck()); + mLength = 0; +} + +template +JS_ALWAYS_INLINE bool +Vector::append(const T &t) +{ + REENTRANCY_GUARD_ET_AL; + if (mLength == mCapacity && !growStorageBy(1)) + return false; + + JS_ASSERT(mLength < mCapacity); + new(endNoCheck()) T(t); + ++mLength; + return true; +} + +template +JS_ALWAYS_INLINE bool +Vector::appendN(const T &t, size_t needed) +{ + REENTRANCY_GUARD_ET_AL; + if (mLength + needed > mCapacity && !growStorageBy(needed)) + return false; + + JS_ASSERT(mLength + needed <= mCapacity); + Impl::copyConstructN(endNoCheck(), needed, t); + mLength += needed; + return true; +} + +template +inline bool +Vector::insert(T *p, const T &val) +{ + JS_ASSERT(begin() <= p && p <= end()); + size_t pos = p - begin(); + JS_ASSERT(pos <= mLength); + size_t oldLength = mLength; + if (pos == oldLength) + return append(val); + { + T oldBack = back(); + if (!append(oldBack)) /* Dup the last element. */ + return false; + } + for (size_t i = oldLength; i > pos; --i) + (*this)[i] = (*this)[i - 1]; + (*this)[pos] = val; + return true; +} + +template +inline void +Vector::erase(T *it) +{ + JS_ASSERT(begin() <= it && it < end()); + while (it + 1 != end()) { + *it = *(it + 1); + ++it; + } + popBack(); +} + +template +template +JS_ALWAYS_INLINE bool +Vector::append(const U *insBegin, const U *insEnd) +{ + REENTRANCY_GUARD_ET_AL; + size_t needed = PointerRangeSize(insBegin, insEnd); + if (mLength + needed > mCapacity && !growStorageBy(needed)) + return false; + + JS_ASSERT(mLength + needed <= mCapacity); + Impl::copyConstruct(endNoCheck(), insBegin, insEnd); + mLength += needed; + return true; +} + +template +template +inline bool +Vector::append(const Vector &other) +{ + return append(other.begin(), other.end()); +} + +template +template +JS_ALWAYS_INLINE bool +Vector::append(const U *insBegin, size_t length) +{ + return this->append(insBegin, insBegin + length); +} + +template +JS_ALWAYS_INLINE void +Vector::popBack() +{ + REENTRANCY_GUARD_ET_AL; + JS_ASSERT(!empty()); + --mLength; + endNoCheck()->~T(); +} + +template +JS_ALWAYS_INLINE T +Vector::popCopy() +{ + T ret = back(); + popBack(); + return ret; +} + +template +inline T * +Vector::extractRawBuffer() +{ + T *ret; + if (usingInlineStorage()) { + ret = reinterpret_cast(this->malloc(mLength * sizeof(T))); + if (!ret) + return NULL; + Impl::copyConstruct(ret, beginNoCheck(), endNoCheck()); + Impl::destroy(beginNoCheck(), endNoCheck()); + /* mBegin, mCapacity are unchanged. */ + mLength = 0; + } else { + ret = mBegin; + mBegin = (T *)storage.addr(); + mLength = 0; + mCapacity = sInlineCapacity; + } + return ret; +} + +template +inline void +Vector::replaceRawBuffer(T *p, size_t length) +{ + REENTRANCY_GUARD_ET_AL; + + /* Destroy what we have. */ + Impl::destroy(beginNoCheck(), endNoCheck()); + if (!usingInlineStorage()) + this->free(beginNoCheck()); + + /* Take in the new buffer. */ + if (length <= sInlineCapacity) { + /* + * We convert to inline storage if possible, even though p might + * otherwise be acceptable. Maybe this behaviour should be + * specifiable with an argument to this function. + */ + mBegin = (T *)storage.addr(); + mLength = length; + mCapacity = sInlineCapacity; + Impl::copyConstruct(mBegin, p, p + length); + Impl::destroy(p, p + length); + this->free(p); + } else { + mBegin = p; + mLength = length; + mCapacity = length; + } +} + +} /* namespace js */ + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#ifdef JSVECTOR_UNDEFD_MOZALLOC_WRAPPERS +# include "mozilla/mozalloc_macro_wrappers.h" +#endif + +#endif /* jsvector_h_ */ diff --git a/js/src/jsversion.h b/js/src/jsversion.h new file mode 100644 index 0000000..f72af49 --- /dev/null +++ b/js/src/jsversion.h @@ -0,0 +1,221 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * JS configuration macros. + */ +#ifndef JS_VERSION +#define JS_VERSION 185 +#endif + +/* + * Compile-time JS version configuration. The JS version numbers lie on the + * number line like so: + * + * 1.0 1.1 1.2 1.3 1.4 ECMAv3 1.5 1.6 1.7 1.8 ECMAv5 + * ^ ^ + * | | + * basis for ECMAv1 close to ECMAv2 + * + * where ECMAv3 stands for ECMA-262 Edition 3, and ECMAv5 stands for Edition 5. + * See the runtime version enum JSVersion in jspubtd.h. Code in the engine can + * therefore count on version <= JSVERSION_1_4 to mean "before the Third + * Edition of ECMA-262" and version > JSVERSION_1_4 to mean "at or after the + * Third Edition". + * + * In the (likely?) event that SpiderMonkey grows to implement JavaScript 2.0, + * the version number to use would be near 200, or greater. + * + * The JS_VERSION_ECMA_3 version is the minimal configuration conforming to + * the ECMA-262 Edition 3 specification. Use it for minimal embeddings, where + * you're sure you don't need any of the extensions disabled in this version. + * In order to facilitate testing, JS_HAS_OBJ_PROTO_PROP is defined as part of + * the JS_VERSION_ECMA_3_TEST version. + * + * To keep things sane in the modern age, where we need exceptions in order to + * implement, e.g., iterators and generators, we are dropping support for all + * versions <= 1.4. + */ +#define JS_VERSION_ECMA_3 148 +#define JS_VERSION_ECMA_3_TEST 149 + +#if JS_VERSION == JS_VERSION_ECMA_3 || \ + JS_VERSION == JS_VERSION_ECMA_3_TEST + +#define JS_HAS_STR_HTML_HELPERS 0 /* has str.anchor, str.bold, etc. */ +#define JS_HAS_PERL_SUBSTR 0 /* has str.substr */ +#if JS_VERSION == JS_VERSION_ECMA_3_TEST +#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */ +#else +#define JS_HAS_OBJ_PROTO_PROP 0 /* has o.__proto__ etc. */ +#endif +#define JS_HAS_OBJ_WATCHPOINT 0 /* has o.watch and o.unwatch */ +#define JS_HAS_SHARP_VARS 0 /* has #n=, #n# for object literals */ +#define JS_HAS_XDR 0 /* has XDR API and internal support */ +#define JS_HAS_TOSOURCE 0 /* has Object/Array toSource method */ +#define JS_HAS_CATCH_GUARD 0 /* has exception handling catch guard */ +#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */ +#define JS_HAS_UNEVAL 0 /* has uneval() top-level function */ +#define JS_HAS_CONST 0 /* has JS2 const as alternative var */ +#define JS_HAS_FUN_EXPR_STMT 0 /* has function expression statement */ +#define JS_HAS_NO_SUCH_METHOD 0 /* has o.__noSuchMethod__ handler */ +#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */ +#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */ +#define JS_HAS_GENERATORS 0 /* has yield in generator function */ +#define JS_HAS_BLOCK_SCOPE 0 /* has block scope via let/arraycomp */ +#define JS_HAS_DESTRUCTURING 0 /* has [a,b] = ... or {p:a,q:b} = ... */ +#define JS_HAS_GENERATOR_EXPRS 0 /* has (expr for (lhs in iterable)) */ +#define JS_HAS_EXPR_CLOSURES 0 /* has function (formals) listexpr */ + +#elif JS_VERSION < 150 + +#error "unsupported JS_VERSION" + +#elif JS_VERSION == 150 + +#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */ +#define JS_HAS_PERL_SUBSTR 1 /* has str.substr */ +#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */ +#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */ +#define JS_HAS_SHARP_VARS 1 /* has #n=, #n# for object literals */ +#define JS_HAS_XDR 1 /* has XDR API and internal support */ +#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */ +#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */ +#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */ +#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */ +#define JS_HAS_CONST 1 /* has JS2 const as alternative var */ +#define JS_HAS_FUN_EXPR_STMT 1 /* has function expression statement */ +#define JS_HAS_NO_SUCH_METHOD 1 /* has o.__noSuchMethod__ handler */ +#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */ +#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */ +#define JS_HAS_GENERATORS 0 /* has yield in generator function */ +#define JS_HAS_BLOCK_SCOPE 0 /* has block scope via let/arraycomp */ +#define JS_HAS_DESTRUCTURING 0 /* has [a,b] = ... or {p:a,q:b} = ... */ +#define JS_HAS_GENERATOR_EXPRS 0 /* has (expr for (lhs in iterable)) */ +#define JS_HAS_EXPR_CLOSURES 0 /* has function (formals) listexpr */ + +#elif JS_VERSION == 160 + +#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */ +#define JS_HAS_PERL_SUBSTR 1 /* has str.substr */ +#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */ +#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */ +#define JS_HAS_SHARP_VARS 1 /* has #n=, #n# for object literals */ +#define JS_HAS_XDR 1 /* has XDR API and internal support */ +#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */ +#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */ +#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */ +#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */ +#define JS_HAS_CONST 1 /* has JS2 const as alternative var */ +#define JS_HAS_FUN_EXPR_STMT 1 /* has function expression statement */ +#define JS_HAS_NO_SUCH_METHOD 1 /* has o.__noSuchMethod__ handler */ +#define JS_HAS_XML_SUPPORT 1 /* has ECMAScript for XML support */ +#define JS_HAS_ARRAY_EXTRAS 1 /* has indexOf and Lispy extras */ +#define JS_HAS_GENERATORS 0 /* has yield in generator function */ +#define JS_HAS_BLOCK_SCOPE 0 /* has block scope via let/arraycomp */ +#define JS_HAS_DESTRUCTURING 0 /* has [a,b] = ... or {p:a,q:b} = ... */ +#define JS_HAS_GENERATOR_EXPRS 0 /* has (expr for (lhs in iterable)) */ +#define JS_HAS_EXPR_CLOSURES 0 /* has function (formals) listexpr */ + +#elif JS_VERSION == 170 + +#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */ +#define JS_HAS_PERL_SUBSTR 1 /* has str.substr */ +#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */ +#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */ +#define JS_HAS_SHARP_VARS 1 /* has #n=, #n# for object literals */ +#define JS_HAS_XDR 1 /* has XDR API and internal support */ +#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */ +#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */ +#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */ +#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */ +#define JS_HAS_CONST 1 /* has JS2 const as alternative var */ +#define JS_HAS_FUN_EXPR_STMT 1 /* has function expression statement */ +#define JS_HAS_NO_SUCH_METHOD 1 /* has o.__noSuchMethod__ handler */ +#define JS_HAS_XML_SUPPORT 1 /* has ECMAScript for XML support */ +#define JS_HAS_ARRAY_EXTRAS 1 /* has indexOf and Lispy extras */ +#define JS_HAS_GENERATORS 1 /* has yield in generator function */ +#define JS_HAS_BLOCK_SCOPE 1 /* has block scope via let/arraycomp */ +#define JS_HAS_DESTRUCTURING 1 /* has [a,b] = ... or {p:a,q:b} = ... */ +#define JS_HAS_GENERATOR_EXPRS 0 /* has (expr for (lhs in iterable)) */ +#define JS_HAS_EXPR_CLOSURES 0 /* has function (formals) listexpr */ + +#elif 180 <= JS_VERSION && JS_VERSION <= 185 + +#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */ +#define JS_HAS_PERL_SUBSTR 1 /* has str.substr */ +#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */ +#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */ +#define JS_HAS_SHARP_VARS 1 /* has #n=, #n# for object literals */ +#define JS_HAS_XDR 1 /* has XDR API and internal support */ +#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */ +#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */ +#define JS_HAS_SPARSE_ARRAYS 0 /* array methods preserve empty elems */ +#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */ +#define JS_HAS_CONST 1 /* has JS2 const as alternative var */ +#define JS_HAS_FUN_EXPR_STMT 1 /* has function expression statement */ +#define JS_HAS_NO_SUCH_METHOD 1 /* has o.__noSuchMethod__ handler */ +#define JS_HAS_XML_SUPPORT 1 /* has ECMAScript for XML support */ +#define JS_HAS_ARRAY_EXTRAS 1 /* has indexOf and Lispy extras */ +#define JS_HAS_GENERATORS 1 /* has yield in generator function */ +#define JS_HAS_BLOCK_SCOPE 1 /* has block scope via let/arraycomp */ +#define JS_HAS_DESTRUCTURING 2 /* has [a,b] = ... or {p:a,q:b} = ... */ +#define JS_HAS_GENERATOR_EXPRS 1 /* has (expr for (lhs in iterable)) */ +#define JS_HAS_EXPR_CLOSURES 1 /* has function (formals) listexpr */ + +#else + +#error "unknown JS_VERSION" + +#endif + +/* Support for JS_NewGlobalObject. */ +#define JS_HAS_NEW_GLOBAL_OBJECT 1 + +/* Support for JS_MakeSystemObject. */ +#define JS_HAS_MAKE_SYSTEM_OBJECT 1 + +/* Feature-test macro for evolving destructuring support. */ +#define JS_HAS_DESTRUCTURING_SHORTHAND (JS_HAS_DESTRUCTURING == 2) + +/* + * Feature for Object.prototype.__{define,lookup}{G,S}etter__ legacy support; + * support likely to be made opt-in at some future time. + */ +#define OLD_GETTER_SETTER_METHODS 1 diff --git a/js/src/jswin.h b/js/src/jswin.h new file mode 100644 index 0000000..b71556a --- /dev/null +++ b/js/src/jswin.h @@ -0,0 +1,45 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is workarounds for the Win32 headers. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This file is a wrapper around to prevent the mangling of + * various function names throughout the codebase. + */ +#ifdef XP_WIN +# include +# undef GetProp +# undef SetProp +#endif diff --git a/js/src/jswince.asm b/js/src/jswince.asm new file mode 100644 index 0000000..6a2e1eb --- /dev/null +++ b/js/src/jswince.asm @@ -0,0 +1,82 @@ + INCLUDE kxarm.h + + area js_msvc, code, readonly + + MACRO + FUNC_HEADER $Name +FuncName SETS VBar:CC:"$Name":CC:VBar +PrologName SETS VBar:CC:"$Name":CC:"_Prolog":CC:VBar +FuncEndName SETS VBar:CC:"$Name":CC:"_end":CC:VBar + + AREA |.pdata|,ALIGN=2,PDATA + DCD $FuncName + DCD (($PrologName-$FuncName)/4) :OR: ((($FuncEndName-$FuncName)/4):SHL:8) :OR: 0x40000000 + AREA $AreaName,CODE,READONLY + ALIGN 2 + GLOBAL $FuncName + EXPORT $FuncName +$FuncName + ROUT +$PrologName + MEND + + ;; -------- Functions to test processor features. + export js_arm_try_thumb_op + export js_arm_try_armv6t2_op + export js_arm_try_armv7_op + export js_arm_try_armv6_op + export js_arm_try_armv5_op + export js_arm_try_vfp_op + + ;; Test for Thumb support. + FUNC_HEADER js_arm_try_thumb_op + bx lr + mov pc, lr + ENTRY_END + endp + + ;; I'm not smart enough to figure out which flags to pass to armasm to get it + ;; to understand movt and fmdrr/vmov; the disassembler figures them out just fine! + + ;; Test for Thumb2 support. + FUNC_HEADER js_arm_try_armv6t2_op + ;; movt r0,#0xFFFF + DCD 0xE34F0FFF + mov pc,lr + ENTRY_END + endp + + ;; Test for VFP support. + FUNC_HEADER js_arm_try_vfp_op + ;; fmdrr d0, r0, r1 + DCD 0xEC410B10 + mov pc,lr + ENTRY_END + endp + + ;; Tests for each architecture version. + + FUNC_HEADER js_arm_try_armv7_op + ;; pli pc, #0 + DCD 0xF45FF000 + mov pc, lr + ENTRY_END + endp + + FUNC_HEADER js_arm_try_armv6_op + ;; rev ip, ip + DCD 0xE6BFCF3C + mov pc, lr + ENTRY_END + endp + + FUNC_HEADER js_arm_try_armv5_op + ;; clz ip, ip + DCD 0xE16FCF1C + mov pc, lr + ENTRY_END + endp + + ;; -------- + + end diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp new file mode 100644 index 0000000..8e4e0c8 --- /dev/null +++ b/js/src/jswrapper.cpp @@ -0,0 +1,701 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Andreas Gal + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsapi.h" +#include "jscntxt.h" +#include "jsiter.h" +#include "jsnum.h" +#include "jsregexp.h" +#include "jswrapper.h" +#include "methodjit/PolyIC.h" +#include "methodjit/MonoIC.h" +#ifdef JS_METHODJIT +# include "assembler/jit/ExecutableAllocator.h" +#endif +#include "jscompartment.h" + +#include "jsobjinlines.h" + +using namespace js; +using namespace js::gc; + +static int sWrapperFamily; + +void * +JSWrapper::getWrapperFamily() +{ + return &sWrapperFamily; +} + +bool +JSObject::isWrapper() const +{ + return isProxy() && getProxyHandler()->family() == &sWrapperFamily; +} + +JSObject * +JSObject::unwrap(uintN *flagsp) +{ + JSObject *wrapped = this; + uintN flags = 0; + while (wrapped->isWrapper()) { + flags |= static_cast(wrapped->getProxyHandler())->flags(); + wrapped = wrapped->getProxyPrivate().toObjectOrNull(); + if (wrapped->getClass()->ext.innerObject) + break; + } + if (flagsp) + *flagsp = flags; + return wrapped; +} + +JSWrapper::JSWrapper(uintN flags) : JSProxyHandler(&sWrapperFamily), mFlags(flags) +{ +} + +JSWrapper::~JSWrapper() +{ +} + +#define CHECKED(op, act) \ + JS_BEGIN_MACRO \ + bool status; \ + if (!enter(cx, wrapper, id, act, &status)) \ + return status; \ + bool ok = (op); \ + leave(cx, wrapper); \ + return ok; \ + JS_END_MACRO + +#define SET(action) CHECKED(action, SET) +#define GET(action) CHECKED(action, GET) + +bool +JSWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, + bool set, PropertyDescriptor *desc) +{ + desc->obj= NULL; // default result if we refuse to perform this action + CHECKED(JS_GetPropertyDescriptorById(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED, + Jsvalify(desc)), set ? SET : GET); +} + +static bool +GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSPropertyDescriptor *desc) +{ + if (!JS_GetPropertyDescriptorById(cx, obj, id, flags, desc)) + return false; + if (desc->obj != obj) + desc->obj = NULL; + return true; +} + +bool +JSWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set, + PropertyDescriptor *desc) +{ + desc->obj= NULL; // default result if we refuse to perform this action + CHECKED(GetOwnPropertyDescriptor(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED, + Jsvalify(desc)), set ? SET : GET); +} + +bool +JSWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id, + PropertyDescriptor *desc) +{ + SET(JS_DefinePropertyById(cx, wrappedObject(wrapper), id, Jsvalify(desc->value), + Jsvalify(desc->getter), Jsvalify(desc->setter), desc->attrs)); +} + +bool +JSWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props) +{ + // if we refuse to perform this action, props remains empty + jsid id = JSID_VOID; + GET(GetPropertyNames(cx, wrappedObject(wrapper), JSITER_OWNONLY | JSITER_HIDDEN, &props)); +} + +static bool +ValueToBoolean(Value *vp, bool *bp) +{ + *bp = js_ValueToBoolean(*vp); + return true; +} + +bool +JSWrapper::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) +{ + *bp = true; // default result if we refuse to perform this action + Value v; + SET(JS_DeletePropertyById2(cx, wrappedObject(wrapper), id, Jsvalify(&v)) && + ValueToBoolean(&v, bp)); +} + +bool +JSWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props) +{ + // if we refuse to perform this action, props remains empty + static jsid id = JSID_VOID; + GET(GetPropertyNames(cx, wrappedObject(wrapper), 0, &props)); +} + +bool +JSWrapper::fix(JSContext *cx, JSObject *wrapper, Value *vp) +{ + vp->setUndefined(); + return true; +} + +static bool +Cond(JSBool b, bool *bp) +{ + *bp = !!b; + return true; +} + +bool +JSWrapper::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) +{ + *bp = false; // default result if we refuse to perform this action + JSBool found; + GET(JS_HasPropertyById(cx, wrappedObject(wrapper), id, &found) && + Cond(found, bp)); +} + +bool +JSWrapper::hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) +{ + *bp = false; // default result if we refuse to perform this action + PropertyDescriptor desc; + JSObject *wobj = wrappedObject(wrapper); + GET(JS_GetPropertyDescriptorById(cx, wobj, id, JSRESOLVE_QUALIFIED, Jsvalify(&desc)) && + Cond(desc.obj == wobj, bp)); +} + +bool +JSWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp) +{ + vp->setUndefined(); // default result if we refuse to perform this action + GET(wrappedObject(wrapper)->getProperty(cx, receiver, id, vp)); +} + +bool +JSWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, bool strict, + Value *vp) +{ + // FIXME (bug 596351): Need deal with strict mode. + SET(wrappedObject(wrapper)->setProperty(cx, id, vp, false)); +} + +bool +JSWrapper::keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props) +{ + // if we refuse to perform this action, props remains empty + const jsid id = JSID_VOID; + GET(GetPropertyNames(cx, wrappedObject(wrapper), JSITER_OWNONLY, &props)); +} + +bool +JSWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, Value *vp) +{ + vp->setUndefined(); // default result if we refuse to perform this action + const jsid id = JSID_VOID; + GET(GetIterator(cx, wrappedObject(wrapper), flags, vp)); +} + +bool +JSWrapper::call(JSContext *cx, JSObject *wrapper, uintN argc, Value *vp) +{ + vp->setUndefined(); // default result if we refuse to perform this action + const jsid id = JSID_VOID; + CHECKED(JSProxyHandler::call(cx, wrapper, argc, vp), CALL); +} + +bool +JSWrapper::construct(JSContext *cx, JSObject *wrapper, uintN argc, Value *argv, Value *vp) +{ + vp->setUndefined(); // default result if we refuse to perform this action + const jsid id = JSID_VOID; + GET(JSProxyHandler::construct(cx, wrapper, argc, argv, vp)); +} + +bool +JSWrapper::hasInstance(JSContext *cx, JSObject *wrapper, const Value *vp, bool *bp) +{ + *bp = true; // default result if we refuse to perform this action + const jsid id = JSID_VOID; + JSBool b; + GET(JS_HasInstance(cx, wrappedObject(wrapper), Jsvalify(*vp), &b) && Cond(b, bp)); +} + +JSType +JSWrapper::typeOf(JSContext *cx, JSObject *wrapper) +{ + return TypeOfValue(cx, ObjectValue(*wrappedObject(wrapper))); +} + +JSString * +JSWrapper::obj_toString(JSContext *cx, JSObject *wrapper) +{ + bool status; + if (!enter(cx, wrapper, JSID_VOID, GET, &status)) { + if (status) { + // Perform some default behavior that doesn't leak any information. + return JS_NewStringCopyZ(cx, "[object Object]"); + } + return NULL; + } + JSString *str = obj_toStringHelper(cx, wrappedObject(wrapper)); + leave(cx, wrapper); + return str; +} + +JSString * +JSWrapper::fun_toString(JSContext *cx, JSObject *wrapper, uintN indent) +{ + bool status; + if (!enter(cx, wrapper, JSID_VOID, GET, &status)) { + if (status) { + // Perform some default behavior that doesn't leak any information. + if (wrapper->isCallable()) + return JS_NewStringCopyZ(cx, "function () {\n [native code]\n}"); + js::Value v = ObjectValue(*wrapper); + js_ReportIsNotFunction(cx, &v, 0); + return NULL; + } + return NULL; + } + JSString *str = JSProxyHandler::fun_toString(cx, wrapper, indent); + leave(cx, wrapper); + return str; +} + +void +JSWrapper::trace(JSTracer *trc, JSObject *wrapper) +{ + MarkObject(trc, *wrappedObject(wrapper), "wrappedObject"); +} + +bool +JSWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, Action act, bool *bp) +{ + *bp = true; + return true; +} + +void +JSWrapper::leave(JSContext *cx, JSObject *wrapper) +{ +} + +JSWrapper JSWrapper::singleton((uintN)0); + +JSObject * +JSWrapper::New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, + JSWrapper *handler) +{ + JS_ASSERT(parent); + if (obj->isXML()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WRAP_XML_OBJECT); + return NULL; + } + return NewProxyObject(cx, handler, ObjectValue(*obj), proto, parent, + obj->isCallable() ? obj : NULL, NULL); +} + +/* Compartments. */ + +namespace js { + +extern JSObject * +TransparentObjectWrapper(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSObject *parent, + uintN flags) +{ + // Allow wrapping outer window proxies. + JS_ASSERT(!obj->isWrapper() || obj->getClass()->ext.innerObject); + return JSWrapper::New(cx, obj, wrappedProto, parent, &JSCrossCompartmentWrapper::singleton); +} + +} + +AutoCompartment::AutoCompartment(JSContext *cx, JSObject *target) + : context(cx), + origin(cx->compartment), + target(target), + destination(target->getCompartment()), + input(cx), + entered(false) +{ +} + +AutoCompartment::~AutoCompartment() +{ + if (entered) + leave(); +} + +bool +AutoCompartment::enter() +{ + JS_ASSERT(!entered); + if (origin != destination) { + LeaveTrace(context); + + context->compartment = destination; + JSObject *scopeChain = target->getGlobal(); + JS_ASSERT(scopeChain->isNative()); + + frame.construct(); + if (!context->stack().pushDummyFrame(context, *scopeChain, &frame.ref())) { + context->compartment = origin; + return false; + } + + if (context->isExceptionPending()) + context->wrapPendingException(); + } + entered = true; + return true; +} + +void +AutoCompartment::leave() +{ + JS_ASSERT(entered); + if (origin != destination) { + frame.destroy(); + context->resetCompartment(); + } + entered = false; +} + +/* Cross compartment wrappers. */ + +JSCrossCompartmentWrapper::JSCrossCompartmentWrapper(uintN flags) + : JSWrapper(CROSS_COMPARTMENT | flags) +{ +} + +JSCrossCompartmentWrapper::~JSCrossCompartmentWrapper() +{ +} + +#define PIERCE(cx, wrapper, mode, pre, op, post) \ + JS_BEGIN_MACRO \ + AutoCompartment call(cx, wrappedObject(wrapper)); \ + if (!call.enter()) \ + return false; \ + bool ok = (pre) && (op); \ + call.leave(); \ + return ok && (post); \ + JS_END_MACRO + +#define NOTHING (true) + +bool +JSCrossCompartmentWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, + bool set, PropertyDescriptor *desc) +{ + PIERCE(cx, wrapper, set ? SET : GET, + call.destination->wrapId(cx, &id), + JSWrapper::getPropertyDescriptor(cx, wrapper, id, set, desc), + call.origin->wrap(cx, desc)); +} + +bool +JSCrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, + bool set, PropertyDescriptor *desc) +{ + PIERCE(cx, wrapper, set ? SET : GET, + call.destination->wrapId(cx, &id), + JSWrapper::getOwnPropertyDescriptor(cx, wrapper, id, set, desc), + call.origin->wrap(cx, desc)); +} + +bool +JSCrossCompartmentWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc) +{ + AutoPropertyDescriptorRooter desc2(cx, desc); + PIERCE(cx, wrapper, SET, + call.destination->wrapId(cx, &id) && call.destination->wrap(cx, &desc2), + JSWrapper::defineProperty(cx, wrapper, id, &desc2), + NOTHING); +} + +bool +JSCrossCompartmentWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props) +{ + PIERCE(cx, wrapper, GET, + NOTHING, + JSWrapper::getOwnPropertyNames(cx, wrapper, props), + call.origin->wrap(cx, props)); +} + +bool +JSCrossCompartmentWrapper::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) +{ + PIERCE(cx, wrapper, SET, + call.destination->wrapId(cx, &id), + JSWrapper::delete_(cx, wrapper, id, bp), + NOTHING); +} + +bool +JSCrossCompartmentWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props) +{ + PIERCE(cx, wrapper, GET, + NOTHING, + JSWrapper::enumerate(cx, wrapper, props), + call.origin->wrap(cx, props)); +} + +bool +JSCrossCompartmentWrapper::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) +{ + PIERCE(cx, wrapper, GET, + call.destination->wrapId(cx, &id), + JSWrapper::has(cx, wrapper, id, bp), + NOTHING); +} + +bool +JSCrossCompartmentWrapper::hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) +{ + PIERCE(cx, wrapper, GET, + call.destination->wrapId(cx, &id), + JSWrapper::hasOwn(cx, wrapper, id, bp), + NOTHING); +} + +bool +JSCrossCompartmentWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp) +{ + PIERCE(cx, wrapper, GET, + call.destination->wrap(cx, &receiver) && call.destination->wrapId(cx, &id), + JSWrapper::get(cx, wrapper, receiver, id, vp), + call.origin->wrap(cx, vp)); +} + +bool +JSCrossCompartmentWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, + bool strict, Value *vp) +{ + AutoValueRooter tvr(cx, *vp); + PIERCE(cx, wrapper, SET, + call.destination->wrap(cx, &receiver) && + call.destination->wrapId(cx, &id) && + call.destination->wrap(cx, tvr.addr()), + JSWrapper::set(cx, wrapper, receiver, id, strict, tvr.addr()), + NOTHING); +} + +bool +JSCrossCompartmentWrapper::keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props) +{ + PIERCE(cx, wrapper, GET, + NOTHING, + JSWrapper::keys(cx, wrapper, props), + call.origin->wrap(cx, props)); +} + +/* + * We can reify non-escaping iterator objects instead of having to wrap them. This + * allows fast iteration over objects across a compartment boundary. + */ +static bool +CanReify(Value *vp) +{ + JSObject *obj; + return vp->isObject() && + (obj = &vp->toObject())->getClass() == &js_IteratorClass && + (obj->getNativeIterator()->flags & JSITER_ENUMERATE); +} + +struct AutoCloseIterator +{ + AutoCloseIterator(JSContext *cx, JSObject *obj) : cx(cx), obj(obj) {} + + ~AutoCloseIterator() { if (obj) js_CloseIterator(cx, obj); } + + void clear() { obj = NULL; } + + private: + JSContext *cx; + JSObject *obj; +}; + +static bool +Reify(JSContext *cx, JSCompartment *origin, Value *vp) +{ + JSObject *iterObj = &vp->toObject(); + NativeIterator *ni = iterObj->getNativeIterator(); + + AutoCloseIterator close(cx, iterObj); + + /* Wrap the iteratee. */ + JSObject *obj = ni->obj; + if (!origin->wrap(cx, &obj)) + return false; + + /* + * Wrap the elements in the iterator's snapshot. + * N.B. the order of closing/creating iterators is important due to the + * implicit cx->enumerators state. + */ + size_t length = ni->numKeys(); + bool isKeyIter = ni->isKeyIter(); + AutoIdVector keys(cx); + if (length > 0) { + if (!keys.resize(length)) + return false; + for (size_t i = 0; i < length; ++i) { + keys[i] = ni->begin()[i]; + if (!origin->wrapId(cx, &keys[i])) + return false; + } + } + + close.clear(); + if (!js_CloseIterator(cx, iterObj)) + return false; + + if (isKeyIter) + return VectorToKeyIterator(cx, obj, ni->flags, keys, vp); + return VectorToValueIterator(cx, obj, ni->flags, keys, vp); +} + +bool +JSCrossCompartmentWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, Value *vp) +{ + PIERCE(cx, wrapper, GET, + NOTHING, + JSWrapper::iterate(cx, wrapper, flags, vp), + CanReify(vp) ? Reify(cx, call.origin, vp) : call.origin->wrap(cx, vp)); +} + +bool +JSCrossCompartmentWrapper::call(JSContext *cx, JSObject *wrapper, uintN argc, Value *vp) +{ + AutoCompartment call(cx, wrappedObject(wrapper)); + if (!call.enter()) + return false; + + vp[0] = ObjectValue(*call.target); + if (!call.destination->wrap(cx, &vp[1])) + return false; + Value *argv = JS_ARGV(cx, vp); + for (size_t n = 0; n < argc; ++n) { + if (!call.destination->wrap(cx, &argv[n])) + return false; + } + if (!JSWrapper::call(cx, wrapper, argc, vp)) + return false; + + call.leave(); + return call.origin->wrap(cx, vp); +} + +bool +JSCrossCompartmentWrapper::construct(JSContext *cx, JSObject *wrapper, uintN argc, Value *argv, + Value *rval) +{ + AutoCompartment call(cx, wrappedObject(wrapper)); + if (!call.enter()) + return false; + + for (size_t n = 0; n < argc; ++n) { + if (!call.destination->wrap(cx, &argv[n])) + return false; + } + if (!JSWrapper::construct(cx, wrapper, argc, argv, rval)) + return false; + + call.leave(); + return call.origin->wrap(cx, rval); +} + +bool +JSCrossCompartmentWrapper::hasInstance(JSContext *cx, JSObject *wrapper, const Value *vp, bool *bp) +{ + AutoCompartment call(cx, wrappedObject(wrapper)); + if (!call.enter()) + return false; + + Value v = *vp; + if (!call.destination->wrap(cx, &v)) + return false; + return JSWrapper::hasInstance(cx, wrapper, &v, bp); +} + +JSString * +JSCrossCompartmentWrapper::obj_toString(JSContext *cx, JSObject *wrapper) +{ + AutoCompartment call(cx, wrappedObject(wrapper)); + if (!call.enter()) + return NULL; + + JSString *str = JSWrapper::obj_toString(cx, wrapper); + if (!str) + return NULL; + + call.leave(); + if (!call.origin->wrap(cx, &str)) + return NULL; + return str; +} + +JSString * +JSCrossCompartmentWrapper::fun_toString(JSContext *cx, JSObject *wrapper, uintN indent) +{ + AutoCompartment call(cx, wrappedObject(wrapper)); + if (!call.enter()) + return NULL; + + JSString *str = JSWrapper::fun_toString(cx, wrapper, indent); + if (!str) + return NULL; + + call.leave(); + if (!call.origin->wrap(cx, &str)) + return NULL; + return str; +} + +JSCrossCompartmentWrapper JSCrossCompartmentWrapper::singleton(0u); diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h new file mode 100644 index 0000000..23514ff --- /dev/null +++ b/js/src/jswrapper.h @@ -0,0 +1,193 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Andreas Gal + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jswrapper_h___ +#define jswrapper_h___ + +#include "jsapi.h" +#include "jsproxy.h" + +JS_BEGIN_EXTERN_C + +/* No-op wrapper handler base class. */ +class JS_FRIEND_API(JSWrapper) : public js::JSProxyHandler { + uintN mFlags; + public: + uintN flags() const { return mFlags; } + + explicit JSWrapper(uintN flags); + + typedef enum { PermitObjectAccess, PermitPropertyAccess, DenyAccess } Permission; + + virtual ~JSWrapper(); + + /* ES5 Harmony fundamental wrapper traps. */ + virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set, + js::PropertyDescriptor *desc); + virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set, + js::PropertyDescriptor *desc); + virtual bool defineProperty(JSContext *cx, JSObject *wrapper, jsid id, + js::PropertyDescriptor *desc); + virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); + virtual bool delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); + virtual bool enumerate(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); + virtual bool fix(JSContext *cx, JSObject *wrapper, js::Value *vp); + + /* ES5 Harmony derived wrapper traps. */ + virtual bool has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); + virtual bool hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); + virtual bool get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, js::Value *vp); + virtual bool set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, bool strict, + js::Value *vp); + virtual bool keys(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); + virtual bool iterate(JSContext *cx, JSObject *wrapper, uintN flags, js::Value *vp); + + /* Spidermonkey extensions. */ + virtual bool call(JSContext *cx, JSObject *wrapper, uintN argc, js::Value *vp); + virtual bool construct(JSContext *cx, JSObject *wrapper, uintN argc, js::Value *argv, + js::Value *rval); + virtual bool hasInstance(JSContext *cx, JSObject *wrapper, const js::Value *vp, bool *bp); + virtual JSType typeOf(JSContext *cx, JSObject *proxy); + virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper); + virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, uintN indent); + + virtual void trace(JSTracer *trc, JSObject *wrapper); + + /* Policy enforcement traps. */ + enum Action { GET, SET, CALL }; + virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Action act, bool *bp); + virtual void leave(JSContext *cx, JSObject *wrapper); + + static JSWrapper singleton; + + static JSObject *New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, + JSWrapper *handler); + + static inline JSObject *wrappedObject(const JSObject *wrapper) { + return wrapper->getProxyPrivate().toObjectOrNull(); + } + static inline JSWrapper *wrapperHandler(const JSObject *wrapper) { + return static_cast(wrapper->getProxyHandler()); + } + + enum { + CROSS_COMPARTMENT = 1 << 0, + LAST_USED_FLAG = CROSS_COMPARTMENT + }; + + static void *getWrapperFamily(); +}; + +/* Base class for all cross compartment wrapper handlers. */ +class JS_FRIEND_API(JSCrossCompartmentWrapper) : public JSWrapper { + public: + JSCrossCompartmentWrapper(uintN flags); + + virtual ~JSCrossCompartmentWrapper(); + + /* ES5 Harmony fundamental wrapper traps. */ + virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set, + js::PropertyDescriptor *desc); + virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set, + js::PropertyDescriptor *desc); + virtual bool defineProperty(JSContext *cx, JSObject *wrapper, jsid id, + js::PropertyDescriptor *desc); + virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); + virtual bool delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); + virtual bool enumerate(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); + + /* ES5 Harmony derived wrapper traps. */ + virtual bool has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); + virtual bool hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); + virtual bool get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, js::Value *vp); + virtual bool set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, bool strict, + js::Value *vp); + virtual bool keys(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); + virtual bool iterate(JSContext *cx, JSObject *wrapper, uintN flags, js::Value *vp); + + /* Spidermonkey extensions. */ + virtual bool call(JSContext *cx, JSObject *wrapper, uintN argc, js::Value *vp); + virtual bool construct(JSContext *cx, JSObject *wrapper, + uintN argc, js::Value *argv, js::Value *rval); + virtual bool hasInstance(JSContext *cx, JSObject *wrapper, const js::Value *vp, bool *bp); + virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper); + virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, uintN indent); + + static JSCrossCompartmentWrapper singleton; +}; + +namespace js { + +class AutoCompartment +{ + public: + JSContext * const context; + JSCompartment * const origin; + JSObject * const target; + JSCompartment * const destination; + private: + LazilyConstructed frame; + JSFrameRegs regs; + AutoStringRooter input; + bool entered; + + public: + AutoCompartment(JSContext *cx, JSObject *target); + ~AutoCompartment(); + + bool enter(); + void leave(); + + private: + // Prohibit copying. + AutoCompartment(const AutoCompartment &); + AutoCompartment & operator=(const AutoCompartment &); +}; + +extern JSObject * +TransparentObjectWrapper(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSObject *parent, + uintN flags); + +} + +JS_END_EXTERN_C + +#endif diff --git a/js/src/jsxdrapi.cpp b/js/src/jsxdrapi.cpp new file mode 100644 index 0000000..ae802af --- /dev/null +++ b/js/src/jsxdrapi.cpp @@ -0,0 +1,797 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsversion.h" + +#if JS_HAS_XDR + +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsutil.h" +#include "jsdhash.h" +#include "jsprf.h" +#include "jsapi.h" +#include "jscntxt.h" +#include "jsnum.h" +#include "jsobj.h" /* js_XDRObject */ +#include "jsscript.h" /* js_XDRScript */ +#include "jsstr.h" +#include "jsxdrapi.h" + +#include "jsobjinlines.h" + +using namespace js; + +#ifdef DEBUG +#define DBG(x) x +#else +#define DBG(x) ((void)0) +#endif + +typedef struct JSXDRMemState { + JSXDRState state; + char *base; + uint32 count; + uint32 limit; +} JSXDRMemState; + +#define MEM_BLOCK 8192 +#define MEM_PRIV(xdr) ((JSXDRMemState *)(xdr)) + +#define MEM_BASE(xdr) (MEM_PRIV(xdr)->base) +#define MEM_COUNT(xdr) (MEM_PRIV(xdr)->count) +#define MEM_LIMIT(xdr) (MEM_PRIV(xdr)->limit) + +#define MEM_LEFT(xdr, bytes) \ + JS_BEGIN_MACRO \ + if ((xdr)->mode == JSXDR_DECODE && \ + MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \ + JS_ReportErrorNumber((xdr)->cx, js_GetErrorMessage, NULL, \ + JSMSG_END_OF_DATA); \ + return 0; \ + } \ + JS_END_MACRO + +#define MEM_NEED(xdr, bytes) \ + JS_BEGIN_MACRO \ + if ((xdr)->mode == JSXDR_ENCODE) { \ + if (MEM_LIMIT(xdr) && \ + MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \ + uint32 limit_ = JS_ROUNDUP(MEM_COUNT(xdr) + bytes, MEM_BLOCK);\ + void *data_ = (xdr)->cx->realloc(MEM_BASE(xdr), limit_); \ + if (!data_) \ + return 0; \ + MEM_BASE(xdr) = (char *) data_; \ + MEM_LIMIT(xdr) = limit_; \ + } \ + } else { \ + MEM_LEFT(xdr, bytes); \ + } \ + JS_END_MACRO + +#define MEM_DATA(xdr) ((void *)(MEM_BASE(xdr) + MEM_COUNT(xdr))) +#define MEM_INCR(xdr,bytes) (MEM_COUNT(xdr) += (bytes)) + +static JSBool +mem_get32(JSXDRState *xdr, uint32 *lp) +{ + MEM_LEFT(xdr, 4); + *lp = *(uint32 *)MEM_DATA(xdr); + MEM_INCR(xdr, 4); + return JS_TRUE; +} + +static JSBool +mem_set32(JSXDRState *xdr, uint32 *lp) +{ + MEM_NEED(xdr, 4); + *(uint32 *)MEM_DATA(xdr) = *lp; + MEM_INCR(xdr, 4); + return JS_TRUE; +} + +static JSBool +mem_getbytes(JSXDRState *xdr, char *bytes, uint32 len) +{ + MEM_LEFT(xdr, len); + memcpy(bytes, MEM_DATA(xdr), len); + MEM_INCR(xdr, len); + return JS_TRUE; +} + +static JSBool +mem_setbytes(JSXDRState *xdr, char *bytes, uint32 len) +{ + MEM_NEED(xdr, len); + memcpy(MEM_DATA(xdr), bytes, len); + MEM_INCR(xdr, len); + return JS_TRUE; +} + +static void * +mem_raw(JSXDRState *xdr, uint32 len) +{ + void *data; + if (xdr->mode == JSXDR_ENCODE) { + MEM_NEED(xdr, len); + } else if (xdr->mode == JSXDR_DECODE) { + MEM_LEFT(xdr, len); + } + data = MEM_DATA(xdr); + MEM_INCR(xdr, len); + return data; +} + +static JSBool +mem_seek(JSXDRState *xdr, int32 offset, JSXDRWhence whence) +{ + switch (whence) { + case JSXDR_SEEK_CUR: + if ((int32)MEM_COUNT(xdr) + offset < 0) { + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_SEEK_BEYOND_START); + return JS_FALSE; + } + if (offset > 0) + MEM_NEED(xdr, offset); + MEM_COUNT(xdr) += offset; + return JS_TRUE; + case JSXDR_SEEK_SET: + if (offset < 0) { + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_SEEK_BEYOND_START); + return JS_FALSE; + } + if (xdr->mode == JSXDR_ENCODE) { + if ((uint32)offset > MEM_COUNT(xdr)) + MEM_NEED(xdr, offset - MEM_COUNT(xdr)); + MEM_COUNT(xdr) = offset; + } else { + if ((uint32)offset > MEM_LIMIT(xdr)) { + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_SEEK_BEYOND_END); + return JS_FALSE; + } + MEM_COUNT(xdr) = offset; + } + return JS_TRUE; + case JSXDR_SEEK_END: + if (offset >= 0 || + xdr->mode == JSXDR_ENCODE || + (int32)MEM_LIMIT(xdr) + offset < 0) { + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_END_SEEK); + return JS_FALSE; + } + MEM_COUNT(xdr) = MEM_LIMIT(xdr) + offset; + return JS_TRUE; + default: { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%d", whence); + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_WHITHER_WHENCE, numBuf); + return JS_FALSE; + } + } +} + +static uint32 +mem_tell(JSXDRState *xdr) +{ + return MEM_COUNT(xdr); +} + +static void +mem_finalize(JSXDRState *xdr) +{ + xdr->cx->free(MEM_BASE(xdr)); +} + +static JSXDROps xdrmem_ops = { + mem_get32, mem_set32, mem_getbytes, mem_setbytes, + mem_raw, mem_seek, mem_tell, mem_finalize +}; + +JS_PUBLIC_API(void) +JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx) +{ + xdr->mode = mode; + xdr->cx = cx; + xdr->registry = NULL; + xdr->numclasses = xdr->maxclasses = 0; + xdr->reghash = NULL; + xdr->userdata = NULL; + xdr->script = NULL; +} + +JS_PUBLIC_API(JSXDRState *) +JS_XDRNewMem(JSContext *cx, JSXDRMode mode) +{ + JSXDRState *xdr = (JSXDRState *) cx->malloc(sizeof(JSXDRMemState)); + if (!xdr) + return NULL; + JS_XDRInitBase(xdr, mode, cx); + if (mode == JSXDR_ENCODE) { + if (!(MEM_BASE(xdr) = (char *) cx->malloc(MEM_BLOCK))) { + cx->free(xdr); + return NULL; + } + } else { + /* XXXbe ok, so better not deref MEM_BASE(xdr) if not ENCODE */ + MEM_BASE(xdr) = NULL; + } + xdr->ops = &xdrmem_ops; + MEM_COUNT(xdr) = 0; + MEM_LIMIT(xdr) = MEM_BLOCK; + return xdr; +} + +JS_PUBLIC_API(void *) +JS_XDRMemGetData(JSXDRState *xdr, uint32 *lp) +{ + if (xdr->ops != &xdrmem_ops) + return NULL; + *lp = MEM_COUNT(xdr); + return MEM_BASE(xdr); +} + +JS_PUBLIC_API(void) +JS_XDRMemSetData(JSXDRState *xdr, void *data, uint32 len) +{ + if (xdr->ops != &xdrmem_ops) + return; + MEM_LIMIT(xdr) = len; + MEM_BASE(xdr) = (char *) data; + MEM_COUNT(xdr) = 0; +} + +JS_PUBLIC_API(uint32) +JS_XDRMemDataLeft(JSXDRState *xdr) +{ + if (xdr->ops != &xdrmem_ops) + return 0; + return MEM_LIMIT(xdr) - MEM_COUNT(xdr); +} + +JS_PUBLIC_API(void) +JS_XDRMemResetData(JSXDRState *xdr) +{ + if (xdr->ops != &xdrmem_ops) + return; + MEM_COUNT(xdr) = 0; +} + +JS_PUBLIC_API(void) +JS_XDRDestroy(JSXDRState *xdr) +{ + JSContext *cx = xdr->cx; + xdr->ops->finalize(xdr); + if (xdr->registry) { + cx->free(xdr->registry); + if (xdr->reghash) + JS_DHashTableDestroy((JSDHashTable *) xdr->reghash); + } + cx->free(xdr); +} + +JS_PUBLIC_API(JSBool) +JS_XDRUint8(JSXDRState *xdr, uint8 *b) +{ + uint32 l = *b; + if (!JS_XDRUint32(xdr, &l)) + return JS_FALSE; + *b = (uint8) l; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_XDRUint16(JSXDRState *xdr, uint16 *s) +{ + uint32 l = *s; + if (!JS_XDRUint32(xdr, &l)) + return JS_FALSE; + *s = (uint16) l; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_XDRUint32(JSXDRState *xdr, uint32 *lp) +{ + JSBool ok = JS_TRUE; + if (xdr->mode == JSXDR_ENCODE) { + uint32 xl = JSXDR_SWAB32(*lp); + ok = xdr->ops->set32(xdr, &xl); + } else if (xdr->mode == JSXDR_DECODE) { + ok = xdr->ops->get32(xdr, lp); + *lp = JSXDR_SWAB32(*lp); + } + return ok; +} + +JS_PUBLIC_API(JSBool) +JS_XDRBytes(JSXDRState *xdr, char *bytes, uint32 len) +{ + uint32 padlen; + static char padbuf[JSXDR_ALIGN-1]; + + if (xdr->mode == JSXDR_ENCODE) { + if (!xdr->ops->setbytes(xdr, bytes, len)) + return JS_FALSE; + } else { + if (!xdr->ops->getbytes(xdr, bytes, len)) + return JS_FALSE; + } + len = xdr->ops->tell(xdr); + if (len % JSXDR_ALIGN) { + padlen = JSXDR_ALIGN - (len % JSXDR_ALIGN); + if (xdr->mode == JSXDR_ENCODE) { + if (!xdr->ops->setbytes(xdr, padbuf, padlen)) + return JS_FALSE; + } else { + if (!xdr->ops->seek(xdr, padlen, JSXDR_SEEK_CUR)) + return JS_FALSE; + } + } + return JS_TRUE; +} + +/** + * Convert between a C string and the XDR representation: + * leading 32-bit count, then counted vector of chars, + * then possibly \0 padding to multiple of 4. + */ +JS_PUBLIC_API(JSBool) +JS_XDRCString(JSXDRState *xdr, char **sp) +{ + uint32 len; + + if (xdr->mode == JSXDR_ENCODE) + len = strlen(*sp); + JS_XDRUint32(xdr, &len); + if (xdr->mode == JSXDR_DECODE) { + if (!(*sp = (char *) xdr->cx->malloc(len + 1))) + return JS_FALSE; + } + if (!JS_XDRBytes(xdr, *sp, len)) { + if (xdr->mode == JSXDR_DECODE) + xdr->cx->free(*sp); + return JS_FALSE; + } + if (xdr->mode == JSXDR_DECODE) { + (*sp)[len] = '\0'; + } else if (xdr->mode == JSXDR_FREE) { + xdr->cx->free(*sp); + *sp = NULL; + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_XDRCStringOrNull(JSXDRState *xdr, char **sp) +{ + uint32 null = (*sp == NULL); + if (!JS_XDRUint32(xdr, &null)) + return JS_FALSE; + if (null) { + *sp = NULL; + return JS_TRUE; + } + return JS_XDRCString(xdr, sp); +} + +static JSBool +XDRChars(JSXDRState *xdr, jschar *chars, uint32 nchars) +{ + uint32 i, padlen, nbytes; + jschar *raw; + + nbytes = nchars * sizeof(jschar); + padlen = nbytes % JSXDR_ALIGN; + if (padlen) { + padlen = JSXDR_ALIGN - padlen; + nbytes += padlen; + } + if (!(raw = (jschar *) xdr->ops->raw(xdr, nbytes))) + return JS_FALSE; + if (xdr->mode == JSXDR_ENCODE) { + for (i = 0; i != nchars; i++) + raw[i] = JSXDR_SWAB16(chars[i]); + if (padlen) + memset((char *)raw + nbytes - padlen, 0, padlen); + } else if (xdr->mode == JSXDR_DECODE) { + for (i = 0; i != nchars; i++) + chars[i] = JSXDR_SWAB16(raw[i]); + } + return JS_TRUE; +} + +/* + * Convert between a JS (Unicode) string and the XDR representation. + */ +JS_PUBLIC_API(JSBool) +JS_XDRString(JSXDRState *xdr, JSString **strp) +{ + uint32 nchars; + jschar *chars; + + if (xdr->mode == JSXDR_ENCODE) + nchars = (*strp)->length(); + if (!JS_XDRUint32(xdr, &nchars)) + return JS_FALSE; + + if (xdr->mode == JSXDR_DECODE) + chars = (jschar *) xdr->cx->malloc((nchars + 1) * sizeof(jschar)); + else + chars = const_cast((*strp)->getChars(xdr->cx)); + if (!chars) + return JS_FALSE; + + if (!XDRChars(xdr, chars, nchars)) + goto bad; + if (xdr->mode == JSXDR_DECODE) { + chars[nchars] = 0; + *strp = JS_NewUCString(xdr->cx, chars, nchars); + if (!*strp) + goto bad; + } + return JS_TRUE; + +bad: + if (xdr->mode == JSXDR_DECODE) + xdr->cx->free(chars); + return JS_FALSE; +} + +JS_PUBLIC_API(JSBool) +JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp) +{ + uint32 null = (*strp == NULL); + if (!JS_XDRUint32(xdr, &null)) + return JS_FALSE; + if (null) { + *strp = NULL; + return JS_TRUE; + } + return JS_XDRString(xdr, strp); +} + +static JSBool +XDRDoubleValue(JSXDRState *xdr, jsdouble *dp) +{ + jsdpun u; + + u.d = (xdr->mode == JSXDR_ENCODE) ? *dp : 0.0; + if (!JS_XDRUint32(xdr, &u.s.lo) || !JS_XDRUint32(xdr, &u.s.hi)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *dp = u.d; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_XDRDouble(JSXDRState *xdr, jsdouble *dp) +{ + jsdouble d = (xdr->mode == JSXDR_ENCODE) ? *dp : 0.0; + if (!XDRDoubleValue(xdr, &d)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *dp = d; + return JS_TRUE; +} + +enum XDRValueTag { + XDRTAG_OBJECT = 0, + XDRTAG_INT = 1, + XDRTAG_DOUBLE = 2, + XDRTAG_STRING = 3, + XDRTAG_SPECIAL = 4, + XDRTAG_XDRNULL = 5, + XDRTAG_XDRVOID = 6 +}; + +static XDRValueTag +GetXDRTag(jsval v) +{ + if (JSVAL_IS_NULL(v)) + return XDRTAG_XDRNULL; + if (JSVAL_IS_VOID(v)) + return XDRTAG_XDRVOID; + if (JSVAL_IS_OBJECT(v)) + return XDRTAG_OBJECT; + if (JSVAL_IS_INT(v)) + return XDRTAG_INT; + if (JSVAL_IS_DOUBLE(v)) + return XDRTAG_DOUBLE; + if (JSVAL_IS_STRING(v)) + return XDRTAG_STRING; + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + return XDRTAG_SPECIAL; +} + +static JSBool +XDRValueBody(JSXDRState *xdr, uint32 type, jsval *vp) +{ + switch (type) { + case XDRTAG_XDRNULL: + *vp = JSVAL_NULL; + break; + case XDRTAG_XDRVOID: + *vp = JSVAL_VOID; + break; + case XDRTAG_STRING: { + JSString *str; + if (xdr->mode == JSXDR_ENCODE) + str = JSVAL_TO_STRING(*vp); + if (!JS_XDRString(xdr, &str)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *vp = STRING_TO_JSVAL(str); + break; + } + case XDRTAG_DOUBLE: { + double d = xdr->mode == JSXDR_ENCODE ? JSVAL_TO_DOUBLE(*vp) : 0; + if (!JS_XDRDouble(xdr, &d)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *vp = DOUBLE_TO_JSVAL(d); + break; + } + case XDRTAG_OBJECT: { + JSObject *obj; + if (xdr->mode == JSXDR_ENCODE) + obj = JSVAL_TO_OBJECT(*vp); + if (!js_XDRObject(xdr, &obj)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *vp = OBJECT_TO_JSVAL(obj); + break; + } + case XDRTAG_SPECIAL: { + uint32 b; + if (xdr->mode == JSXDR_ENCODE) + b = (uint32) JSVAL_TO_BOOLEAN(*vp); + if (!JS_XDRUint32(xdr, &b)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *vp = BOOLEAN_TO_JSVAL(!!b); + break; + } + default: { + uint32 i; + + JS_ASSERT(type == XDRTAG_INT); + if (xdr->mode == JSXDR_ENCODE) + i = (uint32) JSVAL_TO_INT(*vp); + if (!JS_XDRUint32(xdr, &i)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *vp = INT_TO_JSVAL((int32) i); + break; + } + } + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_XDRValue(JSXDRState *xdr, jsval *vp) +{ + uint32 type; + + if (xdr->mode == JSXDR_ENCODE) + type = GetXDRTag(*vp); + return JS_XDRUint32(xdr, &type) && XDRValueBody(xdr, type, vp); +} + +extern JSBool +js_XDRAtom(JSXDRState *xdr, JSAtom **atomp) +{ + JSString *str; + uint32 nchars; + JSAtom *atom; + JSContext *cx; + jschar *chars; + jschar stackChars[256]; + + if (xdr->mode == JSXDR_ENCODE) { + str = ATOM_TO_STRING(*atomp); + return JS_XDRString(xdr, &str); + } + + /* + * Inline JS_XDRString when decoding to avoid JSString allocation + * for already existing atoms. See bug 321985. + */ + if (!JS_XDRUint32(xdr, &nchars)) + return JS_FALSE; + atom = NULL; + cx = xdr->cx; + if (nchars <= JS_ARRAY_LENGTH(stackChars)) { + chars = stackChars; + } else { + /* + * This is very uncommon. Don't use the tempPool arena for this as + * most allocations here will be bigger than tempPool's arenasize. + */ + chars = (jschar *) cx->malloc(nchars * sizeof(jschar)); + if (!chars) + return JS_FALSE; + } + + if (XDRChars(xdr, chars, nchars)) + atom = js_AtomizeChars(cx, chars, nchars, 0); + if (chars != stackChars) + cx->free(chars); + + if (!atom) + return JS_FALSE; + *atomp = atom; + return JS_TRUE; +} + +JS_PUBLIC_API(JSBool) +JS_XDRScriptObject(JSXDRState *xdr, JSObject **scriptObjp) +{ + JSScript *script; + if (xdr->mode == JSXDR_DECODE) { + script = NULL; + *scriptObjp = NULL; + } else { + script = (*scriptObjp)->getScript(); + } + + if (!js_XDRScript(xdr, &script, NULL)) + return false; + + if (xdr->mode == JSXDR_DECODE) { + js_CallNewScriptHook(xdr->cx, script, NULL); + *scriptObjp = js_NewScriptObject(xdr->cx, script); + if (!*scriptObjp) { + js_DestroyScript(xdr->cx, script); + return false; + } + } + + return true; +} + +#define CLASS_REGISTRY_MIN 8 +#define CLASS_INDEX_TO_ID(i) ((i)+1) +#define CLASS_ID_TO_INDEX(id) ((id)-1) + +typedef struct JSRegHashEntry { + JSDHashEntryHdr hdr; + const char *name; + uint32 index; +} JSRegHashEntry; + +JS_PUBLIC_API(JSBool) +JS_XDRRegisterClass(JSXDRState *xdr, JSClass *clasp, uint32 *idp) +{ + uintN numclasses, maxclasses; + JSClass **registry; + + numclasses = xdr->numclasses; + maxclasses = xdr->maxclasses; + if (numclasses == maxclasses) { + maxclasses = (maxclasses == 0) ? CLASS_REGISTRY_MIN : maxclasses << 1; + registry = (JSClass **) + xdr->cx->realloc(xdr->registry, maxclasses * sizeof(JSClass *)); + if (!registry) + return JS_FALSE; + xdr->registry = registry; + xdr->maxclasses = maxclasses; + } else { + JS_ASSERT(numclasses && numclasses < maxclasses); + registry = xdr->registry; + } + + registry[numclasses] = clasp; + if (xdr->reghash) { + JSRegHashEntry *entry = (JSRegHashEntry *) + JS_DHashTableOperate((JSDHashTable *) xdr->reghash, + clasp->name, JS_DHASH_ADD); + if (!entry) { + JS_ReportOutOfMemory(xdr->cx); + return JS_FALSE; + } + entry->name = clasp->name; + entry->index = numclasses; + } + *idp = CLASS_INDEX_TO_ID(numclasses); + xdr->numclasses = ++numclasses; + return JS_TRUE; +} + +JS_PUBLIC_API(uint32) +JS_XDRFindClassIdByName(JSXDRState *xdr, const char *name) +{ + uintN i, numclasses; + + numclasses = xdr->numclasses; + if (numclasses >= 10) { + JSRegHashEntry *entry; + + /* Bootstrap reghash from registry on first overpopulated Find. */ + if (!xdr->reghash) { + xdr->reghash = + JS_NewDHashTable(JS_DHashGetStubOps(), NULL, + sizeof(JSRegHashEntry), + JS_DHASH_DEFAULT_CAPACITY(numclasses)); + if (xdr->reghash) { + for (i = 0; i < numclasses; i++) { + JSClass *clasp = xdr->registry[i]; + entry = (JSRegHashEntry *) + JS_DHashTableOperate((JSDHashTable *) xdr->reghash, + clasp->name, JS_DHASH_ADD); + entry->name = clasp->name; + entry->index = i; + } + } + } + + /* If we managed to create reghash, use it for O(1) Find. */ + if (xdr->reghash) { + entry = (JSRegHashEntry *) + JS_DHashTableOperate((JSDHashTable *) xdr->reghash, + name, JS_DHASH_LOOKUP); + if (JS_DHASH_ENTRY_IS_BUSY(&entry->hdr)) + return CLASS_INDEX_TO_ID(entry->index); + } + } + + /* Only a few classes, or we couldn't malloc reghash: use linear search. */ + for (i = 0; i < numclasses; i++) { + if (!strcmp(name, xdr->registry[i]->name)) + return CLASS_INDEX_TO_ID(i); + } + return 0; +} + +JS_PUBLIC_API(JSClass *) +JS_XDRFindClassById(JSXDRState *xdr, uint32 id) +{ + uintN i = CLASS_ID_TO_INDEX(id); + + if (i >= xdr->numclasses) + return NULL; + return xdr->registry[i]; +} + +#endif /* JS_HAS_XDR */ diff --git a/js/src/jsxdrapi.h b/js/src/jsxdrapi.h new file mode 100644 index 0000000..600c3d9 --- /dev/null +++ b/js/src/jsxdrapi.h @@ -0,0 +1,219 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsxdrapi_h___ +#define jsxdrapi_h___ + +/* + * JS external data representation interface API. + * + * The XDR system is comprised of three major parts: + * + * - the state serialization/deserialization APIs, which allow consumers + * of the API to serialize JS runtime state (script bytecodes, atom maps, + * object graphs, etc.) for later restoration. These portions + * are implemented in various appropriate files, such as jsscript.c + * for the script portions and jsobj.c for object state. + * - the callback APIs through which the runtime requests an opaque + * representation of a native object, and through which the runtime + * constructs a live native object from an opaque representation. These + * portions are the responsibility of the native object implementor. + * - utility functions for en/decoding of primitive types, such as + * JSStrings. This portion is implemented in jsxdrapi.c. + * + * Spiritually guided by Sun's XDR, where appropriate. + */ + +#include "jspubtd.h" +#include "jsprvtd.h" + +JS_BEGIN_EXTERN_C + +/* We use little-endian byteorder for all encoded data */ + +#if defined IS_LITTLE_ENDIAN +#define JSXDR_SWAB32(x) x +#define JSXDR_SWAB16(x) x +#elif defined IS_BIG_ENDIAN +#define JSXDR_SWAB32(x) (((uint32)(x) >> 24) | \ + (((uint32)(x) >> 8) & 0xff00) | \ + (((uint32)(x) << 8) & 0xff0000) | \ + ((uint32)(x) << 24)) +#define JSXDR_SWAB16(x) (((uint16)(x) >> 8) | ((uint16)(x) << 8)) +#else +#error "unknown byte order" +#endif + +#define JSXDR_ALIGN 4 + +typedef enum JSXDRMode { + JSXDR_ENCODE, + JSXDR_DECODE, + JSXDR_FREE +} JSXDRMode; + +typedef enum JSXDRWhence { + JSXDR_SEEK_SET, + JSXDR_SEEK_CUR, + JSXDR_SEEK_END +} JSXDRWhence; + +typedef struct JSXDROps { + JSBool (*get32)(JSXDRState *, uint32 *); + JSBool (*set32)(JSXDRState *, uint32 *); + JSBool (*getbytes)(JSXDRState *, char *, uint32); + JSBool (*setbytes)(JSXDRState *, char *, uint32); + void * (*raw)(JSXDRState *, uint32); + JSBool (*seek)(JSXDRState *, int32, JSXDRWhence); + uint32 (*tell)(JSXDRState *); + void (*finalize)(JSXDRState *); +} JSXDROps; + +struct JSXDRState { + JSXDRMode mode; + JSXDROps *ops; + JSContext *cx; + JSClass **registry; + uintN numclasses; + uintN maxclasses; + void *reghash; + void *userdata; + JSScript *script; +}; + +extern JS_PUBLIC_API(void) +JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx); + +extern JS_PUBLIC_API(JSXDRState *) +JS_XDRNewMem(JSContext *cx, JSXDRMode mode); + +extern JS_PUBLIC_API(void *) +JS_XDRMemGetData(JSXDRState *xdr, uint32 *lp); + +extern JS_PUBLIC_API(void) +JS_XDRMemSetData(JSXDRState *xdr, void *data, uint32 len); + +extern JS_PUBLIC_API(uint32) +JS_XDRMemDataLeft(JSXDRState *xdr); + +extern JS_PUBLIC_API(void) +JS_XDRMemResetData(JSXDRState *xdr); + +extern JS_PUBLIC_API(void) +JS_XDRDestroy(JSXDRState *xdr); + +extern JS_PUBLIC_API(JSBool) +JS_XDRUint8(JSXDRState *xdr, uint8 *b); + +extern JS_PUBLIC_API(JSBool) +JS_XDRUint16(JSXDRState *xdr, uint16 *s); + +extern JS_PUBLIC_API(JSBool) +JS_XDRUint32(JSXDRState *xdr, uint32 *lp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRBytes(JSXDRState *xdr, char *bytes, uint32 len); + +extern JS_PUBLIC_API(JSBool) +JS_XDRCString(JSXDRState *xdr, char **sp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRCStringOrNull(JSXDRState *xdr, char **sp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRString(JSXDRState *xdr, JSString **strp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRDouble(JSXDRState *xdr, jsdouble *dp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRValue(JSXDRState *xdr, jsval *vp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRScriptObject(JSXDRState *xdr, JSObject **scriptObjp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRRegisterClass(JSXDRState *xdr, JSClass *clasp, uint32 *lp); + +extern JS_PUBLIC_API(uint32) +JS_XDRFindClassIdByName(JSXDRState *xdr, const char *name); + +extern JS_PUBLIC_API(JSClass *) +JS_XDRFindClassById(JSXDRState *xdr, uint32 id); + +/* + * Magic numbers. + */ +#define JSXDR_MAGIC_SCRIPT_1 0xdead0001 +#define JSXDR_MAGIC_SCRIPT_2 0xdead0002 +#define JSXDR_MAGIC_SCRIPT_3 0xdead0003 +#define JSXDR_MAGIC_SCRIPT_4 0xdead0004 +#define JSXDR_MAGIC_SCRIPT_5 0xdead0005 +#define JSXDR_MAGIC_SCRIPT_6 0xdead0006 +#define JSXDR_MAGIC_SCRIPT_7 0xdead0007 +#define JSXDR_MAGIC_SCRIPT_8 0xdead0008 +#define JSXDR_MAGIC_SCRIPT_9 0xdead0009 +#define JSXDR_MAGIC_SCRIPT_10 0xdead000a +#define JSXDR_MAGIC_SCRIPT_11 0xdead000b +#define JSXDR_MAGIC_SCRIPT_CURRENT JSXDR_MAGIC_SCRIPT_11 + +/* + * Bytecode version number. Increment the subtrahend whenever JS bytecode + * changes incompatibly. + * + * This version number should be XDR'ed once near the front of any file or + * larger storage unit containing XDR'ed bytecode and other data, and checked + * before deserialization of bytecode. If the saved version does not match + * the current version, abort deserialization and invalidate the file. + */ +#define JSXDR_BYTECODE_VERSION (0xb973c0de - 82) + +/* + * Library-private functions. + */ +extern JSBool +js_XDRAtom(JSXDRState *xdr, JSAtom **atomp); + +JS_END_EXTERN_C + +#endif /* ! jsxdrapi_h___ */ diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp new file mode 100644 index 0000000..7fa3bc1 --- /dev/null +++ b/js/src/jsxml.cpp @@ -0,0 +1,7753 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey E4X code, released August, 2004. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsversion.h" + +#if JS_HAS_XML_SUPPORT + +#include +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsbit.h" +#include "jsprf.h" +#include "jsutil.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsinterp.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsopcode.h" +#include "jsparse.h" +#include "jsscan.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jsstr.h" +#include "jsxml.h" +#include "jsstaticcheck.h" +#include "jsvector.h" + +#include "jsatominlines.h" +#include "jscntxtinlines.h" +#include "jsinterpinlines.h" +#include "jsobjinlines.h" +#include "jsstrinlines.h" + +#ifdef DEBUG +#include /* for #ifdef DEBUG memset calls */ +#endif + +using namespace js; +using namespace js::gc; + +/* + * NOTES + * - in the js shell, you must use the -x command line option, or call + * options('xml') before compiling anything that uses XML literals + * + * TODO + * - XXXbe patrol + * - Fuse objects and their JSXML* private data into single GC-things + * - fix function::foo vs. x.(foo == 42) collision using proper namespacing + * - JSCLASS_DOCUMENT_OBSERVER support -- live two-way binding to Gecko's DOM! + */ + +static inline bool +js_EnterLocalRootScope(JSContext *cx) +{ + return true; +} + +static inline void +js_LeaveLocalRootScope(JSContext *cx) +{ +} + +static inline void +js_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval) +{ +} + +static inline void +js_LeaveLocalRootScopeWithResult(JSContext *cx, Value rval) +{ +} + +static inline void +js_LeaveLocalRootScopeWithResult(JSContext *cx, void *rval) +{ +} + +#ifdef XML_METERING +static struct { + jsrefcount qname; + jsrefcount xmlnamespace; + jsrefcount xml; + jsrefcount xmlobj; +} xml_stats; + +#define METER(x) JS_ATOMIC_INCREMENT(&(x)) +#define UNMETER(x) JS_ATOMIC_DECREMENT(&(x)) +#else +#define METER(x) /* nothing */ +#define UNMETER(x) /* nothing */ +#endif + +/* + * Random utilities and global functions. + */ +const char js_AttributeName_str[] = "AttributeName"; +const char js_isXMLName_str[] = "isXMLName"; +const char js_XMLList_str[] = "XMLList"; +const char js_localName_str[] = "localName"; +const char js_xml_parent_str[] = "parent"; +const char js_prefix_str[] = "prefix"; +const char js_toXMLString_str[] = "toXMLString"; +const char js_uri_str[] = "uri"; + +const char js_amp_entity_str[] = "&"; +const char js_gt_entity_str[] = ">"; +const char js_lt_entity_str[] = "<"; +const char js_quot_entity_str[] = """; +const char js_leftcurly_entity_str[] = "{"; + +#define IS_STAR(str) ((str)->length() == 1 && *(str)->chars() == '*') + +static JSBool +GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp); + +static JSBool +IsDeclared(const JSObject *obj) +{ + jsval v; + + JS_ASSERT(obj->getClass() == &js_NamespaceClass); + v = obj->getNamespaceDeclared(); + JS_ASSERT(JSVAL_IS_VOID(v) || v == JSVAL_TRUE); + return v == JSVAL_TRUE; +} + +static JSBool +xml_isXMLName(JSContext *cx, uintN argc, jsval *vp) +{ + *vp = BOOLEAN_TO_JSVAL(js_IsXMLName(cx, argc ? vp[2] : JSVAL_VOID)); + return JS_TRUE; +} + +/* + * This wrapper is needed because NewBuiltinClassInstance doesn't + * call the constructor, and we need a place to set the + * HAS_EQUALITY bit. + */ +static inline JSObject * +NewBuiltinClassInstanceXML(JSContext *cx, Class *clasp) +{ + JSObject *obj = NewBuiltinClassInstance(cx, clasp); + if (obj) + obj->syncSpecialEquality(); + return obj; +} + +#define DEFINE_GETTER(name,code) \ + static JSBool \ + name(JSContext *cx, JSObject *obj, jsid id, jsval *vp) \ + { \ + code; \ + return true; \ + } + +/* + * Namespace class and library functions. + */ +DEFINE_GETTER(NamePrefix_getter, + if (obj->getClass() == &js_NamespaceClass) *vp = obj->getNamePrefixVal()) +DEFINE_GETTER(NameURI_getter, + if (obj->getClass() == &js_NamespaceClass) *vp = obj->getNameURIVal()) + +static JSBool +namespace_equality(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp) +{ + JSObject *obj2; + + JS_ASSERT(v->isObjectOrNull()); + obj2 = v->toObjectOrNull(); + *bp = (!obj2 || obj2->getClass() != &js_NamespaceClass) + ? JS_FALSE + : EqualStrings(obj->getNameURI(), obj2->getNameURI()); + return JS_TRUE; +} + +JS_FRIEND_DATA(Class) js_NamespaceClass = { + "Namespace", + JSCLASS_CONSTRUCT_PROTOTYPE | + JSCLASS_HAS_RESERVED_SLOTS(JSObject::NAMESPACE_CLASS_RESERVED_SLOTS) | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Namespace), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub, + FinalizeStub, + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + NULL, /* mark */ + { + namespace_equality, + NULL, /* outerObject */ + NULL, /* innerObject */ + NULL, /* iteratorObject */ + NULL, /* wrappedObject */ + } +}; + +#define NAMESPACE_ATTRS \ + (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED) + +static JSPropertySpec namespace_props[] = { + {js_prefix_str, 0, NAMESPACE_ATTRS, NamePrefix_getter, 0}, + {js_uri_str, 0, NAMESPACE_ATTRS, NameURI_getter, 0}, + {0,0,0,0,0} +}; + +static JSBool +namespace_toString(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return JS_FALSE; + if (!JS_InstanceOf(cx, obj, Jsvalify(&js_NamespaceClass), Jsvalify(vp + 2))) + return JS_FALSE; + *vp = Valueify(obj->getNameURIVal()); + return JS_TRUE; +} + +static JSFunctionSpec namespace_methods[] = { + JS_FN(js_toString_str, namespace_toString, 0,0), + JS_FS_END +}; + +static JSObject * +NewXMLNamespace(JSContext *cx, JSLinearString *prefix, JSLinearString *uri, JSBool declared) +{ + JSObject *obj; + + obj = NewBuiltinClassInstanceXML(cx, &js_NamespaceClass); + if (!obj) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_VOID(obj->getNamePrefixVal())); + JS_ASSERT(JSVAL_IS_VOID(obj->getNameURIVal())); + JS_ASSERT(JSVAL_IS_VOID(obj->getNamespaceDeclared())); + if (prefix) + obj->setNamePrefix(prefix); + if (uri) + obj->setNameURI(uri); + if (declared) + obj->setNamespaceDeclared(JSVAL_TRUE); + METER(xml_stats.xmlnamespace); + return obj; +} + +/* + * QName class and library functions. + */ +DEFINE_GETTER(QNameNameURI_getter, + if (obj->getClass() == &js_QNameClass) + *vp = JSVAL_IS_VOID(obj->getNameURIVal()) ? JSVAL_NULL : obj->getNameURIVal()) +DEFINE_GETTER(QNameLocalName_getter, + if (obj->getClass() == &js_QNameClass) + *vp = obj->getQNameLocalNameVal()) + +static JSBool +qname_identity(JSObject *qna, JSObject *qnb) +{ + JSLinearString *uri1 = qna->getNameURI(); + JSLinearString *uri2 = qnb->getNameURI(); + + if (!uri1 ^ !uri2) + return JS_FALSE; + if (uri1 && !EqualStrings(uri1, uri2)) + return JS_FALSE; + return EqualStrings(qna->getQNameLocalName(), qnb->getQNameLocalName()); +} + +static JSBool +qname_equality(JSContext *cx, JSObject *qn, const Value *v, JSBool *bp) +{ + JSObject *obj2; + + obj2 = v->toObjectOrNull(); + *bp = (!obj2 || obj2->getClass() != &js_QNameClass) + ? JS_FALSE + : qname_identity(qn, obj2); + return JS_TRUE; +} + +JS_FRIEND_DATA(Class) js_QNameClass = { + "QName", + JSCLASS_CONSTRUCT_PROTOTYPE | + JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_CLASS_RESERVED_SLOTS) | + JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_QName), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub, + FinalizeStub, + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + NULL, /* mark */ + { + qname_equality, + NULL, /* outerObject */ + NULL, /* innerObject */ + NULL, /* iteratorObject */ + NULL, /* wrappedObject */ + } +}; + +/* + * Classes for the ECMA-357-internal types AttributeName and AnyName, which + * are like QName, except that they have no property getters. They share the + * qname_toString method, and therefore are exposed as constructable objects + * in this implementation. + */ +JS_FRIEND_DATA(Class) js_AttributeNameClass = { + js_AttributeName_str, + JSCLASS_CONSTRUCT_PROTOTYPE | + JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_CLASS_RESERVED_SLOTS) | + JSCLASS_MARK_IS_TRACE | JSCLASS_IS_ANONYMOUS, + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub, + FinalizeStub +}; + +JS_FRIEND_DATA(Class) js_AnyNameClass = { + js_AnyName_str, + JSCLASS_CONSTRUCT_PROTOTYPE | + JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_CLASS_RESERVED_SLOTS) | + JSCLASS_MARK_IS_TRACE | JSCLASS_IS_ANONYMOUS, + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub, + FinalizeStub +}; + +#define QNAME_ATTRS (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED) + +static JSPropertySpec qname_props[] = { + {js_uri_str, 0, QNAME_ATTRS, QNameNameURI_getter, 0}, + {js_localName_str, 0, QNAME_ATTRS, QNameLocalName_getter, 0}, + {0,0,0,0,0} +}; + +static JSString * +ConvertQNameToString(JSContext *cx, JSObject *obj) +{ + JS_ASSERT(obj->isQName()); + JSString *uri = obj->getNameURI(); + JSString *str; + if (!uri) { + /* No uri means wildcard qualifier. */ + str = ATOM_TO_STRING(cx->runtime->atomState.starQualifierAtom); + } else if (uri->empty()) { + /* Empty string for uri means localName is in no namespace. */ + str = cx->runtime->emptyString; + } else { + JSString *qualstr = ATOM_TO_STRING(cx->runtime->atomState.qualifierAtom); + str = js_ConcatStrings(cx, uri, qualstr); + if (!str) + return NULL; + } + str = js_ConcatStrings(cx, str, obj->getQNameLocalName()); + if (!str) + return NULL; + + if (obj->getClass() == &js_AttributeNameClass) { + JS::Anchor anchor(str); + size_t length = str->length(); + jschar *chars = (jschar *) cx->malloc((length + 2) * sizeof(jschar)); + if (!chars) + return JS_FALSE; + *chars = '@'; + const jschar *strChars = str->getChars(cx); + if (!strChars) { + cx->free(chars); + return NULL; + } + js_strncpy(chars + 1, strChars, length); + chars[++length] = 0; + str = js_NewString(cx, chars, length); + if (!str) { + cx->free(chars); + return NULL; + } + } + return str; +} + +static JSBool +qname_toString(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *obj = ToObject(cx, &vp[1]); + if (!obj) + return false; + + if (!InstanceOf(cx, obj, &js_QNameClass, vp + 2)) + return false; + + JSString *str = ConvertQNameToString(cx, obj); + if (!str) + return false; + + vp->setString(str); + return true; +} + +static JSFunctionSpec qname_methods[] = { + JS_FN(js_toString_str, qname_toString, 0,0), + JS_FS_END +}; + + +static void +InitXMLQName(JSObject *obj, JSLinearString *uri, JSLinearString *prefix, + JSLinearString *localName) +{ + JS_ASSERT(obj->isQName()); + JS_ASSERT(JSVAL_IS_VOID(obj->getNamePrefixVal())); + JS_ASSERT(JSVAL_IS_VOID(obj->getNameURIVal())); + JS_ASSERT(JSVAL_IS_VOID(obj->getQNameLocalNameVal())); + if (uri) + obj->setNameURI(uri); + if (prefix) + obj->setNamePrefix(prefix); + if (localName) + obj->setQNameLocalName(localName); +} + +static JSObject * +NewXMLQName(JSContext *cx, JSLinearString *uri, JSLinearString *prefix, + JSLinearString *localName) +{ + JSObject *obj = NewBuiltinClassInstanceXML(cx, &js_QNameClass); + if (!obj) + return NULL; + InitXMLQName(obj, uri, prefix, localName); + METER(xml_stats.qname); + return obj; +} + +static JSObject * +NewXMLAttributeName(JSContext *cx, JSLinearString *uri, JSLinearString *prefix, + JSLinearString *localName) +{ + /* + * AttributeName is an internal anonymous class which instances are not + * exposed to scripts. + */ + JSObject *obj = NewNonFunction(cx, &js_AttributeNameClass, NULL, NULL); + if (!obj) + return NULL; + JS_ASSERT(obj->isQName()); + InitXMLQName(obj, uri, prefix, localName); + METER(xml_stats.qname); + return obj; +} + +JSObject * +js_ConstructXMLQNameObject(JSContext *cx, const Value &nsval, const Value &lnval) +{ + Value argv[2]; + + /* + * ECMA-357 11.1.2, + * The _QualifiedIdentifier : PropertySelector :: PropertySelector_ + * production, step 2. + */ + if (nsval.isObject() && + nsval.toObject().getClass() == &js_AnyNameClass) { + argv[0].setNull(); + } else { + argv[0] = nsval; + } + argv[1] = lnval; + return js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 2, argv); +} + +static JSBool +IsXMLName(const jschar *cp, size_t n) +{ + JSBool rv; + jschar c; + + rv = JS_FALSE; + if (n != 0 && JS_ISXMLNSSTART(*cp)) { + while (--n != 0) { + c = *++cp; + if (!JS_ISXMLNS(c)) + return rv; + } + rv = JS_TRUE; + } + return rv; +} + +JSBool +js_IsXMLName(JSContext *cx, jsval v) +{ + JSLinearString *name = NULL; + JSErrorReporter older; + + /* + * Inline specialization of the QName constructor called with v passed as + * the only argument, to compute the localName for the constructed qname, + * without actually allocating the object or computing its uri and prefix. + * See ECMA-357 13.1.2.1 step 1 and 13.3.2. + */ + if (!JSVAL_IS_PRIMITIVE(v) && + JSVAL_TO_OBJECT(v)->isQName()) { + name = JSVAL_TO_OBJECT(v)->getQNameLocalName(); + } else { + older = JS_SetErrorReporter(cx, NULL); + JSString *str = js_ValueToString(cx, Valueify(v)); + if (str) + name = str->ensureLinear(cx); + JS_SetErrorReporter(cx, older); + if (!name) { + JS_ClearPendingException(cx); + return JS_FALSE; + } + } + + return IsXMLName(name->chars(), name->length()); +} + +/* + * When argc is -1, it indicates argv is empty but the code should behave as + * if argc is 1 and argv[0] is JSVAL_VOID. + */ +static JSBool +NamespaceHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, + jsval *rval) +{ + jsval urival, prefixval; + JSObject *uriobj; + JSBool isNamespace, isQName; + Class *clasp; + JSLinearString *empty, *prefix, *uri; + + isNamespace = isQName = JS_FALSE; +#ifdef __GNUC__ /* suppress bogus gcc warnings */ + uriobj = NULL; +#endif + if (argc <= 0) { + urival = JSVAL_VOID; + } else { + urival = argv[argc > 1]; + if (!JSVAL_IS_PRIMITIVE(urival)) { + uriobj = JSVAL_TO_OBJECT(urival); + clasp = uriobj->getClass(); + isNamespace = (clasp == &js_NamespaceClass); + isQName = (clasp == &js_QNameClass); + } + } + + if (!obj) { + /* Namespace called as function. */ + if (argc == 1 && isNamespace) { + /* Namespace called with one Namespace argument is identity. */ + *rval = urival; + return JS_TRUE; + } + + obj = NewBuiltinClassInstanceXML(cx, &js_NamespaceClass); + if (!obj) + return JS_FALSE; + } + *rval = OBJECT_TO_JSVAL(obj); + METER(xml_stats.xmlnamespace); + + empty = cx->runtime->emptyString; + obj->setNamePrefix(empty); + obj->setNameURI(empty); + + if (argc == 1 || argc == -1) { + if (isNamespace) { + obj->setNameURI(uriobj->getNameURI()); + obj->setNamePrefix(uriobj->getNamePrefix()); + } else if (isQName && (uri = uriobj->getNameURI())) { + obj->setNameURI(uri); + obj->setNamePrefix(uriobj->getNamePrefix()); + } else { + JSString *str = js_ValueToString(cx, Valueify(urival)); + if (!str) + return JS_FALSE; + uri = str->ensureLinear(cx); + if (!uri) + return JS_FALSE; + obj->setNameURI(uri); + if (!uri->empty()) + obj->clearNamePrefix(); + } + } else if (argc == 2) { + if (!isQName || !(uri = uriobj->getNameURI())) { + JSString *str = js_ValueToString(cx, Valueify(urival)); + if (!str) + return JS_FALSE; + uri = str->ensureLinear(cx); + if (!uri) + return JS_FALSE; + } + obj->setNameURI(uri); + + prefixval = argv[0]; + if (uri->empty()) { + if (!JSVAL_IS_VOID(prefixval)) { + JSString *str = js_ValueToString(cx, Valueify(prefixval)); + if (!str) + return JS_FALSE; + if (!str->empty()) { + JSAutoByteString bytes; + if (js_ValueToPrintable(cx, StringValue(str), &bytes)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_XML_NAMESPACE, bytes.ptr()); + } + return JS_FALSE; + } + } + } else if (JSVAL_IS_VOID(prefixval) || !js_IsXMLName(cx, prefixval)) { + obj->clearNamePrefix(); + } else { + JSString *str = js_ValueToString(cx, Valueify(prefixval)); + if (!str) + return JS_FALSE; + prefix = str->ensureLinear(cx); + if (!prefix) + return JS_FALSE; + obj->setNamePrefix(prefix); + } + } + return JS_TRUE; +} + +static JSBool +Namespace(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *thisobj = NULL; + (void)IsConstructing_PossiblyWithGivenThisObject(vp, &thisobj); + return NamespaceHelper(cx, thisobj, argc, Jsvalify(vp + 2), Jsvalify(vp)); +} + +/* + * When argc is -1, it indicates argv is empty but the code should behave as + * if argc is 1 and argv[0] is JSVAL_VOID. + */ +static JSBool +QNameHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, jsval *rval) +{ + jsval nameval, nsval; + JSBool isQName, isNamespace; + JSObject *qn; + JSLinearString *uri, *prefix, *name; + JSObject *obj2; + + if (argc <= 0) { + nameval = JSVAL_VOID; + isQName = JS_FALSE; + } else { + nameval = argv[argc > 1]; + isQName = + !JSVAL_IS_PRIMITIVE(nameval) && + JSVAL_TO_OBJECT(nameval)->getClass() == &js_QNameClass; + } + + if (!obj) { + /* QName called as function. */ + if (argc == 1 && isQName) { + /* QName called with one QName argument is identity. */ + *rval = nameval; + return JS_TRUE; + } + + /* Create and return a new QName object exactly as if constructed. */ + obj = NewBuiltinClassInstanceXML(cx, &js_QNameClass); + if (!obj) + return JS_FALSE; + } + *rval = OBJECT_TO_JSVAL(obj); + METER(xml_stats.qname); + + if (isQName) { + /* If namespace is not specified and name is a QName, clone it. */ + qn = JSVAL_TO_OBJECT(nameval); + if (argc == 1) { + uri = qn->getNameURI(); + prefix = qn->getNamePrefix(); + name = qn->getQNameLocalName(); + goto out; + } + + /* Namespace and qname were passed -- use the qname's localName. */ + nameval = qn->getQNameLocalNameVal(); + } + + if (argc == 0) { + name = cx->runtime->emptyString; + } else if (argc < 0) { + name = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + } else { + JSString *str = js_ValueToString(cx, Valueify(nameval)); + if (!str) + return JS_FALSE; + name = str->ensureLinear(cx); + if (!name) + return JS_FALSE; + argv[argc > 1] = STRING_TO_JSVAL(name); + } + + if (argc > 1 && !JSVAL_IS_VOID(argv[0])) { + nsval = argv[0]; + } else if (IS_STAR(name)) { + nsval = JSVAL_NULL; + } else { + if (!js_GetDefaultXMLNamespace(cx, &nsval)) + return JS_FALSE; + JS_ASSERT(!JSVAL_IS_PRIMITIVE(nsval)); + JS_ASSERT(JSVAL_TO_OBJECT(nsval)->getClass() == + &js_NamespaceClass); + } + + if (JSVAL_IS_NULL(nsval)) { + /* NULL prefix represents *undefined* in ECMA-357 13.3.2 5(a). */ + prefix = uri = NULL; + } else { + /* + * Inline specialization of the Namespace constructor called with + * nsval passed as the only argument, to compute the uri and prefix + * for the constructed namespace, without actually allocating the + * object or computing other members. See ECMA-357 13.3.2 6(a) and + * 13.2.2. + */ + isNamespace = isQName = JS_FALSE; + if (!JSVAL_IS_PRIMITIVE(nsval)) { + obj2 = JSVAL_TO_OBJECT(nsval); + isNamespace = (obj2->getClass() == &js_NamespaceClass); + isQName = (obj2->getClass() == &js_QNameClass); + } +#ifdef __GNUC__ /* suppress bogus gcc warnings */ + else obj2 = NULL; +#endif + + if (isNamespace) { + uri = obj2->getNameURI(); + prefix = obj2->getNamePrefix(); + } else if (isQName && (uri = obj2->getNameURI())) { + JS_ASSERT(argc > 1); + prefix = obj2->getNamePrefix(); + } else { + JS_ASSERT(argc > 1); + JSString *str = js_ValueToString(cx, Valueify(nsval)); + if (!str) + return JS_FALSE; + uri = str->ensureLinear(cx); + if (!uri) + return JS_FALSE; + argv[0] = STRING_TO_JSVAL(uri); /* local root */ + + /* NULL here represents *undefined* in ECMA-357 13.2.2 3(c)iii. */ + prefix = uri->empty() ? cx->runtime->emptyString : NULL; + } + } + +out: + InitXMLQName(obj, uri, prefix, name); + return JS_TRUE; +} + +static JSBool +QName(JSContext *cx, uintN argc, Value *vp) +{ + JSObject *thisobj = NULL; + (void)IsConstructing_PossiblyWithGivenThisObject(vp, &thisobj); + return QNameHelper(cx, thisobj, argc, Jsvalify(vp + 2), Jsvalify(vp)); +} + +/* + * XMLArray library functions. + */ +static JSBool +namespace_identity(const void *a, const void *b) +{ + const JSObject *nsa = (const JSObject *) a; + const JSObject *nsb = (const JSObject *) b; + JSLinearString *prefixa = nsa->getNamePrefix(); + JSLinearString *prefixb = nsb->getNamePrefix(); + + if (prefixa && prefixb) { + if (!EqualStrings(prefixa, prefixb)) + return JS_FALSE; + } else { + if (prefixa || prefixb) + return JS_FALSE; + } + return EqualStrings(nsa->getNameURI(), nsb->getNameURI()); +} + +static JSBool +attr_identity(const void *a, const void *b) +{ + const JSXML *xmla = (const JSXML *) a; + const JSXML *xmlb = (const JSXML *) b; + + return qname_identity(xmla->name, xmlb->name); +} + +void +JSXMLArrayCursor::trace(JSTracer *trc) { +#ifdef DEBUG + size_t index = 0; +#endif + for (JSXMLArrayCursor *cursor = this; cursor; cursor = cursor->next) + js::gc::MarkGCThing(trc, cursor->root, "cursor_root", index++); +} + +static void +XMLArrayCursorTrace(JSTracer *trc, JSXMLArrayCursor *cursor) +{ + cursor->trace(trc); +} + +/* NB: called with null cx from the GC, via xml_trace => JSXMLArray::trim. */ +bool +JSXMLArray::setCapacity(JSContext *cx, uint32 newCapacity) +{ + if (newCapacity == 0) { + /* We could let realloc(p, 0) free this, but purify gets confused. */ + if (vector) { + if (cx) + cx->free(vector); + else + js_free(vector); + } + vector = NULL; + } else { + void **tmp; + + if ( +#if JS_BITS_PER_WORD == 32 + (size_t)newCapacity > ~(size_t)0 / sizeof(void *) || +#endif + !(tmp = (void **) js_realloc(vector, newCapacity * sizeof(void *)))) { + if (cx) + JS_ReportOutOfMemory(cx); + return false; + } + vector = tmp; + } + capacity = JSXML_PRESET_CAPACITY | newCapacity; + return true; +} + +void +JSXMLArray::trim() +{ + if (capacity & JSXML_PRESET_CAPACITY) + return; + if (length < capacity) + setCapacity(NULL, length); +} + +void +JSXMLArray::finish(JSContext *cx) +{ + cx->free(vector); + + while (JSXMLArrayCursor *cursor = cursors) + cursor->disconnect(); + +#ifdef DEBUG + memset(this, 0xd5, sizeof *this); +#endif +} + +#define XML_NOT_FOUND ((uint32) -1) + +static uint32 +XMLArrayFindMember(const JSXMLArray *array, void *elt, JSIdentityOp identity) +{ + void **vector; + uint32 i, n; + + /* The identity op must not reallocate array->vector. */ + vector = array->vector; + if (identity) { + for (i = 0, n = array->length; i < n; i++) { + if (identity(vector[i], elt)) + return i; + } + } else { + for (i = 0, n = array->length; i < n; i++) { + if (vector[i] == elt) + return i; + } + } + return XML_NOT_FOUND; +} + +/* + * Grow array vector capacity by powers of two to LINEAR_THRESHOLD, and after + * that, grow by LINEAR_INCREMENT. Both must be powers of two, and threshold + * should be greater than increment. + */ +#define LINEAR_THRESHOLD 256 +#define LINEAR_INCREMENT 32 + +static JSBool +XMLArrayAddMember(JSContext *cx, JSXMLArray *array, uint32 index, void *elt) +{ + uint32 capacity, i; + int log2; + void **vector; + + if (index >= array->length) { + if (index >= JSXML_CAPACITY(array)) { + /* Arrange to clear JSXML_PRESET_CAPACITY from array->capacity. */ + capacity = index + 1; + if (index >= LINEAR_THRESHOLD) { + capacity = JS_ROUNDUP(capacity, LINEAR_INCREMENT); + } else { + JS_CEILING_LOG2(log2, capacity); + capacity = JS_BIT(log2); + } + if ( +#if JS_BITS_PER_WORD == 32 + (size_t)capacity > ~(size_t)0 / sizeof(void *) || +#endif + !(vector = (void **) + js_realloc(array->vector, capacity * sizeof(void *)))) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + array->capacity = capacity; + array->vector = vector; + for (i = array->length; i < index; i++) + vector[i] = NULL; + } + array->length = index + 1; + } + + array->vector[index] = elt; + return JS_TRUE; +} + +static JSBool +XMLArrayInsert(JSContext *cx, JSXMLArray *array, uint32 i, uint32 n) +{ + uint32 j; + JSXMLArrayCursor *cursor; + + j = array->length; + JS_ASSERT(i <= j); + if (!array->setCapacity(cx, j + n)) + return JS_FALSE; + + array->length = j + n; + JS_ASSERT(n != (uint32)-1); + while (j != i) { + --j; + array->vector[j + n] = array->vector[j]; + } + + for (cursor = array->cursors; cursor; cursor = cursor->next) { + if (cursor->index > i) + cursor->index += n; + } + return JS_TRUE; +} + +static void * +XMLArrayDelete(JSContext *cx, JSXMLArray *array, uint32 index, JSBool compress) +{ + uint32 length; + void **vector, *elt; + JSXMLArrayCursor *cursor; + + length = array->length; + if (index >= length) + return NULL; + + vector = array->vector; + elt = vector[index]; + if (compress) { + while (++index < length) + vector[index-1] = vector[index]; + array->length = length - 1; + array->capacity = JSXML_CAPACITY(array); + } else { + vector[index] = NULL; + } + + for (cursor = array->cursors; cursor; cursor = cursor->next) { + if (cursor->index > index) + --cursor->index; + } + return elt; +} + +static void +XMLArrayTruncate(JSContext *cx, JSXMLArray *array, uint32 length) +{ + void **vector; + + JS_ASSERT(!array->cursors); + if (length >= array->length) + return; + + if (length == 0) { + if (array->vector) + cx->free(array->vector); + vector = NULL; + } else { + vector = (void **) js_realloc(array->vector, length * sizeof(void *)); + if (!vector) + return; + } + + if (array->length > length) + array->length = length; + array->capacity = length; + array->vector = vector; +} + +#define XMLARRAY_FIND_MEMBER(a,e,f) XMLArrayFindMember(a, (void *)(e), f) +#define XMLARRAY_HAS_MEMBER(a,e,f) (XMLArrayFindMember(a, (void *)(e), f) != \ + XML_NOT_FOUND) +#define XMLARRAY_MEMBER(a,i,t) (((i) < (a)->length) \ + ? (t *) (a)->vector[i] \ + : NULL) +#define XMLARRAY_SET_MEMBER(a,i,e) JS_BEGIN_MACRO \ + if ((a)->length <= (i)) \ + (a)->length = (i) + 1; \ + ((a)->vector[i] = (void *)(e)); \ + JS_END_MACRO +#define XMLARRAY_ADD_MEMBER(x,a,i,e)XMLArrayAddMember(x, a, i, (void *)(e)) +#define XMLARRAY_INSERT(x,a,i,n) XMLArrayInsert(x, a, i, n) +#define XMLARRAY_APPEND(x,a,e) XMLARRAY_ADD_MEMBER(x, a, (a)->length, (e)) +#define XMLARRAY_DELETE(x,a,i,c,t) ((t *) XMLArrayDelete(x, a, i, c)) +#define XMLARRAY_TRUNCATE(x,a,n) XMLArrayTruncate(x, a, n) + +/* + * Define XML setting property strings and constants early, so everyone can + * use the same names. + */ +static const char js_ignoreComments_str[] = "ignoreComments"; +static const char js_ignoreProcessingInstructions_str[] + = "ignoreProcessingInstructions"; +static const char js_ignoreWhitespace_str[] = "ignoreWhitespace"; +static const char js_prettyPrinting_str[] = "prettyPrinting"; +static const char js_prettyIndent_str[] = "prettyIndent"; + +#define XSF_IGNORE_COMMENTS JS_BIT(0) +#define XSF_IGNORE_PROCESSING_INSTRUCTIONS JS_BIT(1) +#define XSF_IGNORE_WHITESPACE JS_BIT(2) +#define XSF_PRETTY_PRINTING JS_BIT(3) + +static JSPropertySpec xml_static_props[] = { + {js_ignoreComments_str, 0, JSPROP_PERMANENT, NULL, NULL}, + {js_ignoreProcessingInstructions_str, 0, JSPROP_PERMANENT, NULL, NULL}, + {js_ignoreWhitespace_str, 0, JSPROP_PERMANENT, NULL, NULL}, + {js_prettyPrinting_str, 0, JSPROP_PERMANENT, NULL, NULL}, + {js_prettyIndent_str, 0, JSPROP_PERMANENT, NULL, NULL}, + {0,0,0,0,0} +}; + +/* Macros for special-casing xml:, xmlns= and xmlns:foo= in ParseNodeToQName. */ +#define IS_XML(str) \ + (str->length() == 3 && IS_XML_CHARS(str->chars())) + +#define IS_XMLNS(str) \ + (str->length() == 5 && IS_XMLNS_CHARS(str->chars())) + +#define IS_XML_CHARS(chars) \ + (JS_TOLOWER((chars)[0]) == 'x' && \ + JS_TOLOWER((chars)[1]) == 'm' && \ + JS_TOLOWER((chars)[2]) == 'l') + +#define HAS_NS_AFTER_XML(chars) \ + (JS_TOLOWER((chars)[3]) == 'n' && \ + JS_TOLOWER((chars)[4]) == 's') + +#define IS_XMLNS_CHARS(chars) \ + (IS_XML_CHARS(chars) && HAS_NS_AFTER_XML(chars)) + +#define STARTS_WITH_XML(chars,length) \ + (length >= 3 && IS_XML_CHARS(chars)) + +static const char xml_namespace_str[] = "http://www.w3.org/XML/1998/namespace"; +static const char xmlns_namespace_str[] = "http://www.w3.org/2000/xmlns/"; + +static JSObject * +ParseNodeToQName(Parser *parser, JSParseNode *pn, + JSXMLArray *inScopeNSes, JSBool isAttributeName) +{ + JSContext *cx = parser->context; + JSLinearString *str, *uri, *prefix, *localName; + size_t length, offset; + const jschar *start, *limit, *colon; + uint32 n; + JSObject *ns; + JSLinearString *nsprefix; + + JS_ASSERT(pn->pn_arity == PN_NULLARY); + str = pn->pn_atom; + start = str->chars(); + length = str->length(); + JS_ASSERT(length != 0 && *start != '@'); + JS_ASSERT(length != 1 || *start != '*'); + + uri = cx->runtime->emptyString; + limit = start + length; + colon = js_strchr_limit(start, ':', limit); + if (colon) { + offset = colon - start; + prefix = js_NewDependentString(cx, str, 0, offset); + if (!prefix) + return NULL; + + if (STARTS_WITH_XML(start, offset)) { + if (offset == 3) { + uri = JS_ASSERT_STRING_IS_FLAT(JS_InternString(cx, xml_namespace_str)); + if (!uri) + return NULL; + } else if (offset == 5 && HAS_NS_AFTER_XML(start)) { + uri = JS_ASSERT_STRING_IS_FLAT(JS_InternString(cx, xmlns_namespace_str)); + if (!uri) + return NULL; + } else { + uri = NULL; + } + } else { + uri = NULL; + n = inScopeNSes->length; + while (n != 0) { + --n; + ns = XMLARRAY_MEMBER(inScopeNSes, n, JSObject); + nsprefix = ns->getNamePrefix(); + if (nsprefix && EqualStrings(nsprefix, prefix)) { + uri = ns->getNameURI(); + break; + } + } + } + + if (!uri) { + Value v = StringValue(prefix); + JSAutoByteString bytes; + if (js_ValueToPrintable(parser->context, v, &bytes)) { + ReportCompileErrorNumber(parser->context, &parser->tokenStream, pn, + JSREPORT_ERROR, JSMSG_BAD_XML_NAMESPACE, bytes.ptr()); + } + return NULL; + } + + localName = js_NewStringCopyN(parser->context, colon + 1, length - (offset + 1)); + if (!localName) + return NULL; + } else { + if (isAttributeName) { + /* + * An unprefixed attribute is not in any namespace, so set prefix + * as well as uri to the empty string. + */ + prefix = uri; + } else { + /* + * Loop from back to front looking for the closest declared default + * namespace. + */ + n = inScopeNSes->length; + while (n != 0) { + --n; + ns = XMLARRAY_MEMBER(inScopeNSes, n, JSObject); + nsprefix = ns->getNamePrefix(); + if (!nsprefix || nsprefix->empty()) { + uri = ns->getNameURI(); + break; + } + } + prefix = uri->empty() ? parser->context->runtime->emptyString : NULL; + } + localName = str; + } + + return NewXMLQName(parser->context, uri, prefix, localName); +} + +static JSString * +ChompXMLWhitespace(JSContext *cx, JSString *str) +{ + size_t length, newlength, offset; + const jschar *cp, *start, *end; + jschar c; + + length = str->length(); + start = str->getChars(cx); + if (!start) + return NULL; + + for (cp = start, end = cp + length; cp < end; cp++) { + c = *cp; + if (!JS_ISXMLSPACE(c)) + break; + } + while (end > cp) { + c = end[-1]; + if (!JS_ISXMLSPACE(c)) + break; + --end; + } + newlength = end - cp; + if (newlength == length) + return str; + offset = cp - start; + return js_NewDependentString(cx, str, offset, newlength); +} + +static JSXML * +ParseNodeToXML(Parser *parser, JSParseNode *pn, + JSXMLArray *inScopeNSes, uintN flags) +{ + JSContext *cx = parser->context; + JSXML *xml, *kid, *attr, *attrj; + JSLinearString *str; + uint32 length, n, i, j; + JSParseNode *pn2, *pn3, *head, **pnp; + JSObject *ns; + JSObject *qn, *attrjqn; + JSXMLClass xml_class; + int stackDummy; + + if (!JS_CHECK_STACK_SIZE(cx->stackLimit, &stackDummy)) { + ReportCompileErrorNumber(cx, &parser->tokenStream, pn, JSREPORT_ERROR, + JSMSG_OVER_RECURSED); + return NULL; + } + +#define PN2X_SKIP_CHILD ((JSXML *) 1) + + /* + * Cases return early to avoid common code that gets an outermost xml's + * object, which protects GC-things owned by xml and its descendants from + * garbage collection. + */ + xml = NULL; + if (!js_EnterLocalRootScope(cx)) + return NULL; + switch (pn->pn_type) { + case TOK_XMLELEM: + length = inScopeNSes->length; + pn2 = pn->pn_head; + xml = ParseNodeToXML(parser, pn2, inScopeNSes, flags); + if (!xml) + goto fail; + + n = pn->pn_count; + JS_ASSERT(n >= 2); + n -= 2; + if (!xml->xml_kids.setCapacity(cx, n)) + goto fail; + + i = 0; + while ((pn2 = pn2->pn_next) != NULL) { + if (!pn2->pn_next) { + /* Don't append the end tag! */ + JS_ASSERT(pn2->pn_type == TOK_XMLETAGO); + break; + } + + if ((flags & XSF_IGNORE_WHITESPACE) && + n > 1 && pn2->pn_type == TOK_XMLSPACE) { + --n; + continue; + } + + kid = ParseNodeToXML(parser, pn2, inScopeNSes, flags); + if (kid == PN2X_SKIP_CHILD) { + --n; + continue; + } + + if (!kid) + goto fail; + + /* Store kid in xml right away, to protect it from GC. */ + XMLARRAY_SET_MEMBER(&xml->xml_kids, i, kid); + kid->parent = xml; + ++i; + + /* XXX where is this documented in an XML spec, or in E4X? */ + if ((flags & XSF_IGNORE_WHITESPACE) && + n > 1 && kid->xml_class == JSXML_CLASS_TEXT) { + JSString *str = ChompXMLWhitespace(cx, kid->xml_value); + if (!str) + goto fail; + kid->xml_value = str; + } + } + + JS_ASSERT(i == n); + if (n < pn->pn_count - 2) + xml->xml_kids.trim(); + XMLARRAY_TRUNCATE(cx, inScopeNSes, length); + break; + + case TOK_XMLLIST: + xml = js_NewXML(cx, JSXML_CLASS_LIST); + if (!xml) + goto fail; + + n = pn->pn_count; + if (!xml->xml_kids.setCapacity(cx, n)) + goto fail; + + i = 0; + for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { + /* + * Always ignore insignificant whitespace in lists -- we shouldn't + * condition this on an XML.ignoreWhitespace setting when the list + * constructor is XMLList (note XML/XMLList unification hazard). + */ + if (pn2->pn_type == TOK_XMLSPACE) { + --n; + continue; + } + + kid = ParseNodeToXML(parser, pn2, inScopeNSes, flags); + if (kid == PN2X_SKIP_CHILD) { + --n; + continue; + } + + if (!kid) + goto fail; + + XMLARRAY_SET_MEMBER(&xml->xml_kids, i, kid); + ++i; + } + + if (n < pn->pn_count) + xml->xml_kids.trim(); + break; + + case TOK_XMLSTAGO: + case TOK_XMLPTAGC: + length = inScopeNSes->length; + pn2 = pn->pn_head; + JS_ASSERT(pn2->pn_type == TOK_XMLNAME); + if (pn2->pn_arity == PN_LIST) + goto syntax; + + xml = js_NewXML(cx, JSXML_CLASS_ELEMENT); + if (!xml) + goto fail; + + /* First pass: check syntax and process namespace declarations. */ + JS_ASSERT(pn->pn_count >= 1); + n = pn->pn_count - 1; + pnp = &pn2->pn_next; + head = *pnp; + while ((pn2 = *pnp) != NULL) { + size_t length; + const jschar *chars; + + if (pn2->pn_type != TOK_XMLNAME || pn2->pn_arity != PN_NULLARY) + goto syntax; + + /* Enforce "Well-formedness constraint: Unique Att Spec". */ + for (pn3 = head; pn3 != pn2; pn3 = pn3->pn_next->pn_next) { + if (pn3->pn_atom == pn2->pn_atom) { + Value v = StringValue(ATOM_TO_STRING(pn2->pn_atom)); + JSAutoByteString bytes; + if (js_ValueToPrintable(cx, v, &bytes)) { + ReportCompileErrorNumber(cx, &parser->tokenStream, pn2, + JSREPORT_ERROR, JSMSG_DUPLICATE_XML_ATTR, + bytes.ptr()); + } + goto fail; + } + } + + JSAtom *atom = pn2->pn_atom; + pn2 = pn2->pn_next; + JS_ASSERT(pn2); + if (pn2->pn_type != TOK_XMLATTR) + goto syntax; + + chars = atom->chars(); + length = atom->length(); + if (length >= 5 && + IS_XMLNS_CHARS(chars) && + (length == 5 || chars[5] == ':')) { + JSLinearString *uri, *prefix; + + uri = ATOM_TO_STRING(pn2->pn_atom); + if (length == 5) { + /* 10.3.2.1. Step 6(h)(i)(1)(a). */ + prefix = cx->runtime->emptyString; + } else { + prefix = js_NewStringCopyN(cx, chars + 6, length - 6); + if (!prefix) + goto fail; + } + + /* + * Once the new ns is appended to xml->xml_namespaces, it is + * protected from GC by the object that owns xml -- which is + * either xml->object if outermost, or the object owning xml's + * oldest ancestor if !outermost. + */ + ns = NewXMLNamespace(cx, prefix, uri, JS_TRUE); + if (!ns) + goto fail; + + /* + * Don't add a namespace that's already in scope. If someone + * extracts a child property from its parent via [[Get]], then + * we enforce the invariant, noted many times in ECMA-357, that + * the child's namespaces form a possibly-improper superset of + * its ancestors' namespaces. + */ + if (!XMLARRAY_HAS_MEMBER(inScopeNSes, ns, namespace_identity)) { + if (!XMLARRAY_APPEND(cx, inScopeNSes, ns) || + !XMLARRAY_APPEND(cx, &xml->xml_namespaces, ns)) { + goto fail; + } + } + + JS_ASSERT(n >= 2); + n -= 2; + *pnp = pn2->pn_next; + /* XXXbe recycle pn2 */ + continue; + } + + pnp = &pn2->pn_next; + } + + xml->xml_namespaces.trim(); + + /* Second pass: process tag name and attributes, using namespaces. */ + pn2 = pn->pn_head; + qn = ParseNodeToQName(parser, pn2, inScopeNSes, JS_FALSE); + if (!qn) + goto fail; + xml->name = qn; + + JS_ASSERT((n & 1) == 0); + n >>= 1; + if (!xml->xml_attrs.setCapacity(cx, n)) + goto fail; + + for (i = 0; (pn2 = pn2->pn_next) != NULL; i++) { + qn = ParseNodeToQName(parser, pn2, inScopeNSes, JS_TRUE); + if (!qn) { + xml->xml_attrs.length = i; + goto fail; + } + + /* + * Enforce "Well-formedness constraint: Unique Att Spec", part 2: + * this time checking local name and namespace URI. + */ + for (j = 0; j < i; j++) { + attrj = XMLARRAY_MEMBER(&xml->xml_attrs, j, JSXML); + attrjqn = attrj->name; + if (EqualStrings(attrjqn->getNameURI(), qn->getNameURI()) && + EqualStrings(attrjqn->getQNameLocalName(), qn->getQNameLocalName())) { + Value v = StringValue(ATOM_TO_STRING(pn2->pn_atom)); + JSAutoByteString bytes; + if (js_ValueToPrintable(cx, v, &bytes)) { + ReportCompileErrorNumber(cx, &parser->tokenStream, pn2, + JSREPORT_ERROR, JSMSG_DUPLICATE_XML_ATTR, + bytes.ptr()); + } + goto fail; + } + } + + pn2 = pn2->pn_next; + JS_ASSERT(pn2); + JS_ASSERT(pn2->pn_type == TOK_XMLATTR); + + attr = js_NewXML(cx, JSXML_CLASS_ATTRIBUTE); + if (!attr) + goto fail; + + XMLARRAY_SET_MEMBER(&xml->xml_attrs, i, attr); + attr->parent = xml; + attr->name = qn; + attr->xml_value = ATOM_TO_STRING(pn2->pn_atom); + } + + /* Point tag closes its own namespace scope. */ + if (pn->pn_type == TOK_XMLPTAGC) + XMLARRAY_TRUNCATE(cx, inScopeNSes, length); + break; + + case TOK_XMLSPACE: + case TOK_XMLTEXT: + case TOK_XMLCDATA: + case TOK_XMLCOMMENT: + case TOK_XMLPI: + str = ATOM_TO_STRING(pn->pn_atom); + qn = NULL; + if (pn->pn_type == TOK_XMLCOMMENT) { + if (flags & XSF_IGNORE_COMMENTS) + goto skip_child; + xml_class = JSXML_CLASS_COMMENT; + } else if (pn->pn_type == TOK_XMLPI) { + if (IS_XML(str)) { + Value v = StringValue(str); + JSAutoByteString bytes; + if (js_ValueToPrintable(cx, v, &bytes)) { + ReportCompileErrorNumber(cx, &parser->tokenStream, pn, + JSREPORT_ERROR, JSMSG_RESERVED_ID, bytes.ptr()); + } + goto fail; + } + + if (flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS) + goto skip_child; + + qn = ParseNodeToQName(parser, pn, inScopeNSes, JS_FALSE); + if (!qn) + goto fail; + + str = pn->pn_atom2 + ? ATOM_TO_STRING(pn->pn_atom2) + : cx->runtime->emptyString; + xml_class = JSXML_CLASS_PROCESSING_INSTRUCTION; + } else { + /* CDATA section content, or element text. */ + xml_class = JSXML_CLASS_TEXT; + } + + xml = js_NewXML(cx, xml_class); + if (!xml) + goto fail; + xml->name = qn; + if (pn->pn_type == TOK_XMLSPACE) + xml->xml_flags |= XMLF_WHITESPACE_TEXT; + xml->xml_value = str; + break; + + default: + goto syntax; + } + + js_LeaveLocalRootScopeWithResult(cx, xml); + return xml; + +skip_child: + js_LeaveLocalRootScope(cx); + return PN2X_SKIP_CHILD; + +#undef PN2X_SKIP_CHILD + +syntax: + ReportCompileErrorNumber(cx, &parser->tokenStream, pn, JSREPORT_ERROR, JSMSG_BAD_XML_MARKUP); +fail: + js_LeaveLocalRootScope(cx); + return NULL; +} + +/* + * XML helper, object-ops, and library functions. We start with the helpers, + * in ECMA-357 order, but merging XML (9.1) and XMLList (9.2) helpers. + */ +static JSBool +GetXMLSetting(JSContext *cx, const char *name, jsval *vp) +{ + jsval v; + + if (!js_FindClassObject(cx, NULL, JSProto_XML, Valueify(&v))) + return JS_FALSE; + if (!VALUE_IS_FUNCTION(cx, v)) { + *vp = JSVAL_VOID; + return JS_TRUE; + } + return JS_GetProperty(cx, JSVAL_TO_OBJECT(v), name, vp); +} + +static JSBool +GetBooleanXMLSetting(JSContext *cx, const char *name, JSBool *bp) +{ + jsval v; + + return GetXMLSetting(cx, name, &v) && JS_ValueToBoolean(cx, v, bp); +} + +static JSBool +GetUint32XMLSetting(JSContext *cx, const char *name, uint32 *uip) +{ + jsval v; + + return GetXMLSetting(cx, name, &v) && JS_ValueToECMAUint32(cx, v, uip); +} + +static JSBool +GetXMLSettingFlags(JSContext *cx, uintN *flagsp) +{ + JSBool flag[4]; + + if (!GetBooleanXMLSetting(cx, js_ignoreComments_str, &flag[0]) || + !GetBooleanXMLSetting(cx, js_ignoreProcessingInstructions_str, &flag[1]) || + !GetBooleanXMLSetting(cx, js_ignoreWhitespace_str, &flag[2]) || + !GetBooleanXMLSetting(cx, js_prettyPrinting_str, &flag[3])) { + return false; + } + + *flagsp = 0; + for (size_t n = 0; n < 4; ++n) + if (flag[n]) + *flagsp |= JS_BIT(n); + return true; +} + +static JSXML * +ParseXMLSource(JSContext *cx, JSString *src) +{ + jsval nsval; + JSLinearString *uri; + size_t urilen, srclen, length, offset, dstlen; + jschar *chars; + const jschar *srcp, *endp; + JSXML *xml; + const char *filename; + uintN lineno; + JSOp op; + + static const char prefix[] = ""; + static const char suffix[] = ""; + +#define constrlen(constr) (sizeof(constr) - 1) + + if (!js_GetDefaultXMLNamespace(cx, &nsval)) + return NULL; + uri = JSVAL_TO_OBJECT(nsval)->getNameURI(); + uri = js_EscapeAttributeValue(cx, uri, JS_FALSE); + if (!uri) + return NULL; + + urilen = uri->length(); + srclen = src->length(); + length = constrlen(prefix) + urilen + constrlen(middle) + srclen + + constrlen(suffix); + + chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar)); + if (!chars) + return NULL; + + dstlen = length; + js_InflateStringToBuffer(cx, prefix, constrlen(prefix), chars, &dstlen); + offset = dstlen; + js_strncpy(chars + offset, uri->chars(), urilen); + offset += urilen; + dstlen = length - offset + 1; + js_InflateStringToBuffer(cx, middle, constrlen(middle), chars + offset, + &dstlen); + offset += dstlen; + srcp = src->getChars(cx); + if (!srcp) { + cx->free(chars); + return NULL; + } + js_strncpy(chars + offset, srcp, srclen); + offset += srclen; + dstlen = length - offset + 1; + js_InflateStringToBuffer(cx, suffix, constrlen(suffix), chars + offset, + &dstlen); + chars [offset + dstlen] = 0; + + LeaveTrace(cx); + xml = NULL; + FrameRegsIter i(cx); + for (; !i.done() && !i.pc(); ++i) + JS_ASSERT(!i.fp()->isScriptFrame()); + filename = NULL; + lineno = 1; + if (!i.done()) { + JSStackFrame *fp = i.fp(); + op = (JSOp) *i.pc(); + if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) { + filename = fp->script()->filename; + lineno = js_FramePCToLineNumber(cx, fp); + for (endp = srcp + srclen; srcp < endp; srcp++) { + if (*srcp == '\n') + --lineno; + } + } + } + + { + Parser parser(cx); + if (parser.init(chars, length, filename, lineno, cx->findVersion())) { + JSObject *scopeChain = GetScopeChain(cx); + if (!scopeChain) { + cx->free(chars); + return NULL; + } + JSParseNode *pn = parser.parseXMLText(scopeChain, false); + uintN flags; + if (pn && GetXMLSettingFlags(cx, &flags)) { + AutoNamespaceArray namespaces(cx); + if (namespaces.array.setCapacity(cx, 1)) + xml = ParseNodeToXML(&parser, pn, &namespaces.array, flags); + } + } + } + + cx->free(chars); + return xml; + +#undef constrlen +} + +/* + * Errata in 10.3.1, 10.4.1, and 13.4.4.24 (at least). + * + * 10.3.1 Step 6(a) fails to NOTE that implementations that do not enforce + * the constraint: + * + * for all x belonging to XML: + * x.[[InScopeNamespaces]] >= x.[[Parent]].[[InScopeNamespaces]] + * + * must union x.[[InScopeNamespaces]] into x[0].[[InScopeNamespaces]] here + * (in new sub-step 6(a), renumbering the others to (b) and (c)). + * + * Same goes for 10.4.1 Step 7(a). + * + * In order for XML.prototype.namespaceDeclarations() to work correctly, the + * default namespace thereby unioned into x[0].[[InScopeNamespaces]] must be + * flagged as not declared, so that 13.4.4.24 Step 8(a) can exclude all such + * undeclared namespaces associated with x not belonging to ancestorNS. + */ +static JSXML * +OrphanXMLChild(JSContext *cx, JSXML *xml, uint32 i) +{ + JSObject *ns; + + ns = XMLARRAY_MEMBER(&xml->xml_namespaces, 0, JSObject); + xml = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (!ns || !xml) + return xml; + if (xml->xml_class == JSXML_CLASS_ELEMENT) { + if (!XMLARRAY_APPEND(cx, &xml->xml_namespaces, ns)) + return NULL; + ns->setNamespaceDeclared(JSVAL_VOID); + } + xml->parent = NULL; + return xml; +} + +static JSObject * +ToXML(JSContext *cx, jsval v) +{ + JSObject *obj; + JSXML *xml; + Class *clasp; + JSString *str; + uint32 length; + + if (JSVAL_IS_PRIMITIVE(v)) { + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) + goto bad; + } else { + obj = JSVAL_TO_OBJECT(v); + if (obj->isXML()) { + xml = (JSXML *) obj->getPrivate(); + if (xml->xml_class == JSXML_CLASS_LIST) { + if (xml->xml_kids.length != 1) + goto bad; + xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (xml) { + JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST); + return js_GetXMLObject(cx, xml); + } + } + return obj; + } + + clasp = obj->getClass(); + if (clasp->flags & JSCLASS_DOCUMENT_OBSERVER) { + JS_ASSERT(0); + } + + if (clasp != &js_StringClass && + clasp != &js_NumberClass && + clasp != &js_BooleanClass) { + goto bad; + } + } + + str = js_ValueToString(cx, Valueify(v)); + if (!str) + return NULL; + if (str->empty()) { + length = 0; +#ifdef __GNUC__ /* suppress bogus gcc warnings */ + xml = NULL; +#endif + } else { + xml = ParseXMLSource(cx, str); + if (!xml) + return NULL; + length = JSXML_LENGTH(xml); + } + + if (length == 0) { + obj = js_NewXMLObject(cx, JSXML_CLASS_TEXT); + if (!obj) + return NULL; + } else if (length == 1) { + xml = OrphanXMLChild(cx, xml, 0); + if (!xml) + return NULL; + obj = js_GetXMLObject(cx, xml); + if (!obj) + return NULL; + } else { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_SYNTAX_ERROR); + return NULL; + } + return obj; + +bad: + js_ReportValueError(cx, JSMSG_BAD_XML_CONVERSION, + JSDVG_IGNORE_STACK, Valueify(v), NULL); + return NULL; +} + +static JSBool +Append(JSContext *cx, JSXML *list, JSXML *kid); + +static JSObject * +ToXMLList(JSContext *cx, jsval v) +{ + JSObject *obj, *listobj; + JSXML *xml, *list, *kid; + Class *clasp; + JSString *str; + uint32 i, length; + + if (JSVAL_IS_PRIMITIVE(v)) { + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) + goto bad; + } else { + obj = JSVAL_TO_OBJECT(v); + if (obj->isXML()) { + xml = (JSXML *) obj->getPrivate(); + if (xml->xml_class != JSXML_CLASS_LIST) { + listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!listobj) + return NULL; + list = (JSXML *) listobj->getPrivate(); + if (!Append(cx, list, xml)) + return NULL; + return listobj; + } + return obj; + } + + clasp = obj->getClass(); + if (clasp->flags & JSCLASS_DOCUMENT_OBSERVER) { + JS_ASSERT(0); + } + + if (clasp != &js_StringClass && + clasp != &js_NumberClass && + clasp != &js_BooleanClass) { + goto bad; + } + } + + str = js_ValueToString(cx, Valueify(v)); + if (!str) + return NULL; + if (str->empty()) { + xml = NULL; + length = 0; + } else { + if (!js_EnterLocalRootScope(cx)) + return NULL; + xml = ParseXMLSource(cx, str); + if (!xml) { + js_LeaveLocalRootScope(cx); + return NULL; + } + length = JSXML_LENGTH(xml); + } + + listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (listobj) { + list = (JSXML *) listobj->getPrivate(); + for (i = 0; i < length; i++) { + kid = OrphanXMLChild(cx, xml, i); + if (!kid || !Append(cx, list, kid)) { + listobj = NULL; + break; + } + } + } + + if (xml) + js_LeaveLocalRootScopeWithResult(cx, listobj); + return listobj; + +bad: + js_ReportValueError(cx, JSMSG_BAD_XMLLIST_CONVERSION, + JSDVG_IGNORE_STACK, Valueify(v), NULL); + return NULL; +} + +/* + * ECMA-357 10.2.1 Steps 5-7 pulled out as common subroutines of XMLToXMLString + * and their library-public js_* counterparts. The guts of MakeXMLCDataString, + * MakeXMLCommentString, and MakeXMLPIString are further factored into a common + * MakeXMLSpecialString subroutine. + * + * These functions mutate sb, leaving it empty. + */ +static JSFlatString * +MakeXMLSpecialString(JSContext *cx, StringBuffer &sb, + JSString *str, JSString *str2, + const jschar *prefix, size_t prefixlength, + const jschar *suffix, size_t suffixlength) +{ + if (!sb.append(prefix, prefixlength) || !sb.append(str)) + return NULL; + if (str2 && !str2->empty()) { + if (!sb.append(' ') || !sb.append(str2)) + return NULL; + } + if (!sb.append(suffix, suffixlength)) + return NULL; + + return sb.finishString(); +} + +static JSFlatString * +MakeXMLCDATAString(JSContext *cx, StringBuffer &sb, JSString *str) +{ + static const jschar cdata_prefix_ucNstr[] = {'<', '!', '[', + 'C', 'D', 'A', 'T', 'A', + '['}; + static const jschar cdata_suffix_ucNstr[] = {']', ']', '>'}; + + return MakeXMLSpecialString(cx, sb, str, NULL, + cdata_prefix_ucNstr, 9, + cdata_suffix_ucNstr, 3); +} + +static JSFlatString * +MakeXMLCommentString(JSContext *cx, StringBuffer &sb, JSString *str) +{ + static const jschar comment_prefix_ucNstr[] = {'<', '!', '-', '-'}; + static const jschar comment_suffix_ucNstr[] = {'-', '-', '>'}; + + return MakeXMLSpecialString(cx, sb, str, NULL, + comment_prefix_ucNstr, 4, + comment_suffix_ucNstr, 3); +} + +static JSFlatString * +MakeXMLPIString(JSContext *cx, StringBuffer &sb, JSString *name, + JSString *value) +{ + static const jschar pi_prefix_ucNstr[] = {'<', '?'}; + static const jschar pi_suffix_ucNstr[] = {'?', '>'}; + + return MakeXMLSpecialString(cx, sb, name, value, + pi_prefix_ucNstr, 2, + pi_suffix_ucNstr, 2); +} + +/* + * ECMA-357 10.2.1 17(d-g) pulled out into a common subroutine that appends + * equals, a double quote, an attribute value, and a closing double quote. + */ +static bool +AppendAttributeValue(JSContext *cx, StringBuffer &sb, JSString *valstr) +{ + if (!sb.append('=')) + return false; + valstr = js_EscapeAttributeValue(cx, valstr, JS_TRUE); + return valstr && sb.append(valstr); +} + +/* + * ECMA-357 10.2.1.1 EscapeElementValue helper method. + + * These functions mutate sb, leaving it empty. + */ +static JSFlatString * +EscapeElementValue(JSContext *cx, StringBuffer &sb, JSString *str, uint32 toSourceFlag) +{ + size_t length = str->length(); + const jschar *start = str->getChars(cx); + if (!start) + return NULL; + + for (const jschar *cp = start, *end = start + length; cp != end; ++cp) { + jschar c = *cp; + switch (*cp) { + case '<': + if (!sb.append(js_lt_entity_str)) + return NULL; + break; + case '>': + if (!sb.append(js_gt_entity_str)) + return NULL; + break; + case '&': + if (!sb.append(js_amp_entity_str)) + return NULL; + break; + case '{': + /* + * If EscapeElementValue is called by toSource/uneval, we also need + * to escape '{'. See bug 463360. + */ + if (toSourceFlag) { + if (!sb.append(js_leftcurly_entity_str)) + return NULL; + break; + } + /* FALL THROUGH */ + default: + if (!sb.append(c)) + return NULL; + } + } + return sb.finishString(); +} + +/* + * ECMA-357 10.2.1.2 EscapeAttributeValue helper method. + * + * These functions mutate sb, leaving it empty. + */ +static JSFlatString * +EscapeAttributeValue(JSContext *cx, StringBuffer &sb, JSString *str, JSBool quote) +{ + size_t length = str->length(); + const jschar *start = str->getChars(cx); + if (!start) + return NULL; + + if (quote && !sb.append('"')) + return NULL; + + for (const jschar *cp = start, *end = start + length; cp != end; ++cp) { + jschar c = *cp; + switch (c) { + case '"': + if (!sb.append(js_quot_entity_str)) + return NULL; + break; + case '<': + if (!sb.append(js_lt_entity_str)) + return NULL; + break; + case '&': + if (!sb.append(js_amp_entity_str)) + return NULL; + break; + case '\n': + if (!sb.append(" ")) + return NULL; + break; + case '\r': + if (!sb.append(" ")) + return NULL; + break; + case '\t': + if (!sb.append(" ")) + return NULL; + break; + default: + if (!sb.append(c)) + return NULL; + } + } + + if (quote && !sb.append('"')) + return NULL; + + return sb.finishString(); +} + +/* 13.3.5.4 [[GetNamespace]]([InScopeNamespaces]) */ +static JSObject * +GetNamespace(JSContext *cx, JSObject *qn, const JSXMLArray *inScopeNSes) +{ + JSLinearString *uri, *prefix, *nsprefix; + JSObject *match, *ns; + uint32 i, n; + jsval argv[2]; + + uri = qn->getNameURI(); + prefix = qn->getNamePrefix(); + JS_ASSERT(uri); + if (!uri) { + JSAutoByteString bytes; + const char *s = !prefix ? + js_undefined_str + : js_ValueToPrintable(cx, StringValue(prefix), &bytes); + if (s) + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_XML_NAMESPACE, s); + return NULL; + } + + /* Look for a matching namespace in inScopeNSes, if provided. */ + match = NULL; + if (inScopeNSes) { + for (i = 0, n = inScopeNSes->length; i < n; i++) { + ns = XMLARRAY_MEMBER(inScopeNSes, i, JSObject); + if (!ns) + continue; + + /* + * Erratum, very tricky, and not specified in ECMA-357 13.3.5.4: + * If we preserve prefixes, we must match null prefix against + * an empty prefix of ns, in order to avoid generating redundant + * prefixed and default namespaces for cases such as: + * + * x = + * print(x.toXMLString()); + * + * Per 10.3.2.1, the namespace attribute in t has an empty string + * prefix (*not* a null prefix), per 10.3.2.1 Step 6(h)(i)(1): + * + * 1. If the [local name] property of a is "xmlns" + * a. Map ns.prefix to the empty string + * + * But t's name has a null prefix in this implementation, meaning + * *undefined*, per 10.3.2.1 Step 6(c)'s NOTE (which refers to + * the http://www.w3.org/TR/xml-infoset/ spec, item 2.2.3, without + * saying how "no value" maps to an ECMA-357 value -- but it must + * map to the *undefined* prefix value). + * + * Since "" != undefined (or null, in the current implementation) + * the ECMA-357 spec will fail to match in [[GetNamespace]] called + * on t with argument {} U {(prefix="", uri="http://foo.com")}. + * This spec bug leads to ToXMLString results that duplicate the + * declared namespace. + */ + if (EqualStrings(ns->getNameURI(), uri)) { + nsprefix = ns->getNamePrefix(); + if (nsprefix == prefix || + ((nsprefix && prefix) + ? EqualStrings(nsprefix, prefix) + : (nsprefix ? nsprefix : prefix)->empty())) { + match = ns; + break; + } + } + } + } + + /* If we didn't match, make a new namespace from qn. */ + if (!match) { + argv[0] = prefix ? STRING_TO_JSVAL(prefix) : JSVAL_VOID; + argv[1] = STRING_TO_JSVAL(uri); + ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL, + 2, Valueify(argv)); + if (!ns) + return NULL; + match = ns; + } + return match; +} + +static JSLinearString * +GeneratePrefix(JSContext *cx, JSLinearString *uri, JSXMLArray *decls) +{ + const jschar *cp, *start, *end; + size_t length, newlength, offset; + uint32 i, n, m, serial; + jschar *bp, *dp; + JSBool done; + JSObject *ns; + JSLinearString *nsprefix, *prefix; + + JS_ASSERT(!uri->empty()); + + /* + * If there are no *declared* namespaces, skip all collision detection and + * return a short prefix quickly; an example of such a situation: + * + * var x = ; + * var n = new Namespace("http://example.com/"); + * x.@n::att = "val"; + * x.toXMLString(); + * + * This is necessary for various log10 uses below to be valid. + */ + if (decls->length == 0) + return js_NewStringCopyZ(cx, "a"); + + /* + * Try peeling off the last filename suffix or pathname component till + * we have a valid XML name. This heuristic will prefer "xul" given + * ".../there.is.only.xul", "xbl" given ".../xbl", and "xbl2" given any + * likely URI of the form ".../xbl2/2005". + */ + start = uri->chars(); + end = start + uri->length(); + cp = end; + while (--cp > start) { + if (*cp == '.' || *cp == '/' || *cp == ':') { + ++cp; + length = end - cp; + if (IsXMLName(cp, length) && !STARTS_WITH_XML(cp, length)) + break; + end = --cp; + } + } + length = end - cp; + + /* + * If the namespace consisted only of non-XML names or names that begin + * case-insensitively with "xml", arbitrarily create a prefix consisting + * of 'a's of size length (allowing dp-calculating code to work with or + * without this branch executing) plus the space for storing a hyphen and + * the serial number (avoiding reallocation if a collision happens). + */ + bp = (jschar *) cp; + newlength = length; + if (STARTS_WITH_XML(cp, length) || !IsXMLName(cp, length)) { + newlength = length + 2 + (size_t) log10((double) decls->length); + bp = (jschar *) + cx->malloc((newlength + 1) * sizeof(jschar)); + if (!bp) + return NULL; + + bp[newlength] = 0; + for (i = 0; i < newlength; i++) + bp[i] = 'a'; + } + + /* + * Now search through decls looking for a collision. If we collide with + * an existing prefix, start tacking on a hyphen and a serial number. + */ + serial = 0; + do { + done = JS_TRUE; + for (i = 0, n = decls->length; i < n; i++) { + ns = XMLARRAY_MEMBER(decls, i, JSObject); + if (ns && (nsprefix = ns->getNamePrefix()) && + nsprefix->length() == newlength && + !memcmp(nsprefix->chars(), bp, + newlength * sizeof(jschar))) { + if (bp == cp) { + newlength = length + 2 + (size_t) log10((double) n); + bp = (jschar *) + cx->malloc((newlength + 1) * sizeof(jschar)); + if (!bp) + return NULL; + js_strncpy(bp, cp, length); + } + + ++serial; + JS_ASSERT(serial <= n); + dp = bp + length + 2 + (size_t) log10((double) serial); + *dp = 0; + for (m = serial; m != 0; m /= 10) + *--dp = (jschar)('0' + m % 10); + *--dp = '-'; + JS_ASSERT(dp == bp + length); + + done = JS_FALSE; + break; + } + } + } while (!done); + + if (bp == cp) { + offset = cp - start; + prefix = js_NewDependentString(cx, uri, offset, length); + } else { + prefix = js_NewString(cx, bp, newlength); + if (!prefix) + cx->free(bp); + } + return prefix; +} + +static JSBool +namespace_match(const void *a, const void *b) +{ + const JSObject *nsa = (const JSObject *) a; + const JSObject *nsb = (const JSObject *) b; + JSLinearString *prefixa, *prefixb = nsb->getNamePrefix(); + + if (prefixb) { + prefixa = nsa->getNamePrefix(); + return prefixa && EqualStrings(prefixa, prefixb); + } + return EqualStrings(nsa->getNameURI(), nsb->getNameURI()); +} + +/* ECMA-357 10.2.1 and 10.2.2 */ +#define TO_SOURCE_FLAG 0x80000000 + +static JSString * +XMLToXMLString(JSContext *cx, JSXML *xml, const JSXMLArray *ancestorNSes, + uint32 indentLevel) +{ + JSBool pretty, indentKids; + StringBuffer sb(cx); + JSString *str; + JSLinearString *prefix, *nsuri; + uint32 i, n, nextIndentLevel; + JSObject *ns, *ns2; + AutoNamespaceArray empty(cx), decls(cx), ancdecls(cx); + + if (!GetBooleanXMLSetting(cx, js_prettyPrinting_str, &pretty)) + return NULL; + + if (pretty) { + if (!sb.appendN(' ', indentLevel & ~TO_SOURCE_FLAG)) + return NULL; + } + + str = NULL; + + switch (xml->xml_class) { + case JSXML_CLASS_TEXT: + /* Step 4. */ + if (pretty) { + str = ChompXMLWhitespace(cx, xml->xml_value); + if (!str) + return NULL; + } else { + str = xml->xml_value; + } + return EscapeElementValue(cx, sb, str, indentLevel & TO_SOURCE_FLAG); + + case JSXML_CLASS_ATTRIBUTE: + /* Step 5. */ + return EscapeAttributeValue(cx, sb, xml->xml_value, + (indentLevel & TO_SOURCE_FLAG) != 0); + + case JSXML_CLASS_COMMENT: + /* Step 6. */ + return MakeXMLCommentString(cx, sb, xml->xml_value); + + case JSXML_CLASS_PROCESSING_INSTRUCTION: + /* Step 7. */ + return MakeXMLPIString(cx, sb, xml->name->getQNameLocalName(), + xml->xml_value); + + case JSXML_CLASS_LIST: + /* ECMA-357 10.2.2. */ + { + JSXMLArrayCursor cursor(&xml->xml_kids); + i = 0; + while (JSXML *kid = (JSXML *) cursor.getNext()) { + if (pretty && i != 0) { + if (!sb.append('\n')) + return NULL; + } + + JSString *kidstr = XMLToXMLString(cx, kid, ancestorNSes, indentLevel); + if (!kidstr || !sb.append(kidstr)) + return NULL; + ++i; + } + } + + if (sb.empty()) + return cx->runtime->emptyString; + return sb.finishString(); + + default:; + } + + /* After this point, control must flow through label out: to exit. */ + if (!js_EnterLocalRootScope(cx)) + return NULL; + + /* ECMA-357 10.2.1 step 8 onward: handle ToXMLString on an XML element. */ + if (!ancestorNSes) + ancestorNSes = &empty.array; + + /* Clone in-scope namespaces not in ancestorNSes into decls. */ + { + JSXMLArrayCursor cursor(&xml->xml_namespaces); + while ((ns = (JSObject *) cursor.getNext()) != NULL) { + if (!IsDeclared(ns)) + continue; + if (!XMLARRAY_HAS_MEMBER(ancestorNSes, ns, namespace_identity)) { + /* NOTE: may want to exclude unused namespaces here. */ + ns2 = NewXMLNamespace(cx, ns->getNamePrefix(), ns->getNameURI(), JS_TRUE); + if (!ns2 || !XMLARRAY_APPEND(cx, &decls.array, ns2)) + goto out; + } + } + } + + /* + * Union ancestorNSes and decls into ancdecls. Note that ancdecls does + * not own its member references. In the spec, ancdecls has no name, but + * is always written out as (AncestorNamespaces U namespaceDeclarations). + */ + + if (!ancdecls.array.setCapacity(cx, ancestorNSes->length + decls.length())) + goto out; + for (i = 0, n = ancestorNSes->length; i < n; i++) { + ns2 = XMLARRAY_MEMBER(ancestorNSes, i, JSObject); + if (!ns2) + continue; + JS_ASSERT(!XMLARRAY_HAS_MEMBER(&decls.array, ns2, namespace_identity)); + if (!XMLARRAY_APPEND(cx, &ancdecls.array, ns2)) + goto out; + } + for (i = 0, n = decls.length(); i < n; i++) { + ns2 = XMLARRAY_MEMBER(&decls.array, i, JSObject); + if (!ns2) + continue; + JS_ASSERT(!XMLARRAY_HAS_MEMBER(&ancdecls.array, ns2, namespace_identity)); + if (!XMLARRAY_APPEND(cx, &ancdecls.array, ns2)) + goto out; + } + + /* Step 11, except we don't clone ns unless its prefix is undefined. */ + ns = GetNamespace(cx, xml->name, &ancdecls.array); + if (!ns) + goto out; + + /* Step 12 (NULL means *undefined* here), plus the deferred ns cloning. */ + prefix = ns->getNamePrefix(); + if (!prefix) { + /* + * Create a namespace prefix that isn't used by any member of decls. + * Assign the new prefix to a copy of ns. Flag this namespace as if + * it were declared, for assertion-testing's sake later below. + * + * Erratum: if prefix and xml->name are both null (*undefined* in + * ECMA-357), we know that xml was named using the default namespace + * (proof: see GetNamespace and the Namespace constructor called with + * two arguments). So we ought not generate a new prefix here, when + * we can declare ns as the default namespace for xml. + * + * This helps descendants inherit the namespace instead of redundantly + * redeclaring it with generated prefixes in each descendant. + */ + nsuri = ns->getNameURI(); + if (!xml->name->getNamePrefix()) { + prefix = cx->runtime->emptyString; + } else { + prefix = GeneratePrefix(cx, nsuri, &ancdecls.array); + if (!prefix) + goto out; + } + ns = NewXMLNamespace(cx, prefix, nsuri, JS_TRUE); + if (!ns) + goto out; + + /* + * If the xml->name was unprefixed, we must remove any declared default + * namespace from decls before appending ns. How can you get a default + * namespace in decls that doesn't match the one from name? Apparently + * by calling x.setNamespace(ns) where ns has no prefix. The other way + * to fix this is to update x's in-scope namespaces when setNamespace + * is called, but that's not specified by ECMA-357. + * + * Likely Erratum here, depending on whether the lack of update to x's + * in-scope namespace in XML.prototype.setNamespace (13.4.4.36) is an + * erratum or not. Note that changing setNamespace to update the list + * of in-scope namespaces will change x.namespaceDeclarations(). + */ + if (prefix->empty()) { + i = XMLArrayFindMember(&decls.array, ns, namespace_match); + if (i != XML_NOT_FOUND) + XMLArrayDelete(cx, &decls.array, i, JS_TRUE); + } + + /* + * In the spec, ancdecls has no name, but is always written out as + * (AncestorNamespaces U namespaceDeclarations). Since we compute + * that union in ancdecls, any time we append a namespace strong + * ref to decls, we must also append a weak ref to ancdecls. Order + * matters here: code at label out: releases strong refs in decls. + */ + if (!XMLARRAY_APPEND(cx, &ancdecls.array, ns) || + !XMLARRAY_APPEND(cx, &decls.array, ns)) { + goto out; + } + } + + /* Format the element or point-tag into sb. */ + if (!sb.append('<')) + goto out; + + if (!prefix->empty()) { + if (!sb.append(prefix) || !sb.append(':')) + goto out; + } + if (!sb.append(xml->name->getQNameLocalName())) + goto out; + + /* + * Step 16 makes a union to avoid writing two loops in step 17, to share + * common attribute value appending spec-code. We prefer two loops for + * faster code and less data overhead. + */ + + /* Step 17(b): append attributes. */ + { + JSXMLArrayCursor cursor(&xml->xml_attrs); + while (JSXML *attr = (JSXML *) cursor.getNext()) { + if (!sb.append(' ')) + goto out; + ns2 = GetNamespace(cx, attr->name, &ancdecls.array); + if (!ns2) + goto out; + + /* 17(b)(ii): NULL means *undefined* here. */ + prefix = ns2->getNamePrefix(); + if (!prefix) { + prefix = GeneratePrefix(cx, ns2->getNameURI(), &ancdecls.array); + if (!prefix) + goto out; + + /* Again, we avoid copying ns2 until we know it's prefix-less. */ + ns2 = NewXMLNamespace(cx, prefix, ns2->getNameURI(), JS_TRUE); + if (!ns2) + goto out; + + /* + * In the spec, ancdecls has no name, but is always written out as + * (AncestorNamespaces U namespaceDeclarations). Since we compute + * that union in ancdecls, any time we append a namespace strong + * ref to decls, we must also append a weak ref to ancdecls. Order + * matters here: code at label out: releases strong refs in decls. + */ + if (!XMLARRAY_APPEND(cx, &ancdecls.array, ns2) || + !XMLARRAY_APPEND(cx, &decls.array, ns2)) { + goto out; + } + } + + /* 17(b)(iii). */ + if (!prefix->empty()) { + if (!sb.append(prefix) || !sb.append(':')) + goto out; + } + + /* 17(b)(iv). */ + if (!sb.append(attr->name->getQNameLocalName())) + goto out; + + /* 17(d-g). */ + if (!AppendAttributeValue(cx, sb, attr->xml_value)) + goto out; + } + } + + /* Step 17(c): append XML namespace declarations. */ + { + JSXMLArrayCursor cursor(&decls.array); + while (JSObject *ns3 = (JSObject *) cursor.getNext()) { + JS_ASSERT(IsDeclared(ns3)); + + if (!sb.append(" xmlns")) + goto out; + + /* 17(c)(ii): NULL means *undefined* here. */ + prefix = ns3->getNamePrefix(); + if (!prefix) { + prefix = GeneratePrefix(cx, ns3->getNameURI(), &ancdecls.array); + if (!prefix) + goto out; + ns3->setNamePrefix(prefix); + } + + /* 17(c)(iii). */ + if (!prefix->empty()) { + if (!sb.append(':') || !sb.append(prefix)) + goto out; + } + + /* 17(d-g). */ + if (!AppendAttributeValue(cx, sb, ns3->getNameURI())) + goto out; + } + } + + /* Step 18: handle point tags. */ + n = xml->xml_kids.length; + if (n == 0) { + if (!sb.append("/>")) + goto out; + } else { + /* Steps 19 through 25: handle element content, and open the end-tag. */ + if (!sb.append('>')) + goto out; + { + JSXML *kid; + indentKids = n > 1 || + (n == 1 && + (kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML)) && + kid->xml_class != JSXML_CLASS_TEXT); + } + + if (pretty && indentKids) { + if (!GetUint32XMLSetting(cx, js_prettyIndent_str, &i)) + goto out; + nextIndentLevel = indentLevel + i; + } else { + nextIndentLevel = indentLevel & TO_SOURCE_FLAG; + } + + { + JSXMLArrayCursor cursor(&xml->xml_kids); + while (JSXML *kid = (JSXML *) cursor.getNext()) { + if (pretty && indentKids) { + if (!sb.append('\n')) + goto out; + } + + JSString *kidstr = XMLToXMLString(cx, kid, &ancdecls.array, nextIndentLevel); + if (!kidstr) + goto out; + + if (!sb.append(kidstr)) + goto out; + } + } + + if (pretty && indentKids) { + if (!sb.append('\n') || + !sb.appendN(' ', indentLevel & ~TO_SOURCE_FLAG)) + goto out; + } + if (!sb.append("getNamePrefix(); + if (prefix && !prefix->empty()) { + if (!sb.append(prefix) || !sb.append(':')) + goto out; + } + + /* Step 27. */ + if (!sb.append(xml->name->getQNameLocalName()) || !sb.append('>')) + goto out; + } + + str = sb.finishString(); +out: + js_LeaveLocalRootScopeWithResult(cx, str); + return str; +} + +/* ECMA-357 10.2 */ +static JSString * +ToXMLString(JSContext *cx, jsval v, uint32 toSourceFlag) +{ + JSObject *obj; + JSString *str; + JSXML *xml; + + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_XML_CONVERSION, + JSVAL_IS_NULL(v) ? js_null_str : js_undefined_str); + return NULL; + } + + if (JSVAL_IS_BOOLEAN(v) || JSVAL_IS_NUMBER(v)) + return js_ValueToString(cx, Valueify(v)); + + if (JSVAL_IS_STRING(v)) { + StringBuffer sb(cx); + return EscapeElementValue(cx, sb, JSVAL_TO_STRING(v), toSourceFlag); + } + + obj = JSVAL_TO_OBJECT(v); + if (!obj->isXML()) { + if (!DefaultValue(cx, obj, JSTYPE_STRING, Valueify(&v))) + return NULL; + str = js_ValueToString(cx, Valueify(v)); + if (!str) + return NULL; + StringBuffer sb(cx); + return EscapeElementValue(cx, sb, str, toSourceFlag); + } + + /* Handle non-element cases in this switch, returning from each case. */ + xml = (JSXML *) obj->getPrivate(); + return XMLToXMLString(cx, xml, NULL, toSourceFlag | 0); +} + +static JSObject * +ToAttributeName(JSContext *cx, jsval v) +{ + JSLinearString *name, *uri, *prefix; + JSObject *obj; + Class *clasp; + JSObject *qn; + + if (JSVAL_IS_STRING(v)) { + name = JSVAL_TO_STRING(v)->ensureLinear(cx); + if (!name) + return NULL; + uri = prefix = cx->runtime->emptyString; + } else { + if (JSVAL_IS_PRIMITIVE(v)) { + js_ReportValueError(cx, JSMSG_BAD_XML_ATTR_NAME, + JSDVG_IGNORE_STACK, Valueify(v), NULL); + return NULL; + } + + obj = JSVAL_TO_OBJECT(v); + clasp = obj->getClass(); + if (clasp == &js_AttributeNameClass) + return obj; + + if (clasp == &js_QNameClass) { + qn = obj; + uri = qn->getNameURI(); + prefix = qn->getNamePrefix(); + name = qn->getQNameLocalName(); + } else { + if (clasp == &js_AnyNameClass) { + name = ATOM_TO_STRING(cx->runtime->atomState.starAtom); + } else { + JSString *str = js_ValueToString(cx, Valueify(v)); + if (!str) + return NULL; + name = str->ensureLinear(cx); + if (!name) + return NULL; + } + uri = prefix = cx->runtime->emptyString; + } + } + + qn = NewXMLAttributeName(cx, uri, prefix, name); + if (!qn) + return NULL; + return qn; +} + +static void +ReportBadXMLName(JSContext *cx, const Value &idval) +{ + js_ReportValueError(cx, JSMSG_BAD_XML_NAME, JSDVG_IGNORE_STACK, idval, NULL); +} + +static JSBool +IsFunctionQName(JSContext *cx, JSObject *qn, jsid *funidp) +{ + JSAtom *atom; + JSLinearString *uri; + + atom = cx->runtime->atomState.functionNamespaceURIAtom; + uri = qn->getNameURI(); + if (uri && + (uri == ATOM_TO_STRING(atom) || + EqualStrings(uri, ATOM_TO_STRING(atom)))) { + return JS_ValueToId(cx, STRING_TO_JSVAL(qn->getQNameLocalName()), funidp); + } + *funidp = JSID_VOID; + return JS_TRUE; +} + +JSBool +js_IsFunctionQName(JSContext *cx, JSObject *obj, jsid *funidp) +{ + if (obj->getClass() == &js_QNameClass) + return IsFunctionQName(cx, obj, funidp); + *funidp = JSID_VOID; + return JS_TRUE; +} + +static JSObject * +ToXMLName(JSContext *cx, jsval v, jsid *funidp) +{ + JSAtom *atomizedName; + JSString *name; + JSObject *obj; + Class *clasp; + uint32 index; + + if (JSVAL_IS_STRING(v)) { + name = JSVAL_TO_STRING(v); + } else { + if (JSVAL_IS_PRIMITIVE(v)) { + ReportBadXMLName(cx, Valueify(v)); + return NULL; + } + + obj = JSVAL_TO_OBJECT(v); + clasp = obj->getClass(); + if (clasp == &js_AttributeNameClass || clasp == &js_QNameClass) + goto out; + if (clasp == &js_AnyNameClass) { + name = ATOM_TO_STRING(cx->runtime->atomState.starAtom); + goto construct; + } + name = js_ValueToString(cx, Valueify(v)); + if (!name) + return NULL; + } + + atomizedName = js_AtomizeString(cx, name, 0); + if (!atomizedName) + return NULL; + + /* + * ECMA-357 10.6.1 step 1 seems to be incorrect. The spec says: + * + * 1. If ToString(ToNumber(P)) == ToString(P), throw a TypeError exception + * + * First, _P_ should be _s_, to refer to the given string. + * + * Second, why does ToXMLName applied to the string type throw TypeError + * only for numeric literals without any leading or trailing whitespace? + * + * If the idea is to reject uint32 property names, then the check needs to + * be stricter, to exclude hexadecimal and floating point literals. + */ + if (js_IdIsIndex(ATOM_TO_JSID(atomizedName), &index)) + goto bad; + + if (*atomizedName->chars() == '@') { + name = js_NewDependentString(cx, name, 1, name->length() - 1); + if (!name) + return NULL; + *funidp = JSID_VOID; + return ToAttributeName(cx, STRING_TO_JSVAL(name)); + } + +construct: + v = STRING_TO_JSVAL(name); + obj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1, Valueify(&v)); + if (!obj) + return NULL; + +out: + if (!IsFunctionQName(cx, obj, funidp)) + return NULL; + return obj; + +bad: + JSAutoByteString bytes; + if (js_ValueToPrintable(cx, StringValue(name), &bytes)) + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_XML_NAME, bytes.ptr()); + return NULL; +} + +/* ECMA-357 9.1.1.13 XML [[AddInScopeNamespace]]. */ +static JSBool +AddInScopeNamespace(JSContext *cx, JSXML *xml, JSObject *ns) +{ + JSLinearString *prefix, *prefix2; + JSObject *match, *ns2; + uint32 i, n, m; + + if (xml->xml_class != JSXML_CLASS_ELEMENT) + return JS_TRUE; + + /* NULL means *undefined* here -- see ECMA-357 9.1.1.13 step 2. */ + prefix = ns->getNamePrefix(); + if (!prefix) { + match = NULL; + for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { + ns2 = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + if (ns2 && EqualStrings(ns2->getNameURI(), ns->getNameURI())) { + match = ns2; + break; + } + } + if (!match && !XMLARRAY_ADD_MEMBER(cx, &xml->xml_namespaces, n, ns)) + return JS_FALSE; + } else { + if (prefix->empty() && xml->name->getNameURI()->empty()) + return JS_TRUE; + match = NULL; +#ifdef __GNUC__ /* suppress bogus gcc warnings */ + m = XML_NOT_FOUND; +#endif + for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { + ns2 = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + if (ns2 && (prefix2 = ns2->getNamePrefix()) && + EqualStrings(prefix2, prefix)) { + match = ns2; + m = i; + break; + } + } + if (match && !EqualStrings(match->getNameURI(), ns->getNameURI())) { + ns2 = XMLARRAY_DELETE(cx, &xml->xml_namespaces, m, JS_TRUE, + JSObject); + JS_ASSERT(ns2 == match); + match->clearNamePrefix(); + if (!AddInScopeNamespace(cx, xml, match)) + return JS_FALSE; + } + if (!XMLARRAY_APPEND(cx, &xml->xml_namespaces, ns)) + return JS_FALSE; + } + + /* OPTION: enforce that descendants have superset namespaces. */ + return JS_TRUE; +} + +/* ECMA-357 9.2.1.6 XMLList [[Append]]. */ +static JSBool +Append(JSContext *cx, JSXML *list, JSXML *xml) +{ + uint32 i, j, k, n; + JSXML *kid; + + JS_ASSERT(list->xml_class == JSXML_CLASS_LIST); + i = list->xml_kids.length; + n = 1; + if (xml->xml_class == JSXML_CLASS_LIST) { + list->xml_target = xml->xml_target; + list->xml_targetprop = xml->xml_targetprop; + n = JSXML_LENGTH(xml); + k = i + n; + if (!list->xml_kids.setCapacity(cx, k)) + return JS_FALSE; + for (j = 0; j < n; j++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, j, JSXML); + if (kid) + XMLARRAY_SET_MEMBER(&list->xml_kids, i + j, kid); + } + return JS_TRUE; + } + + list->xml_target = xml->parent; + if (xml->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION) + list->xml_targetprop = NULL; + else + list->xml_targetprop = xml->name; + if (!XMLARRAY_ADD_MEMBER(cx, &list->xml_kids, i, xml)) + return JS_FALSE; + return JS_TRUE; +} + +/* ECMA-357 9.1.1.7 XML [[DeepCopy]] and 9.2.1.7 XMLList [[DeepCopy]]. */ +static JSXML * +DeepCopyInLRS(JSContext *cx, JSXML *xml, uintN flags); + +static JSXML * +DeepCopy(JSContext *cx, JSXML *xml, JSObject *obj, uintN flags) +{ + JSXML *copy; + + /* Our caller may not be protecting newborns with a local root scope. */ + if (!js_EnterLocalRootScope(cx)) + return NULL; + copy = DeepCopyInLRS(cx, xml, flags); + if (copy) { + if (obj) { + /* Caller provided the object for this copy, hook 'em up. */ + obj->setPrivate(copy); + copy->object = obj; + } else if (!js_GetXMLObject(cx, copy)) { + copy = NULL; + } + } + js_LeaveLocalRootScopeWithResult(cx, copy); + return copy; +} + +/* + * (i) We must be in a local root scope (InLRS). + * (ii) parent must have a rooted object. + * (iii) from's owning object must be locked if not thread-local. + */ +static JSBool +DeepCopySetInLRS(JSContext *cx, JSXMLArray *from, JSXMLArray *to, JSXML *parent, + uintN flags) +{ + uint32 j, n; + JSXML *kid2; + JSString *str; + + n = from->length; + if (!to->setCapacity(cx, n)) + return JS_FALSE; + + JSXMLArrayCursor cursor(from); + j = 0; + while (JSXML *kid = (JSXML *) cursor.getNext()) { + if ((flags & XSF_IGNORE_COMMENTS) && + kid->xml_class == JSXML_CLASS_COMMENT) { + continue; + } + if ((flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS) && + kid->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION) { + continue; + } + if ((flags & XSF_IGNORE_WHITESPACE) && + (kid->xml_flags & XMLF_WHITESPACE_TEXT)) { + continue; + } + kid2 = DeepCopyInLRS(cx, kid, flags); + if (!kid2) { + to->length = j; + return JS_FALSE; + } + + if ((flags & XSF_IGNORE_WHITESPACE) && + n > 1 && kid2->xml_class == JSXML_CLASS_TEXT) { + str = ChompXMLWhitespace(cx, kid2->xml_value); + if (!str) { + to->length = j; + return JS_FALSE; + } + kid2->xml_value = str; + } + + XMLARRAY_SET_MEMBER(to, j, kid2); + ++j; + if (parent->xml_class != JSXML_CLASS_LIST) + kid2->parent = parent; + } + + if (j < n) + to->trim(); + return JS_TRUE; +} + +static JSXML * +DeepCopyInLRS(JSContext *cx, JSXML *xml, uintN flags) +{ + JSXML *copy; + JSObject *qn; + JSBool ok; + uint32 i, n; + JSObject *ns, *ns2; + + JS_CHECK_RECURSION(cx, return NULL); + + copy = js_NewXML(cx, JSXMLClass(xml->xml_class)); + if (!copy) + return NULL; + qn = xml->name; + if (qn) { + qn = NewXMLQName(cx, qn->getNameURI(), qn->getNamePrefix(), qn->getQNameLocalName()); + if (!qn) { + ok = JS_FALSE; + goto out; + } + } + copy->name = qn; + copy->xml_flags = xml->xml_flags; + + if (JSXML_HAS_VALUE(xml)) { + copy->xml_value = xml->xml_value; + ok = JS_TRUE; + } else { + ok = DeepCopySetInLRS(cx, &xml->xml_kids, ©->xml_kids, copy, flags); + if (!ok) + goto out; + + if (xml->xml_class == JSXML_CLASS_LIST) { + copy->xml_target = xml->xml_target; + copy->xml_targetprop = xml->xml_targetprop; + } else { + n = xml->xml_namespaces.length; + ok = copy->xml_namespaces.setCapacity(cx, n); + if (!ok) + goto out; + for (i = 0; i < n; i++) { + ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + if (!ns) + continue; + ns2 = NewXMLNamespace(cx, ns->getNamePrefix(), ns->getNameURI(), + IsDeclared(ns)); + if (!ns2) { + copy->xml_namespaces.length = i; + ok = JS_FALSE; + goto out; + } + XMLARRAY_SET_MEMBER(©->xml_namespaces, i, ns2); + } + + ok = DeepCopySetInLRS(cx, &xml->xml_attrs, ©->xml_attrs, copy, + 0); + if (!ok) + goto out; + } + } + +out: + if (!ok) + return NULL; + return copy; +} + +/* ECMA-357 9.1.1.4 XML [[DeleteByIndex]]. */ +static void +DeleteByIndex(JSContext *cx, JSXML *xml, uint32 index) +{ + JSXML *kid; + + if (JSXML_HAS_KIDS(xml) && index < xml->xml_kids.length) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); + if (kid) + kid->parent = NULL; + XMLArrayDelete(cx, &xml->xml_kids, index, JS_TRUE); + } +} + +typedef JSBool (*JSXMLNameMatcher)(JSObject *nameqn, JSXML *xml); + +static JSBool +MatchAttrName(JSObject *nameqn, JSXML *attr) +{ + JSObject *attrqn = attr->name; + JSLinearString *localName = nameqn->getQNameLocalName(); + JSLinearString *uri; + + return (IS_STAR(localName) || + EqualStrings(attrqn->getQNameLocalName(), localName)) && + (!(uri = nameqn->getNameURI()) || + EqualStrings(attrqn->getNameURI(), uri)); +} + +static JSBool +MatchElemName(JSObject *nameqn, JSXML *elem) +{ + JSLinearString *localName = nameqn->getQNameLocalName(); + JSLinearString *uri; + + return (IS_STAR(localName) || + (elem->xml_class == JSXML_CLASS_ELEMENT && + EqualStrings(elem->name->getQNameLocalName(), localName))) && + (!(uri = nameqn->getNameURI()) || + (elem->xml_class == JSXML_CLASS_ELEMENT && + EqualStrings(elem->name->getNameURI(), uri))); +} + +/* ECMA-357 9.1.1.8 XML [[Descendants]] and 9.2.1.8 XMLList [[Descendants]]. */ +static JSBool +DescendantsHelper(JSContext *cx, JSXML *xml, JSObject *nameqn, JSXML *list) +{ + uint32 i, n; + JSXML *attr, *kid; + + JS_CHECK_RECURSION(cx, return JS_FALSE); + + if (xml->xml_class == JSXML_CLASS_ELEMENT && + nameqn->getClass() == &js_AttributeNameClass) { + for (i = 0, n = xml->xml_attrs.length; i < n; i++) { + attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML); + if (attr && MatchAttrName(nameqn, attr)) { + if (!Append(cx, list, attr)) + return JS_FALSE; + } + } + } + + for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (!kid) + continue; + if (nameqn->getClass() != &js_AttributeNameClass && + MatchElemName(nameqn, kid)) { + if (!Append(cx, list, kid)) + return JS_FALSE; + } + if (!DescendantsHelper(cx, kid, nameqn, list)) + return JS_FALSE; + } + return JS_TRUE; +} + +static JSXML * +Descendants(JSContext *cx, JSXML *xml, jsval id) +{ + jsid funid; + JSObject *nameqn; + JSObject *listobj; + JSXML *list, *kid; + uint32 i, n; + JSBool ok; + + nameqn = ToXMLName(cx, id, &funid); + if (!nameqn) + return NULL; + + listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!listobj) + return NULL; + list = (JSXML *) listobj->getPrivate(); + if (!JSID_IS_VOID(funid)) + return list; + + /* + * Protect nameqn's object and strings from GC by linking list to it + * temporarily. The newborn GC root for the last allocated object + * protects listobj, which protects list. Any other object allocations + * occurring beneath DescendantsHelper use local roots. + */ + list->name = nameqn; + if (!js_EnterLocalRootScope(cx)) + return NULL; + if (xml->xml_class == JSXML_CLASS_LIST) { + ok = JS_TRUE; + for (i = 0, n = xml->xml_kids.length; i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { + ok = DescendantsHelper(cx, kid, nameqn, list); + if (!ok) + break; + } + } + } else { + ok = DescendantsHelper(cx, xml, nameqn, list); + } + js_LeaveLocalRootScopeWithResult(cx, list); + if (!ok) + return NULL; + list->name = NULL; + return list; +} + +/* Recursive (JSXML *) parameterized version of Equals. */ +static JSBool +XMLEquals(JSContext *cx, JSXML *xml, JSXML *vxml, JSBool *bp) +{ + JSObject *qn, *vqn; + uint32 i, j, n; + JSXML *kid, *vkid, *attr, *vattr; + JSObject *xobj, *vobj; + +retry: + if (xml->xml_class != vxml->xml_class) { + if (xml->xml_class == JSXML_CLASS_LIST && xml->xml_kids.length == 1) { + xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (xml) + goto retry; + } + if (vxml->xml_class == JSXML_CLASS_LIST && vxml->xml_kids.length == 1) { + vxml = XMLARRAY_MEMBER(&vxml->xml_kids, 0, JSXML); + if (vxml) + goto retry; + } + *bp = JS_FALSE; + return JS_TRUE; + } + + qn = xml->name; + vqn = vxml->name; + if (qn) { + *bp = vqn && + EqualStrings(qn->getQNameLocalName(), vqn->getQNameLocalName()) && + EqualStrings(qn->getNameURI(), vqn->getNameURI()); + } else { + *bp = vqn == NULL; + } + if (!*bp) + return JS_TRUE; + + if (JSXML_HAS_VALUE(xml)) { + if (!EqualStrings(cx, xml->xml_value, vxml->xml_value, bp)) + return JS_FALSE; + } else if (xml->xml_kids.length != vxml->xml_kids.length) { + *bp = JS_FALSE; + } else { + { + JSXMLArrayCursor cursor(&xml->xml_kids); + JSXMLArrayCursor vcursor(&vxml->xml_kids); + for (;;) { + kid = (JSXML *) cursor.getNext(); + vkid = (JSXML *) vcursor.getNext(); + if (!kid || !vkid) { + *bp = !kid && !vkid; + break; + } + xobj = js_GetXMLObject(cx, kid); + vobj = js_GetXMLObject(cx, vkid); + if (!xobj || !vobj || + !js_TestXMLEquality(cx, ObjectValue(*xobj), ObjectValue(*vobj), bp)) + return JS_FALSE; + if (!*bp) + break; + } + } + + if (*bp && xml->xml_class == JSXML_CLASS_ELEMENT) { + n = xml->xml_attrs.length; + if (n != vxml->xml_attrs.length) + *bp = JS_FALSE; + for (i = 0; *bp && i < n; i++) { + attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML); + if (!attr) + continue; + j = XMLARRAY_FIND_MEMBER(&vxml->xml_attrs, attr, attr_identity); + if (j == XML_NOT_FOUND) { + *bp = JS_FALSE; + break; + } + vattr = XMLARRAY_MEMBER(&vxml->xml_attrs, j, JSXML); + if (!vattr) + continue; + if (!EqualStrings(cx, attr->xml_value, vattr->xml_value, bp)) + return JS_FALSE; + } + } + } + + return JS_TRUE; +} + +/* ECMA-357 9.1.1.9 XML [[Equals]] and 9.2.1.9 XMLList [[Equals]]. */ +static JSBool +Equals(JSContext *cx, JSXML *xml, jsval v, JSBool *bp) +{ + JSObject *vobj; + JSXML *vxml; + + if (JSVAL_IS_PRIMITIVE(v)) { + *bp = JS_FALSE; + if (xml->xml_class == JSXML_CLASS_LIST) { + if (xml->xml_kids.length == 1) { + vxml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (!vxml) + return JS_TRUE; + vobj = js_GetXMLObject(cx, vxml); + if (!vobj) + return JS_FALSE; + return js_TestXMLEquality(cx, ObjectValue(*vobj), Valueify(v), bp); + } + if (JSVAL_IS_VOID(v) && xml->xml_kids.length == 0) + *bp = JS_TRUE; + } + } else { + vobj = JSVAL_TO_OBJECT(v); + if (!vobj->isXML()) { + *bp = JS_FALSE; + } else { + vxml = (JSXML *) vobj->getPrivate(); + if (!XMLEquals(cx, xml, vxml, bp)) + return JS_FALSE; + } + } + return JS_TRUE; +} + +static JSBool +CheckCycle(JSContext *cx, JSXML *xml, JSXML *kid) +{ + JS_ASSERT(kid->xml_class != JSXML_CLASS_LIST); + + do { + if (xml == kid) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CYCLIC_VALUE, js_XML_str); + return JS_FALSE; + } + } while ((xml = xml->parent) != NULL); + + return JS_TRUE; +} + +/* ECMA-357 9.1.1.11 XML [[Insert]]. */ +static JSBool +Insert(JSContext *cx, JSXML *xml, uint32 i, jsval v) +{ + uint32 j, n; + JSXML *vxml, *kid; + JSObject *vobj; + JSString *str; + + if (!JSXML_HAS_KIDS(xml)) + return JS_TRUE; + + n = 1; + vxml = NULL; + if (!JSVAL_IS_PRIMITIVE(v)) { + vobj = JSVAL_TO_OBJECT(v); + if (vobj->isXML()) { + vxml = (JSXML *) vobj->getPrivate(); + if (vxml->xml_class == JSXML_CLASS_LIST) { + n = vxml->xml_kids.length; + if (n == 0) + return JS_TRUE; + for (j = 0; j < n; j++) { + kid = XMLARRAY_MEMBER(&vxml->xml_kids, j, JSXML); + if (!kid) + continue; + if (!CheckCycle(cx, xml, kid)) + return JS_FALSE; + } + } else if (vxml->xml_class == JSXML_CLASS_ELEMENT) { + /* OPTION: enforce that descendants have superset namespaces. */ + if (!CheckCycle(cx, xml, vxml)) + return JS_FALSE; + } + } + } + if (!vxml) { + str = js_ValueToString(cx, Valueify(v)); + if (!str) + return JS_FALSE; + + vxml = js_NewXML(cx, JSXML_CLASS_TEXT); + if (!vxml) + return JS_FALSE; + vxml->xml_value = str; + } + + if (i > xml->xml_kids.length) + i = xml->xml_kids.length; + + if (!XMLArrayInsert(cx, &xml->xml_kids, i, n)) + return JS_FALSE; + + if (vxml->xml_class == JSXML_CLASS_LIST) { + for (j = 0; j < n; j++) { + kid = XMLARRAY_MEMBER(&vxml->xml_kids, j, JSXML); + if (!kid) + continue; + kid->parent = xml; + XMLARRAY_SET_MEMBER(&xml->xml_kids, i + j, kid); + + /* OPTION: enforce that descendants have superset namespaces. */ + } + } else { + vxml->parent = xml; + XMLARRAY_SET_MEMBER(&xml->xml_kids, i, vxml); + } + return JS_TRUE; +} + +static JSBool +IndexToId(JSContext *cx, uint32 index, jsid *idp) +{ + JSAtom *atom; + JSString *str; + + if (index <= JSID_INT_MAX) { + *idp = INT_TO_JSID(index); + } else { + str = js_NumberToString(cx, (jsdouble) index); + if (!str) + return JS_FALSE; + atom = js_AtomizeString(cx, str, 0); + if (!atom) + return JS_FALSE; + *idp = ATOM_TO_JSID(atom); + } + return JS_TRUE; +} + +/* ECMA-357 9.1.1.12 XML [[Replace]]. */ +static JSBool +Replace(JSContext *cx, JSXML *xml, uint32 i, jsval v) +{ + uint32 n; + JSXML *vxml, *kid; + JSObject *vobj; + JSString *str; + + if (!JSXML_HAS_KIDS(xml)) + return JS_TRUE; + + /* + * 9.1.1.12 + * [[Replace]] handles _i >= x.[[Length]]_ by incrementing _x.[[Length]_. + * It should therefore constrain callers to pass in _i <= x.[[Length]]_. + */ + n = xml->xml_kids.length; + if (i > n) + i = n; + + vxml = NULL; + if (!JSVAL_IS_PRIMITIVE(v)) { + vobj = JSVAL_TO_OBJECT(v); + if (vobj->isXML()) + vxml = (JSXML *) vobj->getPrivate(); + } + + switch (vxml ? JSXMLClass(vxml->xml_class) : JSXML_CLASS_LIMIT) { + case JSXML_CLASS_ELEMENT: + /* OPTION: enforce that descendants have superset namespaces. */ + if (!CheckCycle(cx, xml, vxml)) + return JS_FALSE; + case JSXML_CLASS_COMMENT: + case JSXML_CLASS_PROCESSING_INSTRUCTION: + case JSXML_CLASS_TEXT: + goto do_replace; + + case JSXML_CLASS_LIST: + if (i < n) + DeleteByIndex(cx, xml, i); + if (!Insert(cx, xml, i, v)) + return JS_FALSE; + break; + + default: + str = js_ValueToString(cx, Valueify(v)); + if (!str) + return JS_FALSE; + + vxml = js_NewXML(cx, JSXML_CLASS_TEXT); + if (!vxml) + return JS_FALSE; + vxml->xml_value = str; + + do_replace: + vxml->parent = xml; + if (i < n) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid) + kid->parent = NULL; + } + if (!XMLARRAY_ADD_MEMBER(cx, &xml->xml_kids, i, vxml)) + return JS_FALSE; + break; + } + + return JS_TRUE; +} + +/* ECMA-357 9.1.1.3 XML [[Delete]], 9.2.1.3 XML [[Delete]] qname cases. */ +static void +DeleteNamedProperty(JSContext *cx, JSXML *xml, JSObject *nameqn, + JSBool attributes) +{ + JSXMLArray *array; + uint32 index, deleteCount; + JSXML *kid; + JSXMLNameMatcher matcher; + + if (xml->xml_class == JSXML_CLASS_LIST) { + array = &xml->xml_kids; + for (index = 0; index < array->length; index++) { + kid = XMLARRAY_MEMBER(array, index, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) + DeleteNamedProperty(cx, kid, nameqn, attributes); + } + } else if (xml->xml_class == JSXML_CLASS_ELEMENT) { + if (attributes) { + array = &xml->xml_attrs; + matcher = MatchAttrName; + } else { + array = &xml->xml_kids; + matcher = MatchElemName; + } + deleteCount = 0; + for (index = 0; index < array->length; index++) { + kid = XMLARRAY_MEMBER(array, index, JSXML); + if (kid && matcher(nameqn, kid)) { + kid->parent = NULL; + XMLArrayDelete(cx, array, index, JS_FALSE); + ++deleteCount; + } else if (deleteCount != 0) { + XMLARRAY_SET_MEMBER(array, + index - deleteCount, + array->vector[index]); + } + } + array->length -= deleteCount; + } +} + +/* ECMA-357 9.2.1.3 index case. */ +static void +DeleteListElement(JSContext *cx, JSXML *xml, uint32 index) +{ + JSXML *kid, *parent; + uint32 kidIndex; + + JS_ASSERT(xml->xml_class == JSXML_CLASS_LIST); + + if (index < xml->xml_kids.length) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); + if (kid) { + parent = kid->parent; + if (parent) { + JS_ASSERT(parent != xml); + JS_ASSERT(JSXML_HAS_KIDS(parent)); + + if (kid->xml_class == JSXML_CLASS_ATTRIBUTE) { + DeleteNamedProperty(cx, parent, kid->name, JS_TRUE); + } else { + kidIndex = XMLARRAY_FIND_MEMBER(&parent->xml_kids, kid, + NULL); + JS_ASSERT(kidIndex != XML_NOT_FOUND); + DeleteByIndex(cx, parent, kidIndex); + } + } + XMLArrayDelete(cx, &xml->xml_kids, index, JS_TRUE); + } + } +} + +static JSBool +SyncInScopeNamespaces(JSContext *cx, JSXML *xml) +{ + JSXMLArray *nsarray; + uint32 i, n; + JSObject *ns; + + nsarray = &xml->xml_namespaces; + while ((xml = xml->parent) != NULL) { + for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { + ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + if (ns && !XMLARRAY_HAS_MEMBER(nsarray, ns, namespace_identity)) { + if (!XMLARRAY_APPEND(cx, nsarray, ns)) + return JS_FALSE; + } + } + } + return JS_TRUE; +} + +static JSBool +GetNamedProperty(JSContext *cx, JSXML *xml, JSObject* nameqn, JSXML *list) +{ + JSXMLArray *array; + JSXMLNameMatcher matcher; + JSBool attrs; + + if (xml->xml_class == JSXML_CLASS_LIST) { + JSXMLArrayCursor cursor(&xml->xml_kids); + while (JSXML *kid = (JSXML *) cursor.getNext()) { + if (kid->xml_class == JSXML_CLASS_ELEMENT && + !GetNamedProperty(cx, kid, nameqn, list)) { + return JS_FALSE; + } + } + } else if (xml->xml_class == JSXML_CLASS_ELEMENT) { + attrs = (nameqn->getClass() == &js_AttributeNameClass); + if (attrs) { + array = &xml->xml_attrs; + matcher = MatchAttrName; + } else { + array = &xml->xml_kids; + matcher = MatchElemName; + } + + JSXMLArrayCursor cursor(array); + while (JSXML *kid = (JSXML *) cursor.getNext()) { + if (matcher(nameqn, kid)) { + if (!attrs && + kid->xml_class == JSXML_CLASS_ELEMENT && + !SyncInScopeNamespaces(cx, kid)) { + return JS_FALSE; + } + if (!Append(cx, list, kid)) + return JS_FALSE; + } + } + } + + return JS_TRUE; +} + +/* ECMA-357 9.1.1.1 XML [[Get]] and 9.2.1.1 XMLList [[Get]]. */ +static JSBool +GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + JSXML *xml, *list, *kid; + uint32 index; + JSObject *kidobj, *listobj; + JSObject *nameqn; + jsid funid; + + xml = (JSXML *) GetInstancePrivate(cx, obj, &js_XMLClass, NULL); + if (!xml) + return true; + + if (js_IdIsIndex(id, &index)) { + if (!JSXML_HAS_KIDS(xml)) { + *vp = (index == 0) ? OBJECT_TO_JSVAL(obj) : JSVAL_VOID; + } else { + /* + * ECMA-357 9.2.1.1 starts here. + * + * Erratum: 9.2 is not completely clear that indexed properties + * correspond to kids, but that's what it seems to say, and it's + * what any sane user would want. + */ + if (index < xml->xml_kids.length) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); + if (!kid) { + *vp = JSVAL_VOID; + return true; + } + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + return false; + + *vp = OBJECT_TO_JSVAL(kidobj); + } else { + *vp = JSVAL_VOID; + } + } + return true; + } + + /* + * ECMA-357 9.2.1.1/9.1.1.1 qname case. + */ + nameqn = ToXMLName(cx, IdToJsval(id), &funid); + if (!nameqn) + return false; + if (!JSID_IS_VOID(funid)) + return GetXMLFunction(cx, obj, funid, vp); + + jsval roots[2] = { OBJECT_TO_JSVAL(nameqn), JSVAL_NULL }; + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), Valueify(roots)); + + listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!listobj) + return false; + + roots[1] = OBJECT_TO_JSVAL(listobj); + + list = (JSXML *) listobj->getPrivate(); + if (!GetNamedProperty(cx, xml, nameqn, list)) + return false; + + /* + * Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the + * given list's [[TargetProperty]] to the property that is being + * appended. This means that any use of the internal [[Get]] + * property returns a list which, when used by e.g. [[Insert]] + * duplicates the last element matched by id. See bug 336921. + */ + list->xml_target = xml; + list->xml_targetprop = nameqn; + *vp = OBJECT_TO_JSVAL(listobj); + return true; +} + +static JSXML * +CopyOnWrite(JSContext *cx, JSXML *xml, JSObject *obj) +{ + JS_ASSERT(xml->object != obj); + + xml = DeepCopy(cx, xml, obj, 0); + if (!xml) + return NULL; + + JS_ASSERT(xml->object == obj); + return xml; +} + +#define CHECK_COPY_ON_WRITE(cx,xml,obj) \ + (xml->object == obj ? xml : CopyOnWrite(cx, xml, obj)) + +static JSString * +KidToString(JSContext *cx, JSXML *xml, uint32 index) +{ + JSXML *kid; + JSObject *kidobj; + + kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); + if (!kid) + return cx->runtime->emptyString; + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + return NULL; + return js_ValueToString(cx, ObjectValue(*kidobj)); +} + +/* Forward declared -- its implementation uses other statics that call it. */ +static JSBool +ResolveValue(JSContext *cx, JSXML *list, JSXML **result); + +/* ECMA-357 9.1.1.2 XML [[Put]] and 9.2.1.2 XMLList [[Put]]. */ +static JSBool +PutProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) +{ + JSBool ok, primitiveAssign; + enum { OBJ_ROOT, ID_ROOT, VAL_ROOT }; + JSXML *xml, *vxml, *rxml, *kid, *attr, *parent, *copy, *kid2, *match; + JSObject *vobj, *nameobj, *attrobj, *parentobj, *kidobj, *copyobj; + JSObject *targetprop, *nameqn, *attrqn; + uint32 index, i, j, k, n, q, matchIndex; + jsval attrval, nsval; + jsid funid; + JSObject *ns; + + xml = (JSXML *) GetInstancePrivate(cx, obj, &js_XMLClass, NULL); + if (!xml) + return JS_TRUE; + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + + /* Precompute vxml for 9.2.1.2 2(c)(vii)(2-3) and 2(d) and 9.1.1.2 1. */ + vxml = NULL; + if (!JSVAL_IS_PRIMITIVE(*vp)) { + vobj = JSVAL_TO_OBJECT(*vp); + if (vobj->isXML()) + vxml = (JSXML *) vobj->getPrivate(); + } + + ok = js_EnterLocalRootScope(cx); + if (!ok) + return JS_FALSE; + + MUST_FLOW_THROUGH("out"); + jsval roots[3]; + roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj); + roots[ID_ROOT] = IdToJsval(id); + roots[VAL_ROOT] = *vp; + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), Valueify(roots)); + + if (js_IdIsIndex(id, &index)) { + if (xml->xml_class != JSXML_CLASS_LIST) { + /* See NOTE in spec: this variation is reserved for future use. */ + ReportBadXMLName(cx, IdToValue(id)); + goto bad; + } + + /* + * Step 1 of ECMA-357 9.2.1.2 index case sets i to the property index. + */ + i = index; + + /* 2(a-b). */ + if (xml->xml_target) { + ok = ResolveValue(cx, xml->xml_target, &rxml); + if (!ok) + goto out; + if (!rxml) + goto out; + JS_ASSERT(rxml->object); + } else { + rxml = NULL; + } + + /* 2(c). */ + if (index >= xml->xml_kids.length) { + /* 2(c)(i). */ + if (rxml) { + if (rxml->xml_class == JSXML_CLASS_LIST) { + if (rxml->xml_kids.length != 1) + goto out; + rxml = XMLARRAY_MEMBER(&rxml->xml_kids, 0, JSXML); + if (!rxml) + goto out; + ok = js_GetXMLObject(cx, rxml) != NULL; + if (!ok) + goto out; + } + + /* + * Erratum: ECMA-357 9.2.1.2 step 2(c)(ii) sets + * _y.[[Parent]] = r_ where _r_ is the result of + * [[ResolveValue]] called on _x.[[TargetObject]] in + * 2(a)(i). This can result in text parenting text: + * + * var MYXML = new XML(); + * MYXML.appendChild(new XML("Giants")); + * + * (testcase from Werner Sharp ). + * + * To match insertChildAfter, insertChildBefore, + * prependChild, and setChildren, we should silently + * do nothing in this case. + */ + if (!JSXML_HAS_KIDS(rxml)) + goto out; + } + + /* 2(c)(ii) is distributed below as several js_NewXML calls. */ + targetprop = xml->xml_targetprop; + if (!targetprop || IS_STAR(targetprop->getQNameLocalName())) { + /* 2(c)(iv)(1-2), out of order w.r.t. 2(c)(iii). */ + kid = js_NewXML(cx, JSXML_CLASS_TEXT); + if (!kid) + goto bad; + } else { + nameobj = targetprop; + if (nameobj->getClass() == &js_AttributeNameClass) { + /* + * 2(c)(iii)(1-3). + * Note that rxml can't be null here, because target + * and targetprop are non-null. + */ + ok = GetProperty(cx, rxml->object, id, &attrval); + if (!ok) + goto out; + if (JSVAL_IS_PRIMITIVE(attrval)) /* no such attribute */ + goto out; + attrobj = JSVAL_TO_OBJECT(attrval); + attr = (JSXML *) attrobj->getPrivate(); + if (JSXML_LENGTH(attr) != 0) + goto out; + + kid = js_NewXML(cx, JSXML_CLASS_ATTRIBUTE); + } else { + /* 2(c)(v). */ + kid = js_NewXML(cx, JSXML_CLASS_ELEMENT); + } + if (!kid) + goto bad; + + /* An important bit of 2(c)(ii). */ + kid->name = targetprop; + } + + /* Final important bit of 2(c)(ii). */ + kid->parent = rxml; + + /* 2(c)(vi-vii). */ + i = xml->xml_kids.length; + if (kid->xml_class != JSXML_CLASS_ATTRIBUTE) { + /* + * 2(c)(vii)(1) tests whether _y.[[Parent]]_ is not null. + * y.[[Parent]] is here called kid->parent, which we know + * from 2(c)(ii) is _r_, here called rxml. So let's just + * test that! Erratum, the spec should be simpler here. + */ + if (rxml) { + JS_ASSERT(JSXML_HAS_KIDS(rxml)); + n = rxml->xml_kids.length; + j = n - 1; + if (n != 0 && i != 0) { + for (n = j, j = 0; j < n; j++) { + if (rxml->xml_kids.vector[j] == + xml->xml_kids.vector[i-1]) { + break; + } + } + } + + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + goto bad; + ok = Insert(cx, rxml, j + 1, OBJECT_TO_JSVAL(kidobj)); + if (!ok) + goto out; + } + + /* + * 2(c)(vii)(2-3). + * Erratum: [[PropertyName]] in 2(c)(vii)(3) must be a + * typo for [[TargetProperty]]. + */ + if (vxml) { + kid->name = (vxml->xml_class == JSXML_CLASS_LIST) + ? vxml->xml_targetprop + : vxml->name; + } + } + + /* 2(c)(viii). */ + ok = Append(cx, xml, kid); + if (!ok) + goto out; + } + + /* 2(d). */ + if (!vxml || + vxml->xml_class == JSXML_CLASS_TEXT || + vxml->xml_class == JSXML_CLASS_ATTRIBUTE) { + ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp); + if (!ok) + goto out; + roots[VAL_ROOT] = *vp; + } + + /* 2(e). */ + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (!kid) + goto out; + parent = kid->parent; + if (kid->xml_class == JSXML_CLASS_ATTRIBUTE) { + nameobj = kid->name; + if (nameobj->getClass() != &js_AttributeNameClass) { + nameobj = NewXMLAttributeName(cx, nameobj->getNameURI(), nameobj->getNamePrefix(), + nameobj->getQNameLocalName()); + if (!nameobj) + goto bad; + } + id = OBJECT_TO_JSID(nameobj); + + if (parent) { + /* 2(e)(i). */ + parentobj = js_GetXMLObject(cx, parent); + if (!parentobj) + goto bad; + ok = PutProperty(cx, parentobj, id, strict, vp); + if (!ok) + goto out; + + /* 2(e)(ii). */ + ok = GetProperty(cx, parentobj, id, vp); + if (!ok) + goto out; + attr = (JSXML *) JSVAL_TO_OBJECT(*vp)->getPrivate(); + + /* 2(e)(iii) - the length check comes from the bug 375406. */ + if (attr->xml_kids.length != 0) + xml->xml_kids.vector[i] = attr->xml_kids.vector[0]; + } + } + + /* 2(f). */ + else if (vxml && vxml->xml_class == JSXML_CLASS_LIST) { + /* + * 2(f)(i) + * + * Erratum: the spec says to create a shallow copy _c_ of _V_, but + * if we do that we never change the parent of each child in the + * list. Since [[Put]] when called on an XML object deeply copies + * the provided list _V_, we also do so here. Perhaps the shallow + * copy was a misguided optimization? + */ + copy = DeepCopyInLRS(cx, vxml, 0); + if (!copy) + goto bad; + copyobj = js_GetXMLObject(cx, copy); + if (!copyobj) + goto bad; + + JS_ASSERT(parent != xml); + if (parent) { + q = XMLARRAY_FIND_MEMBER(&parent->xml_kids, kid, NULL); + JS_ASSERT(q != XML_NOT_FOUND); + ok = Replace(cx, parent, q, OBJECT_TO_JSVAL(copyobj)); + if (!ok) + goto out; + +#ifdef DEBUG + /* Erratum: this loop in the spec is useless. */ + for (j = 0, n = copy->xml_kids.length; j < n; j++) { + kid2 = XMLARRAY_MEMBER(&parent->xml_kids, q + j, JSXML); + JS_ASSERT(XMLARRAY_MEMBER(©->xml_kids, j, JSXML) + == kid2); + } +#endif + } + + /* + * 2(f)(iv-vi). + * Erratum: notice the unhandled zero-length V basis case and + * the off-by-one errors for the n != 0 cases in the spec. + */ + n = copy->xml_kids.length; + if (n == 0) { + XMLArrayDelete(cx, &xml->xml_kids, i, JS_TRUE); + } else { + ok = XMLArrayInsert(cx, &xml->xml_kids, i + 1, n - 1); + if (!ok) + goto out; + + for (j = 0; j < n; j++) + xml->xml_kids.vector[i + j] = copy->xml_kids.vector[j]; + } + } + + /* 2(g). */ + else if (vxml || JSXML_HAS_VALUE(kid)) { + if (parent) { + q = XMLARRAY_FIND_MEMBER(&parent->xml_kids, kid, NULL); + JS_ASSERT(q != XML_NOT_FOUND); + ok = Replace(cx, parent, q, *vp); + if (!ok) + goto out; + + vxml = XMLARRAY_MEMBER(&parent->xml_kids, q, JSXML); + if (!vxml) + goto out; + roots[VAL_ROOT] = *vp = OBJECT_TO_JSVAL(vxml->object); + } + + /* + * 2(g)(iii). + * Erratum: _V_ may not be of type XML, but all index-named + * properties _x[i]_ in an XMLList _x_ must be of type XML, + * according to 9.2.1.1 Overview and other places in the spec. + * + * Thanks to 2(d), we know _V_ (*vp here) is either a string + * or an XML/XMLList object. If *vp is a string, call ToXML + * on it to satisfy the constraint. + */ + if (!vxml) { + JS_ASSERT(JSVAL_IS_STRING(*vp)); + vobj = ToXML(cx, *vp); + if (!vobj) + goto bad; + roots[VAL_ROOT] = *vp = OBJECT_TO_JSVAL(vobj); + vxml = (JSXML *) vobj->getPrivate(); + } + XMLARRAY_SET_MEMBER(&xml->xml_kids, i, vxml); + } + + /* 2(h). */ + else { + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + goto bad; + id = ATOM_TO_JSID(cx->runtime->atomState.starAtom); + ok = PutProperty(cx, kidobj, id, strict, vp); + if (!ok) + goto out; + } + } else { + /* + * ECMA-357 9.2.1.2/9.1.1.2 qname case. + */ + nameqn = ToXMLName(cx, IdToJsval(id), &funid); + if (!nameqn) + goto bad; + if (!JSID_IS_VOID(funid)) { + ok = js_SetProperty(cx, obj, funid, Valueify(vp), false); + goto out; + } + nameobj = nameqn; + roots[ID_ROOT] = OBJECT_TO_JSVAL(nameobj); + + if (xml->xml_class == JSXML_CLASS_LIST) { + /* + * Step 3 of 9.2.1.2. + * Erratum: if x.[[Length]] > 1 or [[ResolveValue]] returns null + * or an r with r.[[Length]] != 1, throw TypeError. + */ + n = JSXML_LENGTH(xml); + if (n > 1) + goto type_error; + if (n == 0) { + ok = ResolveValue(cx, xml, &rxml); + if (!ok) + goto out; + if (!rxml || JSXML_LENGTH(rxml) != 1) + goto type_error; + ok = Append(cx, xml, rxml); + if (!ok) + goto out; + } + JS_ASSERT(JSXML_LENGTH(xml) == 1); + xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (!xml) + goto out; + JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST); + obj = js_GetXMLObject(cx, xml); + if (!obj) + goto bad; + roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj); + + /* FALL THROUGH to non-list case */ + } + + /* + * ECMA-357 9.1.1.2. + * Erratum: move steps 3 and 4 to before 1 and 2, to avoid wasted + * effort in ToString or [[DeepCopy]]. + */ + + if (JSXML_HAS_VALUE(xml)) + goto out; + + if (!vxml || + vxml->xml_class == JSXML_CLASS_TEXT || + vxml->xml_class == JSXML_CLASS_ATTRIBUTE) { + ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp); + if (!ok) + goto out; + } else { + rxml = DeepCopyInLRS(cx, vxml, 0); + if (!rxml || !js_GetXMLObject(cx, rxml)) + goto bad; + vxml = rxml; + *vp = OBJECT_TO_JSVAL(vxml->object); + } + roots[VAL_ROOT] = *vp; + + /* + * 6. + * Erratum: why is this done here, so early? use is way later.... + */ + ok = js_GetDefaultXMLNamespace(cx, &nsval); + if (!ok) + goto out; + + if (nameobj->getClass() == &js_AttributeNameClass) { + /* 7(a). */ + if (!js_IsXMLName(cx, OBJECT_TO_JSVAL(nameobj))) + goto out; + + /* 7(b-c). */ + if (vxml && vxml->xml_class == JSXML_CLASS_LIST) { + n = vxml->xml_kids.length; + if (n == 0) { + *vp = STRING_TO_JSVAL(cx->runtime->emptyString); + } else { + JSString *left = KidToString(cx, vxml, 0); + if (!left) + goto bad; + + JSString *space = cx->runtime->atomState.spaceAtom; + for (i = 1; i < n; i++) { + left = js_ConcatStrings(cx, left, space); + if (!left) + goto bad; + JSString *right = KidToString(cx, vxml, i); + if (!right) + goto bad; + left = js_ConcatStrings(cx, left, right); + if (!left) + goto bad; + } + + roots[VAL_ROOT] = *vp = STRING_TO_JSVAL(left); + } + } else { + ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp); + if (!ok) + goto out; + roots[VAL_ROOT] = *vp; + } + + /* 7(d-e). */ + match = NULL; + for (i = 0, n = xml->xml_attrs.length; i < n; i++) { + attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML); + if (!attr) + continue; + attrqn = attr->name; + if (EqualStrings(attrqn->getQNameLocalName(), nameqn->getQNameLocalName())) { + JSLinearString *uri = nameqn->getNameURI(); + if (!uri || EqualStrings(attrqn->getNameURI(), uri)) { + if (!match) { + match = attr; + } else { + DeleteNamedProperty(cx, xml, attrqn, JS_TRUE); + --i; + } + } + } + } + + /* 7(f). */ + attr = match; + if (!attr) { + /* 7(f)(i-ii). */ + JSLinearString *uri = nameqn->getNameURI(); + JSLinearString *left, *right; + if (!uri) { + left = right = cx->runtime->emptyString; + } else { + left = uri; + right = nameqn->getNamePrefix(); + } + nameqn = NewXMLQName(cx, left, right, nameqn->getQNameLocalName()); + if (!nameqn) + goto bad; + + /* 7(f)(iii). */ + attr = js_NewXML(cx, JSXML_CLASS_ATTRIBUTE); + if (!attr) + goto bad; + attr->parent = xml; + attr->name = nameqn; + + /* 7(f)(iv). */ + ok = XMLARRAY_ADD_MEMBER(cx, &xml->xml_attrs, n, attr); + if (!ok) + goto out; + + /* 7(f)(v-vi). */ + ns = GetNamespace(cx, nameqn, NULL); + if (!ns) + goto bad; + ok = AddInScopeNamespace(cx, xml, ns); + if (!ok) + goto out; + } + + /* 7(g). */ + attr->xml_value = JSVAL_TO_STRING(*vp); + goto out; + } + + /* 8-9. */ + if (!js_IsXMLName(cx, OBJECT_TO_JSVAL(nameobj)) && + !IS_STAR(nameqn->getQNameLocalName())) { + goto out; + } + + /* 10-11. */ + id = JSID_VOID; + primitiveAssign = !vxml && !IS_STAR(nameqn->getQNameLocalName()); + + /* 12. */ + k = n = xml->xml_kids.length; + matchIndex = XML_NOT_FOUND; + kid2 = NULL; + while (k != 0) { + --k; + kid = XMLARRAY_MEMBER(&xml->xml_kids, k, JSXML); + if (kid && MatchElemName(nameqn, kid)) { + if (matchIndex != XML_NOT_FOUND) + DeleteByIndex(cx, xml, matchIndex); + matchIndex = k; + kid2 = kid; + } + } + + /* + * Erratum: ECMA-357 specified child insertion inconsistently: + * insertChildBefore and insertChildAfter insert an arbitrary XML + * instance, and therefore can create cycles, but appendChild as + * specified by the "Overview" of 13.4.4.3 calls [[DeepCopy]] on + * its argument. But the "Semantics" in 13.4.4.3 do not include + * any [[DeepCopy]] call. + * + * Fixing this (https://bugzilla.mozilla.org/show_bug.cgi?id=312692) + * required adding cycle detection, and allowing duplicate kids to + * be created (see comment 6 in the bug). Allowing duplicate kid + * references means the loop above will delete all but the lowest + * indexed reference, and each [[DeleteByIndex]] nulls the kid's + * parent. Thus the need to restore parent here. This is covered + * by https://bugzilla.mozilla.org/show_bug.cgi?id=327564. + */ + if (kid2) { + JS_ASSERT(kid2->parent == xml || !kid2->parent); + if (!kid2->parent) + kid2->parent = xml; + } + + /* 13. */ + if (matchIndex == XML_NOT_FOUND) { + /* 13(a). */ + matchIndex = n; + + /* 13(b). */ + if (primitiveAssign) { + JSLinearString *uri = nameqn->getNameURI(); + JSLinearString *left, *right; + if (!uri) { + ns = JSVAL_TO_OBJECT(nsval); + left = ns->getNameURI(); + right = ns->getNamePrefix(); + } else { + left = uri; + right = nameqn->getNamePrefix(); + } + nameqn = NewXMLQName(cx, left, right, nameqn->getQNameLocalName()); + if (!nameqn) + goto bad; + + /* 13(b)(iii). */ + vobj = js_NewXMLObject(cx, JSXML_CLASS_ELEMENT); + if (!vobj) + goto bad; + vxml = (JSXML *) vobj->getPrivate(); + vxml->parent = xml; + vxml->name = nameqn; + + /* 13(b)(iv-vi). */ + ns = GetNamespace(cx, nameqn, NULL); + if (!ns) + goto bad; + ok = Replace(cx, xml, matchIndex, OBJECT_TO_JSVAL(vobj)); + if (!ok) + goto out; + ok = AddInScopeNamespace(cx, vxml, ns); + if (!ok) + goto out; + } + } + + /* 14. */ + if (primitiveAssign) { + JSXMLArrayCursor cursor(&xml->xml_kids); + cursor.index = matchIndex; + kid = (JSXML *) cursor.getCurrent(); + if (JSXML_HAS_KIDS(kid)) { + kid->xml_kids.finish(cx); + kid->xml_kids.init(); + ok = kid->xml_kids.setCapacity(cx, 1); + } + + /* 14(b-c). */ + /* XXXbe Erratum? redundant w.r.t. 7(b-c) else clause above */ + if (ok) { + ok = JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp); + if (ok && !JSVAL_TO_STRING(*vp)->empty()) { + roots[VAL_ROOT] = *vp; + if ((JSXML *) cursor.getCurrent() == kid) + ok = Replace(cx, kid, 0, *vp); + } + } + } else { + /* 15(a). */ + ok = Replace(cx, xml, matchIndex, *vp); + } + } + +out: + js_LeaveLocalRootScope(cx); + return ok; + +type_error: + { + JSAutoByteString bytes; + if (js_ValueToPrintable(cx, IdToValue(id), &bytes)) + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_XMLLIST_PUT, bytes.ptr()); + } +bad: + ok = JS_FALSE; + goto out; +} + +/* ECMA-357 9.1.1.10 XML [[ResolveValue]], 9.2.1.10 XMLList [[ResolveValue]]. */ +static JSBool +ResolveValue(JSContext *cx, JSXML *list, JSXML **result) +{ + JSXML *target, *base; + JSObject *targetprop; + jsid id; + jsval tv; + + if (list->xml_class != JSXML_CLASS_LIST || list->xml_kids.length != 0) { + if (!js_GetXMLObject(cx, list)) + return JS_FALSE; + *result = list; + return JS_TRUE; + } + + target = list->xml_target; + targetprop = list->xml_targetprop; + if (!target || !targetprop || IS_STAR(targetprop->getQNameLocalName())) { + *result = NULL; + return JS_TRUE; + } + + if (targetprop->getClass() == &js_AttributeNameClass) { + *result = NULL; + return JS_TRUE; + } + + if (!ResolveValue(cx, target, &base)) + return JS_FALSE; + if (!base) { + *result = NULL; + return JS_TRUE; + } + if (!js_GetXMLObject(cx, base)) + return JS_FALSE; + + id = OBJECT_TO_JSID(targetprop); + if (!GetProperty(cx, base->object, id, &tv)) + return JS_FALSE; + target = (JSXML *) JSVAL_TO_OBJECT(tv)->getPrivate(); + + if (JSXML_LENGTH(target) == 0) { + if (base->xml_class == JSXML_CLASS_LIST && JSXML_LENGTH(base) > 1) { + *result = NULL; + return JS_TRUE; + } + tv = STRING_TO_JSVAL(cx->runtime->emptyString); + if (!PutProperty(cx, base->object, id, false, &tv)) + return JS_FALSE; + if (!GetProperty(cx, base->object, id, &tv)) + return JS_FALSE; + target = (JSXML *) JSVAL_TO_OBJECT(tv)->getPrivate(); + } + + *result = target; + return JS_TRUE; +} + +static JSBool +HasNamedProperty(JSXML *xml, JSObject *nameqn) +{ + JSBool found; + JSXMLArray *array; + JSXMLNameMatcher matcher; + uint32 i, n; + + if (xml->xml_class == JSXML_CLASS_LIST) { + found = JS_FALSE; + JSXMLArrayCursor cursor(&xml->xml_kids); + while (JSXML *kid = (JSXML *) cursor.getNext()) { + found = HasNamedProperty(kid, nameqn); + if (found) + break; + } + return found; + } + + if (xml->xml_class == JSXML_CLASS_ELEMENT) { + if (nameqn->getClass() == &js_AttributeNameClass) { + array = &xml->xml_attrs; + matcher = MatchAttrName; + } else { + array = &xml->xml_kids; + matcher = MatchElemName; + } + for (i = 0, n = array->length; i < n; i++) { + JSXML *kid = XMLARRAY_MEMBER(array, i, JSXML); + if (kid && matcher(nameqn, kid)) + return JS_TRUE; + } + } + + return JS_FALSE; +} + +static JSBool +HasIndexedProperty(JSXML *xml, uint32 i) +{ + if (xml->xml_class == JSXML_CLASS_LIST) + return i < JSXML_LENGTH(xml); + + if (xml->xml_class == JSXML_CLASS_ELEMENT) + return i == 0; + + return JS_FALSE; +} + +static JSBool +HasSimpleContent(JSXML *xml); + +static JSBool +HasFunctionProperty(JSContext *cx, JSObject *obj, jsid funid, JSBool *found) +{ + JSObject *pobj; + JSProperty *prop; + JSXML *xml; + + JS_ASSERT(obj->getClass() == &js_XMLClass); + + if (!js_LookupProperty(cx, obj, funid, &pobj, &prop)) + return false; + if (!prop) { + xml = (JSXML *) obj->getPrivate(); + if (HasSimpleContent(xml)) { + AutoObjectRooter tvr(cx); + + /* + * Search in String.prototype to set found whenever + * GetXMLFunction returns existing function. + */ + if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr())) + return false; + + JS_ASSERT(tvr.object()); + if (!js_LookupProperty(cx, tvr.object(), funid, &pobj, &prop)) + return false; + } + } + *found = (prop != NULL); + return true; +} + +/* ECMA-357 9.1.1.6 XML [[HasProperty]] and 9.2.1.5 XMLList [[HasProperty]]. */ +static JSBool +HasProperty(JSContext *cx, JSObject *obj, jsval id, JSBool *found) +{ + JSXML *xml; + bool isIndex; + uint32 i; + JSObject *qn; + jsid funid; + + xml = (JSXML *) obj->getPrivate(); + if (!js_IdValIsIndex(cx, id, &i, &isIndex)) + return JS_FALSE; + + if (isIndex) { + *found = HasIndexedProperty(xml, i); + } else { + qn = ToXMLName(cx, id, &funid); + if (!qn) + return JS_FALSE; + if (!JSID_IS_VOID(funid)) { + if (!HasFunctionProperty(cx, obj, funid, found)) + return JS_FALSE; + } else { + *found = HasNamedProperty(xml, qn); + } + } + return JS_TRUE; +} + +static void +xml_finalize(JSContext *cx, JSObject *obj) +{ + JSXML *xml = (JSXML *) obj->getPrivate(); + if (!xml) + return; + if (xml->object == obj) + xml->object = NULL; +} + +static void +xml_trace_vector(JSTracer *trc, JSXML **vec, uint32 len) +{ + uint32 i; + JSXML *xml; + + for (i = 0; i < len; i++) { + xml = vec[i]; + if (xml) { + JS_SET_TRACING_INDEX(trc, "xml_vector", i); + Mark(trc, xml); + } + } +} + +/* + * XML objects are native. Thus xml_lookupProperty must return a valid + * Shape pointer parameter via *propp to signify "property found". Since the + * only call to xml_lookupProperty is via JSObject::lookupProperty, and then + * only from js_FindProperty (in jsobj.c, called from jsinterp.c) or from + * JSOP_IN case in the interpreter, the only time we add a Shape here is when + * an unqualified name is being accessed or when "name in xml" is called. + * + * This scope property keeps the JSOP_NAME code in js_Interpret happy by + * giving it an shape with (getter, setter) == (GetProperty, PutProperty). + * + * NB: xml_deleteProperty must take care to remove any property added here. + * + * FIXME This clashes with the function namespace implementation which also + * uses native properties. Effectively after xml_lookupProperty any property + * stored previously using assignments to xml.function::name will be removed. + * We partially workaround the problem in GetXMLFunction. There we take + * advantage of the fact that typically function:: is used to access the + * functions from XML.prototype. So when js_GetProperty returns a non-function + * property, we assume that it represents the result of GetProperty setter + * hiding the function and use an extra prototype chain lookup to recover it. + * For a proper solution see bug 355257. +*/ +static JSBool +xml_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, + JSProperty **propp) +{ + JSBool found; + JSXML *xml; + uint32 i; + JSObject *qn; + jsid funid; + + xml = (JSXML *) obj->getPrivate(); + if (js_IdIsIndex(id, &i)) { + found = HasIndexedProperty(xml, i); + } else { + qn = ToXMLName(cx, IdToJsval(id), &funid); + if (!qn) + return JS_FALSE; + if (!JSID_IS_VOID(funid)) + return js_LookupProperty(cx, obj, funid, objp, propp); + found = HasNamedProperty(xml, qn); + } + if (!found) { + *objp = NULL; + *propp = NULL; + } else { + const Shape *shape = + js_AddNativeProperty(cx, obj, id, + Valueify(GetProperty), Valueify(PutProperty), + SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, + 0, 0); + if (!shape) + return JS_FALSE; + + *objp = obj; + *propp = (JSProperty *) shape; + } + return JS_TRUE; +} + +static JSBool +xml_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v, + PropertyOp getter, StrictPropertyOp setter, uintN attrs) +{ + if (IsFunctionObject(*v) || getter || setter || + (attrs & JSPROP_ENUMERATE) == 0 || + (attrs & (JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED))) { + return js_DefineProperty(cx, obj, id, v, getter, setter, attrs); + } + + jsval tmp = Jsvalify(*v); + return PutProperty(cx, obj, id, false, &tmp); +} + +static JSBool +xml_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp) +{ + if (JSID_IS_DEFAULT_XML_NAMESPACE(id)) { + vp->setUndefined(); + return JS_TRUE; + } + + return GetProperty(cx, obj, id, Jsvalify(vp)); +} + +static JSBool +xml_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict) +{ + return PutProperty(cx, obj, id, strict, Jsvalify(vp)); +} + +static JSBool +xml_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +{ + JSBool found; + if (!HasProperty(cx, obj, IdToJsval(id), &found)) + return false; + + *attrsp = found ? JSPROP_ENUMERATE : 0; + return JS_TRUE; +} + +static JSBool +xml_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) +{ + JSBool found; + if (!HasProperty(cx, obj, IdToJsval(id), &found)) + return false; + + if (found) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_SET_XML_ATTRS); + return false; + } + return true; +} + +static JSBool +xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict) +{ + JSXML *xml; + jsval idval; + uint32 index; + JSObject *nameqn; + jsid funid; + + idval = IdToJsval(id); + xml = (JSXML *) obj->getPrivate(); + if (js_IdIsIndex(id, &index)) { + if (xml->xml_class != JSXML_CLASS_LIST) { + /* See NOTE in spec: this variation is reserved for future use. */ + ReportBadXMLName(cx, IdToValue(id)); + return false; + } + + /* ECMA-357 9.2.1.3. */ + DeleteListElement(cx, xml, index); + } else { + nameqn = ToXMLName(cx, idval, &funid); + if (!nameqn) + return false; + if (!JSID_IS_VOID(funid)) + return js_DeleteProperty(cx, obj, funid, rval, false); + + DeleteNamedProperty(cx, xml, nameqn, + nameqn->getClass() == &js_AttributeNameClass); + } + + /* + * If this object has its own (mutable) scope, then we may have added a + * property to the scope in xml_lookupProperty for it to return to mean + * "found" and to provide a handle for access operations to call the + * property's getter or setter. But now it's time to remove any such + * property, to purge the property cache and remove the scope entry. + */ + if (!obj->nativeEmpty() && !js_DeleteProperty(cx, obj, id, rval, false)) + return false; + + rval->setBoolean(true); + return true; +} + +JSBool +xml_convert(JSContext *cx, JSObject *obj, JSType type, Value *rval) +{ + return js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0, NULL, rval); +} + +static JSBool +xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, Value *statep, jsid *idp) +{ + JSXML *xml; + uint32 length, index; + JSXMLArrayCursor *cursor; + + xml = (JSXML *)obj->getPrivate(); + length = JSXML_LENGTH(xml); + + switch (enum_op) { + case JSENUMERATE_INIT: + case JSENUMERATE_INIT_ALL: + if (length == 0) { + statep->setInt32(0); + } else { + cursor = cx->create(&xml->xml_kids); + if (!cursor) + return JS_FALSE; + statep->setPrivate(cursor); + } + if (idp) + *idp = INT_TO_JSID(length); + break; + + case JSENUMERATE_NEXT: + if (statep->isInt32(0)) { + statep->setNull(); + break; + } + cursor = (JSXMLArrayCursor *) statep->toPrivate(); + if (cursor && cursor->array && (index = cursor->index) < length) { + *idp = INT_TO_JSID(index); + cursor->index = index + 1; + break; + } + /* FALL THROUGH */ + + case JSENUMERATE_DESTROY: + if (!statep->isInt32(0)) { + cursor = (JSXMLArrayCursor *) statep->toPrivate(); + if (cursor) + cx->destroy(cursor); + } + statep->setNull(); + break; + } + return JS_TRUE; +} + +static JSType +xml_typeOf(JSContext *cx, JSObject *obj) +{ + return JSTYPE_XML; +} + +static JSBool +xml_hasInstance(JSContext *cx, JSObject *obj, const Value *, JSBool *bp) +{ + return JS_TRUE; +} + +static void +xml_trace(JSTracer *trc, JSObject *obj) +{ + JSXML *xml = (JSXML *) obj->getPrivate(); + if (xml) + JS_CALL_TRACER(trc, xml, JSTRACE_XML, "private"); +} + +static JSBool +xml_fix(JSContext *cx, JSObject *obj, bool *success, AutoIdVector *props) +{ + JS_ASSERT(obj->isExtensible()); + *success = false; + return true; +} + +static void +xml_clear(JSContext *cx, JSObject *obj) +{ +} + +static JSBool +HasSimpleContent(JSXML *xml) +{ + JSXML *kid; + JSBool simple; + uint32 i, n; + +again: + switch (xml->xml_class) { + case JSXML_CLASS_COMMENT: + case JSXML_CLASS_PROCESSING_INSTRUCTION: + return JS_FALSE; + case JSXML_CLASS_LIST: + if (xml->xml_kids.length == 0) + return JS_TRUE; + if (xml->xml_kids.length == 1) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (kid) { + xml = kid; + goto again; + } + } + /* FALL THROUGH */ + default: + simple = JS_TRUE; + for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { + simple = JS_FALSE; + break; + } + } + return simple; + } +} + +/* + * 11.2.2.1 Step 3(d) onward. + */ +JSBool +js_GetXMLMethod(JSContext *cx, JSObject *obj, jsid id, Value *vp) +{ + JS_ASSERT(JS_InstanceOf(cx, obj, Jsvalify(&js_XMLClass), NULL)); + + if (JSID_IS_OBJECT(id)) { + jsid funid; + + if (!js_IsFunctionQName(cx, JSID_TO_OBJECT(id), &funid)) + return JS_FALSE; + if (!JSID_IS_VOID(funid)) + id = funid; + } + + /* + * As our callers have a bad habit of passing a pointer to an unrooted + * local value as vp, we use a proper root here. + */ + AutoValueRooter tvr(cx); + JSBool ok = GetXMLFunction(cx, obj, id, Jsvalify(tvr.addr())); + *vp = tvr.value(); + return ok; +} + +JSBool +js_TestXMLEquality(JSContext *cx, const Value &v1, const Value &v2, JSBool *bp) +{ + JSXML *xml, *vxml; + JSObject *vobj; + JSBool ok; + JSString *str, *vstr; + jsdouble d, d2; + + JSObject *obj; + jsval v; + if (v1.isObject() && v1.toObject().isXML()) { + obj = &v1.toObject(); + v = Jsvalify(v2); + } else { + v = Jsvalify(v1); + obj = &v2.toObject(); + } + + JS_ASSERT(JS_InstanceOf(cx, obj, Jsvalify(&js_XMLClass), NULL)); + + xml = (JSXML *) obj->getPrivate(); + vxml = NULL; + if (!JSVAL_IS_PRIMITIVE(v)) { + vobj = JSVAL_TO_OBJECT(v); + if (vobj->isXML()) + vxml = (JSXML *) vobj->getPrivate(); + } + + if (xml->xml_class == JSXML_CLASS_LIST) { + ok = Equals(cx, xml, v, bp); + } else if (vxml) { + if (vxml->xml_class == JSXML_CLASS_LIST) { + ok = Equals(cx, vxml, OBJECT_TO_JSVAL(obj), bp); + } else { + if (((xml->xml_class == JSXML_CLASS_TEXT || + xml->xml_class == JSXML_CLASS_ATTRIBUTE) && + HasSimpleContent(vxml)) || + ((vxml->xml_class == JSXML_CLASS_TEXT || + vxml->xml_class == JSXML_CLASS_ATTRIBUTE) && + HasSimpleContent(xml))) { + ok = js_EnterLocalRootScope(cx); + if (ok) { + ok = (str = js_ValueToString(cx, ObjectValue(*obj))) && + (vstr = js_ValueToString(cx, Valueify(v))); + if (ok) + ok = EqualStrings(cx, str, vstr, bp); + js_LeaveLocalRootScope(cx); + } + } else { + ok = XMLEquals(cx, xml, vxml, bp); + } + } + } else { + ok = js_EnterLocalRootScope(cx); + if (ok) { + if (HasSimpleContent(xml)) { + ok = (str = js_ValueToString(cx, ObjectValue(*obj))) && + (vstr = js_ValueToString(cx, Valueify(v))); + if (ok) + ok = EqualStrings(cx, str, vstr, bp); + } else if (JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v)) { + str = js_ValueToString(cx, ObjectValue(*obj)); + if (!str) { + ok = JS_FALSE; + } else if (JSVAL_IS_STRING(v)) { + ok = EqualStrings(cx, str, JSVAL_TO_STRING(v), bp); + } else { + ok = JS_ValueToNumber(cx, STRING_TO_JSVAL(str), &d); + if (ok) { + d2 = JSVAL_IS_INT(v) ? JSVAL_TO_INT(v) + : JSVAL_TO_DOUBLE(v); + *bp = JSDOUBLE_COMPARE(d, ==, d2, JS_FALSE); + } + } + } else { + *bp = JS_FALSE; + } + js_LeaveLocalRootScope(cx); + } + } + return ok; +} + +JSBool +js_ConcatenateXML(JSContext *cx, JSObject *obj, JSObject *robj, Value *vp) +{ + JSBool ok; + JSObject *listobj; + JSXML *list, *lxml, *rxml; + + JS_ASSERT(JS_InstanceOf(cx, obj, Jsvalify(&js_XMLClass), NULL)); + ok = js_EnterLocalRootScope(cx); + if (!ok) + return JS_FALSE; + + listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!listobj) { + ok = JS_FALSE; + goto out; + } + + list = (JSXML *) listobj->getPrivate(); + lxml = (JSXML *) obj->getPrivate(); + ok = Append(cx, list, lxml); + if (!ok) + goto out; + + JS_ASSERT(robj->isXML()); + rxml = (JSXML *) robj->getPrivate(); + ok = Append(cx, list, rxml); + if (!ok) + goto out; + + vp->setObject(*listobj); +out: + js_LeaveLocalRootScopeWithResult(cx, *vp); + return ok; +} + +JS_FRIEND_DATA(Class) js_XMLClass = { + js_XML_str, + JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE | + JSCLASS_HAS_CACHED_PROTO(JSProto_XML), + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + xml_convert, + xml_finalize, + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + xml_hasInstance, + JS_CLASS_TRACE(xml_trace), + JS_NULL_CLASS_EXT, + { + xml_lookupProperty, + xml_defineProperty, + xml_getProperty, + xml_setProperty, + xml_getAttributes, + xml_setAttributes, + xml_deleteProperty, + xml_enumerate, + xml_typeOf, + NULL, /* trace */ + xml_fix, + NULL, /* thisObject */ + xml_clear + } +}; + +static JSXML * +StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp) +{ + JSXML *xml; + JSFunction *fun; + char numBuf[12]; + + JS_ASSERT(VALUE_IS_FUNCTION(cx, *vp)); + + *objp = ToObject(cx, Valueify(&vp[1])); + if (!*objp) + return NULL; + xml = (JSXML *) GetInstancePrivate(cx, *objp, &js_XMLClass, Valueify(vp + 2)); + if (!xml || xml->xml_class != JSXML_CLASS_LIST) + return xml; + + if (xml->xml_kids.length == 1) { + xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (xml) { + *objp = js_GetXMLObject(cx, xml); + if (!*objp) + return NULL; + vp[1] = OBJECT_TO_JSVAL(*objp); + return xml; + } + } + + fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(*vp)); + JS_snprintf(numBuf, sizeof numBuf, "%u", xml->xml_kids.length); + JSAutoByteString funNameBytes; + if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NON_LIST_XML_METHOD, + funName, numBuf); + } + return NULL; +} + +/* Beware: these two are not bracketed by JS_BEGIN/END_MACRO. */ +#define XML_METHOD_PROLOG \ + JSObject *obj = ToObject(cx, Valueify(&vp[1])); \ + if (!obj) \ + return JS_FALSE; \ + JSXML *xml = (JSXML *)GetInstancePrivate(cx, obj, &js_XMLClass, Valueify(vp+2)); \ + if (!xml) \ + return JS_FALSE + +#define NON_LIST_XML_METHOD_PROLOG \ + JSObject *obj; \ + JSXML *xml = StartNonListXMLMethod(cx, vp, &obj); \ + if (!xml) \ + return JS_FALSE; \ + JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST) + +static JSBool +xml_addNamespace(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *ns; + + NON_LIST_XML_METHOD_PROLOG; + if (xml->xml_class != JSXML_CLASS_ELEMENT) + goto done; + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + + if (!NamespaceHelper(cx, NULL, argc == 0 ? -1 : 1, vp + 2, vp)) + return JS_FALSE; + JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp)); + + ns = JSVAL_TO_OBJECT(*vp); + if (!AddInScopeNamespace(cx, xml, ns)) + return JS_FALSE; + ns->setNamespaceDeclared(JSVAL_TRUE); + + done: + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +static JSBool +xml_appendChild(JSContext *cx, uintN argc, jsval *vp) +{ + jsval v; + JSObject *vobj; + JSXML *vxml; + + NON_LIST_XML_METHOD_PROLOG; + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + + jsid name; + if (!js_GetAnyName(cx, &name)) + return JS_FALSE; + + if (!GetProperty(cx, obj, name, &v)) + return JS_FALSE; + + JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); + vobj = JSVAL_TO_OBJECT(v); + JS_ASSERT(vobj->isXML()); + vxml = (JSXML *) vobj->getPrivate(); + JS_ASSERT(vxml->xml_class == JSXML_CLASS_LIST); + + if (!IndexToId(cx, vxml->xml_kids.length, &name)) + return JS_FALSE; + *vp = (argc != 0) ? vp[2] : JSVAL_VOID; + + if (!PutProperty(cx, JSVAL_TO_OBJECT(v), name, false, vp)) + return JS_FALSE; + + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_attribute(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *qn; + + if (argc == 0) { + js_ReportMissingArg(cx, Valueify(*vp), 0); + return JS_FALSE; + } + + qn = ToAttributeName(cx, vp[2]); + if (!qn) + return JS_FALSE; + vp[2] = OBJECT_TO_JSVAL(qn); /* local root */ + + jsid id = OBJECT_TO_JSID(qn); + JSObject *obj = ToObject(cx, Valueify(&vp[1])); + if (!obj) + return JS_FALSE; + return GetProperty(cx, obj, id, vp); +} + +/* XML and XMLList */ +static JSBool +xml_attributes(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name = ATOM_TO_JSVAL(cx->runtime->atomState.starAtom); + JSObject *qn = ToAttributeName(cx, name); + if (!qn) + return JS_FALSE; + + AutoObjectRooter tvr(cx, qn); + jsid id = OBJECT_TO_JSID(qn); + JSObject *obj = ToObject(cx, Valueify(&vp[1])); + if (!obj) + return JS_FALSE; + return GetProperty(cx, obj, id, vp); +} + +static JSXML * +xml_list_helper(JSContext *cx, JSXML *xml, jsval *rval) +{ + JSObject *listobj; + JSXML *list; + + listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!listobj) + return NULL; + + *rval = OBJECT_TO_JSVAL(listobj); + list = (JSXML *) listobj->getPrivate(); + list->xml_target = xml; + return list; +} + +static JSBool +ValueToId(JSContext *cx, jsval v, AutoIdRooter *idr) +{ + if (JSVAL_IS_INT(v)) { + jsint i = JSVAL_TO_INT(v); + if (INT_FITS_IN_JSID(i)) + *idr->addr() = INT_TO_JSID(i); + else if (!js_ValueToStringId(cx, Valueify(v), idr->addr())) + return JS_FALSE; + } else if (JSVAL_IS_STRING(v)) { + JSAtom *atom = js_AtomizeString(cx, JSVAL_TO_STRING(v), 0); + if (!atom) + return JS_FALSE; + *idr->addr() = ATOM_TO_JSID(atom); + } else if (!JSVAL_IS_PRIMITIVE(v)) { + *idr->addr() = OBJECT_TO_JSID(JSVAL_TO_OBJECT(v)); + } else { + ReportBadXMLName(cx, Valueify(v)); + return JS_FALSE; + } + return JS_TRUE; +} + +static JSBool +xml_child_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval name, + jsval *rval) +{ + bool isIndex; + uint32 index; + JSXML *kid; + JSObject *kidobj; + + /* ECMA-357 13.4.4.6 */ + JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST); + + if (!js_IdValIsIndex(cx, name, &index, &isIndex)) + return JS_FALSE; + + if (isIndex) { + if (index >= JSXML_LENGTH(xml)) { + *rval = JSVAL_VOID; + } else { + kid = XMLARRAY_MEMBER(&xml->xml_kids, index, JSXML); + if (!kid) { + *rval = JSVAL_VOID; + } else { + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + return JS_FALSE; + *rval = OBJECT_TO_JSVAL(kidobj); + } + } + return JS_TRUE; + } + + AutoIdRooter idr(cx); + if (!ValueToId(cx, name, &idr)) + return JS_FALSE; + + return GetProperty(cx, obj, idr.id(), rval); +} + +/* XML and XMLList */ +static JSBool +xml_child(JSContext *cx, uintN argc, jsval *vp) +{ + jsval v; + JSXML *list, *vxml; + JSObject *kidobj; + + XML_METHOD_PROLOG; + jsval name = argc != 0 ? vp[2] : JSVAL_VOID; + if (xml->xml_class == JSXML_CLASS_LIST) { + /* ECMA-357 13.5.4.4 */ + list = xml_list_helper(cx, xml, vp); + if (!list) + return JS_FALSE; + + JSXMLArrayCursor cursor(&xml->xml_kids); + while (JSXML *kid = (JSXML *) cursor.getNext()) { + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + return JS_FALSE; + if (!xml_child_helper(cx, kidobj, kid, name, &v)) + return JS_FALSE; + if (JSVAL_IS_VOID(v)) { + /* The property didn't exist in this kid. */ + continue; + } + + JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); + vxml = (JSXML *) JSVAL_TO_OBJECT(v)->getPrivate(); + if ((!JSXML_HAS_KIDS(vxml) || vxml->xml_kids.length != 0) && + !Append(cx, list, vxml)) { + return JS_FALSE; + } + } + return JS_TRUE; + } + + /* ECMA-357 Edition 2 13.3.4.6 (note 13.3, not 13.4 as in Edition 1). */ + if (!xml_child_helper(cx, obj, xml, name, vp)) + return JS_FALSE; + if (JSVAL_IS_VOID(*vp) && !xml_list_helper(cx, xml, vp)) + return JS_FALSE; + return JS_TRUE; +} + +static JSBool +xml_childIndex(JSContext *cx, uintN argc, jsval *vp) +{ + JSXML *parent; + uint32 i, n; + + NON_LIST_XML_METHOD_PROLOG; + parent = xml->parent; + if (!parent || xml->xml_class == JSXML_CLASS_ATTRIBUTE) { + *vp = DOUBLE_TO_JSVAL(js_NaN); + return JS_TRUE; + } + for (i = 0, n = JSXML_LENGTH(parent); i < n; i++) { + if (XMLARRAY_MEMBER(&parent->xml_kids, i, JSXML) == xml) + break; + } + JS_ASSERT(i < n); + if (i <= JSVAL_INT_MAX) + *vp = INT_TO_JSVAL(i); + else + *vp = DOUBLE_TO_JSVAL(i); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_children(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj = ToObject(cx, Valueify(&vp[1])); + if (!obj) + return false; + jsid name = ATOM_TO_JSID(cx->runtime->atomState.starAtom); + return GetProperty(cx, obj, name, vp); +} + +/* XML and XMLList */ +static JSBool +xml_comments_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval *vp) +{ + JSXML *list, *kid, *vxml; + JSBool ok; + uint32 i, n; + JSObject *kidobj; + jsval v; + + list = xml_list_helper(cx, xml, vp); + if (!list) + return JS_FALSE; + + ok = JS_TRUE; + + if (xml->xml_class == JSXML_CLASS_LIST) { + /* 13.5.4.6 Step 2. */ + for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { + ok = js_EnterLocalRootScope(cx); + if (!ok) + break; + kidobj = js_GetXMLObject(cx, kid); + if (kidobj) { + ok = xml_comments_helper(cx, kidobj, kid, &v); + } else { + ok = JS_FALSE; + v = JSVAL_NULL; + } + js_LeaveLocalRootScopeWithResult(cx, Valueify(v)); + if (!ok) + break; + vxml = (JSXML *) JSVAL_TO_OBJECT(v)->getPrivate(); + if (JSXML_LENGTH(vxml) != 0) { + ok = Append(cx, list, vxml); + if (!ok) + break; + } + } + } + } else { + /* 13.4.4.9 Step 2. */ + for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_COMMENT) { + ok = Append(cx, list, kid); + if (!ok) + break; + } + } + } + + return ok; +} + +static JSBool +xml_comments(JSContext *cx, uintN argc, jsval *vp) +{ + XML_METHOD_PROLOG; + return xml_comments_helper(cx, obj, xml, vp); +} + +/* XML and XMLList */ +static JSBool +xml_contains(JSContext *cx, uintN argc, jsval *vp) +{ + jsval value; + JSBool eq; + JSObject *kidobj; + + XML_METHOD_PROLOG; + value = argc != 0 ? vp[2] : JSVAL_VOID; + if (xml->xml_class == JSXML_CLASS_LIST) { + eq = JS_FALSE; + JSXMLArrayCursor cursor(&xml->xml_kids); + while (JSXML *kid = (JSXML *) cursor.getNext()) { + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj || !js_TestXMLEquality(cx, ObjectValue(*kidobj), Valueify(value), &eq)) + return JS_FALSE; + if (eq) + break; + } + } else { + if (!js_TestXMLEquality(cx, ObjectValue(*obj), Valueify(value), &eq)) + return JS_FALSE; + } + *vp = BOOLEAN_TO_JSVAL(eq); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_copy(JSContext *cx, uintN argc, jsval *vp) +{ + JSXML *copy; + + XML_METHOD_PROLOG; + copy = DeepCopy(cx, xml, NULL, 0); + if (!copy) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(copy->object); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_descendants(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name; + JSXML *list; + + XML_METHOD_PROLOG; + name = argc == 0 ? ATOM_TO_JSVAL(cx->runtime->atomState.starAtom) : vp[2]; + list = Descendants(cx, xml, name); + if (!list) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(list->object); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_elements_helper(JSContext *cx, JSObject *obj, JSXML *xml, + JSObject *nameqn, jsval *vp) +{ + JSXML *list, *vxml; + jsval v; + JSBool ok; + JSObject *kidobj; + uint32 i, n; + + list = xml_list_helper(cx, xml, vp); + if (!list) + return JS_FALSE; + + list->xml_targetprop = nameqn; + ok = JS_TRUE; + + if (xml->xml_class == JSXML_CLASS_LIST) { + /* 13.5.4.6 */ + JSXMLArrayCursor cursor(&xml->xml_kids); + while (JSXML *kid = (JSXML *) cursor.getNext()) { + if (kid->xml_class == JSXML_CLASS_ELEMENT) { + ok = js_EnterLocalRootScope(cx); + if (!ok) + break; + kidobj = js_GetXMLObject(cx, kid); + if (kidobj) { + ok = xml_elements_helper(cx, kidobj, kid, nameqn, &v); + } else { + ok = JS_FALSE; + v = JSVAL_NULL; + } + js_LeaveLocalRootScopeWithResult(cx, Valueify(v)); + if (!ok) + break; + vxml = (JSXML *) JSVAL_TO_OBJECT(v)->getPrivate(); + if (JSXML_LENGTH(vxml) != 0) { + ok = Append(cx, list, vxml); + if (!ok) + break; + } + } + } + } else { + for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { + JSXML *kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT && + MatchElemName(nameqn, kid)) { + ok = Append(cx, list, kid); + if (!ok) + break; + } + } + } + + return ok; +} + +static JSBool +xml_elements(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name; + JSObject *nameqn; + jsid funid; + + XML_METHOD_PROLOG; + + name = (argc == 0) ? ATOM_TO_JSVAL(cx->runtime->atomState.starAtom) : vp[2]; + nameqn = ToXMLName(cx, name, &funid); + if (!nameqn) + return JS_FALSE; + + if (!JSID_IS_VOID(funid)) + return xml_list_helper(cx, xml, vp) != NULL; + + return xml_elements_helper(cx, obj, xml, nameqn, vp); +} + +/* XML and XMLList */ +static JSBool +xml_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name; + JSBool found; + + JSObject *obj = ToObject(cx, Valueify(&vp[1])); + if (!obj) + return JS_FALSE; + if (!InstanceOf(cx, obj, &js_XMLClass, Valueify(vp + 2))) + return JS_FALSE; + + name = argc != 0 ? vp[2] : JSVAL_VOID; + if (!HasProperty(cx, obj, name, &found)) + return JS_FALSE; + if (found) { + *vp = JSVAL_TRUE; + return JS_TRUE; + } + return js_HasOwnPropertyHelper(cx, js_LookupProperty, argc, Valueify(vp)); +} + +/* XML and XMLList */ +static JSBool +xml_hasComplexContent(JSContext *cx, uintN argc, jsval *vp) +{ + JSXML *kid; + JSObject *kidobj; + uint32 i, n; + + XML_METHOD_PROLOG; +again: + switch (xml->xml_class) { + case JSXML_CLASS_ATTRIBUTE: + case JSXML_CLASS_COMMENT: + case JSXML_CLASS_PROCESSING_INSTRUCTION: + case JSXML_CLASS_TEXT: + *vp = JSVAL_FALSE; + break; + case JSXML_CLASS_LIST: + if (xml->xml_kids.length == 0) { + *vp = JSVAL_TRUE; + } else if (xml->xml_kids.length == 1) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (kid) { + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj) + return JS_FALSE; + obj = kidobj; + xml = (JSXML *) obj->getPrivate(); + goto again; + } + } + /* FALL THROUGH */ + default: + *vp = JSVAL_FALSE; + for (i = 0, n = xml->xml_kids.length; i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { + *vp = JSVAL_TRUE; + break; + } + } + break; + } + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_hasSimpleContent(JSContext *cx, uintN argc, jsval *vp) +{ + XML_METHOD_PROLOG; + *vp = BOOLEAN_TO_JSVAL(HasSimpleContent(xml)); + return JS_TRUE; +} + +static JSBool +FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray) +{ + uint32 length, i, j, n; + JSObject *ns, *ns2; + JSLinearString *prefix, *prefix2; + + length = nsarray->length; + do { + if (xml->xml_class != JSXML_CLASS_ELEMENT) + continue; + for (i = 0, n = xml->xml_namespaces.length; i < n; i++) { + ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + if (!ns) + continue; + + prefix = ns->getNamePrefix(); + for (j = 0; j < length; j++) { + ns2 = XMLARRAY_MEMBER(nsarray, j, JSObject); + if (ns2) { + prefix2 = ns2->getNamePrefix(); + if ((prefix2 && prefix) + ? EqualStrings(prefix2, prefix) + : EqualStrings(ns2->getNameURI(), ns->getNameURI())) { + break; + } + } + } + + if (j == length) { + if (!XMLARRAY_APPEND(cx, nsarray, ns)) + return JS_FALSE; + ++length; + } + } + } while ((xml = xml->parent) != NULL); + JS_ASSERT(length == nsarray->length); + + return JS_TRUE; +} + +/* + * Populate a new JS array with elements of array and place the result into + * rval. rval must point to a rooted location. + */ +static bool +NamespacesToJSArray(JSContext *cx, JSXMLArray *array, jsval *rval) +{ + JSObject *arrayobj = NewDenseEmptyArray(cx); + if (!arrayobj) + return false; + *rval = OBJECT_TO_JSVAL(arrayobj); + + AutoValueRooter tvr(cx); + for (uint32 i = 0, n = array->length; i < n; i++) { + JSObject *ns = XMLARRAY_MEMBER(array, i, JSObject); + if (!ns) + continue; + tvr.set(ObjectValue(*ns)); + if (!arrayobj->setProperty(cx, INT_TO_JSID(i), tvr.addr(), false)) + return false; + } + return true; +} + +static JSBool +xml_inScopeNamespaces(JSContext *cx, uintN argc, jsval *vp) +{ + NON_LIST_XML_METHOD_PROLOG; + + AutoNamespaceArray namespaces(cx); + return FindInScopeNamespaces(cx, xml, &namespaces.array) && + NamespacesToJSArray(cx, &namespaces.array, vp); +} + +static JSBool +xml_insertChildAfter(JSContext *cx, uintN argc, jsval *vp) +{ + jsval arg; + JSXML *kid; + uint32 i; + + NON_LIST_XML_METHOD_PROLOG; + *vp = OBJECT_TO_JSVAL(obj); + if (!JSXML_HAS_KIDS(xml) || argc == 0) + return JS_TRUE; + + arg = vp[2]; + if (JSVAL_IS_NULL(arg)) { + kid = NULL; + i = 0; + } else { + if (!VALUE_IS_XML(arg)) + return JS_TRUE; + kid = (JSXML *) JSVAL_TO_OBJECT(arg)->getPrivate(); + i = XMLARRAY_FIND_MEMBER(&xml->xml_kids, kid, NULL); + if (i == XML_NOT_FOUND) + return JS_TRUE; + ++i; + } + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + return Insert(cx, xml, i, argc >= 2 ? vp[3] : JSVAL_VOID); +} + +static JSBool +xml_insertChildBefore(JSContext *cx, uintN argc, jsval *vp) +{ + jsval arg; + JSXML *kid; + uint32 i; + + NON_LIST_XML_METHOD_PROLOG; + *vp = OBJECT_TO_JSVAL(obj); + if (!JSXML_HAS_KIDS(xml) || argc == 0) + return JS_TRUE; + + arg = vp[2]; + if (JSVAL_IS_NULL(arg)) { + kid = NULL; + i = xml->xml_kids.length; + } else { + if (!VALUE_IS_XML(arg)) + return JS_TRUE; + kid = (JSXML *) JSVAL_TO_OBJECT(arg)->getPrivate(); + i = XMLARRAY_FIND_MEMBER(&xml->xml_kids, kid, NULL); + if (i == XML_NOT_FOUND) + return JS_TRUE; + } + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + return Insert(cx, xml, i, argc >= 2 ? vp[3] : JSVAL_VOID); +} + +/* XML and XMLList */ +static JSBool +xml_length(JSContext *cx, uintN argc, jsval *vp) +{ + XML_METHOD_PROLOG; + if (xml->xml_class != JSXML_CLASS_LIST) { + *vp = JSVAL_ONE; + } else { + uint32 l = xml->xml_kids.length; + if (l <= JSVAL_INT_MAX) + *vp = INT_TO_JSVAL(l); + else + *vp = DOUBLE_TO_JSVAL(l); + } + return JS_TRUE; +} + +static JSBool +xml_localName(JSContext *cx, uintN argc, jsval *vp) +{ + NON_LIST_XML_METHOD_PROLOG; + *vp = xml->name ? xml->name->getQNameLocalNameVal() : JSVAL_NULL; + return JS_TRUE; +} + +static JSBool +xml_name(JSContext *cx, uintN argc, jsval *vp) +{ + NON_LIST_XML_METHOD_PROLOG; + *vp = OBJECT_TO_JSVAL(xml->name); + return JS_TRUE; +} + +static JSBool +xml_namespace(JSContext *cx, uintN argc, jsval *vp) +{ + JSLinearString *prefix, *nsprefix; + jsuint i, length; + JSObject *ns; + + NON_LIST_XML_METHOD_PROLOG; + if (argc == 0 && !JSXML_HAS_NAME(xml)) { + *vp = JSVAL_NULL; + return true; + } + + if (argc == 0) { + prefix = NULL; + } else { + JSString *str = js_ValueToString(cx, Valueify(vp[2])); + if (!str) + return false; + prefix = str->ensureLinear(cx); + if (!prefix) + return false; + vp[2] = STRING_TO_JSVAL(prefix); /* local root */ + } + + AutoNamespaceArray inScopeNSes(cx); + if (!FindInScopeNamespaces(cx, xml, &inScopeNSes.array)) + return false; + + if (!prefix) { + ns = GetNamespace(cx, xml->name, &inScopeNSes.array); + if (!ns) + return false; + } else { + ns = NULL; + for (i = 0, length = inScopeNSes.array.length; i < length; i++) { + ns = XMLARRAY_MEMBER(&inScopeNSes.array, i, JSObject); + if (ns) { + nsprefix = ns->getNamePrefix(); + if (nsprefix && EqualStrings(nsprefix, prefix)) + break; + ns = NULL; + } + } + } + + *vp = (!ns) ? JSVAL_VOID : OBJECT_TO_JSVAL(ns); + return true; +} + +static JSBool +xml_namespaceDeclarations(JSContext *cx, uintN argc, jsval *vp) +{ + NON_LIST_XML_METHOD_PROLOG; + if (JSXML_HAS_VALUE(xml)) + return true; + + AutoNamespaceArray ancestors(cx); + AutoNamespaceArray declared(cx); + + JSXML *yml = xml; + while ((yml = yml->parent) != NULL) { + JS_ASSERT(yml->xml_class == JSXML_CLASS_ELEMENT); + for (uint32 i = 0, n = yml->xml_namespaces.length; i < n; i++) { + JSObject *ns = XMLARRAY_MEMBER(&yml->xml_namespaces, i, JSObject); + if (ns && !XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { + if (!XMLARRAY_APPEND(cx, &ancestors.array, ns)) + return false; + } + } + } + + for (uint32 i = 0, n = xml->xml_namespaces.length; i < n; i++) { + JSObject *ns = XMLARRAY_MEMBER(&xml->xml_namespaces, i, JSObject); + if (!ns) + continue; + if (!IsDeclared(ns)) + continue; + if (!XMLARRAY_HAS_MEMBER(&ancestors.array, ns, namespace_match)) { + if (!XMLARRAY_APPEND(cx, &declared.array, ns)) + return false; + } + } + + return NamespacesToJSArray(cx, &declared.array, vp); +} + +static const char js_attribute_str[] = "attribute"; +static const char js_text_str[] = "text"; + +/* Exported to jsgc.c #ifdef DEBUG. */ +const char *js_xml_class_str[] = { + "list", + "element", + js_attribute_str, + "processing-instruction", + js_text_str, + "comment" +}; + +static JSBool +xml_nodeKind(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + NON_LIST_XML_METHOD_PROLOG; + str = JS_InternString(cx, js_xml_class_str[xml->xml_class]); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static void +NormalizingDelete(JSContext *cx, JSXML *xml, uint32 index) +{ + if (xml->xml_class == JSXML_CLASS_LIST) + DeleteListElement(cx, xml, index); + else + DeleteByIndex(cx, xml, index); +} + +/* XML and XMLList */ +static JSBool +xml_normalize_helper(JSContext *cx, JSObject *obj, JSXML *xml) +{ + JSXML *kid, *kid2; + uint32 i, n; + JSObject *kidobj; + JSString *str; + + if (!JSXML_HAS_KIDS(xml)) + return JS_TRUE; + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + + for (i = 0, n = xml->xml_kids.length; i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (!kid) + continue; + if (kid->xml_class == JSXML_CLASS_ELEMENT) { + kidobj = js_GetXMLObject(cx, kid); + if (!kidobj || !xml_normalize_helper(cx, kidobj, kid)) + return JS_FALSE; + } else if (kid->xml_class == JSXML_CLASS_TEXT) { + while (i + 1 < n && + (kid2 = XMLARRAY_MEMBER(&xml->xml_kids, i + 1, JSXML)) && + kid2->xml_class == JSXML_CLASS_TEXT) { + str = js_ConcatStrings(cx, kid->xml_value, kid2->xml_value); + if (!str) + return JS_FALSE; + NormalizingDelete(cx, xml, i + 1); + n = xml->xml_kids.length; + kid->xml_value = str; + } + if (kid->xml_value->empty()) { + NormalizingDelete(cx, xml, i); + n = xml->xml_kids.length; + --i; + } + } + } + + return JS_TRUE; +} + +static JSBool +xml_normalize(JSContext *cx, uintN argc, jsval *vp) +{ + XML_METHOD_PROLOG; + *vp = OBJECT_TO_JSVAL(obj); + return xml_normalize_helper(cx, obj, xml); +} + +/* XML and XMLList */ +static JSBool +xml_parent(JSContext *cx, uintN argc, jsval *vp) +{ + JSXML *parent, *kid; + uint32 i, n; + JSObject *parentobj; + + XML_METHOD_PROLOG; + parent = xml->parent; + if (xml->xml_class == JSXML_CLASS_LIST) { + *vp = JSVAL_VOID; + n = xml->xml_kids.length; + if (n == 0) + return JS_TRUE; + + kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); + if (!kid) + return JS_TRUE; + parent = kid->parent; + for (i = 1; i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->parent != parent) + return JS_TRUE; + } + } + + if (!parent) { + *vp = JSVAL_NULL; + return JS_TRUE; + } + + parentobj = js_GetXMLObject(cx, parent); + if (!parentobj) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(parentobj); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_processingInstructions_helper(JSContext *cx, JSObject *obj, JSXML *xml, + JSObject *nameqn, jsval *vp) +{ + JSXML *list, *vxml; + JSBool ok; + JSObject *kidobj; + jsval v; + uint32 i, n; + + list = xml_list_helper(cx, xml, vp); + if (!list) + return JS_FALSE; + + list->xml_targetprop = nameqn; + ok = JS_TRUE; + + if (xml->xml_class == JSXML_CLASS_LIST) { + /* 13.5.4.17 Step 4 (misnumbered 9 -- Erratum?). */ + JSXMLArrayCursor cursor(&xml->xml_kids); + while (JSXML *kid = (JSXML *) cursor.getNext()) { + if (kid->xml_class == JSXML_CLASS_ELEMENT) { + ok = js_EnterLocalRootScope(cx); + if (!ok) + break; + kidobj = js_GetXMLObject(cx, kid); + if (kidobj) { + ok = xml_processingInstructions_helper(cx, kidobj, kid, + nameqn, &v); + } else { + ok = JS_FALSE; + v = JSVAL_NULL; + } + js_LeaveLocalRootScopeWithResult(cx, Valueify(v)); + if (!ok) + break; + vxml = (JSXML *) JSVAL_TO_OBJECT(v)->getPrivate(); + if (JSXML_LENGTH(vxml) != 0) { + ok = Append(cx, list, vxml); + if (!ok) + break; + } + } + } + } else { + /* 13.4.4.28 Step 4. */ + for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { + JSXML *kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION) { + JSLinearString *localName = nameqn->getQNameLocalName(); + if (IS_STAR(localName) || + EqualStrings(localName, kid->name->getQNameLocalName())) { + ok = Append(cx, list, kid); + if (!ok) + break; + } + } + } + } + + return ok; +} + +static JSBool +xml_processingInstructions(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name; + JSObject *nameqn; + jsid funid; + + XML_METHOD_PROLOG; + + name = (argc == 0) ? ATOM_TO_JSVAL(cx->runtime->atomState.starAtom) : vp[2]; + nameqn = ToXMLName(cx, name, &funid); + if (!nameqn) + return JS_FALSE; + vp[2] = OBJECT_TO_JSVAL(nameqn); + + if (!JSID_IS_VOID(funid)) + return xml_list_helper(cx, xml, vp) != NULL; + + return xml_processingInstructions_helper(cx, obj, xml, nameqn, vp); +} + +static JSBool +xml_prependChild(JSContext *cx, uintN argc, jsval *vp) +{ + NON_LIST_XML_METHOD_PROLOG; + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(obj); + return Insert(cx, xml, 0, argc != 0 ? vp[2] : JSVAL_VOID); +} + +/* XML and XMLList */ +static JSBool +xml_propertyIsEnumerable(JSContext *cx, uintN argc, jsval *vp) +{ + bool isIndex; + uint32 index; + + XML_METHOD_PROLOG; + *vp = JSVAL_FALSE; + if (argc != 0) { + if (!js_IdValIsIndex(cx, vp[2], &index, &isIndex)) + return JS_FALSE; + + if (isIndex) { + if (xml->xml_class == JSXML_CLASS_LIST) { + /* 13.5.4.18. */ + *vp = BOOLEAN_TO_JSVAL(index < xml->xml_kids.length); + } else { + /* 13.4.4.30. */ + *vp = BOOLEAN_TO_JSVAL(index == 0); + } + } + } + return JS_TRUE; +} + +static JSBool +namespace_full_match(const void *a, const void *b) +{ + const JSObject *nsa = (const JSObject *) a; + const JSObject *nsb = (const JSObject *) b; + JSLinearString *prefixa = nsa->getNamePrefix(); + JSLinearString *prefixb; + + if (prefixa) { + prefixb = nsb->getNamePrefix(); + if (prefixb && !EqualStrings(prefixa, prefixb)) + return JS_FALSE; + } + return EqualStrings(nsa->getNameURI(), nsb->getNameURI()); +} + +static JSBool +xml_removeNamespace_helper(JSContext *cx, JSXML *xml, JSObject *ns) +{ + JSObject *thisns, *attrns; + uint32 i, n; + JSXML *attr, *kid; + + thisns = GetNamespace(cx, xml->name, &xml->xml_namespaces); + JS_ASSERT(thisns); + if (thisns == ns) + return JS_TRUE; + + for (i = 0, n = xml->xml_attrs.length; i < n; i++) { + attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML); + if (!attr) + continue; + attrns = GetNamespace(cx, attr->name, &xml->xml_namespaces); + JS_ASSERT(attrns); + if (attrns == ns) + return JS_TRUE; + } + + i = XMLARRAY_FIND_MEMBER(&xml->xml_namespaces, ns, namespace_full_match); + if (i != XML_NOT_FOUND) + XMLArrayDelete(cx, &xml->xml_namespaces, i, JS_TRUE); + + for (i = 0, n = xml->xml_kids.length; i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { + if (!xml_removeNamespace_helper(cx, kid, ns)) + return JS_FALSE; + } + } + return JS_TRUE; +} + +static JSBool +xml_removeNamespace(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *ns; + + NON_LIST_XML_METHOD_PROLOG; + if (xml->xml_class != JSXML_CLASS_ELEMENT) + goto done; + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + + if (!NamespaceHelper(cx, NULL, argc == 0 ? -1 : 1, vp + 2, vp)) + return JS_FALSE; + JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp)); + ns = JSVAL_TO_OBJECT(*vp); + + /* NOTE: remove ns from each ancestor if not used by that ancestor. */ + if (!xml_removeNamespace_helper(cx, xml, ns)) + return JS_FALSE; + done: + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +static JSBool +xml_replace(JSContext *cx, uintN argc, jsval *vp) +{ + jsval value; + JSXML *vxml, *kid; + uint32 index, i; + JSObject *nameqn; + + NON_LIST_XML_METHOD_PROLOG; + if (xml->xml_class != JSXML_CLASS_ELEMENT) + goto done; + + if (argc <= 1) { + value = ATOM_TO_JSVAL(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + } else { + value = vp[3]; + vxml = VALUE_IS_XML(value) + ? (JSXML *) JSVAL_TO_OBJECT(value)->getPrivate() + : NULL; + if (!vxml) { + if (!JS_ConvertValue(cx, value, JSTYPE_STRING, &vp[3])) + return JS_FALSE; + value = vp[3]; + } else { + vxml = DeepCopy(cx, vxml, NULL, 0); + if (!vxml) + return JS_FALSE; + value = vp[3] = OBJECT_TO_JSVAL(vxml->object); + } + } + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + + bool haveIndex; + if (argc == 0) { + haveIndex = false; + } else { + if (!js_IdValIsIndex(cx, vp[2], &index, &haveIndex)) + return JS_FALSE; + } + + if (!haveIndex) { + /* + * Call function QName per spec, not ToXMLName, to avoid attribute + * names. + */ + if (!QNameHelper(cx, NULL, argc == 0 ? -1 : 1, vp + 2, vp)) + return JS_FALSE; + JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp)); + nameqn = JSVAL_TO_OBJECT(*vp); + + i = xml->xml_kids.length; + index = XML_NOT_FOUND; + while (i != 0) { + --i; + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && MatchElemName(nameqn, kid)) { + if (i != XML_NOT_FOUND) + DeleteByIndex(cx, xml, i); + index = i; + } + } + + if (index == XML_NOT_FOUND) + goto done; + } + + if (!Replace(cx, xml, index, value)) + return JS_FALSE; + + done: + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +static JSBool +xml_setChildren(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; + + if (!StartNonListXMLMethod(cx, vp, &obj)) + return JS_FALSE; + + *vp = argc != 0 ? vp[2] : JSVAL_VOID; /* local root */ + if (!PutProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.starAtom), false, vp)) + return JS_FALSE; + + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +static JSBool +xml_setLocalName(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name; + JSObject *nameqn; + JSLinearString *namestr; + + NON_LIST_XML_METHOD_PROLOG; + if (!JSXML_HAS_NAME(xml)) + return JS_TRUE; + + if (argc == 0) { + namestr = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + } else { + name = vp[2]; + if (!JSVAL_IS_PRIMITIVE(name) && + JSVAL_TO_OBJECT(name)->getClass() == &js_QNameClass) { + nameqn = JSVAL_TO_OBJECT(name); + namestr = nameqn->getQNameLocalName(); + } else { + if (!JS_ConvertValue(cx, name, JSTYPE_STRING, &vp[2])) + return JS_FALSE; + name = vp[2]; + namestr = JSVAL_TO_STRING(name)->ensureLinear(cx); + if (!namestr) + return JS_FALSE; + } + } + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + if (namestr) + xml->name->setQNameLocalName(namestr); + return JS_TRUE; +} + +static JSBool +xml_setName(JSContext *cx, uintN argc, jsval *vp) +{ + jsval name; + JSObject *nameqn; + JSXML *nsowner; + JSXMLArray *nsarray; + uint32 i, n; + JSObject *ns; + + NON_LIST_XML_METHOD_PROLOG; + if (!JSXML_HAS_NAME(xml)) + return JS_TRUE; + + if (argc == 0) { + name = ATOM_TO_JSVAL(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + } else { + name = vp[2]; + if (!JSVAL_IS_PRIMITIVE(name) && + JSVAL_TO_OBJECT(name)->getClass() == &js_QNameClass && + !(nameqn = JSVAL_TO_OBJECT(name))->getNameURI()) { + name = vp[2] = nameqn->getQNameLocalNameVal(); + } + } + + nameqn = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1, Valueify(&name)); + if (!nameqn) + return JS_FALSE; + + /* ECMA-357 13.4.4.35 Step 4. */ + if (xml->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION) + nameqn->setNameURI(cx->runtime->emptyString); + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + xml->name = nameqn; + + /* + * Erratum: nothing in 13.4.4.35 talks about making the name match the + * in-scope namespaces, either by finding an in-scope namespace with a + * matching uri and setting the new name's prefix to that namespace's + * prefix, or by extending the in-scope namespaces for xml (which are in + * xml->parent if xml is an attribute or a PI). + */ + if (xml->xml_class == JSXML_CLASS_ELEMENT) { + nsowner = xml; + } else { + if (!xml->parent || xml->parent->xml_class != JSXML_CLASS_ELEMENT) + return JS_TRUE; + nsowner = xml->parent; + } + + if (nameqn->getNamePrefix()) { + /* + * The name being set has a prefix, which originally came from some + * namespace object (which may be the null namespace, where both the + * prefix and uri are the empty string). We must go through a full + * GetNamespace in case that namespace is in-scope in nsowner. + * + * If we find such an in-scope namespace, we return true right away, + * in this block. Otherwise, we fall through to the final return of + * AddInScopeNamespace(cx, nsowner, ns). + */ + ns = GetNamespace(cx, nameqn, &nsowner->xml_namespaces); + if (!ns) + return JS_FALSE; + + /* XXXbe have to test membership to see whether GetNamespace added */ + if (XMLARRAY_HAS_MEMBER(&nsowner->xml_namespaces, ns, NULL)) + return JS_TRUE; + } else { + /* + * At this point, we know prefix of nameqn is null, so its uri can't + * be the empty string (the null namespace always uses the empty string + * for both prefix and uri). + * + * This means we must inline GetNamespace and specialize it to match + * uri only, never prefix. If we find a namespace with nameqn's uri + * already in nsowner->xml_namespaces, then all that we need do is set + * prefix of nameqn to that namespace's prefix. + * + * If no such namespace exists, we can create one without going through + * the constructor, because we know uri of nameqn is non-empty (so + * prefix does not need to be converted from null to empty by QName). + */ + JS_ASSERT(!nameqn->getNameURI()->empty()); + + nsarray = &nsowner->xml_namespaces; + for (i = 0, n = nsarray->length; i < n; i++) { + ns = XMLARRAY_MEMBER(nsarray, i, JSObject); + if (ns && EqualStrings(ns->getNameURI(), nameqn->getNameURI())) { + nameqn->setNamePrefix(ns->getNamePrefix()); + return JS_TRUE; + } + } + + ns = NewXMLNamespace(cx, NULL, nameqn->getNameURI(), JS_TRUE); + if (!ns) + return JS_FALSE; + } + + if (!AddInScopeNamespace(cx, nsowner, ns)) + return JS_FALSE; + vp[0] = JSVAL_VOID; + return JS_TRUE; +} + +static JSBool +xml_setNamespace(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *qn; + JSObject *ns; + jsval qnargv[2]; + JSXML *nsowner; + + NON_LIST_XML_METHOD_PROLOG; + if (!JSXML_HAS_NAME(xml)) + return JS_TRUE; + + xml = CHECK_COPY_ON_WRITE(cx, xml, obj); + if (!xml) + return JS_FALSE; + + ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, obj, + argc == 0 ? 0 : 1, Valueify(vp + 2)); + if (!ns) + return JS_FALSE; + vp[0] = OBJECT_TO_JSVAL(ns); + ns->setNamespaceDeclared(JSVAL_TRUE); + + qnargv[0] = OBJECT_TO_JSVAL(ns); + qnargv[1] = OBJECT_TO_JSVAL(xml->name); + qn = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 2, Valueify(qnargv)); + if (!qn) + return JS_FALSE; + + xml->name = qn; + + /* + * Erratum: the spec fails to update the governing in-scope namespaces. + * See the erratum noted in xml_setName, above. + */ + if (xml->xml_class == JSXML_CLASS_ELEMENT) { + nsowner = xml; + } else { + if (!xml->parent || xml->parent->xml_class != JSXML_CLASS_ELEMENT) + return JS_TRUE; + nsowner = xml->parent; + } + if (!AddInScopeNamespace(cx, nsowner, ns)) + return JS_FALSE; + vp[0] = JSVAL_VOID; + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_text_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval *vp) +{ + JSXML *list, *kid, *vxml; + uint32 i, n; + JSBool ok; + JSObject *kidobj; + jsval v; + + list = xml_list_helper(cx, xml, vp); + if (!list) + return JS_FALSE; + + if (xml->xml_class == JSXML_CLASS_LIST) { + ok = JS_TRUE; + for (i = 0, n = xml->xml_kids.length; i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { + ok = js_EnterLocalRootScope(cx); + if (!ok) + break; + kidobj = js_GetXMLObject(cx, kid); + if (kidobj) { + ok = xml_text_helper(cx, kidobj, kid, &v); + } else { + ok = JS_FALSE; + v = JSVAL_NULL; + } + js_LeaveLocalRootScopeWithResult(cx, Valueify(v)); + if (!ok) + return JS_FALSE; + vxml = (JSXML *) JSVAL_TO_OBJECT(v)->getPrivate(); + if (JSXML_LENGTH(vxml) != 0 && !Append(cx, list, vxml)) + return JS_FALSE; + } + } + } else { + for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) { + kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); + if (kid && kid->xml_class == JSXML_CLASS_TEXT) { + if (!Append(cx, list, kid)) + return JS_FALSE; + } + } + } + return JS_TRUE; +} + +static JSBool +xml_text(JSContext *cx, uintN argc, jsval *vp) +{ + XML_METHOD_PROLOG; + return xml_text_helper(cx, obj, xml, vp); +} + +/* XML and XMLList */ +static JSString * +xml_toString_helper(JSContext *cx, JSXML *xml) +{ + JSString *str, *kidstr; + + if (xml->xml_class == JSXML_CLASS_ATTRIBUTE || + xml->xml_class == JSXML_CLASS_TEXT) { + return xml->xml_value; + } + + if (!HasSimpleContent(xml)) + return ToXMLString(cx, OBJECT_TO_JSVAL(xml->object), 0); + + str = cx->runtime->emptyString; + if (!js_EnterLocalRootScope(cx)) + return NULL; + JSXMLArrayCursor cursor(&xml->xml_kids); + while (JSXML *kid = (JSXML *) cursor.getNext()) { + if (kid->xml_class != JSXML_CLASS_COMMENT && + kid->xml_class != JSXML_CLASS_PROCESSING_INSTRUCTION) { + kidstr = xml_toString_helper(cx, kid); + if (!kidstr) { + str = NULL; + break; + } + str = js_ConcatStrings(cx, str, kidstr); + if (!str) + break; + } + } + js_LeaveLocalRootScopeWithResult(cx, str); + return str; +} + +static JSBool +xml_toSource(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj = ToObject(cx, Valueify(&vp[1])); + if (!obj) + return JS_FALSE; + JSString *str = ToXMLString(cx, OBJECT_TO_JSVAL(obj), TO_SOURCE_FLAG); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +static JSBool +xml_toString(JSContext *cx, uintN argc, jsval *vp) +{ + JSString *str; + + XML_METHOD_PROLOG; + str = xml_toString_helper(cx, xml); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_toXMLString(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj = ToObject(cx, Valueify(&vp[1])); + if (!obj) + return JS_FALSE; + JSString *str = ToXMLString(cx, OBJECT_TO_JSVAL(obj), 0); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_valueOf(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj = ToObject(cx, Valueify(&vp[1])); + if (!obj) + return false; + *vp = OBJECT_TO_JSVAL(obj); + return true; +} + +static JSFunctionSpec xml_methods[] = { + JS_FN("addNamespace", xml_addNamespace, 1,0), + JS_FN("appendChild", xml_appendChild, 1,0), + JS_FN(js_attribute_str, xml_attribute, 1,0), + JS_FN("attributes", xml_attributes, 0,0), + JS_FN("child", xml_child, 1,0), + JS_FN("childIndex", xml_childIndex, 0,0), + JS_FN("children", xml_children, 0,0), + JS_FN("comments", xml_comments, 0,0), + JS_FN("contains", xml_contains, 1,0), + JS_FN("copy", xml_copy, 0,0), + JS_FN("descendants", xml_descendants, 1,0), + JS_FN("elements", xml_elements, 1,0), + JS_FN("hasOwnProperty", xml_hasOwnProperty, 1,0), + JS_FN("hasComplexContent", xml_hasComplexContent, 1,0), + JS_FN("hasSimpleContent", xml_hasSimpleContent, 1,0), + JS_FN("inScopeNamespaces", xml_inScopeNamespaces, 0,0), + JS_FN("insertChildAfter", xml_insertChildAfter, 2,0), + JS_FN("insertChildBefore", xml_insertChildBefore, 2,0), + JS_FN(js_length_str, xml_length, 0,0), + JS_FN(js_localName_str, xml_localName, 0,0), + JS_FN(js_name_str, xml_name, 0,0), + JS_FN(js_namespace_str, xml_namespace, 1,0), + JS_FN("namespaceDeclarations", xml_namespaceDeclarations, 0,0), + JS_FN("nodeKind", xml_nodeKind, 0,0), + JS_FN("normalize", xml_normalize, 0,0), + JS_FN(js_xml_parent_str, xml_parent, 0,0), + JS_FN("processingInstructions",xml_processingInstructions,1,0), + JS_FN("prependChild", xml_prependChild, 1,0), + JS_FN("propertyIsEnumerable", xml_propertyIsEnumerable, 1,0), + JS_FN("removeNamespace", xml_removeNamespace, 1,0), + JS_FN("replace", xml_replace, 2,0), + JS_FN("setChildren", xml_setChildren, 1,0), + JS_FN("setLocalName", xml_setLocalName, 1,0), + JS_FN("setName", xml_setName, 1,0), + JS_FN("setNamespace", xml_setNamespace, 1,0), + JS_FN(js_text_str, xml_text, 0,0), + JS_FN(js_toSource_str, xml_toSource, 0,0), + JS_FN(js_toString_str, xml_toString, 0,0), + JS_FN(js_toXMLString_str, xml_toXMLString, 0,0), + JS_FN(js_valueOf_str, xml_valueOf, 0,0), + JS_FS_END +}; + +static JSBool +CopyXMLSettings(JSContext *cx, JSObject *from, JSObject *to) +{ + int i; + const char *name; + jsval v; + + /* Note: PRETTY_INDENT is not a boolean setting. */ + for (i = 0; xml_static_props[i].name; i++) { + name = xml_static_props[i].name; + if (!JS_GetProperty(cx, from, name, &v)) + return false; + if (name == js_prettyIndent_str) { + if (!JSVAL_IS_NUMBER(v)) + continue; + } else { + if (!JSVAL_IS_BOOLEAN(v)) + continue; + } + if (!JS_SetProperty(cx, to, name, &v)) + return false; + } + + return true; +} + +static JSBool +SetDefaultXMLSettings(JSContext *cx, JSObject *obj) +{ + int i; + jsval v; + + /* Note: PRETTY_INDENT is not a boolean setting. */ + for (i = 0; xml_static_props[i].name; i++) { + v = (xml_static_props[i].name != js_prettyIndent_str) + ? JSVAL_TRUE : INT_TO_JSVAL(2); + if (!JS_SetProperty(cx, obj, xml_static_props[i].name, &v)) + return JS_FALSE; + } + return true; +} + +static JSBool +xml_settings(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *settings = JS_NewObject(cx, NULL, NULL, NULL); + if (!settings) + return false; + *vp = OBJECT_TO_JSVAL(settings); + JSObject *obj = ToObject(cx, Valueify(&vp[1])); + if (!obj) + return false; + return CopyXMLSettings(cx, obj, settings); +} + +static JSBool +xml_setSettings(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *settings; + jsval v; + JSBool ok; + + JSObject *obj = ToObject(cx, Valueify(&vp[1])); + if (!obj) + return JS_FALSE; + v = (argc == 0) ? JSVAL_VOID : vp[2]; + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) { + ok = SetDefaultXMLSettings(cx, obj); + } else { + if (JSVAL_IS_PRIMITIVE(v)) + return JS_TRUE; + settings = JSVAL_TO_OBJECT(v); + ok = CopyXMLSettings(cx, settings, obj); + } + return ok; +} + +static JSBool +xml_defaultSettings(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *settings; + + settings = JS_NewObject(cx, NULL, NULL, NULL); + if (!settings) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(settings); + return SetDefaultXMLSettings(cx, settings); +} + +static JSFunctionSpec xml_static_methods[] = { + JS_FN("settings", xml_settings, 0,0), + JS_FN("setSettings", xml_setSettings, 1,0), + JS_FN("defaultSettings", xml_defaultSettings, 0,0), + JS_FS_END +}; + +static JSBool +XML(JSContext *cx, uintN argc, Value *vp) +{ + JSXML *xml, *copy; + JSObject *xobj, *vobj; + Class *clasp; + + jsval v = argc ? Jsvalify(vp[2]) : JSVAL_VOID; + + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) + v = STRING_TO_JSVAL(cx->runtime->emptyString); + + xobj = ToXML(cx, v); + if (!xobj) + return JS_FALSE; + xml = (JSXML *) xobj->getPrivate(); + + if (IsConstructing(vp) && !JSVAL_IS_PRIMITIVE(v)) { + vobj = JSVAL_TO_OBJECT(v); + clasp = vobj->getClass(); + if (clasp == &js_XMLClass || + (clasp->flags & JSCLASS_DOCUMENT_OBSERVER)) { + copy = DeepCopy(cx, xml, NULL, 0); + if (!copy) + return JS_FALSE; + vp->setObject(*copy->object); + return JS_TRUE; + } + } + + vp->setObject(*xobj); + return JS_TRUE; +} + +static JSBool +XMLList(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *vobj, *listobj; + JSXML *xml, *list; + + jsval v = argc ? vp[2] : JSVAL_VOID; + + if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) + v = STRING_TO_JSVAL(cx->runtime->emptyString); + + if (IsConstructing(Valueify(vp)) && !JSVAL_IS_PRIMITIVE(v)) { + vobj = JSVAL_TO_OBJECT(v); + if (vobj->isXML()) { + xml = (JSXML *) vobj->getPrivate(); + if (xml->xml_class == JSXML_CLASS_LIST) { + listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!listobj) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(listobj); + + list = (JSXML *) listobj->getPrivate(); + if (!Append(cx, list, xml)) + return JS_FALSE; + return JS_TRUE; + } + } + } + + /* Toggle on XML support since the script has explicitly requested it. */ + listobj = ToXMLList(cx, v); + if (!listobj) + return JS_FALSE; + + *vp = OBJECT_TO_JSVAL(listobj); + return JS_TRUE; +} + +#ifdef DEBUG_notme +JSCList xml_leaks = JS_INIT_STATIC_CLIST(&xml_leaks); +uint32 xml_serial; +#endif + +JSXML * +js_NewXML(JSContext *cx, JSXMLClass xml_class) +{ + JSXML *xml = js_NewGCXML(cx); + if (!xml) + return NULL; + + xml->object = NULL; + xml->domnode = NULL; + xml->parent = NULL; + xml->name = NULL; + xml->xml_class = xml_class; + xml->xml_flags = 0; + if (JSXML_CLASS_HAS_VALUE(xml_class)) { + xml->xml_value = cx->runtime->emptyString; + } else { + xml->xml_kids.init(); + if (xml_class == JSXML_CLASS_LIST) { + xml->xml_target = NULL; + xml->xml_targetprop = NULL; + } else { + xml->xml_namespaces.init(); + xml->xml_attrs.init(); + } + } + +#ifdef DEBUG_notme + JS_APPEND_LINK(&xml->links, &xml_leaks); + xml->serial = xml_serial++; +#endif + METER(xml_stats.xml); + return xml; +} + +void +js_TraceXML(JSTracer *trc, JSXML *xml) +{ + if (xml->object) + MarkObject(trc, *xml->object, "object"); + if (xml->name) + MarkObject(trc, *xml->name, "name"); + if (xml->parent) + JS_CALL_TRACER(trc, xml->parent, JSTRACE_XML, "xml_parent"); + + if (JSXML_HAS_VALUE(xml)) { + if (xml->xml_value) + MarkString(trc, xml->xml_value, "value"); + return; + } + + xml_trace_vector(trc, + (JSXML **) xml->xml_kids.vector, + xml->xml_kids.length); + XMLArrayCursorTrace(trc, xml->xml_kids.cursors); + if (IS_GC_MARKING_TRACER(trc)) + xml->xml_kids.trim(); + + if (xml->xml_class == JSXML_CLASS_LIST) { + if (xml->xml_target) + JS_CALL_TRACER(trc, xml->xml_target, JSTRACE_XML, "target"); + if (xml->xml_targetprop) + MarkObject(trc, *xml->xml_targetprop, "targetprop"); + } else { + MarkObjectRange(trc, xml->xml_namespaces.length, + (JSObject **) xml->xml_namespaces.vector, + "xml_namespaces"); + XMLArrayCursorTrace(trc, xml->xml_namespaces.cursors); + if (IS_GC_MARKING_TRACER(trc)) + xml->xml_namespaces.trim(); + + xml_trace_vector(trc, + (JSXML **) xml->xml_attrs.vector, + xml->xml_attrs.length); + XMLArrayCursorTrace(trc, xml->xml_attrs.cursors); + if (IS_GC_MARKING_TRACER(trc)) + xml->xml_attrs.trim(); + } +} + +JSObject * +js_NewXMLObject(JSContext *cx, JSXMLClass xml_class) +{ + JSXML *xml = js_NewXML(cx, xml_class); + if (!xml) + return NULL; + + AutoXMLRooter root(cx, xml); + return js_GetXMLObject(cx, xml); +} + +static JSObject * +NewXMLObject(JSContext *cx, JSXML *xml) +{ + JSObject *obj; + + obj = NewNonFunction(cx, &js_XMLClass, NULL, NULL); + if (!obj) + return NULL; + obj->setPrivate(xml); + METER(xml_stats.xmlobj); + return obj; +} + +JSObject * +js_GetXMLObject(JSContext *cx, JSXML *xml) +{ + JSObject *obj; + + obj = xml->object; + if (obj) { + JS_ASSERT(obj->getPrivate() == xml); + return obj; + } + + obj = NewXMLObject(cx, xml); + if (!obj) + return NULL; + xml->object = obj; + return obj; +} + +JSObject * +js_InitNamespaceClass(JSContext *cx, JSObject *obj) +{ + return js_InitClass(cx, obj, NULL, &js_NamespaceClass, Namespace, 2, + namespace_props, namespace_methods, NULL, NULL); +} + +JSObject * +js_InitQNameClass(JSContext *cx, JSObject *obj) +{ + return js_InitClass(cx, obj, NULL, &js_QNameClass, QName, 2, + qname_props, qname_methods, NULL, NULL); +} + +JSObject * +js_InitXMLClass(JSContext *cx, JSObject *obj) +{ + JSObject *proto, *pobj; + JSFunction *fun; + JSXML *xml; + JSProperty *prop; + Shape *shape; + jsval cval, vp[3]; + + /* Define the isXMLName function. */ + if (!JS_DefineFunction(cx, obj, js_isXMLName_str, xml_isXMLName, 1, 0)) + return NULL; + + /* Define the XML class constructor and prototype. */ + proto = js_InitClass(cx, obj, NULL, &js_XMLClass, XML, 1, + NULL, xml_methods, + xml_static_props, xml_static_methods); + if (!proto) + return NULL; + + xml = js_NewXML(cx, JSXML_CLASS_TEXT); + if (!xml) + return NULL; + proto->setPrivate(xml); + xml->object = proto; + METER(xml_stats.xmlobj); + + /* + * Prepare to set default settings on the XML constructor we just made. + * NB: We can't use JS_GetConstructor, because it calls + * JSObject::getProperty, which is xml_getProperty, which creates a new + * XMLList every time! We must instead call js_LookupProperty directly. + */ + if (!js_LookupProperty(cx, proto, + ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), + &pobj, &prop)) { + return NULL; + } + JS_ASSERT(prop); + shape = (Shape *) prop; + cval = Jsvalify(pobj->nativeGetSlot(shape->slot)); + JS_ASSERT(VALUE_IS_FUNCTION(cx, cval)); + + /* Set default settings. */ + vp[0] = JSVAL_NULL; + vp[1] = cval; + vp[2] = JSVAL_VOID; + if (!xml_setSettings(cx, 1, vp)) + return NULL; + + /* Define the XMLList function and give it the same prototype as XML. */ + fun = JS_DefineFunction(cx, obj, js_XMLList_str, XMLList, 1, JSFUN_CONSTRUCTOR); + if (!fun) + return NULL; + if (!js_SetClassPrototype(cx, FUN_OBJECT(fun), proto, + JSPROP_READONLY | JSPROP_PERMANENT)) { + return NULL; + } + return proto; +} + +JSObject * +js_InitXMLClasses(JSContext *cx, JSObject *obj) +{ + if (!js_InitNamespaceClass(cx, obj)) + return NULL; + if (!js_InitQNameClass(cx, obj)) + return NULL; + return js_InitXMLClass(cx, obj); +} + +JSBool +js_GetFunctionNamespace(JSContext *cx, Value *vp) +{ + JSObject *global = cx->hasfp() ? cx->fp()->scopeChain().getGlobal() : cx->globalObject; + + *vp = global->getReservedSlot(JSRESERVED_GLOBAL_FUNCTION_NS); + if (vp->isUndefined()) { + JSRuntime *rt = cx->runtime; + JSLinearString *prefix = rt->atomState.typeAtoms[JSTYPE_FUNCTION]; + JSLinearString *uri = rt->atomState.functionNamespaceURIAtom; + JSObject *obj = NewXMLNamespace(cx, prefix, uri, JS_FALSE); + if (!obj) + return false; + + /* + * Avoid entraining any in-scope Object.prototype. The loss of + * Namespace.prototype is not detectable, as there is no way to + * refer to this instance in scripts. When used to qualify method + * names, its prefix and uri references are copied to the QName. + * The parent remains set and links back to global. + */ + obj->clearProto(); + + vp->setObject(*obj); + if (!js_SetReservedSlot(cx, global, JSRESERVED_GLOBAL_FUNCTION_NS, *vp)) + return false; + } + + return true; +} + +/* + * Note the asymmetry between js_GetDefaultXMLNamespace and js_SetDefaultXML- + * Namespace. Get searches fp->scopeChain for JS_DEFAULT_XML_NAMESPACE_ID, + * while Set sets JS_DEFAULT_XML_NAMESPACE_ID in fp->varobj. There's no + * requirement that fp->varobj lie directly on fp->scopeChain, although + * it should be reachable using the prototype chain from a scope object (cf. + * JSOPTION_VAROBJFIX in jsapi.h). + * + * If Get can't find JS_DEFAULT_XML_NAMESPACE_ID along the scope chain, it + * creates a default namespace via 'new Namespace()'. In contrast, Set uses + * its v argument as the uri of a new Namespace, with "" as the prefix. See + * ECMA-357 12.1 and 12.1.1. Note that if Set is called with a Namespace n, + * the default XML namespace will be set to ("", n.uri). So the uri string + * is really the only usefully stored value of the default namespace. + */ +JSBool +js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp) +{ + JSObject *ns, *obj, *tmp; + jsval v; + + JSObject *scopeChain = GetScopeChain(cx); + + obj = NULL; + for (tmp = scopeChain; tmp; tmp = tmp->getParent()) { + Class *clasp = tmp->getClass(); + if (clasp == &js_BlockClass || clasp == &js_WithClass) + continue; + if (!tmp->getProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, Valueify(&v))) + return JS_FALSE; + if (!JSVAL_IS_PRIMITIVE(v)) { + *vp = v; + return JS_TRUE; + } + obj = tmp; + } + + ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, obj, 0, NULL); + if (!ns) + return JS_FALSE; + v = OBJECT_TO_JSVAL(ns); + if (!obj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, Valueify(v), + PropertyStub, StrictPropertyStub, JSPROP_PERMANENT)) { + return JS_FALSE; + } + *vp = v; + return JS_TRUE; +} + +JSBool +js_SetDefaultXMLNamespace(JSContext *cx, const Value &v) +{ + Value argv[2]; + argv[0].setString(cx->runtime->emptyString); + argv[1] = v; + JSObject *ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL, 2, argv); + if (!ns) + return JS_FALSE; + + JSStackFrame *fp = js_GetTopStackFrame(cx); + JSObject &varobj = fp->varobj(cx); + if (!varobj.defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns), + PropertyStub, StrictPropertyStub, JSPROP_PERMANENT)) { + return JS_FALSE; + } + return JS_TRUE; +} + +JSBool +js_ToAttributeName(JSContext *cx, Value *vp) +{ + JSObject *qn; + + qn = ToAttributeName(cx, Jsvalify(*vp)); + if (!qn) + return JS_FALSE; + vp->setObject(*qn); + return JS_TRUE; +} + +JSFlatString * +js_EscapeAttributeValue(JSContext *cx, JSString *str, JSBool quote) +{ + StringBuffer sb(cx); + return EscapeAttributeValue(cx, sb, str, quote); +} + +JSString * +js_AddAttributePart(JSContext *cx, JSBool isName, JSString *str, JSString *str2) +{ + size_t len = str->length(); + const jschar *chars = str->getChars(cx); + if (!chars) + return NULL; + + size_t len2 = str2->length(); + const jschar *chars2 = str2->getChars(cx); + if (!chars2) + return NULL; + + size_t newlen = (isName) ? len + 1 + len2 : len + 2 + len2 + 1; + jschar *newchars = (jschar *) cx->malloc((newlen+1) * sizeof(jschar)); + if (!newchars) + return NULL; + + js_strncpy(newchars, chars, len); + newchars += len; + if (isName) { + *newchars++ = ' '; + js_strncpy(newchars, chars2, len2); + newchars += len2; + } else { + *newchars++ = '='; + *newchars++ = '"'; + js_strncpy(newchars, chars2, len2); + newchars += len2; + *newchars++ = '"'; + } + *newchars = 0; + return js_NewString(cx, newchars - newlen, newlen); +} + +JSFlatString * +js_EscapeElementValue(JSContext *cx, JSString *str) +{ + StringBuffer sb(cx); + return EscapeElementValue(cx, sb, str, 0); +} + +JSString * +js_ValueToXMLString(JSContext *cx, const Value &v) +{ + return ToXMLString(cx, Jsvalify(v), 0); +} + +JSBool +js_GetAnyName(JSContext *cx, jsid *idp) +{ + JSObject *global = cx->hasfp() ? cx->fp()->scopeChain().getGlobal() : cx->globalObject; + Value v = global->getReservedSlot(JSProto_AnyName); + if (v.isUndefined()) { + JSObject *obj = NewNonFunction(cx, &js_AnyNameClass, NULL, global); + if (!obj) + return false; + + JS_ASSERT(!obj->getProto()); + + JSRuntime *rt = cx->runtime; + InitXMLQName(obj, rt->emptyString, rt->emptyString, + ATOM_TO_STRING(rt->atomState.starAtom)); + METER(xml_stats.qname); + + v.setObject(*obj); + if (!js_SetReservedSlot(cx, global, JSProto_AnyName, v)) + return false; + } + *idp = OBJECT_TO_JSID(&v.toObject()); + return true; +} + +JSBool +js_FindXMLProperty(JSContext *cx, const Value &nameval, JSObject **objp, jsid *idp) +{ + JSObject *nameobj; + jsval v; + JSObject *qn; + jsid funid; + JSObject *obj, *target, *proto, *pobj; + JSXML *xml; + JSBool found; + JSProperty *prop; + + JS_ASSERT(nameval.isObject()); + nameobj = &nameval.toObject(); + if (nameobj->getClass() == &js_AnyNameClass) { + v = ATOM_TO_JSVAL(cx->runtime->atomState.starAtom); + nameobj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1, + Valueify(&v)); + if (!nameobj) + return JS_FALSE; + } else { + JS_ASSERT(nameobj->getClass() == &js_AttributeNameClass || + nameobj->getClass() == &js_QNameClass); + } + + qn = nameobj; + if (!IsFunctionQName(cx, qn, &funid)) + return JS_FALSE; + + obj = &js_GetTopStackFrame(cx)->scopeChain(); + do { + /* Skip any With object that can wrap XML. */ + target = obj; + while (target->getClass() == &js_WithClass) { + proto = target->getProto(); + if (!proto) + break; + target = proto; + } + + if (target->isXML()) { + if (JSID_IS_VOID(funid)) { + xml = (JSXML *) target->getPrivate(); + found = HasNamedProperty(xml, qn); + } else { + if (!HasFunctionProperty(cx, target, funid, &found)) + return JS_FALSE; + } + if (found) { + *idp = OBJECT_TO_JSID(nameobj); + *objp = target; + return JS_TRUE; + } + } else if (!JSID_IS_VOID(funid)) { + if (!target->lookupProperty(cx, funid, &pobj, &prop)) + return JS_FALSE; + if (prop) { + *idp = funid; + *objp = target; + return JS_TRUE; + } + } + } while ((obj = obj->getParent()) != NULL); + + JSAutoByteString printable; + JSString *str = ConvertQNameToString(cx, nameobj); + if (str && js_ValueToPrintable(cx, StringValue(str), &printable)) { + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, + JSMSG_UNDEFINED_XML_NAME, printable.ptr()); + } + return JS_FALSE; +} + +static JSBool +GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +{ + JS_ASSERT(obj->isXML()); + + /* + * See comments before xml_lookupProperty about the need for the proto + * chain lookup. + */ + JSObject *target = obj; + AutoObjectRooter tvr(cx); + for (;;) { + if (!js_GetProperty(cx, target, id, Valueify(vp))) + return false; + if (VALUE_IS_FUNCTION(cx, *vp)) + return true; + target = target->getProto(); + if (target == NULL || !target->isNative()) + break; + tvr.setObject(target); + } + + JSXML *xml = (JSXML *) obj->getPrivate(); + if (!HasSimpleContent(xml)) + return true; + + /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */ + if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr())) + return false; + + JS_ASSERT(tvr.object()); + return tvr.object()->getProperty(cx, id, Valueify(vp)); +} + +static JSXML * +GetPrivate(JSContext *cx, JSObject *obj, const char *method) +{ + JSXML *xml; + + xml = (JSXML *) GetInstancePrivate(cx, obj, &js_XMLClass, NULL); + if (!xml) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_METHOD, + js_XML_str, method, obj->getClass()->name); + } + return xml; +} + +JSBool +js_GetXMLDescendants(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + JSXML *xml, *list; + + xml = GetPrivate(cx, obj, "descendants internal method"); + if (!xml) + return JS_FALSE; + + list = Descendants(cx, xml, id); + if (!list) + return JS_FALSE; + *vp = OBJECT_TO_JSVAL(list->object); + return JS_TRUE; +} + +JSBool +js_DeleteXMLListElements(JSContext *cx, JSObject *listobj) +{ + JSXML *list; + uint32 n; + + list = (JSXML *) listobj->getPrivate(); + for (n = list->xml_kids.length; n != 0; --n) + DeleteListElement(cx, list, 0); + + return JS_TRUE; +} + +struct JSXMLFilter +{ + JSXML *list; + JSXML *result; + JSXML *kid; + JSXMLArrayCursor cursor; + + JSXMLFilter(JSXML *list, JSXMLArray *array) + : list(list), result(NULL), kid(NULL), cursor(array) {} + + ~JSXMLFilter() {} +}; + +static void +xmlfilter_trace(JSTracer *trc, JSObject *obj) +{ + JSXMLFilter *filter = (JSXMLFilter *) obj->getPrivate(); + if (!filter) + return; + + JS_ASSERT(filter->list); + JS_CALL_TRACER(trc, filter->list, JSTRACE_XML, "list"); + if (filter->result) + JS_CALL_TRACER(trc, filter->result, JSTRACE_XML, "result"); + if (filter->kid) + JS_CALL_TRACER(trc, filter->kid, JSTRACE_XML, "kid"); + + /* + * We do not need to trace the cursor as that would be done when + * tracing the filter->list. + */ +} + +static void +xmlfilter_finalize(JSContext *cx, JSObject *obj) +{ + JSXMLFilter *filter = (JSXMLFilter *) obj->getPrivate(); + if (!filter) + return; + + cx->destroy(filter); +} + +Class js_XMLFilterClass = { + "XMLFilter", + JSCLASS_HAS_PRIVATE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE, + PropertyStub, /* addProperty */ + PropertyStub, /* delProperty */ + PropertyStub, /* getProperty */ + StrictPropertyStub, /* setProperty */ + EnumerateStub, + ResolveStub, + ConvertStub, + xmlfilter_finalize, + NULL, /* reserved0 */ + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* xdrObject */ + NULL, /* hasInstance */ + JS_CLASS_TRACE(xmlfilter_trace) +}; + +JSBool +js_StepXMLListFilter(JSContext *cx, JSBool initialized) +{ + jsval *sp; + JSObject *obj, *filterobj, *resobj, *kidobj; + JSXML *xml, *list; + JSXMLFilter *filter; + + LeaveTrace(cx); + sp = Jsvalify(cx->regs->sp); + if (!initialized) { + /* + * We haven't iterated yet, so initialize the filter based on the + * value stored in sp[-2]. + */ + if (!VALUE_IS_XML(sp[-2])) { + js_ReportValueError(cx, JSMSG_NON_XML_FILTER, -2, Valueify(sp[-2]), NULL); + return JS_FALSE; + } + obj = JSVAL_TO_OBJECT(sp[-2]); + xml = (JSXML *) obj->getPrivate(); + + if (xml->xml_class == JSXML_CLASS_LIST) { + list = xml; + } else { + obj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!obj) + return JS_FALSE; + + /* + * Root just-created obj. sp[-2] cannot be used yet for rooting + * as it may be the only root holding xml. + */ + sp[-1] = OBJECT_TO_JSVAL(obj); + list = (JSXML *) obj->getPrivate(); + if (!Append(cx, list, xml)) + return JS_FALSE; + } + + filterobj = NewNonFunction(cx, &js_XMLFilterClass, NULL, NULL); + if (!filterobj) + return JS_FALSE; + + /* + * Init all filter fields before setPrivate exposes it to + * xmlfilter_trace or xmlfilter_finalize. + */ + filter = cx->create(list, &list->xml_kids); + if (!filter) + return JS_FALSE; + filterobj->setPrivate(filter); + + /* Store filterobj to use in the later iterations. */ + sp[-2] = OBJECT_TO_JSVAL(filterobj); + + resobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); + if (!resobj) + return JS_FALSE; + + /* This also roots resobj. */ + filter->result = (JSXML *) resobj->getPrivate(); + } else { + /* We have iterated at least once. */ + JS_ASSERT(!JSVAL_IS_PRIMITIVE(sp[-2])); + JS_ASSERT(JSVAL_TO_OBJECT(sp[-2])->getClass() == &js_XMLFilterClass); + filter = (JSXMLFilter *) JSVAL_TO_OBJECT(sp[-2])->getPrivate(); + JS_ASSERT(filter->kid); + + /* Check if the filter expression wants to append the element. */ + if (js_ValueToBoolean(Valueify(sp[-1])) && + !Append(cx, filter->result, filter->kid)) { + return JS_FALSE; + } + } + + /* Do the iteration. */ + filter->kid = (JSXML *) filter->cursor.getNext(); + if (!filter->kid) { + /* + * Do not defer finishing the cursor until the next GC cycle to avoid + * accumulation of dead cursors associated with filter->list. + */ + filter->cursor.disconnect(); + JS_ASSERT(filter->result->object); + sp[-2] = OBJECT_TO_JSVAL(filter->result->object); + kidobj = NULL; + } else { + kidobj = js_GetXMLObject(cx, filter->kid); + if (!kidobj) + return JS_FALSE; + } + + /* Null as kidobj at sp[-1] signals filter termination. */ + sp[-1] = OBJECT_TO_JSVAL(kidobj); + return JS_TRUE; +} + +JSObject * +js_ValueToXMLObject(JSContext *cx, const Value &v) +{ + return ToXML(cx, Jsvalify(v)); +} + +JSObject * +js_ValueToXMLListObject(JSContext *cx, const Value &v) +{ + return ToXMLList(cx, Jsvalify(v)); +} + +JSObject * +js_NewXMLSpecialObject(JSContext *cx, JSXMLClass xml_class, JSString *name, + JSString *value) +{ + uintN flags; + JSObject *obj; + JSXML *xml; + JSObject *qn; + + if (!GetXMLSettingFlags(cx, &flags)) + return NULL; + + if ((xml_class == JSXML_CLASS_COMMENT && + (flags & XSF_IGNORE_COMMENTS)) || + (xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION && + (flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS))) { + return js_NewXMLObject(cx, JSXML_CLASS_TEXT); + } + + obj = js_NewXMLObject(cx, xml_class); + if (!obj) + return NULL; + xml = (JSXML *) obj->getPrivate(); + if (name) { + JSLinearString *linearName = name->ensureLinear(cx); + if (!linearName) + return NULL; + qn = NewXMLQName(cx, cx->runtime->emptyString, NULL, linearName); + if (!qn) + return NULL; + xml->name = qn; + } + xml->xml_value = value; + return obj; +} + +JSString * +js_MakeXMLCDATAString(JSContext *cx, JSString *str) +{ + StringBuffer sb(cx); + return MakeXMLCDATAString(cx, sb, str); +} + +JSString * +js_MakeXMLCommentString(JSContext *cx, JSString *str) +{ + StringBuffer sb(cx); + return MakeXMLCommentString(cx, sb, str); +} + +JSString * +js_MakeXMLPIString(JSContext *cx, JSString *name, JSString *str) +{ + StringBuffer sb(cx); + return MakeXMLPIString(cx, sb, name, str); +} + +#endif /* JS_HAS_XML_SUPPORT */ diff --git a/js/src/jsxml.h b/js/src/jsxml.h new file mode 100644 index 0000000..566ec5d --- /dev/null +++ b/js/src/jsxml.h @@ -0,0 +1,374 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey E4X code, released August, 2004. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsxml_h___ +#define jsxml_h___ + +#include "jspubtd.h" +#include "jsobj.h" +#include "jscell.h" + +extern const char js_AnyName_str[]; +extern const char js_AttributeName_str[]; +extern const char js_isXMLName_str[]; +extern const char js_XMLList_str[]; + +extern const char js_amp_entity_str[]; +extern const char js_gt_entity_str[]; +extern const char js_lt_entity_str[]; +extern const char js_quot_entity_str[]; + +typedef JSBool +(* JSIdentityOp)(const void *a, const void *b); + +struct JSXMLArray { + uint32 length; + uint32 capacity; + void **vector; + JSXMLArrayCursor *cursors; + + void init() { + length = capacity = 0; + vector = NULL; + cursors = NULL; + } + + void finish(JSContext *cx); + + bool setCapacity(JSContext *cx, uint32 capacity); + void trim(); +}; + +struct JSXMLArrayCursor +{ + JSXMLArray *array; + uint32 index; + JSXMLArrayCursor *next; + JSXMLArrayCursor **prevp; + void *root; + + JSXMLArrayCursor(JSXMLArray *array) + : array(array), index(0), next(array->cursors), prevp(&array->cursors), + root(NULL) + { + if (next) + next->prevp = &next; + array->cursors = this; + } + + ~JSXMLArrayCursor() { disconnect(); } + + void disconnect() { + if (!array) + return; + if (next) + next->prevp = prevp; + *prevp = next; + array = NULL; + } + + void *getNext() { + if (!array || index >= array->length) + return NULL; + return root = array->vector[index++]; + } + + void *getCurrent() { + if (!array || index >= array->length) + return NULL; + return root = array->vector[index]; + } + + void trace(JSTracer *trc); +}; + +#define JSXML_PRESET_CAPACITY JS_BIT(31) +#define JSXML_CAPACITY_MASK JS_BITMASK(31) +#define JSXML_CAPACITY(array) ((array)->capacity & JSXML_CAPACITY_MASK) + +/* + * NB: don't reorder this enum without changing all array initializers that + * depend on it in jsxml.c. + */ +typedef enum JSXMLClass { + JSXML_CLASS_LIST, + JSXML_CLASS_ELEMENT, + JSXML_CLASS_ATTRIBUTE, + JSXML_CLASS_PROCESSING_INSTRUCTION, + JSXML_CLASS_TEXT, + JSXML_CLASS_COMMENT, + JSXML_CLASS_LIMIT +} JSXMLClass; + +#define JSXML_CLASS_HAS_KIDS(class_) ((class_) < JSXML_CLASS_ATTRIBUTE) +#define JSXML_CLASS_HAS_VALUE(class_) ((class_) >= JSXML_CLASS_ATTRIBUTE) +#define JSXML_CLASS_HAS_NAME(class_) \ + ((uintN)((class_) - JSXML_CLASS_ELEMENT) <= \ + (uintN)(JSXML_CLASS_PROCESSING_INSTRUCTION - JSXML_CLASS_ELEMENT)) + +#ifdef DEBUG_notme +#include "jsclist.h" +#endif + +typedef struct JSXMLListVar { + JSXMLArray kids; /* NB: must come first */ + JSXML *target; + JSObject *targetprop; +} JSXMLListVar; + +typedef struct JSXMLElemVar { + JSXMLArray kids; /* NB: must come first */ + JSXMLArray namespaces; + JSXMLArray attrs; +} JSXMLElemVar; + +/* union member shorthands */ +#define xml_kids u.list.kids +#define xml_target u.list.target +#define xml_targetprop u.list.targetprop +#define xml_namespaces u.elem.namespaces +#define xml_attrs u.elem.attrs +#define xml_value u.value + +/* xml_class-testing macros */ +#define JSXML_HAS_KIDS(xml) JSXML_CLASS_HAS_KIDS((xml)->xml_class) +#define JSXML_HAS_VALUE(xml) JSXML_CLASS_HAS_VALUE((xml)->xml_class) +#define JSXML_HAS_NAME(xml) JSXML_CLASS_HAS_NAME((xml)->xml_class) +#define JSXML_LENGTH(xml) (JSXML_CLASS_HAS_KIDS((xml)->xml_class) \ + ? (xml)->xml_kids.length \ + : 0) + +struct JSXML : js::gc::Cell { +#ifdef DEBUG_notme + JSCList links; + uint32 serial; +#endif + JSObject *object; + void *domnode; /* DOM node if mapped info item */ + JSXML *parent; + JSObject *name; + uint32 xml_class; /* discriminates u, below */ + uint32 xml_flags; /* flags, see below */ + union { + JSXMLListVar list; + JSXMLElemVar elem; + JSString *value; + } u; + + void finalize(JSContext *cx) { + if (JSXML_HAS_KIDS(this)) { + xml_kids.finish(cx); + if (xml_class == JSXML_CLASS_ELEMENT) { + xml_namespaces.finish(cx); + xml_attrs.finish(cx); + } + } +#ifdef DEBUG_notme + JS_REMOVE_LINK(&links); +#endif + } +}; + +/* xml_flags values */ +#define XMLF_WHITESPACE_TEXT 0x1 + +extern JSXML * +js_NewXML(JSContext *cx, JSXMLClass xml_class); + +extern void +js_TraceXML(JSTracer *trc, JSXML *xml); + +extern JSObject * +js_NewXMLObject(JSContext *cx, JSXMLClass xml_class); + +extern JSObject * +js_GetXMLObject(JSContext *cx, JSXML *xml); + +extern JS_FRIEND_DATA(js::Class) js_XMLClass; +extern JS_FRIEND_DATA(js::Class) js_NamespaceClass; +extern JS_FRIEND_DATA(js::Class) js_QNameClass; +extern JS_FRIEND_DATA(js::Class) js_AttributeNameClass; +extern JS_FRIEND_DATA(js::Class) js_AnyNameClass; +extern js::Class js_XMLFilterClass; + +/* + * Methods to test whether an object or a value is of type "xml" (per typeof). + */ +inline bool +JSObject::isXML() const +{ + return getClass() == &js_XMLClass; +} + +inline bool +JSObject::isXMLId() const +{ + js::Class *clasp = getClass(); + return clasp == &js_QNameClass || + clasp == &js_AttributeNameClass || + clasp == &js_AnyNameClass; +} + +#define VALUE_IS_XML(v) (!JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isXML()) + +inline bool +JSObject::isNamespace() const +{ + return getClass() == &js_NamespaceClass; +} + +inline bool +JSObject::isQName() const +{ + js::Class* clasp = getClass(); + return clasp == &js_QNameClass || + clasp == &js_AttributeNameClass || + clasp == &js_AnyNameClass; +} + +static inline bool +IsXML(const js::Value &v) +{ + return v.isObject() && v.toObject().isXML(); +} + +extern JSObject * +js_InitNamespaceClass(JSContext *cx, JSObject *obj); + +extern JSObject * +js_InitQNameClass(JSContext *cx, JSObject *obj); + +extern JSObject * +js_InitXMLClass(JSContext *cx, JSObject *obj); + +extern JSObject * +js_InitXMLClasses(JSContext *cx, JSObject *obj); + +extern JSBool +js_GetFunctionNamespace(JSContext *cx, js::Value *vp); + +/* + * If obj is QName corresponding to function::name, set *funidp to name's id, + * otherwise set *funidp to void. + */ +JSBool +js_IsFunctionQName(JSContext *cx, JSObject *obj, jsid *funidp); + +extern JSBool +js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp); + +extern JSBool +js_SetDefaultXMLNamespace(JSContext *cx, const js::Value &v); + +/* + * Return true if v is a XML QName object, or if it converts to a string that + * contains a valid XML qualified name (one containing no :), false otherwise. + * NB: This function is an infallible predicate, it hides exceptions. + */ +extern JSBool +js_IsXMLName(JSContext *cx, jsval v); + +extern JSBool +js_ToAttributeName(JSContext *cx, js::Value *vp); + +extern JSFlatString * +js_EscapeAttributeValue(JSContext *cx, JSString *str, JSBool quote); + +extern JSString * +js_AddAttributePart(JSContext *cx, JSBool isName, JSString *str, + JSString *str2); + +extern JSFlatString * +js_EscapeElementValue(JSContext *cx, JSString *str); + +extern JSString * +js_ValueToXMLString(JSContext *cx, const js::Value &v); + +extern JSObject * +js_ConstructXMLQNameObject(JSContext *cx, const js::Value & nsval, + const js::Value & lnval); + +extern JSBool +js_GetAnyName(JSContext *cx, jsid *idp); + +/* + * Note: nameval must be either QName, AttributeName, or AnyName. + */ +extern JSBool +js_FindXMLProperty(JSContext *cx, const js::Value &nameval, JSObject **objp, jsid *idp); + +extern JSBool +js_GetXMLMethod(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); + +extern JSBool +js_GetXMLDescendants(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + +extern JSBool +js_DeleteXMLListElements(JSContext *cx, JSObject *listobj); + +extern JSBool +js_StepXMLListFilter(JSContext *cx, JSBool initialized); + +extern JSObject * +js_ValueToXMLObject(JSContext *cx, const js::Value &v); + +extern JSObject * +js_ValueToXMLListObject(JSContext *cx, const js::Value &v); + +extern JSObject * +js_NewXMLSpecialObject(JSContext *cx, JSXMLClass xml_class, JSString *name, + JSString *value); + +extern JSString * +js_MakeXMLCDATAString(JSContext *cx, JSString *str); + +extern JSString * +js_MakeXMLCommentString(JSContext *cx, JSString *str); + +extern JSString * +js_MakeXMLPIString(JSContext *cx, JSString *name, JSString *str); + +/* The caller must ensure that either v1 or v2 is an object. */ +extern JSBool +js_TestXMLEquality(JSContext *cx, const js::Value &v1, const js::Value &v2, + JSBool *bp); + +extern JSBool +js_ConcatenateXML(JSContext *cx, JSObject *obj1, JSObject *obj2, js::Value *vp); + +#endif /* jsxml_h___ */ diff --git a/js/src/lirasm/LInsClasses.tbl b/js/src/lirasm/LInsClasses.tbl new file mode 100644 index 0000000..a198788 --- /dev/null +++ b/js/src/lirasm/LInsClasses.tbl @@ -0,0 +1,135 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=0 ft=c: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey nanojit. + * + * The Initial Developer of the Original Code is + * the Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Nicholas Nethercote + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* LIns classes, as required for --random mode. Includers must define a CL___ + * macro of the following form: + * + * #define CL___(name, only64bit, relFreq) ... + * + * Selected arguments can be used within the macro expansions. + * + * Field Description + * ----- ----------- + * name Name of the instruction class. The types are B (boolean), I + * (32-bit integer), Q (64-bit integer), F (64-bit float), N + * (null). A name of the form LOP_Z_XY means that it takes + * arguments of type X and Y and produces a result of type Z. + * + * relFreq We weight each class differently, so that some classes are more + * common than others. This field gives the relative frequency of + * the instruction class. All the relFreqs together can sum up to + * any number, but it's easier to think about if the sum is a + * round number. (That's why the relFreqs add up to 100%; the + * running total is shown in comments.) The sum also shouldn't be + * too big, as we generate a table with that many elements in it. + * + * Note that we want a decent number of value sinks (eg. + * stores, calls, guards) and not too many value sources (eg. + * immediates, loads) so that the amount of dead code generated is + * reasonable. + * + * Because certain opcode classes aren't supported on all platforms, CLxyz must be one + * of the following: + * + * CL___: for opcode classes supported on all platforms. + * CL_64: for opcode classes supported only on 64-bit platforms. + */ + +#ifdef NANOJIT_64BIT +# define CL_64(a, b) CL___(a, b) +#else +# define CL_64(a, b) +#endif + + +CL___( LFENCE, 1) // 1% LIR_regfence, LIR_xbarrier + +CL___( LALLOC, 1) // 2% LIR_alloc + +CL___( LIMM_I, 4) // 6% LIR_imm +CL_64( LIMM_Q, 3) // 9% LIR_quad +CL___( LIMM_D, 3) // 12% LIR_float + +CL___( LOP_I_I, 2) // 14% LIR_neg, LIR_not +CL_64( LOP_Q_Q, 0) // 14% (none) +CL___( LOP_D_D, 2) // 16% LIR_fneg + +CL___( LOP_I_II, 6) // 32% LIR_add, LIR_and, LIR_eq, etc. +CL_64( LOP_Q_QQ, 7) // 39% LIR_qiadd, LIR_qiand, LIR_qeq, etc. +CL_64( LOP_Q_QI, 2) // 41% LIR_qilsh, LIR_qirsh, LIR_qursh +CL___( LOP_D_DD, 0) // 51% LIR_fadd, etc. + +// cmov has a low weight because is also used with LIR_div/LIR_mod. +CL___( LOP_I_BII, 1) // 52% LIR_cmovi +CL_64( LOP_Q_BQQ, 1) // 53% LIR_cmovq +CL___( LOP_D_BDD, 1) // 54% LIR_cmovd + +CL___( LOP_B_II, 3) // 57% LIR_eq, LIR_lt, etc +CL_64( LOP_B_QQ, 3) // 60% LIR_qeq, LIR_qlt, etc +CL___( LOP_B_DD, 3) // 63% LIR_feq, LIR_flt, etc + +CL_64( LOP_Q_I, 1) // 64% LIR_i2q, LIR_u2q +CL___( LOP_D_I, 1) // 65% LIR_i2f, LIR_u2f +CL_64( LOP_I_Q, 1) // 66% LIR_q2i +CL___( LOP_I_D, 1) // 67% LIR_qlo, LIR_qhi, LIR_f2i +CL_64( LOP_Q_D, 1) // 68% LIR_dasq +CL_64( LOP_D_Q, 1) // 69% LIR_qasd +CL___( LOP_D_II, 1) // 70% LIR_qjoin + +CL___( LLD_I, 3) // 73% LIR_ld, LIR_ldc, LIR_ld*b, LIR_ld*s +CL_64( LLD_Q, 2) // 75% LIR_ldq, LIR_ldqc +CL___( LLD_D, 3) // 78% LIR_ldf, LIR_ldfc + +CL___( LST_I, 5) // 83% LIR_sti +CL_64( LST_Q, 4) // 87% LIR_stqi +CL___( LST_D, 5) // 92% LIR_stfi + +CL___( LCALL_I_I1, 1) // 93% LIR_icall +CL___( LCALL_I_I6, 1) // 94% LIR_icall +CL_64( LCALL_Q_Q2, 1) // 95% LIR_qcall +CL_64( LCALL_Q_Q7, 1) // 96% LIR_qcall +CL___( LCALL_D_D3, 1) // 97% LIR_fcall +CL___( LCALL_D_D8, 1) // 98% LIR_fcall +CL_64( LCALL_V_IQD, 1) // 99% LIR_icall or LIR_qcall + +CL___( LLABEL, 1) //100% LIR_label + + +#undef CL_64 diff --git a/js/src/lirasm/Makefile.in b/js/src/lirasm/Makefile.in new file mode 100644 index 0000000..5614c71 --- /dev/null +++ b/js/src/lirasm/Makefile.in @@ -0,0 +1,79 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Spidermonkey build system. +# +# The Initial Developer of the Original Code is +# The Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Ted Mielczarek +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ + +VPATH = $(srcdir) +VPATH += $(srcdir)/../nanojit + +include $(DEPTH)/config/autoconf.mk + +PROGRAM = lirasm$(BIN_SUFFIX) +CPPSRCS = lirasm.cpp \ + Assembler.cpp \ + Allocator.cpp \ + CodeAlloc.cpp \ + Containers.cpp \ + Fragmento.cpp \ + LIR.cpp \ + RegAlloc.cpp \ + avmplus.cpp \ + Native$(NANOJIT_ARCH).cpp \ + njconfig.cpp \ + VMPI.cpp \ + $(NULL) + + +LOCAL_INCLUDES += -I$(topsrcdir) -I.. + +include $(topsrcdir)/config/rules.mk + +ifdef _MSC_VER +ifdef WINCE +WIN32_EXE_LDFLAGS += -ENTRY:mainACRTStartup +endif +CFLAGS += -EHsc +CXXFLAGS += -EHsc +endif + +check:: $(PROGRAM) + $(srcdir)/testlirc.sh $(PROGRAM) + diff --git a/js/src/lirasm/lirasm.cpp b/js/src/lirasm/lirasm.cpp new file mode 100644 index 0000000..f9c0e57 --- /dev/null +++ b/js/src/lirasm/lirasm.cpp @@ -0,0 +1,2466 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is LIR Assembler code, released 2009. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Graydon Hoare + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef AVMPLUS_UNIX +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include "nanojit/nanojit.h" + +using namespace nanojit; +using namespace std; + +/* Allocator SPI implementation. */ + +void* +nanojit::Allocator::allocChunk(size_t nbytes, bool /*fallible*/) +{ + void *p = malloc(nbytes); + if (!p) + exit(1); + return p; +} + +void +nanojit::Allocator::freeChunk(void *p) { + free(p); +} + +void +nanojit::Allocator::postReset() { +} + + +struct LasmSideExit : public SideExit { + size_t line; +}; + + +/* LIR SPI implementation */ + +int +nanojit::StackFilter::getTop(LIns*) +{ + return 0; +} + +// We lump everything into a single access region for lirasm. +static const AccSet ACCSET_OTHER = (1 << 0); +static const uint8_t LIRASM_NUM_USED_ACCS = 1; + +#if defined NJ_VERBOSE +void +nanojit::LInsPrinter::formatGuard(InsBuf *buf, LIns *ins) +{ + RefBuf b1, b2; + LasmSideExit *x = (LasmSideExit *)ins->record()->exit; + VMPI_snprintf(buf->buf, buf->len, + "%s: %s %s -> line=%ld (GuardID=%03d)", + formatRef(&b1, ins), + lirNames[ins->opcode()], + ins->oprnd1() ? formatRef(&b2, ins->oprnd1()) : "", + (long)x->line, + ins->record()->profGuardID); +} + +void +nanojit::LInsPrinter::formatGuardXov(InsBuf *buf, LIns *ins) +{ + RefBuf b1, b2, b3; + LasmSideExit *x = (LasmSideExit *)ins->record()->exit; + VMPI_snprintf(buf->buf, buf->len, + "%s = %s %s, %s -> line=%ld (GuardID=%03d)", + formatRef(&b1, ins), + lirNames[ins->opcode()], + formatRef(&b2, ins->oprnd1()), + formatRef(&b3, ins->oprnd2()), + (long)x->line, + ins->record()->profGuardID); +} + +const char* +nanojit::LInsPrinter::accNames[] = { + "o", // (1 << 0) == ACCSET_OTHER + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 1..10 (unused) + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 11..20 (unused) + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 21..30 (unused) + "?" // 31 (unused) +}; +#endif + +#ifdef DEBUG +void ValidateWriter::checkAccSet(LOpcode op, LIns* base, int32_t disp, AccSet accSet) +{ + (void)op; + (void)base; + (void)disp; + NanoAssert(accSet == ACCSET_OTHER); +} +#endif + +typedef int32_t (FASTCALL *RetInt)(); +typedef int64_t (FASTCALL *RetQuad)(); +typedef double (FASTCALL *RetDouble)(); +typedef GuardRecord* (FASTCALL *RetGuard)(); + +struct Function { + const char *name; + struct nanojit::CallInfo callInfo; +}; + +enum ReturnType { + RT_INT = 1, +#ifdef NANOJIT_64BIT + RT_QUAD = 2, +#endif + RT_DOUBLE = 4, + RT_GUARD = 8 +}; + +#ifdef DEBUG +#define DEBUG_ONLY_NAME(name) ,#name +#else +#define DEBUG_ONLY_NAME(name) +#endif + +#define CI(name, args) \ + {(uintptr_t) (&name), args, nanojit::ABI_CDECL, /*isPure*/0, ACCSET_STORE_ANY \ + DEBUG_ONLY_NAME(name)} + +#define FN(name, args) \ + {#name, CI(name, args)} + +enum LirTokenType { + NAME, NUMBER, PUNCT, NEWLINE +}; + +struct LirToken { + LirTokenType type; + string data; + int lineno; +}; + +inline bool +startsWith(const string &s, const string &prefix) +{ + return s.size() >= prefix.size() && s.compare(0, prefix.length(), prefix) == 0; +} + +// LIR files must be ASCII, for simplicity. +class LirTokenStream { +public: + LirTokenStream(istream &in) : mIn(in), mLineno(0) {} + + bool get(LirToken &token) { + if (mLine.empty()) { + if (!getline(mIn, mLine)) + return false; + mLine += '\n'; + mLineno++; + } + mLine.erase(0, mLine.find_first_not_of(" \t\v\r")); + char c = mLine[0]; + size_t e = mLine.find_first_not_of("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$.+-"); + if (startsWith(mLine, "->")) { + mLine.erase(0, 2); + token.type = PUNCT; + token.data = "->"; + } else if (e > 0) { + string s = mLine.substr(0, e); + mLine.erase(0, e); + if (e > 1 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) + token.type = NUMBER; + else if (isdigit(s[0]) || (e > 1 && s[0] == '.' && isdigit(s[1]))) + token.type = NUMBER; + else + token.type = NAME; + token.data = s; + } else if (strchr(":,=[]()", c)) { + token.type = PUNCT; + token.data = c; + mLine.erase(0, 1); + } else if (c == ';' || c == '\n') { + token.type = NEWLINE; + token.data.clear(); + mLine.clear(); + } else { + cerr << "line " << mLineno << ": error: Unrecognized character in file." << endl; + return false; + } + + token.lineno = mLineno; + return true; + } + + bool eat(LirTokenType type, const char *exact = NULL) { + LirToken token; + return (get(token) && token.type == type && (exact == NULL || token.data == exact)); + } + + bool getName(string &name) { + LirToken t; + if (get(t) && t.type == NAME) { + name = t.data; + return true; + } + return false; + } + +private: + istream &mIn; + string mLine; + int mLineno; +}; + +class LirasmFragment { +public: + union { + RetInt rint; +#ifdef NANOJIT_64BIT + RetQuad rquad; +#endif + RetDouble rdouble; + RetGuard rguard; + }; + ReturnType mReturnType; + Fragment *fragptr; + map mLabels; +}; + +typedef map Fragments; + +class Lirasm { +public: + Lirasm(bool verbose); + ~Lirasm(); + + void assemble(istream &in, bool optimize); + void assembleRandom(int nIns, bool optimize); + bool lookupFunction(const string &name, CallInfo *&ci); + + LirBuffer *mLirbuf; + LogControl mLogc; + avmplus::AvmCore mCore; + Allocator mAlloc; + CodeAlloc mCodeAlloc; + bool mVerbose; + Fragments mFragments; + Assembler mAssm; + map mOpMap; + + void bad(const string &msg) { + cerr << "error: " << msg << endl; + exit(1); + } + +private: + void handlePatch(LirTokenStream &in); +}; + +class FragmentAssembler { +public: + FragmentAssembler(Lirasm &parent, const string &fragmentName, bool optimize); + ~FragmentAssembler(); + + void assembleFragment(LirTokenStream &in, + bool implicitBegin, + const LirToken *firstToken); + + void assembleRandomFragment(int nIns); + +private: + static uint32_t sProfId; + // Prohibit copying. + FragmentAssembler(const FragmentAssembler &); + FragmentAssembler & operator=(const FragmentAssembler &); + LasmSideExit *createSideExit(); + GuardRecord *createGuardRecord(LasmSideExit *exit); + + Lirasm &mParent; + const string mFragName; + Fragment *mFragment; + bool optimize; + vector mCallInfos; + map mLabels; + LirWriter *mLir; + LirBufWriter *mBufWriter; + LirWriter *mCseFilter; + LirWriter *mExprFilter; + LirWriter *mSoftFloatFilter; + LirWriter *mVerboseWriter; + LirWriter *mValidateWriter1; + LirWriter *mValidateWriter2; + multimap mFwdJumps; + + size_t mLineno; + LOpcode mOpcode; + size_t mOpcount; + + char mReturnTypeBits; + vector mTokens; + + void tokenizeLine(LirTokenStream &in, LirToken &token); + void need(size_t); + LIns *ref(const string &); + LIns *assemble_jump(bool isCond); + LIns *assemble_load(); + LIns *assemble_call(const string &); + LIns *assemble_ret(ReturnType rt); + LIns *assemble_guard(bool isCond); + LIns *assemble_guard_xov(); + LIns *assemble_jump_jov(); + void bad(const string &msg); + void nyi(const string &opname); + void extract_any_label(string &lab, char lab_delim); + void resolve_forward_jumps(string &lab, LIns *ins); + void endFragment(); +}; + +// 'sin' is overloaded on some platforms, so taking its address +// doesn't quite work. Provide a do-nothing function here +// that's not overloaded. +double sinFn(double d) { + return sin(d); +} +#define sin sinFn + +double calld1(double x, double i, double y, double l, double x1, double i1, double y1, double l1) { + return x + i * y - l + x1 / i1 - y1 * l1; +} + +// The calling tests with mixed argument types are sensible for all platforms, but they highlight +// the differences between the supported ABIs on ARM. + +double callid1(int i, double x, double y, int j, int k, double z) { + return (x + y + z) / (double)(i + j + k); +} + +double callid2(int i, int j, int k, double x) { + return x / (double)(i + j + k); +} + +double callid3(int i, int j, double x, int k, double y, double z) { + return (x + y + z) / (double)(i + j + k); +} + +// Simple print function for testing void calls. +void printi(int x) { + cout << x << endl; +} + +Function functions[] = { + FN(puts, CallInfo::typeSig1(ARGTYPE_I, ARGTYPE_P)), + FN(sin, CallInfo::typeSig1(ARGTYPE_D, ARGTYPE_D)), + FN(malloc, CallInfo::typeSig1(ARGTYPE_P, ARGTYPE_P)), + FN(free, CallInfo::typeSig1(ARGTYPE_V, ARGTYPE_P)), + FN(calld1, CallInfo::typeSig8(ARGTYPE_D, ARGTYPE_D, ARGTYPE_D, ARGTYPE_D, + ARGTYPE_D, ARGTYPE_D, ARGTYPE_D, ARGTYPE_D, ARGTYPE_D)), + FN(callid1, CallInfo::typeSig6(ARGTYPE_D, ARGTYPE_I, ARGTYPE_D, ARGTYPE_D, + ARGTYPE_I, ARGTYPE_I, ARGTYPE_D)), + FN(callid2, CallInfo::typeSig4(ARGTYPE_D, ARGTYPE_I, ARGTYPE_I, ARGTYPE_I, ARGTYPE_D)), + FN(callid3, CallInfo::typeSig6(ARGTYPE_D, ARGTYPE_I, ARGTYPE_I, ARGTYPE_D, + ARGTYPE_I, ARGTYPE_D, ARGTYPE_D)), + FN(printi, CallInfo::typeSig1(ARGTYPE_V, ARGTYPE_I)), +}; + +template out +lexical_cast(in arg) +{ + stringstream tmp; + out ret; + if ((tmp << arg && tmp >> ret && tmp.eof())) + return ret; + cerr << "bad lexical cast from " << arg << endl; + exit(1); +} + +int32_t +immI(const string &s) +{ + stringstream tmp(s); + int32_t ret; + if ((s.find("0x") == 0 || s.find("0X") == 0) && + (tmp >> hex >> ret && tmp.eof())) { + return ret; + } + return lexical_cast(s); +} + +uint64_t +immQ(const string &s) +{ + stringstream tmp(s); + uint64_t ret; + if ((s.find("0x") == 0 || s.find("0X") == 0) && + (tmp >> hex >> ret && tmp.eof())) { + return ret; + } + return lexical_cast(s); +} + +double +immD(const string &s) +{ + return lexical_cast(s); +} + +template t +pop_front(vector &vec) +{ + if (vec.empty()) { + cerr << "pop_front of empty vector" << endl; + exit(1); + } + t tmp = vec[0]; + vec.erase(vec.begin()); + return tmp; +} + +void +dep_u8(char *&buf, uint8_t byte, uint32_t &cksum) +{ + sprintf(buf, "%2.2X", byte); + cksum += byte; + buf += 2; +} + +void +dep_u32(char *&buf, uint32_t word, uint32_t &cksum) +{ + dep_u8(buf, (uint8_t)((word >> 24) & 0xff), cksum); + dep_u8(buf, (uint8_t)((word >> 16) & 0xff), cksum); + dep_u8(buf, (uint8_t)((word >> 8) & 0xff), cksum); + dep_u8(buf, (uint8_t)((word) & 0xff), cksum); +} + +void +dump_srecords(ostream &, Fragment *) +{ + // FIXME: Disabled until we work out a sane way to walk through + // code chunks under the new CodeAlloc regime. +/* + // Write S-records. Can only do 4-byte addresses at the moment. + + // FIXME: this presently dumps out the entire set of code pages + // written-to, which means it often dumps *some* bytes on the last + // page that are not necessarily initialized at all; they're + // beyond the last instruction written. Fix this to terminate + // s-record writing early. + + assert(sizeof(uintptr_t) == 4); + for (Page *page = frag->pages(); page; page = page->next) { + size_t step = 32; + uintptr_t p0 = (uintptr_t) &(page->code); + for (uintptr_t p = p0; p < p0 + sizeof(page->code); p += step) { + char buf[1024]; + + // S-record type S3: 8-char / 4-byte address. + // + // +2 char code 'S3'. + // +2 char / 1 byte count of remaining bytes (37 = addr, payload, cksum). + // +8 char / 4 byte addr. + // --- + // +64 char / 32 byte payload. + // --- + // +2 char / 1 byte checksum. + + uint32_t cksum = 0; + size_t count = sizeof(p) + step + 1; + + sprintf(buf, "S3"); + + char *b = buf + 2; // 2 chars for the "S3" code. + + dep_u8(b, (uint8_t) count, cksum); // Count of data bytes + dep_u32(b, p, cksum); // Address of the data byte being emitted + uint8_t *c = (uint8_t*) p; + for (size_t i = 0; i < step; ++i) { // Actual object code being emitted + dep_u8(b, c[i], cksum); + } + dep_u8(b, (uint8_t)((~cksum) & 0xff), cksum); + out << string(buf) << endl; + } + } +*/ +} + + + +uint32_t +FragmentAssembler::sProfId = 0; + +FragmentAssembler::FragmentAssembler(Lirasm &parent, const string &fragmentName, bool optimize) + : mParent(parent), mFragName(fragmentName), optimize(optimize), + mBufWriter(NULL), mCseFilter(NULL), mExprFilter(NULL), mSoftFloatFilter(NULL), mVerboseWriter(NULL), + mValidateWriter1(NULL), mValidateWriter2(NULL) +{ + mFragment = new Fragment(NULL verbose_only(, (mParent.mLogc.lcbits & + nanojit::LC_FragProfile) ? + sProfId++ : 0)); + mFragment->lirbuf = mParent.mLirbuf; + mParent.mFragments[mFragName].fragptr = mFragment; + + mLir = mBufWriter = new LirBufWriter(mParent.mLirbuf, nanojit::AvmCore::config); +#ifdef DEBUG + if (optimize) { // don't re-validate if no optimization has taken place + mLir = mValidateWriter2 = + new ValidateWriter(mLir, mFragment->lirbuf->printer, "end of writer pipeline"); + } +#endif +#ifdef DEBUG + if (mParent.mVerbose) { + mLir = mVerboseWriter = new VerboseWriter(mParent.mAlloc, mLir, + mParent.mLirbuf->printer, + &mParent.mLogc); + } +#endif + if (optimize) { + mLir = mCseFilter = new CseFilter(mLir, LIRASM_NUM_USED_ACCS, mParent.mAlloc); + } +#if NJ_SOFTFLOAT_SUPPORTED + if (avmplus::AvmCore::config.soft_float) { + mLir = new SoftFloatFilter(mLir); + } +#endif + if (optimize) { + mLir = mExprFilter = new ExprFilter(mLir); + } +#ifdef DEBUG + mLir = mValidateWriter1 = + new ValidateWriter(mLir, mFragment->lirbuf->printer, "start of writer pipeline"); +#endif + + mReturnTypeBits = 0; + mLir->ins0(LIR_start); + for (int i = 0; i < nanojit::NumSavedRegs; ++i) + mLir->insParam(i, 1); + + mLineno = 0; +} + +FragmentAssembler::~FragmentAssembler() +{ + delete mValidateWriter1; + delete mValidateWriter2; + delete mVerboseWriter; + delete mExprFilter; + delete mSoftFloatFilter; + delete mCseFilter; + delete mBufWriter; +} + + +void +FragmentAssembler::bad(const string &msg) +{ + cerr << "line " << mLineno << ": " << msg << endl; + exit(1); +} + +void +FragmentAssembler::nyi(const string &opname) +{ + cerr << "line " << mLineno << ": '" << opname << "' not yet implemented, sorry" << endl; + exit(1); +} + +void +FragmentAssembler::need(size_t n) +{ + if (mTokens.size() != n) { + bad("need " + lexical_cast(n) + + " tokens, have " + lexical_cast(mTokens.size())); + } +} + +LIns * +FragmentAssembler::ref(const string &lab) +{ + if (mLabels.find(lab) == mLabels.end()) + bad("unknown label '" + lab + "'"); + return mLabels.find(lab)->second; +} + +LIns * +FragmentAssembler::assemble_jump(bool isCond) +{ + LIns *condition; + + if (isCond) { + need(2); + string cond = pop_front(mTokens); + condition = ref(cond); + } else { + need(1); + condition = NULL; + } + string name = pop_front(mTokens); + if (mLabels.find(name) != mLabels.end()) { + LIns *target = ref(name); + return mLir->insBranch(mOpcode, condition, target); + } else { + LIns *ins = mLir->insBranch(mOpcode, condition, NULL); +#ifdef __SUNPRO_CC + mFwdJumps.insert(make_pair(name, ins)); +#else + mFwdJumps.insert(make_pair(name, ins)); +#endif + return ins; + } +} + +LIns * +FragmentAssembler::assemble_load() +{ + // Support implicit immediate-as-second-operand modes + // since, unlike sti/stqi, no immediate-displacement + // load opcodes were defined in LIR. + need(2); + if (mTokens[1].find("0x") == 0 || + mTokens[1].find("0x") == 0 || + mTokens[1].find_first_of("0123456789") == 0) { + return mLir->insLoad(mOpcode, + ref(mTokens[0]), + immI(mTokens[1]), ACCSET_OTHER); + } + bad("immediate offset required for load"); + return NULL; // not reached +} + +LIns * +FragmentAssembler::assemble_call(const string &op) +{ + CallInfo *ci = new (mParent.mAlloc) CallInfo; + mCallInfos.push_back(ci); + LIns *args[MAXARGS]; + memset(&args[0], 0, sizeof(args)); + + // Assembler syntax for a call: + // + // call 0x1234 fastcall a b c + // + // requires at least 2 args, + // fn address immediate and ABI token. + + if (mTokens.size() < 2) + bad("need at least address and ABI code for " + op); + + string func = pop_front(mTokens); + string abi = pop_front(mTokens); + + AbiKind _abi = ABI_CDECL; + if (abi == "fastcall") + _abi = ABI_FASTCALL; + else if (abi == "stdcall") + _abi = ABI_STDCALL; + else if (abi == "thiscall") + _abi = ABI_THISCALL; + else if (abi == "cdecl") + _abi = ABI_CDECL; + else + bad("call abi name '" + abi + "'"); + + if (mTokens.size() > MAXARGS) + bad("too many args to " + op); + + bool isBuiltin = mParent.lookupFunction(func, ci); + if (isBuiltin) { + // Built-in: use its CallInfo. Also check (some) CallInfo details + // against those from the call site. + if (_abi != ci->_abi) + bad("invalid calling convention for " + func); + + size_t i; + for (i = 0; i < mTokens.size(); ++i) { + args[i] = ref(mTokens[mTokens.size() - (i+1)]); + } + if (i != ci->count_args()) + bad("wrong number of arguments for " + func); + + } else { + // User-defined function: infer CallInfo details (ABI, arg types, ret + // type) from the call site. + ci->_abi = _abi; + size_t argc = mTokens.size(); + ArgType argTypes[MAXARGS]; + for (size_t i = 0; i < argc; ++i) { + NanoAssert(i < MAXARGS); // should give a useful error msg if this fails + args[i] = ref(mTokens[mTokens.size() - (i+1)]); + if (args[i]->isD()) argTypes[i] = ARGTYPE_D; +#ifdef NANOJIT_64BIT + else if (args[i]->isQ()) argTypes[i] = ARGTYPE_Q; +#endif + else argTypes[i] = ARGTYPE_I; + } + + // Select return type from opcode. + ArgType retType = ARGTYPE_P; + if (mOpcode == LIR_callv) retType = ARGTYPE_V; + else if (mOpcode == LIR_calli) retType = ARGTYPE_I; +#ifdef NANOJIT_64BIT + else if (mOpcode == LIR_callq) retType = ARGTYPE_Q; +#endif + else if (mOpcode == LIR_calld) retType = ARGTYPE_D; + else nyi("callh"); + ci->_typesig = CallInfo::typeSigN(retType, argc, argTypes); + } + + return mLir->insCall(ci, args); +} + +LIns * +FragmentAssembler::assemble_ret(ReturnType rt) +{ + need(1); + mReturnTypeBits |= rt; + return mLir->ins1(mOpcode, ref(mTokens[0])); +} + +LasmSideExit* +FragmentAssembler::createSideExit() +{ + LasmSideExit* exit = new (mParent.mAlloc) LasmSideExit(); + memset(exit, 0, sizeof(LasmSideExit)); + exit->from = mFragment; + exit->target = NULL; + exit->line = mLineno; + return exit; +} + +GuardRecord* +FragmentAssembler::createGuardRecord(LasmSideExit *exit) +{ + GuardRecord *rec = new (mParent.mAlloc) GuardRecord; + memset(rec, 0, sizeof(GuardRecord)); + rec->exit = exit; + exit->addGuard(rec); + return rec; +} + +LIns * +FragmentAssembler::assemble_guard(bool isCond) +{ + GuardRecord* guard = createGuardRecord(createSideExit()); + + LIns *ins_cond; + if (isCond) { + need(1); + ins_cond = ref(pop_front(mTokens)); + } else { + need(0); + ins_cond = NULL; + } + + mReturnTypeBits |= RT_GUARD; + + if (!mTokens.empty()) + bad("too many arguments"); + + return mLir->insGuard(mOpcode, ins_cond, guard); +} + +LIns* +FragmentAssembler::assemble_guard_xov() +{ + GuardRecord* guard = createGuardRecord(createSideExit()); + + need(2); + + mReturnTypeBits |= RT_GUARD; + + return mLir->insGuardXov(mOpcode, ref(mTokens[0]), ref(mTokens[1]), guard); +} + +LIns * +FragmentAssembler::assemble_jump_jov() +{ + need(3); + + LIns *a = ref(mTokens[0]); + LIns *b = ref(mTokens[1]); + string name = mTokens[2]; + + if (mLabels.find(name) != mLabels.end()) { + LIns *target = ref(name); + return mLir->insBranchJov(mOpcode, a, b, target); + } else { + LIns *ins = mLir->insBranchJov(mOpcode, a, b, NULL); +#ifdef __SUNPRO_CC + mFwdJumps.insert(make_pair(name, ins)); +#else + mFwdJumps.insert(make_pair(name, ins)); +#endif + return ins; + } +} + +void +FragmentAssembler::endFragment() +{ + if (mReturnTypeBits == 0) { + cerr << "warning: no return type in fragment '" + << mFragName << "'" << endl; + + } else if (mReturnTypeBits != RT_INT && +#ifdef NANOJIT_64BIT + mReturnTypeBits != RT_QUAD && +#endif + mReturnTypeBits != RT_DOUBLE && + mReturnTypeBits != RT_GUARD) + { + cerr << "warning: multiple return types in fragment '" + << mFragName << "'" << endl; + } + + mFragment->lastIns = + mLir->insGuard(LIR_x, NULL, createGuardRecord(createSideExit())); + + mParent.mAssm.compile(mFragment, mParent.mAlloc, optimize + verbose_only(, mParent.mLirbuf->printer)); + + if (mParent.mAssm.error() != nanojit::None) { + cerr << "error during assembly: "; + switch (mParent.mAssm.error()) { + case nanojit::BranchTooFar: cerr << "BranchTooFar"; break; + case nanojit::StackFull: cerr << "StackFull"; break; + case nanojit::UnknownBranch: cerr << "UnknownBranch"; break; + case nanojit::None: cerr << "None"; break; + default: NanoAssert(0); break; + } + cerr << endl; + std::exit(1); + } + + LirasmFragment *f; + f = &mParent.mFragments[mFragName]; + + switch (mReturnTypeBits) { + case RT_INT: + f->rint = (RetInt)((uintptr_t)mFragment->code()); + f->mReturnType = RT_INT; + break; +#ifdef NANOJIT_64BIT + case RT_QUAD: + f->rquad = (RetQuad)((uintptr_t)mFragment->code()); + f->mReturnType = RT_QUAD; + break; +#endif + case RT_DOUBLE: + f->rdouble = (RetDouble)((uintptr_t)mFragment->code()); + f->mReturnType = RT_DOUBLE; + break; + case RT_GUARD: + f->rguard = (RetGuard)((uintptr_t)mFragment->code()); + f->mReturnType = RT_GUARD; + break; + default: + NanoAssert(0); + break; + } + + mParent.mFragments[mFragName].mLabels = mLabels; +} + +void +FragmentAssembler::tokenizeLine(LirTokenStream &in, LirToken &token) +{ + mTokens.clear(); + mTokens.push_back(token.data); + + while (in.get(token)) { + if (token.type == NEWLINE) + break; + mTokens.push_back(token.data); + } +} + +void +FragmentAssembler::extract_any_label(string &lab, char lab_delim) +{ + if (mTokens.size() > 2 && mTokens[1].size() == 1 && mTokens[1][0] == lab_delim) { + lab = pop_front(mTokens); + pop_front(mTokens); // remove punctuation + + if (mLabels.find(lab) != mLabels.end()) + bad("duplicate label"); + } +} + +void +FragmentAssembler::resolve_forward_jumps(string &lab, LIns *ins) +{ + typedef multimap mulmap; +#ifdef __SUNPRO_CC + typedef mulmap::iterator ci; +#else + typedef mulmap::const_iterator ci; +#endif + pair range = mFwdJumps.equal_range(lab); + for (ci i = range.first; i != range.second; ++i) { + i->second->setTarget(ins); + } + mFwdJumps.erase(lab); +} + +void +FragmentAssembler::assembleFragment(LirTokenStream &in, bool implicitBegin, const LirToken *firstToken) +{ + LirToken token; + while (true) { + if (firstToken) { + token = *firstToken; + firstToken = NULL; + } else if (!in.get(token)) { + if (!implicitBegin) + bad("unexpected end of file in fragment '" + mFragName + "'"); + break; + } + if (token.type == NEWLINE) + continue; + if (token.type != NAME) + bad("unexpected token '" + token.data + "'"); + + string op = token.data; + if (op == ".begin") + bad("nested fragments are not supported"); + if (op == ".end") { + if (implicitBegin) + bad(".end without .begin"); + if (!in.eat(NEWLINE)) + bad("extra junk after .end"); + break; + } + + mLineno = token.lineno; + tokenizeLine(in, token); + + string lab; + LIns *ins = NULL; + extract_any_label(lab, ':'); + + /* Save label and do any back-patching of deferred forward-jumps. */ + if (!lab.empty()) { + ins = mLir->ins0(LIR_label); + resolve_forward_jumps(lab, ins); + lab.clear(); + } + extract_any_label(lab, '='); + + assert(!mTokens.empty()); + op = pop_front(mTokens); + if (mParent.mOpMap.find(op) == mParent.mOpMap.end()) + bad("unknown instruction '" + op + "'"); + + mOpcode = mParent.mOpMap[op]; + + switch (mOpcode) { + case LIR_start: + bad("start instructions cannot be specified explicitly"); + break; + + case LIR_regfence: + need(0); + ins = mLir->ins0(mOpcode); + break; + + case LIR_livei: + CASE64(LIR_liveq:) + case LIR_lived: + case LIR_negi: + case LIR_negd: + case LIR_noti: + CASESF(LIR_dlo2i:) + CASESF(LIR_dhi2i:) + CASE64(LIR_q2i:) + CASE64(LIR_i2q:) + CASE64(LIR_ui2uq:) + CASE64(LIR_dasq:) + CASE64(LIR_qasd:) + case LIR_i2d: + case LIR_ui2d: + case LIR_d2i: +#if defined NANOJIT_IA32 || defined NANOJIT_X64 + case LIR_modi: +#endif + need(1); + ins = mLir->ins1(mOpcode, + ref(mTokens[0])); + break; + + case LIR_addi: + case LIR_subi: + case LIR_muli: +#if defined NANOJIT_IA32 || defined NANOJIT_X64 + case LIR_divi: +#endif + case LIR_addd: + case LIR_subd: + case LIR_muld: + case LIR_divd: + CASE64(LIR_addq:) + CASE64(LIR_subq:) + case LIR_andi: + case LIR_ori: + case LIR_xori: + CASE64(LIR_andq:) + CASE64(LIR_orq:) + CASE64(LIR_xorq:) + case LIR_lshi: + case LIR_rshi: + case LIR_rshui: + CASE64(LIR_lshq:) + CASE64(LIR_rshq:) + CASE64(LIR_rshuq:) + case LIR_eqi: + case LIR_lti: + case LIR_gti: + case LIR_lei: + case LIR_gei: + case LIR_ltui: + case LIR_gtui: + case LIR_leui: + case LIR_geui: + case LIR_eqd: + case LIR_ltd: + case LIR_gtd: + case LIR_led: + case LIR_ged: + CASE64(LIR_eqq:) + CASE64(LIR_ltq:) + CASE64(LIR_gtq:) + CASE64(LIR_leq:) + CASE64(LIR_geq:) + CASE64(LIR_ltuq:) + CASE64(LIR_gtuq:) + CASE64(LIR_leuq:) + CASE64(LIR_geuq:) + CASESF(LIR_ii2d:) + need(2); + ins = mLir->ins2(mOpcode, + ref(mTokens[0]), + ref(mTokens[1])); + break; + + case LIR_cmovi: + CASE64(LIR_cmovq:) + case LIR_cmovd: + need(3); + ins = mLir->ins3(mOpcode, + ref(mTokens[0]), + ref(mTokens[1]), + ref(mTokens[2])); + break; + + case LIR_j: + ins = assemble_jump(/*isCond*/false); + break; + + case LIR_jt: + case LIR_jf: + ins = assemble_jump(/*isCond*/true); + break; + + case LIR_immi: + need(1); + ins = mLir->insImmI(immI(mTokens[0])); + break; + +#ifdef NANOJIT_64BIT + case LIR_immq: + need(1); + ins = mLir->insImmQ(immQ(mTokens[0])); + break; +#endif + + case LIR_immd: + need(1); + ins = mLir->insImmD(immD(mTokens[0])); + break; + +#if NJ_EXPANDED_LOADSTORE_SUPPORTED + case LIR_sti2c: + case LIR_sti2s: + case LIR_std2f: +#endif + case LIR_sti: + CASE64(LIR_stq:) + case LIR_std: + need(3); + ins = mLir->insStore(mOpcode, ref(mTokens[0]), + ref(mTokens[1]), + immI(mTokens[2]), ACCSET_OTHER); + break; + +#if NJ_EXPANDED_LOADSTORE_SUPPORTED + case LIR_ldc2i: + case LIR_lds2i: + case LIR_ldf2d: +#endif + case LIR_lduc2ui: + case LIR_ldus2ui: + case LIR_ldi: + CASE64(LIR_ldq:) + case LIR_ldd: + ins = assemble_load(); + break; + + // XXX: insParam gives the one appropriate for the platform. Eg. if + // you specify qparam on x86 you'll end up with iparam anyway. Fix + // this. + case LIR_paramp: + need(2); + ins = mLir->insParam(immI(mTokens[0]), + immI(mTokens[1])); + break; + + // XXX: similar to iparam/qparam above. + case LIR_allocp: + need(1); + ins = mLir->insAlloc(immI(mTokens[0])); + break; + + case LIR_skip: + bad("skip instruction is deprecated"); + break; + + case LIR_x: + case LIR_xbarrier: + ins = assemble_guard(/*isCond*/false); + break; + + case LIR_xt: + case LIR_xf: + ins = assemble_guard(/*isCond*/true); + break; + + case LIR_addxovi: + case LIR_subxovi: + case LIR_mulxovi: + ins = assemble_guard_xov(); + break; + + case LIR_addjovi: + case LIR_subjovi: + case LIR_muljovi: + CASE64(LIR_addjovq:) + CASE64(LIR_subjovq:) + ins = assemble_jump_jov(); + break; + + case LIR_callv: + case LIR_calli: + CASESF(LIR_hcalli:) + CASE64(LIR_callq:) + case LIR_calld: + ins = assemble_call(op); + break; + + case LIR_reti: + ins = assemble_ret(RT_INT); + break; + +#ifdef NANOJIT_64BIT + case LIR_retq: + ins = assemble_ret(RT_QUAD); + break; +#endif + + case LIR_retd: + ins = assemble_ret(RT_DOUBLE); + break; + + case LIR_label: + ins = mLir->ins0(LIR_label); + if (!lab.empty()) { + resolve_forward_jumps(lab, ins); + } + break; + + case LIR_file: + case LIR_line: + case LIR_xtbl: + case LIR_jtbl: + nyi(op); + break; + + default: + nyi(op); + break; + } + + assert(ins); + if (!lab.empty()) + mLabels.insert(make_pair(lab, ins)); + + } + endFragment(); +} + +/* ------------------ Support for --random -------------------------- */ + +// Returns a positive integer in the range 0..(lim-1). +static inline size_t +rnd(size_t lim) +{ + size_t i = size_t(rand()); + return i % lim; +} + +// Returns an int32_t in the range -RAND_MAX..RAND_MAX. +static inline int32_t +rndI32() +{ + return (rnd(2) ? 1 : -1) * rand(); +} + +// The maximum number of live values (per type, ie. B/I/Q/F) that are +// available to be used as operands. If we make it too high we're prone to +// run out of stack space due to spilling. Needs to be set in consideration +// with spillStackSzB. +const size_t maxLiveValuesPerType = 20; + +// Returns a uint32_t in the range 0..(RAND_MAX*2). +static inline uint32_t +rndU32() +{ + return uint32_t(rnd(2) ? 0 : RAND_MAX) + uint32_t(rand()); +} + +template t +rndPick(vector &v) +{ + assert(!v.empty()); + return v[rnd(v.size())]; +} + +// Add the operand, and retire an old one if we have too many. +template void +addOrReplace(vector &v, t x) +{ + if (v.size() > maxLiveValuesPerType) { + v[rnd(v.size())] = x; // we're full: overwrite an existing element + } else { + v.push_back(x); // add to end + } +} + +// Returns a 4-aligned address within the given size. +static int32_t rndOffset32(size_t szB) +{ + return int32_t(rnd(szB)) & ~3; +} + +// Returns an 8-aligned address within the give size. +static int32_t rndOffset64(size_t szB) +{ + return int32_t(rnd(szB)) & ~7; +} + +static int32_t f_I_I1(int32_t a) +{ + return a; +} + +static int32_t f_I_I6(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f) +{ + return a + b + c + d + e + f; +} + +#ifdef NANOJIT_64BIT +static uint64_t f_Q_Q2(uint64_t a, uint64_t b) +{ + return a + b; +} + +static uint64_t f_Q_Q7(uint64_t a, uint64_t b, uint64_t c, uint64_t d, + uint64_t e, uint64_t f, uint64_t g) +{ + return a + b + c + d + e + f + g; +} +#endif + +static double f_F_F3(double a, double b, double c) +{ + return a + b + c; +} + +static double f_F_F8(double a, double b, double c, double d, + double e, double f, double g, double h) +{ + return a + b + c + d + e + f + g + h; +} + +#ifdef NANOJIT_64BIT +static void f_V_IQF(int32_t, uint64_t, double) +{ + return; // no need to do anything +} +#endif + +const CallInfo ci_I_I1 = CI(f_I_I1, CallInfo::typeSig1(ARGTYPE_I, ARGTYPE_I)); +const CallInfo ci_I_I6 = CI(f_I_I6, CallInfo::typeSig6(ARGTYPE_I, ARGTYPE_I, ARGTYPE_I, ARGTYPE_I, + ARGTYPE_I, ARGTYPE_I, ARGTYPE_I)); + +#ifdef NANOJIT_64BIT +const CallInfo ci_Q_Q2 = CI(f_Q_Q2, CallInfo::typeSig2(ARGTYPE_Q, ARGTYPE_Q, ARGTYPE_Q)); +const CallInfo ci_Q_Q7 = CI(f_Q_Q7, CallInfo::typeSig7(ARGTYPE_Q, ARGTYPE_Q, ARGTYPE_Q, ARGTYPE_Q, + ARGTYPE_Q, ARGTYPE_Q, ARGTYPE_Q, ARGTYPE_Q)); +#endif + +const CallInfo ci_F_F3 = CI(f_F_F3, CallInfo::typeSig3(ARGTYPE_D, ARGTYPE_D, ARGTYPE_D, ARGTYPE_D)); +const CallInfo ci_F_F8 = CI(f_F_F8, CallInfo::typeSig8(ARGTYPE_D, ARGTYPE_D, ARGTYPE_D, ARGTYPE_D, + ARGTYPE_D, ARGTYPE_D, ARGTYPE_D, ARGTYPE_D, + ARGTYPE_D)); + +#ifdef NANOJIT_64BIT +const CallInfo ci_V_IQF = CI(f_V_IQF, CallInfo::typeSig3(ARGTYPE_V, ARGTYPE_I, ARGTYPE_Q, ARGTYPE_D)); +#endif + +// Generate a random block containing nIns instructions, plus a few more +// setup/shutdown ones at the start and end. +// +// Basic operation: +// - We divide LIR into numerous classes, mostly according to their type. +// (See LInsClasses.tbl for details.) Each time around the loop we choose +// the class randomly, but there is weighting so that some classes are more +// common than others, in an attempt to reflect the structure of real code. +// - Each instruction that produces a value is put in a buffer of the +// appropriate type, for possible use as an operand of a later instruction. +// This buffer is trimmed when its size exceeds 'maxLiveValuesPerType'. +// - If not enough operands are present in a buffer for the particular +// instruction, we don't add it. +// - Skips aren't explicitly generated, but they do occcur if the fragment is +// sufficiently big that it's spread across multiple chunks. +// +// The following instructions aren't generated yet: +// - LIR_parami/LIR_paramq (hard to test beyond what is auto-generated in fragment +// prologues) +// - LIR_livei/LIR_liveq/LIR_lived +// - LIR_hcalli +// - LIR_x/LIR_xt/LIR_xf/LIR_xtbl/LIR_addxovi/LIR_subxovi/LIR_mulxovi (hard to +// test without having multiple fragments; when we only have one fragment +// we don't really want to leave it early) +// - LIR_reti/LIR_retq/LIR_retd (hard to test without having multiple fragments) +// - LIR_j/LIR_jt/LIR_jf/LIR_jtbl/LIR_label +// - LIR_file/LIR_line (#ifdef VTUNE only) +// - LIR_modd (not implemented in NJ backends) +// +// Other limitations: +// - Loads always use accSet==ACCSET_OTHER +// - Stores always use accSet==ACCSET_OTHER +// +void +FragmentAssembler::assembleRandomFragment(int nIns) +{ + vector Bs; // boolean values, ie. 32-bit int values produced by tests + vector Is; // 32-bit int values + vector Qs; // 64-bit int values + vector Ds; // 64-bit double values + vector M4s; // 4 byte allocs + vector M8ps; // 8+ byte allocs + + vector I_I_ops; + I_I_ops.push_back(LIR_negi); + I_I_ops.push_back(LIR_noti); + + // Nb: there are no Q_Q_ops. + + vector D_D_ops; + D_D_ops.push_back(LIR_negd); + + vector I_II_ops; + I_II_ops.push_back(LIR_addi); + I_II_ops.push_back(LIR_subi); + I_II_ops.push_back(LIR_muli); +#if defined NANOJIT_IA32 || defined NANOJIT_X64 + I_II_ops.push_back(LIR_divi); + I_II_ops.push_back(LIR_modi); +#endif + I_II_ops.push_back(LIR_andi); + I_II_ops.push_back(LIR_ori); + I_II_ops.push_back(LIR_xori); + I_II_ops.push_back(LIR_lshi); + I_II_ops.push_back(LIR_rshi); + I_II_ops.push_back(LIR_rshui); + +#ifdef NANOJIT_64BIT + vector Q_QQ_ops; + Q_QQ_ops.push_back(LIR_addq); + Q_QQ_ops.push_back(LIR_andq); + Q_QQ_ops.push_back(LIR_orq); + Q_QQ_ops.push_back(LIR_xorq); + + vector Q_QI_ops; + Q_QI_ops.push_back(LIR_lshq); + Q_QI_ops.push_back(LIR_rshq); + Q_QI_ops.push_back(LIR_rshuq); +#endif + + vector D_DD_ops; + D_DD_ops.push_back(LIR_addd); + D_DD_ops.push_back(LIR_subd); + D_DD_ops.push_back(LIR_muld); + D_DD_ops.push_back(LIR_divd); + + vector I_BII_ops; + I_BII_ops.push_back(LIR_cmovi); + +#ifdef NANOJIT_64BIT + vector Q_BQQ_ops; + Q_BQQ_ops.push_back(LIR_cmovq); +#endif + + vector D_BDD_ops; + D_BDD_ops.push_back(LIR_cmovd); + + vector B_II_ops; + B_II_ops.push_back(LIR_eqi); + B_II_ops.push_back(LIR_lti); + B_II_ops.push_back(LIR_gti); + B_II_ops.push_back(LIR_lei); + B_II_ops.push_back(LIR_gei); + B_II_ops.push_back(LIR_ltui); + B_II_ops.push_back(LIR_gtui); + B_II_ops.push_back(LIR_leui); + B_II_ops.push_back(LIR_geui); + +#ifdef NANOJIT_64BIT + vector B_QQ_ops; + B_QQ_ops.push_back(LIR_eqq); + B_QQ_ops.push_back(LIR_ltq); + B_QQ_ops.push_back(LIR_gtq); + B_QQ_ops.push_back(LIR_leq); + B_QQ_ops.push_back(LIR_geq); + B_QQ_ops.push_back(LIR_ltuq); + B_QQ_ops.push_back(LIR_gtuq); + B_QQ_ops.push_back(LIR_leuq); + B_QQ_ops.push_back(LIR_geuq); +#endif + + vector B_DD_ops; + B_DD_ops.push_back(LIR_eqd); + B_DD_ops.push_back(LIR_ltd); + B_DD_ops.push_back(LIR_gtd); + B_DD_ops.push_back(LIR_led); + B_DD_ops.push_back(LIR_ged); + +#ifdef NANOJIT_64BIT + vector Q_I_ops; + Q_I_ops.push_back(LIR_i2q); + Q_I_ops.push_back(LIR_ui2uq); + + vector I_Q_ops; + I_Q_ops.push_back(LIR_q2i); +#endif + + vector D_I_ops; +#if !NJ_SOFTFLOAT_SUPPORTED + // Don't emit LIR_{ui,i}2d for soft-float platforms because the soft-float filter removes them. + D_I_ops.push_back(LIR_i2d); + D_I_ops.push_back(LIR_ui2d); +#elif defined(NANOJIT_ARM) + // The ARM back-end can detect FP support at run-time. + if (avmplus::AvmCore::config.arm_vfp) { + D_I_ops.push_back(LIR_i2d); + D_I_ops.push_back(LIR_ui2d); + } +#endif + + vector I_D_ops; +#if NJ_SOFTFLOAT_SUPPORTED + I_D_ops.push_back(LIR_dlo2i); + I_D_ops.push_back(LIR_dhi2i); +#endif +#if !NJ_SOFTFLOAT_SUPPORTED + // Don't emit LIR_d2i for soft-float platforms because the soft-float filter removes it. + I_D_ops.push_back(LIR_d2i); +#elif defined(NANOJIT_ARM) + // The ARM back-end can detect FP support at run-time. + if (avmplus::AvmCore::config.arm_vfp) { + I_D_ops.push_back(LIR_d2i); + } +#endif + +#ifdef NANOJIT_64BIT + vector Q_D_ops; + Q_D_ops.push_back(LIR_dasq); + + vector D_Q_ops; + D_Q_ops.push_back(LIR_qasd); +#endif + + vector D_II_ops; +#if NJ_SOFTFLOAT_SUPPORTED + D_II_ops.push_back(LIR_ii2d); +#endif + + vector I_loads; + I_loads.push_back(LIR_ldi); // weight LIR_ldi more heavily + I_loads.push_back(LIR_ldi); + I_loads.push_back(LIR_ldi); + I_loads.push_back(LIR_lduc2ui); + I_loads.push_back(LIR_ldus2ui); +#if NJ_EXPANDED_LOADSTORE_SUPPORTED + I_loads.push_back(LIR_ldc2i); + I_loads.push_back(LIR_lds2i); +#endif + +#ifdef NANOJIT_64BIT + vector Q_loads; + Q_loads.push_back(LIR_ldq); +#endif + + vector D_loads; + D_loads.push_back(LIR_ldd); +#if NJ_EXPANDED_LOADSTORE_SUPPORTED + // this loads a 32-bit float and expands it to 64-bit float + D_loads.push_back(LIR_ldf2d); +#endif + + enum LInsClass { +#define CL___(name, relFreq) name, +#include "LInsClasses.tbl" +#undef CL___ + LLAST + }; + + int relFreqs[LLAST]; + memset(relFreqs, 0, sizeof(relFreqs)); +#define CL___(name, relFreq) relFreqs[name] = relFreq; +#include "LInsClasses.tbl" +#undef CL___ + + int relFreqsSum = 0; // the sum of the individual relative frequencies + for (int c = 0; c < LLAST; c++) { + relFreqsSum += relFreqs[c]; + } + + // The number of times each LInsClass value appears in classGenerator[] + // matches 'relFreqs' (see LInsClasses.tbl). Eg. if relFreqs[LIMM_I] == + // 10, then LIMM_I appears in classGenerator[] 10 times. + LInsClass* classGenerator = new LInsClass[relFreqsSum]; + int j = 0; + for (int c = 0; c < LLAST; c++) { + for (int i = 0; i < relFreqs[c]; i++) { + classGenerator[j++] = LInsClass(c); + } + } + + // Used to keep track of how much stack we've explicitly used via + // LIR_allocp. We then need to keep some reserve for spills as well. + const size_t stackSzB = NJ_MAX_STACK_ENTRY * 4; + const size_t spillStackSzB = 1024; + const size_t maxExplicitlyUsedStackSzB = stackSzB - spillStackSzB; + size_t explicitlyUsedStackSzB = 0; + + // Do an 8-byte stack alloc right at the start so that loads and stores + // can be done immediately. + addOrReplace(M8ps, mLir->insAlloc(8)); + + int n = 0; + while (n < nIns) { + + LIns *ins; + + switch (classGenerator[rnd(relFreqsSum)]) { + + case LFENCE: + if (rnd(2)) { + mLir->ins0(LIR_regfence); + } else { + mLir->insGuard(LIR_xbarrier, NULL, createGuardRecord(createSideExit())); + } + n++; + break; + + case LALLOC: { + // The stack has a limited size, so we (a) don't want chunks to be + // too big, and (b) have to stop allocating them after a while. + size_t szB = 0; + switch (rnd(3)) { + case 0: szB = 4; break; + case 1: szB = 8; break; + case 2: szB = 4 * (rnd(6) + 3); break; // 12, 16, ..., 32 + } + if (explicitlyUsedStackSzB + szB <= maxExplicitlyUsedStackSzB) { + ins = mLir->insAlloc(szB); + // We add the result to Is/Qs so it can be used as an ordinary + // operand, and to M4s/M8ps so that loads/stores can be done from + // it. +#if defined NANOJIT_64BIT + addOrReplace(Qs, ins); +#else + addOrReplace(Is, ins); +#endif + if (szB == 4) + addOrReplace(M4s, ins); + else + addOrReplace(M8ps, ins); + + // It's possible that we will exceed maxExplicitlyUsedStackSzB + // by up to 28 bytes. Doesn't matter. + explicitlyUsedStackSzB += szB; + n++; + } + break; + } + + // For the immediates, we bias towards smaller numbers, especially 0 + // and 1 and small multiples of 4 which are common due to memory + // addressing. This puts some realistic stress on CseFilter. + case LIMM_I: { + int32_t immI = 0; // shut gcc up + switch (rnd(5)) { + case 0: immI = 0; break; + case 1: immI = 1; break; + case 2: immI = 4 * (rnd(256) + 1); break; // 4, 8, ..., 1024 + case 3: immI = rnd(19999) - 9999; break; // -9999..9999 + case 4: immI = rndI32(); break; // -RAND_MAX..RAND_MAX + } + ins = mLir->insImmI(immI); + addOrReplace(Is, ins); + n++; + break; + } + +#ifdef NANOJIT_64BIT + case LIMM_Q: { + uint64_t imm64 = 0; + switch (rnd(5)) { + case 0: imm64 = 0; break; + case 1: imm64 = 1; break; + case 2: imm64 = 4 * (rnd(256) + 1); break; // 4, 8, ..., 1024 + case 3: imm64 = rnd(19999) - 9999; break; // -9999..9999 + case 4: imm64 = uint64_t(rndU32()) << 32 | rndU32(); break; // possibly big! + } + ins = mLir->insImmQ(imm64); + addOrReplace(Qs, ins); + n++; + break; + } +#endif + + case LIMM_D: { + // We don't explicitly generate infinities and NaNs here, but they + // end up occurring due to ExprFilter evaluating expressions like + // divd(1,0) and divd(Infinity,Infinity). + double imm64f = 0; + switch (rnd(5)) { + case 0: imm64f = 0.0; break; + case 1: imm64f = 1.0; break; + case 2: + case 3: imm64f = double(rnd(1000)); break; // 0.0..9999.0 + case 4: + union { + double d; + uint64_t q; + } u; + u.q = uint64_t(rndU32()) << 32 | rndU32(); + imm64f = u.d; + break; + } + ins = mLir->insImmD(imm64f); + addOrReplace(Ds, ins); + n++; + break; + } + + case LOP_I_I: + if (!Is.empty()) { + ins = mLir->ins1(rndPick(I_I_ops), rndPick(Is)); + addOrReplace(Is, ins); + n++; + } + break; + + // case LOP_Q_Q: no instruction in this category + + case LOP_D_D: + if (!Ds.empty()) { + ins = mLir->ins1(rndPick(D_D_ops), rndPick(Ds)); + addOrReplace(Ds, ins); + n++; + } + break; + + case LOP_I_II: + if (!Is.empty()) { + LOpcode op = rndPick(I_II_ops); + LIns* lhs = rndPick(Is); + LIns* rhs = rndPick(Is); +#if defined NANOJIT_IA32 || defined NANOJIT_X64 + if (op == LIR_divi || op == LIR_modi) { + // XXX: ExprFilter can't fold a div/mod with constant + // args, due to the horrible semantics of LIR_modi. So we + // just don't generate anything if we hit that case. + if (!lhs->isImmI() || !rhs->isImmI()) { + // If the divisor is positive, no problems. If it's zero, we get an + // exception. If it's -1 and the dividend is -2147483648 (-2^31) we get + // an exception (and this has been encountered in practice). So we only + // allow positive divisors, ie. compute: lhs / (rhs > 0 ? rhs : -k), + // where k is a random number in the range 2..100 (this ensures we have + // some negative divisors). + LIns* gt0 = mLir->ins2ImmI(LIR_gti, rhs, 0); + LIns* rhs2 = mLir->ins3(LIR_cmovi, gt0, rhs, mLir->insImmI(-((int32_t)rnd(99)) - 2)); + LIns* div = mLir->ins2(LIR_divi, lhs, rhs2); + if (op == LIR_divi) { + ins = div; + addOrReplace(Is, ins); + n += 5; + } else { + ins = mLir->ins1(LIR_modi, div); + // Add 'div' to the operands too so it might be used again, because + // the code generated is different as compared to the case where 'div' + // isn't used again. + addOrReplace(Is, div); + addOrReplace(Is, ins); + n += 6; + } + } + } else +#endif + { + ins = mLir->ins2(op, lhs, rhs); + addOrReplace(Is, ins); + n++; + } + } + break; + +#ifdef NANOJIT_64BIT + case LOP_Q_QQ: + if (!Qs.empty()) { + ins = mLir->ins2(rndPick(Q_QQ_ops), rndPick(Qs), rndPick(Qs)); + addOrReplace(Qs, ins); + n++; + } + break; + + case LOP_Q_QI: + if (!Qs.empty() && !Is.empty()) { + ins = mLir->ins2(rndPick(Q_QI_ops), rndPick(Qs), rndPick(Is)); + addOrReplace(Qs, ins); + n++; + } + break; +#endif + + case LOP_D_DD: + if (!Ds.empty()) { + ins = mLir->ins2(rndPick(D_DD_ops), rndPick(Ds), rndPick(Ds)); + addOrReplace(Ds, ins); + n++; + } + break; + + case LOP_I_BII: + if (!Bs.empty() && !Is.empty()) { + ins = mLir->ins3(rndPick(I_BII_ops), rndPick(Bs), rndPick(Is), rndPick(Is)); + addOrReplace(Is, ins); + n++; + } + break; + +#ifdef NANOJIT_64BIT + case LOP_Q_BQQ: + if (!Bs.empty() && !Qs.empty()) { + ins = mLir->ins3(rndPick(Q_BQQ_ops), rndPick(Bs), rndPick(Qs), rndPick(Qs)); + addOrReplace(Qs, ins); + n++; + } + break; +#endif + + case LOP_D_BDD: + if (!Bs.empty() && !Ds.empty()) { + ins = mLir->ins3(rndPick(D_BDD_ops), rndPick(Bs), rndPick(Ds), rndPick(Ds)); + addOrReplace(Ds, ins); + n++; + } + break; + + case LOP_B_II: + if (!Is.empty()) { + ins = mLir->ins2(rndPick(B_II_ops), rndPick(Is), rndPick(Is)); + addOrReplace(Bs, ins); + n++; + } + break; + +#ifdef NANOJIT_64BIT + case LOP_B_QQ: + if (!Qs.empty()) { + ins = mLir->ins2(rndPick(B_QQ_ops), rndPick(Qs), rndPick(Qs)); + addOrReplace(Bs, ins); + n++; + } + break; +#endif + + case LOP_B_DD: + if (!Ds.empty()) { + ins = mLir->ins2(rndPick(B_DD_ops), rndPick(Ds), rndPick(Ds)); + // XXX: we don't push the result, because most (all?) of the + // backends currently can't handle cmovs/qcmovs that take + // float comparisons for the test (see bug 520944). This means + // that all B_DD values are dead, unfortunately. + //addOrReplace(Bs, ins); + n++; + } + break; + +#ifdef NANOJIT_64BIT + case LOP_Q_I: + if (!Is.empty()) { + ins = mLir->ins1(rndPick(Q_I_ops), rndPick(Is)); + addOrReplace(Qs, ins); + n++; + } + break; +#endif + + case LOP_D_I: + if (!Is.empty() && !D_I_ops.empty()) { + ins = mLir->ins1(rndPick(D_I_ops), rndPick(Is)); + addOrReplace(Ds, ins); + n++; + } + break; + +#ifdef NANOJIT_64BIT + case LOP_I_Q: + if (!Qs.empty()) { + ins = mLir->ins1(rndPick(I_Q_ops), rndPick(Qs)); + addOrReplace(Is, ins); + n++; + } + break; +#endif + + case LOP_I_D: +// XXX: NativeX64 doesn't implement qhi yet (and it may not need to). +#if !defined NANOJIT_X64 + if (!Ds.empty()) { + ins = mLir->ins1(rndPick(I_D_ops), rndPick(Ds)); + addOrReplace(Is, ins); + n++; + } +#endif + break; + +#if defined NANOJIT_X64 + case LOP_Q_D: + if (!Ds.empty()) { + ins = mLir->ins1(rndPick(Q_D_ops), rndPick(Ds)); + addOrReplace(Qs, ins); + n++; + } + break; + + case LOP_D_Q: + if (!Qs.empty()) { + ins = mLir->ins1(rndPick(D_Q_ops), rndPick(Qs)); + addOrReplace(Ds, ins); + n++; + } + break; +#endif + + case LOP_D_II: + if (!Is.empty() && !D_II_ops.empty()) { + ins = mLir->ins2(rndPick(D_II_ops), rndPick(Is), rndPick(Is)); + addOrReplace(Ds, ins); + n++; + } + break; + + case LLD_I: { + vector Ms = rnd(2) ? M4s : M8ps; + if (!Ms.empty()) { + LIns* base = rndPick(Ms); + ins = mLir->insLoad(rndPick(I_loads), base, rndOffset32(base->size()), ACCSET_OTHER); + addOrReplace(Is, ins); + n++; + } + break; + } + +#ifdef NANOJIT_64BIT + case LLD_Q: + if (!M8ps.empty()) { + LIns* base = rndPick(M8ps); + ins = mLir->insLoad(rndPick(Q_loads), base, rndOffset64(base->size()), ACCSET_OTHER); + addOrReplace(Qs, ins); + n++; + } + break; +#endif + + case LLD_D: + if (!M8ps.empty()) { + LIns* base = rndPick(M8ps); + ins = mLir->insLoad(rndPick(D_loads), base, rndOffset64(base->size()), ACCSET_OTHER); + addOrReplace(Ds, ins); + n++; + } + break; + + case LST_I: { + vector Ms = rnd(2) ? M4s : M8ps; + if (!Ms.empty() && !Is.empty()) { + LIns* base = rndPick(Ms); + mLir->insStore(rndPick(Is), base, rndOffset32(base->size()), ACCSET_OTHER); + n++; + } + break; + } + +#ifdef NANOJIT_64BIT + case LST_Q: + if (!M8ps.empty() && !Qs.empty()) { + LIns* base = rndPick(M8ps); + mLir->insStore(rndPick(Qs), base, rndOffset64(base->size()), ACCSET_OTHER); + n++; + } + break; +#endif + + case LST_D: + if (!M8ps.empty() && !Ds.empty()) { + LIns* base = rndPick(M8ps); + mLir->insStore(rndPick(Ds), base, rndOffset64(base->size()), ACCSET_OTHER); + n++; + } + break; + + case LCALL_I_I1: + if (!Is.empty()) { + LIns* args[1] = { rndPick(Is) }; + ins = mLir->insCall(&ci_I_I1, args); + addOrReplace(Is, ins); + n++; + } + break; + + case LCALL_I_I6: + if (!Is.empty()) { + LIns* args[6] = { rndPick(Is), rndPick(Is), rndPick(Is), + rndPick(Is), rndPick(Is), rndPick(Is) }; + ins = mLir->insCall(&ci_I_I6, args); + addOrReplace(Is, ins); + n++; + } + break; + +#ifdef NANOJIT_64BIT + case LCALL_Q_Q2: + if (!Qs.empty()) { + LIns* args[2] = { rndPick(Qs), rndPick(Qs) }; + ins = mLir->insCall(&ci_Q_Q2, args); + addOrReplace(Qs, ins); + n++; + } + break; + + case LCALL_Q_Q7: + if (!Qs.empty()) { + LIns* args[7] = { rndPick(Qs), rndPick(Qs), rndPick(Qs), rndPick(Qs), + rndPick(Qs), rndPick(Qs), rndPick(Qs) }; + ins = mLir->insCall(&ci_Q_Q7, args); + addOrReplace(Qs, ins); + n++; + } + break; +#endif + + case LCALL_D_D3: + if (!Ds.empty()) { + LIns* args[3] = { rndPick(Ds), rndPick(Ds), rndPick(Ds) }; + ins = mLir->insCall(&ci_F_F3, args); + addOrReplace(Ds, ins); + n++; + } + break; + + case LCALL_D_D8: + if (!Ds.empty()) { + LIns* args[8] = { rndPick(Ds), rndPick(Ds), rndPick(Ds), rndPick(Ds), + rndPick(Ds), rndPick(Ds), rndPick(Ds), rndPick(Ds) }; + ins = mLir->insCall(&ci_F_F8, args); + addOrReplace(Ds, ins); + n++; + } + break; + +#ifdef NANOJIT_64BIT + case LCALL_V_IQD: + if (!Is.empty() && !Qs.empty() && !Ds.empty()) { + // Nb: args[] holds the args in reverse order... sigh. + LIns* args[3] = { rndPick(Ds), rndPick(Qs), rndPick(Is) }; + ins = mLir->insCall(&ci_V_IQF, args); + n++; + } + break; +#endif + + case LLABEL: + // Although no jumps are generated yet, labels are important + // because they delimit areas where CSE can be applied. Without + // them, CSE can be applied over very long regions, which leads to + // values that have very large live ranges, which leads to stack + // overflows. + mLir->ins0(LIR_label); + n++; + break; + + default: + NanoAssert(0); + break; + } + } + + delete[] classGenerator; + + // Return 0. + mReturnTypeBits |= RT_INT; + mLir->ins1(LIR_reti, mLir->insImmI(0)); + + endFragment(); +} + +Lirasm::Lirasm(bool verbose) : + mAssm(mCodeAlloc, mAlloc, mAlloc, &mCore, &mLogc, nanojit::AvmCore::config) +{ + mVerbose = verbose; + mLogc.lcbits = 0; + + mLirbuf = new (mAlloc) LirBuffer(mAlloc); +#ifdef DEBUG + if (mVerbose) { + mLogc.lcbits = LC_ReadLIR | LC_AfterDCE | LC_Native | LC_RegAlloc | LC_Activation; + mLirbuf->printer = new (mAlloc) LInsPrinter(mAlloc, LIRASM_NUM_USED_ACCS); + } +#endif + + // Populate the mOpMap table. +#define OP___(op, number, repKind, retType, isCse) \ + mOpMap[#op] = LIR_##op; +#include "nanojit/LIRopcode.tbl" +#undef OP___ + + // XXX: could add more pointer-sized synonyms here + mOpMap["paramp"] = mOpMap[PTR_SIZE("parami", "paramq")]; + mOpMap["livep"] = mOpMap[PTR_SIZE("livei", "liveq")]; +} + +Lirasm::~Lirasm() +{ + Fragments::iterator i; + for (i = mFragments.begin(); i != mFragments.end(); ++i) { + delete i->second.fragptr; + } +} + + +bool +Lirasm::lookupFunction(const string &name, CallInfo *&ci) +{ + const size_t nfuns = sizeof(functions) / sizeof(functions[0]); + for (size_t i = 0; i < nfuns; i++) { + if (name == functions[i].name) { + *ci = functions[i].callInfo; + return true; + } + } + + Fragments::const_iterator func = mFragments.find(name); + if (func != mFragments.end()) { + // The ABI, arg types and ret type will be overridden by the caller. + if (func->second.mReturnType == RT_DOUBLE) { + CallInfo target = {(uintptr_t) func->second.rdouble, + 0, ABI_FASTCALL, /*isPure*/0, ACCSET_STORE_ANY + verbose_only(, func->first.c_str()) }; + *ci = target; + + } else { + CallInfo target = {(uintptr_t) func->second.rint, + 0, ABI_FASTCALL, /*isPure*/0, ACCSET_STORE_ANY + verbose_only(, func->first.c_str()) }; + *ci = target; + } + return false; + + } else { + bad("invalid function reference " + name); + return false; + } +} + +void +Lirasm::assemble(istream &in, bool optimize) +{ + LirTokenStream ts(in); + bool first = true; + + LirToken token; + while (ts.get(token)) { + + if (token.type == NEWLINE) + continue; + if (token.type != NAME) + bad("unexpected token '" + token.data + "'"); + + const string &op = token.data; + if (op == ".patch") { + handlePatch(ts); + } else if (op == ".begin") { + string name; + if (!ts.getName(name)) + bad("expected fragment name after .begin"); + if (!ts.eat(NEWLINE)) + bad("extra junk after .begin " + name); + + FragmentAssembler assembler(*this, name, optimize); + assembler.assembleFragment(ts, false, NULL); + first = false; + } else if (op == ".end") { + bad(".end without .begin"); + } else if (first) { + FragmentAssembler assembler(*this, "main", optimize); + assembler.assembleFragment(ts, true, &token); + break; + } else { + bad("unexpected stray opcode '" + op + "'"); + } + } +} + +void +Lirasm::assembleRandom(int nIns, bool optimize) +{ + string name = "main"; + FragmentAssembler assembler(*this, name, optimize); + assembler.assembleRandomFragment(nIns); +} + +void +Lirasm::handlePatch(LirTokenStream &in) +{ + string src, fragName, guardName, destName; + + if (!in.getName(src) || !in.eat(PUNCT, "->") || !in.getName(destName)) + bad("incorrect syntax"); + + // Break the src at '.'. This is awkward but the syntax looks nice. + size_t j = src.find('.'); + if (j == string::npos || j == 0 || j == src.size() - 1) + bad("incorrect syntax"); + fragName = src.substr(0, j); + guardName = src.substr(j + 1); + + Fragments::iterator i; + if ((i=mFragments.find(fragName)) == mFragments.end()) + bad("invalid fragment reference"); + LirasmFragment *frag = &i->second; + if (frag->mLabels.find(guardName) == frag->mLabels.end()) + bad("invalid guard reference"); + LIns *ins = frag->mLabels.find(guardName)->second; + if ((i=mFragments.find(destName)) == mFragments.end()) + bad("invalid guard reference"); + ins->record()->exit->target = i->second.fragptr; + + mAssm.patch(ins->record()->exit); +} + +void +usageAndQuit(const string& progname) +{ + cout << + "usage: " << progname << " [options] [filename]\n" + "Options:\n" + " -h --help print this message\n" + " -v --verbose print LIR and assembly code\n" + " --execute execute LIR\n" + " --[no-]optimize enable or disable optimization of the LIR (default=off)\n" + " --random [N] generate a random LIR block of size N (default=1000)\n" + "\n" + "Build query options (these print a value for this build of lirasm and exit)\n" + " --show-arch show the architecture ('i386', 'X64', 'arm', 'ppc',\n" + " 'sparc', 'mips', or 'sh4')\n" + " --show-word-size show the word size ('32' or '64')\n" + " --show-endianness show the endianness ('little-endian' or 'big-endian')\n" + "\n" + "i386-specific options:\n" + " --[no]sse use SSE2 instructions (default=on)\n" + "\n" + "ARM-specific options:\n" + " --arch N use ARM architecture version N instructions (default=7)\n" + " --[no]vfp use ARM VFP instructions (default=on)\n" + "\n" + ; + exit(0); +} + +void +errMsgAndQuit(const string& progname, const string& msg) +{ + cerr << progname << ": " << msg << endl; + exit(1); +} + +struct CmdLineOptions { + string progname; + bool verbose; + bool execute; + bool optimize; + int random; + string filename; +}; + +static void +processCmdLine(int argc, char **argv, CmdLineOptions& opts) +{ + opts.progname = argv[0]; + opts.verbose = false; + opts.execute = false; + opts.random = 0; + opts.optimize = false; + + // Architecture-specific options. +#if defined NANOJIT_IA32 + bool i386_sse = true; +#elif defined NANOJIT_ARM + unsigned int arm_arch = 7; + bool arm_vfp = true; +#endif + + for (int i = 1; i < argc; i++) { + string arg = argv[i]; + + // Common flags for every architecture. + if (arg == "-h" || arg == "--help") + usageAndQuit(opts.progname); + else if (arg == "-v" || arg == "--verbose") + opts.verbose = true; + else if (arg == "--execute") + opts.execute = true; + else if (arg == "--optimize") + opts.optimize = true; + else if (arg == "--no-optimize") + opts.optimize = false; + else if (arg == "--random") { + const int defaultSize = 100; + if (i == argc - 1) { + opts.random = defaultSize; // no numeric argument, use default + } else { + char* endptr; + int res = strtol(argv[i+1], &endptr, 10); + if ('\0' == *endptr) { + // We don't bother checking for overflow. + if (res <= 0) + errMsgAndQuit(opts.progname, "--random argument must be greater than zero"); + opts.random = res; // next arg is a number, use that for the size + i++; + } else { + opts.random = defaultSize; // next arg is not a number + } + } + } + else if (arg == "--show-arch") { + const char* str = +#if defined NANOJIT_IA32 + "i386"; +#elif defined NANOJIT_X64 + "X64"; +#elif defined NANOJIT_ARM + "arm"; +#elif defined NANOJIT_PPC + "ppc"; +#elif defined NANOJIT_SPARC + "sparc"; +#elif defined NANOJIT_MIPS + "mips"; +#elif defined NANOJIT_SH4 + "sh4"; +#else +# error "unknown arch" +#endif + cout << str << "\n"; + exit(0); + } + else if (arg == "--show-word-size") { + cout << sizeof(void*) * 8 << "\n"; + exit(0); + } + else if (arg == "--show-endianness") { + int32_t x = 0x01020304; + if (*(char*)&x == 0x1) { + cout << "big-endian" << "\n"; + } else { + cout << "little-endian" << "\n"; + } + exit(0); + } + + // Architecture-specific flags. +#if defined NANOJIT_IA32 + else if (arg == "--sse") { + i386_sse = true; + } + else if (arg == "--nosse") { + i386_sse = false; + } +#elif defined NANOJIT_ARM + else if ((arg == "--arch") && (i < argc-1)) { + char* endptr; + arm_arch = strtoul(argv[i+1], &endptr, 10); + // Check that the argument was a number. + if ('\0' == *endptr) { + if ((arm_arch < 4) || (arm_arch > 7)) { + errMsgAndQuit(opts.progname, "Unsupported argument to --arch.\n"); + } + } else { + errMsgAndQuit(opts.progname, "Unrecognized argument to --arch.\n"); + } + i++; + } else if (arg == "--vfp") { + arm_vfp = true; + } else if (arg == "--novfp") { + arm_vfp = false; + } +#endif + // Input file names. + else if (arg[0] != '-') { + if (opts.filename.empty()) + opts.filename = arg; + else + errMsgAndQuit(opts.progname, "you can only specify one filename"); + } + // No matching flag found, so report the error. + else + errMsgAndQuit(opts.progname, "bad option: " + arg); + } + + if ((!opts.random && opts.filename.empty()) || (opts.random && !opts.filename.empty())) + errMsgAndQuit(opts.progname, + "you must specify either a filename or --random (but not both)"); + + // Handle the architecture-specific options. +#if defined NANOJIT_IA32 + avmplus::AvmCore::config.i386_use_cmov = avmplus::AvmCore::config.i386_sse2 = i386_sse; + avmplus::AvmCore::config.i386_fixed_esp = true; +#elif defined NANOJIT_ARM + // Warn about untested configurations. + if ( ((arm_arch == 5) && (arm_vfp)) || ((arm_arch >= 6) && (!arm_vfp)) ) { + char const * vfp_string = (arm_vfp) ? ("VFP") : ("no VFP"); + cerr << "Warning: This configuration (ARMv" << arm_arch << ", " << vfp_string << ") " << + "is not regularly tested." << endl; + } + + avmplus::AvmCore::config.arm_arch = arm_arch; + avmplus::AvmCore::config.arm_vfp = arm_vfp; + avmplus::AvmCore::config.soft_float = !arm_vfp; +#endif +} + +int +main(int argc, char **argv) +{ + CmdLineOptions opts; + processCmdLine(argc, argv, opts); + + Lirasm lasm(opts.verbose); + if (opts.random) { + lasm.assembleRandom(opts.random, opts.optimize); + } else { + ifstream in(opts.filename.c_str()); + if (!in) + errMsgAndQuit(opts.progname, "unable to open file " + opts.filename); + lasm.assemble(in, opts.optimize); + } + + Fragments::const_iterator i; + if (opts.execute) { + i = lasm.mFragments.find("main"); + if (i == lasm.mFragments.end()) + errMsgAndQuit(opts.progname, "error: at least one fragment must be named 'main'"); + switch (i->second.mReturnType) { + case RT_INT: { + int res = i->second.rint(); + cout << "Output is: " << res << endl; + break; + } +#ifdef NANOJIT_64BIT + case RT_QUAD: { + int res = i->second.rquad(); + cout << "Output is: " << res << endl; + break; + } +#endif + case RT_DOUBLE: { + double res = i->second.rdouble(); + cout << "Output is: " << res << endl; + break; + } + case RT_GUARD: { + LasmSideExit *ls = (LasmSideExit*) i->second.rguard()->exit; + cout << "Exited block on line: " << ls->line << endl; + break; + } + } + } else { + for (i = lasm.mFragments.begin(); i != lasm.mFragments.end(); i++) + dump_srecords(cout, i->second.fragptr); + } +} diff --git a/js/src/lirasm/testlirc.sh b/js/src/lirasm/testlirc.sh new file mode 100755 index 0000000..7dbb20a --- /dev/null +++ b/js/src/lirasm/testlirc.sh @@ -0,0 +1,148 @@ +#!/bin/bash + +set -eu + +exitcode=0 + +LIRASM=$1 + +TESTS_DIR=`dirname "$0"`/tests + +function runtest { + local infile=$1 + local options=${2-} + + # Catch a request for the random tests. + if [[ $infile == --random* ]] ; then + local outfile=$TESTS_DIR/random.out + else + local outfile=`echo $infile | sed 's/\.in/\.out/'` + fi + + if [[ ! -e "$outfile" ]] ; then + echo "$0: error: no out file $outfile" + exit 1 + fi + + # sed used to strip extra leading zeros from exponential values 'e+00' (see bug 602786) + if $LIRASM $options --execute $infile | tr -d '\r' | sed -e 's/e+00*/e+0/g' > testoutput.txt && cmp -s testoutput.txt $outfile ; then + echo "TEST-PASS | lirasm | lirasm $options --execute $infile" + else + echo "TEST-UNEXPECTED-FAIL | lirasm | lirasm $options --execute $infile" + echo "expected output" + cat $outfile + echo "actual output" + cat testoutput.txt + exitcode=1 + fi +} + +function runtests { + local testdir=$1 + local options=${2-} + for infile in "$TESTS_DIR"/"$testdir"/*.in ; do + runtest $infile "$options" + done +} + +if [[ $($LIRASM --show-arch 2>/dev/null) == "i386" ]] ; then + # i386 with SSE2. + runtests "." + runtests "hardfloat" + runtests "32-bit" + runtests "littleendian" + runtest "--random 1000000" + runtest "--random 1000000 --optimize" + + # i386 without SSE2. + runtests "." "--nosse" + runtests "hardfloat" "--nosse" + runtests "32-bit" "--nosse" + runtests "littleendian" "--nosse" + runtest "--random 1000000" "--nosse" + +elif [[ $($LIRASM --show-arch 2>/dev/null) == "X64" ]] ; then + # X64. + runtests "." + runtests "hardfloat" + runtests "64-bit" + runtests "littleendian" + runtest "--random 1000000" + runtest "--random 1000000 --optimize" + +elif [[ $($LIRASM --show-arch 2>/dev/null) == "arm" ]] ; then + # ARMv7 with VFP. We could test without VFP but such a platform seems + # unlikely. ARM is bi-endian but usually configured as little-endian. + runtests "." + runtests "hardfloat" + runtests "32-bit" + runtests "littleendian" + runtest "--random 1000000" + runtest "--random 1000000" "--optimize" + + # ARMv6 with VFP. ARMv6 without VFP doesn't seem worth testing. + # Random tests are reduced. + runtests "." "--arch 6" + runtests "hardfloat" "--arch 6" + runtests "32-bit" "--arch 6" + runtests "littleendian" "--arch 6" + runtest "--random 100000" "--arch 6" + + # ARMv5 without VFP. ARMv5 with VFP doesn't seem worth testing. + # Random tests are reduced. + runtests "." "--arch 5 --novfp" + runtests "softfloat" "--arch 5 --novfp" + runtests "32-bit" "--arch 5 --novfp" + runtests "littleendian" "--arch 5 --novfp" + runtest "--random 100000" "--arch 5 --novfp" + +elif [[ $($LIRASM --show-arch 2>/dev/null) == "ppc" ]] ; then + # PPC is bi-endian but usually configured as big-endian. + runtests "." + runtests "hardfloat" + if [[ $($LIRASM --show-word-size) == "32" ]] ; then + runtests "32-bit" + else + runtests "64-bit" + fi + runtests "bigendian" + runtest "--random 1000000" + runtest "--random 1000000 --optimize" + +elif [[ $($LIRASM --show-arch 2>/dev/null) == "sparc" ]] ; then + # Sparc is bi-endian but usually configured as big-endian. + runtests "." + runtests "hardfloat" + runtests "32-bit" + runtests "bigendian" + runtest "--random 1000000" + runtest "--random 1000000 --optimize" + +elif [[ $($LIRASM --show-arch 2>/dev/null) == "mips" ]] ; then + # MIPS is bi-endian but usually configured as big-endian. + # XXX: should we run softfloat tests as well? Seems to depend on + # the configuration... + runtests "." + runtests "hardfloat" + runtests "32-bit" + runtests "bigendian" + runtest "--random 1000000" + runtest "--random 1000000 --optimize" + +elif [[ $($LIRASM --show-arch 2>/dev/null) == "sh4" ]] ; then + # SH4 is bi-endian but usually configured as big-endian. + runtests "." + runtests "hardfloat" + runtests "32-bit" + runtests "bigendian" + runtest "--random 1000000" + runtest "--random 1000000 --optimize" + +else + echo "bad arch" + exit 1 +fi + +rm testoutput.txt + +exit $exitcode diff --git a/js/src/lirasm/tests/32-bit/many_params.in b/js/src/lirasm/tests/32-bit/many_params.in new file mode 100644 index 0000000..f92ae19 --- /dev/null +++ b/js/src/lirasm/tests/32-bit/many_params.in @@ -0,0 +1,31 @@ +.begin many_params +pa = parami 0 0 +pb = parami 1 0 +pc = parami 2 0 +pd = parami 3 0 +pe = parami 4 0 +pf = parami 5 0 +pg = parami 6 0 +ph = parami 7 0 +res1 = addi pa pb +res2 = addi res1 pc +res3 = addi res2 pd +res4 = addi res3 pe +res5 = addi res4 pf +res6 = addi res5 pg +res7 = addi res6 ph +reti res7 +.end + +.begin main +a = immi 1 +b = immi 2 +c = immi 3 +d = immi 4 +e = immi 5 +f = immi 6 +g = immi 7 +h = immi 8 +res = calli many_params fastcall a b c d e f g h +reti res +.end diff --git a/js/src/lirasm/tests/32-bit/many_params.out b/js/src/lirasm/tests/32-bit/many_params.out new file mode 100644 index 0000000..541c0fd --- /dev/null +++ b/js/src/lirasm/tests/32-bit/many_params.out @@ -0,0 +1 @@ +Output is: 36 diff --git a/js/src/lirasm/tests/64-bit/dasq.in b/js/src/lirasm/tests/64-bit/dasq.in new file mode 100644 index 0000000..c12a3c6 --- /dev/null +++ b/js/src/lirasm/tests/64-bit/dasq.in @@ -0,0 +1,8 @@ +q = immq 12345 +d = qasd q +q2 = dasq d +one = immd 1.0 ; do some intermediate stuff to make it less trivial +two = immd 2.0 +three = addd one two +i2 = q2i q2 +reti i2 diff --git a/js/src/lirasm/tests/64-bit/dasq.out b/js/src/lirasm/tests/64-bit/dasq.out new file mode 100644 index 0000000..8c7a208 --- /dev/null +++ b/js/src/lirasm/tests/64-bit/dasq.out @@ -0,0 +1 @@ +Output is: 12345 diff --git a/js/src/lirasm/tests/64-bit/qasd.in b/js/src/lirasm/tests/64-bit/qasd.in new file mode 100644 index 0000000..fe57a68 --- /dev/null +++ b/js/src/lirasm/tests/64-bit/qasd.in @@ -0,0 +1,7 @@ +one = immq 1 +d = immd 123.45 +q = dasq d +q2 = addq q one ; do some intermediate stuff just to complicate things +q3 = subq q2 one +d2 = qasd q3 +retd d2 diff --git a/js/src/lirasm/tests/64-bit/qasd.out b/js/src/lirasm/tests/64-bit/qasd.out new file mode 100644 index 0000000..f70b33e --- /dev/null +++ b/js/src/lirasm/tests/64-bit/qasd.out @@ -0,0 +1 @@ +Output is: 123.45 diff --git a/js/src/lirasm/tests/64-bit/shq.in b/js/src/lirasm/tests/64-bit/shq.in new file mode 100644 index 0000000..7e9686a --- /dev/null +++ b/js/src/lirasm/tests/64-bit/shq.in @@ -0,0 +1,32 @@ +; Only the bottom 6 bits of the shift amount in lshq/rshq/rshuq are used. + +two = immq 2 + +sh1 = immi 1 +sh2 = immi 65 ; 0100_0001b +sh3 = immi 268435393 ; 0000_1111_1111_1111_1111_1111_1100_0001b + +a1 = lshq two sh1 ; --> 4 +a2 = lshq two sh2 ; --> 4 +a3 = lshq two sh3 ; --> 4 + +b1 = rshq two sh1 ; --> 1 +b2 = rshq two sh2 ; --> 1 +b3 = rshq two sh3 ; --> 1 + +c1 = rshuq two sh1 ; --> 1 +c2 = rshuq two sh2 ; --> 1 +c3 = rshuq two sh3 ; --> 1 + +s0 = immq 0 +s1 = addq s0 a1 +s2 = addq s1 a2 +s3 = addq s2 a3 +s4 = addq s3 b1 +s5 = addq s4 b2 +s6 = addq s5 b3 +s7 = addq s6 c1 +s8 = addq s7 c2 +s9 = addq s8 c2 ; --> 18 + +retq s9 diff --git a/js/src/lirasm/tests/64-bit/shq.out b/js/src/lirasm/tests/64-bit/shq.out new file mode 100644 index 0000000..5b7e775 --- /dev/null +++ b/js/src/lirasm/tests/64-bit/shq.out @@ -0,0 +1 @@ +Output is: 18 diff --git a/js/src/lirasm/tests/add.in b/js/src/lirasm/tests/add.in new file mode 100644 index 0000000..70b723d --- /dev/null +++ b/js/src/lirasm/tests/add.in @@ -0,0 +1,4 @@ +two = immi 2 +three = immi 3 +res = addi two three +reti res diff --git a/js/src/lirasm/tests/add.out b/js/src/lirasm/tests/add.out new file mode 100644 index 0000000..3af9482 --- /dev/null +++ b/js/src/lirasm/tests/add.out @@ -0,0 +1 @@ +Output is: 5 diff --git a/js/src/lirasm/tests/addd.in b/js/src/lirasm/tests/addd.in new file mode 100644 index 0000000..6972068 --- /dev/null +++ b/js/src/lirasm/tests/addd.in @@ -0,0 +1,31 @@ +; Try to exercise as many different possibilities for the register allocator as +; is feasible. + +p1 = allocp 8 +p2 = allocp 8 + +d1a = immd 1.5 +d1 = addd d1a d1a ; X = X + X +std d1 p1 0 + +d2a = immd 2.5 +d2b = immd 3.0 +d2 = addd d2a d2b ; X = X + Y +std d2b p2 0 +std d2 p2 0 + +d3a = ldd p1 0 +d3b = ldd p2 0 +d3 = addd d3a d3b ; X = Y + X +std d3a p2 0 +std d3 p2 0 + +d4a = ldd p2 0 +d4b = ldd p1 0 +d4 = addd d4a d4b ; X = Y + Z +std d4a p1 0 +std d4b p2 0 +std d4 p1 0 + +d = ldd p1 0 +retd d diff --git a/js/src/lirasm/tests/addd.out b/js/src/lirasm/tests/addd.out new file mode 100644 index 0000000..9108cf2 --- /dev/null +++ b/js/src/lirasm/tests/addd.out @@ -0,0 +1 @@ +Output is: 11.5 diff --git a/js/src/lirasm/tests/addjovi.in b/js/src/lirasm/tests/addjovi.in new file mode 100644 index 0000000..f2e1de5 --- /dev/null +++ b/js/src/lirasm/tests/addjovi.in @@ -0,0 +1,14 @@ + ptr = allocp 8 + + a = immi 2147483647 + b = immi 0 + c = addjovi a b ovf + sti c ptr 0 + + j done + +ovf: i = immi 12345678 + sti i ptr 0 + +done: res = ldi ptr 0 + reti res diff --git a/js/src/lirasm/tests/addjovi.out b/js/src/lirasm/tests/addjovi.out new file mode 100644 index 0000000..f475781 --- /dev/null +++ b/js/src/lirasm/tests/addjovi.out @@ -0,0 +1 @@ +Output is: 2147483647 diff --git a/js/src/lirasm/tests/addjovi_ovf.in b/js/src/lirasm/tests/addjovi_ovf.in new file mode 100644 index 0000000..de0cc25 --- /dev/null +++ b/js/src/lirasm/tests/addjovi_ovf.in @@ -0,0 +1,14 @@ + ptr = allocp 8 + + a = immi 2147483647 + b = immi 1 + c = addjovi a b ovf + sti c ptr 0 + + j done + +ovf: i = immi 12345678 + sti i ptr 0 + +done: res = ldi ptr 0 + reti res diff --git a/js/src/lirasm/tests/addjovi_ovf.out b/js/src/lirasm/tests/addjovi_ovf.out new file mode 100644 index 0000000..5404b11 --- /dev/null +++ b/js/src/lirasm/tests/addjovi_ovf.out @@ -0,0 +1 @@ +Output is: 12345678 diff --git a/js/src/lirasm/tests/addsub.in b/js/src/lirasm/tests/addsub.in new file mode 100644 index 0000000..db641c3 --- /dev/null +++ b/js/src/lirasm/tests/addsub.in @@ -0,0 +1,5 @@ +two = immi 7 +three = immi 3 +targ = addi two three +res = subi targ three +reti res diff --git a/js/src/lirasm/tests/addsub.out b/js/src/lirasm/tests/addsub.out new file mode 100644 index 0000000..3795758 --- /dev/null +++ b/js/src/lirasm/tests/addsub.out @@ -0,0 +1 @@ +Output is: 7 diff --git a/js/src/lirasm/tests/bigendian/fuzz-527178.in b/js/src/lirasm/tests/bigendian/fuzz-527178.in new file mode 100644 index 0000000..2065f31 --- /dev/null +++ b/js/src/lirasm/tests/bigendian/fuzz-527178.in @@ -0,0 +1,5 @@ +base = allocp 512 +five = immi 5 +sti five base 256 +x = ldus2ui base 258 +reti x diff --git a/js/src/lirasm/tests/bigendian/fuzz-527178.out b/js/src/lirasm/tests/bigendian/fuzz-527178.out new file mode 100644 index 0000000..3af9482 --- /dev/null +++ b/js/src/lirasm/tests/bigendian/fuzz-527178.out @@ -0,0 +1 @@ +Output is: 5 diff --git a/js/src/lirasm/tests/bigendian/ldc2i.in b/js/src/lirasm/tests/bigendian/ldc2i.in new file mode 100644 index 0000000..24233ee --- /dev/null +++ b/js/src/lirasm/tests/bigendian/ldc2i.in @@ -0,0 +1,26 @@ +full = immi 1288908529 ; 0x4cd32ef1 +p = allocp 4 +sti full p 0 + +n0chk = immi -15 ; sign_extend(0xf1) +n1chk = immi 46 ; sign_extend(0x2e) +n2chk = immi -45 ; sign_extend(0xd3) +n3chk = immi 76 ; sign_extend(0x4c) + +n0 = ldc2i p 3 +n1 = ldc2i p 2 +n2 = ldc2i p 1 +n3 = ldc2i p 0 + +; Collate the results. +r0 = xori n0chk n0 +r1 = xori n1chk n1 +r2 = xori n2chk n2 +r3 = xori n3chk n3 + +r0_1 = ori r0 r1 +r2_3 = ori r2 r3 + +r = ori r0_1 r2_3 +reti r + diff --git a/js/src/lirasm/tests/bigendian/ldc2i.out b/js/src/lirasm/tests/bigendian/ldc2i.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/bigendian/ldc2i.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/bigendian/lds2i.in b/js/src/lirasm/tests/bigendian/lds2i.in new file mode 100644 index 0000000..1b17929 --- /dev/null +++ b/js/src/lirasm/tests/bigendian/lds2i.in @@ -0,0 +1,17 @@ +full = immi -249334698 ; 0xf1237456 +p = allocp 4 +sti full p 0 + +n0chk = immi 29782 ; sign_extend(0x7456) +n1chk = immi -3805 ; sign_extend(0xf123) + +n0 = lds2i p 2 +n1 = lds2i p 0 + +; Collate the results. +r0 = xori n0chk n0 +r1 = xori n1chk n1 + +r = ori r0 r1 +reti r + diff --git a/js/src/lirasm/tests/bigendian/lds2i.out b/js/src/lirasm/tests/bigendian/lds2i.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/bigendian/lds2i.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/bigendian/lduc2ui.in b/js/src/lirasm/tests/bigendian/lduc2ui.in new file mode 100644 index 0000000..dd76763 --- /dev/null +++ b/js/src/lirasm/tests/bigendian/lduc2ui.in @@ -0,0 +1,26 @@ +full = immi -992746767 ; 0xc4d3e2f1 +p = allocp 4 +sti full p 0 + +n0chk = immi 241 ; 0xf1 +n1chk = immi 226 ; 0xe2 +n2chk = immi 211 ; 0xd3 +n3chk = immi 196 ; 0xc4 + +n0 = lduc2ui p 3 +n1 = lduc2ui p 2 +n2 = lduc2ui p 1 +n3 = lduc2ui p 0 + +; Collate the results. +r0 = xori n0chk n0 +r1 = xori n1chk n1 +r2 = xori n2chk n2 +r3 = xori n3chk n3 + +r0_1 = ori r0 r1 +r2_3 = ori r2 r3 + +r = ori r0_1 r2_3 +reti r + diff --git a/js/src/lirasm/tests/bigendian/lduc2ui.out b/js/src/lirasm/tests/bigendian/lduc2ui.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/bigendian/lduc2ui.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/bigendian/ldus2ui.in b/js/src/lirasm/tests/bigendian/ldus2ui.in new file mode 100644 index 0000000..c4351c7 --- /dev/null +++ b/js/src/lirasm/tests/bigendian/ldus2ui.in @@ -0,0 +1,17 @@ +full = immi -249334698 ; 0xf1237456 +p = allocp 4 +sti full p 0 + +n0chk = immi 29782 ; sign_extend(0x7456) +n1chk = immi 61731 ; sign_extend(0xf123) + +n0 = ldus2ui p 2 +n1 = ldus2ui p 0 + +; Collate the results. +r0 = xori n0chk n0 +r1 = xori n1chk n1 + +r = ori r0 r1 +reti r + diff --git a/js/src/lirasm/tests/bigendian/ldus2ui.out b/js/src/lirasm/tests/bigendian/ldus2ui.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/bigendian/ldus2ui.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/bug596923.in b/js/src/lirasm/tests/bug596923.in new file mode 100644 index 0000000..67c18dd --- /dev/null +++ b/js/src/lirasm/tests/bug596923.in @@ -0,0 +1,17 @@ +; Try to get asm_load64 (ldd) to store straight to a stack slot with a large +; offset from FP (on ARM, at least). + +a = immd 1.1 +p = allocp 1024 +std a p 0 + +; Emit the load just before a regfence, so the result does not have a register +; assigned. +d = ldd p 0 +regfence + +retd d + +; Ensure that 'p' is live here, so it gets a stack slot before 'd' does (and so +; extends the range required to store out 'd'). +livep p diff --git a/js/src/lirasm/tests/bug596923.out b/js/src/lirasm/tests/bug596923.out new file mode 100644 index 0000000..bac5304 --- /dev/null +++ b/js/src/lirasm/tests/bug596923.out @@ -0,0 +1 @@ +Output is: 1.1 diff --git a/js/src/lirasm/tests/call1.in b/js/src/lirasm/tests/call1.in new file mode 100644 index 0000000..ca65f6c --- /dev/null +++ b/js/src/lirasm/tests/call1.in @@ -0,0 +1,12 @@ +ptr = allocp 8 +a = immi 65 +sti2c a ptr 0 +b = immi 66 +sti2c b ptr 1 +c = immi 67 +sti2c c ptr 2 +zero = immi 0 +sti2c zero ptr 3 +ss = calli puts cdecl ptr +nn = gei ss zero +reti nn diff --git a/js/src/lirasm/tests/call1.out b/js/src/lirasm/tests/call1.out new file mode 100644 index 0000000..bf667e1 --- /dev/null +++ b/js/src/lirasm/tests/call1.out @@ -0,0 +1,2 @@ +ABC +Output is: 1 diff --git a/js/src/lirasm/tests/call2.in b/js/src/lirasm/tests/call2.in new file mode 100644 index 0000000..39357e0 --- /dev/null +++ b/js/src/lirasm/tests/call2.in @@ -0,0 +1,5 @@ +pi = immd 3.14 +half = immd 0.5 +halfpi = muld pi half +res = calld sin cdecl halfpi +retd res diff --git a/js/src/lirasm/tests/call2.out b/js/src/lirasm/tests/call2.out new file mode 100644 index 0000000..25ee5c0 --- /dev/null +++ b/js/src/lirasm/tests/call2.out @@ -0,0 +1 @@ +Output is: 1 diff --git a/js/src/lirasm/tests/calld1.in b/js/src/lirasm/tests/calld1.in new file mode 100644 index 0000000..02b5ed9 --- /dev/null +++ b/js/src/lirasm/tests/calld1.in @@ -0,0 +1,11 @@ +a = immd 1.1; +b = immd 2.2 +c = immd 3.3; +d = immd 4.4; +e = immd 5.5; +f = immd 6.6; +g = immd 7.7; +h = immd 8.8; + +res = calld calld1 cdecl a b c d e f g h +retd res diff --git a/js/src/lirasm/tests/calld1.out b/js/src/lirasm/tests/calld1.out new file mode 100644 index 0000000..feb7893 --- /dev/null +++ b/js/src/lirasm/tests/calld1.out @@ -0,0 +1 @@ +Output is: -62.9667 diff --git a/js/src/lirasm/tests/callid1.in b/js/src/lirasm/tests/callid1.in new file mode 100644 index 0000000..3b5358b --- /dev/null +++ b/js/src/lirasm/tests/callid1.in @@ -0,0 +1,10 @@ +i = immi -1; +j = immi 3; +k = immi 6; +x = immd 1.1; +y = immd 3.3; +z = immd 4.4; + +res = calld callid1 cdecl i x y j k z +retd res + diff --git a/js/src/lirasm/tests/callid1.out b/js/src/lirasm/tests/callid1.out new file mode 100644 index 0000000..bac5304 --- /dev/null +++ b/js/src/lirasm/tests/callid1.out @@ -0,0 +1 @@ +Output is: 1.1 diff --git a/js/src/lirasm/tests/callid2.in b/js/src/lirasm/tests/callid2.in new file mode 100644 index 0000000..d8a5266 --- /dev/null +++ b/js/src/lirasm/tests/callid2.in @@ -0,0 +1,8 @@ +i = immi -1; +j = immi 3; +k = immi 6; +x = immd 8.8; + +res = calld callid2 cdecl i j k x +retd res + diff --git a/js/src/lirasm/tests/callid2.out b/js/src/lirasm/tests/callid2.out new file mode 100644 index 0000000..bac5304 --- /dev/null +++ b/js/src/lirasm/tests/callid2.out @@ -0,0 +1 @@ +Output is: 1.1 diff --git a/js/src/lirasm/tests/callid3.in b/js/src/lirasm/tests/callid3.in new file mode 100644 index 0000000..69dbd5e --- /dev/null +++ b/js/src/lirasm/tests/callid3.in @@ -0,0 +1,10 @@ +i = immi -1; +j = immi 3; +k = immi 6; +x = immd 1.1; +y = immd 3.3; +z = immd 4.4; + +res = calld callid3 cdecl i j x k y z +retd res + diff --git a/js/src/lirasm/tests/callid3.out b/js/src/lirasm/tests/callid3.out new file mode 100644 index 0000000..bac5304 --- /dev/null +++ b/js/src/lirasm/tests/callid3.out @@ -0,0 +1 @@ +Output is: 1.1 diff --git a/js/src/lirasm/tests/callv.in b/js/src/lirasm/tests/callv.in new file mode 100644 index 0000000..ffc7c2b --- /dev/null +++ b/js/src/lirasm/tests/callv.in @@ -0,0 +1,5 @@ +; test call to void function + +forty_two = immi 42 +callv printi cdecl forty_two +reti forty_two diff --git a/js/src/lirasm/tests/callv.out b/js/src/lirasm/tests/callv.out new file mode 100644 index 0000000..57f5329 --- /dev/null +++ b/js/src/lirasm/tests/callv.out @@ -0,0 +1,2 @@ +42 +Output is: 42 diff --git a/js/src/lirasm/tests/cmov.in b/js/src/lirasm/tests/cmov.in new file mode 100644 index 0000000..fe5c55b --- /dev/null +++ b/js/src/lirasm/tests/cmov.in @@ -0,0 +1,68 @@ +i = immi -1 +j = immi 0 +k = immi 1 + +; Test each comparison operator. In each case, the result is set to k (1) if it +; did what it should do, or i (-1) if not. + +c1 = eqi j k +r1 = cmovi c1 i k + +c2 = lti j k +r2 = cmovi c2 k i + +c3 = lei j k +r3 = cmovi c3 k i + +c4 = gti j k +r4 = cmovi c4 i k + +c5 = gei j k +r5 = cmovi c5 i k + +c6 = ltui j k +r6 = cmovi c6 k i + +c7 = leui j k +r7 = cmovi c7 k i + +c8 = gtui j k +r8 = cmovi c8 i k + +c9 = geui j k +r9 = cmovi c9 i k + +; A few weird cases: Perform unsigned tests on a signed quantity to ensure that +; they do what they should. This is dependent on the platform using two's +; complement arithmetic, but we don't support anything that doesn't do that. + +c10 = ltui i k +r10 = cmovi c10 i k + +c11 = leui i k +r11 = cmovi c11 i k + +c12 = gtui i k +r12 = cmovi c12 k i + +c13 = geui i k +r13 = cmovi c13 k i + +; Sum the results. They should all be 1 so an overall result of 13 is a pass. + +r1_2 = addi r1 r2 +r3_4 = addi r3 r4 +r5_6 = addi r5 r6 +r7_8 = addi r7 r8 +r9_10 = addi r9 r10 +r11_12 = addi r11 r12 + +r1_4 = addi r1_2 r3_4 +r5_8 = addi r5_6 r7_8 +r9_12 = addi r9_10 r11_12 + +r1_8 = addi r1_4 r5_8 +r9_13 = addi r9_12 r13 + +res = addi r1_8 r9_13 +reti res diff --git a/js/src/lirasm/tests/cmov.out b/js/src/lirasm/tests/cmov.out new file mode 100644 index 0000000..828a4dd --- /dev/null +++ b/js/src/lirasm/tests/cmov.out @@ -0,0 +1 @@ +Output is: 13 diff --git a/js/src/lirasm/tests/cond_eqd.in b/js/src/lirasm/tests/cond_eqd.in new file mode 100644 index 0000000..aaaae02 --- /dev/null +++ b/js/src/lirasm/tests/cond_eqd.in @@ -0,0 +1,54 @@ +; A few utility constants. +sh0 = immi 0 +sh1 = immi 1 +sh2 = immi 2 +sh3 = immi 3 +sh4 = immi 4 +sh5 = immi 5 +sh6 = immi 6 +sh7 = immi 7 +sh8 = immi 8 + +i0 = immd 0 +i1 = immd 1 +i2 = immd -1 + +; ---------------------------------------------------------------------------- +; Combinations of 'eqd'. +eq0 = eqd i0 i0 ; 1 +eq1 = eqd i0 i1 ; 0 +eq2 = eqd i0 i2 ; 0 +eq3 = eqd i1 i0 ; 0 +eq4 = eqd i1 i1 ; 1 +eq5 = eqd i1 i2 ; 0 +eq6 = eqd i2 i0 ; 0 +eq7 = eqd i2 i1 ; 0 +eq8 = eqd i2 i2 ; 1 + +; Aggregate the results. +eq0sh = lshi eq0 sh0 +eq1sh = lshi eq1 sh1 +eq2sh = lshi eq2 sh2 +eq3sh = lshi eq3 sh3 +eq4sh = lshi eq4 sh4 +eq5sh = lshi eq5 sh5 +eq6sh = lshi eq6 sh6 +eq7sh = lshi eq7 sh7 +eq8sh = lshi eq8 sh8 + +eq0_1 = ori eq0sh eq1sh +eq2_3 = ori eq2sh eq3sh +eq4_5 = ori eq4sh eq5sh +eq6_7 = ori eq6sh eq7sh + +eq0_3 = ori eq0_1 eq2_3 +eq4_7 = ori eq4_5 eq6_7 + +eq0_7 = ori eq0_3 eq4_7 + +eq = ori eq0_7 eq8sh + +; The result should be {0001,0001,0001}, 0x111, or 273. + +reti eq + diff --git a/js/src/lirasm/tests/cond_eqd.out b/js/src/lirasm/tests/cond_eqd.out new file mode 100644 index 0000000..f32253b --- /dev/null +++ b/js/src/lirasm/tests/cond_eqd.out @@ -0,0 +1 @@ +Output is: 273 diff --git a/js/src/lirasm/tests/cond_eqi.in b/js/src/lirasm/tests/cond_eqi.in new file mode 100644 index 0000000..74ff521 --- /dev/null +++ b/js/src/lirasm/tests/cond_eqi.in @@ -0,0 +1,53 @@ +; A few utility constants . +sh0 = immi 0 +sh1 = immi 1 +sh2 = immi 2 +sh3 = immi 3 +sh4 = immi 4 +sh5 = immi 5 +sh6 = immi 6 +sh7 = immi 7 +sh8 = immi 8 + +i0 = immi 0 +i1 = immi 1 +i2 = immi -1 + +; ---------------------------------------------------------------------------- +; Combinations of 'eqi'. +eq0 = eqi i0 i0 ; 1 +eq1 = eqi i0 i1 ; 0 +eq2 = eqi i0 i2 ; 0 +eq3 = eqi i1 i0 ; 0 +eq4 = eqi i1 i1 ; 1 +eq5 = eqi i1 i2 ; 0 +eq6 = eqi i2 i0 ; 0 +eq7 = eqi i2 i1 ; 0 +eq8 = eqi i2 i2 ; 1 + +; Aggregate the results. +eq0sh = lshi eq0 sh0 +eq1sh = lshi eq1 sh1 +eq2sh = lshi eq2 sh2 +eq3sh = lshi eq3 sh3 +eq4sh = lshi eq4 sh4 +eq5sh = lshi eq5 sh5 +eq6sh = lshi eq6 sh6 +eq7sh = lshi eq7 sh7 +eq8sh = lshi eq8 sh8 + +eq0_1 = ori eq0sh eq1sh +eq2_3 = ori eq2sh eq3sh +eq4_5 = ori eq4sh eq5sh +eq6_7 = ori eq6sh eq7sh + +eq0_3 = ori eq0_1 eq2_3 +eq4_7 = ori eq4_5 eq6_7 + +eq0_7 = ori eq0_3 eq4_7 + +eq = ori eq0_7 eq8sh + +; The result should be {0001,0001,0001}, 0x111, or 273. + +reti eq diff --git a/js/src/lirasm/tests/cond_eqi.out b/js/src/lirasm/tests/cond_eqi.out new file mode 100644 index 0000000..f32253b --- /dev/null +++ b/js/src/lirasm/tests/cond_eqi.out @@ -0,0 +1 @@ +Output is: 273 diff --git a/js/src/lirasm/tests/cond_ged.in b/js/src/lirasm/tests/cond_ged.in new file mode 100644 index 0000000..1bdd13b --- /dev/null +++ b/js/src/lirasm/tests/cond_ged.in @@ -0,0 +1,53 @@ +; A few utility constants . +sh0 = immi 0 +sh1 = immi 1 +sh2 = immi 2 +sh3 = immi 3 +sh4 = immi 4 +sh5 = immi 5 +sh6 = immi 6 +sh7 = immi 7 +sh8 = immi 8 + +i0 = immd 0 +i1 = immd 1 +i2 = immd -1 + +; ---------------------------------------------------------------------------- +; Combinations of 'ged'. +ge0 = ged i0 i0 ; 1 +ge1 = ged i0 i1 ; 0 +ge2 = ged i0 i2 ; 1 +ge3 = ged i1 i0 ; 1 +ge4 = ged i1 i1 ; 1 +ge5 = ged i1 i2 ; 1 +ge6 = ged i2 i0 ; 0 +ge7 = ged i2 i1 ; 0 +ge8 = ged i2 i2 ; 1 + +; Aggregate the results. +ge0sh = lshi ge0 sh0 +ge1sh = lshi ge1 sh1 +ge2sh = lshi ge2 sh2 +ge3sh = lshi ge3 sh3 +ge4sh = lshi ge4 sh4 +ge5sh = lshi ge5 sh5 +ge6sh = lshi ge6 sh6 +ge7sh = lshi ge7 sh7 +ge8sh = lshi ge8 sh8 + +ge0_1 = ori ge0sh ge1sh +ge2_3 = ori ge2sh ge3sh +ge4_5 = ori ge4sh ge5sh +ge6_7 = ori ge6sh ge7sh + +ge0_3 = ori ge0_1 ge2_3 +ge4_7 = ori ge4_5 ge6_7 + +ge0_7 = ori ge0_3 ge4_7 + +ge = ori ge0_7 ge8sh + +; The result should be {0001,0011,1101}, 0x13d, or 44. + +reti ge diff --git a/js/src/lirasm/tests/cond_ged.out b/js/src/lirasm/tests/cond_ged.out new file mode 100644 index 0000000..185083d --- /dev/null +++ b/js/src/lirasm/tests/cond_ged.out @@ -0,0 +1 @@ +Output is: 317 diff --git a/js/src/lirasm/tests/cond_gei.in b/js/src/lirasm/tests/cond_gei.in new file mode 100644 index 0000000..c9a4f13 --- /dev/null +++ b/js/src/lirasm/tests/cond_gei.in @@ -0,0 +1,53 @@ +; A few utility constants . +sh0 = immi 0 +sh1 = immi 1 +sh2 = immi 2 +sh3 = immi 3 +sh4 = immi 4 +sh5 = immi 5 +sh6 = immi 6 +sh7 = immi 7 +sh8 = immi 8 + +i0 = immi 0 +i1 = immi 1 +i2 = immi -1 + +; ---------------------------------------------------------------------------- +; Combinations of 'gei'. +ge0 = gei i0 i0 ; 1 +ge1 = gei i0 i1 ; 0 +ge2 = gei i0 i2 ; 1 +ge3 = gei i1 i0 ; 1 +ge4 = gei i1 i1 ; 1 +ge5 = gei i1 i2 ; 1 +ge6 = gei i2 i0 ; 0 +ge7 = gei i2 i1 ; 0 +ge8 = gei i2 i2 ; 1 + +; Aggregate the results. +ge0sh = lshi ge0 sh0 +ge1sh = lshi ge1 sh1 +ge2sh = lshi ge2 sh2 +ge3sh = lshi ge3 sh3 +ge4sh = lshi ge4 sh4 +ge5sh = lshi ge5 sh5 +ge6sh = lshi ge6 sh6 +ge7sh = lshi ge7 sh7 +ge8sh = lshi ge8 sh8 + +ge0_1 = ori ge0sh ge1sh +ge2_3 = ori ge2sh ge3sh +ge4_5 = ori ge4sh ge5sh +ge6_7 = ori ge6sh ge7sh + +ge0_3 = ori ge0_1 ge2_3 +ge4_7 = ori ge4_5 ge6_7 + +ge0_7 = ori ge0_3 ge4_7 + +ge = ori ge0_7 ge8sh + +; The result should be {0001,0011,1101}, 0x13d, or 44. + +reti ge diff --git a/js/src/lirasm/tests/cond_gei.out b/js/src/lirasm/tests/cond_gei.out new file mode 100644 index 0000000..185083d --- /dev/null +++ b/js/src/lirasm/tests/cond_gei.out @@ -0,0 +1 @@ +Output is: 317 diff --git a/js/src/lirasm/tests/cond_geui.in b/js/src/lirasm/tests/cond_geui.in new file mode 100644 index 0000000..8dee8eb --- /dev/null +++ b/js/src/lirasm/tests/cond_geui.in @@ -0,0 +1,53 @@ +; A few utility constants . +sh0 = immi 0 +sh1 = immi 1 +sh2 = immi 2 +sh3 = immi 3 +sh4 = immi 4 +sh5 = immi 5 +sh6 = immi 6 +sh7 = immi 7 +sh8 = immi 8 + +i0 = immi 0 +i1 = immi 1 +i2 = immi -1 + +; ---------------------------------------------------------------------------- +; Combinations of 'geui'. +ge0 = geui i0 i0 ; 1 +ge1 = geui i0 i1 ; 0 +ge2 = geui i0 i2 ; 0 +ge3 = geui i1 i0 ; 1 +ge4 = geui i1 i1 ; 1 +ge5 = geui i1 i2 ; 0 +ge6 = geui i2 i0 ; 1 +ge7 = geui i2 i1 ; 1 +ge8 = geui i2 i2 ; 1 + +; Aggregate the results. +ge0sh = lshi ge0 sh0 +ge1sh = lshi ge1 sh1 +ge2sh = lshi ge2 sh2 +ge3sh = lshi ge3 sh3 +ge4sh = lshi ge4 sh4 +ge5sh = lshi ge5 sh5 +ge6sh = lshi ge6 sh6 +ge7sh = lshi ge7 sh7 +ge8sh = lshi ge8 sh8 + +ge0_1 = ori ge0sh ge1sh +ge2_3 = ori ge2sh ge3sh +ge4_5 = ori ge4sh ge5sh +ge6_7 = ori ge6sh ge7sh + +ge0_3 = ori ge0_1 ge2_3 +ge4_7 = ori ge4_5 ge6_7 + +ge0_7 = ori ge0_3 ge4_7 + +ge = ori ge0_7 ge8sh + +; The result should be {0001,1101,1001}, 0x1d9, or 473. + +reti ge diff --git a/js/src/lirasm/tests/cond_geui.out b/js/src/lirasm/tests/cond_geui.out new file mode 100644 index 0000000..1ba4fef --- /dev/null +++ b/js/src/lirasm/tests/cond_geui.out @@ -0,0 +1 @@ +Output is: 473 diff --git a/js/src/lirasm/tests/cond_gtd.in b/js/src/lirasm/tests/cond_gtd.in new file mode 100644 index 0000000..56deeb0 --- /dev/null +++ b/js/src/lirasm/tests/cond_gtd.in @@ -0,0 +1,53 @@ +; A few utility constants . +sh0 = immi 0 +sh1 = immi 1 +sh2 = immi 2 +sh3 = immi 3 +sh4 = immi 4 +sh5 = immi 5 +sh6 = immi 6 +sh7 = immi 7 +sh8 = immi 8 + +i0 = immd 0 +i1 = immd 1 +i2 = immd -1 + +; ---------------------------------------------------------------------------- +; Combinations of 'gtd'. +gt0 = gtd i0 i0 ; 0 +gt1 = gtd i0 i1 ; 0 +gt2 = gtd i0 i2 ; 1 +gt3 = gtd i1 i0 ; 1 +gt4 = gtd i1 i1 ; 0 +gt5 = gtd i1 i2 ; 1 +gt6 = gtd i2 i0 ; 0 +gt7 = gtd i2 i1 ; 0 +gt8 = gtd i2 i2 ; 0 + +; Aggregate the results. +gt0sh = lshi gt0 sh0 +gt1sh = lshi gt1 sh1 +gt2sh = lshi gt2 sh2 +gt3sh = lshi gt3 sh3 +gt4sh = lshi gt4 sh4 +gt5sh = lshi gt5 sh5 +gt6sh = lshi gt6 sh6 +gt7sh = lshi gt7 sh7 +gt8sh = lshi gt8 sh8 + +gt0_1 = ori gt0sh gt1sh +gt2_3 = ori gt2sh gt3sh +gt4_5 = ori gt4sh gt5sh +gt6_7 = ori gt6sh gt7sh + +gt0_3 = ori gt0_1 gt2_3 +gt4_7 = ori gt4_5 gt6_7 + +gt0_7 = ori gt0_3 gt4_7 + +gt = ori gt0_7 gt8sh + +; The result should be {0000,0010,1100}, 0x02c, or 194. + +reti gt diff --git a/js/src/lirasm/tests/cond_gtd.out b/js/src/lirasm/tests/cond_gtd.out new file mode 100644 index 0000000..de596f7 --- /dev/null +++ b/js/src/lirasm/tests/cond_gtd.out @@ -0,0 +1 @@ +Output is: 44 diff --git a/js/src/lirasm/tests/cond_gti.in b/js/src/lirasm/tests/cond_gti.in new file mode 100644 index 0000000..9f37953 --- /dev/null +++ b/js/src/lirasm/tests/cond_gti.in @@ -0,0 +1,53 @@ +; A few utility constants . +sh0 = immi 0 +sh1 = immi 1 +sh2 = immi 2 +sh3 = immi 3 +sh4 = immi 4 +sh5 = immi 5 +sh6 = immi 6 +sh7 = immi 7 +sh8 = immi 8 + +i0 = immi 0 +i1 = immi 1 +i2 = immi -1 + +; ---------------------------------------------------------------------------- +; Combinations of 'gti'. +gt0 = gti i0 i0 ; 0 +gt1 = gti i0 i1 ; 0 +gt2 = gti i0 i2 ; 1 +gt3 = gti i1 i0 ; 1 +gt4 = gti i1 i1 ; 0 +gt5 = gti i1 i2 ; 1 +gt6 = gti i2 i0 ; 0 +gt7 = gti i2 i1 ; 0 +gt8 = gti i2 i2 ; 0 + +; Aggregate the results. +gt0sh = lshi gt0 sh0 +gt1sh = lshi gt1 sh1 +gt2sh = lshi gt2 sh2 +gt3sh = lshi gt3 sh3 +gt4sh = lshi gt4 sh4 +gt5sh = lshi gt5 sh5 +gt6sh = lshi gt6 sh6 +gt7sh = lshi gt7 sh7 +gt8sh = lshi gt8 sh8 + +gt0_1 = ori gt0sh gt1sh +gt2_3 = ori gt2sh gt3sh +gt4_5 = ori gt4sh gt5sh +gt6_7 = ori gt6sh gt7sh + +gt0_3 = ori gt0_1 gt2_3 +gt4_7 = ori gt4_5 gt6_7 + +gt0_7 = ori gt0_3 gt4_7 + +gt = ori gt0_7 gt8sh + +; The result should be {0000,0010,1100}, 0x02c, or 194. + +reti gt diff --git a/js/src/lirasm/tests/cond_gti.out b/js/src/lirasm/tests/cond_gti.out new file mode 100644 index 0000000..de596f7 --- /dev/null +++ b/js/src/lirasm/tests/cond_gti.out @@ -0,0 +1 @@ +Output is: 44 diff --git a/js/src/lirasm/tests/cond_gtui.in b/js/src/lirasm/tests/cond_gtui.in new file mode 100644 index 0000000..a28d254 --- /dev/null +++ b/js/src/lirasm/tests/cond_gtui.in @@ -0,0 +1,53 @@ +; A few utility constants. +sh0 = immi 0 +sh1 = immi 1 +sh2 = immi 2 +sh3 = immi 3 +sh4 = immi 4 +sh5 = immi 5 +sh6 = immi 6 +sh7 = immi 7 +sh8 = immi 8 + +i0 = immi 0 +i1 = immi 1 +i2 = immi -1 + +; ---------------------------------------------------------------------------- +; Combinations of 'gtui'. +gt0 = gtui i0 i0 ; 0 +gt1 = gtui i0 i1 ; 0 +gt2 = gtui i0 i2 ; 0 +gt3 = gtui i1 i0 ; 1 +gt4 = gtui i1 i1 ; 0 +gt5 = gtui i1 i2 ; 0 +gt6 = gtui i2 i0 ; 1 +gt7 = gtui i2 i1 ; 1 +gt8 = gtui i2 i2 ; 0 + +; Aggregate the results. +gt0sh = lshi gt0 sh0 +gt1sh = lshi gt1 sh1 +gt2sh = lshi gt2 sh2 +gt3sh = lshi gt3 sh3 +gt4sh = lshi gt4 sh4 +gt5sh = lshi gt5 sh5 +gt6sh = lshi gt6 sh6 +gt7sh = lshi gt7 sh7 +gt8sh = lshi gt8 sh8 + +gt0_1 = ori gt0sh gt1sh +gt2_3 = ori gt2sh gt3sh +gt4_5 = ori gt4sh gt5sh +gt6_7 = ori gt6sh gt7sh + +gt0_3 = ori gt0_1 gt2_3 +gt4_7 = ori gt4_5 gt6_7 + +gt0_7 = ori gt0_3 gt4_7 + +gt = ori gt0_7 gt8sh + +; The result should be {0000,1100,1000}, 0x0c8, or 200. + +reti gt diff --git a/js/src/lirasm/tests/cond_gtui.out b/js/src/lirasm/tests/cond_gtui.out new file mode 100644 index 0000000..166c886 --- /dev/null +++ b/js/src/lirasm/tests/cond_gtui.out @@ -0,0 +1 @@ +Output is: 200 diff --git a/js/src/lirasm/tests/cond_led.in b/js/src/lirasm/tests/cond_led.in new file mode 100644 index 0000000..3596169 --- /dev/null +++ b/js/src/lirasm/tests/cond_led.in @@ -0,0 +1,53 @@ +; A few utility constants . +sh0 = immi 0 +sh1 = immi 1 +sh2 = immi 2 +sh3 = immi 3 +sh4 = immi 4 +sh5 = immi 5 +sh6 = immi 6 +sh7 = immi 7 +sh8 = immi 8 + +i0 = immd 0 +i1 = immd 1 +i2 = immd -1 + +; ---------------------------------------------------------------------------- +; Combinations of 'led'. +le0 = led i0 i0 ; 1 +le1 = led i0 i1 ; 1 +le2 = led i0 i2 ; 0 +le3 = led i1 i0 ; 0 +le4 = led i1 i1 ; 1 +le5 = led i1 i2 ; 0 +le6 = led i2 i0 ; 1 +le7 = led i2 i1 ; 1 +le8 = led i2 i2 ; 1 + +; Aggregate the results. +le0sh = lshi le0 sh0 +le1sh = lshi le1 sh1 +le2sh = lshi le2 sh2 +le3sh = lshi le3 sh3 +le4sh = lshi le4 sh4 +le5sh = lshi le5 sh5 +le6sh = lshi le6 sh6 +le7sh = lshi le7 sh7 +le8sh = lshi le8 sh8 + +le0_1 = ori le0sh le1sh +le2_3 = ori le2sh le3sh +le4_5 = ori le4sh le5sh +le6_7 = ori le6sh le7sh + +le0_3 = ori le0_1 le2_3 +le4_7 = ori le4_5 le6_7 + +le0_7 = ori le0_3 le4_7 + +le = ori le0_7 le8sh + +; The result should be {0001,1101,0011}, 0x1d3, or 194. + +reti le diff --git a/js/src/lirasm/tests/cond_led.out b/js/src/lirasm/tests/cond_led.out new file mode 100644 index 0000000..e232760 --- /dev/null +++ b/js/src/lirasm/tests/cond_led.out @@ -0,0 +1 @@ +Output is: 467 diff --git a/js/src/lirasm/tests/cond_lei.in b/js/src/lirasm/tests/cond_lei.in new file mode 100644 index 0000000..a11a3f3 --- /dev/null +++ b/js/src/lirasm/tests/cond_lei.in @@ -0,0 +1,53 @@ +; A few utility constants . +sh0 = immi 0 +sh1 = immi 1 +sh2 = immi 2 +sh3 = immi 3 +sh4 = immi 4 +sh5 = immi 5 +sh6 = immi 6 +sh7 = immi 7 +sh8 = immi 8 + +i0 = immi 0 +i1 = immi 1 +i2 = immi -1 + +; ---------------------------------------------------------------------------- +; Combinations of 'lei'. +le0 = lei i0 i0 ; 1 +le1 = lei i0 i1 ; 1 +le2 = lei i0 i2 ; 0 +le3 = lei i1 i0 ; 0 +le4 = lei i1 i1 ; 1 +le5 = lei i1 i2 ; 0 +le6 = lei i2 i0 ; 1 +le7 = lei i2 i1 ; 1 +le8 = lei i2 i2 ; 1 + +; Aggregate the results. +le0sh = lshi le0 sh0 +le1sh = lshi le1 sh1 +le2sh = lshi le2 sh2 +le3sh = lshi le3 sh3 +le4sh = lshi le4 sh4 +le5sh = lshi le5 sh5 +le6sh = lshi le6 sh6 +le7sh = lshi le7 sh7 +le8sh = lshi le8 sh8 + +le0_1 = ori le0sh le1sh +le2_3 = ori le2sh le3sh +le4_5 = ori le4sh le5sh +le6_7 = ori le6sh le7sh + +le0_3 = ori le0_1 le2_3 +le4_7 = ori le4_5 le6_7 + +le0_7 = ori le0_3 le4_7 + +le = ori le0_7 le8sh + +; The result should be {0001,1101,0011}, 0x1d3, or 194. + +reti le diff --git a/js/src/lirasm/tests/cond_lei.out b/js/src/lirasm/tests/cond_lei.out new file mode 100644 index 0000000..e232760 --- /dev/null +++ b/js/src/lirasm/tests/cond_lei.out @@ -0,0 +1 @@ +Output is: 467 diff --git a/js/src/lirasm/tests/cond_leui.in b/js/src/lirasm/tests/cond_leui.in new file mode 100644 index 0000000..a53bf1b --- /dev/null +++ b/js/src/lirasm/tests/cond_leui.in @@ -0,0 +1,53 @@ +; A few utility constants . +sh0 = immi 0 +sh1 = immi 1 +sh2 = immi 2 +sh3 = immi 3 +sh4 = immi 4 +sh5 = immi 5 +sh6 = immi 6 +sh7 = immi 7 +sh8 = immi 8 + +i0 = immi 0 +i1 = immi 1 +i2 = immi -1 + +; ---------------------------------------------------------------------------- +; Combinations of 'leui'. +le0 = leui i0 i0 ; 1 +le1 = leui i0 i1 ; 1 +le2 = leui i0 i2 ; 1 +le3 = leui i1 i0 ; 0 +le4 = leui i1 i1 ; 1 +le5 = leui i1 i2 ; 1 +le6 = leui i2 i0 ; 0 +le7 = leui i2 i1 ; 0 +le8 = leui i2 i2 ; 1 + +; Aggregate the results. +le0sh = lshi le0 sh0 +le1sh = lshi le1 sh1 +le2sh = lshi le2 sh2 +le3sh = lshi le3 sh3 +le4sh = lshi le4 sh4 +le5sh = lshi le5 sh5 +le6sh = lshi le6 sh6 +le7sh = lshi le7 sh7 +le8sh = lshi le8 sh8 + +le0_1 = ori le0sh le1sh +le2_3 = ori le2sh le3sh +le4_5 = ori le4sh le5sh +le6_7 = ori le6sh le7sh + +le0_3 = ori le0_1 le2_3 +le4_7 = ori le4_5 le6_7 + +le0_7 = ori le0_3 le4_7 + +le = ori le0_7 le8sh + +; The result should be {0001,0011,0111}, 0x137, or 311. + +reti le diff --git a/js/src/lirasm/tests/cond_leui.out b/js/src/lirasm/tests/cond_leui.out new file mode 100644 index 0000000..4e71b2b --- /dev/null +++ b/js/src/lirasm/tests/cond_leui.out @@ -0,0 +1 @@ +Output is: 311 diff --git a/js/src/lirasm/tests/cond_ltd.in b/js/src/lirasm/tests/cond_ltd.in new file mode 100644 index 0000000..11e028f --- /dev/null +++ b/js/src/lirasm/tests/cond_ltd.in @@ -0,0 +1,53 @@ +; A few utility constants . +sh0 = immi 0 +sh1 = immi 1 +sh2 = immi 2 +sh3 = immi 3 +sh4 = immi 4 +sh5 = immi 5 +sh6 = immi 6 +sh7 = immi 7 +sh8 = immi 8 + +i0 = immd 0 +i1 = immd 1 +i2 = immd -1 + +; ---------------------------------------------------------------------------- +; Combinations of 'ltd'. +lt0 = ltd i0 i0 ; 0 +lt1 = ltd i0 i1 ; 1 +lt2 = ltd i0 i2 ; 0 +lt3 = ltd i1 i0 ; 0 +lt4 = ltd i1 i1 ; 0 +lt5 = ltd i1 i2 ; 0 +lt6 = ltd i2 i0 ; 1 +lt7 = ltd i2 i1 ; 1 +lt8 = ltd i2 i2 ; 0 + +; Aggregate the results. +lt0sh = lshi lt0 sh0 +lt1sh = lshi lt1 sh1 +lt2sh = lshi lt2 sh2 +lt3sh = lshi lt3 sh3 +lt4sh = lshi lt4 sh4 +lt5sh = lshi lt5 sh5 +lt6sh = lshi lt6 sh6 +lt7sh = lshi lt7 sh7 +lt8sh = lshi lt8 sh8 + +lt0_1 = ori lt0sh lt1sh +lt2_3 = ori lt2sh lt3sh +lt4_5 = ori lt4sh lt5sh +lt6_7 = ori lt6sh lt7sh + +lt0_3 = ori lt0_1 lt2_3 +lt4_7 = ori lt4_5 lt6_7 + +lt0_7 = ori lt0_3 lt4_7 + +lt = ori lt0_7 lt8sh + +; The result should be {0000,1100,0010}, 0x0c2, or 194. + +reti lt diff --git a/js/src/lirasm/tests/cond_ltd.out b/js/src/lirasm/tests/cond_ltd.out new file mode 100644 index 0000000..a932edb --- /dev/null +++ b/js/src/lirasm/tests/cond_ltd.out @@ -0,0 +1 @@ +Output is: 194 diff --git a/js/src/lirasm/tests/cond_lti.in b/js/src/lirasm/tests/cond_lti.in new file mode 100644 index 0000000..8a8d3d2 --- /dev/null +++ b/js/src/lirasm/tests/cond_lti.in @@ -0,0 +1,53 @@ +; A few utility constants . +sh0 = immi 0 +sh1 = immi 1 +sh2 = immi 2 +sh3 = immi 3 +sh4 = immi 4 +sh5 = immi 5 +sh6 = immi 6 +sh7 = immi 7 +sh8 = immi 8 + +i0 = immi 0 +i1 = immi 1 +i2 = immi -1 + +; ---------------------------------------------------------------------------- +; Combinations of 'lti'. +lt0 = lti i0 i0 ; 0 +lt1 = lti i0 i1 ; 1 +lt2 = lti i0 i2 ; 0 +lt3 = lti i1 i0 ; 0 +lt4 = lti i1 i1 ; 0 +lt5 = lti i1 i2 ; 0 +lt6 = lti i2 i0 ; 1 +lt7 = lti i2 i1 ; 1 +lt8 = lti i2 i2 ; 0 + +; Aggregate the results. +lt0sh = lshi lt0 sh0 +lt1sh = lshi lt1 sh1 +lt2sh = lshi lt2 sh2 +lt3sh = lshi lt3 sh3 +lt4sh = lshi lt4 sh4 +lt5sh = lshi lt5 sh5 +lt6sh = lshi lt6 sh6 +lt7sh = lshi lt7 sh7 +lt8sh = lshi lt8 sh8 + +lt0_1 = ori lt0sh lt1sh +lt2_3 = ori lt2sh lt3sh +lt4_5 = ori lt4sh lt5sh +lt6_7 = ori lt6sh lt7sh + +lt0_3 = ori lt0_1 lt2_3 +lt4_7 = ori lt4_5 lt6_7 + +lt0_7 = ori lt0_3 lt4_7 + +lt = ori lt0_7 lt8sh + +; The result should be {0000,1100,0010}, 0x0c2, or 194. + +reti lt diff --git a/js/src/lirasm/tests/cond_lti.out b/js/src/lirasm/tests/cond_lti.out new file mode 100644 index 0000000..a932edb --- /dev/null +++ b/js/src/lirasm/tests/cond_lti.out @@ -0,0 +1 @@ +Output is: 194 diff --git a/js/src/lirasm/tests/cond_ltui.in b/js/src/lirasm/tests/cond_ltui.in new file mode 100644 index 0000000..421d637 --- /dev/null +++ b/js/src/lirasm/tests/cond_ltui.in @@ -0,0 +1,53 @@ +; A few utility constants . +sh0 = immi 0 +sh1 = immi 1 +sh2 = immi 2 +sh3 = immi 3 +sh4 = immi 4 +sh5 = immi 5 +sh6 = immi 6 +sh7 = immi 7 +sh8 = immi 8 + +i0 = immi 0 +i1 = immi 1 +i2 = immi -1 + +; ---------------------------------------------------------------------------- +; Combinations of 'ltui'. +lt0 = ltui i0 i0 ; 0 +lt1 = ltui i0 i1 ; 1 +lt2 = ltui i0 i2 ; 1 +lt3 = ltui i1 i0 ; 0 +lt4 = ltui i1 i1 ; 0 +lt5 = ltui i1 i2 ; 1 +lt6 = ltui i2 i0 ; 0 +lt7 = ltui i2 i1 ; 0 +lt8 = ltui i2 i2 ; 0 + +; Aggregate the results. +lt0sh = lshi lt0 sh0 +lt1sh = lshi lt1 sh1 +lt2sh = lshi lt2 sh2 +lt3sh = lshi lt3 sh3 +lt4sh = lshi lt4 sh4 +lt5sh = lshi lt5 sh5 +lt6sh = lshi lt6 sh6 +lt7sh = lshi lt7 sh7 +lt8sh = lshi lt8 sh8 + +lt0_1 = ori lt0sh lt1sh +lt2_3 = ori lt2sh lt3sh +lt4_5 = ori lt4sh lt5sh +lt6_7 = ori lt6sh lt7sh + +lt0_3 = ori lt0_1 lt2_3 +lt4_7 = ori lt4_5 lt6_7 + +lt0_7 = ori lt0_3 lt4_7 + +lt = ori lt0_7 lt8sh + +; The result should be {0000,0010,0110}, 0x026, or 38. + +reti lt diff --git a/js/src/lirasm/tests/cond_ltui.out b/js/src/lirasm/tests/cond_ltui.out new file mode 100644 index 0000000..c91e4bb --- /dev/null +++ b/js/src/lirasm/tests/cond_ltui.out @@ -0,0 +1 @@ +Output is: 38 diff --git a/js/src/lirasm/tests/divd.in b/js/src/lirasm/tests/divd.in new file mode 100644 index 0000000..0a99761 --- /dev/null +++ b/js/src/lirasm/tests/divd.in @@ -0,0 +1,31 @@ +; Try to exercise as many different possibilities for the register allocator as +; is feasible. + +p1 = allocp 8 +p2 = allocp 8 + +d1a = immd 1.5 +d1 = divd d1a d1a ; X = X / X +std d1 p1 0 + +d2a = immd 4.0 +d2b = immd 8.0 +d2 = divd d2a d2b ; X = X / Y +std d2b p2 0 +std d2 p2 0 + +d3a = ldd p1 0 +d3b = ldd p2 0 +d3 = divd d3a d3b ; X = Y / X +std d3a p2 0 +std d3 p2 0 + +d4a = ldd p2 0 +d4b = ldd p1 0 +d4 = divd d4a d4b ; X = Y / Z +std d4a p1 0 +std d4b p2 0 +std d4 p1 0 + +d = ldd p1 0 +retd d diff --git a/js/src/lirasm/tests/divd.out b/js/src/lirasm/tests/divd.out new file mode 100644 index 0000000..ca49356 --- /dev/null +++ b/js/src/lirasm/tests/divd.out @@ -0,0 +1 @@ +Output is: 2 diff --git a/js/src/lirasm/tests/float_double.in b/js/src/lirasm/tests/float_double.in new file mode 100644 index 0000000..0ea31e7 --- /dev/null +++ b/js/src/lirasm/tests/float_double.in @@ -0,0 +1,20 @@ +doubleA = immd 1.25 ; single precision +doubleB = immd 4.5 ; single precision +doubleC = immd 1.2 ; not single precision + +ptr = allocp 12 +std2f doubleA ptr 0 +std2f doubleB ptr 4 +std2f doubleC ptr 8 + +doubleD = ldf2d ptr 0 +doubleE = ldf2d ptr 4 +doubleF = ldf2d ptr 8 + +resA = eqd doubleA doubleD ; true +resB = eqd doubleB doubleE ; true +resC = eqd doubleB doubleF ; false +resD = addi resA resB +resE = addi resC resD + +reti resE diff --git a/js/src/lirasm/tests/float_double.out b/js/src/lirasm/tests/float_double.out new file mode 100644 index 0000000..ca49356 --- /dev/null +++ b/js/src/lirasm/tests/float_double.out @@ -0,0 +1 @@ +Output is: 2 diff --git a/js/src/lirasm/tests/floatingpoint.in b/js/src/lirasm/tests/floatingpoint.in new file mode 100644 index 0000000..f2f5b63 --- /dev/null +++ b/js/src/lirasm/tests/floatingpoint.in @@ -0,0 +1,4 @@ +pi = immd 3.14 +two = immd 2.0 +TwoPi = muld pi two +retd two diff --git a/js/src/lirasm/tests/floatingpoint.out b/js/src/lirasm/tests/floatingpoint.out new file mode 100644 index 0000000..ca49356 --- /dev/null +++ b/js/src/lirasm/tests/floatingpoint.out @@ -0,0 +1 @@ +Output is: 2 diff --git a/js/src/lirasm/tests/fneg.in b/js/src/lirasm/tests/fneg.in new file mode 100644 index 0000000..caf466e --- /dev/null +++ b/js/src/lirasm/tests/fneg.in @@ -0,0 +1,3 @@ +p = immd 123.456 +n = negd p +retd n diff --git a/js/src/lirasm/tests/fneg.out b/js/src/lirasm/tests/fneg.out new file mode 100644 index 0000000..7e170f3 --- /dev/null +++ b/js/src/lirasm/tests/fneg.out @@ -0,0 +1 @@ +Output is: -123.456 diff --git a/js/src/lirasm/tests/fpu1-598151.in b/js/src/lirasm/tests/fpu1-598151.in new file mode 100644 index 0000000..e2d154c --- /dev/null +++ b/js/src/lirasm/tests/fpu1-598151.in @@ -0,0 +1,12 @@ + ptr = allocp 8 + + a = immd 1.0 + b = immd 2.5 + c = addd a b + std c ptr 0 + j done + +foo: std c ptr 0 + +done: res = ldd ptr 0 + retd res diff --git a/js/src/lirasm/tests/fpu1-598151.out b/js/src/lirasm/tests/fpu1-598151.out new file mode 100644 index 0000000..5eec694 --- /dev/null +++ b/js/src/lirasm/tests/fpu1-598151.out @@ -0,0 +1 @@ +Output is: 3.5 diff --git a/js/src/lirasm/tests/fpu2-598151.in b/js/src/lirasm/tests/fpu2-598151.in new file mode 100644 index 0000000..6276f7a --- /dev/null +++ b/js/src/lirasm/tests/fpu2-598151.in @@ -0,0 +1,21 @@ + ptr = allocp 8 + + k = immd 1.0 + std k ptr 0 + + a = immd 1.0 + b = immd 2.5 + c = addd a b + std c ptr 0 + + x = ldd ptr 0 + z = immd 0.0 + p = eqd x z + jt p skip + + j done + +skip: std c ptr 0 + +done: res = ldd ptr 0 + retd res diff --git a/js/src/lirasm/tests/fpu2-598151.out b/js/src/lirasm/tests/fpu2-598151.out new file mode 100644 index 0000000..5eec694 --- /dev/null +++ b/js/src/lirasm/tests/fpu2-598151.out @@ -0,0 +1 @@ +Output is: 3.5 diff --git a/js/src/lirasm/tests/fuzz-527178.in b/js/src/lirasm/tests/fuzz-527178.in new file mode 100644 index 0000000..12403dd --- /dev/null +++ b/js/src/lirasm/tests/fuzz-527178.in @@ -0,0 +1,5 @@ +base = allocp 512 +five = immi 5 +sti five base 256 +x = ldus2ui base 256 +reti x diff --git a/js/src/lirasm/tests/fuzz-527178.out b/js/src/lirasm/tests/fuzz-527178.out new file mode 100644 index 0000000..3af9482 --- /dev/null +++ b/js/src/lirasm/tests/fuzz-527178.out @@ -0,0 +1 @@ +Output is: 5 diff --git a/js/src/lirasm/tests/hardfloat/d2i.in b/js/src/lirasm/tests/hardfloat/d2i.in new file mode 100644 index 0000000..c60a169 --- /dev/null +++ b/js/src/lirasm/tests/hardfloat/d2i.in @@ -0,0 +1,26 @@ +; The rounding rules for d2i are pretty relaxed, but integer values should +; convert cleanly. +c1 = immi -2147483648 +d1 = immd -2147483648 +i1 = d2i d1 +r1 = xori c1 i1 + +c2 = immi 2147483647 +d2 = immd 2147483647 +i2 = d2i d2 +r2 = xori i2 c2 + +; The ARM back-end will do something different if there is no machine register +; allocated for d2i, and it doesn't hurt to test the same thing on other +; platforms too: + +c3 = immi 123456 +d3 = immd 123456 +i3 = d2i d3 +regfence +r3 = xori i3 c3 + +res1_2 = ori r1 r2 +res1_3 = ori res1_2 r3 + +reti res1_3 diff --git a/js/src/lirasm/tests/hardfloat/d2i.out b/js/src/lirasm/tests/hardfloat/d2i.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/hardfloat/d2i.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/hardfloat/f2i.in b/js/src/lirasm/tests/hardfloat/f2i.in new file mode 100644 index 0000000..9b3806e --- /dev/null +++ b/js/src/lirasm/tests/hardfloat/f2i.in @@ -0,0 +1,6 @@ +a = allocp 8 +d = immd 5.0 +std d a 0 +x = ldd a 0 +i = d2i x +reti i diff --git a/js/src/lirasm/tests/hardfloat/f2i.out b/js/src/lirasm/tests/hardfloat/f2i.out new file mode 100644 index 0000000..3af9482 --- /dev/null +++ b/js/src/lirasm/tests/hardfloat/f2i.out @@ -0,0 +1 @@ +Output is: 5 diff --git a/js/src/lirasm/tests/hardfloat/i2d.in b/js/src/lirasm/tests/hardfloat/i2d.in new file mode 100644 index 0000000..68c7759 --- /dev/null +++ b/js/src/lirasm/tests/hardfloat/i2d.in @@ -0,0 +1,24 @@ +; This test assumes that d2i and 32-bit integer arithmetic works properly. + +; Start with 0x80000000 +i1 = immi -2147483648 +d1 = i2d i1 +o1 = d2i d1 + +; Test with -1 +c2 = immi 2147483647 +i2 = addi o1 c2 +d2 = i2d i2 +o2 = d2i d2 + +; Test with 2147483647 +i3 = subi o2 i1 +d3 = i2d i3 +o3 = d2i d3 + +; Test with 0 +i4 = subi o3 c2 +d4 = i2d i4 +o4 = d2i d4 + +reti o4 diff --git a/js/src/lirasm/tests/hardfloat/i2d.out b/js/src/lirasm/tests/hardfloat/i2d.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/hardfloat/i2d.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/hardfloat/ui2d.in b/js/src/lirasm/tests/hardfloat/ui2d.in new file mode 100644 index 0000000..dcb8802 --- /dev/null +++ b/js/src/lirasm/tests/hardfloat/ui2d.in @@ -0,0 +1,5 @@ +i = immi -1 +d = ui2d i + +retd d + diff --git a/js/src/lirasm/tests/hardfloat/ui2d.out b/js/src/lirasm/tests/hardfloat/ui2d.out new file mode 100644 index 0000000..b34d0a3 --- /dev/null +++ b/js/src/lirasm/tests/hardfloat/ui2d.out @@ -0,0 +1 @@ +Output is: 4.29497e+09 diff --git a/js/src/lirasm/tests/ldc2i.in b/js/src/lirasm/tests/ldc2i.in new file mode 100644 index 0000000..8db7961 --- /dev/null +++ b/js/src/lirasm/tests/ldc2i.in @@ -0,0 +1,26 @@ +full = immi 1288908529 ; 0x4cd32ef1 +p = allocp 4 +sti full p 0 + +n0chk = immi -15 ; sign_extend(0xf1) +n1chk = immi 46 ; sign_extend(0x2e) +n2chk = immi -45 ; sign_extend(0xd3) +n3chk = immi 76 ; sign_extend(0x4c) + +n0 = ldc2i p 0 +n1 = ldc2i p 1 +n2 = ldc2i p 2 +n3 = ldc2i p 3 + +; Collate the results. +r0 = xori n0chk n0 +r1 = xori n1chk n1 +r2 = xori n2chk n2 +r3 = xori n3chk n3 + +r0_1 = ori r0 r1 +r2_3 = ori r2 r3 + +r = ori r0_1 r2_3 +reti r + diff --git a/js/src/lirasm/tests/ldc2i.out b/js/src/lirasm/tests/ldc2i.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/ldc2i.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/lds2i.in b/js/src/lirasm/tests/lds2i.in new file mode 100644 index 0000000..9546cb8 --- /dev/null +++ b/js/src/lirasm/tests/lds2i.in @@ -0,0 +1,17 @@ +full = immi -249334698 ; 0xf1237456 +p = allocp 4 +sti full p 0 + +n0chk = immi 29782 ; sign_extend(0x7456) +n1chk = immi -3805 ; sign_extend(0xf123) + +n0 = lds2i p 0 +n1 = lds2i p 2 + +; Collate the results. +r0 = xori n0chk n0 +r1 = xori n1chk n1 + +r = ori r0 r1 +reti r + diff --git a/js/src/lirasm/tests/lds2i.out b/js/src/lirasm/tests/lds2i.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/lds2i.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/lduc2ui.in b/js/src/lirasm/tests/lduc2ui.in new file mode 100644 index 0000000..3a4fb0d --- /dev/null +++ b/js/src/lirasm/tests/lduc2ui.in @@ -0,0 +1,26 @@ +full = immi -992746767 ; 0xc4d3e2f1 +p = allocp 4 +sti full p 0 + +n0chk = immi 241 ; 0xf1 +n1chk = immi 226 ; 0xe2 +n2chk = immi 211 ; 0xd3 +n3chk = immi 196 ; 0xc4 + +n0 = lduc2ui p 0 +n1 = lduc2ui p 1 +n2 = lduc2ui p 2 +n3 = lduc2ui p 3 + +; Collate the results. +r0 = xori n0chk n0 +r1 = xori n1chk n1 +r2 = xori n2chk n2 +r3 = xori n3chk n3 + +r0_1 = ori r0 r1 +r2_3 = ori r2 r3 + +r = ori r0_1 r2_3 +reti r + diff --git a/js/src/lirasm/tests/lduc2ui.out b/js/src/lirasm/tests/lduc2ui.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/lduc2ui.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/ldus2ui.in b/js/src/lirasm/tests/ldus2ui.in new file mode 100644 index 0000000..69811e7 --- /dev/null +++ b/js/src/lirasm/tests/ldus2ui.in @@ -0,0 +1,17 @@ +full = immi -249334698 ; 0xf1237456 +p = allocp 4 +sti full p 0 + +n0chk = immi 29782 ; sign_extend(0x7456) +n1chk = immi 61731 ; sign_extend(0xf123) + +n0 = ldus2ui p 0 +n1 = ldus2ui p 2 + +; Collate the results. +r0 = xori n0chk n0 +r1 = xori n1chk n1 + +r = ori r0 r1 +reti r + diff --git a/js/src/lirasm/tests/ldus2ui.out b/js/src/lirasm/tests/ldus2ui.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/ldus2ui.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/littleendian/fuzz-527178.in b/js/src/lirasm/tests/littleendian/fuzz-527178.in new file mode 100644 index 0000000..12403dd --- /dev/null +++ b/js/src/lirasm/tests/littleendian/fuzz-527178.in @@ -0,0 +1,5 @@ +base = allocp 512 +five = immi 5 +sti five base 256 +x = ldus2ui base 256 +reti x diff --git a/js/src/lirasm/tests/littleendian/fuzz-527178.out b/js/src/lirasm/tests/littleendian/fuzz-527178.out new file mode 100644 index 0000000..3af9482 --- /dev/null +++ b/js/src/lirasm/tests/littleendian/fuzz-527178.out @@ -0,0 +1 @@ +Output is: 5 diff --git a/js/src/lirasm/tests/littleendian/ldc2i.in b/js/src/lirasm/tests/littleendian/ldc2i.in new file mode 100644 index 0000000..8db7961 --- /dev/null +++ b/js/src/lirasm/tests/littleendian/ldc2i.in @@ -0,0 +1,26 @@ +full = immi 1288908529 ; 0x4cd32ef1 +p = allocp 4 +sti full p 0 + +n0chk = immi -15 ; sign_extend(0xf1) +n1chk = immi 46 ; sign_extend(0x2e) +n2chk = immi -45 ; sign_extend(0xd3) +n3chk = immi 76 ; sign_extend(0x4c) + +n0 = ldc2i p 0 +n1 = ldc2i p 1 +n2 = ldc2i p 2 +n3 = ldc2i p 3 + +; Collate the results. +r0 = xori n0chk n0 +r1 = xori n1chk n1 +r2 = xori n2chk n2 +r3 = xori n3chk n3 + +r0_1 = ori r0 r1 +r2_3 = ori r2 r3 + +r = ori r0_1 r2_3 +reti r + diff --git a/js/src/lirasm/tests/littleendian/ldc2i.out b/js/src/lirasm/tests/littleendian/ldc2i.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/littleendian/ldc2i.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/littleendian/lds2i.in b/js/src/lirasm/tests/littleendian/lds2i.in new file mode 100644 index 0000000..9546cb8 --- /dev/null +++ b/js/src/lirasm/tests/littleendian/lds2i.in @@ -0,0 +1,17 @@ +full = immi -249334698 ; 0xf1237456 +p = allocp 4 +sti full p 0 + +n0chk = immi 29782 ; sign_extend(0x7456) +n1chk = immi -3805 ; sign_extend(0xf123) + +n0 = lds2i p 0 +n1 = lds2i p 2 + +; Collate the results. +r0 = xori n0chk n0 +r1 = xori n1chk n1 + +r = ori r0 r1 +reti r + diff --git a/js/src/lirasm/tests/littleendian/lds2i.out b/js/src/lirasm/tests/littleendian/lds2i.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/littleendian/lds2i.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/littleendian/lduc2ui.in b/js/src/lirasm/tests/littleendian/lduc2ui.in new file mode 100644 index 0000000..3a4fb0d --- /dev/null +++ b/js/src/lirasm/tests/littleendian/lduc2ui.in @@ -0,0 +1,26 @@ +full = immi -992746767 ; 0xc4d3e2f1 +p = allocp 4 +sti full p 0 + +n0chk = immi 241 ; 0xf1 +n1chk = immi 226 ; 0xe2 +n2chk = immi 211 ; 0xd3 +n3chk = immi 196 ; 0xc4 + +n0 = lduc2ui p 0 +n1 = lduc2ui p 1 +n2 = lduc2ui p 2 +n3 = lduc2ui p 3 + +; Collate the results. +r0 = xori n0chk n0 +r1 = xori n1chk n1 +r2 = xori n2chk n2 +r3 = xori n3chk n3 + +r0_1 = ori r0 r1 +r2_3 = ori r2 r3 + +r = ori r0_1 r2_3 +reti r + diff --git a/js/src/lirasm/tests/littleendian/lduc2ui.out b/js/src/lirasm/tests/littleendian/lduc2ui.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/littleendian/lduc2ui.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/littleendian/ldus2ui.in b/js/src/lirasm/tests/littleendian/ldus2ui.in new file mode 100644 index 0000000..69811e7 --- /dev/null +++ b/js/src/lirasm/tests/littleendian/ldus2ui.in @@ -0,0 +1,17 @@ +full = immi -249334698 ; 0xf1237456 +p = allocp 4 +sti full p 0 + +n0chk = immi 29782 ; sign_extend(0x7456) +n1chk = immi 61731 ; sign_extend(0xf123) + +n0 = ldus2ui p 0 +n1 = ldus2ui p 2 + +; Collate the results. +r0 = xori n0chk n0 +r1 = xori n1chk n1 + +r = ori r0 r1 +reti r + diff --git a/js/src/lirasm/tests/littleendian/ldus2ui.out b/js/src/lirasm/tests/littleendian/ldus2ui.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/littleendian/ldus2ui.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/loadstore.in b/js/src/lirasm/tests/loadstore.in new file mode 100644 index 0000000..8f8911e --- /dev/null +++ b/js/src/lirasm/tests/loadstore.in @@ -0,0 +1,9 @@ +ptr = allocp 8 +five = immi 5 +sti five ptr 0 +three = immi 3 +sti three ptr 4 +v = ldi ptr 0 +u = ldi ptr 4 +res = addi u v +reti res diff --git a/js/src/lirasm/tests/loadstore.out b/js/src/lirasm/tests/loadstore.out new file mode 100644 index 0000000..c6b20cd --- /dev/null +++ b/js/src/lirasm/tests/loadstore.out @@ -0,0 +1 @@ +Output is: 8 diff --git a/js/src/lirasm/tests/mul_xxx.in b/js/src/lirasm/tests/mul_xxx.in new file mode 100644 index 0000000..2210ffd --- /dev/null +++ b/js/src/lirasm/tests/mul_xxx.in @@ -0,0 +1,6 @@ +; 46340 * 46340 < 2^31, and will not overflow. +big = immi 46340 + +res = muli big big + +reti res diff --git a/js/src/lirasm/tests/mul_xxx.out b/js/src/lirasm/tests/mul_xxx.out new file mode 100644 index 0000000..9a99d92 --- /dev/null +++ b/js/src/lirasm/tests/mul_xxx.out @@ -0,0 +1 @@ +Output is: 2147395600 diff --git a/js/src/lirasm/tests/mul_xxy.in b/js/src/lirasm/tests/mul_xxy.in new file mode 100644 index 0000000..75cb8d6 --- /dev/null +++ b/js/src/lirasm/tests/mul_xxy.in @@ -0,0 +1,7 @@ +; 1073741823 * 2 < 2^31, and will not overflow. +big = immi 1073741823 +two = immi 2 + +res = muli big two + +reti res diff --git a/js/src/lirasm/tests/mul_xxy.out b/js/src/lirasm/tests/mul_xxy.out new file mode 100644 index 0000000..2c181c6 --- /dev/null +++ b/js/src/lirasm/tests/mul_xxy.out @@ -0,0 +1 @@ +Output is: 2147483646 diff --git a/js/src/lirasm/tests/mul_xyy.in b/js/src/lirasm/tests/mul_xyy.in new file mode 100644 index 0000000..39d594f --- /dev/null +++ b/js/src/lirasm/tests/mul_xyy.in @@ -0,0 +1,10 @@ +; 46340 * 46340 < 2^31, and will not overflow. +big = immi 46340 + +res = muli big big + +; Ensure that 'big' gets its own register and isn't shared with 'res'. +m = allocp 8 +sti big m 0 + +reti res diff --git a/js/src/lirasm/tests/mul_xyy.out b/js/src/lirasm/tests/mul_xyy.out new file mode 100644 index 0000000..9a99d92 --- /dev/null +++ b/js/src/lirasm/tests/mul_xyy.out @@ -0,0 +1 @@ +Output is: 2147395600 diff --git a/js/src/lirasm/tests/mul_xyz.in b/js/src/lirasm/tests/mul_xyz.in new file mode 100644 index 0000000..864c301 --- /dev/null +++ b/js/src/lirasm/tests/mul_xyz.in @@ -0,0 +1,13 @@ +; 1073741823 * 2 < 2^31, and will not overflow. +big = immi 1073741823 +two = immi 2 + +res = muli big two + +; Ensure that 'big' and 'two' get their own registers and +; aren't shared with 'res'. +m = allocp 12 +sti big m 0 +sti two m 4 + +reti res diff --git a/js/src/lirasm/tests/mul_xyz.out b/js/src/lirasm/tests/mul_xyz.out new file mode 100644 index 0000000..2c181c6 --- /dev/null +++ b/js/src/lirasm/tests/mul_xyz.out @@ -0,0 +1 @@ +Output is: 2147483646 diff --git a/js/src/lirasm/tests/muld.in b/js/src/lirasm/tests/muld.in new file mode 100644 index 0000000..d4f5ea2 --- /dev/null +++ b/js/src/lirasm/tests/muld.in @@ -0,0 +1,31 @@ +; Try to exercise as many different possibilities for the register allocator as +; is feasible. + +p1 = allocp 8 +p2 = allocp 8 + +d1a = immd 2.0 +d1 = muld d1a d1a ; X = X * X +std d1 p1 0 + +d2a = immd 2.5 +d2b = immd 3.0 +d2 = muld d2a d2b ; X = X * Y +std d2b p2 0 +std d2 p2 0 + +d3a = ldd p1 0 +d3b = ldd p2 0 +d3 = muld d3a d3b ; X = Y * X +std d3a p2 0 +std d3 p2 0 + +d4a = ldd p2 0 +d4b = ldd p1 0 +d4 = muld d4a d4b ; X = Y * Z +std d4a p1 0 +std d4b p2 0 +std d4 p1 0 + +d = ldd p1 0 +retd d diff --git a/js/src/lirasm/tests/muld.out b/js/src/lirasm/tests/muld.out new file mode 100644 index 0000000..30488f0 --- /dev/null +++ b/js/src/lirasm/tests/muld.out @@ -0,0 +1 @@ +Output is: 120 diff --git a/js/src/lirasm/tests/muljovi.in b/js/src/lirasm/tests/muljovi.in new file mode 100644 index 0000000..1d5e17f --- /dev/null +++ b/js/src/lirasm/tests/muljovi.in @@ -0,0 +1,15 @@ + ptr = allocp 8 + + a = immi 65536 + b = immi 32767 + c = muljovi a b ovf + sti c ptr 0 + + j done + +ovf: i = immi 12345678 + sti i ptr 0 + +done: res = ldi ptr 0 + reti res + diff --git a/js/src/lirasm/tests/muljovi.out b/js/src/lirasm/tests/muljovi.out new file mode 100644 index 0000000..00047aa --- /dev/null +++ b/js/src/lirasm/tests/muljovi.out @@ -0,0 +1 @@ +Output is: 2147418112 diff --git a/js/src/lirasm/tests/muljovi_ovf.in b/js/src/lirasm/tests/muljovi_ovf.in new file mode 100644 index 0000000..97e2ffb --- /dev/null +++ b/js/src/lirasm/tests/muljovi_ovf.in @@ -0,0 +1,14 @@ + ptr = allocp 8 + + a = immi 65536 + b = immi 32768 + c = muljovi a b ovf + sti c ptr 0 + + j done + +ovf: i = immi 12345678 + sti i ptr 0 + +done: res = ldi ptr 0 + reti res diff --git a/js/src/lirasm/tests/muljovi_ovf.out b/js/src/lirasm/tests/muljovi_ovf.out new file mode 100644 index 0000000..5404b11 --- /dev/null +++ b/js/src/lirasm/tests/muljovi_ovf.out @@ -0,0 +1 @@ +Output is: 12345678 diff --git a/js/src/lirasm/tests/muljovi_xxx.in b/js/src/lirasm/tests/muljovi_xxx.in new file mode 100644 index 0000000..4bb0b8e --- /dev/null +++ b/js/src/lirasm/tests/muljovi_xxx.in @@ -0,0 +1,11 @@ + ; 46340 * 46340 < 2^31, and will not overflow. + big = immi 46340 + + res = muljovi big big err + + reti res + +; ---- Exit route for the error handler. + +err: e = immi -1 + reti e diff --git a/js/src/lirasm/tests/muljovi_xxx.out b/js/src/lirasm/tests/muljovi_xxx.out new file mode 100644 index 0000000..9a99d92 --- /dev/null +++ b/js/src/lirasm/tests/muljovi_xxx.out @@ -0,0 +1 @@ +Output is: 2147395600 diff --git a/js/src/lirasm/tests/muljovi_xxy.in b/js/src/lirasm/tests/muljovi_xxy.in new file mode 100644 index 0000000..faa8242 --- /dev/null +++ b/js/src/lirasm/tests/muljovi_xxy.in @@ -0,0 +1,12 @@ + ; 1073741823 * 2 < 2^31, and will not overflow. + big = immi 1073741823 + two = immi 2 + + res = muljovi big two err + + reti res + +; ---- Exit route for the error handler. + +err: e = immi -1 + reti e diff --git a/js/src/lirasm/tests/muljovi_xxy.out b/js/src/lirasm/tests/muljovi_xxy.out new file mode 100644 index 0000000..2c181c6 --- /dev/null +++ b/js/src/lirasm/tests/muljovi_xxy.out @@ -0,0 +1 @@ +Output is: 2147483646 diff --git a/js/src/lirasm/tests/muljovi_xyy.in b/js/src/lirasm/tests/muljovi_xyy.in new file mode 100644 index 0000000..79771d4 --- /dev/null +++ b/js/src/lirasm/tests/muljovi_xyy.in @@ -0,0 +1,15 @@ + ; 46340 * 46340 < 2^31, and will not overflow. + big = immi 46340 + + res = muljovi big big err + + ; Ensure that 'big' gets its own register and isn't shared with 'res'. + m = allocp 8 + sti big m 0 + + reti res + +; ---- Exit route for the error handler. + +err: e = immi -1 + reti e diff --git a/js/src/lirasm/tests/muljovi_xyy.out b/js/src/lirasm/tests/muljovi_xyy.out new file mode 100644 index 0000000..9a99d92 --- /dev/null +++ b/js/src/lirasm/tests/muljovi_xyy.out @@ -0,0 +1 @@ +Output is: 2147395600 diff --git a/js/src/lirasm/tests/muljovi_xyz.in b/js/src/lirasm/tests/muljovi_xyz.in new file mode 100644 index 0000000..e8dd92a --- /dev/null +++ b/js/src/lirasm/tests/muljovi_xyz.in @@ -0,0 +1,18 @@ + ; 1073741823 * 2 < 2^31, and will not overflow. + big = immi 1073741823 + two = immi 2 + + res = muljovi big two err + + ; Ensure that 'big' and 'two' get their own registers and + ; aren't shared with 'res'. + m = allocp 12 + sti big m 0 + sti two m 4 + + reti res + +; ---- Exit route for the error handler. + +err: e = immi -1 + reti e diff --git a/js/src/lirasm/tests/muljovi_xyz.out b/js/src/lirasm/tests/muljovi_xyz.out new file mode 100644 index 0000000..2c181c6 --- /dev/null +++ b/js/src/lirasm/tests/muljovi_xyz.out @@ -0,0 +1 @@ +Output is: 2147483646 diff --git a/js/src/lirasm/tests/mulov_xxx.in b/js/src/lirasm/tests/mulov_xxx.in new file mode 100644 index 0000000..97d2fd7 --- /dev/null +++ b/js/src/lirasm/tests/mulov_xxx.in @@ -0,0 +1,14 @@ +; 46341 * 46341 >= 2^31, and will overflow. +big = immi 46341 + +; Because 'big' isn't used after mul, it _may_ get allocated to the same +; register as 'res'. This is the case with the ARM back-end, and that is where +; this test is important as rX=rX*rX isn't possible on ARMv5 without some +; trickery. +res = mulxovi big big ; overflow, so we exit here + +; Store 'res' so it isn't dead. +m = allocp 4 +sti res m 0 +x ; we don't exit here + diff --git a/js/src/lirasm/tests/mulov_xxx.out b/js/src/lirasm/tests/mulov_xxx.out new file mode 100644 index 0000000..c5b8999 --- /dev/null +++ b/js/src/lirasm/tests/mulov_xxx.out @@ -0,0 +1 @@ +Exited block on line: 8 diff --git a/js/src/lirasm/tests/mulov_xxy.in b/js/src/lirasm/tests/mulov_xxy.in new file mode 100644 index 0000000..77db073 --- /dev/null +++ b/js/src/lirasm/tests/mulov_xxy.in @@ -0,0 +1,14 @@ +; 1073741824 * 2 >= 2^31, and will overflow. +big = immi 1073741824 +two = immi 2 + +; Because 'big' isn't used after mul, it _may_ get allocated to the same +; register as 'res'. This is the case with the ARM back-end, and that is where +; this test is important as rX=rX*rY isn't possible on ARMv5 without some +; trickery. +res = mulxovi big two ; overflow, so we exit here + +; Store 'res' so it isn't dead. +m = allocp 4 +sti res m 0 +x ; we don't exit here diff --git a/js/src/lirasm/tests/mulov_xxy.out b/js/src/lirasm/tests/mulov_xxy.out new file mode 100644 index 0000000..a648897 --- /dev/null +++ b/js/src/lirasm/tests/mulov_xxy.out @@ -0,0 +1 @@ +Exited block on line: 9 diff --git a/js/src/lirasm/tests/mulov_xyy.in b/js/src/lirasm/tests/mulov_xyy.in new file mode 100644 index 0000000..bde56db --- /dev/null +++ b/js/src/lirasm/tests/mulov_xyy.in @@ -0,0 +1,11 @@ +; 46341 * 46341 >= 2^31, and will overflow. +big = immi 46341 + +res = mulxovi big big ; overflow, so we exit here + +; Ensure that 'big' gets its own register and isn't shared with 'res'. +; Also store 'res' so it isn't dead. +m = allocp 8 +sti big m 0 +sti res m 4 +x ; we don't exit here diff --git a/js/src/lirasm/tests/mulov_xyy.out b/js/src/lirasm/tests/mulov_xyy.out new file mode 100644 index 0000000..ac1b199 --- /dev/null +++ b/js/src/lirasm/tests/mulov_xyy.out @@ -0,0 +1 @@ +Exited block on line: 4 diff --git a/js/src/lirasm/tests/mulov_xyz.in b/js/src/lirasm/tests/mulov_xyz.in new file mode 100644 index 0000000..4967440 --- /dev/null +++ b/js/src/lirasm/tests/mulov_xyz.in @@ -0,0 +1,13 @@ +; 1073741824 * 2 >= 2^31, and will overflow. +big = immi 1073741824 +two = immi 2 + +res = mulxovi big two ; overflow, so we exit here + +; Ensure that 'big' and 'two' get their own registers and +; aren't shared with 'res'. Also store 'res' so it isn't dead. +m = allocp 12 +sti big m 0 +sti two m 4 +sti res m 8 +x ; we don't exit here diff --git a/js/src/lirasm/tests/mulov_xyz.out b/js/src/lirasm/tests/mulov_xyz.out new file mode 100644 index 0000000..6fe165b --- /dev/null +++ b/js/src/lirasm/tests/mulov_xyz.out @@ -0,0 +1 @@ +Exited block on line: 5 diff --git a/js/src/lirasm/tests/multfrag1.in b/js/src/lirasm/tests/multfrag1.in new file mode 100644 index 0000000..fd97e1a --- /dev/null +++ b/js/src/lirasm/tests/multfrag1.in @@ -0,0 +1,27 @@ +.begin a +ptr = allocp 8 +a = immi 65 +sti2c a ptr 0 +b = immi 66 +sti2c b ptr 1 +c = immi 67 +sti2c c ptr 2 +zero = immi 0 +sti2c zero ptr 3 +ss = calli puts cdecl ptr +nn = gei ss zero +reti nn +.end + +.begin b +rr = calli a fastcall +reti rr +.end + +.begin main +ans = calli b fastcall +five = immi 5 +res = addi five ans +reti res +.end + diff --git a/js/src/lirasm/tests/multfrag1.out b/js/src/lirasm/tests/multfrag1.out new file mode 100644 index 0000000..40b88a2 --- /dev/null +++ b/js/src/lirasm/tests/multfrag1.out @@ -0,0 +1,2 @@ +ABC +Output is: 6 diff --git a/js/src/lirasm/tests/multfrag2.in b/js/src/lirasm/tests/multfrag2.in new file mode 100644 index 0000000..6a769a9 --- /dev/null +++ b/js/src/lirasm/tests/multfrag2.in @@ -0,0 +1,14 @@ +.begin sinpibytwo +pi = immd 3.14 +half = immd 0.5 +halfpi = muld pi half +res = calld sin cdecl halfpi +retd res +.end + +.begin main +aa = calld sinpibytwo fastcall +bb = immd 5.53 +res = addd aa bb +retd res +.end diff --git a/js/src/lirasm/tests/multfrag2.out b/js/src/lirasm/tests/multfrag2.out new file mode 100644 index 0000000..5beea1f --- /dev/null +++ b/js/src/lirasm/tests/multfrag2.out @@ -0,0 +1 @@ +Output is: 6.53 diff --git a/js/src/lirasm/tests/multfrag3.in b/js/src/lirasm/tests/multfrag3.in new file mode 100644 index 0000000..5fba3bd --- /dev/null +++ b/js/src/lirasm/tests/multfrag3.in @@ -0,0 +1,16 @@ +; See bug 541232 for why the params are commented out. +.begin avg +oneh = immi 100 ; should be: p1 = paramp 0 0 +twoh = immi 200 ; should be: p2 = paramp 1 0 +sum = addi oneh twoh ; should be: sum = addp p1 p2 +one = immi 1 +avg = rshi sum one +reti avg +.end + +.begin main +oneh = immi 100 +twoh = immi 200 +res = calli avg fastcall twoh oneh +reti res +.end diff --git a/js/src/lirasm/tests/multfrag3.out b/js/src/lirasm/tests/multfrag3.out new file mode 100644 index 0000000..1779f25 --- /dev/null +++ b/js/src/lirasm/tests/multfrag3.out @@ -0,0 +1 @@ +Output is: 150 diff --git a/js/src/lirasm/tests/negnot.in b/js/src/lirasm/tests/negnot.in new file mode 100644 index 0000000..8e6907a --- /dev/null +++ b/js/src/lirasm/tests/negnot.in @@ -0,0 +1,4 @@ +i = immi 0 +a = noti i +b = negi a +reti b diff --git a/js/src/lirasm/tests/negnot.out b/js/src/lirasm/tests/negnot.out new file mode 100644 index 0000000..25ee5c0 --- /dev/null +++ b/js/src/lirasm/tests/negnot.out @@ -0,0 +1 @@ +Output is: 1 diff --git a/js/src/lirasm/tests/random.out b/js/src/lirasm/tests/random.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/random.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/shi.in b/js/src/lirasm/tests/shi.in new file mode 100644 index 0000000..41bf051 --- /dev/null +++ b/js/src/lirasm/tests/shi.in @@ -0,0 +1,32 @@ +; Only the bottom 5 bits of the shift amount in lshi/rshi/rshui are used. + +two = immi 2 + +sh1 = immi 1 +sh2 = immi 33 ; 0010_0001b +sh3 = immi 268435425 ; 0000_1111_1111_1111_1111_1111_1110_0001b + +a1 = lshi two sh1 ; --> 4 +a2 = lshi two sh2 ; --> 4 +a3 = lshi two sh3 ; --> 4 + +b1 = rshi two sh1 ; --> 1 +b2 = rshi two sh2 ; --> 1 +b3 = rshi two sh3 ; --> 1 + +c1 = rshui two sh1 ; --> 1 +c2 = rshui two sh2 ; --> 1 +c3 = rshui two sh3 ; --> 1 + +s0 = immi 0 +s1 = addi s0 a1 +s2 = addi s1 a2 +s3 = addi s2 a3 +s4 = addi s3 b1 +s5 = addi s4 b2 +s6 = addi s5 b3 +s7 = addi s6 c1 +s8 = addi s7 c2 +s9 = addi s8 c2 ; --> 18 + +reti s9 diff --git a/js/src/lirasm/tests/shi.out b/js/src/lirasm/tests/shi.out new file mode 100644 index 0000000..5b7e775 --- /dev/null +++ b/js/src/lirasm/tests/shi.out @@ -0,0 +1 @@ +Output is: 18 diff --git a/js/src/lirasm/tests/softfloat/dhi2i.in b/js/src/lirasm/tests/softfloat/dhi2i.in new file mode 100644 index 0000000..89b7d55 --- /dev/null +++ b/js/src/lirasm/tests/softfloat/dhi2i.in @@ -0,0 +1,4 @@ +; IEEE-754 encodes -0.0 as 0x80000000,00000000 +d = immd -0.0 +hi = dhi2i d +reti hi diff --git a/js/src/lirasm/tests/softfloat/dhi2i.out b/js/src/lirasm/tests/softfloat/dhi2i.out new file mode 100644 index 0000000..b0b45d5 --- /dev/null +++ b/js/src/lirasm/tests/softfloat/dhi2i.out @@ -0,0 +1 @@ +Output is: -2147483648 diff --git a/js/src/lirasm/tests/softfloat/dlo2i.in b/js/src/lirasm/tests/softfloat/dlo2i.in new file mode 100644 index 0000000..cdf01dc --- /dev/null +++ b/js/src/lirasm/tests/softfloat/dlo2i.in @@ -0,0 +1,4 @@ +; IEEE-754 encodes the following constant as 0x3ff00000,ffffffff +d = immd 1.0000009536743162 +lo = dlo2i d +reti lo diff --git a/js/src/lirasm/tests/softfloat/dlo2i.out b/js/src/lirasm/tests/softfloat/dlo2i.out new file mode 100644 index 0000000..7bf0fb6 --- /dev/null +++ b/js/src/lirasm/tests/softfloat/dlo2i.out @@ -0,0 +1 @@ +Output is: -1 diff --git a/js/src/lirasm/tests/softfloat/ii2d.in b/js/src/lirasm/tests/softfloat/ii2d.in new file mode 100644 index 0000000..7189917 --- /dev/null +++ b/js/src/lirasm/tests/softfloat/ii2d.in @@ -0,0 +1,20 @@ +; It's very difficult to test that the 'lo' part is actually doing anything +; because it tends to get lost when lirasm dumps the result to the console. +; By far the easiest way to check this is to use dlo2i and dhi2i to see if we +; get what we started with (assuming that those instructions work). + +hi = immi 1127219201 ; 0x43300001 (positive, exponent of +52 ... +lo = immi -1 ; 0xffffffff (... mantissa of 0x100001ffffffff) +d = ii2d lo hi +hi2 = dhi2i d +lo2 = dlo2i d + +; XOR to check for differences, then OR the two results. 0 indicates success, +; but anything else indicates some kind of loss of data. +rhi = xori hi hi2 +rlo = xori lo lo2 + +res = ori rhi rlo + +reti res + diff --git a/js/src/lirasm/tests/softfloat/ii2d.out b/js/src/lirasm/tests/softfloat/ii2d.out new file mode 100644 index 0000000..e1b88ff --- /dev/null +++ b/js/src/lirasm/tests/softfloat/ii2d.out @@ -0,0 +1 @@ +Output is: 0 diff --git a/js/src/lirasm/tests/std2f.in b/js/src/lirasm/tests/std2f.in new file mode 100644 index 0000000..8f5f413 --- /dev/null +++ b/js/src/lirasm/tests/std2f.in @@ -0,0 +1,7 @@ +ptr = allocp 8 +d = immd -1 +; Store the value twice in consecutive slots to check that it's really stored as 32 bits. +std2f d ptr 4 +std2f d ptr 0 +d2 = ldf2d ptr 4 +retd d2 diff --git a/js/src/lirasm/tests/std2f.out b/js/src/lirasm/tests/std2f.out new file mode 100644 index 0000000..7bf0fb6 --- /dev/null +++ b/js/src/lirasm/tests/std2f.out @@ -0,0 +1 @@ +Output is: -1 diff --git a/js/src/lirasm/tests/subd.in b/js/src/lirasm/tests/subd.in new file mode 100644 index 0000000..9910861 --- /dev/null +++ b/js/src/lirasm/tests/subd.in @@ -0,0 +1,31 @@ +; Try to exercise as many different possibilities for the register allocator as +; is feasible. + +p1 = allocp 8 +p2 = allocp 8 + +d1a = immd 1.5 +d1 = subd d1a d1a ; X = X - X +std d1 p1 0 + +d2a = immd 2.5 +d2b = immd 3.0 +d2 = subd d2a d2b ; X = X - Y +std d2b p2 0 +std d2 p2 0 + +d3a = ldd p1 0 +d3b = ldd p2 0 +d3 = subd d3a d3b ; X = Y - X +std d3a p2 0 +std d3 p2 0 + +d4a = ldd p2 0 +d4b = ldd p1 0 +d4 = subd d4a d4b ; X = Y - Z +std d4a p1 0 +std d4b p2 0 +std d4 p1 0 + +d = ldd p1 0 +retd d diff --git a/js/src/lirasm/tests/subd.out b/js/src/lirasm/tests/subd.out new file mode 100644 index 0000000..8da73fb --- /dev/null +++ b/js/src/lirasm/tests/subd.out @@ -0,0 +1 @@ +Output is: 0.5 diff --git a/js/src/lirasm/tests/subjovi.in b/js/src/lirasm/tests/subjovi.in new file mode 100644 index 0000000..1b0cce5 --- /dev/null +++ b/js/src/lirasm/tests/subjovi.in @@ -0,0 +1,15 @@ + ptr = allocp 8 + + a = immi -2147483647 + b = immi 1 + c = subjovi a b ovf + sti c ptr 0 + + j done + +ovf: i = immi 12345678 + sti i ptr 0 + +done: res = ldi ptr 0 + reti res + diff --git a/js/src/lirasm/tests/subjovi.out b/js/src/lirasm/tests/subjovi.out new file mode 100644 index 0000000..b0b45d5 --- /dev/null +++ b/js/src/lirasm/tests/subjovi.out @@ -0,0 +1 @@ +Output is: -2147483648 diff --git a/js/src/lirasm/tests/subjovi_ovf.in b/js/src/lirasm/tests/subjovi_ovf.in new file mode 100644 index 0000000..6e0ac66 --- /dev/null +++ b/js/src/lirasm/tests/subjovi_ovf.in @@ -0,0 +1,14 @@ + ptr = allocp 8 + + a = immi -2147483647 + b = immi 2 + c = subjovi a b ovf + sti c ptr 0 + + j done + +ovf: i = immi 12345678 + sti i ptr 0 + +done: res = ldi ptr 0 + reti res diff --git a/js/src/lirasm/tests/subjovi_ovf.out b/js/src/lirasm/tests/subjovi_ovf.out new file mode 100644 index 0000000..5404b11 --- /dev/null +++ b/js/src/lirasm/tests/subjovi_ovf.out @@ -0,0 +1 @@ +Output is: 12345678 diff --git a/js/src/lock_sparcv8plus.il b/js/src/lock_sparcv8plus.il new file mode 100644 index 0000000..e7b55d5 --- /dev/null +++ b/js/src/lock_sparcv8plus.il @@ -0,0 +1,84 @@ +! +! ***** BEGIN LICENSE BLOCK ***** +! Version: MPL 1.1/GPL 2.0/LGPL 2.1 +! +! The contents of this file are subject to the Mozilla Public License Version +! 1.1 (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.mozilla.org/MPL/ +! +! Software distributed under the License is distributed on an "AS IS" basis, +! WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +! for the specific language governing rights and limitations under the +! License. +! +! The Original Code is Mozilla Communicator client code, released +! March 31, 1998. +! +! The Initial Developer of the Original Code is +! Netscape Communications Corporation. +! Portions created by the Initial Developer are Copyright (C) 1998-1999 +! the Initial Developer. All Rights Reserved. +! +! Contributor(s): +! +! Alternatively, the contents of this file may be used under the terms of +! either the GNU General Public License Version 2 or later (the "GPL"), or +! the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +! in which case the provisions of the GPL or the LGPL are applicable instead +! of those above. If you wish to allow use of your version of this file only +! under the terms of either the GPL or the LGPL, and not to allow others to +! use your version of this file under the terms of the MPL, indicate your +! decision by deleting the provisions above and replace them with the notice +! and other provisions required by the GPL or the LGPL. If you do not delete +! the provisions above, a recipient may use your version of this file under +! the terms of any one of the MPL, the GPL or the LGPL. +! +! ***** END LICENSE BLOCK ***** + +! +! atomic compare-and-swap routines for V8+ (ultrasparc) +! +! ====================================================================== +! +! Perform the sequence *a = b atomically with respect to previous value +! of a (a0). If *a==a0 then assign *a to b, all in one atomic operation. +! Returns 1 if assignment happened, and 0 otherwise. +! +! usage : old_val = compare_and_swap(address, oldval, newval) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [input] - the old value to compare with +! %o2 [input] - the new value to set for [%o0] +! %o3 [local] - work register +! ----------------------- +! ====================================================================== +! +! v8plus + + .inline NativeCompareAndSwap,3 + + stbar + cas [%o0],%o1,%o2 ! compare *w with old value and set to new if equal + cmp %o1,%o2 ! did we succeed? + be,a 1f ! yes + mov 1,%o0 ! return true (annulled when no jump) + mov 0,%o0 ! return false +1: + + .end + +! +! end +! +! ====================================================================== +! diff --git a/js/src/lock_sparcv9.il b/js/src/lock_sparcv9.il new file mode 100644 index 0000000..e87e065 --- /dev/null +++ b/js/src/lock_sparcv9.il @@ -0,0 +1,84 @@ +! +! ***** BEGIN LICENSE BLOCK ***** +! Version: MPL 1.1/GPL 2.0/LGPL 2.1 +! +! The contents of this file are subject to the Mozilla Public License Version +! 1.1 (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.mozilla.org/MPL/ +! +! Software distributed under the License is distributed on an "AS IS" basis, +! WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +! for the specific language governing rights and limitations under the +! License. +! +! The Original Code is Mozilla Communicator client code, released +! March 31, 1998. +! +! The Initial Developer of the Original Code is +! Netscape Communications Corporation. +! Portions created by the Initial Developer are Copyright (C) 1998-1999 +! the Initial Developer. All Rights Reserved. +! +! Contributor(s): +! +! Alternatively, the contents of this file may be used under the terms of +! either the GNU General Public License Version 2 or later (the "GPL"), or +! the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +! in which case the provisions of the GPL or the LGPL are applicable instead +! of those above. If you wish to allow use of your version of this file only +! under the terms of either the GPL or the LGPL, and not to allow others to +! use your version of this file under the terms of the MPL, indicate your +! decision by deleting the provisions above and replace them with the notice +! and other provisions required by the GPL or the LGPL. If you do not delete +! the provisions above, a recipient may use your version of this file under +! the terms of any one of the MPL, the GPL or the LGPL. +! +! ***** END LICENSE BLOCK ***** + +! +! atomic compare-and-swap routines for V9 (ultrasparc) +! +! ====================================================================== +! +! Perform the sequence *a = b atomically with respect to previous value +! of a (a0). If *a==a0 then assign *a to b, all in one atomic operation. +! Returns 1 if assignment happened, and 0 otherwise. +! +! usage : old_val = compare_and_swap(address, oldval, newval) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [input] - the old value to compare with +! %o2 [input] - the new value to set for [%o0] +! %o3 [local] - work register +! ----------------------- +! ====================================================================== +! +! v9 + + .inline NativeCompareAndSwap,3 + + stbar + casx [%o0],%o1,%o2 ! compare *w with old value and set to new if equal + cmp %o1,%o2 ! did we succeed? + be,a 1f ! yes + mov 1,%o0 ! return true (annulled when no jump) + mov 0,%o0 ! return false +1: + + .end + +! +! end +! +! ====================================================================== +! diff --git a/js/src/methodjit/BaseAssembler.h b/js/src/methodjit/BaseAssembler.h new file mode 100644 index 0000000..bc7cd97 --- /dev/null +++ b/js/src/methodjit/BaseAssembler.h @@ -0,0 +1,777 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_baseassembler_h__ && defined JS_METHODJIT +#define jsjaeger_baseassembler_h__ + +#include "jscntxt.h" +#include "jstl.h" +#include "assembler/assembler/MacroAssemblerCodeRef.h" +#include "assembler/assembler/MacroAssembler.h" +#include "assembler/assembler/LinkBuffer.h" +#include "assembler/moco/MocoStubs.h" +#include "methodjit/MethodJIT.h" +#include "methodjit/MachineRegs.h" +#include "CodeGenIncludes.h" +#include "jsobjinlines.h" +#include "jsscopeinlines.h" + +namespace js { +namespace mjit { + +class MaybeRegisterID { + typedef JSC::MacroAssembler::RegisterID RegisterID; + + public: + MaybeRegisterID() + : reg_(Registers::ReturnReg), set(false) + { } + + MaybeRegisterID(RegisterID reg) + : reg_(reg), set(true) + { } + + inline RegisterID reg() const { JS_ASSERT(set); return reg_; } + inline void setReg(const RegisterID r) { reg_ = r; set = true; } + inline bool isSet() const { return set; } + + MaybeRegisterID & operator =(const MaybeRegisterID &other) { + set = other.set; + reg_ = other.reg_; + return *this; + } + + MaybeRegisterID & operator =(RegisterID r) { + setReg(r); + return *this; + } + + private: + RegisterID reg_; + bool set; +}; + +// Represents an int32 property name in generated code, which must be either +// a RegisterID or a constant value. +struct Int32Key { + typedef JSC::MacroAssembler::RegisterID RegisterID; + + MaybeRegisterID reg_; + int32 index_; + + Int32Key() : index_(0) { } + + static Int32Key FromRegister(RegisterID reg) { + Int32Key key; + key.reg_ = reg; + return key; + } + static Int32Key FromConstant(int32 index) { + Int32Key key; + key.index_ = index; + return key; + } + + int32 index() const { + JS_ASSERT(!reg_.isSet()); + return index_; + } + + RegisterID reg() const { return reg_.reg(); } + bool isConstant() const { return !reg_.isSet(); } +}; + +class MaybeJump { + typedef JSC::MacroAssembler::Jump Jump; + public: + MaybeJump() + : set(false) + { } + + inline Jump getJump() const { JS_ASSERT(set); return jump; } + inline Jump get() const { JS_ASSERT(set); return jump; } + inline void setJump(const Jump &j) { jump = j; set = true; } + inline bool isSet() const { return set; } + + inline MaybeJump &operator=(Jump j) { setJump(j); return *this; } + + private: + Jump jump; + bool set; +}; + +struct FrameAddress : JSC::MacroAssembler::Address +{ + FrameAddress(int32 offset) + : Address(JSC::MacroAssembler::stackPointerRegister, offset) + { } +}; + +struct ImmIntPtr : public JSC::MacroAssembler::ImmPtr +{ + ImmIntPtr(intptr_t val) + : ImmPtr(reinterpret_cast(val)) + { } +}; + +struct StackMarker { + uint32 base; + uint32 bytes; + + StackMarker(uint32 base, uint32 bytes) + : base(base), bytes(bytes) + { } +}; + +class Assembler : public ValueAssembler +{ + struct CallPatch { + CallPatch(Call cl, void *fun) + : call(cl), fun(fun) + { } + + Call call; + JSC::FunctionPtr fun; + }; + + /* Need a temp reg that is not ArgReg1. */ +#if defined(JS_CPU_X86) || defined(JS_CPU_X64) + static const RegisterID ClobberInCall = JSC::X86Registers::ecx; +#elif defined(JS_CPU_ARM) + static const RegisterID ClobberInCall = JSC::ARMRegisters::r2; +#endif + + /* :TODO: OOM */ + Label startLabel; + Vector callPatches; + + // Registers that can be clobbered during a call sequence. + Registers availInCall; + + // Extra number of bytes that can be used for storing structs/references + // across calls. + uint32 extraStackSpace; + + // Calling convention used by the currently in-progress call. + Registers::CallConvention callConvention; + + // Amount of stack space reserved for the currently in-progress call. This + // includes alignment and parameters. + uint32 stackAdjust; + + // Debug flag to make sure calls do not nest. +#ifdef DEBUG + bool callIsAligned; +#endif + + public: + Assembler() + : callPatches(SystemAllocPolicy()), + extraStackSpace(0), + stackAdjust(0) +#ifdef DEBUG + , callIsAligned(false) +#endif + { + startLabel = label(); + } + + /* Total number of floating-point registers. */ + static const uint32 TotalFPRegisters = FPRegisters::TotalFPRegisters; + + /* Register pair storing returned type/data for calls. */ +#if defined(JS_CPU_X86) || defined(JS_CPU_X64) +static const JSC::MacroAssembler::RegisterID JSReturnReg_Type = JSC::X86Registers::ecx; +static const JSC::MacroAssembler::RegisterID JSReturnReg_Data = JSC::X86Registers::edx; +static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::X86Registers::ecx; +#elif defined(JS_CPU_ARM) +static const JSC::MacroAssembler::RegisterID JSReturnReg_Type = JSC::ARMRegisters::r2; +static const JSC::MacroAssembler::RegisterID JSReturnReg_Data = JSC::ARMRegisters::r1; +static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::ARMRegisters::r1; +#endif + + size_t distanceOf(Label l) { + return differenceBetween(startLabel, l); + } + + void load32FromImm(void *ptr, RegisterID reg) { + load32(ptr, reg); + } + + void loadShape(RegisterID obj, RegisterID shape) { + load32(Address(obj, offsetof(JSObject, objShape)), shape); + } + + Jump guardShape(RegisterID objReg, JSObject *obj) { + return branch32(NotEqual, Address(objReg, offsetof(JSObject, objShape)), + Imm32(obj->shape())); + } + + Jump testFunction(Condition cond, RegisterID fun) { + return branchPtr(cond, Address(fun, offsetof(JSObject, clasp)), + ImmPtr(&js_FunctionClass)); + } + + /* + * Finds and returns the address of a known object and slot. + */ + Address objSlotRef(JSObject *obj, RegisterID reg, uint32 slot) { + move(ImmPtr(&obj->slots), reg); + loadPtr(reg, reg); + return Address(reg, slot * sizeof(Value)); + } + +#ifdef JS_CPU_X86 + void idiv(RegisterID reg) { + m_assembler.cdq(); + m_assembler.idivl_r(reg); + } +#endif + + /* Prepare for a call that might THROW. */ + void *getFallibleCallTarget(void *fun) { +#ifdef JS_CPU_ARM + /* + * Insert a veneer for ARM to allow it to catch exceptions. There is no + * reliable way to determine the location of the return address on the + * stack, so a typical C(++) return address cannot be hijacked. + * + * We put the real target address into IP, as this won't conflict with + * the EABI argument-passing mechanism. JaegerStubVeneer is responsible + * for calling 'fun' (in IP) and catching exceptions. + * + * Note that we must use 'moveWithPatch' here, rather than 'move', + * because 'move' might try to optimize the constant load, and we need a + * consistent code sequence for patching. + */ + moveWithPatch(Imm32(intptr_t(fun)), JSC::ARMRegisters::ip); + + return JS_FUNC_TO_DATA_PTR(void *, JaegerStubVeneer); +#else + /* + * Architectures that push the return address to an easily-determined + * location on the stack can hijack C++'s return mechanism by overwriting + * that address, so a veneer is not required. + */ + return fun; +#endif + } + + static inline uint32 align(uint32 bytes, uint32 alignment) { + return (alignment - (bytes % alignment)) % alignment; + } + + // Specifies extra stack space that is available across a call, for storing + // large parameters (structs) or returning values via references. All extra + // stack space must be reserved up-front, and is aligned on an 8-byte + // boundary. + // + // Returns an offset that can be used to index into this stack + StackMarker allocStack(uint32 bytes, uint32 alignment = 4) { + bytes += align(bytes + extraStackSpace, alignment); + subPtr(Imm32(bytes), stackPointerRegister); + extraStackSpace += bytes; + return StackMarker(extraStackSpace, bytes); + } + + // Similar to allocStack(), but combines it with a push(). + void saveReg(RegisterID reg) { + push(reg); + extraStackSpace += sizeof(void *); + } + + // Similar to freeStack(), but combines it with a pop(). + void restoreReg(RegisterID reg) { + JS_ASSERT(extraStackSpace >= sizeof(void *)); + extraStackSpace -= sizeof(void *); + pop(reg); + } + + static const uint32 StackAlignment = 16; + + static inline uint32 alignForCall(uint32 stackBytes) { +#if defined(JS_CPU_X86) || defined(JS_CPU_X64) + // If StackAlignment is a power of two, % is just two shifts. + // 16 - (x % 16) gives alignment, extra % 16 handles total == 0. + return align(stackBytes, StackAlignment); +#else + return 0; +#endif + } + + // Some platforms require stack manipulation before making stub calls. + // When using THROW/V, the return address is replaced, meaning the + // stack de-adjustment will not have occured. JaegerThrowpoline accounts + // for this. For stub calls, which are always invoked as if they use + // two parameters, the stack adjustment is constant. + // + // When using callWithABI() manually, for example via an IC, it might + // be necessary to jump directly to JaegerThrowpoline. In this case, + // the constant is provided here in order to appropriately adjust the + // stack. +#ifdef _WIN64 + static const uint32 ReturnStackAdjustment = 32; +#elif defined(JS_CPU_X86) && defined(JS_NO_FASTCALL) + static const uint32 ReturnStackAdjustment = 16; +#else + static const uint32 ReturnStackAdjustment = 0; +#endif + + void throwInJIT() { + if (ReturnStackAdjustment) + subPtr(Imm32(ReturnStackAdjustment), stackPointerRegister); + move(ImmPtr(JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline)), Registers::ReturnReg); + jump(Registers::ReturnReg); + } + + // Windows x64 requires extra space in between calls. +#ifdef _WIN64 + static const uint32 ShadowStackSpace = 32; +#else + static const uint32 ShadowStackSpace = 0; +#endif + + // Prepare the stack for a call sequence. This must be called AFTER all + // volatile regs have been saved, and BEFORE pushArg() is used. The stack + // is assumed to be aligned to 16-bytes plus any pushes that occured via + // saveRegs(). + // + // During a call sequence all registers are "owned" by the Assembler. + // Attempts to perform loads, nested calls, or anything that can clobber + // a register, is asking for breaking on some platform or some situation. + // Be careful to limit to storeArg() during setupABICall. + void setupABICall(Registers::CallConvention convention, uint32 generalArgs) { + JS_ASSERT(!callIsAligned); + + uint32 numArgRegs = Registers::numArgRegs(convention); + uint32 pushCount = (generalArgs > numArgRegs) + ? generalArgs - numArgRegs + : 0; + + // Assume all temporary regs are available to clobber. + availInCall = Registers::TempRegs; + + // Find the total number of bytes the stack will have been adjusted by, + // in order to compute alignment. + uint32 total = (pushCount * sizeof(void *)) + + extraStackSpace; + + stackAdjust = (pushCount * sizeof(void *)) + + alignForCall(total); + +#ifdef _WIN64 + // Windows x64 ABI requires 32 bytes of "shadow space" for the callee + // to spill its parameters. + stackAdjust += ShadowStackSpace; +#endif + + if (stackAdjust) + subPtr(Imm32(stackAdjust), stackPointerRegister); + + callConvention = convention; +#ifdef DEBUG + callIsAligned = true; +#endif + } + + // Computes an interior pointer into VMFrame during a call. + Address vmFrameOffset(uint32 offs) { + return Address(stackPointerRegister, stackAdjust + extraStackSpace + offs); + } + + // Get an Address to the extra space already allocated before the call. + Address addressOfExtra(const StackMarker &marker) { + // Stack looks like this: + // extraStackSpace + // stackAdjust + // To get to the requested offset into extraStackSpace, we can walk + // up to the top of the extra stack space, then subtract |offs|. + // + // Note that it's not required we're in a call - stackAdjust can be 0. + JS_ASSERT(marker.base <= extraStackSpace); + return Address(stackPointerRegister, stackAdjust + extraStackSpace - marker.base); + } + + // This is an internal function only for use inside a setupABICall(), + // callWithABI() sequence, and only for arguments known to fit in + // registers. + Address addressOfArg(uint32 i) { + uint32 numArgRegs = Registers::numArgRegs(callConvention); + JS_ASSERT(i >= numArgRegs); + + // Note that shadow space is for the callee to spill, and thus it must + // be skipped when writing its arguments. + int32 spOffset = ((i - numArgRegs) * sizeof(void *)) + ShadowStackSpace; + return Address(stackPointerRegister, spOffset); + } + + // Push an argument for a call. + void storeArg(uint32 i, RegisterID reg) { + JS_ASSERT(callIsAligned); + RegisterID to; + if (Registers::regForArg(callConvention, i, &to)) { + if (reg != to) + move(reg, to); + availInCall.takeRegUnchecked(to); + } else { + storePtr(reg, addressOfArg(i)); + } + } + + // This variant can clobber temporary registers. However, it will NOT + // clobber any registers that have already been set via storeArg(). + void storeArg(uint32 i, Address address) { + JS_ASSERT(callIsAligned); + RegisterID to; + if (Registers::regForArg(callConvention, i, &to)) { + loadPtr(address, to); + availInCall.takeRegUnchecked(to); + } else if (!availInCall.empty()) { + // Memory-to-memory, and there is a temporary register free. + RegisterID reg = availInCall.takeAnyReg(); + loadPtr(address, reg); + storeArg(i, reg); + availInCall.putReg(reg); + } else { + // Memory-to-memory, but no temporary registers are free. + // This shouldn't happen on any platforms, because + // (TempRegs) Union (ArgRegs) != 0 + JS_NOT_REACHED("too much reg pressure"); + } + } + + // This variant can clobber temporary registers. However, it will NOT + // clobber any registers that have already been set via storeArg(). + void storeArgAddr(uint32 i, Address address) { + JS_ASSERT(callIsAligned); + RegisterID to; + if (Registers::regForArg(callConvention, i, &to)) { + lea(address, to); + availInCall.takeRegUnchecked(to); + } else if (!availInCall.empty()) { + // Memory-to-memory, and there is a temporary register free. + RegisterID reg = availInCall.takeAnyReg(); + lea(address, reg); + storeArg(i, reg); + availInCall.putReg(reg); + } else { + // Memory-to-memory, but no temporary registers are free. + // This shouldn't happen on any platforms, because + // (TempRegs) Union (ArgRegs) != 0 + JS_NOT_REACHED("too much reg pressure"); + } + } + + void storeArg(uint32 i, Imm32 imm) { + JS_ASSERT(callIsAligned); + RegisterID to; + if (Registers::regForArg(callConvention, i, &to)) { + move(imm, to); + availInCall.takeRegUnchecked(to); + } else { + store32(imm, addressOfArg(i)); + } + } + + // High-level call helper, given an optional function pointer and a + // calling convention. setupABICall() must have been called beforehand, + // as well as each numbered argument stored with storeArg(). + // + // After callWithABI(), the call state is reset, so a new call may begin. + Call callWithABI(void *fun, bool canThrow) { + // [Bug 614953]: This can only be made conditional once the ARM back-end + // is able to distinguish and patch both call sequences. Other + // architecutres are unaffected regardless. + //if (canThrow) { + // Some platforms (such as ARM) require a call veneer if the target + // might THROW. For other platforms, getFallibleCallTarget does + // nothing. + fun = getFallibleCallTarget(fun); + //} + + JS_ASSERT(callIsAligned); + + Call cl = call(); + callPatches.append(CallPatch(cl, fun)); + + if (stackAdjust) + addPtr(Imm32(stackAdjust), stackPointerRegister); + + stackAdjust = 0; + +#ifdef DEBUG + callIsAligned = false; +#endif + return cl; + } + + // Frees stack space allocated by allocStack(). + void freeStack(const StackMarker &mark) { + JS_ASSERT(!callIsAligned); + JS_ASSERT(mark.bytes <= extraStackSpace); + + extraStackSpace -= mark.bytes; + addPtr(Imm32(mark.bytes), stackPointerRegister); + } + + // Wrap AbstractMacroAssembler::getLinkerCallReturnOffset which is protected. + unsigned callReturnOffset(Call call) { + return getLinkerCallReturnOffset(call); + } + + +#define STUB_CALL_TYPE(type) \ + Call callWithVMFrame(type stub, jsbytecode *pc, uint32 fd) { \ + return fallibleVMCall(JS_FUNC_TO_DATA_PTR(void *, stub), pc, fd); \ + } + + STUB_CALL_TYPE(JSObjStub); + STUB_CALL_TYPE(VoidPtrStubUInt32); + STUB_CALL_TYPE(VoidStubUInt32); + STUB_CALL_TYPE(VoidStub); + +#undef STUB_CALL_TYPE + + void setupInfallibleVMFrame(int32 frameDepth) { + // |frameDepth < 0| implies ic::SplatApplyArgs has been called which + // means regs.sp has already been set in the VMFrame. + if (frameDepth >= 0) { + // sp = fp->slots() + frameDepth + // regs->sp = sp + addPtr(Imm32(sizeof(JSStackFrame) + frameDepth * sizeof(jsval)), + JSFrameReg, + ClobberInCall); + storePtr(ClobberInCall, FrameAddress(offsetof(VMFrame, regs.sp))); + } + + // The JIT has moved Arg1 already, and we've guaranteed to not clobber + // it. Move ArgReg0 into place now. setupFallibleVMFrame will not + // clobber it either. + move(MacroAssembler::stackPointerRegister, Registers::ArgReg0); + } + + void setupFallibleVMFrame(jsbytecode *pc, int32 frameDepth) { + setupInfallibleVMFrame(frameDepth); + + /* regs->fp = fp */ + storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp))); + + /* PC -> regs->pc :( */ + storePtr(ImmPtr(pc), + FrameAddress(offsetof(VMFrame, regs) + offsetof(JSFrameRegs, pc))); + } + + // An infallible VM call is a stub call (taking a VMFrame & and one + // optional parameter) that does not need |pc| and |fp| updated, since + // the call is guaranteed to not fail. However, |sp| is always coherent. + Call infallibleVMCall(void *ptr, int32 frameDepth) { + setupInfallibleVMFrame(frameDepth); + return wrapVMCall(ptr); + } + + // A fallible VM call is a stub call (taking a VMFrame & and one optional + // parameter) that needs the entire VMFrame to be coherent, meaning that + // |pc| and |fp| are guaranteed to be up-to-date. + Call fallibleVMCall(void *ptr, jsbytecode *pc, int32 frameDepth) { + setupFallibleVMFrame(pc, frameDepth); + return wrapVMCall(ptr); + } + + Call wrapVMCall(void *ptr) { + JS_ASSERT(!callIsAligned); + + // Every stub call has at most two arguments. + setupABICall(Registers::FastCall, 2); + + // On x86, if JS_NO_FASTCALL is present, these will result in actual + // pushes to the stack, which the caller will clean up. Otherwise, + // they'll be ignored because the registers fit into the calling + // sequence. + storeArg(0, Registers::ArgReg0); + storeArg(1, Registers::ArgReg1); + + // [Bug 614953]: The second argument, 'canThrow', can be set to 'false' + // for infallibleVMCall invocations. However, this changes the call + // sequence on ARM, and the ARM repatcher cannot currently distinguish + // between the two sequences. The argument does not affect the code + // generated by x86 or amd64. + return callWithABI(ptr, true); + } + + void finalize(JSC::LinkBuffer &linker) { + for (size_t i = 0; i < callPatches.length(); i++) { + CallPatch &patch = callPatches[i]; + linker.link(patch.call, JSC::FunctionPtr(patch.fun)); + } + } + + struct FastArrayLoadFails { + Jump rangeCheck; + Jump holeCheck; + }; + + Jump guardArrayCapacity(RegisterID objReg, const Int32Key &key) { + Address capacity(objReg, offsetof(JSObject, capacity)); + if (key.isConstant()) { + JS_ASSERT(key.index() >= 0); + return branch32(BelowOrEqual, payloadOf(capacity), Imm32(key.index())); + } + return branch32(BelowOrEqual, payloadOf(capacity), key.reg()); + } + + // Load a jsval from an array slot, given a key. |objReg| is clobbered. + FastArrayLoadFails fastArrayLoad(RegisterID objReg, const Int32Key &key, + RegisterID typeReg, RegisterID dataReg) { + JS_ASSERT(objReg != typeReg); + + FastArrayLoadFails fails; + fails.rangeCheck = guardArrayCapacity(objReg, key); + + RegisterID dslotsReg = objReg; + loadPtr(Address(objReg, offsetof(JSObject, slots)), dslotsReg); + + // Load the slot out of the array. + if (key.isConstant()) { + Address slot(objReg, key.index() * sizeof(Value)); + fails.holeCheck = fastArrayLoadSlot(slot, typeReg, dataReg); + } else { + BaseIndex slot(objReg, key.reg(), JSVAL_SCALE); + fails.holeCheck = fastArrayLoadSlot(slot, typeReg, dataReg); + } + + return fails; + } + + void loadObjClass(RegisterID objReg, RegisterID destReg) { + loadPtr(Address(objReg, offsetof(JSObject, clasp)), destReg); + } + + Jump testClass(Condition cond, RegisterID claspReg, js::Class *clasp) { + return branchPtr(cond, claspReg, ImmPtr(clasp)); + } + + Jump testObjClass(Condition cond, RegisterID objReg, js::Class *clasp) { + return branchPtr(cond, Address(objReg, offsetof(JSObject, clasp)), ImmPtr(clasp)); + } + + void rematPayload(const StateRemat &remat, RegisterID reg) { + if (remat.inMemory()) + loadPayload(remat.address(), reg); + else + move(remat.reg(), reg); + } + + void loadDynamicSlot(RegisterID objReg, uint32 slot, + RegisterID typeReg, RegisterID dataReg) { + loadPtr(Address(objReg, offsetof(JSObject, slots)), dataReg); + loadValueAsComponents(Address(dataReg, slot * sizeof(Value)), typeReg, dataReg); + } + + void loadObjProp(JSObject *obj, RegisterID objReg, + const js::Shape *shape, + RegisterID typeReg, RegisterID dataReg) + { + if (shape->isMethod()) + loadValueAsComponents(ObjectValue(shape->methodObject()), typeReg, dataReg); + else if (obj->hasSlotsArray()) + loadDynamicSlot(objReg, shape->slot, typeReg, dataReg); + else + loadInlineSlot(objReg, shape->slot, typeReg, dataReg); + } + + static uint32 maskAddress(Address address) { + return Registers::maskReg(address.base); + } + + static uint32 maskAddress(BaseIndex address) { + return Registers::maskReg(address.base) | + Registers::maskReg(address.index); + } +}; + +/* Return f if the script is strict mode code, f otherwise. */ +#define STRICT_VARIANT(f) \ + (FunctionTemplateConditional(script->strictModeCode, \ + f, f)) + +/* Save some typing. */ +static const JSC::MacroAssembler::RegisterID JSReturnReg_Type = Assembler::JSReturnReg_Type; +static const JSC::MacroAssembler::RegisterID JSReturnReg_Data = Assembler::JSReturnReg_Data; +static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = Assembler::JSParamReg_Argc; + +struct FrameFlagsAddress : JSC::MacroAssembler::Address +{ + FrameFlagsAddress() + : Address(JSFrameReg, JSStackFrame::offsetOfFlags()) + {} +}; + +class PreserveRegisters { + typedef JSC::MacroAssembler::RegisterID RegisterID; + + Assembler &masm; + uint32 count; + RegisterID regs[JSC::MacroAssembler::TotalRegisters]; + + public: + PreserveRegisters(Assembler &masm) : masm(masm), count(0) { } + ~PreserveRegisters() { JS_ASSERT(!count); } + + void preserve(Registers mask) { + JS_ASSERT(!count); + + while (!mask.empty()) { + RegisterID reg = mask.takeAnyReg(); + regs[count++] = reg; + masm.saveReg(reg); + } + } + + void restore() { + while (count) + masm.restoreReg(regs[--count]); + } +}; + +} /* namespace mjit */ +} /* namespace js */ + +#endif + diff --git a/js/src/methodjit/BaseCompiler.h b/js/src/methodjit/BaseCompiler.h new file mode 100644 index 0000000..0d61870 --- /dev/null +++ b/js/src/methodjit/BaseCompiler.h @@ -0,0 +1,290 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#if !defined jsjaeger_compilerbase_h__ && defined JS_METHODJIT +#define jsjaeger_compilerbase_h__ + +#include "jscntxt.h" +#include "jstl.h" +#include "assembler/assembler/MacroAssembler.h" +#include "assembler/assembler/LinkBuffer.h" +#include "assembler/assembler/RepatchBuffer.h" +#include "assembler/jit/ExecutableAllocator.h" +#include + +#if defined JS_CPU_ARM +# define POST_INST_OFFSET(__expr) ((__expr) - sizeof(ARMWord)) +#else +# define POST_INST_OFFSET(__expr) (__expr) +#endif + +namespace js { +namespace mjit { + +struct MacroAssemblerTypedefs { + typedef JSC::MacroAssembler::Label Label; + typedef JSC::MacroAssembler::Imm32 Imm32; + typedef JSC::MacroAssembler::ImmPtr ImmPtr; + typedef JSC::MacroAssembler::RegisterID RegisterID; + typedef JSC::MacroAssembler::FPRegisterID FPRegisterID; + typedef JSC::MacroAssembler::Address Address; + typedef JSC::MacroAssembler::BaseIndex BaseIndex; + typedef JSC::MacroAssembler::AbsoluteAddress AbsoluteAddress; + typedef JSC::MacroAssembler MacroAssembler; + typedef JSC::MacroAssembler::Jump Jump; + typedef JSC::MacroAssembler::JumpList JumpList; + typedef JSC::MacroAssembler::Call Call; + typedef JSC::MacroAssembler::DataLabelPtr DataLabelPtr; + typedef JSC::MacroAssembler::DataLabel32 DataLabel32; + typedef JSC::FunctionPtr FunctionPtr; + typedef JSC::RepatchBuffer RepatchBuffer; + typedef JSC::CodeLocationLabel CodeLocationLabel; + typedef JSC::CodeLocationDataLabel32 CodeLocationDataLabel32; + typedef JSC::CodeLocationJump CodeLocationJump; + typedef JSC::CodeLocationCall CodeLocationCall; + typedef JSC::CodeLocationInstruction CodeLocationInstruction; + typedef JSC::ReturnAddressPtr ReturnAddressPtr; + typedef JSC::MacroAssemblerCodePtr MacroAssemblerCodePtr; + typedef JSC::JITCode JITCode; +#if defined JS_CPU_ARM + typedef JSC::ARMWord ARMWord; +#endif +}; + +class BaseCompiler : public MacroAssemblerTypedefs +{ + protected: + JSContext *cx; + + public: + BaseCompiler() : cx(NULL) + { } + + BaseCompiler(JSContext *cx) : cx(cx) + { } + + protected: + + JSC::ExecutablePool * + getExecPool(JSScript *script, size_t size) { + return BaseCompiler::GetExecPool(cx, script, size); + } + + public: + static JSC::ExecutablePool * + GetExecPool(JSContext *cx, JSScript *script, size_t size) { + JaegerCompartment *jc = script->compartment->jaegerCompartment; + JSC::ExecutablePool *pool = jc->poolForSize(size); + if (!pool) + js_ReportOutOfMemory(cx); + return pool; + } +}; + +// This class wraps JSC::LinkBuffer for Mozilla-specific memory handling. +// Every return |false| guarantees an OOM that has been correctly propagated, +// and should continue to propagate. +class LinkerHelper : public JSC::LinkBuffer +{ + protected: + Assembler &masm; +#ifdef DEBUG + bool verifiedRange; +#endif + + public: + LinkerHelper(Assembler &masm) : masm(masm) +#ifdef DEBUG + , verifiedRange(false) +#endif + { } + + ~LinkerHelper() { + JS_ASSERT(verifiedRange); + } + + bool verifyRange(const JSC::JITCode &other) { +#ifdef DEBUG + verifiedRange = true; +#endif +#ifdef JS_CPU_X64 + uintptr_t lowest = JS_MIN(uintptr_t(m_code), uintptr_t(other.start())); + + uintptr_t myEnd = uintptr_t(m_code) + m_size; + uintptr_t otherEnd = uintptr_t(other.start()) + other.size(); + uintptr_t highest = JS_MAX(myEnd, otherEnd); + + return (highest - lowest < INT_MAX); +#else + return true; +#endif + } + + bool verifyRange(JITScript *jit) { + return verifyRange(JSC::JITCode(jit->code.m_code.executableAddress(), jit->code.m_size)); + } + + JSC::ExecutablePool *init(JSContext *cx) { + // The pool is incref'd after this call, so it's necessary to release() + // on any failure. + JSScript *script = cx->fp()->script(); + JSC::ExecutablePool *ep = BaseCompiler::GetExecPool(cx, script, masm.size()); + if (!ep) + return ep; + + m_code = executableCopy(masm, ep); + if (!m_code) { + ep->release(); + js_ReportOutOfMemory(cx); + return NULL; + } + m_size = masm.size(); // must come after the call to executableCopy() + return ep; + } + + JSC::CodeLocationLabel finalize() { + masm.finalize(*this); + return finalizeCodeAddendum(); + } + + void maybeLink(MaybeJump jump, JSC::CodeLocationLabel label) { + if (!jump.isSet()) + return; + link(jump.get(), label); + } + + size_t size() const { + return m_size; + } +}; + +/* + * On ARM, we periodically flush a constant pool into the instruction stream + * where constants are found using PC-relative addressing. This is necessary + * because the fixed-width instruction set doesn't support wide immediates. + * + * ICs perform repatching on the inline (fast) path by knowing small and + * generally fixed code location offset values where the patchable instructions + * live. Dumping a huge constant pool into the middle of an IC's inline path + * makes the distance between emitted instructions potentially variable and/or + * large, which makes the IC offsets invalid. We must reserve contiguous space + * up front to prevent this from happening. + */ +#ifdef JS_CPU_ARM +template +class AutoReserveICSpace { + typedef Assembler::Label Label; + + Assembler &masm; +#ifdef DEBUG + Label startLabel; + bool didCheck; +#endif + + public: + AutoReserveICSpace(Assembler &masm) : masm(masm) { + masm.ensureSpace(reservedSpace); +#ifdef DEBUG + didCheck = false; + + startLabel = masm.label(); + + /* Assert that the constant pool is not flushed until we reach a safe point. */ + masm.allowPoolFlush(false); + + JaegerSpew(JSpew_Insns, " -- BEGIN CONSTANT-POOL-FREE REGION -- \n"); +#endif + } + + /* Allow manual IC space checks so that non-patchable code at the end of an IC section can be + * free to use constant pools. */ + void check() { +#ifdef DEBUG + JS_ASSERT(!didCheck); + didCheck = true; + + Label endLabel = masm.label(); + int spaceUsed = masm.differenceBetween(startLabel, endLabel); + + /* Spew the space used, to help tuning of reservedSpace. */ + JaegerSpew(JSpew_Insns, + " -- END CONSTANT-POOL-FREE REGION: %u bytes used of %u reserved. -- \n", + spaceUsed, reservedSpace); + + /* Assert that we didn't emit more code than we protected. */ + JS_ASSERT(spaceUsed >= 0); + JS_ASSERT(size_t(spaceUsed) <= reservedSpace); + + /* Allow the pool to be flushed. */ + masm.allowPoolFlush(true); +#endif + } + + ~AutoReserveICSpace() { +#ifdef DEBUG + /* Automatically check the IC space if we didn't already do it manually. */ + if (!didCheck) { + check(); + } +#endif + } +}; + +# define RESERVE_IC_SPACE(__masm) AutoReserveICSpace<128> arics(__masm) +# define CHECK_IC_SPACE() arics.check() + +/* The OOL path can need a lot of space because we save and restore a lot of registers. The actual + * sequene varies. However, dumping the literal pool before an OOL block is probably a good idea + * anyway, as we branch directly to the start of the block from the fast path. */ +# define RESERVE_OOL_SPACE(__masm) AutoReserveICSpace<256> arics_ool(__masm) + +/* Allow the OOL patch to be checked before object destruction. Often, non-patchable epilogues or + * rejoining sequences are emitted, and it isn't necessary to protect these from literal pools. */ +# define CHECK_OOL_SPACE() arics_ool.check() +#else +# define RESERVE_IC_SPACE(__masm) /* Do nothing. */ +# define CHECK_IC_SPACE() /* Do nothing. */ +# define RESERVE_OOL_SPACE(__masm) /* Do nothing. */ +# define CHECK_OOL_SPACE() /* Do nothing. */ +#endif + +} /* namespace js */ +} /* namespace mjit */ + +#endif diff --git a/js/src/methodjit/CodeGenIncludes.h b/js/src/methodjit/CodeGenIncludes.h new file mode 100644 index 0000000..855a7d4 --- /dev/null +++ b/js/src/methodjit/CodeGenIncludes.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_codegenincs_h__ && defined JS_METHODJIT +#define jsjaeger_codegenincs_h__ + +/* Get a label for assertion purposes. Prevent #ifdef clutter. */ +#ifdef DEBUG +# define DBGLABEL(name) Label name = masm.label(); +# define DBGLABEL_NOMASM(name) Label name = label(); +# define DBGLABEL_ASSIGN(name) name = masm.label(); +#else +# define DBGLABEL(name) +# define DBGLABEL_NOMASM(name) +# define DBGLABEL_ASSIGN(name) +#endif + +#if defined JS_NUNBOX32 +# include "NunboxAssembler.h" +#elif defined JS_PUNBOX64 +# include "PunboxAssembler.h" +#else +# error "Neither JS_NUNBOX32 nor JS_PUNBOX64 is defined." +#endif + +#include "BaseAssembler.h" + +#endif /* jsjaeger_codegenincs_h__ */ + diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp new file mode 100644 index 0000000..5d77692 --- /dev/null +++ b/js/src/methodjit/Compiler.cpp @@ -0,0 +1,5043 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * Jan de Mooij + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "MethodJIT.h" +#include "jsnum.h" +#include "jsbool.h" +#include "jsemit.h" +#include "jsiter.h" +#include "Compiler.h" +#include "StubCalls.h" +#include "MonoIC.h" +#include "PolyIC.h" +#include "ICChecker.h" +#include "Retcon.h" +#include "assembler/jit/ExecutableAllocator.h" +#include "assembler/assembler/LinkBuffer.h" +#include "FrameState-inl.h" +#include "jsobjinlines.h" +#include "jsscriptinlines.h" +#include "InlineFrameAssembler.h" +#include "jscompartment.h" +#include "jsobjinlines.h" +#include "jsopcodeinlines.h" +#include "jshotloop.h" + +#include "jsautooplen.h" + +using namespace js; +using namespace js::mjit; +#if defined(JS_POLYIC) || defined(JS_MONOIC) +using namespace js::mjit::ic; +#endif + +#define RETURN_IF_OOM(retval) \ + JS_BEGIN_MACRO \ + if (oomInVector || masm.oom() || stubcc.masm.oom()) \ + return retval; \ + JS_END_MACRO + +#if defined(JS_METHODJIT_SPEW) +static const char *OpcodeNames[] = { +# define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) #name, +# include "jsopcode.tbl" +# undef OPDEF +}; +#endif + +mjit::Compiler::Compiler(JSContext *cx, JSStackFrame *fp) + : BaseCompiler(cx), + fp(fp), + script(fp->script()), + scopeChain(&fp->scopeChain()), + globalObj(scopeChain->getGlobal()), + fun(fp->isFunctionFrame() && !fp->isEvalFrame() + ? fp->fun() + : NULL), + isConstructing(fp->isConstructing()), + analysis(NULL), jumpMap(NULL), savedTraps(NULL), + frame(cx, script, fun, masm), + branchPatches(CompilerAllocPolicy(cx, *thisFromCtor())), +#if defined JS_MONOIC + getGlobalNames(CompilerAllocPolicy(cx, *thisFromCtor())), + setGlobalNames(CompilerAllocPolicy(cx, *thisFromCtor())), + callICs(CompilerAllocPolicy(cx, *thisFromCtor())), + equalityICs(CompilerAllocPolicy(cx, *thisFromCtor())), + traceICs(CompilerAllocPolicy(cx, *thisFromCtor())), +#endif +#if defined JS_POLYIC + pics(CompilerAllocPolicy(cx, *thisFromCtor())), + getElemICs(CompilerAllocPolicy(cx, *thisFromCtor())), + setElemICs(CompilerAllocPolicy(cx, *thisFromCtor())), +#endif + callPatches(CompilerAllocPolicy(cx, *thisFromCtor())), + callSites(CompilerAllocPolicy(cx, *thisFromCtor())), + doubleList(CompilerAllocPolicy(cx, *thisFromCtor())), + jumpTables(CompilerAllocPolicy(cx, *thisFromCtor())), + jumpTableOffsets(CompilerAllocPolicy(cx, *thisFromCtor())), + stubcc(cx, *thisFromCtor(), frame, script), + debugMode_(cx->compartment->debugMode), +#if defined JS_TRACER + addTraceHints(cx->traceJitEnabled), +#endif + oomInVector(false), + applyTricks(NoApplyTricks) +{ +} + +CompileStatus +mjit::Compiler::compile() +{ + JS_ASSERT_IF(isConstructing, !script->jitCtor); + JS_ASSERT_IF(!isConstructing, !script->jitNormal); + + JITScript **jit = isConstructing ? &script->jitCtor : &script->jitNormal; + void **checkAddr = isConstructing + ? &script->jitArityCheckCtor + : &script->jitArityCheckNormal; + + CompileStatus status = performCompilation(jit); + if (status == Compile_Okay) { + // Global scripts don't have an arity check entry. That's okay, we + // just need a pointer so the VM can quickly decide whether this + // method can be JIT'd or not. Global scripts cannot be IC'd, since + // they have no functions, so there is no danger. + *checkAddr = (*jit)->arityCheckEntry + ? (*jit)->arityCheckEntry + : (*jit)->invokeEntry; + } else { + *checkAddr = JS_UNJITTABLE_SCRIPT; + } + + return status; +} + +#define CHECK_STATUS(expr) \ + JS_BEGIN_MACRO \ + CompileStatus status_ = (expr); \ + if (status_ != Compile_Okay) { \ + if (oomInVector || masm.oom() || stubcc.masm.oom()) \ + js_ReportOutOfMemory(cx); \ + return status_; \ + } \ + JS_END_MACRO + +CompileStatus +mjit::Compiler::performCompilation(JITScript **jitp) +{ + JaegerSpew(JSpew_Scripts, "compiling script (file \"%s\") (line \"%d\") (length \"%d\")\n", + script->filename, script->lineno, script->length); + + analyze::Script analysis; + PodZero(&analysis); + + analysis.analyze(cx, script); + + if (analysis.OOM()) { + js_ReportOutOfMemory(cx); + return Compile_Error; + } + if (analysis.failed()) { + JaegerSpew(JSpew_Abort, "couldn't analyze bytecode; probably switchX or OOM\n"); + return Compile_Abort; + } + + this->analysis = &analysis; + + if (!frame.init()) { + js_ReportOutOfMemory(cx); + return Compile_Error; + } + + jumpMap = (Label *)cx->malloc(sizeof(Label) * script->length); + if (!jumpMap) { + js_ReportOutOfMemory(cx); + return Compile_Error; + } +#ifdef DEBUG + for (uint32 i = 0; i < script->length; i++) + jumpMap[i] = Label(); +#endif + +#ifdef JS_METHODJIT_SPEW + Profiler prof; + prof.start(); +#endif + + /* Initialize PC early so stub calls in the prologue can be fallible. */ + PC = script->code; + +#ifdef JS_METHODJIT + script->debugMode = debugMode(); +#endif + + for (uint32 i = 0; i < script->nClosedVars; i++) + frame.setClosedVar(script->getClosedVar(i)); + for (uint32 i = 0; i < script->nClosedArgs; i++) + frame.setClosedArg(script->getClosedArg(i)); + + CHECK_STATUS(generatePrologue()); + CHECK_STATUS(generateMethod()); + CHECK_STATUS(generateEpilogue()); + CHECK_STATUS(finishThisUp(jitp)); + +#ifdef JS_METHODJIT_SPEW + prof.stop(); + JaegerSpew(JSpew_Prof, "compilation took %d us\n", prof.time_us()); +#endif + + JaegerSpew(JSpew_Scripts, "successfully compiled (code \"%p\") (size \"%ld\")\n", + (*jitp)->code.m_code.executableAddress(), (*jitp)->code.m_size); + + return Compile_Okay; +} + +#undef CHECK_STATUS + +mjit::Compiler::~Compiler() +{ + cx->free(jumpMap); + cx->free(savedTraps); +} + +CompileStatus JS_NEVER_INLINE +mjit::TryCompile(JSContext *cx, JSStackFrame *fp) +{ + JS_ASSERT(cx->fp() == fp); + +#if JS_HAS_SHARP_VARS + if (fp->script()->hasSharps) + return Compile_Abort; +#endif + + // Ensure that constructors have at least one slot. + if (fp->isConstructing() && !fp->script()->nslots) + fp->script()->nslots++; + + Compiler cc(cx, fp); + + return cc.compile(); +} + +bool +mjit::Compiler::loadOldTraps(const Vector &sites) +{ + savedTraps = (bool *)cx->calloc(sizeof(bool) * script->length); + if (!savedTraps) + return false; + + for (size_t i = 0; i < sites.length(); i++) { + const CallSite &site = sites[i]; + if (site.isTrap()) + savedTraps[site.pcOffset] = true; + } + + return true; +} + +CompileStatus +mjit::Compiler::generatePrologue() +{ + invokeLabel = masm.label(); + + /* + * If there is no function, then this can only be called via JaegerShot(), + * which expects an existing frame to be initialized like the interpreter. + */ + if (fun) { + Jump j = masm.jump(); + + /* + * Entry point #2: The caller has partially constructed a frame, and + * either argc >= nargs or the arity check has corrected the frame. + */ + invokeLabel = masm.label(); + + Label fastPath = masm.label(); + + /* Store this early on so slow paths can access it. */ + masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetOfExec())); + + { + /* + * Entry point #3: The caller has partially constructed a frame, + * but argc might be != nargs, so an arity check might be called. + * + * This loops back to entry point #2. + */ + arityLabel = stubcc.masm.label(); + Jump argMatch = stubcc.masm.branch32(Assembler::Equal, JSParamReg_Argc, + Imm32(fun->nargs)); + stubcc.crossJump(argMatch, fastPath); + + if (JSParamReg_Argc != Registers::ArgReg1) + stubcc.masm.move(JSParamReg_Argc, Registers::ArgReg1); + + /* Slow path - call the arity check function. Returns new fp. */ + stubcc.masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetOfExec())); + stubcc.masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp))); + OOL_STUBCALL(stubs::FixupArity); + stubcc.masm.move(Registers::ReturnReg, JSFrameReg); + stubcc.crossJump(stubcc.masm.jump(), fastPath); + } + + /* + * Guard that there is enough stack space. Note we include the size of + * a second frame, to ensure we can create a frame from call sites. + */ + masm.addPtr(Imm32((script->nslots + VALUES_PER_STACK_FRAME * 2) * sizeof(Value)), + JSFrameReg, + Registers::ReturnReg); + Jump stackCheck = masm.branchPtr(Assembler::AboveOrEqual, Registers::ReturnReg, + FrameAddress(offsetof(VMFrame, stackLimit))); + + /* If the stack check fails... */ + { + stubcc.linkExitDirect(stackCheck, stubcc.masm.label()); + OOL_STUBCALL(stubs::HitStackQuota); + stubcc.crossJump(stubcc.masm.jump(), masm.label()); + } + + /* + * Set locals to undefined, as in initCallFrameLatePrologue. + * Skip locals which aren't closed and are known to be defined before used, + * :FIXME: bug 604541: write undefined if we might be using the tracer, so it works. + */ + for (uint32 i = 0; i < script->nfixed; i++) { + if (analysis->localHasUseBeforeDef(i) || addTraceHints) { + Address local(JSFrameReg, sizeof(JSStackFrame) + i * sizeof(Value)); + masm.storeValue(UndefinedValue(), local); + } + } + + /* Create the call object. */ + if (fun->isHeavyweight()) { + prepareStubCall(Uses(0)); + INLINE_STUBCALL(stubs::GetCallObject); + } + + j.linkTo(masm.label(), &masm); + + if (analysis->usesScopeChain() && !fun->isHeavyweight()) { + /* + * Load the scope chain into the frame if necessary. The scope chain + * is always set for global and eval frames, and will have been set by + * GetCallObject for heavyweight function frames. + */ + RegisterID t0 = Registers::ReturnReg; + Jump hasScope = masm.branchTest32(Assembler::NonZero, + FrameFlagsAddress(), Imm32(JSFRAME_HAS_SCOPECHAIN)); + masm.loadPayload(Address(JSFrameReg, JSStackFrame::offsetOfCallee(fun)), t0); + masm.loadPtr(Address(t0, offsetof(JSObject, parent)), t0); + masm.storePtr(t0, Address(JSFrameReg, JSStackFrame::offsetOfScopeChain())); + hasScope.linkTo(masm.label(), &masm); + } + } + + if (isConstructing) + constructThis(); + + if (debugMode() || Probes::callTrackingActive(cx)) + INLINE_STUBCALL(stubs::EnterScript); + + return Compile_Okay; +} + +CompileStatus +mjit::Compiler::generateEpilogue() +{ + return Compile_Okay; +} + +CompileStatus +mjit::Compiler::finishThisUp(JITScript **jitp) +{ + RETURN_IF_OOM(Compile_Error); + + for (size_t i = 0; i < branchPatches.length(); i++) { + Label label = labelOf(branchPatches[i].pc); + branchPatches[i].jump.linkTo(label, &masm); + } + +#ifdef JS_CPU_ARM + masm.forceFlushConstantPool(); + stubcc.masm.forceFlushConstantPool(); +#endif + JaegerSpew(JSpew_Insns, "## Fast code (masm) size = %u, Slow code (stubcc) size = %u.\n", masm.size(), stubcc.size()); + + size_t totalSize = masm.size() + + stubcc.size() + + doubleList.length() * sizeof(double) + + jumpTableOffsets.length() * sizeof(void *); + + JSC::ExecutablePool *execPool = getExecPool(script, totalSize); + if (!execPool) { + js_ReportOutOfMemory(cx); + return Compile_Error; + } + + uint8 *result = (uint8 *)execPool->alloc(totalSize); + if (!result) { + execPool->release(); + js_ReportOutOfMemory(cx); + return Compile_Error; + } + JSC::ExecutableAllocator::makeWritable(result, totalSize); + masm.executableCopy(result); + stubcc.masm.executableCopy(result + masm.size()); + + JSC::LinkBuffer fullCode(result, totalSize); + JSC::LinkBuffer stubCode(result + masm.size(), stubcc.size()); + + size_t nNmapLive = 0; + for (size_t i = 0; i < script->length; i++) { + analyze::Bytecode *opinfo = analysis->maybeCode(i); + if (opinfo && opinfo->safePoint) + nNmapLive++; + } + + /* Please keep in sync with JITScript::scriptDataSize! */ + size_t totalBytes = sizeof(JITScript) + + sizeof(NativeMapEntry) * nNmapLive + +#if defined JS_MONOIC + sizeof(ic::GetGlobalNameIC) * getGlobalNames.length() + + sizeof(ic::SetGlobalNameIC) * setGlobalNames.length() + + sizeof(ic::CallICInfo) * callICs.length() + + sizeof(ic::EqualityICInfo) * equalityICs.length() + + sizeof(ic::TraceICInfo) * traceICs.length() + +#endif +#if defined JS_POLYIC + sizeof(ic::PICInfo) * pics.length() + + sizeof(ic::GetElementIC) * getElemICs.length() + + sizeof(ic::SetElementIC) * setElemICs.length() + +#endif + sizeof(CallSite) * callSites.length(); + + uint8 *cursor = (uint8 *)cx->calloc(totalBytes); + if (!cursor) { + execPool->release(); + js_ReportOutOfMemory(cx); + return Compile_Error; + } + + JITScript *jit = new(cursor) JITScript; + cursor += sizeof(JITScript); + + jit->code = JSC::MacroAssemblerCodeRef(result, execPool, masm.size() + stubcc.size()); + jit->invokeEntry = result; + jit->singleStepMode = script->singleStepMode; + if (fun) { + jit->arityCheckEntry = stubCode.locationOf(arityLabel).executableAddress(); + jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress(); + } + + /* + * WARNING: mics(), callICs() et al depend on the ordering of these + * variable-length sections. See JITScript's declaration for details. + */ + + /* Build the pc -> ncode mapping. */ + NativeMapEntry *jitNmap = (NativeMapEntry *)cursor; + jit->nNmapPairs = nNmapLive; + cursor += sizeof(NativeMapEntry) * jit->nNmapPairs; + size_t ix = 0; + if (jit->nNmapPairs > 0) { + for (size_t i = 0; i < script->length; i++) { + analyze::Bytecode *opinfo = analysis->maybeCode(i); + if (opinfo && opinfo->safePoint) { + Label L = jumpMap[i]; + JS_ASSERT(L.isValid()); + jitNmap[ix].bcOff = i; + jitNmap[ix].ncode = (uint8 *)(result + masm.distanceOf(L)); + ix++; + } + } + } + JS_ASSERT(ix == jit->nNmapPairs); + +#if defined JS_MONOIC + ic::GetGlobalNameIC *getGlobalNames_ = (ic::GetGlobalNameIC *)cursor; + jit->nGetGlobalNames = getGlobalNames.length(); + cursor += sizeof(ic::GetGlobalNameIC) * jit->nGetGlobalNames; + for (size_t i = 0; i < jit->nGetGlobalNames; i++) { + ic::GetGlobalNameIC &to = getGlobalNames_[i]; + GetGlobalNameICInfo &from = getGlobalNames[i]; + from.copyTo(to, fullCode, stubCode); + + int offset = fullCode.locationOf(from.load) - to.fastPathStart; + to.loadStoreOffset = offset; + JS_ASSERT(to.loadStoreOffset == offset); + + stubCode.patch(from.addrLabel, &to); + } + + ic::SetGlobalNameIC *setGlobalNames_ = (ic::SetGlobalNameIC *)cursor; + jit->nSetGlobalNames = setGlobalNames.length(); + cursor += sizeof(ic::SetGlobalNameIC) * jit->nSetGlobalNames; + for (size_t i = 0; i < jit->nSetGlobalNames; i++) { + ic::SetGlobalNameIC &to = setGlobalNames_[i]; + SetGlobalNameICInfo &from = setGlobalNames[i]; + from.copyTo(to, fullCode, stubCode); + to.slowPathStart = stubCode.locationOf(from.slowPathStart); + + int offset = fullCode.locationOf(from.store).labelAtOffset(0) - + to.fastPathStart; + to.loadStoreOffset = offset; + JS_ASSERT(to.loadStoreOffset == offset); + + to.hasExtraStub = 0; + to.objConst = from.objConst; + to.shapeReg = from.shapeReg; + to.objReg = from.objReg; + to.vr = from.vr; + + offset = fullCode.locationOf(from.shapeGuardJump) - + to.fastPathStart; + to.inlineShapeJump = offset; + JS_ASSERT(to.inlineShapeJump == offset); + + offset = fullCode.locationOf(from.fastPathRejoin) - + to.fastPathStart; + to.fastRejoinOffset = offset; + JS_ASSERT(to.fastRejoinOffset == offset); + + stubCode.patch(from.addrLabel, &to); + } + + ic::CallICInfo *jitCallICs = (ic::CallICInfo *)cursor; + jit->nCallICs = callICs.length(); + cursor += sizeof(ic::CallICInfo) * jit->nCallICs; + for (size_t i = 0; i < jit->nCallICs; i++) { + jitCallICs[i].reset(); + jitCallICs[i].funGuard = fullCode.locationOf(callICs[i].funGuard); + jitCallICs[i].funJump = fullCode.locationOf(callICs[i].funJump); + jitCallICs[i].slowPathStart = stubCode.locationOf(callICs[i].slowPathStart); + + /* Compute the hot call offset. */ + uint32 offset = fullCode.locationOf(callICs[i].hotJump) - + fullCode.locationOf(callICs[i].funGuard); + jitCallICs[i].hotJumpOffset = offset; + JS_ASSERT(jitCallICs[i].hotJumpOffset == offset); + + /* Compute the join point offset. */ + offset = fullCode.locationOf(callICs[i].joinPoint) - + fullCode.locationOf(callICs[i].funGuard); + jitCallICs[i].joinPointOffset = offset; + JS_ASSERT(jitCallICs[i].joinPointOffset == offset); + + /* Compute the OOL call offset. */ + offset = stubCode.locationOf(callICs[i].oolCall) - + stubCode.locationOf(callICs[i].slowPathStart); + jitCallICs[i].oolCallOffset = offset; + JS_ASSERT(jitCallICs[i].oolCallOffset == offset); + + /* Compute the OOL jump offset. */ + offset = stubCode.locationOf(callICs[i].oolJump) - + stubCode.locationOf(callICs[i].slowPathStart); + jitCallICs[i].oolJumpOffset = offset; + JS_ASSERT(jitCallICs[i].oolJumpOffset == offset); + + /* Compute the start of the OOL IC call. */ + offset = stubCode.locationOf(callICs[i].icCall) - + stubCode.locationOf(callICs[i].slowPathStart); + jitCallICs[i].icCallOffset = offset; + JS_ASSERT(jitCallICs[i].icCallOffset == offset); + + /* Compute the slow join point offset. */ + offset = stubCode.locationOf(callICs[i].slowJoinPoint) - + stubCode.locationOf(callICs[i].slowPathStart); + jitCallICs[i].slowJoinOffset = offset; + JS_ASSERT(jitCallICs[i].slowJoinOffset == offset); + + /* Compute the join point offset for continuing on the hot path. */ + offset = stubCode.locationOf(callICs[i].hotPathLabel) - + stubCode.locationOf(callICs[i].funGuard); + jitCallICs[i].hotPathOffset = offset; + JS_ASSERT(jitCallICs[i].hotPathOffset == offset); + + jitCallICs[i].pc = callICs[i].pc; + jitCallICs[i].frameSize = callICs[i].frameSize; + jitCallICs[i].funObjReg = callICs[i].funObjReg; + jitCallICs[i].funPtrReg = callICs[i].funPtrReg; + stubCode.patch(callICs[i].addrLabel1, &jitCallICs[i]); + stubCode.patch(callICs[i].addrLabel2, &jitCallICs[i]); + } + + ic::EqualityICInfo *jitEqualityICs = (ic::EqualityICInfo *)cursor; + jit->nEqualityICs = equalityICs.length(); + cursor += sizeof(ic::EqualityICInfo) * jit->nEqualityICs; + for (size_t i = 0; i < jit->nEqualityICs; i++) { + uint32 offs = uint32(equalityICs[i].jumpTarget - script->code); + JS_ASSERT(jumpMap[offs].isValid()); + jitEqualityICs[i].target = fullCode.locationOf(jumpMap[offs]); + jitEqualityICs[i].stubEntry = stubCode.locationOf(equalityICs[i].stubEntry); + jitEqualityICs[i].stubCall = stubCode.locationOf(equalityICs[i].stubCall); + jitEqualityICs[i].stub = equalityICs[i].stub; + jitEqualityICs[i].lvr = equalityICs[i].lvr; + jitEqualityICs[i].rvr = equalityICs[i].rvr; + jitEqualityICs[i].tempReg = equalityICs[i].tempReg; + jitEqualityICs[i].cond = equalityICs[i].cond; + if (equalityICs[i].jumpToStub.isSet()) + jitEqualityICs[i].jumpToStub = fullCode.locationOf(equalityICs[i].jumpToStub.get()); + jitEqualityICs[i].fallThrough = fullCode.locationOf(equalityICs[i].fallThrough); + + stubCode.patch(equalityICs[i].addrLabel, &jitEqualityICs[i]); + } + + ic::TraceICInfo *jitTraceICs = (ic::TraceICInfo *)cursor; + jit->nTraceICs = traceICs.length(); + cursor += sizeof(ic::TraceICInfo) * jit->nTraceICs; + for (size_t i = 0; i < jit->nTraceICs; i++) { + jitTraceICs[i].initialized = traceICs[i].initialized; + if (!traceICs[i].initialized) + continue; + + uint32 offs = uint32(traceICs[i].jumpTarget - script->code); + JS_ASSERT(jumpMap[offs].isValid()); + jitTraceICs[i].traceHint = fullCode.locationOf(traceICs[i].traceHint); + jitTraceICs[i].jumpTarget = fullCode.locationOf(jumpMap[offs]); + jitTraceICs[i].stubEntry = stubCode.locationOf(traceICs[i].stubEntry); + jitTraceICs[i].traceData = NULL; +#ifdef DEBUG + jitTraceICs[i].jumpTargetPC = traceICs[i].jumpTarget; +#endif + jitTraceICs[i].hasSlowTraceHint = traceICs[i].slowTraceHint.isSet(); + if (traceICs[i].slowTraceHint.isSet()) + jitTraceICs[i].slowTraceHint = stubCode.locationOf(traceICs[i].slowTraceHint.get()); +#ifdef JS_TRACER + jitTraceICs[i].loopCounterStart = GetHotloop(cx); +#endif + jitTraceICs[i].loopCounter = jitTraceICs[i].loopCounterStart + - cx->compartment->backEdgeCount(traceICs[i].jumpTarget); + + stubCode.patch(traceICs[i].addrLabel, &jitTraceICs[i]); + } +#endif /* JS_MONOIC */ + + for (size_t i = 0; i < callPatches.length(); i++) { + CallPatchInfo &patch = callPatches[i]; + + if (patch.hasFastNcode) + fullCode.patch(patch.fastNcodePatch, fullCode.locationOf(patch.joinPoint)); + if (patch.hasSlowNcode) + stubCode.patch(patch.slowNcodePatch, fullCode.locationOf(patch.joinPoint)); + } + +#ifdef JS_POLYIC + ic::GetElementIC *jitGetElems = (ic::GetElementIC *)cursor; + jit->nGetElems = getElemICs.length(); + cursor += sizeof(ic::GetElementIC) * jit->nGetElems; + for (size_t i = 0; i < jit->nGetElems; i++) { + ic::GetElementIC &to = jitGetElems[i]; + GetElementICInfo &from = getElemICs[i]; + + new (&to) ic::GetElementIC(); + from.copyTo(to, fullCode, stubCode); + + to.typeReg = from.typeReg; + to.objReg = from.objReg; + to.idRemat = from.id; + + if (from.typeGuard.isSet()) { + int inlineTypeGuard = fullCode.locationOf(from.typeGuard.get()) - + fullCode.locationOf(from.fastPathStart); + to.inlineTypeGuard = inlineTypeGuard; + JS_ASSERT(to.inlineTypeGuard == inlineTypeGuard); + } + int inlineClaspGuard = fullCode.locationOf(from.claspGuard) - + fullCode.locationOf(from.fastPathStart); + to.inlineClaspGuard = inlineClaspGuard; + JS_ASSERT(to.inlineClaspGuard == inlineClaspGuard); + + stubCode.patch(from.paramAddr, &to); + } + + ic::SetElementIC *jitSetElems = (ic::SetElementIC *)cursor; + jit->nSetElems = setElemICs.length(); + cursor += sizeof(ic::SetElementIC) * jit->nSetElems; + for (size_t i = 0; i < jit->nSetElems; i++) { + ic::SetElementIC &to = jitSetElems[i]; + SetElementICInfo &from = setElemICs[i]; + + new (&to) ic::SetElementIC(); + from.copyTo(to, fullCode, stubCode); + + to.strictMode = script->strictModeCode; + to.vr = from.vr; + to.objReg = from.objReg; + to.objRemat = from.objRemat.toInt32(); + JS_ASSERT(to.objRemat == from.objRemat.toInt32()); + + to.hasConstantKey = from.key.isConstant(); + if (from.key.isConstant()) + to.keyValue = from.key.index(); + else + to.keyReg = from.key.reg(); + + int inlineClaspGuard = fullCode.locationOf(from.claspGuard) - + fullCode.locationOf(from.fastPathStart); + to.inlineClaspGuard = inlineClaspGuard; + JS_ASSERT(to.inlineClaspGuard == inlineClaspGuard); + + int inlineHoleGuard = fullCode.locationOf(from.holeGuard) - + fullCode.locationOf(from.fastPathStart); + to.inlineHoleGuard = inlineHoleGuard; + JS_ASSERT(to.inlineHoleGuard == inlineHoleGuard); + + CheckIsStubCall(to.slowPathCall.labelAtOffset(0)); + + to.volatileMask = from.volatileMask; + JS_ASSERT(to.volatileMask == from.volatileMask); + + stubCode.patch(from.paramAddr, &to); + } + + ic::PICInfo *jitPics = (ic::PICInfo *)cursor; + jit->nPICs = pics.length(); + cursor += sizeof(ic::PICInfo) * jit->nPICs; + for (size_t i = 0; i < jit->nPICs; i++) { + new (&jitPics[i]) ic::PICInfo(); + pics[i].copyTo(jitPics[i], fullCode, stubCode); + pics[i].copySimpleMembersTo(jitPics[i]); + + jitPics[i].shapeGuard = masm.distanceOf(pics[i].shapeGuard) - + masm.distanceOf(pics[i].fastPathStart); + JS_ASSERT(jitPics[i].shapeGuard == masm.distanceOf(pics[i].shapeGuard) - + masm.distanceOf(pics[i].fastPathStart)); + jitPics[i].shapeRegHasBaseShape = true; + jitPics[i].pc = pics[i].pc; + + if (pics[i].kind == ic::PICInfo::SET || + pics[i].kind == ic::PICInfo::SETMETHOD) { + jitPics[i].u.vr = pics[i].vr; + } else if (pics[i].kind != ic::PICInfo::NAME) { + if (pics[i].hasTypeCheck) { + int32 distance = stubcc.masm.distanceOf(pics[i].typeCheck) - + stubcc.masm.distanceOf(pics[i].slowPathStart); + JS_ASSERT(distance <= 0); + jitPics[i].u.get.typeCheckOffset = distance; + } + } + stubCode.patch(pics[i].paramAddr, &jitPics[i]); + } +#endif + + /* Link fast and slow paths together. */ + stubcc.fixCrossJumps(result, masm.size(), masm.size() + stubcc.size()); + + /* Patch all double references. */ + size_t doubleOffset = masm.size() + stubcc.size(); + double *doubleVec = (double *)(result + doubleOffset); + for (size_t i = 0; i < doubleList.length(); i++) { + DoublePatch &patch = doubleList[i]; + doubleVec[i] = patch.d; + if (patch.ool) + stubCode.patch(patch.label, &doubleVec[i]); + else + fullCode.patch(patch.label, &doubleVec[i]); + } + + /* Generate jump tables. */ + void **jumpVec = (void **)(doubleVec + doubleList.length()); + + for (size_t i = 0; i < jumpTableOffsets.length(); i++) { + uint32 offset = jumpTableOffsets[i]; + JS_ASSERT(jumpMap[offset].isValid()); + jumpVec[i] = (void *)(result + masm.distanceOf(jumpMap[offset])); + } + + /* Patch jump table references. */ + for (size_t i = 0; i < jumpTables.length(); i++) { + JumpTable &jumpTable = jumpTables[i]; + fullCode.patch(jumpTable.label, &jumpVec[jumpTable.offsetIndex]); + } + + /* Patch all outgoing calls. */ + masm.finalize(fullCode); + stubcc.masm.finalize(stubCode); + + JSC::ExecutableAllocator::makeExecutable(result, masm.size() + stubcc.size()); + JSC::ExecutableAllocator::cacheFlush(result, masm.size() + stubcc.size()); + + /* Build the table of call sites. */ + CallSite *jitCallSites = (CallSite *)cursor; + jit->nCallSites = callSites.length(); + cursor += sizeof(CallSite) * jit->nCallSites; + for (size_t i = 0; i < jit->nCallSites; i++) { + CallSite &to = jitCallSites[i]; + InternalCallSite &from = callSites[i]; + uint32 codeOffset = from.ool + ? masm.size() + from.returnOffset + : from.returnOffset; + to.initialize(codeOffset, from.pc - script->code, from.id); + } + + JS_ASSERT(size_t(cursor - (uint8*)jit) == totalBytes); + + *jitp = jit; + + /* We tolerate a race in the stats. */ + cx->runtime->mjitMemoryUsed += totalSize + totalBytes; + + return Compile_Okay; +} + +class SrcNoteLineScanner { + ptrdiff_t offset; + jssrcnote *sn; + +public: + SrcNoteLineScanner(jssrcnote *sn) : offset(SN_DELTA(sn)), sn(sn) {} + + bool firstOpInLine(ptrdiff_t relpc) { + while ((offset < relpc) && !SN_IS_TERMINATOR(sn)) { + sn = SN_NEXT(sn); + offset += SN_DELTA(sn); + } + + while ((offset == relpc) && !SN_IS_TERMINATOR(sn)) { + JSSrcNoteType type = (JSSrcNoteType) SN_TYPE(sn); + if (type == SRC_SETLINE || type == SRC_NEWLINE) + return true; + + sn = SN_NEXT(sn); + offset += SN_DELTA(sn); + } + + return false; + } +}; + +#ifdef DEBUG +#define SPEW_OPCODE() \ + JS_BEGIN_MACRO \ + if (IsJaegerSpewChannelActive(JSpew_JSOps)) { \ + JaegerSpew(JSpew_JSOps, " %2d ", frame.stackDepth()); \ + js_Disassemble1(cx, script, PC, PC - script->code, \ + JS_TRUE, stdout); \ + } \ + JS_END_MACRO; +#else +#define SPEW_OPCODE() +#endif /* DEBUG */ + +#define BEGIN_CASE(name) case name: +#define END_CASE(name) \ + JS_BEGIN_MACRO \ + PC += name##_LENGTH; \ + JS_END_MACRO; \ + break; + +CompileStatus +mjit::Compiler::generateMethod() +{ + mjit::AutoScriptRetrapper trapper(cx, script); + SrcNoteLineScanner scanner(script->notes()); + + for (;;) { + JSOp op = JSOp(*PC); + int trap = stubs::JSTRAP_NONE; + if (op == JSOP_TRAP) { + if (!trapper.untrap(PC)) + return Compile_Error; + op = JSOp(*PC); + trap |= stubs::JSTRAP_TRAP; + } + if (script->singleStepMode && scanner.firstOpInLine(PC - script->code)) + trap |= stubs::JSTRAP_SINGLESTEP; + + analyze::Bytecode *opinfo = analysis->maybeCode(PC); + + if (!opinfo) { + if (op == JSOP_STOP) + break; + if (js_CodeSpec[op].length != -1) + PC += js_CodeSpec[op].length; + else + PC += js_GetVariableBytecodeLength(PC); + continue; + } + + frame.setInTryBlock(opinfo->inTryBlock); + if (opinfo->jumpTarget || trap) { + frame.syncAndForgetEverything(opinfo->stackDepth); + opinfo->safePoint = true; + } + jumpMap[uint32(PC - script->code)] = masm.label(); + + SPEW_OPCODE(); + JS_ASSERT(frame.stackDepth() == opinfo->stackDepth); + + if (trap) { + prepareStubCall(Uses(0)); + masm.move(Imm32(trap), Registers::ArgReg1); + Call cl = emitStubCall(JS_FUNC_TO_DATA_PTR(void *, stubs::Trap)); + InternalCallSite site(masm.callReturnOffset(cl), PC, + CallSite::MAGIC_TRAP_ID, true, false); + addCallSite(site); + } else if (savedTraps && savedTraps[PC - script->code]) { + // Normally when we patch return addresses, we have generated the + // same exact code at that site. For example, patching a stub call's + // return address will resume at the same stub call. + // + // In the case we're handling here, we could potentially be + // recompiling to remove a trap, and therefore we won't generate + // a call to the trap. However, we could be re-entering from that + // trap. The callsite will be missing, and fixing the stack will + // fail! Worse, we can't just put a label here, because on some + // platforms the stack needs to be adjusted when returning from + // the old trap call. + // + // To deal with this, we add a small bit of code in the OOL path + // that will adjust the stack and jump back into the script. + // Note that this uses MAGIC_TRAP_ID, which is necessary for + // repatching to detect the callsite as identical to the return + // address. + // + // Unfortunately, this means that if a bytecode is ever trapped, + // we will always generate a CallSite (either Trapped or not) for + // every debug recompilation of the script thereafter. The reason + // is that MAGIC_TRAP_ID callsites always propagate to the next + // recompilation. That's okay, and not worth fixing - it's a small + // amount of memory. + uint32 offset = stubcc.masm.distanceOf(stubcc.masm.label()); + if (Assembler::ReturnStackAdjustment) { + stubcc.masm.addPtr(Imm32(Assembler::ReturnStackAdjustment), + Assembler::stackPointerRegister); + } + stubcc.crossJump(stubcc.masm.jump(), masm.label()); + + InternalCallSite site(offset, PC, CallSite::MAGIC_TRAP_ID, false, true); + addCallSite(site); + } + + /********************** + * BEGIN COMPILER OPS * + **********************/ + + switch (op) { + BEGIN_CASE(JSOP_NOP) + END_CASE(JSOP_NOP) + + BEGIN_CASE(JSOP_PUSH) + frame.push(UndefinedValue()); + END_CASE(JSOP_PUSH) + + BEGIN_CASE(JSOP_POPV) + BEGIN_CASE(JSOP_SETRVAL) + { + RegisterID reg = frame.allocReg(); + masm.load32(FrameFlagsAddress(), reg); + masm.or32(Imm32(JSFRAME_HAS_RVAL), reg); + masm.store32(reg, FrameFlagsAddress()); + frame.freeReg(reg); + + FrameEntry *fe = frame.peek(-1); + frame.storeTo(fe, Address(JSFrameReg, JSStackFrame::offsetOfReturnValue()), true); + frame.pop(); + } + END_CASE(JSOP_POPV) + + BEGIN_CASE(JSOP_RETURN) + emitReturn(frame.peek(-1)); + END_CASE(JSOP_RETURN) + + BEGIN_CASE(JSOP_GOTO) + { + /* :XXX: this isn't really necessary if we follow the branch. */ + frame.syncAndForgetEverything(); + Jump j = masm.jump(); + if (!jumpAndTrace(j, PC + GET_JUMP_OFFSET(PC))) + return Compile_Error; + } + END_CASE(JSOP_GOTO) + + BEGIN_CASE(JSOP_IFEQ) + BEGIN_CASE(JSOP_IFNE) + if (!jsop_ifneq(op, PC + GET_JUMP_OFFSET(PC))) + return Compile_Error; + END_CASE(JSOP_IFNE) + + BEGIN_CASE(JSOP_ARGUMENTS) + /* + * For calls of the form 'f.apply(x, arguments)' we can avoid + * creating an args object by having ic::SplatApplyArgs pull + * directly from the stack. To do this, we speculate here that + * 'apply' actually refers to js_fun_apply. If this is not true, + * the slow path in JSOP_FUNAPPLY will create the args object. + */ + if (canUseApplyTricks()) + applyTricks = LazyArgsObj; + else + jsop_arguments(); + frame.pushSynced(); + END_CASE(JSOP_ARGUMENTS) + + BEGIN_CASE(JSOP_FORARG) + iterNext(); + frame.storeArg(GET_SLOTNO(PC), true); + frame.pop(); + END_CASE(JSOP_FORARG) + + BEGIN_CASE(JSOP_FORLOCAL) + iterNext(); + frame.storeLocal(GET_SLOTNO(PC), true); + frame.pop(); + END_CASE(JSOP_FORLOCAL) + + BEGIN_CASE(JSOP_DUP) + frame.dup(); + END_CASE(JSOP_DUP) + + BEGIN_CASE(JSOP_DUP2) + frame.dup2(); + END_CASE(JSOP_DUP2) + + BEGIN_CASE(JSOP_BITOR) + BEGIN_CASE(JSOP_BITXOR) + BEGIN_CASE(JSOP_BITAND) + jsop_bitop(op); + END_CASE(JSOP_BITAND) + + BEGIN_CASE(JSOP_LT) + BEGIN_CASE(JSOP_LE) + BEGIN_CASE(JSOP_GT) + BEGIN_CASE(JSOP_GE) + BEGIN_CASE(JSOP_EQ) + BEGIN_CASE(JSOP_NE) + { + /* Detect fusions. */ + jsbytecode *next = &PC[JSOP_GE_LENGTH]; + JSOp fused = JSOp(*next); + if ((fused != JSOP_IFEQ && fused != JSOP_IFNE) || analysis->jumpTarget(next)) + fused = JSOP_NOP; + + /* Get jump target, if any. */ + jsbytecode *target = NULL; + if (fused != JSOP_NOP) + target = next + GET_JUMP_OFFSET(next); + + BoolStub stub = NULL; + switch (op) { + case JSOP_LT: + stub = stubs::LessThan; + break; + case JSOP_LE: + stub = stubs::LessEqual; + break; + case JSOP_GT: + stub = stubs::GreaterThan; + break; + case JSOP_GE: + stub = stubs::GreaterEqual; + break; + case JSOP_EQ: + stub = stubs::Equal; + break; + case JSOP_NE: + stub = stubs::NotEqual; + break; + default: + JS_NOT_REACHED("WAT"); + break; + } + + FrameEntry *rhs = frame.peek(-1); + FrameEntry *lhs = frame.peek(-2); + + /* Check for easy cases that the parser does not constant fold. */ + if (lhs->isConstant() && rhs->isConstant()) { + /* Primitives can be trivially constant folded. */ + const Value &lv = lhs->getValue(); + const Value &rv = rhs->getValue(); + + if (lv.isPrimitive() && rv.isPrimitive()) { + bool result = compareTwoValues(cx, op, lv, rv); + + frame.pop(); + frame.pop(); + + if (!target) { + frame.push(Value(BooleanValue(result))); + } else { + if (fused == JSOP_IFEQ) + result = !result; + + /* Branch is never taken, don't bother doing anything. */ + if (result) { + frame.syncAndForgetEverything(); + Jump j = masm.jump(); + if (!jumpAndTrace(j, target)) + return Compile_Error; + } + } + } else { + if (!emitStubCmpOp(stub, target, fused)) + return Compile_Error; + } + } else { + /* Anything else should go through the fast path generator. */ + if (!jsop_relational(op, stub, target, fused)) + return Compile_Error; + } + + /* Advance PC manually. */ + JS_STATIC_ASSERT(JSOP_LT_LENGTH == JSOP_GE_LENGTH); + JS_STATIC_ASSERT(JSOP_LE_LENGTH == JSOP_GE_LENGTH); + JS_STATIC_ASSERT(JSOP_GT_LENGTH == JSOP_GE_LENGTH); + JS_STATIC_ASSERT(JSOP_EQ_LENGTH == JSOP_GE_LENGTH); + JS_STATIC_ASSERT(JSOP_NE_LENGTH == JSOP_GE_LENGTH); + + PC += JSOP_GE_LENGTH; + if (fused != JSOP_NOP) { + SPEW_OPCODE(); + PC += JSOP_IFNE_LENGTH; + } + break; + } + END_CASE(JSOP_GE) + + BEGIN_CASE(JSOP_LSH) + jsop_bitop(op); + END_CASE(JSOP_LSH) + + BEGIN_CASE(JSOP_RSH) + jsop_rsh(); + END_CASE(JSOP_RSH) + + BEGIN_CASE(JSOP_URSH) + jsop_bitop(op); + END_CASE(JSOP_URSH) + + BEGIN_CASE(JSOP_ADD) + jsop_binary(op, stubs::Add); + END_CASE(JSOP_ADD) + + BEGIN_CASE(JSOP_SUB) + jsop_binary(op, stubs::Sub); + END_CASE(JSOP_SUB) + + BEGIN_CASE(JSOP_MUL) + jsop_binary(op, stubs::Mul); + END_CASE(JSOP_MUL) + + BEGIN_CASE(JSOP_DIV) + jsop_binary(op, stubs::Div); + END_CASE(JSOP_DIV) + + BEGIN_CASE(JSOP_MOD) + jsop_mod(); + END_CASE(JSOP_MOD) + + BEGIN_CASE(JSOP_NOT) + jsop_not(); + END_CASE(JSOP_NOT) + + BEGIN_CASE(JSOP_BITNOT) + { + FrameEntry *top = frame.peek(-1); + if (top->isConstant() && top->getValue().isPrimitive()) { + int32_t i; + ValueToECMAInt32(cx, top->getValue(), &i); + i = ~i; + frame.pop(); + frame.push(Int32Value(i)); + } else { + jsop_bitnot(); + } + } + END_CASE(JSOP_BITNOT) + + BEGIN_CASE(JSOP_NEG) + { + FrameEntry *top = frame.peek(-1); + if (top->isConstant() && top->getValue().isPrimitive()) { + double d; + ValueToNumber(cx, top->getValue(), &d); + d = -d; + frame.pop(); + frame.push(NumberValue(d)); + } else { + jsop_neg(); + } + } + END_CASE(JSOP_NEG) + + BEGIN_CASE(JSOP_POS) + jsop_pos(); + END_CASE(JSOP_POS) + + BEGIN_CASE(JSOP_DELNAME) + { + uint32 index = fullAtomIndex(PC); + JSAtom *atom = script->getAtom(index); + + prepareStubCall(Uses(0)); + masm.move(ImmPtr(atom), Registers::ArgReg1); + INLINE_STUBCALL(stubs::DelName); + frame.pushSynced(); + } + END_CASE(JSOP_DELNAME) + + BEGIN_CASE(JSOP_DELPROP) + { + uint32 index = fullAtomIndex(PC); + JSAtom *atom = script->getAtom(index); + + prepareStubCall(Uses(1)); + masm.move(ImmPtr(atom), Registers::ArgReg1); + INLINE_STUBCALL(STRICT_VARIANT(stubs::DelProp)); + frame.pop(); + frame.pushSynced(); + } + END_CASE(JSOP_DELPROP) + + BEGIN_CASE(JSOP_DELELEM) + prepareStubCall(Uses(2)); + INLINE_STUBCALL(STRICT_VARIANT(stubs::DelElem)); + frame.popn(2); + frame.pushSynced(); + END_CASE(JSOP_DELELEM) + + BEGIN_CASE(JSOP_TYPEOF) + BEGIN_CASE(JSOP_TYPEOFEXPR) + jsop_typeof(); + END_CASE(JSOP_TYPEOF) + + BEGIN_CASE(JSOP_VOID) + frame.pop(); + frame.push(UndefinedValue()); + END_CASE(JSOP_VOID) + + BEGIN_CASE(JSOP_INCNAME) + if (!jsop_nameinc(op, STRICT_VARIANT(stubs::IncName), fullAtomIndex(PC))) + return Compile_Error; + break; + END_CASE(JSOP_INCNAME) + + BEGIN_CASE(JSOP_INCGNAME) + jsop_gnameinc(op, STRICT_VARIANT(stubs::IncGlobalName), fullAtomIndex(PC)); + break; + END_CASE(JSOP_INCGNAME) + + BEGIN_CASE(JSOP_INCPROP) + if (!jsop_propinc(op, STRICT_VARIANT(stubs::IncProp), fullAtomIndex(PC))) + return Compile_Error; + break; + END_CASE(JSOP_INCPROP) + + BEGIN_CASE(JSOP_INCELEM) + jsop_eleminc(op, STRICT_VARIANT(stubs::IncElem)); + END_CASE(JSOP_INCELEM) + + BEGIN_CASE(JSOP_DECNAME) + if (!jsop_nameinc(op, STRICT_VARIANT(stubs::DecName), fullAtomIndex(PC))) + return Compile_Error; + break; + END_CASE(JSOP_DECNAME) + + BEGIN_CASE(JSOP_DECGNAME) + jsop_gnameinc(op, STRICT_VARIANT(stubs::DecGlobalName), fullAtomIndex(PC)); + break; + END_CASE(JSOP_DECGNAME) + + BEGIN_CASE(JSOP_DECPROP) + if (!jsop_propinc(op, STRICT_VARIANT(stubs::DecProp), fullAtomIndex(PC))) + return Compile_Error; + break; + END_CASE(JSOP_DECPROP) + + BEGIN_CASE(JSOP_DECELEM) + jsop_eleminc(op, STRICT_VARIANT(stubs::DecElem)); + END_CASE(JSOP_DECELEM) + + BEGIN_CASE(JSOP_NAMEINC) + if (!jsop_nameinc(op, STRICT_VARIANT(stubs::NameInc), fullAtomIndex(PC))) + return Compile_Error; + break; + END_CASE(JSOP_NAMEINC) + + BEGIN_CASE(JSOP_GNAMEINC) + jsop_gnameinc(op, STRICT_VARIANT(stubs::GlobalNameInc), fullAtomIndex(PC)); + break; + END_CASE(JSOP_GNAMEINC) + + BEGIN_CASE(JSOP_PROPINC) + if (!jsop_propinc(op, STRICT_VARIANT(stubs::PropInc), fullAtomIndex(PC))) + return Compile_Error; + break; + END_CASE(JSOP_PROPINC) + + BEGIN_CASE(JSOP_ELEMINC) + jsop_eleminc(op, STRICT_VARIANT(stubs::ElemInc)); + END_CASE(JSOP_ELEMINC) + + BEGIN_CASE(JSOP_NAMEDEC) + if (!jsop_nameinc(op, STRICT_VARIANT(stubs::NameDec), fullAtomIndex(PC))) + return Compile_Error; + break; + END_CASE(JSOP_NAMEDEC) + + BEGIN_CASE(JSOP_GNAMEDEC) + jsop_gnameinc(op, STRICT_VARIANT(stubs::GlobalNameDec), fullAtomIndex(PC)); + break; + END_CASE(JSOP_GNAMEDEC) + + BEGIN_CASE(JSOP_PROPDEC) + if (!jsop_propinc(op, STRICT_VARIANT(stubs::PropDec), fullAtomIndex(PC))) + return Compile_Error; + break; + END_CASE(JSOP_PROPDEC) + + BEGIN_CASE(JSOP_ELEMDEC) + jsop_eleminc(op, STRICT_VARIANT(stubs::ElemDec)); + END_CASE(JSOP_ELEMDEC) + + BEGIN_CASE(JSOP_GETTHISPROP) + /* Push thisv onto stack. */ + jsop_this(); + if (!jsop_getprop(script->getAtom(fullAtomIndex(PC)))) + return Compile_Error; + END_CASE(JSOP_GETTHISPROP); + + BEGIN_CASE(JSOP_GETARGPROP) + /* Push arg onto stack. */ + frame.pushArg(GET_SLOTNO(PC)); + if (!jsop_getprop(script->getAtom(fullAtomIndex(&PC[ARGNO_LEN])))) + return Compile_Error; + END_CASE(JSOP_GETARGPROP) + + BEGIN_CASE(JSOP_GETLOCALPROP) + frame.pushLocal(GET_SLOTNO(PC)); + if (!jsop_getprop(script->getAtom(fullAtomIndex(&PC[SLOTNO_LEN])))) + return Compile_Error; + END_CASE(JSOP_GETLOCALPROP) + + BEGIN_CASE(JSOP_GETPROP) + if (!jsop_getprop(script->getAtom(fullAtomIndex(PC)))) + return Compile_Error; + END_CASE(JSOP_GETPROP) + + BEGIN_CASE(JSOP_LENGTH) + if (!jsop_length()) + return Compile_Error; + END_CASE(JSOP_LENGTH) + + BEGIN_CASE(JSOP_GETELEM) + if (!jsop_getelem(false)) + return Compile_Error; + END_CASE(JSOP_GETELEM) + + BEGIN_CASE(JSOP_SETELEM) + { + jsbytecode *next = &PC[JSOP_SETELEM_LENGTH]; + bool pop = (JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next)); + if (!jsop_setelem(pop)) + return Compile_Error; + } + END_CASE(JSOP_SETELEM); + + BEGIN_CASE(JSOP_CALLNAME) + prepareStubCall(Uses(0)); + masm.move(Imm32(fullAtomIndex(PC)), Registers::ArgReg1); + INLINE_STUBCALL(stubs::CallName); + frame.pushSynced(); + frame.pushSynced(); + END_CASE(JSOP_CALLNAME) + + BEGIN_CASE(JSOP_EVAL) + { + JaegerSpew(JSpew_Insns, " --- EVAL --- \n"); + emitEval(GET_ARGC(PC)); + JaegerSpew(JSpew_Insns, " --- END EVAL --- \n"); + } + END_CASE(JSOP_EVAL) + + BEGIN_CASE(JSOP_CALL) + BEGIN_CASE(JSOP_FUNAPPLY) + BEGIN_CASE(JSOP_FUNCALL) + { + JaegerSpew(JSpew_Insns, " --- SCRIPTED CALL --- \n"); + inlineCallHelper(GET_ARGC(PC), false); + JaegerSpew(JSpew_Insns, " --- END SCRIPTED CALL --- \n"); + } + END_CASE(JSOP_CALL) + + BEGIN_CASE(JSOP_NAME) + jsop_name(script->getAtom(fullAtomIndex(PC))); + END_CASE(JSOP_NAME) + + BEGIN_CASE(JSOP_DOUBLE) + { + uint32 index = fullAtomIndex(PC); + double d = script->getConst(index).toDouble(); + frame.push(Value(DoubleValue(d))); + } + END_CASE(JSOP_DOUBLE) + + BEGIN_CASE(JSOP_STRING) + { + JSAtom *atom = script->getAtom(fullAtomIndex(PC)); + JSString *str = ATOM_TO_STRING(atom); + frame.push(Value(StringValue(str))); + } + END_CASE(JSOP_STRING) + + BEGIN_CASE(JSOP_ZERO) + frame.push(Valueify(JSVAL_ZERO)); + END_CASE(JSOP_ZERO) + + BEGIN_CASE(JSOP_ONE) + frame.push(Valueify(JSVAL_ONE)); + END_CASE(JSOP_ONE) + + BEGIN_CASE(JSOP_NULL) + frame.push(NullValue()); + END_CASE(JSOP_NULL) + + BEGIN_CASE(JSOP_THIS) + jsop_this(); + END_CASE(JSOP_THIS) + + BEGIN_CASE(JSOP_FALSE) + frame.push(Value(BooleanValue(false))); + END_CASE(JSOP_FALSE) + + BEGIN_CASE(JSOP_TRUE) + frame.push(Value(BooleanValue(true))); + END_CASE(JSOP_TRUE) + + BEGIN_CASE(JSOP_OR) + BEGIN_CASE(JSOP_AND) + if (!jsop_andor(op, PC + GET_JUMP_OFFSET(PC))) + return Compile_Error; + END_CASE(JSOP_AND) + + BEGIN_CASE(JSOP_TABLESWITCH) +#if defined JS_CPU_ARM /* Need to implement jump(BaseIndex) for ARM */ + frame.syncAndForgetEverything(); + masm.move(ImmPtr(PC), Registers::ArgReg1); + + /* prepareStubCall() is not needed due to syncAndForgetEverything() */ + INLINE_STUBCALL(stubs::TableSwitch); + frame.pop(); + + masm.jump(Registers::ReturnReg); +#else + if (!jsop_tableswitch(PC)) + return Compile_Error; +#endif + PC += js_GetVariableBytecodeLength(PC); + break; + END_CASE(JSOP_TABLESWITCH) + + BEGIN_CASE(JSOP_LOOKUPSWITCH) + frame.syncAndForgetEverything(); + masm.move(ImmPtr(PC), Registers::ArgReg1); + + /* prepareStubCall() is not needed due to syncAndForgetEverything() */ + INLINE_STUBCALL(stubs::LookupSwitch); + frame.pop(); + + masm.jump(Registers::ReturnReg); + PC += js_GetVariableBytecodeLength(PC); + break; + END_CASE(JSOP_LOOKUPSWITCH) + + BEGIN_CASE(JSOP_STRICTEQ) + jsop_stricteq(op); + END_CASE(JSOP_STRICTEQ) + + BEGIN_CASE(JSOP_STRICTNE) + jsop_stricteq(op); + END_CASE(JSOP_STRICTNE) + + BEGIN_CASE(JSOP_ITER) + if (!iter(PC[1])) + return Compile_Error; + END_CASE(JSOP_ITER) + + BEGIN_CASE(JSOP_MOREITER) + /* At the byte level, this is always fused with IFNE or IFNEX. */ + if (!iterMore()) + return Compile_Error; + break; + END_CASE(JSOP_MOREITER) + + BEGIN_CASE(JSOP_ENDITER) + iterEnd(); + END_CASE(JSOP_ENDITER) + + BEGIN_CASE(JSOP_POP) + frame.pop(); + END_CASE(JSOP_POP) + + BEGIN_CASE(JSOP_NEW) + { + JaegerSpew(JSpew_Insns, " --- NEW OPERATOR --- \n"); + inlineCallHelper(GET_ARGC(PC), true); + JaegerSpew(JSpew_Insns, " --- END NEW OPERATOR --- \n"); + } + END_CASE(JSOP_NEW) + + BEGIN_CASE(JSOP_GETARG) + BEGIN_CASE(JSOP_CALLARG) + { + frame.pushArg(GET_SLOTNO(PC)); + if (op == JSOP_CALLARG) + frame.push(UndefinedValue()); + } + END_CASE(JSOP_GETARG) + + BEGIN_CASE(JSOP_BINDGNAME) + jsop_bindgname(); + END_CASE(JSOP_BINDGNAME) + + BEGIN_CASE(JSOP_SETARG) + { + jsbytecode *next = &PC[JSOP_SETLOCAL_LENGTH]; + bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next); + frame.storeArg(GET_SLOTNO(PC), pop); + if (pop) { + frame.pop(); + PC += JSOP_SETARG_LENGTH + JSOP_POP_LENGTH; + break; + } + } + END_CASE(JSOP_SETARG) + + BEGIN_CASE(JSOP_GETLOCAL) + { + uint32 slot = GET_SLOTNO(PC); + frame.pushLocal(slot); + } + END_CASE(JSOP_GETLOCAL) + + BEGIN_CASE(JSOP_SETLOCAL) + { + jsbytecode *next = &PC[JSOP_SETLOCAL_LENGTH]; + bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next); + frame.storeLocal(GET_SLOTNO(PC), pop); + if (pop) { + frame.pop(); + PC += JSOP_SETLOCAL_LENGTH + JSOP_POP_LENGTH; + break; + } + } + END_CASE(JSOP_SETLOCAL) + + BEGIN_CASE(JSOP_SETLOCALPOP) + frame.storeLocal(GET_SLOTNO(PC), true); + frame.pop(); + END_CASE(JSOP_SETLOCALPOP) + + BEGIN_CASE(JSOP_UINT16) + frame.push(Value(Int32Value((int32_t) GET_UINT16(PC)))); + END_CASE(JSOP_UINT16) + + BEGIN_CASE(JSOP_NEWINIT) + jsop_newinit(); + END_CASE(JSOP_NEWINIT) + + BEGIN_CASE(JSOP_NEWARRAY) + jsop_newinit(); + END_CASE(JSOP_NEWARRAY) + + BEGIN_CASE(JSOP_NEWOBJECT) + jsop_newinit(); + END_CASE(JSOP_NEWOBJECT) + + BEGIN_CASE(JSOP_ENDINIT) + END_CASE(JSOP_ENDINIT) + + BEGIN_CASE(JSOP_INITMETHOD) + jsop_initmethod(); + frame.pop(); + END_CASE(JSOP_INITMETHOD) + + BEGIN_CASE(JSOP_INITPROP) + jsop_initprop(); + frame.pop(); + END_CASE(JSOP_INITPROP) + + BEGIN_CASE(JSOP_INITELEM) + jsop_initelem(); + frame.popn(2); + END_CASE(JSOP_INITELEM) + + BEGIN_CASE(JSOP_INCARG) + BEGIN_CASE(JSOP_DECARG) + BEGIN_CASE(JSOP_ARGINC) + BEGIN_CASE(JSOP_ARGDEC) + { + jsbytecode *next = &PC[JSOP_ARGINC_LENGTH]; + bool popped = false; + if (JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next)) + popped = true; + jsop_arginc(op, GET_SLOTNO(PC), popped); + PC += JSOP_ARGINC_LENGTH; + if (popped) + PC += JSOP_POP_LENGTH; + break; + } + END_CASE(JSOP_ARGDEC) + + BEGIN_CASE(JSOP_INCLOCAL) + BEGIN_CASE(JSOP_DECLOCAL) + BEGIN_CASE(JSOP_LOCALINC) + BEGIN_CASE(JSOP_LOCALDEC) + { + jsbytecode *next = &PC[JSOP_LOCALINC_LENGTH]; + bool popped = false; + if (JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next)) + popped = true; + /* These manually advance the PC. */ + jsop_localinc(op, GET_SLOTNO(PC), popped); + PC += JSOP_LOCALINC_LENGTH; + if (popped) + PC += JSOP_POP_LENGTH; + break; + } + END_CASE(JSOP_LOCALDEC) + + BEGIN_CASE(JSOP_FORNAME) + jsop_forname(script->getAtom(fullAtomIndex(PC))); + END_CASE(JSOP_FORNAME) + + BEGIN_CASE(JSOP_FORGNAME) + jsop_forgname(script->getAtom(fullAtomIndex(PC))); + END_CASE(JSOP_FORGNAME) + + BEGIN_CASE(JSOP_FORPROP) + jsop_forprop(script->getAtom(fullAtomIndex(PC))); + END_CASE(JSOP_FORPROP) + + BEGIN_CASE(JSOP_FORELEM) + // This opcode is for the decompiler; it is succeeded by an + // ENUMELEM, which performs the actual array store. + iterNext(); + END_CASE(JSOP_FORELEM) + + BEGIN_CASE(JSOP_BINDNAME) + jsop_bindname(script->getAtom(fullAtomIndex(PC)), true); + END_CASE(JSOP_BINDNAME) + + BEGIN_CASE(JSOP_SETPROP) + if (!jsop_setprop(script->getAtom(fullAtomIndex(PC)), true)) + return Compile_Error; + END_CASE(JSOP_SETPROP) + + BEGIN_CASE(JSOP_SETNAME) + BEGIN_CASE(JSOP_SETMETHOD) + if (!jsop_setprop(script->getAtom(fullAtomIndex(PC)), true)) + return Compile_Error; + END_CASE(JSOP_SETNAME) + + BEGIN_CASE(JSOP_THROW) + prepareStubCall(Uses(1)); + INLINE_STUBCALL(stubs::Throw); + frame.pop(); + END_CASE(JSOP_THROW) + + BEGIN_CASE(JSOP_IN) + prepareStubCall(Uses(2)); + INLINE_STUBCALL(stubs::In); + frame.popn(2); + frame.takeReg(Registers::ReturnReg); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, Registers::ReturnReg); + END_CASE(JSOP_IN) + + BEGIN_CASE(JSOP_INSTANCEOF) + if (!jsop_instanceof()) + return Compile_Error; + END_CASE(JSOP_INSTANCEOF) + + BEGIN_CASE(JSOP_EXCEPTION) + prepareStubCall(Uses(0)); + INLINE_STUBCALL(stubs::Exception); + frame.pushSynced(); + END_CASE(JSOP_EXCEPTION) + + BEGIN_CASE(JSOP_LINENO) + END_CASE(JSOP_LINENO) + + BEGIN_CASE(JSOP_ENUMELEM) + // Normally, SETELEM transforms the stack + // from: OBJ ID VALUE + // to: VALUE + // + // Here, the stack transition is + // from: VALUE OBJ ID + // to: + // So we make the stack look like a SETELEM, and re-use it. + + // Before: VALUE OBJ ID + // After: VALUE OBJ ID VALUE + frame.dupAt(-3); + + // Before: VALUE OBJ ID VALUE + // After: VALUE VALUE + if (!jsop_setelem(true)) + return Compile_Error; + + // Before: VALUE VALUE + // After: + frame.popn(2); + END_CASE(JSOP_ENUMELEM) + + BEGIN_CASE(JSOP_BLOCKCHAIN) + END_CASE(JSOP_BLOCKCHAIN) + + BEGIN_CASE(JSOP_NULLBLOCKCHAIN) + END_CASE(JSOP_NULLBLOCKCHAIN) + + BEGIN_CASE(JSOP_CONDSWITCH) + /* No-op for the decompiler. */ + END_CASE(JSOP_CONDSWITCH) + + BEGIN_CASE(JSOP_DEFFUN) + { + uint32 index = fullAtomIndex(PC); + JSFunction *innerFun = script->getFunction(index); + + if (fun && script->bindings.hasBinding(cx, innerFun->atom)) + frame.syncAndForgetEverything(); + + prepareStubCall(Uses(0)); + masm.move(ImmPtr(innerFun), Registers::ArgReg1); + INLINE_STUBCALL(STRICT_VARIANT(stubs::DefFun)); + } + END_CASE(JSOP_DEFFUN) + + BEGIN_CASE(JSOP_DEFVAR) + BEGIN_CASE(JSOP_DEFCONST) + { + uint32 index = fullAtomIndex(PC); + JSAtom *atom = script->getAtom(index); + + prepareStubCall(Uses(0)); + masm.move(ImmPtr(atom), Registers::ArgReg1); + INLINE_STUBCALL(stubs::DefVarOrConst); + } + END_CASE(JSOP_DEFVAR) + + BEGIN_CASE(JSOP_SETCONST) + { + uint32 index = fullAtomIndex(PC); + JSAtom *atom = script->getAtom(index); + + if (fun && script->bindings.hasBinding(cx, atom)) + frame.syncAndForgetEverything(); + + prepareStubCall(Uses(1)); + masm.move(ImmPtr(atom), Registers::ArgReg1); + INLINE_STUBCALL(stubs::SetConst); + } + END_CASE(JSOP_SETCONST) + + BEGIN_CASE(JSOP_DEFLOCALFUN_FC) + { + uint32 slot = GET_SLOTNO(PC); + JSFunction *fun = script->getFunction(fullAtomIndex(&PC[SLOTNO_LEN])); + prepareStubCall(Uses(frame.frameSlots())); + masm.move(ImmPtr(fun), Registers::ArgReg1); + INLINE_STUBCALL(stubs::DefLocalFun_FC); + frame.takeReg(Registers::ReturnReg); + frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg); + frame.storeLocal(slot, true); + frame.pop(); + } + END_CASE(JSOP_DEFLOCALFUN_FC) + + BEGIN_CASE(JSOP_LAMBDA) + { + JSFunction *fun = script->getFunction(fullAtomIndex(PC)); + + JSObjStubFun stub = stubs::Lambda; + uint32 uses = 0; + + jsbytecode *pc2 = AdvanceOverBlockchainOp(PC + JSOP_LAMBDA_LENGTH); + JSOp next = JSOp(*pc2); + + if (next == JSOP_INITMETHOD) { + stub = stubs::LambdaForInit; + } else if (next == JSOP_SETMETHOD) { + stub = stubs::LambdaForSet; + uses = 1; + } else if (fun->joinable()) { + if (next == JSOP_CALL) { + stub = stubs::LambdaJoinableForCall; + uses = frame.frameSlots(); + } else if (next == JSOP_NULL) { + stub = stubs::LambdaJoinableForNull; + } + } + + prepareStubCall(Uses(uses)); + masm.move(ImmPtr(fun), Registers::ArgReg1); + + if (stub == stubs::Lambda) { + INLINE_STUBCALL(stub); + } else { + jsbytecode *savedPC = PC; + PC = pc2; + INLINE_STUBCALL(stub); + PC = savedPC; + } + + frame.takeReg(Registers::ReturnReg); + frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg); + } + END_CASE(JSOP_LAMBDA) + + BEGIN_CASE(JSOP_TRY) + frame.syncAndForgetEverything(); + END_CASE(JSOP_TRY) + + BEGIN_CASE(JSOP_GETFCSLOT) + BEGIN_CASE(JSOP_CALLFCSLOT) + { + uintN index = GET_UINT16(PC); + + // Load the callee's payload into a register. + frame.pushCallee(); + RegisterID reg = frame.copyDataIntoReg(frame.peek(-1)); + frame.pop(); + + // obj->getFlatClosureUpvars() + masm.loadPtr(Address(reg, offsetof(JSObject, slots)), reg); + Address upvarAddress(reg, JSObject::JSSLOT_FLAT_CLOSURE_UPVARS * sizeof(Value)); + masm.loadPrivate(upvarAddress, reg); + // push ((Value *) reg)[index] + frame.freeReg(reg); + frame.push(Address(reg, index * sizeof(Value))); + if (op == JSOP_CALLFCSLOT) + frame.push(UndefinedValue()); + } + END_CASE(JSOP_CALLFCSLOT) + + BEGIN_CASE(JSOP_ARGSUB) + prepareStubCall(Uses(0)); + masm.move(Imm32(GET_ARGNO(PC)), Registers::ArgReg1); + INLINE_STUBCALL(stubs::ArgSub); + frame.pushSynced(); + END_CASE(JSOP_ARGSUB) + + BEGIN_CASE(JSOP_ARGCNT) + prepareStubCall(Uses(0)); + INLINE_STUBCALL(stubs::ArgCnt); + frame.pushSynced(); + END_CASE(JSOP_ARGCNT) + + BEGIN_CASE(JSOP_DEFLOCALFUN) + { + uint32 slot = GET_SLOTNO(PC); + JSFunction *fun = script->getFunction(fullAtomIndex(&PC[SLOTNO_LEN])); + prepareStubCall(Uses(0)); + masm.move(ImmPtr(fun), Registers::ArgReg1); + INLINE_STUBCALL(stubs::DefLocalFun); + frame.takeReg(Registers::ReturnReg); + frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg); + frame.storeLocal(slot, true); + frame.pop(); + } + END_CASE(JSOP_DEFLOCALFUN) + + BEGIN_CASE(JSOP_RETRVAL) + emitReturn(NULL); + END_CASE(JSOP_RETRVAL) + + BEGIN_CASE(JSOP_GETGNAME) + BEGIN_CASE(JSOP_CALLGNAME) + jsop_getgname(fullAtomIndex(PC)); + if (op == JSOP_CALLGNAME) + jsop_callgname_epilogue(); + END_CASE(JSOP_GETGNAME) + + BEGIN_CASE(JSOP_SETGNAME) + jsop_setgname(script->getAtom(fullAtomIndex(PC)), true); + END_CASE(JSOP_SETGNAME) + + BEGIN_CASE(JSOP_REGEXP) + { + JSObject *regex = script->getRegExp(fullAtomIndex(PC)); + prepareStubCall(Uses(0)); + masm.move(ImmPtr(regex), Registers::ArgReg1); + INLINE_STUBCALL(stubs::RegExp); + frame.takeReg(Registers::ReturnReg); + frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg); + } + END_CASE(JSOP_REGEXP) + + BEGIN_CASE(JSOP_OBJECT) + { + JSObject *object = script->getObject(fullAtomIndex(PC)); + RegisterID reg = frame.allocReg(); + masm.move(ImmPtr(object), reg); + frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg); + } + END_CASE(JSOP_OBJECT) + + BEGIN_CASE(JSOP_CALLPROP) + if (!jsop_callprop(script->getAtom(fullAtomIndex(PC)))) + return Compile_Error; + END_CASE(JSOP_CALLPROP) + + BEGIN_CASE(JSOP_UINT24) + frame.push(Value(Int32Value((int32_t) GET_UINT24(PC)))); + END_CASE(JSOP_UINT24) + + BEGIN_CASE(JSOP_CALLELEM) + jsop_getelem(true); + END_CASE(JSOP_CALLELEM) + + BEGIN_CASE(JSOP_STOP) + /* Safe point! */ + emitReturn(NULL); + goto done; + END_CASE(JSOP_STOP) + + BEGIN_CASE(JSOP_GETXPROP) + if (!jsop_xname(script->getAtom(fullAtomIndex(PC)))) + return Compile_Error; + END_CASE(JSOP_GETXPROP) + + BEGIN_CASE(JSOP_ENTERBLOCK) + enterBlock(script->getObject(fullAtomIndex(PC))); + END_CASE(JSOP_ENTERBLOCK); + + BEGIN_CASE(JSOP_LEAVEBLOCK) + leaveBlock(); + END_CASE(JSOP_LEAVEBLOCK) + + BEGIN_CASE(JSOP_CALLLOCAL) + frame.pushLocal(GET_SLOTNO(PC)); + frame.push(UndefinedValue()); + END_CASE(JSOP_CALLLOCAL) + + BEGIN_CASE(JSOP_INT8) + frame.push(Value(Int32Value(GET_INT8(PC)))); + END_CASE(JSOP_INT8) + + BEGIN_CASE(JSOP_INT32) + frame.push(Value(Int32Value(GET_INT32(PC)))); + END_CASE(JSOP_INT32) + + BEGIN_CASE(JSOP_HOLE) + frame.push(MagicValue(JS_ARRAY_HOLE)); + END_CASE(JSOP_HOLE) + + BEGIN_CASE(JSOP_LAMBDA_FC) + { + JSFunction *fun = script->getFunction(fullAtomIndex(PC)); + prepareStubCall(Uses(frame.frameSlots())); + masm.move(ImmPtr(fun), Registers::ArgReg1); + INLINE_STUBCALL(stubs::FlatLambda); + frame.takeReg(Registers::ReturnReg); + frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg); + } + END_CASE(JSOP_LAMBDA_FC) + + BEGIN_CASE(JSOP_TRACE) + BEGIN_CASE(JSOP_NOTRACE) + { + if (analysis->jumpTarget(PC)) + interruptCheckHelper(); + } + END_CASE(JSOP_TRACE) + + BEGIN_CASE(JSOP_DEBUGGER) + prepareStubCall(Uses(0)); + masm.move(ImmPtr(PC), Registers::ArgReg1); + INLINE_STUBCALL(stubs::Debugger); + END_CASE(JSOP_DEBUGGER) + + BEGIN_CASE(JSOP_UNBRAND) + jsop_unbrand(); + END_CASE(JSOP_UNBRAND) + + BEGIN_CASE(JSOP_UNBRANDTHIS) + jsop_this(); + jsop_unbrand(); + frame.pop(); + END_CASE(JSOP_UNBRANDTHIS) + + BEGIN_CASE(JSOP_GETGLOBAL) + BEGIN_CASE(JSOP_CALLGLOBAL) + jsop_getglobal(GET_SLOTNO(PC)); + if (op == JSOP_CALLGLOBAL) + frame.push(UndefinedValue()); + END_CASE(JSOP_GETGLOBAL) + + default: + /* Sorry, this opcode isn't implemented yet. */ +#ifdef JS_METHODJIT_SPEW + JaegerSpew(JSpew_Abort, "opcode %s not handled yet (%s line %d)\n", OpcodeNames[op], + script->filename, js_PCToLineNumber(cx, script, PC)); +#endif + return Compile_Abort; + } + + /********************** + * END COMPILER OPS * + **********************/ + +#ifdef DEBUG + frame.assertValidRegisterState(); +#endif + } + + done: + return Compile_Okay; +} + +#undef END_CASE +#undef BEGIN_CASE + +JSC::MacroAssembler::Label +mjit::Compiler::labelOf(jsbytecode *pc) +{ + uint32 offs = uint32(pc - script->code); + JS_ASSERT(jumpMap[offs].isValid()); + return jumpMap[offs]; +} + +uint32 +mjit::Compiler::fullAtomIndex(jsbytecode *pc) +{ + return GET_SLOTNO(pc); + + /* If we ever enable INDEXBASE garbage, use this below. */ +#if 0 + return GET_SLOTNO(pc) + (atoms - script->atomMap.vector); +#endif +} + +bool +mjit::Compiler::knownJump(jsbytecode *pc) +{ + return pc < PC; +} + +void * +mjit::Compiler::findCallSite(const CallSite &callSite) +{ + JS_ASSERT(callSite.pcOffset < script->length); + + JITScript *jit = script->getJIT(fp->isConstructing()); + uint8* ilPath = (uint8 *)jit->code.m_code.executableAddress(); + uint8* oolPath = ilPath + masm.size(); + + for (uint32 i = 0; i < callSites.length(); i++) { + InternalCallSite &cs = callSites[i]; + if (cs.pc == script->code + callSite.pcOffset && cs.id == callSite.id) { + if (cs.ool) + return oolPath + cs.returnOffset; + return ilPath + cs.returnOffset; + } + } + + /* We have no idea where to patch up to. */ + JS_NOT_REACHED("Call site vanished."); + return NULL; +} + +bool +mjit::Compiler::jumpInScript(Jump j, jsbytecode *pc) +{ + JS_ASSERT(pc >= script->code && uint32(pc - script->code) < script->length); + + if (pc < PC) { + j.linkTo(jumpMap[uint32(pc - script->code)], &masm); + return true; + } + return branchPatches.append(BranchPatch(j, pc)); +} + +void +mjit::Compiler::jsop_getglobal(uint32 index) +{ + JS_ASSERT(globalObj); + uint32 slot = script->getGlobalSlot(index); + + RegisterID reg = frame.allocReg(); + Address address = masm.objSlotRef(globalObj, reg, slot); + frame.freeReg(reg); + frame.push(address); +} + +void +mjit::Compiler::emitFinalReturn(Assembler &masm) +{ + masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfncode()), Registers::ReturnReg); + masm.jump(Registers::ReturnReg); +} + +// Emits code to load a return value of the frame into the scripted-ABI +// type & data register pair. If the return value is in fp->rval, then |fe| +// is NULL. Otherwise, |fe| contains the return value. +// +// If reading from fp->rval, |undefined| is loaded optimistically, before +// checking if fp->rval is set in the frame flags and loading that instead. +// +// Otherwise, if |masm| is the inline path, it is loaded as efficiently as +// the FrameState can manage. If |masm| is the OOL path, the value is simply +// loaded from its slot in the frame, since the caller has guaranteed it's +// been synced. +// +void +mjit::Compiler::loadReturnValue(Assembler *masm, FrameEntry *fe) +{ + RegisterID typeReg = JSReturnReg_Type; + RegisterID dataReg = JSReturnReg_Data; + + if (fe) { + // If using the OOL assembler, the caller signifies that the |fe| is + // synced, but not to rely on its register state. + if (masm != &this->masm) { + if (fe->isConstant()) { + stubcc.masm.loadValueAsComponents(fe->getValue(), typeReg, dataReg); + } else { + Address rval(frame.addressOf(fe)); + if (fe->isTypeKnown()) { + stubcc.masm.loadPayload(rval, dataReg); + stubcc.masm.move(ImmType(fe->getKnownType()), typeReg); + } else { + stubcc.masm.loadValueAsComponents(rval, typeReg, dataReg); + } + } + } else { + frame.loadForReturn(fe, typeReg, dataReg, Registers::ReturnReg); + } + } else { + // Load a return value from POPV or SETRVAL into the return registers, + // otherwise return undefined. + masm->loadValueAsComponents(UndefinedValue(), typeReg, dataReg); + if (analysis->usesReturnValue()) { + Jump rvalClear = masm->branchTest32(Assembler::Zero, + FrameFlagsAddress(), + Imm32(JSFRAME_HAS_RVAL)); + Address rvalAddress(JSFrameReg, JSStackFrame::offsetOfReturnValue()); + masm->loadValueAsComponents(rvalAddress, typeReg, dataReg); + rvalClear.linkTo(masm->label(), masm); + } + } +} + +// This ensures that constructor return values are an object. If a non-object +// is returned, either explicitly or implicitly, the newly created object is +// loaded out of the frame. Otherwise, the explicitly returned object is kept. +// +void +mjit::Compiler::fixPrimitiveReturn(Assembler *masm, FrameEntry *fe) +{ + JS_ASSERT(isConstructing); + + bool ool = (masm != &this->masm); + Address thisv(JSFrameReg, JSStackFrame::offsetOfThis(fun)); + + // We can just load |thisv| if either of the following is true: + // (1) There is no explicit return value, AND fp->rval is not used. + // (2) There is an explicit return value, and it's known to be primitive. + if ((!fe && !analysis->usesReturnValue()) || + (fe && fe->isTypeKnown() && fe->getKnownType() != JSVAL_TYPE_OBJECT)) + { + if (ool) + masm->loadValueAsComponents(thisv, JSReturnReg_Type, JSReturnReg_Data); + else + frame.loadThisForReturn(JSReturnReg_Type, JSReturnReg_Data, Registers::ReturnReg); + return; + } + + // If the type is known to be an object, just load the return value as normal. + if (fe && fe->isTypeKnown() && fe->getKnownType() == JSVAL_TYPE_OBJECT) { + loadReturnValue(masm, fe); + return; + } + + // There's a return value, and its type is unknown. Test the type and load + // |thisv| if necessary. + loadReturnValue(masm, fe); + Jump j = masm->testObject(Assembler::Equal, JSReturnReg_Type); + masm->loadValueAsComponents(thisv, JSReturnReg_Type, JSReturnReg_Data); + j.linkTo(masm->label(), masm); +} + +// Loads the return value into the scripted ABI register pair, such that JS +// semantics in constructors are preserved. +// +void +mjit::Compiler::emitReturnValue(Assembler *masm, FrameEntry *fe) +{ + if (isConstructing) + fixPrimitiveReturn(masm, fe); + else + loadReturnValue(masm, fe); +} + +void +mjit::Compiler::emitReturn(FrameEntry *fe) +{ + JS_ASSERT_IF(!fun, JSOp(*PC) == JSOP_STOP); + + /* Only the top of the stack can be returned. */ + JS_ASSERT_IF(fe, fe == frame.peek(-1)); + + if (debugMode() || Probes::callTrackingActive(cx)) { + prepareStubCall(Uses(0)); + INLINE_STUBCALL(stubs::LeaveScript); + } + + /* + * If there's a function object, deal with the fact that it can escape. + * Note that after we've placed the call object, all tracked state can + * be thrown away. This will happen anyway because the next live opcode + * (if any) must have an incoming edge. + * + * However, it's an optimization to throw it away early - the tracker + * won't be spilled on further exits or join points. + */ + if (fun) { + if (fun->isHeavyweight()) { + /* There will always be a call object. */ + prepareStubCall(Uses(fe ? 1 : 0)); + INLINE_STUBCALL(stubs::PutActivationObjects); + } else { + /* if (hasCallObj() || hasArgsObj()) stubs::PutActivationObjects() */ + Jump putObjs = masm.branchTest32(Assembler::NonZero, + Address(JSFrameReg, JSStackFrame::offsetOfFlags()), + Imm32(JSFRAME_HAS_CALL_OBJ | JSFRAME_HAS_ARGS_OBJ)); + stubcc.linkExit(putObjs, Uses(frame.frameSlots())); + + stubcc.leave(); + OOL_STUBCALL(stubs::PutActivationObjects); + + emitReturnValue(&stubcc.masm, fe); + emitFinalReturn(stubcc.masm); + } + } else { + if (fp->isEvalFrame() && script->strictModeCode) { + /* There will always be a call object. */ + prepareStubCall(Uses(fe ? 1 : 0)); + INLINE_STUBCALL(stubs::PutStrictEvalCallObject); + } + } + + emitReturnValue(&masm, fe); + emitFinalReturn(masm); + frame.discardFrame(); +} + +void +mjit::Compiler::prepareStubCall(Uses uses) +{ + JaegerSpew(JSpew_Insns, " ---- STUB CALL, SYNCING FRAME ---- \n"); + frame.syncAndKill(Registers(Registers::TempRegs), uses); + JaegerSpew(JSpew_Insns, " ---- FRAME SYNCING DONE ---- \n"); +} + +JSC::MacroAssembler::Call +mjit::Compiler::emitStubCall(void *ptr) +{ + JaegerSpew(JSpew_Insns, " ---- CALLING STUB ---- \n"); + Call cl = masm.fallibleVMCall(ptr, PC, frame.stackDepth() + script->nfixed); + JaegerSpew(JSpew_Insns, " ---- END STUB CALL ---- \n"); + return cl; +} + +void +mjit::Compiler::interruptCheckHelper() +{ + RegisterID reg = frame.allocReg(); + + /* + * Bake in and test the address of the interrupt counter for the runtime. + * This is faster than doing two additional loads for the context's + * thread data, but will cause this thread to run slower if there are + * pending interrupts on some other thread. For non-JS_THREADSAFE builds + * we can skip this, as there is only one flag to poll. + */ +#ifdef JS_THREADSAFE + void *interrupt = (void*) &cx->runtime->interruptCounter; +#else + void *interrupt = (void*) &JS_THREAD_DATA(cx)->interruptFlags; +#endif + +#if defined(JS_CPU_X86) || defined(JS_CPU_ARM) + Jump jump = masm.branch32(Assembler::NotEqual, AbsoluteAddress(interrupt), Imm32(0)); +#else + /* Handle processors that can't load from absolute addresses. */ + masm.move(ImmPtr(interrupt), reg); + Jump jump = masm.branchTest32(Assembler::NonZero, Address(reg, 0)); +#endif + + stubcc.linkExitDirect(jump, stubcc.masm.label()); + +#ifdef JS_THREADSAFE + /* + * Do a slightly slower check for an interrupt on this thread. + * We don't want this thread to slow down excessively if the pending + * interrupt is on another thread. + */ + stubcc.masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), reg); + stubcc.masm.loadPtr(Address(reg, offsetof(JSContext, thread)), reg); + Address flag(reg, offsetof(JSThread, data.interruptFlags)); + Jump noInterrupt = stubcc.masm.branchTest32(Assembler::Zero, flag); +#endif + + frame.sync(stubcc.masm, Uses(0)); + stubcc.masm.move(ImmPtr(PC), Registers::ArgReg1); + OOL_STUBCALL(stubs::Interrupt); + stubcc.rejoin(Changes(0)); + +#ifdef JS_THREADSAFE + stubcc.linkRejoin(noInterrupt); +#endif + + frame.freeReg(reg); +} + +void +mjit::Compiler::addReturnSite(Label joinPoint, uint32 id) +{ + InternalCallSite site(masm.distanceOf(joinPoint), PC, id, false, false); + addCallSite(site); +} + +void +mjit::Compiler::emitUncachedCall(uint32 argc, bool callingNew) +{ + CallPatchInfo callPatch; + + RegisterID r0 = Registers::ReturnReg; + VoidPtrStubUInt32 stub = callingNew ? stubs::UncachedNew : stubs::UncachedCall; + + frame.syncAndKill(Registers(Registers::AvailRegs), Uses(argc + 2)); + prepareStubCall(Uses(argc + 2)); + masm.move(Imm32(argc), Registers::ArgReg1); + INLINE_STUBCALL(stub); + + Jump notCompiled = masm.branchTestPtr(Assembler::Zero, r0, r0); + + masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg); + callPatch.hasFastNcode = true; + callPatch.fastNcodePatch = + masm.storePtrWithPatch(ImmPtr(NULL), + Address(JSFrameReg, JSStackFrame::offsetOfncode())); + + masm.jump(r0); + callPatch.joinPoint = masm.label(); + addReturnSite(callPatch.joinPoint, __LINE__); + masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfPrev()), JSFrameReg); + + frame.popn(argc + 2); + frame.takeReg(JSReturnReg_Type); + frame.takeReg(JSReturnReg_Data); + frame.pushRegs(JSReturnReg_Type, JSReturnReg_Data); + + stubcc.linkExitDirect(notCompiled, stubcc.masm.label()); + stubcc.rejoin(Changes(0)); + callPatches.append(callPatch); +} + +static bool +IsLowerableFunCallOrApply(jsbytecode *pc) +{ +#ifdef JS_MONOIC + return (*pc == JSOP_FUNCALL && GET_ARGC(pc) >= 1) || + (*pc == JSOP_FUNAPPLY && GET_ARGC(pc) == 2); +#else + return false; +#endif +} + +void +mjit::Compiler::checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedArgc, + FrameEntry *origCallee, FrameEntry *origThis, + MaybeRegisterID origCalleeType, RegisterID origCalleeData, + MaybeRegisterID origThisType, RegisterID origThisData, + Jump *uncachedCallSlowRejoin, CallPatchInfo *uncachedCallPatch) +{ + JS_ASSERT(IsLowerableFunCallOrApply(PC)); + + /* + * if (origCallee.isObject() && + * origCallee.toObject().isFunction && + * origCallee.toObject().getFunctionPrivate() == js_fun_{call,apply}) + */ + MaybeJump isObj; + if (origCalleeType.isSet()) + isObj = masm.testObject(Assembler::NotEqual, origCalleeType.reg()); + Jump isFun = masm.testFunction(Assembler::NotEqual, origCalleeData); + masm.loadObjPrivate(origCalleeData, origCalleeData); + Native native = *PC == JSOP_FUNCALL ? js_fun_call : js_fun_apply; + Jump isNative = masm.branchPtr(Assembler::NotEqual, + Address(origCalleeData, JSFunction::offsetOfNativeOrScript()), + ImmPtr(JS_FUNC_TO_DATA_PTR(void *, native))); + + /* + * If speculation fails, we can't use the ic, since it is compiled on the + * assumption that speculation succeeds. Instead, just do an uncached call. + */ + { + if (isObj.isSet()) + stubcc.linkExitDirect(isObj.getJump(), stubcc.masm.label()); + stubcc.linkExitDirect(isFun, stubcc.masm.label()); + stubcc.linkExitDirect(isNative, stubcc.masm.label()); + + int32 frameDepthAdjust; + if (applyTricks == LazyArgsObj) { + OOL_STUBCALL(stubs::Arguments); + frameDepthAdjust = +1; + } else { + frameDepthAdjust = 0; + } + + stubcc.masm.move(Imm32(callImmArgc), Registers::ArgReg1); + JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW CALL CODE ---- \n"); + OOL_STUBCALL_LOCAL_SLOTS(JS_FUNC_TO_DATA_PTR(void *, stubs::UncachedCall), + frame.localSlots() + frameDepthAdjust); + JaegerSpew(JSpew_Insns, " ---- END SLOW CALL CODE ---- \n"); + + RegisterID r0 = Registers::ReturnReg; + Jump notCompiled = stubcc.masm.branchTestPtr(Assembler::Zero, r0, r0); + + stubcc.masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg); + Address ncodeAddr(JSFrameReg, JSStackFrame::offsetOfncode()); + uncachedCallPatch->hasSlowNcode = true; + uncachedCallPatch->slowNcodePatch = stubcc.masm.storePtrWithPatch(ImmPtr(NULL), ncodeAddr); + + stubcc.masm.jump(r0); + addReturnSite(masm.label(), __LINE__); + + notCompiled.linkTo(stubcc.masm.label(), &stubcc.masm); + + /* + * inlineCallHelper will link uncachedCallSlowRejoin to the join point + * at the end of the ic. At that join point, the return value of the + * call is assumed to be in registers, so load them before jumping. + */ + JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW RESTORE CODE ---- \n"); + Address rval = frame.addressOf(origCallee); /* vp[0] == rval */ + stubcc.masm.loadValueAsComponents(rval, JSReturnReg_Type, JSReturnReg_Data); + *uncachedCallSlowRejoin = stubcc.masm.jump(); + JaegerSpew(JSpew_Insns, " ---- END SLOW RESTORE CODE ---- \n"); + } + + /* + * For simplicity, we don't statically specialize calls to + * ic::SplatApplyArgs based on applyTricks. Rather, this state is + * communicated dynamically through the VMFrame. + */ + if (*PC == JSOP_FUNAPPLY) { + masm.store32(Imm32(applyTricks == LazyArgsObj), + FrameAddress(offsetof(VMFrame, u.call.lazyArgsObj))); + } +} + +/* This predicate must be called before the current op mutates the FrameState. */ +bool +mjit::Compiler::canUseApplyTricks() +{ + JS_ASSERT(*PC == JSOP_ARGUMENTS); + jsbytecode *nextpc = PC + JSOP_ARGUMENTS_LENGTH; + return *nextpc == JSOP_FUNAPPLY && + IsLowerableFunCallOrApply(nextpc) && + !analysis->jumpTarget(nextpc) && + !debugMode(); +} + +/* See MonoIC.cpp, CallCompiler for more information on call ICs. */ +void +mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew) +{ + /* Check for interrupts on function call */ + interruptCheckHelper(); + + int32 speculatedArgc; + if (applyTricks == LazyArgsObj) { + frame.pop(); + speculatedArgc = 1; + } else { + speculatedArgc = callImmArgc; + } + + FrameEntry *origCallee = frame.peek(-(speculatedArgc + 2)); + FrameEntry *origThis = frame.peek(-(speculatedArgc + 1)); + + /* 'this' does not need to be synced for constructing. */ + if (callingNew) + frame.discardFe(origThis); + + /* + * From the presence of JSOP_FUN{CALL,APPLY}, we speculate that we are + * going to call js_fun_{call,apply}. Normally, this call would go through + * js::Invoke to ultimately call 'this'. We can do much better by having + * the callIC cache and call 'this' directly. However, if it turns out that + * we are not actually calling js_fun_call, the callIC must act as normal. + */ + bool lowerFunCallOrApply = IsLowerableFunCallOrApply(PC); + + /* + * Currently, constant values are not functions, so don't even try to + * optimize. This lets us assume that callee/this have regs below. + */ +#ifdef JS_MONOIC + if (debugMode() || + origCallee->isConstant() || origCallee->isNotType(JSVAL_TYPE_OBJECT) || + (lowerFunCallOrApply && + (origThis->isConstant() || origThis->isNotType(JSVAL_TYPE_OBJECT)))) { +#endif + if (applyTricks == LazyArgsObj) { + /* frame.pop() above reset us to pre-JSOP_ARGUMENTS state */ + jsop_arguments(); + frame.pushSynced(); + } + emitUncachedCall(callImmArgc, callingNew); + return; +#ifdef JS_MONOIC + } + + /* Initialized by both branches below. */ + CallGenInfo callIC(PC); + CallPatchInfo callPatch; + MaybeRegisterID icCalleeType; /* type to test for function-ness */ + RegisterID icCalleeData; /* data to call */ + Address icRvalAddr; /* return slot on slow-path rejoin */ + + /* + * IC space must be reserved (using RESERVE_IC_SPACE or RESERVE_OOL_SPACE) between the + * following labels (as used in finishThisUp): + * - funGuard -> hotJump + * - funGuard -> joinPoint + * - funGuard -> hotPathLabel + * - slowPathStart -> oolCall + * - slowPathStart -> oolJump + * - slowPathStart -> icCall + * - slowPathStart -> slowJoinPoint + * Because the call ICs are fairly long (compared to PICs), we don't reserve the space in each + * path until the first usage of funGuard (for the in-line path) or slowPathStart (for the + * out-of-line path). + */ + + /* Initialized only on lowerFunCallOrApply branch. */ + Jump uncachedCallSlowRejoin; + CallPatchInfo uncachedCallPatch; + + { + MaybeRegisterID origCalleeType, maybeOrigCalleeData; + RegisterID origCalleeData; + + /* Get the callee in registers. */ + frame.ensureFullRegs(origCallee, &origCalleeType, &maybeOrigCalleeData); + origCalleeData = maybeOrigCalleeData.reg(); + PinRegAcrossSyncAndKill p1(frame, origCalleeData), p2(frame, origCalleeType); + + if (lowerFunCallOrApply) { + MaybeRegisterID origThisType, maybeOrigThisData; + RegisterID origThisData; + { + /* Get thisv in registers. */ + frame.ensureFullRegs(origThis, &origThisType, &maybeOrigThisData); + origThisData = maybeOrigThisData.reg(); + PinRegAcrossSyncAndKill p3(frame, origThisData), p4(frame, origThisType); + + /* Leaves pinned regs untouched. */ + frame.syncAndKill(Registers(Registers::AvailRegs), Uses(speculatedArgc + 2)); + } + + checkCallApplySpeculation(callImmArgc, speculatedArgc, + origCallee, origThis, + origCalleeType, origCalleeData, + origThisType, origThisData, + &uncachedCallSlowRejoin, &uncachedCallPatch); + + icCalleeType = origThisType; + icCalleeData = origThisData; + icRvalAddr = frame.addressOf(origThis); + + /* + * For f.call(), since we compile the ic under the (checked) + * assumption that call == js_fun_call, we still have a static + * frame size. For f.apply(), the frame size depends on the dynamic + * length of the array passed to apply. + */ + if (*PC == JSOP_FUNCALL) + callIC.frameSize.initStatic(frame.localSlots(), speculatedArgc - 1); + else + callIC.frameSize.initDynamic(); + } else { + /* Leaves pinned regs untouched. */ + frame.syncAndKill(Registers(Registers::AvailRegs), Uses(speculatedArgc + 2)); + + icCalleeType = origCalleeType; + icCalleeData = origCalleeData; + icRvalAddr = frame.addressOf(origCallee); + callIC.frameSize.initStatic(frame.localSlots(), speculatedArgc); + } + } + + /* Test the type if necessary. Failing this always takes a really slow path. */ + MaybeJump notObjectJump; + if (icCalleeType.isSet()) + notObjectJump = masm.testObject(Assembler::NotEqual, icCalleeType.reg()); + + /* + * For an optimized apply, keep icCalleeData and funPtrReg in a + * callee-saved registers for the subsequent ic::SplatApplyArgs call. + */ + Registers tempRegs; + if (callIC.frameSize.isDynamic() && !Registers::isSaved(icCalleeData)) { + RegisterID x = tempRegs.takeRegInMask(Registers::SavedRegs); + masm.move(icCalleeData, x); + icCalleeData = x; + } else { + tempRegs.takeReg(icCalleeData); + } + RegisterID funPtrReg = tempRegs.takeRegInMask(Registers::SavedRegs); + + /* Reserve space just before initialization of funGuard. */ + RESERVE_IC_SPACE(masm); + + /* + * Guard on the callee identity. This misses on the first run. If the + * callee is scripted, compiled/compilable, and argc == nargs, then this + * guard is patched, and the compiled code address is baked in. + */ + Jump j = masm.branchPtrWithPatch(Assembler::NotEqual, icCalleeData, callIC.funGuard); + callIC.funJump = j; + + /* Reserve space just before initialization of slowPathStart. */ + RESERVE_OOL_SPACE(stubcc.masm); + + Jump rejoin1, rejoin2; + { + RESERVE_OOL_SPACE(stubcc.masm); + stubcc.linkExitDirect(j, stubcc.masm.label()); + callIC.slowPathStart = stubcc.masm.label(); + + /* + * Test if the callee is even a function. If this doesn't match, we + * take a _really_ slow path later. + */ + Jump notFunction = stubcc.masm.testFunction(Assembler::NotEqual, icCalleeData); + + /* Test if the function is scripted. */ + RegisterID tmp = tempRegs.takeAnyReg(); + stubcc.masm.loadObjPrivate(icCalleeData, funPtrReg); + stubcc.masm.load16(Address(funPtrReg, offsetof(JSFunction, flags)), tmp); + stubcc.masm.and32(Imm32(JSFUN_KINDMASK), tmp); + Jump isNative = stubcc.masm.branch32(Assembler::Below, tmp, Imm32(JSFUN_INTERPRETED)); + tempRegs.putReg(tmp); + + /* + * N.B. After this call, the frame will have a dynamic frame size. + * Check after the function is known not to be a native so that the + * catch-all/native path has a static depth. + */ + if (callIC.frameSize.isDynamic()) + OOL_STUBCALL(ic::SplatApplyArgs); + + /* + * No-op jump that gets patched by ic::New/Call to the stub generated + * by generateFullCallStub. + */ + Jump toPatch = stubcc.masm.jump(); + toPatch.linkTo(stubcc.masm.label(), &stubcc.masm); + callIC.oolJump = toPatch; + callIC.icCall = stubcc.masm.label(); + + /* + * At this point the function is definitely scripted, so we try to + * compile it and patch either funGuard/funJump or oolJump. This code + * is only executed once. + */ + callIC.addrLabel1 = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1); + void *icFunPtr = JS_FUNC_TO_DATA_PTR(void *, callingNew ? ic::New : ic::Call); + if (callIC.frameSize.isStatic()) + callIC.oolCall = OOL_STUBCALL_LOCAL_SLOTS(icFunPtr, frame.localSlots()); + else + callIC.oolCall = OOL_STUBCALL_LOCAL_SLOTS(icFunPtr, -1); + + callIC.funObjReg = icCalleeData; + callIC.funPtrReg = funPtrReg; + + /* + * The IC call either returns NULL, meaning call completed, or a + * function pointer to jump to. Caveat: Must restore JSFrameReg + * because a new frame has been pushed. + */ + rejoin1 = stubcc.masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg, + Registers::ReturnReg); + if (callIC.frameSize.isStatic()) + stubcc.masm.move(Imm32(callIC.frameSize.staticArgc()), JSParamReg_Argc); + else + stubcc.masm.load32(FrameAddress(offsetof(VMFrame, u.call.dynamicArgc)), JSParamReg_Argc); + stubcc.masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg); + callPatch.hasSlowNcode = true; + callPatch.slowNcodePatch = + stubcc.masm.storePtrWithPatch(ImmPtr(NULL), + Address(JSFrameReg, JSStackFrame::offsetOfncode())); + stubcc.masm.jump(Registers::ReturnReg); + + /* + * This ool path is the catch-all for everything but scripted function + * callees. For native functions, ic::NativeNew/NativeCall will repatch + * funGaurd/funJump with a fast call stub. All other cases + * (non-function callable objects and invalid callees) take the slow + * path through js::Invoke. + */ + if (notObjectJump.isSet()) + stubcc.linkExitDirect(notObjectJump.get(), stubcc.masm.label()); + notFunction.linkTo(stubcc.masm.label(), &stubcc.masm); + isNative.linkTo(stubcc.masm.label(), &stubcc.masm); + + callIC.addrLabel2 = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1); + OOL_STUBCALL(callingNew ? ic::NativeNew : ic::NativeCall); + + rejoin2 = stubcc.masm.jump(); + } + + /* + * If the call site goes to a closure over the same function, it will + * generate an out-of-line stub that joins back here. + */ + callIC.hotPathLabel = masm.label(); + + uint32 flags = 0; + if (callingNew) + flags |= JSFRAME_CONSTRUCTING; + + InlineFrameAssembler inlFrame(masm, callIC, flags); + callPatch.hasFastNcode = true; + callPatch.fastNcodePatch = inlFrame.assemble(NULL); + + callIC.hotJump = masm.jump(); + callIC.joinPoint = callPatch.joinPoint = masm.label(); + addReturnSite(callPatch.joinPoint, __LINE__); + if (lowerFunCallOrApply) + uncachedCallPatch.joinPoint = callIC.joinPoint; + masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfPrev()), JSFrameReg); + + /* + * We've placed hotJump, joinPoint and hotPathLabel, and no other labels are located by offset + * in the in-line path so we can check the IC space now. + */ + CHECK_IC_SPACE(); + + frame.popn(speculatedArgc + 2); + frame.takeReg(JSReturnReg_Type); + frame.takeReg(JSReturnReg_Data); + frame.pushRegs(JSReturnReg_Type, JSReturnReg_Data); + + /* + * Now that the frame state is set, generate the rejoin path. Note that, if + * lowerFunCallOrApply, we cannot just call 'stubcc.rejoin' since the return + * value has been placed at vp[1] which is not the stack address associated + * with frame.peek(-1). + */ + callIC.slowJoinPoint = stubcc.masm.label(); + rejoin1.linkTo(callIC.slowJoinPoint, &stubcc.masm); + rejoin2.linkTo(callIC.slowJoinPoint, &stubcc.masm); + JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW RESTORE CODE ---- \n"); + stubcc.masm.loadValueAsComponents(icRvalAddr, JSReturnReg_Type, JSReturnReg_Data); + stubcc.crossJump(stubcc.masm.jump(), masm.label()); + JaegerSpew(JSpew_Insns, " ---- END SLOW RESTORE CODE ---- \n"); + + CHECK_OOL_SPACE(); + + if (lowerFunCallOrApply) + stubcc.crossJump(uncachedCallSlowRejoin, masm.label()); + + callICs.append(callIC); + callPatches.append(callPatch); + if (lowerFunCallOrApply) + callPatches.append(uncachedCallPatch); + + applyTricks = NoApplyTricks; +#endif +} + +/* + * This function must be called immediately after any instruction which could + * cause a new JSStackFrame to be pushed and could lead to a new debug trap + * being set. This includes any API callbacks and any scripted or native call. + */ +void +mjit::Compiler::addCallSite(const InternalCallSite &site) +{ + callSites.append(site); +} + +void +mjit::Compiler::restoreFrameRegs(Assembler &masm) +{ + masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg); +} + +bool +mjit::Compiler::compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const Value &rhs) +{ + JS_ASSERT(lhs.isPrimitive()); + JS_ASSERT(rhs.isPrimitive()); + + if (lhs.isString() && rhs.isString()) { + int32 cmp; + CompareStrings(cx, lhs.toString(), rhs.toString(), &cmp); + switch (op) { + case JSOP_LT: + return cmp < 0; + case JSOP_LE: + return cmp <= 0; + case JSOP_GT: + return cmp > 0; + case JSOP_GE: + return cmp >= 0; + case JSOP_EQ: + return cmp == 0; + case JSOP_NE: + return cmp != 0; + default: + JS_NOT_REACHED("NYI"); + } + } else { + double ld, rd; + + /* These should be infallible w/ primitives. */ + ValueToNumber(cx, lhs, &ld); + ValueToNumber(cx, rhs, &rd); + switch(op) { + case JSOP_LT: + return ld < rd; + case JSOP_LE: + return ld <= rd; + case JSOP_GT: + return ld > rd; + case JSOP_GE: + return ld >= rd; + case JSOP_EQ: /* fall through */ + case JSOP_NE: + /* Special case null/undefined/void comparisons. */ + if (lhs.isNullOrUndefined()) { + if (rhs.isNullOrUndefined()) + return op == JSOP_EQ; + return op == JSOP_NE; + } + if (rhs.isNullOrUndefined()) + return op == JSOP_NE; + + /* Normal return. */ + return (op == JSOP_EQ) ? (ld == rd) : (ld != rd); + default: + JS_NOT_REACHED("NYI"); + } + } + + JS_NOT_REACHED("NYI"); + return false; +} + +bool +mjit::Compiler::emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused) +{ + prepareStubCall(Uses(2)); + INLINE_STUBCALL(stub); + frame.pop(); + frame.pop(); + + if (!target) { + frame.takeReg(Registers::ReturnReg); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, Registers::ReturnReg); + return true; + } + + JS_ASSERT(fused == JSOP_IFEQ || fused == JSOP_IFNE); + frame.syncAndForgetEverything(); + Assembler::Condition cond = (fused == JSOP_IFEQ) + ? Assembler::Zero + : Assembler::NonZero; + Jump j = masm.branchTest32(cond, Registers::ReturnReg, + Registers::ReturnReg); + return jumpAndTrace(j, target); +} + +void +mjit::Compiler::jsop_setprop_slow(JSAtom *atom, bool usePropCache) +{ + prepareStubCall(Uses(2)); + masm.move(ImmPtr(atom), Registers::ArgReg1); + if (usePropCache) + INLINE_STUBCALL(STRICT_VARIANT(stubs::SetName)); + else + INLINE_STUBCALL(STRICT_VARIANT(stubs::SetPropNoCache)); + JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH); + frame.shimmy(1); +} + +void +mjit::Compiler::jsop_getprop_slow(JSAtom *atom, bool usePropCache) +{ + prepareStubCall(Uses(1)); + if (usePropCache) { + INLINE_STUBCALL(stubs::GetProp); + } else { + masm.move(ImmPtr(atom), Registers::ArgReg1); + INLINE_STUBCALL(stubs::GetPropNoCache); + } + frame.pop(); + frame.pushSynced(); +} + +bool +mjit::Compiler::jsop_callprop_slow(JSAtom *atom) +{ + prepareStubCall(Uses(1)); + masm.move(ImmPtr(atom), Registers::ArgReg1); + INLINE_STUBCALL(stubs::CallProp); + frame.pop(); + frame.pushSynced(); + frame.pushSynced(); + return true; +} + +bool +mjit::Compiler::jsop_length() +{ + FrameEntry *top = frame.peek(-1); + + if (top->isTypeKnown() && top->getKnownType() == JSVAL_TYPE_STRING) { + if (top->isConstant()) { + JSString *str = top->getValue().toString(); + Value v; + v.setNumber(uint32(str->length())); + frame.pop(); + frame.push(v); + } else { + RegisterID str = frame.ownRegForData(top); + masm.loadPtr(Address(str, JSString::offsetOfLengthAndFlags()), str); + masm.urshift32(Imm32(JSString::LENGTH_SHIFT), str); + frame.pop(); + frame.pushTypedPayload(JSVAL_TYPE_INT32, str); + } + return true; + } + +#if defined JS_POLYIC + return jsop_getprop(cx->runtime->atomState.lengthAtom); +#else + prepareStubCall(Uses(1)); + INLINE_STUBCALL(stubs::Length); + frame.pop(); + frame.pushSynced(); + return true; +#endif +} + +#ifdef JS_MONOIC +void +mjit::Compiler::passMICAddress(GlobalNameICInfo &ic) +{ + ic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1); +} +#endif + +#if defined JS_POLYIC +void +mjit::Compiler::passICAddress(BaseICInfo *ic) +{ + ic->paramAddr = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1); +} + +bool +mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache) +{ + FrameEntry *top = frame.peek(-1); + + /* If the incoming type will never PIC, take slow path. */ + if (top->isTypeKnown() && top->getKnownType() != JSVAL_TYPE_OBJECT) { + JS_ASSERT_IF(atom == cx->runtime->atomState.lengthAtom, + top->getKnownType() != JSVAL_TYPE_STRING); + jsop_getprop_slow(atom, usePropCache); + return true; + } + + /* + * These two must be loaded first. The objReg because the string path + * wants to read it, and the shapeReg because it could cause a spill that + * the string path wouldn't sink back. + */ + RegisterID objReg = Registers::ReturnReg; + RegisterID shapeReg = Registers::ReturnReg; + if (atom == cx->runtime->atomState.lengthAtom) { + objReg = frame.copyDataIntoReg(top); + shapeReg = frame.allocReg(); + } + + RESERVE_IC_SPACE(masm); + + PICGenInfo pic(ic::PICInfo::GET, JSOp(*PC), usePropCache); + + /* Guard that the type is an object. */ + Label typeCheck; + if (doTypeCheck && !top->isTypeKnown()) { + RegisterID reg = frame.tempRegForType(top); + pic.typeReg = reg; + + /* Start the hot path where it's easy to patch it. */ + pic.fastPathStart = masm.label(); + Jump j = masm.testObject(Assembler::NotEqual, reg); + typeCheck = masm.label(); + RETURN_IF_OOM(false); + + pic.typeCheck = stubcc.linkExit(j, Uses(1)); + pic.hasTypeCheck = true; + } else { + pic.fastPathStart = masm.label(); + pic.hasTypeCheck = false; + pic.typeReg = Registers::ReturnReg; + } + + if (atom != cx->runtime->atomState.lengthAtom) { + objReg = frame.copyDataIntoReg(top); + shapeReg = frame.allocReg(); + } + + pic.shapeReg = shapeReg; + pic.atom = atom; + + /* Guard on shape. */ + masm.loadShape(objReg, shapeReg); + pic.shapeGuard = masm.label(); + + DataLabel32 inlineShapeLabel; + Jump j = masm.branch32WithPatch(Assembler::NotEqual, shapeReg, + Imm32(int32(JSObjectMap::INVALID_SHAPE)), + inlineShapeLabel); + Label inlineShapeJump = masm.label(); + + RESERVE_OOL_SPACE(stubcc.masm); + pic.slowPathStart = stubcc.linkExit(j, Uses(1)); + + stubcc.leave(); + passICAddress(&pic); + pic.slowPathCall = OOL_STUBCALL(ic::GetProp); + CHECK_OOL_SPACE(); + + /* Load the base slot address. */ + Label dslotsLoadLabel = masm.loadPtrWithPatchToLEA(Address(objReg, offsetof(JSObject, slots)), + objReg); + + /* Copy the slot value to the expression stack. */ + Address slot(objReg, 1 << 24); + frame.pop(); + + Label fastValueLoad = masm.loadValueWithAddressOffsetPatch(slot, shapeReg, objReg); + pic.fastPathRejoin = masm.label(); + + RETURN_IF_OOM(false); + + /* Initialize op labels. */ + GetPropLabels &labels = pic.getPropLabels(); + labels.setDslotsLoad(masm, pic.fastPathRejoin, dslotsLoadLabel); + labels.setInlineShapeData(masm, pic.shapeGuard, inlineShapeLabel); + + labels.setValueLoad(masm, pic.fastPathRejoin, fastValueLoad); + if (pic.hasTypeCheck) + labels.setInlineTypeJump(masm, pic.fastPathStart, typeCheck); +#ifdef JS_CPU_X64 + labels.setInlineShapeJump(masm, inlineShapeLabel, inlineShapeJump); +#else + labels.setInlineShapeJump(masm, pic.shapeGuard, inlineShapeJump); +#endif + + pic.objReg = objReg; + frame.pushRegs(shapeReg, objReg); + + stubcc.rejoin(Changes(1)); + + pics.append(pic); + return true; +} + +bool +mjit::Compiler::jsop_callprop_generic(JSAtom *atom) +{ + FrameEntry *top = frame.peek(-1); + + /* + * These two must be loaded first. The objReg because the string path + * wants to read it, and the shapeReg because it could cause a spill that + * the string path wouldn't sink back. + */ + RegisterID objReg = frame.copyDataIntoReg(top); + RegisterID shapeReg = frame.allocReg(); + + PICGenInfo pic(ic::PICInfo::CALL, JSOp(*PC), true); + + pic.pc = PC; + + /* Guard that the type is an object. */ + pic.typeReg = frame.copyTypeIntoReg(top); + + RESERVE_IC_SPACE(masm); + + /* Start the hot path where it's easy to patch it. */ + pic.fastPathStart = masm.label(); + + /* + * Guard that the value is an object. This part needs some extra gunk + * because the leave() after the shape guard will emit a jump from this + * path to the final call. We need a label in between that jump, which + * will be the target of patched jumps in the PIC. + */ + Jump typeCheckJump = masm.testObject(Assembler::NotEqual, pic.typeReg); + Label typeCheck = masm.label(); + RETURN_IF_OOM(false); + + pic.typeCheck = stubcc.linkExit(typeCheckJump, Uses(1)); + pic.hasTypeCheck = true; + pic.objReg = objReg; + pic.shapeReg = shapeReg; + pic.atom = atom; + + /* + * Store the type and object back. Don't bother keeping them in registers, + * since a sync will be needed for the upcoming call. + */ + uint32 thisvSlot = frame.localSlots(); + Address thisv = Address(JSFrameReg, sizeof(JSStackFrame) + thisvSlot * sizeof(Value)); + +#if defined JS_NUNBOX32 + masm.storeValueFromComponents(pic.typeReg, pic.objReg, thisv); +#elif defined JS_PUNBOX64 + masm.orPtr(pic.objReg, pic.typeReg); + masm.storePtr(pic.typeReg, thisv); +#endif + + frame.freeReg(pic.typeReg); + + /* Guard on shape. */ + masm.loadShape(objReg, shapeReg); + pic.shapeGuard = masm.label(); + + DataLabel32 inlineShapeLabel; + Jump j = masm.branch32WithPatch(Assembler::NotEqual, shapeReg, + Imm32(int32(JSObjectMap::INVALID_SHAPE)), + inlineShapeLabel); + Label inlineShapeJump = masm.label(); + + /* Slow path. */ + RESERVE_OOL_SPACE(stubcc.masm); + pic.slowPathStart = stubcc.linkExit(j, Uses(1)); + stubcc.leave(); + passICAddress(&pic); + pic.slowPathCall = OOL_STUBCALL(ic::CallProp); + CHECK_OOL_SPACE(); + + /* Adjust the frame. None of this will generate code. */ + frame.pop(); + frame.pushRegs(shapeReg, objReg); + frame.pushSynced(); + + /* Load the base slot address. */ + Label dslotsLoadLabel = masm.loadPtrWithPatchToLEA(Address(objReg, offsetof(JSObject, slots)), + objReg); + + /* Copy the slot value to the expression stack. */ + Address slot(objReg, 1 << 24); + + Label fastValueLoad = masm.loadValueWithAddressOffsetPatch(slot, shapeReg, objReg); + pic.fastPathRejoin = masm.label(); + + RETURN_IF_OOM(false); + + /* + * Initialize op labels. We use GetPropLabels here because we have the same patching + * requirements for CallProp. + */ + GetPropLabels &labels = pic.getPropLabels(); + labels.setDslotsLoadOffset(masm.differenceBetween(pic.fastPathRejoin, dslotsLoadLabel)); + labels.setInlineShapeOffset(masm.differenceBetween(pic.shapeGuard, inlineShapeLabel)); + labels.setValueLoad(masm, pic.fastPathRejoin, fastValueLoad); + labels.setInlineTypeJump(masm, pic.fastPathStart, typeCheck); +#ifdef JS_CPU_X64 + labels.setInlineShapeJump(masm, inlineShapeLabel, inlineShapeJump); +#else + labels.setInlineShapeJump(masm, pic.shapeGuard, inlineShapeJump); +#endif + + stubcc.rejoin(Changes(2)); + pics.append(pic); + + return true; +} + +bool +mjit::Compiler::jsop_callprop_str(JSAtom *atom) +{ + if (!script->compileAndGo) { + jsop_callprop_slow(atom); + return true; + } + + /* + * Bake in String.prototype. This is safe because of compileAndGo. + * We must pass an explicit scope chain only because JSD calls into + * here via the recompiler with a dummy context, and we need to use + * the global object for the script we are now compiling. + */ + JSObject *obj; + if (!js_GetClassPrototype(cx, &fp->scopeChain(), JSProto_String, &obj)) + return false; + + /* Force into a register because getprop won't expect a constant. */ + RegisterID reg = frame.allocReg(); + + masm.move(ImmPtr(obj), reg); + frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg); + + /* Get the property. */ + if (!jsop_getprop(atom)) + return false; + + /* Perform a swap. */ + frame.dup2(); + frame.shift(-3); + frame.shift(-1); + + /* 4) Test if the function can take a primitive. */ +#ifdef DEBUG + FrameEntry *funFe = frame.peek(-2); +#endif + JS_ASSERT(!funFe->isTypeKnown()); + + /* + * See bug 584579 - need to forget string type, since wrapping could + * create an object. forgetType() alone is not valid because it cannot be + * used on copies or constants. + */ + RegisterID strReg; + FrameEntry *strFe = frame.peek(-1); + if (strFe->isConstant()) { + strReg = frame.allocReg(); + masm.move(ImmPtr(strFe->getValue().toString()), strReg); + } else { + strReg = frame.ownRegForData(strFe); + } + frame.pop(); + frame.pushTypedPayload(JSVAL_TYPE_STRING, strReg); + frame.forgetType(frame.peek(-1)); + + return true; +} + +bool +mjit::Compiler::jsop_callprop_obj(JSAtom *atom) +{ + FrameEntry *top = frame.peek(-1); + + PICGenInfo pic(ic::PICInfo::CALL, JSOp(*PC), true); + + JS_ASSERT(top->isTypeKnown()); + JS_ASSERT(top->getKnownType() == JSVAL_TYPE_OBJECT); + + RESERVE_IC_SPACE(masm); + + pic.pc = PC; + pic.fastPathStart = masm.label(); + pic.hasTypeCheck = false; + pic.typeReg = Registers::ReturnReg; + + RegisterID objReg = frame.copyDataIntoReg(top); + RegisterID shapeReg = frame.allocReg(); + + pic.shapeReg = shapeReg; + pic.atom = atom; + + /* Guard on shape. */ + masm.loadShape(objReg, shapeReg); + pic.shapeGuard = masm.label(); + + DataLabel32 inlineShapeLabel; + Jump j = masm.branch32WithPatch(Assembler::NotEqual, shapeReg, + Imm32(int32(JSObjectMap::INVALID_SHAPE)), + inlineShapeLabel); + Label inlineShapeJump = masm.label(); + + /* Slow path. */ + RESERVE_OOL_SPACE(stubcc.masm); + pic.slowPathStart = stubcc.linkExit(j, Uses(1)); + stubcc.leave(); + passICAddress(&pic); + pic.slowPathCall = OOL_STUBCALL(ic::CallProp); + CHECK_OOL_SPACE(); + + /* Load the base slot address. */ + Label dslotsLoadLabel = masm.loadPtrWithPatchToLEA(Address(objReg, offsetof(JSObject, slots)), + objReg); + + /* Copy the slot value to the expression stack. */ + Address slot(objReg, 1 << 24); + + Label fastValueLoad = masm.loadValueWithAddressOffsetPatch(slot, shapeReg, objReg); + + pic.fastPathRejoin = masm.label(); + pic.objReg = objReg; + + /* + * 1) Dup the |this| object. + * 2) Push the property value onto the stack. + * 3) Move the value below the dup'd |this|, uncopying it. This could + * generate code, thus the fastPathRejoin label being prior. This is safe + * as a stack transition, because JSOP_CALLPROP has JOF_TMPSLOT. It is + * also safe for correctness, because if we know the LHS is an object, it + * is the resulting vp[1]. + */ + frame.dup(); + frame.pushRegs(shapeReg, objReg); + frame.shift(-2); + + /* + * Assert correctness of hardcoded offsets. + * No type guard: type is asserted. + */ + RETURN_IF_OOM(false); + + GetPropLabels &labels = pic.getPropLabels(); + labels.setDslotsLoadOffset(masm.differenceBetween(pic.fastPathRejoin, dslotsLoadLabel)); + labels.setInlineShapeOffset(masm.differenceBetween(pic.shapeGuard, inlineShapeLabel)); + labels.setValueLoad(masm, pic.fastPathRejoin, fastValueLoad); +#ifdef JS_CPU_X64 + labels.setInlineShapeJump(masm, inlineShapeLabel, inlineShapeJump); +#else + labels.setInlineShapeJump(masm, pic.shapeGuard, inlineShapeJump); +#endif + + stubcc.rejoin(Changes(2)); + pics.append(pic); + + return true; +} + +bool +mjit::Compiler::jsop_callprop(JSAtom *atom) +{ + FrameEntry *top = frame.peek(-1); + + /* If the incoming type will never PIC, take slow path. */ + if (top->isTypeKnown() && top->getKnownType() != JSVAL_TYPE_OBJECT) { + if (top->getKnownType() == JSVAL_TYPE_STRING) + return jsop_callprop_str(atom); + return jsop_callprop_slow(atom); + } + + if (top->isTypeKnown()) + return jsop_callprop_obj(atom); + return jsop_callprop_generic(atom); +} + +bool +mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache) +{ + FrameEntry *lhs = frame.peek(-2); + FrameEntry *rhs = frame.peek(-1); + + /* If the incoming type will never PIC, take slow path. */ + if (lhs->isTypeKnown() && lhs->getKnownType() != JSVAL_TYPE_OBJECT) { + jsop_setprop_slow(atom, usePropCache); + return true; + } + + JSOp op = JSOp(*PC); + + ic::PICInfo::Kind kind = (op == JSOP_SETMETHOD) + ? ic::PICInfo::SETMETHOD + : ic::PICInfo::SET; + PICGenInfo pic(kind, op, usePropCache); + pic.atom = atom; + + RESERVE_IC_SPACE(masm); + RESERVE_OOL_SPACE(stubcc.masm); + + /* Guard that the type is an object. */ + Jump typeCheck; + if (!lhs->isTypeKnown()) { + RegisterID reg = frame.tempRegForType(lhs); + pic.typeReg = reg; + + /* Start the hot path where it's easy to patch it. */ + pic.fastPathStart = masm.label(); + Jump j = masm.testObject(Assembler::NotEqual, reg); + + pic.typeCheck = stubcc.linkExit(j, Uses(2)); + stubcc.leave(); + + stubcc.masm.move(ImmPtr(atom), Registers::ArgReg1); + if (usePropCache) + OOL_STUBCALL(STRICT_VARIANT(stubs::SetName)); + else + OOL_STUBCALL(STRICT_VARIANT(stubs::SetPropNoCache)); + typeCheck = stubcc.masm.jump(); + pic.hasTypeCheck = true; + } else { + pic.fastPathStart = masm.label(); + pic.hasTypeCheck = false; + pic.typeReg = Registers::ReturnReg; + } + + /* Get the object into a mutable register. */ + RegisterID objReg = frame.copyDataIntoReg(lhs); + pic.objReg = objReg; + + /* Get info about the RHS and pin it. */ + ValueRemat vr; + frame.pinEntry(rhs, vr); + pic.vr = vr; + + RegisterID shapeReg = frame.allocReg(); + pic.shapeReg = shapeReg; + + frame.unpinEntry(vr); + + /* Guard on shape. */ + masm.loadShape(objReg, shapeReg); + pic.shapeGuard = masm.label(); + DataLabel32 inlineShapeData; + Jump j = masm.branch32WithPatch(Assembler::NotEqual, shapeReg, + Imm32(int32(JSObjectMap::INVALID_SHAPE)), + inlineShapeData); + Label afterInlineShapeJump = masm.label(); + + /* Slow path. */ + { + pic.slowPathStart = stubcc.linkExit(j, Uses(2)); + + stubcc.leave(); + passICAddress(&pic); + pic.slowPathCall = OOL_STUBCALL(ic::SetProp); + CHECK_OOL_SPACE(); + } + + /* Load dslots. */ + Label dslotsLoadLabel = masm.loadPtrWithPatchToLEA(Address(objReg, offsetof(JSObject, slots)), + objReg); + + /* Store RHS into object slot. */ + Address slot(objReg, 1 << 24); + DataLabel32 inlineValueStore = masm.storeValueWithAddressOffsetPatch(vr, slot); + pic.fastPathRejoin = masm.label(); + + frame.freeReg(objReg); + frame.freeReg(shapeReg); + + /* "Pop under", taking out object (LHS) and leaving RHS. */ + frame.shimmy(1); + + /* Finish slow path. */ + { + if (pic.hasTypeCheck) + typeCheck.linkTo(stubcc.masm.label(), &stubcc.masm); + stubcc.rejoin(Changes(1)); + } + + RETURN_IF_OOM(false); + + SetPropLabels &labels = pic.setPropLabels(); + labels.setInlineShapeData(masm, pic.shapeGuard, inlineShapeData); + labels.setDslotsLoad(masm, pic.fastPathRejoin, dslotsLoadLabel, vr); + labels.setInlineValueStore(masm, pic.fastPathRejoin, inlineValueStore, vr); + labels.setInlineShapeJump(masm, pic.shapeGuard, afterInlineShapeJump); + + pics.append(pic); + return true; +} + +void +mjit::Compiler::jsop_name(JSAtom *atom) +{ + PICGenInfo pic(ic::PICInfo::NAME, JSOp(*PC), true); + + RESERVE_IC_SPACE(masm); + + pic.shapeReg = frame.allocReg(); + pic.objReg = frame.allocReg(); + pic.typeReg = Registers::ReturnReg; + pic.atom = atom; + pic.hasTypeCheck = false; + pic.fastPathStart = masm.label(); + + /* There is no inline implementation, so we always jump to the slow path or to a stub. */ + pic.shapeGuard = masm.label(); + Jump inlineJump = masm.jump(); + { + RESERVE_OOL_SPACE(stubcc.masm); + pic.slowPathStart = stubcc.linkExit(inlineJump, Uses(0)); + stubcc.leave(); + passICAddress(&pic); + pic.slowPathCall = OOL_STUBCALL(ic::Name); + CHECK_OOL_SPACE(); + } + pic.fastPathRejoin = masm.label(); + + /* Initialize op labels. */ + ScopeNameLabels &labels = pic.scopeNameLabels(); + labels.setInlineJump(masm, pic.fastPathStart, inlineJump); + + frame.pushRegs(pic.shapeReg, pic.objReg); + + stubcc.rejoin(Changes(1)); + + pics.append(pic); +} + +bool +mjit::Compiler::jsop_xname(JSAtom *atom) +{ + PICGenInfo pic(ic::PICInfo::XNAME, JSOp(*PC), true); + + FrameEntry *fe = frame.peek(-1); + if (fe->isNotType(JSVAL_TYPE_OBJECT)) { + return jsop_getprop(atom); + } + + if (!fe->isTypeKnown()) { + Jump notObject = frame.testObject(Assembler::NotEqual, fe); + stubcc.linkExit(notObject, Uses(1)); + } + + RESERVE_IC_SPACE(masm); + + pic.shapeReg = frame.allocReg(); + pic.objReg = frame.copyDataIntoReg(fe); + pic.typeReg = Registers::ReturnReg; + pic.atom = atom; + pic.hasTypeCheck = false; + pic.fastPathStart = masm.label(); + + /* There is no inline implementation, so we always jump to the slow path or to a stub. */ + pic.shapeGuard = masm.label(); + Jump inlineJump = masm.jump(); + { + RESERVE_OOL_SPACE(stubcc.masm); + pic.slowPathStart = stubcc.linkExit(inlineJump, Uses(1)); + stubcc.leave(); + passICAddress(&pic); + pic.slowPathCall = OOL_STUBCALL(ic::XName); + CHECK_OOL_SPACE(); + } + + pic.fastPathRejoin = masm.label(); + + RETURN_IF_OOM(false); + + /* Initialize op labels. */ + ScopeNameLabels &labels = pic.scopeNameLabels(); + labels.setInlineJumpOffset(masm.differenceBetween(pic.fastPathStart, inlineJump)); + + frame.pop(); + frame.pushRegs(pic.shapeReg, pic.objReg); + + stubcc.rejoin(Changes(1)); + + pics.append(pic); + return true; +} + +void +mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache) +{ + PICGenInfo pic(ic::PICInfo::BIND, JSOp(*PC), usePropCache); + + // This code does not check the frame flags to see if scopeChain has been + // set. Rather, it relies on the up-front analysis statically determining + // whether BINDNAME can be used, which reifies the scope chain at the + // prologue. + JS_ASSERT(analysis->usesScopeChain()); + + pic.shapeReg = frame.allocReg(); + pic.objReg = frame.allocReg(); + pic.typeReg = Registers::ReturnReg; + pic.atom = atom; + pic.hasTypeCheck = false; + + RESERVE_IC_SPACE(masm); + pic.fastPathStart = masm.label(); + + Address parent(pic.objReg, offsetof(JSObject, parent)); + masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg); + + pic.shapeGuard = masm.label(); + Jump inlineJump = masm.branchPtr(Assembler::NotEqual, masm.payloadOf(parent), ImmPtr(0)); + { + RESERVE_OOL_SPACE(stubcc.masm); + pic.slowPathStart = stubcc.linkExit(inlineJump, Uses(0)); + stubcc.leave(); + passICAddress(&pic); + pic.slowPathCall = OOL_STUBCALL(ic::BindName); + CHECK_OOL_SPACE(); + } + + pic.fastPathRejoin = masm.label(); + + /* Initialize op labels. */ + BindNameLabels &labels = pic.bindNameLabels(); + labels.setInlineJump(masm, pic.shapeGuard, inlineJump); + + frame.pushTypedPayload(JSVAL_TYPE_OBJECT, pic.objReg); + frame.freeReg(pic.shapeReg); + + stubcc.rejoin(Changes(1)); + + pics.append(pic); +} + +#else /* !JS_POLYIC */ + +void +mjit::Compiler::jsop_name(JSAtom *atom) +{ + prepareStubCall(Uses(0)); + INLINE_STUBCALL(stubs::Name); + frame.pushSynced(); +} + +bool +mjit::Compiler::jsop_xname(JSAtom *atom) +{ + return jsop_getprop(atom); +} + +bool +mjit::Compiler::jsop_getprop(JSAtom *atom, bool typecheck, bool usePropCache) +{ + jsop_getprop_slow(atom, usePropCache); + return true; +} + +bool +mjit::Compiler::jsop_callprop(JSAtom *atom) +{ + return jsop_callprop_slow(atom); +} + +bool +mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache) +{ + jsop_setprop_slow(atom, usePropCache); + return true; +} + +void +mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache) +{ + RegisterID reg = frame.allocReg(); + Address scopeChain(JSFrameReg, JSStackFrame::offsetOfScopeChain()); + masm.loadPtr(scopeChain, reg); + + Address address(reg, offsetof(JSObject, parent)); + + Jump j = masm.branchPtr(Assembler::NotEqual, masm.payloadOf(address), ImmPtr(0)); + + stubcc.linkExit(j, Uses(0)); + stubcc.leave(); + if (usePropCache) { + OOL_STUBCALL(stubs::BindName); + } else { + stubcc.masm.move(ImmPtr(atom), Registers::ArgReg1); + OOL_STUBCALL(stubs::BindNameNoCache); + } + + frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg); + + stubcc.rejoin(Changes(1)); +} +#endif + +void +mjit::Compiler::jsop_this() +{ + frame.pushThis(); + + /* + * In strict mode code, we don't wrap 'this'. + * In direct-call eval code, we wrapped 'this' before entering the eval. + * In global code, 'this' is always an object. + */ + if (fun && !script->strictModeCode) { + FrameEntry *thisFe = frame.peek(-1); + if (!thisFe->isTypeKnown()) { + Jump notObj = frame.testObject(Assembler::NotEqual, thisFe); + stubcc.linkExit(notObj, Uses(1)); + stubcc.leave(); + OOL_STUBCALL(stubs::This); + stubcc.rejoin(Changes(1)); + + // Now we know that |this| is an object. + frame.pop(); + frame.learnThisIsObject(); + frame.pushThis(); + } + + JS_ASSERT(thisFe->isType(JSVAL_TYPE_OBJECT)); + } +} + +void +mjit::Compiler::jsop_gnameinc(JSOp op, VoidStubAtom stub, uint32 index) +{ + JSAtom *atom = script->getAtom(index); + +#if defined JS_MONOIC + jsbytecode *next = &PC[JSOP_GNAMEINC_LENGTH]; + bool pop = (JSOp(*next) == JSOP_POP) && !analysis->jumpTarget(next); + int amt = (op == JSOP_GNAMEINC || op == JSOP_INCGNAME) ? -1 : 1; + + if (pop || (op == JSOP_INCGNAME || op == JSOP_DECGNAME)) { + /* These cases are easy, the original value is not observed. */ + + jsop_getgname(index); + // V + + frame.push(Int32Value(amt)); + // V 1 + + /* Use sub since it calls ValueToNumber instead of string concat. */ + jsop_binary(JSOP_SUB, stubs::Sub); + // N+1 + + jsop_bindgname(); + // V+1 OBJ + + frame.dup2(); + // V+1 OBJ V+1 OBJ + + frame.shift(-3); + // OBJ OBJ V+1 + + frame.shift(-1); + // OBJ V+1 + + jsop_setgname(atom, false); + // V+1 + + if (pop) + frame.pop(); + } else { + /* The pre-value is observed, making this more tricky. */ + + jsop_getgname(index); + // V + + jsop_pos(); + // N + + frame.dup(); + // N N + + frame.push(Int32Value(-amt)); + // N N 1 + + jsop_binary(JSOP_ADD, stubs::Add); + // N N+1 + + jsop_bindgname(); + // N N+1 OBJ + + frame.dup2(); + // N N+1 OBJ N+1 OBJ + + frame.shift(-3); + // N OBJ OBJ N+1 + + frame.shift(-1); + // N OBJ N+1 + + jsop_setgname(atom, false); + // N N+1 + + frame.pop(); + // N + } + + if (pop) + PC += JSOP_POP_LENGTH; +#else + prepareStubCall(Uses(0)); + masm.move(ImmPtr(atom), Registers::ArgReg1); + INLINE_STUBCALL(stub); + frame.pushSynced(); +#endif + + PC += JSOP_GNAMEINC_LENGTH; +} + +bool +mjit::Compiler::jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index) +{ + JSAtom *atom = script->getAtom(index); +#if defined JS_POLYIC + jsbytecode *next = &PC[JSOP_NAMEINC_LENGTH]; + bool pop = (JSOp(*next) == JSOP_POP) && !analysis->jumpTarget(next); + int amt = (op == JSOP_NAMEINC || op == JSOP_INCNAME) ? -1 : 1; + + if (pop || (op == JSOP_INCNAME || op == JSOP_DECNAME)) { + /* These cases are easy, the original value is not observed. */ + + jsop_name(atom); + // V + + frame.push(Int32Value(amt)); + // V 1 + + /* Use sub since it calls ValueToNumber instead of string concat. */ + jsop_binary(JSOP_SUB, stubs::Sub); + // N+1 + + jsop_bindname(atom, false); + // V+1 OBJ + + frame.dup2(); + // V+1 OBJ V+1 OBJ + + frame.shift(-3); + // OBJ OBJ V+1 + + frame.shift(-1); + // OBJ V+1 + + if (!jsop_setprop(atom, false)) + return false; + // V+1 + + if (pop) + frame.pop(); + } else { + /* The pre-value is observed, making this more tricky. */ + + jsop_name(atom); + // V + + jsop_pos(); + // N + + frame.dup(); + // N N + + frame.push(Int32Value(-amt)); + // N N 1 + + jsop_binary(JSOP_ADD, stubs::Add); + // N N+1 + + jsop_bindname(atom, false); + // N N+1 OBJ + + frame.dup2(); + // N N+1 OBJ N+1 OBJ + + frame.shift(-3); + // N OBJ OBJ N+1 + + frame.shift(-1); + // N OBJ N+1 + + if (!jsop_setprop(atom, false)) + return false; + // N N+1 + + frame.pop(); + // N + } + + if (pop) + PC += JSOP_POP_LENGTH; +#else + prepareStubCall(Uses(0)); + masm.move(ImmPtr(atom), Registers::ArgReg1); + INLINE_STUBCALL(stub); + frame.pushSynced(); +#endif + + PC += JSOP_NAMEINC_LENGTH; + return true; +} + +bool +mjit::Compiler::jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index) +{ + JSAtom *atom = script->getAtom(index); +#if defined JS_POLYIC + FrameEntry *objFe = frame.peek(-1); + if (!objFe->isTypeKnown() || objFe->getKnownType() == JSVAL_TYPE_OBJECT) { + jsbytecode *next = &PC[JSOP_PROPINC_LENGTH]; + bool pop = (JSOp(*next) == JSOP_POP) && !analysis->jumpTarget(next); + int amt = (op == JSOP_PROPINC || op == JSOP_INCPROP) ? -1 : 1; + + if (pop || (op == JSOP_INCPROP || op == JSOP_DECPROP)) { + /* These cases are easy, the original value is not observed. */ + + frame.dup(); + // OBJ OBJ + + if (!jsop_getprop(atom)) + return false; + // OBJ V + + frame.push(Int32Value(amt)); + // OBJ V 1 + + /* Use sub since it calls ValueToNumber instead of string concat. */ + jsop_binary(JSOP_SUB, stubs::Sub); + // OBJ V+1 + + if (!jsop_setprop(atom, false)) + return false; + // V+1 + + if (pop) + frame.pop(); + } else { + /* The pre-value is observed, making this more tricky. */ + + frame.dup(); + // OBJ OBJ + + if (!jsop_getprop(atom)) + return false; + // OBJ V + + jsop_pos(); + // OBJ N + + frame.dup(); + // OBJ N N + + frame.push(Int32Value(-amt)); + // OBJ N N 1 + + jsop_binary(JSOP_ADD, stubs::Add); + // OBJ N N+1 + + frame.dupAt(-3); + // OBJ N N+1 OBJ + + frame.dupAt(-2); + // OBJ N N+1 OBJ N+1 + + if (!jsop_setprop(atom, false)) + return false; + // OBJ N N+1 N+1 + + frame.popn(2); + // OBJ N + + frame.shimmy(1); + // N + } + if (pop) + PC += JSOP_POP_LENGTH; + } else +#endif + { + prepareStubCall(Uses(1)); + masm.move(ImmPtr(atom), Registers::ArgReg1); + INLINE_STUBCALL(stub); + frame.pop(); + frame.pushSynced(); + } + + PC += JSOP_PROPINC_LENGTH; + return true; +} + +bool +mjit::Compiler::iter(uintN flags) +{ + FrameEntry *fe = frame.peek(-1); + + /* + * Stub the call if this is not a simple 'for in' loop or if the iterated + * value is known to not be an object. + */ + if ((flags != JSITER_ENUMERATE) || fe->isNotType(JSVAL_TYPE_OBJECT)) { + prepareStubCall(Uses(1)); + masm.move(Imm32(flags), Registers::ArgReg1); + INLINE_STUBCALL(stubs::Iter); + frame.pop(); + frame.pushSynced(); + return true; + } + + if (!fe->isTypeKnown()) { + Jump notObject = frame.testObject(Assembler::NotEqual, fe); + stubcc.linkExit(notObject, Uses(1)); + } + + RegisterID reg = frame.tempRegForData(fe); + + frame.pinReg(reg); + RegisterID ioreg = frame.allocReg(); /* Will hold iterator JSObject */ + RegisterID nireg = frame.allocReg(); /* Will hold NativeIterator */ + RegisterID T1 = frame.allocReg(); + RegisterID T2 = frame.allocReg(); + frame.unpinReg(reg); + + /* Fetch the most recent iterator. */ + masm.loadPtr(&script->compartment->nativeIterCache.last, ioreg); + + /* Test for NULL. */ + Jump nullIterator = masm.branchTest32(Assembler::Zero, ioreg, ioreg); + stubcc.linkExit(nullIterator, Uses(1)); + + /* Get NativeIterator from iter obj. */ + masm.loadObjPrivate(ioreg, nireg); + + /* Test for active iterator. */ + Address flagsAddr(nireg, offsetof(NativeIterator, flags)); + masm.load32(flagsAddr, T1); + Jump activeIterator = masm.branchTest32(Assembler::NonZero, T1, + Imm32(JSITER_ACTIVE|JSITER_UNREUSABLE)); + stubcc.linkExit(activeIterator, Uses(1)); + + /* Compare shape of object with iterator. */ + masm.loadShape(reg, T1); + masm.loadPtr(Address(nireg, offsetof(NativeIterator, shapes_array)), T2); + masm.load32(Address(T2, 0), T2); + Jump mismatchedObject = masm.branch32(Assembler::NotEqual, T1, T2); + stubcc.linkExit(mismatchedObject, Uses(1)); + + /* Compare shape of object's prototype with iterator. */ + masm.loadPtr(Address(reg, offsetof(JSObject, proto)), T1); + masm.loadShape(T1, T1); + masm.loadPtr(Address(nireg, offsetof(NativeIterator, shapes_array)), T2); + masm.load32(Address(T2, sizeof(uint32)), T2); + Jump mismatchedProto = masm.branch32(Assembler::NotEqual, T1, T2); + stubcc.linkExit(mismatchedProto, Uses(1)); + + /* + * Compare object's prototype's prototype with NULL. The last native + * iterator will always have a prototype chain length of one + * (i.e. it must be a plain object), so we do not need to generate + * a loop here. + */ + masm.loadPtr(Address(reg, offsetof(JSObject, proto)), T1); + masm.loadPtr(Address(T1, offsetof(JSObject, proto)), T1); + Jump overlongChain = masm.branchPtr(Assembler::NonZero, T1, T1); + stubcc.linkExit(overlongChain, Uses(1)); + + /* Found a match with the most recent iterator. Hooray! */ + + /* Mark iterator as active. */ + masm.storePtr(reg, Address(nireg, offsetof(NativeIterator, obj))); + masm.load32(flagsAddr, T1); + masm.or32(Imm32(JSITER_ACTIVE), T1); + masm.store32(T1, flagsAddr); + + /* Chain onto the active iterator stack. */ + masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), T1); + masm.loadPtr(Address(T1, offsetof(JSContext, enumerators)), T2); + masm.storePtr(T2, Address(nireg, offsetof(NativeIterator, next))); + masm.storePtr(ioreg, Address(T1, offsetof(JSContext, enumerators))); + + frame.freeReg(nireg); + frame.freeReg(T1); + frame.freeReg(T2); + + stubcc.leave(); + stubcc.masm.move(Imm32(flags), Registers::ArgReg1); + OOL_STUBCALL(stubs::Iter); + + /* Push the iterator object. */ + frame.pop(); + frame.pushTypedPayload(JSVAL_TYPE_OBJECT, ioreg); + + stubcc.rejoin(Changes(1)); + + return true; +} + +/* + * This big nasty function emits a fast-path for native iterators, producing + * a temporary value on the stack for FORLOCAL,ARG,GLOBAL,etc ops to use. + */ +void +mjit::Compiler::iterNext() +{ + FrameEntry *fe = frame.peek(-1); + RegisterID reg = frame.tempRegForData(fe); + + /* Is it worth trying to pin this longer? Prolly not. */ + frame.pinReg(reg); + RegisterID T1 = frame.allocReg(); + frame.unpinReg(reg); + + /* Test clasp */ + Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &js_IteratorClass); + stubcc.linkExit(notFast, Uses(1)); + + /* Get private from iter obj. */ + masm.loadObjPrivate(reg, T1); + + RegisterID T3 = frame.allocReg(); + RegisterID T4 = frame.allocReg(); + + /* Test for a value iterator, which could come through an Iterator object. */ + masm.load32(Address(T1, offsetof(NativeIterator, flags)), T3); + notFast = masm.branchTest32(Assembler::NonZero, T3, Imm32(JSITER_FOREACH)); + stubcc.linkExit(notFast, Uses(1)); + + RegisterID T2 = frame.allocReg(); + + /* Get cursor. */ + masm.loadPtr(Address(T1, offsetof(NativeIterator, props_cursor)), T2); + + /* Test if the jsid is a string. */ + masm.loadPtr(T2, T3); + masm.move(T3, T4); + masm.andPtr(Imm32(JSID_TYPE_MASK), T4); + notFast = masm.branchTestPtr(Assembler::NonZero, T4, T4); + stubcc.linkExit(notFast, Uses(1)); + + /* It's safe to increase the cursor now. */ + masm.addPtr(Imm32(sizeof(jsid)), T2, T4); + masm.storePtr(T4, Address(T1, offsetof(NativeIterator, props_cursor))); + + frame.freeReg(T4); + frame.freeReg(T1); + frame.freeReg(T2); + + stubcc.leave(); + OOL_STUBCALL(stubs::IterNext); + + frame.pushUntypedPayload(JSVAL_TYPE_STRING, T3); + + /* Join with the stub call. */ + stubcc.rejoin(Changes(1)); +} + +bool +mjit::Compiler::iterMore() +{ + FrameEntry *fe = frame.peek(-1); + RegisterID reg = frame.tempRegForData(fe); + + frame.pinReg(reg); + RegisterID T1 = frame.allocReg(); + frame.unpinReg(reg); + + /* Test clasp */ + Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &js_IteratorClass); + stubcc.linkExitForBranch(notFast); + + /* Get private from iter obj. */ + masm.loadObjPrivate(reg, T1); + + /* Test that the iterator supports fast iteration. */ + notFast = masm.branchTest32(Assembler::NonZero, Address(T1, offsetof(NativeIterator, flags)), + Imm32(JSITER_FOREACH)); + stubcc.linkExitForBranch(notFast); + + /* Get props_cursor, test */ + RegisterID T2 = frame.allocReg(); + frame.syncAndForgetEverything(); + masm.loadPtr(Address(T1, offsetof(NativeIterator, props_cursor)), T2); + masm.loadPtr(Address(T1, offsetof(NativeIterator, props_end)), T1); + Jump jFast = masm.branchPtr(Assembler::LessThan, T2, T1); + + jsbytecode *target = &PC[JSOP_MOREITER_LENGTH]; + JSOp next = JSOp(*target); + JS_ASSERT(next == JSOP_IFNE || next == JSOP_IFNEX); + + target += (next == JSOP_IFNE) + ? GET_JUMP_OFFSET(target) + : GET_JUMPX_OFFSET(target); + + stubcc.leave(); + OOL_STUBCALL(stubs::IterMore); + Jump j = stubcc.masm.branchTest32(Assembler::NonZero, Registers::ReturnReg, + Registers::ReturnReg); + + PC += JSOP_MOREITER_LENGTH; + PC += js_CodeSpec[next].length; + + stubcc.rejoin(Changes(1)); + + return jumpAndTrace(jFast, target, &j); +} + +void +mjit::Compiler::iterEnd() +{ + FrameEntry *fe= frame.peek(-1); + RegisterID reg = frame.tempRegForData(fe); + + frame.pinReg(reg); + RegisterID T1 = frame.allocReg(); + frame.unpinReg(reg); + + /* Test clasp */ + Jump notIterator = masm.testObjClass(Assembler::NotEqual, reg, &js_IteratorClass); + stubcc.linkExit(notIterator, Uses(1)); + + /* Get private from iter obj. */ + masm.loadObjPrivate(reg, T1); + + RegisterID T2 = frame.allocReg(); + + /* Load flags. */ + Address flagAddr(T1, offsetof(NativeIterator, flags)); + masm.loadPtr(flagAddr, T2); + + /* Test for a normal enumerate iterator. */ + Jump notEnumerate = masm.branchTest32(Assembler::Zero, T2, Imm32(JSITER_ENUMERATE)); + stubcc.linkExit(notEnumerate, Uses(1)); + + /* Clear active bit. */ + masm.and32(Imm32(~JSITER_ACTIVE), T2); + masm.storePtr(T2, flagAddr); + + /* Reset property cursor. */ + masm.loadPtr(Address(T1, offsetof(NativeIterator, props_array)), T2); + masm.storePtr(T2, Address(T1, offsetof(NativeIterator, props_cursor))); + + /* Advance enumerators list. */ + masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), T2); + masm.loadPtr(Address(T1, offsetof(NativeIterator, next)), T1); + masm.storePtr(T1, Address(T2, offsetof(JSContext, enumerators))); + + frame.freeReg(T1); + frame.freeReg(T2); + + stubcc.leave(); + OOL_STUBCALL(stubs::EndIter); + + frame.pop(); + + stubcc.rejoin(Changes(1)); +} + +void +mjit::Compiler::jsop_eleminc(JSOp op, VoidStub stub) +{ + prepareStubCall(Uses(2)); + INLINE_STUBCALL(stub); + frame.popn(2); + frame.pushSynced(); +} + +void +mjit::Compiler::jsop_getgname_slow(uint32 index) +{ + prepareStubCall(Uses(0)); + INLINE_STUBCALL(stubs::GetGlobalName); + frame.pushSynced(); +} + +void +mjit::Compiler::jsop_bindgname() +{ + if (script->compileAndGo && globalObj) { + frame.push(ObjectValue(*globalObj)); + return; + } + + /* :TODO: this is slower than it needs to be. */ + prepareStubCall(Uses(0)); + INLINE_STUBCALL(stubs::BindGlobalName); + frame.takeReg(Registers::ReturnReg); + frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg); +} + +void +mjit::Compiler::jsop_getgname(uint32 index) +{ + /* Optimize undefined, NaN and Infinity. */ + JSAtom *atom = script->getAtom(index); + if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID]) { + frame.push(UndefinedValue()); + return; + } + if (atom == cx->runtime->atomState.NaNAtom) { + frame.push(cx->runtime->NaNValue); + return; + } + if (atom == cx->runtime->atomState.InfinityAtom) { + frame.push(cx->runtime->positiveInfinityValue); + return; + } +#if defined JS_MONOIC + jsop_bindgname(); + + FrameEntry *fe = frame.peek(-1); + JS_ASSERT(fe->isTypeKnown() && fe->getKnownType() == JSVAL_TYPE_OBJECT); + + GetGlobalNameICInfo ic; + RESERVE_IC_SPACE(masm); + RegisterID objReg; + Jump shapeGuard; + + ic.usePropertyCache = true; + + ic.fastPathStart = masm.label(); + if (fe->isConstant()) { + JSObject *obj = &fe->getValue().toObject(); + frame.pop(); + JS_ASSERT(obj->isNative()); + + objReg = frame.allocReg(); + + masm.load32FromImm(&obj->objShape, objReg); + shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, objReg, + Imm32(int32(JSObjectMap::INVALID_SHAPE)), ic.shape); + masm.move(ImmPtr(obj), objReg); + } else { + objReg = frame.ownRegForData(fe); + frame.pop(); + RegisterID reg = frame.allocReg(); + + masm.loadShape(objReg, reg); + shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, reg, + Imm32(int32(JSObjectMap::INVALID_SHAPE)), ic.shape); + frame.freeReg(reg); + } + stubcc.linkExit(shapeGuard, Uses(0)); + + stubcc.leave(); + passMICAddress(ic); + ic.slowPathCall = OOL_STUBCALL(ic::GetGlobalName); + + /* Garbage value. */ + uint32 slot = 1 << 24; + + masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg); + Address address(objReg, slot); + + /* Allocate any register other than objReg. */ + RegisterID treg = frame.allocReg(); + /* After dreg is loaded, it's safe to clobber objReg. */ + RegisterID dreg = objReg; + + ic.load = masm.loadValueWithAddressOffsetPatch(address, treg, dreg); + + frame.pushRegs(treg, dreg); + + stubcc.rejoin(Changes(1)); + + getGlobalNames.append(ic); + +#else + jsop_getgname_slow(index); +#endif +} + +/* + * Generate just the epilogue code that is specific to callgname. The rest + * is shared with getgname. + */ +void +mjit::Compiler::jsop_callgname_epilogue() +{ + /* + * This slow path does the same thing as the interpreter. + */ + if (!script->compileAndGo) { + prepareStubCall(Uses(1)); + INLINE_STUBCALL(stubs::PushImplicitThisForGlobal); + frame.pushSynced(); + return; + } + + /* Fast path for known-not-an-object callee. */ + FrameEntry *fval = frame.peek(-1); + if (fval->isNotType(JSVAL_TYPE_OBJECT)) { + frame.push(UndefinedValue()); + return; + } + + /* + * Optimized version. This inlines the common case, calling a + * (non-proxied) function that has the same global as the current + * script. To make the code simpler, we: + * 1. test the stronger property that the callee's parent is + * equal to the global of the current script, and + * 2. bake in the global of the current script, which is why + * this optimized path requires compile-and-go. + */ + + /* If the callee is not an object, jump to the inline fast path. */ + MaybeRegisterID typeReg = frame.maybePinType(fval); + RegisterID objReg = frame.copyDataIntoReg(fval); + + MaybeJump isNotObj; + if (!fval->isType(JSVAL_TYPE_OBJECT)) { + isNotObj = frame.testObject(Assembler::NotEqual, fval); + frame.maybeUnpinReg(typeReg); + } + + /* + * If the callee is not a function, jump to OOL slow path. + */ + Jump notFunction = masm.testFunction(Assembler::NotEqual, objReg); + stubcc.linkExit(notFunction, Uses(1)); + + /* + * If the callee's parent is not equal to the global, jump to + * OOL slow path. + */ + masm.loadPtr(Address(objReg, offsetof(JSObject, parent)), objReg); + Jump globalMismatch = masm.branchPtr(Assembler::NotEqual, objReg, ImmPtr(globalObj)); + stubcc.linkExit(globalMismatch, Uses(1)); + frame.freeReg(objReg); + + /* OOL stub call path. */ + stubcc.leave(); + OOL_STUBCALL(stubs::PushImplicitThisForGlobal); + + /* Fast path. */ + if (isNotObj.isSet()) + isNotObj.getJump().linkTo(masm.label(), &masm); + frame.pushUntypedValue(UndefinedValue()); + + stubcc.rejoin(Changes(1)); +} + +void +mjit::Compiler::jsop_setgname_slow(JSAtom *atom, bool usePropertyCache) +{ + prepareStubCall(Uses(2)); + masm.move(ImmPtr(atom), Registers::ArgReg1); + if (usePropertyCache) + INLINE_STUBCALL(STRICT_VARIANT(stubs::SetGlobalName)); + else + INLINE_STUBCALL(STRICT_VARIANT(stubs::SetGlobalNameNoCache)); + frame.popn(2); + frame.pushSynced(); +} + +void +mjit::Compiler::jsop_setgname(JSAtom *atom, bool usePropertyCache) +{ +#if defined JS_MONOIC + FrameEntry *objFe = frame.peek(-2); + FrameEntry *fe = frame.peek(-1); + JS_ASSERT_IF(objFe->isTypeKnown(), objFe->getKnownType() == JSVAL_TYPE_OBJECT); + + SetGlobalNameICInfo ic; + + frame.pinEntry(fe, ic.vr); + Jump shapeGuard; + + RESERVE_IC_SPACE(masm); + ic.fastPathStart = masm.label(); + if (objFe->isConstant()) { + JSObject *obj = &objFe->getValue().toObject(); + JS_ASSERT(obj->isNative()); + + ic.objReg = frame.allocReg(); + ic.shapeReg = ic.objReg; + ic.objConst = true; + + masm.load32FromImm(&obj->objShape, ic.shapeReg); + shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, ic.shapeReg, + Imm32(int32(JSObjectMap::INVALID_SHAPE)), + ic.shape); + masm.move(ImmPtr(obj), ic.objReg); + } else { + ic.objReg = frame.copyDataIntoReg(objFe); + ic.shapeReg = frame.allocReg(); + ic.objConst = false; + + masm.loadShape(ic.objReg, ic.shapeReg); + shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, ic.shapeReg, + Imm32(int32(JSObjectMap::INVALID_SHAPE)), + ic.shape); + frame.freeReg(ic.shapeReg); + } + ic.shapeGuardJump = shapeGuard; + ic.slowPathStart = stubcc.linkExit(shapeGuard, Uses(2)); + + stubcc.leave(); + passMICAddress(ic); + ic.slowPathCall = OOL_STUBCALL(ic::SetGlobalName); + + /* Garbage value. */ + uint32 slot = 1 << 24; + + ic.usePropertyCache = usePropertyCache; + + masm.loadPtr(Address(ic.objReg, offsetof(JSObject, slots)), ic.objReg); + Address address(ic.objReg, slot); + + if (ic.vr.isConstant()) { + ic.store = masm.storeValueWithAddressOffsetPatch(ic.vr.value(), address); + } else if (ic.vr.isTypeKnown()) { + ic.store = masm.storeValueWithAddressOffsetPatch(ImmType(ic.vr.knownType()), + ic.vr.dataReg(), address); + } else { + ic.store = masm.storeValueWithAddressOffsetPatch(ic.vr.typeReg(), ic.vr.dataReg(), address); + } + + frame.freeReg(ic.objReg); + frame.unpinEntry(ic.vr); + frame.shimmy(1); + + stubcc.rejoin(Changes(1)); + + ic.fastPathRejoin = masm.label(); + setGlobalNames.append(ic); +#else + jsop_setgname_slow(atom, usePropertyCache); +#endif +} + +void +mjit::Compiler::jsop_setelem_slow() +{ + prepareStubCall(Uses(3)); + INLINE_STUBCALL(STRICT_VARIANT(stubs::SetElem)); + frame.popn(3); + frame.pushSynced(); +} + +void +mjit::Compiler::jsop_getelem_slow() +{ + prepareStubCall(Uses(2)); + INLINE_STUBCALL(stubs::GetElem); + frame.popn(2); + frame.pushSynced(); +} + +void +mjit::Compiler::jsop_unbrand() +{ + prepareStubCall(Uses(1)); + INLINE_STUBCALL(stubs::Unbrand); +} + +bool +mjit::Compiler::jsop_instanceof() +{ + FrameEntry *lhs = frame.peek(-2); + FrameEntry *rhs = frame.peek(-1); + + // The fast path applies only when both operands are objects. + if (rhs->isNotType(JSVAL_TYPE_OBJECT) || lhs->isNotType(JSVAL_TYPE_OBJECT)) { + prepareStubCall(Uses(2)); + INLINE_STUBCALL(stubs::InstanceOf); + frame.popn(2); + frame.takeReg(Registers::ReturnReg); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, Registers::ReturnReg); + return true; + } + + MaybeJump firstSlow; + if (!rhs->isTypeKnown()) { + Jump j = frame.testObject(Assembler::NotEqual, rhs); + stubcc.linkExit(j, Uses(2)); + RegisterID reg = frame.tempRegForData(rhs); + j = masm.testFunction(Assembler::NotEqual, reg); + stubcc.linkExit(j, Uses(2)); + } + + /* Test for bound functions. */ + RegisterID obj = frame.tempRegForData(rhs); + Jump isBound = masm.branchTest32(Assembler::NonZero, Address(obj, offsetof(JSObject, flags)), + Imm32(JSObject::BOUND_FUNCTION)); + { + stubcc.linkExit(isBound, Uses(2)); + stubcc.leave(); + OOL_STUBCALL(stubs::InstanceOf); + firstSlow = stubcc.masm.jump(); + } + + + /* This is sadly necessary because the error case needs the object. */ + frame.dup(); + + if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom, false)) + return false; + + /* Primitive prototypes are invalid. */ + rhs = frame.peek(-1); + Jump j = frame.testPrimitive(Assembler::Equal, rhs); + stubcc.linkExit(j, Uses(3)); + + /* Allocate registers up front, because of branchiness. */ + obj = frame.copyDataIntoReg(lhs); + RegisterID proto = frame.copyDataIntoReg(rhs); + RegisterID temp = frame.allocReg(); + + MaybeJump isFalse; + if (!lhs->isTypeKnown()) + isFalse = frame.testPrimitive(Assembler::Equal, lhs); + + Address protoAddr(obj, offsetof(JSObject, proto)); + Label loop = masm.label(); + + /* Walk prototype chain, break out on NULL or hit. */ + masm.loadPayload(protoAddr, obj); + Jump isFalse2 = masm.branchTestPtr(Assembler::Zero, obj, obj); + Jump isTrue = masm.branchPtr(Assembler::NotEqual, obj, proto); + isTrue.linkTo(loop, &masm); + masm.move(Imm32(1), temp); + isTrue = masm.jump(); + + if (isFalse.isSet()) + isFalse.getJump().linkTo(masm.label(), &masm); + isFalse2.linkTo(masm.label(), &masm); + masm.move(Imm32(0), temp); + isTrue.linkTo(masm.label(), &masm); + + frame.freeReg(proto); + frame.freeReg(obj); + + stubcc.leave(); + OOL_STUBCALL(stubs::FastInstanceOf); + + frame.popn(3); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, temp); + + if (firstSlow.isSet()) + firstSlow.getJump().linkTo(stubcc.masm.label(), &stubcc.masm); + stubcc.rejoin(Changes(1)); + return true; +} + +void +mjit::Compiler::emitEval(uint32 argc) +{ + /* Check for interrupts on function call */ + interruptCheckHelper(); + + frame.syncAndKill(Registers(Registers::AvailRegs), Uses(argc + 2)); + prepareStubCall(Uses(argc + 2)); + masm.move(Imm32(argc), Registers::ArgReg1); + INLINE_STUBCALL(stubs::Eval); + frame.popn(argc + 2); + frame.pushSynced(); +} + +void +mjit::Compiler::jsop_arguments() +{ + prepareStubCall(Uses(0)); + INLINE_STUBCALL(stubs::Arguments); +} + +void +mjit::Compiler::jsop_newinit() +{ + bool isArray; + unsigned count = 0; + JSObject *baseobj = NULL; + switch (*PC) { + case JSOP_NEWINIT: + isArray = (PC[1] == JSProto_Array); + break; + case JSOP_NEWARRAY: + isArray = true; + count = GET_UINT24(PC); + break; + case JSOP_NEWOBJECT: + isArray = false; + baseobj = script->getObject(fullAtomIndex(PC)); + break; + default: + JS_NOT_REACHED("Bad op"); + return; + } + + prepareStubCall(Uses(0)); + if (isArray) { + masm.move(Imm32(count), Registers::ArgReg1); + INLINE_STUBCALL(stubs::NewInitArray); + } else { + masm.move(ImmPtr(baseobj), Registers::ArgReg1); + INLINE_STUBCALL(stubs::NewInitObject); + } + frame.takeReg(Registers::ReturnReg); + frame.pushInitializerObject(Registers::ReturnReg, *PC == JSOP_NEWARRAY, baseobj); +} + +/* + * Note: This function emits tracer hooks into the OOL path. This means if + * it is used in the middle of an in-progress slow path, the stream will be + * hopelessly corrupted. Take care to only call this before linkExits() and + * after rejoin()s. + */ +bool +mjit::Compiler::jumpAndTrace(Jump j, jsbytecode *target, Jump *slow) +{ + // XXX refactor this little bit +#ifndef JS_TRACER + if (!jumpInScript(j, target)) + return false; + + if (slow) { + if (!stubcc.jumpInScript(*slow, target)) + return false; + } +#else + if (!addTraceHints || target >= PC || + (JSOp(*target) != JSOP_TRACE && JSOp(*target) != JSOP_NOTRACE) +#ifdef JS_MONOIC + || GET_UINT16(target) == BAD_TRACEIC_INDEX +#endif + ) + { + if (!jumpInScript(j, target)) + return false; + if (slow && !stubcc.jumpInScript(*slow, target)) + return false; + return true; + } + +# if JS_MONOIC + TraceGenInfo ic; + + ic.initialized = true; + ic.stubEntry = stubcc.masm.label(); + ic.jumpTarget = target; + ic.traceHint = j; + if (slow) + ic.slowTraceHint = *slow; + + uint16 index = GET_UINT16(target); + if (traceICs.length() <= index) + if (!traceICs.resize(index+1)) + return false; +# endif + + Label traceStart = stubcc.masm.label(); + + /* + * We make a trace IC even if the trace is currently disabled, in case it is + * enabled later, but set up the jumps so that InvokeTracer is initially skipped. + */ + if (JSOp(*target) == JSOP_TRACE) { + stubcc.linkExitDirect(j, traceStart); + if (slow) + slow->linkTo(traceStart, &stubcc.masm); + } else { + if (!jumpInScript(j, target)) + return false; + if (slow && !stubcc.jumpInScript(*slow, target)) + return false; + } + +# if JS_MONOIC + ic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1); + traceICs[index] = ic; + + Jump nonzero = stubcc.masm.branchSub32(Assembler::NonZero, Imm32(1), + Address(Registers::ArgReg1, + offsetof(TraceICInfo, loopCounter))); + stubcc.jumpInScript(nonzero, target); +# endif + + /* Save and restore compiler-tracked PC, so cx->regs is right in InvokeTracer. */ + { + jsbytecode* pc = PC; + PC = target; + + OOL_STUBCALL(stubs::InvokeTracer); + + PC = pc; + } + + Jump no = stubcc.masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg, + Registers::ReturnReg); + if (!stubcc.jumpInScript(no, target)) + return false; + restoreFrameRegs(stubcc.masm); + stubcc.masm.jump(Registers::ReturnReg); +#endif + return true; +} + +void +mjit::Compiler::enterBlock(JSObject *obj) +{ + // If this is an exception entry point, then jsl_InternalThrow has set + // VMFrame::fp to the correct fp for the entry point. We need to copy + // that value here to FpReg so that FpReg also has the correct sp. + // Otherwise, we would simply be using a stale FpReg value. + // Additionally, we check the interrupt flag to allow interrupting + // deeply nested exception handling. + if (analysis->getCode(PC).exceptionEntry) { + restoreFrameRegs(masm); + interruptCheckHelper(); + } + + uint32 oldFrameDepth = frame.localSlots(); + + /* For now, don't bother doing anything for this opcode. */ + frame.syncAndForgetEverything(); + masm.move(ImmPtr(obj), Registers::ArgReg1); + uint32 n = js_GetEnterBlockStackDefs(cx, script, PC); + INLINE_STUBCALL(stubs::EnterBlock); + frame.enterBlock(n); + + uintN base = JSSLOT_FREE(&js_BlockClass); + uintN count = OBJ_BLOCK_COUNT(cx, obj); + uintN limit = base + count; + for (uintN slot = base, i = 0; slot < limit; slot++, i++) { + const Value &v = obj->getSlotRef(slot); + if (v.isBoolean() && v.toBoolean()) + frame.setClosedVar(oldFrameDepth + i); + } +} + +void +mjit::Compiler::leaveBlock() +{ + /* + * Note: After bug 535912, we can pass the block obj directly, inline + * PutBlockObject, and do away with the muckiness in PutBlockObject. + */ + uint32 n = js_GetVariableStackUses(JSOP_LEAVEBLOCK, PC); + JSObject *obj = script->getObject(fullAtomIndex(PC + UINT16_LEN)); + prepareStubCall(Uses(n)); + masm.move(ImmPtr(obj), Registers::ArgReg1); + INLINE_STUBCALL(stubs::LeaveBlock); + frame.leaveBlock(n); +} + +// Creates the new object expected for constructors, and places it in |thisv|. +// It is broken down into the following operations: +// CALLEE +// GETPROP "prototype" +// IFPRIMTOP: +// NULL +// call js_CreateThisFromFunctionWithProto(...) +// +bool +mjit::Compiler::constructThis() +{ + JS_ASSERT(isConstructing); + + // Load the callee. + frame.pushCallee(); + + // Get callee.prototype. + if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom, false, false)) + return false; + + // Reach into the proto Value and grab a register for its data. + FrameEntry *protoFe = frame.peek(-1); + RegisterID protoReg = frame.ownRegForData(protoFe); + + // Now, get the type. If it's not an object, set protoReg to NULL. + Jump isNotObject = frame.testObject(Assembler::NotEqual, protoFe); + stubcc.linkExitDirect(isNotObject, stubcc.masm.label()); + stubcc.masm.move(ImmPtr(NULL), protoReg); + stubcc.crossJump(stubcc.masm.jump(), masm.label()); + + // Done with the protoFe. + frame.pop(); + + prepareStubCall(Uses(0)); + if (protoReg != Registers::ArgReg1) + masm.move(protoReg, Registers::ArgReg1); + INLINE_STUBCALL(stubs::CreateThis); + frame.freeReg(protoReg); + return true; +} + +bool +mjit::Compiler::jsop_tableswitch(jsbytecode *pc) +{ +#if defined JS_CPU_ARM + JS_NOT_REACHED("Implement jump(BaseIndex) for ARM"); + return true; +#else + jsbytecode *originalPC = pc; + + uint32 defaultTarget = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + + jsint low = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + jsint high = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + int numJumps = high + 1 - low; + JS_ASSERT(numJumps >= 0); + + /* + * If there are no cases, this is a no-op. The default case immediately + * follows in the bytecode and is always taken. + */ + if (numJumps == 0) { + frame.pop(); + return true; + } + + FrameEntry *fe = frame.peek(-1); + if (fe->isNotType(JSVAL_TYPE_INT32) || numJumps > 256) { + frame.syncAndForgetEverything(); + masm.move(ImmPtr(originalPC), Registers::ArgReg1); + + /* prepareStubCall() is not needed due to forgetEverything() */ + INLINE_STUBCALL(stubs::TableSwitch); + frame.pop(); + masm.jump(Registers::ReturnReg); + return true; + } + + RegisterID dataReg; + if (fe->isConstant()) { + JS_ASSERT(fe->isType(JSVAL_TYPE_INT32)); + dataReg = frame.allocReg(); + masm.move(Imm32(fe->getValue().toInt32()), dataReg); + } else { + dataReg = frame.copyDataIntoReg(fe); + } + + RegisterID reg = frame.allocReg(); + frame.syncAndForgetEverything(); + + MaybeJump notInt; + if (!fe->isType(JSVAL_TYPE_INT32)) + notInt = masm.testInt32(Assembler::NotEqual, frame.addressOf(fe)); + + JumpTable jt; + jt.offsetIndex = jumpTableOffsets.length(); + jt.label = masm.moveWithPatch(ImmPtr(NULL), reg); + jumpTables.append(jt); + + for (int i = 0; i < numJumps; i++) { + uint32 target = GET_JUMP_OFFSET(pc); + if (!target) + target = defaultTarget; + uint32 offset = (originalPC + target) - script->code; + jumpTableOffsets.append(offset); + pc += JUMP_OFFSET_LEN; + } + if (low != 0) + masm.sub32(Imm32(low), dataReg); + Jump defaultCase = masm.branch32(Assembler::AboveOrEqual, dataReg, Imm32(numJumps)); + BaseIndex jumpTarget(reg, dataReg, Assembler::ScalePtr); + masm.jump(jumpTarget); + + if (notInt.isSet()) { + stubcc.linkExitDirect(notInt.get(), stubcc.masm.label()); + stubcc.leave(); + stubcc.masm.move(ImmPtr(originalPC), Registers::ArgReg1); + OOL_STUBCALL(stubs::TableSwitch); + stubcc.masm.jump(Registers::ReturnReg); + } + frame.pop(); + return jumpAndTrace(defaultCase, originalPC + defaultTarget); +#endif +} + +void +mjit::Compiler::jsop_callelem_slow() +{ + prepareStubCall(Uses(2)); + INLINE_STUBCALL(stubs::CallElem); + frame.popn(2); + frame.pushSynced(); + frame.pushSynced(); +} + +void +mjit::Compiler::jsop_forprop(JSAtom *atom) +{ + // Before: ITER OBJ + // After: ITER OBJ ITER + frame.dupAt(-2); + + // Before: ITER OBJ ITER + // After: ITER OBJ ITER VALUE + iterNext(); + + // Before: ITER OBJ ITER VALUE + // After: ITER OBJ VALUE + frame.shimmy(1); + + // Before: ITER OBJ VALUE + // After: ITER VALUE + jsop_setprop(atom, false); + + // Before: ITER VALUE + // After: ITER + frame.pop(); +} + +void +mjit::Compiler::jsop_forname(JSAtom *atom) +{ + // Before: ITER + // After: ITER SCOPEOBJ + jsop_bindname(atom, false); + jsop_forprop(atom); +} + +void +mjit::Compiler::jsop_forgname(JSAtom *atom) +{ + // Before: ITER + // After: ITER GLOBAL + jsop_bindgname(); + + // Before: ITER GLOBAL + // After: ITER GLOBAL ITER + frame.dupAt(-2); + + // Before: ITER GLOBAL ITER + // After: ITER GLOBAL ITER VALUE + iterNext(); + + // Before: ITER GLOBAL ITER VALUE + // After: ITER GLOBAL VALUE + frame.shimmy(1); + + // Before: ITER GLOBAL VALUE + // After: ITER VALUE + jsop_setgname(atom, false); + + // Before: ITER VALUE + // After: ITER + frame.pop(); +} + diff --git a/js/src/methodjit/Compiler.h b/js/src/methodjit/Compiler.h new file mode 100644 index 0000000..95d8074 --- /dev/null +++ b/js/src/methodjit/Compiler.h @@ -0,0 +1,567 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#if !defined jsjaeger_compiler_h__ && defined JS_METHODJIT +#define jsjaeger_compiler_h__ + +#include "jsanalyze.h" +#include "jscntxt.h" +#include "jstl.h" +#include "MethodJIT.h" +#include "CodeGenIncludes.h" +#include "BaseCompiler.h" +#include "StubCompiler.h" +#include "MonoIC.h" +#include "PolyIC.h" + +namespace js { +namespace mjit { + +class Compiler : public BaseCompiler +{ + friend class StubCompiler; + + struct BranchPatch { + BranchPatch(const Jump &j, jsbytecode *pc) + : jump(j), pc(pc) + { } + + Jump jump; + jsbytecode *pc; + }; + +#if defined JS_MONOIC + struct GlobalNameICInfo { + Label fastPathStart; + Call slowPathCall; + DataLabel32 shape; + DataLabelPtr addrLabel; + bool usePropertyCache; + + void copyTo(ic::GlobalNameIC &to, JSC::LinkBuffer &full, JSC::LinkBuffer &stub) { + to.fastPathStart = full.locationOf(fastPathStart); + + int offset = full.locationOf(shape) - to.fastPathStart; + to.shapeOffset = offset; + JS_ASSERT(to.shapeOffset == offset); + + to.slowPathCall = stub.locationOf(slowPathCall); + to.usePropertyCache = usePropertyCache; + } + }; + + struct GetGlobalNameICInfo : public GlobalNameICInfo { + Label load; + }; + + struct SetGlobalNameICInfo : public GlobalNameICInfo { + Label slowPathStart; + Label fastPathRejoin; + DataLabel32 store; + Jump shapeGuardJump; + ValueRemat vr; + RegisterID objReg; + RegisterID shapeReg; + bool objConst; + }; + + struct EqualityGenInfo { + DataLabelPtr addrLabel; + Label stubEntry; + Call stubCall; + BoolStub stub; + MaybeJump jumpToStub; + Label fallThrough; + jsbytecode *jumpTarget; + ValueRemat lvr, rvr; + Assembler::Condition cond; + JSC::MacroAssembler::RegisterID tempReg; + }; + + struct TraceGenInfo { + bool initialized; + Label stubEntry; + DataLabelPtr addrLabel; + jsbytecode *jumpTarget; + Jump traceHint; + MaybeJump slowTraceHint; + + TraceGenInfo() : initialized(false) {} + }; + + /* InlineFrameAssembler wants to see this. */ + public: + struct CallGenInfo { + CallGenInfo(jsbytecode *pc) : pc(pc) {} + + /* + * These members map to members in CallICInfo. See that structure for + * more comments. + */ + jsbytecode *pc; + DataLabelPtr funGuard; + Jump funJump; + Jump hotJump; + Call oolCall; + Label joinPoint; + Label slowJoinPoint; + Label slowPathStart; + Label hotPathLabel; + DataLabelPtr addrLabel1; + DataLabelPtr addrLabel2; + Jump oolJump; + Label icCall; + RegisterID funObjReg; + RegisterID funPtrReg; + FrameSize frameSize; + }; + + private: +#endif + + /* + * Writes of call return addresses which needs to be delayed until the final + * absolute address of the join point is known. + */ + struct CallPatchInfo { + CallPatchInfo() : hasFastNcode(false), hasSlowNcode(false) {} + Label joinPoint; + DataLabelPtr fastNcodePatch; + DataLabelPtr slowNcodePatch; + bool hasFastNcode; + bool hasSlowNcode; + }; + + struct BaseICInfo { + BaseICInfo(JSOp op) : op(op) + { } + Label fastPathStart; + Label fastPathRejoin; + Label slowPathStart; + Call slowPathCall; + DataLabelPtr paramAddr; + JSOp op; + + void copyTo(ic::BaseIC &to, JSC::LinkBuffer &full, JSC::LinkBuffer &stub) { + to.fastPathStart = full.locationOf(fastPathStart); + to.fastPathRejoin = full.locationOf(fastPathRejoin); + to.slowPathStart = stub.locationOf(slowPathStart); + to.slowPathCall = stub.locationOf(slowPathCall); + to.op = op; + JS_ASSERT(to.op == op); + } + }; + + struct GetElementICInfo : public BaseICInfo { + GetElementICInfo(JSOp op) : BaseICInfo(op) + { } + RegisterID typeReg; + RegisterID objReg; + ValueRemat id; + MaybeJump typeGuard; + Jump claspGuard; + }; + + struct SetElementICInfo : public BaseICInfo { + SetElementICInfo(JSOp op) : BaseICInfo(op) + { } + RegisterID objReg; + StateRemat objRemat; + ValueRemat vr; + Jump capacityGuard; + Jump claspGuard; + Jump holeGuard; + Int32Key key; + uint32 volatileMask; + }; + + struct PICGenInfo : public BaseICInfo { + PICGenInfo(ic::PICInfo::Kind kind, JSOp op, bool usePropCache) + : BaseICInfo(op), kind(kind), usePropCache(usePropCache) + { } + ic::PICInfo::Kind kind; + Label typeCheck; + RegisterID shapeReg; + RegisterID objReg; + RegisterID typeReg; + bool usePropCache; + Label shapeGuard; + jsbytecode *pc; + JSAtom *atom; + bool hasTypeCheck; + ValueRemat vr; +#ifdef JS_HAS_IC_LABELS + union { + ic::GetPropLabels getPropLabels_; + ic::SetPropLabels setPropLabels_; + ic::BindNameLabels bindNameLabels_; + ic::ScopeNameLabels scopeNameLabels_; + }; + + ic::GetPropLabels &getPropLabels() { + JS_ASSERT(kind == ic::PICInfo::GET || kind == ic::PICInfo::CALL); + return getPropLabels_; + } + ic::SetPropLabels &setPropLabels() { + JS_ASSERT(kind == ic::PICInfo::SET || kind == ic::PICInfo::SETMETHOD); + return setPropLabels_; + } + ic::BindNameLabels &bindNameLabels() { + JS_ASSERT(kind == ic::PICInfo::BIND); + return bindNameLabels_; + } + ic::ScopeNameLabels &scopeNameLabels() { + JS_ASSERT(kind == ic::PICInfo::NAME || kind == ic::PICInfo::XNAME); + return scopeNameLabels_; + } +#else + ic::GetPropLabels &getPropLabels() { + JS_ASSERT(kind == ic::PICInfo::GET || kind == ic::PICInfo::CALL); + return ic::PICInfo::getPropLabels_; + } + ic::SetPropLabels &setPropLabels() { + JS_ASSERT(kind == ic::PICInfo::SET || kind == ic::PICInfo::SETMETHOD); + return ic::PICInfo::setPropLabels_; + } + ic::BindNameLabels &bindNameLabels() { + JS_ASSERT(kind == ic::PICInfo::BIND); + return ic::PICInfo::bindNameLabels_; + } + ic::ScopeNameLabels &scopeNameLabels() { + JS_ASSERT(kind == ic::PICInfo::NAME || kind == ic::PICInfo::XNAME); + return ic::PICInfo::scopeNameLabels_; + } +#endif + + void copySimpleMembersTo(ic::PICInfo &ic) { + ic.kind = kind; + ic.shapeReg = shapeReg; + ic.objReg = objReg; + ic.atom = atom; + ic.usePropCache = usePropCache; + if (ic.isSet()) { + ic.u.vr = vr; + } else if (ic.isGet()) { + ic.u.get.typeReg = typeReg; + ic.u.get.hasTypeCheck = hasTypeCheck; + } +#ifdef JS_HAS_IC_LABELS + if (ic.isGet()) + ic.setLabels(getPropLabels()); + else if (ic.isSet()) + ic.setLabels(setPropLabels()); + else if (ic.isBind()) + ic.setLabels(bindNameLabels()); + else if (ic.isScopeName()) + ic.setLabels(scopeNameLabels()); +#endif + } + + }; + + struct Defs { + Defs(uint32 ndefs) + : ndefs(ndefs) + { } + uint32 ndefs; + }; + + struct InternalCallSite { + uint32 returnOffset; + jsbytecode *pc; + uint32 id; + bool call; + bool ool; + + InternalCallSite(uint32 returnOffset, jsbytecode *pc, uint32 id, + bool call, bool ool) + : returnOffset(returnOffset), pc(pc), id(id), call(call), ool(ool) + { } + }; + + struct DoublePatch { + double d; + DataLabelPtr label; + bool ool; + }; + + struct JumpTable { + DataLabelPtr label; + size_t offsetIndex; + }; + + JSStackFrame *fp; + JSScript *script; + JSObject *scopeChain; + JSObject *globalObj; + JSFunction *fun; + bool isConstructing; + analyze::Script *analysis; + Label *jumpMap; + bool *savedTraps; + jsbytecode *PC; + Assembler masm; + FrameState frame; + js::Vector branchPatches; +#if defined JS_MONOIC + js::Vector getGlobalNames; + js::Vector setGlobalNames; + js::Vector callICs; + js::Vector equalityICs; + js::Vector traceICs; +#endif +#if defined JS_POLYIC + js::Vector pics; + js::Vector getElemICs; + js::Vector setElemICs; +#endif + js::Vector callPatches; + js::Vector callSites; + js::Vector doubleList; + js::Vector jumpTables; + js::Vector jumpTableOffsets; + StubCompiler stubcc; + Label invokeLabel; + Label arityLabel; + bool debugMode_; + bool addTraceHints; + bool oomInVector; // True if we have OOM'd appending to a vector. + enum { NoApplyTricks, LazyArgsObj } applyTricks; + + Compiler *thisFromCtor() { return this; } + + friend class CompilerAllocPolicy; + public: + // Special atom index used to indicate that the atom is 'length'. This + // follows interpreter usage in JSOP_LENGTH. + enum { LengthAtomIndex = uint32(-2) }; + + Compiler(JSContext *cx, JSStackFrame *fp); + ~Compiler(); + + CompileStatus compile(); + + jsbytecode *getPC() { return PC; } + Label getLabel() { return masm.label(); } + bool knownJump(jsbytecode *pc); + Label labelOf(jsbytecode *target); + void *findCallSite(const CallSite &callSite); + void addCallSite(const InternalCallSite &callSite); + void addReturnSite(Label joinPoint, uint32 id); + bool loadOldTraps(const Vector &site); + + bool debugMode() { return debugMode_; } + + private: + CompileStatus performCompilation(JITScript **jitp); + CompileStatus generatePrologue(); + CompileStatus generateMethod(); + CompileStatus generateEpilogue(); + CompileStatus finishThisUp(JITScript **jitp); + + /* Non-emitting helpers. */ + uint32 fullAtomIndex(jsbytecode *pc); + bool jumpInScript(Jump j, jsbytecode *pc); + bool compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const Value &rhs); + bool canUseApplyTricks(); + + /* Emitting helpers. */ + void restoreFrameRegs(Assembler &masm); + bool emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused); + bool iter(uintN flags); + void iterNext(); + bool iterMore(); + void iterEnd(); + MaybeJump loadDouble(FrameEntry *fe, FPRegisterID fpReg); +#ifdef JS_POLYIC + void passICAddress(BaseICInfo *ic); +#endif +#ifdef JS_MONOIC + void passMICAddress(GlobalNameICInfo &mic); +#endif + bool constructThis(); + + /* Opcode handlers. */ + bool jumpAndTrace(Jump j, jsbytecode *target, Jump *slow = NULL); + void jsop_bindname(JSAtom *atom, bool usePropCache); + void jsop_setglobal(uint32 index); + void jsop_getglobal(uint32 index); + void jsop_getprop_slow(JSAtom *atom, bool usePropCache = true); + void jsop_getarg(uint32 slot); + void jsop_setarg(uint32 slot, bool popped); + void jsop_this(); + void emitReturn(FrameEntry *fe); + void emitFinalReturn(Assembler &masm); + void loadReturnValue(Assembler *masm, FrameEntry *fe); + void emitReturnValue(Assembler *masm, FrameEntry *fe); + void dispatchCall(VoidPtrStubUInt32 stub, uint32 argc); + void interruptCheckHelper(); + void emitUncachedCall(uint32 argc, bool callingNew); + void checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedArgc, + FrameEntry *origCallee, FrameEntry *origThis, + MaybeRegisterID origCalleeType, RegisterID origCalleeData, + MaybeRegisterID origThisType, RegisterID origThisData, + Jump *uncachedCallSlowRejoin, CallPatchInfo *uncachedCallPatch); + void inlineCallHelper(uint32 argc, bool callingNew); + void fixPrimitiveReturn(Assembler *masm, FrameEntry *fe); + void jsop_gnameinc(JSOp op, VoidStubAtom stub, uint32 index); + bool jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index); + bool jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index); + void jsop_eleminc(JSOp op, VoidStub); + void jsop_getgname(uint32 index); + void jsop_getgname_slow(uint32 index); + void jsop_callgname_epilogue(); + void jsop_setgname(JSAtom *atom, bool usePropertyCache); + void jsop_setgname_slow(JSAtom *atom, bool usePropertyCache); + void jsop_bindgname(); + void jsop_setelem_slow(); + void jsop_getelem_slow(); + void jsop_callelem_slow(); + void jsop_unbrand(); + bool jsop_getprop(JSAtom *atom, bool typeCheck = true, bool usePropCache = true); + bool jsop_length(); + bool jsop_setprop(JSAtom *atom, bool usePropCache = true); + void jsop_setprop_slow(JSAtom *atom, bool usePropCache = true); + bool jsop_callprop_slow(JSAtom *atom); + bool jsop_callprop(JSAtom *atom); + bool jsop_callprop_obj(JSAtom *atom); + bool jsop_callprop_str(JSAtom *atom); + bool jsop_callprop_generic(JSAtom *atom); + bool jsop_instanceof(); + void jsop_name(JSAtom *atom); + bool jsop_xname(JSAtom *atom); + void enterBlock(JSObject *obj); + void leaveBlock(); + void emitEval(uint32 argc); + void jsop_arguments(); + bool jsop_tableswitch(jsbytecode *pc); + void jsop_forprop(JSAtom *atom); + void jsop_forname(JSAtom *atom); + void jsop_forgname(JSAtom *atom); + + /* Fast arithmetic. */ + void jsop_binary(JSOp op, VoidStub stub); + void jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub); + void jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub); + void jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub); + void slowLoadConstantDouble(Assembler &masm, FrameEntry *fe, + FPRegisterID fpreg); + void maybeJumpIfNotInt32(Assembler &masm, MaybeJump &mj, FrameEntry *fe, + MaybeRegisterID &mreg); + void maybeJumpIfNotDouble(Assembler &masm, MaybeJump &mj, FrameEntry *fe, + MaybeRegisterID &mreg); + bool jsop_relational(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused); + bool jsop_relational_self(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused); + bool jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused); + bool jsop_relational_double(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused); + + void emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc ®s, + MaybeJump &lhsNotDouble, MaybeJump &rhsNotNumber, + MaybeJump &lhsUnknownDone); + void emitRightDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc ®s, + MaybeJump &rhsNotNumber2); + bool tryBinaryConstantFold(JSContext *cx, FrameState &frame, JSOp op, + FrameEntry *lhs, FrameEntry *rhs); + + /* Fast opcodes. */ + void jsop_bitop(JSOp op); + void jsop_rsh(); + RegisterID rightRegForShift(FrameEntry *rhs); + void jsop_rsh_int_int(FrameEntry *lhs, FrameEntry *rhs); + void jsop_rsh_const_int(FrameEntry *lhs, FrameEntry *rhs); + void jsop_rsh_int_const(FrameEntry *lhs, FrameEntry *rhs); + void jsop_rsh_int_unknown(FrameEntry *lhs, FrameEntry *rhs); + void jsop_rsh_const_const(FrameEntry *lhs, FrameEntry *rhs); + void jsop_rsh_const_unknown(FrameEntry *lhs, FrameEntry *rhs); + void jsop_rsh_unknown_const(FrameEntry *lhs, FrameEntry *rhs); + void jsop_rsh_unknown_any(FrameEntry *lhs, FrameEntry *rhs); + void jsop_mod(); + void jsop_neg(); + void jsop_bitnot(); + void jsop_not(); + void jsop_typeof(); + bool booleanJumpScript(JSOp op, jsbytecode *target); + bool jsop_ifneq(JSOp op, jsbytecode *target); + bool jsop_andor(JSOp op, jsbytecode *target); + void jsop_arginc(JSOp op, uint32 slot, bool popped); + void jsop_localinc(JSOp op, uint32 slot, bool popped); + void jsop_newinit(); + void jsop_initmethod(); + void jsop_initprop(); + void jsop_initelem(); + bool jsop_setelem(bool popGuaranteed); + bool jsop_getelem(bool isCall); + bool isCacheableBaseAndIndex(FrameEntry *obj, FrameEntry *id); + void jsop_stricteq(JSOp op); + bool jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused); + bool jsop_equality_int_string(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused); + void jsop_pos(); + + + void prepareStubCall(Uses uses); + Call emitStubCall(void *ptr); +}; + +// Given a stub call, emits the call into the inline assembly path. If +// debug mode is on, adds the appropriate instrumentation for recompilation. +#define INLINE_STUBCALL(stub) \ + do { \ + Call cl = emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub))); \ + if (debugMode()) { \ + InternalCallSite site(masm.callReturnOffset(cl), PC, __LINE__, \ + true, false); \ + addCallSite(site); \ + } \ + } while (0) \ + +// Given a stub call, emits the call into the out-of-line assembly path. If +// debug mode is on, adds the appropriate instrumentation for recompilation. +// Unlike the INLINE_STUBCALL variant, this returns the Call offset. +#define OOL_STUBCALL(stub) \ + stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), __LINE__) \ + +// Same as OOL_STUBCALL, but specifies a slot depth. +#define OOL_STUBCALL_LOCAL_SLOTS(stub, slots) \ + stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), (slots), __LINE__) \ + +} /* namespace js */ +} /* namespace mjit */ + +#endif + diff --git a/js/src/methodjit/FastArithmetic.cpp b/js/src/methodjit/FastArithmetic.cpp new file mode 100644 index 0000000..653581d --- /dev/null +++ b/js/src/methodjit/FastArithmetic.cpp @@ -0,0 +1,1617 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * Sean Stangl + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "jsbool.h" +#include "jslibmath.h" +#include "jsnum.h" +#include "methodjit/MethodJIT.h" +#include "methodjit/Compiler.h" +#include "methodjit/StubCalls.h" +#include "methodjit/FrameState-inl.h" + +using namespace js; +using namespace js::mjit; +using namespace JSC; + +typedef JSC::MacroAssembler::FPRegisterID FPRegisterID; + +bool +mjit::Compiler::tryBinaryConstantFold(JSContext *cx, FrameState &frame, JSOp op, + FrameEntry *lhs, FrameEntry *rhs) +{ + if (!lhs->isConstant() || !rhs->isConstant()) + return false; + + const Value &L = lhs->getValue(); + const Value &R = rhs->getValue(); + + if (!L.isPrimitive() || !R.isPrimitive() || + (op == JSOP_ADD && (L.isString() || R.isString()))) { + return false; + } + + bool needInt; + switch (op) { + case JSOP_ADD: + case JSOP_SUB: + case JSOP_MUL: + case JSOP_DIV: + needInt = false; + break; + + case JSOP_MOD: + needInt = (L.isInt32() && R.isInt32() && + L.toInt32() >= 0 && R.toInt32() > 0); + break; + + case JSOP_RSH: + needInt = true; + break; + + default: + JS_NOT_REACHED("NYI"); + needInt = false; /* Silence compiler warning. */ + break; + } + + double dL = 0, dR = 0; + int32_t nL = 0, nR = 0; + /* + * We don't need to check for conversion failure, since primitive conversion + * is infallible. + */ + if (needInt) { + ValueToECMAInt32(cx, L, &nL); + ValueToECMAInt32(cx, R, &nR); + } else { + ValueToNumber(cx, L, &dL); + ValueToNumber(cx, R, &dR); + } + + switch (op) { + case JSOP_ADD: + dL += dR; + break; + case JSOP_SUB: + dL -= dR; + break; + case JSOP_MUL: + dL *= dR; + break; + case JSOP_DIV: + if (dR == 0) { +#ifdef XP_WIN + if (JSDOUBLE_IS_NaN(dR)) + dL = js_NaN; + else +#endif + if (dL == 0 || JSDOUBLE_IS_NaN(dL)) + dL = js_NaN; + else if (JSDOUBLE_IS_NEG(dL) != JSDOUBLE_IS_NEG(dR)) + dL = cx->runtime->negativeInfinityValue.toDouble(); + else + dL = cx->runtime->positiveInfinityValue.toDouble(); + } else { + dL /= dR; + } + break; + case JSOP_MOD: + if (needInt) + nL %= nR; + else if (dR == 0) + dL = js_NaN; + else + dL = js_fmod(dL, dR); + break; + + case JSOP_RSH: + nL >>= (nR & 31); + break; + + default: + JS_NOT_REACHED("NYI"); + break; + } + + Value v; + if (needInt) + v.setInt32(nL); + else + v.setNumber(dL); + frame.popn(2); + frame.push(v); + + return true; +} + +void +mjit::Compiler::slowLoadConstantDouble(Assembler &masm, + FrameEntry *fe, FPRegisterID fpreg) +{ + DoublePatch patch; + if (fe->getKnownType() == JSVAL_TYPE_INT32) + patch.d = (double)fe->getValue().toInt32(); + else + patch.d = fe->getValue().toDouble(); + patch.label = masm.loadDouble(NULL, fpreg); + patch.ool = &masm != &this->masm; + JS_ASSERT_IF(patch.ool, &masm == &stubcc.masm); + doubleList.append(patch); +} + +void +mjit::Compiler::maybeJumpIfNotInt32(Assembler &masm, MaybeJump &mj, FrameEntry *fe, + MaybeRegisterID &mreg) +{ + if (!fe->isTypeKnown()) { + if (mreg.isSet()) + mj.setJump(masm.testInt32(Assembler::NotEqual, mreg.reg())); + else + mj.setJump(masm.testInt32(Assembler::NotEqual, frame.addressOf(fe))); + } else if (fe->getKnownType() != JSVAL_TYPE_INT32) { + mj.setJump(masm.jump()); + } +} + +void +mjit::Compiler::maybeJumpIfNotDouble(Assembler &masm, MaybeJump &mj, FrameEntry *fe, + MaybeRegisterID &mreg) +{ + if (!fe->isTypeKnown()) { + if (mreg.isSet()) + mj.setJump(masm.testDouble(Assembler::NotEqual, mreg.reg())); + else + mj.setJump(masm.testDouble(Assembler::NotEqual, frame.addressOf(fe))); + } else if (fe->getKnownType() != JSVAL_TYPE_DOUBLE) { + mj.setJump(masm.jump()); + } +} + +void +mjit::Compiler::jsop_binary(JSOp op, VoidStub stub) +{ + FrameEntry *rhs = frame.peek(-1); + FrameEntry *lhs = frame.peek(-2); + + if (tryBinaryConstantFold(cx, frame, op, lhs, rhs)) + return; + + /* + * Bail out if there are unhandled types or ops. + * This is temporary while ops are still being implemented. + */ + if ((op == JSOP_MOD) || + (lhs->isTypeKnown() && (lhs->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET)) || + (rhs->isTypeKnown() && (rhs->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET)) +#if defined(JS_CPU_ARM) + /* ARM cannot detect integer overflow with multiplication. */ + || op == JSOP_MUL +#endif /* JS_CPU_ARM */ + ) { + bool isStringResult = (op == JSOP_ADD) && + (lhs->isType(JSVAL_TYPE_STRING) || + rhs->isType(JSVAL_TYPE_STRING)); + + prepareStubCall(Uses(2)); + INLINE_STUBCALL(stub); + frame.popn(2); + if (isStringResult) + frame.pushSyncedType(JSVAL_TYPE_STRING); + else + frame.pushSynced(); + return; + } + + /* Can do int math iff there is no double constant and the op is not division. */ + bool canDoIntMath = op != JSOP_DIV && + !((rhs->isTypeKnown() && rhs->getKnownType() == JSVAL_TYPE_DOUBLE) || + (lhs->isTypeKnown() && lhs->getKnownType() == JSVAL_TYPE_DOUBLE)); + + if (canDoIntMath) + jsop_binary_full(lhs, rhs, op, stub); + else + jsop_binary_double(lhs, rhs, op, stub); +} + +static void +EmitDoubleOp(JSOp op, FPRegisterID fpRight, FPRegisterID fpLeft, Assembler &masm) +{ + switch (op) { + case JSOP_ADD: + masm.addDouble(fpRight, fpLeft); + break; + + case JSOP_SUB: + masm.subDouble(fpRight, fpLeft); + break; + + case JSOP_MUL: + masm.mulDouble(fpRight, fpLeft); + break; + + case JSOP_DIV: + masm.divDouble(fpRight, fpLeft); + break; + + default: + JS_NOT_REACHED("unrecognized binary op"); + } +} + +mjit::MaybeJump +mjit::Compiler::loadDouble(FrameEntry *fe, FPRegisterID fpReg) +{ + MaybeJump notNumber; + + if (fe->isConstant()) { + slowLoadConstantDouble(masm, fe, fpReg); + } else if (!fe->isTypeKnown()) { + frame.tempRegForType(fe); + Jump j = frame.testDouble(Assembler::Equal, fe); + notNumber = frame.testInt32(Assembler::NotEqual, fe); + frame.convertInt32ToDouble(masm, fe, fpReg); + Jump converted = masm.jump(); + j.linkTo(masm.label(), &masm); + // CANDIDATE + frame.loadDouble(fe, fpReg, masm); + converted.linkTo(masm.label(), &masm); + } else if (fe->getKnownType() == JSVAL_TYPE_INT32) { + frame.tempRegForData(fe); + frame.convertInt32ToDouble(masm, fe, fpReg); + } else { + JS_ASSERT(fe->getKnownType() == JSVAL_TYPE_DOUBLE); + frame.loadDouble(fe, fpReg, masm); + } + + return notNumber; +} + +/* + * This function emits a single fast-path for handling numerical arithmetic. + * Unlike jsop_binary_full(), all integers are converted to doubles. + */ +void +mjit::Compiler::jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub) +{ + FPRegisterID fpLeft = FPRegisters::First; + FPRegisterID fpRight = FPRegisters::Second; + + MaybeJump lhsNotNumber = loadDouble(lhs, fpLeft); + if (lhsNotNumber.isSet()) + stubcc.linkExit(lhsNotNumber.get(), Uses(2)); + + MaybeJump rhsNotNumber; + if (frame.haveSameBacking(lhs, rhs)) { + masm.moveDouble(fpLeft, fpRight); + } else { + rhsNotNumber = loadDouble(rhs, fpRight); + if (rhsNotNumber.isSet()) + stubcc.linkExit(rhsNotNumber.get(), Uses(2)); + } + + EmitDoubleOp(op, fpRight, fpLeft, masm); + + MaybeJump done; + + /* + * Try to convert result to integer. Skip this for 1/x or -1/x, as the + * result is unlikely to fit in an int. + */ + if (op == JSOP_DIV && !(lhs->isConstant() && lhs->isType(JSVAL_TYPE_INT32) && + abs(lhs->getValue().toInt32()) == 1)) { + RegisterID reg = frame.allocReg(); + JumpList isDouble; + masm.branchConvertDoubleToInt32(fpLeft, reg, isDouble, fpRight); + + masm.storeValueFromComponents(ImmType(JSVAL_TYPE_INT32), reg, + frame.addressOf(lhs)); + + frame.freeReg(reg); + done.setJump(masm.jump()); + isDouble.linkTo(masm.label(), &masm); + } + + masm.storeDouble(fpLeft, frame.addressOf(lhs)); + + if (done.isSet()) + done.getJump().linkTo(masm.label(), &masm); + + if (lhsNotNumber.isSet() || rhsNotNumber.isSet()) { + stubcc.leave(); + OOL_STUBCALL(stub); + } + + frame.popn(2); + frame.pushNumber(MaybeRegisterID()); + + if (lhsNotNumber.isSet() || rhsNotNumber.isSet()) + stubcc.rejoin(Changes(1)); +} + +/* + * Simpler version of jsop_binary_full() for when lhs == rhs. + */ +void +mjit::Compiler::jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub) +{ + FrameEntry *lhs = frame.peek(-2); + + /* Easiest case: known double. Don't bother conversion back yet? */ + if (fe->isTypeKnown() && fe->getKnownType() == JSVAL_TYPE_DOUBLE) { + loadDouble(fe, FPRegisters::First); + EmitDoubleOp(op, FPRegisters::First, FPRegisters::First, masm); + frame.popn(2); + frame.pushNumber(MaybeRegisterID()); + return; + } + + /* Allocate all registers up-front. */ + FrameState::BinaryAlloc regs; + frame.allocForSameBinary(fe, op, regs); + + MaybeJump notNumber; + MaybeJump doublePathDone; + if (!fe->isTypeKnown()) { + Jump notInt = masm.testInt32(Assembler::NotEqual, regs.lhsType.reg()); + stubcc.linkExitDirect(notInt, stubcc.masm.label()); + + notNumber = stubcc.masm.testDouble(Assembler::NotEqual, regs.lhsType.reg()); + frame.loadDouble(fe, FPRegisters::First, stubcc.masm); + EmitDoubleOp(op, FPRegisters::First, FPRegisters::First, stubcc.masm); + + /* Force the double back to memory. */ + Address result = frame.addressOf(lhs); + stubcc.masm.storeDouble(FPRegisters::First, result); + + /* Load the payload into the result reg so the rejoin is safe. */ + stubcc.masm.loadPayload(result, regs.result); + + doublePathDone = stubcc.masm.jump(); + } + + /* Okay - good to emit the integer fast-path. */ + MaybeJump overflow; + switch (op) { + case JSOP_ADD: + overflow = masm.branchAdd32(Assembler::Overflow, regs.result, regs.result); + break; + + case JSOP_SUB: + overflow = masm.branchSub32(Assembler::Overflow, regs.result, regs.result); + break; + +#if !defined(JS_CPU_ARM) + case JSOP_MUL: + overflow = masm.branchMul32(Assembler::Overflow, regs.result, regs.result); + break; +#endif + + default: + JS_NOT_REACHED("unrecognized op"); + } + + JS_ASSERT(overflow.isSet()); + + /* + * Integer overflow path. Separate from the first double path, since we + * know never to try and convert back to integer. + */ + MaybeJump overflowDone; + stubcc.linkExitDirect(overflow.get(), stubcc.masm.label()); + { + if (regs.lhsNeedsRemat) { + Address address = masm.payloadOf(frame.addressForDataRemat(lhs)); + stubcc.masm.convertInt32ToDouble(address, FPRegisters::First); + } else if (!lhs->isConstant()) { + stubcc.masm.convertInt32ToDouble(regs.lhsData.reg(), FPRegisters::First); + } else { + slowLoadConstantDouble(stubcc.masm, lhs, FPRegisters::First); + } + + EmitDoubleOp(op, FPRegisters::First, FPRegisters::First, stubcc.masm); + + Address address = frame.addressOf(lhs); + stubcc.masm.storeDouble(FPRegisters::First, address); + stubcc.masm.loadPayload(address, regs.result); + + overflowDone = stubcc.masm.jump(); + } + + /* Slow paths funnel here. */ + if (notNumber.isSet()) + notNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm); + overflowDone.get().linkTo(stubcc.masm.label(), &stubcc.masm); + + /* Slow call - use frame.sync to avoid erroneous jump repatching in stubcc. */ + frame.sync(stubcc.masm, Uses(2)); + stubcc.leave(); + OOL_STUBCALL(stub); + + /* Finish up stack operations. */ + frame.popn(2); + frame.pushNumber(regs.result, true); + + /* Merge back OOL double paths. */ + if (doublePathDone.isSet()) + stubcc.linkRejoin(doublePathDone.get()); + stubcc.linkRejoin(overflowDone.get()); + + stubcc.rejoin(Changes(1)); +} + +/* + * This function emits multiple fast-paths for handling numerical arithmetic. + * Currently, it handles only ADD, SUB, and MUL, where both LHS and RHS are + * known not to be doubles. + * + * The control flow of the emitted code depends on which types are known. + * Given both types are unknown, the full spread looks like: + * + * Inline OOL + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Is LHS Int32? ------ No --------> Is LHS Double? ----- No -------, + * Sync LHS | + * Load LHS into XMM1 | + * Is RHS Double? ---- Yes --, | + * Is RHS Int32? ---- No --|-----| + * Convert RHS into XMM0 | | + * Else <-------------------' | + * Sync RHS | + * Load RHS into XMM0 | + * [Add,Sub,Mul] XMM0,XMM1 | + * Jump ---------------------, | + * | | + * Is RHS Int32? ------ No -------> Is RHS Double? ----- No --|-----| + * Sync RHS | | + * Load RHS into XMM0 | | + * Convert LHS into XMM1 | | + * [Add,Sub,Mul] XMM0,XMM1 | | + * Jump ---------------------| Slow Call + * | + * [Add,Sub,Mul] RHS, LHS | + * Overflow ------ Yes -------> Convert RHS into XMM0 | + * Convert LHS into XMM1 | + * [Add,Sub,Mul] XMM0,XMM1 | + * Sync XMM1 to stack <---' + * <--------------------------------- Rejoin + */ +void +mjit::Compiler::jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub) +{ + if (frame.haveSameBacking(lhs, rhs)) { + jsop_binary_full_simple(lhs, op, stub); + return; + } + + /* Allocate all registers up-front. */ + FrameState::BinaryAlloc regs; + frame.allocForBinary(lhs, rhs, op, regs); + + /* Quick-test some invariants. */ + JS_ASSERT_IF(lhs->isTypeKnown(), lhs->getKnownType() == JSVAL_TYPE_INT32); + JS_ASSERT_IF(rhs->isTypeKnown(), rhs->getKnownType() == JSVAL_TYPE_INT32); + + FPRegisterID fpLeft = FPRegisters::First; + FPRegisterID fpRight = FPRegisters::Second; + + MaybeJump lhsNotDouble, rhsNotNumber, lhsUnknownDone; + if (!lhs->isTypeKnown()) + emitLeftDoublePath(lhs, rhs, regs, lhsNotDouble, rhsNotNumber, lhsUnknownDone); + + MaybeJump rhsNotNumber2; + if (!rhs->isTypeKnown()) + emitRightDoublePath(lhs, rhs, regs, rhsNotNumber2); + + /* Perform the double addition. */ + MaybeJump doublePathDone; + if (!rhs->isTypeKnown() || lhsUnknownDone.isSet()) { + /* If the LHS type was not known, link its path here. */ + if (lhsUnknownDone.isSet()) + lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm); + + /* Perform the double operation. */ + EmitDoubleOp(op, fpRight, fpLeft, stubcc.masm); + + /* Force the double back to memory. */ + Address result = frame.addressOf(lhs); + stubcc.masm.storeDouble(fpLeft, result); + + /* Load the payload into the result reg so the rejoin is safe. */ + stubcc.masm.loadPayload(result, regs.result); + + /* We'll link this back up later, at the bottom of the op. */ + doublePathDone = stubcc.masm.jump(); + } + + /* Time to do the integer path. Figure out the immutable side. */ + int32 value = 0; + JSOp origOp = op; + MaybeRegisterID reg; + MaybeJump preOverflow; + if (!regs.resultHasRhs) { + if (!regs.rhsData.isSet()) + value = rhs->getValue().toInt32(); + else + reg = regs.rhsData.reg(); + } else { + if (!regs.lhsData.isSet()) + value = lhs->getValue().toInt32(); + else + reg = regs.lhsData.reg(); + if (op == JSOP_SUB) { + // If the RHS is 0x80000000, the smallest negative value, neg does + // not work. Guard against this and treat it as an overflow. + preOverflow = masm.branch32(Assembler::Equal, regs.result, Imm32(0x80000000)); + masm.neg32(regs.result); + op = JSOP_ADD; + } + } + + /* Okay - good to emit the integer fast-path. */ + MaybeJump overflow, negZeroDone; + switch (op) { + case JSOP_ADD: + if (reg.isSet()) + overflow = masm.branchAdd32(Assembler::Overflow, reg.reg(), regs.result); + else + overflow = masm.branchAdd32(Assembler::Overflow, Imm32(value), regs.result); + break; + + case JSOP_SUB: + if (reg.isSet()) + overflow = masm.branchSub32(Assembler::Overflow, reg.reg(), regs.result); + else + overflow = masm.branchSub32(Assembler::Overflow, Imm32(value), regs.result); + break; + +#if !defined(JS_CPU_ARM) + case JSOP_MUL: + { + JS_ASSERT(reg.isSet()); + + MaybeJump storeNegZero; + bool maybeNegZero = true; + bool hasConstant = (lhs->isConstant() || rhs->isConstant()); + + if (hasConstant) { + value = (lhs->isConstant() ? lhs : rhs)->getValue().toInt32(); + RegisterID nonConstReg = lhs->isConstant() ? regs.rhsData.reg() : regs.lhsData.reg(); + + if (value > 0) + maybeNegZero = false; + else if (value < 0) + storeNegZero = masm.branchTest32(Assembler::Zero, nonConstReg); + else + storeNegZero = masm.branch32(Assembler::LessThan, nonConstReg, Imm32(0)); + } + overflow = masm.branchMul32(Assembler::Overflow, reg.reg(), regs.result); + + if (maybeNegZero) { + if (!hasConstant) { + Jump isZero = masm.branchTest32(Assembler::Zero, regs.result); + stubcc.linkExitDirect(isZero, stubcc.masm.label()); + + /* Restore original value. */ + if (regs.resultHasRhs) { + if (regs.rhsNeedsRemat) + stubcc.masm.loadPayload(frame.addressForDataRemat(rhs), regs.result); + else + stubcc.masm.move(regs.rhsData.reg(), regs.result); + } else { + if (regs.lhsNeedsRemat) + stubcc.masm.loadPayload(frame.addressForDataRemat(lhs), regs.result); + else + stubcc.masm.move(regs.lhsData.reg(), regs.result); + } + storeNegZero = stubcc.masm.branchOr32(Assembler::Signed, reg.reg(), regs.result); + stubcc.masm.xor32(regs.result, regs.result); + stubcc.crossJump(stubcc.masm.jump(), masm.label()); + storeNegZero.getJump().linkTo(stubcc.masm.label(), &stubcc.masm); + } else { + JS_ASSERT(storeNegZero.isSet()); + stubcc.linkExitDirect(storeNegZero.get(), stubcc.masm.label()); + } + stubcc.masm.storeValue(DoubleValue(-0.0), frame.addressOf(lhs)); + stubcc.masm.loadPayload(frame.addressOf(lhs), regs.result); + negZeroDone = stubcc.masm.jump(); + } + break; + } +#endif + + default: + JS_NOT_REACHED("unrecognized op"); + } + op = origOp; + + JS_ASSERT(overflow.isSet()); + + /* + * Integer overflow path. Separate from the first double path, since we + * know never to try and convert back to integer. + */ + MaybeJump overflowDone; + if (preOverflow.isSet()) + stubcc.linkExitDirect(preOverflow.get(), stubcc.masm.label()); + stubcc.linkExitDirect(overflow.get(), stubcc.masm.label()); + { + if (regs.lhsNeedsRemat) { + Address address = masm.payloadOf(frame.addressForDataRemat(lhs)); + stubcc.masm.convertInt32ToDouble(address, fpLeft); + } else if (!lhs->isConstant()) { + stubcc.masm.convertInt32ToDouble(regs.lhsData.reg(), fpLeft); + } else { + slowLoadConstantDouble(stubcc.masm, lhs, fpLeft); + } + + if (regs.rhsNeedsRemat) { + Address address = masm.payloadOf(frame.addressForDataRemat(rhs)); + stubcc.masm.convertInt32ToDouble(address, fpRight); + } else if (!rhs->isConstant()) { + stubcc.masm.convertInt32ToDouble(regs.rhsData.reg(), fpRight); + } else { + slowLoadConstantDouble(stubcc.masm, rhs, fpRight); + } + + EmitDoubleOp(op, fpRight, fpLeft, stubcc.masm); + + Address address = frame.addressOf(lhs); + stubcc.masm.storeDouble(fpLeft, address); + stubcc.masm.loadPayload(address, regs.result); + + overflowDone = stubcc.masm.jump(); + } + + /* The register allocator creates at most one temporary. */ + if (regs.extraFree.isSet()) + frame.freeReg(regs.extraFree.reg()); + + /* Slow paths funnel here. */ + if (lhsNotDouble.isSet()) { + lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm); + if (rhsNotNumber.isSet()) + rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm); + } + if (rhsNotNumber2.isSet()) + rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm); + + /* Slow call - use frame.sync to avoid erroneous jump repatching in stubcc. */ + frame.sync(stubcc.masm, Uses(2)); + stubcc.leave(); + OOL_STUBCALL(stub); + + /* Finish up stack operations. */ + frame.popn(2); + frame.pushNumber(regs.result, true); + + /* Merge back OOL double paths. */ + if (doublePathDone.isSet()) + stubcc.linkRejoin(doublePathDone.get()); + if (negZeroDone.isSet()) + stubcc.linkRejoin(negZeroDone.get()); + stubcc.linkRejoin(overflowDone.get()); + + stubcc.rejoin(Changes(1)); +} + +static const uint64 DoubleNegMask = 0x8000000000000000ULL; + +void +mjit::Compiler::jsop_neg() +{ + FrameEntry *fe = frame.peek(-1); + + if (fe->isTypeKnown() && fe->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET) { + prepareStubCall(Uses(1)); + INLINE_STUBCALL(stubs::Neg); + frame.pop(); + frame.pushSynced(); + return; + } + + JS_ASSERT(!fe->isConstant()); + + /* Load type information into register. */ + MaybeRegisterID feTypeReg; + if (!fe->isTypeKnown() && !frame.shouldAvoidTypeRemat(fe)) { + /* Safe because only one type is loaded. */ + feTypeReg.setReg(frame.tempRegForType(fe)); + + /* Don't get clobbered by copyDataIntoReg(). */ + frame.pinReg(feTypeReg.reg()); + } + + RegisterID reg = frame.copyDataIntoReg(masm, fe); + Label feSyncTarget = stubcc.syncExitAndJump(Uses(1)); + + /* Try a double path (inline). */ + MaybeJump jmpNotDbl; + { + maybeJumpIfNotDouble(masm, jmpNotDbl, fe, feTypeReg); + + FPRegisterID fpreg = frame.copyEntryIntoFPReg(fe, FPRegisters::First); + +#if defined JS_CPU_X86 || defined JS_CPU_X64 + masm.loadDouble(&DoubleNegMask, FPRegisters::Second); + masm.xorDouble(FPRegisters::Second, fpreg); +#elif defined JS_CPU_ARM + masm.negDouble(fpreg, fpreg); +#endif + + /* Overwrite pushed frame's memory (before push). */ + masm.storeDouble(fpreg, frame.addressOf(fe)); + } + + /* Try an integer path (out-of-line). */ + MaybeJump jmpNotInt; + MaybeJump jmpIntZero; + MaybeJump jmpMinInt; + MaybeJump jmpIntRejoin; + Label lblIntPath = stubcc.masm.label(); + { + maybeJumpIfNotInt32(stubcc.masm, jmpNotInt, fe, feTypeReg); + + /* 0 (int) -> -0 (double). */ + jmpIntZero.setJump(stubcc.masm.branch32(Assembler::Equal, reg, Imm32(0))); + /* int32 negation on (-2147483648) yields (-2147483648). */ + jmpMinInt.setJump(stubcc.masm.branch32(Assembler::Equal, reg, Imm32(1 << 31))); + + stubcc.masm.neg32(reg); + + /* Sync back with double path. */ + stubcc.masm.storeValueFromComponents(ImmType(JSVAL_TYPE_INT32), reg, + frame.addressOf(fe)); + + jmpIntRejoin.setJump(stubcc.masm.jump()); + } + + frame.freeReg(reg); + if (feTypeReg.isSet()) + frame.unpinReg(feTypeReg.reg()); + + stubcc.leave(); + OOL_STUBCALL(stubs::Neg); + + frame.pop(); + frame.pushSynced(); + + /* Link jumps. */ + if (jmpNotDbl.isSet()) + stubcc.linkExitDirect(jmpNotDbl.getJump(), lblIntPath); + + if (jmpNotInt.isSet()) + jmpNotInt.getJump().linkTo(feSyncTarget, &stubcc.masm); + if (jmpIntZero.isSet()) + jmpIntZero.getJump().linkTo(feSyncTarget, &stubcc.masm); + if (jmpMinInt.isSet()) + jmpMinInt.getJump().linkTo(feSyncTarget, &stubcc.masm); + if (jmpIntRejoin.isSet()) + stubcc.crossJump(jmpIntRejoin.getJump(), masm.label()); + + stubcc.rejoin(Changes(1)); +} + +void +mjit::Compiler::jsop_mod() +{ +#if defined(JS_CPU_X86) + FrameEntry *lhs = frame.peek(-2); + FrameEntry *rhs = frame.peek(-1); + + if (tryBinaryConstantFold(cx, frame, JSOP_MOD, lhs, rhs)) + return; + + if ((lhs->isTypeKnown() && lhs->getKnownType() != JSVAL_TYPE_INT32) || + (rhs->isTypeKnown() && rhs->getKnownType() != JSVAL_TYPE_INT32)) +#endif + { + prepareStubCall(Uses(2)); + INLINE_STUBCALL(stubs::Mod); + frame.popn(2); + frame.pushSynced(); + return; + } + +#if defined(JS_CPU_X86) + if (!lhs->isTypeKnown()) { + Jump j = frame.testInt32(Assembler::NotEqual, lhs); + stubcc.linkExit(j, Uses(2)); + } + if (!rhs->isTypeKnown()) { + Jump j = frame.testInt32(Assembler::NotEqual, rhs); + stubcc.linkExit(j, Uses(2)); + } + + /* LHS must be in EAX:EDX */ + if (!lhs->isConstant()) { + frame.copyDataIntoReg(lhs, X86Registers::eax); + } else { + frame.takeReg(X86Registers::eax); + masm.move(Imm32(lhs->getValue().toInt32()), X86Registers::eax); + } + + /* Get RHS into anything but EDX - could avoid more spilling? */ + MaybeRegisterID temp; + RegisterID rhsReg; + if (!rhs->isConstant()) { + uint32 mask = Registers::AvailRegs & ~Registers::maskReg(X86Registers::edx); + rhsReg = frame.tempRegInMaskForData(rhs, mask); + JS_ASSERT(rhsReg != X86Registers::edx); + } else { + rhsReg = frame.allocReg(Registers::AvailRegs & ~Registers::maskReg(X86Registers::edx)); + JS_ASSERT(rhsReg != X86Registers::edx); + masm.move(Imm32(rhs->getValue().toInt32()), rhsReg); + temp = rhsReg; + } + frame.takeReg(X86Registers::edx); + frame.freeReg(X86Registers::eax); + + if (temp.isSet()) + frame.freeReg(temp.reg()); + + bool slowPath = !(lhs->isTypeKnown() && rhs->isTypeKnown()); + if (rhs->isConstant() && rhs->getValue().toInt32() != 0) { + if (rhs->getValue().toInt32() == -1) { + /* Guard against -1 / INT_MIN which throws a hardware exception. */ + Jump checkDivExc = masm.branch32(Assembler::Equal, X86Registers::eax, + Imm32(0x80000000)); + stubcc.linkExit(checkDivExc, Uses(2)); + slowPath = true; + } + } else { + Jump checkDivExc = masm.branch32(Assembler::Equal, X86Registers::eax, Imm32(0x80000000)); + stubcc.linkExit(checkDivExc, Uses(2)); + Jump checkZero = masm.branchTest32(Assembler::Zero, rhsReg, rhsReg); + stubcc.linkExit(checkZero, Uses(2)); + slowPath = true; + } + + /* Perform division. */ + masm.idiv(rhsReg); + + /* ECMA-262 11.5.3 requires the result to have the same sign as the lhs. + * Thus, if the remainder of the div instruction is zero and the lhs is + * negative, we must return negative 0. */ + + bool lhsMaybeNeg = true; + bool lhsIsNeg = false; + if (lhs->isConstant()) { + /* This condition is established at the top of this function. */ + JS_ASSERT(lhs->getValue().isInt32()); + lhsMaybeNeg = lhsIsNeg = (lhs->getValue().toInt32() < 0); + } + + MaybeJump done; + if (lhsMaybeNeg) { + MaybeRegisterID lhsData; + if (!lhsIsNeg) + lhsData = frame.tempRegForData(lhs); + Jump negZero1 = masm.branchTest32(Assembler::NonZero, X86Registers::edx); + MaybeJump negZero2; + if (!lhsIsNeg) + negZero2 = masm.branchTest32(Assembler::Zero, lhsData.reg(), Imm32(0x80000000)); + /* Darn, negative 0. */ + masm.storeValue(DoubleValue(-0.0), frame.addressOf(lhs)); + + /* :TODO: This is wrong, must load into EDX as well. */ + + done = masm.jump(); + negZero1.linkTo(masm.label(), &masm); + if (negZero2.isSet()) + negZero2.getJump().linkTo(masm.label(), &masm); + } + + /* Better - integer. */ + masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), frame.addressOf(lhs)); + + if (done.isSet()) + done.getJump().linkTo(masm.label(), &masm); + + if (slowPath) { + stubcc.leave(); + OOL_STUBCALL(stubs::Mod); + } + + frame.popn(2); + frame.pushNumber(X86Registers::edx); + + if (slowPath) + stubcc.rejoin(Changes(1)); +#endif +} + +bool +mjit::Compiler::jsop_equality_int_string(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused) +{ + FrameEntry *rhs = frame.peek(-1); + FrameEntry *lhs = frame.peek(-2); + + /* Swap the LHS and RHS if it makes register allocation better... or possible. */ + if (lhs->isConstant() || + (frame.shouldAvoidDataRemat(lhs) && !rhs->isConstant())) { + FrameEntry *temp = rhs; + rhs = lhs; + lhs = temp; + } + + bool lhsInt = lhs->isType(JSVAL_TYPE_INT32); + bool rhsInt = rhs->isType(JSVAL_TYPE_INT32); + + /* Invert the condition if fusing with an IFEQ branch. */ + bool flipCondition = (target && fused == JSOP_IFEQ); + + /* Get the condition being tested. */ + Assembler::Condition cond; + switch (op) { + case JSOP_EQ: + cond = flipCondition ? Assembler::NotEqual : Assembler::Equal; + break; + case JSOP_NE: + cond = flipCondition ? Assembler::Equal : Assembler::NotEqual; + break; + default: + JS_NOT_REACHED("wat"); + return false; + } + + if (target) { + Value rval = UndefinedValue(); /* quiet gcc warning */ + bool rhsConst = false; + if (rhs->isConstant()) { + rhsConst = true; + rval = rhs->getValue(); + } + + ValueRemat lvr, rvr; + frame.pinEntry(lhs, lvr); + frame.pinEntry(rhs, rvr); + + /* + * Sync everything except the top two entries. + * We will handle the lhs/rhs in the stub call path. + */ + frame.syncAndKill(Registers(Registers::AvailRegs), Uses(frame.frameSlots()), Uses(2)); + + RegisterID tempReg = frame.allocReg(); + + frame.pop(); + frame.pop(); + frame.discardFrame(); + + JaegerSpew(JSpew_Insns, " ---- BEGIN STUB CALL CODE ---- \n"); + + RESERVE_OOL_SPACE(stubcc.masm); + + /* Start of the slow path for equality stub call. */ + Label stubEntry = stubcc.masm.label(); + + /* The lhs/rhs need to be synced in the stub call path. */ + frame.ensureValueSynced(stubcc.masm, lhs, lvr); + frame.ensureValueSynced(stubcc.masm, rhs, rvr); + + bool needStub = true; + +#ifdef JS_MONOIC + EqualityGenInfo ic; + + ic.cond = cond; + ic.tempReg = tempReg; + ic.lvr = lvr; + ic.rvr = rvr; + ic.stubEntry = stubEntry; + ic.stub = stub; + + bool useIC = !addTraceHints || target >= PC; + + /* Call the IC stub, which may generate a fast path. */ + if (useIC) { + /* Adjust for the two values just pushed. */ + ic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1); + ic.stubCall = OOL_STUBCALL_LOCAL_SLOTS(ic::Equality, + frame.stackDepth() + script->nfixed + 2); + needStub = false; + } +#endif + + if (needStub) + OOL_STUBCALL_LOCAL_SLOTS(stub, frame.stackDepth() + script->nfixed + 2); + + /* + * The stub call has no need to rejoin, since state is synced. + * Instead, we can just test the return value. + */ + Assembler::Condition ncond = (fused == JSOP_IFEQ) + ? Assembler::Zero + : Assembler::NonZero; + Jump stubBranch = + stubcc.masm.branchTest32(ncond, Registers::ReturnReg, Registers::ReturnReg); + Jump stubFallthrough = stubcc.masm.jump(); + + JaegerSpew(JSpew_Insns, " ---- END STUB CALL CODE ---- \n"); + CHECK_OOL_SPACE(); + + Jump fast; + MaybeJump firstStubJump; + + if ((!lhs->isTypeKnown() || lhsInt) && (!rhs->isTypeKnown() || rhsInt)) { + if (!lhsInt) { + Jump lhsFail = masm.testInt32(Assembler::NotEqual, lvr.typeReg()); + stubcc.linkExitDirect(lhsFail, stubEntry); + firstStubJump = lhsFail; + } + if (!rhsInt) { + Jump rhsFail = masm.testInt32(Assembler::NotEqual, rvr.typeReg()); + stubcc.linkExitDirect(rhsFail, stubEntry); + if (!firstStubJump.isSet()) + firstStubJump = rhsFail; + } + + if (rhsConst) + fast = masm.branch32(cond, lvr.dataReg(), Imm32(rval.toInt32())); + else + fast = masm.branch32(cond, lvr.dataReg(), rvr.dataReg()); + + if (!jumpInScript(fast, target)) + return false; + } else { + Jump j = masm.jump(); + stubcc.linkExitDirect(j, stubEntry); + firstStubJump = j; + + /* This is just a dummy jump. */ + fast = masm.jump(); + } + +#ifdef JS_MONOIC + ic.jumpToStub = firstStubJump; + if (useIC) { + ic.fallThrough = masm.label(); + ic.jumpTarget = target; + equalityICs.append(ic); + } +#endif + + /* Jump from the stub call fallthrough to here. */ + stubcc.crossJump(stubFallthrough, masm.label()); + + /* + * NB: jumpAndTrace emits to the OOL path, so make sure not to use it + * in the middle of an in-progress slow path. + */ + if (!jumpAndTrace(fast, target, &stubBranch)) + return false; + } else { + /* No fusing. Compare, set, and push a boolean. */ + + /* Should have filtered these out in the caller. */ + JS_ASSERT(!lhs->isType(JSVAL_TYPE_STRING) && !rhs->isType(JSVAL_TYPE_STRING)); + + /* Test the types. */ + if ((lhs->isTypeKnown() && !lhsInt) || (rhs->isTypeKnown() && !rhsInt)) { + stubcc.linkExit(masm.jump(), Uses(2)); + } else { + if (!lhsInt) { + Jump lhsFail = frame.testInt32(Assembler::NotEqual, lhs); + stubcc.linkExit(lhsFail, Uses(2)); + } + if (!rhsInt) { + Jump rhsFail = frame.testInt32(Assembler::NotEqual, rhs); + stubcc.linkExit(rhsFail, Uses(2)); + } + } + + stubcc.leave(); + OOL_STUBCALL(stub); + + RegisterID reg = frame.ownRegForData(lhs); + + /* x86/64's SET instruction can only take single-byte regs.*/ + RegisterID resultReg = reg; + if (!(Registers::maskReg(reg) & Registers::SingleByteRegs)) + resultReg = frame.allocReg(Registers::SingleByteRegs); + + /* Emit the compare & set. */ + if (rhs->isConstant()) { + masm.set32(cond, reg, Imm32(rhs->getValue().toInt32()), resultReg); + } else if (frame.shouldAvoidDataRemat(rhs)) { + masm.set32(cond, reg, + masm.payloadOf(frame.addressOf(rhs)), + resultReg); + } else { + masm.set32(cond, reg, frame.tempRegForData(rhs), resultReg); + } + + /* Clean up and push a boolean. */ + frame.pop(); + frame.pop(); + if (reg != resultReg) + frame.freeReg(reg); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, resultReg); + stubcc.rejoin(Changes(1)); + } + return true; +} + +/* + * Emit an OOL path for a possibly double LHS, and possibly int32 or number RHS. + */ +void +mjit::Compiler::emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc ®s, + MaybeJump &lhsNotDouble, MaybeJump &rhsNotNumber, + MaybeJump &lhsUnknownDone) +{ + FPRegisterID fpLeft = FPRegisters::First; + FPRegisterID fpRight = FPRegisters::Second; + + /* If the LHS is not a 32-bit integer, take OOL path. */ + Jump lhsNotInt32 = masm.testInt32(Assembler::NotEqual, regs.lhsType.reg()); + stubcc.linkExitDirect(lhsNotInt32, stubcc.masm.label()); + + /* OOL path for LHS as a double - first test LHS is double. */ + lhsNotDouble = stubcc.masm.testDouble(Assembler::NotEqual, regs.lhsType.reg()); + + /* Ensure the RHS is a number. */ + MaybeJump rhsIsDouble; + if (!rhs->isTypeKnown()) { + rhsIsDouble = stubcc.masm.testDouble(Assembler::Equal, regs.rhsType.reg()); + rhsNotNumber = stubcc.masm.testInt32(Assembler::NotEqual, regs.rhsType.reg()); + } + + /* If RHS is constant, convert now. */ + if (rhs->isConstant()) + slowLoadConstantDouble(stubcc.masm, rhs, fpRight); + else + stubcc.masm.convertInt32ToDouble(regs.rhsData.reg(), fpRight); + + if (!rhs->isTypeKnown()) { + /* Jump past double load, bind double type check. */ + Jump converted = stubcc.masm.jump(); + rhsIsDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm); + + /* Load the double. */ + frame.loadDouble(regs.rhsType.reg(), regs.rhsData.reg(), + rhs, fpRight, stubcc.masm); + + converted.linkTo(stubcc.masm.label(), &stubcc.masm); + } + + /* Load the LHS. */ + frame.loadDouble(regs.lhsType.reg(), regs.lhsData.reg(), + lhs, fpLeft, stubcc.masm); + lhsUnknownDone = stubcc.masm.jump(); +} + +/* + * Emit an OOL path for an integer LHS, possibly double RHS. + */ +void +mjit::Compiler::emitRightDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc ®s, + MaybeJump &rhsNotNumber2) +{ + FPRegisterID fpLeft = FPRegisters::First; + FPRegisterID fpRight = FPRegisters::Second; + + /* If the RHS is not a double, take OOL path. */ + Jump notInt32 = masm.testInt32(Assembler::NotEqual, regs.rhsType.reg()); + stubcc.linkExitDirect(notInt32, stubcc.masm.label()); + + /* Now test if RHS is a double. */ + rhsNotNumber2 = stubcc.masm.testDouble(Assembler::NotEqual, regs.rhsType.reg()); + + /* We know LHS is an integer. */ + if (lhs->isConstant()) + slowLoadConstantDouble(stubcc.masm, lhs, fpLeft); + else + stubcc.masm.convertInt32ToDouble(regs.lhsData.reg(), fpLeft); + + /* Load the RHS. */ + frame.loadDouble(regs.rhsType.reg(), regs.rhsData.reg(), + rhs, fpRight, stubcc.masm); +} + +static inline Assembler::DoubleCondition +DoubleCondForOp(JSOp op, JSOp fused) +{ + bool ifeq = fused == JSOP_IFEQ; + switch (op) { + case JSOP_GT: + return ifeq + ? Assembler::DoubleLessThanOrEqualOrUnordered + : Assembler::DoubleGreaterThan; + case JSOP_GE: + return ifeq + ? Assembler::DoubleLessThanOrUnordered + : Assembler::DoubleGreaterThanOrEqual; + case JSOP_LT: + return ifeq + ? Assembler::DoubleGreaterThanOrEqualOrUnordered + : Assembler::DoubleLessThan; + case JSOP_LE: + return ifeq + ? Assembler::DoubleGreaterThanOrUnordered + : Assembler::DoubleLessThanOrEqual; + default: + JS_NOT_REACHED("unrecognized op"); + return Assembler::DoubleLessThan; + } +} + +bool +mjit::Compiler::jsop_relational_double(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused) +{ + FrameEntry *rhs = frame.peek(-1); + FrameEntry *lhs = frame.peek(-2); + + FPRegisterID fpLeft = FPRegisters::First; + FPRegisterID fpRight = FPRegisters::Second; + + JS_ASSERT_IF(!target, fused != JSOP_IFEQ); + + MaybeJump lhsNotNumber = loadDouble(lhs, fpLeft); + MaybeJump rhsNotNumber = loadDouble(rhs, fpRight); + + Assembler::DoubleCondition dblCond = DoubleCondForOp(op, fused); + + if (target) { + if (lhsNotNumber.isSet()) + stubcc.linkExitForBranch(lhsNotNumber.get()); + if (rhsNotNumber.isSet()) + stubcc.linkExitForBranch(rhsNotNumber.get()); + stubcc.leave(); + OOL_STUBCALL(stub); + + frame.popn(2); + frame.syncAndForgetEverything(); + + Jump j = masm.branchDouble(dblCond, fpLeft, fpRight); + + /* + * The stub call has no need to rejoin since the state is synced. + * Instead, we can just test the return value. + */ + Assembler::Condition cond = (fused == JSOP_IFEQ) + ? Assembler::Zero + : Assembler::NonZero; + Jump sj = stubcc.masm.branchTest32(cond, Registers::ReturnReg, Registers::ReturnReg); + + /* Rejoin from the slow path. */ + Jump j2 = stubcc.masm.jump(); + stubcc.crossJump(j2, masm.label()); + + /* + * NB: jumpAndTrace emits to the OOL path, so make sure not to use it + * in the middle of an in-progress slow path. + */ + if (!jumpAndTrace(j, target, &sj)) + return false; + } else { + if (lhsNotNumber.isSet()) + stubcc.linkExit(lhsNotNumber.get(), Uses(2)); + if (rhsNotNumber.isSet()) + stubcc.linkExit(rhsNotNumber.get(), Uses(2)); + stubcc.leave(); + OOL_STUBCALL(stub); + + frame.popn(2); + + RegisterID reg = frame.allocReg(); + Jump j = masm.branchDouble(dblCond, fpLeft, fpRight); + masm.move(Imm32(0), reg); + Jump skip = masm.jump(); + j.linkTo(masm.label(), &masm); + masm.move(Imm32(1), reg); + skip.linkTo(masm.label(), &masm); + + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg); + + stubcc.rejoin(Changes(1)); + } + return true; +} + +bool +mjit::Compiler::jsop_relational_self(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused) +{ +#ifdef DEBUG + FrameEntry *rhs = frame.peek(-1); + FrameEntry *lhs = frame.peek(-2); + + JS_ASSERT(frame.haveSameBacking(lhs, rhs)); +#endif + + /* :TODO: optimize this? */ + return emitStubCmpOp(stub, target, fused); +} + +/* See jsop_binary_full() for more information on how this works. */ +bool +mjit::Compiler::jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused) +{ + FrameEntry *rhs = frame.peek(-1); + FrameEntry *lhs = frame.peek(-2); + + /* Allocate all registers up-front. */ + FrameState::BinaryAlloc regs; + frame.allocForBinary(lhs, rhs, op, regs, !target); + + FPRegisterID fpLeft = FPRegisters::First; + FPRegisterID fpRight = FPRegisters::Second; + + MaybeJump lhsNotDouble, rhsNotNumber, lhsUnknownDone; + if (!lhs->isTypeKnown()) + emitLeftDoublePath(lhs, rhs, regs, lhsNotDouble, rhsNotNumber, lhsUnknownDone); + + MaybeJump rhsNotNumber2; + if (!rhs->isTypeKnown()) + emitRightDoublePath(lhs, rhs, regs, rhsNotNumber2); + + /* Both double paths will join here. */ + bool hasDoublePath = false; + if (!rhs->isTypeKnown() || lhsUnknownDone.isSet()) + hasDoublePath = true; + + /* Integer path - figure out the immutable side. */ + JSOp cmpOp = op; + int32 value = 0; + RegisterID cmpReg; + MaybeRegisterID reg; + if (regs.lhsData.isSet()) { + cmpReg = regs.lhsData.reg(); + if (!regs.rhsData.isSet()) + value = rhs->getValue().toInt32(); + else + reg = regs.rhsData.reg(); + } else { + cmpReg = regs.rhsData.reg(); + value = lhs->getValue().toInt32(); + switch (op) { + case JSOP_GT: + cmpOp = JSOP_LT; + break; + case JSOP_GE: + cmpOp = JSOP_LE; + break; + case JSOP_LT: + cmpOp = JSOP_GT; + break; + case JSOP_LE: + cmpOp = JSOP_GE; + break; + default: + JS_NOT_REACHED("unrecognized op"); + break; + } + } + + /* + * Emit the actual comparisons. When a fusion is in play, it's faster to + * combine the comparison with the jump, so these two cases are implemented + * separately. + */ + + if (target) { + /* + * Emit the double path now, necessary to complete the OOL fast-path + * before emitting the slow path. + * + * Note: doubles have not been swapped yet. Use original op. + */ + MaybeJump doubleTest, doubleFall; + Assembler::DoubleCondition dblCond = DoubleCondForOp(op, fused); + if (hasDoublePath) { + if (lhsUnknownDone.isSet()) + lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm); + frame.sync(stubcc.masm, Uses(frame.frameSlots())); + doubleTest = stubcc.masm.branchDouble(dblCond, fpLeft, fpRight); + doubleFall = stubcc.masm.jump(); + + /* Link all incoming slow paths to here. */ + if (lhsNotDouble.isSet()) { + lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm); + if (rhsNotNumber.isSet()) + rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm); + } + if (rhsNotNumber2.isSet()) + rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm); + + /* + * For fusions, spill the tracker state. xmm* remain intact. Note + * that frame.sync() must be used directly, to avoid syncExit()'s + * jumping logic. + */ + frame.sync(stubcc.masm, Uses(frame.frameSlots())); + stubcc.leave(); + OOL_STUBCALL(stub); + } + + /* Forget the world, preserving data. */ + frame.pinReg(cmpReg); + if (reg.isSet()) + frame.pinReg(reg.reg()); + + frame.popn(2); + + frame.syncAndKillEverything(); + frame.unpinKilledReg(cmpReg); + if (reg.isSet()) + frame.unpinKilledReg(reg.reg()); + frame.syncAndForgetEverything(); + + /* Operands could have been reordered, so use cmpOp. */ + Assembler::Condition i32Cond; + bool ifeq = fused == JSOP_IFEQ; + switch (cmpOp) { + case JSOP_GT: + i32Cond = ifeq ? Assembler::LessThanOrEqual : Assembler::GreaterThan; + break; + case JSOP_GE: + i32Cond = ifeq ? Assembler::LessThan : Assembler::GreaterThanOrEqual; + break; + case JSOP_LT: + i32Cond = ifeq ? Assembler::GreaterThanOrEqual : Assembler::LessThan; + break; + case JSOP_LE: + i32Cond = ifeq ? Assembler::GreaterThan : Assembler::LessThanOrEqual; + break; + default: + JS_NOT_REACHED("unrecognized op"); + return false; + } + + /* Emit the i32 path. */ + Jump fast; + if (reg.isSet()) + fast = masm.branch32(i32Cond, cmpReg, reg.reg()); + else + fast = masm.branch32(i32Cond, cmpReg, Imm32(value)); + + /* + * The stub call has no need to rejoin since state is synced. Instead, + * we can just test the return value. + */ + Assembler::Condition cond = (fused == JSOP_IFEQ) + ? Assembler::Zero + : Assembler::NonZero; + Jump j = stubcc.masm.branchTest32(cond, Registers::ReturnReg, Registers::ReturnReg); + + /* Rejoin from the slow path. */ + Jump j2 = stubcc.masm.jump(); + stubcc.crossJump(j2, masm.label()); + + /* :TODO: make double path invoke tracer. */ + if (hasDoublePath) { + j.linkTo(stubcc.masm.label(), &stubcc.masm); + doubleTest.get().linkTo(stubcc.masm.label(), &stubcc.masm); + j = stubcc.masm.jump(); + } + + /* + * NB: jumpAndTrace emits to the OOL path, so make sure not to use it + * in the middle of an in-progress slow path. + */ + if (!jumpAndTrace(fast, target, &j)) + return false; + + /* Rejoin from the double path. */ + if (hasDoublePath) + stubcc.crossJump(doubleFall.get(), masm.label()); + } else { + /* + * Emit the double path now, necessary to complete the OOL fast-path + * before emitting the slow path. + */ + MaybeJump doubleDone; + Assembler::DoubleCondition dblCond = DoubleCondForOp(op, JSOP_NOP); + if (hasDoublePath) { + if (lhsUnknownDone.isSet()) + lhsUnknownDone.get().linkTo(stubcc.masm.label(), &stubcc.masm); + /* :FIXME: Use SET if we can? */ + Jump test = stubcc.masm.branchDouble(dblCond, fpLeft, fpRight); + stubcc.masm.move(Imm32(0), regs.result); + Jump skip = stubcc.masm.jump(); + test.linkTo(stubcc.masm.label(), &stubcc.masm); + stubcc.masm.move(Imm32(1), regs.result); + skip.linkTo(stubcc.masm.label(), &stubcc.masm); + doubleDone = stubcc.masm.jump(); + + /* Link all incoming slow paths to here. */ + if (lhsNotDouble.isSet()) { + lhsNotDouble.get().linkTo(stubcc.masm.label(), &stubcc.masm); + if (rhsNotNumber.isSet()) + rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm); + } + if (rhsNotNumber2.isSet()) + rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm); + + /* Emit the slow path - note full frame syncage. */ + frame.sync(stubcc.masm, Uses(2)); + stubcc.leave(); + OOL_STUBCALL(stub); + } + + /* Get an integer comparison condition. */ + Assembler::Condition i32Cond; + switch (cmpOp) { + case JSOP_GT: + i32Cond = Assembler::GreaterThan; + break; + case JSOP_GE: + i32Cond = Assembler::GreaterThanOrEqual; + break; + case JSOP_LT: + i32Cond = Assembler::LessThan; + break; + case JSOP_LE: + i32Cond = Assembler::LessThanOrEqual; + break; + default: + JS_NOT_REACHED("unrecognized op"); + return false; + } + + /* Emit the compare & set. */ + if (Registers::maskReg(regs.result) & Registers::SingleByteRegs) { + if (reg.isSet()) + masm.set32(i32Cond, cmpReg, reg.reg(), regs.result); + else + masm.set32(i32Cond, cmpReg, Imm32(value), regs.result); + } else { + Jump j; + if (reg.isSet()) + j = masm.branch32(i32Cond, cmpReg, reg.reg()); + else + j = masm.branch32(i32Cond, cmpReg, Imm32(value)); + masm.move(Imm32(0), regs.result); + Jump skip = masm.jump(); + j.linkTo(masm.label(), &masm); + masm.move(Imm32(1), regs.result); + skip.linkTo(masm.label(), &masm); + } + + frame.popn(2); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, regs.result); + + if (hasDoublePath) + stubcc.crossJump(doubleDone.get(), masm.label()); + stubcc.rejoin(Changes(1)); + } + return true; +} + diff --git a/js/src/methodjit/FastOps.cpp b/js/src/methodjit/FastOps.cpp new file mode 100644 index 0000000..7e1c5b1 --- /dev/null +++ b/js/src/methodjit/FastOps.cpp @@ -0,0 +1,1856 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "jsbool.h" +#include "jscntxt.h" +#include "jsemit.h" +#include "jslibmath.h" +#include "jsnum.h" +#include "jsscope.h" +#include "jsobjinlines.h" +#include "jsscriptinlines.h" + +#include "methodjit/MethodJIT.h" +#include "methodjit/Compiler.h" +#include "methodjit/StubCalls.h" +#include "methodjit/FrameState-inl.h" + +#include "jsautooplen.h" + +using namespace js; +using namespace js::mjit; + +typedef JSC::MacroAssembler::RegisterID RegisterID; + +RegisterID +mjit::Compiler::rightRegForShift(FrameEntry *rhs) +{ +#if defined(JS_CPU_X86) || defined(JS_CPU_X64) + /* + * Gross: RHS _must_ be in ECX, on x86. + * Note that we take this first so that we can't up with other register + * allocations (below) owning ecx before rhs. + */ + RegisterID reg = JSC::X86Registers::ecx; + if (!rhs->isConstant()) + frame.copyDataIntoReg(rhs, reg); + return reg; +#else + if (rhs->isConstant()) + return frame.allocReg(); + return frame.copyDataIntoReg(rhs); +#endif +} + +void +mjit::Compiler::jsop_rsh_const_int(FrameEntry *lhs, FrameEntry *rhs) +{ + RegisterID rhsData = rightRegForShift(rhs); + RegisterID result = frame.allocReg(); + masm.move(Imm32(lhs->getValue().toInt32()), result); + masm.rshift32(rhsData, result); + + frame.freeReg(rhsData); + frame.popn(2); + frame.pushTypedPayload(JSVAL_TYPE_INT32, result); +} + +void +mjit::Compiler::jsop_rsh_int_int(FrameEntry *lhs, FrameEntry *rhs) +{ + RegisterID rhsData = rightRegForShift(rhs); + RegisterID lhsData = frame.copyDataIntoReg(lhs); + masm.rshift32(rhsData, lhsData); + frame.freeReg(rhsData); + frame.popn(2); + frame.pushTypedPayload(JSVAL_TYPE_INT32, lhsData); +} + +void +mjit::Compiler::jsop_rsh_int_const(FrameEntry *lhs, FrameEntry *rhs) +{ + int32 shiftAmount = rhs->getValue().toInt32(); + + if (!shiftAmount) { + frame.pop(); + return; + } + + RegisterID result = frame.copyDataIntoReg(lhs); + masm.rshift32(Imm32(shiftAmount), result); + frame.popn(2); + frame.pushTypedPayload(JSVAL_TYPE_INT32, result); +} + +void +mjit::Compiler::jsop_rsh_unknown_const(FrameEntry *lhs, FrameEntry *rhs) +{ + int32 shiftAmount = rhs->getValue().toInt32(); + + RegisterID lhsType = frame.tempRegForType(lhs); + frame.pinReg(lhsType); + RegisterID lhsData = frame.copyDataIntoReg(lhs); + frame.unpinReg(lhsType); + + Jump lhsIntGuard = masm.testInt32(Assembler::NotEqual, lhsType); + stubcc.linkExitDirect(lhsIntGuard, stubcc.masm.label()); + + Jump lhsDoubleGuard = stubcc.masm.testDouble(Assembler::NotEqual, lhsType); + frame.loadDouble(lhs, FPRegisters::First, stubcc.masm); + Jump lhsTruncateGuard = stubcc.masm.branchTruncateDoubleToInt32(FPRegisters::First, lhsData); + stubcc.crossJump(stubcc.masm.jump(), masm.label()); + + lhsDoubleGuard.linkTo(stubcc.masm.label(), &stubcc.masm); + lhsTruncateGuard.linkTo(stubcc.masm.label(), &stubcc.masm); + + frame.sync(stubcc.masm, Uses(2)); + OOL_STUBCALL(stubs::Rsh); + + if (shiftAmount) + masm.rshift32(Imm32(shiftAmount), lhsData); + + frame.popn(2); + frame.pushTypedPayload(JSVAL_TYPE_INT32, lhsData); + + stubcc.rejoin(Changes(1)); +} + +void +mjit::Compiler::jsop_rsh_const_unknown(FrameEntry *lhs, FrameEntry *rhs) +{ + RegisterID rhsData = rightRegForShift(rhs); + RegisterID rhsType = frame.tempRegForType(rhs); + frame.pinReg(rhsType); + RegisterID result = frame.allocReg(); + frame.unpinReg(rhsType); + + Jump rhsIntGuard = masm.testInt32(Assembler::NotEqual, rhsType); + stubcc.linkExit(rhsIntGuard, Uses(2)); + stubcc.leave(); + OOL_STUBCALL(stubs::Rsh); + masm.move(Imm32(lhs->getValue().toInt32()), result); + masm.rshift32(rhsData, result); + frame.freeReg(rhsData); + + frame.popn(2); + frame.pushTypedPayload(JSVAL_TYPE_INT32, result); + stubcc.rejoin(Changes(1)); +} + +void +mjit::Compiler::jsop_rsh_int_unknown(FrameEntry *lhs, FrameEntry *rhs) +{ + RegisterID rhsData = rightRegForShift(rhs); + RegisterID rhsType = frame.tempRegForType(rhs); + frame.pinReg(rhsType); + RegisterID lhsData = frame.copyDataIntoReg(lhs); + frame.unpinReg(rhsType); + + Jump rhsIntGuard = masm.testInt32(Assembler::NotEqual, rhsType); + stubcc.linkExit(rhsIntGuard, Uses(2)); + stubcc.leave(); + OOL_STUBCALL(stubs::Rsh); + + masm.rshift32(rhsData, lhsData); + frame.freeReg(rhsData); + frame.popn(2); + frame.pushTypedPayload(JSVAL_TYPE_INT32, lhsData); + + stubcc.rejoin(Changes(1)); +} + +void +mjit::Compiler::jsop_rsh_unknown_any(FrameEntry *lhs, FrameEntry *rhs) +{ + JS_ASSERT(!lhs->isTypeKnown()); + JS_ASSERT(!rhs->isNotType(JSVAL_TYPE_INT32)); + + /* Allocate registers. */ + RegisterID rhsData = rightRegForShift(rhs); + + MaybeRegisterID rhsType; + if (!rhs->isTypeKnown()) { + rhsType.setReg(frame.tempRegForType(rhs)); + frame.pinReg(rhsType.reg()); + } + + RegisterID lhsData = frame.copyDataIntoReg(lhs); + MaybeRegisterID lhsType; + if (rhsType.isSet() && frame.haveSameBacking(lhs, rhs)) + lhsType = rhsType; + else + lhsType = frame.tempRegForType(lhs); + + /* Non-integer rhs jumps to stub. */ + MaybeJump rhsIntGuard; + if (rhsType.isSet()) { + rhsIntGuard.setJump(masm.testInt32(Assembler::NotEqual, rhsType.reg())); + frame.unpinReg(rhsType.reg()); + } + + /* Non-integer lhs jumps to double guard. */ + Jump lhsIntGuard = masm.testInt32(Assembler::NotEqual, lhsType.reg()); + stubcc.linkExitDirect(lhsIntGuard, stubcc.masm.label()); + + /* Attempt to convert lhs double to int32. */ + Jump lhsDoubleGuard = stubcc.masm.testDouble(Assembler::NotEqual, lhsType.reg()); + frame.loadDouble(lhs, FPRegisters::First, stubcc.masm); + Jump lhsTruncateGuard = stubcc.masm.branchTruncateDoubleToInt32(FPRegisters::First, lhsData); + stubcc.crossJump(stubcc.masm.jump(), masm.label()); + + lhsDoubleGuard.linkTo(stubcc.masm.label(), &stubcc.masm); + lhsTruncateGuard.linkTo(stubcc.masm.label(), &stubcc.masm); + + if (rhsIntGuard.isSet()) + stubcc.linkExitDirect(rhsIntGuard.getJump(), stubcc.masm.label()); + frame.sync(stubcc.masm, Uses(2)); + OOL_STUBCALL(stubs::Rsh); + + masm.rshift32(rhsData, lhsData); + + frame.freeReg(rhsData); + frame.popn(2); + frame.pushTypedPayload(JSVAL_TYPE_INT32, lhsData); + + stubcc.rejoin(Changes(1)); +} + +void +mjit::Compiler::jsop_rsh() +{ + FrameEntry *rhs = frame.peek(-1); + FrameEntry *lhs = frame.peek(-2); + + if (tryBinaryConstantFold(cx, frame, JSOP_RSH, lhs, rhs)) + return; + + if (lhs->isNotType(JSVAL_TYPE_INT32) || rhs->isNotType(JSVAL_TYPE_INT32)) { + prepareStubCall(Uses(2)); + INLINE_STUBCALL(stubs::Rsh); + frame.popn(2); + frame.pushSyncedType(JSVAL_TYPE_INT32); + return; + } + + JS_ASSERT(!(lhs->isConstant() && rhs->isConstant())); + if (lhs->isConstant()) { + if (rhs->isType(JSVAL_TYPE_INT32)) + jsop_rsh_const_int(lhs, rhs); + else + jsop_rsh_const_unknown(lhs, rhs); + } else if (rhs->isConstant()) { + if (lhs->isType(JSVAL_TYPE_INT32)) + jsop_rsh_int_const(lhs, rhs); + else + jsop_rsh_unknown_const(lhs, rhs); + } else { + if (lhs->isType(JSVAL_TYPE_INT32) && rhs->isType(JSVAL_TYPE_INT32)) + jsop_rsh_int_int(lhs, rhs); + else if (lhs->isType(JSVAL_TYPE_INT32)) + jsop_rsh_int_unknown(lhs, rhs); + else + jsop_rsh_unknown_any(lhs, rhs); + } +} + +void +mjit::Compiler::jsop_bitnot() +{ + FrameEntry *top = frame.peek(-1); + + /* We only want to handle integers here. */ + if (top->isTypeKnown() && top->getKnownType() != JSVAL_TYPE_INT32) { + prepareStubCall(Uses(1)); + INLINE_STUBCALL(stubs::BitNot); + frame.pop(); + frame.pushSyncedType(JSVAL_TYPE_INT32); + return; + } + + /* Test the type. */ + bool stubNeeded = false; + if (!top->isTypeKnown()) { + Jump intFail = frame.testInt32(Assembler::NotEqual, top); + stubcc.linkExit(intFail, Uses(1)); + frame.learnType(top, JSVAL_TYPE_INT32); + stubNeeded = true; + } + + if (stubNeeded) { + stubcc.leave(); + OOL_STUBCALL(stubs::BitNot); + } + + RegisterID reg = frame.ownRegForData(top); + masm.not32(reg); + frame.pop(); + frame.pushTypedPayload(JSVAL_TYPE_INT32, reg); + + if (stubNeeded) + stubcc.rejoin(Changes(1)); +} + +void +mjit::Compiler::jsop_bitop(JSOp op) +{ + FrameEntry *rhs = frame.peek(-1); + FrameEntry *lhs = frame.peek(-2); + + VoidStub stub; + switch (op) { + case JSOP_BITOR: + stub = stubs::BitOr; + break; + case JSOP_BITAND: + stub = stubs::BitAnd; + break; + case JSOP_BITXOR: + stub = stubs::BitXor; + break; + case JSOP_LSH: + stub = stubs::Lsh; + break; + case JSOP_URSH: + stub = stubs::Ursh; + break; + default: + JS_NOT_REACHED("wat"); + return; + } + + bool lhsIntOrDouble = !(lhs->isNotType(JSVAL_TYPE_DOUBLE) && + lhs->isNotType(JSVAL_TYPE_INT32)); + + /* Fast-path double to int conversion. */ + if (!lhs->isConstant() && rhs->isConstant() && lhsIntOrDouble && + rhs->isType(JSVAL_TYPE_INT32) && rhs->getValue().toInt32() == 0 && + (op == JSOP_BITOR || op == JSOP_LSH)) { + RegisterID reg = frame.copyDataIntoReg(lhs); + if (lhs->isType(JSVAL_TYPE_INT32)) { + frame.popn(2); + frame.pushTypedPayload(JSVAL_TYPE_INT32, reg); + return; + } + MaybeJump isInt; + if (!lhs->isType(JSVAL_TYPE_DOUBLE)) { + RegisterID typeReg = frame.tempRegForType(lhs); + isInt = masm.testInt32(Assembler::Equal, typeReg); + Jump notDouble = masm.testDouble(Assembler::NotEqual, typeReg); + stubcc.linkExit(notDouble, Uses(2)); + } + frame.loadDouble(lhs, FPRegisters::First, masm); + + Jump truncateGuard = masm.branchTruncateDoubleToInt32(FPRegisters::First, reg); + stubcc.linkExit(truncateGuard, Uses(2)); + stubcc.leave(); + OOL_STUBCALL(stub); + + if (isInt.isSet()) + isInt.get().linkTo(masm.label(), &masm); + frame.popn(2); + frame.pushTypedPayload(JSVAL_TYPE_INT32, reg); + stubcc.rejoin(Changes(1)); + return; + } + + /* We only want to handle integers here. */ + if (rhs->isNotType(JSVAL_TYPE_INT32) || lhs->isNotType(JSVAL_TYPE_INT32) || + (op == JSOP_URSH && rhs->isConstant() && rhs->getValue().toInt32() % 32 == 0)) { + prepareStubCall(Uses(2)); + INLINE_STUBCALL(stub); + frame.popn(2); + if (op == JSOP_URSH) + frame.pushSynced(); + else + frame.pushSyncedType(JSVAL_TYPE_INT32); + return; + } + + /* Test the types. */ + bool stubNeeded = false; + if (!rhs->isTypeKnown()) { + Jump rhsFail = frame.testInt32(Assembler::NotEqual, rhs); + stubcc.linkExit(rhsFail, Uses(2)); + frame.learnType(rhs, JSVAL_TYPE_INT32); + stubNeeded = true; + } + if (!lhs->isTypeKnown() && !frame.haveSameBacking(lhs, rhs)) { + Jump lhsFail = frame.testInt32(Assembler::NotEqual, lhs); + stubcc.linkExit(lhsFail, Uses(2)); + stubNeeded = true; + } + + if (lhs->isConstant() && rhs->isConstant()) { + int32 L = lhs->getValue().toInt32(); + int32 R = rhs->getValue().toInt32(); + + frame.popn(2); + switch (op) { + case JSOP_BITOR: + frame.push(Int32Value(L | R)); + return; + case JSOP_BITXOR: + frame.push(Int32Value(L ^ R)); + return; + case JSOP_BITAND: + frame.push(Int32Value(L & R)); + return; + case JSOP_LSH: + frame.push(Int32Value(L << R)); + return; + case JSOP_URSH: + { + uint32 unsignedL; + if (ValueToECMAUint32(cx, lhs->getValue(), (uint32_t*)&unsignedL)) { + frame.push(NumberValue(uint32(unsignedL >> (R & 31)))); + return; + } + break; + } + default: + JS_NOT_REACHED("say wat"); + } + } + + RegisterID reg; + + switch (op) { + case JSOP_BITOR: + case JSOP_BITXOR: + case JSOP_BITAND: + { + /* Commutative, and we're guaranteed both are ints. */ + if (lhs->isConstant()) { + JS_ASSERT(!rhs->isConstant()); + FrameEntry *temp = rhs; + rhs = lhs; + lhs = temp; + } + + reg = frame.ownRegForData(lhs); + if (rhs->isConstant()) { + if (op == JSOP_BITAND) + masm.and32(Imm32(rhs->getValue().toInt32()), reg); + else if (op == JSOP_BITXOR) + masm.xor32(Imm32(rhs->getValue().toInt32()), reg); + else + masm.or32(Imm32(rhs->getValue().toInt32()), reg); + } else if (frame.shouldAvoidDataRemat(rhs)) { + if (op == JSOP_BITAND) + masm.and32(masm.payloadOf(frame.addressOf(rhs)), reg); + else if (op == JSOP_BITXOR) + masm.xor32(masm.payloadOf(frame.addressOf(rhs)), reg); + else + masm.or32(masm.payloadOf(frame.addressOf(rhs)), reg); + } else { + RegisterID rhsReg = frame.tempRegForData(rhs); + if (op == JSOP_BITAND) + masm.and32(rhsReg, reg); + else if (op == JSOP_BITXOR) + masm.xor32(rhsReg, reg); + else + masm.or32(rhsReg, reg); + } + + break; + } + + case JSOP_LSH: + case JSOP_URSH: + { + /* Not commutative. */ + if (rhs->isConstant()) { + RegisterID reg = frame.ownRegForData(lhs); + int shift = rhs->getValue().toInt32() & 0x1F; + + if (shift) { + if (op == JSOP_LSH) + masm.lshift32(Imm32(shift), reg); + else + masm.urshift32(Imm32(shift), reg); + } + if (stubNeeded) { + stubcc.leave(); + OOL_STUBCALL(stub); + } + frame.popn(2); + + /* x >>> 0 may result in a double, handled above. */ + JS_ASSERT_IF(op == JSOP_URSH, shift >= 1); + frame.pushTypedPayload(JSVAL_TYPE_INT32, reg); + + if (stubNeeded) + stubcc.rejoin(Changes(1)); + + return; + } +#if defined(JS_CPU_X86) || defined(JS_CPU_X64) + /* Grosssssss! RHS _must_ be in ECX, on x86 */ + RegisterID rr = frame.tempRegInMaskForData(rhs, + Registers::maskReg(JSC::X86Registers::ecx)); +#else + RegisterID rr = frame.tempRegForData(rhs); +#endif + + if (frame.haveSameBacking(lhs, rhs)) { + // It's okay to allocReg(). If |rr| is evicted, it won't result in + // a load, and |rr == reg| is fine since this is (x << x). + reg = frame.allocReg(); + if (rr != reg) + masm.move(rr, reg); + } else { + frame.pinReg(rr); + if (lhs->isConstant()) { + reg = frame.allocReg(); + masm.move(Imm32(lhs->getValue().toInt32()), reg); + } else { + reg = frame.copyDataIntoReg(lhs); + } + frame.unpinReg(rr); + } + + if (op == JSOP_LSH) { + masm.lshift32(rr, reg); + } else { + masm.urshift32(rr, reg); + + Jump isNegative = masm.branch32(Assembler::LessThan, reg, Imm32(0)); + stubcc.linkExit(isNegative, Uses(2)); + stubNeeded = true; + } + break; + } + + default: + JS_NOT_REACHED("NYI"); + return; + } + + if (stubNeeded) { + stubcc.leave(); + OOL_STUBCALL(stub); + } + + frame.pop(); + frame.pop(); + + if (op == JSOP_URSH) + frame.pushNumber(reg, true); + else + frame.pushTypedPayload(JSVAL_TYPE_INT32, reg); + + if (stubNeeded) + stubcc.rejoin(Changes(1)); +} + +static inline bool +CheckNullOrUndefined(FrameEntry *fe) +{ + if (!fe->isTypeKnown()) + return false; + JSValueType type = fe->getKnownType(); + return type == JSVAL_TYPE_NULL || type == JSVAL_TYPE_UNDEFINED; +} + +bool +mjit::Compiler::jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused) +{ + FrameEntry *rhs = frame.peek(-1); + FrameEntry *lhs = frame.peek(-2); + + /* The compiler should have handled constant folding. */ + JS_ASSERT(!(rhs->isConstant() && lhs->isConstant())); + + bool lhsTest; + if ((lhsTest = CheckNullOrUndefined(lhs)) || CheckNullOrUndefined(rhs)) { + /* What's the other mask? */ + FrameEntry *test = lhsTest ? rhs : lhs; + + if (test->isTypeKnown()) + return emitStubCmpOp(stub, target, fused); + + /* The other side must be null or undefined. */ + RegisterID reg = frame.ownRegForType(test); + frame.pop(); + frame.pop(); + + /* + * :FIXME: Easier test for undefined || null? + * Maybe put them next to each other, subtract, do a single compare? + */ + + if (target) { + frame.syncAndForgetEverything(); + + if ((op == JSOP_EQ && fused == JSOP_IFNE) || + (op == JSOP_NE && fused == JSOP_IFEQ)) { + /* + * It would be easier to just have two jumpAndTrace calls here, but since + * each jumpAndTrace creates a TRACE IC, and since we want the bytecode + * to have a reference to the TRACE IC at the top of the loop, it's much + * better to have only one TRACE IC per loop, and hence at most one + * jumpAndTrace. + */ + Jump b1 = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_UNDEFINED)); + Jump b2 = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_NULL)); + Jump j1 = masm.jump(); + b1.linkTo(masm.label(), &masm); + b2.linkTo(masm.label(), &masm); + Jump j2 = masm.jump(); + if (!jumpAndTrace(j2, target)) + return false; + j1.linkTo(masm.label(), &masm); + } else { + Jump j = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_UNDEFINED)); + Jump j2 = masm.branchPtr(Assembler::NotEqual, reg, ImmType(JSVAL_TYPE_NULL)); + if (!jumpAndTrace(j2, target)) + return false; + j.linkTo(masm.label(), &masm); + } + } else { + Jump j = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_UNDEFINED)); + Jump j2 = masm.branchPtr(Assembler::Equal, reg, ImmType(JSVAL_TYPE_NULL)); + masm.move(Imm32(op == JSOP_NE), reg); + Jump j3 = masm.jump(); + j2.linkTo(masm.label(), &masm); + j.linkTo(masm.label(), &masm); + masm.move(Imm32(op == JSOP_EQ), reg); + j3.linkTo(masm.label(), &masm); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg); + } + return true; + } + + return emitStubCmpOp(stub, target, fused); +} + +bool +mjit::Compiler::jsop_relational(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused) +{ + FrameEntry *rhs = frame.peek(-1); + FrameEntry *lhs = frame.peek(-2); + + /* The compiler should have handled constant folding. */ + JS_ASSERT(!(rhs->isConstant() && lhs->isConstant())); + + /* Always slow path... */ + if ((lhs->isNotType(JSVAL_TYPE_INT32) && lhs->isNotType(JSVAL_TYPE_DOUBLE) && + lhs->isNotType(JSVAL_TYPE_STRING)) || + (rhs->isNotType(JSVAL_TYPE_INT32) && rhs->isNotType(JSVAL_TYPE_DOUBLE) && + rhs->isNotType(JSVAL_TYPE_STRING))) { + if (op == JSOP_EQ || op == JSOP_NE) + return jsop_equality(op, stub, target, fused); + return emitStubCmpOp(stub, target, fused); + } + + if (op == JSOP_EQ || op == JSOP_NE) { + if ((lhs->isNotType(JSVAL_TYPE_INT32) && lhs->isNotType(JSVAL_TYPE_STRING)) || + (rhs->isNotType(JSVAL_TYPE_INT32) && rhs->isNotType(JSVAL_TYPE_STRING))) { + return emitStubCmpOp(stub, target, fused); + } else if (!target && (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING))) { + return emitStubCmpOp(stub, target, fused); + } else if (frame.haveSameBacking(lhs, rhs)) { + return emitStubCmpOp(stub, target, fused); + } else { + return jsop_equality_int_string(op, stub, target, fused); + } + } + + if (frame.haveSameBacking(lhs, rhs)) { + return jsop_relational_self(op, stub, target, fused); + } else if (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING)) { + return emitStubCmpOp(stub, target, fused); + } else if (lhs->isType(JSVAL_TYPE_DOUBLE) || rhs->isType(JSVAL_TYPE_DOUBLE)) { + return jsop_relational_double(op, stub, target, fused); + } else { + return jsop_relational_full(op, stub, target, fused); + } +} + +void +mjit::Compiler::jsop_not() +{ + FrameEntry *top = frame.peek(-1); + + if (top->isConstant()) { + const Value &v = top->getValue(); + frame.pop(); + frame.push(BooleanValue(!js_ValueToBoolean(v))); + return; + } + + if (top->isTypeKnown()) { + JSValueType type = top->getKnownType(); + switch (type) { + case JSVAL_TYPE_INT32: + { + RegisterID data = frame.allocReg(Registers::SingleByteRegs); + if (frame.shouldAvoidDataRemat(top)) + masm.loadPayload(frame.addressOf(top), data); + else + masm.move(frame.tempRegForData(top), data); + + masm.set32(Assembler::Equal, data, Imm32(0), data); + + frame.pop(); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, data); + break; + } + + case JSVAL_TYPE_BOOLEAN: + { + RegisterID reg = frame.ownRegForData(top); + + masm.xor32(Imm32(1), reg); + + frame.pop(); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg); + break; + } + + case JSVAL_TYPE_OBJECT: + { + frame.pop(); + frame.push(BooleanValue(false)); + break; + } + + default: + { + prepareStubCall(Uses(1)); + INLINE_STUBCALL(stubs::ValueToBoolean); + + RegisterID reg = Registers::ReturnReg; + frame.takeReg(reg); + masm.xor32(Imm32(1), reg); + + frame.pop(); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg); + break; + } + } + + return; + } + + RegisterID data = frame.allocReg(Registers::SingleByteRegs); + if (frame.shouldAvoidDataRemat(top)) + masm.loadPayload(frame.addressOf(top), data); + else + masm.move(frame.tempRegForData(top), data); + RegisterID type = frame.tempRegForType(top); + Label syncTarget = stubcc.syncExitAndJump(Uses(1)); + + + /* Inline path is for booleans. */ + Jump jmpNotBool = masm.testBoolean(Assembler::NotEqual, type); + masm.xor32(Imm32(1), data); + + + /* OOL path is for int + object. */ + Label lblMaybeInt32 = stubcc.masm.label(); + + Jump jmpNotInt32 = stubcc.masm.testInt32(Assembler::NotEqual, type); + stubcc.masm.set32(Assembler::Equal, data, Imm32(0), data); + Jump jmpInt32Exit = stubcc.masm.jump(); + + Label lblMaybeObject = stubcc.masm.label(); + Jump jmpNotObject = stubcc.masm.testPrimitive(Assembler::Equal, type); + stubcc.masm.move(Imm32(0), data); + Jump jmpObjectExit = stubcc.masm.jump(); + + + /* Rejoin location. */ + Label lblRejoin = masm.label(); + + /* Patch up jumps. */ + stubcc.linkExitDirect(jmpNotBool, lblMaybeInt32); + + jmpNotInt32.linkTo(lblMaybeObject, &stubcc.masm); + stubcc.crossJump(jmpInt32Exit, lblRejoin); + + jmpNotObject.linkTo(syncTarget, &stubcc.masm); + stubcc.crossJump(jmpObjectExit, lblRejoin); + + + /* Leave. */ + stubcc.leave(); + OOL_STUBCALL(stubs::Not); + + frame.pop(); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, data); + + stubcc.rejoin(Changes(1)); +} + +void +mjit::Compiler::jsop_typeof() +{ + FrameEntry *fe = frame.peek(-1); + + if (fe->isTypeKnown()) { + JSRuntime *rt = cx->runtime; + + JSAtom *atom = NULL; + switch (fe->getKnownType()) { + case JSVAL_TYPE_STRING: + atom = rt->atomState.typeAtoms[JSTYPE_STRING]; + break; + case JSVAL_TYPE_UNDEFINED: + atom = rt->atomState.typeAtoms[JSTYPE_VOID]; + break; + case JSVAL_TYPE_NULL: + atom = rt->atomState.typeAtoms[JSTYPE_OBJECT]; + break; + case JSVAL_TYPE_OBJECT: + atom = NULL; + break; + case JSVAL_TYPE_BOOLEAN: + atom = rt->atomState.typeAtoms[JSTYPE_BOOLEAN]; + break; + default: + atom = rt->atomState.typeAtoms[JSTYPE_NUMBER]; + break; + } + + if (atom) { + frame.pop(); + frame.push(StringValue(ATOM_TO_STRING(atom))); + return; + } + } + + JSOp fused = JSOp(PC[JSOP_TYPEOF_LENGTH]); + if (fused == JSOP_STRING && !fe->isTypeKnown()) { + JSOp op = JSOp(PC[JSOP_TYPEOF_LENGTH + JSOP_STRING_LENGTH]); + + if (op == JSOP_STRICTEQ || op == JSOP_EQ || op == JSOP_STRICTNE || op == JSOP_NE) { + JSAtom *atom = script->getAtom(fullAtomIndex(PC + JSOP_TYPEOF_LENGTH)); + JSRuntime *rt = cx->runtime; + JSValueType type = JSVAL_TYPE_BOXED; + Assembler::Condition cond = (op == JSOP_STRICTEQ || op == JSOP_EQ) + ? Assembler::Equal + : Assembler::NotEqual; + + if (atom == rt->atomState.typeAtoms[JSTYPE_VOID]) { + type = JSVAL_TYPE_UNDEFINED; + } else if (atom == rt->atomState.typeAtoms[JSTYPE_STRING]) { + type = JSVAL_TYPE_STRING; + } else if (atom == rt->atomState.typeAtoms[JSTYPE_BOOLEAN]) { + type = JSVAL_TYPE_BOOLEAN; + } else if (atom == rt->atomState.typeAtoms[JSTYPE_NUMBER]) { + type = JSVAL_TYPE_INT32; + + /* JSVAL_TYPE_DOUBLE is 0x0 and JSVAL_TYPE_INT32 is 0x1, use <= or > to match both */ + cond = (cond == Assembler::Equal) ? Assembler::BelowOrEqual : Assembler::Above; + } + + if (type != JSVAL_TYPE_BOXED) { + PC += JSOP_STRING_LENGTH;; + PC += JSOP_EQ_LENGTH; + + RegisterID result = frame.allocReg(Registers::SingleByteRegs); + +#if defined JS_NUNBOX32 + if (frame.shouldAvoidTypeRemat(fe)) + masm.set32(cond, masm.tagOf(frame.addressOf(fe)), ImmType(type), result); + else + masm.set32(cond, frame.tempRegForType(fe), ImmType(type), result); +#elif defined JS_PUNBOX64 + masm.setPtr(cond, frame.tempRegForType(fe), ImmType(type), result); +#endif + + frame.pop(); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result); + return; + } + } + } + + prepareStubCall(Uses(1)); + INLINE_STUBCALL(stubs::TypeOf); + frame.pop(); + frame.takeReg(Registers::ReturnReg); + frame.pushTypedPayload(JSVAL_TYPE_STRING, Registers::ReturnReg); +} + +bool +mjit::Compiler::booleanJumpScript(JSOp op, jsbytecode *target) +{ + FrameEntry *fe = frame.peek(-1); + + MaybeRegisterID type; + MaybeRegisterID data; + + if (!fe->isTypeKnown() && !frame.shouldAvoidTypeRemat(fe)) + type.setReg(frame.copyTypeIntoReg(fe)); + data.setReg(frame.copyDataIntoReg(fe)); + + frame.syncAndForgetEverything(); + + Assembler::Condition cond = (op == JSOP_IFNE || op == JSOP_OR) + ? Assembler::NonZero + : Assembler::Zero; + Assembler::Condition ncond = (op == JSOP_IFNE || op == JSOP_OR) + ? Assembler::Zero + : Assembler::NonZero; + + /* Inline path: Boolean guard + call script. */ + MaybeJump jmpNotBool; + MaybeJump jmpNotExecScript; + if (type.isSet()) { + jmpNotBool.setJump(masm.testBoolean(Assembler::NotEqual, type.reg())); + } else { + if (!fe->isTypeKnown()) { + jmpNotBool.setJump(masm.testBoolean(Assembler::NotEqual, + frame.addressOf(fe))); + } else if (fe->isNotType(JSVAL_TYPE_BOOLEAN) && + fe->isNotType(JSVAL_TYPE_INT32)) { + jmpNotBool.setJump(masm.jump()); + } + } + + /* + * TODO: We don't need the second jump if + * jumpInScript() can go from ool path to inline path. + */ + jmpNotExecScript.setJump(masm.branchTest32(ncond, data.reg(), data.reg())); + Label lblExecScript = masm.label(); + Jump j = masm.jump(); + + + /* OOL path: Conversion to boolean. */ + MaybeJump jmpCvtExecScript; + MaybeJump jmpCvtRejoin; + Label lblCvtPath = stubcc.masm.label(); + + if (!fe->isTypeKnown() || + !(fe->isType(JSVAL_TYPE_BOOLEAN) || fe->isType(JSVAL_TYPE_INT32))) { + stubcc.masm.infallibleVMCall(JS_FUNC_TO_DATA_PTR(void *, stubs::ValueToBoolean), + frame.localSlots()); + + jmpCvtExecScript.setJump(stubcc.masm.branchTest32(cond, Registers::ReturnReg, + Registers::ReturnReg)); + jmpCvtRejoin.setJump(stubcc.masm.jump()); + } + + /* Rejoin tag. */ + Label lblAfterScript = masm.label(); + + /* Patch up jumps. */ + if (jmpNotBool.isSet()) + stubcc.linkExitDirect(jmpNotBool.getJump(), lblCvtPath); + if (jmpNotExecScript.isSet()) + jmpNotExecScript.getJump().linkTo(lblAfterScript, &masm); + + if (jmpCvtExecScript.isSet()) + stubcc.crossJump(jmpCvtExecScript.getJump(), lblExecScript); + if (jmpCvtRejoin.isSet()) + stubcc.crossJump(jmpCvtRejoin.getJump(), lblAfterScript); + + frame.pop(); + + return jumpAndTrace(j, target); +} + +bool +mjit::Compiler::jsop_ifneq(JSOp op, jsbytecode *target) +{ + FrameEntry *fe = frame.peek(-1); + + if (fe->isConstant()) { + JSBool b = js_ValueToBoolean(fe->getValue()); + + frame.pop(); + + if (op == JSOP_IFEQ) + b = !b; + if (b) { + frame.syncAndForgetEverything(); + if (!jumpAndTrace(masm.jump(), target)) + return false; + } + return true; + } + + return booleanJumpScript(op, target); +} + +bool +mjit::Compiler::jsop_andor(JSOp op, jsbytecode *target) +{ + FrameEntry *fe = frame.peek(-1); + + if (fe->isConstant()) { + JSBool b = js_ValueToBoolean(fe->getValue()); + + /* Short-circuit. */ + if ((op == JSOP_OR && b == JS_TRUE) || + (op == JSOP_AND && b == JS_FALSE)) { + frame.syncAndForgetEverything(); + if (!jumpAndTrace(masm.jump(), target)) + return false; + } + + frame.pop(); + return true; + } + + return booleanJumpScript(op, target); +} + +void +mjit::Compiler::jsop_localinc(JSOp op, uint32 slot, bool popped) +{ + if (popped || (op == JSOP_INCLOCAL || op == JSOP_DECLOCAL)) { + int amt = (op == JSOP_LOCALINC || op == JSOP_INCLOCAL) ? -1 : 1; + + // Before: + // After: V + frame.pushLocal(slot); + + // Before: V + // After: V 1 + frame.push(Int32Value(amt)); + + // Note, SUB will perform integer conversion for us. + // Before: V 1 + // After: N+1 + jsop_binary(JSOP_SUB, stubs::Sub); + + // Before: N+1 + // After: N+1 + frame.storeLocal(slot, popped); + + if (popped) + frame.pop(); + } else { + int amt = (op == JSOP_LOCALINC || op == JSOP_INCLOCAL) ? 1 : -1; + + // Before: + // After: V + frame.pushLocal(slot); + + // Before: V + // After: N + jsop_pos(); + + // Before: N + // After: N N + frame.dup(); + + // Before: N N + // After: N N 1 + frame.push(Int32Value(amt)); + + // Before: N N 1 + // After: N N+1 + jsop_binary(JSOP_ADD, stubs::Add); + + // Before: N N+1 + // After: N N+1 + frame.storeLocal(slot, true); + + // Before: N N+1 + // After: N + frame.pop(); + } +} + +void +mjit::Compiler::jsop_arginc(JSOp op, uint32 slot, bool popped) +{ + if (popped || (op == JSOP_INCARG || op == JSOP_DECARG)) { + int amt = (op == JSOP_ARGINC || op == JSOP_INCARG) ? -1 : 1; + + // Before: + // After: V + frame.pushArg(slot); + + // Before: V + // After: V 1 + frame.push(Int32Value(amt)); + + // Note, SUB will perform integer conversion for us. + // Before: V 1 + // After: N+1 + jsop_binary(JSOP_SUB, stubs::Sub); + + // Before: N+1 + // After: N+1 + frame.storeArg(slot, popped); + + if (popped) + frame.pop(); + } else { + int amt = (op == JSOP_ARGINC || op == JSOP_INCARG) ? 1 : -1; + + // Before: + // After: V + frame.pushArg(slot); + + // Before: V + // After: N + jsop_pos(); + + // Before: N + // After: N N + frame.dup(); + + // Before: N N + // After: N N 1 + frame.push(Int32Value(amt)); + + // Before: N N 1 + // After: N N+1 + jsop_binary(JSOP_ADD, stubs::Add); + + // Before: N N+1 + // After: N N+1 + frame.storeArg(slot, true); + + // Before: N N+1 + // After: N + frame.pop(); + } +} + +static inline bool +IsCacheableSetElem(FrameEntry *obj, FrameEntry *id, FrameEntry *value) +{ + if (obj->isNotType(JSVAL_TYPE_OBJECT)) + return false; + if (id->isNotType(JSVAL_TYPE_INT32)) + return false; + if (id->isConstant() && id->getValue().toInt32() < 0) + return false; + + // obj[obj] * is not allowed, since it will never optimize. + // obj[id] = id is allowed. + // obj[id] = obj is allowed. + if (obj->hasSameBacking(id)) + return false; + + return true; +} + +bool +mjit::Compiler::jsop_setelem(bool popGuaranteed) +{ + FrameEntry *obj = frame.peek(-3); + FrameEntry *id = frame.peek(-2); + FrameEntry *value = frame.peek(-1); + + if (!IsCacheableSetElem(obj, id, value)) { + jsop_setelem_slow(); + return true; + } + + SetElementICInfo ic = SetElementICInfo(JSOp(*PC)); + + // One by one, check if the most important stack entries have registers, + // and if so, pin them. This is to avoid spilling and reloading from the + // stack as we incrementally allocate other registers. + MaybeRegisterID pinnedValueType = frame.maybePinType(value); + MaybeRegisterID pinnedValueData = frame.maybePinData(value); + + // Pin |obj| if it doesn't share a backing with |value|. + MaybeRegisterID pinnedObjData; + if (!obj->hasSameBacking(value)) + pinnedObjData = frame.maybePinData(obj); + + // Pin |id| if it doesn't share a backing with |value|. + MaybeRegisterID pinnedIdData; + if (!id->hasSameBacking(value)) + pinnedIdData = frame.maybePinData(id); + + // Note: The fact that |obj| and |value|, or |id| and |value| can be + // copies, is a little complicated, but it is safe. Explanations + // follow at each point. Keep in mind two points: + // 1) maybePin() never allocates a register, it only pins if a register + // already existed. + // 2) tempRegForData() will work fine on a pinned register. + + // Guard that the object is an object. + if (!obj->isTypeKnown()) { + Jump j = frame.testObject(Assembler::NotEqual, obj); + stubcc.linkExit(j, Uses(3)); + } + + // Guard that the id is int32. + if (!id->isTypeKnown()) { + Jump j = frame.testInt32(Assembler::NotEqual, id); + stubcc.linkExit(j, Uses(3)); + } + + // Grab a register for the object. It's safe to unpin |obj| because it + // won't have been pinned if it shares a backing with |value|. However, + // it would not be safe to copyDataIntoReg() if the value was pinned, + // since this could evict the register. So we special case. + frame.maybeUnpinReg(pinnedObjData); + if (obj->hasSameBacking(value) && pinnedValueData.isSet()) { + ic.objReg = frame.allocReg(); + masm.move(pinnedValueData.reg(), ic.objReg); + } else { + ic.objReg = frame.copyDataIntoReg(obj); + } + + // pinEntry() will ensure pinned registers for |value|. To avoid a + // double-pin assert, first unpin any registers that |value| had. + frame.maybeUnpinReg(pinnedValueType); + frame.maybeUnpinReg(pinnedValueData); + frame.pinEntry(value, ic.vr); + + // Store rematerialization information about the key. This is the final + // register we allocate, and thus it can use tempRegForData() without + // the worry of being spilled. Once again, this is safe even if |id| + // shares a backing with |value|, because tempRegForData() will work on + // the pinned register, and |pinnedIdData| will not double-pin. + frame.maybeUnpinReg(pinnedIdData); + if (id->isConstant()) + ic.key = Int32Key::FromConstant(id->getValue().toInt32()); + else + ic.key = Int32Key::FromRegister(frame.tempRegForData(id)); + + // Unpin the value since register allocation is complete. + frame.unpinEntry(ic.vr); + + // Now it's also safe to grab remat info for obj (all exits that can + // generate stubs must have the same register state). + ic.objRemat = frame.dataRematInfo(obj); + + // All patchable guards must occur after this point. + RESERVE_IC_SPACE(masm); + ic.fastPathStart = masm.label(); + + // Create the common out-of-line sync block, taking care to link previous + // guards here after. + RESERVE_OOL_SPACE(stubcc.masm); + ic.slowPathStart = stubcc.syncExit(Uses(3)); + + // Guard obj is a dense array. + ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &js_ArrayClass); + stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart); + + // Guard capacity in range. + Jump capacityGuard = masm.guardArrayCapacity(ic.objReg, ic.key); + stubcc.linkExitDirect(capacityGuard, ic.slowPathStart); + + // Load the dynamic slots vector. + masm.loadPtr(Address(ic.objReg, offsetof(JSObject, slots)), ic.objReg); + + // Guard there's no hole, then store directly to the slot. + if (ic.key.isConstant()) { + Address slot(ic.objReg, ic.key.index() * sizeof(Value)); + ic.holeGuard = masm.guardNotHole(slot); + masm.storeValue(ic.vr, slot); + } else { + BaseIndex slot(ic.objReg, ic.key.reg(), Assembler::JSVAL_SCALE); + ic.holeGuard = masm.guardNotHole(slot); + masm.storeValue(ic.vr, slot); + } + stubcc.linkExitDirect(ic.holeGuard, ic.slowPathStart); + + stubcc.leave(); +#if defined JS_POLYIC + passICAddress(&ic); + ic.slowPathCall = OOL_STUBCALL(STRICT_VARIANT(ic::SetElement)); +#else + OOL_STUBCALL(STRICT_VARIANT(stubs::SetElem)); +#endif + + ic.fastPathRejoin = masm.label(); + + // When generating typed array stubs, it may be necessary to call + // js_DoubleToECMAInt32(), which would clobber registers. To deal with + // this, we tell the IC exactly which registers need to be saved + // across calls. + ic.volatileMask = frame.regsInUse(); + + // If the RHS will be popped, and doesn't overlap any live values, then + // there's no need to save it across calls. Note that this is not true of + // |obj| or |key|, which will be used to compute the LHS reference for + // assignment. + // + // Note that the IC wants to clobber |vr.dataReg| to convert for typed + // arrays. If this clobbering is necessary, we must preserve dataReg, + // even if it's not in a volatile register. + if (popGuaranteed && + !ic.vr.isConstant() && + !value->isCopy() && + !frame.haveSameBacking(value, obj) && + !frame.haveSameBacking(value, id)) + { + ic.volatileMask &= ~Registers::maskReg(ic.vr.dataReg()); + if (!ic.vr.isTypeKnown()) + ic.volatileMask &= ~Registers::maskReg(ic.vr.typeReg()); + } else if (!ic.vr.isConstant()) { + ic.volatileMask |= Registers::maskReg(ic.vr.dataReg()); + } + + frame.freeReg(ic.objReg); + frame.shimmy(2); + stubcc.rejoin(Changes(2)); + +#if defined JS_POLYIC + if (!setElemICs.append(ic)) + return false; +#endif + + return true; +} + +static inline bool +IsCacheableGetElem(FrameEntry *obj, FrameEntry *id) +{ + if (obj->isTypeKnown() && obj->getKnownType() != JSVAL_TYPE_OBJECT) + return false; + if (id->isTypeKnown() && + !(id->getKnownType() == JSVAL_TYPE_INT32 +#if defined JS_POLYIC + || id->getKnownType() == JSVAL_TYPE_STRING +#endif + )) { + return false; + } + + if (id->isTypeKnown() && id->getKnownType() == JSVAL_TYPE_INT32 && id->isConstant() && + id->getValue().toInt32() < 0) { + return false; + } + + // obj[obj] is not allowed, since it will never optimize. + if (obj->hasSameBacking(id)) + return false; + + return true; +} + +bool +mjit::Compiler::jsop_getelem(bool isCall) +{ + FrameEntry *obj = frame.peek(-2); + FrameEntry *id = frame.peek(-1); + + if (!IsCacheableGetElem(obj, id)) { + if (isCall) + jsop_callelem_slow(); + else + jsop_getelem_slow(); + return true; + } + + GetElementICInfo ic = GetElementICInfo(JSOp(*PC)); + + // Pin the top of the stack to avoid spills, before allocating registers. + MaybeRegisterID pinnedIdData = frame.maybePinData(id); + MaybeRegisterID pinnedIdType = frame.maybePinType(id); + + MaybeJump objTypeGuard; + if (!obj->isTypeKnown()) { + // Test the type of the object without spilling the payload. + MaybeRegisterID pinnedObjData = frame.maybePinData(obj); + Jump guard = frame.testObject(Assembler::NotEqual, obj); + frame.maybeUnpinReg(pinnedObjData); + + // Create a sync path, which we'll rejoin manually later. This is safe + // as long as the IC does not build a stub; it won't, because |obj| + // won't be an object. If we extend this IC to support strings, all + // that needs to change is a little code movement. + stubcc.linkExit(guard, Uses(2)); + objTypeGuard = stubcc.masm.jump(); + } + + // Get a mutable register for the object. This will be the data reg. + ic.objReg = frame.copyDataIntoReg(obj); + + // For potential dense array calls, grab an extra reg to save the + // outgoing object. + MaybeRegisterID thisReg; + if (isCall && id->mightBeType(JSVAL_TYPE_INT32)) { + thisReg = frame.allocReg(); + masm.move(ic.objReg, thisReg.reg()); + } + + // Get a mutable register for pushing the result type. We kill two birds + // with one stone by making sure, if the key type is not known, to be loaded + // into this register. In this case it is both an input and an output. + frame.maybeUnpinReg(pinnedIdType); + if (id->isConstant() || id->isTypeKnown()) + ic.typeReg = frame.allocReg(); + else + ic.typeReg = frame.copyTypeIntoReg(id); + + // Fill in the id value. + frame.maybeUnpinReg(pinnedIdData); + if (id->isConstant()) { + ic.id = ValueRemat::FromConstant(id->getValue()); + } else { + RegisterID dataReg = frame.tempRegForData(id); + if (id->isTypeKnown()) + ic.id = ValueRemat::FromKnownType(id->getKnownType(), dataReg); + else + ic.id = ValueRemat::FromRegisters(ic.typeReg, dataReg); + } + + RESERVE_IC_SPACE(masm); + ic.fastPathStart = masm.label(); + + // Note: slow path here is safe, since the frame will not be modified. + RESERVE_OOL_SPACE(stubcc.masm); + ic.slowPathStart = stubcc.masm.label(); + frame.sync(stubcc.masm, Uses(2)); + + if (id->mightBeType(JSVAL_TYPE_INT32)) { + // Always test the type first (see comment in PolyIC.h). + if (!id->isTypeKnown()) { + ic.typeGuard = masm.testInt32(Assembler::NotEqual, ic.typeReg); + stubcc.linkExitDirect(ic.typeGuard.get(), ic.slowPathStart); + } + + // Guard on the clasp. + ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &js_ArrayClass); + stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart); + + Int32Key key = id->isConstant() + ? Int32Key::FromConstant(id->getValue().toInt32()) + : Int32Key::FromRegister(ic.id.dataReg()); + + Assembler::FastArrayLoadFails fails = + masm.fastArrayLoad(ic.objReg, key, ic.typeReg, ic.objReg); + + // Store the object back to sp[-1] for calls. This must occur after + // all guards because otherwise sp[-1] will be clobbered. + if (isCall) { + Address thisSlot = frame.addressOf(id); + masm.storeValueFromComponents(ImmType(JSVAL_TYPE_OBJECT), thisReg.reg(), thisSlot); + frame.freeReg(thisReg.reg()); + } + + stubcc.linkExitDirect(fails.rangeCheck, ic.slowPathStart); + stubcc.linkExitDirect(fails.holeCheck, ic.slowPathStart); + } else { + // The type is known to not be dense-friendly ahead of time, so always + // fall back to a slow path. + ic.claspGuard = masm.jump(); + stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart); + } + + stubcc.leave(); + if (objTypeGuard.isSet()) + objTypeGuard.get().linkTo(stubcc.masm.label(), &stubcc.masm); +#ifdef JS_POLYIC + passICAddress(&ic); + if (isCall) + ic.slowPathCall = OOL_STUBCALL(ic::CallElement); + else + ic.slowPathCall = OOL_STUBCALL(ic::GetElement); +#else + if (isCall) + ic.slowPathCall = OOL_STUBCALL(stubs::CallElem); + else + ic.slowPathCall = OOL_STUBCALL(stubs::GetElem); +#endif + + ic.fastPathRejoin = masm.label(); + + frame.popn(2); + frame.pushRegs(ic.typeReg, ic.objReg); + if (isCall) + frame.pushSynced(); + + stubcc.rejoin(Changes(2)); + +#ifdef JS_POLYIC + if (!getElemICs.append(ic)) + return false; +#endif + + return true; +} + +static inline bool +ReallySimpleStrictTest(FrameEntry *fe) +{ + if (!fe->isTypeKnown()) + return false; + JSValueType type = fe->getKnownType(); + return type == JSVAL_TYPE_NULL || type == JSVAL_TYPE_UNDEFINED; +} + +static inline bool +BooleanStrictTest(FrameEntry *fe) +{ + return fe->isConstant() && fe->getKnownType() == JSVAL_TYPE_BOOLEAN; +} + +void +mjit::Compiler::jsop_stricteq(JSOp op) +{ + FrameEntry *rhs = frame.peek(-1); + FrameEntry *lhs = frame.peek(-2); + + Assembler::Condition cond = (op == JSOP_STRICTEQ) ? Assembler::Equal : Assembler::NotEqual; + + /* + * NB: x64 can do full-Value comparisons. This is beneficial + * to do if the payload/type are not yet in registers. + */ + + /* Constant-fold. */ + if (lhs->isConstant() && rhs->isConstant()) { + JSBool b; + StrictlyEqual(cx, lhs->getValue(), rhs->getValue(), &b); + frame.popn(2); + frame.push(BooleanValue((op == JSOP_STRICTEQ) ? b : !b)); + return; + } + + if (frame.haveSameBacking(lhs, rhs)) { + /* False iff NaN. */ + if (lhs->isTypeKnown() && lhs->isNotType(JSVAL_TYPE_DOUBLE)) { + frame.popn(2); + frame.push(BooleanValue(op == JSOP_STRICTEQ)); + return; + } + + /* Assume NaN is in canonical form. */ + RegisterID result = frame.allocReg(Registers::SingleByteRegs); + RegisterID treg = frame.tempRegForType(lhs); + + Assembler::Condition oppositeCond = (op == JSOP_STRICTEQ) ? Assembler::NotEqual : Assembler::Equal; + +#if defined JS_CPU_X86 || defined JS_CPU_ARM + static const int CanonicalNaNType = 0x7FF80000; + masm.setPtr(oppositeCond, treg, Imm32(CanonicalNaNType), result); +#elif defined JS_CPU_X64 + static const void *CanonicalNaNType = (void *)0x7FF8000000000000; + masm.move(ImmPtr(CanonicalNaNType), JSC::X86Registers::r11); + masm.setPtr(oppositeCond, treg, JSC::X86Registers::r11, result); +#endif + + frame.popn(2); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result); + return; + } + + /* Comparison against undefined or null is super easy. */ + bool lhsTest; + if ((lhsTest = ReallySimpleStrictTest(lhs)) || ReallySimpleStrictTest(rhs)) { + FrameEntry *test = lhsTest ? rhs : lhs; + FrameEntry *known = lhsTest ? lhs : rhs; + + if (test->isTypeKnown()) { + frame.popn(2); + frame.push(BooleanValue((test->getKnownType() == known->getKnownType()) == + (op == JSOP_STRICTEQ))); + return; + } + + /* This is only true if the other side is |null|. */ + RegisterID result = frame.allocReg(Registers::SingleByteRegs); +#if defined JS_CPU_X86 || defined JS_CPU_ARM + JSValueTag mask = known->getKnownTag(); + if (frame.shouldAvoidTypeRemat(test)) + masm.set32(cond, masm.tagOf(frame.addressOf(test)), Imm32(mask), result); + else + masm.set32(cond, frame.tempRegForType(test), Imm32(mask), result); +#elif defined JS_CPU_X64 + RegisterID maskReg = frame.allocReg(); + masm.move(ImmTag(known->getKnownTag()), maskReg); + + RegisterID r = frame.tempRegForType(test); + masm.setPtr(cond, r, maskReg, result); + + frame.freeReg(maskReg); +#endif + frame.popn(2); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result); + return; + } + + /* Hardcoded booleans are easy too. */ + if ((lhsTest = BooleanStrictTest(lhs)) || BooleanStrictTest(rhs)) { + FrameEntry *test = lhsTest ? rhs : lhs; + + if (test->isTypeKnown() && test->isNotType(JSVAL_TYPE_BOOLEAN)) { + frame.popn(2); + frame.push(BooleanValue(op == JSOP_STRICTNE)); + return; + } + + if (test->isConstant()) { + frame.popn(2); + const Value &L = lhs->getValue(); + const Value &R = rhs->getValue(); + frame.push(BooleanValue((L.toBoolean() == R.toBoolean()) == (op == JSOP_STRICTEQ))); + return; + } + + RegisterID data = frame.copyDataIntoReg(test); + + RegisterID result = data; + if (!(Registers::maskReg(data) & Registers::SingleByteRegs)) + result = frame.allocReg(Registers::SingleByteRegs); + + Jump notBoolean; + if (!test->isTypeKnown()) + notBoolean = frame.testBoolean(Assembler::NotEqual, test); + + /* Do a dynamic test. */ + bool val = lhsTest ? lhs->getValue().toBoolean() : rhs->getValue().toBoolean(); + masm.set32(cond, data, Imm32(val), result); + + if (!test->isTypeKnown()) { + Jump done = masm.jump(); + notBoolean.linkTo(masm.label(), &masm); + masm.move(Imm32((op == JSOP_STRICTNE)), result); + done.linkTo(masm.label(), &masm); + } + + if (data != result) + frame.freeReg(data); + + frame.popn(2); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result); + return; + } + + /* Is it impossible that both Values are ints? */ + if ((lhs->isTypeKnown() && lhs->isNotType(JSVAL_TYPE_INT32)) || + (rhs->isTypeKnown() && rhs->isNotType(JSVAL_TYPE_INT32))) { + prepareStubCall(Uses(2)); + + if (op == JSOP_STRICTEQ) + INLINE_STUBCALL(stubs::StrictEq); + else + INLINE_STUBCALL(stubs::StrictNe); + + frame.popn(2); + frame.pushSyncedType(JSVAL_TYPE_BOOLEAN); + return; + } + +#ifndef JS_CPU_ARM + /* Try an integer fast-path. */ + bool needStub = false; + if (!lhs->isTypeKnown()) { + Jump j = frame.testInt32(Assembler::NotEqual, lhs); + stubcc.linkExit(j, Uses(2)); + needStub = true; + } + + if (!rhs->isTypeKnown() && !frame.haveSameBacking(lhs, rhs)) { + Jump j = frame.testInt32(Assembler::NotEqual, rhs); + stubcc.linkExit(j, Uses(2)); + needStub = true; + } + + FrameEntry *test = lhs->isConstant() ? rhs : lhs; + FrameEntry *other = lhs->isConstant() ? lhs : rhs; + + /* ReturnReg is safely usable with set32, since %ah can be accessed. */ + RegisterID resultReg = Registers::ReturnReg; + frame.takeReg(resultReg); + RegisterID testReg = frame.tempRegForData(test); + frame.pinReg(testReg); + + JS_ASSERT(resultReg != testReg); + + /* Set boolean in resultReg. */ + if (other->isConstant()) { + masm.set32(cond, testReg, Imm32(other->getValue().toInt32()), resultReg); + } else if (frame.shouldAvoidDataRemat(other)) { + masm.set32(cond, testReg, frame.addressOf(other), resultReg); + } else { + RegisterID otherReg = frame.tempRegForData(other); + + JS_ASSERT(otherReg != resultReg); + JS_ASSERT(otherReg != testReg); + + masm.set32(cond, testReg, otherReg, resultReg); + } + + frame.unpinReg(testReg); + + if (needStub) { + stubcc.leave(); + if (op == JSOP_STRICTEQ) + OOL_STUBCALL(stubs::StrictEq); + else + OOL_STUBCALL(stubs::StrictNe); + } + + frame.popn(2); + frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, resultReg); + + if (needStub) + stubcc.rejoin(Changes(1)); +#else + /* TODO: Port set32() logic to ARM. */ + prepareStubCall(Uses(2)); + + if (op == JSOP_STRICTEQ) + INLINE_STUBCALL(stubs::StrictEq); + else + INLINE_STUBCALL(stubs::StrictNe); + + frame.popn(2); + frame.pushSyncedType(JSVAL_TYPE_BOOLEAN); + return; +#endif +} + +void +mjit::Compiler::jsop_pos() +{ + FrameEntry *top = frame.peek(-1); + + if (top->isTypeKnown()) { + if (top->getKnownType() <= JSVAL_TYPE_INT32) + return; + prepareStubCall(Uses(1)); + INLINE_STUBCALL(stubs::Pos); + frame.pop(); + frame.pushSynced(); + return; + } + + frame.giveOwnRegs(top); + + Jump j; + if (frame.shouldAvoidTypeRemat(top)) + j = masm.testNumber(Assembler::NotEqual, frame.addressOf(top)); + else + j = masm.testNumber(Assembler::NotEqual, frame.tempRegForType(top)); + stubcc.linkExit(j, Uses(1)); + + stubcc.leave(); + OOL_STUBCALL(stubs::Pos); + + stubcc.rejoin(Changes(1)); +} + +void +mjit::Compiler::jsop_initmethod() +{ +#ifdef DEBUG + FrameEntry *obj = frame.peek(-2); +#endif + JSAtom *atom = script->getAtom(fullAtomIndex(PC)); + + /* Initializers with INITMETHOD are not fast yet. */ + JS_ASSERT(!obj->initializerObject()); + + prepareStubCall(Uses(2)); + masm.move(ImmPtr(atom), Registers::ArgReg1); + INLINE_STUBCALL(stubs::InitMethod); +} + +void +mjit::Compiler::jsop_initprop() +{ + FrameEntry *obj = frame.peek(-2); + FrameEntry *fe = frame.peek(-1); + JSAtom *atom = script->getAtom(fullAtomIndex(PC)); + + JSObject *baseobj = obj->initializerObject(); + + if (!baseobj) { + prepareStubCall(Uses(2)); + masm.move(ImmPtr(atom), Registers::ArgReg1); + INLINE_STUBCALL(stubs::InitProp); + return; + } + + JSObject *holder; + JSProperty *prop = NULL; +#ifdef DEBUG + int res = +#endif + js_LookupPropertyWithFlags(cx, baseobj, ATOM_TO_JSID(atom), + JSRESOLVE_QUALIFIED, &holder, &prop); + JS_ASSERT(res >= 0 && prop && holder == baseobj); + + RegisterID objReg = frame.copyDataIntoReg(obj); + masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg); + + /* Perform the store. */ + Shape *shape = (Shape *) prop; + frame.storeTo(fe, Address(objReg, shape->slot * sizeof(Value))); + frame.freeReg(objReg); +} + +void +mjit::Compiler::jsop_initelem() +{ + FrameEntry *obj = frame.peek(-3); + FrameEntry *id = frame.peek(-2); + FrameEntry *fe = frame.peek(-1); + + /* + * The initialized index is always a constant, but we won't remember which + * constant if there are branches inside the code computing the initializer + * expression (e.g. the expression uses the '?' operator). Slow path those + * cases, as well as those where INITELEM is used on an object initializer + * or a non-fast array initializer. + */ + if (!id->isConstant() || !obj->initializerArray()) { + JSOp next = JSOp(PC[JSOP_INITELEM_LENGTH]); + + prepareStubCall(Uses(3)); + masm.move(Imm32(next == JSOP_ENDINIT ? 1 : 0), Registers::ArgReg1); + INLINE_STUBCALL(stubs::InitElem); + return; + } + + JS_ASSERT(id->getValue().isInt32()); + + if (fe->isConstant() && fe->getValue().isMagic(JS_ARRAY_HOLE)) { + /* The array already has the correct length, nothing to do. */ + return; + } + + RegisterID objReg = frame.copyDataIntoReg(obj); + masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg); + + /* Perform the store. */ + frame.storeTo(fe, Address(objReg, id->getValue().toInt32() * sizeof(Value))); + frame.freeReg(objReg); +} diff --git a/js/src/methodjit/FrameEntry.h b/js/src/methodjit/FrameEntry.h new file mode 100644 index 0000000..950bded --- /dev/null +++ b/js/src/methodjit/FrameEntry.h @@ -0,0 +1,263 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_valueinfo_h__ && defined JS_METHODJIT +#define jsjaeger_valueinfo_h__ + +#include "jsapi.h" +#include "jstypes.h" +#include "methodjit/MachineRegs.h" +#include "methodjit/RematInfo.h" +#include "assembler/assembler/MacroAssembler.h" + +namespace js { +namespace mjit { + +class FrameEntry +{ + friend class FrameState; + friend class ImmutableSync; + + public: + bool isConstant() const { + return data.isConstant(); + } + + const jsval_layout &getConstant() const { + JS_ASSERT(isConstant()); + return v_; + } + + const Value &getValue() const { + JS_ASSERT(isConstant()); + return Valueify(JSVAL_FROM_LAYOUT(v_)); + } + + bool isTypeKnown() const { + return type.isConstant(); + } + + JSValueType getKnownType() const { + JS_ASSERT(isTypeKnown()); + return knownType; + } + +#if defined JS_NUNBOX32 + JSValueTag getKnownTag() const { + return v_.s.tag; + } +#elif defined JS_PUNBOX64 + JSValueShiftedTag getKnownTag() const { + return JSValueShiftedTag(v_.asBits & JSVAL_TAG_MASK); + } +#endif + + // Return true iff the type of this value is definitely known to be type_. + bool isType(JSValueType type_) const { + return isTypeKnown() && getKnownType() == type_; + } + + // Return true iff the type of this value is definitely known not to be type_. + bool isNotType(JSValueType type_) const { + return isTypeKnown() && getKnownType() != type_; + } + + // Return true if the type of this value is definitely type_, or is unknown + // and thus potentially type_ at runtime. + bool mightBeType(JSValueType type_) const { + return !isNotType(type_); + } + +#if defined JS_NUNBOX32 + uint32 getPayload() const { + //JS_ASSERT(!Valueify(v_.asBits).isDouble() || type.synced()); + return v_.s.payload.u32; + } +#elif defined JS_PUNBOX64 + uint64 getPayload() const { + return v_.asBits & JSVAL_PAYLOAD_MASK; + } +#endif + + bool isCachedNumber() const { + return isNumber; + } + + bool hasSameBacking(const FrameEntry *other) const { + return backing() == other->backing(); + } + + bool isCopy() const { return !!copy; } + bool isCopied() const { return copied; } + + inline bool initializerArray() { + return initArray; + } + + inline JSObject *initializerObject() { + return initObject; + } + + private: + void setType(JSValueType type_) { + type.setConstant(); +#if defined JS_NUNBOX32 + v_.s.tag = JSVAL_TYPE_TO_TAG(type_); +#elif defined JS_PUNBOX64 + v_.asBits &= JSVAL_PAYLOAD_MASK; + v_.asBits |= JSVAL_TYPE_TO_SHIFTED_TAG(type_); +#endif + knownType = type_; + JS_ASSERT(!isNumber); + } + + void track(uint32 index) { + clear(); + index_ = index; + tracked = true; + } + + void clear() { + copied = false; + copy = NULL; + isNumber = false; + } + + uint32 trackerIndex() { + return index_; + } + + /* + * Marks the FE as unsynced & invalid. + */ + void resetUnsynced() { + clear(); + type.unsync(); + data.unsync(); +#ifdef DEBUG + type.invalidate(); + data.invalidate(); +#endif + } + + /* + * Marks the FE as synced & in memory. + */ + void resetSynced() { + clear(); + type.setMemory(); + data.setMemory(); + } + + /* + * Marks the FE as having a constant. + */ + void setConstant(const jsval &v) { + clear(); + type.unsync(); + data.unsync(); + type.setConstant(); + data.setConstant(); + v_.asBits = JSVAL_BITS(v); + Value cv = Valueify(v); + if (cv.isDouble()) + knownType = JSVAL_TYPE_DOUBLE; + else + knownType = cv.extractNonDoubleType(); + } + + void setCopied() { + JS_ASSERT(!isCopy()); + copied = true; + } + + FrameEntry *copyOf() const { + JS_ASSERT(isCopy()); + JS_ASSERT(copy < this); + return copy; + } + + const FrameEntry *backing() const { + return isCopy() ? copyOf() : this; + } + + void setNotCopied() { + copied = false; + } + + /* + * Set copy index. + */ + void setCopyOf(FrameEntry *fe) { + JS_ASSERT_IF(fe, !fe->isConstant()); + JS_ASSERT(!isCopied()); + copy = fe; + } + + inline bool isTracked() const { + return tracked; + } + + inline void untrack() { + tracked = false; + } + + private: + JSValueType knownType; + jsval_layout v_; + RematInfo type; + RematInfo data; + uint32 index_; + FrameEntry *copy; + bool copied; + bool isNumber; + bool tracked; + bool initArray; + JSObject *initObject; + +#if (JS_BITS_PER_WORD == 32) + void *padding; +#endif +}; + +} /* namespace mjit */ +} /* namespace js */ + +#endif /* jsjaeger_valueinfo_h__ */ + diff --git a/js/src/methodjit/FrameState-inl.h b/js/src/methodjit/FrameState-inl.h new file mode 100644 index 0000000..9dfeb82 --- /dev/null +++ b/js/src/methodjit/FrameState-inl.h @@ -0,0 +1,1164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_framestate_inl_h__ && defined JS_METHODJIT +#define jsjaeger_framestate_inl_h__ + +namespace js { +namespace mjit { + +inline void +FrameState::addToTracker(FrameEntry *fe) +{ + JS_ASSERT(!fe->isTracked()); + fe->track(tracker.nentries); + tracker.add(fe); + JS_ASSERT(tracker.nentries <= feLimit()); +} + +inline FrameEntry * +FrameState::peek(int32 depth) +{ + JS_ASSERT(depth < 0); + JS_ASSERT(sp + depth >= spBase); + FrameEntry *fe = &sp[depth]; + if (!fe->isTracked()) { + addToTracker(fe); + fe->resetSynced(); + } + return fe; +} + +inline void +FrameState::popn(uint32 n) +{ + for (uint32 i = 0; i < n; i++) + pop(); +} + +inline bool +FrameState::haveSameBacking(FrameEntry *lhs, FrameEntry *rhs) +{ + if (lhs->isCopy()) + lhs = lhs->copyOf(); + if (rhs->isCopy()) + rhs = rhs->copyOf(); + return lhs == rhs; +} + +inline JSC::MacroAssembler::RegisterID +FrameState::allocReg() +{ + RegisterID reg; + if (!freeRegs.empty()) { + reg = freeRegs.takeAnyReg(); + } else { + reg = evictSomeReg(); + regstate[reg].forget(); + } + + return reg; +} + +inline JSC::MacroAssembler::RegisterID +FrameState::allocReg(uint32 mask) +{ + RegisterID reg; + if (freeRegs.hasRegInMask(mask)) { + reg = freeRegs.takeRegInMask(mask); + } else { + reg = evictSomeReg(mask); + regstate[reg].forget(); + } + + return reg; +} + +inline JSC::MacroAssembler::RegisterID +FrameState::allocReg(FrameEntry *fe, RematInfo::RematType type) +{ + RegisterID reg; + if (!freeRegs.empty()) { + reg = freeRegs.takeAnyReg(); + } else { + reg = evictSomeReg(); + regstate[reg].forget(); + } + + regstate[reg].associate(fe, type); + + return reg; +} + +inline void +FrameState::convertInt32ToDouble(Assembler &masm, FrameEntry *fe, FPRegisterID fpreg) const +{ + JS_ASSERT(!fe->isConstant()); + + if (fe->isCopy()) + fe = fe->copyOf(); + + if (fe->data.inRegister()) + masm.convertInt32ToDouble(fe->data.reg(), fpreg); + else + masm.convertInt32ToDouble(addressOf(fe), fpreg); +} + +inline bool +FrameState::peekTypeInRegister(FrameEntry *fe) const +{ + if (fe->isCopy()) + fe = fe->copyOf(); + return fe->type.inRegister(); +} + +inline void +FrameState::pop() +{ + JS_ASSERT(sp > spBase); + + FrameEntry *fe = --sp; + if (!fe->isTracked()) + return; + + forgetAllRegs(fe); +} + +inline void +FrameState::freeReg(RegisterID reg) +{ + JS_ASSERT(!regstate[reg].usedBy()); + + freeRegs.putReg(reg); +} + +inline void +FrameState::forgetReg(RegisterID reg) +{ + /* + * Important: Do not touch the fe here. We can peephole optimize away + * loads and stores by re-using the contents of old FEs. + */ + JS_ASSERT_IF(regstate[reg].fe(), !regstate[reg].fe()->isCopy()); + + if (!regstate[reg].isPinned()) { + regstate[reg].forget(); + freeRegs.putReg(reg); + } +} + +inline void +FrameState::syncAndForgetEverything(uint32 newStackDepth) +{ + syncAndForgetEverything(); + sp = spBase + newStackDepth; +} + +inline FrameEntry * +FrameState::rawPush() +{ + JS_ASSERT(unsigned(sp - entries) < feLimit()); + + if (!sp->isTracked()) + addToTracker(sp); + + return sp++; +} + +inline void +FrameState::push(const Value &v) +{ + FrameEntry *fe = rawPush(); + fe->setConstant(Jsvalify(v)); +} + +inline void +FrameState::pushSynced() +{ + if (sp->isTracked()) + sp->resetSynced(); + sp++; +} + +inline void +FrameState::pushSyncedType(JSValueType type) +{ + FrameEntry *fe = rawPush(); + + fe->resetSynced(); + fe->setType(type); +} + +inline void +FrameState::pushSynced(JSValueType type, RegisterID reg) +{ + FrameEntry *fe = rawPush(); + + fe->resetUnsynced(); + fe->type.sync(); + fe->data.sync(); + fe->setType(type); + fe->data.setRegister(reg); + regstate[reg].associate(fe, RematInfo::DATA); +} + +inline void +FrameState::push(Address address) +{ +#ifdef JS_PUNBOX64 + // It's okay if either of these clobbers address.base, since we guarantee + // eviction will not physically clobber. It's also safe, on x64, for + // loadValueAsComponents() to take either type or data regs as address.base. + RegisterID typeReg = allocReg(); + RegisterID dataReg = allocReg(); + masm.loadValueAsComponents(address, typeReg, dataReg); +#elif JS_NUNBOX32 + // Prevent us from clobbering this reg. + bool free = freeRegs.hasReg(address.base); + if (free) + freeRegs.takeReg(address.base); + + RegisterID typeReg = allocReg(); + + masm.loadTypeTag(address, typeReg); + + // Allow re-use of the base register. This could avoid a spill, and + // is safe because the following allocReg() won't actually emit any + // writes to the register. + if (free) + freeRegs.putReg(address.base); + + RegisterID dataReg = allocReg(); + masm.loadPayload(address, dataReg); +#endif + + pushRegs(typeReg, dataReg); +} + +inline void +FrameState::pushRegs(RegisterID type, RegisterID data) +{ + JS_ASSERT(!freeRegs.hasReg(type) && !freeRegs.hasReg(data)); + + FrameEntry *fe = rawPush(); + + fe->resetUnsynced(); + fe->type.setRegister(type); + fe->data.setRegister(data); + regstate[type].associate(fe, RematInfo::TYPE); + regstate[data].associate(fe, RematInfo::DATA); +} + +inline void +FrameState::pushTypedPayload(JSValueType type, RegisterID payload) +{ + JS_ASSERT(!freeRegs.hasReg(payload)); + + FrameEntry *fe = rawPush(); + + fe->resetUnsynced(); + fe->setType(type); + fe->data.setRegister(payload); + regstate[payload].associate(fe, RematInfo::DATA); +} + +inline void +FrameState::pushNumber(MaybeRegisterID payload, bool asInt32) +{ + JS_ASSERT_IF(payload.isSet(), !freeRegs.hasReg(payload.reg())); + + FrameEntry *fe = rawPush(); + fe->clear(); + + JS_ASSERT(!fe->isNumber); + + if (asInt32) { + if (!fe->type.synced()) + masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), addressOf(fe)); + fe->type.setMemory(); + } else { + fe->type.setMemory(); + } + + fe->isNumber = true; + if (payload.isSet()) { + fe->data.unsync(); + fe->data.setRegister(payload.reg()); + regstate[payload.reg()].associate(fe, RematInfo::DATA); + } else { + fe->data.setMemory(); + } +} + +inline void +FrameState::pushInt32(RegisterID payload) +{ + FrameEntry *fe = rawPush(); + fe->clear(); + JS_ASSERT(!fe->isNumber); + + masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), addressOf(fe)); + fe->type.setMemory(); + + fe->isNumber = true; + fe->data.unsync(); + fe->data.setRegister(payload); + regstate[payload].associate(fe, RematInfo::DATA); +} + +inline void +FrameState::pushInitializerObject(RegisterID payload, bool array, JSObject *baseobj) +{ + pushTypedPayload(JSVAL_TYPE_OBJECT, payload); + + FrameEntry *fe = peek(-1); + fe->initArray = array; + fe->initObject = baseobj; +} + +inline void +FrameState::pushUntypedPayload(JSValueType type, RegisterID payload) +{ + JS_ASSERT(!freeRegs.hasReg(payload)); + + FrameEntry *fe = rawPush(); + + fe->clear(); + + masm.storeTypeTag(ImmType(type), addressOf(fe)); + + /* The forceful type sync will assert otherwise. */ +#ifdef DEBUG + fe->type.unsync(); +#endif + fe->type.setMemory(); + fe->data.unsync(); + fe->setNotCopied(); + fe->setCopyOf(NULL); + fe->data.setRegister(payload); + regstate[payload].associate(fe, RematInfo::DATA); +} + +inline void +FrameState::pushUntypedValue(const Value &v) +{ + FrameEntry *fe = rawPush(); + + fe->clear(); + + masm.storeValue(v, addressOf(fe)); + + /* The forceful type sync will assert otherwise. */ +#ifdef DEBUG + fe->type.unsync(); +#endif + fe->type.setMemory(); + fe->data.unsync(); + fe->data.setMemory(); + fe->setNotCopied(); + fe->setCopyOf(NULL); +} + +inline JSC::MacroAssembler::RegisterID +FrameState::tempRegForType(FrameEntry *fe, RegisterID fallback) +{ + JS_ASSERT(!regstate[fallback].fe()); + if (fe->isCopy()) + fe = fe->copyOf(); + + JS_ASSERT(!fe->type.isConstant()); + + if (fe->type.inRegister()) + return fe->type.reg(); + + /* :XXX: X86 */ + + masm.loadTypeTag(addressOf(fe), fallback); + return fallback; +} + + +inline JSC::MacroAssembler::RegisterID +FrameState::tempRegForType(FrameEntry *fe) +{ + if (fe->isCopy()) + fe = fe->copyOf(); + + JS_ASSERT(!fe->type.isConstant()); + + if (fe->type.inRegister()) + return fe->type.reg(); + + /* :XXX: X86 */ + + RegisterID reg = allocReg(fe, RematInfo::TYPE); + masm.loadTypeTag(addressOf(fe), reg); + fe->type.setRegister(reg); + return reg; +} + +inline JSC::MacroAssembler::RegisterID +FrameState::tempRegForData(FrameEntry *fe) +{ + JS_ASSERT(!fe->data.isConstant()); + + if (fe->isCopy()) + fe = fe->copyOf(); + + if (fe->data.inRegister()) + return fe->data.reg(); + + RegisterID reg = allocReg(fe, RematInfo::DATA); + masm.loadPayload(addressOf(fe), reg); + fe->data.setRegister(reg); + return reg; +} + +inline JSC::MacroAssembler::RegisterID +FrameState::tempRegInMaskForData(FrameEntry *fe, uint32 mask) +{ + JS_ASSERT(!fe->data.isConstant()); + + if (fe->isCopy()) + fe = fe->copyOf(); + + RegisterID reg; + if (fe->data.inRegister()) { + RegisterID old = fe->data.reg(); + if (Registers::maskReg(old) & mask) + return old; + + /* Keep the old register pinned. */ + regstate[old].forget(); + reg = allocReg(mask); + masm.move(old, reg); + freeReg(old); + } else { + reg = allocReg(mask); + masm.loadPayload(addressOf(fe), reg); + } + regstate[reg].associate(fe, RematInfo::DATA); + fe->data.setRegister(reg); + return reg; +} + +inline JSC::MacroAssembler::RegisterID +FrameState::tempRegForData(FrameEntry *fe, RegisterID reg, Assembler &masm) const +{ + JS_ASSERT(!fe->data.isConstant()); + + if (fe->isCopy()) + fe = fe->copyOf(); + + if (fe->data.inRegister()) { + JS_ASSERT(fe->data.reg() != reg); + return fe->data.reg(); + } else { + masm.loadPayload(addressOf(fe), reg); + return reg; + } +} + +inline bool +FrameState::shouldAvoidTypeRemat(FrameEntry *fe) +{ + return fe->type.inMemory(); +} + +inline bool +FrameState::shouldAvoidDataRemat(FrameEntry *fe) +{ + return fe->data.inMemory(); +} + +inline void +FrameState::ensureFeSynced(const FrameEntry *fe, Assembler &masm) const +{ +#if defined JS_PUNBOX64 + Address to = addressOf(fe); + const FrameEntry *backing = fe; + if (fe->isCopy()) + backing = fe->copyOf(); + + /* If we can, sync the type and data in one go. */ + if (!fe->data.synced() && !fe->type.synced()) { + if (backing->isConstant()) + masm.storeValue(backing->getValue(), to); + else if (backing->isTypeKnown()) + masm.storeValueFromComponents(ImmType(backing->getKnownType()), backing->data.reg(), to); + else + masm.storeValueFromComponents(backing->type.reg(), backing->data.reg(), to); + return; + } +#endif + + /* + * On x86_64, only one of the following two calls will have output, + * and a load will only occur if necessary. + */ + ensureDataSynced(fe, masm); + ensureTypeSynced(fe, masm); +} + +inline void +FrameState::ensureTypeSynced(const FrameEntry *fe, Assembler &masm) const +{ + if (fe->type.synced()) + return; + + Address to = addressOf(fe); + const FrameEntry *backing = fe; + if (fe->isCopy()) + backing = fe->copyOf(); + +#if defined JS_PUNBOX64 + /* Attempt to store the entire Value, to prevent a load. */ + if (backing->isConstant()) { + masm.storeValue(backing->getValue(), to); + return; + } + + if (backing->data.inRegister()) { + RegisterID dreg = backing->data.reg(); + if (backing->isTypeKnown()) + masm.storeValueFromComponents(ImmType(backing->getKnownType()), dreg, to); + else + masm.storeValueFromComponents(backing->type.reg(), dreg, to); + return; + } +#endif + + /* Store a double's type bits, even though !isTypeKnown(). */ + if (backing->isConstant()) + masm.storeTypeTag(ImmTag(backing->getKnownTag()), to); + else if (backing->isTypeKnown()) + masm.storeTypeTag(ImmType(backing->getKnownType()), to); + else + masm.storeTypeTag(backing->type.reg(), to); +} + +inline void +FrameState::ensureDataSynced(const FrameEntry *fe, Assembler &masm) const +{ + if (fe->data.synced()) + return; + + Address to = addressOf(fe); + const FrameEntry *backing = fe; + if (fe->isCopy()) + backing = fe->copyOf(); + +#if defined JS_PUNBOX64 + if (backing->isConstant()) + masm.storeValue(backing->getValue(), to); + else if (backing->isTypeKnown()) + masm.storeValueFromComponents(ImmType(backing->getKnownType()), backing->data.reg(), to); + else if (backing->type.inRegister()) + masm.storeValueFromComponents(backing->type.reg(), backing->data.reg(), to); + else + masm.storePayload(backing->data.reg(), to); +#elif defined JS_NUNBOX32 + if (backing->isConstant()) + masm.storePayload(ImmPayload(backing->getPayload()), to); + else + masm.storePayload(backing->data.reg(), to); +#endif +} + +inline void +FrameState::syncFe(FrameEntry *fe) +{ + FrameEntry *backing = fe; + if (fe->isCopy()) + backing = fe->copyOf(); + + bool needTypeReg = !fe->type.synced() && backing->type.inMemory(); + bool needDataReg = !fe->data.synced() && backing->data.inMemory(); + +#if defined JS_NUNBOX32 + /* Determine an ordering that won't spill known regs. */ + if (needTypeReg && !needDataReg) { + syncData(fe); + syncType(fe); + } else { + syncType(fe); + syncData(fe); + } +#elif defined JS_PUNBOX64 + if (JS_UNLIKELY(needTypeReg && needDataReg)) { + /* Memory-to-memory moves can only occur for copies backed by memory. */ + JS_ASSERT(backing != fe); + + /* Use ValueReg to do a whole-Value mem-to-mem move. */ + masm.loadValue(addressOf(backing), Registers::ValueReg); + masm.storeValue(Registers::ValueReg, addressOf(fe)); + } else { + /* Store in case unpinning is necessary. */ + MaybeRegisterID pairReg; + + /* Get a register if necessary, without clobbering its pair. */ + if (needTypeReg) { + if (backing->data.inRegister() && !regstate[backing->data.reg()].isPinned()) { + pairReg = backing->data.reg(); + pinReg(backing->data.reg()); + } + tempRegForType(backing); + } else if (needDataReg) { + if (backing->type.inRegister() && !regstate[backing->type.reg()].isPinned()) { + pairReg = backing->type.reg(); + pinReg(backing->type.reg()); + } + tempRegForData(backing); + } + + ensureFeSynced(fe, masm); + + if (pairReg.isSet()) + unpinReg(pairReg.reg()); + } + + if (!fe->type.synced()) + fe->type.sync(); + if (!fe->data.synced()) + fe->data.sync(); +#endif +} + +inline void +FrameState::syncType(FrameEntry *fe) +{ + FrameEntry *backing = fe; + if (fe->isCopy()) + backing = fe->copyOf(); + + if (!fe->type.synced() && backing->type.inMemory()) + tempRegForType(backing); + + ensureTypeSynced(fe, masm); + + if (!fe->type.synced()) + fe->type.sync(); +} + +inline void +FrameState::syncData(FrameEntry *fe) +{ + FrameEntry *backing = fe; + if (fe->isCopy()) + backing = fe->copyOf(); + + if (!fe->data.synced() && backing->data.inMemory()) + tempRegForData(backing); + + ensureDataSynced(fe, masm); + + if (!fe->data.synced()) + fe->data.sync(); +} + +inline void +FrameState::forgetType(FrameEntry *fe) +{ + /* + * The type may have been forgotten with an intervening storeLocal in the + * presence of eval or closed variables. For defense in depth and to make + * callers' lives simpler, bail out if the type is not known. + */ + if (!fe->isTypeKnown()) + return; + + /* + * Likewise, storeLocal() may have set this FE, with a known type, + * to be a copy of another FE, which has an unknown type. + * Just forget the type, since the backing is used in all cases. + */ + if (fe->isCopy()) { + fe->type.invalidate(); + return; + } + + ensureTypeSynced(fe, masm); + fe->type.setMemory(); +} + +inline void +FrameState::learnType(FrameEntry *fe, JSValueType type) +{ + if (fe->type.inRegister()) + forgetReg(fe->type.reg()); +#ifdef DEBUG + fe->isNumber = false; +#endif + fe->setType(type); +} + +inline JSC::MacroAssembler::Address +FrameState::addressOf(const FrameEntry *fe) const +{ + int32 frameOffset = 0; + if (fe >= locals) + frameOffset = JSStackFrame::offsetOfFixed(uint32(fe - locals)); + else if (fe >= args) + frameOffset = JSStackFrame::offsetOfFormalArg(fun, uint32(fe - args)); + else if (fe == this_) + frameOffset = JSStackFrame::offsetOfThis(fun); + else if (fe == callee_) + frameOffset = JSStackFrame::offsetOfCallee(fun); + JS_ASSERT(frameOffset); + return Address(JSFrameReg, frameOffset); +} + +inline JSC::MacroAssembler::Address +FrameState::addressForDataRemat(const FrameEntry *fe) const +{ + if (fe->isCopy() && !fe->data.synced()) + fe = fe->copyOf(); + JS_ASSERT(fe->data.synced()); + return addressOf(fe); +} + +inline JSC::MacroAssembler::Jump +FrameState::testNull(Assembler::Condition cond, FrameEntry *fe) +{ + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + if (shouldAvoidTypeRemat(fe)) + return masm.testNull(cond, addressOf(fe)); + return masm.testNull(cond, tempRegForType(fe)); +} + +inline JSC::MacroAssembler::Jump +FrameState::testUndefined(Assembler::Condition cond, FrameEntry *fe) +{ + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + if (shouldAvoidTypeRemat(fe)) + return masm.testUndefined(cond, addressOf(fe)); + return masm.testUndefined(cond, tempRegForType(fe)); +} + +inline JSC::MacroAssembler::Jump +FrameState::testInt32(Assembler::Condition cond, FrameEntry *fe) +{ + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + if (shouldAvoidTypeRemat(fe)) + return masm.testInt32(cond, addressOf(fe)); + return masm.testInt32(cond, tempRegForType(fe)); +} + +inline JSC::MacroAssembler::Jump +FrameState::testPrimitive(Assembler::Condition cond, FrameEntry *fe) +{ + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + if (shouldAvoidTypeRemat(fe)) + return masm.testPrimitive(cond, addressOf(fe)); + return masm.testPrimitive(cond, tempRegForType(fe)); +} + +inline JSC::MacroAssembler::Jump +FrameState::testObject(Assembler::Condition cond, FrameEntry *fe) +{ + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + if (shouldAvoidTypeRemat(fe)) + return masm.testObject(cond, addressOf(fe)); + return masm.testObject(cond, tempRegForType(fe)); +} + +inline JSC::MacroAssembler::Jump +FrameState::testDouble(Assembler::Condition cond, FrameEntry *fe) +{ + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + if (shouldAvoidTypeRemat(fe)) + return masm.testDouble(cond, addressOf(fe)); + return masm.testDouble(cond, tempRegForType(fe)); +} + +inline JSC::MacroAssembler::Jump +FrameState::testBoolean(Assembler::Condition cond, FrameEntry *fe) +{ + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + if (shouldAvoidTypeRemat(fe)) + return masm.testBoolean(cond, addressOf(fe)); + return masm.testBoolean(cond, tempRegForType(fe)); +} + +inline JSC::MacroAssembler::Jump +FrameState::testString(Assembler::Condition cond, FrameEntry *fe) +{ + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + if (shouldAvoidTypeRemat(fe)) + return masm.testString(cond, addressOf(fe)); + return masm.testString(cond, tempRegForType(fe)); +} + +inline FrameEntry * +FrameState::getOrTrack(uint32 index) +{ + FrameEntry *fe = &entries[index]; + if (!fe->isTracked()) { + addToTracker(fe); + fe->resetSynced(); + } + return fe; +} + +inline FrameEntry * +FrameState::getLocal(uint32 slot) +{ + JS_ASSERT(slot < script->nslots); + return getOrTrack(uint32(&locals[slot] - entries)); +} + +inline FrameEntry * +FrameState::getArg(uint32 slot) +{ + JS_ASSERT(slot < nargs); + return getOrTrack(uint32(&args[slot] - entries)); +} + +inline FrameEntry * +FrameState::getThis() +{ + return getOrTrack(uint32(this_ - entries)); +} + +inline FrameEntry * +FrameState::getCallee() +{ + // Callee can only be used in function code, and it's always an object. + JS_ASSERT(fun); + if (!callee_->isTracked()) { + addToTracker(callee_); + callee_->resetSynced(); + callee_->setType(JSVAL_TYPE_OBJECT); + } + return callee_; +} + +inline void +FrameState::pinReg(RegisterID reg) +{ + regstate[reg].pin(); +} + +inline void +FrameState::unpinReg(RegisterID reg) +{ + regstate[reg].unpin(); +} + +inline void +FrameState::unpinKilledReg(RegisterID reg) +{ + regstate[reg].unpinUnsafe(); + freeRegs.putReg(reg); +} + +inline void +FrameState::forgetAllRegs(FrameEntry *fe) +{ + if (fe->type.inRegister()) + forgetReg(fe->type.reg()); + if (fe->data.inRegister()) + forgetReg(fe->data.reg()); +} + +inline void +FrameState::swapInTracker(FrameEntry *lhs, FrameEntry *rhs) +{ + uint32 li = lhs->trackerIndex(); + uint32 ri = rhs->trackerIndex(); + JS_ASSERT(tracker[li] == lhs); + JS_ASSERT(tracker[ri] == rhs); + tracker.entries[ri] = lhs; + tracker.entries[li] = rhs; + lhs->index_ = ri; + rhs->index_ = li; +} + +inline void +FrameState::dup() +{ + dupAt(-1); +} + +inline void +FrameState::dup2() +{ + FrameEntry *lhs = peek(-2); + FrameEntry *rhs = peek(-1); + pushCopyOf(indexOfFe(lhs)); + pushCopyOf(indexOfFe(rhs)); +} + +inline void +FrameState::dupAt(int32 n) +{ + JS_ASSERT(n < 0); + FrameEntry *fe = peek(n); + pushCopyOf(indexOfFe(fe)); +} + +inline void +FrameState::pushLocal(uint32 n) +{ + FrameEntry *fe = getLocal(n); + if (!isClosedVar(n)) { + pushCopyOf(indexOfFe(fe)); + } else { +#ifdef DEBUG + /* + * We really want to assert on local variables, but in the presence of + * SETLOCAL equivocation of stack slots, and let expressions, just + * weakly assert on the fixed local vars. + */ + FrameEntry *fe = &locals[n]; + if (fe->isTracked() && n < script->nfixed) { + JS_ASSERT(fe->type.inMemory()); + JS_ASSERT(fe->data.inMemory()); + } +#endif + push(addressOf(fe)); + } +} + +inline void +FrameState::pushArg(uint32 n) +{ + FrameEntry *fe = getArg(n); + if (!isClosedArg(n)) { + pushCopyOf(indexOfFe(fe)); + } else { +#ifdef DEBUG + FrameEntry *fe = &args[n]; + if (fe->isTracked()) { + JS_ASSERT(fe->type.inMemory()); + JS_ASSERT(fe->data.inMemory()); + } +#endif + push(addressOf(fe)); + } +} + +inline void +FrameState::pushCallee() +{ + FrameEntry *fe = getCallee(); + pushCopyOf(indexOfFe(fe)); +} + +inline void +FrameState::pushThis() +{ + FrameEntry *fe = getThis(); + pushCopyOf(indexOfFe(fe)); +} + +void +FrameState::learnThisIsObject() +{ + // This is safe, albeit hacky. This is only called from the compiler, + // and only on the first use of |this| inside a basic block. Thus, + // there are no copies of |this| anywhere. + learnType(this_, JSVAL_TYPE_OBJECT); +} + +inline void +FrameState::leaveBlock(uint32 n) +{ + popn(n); +} + +inline void +FrameState::enterBlock(uint32 n) +{ + /* expect that tracker has 0 entries, for now. */ + JS_ASSERT(!tracker.nentries); + JS_ASSERT(uint32(sp + n - locals) <= script->nslots); + + if (!eval) + memset(&closedVars[uint32(sp - locals)], 0, n * sizeof(*closedVars)); + sp += n; +} + +inline void +FrameState::eviscerate(FrameEntry *fe) +{ + forgetAllRegs(fe); + fe->type.invalidate(); + fe->data.invalidate(); + fe->setNotCopied(); + fe->setCopyOf(NULL); +} + +inline void +FrameState::setClosedVar(uint32 slot) +{ + if (!eval) + closedVars[slot] = true; +} + +inline void +FrameState::setClosedArg(uint32 slot) +{ + if (!eval && !usesArguments) + closedArgs[slot] = true; +} + +inline StateRemat +FrameState::dataRematInfo(const FrameEntry *fe) const +{ + if (fe->isCopy()) + fe = fe->copyOf(); + + if (fe->data.inRegister()) + return StateRemat::FromRegister(fe->data.reg()); + + JS_ASSERT(fe->data.synced()); + return StateRemat::FromAddress(addressOf(fe)); +} + +inline void +FrameState::giveOwnRegs(FrameEntry *fe) +{ + JS_ASSERT(!fe->isConstant()); + JS_ASSERT(fe == peek(-1)); + + if (!fe->isCopy()) + return; + + RegisterID data = copyDataIntoReg(fe); + if (fe->isTypeKnown()) { + JSValueType type = fe->getKnownType(); + pop(); + pushTypedPayload(type, data); + } else { + RegisterID type = copyTypeIntoReg(fe); + pop(); + pushRegs(type, data); + } +} + +inline void +FrameState::loadDouble(RegisterID t, RegisterID d, FrameEntry *fe, FPRegisterID fpReg, + Assembler &masm) const +{ +#ifdef JS_CPU_X86 + masm.fastLoadDouble(d, t, fpReg); +#else + loadDouble(fe, fpReg, masm); +#endif +} + +inline bool +FrameState::tryFastDoubleLoad(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const +{ +#ifdef JS_CPU_X86 + if (fe->type.inRegister() && fe->data.inRegister()) { + masm.fastLoadDouble(fe->data.reg(), fe->type.reg(), fpReg); + return true; + } +#endif + return false; +} + +inline void +FrameState::loadDouble(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const +{ + if (fe->isCopy()) { + FrameEntry *backing = fe->copyOf(); + if (tryFastDoubleLoad(fe, fpReg, masm)) + return; + if (backing->isCachedNumber() || (backing->type.synced() && backing->data.synced())) { + masm.loadDouble(addressOf(backing), fpReg); + return; + } + fe = backing; + } + + if (tryFastDoubleLoad(fe, fpReg, masm)) + return; + + if ((fe->type.synced() && fe->data.synced()) || fe->isCachedNumber()) { + masm.loadDouble(addressOf(fe), fpReg); + return; + } + + ensureFeSynced(fe, masm); + masm.loadDouble(addressOf(fe), fpReg); +} + +inline bool +FrameState::isClosedVar(uint32 slot) +{ + return eval || closedVars[slot]; +} + +inline bool +FrameState::isClosedArg(uint32 slot) +{ + return eval || usesArguments || closedArgs[slot]; +} + +class PinRegAcrossSyncAndKill +{ + typedef JSC::MacroAssembler::RegisterID RegisterID; + FrameState &frame; + MaybeRegisterID maybeReg; + public: + PinRegAcrossSyncAndKill(FrameState &frame, RegisterID reg) + : frame(frame), maybeReg(reg) + { + frame.pinReg(reg); + } + PinRegAcrossSyncAndKill(FrameState &frame, MaybeRegisterID maybeReg) + : frame(frame), maybeReg(maybeReg) + { + if (maybeReg.isSet()) + frame.pinReg(maybeReg.reg()); + } + ~PinRegAcrossSyncAndKill() { + if (maybeReg.isSet()) + frame.unpinKilledReg(maybeReg.reg()); + } +}; + +} /* namespace mjit */ +} /* namespace js */ + +#endif /* include */ + diff --git a/js/src/methodjit/FrameState.cpp b/js/src/methodjit/FrameState.cpp new file mode 100644 index 0000000..2781844 --- /dev/null +++ b/js/src/methodjit/FrameState.cpp @@ -0,0 +1,1695 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "jscntxt.h" +#include "FrameState.h" +#include "FrameState-inl.h" + +using namespace js; +using namespace js::mjit; + +/* Because of Value alignment */ +JS_STATIC_ASSERT(sizeof(FrameEntry) % 8 == 0); + +FrameState::FrameState(JSContext *cx, JSScript *script, JSFunction *fun, Assembler &masm) + : cx(cx), script(script), fun(fun), + nargs(fun ? fun->nargs : 0), + masm(masm), entries(NULL), +#if defined JS_NUNBOX32 + reifier(cx, *thisFromCtor()), +#endif + closedVars(NULL), + closedArgs(NULL), + usesArguments(script->usesArguments), + inTryBlock(false) +{ +} + +FrameState::~FrameState() +{ + cx->free(entries); +} + +bool +FrameState::init() +{ + // nslots + nargs + 2 (callee, this) + uint32 nentries = feLimit(); + if (!nentries) { + sp = spBase = locals = args = NULL; + return true; + } + + eval = script->usesEval || cx->compartment->debugMode; + + size_t totalBytes = sizeof(FrameEntry) * nentries + // entries[], w/ callee+this + sizeof(FrameEntry *) * nentries + // tracker.entries + (eval + ? 0 + : sizeof(JSPackedBool) * script->nslots) + // closedVars[] + (eval || usesArguments + ? 0 + : sizeof(JSPackedBool) * nargs); // closedArgs[] + + uint8 *cursor = (uint8 *)cx->calloc(totalBytes); + if (!cursor) + return false; + +#if defined JS_NUNBOX32 + if (!reifier.init(nentries)) + return false; +#endif + + entries = (FrameEntry *)cursor; + cursor += sizeof(FrameEntry) * nentries; + + callee_ = entries; + this_ = entries + 1; + args = entries + 2; + locals = args + nargs; + spBase = locals + script->nfixed; + sp = spBase; + + tracker.entries = (FrameEntry **)cursor; + cursor += sizeof(FrameEntry *) * nentries; + + if (!eval) { + if (script->nslots) { + closedVars = (JSPackedBool *)cursor; + cursor += sizeof(JSPackedBool) * script->nslots; + } + if (!usesArguments && nargs) { + closedArgs = (JSPackedBool *)cursor; + cursor += sizeof(JSPackedBool) * nargs; + } + } + + JS_ASSERT(reinterpret_cast(entries) + totalBytes == cursor); + + return true; +} + +void +FrameState::takeReg(RegisterID reg) +{ + if (freeRegs.hasReg(reg)) { + freeRegs.takeReg(reg); + JS_ASSERT(!regstate[reg].usedBy()); + } else { + JS_ASSERT(regstate[reg].fe()); + evictReg(reg); + regstate[reg].forget(); + } +} + +void +FrameState::evictReg(RegisterID reg) +{ + FrameEntry *fe = regstate[reg].fe(); + + if (regstate[reg].type() == RematInfo::TYPE) { + ensureTypeSynced(fe, masm); + fe->type.setMemory(); + } else { + ensureDataSynced(fe, masm); + fe->data.setMemory(); + } +} + +JSC::MacroAssembler::RegisterID +FrameState::evictSomeReg(uint32 mask) +{ +#ifdef DEBUG + bool fallbackSet = false; +#endif + RegisterID fallback = Registers::ReturnReg; + + for (uint32 i = 0; i < JSC::MacroAssembler::TotalRegisters; i++) { + RegisterID reg = RegisterID(i); + + /* Register is not allocatable, don't bother. */ + if (!(Registers::maskReg(reg) & mask)) + continue; + + /* Register is not owned by the FrameState. */ + FrameEntry *fe = regstate[i].fe(); + if (!fe) + continue; + + /* Try to find a candidate... that doesn't need spilling. */ +#ifdef DEBUG + fallbackSet = true; +#endif + fallback = reg; + + if (regstate[i].type() == RematInfo::TYPE && fe->type.synced()) { + fe->type.setMemory(); + return fallback; + } + if (regstate[i].type() == RematInfo::DATA && fe->data.synced()) { + fe->data.setMemory(); + return fallback; + } + } + + JS_ASSERT(fallbackSet); + + evictReg(fallback); + return fallback; +} + + +void +FrameState::syncAndForgetEverything() +{ + syncAndKill(Registers(Registers::AvailRegs), Uses(frameSlots())); + forgetEverything(); +} + +void +FrameState::resetInternalState() +{ + for (uint32 i = 0; i < tracker.nentries; i++) + tracker[i]->untrack(); + + tracker.reset(); + freeRegs.reset(); +} + +void +FrameState::discardFrame() +{ + resetInternalState(); + + memset(regstate, 0, sizeof(regstate)); +} + +void +FrameState::forgetEverything() +{ + resetInternalState(); + +#ifdef DEBUG + for (uint32 i = 0; i < JSC::MacroAssembler::TotalRegisters; i++) { + JS_ASSERT(!regstate[i].usedBy()); + } +#endif +} + +void +FrameState::storeTo(FrameEntry *fe, Address address, bool popped) +{ + if (fe->isConstant()) { + masm.storeValue(fe->getValue(), address); + return; + } + + if (fe->isCopy()) + fe = fe->copyOf(); + + /* Cannot clobber the address's register. */ + JS_ASSERT(!freeRegs.hasReg(address.base)); + + /* If loading from memory, ensure destination differs. */ + JS_ASSERT_IF((fe->type.inMemory() || fe->data.inMemory()), + addressOf(fe).base != address.base || + addressOf(fe).offset != address.offset); + +#if defined JS_PUNBOX64 + if (fe->type.inMemory() && fe->data.inMemory()) { + /* Future optimization: track that the Value is in a register. */ + RegisterID vreg = Registers::ValueReg; + masm.loadPtr(addressOf(fe), vreg); + masm.storePtr(vreg, address); + return; + } + + /* + * If dreg is obtained via allocReg(), then calling + * pinReg() trips an assertion. But in all other cases, + * calling pinReg() is necessary in the fe->type.inMemory() path. + * Remember whether pinReg() can be safely called. + */ + bool canPinDreg = true; + bool wasInRegister = fe->data.inRegister(); + + /* Get a register for the payload. */ + MaybeRegisterID dreg; + if (fe->data.inRegister()) { + dreg = fe->data.reg(); + } else { + JS_ASSERT(fe->data.inMemory()); + if (popped) { + dreg = allocReg(); + canPinDreg = false; + } else { + dreg = allocReg(fe, RematInfo::DATA); + fe->data.setRegister(dreg.reg()); + } + masm.loadPayload(addressOf(fe), dreg.reg()); + } + + /* Store the Value. */ + if (fe->type.inRegister()) { + masm.storeValueFromComponents(fe->type.reg(), dreg.reg(), address); + } else if (fe->isTypeKnown()) { + masm.storeValueFromComponents(ImmType(fe->getKnownType()), dreg.reg(), address); + } else { + JS_ASSERT(fe->type.inMemory()); + if (canPinDreg) + pinReg(dreg.reg()); + + RegisterID treg = popped ? allocReg() : allocReg(fe, RematInfo::TYPE); + masm.loadTypeTag(addressOf(fe), treg); + masm.storeValueFromComponents(treg, dreg.reg(), address); + + if (popped) + freeReg(treg); + else + fe->type.setRegister(treg); + + if (canPinDreg) + unpinReg(dreg.reg()); + } + + /* If register is untracked, free it. */ + if (!wasInRegister && popped) + freeReg(dreg.reg()); + +#elif defined JS_NUNBOX32 + + if (fe->data.inRegister()) { + masm.storePayload(fe->data.reg(), address); + } else { + JS_ASSERT(fe->data.inMemory()); + RegisterID reg = popped ? allocReg() : allocReg(fe, RematInfo::DATA); + masm.loadPayload(addressOf(fe), reg); + masm.storePayload(reg, address); + if (popped) + freeReg(reg); + else + fe->data.setRegister(reg); + } + + if (fe->isTypeKnown()) { + masm.storeTypeTag(ImmType(fe->getKnownType()), address); + } else if (fe->type.inRegister()) { + masm.storeTypeTag(fe->type.reg(), address); + } else { + JS_ASSERT(fe->type.inMemory()); + RegisterID reg = popped ? allocReg() : allocReg(fe, RematInfo::TYPE); + masm.loadTypeTag(addressOf(fe), reg); + masm.storeTypeTag(reg, address); + if (popped) + freeReg(reg); + else + fe->type.setRegister(reg); + } +#endif +} + +void +FrameState::loadThisForReturn(RegisterID typeReg, RegisterID dataReg, RegisterID tempReg) +{ + return loadForReturn(getThis(), typeReg, dataReg, tempReg); +} + +void FrameState::loadForReturn(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg) +{ + JS_ASSERT(dataReg != typeReg && dataReg != tempReg && typeReg != tempReg); + + if (fe->isConstant()) { + masm.loadValueAsComponents(fe->getValue(), typeReg, dataReg); + return; + } + + if (fe->isCopy()) + fe = fe->copyOf(); + + MaybeRegisterID maybeType = maybePinType(fe); + MaybeRegisterID maybeData = maybePinData(fe); + + if (fe->isTypeKnown()) { + // If the data is in memory, or in the wrong reg, load/move it. + if (!maybeData.isSet()) + masm.loadPayload(addressOf(fe), dataReg); + else if (maybeData.reg() != dataReg) + masm.move(maybeData.reg(), dataReg); + masm.move(ImmType(fe->getKnownType()), typeReg); + return; + } + + // If both halves of the value are in memory, make this easier and load + // both pieces into their respective registers. + if (fe->type.inMemory() && fe->data.inMemory()) { + masm.loadValueAsComponents(addressOf(fe), typeReg, dataReg); + return; + } + + // Now, we should be guaranteed that at least one part is in a register. + JS_ASSERT(maybeType.isSet() || maybeData.isSet()); + + // Make sure we have two registers while making sure not clobber either half. + // Here we are allowed to mess up the FrameState invariants, because this + // is specialized code for a path that is about to discard the entire frame. + if (!maybeType.isSet()) { + JS_ASSERT(maybeData.isSet()); + if (maybeData.reg() != typeReg) + maybeType = typeReg; + else + maybeType = tempReg; + masm.loadTypeTag(addressOf(fe), maybeType.reg()); + } else if (!maybeData.isSet()) { + JS_ASSERT(maybeType.isSet()); + if (maybeType.reg() != dataReg) + maybeData = dataReg; + else + maybeData = tempReg; + masm.loadPayload(addressOf(fe), maybeData.reg()); + } + + RegisterID type = maybeType.reg(); + RegisterID data = maybeData.reg(); + + if (data == typeReg && type == dataReg) { + masm.move(type, tempReg); + masm.move(data, dataReg); + masm.move(tempReg, typeReg); + } else if (data != dataReg) { + if (type == typeReg) { + masm.move(data, dataReg); + } else if (type != dataReg) { + masm.move(data, dataReg); + if (type != typeReg) + masm.move(type, typeReg); + } else { + JS_ASSERT(data != typeReg); + masm.move(type, typeReg); + masm.move(data, dataReg); + } + } else if (type != typeReg) { + masm.move(type, typeReg); + } +} + +#ifdef DEBUG +void +FrameState::assertValidRegisterState() const +{ + Registers checkedFreeRegs; + + for (uint32 i = 0; i < tracker.nentries; i++) { + FrameEntry *fe = tracker[i]; + if (fe >= sp) + continue; + + JS_ASSERT(i == fe->trackerIndex()); + JS_ASSERT_IF(fe->isCopy(), + fe->trackerIndex() > fe->copyOf()->trackerIndex()); + JS_ASSERT_IF(fe->isCopy(), fe > fe->copyOf()); + JS_ASSERT_IF(fe->isCopy(), !fe->type.inRegister() && !fe->data.inRegister()); + JS_ASSERT_IF(fe->isCopy(), fe->copyOf() < sp); + JS_ASSERT_IF(fe->isCopy(), fe->copyOf()->isCopied()); + + if (fe->isCopy()) + continue; + if (fe->type.inRegister()) { + checkedFreeRegs.takeReg(fe->type.reg()); + JS_ASSERT(regstate[fe->type.reg()].fe() == fe); + } + if (fe->data.inRegister()) { + checkedFreeRegs.takeReg(fe->data.reg()); + JS_ASSERT(regstate[fe->data.reg()].fe() == fe); + } + } + + JS_ASSERT(checkedFreeRegs == freeRegs); + + for (uint32 i = 0; i < JSC::MacroAssembler::TotalRegisters; i++) { + JS_ASSERT(!regstate[i].isPinned()); + JS_ASSERT_IF(regstate[i].fe(), !freeRegs.hasReg(RegisterID(i))); + JS_ASSERT_IF(regstate[i].fe(), regstate[i].fe()->isTracked()); + } +} +#endif + +#if defined JS_NUNBOX32 +void +FrameState::syncFancy(Assembler &masm, Registers avail, FrameEntry *resumeAt, + FrameEntry *bottom) const +{ + reifier.reset(&masm, avail, resumeAt, bottom); + + for (FrameEntry *fe = resumeAt; fe >= bottom; fe--) { + if (!fe->isTracked()) + continue; + + reifier.sync(fe); + } +} +#endif + +void +FrameState::sync(Assembler &masm, Uses uses) const +{ + if (!entries) + return; + + /* Sync all registers up-front. */ + Registers allRegs(Registers::AvailRegs); + while (!allRegs.empty()) { + RegisterID reg = allRegs.takeAnyReg(); + FrameEntry *fe = regstate[reg].usedBy(); + if (!fe) + continue; + + JS_ASSERT(fe->isTracked()); + +#if defined JS_PUNBOX64 + /* Sync entire FE to prevent loads. */ + ensureFeSynced(fe, masm); + + /* Take the other register in the pair, if one exists. */ + if (regstate[reg].type() == RematInfo::DATA && fe->type.inRegister()) + allRegs.takeReg(fe->type.reg()); + else if (regstate[reg].type() == RematInfo::TYPE && fe->data.inRegister()) + allRegs.takeReg(fe->data.reg()); +#elif defined JS_NUNBOX32 + /* Sync register if unsynced. */ + if (regstate[reg].type() == RematInfo::DATA) { + JS_ASSERT(fe->data.reg() == reg); + ensureDataSynced(fe, masm); + } else { + JS_ASSERT(fe->type.reg() == reg); + ensureTypeSynced(fe, masm); + } +#endif + } + + /* + * Keep track of free registers using a bitmask. If we have to drop into + * syncFancy(), then this mask will help avoid eviction. + */ + Registers avail(freeRegs); + Registers temp(Registers::TempRegs); + + FrameEntry *bottom = sp - uses.nuses; + + for (FrameEntry *fe = sp - 1; fe >= bottom; fe--) { + if (!fe->isTracked()) + continue; + + FrameEntry *backing = fe; + + if (!fe->isCopy()) { + if (fe->data.inRegister()) + avail.putReg(fe->data.reg()); + if (fe->type.inRegister()) + avail.putReg(fe->type.reg()); + } else { + backing = fe->copyOf(); + JS_ASSERT(!backing->isConstant() && !fe->isConstant()); + +#if defined JS_PUNBOX64 + if ((!fe->type.synced() && backing->type.inMemory()) || + (!fe->data.synced() && backing->data.inMemory())) { + + RegisterID syncReg = Registers::ValueReg; + + /* Load the entire Value into syncReg. */ + if (backing->type.synced() && backing->data.synced()) { + masm.loadValue(addressOf(backing), syncReg); + } else if (backing->type.inMemory()) { + masm.loadTypeTag(addressOf(backing), syncReg); + masm.orPtr(backing->data.reg(), syncReg); + } else { + JS_ASSERT(backing->data.inMemory()); + masm.loadPayload(addressOf(backing), syncReg); + if (backing->isTypeKnown()) + masm.orPtr(ImmType(backing->getKnownType()), syncReg); + else + masm.orPtr(backing->type.reg(), syncReg); + } + + masm.storeValue(syncReg, addressOf(fe)); + continue; + } +#elif defined JS_NUNBOX32 + /* Fall back to a slower sync algorithm if load required. */ + if ((!fe->type.synced() && backing->type.inMemory()) || + (!fe->data.synced() && backing->data.inMemory())) { + syncFancy(masm, avail, fe, bottom); + return; + } +#endif + } + + /* If a part still needs syncing, it is either a copy or constant. */ +#if defined JS_PUNBOX64 + /* All register-backed FEs have been entirely synced up-front. */ + if (!fe->type.inRegister() && !fe->data.inRegister()) + ensureFeSynced(fe, masm); +#elif defined JS_NUNBOX32 + /* All components held in registers have been already synced. */ + if (!fe->data.inRegister()) + ensureDataSynced(fe, masm); + if (!fe->type.inRegister()) + ensureTypeSynced(fe, masm); +#endif + } +} + +void +FrameState::syncAndKill(Registers kill, Uses uses, Uses ignore) +{ + FrameEntry *spStop = sp - ignore.nuses; + + /* Sync all kill-registers up-front. */ + Registers search(kill.freeMask & ~freeRegs.freeMask); + while (!search.empty()) { + RegisterID reg = search.takeAnyReg(); + FrameEntry *fe = regstate[reg].usedBy(); + if (!fe || fe >= spStop) + continue; + + JS_ASSERT(fe->isTracked()); + +#if defined JS_PUNBOX64 + /* Don't use syncFe(), since that may clobber more registers. */ + ensureFeSynced(fe, masm); + + if (!fe->type.synced()) + fe->type.sync(); + if (!fe->data.synced()) + fe->data.sync(); + + /* Take the other register in the pair, if one exists. */ + if (regstate[reg].type() == RematInfo::DATA) { + JS_ASSERT(fe->data.reg() == reg); + if (fe->type.inRegister() && search.hasReg(fe->type.reg())) + search.takeReg(fe->type.reg()); + } else { + JS_ASSERT(fe->type.reg() == reg); + if (fe->data.inRegister() && search.hasReg(fe->data.reg())) + search.takeReg(fe->data.reg()); + } +#elif defined JS_NUNBOX32 + /* Sync this register. */ + if (regstate[reg].type() == RematInfo::DATA) { + JS_ASSERT(fe->data.reg() == reg); + syncData(fe); + } else { + JS_ASSERT(fe->type.reg() == reg); + syncType(fe); + } +#endif + } + + uint32 maxvisits = tracker.nentries; + FrameEntry *bottom = sp - uses.nuses; + + for (FrameEntry *fe = sp - 1; fe >= bottom && maxvisits; fe--) { + if (!fe->isTracked()) + continue; + + maxvisits--; + + if (fe >= spStop) + continue; + + syncFe(fe); + + /* Forget registers. */ + if (fe->data.inRegister() && kill.hasReg(fe->data.reg()) && + !regstate[fe->data.reg()].isPinned()) { + forgetReg(fe->data.reg()); + fe->data.setMemory(); + } + if (fe->type.inRegister() && kill.hasReg(fe->type.reg()) && + !regstate[fe->type.reg()].isPinned()) { + forgetReg(fe->type.reg()); + fe->type.setMemory(); + } + } + + /* + * Anything still alive at this point is guaranteed to be synced. However, + * it is necessary to evict temporary registers. + */ + search = Registers(kill.freeMask & ~freeRegs.freeMask); + while (!search.empty()) { + RegisterID reg = search.takeAnyReg(); + FrameEntry *fe = regstate[reg].usedBy(); + if (!fe || fe >= spStop) + continue; + + JS_ASSERT(fe->isTracked()); + + if (regstate[reg].type() == RematInfo::DATA) { + JS_ASSERT(fe->data.reg() == reg); + JS_ASSERT(fe->data.synced()); + fe->data.setMemory(); + } else { + JS_ASSERT(fe->type.reg() == reg); + JS_ASSERT(fe->type.synced()); + fe->type.setMemory(); + } + + forgetReg(reg); + } +} + +void +FrameState::merge(Assembler &masm, Changes changes) const +{ + Registers search(Registers::AvailRegs & ~freeRegs.freeMask); + + while (!search.empty()) { + RegisterID reg = search.peekReg(); + FrameEntry *fe = regstate[reg].usedBy(); + + if (!fe) { + search.takeReg(reg); + continue; + } + + if (fe->data.inRegister() && fe->type.inRegister()) { + search.takeReg(fe->data.reg()); + search.takeReg(fe->type.reg()); + masm.loadValueAsComponents(addressOf(fe), fe->type.reg(), fe->data.reg()); + } else { + if (fe->data.inRegister()) { + search.takeReg(fe->data.reg()); + masm.loadPayload(addressOf(fe), fe->data.reg()); + } + if (fe->type.inRegister()) { + search.takeReg(fe->type.reg()); + masm.loadTypeTag(addressOf(fe), fe->type.reg()); + } + } + } +} + +JSC::MacroAssembler::RegisterID +FrameState::copyDataIntoReg(FrameEntry *fe) +{ + return copyDataIntoReg(this->masm, fe); +} + +void +FrameState::copyDataIntoReg(FrameEntry *fe, RegisterID hint) +{ + JS_ASSERT(!fe->data.isConstant()); + + if (fe->isCopy()) + fe = fe->copyOf(); + + if (!fe->data.inRegister()) + tempRegForData(fe); + + RegisterID reg = fe->data.reg(); + if (reg == hint) { + if (freeRegs.empty()) { + ensureDataSynced(fe, masm); + fe->data.setMemory(); + } else { + reg = allocReg(); + masm.move(hint, reg); + fe->data.setRegister(reg); + regstate[reg].associate(regstate[hint].fe(), RematInfo::DATA); + } + regstate[hint].forget(); + } else { + pinReg(reg); + takeReg(hint); + unpinReg(reg); + masm.move(reg, hint); + } +} + +JSC::MacroAssembler::RegisterID +FrameState::copyDataIntoReg(Assembler &masm, FrameEntry *fe) +{ + JS_ASSERT(!fe->data.isConstant()); + + if (fe->isCopy()) + fe = fe->copyOf(); + + if (fe->data.inRegister()) { + RegisterID reg = fe->data.reg(); + if (freeRegs.empty()) { + ensureDataSynced(fe, masm); + fe->data.setMemory(); + regstate[reg].forget(); + } else { + RegisterID newReg = allocReg(); + masm.move(reg, newReg); + reg = newReg; + } + return reg; + } + + RegisterID reg = allocReg(); + + if (!freeRegs.empty()) + masm.move(tempRegForData(fe), reg); + else + masm.loadPayload(addressOf(fe),reg); + + return reg; +} + +JSC::MacroAssembler::RegisterID +FrameState::copyTypeIntoReg(FrameEntry *fe) +{ + JS_ASSERT(!fe->type.isConstant()); + + if (fe->isCopy()) + fe = fe->copyOf(); + + if (fe->type.inRegister()) { + RegisterID reg = fe->type.reg(); + if (freeRegs.empty()) { + ensureTypeSynced(fe, masm); + fe->type.setMemory(); + regstate[reg].forget(); + } else { + RegisterID newReg = allocReg(); + masm.move(reg, newReg); + reg = newReg; + } + return reg; + } + + RegisterID reg = allocReg(); + + if (!freeRegs.empty()) + masm.move(tempRegForType(fe), reg); + else + masm.loadTypeTag(addressOf(fe), reg); + + return reg; +} + +JSC::MacroAssembler::RegisterID +FrameState::copyInt32ConstantIntoReg(FrameEntry *fe) +{ + return copyInt32ConstantIntoReg(masm, fe); +} + +JSC::MacroAssembler::RegisterID +FrameState::copyInt32ConstantIntoReg(Assembler &masm, FrameEntry *fe) +{ + JS_ASSERT(fe->data.isConstant()); + + if (fe->isCopy()) + fe = fe->copyOf(); + + RegisterID reg = allocReg(); + masm.move(Imm32(fe->getValue().toInt32()), reg); + return reg; +} + +JSC::MacroAssembler::FPRegisterID +FrameState::copyEntryIntoFPReg(FrameEntry *fe, FPRegisterID fpreg) +{ + return copyEntryIntoFPReg(this->masm, fe, fpreg); +} + +JSC::MacroAssembler::FPRegisterID +FrameState::copyEntryIntoFPReg(Assembler &masm, FrameEntry *fe, FPRegisterID fpreg) +{ + if (fe->isCopy()) + fe = fe->copyOf(); + + ensureFeSynced(fe, masm); + masm.loadDouble(addressOf(fe), fpreg); + + return fpreg; +} + +JSC::MacroAssembler::RegisterID +FrameState::ownRegForType(FrameEntry *fe) +{ + JS_ASSERT(!fe->type.isConstant()); + + RegisterID reg; + if (fe->isCopy()) { + /* For now, just do an extra move. The reg must be mutable. */ + FrameEntry *backing = fe->copyOf(); + if (!backing->type.inRegister()) { + JS_ASSERT(backing->type.inMemory()); + tempRegForType(backing); + } + + if (freeRegs.empty()) { + /* For now... just steal the register that already exists. */ + ensureTypeSynced(backing, masm); + reg = backing->type.reg(); + backing->type.setMemory(); + regstate[reg].forget(); + } else { + reg = allocReg(); + masm.move(backing->type.reg(), reg); + } + return reg; + } + + if (fe->type.inRegister()) { + reg = fe->type.reg(); + + /* Remove ownership of this register. */ + JS_ASSERT(regstate[reg].fe() == fe); + JS_ASSERT(regstate[reg].type() == RematInfo::TYPE); + regstate[reg].forget(); + fe->type.invalidate(); + } else { + JS_ASSERT(fe->type.inMemory()); + reg = allocReg(); + masm.loadTypeTag(addressOf(fe), reg); + } + return reg; +} + +JSC::MacroAssembler::RegisterID +FrameState::ownRegForData(FrameEntry *fe) +{ + JS_ASSERT(!fe->data.isConstant()); + + RegisterID reg; + if (fe->isCopy()) { + /* For now, just do an extra move. The reg must be mutable. */ + FrameEntry *backing = fe->copyOf(); + if (!backing->data.inRegister()) { + JS_ASSERT(backing->data.inMemory()); + tempRegForData(backing); + } + + if (freeRegs.empty()) { + /* For now... just steal the register that already exists. */ + ensureDataSynced(backing, masm); + reg = backing->data.reg(); + backing->data.setMemory(); + regstate[reg].forget(); + } else { + reg = allocReg(); + masm.move(backing->data.reg(), reg); + } + return reg; + } + + if (fe->isCopied()) { + FrameEntry *copy = uncopy(fe); + if (fe->isCopied()) { + fe->type.invalidate(); + fe->data.invalidate(); + return copyDataIntoReg(copy); + } + } + + if (fe->data.inRegister()) { + reg = fe->data.reg(); + /* Remove ownership of this register. */ + JS_ASSERT(regstate[reg].fe() == fe); + JS_ASSERT(regstate[reg].type() == RematInfo::DATA); + regstate[reg].forget(); + fe->data.invalidate(); + } else { + JS_ASSERT(fe->data.inMemory()); + reg = allocReg(); + masm.loadPayload(addressOf(fe), reg); + } + return reg; +} + +void +FrameState::discardFe(FrameEntry *fe) +{ + forgetEntry(fe); + fe->type.setMemory(); + fe->data.setMemory(); +} + +void +FrameState::pushCopyOf(uint32 index) +{ + FrameEntry *backing = entryFor(index); + FrameEntry *fe = rawPush(); + fe->resetUnsynced(); + if (backing->isConstant()) { + fe->setConstant(Jsvalify(backing->getValue())); + } else { + if (backing->isTypeKnown()) + fe->setType(backing->getKnownType()); + else + fe->type.invalidate(); + fe->isNumber = backing->isNumber; + fe->data.invalidate(); + if (backing->isCopy()) { + backing = backing->copyOf(); + fe->setCopyOf(backing); + } else { + fe->setCopyOf(backing); + backing->setCopied(); + } + + /* Maintain tracker ordering guarantees for copies. */ + JS_ASSERT(backing->isCopied()); + if (fe->trackerIndex() < backing->trackerIndex()) + swapInTracker(fe, backing); + } +} + +FrameEntry * +FrameState::walkTrackerForUncopy(FrameEntry *original) +{ + uint32 firstCopy = InvalidIndex; + FrameEntry *bestFe = NULL; + uint32 ncopies = 0; + for (uint32 i = original->trackerIndex() + 1; i < tracker.nentries; i++) { + FrameEntry *fe = tracker[i]; + if (fe >= sp) + continue; + if (fe->isCopy() && fe->copyOf() == original) { + if (firstCopy == InvalidIndex) { + firstCopy = i; + bestFe = fe; + } else if (fe < bestFe) { + bestFe = fe; + } + ncopies++; + } + } + + if (!ncopies) { + JS_ASSERT(firstCopy == InvalidIndex); + JS_ASSERT(!bestFe); + return NULL; + } + + JS_ASSERT(firstCopy != InvalidIndex); + JS_ASSERT(bestFe); + JS_ASSERT(bestFe > original); + + /* Mark all extra copies as copies of the new backing index. */ + bestFe->setCopyOf(NULL); + if (ncopies > 1) { + bestFe->setCopied(); + for (uint32 i = firstCopy; i < tracker.nentries; i++) { + FrameEntry *other = tracker[i]; + if (other >= sp || other == bestFe) + continue; + + /* The original must be tracked before copies. */ + JS_ASSERT(other != original); + + if (!other->isCopy() || other->copyOf() != original) + continue; + + other->setCopyOf(bestFe); + + /* + * This is safe even though we're mutating during iteration. There + * are two cases. The first is that both indexes are <= i, and :. + * will never be observed. The other case is we're placing the + * other FE such that it will be observed later. Luckily, copyOf() + * will return != original, so nothing will happen. + */ + if (other->trackerIndex() < bestFe->trackerIndex()) + swapInTracker(bestFe, other); + } + } else { + bestFe->setNotCopied(); + } + + return bestFe; +} + +FrameEntry * +FrameState::walkFrameForUncopy(FrameEntry *original) +{ + FrameEntry *bestFe = NULL; + uint32 ncopies = 0; + + /* It's only necessary to visit as many FEs are being tracked. */ + uint32 maxvisits = tracker.nentries; + + for (FrameEntry *fe = original + 1; fe < sp && maxvisits; fe++) { + if (!fe->isTracked()) + continue; + + maxvisits--; + + if (fe->isCopy() && fe->copyOf() == original) { + if (!bestFe) { + bestFe = fe; + bestFe->setCopyOf(NULL); + } else { + fe->setCopyOf(bestFe); + if (fe->trackerIndex() < bestFe->trackerIndex()) + swapInTracker(bestFe, fe); + } + ncopies++; + } + } + + if (ncopies) + bestFe->setCopied(); + + return bestFe; +} + +FrameEntry * +FrameState::uncopy(FrameEntry *original) +{ + JS_ASSERT(original->isCopied()); + + /* + * Copies have three critical invariants: + * 1) The backing store precedes all copies in the tracker. + * 2) The backing store precedes all copies in the FrameState. + * 3) The backing store of a copy cannot be popped from the stack + * while the copy is still live. + * + * Maintaining this invariant iteratively is kind of hard, so we choose + * the "lowest" copy in the frame up-front. + * + * For example, if the stack is: + * [A, B, C, D] + * And the tracker has: + * [A, D, C, B] + * + * If B, C, and D are copies of A - we will walk the tracker to the end + * and select B, not D (see bug 583684). + * + * Note: |tracker.nentries <= (nslots + nargs)|. However, this walk is + * sub-optimal if |tracker.nentries - original->trackerIndex() > sp - original|. + * With large scripts this may be a problem worth investigating. Note that + * the tracker is walked twice, so we multiply by 2 for pessimism. + */ + FrameEntry *fe; + if ((tracker.nentries - original->trackerIndex()) * 2 > uint32(sp - original)) + fe = walkFrameForUncopy(original); + else + fe = walkTrackerForUncopy(original); + if (!fe) { + original->setNotCopied(); + return NULL; + } + + /* + * Switch the new backing store to the old backing store. During + * this process we also necessarily make sure the copy can be + * synced. + */ + if (!original->isTypeKnown()) { + /* + * If the copy is unsynced, and the original is in memory, + * give the original a register. We do this below too; it's + * okay if it's spilled. + */ + if (original->type.inMemory() && !fe->type.synced()) + tempRegForType(original); + fe->type.inherit(original->type); + if (fe->type.inRegister()) + regstate[fe->type.reg()].reassociate(fe); + } else { + JS_ASSERT(fe->isTypeKnown()); + JS_ASSERT(fe->getKnownType() == original->getKnownType()); + } + if (original->data.inMemory() && !fe->data.synced()) + tempRegForData(original); + fe->data.inherit(original->data); + if (fe->data.inRegister()) + regstate[fe->data.reg()].reassociate(fe); + + return fe; +} + +void +FrameState::finishStore(FrameEntry *fe, bool closed) +{ + // Make sure the backing store entry is synced to memory, then if it's + // closed, forget it entirely (removing all copies) and reset it to a + // synced, in-memory state. + syncFe(fe); + if (closed) { + if (!fe->isCopy()) + forgetEntry(fe); + fe->resetSynced(); + } +} + +void +FrameState::storeLocal(uint32 n, bool popGuaranteed, bool typeChange) +{ + FrameEntry *local = getLocal(n); + storeTop(local, popGuaranteed, typeChange); + + bool closed = isClosedVar(n); + if (!closed && !inTryBlock) + return; + + finishStore(local, closed); +} + +void +FrameState::storeArg(uint32 n, bool popGuaranteed) +{ + // Note that args are always immediately synced, because they can be + // aliased (but not written to) via f.arguments. + FrameEntry *arg = getArg(n); + storeTop(arg, popGuaranteed, true); + finishStore(arg, isClosedArg(n)); +} + +void +FrameState::forgetEntry(FrameEntry *fe) +{ + if (fe->isCopied()) { + uncopy(fe); + if (!fe->isCopied()) + forgetAllRegs(fe); + } else { + forgetAllRegs(fe); + } +} + +void +FrameState::storeTop(FrameEntry *target, bool popGuaranteed, bool typeChange) +{ + bool wasSynced = target->type.synced(); + /* Detect something like (x = x) which is a no-op. */ + FrameEntry *top = peek(-1); + if (top->isCopy() && top->copyOf() == target) { + JS_ASSERT(target->isCopied()); + return; + } + + /* Completely invalidate the local variable. */ + forgetEntry(target); + target->resetUnsynced(); + + /* Constants are easy to propagate. */ + if (top->isConstant()) { + target->setCopyOf(NULL); + target->setNotCopied(); + target->setConstant(Jsvalify(top->getValue())); + return; + } + + /* + * When dealing with copies, there are three important invariants: + * + * 1) The backing store precedes all copies in the tracker. + * 2) The backing store precedes all copies in the FrameState. + * 2) The backing store of a local is never a stack slot, UNLESS the local + * variable itself is a stack slot (blocks) that precedes the stack + * slot. + * + * If the top is a copy, and the second condition holds true, the local + * can be rewritten as a copy of the original backing slot. If the first + * condition does not hold, force it to hold by swapping in-place. + */ + FrameEntry *backing = top; + bool copied = false; + if (top->isCopy()) { + backing = top->copyOf(); + JS_ASSERT(backing->trackerIndex() < top->trackerIndex()); + + if (backing < target) { + /* local.idx < backing.idx means local cannot be a copy yet */ + if (target->trackerIndex() < backing->trackerIndex()) + swapInTracker(backing, target); + target->setNotCopied(); + target->setCopyOf(backing); + if (backing->isTypeKnown()) + target->setType(backing->getKnownType()); + else + target->type.invalidate(); + target->data.invalidate(); + target->isNumber = backing->isNumber; + return; + } + + /* + * If control flow lands here, then there was a bytecode sequence like + * + * ENTERBLOCK 2 + * GETLOCAL 1 + * SETLOCAL 0 + * + * The problem is slot N can't be backed by M if M could be popped + * before N. We want a guarantee that when we pop M, even if it was + * copied, it has no outstanding copies. + * + * Because of |let| expressions, it's kind of hard to really know + * whether a region on the stack will be popped all at once. Bleh! + * + * This should be rare except in browser code (and maybe even then), + * but even so there's a quick workaround. We take all copies of the + * backing fe, and redirect them to be copies of the destination. + */ + for (uint32 i = backing->trackerIndex() + 1; i < tracker.nentries; i++) { + FrameEntry *fe = tracker[i]; + if (fe >= sp) + continue; + if (fe->isCopy() && fe->copyOf() == backing) { + fe->setCopyOf(target); + copied = true; + } + } + } + backing->setNotCopied(); + + /* + * This is valid from the top->isCopy() path because we're guaranteed a + * consistent ordering - all copies of |backing| are tracked after + * |backing|. Transitively, only one swap is needed. + */ + if (backing->trackerIndex() < target->trackerIndex()) + swapInTracker(backing, target); + + /* + * Move the backing store down - we spill registers here, but we could be + * smarter and re-use the type reg. + */ + RegisterID reg = tempRegForData(backing); + target->data.setRegister(reg); + regstate[reg].reassociate(target); + + if (typeChange) { + if (backing->isTypeKnown()) { + target->setType(backing->getKnownType()); + } else { + RegisterID reg = tempRegForType(backing); + target->type.setRegister(reg); + regstate[reg].reassociate(target); + } + } else { + if (!wasSynced) + masm.storeTypeTag(ImmType(backing->getKnownType()), addressOf(target)); + target->type.setMemory(); + } + + if (!backing->isTypeKnown()) + backing->type.invalidate(); + backing->data.invalidate(); + backing->setCopyOf(target); + backing->isNumber = target->isNumber; + + JS_ASSERT(top->copyOf() == target); + + /* + * Right now, |backing| is a copy of |target| (note the reversal), but + * |target| is not marked as copied. This is an optimization so uncopy() + * may avoid frame traversal. + * + * There are two cases where we must set the copy bit, however: + * - The fixup phase redirected more copies to |target|. + * - An immediate pop is not guaranteed. + */ + if (copied || !popGuaranteed) + target->setCopied(); +} + +void +FrameState::shimmy(uint32 n) +{ + JS_ASSERT(sp - n >= spBase); + int32 depth = 0 - int32(n); + storeTop(peek(depth - 1), true); + popn(n); +} + +void +FrameState::shift(int32 n) +{ + JS_ASSERT(n < 0); + JS_ASSERT(sp + n - 1 >= spBase); + storeTop(peek(n - 1), true); + pop(); +} + +void +FrameState::pinEntry(FrameEntry *fe, ValueRemat &vr) +{ + if (fe->isConstant()) { + vr = ValueRemat::FromConstant(fe->getValue()); + } else { + // Pin the type register so it can't spill. + MaybeRegisterID maybePinnedType = maybePinType(fe); + + // Get and pin the data register. + RegisterID dataReg = tempRegForData(fe); + pinReg(dataReg); + + if (fe->isTypeKnown()) { + vr = ValueRemat::FromKnownType(fe->getKnownType(), dataReg); + } else { + // The type might not be loaded yet, so unpin for simplicity. + maybeUnpinReg(maybePinnedType); + + vr = ValueRemat::FromRegisters(tempRegForType(fe), dataReg); + pinReg(vr.typeReg()); + } + } + + // Set these bits last, since allocation could have caused a sync. + vr.isDataSynced = fe->data.synced(); + vr.isTypeSynced = fe->type.synced(); +} + +void +FrameState::unpinEntry(const ValueRemat &vr) +{ + if (!vr.isConstant()) { + if (!vr.isTypeKnown()) + unpinReg(vr.typeReg()); + unpinReg(vr.dataReg()); + } +} + +void +FrameState::ensureValueSynced(Assembler &masm, FrameEntry *fe, const ValueRemat &vr) +{ +#if defined JS_PUNBOX64 + if (!vr.isDataSynced || !vr.isTypeSynced) + masm.storeValue(vr, addressOf(fe)); +#elif defined JS_NUNBOX32 + if (vr.isConstant()) { + if (!vr.isDataSynced || !vr.isTypeSynced) + masm.storeValue(vr.value(), addressOf(fe)); + } else { + if (!vr.isDataSynced) + masm.storePayload(vr.dataReg(), addressOf(fe)); + if (!vr.isTypeSynced) { + if (vr.isTypeKnown()) + masm.storeTypeTag(ImmType(vr.knownType()), addressOf(fe)); + else + masm.storeTypeTag(vr.typeReg(), addressOf(fe)); + } + } +#endif +} + +static inline bool +AllocHelper(RematInfo &info, MaybeRegisterID &maybe) +{ + if (info.inRegister()) { + maybe = info.reg(); + return true; + } + return false; +} + +void +FrameState::allocForSameBinary(FrameEntry *fe, JSOp op, BinaryAlloc &alloc) +{ + if (!fe->isTypeKnown()) { + alloc.lhsType = tempRegForType(fe); + pinReg(alloc.lhsType.reg()); + } + + alloc.lhsData = tempRegForData(fe); + + if (!freeRegs.empty()) { + alloc.result = allocReg(); + masm.move(alloc.lhsData.reg(), alloc.result); + alloc.lhsNeedsRemat = false; + } else { + alloc.result = alloc.lhsData.reg(); + takeReg(alloc.result); + alloc.lhsNeedsRemat = true; + } + + if (alloc.lhsType.isSet()) + unpinReg(alloc.lhsType.reg()); +} + +void +FrameState::ensureFullRegs(FrameEntry *fe, MaybeRegisterID *type, MaybeRegisterID *data) +{ + fe = fe->isCopy() ? fe->copyOf() : fe; + + JS_ASSERT(!data->isSet() && !type->isSet()); + if (!fe->type.inMemory()) { + if (fe->type.inRegister()) + *type = fe->type.reg(); + if (fe->data.isConstant()) + return; + if (fe->data.inRegister()) { + *data = fe->data.reg(); + return; + } + if (fe->type.inRegister()) + pinReg(fe->type.reg()); + *data = tempRegForData(fe); + if (fe->type.inRegister()) + unpinReg(fe->type.reg()); + } else if (!fe->data.inMemory()) { + if (fe->data.inRegister()) + *data = fe->data.reg(); + if (fe->type.isConstant()) + return; + if (fe->type.inRegister()) { + *type = fe->type.reg(); + return; + } + if (fe->data.inRegister()) + pinReg(fe->data.reg()); + *type = tempRegForType(fe); + if (fe->data.inRegister()) + unpinReg(fe->data.reg()); + } else { + *data = tempRegForData(fe); + pinReg(data->reg()); + *type = tempRegForType(fe); + unpinReg(data->reg()); + } +} + +void +FrameState::allocForBinary(FrameEntry *lhs, FrameEntry *rhs, JSOp op, BinaryAlloc &alloc, + bool needsResult) +{ + FrameEntry *backingLeft = lhs; + FrameEntry *backingRight = rhs; + + if (backingLeft->isCopy()) + backingLeft = backingLeft->copyOf(); + if (backingRight->isCopy()) + backingRight = backingRight->copyOf(); + + /* + * For each remat piece of both FEs, if a register is assigned, get it now + * and pin it. This is safe - constants and known types will be avoided. + */ + if (AllocHelper(backingLeft->type, alloc.lhsType)) + pinReg(alloc.lhsType.reg()); + if (AllocHelper(backingLeft->data, alloc.lhsData)) + pinReg(alloc.lhsData.reg()); + if (AllocHelper(backingRight->type, alloc.rhsType)) + pinReg(alloc.rhsType.reg()); + if (AllocHelper(backingRight->data, alloc.rhsData)) + pinReg(alloc.rhsData.reg()); + + /* For each type without a register, give it a register if needed. */ + if (!alloc.lhsType.isSet() && backingLeft->type.inMemory()) { + alloc.lhsType = tempRegForType(lhs); + pinReg(alloc.lhsType.reg()); + } + if (!alloc.rhsType.isSet() && backingRight->type.inMemory()) { + alloc.rhsType = tempRegForType(rhs); + pinReg(alloc.rhsType.reg()); + } + + bool commu; + switch (op) { + case JSOP_EQ: + case JSOP_GT: + case JSOP_GE: + case JSOP_LT: + case JSOP_LE: + /* fall through */ + case JSOP_ADD: + case JSOP_MUL: + case JSOP_SUB: + commu = true; + break; + + case JSOP_DIV: + commu = false; + break; + + default: + JS_NOT_REACHED("unknown op"); + return; + } + + /* + * Data is a little more complicated. If the op is MUL, not all CPUs + * have multiplication on immediates, so a register is needed. Also, + * if the op is not commutative, the LHS _must_ be in a register. + */ + JS_ASSERT_IF(lhs->isConstant(), !rhs->isConstant()); + JS_ASSERT_IF(rhs->isConstant(), !lhs->isConstant()); + + if (!alloc.lhsData.isSet()) { + if (backingLeft->data.inMemory()) { + alloc.lhsData = tempRegForData(lhs); + pinReg(alloc.lhsData.reg()); + } else if (op == JSOP_MUL || !commu) { + JS_ASSERT(lhs->isConstant()); + alloc.lhsData = allocReg(); + alloc.extraFree = alloc.lhsData; + masm.move(Imm32(lhs->getValue().toInt32()), alloc.lhsData.reg()); + } + } + if (!alloc.rhsData.isSet()) { + if (backingRight->data.inMemory()) { + alloc.rhsData = tempRegForData(rhs); + pinReg(alloc.rhsData.reg()); + } else if (op == JSOP_MUL) { + JS_ASSERT(rhs->isConstant()); + alloc.rhsData = allocReg(); + alloc.extraFree = alloc.rhsData; + masm.move(Imm32(rhs->getValue().toInt32()), alloc.rhsData.reg()); + } + } + + alloc.lhsNeedsRemat = false; + alloc.rhsNeedsRemat = false; + + if (!needsResult) + goto skip; + + /* + * Now a result register is needed. It must contain a mutable copy of the + * LHS. For commutative operations, we can opt to use the RHS instead. At + * this point, if for some reason either must be in a register, that has + * already been guaranteed at this point. + */ + if (!freeRegs.empty()) { + /* Free reg - just grab it. */ + alloc.result = allocReg(); + if (!alloc.lhsData.isSet()) { + JS_ASSERT(alloc.rhsData.isSet()); + JS_ASSERT(commu); + masm.move(alloc.rhsData.reg(), alloc.result); + alloc.resultHasRhs = true; + } else { + masm.move(alloc.lhsData.reg(), alloc.result); + alloc.resultHasRhs = false; + } + } else { + /* + * No free regs. Find a good candidate to re-use. Best candidates don't + * require syncs on the inline path. + */ + bool leftInReg = backingLeft->data.inRegister(); + bool rightInReg = backingRight->data.inRegister(); + bool leftSynced = backingLeft->data.synced(); + bool rightSynced = backingRight->data.synced(); + if (!commu || (leftInReg && (leftSynced || (!rightInReg || !rightSynced)))) { + JS_ASSERT(backingLeft->data.inRegister() || !commu); + JS_ASSERT_IF(backingLeft->data.inRegister(), + backingLeft->data.reg() == alloc.lhsData.reg()); + if (backingLeft->data.inRegister()) { + alloc.result = backingLeft->data.reg(); + unpinReg(alloc.result); + takeReg(alloc.result); + alloc.lhsNeedsRemat = true; + } else { + /* For now, just spill... */ + alloc.result = allocReg(); + masm.move(alloc.lhsData.reg(), alloc.result); + } + alloc.resultHasRhs = false; + } else { + JS_ASSERT(commu); + JS_ASSERT(!leftInReg || (rightInReg && rightSynced)); + alloc.result = backingRight->data.reg(); + unpinReg(alloc.result); + takeReg(alloc.result); + alloc.resultHasRhs = true; + alloc.rhsNeedsRemat = true; + } + } + + skip: + /* Unpin everything that was pinned. */ + if (backingLeft->type.inRegister()) + unpinReg(backingLeft->type.reg()); + if (backingRight->type.inRegister()) + unpinReg(backingRight->type.reg()); + if (backingLeft->data.inRegister()) + unpinReg(backingLeft->data.reg()); + if (backingRight->data.inRegister()) + unpinReg(backingRight->data.reg()); +} + +MaybeRegisterID +FrameState::maybePinData(FrameEntry *fe) +{ + fe = fe->isCopy() ? fe->copyOf() : fe; + if (fe->data.inRegister()) { + pinReg(fe->data.reg()); + return fe->data.reg(); + } + return MaybeRegisterID(); +} + +MaybeRegisterID +FrameState::maybePinType(FrameEntry *fe) +{ + fe = fe->isCopy() ? fe->copyOf() : fe; + if (fe->type.inRegister()) { + pinReg(fe->type.reg()); + return fe->type.reg(); + } + return MaybeRegisterID(); +} + +void +FrameState::maybeUnpinReg(MaybeRegisterID reg) +{ + if (reg.isSet()) + unpinReg(reg.reg()); +} + diff --git a/js/src/methodjit/FrameState.h b/js/src/methodjit/FrameState.h new file mode 100644 index 0000000..c7f214b --- /dev/null +++ b/js/src/methodjit/FrameState.h @@ -0,0 +1,913 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_framestate_h__ && defined JS_METHODJIT +#define jsjaeger_framestate_h__ + +#include "jsapi.h" +#include "methodjit/MachineRegs.h" +#include "methodjit/FrameEntry.h" +#include "CodeGenIncludes.h" +#include "ImmutableSync.h" +#include "jscompartment.h" + +namespace js { +namespace mjit { + +struct Uses { + explicit Uses(uint32 nuses) + : nuses(nuses) + { } + uint32 nuses; +}; + +struct Changes { + explicit Changes(uint32 nchanges) + : nchanges(nchanges) + { } + uint32 nchanges; +}; + +/* + * The FrameState keeps track of values on the frame during compilation. + * The compiler can query FrameState for information about arguments, locals, + * and stack slots (all hereby referred to as "slots"). Slot information can + * be requested in constant time. For each slot there is a FrameEntry *. If + * this is non-NULL, it contains valid information and can be returned. + * + * The register allocator keeps track of registers as being in one of two + * states. These are: + * + * 1) Unowned. Some code in the compiler is working on a register. + * 2) Owned. The FrameState owns the register, and may spill it at any time. + * + * ------------------ Implementation Details ------------------ + * + * Observations: + * + * 1) We totally blow away known information quite often; branches, merge points. + * 2) Every time we need a slow call, we must sync everything. + * 3) Efficient side-exits need to quickly deltize state snapshots. + * 4) Syncing is limited to constants and registers. + * 5) Once a value is tracked, there is no reason to "forget" it until #1. + * + * With these in mind, we want to make sure that the compiler doesn't degrade + * badly as functions get larger. + * + * If the FE is NULL, a new one is allocated, initialized, and stored. They + * are allocated from a pool such that (fe - pool) can be used to compute + * the slot's Address. + * + * We keep a side vector of all tracked FrameEntry * to quickly generate + * memory stores and clear the tracker. + * + * It is still possible to get really bad behavior with a very large script + * that doesn't have branches or calls. That's okay, having this code in + * minimizes damage and lets us introduce a hard cut-off point. + */ +class FrameState +{ + friend class ImmutableSync; + + typedef JSC::MacroAssembler::RegisterID RegisterID; + typedef JSC::MacroAssembler::FPRegisterID FPRegisterID; + typedef JSC::MacroAssembler::Address Address; + typedef JSC::MacroAssembler::Jump Jump; + typedef JSC::MacroAssembler::Imm32 Imm32; + + static const uint32 InvalidIndex = 0xFFFFFFFF; + + struct Tracker { + Tracker() + : entries(NULL), nentries(0) + { } + + void add(FrameEntry *fe) { + entries[nentries++] = fe; + } + + void reset() { + nentries = 0; + } + + FrameEntry * operator [](uint32 n) const { + JS_ASSERT(n < nentries); + return entries[n]; + } + + FrameEntry **entries; + uint32 nentries; + }; + + /* + * Some RegisterState invariants. + * + * If |fe| is non-NULL, |save| is NULL. + * If |save| is non-NULL, |fe| is NULL. + * That is, both |fe| and |save| cannot be non-NULL. + * + * If either |fe| or |save| is non-NULL, the register is not in freeRegs. + * If both |fe| and |save| are NULL, the register is either in freeRegs, + * or owned by the compiler. + */ + struct RegisterState { + RegisterState() : fe_(NULL), save_(NULL) + { } + + RegisterState(FrameEntry *fe, RematInfo::RematType type) + : fe_(fe), save_(NULL), type_(type) + { + JS_ASSERT(!save_); + } + + bool isPinned() const { + assertConsistency(); + return !!save_; + } + + void assertConsistency() const { + JS_ASSERT_IF(fe_, !save_); + JS_ASSERT_IF(save_, !fe_); + } + + FrameEntry *fe() const { + assertConsistency(); + return fe_; + } + + RematInfo::RematType type() const { + assertConsistency(); + return type_; + } + + FrameEntry *usedBy() const { + if (fe_) + return fe_; + return save_; + } + + void associate(FrameEntry *fe, RematInfo::RematType type) { + JS_ASSERT(!fe_); + JS_ASSERT(!save_); + + fe_ = fe; + type_ = type; + JS_ASSERT(!save_); + } + + /* Change ownership. */ + void reassociate(FrameEntry *fe) { + assertConsistency(); + JS_ASSERT(fe); + + fe_ = fe; + } + + /* Unassociate this register from the FE. */ + void forget() { + JS_ASSERT(fe_); + fe_ = NULL; + JS_ASSERT(!save_); + } + + void pin() { + JS_ASSERT(fe_ != NULL); + assertConsistency(); + save_ = fe_; + fe_ = NULL; + } + + void unpin() { + JS_ASSERT(save_ != NULL); + assertConsistency(); + fe_ = save_; + save_ = NULL; + } + + void unpinUnsafe() { + assertConsistency(); + save_ = NULL; + } + + private: + /* FrameEntry owning this register, or NULL if not owned by a frame. */ + FrameEntry *fe_; + + /* Hack - simplifies register allocation for pairs. */ + FrameEntry *save_; + + /* Part of the FrameEntry that owns the FE. */ + RematInfo::RematType type_; + }; + + FrameState *thisFromCtor() { return this; } + public: + FrameState(JSContext *cx, JSScript *script, JSFunction *fun, Assembler &masm); + ~FrameState(); + bool init(); + + /* + * Pushes a synced slot. + */ + inline void pushSynced(); + + /* + * Pushes a slot that has a known, synced type and payload. + */ + inline void pushSyncedType(JSValueType type); + + /* + * Pushes a slot that has a known, synced type and payload. + */ + inline void pushSynced(JSValueType type, RegisterID reg); + + /* + * Pushes a constant value. + */ + inline void push(const Value &v); + + /* + * Loads a value from memory and pushes it. + */ + inline void push(Address address); + + /* + * Pushes a known type and allocated payload onto the operation stack. + */ + inline void pushTypedPayload(JSValueType type, RegisterID payload); + + /* + * Pushes a type register and data register pair. + */ + inline void pushRegs(RegisterID type, RegisterID data); + + /* + * Pushes a known type and allocated payload onto the operation stack. + * This must be used when the type is known, but cannot be propagated + * because it is not known to be correct at a slow-path merge point. + * + * The caller guarantees that the tag was a fast-path check; that is, + * the value it replaces on the stack had the same tag if the fast-path + * was taken. + */ + inline void pushUntypedPayload(JSValueType type, RegisterID payload); + + /* + * Pushes a value onto the operation stack. This must be used when the + * value is known, but its type cannot be propagated because it is not + * known to be correct at a slow-path merge point. + */ + inline void pushUntypedValue(const Value &value); + + /* + * Pushes a number onto the operation stack. + * + * If asInt32 is set to true, then the FS will attempt to optimize + * syncing the type as int32. Only use this parameter when the fast-path + * guaranteed that the stack slot was guarded to be an int32 originally. + * + * For example, checking LHS and RHS as ints guarantees that if the LHS + * was synced, then popping both and pushing a maybe-int32 does not need + * to be synced. + */ + inline void pushNumber(MaybeRegisterID payload, bool asInt32 = false); + + /* + * Pushes an int32 onto the operation stack. This is a specialized version + * of pushNumber. The caller must guarantee that (a) an int32 is to be + * pushed on the inline path, and (b) if any slow path pushes a double, + * the slow path also stores the double to memory. + */ + inline void pushInt32(RegisterID payload); + + /* + * Pushes an initializer with specified payload, storing whether it is an array + * or object whose contents can be initialized in fast paths. + */ + inline void pushInitializerObject(RegisterID payload, bool array, JSObject *baseobj); + + /* + * Pops a value off the operation stack, freeing any of its resources. + */ + inline void pop(); + + /* + * Pops a number of values off the operation stack, freeing any of their + * resources. + */ + inline void popn(uint32 n); + + /* + * Returns true iff lhs and rhs are copies of the same FrameEntry. + */ + inline bool haveSameBacking(FrameEntry *lhs, FrameEntry *rhs); + + /* + * Temporarily increase and decrease local variable depth. + */ + inline void enterBlock(uint32 n); + inline void leaveBlock(uint32 n); + + // Pushes a copy of a slot (formal argument, local variable, or stack slot) + // onto the operation stack. + void pushLocal(uint32 n); + void pushArg(uint32 n); + void pushCallee(); + void pushThis(); + inline void learnThisIsObject(); + + /* + * Allocates a temporary register for a FrameEntry's type. The register + * can be spilled or clobbered by the frame. The compiler may only operate + * on it temporarily, and must take care not to clobber it. + */ + inline RegisterID tempRegForType(FrameEntry *fe); + + /* + * Try to use a register already allocated for fe's type, but if one + * is not already available, use fallback. + * + * Note: this does NOT change fe's type-register remat info. It's supposed + * to be a super lightweight/transparent operation. + */ + inline RegisterID tempRegForType(FrameEntry *fe, RegisterID fallback); + + /* + * Returns a register that is guaranteed to contain the frame entry's + * data payload. The compiler may not modify the contents of the register. + * The compiler should NOT explicitly free it. + */ + inline RegisterID tempRegForData(FrameEntry *fe); + + /* + * Same as above, except register must match identically. + */ + inline RegisterID tempRegInMaskForData(FrameEntry *fe, uint32 mask); + + /* + * Same as above, except loads into reg (using masm) if the entry does not + * already have a register, and does not change the frame state in doing so. + */ + inline RegisterID tempRegForData(FrameEntry *fe, RegisterID reg, Assembler &masm) const; + + /* + * Convert an integer to a double without applying + * additional Register pressure. + */ + inline void convertInt32ToDouble(Assembler &masm, FrameEntry *fe, + FPRegisterID fpreg) const; + + /* + * Dive into a FrameEntry and check whether it's in a register. + */ + inline bool peekTypeInRegister(FrameEntry *fe) const; + + /* + * Allocates a register for a FrameEntry's data, such that the compiler + * can modify it in-place. + * + * The caller guarantees the FrameEntry will not be observed again. This + * allows the compiler to avoid spilling. Only call this if the FE is + * going to be popped before stubcc joins/guards or the end of the current + * opcode. + */ + RegisterID ownRegForData(FrameEntry *fe); + + /* + * Allocates a register for a FrameEntry's type, such that the compiler + * can modify it in-place. + * + * The caller guarantees the FrameEntry will not be observed again. This + * allows the compiler to avoid spilling. Only call this if the FE is + * going to be popped before stubcc joins/guards or the end of the current + * opcode. + */ + RegisterID ownRegForType(FrameEntry *fe); + + /* + * Allocates a register for a FrameEntry's data, such that the compiler + * can modify it in-place. The actual FE is not modified. + */ + RegisterID copyDataIntoReg(FrameEntry *fe); + void copyDataIntoReg(FrameEntry *fe, RegisterID exact); + RegisterID copyDataIntoReg(Assembler &masm, FrameEntry *fe); + + /* + * Allocates a FPRegister for a FrameEntry, such that the compiler + * can modify it in-place. The FrameState is not modified. + */ + FPRegisterID copyEntryIntoFPReg(FrameEntry *fe, FPRegisterID fpreg); + FPRegisterID copyEntryIntoFPReg(Assembler &masm, FrameEntry *fe, + FPRegisterID fpreg); + + /* + * Allocates a register for a FrameEntry's type, such that the compiler + * can modify it in-place. The actual FE is not modified. + */ + RegisterID copyTypeIntoReg(FrameEntry *fe); + + /* + * Returns a register that contains the constant Int32 value of the + * frame entry's data payload. + * Since the register is not bound to a FrameEntry, + * it MUST be explicitly freed with freeReg(). + */ + RegisterID copyInt32ConstantIntoReg(FrameEntry *fe); + RegisterID copyInt32ConstantIntoReg(Assembler &masm, FrameEntry *fe); + + /* + * Gets registers for the components of fe where needed, + * pins them and stores into vr. + */ + void pinEntry(FrameEntry *fe, ValueRemat &vr); + + /* Unpins registers from a call to pinEntry. */ + void unpinEntry(const ValueRemat &vr); + + /* Syncs fe to memory, given its state as constructed by a call to pinEntry. */ + void ensureValueSynced(Assembler &masm, FrameEntry *fe, const ValueRemat &vr); + + struct BinaryAlloc { + MaybeRegisterID lhsType; + MaybeRegisterID lhsData; + MaybeRegisterID rhsType; + MaybeRegisterID rhsData; + MaybeRegisterID extraFree; + RegisterID result; // mutable result reg + bool resultHasRhs; // whether the result has the RHS instead of the LHS + bool lhsNeedsRemat; // whether LHS needs memory remat + bool rhsNeedsRemat; // whether RHS needs memory remat + }; + + /* + * Ensures that the two given FrameEntries have registers for both their + * type and data. The register allocations are returned in a struct. + * + * One mutable register is allocated as well, holding the LHS payload. If + * this would cause a spill that could be avoided by using a mutable RHS, + * and the operation is commutative, then the resultHasRhs is set to true. + */ + void allocForBinary(FrameEntry *lhs, FrameEntry *rhs, JSOp op, BinaryAlloc &alloc, + bool resultNeeded = true); + + /* Ensures that an FE has both type and data remat'd in registers. */ + void ensureFullRegs(FrameEntry *fe, MaybeRegisterID *typeReg, MaybeRegisterID *dataReg); + + /* + * Similar to allocForBinary, except works when the LHS and RHS have the + * same backing FE. Only a reduced subset of BinaryAlloc is used: + * lhsType + * lhsData + * result + * lhsNeedsRemat + */ + void allocForSameBinary(FrameEntry *fe, JSOp op, BinaryAlloc &alloc); + + /* Loads an FE into an fp reg. */ + inline void loadDouble(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const; + + /* + * Slightly more specialized version when more precise register + * information is known. + */ + inline void loadDouble(RegisterID type, RegisterID data, FrameEntry *fe, FPRegisterID fpReg, + Assembler &masm) const; + + /* + * Types don't always have to be in registers, sometimes the compiler + * can use addresses and avoid spilling. If this FrameEntry has a synced + * address and no register, this returns true. + */ + inline bool shouldAvoidTypeRemat(FrameEntry *fe); + + /* + * Payloads don't always have to be in registers, sometimes the compiler + * can use addresses and avoid spilling. If this FrameEntry has a synced + * address and no register, this returns true. + */ + inline bool shouldAvoidDataRemat(FrameEntry *fe); + + /* + * Frees a temporary register. If this register is being tracked, then it + * is not spilled; the backing data becomes invalidated! + */ + inline void freeReg(RegisterID reg); + + /* + * Allocates a register. If none are free, one may be spilled from the + * tracker. If there are none available for spilling in the tracker, + * then this is considered a compiler bug and an assert will fire. + */ + inline RegisterID allocReg(); + + /* + * Allocates a register, except using a mask. + */ + inline RegisterID allocReg(uint32 mask); + + /* + * Allocates a specific register, evicting it if it's not avaliable. + */ + void takeReg(RegisterID reg); + + /* + * Returns a FrameEntry * for a slot on the operation stack. + */ + inline FrameEntry *peek(int32 depth); + + /* + * Fully stores a FrameEntry at an arbitrary address. popHint specifies + * how hard the register allocator should try to keep the FE in registers. + */ + void storeTo(FrameEntry *fe, Address address, bool popHint = false); + + /* + * Fully stores a FrameEntry into two arbitrary registers. tempReg may be + * used as a temporary. + */ + void loadForReturn(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg); + void loadThisForReturn(RegisterID typeReg, RegisterID dataReg, RegisterID tempReg); + + /* + * Stores the top stack slot back to a slot. + */ + void storeLocal(uint32 n, bool popGuaranteed = false, bool typeChange = true); + void storeArg(uint32 n, bool popGuaranteed = false); + void storeTop(FrameEntry *target, bool popGuaranteed = false, bool typeChange = true); + void finishStore(FrameEntry *fe, bool closed); + + /* + * Restores state from a slow path. + */ + void merge(Assembler &masm, Changes changes) const; + + /* + * Writes unsynced stores to an arbitrary buffer. + */ + void sync(Assembler &masm, Uses uses) const; + + /* + * Syncs all outstanding stores to memory and possibly kills regs in the + * process. The top [ignored..uses-1] frame entries will be synced. + */ + void syncAndKill(Registers kill, Uses uses, Uses ignored); + void syncAndKill(Registers kill, Uses uses) { syncAndKill(kill, uses, Uses(0)); } + + /* Syncs and kills everything. */ + void syncAndKillEverything() { + syncAndKill(Registers(Registers::AvailRegs), Uses(frameSlots())); + } + + /* + * Clear all tracker entries, syncing all outstanding stores in the process. + * The stack depth is in case some merge points' edges did not immediately + * precede the current instruction. + */ + inline void syncAndForgetEverything(uint32 newStackDepth); + + /* + * Same as above, except the stack depth is not changed. This is used for + * branching opcodes. + */ + void syncAndForgetEverything(); + + /* + * Throw away the entire frame state, without syncing anything. + * This can only be called after a syncAndKill() against all registers. + */ + void forgetEverything(); + + /* + * Discard the entire framestate forcefully. + */ + void discardFrame(); + + /* + * Mark an existing slot with a type. + */ + inline void learnType(FrameEntry *fe, JSValueType type); + + /* + * Forget a type, syncing in the process. + */ + inline void forgetType(FrameEntry *fe); + + /* + * Discards a FrameEntry, tricking the FS into thinking it's synced. + */ + void discardFe(FrameEntry *fe); + + /* + * Helper function. Tests if a slot's type is null. Condition must + * be Equal or NotEqual. + */ + inline Jump testNull(Assembler::Condition cond, FrameEntry *fe); + + /* + * Helper function. Tests if a slot's type is undefined. Condition must + * be Equal or NotEqual. + */ + inline Jump testUndefined(Assembler::Condition cond, FrameEntry *fe); + + /* + * Helper function. Tests if a slot's type is an integer. Condition must + * be Equal or NotEqual. + */ + inline Jump testInt32(Assembler::Condition cond, FrameEntry *fe); + + /* + * Helper function. Tests if a slot's type is a double. Condition must + * be Equal or Not Equal. + */ + inline Jump testDouble(Assembler::Condition cond, FrameEntry *fe); + + /* + * Helper function. Tests if a slot's type is a boolean. Condition must + * be Equal or NotEqual. + */ + inline Jump testBoolean(Assembler::Condition cond, FrameEntry *fe); + + /* + * Helper function. Tests if a slot's type is a string. Condition must + * be Equal or NotEqual. + */ + inline Jump testString(Assembler::Condition cond, FrameEntry *fe); + + /* + * Helper function. Tests if a slot's type is a non-funobj. Condition must + * be Equal or NotEqual. + */ + inline Jump testObject(Assembler::Condition cond, FrameEntry *fe); + + /* + * Helper function. Tests if a slot's type is primitive. Condition must + * be Equal or NotEqual. + */ + inline Jump testPrimitive(Assembler::Condition cond, FrameEntry *fe); + + /* + * Marks a register such that it cannot be spilled by the register + * allocator. Any pinned registers must be unpinned at the end of the op, + * no matter what. In addition, pinReg() can only be used on registers + * which are associated with FrameEntries. + */ + inline void pinReg(RegisterID reg); + + /* + * Unpins a previously pinned register. + */ + inline void unpinReg(RegisterID reg); + + /* + * Same as unpinReg(), but does not restore the FrameEntry. + */ + inline void unpinKilledReg(RegisterID reg); + + /* Pins a data or type register if one exists. */ + MaybeRegisterID maybePinData(FrameEntry *fe); + MaybeRegisterID maybePinType(FrameEntry *fe); + void maybeUnpinReg(MaybeRegisterID reg); + + /* + * Dups the top item on the stack. + */ + inline void dup(); + + /* + * Dups the top 2 items on the stack. + */ + inline void dup2(); + + /* + * Dups an item n-deep in the stack. n must be < 0 + */ + inline void dupAt(int32 n); + + /* + * If the frameentry is a copy, give it its own registers. + * This may only be called on the topmost fe. + */ + inline void giveOwnRegs(FrameEntry *fe); + + uint32 stackDepth() const { return sp - spBase; } + + // Returns the number of entries in the frame, that is: + // 2 for callee, this + + // nargs + + // nfixed + + // currently pushed stack slots + uint32 frameSlots() const { return uint32(sp - entries); } + + // Returns the number of local variables and active stack slots. + uint32 localSlots() const { return uint32(sp - locals); } + +#ifdef DEBUG + void assertValidRegisterState() const; +#endif + + // Return an address, relative to the JSStackFrame, that represents where + // this FrameEntry is stored in memory. Note that this is its canonical + // address, not its backing store. There is no guarantee that the memory + // is coherent. + Address addressOf(const FrameEntry *fe) const; + + // Returns an address, relative to the JSStackFrame, that represents where + // this FrameEntry is backed in memory. This is not necessarily its + // canonical address, but the address for which the payload has been synced + // to memory. The caller guarantees that the payload has been synced. + Address addressForDataRemat(const FrameEntry *fe) const; + + inline StateRemat dataRematInfo(const FrameEntry *fe) const; + + /* + * This is similar to freeReg(ownRegForData(fe)) - except no movement takes place. + * The fe is simply invalidated as if it were popped. This can be used to free + * registers in the working area of the stack. Obviously, this can only be called + * in infallible code that will pop these entries soon after. + */ + inline void eviscerate(FrameEntry *fe); + + /* + * Moves the top of the stack down N slots, popping each item above it. + * Caller guarantees the slots below have been observed and eviscerated. + */ + void shimmy(uint32 n); + + /* + * Stores the top item on the stack to a stack slot, count down from the + * current stack depth. For example, to move the top (-1) to -3, you would + * call shift(-2). + */ + void shift(int32 n); + + // Notifies the frame that a local variable or argument slot is closed over. + inline void setClosedVar(uint32 slot); + inline void setClosedArg(uint32 slot); + + inline void setInTryBlock(bool inTryBlock) { + this->inTryBlock = inTryBlock; + } + + inline uint32 regsInUse() const { return Registers::AvailRegs & ~freeRegs.freeMask; } + + private: + inline RegisterID allocReg(FrameEntry *fe, RematInfo::RematType type); + inline void forgetReg(RegisterID reg); + RegisterID evictSomeReg(uint32 mask); + void evictReg(RegisterID reg); + inline FrameEntry *rawPush(); + inline void addToTracker(FrameEntry *fe); + + /* Guarantee sync, but do not set any sync flag. */ + inline void ensureFeSynced(const FrameEntry *fe, Assembler &masm) const; + inline void ensureTypeSynced(const FrameEntry *fe, Assembler &masm) const; + inline void ensureDataSynced(const FrameEntry *fe, Assembler &masm) const; + + /* Guarantee sync, even if register allocation is required, and set sync. */ + inline void syncFe(FrameEntry *fe); + inline void syncType(FrameEntry *fe); + inline void syncData(FrameEntry *fe); + + inline FrameEntry *getOrTrack(uint32 index); + inline FrameEntry *getLocal(uint32 slot); + inline FrameEntry *getArg(uint32 slot); + inline FrameEntry *getCallee(); + inline FrameEntry *getThis(); + inline void forgetAllRegs(FrameEntry *fe); + inline void swapInTracker(FrameEntry *lhs, FrameEntry *rhs); + void pushCopyOf(uint32 index); +#if defined JS_NUNBOX32 + void syncFancy(Assembler &masm, Registers avail, FrameEntry *resumeAt, + FrameEntry *bottom) const; +#endif + inline bool tryFastDoubleLoad(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const; + void resetInternalState(); + + /* + * "Uncopies" the backing store of a FrameEntry that has been copied. The + * original FrameEntry is not invalidated; this is the responsibility of + * the caller. The caller can check isCopied() to see if the registers + * were moved to a copy. + * + * Later addition: uncopy() returns the first copy found. + */ + FrameEntry *uncopy(FrameEntry *original); + FrameEntry *walkTrackerForUncopy(FrameEntry *original); + FrameEntry *walkFrameForUncopy(FrameEntry *original); + + /* + * All registers in the FE are forgotten. If it is copied, it is uncopied + * beforehand. + */ + void forgetEntry(FrameEntry *fe); + + FrameEntry *entryFor(uint32 index) const { + JS_ASSERT(entries[index].isTracked()); + return &entries[index]; + } + + RegisterID evictSomeReg() { return evictSomeReg(Registers::AvailRegs); } + uint32 indexOf(int32 depth) const { + JS_ASSERT(uint32((sp + depth) - entries) < feLimit()); + return uint32((sp + depth) - entries); + } + uint32 indexOfFe(FrameEntry *fe) const { + JS_ASSERT(uint32(fe - entries) < feLimit()); + return uint32(fe - entries); + } + uint32 feLimit() const { return script->nslots + nargs + 2; } + + inline bool isClosedVar(uint32 slot); + inline bool isClosedArg(uint32 slot); + + private: + JSContext *cx; + JSScript *script; + JSFunction *fun; + uint32 nargs; + Assembler &masm; + + /* All allocated registers. */ + Registers freeRegs; + + /* Cache of FrameEntry objects. */ + FrameEntry *entries; + + FrameEntry *callee_; + FrameEntry *this_; + + /* Base pointer for arguments. */ + FrameEntry *args; + + /* Base pointer for local variables. */ + FrameEntry *locals; + + /* Base pointer for the stack. */ + FrameEntry *spBase; + + /* Dynamic stack pointer. */ + FrameEntry *sp; + + /* Vector of tracked slot indexes. */ + Tracker tracker; + + /* + * Register ownership state. This can't be used alone; to find whether an + * entry is active, you must check the allocated registers. + */ + RegisterState regstate[Assembler::TotalRegisters]; + +#if defined JS_NUNBOX32 + mutable ImmutableSync reifier; +#endif + + JSPackedBool *closedVars; + JSPackedBool *closedArgs; + bool eval; + bool usesArguments; + bool inTryBlock; +}; + +class AutoPreserveAcrossSyncAndKill; + +} /* namespace mjit */ +} /* namespace js */ + +#endif /* jsjaeger_framestate_h__ */ + diff --git a/js/src/methodjit/ICChecker.h b/js/src/methodjit/ICChecker.h new file mode 100644 index 0000000..01119bf --- /dev/null +++ b/js/src/methodjit/ICChecker.h @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Mandelin + * David Anderson + * Chris Leary + * Jacob Bramley + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_icchecker_h__ && defined JS_METHODJIT +#define jsjaeger_icchecker_h__ + +#include "assembler/assembler/MacroAssembler.h" + +namespace js { +namespace mjit { + +#if defined DEBUG && defined JS_CPU_ARM +static inline void +CheckInstMask(void *addr, uint32 mask, uint32 expected) +{ + uint32 inst = *static_cast(addr); + JS_ASSERT((inst & mask) == expected); +} + +static inline void +CheckIsLDR(JSC::CodeLocationLabel label, uint8 rd) +{ + JS_ASSERT((rd & 0xf) == rd); + CheckInstMask(label.executableAddress(), 0xfc50f000, 0xe4100000 | (rd << 12)); +} + +static inline void +CheckIsBLX(JSC::CodeLocationLabel label, uint8 rsrc) +{ + JS_ASSERT((rsrc & 0xf) == rsrc); + CheckInstMask(label.executableAddress(), 0xfff000ff, 0xe1200030 | rsrc); +} + +static inline void +CheckIsStubCall(JSC::CodeLocationLabel label) +{ + CheckIsLDR(label.labelAtOffset(-4), JSC::ARMRegisters::ip); + CheckIsLDR(label.labelAtOffset(0), JSC::ARMRegisters::r8); + CheckIsBLX(label.labelAtOffset(4), JSC::ARMRegisters::r8); +} +#else +static inline void CheckIsStubCall(JSC::CodeLocationLabel label) {} +#endif + +} /* namespace mjit */ +} /* namespace js */ + +#endif diff --git a/js/src/methodjit/ICLabels.h b/js/src/methodjit/ICLabels.h new file mode 100644 index 0000000..cddcf7a --- /dev/null +++ b/js/src/methodjit/ICLabels.h @@ -0,0 +1,508 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Mandelin + * David Anderson + * Chris Leary + * Jacob Bramley + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_ic_labels_h__ && defined JS_METHODJIT +#define jsjaeger_ic_labels_h__ + +#include "methodjit/BaseCompiler.h" + +class ICOffsetInitializer { + public: + ICOffsetInitializer(); +}; + +namespace js { +namespace mjit { +namespace ic { + +/* + * On x64 and ARM, we record offsets into the labels data structures at runtime + * instead of using hardcoded offsets into the instruction stream, as we do on + * x86. + * + * This is done on x64 because of variable-width instruction encoding when + * using the extended register set. It is done on ARM for ease of + * implementation. + */ + +#if defined JS_CPU_X64 || defined JS_CPU_ARM +# define JS_HAS_IC_LABELS +#endif + +/* GetPropCompiler */ +struct GetPropLabels : MacroAssemblerTypedefs { + friend class ::ICOffsetInitializer; + + void setValueLoad(MacroAssembler &masm, Label fastPathRejoin, Label fastValueLoad) { + int offset = masm.differenceBetween(fastPathRejoin, fastValueLoad); +#ifdef JS_HAS_IC_LABELS + inlineValueLoadOffset = offset; +#endif + /* + * Note: the offset between the type and data loads for x86 is asserted + * in NunboxAssembler::loadValueWithAddressOffsetPatch. + */ + JS_ASSERT(offset == inlineValueLoadOffset); + (void) offset; + } + + CodeLocationLabel getValueLoad(CodeLocationLabel fastPathRejoin) { + return fastPathRejoin.labelAtOffset(inlineValueLoadOffset); + } + + void setDslotsLoad(MacroAssembler &masm, Label fastPathRejoin, Label dslotsLoad) { + int offset = masm.differenceBetween(fastPathRejoin, dslotsLoad); + setDslotsLoadOffset(offset); + } + + CodeLocationInstruction getDslotsLoad(CodeLocationLabel fastPathRejoin) { + return fastPathRejoin.instructionAtOffset(getDslotsLoadOffset()); + } + + void setInlineShapeData(MacroAssembler &masm, Label shapeGuard, DataLabel32 inlineShape) { + int offset = masm.differenceBetween(shapeGuard, inlineShape); + setInlineShapeOffset(offset); + } + + CodeLocationDataLabel32 getInlineShapeData(CodeLocationLabel fastShapeGuard) { + return fastShapeGuard.dataLabel32AtOffset(getInlineShapeOffset()); + } + + /* + * Note: on x64, the base is the inlineShapeLabel DataLabel32, whereas on other + * platforms the base is the shapeGuard. + */ + template + void setInlineShapeJump(MacroAssembler &masm, T base, Label afterJump) { + setInlineShapeJumpOffset(masm.differenceBetween(base, afterJump)); + } + + CodeLocationJump getInlineShapeJump(CodeLocationLabel fastShapeGuard) { + return fastShapeGuard.jumpAtOffset(getInlineShapeJumpOffset()); + } + + void setInlineTypeJump(MacroAssembler &masm, Label fastPathStart, Label afterTypeJump) { + int offset = masm.differenceBetween(fastPathStart, afterTypeJump); + setInlineTypeJumpOffset(offset); + } + + CodeLocationJump getInlineTypeJump(CodeLocationLabel fastPathStart) { + return fastPathStart.jumpAtOffset(getInlineTypeJumpOffset()); + } + + void setStubShapeJump(MacroAssembler &masm, Label stubStart, Label shapeJump) { + int offset = masm.differenceBetween(stubStart, shapeJump); + setStubShapeJumpOffset(offset); + } + + /* Offset-based interface */ + + void setDslotsLoadOffset(int offset) { +#ifdef JS_HAS_IC_LABELS + dslotsLoadOffset = offset; +#endif + JS_ASSERT(offset == dslotsLoadOffset); + } + + void setInlineShapeOffset(int offset) { +#ifdef JS_HAS_IC_LABELS + inlineShapeOffset = offset; +#endif + JS_ASSERT(offset == inlineShapeOffset); + } + + void setStubShapeJumpOffset(int offset) { +#ifdef JS_HAS_IC_LABELS + stubShapeJumpOffset = offset; +#endif + JS_ASSERT(offset == stubShapeJumpOffset); + } + + int getInlineShapeJumpOffset() { +#if defined JS_CPU_X64 + return getInlineShapeOffset() + INLINE_SHAPE_JUMP; +#else + return POST_INST_OFFSET(INLINE_SHAPE_JUMP); +#endif + } + + void setInlineShapeJumpOffset(int offset) { + JS_ASSERT(INLINE_SHAPE_JUMP == offset); + } + + int getInlineTypeJumpOffset() { +#if defined JS_CPU_X86 || defined JS_CPU_X64 + return INLINE_TYPE_JUMP; +#elif defined JS_CPU_ARM + return POST_INST_OFFSET(inlineTypeJumpOffset); +#endif + } + + void setInlineTypeJumpOffset(int offset) { +#if defined JS_CPU_X86 || defined JS_CPU_X64 + JS_ASSERT(INLINE_TYPE_JUMP == offset); +#elif defined JS_CPU_ARM + inlineTypeJumpOffset = offset; + JS_ASSERT(offset == inlineTypeJumpOffset); +#endif + } + + int getInlineShapeOffset() { + return inlineShapeOffset; + } + int getDslotsLoadOffset() { + return dslotsLoadOffset; + } + int getStubShapeJumpOffset() { + return POST_INST_OFFSET(stubShapeJumpOffset); + } + + private: + /* Offset from storeBack to beginning of 'mov dslots, addr' */ + int32 dslotsLoadOffset : 8; + + /* Offset from shapeGuard to end of shape comparison. */ + int32 inlineShapeOffset : 8; + + /* Offset from storeBack to end of value load. */ + int32 inlineValueLoadOffset : 8; + + /* + * Offset from lastStubStart to end of shape jump. + * TODO: We can redefine the location of lastStubStart to be + * after the jump -- at which point this is always 0. + */ + int32 stubShapeJumpOffset : 8; + +#if defined JS_CPU_X86 + static const int32 INLINE_SHAPE_JUMP = 12; + static const int32 INLINE_TYPE_JUMP = 12; +#elif defined JS_CPU_X64 + static const int32 INLINE_SHAPE_JUMP = 6; + static const int32 INLINE_TYPE_JUMP = 19; +#elif defined JS_CPU_ARM + /* Offset from the shape guard start to the shape guard jump. */ + static const int32 INLINE_SHAPE_JUMP = 12; + + /* Offset from the fast path to the type guard jump. */ + int32 inlineTypeJumpOffset : 8; +#endif +}; + +/* SetPropCompiler */ +struct SetPropLabels : MacroAssemblerTypedefs { + friend class ::ICOffsetInitializer; + + void setInlineValueStore(MacroAssembler &masm, Label fastPathRejoin, DataLabel32 inlineValueStore, + const ValueRemat &vr) { + int offset = masm.differenceBetween(fastPathRejoin, inlineValueStore); + setInlineValueStoreOffset(offset, vr.isConstant(), vr.isTypeKnown()); + } + + CodeLocationLabel getInlineValueStore(CodeLocationLabel fastPathRejoin, const ValueRemat &vr) { + return fastPathRejoin.labelAtOffset(getInlineValueStoreOffset(vr.isConstant(), + vr.isTypeKnown())); + } + + void setInlineShapeData(MacroAssembler &masm, Label shapeGuard, DataLabel32 inlineShapeData) { + int offset = masm.differenceBetween(shapeGuard, inlineShapeData); + setInlineShapeDataOffset(offset); + } + + CodeLocationDataLabel32 getInlineShapeData(CodeLocationLabel fastPathStart, int shapeGuardOffset) { + return fastPathStart.dataLabel32AtOffset(shapeGuardOffset + getInlineShapeDataOffset()); + } + + void setDslotsLoad(MacroAssembler &masm, Label fastPathRejoin, Label beforeLoad, + const ValueRemat &rhs) { + int offset = masm.differenceBetween(fastPathRejoin, beforeLoad); + setDslotsLoadOffset(offset, rhs.isConstant(), rhs.isTypeKnown()); + } + + CodeLocationInstruction getDslotsLoad(CodeLocationLabel fastPathRejoin, const ValueRemat &vr) { + return fastPathRejoin.instructionAtOffset(getDslotsLoadOffset(vr)); + } + + void setInlineShapeJump(MacroAssembler &masm, Label shapeGuard, Label afterJump) { + setInlineShapeJumpOffset(masm.differenceBetween(shapeGuard, afterJump)); + } + + CodeLocationJump getInlineShapeJump(CodeLocationLabel shapeGuard) { + return shapeGuard.jumpAtOffset(getInlineShapeJumpOffset()); + } + + void setStubShapeJump(MacroAssembler &masm, Label stubStart, Label afterShapeJump) { + int offset = masm.differenceBetween(stubStart, afterShapeJump); + setStubShapeJumpOffset(offset); + } + + CodeLocationJump getStubShapeJump(CodeLocationLabel stubStart) { + return stubStart.jumpAtOffset(getStubShapeJumpOffset()); + } + + private: + + /* Offset-based interface. */ + + void setDslotsLoadOffset(int offset, bool isConstant, bool isTypeKnown) { +#if defined JS_HAS_IC_LABELS + dslotsLoadOffset = offset; + JS_ASSERT(offset == dslotsLoadOffset); +#elif defined JS_CPU_X86 + JS_ASSERT_IF(isConstant, offset == INLINE_DSLOTS_BEFORE_CONSTANT); + JS_ASSERT_IF(isTypeKnown && !isConstant, offset == INLINE_DSLOTS_BEFORE_KTYPE); + JS_ASSERT_IF(!isTypeKnown, offset == INLINE_DSLOTS_BEFORE_DYNAMIC); +#else +# error +#endif + } + + int getDslotsLoadOffset(const ValueRemat &vr) { +#if defined JS_CPU_X86 + if (vr.isConstant()) + return INLINE_DSLOTS_BEFORE_CONSTANT; + if (vr.isTypeKnown()) + return INLINE_DSLOTS_BEFORE_KTYPE; + return INLINE_DSLOTS_BEFORE_DYNAMIC; +#else + (void) vr; + return dslotsLoadOffset; +#endif + } + + void setInlineShapeDataOffset(int offset) { +#ifdef JS_HAS_IC_LABELS + inlineShapeDataOffset = offset; +#endif + JS_ASSERT(offset == inlineShapeDataOffset); + } + + void setStubShapeJumpOffset(int offset) { +#ifdef JS_HAS_IC_LABELS + stubShapeJumpOffset = offset; +#endif + JS_ASSERT(offset == stubShapeJumpOffset); + } + + void setInlineValueStoreOffset(int offset, bool isConstant, bool isTypeKnown) { +#ifdef JS_HAS_IC_LABELS + inlineValueStoreOffset = offset; + JS_ASSERT(offset == inlineValueStoreOffset); +#elif defined JS_CPU_X86 + JS_ASSERT_IF(isConstant, offset == INLINE_VALUE_STORE_CONSTANT); + JS_ASSERT_IF(isTypeKnown && !isConstant, offset == INLINE_VALUE_STORE_KTYPE); + JS_ASSERT_IF(!isTypeKnown && !isConstant, offset == INLINE_VALUE_STORE_DYNAMIC); +#endif + } + + void setInlineShapeJumpOffset(int offset) { +#ifdef JS_HAS_IC_LABELS + inlineShapeJumpOffset = offset; +#endif + JS_ASSERT(offset == inlineShapeJumpOffset); + } + + int getInlineShapeJumpOffset() { + return POST_INST_OFFSET(inlineShapeJumpOffset); + } + + int getInlineShapeDataOffset() { + return inlineShapeDataOffset; + } + + int getStubShapeJumpOffset() { + return POST_INST_OFFSET(stubShapeJumpOffset); + } + + int getInlineValueStoreOffset(bool isConstant, bool isTypeKnown) { +#ifdef JS_HAS_IC_LABELS + return inlineValueStoreOffset; +#elif defined JS_CPU_X86 + if (isConstant) + return INLINE_VALUE_STORE_CONSTANT; + else if (isTypeKnown) + return INLINE_VALUE_STORE_KTYPE; + else + return INLINE_VALUE_STORE_DYNAMIC; +#endif + } + + /* Offset from storeBack to beginning of 'mov dslots, addr'. */ +#if defined JS_CPU_X86 + static const int INLINE_DSLOTS_BEFORE_CONSTANT = -23; + static const int INLINE_DSLOTS_BEFORE_KTYPE = -19; + static const int INLINE_DSLOTS_BEFORE_DYNAMIC = -15; +#else + int32 dslotsLoadOffset : 8; +#endif + + /* Offset from shapeGuard to end of shape comparison. */ + int32 inlineShapeDataOffset : 8; + + /* + * Offset from lastStubStart to end of shape jump. + * TODO: We can redefine the location of lastStubStart to be + * after the jump -- at which point this is always 0. + */ + int32 stubShapeJumpOffset : 8; + +#if defined JS_CPU_X86 + static const int INLINE_VALUE_STORE_CONSTANT = -20; + static const int INLINE_VALUE_STORE_KTYPE = -16; + static const int INLINE_VALUE_STORE_DYNAMIC = -12; +#else + int32 inlineValueStoreOffset : 8; +#endif + + /* Offset from shapeGuard to the end of the shape jump. */ + int32 inlineShapeJumpOffset : 8; +}; + +/* BindNameCompiler */ +struct BindNameLabels : MacroAssemblerTypedefs { + friend class ::ICOffsetInitializer; + + void setInlineJumpOffset(int offset) { +#ifdef JS_HAS_IC_LABELS + inlineJumpOffset = offset; +#endif + JS_ASSERT(offset == inlineJumpOffset); + } + + void setInlineJump(MacroAssembler &masm, Label shapeGuard, Jump inlineJump) { + int offset = masm.differenceBetween(shapeGuard, inlineJump); + setInlineJumpOffset(offset); + } + + CodeLocationJump getInlineJump(CodeLocationLabel fastPathStart) { + return fastPathStart.jumpAtOffset(getInlineJumpOffset()); + } + + int getInlineJumpOffset() { + return inlineJumpOffset; + } + + void setStubJumpOffset(int offset) { +#ifdef JS_HAS_IC_LABELS + stubJumpOffset = offset; +#endif + JS_ASSERT(offset == stubJumpOffset); + } + + void setStubJump(MacroAssembler &masm, Label stubStart, Jump stubJump) { + int offset = masm.differenceBetween(stubStart, stubJump); + setStubJumpOffset(offset); + } + + CodeLocationJump getStubJump(CodeLocationLabel lastStubStart) { + return lastStubStart.jumpAtOffset(getStubJumpOffset()); + } + + int getStubJumpOffset() { + return stubJumpOffset; + } + + private: + /* Offset from shapeGuard to end of shape jump. */ + int32 inlineJumpOffset : 8; + + /* Offset from lastStubStart to end of the shape jump. */ + int32 stubJumpOffset : 8; +}; + +/* ScopeNameCompiler */ +struct ScopeNameLabels : MacroAssemblerTypedefs { + friend class ::ICOffsetInitializer; + + void setInlineJumpOffset(int offset) { +#ifdef JS_HAS_IC_LABELS + inlineJumpOffset = offset; +#endif + JS_ASSERT(offset == inlineJumpOffset); + } + + void setInlineJump(MacroAssembler &masm, Label fastPathStart, Jump inlineJump) { + int offset = masm.differenceBetween(fastPathStart, inlineJump); + setInlineJumpOffset(offset); + } + + CodeLocationJump getInlineJump(CodeLocationLabel fastPathStart) { + return fastPathStart.jumpAtOffset(getInlineJumpOffset()); + } + + int getInlineJumpOffset() { + return inlineJumpOffset; + } + + void setStubJumpOffset(int offset) { +#ifdef JS_HAS_IC_LABELS + stubJumpOffset = offset; +#endif + JS_ASSERT(offset == stubJumpOffset); + } + + void setStubJump(MacroAssembler &masm, Label stubStart, Jump stubJump) { + int offset = masm.differenceBetween(stubStart, stubJump); + setStubJumpOffset(offset); + } + + CodeLocationJump getStubJump(CodeLocationLabel lastStubStart) { + return lastStubStart.jumpAtOffset(getStubJumpOffset()); + } + + int getStubJumpOffset() { + return stubJumpOffset; + } + + private: + /* Offset from fastPathStart to end of shape jump. */ + int32 inlineJumpOffset : 8; + + /* Offset from lastStubStart to end of the shape jump. */ + int32 stubJumpOffset : 8; +}; + +} /* namespace ic */ +} /* namespace mjit */ +} /* namespace js */ + +#endif /* jsjaeger_ic_labels_h__ */ diff --git a/js/src/methodjit/ICRepatcher.h b/js/src/methodjit/ICRepatcher.h new file mode 100644 index 0000000..59d8e78 --- /dev/null +++ b/js/src/methodjit/ICRepatcher.h @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Mandelin + * David Anderson + * Chris Leary + * Jacob Bramley + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_icrepatcher_h__ && defined JS_METHODJIT +#define jsjaeger_icrepatcher_h__ + +#include "assembler/assembler/RepatchBuffer.h" +#include "assembler/moco/MocoStubs.h" +#include "methodjit/ICChecker.h" + +namespace js { +namespace mjit { +namespace ic { + +class Repatcher : public JSC::RepatchBuffer +{ + typedef JSC::CodeLocationLabel CodeLocationLabel; + typedef JSC::CodeLocationCall CodeLocationCall; + typedef JSC::FunctionPtr FunctionPtr; + + CodeLocationLabel label; + + public: + explicit Repatcher(JITScript *js) + : JSC::RepatchBuffer(js->code), label(js->code.m_code.executableAddress()) + { } + + explicit Repatcher(const JSC::JITCode &code) + : JSC::RepatchBuffer(code), label(code.start()) + { } + + using JSC::RepatchBuffer::relink; + + /* Patch a stub call. */ + void relink(CodeLocationCall call, FunctionPtr stub) { +#if defined JS_CPU_X64 || defined JS_CPU_X86 + JSC::RepatchBuffer::relink(call, stub); +#elif defined JS_CPU_ARM + /* + * Stub calls on ARM look like this: + * + * ldr ip, =stub + * call label -> ldr r8, =JaegerStubVeneer + * blx r8 + * + * ARM has to run stub calls through a veneer in order for THROW to + * work properly. The address that must be patched is the load into + * 'ip', not the load into 'r8'. + */ + CheckIsStubCall(call.labelAtOffset(0)); + JSC::RepatchBuffer::relink(call.callAtOffset(-4), stub); +#else +# error +#endif + } + + /* Patch the offset of a Value load emitted by loadValueWithAddressOffsetPatch. */ + void patchAddressOffsetForValueLoad(CodeLocationLabel label, uint32 offset) { +#if defined JS_CPU_X64 || defined JS_CPU_ARM + repatch(label.dataLabel32AtOffset(0), offset); +#elif defined JS_CPU_X86 + static const unsigned LOAD_TYPE_OFFSET = 6; + static const unsigned LOAD_DATA_OFFSET = 12; + + /* + * We have the following sequence to patch: + * + * mov ($base), % + * mov ($base), % + */ + repatch(label.dataLabel32AtOffset(LOAD_DATA_OFFSET), offset); + repatch(label.dataLabel32AtOffset(LOAD_TYPE_OFFSET), offset + 4); +#else +# error +#endif + } + + void patchAddressOffsetForValueStore(CodeLocationLabel label, uint32 offset, bool typeConst) { +#if defined JS_CPU_ARM || defined JS_CPU_X64 + (void) typeConst; + repatch(label.dataLabel32AtOffset(0), offset); +#elif defined JS_CPU_X86 + static const unsigned STORE_TYPE_OFFSET = 6; + static const unsigned STORE_DATA_CONST_TYPE_OFFSET = 16; + static const unsigned STORE_DATA_TYPE_OFFSET = 12; + + /* + * The type is stored first, then the payload. Both stores can vary in + * size, depending on whether or not the data is a constant in the + * instruction stream (though only the first store matters for the + * purpose of locating both offsets for patching). + * + * We have one of the following sequences to patch. Offsets are located + * before 6B into a given move instruction, but the mov instructions + * carrying constant payloads are 10B wide overall. + * + * typeConst=false, dataConst=false + * mov %, ($base) ; Length is 6 + * mov %, ($base) ; Offset @ len(prev) + 6 = 12 + * typeConst=true, dataConst=false + * mov $, ($base) ; Length is 10 + * mov %, ($base) ; Offset @ len(prev) + 6 = 16 + * typeConst=true, dataConst=true + * mov $, ($base) ; Length is 10 + * mov $, ($base) ; Offset @ len(prev) + 6 = 16 + * + * Note that we only need to know whether type is const to determine the + * correct patch offsets. In all cases, the label points to the start + * of the sequence. + */ + repatch(label.dataLabel32AtOffset(STORE_TYPE_OFFSET), offset + 4); + + unsigned payloadOffset = typeConst ? STORE_DATA_CONST_TYPE_OFFSET : STORE_DATA_TYPE_OFFSET; + repatch(label.dataLabel32AtOffset(payloadOffset), offset); +#else +# error +#endif + } +}; + +} /* namespace ic */ +} /* namespace mjit */ +} /* namespace js */ + +#endif diff --git a/js/src/methodjit/ImmutableSync.cpp b/js/src/methodjit/ImmutableSync.cpp new file mode 100644 index 0000000..05d2da0 --- /dev/null +++ b/js/src/methodjit/ImmutableSync.cpp @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if defined JS_NUNBOX32 + +#include "FrameEntry.h" +#include "FrameState.h" +#include "FrameState-inl.h" +#include "ImmutableSync.h" + +using namespace js; +using namespace js::mjit; + +ImmutableSync::ImmutableSync(JSContext *cx, const FrameState &frame) + : cx(cx), entries(NULL), frame(frame), generation(0) +{ +} + +ImmutableSync::~ImmutableSync() +{ + cx->free(entries); +} + +bool +ImmutableSync::init(uint32 nentries) +{ + entries = (SyncEntry *)cx->calloc(sizeof(SyncEntry) * nentries); + return !!entries; +} + +void +ImmutableSync::reset(Assembler *masm, Registers avail, FrameEntry *top, FrameEntry *bottom) +{ + this->avail = avail; + this->masm = masm; + this->top = top; + this->bottom = bottom; + this->generation++; + memset(regs, 0, sizeof(regs)); +} + +JSC::MacroAssembler::RegisterID +ImmutableSync::allocReg() +{ + if (!avail.empty()) + return avail.takeAnyReg(); + + uint32 lastResort = FrameState::InvalidIndex; + uint32 evictFromFrame = FrameState::InvalidIndex; + + /* Find something to evict. */ + for (uint32 i = 0; i < JSC::MacroAssembler::TotalRegisters; i++) { + RegisterID reg = RegisterID(i); + if (!(Registers::maskReg(reg) & Registers::AvailRegs)) + continue; + + lastResort = 0; + + if (!regs[i]) { + /* If the frame does not own this register, take it! */ + FrameEntry *fe = frame.regstate[i].usedBy(); + if (!fe) + return reg; + + evictFromFrame = i; + + /* + * If not copied, we can sync and not have to load again later. + * That's about as good as it gets, so just break out now. + */ + if (!fe->isCopied()) + break; + } + } + + if (evictFromFrame != FrameState::InvalidIndex) { + FrameEntry *fe = frame.regstate[evictFromFrame].usedBy(); + SyncEntry &e = entryFor(fe); + if (frame.regstate[evictFromFrame].type() == RematInfo::TYPE) { + JS_ASSERT(!e.typeClobbered); + e.typeClobbered = true; + } else { + JS_ASSERT(!e.dataClobbered); + e.dataClobbered = true; + } + return RegisterID(evictFromFrame); + } + + JS_ASSERT(lastResort != FrameState::InvalidIndex); + JS_ASSERT(regs[lastResort]); + + SyncEntry *e = regs[lastResort]; + RegisterID reg = RegisterID(lastResort); + if (e->hasDataReg && e->dataReg == reg) { + e->hasDataReg = false; + } else if (e->hasTypeReg && e->typeReg == reg) { + e->hasTypeReg = false; + } else { + JS_NOT_REACHED("no way"); + } + + return reg; +} + +inline ImmutableSync::SyncEntry & +ImmutableSync::entryFor(FrameEntry *fe) +{ + JS_ASSERT(fe <= top); + SyncEntry &e = entries[frame.indexOfFe(fe)]; + if (e.generation != generation) + e.reset(generation); + return e; +} + +void +ImmutableSync::sync(FrameEntry *fe) +{ +#ifdef DEBUG + top = fe; +#endif + + if (fe->isCopy()) + syncCopy(fe); + else + syncNormal(fe); +} + +bool +ImmutableSync::shouldSyncType(FrameEntry *fe, SyncEntry &e) +{ + /* Registers are synced up-front. */ + return !fe->type.synced() && !fe->type.inRegister(); +} + +bool +ImmutableSync::shouldSyncData(FrameEntry *fe, SyncEntry &e) +{ + /* Registers are synced up-front. */ + return !fe->data.synced() && !fe->data.inRegister(); +} + +JSC::MacroAssembler::RegisterID +ImmutableSync::ensureTypeReg(FrameEntry *fe, SyncEntry &e) +{ + if (fe->type.inRegister() && !e.typeClobbered) + return fe->type.reg(); + if (e.hasTypeReg) + return e.typeReg; + e.typeReg = allocReg(); + e.hasTypeReg = true; + regs[e.typeReg] = &e; + masm->loadTypeTag(frame.addressOf(fe), e.typeReg); + return e.typeReg; +} + +JSC::MacroAssembler::RegisterID +ImmutableSync::ensureDataReg(FrameEntry *fe, SyncEntry &e) +{ + if (fe->data.inRegister() && !e.dataClobbered) + return fe->data.reg(); + if (e.hasDataReg) + return e.dataReg; + e.dataReg = allocReg(); + e.hasDataReg = true; + regs[e.dataReg] = &e; + masm->loadPayload(frame.addressOf(fe), e.dataReg); + return e.dataReg; +} + +void +ImmutableSync::syncCopy(FrameEntry *fe) +{ + JS_ASSERT(fe >= bottom); + + FrameEntry *backing = fe->copyOf(); + SyncEntry &e = entryFor(backing); + + JS_ASSERT(!backing->isConstant()); + + Address addr = frame.addressOf(fe); + + if (fe->isTypeKnown() && !e.learnedType) { + e.learnedType = true; + e.type = fe->getKnownType(); + } + + if (!fe->data.synced()) + masm->storePayload(ensureDataReg(backing, e), addr); + + if (!fe->type.synced()) { + if (e.learnedType) + masm->storeTypeTag(ImmType(e.type), addr); + else + masm->storeTypeTag(ensureTypeReg(backing, e), addr); + } +} + +void +ImmutableSync::syncNormal(FrameEntry *fe) +{ + SyncEntry &e = entryFor(fe); + + Address addr = frame.addressOf(fe); + + if (fe->isTypeKnown()) { + e.learnedType = true; + e.type = fe->getKnownType(); + } + + if (shouldSyncData(fe, e)) { + if (fe->isConstant()) { + masm->storeValue(fe->getValue(), addr); + return; + } + masm->storePayload(ensureDataReg(fe, e), addr); + } + + if (shouldSyncType(fe, e)) { + if (e.learnedType) + masm->storeTypeTag(ImmType(e.type), addr); + else + masm->storeTypeTag(ensureTypeReg(fe, e), addr); + } + + if (e.hasDataReg) { + avail.putReg(e.dataReg); + regs[e.dataReg] = NULL; + } else if (!e.dataClobbered && + fe->data.inRegister() && + frame.regstate[fe->data.reg()].usedBy()) { + avail.putReg(fe->data.reg()); + } + + if (e.hasTypeReg) { + avail.putReg(e.typeReg); + regs[e.typeReg] = NULL; + } else if (!e.typeClobbered && + fe->type.inRegister() && + frame.regstate[fe->type.reg()].usedBy()) { + avail.putReg(fe->type.reg()); + } +} + +#endif /* JS_NUNBOX32 */ + diff --git a/js/src/methodjit/ImmutableSync.h b/js/src/methodjit/ImmutableSync.h new file mode 100644 index 0000000..204dbab --- /dev/null +++ b/js/src/methodjit/ImmutableSync.h @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_imm_sync_h__ && defined JS_METHODJIT && defined JS_NUNBOX32 +#define jsjaeger_imm_sync_h__ + +#include "methodjit/MachineRegs.h" +#include "methodjit/FrameEntry.h" +#include "CodeGenIncludes.h" + +namespace js { +namespace mjit { + +class FrameState; + +/* + * This is a structure nestled within the FrameState used for safely syncing + * registers to memory during transitions from the fast path into a slow path + * stub call. During this process, the frame itself is immutable, and we may + * run out of registers needed to remat copies. + * + * This structure maintains a mapping of the tracker used to perform ad-hoc + * register allocation. + */ +class ImmutableSync +{ + typedef JSC::MacroAssembler::RegisterID RegisterID; + typedef JSC::MacroAssembler::Address Address; + + struct SyncEntry { + /* + * NB: clobbered and sync mean the same thing: the register associated + * in the FrameEntry is no longer valid, and has been written back. + * + * They are separated for readability. + */ + uint32 generation; + bool dataClobbered; + bool typeClobbered; + bool hasDataReg; + bool hasTypeReg; + bool learnedType; + RegisterID dataReg; + RegisterID typeReg; + JSValueType type; + + void reset(uint32 gen) { + dataClobbered = false; + typeClobbered = false; + hasDataReg = false; + hasTypeReg = false; + learnedType = false; + generation = gen; + } + }; + + public: + ImmutableSync(JSContext *cx, const FrameState &frame); + ~ImmutableSync(); + bool init(uint32 nentries); + + void reset(Assembler *masm, Registers avail, FrameEntry *top, FrameEntry *bottom); + void sync(FrameEntry *fe); + + private: + void syncCopy(FrameEntry *fe); + void syncNormal(FrameEntry *fe); + RegisterID ensureDataReg(FrameEntry *fe, SyncEntry &e); + RegisterID ensureTypeReg(FrameEntry *fe, SyncEntry &e); + RegisterID allocReg(); + + inline SyncEntry &entryFor(FrameEntry *fe); + + bool shouldSyncType(FrameEntry *fe, SyncEntry &e); + bool shouldSyncData(FrameEntry *fe, SyncEntry &e); + + private: + JSContext *cx; + SyncEntry *entries; + const FrameState &frame; + uint32 nentries; + Registers avail; + Assembler *masm; + SyncEntry *regs[Assembler::TotalRegisters]; + FrameEntry *top; + FrameEntry *bottom; + uint32 generation; +}; + +} /* namespace mjit */ +} /* namespace js */ + +#endif /* jsjaeger_imm_sync_h__ */ + diff --git a/js/src/methodjit/InlineFrameAssembler.h b/js/src/methodjit/InlineFrameAssembler.h new file mode 100644 index 0000000..0e60478 --- /dev/null +++ b/js/src/methodjit/InlineFrameAssembler.h @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_inl_frame_asm_h__ && defined JS_METHODJIT && defined JS_MONOIC +#define jsjaeger_inl_frame_asm_h__ + +#include "assembler/assembler/MacroAssembler.h" +#include "assembler/assembler/CodeLocation.h" +#include "methodjit/MethodJIT.h" +#include "CodeGenIncludes.h" + +namespace js { +namespace mjit { + +struct AdjustedFrame { + AdjustedFrame(uint32 baseOffset) + : baseOffset(baseOffset) + { } + + uint32 baseOffset; + + JSC::MacroAssembler::Address addrOf(uint32 offset) { + return JSC::MacroAssembler::Address(JSFrameReg, baseOffset + offset); + } +}; + +/* + * This is used for emitting code to inline callee-side frame creation and + * should jit code equivalent to JSStackFrame::initCallFrameCallerHalf. + * + * Once finished, JSFrameReg is advanced to be the new fp. + */ +class InlineFrameAssembler { + typedef JSC::MacroAssembler::RegisterID RegisterID; + typedef JSC::MacroAssembler::Address Address; + typedef JSC::MacroAssembler::Imm32 Imm32; + typedef JSC::MacroAssembler::ImmPtr ImmPtr; + typedef JSC::MacroAssembler::DataLabelPtr DataLabelPtr; + + Assembler &masm; + FrameSize frameSize; // size of the caller's frame + RegisterID funObjReg; // register containing the function object (callee) + jsbytecode *pc; // bytecode location at the caller call site + uint32 flags; // frame flags + + public: + /* + * Register state, so consumers of this class can restrict which registers + * can and can't be clobbered. + */ + Registers tempRegs; + + InlineFrameAssembler(Assembler &masm, ic::CallICInfo &ic, uint32 flags) + : masm(masm), pc(ic.pc), flags(flags) + { + frameSize = ic.frameSize; + funObjReg = ic.funObjReg; + tempRegs.takeReg(ic.funPtrReg); + tempRegs.takeReg(funObjReg); + } + + InlineFrameAssembler(Assembler &masm, Compiler::CallGenInfo &gen, uint32 flags) + : masm(masm), pc(gen.pc), flags(flags) + { + frameSize = gen.frameSize; + funObjReg = gen.funObjReg; + tempRegs.takeReg(funObjReg); + } + + DataLabelPtr assemble(void *ncode) + { + JS_ASSERT((flags & ~JSFRAME_CONSTRUCTING) == 0); + + /* Generate JSStackFrame::initCallFrameCallerHalf. */ + + DataLabelPtr ncodePatch; + if (frameSize.isStatic()) { + uint32 frameDepth = frameSize.staticLocalSlots(); + AdjustedFrame newfp(sizeof(JSStackFrame) + frameDepth * sizeof(Value)); + + Address flagsAddr = newfp.addrOf(JSStackFrame::offsetOfFlags()); + masm.store32(Imm32(JSFRAME_FUNCTION | flags), flagsAddr); + Address prevAddr = newfp.addrOf(JSStackFrame::offsetOfPrev()); + masm.storePtr(JSFrameReg, prevAddr); + Address ncodeAddr = newfp.addrOf(JSStackFrame::offsetOfncode()); + ncodePatch = masm.storePtrWithPatch(ImmPtr(ncode), ncodeAddr); + + masm.addPtr(Imm32(sizeof(JSStackFrame) + frameDepth * sizeof(Value)), JSFrameReg); + } else { + /* + * If the frame size is dynamic, then the fast path generated by + * generateFullCallStub must be used. Thus, this code is executed + * after stubs::SplatApplyArgs has been called. SplatApplyArgs + * stores the dynamic stack pointer (i.e., regs.sp after pushing a + * dynamic number of arguments) to VMFrame.regs, so we just load it + * here to get the new frame pointer. + */ + RegisterID newfp = tempRegs.takeAnyReg(); + masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.sp)), newfp); + + Address flagsAddr(newfp, JSStackFrame::offsetOfFlags()); + masm.store32(Imm32(JSFRAME_FUNCTION | flags), flagsAddr); + Address prevAddr(newfp, JSStackFrame::offsetOfPrev()); + masm.storePtr(JSFrameReg, prevAddr); + Address ncodeAddr(newfp, JSStackFrame::offsetOfncode()); + ncodePatch = masm.storePtrWithPatch(ImmPtr(ncode), ncodeAddr); + + masm.move(newfp, JSFrameReg); + tempRegs.putReg(newfp); + } + + return ncodePatch; + } +}; + + +} /* namespace mjit */ +} /* namespace js */ + +#endif /* jsjaeger_inl_frame_asm_h__ */ + diff --git a/js/src/methodjit/InvokeHelpers.cpp b/js/src/methodjit/InvokeHelpers.cpp new file mode 100644 index 0000000..59ac8c6 --- /dev/null +++ b/js/src/methodjit/InvokeHelpers.cpp @@ -0,0 +1,1130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jscntxt.h" +#include "jsscope.h" +#include "jsobj.h" +#include "jslibmath.h" +#include "jsiter.h" +#include "jsnum.h" +#include "jsxml.h" +#include "jsstaticcheck.h" +#include "jsbool.h" +#include "assembler/assembler/MacroAssemblerCodeRef.h" +#include "assembler/assembler/CodeLocation.h" +#include "jsiter.h" +#include "jstypes.h" +#include "methodjit/StubCalls.h" +#include "jstracer.h" +#include "jspropertycache.h" +#include "methodjit/MonoIC.h" +#include "jsanalyze.h" +#include "methodjit/BaseCompiler.h" +#include "methodjit/ICRepatcher.h" + +#include "jsinterpinlines.h" +#include "jspropertycacheinlines.h" +#include "jsscopeinlines.h" +#include "jsscriptinlines.h" +#include "jsstrinlines.h" +#include "jsobjinlines.h" +#include "jscntxtinlines.h" +#include "jsatominlines.h" +#include "StubCalls-inl.h" +#include "MethodJIT-inl.h" + +#include "jsautooplen.h" + +using namespace js; +using namespace js::mjit; +using namespace JSC; + +using ic::Repatcher; + +static jsbytecode * +FindExceptionHandler(JSContext *cx) +{ + JSStackFrame *fp = cx->fp(); + JSScript *script = fp->script(); + +top: + if (cx->isExceptionPending() && JSScript::isValidOffset(script->trynotesOffset)) { + // The PC is updated before every stub call, so we can use it here. + unsigned offset = cx->regs->pc - script->main; + + JSTryNoteArray *tnarray = script->trynotes(); + for (unsigned i = 0; i < tnarray->length; ++i) { + JSTryNote *tn = &tnarray->vector[i]; + + // The following if condition actually tests two separate conditions: + // (1) offset - tn->start >= tn->length + // means the PC is not in the range of this try note, so we + // should continue searching, after considering: + // (2) offset - tn->start == tn->length + // means the PC is at the first op of the exception handler + // for this try note. This happens when an exception is thrown + // during recording: the interpreter sets the PC to the handler + // and then exits. In this case, we are in fact at the right + // exception handler. + // + // Hypothetically, the op we are at might have thrown an + // exception, in which case this would not be the right handler. + // But the first ops of exception handlers generated by our + // bytecode compiler cannot throw, so this is not possible. + if (offset - tn->start > tn->length) + continue; + if (tn->stackDepth > cx->regs->sp - fp->base()) + continue; + + jsbytecode *pc = script->main + tn->start + tn->length; + JSBool ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE); + JS_ASSERT(cx->regs->sp == fp->base() + tn->stackDepth); + + switch (tn->kind) { + case JSTRY_CATCH: + JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENTERBLOCK); + +#if JS_HAS_GENERATORS + /* Catch cannot intercept the closing of a generator. */ + if (JS_UNLIKELY(cx->getPendingException().isMagic(JS_GENERATOR_CLOSING))) + break; +#endif + + /* + * Don't clear cx->throwing to save cx->exception from GC + * until it is pushed to the stack via [exception] in the + * catch block. + */ + return pc; + + case JSTRY_FINALLY: + /* + * Push (true, exception) pair for finally to indicate that + * [retsub] should rethrow the exception. + */ + cx->regs->sp[0].setBoolean(true); + cx->regs->sp[1] = cx->getPendingException(); + cx->regs->sp += 2; + cx->clearPendingException(); + return pc; + + case JSTRY_ITER: + { + /* + * This is similar to JSOP_ENDITER in the interpreter loop, + * except the code now uses the stack slot normally used by + * JSOP_NEXTITER, namely regs.sp[-1] before the regs.sp -= 2 + * adjustment and regs.sp[1] after, to save and restore the + * pending exception. + */ + Value v = cx->getPendingException(); + JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENDITER); + cx->clearPendingException(); + ok = !!js_CloseIterator(cx, &cx->regs->sp[-1].toObject()); + cx->regs->sp -= 1; + if (!ok) + goto top; + cx->setPendingException(v); + } + } + } + } + + return NULL; +} + +/* + * Clean up a frame and return. + */ +static void +InlineReturn(VMFrame &f) +{ + JSContext *cx = f.cx; + JSStackFrame *fp = f.regs.fp; + + JS_ASSERT(f.fp() != f.entryfp); + + JS_ASSERT(!js_IsActiveWithOrBlock(cx, &fp->scopeChain(), 0)); + + Value *newsp = fp->actualArgs() - 1; + newsp[-1] = fp->returnValue(); + cx->stack().popInlineFrame(cx, fp->prev(), newsp); +} + +void JS_FASTCALL +stubs::SlowCall(VMFrame &f, uint32 argc) +{ + Value *vp = f.regs.sp - (argc + 2); + + if (!Invoke(f.cx, InvokeArgsAlreadyOnTheStack(vp, argc), 0)) + THROW(); +} + +void JS_FASTCALL +stubs::SlowNew(VMFrame &f, uint32 argc) +{ + JSContext *cx = f.cx; + Value *vp = f.regs.sp - (argc + 2); + + if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc))) + THROW(); +} + +/* + * This function must only be called after the early prologue, since it depends + * on fp->exec.fun. + */ +static inline void +RemovePartialFrame(JSContext *cx, JSStackFrame *fp) +{ + JSStackFrame *prev = fp->prev(); + Value *newsp = (Value *)fp; + cx->stack().popInlineFrame(cx, prev, newsp); +} + +/* + * HitStackQuota is called after the early prologue pushing the new frame would + * overflow f.stackLimit. + */ +void JS_FASTCALL +stubs::HitStackQuota(VMFrame &f) +{ + /* Include space to push another frame. */ + uintN nvals = f.fp()->script()->nslots + VALUES_PER_STACK_FRAME; + JS_ASSERT(f.regs.sp == f.fp()->base()); + if (f.cx->stack().bumpCommitAndLimit(f.entryfp, f.regs.sp, nvals, &f.stackLimit)) + return; + + /* Remove the current partially-constructed frame before throwing. */ + RemovePartialFrame(f.cx, f.fp()); + js_ReportOverRecursed(f.cx); + THROW(); +} + +/* + * This function must only be called after the early prologue, since it depends + * on fp->exec.fun. + */ +void * JS_FASTCALL +stubs::FixupArity(VMFrame &f, uint32 nactual) +{ + JSContext *cx = f.cx; + JSStackFrame *oldfp = f.fp(); + + JS_ASSERT(nactual != oldfp->numFormalArgs()); + + /* + * Grossssss! *move* the stack frame. If this ends up being perf-critical, + * we can figure out how to spot-optimize it. Be careful to touch only the + * members that have been initialized by initCallFrameCallerHalf and the + * early prologue. + */ + uint32 flags = oldfp->isConstructingFlag(); + JSFunction *fun = oldfp->fun(); + void *ncode = oldfp->nativeReturnAddress(); + + /* Pop the inline frame. */ + f.fp() = oldfp->prev(); + f.regs.sp = (Value*) oldfp; + + /* Reserve enough space for a callee frame. */ + JSStackFrame *newfp = cx->stack().getInlineFrameWithinLimit(cx, (Value*) oldfp, nactual, + fun, fun->script(), &flags, + f.entryfp, &f.stackLimit); + if (!newfp) { + /* + * The PC is not coherent with the current frame, so fix it up for + * exception handling. + */ + f.regs.pc = f.jit()->nativeToPC(ncode); + THROWV(NULL); + } + + /* Reset the part of the stack frame set by the caller. */ + newfp->initCallFrameCallerHalf(cx, flags, ncode); + + /* Reset the part of the stack frame set by the prologue up to now. */ + newfp->initCallFrameEarlyPrologue(fun, nactual); + + /* The caller takes care of assigning fp to regs. */ + return newfp; +} + +void * JS_FASTCALL +stubs::CompileFunction(VMFrame &f, uint32 nactual) +{ + /* + * We have a partially constructed frame. That's not really good enough to + * compile though because we could throw, so get a full, adjusted frame. + */ + JSContext *cx = f.cx; + JSStackFrame *fp = f.fp(); + + /* + * Since we can only use members set by initCallFrameCallerHalf, + * we must carefully extract the callee from the nactual. + */ + JSObject &callee = fp->formalArgsEnd()[-(int(nactual) + 2)].toObject(); + JSFunction *fun = callee.getFunctionPrivate(); + JSScript *script = fun->script(); + + /* + * FixupArity/RemovePartialFrame expect to be called after the early + * prologue. + */ + fp->initCallFrameEarlyPrologue(fun, nactual); + + if (nactual != fp->numFormalArgs()) { + fp = (JSStackFrame *)FixupArity(f, nactual); + if (!fp) + return NULL; + } + + /* Finish frame initialization. */ + fp->initCallFrameLatePrologue(); + + /* These would have been initialized by the prologue. */ + f.regs.fp = fp; + f.regs.sp = fp->base(); + f.regs.pc = script->code; + + if (fun->isHeavyweight() && !js_GetCallObject(cx, fp)) + THROWV(NULL); + + CompileStatus status = CanMethodJIT(cx, script, fp, CompileRequest_JIT); + if (status == Compile_Okay) + return script->getJIT(fp->isConstructing())->invokeEntry; + + /* Function did not compile... interpret it. */ + JSBool ok = Interpret(cx, fp); + InlineReturn(f); + + if (!ok) + THROWV(NULL); + + return NULL; +} + +static inline bool +UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint32 argc) +{ + JSContext *cx = f.cx; + Value *vp = f.regs.sp - (argc + 2); + JSObject &callee = vp->toObject(); + JSFunction *newfun = callee.getFunctionPrivate(); + JSScript *newscript = newfun->script(); + + /* Get pointer to new frame/slots, prepare arguments. */ + StackSpace &stack = cx->stack(); + JSStackFrame *newfp = stack.getInlineFrameWithinLimit(cx, f.regs.sp, argc, + newfun, newscript, &flags, + f.entryfp, &f.stackLimit); + if (JS_UNLIKELY(!newfp)) + return false; + + /* Initialize frame, locals. */ + newfp->initCallFrame(cx, callee, newfun, argc, flags); + SetValueRangeToUndefined(newfp->slots(), newscript->nfixed); + + /* Officially push the frame. */ + stack.pushInlineFrame(cx, newscript, newfp, &f.regs); + JS_ASSERT(newfp == f.regs.fp); + + /* Try to compile if not already compiled. */ + if (newscript->getJITStatus(newfp->isConstructing()) == JITScript_None) { + CompileStatus status = CanMethodJIT(cx, newscript, newfp, CompileRequest_Interpreter); + if (status == Compile_Error) { + /* A runtime exception was thrown, get out. */ + InlineReturn(f); + return false; + } + if (status == Compile_Abort) + *unjittable = true; + } + + /* Create call object now that we can't fail entering callee. */ + if (newfun->isHeavyweight() && !js_GetCallObject(cx, newfp)) + return false; + + /* If newscript was successfully compiled, run it. */ + if (JITScript *jit = newscript->getJIT(newfp->isConstructing())) { + *pret = jit->invokeEntry; + return true; + } + + /* Otherwise, run newscript in the interpreter. */ + bool ok = !!Interpret(cx, cx->fp()); + InlineReturn(f); + + *pret = NULL; + return ok; +} + +void * JS_FASTCALL +stubs::UncachedNew(VMFrame &f, uint32 argc) +{ + UncachedCallResult ucr; + UncachedNewHelper(f, argc, &ucr); + return ucr.codeAddr; +} + +void +stubs::UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr) +{ + ucr->init(); + + JSContext *cx = f.cx; + Value *vp = f.regs.sp - (argc + 2); + + /* Try to do a fast inline call before the general Invoke path. */ + if (IsFunctionObject(*vp, &ucr->fun) && ucr->fun->isInterpreted()) { + ucr->callee = &vp->toObject(); + if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ucr->codeAddr, &ucr->unjittable, argc)) + THROW(); + } else { + if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc))) + THROW(); + } +} + +void * JS_FASTCALL +stubs::UncachedCall(VMFrame &f, uint32 argc) +{ + UncachedCallResult ucr; + UncachedCallHelper(f, argc, &ucr); + return ucr.codeAddr; +} + +void JS_FASTCALL +stubs::Eval(VMFrame &f, uint32 argc) +{ + Value *vp = f.regs.sp - (argc + 2); + + JSObject *callee; + JSFunction *fun; + + if (!IsFunctionObject(*vp, &callee) || + !IsBuiltinEvalFunction((fun = callee->getFunctionPrivate()))) + { + if (!Invoke(f.cx, InvokeArgsAlreadyOnTheStack(vp, argc), 0)) + THROW(); + return; + } + + JS_ASSERT(f.regs.fp == f.cx->fp()); + if (!DirectEval(f.cx, fun, argc, vp)) + THROW(); +} + +void +stubs::UncachedCallHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr) +{ + ucr->init(); + + JSContext *cx = f.cx; + Value *vp = f.regs.sp - (argc + 2); + + if (IsFunctionObject(*vp, &ucr->callee)) { + ucr->callee = &vp->toObject(); + ucr->fun = GET_FUNCTION_PRIVATE(cx, ucr->callee); + + if (ucr->fun->isInterpreted()) { + if (!UncachedInlineCall(f, 0, &ucr->codeAddr, &ucr->unjittable, argc)) + THROW(); + return; + } + + if (ucr->fun->isNative()) { + if (!CallJSNative(cx, ucr->fun->u.n.native, argc, vp)) + THROW(); + return; + } + } + + if (!Invoke(f.cx, InvokeArgsAlreadyOnTheStack(vp, argc), 0)) + THROW(); + + return; +} + +void JS_FASTCALL +stubs::PutStrictEvalCallObject(VMFrame &f) +{ + JS_ASSERT(f.fp()->isEvalFrame()); + JS_ASSERT(f.fp()->script()->strictModeCode); + JS_ASSERT(f.fp()->hasCallObj()); + js_PutCallObject(f.cx, f.fp()); +} + +void JS_FASTCALL +stubs::PutActivationObjects(VMFrame &f) +{ + JS_ASSERT(f.fp()->hasCallObj() || f.fp()->hasArgsObj()); + js::PutActivationObjects(f.cx, f.fp()); +} + +extern "C" void * +js_InternalThrow(VMFrame &f) +{ + JSContext *cx = f.cx; + + // It's possible that from within RunTracer(), Interpret() returned with + // an error and finished the frame (i.e., called ScriptEpilogue), but has + // not yet performed an inline return. + // + // In this case, RunTracer() has no choice but to propagate the error + // up to the method JIT, and thus to this function. But ScriptEpilogue() + // has already been called. Detect this, and avoid double-finishing the + // frame. See HandleErrorInExcessFrame() and bug 624100. + if (f.fp()->finishedInInterpreter()) { + // If it's the last frame, just propagate the failure up again. + if (f.fp() == f.entryfp) + return NULL; + + InlineReturn(f); + } + + // Make sure sp is up to date. + JS_ASSERT(cx->regs == &f.regs); + + // Call the throw hook if necessary + JSThrowHook handler = f.cx->debugHooks->throwHook; + if (handler) { + Value rval; + switch (handler(cx, cx->fp()->script(), cx->regs->pc, Jsvalify(&rval), + cx->debugHooks->throwHookData)) { + case JSTRAP_ERROR: + cx->clearPendingException(); + return NULL; + + case JSTRAP_RETURN: + cx->clearPendingException(); + cx->fp()->setReturnValue(rval); + return JS_FUNC_TO_DATA_PTR(void *, + cx->jaegerCompartment()->forceReturnTrampoline()); + + case JSTRAP_THROW: + cx->setPendingException(rval); + break; + + default: + break; + } + } + + jsbytecode *pc = NULL; + for (;;) { + pc = FindExceptionHandler(cx); + if (pc) + break; + + // The JIT guarantees that ScriptEpilogue() has always been run + // upon exiting to its caller. This is important for consistency, + // where execution modes make similar guarantees about prologues + // and epilogues. RunTracer(), Interpret(), and Invoke() all + // rely on this property. + JS_ASSERT(!f.fp()->finishedInInterpreter()); + js_UnwindScope(cx, 0, cx->isExceptionPending()); + ScriptEpilogue(f.cx, f.fp(), false); + + // Don't remove the last frame, this is the responsibility of + // JaegerShot()'s caller. We only guarantee that ScriptEpilogue() + // has been run. + if (f.entryfp == f.fp()) + break; + + JS_ASSERT(f.regs.sp == cx->regs->sp); + InlineReturn(f); + } + + JS_ASSERT(f.regs.sp == cx->regs->sp); + + if (!pc) + return NULL; + + JSStackFrame *fp = cx->fp(); + JSScript *script = fp->script(); + return script->nativeCodeForPC(fp->isConstructing(), pc); +} + +void JS_FASTCALL +stubs::GetCallObject(VMFrame &f) +{ + JS_ASSERT(f.fp()->fun()->isHeavyweight()); + if (!js_GetCallObject(f.cx, f.fp())) + THROW(); +} + +void JS_FASTCALL +stubs::CreateThis(VMFrame &f, JSObject *proto) +{ + JSContext *cx = f.cx; + JSStackFrame *fp = f.fp(); + JSObject *callee = &fp->callee(); + JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto); + if (!obj) + THROW(); + fp->formalArgs()[-1].setObject(*obj); +} + +void JS_FASTCALL +stubs::EnterScript(VMFrame &f) +{ + JSStackFrame *fp = f.fp(); + JSContext *cx = f.cx; + + if (fp->script()->debugMode) { + if (fp->isExecuteFrame()) { + JSInterpreterHook hook = cx->debugHooks->executeHook; + if (JS_UNLIKELY(hook != NULL)) + fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->executeHookData)); + } else { + JSInterpreterHook hook = cx->debugHooks->callHook; + if (JS_UNLIKELY(hook != NULL)) + fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData)); + } + } + + Probes::enterJSFun(cx, fp->maybeFun(), fp->script()); +} + +void JS_FASTCALL +stubs::LeaveScript(VMFrame &f) +{ + JSStackFrame *fp = f.fp(); + JSContext *cx = f.cx; + Probes::exitJSFun(cx, fp->maybeFun(), fp->maybeScript()); + + if (fp->script()->debugMode) { + void *hookData; + JSInterpreterHook hook = + fp->isExecuteFrame() ? cx->debugHooks->executeHook : cx->debugHooks->callHook; + + if (JS_UNLIKELY(hook != NULL) && (hookData = fp->maybeHookData())) { + JSBool ok = JS_TRUE; + hook(cx, fp, JS_FALSE, &ok, hookData); + if (!ok) + THROW(); + } + } +} + +#ifdef JS_TRACER + +/* + * Called when an error is in progress and the topmost frame could not handle + * it. This will unwind to a given frame, or find and align to an exception + * handler in the process. + */ +static inline bool +HandleErrorInExcessFrame(VMFrame &f, JSStackFrame *stopFp, bool searchedTopmostFrame = true) +{ + JSContext *cx = f.cx; + + /* + * Callers of this called either Interpret() or JaegerShot(), which would + * have searched for exception handlers already. If we see stopFp, just + * return false. Otherwise, pop the frame, since it's guaranteed useless. + * + * Note that this also guarantees ScriptEpilogue() has been called. + */ + JSStackFrame *fp = cx->fp(); + if (searchedTopmostFrame) { + /* + * This is a special case meaning that fp->finishedInInterpreter() is + * true. If so, and fp == stopFp, our only choice is to propagate this + * error up, back to the method JIT, and then to js_InternalThrow, + * where this becomes a special case. See the comment there and bug + * 624100. + */ + if (fp == stopFp) + return false; + + /* + * Otherwise, the protocol here (like Invoke) is to assume that the + * execution mode finished the frame, and to just pop it. + */ + InlineReturn(f); + } + + /* Remove the bottom frame. */ + bool returnOK = false; + for (;;) { + fp = cx->fp(); + + /* Clear imacros. */ + if (fp->hasImacropc()) { + cx->regs->pc = fp->imacropc(); + fp->clearImacropc(); + } + JS_ASSERT(!fp->hasImacropc()); + + /* If there's an exception and a handler, set the pc and leave. */ + if (cx->isExceptionPending()) { + jsbytecode *pc = FindExceptionHandler(cx); + if (pc) { + cx->regs->pc = pc; + returnOK = true; + break; + } + } + + /* Don't unwind if this was the entry frame. */ + if (fp == stopFp) + break; + + /* Unwind and return. */ + returnOK &= bool(js_UnwindScope(cx, 0, returnOK || cx->isExceptionPending())); + returnOK = ScriptEpilogue(cx, fp, returnOK); + InlineReturn(f); + } + + JS_ASSERT(&f.regs == cx->regs); + JS_ASSERT_IF(!returnOK, cx->fp() == stopFp); + + return returnOK; +} + +/* Returns whether the current PC has method JIT'd code. */ +static inline void * +AtSafePoint(JSContext *cx) +{ + JSStackFrame *fp = cx->fp(); + if (fp->hasImacropc()) + return false; + + JSScript *script = fp->script(); + return script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs->pc); +} + +/* + * Interprets until either a safe point is reached that has method JIT'd + * code, or the current frame tries to return. + */ +static inline JSBool +PartialInterpret(VMFrame &f) +{ + JSContext *cx = f.cx; + JSStackFrame *fp = cx->fp(); + +#ifdef DEBUG + JSScript *script = fp->script(); + JS_ASSERT(!fp->finishedInInterpreter()); + JS_ASSERT(fp->hasImacropc() || + !script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs->pc)); +#endif + + JSBool ok = JS_TRUE; + ok = Interpret(cx, fp, 0, JSINTERP_SAFEPOINT); + + return ok; +} + +JS_STATIC_ASSERT(JSOP_NOP == 0); + +/* + * Returns whether the current PC would return, or if the frame has already + * been completed. This distinction avoids re-entering the interpreter or JIT + * to complete a JSOP_RETURN. Instead, that edge case is handled in + * HandleFinishedFrame. We could consider reducing complexity, and making this + * function return only "finishedInInterpreter", and always using the full VM + * machinery to fully finish frames. + */ +static inline bool +FrameIsFinished(JSContext *cx) +{ + JSOp op = JSOp(*cx->regs->pc); + return (op == JSOP_RETURN || + op == JSOP_RETRVAL || + op == JSOP_STOP) + ? true + : cx->fp()->finishedInInterpreter(); +} + + +/* Simulate an inline_return by advancing the pc. */ +static inline void +AdvanceReturnPC(JSContext *cx) +{ + JS_ASSERT(*cx->regs->pc == JSOP_CALL || + *cx->regs->pc == JSOP_NEW || + *cx->regs->pc == JSOP_EVAL || + *cx->regs->pc == JSOP_FUNCALL || + *cx->regs->pc == JSOP_FUNAPPLY); + cx->regs->pc += JSOP_CALL_LENGTH; +} + + +/* + * Given a frame that is about to return, make sure its return value and + * activation objects are fixed up. Then, pop the frame and advance the + * current PC. Note that while we could enter the JIT at this point, the + * logic would still be necessary for the interpreter, so it's easier + * (and faster) to finish frames in C++ even if at a safe point here. + */ +static bool +HandleFinishedFrame(VMFrame &f, JSStackFrame *entryFrame) +{ + JSContext *cx = f.cx; + + JS_ASSERT(FrameIsFinished(cx)); + + /* + * This is the most difficult and complicated piece of the tracer + * integration, and historically has been very buggy. The problem is that + * although this frame has to be popped (see RemoveExcessFrames), it may + * be at a JSOP_RETURN opcode, and it might not have ever been executed. + * That is, fp->rval may not be set to the top of the stack, and if it + * has, the stack has already been decremented. Note that fp->rval is not + * the only problem: the epilogue may never have been executed. + * + * Here are the edge cases and whether the frame has been exited cleanly: + * 1. No: A trace exited directly before a RETURN op, and the + * interpreter never ran. + * 2. Yes: The interpreter exited cleanly. + * 3. No: The interpreter exited on a safe point. LEAVE_ON_SAFE_POINT + * is not used in between JSOP_RETURN and advancing the PC, + * therefore, it cannot have been run if at a safe point. + * 4. No: Somewhere in the RunTracer call tree, we removed a frame, + * and we returned to a JSOP_RETURN opcode. Note carefully + * that in this situation, FrameIsFinished() returns true! + * 5. Yes: The function exited in the method JIT, during + * FinishExcessFrames() However, in this case, we'll never enter + * HandleFinishedFrame(): we always immediately pop JIT'd frames. + * + * Since the only scenario where this fixup is NOT needed is a normal exit + * from the interpreter, we can cleanly check for this scenario by checking + * a bit it sets in the frame. + */ + bool returnOK = true; + if (!cx->fp()->finishedInInterpreter()) { + if (JSOp(*cx->regs->pc) == JSOP_RETURN) + cx->fp()->setReturnValue(f.regs.sp[-1]); + + returnOK = ScriptEpilogue(cx, cx->fp(), true); + } + + JS_ASSERT_IF(cx->fp()->isFunctionFrame() && + !cx->fp()->isEvalFrame(), + !cx->fp()->hasCallObj()); + + if (cx->fp() != entryFrame) { + InlineReturn(f); + AdvanceReturnPC(cx); + } + + return returnOK; +} + +/* + * Given a frame newer than the entry frame, try to finish it. If it's at a + * return position, pop the frame. If it's at a safe point, execute it in + * Jaeger code. Otherwise, try to interpret until a safe point. + * + * While this function is guaranteed to make progress, it may not actually + * finish or pop the current frame. It can either: + * 1) Finalize a finished frame, or + * 2) Finish and finalize the frame in the Method JIT, or + * 3) Interpret, which can: + * a) Propagate an error, or + * b) Finish the frame, but not finalize it, or + * c) Abruptly leave at any point in the frame, or in a newer frame + * pushed by a call, that has method JIT'd code. + */ +static bool +EvaluateExcessFrame(VMFrame &f, JSStackFrame *entryFrame) +{ + JSContext *cx = f.cx; + JSStackFrame *fp = cx->fp(); + + /* + * A "finished" frame is when the interpreter rested on a STOP, + * RETURN, RETRVAL, etc. We check for finished frames BEFORE looking + * for a safe point. If the frame was finished, we could have already + * called ScriptEpilogue(), and entering the JIT could call it twice. + */ + if (!fp->hasImacropc() && FrameIsFinished(cx)) + return HandleFinishedFrame(f, entryFrame); + + if (void *ncode = AtSafePoint(cx)) { + if (!JaegerShotAtSafePoint(cx, ncode)) + return false; + InlineReturn(f); + AdvanceReturnPC(cx); + return true; + } + + return PartialInterpret(f); +} + +/* + * Evaluate frames newer than the entry frame until all are gone. This will + * always leave f.regs.fp == entryFrame. + */ +static bool +FinishExcessFrames(VMFrame &f, JSStackFrame *entryFrame) +{ + JSContext *cx = f.cx; + + while (cx->fp() != entryFrame || entryFrame->hasImacropc()) { + if (!EvaluateExcessFrame(f, entryFrame)) { + if (!HandleErrorInExcessFrame(f, entryFrame)) + return false; + } + } + + return true; +} + +#if defined JS_MONOIC +static void +UpdateTraceHintSingle(Repatcher &repatcher, JSC::CodeLocationJump jump, JSC::CodeLocationLabel target) +{ + /* + * Hack: The value that will be patched is before the executable address, + * so to get protection right, just unprotect the general region around + * the jump. + */ + repatcher.relink(jump, target); + + JaegerSpew(JSpew_PICs, "relinking trace hint %p to %p\n", + jump.executableAddress(), target.executableAddress()); +} + +static void +DisableTraceHint(JITScript *jit, ic::TraceICInfo &ic) +{ + Repatcher repatcher(jit); + UpdateTraceHintSingle(repatcher, ic.traceHint, ic.jumpTarget); + + if (ic.hasSlowTraceHint) + UpdateTraceHintSingle(repatcher, ic.slowTraceHint, ic.jumpTarget); +} + +static void +ResetTraceHintAt(JSScript *script, js::mjit::JITScript *jit, + jsbytecode *pc, uint16_t index, bool full) +{ + if (index >= jit->nTraceICs) + return; + ic::TraceICInfo &ic = jit->traceICs()[index]; + if (!ic.initialized) + return; + + JS_ASSERT(ic.jumpTargetPC == pc); + + JaegerSpew(JSpew_PICs, "Enabling trace IC %u in script %p\n", index, script); + + Repatcher repatcher(jit); + + UpdateTraceHintSingle(repatcher, ic.traceHint, ic.stubEntry); + + if (ic.hasSlowTraceHint) + UpdateTraceHintSingle(repatcher, ic.slowTraceHint, ic.stubEntry); + + if (full) { + ic.traceData = NULL; + ic.loopCounterStart = 1; + ic.loopCounter = ic.loopCounterStart; + } +} +#endif + +void +js::mjit::ResetTraceHint(JSScript *script, jsbytecode *pc, uint16_t index, bool full) +{ +#if JS_MONOIC + if (script->jitNormal) + ResetTraceHintAt(script, script->jitNormal, pc, index, full); + + if (script->jitCtor) + ResetTraceHintAt(script, script->jitCtor, pc, index, full); +#endif +} + +#if JS_MONOIC +void * +RunTracer(VMFrame &f, ic::TraceICInfo &ic) +#else +void * +RunTracer(VMFrame &f) +#endif +{ + JSContext *cx = f.cx; + JSStackFrame *entryFrame = f.fp(); + TracePointAction tpa; + + /* :TODO: nuke PIC? */ + if (!cx->traceJitEnabled) + return NULL; + + /* + * Force initialization of the entry frame's scope chain and return value, + * if necessary. The tracer can query the scope chain without needing to + * check the HAS_SCOPECHAIN flag, and the frame is guaranteed to have the + * correct return value stored if we trace/interpret through to the end + * of the frame. + */ + entryFrame->scopeChain(); + entryFrame->returnValue(); + + bool blacklist; + uintN inlineCallCount = 0; + void **traceData; + uintN *traceEpoch; + uint32 *loopCounter; + uint32 hits; +#if JS_MONOIC + traceData = &ic.traceData; + traceEpoch = &ic.traceEpoch; + loopCounter = &ic.loopCounter; + *loopCounter = 1; + hits = ic.loopCounterStart; +#else + traceData = NULL; + traceEpoch = NULL; + loopCounter = NULL; + hits = 1; +#endif + tpa = MonitorTracePoint(f.cx, inlineCallCount, &blacklist, traceData, traceEpoch, + loopCounter, hits); + JS_ASSERT(!TRACE_RECORDER(cx)); + +#if JS_MONOIC + ic.loopCounterStart = *loopCounter; + if (blacklist) + DisableTraceHint(entryFrame->jit(), ic); +#endif + + // Even though ExecuteTree() bypasses the interpreter, it should propagate + // error failures correctly. + JS_ASSERT_IF(cx->isExceptionPending(), tpa == TPA_Error); + + f.fp() = cx->fp(); + JS_ASSERT(f.fp() == cx->fp()); + switch (tpa) { + case TPA_Nothing: + return NULL; + + case TPA_Error: + if (!HandleErrorInExcessFrame(f, entryFrame, f.fp()->finishedInInterpreter())) + THROWV(NULL); + JS_ASSERT(!cx->fp()->hasImacropc()); + break; + + case TPA_RanStuff: + case TPA_Recorded: + break; + } + + /* + * The tracer could have dropped us off on any frame at any position. + * Well, it could not have removed frames (recursion is disabled). + * + * Frames after the entryFrame cannot be entered via JaegerShotAtSafePoint() + * unless each is at a safe point. We can JaegerShotAtSafePoint these + * frames individually, but we must unwind to the entryFrame. + * + * Note carefully that JaegerShotAtSafePoint can resume methods at + * arbitrary safe points whereas JaegerShot cannot. + * + * If we land on entryFrame without a safe point in sight, we'll end up + * at the RETURN op. This is an edge case with two paths: + * + * 1) The entryFrame is the last inline frame. If it fell on a RETURN, + * move the return value down. + * 2) The entryFrame is NOT the last inline frame. Pop the frame. + * + * In both cases, we hijack the stub to return to InjectJaegerReturn. This + * moves |oldFp->rval| into the scripted return registers. + */ + + restart: + /* Step 1. Finish frames created after the entry frame. */ + if (!FinishExcessFrames(f, entryFrame)) + THROWV(NULL); + + /* IMacros are guaranteed to have been removed by now. */ + JS_ASSERT(f.fp() == entryFrame); + JS_ASSERT(!entryFrame->hasImacropc()); + + /* Step 2. If entryFrame is done, use a special path to return to EnterMethodJIT(). */ + if (FrameIsFinished(cx)) { + if (!HandleFinishedFrame(f, entryFrame)) + THROWV(NULL); + + void *retPtr = JS_FUNC_TO_DATA_PTR(void *, InjectJaegerReturn); + *f.returnAddressLocation() = retPtr; + return NULL; + } + + /* Step 3. If entryFrame is at a safe point, just leave. */ + if (void *ncode = AtSafePoint(cx)) + return ncode; + + /* Step 4. Do a partial interp, then restart the whole process. */ + if (!PartialInterpret(f)) { + if (!HandleErrorInExcessFrame(f, entryFrame)) + THROWV(NULL); + } + + goto restart; +} + +#endif /* JS_TRACER */ + +#if defined JS_TRACER +# if defined JS_MONOIC +void *JS_FASTCALL +stubs::InvokeTracer(VMFrame &f, ic::TraceICInfo *ic) +{ + return RunTracer(f, *ic); +} + +# else + +void *JS_FASTCALL +stubs::InvokeTracer(VMFrame &f) +{ + return RunTracer(f); +} +# endif /* JS_MONOIC */ +#endif /* JS_TRACER */ + diff --git a/js/src/methodjit/Logging.cpp b/js/src/methodjit/Logging.cpp new file mode 100644 index 0000000..ed7b0ef --- /dev/null +++ b/js/src/methodjit/Logging.cpp @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * Julian Seward + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include +#include +#include "jsutil.h" +#include "MethodJIT.h" +#include "Logging.h" + +#if defined(JS_METHODJIT_SPEW) + +static bool LoggingChecked = false; +static uint32 LoggingBits = 0; + +static const char *ChannelNames[] = +{ +#define _(name) #name, + JSPEW_CHAN_MAP(_) +#undef _ +}; + +void +js::JMCheckLogging() +{ + /* Not MT safe; races on Logging{Checked,Bits}. */ + if (LoggingChecked) + return; + LoggingChecked = true; + const char *env = getenv("JMFLAGS"); + if (!env) + return; + if (strstr(env, "help")) { + fflush(NULL); + printf( + "\n" + "usage: JMFLAGS=option,option,option,... where options can be:\n" + "\n" + " help show this message\n" + " abort/aborts ???\n" + " scripts ???\n" + " profile ???\n" +#ifdef DEBUG + " jsops JS opcodes\n" +#endif + " insns JS opcodes and generated insns\n" + " vmframe VMFrame contents\n" + " pics PIC patching activity\n" + " slowcalls Calls to slow path functions\n" + " full everything\n" + " notrace disable trace hints\n" + "\n" + ); + exit(0); + /*NOTREACHED*/ + } + if (strstr(env, "abort") || strstr(env, "aborts")) + LoggingBits |= (1 << uint32(JSpew_Abort)); + if (strstr(env, "scripts")) + LoggingBits |= (1 << uint32(JSpew_Scripts)); + if (strstr(env, "profile")) + LoggingBits |= (1 << uint32(JSpew_Prof)); +#ifdef DEBUG + if (strstr(env, "jsops")) + LoggingBits |= (1 << uint32(JSpew_JSOps)); +#endif + if (strstr(env, "insns")) + LoggingBits |= (1 << uint32(JSpew_Insns) | (1 << uint32(JSpew_JSOps))); + if (strstr(env, "vmframe")) + LoggingBits |= (1 << uint32(JSpew_VMFrame)); + if (strstr(env, "pics")) + LoggingBits |= (1 << uint32(JSpew_PICs)); + if (strstr(env, "slowcalls")) + LoggingBits |= (1 << uint32(JSpew_SlowCalls)); + if (strstr(env, "full")) + LoggingBits |= 0xFFFFFFFF; +} + +bool +js::IsJaegerSpewChannelActive(JaegerSpewChannel channel) +{ + JS_ASSERT(LoggingChecked); + return !!(LoggingBits & (1 << uint32(channel))); +} + +void +js::JaegerSpew(JaegerSpewChannel channel, const char *fmt, ...) +{ + JS_ASSERT(LoggingChecked); + + if (!(LoggingBits & (1 << uint32(channel)))) + return; + + fprintf(stderr, "[jaeger] %-7s ", ChannelNames[channel]); + + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + /* fprintf(stdout, "\n"); */ +} + +#endif + diff --git a/js/src/methodjit/Logging.h b/js/src/methodjit/Logging.h new file mode 100644 index 0000000..ba1ecc1 --- /dev/null +++ b/js/src/methodjit/Logging.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * Julian Seward + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_logging_h__ && (defined JS_METHODJIT || defined JS_TRACER) +#define jsjaeger_logging_h__ + +#include "prmjtime.h" + +namespace js { + +#define JSPEW_CHAN_MAP(_) \ + _(Abort) \ + _(Scripts) \ + _(Prof) \ + _(JSOps) \ + _(Insns) \ + _(VMFrame) \ + _(PICs) \ + _(SlowCalls) + +enum JaegerSpewChannel { +#define _(name) JSpew_##name, + JSPEW_CHAN_MAP(_) +#undef _ + JSpew_Terminator +}; + +#if defined(DEBUG) && !defined(JS_METHODJIT_SPEW) +# define JS_METHODJIT_SPEW +#endif + +#if defined(JS_METHODJIT_SPEW) + +void JMCheckLogging(); + +bool IsJaegerSpewChannelActive(JaegerSpewChannel channel); +void JaegerSpew(JaegerSpewChannel channel, const char *fmt, ...); + +struct Profiler { + JSInt64 t_start; + JSInt64 t_stop; + + static inline JSInt64 now() { + return PRMJ_Now(); + } + + inline void start() { + t_start = now(); + } + + inline void stop() { + t_stop = now(); + } + + inline uint32 time_ms() { + return uint32((t_stop - t_start) / PRMJ_USEC_PER_MSEC); + } + + inline uint32 time_us() { + return uint32(t_stop - t_start); + } +}; + +#else + +static inline void JaegerSpew(JaegerSpewChannel channel, const char *fmt, ...) +{ +} + +#endif + +} + +#endif + diff --git a/js/src/methodjit/MachineRegs.h b/js/src/methodjit/MachineRegs.h new file mode 100644 index 0000000..149f188 --- /dev/null +++ b/js/src/methodjit/MachineRegs.h @@ -0,0 +1,454 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_regstate_h__ && defined JS_METHODJIT +#define jsjaeger_regstate_h__ + +#include "jsbit.h" +#include "assembler/assembler/MacroAssembler.h" + +namespace js { + +namespace mjit { + +struct Registers { + enum CallConvention { + NormalCall, + FastCall + }; + + typedef JSC::MacroAssembler::RegisterID RegisterID; + + // Homed and scratch registers for working with Values on x64. +#if defined(JS_CPU_X64) + static const RegisterID TypeMaskReg = JSC::X86Registers::r13; + static const RegisterID PayloadMaskReg = JSC::X86Registers::r14; + static const RegisterID ValueReg = JSC::X86Registers::r10; +#endif + + // Register that homes the current JSStackFrame. +#if defined(JS_CPU_X86) || defined(JS_CPU_X64) + static const RegisterID JSFrameReg = JSC::X86Registers::ebx; +#elif defined(JS_CPU_ARM) + static const RegisterID JSFrameReg = JSC::ARMRegisters::r11; +#endif + +#if defined(JS_CPU_X86) || defined(JS_CPU_X64) + static const RegisterID ReturnReg = JSC::X86Registers::eax; +# if defined(JS_CPU_X86) || defined(_MSC_VER) + static const RegisterID ArgReg0 = JSC::X86Registers::ecx; + static const RegisterID ArgReg1 = JSC::X86Registers::edx; +# if defined(JS_CPU_X64) + static const RegisterID ArgReg2 = JSC::X86Registers::r8; +# endif +# else + static const RegisterID ArgReg0 = JSC::X86Registers::edi; + static const RegisterID ArgReg1 = JSC::X86Registers::esi; + static const RegisterID ArgReg2 = JSC::X86Registers::edx; +# endif +#elif JS_CPU_ARM + static const RegisterID ReturnReg = JSC::ARMRegisters::r0; + static const RegisterID ArgReg0 = JSC::ARMRegisters::r0; + static const RegisterID ArgReg1 = JSC::ARMRegisters::r1; + static const RegisterID ArgReg2 = JSC::ARMRegisters::r2; +#endif + + static const RegisterID StackPointer = JSC::MacroAssembler::stackPointerRegister; + + static inline uint32 maskReg(RegisterID reg) { + return (1 << reg); + } + + static inline uint32 mask2Regs(RegisterID reg1, RegisterID reg2) { + return maskReg(reg1) | maskReg(reg2); + } + + static inline uint32 mask3Regs(RegisterID reg1, RegisterID reg2, RegisterID reg3) { + return maskReg(reg1) | maskReg(reg2) | maskReg(reg3); + } + +#if defined(JS_CPU_X86) || defined(JS_CPU_X64) + static const uint32 TempRegs = + (1 << JSC::X86Registers::eax) + | (1 << JSC::X86Registers::ecx) + | (1 << JSC::X86Registers::edx) +# if defined(JS_CPU_X64) + | (1 << JSC::X86Registers::r8) + | (1 << JSC::X86Registers::r9) +# if !defined(_MSC_VER) + | (1 << JSC::X86Registers::esi) + | (1 << JSC::X86Registers::edi) +# endif +# endif + ; + +# if defined(JS_CPU_X64) + static const uint32 SavedRegs = + /* r11 is scratchRegister, used by JSC. */ + (1 << JSC::X86Registers::r12) + // r13 is TypeMaskReg. + // r14 is PayloadMaskReg. + | (1 << JSC::X86Registers::r15) +# if defined(_MSC_VER) + | (1 << JSC::X86Registers::esi) + | (1 << JSC::X86Registers::edi) +# endif +# else + static const uint32 SavedRegs = + (1 << JSC::X86Registers::esi) + | (1 << JSC::X86Registers::edi) +# endif + ; + +# if defined(JS_CPU_X86) + static const uint32 SingleByteRegs = (TempRegs | SavedRegs) & + ~((1 << JSC::X86Registers::esi) | + (1 << JSC::X86Registers::edi) | + (1 << JSC::X86Registers::ebp) | + (1 << JSC::X86Registers::esp)); +# elif defined(JS_CPU_X64) + static const uint32 SingleByteRegs = TempRegs | SavedRegs; +# endif + +#elif defined(JS_CPU_ARM) + static const uint32 TempRegs = + (1 << JSC::ARMRegisters::r0) + | (1 << JSC::ARMRegisters::r1) + | (1 << JSC::ARMRegisters::r2); + // r3 is reserved as a scratch register for the assembler. + + static const uint32 SavedRegs = + (1 << JSC::ARMRegisters::r4) + | (1 << JSC::ARMRegisters::r5) + | (1 << JSC::ARMRegisters::r6) + | (1 << JSC::ARMRegisters::r7) + // r8 is reserved as a scratch register for the assembler. + | (1 << JSC::ARMRegisters::r9) + | (1 << JSC::ARMRegisters::r10); + // r11 is reserved for JSFrameReg. + // r12 is IP, and is used for stub calls. + // r13 is SP and must always point to VMFrame whilst in generated code. + // r14 is LR and is used for return sequences. + // r15 is PC (program counter). + + static const uint32 SingleByteRegs = TempRegs | SavedRegs; +#else +# error "Unsupported platform" +#endif + + static const uint32 AvailRegs = SavedRegs | TempRegs; + + static bool isSaved(RegisterID reg) { + uint32 mask = maskReg(reg); + JS_ASSERT(mask & AvailRegs); + return bool(mask & SavedRegs); + } + + static inline uint32 numArgRegs(CallConvention convention) { +#if defined(JS_CPU_X86) +# if defined(JS_NO_FASTCALL) + return 0; +# else + return (convention == FastCall) ? 2 : 0; +# endif +#elif defined(JS_CPU_X64) +# ifdef _WIN64 + return 4; +# else + return 6; +# endif +#elif defined(JS_CPU_ARM) + return 4; +#endif + } + + static inline bool regForArg(CallConvention conv, uint32 i, RegisterID *reg) { +#if defined(JS_CPU_X86) + static const RegisterID regs[] = { + JSC::X86Registers::ecx, + JSC::X86Registers::edx + }; + +# if defined(JS_NO_FASTCALL) + return false; +# else + if (conv == NormalCall) + return false; +# endif +#elif defined(JS_CPU_X64) +# ifdef _WIN64 + static const RegisterID regs[] = { + JSC::X86Registers::ecx, + JSC::X86Registers::edx, + JSC::X86Registers::r8, + JSC::X86Registers::r9 + }; +# else + static const RegisterID regs[] = { + JSC::X86Registers::edi, + JSC::X86Registers::esi, + JSC::X86Registers::edx, + JSC::X86Registers::ecx, + JSC::X86Registers::r8, + JSC::X86Registers::r9 + }; +# endif +#elif defined(JS_CPU_ARM) + static const RegisterID regs[] = { + JSC::ARMRegisters::r0, + JSC::ARMRegisters::r1, + JSC::ARMRegisters::r2, + JSC::ARMRegisters::r3 + }; +#endif + JS_ASSERT(numArgRegs(conv) == JS_ARRAY_LENGTH(regs)); + if (i > JS_ARRAY_LENGTH(regs)) + return false; + *reg = regs[i]; + return true; + } + + Registers() + : freeMask(AvailRegs) + { } + + Registers(uint32 freeMask) + : freeMask(freeMask) + { } + + Registers(const Registers &other) + : freeMask(other.freeMask) + { } + + Registers & operator =(const Registers &other) + { + freeMask = other.freeMask; + return *this; + } + + void reset() { + freeMask = AvailRegs; + } + + bool empty() const { + return !freeMask; + } + + bool empty(uint32 mask) const { + return !(freeMask & mask); + } + + RegisterID peekReg() { + JS_ASSERT(!empty()); + int ireg; + JS_FLOOR_LOG2(ireg, freeMask); + RegisterID reg = (RegisterID)ireg; + return reg; + } + + RegisterID takeAnyReg() { + RegisterID reg = peekReg(); + takeReg(reg); + return reg; + } + + bool hasRegInMask(uint32 mask) const { + Registers temp(freeMask & mask); + return !temp.empty(); + } + + RegisterID takeRegInMask(uint32 mask) { + Registers temp(freeMask & mask); + RegisterID reg = temp.takeAnyReg(); + takeReg(reg); + return reg; + } + + bool hasReg(RegisterID reg) const { + return !!(freeMask & (1 << reg)); + } + + void putRegUnchecked(RegisterID reg) { + freeMask |= (1 << reg); + } + + void putReg(RegisterID reg) { + JS_ASSERT(!hasReg(reg)); + putRegUnchecked(reg); + } + + void takeReg(RegisterID reg) { + JS_ASSERT(hasReg(reg)); + takeRegUnchecked(reg); + } + + void takeRegUnchecked(RegisterID reg) { + freeMask &= ~(1 << reg); + } + + bool operator ==(const Registers &other) { + return freeMask == other.freeMask; + } + + uint32 freeMask; +}; + + +struct FPRegisters { + + typedef JSC::MacroAssembler::FPRegisterID FPRegisterID; + +#if defined(JS_CPU_X86) || defined(JS_CPU_X64) + static const uint32 TotalFPRegisters = 8; + static const uint32 TempFPRegs = + (1 << JSC::X86Registers::xmm0) + | (1 << JSC::X86Registers::xmm1) + | (1 << JSC::X86Registers::xmm2) + | (1 << JSC::X86Registers::xmm3) + | (1 << JSC::X86Registers::xmm4) + | (1 << JSC::X86Registers::xmm5) + | (1 << JSC::X86Registers::xmm6) + | (1 << JSC::X86Registers::xmm7); + /* FIXME: Temporary hack until FPRegister allocation exists. */ + static const FPRegisterID First = JSC::X86Registers::xmm0; + static const FPRegisterID Second = JSC::X86Registers::xmm1; + static const FPRegisterID Temp0 = JSC::X86Registers::xmm2; + static const FPRegisterID Temp1 = JSC::X86Registers::xmm3; +#elif defined(JS_CPU_ARM) + static const uint32 TotalFPRegisters = 4; + static const uint32 TempFPRegs = + (1 << JSC::ARMRegisters::d0) + | (1 << JSC::ARMRegisters::d1) + | (1 << JSC::ARMRegisters::d2) + | (1 << JSC::ARMRegisters::d3); + /* FIXME: Temporary hack until FPRegister allocation exists. */ + static const FPRegisterID First = JSC::ARMRegisters::d0; + static const FPRegisterID Second = JSC::ARMRegisters::d1; + static const FPRegisterID Temp0 = JSC::ARMRegisters::d2; + static const FPRegisterID Temp1 = JSC::ARMRegisters::d3; +#else +# error "Unsupported platform" +#endif + + static const uint32 AvailFPRegs = TempFPRegs; + + FPRegisters() + : freeFPMask(AvailFPRegs) + { } + + FPRegisters(uint32 freeFPMask) + : freeFPMask(freeFPMask) + { } + + FPRegisters(const FPRegisters &other) + : freeFPMask(other.freeFPMask) + { } + + FPRegisters & operator =(const FPRegisters &other) + { + freeFPMask = other.freeFPMask; + return *this; + } + + void reset() { + freeFPMask = AvailFPRegs; + } + + bool empty() const { + return !freeFPMask; + } + + bool empty(uint32 mask) const { + return !(freeFPMask & mask); + } + + FPRegisterID takeAnyReg() { + JS_ASSERT(!empty()); + int ireg; + JS_FLOOR_LOG2(ireg, freeFPMask); + FPRegisterID reg = (FPRegisterID)ireg; + takeReg(reg); + return reg; + } + + bool hasRegInMask(uint32 mask) const { + FPRegisters temp(freeFPMask & mask); + return !temp.empty(); + } + + FPRegisterID takeRegInMask(uint32 mask) { + FPRegisters temp(freeFPMask & mask); + FPRegisterID reg = temp.takeAnyReg(); + takeReg(reg); + return reg; + } + + bool hasReg(FPRegisterID fpreg) const { + return !!(freeFPMask & (1 << fpreg)); + } + + void putRegUnchecked(FPRegisterID fpreg) { + freeFPMask |= (1 << fpreg); + } + + void putReg(FPRegisterID fpreg) { + JS_ASSERT(!hasReg(fpreg)); + putRegUnchecked(fpreg); + } + + void takeReg(FPRegisterID fpreg) { + JS_ASSERT(hasReg(fpreg)); + freeFPMask &= ~(1 << fpreg); + } + + bool operator ==(const FPRegisters &other) { + return freeFPMask == other.freeFPMask; + } + + uint32 freeFPMask; +}; + +static const JSC::MacroAssembler::RegisterID JSFrameReg = Registers::JSFrameReg; + +} /* namespace mjit */ + +} /* namespace js */ + +#endif /* jsjaeger_regstate_h__ */ + diff --git a/js/src/methodjit/MethodJIT-inl.h b/js/src/methodjit/MethodJIT-inl.h new file mode 100644 index 0000000..8f392ff --- /dev/null +++ b/js/src/methodjit/MethodJIT-inl.h @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_methodjit_inl_h__ && defined JS_METHODJIT +#define jsjaeger_methodjit_inl_h__ + +namespace js { +namespace mjit { + +enum CompileRequest +{ + CompileRequest_Interpreter, + CompileRequest_JIT +}; + +/* Number of times a script must be called before we run it in the methodjit. */ +static const size_t CALLS_BEFORE_COMPILE = 16; + +/* Number of loop back-edges we execute in the interpreter before methodjitting. */ +static const size_t BACKEDGES_BEFORE_COMPILE = 16; + +static inline CompileStatus +CanMethodJIT(JSContext *cx, JSScript *script, JSStackFrame *fp, CompileRequest request) +{ + if (!cx->methodJitEnabled) + return Compile_Abort; + JITScriptStatus status = script->getJITStatus(fp->isConstructing()); + if (status == JITScript_Invalid) + return Compile_Abort; + if (request == CompileRequest_Interpreter && + status == JITScript_None && + !cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) && + script->incCallCount() <= CALLS_BEFORE_COMPILE) + { + return Compile_Skipped; + } + if (status == JITScript_None) + return TryCompile(cx, fp); + return Compile_Okay; +} + +/* + * Called from a backedge in the interpreter to decide if we should transition to the + * methodjit. If so, we compile the given function. + */ +static inline CompileStatus +CanMethodJITAtBranch(JSContext *cx, JSScript *script, JSStackFrame *fp, jsbytecode *pc) +{ + if (!cx->methodJitEnabled) + return Compile_Abort; + JITScriptStatus status = script->getJITStatus(fp->isConstructing()); + if (status == JITScript_Invalid) + return Compile_Abort; + if (status == JITScript_None && + !cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) && + cx->compartment->incBackEdgeCount(pc) <= BACKEDGES_BEFORE_COMPILE) + { + return Compile_Skipped; + } + if (status == JITScript_None) + return TryCompile(cx, fp); + return Compile_Okay; +} + +} +} + +#endif diff --git a/js/src/methodjit/MethodJIT.cpp b/js/src/methodjit/MethodJIT.cpp new file mode 100644 index 0000000..6169972 --- /dev/null +++ b/js/src/methodjit/MethodJIT.cpp @@ -0,0 +1,1088 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "MethodJIT.h" +#include "Logging.h" +#include "assembler/jit/ExecutableAllocator.h" +#include "jstracer.h" +#include "BaseAssembler.h" +#include "Compiler.h" +#include "MonoIC.h" +#include "PolyIC.h" +#include "TrampolineCompiler.h" +#include "jscntxtinlines.h" +#include "jscompartment.h" +#include "jsscope.h" + +#include "jsgcinlines.h" +#include "jsinterpinlines.h" + +using namespace js; +using namespace js::mjit; + + +js::mjit::CompilerAllocPolicy::CompilerAllocPolicy(JSContext *cx, Compiler &compiler) +: ContextAllocPolicy(cx), + oomFlag(&compiler.oomInVector) +{ +} +void +JSStackFrame::methodjitStaticAsserts() +{ + /* Static assert for x86 trampolines in MethodJIT.cpp. */ +#if defined(JS_CPU_X86) + JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 0x18); + JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) + 4 == 0x1C); + JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 0x14); + /* ARM uses decimal literals. */ + JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 24); + JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) + 4 == 28); + JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 20); +#elif defined(JS_CPU_X64) + JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 0x30); + JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 0x28); +#endif +} + +/* + * Explanation of VMFrame activation and various helper thunks below. + * + * JaegerTrampoline - Executes a method JIT-compiled JSFunction. This function + * creates a VMFrame on the machine stack and jumps into JIT'd code. The JIT'd + * code will eventually jump back to the VMFrame. + * + * - Called from C++ function EnterMethodJIT. + * - Parameters: cx, fp, code, stackLimit + * + * JaegerThrowpoline - Calls into an exception handler from JIT'd code, and if a + * scripted exception handler is not found, unwinds the VMFrame and returns + * to C++. + * + * - To start exception handling, we return from a stub call to the throwpoline. + * - On entry to the throwpoline, the normal conditions of the jit-code ABI + * are satisfied. + * - To do the unwinding and find out where to continue executing, we call + * js_InternalThrow. + * - js_InternalThrow may return 0, which means the place to continue, if any, + * is above this JaegerShot activation, so we just return, in the same way + * the trampoline does. + * - Otherwise, js_InternalThrow returns a jit-code address to continue execution + * at. Because the jit-code ABI conditions are satisfied, we can just jump to + * that point. + * + * InjectJaegerReturn - Implements the tail of InlineReturn. This is needed for + * tracer integration, where a "return" opcode might not be a safe-point, + * and thus the return path must be injected by hijacking the stub return + * address. + * + * - Used by RunTracer() + */ + +#ifdef JS_METHODJIT_PROFILE_STUBS +static const size_t STUB_CALLS_FOR_OP_COUNT = 255; +static uint32 StubCallsForOp[STUB_CALLS_FOR_OP_COUNT]; +#endif + +extern "C" void JaegerTrampolineReturn(); + +extern "C" void JS_FASTCALL +PushActiveVMFrame(VMFrame &f) +{ + f.entryfp->script()->compartment->jaegerCompartment->pushActiveFrame(&f); + f.regs.fp->setNativeReturnAddress(JS_FUNC_TO_DATA_PTR(void*, JaegerTrampolineReturn)); +} + +extern "C" void JS_FASTCALL +PopActiveVMFrame(VMFrame &f) +{ + f.entryfp->script()->compartment->jaegerCompartment->popActiveFrame(); +} + +extern "C" void JS_FASTCALL +SetVMFrameRegs(VMFrame &f) +{ + f.cx->setCurrentRegs(&f.regs); +} + +#if defined(__APPLE__) || (defined(XP_WIN) && !defined(JS_CPU_X64)) || defined(XP_OS2) +# define SYMBOL_STRING(name) "_" #name +#else +# define SYMBOL_STRING(name) #name +#endif + +JS_STATIC_ASSERT(offsetof(JSFrameRegs, sp) == 0); + +#if defined(__linux__) && defined(JS_CPU_X64) +# define SYMBOL_STRING_RELOC(name) #name "@plt" +#else +# define SYMBOL_STRING_RELOC(name) SYMBOL_STRING(name) +#endif + +#if (defined(XP_WIN) || defined(XP_OS2)) && defined(JS_CPU_X86) +# define SYMBOL_STRING_VMFRAME(name) "@" #name "@4" +#else +# define SYMBOL_STRING_VMFRAME(name) SYMBOL_STRING_RELOC(name) +#endif + +#if defined(XP_MACOSX) +# define HIDE_SYMBOL(name) ".private_extern _" #name +#elif defined(__linux__) +# define HIDE_SYMBOL(name) ".hidden" #name +#else +# define HIDE_SYMBOL(name) +#endif + +#if defined(__GNUC__) + +/* If this assert fails, you need to realign VMFrame to 16 bytes. */ +#ifdef JS_CPU_ARM +JS_STATIC_ASSERT(sizeof(VMFrame) % 8 == 0); +#else +JS_STATIC_ASSERT(sizeof(VMFrame) % 16 == 0); +#endif + +# if defined(JS_CPU_X64) + +/* + * *** DANGER *** + * If these assertions break, update the constants below. + * *** DANGER *** + */ +JS_STATIC_ASSERT(offsetof(VMFrame, savedRBX) == 0x58); +JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38); + +JS_STATIC_ASSERT(JSVAL_TAG_MASK == 0xFFFF800000000000LL); +JS_STATIC_ASSERT(JSVAL_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL); + +asm volatile ( +".text\n" +".globl " SYMBOL_STRING(JaegerTrampoline) "\n" +SYMBOL_STRING(JaegerTrampoline) ":" "\n" + /* Prologue. */ + "pushq %rbp" "\n" + "movq %rsp, %rbp" "\n" + /* Save non-volatile registers. */ + "pushq %r12" "\n" + "pushq %r13" "\n" + "pushq %r14" "\n" + "pushq %r15" "\n" + "pushq %rbx" "\n" + + /* Load mask registers. */ + "movq $0xFFFF800000000000, %r13" "\n" + "movq $0x00007FFFFFFFFFFF, %r14" "\n" + + /* Build the JIT frame. + * rdi = cx + * rsi = fp + * rcx = inlineCallCount + * fp must go into rbx + */ + "pushq %rsi" "\n" /* entryfp */ + "pushq %rcx" "\n" /* inlineCallCount */ + "pushq %rdi" "\n" /* cx */ + "pushq %rsi" "\n" /* fp */ + "movq %rsi, %rbx" "\n" + + /* Space for the rest of the VMFrame. */ + "subq $0x28, %rsp" "\n" + + /* This is actually part of the VMFrame. */ + "pushq %r8" "\n" + + /* Set cx->regs and set the active frame. Save rdx and align frame in one. */ + "pushq %rdx" "\n" + "movq %rsp, %rdi" "\n" + "call " SYMBOL_STRING_VMFRAME(SetVMFrameRegs) "\n" + "movq %rsp, %rdi" "\n" + "call " SYMBOL_STRING_VMFRAME(PushActiveVMFrame) "\n" + + /* Jump into the JIT'd code. */ + "jmp *0(%rsp)" "\n" +); + +asm volatile ( +".text\n" +".globl " SYMBOL_STRING(JaegerTrampolineReturn) "\n" +SYMBOL_STRING(JaegerTrampolineReturn) ":" "\n" + "or %rdx, %rcx" "\n" + "movq %rcx, 0x30(%rbx)" "\n" + "movq %rsp, %rdi" "\n" + "call " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n" + + "addq $0x58, %rsp" "\n" + "popq %rbx" "\n" + "popq %r15" "\n" + "popq %r14" "\n" + "popq %r13" "\n" + "popq %r12" "\n" + "popq %rbp" "\n" + "movq $1, %rax" "\n" + "ret" "\n" +); + +asm volatile ( +".text\n" +".globl " SYMBOL_STRING(JaegerThrowpoline) "\n" +SYMBOL_STRING(JaegerThrowpoline) ":" "\n" + "movq %rsp, %rdi" "\n" + "call " SYMBOL_STRING_RELOC(js_InternalThrow) "\n" + "testq %rax, %rax" "\n" + "je throwpoline_exit" "\n" + "jmp *%rax" "\n" + "throwpoline_exit:" "\n" + "movq %rsp, %rdi" "\n" + "call " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n" + "addq $0x58, %rsp" "\n" + "popq %rbx" "\n" + "popq %r15" "\n" + "popq %r14" "\n" + "popq %r13" "\n" + "popq %r12" "\n" + "popq %rbp" "\n" + "xorq %rax,%rax" "\n" + "ret" "\n" +); + +JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38); + +asm volatile ( +".text\n" +".globl " SYMBOL_STRING(InjectJaegerReturn) "\n" +SYMBOL_STRING(InjectJaegerReturn) ":" "\n" + "movq 0x30(%rbx), %rcx" "\n" /* load fp->rval_ into typeReg */ + "movq 0x28(%rbx), %rax" "\n" /* fp->ncode_ */ + + /* Reimplementation of PunboxAssembler::loadValueAsComponents() */ + "movq %r14, %rdx" "\n" /* payloadReg = payloadMaskReg */ + "andq %rcx, %rdx" "\n" + "xorq %rdx, %rcx" "\n" + + "movq 0x38(%rsp), %rbx" "\n" /* f.fp */ + "jmp *%rax" "\n" /* return. */ +); + +# elif defined(JS_CPU_X86) + +/* + * *** DANGER *** + * If these assertions break, update the constants below. The throwpoline + * should have the offset of savedEBX plus 4, because it needs to clean + * up the argument. + * *** DANGER *** + */ +JS_STATIC_ASSERT(offsetof(VMFrame, savedEBX) == 0x2c); +JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x1C); + +asm volatile ( +".text\n" +".globl " SYMBOL_STRING(JaegerTrampoline) "\n" +SYMBOL_STRING(JaegerTrampoline) ":" "\n" + /* Prologue. */ + "pushl %ebp" "\n" + "movl %esp, %ebp" "\n" + /* Save non-volatile registers. */ + "pushl %esi" "\n" + "pushl %edi" "\n" + "pushl %ebx" "\n" + + /* Build the JIT frame. Push fields in order, + * then align the stack to form esp == VMFrame. */ + "movl 12(%ebp), %ebx" "\n" /* load fp */ + "pushl %ebx" "\n" /* entryfp */ + "pushl 20(%ebp)" "\n" /* stackLimit */ + "pushl 8(%ebp)" "\n" /* cx */ + "pushl %ebx" "\n" /* fp */ + "subl $0x1C, %esp" "\n" + + /* Jump into the JIT'd code. */ + "movl %esp, %ecx" "\n" + "call " SYMBOL_STRING_VMFRAME(SetVMFrameRegs) "\n" + "movl %esp, %ecx" "\n" + "call " SYMBOL_STRING_VMFRAME(PushActiveVMFrame) "\n" + + "jmp *16(%ebp)" "\n" +); + +asm volatile ( +".text\n" +".globl " SYMBOL_STRING(JaegerTrampolineReturn) "\n" +SYMBOL_STRING(JaegerTrampolineReturn) ":" "\n" + "movl %edx, 0x18(%ebx)" "\n" + "movl %ecx, 0x1C(%ebx)" "\n" + "movl %esp, %ecx" "\n" + "call " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n" + + "addl $0x2C, %esp" "\n" + "popl %ebx" "\n" + "popl %edi" "\n" + "popl %esi" "\n" + "popl %ebp" "\n" + "movl $1, %eax" "\n" + "ret" "\n" +); + +asm volatile ( +".text\n" +".globl " SYMBOL_STRING(JaegerThrowpoline) "\n" +SYMBOL_STRING(JaegerThrowpoline) ":" "\n" + /* Align the stack to 16 bytes. */ + "pushl %esp" "\n" + "pushl (%esp)" "\n" + "pushl (%esp)" "\n" + "pushl (%esp)" "\n" + "call " SYMBOL_STRING_RELOC(js_InternalThrow) "\n" + /* Bump the stack by 0x2c, as in the basic trampoline, but + * also one more word to clean up the stack for js_InternalThrow, + * and another to balance the alignment above. */ + "addl $0x10, %esp" "\n" + "testl %eax, %eax" "\n" + "je throwpoline_exit" "\n" + "jmp *%eax" "\n" + "throwpoline_exit:" "\n" + "movl %esp, %ecx" "\n" + "call " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n" + "addl $0x2c, %esp" "\n" + "popl %ebx" "\n" + "popl %edi" "\n" + "popl %esi" "\n" + "popl %ebp" "\n" + "xorl %eax, %eax" "\n" + "ret" "\n" +); + +JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x1C); + +asm volatile ( +".text\n" +".globl " SYMBOL_STRING(InjectJaegerReturn) "\n" +SYMBOL_STRING(InjectJaegerReturn) ":" "\n" + "movl 0x18(%ebx), %edx" "\n" /* fp->rval_ data */ + "movl 0x1C(%ebx), %ecx" "\n" /* fp->rval_ type */ + "movl 0x14(%ebx), %eax" "\n" /* fp->ncode_ */ + "movl 0x1C(%esp), %ebx" "\n" /* f.fp */ + "jmp *%eax" "\n" +); + +# elif defined(JS_CPU_ARM) + +JS_STATIC_ASSERT(sizeof(VMFrame) == 80); +JS_STATIC_ASSERT(offsetof(VMFrame, savedLR) == (4*19)); +JS_STATIC_ASSERT(offsetof(VMFrame, entryfp) == (4*10)); +JS_STATIC_ASSERT(offsetof(VMFrame, stackLimit) == (4*9)); +JS_STATIC_ASSERT(offsetof(VMFrame, cx) == (4*8)); +JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == (4*7)); +JS_STATIC_ASSERT(offsetof(VMFrame, unused) == (4*4)); +JS_STATIC_ASSERT(offsetof(VMFrame, previous) == (4*3)); + +JS_STATIC_ASSERT(JSFrameReg == JSC::ARMRegisters::r11); +JS_STATIC_ASSERT(JSReturnReg_Data == JSC::ARMRegisters::r1); +JS_STATIC_ASSERT(JSReturnReg_Type == JSC::ARMRegisters::r2); + +#ifdef MOZ_THUMB2 +#define FUNCTION_HEADER_EXTRA \ + ".align 2\n" \ + ".thumb\n" \ + ".thumb_func\n" +#else +#define FUNCTION_HEADER_EXTRA +#endif + +asm volatile ( +".text\n" +FUNCTION_HEADER_EXTRA +".globl " SYMBOL_STRING(InjectJaegerReturn) "\n" +SYMBOL_STRING(InjectJaegerReturn) ":" "\n" + /* Restore frame regs. */ + "ldr lr, [r11, #20]" "\n" /* fp->ncode */ + "ldr r1, [r11, #24]" "\n" /* fp->rval data */ + "ldr r2, [r11, #28]" "\n" /* fp->rval type */ + "ldr r11, [sp, #28]" "\n" /* load f.fp */ + "bx lr" "\n" +); + +asm volatile ( +".text\n" +FUNCTION_HEADER_EXTRA +".globl " SYMBOL_STRING(JaegerTrampoline) "\n" +SYMBOL_STRING(JaegerTrampoline) ":" "\n" + /* + * On entry to JaegerTrampoline: + * r0 = cx + * r1 = fp + * r2 = code + * r3 = stackLimit + * + * The VMFrame for ARM looks like this: + * [ lr ] \ + * [ r11 ] | + * [ r10 ] | + * [ r9 ] | Callee-saved registers. + * [ r8 ] | VFP registers d8-d15 may be required here too, but + * [ r7 ] | unconditionally preserving them might be expensive + * [ r6 ] | considering that we might not use them anyway. + * [ r5 ] | + * [ r4 ] / + * [ entryfp ] + * [ stkLimit ] + * [ cx ] + * [ regs.fp ] + * [ regs.pc ] + * [ regs.sp ] + * [ unused ] + * [ previous ] + * [ args.ptr3 ] + * [ args.ptr2 ] + * [ args.ptr ] + */ + + /* Push callee-saved registers. */ +" push {r4-r11,lr}" "\n" + /* Push interesting VMFrame content. */ +" push {r1}" "\n" /* entryfp */ +" push {r3}" "\n" /* stackLimit */ +" push {r0}" "\n" /* cx */ +" push {r1}" "\n" /* regs.fp */ + /* Remaining fields are set elsewhere, but we need to leave space for them. */ +" sub sp, sp, #(4*7)" "\n" + + /* Preserve 'code' (r2) in an arbitrary callee-saved register. */ +" mov r4, r2" "\n" + /* Preserve 'fp' (r1) in r11 (JSFrameReg). */ +" mov r11, r1" "\n" + +" mov r0, sp" "\n" +" blx " SYMBOL_STRING_VMFRAME(SetVMFrameRegs) "\n" +" mov r0, sp" "\n" +" blx " SYMBOL_STRING_VMFRAME(PushActiveVMFrame)"\n" + + /* Call the compiled JavaScript function. */ +" bx r4" "\n" +); + +asm volatile ( +".text\n" +FUNCTION_HEADER_EXTRA +".globl " SYMBOL_STRING(JaegerTrampolineReturn) "\n" +SYMBOL_STRING(JaegerTrampolineReturn) ":" "\n" +" str r1, [r11, #24]" "\n" /* fp->rval data */ +" str r2, [r11, #28]" "\n" /* fp->rval type */ + + /* Tidy up. */ +" mov r0, sp" "\n" +" blx " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n" + + /* Skip past the parameters we pushed (such as cx and the like). */ +" add sp, sp, #(4*7 + 4*4)" "\n" + + /* Set a 'true' return value to indicate successful completion. */ +" mov r0, #1" "\n" +" pop {r4-r11,pc}" "\n" +); + +asm volatile ( +".text\n" +FUNCTION_HEADER_EXTRA +".globl " SYMBOL_STRING(JaegerThrowpoline) "\n" +SYMBOL_STRING(JaegerThrowpoline) ":" "\n" + /* Find the VMFrame pointer for js_InternalThrow. */ +" mov r0, sp" "\n" + + /* Call the utility function that sets up the internal throw routine. */ +" blx " SYMBOL_STRING_RELOC(js_InternalThrow) "\n" + + /* If js_InternalThrow found a scripted handler, jump to it. Otherwise, tidy + * up and return. */ +" cmp r0, #0" "\n" +" it ne" "\n" +" bxne r0" "\n" + + /* Tidy up, then return '0' to represent an unhandled exception. */ +" mov r0, sp" "\n" +" blx " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n" +" add sp, sp, #(4*7 + 4*4)" "\n" +" mov r0, #0" "\n" +" pop {r4-r11,pc}" "\n" +); + +asm volatile ( +".text\n" +FUNCTION_HEADER_EXTRA +".globl " SYMBOL_STRING(JaegerStubVeneer) "\n" +SYMBOL_STRING(JaegerStubVeneer) ":" "\n" + /* We enter this function as a veneer between a compiled method and one of the js_ stubs. We + * need to store the LR somewhere (so it can be modified in case on an exception) and then + * branch to the js_ stub as if nothing had happened. + * The arguments are identical to those for js_* except that the target function should be in + * 'ip'. */ +" push {ip,lr}" "\n" +" blx ip" "\n" +" pop {ip,pc}" "\n" +); + +# else +# error "Unsupported CPU!" +# endif +#elif defined(_MSC_VER) + +#if defined(JS_CPU_X86) + +/* + * *** DANGER *** + * If these assertions break, update the constants below. The throwpoline + * should have the offset of savedEBX plus 4, because it needs to clean + * up the argument. + * *** DANGER *** + */ +JS_STATIC_ASSERT(offsetof(VMFrame, savedEBX) == 0x2c); +JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x1C); + +extern "C" { + + __declspec(naked) void InjectJaegerReturn() + { + __asm { + mov edx, [ebx + 0x18]; + mov ecx, [ebx + 0x1C]; + mov eax, [ebx + 0x14]; + mov ebx, [esp + 0x1C]; + jmp eax; + } + } + + __declspec(naked) JSBool JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code, + Value *stackLimit) + { + __asm { + /* Prologue. */ + push ebp; + mov ebp, esp; + /* Save non-volatile registers. */ + push esi; + push edi; + push ebx; + + /* Build the JIT frame. Push fields in order, + * then align the stack to form esp == VMFrame. */ + mov ebx, [ebp + 12]; + push ebx; + push [ebp + 20]; + push [ebp + 8]; + push ebx; + sub esp, 0x1C; + + /* Jump into into the JIT'd code. */ + mov ecx, esp; + call SetVMFrameRegs; + mov ecx, esp; + call PushActiveVMFrame; + + jmp dword ptr [ebp + 16]; + } + } + + __declspec(naked) void JaegerTrampolineReturn() + { + __asm { + mov [ebx + 0x18], edx; + mov [ebx + 0x1C], ecx; + mov ecx, esp; + call PopActiveVMFrame; + + add esp, 0x2C; + + pop ebx; + pop edi; + pop esi; + pop ebp; + mov eax, 1; + ret; + } + } + + extern "C" void *js_InternalThrow(js::VMFrame &f); + + __declspec(naked) void *JaegerThrowpoline(js::VMFrame *vmFrame) { + __asm { + /* Align the stack to 16 bytes. */ + push esp; + push [esp]; + push [esp]; + push [esp]; + call js_InternalThrow; + /* Bump the stack by 0x2c, as in the basic trampoline, but + * also one more word to clean up the stack for js_InternalThrow, + * and another to balance the alignment above. */ + add esp, 0x10; + test eax, eax; + je throwpoline_exit; + jmp eax; + throwpoline_exit: + mov ecx, esp; + call PopActiveVMFrame; + add esp, 0x2c; + pop ebx; + pop edi; + pop esi; + pop ebp; + xor eax, eax + ret; + } + } +} + +#elif defined(JS_CPU_X64) + +/* + * *** DANGER *** + * If these assertions break, update the constants below. + * *** DANGER *** + */ +JS_STATIC_ASSERT(offsetof(VMFrame, savedRBX) == 0x58); +JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38); +JS_STATIC_ASSERT(JSVAL_TAG_MASK == 0xFFFF800000000000LL); +JS_STATIC_ASSERT(JSVAL_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL); + +// Windows x64 uses assembler version since compiler doesn't support +// inline assembler +#else +# error "Unsupported CPU!" +#endif + +#endif /* _MSC_VER */ + +bool +JaegerCompartment::Initialize() +{ + execAlloc = JSC::ExecutableAllocator::create(); + if (!execAlloc) + return false; + + TrampolineCompiler tc(execAlloc, &trampolines); + if (!tc.compile()) { + delete execAlloc; + return false; + } + +#ifdef JS_METHODJIT_PROFILE_STUBS + for (size_t i = 0; i < STUB_CALLS_FOR_OP_COUNT; ++i) + StubCallsForOp[i] = 0; +#endif + + activeFrame_ = NULL; + + return true; +} + +void +JaegerCompartment::Finish() +{ + TrampolineCompiler::release(&trampolines); + js_delete(execAlloc); +#ifdef JS_METHODJIT_PROFILE_STUBS + FILE *fp = fopen("/tmp/stub-profiling", "wt"); +# define OPDEF(op,val,name,image,length,nuses,ndefs,prec,format) \ + fprintf(fp, "%03d %s %d\n", val, #op, StubCallsForOp[val]); +# include "jsopcode.tbl" +# undef OPDEF + fclose(fp); +#endif +} + +extern "C" JSBool +JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code, Value *stackLimit); + +JSBool +mjit::EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, Value *stackLimit) +{ +#ifdef JS_METHODJIT_SPEW + Profiler prof; + JSScript *script = fp->script(); + + JaegerSpew(JSpew_Prof, "%s jaeger script, line %d\n", + script->filename, script->lineno); + prof.start(); +#endif + + JS_ASSERT(cx->regs->fp == fp); + JSFrameRegs *oldRegs = cx->regs; + + JSBool ok; + { + AssertCompartmentUnchanged pcc(cx); + JSAutoResolveFlags rf(cx, JSRESOLVE_INFER); + ok = JaegerTrampoline(cx, fp, code, stackLimit); + } + + cx->setCurrentRegs(oldRegs); + JS_ASSERT(fp == cx->fp()); + + /* The trampoline wrote the return value but did not set the HAS_RVAL flag. */ + fp->markReturnValue(); + +#ifdef JS_METHODJIT_SPEW + prof.stop(); + JaegerSpew(JSpew_Prof, "script run took %d ms\n", prof.time_ms()); +#endif + + return ok; +} + +static inline JSBool +CheckStackAndEnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code) +{ + bool ok; + Value *stackLimit; + + JS_CHECK_RECURSION(cx, goto error;); + + stackLimit = cx->stack().getStackLimit(cx); + if (!stackLimit) + goto error; + + ok = EnterMethodJIT(cx, fp, code, stackLimit); + JS_ASSERT_IF(!fp->isYielding() && !(fp->isEvalFrame() && !fp->script()->strictModeCode), + !fp->hasCallObj() && !fp->hasArgsObj()); + return ok; + + error: + js::PutOwnedActivationObjects(cx, fp); + return false; +} + +JSBool +mjit::JaegerShot(JSContext *cx) +{ + JSStackFrame *fp = cx->fp(); + JSScript *script = fp->script(); + JITScript *jit = script->getJIT(fp->isConstructing()); + +#ifdef JS_TRACER + if (TRACE_RECORDER(cx)) + AbortRecording(cx, "attempt to enter method JIT while recording"); +#endif + + JS_ASSERT(cx->regs->pc == script->code); + + return CheckStackAndEnterMethodJIT(cx, cx->fp(), jit->invokeEntry); +} + +JSBool +js::mjit::JaegerShotAtSafePoint(JSContext *cx, void *safePoint) +{ +#ifdef JS_TRACER + JS_ASSERT(!TRACE_RECORDER(cx)); +#endif + + return CheckStackAndEnterMethodJIT(cx, cx->fp(), safePoint); +} + +NativeMapEntry * +JITScript::nmap() const +{ + return (NativeMapEntry *)((char*)this + sizeof(JITScript)); +} + +char * +JITScript::nmapSectionLimit() const +{ + return (char *)nmap() + sizeof(NativeMapEntry) * nNmapPairs; +} + +#ifdef JS_MONOIC +ic::GetGlobalNameIC * +JITScript::getGlobalNames() const +{ + return (ic::GetGlobalNameIC *)nmapSectionLimit(); +} + +ic::SetGlobalNameIC * +JITScript::setGlobalNames() const +{ + return (ic::SetGlobalNameIC *)((char *)nmapSectionLimit() + + sizeof(ic::GetGlobalNameIC) * nGetGlobalNames); +} + +ic::CallICInfo * +JITScript::callICs() const +{ + return (ic::CallICInfo *)((char *)setGlobalNames() + + sizeof(ic::SetGlobalNameIC) * nSetGlobalNames); +} + +ic::EqualityICInfo * +JITScript::equalityICs() const +{ + return (ic::EqualityICInfo *)((char *)callICs() + sizeof(ic::CallICInfo) * nCallICs); +} + +ic::TraceICInfo * +JITScript::traceICs() const +{ + return (ic::TraceICInfo *)((char *)equalityICs() + sizeof(ic::EqualityICInfo) * nEqualityICs); +} + +char * +JITScript::monoICSectionsLimit() const +{ + return (char *)traceICs() + sizeof(ic::TraceICInfo) * nTraceICs; +} +#else // JS_MONOIC +char * +JITScript::monoICSectionsLimit() const +{ + return nmapSectionsLimit(); +} +#endif // JS_MONOIC + +#ifdef JS_POLYIC +ic::GetElementIC * +JITScript::getElems() const +{ + return (ic::GetElementIC *)monoICSectionsLimit(); +} + +ic::SetElementIC * +JITScript::setElems() const +{ + return (ic::SetElementIC *)((char *)getElems() + sizeof(ic::GetElementIC) * nGetElems); +} + +ic::PICInfo * +JITScript::pics() const +{ + return (ic::PICInfo *)((char *)setElems() + sizeof(ic::SetElementIC) * nSetElems); +} + +char * +JITScript::polyICSectionsLimit() const +{ + return (char *)pics() + sizeof(ic::PICInfo) * nPICs; +} +#else // JS_POLYIC +char * +JITScript::polyICSectionsLimit() const +{ + return monoICSectionsLimit(); +} +#endif // JS_POLYIC + +js::mjit::CallSite * +JITScript::callSites() const +{ + return (js::mjit::CallSite *)polyICSectionsLimit(); +} + +template +static inline void Destroy(T &t) +{ + t.~T(); +} + +mjit::JITScript::~JITScript() +{ +#if defined DEBUG && (defined JS_CPU_X86 || defined JS_CPU_X64) + void *addr = code.m_code.executableAddress(); + memset(addr, 0xcc, code.m_size); +#endif + + code.m_executablePool->release(); + +#if defined JS_POLYIC + ic::GetElementIC *getElems_ = getElems(); + ic::SetElementIC *setElems_ = setElems(); + ic::PICInfo *pics_ = pics(); + for (uint32 i = 0; i < nGetElems; i++) + Destroy(getElems_[i]); + for (uint32 i = 0; i < nSetElems; i++) + Destroy(setElems_[i]); + for (uint32 i = 0; i < nPICs; i++) + Destroy(pics_[i]); +#endif + +#if defined JS_MONOIC + for (JSC::ExecutablePool **pExecPool = execPools.begin(); + pExecPool != execPools.end(); + ++pExecPool) + { + (*pExecPool)->release(); + } + + ic::CallICInfo *callICs_ = callICs(); + for (uint32 i = 0; i < nCallICs; i++) + callICs_[i].releasePools(); +#endif +} + +/* Please keep in sync with Compiler::finishThisUp! */ +size_t +mjit::JITScript::scriptDataSize() +{ + return sizeof(JITScript) + + sizeof(NativeMapEntry) * nNmapPairs + +#if defined JS_MONOIC + sizeof(ic::GetGlobalNameIC) * nGetGlobalNames + + sizeof(ic::SetGlobalNameIC) * nSetGlobalNames + + sizeof(ic::CallICInfo) * nCallICs + + sizeof(ic::EqualityICInfo) * nEqualityICs + + sizeof(ic::TraceICInfo) * nTraceICs + +#endif +#if defined JS_POLYIC + sizeof(ic::PICInfo) * nPICs + + sizeof(ic::GetElementIC) * nGetElems + + sizeof(ic::SetElementIC) * nSetElems + +#endif + sizeof(CallSite) * nCallSites; +} + +void +mjit::ReleaseScriptCode(JSContext *cx, JSScript *script) +{ + // NB: The recompiler may call ReleaseScriptCode, in which case it + // will get called again when the script is destroyed, so we + // must protect against calling ReleaseScriptCode twice. + JITScript *jscr; + + if ((jscr = script->jitNormal)) { + cx->runtime->mjitMemoryUsed -= jscr->scriptDataSize() + jscr->mainCodeSize(); + + jscr->~JITScript(); + cx->free(jscr); + script->jitNormal = NULL; + script->jitArityCheckNormal = NULL; + } + + if ((jscr = script->jitCtor)) { + cx->runtime->mjitMemoryUsed -= jscr->scriptDataSize() + jscr->mainCodeSize(); + + jscr->~JITScript(); + cx->free(jscr); + script->jitCtor = NULL; + script->jitArityCheckCtor = NULL; + } +} + +#ifdef JS_METHODJIT_PROFILE_STUBS +void JS_FASTCALL +mjit::ProfileStubCall(VMFrame &f) +{ + JSOp op = JSOp(*f.regs.pc); + StubCallsForOp[op]++; +} +#endif + +#ifdef JS_POLYIC +static int +PICPCComparator(const void *key, const void *entry) +{ + const jsbytecode *pc = (const jsbytecode *)key; + const ic::PICInfo *pic = (const ic::PICInfo *)entry; + + if (ic::PICInfo::CALL != pic->kind) + return ic::PICInfo::CALL - pic->kind; + + /* + * We can't just return |pc - pic->pc| because the pointers may be + * far apart and an int (or even a ptrdiff_t) may not be large + * enough to hold the difference. C says that pointer subtraction + * is only guaranteed to work for two pointers into the same array. + */ + if (pc < pic->pc) + return -1; + else if (pc == pic->pc) + return 0; + else + return 1; +} + +uintN +mjit::GetCallTargetCount(JSScript *script, jsbytecode *pc) +{ + ic::PICInfo *pic; + + if (mjit::JITScript *jit = script->getJIT(false)) { + pic = (ic::PICInfo *)bsearch(pc, jit->pics(), jit->nPICs, sizeof(ic::PICInfo), + PICPCComparator); + if (pic) + return pic->stubsGenerated + 1; /* Add 1 for the inline path. */ + } + + if (mjit::JITScript *jit = script->getJIT(true)) { + pic = (ic::PICInfo *)bsearch(pc, jit->pics(), jit->nPICs, sizeof(ic::PICInfo), + PICPCComparator); + if (pic) + return pic->stubsGenerated + 1; /* Add 1 for the inline path. */ + } + + return 1; +} +#else +uintN +mjit::GetCallTargetCount(JSScript *script, jsbytecode *pc) +{ + return 1; +} +#endif + +jsbytecode * +JITScript::nativeToPC(void *returnAddress) const +{ + size_t low = 0; + size_t high = nCallICs; + js::mjit::ic::CallICInfo *callICs_ = callICs(); + while (high > low + 1) { + /* Could overflow here on a script with 2 billion calls. Oh well. */ + size_t mid = (high + low) / 2; + void *entry = callICs_[mid].funGuard.executableAddress(); + + /* + * Use >= here as the return address of the call is likely to be + * the start address of the next (possibly IC'ed) operation. + */ + if (entry >= returnAddress) + high = mid; + else + low = mid; + } + + js::mjit::ic::CallICInfo &ic = callICs_[low]; + + JS_ASSERT((uint8*)ic.funGuard.executableAddress() + ic.joinPointOffset == returnAddress); + return ic.pc; +} + diff --git a/js/src/methodjit/MethodJIT.h b/js/src/methodjit/MethodJIT.h new file mode 100644 index 0000000..8c2ab39 --- /dev/null +++ b/js/src/methodjit/MethodJIT.h @@ -0,0 +1,496 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_h__ && defined JS_METHODJIT +#define jsjaeger_h__ + +#include "jscntxt.h" + +#include "assembler/assembler/MacroAssemblerCodeRef.h" + +#if !defined JS_CPU_X64 && \ + !defined JS_CPU_X86 && \ + !defined JS_CPU_ARM +# error "Oh no, you should define a platform so this compiles." +#endif + +#if !defined(JS_NUNBOX32) && !defined(JS_PUNBOX64) +# error "No boxing format selected." +#endif + +namespace js { + +namespace mjit { struct JITScript; } + +struct VMFrame +{ + union Arguments { + struct { + void *ptr; + void *ptr2; + void *ptr3; + } x; + struct { + uint32 lazyArgsObj; + uint32 dynamicArgc; + } call; + } u; + + VMFrame *previous; + void *unused; + JSFrameRegs regs; + JSContext *cx; + Value *stackLimit; + JSStackFrame *entryfp; + +#if defined(JS_CPU_X86) + void *savedEBX; + void *savedEDI; + void *savedESI; + void *savedEBP; + void *savedEIP; + +# ifdef JS_NO_FASTCALL + inline void** returnAddressLocation() { + return reinterpret_cast(this) - 5; + } +# else + inline void** returnAddressLocation() { + return reinterpret_cast(this) - 1; + } +# endif +#elif defined(JS_CPU_X64) + void *savedRBX; +# ifdef _WIN64 + void *savedRSI; + void *savedRDI; +# endif + void *savedR15; + void *savedR14; + void *savedR13; + void *savedR12; + void *savedRBP; + void *savedRIP; + +# ifdef _WIN64 + inline void** returnAddressLocation() { + return reinterpret_cast(this) - 5; + } +# else + inline void** returnAddressLocation() { + return reinterpret_cast(this) - 1; + } +# endif + +#elif defined(JS_CPU_ARM) + void *savedR4; + void *savedR5; + void *savedR6; + void *savedR7; + void *savedR8; + void *savedR9; + void *savedR10; + void *savedR11; + void *savedLR; + + inline void** returnAddressLocation() { + return reinterpret_cast(this) - 1; + } +#else +# error "The VMFrame layout isn't defined for your processor architecture!" +#endif + + JSRuntime *runtime() { return cx->runtime; } + + JSStackFrame *&fp() { return regs.fp; } + mjit::JITScript *jit() { return fp()->jit(); } +}; + +#ifdef JS_CPU_ARM +// WARNING: Do not call this function directly from C(++) code because it is not ABI-compliant. +extern "C" void JaegerStubVeneer(void); +#endif + +namespace mjit { + +/* + * Trampolines to force returns from jit code. + * See also TrampolineCompiler::generateForceReturn(Fast). + */ +struct Trampolines { + typedef void (*TrampolinePtr)(); + + TrampolinePtr forceReturn; + JSC::ExecutablePool *forceReturnPool; + +#if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64) + TrampolinePtr forceReturnFast; + JSC::ExecutablePool *forceReturnFastPool; +#endif +}; + +/* + * Method JIT compartment data. Currently, there is exactly one per + * JS compartment. It would be safe for multiple JS compartments to + * share a JaegerCompartment as long as only one thread can enter + * the JaegerCompartment at a time. + */ +class JaegerCompartment { + JSC::ExecutableAllocator *execAlloc; // allocator for jit code + Trampolines trampolines; // force-return trampolines + VMFrame *activeFrame_; // current active VMFrame + + void Finish(); + + public: + bool Initialize(); + + ~JaegerCompartment() { Finish(); } + + JSC::ExecutablePool *poolForSize(size_t size) { + return execAlloc->poolForSize(size); + } + + VMFrame *activeFrame() { + return activeFrame_; + } + + void pushActiveFrame(VMFrame *f) { + f->previous = activeFrame_; + activeFrame_ = f; + } + + void popActiveFrame() { + JS_ASSERT(activeFrame_); + activeFrame_ = activeFrame_->previous; + } + + Trampolines::TrampolinePtr forceReturnTrampoline() const { + return trampolines.forceReturn; + } + +#if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64) + Trampolines::TrampolinePtr forceReturnFastTrampoline() const { + return trampolines.forceReturnFast; + } +#endif +}; + +/* + * Allocation policy for compiler jstl objects. The goal is to free the + * compiler from having to check and propagate OOM after every time we + * append to a vector. We do this by reporting OOM to the engine and + * setting a flag on the compiler when OOM occurs. The compiler is required + * to check for OOM only before trying to use the contents of the list. + */ +class CompilerAllocPolicy : public ContextAllocPolicy +{ + bool *oomFlag; + + void *checkAlloc(void *p) { + if (!p) + *oomFlag = true; + return p; + } + + public: + CompilerAllocPolicy(JSContext *cx, bool *oomFlag) + : ContextAllocPolicy(cx), oomFlag(oomFlag) {} + CompilerAllocPolicy(JSContext *cx, Compiler &compiler); + + void *malloc(size_t bytes) { return checkAlloc(ContextAllocPolicy::malloc(bytes)); } + void *realloc(void *p, size_t bytes) { + return checkAlloc(ContextAllocPolicy::realloc(p, bytes)); + } +}; + +namespace ic { +# if defined JS_POLYIC + struct PICInfo; + struct GetElementIC; + struct SetElementIC; +# endif +# if defined JS_MONOIC + struct GetGlobalNameIC; + struct SetGlobalNameIC; + struct EqualityICInfo; + struct TraceICInfo; + struct CallICInfo; +# endif +} +} + +typedef void (JS_FASTCALL *VoidStub)(VMFrame &); +typedef void (JS_FASTCALL *VoidVpStub)(VMFrame &, Value *); +typedef void (JS_FASTCALL *VoidStubUInt32)(VMFrame &, uint32); +typedef void (JS_FASTCALL *VoidStubInt32)(VMFrame &, int32); +typedef JSBool (JS_FASTCALL *BoolStub)(VMFrame &); +typedef void * (JS_FASTCALL *VoidPtrStub)(VMFrame &); +typedef void * (JS_FASTCALL *VoidPtrStubPC)(VMFrame &, jsbytecode *); +typedef void * (JS_FASTCALL *VoidPtrStubUInt32)(VMFrame &, uint32); +typedef JSObject * (JS_FASTCALL *JSObjStub)(VMFrame &); +typedef JSObject * (JS_FASTCALL *JSObjStubUInt32)(VMFrame &, uint32); +typedef JSObject * (JS_FASTCALL *JSObjStubFun)(VMFrame &, JSFunction *); +typedef void (JS_FASTCALL *VoidStubFun)(VMFrame &, JSFunction *); +typedef JSObject * (JS_FASTCALL *JSObjStubJSObj)(VMFrame &, JSObject *); +typedef void (JS_FASTCALL *VoidStubAtom)(VMFrame &, JSAtom *); +typedef JSString * (JS_FASTCALL *JSStrStub)(VMFrame &); +typedef JSString * (JS_FASTCALL *JSStrStubUInt32)(VMFrame &, uint32); +typedef void (JS_FASTCALL *VoidStubJSObj)(VMFrame &, JSObject *); +typedef void (JS_FASTCALL *VoidStubPC)(VMFrame &, jsbytecode *); +typedef JSBool (JS_FASTCALL *BoolStubUInt32)(VMFrame &f, uint32); +#ifdef JS_MONOIC +typedef void (JS_FASTCALL *VoidStubCallIC)(VMFrame &, js::mjit::ic::CallICInfo *); +typedef void * (JS_FASTCALL *VoidPtrStubCallIC)(VMFrame &, js::mjit::ic::CallICInfo *); +typedef void (JS_FASTCALL *VoidStubGetGlobal)(VMFrame &, js::mjit::ic::GetGlobalNameIC *); +typedef void (JS_FASTCALL *VoidStubSetGlobal)(VMFrame &, js::mjit::ic::SetGlobalNameIC *); +typedef JSBool (JS_FASTCALL *BoolStubEqualityIC)(VMFrame &, js::mjit::ic::EqualityICInfo *); +typedef void * (JS_FASTCALL *VoidPtrStubTraceIC)(VMFrame &, js::mjit::ic::TraceICInfo *); +#endif +#ifdef JS_POLYIC +typedef void (JS_FASTCALL *VoidStubPIC)(VMFrame &, js::mjit::ic::PICInfo *); +typedef void (JS_FASTCALL *VoidStubGetElemIC)(VMFrame &, js::mjit::ic::GetElementIC *); +typedef void (JS_FASTCALL *VoidStubSetElemIC)(VMFrame &f, js::mjit::ic::SetElementIC *); +#endif + +namespace mjit { + +struct CallSite; + +struct NativeMapEntry { + size_t bcOff; /* bytecode offset in script */ + void *ncode; /* pointer to native code */ +}; + +struct JITScript { + typedef JSC::MacroAssemblerCodeRef CodeRef; + CodeRef code; /* pool & code addresses */ + + + void *invokeEntry; /* invoke address */ + void *fastEntry; /* cached entry, fastest */ + void *arityCheckEntry; /* arity check address */ + + /* + * This struct has several variable-length sections that are allocated on + * the end: nmaps, MICs, callICs, etc. To save space -- worthwhile + * because JITScripts are common -- we only record their lengths. We can + * find any of the sections from the lengths because we know their order. + * Therefore, do not change the section ordering in finishThisUp() without + * changing nMICs() et al as well. + */ + uint32 nNmapPairs:31; /* The NativeMapEntrys are sorted by .bcOff. + .ncode values may not be NULL. */ + bool singleStepMode:1; /* compiled in "single step mode" */ +#ifdef JS_MONOIC + uint32 nGetGlobalNames; + uint32 nSetGlobalNames; + uint32 nCallICs; + uint32 nEqualityICs; + uint32 nTraceICs; +#endif +#ifdef JS_POLYIC + uint32 nGetElems; + uint32 nSetElems; + uint32 nPICs; +#endif + uint32 nCallSites; + +#ifdef JS_MONOIC + // Additional ExecutablePools that IC stubs were generated into. + typedef Vector ExecPoolVector; + ExecPoolVector execPools; +#endif + + NativeMapEntry *nmap() const; +#ifdef JS_MONOIC + ic::GetGlobalNameIC *getGlobalNames() const; + ic::SetGlobalNameIC *setGlobalNames() const; + ic::CallICInfo *callICs() const; + ic::EqualityICInfo *equalityICs() const; + ic::TraceICInfo *traceICs() const; +#endif +#ifdef JS_POLYIC + ic::GetElementIC *getElems() const; + ic::SetElementIC *setElems() const; + ic::PICInfo *pics() const; +#endif + js::mjit::CallSite *callSites() const; + + ~JITScript(); + + bool isValidCode(void *ptr) { + char *jitcode = (char *)code.m_code.executableAddress(); + char *jcheck = (char *)ptr; + return jcheck >= jitcode && jcheck < jitcode + code.m_size; + } + + void nukeScriptDependentICs(); + void sweepCallICs(JSContext *cx, bool purgeAll); + void purgeMICs(); + void purgePICs(); + + size_t scriptDataSize(); + + size_t mainCodeSize() { return code.m_size; } /* doesn't account for fragmentation */ + + jsbytecode *nativeToPC(void *returnAddress) const; + + private: + /* Helpers used to navigate the variable-length sections. */ + char *nmapSectionLimit() const; + char *monoICSectionsLimit() const; + char *polyICSectionsLimit() const; +}; + +/* + * Execute the given mjit code. This is a low-level call and callers must + * provide the same guarantees as JaegerShot/CheckStackAndEnterMethodJIT. + */ +JSBool EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, Value *stackLimit); + +/* Execute a method that has been JIT compiled. */ +JSBool JaegerShot(JSContext *cx); + +/* Drop into the middle of a method at an arbitrary point, and execute. */ +JSBool JaegerShotAtSafePoint(JSContext *cx, void *safePoint); + +enum CompileStatus +{ + Compile_Okay, + Compile_Abort, + Compile_Error, + Compile_Skipped +}; + +void JS_FASTCALL +ProfileStubCall(VMFrame &f); + +CompileStatus JS_NEVER_INLINE +TryCompile(JSContext *cx, JSStackFrame *fp); + +void +ReleaseScriptCode(JSContext *cx, JSScript *script); + +struct CallSite +{ + uint32 codeOffset; + uint32 pcOffset; + uint32 id; + + // Normally, callsite ID is the __LINE__ in the program that added the + // callsite. Since traps can be removed, we make sure they carry over + // from each compilation, and identify them with a single, canonical + // ID. Hopefully a SpiderMonkey file won't have two billion source lines. + static const uint32 MAGIC_TRAP_ID = 0xFEDCBABC; + + void initialize(uint32 codeOffset, uint32 pcOffset, uint32 id) { + this->codeOffset = codeOffset; + this->pcOffset = pcOffset; + this->id = id; + } + + bool isTrap() const { + return id == MAGIC_TRAP_ID; + } +}; + +/* + * Re-enables a tracepoint in the method JIT. When full is true, we + * also reset the iteration counter. + */ +void +ResetTraceHint(JSScript *script, jsbytecode *pc, uint16_t index, bool full); + +uintN +GetCallTargetCount(JSScript *script, jsbytecode *pc); + +inline void * bsearch_nmap(NativeMapEntry *nmap, size_t nPairs, size_t bcOff) +{ + size_t lo = 1, hi = nPairs; + while (1) { + /* current unsearched space is from lo-1 to hi-1, inclusive. */ + if (lo > hi) + return NULL; /* not found */ + size_t mid = (lo + hi) / 2; + size_t bcOff_mid = nmap[mid-1].bcOff; + if (bcOff < bcOff_mid) { + hi = mid-1; + continue; + } + if (bcOff > bcOff_mid) { + lo = mid+1; + continue; + } + return nmap[mid-1].ncode; + } +} + +} /* namespace mjit */ + +} /* namespace js */ + +inline void * +JSScript::maybeNativeCodeForPC(bool constructing, jsbytecode *pc) +{ + js::mjit::JITScript *jit = getJIT(constructing); + if (!jit) + return NULL; + JS_ASSERT(pc >= code && pc < code + length); + return bsearch_nmap(jit->nmap(), jit->nNmapPairs, (size_t)(pc - code)); +} + +inline void * +JSScript::nativeCodeForPC(bool constructing, jsbytecode *pc) +{ + js::mjit::JITScript *jit = getJIT(constructing); + JS_ASSERT(pc >= code && pc < code + length); + void* native = bsearch_nmap(jit->nmap(), jit->nNmapPairs, (size_t)(pc - code)); + JS_ASSERT(native); + return native; +} + +#ifdef _MSC_VER +extern "C" void *JaegerThrowpoline(js::VMFrame *vmFrame); +#else +extern "C" void JaegerThrowpoline(); +#endif +extern "C" void InjectJaegerReturn(); + +#endif /* jsjaeger_h__ */ + diff --git a/js/src/methodjit/MonoIC.cpp b/js/src/methodjit/MonoIC.cpp new file mode 100644 index 0000000..b5a42b9 --- /dev/null +++ b/js/src/methodjit/MonoIC.cpp @@ -0,0 +1,1338 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "jsscope.h" +#include "jsnum.h" +#include "MonoIC.h" +#include "StubCalls.h" +#include "StubCalls-inl.h" +#include "assembler/assembler/LinkBuffer.h" +#include "assembler/assembler/MacroAssembler.h" +#include "assembler/assembler/CodeLocation.h" +#include "methodjit/CodeGenIncludes.h" +#include "methodjit/Compiler.h" +#include "methodjit/ICRepatcher.h" +#include "methodjit/PolyIC.h" +#include "InlineFrameAssembler.h" +#include "jsobj.h" + +#include "jsinterpinlines.h" +#include "jsobjinlines.h" +#include "jsscopeinlines.h" +#include "jsscriptinlines.h" + +using namespace js; +using namespace js::mjit; +using namespace js::mjit::ic; + +typedef JSC::MacroAssembler::RegisterID RegisterID; +typedef JSC::MacroAssembler::Address Address; +typedef JSC::MacroAssembler::Jump Jump; +typedef JSC::MacroAssembler::Imm32 Imm32; +typedef JSC::MacroAssembler::ImmPtr ImmPtr; +typedef JSC::MacroAssembler::Call Call; +typedef JSC::MacroAssembler::Label Label; +typedef JSC::MacroAssembler::DataLabel32 DataLabel32; + +#if defined JS_MONOIC + +static void +PatchGetFallback(VMFrame &f, ic::GetGlobalNameIC *ic) +{ + Repatcher repatch(f.jit()); + JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, stubs::GetGlobalName)); + repatch.relink(ic->slowPathCall, fptr); +} + +void JS_FASTCALL +ic::GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic) +{ + JSObject *obj = f.fp()->scopeChain().getGlobal(); + JSAtom *atom = f.fp()->script()->getAtom(GET_INDEX(f.regs.pc)); + jsid id = ATOM_TO_JSID(atom); + + const Shape *shape = obj->nativeLookup(id); + if (!shape || + !shape->hasDefaultGetterOrIsMethod() || + !shape->hasSlot()) + { + if (shape) + PatchGetFallback(f, ic); + stubs::GetGlobalName(f); + return; + } + uint32 slot = shape->slot; + + /* Patch shape guard. */ + Repatcher repatcher(f.jit()); + repatcher.repatch(ic->fastPathStart.dataLabel32AtOffset(ic->shapeOffset), obj->shape()); + + /* Patch loads. */ + JSC::CodeLocationLabel label = ic->fastPathStart.labelAtOffset(ic->loadStoreOffset); + repatcher.patchAddressOffsetForValueLoad(label, slot * sizeof(Value)); + + /* Do load anyway... this time. */ + stubs::GetGlobalName(f); +} + +template +static void JS_FASTCALL +DisabledSetGlobal(VMFrame &f, ic::SetGlobalNameIC *ic) +{ + JSScript *script = f.fp()->script(); + JSAtom *atom = script->getAtom(GET_INDEX(f.regs.pc)); + stubs::SetGlobalName(f, atom); +} + +template void JS_FASTCALL DisabledSetGlobal(VMFrame &f, ic::SetGlobalNameIC *ic); +template void JS_FASTCALL DisabledSetGlobal(VMFrame &f, ic::SetGlobalNameIC *ic); + +template +static void JS_FASTCALL +DisabledSetGlobalNoCache(VMFrame &f, ic::SetGlobalNameIC *ic) +{ + JSScript *script = f.fp()->script(); + JSAtom *atom = script->getAtom(GET_INDEX(f.regs.pc)); + stubs::SetGlobalNameNoCache(f, atom); +} + +template void JS_FASTCALL DisabledSetGlobalNoCache(VMFrame &f, ic::SetGlobalNameIC *ic); +template void JS_FASTCALL DisabledSetGlobalNoCache(VMFrame &f, ic::SetGlobalNameIC *ic); + +static void +PatchSetFallback(VMFrame &f, ic::SetGlobalNameIC *ic) +{ + JSScript *script = f.fp()->script(); + + Repatcher repatch(f.jit()); + VoidStubSetGlobal stub = ic->usePropertyCache + ? STRICT_VARIANT(DisabledSetGlobal) + : STRICT_VARIANT(DisabledSetGlobalNoCache); + JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, stub)); + repatch.relink(ic->slowPathCall, fptr); +} + +void +SetGlobalNameIC::patchExtraShapeGuard(Repatcher &repatcher, int32 shape) +{ + JS_ASSERT(hasExtraStub); + + JSC::CodeLocationLabel label(JSC::MacroAssemblerCodePtr(extraStub.start())); + repatcher.repatch(label.dataLabel32AtOffset(extraShapeGuard), shape); +} + +void +SetGlobalNameIC::patchInlineShapeGuard(Repatcher &repatcher, int32 shape) +{ + JSC::CodeLocationDataLabel32 label = fastPathStart.dataLabel32AtOffset(shapeOffset); + repatcher.repatch(label, shape); +} + +static LookupStatus +UpdateSetGlobalNameStub(VMFrame &f, ic::SetGlobalNameIC *ic, JSObject *obj, const Shape *shape) +{ + Repatcher repatcher(ic->extraStub); + + ic->patchExtraShapeGuard(repatcher, obj->shape()); + + JSC::CodeLocationLabel label(JSC::MacroAssemblerCodePtr(ic->extraStub.start())); + label = label.labelAtOffset(ic->extraStoreOffset); + repatcher.patchAddressOffsetForValueStore(label, shape->slot * sizeof(Value), + ic->vr.isTypeKnown()); + + return Lookup_Cacheable; +} + +static LookupStatus +AttachSetGlobalNameStub(VMFrame &f, ic::SetGlobalNameIC *ic, JSObject *obj, const Shape *shape) +{ + Assembler masm; + + Label start = masm.label(); + + DataLabel32 shapeLabel; + Jump guard = masm.branch32WithPatch(Assembler::NotEqual, ic->shapeReg, Imm32(obj->shape()), + shapeLabel); + + /* A constant object needs rematerialization. */ + if (ic->objConst) + masm.move(ImmPtr(obj), ic->objReg); + + JS_ASSERT(obj->branded()); + + /* + * Load obj->slots. If ic->objConst, then this clobbers objReg, because + * ic->objReg == ic->shapeReg. + */ + masm.loadPtr(Address(ic->objReg, offsetof(JSObject, slots)), ic->shapeReg); + + /* Test if overwriting a function-tagged slot. */ + Address slot(ic->shapeReg, sizeof(Value) * shape->slot); + Jump isNotObject = masm.testObject(Assembler::NotEqual, slot); + + /* Now, test if the object is a function object. */ + masm.loadPayload(slot, ic->shapeReg); + Jump isFun = masm.testFunction(Assembler::Equal, ic->shapeReg); + + /* Restore shapeReg to obj->slots, since we clobbered it. */ + if (ic->objConst) + masm.move(ImmPtr(obj), ic->objReg); + masm.loadPtr(Address(ic->objReg, offsetof(JSObject, slots)), ic->shapeReg); + + /* If the object test fails, shapeReg is still obj->slots. */ + isNotObject.linkTo(masm.label(), &masm); + DataLabel32 store = masm.storeValueWithAddressOffsetPatch(ic->vr, slot); + + Jump done = masm.jump(); + + JITScript *jit = f.jit(); + LinkerHelper linker(masm); + JSC::ExecutablePool *ep = linker.init(f.cx); + if (!ep) + return Lookup_Error; + if (!jit->execPools.append(ep)) { + ep->release(); + js_ReportOutOfMemory(f.cx); + return Lookup_Error; + } + + if (!linker.verifyRange(jit)) + return Lookup_Uncacheable; + + linker.link(done, ic->fastPathStart.labelAtOffset(ic->fastRejoinOffset)); + linker.link(guard, ic->slowPathStart); + linker.link(isFun, ic->slowPathStart); + + JSC::CodeLocationLabel cs = linker.finalize(); + JaegerSpew(JSpew_PICs, "generated setgname stub at %p\n", cs.executableAddress()); + + Repatcher repatcher(f.jit()); + repatcher.relink(ic->fastPathStart.jumpAtOffset(ic->inlineShapeJump), cs); + + int offset = linker.locationOf(shapeLabel) - linker.locationOf(start); + ic->extraShapeGuard = offset; + JS_ASSERT(ic->extraShapeGuard == offset); + + ic->extraStub = JSC::JITCode(cs.executableAddress(), linker.size()); + offset = linker.locationOf(store) - linker.locationOf(start); + ic->extraStoreOffset = offset; + JS_ASSERT(ic->extraStoreOffset == offset); + + ic->hasExtraStub = true; + + return Lookup_Cacheable; +} + +static LookupStatus +UpdateSetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic, JSObject *obj, const Shape *shape) +{ + /* Give globals a chance to appear. */ + if (!shape) + return Lookup_Uncacheable; + + if (shape->isMethod() || + !shape->hasDefaultSetter() || + !shape->writable() || + !shape->hasSlot()) + { + /* Disable the IC for weird shape attributes. */ + PatchSetFallback(f, ic); + return Lookup_Uncacheable; + } + + /* Branded sets must guard that they don't overwrite method-valued properties. */ + if (obj->branded()) { + /* + * If this slot has a function valued property, the tail of this opcode + * could change the shape. Even if it doesn't, the IC is probably + * pointless, because it will always hit the function-test path and + * bail out. In these cases, don't bother building or updating the IC. + */ + const Value &v = obj->getSlot(shape->slot); + if (v.isObject() && v.toObject().isFunction()) { + /* + * If we're going to rebrand, the object may unbrand, allowing this + * IC to come back to life. In that case, we don't disable the IC. + */ + if (!ChangesMethodValue(v, f.regs.sp[-1])) + PatchSetFallback(f, ic); + return Lookup_Uncacheable; + } + + if (ic->hasExtraStub) + return UpdateSetGlobalNameStub(f, ic, obj, shape); + + return AttachSetGlobalNameStub(f, ic, obj, shape); + } + + /* Object is not branded, so we can use the inline path. */ + Repatcher repatcher(f.jit()); + ic->patchInlineShapeGuard(repatcher, obj->shape()); + + JSC::CodeLocationLabel label = ic->fastPathStart.labelAtOffset(ic->loadStoreOffset); + repatcher.patchAddressOffsetForValueStore(label, shape->slot * sizeof(Value), + ic->vr.isTypeKnown()); + + return Lookup_Cacheable; +} + +void JS_FASTCALL +ic::SetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic) +{ + JSObject *obj = f.fp()->scopeChain().getGlobal(); + JSScript *script = f.fp()->script(); + JSAtom *atom = script->getAtom(GET_INDEX(f.regs.pc)); + const Shape *shape = obj->nativeLookup(ATOM_TO_JSID(atom)); + + LookupStatus status = UpdateSetGlobalName(f, ic, obj, shape); + if (status == Lookup_Error) + THROW(); + + if (ic->usePropertyCache) + STRICT_VARIANT(stubs::SetGlobalName)(f, atom); + else + STRICT_VARIANT(stubs::SetGlobalNameNoCache)(f, atom); +} + +class EqualityICLinker : public LinkerHelper +{ + VMFrame &f; + + public: + EqualityICLinker(Assembler &masm, VMFrame &f) + : LinkerHelper(masm), f(f) + { } + + bool init(JSContext *cx) { + JSC::ExecutablePool *pool = LinkerHelper::init(cx); + if (!pool) + return false; + JSScript *script = f.fp()->script(); + JITScript *jit = script->getJIT(f.fp()->isConstructing()); + if (!jit->execPools.append(pool)) { + pool->release(); + js_ReportOutOfMemory(cx); + return false; + } + return true; + } +}; + +/* Rough over-estimate of how much memory we need to unprotect. */ +static const uint32 INLINE_PATH_LENGTH = 64; + +class EqualityCompiler : public BaseCompiler +{ + VMFrame &f; + EqualityICInfo ⁣ + + Vector jumpList; + Jump trueJump; + Jump falseJump; + + public: + EqualityCompiler(VMFrame &f, EqualityICInfo &ic) + : BaseCompiler(f.cx), f(f), ic(ic), jumpList(SystemAllocPolicy()) + { + } + + void linkToStub(Jump j) + { + jumpList.append(j); + } + + void linkTrue(Jump j) + { + trueJump = j; + } + + void linkFalse(Jump j) + { + falseJump = j; + } + + void generateStringPath(Assembler &masm) + { + const ValueRemat &lvr = ic.lvr; + const ValueRemat &rvr = ic.rvr; + + if (!lvr.isConstant() && !lvr.isType(JSVAL_TYPE_STRING)) { + Jump lhsFail = masm.testString(Assembler::NotEqual, lvr.typeReg()); + linkToStub(lhsFail); + } + + if (!rvr.isConstant() && !rvr.isType(JSVAL_TYPE_STRING)) { + Jump rhsFail = masm.testString(Assembler::NotEqual, rvr.typeReg()); + linkToStub(rhsFail); + } + + RegisterID tmp = ic.tempReg; + + /* Test if lhs/rhs are atomized. */ + Imm32 atomizedFlags(JSString::FLAT | JSString::ATOMIZED); + + masm.load32(Address(lvr.dataReg(), JSString::offsetOfLengthAndFlags()), tmp); + masm.and32(Imm32(JSString::TYPE_FLAGS_MASK), tmp); + Jump lhsNotAtomized = masm.branch32(Assembler::NotEqual, tmp, atomizedFlags); + linkToStub(lhsNotAtomized); + + if (!rvr.isConstant()) { + masm.load32(Address(rvr.dataReg(), JSString::offsetOfLengthAndFlags()), tmp); + masm.and32(Imm32(JSString::TYPE_FLAGS_MASK), tmp); + Jump rhsNotAtomized = masm.branch32(Assembler::NotEqual, tmp, atomizedFlags); + linkToStub(rhsNotAtomized); + } + + if (rvr.isConstant()) { + JSString *str = rvr.value().toString(); + JS_ASSERT(str->isAtomized()); + Jump test = masm.branchPtr(ic.cond, lvr.dataReg(), ImmPtr(str)); + linkTrue(test); + } else { + Jump test = masm.branchPtr(ic.cond, lvr.dataReg(), rvr.dataReg()); + linkTrue(test); + } + + Jump fallthrough = masm.jump(); + linkFalse(fallthrough); + } + + void generateObjectPath(Assembler &masm) + { + ValueRemat &lvr = ic.lvr; + ValueRemat &rvr = ic.rvr; + + if (!lvr.isConstant() && !lvr.isType(JSVAL_TYPE_OBJECT)) { + Jump lhsFail = masm.testObject(Assembler::NotEqual, lvr.typeReg()); + linkToStub(lhsFail); + } + + if (!rvr.isConstant() && !rvr.isType(JSVAL_TYPE_OBJECT)) { + Jump rhsFail = masm.testObject(Assembler::NotEqual, rvr.typeReg()); + linkToStub(rhsFail); + } + + Jump lhsHasEq = masm.branchTest32(Assembler::NonZero, + Address(lvr.dataReg(), + offsetof(JSObject, flags)), + Imm32(JSObject::HAS_EQUALITY)); + linkToStub(lhsHasEq); + + if (rvr.isConstant()) { + JSObject *obj = &rvr.value().toObject(); + Jump test = masm.branchPtr(ic.cond, lvr.dataReg(), ImmPtr(obj)); + linkTrue(test); + } else { + Jump test = masm.branchPtr(ic.cond, lvr.dataReg(), rvr.dataReg()); + linkTrue(test); + } + + Jump fallthrough = masm.jump(); + linkFalse(fallthrough); + } + + bool linkForIC(Assembler &masm) + { + EqualityICLinker buffer(masm, f); + if (!buffer.init(cx)) + return false; + + Repatcher repatcher(f.jit()); + + /* Overwrite the call to the IC with a call to the stub. */ + JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, ic.stub)); + repatcher.relink(ic.stubCall, fptr); + + // Silently fail, the IC is disabled now. + if (!buffer.verifyRange(f.jit())) + return true; + + /* Set the targets of all type test failures to go to the stub. */ + for (size_t i = 0; i < jumpList.length(); i++) + buffer.link(jumpList[i], ic.stubEntry); + jumpList.clear(); + + /* Set the targets for the the success and failure of the actual equality test. */ + buffer.link(trueJump, ic.target); + buffer.link(falseJump, ic.fallThrough); + + CodeLocationLabel cs = buffer.finalize(); + + /* Jump to the newly generated code instead of to the IC. */ + repatcher.relink(ic.jumpToStub, cs); + + return true; + } + + bool update() + { + if (!ic.generated) { + Assembler masm; + Value rval = f.regs.sp[-1]; + Value lval = f.regs.sp[-2]; + + if (rval.isObject() && lval.isObject()) { + generateObjectPath(masm); + ic.generated = true; + } else if (rval.isString() && lval.isString()) { + generateStringPath(masm); + ic.generated = true; + } else { + return true; + } + + return linkForIC(masm); + } + + return true; + } +}; + +JSBool JS_FASTCALL +ic::Equality(VMFrame &f, ic::EqualityICInfo *ic) +{ + EqualityCompiler cc(f, *ic); + if (!cc.update()) + THROWV(JS_FALSE); + + return ic->stub(f); +} + +static void * JS_FASTCALL +SlowCallFromIC(VMFrame &f, ic::CallICInfo *ic) +{ + stubs::SlowCall(f, ic->frameSize.getArgc(f)); + return NULL; +} + +static void * JS_FASTCALL +SlowNewFromIC(VMFrame &f, ic::CallICInfo *ic) +{ + stubs::SlowNew(f, ic->frameSize.staticArgc()); + return NULL; +} + +/* + * Calls have an inline path and an out-of-line path. The inline path is used + * in the fastest case: the method has JIT'd code, and |argc == nargs|. + * + * The inline path and OOL path are separated by a guard on the identity of + * the callee object. This guard starts as NULL and always fails on the first + * hit. On the OOL path, the callee is verified to be both a function and a + * scripted function. If these conditions hold, |ic::Call| is invoked. + * + * |ic::Call| first ensures that the callee has JIT code. If it doesn't, the + * call to |ic::Call| is patched to a slow path. If it does have JIT'd code, + * the following cases can occur: + * + * 1) args != nargs: The call to |ic::Call| is patched with a dynamically + * generated stub. This stub inlines a path that looks like: + * ---- + * push frame + * if (callee is not compiled) { + * Compile(callee); + * } + * call callee->arityLabel + * + * The arity label is a special entry point for correcting frames for + * arity mismatches. + * + * 2) args == nargs, and the inline call site was not patched yet. + * The guard dividing the two paths is patched to guard on the given + * function object identity, and the proceeding call is patched to + * directly call the JIT code. + * + * 3) args == nargs, and the inline call site was patched already. + * A small stub is created which extends the original guard to also + * guard on the JSFunction lying underneath the function object. + * + * If the OOL path does not have a scripted function, but does have a + * scripted native, then a small stub is generated which inlines the native + * invocation. + */ +class CallCompiler : public BaseCompiler +{ + VMFrame &f; + CallICInfo ⁣ + bool callingNew; + + public: + CallCompiler(VMFrame &f, CallICInfo &ic, bool callingNew) + : BaseCompiler(f.cx), f(f), ic(ic), callingNew(callingNew) + { + } + + JSC::ExecutablePool *poolForSize(LinkerHelper &linker, CallICInfo::PoolIndex index) + { + JSC::ExecutablePool *ep = linker.init(f.cx); + if (!ep) + return NULL; + JS_ASSERT(!ic.pools[index]); + ic.pools[index] = ep; + return ep; + } + + void disable(JITScript *jit) + { + JSC::CodeLocationCall oolCall = ic.slowPathStart.callAtOffset(ic.oolCallOffset); + Repatcher repatch(jit); + JSC::FunctionPtr fptr = callingNew + ? JSC::FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, SlowNewFromIC)) + : JSC::FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, SlowCallFromIC)); + repatch.relink(oolCall, fptr); + } + + bool generateFullCallStub(JITScript *from, JSScript *script, uint32 flags) + { + /* + * Create a stub that works with arity mismatches. Like the fast-path, + * this allocates a frame on the caller side, but also performs extra + * checks for compilability. Perhaps this should be a separate, shared + * trampoline, but for now we generate it dynamically. + */ + Assembler masm; + InlineFrameAssembler inlFrame(masm, ic, flags); + RegisterID t0 = inlFrame.tempRegs.takeAnyReg(); + + /* Generate the inline frame creation. */ + inlFrame.assemble(ic.funGuard.labelAtOffset(ic.joinPointOffset).executableAddress()); + + /* funPtrReg is still valid. Check if a compilation is needed. */ + Address scriptAddr(ic.funPtrReg, offsetof(JSFunction, u) + + offsetof(JSFunction::U::Scripted, script)); + masm.loadPtr(scriptAddr, t0); + + /* + * Test if script->nmap is NULL - same as checking ncode, but faster + * here since ncode has two failure modes and we need to load out of + * nmap anyway. + */ + size_t offset = callingNew + ? offsetof(JSScript, jitArityCheckCtor) + : offsetof(JSScript, jitArityCheckNormal); + masm.loadPtr(Address(t0, offset), t0); + Jump hasCode = masm.branchPtr(Assembler::Above, t0, ImmPtr(JS_UNJITTABLE_SCRIPT)); + + /* Try and compile. On success we get back the nmap pointer. */ + masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp))); + void *compilePtr = JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction); + if (ic.frameSize.isStatic()) { + masm.move(Imm32(ic.frameSize.staticArgc()), Registers::ArgReg1); + masm.fallibleVMCall(compilePtr, script->code, ic.frameSize.staticLocalSlots()); + } else { + masm.load32(FrameAddress(offsetof(VMFrame, u.call.dynamicArgc)), Registers::ArgReg1); + masm.fallibleVMCall(compilePtr, script->code, -1); + } + masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg); + + Jump notCompiled = masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg, + Registers::ReturnReg); + + masm.jump(Registers::ReturnReg); + + hasCode.linkTo(masm.label(), &masm); + + /* Get nmap[ARITY], set argc, call. */ + if (ic.frameSize.isStatic()) + masm.move(Imm32(ic.frameSize.staticArgc()), JSParamReg_Argc); + else + masm.load32(FrameAddress(offsetof(VMFrame, u.call.dynamicArgc)), JSParamReg_Argc); + masm.jump(t0); + + LinkerHelper linker(masm); + JSC::ExecutablePool *ep = poolForSize(linker, CallICInfo::Pool_ScriptStub); + if (!ep) + return false; + + if (!linker.verifyRange(from)) { + disable(from); + return true; + } + + linker.link(notCompiled, ic.slowPathStart.labelAtOffset(ic.slowJoinOffset)); + JSC::CodeLocationLabel cs = linker.finalize(); + + JaegerSpew(JSpew_PICs, "generated CALL stub %p (%d bytes)\n", cs.executableAddress(), + masm.size()); + + Repatcher repatch(from); + JSC::CodeLocationJump oolJump = ic.slowPathStart.jumpAtOffset(ic.oolJumpOffset); + repatch.relink(oolJump, cs); + + return true; + } + + bool patchInlinePath(JITScript *from, JSScript *script, JSObject *obj) + { + JS_ASSERT(ic.frameSize.isStatic()); + JITScript *jit = script->getJIT(callingNew); + + /* Very fast path. */ + Repatcher repatch(from); + + if (!repatch.canRelink(ic.funGuard.jumpAtOffset(ic.hotJumpOffset), + JSC::CodeLocationLabel(jit->fastEntry))) { + return false; + } + + ic.fastGuardedObject = obj; + + repatch.repatch(ic.funGuard, obj); + repatch.relink(ic.funGuard.jumpAtOffset(ic.hotJumpOffset), + JSC::CodeLocationLabel(jit->fastEntry)); + + JaegerSpew(JSpew_PICs, "patched CALL path %p (obj: %p)\n", + ic.funGuard.executableAddress(), ic.fastGuardedObject); + + return true; + } + + bool generateStubForClosures(JITScript *from, JSObject *obj) + { + JS_ASSERT(ic.frameSize.isStatic()); + + /* Slightly less fast path - guard on fun->getFunctionPrivate() instead. */ + Assembler masm; + + Registers tempRegs; + tempRegs.takeReg(ic.funObjReg); + + RegisterID t0 = tempRegs.takeAnyReg(); + + /* Guard that it's actually a function object. */ + Jump claspGuard = masm.testObjClass(Assembler::NotEqual, ic.funObjReg, &js_FunctionClass); + + /* Guard that it's the same function. */ + JSFunction *fun = obj->getFunctionPrivate(); + masm.loadObjPrivate(ic.funObjReg, t0); + Jump funGuard = masm.branchPtr(Assembler::NotEqual, t0, ImmPtr(fun)); + Jump done = masm.jump(); + + LinkerHelper linker(masm); + JSC::ExecutablePool *ep = poolForSize(linker, CallICInfo::Pool_ClosureStub); + if (!ep) + return false; + + ic.hasJsFunCheck = true; + + if (!linker.verifyRange(from)) { + disable(from); + return true; + } + + linker.link(claspGuard, ic.slowPathStart); + linker.link(funGuard, ic.slowPathStart); + linker.link(done, ic.funGuard.labelAtOffset(ic.hotPathOffset)); + JSC::CodeLocationLabel cs = linker.finalize(); + + JaegerSpew(JSpew_PICs, "generated CALL closure stub %p (%d bytes)\n", + cs.executableAddress(), masm.size()); + + Repatcher repatch(from); + repatch.relink(ic.funJump, cs); + + return true; + } + + bool generateNativeStub() + { + JITScript *jit = f.jit(); + + /* Snapshot the frameDepth before SplatApplyArgs modifies it. */ + uintN initialFrameDepth = f.regs.sp - f.regs.fp->slots(); + + /* + * SplatApplyArgs has not been called, so we call it here before + * potentially touching f.u.call.dynamicArgc. + */ + Value *vp; + if (ic.frameSize.isStatic()) { + JS_ASSERT(f.regs.sp - f.regs.fp->slots() == (int)ic.frameSize.staticLocalSlots()); + vp = f.regs.sp - (2 + ic.frameSize.staticArgc()); + } else { + JS_ASSERT(*f.regs.pc == JSOP_FUNAPPLY && GET_ARGC(f.regs.pc) == 2); + if (!ic::SplatApplyArgs(f)) /* updates regs.sp */ + THROWV(true); + vp = f.regs.sp - (2 + f.u.call.dynamicArgc); + } + + JSObject *obj; + if (!IsFunctionObject(*vp, &obj)) + return false; + + JSFunction *fun = obj->getFunctionPrivate(); + if ((!callingNew && !fun->isNative()) || (callingNew && !fun->isConstructor())) + return false; + + if (callingNew) + vp[1].setMagicWithObjectOrNullPayload(NULL); + + if (!CallJSNative(cx, fun->u.n.native, ic.frameSize.getArgc(f), vp)) + THROWV(true); + + /* Right now, take slow-path for IC misses or multiple stubs. */ + if (ic.fastGuardedNative || ic.hasJsFunCheck) + return true; + + /* Native MIC needs to warm up first. */ + if (!ic.hit) { + ic.hit = true; + return true; + } + + /* Generate fast-path for calling this native. */ + Assembler masm; + + /* Guard on the function object identity, for now. */ + Jump funGuard = masm.branchPtr(Assembler::NotEqual, ic.funObjReg, ImmPtr(obj)); + + /* N.B. After this call, the frame will have a dynamic frame size. */ + if (ic.frameSize.isDynamic()) { + masm.fallibleVMCall(JS_FUNC_TO_DATA_PTR(void *, ic::SplatApplyArgs), + f.regs.pc, initialFrameDepth); + } + + Registers tempRegs; +#ifndef JS_CPU_X86 + tempRegs.takeReg(Registers::ArgReg0); + tempRegs.takeReg(Registers::ArgReg1); + tempRegs.takeReg(Registers::ArgReg2); +#endif + RegisterID t0 = tempRegs.takeAnyReg(); + + /* Store pc. */ + masm.storePtr(ImmPtr(cx->regs->pc), + FrameAddress(offsetof(VMFrame, regs.pc))); + + /* Store sp (if not already set by ic::SplatApplyArgs). */ + if (ic.frameSize.isStatic()) { + uint32 spOffset = sizeof(JSStackFrame) + initialFrameDepth * sizeof(Value); + masm.addPtr(Imm32(spOffset), JSFrameReg, t0); + masm.storePtr(t0, FrameAddress(offsetof(VMFrame, regs.sp))); + } + + /* Store fp. */ + masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp))); + + /* Grab cx. */ +#ifdef JS_CPU_X86 + RegisterID cxReg = tempRegs.takeAnyReg(); +#else + RegisterID cxReg = Registers::ArgReg0; +#endif + masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), cxReg); + + /* Compute vp. */ +#ifdef JS_CPU_X86 + RegisterID vpReg = t0; +#else + RegisterID vpReg = Registers::ArgReg2; +#endif + MaybeRegisterID argcReg; + if (ic.frameSize.isStatic()) { + uint32 vpOffset = sizeof(JSStackFrame) + (vp - f.regs.fp->slots()) * sizeof(Value); + masm.addPtr(Imm32(vpOffset), JSFrameReg, vpReg); + } else { + argcReg = tempRegs.takeAnyReg(); + masm.load32(FrameAddress(offsetof(VMFrame, u.call.dynamicArgc)), argcReg.reg()); + masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.sp)), vpReg); + + /* vpOff = (argc + 2) * sizeof(Value) */ + RegisterID vpOff = tempRegs.takeAnyReg(); + masm.move(argcReg.reg(), vpOff); + masm.add32(Imm32(2), vpOff); /* callee, this */ + JS_STATIC_ASSERT(sizeof(Value) == 8); + masm.lshift32(Imm32(3), vpOff); + masm.subPtr(vpOff, vpReg); + + tempRegs.putReg(vpOff); + } + + /* Mark vp[1] as magic for |new|. */ + if (callingNew) { + Value v; + v.setMagicWithObjectOrNullPayload(NULL); + masm.storeValue(v, Address(vpReg, sizeof(Value))); + } + + masm.setupABICall(Registers::NormalCall, 3); + masm.storeArg(2, vpReg); + if (ic.frameSize.isStatic()) + masm.storeArg(1, Imm32(ic.frameSize.staticArgc())); + else + masm.storeArg(1, argcReg.reg()); + masm.storeArg(0, cxReg); + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, fun->u.n.native), false); + + Jump hasException = masm.branchTest32(Assembler::Zero, Registers::ReturnReg, + Registers::ReturnReg); + + + Jump done = masm.jump(); + + /* Move JaegerThrowpoline into register for very far jump on x64. */ + hasException.linkTo(masm.label(), &masm); + masm.throwInJIT(); + + LinkerHelper linker(masm); + JSC::ExecutablePool *ep = poolForSize(linker, CallICInfo::Pool_NativeStub); + if (!ep) + THROWV(true); + + ic.fastGuardedNative = obj; + + if (!linker.verifyRange(jit)) { + disable(jit); + return true; + } + + linker.link(done, ic.slowPathStart.labelAtOffset(ic.slowJoinOffset)); + linker.link(funGuard, ic.slowPathStart); + JSC::CodeLocationLabel cs = linker.finalize(); + + JaegerSpew(JSpew_PICs, "generated native CALL stub %p (%d bytes)\n", + cs.executableAddress(), masm.size()); + + Repatcher repatch(jit); + repatch.relink(ic.funJump, cs); + + return true; + } + + void *update() + { + JITScript *jit = f.jit(); + + stubs::UncachedCallResult ucr; + if (callingNew) + stubs::UncachedNewHelper(f, ic.frameSize.staticArgc(), &ucr); + else + stubs::UncachedCallHelper(f, ic.frameSize.getArgc(f), &ucr); + + // If the function cannot be jitted (generally unjittable or empty script), + // patch this site to go to a slow path always. + if (!ucr.codeAddr) { + if (ucr.unjittable) + disable(jit); + return NULL; + } + + JSFunction *fun = ucr.fun; + JS_ASSERT(fun); + JSScript *script = fun->script(); + JS_ASSERT(script); + JSObject *callee = ucr.callee; + JS_ASSERT(callee); + + uint32 flags = callingNew ? JSFRAME_CONSTRUCTING : 0; + + if (!ic.hit) { + ic.hit = true; + return ucr.codeAddr; + } + + if (!ic.frameSize.isStatic() || ic.frameSize.staticArgc() != fun->nargs) { + if (!generateFullCallStub(jit, script, flags)) + THROWV(NULL); + } else { + if (!ic.fastGuardedObject && patchInlinePath(jit, script, callee)) { + // Nothing, done. + } else if (ic.fastGuardedObject && + !ic.hasJsFunCheck && + !ic.fastGuardedNative && + ic.fastGuardedObject->getFunctionPrivate() == fun) { + /* + * Note: Multiple "function guard" stubs are not yet + * supported, thus the fastGuardedNative check. + */ + if (!generateStubForClosures(jit, callee)) + THROWV(NULL); + } else { + if (!generateFullCallStub(jit, script, flags)) + THROWV(NULL); + } + } + + return ucr.codeAddr; + } +}; + +void * JS_FASTCALL +ic::Call(VMFrame &f, CallICInfo *ic) +{ + CallCompiler cc(f, *ic, false); + return cc.update(); +} + +void * JS_FASTCALL +ic::New(VMFrame &f, CallICInfo *ic) +{ + CallCompiler cc(f, *ic, true); + return cc.update(); +} + +void JS_FASTCALL +ic::NativeCall(VMFrame &f, CallICInfo *ic) +{ + CallCompiler cc(f, *ic, false); + if (!cc.generateNativeStub()) + stubs::SlowCall(f, ic->frameSize.getArgc(f)); +} + +void JS_FASTCALL +ic::NativeNew(VMFrame &f, CallICInfo *ic) +{ + CallCompiler cc(f, *ic, true); + if (!cc.generateNativeStub()) + stubs::SlowNew(f, ic->frameSize.staticArgc()); +} + +static inline bool +BumpStack(VMFrame &f, uintN inc) +{ + static const unsigned MANY_ARGS = 1024; + static const unsigned MIN_SPACE = 500; + + /* If we are not passing many args, treat this as a normal call. */ + if (inc < MANY_ARGS) { + if (f.regs.sp + inc < f.stackLimit) + return true; + StackSpace &stack = f.cx->stack(); + if (!stack.bumpCommitAndLimit(f.entryfp, f.regs.sp, inc, &f.stackLimit)) { + js_ReportOverRecursed(f.cx); + return false; + } + return true; + } + + /* + * The purpose of f.stackLimit is to catch over-recursion based on + * assumptions about the average frame size. 'apply' with a large number of + * arguments breaks these assumptions and can result in premature "out of + * script quota" errors. Normally, apply will go through js::Invoke, which + * effectively starts a fresh stackLimit. Here, we bump f.stackLimit, + * if necessary, to allow for this 'apply' call, and a reasonable number of + * subsequent calls, to succeed without hitting the stackLimit. In theory, + * this a recursive chain containing apply to circumvent the stackLimit. + * However, since each apply call must consume at least MANY_ARGS slots, + * this sequence will quickly reach the end of the stack and OOM. + */ + + uintN incWithSpace = inc + MIN_SPACE; + Value *bumpedWithSpace = f.regs.sp + incWithSpace; + if (bumpedWithSpace < f.stackLimit) + return true; + + StackSpace &stack = f.cx->stack(); + if (stack.bumpCommitAndLimit(f.entryfp, f.regs.sp, incWithSpace, &f.stackLimit)) + return true; + + if (!stack.ensureSpace(f.cx, f.regs.sp, incWithSpace)) + return false; + f.stackLimit = bumpedWithSpace; + return true; +} + +/* + * SplatApplyArgs is only called for expressions of the form |f.apply(x, y)|. + * Additionally, the callee has already been checked to be the native apply. + * All successful paths through SplatApplyArgs must set f.u.call.dynamicArgc + * and f.regs.sp. + */ +JSBool JS_FASTCALL +ic::SplatApplyArgs(VMFrame &f) +{ + JSContext *cx = f.cx; + JS_ASSERT(GET_ARGC(f.regs.pc) == 2); + + /* + * The lazyArgsObj flag indicates an optimized call |f.apply(x, arguments)| + * where the args obj has not been created or pushed on the stack. Thus, + * if lazyArgsObj is set, the stack for |f.apply(x, arguments)| is: + * + * | Function.prototype.apply | f | x | + * + * Otherwise, if !lazyArgsObj, the stack is a normal 2-argument apply: + * + * | Function.prototype.apply | f | x | arguments | + */ + if (f.u.call.lazyArgsObj) { + Value *vp = f.regs.sp - 3; + JS_ASSERT(JS_CALLEE(cx, vp).toObject().getFunctionPrivate()->u.n.native == js_fun_apply); + + JSStackFrame *fp = f.regs.fp; + if (!fp->hasOverriddenArgs() && + (!fp->hasArgsObj() || + (fp->hasArgsObj() && !fp->argsObj().isArgsLengthOverridden() && + !js_PrototypeHasIndexedProperties(cx, &fp->argsObj())))) { + + uintN n = fp->numActualArgs(); + if (!BumpStack(f, n)) + THROWV(false); + f.regs.sp += n; + + Value *argv = JS_ARGV(cx, vp + 1 /* vp[1]'s argv */); + if (fp->hasArgsObj()) + fp->forEachCanonicalActualArg(CopyNonHoleArgsTo(&fp->argsObj(), argv)); + else + fp->forEachCanonicalActualArg(CopyTo(argv)); + + f.u.call.dynamicArgc = n; + return true; + } + + /* + * Can't optimize; push the arguments object so that the stack matches + * the !lazyArgsObj stack state described above. + */ + f.regs.sp++; + if (!js_GetArgsValue(cx, fp, &vp[3])) + THROWV(false); + } + + Value *vp = f.regs.sp - 4; + JS_ASSERT(JS_CALLEE(cx, vp).toObject().getFunctionPrivate()->u.n.native == js_fun_apply); + + /* + * This stub should mimic the steps taken by js_fun_apply. Step 1 and part + * of Step 2 have already been taken care of by calling jit code. + */ + + /* Step 2 (part 2). */ + if (vp[3].isNullOrUndefined()) { + f.regs.sp--; + f.u.call.dynamicArgc = 0; + return true; + } + + /* Step 3. */ + if (!vp[3].isObject()) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_APPLY_ARGS, js_apply_str); + THROWV(false); + } + + /* Steps 4-5. */ + JSObject *aobj = &vp[3].toObject(); + jsuint length; + if (!js_GetLengthProperty(cx, aobj, &length)) + THROWV(false); + + JS_ASSERT(!JS_ON_TRACE(cx)); + + /* Step 6. */ + uintN n = uintN(JS_MIN(length, JS_ARGS_LENGTH_MAX)); + + intN delta = n - 1; + if (delta > 0 && !BumpStack(f, delta)) + THROWV(false); + f.regs.sp += delta; + + /* Steps 7-8. */ + if (!GetElements(cx, aobj, n, f.regs.sp - n)) + THROWV(false); + + f.u.call.dynamicArgc = n; + return true; +} + +void +JITScript::purgeMICs() +{ + if (!nGetGlobalNames || !nSetGlobalNames) + return; + + Repatcher repatch(this); + + ic::GetGlobalNameIC *getGlobalNames_ = getGlobalNames(); + for (uint32 i = 0; i < nGetGlobalNames; i++) { + ic::GetGlobalNameIC &ic = getGlobalNames_[i]; + JSC::CodeLocationDataLabel32 label = ic.fastPathStart.dataLabel32AtOffset(ic.shapeOffset); + repatch.repatch(label, int(JSObjectMap::INVALID_SHAPE)); + } + + ic::SetGlobalNameIC *setGlobalNames_ = setGlobalNames(); + for (uint32 i = 0; i < nSetGlobalNames; i++) { + ic::SetGlobalNameIC &ic = setGlobalNames_[i]; + ic.patchInlineShapeGuard(repatch, int32(JSObjectMap::INVALID_SHAPE)); + + if (ic.hasExtraStub) { + Repatcher repatcher(ic.extraStub); + ic.patchExtraShapeGuard(repatcher, int32(JSObjectMap::INVALID_SHAPE)); + } + } +} + +void +ic::PurgeMICs(JSContext *cx, JSScript *script) +{ + /* MICs are purged during GC to handle changing shapes. */ + JS_ASSERT(cx->runtime->gcRegenShapes); + + if (script->jitNormal) + script->jitNormal->purgeMICs(); + if (script->jitCtor) + script->jitCtor->purgeMICs(); +} + +void +JITScript::nukeScriptDependentICs() +{ + if (!nCallICs) + return; + + Repatcher repatcher(this); + + ic::CallICInfo *callICs_ = callICs(); + for (uint32 i = 0; i < nCallICs; i++) { + ic::CallICInfo &ic = callICs_[i]; + if (!ic.fastGuardedObject) + continue; + repatcher.repatch(ic.funGuard, NULL); + repatcher.relink(ic.funJump, ic.slowPathStart); + ic.releasePool(CallICInfo::Pool_ClosureStub); + ic.fastGuardedObject = NULL; + ic.hasJsFunCheck = false; + } +} + +void +JITScript::sweepCallICs(JSContext *cx, bool purgeAll) +{ + Repatcher repatcher(this); + + /* + * If purgeAll is set, purge stubs in the script except those covered by PurgePICs + * (which is always called during GC). We want to remove references which can keep + * alive pools that we are trying to destroy (see JSCompartment::sweep). + */ + + ic::CallICInfo *callICs_ = callICs(); + for (uint32 i = 0; i < nCallICs; i++) { + ic::CallICInfo &ic = callICs_[i]; + + /* + * If the object is unreachable, we're guaranteed not to be currently + * executing a stub generated by a guard on that object. This lets us + * precisely GC call ICs while keeping the identity guard safe. + */ + bool fastFunDead = ic.fastGuardedObject && + (purgeAll || IsAboutToBeFinalized(cx, ic.fastGuardedObject)); + bool nativeDead = ic.fastGuardedNative && + (purgeAll || IsAboutToBeFinalized(cx, ic.fastGuardedNative)); + + /* + * There are three conditions where we need to relink: + * (1) purgeAll is true. + * (2) The native is dead, since it always has a stub. + * (3) The fastFun is dead *and* there is a closure stub. + * + * Note although both objects can be non-NULL, there can only be one + * of [closure, native] stub per call IC. + */ + if (purgeAll || nativeDead || (fastFunDead && ic.hasJsFunCheck)) { + repatcher.relink(ic.funJump, ic.slowPathStart); + ic.hit = false; + } + + if (fastFunDead) { + repatcher.repatch(ic.funGuard, NULL); + ic.releasePool(CallICInfo::Pool_ClosureStub); + ic.hasJsFunCheck = false; + ic.fastGuardedObject = NULL; + } + + if (nativeDead) { + ic.releasePool(CallICInfo::Pool_NativeStub); + ic.fastGuardedNative = NULL; + } + + if (purgeAll) { + ic.releasePool(CallICInfo::Pool_ScriptStub); + JSC::CodeLocationJump oolJump = ic.slowPathStart.jumpAtOffset(ic.oolJumpOffset); + JSC::CodeLocationLabel icCall = ic.slowPathStart.labelAtOffset(ic.icCallOffset); + repatcher.relink(oolJump, icCall); + } + } + + if (purgeAll) { + /* Purge ICs generating stubs into execPools. */ + uint32 released = 0; + + ic::EqualityICInfo *equalityICs_ = equalityICs(); + for (uint32 i = 0; i < nEqualityICs; i++) { + ic::EqualityICInfo &ic = equalityICs_[i]; + if (!ic.generated) + continue; + + JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, ic::Equality)); + repatcher.relink(ic.stubCall, fptr); + repatcher.relink(ic.jumpToStub, ic.stubEntry); + + ic.generated = false; + released++; + } + + ic::SetGlobalNameIC *setGlobalNames_ = setGlobalNames(); + for (uint32 i = 0; i < nSetGlobalNames; i ++) { + ic::SetGlobalNameIC &ic = setGlobalNames_[i]; + if (!ic.hasExtraStub) + continue; + repatcher.relink(ic.fastPathStart.jumpAtOffset(ic.inlineShapeJump), ic.slowPathStart); + ic.hasExtraStub = false; + released++; + } + + JS_ASSERT(released == execPools.length()); + for (uint32 i = 0; i < released; i++) + execPools[i]->release(); + execPools.clear(); + } +} + +void +ic::SweepCallICs(JSContext *cx, JSScript *script, bool purgeAll) +{ + if (script->jitNormal) + script->jitNormal->sweepCallICs(cx, purgeAll); + if (script->jitCtor) + script->jitCtor->sweepCallICs(cx, purgeAll); +} + +#endif /* JS_MONOIC */ + diff --git a/js/src/methodjit/MonoIC.h b/js/src/methodjit/MonoIC.h new file mode 100644 index 0000000..66254b1 --- /dev/null +++ b/js/src/methodjit/MonoIC.h @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_mono_ic_h__ && defined JS_METHODJIT && defined JS_MONOIC +#define jsjaeger_mono_ic_h__ + +#include "assembler/assembler/MacroAssembler.h" +#include "assembler/assembler/CodeLocation.h" +#include "assembler/moco/MocoStubs.h" +#include "methodjit/MethodJIT.h" +#include "CodeGenIncludes.h" +#include "methodjit/ICRepatcher.h" + +namespace js { +namespace mjit { + +class FrameSize +{ + uint32 frameDepth_ : 16; + uint32 argc_; + public: + void initStatic(uint32 frameDepth, uint32 argc) { + JS_ASSERT(frameDepth > 0); + frameDepth_ = frameDepth; + argc_ = argc; + } + + void initDynamic() { + frameDepth_ = 0; + argc_ = -1; /* quiet gcc */ + } + + bool isStatic() const { + return frameDepth_ > 0; + } + + bool isDynamic() const { + return frameDepth_ == 0; + } + + uint32 staticLocalSlots() const { + JS_ASSERT(isStatic()); + return frameDepth_; + } + + uint32 staticArgc() const { + JS_ASSERT(isStatic()); + return argc_; + } + + uint32 getArgc(VMFrame &f) const { + return isStatic() ? staticArgc() : f.u.call.dynamicArgc; + } +}; + +namespace ic { + +struct GlobalNameIC +{ + typedef JSC::MacroAssembler::RegisterID RegisterID; + + JSC::CodeLocationLabel fastPathStart; + JSC::CodeLocationCall slowPathCall; + + /* + * - ARM and x64 always emit exactly one instruction which needs to be + * patched. On ARM, the label points to the patched instruction, whilst + * on x64 it points to the instruction after it. + * - For x86, the label "load" points to the start of the load/store + * sequence, which may consist of one or two "mov" instructions. Because + * of this, x86 is the only platform which requires non-trivial patching + * code. + */ + int32 loadStoreOffset : 15; + int32 shapeOffset : 15; + bool usePropertyCache : 1; +}; + +struct GetGlobalNameIC : public GlobalNameIC +{ +}; + +struct SetGlobalNameIC : public GlobalNameIC +{ + JSC::CodeLocationLabel slowPathStart; + + /* Dynamically generted stub for method-write checks. */ + JSC::JITCode extraStub; + + /* SET only, if we had to generate an out-of-line path. */ + int inlineShapeJump : 10; /* Offset into inline path for shape jump. */ + int extraShapeGuard : 6; /* Offset into stub for shape guard. */ + bool objConst : 1; /* True if the object is constant. */ + RegisterID objReg : 5; /* Register for object, if objConst is false. */ + RegisterID shapeReg : 5; /* Register for shape; volatile. */ + bool hasExtraStub : 1; /* Extra stub is preset. */ + + int fastRejoinOffset : 16; /* Offset from fastPathStart to rejoin. */ + int extraStoreOffset : 16; /* Offset into store code. */ + + /* SET only. */ + ValueRemat vr; /* RHS value. */ + + void patchInlineShapeGuard(Repatcher &repatcher, int32 shape); + void patchExtraShapeGuard(Repatcher &repatcher, int32 shape); +}; + +struct TraceICInfo { + TraceICInfo() {} + + JSC::CodeLocationLabel stubEntry; + JSC::CodeLocationLabel jumpTarget; + JSC::CodeLocationJump traceHint; + JSC::CodeLocationJump slowTraceHint; +#ifdef DEBUG + jsbytecode *jumpTargetPC; +#endif + + /* This data is used by the tracing JIT. */ + void *traceData; + uintN traceEpoch; + uint32 loopCounter; + uint32 loopCounterStart; + + bool initialized : 1; + bool hasSlowTraceHint : 1; +}; + +static const uint16 BAD_TRACEIC_INDEX = (uint16)0xffff; + +void JS_FASTCALL GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic); +void JS_FASTCALL SetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic); + +struct EqualityICInfo { + typedef JSC::MacroAssembler::RegisterID RegisterID; + + JSC::CodeLocationLabel stubEntry; + JSC::CodeLocationCall stubCall; + BoolStub stub; + JSC::CodeLocationLabel target; + JSC::CodeLocationLabel fallThrough; + JSC::CodeLocationJump jumpToStub; + + ValueRemat lvr, rvr; + + bool generated : 1; + JSC::MacroAssembler::RegisterID tempReg : 5; + Assembler::Condition cond; +}; + +JSBool JS_FASTCALL Equality(VMFrame &f, ic::EqualityICInfo *ic); + +/* See MonoIC.cpp, CallCompiler for more information on call ICs. */ +struct CallICInfo { + typedef JSC::MacroAssembler::RegisterID RegisterID; + + enum PoolIndex { + Pool_ScriptStub, + Pool_ClosureStub, + Pool_NativeStub, + Total_Pools + }; + + JSC::ExecutablePool *pools[Total_Pools]; + + /* Used for rooting and reification. */ + JSObject *fastGuardedObject; + JSObject *fastGuardedNative; + + /* PC at the call site. */ + jsbytecode *pc; + + FrameSize frameSize; + + /* Function object identity guard. */ + JSC::CodeLocationDataLabelPtr funGuard; + + /* Starting point for all slow call paths. */ + JSC::CodeLocationLabel slowPathStart; + + /* Inline to OOL jump, redirected by stubs. */ + JSC::CodeLocationJump funJump; + + /* Offset to inline scripted call, from funGuard. */ + uint32 hotJumpOffset : 16; + uint32 joinPointOffset : 16; + + /* Out of line slow call. */ + uint32 oolCallOffset : 16; + + /* Jump to patch for out-of-line scripted calls. */ + uint32 oolJumpOffset : 16; + + /* Label for out-of-line call to IC function. */ + uint32 icCallOffset : 16; + + /* Offset for deep-fun check to rejoin at. */ + uint32 hotPathOffset : 16; + + /* Join point for all slow call paths. */ + uint32 slowJoinOffset : 16; + + RegisterID funObjReg : 5; + RegisterID funPtrReg : 5; + bool hit : 1; + bool hasJsFunCheck : 1; + + inline void reset() { + fastGuardedObject = NULL; + fastGuardedNative = NULL; + hit = false; + hasJsFunCheck = false; + pools[0] = pools[1] = pools[2] = NULL; + } + + inline void releasePools() { + releasePool(Pool_ScriptStub); + releasePool(Pool_ClosureStub); + releasePool(Pool_NativeStub); + } + + inline void releasePool(PoolIndex index) { + if (pools[index]) { + pools[index]->release(); + pools[index] = NULL; + } + } +}; + +void * JS_FASTCALL New(VMFrame &f, ic::CallICInfo *ic); +void * JS_FASTCALL Call(VMFrame &f, ic::CallICInfo *ic); +void JS_FASTCALL NativeNew(VMFrame &f, ic::CallICInfo *ic); +void JS_FASTCALL NativeCall(VMFrame &f, ic::CallICInfo *ic); +JSBool JS_FASTCALL SplatApplyArgs(VMFrame &f); + +void PurgeMICs(JSContext *cx, JSScript *script); +void SweepCallICs(JSContext *cx, JSScript *script, bool purgeAll); + +} /* namespace ic */ +} /* namespace mjit */ +} /* namespace js */ + +#endif /* jsjaeger_mono_ic_h__ */ + diff --git a/js/src/methodjit/NunboxAssembler.h b/js/src/methodjit/NunboxAssembler.h new file mode 100644 index 0000000..6ce0ac8 --- /dev/null +++ b/js/src/methodjit/NunboxAssembler.h @@ -0,0 +1,463 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_assembler_h__ && defined JS_METHODJIT && defined JS_NUNBOX32 +#define jsjaeger_assembler_h__ + +#include "assembler/assembler/MacroAssembler.h" +#include "methodjit/CodeGenIncludes.h" +#include "methodjit/RematInfo.h" + +namespace js { +namespace mjit { + +/* Don't use ImmTag. Use ImmType instead. */ +struct ImmTag : JSC::MacroAssembler::Imm32 +{ + ImmTag(JSValueTag mask) + : Imm32(int32(mask)) + { } +}; + +struct ImmType : ImmTag +{ + ImmType(JSValueType type) + : ImmTag(JSVAL_TYPE_TO_TAG(type)) + { } +}; + +struct ImmPayload : JSC::MacroAssembler::Imm32 +{ + ImmPayload(uint32 payload) + : Imm32(payload) + { } +}; + +class NunboxAssembler : public JSC::MacroAssembler +{ + static const uint32 PAYLOAD_OFFSET = 0; + static const uint32 TAG_OFFSET = 4; + + public: + static const JSC::MacroAssembler::Scale JSVAL_SCALE = JSC::MacroAssembler::TimesEight; + + template + T payloadOf(T address) { + JS_ASSERT(PAYLOAD_OFFSET == 0); + return address; + } + + Address tagOf(Address address) { + return Address(address.base, address.offset + TAG_OFFSET); + } + + BaseIndex tagOf(BaseIndex address) { + return BaseIndex(address.base, address.index, address.scale, address.offset + TAG_OFFSET); + } + + void loadInlineSlot(RegisterID objReg, uint32 slot, + RegisterID typeReg, RegisterID dataReg) { + Address address(objReg, JSObject::getFixedSlotOffset(slot)); + if (objReg == typeReg) { + loadPayload(address, dataReg); + loadTypeTag(address, typeReg); + } else { + loadTypeTag(address, typeReg); + loadPayload(address, dataReg); + } + } + + template + void loadTypeTag(T address, RegisterID reg) { + load32(tagOf(address), reg); + } + + template + void storeTypeTag(ImmTag imm, T address) { + store32(imm, tagOf(address)); + } + + template + void storeTypeTag(RegisterID reg, T address) { + store32(reg, tagOf(address)); + } + + template + void loadPayload(T address, RegisterID reg) { + load32(payloadOf(address), reg); + } + + template + void storePayload(RegisterID reg, T address) { + store32(reg, payloadOf(address)); + } + + template + void storePayload(ImmPayload imm, T address) { + store32(imm, payloadOf(address)); + } + + bool addressUsesRegister(BaseIndex address, RegisterID reg) { + return (address.base == reg) || (address.index == reg); + } + + bool addressUsesRegister(Address address, RegisterID reg) { + return address.base == reg; + } + + /* Loads type first, then payload, returning label after type load. */ + template + Label loadValueAsComponents(T address, RegisterID type, RegisterID payload) { + JS_ASSERT(!addressUsesRegister(address, type)); + loadTypeTag(address, type); + Label l = label(); + loadPayload(address, payload); + return l; + } + + void loadValueAsComponents(const Value &val, RegisterID type, RegisterID payload) { + jsval_layout jv; + jv.asBits = JSVAL_BITS(Jsvalify(val)); + + move(ImmTag(jv.s.tag), type); + move(Imm32(jv.s.payload.u32), payload); + } + + /* + * Load a (64b) js::Value from 'address' into 'type' and 'payload', and + * return a label which can be used by + * ICRepatcher::patchAddressOffsetForValueLoad to patch the address' + * offset. + * + * The data register is guaranteed to be clobbered last. (This makes the + * base register for the address reusable as 'dreg'.) + */ + Label loadValueWithAddressOffsetPatch(Address address, RegisterID treg, RegisterID dreg) { + JS_ASSERT(address.base != treg); /* treg is clobbered first. */ + + Label start = label(); +#if defined JS_CPU_X86 + /* + * On x86 there are two loads to patch and they both encode the offset + * in-line. + */ + loadTypeTag(address, treg); + DBGLABEL_NOMASM(endType); + loadPayload(address, dreg); + DBGLABEL_NOMASM(endPayload); + JS_ASSERT(differenceBetween(start, endType) == 6); + JS_ASSERT(differenceBetween(endType, endPayload) == 6); + return start; +#elif defined JS_CPU_ARM + /* + * On ARM, the first instruction loads the offset from a literal pool, so the label + * returned points at that instruction. + */ + DataLabel32 load = load64WithAddressOffsetPatch(address, treg, dreg); + JS_ASSERT(differenceBetween(start, load) == 0); + (void) load; + return start; +#endif + } + + /* + * Store a (64b) js::Value from type |treg| and payload |dreg| into |address|, and + * return a label which can be used by + * ICRepatcher::patchAddressOffsetForValueStore to patch the address' + * offset. + */ + DataLabel32 storeValueWithAddressOffsetPatch(RegisterID treg, RegisterID dreg, Address address) { + DataLabel32 start = dataLabel32(); +#if defined JS_CPU_X86 + /* + * On x86 there are two stores to patch and they both encode the offset + * in-line. + */ + storeTypeTag(treg, address); + DBGLABEL_NOMASM(endType); + storePayload(dreg, address); + DBGLABEL_NOMASM(endPayload); + JS_ASSERT(differenceBetween(start, endType) == 6); + JS_ASSERT(differenceBetween(endType, endPayload) == 6); + return start; +#elif defined JS_CPU_ARM + return store64WithAddressOffsetPatch(treg, dreg, address); +#endif + } + + /* Overloaded for storing a constant type. */ + DataLabel32 storeValueWithAddressOffsetPatch(ImmType type, RegisterID dreg, Address address) { + DataLabel32 start = dataLabel32(); +#if defined JS_CPU_X86 + storeTypeTag(type, address); + DBGLABEL_NOMASM(endType); + storePayload(dreg, address); + DBGLABEL_NOMASM(endPayload); + JS_ASSERT(differenceBetween(start, endType) == 10); + JS_ASSERT(differenceBetween(endType, endPayload) == 6); + return start; +#elif defined JS_CPU_ARM + return store64WithAddressOffsetPatch(type, dreg, address); +#endif + } + + /* Overloaded for storing constant type and data. */ + DataLabel32 storeValueWithAddressOffsetPatch(const Value &v, Address address) { + jsval_layout jv; + jv.asBits = JSVAL_BITS(Jsvalify(v)); + ImmTag type(jv.s.tag); + Imm32 payload(jv.s.payload.u32); + DataLabel32 start = dataLabel32(); +#if defined JS_CPU_X86 + store32(type, tagOf(address)); + DBGLABEL_NOMASM(endType); + store32(payload, payloadOf(address)); + DBGLABEL_NOMASM(endPayload); + JS_ASSERT(differenceBetween(start, endType) == 10); + JS_ASSERT(differenceBetween(endType, endPayload) == 10); + return start; +#elif defined JS_CPU_ARM + return store64WithAddressOffsetPatch(type, payload, address); +#endif + } + + /* Overloaded for store with value remat info. */ + DataLabel32 storeValueWithAddressOffsetPatch(const ValueRemat &vr, Address address) { + if (vr.isConstant()) { + return storeValueWithAddressOffsetPatch(vr.value(), address); + } else if (vr.isTypeKnown()) { + ImmType type(vr.knownType()); + RegisterID data(vr.dataReg()); + return storeValueWithAddressOffsetPatch(type, data, address); + } else { + RegisterID type(vr.typeReg()); + RegisterID data(vr.dataReg()); + return storeValueWithAddressOffsetPatch(type, data, address); + } + } + + /* + * Stores type first, then payload. + */ + template + Label storeValue(const Value &v, T address) { + jsval_layout jv; + jv.asBits = JSVAL_BITS(Jsvalify(v)); + + store32(ImmTag(jv.s.tag), tagOf(address)); + Label l = label(); + store32(Imm32(jv.s.payload.u32), payloadOf(address)); + return l; + } + + template + void storeValueFromComponents(RegisterID type, RegisterID payload, T address) { + storeTypeTag(type, address); + storePayload(payload, address); + } + + template + void storeValueFromComponents(ImmType type, RegisterID payload, T address) { + storeTypeTag(type, address); + storePayload(payload, address); + } + + template + Label storeValue(const ValueRemat &vr, T address) { + if (vr.isConstant()) { + return storeValue(vr.value(), address); + } else { + if (vr.isTypeKnown()) + storeTypeTag(ImmType(vr.knownType()), address); + else + storeTypeTag(vr.typeReg(), address); + Label l = label(); + storePayload(vr.dataReg(), address); + return l; + } + } + + template + Jump guardNotHole(T address) { + return branch32(Equal, tagOf(address), ImmType(JSVAL_TYPE_MAGIC)); + } + + void loadPrivate(Address privAddr, RegisterID to) { + loadPtr(privAddr, to); + } + + void loadObjPrivate(RegisterID base, RegisterID to) { + Address priv(base, offsetof(JSObject, privateData)); + loadPtr(priv, to); + } + + Jump testNull(Condition cond, RegisterID reg) { + return branch32(cond, reg, ImmTag(JSVAL_TAG_NULL)); + } + + Jump testNull(Condition cond, Address address) { + return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_NULL)); + } + + Jump testUndefined(Condition cond, RegisterID reg) { + return branch32(cond, reg, ImmTag(JSVAL_TAG_UNDEFINED)); + } + + Jump testUndefined(Condition cond, Address address) { + return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED)); + } + + Jump testInt32(Condition cond, RegisterID reg) { + return branch32(cond, reg, ImmTag(JSVAL_TAG_INT32)); + } + + Jump testInt32(Condition cond, Address address) { + return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_INT32)); + } + + Jump testNumber(Condition cond, RegisterID reg) { + cond = (cond == Equal) ? BelowOrEqual : Above; + return branch32(cond, reg, ImmTag(JSVAL_TAG_INT32)); + } + + Jump testNumber(Condition cond, Address address) { + cond = (cond == Equal) ? BelowOrEqual : Above; + return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_INT32)); + } + + Jump testPrimitive(Condition cond, RegisterID reg) { + cond = (cond == NotEqual) ? AboveOrEqual : Below; + return branch32(cond, reg, ImmTag(JSVAL_TAG_OBJECT)); + } + + Jump testPrimitive(Condition cond, Address address) { + cond = (cond == NotEqual) ? AboveOrEqual : Below; + return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_OBJECT)); + } + + Jump testObject(Condition cond, RegisterID reg) { + return branch32(cond, reg, ImmTag(JSVAL_TAG_OBJECT)); + } + + Jump testObject(Condition cond, Address address) { + return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_OBJECT)); + } + + Jump testDouble(Condition cond, RegisterID reg) { + Condition opcond; + if (cond == Equal) + opcond = Below; + else + opcond = AboveOrEqual; + return branch32(opcond, reg, ImmTag(JSVAL_TAG_CLEAR)); + } + + Jump testDouble(Condition cond, Address address) { + Condition opcond; + if (cond == Equal) + opcond = Below; + else + opcond = AboveOrEqual; + return branch32(opcond, tagOf(address), ImmTag(JSVAL_TAG_CLEAR)); + } + + Jump testBoolean(Condition cond, RegisterID reg) { + return branch32(cond, reg, ImmTag(JSVAL_TAG_BOOLEAN)); + } + + Jump testBoolean(Condition cond, Address address) { + return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN)); + } + + Jump testString(Condition cond, RegisterID reg) { + return branch32(cond, reg, ImmTag(JSVAL_TAG_STRING)); + } + + Jump testString(Condition cond, Address address) { + return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_STRING)); + } + +#ifdef JS_CPU_X86 + void fastLoadDouble(RegisterID lo, RegisterID hi, FPRegisterID fpReg) { + if (MacroAssemblerX86Common::getSSEState() >= HasSSE4_1) { + m_assembler.movd_rr(lo, fpReg); + m_assembler.pinsrd_rr(hi, fpReg); + } else { + m_assembler.movd_rr(lo, fpReg); + m_assembler.movd_rr(hi, FPRegisters::Temp0); + m_assembler.unpcklps_rr(FPRegisters::Temp0, fpReg); + } + } +#endif + + void breakDouble(FPRegisterID srcDest, RegisterID typeReg, RegisterID dataReg) { +#ifdef JS_CPU_X86 + // Move the low 32-bits of the 128-bit XMM register into dataReg. + // Then, right shift the 128-bit XMM register by 4 bytes. + // Finally, move the new low 32-bits of the 128-bit XMM register into typeReg. + m_assembler.movd_rr(srcDest, dataReg); + m_assembler.psrldq_rr(srcDest, 4); + m_assembler.movd_rr(srcDest, typeReg); +#else + JS_NOT_REACHED("implement this - push double, pop pop is easiest"); +#endif + } + + void loadStaticDouble(const double *dp, FPRegisterID dest, RegisterID scratch) { + move(ImmPtr(dp), scratch); + loadDouble(Address(scratch), dest); + } + + template + Jump fastArrayLoadSlot(T address, RegisterID typeReg, RegisterID dataReg) { + loadTypeTag(address, typeReg); + Jump notHole = branch32(Equal, typeReg, ImmType(JSVAL_TYPE_MAGIC)); + loadPayload(address, dataReg); + return notHole; + } +}; + +typedef NunboxAssembler ValueAssembler; + +} /* namespace mjit */ +} /* namespace js */ + +#endif + diff --git a/js/src/methodjit/PolyIC.cpp b/js/src/methodjit/PolyIC.cpp new file mode 100644 index 0000000..aa82dab --- /dev/null +++ b/js/src/methodjit/PolyIC.cpp @@ -0,0 +1,2749 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "PolyIC.h" +#include "StubCalls.h" +#include "CodeGenIncludes.h" +#include "StubCalls-inl.h" +#include "BaseCompiler.h" +#include "assembler/assembler/LinkBuffer.h" +#include "TypedArrayIC.h" +#include "jsscope.h" +#include "jsnum.h" +#include "jstypedarray.h" +#include "jsatominlines.h" +#include "jsobjinlines.h" +#include "jsscopeinlines.h" +#include "jspropertycache.h" +#include "jspropertycacheinlines.h" +#include "jsinterpinlines.h" +#include "jsautooplen.h" + +#if defined JS_POLYIC + +using namespace js; +using namespace js::mjit; +using namespace js::mjit::ic; + +typedef JSC::FunctionPtr FunctionPtr; +typedef JSC::MacroAssembler::RegisterID RegisterID; +typedef JSC::MacroAssembler::Jump Jump; +typedef JSC::MacroAssembler::Imm32 Imm32; + +/* Rough over-estimate of how much memory we need to unprotect. */ +static const uint32 INLINE_PATH_LENGTH = 64; + +/* Static initializer to prime platforms that use constant offsets for ICs. */ +#ifndef JS_HAS_IC_LABELS +ICOffsetInitializer::ICOffsetInitializer() +{ + { + GetPropLabels &labels = PICInfo::getPropLabels_; +#if defined JS_CPU_X86 + labels.dslotsLoadOffset = -15; + labels.inlineShapeOffset = 6; + labels.stubShapeJumpOffset = 12; + labels.inlineValueLoadOffset = -12; +#endif + } + { + SetPropLabels &labels = PICInfo::setPropLabels_; +#if defined JS_CPU_X86 + labels.inlineShapeDataOffset = 6; + /* Store w/ address offset patch is two movs. */ + labels.inlineShapeJumpOffset = 12; + labels.stubShapeJumpOffset = 12; +#endif + } + { + BindNameLabels &labels = PICInfo::bindNameLabels_; +#if defined JS_CPU_X86 + labels.inlineJumpOffset = 10; + labels.stubJumpOffset = 5; +#endif + } + { + ScopeNameLabels &labels = PICInfo::scopeNameLabels_; +#if defined JS_CPU_X86 + labels.inlineJumpOffset = 5; + labels.stubJumpOffset = 5; +#endif + } +} + +ICOffsetInitializer s_ICOffsetInitializer; +GetPropLabels PICInfo::getPropLabels_; +SetPropLabels PICInfo::setPropLabels_; +BindNameLabels PICInfo::bindNameLabels_; +ScopeNameLabels PICInfo::scopeNameLabels_; +#endif + +// Helper class to simplify LinkBuffer usage in PIC stub generators. +// This guarantees correct OOM and refcount handling for buffers while they +// are instantiated and rooted. +class PICLinker : public LinkerHelper +{ + ic::BasePolyIC ⁣ + + public: + PICLinker(Assembler &masm, ic::BasePolyIC &ic) + : LinkerHelper(masm), ic(ic) + { } + + bool init(JSContext *cx) { + JSC::ExecutablePool *pool = LinkerHelper::init(cx); + if (!pool) + return false; + if (!ic.addPool(cx, pool)) { + pool->release(); + js_ReportOutOfMemory(cx); + return false; + } + return true; + } +}; + +class PICStubCompiler : public BaseCompiler +{ + protected: + const char *type; + VMFrame &f; + JSScript *script; + ic::PICInfo &pic; + void *stub; + + public: + PICStubCompiler(const char *type, VMFrame &f, JSScript *script, ic::PICInfo &pic, void *stub) + : BaseCompiler(f.cx), type(type), f(f), script(script), pic(pic), stub(stub) + { } + + bool isCallOp() const { + if (pic.kind == ic::PICInfo::CALL) + return true; + return !!(js_CodeSpec[pic.op].format & JOF_CALLOP); + } + + LookupStatus error() { + disable("error"); + return Lookup_Error; + } + + LookupStatus error(JSContext *cx) { + return error(); + } + + LookupStatus disable(const char *reason) { + return disable(f.cx, reason); + } + + LookupStatus disable(JSContext *cx, const char *reason) { + return pic.disable(cx, reason, stub); + } + + protected: + void spew(const char *event, const char *op) { +#ifdef JS_METHODJIT_SPEW + JaegerSpew(JSpew_PICs, "%s %s: %s (%s: %d)\n", + type, event, op, script->filename, + js_FramePCToLineNumber(cx, f.fp())); +#endif + } +}; + +class SetPropCompiler : public PICStubCompiler +{ + JSObject *obj; + JSAtom *atom; + int lastStubSecondShapeGuard; + + public: + SetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom, + VoidStubPIC stub) + : PICStubCompiler("setprop", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)), + obj(obj), atom(atom), lastStubSecondShapeGuard(pic.secondShapeGuard) + { } + + static void reset(Repatcher &repatcher, ic::PICInfo &pic) + { + SetPropLabels &labels = pic.setPropLabels(); + repatcher.repatchLEAToLoadPtr(labels.getDslotsLoad(pic.fastPathRejoin, pic.u.vr)); + repatcher.repatch(labels.getInlineShapeData(pic.fastPathStart, pic.shapeGuard), + int32(JSObjectMap::INVALID_SHAPE)); + repatcher.relink(labels.getInlineShapeJump(pic.fastPathStart.labelAtOffset(pic.shapeGuard)), + pic.slowPathStart); + + FunctionPtr target(JS_FUNC_TO_DATA_PTR(void *, ic::SetProp)); + repatcher.relink(pic.slowPathCall, target); + } + + LookupStatus patchInline(const Shape *shape, bool inlineSlot) + { + JS_ASSERT(!pic.inlinePathPatched); + JaegerSpew(JSpew_PICs, "patch setprop inline at %p\n", pic.fastPathStart.executableAddress()); + + Repatcher repatcher(f.jit()); + SetPropLabels &labels = pic.setPropLabels(); + + int32 offset; + if (inlineSlot) { + CodeLocationInstruction istr = labels.getDslotsLoad(pic.fastPathRejoin, pic.u.vr); + repatcher.repatchLoadPtrToLEA(istr); + + // + // We've patched | mov dslots, [obj + DSLOTS_OFFSET] + // To: | lea fslots, [obj + DSLOTS_OFFSET] + // + // Because the offset is wrong, it's necessary to correct it + // below. + // + int32 diff = int32(JSObject::getFixedSlotOffset(0)) - + int32(offsetof(JSObject, slots)); + JS_ASSERT(diff != 0); + offset = (int32(shape->slot) * sizeof(Value)) + diff; + } else { + offset = shape->slot * sizeof(Value); + } + + repatcher.repatch(labels.getInlineShapeData(pic.fastPathStart, pic.shapeGuard), + obj->shape()); + repatcher.patchAddressOffsetForValueStore(labels.getInlineValueStore(pic.fastPathRejoin, + pic.u.vr), + offset, pic.u.vr.isTypeKnown()); + + pic.inlinePathPatched = true; + + return Lookup_Cacheable; + } + + int getLastStubSecondShapeGuard() const { + return lastStubSecondShapeGuard ? POST_INST_OFFSET(lastStubSecondShapeGuard) : 0; + } + + void patchPreviousToHere(CodeLocationLabel cs) + { + Repatcher repatcher(pic.lastCodeBlock(f.jit())); + CodeLocationLabel label = pic.lastPathStart(); + + // Patch either the inline fast path or a generated stub. The stub + // omits the prefix of the inline fast path that loads the shape, so + // the offsets are different. + if (pic.stubsGenerated) { + repatcher.relink(pic.setPropLabels().getStubShapeJump(label), cs); + } else { + CodeLocationLabel shapeGuard = label.labelAtOffset(pic.shapeGuard); + repatcher.relink(pic.setPropLabels().getInlineShapeJump(shapeGuard), cs); + } + if (int secondGuardOffset = getLastStubSecondShapeGuard()) + repatcher.relink(label.jumpAtOffset(secondGuardOffset), cs); + } + + LookupStatus generateStub(uint32 initialShape, const Shape *shape, bool adding, bool inlineSlot) + { + /* Exits to the slow path. */ + Vector slowExits(cx); + Vector otherGuards(cx); + + Assembler masm; + + // Shape guard. + if (pic.shapeNeedsRemat()) { + masm.loadShape(pic.objReg, pic.shapeReg); + pic.shapeRegHasBaseShape = true; + } + + Label start = masm.label(); + Jump shapeGuard = masm.branch32FixedLength(Assembler::NotEqual, pic.shapeReg, + Imm32(initialShape)); + + Label stubShapeJumpLabel = masm.label(); + + pic.setPropLabels().setStubShapeJump(masm, start, stubShapeJumpLabel); + + JS_ASSERT_IF(!shape->hasDefaultSetter(), obj->getClass() == &js_CallClass); + + MaybeJump skipOver; + + if (adding) { + JS_ASSERT(shape->hasSlot()); + pic.shapeRegHasBaseShape = false; + + /* Emit shape guards for the object's prototype chain. */ + JSObject *proto = obj->getProto(); + RegisterID lastReg = pic.objReg; + while (proto) { + masm.loadPtr(Address(lastReg, offsetof(JSObject, proto)), pic.shapeReg); + Jump protoGuard = masm.guardShape(pic.shapeReg, proto); + if (!otherGuards.append(protoGuard)) + return error(); + + proto = proto->getProto(); + lastReg = pic.shapeReg; + } + + if (pic.kind == ic::PICInfo::SETMETHOD) { + /* + * Guard that the value is equal to the shape's method. + * We already know it is a function, so test the payload. + */ + JS_ASSERT(shape->isMethod()); + JSObject *funobj = &shape->methodObject(); + if (pic.u.vr.isConstant()) { + JS_ASSERT(funobj == &pic.u.vr.value().toObject()); + } else { + Jump mismatchedFunction = + masm.branchPtr(Assembler::NotEqual, pic.u.vr.dataReg(), ImmPtr(funobj)); + if (!slowExits.append(mismatchedFunction)) + return error(); + } + } + + if (inlineSlot) { + Address address(pic.objReg, + JSObject::getFixedSlotOffset(shape->slot)); + masm.storeValue(pic.u.vr, address); + } else { + /* Check capacity. */ + Address capacity(pic.objReg, offsetof(JSObject, capacity)); + masm.load32(masm.payloadOf(capacity), pic.shapeReg); + Jump overCapacity = masm.branch32(Assembler::LessThanOrEqual, pic.shapeReg, + Imm32(shape->slot)); + if (!slowExits.append(overCapacity)) + return error(); + + masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.shapeReg); + Address address(pic.shapeReg, shape->slot * sizeof(Value)); + masm.storeValue(pic.u.vr, address); + } + + uint32 newShape = obj->shape(); + JS_ASSERT(newShape != initialShape); + + /* Write the object's new shape. */ + masm.storePtr(ImmPtr(shape), Address(pic.objReg, offsetof(JSObject, lastProp))); + masm.store32(Imm32(newShape), Address(pic.objReg, offsetof(JSObject, objShape))); + + /* If this is a method shape, update the object's flags. */ + if (shape->isMethod()) { + Address flags(pic.objReg, offsetof(JSObject, flags)); + + /* Use shapeReg to load, bitwise-or, and store flags. */ + masm.load32(flags, pic.shapeReg); + masm.or32(Imm32(JSObject::METHOD_BARRIER), pic.shapeReg); + masm.store32(pic.shapeReg, flags); + } + } else if (shape->hasDefaultSetter()) { + Address address(pic.objReg, JSObject::getFixedSlotOffset(shape->slot)); + if (!inlineSlot) { + masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg); + address = Address(pic.objReg, shape->slot * sizeof(Value)); + } + + // If the scope is branded, or has a method barrier. It's now necessary + // to guard that we're not overwriting a function-valued property. + if (obj->brandedOrHasMethodBarrier()) { + masm.loadTypeTag(address, pic.shapeReg); + Jump skip = masm.testObject(Assembler::NotEqual, pic.shapeReg); + masm.loadPayload(address, pic.shapeReg); + Jump rebrand = masm.testFunction(Assembler::Equal, pic.shapeReg); + if (!slowExits.append(rebrand)) + return error(); + skip.linkTo(masm.label(), &masm); + pic.shapeRegHasBaseShape = false; + } + + masm.storeValue(pic.u.vr, address); + } else { + // \ / In general, two function objects with different JSFunctions + // # can have the same shape, thus we must not rely on the identity + // >--+--< of 'fun' remaining the same. However, since: + // ||| 1. the shape includes all arguments and locals and their setters + // \\ V and getters, and + // \===/ 2. arguments and locals have different getters + // then we can rely on fun->nargs remaining invariant. + JSFunction *fun = obj->getCallObjCalleeFunction(); + uint16 slot = uint16(shape->shortid); + + /* Guard that the call object has a frame. */ + masm.loadObjPrivate(pic.objReg, pic.shapeReg); + Jump escapedFrame = masm.branchTestPtr(Assembler::Zero, pic.shapeReg, pic.shapeReg); + + { + Address addr(pic.shapeReg, shape->setterOp() == SetCallArg + ? JSStackFrame::offsetOfFormalArg(fun, slot) + : JSStackFrame::offsetOfFixed(slot)); + masm.storeValue(pic.u.vr, addr); + skipOver = masm.jump(); + } + + escapedFrame.linkTo(masm.label(), &masm); + { + if (shape->setterOp() == SetCallVar) + slot += fun->nargs; + masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg); + + Address dslot(pic.objReg, (slot + JSObject::CALL_RESERVED_SLOTS) * sizeof(Value)); + masm.storeValue(pic.u.vr, dslot); + } + + pic.shapeRegHasBaseShape = false; + } + + Jump done = masm.jump(); + + // Common all secondary guards into one big exit. + MaybeJump slowExit; + if (otherGuards.length()) { + for (Jump *pj = otherGuards.begin(); pj != otherGuards.end(); ++pj) + pj->linkTo(masm.label(), &masm); + slowExit = masm.jump(); + pic.secondShapeGuard = masm.distanceOf(masm.label()) - masm.distanceOf(start); + } else { + pic.secondShapeGuard = 0; + } + + PICLinker buffer(masm, pic); + if (!buffer.init(cx)) + return error(); + + if (!buffer.verifyRange(pic.lastCodeBlock(f.jit())) || + !buffer.verifyRange(f.jit())) { + return disable("code memory is out of range"); + } + + buffer.link(shapeGuard, pic.slowPathStart); + if (slowExit.isSet()) + buffer.link(slowExit.get(), pic.slowPathStart); + for (Jump *pj = slowExits.begin(); pj != slowExits.end(); ++pj) + buffer.link(*pj, pic.slowPathStart); + buffer.link(done, pic.fastPathRejoin); + if (skipOver.isSet()) + buffer.link(skipOver.get(), pic.fastPathRejoin); + CodeLocationLabel cs = buffer.finalize(); + JaegerSpew(JSpew_PICs, "generate setprop stub %p %d %d at %p\n", + (void*)&pic, + initialShape, + pic.stubsGenerated, + cs.executableAddress()); + + // This function can patch either the inline fast path for a generated + // stub. The stub omits the prefix of the inline fast path that loads + // the shape, so the offsets are different. + patchPreviousToHere(cs); + + pic.stubsGenerated++; + pic.updateLastPath(buffer, start); + + if (pic.stubsGenerated == MAX_PIC_STUBS) + disable("max stubs reached"); + + return Lookup_Cacheable; + } + + LookupStatus update() + { + JS_ASSERT(pic.hit); + + if (obj->isDenseArray()) + return disable("dense array"); + if (!obj->isNative()) + return disable("non-native"); + + Class *clasp = obj->getClass(); + + if (clasp->setProperty != StrictPropertyStub) + return disable("set property hook"); + if (clasp->ops.lookupProperty) + return disable("ops lookup property hook"); + if (clasp->ops.setProperty) + return disable("ops set property hook"); + + jsid id = ATOM_TO_JSID(atom); + + JSObject *holder; + JSProperty *prop = NULL; + if (!obj->lookupProperty(cx, id, &holder, &prop)) + return error(); + + /* If the property exists but is on a prototype, treat as addprop. */ + if (prop && holder != obj) { + const Shape *shape = (const Shape *) prop; + + if (!holder->isNative()) + return disable("non-native holder"); + + if (!shape->writable()) + return disable("readonly"); + if (!shape->hasDefaultSetter() || !shape->hasDefaultGetter()) + return disable("getter/setter in prototype"); + if (shape->hasShortID()) + return disable("short ID in prototype"); + if (!shape->hasSlot()) + return disable("missing slot"); + + prop = NULL; + } + + if (!prop) { + /* Adding a property to the object. */ + if (obj->isDelegate()) + return disable("delegate"); + if (!obj->isExtensible()) + return disable("not extensible"); + + if (clasp->addProperty != PropertyStub) + return disable("add property hook"); + if (clasp->ops.defineProperty) + return disable("ops define property hook"); + + uint32 index; + if (js_IdIsIndex(id, &index)) + return disable("index"); + + uint32 initialShape = obj->shape(); + + if (!obj->ensureClassReservedSlots(cx)) + return error(); + + uint32 slots = obj->numSlots(); + uintN flags = 0; + PropertyOp getter = clasp->getProperty; + + if (pic.kind == ic::PICInfo::SETMETHOD) { + if (!obj->canHaveMethodBarrier()) + return disable("can't have method barrier"); + + JSObject *funobj = &f.regs.sp[-1].toObject(); + if (funobj != GET_FUNCTION_PRIVATE(cx, funobj)) + return disable("mismatched function"); + + flags |= Shape::METHOD; + getter = CastAsPropertyOp(funobj); + } + + /* + * Define the property but do not set it yet. For setmethod, + * populate the slot to satisfy the method invariant (in case we + * hit an early return below). + */ + const Shape *shape = + obj->putProperty(cx, id, getter, clasp->setProperty, + SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, flags, 0); + if (!shape) + return error(); + if (flags & Shape::METHOD) + obj->nativeSetSlot(shape->slot, f.regs.sp[-1]); + + /* + * Test after calling putProperty since it can switch obj into + * dictionary mode, specifically if the shape tree ancestor line + * exceeds PropertyTree::MAX_HEIGHT. + */ + if (obj->inDictionaryMode()) + return disable("dictionary"); + + if (!shape->hasDefaultSetter()) + return disable("adding non-default setter"); + if (!shape->hasSlot()) + return disable("adding invalid slot"); + + /* + * Watch for cases where the object reallocated its slots when + * adding the property, and disable the PIC. Otherwise we will + * keep generating identical PICs as side exits are taken on the + * capacity checks. Alternatively, we could avoid the disable + * and just not generate a stub in case there are multiple shapes + * that can flow here which don't all require reallocation. + * Doing this would cause us to walk down this same update path + * every time a reallocation is needed, however, which will + * usually be a slowdown even if there *are* other shapes that + * don't realloc. + */ + if (obj->numSlots() != slots) + return disable("insufficient slot capacity"); + + return generateStub(initialShape, shape, true, !obj->hasSlotsArray()); + } + + const Shape *shape = (const Shape *) prop; + if (pic.kind == ic::PICInfo::SETMETHOD && !shape->isMethod()) + return disable("set method on non-method shape"); + if (!shape->writable()) + return disable("readonly"); + + if (shape->hasDefaultSetter()) { + if (!shape->hasSlot()) + return disable("invalid slot"); + } else { + if (shape->hasSetterValue()) + return disable("scripted setter"); + if (shape->setterOp() != SetCallArg && + shape->setterOp() != SetCallVar) { + return disable("setter"); + } + } + + JS_ASSERT(obj == holder); + if (!pic.inlinePathPatched && + !obj->brandedOrHasMethodBarrier() && + shape->hasDefaultSetter() && + !obj->isDenseArray()) { + return patchInline(shape, !obj->hasSlotsArray()); + } + + return generateStub(obj->shape(), shape, false, !obj->hasSlotsArray()); + } +}; + +static bool +IsCacheableProtoChain(JSObject *obj, JSObject *holder) +{ + while (obj != holder) { + JSObject *proto = obj->getProto(); + if (!proto->isNative()) + return false; + obj = proto; + } + return true; +} + +template +struct GetPropertyHelper { + // These fields are set in the constructor and describe a property lookup. + JSContext *cx; + JSObject *obj; + JSAtom *atom; + IC ⁣ + + // These fields are set by |bind| and |lookup|. After a call to either + // function, these are set exactly as they are in JSOP_GETPROP or JSOP_NAME. + JSObject *aobj; + JSObject *holder; + JSProperty *prop; + + // This field is set by |bind| and |lookup| only if they returned + // Lookup_Cacheable, otherwise it is NULL. + const Shape *shape; + + GetPropertyHelper(JSContext *cx, JSObject *obj, JSAtom *atom, IC &ic) + : cx(cx), obj(obj), atom(atom), ic(ic), holder(NULL), prop(NULL), shape(NULL) + { } + + public: + LookupStatus bind() { + if (!js_FindProperty(cx, ATOM_TO_JSID(atom), &obj, &holder, &prop)) + return ic.error(cx); + if (!prop) + return ic.disable(cx, "lookup failed"); + if (!obj->isNative()) + return ic.disable(cx, "non-native"); + if (!IsCacheableProtoChain(obj, holder)) + return ic.disable(cx, "non-native holder"); + shape = (const Shape *)prop; + return Lookup_Cacheable; + } + + LookupStatus lookup() { + JSObject *aobj = js_GetProtoIfDenseArray(obj); + if (!aobj->isNative()) + return ic.disable(cx, "non-native"); + if (!aobj->lookupProperty(cx, ATOM_TO_JSID(atom), &holder, &prop)) + return ic.error(cx); + if (!prop) + return ic.disable(cx, "lookup failed"); + if (!IsCacheableProtoChain(obj, holder)) + return ic.disable(cx, "non-native holder"); + shape = (const Shape *)prop; + return Lookup_Cacheable; + } + + LookupStatus testForGet() { + if (!shape->hasDefaultGetter()) { + if (!shape->isMethod()) + return ic.disable(cx, "getter"); + if (!ic.isCallOp()) + return ic.disable(cx, "method valued shape"); + } else if (!shape->hasSlot()) { + return ic.disable(cx, "no slot"); + } + + return Lookup_Cacheable; + } + + LookupStatus lookupAndTest() { + LookupStatus status = lookup(); + if (status != Lookup_Cacheable) + return status; + return testForGet(); + } +}; + +class GetPropCompiler : public PICStubCompiler +{ + JSObject *obj; + JSAtom *atom; + int lastStubSecondShapeGuard; + + public: + GetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom, + VoidStubPIC stub) + : PICStubCompiler(pic.kind == ic::PICInfo::CALL ? "callprop" : "getprop", f, script, pic, + JS_FUNC_TO_DATA_PTR(void *, stub)), + obj(obj), + atom(atom), + lastStubSecondShapeGuard(pic.secondShapeGuard) + { } + + int getLastStubSecondShapeGuard() const { + return lastStubSecondShapeGuard ? POST_INST_OFFSET(lastStubSecondShapeGuard) : 0; + } + + static void reset(Repatcher &repatcher, ic::PICInfo &pic) + { + GetPropLabels &labels = pic.getPropLabels(); + repatcher.repatchLEAToLoadPtr(labels.getDslotsLoad(pic.fastPathRejoin)); + repatcher.repatch(labels.getInlineShapeData(pic.getFastShapeGuard()), + int32(JSObjectMap::INVALID_SHAPE)); + repatcher.relink(labels.getInlineShapeJump(pic.getFastShapeGuard()), pic.slowPathStart); + + if (pic.hasTypeCheck()) { + /* TODO: combine pic.u.get into ICLabels? */ + repatcher.relink(labels.getInlineTypeJump(pic.fastPathStart), pic.getSlowTypeCheck()); + } + + VoidStubPIC stub; + switch (pic.kind) { + case ic::PICInfo::GET: + stub = ic::GetProp; + break; + case ic::PICInfo::CALL: + stub = ic::CallProp; + break; + default: + JS_NOT_REACHED("invalid pic kind for GetPropCompiler::reset"); + return; + } + + FunctionPtr target(JS_FUNC_TO_DATA_PTR(void *, stub)); + repatcher.relink(pic.slowPathCall, target); + } + + LookupStatus generateArgsLengthStub() + { + Assembler masm; + + Jump notArgs = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass()); + + masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg); + masm.load32(Address(pic.objReg, JSObject::JSSLOT_ARGS_LENGTH * sizeof(Value)), + pic.objReg); + masm.move(pic.objReg, pic.shapeReg); + Jump overridden = masm.branchTest32(Assembler::NonZero, pic.shapeReg, + Imm32(JSObject::ARGS_LENGTH_OVERRIDDEN_BIT)); + masm.rshift32(Imm32(JSObject::ARGS_PACKED_BITS_COUNT), pic.objReg); + + masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg); + Jump done = masm.jump(); + + PICLinker buffer(masm, pic); + if (!buffer.init(cx)) + return error(); + + if (!buffer.verifyRange(pic.lastCodeBlock(f.jit())) || + !buffer.verifyRange(f.jit())) { + return disable("code memory is out of range"); + } + + buffer.link(notArgs, pic.slowPathStart); + buffer.link(overridden, pic.slowPathStart); + buffer.link(done, pic.fastPathRejoin); + + CodeLocationLabel start = buffer.finalize(); + JaegerSpew(JSpew_PICs, "generate args length stub at %p\n", + start.executableAddress()); + + patchPreviousToHere(start); + + disable("args length done"); + + return Lookup_Cacheable; + } + + LookupStatus generateArrayLengthStub() + { + Assembler masm; + + masm.loadObjClass(pic.objReg, pic.shapeReg); + Jump isDense = masm.testClass(Assembler::Equal, pic.shapeReg, &js_ArrayClass); + Jump notArray = masm.testClass(Assembler::NotEqual, pic.shapeReg, &js_SlowArrayClass); + + isDense.linkTo(masm.label(), &masm); + masm.load32(Address(pic.objReg, offsetof(JSObject, privateData)), pic.objReg); + Jump oob = masm.branch32(Assembler::Above, pic.objReg, Imm32(JSVAL_INT_MAX)); + masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg); + Jump done = masm.jump(); + + PICLinker buffer(masm, pic); + if (!buffer.init(cx)) + return error(); + + if (!buffer.verifyRange(pic.lastCodeBlock(f.jit())) || + !buffer.verifyRange(f.jit())) { + return disable("code memory is out of range"); + } + + buffer.link(notArray, pic.slowPathStart); + buffer.link(oob, pic.slowPathStart); + buffer.link(done, pic.fastPathRejoin); + + CodeLocationLabel start = buffer.finalize(); + JaegerSpew(JSpew_PICs, "generate array length stub at %p\n", + start.executableAddress()); + + patchPreviousToHere(start); + + disable("array length done"); + + return Lookup_Cacheable; + } + + LookupStatus generateStringObjLengthStub() + { + Assembler masm; + + Jump notStringObj = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass()); + masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg); + masm.loadPayload(Address(pic.objReg, JSObject::JSSLOT_PRIMITIVE_THIS * sizeof(Value)), + pic.objReg); + masm.loadPtr(Address(pic.objReg, JSString::offsetOfLengthAndFlags()), pic.objReg); + masm.urshift32(Imm32(JSString::LENGTH_SHIFT), pic.objReg); + masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg); + Jump done = masm.jump(); + + PICLinker buffer(masm, pic); + if (!buffer.init(cx)) + return error(); + + if (!buffer.verifyRange(pic.lastCodeBlock(f.jit())) || + !buffer.verifyRange(f.jit())) { + return disable("code memory is out of range"); + } + + buffer.link(notStringObj, pic.slowPathStart); + buffer.link(done, pic.fastPathRejoin); + + CodeLocationLabel start = buffer.finalize(); + JaegerSpew(JSpew_PICs, "generate string object length stub at %p\n", + start.executableAddress()); + + patchPreviousToHere(start); + + disable("string object length done"); + + return Lookup_Cacheable; + } + + LookupStatus generateStringCallStub() + { + JS_ASSERT(pic.hasTypeCheck()); + JS_ASSERT(pic.kind == ic::PICInfo::CALL); + + if (!f.fp()->script()->compileAndGo) + return disable("String.prototype without compile-and-go"); + + GetPropertyHelper getprop(cx, obj, atom, *this); + LookupStatus status = getprop.lookupAndTest(); + if (status != Lookup_Cacheable) + return status; + if (getprop.obj != getprop.holder) + return disable("proto walk on String.prototype"); + + Assembler masm; + + /* Only strings are allowed. */ + Jump notString = masm.branchPtr(Assembler::NotEqual, pic.typeReg(), + ImmType(JSVAL_TYPE_STRING)); + + /* + * Sink pic.objReg, since we're about to lose it. + * + * Note: This is really hacky, and relies on f.regs.sp being set + * correctly in ic::CallProp. Should we just move the store higher + * up in the fast path, or put this offset in PICInfo? + */ + uint32 thisvOffset = uint32(f.regs.sp - f.fp()->slots()) - 1; + Address thisv(JSFrameReg, sizeof(JSStackFrame) + thisvOffset * sizeof(Value)); + masm.storeValueFromComponents(ImmType(JSVAL_TYPE_STRING), + pic.objReg, thisv); + + /* + * Clobber objReg with String.prototype and do some PIC stuff. Well, + * really this is now a MIC, except it won't ever be patched, so we + * just disable the PIC at the end. :FIXME:? String.prototype probably + * does not get random shape changes. + */ + masm.move(ImmPtr(obj), pic.objReg); + masm.loadShape(pic.objReg, pic.shapeReg); + Jump shapeMismatch = masm.branch32(Assembler::NotEqual, pic.shapeReg, + Imm32(obj->shape())); + masm.loadObjProp(obj, pic.objReg, getprop.shape, pic.shapeReg, pic.objReg); + + Jump done = masm.jump(); + + PICLinker buffer(masm, pic); + if (!buffer.init(cx)) + return error(); + + if (!buffer.verifyRange(pic.lastCodeBlock(f.jit())) || + !buffer.verifyRange(f.jit())) { + return disable("code memory is out of range"); + } + + buffer.link(notString, pic.getSlowTypeCheck()); + buffer.link(shapeMismatch, pic.slowPathStart); + buffer.link(done, pic.fastPathRejoin); + + CodeLocationLabel cs = buffer.finalize(); + JaegerSpew(JSpew_PICs, "generate string call stub at %p\n", + cs.executableAddress()); + + /* Patch the type check to jump here. */ + if (pic.hasTypeCheck()) { + Repatcher repatcher(f.jit()); + repatcher.relink(pic.getPropLabels().getInlineTypeJump(pic.fastPathStart), cs); + } + + /* Disable the PIC so we don't keep generating stubs on the above shape mismatch. */ + disable("generated string call stub"); + + return Lookup_Cacheable; + } + + LookupStatus generateStringLengthStub() + { + JS_ASSERT(pic.hasTypeCheck()); + + Assembler masm; + Jump notString = masm.branchPtr(Assembler::NotEqual, pic.typeReg(), + ImmType(JSVAL_TYPE_STRING)); + masm.loadPtr(Address(pic.objReg, JSString::offsetOfLengthAndFlags()), pic.objReg); + // String length is guaranteed to be no more than 2**28, so the 32-bit operation is OK. + masm.urshift32(Imm32(JSString::LENGTH_SHIFT), pic.objReg); + masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg); + Jump done = masm.jump(); + + PICLinker buffer(masm, pic); + if (!buffer.init(cx)) + return error(); + + if (!buffer.verifyRange(pic.lastCodeBlock(f.jit())) || + !buffer.verifyRange(f.jit())) { + return disable("code memory is out of range"); + } + + buffer.link(notString, pic.getSlowTypeCheck()); + buffer.link(done, pic.fastPathRejoin); + + CodeLocationLabel start = buffer.finalize(); + JaegerSpew(JSpew_PICs, "generate string length stub at %p\n", + start.executableAddress()); + + if (pic.hasTypeCheck()) { + Repatcher repatcher(f.jit()); + repatcher.relink(pic.getPropLabels().getInlineTypeJump(pic.fastPathStart), start); + } + + disable("generated string length stub"); + + return Lookup_Cacheable; + } + + LookupStatus patchInline(JSObject *holder, const Shape *shape) + { + spew("patch", "inline"); + Repatcher repatcher(f.jit()); + GetPropLabels &labels = pic.getPropLabels(); + + int32 offset; + if (!holder->hasSlotsArray()) { + CodeLocationInstruction istr = labels.getDslotsLoad(pic.fastPathRejoin); + repatcher.repatchLoadPtrToLEA(istr); + + // + // We've patched | mov dslots, [obj + DSLOTS_OFFSET] + // To: | lea fslots, [obj + DSLOTS_OFFSET] + // + // Because the offset is wrong, it's necessary to correct it + // below. + // + int32 diff = int32(JSObject::getFixedSlotOffset(0)) - + int32(offsetof(JSObject, slots)); + JS_ASSERT(diff != 0); + offset = (int32(shape->slot) * sizeof(Value)) + diff; + } else { + offset = shape->slot * sizeof(Value); + } + + repatcher.repatch(labels.getInlineShapeData(pic.getFastShapeGuard()), obj->shape()); + repatcher.patchAddressOffsetForValueLoad(labels.getValueLoad(pic.fastPathRejoin), offset); + + pic.inlinePathPatched = true; + + return Lookup_Cacheable; + } + + LookupStatus generateStub(JSObject *holder, const Shape *shape) + { + Vector shapeMismatches(cx); + + Assembler masm; + + Label start; + Jump shapeGuardJump; + Jump argsLenGuard; + + bool setStubShapeOffset = true; + if (obj->isDenseArray()) { + start = masm.label(); + shapeGuardJump = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass()); + + /* + * No need to assert validity of GETPROP_STUB_SHAPE_JUMP in this case: + * the IC is disabled after a dense array hit, so no patching can occur. + */ +#ifndef JS_HAS_IC_LABELS + setStubShapeOffset = false; +#endif + } else { + if (pic.shapeNeedsRemat()) { + masm.loadShape(pic.objReg, pic.shapeReg); + pic.shapeRegHasBaseShape = true; + } + + start = masm.label(); + shapeGuardJump = masm.branch32FixedLength(Assembler::NotEqual, pic.shapeReg, + Imm32(obj->shape())); + } + Label stubShapeJumpLabel = masm.label(); + + if (!shapeMismatches.append(shapeGuardJump)) + return error(); + + RegisterID holderReg = pic.objReg; + if (obj != holder) { + // Bake in the holder identity. Careful not to clobber |objReg|, since we can't remat it. + holderReg = pic.shapeReg; + masm.move(ImmPtr(holder), holderReg); + pic.shapeRegHasBaseShape = false; + + // Guard on the holder's shape. + Jump j = masm.guardShape(holderReg, holder); + if (!shapeMismatches.append(j)) + return error(); + + pic.secondShapeGuard = masm.distanceOf(masm.label()) - masm.distanceOf(start); + } else { + pic.secondShapeGuard = 0; + } + + /* Load the value out of the object. */ + masm.loadObjProp(holder, holderReg, shape, pic.shapeReg, pic.objReg); + Jump done = masm.jump(); + + PICLinker buffer(masm, pic); + if (!buffer.init(cx)) + return error(); + + if (!buffer.verifyRange(pic.lastCodeBlock(f.jit())) || + !buffer.verifyRange(f.jit())) { + return disable("code memory is out of range"); + } + + // The guard exit jumps to the original slow case. + for (Jump *pj = shapeMismatches.begin(); pj != shapeMismatches.end(); ++pj) + buffer.link(*pj, pic.slowPathStart); + + // The final exit jumps to the store-back in the inline stub. + buffer.link(done, pic.fastPathRejoin); + CodeLocationLabel cs = buffer.finalize(); + JaegerSpew(JSpew_PICs, "generated %s stub at %p\n", type, cs.executableAddress()); + + patchPreviousToHere(cs); + + pic.stubsGenerated++; + pic.updateLastPath(buffer, start); + + if (setStubShapeOffset) + pic.getPropLabels().setStubShapeJump(masm, start, stubShapeJumpLabel); + + if (pic.stubsGenerated == MAX_PIC_STUBS) + disable("max stubs reached"); + if (obj->isDenseArray()) + disable("dense array"); + + return Lookup_Cacheable; + } + + void patchPreviousToHere(CodeLocationLabel cs) + { + Repatcher repatcher(pic.lastCodeBlock(f.jit())); + CodeLocationLabel label = pic.lastPathStart(); + + // Patch either the inline fast path or a generated stub. The stub + // omits the prefix of the inline fast path that loads the shape, so + // the offsets are different. + int shapeGuardJumpOffset; + if (pic.stubsGenerated) + shapeGuardJumpOffset = pic.getPropLabels().getStubShapeJumpOffset(); + else + shapeGuardJumpOffset = pic.shapeGuard + pic.getPropLabels().getInlineShapeJumpOffset(); + repatcher.relink(label.jumpAtOffset(shapeGuardJumpOffset), cs); + if (int secondGuardOffset = getLastStubSecondShapeGuard()) + repatcher.relink(label.jumpAtOffset(secondGuardOffset), cs); + } + + LookupStatus update() + { + JS_ASSERT(pic.hit); + + GetPropertyHelper getprop(cx, obj, atom, *this); + LookupStatus status = getprop.lookupAndTest(); + if (status != Lookup_Cacheable) + return status; + + if (obj == getprop.holder && !pic.inlinePathPatched) + return patchInline(getprop.holder, getprop.shape); + + return generateStub(getprop.holder, getprop.shape); + } +}; + +class ScopeNameCompiler : public PICStubCompiler +{ + private: + typedef Vector JumpList; + + JSObject *scopeChain; + JSAtom *atom; + GetPropertyHelper getprop; + ScopeNameCompiler *thisFromCtor() { return this; } + + void patchPreviousToHere(CodeLocationLabel cs) + { + ScopeNameLabels & labels = pic.scopeNameLabels(); + Repatcher repatcher(pic.lastCodeBlock(f.jit())); + CodeLocationLabel start = pic.lastPathStart(); + JSC::CodeLocationJump jump; + + // Patch either the inline fast path or a generated stub. + if (pic.stubsGenerated) + jump = labels.getStubJump(start); + else + jump = labels.getInlineJump(start); + repatcher.relink(jump, cs); + } + + LookupStatus walkScopeChain(Assembler &masm, JumpList &fails) + { + /* Walk the scope chain. */ + JSObject *tobj = scopeChain; + + /* For GETXPROP, we'll never enter this loop. */ + JS_ASSERT_IF(pic.kind == ic::PICInfo::XNAME, tobj && tobj == getprop.holder); + JS_ASSERT_IF(pic.kind == ic::PICInfo::XNAME, getprop.obj == tobj); + + while (tobj && tobj != getprop.holder) { + if (!IsCacheableNonGlobalScope(tobj)) + return disable("non-cacheable scope chain object"); + JS_ASSERT(tobj->isNative()); + + if (tobj != scopeChain) { + /* scopeChain will never be NULL, but parents can be NULL. */ + Jump j = masm.branchTestPtr(Assembler::Zero, pic.objReg, pic.objReg); + if (!fails.append(j)) + return error(); + } + + /* Guard on intervening shapes. */ + masm.loadShape(pic.objReg, pic.shapeReg); + Jump j = masm.branch32(Assembler::NotEqual, pic.shapeReg, Imm32(tobj->shape())); + if (!fails.append(j)) + return error(); + + /* Load the next link in the scope chain. */ + Address parent(pic.objReg, offsetof(JSObject, parent)); + masm.loadPtr(parent, pic.objReg); + + tobj = tobj->getParent(); + } + + if (tobj != getprop.holder) + return disable("scope chain walk terminated early"); + + return Lookup_Cacheable; + } + + public: + ScopeNameCompiler(VMFrame &f, JSScript *script, JSObject *scopeChain, ic::PICInfo &pic, + JSAtom *atom, VoidStubPIC stub) + : PICStubCompiler("name", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)), + scopeChain(scopeChain), atom(atom), + getprop(f.cx, NULL, atom, *thisFromCtor()) + { } + + static void reset(Repatcher &repatcher, ic::PICInfo &pic) + { + ScopeNameLabels &labels = pic.scopeNameLabels(); + + /* Link the inline path back to the slow path. */ + JSC::CodeLocationJump inlineJump = labels.getInlineJump(pic.fastPathStart); + repatcher.relink(inlineJump, pic.slowPathStart); + + VoidStubPIC stub = (pic.kind == ic::PICInfo::NAME) ? ic::Name : ic::XName; + FunctionPtr target(JS_FUNC_TO_DATA_PTR(void *, stub)); + repatcher.relink(pic.slowPathCall, target); + } + + LookupStatus generateGlobalStub(JSObject *obj) + { + Assembler masm; + JumpList fails(cx); + ScopeNameLabels &labels = pic.scopeNameLabels(); + + /* For GETXPROP, the object is already in objReg. */ + if (pic.kind == ic::PICInfo::NAME) + masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg); + + JS_ASSERT(obj == getprop.holder); + JS_ASSERT(getprop.holder == scopeChain->getGlobal()); + + LookupStatus status = walkScopeChain(masm, fails); + if (status != Lookup_Cacheable) + return status; + + /* If a scope chain walk was required, the final object needs a NULL test. */ + MaybeJump finalNull; + if (pic.kind == ic::PICInfo::NAME) + finalNull = masm.branchTestPtr(Assembler::Zero, pic.objReg, pic.objReg); + masm.loadShape(pic.objReg, pic.shapeReg); + Jump finalShape = masm.branch32(Assembler::NotEqual, pic.shapeReg, Imm32(getprop.holder->shape())); + + masm.loadObjProp(obj, pic.objReg, getprop.shape, pic.shapeReg, pic.objReg); + Jump done = masm.jump(); + + /* All failures flow to here, so there is a common point to patch. */ + for (Jump *pj = fails.begin(); pj != fails.end(); ++pj) + pj->linkTo(masm.label(), &masm); + if (finalNull.isSet()) + finalNull.get().linkTo(masm.label(), &masm); + finalShape.linkTo(masm.label(), &masm); + Label failLabel = masm.label(); + Jump failJump = masm.jump(); + + PICLinker buffer(masm, pic); + if (!buffer.init(cx)) + return error(); + + if (!buffer.verifyRange(pic.lastCodeBlock(f.jit())) || + !buffer.verifyRange(f.jit())) { + return disable("code memory is out of range"); + } + + buffer.link(failJump, pic.slowPathStart); + buffer.link(done, pic.fastPathRejoin); + CodeLocationLabel cs = buffer.finalize(); + JaegerSpew(JSpew_PICs, "generated %s global stub at %p\n", type, cs.executableAddress()); + spew("NAME stub", "global"); + + patchPreviousToHere(cs); + + pic.stubsGenerated++; + pic.updateLastPath(buffer, failLabel); + labels.setStubJump(masm, failLabel, failJump); + + if (pic.stubsGenerated == MAX_PIC_STUBS) + disable("max stubs reached"); + + return Lookup_Cacheable; + } + + enum CallObjPropKind { + ARG, + VAR + }; + + LookupStatus generateCallStub(JSObject *obj) + { + Assembler masm; + Vector fails(cx); + ScopeNameLabels &labels = pic.scopeNameLabels(); + + /* For GETXPROP, the object is already in objReg. */ + if (pic.kind == ic::PICInfo::NAME) + masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg); + + JS_ASSERT(obj == getprop.holder); + JS_ASSERT(getprop.holder != scopeChain->getGlobal()); + + CallObjPropKind kind; + const Shape *shape = getprop.shape; + if (shape->getterOp() == GetCallArg) { + kind = ARG; + } else if (shape->getterOp() == GetCallVar) { + kind = VAR; + } else { + return disable("unhandled callobj sprop getter"); + } + + LookupStatus status = walkScopeChain(masm, fails); + if (status != Lookup_Cacheable) + return status; + + /* If a scope chain walk was required, the final object needs a NULL test. */ + MaybeJump finalNull; + if (pic.kind == ic::PICInfo::NAME) + finalNull = masm.branchTestPtr(Assembler::Zero, pic.objReg, pic.objReg); + masm.loadShape(pic.objReg, pic.shapeReg); + Jump finalShape = masm.branch32(Assembler::NotEqual, pic.shapeReg, Imm32(getprop.holder->shape())); + + /* Get callobj's stack frame. */ + masm.loadObjPrivate(pic.objReg, pic.shapeReg); + + JSFunction *fun = getprop.holder->getCallObjCalleeFunction(); + uint16 slot = uint16(shape->shortid); + + Jump skipOver; + Jump escapedFrame = masm.branchTestPtr(Assembler::Zero, pic.shapeReg, pic.shapeReg); + + /* Not-escaped case. */ + { + Address addr(pic.shapeReg, kind == ARG ? JSStackFrame::offsetOfFormalArg(fun, slot) + : JSStackFrame::offsetOfFixed(slot)); + masm.loadPayload(addr, pic.objReg); + masm.loadTypeTag(addr, pic.shapeReg); + skipOver = masm.jump(); + } + + escapedFrame.linkTo(masm.label(), &masm); + + { + masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg); + + if (kind == VAR) + slot += fun->nargs; + Address dslot(pic.objReg, (slot + JSObject::CALL_RESERVED_SLOTS) * sizeof(Value)); + + /* Safe because type is loaded first. */ + masm.loadValueAsComponents(dslot, pic.shapeReg, pic.objReg); + } + + skipOver.linkTo(masm.label(), &masm); + Jump done = masm.jump(); + + // All failures flow to here, so there is a common point to patch. + for (Jump *pj = fails.begin(); pj != fails.end(); ++pj) + pj->linkTo(masm.label(), &masm); + if (finalNull.isSet()) + finalNull.get().linkTo(masm.label(), &masm); + finalShape.linkTo(masm.label(), &masm); + Label failLabel = masm.label(); + Jump failJump = masm.jump(); + + PICLinker buffer(masm, pic); + if (!buffer.init(cx)) + return error(); + + if (!buffer.verifyRange(pic.lastCodeBlock(f.jit())) || + !buffer.verifyRange(f.jit())) { + return disable("code memory is out of range"); + } + + buffer.link(failJump, pic.slowPathStart); + buffer.link(done, pic.fastPathRejoin); + CodeLocationLabel cs = buffer.finalize(); + JaegerSpew(JSpew_PICs, "generated %s call stub at %p\n", type, cs.executableAddress()); + + patchPreviousToHere(cs); + + pic.stubsGenerated++; + pic.updateLastPath(buffer, failLabel); + labels.setStubJump(masm, failLabel, failJump); + + if (pic.stubsGenerated == MAX_PIC_STUBS) + disable("max stubs reached"); + + return Lookup_Cacheable; + } + + LookupStatus updateForName() + { + // |getprop.obj| is filled by bind() + LookupStatus status = getprop.bind(); + if (status != Lookup_Cacheable) + return status; + + return update(getprop.obj); + } + + LookupStatus updateForXName() + { + // |obj| and |getprop.obj| are NULL, but should be the given scopeChain. + getprop.obj = scopeChain; + LookupStatus status = getprop.lookup(); + if (status != Lookup_Cacheable) + return status; + + return update(getprop.obj); + } + + LookupStatus update(JSObject *obj) + { + if (obj != getprop.holder) + return disable("property is on proto of a scope object"); + + if (obj->getClass() == &js_CallClass) + return generateCallStub(obj); + + LookupStatus status = getprop.testForGet(); + if (status != Lookup_Cacheable) + return status; + + if (!obj->getParent()) + return generateGlobalStub(obj); + + return disable("scope object not handled yet"); + } + + bool retrieve(Value *vp) + { + JSObject *obj = getprop.obj; + JSObject *holder = getprop.holder; + const JSProperty *prop = getprop.prop; + + if (!prop) { + /* Kludge to allow (typeof foo == "undefined") tests. */ + disable("property not found"); + if (pic.kind == ic::PICInfo::NAME) { + JSOp op2 = js_GetOpcode(cx, script, cx->regs->pc + JSOP_NAME_LENGTH); + if (op2 == JSOP_TYPEOF) { + vp->setUndefined(); + return true; + } + } + ReportAtomNotDefined(cx, atom); + return false; + } + + // If the property was found, but we decided not to cache it, then + // take a slow path and do a full property fetch. + if (!getprop.shape) + return obj->getProperty(cx, ATOM_TO_JSID(atom), vp); + + const Shape *shape = getprop.shape; + JSObject *normalized = obj; + if (obj->getClass() == &js_WithClass && !shape->hasDefaultGetter()) + normalized = js_UnwrapWithObject(cx, obj); + NATIVE_GET(cx, normalized, holder, shape, JSGET_METHOD_BARRIER, vp, return false); + + return true; + } +}; + +class BindNameCompiler : public PICStubCompiler +{ + JSObject *scopeChain; + JSAtom *atom; + + public: + BindNameCompiler(VMFrame &f, JSScript *script, JSObject *scopeChain, ic::PICInfo &pic, + JSAtom *atom, VoidStubPIC stub) + : PICStubCompiler("bind", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)), + scopeChain(scopeChain), atom(atom) + { } + + static void reset(Repatcher &repatcher, ic::PICInfo &pic) + { + BindNameLabels &labels = pic.bindNameLabels(); + + /* Link the inline jump back to the slow path. */ + JSC::CodeLocationJump inlineJump = labels.getInlineJump(pic.getFastShapeGuard()); + repatcher.relink(inlineJump, pic.slowPathStart); + + /* Link the slow path to call the IC entry point. */ + FunctionPtr target(JS_FUNC_TO_DATA_PTR(void *, ic::BindName)); + repatcher.relink(pic.slowPathCall, target); + } + + void patchPreviousToHere(CodeLocationLabel cs) + { + BindNameLabels &labels = pic.bindNameLabels(); + Repatcher repatcher(pic.lastCodeBlock(f.jit())); + JSC::CodeLocationJump jump; + + /* Patch either the inline fast path or a generated stub. */ + if (pic.stubsGenerated) + jump = labels.getStubJump(pic.lastPathStart()); + else + jump = labels.getInlineJump(pic.getFastShapeGuard()); + repatcher.relink(jump, cs); + } + + LookupStatus generateStub(JSObject *obj) + { + Assembler masm; + js::Vector fails(cx); + + BindNameLabels &labels = pic.bindNameLabels(); + + /* Guard on the shape of the scope chain. */ + masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg); + masm.loadShape(pic.objReg, pic.shapeReg); + Jump firstShape = masm.branch32(Assembler::NotEqual, pic.shapeReg, + Imm32(scopeChain->shape())); + + /* Walk up the scope chain. */ + JSObject *tobj = scopeChain; + Address parent(pic.objReg, offsetof(JSObject, parent)); + while (tobj && tobj != obj) { + if (!IsCacheableNonGlobalScope(tobj)) + return disable("non-cacheable obj in scope chain"); + masm.loadPtr(parent, pic.objReg); + Jump nullTest = masm.branchTestPtr(Assembler::Zero, pic.objReg, pic.objReg); + if (!fails.append(nullTest)) + return error(); + masm.loadShape(pic.objReg, pic.shapeReg); + Jump shapeTest = masm.branch32(Assembler::NotEqual, pic.shapeReg, + Imm32(tobj->shape())); + if (!fails.append(shapeTest)) + return error(); + tobj = tobj->getParent(); + } + if (tobj != obj) + return disable("indirect hit"); + + Jump done = masm.jump(); + + // All failures flow to here, so there is a common point to patch. + for (Jump *pj = fails.begin(); pj != fails.end(); ++pj) + pj->linkTo(masm.label(), &masm); + firstShape.linkTo(masm.label(), &masm); + Label failLabel = masm.label(); + Jump failJump = masm.jump(); + + PICLinker buffer(masm, pic); + if (!buffer.init(cx)) + return error(); + + if (!buffer.verifyRange(pic.lastCodeBlock(f.jit())) || + !buffer.verifyRange(f.jit())) { + return disable("code memory is out of range"); + } + + buffer.link(failJump, pic.slowPathStart); + buffer.link(done, pic.fastPathRejoin); + CodeLocationLabel cs = buffer.finalize(); + JaegerSpew(JSpew_PICs, "generated %s stub at %p\n", type, cs.executableAddress()); + + patchPreviousToHere(cs); + + pic.stubsGenerated++; + pic.updateLastPath(buffer, failLabel); + labels.setStubJump(masm, failLabel, failJump); + + if (pic.stubsGenerated == MAX_PIC_STUBS) + disable("max stubs reached"); + + return Lookup_Cacheable; + } + + JSObject *update() + { + JS_ASSERT(scopeChain->getParent()); + + JSObject *obj = js_FindIdentifierBase(cx, scopeChain, ATOM_TO_JSID(atom)); + if (!obj) + return obj; + + if (!pic.hit) { + spew("first hit", "nop"); + pic.hit = true; + return obj; + } + + LookupStatus status = generateStub(obj); + if (status == Lookup_Error) + return NULL; + + return obj; + } +}; + +static void JS_FASTCALL +DisabledLengthIC(VMFrame &f, ic::PICInfo *pic) +{ + stubs::Length(f); +} + +static void JS_FASTCALL +DisabledGetPropIC(VMFrame &f, ic::PICInfo *pic) +{ + stubs::GetProp(f); +} + +static void JS_FASTCALL +DisabledGetPropICNoCache(VMFrame &f, ic::PICInfo *pic) +{ + stubs::GetPropNoCache(f, pic->atom); +} + +void JS_FASTCALL +ic::GetProp(VMFrame &f, ic::PICInfo *pic) +{ + JSScript *script = f.fp()->script(); + + JSAtom *atom = pic->atom; + if (atom == f.cx->runtime->atomState.lengthAtom) { + if (f.regs.sp[-1].isString()) { + GetPropCompiler cc(f, script, NULL, *pic, NULL, DisabledLengthIC); + LookupStatus status = cc.generateStringLengthStub(); + if (status == Lookup_Error) + THROW(); + JSString *str = f.regs.sp[-1].toString(); + f.regs.sp[-1].setInt32(str->length()); + return; + } else if (!f.regs.sp[-1].isPrimitive()) { + JSObject *obj = &f.regs.sp[-1].toObject(); + if (obj->isArray() || (obj->isArguments() && !obj->isArgsLengthOverridden()) || + obj->isString()) { + GetPropCompiler cc(f, script, obj, *pic, NULL, DisabledLengthIC); + if (obj->isArray()) { + LookupStatus status = cc.generateArrayLengthStub(); + if (status == Lookup_Error) + THROW(); + f.regs.sp[-1].setNumber(obj->getArrayLength()); + } else if (obj->isArguments()) { + LookupStatus status = cc.generateArgsLengthStub(); + if (status == Lookup_Error) + THROW(); + f.regs.sp[-1].setInt32(int32_t(obj->getArgsInitialLength())); + } else if (obj->isString()) { + LookupStatus status = cc.generateStringObjLengthStub(); + if (status == Lookup_Error) + THROW(); + JSString *str = obj->getPrimitiveThis().toString(); + f.regs.sp[-1].setInt32(str->length()); + } + return; + } + } + atom = f.cx->runtime->atomState.lengthAtom; + } + + JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-1]); + if (!obj) + THROW(); + + if (pic->shouldUpdate(f.cx)) { + VoidStubPIC stub = pic->usePropCache + ? DisabledGetPropIC + : DisabledGetPropICNoCache; + GetPropCompiler cc(f, script, obj, *pic, atom, stub); + if (!cc.update()) { + cc.disable("error"); + THROW(); + } + } + + Value v; + if (!obj->getProperty(f.cx, ATOM_TO_JSID(atom), &v)) + THROW(); + f.regs.sp[-1] = v; +} + +template +static void JS_FASTCALL +DisabledSetPropIC(VMFrame &f, ic::PICInfo *pic) +{ + stubs::SetName(f, pic->atom); +} + +template +static void JS_FASTCALL +DisabledSetPropICNoCache(VMFrame &f, ic::PICInfo *pic) +{ + stubs::SetPropNoCache(f, pic->atom); +} + +void JS_FASTCALL +ic::SetProp(VMFrame &f, ic::PICInfo *pic) +{ + JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]); + if (!obj) + THROW(); + + JSScript *script = f.fp()->script(); + JS_ASSERT(pic->isSet()); + + VoidStubPIC stub = pic->usePropCache + ? STRICT_VARIANT(DisabledSetPropIC) + : STRICT_VARIANT(DisabledSetPropICNoCache); + + // + // Important: We update the PIC before looking up the property so that the + // PIC is updated only if the property already exists. The PIC doesn't try + // to optimize adding new properties; that is for the slow case. + // + // Also note, we can't use SetName for PROPINC PICs because the property + // cache can't handle a GET and SET from the same scripted PC. + if (pic->shouldUpdate(f.cx)) { + + SetPropCompiler cc(f, script, obj, *pic, pic->atom, stub); + LookupStatus status = cc.update(); + if (status == Lookup_Error) + THROW(); + } + + Value rval = f.regs.sp[-1]; + stub(f, pic); +} + +static void JS_FASTCALL +DisabledCallPropIC(VMFrame &f, ic::PICInfo *pic) +{ + stubs::CallProp(f, pic->atom); +} + +void JS_FASTCALL +ic::CallProp(VMFrame &f, ic::PICInfo *pic) +{ + JSContext *cx = f.cx; + JSFrameRegs ®s = f.regs; + + JSScript *script = f.fp()->script(); + + Value lval; + lval = regs.sp[-1]; + + Value objv; + if (lval.isObject()) { + objv = lval; + } else { + JSProtoKey protoKey; + if (lval.isString()) { + protoKey = JSProto_String; + } else if (lval.isNumber()) { + protoKey = JSProto_Number; + } else if (lval.isBoolean()) { + protoKey = JSProto_Boolean; + } else { + JS_ASSERT(lval.isNull() || lval.isUndefined()); + js_ReportIsNullOrUndefined(cx, -1, lval, NULL); + THROW(); + } + JSObject *pobj; + if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj)) + THROW(); + objv.setObject(*pobj); + } + + JSObject *aobj = js_GetProtoIfDenseArray(&objv.toObject()); + Value rval; + + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); + if (!atom) { + if (entry->vword.isFunObj()) { + rval.setObject(entry->vword.toFunObj()); + } else if (entry->vword.isSlot()) { + uint32 slot = entry->vword.toSlot(); + rval = obj2->nativeGetSlot(slot); + } else { + JS_ASSERT(entry->vword.isShape()); + const Shape *shape = entry->vword.toShape(); + NATIVE_GET(cx, &objv.toObject(), obj2, shape, JSGET_NO_METHOD_BARRIER, &rval, + THROW()); + } + regs.sp++; + regs.sp[-2] = rval; + regs.sp[-1] = lval; + } else { + /* + * Cache miss: use the immediate atom that was loaded for us under + * PropertyCache::test. + */ + jsid id; + id = ATOM_TO_JSID(pic->atom); + + regs.sp++; + regs.sp[-1].setNull(); + if (lval.isObject()) { + if (!js_GetMethod(cx, &objv.toObject(), id, + JS_LIKELY(!objv.toObject().getOps()->getProperty) + ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER + : JSGET_NO_METHOD_BARRIER, + &rval)) { + THROW(); + } + regs.sp[-1] = objv; + regs.sp[-2] = rval; + } else { + JS_ASSERT(!objv.toObject().getOps()->getProperty); + if (!js_GetPropertyHelper(cx, &objv.toObject(), id, + JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER, + &rval)) { + THROW(); + } + regs.sp[-1] = lval; + regs.sp[-2] = rval; + } + } + + GetPropCompiler cc(f, script, &objv.toObject(), *pic, pic->atom, DisabledCallPropIC); + if (lval.isObject()) { + if (pic->shouldUpdate(cx)) { + LookupStatus status = cc.update(); + if (status == Lookup_Error) + THROW(); + } + } else if (lval.isString()) { + LookupStatus status = cc.generateStringCallStub(); + if (status == Lookup_Error) + THROW(); + } else { + cc.disable("non-string primitive"); + } + +#if JS_HAS_NO_SUCH_METHOD + if (JS_UNLIKELY(rval.isUndefined()) && regs.sp[-1].isObject()) { + regs.sp[-2].setString(ATOM_TO_STRING(pic->atom)); + if (!js_OnUnknownMethod(cx, regs.sp - 2)) + THROW(); + } +#endif +} + +static void JS_FASTCALL +DisabledNameIC(VMFrame &f, ic::PICInfo *pic) +{ + stubs::Name(f); +} + +static void JS_FASTCALL +DisabledXNameIC(VMFrame &f, ic::PICInfo *pic) +{ + stubs::GetProp(f); +} + +void JS_FASTCALL +ic::XName(VMFrame &f, ic::PICInfo *pic) +{ + JSScript *script = f.fp()->script(); + + /* GETXPROP is guaranteed to have an object. */ + JSObject *obj = &f.regs.sp[-1].toObject(); + + ScopeNameCompiler cc(f, script, obj, *pic, pic->atom, DisabledXNameIC); + + LookupStatus status = cc.updateForXName(); + if (status == Lookup_Error) + THROW(); + + Value rval; + if (!cc.retrieve(&rval)) + THROW(); + f.regs.sp[-1] = rval; +} + +void JS_FASTCALL +ic::Name(VMFrame &f, ic::PICInfo *pic) +{ + JSScript *script = f.fp()->script(); + + ScopeNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, DisabledNameIC); + + LookupStatus status = cc.updateForName(); + if (status == Lookup_Error) + THROW(); + + Value rval; + if (!cc.retrieve(&rval)) + THROW(); + f.regs.sp[0] = rval; +} + +static void JS_FASTCALL +DisabledBindNameIC(VMFrame &f, ic::PICInfo *pic) +{ + stubs::BindName(f); +} + +static void JS_FASTCALL +DisabledBindNameICNoCache(VMFrame &f, ic::PICInfo *pic) +{ + stubs::BindNameNoCache(f, pic->atom); +} + +void JS_FASTCALL +ic::BindName(VMFrame &f, ic::PICInfo *pic) +{ + JSScript *script = f.fp()->script(); + + VoidStubPIC stub = pic->usePropCache + ? DisabledBindNameIC + : DisabledBindNameICNoCache; + BindNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, stub); + + JSObject *obj = cc.update(); + if (!obj) { + cc.disable("error"); + THROW(); + } + + f.regs.sp[0].setObject(*obj); +} + +bool +BaseIC::isCallOp() +{ + return !!(js_CodeSpec[op].format & JOF_CALLOP); +} + +void +BaseIC::spew(JSContext *cx, const char *event, const char *message) +{ +#ifdef JS_METHODJIT_SPEW + JaegerSpew(JSpew_PICs, "%s %s: %s (%s: %d)\n", + js_CodeName[op], event, message, cx->fp()->script()->filename, + js_FramePCToLineNumber(cx, cx->fp())); +#endif +} + +LookupStatus +BaseIC::disable(JSContext *cx, const char *reason, void *stub) +{ + spew(cx, "disabled", reason); + Repatcher repatcher(cx->fp()->jit()); + repatcher.relink(slowPathCall, FunctionPtr(stub)); + return Lookup_Uncacheable; +} + +bool +BaseIC::shouldUpdate(JSContext *cx) +{ + if (!hit) { + hit = true; + spew(cx, "ignored", "first hit"); + return false; + } + JS_ASSERT(stubsGenerated < MAX_PIC_STUBS); + return true; +} + +static void JS_FASTCALL +DisabledGetElem(VMFrame &f, ic::GetElementIC *ic) +{ + stubs::GetElem(f); +} + +static void JS_FASTCALL +DisabledCallElem(VMFrame &f, ic::GetElementIC *ic) +{ + stubs::CallElem(f); +} + +bool +GetElementIC::shouldUpdate(JSContext *cx) +{ + if (!hit) { + hit = true; + spew(cx, "ignored", "first hit"); + return false; + } + JS_ASSERT(stubsGenerated < MAX_GETELEM_IC_STUBS); + return true; +} + +LookupStatus +GetElementIC::disable(JSContext *cx, const char *reason) +{ + slowCallPatched = true; + void *stub = (op == JSOP_GETELEM) + ? JS_FUNC_TO_DATA_PTR(void *, DisabledGetElem) + : JS_FUNC_TO_DATA_PTR(void *, DisabledCallElem); + BaseIC::disable(cx, reason, stub); + return Lookup_Uncacheable; +} + +LookupStatus +GetElementIC::error(JSContext *cx) +{ + disable(cx, "error"); + return Lookup_Error; +} + +void +GetElementIC::purge(Repatcher &repatcher) +{ + // Repatch the inline jumps. + if (inlineTypeGuardPatched) + repatcher.relink(fastPathStart.jumpAtOffset(inlineTypeGuard), slowPathStart); + if (inlineClaspGuardPatched) + repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), slowPathStart); + + if (slowCallPatched) { + if (op == JSOP_GETELEM) { + repatcher.relink(slowPathCall, + FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, ic::GetElement))); + } else if (op == JSOP_CALLELEM) { + repatcher.relink(slowPathCall, + FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, ic::CallElement))); + } + } + + reset(); +} + +LookupStatus +GetElementIC::attachGetProp(JSContext *cx, JSObject *obj, const Value &v, jsid id, Value *vp) +{ + JS_ASSERT(v.isString()); + + GetPropertyHelper getprop(cx, obj, JSID_TO_ATOM(id), *this); + LookupStatus status = getprop.lookupAndTest(); + if (status != Lookup_Cacheable) + return status; + + Assembler masm; + + // Guard on the string's type and identity. + MaybeJump atomTypeGuard; + if (hasInlineTypeGuard() && !inlineTypeGuardPatched) { + // We link all string-key dependent stubs together, and store the + // first set of guards in the IC, separately, from int-key dependent + // stubs. As long as we guarantee that the first string-key dependent + // stub guards on the key type, then all other string-key stubs can + // omit the guard. + JS_ASSERT(!idRemat.isTypeKnown()); + atomTypeGuard = masm.testString(Assembler::NotEqual, typeReg); + } else { + // If there was no inline type guard, then a string type is guaranteed. + // Otherwise, we are guaranteed the type has already been checked, via + // the comment above. + JS_ASSERT_IF(!hasInlineTypeGuard(), idRemat.knownType() == JSVAL_TYPE_STRING); + } + + // Reify the shape before guards that could flow into shape guarding stubs. + if (!obj->isDenseArray() && !typeRegHasBaseShape) { + masm.loadShape(objReg, typeReg); + typeRegHasBaseShape = true; + } + + MaybeJump atomIdGuard; + if (!idRemat.isConstant()) + atomIdGuard = masm.branchPtr(Assembler::NotEqual, idRemat.dataReg(), ImmPtr(v.toString())); + + // Guard on the base shape (or in the dense array case, the clasp). + Jump shapeGuard; + if (obj->isDenseArray()) { + shapeGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass()); + } else { + shapeGuard = masm.branch32(Assembler::NotEqual, typeReg, Imm32(obj->shape())); + } + + // Guard on the prototype, if applicable. + MaybeJump protoGuard; + JSObject *holder = getprop.holder; + RegisterID holderReg = objReg; + if (obj != holder) { + // Bake in the holder identity. Careful not to clobber |objReg|, since we can't remat it. + holderReg = typeReg; + masm.move(ImmPtr(holder), holderReg); + typeRegHasBaseShape = false; + + // Guard on the holder's shape. + protoGuard = masm.guardShape(holderReg, holder); + } + + if (op == JSOP_CALLELEM) { + // Emit a write of |obj| to the top of the stack, before we lose it. + Value *thisVp = &cx->regs->sp[-1]; + Address thisSlot(JSFrameReg, JSStackFrame::offsetOfFixed(thisVp - cx->fp()->slots())); + masm.storeValueFromComponents(ImmType(JSVAL_TYPE_OBJECT), objReg, thisSlot); + } + + // Load the value. + const Shape *shape = getprop.shape; + masm.loadObjProp(holder, holderReg, shape, typeReg, objReg); + + Jump done = masm.jump(); + + PICLinker buffer(masm, *this); + if (!buffer.init(cx)) + return error(cx); + + if (hasLastStringStub && !buffer.verifyRange(lastStringStub)) + return disable(cx, "code memory is out of range"); + if (!buffer.verifyRange(cx->fp()->jit())) + return disable(cx, "code memory is out of range"); + + // Patch all guards. + buffer.maybeLink(atomIdGuard, slowPathStart); + buffer.maybeLink(atomTypeGuard, slowPathStart); + buffer.link(shapeGuard, slowPathStart); + buffer.maybeLink(protoGuard, slowPathStart); + buffer.link(done, fastPathRejoin); + + CodeLocationLabel cs = buffer.finalize(); +#if DEBUG + char *chars = js_DeflateString(cx, v.toString()->nonRopeChars(), v.toString()->length()); + JaegerSpew(JSpew_PICs, "generated %s stub at %p for atom 0x%x (\"%s\") shape 0x%x (%s: %d)\n", + js_CodeName[op], cs.executableAddress(), id, chars, holder->shape(), + cx->fp()->script()->filename, js_FramePCToLineNumber(cx, cx->fp())); + cx->free(chars); +#endif + + // Update the inline guards, if needed. + if (shouldPatchInlineTypeGuard() || shouldPatchUnconditionalClaspGuard()) { + Repatcher repatcher(cx->fp()->jit()); + + if (shouldPatchInlineTypeGuard()) { + // A type guard is present in the inline path, and this is the + // first string stub, so patch it now. + JS_ASSERT(!inlineTypeGuardPatched); + JS_ASSERT(atomTypeGuard.isSet()); + + repatcher.relink(fastPathStart.jumpAtOffset(inlineTypeGuard), cs); + inlineTypeGuardPatched = true; + } + + if (shouldPatchUnconditionalClaspGuard()) { + // The clasp guard is unconditional, meaning there is no type + // check. This is the first stub, so it has to be patched. Note + // that it is wrong to patch the inline clasp guard otherwise, + // because it follows an integer-id guard. + JS_ASSERT(!hasInlineTypeGuard()); + + repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs); + inlineClaspGuardPatched = true; + } + } + + // If there were previous stub guards, patch them now. + if (hasLastStringStub) { + Repatcher repatcher(lastStringStub); + CodeLocationLabel stub(lastStringStub.start()); + if (atomGuard) + repatcher.relink(stub.jumpAtOffset(atomGuard), cs); + repatcher.relink(stub.jumpAtOffset(firstShapeGuard), cs); + if (secondShapeGuard) + repatcher.relink(stub.jumpAtOffset(secondShapeGuard), cs); + } + + // Update state. + hasLastStringStub = true; + lastStringStub = JITCode(cs.executableAddress(), buffer.size()); + if (atomIdGuard.isSet()) { + atomGuard = buffer.locationOf(atomIdGuard.get()) - cs; + JS_ASSERT(atomGuard == buffer.locationOf(atomIdGuard.get()) - cs); + JS_ASSERT(atomGuard); + } else { + atomGuard = 0; + } + if (protoGuard.isSet()) { + secondShapeGuard = buffer.locationOf(protoGuard.get()) - cs; + JS_ASSERT(secondShapeGuard == buffer.locationOf(protoGuard.get()) - cs); + JS_ASSERT(secondShapeGuard); + } else { + secondShapeGuard = 0; + } + firstShapeGuard = buffer.locationOf(shapeGuard) - cs; + JS_ASSERT(firstShapeGuard == buffer.locationOf(shapeGuard) - cs); + JS_ASSERT(firstShapeGuard); + + stubsGenerated++; + + if (stubsGenerated == MAX_GETELEM_IC_STUBS) + disable(cx, "max stubs reached"); + + // Finally, fetch the value to avoid redoing the property lookup. + if (shape->isMethod()) + *vp = ObjectValue(shape->methodObject()); + else + *vp = holder->getSlot(shape->slot); + + return Lookup_Cacheable; +} + +#if defined JS_POLYIC_TYPED_ARRAY +LookupStatus +GetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, const Value &v, jsid id, Value *vp) +{ + if (!v.isInt32()) + return disable(cx, "typed array with string key"); + + if (op == JSOP_CALLELEM) + return disable(cx, "typed array with call"); + + // The fast-path guarantees that after the dense clasp guard, the type is + // known to be int32, either via type inference or the inline type check. + JS_ASSERT(hasInlineTypeGuard() || idRemat.knownType() == JSVAL_TYPE_INT32); + + Assembler masm; + + // Guard on this typed array's clasp. + Jump claspGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass()); + + // Get the internal typed array. + masm.loadPtr(Address(objReg, offsetof(JSObject, privateData)), objReg); + + // Bounds check. + Jump outOfBounds; + Address typedArrayLength(objReg, js::TypedArray::lengthOffset()); + if (idRemat.isConstant()) { + JS_ASSERT(idRemat.value().toInt32() == v.toInt32()); + outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, Imm32(v.toInt32())); + } else { + outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, idRemat.dataReg()); + } + + // Load the array's packed data vector. + masm.loadPtr(Address(objReg, js::TypedArray::dataOffset()), objReg); + + js::TypedArray *tarray = js::TypedArray::fromJSObject(obj); + int shift = tarray->slotWidth(); + if (idRemat.isConstant()) { + int32 index = v.toInt32(); + Address addr(objReg, index * shift); + LoadFromTypedArray(masm, tarray, addr, typeReg, objReg); + } else { + Assembler::Scale scale = Assembler::TimesOne; + switch (shift) { + case 2: + scale = Assembler::TimesTwo; + break; + case 4: + scale = Assembler::TimesFour; + break; + case 8: + scale = Assembler::TimesEight; + break; + } + BaseIndex addr(objReg, idRemat.dataReg(), scale); + LoadFromTypedArray(masm, tarray, addr, typeReg, objReg); + } + + Jump done1 = masm.jump(); + + outOfBounds.linkTo(masm.label(), &masm); + masm.loadValueAsComponents(UndefinedValue(), typeReg, objReg); + + Jump done2 = masm.jump(); + + PICLinker buffer(masm, *this); + if (!buffer.init(cx)) + return error(cx); + + if (!buffer.verifyRange(cx->fp()->jit())) + return disable(cx, "code memory is out of range"); + + buffer.link(claspGuard, slowPathStart); + buffer.link(done1, fastPathRejoin); + buffer.link(done2, fastPathRejoin); + + CodeLocationLabel cs = buffer.finalizeCodeAddendum(); + JaegerSpew(JSpew_PICs, "generated getelem typed array stub at %p\n", cs.executableAddress()); + + // If we can generate a typed array stub, the clasp guard is conditional. + // Also, we only support one typed array. + JS_ASSERT(!shouldPatchUnconditionalClaspGuard()); + JS_ASSERT(!inlineClaspGuardPatched); + + Repatcher repatcher(cx->fp()->jit()); + repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs); + inlineClaspGuardPatched = true; + + stubsGenerated++; + + // In the future, it might make sense to attach multiple typed array stubs. + // For simplicitly, they are currently monomorphic. + if (stubsGenerated == MAX_GETELEM_IC_STUBS) + disable(cx, "max stubs reached"); + + disable(cx, "generated typed array stub"); + + // Fetch the value as expected of Lookup_Cacheable for GetElement. + if (!obj->getProperty(cx, id, vp)) + return Lookup_Error; + + return Lookup_Cacheable; +} +#endif /* JS_POLYIC_TYPED_ARRAY */ + +LookupStatus +GetElementIC::update(JSContext *cx, JSObject *obj, const Value &v, jsid id, Value *vp) +{ + if (v.isString()) + return attachGetProp(cx, obj, v, id, vp); + +#if defined JS_POLYIC_TYPED_ARRAY + if (js_IsTypedArray(obj)) + return attachTypedArray(cx, obj, v, id, vp); +#endif + + return disable(cx, "unhandled object and key type"); +} + +void JS_FASTCALL +ic::CallElement(VMFrame &f, ic::GetElementIC *ic) +{ + JSContext *cx = f.cx; + + // Right now, we don't optimize for strings. + if (!f.regs.sp[-2].isObject()) { + ic->disable(cx, "non-object"); + stubs::CallElem(f); + return; + } + + Value thisv = f.regs.sp[-2]; + JSObject *thisObj = ValuePropertyBearer(cx, thisv, -2); + if (!thisObj) + THROW(); + + jsid id; + Value idval = f.regs.sp[-1]; + if (idval.isInt32() && INT_FITS_IN_JSID(idval.toInt32())) + id = INT_TO_JSID(idval.toInt32()); + else if (!js_InternNonIntElementId(cx, thisObj, idval, &id)) + THROW(); + + if (ic->shouldUpdate(cx)) { +#ifdef DEBUG + f.regs.sp[-2] = MagicValue(JS_GENERIC_MAGIC); +#endif + LookupStatus status = ic->update(cx, thisObj, idval, id, &f.regs.sp[-2]); + if (status != Lookup_Uncacheable) { + if (status == Lookup_Error) + THROW(); + + // If the result can be cached, the value was already retrieved. + JS_ASSERT(!f.regs.sp[-2].isMagic()); + f.regs.sp[-1].setObject(*thisObj); + return; + } + } + + /* Get or set the element. */ + if (!js_GetMethod(cx, thisObj, id, JSGET_NO_METHOD_BARRIER, &f.regs.sp[-2])) + THROW(); + +#if JS_HAS_NO_SUCH_METHOD + if (JS_UNLIKELY(f.regs.sp[-2].isUndefined()) && thisv.isObject()) { + f.regs.sp[-2] = f.regs.sp[-1]; + f.regs.sp[-1].setObject(*thisObj); + if (!js_OnUnknownMethod(cx, f.regs.sp - 2)) + THROW(); + } else +#endif + { + f.regs.sp[-1] = thisv; + } +} + +void JS_FASTCALL +ic::GetElement(VMFrame &f, ic::GetElementIC *ic) +{ + JSContext *cx = f.cx; + + // Right now, we don't optimize for strings. + if (!f.regs.sp[-2].isObject()) { + ic->disable(cx, "non-object"); + stubs::GetElem(f); + return; + } + + JSObject *obj = ValueToObject(cx, &f.regs.sp[-2]); + if (!obj) + THROW(); + + Value idval = f.regs.sp[-1]; + + jsid id; + if (idval.isInt32() && INT_FITS_IN_JSID(idval.toInt32())) { + id = INT_TO_JSID(idval.toInt32()); + } else { + if (!js_InternNonIntElementId(cx, obj, idval, &id)) + THROW(); + } + + if (ic->shouldUpdate(cx)) { +#ifdef DEBUG + f.regs.sp[-2] = MagicValue(JS_GENERIC_MAGIC); +#endif + LookupStatus status = ic->update(cx, obj, idval, id, &f.regs.sp[-2]); + if (status != Lookup_Uncacheable) { + if (status == Lookup_Error) + THROW(); + + // If the result can be cached, the value was already retrieved. + JS_ASSERT(!f.regs.sp[-2].isMagic()); + return; + } + } + + if (!obj->getProperty(cx, id, &f.regs.sp[-2])) + THROW(); +} + +#define APPLY_STRICTNESS(f, s) \ + (FunctionTemplateConditional(s, f, f)) + +LookupStatus +SetElementIC::disable(JSContext *cx, const char *reason) +{ + slowCallPatched = true; + VoidStub stub = APPLY_STRICTNESS(stubs::SetElem, strictMode); + BaseIC::disable(cx, reason, JS_FUNC_TO_DATA_PTR(void *, stub)); + return Lookup_Uncacheable; +} + +LookupStatus +SetElementIC::error(JSContext *cx) +{ + disable(cx, "error"); + return Lookup_Error; +} + +void +SetElementIC::purge(Repatcher &repatcher) +{ + // Repatch the inline jumps. + if (inlineClaspGuardPatched) + repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), slowPathStart); + if (inlineHoleGuardPatched) + repatcher.relink(fastPathStart.jumpAtOffset(inlineHoleGuard), slowPathStart); + + if (slowCallPatched) { + void *stub = JS_FUNC_TO_DATA_PTR(void *, APPLY_STRICTNESS(ic::SetElement, strictMode)); + repatcher.relink(slowPathCall, FunctionPtr(stub)); + } + + reset(); +} + +LookupStatus +SetElementIC::attachHoleStub(JSContext *cx, JSObject *obj, int32 keyval) +{ + if (keyval < 0) + return disable(cx, "negative key index"); + + // We may have failed a capacity check instead of a dense array check. + // However we should still build the IC in this case, since it could + // be in a loop that is filling in the array. We can assert, however, + // that either we're in capacity or there's a hole - guaranteed by + // the fast path. + JS_ASSERT((jsuint)keyval >= obj->getDenseArrayCapacity() || + obj->getDenseArrayElement(keyval).isMagic(JS_ARRAY_HOLE)); + + if (js_PrototypeHasIndexedProperties(cx, obj)) + return disable(cx, "prototype has indexed properties"); + + Assembler masm; + + Vector fails(cx); + + // Test for indexed properties in Array.prototype. We test each shape + // along the proto chain. This affords us two optimizations: + // 1) Loading the prototype can be avoided because the shape would change; + // instead we can bake in their identities. + // 2) We only have to test the shape, rather than INDEXED. + for (JSObject *pobj = obj->getProto(); pobj; pobj = pobj->getProto()) { + if (!pobj->isNative()) + return disable(cx, "non-native array prototype"); + masm.move(ImmPtr(pobj), objReg); + Jump j = masm.guardShape(objReg, pobj); + if (!fails.append(j)) + return error(cx); + } + + // Restore |obj|. + masm.rematPayload(StateRemat::FromInt32(objRemat), objReg); + + // Guard against negative indices. + MaybeJump keyGuard; + if (!hasConstantKey) + keyGuard = masm.branch32(Assembler::LessThan, keyReg, Imm32(0)); + + // Update the array length if necessary. + Jump skipUpdate; + Address arrayLength(objReg, offsetof(JSObject, privateData)); + if (hasConstantKey) { + skipUpdate = masm.branch32(Assembler::Above, arrayLength, Imm32(keyValue)); + masm.store32(Imm32(keyValue + 1), arrayLength); + } else { + skipUpdate = masm.branch32(Assembler::Above, arrayLength, keyReg); + masm.add32(Imm32(1), keyReg); + masm.store32(keyReg, arrayLength); + masm.sub32(Imm32(1), keyReg); + } + skipUpdate.linkTo(masm.label(), &masm); + + // Store the value back. + masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg); + if (hasConstantKey) { + Address slot(objReg, keyValue * sizeof(Value)); + masm.storeValue(vr, slot); + } else { + BaseIndex slot(objReg, keyReg, Assembler::JSVAL_SCALE); + masm.storeValue(vr, slot); + } + + Jump done = masm.jump(); + + JS_ASSERT(!execPool); + JS_ASSERT(!inlineHoleGuardPatched); + + LinkerHelper buffer(masm); + execPool = buffer.init(cx); + if (!execPool) + return error(cx); + + if (!buffer.verifyRange(cx->fp()->jit())) + return disable(cx, "code memory is out of range"); + + // Patch all guards. + for (size_t i = 0; i < fails.length(); i++) + buffer.link(fails[i], slowPathStart); + buffer.link(done, fastPathRejoin); + + CodeLocationLabel cs = buffer.finalize(); + JaegerSpew(JSpew_PICs, "generated dense array hole stub at %p\n", cs.executableAddress()); + + Repatcher repatcher(cx->fp()->jit()); + repatcher.relink(fastPathStart.jumpAtOffset(inlineHoleGuard), cs); + inlineHoleGuardPatched = true; + + disable(cx, "generated dense array hole stub"); + + return Lookup_Cacheable; +} + +#if defined JS_POLYIC_TYPED_ARRAY +LookupStatus +SetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, int32 key) +{ + // Right now, only one clasp guard extension is supported. + JS_ASSERT(!inlineClaspGuardPatched); + + Assembler masm; + + // Guard on this typed array's clasp. + Jump claspGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass()); + + // Get the internal typed array. + masm.loadPtr(Address(objReg, offsetof(JSObject, privateData)), objReg); + + // Bounds check. + Jump outOfBounds; + Address typedArrayLength(objReg, js::TypedArray::lengthOffset()); + if (hasConstantKey) + outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, Imm32(keyValue)); + else + outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, keyReg); + + // Load the array's packed data vector. + js::TypedArray *tarray = js::TypedArray::fromJSObject(obj); + masm.loadPtr(Address(objReg, js::TypedArray::dataOffset()), objReg); + + int shift = tarray->slotWidth(); + if (hasConstantKey) { + Address addr(objReg, keyValue * shift); + if (!StoreToTypedArray(cx, masm, tarray, addr, vr, volatileMask)) + return error(cx); + } else { + Assembler::Scale scale = Assembler::TimesOne; + switch (shift) { + case 2: + scale = Assembler::TimesTwo; + break; + case 4: + scale = Assembler::TimesFour; + break; + case 8: + scale = Assembler::TimesEight; + break; + } + BaseIndex addr(objReg, keyReg, scale); + if (!StoreToTypedArray(cx, masm, tarray, addr, vr, volatileMask)) + return error(cx); + } + + Jump done = masm.jump(); + + // The stub does not rely on any pointers or numbers that could be ruined + // by a GC or shape regenerated GC. We let this stub live for the lifetime + // of the script. + JS_ASSERT(!execPool); + LinkerHelper buffer(masm); + execPool = buffer.init(cx); + if (!execPool) + return error(cx); + + if (!buffer.verifyRange(cx->fp()->jit())) + return disable(cx, "code memory is out of range"); + + // Note that the out-of-bounds path simply does nothing. + buffer.link(claspGuard, slowPathStart); + buffer.link(outOfBounds, fastPathRejoin); + buffer.link(done, fastPathRejoin); + masm.finalize(buffer); + + CodeLocationLabel cs = buffer.finalizeCodeAddendum(); + JaegerSpew(JSpew_PICs, "generated setelem typed array stub at %p\n", cs.executableAddress()); + + Repatcher repatcher(cx->fp()->jit()); + repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs); + inlineClaspGuardPatched = true; + + stubsGenerated++; + + // In the future, it might make sense to attach multiple typed array stubs. + // For simplicitly, they are currently monomorphic. + if (stubsGenerated == MAX_GETELEM_IC_STUBS) + disable(cx, "max stubs reached"); + + disable(cx, "generated typed array stub"); + + return Lookup_Cacheable; +} +#endif /* JS_POLYIC_TYPED_ARRAY */ + +LookupStatus +SetElementIC::update(JSContext *cx, const Value &objval, const Value &idval) +{ + if (!objval.isObject()) + return disable(cx, "primitive lval"); + if (!idval.isInt32()) + return disable(cx, "non-int32 key"); + + JSObject *obj = &objval.toObject(); + int32 key = idval.toInt32(); + + if (obj->isDenseArray()) + return attachHoleStub(cx, obj, key); + +#if defined JS_POLYIC_TYPED_ARRAY + if (js_IsTypedArray(obj)) + return attachTypedArray(cx, obj, key); +#endif + + return disable(cx, "unsupported object type"); +} + +template +void JS_FASTCALL +ic::SetElement(VMFrame &f, ic::SetElementIC *ic) +{ + JSContext *cx = f.cx; + + if (ic->shouldUpdate(cx)) { + LookupStatus status = ic->update(cx, f.regs.sp[-3], f.regs.sp[-2]); + if (status == Lookup_Error) + THROW(); + } + + stubs::SetElem(f); +} + +template void JS_FASTCALL ic::SetElement(VMFrame &f, SetElementIC *ic); +template void JS_FASTCALL ic::SetElement(VMFrame &f, SetElementIC *ic); + +void +JITScript::purgePICs() +{ + if (!nPICs && !nGetElems && !nSetElems) + return; + + Repatcher repatcher(this); + + ic::PICInfo *pics_ = pics(); + for (uint32 i = 0; i < nPICs; i++) { + ic::PICInfo &pic = pics_[i]; + switch (pic.kind) { + case ic::PICInfo::SET: + case ic::PICInfo::SETMETHOD: + SetPropCompiler::reset(repatcher, pic); + break; + case ic::PICInfo::NAME: + case ic::PICInfo::XNAME: + ScopeNameCompiler::reset(repatcher, pic); + break; + case ic::PICInfo::BIND: + BindNameCompiler::reset(repatcher, pic); + break; + case ic::PICInfo::CALL: /* fall-through */ + case ic::PICInfo::GET: + GetPropCompiler::reset(repatcher, pic); + break; + default: + JS_NOT_REACHED("Unhandled PIC kind"); + break; + } + pic.reset(); + } + + ic::GetElementIC *getElems_ = getElems(); + ic::SetElementIC *setElems_ = setElems(); + for (uint32 i = 0; i < nGetElems; i++) + getElems_[i].purge(repatcher); + for (uint32 i = 0; i < nSetElems; i++) + setElems_[i].purge(repatcher); +} + +void +ic::PurgePICs(JSContext *cx, JSScript *script) +{ + if (script->jitNormal) + script->jitNormal->purgePICs(); + if (script->jitCtor) + script->jitCtor->purgePICs(); +} + +#endif /* JS_POLYIC */ + diff --git a/js/src/methodjit/PolyIC.h b/js/src/methodjit/PolyIC.h new file mode 100644 index 0000000..14e53e3 --- /dev/null +++ b/js/src/methodjit/PolyIC.h @@ -0,0 +1,561 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_poly_ic_h__ && defined JS_METHODJIT +#define jsjaeger_poly_ic_h__ + +#include "jscntxt.h" +#include "jstl.h" +#include "jsvector.h" +#include "assembler/assembler/MacroAssembler.h" +#include "assembler/assembler/CodeLocation.h" +#include "methodjit/MethodJIT.h" +#include "methodjit/ICRepatcher.h" +#include "BaseAssembler.h" +#include "RematInfo.h" +#include "BaseCompiler.h" +#include "methodjit/ICLabels.h" +#include "assembler/moco/MocoStubs.h" + +namespace js { +namespace mjit { +namespace ic { + +/* Maximum number of stubs for a given callsite. */ +static const uint32 MAX_PIC_STUBS = 16; +static const uint32 MAX_GETELEM_IC_STUBS = 17; + +void PurgePICs(JSContext *cx); + +enum LookupStatus { + Lookup_Error = 0, + Lookup_Uncacheable, + Lookup_Cacheable +}; + +struct BaseIC : public MacroAssemblerTypedefs { + BaseIC() { } + + // Address of inline fast-path. + CodeLocationLabel fastPathStart; + + // Address to rejoin to the fast-path. + CodeLocationLabel fastPathRejoin; + + // Start of the slow path. + CodeLocationLabel slowPathStart; + + // Slow path stub call. + CodeLocationCall slowPathCall; + + // Whether or not the callsite has been hit at least once. + bool hit : 1; + bool slowCallPatched : 1; + + // Number of stubs generated. + uint32 stubsGenerated : 5; + + // Offset from start of stub to jump target of second shape guard as Nitro + // asm data location. This is 0 if there is only one shape guard in the + // last stub. + int secondShapeGuard : 11; + + // Opcode this was compiled for. + JSOp op : 9; + + void reset() { + hit = false; + slowCallPatched = false; + stubsGenerated = 0; + secondShapeGuard = 0; + } + bool shouldUpdate(JSContext *cx); + void spew(JSContext *cx, const char *event, const char *reason); + LookupStatus disable(JSContext *cx, const char *reason, void *stub); + bool isCallOp(); +}; + +class BasePolyIC : public BaseIC { + typedef Vector ExecPoolVector; + + // ExecutablePools that IC stubs were generated into. Very commonly (eg. + // 99.5% of BasePolyICs) there are 0 or 1, and there are lots of + // BasePolyICs, so we space-optimize for that case. If the bottom bit of + // the pointer is 0, execPool should be used, and it will be NULL (for 0 + // pools) or non-NULL (for 1 pool). If the bottom bit of the + // pointer is 1, taggedExecPools should be used, but only after de-tagging + // (for 2 or more pools). + union { + JSC::ExecutablePool *execPool; // valid when bottom bit is a 0 + ExecPoolVector *taggedExecPools; // valid when bottom bit is a 1 + } u; + + static bool isTagged(void *p) { + return !!(intptr_t(p) & 1); + } + + static ExecPoolVector *tag(ExecPoolVector *p) { + JS_ASSERT(!isTagged(p)); + return (ExecPoolVector *)(intptr_t(p) | 1); + } + + static ExecPoolVector *detag(ExecPoolVector *p) { + JS_ASSERT(isTagged(p)); + return (ExecPoolVector *)(intptr_t(p) & ~1); + } + + bool areZeroPools() { return !u.execPool; } + bool isOnePool() { return u.execPool && !isTagged(u.execPool); } + bool areMultiplePools() { return isTagged(u.taggedExecPools); } + + ExecPoolVector *multiplePools() { + JS_ASSERT(areMultiplePools()); + return detag(u.taggedExecPools); + } + + public: + BasePolyIC() { + u.execPool = NULL; + } + + ~BasePolyIC() { + releasePools(); + if (areMultiplePools()) + js_delete(multiplePools()); + } + + void reset() { + BaseIC::reset(); + releasePools(); + if (areZeroPools()) { + // Common case: do nothing. + } else if (isOnePool()) { + u.execPool = NULL; + } else { + multiplePools()->clear(); + } + } + + void releasePools() { + if (areZeroPools()) { + // Common case: do nothing. + } else if (isOnePool()) { + u.execPool->release(); + } else { + ExecPoolVector *execPools = multiplePools(); + for (size_t i = 0; i < execPools->length(); i++) + (*execPools)[i]->release(); + } + } + + bool addPool(JSContext *cx, JSC::ExecutablePool *pool) { + if (areZeroPools()) { + u.execPool = pool; + return true; + } + if (isOnePool()) { + JSC::ExecutablePool *oldPool = u.execPool; + JS_ASSERT(!isTagged(oldPool)); + ExecPoolVector *execPools = js_new(SystemAllocPolicy()); + if (!execPools) + return false; + if (!execPools->append(oldPool) || !execPools->append(pool)) { + js_delete(execPools); + return false; + } + u.taggedExecPools = tag(execPools); + return true; + } + return multiplePools()->append(pool); + } +}; + +struct GetElementIC : public BasePolyIC { + GetElementIC() { reset(); } + + // On stub entry: + // If hasInlineTypeCheck() is true, and inlineTypeCheckPatched is false, + // - typeReg contains the type of the |id| parameter. + // If hasInlineTypeCheck() is true, and inlineTypeCheckPatched is true, + // - typeReg contains the shape of |objReg| iff typeRegHasBaseShape + // is true. + // Otherwise, typeReg is garbage. + // + // On stub exit, typeReg must contain the type of the result value. + RegisterID typeReg : 5; + + // On stub entry, objReg contains the object pointer for the |obj| parameter. + // On stub exit, objReg must contain the payload of the result value. + RegisterID objReg : 5; + + // Offset from the fast path to the inline type check. + // This is only set if hasInlineTypeCheck() is true. + unsigned inlineTypeGuard : 8; + + // Offset from the fast path to the inline clasp guard. This is always + // set; if |id| is known to not be int32, then it's an unconditional + // jump to the slow path. + unsigned inlineClaspGuard : 8; + + // This is usable if hasInlineTypeGuard() returns true, which implies + // that a dense array fast path exists. The inline type guard serves as + // the head of the chain of all string-based element stubs. + bool inlineTypeGuardPatched : 1; + + // This is always usable, and specifies whether the inline clasp guard + // has been patched. If hasInlineTypeGuard() is true, it guards against + // a dense array, and guarantees the inline type guard has passed. + // Otherwise, there is no inline type guard, and the clasp guard is just + // an unconditional jump. + bool inlineClaspGuardPatched : 1; + + //////////////////////////////////////////// + // State for string-based property stubs. // + //////////////////////////////////////////// + + // True if typeReg is guaranteed to have the shape of objReg. + bool typeRegHasBaseShape : 1; + + // These offsets are used for string-key dependent stubs, such as named + // property accesses. They are separated from the int-key dependent stubs, + // in order to guarantee that the id type needs only one guard per type. + int atomGuard : 8; // optional, non-zero if present + int firstShapeGuard : 8; // always set + int secondShapeGuard : 8; // optional, non-zero if present + + bool hasLastStringStub : 1; + JITCode lastStringStub; + + // A limited ValueRemat instance. It may contains either: + // 1) A constant, or + // 2) A known type and data reg, or + // 3) A data reg. + // The sync bits are not set, and the type reg is never set and should not + // be used, as it is encapsulated more accurately in |typeReg|. Also, note + // carefully that the data reg is immutable. + ValueRemat idRemat; + + bool hasInlineTypeGuard() const { + return !idRemat.isTypeKnown(); + } + bool shouldPatchInlineTypeGuard() { + return hasInlineTypeGuard() && !inlineTypeGuardPatched; + } + bool shouldPatchUnconditionalClaspGuard() { + // The clasp guard is only unconditional if the type is known to not + // be an int32. + if (idRemat.isTypeKnown() && idRemat.knownType() != JSVAL_TYPE_INT32) + return !inlineClaspGuardPatched; + return false; + } + + void reset() { + BasePolyIC::reset(); + inlineTypeGuardPatched = false; + inlineClaspGuardPatched = false; + typeRegHasBaseShape = false; + hasLastStringStub = false; + } + void purge(Repatcher &repatcher); + LookupStatus update(JSContext *cx, JSObject *obj, const Value &v, jsid id, Value *vp); + LookupStatus attachGetProp(JSContext *cx, JSObject *obj, const Value &v, jsid id, + Value *vp); + LookupStatus attachTypedArray(JSContext *cx, JSObject *obj, const Value &v, jsid id, + Value *vp); + LookupStatus disable(JSContext *cx, const char *reason); + LookupStatus error(JSContext *cx); + bool shouldUpdate(JSContext *cx); +}; + +struct SetElementIC : public BaseIC { + SetElementIC() : execPool(NULL) { reset(); } + ~SetElementIC() { + if (execPool) + execPool->release(); + } + + // On stub entry: + // objReg contains the payload of the |obj| parameter. + // On stub exit: + // objReg may be clobbered. + RegisterID objReg : 5; + + // Information on how to rematerialize |objReg|. + int32 objRemat : MIN_STATE_REMAT_BITS; + + // Offset from the start of the fast path to the inline clasp guard. + unsigned inlineClaspGuard : 6; + + // True if the clasp guard has been patched; false otherwise. + bool inlineClaspGuardPatched : 1; + + // Offset from the start of the fast path to the inline hole guard. + unsigned inlineHoleGuard : 8; + + // True if the capacity guard has been patched; false otherwise. + bool inlineHoleGuardPatched : 1; + + // True if this is from a strict-mode script. + bool strictMode : 1; + + // A bitmask of registers that are volatile and must be preserved across + // stub calls inside the IC. + uint32 volatileMask : 16; + + // If true, then keyValue contains a constant index value >= 0. Otherwise, + // keyReg contains a dynamic integer index in any range. + bool hasConstantKey : 1; + union { + RegisterID keyReg; + int32 keyValue; + }; + + // Rematerialize information about the value being stored. + ValueRemat vr; + + // Optional executable pool for the out-of-line hole stub. + JSC::ExecutablePool *execPool; + + void reset() { + BaseIC::reset(); + if (execPool != NULL) + execPool->release(); + execPool = NULL; + inlineClaspGuardPatched = false; + inlineHoleGuardPatched = false; + } + void purge(Repatcher &repatcher); + LookupStatus attachTypedArray(JSContext *cx, JSObject *obj, int32 key); + LookupStatus attachHoleStub(JSContext *cx, JSObject *obj, int32 key); + LookupStatus update(JSContext *cx, const Value &objval, const Value &idval); + LookupStatus disable(JSContext *cx, const char *reason); + LookupStatus error(JSContext *cx); +}; + +struct PICInfo : public BasePolyIC { + PICInfo() { reset(); } + + // Operation this is a PIC for. + enum Kind +#ifdef _MSC_VER + : uint8_t +#endif + { + GET, // JSOP_GETPROP + CALL, // JSOP_CALLPROP + SET, // JSOP_SETPROP, JSOP_SETNAME + SETMETHOD, // JSOP_SETMETHOD + NAME, // JSOP_NAME + BIND, // JSOP_BINDNAME + XNAME // JSOP_GETXPROP + }; + + union { + struct { + RegisterID typeReg : 5; // reg used for checking type + bool hasTypeCheck : 1; // type check and reg are present + + // Reverse offset from slowPathStart to the type check slow path. + int32 typeCheckOffset; + } get; + ValueRemat vr; + } u; + + // Address of the start of the last generated stub, if any. Note that this + // does not correctly overlay with the allocated memory; it does however + // overlay the portion that may need to be patched, which is good enough. + JITCode lastStubStart; + + // Return the start address of the last path in this PIC, which is the + // inline path if no stubs have been generated yet. + CodeLocationLabel lastPathStart() { + if (!stubsGenerated) + return fastPathStart; + return CodeLocationLabel(lastStubStart.start()); + } + + CodeLocationLabel getFastShapeGuard() { + return fastPathStart.labelAtOffset(shapeGuard); + } + + CodeLocationLabel getSlowTypeCheck() { + JS_ASSERT(isGet()); + return slowPathStart.labelAtOffset(u.get.typeCheckOffset); + } + + // Return a JITCode block corresponding to the code memory to attach a + // new stub to. + JITCode lastCodeBlock(JITScript *jit) { + if (!stubsGenerated) + return JITCode(jit->code.m_code.executableAddress(), jit->code.m_size); + return lastStubStart; + } + + void updateLastPath(LinkerHelper &linker, Label label) { + CodeLocationLabel loc = linker.locationOf(label); + lastStubStart = JITCode(loc.executableAddress(), linker.size()); + } + + Kind kind : 3; + + // True if register R holds the base object shape along exits from the + // last stub. + bool shapeRegHasBaseShape : 1; + + // True if can use the property cache. + bool usePropCache : 1; + + // State flags. + bool inlinePathPatched : 1; // inline path has been patched + + RegisterID shapeReg : 5; // also the out type reg + RegisterID objReg : 5; // also the out data reg + + // Offset from start of fast path to initial shape guard. + uint32 shapeGuard; + + inline bool isSet() const { + return kind == SET || kind == SETMETHOD; + } + inline bool isGet() const { + return kind == GET || kind == CALL; + } + inline bool isBind() const { + return kind == BIND; + } + inline bool isScopeName() const { + return kind == NAME || kind == XNAME; + } + inline RegisterID typeReg() { + JS_ASSERT(isGet()); + return u.get.typeReg; + } + inline bool hasTypeCheck() { + JS_ASSERT(isGet()); + return u.get.hasTypeCheck; + } + inline bool shapeNeedsRemat() { + return !shapeRegHasBaseShape; + } + inline bool isFastCall() { + JS_ASSERT(kind == CALL); + return !hasTypeCheck(); + } + +#if !defined JS_HAS_IC_LABELS + static GetPropLabels getPropLabels_; + static SetPropLabels setPropLabels_; + static BindNameLabels bindNameLabels_; + static ScopeNameLabels scopeNameLabels_; +#else + union { + GetPropLabels getPropLabels_; + SetPropLabels setPropLabels_; + BindNameLabels bindNameLabels_; + ScopeNameLabels scopeNameLabels_; + }; + void setLabels(const ic::GetPropLabels &labels) { + JS_ASSERT(isGet()); + getPropLabels_ = labels; + } + void setLabels(const ic::SetPropLabels &labels) { + JS_ASSERT(isSet()); + setPropLabels_ = labels; + } + void setLabels(const ic::BindNameLabels &labels) { + JS_ASSERT(kind == BIND); + bindNameLabels_ = labels; + } + void setLabels(const ic::ScopeNameLabels &labels) { + JS_ASSERT(kind == NAME || kind == XNAME); + scopeNameLabels_ = labels; + } +#endif + + GetPropLabels &getPropLabels() { + JS_ASSERT(isGet()); + return getPropLabels_; + } + SetPropLabels &setPropLabels() { + JS_ASSERT(isSet()); + return setPropLabels_; + } + BindNameLabels &bindNameLabels() { + JS_ASSERT(kind == BIND); + return bindNameLabels_; + } + ScopeNameLabels &scopeNameLabels() { + JS_ASSERT(kind == NAME || kind == XNAME); + return scopeNameLabels_; + } + + // Where in the script did we generate this PIC? + jsbytecode *pc; + + // Index into the script's atom table. + JSAtom *atom; + + // Reset the data members to the state of a fresh PIC before any patching + // or stub generation was done. + void reset() { + BasePolyIC::reset(); + inlinePathPatched = false; + shapeRegHasBaseShape = true; + } +}; + +#ifdef JS_POLYIC +void PurgePICs(JSContext *cx, JSScript *script); +void JS_FASTCALL GetProp(VMFrame &f, ic::PICInfo *); +void JS_FASTCALL SetProp(VMFrame &f, ic::PICInfo *); +void JS_FASTCALL CallProp(VMFrame &f, ic::PICInfo *); +void JS_FASTCALL Name(VMFrame &f, ic::PICInfo *); +void JS_FASTCALL XName(VMFrame &f, ic::PICInfo *); +void JS_FASTCALL BindName(VMFrame &f, ic::PICInfo *); +void JS_FASTCALL GetElement(VMFrame &f, ic::GetElementIC *); +void JS_FASTCALL CallElement(VMFrame &f, ic::GetElementIC *); +template void JS_FASTCALL SetElement(VMFrame &f, ic::SetElementIC *); +#endif + +} /* namespace ic */ +} /* namespace mjit */ +} /* namespace js */ + +#endif /* jsjaeger_poly_ic_h__ */ + diff --git a/js/src/methodjit/PunboxAssembler.h b/js/src/methodjit/PunboxAssembler.h new file mode 100644 index 0000000..5c6da27 --- /dev/null +++ b/js/src/methodjit/PunboxAssembler.h @@ -0,0 +1,399 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * Sean Stangl + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_assembler64_h__ && defined JS_METHODJIT && defined JS_PUNBOX64 +#define jsjaeger_assembler64_h__ + +#include "assembler/assembler/MacroAssembler.h" +#include "methodjit/MachineRegs.h" +#include "methodjit/RematInfo.h" +#include "jsnum.h" + +namespace js { +namespace mjit { + +struct Imm64 : JSC::MacroAssembler::ImmPtr +{ + Imm64(uint64 u) + : ImmPtr((const void *)u) + { } +}; + +/* Tag stored in shifted format. */ +struct ImmTag : JSC::MacroAssembler::ImmPtr +{ + ImmTag(JSValueShiftedTag shtag) + : ImmPtr((const void *)shtag) + { } +}; + +struct ImmType : ImmTag +{ + ImmType(JSValueType type) + : ImmTag(JSValueShiftedTag(JSVAL_TYPE_TO_SHIFTED_TAG(type))) + { } +}; + +struct ImmPayload : Imm64 +{ + ImmPayload(uint64 payload) + : Imm64(payload) + { } +}; + +class PunboxAssembler : public JSC::MacroAssembler +{ + static const uint32 PAYLOAD_OFFSET = 0; + + public: + static const JSC::MacroAssembler::Scale JSVAL_SCALE = JSC::MacroAssembler::TimesEight; + + template + T payloadOf(T address) { + return address; + } + + template + T valueOf(T address) { + return address; + } + + void loadInlineSlot(RegisterID objReg, uint32 slot, + RegisterID typeReg, RegisterID dataReg) { + Address address(objReg, JSObject::getFixedSlotOffset(slot)); + loadValueAsComponents(address, typeReg, dataReg); + } + + template + void loadValue(T address, RegisterID dst) { + loadPtr(address, dst); + } + + void convertValueToType(RegisterID val) { + andPtr(Registers::TypeMaskReg, val); + } + + void convertValueToPayload(RegisterID val) { + andPtr(Registers::PayloadMaskReg, val); + } + + // Returns a label after the one Value load. + template + Label loadValueAsComponents(T address, RegisterID type, RegisterID payload) { + loadValue(address, type); + Label l = label(); + + move(Registers::PayloadMaskReg, payload); + andPtr(type, payload); + xorPtr(payload, type); + + return l; + } + + void loadValueAsComponents(const Value &val, RegisterID type, RegisterID payload) { + move(Imm64(val.asRawBits() & JSVAL_TAG_MASK), type); + move(Imm64(val.asRawBits() & JSVAL_PAYLOAD_MASK), payload); + } + + /* + * Load a (64b) js::Value from 'address' into 'type' and 'payload', and + * return a label which can be used by + * Repatcher::patchAddressOffsetForValue to patch the address offset. + */ + Label loadValueWithAddressOffsetPatch(Address address, RegisterID type, RegisterID payload) { + return loadValueAsComponents(address, type, payload); + } + + template + void storeValueFromComponents(RegisterID type, RegisterID payload, T address) { + move(type, Registers::ValueReg); + orPtr(payload, Registers::ValueReg); + storeValue(Registers::ValueReg, address); + } + + template + void storeValueFromComponents(ImmTag type, RegisterID payload, T address) { + move(type, Registers::ValueReg); + orPtr(payload, Registers::ValueReg); + storeValue(Registers::ValueReg, address); + } + + /* + * Store a (64b) js::Value from 'type' and 'payload' into 'address', and + * return a label which can be used by + * Repatcher::patchAddressOffsetForValueStore to patch the address offset. + */ + DataLabel32 storeValueWithAddressOffsetPatch(RegisterID type, RegisterID payload, Address address) { + move(type, Registers::ValueReg); + orPtr(payload, Registers::ValueReg); + return storePtrWithAddressOffsetPatch(Registers::ValueReg, address); + } + + /* Overload for constant type. */ + DataLabel32 storeValueWithAddressOffsetPatch(ImmTag type, RegisterID payload, Address address) { + move(type, Registers::ValueReg); + orPtr(payload, Registers::ValueReg); + return storePtrWithAddressOffsetPatch(Registers::ValueReg, address); + } + + /* Overload for constant type and constant data. */ + DataLabel32 storeValueWithAddressOffsetPatch(const Value &v, Address address) { + jsval_layout jv; + jv.asBits = JSVAL_BITS(Jsvalify(v)); + + move(ImmPtr(reinterpret_cast(jv.asBits)), Registers::ValueReg); + return storePtrWithAddressOffsetPatch(Registers::ValueReg, valueOf(address)); + } + + /* Overloaded for store with value remat info. */ + DataLabel32 storeValueWithAddressOffsetPatch(const ValueRemat &vr, Address address) { + if (vr.isConstant()) { + return storeValueWithAddressOffsetPatch(vr.value(), address); + } else if (vr.isTypeKnown()) { + ImmType type(vr.knownType()); + RegisterID data(vr.dataReg()); + return storeValueWithAddressOffsetPatch(type, data, address); + } else { + RegisterID type(vr.typeReg()); + RegisterID data(vr.dataReg()); + return storeValueWithAddressOffsetPatch(type, data, address); + } + } + + template + void loadTypeTag(T address, RegisterID reg) { + loadValue(address, reg); + convertValueToType(reg); + } + + template + void storeTypeTag(ImmTag imm, T address) { + loadPayload(address, Registers::ValueReg); + orPtr(imm, Registers::ValueReg); + storePtr(Registers::ValueReg, valueOf(address)); + } + + template + void storeTypeTag(RegisterID reg, T address) { + /* The type tag must be stored in shifted format. */ + loadPayload(address, Registers::ValueReg); + orPtr(reg, Registers::ValueReg); + storePtr(Registers::ValueReg, valueOf(address)); + } + + template + void loadPayload(T address, RegisterID reg) { + loadValue(address, reg); + convertValueToPayload(reg); + } + + template + void storePayload(RegisterID reg, T address) { + /* Not for doubles. */ + loadTypeTag(address, Registers::ValueReg); + orPtr(reg, Registers::ValueReg); + storePtr(Registers::ValueReg, valueOf(address)); + } + + template + void storePayload(ImmPayload imm, T address) { + /* Not for doubles. */ + storePtr(imm, valueOf(address)); + } + + template + void storeValue(RegisterID reg, T address) { + storePtr(reg, valueOf(address)); + } + + template + void storeValue(const Value &v, T address) { + jsval_layout jv; + jv.asBits = JSVAL_BITS(Jsvalify(v)); + + storePtr(Imm64(jv.asBits), valueOf(address)); + } + + template + void storeValue(const ValueRemat &vr, T address) { + if (vr.isConstant()) + storeValue(vr.value(), address); + else if (vr.isTypeKnown()) + storeValueFromComponents(ImmType(vr.knownType()), vr.dataReg(), address); + else + storeValueFromComponents(vr.typeReg(), vr.dataReg(), address); + } + + template + Jump guardNotHole(T address) { + loadTypeTag(address, Registers::ValueReg); + return branchPtr(Equal, Registers::ValueReg, ImmType(JSVAL_TYPE_MAGIC)); + } + + void loadPrivate(Address privAddr, RegisterID to) { + loadPtr(privAddr, to); + lshiftPtr(Imm32(1), to); + } + + void loadObjPrivate(RegisterID base, RegisterID to) { + Address priv(base, offsetof(JSObject, privateData)); + loadPtr(priv, to); + } + + Jump testNull(Condition cond, RegisterID reg) { + return branchPtr(cond, reg, ImmTag(JSVAL_SHIFTED_TAG_NULL)); + } + + Jump testNull(Condition cond, Address address) { + loadValue(address, Registers::ValueReg); + return testNull(cond, Registers::ValueReg); + } + + Jump testUndefined(Condition cond, RegisterID reg) { + return branchPtr(cond, reg, ImmTag(JSVAL_SHIFTED_TAG_UNDEFINED)); + } + + Jump testUndefined(Condition cond, Address address) { + loadValue(address, Registers::ValueReg); + return testUndefined(cond, Registers::ValueReg); + } + + Jump testInt32(Condition cond, RegisterID reg) { + return branchPtr(cond, reg, ImmTag(JSVAL_SHIFTED_TAG_INT32)); + } + + Jump testInt32(Condition cond, Address address) { + loadTypeTag(address, Registers::ValueReg); + return testInt32(cond, Registers::ValueReg); + } + + Jump testNumber(Condition cond, RegisterID reg) { + cond = (cond == Equal) ? Below : AboveOrEqual; + return branchPtr(cond, reg, + ImmTag(JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET)); + } + + Jump testNumber(Condition cond, Address address) { + loadValue(address, Registers::ValueReg); + return testNumber(cond, Registers::ValueReg); + } + + Jump testPrimitive(Condition cond, RegisterID reg) { + cond = (cond == Equal) ? Below : AboveOrEqual; + return branchPtr(cond, reg, + ImmTag(JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET)); + } + + Jump testPrimitive(Condition cond, Address address) { + loadValue(address, Registers::ValueReg); + return testPrimitive(cond, Registers::ValueReg); + } + + Jump testObject(Condition cond, RegisterID reg) { + cond = (cond == Equal) ? AboveOrEqual : Below; + return branchPtr(cond, reg, ImmTag(JSVAL_SHIFTED_TAG_OBJECT)); + } + + Jump testObject(Condition cond, Address address) { + loadValue(address, Registers::ValueReg); + return testObject(cond, Registers::ValueReg); + } + + Jump testDouble(Condition cond, RegisterID reg) { + cond = (cond == Equal) ? BelowOrEqual : Above; + return branchPtr(cond, reg, ImmTag(JSVAL_SHIFTED_TAG_MAX_DOUBLE)); + } + + Jump testDouble(Condition cond, Address address) { + loadValue(address, Registers::ValueReg); + return testDouble(cond, Registers::ValueReg); + } + + Jump testBoolean(Condition cond, RegisterID reg) { + return branchPtr(cond, reg, ImmTag(JSVAL_SHIFTED_TAG_BOOLEAN)); + } + + Jump testBoolean(Condition cond, Address address) { + loadTypeTag(address, Registers::ValueReg); + return testBoolean(cond, Registers::ValueReg); + } + + Jump testString(Condition cond, RegisterID reg) { + return branchPtr(cond, reg, ImmTag(JSVAL_SHIFTED_TAG_STRING)); + } + + Jump testString(Condition cond, Address address) { + loadTypeTag(address, Registers::ValueReg); + return testString(cond, Registers::ValueReg); + } + + void breakDouble(FPRegisterID srcDest, RegisterID typeReg, RegisterID dataReg) { + m_assembler.movq_rr(srcDest, typeReg); + move(Registers::PayloadMaskReg, dataReg); + andPtr(typeReg, dataReg); + xorPtr(dataReg, typeReg); + } + + void fastLoadDouble(RegisterID dataReg, RegisterID typeReg, FPRegisterID fpReg) { + move(typeReg, Registers::ValueReg); + orPtr(dataReg, Registers::ValueReg); + m_assembler.movq_rr(Registers::ValueReg, fpReg); + } + + void loadStaticDouble(const double *dp, FPRegisterID dest, RegisterID scratch) { + jsdpun du; + du.d = *dp; + move(ImmPtr(reinterpret_cast(du.u64)), scratch); + m_assembler.movq_rr(scratch, dest); + } + + template + Jump fastArrayLoadSlot(T address, RegisterID typeReg, RegisterID dataReg) { + loadValueAsComponents(address, typeReg, dataReg); + return branchPtr(Equal, typeReg, ImmType(JSVAL_TYPE_MAGIC)); + } +}; + +typedef PunboxAssembler ValueAssembler; + +} /* namespace mjit */ +} /* namespace js */ + +#endif + diff --git a/js/src/methodjit/RematInfo.h b/js/src/methodjit/RematInfo.h new file mode 100644 index 0000000..3279e76 --- /dev/null +++ b/js/src/methodjit/RematInfo.h @@ -0,0 +1,287 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined jsjaeger_remat_h__ && defined JS_METHODJIT +#define jsjaeger_remat_h__ + +#include "jscntxt.h" +#include "MachineRegs.h" +#include "assembler/assembler/MacroAssembler.h" + +namespace js { +namespace mjit { + +// Lightweight, union-able components of FrameEntry. +struct StateRemat { + typedef JSC::MacroAssembler::RegisterID RegisterID; + typedef JSC::MacroAssembler::Address Address; + + static const int32 CONSTANT = -int(UINT16_LIMIT * sizeof(Value)); + + // This union encodes the fastest rematerialization of a non-constant + // value. The |offset| field can be used to recover information + // without this struct's helpers: + // 1) A value in (CONSTANT, 0) is an argument slot. + // 2) A value in [0, fp) is a register ID. + // 3) A value in [fp, inf) is a local slot. + union { + RegisterID reg_; + int32 offset_; + }; + + static StateRemat FromInt32(int32 i32) { + StateRemat sr; + sr.offset_ = i32; + return sr; + } + static StateRemat FromRegister(RegisterID reg) { + StateRemat sr; + sr.reg_ = reg; + JS_ASSERT(sr.inRegister()); + return sr; + } + static StateRemat FromAddress(Address address) { + JS_ASSERT(address.base == JSFrameReg); + StateRemat sr; + sr.offset_ = address.offset; + JS_ASSERT(sr.inMemory()); + return sr; + } + + // Minimum number of bits needed to compactly store the int32 + // representation in a struct or union. This prevents bloating the IC + // structs by an extra 8 bytes in some cases. 16 bits are needed to encode + // the largest local: + // ((UINT16_LIMIT - 1) * sizeof(Value) + sizeof(JSStackFrame), + // And an extra bit for the sign on arguments. +#define MIN_STATE_REMAT_BITS 21 + + bool isConstant() const { return offset_ == CONSTANT; } + bool inRegister() const { return offset_ >= 0 && + offset_ <= int32(JSC::MacroAssembler::TotalRegisters); } + bool inMemory() const { + return offset_ >= int32(sizeof(JSStackFrame)) || + offset_ < 0; + } + + int32 toInt32() const { return offset_; } + Address address() const { + JS_ASSERT(inMemory()); + return Address(JSFrameReg, offset_); + } + RegisterID reg() const { + JS_ASSERT(inRegister()); + return reg_; + } +}; + +/* Lightweight version of FrameEntry. */ +struct ValueRemat { + typedef JSC::MacroAssembler::RegisterID RegisterID; + union { + struct { + union { + int32 typeRemat_; + JSValueType knownType_; + } type; + int32 dataRemat_ : MIN_STATE_REMAT_BITS; + bool isTypeKnown_ : 1; + } s; + jsval v_; + } u; + bool isConstant_ : 1; + bool isDataSynced : 1; + bool isTypeSynced : 1; + + static ValueRemat FromConstant(const Value &v) { + ValueRemat vr; + vr.isConstant_ = true; + vr.u.v_ = Jsvalify(v); + return vr; + } + static ValueRemat FromKnownType(JSValueType type, RegisterID dataReg) { + ValueRemat vr; + vr.isConstant_ = false; + vr.u.s.type.knownType_ = type; + vr.u.s.isTypeKnown_ = true; + vr.u.s.dataRemat_ = StateRemat::FromRegister(dataReg).toInt32(); + + // Assert bitfields are okay. + JS_ASSERT(vr.dataReg() == dataReg); + return vr; + } + static ValueRemat FromRegisters(RegisterID typeReg, RegisterID dataReg) { + ValueRemat vr; + vr.isConstant_ = false; + vr.u.s.isTypeKnown_ = false; + vr.u.s.type.typeRemat_ = StateRemat::FromRegister(typeReg).toInt32(); + vr.u.s.dataRemat_ = StateRemat::FromRegister(dataReg).toInt32(); + + // Assert bitfields are okay. + JS_ASSERT(vr.dataReg() == dataReg); + JS_ASSERT(vr.typeReg() == typeReg); + return vr; + } + + RegisterID dataReg() const { + JS_ASSERT(!isConstant()); + return dataRemat().reg(); + } + RegisterID typeReg() const { + JS_ASSERT(!isTypeKnown()); + return typeRemat().reg(); + } + + bool isConstant() const { return isConstant_; } + bool isTypeKnown() const { return isConstant() || u.s.isTypeKnown_; } + + StateRemat dataRemat() const { + JS_ASSERT(!isConstant()); + return StateRemat::FromInt32(u.s.dataRemat_); + } + StateRemat typeRemat() const { + JS_ASSERT(!isTypeKnown()); + return StateRemat::FromInt32(u.s.type.typeRemat_); + } + Value value() const { + JS_ASSERT(isConstant()); + return Valueify(u.v_); + } + JSValueType knownType() const { + JS_ASSERT(isTypeKnown()); + if (isConstant()) { + const Value v = value(); + if (v.isDouble()) + return JSVAL_TYPE_DOUBLE; + return v.extractNonDoubleType(); + } + return u.s.type.knownType_; + } + bool isType(JSValueType type_) const { + return isTypeKnown() && knownType() == type_; + } +}; + +/* + * Describes how to rematerialize a value during compilation. + */ +struct RematInfo { + typedef JSC::MacroAssembler::RegisterID RegisterID; + + enum SyncState { + SYNCED, + UNSYNCED + }; + + enum RematType { + TYPE, + DATA + }; + + /* Physical location. */ + enum PhysLoc { + /* + * Backing bits are in memory. No fast remat. + */ + PhysLoc_Memory = 0, + + /* Backing bits are known at compile time. */ + PhysLoc_Constant, + + /* Backing bits are in a register. */ + PhysLoc_Register, + + /* Backing bits are invalid/unknown. */ + PhysLoc_Invalid + }; + + void setRegister(RegisterID reg) { + reg_ = reg; + location_ = PhysLoc_Register; + } + + RegisterID reg() const { + JS_ASSERT(inRegister()); + return reg_; + } + + void setMemory() { + location_ = PhysLoc_Memory; + sync_ = SYNCED; + } + + void invalidate() { + location_ = PhysLoc_Invalid; + } + + void setConstant() { location_ = PhysLoc_Constant; } + + bool isConstant() const { return location_ == PhysLoc_Constant; } + bool inRegister() const { return location_ == PhysLoc_Register; } + bool inMemory() const { return location_ == PhysLoc_Memory; } + bool synced() const { return sync_ == SYNCED; } + void sync() { + JS_ASSERT(!synced()); + sync_ = SYNCED; + } + void unsync() { + sync_ = UNSYNCED; + } + + void inherit(const RematInfo &other) { + reg_ = other.reg_; + location_ = other.location_; + } + + private: + /* Set if location is PhysLoc_Register. */ + RegisterID reg_; + + /* Remat source. */ + PhysLoc location_; + + /* Sync state. */ + SyncState sync_; +}; + +} /* namespace mjit */ +} /* namespace js */ + +#endif + diff --git a/js/src/methodjit/Retcon.cpp b/js/src/methodjit/Retcon.cpp new file mode 100644 index 0000000..8956b67 --- /dev/null +++ b/js/src/methodjit/Retcon.cpp @@ -0,0 +1,225 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Jaegermonkey. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Andrew Drake + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifdef JS_METHODJIT + +#include "Retcon.h" +#include "MethodJIT.h" +#include "Compiler.h" +#include "jsdbgapi.h" +#include "jsnum.h" + +#include "jscntxtinlines.h" + +using namespace js; +using namespace js::mjit; + +namespace js { +namespace mjit { + +AutoScriptRetrapper::~AutoScriptRetrapper() +{ + while (!traps.empty()) { + jsbytecode *pc = traps.back(); + traps.popBack(); + *pc = JSOP_TRAP; + } +} + +bool +AutoScriptRetrapper::untrap(jsbytecode *pc) +{ + if (!traps.append(pc)) + return false; + *pc = JS_GetTrapOpcode(cx, script, pc); + return true; +} + +Recompiler::PatchableAddress +Recompiler::findPatch(JITScript *jit, void **location) +{ + uint8* codeStart = (uint8 *)jit->code.m_code.executableAddress(); + CallSite *callSites_ = jit->callSites(); + for (uint32 i = 0; i < jit->nCallSites; i++) { + if (callSites_[i].codeOffset + codeStart == *location) { + PatchableAddress result; + result.location = location; + result.callSite = callSites_[i]; + return result; + } + } + + JS_NOT_REACHED("failed to find call site"); + return PatchableAddress(); +} + +void +Recompiler::applyPatch(Compiler& c, PatchableAddress& toPatch) +{ + void *result = c.findCallSite(toPatch.callSite); + JS_ASSERT(result); + *toPatch.location = result; +} + +Recompiler::Recompiler(JSContext *cx, JSScript *script) + : cx(cx), script(script) +{ +} + +/* + * The strategy for this goes as follows: + * + * 1) Scan the stack, looking at all return addresses that could go into JIT + * code. + * 2) If an address corresponds to a call site registered by |callSite| during + * the last compilation, remember it. + * 3) Purge the old compiled state and return if there were no active frames of + * this script on the stack. + * 4) Fix up the stack by replacing all saved addresses with the addresses the + * new compiler gives us for the call sites. + */ +bool +Recompiler::recompile() +{ + JS_ASSERT(script->hasJITCode()); + + Vector normalPatches(cx); + Vector ctorPatches(cx); + + JSStackFrame *firstCtorFrame = NULL; + JSStackFrame *firstNormalFrame = NULL; + + // Find all JIT'd stack frames to account for return addresses that will + // need to be patched after recompilation. + for (VMFrame *f = script->compartment->jaegerCompartment->activeFrame(); + f != NULL; + f = f->previous) { + + // Scan all frames owned by this VMFrame. + JSStackFrame *end = f->entryfp->prev(); + for (JSStackFrame *fp = f->fp(); fp != end; fp = fp->prev()) { + // Remember the latest frame for each type of JIT'd code, so the + // compiler will have a frame to re-JIT from. + if (!firstCtorFrame && fp->script() == script && fp->isConstructing()) + firstCtorFrame = fp; + else if (!firstNormalFrame && fp->script() == script && !fp->isConstructing()) + firstNormalFrame = fp; + + void **addr = fp->addressOfNativeReturnAddress(); + if (script->jitCtor && script->jitCtor->isValidCode(*addr)) { + if (!ctorPatches.append(findPatch(script->jitCtor, addr))) + return false; + } else if (script->jitNormal && script->jitNormal->isValidCode(*addr)) { + if (!normalPatches.append(findPatch(script->jitNormal, addr))) + return false; + } + } + + void **addr = f->returnAddressLocation(); + if (script->jitCtor && script->jitCtor->isValidCode(*addr)) { + if (!ctorPatches.append(findPatch(script->jitCtor, addr))) + return false; + } else if (script->jitNormal && script->jitNormal->isValidCode(*addr)) { + if (!normalPatches.append(findPatch(script->jitNormal, addr))) + return false; + } + } + + Vector normalSites(cx); + Vector ctorSites(cx); + + if (script->jitNormal && !saveTraps(script->jitNormal, &normalSites)) + return false; + if (script->jitCtor && !saveTraps(script->jitCtor, &ctorSites)) + return false; + + ReleaseScriptCode(cx, script); + + if (normalPatches.length() && + !recompile(firstNormalFrame, normalPatches, normalSites)) { + return false; + } + + if (ctorPatches.length() && + !recompile(firstCtorFrame, ctorPatches, ctorSites)) { + return false; + } + + return true; +} + +bool +Recompiler::saveTraps(JITScript *jit, Vector *sites) +{ + CallSite *callSites_ = jit->callSites(); + for (uint32 i = 0; i < jit->nCallSites; i++) { + CallSite &site = callSites_[i]; + if (site.isTrap() && !sites->append(site)) + return false; + } + return true; +} + +bool +Recompiler::recompile(JSStackFrame *fp, Vector &patches, + Vector &sites) +{ + /* If we get this far, the script is live, and we better be safe to re-jit. */ + JS_ASSERT(cx->compartment->debugMode); + JS_ASSERT(fp); + + Compiler c(cx, fp); + if (!c.loadOldTraps(sites)) + return false; + if (c.compile() != Compile_Okay) + return false; + + /* Perform the earlier scanned patches */ + for (uint32 i = 0; i < patches.length(); i++) + applyPatch(c, patches[i]); + + return true; +} + +} /* namespace mjit */ +} /* namespace js */ + +#endif /* JS_METHODJIT */ + diff --git a/js/src/methodjit/Retcon.h b/js/src/methodjit/Retcon.h new file mode 100644 index 0000000..d07409b --- /dev/null +++ b/js/src/methodjit/Retcon.h @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Jaegermonkey. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Andrew Drake + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Retroactive continuity ("retcon") refers to the retroactive modification + * or reinterpretation of established facts. + */ + +#if !defined jsjaeger_retcon_h__ && defined JS_METHODJIT +#define jsjaeger_retcon_h__ + +#include "jscntxt.h" +#include "jsscript.h" +#include "MethodJIT.h" +#include "Compiler.h" + +namespace js { +namespace mjit { + +/* + * A problem often arises where, for one reason or another, a piece of code + * wants to touch the script->code, but isn't expecting JSOP_TRAP. This allows + * one to temporarily remove JSOP_TRAPs from the instruction stream (without + * copying) and automatically re-add them on scope exit. + */ +class AutoScriptRetrapper +{ + public: + AutoScriptRetrapper(JSContext *cx1, JSScript *script1) : + cx(cx1), script(script1), traps(cx) {}; + ~AutoScriptRetrapper(); + + bool untrap(jsbytecode *pc); + + private: + JSContext *cx; + JSScript *script; + Vector traps; +}; + +/* + * This class is responsible for sanely re-JITing a script and fixing up + * the world. If you ever change the code associated with a JSScript, or + * otherwise would cause existing JITed code to be incorrect, you /must/ use + * this to invalidate and potentially re-compile the existing JITed code, + * fixing up the stack in the process. + */ +class Recompiler { + struct PatchableAddress { + void **location; + CallSite callSite; + }; + +public: + Recompiler(JSContext *cx, JSScript *script); + + bool recompile(); + +private: + JSContext *cx; + JSScript *script; + + PatchableAddress findPatch(JITScript *jit, void **location); + void applyPatch(Compiler& c, PatchableAddress& toPatch); + bool recompile(JSStackFrame *fp, Vector &patches, + Vector &sites); + bool saveTraps(JITScript *jit, Vector *sites); +}; + +} /* namespace mjit */ +} /* namespace js */ + +#endif + diff --git a/js/src/methodjit/StubCalls-inl.h b/js/src/methodjit/StubCalls-inl.h new file mode 100644 index 0000000..84ce861 --- /dev/null +++ b/js/src/methodjit/StubCalls-inl.h @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jslogic_h_inl__ +#define jslogic_h_inl__ + +namespace js { +namespace mjit { + +static inline void +ThrowException(VMFrame &f) +{ + void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); + *f.returnAddressLocation() = ptr; +} + +#define THROW() do { ThrowException(f); return; } while (0) +#define THROWV(v) do { ThrowException(f); return v; } while (0) + +static inline JSObject * +ValueToObject(JSContext *cx, Value *vp) +{ + if (vp->isObject()) + return &vp->toObject(); + return js_ValueToNonNullObject(cx, *vp); +} + +static inline void +ReportAtomNotDefined(JSContext *cx, JSAtom *atom) +{ + JSAutoByteString printable; + if (js_AtomToPrintableString(cx, atom, &printable)) + js_ReportIsNotDefined(cx, printable.ptr()); +} + +#define NATIVE_SET(cx,obj,shape,entry,strict,vp) \ + JS_BEGIN_MACRO \ + if (shape->hasDefaultSetter() && \ + (shape)->slot != SHAPE_INVALID_SLOT && \ + !(obj)->brandedOrHasMethodBarrier()) { \ + /* Fast path for, e.g., plain Object instance properties. */ \ + (obj)->nativeSetSlot((shape)->slot, *vp); \ + } else { \ + if (!js_NativeSet(cx, obj, shape, false, strict, vp)) \ + THROW(); \ + } \ + JS_END_MACRO + +#define NATIVE_GET(cx,obj,pobj,shape,getHow,vp,onerr) \ + JS_BEGIN_MACRO \ + if (shape->isDataDescriptor() && shape->hasDefaultGetter()) { \ + /* Fast path for Object instance properties. */ \ + JS_ASSERT((shape)->slot != SHAPE_INVALID_SLOT || \ + !shape->hasDefaultSetter()); \ + if (((shape)->slot != SHAPE_INVALID_SLOT)) \ + *(vp) = (pobj)->nativeGetSlot((shape)->slot); \ + else \ + (vp)->setUndefined(); \ + } else { \ + if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp)) \ + onerr; \ + } \ + JS_END_MACRO + +}} + +#endif /* jslogic_h__ */ + diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp new file mode 100644 index 0000000..5741f29 --- /dev/null +++ b/js/src/methodjit/StubCalls.cpp @@ -0,0 +1,2708 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jscntxt.h" +#include "jsscope.h" +#include "jsobj.h" +#include "jslibmath.h" +#include "jsiter.h" +#include "jsnum.h" +#include "jsxml.h" +#include "jsstaticcheck.h" +#include "jsbool.h" +#include "assembler/assembler/MacroAssemblerCodeRef.h" +#include "jsiter.h" +#include "jstypes.h" +#include "methodjit/Compiler.h" +#include "methodjit/StubCalls.h" +#include "jstracer.h" + +#include "jsinterpinlines.h" +#include "jspropertycache.h" +#include "jspropertycacheinlines.h" +#include "jsscopeinlines.h" +#include "jsscriptinlines.h" +#include "jsstrinlines.h" +#include "jsobjinlines.h" +#include "jscntxtinlines.h" +#include "jsatominlines.h" +#include "StubCalls-inl.h" +#include "jsfuninlines.h" +#include "jstypedarray.h" + +#ifdef XP_WIN +# include "jswin.h" +#endif + +#include "jsautooplen.h" + +using namespace js; +using namespace js::mjit; +using namespace JSC; + +void JS_FASTCALL +stubs::BindName(VMFrame &f) +{ + PropertyCacheEntry *entry; + + /* Fast-path should have caught this. See comment in interpreter. */ + JS_ASSERT(f.fp()->scopeChain().getParent()); + + JSAtom *atom; + JSObject *obj2; + JSContext *cx = f.cx; + JSObject *obj = &f.fp()->scopeChain(); + JS_PROPERTY_CACHE(cx).test(cx, f.regs.pc, obj, obj2, entry, atom); + if (atom) { + jsid id = ATOM_TO_JSID(atom); + obj = js_FindIdentifierBase(cx, &f.fp()->scopeChain(), id); + if (!obj) + THROW(); + } + f.regs.sp++; + f.regs.sp[-1].setObject(*obj); +} + +void JS_FASTCALL +stubs::BindNameNoCache(VMFrame &f, JSAtom *atom) +{ + JSObject *obj = js_FindIdentifierBase(f.cx, &f.fp()->scopeChain(), ATOM_TO_JSID(atom)); + if (!obj) + THROW(); + f.regs.sp[0].setObject(*obj); +} + +JSObject * JS_FASTCALL +stubs::BindGlobalName(VMFrame &f) +{ + return f.fp()->scopeChain().getGlobal(); +} + +template +void JS_FASTCALL +stubs::SetName(VMFrame &f, JSAtom *origAtom) +{ + JSContext *cx = f.cx; + + Value rval = f.regs.sp[-1]; + Value &lref = f.regs.sp[-2]; + JSObject *obj = ValueToObject(cx, &lref); + if (!obj) + THROW(); + + do { + PropertyCache *cache = &JS_PROPERTY_CACHE(cx); + + /* + * Probe the property cache, specializing for two important + * set-property cases. First: + * + * function f(a, b, c) { + * var o = {p:a, q:b, r:c}; + * return o; + * } + * + * or similar real-world cases, which evolve a newborn native + * object predicatably through some bounded number of property + * additions. And second: + * + * o.p = x; + * + * in a frequently executed method or loop body, where p will + * (possibly after the first iteration) always exist in native + * object o. + */ + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + if (cache->testForSet(cx, f.regs.pc, obj, &entry, &obj2, &atom)) { + /* + * Property cache hit, only partially confirmed by testForSet. We + * know that the entry applies to regs.pc and that obj's shape + * matches. + * + * The entry predicts either a new property to be added directly to + * obj by this set, or on an existing "own" property, or on a + * prototype property that has a setter. + */ + const Shape *shape = entry->vword.toShape(); + JS_ASSERT_IF(shape->isDataDescriptor(), shape->writable()); + JS_ASSERT_IF(shape->hasSlot(), entry->vcapTag() == 0); + + /* + * Fastest path: check whether obj already has the cached shape and + * call NATIVE_SET and break to get out of the do-while(0). But we + * can call NATIVE_SET only for a direct or proto-setter hit. + */ + if (!entry->adding()) { + if (entry->vcapTag() == 0 || + ((obj2 = obj->getProto()) && obj2->shape() == entry->vshape())) + { +#ifdef DEBUG + if (entry->directHit()) { + JS_ASSERT(obj->nativeContains(*shape)); + } else { + JS_ASSERT(obj2->nativeContains(*shape)); + JS_ASSERT(entry->vcapTag() == 1); + JS_ASSERT(entry->kshape != entry->vshape()); + JS_ASSERT(!shape->hasSlot()); + } +#endif + + PCMETER(cache->pchits++); + PCMETER(cache->setpchits++); + NATIVE_SET(cx, obj, shape, entry, strict, &rval); + break; + } + } else { + JS_ASSERT(obj->isExtensible()); + + if (obj->nativeEmpty()) { + if (!obj->ensureClassReservedSlotsForEmptyObject(cx)) + THROW(); + } + + uint32 slot; + if (shape->previous() == obj->lastProperty() && + entry->vshape() == cx->runtime->protoHazardShape && + shape->hasDefaultSetter()) { + slot = shape->slot; + JS_ASSERT(slot == obj->slotSpan()); + + /* + * Fast path: adding a plain old property that was once at + * the frontier of the property tree, whose slot is next to + * claim among the already-allocated slots in obj, where + * shape->table has not been created yet. + */ + PCMETER(cache->pchits++); + PCMETER(cache->addpchits++); + + if (slot < obj->numSlots()) { + JS_ASSERT(obj->getSlot(slot).isUndefined()); + } else { + if (!obj->allocSlot(cx, &slot)) + THROW(); + JS_ASSERT(slot == shape->slot); + } + + /* Simply extend obj's property tree path with shape! */ + obj->extend(cx, shape); + + /* + * No method change check here because here we are adding a + * new property, not updating an existing slot's value that + * might contain a method of a branded shape. + */ + obj->setSlot(slot, rval); + + /* + * Purge the property cache of the id we may have just + * shadowed in obj's scope and proto chains. + */ + js_PurgeScopeChain(cx, obj, shape->id); + break; + } + } + PCMETER(cache->setpcmisses++); + + atom = origAtom; + } else { + JS_ASSERT(atom); + } + + jsid id = ATOM_TO_JSID(atom); + if (entry && JS_LIKELY(!obj->getOps()->setProperty)) { + uintN defineHow; + JSOp op = JSOp(*f.regs.pc); + if (op == JSOP_SETMETHOD) + defineHow = JSDNP_CACHE_RESULT | JSDNP_SET_METHOD; + else if (op == JSOP_SETNAME) + defineHow = JSDNP_CACHE_RESULT | JSDNP_UNQUALIFIED; + else + defineHow = JSDNP_CACHE_RESULT; + if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rval, strict)) + THROW(); + } else { + if (!obj->setProperty(cx, id, &rval, strict)) + THROW(); + } + } while (0); + + f.regs.sp[-2] = f.regs.sp[-1]; +} + +template void JS_FASTCALL stubs::SetName(VMFrame &f, JSAtom *origAtom); +template void JS_FASTCALL stubs::SetName(VMFrame &f, JSAtom *origAtom); + +template +void JS_FASTCALL +stubs::SetPropNoCache(VMFrame &f, JSAtom *atom) +{ + JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]); + if (!obj) + THROW(); + Value rval = f.regs.sp[-1]; + if (!obj->setProperty(f.cx, ATOM_TO_JSID(atom), &f.regs.sp[-1], strict)) + THROW(); + f.regs.sp[-2] = rval; +} + +template void JS_FASTCALL stubs::SetPropNoCache(VMFrame &f, JSAtom *origAtom); +template void JS_FASTCALL stubs::SetPropNoCache(VMFrame &f, JSAtom *origAtom); + +template +void JS_FASTCALL +stubs::SetGlobalNameNoCache(VMFrame &f, JSAtom *atom) +{ + JSContext *cx = f.cx; + + Value rval = f.regs.sp[-1]; + Value &lref = f.regs.sp[-2]; + JSObject *obj = ValueToObject(cx, &lref); + if (!obj) + THROW(); + jsid id = ATOM_TO_JSID(atom); + if (!obj->setProperty(cx, id, &rval, strict)) + THROW(); + + f.regs.sp[-2] = f.regs.sp[-1]; +} + +template void JS_FASTCALL stubs::SetGlobalNameNoCache(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::SetGlobalNameNoCache(VMFrame &f, JSAtom *atom); + +template +void JS_FASTCALL +stubs::SetGlobalName(VMFrame &f, JSAtom *atom) +{ + SetName(f, atom); +} + +template void JS_FASTCALL stubs::SetGlobalName(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::SetGlobalName(VMFrame &f, JSAtom *atom); + +static inline void +PushImplicitThis(VMFrame &f, JSObject *obj, Value &rval) +{ + Value thisv; + + if (!ComputeImplicitThis(f.cx, obj, rval, &thisv)) + return; + *f.regs.sp++ = thisv; +} + +static JSObject * +NameOp(VMFrame &f, JSObject *obj, bool callname = false) +{ + JSContext *cx = f.cx; + + const Shape *shape; + Value rval; + + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + JS_PROPERTY_CACHE(cx).test(cx, f.regs.pc, obj, obj2, entry, atom); + if (!atom) { + if (entry->vword.isFunObj()) { + rval.setObject(entry->vword.toFunObj()); + } else if (entry->vword.isSlot()) { + uintN slot = entry->vword.toSlot(); + rval = obj2->nativeGetSlot(slot); + } else { + JS_ASSERT(entry->vword.isShape()); + shape = entry->vword.toShape(); + NATIVE_GET(cx, obj, obj2, shape, JSGET_METHOD_BARRIER, &rval, return NULL); + } + + JS_ASSERT(obj->isGlobal() || IsCacheableNonGlobalScope(obj)); + } else { + jsid id; + id = ATOM_TO_JSID(atom); + JSProperty *prop; + if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop)) + return NULL; + if (!prop) { + /* Kludge to allow (typeof foo == "undefined") tests. */ + JSOp op2 = js_GetOpcode(cx, f.fp()->script(), f.regs.pc + JSOP_NAME_LENGTH); + if (op2 == JSOP_TYPEOF) { + f.regs.sp++; + f.regs.sp[-1].setUndefined(); + return obj; + } + ReportAtomNotDefined(cx, atom); + return NULL; + } + + /* Take the slow path if prop was not found in a native object. */ + if (!obj->isNative() || !obj2->isNative()) { + if (!obj->getProperty(cx, id, &rval)) + return NULL; + } else { + shape = (Shape *)prop; + JSObject *normalized = obj; + if (normalized->getClass() == &js_WithClass && !shape->hasDefaultGetter()) + normalized = js_UnwrapWithObject(cx, normalized); + NATIVE_GET(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, &rval, return NULL); + } + } + + *f.regs.sp++ = rval; + + if (callname) + PushImplicitThis(f, obj, rval); + + return obj; +} + +void JS_FASTCALL +stubs::Name(VMFrame &f) +{ + if (!NameOp(f, &f.fp()->scopeChain())) + THROW(); +} + +void JS_FASTCALL +stubs::GetGlobalName(VMFrame &f) +{ + JSObject *globalObj = f.fp()->scopeChain().getGlobal(); + if (!NameOp(f, globalObj)) + THROW(); +} + +void JS_FASTCALL +stubs::GetElem(VMFrame &f) +{ + JSContext *cx = f.cx; + JSFrameRegs ®s = f.regs; + + Value &lref = regs.sp[-2]; + Value &rref = regs.sp[-1]; + if (lref.isString() && rref.isInt32()) { + JSString *str = lref.toString(); + int32_t i = rref.toInt32(); + if ((size_t)i < str->length()) { + str = JSString::getUnitString(cx, str, (size_t)i); + if (!str) + THROW(); + f.regs.sp[-2].setString(str); + return; + } + } + + JSObject *obj = ValueToObject(cx, &lref); + if (!obj) + THROW(); + + const Value *copyFrom; + Value rval; + jsid id; + if (rref.isInt32()) { + int32_t i = rref.toInt32(); + if (obj->isDenseArray()) { + jsuint idx = jsuint(i); + + if (idx < obj->getArrayLength() && + idx < obj->getDenseArrayCapacity()) { + copyFrom = obj->addressOfDenseArrayElement(idx); + if (!copyFrom->isMagic()) + goto end_getelem; + } + } else if (obj->isArguments()) { + uint32 arg = uint32(i); + + if (arg < obj->getArgsInitialLength()) { + copyFrom = obj->addressOfArgsElement(arg); + if (!copyFrom->isMagic()) { + if (JSStackFrame *afp = (JSStackFrame *) obj->getPrivate()) + copyFrom = &afp->canonicalActualArg(arg); + goto end_getelem; + } + } + } + if (JS_LIKELY(INT_FITS_IN_JSID(i))) + id = INT_TO_JSID(i); + else + goto intern_big_int; + + } else { + int32_t i; + if (ValueFitsInInt32(rref, &i) && INT_FITS_IN_JSID(i)) { + id = INT_TO_JSID(i); + } else { + intern_big_int: + if (!js_InternNonIntElementId(cx, obj, rref, &id)) + THROW(); + } + } + + if (!obj->getProperty(cx, id, &rval)) + THROW(); + copyFrom = &rval; + + end_getelem: + f.regs.sp[-2] = *copyFrom; +} + +static inline bool +FetchElementId(VMFrame &f, JSObject *obj, const Value &idval, jsid &id, Value *vp) +{ + int32_t i_; + if (ValueFitsInInt32(idval, &i_) && INT_FITS_IN_JSID(i_)) { + id = INT_TO_JSID(i_); + return true; + } + return !!js_InternNonIntElementId(f.cx, obj, idval, &id, vp); +} + +void JS_FASTCALL +stubs::CallElem(VMFrame &f) +{ + JSContext *cx = f.cx; + JSFrameRegs ®s = f.regs; + + /* Find the object on which to look for |this|'s properties. */ + Value thisv = regs.sp[-2]; + JSObject *thisObj = ValuePropertyBearer(cx, thisv, -2); + if (!thisObj) + THROW(); + + /* Fetch index and convert it to id suitable for use with thisObj. */ + jsid id; + if (!FetchElementId(f, thisObj, regs.sp[-1], id, ®s.sp[-2])) + THROW(); + + /* Get or set the element. */ + if (!js_GetMethod(cx, thisObj, id, JSGET_NO_METHOD_BARRIER, ®s.sp[-2])) + THROW(); + +#if JS_HAS_NO_SUCH_METHOD + if (JS_UNLIKELY(regs.sp[-2].isUndefined()) && thisv.isObject()) { + regs.sp[-2] = regs.sp[-1]; + regs.sp[-1].setObject(*thisObj); + if (!js_OnUnknownMethod(cx, regs.sp - 2)) + THROW(); + } else +#endif + { + regs.sp[-1] = thisv; + } +} + +template +void JS_FASTCALL +stubs::SetElem(VMFrame &f) +{ + JSContext *cx = f.cx; + JSFrameRegs ®s = f.regs; + + Value &objval = regs.sp[-3]; + Value &idval = regs.sp[-2]; + Value rval = regs.sp[-1]; + + JSObject *obj; + jsid id; + + obj = ValueToObject(cx, &objval); + if (!obj) + THROW(); + + if (!FetchElementId(f, obj, idval, id, ®s.sp[-2])) + THROW(); + + do { + if (obj->isDenseArray() && JSID_IS_INT(id)) { + jsuint length = obj->getDenseArrayCapacity(); + jsint i = JSID_TO_INT(id); + if ((jsuint)i < length) { + if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) { + if (js_PrototypeHasIndexedProperties(cx, obj)) + break; + if ((jsuint)i >= obj->getArrayLength()) + obj->setArrayLength(i + 1); + } + obj->setDenseArrayElement(i, rval); + goto end_setelem; + } + } + } while (0); + if (!obj->setProperty(cx, id, &rval, strict)) + THROW(); + end_setelem: + /* :FIXME: Moving the assigned object into the lowest stack slot + * is a temporary hack. What we actually want is an implementation + * of popAfterSet() that allows popping more than one value; + * this logic can then be handled in Compiler.cpp. */ + regs.sp[-3] = regs.sp[-1]; +} + +template void JS_FASTCALL stubs::SetElem(VMFrame &f); +template void JS_FASTCALL stubs::SetElem(VMFrame &f); + +void JS_FASTCALL +stubs::CallName(VMFrame &f) +{ + JSObject *obj = NameOp(f, &f.fp()->scopeChain(), true); + if (!obj) + THROW(); +} + +/* + * Push the implicit this value, with the assumption that the callee + * (which is on top of the stack) was read as a property from the + * global object. + */ +void JS_FASTCALL +stubs::PushImplicitThisForGlobal(VMFrame &f) +{ + return PushImplicitThis(f, f.fp()->scopeChain().getGlobal(), f.regs.sp[-1]); +} + +void JS_FASTCALL +stubs::BitOr(VMFrame &f) +{ + int32_t i, j; + + if (!ValueToECMAInt32(f.cx, f.regs.sp[-2], &i) || + !ValueToECMAInt32(f.cx, f.regs.sp[-1], &j)) { + THROW(); + } + i = i | j; + f.regs.sp[-2].setInt32(i); +} + +void JS_FASTCALL +stubs::BitXor(VMFrame &f) +{ + int32_t i, j; + + if (!ValueToECMAInt32(f.cx, f.regs.sp[-2], &i) || + !ValueToECMAInt32(f.cx, f.regs.sp[-1], &j)) { + THROW(); + } + i = i ^ j; + f.regs.sp[-2].setInt32(i); +} + +void JS_FASTCALL +stubs::BitAnd(VMFrame &f) +{ + int32_t i, j; + + if (!ValueToECMAInt32(f.cx, f.regs.sp[-2], &i) || + !ValueToECMAInt32(f.cx, f.regs.sp[-1], &j)) { + THROW(); + } + i = i & j; + f.regs.sp[-2].setInt32(i); +} + +void JS_FASTCALL +stubs::BitNot(VMFrame &f) +{ + int32_t i; + + if (!ValueToECMAInt32(f.cx, f.regs.sp[-1], &i)) + THROW(); + i = ~i; + f.regs.sp[-1].setInt32(i); +} + +void JS_FASTCALL +stubs::Lsh(VMFrame &f) +{ + int32_t i, j; + if (!ValueToECMAInt32(f.cx, f.regs.sp[-2], &i)) + THROW(); + if (!ValueToECMAInt32(f.cx, f.regs.sp[-1], &j)) + THROW(); + i = i << (j & 31); + f.regs.sp[-2].setInt32(i); +} + +void JS_FASTCALL +stubs::Rsh(VMFrame &f) +{ + int32_t i, j; + if (!ValueToECMAInt32(f.cx, f.regs.sp[-2], &i)) + THROW(); + if (!ValueToECMAInt32(f.cx, f.regs.sp[-1], &j)) + THROW(); + i = i >> (j & 31); + f.regs.sp[-2].setInt32(i); +} + +void JS_FASTCALL +stubs::Ursh(VMFrame &f) +{ + uint32_t u; + if (!ValueToECMAUint32(f.cx, f.regs.sp[-2], &u)) + THROW(); + int32_t j; + if (!ValueToECMAInt32(f.cx, f.regs.sp[-1], &j)) + THROW(); + + u >>= (j & 31); + + f.regs.sp[-2].setNumber(uint32(u)); +} + +template +void JS_FASTCALL +stubs::DefFun(VMFrame &f, JSFunction *fun) +{ + JSObject *obj2; + + JSContext *cx = f.cx; + JSStackFrame *fp = f.fp(); + + /* + * A top-level function defined in Global or Eval code (see ECMA-262 + * Ed. 3), or else a SpiderMonkey extension: a named function statement in + * a compound statement (not at the top statement level of global code, or + * at the top level of a function body). + */ + JSObject *obj = FUN_OBJECT(fun); + + if (FUN_NULL_CLOSURE(fun)) { + /* + * Even a null closure needs a parent for principals finding. + * FIXME: bug 476950, although debugger users may also demand some kind + * of scope link for debugger-assisted eval-in-frame. + */ + obj2 = &fp->scopeChain(); + } else { + JS_ASSERT(!fun->isFlatClosure()); + + obj2 = GetScopeChainFast(cx, fp, JSOP_DEFFUN, JSOP_DEFFUN_LENGTH); + if (!obj2) + THROW(); + } + + /* + * If static link is not current scope, clone fun's object to link to the + * current scope via parent. We do this to enable sharing of compiled + * functions among multiple equivalent scopes, amortizing the cost of + * compilation over a number of executions. Examples include XUL scripts + * and event handlers shared among Firefox or other Mozilla app chrome + * windows, and user-defined JS functions precompiled and then shared among + * requests in server-side JS. + */ + if (obj->getParent() != obj2) { + obj = CloneFunctionObject(cx, fun, obj2); + if (!obj) + THROW(); + } + + /* + * ECMA requires functions defined when entering Eval code to be + * impermanent. + */ + uintN attrs = fp->isEvalFrame() + ? JSPROP_ENUMERATE + : JSPROP_ENUMERATE | JSPROP_PERMANENT; + + /* + * We define the function as a property of the variable object and not the + * current scope chain even for the case of function expression statements + * and functions defined by eval inside let or with blocks. + */ + JSObject *parent = &fp->varobj(cx); + + /* ES5 10.5 (NB: with subsequent errata). */ + jsid id = ATOM_TO_JSID(fun->atom); + JSProperty *prop = NULL; + JSObject *pobj; + if (!parent->lookupProperty(cx, id, &pobj, &prop)) + THROW(); + + Value rval = ObjectValue(*obj); + + do { + /* Steps 5d, 5f. */ + if (!prop || pobj != parent) { + if (!parent->defineProperty(cx, id, rval, PropertyStub, StrictPropertyStub, attrs)) + THROW(); + break; + } + + /* Step 5e. */ + JS_ASSERT(parent->isNative()); + Shape *shape = reinterpret_cast(prop); + if (parent->isGlobal()) { + if (shape->configurable()) { + if (!parent->defineProperty(cx, id, rval, PropertyStub, StrictPropertyStub, attrs)) + THROW(); + break; + } + + if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) { + JSAutoByteString bytes; + if (const char *name = js_ValueToPrintable(cx, IdToValue(id), &bytes)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_CANT_REDEFINE_PROP, name); + } + THROW(); + } + } + + /* + * Non-global properties, and global properties which we aren't simply + * redefining, must be set. First, this preserves their attributes. + * Second, this will produce warnings and/or errors as necessary if the + * specified Call object property is not writable (const). + */ + + /* Step 5f. */ + if (!parent->setProperty(cx, id, &rval, strict)) + THROW(); + } while (false); +} + +template void JS_FASTCALL stubs::DefFun(VMFrame &f, JSFunction *fun); +template void JS_FASTCALL stubs::DefFun(VMFrame &f, JSFunction *fun); + +#define DEFAULT_VALUE(cx, n, hint, v) \ + JS_BEGIN_MACRO \ + JS_ASSERT(v.isObject()); \ + JS_ASSERT(v == regs.sp[n]); \ + if (!DefaultValue(cx, &v.toObject(), hint, ®s.sp[n])) \ + THROWV(JS_FALSE); \ + v = regs.sp[n]; \ + JS_END_MACRO + +#define RELATIONAL(OP) \ + JS_BEGIN_MACRO \ + JSContext *cx = f.cx; \ + JSFrameRegs ®s = f.regs; \ + Value rval = regs.sp[-1]; \ + Value lval = regs.sp[-2]; \ + bool cond; \ + if (lval.isObject()) \ + DEFAULT_VALUE(cx, -2, JSTYPE_NUMBER, lval); \ + if (rval.isObject()) \ + DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \ + if (lval.isString() && rval.isString()) { \ + JSString *l = lval.toString(), *r = rval.toString(); \ + JSBool cmp; \ + if (!CompareStrings(cx, l, r, &cmp)) \ + THROWV(JS_FALSE); \ + cond = cmp OP 0; \ + } else { \ + double l, r; \ + if (!ValueToNumber(cx, lval, &l) || \ + !ValueToNumber(cx, rval, &r)) { \ + THROWV(JS_FALSE); \ + } \ + cond = JSDOUBLE_COMPARE(l, OP, r, false); \ + } \ + regs.sp[-2].setBoolean(cond); \ + return cond; \ + JS_END_MACRO + +JSBool JS_FASTCALL +stubs::LessThan(VMFrame &f) +{ + RELATIONAL(<); +} + +JSBool JS_FASTCALL +stubs::LessEqual(VMFrame &f) +{ + RELATIONAL(<=); +} + +JSBool JS_FASTCALL +stubs::GreaterThan(VMFrame &f) +{ + RELATIONAL(>); +} + +JSBool JS_FASTCALL +stubs::GreaterEqual(VMFrame &f) +{ + RELATIONAL(>=); +} + +JSBool JS_FASTCALL +stubs::ValueToBoolean(VMFrame &f) +{ + return js_ValueToBoolean(f.regs.sp[-1]); +} + +void JS_FASTCALL +stubs::Not(VMFrame &f) +{ + JSBool b = !js_ValueToBoolean(f.regs.sp[-1]); + f.regs.sp[-1].setBoolean(b); +} + +template +static inline bool +StubEqualityOp(VMFrame &f) +{ + JSContext *cx = f.cx; + JSFrameRegs ®s = f.regs; + + Value rval = regs.sp[-1]; + Value lval = regs.sp[-2]; + + JSBool cond; + + /* The string==string case is easily the hottest; try it first. */ + if (lval.isString() && rval.isString()) { + JSString *l = lval.toString(); + JSString *r = rval.toString(); + JSBool equal; + if (!EqualStrings(cx, l, r, &equal)) + return false; + cond = equal == EQ; + } else +#if JS_HAS_XML_SUPPORT + if ((lval.isObject() && lval.toObject().isXML()) || + (rval.isObject() && rval.toObject().isXML())) { + if (!js_TestXMLEquality(cx, lval, rval, &cond)) + return false; + cond = cond == EQ; + } else +#endif + + if (SameType(lval, rval)) { + JS_ASSERT(!lval.isString()); /* this case is handled above */ + if (lval.isDouble()) { + double l = lval.toDouble(); + double r = rval.toDouble(); + if (EQ) + cond = JSDOUBLE_COMPARE(l, ==, r, IFNAN); + else + cond = JSDOUBLE_COMPARE(l, !=, r, IFNAN); + } else if (lval.isObject()) { + JSObject *l = &lval.toObject(), *r = &rval.toObject(); + l->assertSpecialEqualitySynced(); + if (EqualityOp eq = l->getClass()->ext.equality) { + if (!eq(cx, l, &rval, &cond)) + return false; + cond = cond == EQ; + } else { + cond = (l == r) == EQ; + } + } else if (lval.isNullOrUndefined()) { + cond = EQ; + } else { + cond = (lval.payloadAsRawUint32() == rval.payloadAsRawUint32()) == EQ; + } + } else { + if (lval.isNullOrUndefined()) { + cond = rval.isNullOrUndefined() == EQ; + } else if (rval.isNullOrUndefined()) { + cond = !EQ; + } else { + if (lval.isObject()) { + if (!DefaultValue(cx, &lval.toObject(), JSTYPE_VOID, ®s.sp[-2])) + return false; + lval = regs.sp[-2]; + } + + if (rval.isObject()) { + if (!DefaultValue(cx, &rval.toObject(), JSTYPE_VOID, ®s.sp[-1])) + return false; + rval = regs.sp[-1]; + } + + /* + * The string==string case is repeated because DefaultValue() can + * convert lval/rval to strings. + */ + if (lval.isString() && rval.isString()) { + JSString *l = lval.toString(); + JSString *r = rval.toString(); + JSBool equal; + if (!EqualStrings(cx, l, r, &equal)) + return false; + cond = equal == EQ; + } else { + double l, r; + if (!ValueToNumber(cx, lval, &l) || + !ValueToNumber(cx, rval, &r)) { + return false; + } + + if (EQ) + cond = JSDOUBLE_COMPARE(l, ==, r, false); + else + cond = JSDOUBLE_COMPARE(l, !=, r, true); + } + } + } + + regs.sp[-2].setBoolean(cond); + return true; +} + +JSBool JS_FASTCALL +stubs::Equal(VMFrame &f) +{ + if (!StubEqualityOp(f)) + THROWV(JS_FALSE); + return f.regs.sp[-2].toBoolean(); +} + +JSBool JS_FASTCALL +stubs::NotEqual(VMFrame &f) +{ + if (!StubEqualityOp(f)) + THROWV(JS_FALSE); + return f.regs.sp[-2].toBoolean(); +} + +static inline bool +DefaultValue(VMFrame &f, JSType hint, Value &v, int n) +{ + JS_ASSERT(v.isObject()); + if (!DefaultValue(f.cx, &v.toObject(), hint, &f.regs.sp[n])) + return false; + v = f.regs.sp[n]; + return true; +} + +void JS_FASTCALL +stubs::Add(VMFrame &f) +{ + JSContext *cx = f.cx; + JSFrameRegs ®s = f.regs; + Value rval = regs.sp[-1]; + Value lval = regs.sp[-2]; + + /* The string + string case is easily the hottest; try it first. */ + bool lIsString = lval.isString(); + bool rIsString = rval.isString(); + JSString *lstr, *rstr; + if (lIsString && rIsString) { + lstr = lval.toString(); + rstr = rval.toString(); + goto string_concat; + + } else +#if JS_HAS_XML_SUPPORT + if (lval.isObject() && lval.toObject().isXML() && + rval.isObject() && rval.toObject().isXML()) { + if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), &rval)) + THROW(); + regs.sp--; + regs.sp[-1] = rval; + } else +#endif + { + /* These can convert lval/rval to strings. */ + if (lval.isObject() && !DefaultValue(f, JSTYPE_VOID, lval, -2)) + THROW(); + if (rval.isObject() && !DefaultValue(f, JSTYPE_VOID, rval, -1)) + THROW(); + if ((lIsString = lval.isString()) || (rIsString = rval.isString())) { + if (lIsString) { + lstr = lval.toString(); + } else { + lstr = js_ValueToString(cx, lval); + if (!lstr) + THROW(); + regs.sp[-2].setString(lstr); + } + if (rIsString) { + rstr = rval.toString(); + } else { + rstr = js_ValueToString(cx, rval); + if (!rstr) + THROW(); + regs.sp[-1].setString(rstr); + } + goto string_concat; + + } else { + double l, r; + if (!ValueToNumber(cx, lval, &l) || !ValueToNumber(cx, rval, &r)) + THROW(); + l += r; + regs.sp--; + regs.sp[-1].setNumber(l); + } + } + return; + + string_concat: + JSString *str = js_ConcatStrings(cx, lstr, rstr); + if (!str) + THROW(); + regs.sp--; + regs.sp[-1].setString(str); +} + + +void JS_FASTCALL +stubs::Sub(VMFrame &f) +{ + JSContext *cx = f.cx; + JSFrameRegs ®s = f.regs; + double d1, d2; + if (!ValueToNumber(cx, regs.sp[-2], &d1) || + !ValueToNumber(cx, regs.sp[-1], &d2)) { + THROW(); + } + double d = d1 - d2; + regs.sp[-2].setNumber(d); +} + +void JS_FASTCALL +stubs::Mul(VMFrame &f) +{ + JSContext *cx = f.cx; + JSFrameRegs ®s = f.regs; + double d1, d2; + if (!ValueToNumber(cx, regs.sp[-2], &d1) || + !ValueToNumber(cx, regs.sp[-1], &d2)) { + THROW(); + } + double d = d1 * d2; + regs.sp[-2].setNumber(d); +} + +void JS_FASTCALL +stubs::Div(VMFrame &f) +{ + JSContext *cx = f.cx; + JSRuntime *rt = cx->runtime; + JSFrameRegs ®s = f.regs; + + double d1, d2; + if (!ValueToNumber(cx, regs.sp[-2], &d1) || + !ValueToNumber(cx, regs.sp[-1], &d2)) { + THROW(); + } + if (d2 == 0) { + const Value *vp; +#ifdef XP_WIN + /* XXX MSVC miscompiles such that (NaN == 0) */ + if (JSDOUBLE_IS_NaN(d2)) + vp = &rt->NaNValue; + else +#endif + if (d1 == 0 || JSDOUBLE_IS_NaN(d1)) + vp = &rt->NaNValue; + else if (JSDOUBLE_IS_NEG(d1) != JSDOUBLE_IS_NEG(d2)) + vp = &rt->negativeInfinityValue; + else + vp = &rt->positiveInfinityValue; + regs.sp[-2] = *vp; + } else { + d1 /= d2; + regs.sp[-2].setNumber(d1); + } +} + +void JS_FASTCALL +stubs::Mod(VMFrame &f) +{ + JSContext *cx = f.cx; + JSFrameRegs ®s = f.regs; + + Value &lref = regs.sp[-2]; + Value &rref = regs.sp[-1]; + int32_t l, r; + if (lref.isInt32() && rref.isInt32() && + (l = lref.toInt32()) >= 0 && (r = rref.toInt32()) > 0) { + int32_t mod = l % r; + regs.sp[-2].setInt32(mod); + } else { + double d1, d2; + if (!ValueToNumber(cx, regs.sp[-2], &d1) || + !ValueToNumber(cx, regs.sp[-1], &d2)) { + THROW(); + } + if (d2 == 0) { + regs.sp[-2].setDouble(js_NaN); + } else { + d1 = js_fmod(d1, d2); + regs.sp[-2].setDouble(d1); + } + } +} + +void JS_FASTCALL +stubs::Debugger(VMFrame &f, jsbytecode *pc) +{ + JSDebuggerHandler handler = f.cx->debugHooks->debuggerHandler; + if (handler) { + Value rval; + switch (handler(f.cx, f.cx->fp()->script(), pc, Jsvalify(&rval), + f.cx->debugHooks->debuggerHandlerData)) { + case JSTRAP_THROW: + f.cx->setPendingException(rval); + THROW(); + + case JSTRAP_RETURN: + f.cx->clearPendingException(); + f.cx->fp()->setReturnValue(rval); +#if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64) + *f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *, + f.cx->jaegerCompartment()->forceReturnFastTrampoline()); +#else + *f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *, + f.cx->jaegerCompartment()->forceReturnTrampoline()); +#endif + break; + + case JSTRAP_ERROR: + f.cx->clearPendingException(); + THROW(); + + default: + break; + } + } +} + +void JS_FASTCALL +stubs::Interrupt(VMFrame &f, jsbytecode *pc) +{ + if (!js_HandleExecutionInterrupt(f.cx)) + THROW(); +} + +void JS_FASTCALL +stubs::Trap(VMFrame &f, uint32 trapTypes) +{ + Value rval; + jsbytecode *pc = f.cx->regs->pc; + + /* + * Trap may be called for a single-step interrupt trap and/or a + * regular trap. Try the single-step first, and if it lets control + * flow through or does not exist, do the regular trap. + */ + JSTrapStatus result = JSTRAP_CONTINUE; + if (trapTypes & JSTRAP_SINGLESTEP) { + /* + * single step mode may be paused without recompiling by + * setting the interruptHook to NULL. + */ + JSInterruptHook hook = f.cx->debugHooks->interruptHook; + if (hook) + result = hook(f.cx, f.cx->fp()->script(), pc, Jsvalify(&rval), + f.cx->debugHooks->interruptHookData); + } + + if (result == JSTRAP_CONTINUE && (trapTypes & JSTRAP_TRAP)) + result = JS_HandleTrap(f.cx, f.cx->fp()->script(), pc, Jsvalify(&rval)); + + switch (result) { + case JSTRAP_THROW: + f.cx->setPendingException(rval); + THROW(); + + case JSTRAP_RETURN: + f.cx->clearPendingException(); + f.cx->fp()->setReturnValue(rval); +#if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64) + *f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *, + f.cx->jaegerCompartment()->forceReturnFastTrampoline()); +#else + *f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *, + f.cx->jaegerCompartment()->forceReturnTrampoline()); +#endif + break; + + case JSTRAP_ERROR: + f.cx->clearPendingException(); + THROW(); + + default: + break; + } +} + +void JS_FASTCALL +stubs::This(VMFrame &f) +{ + if (!f.fp()->computeThis(f.cx)) + THROW(); + f.regs.sp[-1] = f.fp()->thisValue(); +} + +void JS_FASTCALL +stubs::Neg(VMFrame &f) +{ + double d; + if (!ValueToNumber(f.cx, f.regs.sp[-1], &d)) + THROW(); + d = -d; + f.regs.sp[-1].setNumber(d); +} + +JSObject * JS_FASTCALL +stubs::NewInitArray(VMFrame &f, uint32 count) +{ + JSObject *obj = NewDenseAllocatedArray(f.cx, count); + if (!obj) + THROWV(NULL); + + return obj; +} + +JSObject * JS_FASTCALL +stubs::NewInitObject(VMFrame &f, JSObject *baseobj) +{ + JSContext *cx = f.cx; + + if (!baseobj) { + gc::FinalizeKind kind = GuessObjectGCKind(0, false); + JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind); + if (!obj) + THROWV(NULL); + return obj; + } + + JSObject *obj = CopyInitializerObject(cx, baseobj); + + if (!obj) + THROWV(NULL); + return obj; +} + +void JS_FASTCALL +stubs::InitElem(VMFrame &f, uint32 last) +{ + JSContext *cx = f.cx; + JSFrameRegs ®s = f.regs; + + /* Pop the element's value into rval. */ + JS_ASSERT(regs.sp - f.fp()->base() >= 3); + const Value &rref = regs.sp[-1]; + + /* Find the object being initialized at top of stack. */ + const Value &lref = regs.sp[-3]; + JS_ASSERT(lref.isObject()); + JSObject *obj = &lref.toObject(); + + /* Fetch id now that we have obj. */ + jsid id; + const Value &idval = regs.sp[-2]; + if (!FetchElementId(f, obj, idval, id, ®s.sp[-2])) + THROW(); + + /* + * If rref is a hole, do not call JSObject::defineProperty. In this case, + * obj must be an array, so if the current op is the last element + * initialiser, set the array length to one greater than id. + */ + if (rref.isMagic(JS_ARRAY_HOLE)) { + JS_ASSERT(obj->isArray()); + JS_ASSERT(JSID_IS_INT(id)); + JS_ASSERT(jsuint(JSID_TO_INT(id)) < JS_ARGS_LENGTH_MAX); + if (last && !js_SetLengthProperty(cx, obj, (jsuint) (JSID_TO_INT(id) + 1))) + THROW(); + } else { + if (!obj->defineProperty(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE)) + THROW(); + } +} + +void JS_FASTCALL +stubs::GetUpvar(VMFrame &f, uint32 ck) +{ + /* :FIXME: We can do better, this stub isn't needed. */ + uint32 staticLevel = f.fp()->script()->staticLevel; + UpvarCookie cookie; + cookie.fromInteger(ck); + f.regs.sp[0] = GetUpvar(f.cx, staticLevel, cookie); +} + +JSObject * JS_FASTCALL +stubs::DefLocalFun(VMFrame &f, JSFunction *fun) +{ + /* + * Define a local function (i.e., one nested at the top level of another + * function), parented by the current scope chain, stored in a local + * variable slot that the compiler allocated. This is an optimization over + * JSOP_DEFFUN that avoids requiring a call object for the outer function's + * activation. + */ + JS_ASSERT(fun->isInterpreted()); + JS_ASSERT(!FUN_FLAT_CLOSURE(fun)); + JSObject *obj = FUN_OBJECT(fun); + + if (FUN_NULL_CLOSURE(fun)) { + obj = CloneFunctionObject(f.cx, fun, &f.fp()->scopeChain()); + if (!obj) + THROWV(NULL); + } else { + JSObject *parent = GetScopeChainFast(f.cx, f.fp(), JSOP_DEFLOCALFUN, + JSOP_DEFLOCALFUN_LENGTH); + if (!parent) + THROWV(NULL); + + if (obj->getParent() != parent) { + obj = CloneFunctionObject(f.cx, fun, parent); + if (!obj) + THROWV(NULL); + } + } + + return obj; +} + +JSObject * JS_FASTCALL +stubs::DefLocalFun_FC(VMFrame &f, JSFunction *fun) +{ + JSObject *obj = js_NewFlatClosure(f.cx, fun, JSOP_DEFLOCALFUN_FC, JSOP_DEFLOCALFUN_FC_LENGTH); + if (!obj) + THROWV(NULL); + return obj; +} + +JSObject * JS_FASTCALL +stubs::RegExp(VMFrame &f, JSObject *regex) +{ + /* + * Push a regexp object cloned from the regexp literal object mapped by the + * bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was + * flouted by many browser-based implementations. + * + * We avoid the GetScopeChain call here and pass fp->scopeChain() as + * js_GetClassPrototype uses the latter only to locate the global. + */ + JSObject *proto; + if (!js_GetClassPrototype(f.cx, &f.fp()->scopeChain(), JSProto_RegExp, &proto)) + THROWV(NULL); + JS_ASSERT(proto); + JSObject *obj = js_CloneRegExpObject(f.cx, regex, proto); + if (!obj) + THROWV(NULL); + return obj; +} + +JSObject * JS_FASTCALL +stubs::LambdaForInit(VMFrame &f, JSFunction *fun) +{ + JSObject *obj = FUN_OBJECT(fun); + if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) { + fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(f.regs.pc))); + return obj; + } + return Lambda(f, fun); +} + +JSObject * JS_FASTCALL +stubs::LambdaForSet(VMFrame &f, JSFunction *fun) +{ + JSObject *obj = FUN_OBJECT(fun); + if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) { + const Value &lref = f.regs.sp[-1]; + if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) { + fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(f.regs.pc))); + return obj; + } + } + return Lambda(f, fun); +} + +JSObject * JS_FASTCALL +stubs::LambdaJoinableForCall(VMFrame &f, JSFunction *fun) +{ + JSObject *obj = FUN_OBJECT(fun); + if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) { + /* + * Array.prototype.sort and String.prototype.replace are + * optimized as if they are special form. We know that they + * won't leak the joined function object in obj, therefore + * we don't need to clone that compiler- created function + * object for identity/mutation reasons. + */ + int iargc = GET_ARGC(f.regs.pc); + + /* + * Note that we have not yet pushed obj as the final argument, + * so regs.sp[1 - (iargc + 2)], and not regs.sp[-(iargc + 2)], + * is the callee for this JSOP_CALL. + */ + const Value &cref = f.regs.sp[1 - (iargc + 2)]; + JSObject *callee; + + if (IsFunctionObject(cref, &callee)) { + JSFunction *calleeFun = callee->getFunctionPrivate(); + Native native = calleeFun->maybeNative(); + + if (native) { + if (iargc == 1 && native == array_sort) + return obj; + if (iargc == 2 && native == str_replace) + return obj; + } + } + } + return Lambda(f, fun); +} + +JSObject * JS_FASTCALL +stubs::LambdaJoinableForNull(VMFrame &f, JSFunction *fun) +{ + JSObject *obj = FUN_OBJECT(fun); + if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) { + jsbytecode *pc2 = f.regs.pc + JSOP_NULL_LENGTH; + JSOp op2 = JSOp(*pc2); + + if (op2 == JSOP_CALL && GET_ARGC(pc2) == 0) + return obj; + } + return Lambda(f, fun); +} + +JSObject * JS_FASTCALL +stubs::Lambda(VMFrame &f, JSFunction *fun) +{ + JSObject *obj = FUN_OBJECT(fun); + + JSObject *parent; + if (FUN_NULL_CLOSURE(fun)) { + parent = &f.fp()->scopeChain(); + } else { + parent = GetScopeChainFast(f.cx, f.fp(), JSOP_LAMBDA, JSOP_LAMBDA_LENGTH); + if (!parent) + THROWV(NULL); + } + + obj = CloneFunctionObject(f.cx, fun, parent); + if (!obj) + THROWV(NULL); + + return obj; +} + +/* Test whether v is an int in the range [-2^31 + 1, 2^31 - 2] */ +static JS_ALWAYS_INLINE bool +CanIncDecWithoutOverflow(int32_t i) +{ + return (i > JSVAL_INT_MIN) && (i < JSVAL_INT_MAX); +} + +template +static inline bool +ObjIncOp(VMFrame &f, JSObject *obj, jsid id) +{ + JSContext *cx = f.cx; + JSStackFrame *fp = f.fp(); + + f.regs.sp[0].setNull(); + f.regs.sp++; + if (!obj->getProperty(cx, id, &f.regs.sp[-1])) + return false; + + Value &ref = f.regs.sp[-1]; + int32_t tmp; + if (JS_LIKELY(ref.isInt32() && CanIncDecWithoutOverflow(tmp = ref.toInt32()))) { + if (POST) + ref.getInt32Ref() = tmp + N; + else + ref.getInt32Ref() = tmp += N; + fp->setAssigning(); + JSBool ok = obj->setProperty(cx, id, &ref, strict); + fp->clearAssigning(); + if (!ok) + return false; + + /* + * We must set regs.sp[-1] to tmp for both post and pre increments + * as the setter overwrites regs.sp[-1]. + */ + ref.setInt32(tmp); + } else { + Value v; + double d; + if (!ValueToNumber(cx, ref, &d)) + return false; + if (POST) { + ref.setDouble(d); + d += N; + } else { + d += N; + ref.setDouble(d); + } + v.setDouble(d); + fp->setAssigning(); + JSBool ok = obj->setProperty(cx, id, &v, strict); + fp->clearAssigning(); + if (!ok) + return false; + } + + return true; +} + +template +static inline bool +NameIncDec(VMFrame &f, JSObject *obj, JSAtom *origAtom) +{ + JSContext *cx = f.cx; + + JSAtom *atom; + JSObject *obj2; + JSProperty *prop; + PropertyCacheEntry *entry; + JS_PROPERTY_CACHE(cx).test(cx, f.regs.pc, obj, obj2, entry, atom); + if (!atom) { + if (obj == obj2 && entry->vword.isSlot()) { + uint32 slot = entry->vword.toSlot(); + Value &rref = obj->nativeGetSlotRef(slot); + int32_t tmp; + if (JS_LIKELY(rref.isInt32() && CanIncDecWithoutOverflow(tmp = rref.toInt32()))) { + int32_t inc = tmp + N; + if (!POST) + tmp = inc; + rref.getInt32Ref() = inc; + f.regs.sp[0].setInt32(tmp); + return true; + } + } + atom = origAtom; + } + + jsid id = ATOM_TO_JSID(atom); + if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop)) + return false; + if (!prop) { + ReportAtomNotDefined(cx, atom); + return false; + } + return ObjIncOp(f, obj, id); +} + +template +void JS_FASTCALL +stubs::PropInc(VMFrame &f, JSAtom *atom) +{ + JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-1]); + if (!obj) + THROW(); + if (!ObjIncOp<1, true, strict>(f, obj, ATOM_TO_JSID(atom))) + THROW(); + f.regs.sp[-2] = f.regs.sp[-1]; +} + +template void JS_FASTCALL stubs::PropInc(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::PropInc(VMFrame &f, JSAtom *atom); + +template +void JS_FASTCALL +stubs::PropDec(VMFrame &f, JSAtom *atom) +{ + JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-1]); + if (!obj) + THROW(); + if (!ObjIncOp<-1, true, strict>(f, obj, ATOM_TO_JSID(atom))) + THROW(); + f.regs.sp[-2] = f.regs.sp[-1]; +} + +template void JS_FASTCALL stubs::PropDec(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::PropDec(VMFrame &f, JSAtom *atom); + +template +void JS_FASTCALL +stubs::IncProp(VMFrame &f, JSAtom *atom) +{ + JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-1]); + if (!obj) + THROW(); + if (!ObjIncOp<1, false, strict>(f, obj, ATOM_TO_JSID(atom))) + THROW(); + f.regs.sp[-2] = f.regs.sp[-1]; +} + +template void JS_FASTCALL stubs::IncProp(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::IncProp(VMFrame &f, JSAtom *atom); + +template +void JS_FASTCALL +stubs::DecProp(VMFrame &f, JSAtom *atom) +{ + JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-1]); + if (!obj) + THROW(); + if (!ObjIncOp<-1, false, strict>(f, obj, ATOM_TO_JSID(atom))) + THROW(); + f.regs.sp[-2] = f.regs.sp[-1]; +} + +template void JS_FASTCALL stubs::DecProp(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::DecProp(VMFrame &f, JSAtom *atom); + +template +void JS_FASTCALL +stubs::ElemInc(VMFrame &f) +{ + JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]); + if (!obj) + THROW(); + jsid id; + if (!FetchElementId(f, obj, f.regs.sp[-1], id, &f.regs.sp[-1])) + THROW(); + if (!ObjIncOp<1, true, strict>(f, obj, id)) + THROW(); + f.regs.sp[-3] = f.regs.sp[-1]; +} + +template void JS_FASTCALL stubs::ElemInc(VMFrame &f); +template void JS_FASTCALL stubs::ElemInc(VMFrame &f); + +template +void JS_FASTCALL +stubs::ElemDec(VMFrame &f) +{ + JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]); + if (!obj) + THROW(); + jsid id; + if (!FetchElementId(f, obj, f.regs.sp[-1], id, &f.regs.sp[-1])) + THROW(); + if (!ObjIncOp<-1, true, strict>(f, obj, id)) + THROW(); + f.regs.sp[-3] = f.regs.sp[-1]; +} + +template void JS_FASTCALL stubs::ElemDec(VMFrame &f); +template void JS_FASTCALL stubs::ElemDec(VMFrame &f); + +template +void JS_FASTCALL +stubs::IncElem(VMFrame &f) +{ + JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]); + if (!obj) + THROW(); + jsid id; + if (!FetchElementId(f, obj, f.regs.sp[-1], id, &f.regs.sp[-1])) + THROW(); + if (!ObjIncOp<1, false, strict>(f, obj, id)) + THROW(); + f.regs.sp[-3] = f.regs.sp[-1]; +} + +template void JS_FASTCALL stubs::IncElem(VMFrame &f); +template void JS_FASTCALL stubs::IncElem(VMFrame &f); + +template +void JS_FASTCALL +stubs::DecElem(VMFrame &f) +{ + JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]); + if (!obj) + THROW(); + jsid id; + if (!FetchElementId(f, obj, f.regs.sp[-1], id, &f.regs.sp[-1])) + THROW(); + if (!ObjIncOp<-1, false, strict>(f, obj, id)) + THROW(); + f.regs.sp[-3] = f.regs.sp[-1]; +} + +template void JS_FASTCALL stubs::DecElem(VMFrame &f); +template void JS_FASTCALL stubs::DecElem(VMFrame &f); + +template +void JS_FASTCALL +stubs::NameInc(VMFrame &f, JSAtom *atom) +{ + JSObject *obj = &f.fp()->scopeChain(); + if (!NameIncDec<1, true, strict>(f, obj, atom)) + THROW(); +} + +template void JS_FASTCALL stubs::NameInc(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::NameInc(VMFrame &f, JSAtom *atom); + +template +void JS_FASTCALL +stubs::NameDec(VMFrame &f, JSAtom *atom) +{ + JSObject *obj = &f.fp()->scopeChain(); + if (!NameIncDec<-1, true, strict>(f, obj, atom)) + THROW(); +} + +template void JS_FASTCALL stubs::NameDec(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::NameDec(VMFrame &f, JSAtom *atom); + +template +void JS_FASTCALL +stubs::IncName(VMFrame &f, JSAtom *atom) +{ + JSObject *obj = &f.fp()->scopeChain(); + if (!NameIncDec<1, false, strict>(f, obj, atom)) + THROW(); +} + +template void JS_FASTCALL stubs::IncName(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::IncName(VMFrame &f, JSAtom *atom); + +template +void JS_FASTCALL +stubs::DecName(VMFrame &f, JSAtom *atom) +{ + JSObject *obj = &f.fp()->scopeChain(); + if (!NameIncDec<-1, false, strict>(f, obj, atom)) + THROW(); +} + +template void JS_FASTCALL stubs::DecName(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::DecName(VMFrame &f, JSAtom *atom); + +template +void JS_FASTCALL +stubs::GlobalNameInc(VMFrame &f, JSAtom *atom) +{ + JSObject *obj = f.fp()->scopeChain().getGlobal(); + if (!NameIncDec<1, true, strict>(f, obj, atom)) + THROW(); +} + +template void JS_FASTCALL stubs::GlobalNameInc(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::GlobalNameInc(VMFrame &f, JSAtom *atom); + +template +void JS_FASTCALL +stubs::GlobalNameDec(VMFrame &f, JSAtom *atom) +{ + JSObject *obj = f.fp()->scopeChain().getGlobal(); + if (!NameIncDec<-1, true, strict>(f, obj, atom)) + THROW(); +} + +template void JS_FASTCALL stubs::GlobalNameDec(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::GlobalNameDec(VMFrame &f, JSAtom *atom); + +template +void JS_FASTCALL +stubs::IncGlobalName(VMFrame &f, JSAtom *atom) +{ + JSObject *obj = f.fp()->scopeChain().getGlobal(); + if (!NameIncDec<1, false, strict>(f, obj, atom)) + THROW(); +} + +template void JS_FASTCALL stubs::IncGlobalName(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::IncGlobalName(VMFrame &f, JSAtom *atom); + +template +void JS_FASTCALL +stubs::DecGlobalName(VMFrame &f, JSAtom *atom) +{ + JSObject *obj = f.fp()->scopeChain().getGlobal(); + if (!NameIncDec<-1, false, strict>(f, obj, atom)) + THROW(); +} + +template void JS_FASTCALL stubs::DecGlobalName(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::DecGlobalName(VMFrame &f, JSAtom *atom); + +static bool JS_FASTCALL +InlineGetProp(VMFrame &f) +{ + JSContext *cx = f.cx; + JSFrameRegs ®s = f.regs; + + Value *vp = &f.regs.sp[-1]; + JSObject *obj = ValueToObject(f.cx, vp); + if (!obj) + return false; + + Value rval; + do { + /* + * We do not impose the method read barrier if in an imacro, + * assuming any property gets it does (e.g., for 'toString' + * from JSOP_NEW) will not be leaked to the calling script. + */ + JSObject *aobj = js_GetProtoIfDenseArray(obj); + + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); + if (!atom) { + if (entry->vword.isFunObj()) { + rval.setObject(entry->vword.toFunObj()); + } else if (entry->vword.isSlot()) { + uint32 slot = entry->vword.toSlot(); + rval = obj2->nativeGetSlot(slot); + } else { + JS_ASSERT(entry->vword.isShape()); + const Shape *shape = entry->vword.toShape(); + NATIVE_GET(cx, obj, obj2, shape, + f.fp()->hasImacropc() ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER, + &rval, return false); + } + break; + } + + jsid id = ATOM_TO_JSID(atom); + if (JS_LIKELY(!aobj->getOps()->getProperty) + ? !js_GetPropertyHelper(cx, obj, id, + f.fp()->hasImacropc() + ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER + : JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER, + &rval) + : !obj->getProperty(cx, id, &rval)) { + return false; + } + } while(0); + + regs.sp[-1] = rval; + return true; +} + +void JS_FASTCALL +stubs::GetProp(VMFrame &f) +{ + if (!InlineGetProp(f)) + THROW(); +} + +void JS_FASTCALL +stubs::GetPropNoCache(VMFrame &f, JSAtom *atom) +{ + JSContext *cx = f.cx; + + Value *vp = &f.regs.sp[-1]; + JSObject *obj = ValueToObject(cx, vp); + if (!obj) + THROW(); + + if (!obj->getProperty(cx, ATOM_TO_JSID(atom), vp)) + THROW(); +} + +void JS_FASTCALL +stubs::CallProp(VMFrame &f, JSAtom *origAtom) +{ + JSContext *cx = f.cx; + JSFrameRegs ®s = f.regs; + + Value lval; + lval = regs.sp[-1]; + + Value objv; + if (lval.isObject()) { + objv = lval; + } else { + JSProtoKey protoKey; + if (lval.isString()) { + protoKey = JSProto_String; + } else if (lval.isNumber()) { + protoKey = JSProto_Number; + } else if (lval.isBoolean()) { + protoKey = JSProto_Boolean; + } else { + JS_ASSERT(lval.isNull() || lval.isUndefined()); + js_ReportIsNullOrUndefined(cx, -1, lval, NULL); + THROW(); + } + JSObject *pobj; + if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj)) + THROW(); + objv.setObject(*pobj); + } + + JSObject *aobj = js_GetProtoIfDenseArray(&objv.toObject()); + Value rval; + + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); + if (!atom) { + if (entry->vword.isFunObj()) { + rval.setObject(entry->vword.toFunObj()); + } else if (entry->vword.isSlot()) { + uint32 slot = entry->vword.toSlot(); + rval = obj2->nativeGetSlot(slot); + } else { + JS_ASSERT(entry->vword.isShape()); + const Shape *shape = entry->vword.toShape(); + NATIVE_GET(cx, &objv.toObject(), obj2, shape, JSGET_NO_METHOD_BARRIER, &rval, + THROW()); + } + regs.sp++; + regs.sp[-2] = rval; + regs.sp[-1] = lval; + } else { + /* + * Cache miss: use the immediate atom that was loaded for us under + * PropertyCache::test. + */ + jsid id; + id = ATOM_TO_JSID(origAtom); + + regs.sp++; + regs.sp[-1].setNull(); + if (lval.isObject()) { + if (!js_GetMethod(cx, &objv.toObject(), id, + JS_LIKELY(!aobj->getOps()->getProperty) + ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER + : JSGET_NO_METHOD_BARRIER, + &rval)) { + THROW(); + } + regs.sp[-1] = objv; + regs.sp[-2] = rval; + } else { + JS_ASSERT(!objv.toObject().getOps()->getProperty); + if (!js_GetPropertyHelper(cx, &objv.toObject(), id, + JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER, + &rval)) { + THROW(); + } + regs.sp[-1] = lval; + regs.sp[-2] = rval; + } + } +#if JS_HAS_NO_SUCH_METHOD + if (JS_UNLIKELY(rval.isUndefined()) && regs.sp[-1].isObject()) { + regs.sp[-2].setString(ATOM_TO_STRING(origAtom)); + if (!js_OnUnknownMethod(cx, regs.sp - 2)) + THROW(); + } +#endif +} + +void JS_FASTCALL +stubs::Length(VMFrame &f) +{ + JSFrameRegs ®s = f.regs; + Value *vp = ®s.sp[-1]; + + if (vp->isString()) { + vp->setInt32(vp->toString()->length()); + return; + } else if (vp->isObject()) { + JSObject *obj = &vp->toObject(); + if (obj->isArray()) { + jsuint length = obj->getArrayLength(); + regs.sp[-1].setNumber(length); + return; + } else if (obj->isArguments() && !obj->isArgsLengthOverridden()) { + uint32 length = obj->getArgsInitialLength(); + JS_ASSERT(length < INT32_MAX); + regs.sp[-1].setInt32(int32_t(length)); + return; + } + } + + if (!InlineGetProp(f)) + THROW(); +} + +void JS_FASTCALL +stubs::Iter(VMFrame &f, uint32 flags) +{ + if (!js_ValueToIterator(f.cx, flags, &f.regs.sp[-1])) + THROW(); + JS_ASSERT(!f.regs.sp[-1].isPrimitive()); +} + +static void +InitPropOrMethod(VMFrame &f, JSAtom *atom, JSOp op) +{ + JSContext *cx = f.cx; + JSRuntime *rt = cx->runtime; + JSFrameRegs ®s = f.regs; + + /* Load the property's initial value into rval. */ + JS_ASSERT(regs.sp - f.fp()->base() >= 2); + Value rval; + rval = regs.sp[-1]; + + /* Load the object being initialized into lval/obj. */ + JSObject *obj = ®s.sp[-2].toObject(); + JS_ASSERT(obj->isNative()); + + /* + * Probe the property cache. + * + * We can not assume that the object created by JSOP_NEWINIT is still + * single-threaded as the debugger can access it from other threads. + * So check first. + * + * On a hit, if the cached shape has a non-default setter, it must be + * __proto__. If shape->previous() != obj->lastProperty(), there must be a + * repeated property name. The fast path does not handle these two cases. + */ + PropertyCacheEntry *entry; + const Shape *shape; + if (JS_PROPERTY_CACHE(cx).testForInit(rt, regs.pc, obj, &shape, &entry) && + shape->hasDefaultSetter() && + shape->previous() == obj->lastProperty()) + { + /* Fast path. Property cache hit. */ + uint32 slot = shape->slot; + + JS_ASSERT(slot == obj->slotSpan()); + JS_ASSERT(slot >= JSSLOT_FREE(obj->getClass())); + if (slot < obj->numSlots()) { + JS_ASSERT(obj->getSlot(slot).isUndefined()); + } else { + if (!obj->allocSlot(cx, &slot)) + THROW(); + JS_ASSERT(slot == shape->slot); + } + + /* A new object, or one we just extended in a recent initprop op. */ + JS_ASSERT(!obj->lastProperty() || + obj->shape() == obj->lastProperty()->shape); + obj->extend(cx, shape); + + /* + * No method change check here because here we are adding a new + * property, not updating an existing slot's value that might + * contain a method of a branded shape. + */ + obj->nativeSetSlot(slot, rval); + } else { + PCMETER(JS_PROPERTY_CACHE(cx).inipcmisses++); + + /* Get the immediate property name into id. */ + jsid id = ATOM_TO_JSID(atom); + + uintN defineHow = (op == JSOP_INITMETHOD) + ? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD + : JSDNP_CACHE_RESULT; + if (!(JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom) + ? js_SetPropertyHelper(cx, obj, id, defineHow, &rval, false) + : js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL, + JSPROP_ENUMERATE, 0, 0, NULL, + defineHow))) { + THROW(); + } + } +} + +void JS_FASTCALL +stubs::InitProp(VMFrame &f, JSAtom *atom) +{ + InitPropOrMethod(f, atom, JSOP_INITPROP); +} + +void JS_FASTCALL +stubs::InitMethod(VMFrame &f, JSAtom *atom) +{ + InitPropOrMethod(f, atom, JSOP_INITMETHOD); +} + +void JS_FASTCALL +stubs::IterNext(VMFrame &f) +{ + JS_ASSERT(f.regs.sp - 1 >= f.fp()->base()); + JS_ASSERT(f.regs.sp[-1].isObject()); + + JSObject *iterobj = &f.regs.sp[-1].toObject(); + f.regs.sp[0].setNull(); + f.regs.sp++; + if (!js_IteratorNext(f.cx, iterobj, &f.regs.sp[-1])) + THROW(); +} + +JSBool JS_FASTCALL +stubs::IterMore(VMFrame &f) +{ + JS_ASSERT(f.regs.sp - 1 >= f.fp()->base()); + JS_ASSERT(f.regs.sp[-1].isObject()); + + Value v; + JSObject *iterobj = &f.regs.sp[-1].toObject(); + if (!js_IteratorMore(f.cx, iterobj, &v)) + THROWV(JS_FALSE); + + return v.toBoolean(); +} + +void JS_FASTCALL +stubs::EndIter(VMFrame &f) +{ + JS_ASSERT(f.regs.sp - 1 >= f.fp()->base()); + if (!js_CloseIterator(f.cx, &f.regs.sp[-1].toObject())) + THROW(); +} + +JSString * JS_FASTCALL +stubs::TypeOf(VMFrame &f) +{ + const Value &ref = f.regs.sp[-1]; + JSType type = JS_TypeOfValue(f.cx, Jsvalify(ref)); + JSAtom *atom = f.cx->runtime->atomState.typeAtoms[type]; + return ATOM_TO_STRING(atom); +} + +void JS_FASTCALL +stubs::StrictEq(VMFrame &f) +{ + const Value &rhs = f.regs.sp[-1]; + const Value &lhs = f.regs.sp[-2]; + JSBool equal; + if (!StrictlyEqual(f.cx, lhs, rhs, &equal)) + THROW(); + f.regs.sp--; + f.regs.sp[-1].setBoolean(equal == JS_TRUE); +} + +void JS_FASTCALL +stubs::StrictNe(VMFrame &f) +{ + const Value &rhs = f.regs.sp[-1]; + const Value &lhs = f.regs.sp[-2]; + JSBool equal; + if (!StrictlyEqual(f.cx, lhs, rhs, &equal)) + THROW(); + f.regs.sp--; + f.regs.sp[-1].setBoolean(equal != JS_TRUE); +} + +void JS_FASTCALL +stubs::Throw(VMFrame &f) +{ + JSContext *cx = f.cx; + + JS_ASSERT(!cx->isExceptionPending()); + cx->setPendingException(f.regs.sp[-1]); + THROW(); +} + +JSObject * JS_FASTCALL +stubs::FlatLambda(VMFrame &f, JSFunction *fun) +{ + JSObject *obj = js_NewFlatClosure(f.cx, fun, JSOP_LAMBDA_FC, JSOP_LAMBDA_FC_LENGTH); + if (!obj) + THROWV(NULL); + return obj; +} + +void JS_FASTCALL +stubs::Arguments(VMFrame &f) +{ + f.regs.sp++; + if (!js_GetArgsValue(f.cx, f.fp(), &f.regs.sp[-1])) + THROW(); +} + +JSBool JS_FASTCALL +stubs::InstanceOf(VMFrame &f) +{ + JSContext *cx = f.cx; + JSFrameRegs ®s = f.regs; + + const Value &rref = regs.sp[-1]; + if (rref.isPrimitive()) { + js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, + -1, rref, NULL); + THROWV(JS_FALSE); + } + JSObject *obj = &rref.toObject(); + const Value &lref = regs.sp[-2]; + JSBool cond = JS_FALSE; + if (!HasInstance(cx, obj, &lref, &cond)) + THROWV(JS_FALSE); + f.regs.sp[-2].setBoolean(cond); + return cond; +} + +void JS_FASTCALL +stubs::FastInstanceOf(VMFrame &f) +{ + const Value &lref = f.regs.sp[-1]; + + if (lref.isPrimitive()) { + /* + * Throw a runtime error if instanceof is called on a function that + * has a non-object as its .prototype value. + */ + js_ReportValueError(f.cx, JSMSG_BAD_PROTOTYPE, -1, f.regs.sp[-2], NULL); + THROW(); + } + + f.regs.sp[-3].setBoolean(js_IsDelegate(f.cx, &lref.toObject(), f.regs.sp[-3])); +} + +void JS_FASTCALL +stubs::ArgCnt(VMFrame &f) +{ + JSContext *cx = f.cx; + JSRuntime *rt = cx->runtime; + JSStackFrame *fp = f.fp(); + + jsid id = ATOM_TO_JSID(rt->atomState.lengthAtom); + f.regs.sp++; + if (!js_GetArgsProperty(cx, fp, id, &f.regs.sp[-1])) + THROW(); +} + +void JS_FASTCALL +stubs::EnterBlock(VMFrame &f, JSObject *obj) +{ + JSFrameRegs ®s = f.regs; +#ifdef DEBUG + JSStackFrame *fp = f.fp(); +#endif + + JS_ASSERT(obj->isStaticBlock()); + JS_ASSERT(fp->base() + OBJ_BLOCK_DEPTH(cx, obj) == regs.sp); + Value *vp = regs.sp + OBJ_BLOCK_COUNT(cx, obj); + JS_ASSERT(regs.sp < vp); + JS_ASSERT(vp <= fp->slots() + fp->script()->nslots); + SetValueRangeToUndefined(regs.sp, vp); + regs.sp = vp; + +#ifdef DEBUG + JSContext *cx = f.cx; + + /* + * The young end of fp->scopeChain() may omit blocks if we haven't closed + * over them, but if there are any closure blocks on fp->scopeChain(), they'd + * better be (clones of) ancestors of the block we're entering now; + * anything else we should have popped off fp->scopeChain() when we left its + * static scope. + */ + JSObject *obj2 = &fp->scopeChain(); + Class *clasp; + while ((clasp = obj2->getClass()) == &js_WithClass) + obj2 = obj2->getParent(); + if (clasp == &js_BlockClass && + obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, fp)) { + JSObject *youngestProto = obj2->getProto(); + JS_ASSERT(youngestProto->isStaticBlock()); + JSObject *parent = obj; + while ((parent = parent->getParent()) != youngestProto) + JS_ASSERT(parent); + } +#endif +} + +void JS_FASTCALL +stubs::LeaveBlock(VMFrame &f, JSObject *blockChain) +{ + JSContext *cx = f.cx; + JSStackFrame *fp = f.fp(); + +#ifdef DEBUG + JS_ASSERT(blockChain->isStaticBlock()); + uintN blockDepth = OBJ_BLOCK_DEPTH(cx, blockChain); + + JS_ASSERT(blockDepth <= StackDepth(fp->script())); +#endif + /* + * If we're about to leave the dynamic scope of a block that has been + * cloned onto fp->scopeChain(), clear its private data, move its locals from + * the stack into the clone, and pop it off the chain. + */ + JSObject *obj = &fp->scopeChain(); + if (obj->getProto() == blockChain) { + JS_ASSERT(obj->getClass() == &js_BlockClass); + if (!js_PutBlockObject(cx, JS_TRUE)) + THROW(); + } +} + +void * JS_FASTCALL +stubs::LookupSwitch(VMFrame &f, jsbytecode *pc) +{ + jsbytecode *jpc = pc; + JSScript *script = f.fp()->script(); + bool ctor = f.fp()->isConstructing(); + + /* This is correct because the compiler adjusts the stack beforehand. */ + Value lval = f.regs.sp[-1]; + + if (!lval.isPrimitive()) { + void* native = script->nativeCodeForPC(ctor, pc + GET_JUMP_OFFSET(pc)); + JS_ASSERT(native); + return native; + } + + JS_ASSERT(pc[0] == JSOP_LOOKUPSWITCH); + + pc += JUMP_OFFSET_LEN; + uint32 npairs = GET_UINT16(pc); + pc += UINT16_LEN; + + JS_ASSERT(npairs); + + if (lval.isString()) { + JSLinearString *str = lval.toString()->ensureLinear(f.cx); + if (!str) + THROWV(NULL); + for (uint32 i = 1; i <= npairs; i++) { + Value rval = script->getConst(GET_INDEX(pc)); + pc += INDEX_LEN; + if (rval.isString()) { + JSLinearString *rhs = rval.toString()->assertIsLinear(); + if (rhs == str || EqualStrings(str, rhs)) { + void* native = script->nativeCodeForPC(ctor, + jpc + GET_JUMP_OFFSET(pc)); + JS_ASSERT(native); + return native; + } + } + pc += JUMP_OFFSET_LEN; + } + } else if (lval.isNumber()) { + double d = lval.toNumber(); + for (uint32 i = 1; i <= npairs; i++) { + Value rval = script->getConst(GET_INDEX(pc)); + pc += INDEX_LEN; + if (rval.isNumber() && d == rval.toNumber()) { + void* native = script->nativeCodeForPC(ctor, + jpc + GET_JUMP_OFFSET(pc)); + JS_ASSERT(native); + return native; + } + pc += JUMP_OFFSET_LEN; + } + } else { + for (uint32 i = 1; i <= npairs; i++) { + Value rval = script->getConst(GET_INDEX(pc)); + pc += INDEX_LEN; + if (lval == rval) { + void* native = script->nativeCodeForPC(ctor, + jpc + GET_JUMP_OFFSET(pc)); + JS_ASSERT(native); + return native; + } + pc += JUMP_OFFSET_LEN; + } + } + + void* native = script->nativeCodeForPC(ctor, jpc + GET_JUMP_OFFSET(jpc)); + JS_ASSERT(native); + return native; +} + +void * JS_FASTCALL +stubs::TableSwitch(VMFrame &f, jsbytecode *origPc) +{ + jsbytecode * const originalPC = origPc; + jsbytecode *pc = originalPC; + uint32 jumpOffset = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + + /* Note: compiler adjusts the stack beforehand. */ + Value rval = f.regs.sp[-1]; + + jsint tableIdx; + if (rval.isInt32()) { + tableIdx = rval.toInt32(); + } else if (rval.isDouble()) { + double d = rval.toDouble(); + if (d == 0) { + /* Treat -0 (double) as 0. */ + tableIdx = 0; + } else if (!JSDOUBLE_IS_INT32(d, (int32_t *)&tableIdx)) { + goto finally; + } + } else { + goto finally; + } + + { + jsint low = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + jsint high = GET_JUMP_OFFSET(pc); + pc += JUMP_OFFSET_LEN; + + tableIdx -= low; + if ((jsuint) tableIdx < (jsuint)(high - low + 1)) { + pc += JUMP_OFFSET_LEN * tableIdx; + uint32 candidateOffset = GET_JUMP_OFFSET(pc); + if (candidateOffset) + jumpOffset = candidateOffset; + } + } + +finally: + /* Provide the native address. */ + JSScript* script = f.fp()->script(); + void* native = script->nativeCodeForPC(f.fp()->isConstructing(), + originalPC + jumpOffset); + JS_ASSERT(native); + return native; +} + +void JS_FASTCALL +stubs::Unbrand(VMFrame &f) +{ + const Value &thisv = f.regs.sp[-1]; + if (!thisv.isObject()) + return; + JSObject *obj = &thisv.toObject(); + if (obj->isNative()) + obj->unbrand(f.cx); +} + +void JS_FASTCALL +stubs::Pos(VMFrame &f) +{ + if (!ValueToNumber(f.cx, &f.regs.sp[-1])) + THROW(); +} + +void JS_FASTCALL +stubs::ArgSub(VMFrame &f, uint32 n) +{ + jsid id = INT_TO_JSID(n); + Value rval; + if (!js_GetArgsProperty(f.cx, f.fp(), id, &rval)) + THROW(); + f.regs.sp[0] = rval; +} + +void JS_FASTCALL +stubs::DelName(VMFrame &f, JSAtom *atom) +{ + jsid id = ATOM_TO_JSID(atom); + JSObject *obj, *obj2; + JSProperty *prop; + if (!js_FindProperty(f.cx, id, &obj, &obj2, &prop)) + THROW(); + + /* Strict mode code should never contain JSOP_DELNAME opcodes. */ + JS_ASSERT(!f.fp()->script()->strictModeCode); + + /* ECMA says to return true if name is undefined or inherited. */ + f.regs.sp++; + f.regs.sp[-1] = BooleanValue(true); + if (prop) { + if (!obj->deleteProperty(f.cx, id, &f.regs.sp[-1], false)) + THROW(); + } +} + +template +void JS_FASTCALL +stubs::DelProp(VMFrame &f, JSAtom *atom) +{ + JSContext *cx = f.cx; + + JSObject *obj = ValueToObject(cx, &f.regs.sp[-1]); + if (!obj) + THROW(); + + Value rval; + if (!obj->deleteProperty(cx, ATOM_TO_JSID(atom), &rval, strict)) + THROW(); + + f.regs.sp[-1] = rval; +} + +template void JS_FASTCALL stubs::DelProp(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL stubs::DelProp(VMFrame &f, JSAtom *atom); + +template +void JS_FASTCALL +stubs::DelElem(VMFrame &f) +{ + JSContext *cx = f.cx; + + JSObject *obj = ValueToObject(cx, &f.regs.sp[-2]); + if (!obj) + THROW(); + + jsid id; + if (!FetchElementId(f, obj, f.regs.sp[-1], id, &f.regs.sp[-1])) + THROW(); + + if (!obj->deleteProperty(cx, id, &f.regs.sp[-2], strict)) + THROW(); +} + +void JS_FASTCALL +stubs::DefVarOrConst(VMFrame &f, JSAtom *atom) +{ + JSContext *cx = f.cx; + JSStackFrame *fp = f.fp(); + + JSObject *obj = &fp->varobj(cx); + JS_ASSERT(!obj->getOps()->defineProperty); + uintN attrs = JSPROP_ENUMERATE; + if (!fp->isEvalFrame()) + attrs |= JSPROP_PERMANENT; + + /* Lookup id in order to check for redeclaration problems. */ + jsid id = ATOM_TO_JSID(atom); + bool shouldDefine; + if (JSOp(*f.regs.pc) == JSOP_DEFVAR) { + /* + * Redundant declaration of a |var|, even one for a non-writable + * property like |undefined| in ES5, does nothing. + */ + JSProperty *prop; + JSObject *obj2; + if (!obj->lookupProperty(cx, id, &obj2, &prop)) + THROW(); + shouldDefine = (!prop || obj2 != obj); + } else { + JS_ASSERT(JSOp(*f.regs.pc) == JSOP_DEFCONST); + attrs |= JSPROP_READONLY; + if (!CheckRedeclaration(cx, obj, id, attrs)) + THROW(); + + /* + * As attrs includes readonly, CheckRedeclaration can succeed only + * if prop does not exist. + */ + shouldDefine = true; + } + + /* Bind a variable only if it's not yet defined. */ + if (shouldDefine && + !js_DefineNativeProperty(cx, obj, id, UndefinedValue(), PropertyStub, StrictPropertyStub, + attrs, 0, 0, NULL)) { + THROW(); + } +} + +void JS_FASTCALL +stubs::SetConst(VMFrame &f, JSAtom *atom) +{ + JSContext *cx = f.cx; + JSStackFrame *fp = f.fp(); + + JSObject *obj = &fp->varobj(cx); + const Value &ref = f.regs.sp[-1]; + if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), ref, + PropertyStub, StrictPropertyStub, + JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) { + THROW(); + } +} + +JSBool JS_FASTCALL +stubs::In(VMFrame &f) +{ + JSContext *cx = f.cx; + + const Value &rref = f.regs.sp[-1]; + if (!rref.isObject()) { + js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL); + THROWV(JS_FALSE); + } + + JSObject *obj = &rref.toObject(); + jsid id; + if (!FetchElementId(f, obj, f.regs.sp[-2], id, &f.regs.sp[-2])) + THROWV(JS_FALSE); + + JSObject *obj2; + JSProperty *prop; + if (!obj->lookupProperty(cx, id, &obj2, &prop)) + THROWV(JS_FALSE); + + return !!prop; +} + +template void JS_FASTCALL stubs::DelElem(VMFrame &f); +template void JS_FASTCALL stubs::DelElem(VMFrame &f); + +void JS_FASTCALL +stubs::Exception(VMFrame &f) +{ + f.regs.sp[0] = f.cx->getPendingException(); + f.cx->clearPendingException(); +} +template +int32 JS_FASTCALL +stubs::ConvertToTypedInt(JSContext *cx, Value *vp) +{ + JS_ASSERT(!vp->isInt32()); + + if (vp->isDouble()) { + if (Clamped) + return js_TypedArray_uint8_clamp_double(vp->toDouble()); + return js_DoubleToECMAInt32(vp->toDouble()); + } + + if (vp->isNull() || vp->isObject() || vp->isUndefined()) + return 0; + + if (vp->isBoolean()) + return vp->toBoolean() ? 1 : 0; + + JS_ASSERT(vp->isString()); + + int32 i32 = 0; +#ifdef DEBUG + bool success = +#endif + StringToNumberType(cx, vp->toString(), &i32); + JS_ASSERT(success); + + return i32; +} + +template int32 JS_FASTCALL stubs::ConvertToTypedInt(JSContext *, Value *); +template int32 JS_FASTCALL stubs::ConvertToTypedInt(JSContext *, Value *); + +void JS_FASTCALL +stubs::ConvertToTypedFloat(JSContext *cx, Value *vp) +{ + JS_ASSERT(!vp->isDouble() && !vp->isInt32()); + + if (vp->isNull()) { + vp->setDouble(0); + } else if (vp->isObject() || vp->isUndefined()) { + vp->setDouble(js_NaN); + } else if (vp->isBoolean()) { + vp->setDouble(vp->toBoolean() ? 1 : 0); + } else { + JS_ASSERT(vp->isString()); + double d = 0; +#ifdef DEBUG + bool success = +#endif + StringToNumberType(cx, vp->toString(), &d); + JS_ASSERT(success); + vp->setDouble(d); + } +} + diff --git a/js/src/methodjit/StubCalls.h b/js/src/methodjit/StubCalls.h new file mode 100644 index 0000000..a58436b --- /dev/null +++ b/js/src/methodjit/StubCalls.h @@ -0,0 +1,243 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jslogic_h__ +#define jslogic_h__ + +#include "MethodJIT.h" + +namespace js { +namespace mjit { +namespace stubs { + +typedef enum JSTrapType { + JSTRAP_NONE = 0, + JSTRAP_TRAP = 1, + JSTRAP_SINGLESTEP = 2 +} JSTrapType; + +void JS_FASTCALL This(VMFrame &f); +JSObject * JS_FASTCALL NewInitArray(VMFrame &f, uint32 count); +JSObject * JS_FASTCALL NewInitObject(VMFrame &f, JSObject *base); +void JS_FASTCALL Trap(VMFrame &f, uint32 trapTypes); +void JS_FASTCALL Debugger(VMFrame &f, jsbytecode *pc); +void JS_FASTCALL Interrupt(VMFrame &f, jsbytecode *pc); +void JS_FASTCALL InitElem(VMFrame &f, uint32 last); +void JS_FASTCALL InitProp(VMFrame &f, JSAtom *atom); +void JS_FASTCALL InitMethod(VMFrame &f, JSAtom *atom); + +void JS_FASTCALL HitStackQuota(VMFrame &f); +void * JS_FASTCALL FixupArity(VMFrame &f, uint32 argc); +void * JS_FASTCALL CompileFunction(VMFrame &f, uint32 argc); +void JS_FASTCALL SlowNew(VMFrame &f, uint32 argc); +void JS_FASTCALL SlowCall(VMFrame &f, uint32 argc); +void * JS_FASTCALL UncachedNew(VMFrame &f, uint32 argc); +void * JS_FASTCALL UncachedCall(VMFrame &f, uint32 argc); +void JS_FASTCALL Eval(VMFrame &f, uint32 argc); +void JS_FASTCALL EnterScript(VMFrame &f); +void JS_FASTCALL LeaveScript(VMFrame &f); + +/* + * Result struct for UncachedXHelper. + * + * These functions can have one of two results: + * + * (1) The function was executed in the interpreter. Then all fields + * are NULL except unjittable. + * + * (2) The function was not executed, and the function has been compiled + * to JM native code. Then all fields are non-NULL. + */ +struct UncachedCallResult { + JSObject *callee; // callee object + JSFunction *fun; // callee function + void *codeAddr; // code address of compiled callee function + bool unjittable; // did we try to JIT and fail? + + void init() { + callee = NULL; + fun = NULL; + codeAddr = NULL; + unjittable = false; + } +}; + +/* + * Helper functions for stubs and IC functions for calling functions. + * These functions either execute the function, return a native code + * pointer that can be used to call the function, or throw. + */ +void UncachedCallHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr); +void UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr); + +void JS_FASTCALL CreateThis(VMFrame &f, JSObject *proto); +void JS_FASTCALL Throw(VMFrame &f); +void JS_FASTCALL PutStrictEvalCallObject(VMFrame &f); +void JS_FASTCALL PutActivationObjects(VMFrame &f); +void JS_FASTCALL GetCallObject(VMFrame &f); +#if JS_MONOIC +void * JS_FASTCALL InvokeTracer(VMFrame &f, ic::TraceICInfo *tic); +#else +void * JS_FASTCALL InvokeTracer(VMFrame &f); +#endif + +void * JS_FASTCALL LookupSwitch(VMFrame &f, jsbytecode *pc); +void * JS_FASTCALL TableSwitch(VMFrame &f, jsbytecode *origPc); + +void JS_FASTCALL BindName(VMFrame &f); +void JS_FASTCALL BindNameNoCache(VMFrame &f, JSAtom *atom); +JSObject * JS_FASTCALL BindGlobalName(VMFrame &f); +template void JS_FASTCALL SetName(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL SetPropNoCache(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL SetGlobalName(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL SetGlobalNameNoCache(VMFrame &f, JSAtom *atom); +void JS_FASTCALL Name(VMFrame &f); +void JS_FASTCALL GetProp(VMFrame &f); +void JS_FASTCALL GetPropNoCache(VMFrame &f, JSAtom *atom); +void JS_FASTCALL GetElem(VMFrame &f); +void JS_FASTCALL CallElem(VMFrame &f); +template void JS_FASTCALL SetElem(VMFrame &f); +void JS_FASTCALL Length(VMFrame &f); +void JS_FASTCALL CallName(VMFrame &f); +void JS_FASTCALL PushImplicitThisForGlobal(VMFrame &f); +void JS_FASTCALL GetUpvar(VMFrame &f, uint32 index); +void JS_FASTCALL GetGlobalName(VMFrame &f); + +template void JS_FASTCALL NameInc(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL NameDec(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL IncName(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL DecName(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL GlobalNameInc(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL GlobalNameDec(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL IncGlobalName(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL DecGlobalName(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL PropInc(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL PropDec(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL IncProp(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL DecProp(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL ElemInc(VMFrame &f); +template void JS_FASTCALL ElemDec(VMFrame &f); +template void JS_FASTCALL IncElem(VMFrame &f); +template void JS_FASTCALL DecElem(VMFrame &f); +void JS_FASTCALL CallProp(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL DelProp(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL DelElem(VMFrame &f); +void JS_FASTCALL DelName(VMFrame &f, JSAtom *atom); +JSBool JS_FASTCALL In(VMFrame &f); + +void JS_FASTCALL DefVarOrConst(VMFrame &f, JSAtom *atom); +void JS_FASTCALL SetConst(VMFrame &f, JSAtom *atom); +template void JS_FASTCALL DefFun(VMFrame &f, JSFunction *fun); +JSObject * JS_FASTCALL DefLocalFun(VMFrame &f, JSFunction *fun); +JSObject * JS_FASTCALL DefLocalFun_FC(VMFrame &f, JSFunction *fun); +JSObject * JS_FASTCALL RegExp(VMFrame &f, JSObject *regex); +JSObject * JS_FASTCALL Lambda(VMFrame &f, JSFunction *fun); +JSObject * JS_FASTCALL LambdaForInit(VMFrame &f, JSFunction *fun); +JSObject * JS_FASTCALL LambdaForSet(VMFrame &f, JSFunction *fun); +JSObject * JS_FASTCALL LambdaJoinableForCall(VMFrame &f, JSFunction *fun); +JSObject * JS_FASTCALL LambdaJoinableForNull(VMFrame &f, JSFunction *fun); +JSObject * JS_FASTCALL FlatLambda(VMFrame &f, JSFunction *fun); +void JS_FASTCALL Arguments(VMFrame &f); +void JS_FASTCALL ArgSub(VMFrame &f, uint32 n); +void JS_FASTCALL EnterBlock(VMFrame &f, JSObject *obj); +void JS_FASTCALL LeaveBlock(VMFrame &f, JSObject *blockChain); + +JSBool JS_FASTCALL LessThan(VMFrame &f); +JSBool JS_FASTCALL LessEqual(VMFrame &f); +JSBool JS_FASTCALL GreaterThan(VMFrame &f); +JSBool JS_FASTCALL GreaterEqual(VMFrame &f); +JSBool JS_FASTCALL Equal(VMFrame &f); +JSBool JS_FASTCALL NotEqual(VMFrame &f); + +void JS_FASTCALL BitOr(VMFrame &f); +void JS_FASTCALL BitXor(VMFrame &f); +void JS_FASTCALL BitAnd(VMFrame &f); +void JS_FASTCALL BitNot(VMFrame &f); +void JS_FASTCALL Lsh(VMFrame &f); +void JS_FASTCALL Rsh(VMFrame &f); +void JS_FASTCALL Ursh(VMFrame &f); +void JS_FASTCALL Add(VMFrame &f); +void JS_FASTCALL Sub(VMFrame &f); +void JS_FASTCALL Mul(VMFrame &f); +void JS_FASTCALL Div(VMFrame &f); +void JS_FASTCALL Mod(VMFrame &f); +void JS_FASTCALL Neg(VMFrame &f); +void JS_FASTCALL Pos(VMFrame &f); +void JS_FASTCALL Not(VMFrame &f); +void JS_FASTCALL StrictEq(VMFrame &f); +void JS_FASTCALL StrictNe(VMFrame &f); + +void JS_FASTCALL Iter(VMFrame &f, uint32 flags); +void JS_FASTCALL IterNext(VMFrame &f); +JSBool JS_FASTCALL IterMore(VMFrame &f); +void JS_FASTCALL EndIter(VMFrame &f); + +JSBool JS_FASTCALL ValueToBoolean(VMFrame &f); +JSString * JS_FASTCALL TypeOf(VMFrame &f); +JSBool JS_FASTCALL InstanceOf(VMFrame &f); +void JS_FASTCALL FastInstanceOf(VMFrame &f); +void JS_FASTCALL ArgCnt(VMFrame &f); +void JS_FASTCALL Unbrand(VMFrame &f); + +template int32 JS_FASTCALL ConvertToTypedInt(JSContext *cx, Value *vp); +void JS_FASTCALL ConvertToTypedFloat(JSContext *cx, Value *vp); + +void JS_FASTCALL Exception(VMFrame &f); + +} /* namespace stubs */ + +/* + * If COND is true, return A; otherwise, return B. This allows us to choose between + * function template instantiations without running afoul of C++'s overload resolution + * rules. (Try simplifying, and you'll either see the problem --- or have found a + * better solution!) + */ +template +inline FuncPtr FunctionTemplateConditional(bool cond, FuncPtr a, FuncPtr b) { + return cond ? a : b; +} + +}} /* namespace stubs,mjit,js */ + +extern "C" void * +js_InternalThrow(js::VMFrame &f); + +#endif /* jslogic_h__ */ + diff --git a/js/src/methodjit/StubCompiler.cpp b/js/src/methodjit/StubCompiler.cpp new file mode 100644 index 0000000..1bde460 --- /dev/null +++ b/js/src/methodjit/StubCompiler.cpp @@ -0,0 +1,224 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "StubCalls.h" +#include "StubCompiler.h" +#include "Compiler.h" +#include "assembler/assembler/LinkBuffer.h" +#include "FrameState-inl.h" + +using namespace js; +using namespace mjit; + +StubCompiler::StubCompiler(JSContext *cx, mjit::Compiler &cc, FrameState &frame, JSScript *script) +: cx(cx), + cc(cc), + frame(frame), + script(script), + generation(1), + lastGeneration(0), + exits(CompilerAllocPolicy(cx, cc)), + joins(CompilerAllocPolicy(cx, cc)), + scriptJoins(CompilerAllocPolicy(cx, cc)), + jumpList(SystemAllocPolicy()) +{ +#ifdef DEBUG + masm.setSpewPath(true); +#endif +} + +void +StubCompiler::linkExitDirect(Jump j, Label L) +{ + exits.append(CrossPatch(j, L)); +} + +JSC::MacroAssembler::Label +StubCompiler::syncExit(Uses uses) +{ + JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW MERGE CODE ---- \n"); + + if (lastGeneration == generation) { + Jump j2 = masm.jump(); + jumpList.append(j2); + } + + Label l = masm.label(); + frame.sync(masm, uses); + lastGeneration = generation; + + JaegerSpew(JSpew_Insns, " ---- END SLOW MERGE CODE ---- \n"); + + return l; +} + +JSC::MacroAssembler::Label +StubCompiler::syncExitAndJump(Uses uses) +{ + Label l = syncExit(uses); + Jump j2 = masm.jump(); + jumpList.append(j2); + /* Suppress jumping on next sync/link. */ + generation++; + return l; +} + +// Link an exit from the fast path to a slow path. This does two main things: +// (a) links the given jump to the slow path, and (b) generates a prolog for +// the slow path that syncs frame state for a slow call that uses |uses| +// values from the top of the stack. +// +// The return value is the label for the start of the merge code. This is +// the correct place to jump to in order to execute the slow path being +// generated here. +// +// Note 1: Slow path generation is interleaved with fast path generation, but +// the slow path goes into a separate buffer. The slow path code is appended +// to the fast path code to keep it nearby in code memory. +// +// Note 2: A jump from the fast path to the slow path is called an "exit". +// A jump from the slow path to the fast path is called a "rejoin". +JSC::MacroAssembler::Label +StubCompiler::linkExit(Jump j, Uses uses) +{ + Label l = syncExit(uses); + linkExitDirect(j, l); + return l; +} + +// Special version of linkExit that is used when there is a JavaScript +// control-flow branch after the slow path. Our compilation strategy +// requires the JS frame to be fully materialized in memory across branches. +// This function does a linkExit and also fully materializes the frame. +void +StubCompiler::linkExitForBranch(Jump j) +{ + Label l = syncExit(Uses(frame.frameSlots())); + linkExitDirect(j, l); +} + +void +StubCompiler::leave() +{ + JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW LEAVE CODE ---- \n"); + for (size_t i = 0; i < jumpList.length(); i++) + jumpList[i].linkTo(masm.label(), &masm); + jumpList.clear(); + generation++; + JaegerSpew(JSpew_Insns, " ---- END SLOW LEAVE CODE ---- \n"); +} + +void +StubCompiler::rejoin(Changes changes) +{ + JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW RESTORE CODE ---- \n"); + + frame.merge(masm, changes); + + Jump j = masm.jump(); + crossJump(j, cc.getLabel()); + + JaegerSpew(JSpew_Insns, " ---- END SLOW RESTORE CODE ---- \n"); +} + +void +StubCompiler::linkRejoin(Jump j) +{ + crossJump(j, cc.getLabel()); +} + +typedef JSC::MacroAssembler::RegisterID RegisterID; +typedef JSC::MacroAssembler::ImmPtr ImmPtr; +typedef JSC::MacroAssembler::Imm32 Imm32; + +JSC::MacroAssembler::Call +StubCompiler::emitStubCall(void *ptr, uint32 id) +{ + return emitStubCall(ptr, frame.stackDepth() + script->nfixed, id); +} + +JSC::MacroAssembler::Call +StubCompiler::emitStubCall(void *ptr, int32 slots, uint32 id) +{ + JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW CALL CODE ---- \n"); + Call cl = masm.fallibleVMCall(ptr, cc.getPC(), slots); + JaegerSpew(JSpew_Insns, " ---- END SLOW CALL CODE ---- \n"); + if (cc.debugMode()) { + Compiler::InternalCallSite site(masm.callReturnOffset(cl), cc.getPC(), id, true, true); + cc.addCallSite(site); + } + return cl; +} + +void +StubCompiler::fixCrossJumps(uint8 *ncode, size_t offset, size_t total) +{ + JSC::LinkBuffer fast(ncode, total); + JSC::LinkBuffer slow(ncode + offset, total - offset); + + for (size_t i = 0; i < exits.length(); i++) + fast.link(exits[i].from, slow.locationOf(exits[i].to)); + + for (size_t i = 0; i < scriptJoins.length(); i++) { + const CrossJumpInScript &cj = scriptJoins[i]; + slow.link(cj.from, fast.locationOf(cc.labelOf(cj.pc))); + } + + for (size_t i = 0; i < joins.length(); i++) + slow.link(joins[i].from, fast.locationOf(joins[i].to)); +} + +void +StubCompiler::crossJump(Jump j, Label L) +{ + joins.append(CrossPatch(j, L)); +} + +bool +StubCompiler::jumpInScript(Jump j, jsbytecode *target) +{ + if (cc.knownJump(target)) { + crossJump(j, cc.labelOf(target)); + return true; + } else { + return scriptJoins.append(CrossJumpInScript(j, target)); + } +} + diff --git a/js/src/methodjit/StubCompiler.h b/js/src/methodjit/StubCompiler.h new file mode 100644 index 0000000..e7a8ccc --- /dev/null +++ b/js/src/methodjit/StubCompiler.h @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * David Mandelin + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined(jsstub_compiler_h__) && defined(JS_METHODJIT) +#define jsstub_compiler_h__ + +#include "jscntxt.h" +#include "jstl.h" +#include "MethodJIT.h" +#include "methodjit/FrameState.h" +#include "CodeGenIncludes.h" + +namespace js { +namespace mjit { + +class Compiler; + +class StubCompiler +{ + typedef JSC::MacroAssembler::Call Call; + typedef JSC::MacroAssembler::Jump Jump; + typedef JSC::MacroAssembler::Label Label; + + struct CrossPatch { + CrossPatch(Jump from, Label to) + : from(from), to(to) + { } + + Jump from; + Label to; + }; + + struct CrossJumpInScript { + CrossJumpInScript(Jump from, jsbytecode *pc) + : from(from), pc(pc) + { } + + Jump from; + jsbytecode *pc; + }; + + JSContext *cx; + Compiler &cc; + FrameState &frame; + JSScript *script; + + public: + Assembler masm; + + private: + uint32 generation; + uint32 lastGeneration; + + Vector exits; + Vector joins; + Vector scriptJoins; + Vector jumpList; + + public: + StubCompiler(JSContext *cx, mjit::Compiler &cc, FrameState &frame, JSScript *script); + + size_t size() { + return masm.size(); + } + + uint8 *buffer() { + return masm.buffer(); + } + + /* + * Force a frame sync and return a label before the syncing code. + * A Jump may bind to the label with leaveExitDirect(). + */ + JSC::MacroAssembler::Label syncExit(Uses uses); + + /* + * Sync the exit, and state that code will be immediately outputted + * to the out-of-line buffer. + */ + JSC::MacroAssembler::Label syncExitAndJump(Uses uses); + + /* Exits from the fast path into the slow path. */ + JSC::MacroAssembler::Label linkExit(Jump j, Uses uses); + void linkExitForBranch(Jump j); + void linkExitDirect(Jump j, Label L); + + void leave(); + void leaveWithDepth(uint32 depth); + + /* + * Rejoins slow-path code back to the fast-path. The invalidation param + * specifies how many stack slots below sp must not be reloaded from + * registers. + */ + void rejoin(Changes changes); + void linkRejoin(Jump j); + + /* Finish all native code patching. */ + void fixCrossJumps(uint8 *ncode, size_t offset, size_t total); + bool jumpInScript(Jump j, jsbytecode *target); + void crossJump(Jump j, Label l); + + Call emitStubCall(void *ptr, uint32 id); + Call emitStubCall(void *ptr, int32 slots, uint32 id); +}; + +} /* namepsace mjit */ +} /* namespace js */ + +#endif /* jsstub_compiler_h__ */ + diff --git a/js/src/methodjit/TrampolineCompiler.cpp b/js/src/methodjit/TrampolineCompiler.cpp new file mode 100644 index 0000000..24531a6 --- /dev/null +++ b/js/src/methodjit/TrampolineCompiler.cpp @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Jaegermonkey. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Andrew Drake + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "TrampolineCompiler.h" +#include "StubCalls.h" +#include "assembler/assembler/LinkBuffer.h" + +namespace js { +namespace mjit { + +#define CHECK_RESULT(x) if (!(x)) return false +#define COMPILE(which, pool, how) CHECK_RESULT(compileTrampoline(&(which), &pool, how)) +#define RELEASE(which, pool) JS_BEGIN_MACRO \ + which = NULL; \ + if (pool) \ + pool->release(); \ + pool = NULL; \ +JS_END_MACRO + +typedef JSC::MacroAssembler::Address Address; +typedef JSC::MacroAssembler::Label Label; +typedef JSC::MacroAssembler::Jump Jump; +typedef JSC::MacroAssembler::ImmPtr ImmPtr; +typedef JSC::MacroAssembler::Imm32 Imm32; +typedef JSC::MacroAssembler::Address Address; + +bool +TrampolineCompiler::compile() +{ +#ifdef JS_METHODJIT_SPEW + JMCheckLogging(); +#endif + + COMPILE(trampolines->forceReturn, trampolines->forceReturnPool, generateForceReturn); +#if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64) + COMPILE(trampolines->forceReturnFast, trampolines->forceReturnFastPool, generateForceReturnFast); +#endif + + return true; +} + +void +TrampolineCompiler::release(Trampolines *tramps) +{ + RELEASE(tramps->forceReturn, tramps->forceReturnPool); +#if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64) + RELEASE(tramps->forceReturnFast, tramps->forceReturnFastPool); +#endif +} + +bool +TrampolineCompiler::compileTrampoline(Trampolines::TrampolinePtr *where, JSC::ExecutablePool **pool, + TrampolineGenerator generator) +{ + Assembler masm; + + Label entry = masm.label(); + CHECK_RESULT(generator(masm)); + JS_ASSERT(entry.isValid()); + + *pool = execPool->poolForSize(masm.size()); + if (!*pool) + return false; + + JSC::LinkBuffer buffer(&masm, *pool); + masm.finalize(buffer); + uint8 *result = (uint8*)buffer.finalizeCodeAddendum().dataLocation(); + *where = JS_DATA_TO_FUNC_PTR(Trampolines::TrampolinePtr, result + masm.distanceOf(entry)); + + return true; +} + +/* + * This is shamelessly copied from emitReturn, but with several changes: + * - There was always at least one inline call. + * - We don't know if there is a call object, so we always check. + * - We don't know where we came from, so we don't know frame depth or PC. + * - There is no stub buffer. + */ +bool +TrampolineCompiler::generateForceReturn(Assembler &masm) +{ + /* if (hasArgsObj() || hasCallObj()) stubs::PutActivationObjects() */ + Jump noActObjs = masm.branchTest32(Assembler::Zero, FrameFlagsAddress(), + Imm32(JSFRAME_HAS_CALL_OBJ | JSFRAME_HAS_ARGS_OBJ)); + masm.fallibleVMCall(JS_FUNC_TO_DATA_PTR(void *, stubs::PutActivationObjects), NULL, 0); + noActObjs.linkTo(masm.label(), &masm); + + /* Store any known return value */ + masm.loadValueAsComponents(UndefinedValue(), JSReturnReg_Type, JSReturnReg_Data); + Jump rvalClear = masm.branchTest32(Assembler::Zero, + FrameFlagsAddress(), Imm32(JSFRAME_HAS_RVAL)); + Address rvalAddress(JSFrameReg, JSStackFrame::offsetOfReturnValue()); + masm.loadValueAsComponents(rvalAddress, JSReturnReg_Type, JSReturnReg_Data); + rvalClear.linkTo(masm.label(), &masm); + + /* Return to the caller */ + masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfncode()), Registers::ReturnReg); + masm.jump(Registers::ReturnReg); + return true; +} + +#if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64) +bool +TrampolineCompiler::generateForceReturnFast(Assembler &masm) +{ +#ifdef _WIN64 + masm.addPtr(Imm32(32), Registers::StackPointer); +#else + // In case of no fast call, when we change the return address, + // we need to make sure add esp by 8. + masm.addPtr(Imm32(16), Registers::StackPointer); +#endif + return generateForceReturn(masm); +} +#endif + +} /* namespace mjit */ +} /* namespace js */ + diff --git a/js/src/methodjit/TrampolineCompiler.h b/js/src/methodjit/TrampolineCompiler.h new file mode 100644 index 0000000..208a3d5 --- /dev/null +++ b/js/src/methodjit/TrampolineCompiler.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Jaegermonkey. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Andrew Drake + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined trampolines_h__ && defined JS_METHODJIT +#define trampolines_h__ + +#include "assembler/jit/ExecutableAllocator.h" +#include "methodjit/CodeGenIncludes.h" + +namespace js { +namespace mjit { + +class TrampolineCompiler +{ + typedef bool (*TrampolineGenerator)(Assembler &masm); + +public: + TrampolineCompiler(JSC::ExecutableAllocator *pool, Trampolines *tramps) + : execPool(pool), trampolines(tramps) + { } + + bool compile(); + static void release(Trampolines *tramps); + +private: + bool compileTrampoline(Trampolines::TrampolinePtr *where, JSC::ExecutablePool **pool, + TrampolineGenerator generator); + + /* Generators for trampolines. */ + static bool generateForceReturn(Assembler &masm); + +#if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64) + static bool generateForceReturnFast(Assembler &masm); +#endif + + JSC::ExecutableAllocator *execPool; + Trampolines *trampolines; +}; + +} /* namespace mjit */ +} /* namespace js */ + +#endif + diff --git a/js/src/methodjit/TrampolineMasmX64.asm b/js/src/methodjit/TrampolineMasmX64.asm new file mode 100644 index 0000000..3c5dac5 --- /dev/null +++ b/js/src/methodjit/TrampolineMasmX64.asm @@ -0,0 +1,175 @@ +; -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +; ***** BEGIN LICENSE BLOCK ***** +; Version: MPL 1.1/GPL 2.0/LGPL 2.1 +; +; The contents of this file are subject to the Mozilla Public License Version +; 1.1 (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.mozilla.org/MPL/ +; +; Software distributed under the License is distributed on an "AS IS" basis, +; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +; for the specific language governing rights and limitations under the +; License. +; +; The Original Code is mozilla.org code. +; +; The Initial Developer of the Original Code is Mozilla Japan. +; Portions created by the Initial Developer are Copyright (C) 2010 +; the Initial Developer. All Rights Reserved. +; +; Contributor(s): +; Makoto Kato +; +; Alternatively, the contents of this file may be used under the terms of +; either the GNU General Public License Version 2 or later (the "GPL"), or +; the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +; in which case the provisions of the GPL or the LGPL are applicable instead +; of those above. If you wish to allow use of your version of this file only +; under the terms of either the GPL or the LGPL, and not to allow others to +; use your version of this file under the terms of the MPL, indicate your +; decision by deleting the provisions above and replace them with the notice +; and other provisions required by the GPL or the LGPL. If you do not delete +; the provisions above, a recipient may use your version of this file under +; the terms of any one of the MPL, the GPL or the LGPL. +; +; ***** END LICENSE BLOCK ***** + + +extern js_InternalThrow:PROC +extern SetVMFrameRegs:PROC +extern PushActiveVMFrame:PROC +extern PopActiveVMFrame:PROC + +.CODE + +; JSBool JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code, +; Value *stackLimit, void *safePoint); +JaegerTrampoline PROC FRAME + push rbp + .PUSHREG rbp + mov rbp, rsp + .SETFRAME rbp, 0 + push r12 + .PUSHREG r12 + push r13 + .PUSHREG r13 + push r14 + .PUSHREG r14 + push r15 + .PUSHREG r15 + push rdi + .PUSHREG rdi + push rsi + .PUSHREG rsi + push rbx + .PUSHREG rbx + .ENDPROLOG + + ; Load mask registers + mov r13, 0ffff800000000000h + mov r14, 7fffffffffffh + + ; Build the JIT frame. + ; rcx = cx + ; rdx = fp + ; r9 = inlineCallCount + ; fp must go into rbx + push rdx ; entryFp + push r9 ; inlineCallCount + push rcx ; cx + push rdx ; fp + mov rbx, rdx + + ; Space for the rest of the VMFrame. + sub rsp, 28h + + ; This is actually part of the VMFrame. + mov r10, [rbp+8*5+8] + push r10 + + ; Set cx->regs and set the active frame. Save r8 and align frame in one + push r8 + mov rcx, rsp + sub rsp, 20h + call SetVMFrameRegs + lea rcx, [rsp+20h] + call PushActiveVMFrame + add rsp, 20h + + ; Jump into the JIT code. + jmp qword ptr [rsp] +JaegerTrampoline ENDP + +; void JaegerTrampolineReturn(); +JaegerTrampolineReturn PROC FRAME + .ENDPROLOG + or rcx, rdx + mov qword ptr [rbx + 30h], rcx + sub rsp, 20h + lea rcx, [rsp+20h] + call PopActiveVMFrame + + add rsp, 58h+20h + pop rbx + pop rsi + pop rdi + pop r15 + pop r14 + pop r13 + pop r12 + pop rbp + mov rax, 1 + ret +JaegerTrampolineReturn ENDP + + +; void JaegerThrowpoline() +JaegerThrowpoline PROC FRAME + .ENDPROLOG + ; For Windows x64 stub calls, we pad the stack by 32 before + ; calling, so we must account for that here. See doStubCall. + lea rcx, [rsp+20h] + call js_InternalThrow + test rax, rax + je throwpoline_exit + add rsp, 20h + jmp rax + +throwpoline_exit: + lea rcx, [rsp+20h] + call PopActiveVMFrame + add rsp, 58h+20h + pop rbx + pop rsi + pop rdi + pop r15 + pop r14 + pop r13 + pop r12 + pop rbp + xor rax, rax + ret +JaegerThrowpoline ENDP + + + +; void InjectJaegerReturn(); +InjectJaegerReturn PROC FRAME + .ENDPROLOG + mov rcx, qword ptr [rbx+30h] ; load fp->rval_ into typeReg + mov rax, qword ptr [rbx+28h] ; fp->ncode_ + + ; Reimplementation of PunboxAssembler::loadValueAsComponents() + mov rdx, r14 + and rdx, rcx + xor rcx, rdx + + ; For Windows x64 stub calls, we pad the stack by 32 before + ; calling, so we must account for that here. See doStubCall. + mov rbx, qword ptr [rsp+38h+20h] ; f.fp + add rsp, 20h + jmp rax ; return +InjectJaegerReturn ENDP + +END diff --git a/js/src/methodjit/TrampolineSUNWX64.s b/js/src/methodjit/TrampolineSUNWX64.s new file mode 100644 index 0000000..b34f6a6 --- /dev/null +++ b/js/src/methodjit/TrampolineSUNWX64.s @@ -0,0 +1,145 @@ +/ -*- Mode: C++/ tab-width: 4/ indent-tabs-mode: nil/ c-basic-offset: 4 -*- +/ ***** BEGIN LICENSE BLOCK ***** +/ Version: MPL 1.1/GPL 2.0/LGPL 2.1 +/ +/ The contents of this file are subject to the Mozilla Public License Version +/ 1.1 (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.mozilla.org/MPL/ +/ +/ Software distributed under the License is distributed on an "AS IS" basis, +/ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +/ for the specific language governing rights and limitations under the +/ License. +/ +/ The Original Code is mozilla.org code. +/ +/ The Initial Developer of the Original Code is Mozilla Japan. +/ Portions created by the Initial Developer are Copyright (C) 2010 +/ the Initial Developer. All Rights Reserved. +/ +/ Contributor(s): +/ Leon Sha +/ +/ Alternatively, the contents of this file may be used under the terms of +/ either the GNU General Public License Version 2 or later (the "GPL"), or +/ the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +/ in which case the provisions of the GPL or the LGPL are applicable instead +/ of those above. If you wish to allow use of your version of this file only +/ under the terms of either the GPL or the LGPL, and not to allow others to +/ use your version of this file under the terms of the MPL, indicate your +/ decision by deleting the provisions above and replace them with the notice +/ and other provisions required by the GPL or the LGPL. If you do not delete +/ the provisions above, a recipient may use your version of this file under +/ the terms of any one of the MPL, the GPL or the LGPL. +/ +/ ***** END LICENSE BLOCK ***** + +.text + +/ JSBool JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code, +/ JSFrameRegs *regs, uintptr_t inlineCallCount) +.global JaegerTrampoline +.type JaegerTrampoline, @function +JaegerTrampoline: + /* Prologue. */ + pushq %rbp + movq %rsp, %rbp + /* Save non-volatile registers. */ + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + pushq %rbx + + /* Load mask registers. */ + movq $0xFFFF800000000000, %r13 + movq $0x00007FFFFFFFFFFF, %r14 + + /* Build the JIT frame. + * rdi = cx + * rsi = fp + * rcx = inlineCallCount + * fp must go into rbx + */ + pushq %rsi /* entryFp */ + pushq %rcx /* inlineCallCount */ + pushq %rdi /* cx */ + pushq %rsi /* fp */ + movq %rsi, %rbx + + /* Space for the rest of the VMFrame. */ + subq $0x28, %rsp + + /* This is actually part of the VMFrame. */ + pushq %r8 + + /* Set cx->regs and set the active frame. Save rdx and align frame in one. */ + pushq %rdx + movq %rsp, %rdi + call SetVMFrameRegs + movq %rsp, %rdi + call PushActiveVMFrame + + /* Jump into into the JIT'd code. */ + jmp *0(%rsp) +.size JaegerTrampoline, . - JaegerTrampoline + +/ void JaegerTrampolineReturn() +.global JaegerTrampolineReturn +.type JaegerTrampolineReturn, @function +JaegerTrampolineReturn: + or %rdx, %rcx + movq %rcx, 0x30(%rbx) + movq %rsp, %rdi + call PopActiveVMFrame + + addq $0x58, %rsp + popq %rbx + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + movq $1, %rax + ret +.size JaegerTrampolineReturn, . - JaegerTrampolineReturn + + +/ void *JaegerThrowpoline(js::VMFrame *vmFrame) +.global JaegerThrowpoline +.type JaegerThrowpoline, @function +JaegerThrowpoline: + movq %rsp, %rdi + call js_InternalThrow + testq %rax, %rax + je throwpoline_exit + jmp *%rax + throwpoline_exit: + movq %rsp, %rdi + call PopActiveVMFrame + addq $0x58, %rsp + popq %rbx + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + xorq %rax,%rax + ret +.size JaegerThrowpoline, . - JaegerThrowpoline + +.global InjectJaegerReturn +.type InjectJaegerReturn, @function +InjectJaegerReturn: + movq 0x30(%rbx), %rcx /* load fp->rval_ into typeReg */ + movq 0x28(%rbx), %rax /* fp->ncode_ */ + + /* Reimplementation of PunboxAssembler::loadValueAsComponents() */ + movq %r14, %rdx /* payloadReg = payloadMaskReg */ + andq %rcx, %rdx + xorq %rdx, %rcx + + movq 0x38(%rsp), %rbx /* f.fp */ + jmp *%rax /* return. */ +.size InjectJaegerReturn, . - InjectJaegerReturn diff --git a/js/src/methodjit/TrampolineSUNWX86.s b/js/src/methodjit/TrampolineSUNWX86.s new file mode 100644 index 0000000..dbc75a4 --- /dev/null +++ b/js/src/methodjit/TrampolineSUNWX86.s @@ -0,0 +1,135 @@ +/ -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/ ***** BEGIN LICENSE BLOCK ***** +/ Version: MPL 1.1/GPL 2.0/LGPL 2.1 +/ +/ The contents of this file are subject to the Mozilla Public License Version +/ 1.1 (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.mozilla.org/MPL/ +/ +/ Software distributed under the License is distributed on an "AS IS" basis, +/ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +/ for the specific language governing rights and limitations under the +/ License. +/ +/ The Original Code is mozilla.org code. +/ +/ The Initial Developer of the Original Code is Mozilla Japan. +/ Portions created by the Initial Developer are Copyright (C) 2010 +/ the Initial Developer. All Rights Reserved. +/ +/ Contributor(s): +/ Leon Sha +/ +/ Alternatively, the contents of this file may be used under the terms of +/ either the GNU General Public License Version 2 or later (the "GPL"), or +/ the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +/ in which case the provisions of the GPL or the LGPL are applicable instead +/ of those above. If you wish to allow use of your version of this file only +/ under the terms of either the GPL or the LGPL, and not to allow others to +/ use your version of this file under the terms of the MPL, indicate your +/ decision by deleting the provisions above and replace them with the notice +/ and other provisions required by the GPL or the LGPL. If you do not delete +/ the provisions above, a recipient may use your version of this file under +/ the terms of any one of the MPL, the GPL or the LGPL. +/ +/ ***** END LICENSE BLOCK ***** + +.text + +/ JSBool JaegerTrampoline(JSContext *cx, JSStackFrame *fp, void *code, +/ JSFrameRegs *regs, uintptr_t inlineCallCount) +.global JaegerTrampoline +.type JaegerTrampoline, @function +JaegerTrampoline: + /* Prologue. */ + pushl %ebp + movl %esp, %ebp + /* Save non-volatile registers. */ + pushl %esi + pushl %edi + pushl %ebx + + /* Build the JIT frame. Push fields in order, */ + /* then align the stack to form esp == VMFrame. */ + movl 12(%ebp), %ebx /* fp */ + pushl %ebx /* entryFp */ + pushl 20(%ebp) /* stackLimit */ + pushl 8(%ebp) /* cx */ + pushl %ebx /* fp */ + subl $0x1C, %esp + + /* Jump into the JIT'd code. */ + /* No fastcall for sunstudio. */ + pushl %esp + call SetVMFrameRegs + call PushActiveVMFrame + popl %edx + jmp *16(%ebp) +.size JaegerTrampoline, . - JaegerTrampoline + +/ void JaegerTrampolineReturn() +.global JaegerTrampolineReturn +.type JaegerTrampolineReturn, @function +JaegerTrampolineReturn: + movl %edx, 0x18(%ebx) + movl %ecx, 0x1C(%ebx) + pushl %esp + call PopActiveVMFrame + + addl $0x30, %esp + popl %ebx + popl %edi + popl %esi + popl %ebp + movl $1, %eax + ret +.size JaegerTrampolineReturn, . - JaegerTrampolineReturn + + +/ void *JaegerThrowpoline(js::VMFrame *vmFrame) +.global JaegerThrowpoline +.type JaegerThrowpoline, @function +JaegerThrowpoline: + /* For Sun Studio there is no fast call. */ + /* We add the stack by 16 before. */ + addl $0x10, %esp + /* Align the stack to 16 bytes. */ + pushl %esp + pushl (%esp) + pushl (%esp) + pushl (%esp) + call js_InternalThrow + /* Bump the stack by 0x2c, as in the basic trampoline, but */ + /* also one more word to clean up the stack for jsl_InternalThrow,*/ + /* and another to balance the alignment above. */ + addl $0x10, %esp + testl %eax, %eax + je throwpoline_exit + jmp *%eax +throwpoline_exit: + pushl %esp + call PopActiveVMFrame + popl %ebx + addl $0x2C, %esp + popl %ebx + popl %edi + popl %esi + popl %ebp + xorl %eax, %eax + ret +.size JaegerThrowpoline, . - JaegerThrowpoline + +.global InjectJaegerReturn +.type InjectJaegerReturn, @function +InjectJaegerReturn: + movl 0x18(%ebx), %edx /* fp->rval_ data */ + movl 0x1C(%ebx), %ecx /* fp->rval_ type */ + movl 0x14(%ebx), %eax /* fp->ncode_ */ + /* For Sun Studio there is no fast call. */ + /* We add the stack by 16 before. */ + addl $0x10, %esp + /* Restore frame regs. */ + movl 0x1C(%esp), %ebx /* f.fp */ + jmp *%eax +.size InjectJaegerReturn, . - InjectJaegerReturn diff --git a/js/src/methodjit/TypedArrayIC.h b/js/src/methodjit/TypedArrayIC.h new file mode 100644 index 0000000..88f8175 --- /dev/null +++ b/js/src/methodjit/TypedArrayIC.h @@ -0,0 +1,546 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Brendan Eich + * + * Contributor(s): + * David Anderson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef js_typedarray_ic_h___ +#define js_typedarray_ic_h___ + +#include "jscntxt.h" +#include "jstypedarray.h" + +namespace js { +namespace mjit { + +#if defined(JS_POLYIC) && (defined JS_CPU_X86 || defined JS_CPU_X64) + +typedef JSC::MacroAssembler::RegisterID RegisterID; +typedef JSC::MacroAssembler::FPRegisterID FPRegisterID; +typedef JSC::MacroAssembler::Jump Jump; +typedef JSC::MacroAssembler::Imm32 Imm32; +typedef JSC::MacroAssembler::ImmDouble ImmDouble; + +template +static void +LoadFromTypedArray(Assembler &masm, js::TypedArray *tarray, T address, + RegisterID typeReg, RegisterID dataReg) +{ + switch (tarray->type) { + case js::TypedArray::TYPE_INT8: + masm.load8SignExtend(address, dataReg); + masm.move(ImmType(JSVAL_TYPE_INT32), typeReg); + break; + case js::TypedArray::TYPE_UINT8: + case js::TypedArray::TYPE_UINT8_CLAMPED: + masm.load8ZeroExtend(address, dataReg); + masm.move(ImmType(JSVAL_TYPE_INT32), typeReg); + break; + case js::TypedArray::TYPE_INT16: + masm.load16SignExtend(address, dataReg); + masm.move(ImmType(JSVAL_TYPE_INT32), typeReg); + break; + case js::TypedArray::TYPE_UINT16: + masm.load16(address, dataReg); + masm.move(ImmType(JSVAL_TYPE_INT32), typeReg); + break; + case js::TypedArray::TYPE_INT32: + masm.load32(address, dataReg); + masm.move(ImmType(JSVAL_TYPE_INT32), typeReg); + break; + case js::TypedArray::TYPE_UINT32: + { + masm.load32(address, dataReg); + masm.move(ImmType(JSVAL_TYPE_INT32), typeReg); + Jump safeInt = masm.branch32(Assembler::Below, dataReg, Imm32(0x80000000)); + masm.convertUInt32ToDouble(dataReg, FPRegisters::First); + masm.breakDouble(FPRegisters::First, typeReg, dataReg); + safeInt.linkTo(masm.label(), &masm); + break; + } + case js::TypedArray::TYPE_FLOAT32: + case js::TypedArray::TYPE_FLOAT64: + { + if (tarray->type == js::TypedArray::TYPE_FLOAT32) + masm.loadFloat(address, FPRegisters::First); + else + masm.loadDouble(address, FPRegisters::First); + // Make sure NaN gets canonicalized. + Jump notNaN = masm.branchDouble(Assembler::DoubleEqual, + FPRegisters::First, + FPRegisters::First); + masm.loadStaticDouble(&js_NaN, FPRegisters::First, dataReg); + notNaN.linkTo(masm.label(), &masm); + masm.breakDouble(FPRegisters::First, typeReg, dataReg); + break; + } + } +} + +static inline bool +ConstantFoldForFloatArray(JSContext *cx, ValueRemat *vr) +{ + if (!vr->isTypeKnown()) + return true; + + // Objects and undefined coerce to NaN, which coerces to 0. + // Null converts to 0. + if (vr->knownType() == JSVAL_TYPE_OBJECT || + vr->knownType() == JSVAL_TYPE_UNDEFINED) { + *vr = ValueRemat::FromConstant(DoubleValue(js_NaN)); + return true; + } + if (vr->knownType() == JSVAL_TYPE_NULL) { + *vr = ValueRemat::FromConstant(DoubleValue(0)); + return true; + } + + if (!vr->isConstant()) + return true; + + if (vr->knownType() == JSVAL_TYPE_DOUBLE) + return true; + + jsdouble d = 0; + Value v = vr->value(); + if (v.isString()) { + if (!StringToNumberType(cx, v.toString(), &d)) + return false; + } else if (v.isBoolean()) { + d = v.toBoolean() ? 1 : 0; + } else if (v.isInt32()) { + d = v.toInt32(); + } else { + JS_NOT_REACHED("unknown constant type"); + } + *vr = ValueRemat::FromConstant(DoubleValue(d)); + return true; +} + +static inline int32 +ClampIntForUint8Array(int32 x) +{ + if (x < 0) + return 0; + if (x > 255) + return 255; + return x; +} + +static inline bool +ConstantFoldForIntArray(JSContext *cx, js::TypedArray *tarray, ValueRemat *vr) +{ + if (!vr->isTypeKnown()) + return true; + + // Objects and undefined coerce to NaN, which coerces to 0. + // Null converts to 0. + if (vr->knownType() == JSVAL_TYPE_OBJECT || + vr->knownType() == JSVAL_TYPE_UNDEFINED || + vr->knownType() == JSVAL_TYPE_NULL) { + *vr = ValueRemat::FromConstant(Int32Value(0)); + return true; + } + + if (!vr->isConstant()) + return true; + + // Convert from string to double first (see bug 624483). + Value v = vr->value(); + if (v.isString()) { + double d; + if (!StringToNumberType(cx, v.toString(), &d)) + return false; + v.setNumber(d); + } + + int32 i32 = 0; + if (v.isDouble()) { + i32 = (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED) + ? js_TypedArray_uint8_clamp_double(v.toDouble()) + : js_DoubleToECMAInt32(v.toDouble()); + } else if (v.isInt32()) { + i32 = v.toInt32(); + if (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED) + i32 = ClampIntForUint8Array(i32); + } else if (v.isBoolean()) { + i32 = v.toBoolean() ? 1 : 0; + } else { + JS_NOT_REACHED("unknown constant type"); + } + + *vr = ValueRemat::FromConstant(Int32Value(i32)); + + return true; +} + +template +static void +StoreToIntArray(Assembler &masm, js::TypedArray *tarray, S src, T address) +{ + switch (tarray->type) { + case js::TypedArray::TYPE_INT8: + case js::TypedArray::TYPE_UINT8: + case js::TypedArray::TYPE_UINT8_CLAMPED: + masm.store8(src, address); + break; + case js::TypedArray::TYPE_INT16: + case js::TypedArray::TYPE_UINT16: + masm.store16(src, address); + break; + case js::TypedArray::TYPE_INT32: + case js::TypedArray::TYPE_UINT32: + masm.store32(src, address); + break; + default: + JS_NOT_REACHED("unknown int array type"); + } +} + +template +static void +StoreToFloatArray(Assembler &masm, js::TypedArray *tarray, S src, T address) +{ + if (tarray->type == js::TypedArray::TYPE_FLOAT32) + masm.storeFloat(src, address); + else + masm.storeDouble(src, address); +} + +// Generate code that will ensure a dynamically typed value, pinned in |vr|, +// can be stored in an integer typed array. If any sort of conversion is +// required, |dataReg| will be clobbered by a new value. |saveMask| is +// used to ensure that |dataReg| (and volatile registers) are preserved +// across any conversion process. +static void +GenConversionForIntArray(Assembler &masm, js::TypedArray *tarray, const ValueRemat &vr, + uint32 saveMask) +{ + if (vr.isConstant()) { + // Constants are always folded to ints up-front. + JS_ASSERT(vr.knownType() == JSVAL_TYPE_INT32); + return; + } + + if (!vr.isTypeKnown() || vr.knownType() != JSVAL_TYPE_INT32) { + // If a conversion is necessary, save registers now. + MaybeJump checkInt32; + if (!vr.isTypeKnown()) + checkInt32 = masm.testInt32(Assembler::Equal, vr.typeReg()); + + // Store the value to convert. + StackMarker vp = masm.allocStack(sizeof(Value), sizeof(double)); + masm.storeValue(vr, masm.addressOfExtra(vp)); + + // Preserve volatile registers. + PreserveRegisters saveForCall(masm); + saveForCall.preserve(saveMask & Registers::TempRegs); + + masm.setupABICall(Registers::FastCall, 2); + masm.storeArg(0, masm.vmFrameOffset(offsetof(VMFrame, cx))); + masm.storeArgAddr(1, masm.addressOfExtra(vp)); + + typedef int32 (JS_FASTCALL *Int32CxVp)(JSContext *, Value *); + Int32CxVp stub; + if (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED) + stub = stubs::ConvertToTypedInt; + else + stub = stubs::ConvertToTypedInt; + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, stub), false); + if (vr.dataReg() != Registers::ReturnReg) + masm.move(Registers::ReturnReg, vr.dataReg()); + + saveForCall.restore(); + masm.freeStack(vp); + + if (checkInt32.isSet()) + checkInt32.get().linkTo(masm.label(), &masm); + } + + // Performing clamping, if needed. + if (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED) { + // cmp dr, 0 + // jge _min + // mov dr, 0 + // jump _done + // _min: + // cmp dr, 255 + // jle _done + // mov dr, 255 + // _done: + // + Jump j = masm.branch32(Assembler::GreaterThanOrEqual, vr.dataReg(), Imm32(0)); + masm.move(Imm32(0), vr.dataReg()); + Jump done = masm.jump(); + j.linkTo(masm.label(), &masm); + j = masm.branch32(Assembler::LessThanOrEqual, vr.dataReg(), Imm32(255)); + masm.move(Imm32(255), vr.dataReg()); + j.linkTo(masm.label(), &masm); + done.linkTo(masm.label(), &masm); + } +} + +// Generate code that will ensure a dynamically typed value, pinned in |vr|, +// can be stored in an integer typed array. saveMask| is used to ensure that +// |dataReg| (and volatile registers) are preserved across any conversion +// process. +// +// Constants are left untouched. Any other value is placed into +// FPRegisters::First. +static void +GenConversionForFloatArray(Assembler &masm, js::TypedArray *tarray, const ValueRemat &vr, + FPRegisterID destReg, uint32 saveMask) +{ + if (vr.isConstant()) { + // Constants are always folded to doubles up-front. + JS_ASSERT(vr.knownType() == JSVAL_TYPE_DOUBLE); + return; + } + + // Fast-path, if the value is a double, skip converting. + MaybeJump isDouble; + if (!vr.isTypeKnown()) + isDouble = masm.testDouble(Assembler::Equal, vr.typeReg()); + + // If the value is an integer, inline the conversion. + MaybeJump skip1, skip2; + if (!vr.isTypeKnown() || vr.knownType() == JSVAL_TYPE_INT32) { + MaybeJump isNotInt32; + if (!vr.isTypeKnown()) + isNotInt32 = masm.testInt32(Assembler::NotEqual, vr.typeReg()); + masm.convertInt32ToDouble(vr.dataReg(), destReg); + if (isNotInt32.isSet()) { + skip1 = masm.jump(); + isNotInt32.get().linkTo(masm.label(), &masm); + } + } + + // Generate a generic conversion call, if not known to be int32 or double. + if (!vr.isTypeKnown() || + (vr.knownType() != JSVAL_TYPE_INT32 && + vr.knownType() != JSVAL_TYPE_DOUBLE)) { + // Store this value, which is also an outparam. + StackMarker vp = masm.allocStack(sizeof(Value), sizeof(double)); + masm.storeValue(vr, masm.addressOfExtra(vp)); + + // Preserve volatile registers, and make the call. + PreserveRegisters saveForCall(masm); + saveForCall.preserve(saveMask & Registers::TempRegs); + masm.setupABICall(Registers::FastCall, 2); + masm.storeArg(0, masm.vmFrameOffset(offsetof(VMFrame, cx))); + masm.storeArgAddr(1, masm.addressOfExtra(vp)); + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, stubs::ConvertToTypedFloat), false); + saveForCall.restore(); + + // Load the value from the outparam, then pop the stack. + masm.loadDouble(masm.addressOfExtra(vp), destReg); + masm.freeStack(vp); + skip2 = masm.jump(); + } + + if (isDouble.isSet()) + isDouble.get().linkTo(masm.label(), &masm); + + // If it's possible the value was already a double, load it directly + // from registers (the known type is distinct from typeReg, which has + // 32-bits of the 64-bit double). + if (!vr.isTypeKnown() || vr.knownType() == JSVAL_TYPE_DOUBLE) + masm.fastLoadDouble(vr.dataReg(), vr.typeReg(), destReg); + + // At this point, all loads into xmm1 are complete. + if (skip1.isSet()) + skip1.get().linkTo(masm.label(), &masm); + if (skip2.isSet()) + skip2.get().linkTo(masm.label(), &masm); + + if (tarray->type == js::TypedArray::TYPE_FLOAT32) + masm.convertDoubleToFloat(destReg, destReg); +} + +template +static bool +StoreToTypedArray(JSContext *cx, Assembler &masm, js::TypedArray *tarray, T address, + const ValueRemat &vrIn, uint32 saveMask) +{ + ValueRemat vr = vrIn; + + switch (tarray->type) { + case js::TypedArray::TYPE_INT8: + case js::TypedArray::TYPE_UINT8: + case js::TypedArray::TYPE_UINT8_CLAMPED: + case js::TypedArray::TYPE_INT16: + case js::TypedArray::TYPE_UINT16: + case js::TypedArray::TYPE_INT32: + case js::TypedArray::TYPE_UINT32: + { + if (!ConstantFoldForIntArray(cx, tarray, &vr)) + return false; + + PreserveRegisters saveRHS(masm); + PreserveRegisters saveLHS(masm); + + // There are three tricky situations to handle: + // (1) The RHS needs conversion. saveMask will be stomped, and + // the RHS may need to be stomped. + // (2) The RHS may need to be clamped, which clobbers it. + // (3) The RHS may need to be in a single-byte register. + // + // In all of these cases, we try to find a free register that can be + // used to mutate the RHS. Failing that, we evict an existing volatile + // register. + // + // Note that we are careful to preserve the RHS before saving registers + // for the conversion call. This is because the object and key may be + // in temporary registers, and we want to restore those without killing + // the mutated RHS. + bool singleByte = (tarray->type == js::TypedArray::TYPE_INT8 || + tarray->type == js::TypedArray::TYPE_UINT8 || + tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED); + bool mayNeedConversion = (!vr.isTypeKnown() || vr.knownType() != JSVAL_TYPE_INT32); + bool mayNeedClamping = !vr.isConstant() && (tarray->type == js::TypedArray::TYPE_UINT8_CLAMPED); + bool needsSingleByteReg = singleByte && + !vr.isConstant() && + !(Registers::SingleByteRegs & Registers::maskReg(vr.dataReg())); + bool rhsIsMutable = !vr.isConstant() && !(saveMask & Registers::maskReg(vr.dataReg())); + + if (((mayNeedConversion || mayNeedClamping) && !rhsIsMutable) || needsSingleByteReg) { + // First attempt to find a free temporary register that: + // - is compatible with the RHS constraints + // - won't clobber the key, object, or RHS type regs + // - is temporary, but + // - is not in saveMask, which contains live volatile registers. + uint32 allowMask = Registers::AvailRegs; + if (singleByte) + allowMask &= Registers::SingleByteRegs; + + // Create a mask of registers we absolutely cannot clobber. + uint32 pinned = Assembler::maskAddress(address); + if (!vr.isTypeKnown()) + pinned |= Registers::maskReg(vr.typeReg()); + + Registers avail = allowMask & ~(pinned | saveMask); + + RegisterID newReg; + if (!avail.empty()) { + newReg = avail.takeAnyReg(); + } else { + // If no registers meet the ideal set, relax a constraint and spill. + avail = allowMask & ~pinned; + + if (!avail.empty()) { + newReg = avail.takeAnyReg(); + saveRHS.preserve(Registers::maskReg(newReg)); + } else { + // Oh no! *All* single byte registers are pinned. This + // sucks. We'll swap the type and data registers in |vr| + // and unswap them later. + + // If |vr|'s registers are part of the address, swapping is + // going to cause problems during the store. + uint32 vrRegs = Registers::mask2Regs(vr.dataReg(), vr.typeReg()); + uint32 lhsMask = vrRegs & Assembler::maskAddress(address); + + // We'll also need to save any of the registers which won't + // be restored via |lhsMask| above. + uint32 rhsMask = vrRegs & ~lhsMask; + + // Push them, but get the order right. We'll pop LHS first. + saveRHS.preserve(rhsMask); + saveLHS.preserve(lhsMask); + + // Don't store/restore registers if we dont have to. + saveMask &= ~lhsMask; + + // Actually perform the swap. + masm.swap(vr.typeReg(), vr.dataReg()); + vr = ValueRemat::FromRegisters(vr.dataReg(), vr.typeReg()); + newReg = vr.dataReg(); + } + + // Now, make sure the new register is not in the saveMask, + // so it won't get restored right after the call. + saveMask &= ~Registers::maskReg(newReg); + } + + if (vr.dataReg() != newReg) + masm.move(vr.dataReg(), newReg); + + // Update |vr|. + if (vr.isTypeKnown()) + vr = ValueRemat::FromKnownType(vr.knownType(), newReg); + else + vr = ValueRemat::FromRegisters(vr.typeReg(), newReg); + } + + GenConversionForIntArray(masm, tarray, vr, saveMask); + + // Restore the registers in |address|. |GenConversionForIntArray| won't + // restore them because we told it not to by fiddling with |saveMask|. + saveLHS.restore(); + + if (vr.isConstant()) + StoreToIntArray(masm, tarray, Imm32(vr.value().toInt32()), address); + else + StoreToIntArray(masm, tarray, vr.dataReg(), address); + + // Note that this will finish restoring the damage from the + // earlier register swap. + saveRHS.restore(); + break; + } + + case js::TypedArray::TYPE_FLOAT32: + case js::TypedArray::TYPE_FLOAT64: + if (!ConstantFoldForFloatArray(cx, &vr)) + return false; + GenConversionForFloatArray(masm, tarray, vr, FPRegisters::First, saveMask); + if (vr.isConstant()) + StoreToFloatArray(masm, tarray, ImmDouble(vr.value().toDouble()), address); + else + StoreToFloatArray(masm, tarray, FPRegisters::First, address); + break; + } + + return true; +} + +#endif // defined(JS_POLYIC) && (defined JS_CPU_X86 || defined JS_CPU_X64) + +} /* namespace mjit */ +} /* namespace js */ + +#endif /* js_typedarray_ic_h___ */ + diff --git a/js/src/metrics/gc/README.txt b/js/src/metrics/gc/README.txt new file mode 100644 index 0000000..23ddbf2 --- /dev/null +++ b/js/src/metrics/gc/README.txt @@ -0,0 +1,8 @@ +Usage: + +Requirements: +1) The shell has to be compiled with --enable-gctimer + +2) The JS_WANT_GC_SUITE_PRINT flag has to be set to true in jsgc.cpp + +Tested with python2.6 diff --git a/js/src/metrics/gc/gc-test.py b/js/src/metrics/gc/gc-test.py new file mode 100644 index 0000000..90ee29a --- /dev/null +++ b/js/src/metrics/gc/gc-test.py @@ -0,0 +1,177 @@ +# Works with python2.6 + +import datetime, os, re, sys, traceback +import math, string, copy +import subprocess +from subprocess import * +from operator import itemgetter + +class Test: + def __init__(self, path, name): + self.path = path + self.name = name + + @classmethod + def from_file(cls, path, name, options): + return cls(path, name) + +def find_tests(dir, substring = None): + ans = [] + for dirpath, dirnames, filenames in os.walk(dir): + if dirpath == '.': + continue + for filename in filenames: + if not filename.endswith('.js'): + continue + test = os.path.join(dirpath, filename) + if substring is None or substring in os.path.relpath(test, dir): + ans.append([test, filename]) + return ans + +def get_test_cmd(path): + return [ JS, '-f', path ] + +def avg(seq): + return sum(seq) / len(seq) + +def stddev(seq, mean): + diffs = ((float(item) - mean) ** 2 for item in seq) + return math.sqrt(sum(diffs) / len(seq)) + +def run_test(test): + env = os.environ.copy() + cmd = get_test_cmd(test.path) + total = [] + mark = [] + sweep = [] + close_fds = sys.platform != 'win32' + p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=close_fds, env=env) + out, err = p.communicate() + out, err = out.decode(), err.decode() + + float_array = [float(_) for _ in err.split()] + + if len(float_array) == 0: + print('Error: No data from application. Configured with --enable-gctimer?') + sys.exit(1) + + for i, currItem in enumerate(float_array): + if (i % 3 == 0): + total.append(currItem) + else: + if (i % 3 == 1): + mark.append(currItem) + else: + sweep.append(currItem) + + return max(total), avg(total), max(mark), avg(mark), max(sweep), avg(sweep) + +def run_tests(tests, test_dir): + bench_map = {} + + try: + for i, test in enumerate(tests): + filename_str = '"%s"' % test.name + TMax, TAvg, MMax, MAvg, SMax, SAvg = run_test(test) + bench_map[test.name] = [TMax, TAvg, MMax, MAvg, SMax, SAvg] + fmt = '%20s: {"TMax": %4.1f, "TAvg": %4.1f, "MMax": %4.1f, "MAvg": %4.1f, "SMax": %4.1f, "SAvg": %4.1f}' + if (i != len(tests) - 1): + fmt += ',' + print(fmt %(filename_str ,TMax, TAvg, MMax, MAvg, SMax, MAvg)) + except KeyboardInterrupt: + print('fail') + + return dict((filename, dict(TMax=TMax, TAvg=TAvg, MMax=MMax, MAvg=MAvg, SMax=SMax, SAvg=SAvg)) + for filename, (TMax, TAvg, MMax, MAvg, SMax, SAvg) in bench_map.iteritems()) + +def compare(current, baseline): + percent_speedups = [] + for key, current_result in current.iteritems(): + try: + baseline_result = baseline[key] + except KeyError: + print key, 'missing from baseline' + continue + + val_getter = itemgetter('TMax', 'TAvg', 'MMax', 'MAvg', 'SMax', 'SAvg') + BTMax, BTAvg, BMMax, BMAvg, BSMax, BSAvg = val_getter(baseline_result) + CTMax, CTAvg, CMMax, CMAvg, CSMax, CSAvg = val_getter(current_result) + + fmt = '%30s: %s' + if CTAvg <= BTAvg: + speedup = (CTAvg / BTAvg - 1) * 100 + result = 'faster: %6.2f < baseline %6.2f (%+6.2f%%)' % \ + (CTAvg, BTAvg, speedup) + percent_speedups.append(speedup) + else: + slowdown = (CTAvg / BTAvg - 1) * 100 + result = 'SLOWER: %6.2f > baseline %6.2f (%+6.2f%%) ' % \ + (CTAvg, BTAvg, slowdown) + percent_speedups.append(slowdown) + print '%30s: %s' % (key, result) + if percent_speedups: + print 'Average speedup: %.2f%%' % avg(percent_speedups) + +def try_import_json(): + try: + import json + return json + except ImportError: + try: + import simplejson as json + return json + except ImportError: + pass + +if __name__ == '__main__': + script_path = os.path.abspath(__file__) + script_dir = os.path.dirname(script_path) + test_dir = os.path.join(script_dir, 'tests') + + from optparse import OptionParser + op = OptionParser(usage='%prog [options] JS_SHELL [TESTS]') + + op.add_option('-b', '--baseline', metavar='JSON_PATH', + dest='baseline_path', help='json file with baseline values to ' + 'compare against') + + (OPTIONS, args) = op.parse_args() + if len(args) < 1: + op.error('missing JS_SHELL argument') + # We need to make sure we are using backslashes on Windows. + JS, test_args = os.path.normpath(args[0]), args[1:] + + test_list = [] + bench_map = {} + + test_list = find_tests(test_dir) + + if not test_list: + print >> sys.stderr, "No tests found matching command line arguments." + sys.exit(0) + + test_list = [ Test.from_file(tst, name, OPTIONS) for tst, name in test_list ] + + if OPTIONS.baseline_path: + json = try_import_json() + if not json: + print('You need a json lib for baseline comparison') + sys.exit(1) + try: + print("{") + bench_map = run_tests(test_list, test_dir) + print("}") + + except OSError: + if not os.path.exists(JS): + print >> sys.stderr, "JS shell argument: file does not exist: '%s'"%JS + sys.exit(1) + else: + raise + + if OPTIONS.baseline_path: + baseline_map = [] + fh = open(OPTIONS.baseline_path, 'r') + baseline_map = json.load(fh) + fh.close() + compare(current=bench_map, baseline=baseline_map) diff --git a/js/src/metrics/gc/tests/clock.js b/js/src/metrics/gc/tests/clock.js new file mode 100644 index 0000000..fd2fb98 --- /dev/null +++ b/js/src/metrics/gc/tests/clock.js @@ -0,0 +1,35 @@ +//Shell version of Clock Benchmark: https://bug548388.bugzilla.mozilla.org/attachment.cgi?id=434576 + +var t0; +var tl; + +function alloc(dt) { + if (dt > 100) + dt = 100; + for (var i = 0; i < dt * 1000; ++i) { + var o = new String("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + } +} + +function cycle() { + if (!running) + return; + + var t1 = new Date; + if (t0 == undefined) t0 = t1; + + if (tl != undefined) { + var dt = t1 - tl; + alloc(dt); + } + + tl = t1; + + if(t1 - t0 > (5 * 1000)) + running = false; +} + +var running = true; +while(running) + cycle(); + diff --git a/js/src/metrics/gc/tests/dslots.js b/js/src/metrics/gc/tests/dslots.js new file mode 100644 index 0000000..8fcb6e8 --- /dev/null +++ b/js/src/metrics/gc/tests/dslots.js @@ -0,0 +1,26 @@ +//Benchmark to measure overhead of dslots allocation and deallocation + +function Object0() {}; +function Object1() { this.a=1; }; +function Object2() { this.a=1; this.b=1; }; +function Object3() { this.a=1; this.b=1; this.c=1; }; +function Object4() { this.a=1; this.b=1; this.c=1; this.d=1; }; +function Object5() { this.a=1; this.b=1; this.c=1; this.d=1; this.e=1; }; + +function test() { + var N = 1e5; + gc(); + + for(var i = 0; i<=5; i++) + { + var tmp = i==0 ? Object0 : i==1 ? Object1 : i==2 ? Object2 : i==3 ? Object3 : i==4 ? Object4 : Object5; + for (var j = 0; j != N; j++) { + var a = new tmp(); + } + gc(); + } +} + +for(var i = 0; i<=5; i++) { + test(); +} diff --git a/js/src/metrics/gc/tests/loops.js b/js/src/metrics/gc/tests/loops.js new file mode 100644 index 0000000..a99961a --- /dev/null +++ b/js/src/metrics/gc/tests/loops.js @@ -0,0 +1,55 @@ +//Measure plain GC. + +var t = []; +var N = 500000 + +for(var i = 0; i < N; i++) + t[i] = {}; + +gc() + +t = []; + +gc(); + +for(var i = 0; i < N; i++) + t[i] = ({}); + +gc(); + +t = []; + +gc(); + + +for(var i = 0; i < N; i++) + t[i] = "asdf"; + +gc(); + +t = []; + +gc(); + + +for(var i = 0; i < N; i++) + t[i] = 1.12345; + +gc(); + +t=[]; + +gc(); + +for(var i = 0; i < N; i++) { + t[i] = ({}); + if (i != 0) + t[i].a = t[i-1]; +} + +gc(); + +t = []; + +gc(); + diff --git a/js/src/metrics/gc/tests/objGraph.js b/js/src/metrics/gc/tests/objGraph.js new file mode 100644 index 0000000..6076331 --- /dev/null +++ b/js/src/metrics/gc/tests/objGraph.js @@ -0,0 +1,37 @@ +test(); + +function test() +{ + function generate_big_object_graph() + { + var root = {}; + f(root, 17); + return root; + function f(parent, depth) { + if (depth == 0) + return; + --depth; + + f(parent.a = {}, depth); + f(parent.b = {}, depth); + } + } + + function f(obj) { + with (obj) + return arguments; + } + + for(var i = 0; i != 10; ++i) + { + gc(); + var x = null; + x = f(generate_big_object_graph()); + + gc(); //all used + + x = null; + + gc(); //all free + } +} diff --git a/js/src/metrics/jint/sunspider/3d-cube.js b/js/src/metrics/jint/sunspider/3d-cube.js new file mode 100644 index 0000000..fa4b735 --- /dev/null +++ b/js/src/metrics/jint/sunspider/3d-cube.js @@ -0,0 +1,369 @@ +// 3D Cube Rotation +// http://www.speich.net/computer/moztesting/3d.htm +// Created by Simon Speich + +var Q = new Array(); +var MTrans = new Array(); // transformation matrix +var MQube = new Array(); // position information of qube +var I = new Array(); // entity matrix +var Origin = new Object(); +var Testing = new Object(); +var LoopTimer; + +var DisplArea = new Object(); +DisplArea.Width = 300; +DisplArea.Height = 300; + +function DrawLine(From, To) { + var x1 = From.V[0]; + var x2 = To.V[0]; + var y1 = From.V[1]; + var y2 = To.V[1]; + var dx = Math.abs(x2 - x1); + var dy = Math.abs(y2 - y1); + var x = x1; + var y = y1; + var IncX1, IncY1; + var IncX2, IncY2; + var Den; + var Num; + var NumAdd; + var NumPix; + + if (x2 >= x1) { IncX1 = 1; IncX2 = 1; } + else { IncX1 = -1; IncX2 = -1; } + if (y2 >= y1) { IncY1 = 1; IncY2 = 1; } + else { IncY1 = -1; IncY2 = -1; } + if (dx >= dy) { + IncX1 = 0; + IncY2 = 0; + Den = dx; + Num = dx / 2; + NumAdd = dy; + NumPix = dx; + } + else { + IncX2 = 0; + IncY1 = 0; + Den = dy; + Num = dy / 2; + NumAdd = dx; + NumPix = dy; + } + + NumPix = Math.round(Q.LastPx + NumPix); + + var i = Q.LastPx; +/* BEGIN LOOP */ + for (; i < NumPix; i++) { + Num += NumAdd; + if (Num >= Den) { + Num -= Den; + x += IncX1; + y += IncY1; + } + x += IncX2; + y += IncY2; + } +/* END LOOP */ + Q.LastPx = NumPix; +} + +function CalcCross(V0, V1) { + var Cross = new Array(); + Cross[0] = V0[1]*V1[2] - V0[2]*V1[1]; + Cross[1] = V0[2]*V1[0] - V0[0]*V1[2]; + Cross[2] = V0[0]*V1[1] - V0[1]*V1[0]; + return Cross; +} + +function CalcNormal(V0, V1, V2) { + var A = new Array(); var B = new Array(); +/* BEGIN LOOP */ + for (var i = 0; i < 3; i++) { + A[i] = V0[i] - V1[i]; + B[i] = V2[i] - V1[i]; + } +/* END LOOP */ + A = CalcCross(A, B); + var Length = Math.sqrt(A[0]*A[0] + A[1]*A[1] + A[2]*A[2]); +/* BEGIN LOOP */ + for (var i = 0; i < 3; i++) A[i] = A[i] / Length; +/* END LOOP */ + A[3] = 1; + return A; +} + +function CreateP(X,Y,Z) { + this.V = [X,Y,Z,1]; +} + +// multiplies two matrices +function MMulti(M1, M2) { + var M = [[],[],[],[]]; + var i = 0; + var j = 0; +/* BEGIN LOOP */ + for (; i < 4; i++) { + j = 0; +/* BEGIN LOOP */ + for (; j < 4; j++) M[i][j] = M1[i][0] * M2[0][j] + M1[i][1] * M2[1][j] + M1[i][2] * M2[2][j] + M1[i][3] * M2[3][j]; +/* END LOOP */ + } +/* END LOOP */ + return M; +} + +//multiplies matrix with vector +function VMulti(M, V) { + var Vect = new Array(); + var i = 0; +/* BEGIN LOOP */ + for (;i < 4; i++) Vect[i] = M[i][0] * V[0] + M[i][1] * V[1] + M[i][2] * V[2] + M[i][3] * V[3]; +/* END LOOP */ + return Vect; +} + +function VMulti2(M, V) { + var Vect = new Array(); + var i = 0; +/* BEGIN LOOP */ + for (;i < 3; i++) Vect[i] = M[i][0] * V[0] + M[i][1] * V[1] + M[i][2] * V[2]; +/* END LOOP */ + return Vect; +} + +// add to matrices +function MAdd(M1, M2) { + var M = [[],[],[],[]]; + var i = 0; + var j = 0; +/* BEGIN LOOP */ + for (; i < 4; i++) { + j = 0; +/* BEGIN LOOP */ + for (; j < 4; j++) M[i][j] = M1[i][j] + M2[i][j]; +/* END LOOP */ + } +/* END LOOP */ + return M; +} + +function Translate(M, Dx, Dy, Dz) { + var T = [ + [1,0,0,Dx], + [0,1,0,Dy], + [0,0,1,Dz], + [0,0,0,1] + ]; + return MMulti(T, M); +} + +function RotateX(M, Phi) { + var a = Phi; + a *= Math.PI / 180; + var Cos = Math.cos(a); + var Sin = Math.sin(a); + var R = [ + [1,0,0,0], + [0,Cos,-Sin,0], + [0,Sin,Cos,0], + [0,0,0,1] + ]; + return MMulti(R, M); +} + +function RotateY(M, Phi) { + var a = Phi; + a *= Math.PI / 180; + var Cos = Math.cos(a); + var Sin = Math.sin(a); + var R = [ + [Cos,0,Sin,0], + [0,1,0,0], + [-Sin,0,Cos,0], + [0,0,0,1] + ]; + return MMulti(R, M); +} + +function RotateZ(M, Phi) { + var a = Phi; + a *= Math.PI / 180; + var Cos = Math.cos(a); + var Sin = Math.sin(a); + var R = [ + [Cos,-Sin,0,0], + [Sin,Cos,0,0], + [0,0,1,0], + [0,0,0,1] + ]; + return MMulti(R, M); +} + +function DrawQube() { + // calc current normals + var CurN = new Array(); + var i = 5; + Q.LastPx = 0; +/* BEGIN LOOP */ + for (; i > -1; i--) CurN[i] = VMulti2(MQube, Q.Normal[i]); +/* END LOOP */ + if (CurN[0][2] < 0) { + if (!Q.Line[0]) { DrawLine(Q[0], Q[1]); Q.Line[0] = true; }; + if (!Q.Line[1]) { DrawLine(Q[1], Q[2]); Q.Line[1] = true; }; + if (!Q.Line[2]) { DrawLine(Q[2], Q[3]); Q.Line[2] = true; }; + if (!Q.Line[3]) { DrawLine(Q[3], Q[0]); Q.Line[3] = true; }; + } + if (CurN[1][2] < 0) { + if (!Q.Line[2]) { DrawLine(Q[3], Q[2]); Q.Line[2] = true; }; + if (!Q.Line[9]) { DrawLine(Q[2], Q[6]); Q.Line[9] = true; }; + if (!Q.Line[6]) { DrawLine(Q[6], Q[7]); Q.Line[6] = true; }; + if (!Q.Line[10]) { DrawLine(Q[7], Q[3]); Q.Line[10] = true; }; + } + if (CurN[2][2] < 0) { + if (!Q.Line[4]) { DrawLine(Q[4], Q[5]); Q.Line[4] = true; }; + if (!Q.Line[5]) { DrawLine(Q[5], Q[6]); Q.Line[5] = true; }; + if (!Q.Line[6]) { DrawLine(Q[6], Q[7]); Q.Line[6] = true; }; + if (!Q.Line[7]) { DrawLine(Q[7], Q[4]); Q.Line[7] = true; }; + } + if (CurN[3][2] < 0) { + if (!Q.Line[4]) { DrawLine(Q[4], Q[5]); Q.Line[4] = true; }; + if (!Q.Line[8]) { DrawLine(Q[5], Q[1]); Q.Line[8] = true; }; + if (!Q.Line[0]) { DrawLine(Q[1], Q[0]); Q.Line[0] = true; }; + if (!Q.Line[11]) { DrawLine(Q[0], Q[4]); Q.Line[11] = true; }; + } + if (CurN[4][2] < 0) { + if (!Q.Line[11]) { DrawLine(Q[4], Q[0]); Q.Line[11] = true; }; + if (!Q.Line[3]) { DrawLine(Q[0], Q[3]); Q.Line[3] = true; }; + if (!Q.Line[10]) { DrawLine(Q[3], Q[7]); Q.Line[10] = true; }; + if (!Q.Line[7]) { DrawLine(Q[7], Q[4]); Q.Line[7] = true; }; + } + if (CurN[5][2] < 0) { + if (!Q.Line[8]) { DrawLine(Q[1], Q[5]); Q.Line[8] = true; }; + if (!Q.Line[5]) { DrawLine(Q[5], Q[6]); Q.Line[5] = true; }; + if (!Q.Line[9]) { DrawLine(Q[6], Q[2]); Q.Line[9] = true; }; + if (!Q.Line[1]) { DrawLine(Q[2], Q[1]); Q.Line[1] = true; }; + } + Q.Line = [false,false,false,false,false,false,false,false,false,false,false,false]; + Q.LastPx = 0; +} + +function Loop() { + if (Testing.LoopCount > Testing.LoopMax) return; + var TestingStr = String(Testing.LoopCount); +/* BEGIN LOOP */ + while (TestingStr.length < 3) TestingStr = "0" + TestingStr; +/* END LOOP */ + MTrans = Translate(I, -Q[8].V[0], -Q[8].V[1], -Q[8].V[2]); + MTrans = RotateX(MTrans, 1); + MTrans = RotateY(MTrans, 3); + MTrans = RotateZ(MTrans, 5); + MTrans = Translate(MTrans, Q[8].V[0], Q[8].V[1], Q[8].V[2]); + MQube = MMulti(MTrans, MQube); + var i = 8; +/* BEGIN LOOP */ + for (; i > -1; i--) { + Q[i].V = VMulti(MTrans, Q[i].V); + } +/* END LOOP */ + DrawQube(); + Testing.LoopCount++; + Loop(); +} + +function Init(CubeSize) { + // init/reset vars + Origin.V = [150,150,20,1]; + Testing.LoopCount = 0; + Testing.LoopMax = 50; + Testing.TimeMax = 0; + Testing.TimeAvg = 0; + Testing.TimeMin = 0; + Testing.TimeTemp = 0; + Testing.TimeTotal = 0; + Testing.Init = false; + + // transformation matrix + MTrans = [ + [1,0,0,0], + [0,1,0,0], + [0,0,1,0], + [0,0,0,1] + ]; + + // position information of qube + MQube = [ + [1,0,0,0], + [0,1,0,0], + [0,0,1,0], + [0,0,0,1] + ]; + + // entity matrix + I = [ + [1,0,0,0], + [0,1,0,0], + [0,0,1,0], + [0,0,0,1] + ]; + + // create qube + Q[0] = new CreateP(-CubeSize,-CubeSize, CubeSize); + Q[1] = new CreateP(-CubeSize, CubeSize, CubeSize); + Q[2] = new CreateP( CubeSize, CubeSize, CubeSize); + Q[3] = new CreateP( CubeSize,-CubeSize, CubeSize); + Q[4] = new CreateP(-CubeSize,-CubeSize,-CubeSize); + Q[5] = new CreateP(-CubeSize, CubeSize,-CubeSize); + Q[6] = new CreateP( CubeSize, CubeSize,-CubeSize); + Q[7] = new CreateP( CubeSize,-CubeSize,-CubeSize); + + // center of gravity + Q[8] = new CreateP(0, 0, 0); + + // anti-clockwise edge check + Q.Edge = [[0,1,2],[3,2,6],[7,6,5],[4,5,1],[4,0,3],[1,5,6]]; + + // calculate squad normals + Q.Normal = new Array(); +/* BEGIN LOOP */ + for (var i = 0; i < Q.Edge.length; i++) Q.Normal[i] = CalcNormal(Q[Q.Edge[i][0]].V, Q[Q.Edge[i][1]].V, Q[Q.Edge[i][2]].V); +/* END LOOP */ + + // line drawn ? + Q.Line = [false,false,false,false,false,false,false,false,false,false,false,false]; + + // create line pixels + Q.NumPx = 9 * 2 * CubeSize; +/* BEGIN LOOP */ + for (var i = 0; i < Q.NumPx; i++) CreateP(0,0,0); +/* END LOOP */ + + MTrans = Translate(MTrans, Origin.V[0], Origin.V[1], Origin.V[2]); + MQube = MMulti(MTrans, MQube); + + var i = 0; +/* BEGIN LOOP */ + for (; i < 9; i++) { + Q[i].V = VMulti(MTrans, Q[i].V); + } +/* END LOOP */ + DrawQube(); + Testing.Init = true; + Loop(); +} + +/* BEGIN LOOP */ +for ( var i = 20; i <= 160; i *= 2 ) { + Init(i); +} +/* END LOOP */ + +Q = null; +MTrans = null; +MQube = null; +I = null; +Origin = null; +Testing = null; +LoopTime = null; +DisplArea = null; diff --git a/js/src/metrics/jint/sunspider/3d-morph.js b/js/src/metrics/jint/sunspider/3d-morph.js new file mode 100644 index 0000000..049a329 --- /dev/null +++ b/js/src/metrics/jint/sunspider/3d-morph.js @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +var loops = 15 +var nx = 120 +var nz = 120 + +function morph(a, f) { + var PI2nx = Math.PI * 8/nx + var sin = Math.sin + var f30 = -(50 * sin(f*Math.PI*2)) + +/* BEGIN LOOP */ + for (var i = 0; i < nz; ++i) { +/* BEGIN LOOP */ + for (var j = 0; j < nx; ++j) { + a[3*(i*nx+j)+1] = sin((j-1) * PI2nx ) * -f30 + } +/* END LOOP */ + } +/* END LOOP */ +} + + +var a = Array() +/* BEGIN LOOP */ +for (var i=0; i < nx*nz*3; ++i) + a[i] = 0 +/* END LOOP */ + +/* BEGIN LOOP */ +for (var i = 0; i < loops; ++i) { + morph(a, i/loops) +} +/* END LOOP */ + +testOutput = 0; +/* BEGIN LOOP */ +for (var i = 0; i < nx; i++) + testOutput += a[3*(i*nx+i)+1]; +/* END LOOP */ +a = null; diff --git a/js/src/metrics/jint/sunspider/3d-raytrace.js b/js/src/metrics/jint/sunspider/3d-raytrace.js new file mode 100644 index 0000000..d0f860f --- /dev/null +++ b/js/src/metrics/jint/sunspider/3d-raytrace.js @@ -0,0 +1,466 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function createVector(x,y,z) { + return new Array(x,y,z); +} + +function sqrLengthVector(self) { + return self[0] * self[0] + self[1] * self[1] + self[2] * self[2]; +} + +function lengthVector(self) { + return Math.sqrt(self[0] * self[0] + self[1] * self[1] + self[2] * self[2]); +} + +function addVector(self, v) { + self[0] += v[0]; + self[1] += v[1]; + self[2] += v[2]; + return self; +} + +function subVector(self, v) { + self[0] -= v[0]; + self[1] -= v[1]; + self[2] -= v[2]; + return self; +} + +function scaleVector(self, scale) { + self[0] *= scale; + self[1] *= scale; + self[2] *= scale; + return self; +} + +function normaliseVector(self) { + var len = Math.sqrt(self[0] * self[0] + self[1] * self[1] + self[2] * self[2]); + self[0] /= len; + self[1] /= len; + self[2] /= len; + return self; +} + +function add(v1, v2) { + return new Array(v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]); +} + +function sub(v1, v2) { + return new Array(v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]); +} + +function scalev(v1, v2) { + return new Array(v1[0] * v2[0], v1[1] * v2[1], v1[2] * v2[2]); +} + +function dot(v1, v2) { + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; +} + +function scale(v, scale) { + return [v[0] * scale, v[1] * scale, v[2] * scale]; +} + +function cross(v1, v2) { + return [v1[1] * v2[2] - v1[2] * v2[1], + v1[2] * v2[0] - v1[0] * v2[2], + v1[0] * v2[1] - v1[1] * v2[0]]; + +} + +function normalise(v) { + var len = lengthVector(v); + return [v[0] / len, v[1] / len, v[2] / len]; +} + +function transformMatrix(self, v) { + var vals = self; + var x = vals[0] * v[0] + vals[1] * v[1] + vals[2] * v[2] + vals[3]; + var y = vals[4] * v[0] + vals[5] * v[1] + vals[6] * v[2] + vals[7]; + var z = vals[8] * v[0] + vals[9] * v[1] + vals[10] * v[2] + vals[11]; + return [x, y, z]; +} + +function invertMatrix(self) { + var temp = new Array(16); + var tx = -self[3]; + var ty = -self[7]; + var tz = -self[11]; + /* BEGIN LOOP */ + for (h = 0; h < 3; h++) { + /* BEGIN LOOP */ + for (v = 0; v < 3; v++) + temp[h + v * 4] = self[v + h * 4]; + /* END LOOP */ + } + /* END LOOP */ + /* BEGIN LOOP */ + for (i = 0; i < 11; i++) + self[i] = temp[i]; + /* END LOOP */ + self[3] = tx * self[0] + ty * self[1] + tz * self[2]; + self[7] = tx * self[4] + ty * self[5] + tz * self[6]; + self[11] = tx * self[8] + ty * self[9] + tz * self[10]; + return self; +} + + +// Triangle intersection using barycentric coord method +function Triangle(p1, p2, p3) { + var edge1 = sub(p3, p1); + var edge2 = sub(p2, p1); + var normal = cross(edge1, edge2); + if (Math.abs(normal[0]) > Math.abs(normal[1])) + if (Math.abs(normal[0]) > Math.abs(normal[2])) + this.axis = 0; + else + this.axis = 2; + else + if (Math.abs(normal[1]) > Math.abs(normal[2])) + this.axis = 1; + else + this.axis = 2; + var u = (this.axis + 1) % 3; + var v = (this.axis + 2) % 3; + var u1 = edge1[u]; + var v1 = edge1[v]; + + var u2 = edge2[u]; + var v2 = edge2[v]; + this.normal = normalise(normal); + this.nu = normal[u] / normal[this.axis]; + this.nv = normal[v] / normal[this.axis]; + this.nd = dot(normal, p1) / normal[this.axis]; + var det = u1 * v2 - v1 * u2; + this.eu = p1[u]; + this.ev = p1[v]; + this.nu1 = u1 / det; + this.nv1 = -v1 / det; + this.nu2 = v2 / det; + this.nv2 = -u2 / det; + this.material = [0.7, 0.7, 0.7]; +} + +Triangle.prototype.intersect = function(orig, dir, near, far) { + var u = (this.axis + 1) % 3; + var v = (this.axis + 2) % 3; + var d = dir[this.axis] + this.nu * dir[u] + this.nv * dir[v]; + var t = (this.nd - orig[this.axis] - this.nu * orig[u] - this.nv * orig[v]) / d; + if (t < near || t > far) + return null; + var Pu = orig[u] + t * dir[u] - this.eu; + var Pv = orig[v] + t * dir[v] - this.ev; + var a2 = Pv * this.nu1 + Pu * this.nv1; + if (a2 < 0) + return null; + var a3 = Pu * this.nu2 + Pv * this.nv2; + if (a3 < 0) + return null; + + if ((a2 + a3) > 1) + return null; + return t; +} + +function Scene(a_triangles) { + this.triangles = a_triangles; + this.lights = []; + this.ambient = [0,0,0]; + this.background = [0.8,0.8,1]; +} +var zero = new Array(0,0,0); + +Scene.prototype.intersect = function(origin, dir, near, far) { + var closest = null; + /* BEGIN LOOP */ + for (i = 0; i < this.triangles.length; i++) { + var triangle = this.triangles[i]; + var d = triangle.intersect(origin, dir, near, far); + if (d == null || d > far || d < near) + continue; + far = d; + closest = triangle; + } + /* END LOOP */ + + if (!closest) + return [this.background[0],this.background[1],this.background[2]]; + + var normal = closest.normal; + var hit = add(origin, scale(dir, far)); + if (dot(dir, normal) > 0) + normal = [-normal[0], -normal[1], -normal[2]]; + + var colour = null; + if (closest.shader) { + colour = closest.shader(closest, hit, dir); + } else { + colour = closest.material; + } + + // do reflection + var reflected = null; + if (colour.reflection > 0.001) { + var reflection = addVector(scale(normal, -2*dot(dir, normal)), dir); + reflected = this.intersect(hit, reflection, 0.0001, 1000000); + if (colour.reflection >= 0.999999) + return reflected; + } + + var l = [this.ambient[0], this.ambient[1], this.ambient[2]]; + /* BEGIN LOOP */ + for (var i = 0; i < this.lights.length; i++) { + var light = this.lights[i]; + var toLight = sub(light, hit); + var distance = lengthVector(toLight); + scaleVector(toLight, 1.0/distance); + distance -= 0.0001; + if (this.blocked(hit, toLight, distance)) + continue; + var nl = dot(normal, toLight); + if (nl > 0) + addVector(l, scale(light.colour, nl)); + } + /* END LOOP */ + l = scalev(l, colour); + if (reflected) { + l = addVector(scaleVector(l, 1 - colour.reflection), scaleVector(reflected, colour.reflection)); + } + return l; +} + +Scene.prototype.blocked = function(O, D, far) { + var near = 0.0001; + var closest = null; + /* BEGIN LOOP */ + for (i = 0; i < this.triangles.length; i++) { + var triangle = this.triangles[i]; + var d = triangle.intersect(O, D, near, far); + if (d == null || d > far || d < near) + continue; + return true; + } + /* END LOOP */ + + return false; +} + + +// this camera code is from notes i made ages ago, it is from *somewhere* -- i cannot remember where +// that somewhere is +function Camera(origin, lookat, up) { + var zaxis = normaliseVector(subVector(lookat, origin)); + var xaxis = normaliseVector(cross(up, zaxis)); + var yaxis = normaliseVector(cross(xaxis, subVector([0,0,0], zaxis))); + var m = new Array(16); + m[0] = xaxis[0]; m[1] = xaxis[1]; m[2] = xaxis[2]; + m[4] = yaxis[0]; m[5] = yaxis[1]; m[6] = yaxis[2]; + m[8] = zaxis[0]; m[9] = zaxis[1]; m[10] = zaxis[2]; + invertMatrix(m); + m[3] = 0; m[7] = 0; m[11] = 0; + this.origin = origin; + this.directions = new Array(4); + this.directions[0] = normalise([-0.7, 0.7, 1]); + this.directions[1] = normalise([ 0.7, 0.7, 1]); + this.directions[2] = normalise([ 0.7, -0.7, 1]); + this.directions[3] = normalise([-0.7, -0.7, 1]); + this.directions[0] = transformMatrix(m, this.directions[0]); + this.directions[1] = transformMatrix(m, this.directions[1]); + this.directions[2] = transformMatrix(m, this.directions[2]); + this.directions[3] = transformMatrix(m, this.directions[3]); +} + +Camera.prototype.generateRayPair = function(y) { + rays = new Array(new Object(), new Object()); + rays[0].origin = this.origin; + rays[1].origin = this.origin; + rays[0].dir = addVector(scale(this.directions[0], y), scale(this.directions[3], 1 - y)); + rays[1].dir = addVector(scale(this.directions[1], y), scale(this.directions[2], 1 - y)); + return rays; +} + +function renderRows(camera, scene, pixels, width, height, starty, stopy) { + /* BEGIN LOOP */ + for (var y = starty; y < stopy; y++) { + var rays = camera.generateRayPair(y / height); + /* BEGIN LOOP */ + for (var x = 0; x < width; x++) { + var xp = x / width; + var origin = addVector(scale(rays[0].origin, xp), scale(rays[1].origin, 1 - xp)); + var dir = normaliseVector(addVector(scale(rays[0].dir, xp), scale(rays[1].dir, 1 - xp))); + var l = scene.intersect(origin, dir); + pixels[y][x] = l; + } + /* END LOOP */ + } + /* END LOOP */ +} + +Camera.prototype.render = function(scene, pixels, width, height) { + var cam = this; + var row = 0; + renderRows(cam, scene, pixels, width, height, 0, height); +} + + + +function raytraceScene() +{ + var startDate = new Date().getTime(); + var numTriangles = 2 * 6; + var triangles = new Array();//numTriangles); + var tfl = createVector(-10, 10, -10); + var tfr = createVector( 10, 10, -10); + var tbl = createVector(-10, 10, 10); + var tbr = createVector( 10, 10, 10); + var bfl = createVector(-10, -10, -10); + var bfr = createVector( 10, -10, -10); + var bbl = createVector(-10, -10, 10); + var bbr = createVector( 10, -10, 10); + + // cube!!! + // front + var i = 0; + + triangles[i++] = new Triangle(tfl, tfr, bfr); + triangles[i++] = new Triangle(tfl, bfr, bfl); + // back + triangles[i++] = new Triangle(tbl, tbr, bbr); + triangles[i++] = new Triangle(tbl, bbr, bbl); + // triangles[i-1].material = [0.7,0.2,0.2]; + // triangles[i-1].material.reflection = 0.8; + // left + triangles[i++] = new Triangle(tbl, tfl, bbl); + // triangles[i-1].reflection = 0.6; + triangles[i++] = new Triangle(tfl, bfl, bbl); + // triangles[i-1].reflection = 0.6; + // right + triangles[i++] = new Triangle(tbr, tfr, bbr); + triangles[i++] = new Triangle(tfr, bfr, bbr); + // top + triangles[i++] = new Triangle(tbl, tbr, tfr); + triangles[i++] = new Triangle(tbl, tfr, tfl); + // bottom + triangles[i++] = new Triangle(bbl, bbr, bfr); + triangles[i++] = new Triangle(bbl, bfr, bfl); + + //Floor!!!! + var green = createVector(0.0, 0.4, 0.0); + var grey = createVector(0.4, 0.4, 0.4); + grey.reflection = 1.0; + var floorShader = function(tri, pos, view) { + var x = ((pos[0]/32) % 2 + 2) % 2; + var z = ((pos[2]/32 + 0.3) % 2 + 2) % 2; + if (x < 1 != z < 1) { + //in the real world we use the fresnel term... + // var angle = 1-dot(view, tri.normal); + // angle *= angle; + // angle *= angle; + // angle *= angle; + //grey.reflection = angle; + return grey; + } else + return green; + } + var ffl = createVector(-1000, -30, -1000); + var ffr = createVector( 1000, -30, -1000); + var fbl = createVector(-1000, -30, 1000); + var fbr = createVector( 1000, -30, 1000); + triangles[i++] = new Triangle(fbl, fbr, ffr); + triangles[i-1].shader = floorShader; + triangles[i++] = new Triangle(fbl, ffr, ffl); + triangles[i-1].shader = floorShader; + + var _scene = new Scene(triangles); + _scene.lights[0] = createVector(20, 38, -22); + _scene.lights[0].colour = createVector(0.7, 0.3, 0.3); + _scene.lights[1] = createVector(-23, 40, 17); + _scene.lights[1].colour = createVector(0.7, 0.3, 0.3); + _scene.lights[2] = createVector(23, 20, 17); + _scene.lights[2].colour = createVector(0.7, 0.7, 0.7); + _scene.ambient = createVector(0.1, 0.1, 0.1); + // _scene.background = createVector(0.7, 0.7, 1.0); + + var size = 30; + var pixels = new Array(); + /* BEGIN LOOP */ + for (var y = 0; y < size; y++) { + pixels[y] = new Array(); + /* BEGIN LOOP */ + for (var x = 0; x < size; x++) { + pixels[y][x] = 0; + } + /* END LOOP */ + } + /* END LOOP */ + + var _camera = new Camera(createVector(-40, 40, 40), createVector(0, 0, 0), createVector(0, 1, 0)); + _camera.render(_scene, pixels, size, size); + + return pixels; +} + +function arrayToCanvasCommands(pixels) +{ + var s = '\nvar pixels = ['; + var size = 30; + /* BEGIN LOOP */ + for (var y = 0; y < size; y++) { + s += "["; + /* BEGIN LOOP */ + for (var x = 0; x < size; x++) { + s += "[" + pixels[y][x] + "],"; + } + /* END LOOP */ + s+= "],"; + } + /* END LOOP */ + s += '];\n var canvas = document.getElementById("renderCanvas").getContext("2d");\n\ +\n\ +\n\ + var size = 30;\n\ + canvas.fillStyle = "red";\n\ + canvas.fillRect(0, 0, size, size);\n\ + canvas.scale(1, -1);\n\ + canvas.translate(0, -size);\n\ +\n\ + if (!canvas.setFillColor)\n\ + canvas.setFillColor = function(r, g, b, a) {\n\ + this.fillStyle = "rgb("+[Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)]+")";\n\ + }\n\ +\n\ +for (var y = 0; y < size; y++) {\n\ + for (var x = 0; x < size; x++) {\n\ + var l = pixels[y][x];\n\ + canvas.setFillColor(l[0], l[1], l[2], 1);\n\ + canvas.fillRect(x, y, 1, 1);\n\ + }\n\ +}'; + + return s; +} + +testOutput = arrayToCanvasCommands(raytraceScene()); diff --git a/js/src/metrics/jint/sunspider/access-binary-trees.js b/js/src/metrics/jint/sunspider/access-binary-trees.js new file mode 100644 index 0000000..475d0a2 --- /dev/null +++ b/js/src/metrics/jint/sunspider/access-binary-trees.js @@ -0,0 +1,56 @@ +/* The Great Computer Language Shootout + http://shootout.alioth.debian.org/ + contributed by Isaac Gouy */ + +function TreeNode(left,right,item){ + this.left = left; + this.right = right; + this.item = item; +} + +TreeNode.prototype.itemCheck = function(){ + if (this.left==null) return this.item; + else return this.item + this.left.itemCheck() - this.right.itemCheck(); +} + +function bottomUpTree(item,depth){ + if (depth>0){ + return new TreeNode( + bottomUpTree(2*item-1, depth-1) + ,bottomUpTree(2*item, depth-1) + ,item + ); + } + else { + return new TreeNode(null,null,item); + } +} + +var ret; + +/* BEGIN LOOP */ +for ( var n = 4; n <= 7; n += 1 ) { + var minDepth = 4; + var maxDepth = Math.max(minDepth + 2, n); + var stretchDepth = maxDepth + 1; + + var check = bottomUpTree(0,stretchDepth).itemCheck(); + + var longLivedTree = bottomUpTree(0,maxDepth); + /* BEGIN LOOP */ + for (var depth=minDepth; depth<=maxDepth; depth+=2){ + var iterations = 1 << (maxDepth - depth + minDepth); + + check = 0; + /* BEGIN LOOP */ + for (var i=1; i<=iterations; i++){ + check += bottomUpTree(i,depth).itemCheck(); + check += bottomUpTree(-i,depth).itemCheck(); + } + /* END LOOP */ + } + /* END LOOP */ + + ret = longLivedTree.itemCheck(); +} +/* END LOOP */ diff --git a/js/src/metrics/jint/sunspider/access-fannkuch.js b/js/src/metrics/jint/sunspider/access-fannkuch.js new file mode 100644 index 0000000..acc0510 --- /dev/null +++ b/js/src/metrics/jint/sunspider/access-fannkuch.js @@ -0,0 +1,86 @@ +/* The Great Computer Language Shootout + http://shootout.alioth.debian.org/ + contributed by Isaac Gouy */ + +function fannkuch(n) { + var check = 0; + var perm = Array(n); + var perm1 = Array(n); + var count = Array(n); + var maxPerm = Array(n); + var maxFlipsCount = 0; + var m = n - 1; + + /* BEGIN LOOP */ + for (var i = 0; i < n; i++) perm1[i] = i; + /* END LOOP */ + var r = n; + + /* BEGIN LOOP */ + while (true) { + // write-out the first 30 permutations + if (check < 30){ + var s = ""; + /* BEGIN LOOP */ + for(var i=0; i> 1; + /* BEGIN LOOP */ + for (var i = 0; i < k2; i++) { + var temp = perm[i]; perm[i] = perm[k - i]; perm[k - i] = temp; + } + /* END LOOP */ + flipsCount++; + } + /* END LOOP */ + + if (flipsCount > maxFlipsCount) { + maxFlipsCount = flipsCount; + /* BEGIN LOOP */ + for (var i = 0; i < n; i++) maxPerm[i] = perm1[i]; + /* END LOOP */ + } + } + + /* BEGIN LOOP */ + while (true) { + if (r == n) return maxFlipsCount; + var perm0 = perm1[0]; + var i = 0; + /* BEGIN LOOP */ + while (i < r) { + var j = i + 1; + perm1[i] = perm1[j]; + i = j; + } + /* END LOOP */ + perm1[r] = perm0; + + count[r] = count[r] - 1; + if (count[r] > 0) break; + r++; + } + /* END LOOP */ + } + /* END LOOP */ +} + +var n = 8; +var ret = fannkuch(n); + diff --git a/js/src/metrics/jint/sunspider/access-nbody.js b/js/src/metrics/jint/sunspider/access-nbody.js new file mode 100644 index 0000000..7b4c711 --- /dev/null +++ b/js/src/metrics/jint/sunspider/access-nbody.js @@ -0,0 +1,185 @@ +/* The Great Computer Language Shootout + http://shootout.alioth.debian.org/ + contributed by Isaac Gouy */ + +var PI = 3.141592653589793; +var SOLAR_MASS = 4 * PI * PI; +var DAYS_PER_YEAR = 365.24; + +function Body(x,y,z,vx,vy,vz,mass){ + this.x = x; + this.y = y; + this.z = z; + this.vx = vx; + this.vy = vy; + this.vz = vz; + this.mass = mass; +} + +Body.prototype.offsetMomentum = function(px,py,pz) { + this.vx = -px / SOLAR_MASS; + this.vy = -py / SOLAR_MASS; + this.vz = -pz / SOLAR_MASS; + return this; +} + +function Jupiter(){ + return new Body( + 4.84143144246472090e+00, + -1.16032004402742839e+00, + -1.03622044471123109e-01, + 1.66007664274403694e-03 * DAYS_PER_YEAR, + 7.69901118419740425e-03 * DAYS_PER_YEAR, + -6.90460016972063023e-05 * DAYS_PER_YEAR, + 9.54791938424326609e-04 * SOLAR_MASS + ); +} + +function Saturn(){ + return new Body( + 8.34336671824457987e+00, + 4.12479856412430479e+00, + -4.03523417114321381e-01, + -2.76742510726862411e-03 * DAYS_PER_YEAR, + 4.99852801234917238e-03 * DAYS_PER_YEAR, + 2.30417297573763929e-05 * DAYS_PER_YEAR, + 2.85885980666130812e-04 * SOLAR_MASS + ); +} + +function Uranus(){ + return new Body( + 1.28943695621391310e+01, + -1.51111514016986312e+01, + -2.23307578892655734e-01, + 2.96460137564761618e-03 * DAYS_PER_YEAR, + 2.37847173959480950e-03 * DAYS_PER_YEAR, + -2.96589568540237556e-05 * DAYS_PER_YEAR, + 4.36624404335156298e-05 * SOLAR_MASS + ); +} + +function Neptune(){ + return new Body( + 1.53796971148509165e+01, + -2.59193146099879641e+01, + 1.79258772950371181e-01, + 2.68067772490389322e-03 * DAYS_PER_YEAR, + 1.62824170038242295e-03 * DAYS_PER_YEAR, + -9.51592254519715870e-05 * DAYS_PER_YEAR, + 5.15138902046611451e-05 * SOLAR_MASS + ); +} + +function Sun(){ + return new Body(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, SOLAR_MASS); +} + + +function NBodySystem(bodies){ + this.bodies = bodies; + var px = 0.0; + var py = 0.0; + var pz = 0.0; + var size = this.bodies.length; + /* BEGIN LOOP */ + for (var i=0; i0){ + /* BEGIN LOOP */ + for (var i=1; i<=prefixWidth; i++) s = " " + s; + /* END LOOP */ + } + return s; +} + +function nsieve(m, isPrime){ + var i, k, count; + + /* BEGIN LOOP */ + for (i=2; i<=m; i++) { isPrime[i] = true; } + /* END LOOP */ + count = 0; + + /* BEGIN LOOP */ + for (i=2; i<=m; i++){ + if (isPrime[i]) { + /* BEGIN LOOP */ + for (k=i+i; k<=m; k+=i) isPrime[k] = false; + /* END LOOP */ + count++; + } + } + /* END LOOP */ + return count; +} + +function sieve() { + /* BEGIN LOOP */ + for (var i = 1; i <= 3; i++ ) { + var m = (1<> ((b << 1) & 14)); +c += 3 & (bi3b >> ((b >> 2) & 14)); +c += 3 & (bi3b >> ((b >> 5) & 6)); +return c; + +/* +lir4,0xE994; 9 instructions, no memory access, minimal register dependence, 6 shifts, 2 adds, 1 inline assign +rlwinmr5,r3,1,28,30 +rlwinmr6,r3,30,28,30 +rlwinmr7,r3,27,29,30 +rlwnmr8,r4,r5,30,31 +rlwnmr9,r4,r6,30,31 +rlwnmr10,r4,r7,30,31 +addr3,r8,r9 +addr3,r3,r10 +*/ +} + + +function TimeFunc(func) { +var x, y, t; +/* BEGIN LOOP */ +for(var x=0; x<500; x++) { + /* BEGIN LOOP */ +for(var y=0; y<256; y++) func(y); + /* END LOOP */ +} +/* END LOOP */ +} + +TimeFunc(fast3bitlookup); diff --git a/js/src/metrics/jint/sunspider/bitops-bits-in-byte.js b/js/src/metrics/jint/sunspider/bitops-bits-in-byte.js new file mode 100644 index 0000000..c64e261 --- /dev/null +++ b/js/src/metrics/jint/sunspider/bitops-bits-in-byte.js @@ -0,0 +1,28 @@ +// Copyright (c) 2004 by Arthur Langereis (arthur_ext at domain xfinitegames, tld com) + + +// 1 op = 2 assigns, 16 compare/branches, 8 ANDs, (0-8) ADDs, 8 SHLs +// O(n) +function bitsinbyte(b) { +var m = 1, c = 0; +/* BEGIN LOOP */ +while(m<0x100) { +if(b & m) c++; +m <<= 1; +} +/* END LOOP */ +return c; +} + +function TimeFunc(func) { +var x, y, t; +/* BEGIN LOOP */ +for(var x=0; x<350; x++) { +/* BEGIN LOOP */ +for(var y=0; y<256; y++) func(y); +/* END LOOP */ +} +/* END LOOP */ +} + +TimeFunc(bitsinbyte); diff --git a/js/src/metrics/jint/sunspider/bitops-bitwise-and.js b/js/src/metrics/jint/sunspider/bitops-bitwise-and.js new file mode 100644 index 0000000..4e1ae8e --- /dev/null +++ b/js/src/metrics/jint/sunspider/bitops-bitwise-and.js @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +bitwiseAndValue = 4294967296; +/* BEGIN LOOP */ +for (var i = 0; i < 600000; i++) + bitwiseAndValue = bitwiseAndValue & i; +/* END LOOP */ diff --git a/js/src/metrics/jint/sunspider/bitops-nsieve-bits.js b/js/src/metrics/jint/sunspider/bitops-nsieve-bits.js new file mode 100644 index 0000000..982cf59 --- /dev/null +++ b/js/src/metrics/jint/sunspider/bitops-nsieve-bits.js @@ -0,0 +1,42 @@ +// The Great Computer Language Shootout +// http://shootout.alioth.debian.org +// +// Contributed by Ian Osgood + +function pad(n,width) { + var s = n.toString(); + /* BEGIN LOOP */ + while (s.length < width) s = ' ' + s; + /* END LOOP */ + return s; +} + +function primes(isPrime, n) { + var i, count = 0, m = 10000<>5; + + /* BEGIN LOOP */ + for (i=0; i>5] & 1<<(i&31)) { + /* BEGIN LOOP */ + for (var j=i+i; j>5] &= ~(1<<(j&31)); + /* END LOOP */ + count++; + } + /* END LOOP */ +} + +function sieve() { + /* BEGIN LOOP */ + for (var i = 4; i <= 4; i++) { + var isPrime = new Array((10000<>5); + primes(isPrime, i); + } + /* END LOOP */ +} + +sieve(); diff --git a/js/src/metrics/jint/sunspider/controlflow-recursive.js b/js/src/metrics/jint/sunspider/controlflow-recursive.js new file mode 100644 index 0000000..09eeedd --- /dev/null +++ b/js/src/metrics/jint/sunspider/controlflow-recursive.js @@ -0,0 +1,27 @@ +// The Computer Language Shootout +// http://shootout.alioth.debian.org/ +// contributed by Isaac Gouy + +function ack(m,n){ + if (m==0) { return n+1; } + if (n==0) { return ack(m-1,1); } + return ack(m-1, ack(m,n-1) ); +} + +function fib(n) { + if (n < 2){ return 1; } + return fib(n-2) + fib(n-1); +} + +function tak(x,y,z) { + if (y >= x) return z; + return tak(tak(x-1,y,z), tak(y-1,z,x), tak(z-1,x,y)); +} + +/* BEGIN LOOP */ +for ( var i = 3; i <= 5; i++ ) { + ack(3,i); + fib(17.0+i); + tak(3*i+3,2*i+2,i+1); +} +/* END LOOP */ diff --git a/js/src/metrics/jint/sunspider/crypto-aes.js b/js/src/metrics/jint/sunspider/crypto-aes.js new file mode 100644 index 0000000..912c8a3 --- /dev/null +++ b/js/src/metrics/jint/sunspider/crypto-aes.js @@ -0,0 +1,494 @@ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* + * AES Cipher function: encrypt 'input' with Rijndael algorithm + * + * takes byte-array 'input' (16 bytes) + * 2D byte-array key schedule 'w' (Nr+1 x Nb bytes) + * + * applies Nr rounds (10/12/14) using key schedule w for 'add round key' stage + * + * returns byte-array encrypted value (16 bytes) + */ +function Cipher(input, w) { // main Cipher function [§5.1] + var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES) + var Nr = w.length/Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys + + var state = [[],[],[],[]]; // initialise 4xNb byte-array 'state' with input [§3.4] + /* BEGIN LOOP */ + for (var i=0; i<4*Nb; i++) state[i%4][Math.floor(i/4)] = input[i]; + /* END LOOP */ + + state = AddRoundKey(state, w, 0, Nb); + + /* BEGIN LOOP */ + for (var round=1; round 6 && i%Nk == 4) { + temp = SubWord(temp); + } + /* BEGIN LOOP */ + for (var t=0; t<4; t++) w[i][t] = w[i-Nk][t] ^ temp[t]; + /* END LOOP */ + } + /* END LOOP */ + + return w; +} + +function SubWord(w) { // apply SBox to 4-byte word w + /* BEGIN LOOP */ + for (var i=0; i<4; i++) w[i] = Sbox[w[i]]; + /* END LOOP */ + return w; +} + +function RotWord(w) { // rotate 4-byte word w left by one byte + w[4] = w[0]; + /* BEGIN LOOP */ + for (var i=0; i<4; i++) w[i] = w[i+1]; + /* END LOOP */ + return w; +} + + +// Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [§5.1.1] +var Sbox = [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, + 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, + 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, + 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, + 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, + 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, + 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, + 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, + 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, + 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, + 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, + 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, + 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, + 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, + 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, + 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16]; + +// Rcon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [§5.2] +var Rcon = [ [0x00, 0x00, 0x00, 0x00], + [0x01, 0x00, 0x00, 0x00], + [0x02, 0x00, 0x00, 0x00], + [0x04, 0x00, 0x00, 0x00], + [0x08, 0x00, 0x00, 0x00], + [0x10, 0x00, 0x00, 0x00], + [0x20, 0x00, 0x00, 0x00], + [0x40, 0x00, 0x00, 0x00], + [0x80, 0x00, 0x00, 0x00], + [0x1b, 0x00, 0x00, 0x00], + [0x36, 0x00, 0x00, 0x00] ]; + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* + * Use AES to encrypt 'plaintext' with 'password' using 'nBits' key, in 'Counter' mode of operation + * - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + * for each block + * - outputblock = cipher(counter, key) + * - cipherblock = plaintext xor outputblock + */ +function AESEncryptCtr(plaintext, password, nBits) { + if (!(nBits==128 || nBits==192 || nBits==256)) return ''; // standard allows 128/192/256 bit keys + + // for this example script, generate the key by applying Cipher to 1st 16/24/32 chars of password; + // for real-world applications, a more secure approach would be to hash the password e.g. with SHA-1 + var nBytes = nBits/8; // no bytes in key + var pwBytes = new Array(nBytes); + /* BEGIN LOOP */ + for (var i=0; i>> i*8) & 0xff; + /* END LOOP */ + /* BEGIN LOOP */ + for (var i=0; i<4; i++) counterBlock[i+4] = (nonce/0x100000000 >>> i*8) & 0xff; + /* END LOOP */ + + // generate key schedule - an expansion of the key into distinct Key Rounds for each round + var keySchedule = KeyExpansion(key); + + var blockCount = Math.ceil(plaintext.length/blockSize); + var ciphertext = new Array(blockCount); // ciphertext as array of strings + + /* BEGIN LOOP */ + for (var b=0; b>> c*8) & 0xff; + /* END LOOP */ + /* BEGIN LOOP */ + for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8) + /* END LOOP */ + + var cipherCntr = Cipher(counterBlock, keySchedule); // -- encrypt counter block -- + + // calculate length of final block: + var blockLength = b>> c*8) & 0xff; + /* END LOOP */ + /* BEGIN LOOP */ + for (var c=0; c<4; c++) counterBlock[15-c-4] = ((b/0x100000000-1) >>> c*8) & 0xff; + /* END LOOP */ + + var cipherCntr = Cipher(counterBlock, keySchedule); // encrypt counter block + + ciphertext[b] = unescCtrlChars(ciphertext[b]); + + var pt = ''; + /* BEGIN LOOP */ + for (var i=0; i>18 & 0x3f; + h2 = bits>>12 & 0x3f; + h3 = bits>>6 & 0x3f; + h4 = bits & 0x3f; + + // end of string? index to '=' in b64 + if (isNaN(o3)) h4 = 64; + if (isNaN(o2)) h3 = 64; + + // use hexets to index into b64, and append result to encoded string + enc += b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); + } while (i < str.length); + /* END LOOP */ + + return enc; +} + +function decodeBase64(str) { + var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc=''; + + /* BEGIN LOOP */ + do { // unpack four hexets into three octets using index points in b64 + h1 = b64.indexOf(str.charAt(i++)); + h2 = b64.indexOf(str.charAt(i++)); + h3 = b64.indexOf(str.charAt(i++)); + h4 = b64.indexOf(str.charAt(i++)); + + bits = h1<<18 | h2<<12 | h3<<6 | h4; + + o1 = bits>>16 & 0xff; + o2 = bits>>8 & 0xff; + o3 = bits & 0xff; + + if (h3 == 64) enc += String.fromCharCode(o1); + else if (h4 == 64) enc += String.fromCharCode(o1, o2); + else enc += String.fromCharCode(o1, o2, o3); + } while (i < str.length); + /* END LOOP */ + + return decodeUTF8(enc); // decode UTF-8 byte-array back to Unicode +} + +function encodeUTF8(str) { // encode multi-byte string into utf-8 multiple single-byte characters + str = str.replace( + /[\u0080-\u07ff]/g, // U+0080 - U+07FF = 2-byte chars + function(c) { + var cc = c.charCodeAt(0); + return String.fromCharCode(0xc0 | cc>>6, 0x80 | cc&0x3f); } + ); + str = str.replace( + /[\u0800-\uffff]/g, // U+0800 - U+FFFF = 3-byte chars + function(c) { + var cc = c.charCodeAt(0); + return String.fromCharCode(0xe0 | cc>>12, 0x80 | cc>>6&0x3F, 0x80 | cc&0x3f); } + ); + return str; +} + +function decodeUTF8(str) { // decode utf-8 encoded string back into multi-byte characters + str = str.replace( + /[\u00c0-\u00df][\u0080-\u00bf]/g, // 2-byte chars + function(c) { + var cc = (c.charCodeAt(0)&0x1f)<<6 | c.charCodeAt(1)&0x3f; + return String.fromCharCode(cc); } + ); + str = str.replace( + /[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, // 3-byte chars + function(c) { + var cc = (c.charCodeAt(0)&0x0f)<<12 | (c.charCodeAt(1)&0x3f<<6) | c.charCodeAt(2)&0x3f; + return String.fromCharCode(cc); } + ); + return str; +} + + +function byteArrayToHexStr(b) { // convert byte array to hex string for displaying test vectors + var s = ''; + /* BEGIN LOOP */ + for (var i=0; i> 5] |= 0x80 << ((len) % 32); + x[(((len + 64) >>> 9) << 4) + 14] = len; + + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + + /* BEGIN LOOP */ + for(var i = 0; i < x.length; i += 16) + { + var olda = a; + var oldb = b; + var oldc = c; + var oldd = d; + + a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); + d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); + c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); + b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); + a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); + d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); + c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); + b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); + a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); + d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); + c = md5_ff(c, d, a, b, x[i+10], 17, -42063); + b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); + a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); + d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); + c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); + b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); + + a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); + d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); + c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); + b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); + a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); + d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); + c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); + b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); + a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); + d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); + c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); + b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); + a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); + d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); + c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); + b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); + + a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); + d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); + c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); + b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); + a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); + d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); + c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); + b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); + a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); + d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); + c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); + b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); + a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); + d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); + c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); + b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); + + a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); + d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); + c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); + b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); + a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); + d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); + c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); + b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); + a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); + d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); + c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); + b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); + a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); + d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); + c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); + b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + } + /* END LOOP */ + return Array(a, b, c, d); + +} + +/* + * These functions implement the four basic operations the algorithm uses. + */ +function md5_cmn(q, a, b, x, s, t) +{ + return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); +} +function md5_ff(a, b, c, d, x, s, t) +{ + return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); +} +function md5_gg(a, b, c, d, x, s, t) +{ + return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); +} +function md5_hh(a, b, c, d, x, s, t) +{ + return md5_cmn(b ^ c ^ d, a, b, x, s, t); +} +function md5_ii(a, b, c, d, x, s, t) +{ + return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); +} + +/* + * Calculate the HMAC-MD5, of a key and some data + */ +function core_hmac_md5(key, data) +{ + var bkey = str2binl(key); + if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz); + + var ipad = Array(16), opad = Array(16); + /* BEGIN LOOP */ + for(var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + /* END LOOP */ + + var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); + return core_md5(opad.concat(hash), 512 + 128); +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function bit_rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +} + +/* + * Convert a string to an array of little-endian words + * If chrsz is ASCII, characters >255 have their hi-byte silently ignored. + */ +function str2binl(str) +{ + var bin = Array(); + var mask = (1 << chrsz) - 1; + /* BEGIN LOOP */ + for(var i = 0; i < str.length * chrsz; i += chrsz) + bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); + /* END LOOP */ + return bin; +} + +/* + * Convert an array of little-endian words to a string + */ +function binl2str(bin) +{ + var str = ""; + var mask = (1 << chrsz) - 1; + /* BEGIN LOOP */ + for(var i = 0; i < bin.length * 32; i += chrsz) + str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); + /* END LOOP */ + return str; +} + +/* + * Convert an array of little-endian words to a hex string. + */ +function binl2hex(binarray) +{ + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var str = ""; + /* BEGIN LOOP */ + for(var i = 0; i < binarray.length * 4; i++) + { + str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + + hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF); + } + /* END LOOP */ + return str; +} + +/* + * Convert an array of little-endian words to a base-64 string + */ +function binl2b64(binarray) +{ + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var str = ""; + /* BEGIN LOOP */ + for(var i = 0; i < binarray.length * 4; i += 3) + { + var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16) + | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) + | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF); + /* BEGIN LOOP */ + for(var j = 0; j < 4; j++) + { + if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; + else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); + } + /* END LOOP */ + } + /* END LOOP */ + return str; +} + +var plainText = "Rebellious subjects, enemies to peace,\n\ +Profaners of this neighbour-stained steel,--\n\ +Will they not hear? What, ho! you men, you beasts,\n\ +That quench the fire of your pernicious rage\n\ +With purple fountains issuing from your veins,\n\ +On pain of torture, from those bloody hands\n\ +Throw your mistemper'd weapons to the ground,\n\ +And hear the sentence of your moved prince.\n\ +Three civil brawls, bred of an airy word,\n\ +By thee, old Capulet, and Montague,\n\ +Have thrice disturb'd the quiet of our streets,\n\ +And made Verona's ancient citizens\n\ +Cast by their grave beseeming ornaments,\n\ +To wield old partisans, in hands as old,\n\ +Canker'd with peace, to part your canker'd hate:\n\ +If ever you disturb our streets again,\n\ +Your lives shall pay the forfeit of the peace.\n\ +For this time, all the rest depart away:\n\ +You Capulet; shall go along with me:\n\ +And, Montague, come you this afternoon,\n\ +To know our further pleasure in this case,\n\ +To old Free-town, our common judgment-place.\n\ +Once more, on pain of death, all men depart." + + /* BEGIN LOOP */ +for (var i = 0; i <4; i++) { + plainText += plainText; +} + /* END LOOP */ + +var md5Output = hex_md5(plainText); diff --git a/js/src/metrics/jint/sunspider/crypto-sha1.js b/js/src/metrics/jint/sunspider/crypto-sha1.js new file mode 100644 index 0000000..08e81b9 --- /dev/null +++ b/js/src/metrics/jint/sunspider/crypto-sha1.js @@ -0,0 +1,242 @@ +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined + * in FIPS PUB 180-1 + * Version 2.1a Copyright Paul Johnston 2000 - 2002. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for details. + */ + +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ +var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ + +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));} +function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));} +function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));} +function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));} +function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));} +function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));} + +/* + * Perform a simple self-test to see if the VM is working + */ +function sha1_vm_test() +{ + return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; +} + +/* + * Calculate the SHA-1 of an array of big-endian words, and a bit length + */ +function core_sha1(x, len) +{ + /* append padding */ + x[len >> 5] |= 0x80 << (24 - len % 32); + x[((len + 64 >> 9) << 4) + 15] = len; + + var w = Array(80); + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + var e = -1009589776; + + /* BEGIN LOOP */ + for(var i = 0; i < x.length; i += 16) + { + var olda = a; + var oldb = b; + var oldc = c; + var oldd = d; + var olde = e; + + /* BEGIN LOOP */ + for(var j = 0; j < 80; j++) + { + if(j < 16) w[j] = x[i + j]; + else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); + var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), + safe_add(safe_add(e, w[j]), sha1_kt(j))); + e = d; + d = c; + c = rol(b, 30); + b = a; + a = t; + } + /* END LOOP */ + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + e = safe_add(e, olde); + } + /* END LOOP */ + return Array(a, b, c, d, e); + +} + +/* + * Perform the appropriate triplet combination function for the current + * iteration + */ +function sha1_ft(t, b, c, d) +{ + if(t < 20) return (b & c) | ((~b) & d); + if(t < 40) return b ^ c ^ d; + if(t < 60) return (b & c) | (b & d) | (c & d); + return b ^ c ^ d; +} + +/* + * Determine the appropriate additive constant for the current iteration + */ +function sha1_kt(t) +{ + return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : + (t < 60) ? -1894007588 : -899497514; +} + +/* + * Calculate the HMAC-SHA1 of a key and some data + */ +function core_hmac_sha1(key, data) +{ + var bkey = str2binb(key); + if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz); + + var ipad = Array(16), opad = Array(16); + /* BEGIN LOOP */ + for(var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + /* END LOOP */ + + var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); + return core_sha1(opad.concat(hash), 512 + 160); +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +} + +/* + * Convert an 8-bit or 16-bit string to an array of big-endian words + * In 8-bit function, characters >255 have their hi-byte silently ignored. + */ +function str2binb(str) +{ + var bin = Array(); + var mask = (1 << chrsz) - 1; + /* BEGIN LOOP */ + for(var i = 0; i < str.length * chrsz; i += chrsz) + bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32); + /* END LOOP */ + return bin; +} + +/* + * Convert an array of big-endian words to a string + */ +function binb2str(bin) +{ + var str = ""; + var mask = (1 << chrsz) - 1; + /* BEGIN LOOP */ + for(var i = 0; i < bin.length * 32; i += chrsz) + str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask); + /* END LOOP */ + return str; +} + +/* + * Convert an array of big-endian words to a hex string. + */ +function binb2hex(binarray) +{ + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var str = ""; + /* BEGIN LOOP */ + for(var i = 0; i < binarray.length * 4; i++) + { + str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + + hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); + } + /* END LOOP */ + return str; +} + +/* + * Convert an array of big-endian words to a base-64 string + */ +function binb2b64(binarray) +{ + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var str = ""; + /* BEGIN LOOP */ + for(var i = 0; i < binarray.length * 4; i += 3) + { + var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16) + | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) + | ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF); + /* BEGIN LOOP */ + for(var j = 0; j < 4; j++) + { + if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; + else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); + } + /* END LOOP */ + } + /* END LOOP */ + return str; +} + + +var plainText = "Two households, both alike in dignity,\n\ +In fair Verona, where we lay our scene,\n\ +From ancient grudge break to new mutiny,\n\ +Where civil blood makes civil hands unclean.\n\ +From forth the fatal loins of these two foes\n\ +A pair of star-cross'd lovers take their life;\n\ +Whole misadventured piteous overthrows\n\ +Do with their death bury their parents' strife.\n\ +The fearful passage of their death-mark'd love,\n\ +And the continuance of their parents' rage,\n\ +Which, but their children's end, nought could remove,\n\ +Is now the two hours' traffic of our stage;\n\ +The which if you with patient ears attend,\n\ +What here shall miss, our toil shall strive to mend."; + + /* BEGIN LOOP */ +for (var i = 0; i <4; i++) { + plainText += plainText; +} + /* END LOOP */ + +var sha1Output = hex_sha1(plainText); diff --git a/js/src/metrics/jint/sunspider/date-format-tofte.js b/js/src/metrics/jint/sunspider/date-format-tofte.js new file mode 100644 index 0000000..b5e81ad --- /dev/null +++ b/js/src/metrics/jint/sunspider/date-format-tofte.js @@ -0,0 +1,305 @@ +function arrayExists(array, x) { + /* BEGIN LOOP */ + for (var i = 0; i < array.length; i++) { + if (array[i] == x) return true; + } + /* END LOOP */ + return false; +} + +Date.prototype.formatDate = function (input,time) { + // formatDate : + // a PHP date like function, for formatting date strings + // See: http://www.php.net/date + // + // input : format string + // time : epoch time (seconds, and optional) + // + // if time is not passed, formatting is based on + // the current "this" date object's set time. + // + // supported: + // a, A, B, d, D, F, g, G, h, H, i, j, l (lowercase L), L, + // m, M, n, O, r, s, S, t, U, w, W, y, Y, z + // + // unsupported: + // I (capital i), T, Z + + var switches = ["a", "A", "B", "d", "D", "F", "g", "G", "h", "H", + "i", "j", "l", "L", "m", "M", "n", "O", "r", "s", + "S", "t", "U", "w", "W", "y", "Y", "z"]; + var daysLong = ["Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday"]; + var daysShort = ["Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat"]; + var monthsShort = ["Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", "Sep", + "Oct", "Nov", "Dec"]; + var monthsLong = ["January", "February", "March", "April", + "May", "June", "July", "August", "September", + "October", "November", "December"]; + var daysSuffix = ["st", "nd", "rd", "th", "th", "th", "th", // 1st - 7th + "th", "th", "th", "th", "th", "th", "th", // 8th - 14th + "th", "th", "th", "th", "th", "th", "st", // 15th - 21st + "nd", "rd", "th", "th", "th", "th", "th", // 22nd - 28th + "th", "th", "st"]; // 29th - 31st + + function a() { + // Lowercase Ante meridiem and Post meridiem + return self.getHours() > 11? "pm" : "am"; + } + function A() { + // Uppercase Ante meridiem and Post meridiem + return self.getHours() > 11? "PM" : "AM"; + } + + function B(){ + // Swatch internet time. code simply grabbed from ppk, + // since I was feeling lazy: + // http://www.xs4all.nl/~ppk/js/beat.html + var off = (self.getTimezoneOffset() + 60)*60; + var theSeconds = (self.getHours() * 3600) + + (self.getMinutes() * 60) + + self.getSeconds() + off; + var beat = Math.floor(theSeconds/86.4); + if (beat > 1000) beat -= 1000; + if (beat < 0) beat += 1000; + if ((""+beat).length == 1) beat = "00"+beat; + if ((""+beat).length == 2) beat = "0"+beat; + return beat; + } + + function d() { + // Day of the month, 2 digits with leading zeros + return new String(self.getDate()).length == 1? + "0"+self.getDate() : self.getDate(); + } + function D() { + // A textual representation of a day, three letters + return daysShort[self.getDay()]; + } + function F() { + // A full textual representation of a month + return monthsLong[self.getMonth()]; + } + function g() { + // 12-hour format of an hour without leading zeros + return self.getHours() > 12? self.getHours()-12 : self.getHours(); + } + function G() { + // 24-hour format of an hour without leading zeros + return self.getHours(); + } + function h() { + // 12-hour format of an hour with leading zeros + if (self.getHours() > 12) { + var s = new String(self.getHours()-12); + return s.length == 1? + "0"+ (self.getHours()-12) : self.getHours()-12; + } else { + var s = new String(self.getHours()); + return s.length == 1? + "0"+self.getHours() : self.getHours(); + } + } + function H() { + // 24-hour format of an hour with leading zeros + return new String(self.getHours()).length == 1? + "0"+self.getHours() : self.getHours(); + } + function i() { + // Minutes with leading zeros + return new String(self.getMinutes()).length == 1? + "0"+self.getMinutes() : self.getMinutes(); + } + function j() { + // Day of the month without leading zeros + return self.getDate(); + } + function l() { + // A full textual representation of the day of the week + return daysLong[self.getDay()]; + } + function L() { + // leap year or not. 1 if leap year, 0 if not. + // the logic should match iso's 8601 standard. + var y_ = Y(); + if ( + (y_ % 4 == 0 && y_ % 100 != 0) || + (y_ % 4 == 0 && y_ % 100 == 0 && y_ % 400 == 0) + ) { + return 1; + } else { + return 0; + } + } + function m() { + // Numeric representation of a month, with leading zeros + return self.getMonth() < 9? + "0"+(self.getMonth()+1) : + self.getMonth()+1; + } + function M() { + // A short textual representation of a month, three letters + return monthsShort[self.getMonth()]; + } + function n() { + // Numeric representation of a month, without leading zeros + return self.getMonth()+1; + } + function O() { + // Difference to Greenwich time (GMT) in hours + var os = Math.abs(self.getTimezoneOffset()); + var h = ""+Math.floor(os/60); + var m = ""+(os%60); + h.length == 1? h = "0"+h:1; + m.length == 1? m = "0"+m:1; + return self.getTimezoneOffset() < 0 ? "+"+h+m : "-"+h+m; + } + function r() { + // RFC 822 formatted date + var r; // result + // Thu , 21 Dec 2000 + r = D() + ", " + j() + " " + M() + " " + Y() + + // 16 : 01 : 07 +0200 + " " + H() + ":" + i() + ":" + s() + " " + O(); + return r; + } + function S() { + // English ordinal suffix for the day of the month, 2 characters + return daysSuffix[self.getDate()-1]; + } + function s() { + // Seconds, with leading zeros + return new String(self.getSeconds()).length == 1? + "0"+self.getSeconds() : self.getSeconds(); + } + function t() { + + // thanks to Matt Bannon for some much needed code-fixes here! + var daysinmonths = [null,31,28,31,30,31,30,31,31,30,31,30,31]; + if (L()==1 && n()==2) return 29; // leap day + return daysinmonths[n()]; + } + function U() { + // Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) + return Math.round(self.getTime()/1000); + } + function W() { + // Weeknumber, as per ISO specification: + // http://www.cl.cam.ac.uk/~mgk25/iso-time.html + + // if the day is three days before newyears eve, + // there's a chance it's "week 1" of next year. + // here we check for that. + var beforeNY = 364+L() - z(); + var afterNY = z(); + var weekday = w()!=0?w()-1:6; // makes sunday (0), into 6. + if (beforeNY <= 2 && weekday <= 2-beforeNY) { + return 1; + } + // similarly, if the day is within threedays of newyears + // there's a chance it belongs in the old year. + var ny = new Date("January 1 " + Y() + " 00:00:00"); + var nyDay = ny.getDay()!=0?ny.getDay()-1:6; + if ( + (afterNY <= 2) && + (nyDay >=4) && + (afterNY >= (6-nyDay)) + ) { + // Since I'm not sure we can just always return 53, + // i call the function here again, using the last day + // of the previous year, as the date, and then just + // return that week. + var prevNY = new Date("December 31 " + (Y()-1) + " 00:00:00"); + return prevNY.formatDate("W"); + } + + // week 1, is the week that has the first thursday in it. + // note that this value is not zero index. + if (nyDay <= 3) { + // first day of the year fell on a thursday, or earlier. + return 1 + Math.floor( ( z() + nyDay ) / 7 ); + } else { + // first day of the year fell on a friday, or later. + return 1 + Math.floor( ( z() - ( 7 - nyDay ) ) / 7 ); + } + } + function w() { + // Numeric representation of the day of the week + return self.getDay(); + } + + function Y() { + // A full numeric representation of a year, 4 digits + + // we first check, if getFullYear is supported. if it + // is, we just use that. ppks code is nice, but wont + // work with dates outside 1900-2038, or something like that + if (self.getFullYear) { + var newDate = new Date("January 1 2001 00:00:00 +0000"); + var x = newDate .getFullYear(); + if (x == 2001) { + // i trust the method now + return self.getFullYear(); + } + } + // else, do this: + // codes thanks to ppk: + // http://www.xs4all.nl/~ppk/js/introdate.html + var x = self.getYear(); + var y = x % 100; + y += (y < 38) ? 2000 : 1900; + return y; + } + function y() { + // A two-digit representation of a year + var y = Y()+""; + return y.substring(y.length-2,y.length); + } + function z() { + // The day of the year, zero indexed! 0 through 366 + var t = new Date("January 1 " + Y() + " 00:00:00"); + var diff = self.getTime() - t.getTime(); + return Math.floor(diff/1000/60/60/24); + } + + var self = this; + if (time) { + // save time + var prevTime = self.getTime(); + self.setTime(time); + } + + var ia = input.split(""); + var ij = 0; + /* BEGIN LOOP */ + while (ia[ij]) { + if (ia[ij] == "\\") { + // this is our way of allowing users to escape stuff + ia.splice(ij,1); + } else { + if (arrayExists(switches,ia[ij])) { + ia[ij] = eval(ia[ij] + "()"); + } + } + ij++; + } + /* END LOOP */ + // reset time, back to what it was + if (prevTime) { + self.setTime(prevTime); + } + return ia.join(""); +} + +var date = new Date("1/1/2007 1:11:11"); + + /* BEGIN LOOP */ +for (i = 0; i < 500; ++i) { + var shortFormat = date.formatDate("Y-m-d"); + var longFormat = date.formatDate("l, F d, Y g:i:s A"); + date.setTime(date.getTime() + 84266956); +} + /* END LOOP */ + diff --git a/js/src/metrics/jint/sunspider/date-format-xparb.js b/js/src/metrics/jint/sunspider/date-format-xparb.js new file mode 100644 index 0000000..ef1dc23 --- /dev/null +++ b/js/src/metrics/jint/sunspider/date-format-xparb.js @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2004 Baron Schwartz + * + * This program 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, version 2.1. + * + * This program 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. + */ + +Date.parseFunctions = {count:0}; +Date.parseRegexes = []; +Date.formatFunctions = {count:0}; + +Date.prototype.dateFormat = function(format) { + if (Date.formatFunctions[format] == null) { + Date.createNewFormat(format); + } + var func = Date.formatFunctions[format]; + return this[func](); +} + +Date.createNewFormat = function(format) { + var funcName = "format" + Date.formatFunctions.count++; + Date.formatFunctions[format] = funcName; + var code = "Date.prototype." + funcName + " = function(){return "; + var special = false; + var ch = ''; + /* BEGIN LOOP */ + for (var i = 0; i < format.length; ++i) { + ch = format.charAt(i); + if (!special && ch == "\\") { + special = true; + } + else if (special) { + special = false; + code += "'" + String.escape(ch) + "' + "; + } + else { + code += Date.getFormatCode(ch); + } + } + /* END LOOP */ + eval(code.substring(0, code.length - 3) + ";}"); +} + +Date.getFormatCode = function(character) { + switch (character) { + case "d": + return "String.leftPad(this.getDate(), 2, '0') + "; + case "D": + return "Date.dayNames[this.getDay()].substring(0, 3) + "; + case "j": + return "this.getDate() + "; + case "l": + return "Date.dayNames[this.getDay()] + "; + case "S": + return "this.getSuffix() + "; + case "w": + return "this.getDay() + "; + case "z": + return "this.getDayOfYear() + "; + case "W": + return "this.getWeekOfYear() + "; + case "F": + return "Date.monthNames[this.getMonth()] + "; + case "m": + return "String.leftPad(this.getMonth() + 1, 2, '0') + "; + case "M": + return "Date.monthNames[this.getMonth()].substring(0, 3) + "; + case "n": + return "(this.getMonth() + 1) + "; + case "t": + return "this.getDaysInMonth() + "; + case "L": + return "(this.isLeapYear() ? 1 : 0) + "; + case "Y": + return "this.getFullYear() + "; + case "y": + return "('' + this.getFullYear()).substring(2, 4) + "; + case "a": + return "(this.getHours() < 12 ? 'am' : 'pm') + "; + case "A": + return "(this.getHours() < 12 ? 'AM' : 'PM') + "; + case "g": + return "((this.getHours() %12) ? this.getHours() % 12 : 12) + "; + case "G": + return "this.getHours() + "; + case "h": + return "String.leftPad((this.getHours() %12) ? this.getHours() % 12 : 12, 2, '0') + "; + case "H": + return "String.leftPad(this.getHours(), 2, '0') + "; + case "i": + return "String.leftPad(this.getMinutes(), 2, '0') + "; + case "s": + return "String.leftPad(this.getSeconds(), 2, '0') + "; + case "O": + return "this.getGMTOffset() + "; + case "T": + return "this.getTimezone() + "; + case "Z": + return "(this.getTimezoneOffset() * -60) + "; + default: + return "'" + String.escape(character) + "' + "; + } +} + +Date.parseDate = function(input, format) { + if (Date.parseFunctions[format] == null) { + Date.createParser(format); + } + var func = Date.parseFunctions[format]; + return Date[func](input); +} + +Date.createParser = function(format) { + var funcName = "parse" + Date.parseFunctions.count++; + var regexNum = Date.parseRegexes.length; + var currentGroup = 1; + Date.parseFunctions[format] = funcName; + + var code = "Date." + funcName + " = function(input){\n" + + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1;\n" + + "var d = new Date();\n" + + "y = d.getFullYear();\n" + + "m = d.getMonth();\n" + + "d = d.getDate();\n" + + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n" + + "if (results && results.length > 0) {" + var regex = ""; + + var special = false; + var ch = ''; + /* BEGIN LOOP */ + for (var i = 0; i < format.length; ++i) { + ch = format.charAt(i); + if (!special && ch == "\\") { + special = true; + } + else if (special) { + special = false; + regex += String.escape(ch); + } + else { + obj = Date.formatCodeToRegex(ch, currentGroup); + currentGroup += obj.g; + regex += obj.s; + if (obj.g && obj.c) { + code += obj.c; + } + } + } + /* END LOOP */ + + code += "if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n" + + "{return new Date(y, m, d, h, i, s);}\n" + + "else if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n" + + "{return new Date(y, m, d, h, i);}\n" + + "else if (y > 0 && m >= 0 && d > 0 && h >= 0)\n" + + "{return new Date(y, m, d, h);}\n" + + "else if (y > 0 && m >= 0 && d > 0)\n" + + "{return new Date(y, m, d);}\n" + + "else if (y > 0 && m >= 0)\n" + + "{return new Date(y, m);}\n" + + "else if (y > 0)\n" + + "{return new Date(y);}\n" + + "}return null;}"; + + Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$"); + eval(code); +} + +Date.formatCodeToRegex = function(character, currentGroup) { + switch (character) { + case "D": + return {g:0, + c:null, + s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"}; + case "j": + case "d": + return {g:1, + c:"d = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{1,2})"}; + case "l": + return {g:0, + c:null, + s:"(?:" + Date.dayNames.join("|") + ")"}; + case "S": + return {g:0, + c:null, + s:"(?:st|nd|rd|th)"}; + case "w": + return {g:0, + c:null, + s:"\\d"}; + case "z": + return {g:0, + c:null, + s:"(?:\\d{1,3})"}; + case "W": + return {g:0, + c:null, + s:"(?:\\d{2})"}; + case "F": + return {g:1, + c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n", + s:"(" + Date.monthNames.join("|") + ")"}; + case "M": + return {g:1, + c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n", + s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"}; + case "n": + case "m": + return {g:1, + c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n", + s:"(\\d{1,2})"}; + case "t": + return {g:0, + c:null, + s:"\\d{1,2}"}; + case "L": + return {g:0, + c:null, + s:"(?:1|0)"}; + case "Y": + return {g:1, + c:"y = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{4})"}; + case "y": + return {g:1, + c:"var ty = parseInt(results[" + currentGroup + "], 10);\n" + + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n", + s:"(\\d{1,2})"}; + case "a": + return {g:1, + c:"if (results[" + currentGroup + "] == 'am') {\n" + + "if (h == 12) { h = 0; }\n" + + "} else { if (h < 12) { h += 12; }}", + s:"(am|pm)"}; + case "A": + return {g:1, + c:"if (results[" + currentGroup + "] == 'AM') {\n" + + "if (h == 12) { h = 0; }\n" + + "} else { if (h < 12) { h += 12; }}", + s:"(AM|PM)"}; + case "g": + case "G": + case "h": + case "H": + return {g:1, + c:"h = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{1,2})"}; + case "i": + return {g:1, + c:"i = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{2})"}; + case "s": + return {g:1, + c:"s = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{2})"}; + case "O": + return {g:0, + c:null, + s:"[+-]\\d{4}"}; + case "T": + return {g:0, + c:null, + s:"[A-Z]{3}"}; + case "Z": + return {g:0, + c:null, + s:"[+-]\\d{1,5}"}; + default: + return {g:0, + c:null, + s:String.escape(character)}; + } +} + +Date.prototype.getTimezone = function() { + return this.toString().replace( + /^.*? ([A-Z]{3}) [0-9]{4}.*$/, "$1").replace( + /^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, "$1$2$3"); +} + +Date.prototype.getGMTOffset = function() { + return (this.getTimezoneOffset() > 0 ? "-" : "+") + + String.leftPad(Math.floor(this.getTimezoneOffset() / 60), 2, "0") + + String.leftPad(this.getTimezoneOffset() % 60, 2, "0"); +} + +Date.prototype.getDayOfYear = function() { + var num = 0; + Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28; + /* BEGIN LOOP */ + for (var i = 0; i < this.getMonth(); ++i) { + num += Date.daysInMonth[i]; + } + /* END LOOP */ + return num + this.getDate() - 1; +} + +Date.prototype.getWeekOfYear = function() { + // Skip to Thursday of this week + var now = this.getDayOfYear() + (4 - this.getDay()); + // Find the first Thursday of the year + var jan1 = new Date(this.getFullYear(), 0, 1); + var then = (7 - jan1.getDay() + 4); + document.write(then); + return String.leftPad(((now - then) / 7) + 1, 2, "0"); +} + +Date.prototype.isLeapYear = function() { + var year = this.getFullYear(); + return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year))); +} + +Date.prototype.getFirstDayOfMonth = function() { + var day = (this.getDay() - (this.getDate() - 1)) % 7; + return (day < 0) ? (day + 7) : day; +} + +Date.prototype.getLastDayOfMonth = function() { + var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7; + return (day < 0) ? (day + 7) : day; +} + +Date.prototype.getDaysInMonth = function() { + Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28; + return Date.daysInMonth[this.getMonth()]; +} + +Date.prototype.getSuffix = function() { + switch (this.getDate()) { + case 1: + case 21: + case 31: + return "st"; + case 2: + case 22: + return "nd"; + case 3: + case 23: + return "rd"; + default: + return "th"; + } +} + +String.escape = function(string) { + return string.replace(/('|\\)/g, "\\$1"); +} + +String.leftPad = function (val, size, ch) { + var result = new String(val); + if (ch == null) { + ch = " "; + } + /* BEGIN LOOP */ + while (result.length < size) { + result = ch + result; + } + /* END LOOP */ + return result; +} + +Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31]; +Date.monthNames = + ["January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December"]; +Date.dayNames = + ["Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday"]; +Date.y2kYear = 50; +Date.monthNumbers = { + Jan:0, + Feb:1, + Mar:2, + Apr:3, + May:4, + Jun:5, + Jul:6, + Aug:7, + Sep:8, + Oct:9, + Nov:10, + Dec:11}; +Date.patterns = { + ISO8601LongPattern:"Y-m-d H:i:s", + ISO8601ShortPattern:"Y-m-d", + ShortDatePattern: "n/j/Y", + LongDatePattern: "l, F d, Y", + FullDateTimePattern: "l, F d, Y g:i:s A", + MonthDayPattern: "F d", + ShortTimePattern: "g:i A", + LongTimePattern: "g:i:s A", + SortableDateTimePattern: "Y-m-d\\TH:i:s", + UniversalSortableDateTimePattern: "Y-m-d H:i:sO", + YearMonthPattern: "F, Y"}; + +var date = new Date("1/1/2007 1:11:11"); + + /* BEGIN LOOP */ +for (i = 0; i < 4000; ++i) { + var shortFormat = date.dateFormat("Y-m-d"); + var longFormat = date.dateFormat("l, F d, Y g:i:s A"); + date.setTime(date.getTime() + 84266956); +} + /* END LOOP */ diff --git a/js/src/metrics/jint/sunspider/math-cordic.js b/js/src/metrics/jint/sunspider/math-cordic.js new file mode 100644 index 0000000..7cd67df --- /dev/null +++ b/js/src/metrics/jint/sunspider/math-cordic.js @@ -0,0 +1,99 @@ +/* + * Copyright (C) Rich Moore. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/////. Start CORDIC + +var AG_CONST = 0.6072529350; + +function FIXED(X) +{ + return X * 65536.0; +} + +function FLOAT(X) +{ + return X / 65536.0; +} + +function DEG2RAD(X) +{ + return 0.017453 * (X); +} + +var Angles = [ + FIXED(45.0), FIXED(26.565), FIXED(14.0362), FIXED(7.12502), + FIXED(3.57633), FIXED(1.78991), FIXED(0.895174), FIXED(0.447614), + FIXED(0.223811), FIXED(0.111906), FIXED(0.055953), + FIXED(0.027977) + ]; + + +function cordicsincos() { + var X; + var Y; + var TargetAngle; + var CurrAngle; + var Step; + + X = FIXED(AG_CONST); /* AG_CONST * cos(0) */ + Y = 0; /* AG_CONST * sin(0) */ + + TargetAngle = FIXED(28.027); + CurrAngle = 0; + /* BEGIN LOOP */ + for (Step = 0; Step < 12; Step++) { + var NewX; + if (TargetAngle > CurrAngle) { + NewX = X - (Y >> Step); + Y = (X >> Step) + Y; + X = NewX; + CurrAngle += Angles[Step]; + } else { + NewX = X + (Y >> Step); + Y = -(X >> Step) + Y; + X = NewX; + CurrAngle -= Angles[Step]; + } + } + /* END LOOP */ +} + +///// End CORDIC + +function cordic( runs ) { + var start = new Date(); + + /* BEGIN LOOP */ + for ( var i = 0 ; i < runs ; i++ ) { + cordicsincos(); + } + /* END LOOP */ + + var end = new Date(); + + return end.getTime() - start.getTime(); +} + +cordic(25000); diff --git a/js/src/metrics/jint/sunspider/math-partial-sums.js b/js/src/metrics/jint/sunspider/math-partial-sums.js new file mode 100644 index 0000000..07442cb --- /dev/null +++ b/js/src/metrics/jint/sunspider/math-partial-sums.js @@ -0,0 +1,37 @@ +// The Computer Language Shootout +// http://shootout.alioth.debian.org/ +// contributed by Isaac Gouy + +function partial(n){ + var a1 = a2 = a3 = a4 = a5 = a6 = a7 = a8 = a9 = 0.0; + var twothirds = 2.0/3.0; + var alt = -1.0; + var k2 = k3 = sk = ck = 0.0; + + /* BEGIN LOOP */ + for (var k = 1; k <= n; k++){ + k2 = k*k; + k3 = k2*k; + sk = Math.sin(k); + ck = Math.cos(k); + alt = -alt; + + a1 += Math.pow(twothirds,k-1); + a2 += Math.pow(k,-0.5); + a3 += 1.0/(k*(k+1.0)); + a4 += 1.0/(k3 * sk*sk); + a5 += 1.0/(k3 * ck*ck); + a6 += 1.0/k; + a7 += 1.0/k2; + a8 += alt/k; + a9 += alt/(2*k -1); + } + /* END LOOP */ +} + + /* BEGIN LOOP */ +for (var i = 1024; i <= 16384; i *= 2) { + partial(i); +} + /* END LOOP */ + diff --git a/js/src/metrics/jint/sunspider/math-spectral-norm.js b/js/src/metrics/jint/sunspider/math-spectral-norm.js new file mode 100644 index 0000000..d079568 --- /dev/null +++ b/js/src/metrics/jint/sunspider/math-spectral-norm.js @@ -0,0 +1,67 @@ +// The Great Computer Language Shootout +// http://shootout.alioth.debian.org/ +// +// contributed by Ian Osgood + +function A(i,j) { + return 1/((i+j)*(i+j+1)/2+i+1); +} + +function Au(u,v) { + /* BEGIN LOOP */ + for (var i=0; i.*\n|\n/g,"") +clen = dnaInput.length + +var dnaOutputString; + + /* BEGIN LOOP */ +for(i in seqs) + dnaOutputString += seqs[i].source + " " + (dnaInput.match(seqs[i]) || []).length + "\n"; + /* END LOOP */ + // match returns null if no matches, so replace with empty + + /* BEGIN LOOP */ +for(k in subs) + dnaInput = dnaInput.replace(k, subs[k], "g") + /* END LOOP */ + // search string, replacement string, flags diff --git a/js/src/metrics/jint/sunspider/string-base64.js b/js/src/metrics/jint/sunspider/string-base64.js new file mode 100644 index 0000000..83d3814 --- /dev/null +++ b/js/src/metrics/jint/sunspider/string-base64.js @@ -0,0 +1,143 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla XML-RPC Client component. + * + * The Initial Developer of the Original Code is + * Digital Creations 2, Inc. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Martijn Pieters (original author) + * Samuel Sieb + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// From: http://lxr.mozilla.org/mozilla/source/extensions/xml-rpc/src/nsXmlRpcClient.js#956 + +/* Convert data (an array of integers) to a Base64 string. */ +var toBase64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; +var base64Pad = '='; + +function toBase64(data) { + var result = ''; + var length = data.length; + var i; + // Convert every three bytes to 4 ascii characters. + /* BEGIN LOOP */ + for (i = 0; i < (length - 2); i += 3) { + result += toBase64Table[data[i] >> 2]; + result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)]; + result += toBase64Table[((data[i+1] & 0x0f) << 2) + (data[i+2] >> 6)]; + result += toBase64Table[data[i+2] & 0x3f]; + } + /* END LOOP */ + + // Convert the remaining 1 or 2 bytes, pad out to 4 characters. + if (length%3) { + i = length - (length%3); + result += toBase64Table[data[i] >> 2]; + if ((length%3) == 2) { + result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)]; + result += toBase64Table[(data[i+1] & 0x0f) << 2]; + result += base64Pad; + } else { + result += toBase64Table[(data[i] & 0x03) << 4]; + result += base64Pad + base64Pad; + } + } + + return result; +} + +/* Convert Base64 data to a string */ +var toBinaryTable = [ + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 +]; + +function base64ToString(data) { + var result = ''; + var leftbits = 0; // number of bits decoded, but yet to be appended + var leftdata = 0; // bits decoded, but yet to be appended + + // Convert one by one. + /* BEGIN LOOP */ + for (var i = 0; i < data.length; i++) { + var c = toBinaryTable[data.charCodeAt(i) & 0x7f]; + var padding = (data[i] == base64Pad); + // Skip illegal characters and whitespace + if (c == -1) continue; + + // Collect data into leftdata, update bitcount + leftdata = (leftdata << 6) | c; + leftbits += 6; + + // If we have 8 or more bits, append 8 bits to the result + if (leftbits >= 8) { + leftbits -= 8; + // Append if not padding. + if (!padding) + result += String.fromCharCode((leftdata >> leftbits) & 0xff); + leftdata &= (1 << leftbits) - 1; + } + } + /* END LOOP */ + + // If there are any bits left, the base64 string was corrupted + if (leftbits) + throw Components.Exception('Corrupted base64 string'); + + return result; +} + +var str = ""; + + /* BEGIN LOOP */ +for ( var i = 0; i < 8192; i++ ) + str += String.fromCharCode( (25 * Math.random()) + 97 ); + /* END LOOP */ + + /* BEGIN LOOP */ +for ( var i = 8192; i <= 16384; i *= 2 ) { + + var base64; + + base64 = toBase64(str); + base64ToString(base64); + + // Double the string + str += str; +} + /* END LOOP */ + +toBinaryTable = null; diff --git a/js/src/metrics/jint/sunspider/string-fasta.js b/js/src/metrics/jint/sunspider/string-fasta.js new file mode 100644 index 0000000..7032736 --- /dev/null +++ b/js/src/metrics/jint/sunspider/string-fasta.js @@ -0,0 +1,95 @@ +// The Great Computer Language Shootout +// http://shootout.alioth.debian.org +// +// Contributed by Ian Osgood + +var last = 42, A = 3877, C = 29573, M = 139968; + +function rand(max) { + last = (last * A + C) % M; + return max * last / M; +} + +var ALU = + "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG" + + "GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA" + + "CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT" + + "ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA" + + "GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG" + + "AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC" + + "AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA"; + +var IUB = { + a:0.27, c:0.12, g:0.12, t:0.27, + B:0.02, D:0.02, H:0.02, K:0.02, + M:0.02, N:0.02, R:0.02, S:0.02, + V:0.02, W:0.02, Y:0.02 +} + +var HomoSap = { + a: 0.3029549426680, + c: 0.1979883004921, + g: 0.1975473066391, + t: 0.3015094502008 +} + +function makeCumulative(table) { + var last = null; + /* BEGIN LOOP */ + for (var c in table) { + if (last) table[c] += table[last]; + last = c; + } + /* END LOOP */ +} + +function fastaRepeat(n, seq) { + var seqi = 0, lenOut = 60; + /* BEGIN LOOP */ + while (n>0) { + if (n0) { + if (n= 0x7f) { + validates = false; + break; + } + } + /* END LOOP */ + + if (!validates) + continue; + + var url = "http://example.com/tag/" + tag.replace(" ", "").toLowerCase(); + var popularity = tagInfo[i].popularity; + var color = 'rgb(' + Math.floor(255 * (popularity - 12) / 20) + ', 0, 255)'; + output += ' ' + tag + ' \n'; + } + /* END LOOP */ + + output += ''; + output.replace(" ", " "); + + return output; +} + +var tagcloud = makeTagCloud(tagInfo); +tagInfo = null; diff --git a/js/src/metrics/jint/sunspider/string-unpack-code.js b/js/src/metrics/jint/sunspider/string-unpack-code.js new file mode 100644 index 0000000..0c01d44 --- /dev/null +++ b/js/src/metrics/jint/sunspider/string-unpack-code.js @@ -0,0 +1,152 @@ +// This test case unpacks the compressed code for the MochiKit, +// jQuery, Dojo and Prototype JavaScript libraries. +/*** + MochiKit.MochiKit 1.3.1 : PACKED VERSION + THIS FILE IS AUTOMATICALLY GENERATED. If creating patches, please + diff against the source tree, not this file. + + See for documentation, downloads, license, etc. + + (c) 2005 Bob Ippolito. All rights Reserved. + ***/ + +/* BEGIN LOOP */ +for (var i = 0; i < 2; i++) { + + var decompressedMochiKit = function (p, a, c, k, e, d) { + e = function (c) { + return (c < a ? "" : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36)) + }; + if (!''.replace(/^/, String)) { + +/* BEGIN LOOP */ + while (c--) d[e(c)] = k[c] || e(c); + +/* END LOOP */ + k = [function (e) { + return d[e] + }]; + e = function () { + return '\\w+' + }; + c = 1 + }; +/* BEGIN LOOP */ + while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]); +/* END LOOP */ + return p + }('if(H(1q)!="L"){1q.2X("B.J")}if(H(B)=="L"){B={}}if(H(B.J)=="L"){B.J={}}B.J.1Y="1.3.1";B.J.1r="B.J";B.J.2l=G(7V,vR){if(7V===O){7V={}}R(u i=1;i=0;i--){aw.e9(o[i])}}N{X.1c(o)}}F X},1R:G(7U,1i,av){if(!av){av=0}if(1i){u l=1i.K;if(H(l)!="2y"){if(H(B.15)!="L"){1i=B.15.2G(1i);l=1i.K}N{14 Y 3p("au 2E an at-as 3W B.15 2E ar")}}if(!7U){7U=[]}R(u i=av;i>b},vG:G(a,b){F a>>>b},eq:G(a,b){F a==b},ne:G(a,b){F a!=b},gt:G(a,b){F a>b},ge:G(a,b){F a>=b},lt:G(a,b){F al){7T=l}}69=[];R(i=0;i<7T;i++){u fa=[];R(u j=1;j0){ap=m.2o(me.am,ap)}u 4o=me.f7;if(!4o){4o=D}F me.f5.1w(4o,ap)};7Q.f7=f6;7Q.f5=ao;7Q.am=5f;F 7Q},lF:G(7P){u mp=B.J.1O;R(u k in 7P){u f4=7P[k];if(H(f4)=="G"){7P[k]=mp(f4,7P)}}},5u:G(mo,mn,ml,mk){B.J.ae.5M(mo,mn,ml,mk)},mj:{"5L":1h,"1n":1h,"2y":1h},2f:G(a,b){if(a==b){F 0}u f3=(H(a)=="L"||a===O);u f2=(H(b)=="L"||b===O);if(f3&&f2){F 0}N{if(f3){F-1}N{if(f2){F 1}}}u m=B.J;u f1=m.mj;if(!(H(a)in f1&&H(b)in f1)){1f{F m.ae.3C(a,b)}1e(e){if(e!=m.4d){14 e}}}if(ab){F 1}}u f0=m.U;14 Y 3p(f0(a)+" 3W "+f0(b)+" 9v 2E be vv")},eM:G(a,b){F B.J.2f(a.9P(),b.9P())},eL:G(a,b){u mi=B.J.2f;u 7O=a.K;u al=0;if(7O>b.K){al=1;7O=b.K}N{if(7O0))){u kv=B.S.d5(3s);3s=kv[0];68=kv[1]}N{if(M.K==1){u o=3s;3s=[];68=[];R(u k in o){u v=o[k];if(H(v)!="G"){3s.1c(k);68.1c(v)}}}}u W=[];u lT=28.2a(3s.K,68.K);u eT=B.J.af;R(u i=0;i=2J){14 I.25}5c+=3a;F W}}},4c:G(aa,p,q){u m=B.J;u I=B.15;u lb=m.2r(I.1Q,m.1R(O,M,1));u 2r=m.2r;u 1a=I.1a;F{U:G(){F"4c(...)"},1l:m.24("U"),1a:G(){F aa.1w(D,2r(1a,lb))}}},ep:G(aa,1V,I){1V=B.15.1Q(1V);u m=B.J;F{U:G(){F"ep(...)"},1l:m.24("U"),1a:G(){F aa.1w(I,1V.1a())}}},55:G(p,q){u I=B.15;u m=B.J;if(M.K==1){F I.1Q(M[0])}u 64=m.2r(I.1Q,M);F{U:G(){F"55(...)"},1l:m.24("U"),1a:G(){1M(64.K>1){1f{F 64[0].1a()}1e(e){if(e!=I.25){14 e}64.2P()}}if(64.K==1){u a9=64.2P();D.1a=m.1O("1a",a9);F D.1a()}14 I.25}}},9Z:G(3b,1V){u I=B.15;1V=I.1Q(1V);F{U:G(){F"9Z(...)"},1l:B.J.24("U"),1a:G(){u W=1V.1a();if(!3b(W)){D.1a=G(){14 I.25};D.1a()}F W}}},eo:G(3b,1V){1V=B.15.1Q(1V);u m=B.J;u 1O=m.1O;F{"U":G(){F"eo(...)"},"1l":m.24("U"),"1a":G(){1M(1h){u W=1V.1a();if(!3b(W)){2K}}D.1a=1O("1a",1V);F W}}},a7:G(63,2u,la){2u.62[63]=-1;u m=B.J;u l9=m.eI;F{U:G(){F"en("+63+", ...)"},1l:m.24("U"),1a:G(){u W;u i=2u.62[63];if(i==2u.29){W=la.1a();2u.a8.1c(W);2u.29+=1;2u.62[63]+=1}N{W=2u.a8[i-2u.2a];2u.62[63]+=1;if(i==2u.2a&&l9(2u.62)!=2u.2a){2u.2a+=1;2u.a8.2P()}}F W}}},en:G(a6,n){u W=[];u 2u={"62":[],"a8":[],"29":-1,"2a":-1};if(M.K==1){n=2}u I=B.15;a6=I.1Q(a6);u a7=I.a7;R(u i=0;i0&&4k>=2J)||(3a<0&&4k<=2J)){14 B.15.25}u W=4k;4k+=3a;F W},U:G(){F"7I("+[4k,2J,3a].2b(", ")+")"},1l:B.J.24("U")}},l0:G(a5,l7){u x=l7||0;u I=B.15;a5=I.1Q(a5);1f{1M(1h){x+=a5.1a()}}1e(e){if(e!=I.25){14 e}}F x},em:G(a4){u I=B.15;a4=I.1Q(a4);1f{1M(1h){a4.1a()}}1e(e){if(e!=I.25){14 e}}},9a:G(7J,1A,I){u m=B.J;if(M.K>2){1A=m.1O(1A,I)}if(m.3A(7J)){1f{R(u i=0;i<7J.K;i++){1A(7J[i])}}1e(e){if(e!=B.15.25){14 e}}}N{I=B.15;I.em(I.4c(1A,7J))}},kZ:G(l6,1A){u I=B.15;1f{I.a0(1A,l6).1a();F 1m}1e(e){if(e!=I.25){14 e}F 1h}},kY:G(l5,4j){u W=B.15.2G(l5);if(M.K==1){4j=B.J.2f}W.iz(4j);F W},kX:G(l4){u W=B.15.2G(l4);W.vg();F W},kW:G(l3,1A){u I=B.15;1f{I.a1(1A,l3).1a();F 1h}1e(e){if(e!=I.25){14 e}F 1m}},kV:G(1g,5b){if(B.J.3A(5b)){R(u i=0;i<5b.K;i++){1g.1c(5b[i])}}N{u I=B.15;5b=I.1Q(5b);1f{1M(1h){1g.1c(5b.1a())}}1e(e){if(e!=I.25){14 e}}}F 1g},ek:G(a3,eH){u m=B.J;u I=B.15;if(M.K<2){eH=m.4i.eE}a3=I.1Q(a3);u pk=L;u k=L;u v;G eF(){v=a3.1a();k=eH(v)}G l2(){u 7j=v;v=L;F 7j}u eG=1h;F{U:G(){F"ek(...)"},1a:G(){1M(k==pk){eF();if(eG){eG=1m;2K}}pk=k;F[k,{1a:G(){if(v==L){eF()}if(k!=pk){14 I.25}F l2()}}]}}},kU:G(a2,eD){u m=B.J;u I=B.15;if(M.K<2){eD=m.4i.eE}a2=I.1Q(a2);u ey=[];u eA=1h;u ez;1M(1h){1f{u eB=a2.1a();u 2h=eD(eB)}1e(e){if(e==I.25){2K}14 e}if(eA||2h!=ez){u eC=[];ey.1c([2h,eC])}eC.1c(eB);eA=1m;ez=2h}F ey},9X:G(ex){u i=0;F{U:G(){F"9X(...)"},1l:B.J.24("U"),1a:G(){if(i>=ex.K){14 B.15.25}F ex[i++]}}},eh:G(ew){F(ew&&H(ew.ei)=="G")},9V:G(l1){F{U:G(){F"9V(...)"},1l:B.J.24("U"),1a:G(){u W=l1.ei();if(W===O||W===L){14 B.15.25}F W}}}});B.15.1W=["9Y","9X","eh","9V",];B.15.1z=["25","9W","1Q","eu","et","7b","1a","es","a1","a0","er","4c","ep","55","9Z","eo","en","2G","7H","7I","l0","em","9a","kZ","kY","kX","kW","kV","ek","kU"];B.15.2d=G(){u m=B.J;D.25=Y m.5a("25");D.9Y=Y m.4a();D.9W("ej",m.3A,D.9X);D.9W("ei",D.eh,D.9V);D.2k={":3e":D.1z,":1p":m.2o(D.1z,D.1W)};m.3f(D)};B.15.2d();if(!B.3d){7H=B.15.7H}B.J.2Y(D,B.15);if(H(1q)!="L"){1q.2X("B.1H");1q.2M("B.J")}if(H(1x)!="L"){1x.26("B.J",[])}1f{if(H(B.J)=="L"){14""}}1e(e){14"B.1H 3F on B.J!"}if(H(B.1H)=="L"){B.1H={}}B.1H.1r="B.1H";B.1H.1Y="1.3.1";B.1H.1K=G(){F"["+D.1r+" "+D.1Y+"]"};B.1H.1l=G(){F D.1K()};B.1H.1z=["5C","49","7A","kR","2L","5Z","kG","ch","kE","kC"];B.1H.1W=["ef","e8","e7"];B.1H.49=G(1P,kT,3z){D.1P=1P;D.3N=kT;D.3z=3z;D.vf=Y 3Q()};B.1H.49.1U={U:G(){u m=B.J;F"49("+m.2r(m.U,[D.1P,D.3N,D.3z]).2b(", ")+")"},1l:B.J.24("U")};B.J.2l(B.1H,{ef:G(7F){u I=B.1H;if(H(7F)=="1n"){7F=I.5C[7F]}F G(1t){u 7G=1t.3N;if(H(7G)=="1n"){7G=I.5C[7G]}F 7G>=7F}},e8:G(){u kS=B.1H.49;R(u i=0;i=0&&D.4h.K>D.ec){D.4h.2P()}},c8:G(9U){u ea=0;if(!(H(9U)=="L"||9U===O)){ea=28.29(0,D.4h.K-9U)}F D.4h.9T(ea)},kJ:G(7B){if(H(7B)=="L"||7B===O){7B=30}u 9S=D.c8(7B);if(9S.K){u 1g=2r(G(m){F"\\n ["+m.1P+"] "+m.3N+": "+m.3z.2b(" ")},9S);1g.e9("va "+9S.K+" v9:");F 1g.2b("")}F""},v8:G(kI){if(H(B.1I)=="L"){cq(D.kJ())}N{B.1I.bY(kI||1m)}}};B.1H.2d=G(){D.5C={8M:40,8L:50,8K:30,8J:20,8I:10};u m=B.J;m.5u("49",D.e8,D.e7);u 61=m.2z;u e6=D.7A;u 60=e6.1U.kH;m.2l(D.7A.1U,{kF:61(60,"8I"),5Z:61(60,"8J"),dE:61(60,"8M"),kD:61(60,"8L"),kB:61(60,"8K")});u I=D;u 5Y=G(1b){F G(){I.2L[1b].1w(I.2L,M)}};D.5Z=5Y("5Z");D.kG=5Y("dE");D.ch=5Y("kF");D.kE=5Y("kD");D.kC=5Y("kB");D.2L=Y e6();D.2L.e5=1h;D.2k={":3e":D.1z,":1p":m.2o(D.1z,D.1W)};m.3f(D)};if(H(5X)=="L"&&H(2v)!="L"&&2v.kA&&H(kz)!="L"){5X=G(){5X.3G=M;u ev=2v.kA("v7");ev.v6("5X",1m,1h);kz(ev)}}B.1H.2d();B.J.2Y(D,B.1H);if(H(1q)!="L"){1q.2X("B.1D")}if(H(B)=="L"){B={}}if(H(B.1D)=="L"){B.1D={}}B.1D.1r="B.1D";B.1D.1Y="1.3.1";B.1D.1K=G(){F"["+D.1r+" "+D.1Y+"]"};B.1D.1l=G(){F D.1K()};B.1D.ks=G(1y){1y=1y+"";if(H(1y)!="1n"||1y.K===0){F O}u 7z=1y.2R("-");if(7z.K===0){F O}F Y 3Q(7z[0],7z[1]-1,7z[2])};B.1D.ky=/(\\d{4,})(?:-(\\d{1,2})(?:-(\\d{1,2})(?:[T ](\\d{1,2}):(\\d{1,2})(?::(\\d{1,2})(?:\\.(\\d+))?)?(?:(Z)|([+-])(\\d{1,2})(?::(\\d{1,2}))?)?)?)?)?/;B.1D.kr=G(1y){1y=1y+"";if(H(1y)!="1n"||1y.K===0){F O}u X=1y.3C(B.1D.ky);if(H(X)=="L"||X===O){F O}u 5W,7y,7x,9R,2a,9Q,7w;5W=3w(X[1],10);if(H(X[2])=="L"||X[2]===""){F Y 3Q(5W)}7y=3w(X[2],10)-1;7x=3w(X[3],10);if(H(X[4])=="L"||X[4]===""){F Y 3Q(5W,7y,7x)}9R=3w(X[4],10);2a=3w(X[5],10);9Q=(H(X[6])!="L"&&X[6]!=="")?3w(X[6],10):0;if(H(X[7])!="L"&&X[7]!==""){7w=28.ha(c5*4M("0."+X[7]))}N{7w=0}if((H(X[8])=="L"||X[8]==="")&&(H(X[9])=="L"||X[9]==="")){F Y 3Q(5W,7y,7x,9R,2a,9Q,7w)}u 58;if(H(X[9])!="L"&&X[9]!==""){58=3w(X[10],10)*v5;if(H(X[11])!="L"&&X[11]!==""){58+=3w(X[11],10)*kw}if(X[9]=="-"){58=-58}}N{58=0}F Y 3Q(3Q.v4(5W,7y,7x,9R,2a,9Q,7w)-58)};B.1D.dY=G(2g,kx){if(H(2g)=="L"||2g===O){F O}u hh=2g.v3();u mm=2g.v2();u ss=2g.v1();u 1g=[((kx&&(hh<10))?"0"+hh:hh),((mm<10)?"0"+mm:mm),((ss<10)?"0"+ss:ss)];F 1g.2b(":")};B.1D.kq=G(2g,7v){if(H(2g)=="L"||2g===O){F O}u ku=7v?"T":" ";u kt=7v?"Z":"";if(7v){2g=Y 3Q(2g.9P()+(2g.v0()*kw))}F B.1D.dX(2g)+ku+B.1D.dY(2g,7v)+kt};B.1D.dX=G(2g){if(H(2g)=="L"||2g===O){F O}u e4=B.1D.e3;F[2g.dZ(),e4(2g.e1()+1),e4(2g.e0())].2b("-")};B.1D.kp=G(d){d=d+"";if(H(d)!="1n"||d.K===0){F O}u a=d.2R("/");F Y 3Q(a[2],a[0]-1,a[1])};B.1D.e3=G(n){F(n>9)?n:"0"+n};B.1D.ko=G(d){if(H(d)=="L"||d===O){F O}u e2=B.1D.e3;F[e2(d.e1()+1),e2(d.e0()),d.dZ()].2b("/")};B.1D.kn=G(d){if(H(d)=="L"||d===O){F O}F[d.e1()+1,d.e0(),d.dZ()].2b("/")};B.1D.1z=["ks","kr","dY","kq","dX","kp","ko","kn"];B.1D.1W=[];B.1D.2k={":3e":B.1D.1z,":1p":B.1D.1z};B.1D.2d=G(){u 2w=D.1r+".";R(u k in D){u o=D[k];if(H(o)=="G"&&H(o.1r)=="L"){1f{o.1r=2w+k}1e(e){}}}};B.1D.2d();if(H(B.J)!="L"){B.J.2Y(D,B.1D)}N{(G(km,dW){if((H(1x)=="L"&&H(1q)=="L")||(H(B.3d)=="5L"&&B.3d)){u 1p=dW.2k[":1p"];R(u i=0;i<1p.K;i++){km[1p[i]]=dW[1p[i]]}}})(D,B.1D)}if(H(1q)!="L"){1q.2X("B.1s")}if(H(B)=="L"){B={}}if(H(B.1s)=="L"){B.1s={}}B.1s.1r="B.1s";B.1s.1Y="1.3.1";B.1s.1K=G(){F"["+D.1r+" "+D.1Y+"]"};B.1s.1l=G(){F D.1K()};B.1s.ke=G(kl,kk,kj,ki,kh,dV,kg,9N,kf){F G(1P){1P=4M(1P);if(H(1P)=="L"||1P===O||k8(1P)){F kl}u 9L=kk;u 9K=kj;if(1P<0){1P=-1P}N{9L=9L.23(/-/,"")}u me=M.2U;u 9M=B.1s.dJ(ki);if(kh){1P=1P*3k;9K=9M.9y+9K}1P=B.1s.dK(1P,dV);u 9O=1P.2R(/\\./);u 3r=9O[0];u 3P=(9O.K==1)?"":9O[1];u X="";1M(3r.K9N){u i=3r.K-9N;X=9M.9A+3r.2W(i,3r.K)+X;3r=3r.2W(0,i)}}X=3r+X;if(dV>0){1M(3P.K=0)){D.9u()}},jR:G(X){D.9x(X);D.jX()},9x:G(X){D.2H=((X 2C 2x)?1:0);D.53[D.2H]=X;D.9u()},dD:G(){if(D.2H!=-1){if(!D.7l){14 Y B.1k.dj(D)}D.7l=1m;F}},3o:G(X){D.dD();if(X 2C B.1k.2t){14 Y 2x("2t jW 9v aB be 7r if jV jU jT jS of a 3o")}D.9x(X)},52:G(X){D.dD();u I=B.1k;if(X 2C I.2t){14 Y 2x("2t jW 9v aB be 7r if jV jU jT jS of a 3o")}if(!(X 2C 2x)){X=Y I.9p(X)}D.9x(X)},jP:G(fn){if(M.K>1){fn=B.J.2z.1w(O,M)}F D.9w(fn,fn)},5Q:G(fn){if(M.K>1){fn=B.J.2z.1w(O,M)}F D.9w(fn,O)},jA:G(fn){if(M.K>1){fn=B.J.2z.1w(O,M)}F D.9w(O,fn)},9w:G(cb,eb){if(D.7r){14 Y 2x("uQ uP 9v 2E be re-uO")}D.55.1c([cb,eb]);if(D.2H>=0){D.9u()}F D},9u:G(){u dC=D.55;u 56=D.2H;u X=D.53[56];u I=D;u cb=O;1M(dC.K>0&&D.54===0){u 2n=dC.2P();u f=2n[56];if(f===O){2V}1f{X=f(X);56=((X 2C 2x)?1:0);if(X 2C B.1k.2t){cb=G(X){I.jR(X)};D.jQ()}}1e(3O){56=1;if(!(3O 2C 2x)){3O=Y B.1k.9p(3O)}X=3O}}D.2H=56;D.53[56]=X;if(cb&&D.54){X.jP(cb);X.7r=1h}}};B.J.2l(B.1k,{dk:G(){F dB("("+M[0].jN+")")},dp:G(uN){u d=Y B.1k.2t();d.3o.1w(d,M);F d},9q:G(uM){u d=Y B.1k.2t();d.52.1w(d,M);F d},do:G(){u I=M.2U;if(!I.7q){u dy=[G(){F Y 7q()},G(){F Y dA("jO.dz")},G(){F Y dA("uL.dz")},G(){F Y dA("jO.dz.4.0")},G(){14 Y B.1k.dh("uK uJ 2E uI 7q")}];R(u i=0;i1){u m=B.J;u qs=m.dw.1w(O,m.1R(O,M,1));if(qs){5F+="?"+qs}}2s.cp("uB",5F,1h);F I.dl(2s)},jv:G(5F){u I=B.1k;u d=I.dn.1w(I,M);d=d.5Q(I.dk);F d},dm:G(jJ,dv){u d=Y B.1k.2t();u m=B.J;if(H(dv)!="L"){d.5Q(G(){F dv})}u jI=uA(m.1O("3o",d),28.8B(jJ*c5));d.7m=G(){1f{uz(jI)}1e(e){}};F d},ju:G(jH,1A){u m=B.J;u jG=m.2z.1w(m,m.1R(O,M,1));F B.1k.dm(jH).5Q(G(X){F jG()})}});B.1k.5O=G(){D.5S=[];D.4e=1m;D.id=D.7n()};B.1k.5O.1U={bX:B.1k.5O,uy:G(){d=Y B.1k.2t();if(D.4e){D.5S.1c(d)}N{D.4e=1h;d.3o(D)}F d},jF:G(){if(!D.4e){14 3p("ux to jF an jE 5O")}D.4e=1m;if(D.5S.K>0){D.4e=1h;D.5S.2P().3o(D)}},7n:B.J.4f(),U:G(){u 9t;if(D.4e){9t="4e, "+D.5S.K+" 5S"}N{9t="jE"}F"5O("+D.id+", "+9t+")"},1l:B.J.24("U")};B.1k.7i=G(2G,du,jC,jB,jD){D.2G=2G;D.9r=Y 7o(D.2G.K);D.55=[];D.id=D.7n();D.2H=-1;D.54=0;D.53=[O,O];D.7m=jD;D.7l=1m;if(D.2G.K===0&&!du){D.3o(D.9r)}D.dr=0;D.jz=du;D.jy=jC;D.jx=jB;u 9s=0;B.J.2r(B.J.1O(G(d){d.5Q(B.J.1O(D.dt,D),9s,1h);d.jA(B.J.1O(D.dt,D),9s,1m);9s+=1},D),D.2G)};B.J.2l(B.1k.7i.1U,B.1k.2t.1U);B.J.2l(B.1k.7i.1U,{dt:G(ds,7k,5R){D.9r[ds]=[7k,5R];D.dr+=1;if(D.2H!==0){if(7k&&D.jz){D.3o([ds,5R])}N{if(!7k&&D.jy){D.52(5R)}N{if(D.dr==D.2G.K){D.3o(D.9r)}}}}if(!7k&&D.jx){5R=O}F 5R}});B.1k.jt=G(jw){u d=Y B.1k.7i(jw,1m,1h,1m);d.5Q(G(dq){u 7j=[];R(u i=0;i=0){u 9m=Q.1S[Q.j4];7d.1c(1b);7c.1c((9m.3m)?9m.3m:9m.7X);F O}7d.1c(1b);7c.1c("");F O}if(4Y=="cu"||4Y=="P"||4Y=="8d"||4Y=="6m"){F Q.5h}7d.1c(1b);7c.1c(Q.3m||"");F O}F Q.5h});F[7d,7c]},94:G(1N,1A){u I=B.S;u d3=I.1Z;u W;1f{I.1Z=1N;W=1A()}1e(e){I.1Z=d3;14 e}I.1Z=d3;F W},j3:G(1b,j2,3y,j1){B.S.9b.5M(1b,j2,3y,j1)},9k:G(1j,7a){u im=B.15;u I=B.S;u 1Q=im.1Q;u iY=im.7b;u 4c=im.4c;u iX=I.9b;u iZ=I.9k;u iW=B.J.4d;1M(1h){if(H(1j)=="L"||1j===O){F O}if(H(1j.3T)!="L"&&1j.3T>0){F 1j}if(H(1j)=="2y"||H(1j)=="5L"){1j=1j.1l()}if(H(1j)=="1n"){F I.1Z.4S(1j)}if(H(1j.j0)=="G"){1j=1j.j0(7a);2V}if(H(1j)=="G"){1j=1j(7a);2V}u 9l=O;1f{9l=1Q(1j)}1e(e){}if(9l){F 4c(iZ,9l,iY(7a))}1f{1j=iX.3C(1j,7a);2V}1e(e){if(e!=iW){14 e}}F I.1Z.4S(1j.1l())}F L},iV:G(1j,79,iU){u o={};o[79]=iU;1f{F B.S.4X(1j,o)}1e(e){}F O},iT:G(1j,79){u I=B.S;u d2=I.4U.99[79];1j=I.1E(1j);1f{if(d2){F 1j[d2]}F 1j.fm(79)}1e(e){}F O},4X:G(1j,5K){u Q=1j;u I=B.S;if(H(1j)=="1n"){Q=I.1E(1j)}if(5K){u d0=B.J.8Z;if(I.4U.6X){R(u k in 5K){u v=5K[k];if(H(v)=="3n"&&H(Q[k])=="3n"){d0(Q[k],v)}N{if(k.2W(0,2)=="on"){if(H(v)=="1n"){v=Y cZ(v)}Q[k]=v}N{Q.4p(k,v)}}}}N{u iS=I.4U.99;R(k in 5K){v=5K[k];u d1=iS[k];if(k=="1T"&&H(v)=="1n"){Q.1T.3x=v}N{if(H(d1)=="1n"){Q[d1]=v}N{if(H(Q[k])=="3n"&&H(v)=="3n"){d0(Q[k],v)}N{if(k.2W(0,2)=="on"){if(H(v)=="1n"){v=Y cZ(v)}Q[k]=v}N{Q.4p(k,v)}}}}}}}F Q},9j:G(1j){u Q=1j;u I=B.S;if(H(1j)=="1n"){Q=I.1E(1j)}u 78=[I.9k(B.J.1R(O,M,1),Q)];u iR=B.J.2o;1M(78.K){u n=78.2P();if(H(n)=="L"||n===O){}N{if(H(n.3T)=="2y"){Q.2c(n)}N{78=iR(n,78)}}}F Q},iQ:G(1j){u Q=1j;u I=B.S;if(H(1j)=="1n"){Q=I.1E(1j);M[0]=Q}u cY;1M((cY=Q.6n)){Q.6S(cY)}if(M.K<2){F Q}N{F I.9j.1w(D,M)}},cX:G(1b,4b){u Q;u I=B.S;u m=B.J;if(H(4b)=="1n"||H(4b)=="2y"){u 3G=m.1R([1b,O],M,1);F M.2U.1w(D,3G)}if(H(1b)=="1n"){if(4b&&"1b"in 4b&&!I.4U.6X){1b=("<"+1b+" 1b=\\""+I.9c(4b.1b)+"\\">")}Q=I.1Z.2S(1b)}N{Q=1b}if(4b){I.4X(Q,4b)}if(M.K<=2){F Q}N{u 3G=m.1R([Q],M,2);F I.9j.1w(D,3G)}},cw:G(){u m=B.J;F m.2z.1w(D,m.1R([B.S.cX],M))},cs:G(5J,1d){u I=B.S;5J=I.1E(5J);u cW=5J.3t;if(1d){1d=I.1E(1d);cW.uj(1d,5J)}N{cW.6S(5J)}F 1d},1E:G(id){u I=B.S;if(M.K==1){F((H(id)=="1n")?I.1Z.hN(id):id)}N{F B.J.2r(I.1E,M)}},4q:G(iP,cV,cU){if(M.K==2){cU=cV}u I=B.S;u el=I.1E(iP);u 77=I.1Z;if(!el||el==77){F L}if(el.iO){F el.iO[cV]}if(H(77.5k)=="L"){F L}if(77.5k===O){F L}u 9i=77.5k.g4(el,O);if(H(9i)=="L"||9i===O){F L}F 9i.6q(cU)},aH:G(76,9g,4W){u I=B.S;if(H(76)=="L"||76===O){76="*"}if(H(4W)=="L"||4W===O){4W=I.1Z}4W=I.1E(4W);u 9h=(4W.fr(76)||I.1Z.1p);if(H(9g)=="L"||9g===O){F B.J.1R(O,9h)}u cR=[];R(u i=0;i<9h.K;i++){u cS=9h[i];u cT=cS.3M.2R(" ");R(u j=0;j/g,">")},iB:G(2q){F B.S.cG(2q).2b("")},cG:G(2q,1g){if(H(1g)=="L"||1g===O){1g=[]}u 70=[2q];u I=B.S;u cB=I.9c;u iA=I.4U;1M(70.K){2q=70.hP();if(H(2q)=="1n"){1g.1c(2q)}N{if(2q.3T==1){1g.1c("<"+2q.cD.8G());u 71=[];u cF=iA(2q);R(u i=0;i");70.1c("");u cC=2q.5h;R(i=cC.K-1;i>=0;i--){70.1c(cC[i])}}N{1g.1c("/>")}}N{if(2q.3T==3){1g.1c(cB(2q.iv))}}}}F 1g},97:G(ix,cA){u m=B.J;u iy=m.1R(O,M,1);B.15.9a(m.47(O,m.2r(B.S.1E,iy)),G(cA){cA.1T.3u=ix})},iw:G(1j,iu){u W=[];(G(1j){u cn=1j.5h;if(cn){R(u i=0;i0){u it=m.47;2T=G(1j){F it(2T.ir,1j.6Y)};2T.cx={};B.15.9a(6Z.6Y,G(a){2T.cx[a.1b]=a.3m});2T.ir=G(a){F(2T.cx[a.1b]!=a.3m)};2T.6X=1m;2T.99={"iq":"3M","ip":"ud","uc":"ub","R":"u9"}}N{2T=G(1j){F 1j.6Y};2T.6X=1h;2T.99={}}D.4U=2T;u 1C=D.cw;D.io=1C("ul");D.il=1C("ol");D.ik=1C("li");D.ij=1C("td");D.cm=1C("tr");D.ii=1C("u8");D.ih=1C("u7");D.ig=1C("u6");D.ie=1C("u5");D.ic=1C("th");D.cv=1C("ck");D.8d=1C("cj");D.A=1C("a");D.6m=1C("4u");D.ib=1C("u4");D.ia=1C("2e");D.i9=1C("tt");D.i8=1C("4O");D.i7=1C("h1");D.i6=1C("h2");D.i5=1C("h3");D.i4=1C("br");D.i3=1C("hr");D.i2=1C("u3");D.i1=1C("u2");D.cu=1C("u1");D.P=1C("p");D.ct=1C("u0");D.i0=1C("hJ");D.hZ=1C("tZ");D.hY=1C("tY");D.hX=1C("tX");D.hW=1C("tW");D.hV=1C("tV");D.hU=m.2z(D.97,"98");D.hT=m.2z(D.97,"8c");D.hS=D.cs;D.$=D.1E;D.2k={":3e":D.1z,":1p":m.2o(D.1z,D.1W)};m.3f(D)}});B.S.2d(((H(2O)=="L")?D:2O));if(!B.3d){95=B.S.95;94=B.S.94}B.J.2Y(D,B.S);if(H(1q)!="L"){1q.2X("B.1I");1q.2M("B.1H");1q.2M("B.J")}if(H(1x)!="L"){1x.26("B.1H",[]);1x.26("B.J",[])}1f{if(H(B.J)=="L"||H(B.1H)=="L"){14""}}1e(e){14"B.1I 3F on B.J 3W B.1H!"}if(H(B.1I)=="L"){B.1I={}}B.1I.1r="B.1I";B.1I.1Y="1.3.1";B.1I.1K=G(){F"["+D.1r+" "+D.1Y+"]"};B.1I.1l=G(){F D.1K()};B.1I.bY=G(6W){u m=B.1I;6W=!(!6W);if(m.3l&&m.3l.8Q!=6W){m.3l.hA();m.3l=O}if(!m.3l||m.3l.8P){m.3l=Y m.1I(6W,B.1H.2L)}F m.3l};B.1I.1I=G(4R,6V){if(H(6V)=="L"||6V===O){6V=B.1H.2L}D.2L=6V;u tU=B.J.2l;u c3=B.J.8Z;u 1O=B.J.1O;u hM=B.J.4L;u 2m=2O;u 6U="tT";if(H(B.S)!="L"){2m=B.S.cr()}if(!4R){u 5F=2m.tS.tR.2R("?")[0].23(/[:\\/.><&]/g,"hR");u 1b=6U+"hR"+5F;u 5D=2m.cp("",1b,"tQ,tP,3V=hQ");if(!5D){cq("tO tN to cp tM 2O tL to hP-up tK.");F L}5D.2v.fl(""+"<5E><8Y>[B.1I]"+"<5s>");5D.2v.hG();5D.2v.8Y+=" "+2m.2v.8Y;2m=5D}u 1N=2m.2v;D.1N=1N;u 21=1N.hN(6U);u c4=!!21;if(21&&H(21.5B)!="L"){21.5B.2L=D.2L;21.5B.6K();F 21.5B}if(c4){u cl;1M((cl=21.6n)){21.6S(cl)}}N{21=1N.2S("4u");21.id=6U}21.5B=D;u 8T=1N.2S("ck");u 8S=1N.2S("ck");u 6O=1N.2S("2e");u 6N=1N.2S("2e");u 6M=1N.2S("2e");u 6L=1N.2S("2e");u 3L=1N.2S("4u");u 42=1N.2S("4u");u 8U=6U+"tz";D.8N=hM(D.8N);u 4T=[];u 6R=O;u cf=G(1t){u 6T=1t.3N;if(H(6T)=="2y"){6T=B.1H.5C[6T]}F 6T};u cd=G(1t){F 1t.3z.2b(" ")};u ca=1O(G(1t){u 8W=cf(1t);u 7X=cd(1t);u c=D.8N[8W];u p=1N.2S("cj");p.3M="B-49 B-5C-"+8W;p.1T.3x="ty: 2N; 4F-8X: -hL-4O-3y; 4F-8X: -o-4O-3y; 4F-8X: 4O-3y; 4F-8X: 4O-tx; hK-3y: 2K-hK; 3y-hJ: tw; 3U: "+c;p.2c(1N.4S(8W+": "+7X));42.2c(p);42.2c(1N.2S("br"));if(3L.ci>3L.hI){3L.4C=0}N{3L.4C=3L.hI}},D);u hD=G(1t){4T[4T.K]=1t;ca(1t)};u hF=G(){u cg,ce;1f{cg=Y 8V(8T.3m);ce=Y 8V(8S.3m)}1e(e){ch("2x in 47 tv: "+e.43);F O}F G(1t){F(cg.hH(cf(1t))&&ce.hH(cd(1t)))}};u cc=G(){1M(42.6n){42.6S(42.6n)}};u hB=G(){4T=[];cc()};u bZ=1O(G(){if(D.8P){F}D.8P=1h;if(B.1I.3l==D){B.1I.3l=O}D.2L.c9(8U);21.5B=O;if(4R){21.3t.6S(21)}N{D.2m.hG()}},D);u c7=G(){cc();R(u i=0;i<4T.K;i++){u 1t=4T[i];if(6R===O||6R(1t)){ca(1t)}}};D.6K=G(){6R=hF();c7();D.2L.c9(8U);D.2L.hE(8U,6R,hD)};u c0=1O(G(){4T=D.2L.c8();c7()},D);u c2=1O(G(6Q){6Q=6Q||2O.6D;2h=6Q.6w||6Q.8t;if(2h==13){D.6K()}},D);u 31="3u: 8c; z-c6: c5; 2I: 2N; 6f: 2N; 6P: tu; 5A: 3k%; he-3U: 4F; c1: "+D.8O;if(4R){31+="; 3V: ts; 3E-3D: fO 8a 8y"}N{31+="; 3V: 3k%;"}21.1T.3x=31;if(!c4){1N.5s.2c(21)}31={"3x":"5A: 33%; 3u: 8Q; c1: "+D.8O};c3(8T,{"3m":"8L|8M|8K|8J|8I","hC":c2,"1T":31});21.2c(8T);c3(8S,{"3m":".*","hC":c2,"1T":31});21.2c(8S);31="5A: 8%; 3u:8Q; c1: "+D.8O;6O.2c(1N.4S("tq"));6O.8R=1O("6K",D);6O.1T.3x=31;21.2c(6O);6N.2c(1N.4S("tp"));6N.8R=c0;6N.1T.3x=31;21.2c(6N);6M.2c(1N.4S("tn"));6M.8R=hB;6M.1T.3x=31;21.2c(6M);6L.2c(1N.4S("tm"));6L.8R=bZ;6L.1T.3x=31;21.2c(6L);3L.1T.3x="fS: tk; 5A: 3k%";42.1T.3x="5A: 3k%; 3V: "+(4R?"tj":"3k%");3L.2c(42);21.2c(3L);D.6K();c0();if(4R){D.2m=L}N{D.2m=2m}D.8Q=4R;D.hA=bZ;D.8P=1m;F D};B.1I.1I.1U={"8O":"ti tg,tf-te","8N":{"8M":"1v","8L":"gU","8K":"1F","8J":"8y","8I":"bx"}};B.1I.1W=["1I"];B.1I.1z=["bY"];B.1I.2d=G(){D.2k={":3e":D.1z,":1p":B.J.2o(D.1z,D.1W)};B.J.3f(D);B.1I.3l=O};B.1I.2d();B.J.2Y(D,B.1I);if(H(1q)!="L"){1q.2X("B.V");1q.2M("B.J")}if(H(1x)!="L"){1x.26("B.J",[])}1f{if(H(B.J)=="L"){14""}}1e(e){14"B.V 3F on B.J"}if(H(B.V)=="L"){B.V={}}B.V.1r="B.V";B.V.1Y="1.3.1";B.V.1K=G(){F"["+D.1r+" "+D.1Y+"]"};B.V.1l=G(){F D.1K()};B.V.V=G(1v,hz,1F,6J){if(H(6J)=="L"||6J===O){6J=1}D.1B={r:1v,g:hz,b:1F,a:6J}};B.V.V.1U={bX:B.V.V,tc:G(hy){u 1B=D.1B;u m=B.V;F m.V.3Y(1B.r,1B.g,1B.b,hy)},tb:G(1o){u 1G=D.41();1G.h=1o;u m=B.V;F m.V.4H(1G)},ta:G(hx){u 1G=D.41();1G.s=hx;u m=B.V;F m.V.4H(1G)},t9:G(hw){u 1G=D.41();1G.l=hw;u m=B.V;F m.V.4H(1G)},t8:G(hv){u 1G=D.41();1G.l=28.29(1G.l-hv,0);u m=B.V;F m.V.4H(1G)},t7:G(hu){u 1G=D.41();1G.l=28.2a(1G.l+hu,1);u m=B.V;F m.V.4H(1G)},fJ:G(ht,5z){if(H(5z)=="L"||5z===O){5z=0.5}u sf=1-5z;u s=D.1B;u d=ht.1B;u df=5z;F B.V.V.3Y((s.r*sf)+(d.r*df),(s.g*sf)+(d.g*df),(s.b*sf)+(d.b*df),(s.a*sf)+(d.a*df))},h4:G(hs){u a=D.6r();u b=hs.6r();F B.J.2f([a.r,a.g,a.b,a.a],[b.r,b.g,b.b,b.a])},hq:G(){F D.41().b>0.5},t6:G(){F(!D.hq())},t5:G(){u c=D.41();u 2Z=B.V.6F;u W=D.ho;if(!W){u 5y=(2Z(c.h,bF).6I(0)+","+2Z(c.s,3k).hp(4)+"%"+","+2Z(c.l,3k).hp(4)+"%");u a=c.a;if(a>=1){a=1;W="1G("+5y+")"}N{if(a<=0){a=0}W="t4("+5y+","+a+")"}D.ho=W}F W},hl:G(){u c=D.1B;u 2Z=B.V.6F;u W=D.hn;if(!W){u 5y=(2Z(c.r,3h).6I(0)+","+2Z(c.g,3h).6I(0)+","+2Z(c.b,3h).6I(0));if(c.a!=1){W="t3("+5y+","+c.a+")"}N{W="1B("+5y+")"}D.hn=W}F W},6r:G(){F B.J.4L(D.1B)},t2:G(){u m=B.V;u c=D.1B;u 2Z=B.V.6F;u W=D.hm;if(!W){W=("#"+m.6E(2Z(c.r,3h))+m.6E(2Z(c.g,3h))+m.6E(2Z(c.b,3h)));D.hm=W}F W},t1:G(){u 2Q=D.2Q;u c=D.1B;if(H(2Q)=="L"||2Q===O){2Q=B.V.bA(D.1B);D.2Q=2Q}F B.J.4L(2Q)},41:G(){u 1G=D.1G;u c=D.1B;if(H(1G)=="L"||1G===O){1G=B.V.bC(D.1B);D.1G=1G}F B.J.4L(1G)},1l:G(){F D.hl()},U:G(){u c=D.1B;u hk=[c.r,c.g,c.b,c.a];F D.bX.1r+"("+hk.2b(", ")+")"}};B.J.2l(B.V.V,{3Y:G(1v,bW,1F,8H){u hj=B.V.V;if(M.K==1){u 1B=1v;1v=1B.r;bW=1B.g;1F=1B.b;if(H(1B.a)=="L"){8H=L}N{8H=1B.a}}F Y hj(1v,bW,1F,8H)},4H:G(1o,t0,sZ,sY){u m=B.V;F m.V.3Y(m.bB.1w(m,M))},sX:G(1o,sW,sV,sU){u m=B.V;F m.V.3Y(m.bz.1w(m,M))},hi:G(1b){u 8F=B.V.V;if(1b.3Z(0)=="\\""){1b=1b.3H(1,1b.K-2)}u bV=8F.by[1b.8G()];if(H(bV)=="1n"){F 8F.bT(bV)}N{if(1b=="aP"){F 8F.sT()}}F O},8f:G(4Q){u I=B.V.V;u bU=4Q.3H(0,3);if(bU=="1B"){F I.h9(4Q)}N{if(bU=="1G"){F I.h8(4Q)}N{if(4Q.3Z(0)=="#"){F I.bT(4Q)}}}F I.hi(4Q)},bT:G(4P){if(4P.3Z(0)=="#"){4P=4P.2W(1)}u 8E=[];u i,5x;if(4P.K==3){R(i=0;i<3;i++){5x=4P.3H(i,1);8E.1c(3w(5x+5x,16)/3h)}}N{R(i=0;i<6;i+=2){5x=4P.3H(i,2);8E.1c(3w(5x,16)/3h)}}u bS=B.V.V;F bS.3Y.1w(bS,8E)},bG:G(4O,hf,hg,4N){if(4N.2A(4O)===0){4N=4N.2W(4N.2A("(",3)+1,4N.K-1)}u bR=4N.2R(/\\s*,\\s*/);u bP=[];R(u i=0;i0){F 8D}}F O},ba:G(Q){u 2F=B.V.V;F 2F.bN(Q,"aZ","he-3U")||2F.sN()},sM:G(Q){u 2F=B.V.V;F 2F.bN(Q,"3U","3U")||2F.sL()},sK:G(){F B.J.4L(B.V.V.by)}});B.J.2l(B.V,{6F:G(v,8C){v*=8C;if(v<0){F 0}N{if(v>8C){F 8C}N{F v}}},hc:G(n1,n2,1o){if(1o>6){1o-=6}N{if(1o<0){1o+=6}}u 2i;if(1o<1){2i=n1+(n2-n1)*1o}N{if(1o<3){2i=n2}N{if(1o<4){2i=n1+(n2-n1)*(4-1o)}N{2i=n1}}}F 2i},bz:G(1o,5w,3i,bM){if(M.K==1){u 2Q=1o;1o=2Q.h;5w=2Q.s;3i=2Q.v;bM=2Q.a}u 1v;u 3K;u 1F;if(5w===0){1v=0;3K=0;1F=0}N{u i=28.8B(1o*6);u f=(1o*6)-i;u p=3i*(1-5w);u q=3i*(1-(5w*f));u t=3i*(1-(5w*(1-f)));hd(i){3j 1:1v=q;3K=3i;1F=p;2K;3j 2:1v=p;3K=3i;1F=t;2K;3j 3:1v=p;3K=q;1F=3i;2K;3j 4:1v=t;3K=p;1F=3i;2K;3j 5:1v=3i;3K=p;1F=q;2K;3j 6:3j 0:1v=3i;3K=t;1F=p;2K}}F{r:1v,g:3K,b:1F,a:bM}},bB:G(1o,5v,3v,bL){if(M.K==1){u 1G=1o;1o=1G.h;5v=1G.s;3v=1G.l;bL=1G.a}u 1v;u 8A;u 1F;if(5v===0){1v=3v;8A=3v;1F=3v}N{u m2;if(3v<=0.5){m2=3v*(1+5v)}N{m2=3v+5v-(3v*5v)}u m1=(2*3v)-m2;u f=B.V.hc;u h6=1o*6;1v=f(m1,m2,h6+2);8A=f(m1,m2,h6);1F=f(m1,m2,h6-2)}F{r:1v,g:8A,b:1F,a:bL}},bA:G(1v,4K,1F,bK){if(M.K==1){u 1B=1v;1v=1B.r;4K=1B.g;1F=1B.b;bK=1B.a}u 29=28.29(28.29(1v,4K),1F);u 2a=28.2a(28.2a(1v,4K),1F);u 1o;u 8z;u hb=29;if(2a==29){1o=0;8z=0}N{u 6H=(29-2a);8z=6H/29;if(1v==29){1o=(4K-1F)/6H}N{if(4K==29){1o=2+((1F-1v)/6H)}N{1o=4+((1v-4K)/6H)}}1o/=6;if(1o<0){1o+=1}if(1o>1){1o-=1}}F{h:1o,s:8z,v:hb,a:bK}},bC:G(1v,4J,1F,bI){if(M.K==1){u 1B=1v;1v=1B.r;4J=1B.g;1F=1B.b;bI=1B.a}u 29=28.29(1v,28.29(4J,1F));u 2a=28.2a(1v,28.2a(4J,1F));u 1o;u 6G;u bJ=(29+2a)/2;u 4I=29-2a;if(4I===0){1o=0;6G=0}N{if(bJ<=0.5){6G=4I/(29+2a)}N{6G=4I/(2-29-2a)}if(1v==29){1o=(4J-1F)/4I}N{if(4J==29){1o=2+((1F-1v)/4I)}N{1o=4+((1v-4J)/4I)}}1o/=6;if(1o<0){1o+=1}if(1o>1){1o-=1}}F{h:1o,s:6G,l:bJ,a:bI}},6E:G(1P){1P=28.ha(1P);u bH=1P.1l(16);if(1P<16){F"0"+bH}F bH},2d:G(){u m=B.J;D.V.h9=m.1O(D.V.bG,D.V,"1B","3Y",[1/3h,1/3h,1/3h,1]);D.V.h8=m.1O(D.V.bG,D.V,"1G","4H",[1/bF,0.bE,0.bE,1]);u 4G=1/3;u bD={8y:[0,0,0],1F:[0,0,1],gY:[0.6,0.4,0.2],gX:[0,1,1],sJ:[4G,4G,4G],gR:[0.5,0.5,0.5],bx:[0,1,0],sI:[2*4G,2*4G,2*4G],gN:[1,0,1],gL:[1,0.5,0],gK:[0.5,0,0.5],1v:[1,0,0],aP:[0,0,0,0],4F:[1,1,1],gI:[1,1,0]};u h7=G(1b,r,g,b,a){u W=D.3Y(r,g,b,a);D[1b]=G(){F W};F W};R(u k in bD){u 1b=k+"V";u h5=m.2o([h7,D.V,1b],bD[k]);D.V[1b]=m.1O.1w(O,h5)}u h0=G(){R(u i=0;i1){u 1d=B.S.1E(M[0]);u 2D=M[1];u 1i=M[2];u 1A=M[3];R(u i=5o.K-1;i>=0;i--){u o=5o[i];if(o[0]===1d&&o[1]===2D&&o[4]===1i&&o[5]===1A){I.6t(o);5o.4y(i,1);F 1h}}}N{u 5n=m.bi(5o,bh);if(5n>=0){I.6t(bh);5o.4y(5n,1);F 1h}}F 1m},8i:G(1d,2D){1d=B.S.1E(1d);u m=B.J;u 8l=m.bg(m.1R(O,M,1));u I=B.1u;u bd=I.6t;u 4z=I.4x;if(8l.K===0){R(u i=4z.K-1;i>=0;i--){u 4A=4z[i];if(4A[0]===1d){bd(4A);4z.4y(i,1)}}}N{u bf={};R(u i=0;i<8l.K;i++){bf[8l[i]]=1h}R(u i=4z.K-1;i>=0;i--){u 4A=4z[i];if(4A[0]===1d&&4A[1]in bf){bd(4A);4z.4y(i,1)}}}},8h:G(1d,2D){u bc=B.1u.4x;1d=B.S.1E(1d);u 3G=B.J.1R(O,M,2);u 5m=[];R(u i=0;i1){u e=Y 2x("mZ bb mY in mX \'2D\', mW bb mV");e.bb=5m;14 e}}}});B.1u.1W=[];B.1u.1z=["6s","8j","8h","8i"];B.1u.2d=G(2m){u m=B.J;D.1Z=2v;D.3X=2m;1f{D.6s(2O,"g8",D.g7)}1e(e){}D.2k={":3e":D.1z,":1p":m.2o(D.1z,D.1W)};m.3f(D)};B.1u.2d(D);if(!B.3d){6s=B.1u.6s;8j=B.1u.8j;8i=B.1u.8i;8h=B.1u.8h}B.J.2Y(D,B.1u);if(H(1q)!="L"){1q.2X("B.1X");1q.2M("B.J");1q.2M("B.S");1q.2M("B.V")}if(H(1x)!="L"){1x.26("B.J",[]);1x.26("B.S",[]);1x.26("B.V",[])}1f{if(H(B.J)=="L"||H(B.S)=="L"||H(B.V)=="L"){14""}}1e(e){14"B.1X 3F on B.J, B.S 3W B.V!"}if(H(B.1X)=="L"){B.1X={}}B.1X.1r="B.1X";B.1X.1Y="1.3.1";B.1X.1K=G(){F"["+D.1r+" "+D.1Y+"]"};B.1X.1l=G(){F D.1K()};B.1X.aI=G(e,g6){e=B.S.1E(e);D.fN(g6);if(D.1S.fL){e=D.g5(e)}u 4w=D.1S.3U;u C=B.V.V;if(D.1S.3U=="aW"){4w=C.ba(e)}N{if(!(4w 2C C)){4w=C.8f(4w)}}D.82=(4w.6r().a<=0);u 5l=D.1S.aV;if(D.1S.aV=="fM"){5l=C.ba(e.8g)}N{if(!(5l 2C C)){5l=C.8f(5l)}}D.g3(e,4w,5l)};B.1X.aI.1U={g5:G(e){u mU=e.3t;u 1N=B.S.b9();if(H(1N.5k)=="L"||1N.5k===O){F e}u 4v=1N.5k.g4(e,O);if(H(4v)=="L"||4v===O){F e}u b8=B.S.6m({"1T":{3u:"8c",mT:4v.6q("6p-3D"),85:4v.6q("6p-3g"),mS:4v.6q("6p-6f"),86:4v.6q("6p-2I"),6p:"2N"}});b8.6o=e.6o;e.6o="";e.2c(b8);F e},g3:G(e,b7,8e){if(D.1S.3E){D.g2(e,8e)}if(D.fy()){D.fX(e,b7,8e)}if(D.fx()){D.fV(e,b7,8e)}},g2:G(el,g1){u b6="6l 8a "+D.aQ(g1);u g0="3E-2I: "+b6;u fZ="3E-3g: "+b6;u fY="1T=\'"+g0+";"+fZ+"\'";el.6o="<4u "+fY+">"+el.6o+""},fX:G(el,fW,b5){u b4=D.b1(b5);R(u i=0;i=0;i--){b2.2c(D.b0(fU,b3,i,"6f"))}el.1T.mP=0;el.2c(b2)},b1:G(fT){u 2q=B.S;F 2q.6m({1T:{aZ:fT.1l()}})},b0:G(aY,fQ,n,aX){u 6k=B.S.8d();u 2p=6k.1T;2p.aZ=aY.1l();2p.3u="8c";2p.3V="6l";2p.fS="fR";2p.mO="6l";u 8b=D.aQ(aY,fQ);if(D.1S.3E&&n===0){2p.mN="8a";2p.mM="6l";2p.84="2N";2p.83="2N";2p.mL="2N";2p.3V="2N";2p.fP=8b.1l()}N{if(8b){2p.fP=8b.1l();2p.mK="8a";2p.mJ="2N 6l"}}if(!D.1S.4r&&(n==(D.1S.89-1))){2p.3V="fO"}D.fI(6k,n,aX);D.fG(6k,n,aX);F 6k},fN:G(fK){D.1S={6g:"1p",3U:"aW",aV:"fM",5j:1h,3E:1m,4r:1m,fL:1m};B.J.2l(D.1S,fK);D.1S.89=(D.1S.4r?2:4)},aL:G(){u 88=D.1S.6g;if(D.6h(88,"1p","3D")){F""}u aU=(88.2A("tl")!=-1);u aT=(88.2A("tr")!=-1);if(aU&&aT){F""}if(aU){F"2I"}if(aT){F"3g"}F""},aK:G(){u 87=D.1S.6g;if(D.6h(87,"1p","6f")){F""}u aS=(87.2A("bl")!=-1);u aR=(87.2A("br")!=-1);if(aS&&aR){F""}if(aS){F"2I"}if(aR){F"3g"}F""},aQ:G(aN,aO){if(aN=="aP"){F aO}N{if(D.1S.3E){F D.1S.3E}N{if(D.1S.5j){F aO.fJ(aN)}}}F""},fI:G(el,n,fH){u 6j=D.fE(n)+"px";u aM=(fH=="3D"?D.aL():D.aK());u 4t=el.1T;if(aM=="2I"){4t.86=6j;4t.85="2N"}N{if(aM=="3g"){4t.85=6j;4t.86="2N"}N{4t.86=6j;4t.85=6j}}},fG:G(el,n,fF){u 6i=D.fz(n)+"px";u aJ=(fF=="3D"?D.aL():D.aK());u 4s=el.1T;if(aJ=="2I"){4s.84=6i;4s.83="2N"}N{if(aJ=="3g"){4s.83=6i;4s.84="2N"}N{4s.84=6i;4s.83=6i}}},fE:G(n){if(D.82){F 0}u o=D.1S;if(o.4r&&o.5j){u fD=[1,0];F fD[n]}N{if(o.4r){u fC=[2,1];F fC[n]}N{if(o.5j){u fB=[3,2,1,0];F fB[n]}N{u fA=[5,3,2,1];F fA[n]}}}},fz:G(n){u o=D.1S;u 5i;if(o.4r&&(o.5j||D.82)){F 1}N{if(o.4r){5i=[1,0]}N{if(o.5j){5i=[2,1,1,1]}N{if(o.3E){5i=[0,2,0,0]}N{if(D.82){5i=[5,3,2,1]}N{F 0}}}}}F 5i[n]},6h:G(1y){R(u i=1;i")}}})()}', 62, 1976, '||||||||||||||||||||||||||||||var|||||||MochiKit||this||return|function|typeof|self|Base|length|undefined|arguments|else|null||elem|for|DOM||repr|Color|rval|res|new||||||throw|Iter|||||next|name|push|src|catch|try|lst|true|obj|node|Async|toString|false|string|hue|all|dojo|NAME|Format|msg|Signal|red|apply|JSAN|str|EXPORT|func|rgb|_425|DateTime|getElement|blue|hsl|Logging|LoggingPane|type|__repr__|_event|while|doc|bind|num|iter|extend|options|style|prototype|seq|EXPORT_OK|Visual|VERSION|_document||_434||replace|forwardCall|StopIteration|use||Math|max|min|join|appendChild|__new__|button|compare|date|key|val|_329|EXPORT_TAGS|update|win|pair|concat|_596|dom|map|req|Deferred|sync|document|base|Error|number|partial|indexOf||instanceof|sig|not|cls|list|fired|left|stop|break|logger|require|0px|window|shift|hsv|split|createElement|_423|callee|continue|substring|provide|_exportSymbols|ccc||_464|||||||||step|pred|_51|__compat__|common|nameFunctions|right|255|_517|case|100|_loggingPane|value|object|callback|TypeError|_251|_246|_113|parentNode|display|_522|parseInt|cssText|wrap|info|isArrayLike|end|match|top|border|depends|args|substr|mouse|code|_519|_443|className|level|err|frac|Date|_135|_85|nodeType|color|height|and|_window|fromRGB|charAt||asHSL|_444|message||||filter||LogMessage|AdapterRegistry|_366|imap|NotFound|locked|counter|_262|_messages|operator|cmp|_165|_161|pairs|arr|_52|setAttribute|computedStyle|compact|_614|_610|div|_576|_572|_observers|splice|_565|_566|_555|scrollTop|page|modifier|white|_541|fromHSL|_539|_535|_528|clone|parseFloat|_505|pre|_499|_497|_427|createTextNode|_446|attributeArray|_388|_379|updateNodeAttributes|_341|_326||box|errback|results|paused|chain|_285||ofs||NamedError|_175|_147|_122|_83|_54|_17|childNodes|_619|blend|defaultView|_574|_569|idx|_562|must|_554|_specialKeys|body|Coordinates|registerComparator|_521|_516|hex|mid|_478|width|loggingPane|LogLevel|nwin|head|url|setElementClass|callStack|path|dest|_359|boolean|register|Dimensions|DeferredLock|_313|addCallback|_310|waiting|onreadystatechange|_290|LOCALE|year|printfire|_214|log|_213|_211|pos|_155|_153||typeMatcher|listMinMax|_114|_40|itr|typ|_19|_634|_625|bottom|corners|_hasString|_612|_608|_595|1px|DIV|firstChild|innerHTML|padding|getPropertyValue|asRGB|connect|_disconnect|_559|middle|which|clientY|scrollLeft|clientX|client|charCode|relatedTarget|event|toColorPart|clampColorComponent|_537|_534|toFixed|_468|buildAndApplyFilter|_442|_441|_440|_439|position|_463|_447|removeChild|_449|uid|_428|_426|compliant|attributes|_422|_409|_412|_400|_395|_390|_389|_377|_375|_363|attr|ctx|repeat|_340|_339|isNotEmpty|_335|_333|opera|DeferredList|ret|_309|silentlyCancelled|canceller|_nextId|Array|_293|XMLHttpRequest|chained|_281|tail|_252|_225|msec|day|month|iso|Logger|_208|listeners|_200|_198|_194|_196|reduce|range|_169|_162|truth|registerRepr|_121|_70|_58|_56|_47|_45|_41|_13|_1|script|text|uri|documentElement|_630|_629|isTransparent|borderRightWidth|borderLeftWidth|marginRight|marginLeft|_602|_599|numSlices|solid|_597|block|SPAN|_579|fromString|offsetParent|signal|disconnectAll|disconnect|_570|_563|_557|preventDefault|stopPropagation|clientTop|clientLeft|pageY|pageX|keyCode|meta|ctrl|alt|target|black|_532|_524|floor|_513|_512|_500|_495|toLowerCase|_487|DEBUG|INFO|WARNING|FATAL|ERROR|colorTable|logFont|closed|inline|onclick|_438|_437|_445|RegExp|_452|space|title|updatetree|||||withDocument|withWindow||setDisplayForElement|none|renames|forEach|domConverters|escapeHTML|addElementClass|removeElementClass|once|_378|_380|_376|appendChildNodes|coerceToDOM|_355|opt|clientWidth|opacity|GenericError|fail|resultList|_307|_301|_fire|can|addCallbacks|_resback|percent|decimal|separator|twoDigitFloat|_274|_273|_264|_257|_250|_249|_254|_248|_243|_242|fmt|_240|_245|getTime|sec|hour|_209|slice|_206|iterateNextIter|registerIteratorFactory|arrayLikeIter|iteratorRegistry|takewhile|ifilterfalse|ifilter|_181|_176|_168|_166|_159|_tee|deque|arg|fun|jsonRegistry|reprString|reprRegistry|comparatorRegistry|urlEncode|_110|_108|cur|_95|_87|_71|im_preargs||_53|_57|_46|present|like|array|Argument|_15|_12|_632|_631|_633|SUBMODULES|only|_628|_627|_626|roundElement|_624|getElementsByTagAndClassName|_RoundCorners|_613|_whichSideBottom|_whichSideTop|_609|_605|_606|transparent|_borderColor|_604|_603|_601|_600|bgColor|fromElement|_594|_592|backgroundColor|_createCornerSlice|_createCorner|_590|_589|_587|_586|_581|_578|_577|currentDocument|fromBackground|errors|_568|_564||sigs|flattenArguments|_561|findIdentical|_560|_558||_556|attachEvent|addEventListener|funcOrStr|Event||_548|fromCharCode|String|_specialMacKeys|any|green|_namedColors|hsvToRGB|rgbToHSV|hslToRGB|rgbToHSL|_542|01|360|_fromColorString|_540|_536|_538|_529|_523|_518|fromComputedStyle|_511|_507|_508|_506|_501|fromHexString|_498|_496|_486|__class__|createLoggingPane|_459|_461|font|_462|_430|_435|1000|index|_460|getMessages|removeListener|_451||_457|_450|infore|_448|_456|logDebug|offsetHeight|span|input|_436|TR||HTML|open|alert|currentWindow|swapDOM|SELECT|FORM|INPUT|createDOMFunc|ignoreAttr|_421|call|_417|_410|_415|nodeName|_414|_413|emitHTML|good|_406|_399|_397|_393|_392|addLoadEvent|addToCallStack|_387|_386|_381|_382|_383|_373|_372|_369|createDOM|_365|Function|_360|_362|_358|_344|nodeWalk|formContents|_337|_338|_334|_332|offsetTop|offsetLeft|visibility|parentElement|||XMLHttpRequestError|BrowserComplianceError|CancelledError|AlreadyCalledError|evalJSONRequest|sendXMLHttpRequest|wait|doSimpleXMLHttpRequest|getXMLHttpRequest|succeed|_312|finishedCount|_308|_cbDeferred|_303|_297|queryString|_nothing|_289|XMLHTTP|ActiveXObject|eval|_284|_check|error|_279|default|rstrip|lstrip|formatLocale|roundToFixed|truncToFixed|_276|pow|_272|_271|_270|sign|_265|_263|tmp|_238|_232|toISODate|toISOTime|getFullYear|getDate|getMonth|_230|_padTwo|_228|useNativeConsole|_212|compareLogMessage|isLogMessage|unshift|_207||maxSize|_202|_199|logLevelAtLeast|console|hasIterateNext|iterateNext|arrayLike|groupby||exhaust|tee|dropwhile|applymap||islice|izip|cycle|count||_189|_188|_183|_185|_184|_186|_187|_182|identity|fetch|_180|_177|listMin|reprNumber|reprArrayLike|compareArrayLike|compareDateLike|isDateLike|findValue|_128|__export__|keyComparator|_124|_118|_93|_94|_90|_88|_84|_77|_68|_67|_66|_65|_60|im_func|_55|im_self|_48|_44|_42|_39|_36|_33|_27|_26|_25|_22|_24|_20|javascript|write|getAttribute||org|www|http|getElementsByTagName|roundClass|_623|_622|_621|_620|_isBottomRounded|_isTopRounded|_borderSize|_618|_617|_616|_615|_marginSize|_611|_setBorder|_607|_setMargin|blendedColor|_598|__unstable__wrapElement|fromParent|_setOptions|2px|borderColor|_593|hidden|overflow|_591|_588|_roundBottomCorners|_585|_roundTopCorners|_584|_583|_582|_580|_renderBorder|_roundCornersImpl|getComputedStyle|_doWrap|_571|_unloadCache|onunload|detachEvent|removeEventListener|_listener|objOrFunc|_552||_551|_549|onload|delete|112|KEY_F|KEY_|MINUS|KEY_SEMICOLON|KEY_DELETE|KEY_INSERT|KEY_ARROW_DOWN|KEY_ARROW_RIGHT|KEY_ARROW_UP||KEY_ARROW_LEFT|KEY_HOME|KEY_END|KEY_PAGE_DOWN|KEY_PAGE_UP|KEY_ENTER|KEY_NUM_PAD_CLEAR|63236|mousemove|contextmenu|click|mouseout|mouseover|_src|yellow|708090|purple|orange|ff00ff|magenta|778899|d3d3d3|808080|gray|696969|2f4f4f|darkred|a9a9a9|00ffff|cyan|brown|_547|_546||||compareRGB|_545||_543|fromHSLString|fromRGBString|round|_533|_hslValue|switch|background|_503|_504||fromName|_488|col|toRGBString|_hexString|_rgbString|_hslString|toPrecision|isLight||_481|_477|_476|_475|_474|_473|_469|_466|closePane|_458|onkeypress|_454|addListener|_455|close|test|scrollHeight|option|word|moz|_431|getElementById|html|pop|200|_|removeElement|showElement|hideElement|CANVAS|STRONG|FIELDSET|LEGEND|OPTGROUP|OPTION|TEXTAREA|LABEL|HR|BR|H3|H2|H1|PRE|TT|BUTTON|IMG|TH||TABLE||TFOOT|THEAD|TBODY|TD|LI|OL|||UL|checked|class|ignoreAttrFilter||_424|_419|nodeValue|scrapeText|_416|_418|sort|_411|toHTML|_404|hasElementClass|_403|_402|_401|swapElementClass|_398|_394|toggleElementClass|_391|focusOnLoad|_newCallStack|currentStyle|_371|replaceChildNodes|_364|_361|getNodeAttribute|_357|setNodeAttribute|_354|_352|_350|_353|toDOM|_346|_345|registerDOMConverter|selectedIndex|setElementPosition|setElementDimensions|tagName|absolute|getBoxObjectFor|getBoundingClientRect|elementPosition|_325|_324|_322|_323|offsetWidth|elementDimensions|clientHeight|innerWidth|getViewportDimensions|setOpacity|status|_317|deferred|_316|_newNamedError|maybeDeferred||gatherResults|callLater|loadJSONDoc|_311|consumeErrors|fireOnOneErrback|fireOnOneCallback|addErrback|_305|_304|_306|unlocked|release|_300|_299|_298|_296|_xhr_onreadystatechange|_xhr_canceller|304|responseText|Msxml2|addBoth|_pause|_continue|result|the|are|they|instances|_unpause|cancel|_280|_278|en_US|strip|percentFormat|twoDigitAverage|numberFormatter|_277|_275|isNaN|_259|_258|_260|_255|_253|_numberFormatter|_241|_239|_237|_236|_235|_234|_233|_231|toAmericanDate|toPaddedAmericanDate|americanDate|toISOTimestamp|isoTimestamp|isoDate|foot|sep||60000|_221|_isoRegexp|dispatchEvent|createEvent|warning|logWarning|fatal|logFatal|debug|logError|baseLog|_210|getMessageText|logToConsole|dispatchListeners|_204|_203|ident|_201|postError|alertListener|_197|_192|groupby_as_array|iextend|some|reversed|sorted|every|sum|_190|eat|_174|_173|_172|_171|_167|_163|_158|_157|_151|_144|_141||_139|_136|_134||_133|_132|zip|merge|isUndefined|isCallable|listMax|_131|_130|encodeURIComponent||_127|method|parseQueryString|evalJSON|registerJSON|serializeJSON|objMin|objMax|reverseKeyComparator|arrayEqual|objEqual|bindMethods|xfilter|xmap|isEmpty|isNull|isUndefinedOrNull|itemgetter|items|keys|setdefault|_126|_120|decodeURIComponent|_119|len|_109|_107|_104|_105|_101|_102|_98|||_100|_97|_96|_91|json|__json__|_82|_81|_80|_79|_76||_75|_74|_73|_69|_primitives|_64|_63||_62|_61|_59|_wrapDumbFunction|_49|_50|_31|_30|_21|_7|application|MochiKit_|createElementNS|namespaceURI|lastIndexOf|xul|there|gatekeeper|keymaster|mozilla|getElementsComputedStyle|_hasSingleTextChild|borderWidth|borderStyle|borderBottomWidth|borderTopWidth|borderTopStyle|fontSize|paddingBottom|insertBefore|paddingTop|marginBottom|marginTop|_575|property|see|handling|thrown|Multiple|element|||given|123|KEY_NUM_PAD_|105|KEY_APOSTROPHE|222|KEY_RIGHT_SQUARE_BRACKET|221|KEY_REVERSE_SOLIDUS|220|KEY_LEFT_SQUARE_BRACKET||219|KEY_GRAVE_ACCENT|192|KEY_SOLIDUS|191|KEY_FULL_STOP|190|KEY_HYPHEN|189||KEY_COMMA|188|KEY_EQUALS_SIGN|187|186|KEY_SCROLL_LOCK|145|KEY_NUM_LOCK|144|KEY_NUM_PAD_SOLIDUS|111|KEY_NUM_PAD_FULL_STOP|110|KEY_NUM_PAD_HYPHEN|109|KEY_NUM_PAD_PLUS_SIGN|107|KEY_NUM_PAD_ASTERISK|106|KEY_SELECT|KEY_WINDOWS_RIGHT|KEY_WINDOWS_LEFT|KEY_PRINT_SCREEN|KEY_SPACEBAR|KEY_ESCAPE|KEY_CAPS_LOCK|KEY_PAUSE|KEY_ALT|KEY_CTRL|KEY_SHIFT|KEY_TAB|KEY_BACKSPACE|63242|63272|63302|63233|63235|63232|63234|63273|63275|63277|63276|63289|returnValue|cancelBubble|keypress|KEY_UNKNOWN|keyup|keydown|shiftKey|metaKey||ctrlKey|altKey|toElement|srcElement|9acd32||yellowgreen||ffff00|f5f5f5|whitesmoke||ffffff|f5deb3|wheat|ee82ee|violet|40e0d0|turquoise|ff6347|tomato|d8bfd8|thistle|008080|teal|d2b48c|tan|4682b4|steelblue|00ff7f|springgreen|fffafa|snow|slategrey|slategray|6a5acd|slateblue|87ceeb|skyblue|c0c0c0|silver|a0522d|sienna|fff5ee|seashell|2e8b57|seagreen|f4a460|sandybrown|fa8072|salmon|8b4513|saddlebrown|4169e1|royalblue|bc8f8f|rosybrown|ff0000|800080|b0e0e6|powderblue|dda0dd|plum|ffc0cb|pink|cd853f||peru|ffdab9|peachpuff|ffefd5|papayawhip|db7093|palevioletred|afeeee|paleturquoise|98fb98|palegreen|eee8aa||palegoldenrod|da70d6|orchid|ff4500|orangered|ffa500|6b8e23|olivedrab|808000|olive|fdf5e6|oldlace|000080|navy|ffdead|navajowhite|ffe4b5|moccasin|ffe4e1|mistyrose|f5fffa|mintcream|191970|midnightblue|c71585|mediumvioletred|48d1cc|mediumturquoise|00fa9a|mediumspringgreen|7b68ee|mediumslateblue|3cb371|mediumseagreen|9370db|mediumpurple|ba55d3|mediumorchid|0000cd|mediumblue|66cdaa|mediumaquamarine|800000|maroon|faf0e6|linen|32cd32|limegreen|00ff00|lime|ffffe0|lightyellow|b0c4de|lightsteelblue|lightslategrey|lightslategray||87cefa|lightskyblue|20b2aa|lightseagreen|ffa07a|lightsalmon|ffb6c1|lightpink|lightgrey|90ee90|lightgreen|lightgray|fafad2|lightgoldenrodyellow|e0ffff|lightcyan|f08080|lightcoral|add8e6|lightblue|fffacd|lemonchiffon|7cfc00|lawngreen|fff0f5|lavenderblush|e6e6fa|lavender|f0e68c|khaki|fffff0|ivory|4b0082|indigo|cd5c5c|indianred|ff69b4|hotpink|f0fff0|honeydew|grey|adff2f|greenyellow|008000|daa520|goldenrod|ffd700||gold|f8f8ff|ghostwhite|dcdcdc|gainsboro|fuchsia|228b22|forestgreen|fffaf0|floralwhite|b22222|firebrick|1e90ff|dodgerblue|dimgrey|dimgray|00bfff|deepskyblue|ff1493|deeppink|9400d3|darkviolet|00ced1|darkturquoise|darkslategrey|darkslategray|483d8b|darkslateblue|8fbc8f|darkseagreen|e9967a|darksalmon|8b0000|9932cc|darkorchid|ff8c00|darkorange|556b2f|darkolivegreen|8b008b|darkmagenta|bdb76b|darkkhaki|darkgrey|006400|darkgreen|darkgray|b8860b|darkgoldenrod|008b8b|darkcyan|00008b|darkblue|dc143c|crimson|fff8dc|cornsilk|6495ed|cornflowerblue|ff7f50|coral|d2691e||chocolate|7fff00|chartreuse|5f9ea0|cadetblue|deb887|burlywood|a52a2a|8a2be2|blueviolet|0000ff|ffebcd||blanchedalmond|000000|ffe4c4|bisque|f5f5dc|beige|f0ffff|azure|7fffd4|aquamarine|aqua|faebd7|antiquewhite|f0f8ff|aliceblue|lightGray|darkGray|namedColors|blackColor|fromText|whiteColor|_510|_509|PI|rad|deg|transparentColor|_494|_493|_492|fromHSV|_491|_490|_489|asHSV|toHexString|rgba|hsla|toHSLString|isDark|lighterColorWithLevel|darkerColorWithLevel|colorWithLightness|colorWithSaturation|colorWithHue|colorWithAlpha||serif|sans|Verdana||8pt|8em|auto||Close|Clear||Load|Filter||10em||fixed|regex|emergency|line|margin|_Listener|dtd|loose|html4|w3|EN|Transitional|DTD|W3C|PUBLIC|DOCTYPE|blocking|due|debugging|able|Not|resizable|dependent|href|location|_MochiKit_LoggingPane|_429|canvas|strong|fieldset|legend|optgroup|select|form|textarea|label|img|table|tfoot|thead|tbody|htmlFor||useMap|usemap|defaultChecked|hasChildNodes|quot|amp|_405|focus|replaceChild|checkbox||radio|_win|BODY||safari|version|userAgent|navigator|innerHeight|alpha|khtml|Tried|acquire|clearTimeout|setTimeout|GET|ignore|send|abort|failed|Request|readyState|support|does|Browser|Microsoft|_288|_287|used|Deferreds|Chained|success|unfired|fr_FR|de_DE|00|abs|search|pattern|Invalid|getTimezoneOffset|getSeconds|getMinutes|getHours|UTC|3600000|initEvent|Events|debuggingBookmarklet|MESSAGES|LAST|_205|clear|ninfo|nlevel|timestamp|reverse|takes|initial|with|sequence|empty|iterable|numbers|dateLike|escape|find|forward|unregister|unescape|Object|compared|item|contains|logor|logand|cle|clt|cge|cgt|cne|ceq|zrshift|rshift|lshift|xor|mul|mod|sub|add|neg|lognot|_9|_2'.split('|'), 0, {}) + + +/* + * jQuery 1.2.1 - New Wave Javascript + * + * Copyright (c) 2007 John Resig (jquery.com) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * $Date: 2007-09-16 23:42:06 -0400 (Sun, 16 Sep 2007) $ + * $Rev: 3353 $ + */ + + var decompressedJQuery = function (p, a, c, k, e, r) { + e = function (c) { + return (c < a ? '' : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36)) + }; + if (!''.replace(/^/, String)) { + while (c--) r[e(c)] = k[c] || e(c); + k = [function (e) { + return r[e] + }]; + e = function () { + return '\\w+' + }; + c = 1 + }; + while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]); + return p + }('(G(){9(1m E!="W")H w=E;H E=18.15=G(a,b){I 6 7u E?6.5N(a,b):1u E(a,b)};9(1m $!="W")H D=$;18.$=E;H u=/^[^<]*(<(.|\\s)+>)[^>]*$|^#(\\w+)$/;E.1b=E.3A={5N:G(c,a){c=c||U;9(1m c=="1M"){H m=u.2S(c);9(m&&(m[1]||!a)){9(m[1])c=E.4D([m[1]],a);J{H b=U.3S(m[3]);9(b)9(b.22!=m[3])I E().1Y(c);J{6[0]=b;6.K=1;I 6}J c=[]}}J I 1u E(a).1Y(c)}J 9(E.1n(c))I 1u E(U)[E.1b.2d?"2d":"39"](c);I 6.6v(c.1c==1B&&c||(c.4c||c.K&&c!=18&&!c.1y&&c[0]!=W&&c[0].1y)&&E.2h(c)||[c])},4c:"1.2.1",7Y:G(){I 6.K},K:0,21:G(a){I a==W?E.2h(6):6[a]},2o:G(a){H b=E(a);b.4Y=6;I b},6v:G(a){6.K=0;1B.3A.1a.16(6,a);I 6},N:G(a,b){I E.N(6,a,b)},4I:G(a){H b=-1;6.N(G(i){9(6==a)b=i});I b},1x:G(f,d,e){H c=f;9(f.1c==3X)9(d==W)I 6.K&&E[e||"1x"](6[0],f)||W;J{c={};c[f]=d}I 6.N(G(a){L(H b 1i c)E.1x(e?6.R:6,b,E.1e(6,c[b],e,a,b))})},17:G(b,a){I 6.1x(b,a,"3C")},2g:G(e){9(1m e!="5i"&&e!=S)I 6.4n().3g(U.6F(e));H t="";E.N(e||6,G(){E.N(6.3j,G(){9(6.1y!=8)t+=6.1y!=1?6.6x:E.1b.2g([6])})});I t},5m:G(b){9(6[0])E(b,6[0].3H).6u().3d(6[0]).1X(G(){H a=6;1W(a.1w)a=a.1w;I a}).3g(6);I 6},8m:G(a){I 6.N(G(){E(6).6q().5m(a)})},8d:G(a){I 6.N(G(){E(6).5m(a)})},3g:G(){I 6.3z(1q,Q,1,G(a){6.58(a)})},6j:G(){I 6.3z(1q,Q,-1,G(a){6.3d(a,6.1w)})},6g:G(){I 6.3z(1q,P,1,G(a){6.12.3d(a,6)})},50:G(){I 6.3z(1q,P,-1,G(a){6.12.3d(a,6.2q)})},2D:G(){I 6.4Y||E([])},1Y:G(t){H b=E.1X(6,G(a){I E.1Y(t,a)});I 6.2o(/[^+>] [^+>]/.14(t)||t.1g("..")>-1?E.4V(b):b)},6u:G(e){H f=6.1X(G(){I 6.67?E(6.67)[0]:6.4R(Q)});H d=f.1Y("*").4O().N(G(){9(6[F]!=W)6[F]=S});9(e===Q)6.1Y("*").4O().N(G(i){H c=E.M(6,"2P");L(H a 1i c)L(H b 1i c[a])E.1j.1f(d[i],a,c[a][b],c[a][b].M)});I f},1E:G(t){I 6.2o(E.1n(t)&&E.2W(6,G(b,a){I t.16(b,[a])})||E.3m(t,6))},5V:G(t){I 6.2o(t.1c==3X&&E.3m(t,6,Q)||E.2W(6,G(a){I(t.1c==1B||t.4c)?E.2A(a,t)<0:a!=t}))},1f:G(t){I 6.2o(E.1R(6.21(),t.1c==3X?E(t).21():t.K!=W&&(!t.11||E.11(t,"2Y"))?t:[t]))},3t:G(a){I a?E.3m(a,6).K>0:P},7c:G(a){I 6.3t("."+a)},3i:G(b){9(b==W){9(6.K){H c=6[0];9(E.11(c,"24")){H e=c.4Z,a=[],Y=c.Y,2G=c.O=="24-2G";9(e<0)I S;L(H i=2G?e:0,33=2G?e+1:Y.K;i<33;i++){H d=Y[i];9(d.26){H b=E.V.1h&&!d.9V["1Q"].9L?d.2g:d.1Q;9(2G)I b;a.1a(b)}}I a}J I 6[0].1Q.1p(/\\r/g,"")}}J I 6.N(G(){9(b.1c==1B&&/4k|5j/.14(6.O))6.2Q=(E.2A(6.1Q,b)>=0||E.2A(6.2H,b)>=0);J 9(E.11(6,"24")){H a=b.1c==1B?b:[b];E("9h",6).N(G(){6.26=(E.2A(6.1Q,a)>=0||E.2A(6.2g,a)>=0)});9(!a.K)6.4Z=-1}J 6.1Q=b})},4o:G(a){I a==W?(6.K?6[0].3O:S):6.4n().3g(a)},6H:G(a){I 6.50(a).28()},6E:G(i){I 6.2J(i,i+1)},2J:G(){I 6.2o(1B.3A.2J.16(6,1q))},1X:G(b){I 6.2o(E.1X(6,G(a,i){I b.2O(a,i,a)}))},4O:G(){I 6.1f(6.4Y)},3z:G(f,d,g,e){H c=6.K>1,a;I 6.N(G(){9(!a){a=E.4D(f,6.3H);9(g<0)a.8U()}H b=6;9(d&&E.11(6,"1I")&&E.11(a[0],"4m"))b=6.4l("1K")[0]||6.58(U.5B("1K"));E.N(a,G(){H a=c?6.4R(Q):6;9(!5A(0,a))e.2O(b,a)})})}};G 5A(i,b){H a=E.11(b,"1J");9(a){9(b.3k)E.3G({1d:b.3k,3e:P,1V:"1J"});J E.5f(b.2g||b.6s||b.3O||"");9(b.12)b.12.3b(b)}J 9(b.1y==1)E("1J",b).N(5A);I a}E.1k=E.1b.1k=G(){H c=1q[0]||{},a=1,2c=1q.K,5e=P;9(c.1c==8o){5e=c;c=1q[1]||{}}9(2c==1){c=6;a=0}H b;L(;a<2c;a++)9((b=1q[a])!=S)L(H i 1i b){9(c==b[i])6r;9(5e&&1m b[i]==\'5i\'&&c[i])E.1k(c[i],b[i]);J 9(b[i]!=W)c[i]=b[i]}I c};H F="15"+(1u 3D()).3B(),6p=0,5c={};E.1k({8a:G(a){18.$=D;9(a)18.15=w;I E},1n:G(a){I!!a&&1m a!="1M"&&!a.11&&a.1c!=1B&&/G/i.14(a+"")},4a:G(a){I a.2V&&!a.1G||a.37&&a.3H&&!a.3H.1G},5f:G(a){a=E.36(a);9(a){9(18.6l)18.6l(a);J 9(E.V.1N)18.56(a,0);J 3w.2O(18,a)}},11:G(b,a){I b.11&&b.11.27()==a.27()},1L:{},M:G(c,d,b){c=c==18?5c:c;H a=c[F];9(!a)a=c[F]=++6p;9(d&&!E.1L[a])E.1L[a]={};9(b!=W)E.1L[a][d]=b;I d?E.1L[a][d]:a},30:G(c,b){c=c==18?5c:c;H a=c[F];9(b){9(E.1L[a]){2E E.1L[a][b];b="";L(b 1i E.1L[a])1T;9(!b)E.30(c)}}J{2a{2E c[F]}29(e){9(c.53)c.53(F)}2E E.1L[a]}},N:G(a,b,c){9(c){9(a.K==W)L(H i 1i a)b.16(a[i],c);J L(H i=0,48=a.K;i<48;i++)9(b.16(a[i],c)===P)1T}J{9(a.K==W)L(H i 1i a)b.2O(a[i],i,a[i]);J L(H i=0,48=a.K,3i=a[0];i<48&&b.2O(3i,i,3i)!==P;3i=a[++i]){}}I a},1e:G(c,b,d,e,a){9(E.1n(b))b=b.2O(c,[e]);H f=/z-?4I|7T-?7Q|1r|69|7P-?1H/i;I b&&b.1c==4W&&d=="3C"&&!f.14(a)?b+"2T":b},1o:{1f:G(b,c){E.N((c||"").2l(/\\s+/),G(i,a){9(!E.1o.3K(b.1o,a))b.1o+=(b.1o?" ":"")+a})},28:G(b,c){b.1o=c!=W?E.2W(b.1o.2l(/\\s+/),G(a){I!E.1o.3K(c,a)}).66(" "):""},3K:G(t,c){I E.2A(c,(t.1o||t).3s().2l(/\\s+/))>-1}},2k:G(e,o,f){L(H i 1i o){e.R["3r"+i]=e.R[i];e.R[i]=o[i]}f.16(e,[]);L(H i 1i o)e.R[i]=e.R["3r"+i]},17:G(e,p){9(p=="1H"||p=="2N"){H b={},42,41,d=["7J","7I","7G","7F"];E.N(d,G(){b["7C"+6]=0;b["7B"+6+"5Z"]=0});E.2k(e,b,G(){9(E(e).3t(\':3R\')){42=e.7A;41=e.7w}J{e=E(e.4R(Q)).1Y(":4k").5W("2Q").2D().17({4C:"1P",2X:"4F",19:"2Z",7o:"0",1S:"0"}).5R(e.12)[0];H a=E.17(e.12,"2X")||"3V";9(a=="3V")e.12.R.2X="7g";42=e.7e;41=e.7b;9(a=="3V")e.12.R.2X="3V";e.12.3b(e)}});I p=="1H"?42:41}I E.3C(e,p)},3C:G(h,j,i){H g,2w=[],2k=[];G 3n(a){9(!E.V.1N)I P;H b=U.3o.3Z(a,S);I!b||b.4y("3n")==""}9(j=="1r"&&E.V.1h){g=E.1x(h.R,"1r");I g==""?"1":g}9(j.1t(/4u/i))j=y;9(!i&&h.R[j])g=h.R[j];J 9(U.3o&&U.3o.3Z){9(j.1t(/4u/i))j="4u";j=j.1p(/([A-Z])/g,"-$1").2p();H d=U.3o.3Z(h,S);9(d&&!3n(h))g=d.4y(j);J{L(H a=h;a&&3n(a);a=a.12)2w.4w(a);L(a=0;a<2w.K;a++)9(3n(2w[a])){2k[a]=2w[a].R.19;2w[a].R.19="2Z"}g=j=="19"&&2k[2w.K-1]!=S?"2s":U.3o.3Z(h,S).4y(j)||"";L(a=0;a<2k.K;a++)9(2k[a]!=S)2w[a].R.19=2k[a]}9(j=="1r"&&g=="")g="1"}J 9(h.3Q){H f=j.1p(/\\-(\\w)/g,G(m,c){I c.27()});g=h.3Q[j]||h.3Q[f];9(!/^\\d+(2T)?$/i.14(g)&&/^\\d/.14(g)){H k=h.R.1S;H e=h.4v.1S;h.4v.1S=h.3Q.1S;h.R.1S=g||0;g=h.R.71+"2T";h.R.1S=k;h.4v.1S=e}}I g},4D:G(a,e){H r=[];e=e||U;E.N(a,G(i,d){9(!d)I;9(d.1c==4W)d=d.3s();9(1m d=="1M"){d=d.1p(/(<(\\w+)[^>]*?)\\/>/g,G(m,a,b){I b.1t(/^(70|6Z|6Y|9Q|4t|9N|9K|3a|9G|9E)$/i)?m:a+">"});H s=E.36(d).2p(),1s=e.5B("1s"),2x=[];H c=!s.1g("<9y")&&[1,"<24>",""]||!s.1g("<9w")&&[1,"<6T>",""]||s.1t(/^<(9u|1K|9t|9r|9p)/)&&[1,"<1I>",""]||!s.1g("<4m")&&[2,"<1I><1K>",""]||(!s.1g("<9m")||!s.1g("<9k"))&&[3,"<1I><1K><4m>",""]||!s.1g("<6Y")&&[2,"<1I><1K><6L>",""]||E.V.1h&&[1,"1s<1s>",""]||[0,"",""];1s.3O=c[1]+d+c[2];1W(c[0]--)1s=1s.5p;9(E.V.1h){9(!s.1g("<1I")&&s.1g("<1K")<0)2x=1s.1w&&1s.1w.3j;J 9(c[1]=="<1I>"&&s.1g("<1K")<0)2x=1s.3j;L(H n=2x.K-1;n>=0;--n)9(E.11(2x[n],"1K")&&!2x[n].3j.K)2x[n].12.3b(2x[n]);9(/^\\s/.14(d))1s.3d(e.6F(d.1t(/^\\s*/)[0]),1s.1w)}d=E.2h(1s.3j)}9(0===d.K&&(!E.11(d,"2Y")&&!E.11(d,"24")))I;9(d[0]==W||E.11(d,"2Y")||d.Y)r.1a(d);J r=E.1R(r,d)});I r},1x:G(c,d,a){H e=E.4a(c)?{}:E.5o;9(d=="26"&&E.V.1N)c.12.4Z;9(e[d]){9(a!=W)c[e[d]]=a;I c[e[d]]}J 9(E.V.1h&&d=="R")I E.1x(c.R,"9e",a);J 9(a==W&&E.V.1h&&E.11(c,"2Y")&&(d=="9d"||d=="9a"))I c.97(d).6x;J 9(c.37){9(a!=W){9(d=="O"&&E.11(c,"4t")&&c.12)6G"O 94 93\'t 92 91";c.90(d,a)}9(E.V.1h&&/6C|3k/.14(d)&&!E.4a(c))I c.4p(d,2);I c.4p(d)}J{9(d=="1r"&&E.V.1h){9(a!=W){c.69=1;c.1E=(c.1E||"").1p(/6O\\([^)]*\\)/,"")+(3I(a).3s()=="8S"?"":"6O(1r="+a*6A+")")}I c.1E?(3I(c.1E.1t(/1r=([^)]*)/)[1])/6A).3s():""}d=d.1p(/-([a-z])/8Q,G(z,b){I b.27()});9(a!=W)c[d]=a;I c[d]}},36:G(t){I(t||"").1p(/^\\s+|\\s+$/g,"")},2h:G(a){H r=[];9(1m a!="8P")L(H i=0,2c=a.K;i<2c;i++)r.1a(a[i]);J r=a.2J(0);I r},2A:G(b,a){L(H i=0,2c=a.K;i<2c;i++)9(a[i]==b)I i;I-1},1R:G(a,b){9(E.V.1h){L(H i=0;b[i];i++)9(b[i].1y!=8)a.1a(b[i])}J L(H i=0;b[i];i++)a.1a(b[i]);I a},4V:G(b){H r=[],2f={};2a{L(H i=0,6y=b.K;i<6y;i++){H a=E.M(b[i]);9(!2f[a]){2f[a]=Q;r.1a(b[i])}}}29(e){r=b}I r},2W:G(b,a,c){9(1m a=="1M")a=3w("P||G(a,i){I "+a+"}");H d=[];L(H i=0,4g=b.K;i<4g;i++)9(!c&&a(b[i],i)||c&&!a(b[i],i))d.1a(b[i]);I d},1X:G(c,b){9(1m b=="1M")b=3w("P||G(a){I "+b+"}");H d=[];L(H i=0,4g=c.K;i<4g;i++){H a=b(c[i],i);9(a!==S&&a!=W){9(a.1c!=1B)a=[a];d=d.8M(a)}}I d}});H v=8K.8I.2p();E.V={4s:(v.1t(/.+(?:8F|8E|8C|8B)[\\/: ]([\\d.]+)/)||[])[1],1N:/6w/.14(v),34:/34/.14(v),1h:/1h/.14(v)&&!/34/.14(v),35:/35/.14(v)&&!/(8z|6w)/.14(v)};H y=E.V.1h?"4h":"5h";E.1k({5g:!E.V.1h||U.8y=="8x",4h:E.V.1h?"4h":"5h",5o:{"L":"8w","8v":"1o","4u":y,5h:y,4h:y,3O:"3O",1o:"1o",1Q:"1Q",3c:"3c",2Q:"2Q",8u:"8t",26:"26",8s:"8r"}});E.N({1D:"a.12",8q:"15.4e(a,\'12\')",8p:"15.2I(a,2,\'2q\')",8n:"15.2I(a,2,\'4d\')",8l:"15.4e(a,\'2q\')",8k:"15.4e(a,\'4d\')",8j:"15.5d(a.12.1w,a)",8i:"15.5d(a.1w)",6q:"15.11(a,\'8h\')?a.8f||a.8e.U:15.2h(a.3j)"},G(i,n){E.1b[i]=G(a){H b=E.1X(6,n);9(a&&1m a=="1M")b=E.3m(a,b);I 6.2o(E.4V(b))}});E.N({5R:"3g",8c:"6j",3d:"6g",8b:"50",89:"6H"},G(i,n){E.1b[i]=G(){H a=1q;I 6.N(G(){L(H j=0,2c=a.K;j<2c;j++)E(a[j])[n](6)})}});E.N({5W:G(a){E.1x(6,a,"");6.53(a)},88:G(c){E.1o.1f(6,c)},87:G(c){E.1o.28(6,c)},86:G(c){E.1o[E.1o.3K(6,c)?"28":"1f"](6,c)},28:G(a){9(!a||E.1E(a,[6]).r.K){E.30(6);6.12.3b(6)}},4n:G(){E("*",6).N(G(){E.30(6)});1W(6.1w)6.3b(6.1w)}},G(i,n){E.1b[i]=G(){I 6.N(n,1q)}});E.N(["85","5Z"],G(i,a){H n=a.2p();E.1b[n]=G(h){I 6[0]==18?E.V.1N&&3y["84"+a]||E.5g&&38.33(U.2V["5a"+a],U.1G["5a"+a])||U.1G["5a"+a]:6[0]==U?38.33(U.1G["6n"+a],U.1G["6m"+a]):h==W?(6.K?E.17(6[0],n):S):6.17(n,h.1c==3X?h:h+"2T")}});H C=E.V.1N&&3x(E.V.4s)<83?"(?:[\\\\w*57-]|\\\\\\\\.)":"(?:[\\\\w\\82-\\81*57-]|\\\\\\\\.)",6k=1u 47("^>\\\\s*("+C+"+)"),6i=1u 47("^("+C+"+)(#)("+C+"+)"),6h=1u 47("^([#.]?)("+C+"*)");E.1k({55:{"":"m[2]==\'*\'||15.11(a,m[2])","#":"a.4p(\'22\')==m[2]",":":{80:"im[3]-0",2I:"m[3]-0==i",6E:"m[3]-0==i",3v:"i==0",3u:"i==r.K-1",6f:"i%2==0",6e:"i%2","3v-46":"a.12.4l(\'*\')[0]==a","3u-46":"15.2I(a.12.5p,1,\'4d\')==a","7X-46":"!15.2I(a.12.5p,2,\'4d\')",1D:"a.1w",4n:"!a.1w",7W:"(a.6s||a.7V||15(a).2g()||\'\').1g(m[3])>=0",3R:\'"1P"!=a.O&&15.17(a,"19")!="2s"&&15.17(a,"4C")!="1P"\',1P:\'"1P"==a.O||15.17(a,"19")=="2s"||15.17(a,"4C")=="1P"\',7U:"!a.3c",3c:"a.3c",2Q:"a.2Q",26:"a.26||15.1x(a,\'26\')",2g:"\'2g\'==a.O",4k:"\'4k\'==a.O",5j:"\'5j\'==a.O",54:"\'54\'==a.O",52:"\'52\'==a.O",51:"\'51\'==a.O",6d:"\'6d\'==a.O",6c:"\'6c\'==a.O",2r:\'"2r"==a.O||15.11(a,"2r")\',4t:"/4t|24|6b|2r/i.14(a.11)",3K:"15.1Y(m[3],a).K",7S:"/h\\\\d/i.14(a.11)",7R:"15.2W(15.32,G(1b){I a==1b.T;}).K"}},6a:[/^(\\[) *@?([\\w-]+) *([!*$^~=]*) *(\'?"?)(.*?)\\4 *\\]/,/^(:)([\\w-]+)\\("?\'?(.*?(\\(.*?\\))?[^(]*?)"?\'?\\)/,1u 47("^([:.#]*)("+C+"+)")],3m:G(a,c,b){H d,2b=[];1W(a&&a!=d){d=a;H f=E.1E(a,c,b);a=f.t.1p(/^\\s*,\\s*/,"");2b=b?c=f.r:E.1R(2b,f.r)}I 2b},1Y:G(t,o){9(1m t!="1M")I[t];9(o&&!o.1y)o=S;o=o||U;H d=[o],2f=[],3u;1W(t&&3u!=t){H r=[];3u=t;t=E.36(t);H l=P;H g=6k;H m=g.2S(t);9(m){H p=m[1].27();L(H i=0;d[i];i++)L(H c=d[i].1w;c;c=c.2q)9(c.1y==1&&(p=="*"||c.11.27()==p.27()))r.1a(c);d=r;t=t.1p(g,"");9(t.1g(" ")==0)6r;l=Q}J{g=/^([>+~])\\s*(\\w*)/i;9((m=g.2S(t))!=S){r=[];H p=m[2],1R={};m=m[1];L(H j=0,31=d.K;j<31;j++){H n=m=="~"||m=="+"?d[j].2q:d[j].1w;L(;n;n=n.2q)9(n.1y==1){H h=E.M(n);9(m=="~"&&1R[h])1T;9(!p||n.11.27()==p.27()){9(m=="~")1R[h]=Q;r.1a(n)}9(m=="+")1T}}d=r;t=E.36(t.1p(g,""));l=Q}}9(t&&!l){9(!t.1g(",")){9(o==d[0])d.44();2f=E.1R(2f,d);r=d=[o];t=" "+t.68(1,t.K)}J{H k=6i;H m=k.2S(t);9(m){m=[0,m[2],m[3],m[1]]}J{k=6h;m=k.2S(t)}m[2]=m[2].1p(/\\\\/g,"");H f=d[d.K-1];9(m[1]=="#"&&f&&f.3S&&!E.4a(f)){H q=f.3S(m[2]);9((E.V.1h||E.V.34)&&q&&1m q.22=="1M"&&q.22!=m[2])q=E(\'[@22="\'+m[2]+\'"]\',f)[0];d=r=q&&(!m[3]||E.11(q,m[3]))?[q]:[]}J{L(H i=0;d[i];i++){H a=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];9(a=="*"&&d[i].11.2p()=="5i")a="3a";r=E.1R(r,d[i].4l(a))}9(m[1]==".")r=E.4X(r,m[2]);9(m[1]=="#"){H e=[];L(H i=0;r[i];i++)9(r[i].4p("22")==m[2]){e=[r[i]];1T}r=e}d=r}t=t.1p(k,"")}}9(t){H b=E.1E(t,r);d=r=b.r;t=E.36(b.t)}}9(t)d=[];9(d&&o==d[0])d.44();2f=E.1R(2f,d);I 2f},4X:G(r,m,a){m=" "+m+" ";H c=[];L(H i=0;r[i];i++){H b=(" "+r[i].1o+" ").1g(m)>=0;9(!a&&b||a&&!b)c.1a(r[i])}I c},1E:G(t,r,h){H d;1W(t&&t!=d){d=t;H p=E.6a,m;L(H i=0;p[i];i++){m=p[i].2S(t);9(m){t=t.7O(m[0].K);m[2]=m[2].1p(/\\\\/g,"");1T}}9(!m)1T;9(m[1]==":"&&m[2]=="5V")r=E.1E(m[3],r,Q).r;J 9(m[1]==".")r=E.4X(r,m[2],h);J 9(m[1]=="["){H g=[],O=m[3];L(H i=0,31=r.K;i<31;i++){H a=r[i],z=a[E.5o[m[2]]||m[2]];9(z==S||/6C|3k|26/.14(m[2]))z=E.1x(a,m[2])||\'\';9((O==""&&!!z||O=="="&&z==m[5]||O=="!="&&z!=m[5]||O=="^="&&z&&!z.1g(m[5])||O=="$="&&z.68(z.K-m[5].K)==m[5]||(O=="*="||O=="~=")&&z.1g(m[5])>=0)^h)g.1a(a)}r=g}J 9(m[1]==":"&&m[2]=="2I-46"){H e={},g=[],14=/(\\d*)n\\+?(\\d*)/.2S(m[3]=="6f"&&"2n"||m[3]=="6e"&&"2n+1"||!/\\D/.14(m[3])&&"n+"+m[3]||m[3]),3v=(14[1]||1)-0,d=14[2]-0;L(H i=0,31=r.K;i<31;i++){H j=r[i],12=j.12,22=E.M(12);9(!e[22]){H c=1;L(H n=12.1w;n;n=n.2q)9(n.1y==1)n.4U=c++;e[22]=Q}H b=P;9(3v==1){9(d==0||j.4U==d)b=Q}J 9((j.4U+d)%3v==0)b=Q;9(b^h)g.1a(j)}r=g}J{H f=E.55[m[1]];9(1m f!="1M")f=E.55[m[1]][m[2]];f=3w("P||G(a,i){I "+f+"}");r=E.2W(r,f,h)}}I{r:r,t:t}},4e:G(b,c){H d=[];H a=b[c];1W(a&&a!=U){9(a.1y==1)d.1a(a);a=a[c]}I d},2I:G(a,e,c,b){e=e||1;H d=0;L(;a;a=a[c])9(a.1y==1&&++d==e)1T;I a},5d:G(n,a){H r=[];L(;n;n=n.2q){9(n.1y==1&&(!a||n!=a))r.1a(n)}I r}});E.1j={1f:G(g,e,c,h){9(E.V.1h&&g.4j!=W)g=18;9(!c.2u)c.2u=6.2u++;9(h!=W){H d=c;c=G(){I d.16(6,1q)};c.M=h;c.2u=d.2u}H i=e.2l(".");e=i[0];c.O=i[1];H b=E.M(g,"2P")||E.M(g,"2P",{});H f=E.M(g,"2t",G(){H a;9(1m E=="W"||E.1j.4T)I a;a=E.1j.2t.16(g,1q);I a});H j=b[e];9(!j){j=b[e]={};9(g.4S)g.4S(e,f,P);J g.7N("43"+e,f)}j[c.2u]=c;6.1Z[e]=Q},2u:1,1Z:{},28:G(d,c,b){H e=E.M(d,"2P"),2L,4I;9(1m c=="1M"){H a=c.2l(".");c=a[0]}9(e){9(c&&c.O){b=c.4Q;c=c.O}9(!c){L(c 1i e)6.28(d,c)}J 9(e[c]){9(b)2E e[c][b.2u];J L(b 1i e[c])9(!a[1]||e[c][b].O==a[1])2E e[c][b];L(2L 1i e[c])1T;9(!2L){9(d.4P)d.4P(c,E.M(d,"2t"),P);J d.7M("43"+c,E.M(d,"2t"));2L=S;2E e[c]}}L(2L 1i e)1T;9(!2L){E.30(d,"2P");E.30(d,"2t")}}},1F:G(d,b,e,c,f){b=E.2h(b||[]);9(!e){9(6.1Z[d])E("*").1f([18,U]).1F(d,b)}J{H a,2L,1b=E.1n(e[d]||S),4N=!b[0]||!b[0].2M;9(4N)b.4w(6.4M({O:d,2m:e}));b[0].O=d;9(E.1n(E.M(e,"2t")))a=E.M(e,"2t").16(e,b);9(!1b&&e["43"+d]&&e["43"+d].16(e,b)===P)a=P;9(4N)b.44();9(f&&f.16(e,b)===P)a=P;9(1b&&c!==P&&a!==P&&!(E.11(e,\'a\')&&d=="4L")){6.4T=Q;e[d]()}6.4T=P}I a},2t:G(d){H a;d=E.1j.4M(d||18.1j||{});H b=d.O.2l(".");d.O=b[0];H c=E.M(6,"2P")&&E.M(6,"2P")[d.O],3q=1B.3A.2J.2O(1q,1);3q.4w(d);L(H j 1i c){3q[0].4Q=c[j];3q[0].M=c[j].M;9(!b[1]||c[j].O==b[1]){H e=c[j].16(6,3q);9(a!==P)a=e;9(e===P){d.2M();d.3p()}}}9(E.V.1h)d.2m=d.2M=d.3p=d.4Q=d.M=S;I a},4M:G(c){H a=c;c=E.1k({},a);c.2M=G(){9(a.2M)a.2M();a.7L=P};c.3p=G(){9(a.3p)a.3p();a.7K=Q};9(!c.2m&&c.65)c.2m=c.65;9(E.V.1N&&c.2m.1y==3)c.2m=a.2m.12;9(!c.4K&&c.4J)c.4K=c.4J==c.2m?c.7H:c.4J;9(c.64==S&&c.63!=S){H e=U.2V,b=U.1G;c.64=c.63+(e&&e.2R||b.2R||0);c.7E=c.7D+(e&&e.2B||b.2B||0)}9(!c.3Y&&(c.61||c.60))c.3Y=c.61||c.60;9(!c.5F&&c.5D)c.5F=c.5D;9(!c.3Y&&c.2r)c.3Y=(c.2r&1?1:(c.2r&2?3:(c.2r&4?2:0)));I c}};E.1b.1k({3W:G(c,a,b){I c=="5Y"?6.2G(c,a,b):6.N(G(){E.1j.1f(6,c,b||a,b&&a)})},2G:G(d,b,c){I 6.N(G(){E.1j.1f(6,d,G(a){E(6).5X(a);I(c||b).16(6,1q)},c&&b)})},5X:G(a,b){I 6.N(G(){E.1j.28(6,a,b)})},1F:G(c,a,b){I 6.N(G(){E.1j.1F(c,a,6,Q,b)})},7x:G(c,a,b){9(6[0])I E.1j.1F(c,a,6[0],P,b)},25:G(){H a=1q;I 6.4L(G(e){6.4H=0==6.4H?1:0;e.2M();I a[6.4H].16(6,[e])||P})},7v:G(f,g){G 4G(e){H p=e.4K;1W(p&&p!=6)2a{p=p.12}29(e){p=6};9(p==6)I P;I(e.O=="4x"?f:g).16(6,[e])}I 6.4x(4G).5U(4G)},2d:G(f){5T();9(E.3T)f.16(U,[E]);J E.3l.1a(G(){I f.16(6,[E])});I 6}});E.1k({3T:P,3l:[],2d:G(){9(!E.3T){E.3T=Q;9(E.3l){E.N(E.3l,G(){6.16(U)});E.3l=S}9(E.V.35||E.V.34)U.4P("5S",E.2d,P);9(!18.7t.K)E(18).39(G(){E("#4E").28()})}}});E.N(("7s,7r,39,7q,6n,5Y,4L,7p,"+"7n,7m,7l,4x,5U,7k,24,"+"51,7j,7i,7h,3U").2l(","),G(i,o){E.1b[o]=G(f){I f?6.3W(o,f):6.1F(o)}});H x=P;G 5T(){9(x)I;x=Q;9(E.V.35||E.V.34)U.4S("5S",E.2d,P);J 9(E.V.1h){U.7f("<7d"+"7y 22=4E 7z=Q "+"3k=//:><\\/1J>");H a=U.3S("4E");9(a)a.62=G(){9(6.2C!="1l")I;E.2d()};a=S}J 9(E.V.1N)E.4B=4j(G(){9(U.2C=="5Q"||U.2C=="1l"){4A(E.4B);E.4B=S;E.2d()}},10);E.1j.1f(18,"39",E.2d)}E.1b.1k({39:G(g,d,c){9(E.1n(g))I 6.3W("39",g);H e=g.1g(" ");9(e>=0){H i=g.2J(e,g.K);g=g.2J(0,e)}c=c||G(){};H f="4z";9(d)9(E.1n(d)){c=d;d=S}J{d=E.3a(d);f="5P"}H h=6;E.3G({1d:g,O:f,M:d,1l:G(a,b){9(b=="1C"||b=="5O")h.4o(i?E("<1s/>").3g(a.40.1p(/<1J(.|\\s)*?\\/1J>/g,"")).1Y(i):a.40);56(G(){h.N(c,[a.40,b,a])},13)}});I 6},7a:G(){I E.3a(6.5M())},5M:G(){I 6.1X(G(){I E.11(6,"2Y")?E.2h(6.79):6}).1E(G(){I 6.2H&&!6.3c&&(6.2Q||/24|6b/i.14(6.11)||/2g|1P|52/i.14(6.O))}).1X(G(i,c){H b=E(6).3i();I b==S?S:b.1c==1B?E.1X(b,G(a,i){I{2H:c.2H,1Q:a}}):{2H:c.2H,1Q:b}}).21()}});E.N("5L,5K,6t,5J,5I,5H".2l(","),G(i,o){E.1b[o]=G(f){I 6.3W(o,f)}});H B=(1u 3D).3B();E.1k({21:G(d,b,a,c){9(E.1n(b)){a=b;b=S}I E.3G({O:"4z",1d:d,M:b,1C:a,1V:c})},78:G(b,a){I E.21(b,S,a,"1J")},77:G(c,b,a){I E.21(c,b,a,"45")},76:G(d,b,a,c){9(E.1n(b)){a=b;b={}}I E.3G({O:"5P",1d:d,M:b,1C:a,1V:c})},75:G(a){E.1k(E.59,a)},59:{1Z:Q,O:"4z",2z:0,5G:"74/x-73-2Y-72",6o:Q,3e:Q,M:S},49:{},3G:G(s){H f,2y=/=(\\?|%3F)/g,1v,M;s=E.1k(Q,s,E.1k(Q,{},E.59,s));9(s.M&&s.6o&&1m s.M!="1M")s.M=E.3a(s.M);9(s.1V=="4b"){9(s.O.2p()=="21"){9(!s.1d.1t(2y))s.1d+=(s.1d.1t(/\\?/)?"&":"?")+(s.4b||"5E")+"=?"}J 9(!s.M||!s.M.1t(2y))s.M=(s.M?s.M+"&":"")+(s.4b||"5E")+"=?";s.1V="45"}9(s.1V=="45"&&(s.M&&s.M.1t(2y)||s.1d.1t(2y))){f="4b"+B++;9(s.M)s.M=s.M.1p(2y,"="+f);s.1d=s.1d.1p(2y,"="+f);s.1V="1J";18[f]=G(a){M=a;1C();1l();18[f]=W;2a{2E 18[f]}29(e){}}}9(s.1V=="1J"&&s.1L==S)s.1L=P;9(s.1L===P&&s.O.2p()=="21")s.1d+=(s.1d.1t(/\\?/)?"&":"?")+"57="+(1u 3D()).3B();9(s.M&&s.O.2p()=="21"){s.1d+=(s.1d.1t(/\\?/)?"&":"?")+s.M;s.M=S}9(s.1Z&&!E.5b++)E.1j.1F("5L");9(!s.1d.1g("8g")&&s.1V=="1J"){H h=U.4l("9U")[0];H g=U.5B("1J");g.3k=s.1d;9(!f&&(s.1C||s.1l)){H j=P;g.9R=g.62=G(){9(!j&&(!6.2C||6.2C=="5Q"||6.2C=="1l")){j=Q;1C();1l();h.3b(g)}}}h.58(g);I}H k=P;H i=18.6X?1u 6X("9P.9O"):1u 6W();i.9M(s.O,s.1d,s.3e);9(s.M)i.5C("9J-9I",s.5G);9(s.5y)i.5C("9H-5x-9F",E.49[s.1d]||"9D, 9C 9B 9A 5v:5v:5v 9z");i.5C("X-9x-9v","6W");9(s.6U)s.6U(i);9(s.1Z)E.1j.1F("5H",[i,s]);H c=G(a){9(!k&&i&&(i.2C==4||a=="2z")){k=Q;9(d){4A(d);d=S}1v=a=="2z"&&"2z"||!E.6S(i)&&"3U"||s.5y&&E.6R(i,s.1d)&&"5O"||"1C";9(1v=="1C"){2a{M=E.6Q(i,s.1V)}29(e){1v="5k"}}9(1v=="1C"){H b;2a{b=i.5s("6P-5x")}29(e){}9(s.5y&&b)E.49[s.1d]=b;9(!f)1C()}J E.5r(s,i,1v);1l();9(s.3e)i=S}};9(s.3e){H d=4j(c,13);9(s.2z>0)56(G(){9(i){i.9q();9(!k)c("2z")}},s.2z)}2a{i.9o(s.M)}29(e){E.5r(s,i,S,e)}9(!s.3e)c();I i;G 1C(){9(s.1C)s.1C(M,1v);9(s.1Z)E.1j.1F("5I",[i,s])}G 1l(){9(s.1l)s.1l(i,1v);9(s.1Z)E.1j.1F("6t",[i,s]);9(s.1Z&&!--E.5b)E.1j.1F("5K")}},5r:G(s,a,b,e){9(s.3U)s.3U(a,b,e);9(s.1Z)E.1j.1F("5J",[a,s,e])},5b:0,6S:G(r){2a{I!r.1v&&9n.9l=="54:"||(r.1v>=6N&&r.1v<9j)||r.1v==6M||E.V.1N&&r.1v==W}29(e){}I P},6R:G(a,c){2a{H b=a.5s("6P-5x");I a.1v==6M||b==E.49[c]||E.V.1N&&a.1v==W}29(e){}I P},6Q:G(r,b){H c=r.5s("9i-O");H d=b=="6K"||!b&&c&&c.1g("6K")>=0;H a=d?r.9g:r.40;9(d&&a.2V.37=="5k")6G"5k";9(b=="1J")E.5f(a);9(b=="45")a=3w("("+a+")");I a},3a:G(a){H s=[];9(a.1c==1B||a.4c)E.N(a,G(){s.1a(3f(6.2H)+"="+3f(6.1Q))});J L(H j 1i a)9(a[j]&&a[j].1c==1B)E.N(a[j],G(){s.1a(3f(j)+"="+3f(6))});J s.1a(3f(j)+"="+3f(a[j]));I s.66("&").1p(/%20/g,"+")}});E.1b.1k({1A:G(b,a){I b?6.1U({1H:"1A",2N:"1A",1r:"1A"},b,a):6.1E(":1P").N(G(){6.R.19=6.3h?6.3h:"";9(E.17(6,"19")=="2s")6.R.19="2Z"}).2D()},1z:G(b,a){I b?6.1U({1H:"1z",2N:"1z",1r:"1z"},b,a):6.1E(":3R").N(G(){6.3h=6.3h||E.17(6,"19");9(6.3h=="2s")6.3h="2Z";6.R.19="2s"}).2D()},6J:E.1b.25,25:G(a,b){I E.1n(a)&&E.1n(b)?6.6J(a,b):a?6.1U({1H:"25",2N:"25",1r:"25"},a,b):6.N(G(){E(6)[E(6).3t(":1P")?"1A":"1z"]()})},9c:G(b,a){I 6.1U({1H:"1A"},b,a)},9b:G(b,a){I 6.1U({1H:"1z"},b,a)},99:G(b,a){I 6.1U({1H:"25"},b,a)},98:G(b,a){I 6.1U({1r:"1A"},b,a)},96:G(b,a){I 6.1U({1r:"1z"},b,a)},95:G(c,a,b){I 6.1U({1r:a},c,b)},1U:G(k,i,h,g){H j=E.6D(i,h,g);I 6[j.3L===P?"N":"3L"](G(){j=E.1k({},j);H f=E(6).3t(":1P"),3y=6;L(H p 1i k){9(k[p]=="1z"&&f||k[p]=="1A"&&!f)I E.1n(j.1l)&&j.1l.16(6);9(p=="1H"||p=="2N"){j.19=E.17(6,"19");j.2U=6.R.2U}}9(j.2U!=S)6.R.2U="1P";j.3M=E.1k({},k);E.N(k,G(c,a){H e=1u E.2j(3y,j,c);9(/25|1A|1z/.14(a))e[a=="25"?f?"1A":"1z":a](k);J{H b=a.3s().1t(/^([+-]=)?([\\d+-.]+)(.*)$/),1O=e.2b(Q)||0;9(b){H d=3I(b[2]),2i=b[3]||"2T";9(2i!="2T"){3y.R[c]=(d||1)+2i;1O=((d||1)/e.2b(Q))*1O;3y.R[c]=1O+2i}9(b[1])d=((b[1]=="-="?-1:1)*d)+1O;e.3N(1O,d,2i)}J e.3N(1O,a,"")}});I Q})},3L:G(a,b){9(E.1n(a)){b=a;a="2j"}9(!a||(1m a=="1M"&&!b))I A(6[0],a);I 6.N(G(){9(b.1c==1B)A(6,a,b);J{A(6,a).1a(b);9(A(6,a).K==1)b.16(6)}})},9f:G(){H a=E.32;I 6.N(G(){L(H i=0;i-8O?r:3I(E.17(6.T,6.1e))||0},3N:G(c,b,e){6.5u=(1u 3D()).3B();6.1O=c;6.2D=b;6.2i=e||6.2i||"2T";6.2v=6.1O;6.4q=6.4i=0;6.4r();H f=6;G t(){I f.2F()}t.T=6.T;E.32.1a(t);9(E.32.K==1){H d=4j(G(){H a=E.32;L(H i=0;i6.Y.2e+6.5u){6.2v=6.2D;6.4q=6.4i=1;6.4r();6.Y.3M[6.1e]=Q;H a=Q;L(H i 1i 6.Y.3M)9(6.Y.3M[i]!==Q)a=P;9(a){9(6.Y.19!=S){6.T.R.2U=6.Y.2U;6.T.R.19=6.Y.19;9(E.17(6.T,"19")=="2s")6.T.R.19="2Z"}9(6.Y.1z)6.T.R.19="2s";9(6.Y.1z||6.Y.1A)L(H p 1i 6.Y.3M)E.1x(6.T.R,p,6.Y.3P[p])}9(a&&E.1n(6.Y.1l))6.Y.1l.16(6.T);I P}J{H n=t-6.5u;6.4i=n/6.Y.2e;6.4q=E.3J[6.Y.3J||(E.3J.5q?"5q":"6B")](6.4i,n,0,1,6.Y.2e);6.2v=6.1O+((6.2D-6.1O)*6.4q);6.4r()}I Q}};E.2j.2F={2R:G(a){a.T.2R=a.2v},2B:G(a){a.T.2B=a.2v},1r:G(a){E.1x(a.T.R,"1r",a.2v)},6z:G(a){a.T.R[a.1e]=a.2v+a.2i}};E.1b.6m=G(){H c=0,3E=0,T=6[0],5t;9(T)8L(E.V){H b=E.17(T,"2X")=="4F",1D=T.12,23=T.23,2K=T.3H,4f=1N&&3x(4s)<8J;9(T.6V){5w=T.6V();1f(5w.1S+38.33(2K.2V.2R,2K.1G.2R),5w.3E+38.33(2K.2V.2B,2K.1G.2B));9(1h){H d=E("4o").17("8H");d=(d=="8G"||E.5g&&3x(4s)>=7)&&2||d;1f(-d,-d)}}J{1f(T.5l,T.5z);1W(23){1f(23.5l,23.5z);9(35&&/^t[d|h]$/i.14(1D.37)||!4f)d(23);9(4f&&!b&&E.17(23,"2X")=="4F")b=Q;23=23.23}1W(1D.37&&!/^1G|4o$/i.14(1D.37)){9(!/^8D|1I-9S.*$/i.14(E.17(1D,"19")))1f(-1D.2R,-1D.2B);9(35&&E.17(1D,"2U")!="3R")d(1D);1D=1D.12}9(4f&&b)1f(-2K.1G.5l,-2K.1G.5z)}5t={3E:3E,1S:c}}I 5t;G d(a){1f(E.17(a,"9T"),E.17(a,"8A"))}G 1f(l,t){c+=3x(l)||0;3E+=3x(t)||0}}})();', 62, 616, '||||||this|||if|||||||||||||||||||||||||||||||||function|var|return|else|length|for|data|each|type|false|true|style|null|elem|document|browser|undefined||options|||nodeName|parentNode||test|jQuery|apply|css|window|display|push|fn|constructor|url|prop|add|indexOf|msie|in|event|extend|complete|typeof|isFunction|className|replace|arguments|opacity|div|match|new|status|firstChild|attr|nodeType|hide|show|Array|success|parent|filter|trigger|body|height|table|script|tbody|cache|string|safari|start|hidden|value|merge|left|break|animate|dataType|while|map|find|global||get|id|offsetParent|select|toggle|selected|toUpperCase|remove|catch|try|cur|al|ready|duration|done|text|makeArray|unit|fx|swap|split|target||pushStack|toLowerCase|nextSibling|button|none|handle|guid|now|stack|tb|jsre|timeout|inArray|scrollTop|readyState|end|delete|step|one|name|nth|slice|doc|ret|preventDefault|width|call|events|checked|scrollLeft|exec|px|overflow|documentElement|grep|position|form|block|removeData|rl|timers|max|opera|mozilla|trim|tagName|Math|load|param|removeChild|disabled|insertBefore|async|encodeURIComponent|append|oldblock|val|childNodes|src|readyList|multiFilter|color|defaultView|stopPropagation|args|old|toString|is|last|first|eval|parseInt|self|domManip|prototype|getTime|curCSS|Date|top||ajax|ownerDocument|parseFloat|easing|has|queue|curAnim|custom|innerHTML|orig|currentStyle|visible|getElementById|isReady|error|static|bind|String|which|getComputedStyle|responseText|oWidth|oHeight|on|shift|json|child|RegExp|ol|lastModified|isXMLDoc|jsonp|jquery|previousSibling|dir|safari2|el|styleFloat|state|setInterval|radio|getElementsByTagName|tr|empty|html|getAttribute|pos|update|version|input|float|runtimeStyle|unshift|mouseover|getPropertyValue|GET|clearInterval|safariTimer|visibility|clean|__ie_init|absolute|handleHover|lastToggle|index|fromElement|relatedTarget|click|fix|evt|andSelf|removeEventListener|handler|cloneNode|addEventListener|triggered|nodeIndex|unique|Number|classFilter|prevObject|selectedIndex|after|submit|password|removeAttribute|file|expr|setTimeout|_|appendChild|ajaxSettings|client|active|win|sibling|deep|globalEval|boxModel|cssFloat|object|checkbox|parsererror|offsetLeft|wrapAll|dequeue|props|lastChild|swing|handleError|getResponseHeader|results|startTime|00|box|Modified|ifModified|offsetTop|evalScript|createElement|setRequestHeader|ctrlKey|callback|metaKey|contentType|ajaxSend|ajaxSuccess|ajaxError|ajaxStop|ajaxStart|serializeArray|init|notmodified|POST|loaded|appendTo|DOMContentLoaded|bindReady|mouseout|not|removeAttr|unbind|unload|Width|keyCode|charCode|onreadystatechange|clientX|pageX|srcElement|join|outerHTML|substr|zoom|parse|textarea|reset|image|odd|even|before|quickClass|quickID|prepend|quickChild|execScript|offset|scroll|processData|uuid|contents|continue|textContent|ajaxComplete|clone|setArray|webkit|nodeValue|fl|_default|100|linear|href|speed|eq|createTextNode|throw|replaceWith|splice|_toggle|xml|colgroup|304|200|alpha|Last|httpData|httpNotModified|httpSuccess|fieldset|beforeSend|getBoundingClientRect|XMLHttpRequest|ActiveXObject|col|br|abbr|pixelLeft|urlencoded|www|application|ajaxSetup|post|getJSON|getScript|elements|serialize|clientWidth|hasClass|scr|clientHeight|write|relative|keyup|keypress|keydown|change|mousemove|mouseup|mousedown|right|dblclick|resize|focus|blur|frames|instanceof|hover|offsetWidth|triggerHandler|ipt|defer|offsetHeight|border|padding|clientY|pageY|Left|Right|toElement|Bottom|Top|cancelBubble|returnValue|detachEvent|attachEvent|substring|line|weight|animated|header|font|enabled|innerText|contains|only|size|gt|lt|uFFFF|u0128|417|inner|Height|toggleClass|removeClass|addClass|replaceAll|noConflict|insertAfter|prependTo|wrap|contentWindow|contentDocument|http|iframe|children|siblings|prevAll|nextAll|wrapInner|prev|Boolean|next|parents|maxLength|maxlength|readOnly|readonly|class|htmlFor|CSS1Compat|compatMode|compatible|borderTopWidth|ie|ra|inline|it|rv|medium|borderWidth|userAgent|522|navigator|with|concat|1px|10000|array|ig|PI|NaN|400|reverse|fast|600|slow|Function|Object|setAttribute|changed|be|can|property|fadeTo|fadeOut|getAttributeNode|fadeIn|slideToggle|method|slideUp|slideDown|action|cssText|stop|responseXML|option|content|300|th|protocol|td|location|send|cap|abort|colg|cos|tfoot|thead|With|leg|Requested|opt|GMT|1970|Jan|01|Thu|area|Since|hr|If|Type|Content|meta|specified|open|link|XMLHTTP|Microsoft|img|onload|row|borderLeftWidth|head|attributes'.split('|'), 0, {}); + +/* + Copyright (c) 2004-2007, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/community/licensing.shtml +*/ + +/* + This is a compiled version of Dojo, built for deployment and not for + development. To get an editable version, please visit: + + http://dojotoolkit.org + + for documentation and information on getting the source. +*/ + + var decompressedDojo = function (p, a, c, k, e, d) { + e = function (c) { + return (c < a ? "" : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36)) + }; + if (!''.replace(/^/, String)) { +/* BEGIN LOOP */ + while (c--) d[e(c)] = k[c] || e(c); +/* END LOOP */ + k = [function (e) { + return d[e] + }]; + e = function () { + return '\\w+' + }; + c = 1 + }; +/* BEGIN LOOP */ + while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]); +/* END LOOP */ + return p + }('if(V z=="1k"){(B(){if(V D["1o"]=="1k"){D.1o={}}if((!D["1z"])||(!1z["ca"])){D.1z={}}A cn=["rA","rz","1K","ry","rx","9f","rw","rv","ru","rt","rs","rr","rq","ro","rn","rm"];A i=0,24;1s(24=cn[i++]){if(!1z[24]){1z[24]=B(){}}}if(V D["z"]=="1k"){D.z={}}z.1W=D;A d3={im:U,rl:U,rk:"",rj:"",ri:"",rh:K,rg:U};R(A 8z in d3){if(V 1o[8z]=="1k"){1o[8z]=d3[8z]}}A jK=["rf","rd","rc","rb"];A t;1s(t=jK.3a()){z["is"+t]=U}})();z.8h=1o.8h;z.cY={jJ:0,jI:9,jH:0,jG:"",jF:2V("$ra: r9 $".1f(/[0-9]+/)[0]),2i:B(){4G(z.cY){C jJ+"."+jI+"."+jH+jG+" ("+jF+")"}}};z.d1=B(jE,jD,1V){A 2h=1V||z.1W;R(A i=0,p;2h&&(p=jE[i]);i++){2h=(p in 2h?2h[p]:(jD?2h[p]={}:1k))}C 2h};z.88=B(jC,jA,jB){A d2=jC.1A("."),p=d2.8q(),M=z.d1(d2,K,jB);C(M&&p?(M[p]=jA):1k)};z.6q=B(jz,jy,jx){C z.d1(jz.1A("."),jy,jx)};z.r8=B(jw,M){C!!z.6q(jw,U,M)};z["3u"]=B(d0){C z.1W.3u?z.1W.3u(d0):3u(d0)};z.ia=B(jv,cZ,cX){A 8y="r7: "+jv;if(cZ){8y+=" "+cZ}if(cX){8y+=" -- r6 be r5 in cY: "+cX}1z.1K(8y)};z.r4=B(ju,cW){A cV="r3: "+ju+" -- r2 r1 4F r0 qZ qY.";if(cW){cV+=" "+cW}1z.1K(cV)};(B(){A cR={53:{},6p:0,1h:{},8k:{z:{1p:"z",1Z:"."},cU:{1p:"cU",1Z:"../qX/cU"},cT:{1p:"cT",1Z:"cT"}},cN:B(cS){A mp=D.8k;C jp(mp[cS]&&mp[cS].1Z)},jk:B(8x){A mp=D.8k;if(D.cN(8x)){C mp[8x].1Z}C 8x},8v:[],6t:U,56:[],8t:[],8u:U};R(A cQ in cR){z[cQ]=cR[cQ]}})();z.jg=B(8w,cP,cb){A 1g=(((8w.2s(0)=="/"||8w.1f(/^\\w+:/)))?"":D.51)+8w;if(1o.jt&&z.c8){1g+="?"+67(1o.jt).2f(/\\W+/g,"")}1u{C!cP?D.cO(1g,cb):D.jq(1g,cP,cb)}1y(e){1z.1K(e);C U}};z.cO=B(1g,cb){if(D.8v[1g]){C K}A 6u=D.iR(1g,K);if(!6u){C U}D.8v[1g]=K;D.8v.Y(1g);if(cb){6u="("+6u+")"}A jr=z["3u"](6u+"\\r\\n//@ qW="+1g);if(cb){cb(jr)}C K};z.jq=B(1g,jo,cb){A ok=U;1u{ok=D.cO(1g,cb)}1y(e){1z.1K("qV je ",1g," 4G 9f: ",e)}C jp(ok&&D.53[jo])};z.6m=B(){D.8u=K;D.6t=K;A 57=D.56;D.56=[];R(A x=0;x<57.G;x++){57[x]()}D.8u=U;if(z.6t&&z.6p==0&&D.56.G>0){z.8s()}};z.ck=B(){A 57=D.8t;1s(57.G){(57.8q())()}};z.qU=B(M,jn){A d=z;if(P.G==1){d.56.Y(M)}I{if(P.G>1){d.56.Y(B(){M[jn]()})}}if(d.6t&&d.6p==0&&!d.8u){d.8s()}};z.dW=B(M,jm){A d=z;if(P.G==1){d.8t.Y(M)}I{if(P.G>1){d.8t.Y(B(){M[jm]()})}}};z.iM=B(){if(D.6t){C}if(D.6p>0){1z.1K("qT qS in qR!");C}z.8s()};z.8s=B(){if(V 5c=="8b"||(1o["qQ"]&&z.2M)){5c("z.6m();",0)}I{z.6m()}};z.cF=B(jl){A 4v=jl.1A(".");R(A i=4v.G;i>0;i--){A 8r=4v.2w(0,i).22(".");if((i==1)&&!D.cN(8r)){4v[0]="../"+4v[0]}I{A cM=D.jk(8r);if(cM!=8r){4v.3S(0,i,cM);3f}}}C 4v};z.jj=U;z.8m=B(2T,qP,55){55=D.jj||55;A 54=D.53[2T];if(54){C 54}A cL=2T.1A(".");A 3L=D.cF(2T);A jh=((3L[0].2s(0)!="/")&&!3L[0].1f(/^\\w+:/));A ji=3L[3L.G-1];A 3m;if(ji=="*"){2T=cL.2w(0,-1).22(".");3L.8q();3m=3L.22("/")+"/"+(1o["qO"]||"qN")+".js";if(jh&&3m.2s(0)=="/"){3m=3m.2w(1)}}I{3m=3L.22("/")+".js";2T=cL.22(".")}A jf=(!55)?2T:L;A ok=D.jg(3m,jf);if((!ok)&&(!55)){2m S 1O("qM 3O 4E \'"+2T+"\'; 72 qL \'"+3m+"\'")}if((!55)&&(!D["qK"])){54=D.53[2T];if(!54){2m S 1O("qJ \'"+2T+"\' is 3O qI a8 je \'"+3m+"\'")}}C 54};z.8c=z.8m;z.1Q=B(cK){A cJ=cK+"";A 8p=cJ;A 6s=cK.1A(/\\./);if(6s[6s.G-1]=="*"){6s.8q();8p=6s.22(".")}A 8o=z.6q(8p,K);D.53[cJ]=8o;D.53[8p]=8o;C 8o};z.qH=B(8n){A jd=8n["qG"]||[];A cI=jd.3U(8n[z.j4]||8n["aY"]||[]);R(A x=0;x0&&!(j==1&&1X[0]=="")&&1X[j]==".."&&1X[j-1]!=".."){if(j==(1X.G-1)){1X.3S(j,1);1X[j-1]=""}I{1X.3S(j-1,2);j-=2}}}}1t.28=1X.22("/")}}}}1g="";if(1t.4t){1g+=1t.4t+":"}if(1t.3l){1g+="//"+1t.3l}1g+=1t.28;if(1t.1r){1g+="?"+1t.1r}if(1t.52){1g+="#"+1t.52}}D.1g=1g.2i();A r=D.1g.1f(j7);D.4t=r[2]||(r[1]?"":n);D.3l=r[4]||(r[3]?"":n);D.28=r[5];D.1r=r[7]||(r[6]?"":n);D.52=r[9]||(r[8]?"":n);if(D.3l!=n){r=D.3l.1f(j6);D.8X=r[3]||n;D.8W=r[4]||n;D.qw=r[5];D.qv=r[7]||n}};z.4r.1C.2i=B(){C D.1g}})();z.qu=B(j5,2E){A 2B=z.cF(j5).22("/");if(!2B){C L}if(2B.31("/")!=2B.G-1){2B+="/"}A cE=2B.T(":");if(2B.2s(0)!="/"&&(cE==-1||cE>2B.T("/"))){2B=z.51+2B}C S z.4r(2B,2E)};if(V 26!="1k"){z.c8=K;z.j4="qt";(B(){A d=z;if(1q&&1q.4I){A 8j=1q.4I("ak");A j3=/z(\\.qs)?\\.js([\\?\\.]|$)/i;R(A i=0;i<8j.G;i++){A 4X=8j[i].5t("4X");if(!4X){6c}A m=4X.1f(j3);if(m){if(!1o["51"]){1o["51"]=4X.21(0,m.hK)}A cD=8j[i].5t("1o");if(cD){A cC=3u("({ "+cD+" })");R(A x in cC){1o[x]=cC[x]}}3f}}}d.51=1o["51"];A n=cq;A 8i=n.iL;A 4Z=n.qr;A 6r=2k(4Z);d.2M=(8i.T("qq")>=0)?6r:0;d.6B=(4Z.T("qo")>=0)||(4Z.T("j2")>=0)?6r:0;d.3o=(4Z.T("j2")>=0)?6r:0;A j1=8i.T("qn");d.gu=d.7B=((j1>=0)&&(!d.6B))?6r:0;d.j0=0;d.1l=0;d.iV=0;1u{if(d.7B){d.j0=2k(8i.1A("qm/")[1].1A(" ")[0])}if((1q.gx)&&(!d.2M)){d.1l=2k(4Z.1A("qk ")[1].1A(";")[0])}}1y(e){}if(z.1l&&(26.8f.cu==="9q:")){1o.iT=K}d.iX=B(){A 2A;A qj;A cB=d.6q("cz.cy");if(cB){C cB}if(V iZ!="1k"){2A=S iZ()}I{if(d.1l){1u{2A=S 9j("qi.qh")}1y(e){}}I{if(cq.qg["8Z/x-iY"]){2A=1q.a9("8b");2A.cA("Z","8Z/x-iY");2A.cA("3n",0);2A.cA("58",0);2A.1c.gq="7C";1q.5K.4c(2A)}}}if(!2A){C L}z.88("cz.cy.qf",2A);C z.6q("cz.cy")};A iW=d.iX();if(iW){d.iV=K}A cm=1q["aX"];d.qe=(cm=="aW")||(cm=="gr")||(d.1l<6);d.8h=1o.8h||(d.1l?n.qd:n.qc).1M();d.qb=1z.1K;d.cx=["iU.8g","em.8g","iU.8g.4.0"];d.9b=B(){A 4s=L;A cv=L;if(!z.1l||!1o.iT){1u{4s=S qa()}1y(e){}}if(!4s){R(A i=0;i<3;++i){A cw=z.cx[i];1u{4s=S 9j(cw)}1y(e){cv=e}if(4s){z.cx=[cw];3f}}}if(!4s){2m S 1O("8g 3O q9: "+cv)}C 4s};d.8Y=B(iS){A 4Y=iS.3N||0;C((4Y>=q8)&&(4Y0);d.iR=B(1g,iP){A 3K=D.9b();if(!iQ&&z.4r){1g=(S z.4r(26.8f,1g)).2i()}3K.dL("dD",1g,U);1u{3K.dI(L);if(!d.8Y(3K)){A 1G=1O("q2 4F 4E "+1g+" 3N:"+3K.3N);1G.3N=3K.3N;1G.2G=3K.2G;2m 1G}}1y(e){if(iP){C L}2m e}C 3K.2G}})();z.iO=U;z.6o=B(e){z.iO=K;A cr=(e&&e.Z)?e.Z.1M():"4E";if(P.2O.iN||(cr!="q1"&&cr!="4E")){C}P.2O.iN=K;if(V z["8e"]!="1k"){dX(z.8e);63 z.8e}if(z.6p==0){z.iM()}};if(1q.66){if(z.2M||(z.7B&&(1o["q0"]===K))){1q.66("pZ",z.6o,L)}26.66("4E",z.6o,L)}if(/(pY|pX)/i.6Z(cq.iL)){z.8e=dN(B(){if(/6m|iJ/.6Z(1q.6F)){z.6o()}},10)}(B(){A 3g=26;A 8d=B(cp,fp){A iK=3g[cp]||B(){};3g[cp]=B(){fp.14(3g,P);iK.14(3g,P)}};if(z.1l){1q.fJ(""+"");A co=K;8d("iG",B(){3g.5c(B(){co=U},0)});8d("pU",B(){if(co){z.ck()}});1u{1q.pT.2P("v","pS:pR-pQ-pP:pO");1q.pN().pM("v\\\\:*","pL:2E(#aY#pK)")}1y(e){}}I{8d("iG",B(){z.ck()})}})();z.pJ=B(){};z.1e=26["1q"]||L;z.3E=B(){C z.1e.3E||z.1e.4I("3E")[0]};z.ch=B(iF,iE){z.1W=iF;z.1e=iE};z.cf=B(4q,6n,iD){if((6n)&&((V 4q=="3c")||(4q 1N 67))){4q=6n[4q]}C(6n?4q.14(6n,iD||[]):4q())};z.pI=B(cj,iC,iB,iA){A cg;A iz=z.1W;A iy=z.1e;1u{z.ch(cj,cj.1q);cg=z.cf(iC,iB,iA)}ir{z.ch(iz,iy)}C cg};z.pH=B(ix,iw,iv,iu){A ce;A ip=z.1e;1u{z.1e=ix;ce=z.cf(iw,iv,iu)}ir{z.1e=ip}C ce};if(1o["cd"]){R(A cc in 1o["cd"]){z.io(cc,1o["cd"][cc])}}}if(1o.im){if(!1z.ca){z.8c("z.pG.ca")}}}if(!z.1h["z.X.c9"]){z.1h["z.X.c9"]=K;z.1Q("z.X.c9");z.1R=B(it){C(V it=="3c"||it 1N 67)};z.2l=B(it){C(it&&it 1N 4e||V it=="6a"||((V z["1H"]!="1k")&&(it 1N z.1H)))};if(z.c8&&z.3o){z.1Y=B(it){if((V(it)=="B")&&(it=="[8b 1H]")){C U}C(V it=="B"||it 1N bI)}}I{z.1Y=B(it){C(V it=="B"||it 1N bI)}}z.ib=B(it){if(V it=="1k"){C U}C(it===L||V it=="8b"||z.2l(it)||z.1Y(it))};z.pF=B(it){A d=z;if((!it)||(V it=="1k")){C U}if(d.1R(it)){C U}if(d.1Y(it)){C U}if(d.2l(it)){C K}if((it.5w)&&(it.5w.1M()=="3R")){C U}if(pE(it.G)){C K}C U};z.pD=B(it){if(!it){C U}C!z.1Y(it)&&/\\{\\s*\\[il 5h\\]\\s*\\}/.6Z(67(it))};z.c7=B(M,4W){A 8a={};R(A x in 4W){if((V 8a[x]=="1k")||(8a[x]!=4W[x])){M[x]=4W[x]}}if(z.1l){A p=4W.2i;if((V(p)=="B")&&(p!=M.2i)&&(p!=8a.2i)&&(p!="\\pC 2i() {\\n [il 5h]\\n}\\n")){M.2i=4W.2i}}C M};z.1x=B(M,pB){R(A i=1,l=P.G;i2){C z.ig.14(z,P)}if(!3k){3k=2z;2z=L}if(z.1R(3k)){2z=2z||z.1W;if(!2z[3k]){2m(["z.2p: ie[\\"",3k,"\\"] is L (ie=\\"",2z,"\\")"].22(""))}C B(){C 2z[3k].14(2z,P||[])}}I{C(!2z?3k:B(){C 3k.14(2z,P||[])})}};z.6j=B(M,c3){B c4(){};c4.1C=M;A c2=S c4();if(c3){z.1x(c2,c3)}C c2};z.7X=B(pz){A Q=[L];C z.2p.14(z,Q.3U(z.4d(P)))};z.4d=B(M,ic){A Q=[];R(A x=ic||0;x3)){z.ia("z.2r: R 9P \'"+6l+"\' py pw B as \'1P\' pv pu of as a pt i3.","","1.0");A c=3j;3j=P[3]||{};3j.1P=c}A dd=P.2O,4V=L;if(z.2l(4p)){4V=4p;4p=4V.3a()}if(4V){R(A i=0,m;i<4V.G;i++){m=4V[i];if(!m){2m("ps #"+i+" 4F pr of "+6l+" is L. pq\'s pp a po pl is 3O 6m.")}4p=dd.6j(4p,m)}}A i9=(3j||0).1P,6k=dd.6j(4p),fn;R(A i in 3j){if(z.1Y(fn=3j[i])&&(!0[i])){fn.i4=i}}z.4M(6k,{4o:6l,bY:i9,bZ:L},3j||0);6k.1C.1P=6k;C z.88(6l,6k)};z.1x(z.2r,{6j:B(c0,i8){A bp=(c0||0).1C,mp=(i8||0).1C;A 2S=z.2r.i7();z.1x(2S,{84:bp,1x:mp});if(c0){2S.1C=z.6j(bp)}z.4M(2S,z.2r.i6,mp||0,{bY:L});2S.1C.1P=2S;2S.1C.4o=(bp||0).4o+"pk"+(mp||0).4o;z.88(2S.1C.4o,2S);C 2S},i7:B(){C B(){D.i5(P)}},i6:{i5:B(86){A c=86.2O,s=c.84,ct=s&&s.1P,m=c.1x,87=m&&m.1P,a=86,ii,fn;if(a[0]){if((fn=a[0]["bZ"])){a=fn.14(D,a)||a}}if(fn=c.1C.bZ){a=fn.14(D,a)||a}if(ct&&ct.14){ct.14(D,a)}if(87&&87.14){87.14(D,a)}if(ii=c.1C.bY){ii.14(D,86)}},bX:B(85){A c=D.1P,p,m;1s(c){p=c.84;m=c.1x;if(m==85||(m 1N 85.1P)){C p}if(m&&(m=m.bX(85))){C m}c=p&&p.1P}},6h:B(83,82,bW,6i){A p=bW,c,m,f;do{c=p.1P;m=c.1x;if(m&&(m=D.6h(83,82,m,6i))){C m}if((f=p[83])&&(6i==(f==82))){C p}p=c.84}1s(p);C!6i&&(p=D.bX(bW))&&D.6h(83,82,p,6i)},bU:B(2R,4U,bV){A a=P;if(!z.1R(a[0])){bV=4U;4U=2R;2R=4U.2O.i4}A c=4U.2O,p=D.1P.1C,a=bV||4U,fn,mp;if(D[2R]!=c||p[2R]==c){mp=D.6h(2R,c,p,K);if(!mp){2m(D.4o+": 1p i3 (\\""+2R+"\\") 4F bU pj 1f 2O (2r.js)")}p=D.6h(2R,c,mp,U)}fn=p&&p[2R];if(!fn){1z.1K(mp.4o+": no bU \\""+2R+"\\" ph pg (2r.js)");C}C fn.14(D,a)}}})}if(!z.1h["z.X.2c"]){z.1h["z.X.2c"]=K;z.1Q("z.X.2c");z.3i={i2:B(){C B(){A ap=4e.1C,c=P.2O,ls=c.2b,t=c.5V;A r=t&&t.14(D,P);R(A i in ls){if(!(i in ap)){ls[i].14(D,P)}}C r}},2P:B(6g,bT,i1){6g=6g||z.1W;A f=6g[bT];if(!f||!f.2b){A d=z.3i.i2();d.5V=f;d.2b=[];f=6g[bT]=d}C f.2b.Y(i1)},3J:B(i0,hZ,bS){A f=(i0||z.1W)[hZ];if(f&&f.2b&&bS--){63 f.2b[bS]}}};z.2c=B(M,pd,pc,pa,p9){A a=P,F=[],i=0;F.Y(z.1R(a[0])?L:a[i++],a[i++]);A a1=a[i+1];F.Y(z.1R(a1)||z.1Y(a1)?a[i++]:L,a[i++]);R(A l=a.G;i2){6e=z.7X(6e,P,2)}C D.5k(6e,6e)},ef:B(cb,4T){A 7Y=z.2p(cb,4T);if(P.G>2){7Y=z.7X(7Y,P,2)}C D.5k(7Y,L)},ed:B(cb,4T){A 7W=z.2p(cb,4T);if(P.G>2){7W=z.7X(7W,P,2)}C D.5k(L,7W)},5k:B(cb,eb){D.bM.Y([cb,eb]);if(D.2y>=0){D.7U()}C D},7U:B(){A bL=D.bM;A 4n=D.2y;A 1v=D.4R[4n];A 4S=D;A cb=L;1s((bL.G>0)&&(D.3M==0)){A f=bL.3a()[4n];if(!f){6c}1u{1v=f(1v);4n=((1v 1N 1O)?1:0);if(1v 1N z.30){cb=B(1v){4S.7V(1v);4S.3M--;if((4S.3M==0)&&(4S.2y>=0)){4S.7U()}};D.3M++}}1y(1G){1z.1K(1G);4n=1;1v=1G}}D.2y=4n;D.4R[4n]=1v;if((cb)&&(D.3M)){1v.9e(cb)}}})}if(!z.1h["z.X.2e"]){z.1h["z.X.2e"]=K;z.1Q("z.X.2e");z.5m=B(2e){1u{C 3u("("+2e+")")}1y(e){1z.1K(e);C 2e}};z.bK=B(2H){C("\\""+2H.2f(/(["\\\\])/g,"\\\\$1")+"\\"").2f(/[\\f]/g,"\\\\f").2f(/[\\b]/g,"\\\\b").2f(/[\\n]/g,"\\\\n").2f(/[\\t]/g,"\\\\t").2f(/[\\r]/g,"\\\\r")};z.hM="\\t";z.eq=B(it,4l,4P){4P=4P||"";A 4k=(4l?4P+z.hM:"");A 6b=(4l?"\\n":"");A 4Q=V(it);if(4Q=="1k"){C"1k"}I{if((4Q=="4J")||(4Q=="p1")){C it+""}I{if(it===L){C"L"}}}if(4Q=="3c"){C z.bK(it)}A 6d=P.2O;A 4m;if(V it.hL=="B"){4m=it.hL();if(it!==4m){C 6d(4m,4l,4k)}}if(V it.2e=="B"){4m=it.2e();if(it!==4m){C 6d(4m,4l,4k)}}if(z.2l(it)){A 1v=[];R(A i=0;i>=7R;t[x]=7R==4?17*c:c});t.a=1;C t};z.7P=B(a,M){A t=M||S z.1J();t.bz(2V(a[0]),2V(a[1]),2V(a[2]),2V(a[3]));if(2L(t.a)){t.a=1}C t.7Q()};z.hq=B(2H,M){A a=z.1J.hp[2H];C a&&z.7P(a,M)||z.ho(2H,M)||z.hn(2H,M)}}if(!z.1h["z.X"]){z.1h["z.X"]=K;z.1Q("z.X")}if(!z.1h["z.X.5Z"]){z.1h["z.X.5Z"]=K;z.1Q("z.X.5Z");(B(){A 1j=z.b2={2P:B(E,68,fp){if(!E){C}68=1j.4O(68);fp=1j.7G(68,fp);E.66(68,fp,U);C fp},3J:B(E,hm,hl){(E)&&(E.oF(1j.4O(hm),hl,U))},4O:B(1p){C(1p.2w(0,2)=="on"?1p.2w(2):1p)},7G:B(1p,fp){C(1p!="4b"?fp:B(e){C fp.2d(D,1j.4i(e,D))})},4i:B(H,oE){4w(H.Z){2X"4b":1j.7K(H);3f}C H},7K:B(H){H.oD=(H.3h?67.oC(H.3h):"")}};z.oB=B(H,hk){C 1j.4i(H,hk)};z.gY=B(H){H.7J();H.7I()};A 7O=z.3i;z.by=B(M,bx,hh,hg,hi){A hj=M&&(M.2t||M.oA||M.66);A bw=!hj?0:(!hi?1:2),l=[z.3i,1j,7O][bw];A h=l.2P(M,bx,z.2p(hh,hg));C[M,bx,h,bw]};z.bv=B(M,he,hd,hf){([z.3i,1j,7O][hf]).3J(M,he,hd)};z.5W={oz:8,gV:9,oy:12,ox:13,ow:16,ov:17,ou:18,gG:19,ot:20,os:27,or:32,b5:33,b4:34,gE:35,gF:36,b7:37,b9:38,b6:39,b8:40,gD:45,8S:46,oq:47,oo:91,om:92,ol:93,oj:96,oi:97,oh:98,og:99,oe:6D,od:oc,ob:oa,o9:o8,o7:o6,o5:o4,o3:bi,o2:o1,o0:nZ,nY:nX,nW:nV,nU:bk,gS:nT,gR:nS,gQ:nR,gP:nQ,gO:nP,gN:nO,gM:nN,gL:nM,gK:nL,gJ:nK,gI:nJ,gH:nI,nH:nG,nF:nE,nD:nC,gB:nB,gC:nA};if(z.1l){bf=B(e,5h){1u{C(e.3I=5h)}1y(e){C 0}};A 61=z.3i;if(!1o.nz){7O=61=z.gy={b3:[],2P:B(64,bu,hc){64=64||z.1W;A f=64[bu];if(!f||!f.2b){A d=z.gz();d.5V=f&&(7M.Y(f)-1);d.2b=[];f=64[bu]=d}C f.2b.Y(7M.Y(hc)-1)},3J:B(hb,ha,7N){A f=(hb||z.1W)[ha],l=f&&f.2b;if(f&&l&&7N--){63 7M[l[7N]];63 l[7N]}}};A 7M=61.b3}z.1x(1j,{2P:B(E,62,fp){if(!E){C}62=1j.4O(62);if(62=="h3"){A kd=E.bs;if(!kd||!kd.2b||!kd.h9){1j.2P(E,"bs",1j.h4);E.bs.h9=K}}C 61.2P(E,62,1j.7G(fp))},3J:B(E,h8,h7){61.3J(E,1j.4O(h8),h7)},4O:B(7L){C(7L.2w(0,2)!="on"?"on"+7L:7L)},ny:B(){},4i:B(H,4N){if(!H){A w=(4N)&&((4N.aD||4N.1q||4N).nx)||26;H=w.5Z}if(!H){C(H)}H.5V=H.br;H.bh=(4N||H.br);H.nw=H.nv;H.nu=H.nr;A bq=H.br,1e=(bq&&bq.aD)||1q;A bn=((z.1l<6)||(1e["aX"]=="aW"))?1e.3E:1e.5K;A bm=z.aB();H.nq=H.np+z.aH(bn.5I||0)-bm.x;H.nn=H.nm+(bn.5G||0)-bm.y;if(H.Z=="fk"){H.h6=H.nl}if(H.Z=="fj"){H.h6=H.nk}H.7I=1j.bc;H.7J=1j.ba;C 1j.h5(H)},h5:B(H){4w(H.Z){2X"4b":A c=("3h"in H?H.3h:H.3I);if(c==10){c=0;H.3I=13}I{if(c==13||c==27){c=0}I{if(c==3){c=99}}}H.3h=c;1j.7K(H);3f}C H},gZ:{bi:42,bk:47,h2:59,nj:43,ni:44,nh:45,ng:46,nf:47,60:96,h1:91,nb:92,na:93,h0:39},h4:B(H){A kp=H.bh.h3;if(!kp||!kp.2b){C}A k=H.3I;A bj=(k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>bk)&&(k60)&&(kh0);if(bj||H.5Y){A c=(bj?0:k);if(H.5Y){if(k==3||k==13){C}I{if(c>95&&c=65&&c<=90)){c+=32}I{c=1j.gZ[c]||c}}}}A 2x=1j.7H(H,{Z:"4b",2x:K,3h:c});kp.2d(H.bh,2x);H.bg=2x.bg;H.bd=2x.bd;bf(H,2x.3I)}},bc:B(){D.bg=K},ba:B(){D.n9=D.3I;if(D.5Y){bf(D,0)}D.bd=U}});z.gY=B(H){H=H||26.5Z;1j.bc.2d(H);1j.ba.2d(H)}}1j.7H=B(H,gX){A 2x=z.1x({},H,gX);1j.7K(2x);2x.7J=B(){H.7J()};2x.7I=B(){H.7I()};C 2x};if(z.2M){z.1x(1j,{4i:B(H,n8){4w(H.Z){2X"4b":A c=H.n7;if(c==3){c=99}c=((c<41)&&(!H.5X)?0:c);if((H.5Y)&&(!H.5X)&&(c>=65)&&(c<=90)){c+=32}C 1j.7H(H,{3h:c})}C H}})}if(z.3o){z.1x(1j,{4i:B(H,n6){4w(H.Z){2X"4b":A c=H.3h,s=H.5X,k=H.3I;k=k||gA[H.gW]||0;if(H.gW=="n5"){c=0}I{if((H.5Y)&&(c>0)&&(c<27)){c+=96}I{if(c==z.5W.gU){c=z.5W.gV;s=K}I{c=(c>=32&&c gh",E).1n(B(i){i.1c.7E=i.1c.7E.2f(/gk:[^;]*;/i,"")})}}I{A o="mh(mg="+(7D*6D)+")";E.1c.3T=o}if(E.gj.1M()=="gi"){z.1r("> gh",E).1n(B(i){i.1c.3T=o})}C 7D}:B(E,gg){C E.1c.2W=gg});A 5Q={3n:K,58:K,2g:K,5J:K};A gd=B(E,Z,5P){Z=Z.1M();if(5Q[Z]===K){C z.4g(E,5P)}I{if(5Q[Z]===U){C 5P}I{if((Z.T("mf")>=0)||(Z.T("md")>=0)||(Z.T("3n")>=0)||(Z.T("58")>=0)||(Z.T("5q")>=0)||(Z.T("mc")>=0)||(Z.T("ma")>=0)){5Q[Z]=K;C z.4g(E,5P)}I{5Q[Z]=U;C 5P}}}};z.1c=B(E,5O,aT){A n=z.1D(E),F=P.G,op=(5O=="2W");if(F==3){C op?z.gf(n,aT):n.1c[5O]=aT}if(F==2&&op){C z.ge(n)}A s=z.3F(n);C(F==1)?s:gd(n,5O,s[5O])};z.7A=B(n,gc){A s=gc||1E(n),px=z.4g,l=px(n,s.m9),t=px(n,s.m8);C{l:l,t:t,w:l+px(n,s.m7),h:t+px(n,s.m6)}};z.5N=B(n,gb){A ne="7C",px=z.4g,s=gb||1E(n),bl=(s.m5!=ne?px(n,s.m4):0),bt=(s.m3!=ne?px(n,s.m2):0);C{l:bl,t:bt,w:bl+(s.m1!=ne?px(n,s.m0):0),h:bt+(s.lZ!=ne?px(n,s.lY):0)}};z.aN=B(n,ga){A s=ga||1E(n),p=z.7A(n,s),b=z.5N(n,s);C{l:p.l+b.l,t:p.t+b.t,w:p.w+b.w,h:p.h+b.h}};z.aM=B(n,g9){A s=g9||1E(n),px=z.4g,l=px(n,s.lX),t=px(n,s.lW),r=px(n,s.lV),b=px(n,s.lU);if(z.3o&&(s.ax!="fU")){r=l}C{l:l,t:t,w:l+r,h:t+b}};z.au=B(E,g8){A s=g8||1E(E),me=z.aM(E,s);A l=E.fT-me.l,t=E.fS-me.t;if(z.7B){A aS=2k(s.2g),aR=2k(s.5J);if(!2L(aS)&&!2L(aR)){l=aS,t=aR}I{A p=E.1L;if(p&&p.1c){A aQ=1E(p);if(aQ.lT!="lS"){A be=z.5N(p,aQ);l+=be.l,t+=be.t}}}}I{if(z.2M){A p=E.1L;if(p){A be=z.5N(p);l-=be.l,t-=be.t}}}C{l:l,t:t,w:E.6v+me.w,h:E.8D+me.h}};z.aK=B(E,g7){A s=g7||1E(E),pe=z.7A(E,s),be=z.5N(E,s),w=E.aF,h;if(!w){w=E.6v,h=E.8D}I{h=E.lR,be.w=be.h=0}if(z.2M){pe.l+=be.l;pe.t+=be.t}C{l:pe.l,t:pe.t,w:w-pe.w-be.w,h:h-pe.h-be.h}};z.lQ=B(E,g6){A s=g6||1E(E),pe=z.7A(E,s),cb=z.aK(E,s);C{l:cb.l-pe.l,t:cb.t-pe.t,w:cb.w+pe.w,h:cb.h+pe.h}};z.aL=B(E,l,t,w,h,u){u=u||"px";4G(E.1c){if(!2L(l)){2g=l+u}if(!2L(t)){5J=t+u}if(w>=0){3n=w+u}if(h>=0){58=h+u}}};z.aO=B(E){A n=E.5w;C(z.aP=="g5-3G")||(n=="lP")||(n=="lO")};z.fX=B(E,7z,7y,g4){A bb=z.aO(E);if(bb){A pb=z.aN(E,g4);if(7z>=0){7z+=pb.w}if(7y>=0){7y+=pb.h}}z.aL(E,g3,g3,7z,7y)};z.fY=B(E,g1,g0,5M,5L,g2){A s=g2||z.3F(E);A bb=z.aO(E),pb=bb?fZ:z.aN(E,s),mb=z.aM(E,s);if(5M>=0){5M=2Y.5q(5M-pb.w-mb.w,0)}if(5L>=0){5L=2Y.5q(5L-pb.h-mb.h,0)}z.aL(E,g1,g0,5M,5L)};A fZ={l:0,t:0,w:0,h:0};z.lN=B(E,3G){A n=z.1D(E),s=1E(n),b=3G;C!b?z.au(n,s):z.fY(n,b.l,b.t,b.w,b.h,s)};z.lM=B(E,3G){A n=z.1D(E),s=1E(n),b=3G;C!b?z.aK(n,s):z.fX(n,b.w,b.h,s)};A 5H=B(E,1a){if(!(E=(E||0).1L)){C 0}A 1U,aJ=0,2h=z.3E();1s(E&&E.1c){if(1E(E).ax=="lL"){C 0}1U=E[1a];if(1U){aJ+=1U-0;if(E==2h){3f}}E=E.1L}C aJ};z.fQ=B(){A 2h=z.3E();A 3g=z.1W;A de=z.1e.5K;C{y:(3g.lK||de.5G||2h.5G||0),x:(3g.lJ||z.aH(de.5I)||2h.5I||0)}};z.aG=B(){C V z.aI=="1k"?(z.aI=z.3F(z.3E()).lI=="lH"):z.aI};z.aB=B(){A de=z.1e.5K;if(z.1l>=7){C{x:de.aC().2g,y:de.aC().5J}}I{C{x:z.aG()||26.am==26?de.fW:de.6v-de.aF-de.fW,y:de.lG}}};z.aH=B(aE){if(z.1l&&!z.aG()){A de=z.1e.5K;C aE+de.aF-de.lF}C aE};z.fP=B(E,aw){A ay=E.aD;A J={x:0,y:0};A 7w=U;A db=z.3E();if(z.1l){A aA=E.aC();A az=z.aB();J.x=aA.2g-az.x;J.y=aA.5J-az.y}I{if(ay["fV"]){A bo=ay.fV(E);J.x=bo.x-5H(E,"5I");J.y=bo.y-5H(E,"5G")}I{if(E["fR"]){7w=K;A 7x;if(z.3o&&(1E(E).ax=="fU")&&(E.1L==db)){7x=db}I{7x=db.1L}if(E.1L!=db){A nd=E;if(z.2M){nd=db}J.x-=5H(nd,"5I");J.y-=5H(nd,"5G")}A 4f=E;do{A n=4f["fT"];if(!z.2M||n>0){J.x+=2L(n)?0:n}A m=4f["fS"];J.y+=2L(m)?0:m;4f=4f.fR}1s((4f!=7x)&&4f)}I{if(E["x"]&&E["y"]){J.x+=2L(E.x)?0:E.x;J.y+=2L(E.y)?0:E.y}}}}if(7w||aw){A av=z.fQ();A m=7w?(!aw?-1:0):1;J.y+=m*av.y;J.x+=m*av.x}C J};z.af=B(E,fO){A n=z.1D(E),s=1E(n),mb=z.au(n,s);A at=z.fP(n,fO);mb.x=at.x;mb.y=at.y;C mb}})();z.fL=B(E,fN){C((" "+E.3A+" ").T(" "+fN+" ")>=0)};z.7s=B(E,ar){A 7v=E.3A;if((" "+7v+" ").T(" "+ar+" ")<0){E.3A=7v+(7v?" ":"")+ar}};z.7r=B(E,fM){A t=z.7g((" "+E.3A+" ").2f(" "+fM+" "," "));if(E.3A!=t){E.3A=t}};z.lE=B(E,aq,7u){if(V 7u=="1k"){7u=!z.fL(E,aq)}z[7u?"7s":"7r"](E,aq)}}if(!z.1h["z.X.1H"]){z.1h["z.X.1H"]=K;z.1Q("z.X.1H");(B(){A d=z;z.1H=B(){A F=P;if((F.G==1)&&(V F[0]=="4J")){D.G=eK(F[0])}I{if(F.G){d.1n(F,B(i){D.Y(i)},D)}}};z.1H.1C=S 4e;if(d.1l){A fK=B(al){C("A a2 = am."+al+"; "+"A ap = 4e.1C; "+"A ao = a2.1C; "+"R(A x in ao){ ap[x] = ao[x]; } "+"am."+al+" = 4e; ")};A fI=fK("z.1H");A aj=26.lD();aj.1q.fJ(""+fI+"");aj.lC(1,1,1,1)}z.4M(z.1H,{T:B(fH,fG){C d.T(D,fH,fG)},31:B(lB,lA){A aa=d.4d(P);aa.ae(D);C d.31.14(d,aa)},ah:B(fF,fE){C d.ah(D,fF,fE)},ag:B(fD,fC){C d.ag(D,fD,fC)},1n:B(fB,fA){d.1n(D,fB,fA);C D},23:B(7t,M){C d.23(D,7t,M,d.1H)},af:B(){C d.23(D,d.af)},1c:B(lz,ly){A aa=d.4d(P);aa.ae(D[0]);A s=d.1c.14(d,aa);C(P.G>1)?D:s},lx:B(lw,lv){A aa=d.4d(P);aa.ae(L);A s=D.23(B(i){aa[0]=i;C d.1c.14(d,aa)});C(P.G>1)?D:s},7s:B(fz){C D.1n(B(i){z.7s(i,fz)})},7r:B(fy){C D.1n(B(i){z.7r(i,fy)})},5E:B(fw,7q){A 1m=d.1r(fw)[0];7q=7q||"72";R(A x=0;x=0){if(i[x]<1d){1d=i[x]}}}C(1d<0)?ql:1d};A 6X=B(7l){A i=2I(7l);if(i[0]!=-1){C 7l.21(i[0]+1,a0(7l,1))}I{C""}};A 5r=B(7k){A 5D;A i=2I(7k);if((i[0]==0)||(i[1]==0)){5D=0}I{5D=a0(7k,0)}C((5D>0)?7k.3b(0,5D).1M():"*")};A fg=B(Q){A J=-1;R(A x=0;x=0){if((1S>J)||(J==-1)){J=1S}}}C J};A 9H=B(7i){A i=2I(7i);if(-1==i[1]){C""}A di=i[1]+1;A 7j=fg(i.2w(2));if(di<7j){C 7i.21(di,7j)}I{if(-1==7j){C 7i.3b(di)}I{C""}}};A f3=[{1i:"|=",1f:B(15,fe){C"[5z(3U(\' \',@"+15+",\' \'), \' "+fe+"-\')]"}},{1i:"~=",1f:B(15,fd){C"[5z(3U(\' \',@"+15+",\' \'), \' "+fd+" \')]"}},{1i:"^=",1f:B(15,fb){C"[li-4G(@"+15+", \'"+fb+"\')]"}},{1i:"*=",1f:B(15,fa){C"[5z(@"+15+", \'"+fa+"\')]"}},{1i:"$=",1f:B(15,9Z){C"[21(@"+15+", 3c-G(@"+15+")-"+(9Z.G-1)+")=\'"+9Z+"\']"}},{1i:"!=",1f:B(15,f9){C"[3O(@"+15+"=\'"+f9+"\')]"}},{1i:"=",1f:B(15,f8){C"[@"+15+"=\'"+f8+"\']"}}];A 9C=B(9Y,3Z,f7,f6){A 49;A i=2I(3Z);if(i[2]>=0){A 4L=3Z.T("]",i[2]);A 29=3Z.21(i[2]+1,4L);1s(29&&29.G){if(29.2s(0)=="@"){29=29.2w(1)}49=L;R(A x=0;x<9Y.G;x++){A 1S=9Y[x];A 7h=29.T(1S.1i);if(7h>=0){A 15=29.21(0,7h);A 4a=29.21(7h+1S.1i.G);if((4a.2s(0)=="\\"")||(4a.2s(0)=="\'")){4a=4a.21(1,4a.G-1)}49=1S.1f(d.7g(15),d.7g(4a));3f}}if((!49)&&(29.G)){49=f7(29)}if(49){f6(49)}29=L;A 7f=3Z.T("[",4L);if(0<=7f){4L=3Z.T("]",7f);if(0<=4L){29=3Z.21(7f+1,4L)}}}}};A f0=B(f5){A 4K=".";A 7e=f5.1A(" ");1s(7e.G){A 2K=7e.3a();A 7d;if(2K==">"){7d="/";2K=7e.3a()}I{7d="//"}A f4=5r(2K);4K+=7d+f4;A id=6X(2K);if(id.G){4K+="[@id=\'"+id+"\'][1]"}A cn=9H(2K);if(cn.G){A 9X=" ";if(cn.2s(cn.G-1)=="*"){9X="";cn=cn.3b(0,cn.G-1)}4K+="[5z(3U(\' \',@9P,\' \'), \' "+cn+9X+"\')]"}9C(f3,2K,B(f2){C"[@"+f2+"]"},B(f1){4K+=f1})}C 4K};A 7a={};A eC=B(28){if(7a[28]){C 7a[28]}A 1e=d.1e;A 9W=f0(28);A 4H=B(9V){A J=[];A 7b;1u{7b=1e.9x(9W,9V,L,lh.lg,L)}1y(e){1z.1K("lf in le:",9W,"lc:",9V);1z.1K(e)}A 7c=7b.eZ();1s(7c){J.Y(7c);7c=7b.eZ()}C J};C 7a[28]=4H};A 5x={};A 9B={};A 3y=B(79,78){if(!79){C 78}if(!78){C 79}C B(){C 79.14(26,P)&&78.14(26,P)}};A 75=B(9U,3Y,5B,2J){A 2v=2J+1;A 76=(3Y.G==2v);A 2K=3Y[2J];if(2K==">"){A 77=9U.3W;if(!77.G){C}2v++;76=(3Y.G==2v);A 4H=6O(3Y[2J+1]);R(A x=0,11;x<77.G,11=77[x];x++){if(4H(11)){if(76){5B.Y(11)}I{75(11,3Y,5B,2v)}}}}A 5C=6U(2K)(9U);if(76){1s(5C.G){5B.Y(5C.3a())}}I{1s(5C.G){75(5C.3a(),3Y,5B,2v)}}};A eE=B(9T,eY){A J=[];A x=9T.G-1,11;1s(11=9T[x--]){75(11,eY,J,0)}C J};A 6O=B(3D){if(5x[3D]){C 5x[3D]}A ff=L;A 9S=5r(3D);if(9S!="*"){ff=3y(ff,B(N){C((N.2t==1)&&(9S==N.5w.1M()))})}A 9R=6X(3D);if(9R.G){ff=3y(ff,B(N){C((N.2t==1)&&(N.id==9R))})}if(2Y.5q.14(D,2I(3D).2w(1))>=0){ff=3y(ff,9z(3D))}C 5x[3D]=ff};A 5y=B(E){A pn=E.1L;A 9Q=pn.3W;A 2v=-1;A 3C=pn.5A;if(!3C){C 2v}A ci=E["eW"];A cl=pn["eX"];if(((V cl=="4J")&&(cl!=9Q.G))||(V ci!="4J")){pn["eX"]=9Q.G;A 2J=1;do{if(3C===E){2v=2J}if(3C.2t==1){3C["eW"]=2J;2J++}3C=3C.71}1s(3C)}I{2v=ci}C 2v};A lb=0;A 3X=B(N,15){A 74="";if(15=="9P"){C N.3A||74}if(15=="R"){C N.la||74}C N.5t(15,2)||74};A eH=[{1i:"|=",1f:B(15,9O){A eV=" "+9O+"-";C B(N){A ea=" "+(N.5t(15,2)||"");C((ea==9O)||(ea.T(eV)==0))}}},{1i:"^=",1f:B(15,eU){C B(N){C(3X(N,15).T(eU)==0)}}},{1i:"*=",1f:B(15,eT){C B(N){C(3X(N,15).T(eT)>=0)}}},{1i:"~=",1f:B(15,eS){A 9N=" "+eS+" ";C B(N){A ea=" "+3X(N,15)+" ";C(ea.T(9N)>=0)}}},{1i:"$=",1f:B(15,73){A 9N=" "+73;C B(N){A ea=" "+3X(N,15);C(ea.31(73)==(ea.G-73.G))}}},{1i:"!=",1f:B(15,eR){C B(N){C(3X(N,15)!=eR)}}},{1i:"=",1f:B(15,eQ){C B(N){C(3X(N,15)==eQ)}}}];A 9E=[{1i:"9M-9K",1f:B(1p,l9){C B(N){if(N.2t!=1){C U}A fc=N.eP;1s(fc&&(fc.2t!=1)){fc=fc.eP}C(!fc)}}},{1i:"72-9K",1f:B(1p,l8){C B(N){if(N.2t!=1){C U}A nc=N.71;1s(nc&&(nc.2t!=1)){nc=nc.71}C(!nc)}}},{1i:"l7",1f:B(1p,l6){C B(N){A cn=N.3W;A eO=N.3W.G;R(A x=eO-1;x>=0;x--){A nt=cn[x].2t;if((nt==1)||(nt==3)){C U}}C K}}},{1i:"5z",1f:B(1p,eN){C B(N){C(N.9L.T(eN)>=0)}}},{1i:"3O",1f:B(1p,eM){A eL=6O(eM);C B(N){C(!eL(N))}}},{1i:"l5-9K",1f:B(1p,2u){A pi=eK;if(2u=="l4"){C B(N){C(((5y(N))%2)==1)}}I{if((2u=="2n")||(2u=="l3")){C B(N){C((5y(N)%2)==0)}}I{if(2u.T("l2+")==0){A 70=pi(2u.3b(3));C B(N){C(N.1L.3W[70-1]===N)}}I{if((2u.T("n+")>0)&&(2u.G>3)){A 9J=2u.1A("n+",2);A eJ=pi(9J[0]);A 2J=pi(9J[1]);C B(N){C((5y(N)%eJ)==2J)}}I{if(2u.T("n")==-1){A 70=pi(2u);C B(N){C(5y(N)==70)}}}}}}}}];A 9z=B(3e){A 9I=(9B[3e]||5x[3e]);if(9I){C 9I}A ff=L;A i=2I(3e);if(i[0]>=0){A 24=5r(3e);if(24!="*"){ff=3y(ff,B(N){C(N.5w.1M()==24)})}}A 5u;A 3B=9H(3e);if(3B.G){A 9F=3B.2s(3B.G-1)=="*";if(9F){3B=3B.3b(0,3B.G-1)}A re=S 9G("(?:^|\\\\s)"+3B+(9F?".*":"")+"(?:\\\\s|$)");ff=3y(ff,B(N){C re.6Z(N.3A)})}if(i[3]>=0){A 3z=3e.3b(i[3]+1);A 9D="";A 5v=3z.T("(");A 6Y=3z.31(")");if((0<=5v)&&(0<=6Y)&&(6Y>5v)){9D=3z.21(5v+1,6Y);3z=3z.3b(0,5v)}5u=L;R(A x=0;x<9E.G;x++){A 1S=9E[x];if(1S.1i==3z){5u=1S.1f(3z,9D);3f}}if(5u){ff=3y(ff,5u)}}A eG=(d.1l)?B(5s){A eI=5s.1M();C B(N){C N[5s]||N[eI]}}:B(5s){C B(N){C(N&&N.5t&&N.l1(5s))}};9C(eH,3e,eG,B(eF){ff=3y(ff,eF)});if(!ff){ff=B(){C K}}C 9B[3e]=ff};A 6W={};A 6U=B(3d,1B){A 9A=6W[3d];if(9A){C 9A}A i=2I(3d);A id=6X(3d);if(i[0]==0){C 6W[3d]=B(1B){C[d.1D(id)]}}A 9y=9z(3d);A 5p;if(i[0]>=0){5p=B(1B){A 11=d.1D(id);if(9y(11)){C[11]}}}I{A 3V;A 24=5r(3d);if(2Y.5q.14(D,2I(3d))==-1){5p=B(1B){A J=[];A 11,x=0,3V=1B.4I(24);1s(11=3V[x++]){J.Y(11)}C J}}I{5p=B(1B){A J=[];A 11,x=0,3V=1B.4I(24);1s(11=3V[x++]){if(9y(11)){J.Y(11)}}C J}}}C 6W[3d]=5p};A l0={};A 5o={">":B(1B){A J=[];A 11,x=0,3V=1B.3W;1s(11=3V[x++]){if(11.2t==1){J.Y(11)}}C J}};A 9w=B(6V){if(0>6V.T(" ")){C 6U(6V)}A eD=B(1B){A 6S=6V.1A(" ");A 6T;if(6S[0]==">"){6T=[1B]}I{6T=6U(6S.3a())(1B)}C eE(6T,6S)};C eD};A 9v=((1q["9x"]&&!d.3o)?B(3x){A 6R=3x.1A(" ");if((1q["9x"])&&(3x.T(":")==-1)&&((K))){if(((6R.G>2)&&(3x.T(">")==-1))||(6R.G>3)||(3x.T("[")>=0)||((1==6R.G)&&(0<=3x.T(".")))){C eC(3x)}}C 9w(3x)}:9w);A ey=B(3w){if(5o[3w]){C 5o[3w]}if(0>3w.T(",")){C 5o[3w]=9v(3w)}I{A eB=3w.1A(/\\s*,\\s*/);A 4H=B(1B){A eA=0;A J=[];A 6Q;1s(6Q=eB[eA++]){J=J.3U(9v(6Q,6Q.T(" "))(1B))}C J};C 5o[3w]=4H}};A 5n=0;A ez=B(Q){A J=S d.1H();if(!Q){C J}if(Q[0]){J.Y(Q[0])}if(Q.G<2){C J}5n++;Q[0]["9u"]=5n;R(A x=1,11;11=Q[x];x++){if(Q[x]["9u"]!=5n){J.Y(11)}11["9u"]=5n}C J};d.1r=B(6P,1B){if(V 6P!="3c"){C S d.1H(6P)}if(V 1B=="3c"){1B=d.1D(1B)}C ez(ey(6P)(1B||d.1e))};d.9t=B(ex,9s){A 9r=S d.1H();A ff=(9s)?6O(9s):B(){C K};R(A x=0,11;11=ex[x];x++){if(ff(11)){9r.Y(11)}}C 9r}})()}if(!z.1h["z.X.1b"]){z.1h["z.X.1b"]=K;z.1Q("z.X.1b");z.6K=B(ew){A J={};A iq="kZ[Z!=9q][Z!=kY][Z!=et][Z!=kX][Z!=kW], kV, kU";z.1r(iq,ew).3T(B(E){C(!E.kT)}).1n(B(1m){A 3v=1m.1p;A Z=(1m.Z||"").1M();if((Z=="kS")||(Z=="kR")){if(1m.kQ){J[3v]=1m.1Z}}I{if(1m.kP){A ev=J[3v]=[];z.1r("kO[kN]",1m).1n(B(eu){ev.Y(eu.1Z)})}I{J[3v]=1m.1Z;if(Z=="et"){J[3v+".x"]=J[3v+".y"]=J[3v].x=J[3v].y=0}}}});C J};z.9h=B(23){A ec=kM;A J="";A es={};R(A x in 23){if(23[x]!=es[x]){if(z.2l(23[x])){R(A y=0;y<23[x].G;y++){J+=ec(x)+"="+ec(23[x][y])+"&"}}I{J+=ec(x)+"="+ec(23[x])+"&"}}}if((J.G)&&(J.2s(J.G-1)=="&")){J=J.3b(0,J.G-1)}C J};z.kL=B(er){C z.9h(z.6K(er))};z.kK=B(ep){C z.eq(z.6K(ep))};z.kJ=B(2H){A J={};A qp=2H.1A("&");A dc=kI;z.1n(qp,B(1m){if(1m.G){A 9p=1m.1A("=");A 1p=dc(9p.3a());A 1U=dc(9p.22("="));if(z.1R(J[1p])){J[1p]=[J[1p]]}if(z.2l(J[1p])){J[1p].Y(1U)}I{J[1p]=1U}}});C J};z.e1=U;z.e6={"9g":B(1b){C 1b.2G},"2e":B(1b){if(!1o.eo){1z.1K("kH kG kF a kE of 9g/2e-6M-9m"+" 4F kD kC kB kA 4G en kz"+" (ky 1o.eo=K 4F kx kw D kv)")}C z.5m(1b.2G)},"2e-6M-ku":B(1b){A 6N=1b.2G;A 9o=6N.T("/*");A 9n=6N.31("*/");if((9o==-1)||(9n==-1)){C z.5m(1b.2G)}C z.5m(6N.21(9o+2,9n))},"2e-6M-9m":B(1b){A 6L=1b.2G;A 9l=6L.T("/*");A 9k=6L.31("*/");if((9l==-1)||(9k==-1)){1z.1K("kt en ks\'t 6M 9m!");C""}C z.5m(6L.21(9l+2,9k))},"kr":B(1b){C z.3u(1b.2G)},"kq":B(1b){if(z.1l&&!1b.el){z.1n(["ko","em","kn","km"],B(i){1u{A 1e=S 9j(kl[i]+".kk");1e.kj=U;1e.ki(1b.2G);C 1e}1y(e){}})}I{C 1b.el}}};(B(){z.e5=B(F,ej,ei,eh){A 2F={};2F.F=F;A 6J=L;if(F.3R){A 3R=z.1D(F.3R);A 9i=3R.kh("kg");2F.2E=F.2E||(9i?9i.1Z:L);6J=z.6K(3R)}I{2F.2E=F.2E}A 5l=[{}];if(6J){5l.Y(6J)}if(F.5g){5l.Y(F.5g)}if(F.ek){5l.Y({"z.ek":S 5d().8O()})}2F.1r=z.9h(z.1x.14(L,5l));2F.9d=F.9d||"9g";A d=S z.30(ej);d.5k(ei,B(eg){C eh(eg,d)});A ld=F.4E;if(ld&&z.1Y(ld)){d.ef(B(ee){C ld.2d(F,ee,2F)})}A 1G=F.9f;if(1G&&z.1Y(1G)){d.ed(B(e9){C 1G.2d(F,e9,2F)})}A 6I=F.kf;if(6I&&z.1Y(6I)){d.9e(B(e8){C 6I.2d(F,e8,2F)})}d.1F=2F;C d};A e4=B(O){O.e0=K;A 1b=O.1F.1b;if(V 1b.e7=="B"){1b.e7()}};A e3=B(O){C z.e6[O.1F.9d](O.1F.1b)};A e2=B(9c,O){1z.1K(9c);C 9c};A 3Q=B(F){A O=z.e5(F,e4,e3,e2);O.1F.1b=z.9b(O.1F.F);C O};A 5j=L;A 3t=[];A 94=B(){A dZ=(S 5d()).dU();if(!z.e1){z.1n(3t,B(4D,6H){if(!4D){C}A O=4D.O;1u{if(!O||O.e0||!4D.dT(O)){3t.3S(6H,1);C}if(4D.dR(O)){3t.3S(6H,1);4D.dP(O)}I{if(O.9a){if(O.9a+(O.1F.F.6G||0)0){5c(z.2p(D,B(){D.5b(L,8R)}),d);C D}D.4A=S 5d().8O();if(D.2Z){D.4A-=D.8Q*D.2o}D.8N=D.4A+D.8Q;D.2D=K;D.2Z=U;A 8P=D.2C.4x(D.2o);if(!D.2o){if(!D.4y){D.4y=D.4z}D.3q("dt",[8P])}D.3q("ds",[8P]);D.8M();C D},jS:B(){5e(D.3r);if(!D.2D){C D}D.2Z=K;D.3q("dr",[D.2C.4x(D.2o)]);C D},jR:B(dq,dp){5e(D.3r);D.2D=D.2Z=K;D.2o=dq*6D;if(dp){D.5b()}C D},jQ:B(dn){if(!D.3r){C}5e(D.3r);if(dn){D.2o=1}D.3q("dm",[D.2C.4x(D.2o)]);D.2D=D.2Z=U;C D},3N:B(){if(D.2D){C D.2Z?"3M":"jP"}C"jO"},8M:B(){5e(D.3r);if(D.2D){A dl=S 5d().8O();A 2q=(dl-D.4A)/(D.8N-D.4A);if(2q>=1){2q=1}D.2o=2q;if(D.5a){2q=D.5a(2q)}D.3q("8B",[D.2C.4x(2q)]);if(2q<1){D.3r=5c(z.2p(D,"8M"),D.dj)}I{D.2D=U;if(D.4z>0){D.4z--;D.5b(L,K)}I{if(D.4z==-1){D.5b(L,K)}I{if(D.4y){D.4z=D.4y;D.4y=0}}}D.2o=0;D.3q("dh")}}C D}});(B(){A df=B(E){if(z.1l){A ns=E.1c;if(!ns.8L.G&&z.1c(E,"8L")=="dg"){ns.8L="1"}if(!ns.3n.G&&z.1c(E,"3n")=="8K"){ns.3n="8K"}}};z.6C=B(F){if(V F.1d=="1k"){2m S 1O("z.6C jN an 1d 1Z")}F.E=z.1D(F.E);A 3p=z.1x({6w:{}},F);A 8J=(3p.6w.2W={});8J.1w=(V 3p.1w=="1k")?B(){C 2V(z.1c(3p.E,"2W"))}:3p.1w;8J.1d=3p.1d;A 2U=z.6y(3p);z.2c(2U,"6x",L,B(){df(3p.E)});C 2U};z.8I=B(F){C z.6C(z.1x({1d:1},F))};z.8H=B(F){C z.6C(z.1x({1d:0},F))};if(z.6B&&!z.3o){z.8E=B(n){C 2k("0.5")+((2Y.da((n+2k("1.5"))*2Y.d9))/2)}}I{z.8E=B(n){C 0.5+((2Y.da((n+1.5)*2Y.d9))/2)}}A d4=B(6A){D.8G=6A;R(A p in 6A){A 1a=6A[p];if(1a.1w 1N z.1J){1a.d7=S z.1J()}}D.4x=B(r){A J={};R(A p in D.8G){A 1a=D.8G[p];A 6z=L;if(1a.1w 1N z.1J){6z=z.d8(1a.1w,1a.1d,r,1a.d7).8F()}I{if(!z.2l(1a.1w)){6z=((1a.1d-1a.1w)*r)+1a.1w+(p!="2W"?1a.jM||"px":"")}}J[p]=6z}C J}};z.6y=B(F){F.E=z.1D(F.E);if(!F.5a){F.5a=z.8E}A 2U=S z.d6(F);z.2c(2U,"6x",2U,B(){A pm={};R(A p in D.6w){A 1a=pm[p]=z.1x({},D.6w[p]);if(z.1Y(1a.1w)){1a.1w=1a.1w()}if(z.1Y(1a.1d)){1a.1d=1a.1d()}A d5=(p.1M().T("jL")>=0);B 8C(E,p){4w(p){2X"58":C E.8D;2X"3n":C E.6v}A v=z.1c(E,p);C(p=="2W")?2V(v):2k(v)};if(V 1a.1d=="1k"){1a.1d=8C(D.E,p)}I{if(V 1a.1w=="1k"){1a.1w=8C(D.E,p)}}if(d5){1a.1w=S z.1J(1a.1w);1a.1d=S z.1J(1a.1d)}I{1a.1w=(p=="2W")?2V(1a.1w):2k(1a.1w)}}D.2C=S d4(pm)});z.2c(2U,"8B",2U,B(8A){R(A s in 8A){z.1c(D.E,s,8A[s])}});C 2U}})()}', 62, 1711, '|||||||||||||||||||||||||||||||||||dojo|var|function|return|this|node|args|length|evt|else|ret|true|null|obj|elem|dfd|arguments|arr|for|new|indexOf|false|typeof||_base|push|type||te|||apply|attr|||||prop|xhr|style|end|doc|match|uri|_hasResource|key|del|undefined|isIE|item|forEach|djConfig|name|document|query|while|_66|try|res|start|mixin|catch|console|split|root|prototype|byId|gcs|ioArgs|err|NodeList|_p|Color|debug|parentNode|toLowerCase|instanceof|Error|constructor|provide|isString|ta|255|val|_a|global|_69|isFunction|value||substring|join|map|tn||window||path|_343|_220|_listeners|connect|call|json|replace|left|_b|toString|128|parseFloat|isArray|throw||_percent|hitch|step|declare|charAt|nodeType|_3c3|nidx|slice|faux|fired|_c4|_7e|loc|curve|_active|url|_44c|responseText|str|_312|idx|tqp|isNaN|isOpera|_22d|callee|add|_18b|_f8|_e2|_41|anim|Number|opacity|case|Math|_paused|Deferred|lastIndexOf|||||||||shift|substr|string|_3e7|_3ce|break|_w|charCode|_listener|_d5|_c5|authority|_49|width|isSafari|_49e|fire|_timer|_47b|_465|eval|_in|_40c|_409|_362|_3d9|className|_3d5|_386|_37a|body|getComputedStyle|box|_221|keyCode|remove|_8d|_46|paused|status|not|_478|_461|form|splice|filter|concat|tret|childNodes|_38b|_367|_33d||||||||||_340|_348|keypress|appendChild|_toArray|Array|_2b0|_toPixelValue|ref|_fixEvent|_19f|_14c|_14a|_150|_141|declaredClass|_d4|_99|_Url|_83|scheme|_67|_3d|switch|getValue|_startRepeatCount|repeat|_startTime|_47e|cancel|tif|load|to|with|tf|getElementsByTagName|number|_34c|_342|extend|_1e3|_normalizeEventName|_14b|_14e|results|self|cbfn|_f9|_d8|_b2|src|_88|dav||baseUrl|fragment|_loadedModules|_44|_43|_loaders|mll|height||easing|play|setTimeout|Date|clearTimeout|hdr|content|code|errback|_464|addCallbacks|_450|fromJson|_413|_3fc|_3ee|max|_31e|cond|getAttribute|_3d4|obi|tagName|_360|_381|contains|firstChild|_368|_372|_320|place|_2fa|scrollTop|_299|scrollLeft|top|documentElement|_288|_287|_getBorderExtents|_23f|_23d|_239|_218|_216|_211|eles|target|keys|shiftKey|ctrlKey|event|192|iel|_1db|delete|_1cf||addEventListener|String|_1af|_157|array|_14d|continue|_14f|_137|_11f|_106|_findMethod|has|_delegate|_dc|_d3|loaded|_9a|_loadInit|_inFlightCount|getObject|tv|_4f|_postLoad|_2d|offsetWidth|properties|beforeBegin|animateProperty|_4ad|_4a6|isKhtml|_fade|100|headers|readyState|timeout|_469|_457|_44d|formToObject|_441|comment|_43d|_36f|_419|tp|_40a|_406|_407|_373|_403|_3e6|_31b|cbi|test|_3c7|nextSibling|last|_3a1|_38e|_365|_36b|ecn|_364|_363|_356|_35e|_35f|_34f|_34d|_349|trim|tci|_328|_32b|_31f|_31c|_anim|_300|_2ff|_2f5|_2e7|removeClass|addClass|func|_2c4|cls|_2a9|_2ae|_280|_27f|_getPadExtents|isMoz|none|_233|cssText|_214|_fixCallback|_synthesizeEvent|stopPropagation|preventDefault|_setKeyChar|_1e1|ieh|_1d7|_1be|colorFromArray|sanitize|bits|rgb|_156|_fire|_resback|_13d|partial|_13a|silentlyCancelled|_topics|_127|_f1|_f0|superclass|_ec|_e3|mct|setObject|_bf|_b3|object|require|_92|_khtmlTimer|location|XMLHTTP|locale|dua|_71|_modulePrefixes|_55|_loadModule|_51|_50|_4e|pop|_3f|_callLoaded|_unloaders|_loadNotifying|_loadedUrls|_27|_24|_1d|_5|_4b7|onAnimate|getStyle|offsetHeight|_defaultEasing|toCss|_properties|fadeOut|fadeIn|_49f|auto|zoom|_cycle|_endTime|valueOf|_494|duration|_492|DELETE|_ioAddQueryToUrl|putData|contentType|password|user|_isDocumentOk|application|||||_466||||||startTime|_xhrObj|_45f|handleAs|addBoth|error|text|objectToQuery|_44f|ActiveXObject|_443|_442|filtered|_43f|_43e|_437|file|tnl|_41c|_filterQueryResult|_zipIdx|_408|_402|evaluate|_3ed|_380|fHit|_361|_33b|_3da|_3ab|_3d6|RegExp|_327|_3cf|_3c9|child|innerHTML|first|tval|_391|class|pnc|_37e|_37c|_375|_366|_35c|_35a|_353|_33c|_336|_314|||_315|_oe|_307|_309|cloneNode|after|createElement||_2f8|_2ef|_2ee|unshift|coords|some|every||_2cb|script|_2c9|parent||a2p||_2c3|_2bd||abs|_getMarginBox|_2b3|_2a6|position|_2a7|_2ac|_2ab|_getIeDocumentElementOffset|getBoundingClientRect|ownerDocument|_2a3|clientWidth|_isBodyLtr|_fixIeBiDiScrollLeft|_bodyLtr|_29d|_getContentBox|_setBox|_getMarginExtents|_getPadBorderExtents|_usesBorderBox|boxModel|pcs|st|sl|_240|runtimeStyle|_dcm|BackCompat|compatMode|default|_21b|_d|html|_event_listener|handlers|PAGE_DOWN|PAGE_UP|RIGHT_ARROW|LEFT_ARROW|DOWN_ARROW|UP_ARROW|_preventDefault||_stopPropagation|returnValue||_trySetKeyCode|cancelBubble|currentTarget|106|_1ee|111||_1e8|_1e7|||se|srcElement|onkeydown||_1d0|_disconnect|lid|_1c0|_connect|_set|_195|_185|_183|_17d|_everyOrSome|_16b|_172|_15b|Function|_154|_escapeString|_140|chain|_check|canceller|_12d|_124|_11a|_10d|_107|inherited|_fa|_f2|_findMixin|_constructor|preamble|_de|clone|tmp|_c7|TMP|_be|_ba|_mixin|isBrowser|lang|firebug||param|modulePaths|_a7|_fireCallback|_a0|setContext||_9c|unloaded||||_96|_93|navigator|_90|_89||protocol|_84|_86|_XMLHTTP_PROGIDS|gears|google|setAttribute|_80|_77|cfg|_6f|_getModuleSymbols|_5a|_58|_53|_4d|_4c|_45|_40|_moduleHasPrefix|_loadUri|_28|_26|_21|_22|tests|doh|_20|_1f|_1c|version|_1b|_19|_getProp|_11|_4|_4a5|_4b3|_Animation|tempColor|blendColors|PI|sin|||||_49a|normal|onEnd||rate||curr|onStop|_497||_496|pct|onPause|onPlay|onBegin|delay||_491|_Line|_48b|wrapForm|PUT|_487|POST|GET|_476|_474|_472|_ioWatch|send|_471|setRequestHeader|open|callback|setInterval|_470|resHandle|_46f|ioCheck|_46e|validCheck|getTime|_ioCancelAll|addOnUnload|clearInterval|dojoType|now|canceled|_blockAsync|_45e|_45c|_459|_ioSetArgs|_contentHandlers|abort|_458|_456||||addErrback|_454|addCallback|_452|_44b|_44a|_449|preventCache|responseXML|Microsoft|JSON|usePlainJson|_431|toJson|_430|_42d|image|opt|ria|_421|_41b|_40b|_zip|_410|_40d|_357|sqf|_374|_3e5|_3df|_38f|clc|pred|parseInt|ntf|_3bf|_3bc|cnl|previousSibling|_3a9|_3a6|_39c|_399|_396|_392|__cachedIndex|__cachedLength|_376|iterateNext|_34a|_355|_354|_32c|_350|_34b|_33f|_33e|_33a|_338|_334|_332||_330|_32e||_322|_316|mousemove|mouseout|mouseover|_305|lastChild||_2f9||_2f2|_2f1|removeChild|_2ec|_2eb|_2ea|_2e6||_2e4|_2e2|_2d6|_2d5|_2d4|_2d3|_2d2|_2d1|_2cd|_2cc|scs|write|_2c8|hasClass|_2c0|_2bb|_2b5|_abs|_docScroll|offsetParent|offsetTop|offsetLeft|absolute|getBoxObjectFor|clientLeft|_setContentSize|_setMarginBox|_28d|_286|_285|_289|NaN|_281|border|_272|_26b|_260|_258|_253|_24c|_246|_23a|_getOpacity|_setOpacity|_238|td|tr|nodeName|FILTER|_22f|_22e|currentStyle|_22c|_22b|display|QuirksMode|unselectable|_217|isMozilla|getElementById|attributes|all|_ie_listener|_getIeDispatcher|_1fd|NUM_LOCK|SCROLL_LOCK|INSERT|END|HOME|PAUSE|F12|F11|F10|F9|F8|F7|F6|F5|F4|F3|F2|F1|63232|SHIFT_TAB|TAB|keyIdentifier|_1f3|stopEvent|_punctMap|222|219|186|onkeypress|_stealthKeyDown|_fixKeys|relatedTarget|_1e0|_1df|_stealthKeydown|_1d6|_1d5|_1d1|_1ca|_1c9|_1cb|_1c2|_1c1|_1c3|_1c4|_1bc|_1b3|_1b2|colorFromHex|colorFromRgb|named|colorFromString|mask|rgba|_19c|_197|_192|setColor|_180|_178|_177|_175|_174|_16d|_166|_164|_163|_162|_15c|_15d|_15e|index|__json__|toJsonIndentStr|_nextId|_12f|_12b|publish|_128|_126|_125|_122|_121|_123|_11c|_11b|_10c|_10b|_108|getDispatcher|argument|nom|_construct|_core|_makeCtor|_df|_db|deprecated|isObject|_cc||scope||_hitchArgs|_c2||pre|_c1|native|isDebug||registerModulePath|_a8||finally|||_a6|_a5|_a4|_a3|_a2|_a1|_9f|_9e|_9d|_9b|_98|_97|onbeforeunload|ipt|scr|complete|_95|userAgent|_modulesLoaded|initialized|_initFired|_8c|_8a|_getText|_87|ieForceActiveXXhr|Msxml2|isGears|_81|_gearsObject|googlegears|GearsFactory|isFF|_7d|Safari|_72|_name|_6c|ire|ore|_68|i18n|_5b|requireIf|_56|_52|loading|_4a|_loadPath|_47|_48|_global_omit_module_check|_getModulePrefix|_3c|_3a|_37|_30|Boolean|_loadUriAndCheck|_2e||cacheBust|_1e|_1a|_17|_16|_15|_14|_f|_10|_e|_9|_8|revision|flag|patch|minor|major|_6|color|units|needs|stopped|playing|stop|gotoPercent|pause|1000|implemented|yet|_48a|xhrDelete|rawXhrPut|xhrPut|postData|rawXhrPost|xhrPost|xhrGet|Type|Content|sync|response|http|bad|urlencoded|www|_watchInFlightError||exceeded|handle|action|getAttributeNode|loadXML|async|XMLDOM|prefixes|MSXML3|MSXML|MSXML2||xml|javascript|wasn|your|optional|message|off|turn|use|endpoints|issues|security|potential|avoid|mimetype|using|consider|please|decodeURIComponent|queryToObject|formToJson|formToQuery|encodeURIComponent|selected|option|multiple|checked|checkbox|radio|disabled|textarea|select|button|reset|submit|input|_3fb|hasAttribute|0n|even|odd|nth|_3b5|empty|_3b1|_3ad|htmlFor|_38a|under||exprssion|failure|ANY_TYPE|XPathResult|starts|keyup|keydown|mouseup|mousedown|blur|click|combine|span|addContent||adopt|orphan|_2de|_2dd|styles|_2da|_2d9|_2cf|_2ce|show|createPopup|toggleClass|scrollWidth|clientTop|ltr|direction|pageXOffset|pageYOffset|fixed|contentBox|marginBox|BUTTON|TABLE|_getBorderBox|clientHeight|visible|overflow|marginBottom|marginRight|marginTop|marginLeft|borderBottomWidth|borderBottomStyle|borderRightWidth|borderRightStyle|borderTopWidth|borderTopStyle|borderLeftWidth|borderLeftStyle|paddingBottom|paddingRight|paddingTop|paddingLeft|offset||min|padding||margin|Opacity|Alpha|alpha|filters|pixelLeft|medium|_22a|defaultView|before||insertBefore|KhtmlUserSelect|MozUserSelect|setSelectable|isDescendant|div|_destroyElement|BackgroundImageCache|execCommand|PageDown|PageUp|Right|Left|Down|Up|63289|63249|63248|PRINT_SCREEN|63302|63277|63276|63275|63273|63272|63250|63247|63246|63245|63244|63243|63242|63241|63240|63239|63238|63237|63236|63235|63234|63233|Enter|_1f9|which|_1f6|bubbledKeyCode|221|220||||191|190|189|188|187|toElement|fromElement|clientY|pageY||clientX|pageX|offsetY|||layerY|offsetX|layerX|parentWindow|_nop|_allow_leaks|145|144|126|F15|125|F14|124|F13|123|122|121|120|119|118|117|116|115|114|113|112|NUMPAD_DIVIDE|110|NUMPAD_PERIOD|109|NUMPAD_MINUS|108|NUMPAD_ENTER|107|NUMPAD_PLUS|NUMPAD_MULTIPLY|105|NUMPAD_9|104|NUMPAD_8|103|NUMPAD_7|102|NUMPAD_6|101|NUMPAD_5|NUMPAD_4||NUMPAD_3|NUMPAD_2|NUMPAD_1|NUMPAD_0||SELECT|RIGHT_WINDOW||LEFT_WINDOW||HELP|SPACE|ESCAPE|CAPS_LOCK|ALT|CTRL|SHIFT|ENTER|CLEAR|BACKSPACE|attachEvent|fixEvent|fromCharCode|keyChar|_1b9|removeEventListener|0x|round|toHex|toRgba|toRgb|aqua|teal|blue|navy|yellow|olive|lime|green|fuchsia|purple|red|maroon|white|gray|silver|black|boolean|called|already|Cancelled|connectPublisher|unsubscribe|subscribe|disconnect|_113|_112||_111|_110|||found|was||must|_|module|||required|likely|It|declaration|Mixin|separate|instead|property|initializer||pass|_c9|_bb|_b7|nfunction|isAlien|isFinite|isArrayLike|_firebug|withDoc|withGlobal|_writeIncludes|VML|behavior|addRule|createStyleSheet|vml|com|microsoft|schemas|urn|namespaces|onunload|onreadystatechange|defer|khtml|WebKit|DOMContentLoaded|enableMozDomContentLoaded|domcontentloaded|Unable|base|chrome|1223|304|300|200|available|XMLHttpRequest|_println|language|userLanguage|isQuirks|factory|mimeTypes|Factory|Gears|_7f|MSIE||Firefox|Gecko|Konqueror||Opera|appVersion|xd|browser|moduleUrl|port|host|hostenv|_requireLocalization|_5f|_5e|_5d|_5c|requireLocalization|requireAfterIf|_57|common|platformRequire|defined|symbol|_isXDomain|tried|Could|__package__|packageFileName|_42|useXDomain|flight|still|files|addOnLoad|failed|sourceURL|util|notice|without|change|subject|APIs|EXPERIMENTAL|experimental|removed|will|DEPRECATED|exists|10315|Rev|Mobile|Spidermonkey|Rhino||Browser|delayMozLoadingFix|preventBackButtonFix|libraryScriptUri|baseRelativePath|baseScriptUri|allowQueryConfig|warn|trace|timeEnd||time|profileEnd|profile|log|info|groupEnd|group|dirxml|dir|count|assert'.split('|'), 0, {}); + + +/* + +Prototype 1.5 rc0 + - Adapted from Ruby on Rails - http://dev.rubyonrails.org/browser/spinoffs/prototype/src + - By Lunarmedia, 06 August, 2006 + - Available at (and packed with) JavascriptCompressor.com + +Please note this version is missing the selector.js component of the full Prototype library. +You can get the compressed version of selector at JavascriptCompressor.com + +*/ + + var decompressedPrototype = function (p, a, c, k, e, d) { + e = function (c) { + return (c < a ? "" : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36)) + }; + if (!''.replace(/^/, String)) { +/* BEGIN LOOP */ + while (c--) { + d[e(c)] = k[c] || e(c) + } +/* END LOOP */ + k = [(function (e) { + return d[e] + })]; + e = (function () { + return '\\w+' + }); + c = 1 + }; +/* BEGIN LOOP */ + while (c--) { + if (k[c]) { + p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]) + } + } +/* END LOOP */ + return p + }('d T={4l:\'1.5.8P\',3E:\'(?:<3G.*?>)((\\n|\\r|.)*?)(?:<\\/3G>)\',2v:7(){},K:7(x){c x}};d 1b={17:7(){c 7(){6.1I.2n(6,N)}}};d 1e=z q();q.u=7(5d,O){G(d 1G 2M O){5d[1G]=O[1G]}c 5d};q.1U=7(U){1j{f(U==1v)c\'1v\';f(U==1L)c\'1L\';c U.1U?U.1U():U.2C()}1s(e){f(e 8R 9l)c\'...\';25 e}};7j.v.1d=7(){d 43=6,23=$A(N),U=23.8S();c 7(){c 43.2n(U,23.3s($A(N)))}};7j.v.8U=7(U){d 43=6;c 7(C){c 43.8V(U,C||1W.C)}};q.u(8Q.v,{8W:7(){d 4Z=6.2C(16);f(6<16)c\'0\'+4Z;c 4Z},5j:7(){c 6+1},8Y:7(o){$R(0,6,11).V(o);c 6}});d 6s={6j:7(){d 48;G(d i=0;i0){f(I=O.I(1A)){L+=O.47(0,I.w);L+=(1z(I)||\'\').2C();O=O.47(I.w+I[0].t)}1D{L+=O,O=\'\'}}c L},92:7(1A,1z,3i){1z=6.2T.52(1z);3i=3i===1v?1:3i;c 6.2T(1A,7(I){f(--3i<0)c I[0];c 1z(I)})},93:7(1A,o){6.2T(1A,o);c 6},94:7(t,2S){t=t||30;2S=2S===1v?\'...\':2S;c 6.t>t?6.47(0,t-2S.t)+2S:6},9F:7(){c 6.2y(/^\\s+/,\'\').2y(/\\s+$/,\'\')},71:7(){c 6.2y(/<\\/?[^>]+>/7Y,\'\')},2Q:7(){c 6.2y(z 3O(T.3E,\'5P\'),\'\')},70:7(){d 6Y=z 3O(T.3E,\'5P\');d 5p=z 3O(T.3E,\'98\');c(6.I(6Y)||[]).1C(7(5o){c(5o.I(5p)||[\'\',\'\'])[1]})},3q:7(){c 6.70().1C(7(3G){c 4q(3G)})},9E:7(){d 1q=J.4Y(\'1q\');d 1Y=J.9D(6);1q.75(1Y);c 1q.3h},9c:7(){d 1q=J.4Y(\'1q\');1q.3h=6.71();c 1q.2z[0]?1q.2z[0].6q:\'\'},78:7(){d 7i=6.I(/^\\??(.*)$/)[1].3j(\'&\');c 7i.36({},7(5b,72){d 1i=72.3j(\'=\');5b[1i[0]]=1i[1];c 5b})},1Z:7(){c 6.3j(\'\')},3P:7(){d 2l=6.3j(\'-\');f(2l.t==1)c 2l[0];d 54=6.5g(\'-\')==0?2l[0].7e(0).3Y()+2l[0].7g(1):2l[0];G(d i=1,73=2l.t;i<73;i++){d s=2l[i];54+=s.7e(0).3Y()+s.7g(1)}c 54},1U:7(){c"\'"+6.2y(/\\\\/g,\'\\\\\\\\\').2y(/\'/g,\'\\\\\\\'\')+"\'"}});4b.v.2T.52=7(1z){f(2i 1z==\'7\')c 1z;d 2U=z 3n(1z);c 7(I){c 2U.7a(I)}};4b.v.9h=4b.v.78;d 3n=1b.17();3n.79=/(^|.|\\r|\\n)(#\\{(.*?)\\})/;3n.v={1I:7(2U,1A){6.2U=2U.2C();6.1A=1A||3n.79},7a:7(U){c 6.2U.2T(6.1A,7(I){d 53=I[1];f(53==\'\\\\\')c I[2];c 53+(U[I[3]]||\'\').2C()})}};d $1y=z q();d $49=z q();d 1p={V:7(o){d w=0;1j{6.2m(7(h){1j{o(h,w++)}1s(e){f(e!=$49)25 e}})}1s(e){f(e!=$1y)25 e}},9n:7(o){d L=11;6.V(7(h,w){L=L&&!!(o||T.K)(h,w);f(!L)25 $1y});c L},9o:7(o){d L=11;6.V(7(h,w){f(L=!!(o||T.K)(h,w))25 $1y});c L},3e:7(o){d P=[];6.V(7(h,w){P.W(o(h,w))});c P},7n:7(o){d L;6.V(7(h,w){f(o(h,w)){L=h;25 $1y}});c L},7o:7(o){d P=[];6.V(7(h,w){f(o(h,w))P.W(h)});c P},9p:7(1A,o){d P=[];6.V(7(h,w){d 7c=h.2C();f(7c.I(1A))P.W((o||T.K)(h,w))});c P},1M:7(U){d 51=Y;6.V(7(h){f(h==U){51=11;25 $1y}});c 51},36:7(45,o){6.V(7(h,w){45=o(45,h,w)});c 45},9q:7(1F){d 23=$A(N).47(1);c 6.3e(7(h){c h[1F].2n(h,23)})},9s:7(o){d L;6.V(7(h,w){h=(o||T.K)(h,w);f(L==1v||h>=L)L=h});c L},9u:7(o){d L;6.V(7(h,w){h=(o||T.K)(h,w);f(L==1v||hb?1:0}).3r(\'h\')},1Z:7(){c 6.3e(T.K)},9B:7(){d o=T.K,23=$A(N);f(2i 23.5e()==\'7\')o=23.9C();d 7l=[6].3s(23).1C($A);c 6.1C(7(h,w){c o(7l.3r(w))})},1U:7(){c\'#<1p:\'+6.1Z().1U()+\'>\'}};q.u(1p,{1C:1p.3e,5v:1p.7n,1k:1p.7o,8M:1p.1M,7p:1p.1Z});d $A=1E.7q=7(2R){f(!2R)c[];f(2R.1Z){c 2R.1Z()}1D{d P=[];G(d i=0;i<2R.t;i++)P.W(2R[i]);c P}};q.u(1E.v,1p);f(!1E.v.4d)1E.v.4d=1E.v.4m;q.u(1E.v,{2m:7(o){G(d i=0;i<6.t;i++)o(6[i])},5i:7(){6.t=0;c 6},7r:7(){c 6[0]},5e:7(){c 6[6.t-1]},7s:7(){c 6.1k(7(h){c h!=1v||h!=1L})},6J:7(){c 6.36([],7(6H,h){c 6H.3s(h&&h.5D==1E?h.6J():[h])})},5s:7(){d 4N=$A(N);c 6.1k(7(h){c!4N.1M(h)})},5g:7(U){G(d i=0;i<6.t;i++)f(6[i]==U)c i;c-1},4m:7(5h){c(5h!==Y?6:6.1Z()).4d()},1U:7(){c\'[\'+6.1C(q.1U).1N(\', \')+\']\'}});d 4h={2m:7(o){G(d 1O 2M 6){d h=6[1O];f(2i h==\'7\')49;d 1i=[1O,h];1i.1O=1O;1i.h=h;o(1i)}},7t:7(){c 6.3r(\'1O\')},4N:7(){c 6.3r(\'h\')},7u:7(2N){c $H(2N).36($H(6),7(4Q,1i){4Q[1i.1O]=1i.h;c 4Q})},7w:7(){c 6.1C(7(1i){c 1i.1C(4n).1N(\'=\')}).1N(\'&\')},1U:7(){c\'#<4h:{\'+6.1C(7(1i){c 1i.1C(q.1U).1N(\': \')}).1N(\', \')+\'}>\'}};7 $H(U){d 2N=q.u({},U||{});q.u(2N,1p);q.u(2N,4h);c 2N};3L=1b.17();q.u(3L.v,1p);q.u(3L.v,{1I:7(22,2x,2H){6.22=22;6.2x=2x;6.2H=2H},2m:7(o){d h=6.22;2q{o(h);h=h.5j()}1H(6.1M(h))},1M:7(h){f(h<6.22)c Y;f(6.2H)c h<6.2x;c h<=6.2x}});d $R=7(22,2x,2H){c z 3L(22,2x,2H)};d M={4w:7(){c 6s.6j(7(){c z 5C()},7(){c z 5n(\'7y.6d\')},7(){c z 5n(\'7z.6d\')})||Y},4s:0};M.2W={3b:[],2m:7(o){6.3b.2m(o)},69:7(4F){f(!6.1M(4F))6.3b.W(4F)},7A:7(5t){6.3b=6.3b.5s(5t)},3y:7(1a,26,E,2Z){6.V(7(3o){f(3o[1a]&&2i 3o[1a]==\'7\'){1j{3o[1a].2n(3o,[26,E,2Z])}1s(e){}}})}};q.u(M.2W,1p);M.2W.69({5G:7(){M.4s++},1B:7(){M.4s--}});M.44=7(){};M.44.v={4a:7(m){6.m={1F:\'4j\',4p:11,5H:\'5E/x-86-Q-7C\',28:\'\'};q.u(6.m,m||{})},3l:7(){c 6.E.32==1v||6.E.32==0||(6.E.32>=84&&6.E.32<7E)},7G:7(){c!6.3l()}};M.3t=1b.17();M.3t.5L=[\'7H\',\'80\',\'7I\',\'7J\',\'4t\'];M.3t.v=q.u(z M.44(),{1I:7(1l,m){6.E=M.4w();6.4a(m);6.26(1l)},26:7(1l){d 28=6.m.28||\'\';f(28.t>0)28+=\'&7K=\';1j{6.1l=1l;f(6.m.1F==\'7L\'&&28.t>0)6.1l+=(6.1l.I(/\\?/)?\'&\':\'?\')+28;M.2W.3y(\'5G\',6,6.E);6.E.7N(6.m.1F,6.1l,6.m.4p);f(6.m.4p){6.E.5T=6.5J.1d(6);2Y((7(){6.4r(1)}).1d(6),10)}6.5A();d 1c=6.m.5V?6.m.5V:28;6.E.7O(6.m.1F==\'4j\'?1c:1L)}1s(e){6.3p(e)}},5A:7(){d 1P=[\'X-7P-7Q\',\'5C\',\'X-T-4l\',T.4l,\'7R\',\'1Y/7m, 1Y/2e, 5E/5F, 1Y/5F, */*\'];f(6.m.1F==\'4j\'){1P.W(\'5Q-2g\',6.m.5H);f(6.E.7S)1P.W(\'7T\',\'7U\')}f(6.m.1P)1P.W.2n(1P,6.m.1P);G(d i=0;i<1P.t;i+=2)6.E.7V(1P[i],1P[i+1])},5J:7(){d 2F=6.E.2F;f(2F!=1)6.4r(6.E.2F)},4A:7(B){1j{c 6.E.7W(B)}1s(e){}},5M:7(){1j{c 4q(\'(\'+6.4A(\'X-7X\')+\')\')}1s(e){}},5R:7(){1j{c 4q(6.E.3F)}1s(e){6.3p(e)}},4r:7(2F){d C=M.3t.5L[2F];d E=6.E,2Z=6.5M();f(C==\'4t\'){1j{(6.m[\'2I\'+6.E.32]||6.m[\'2I\'+(6.3l()?\'81\':\'82\')]||T.2v)(E,2Z)}1s(e){6.3p(e)}f((6.4A(\'5Q-2g\')||\'\').I(/^1Y\\/7m/i))6.5R()}1j{(6.m[\'2I\'+C]||T.2v)(E,2Z);M.2W.3y(\'2I\'+C,6,E,2Z)}1s(e){6.3p(e)}f(C==\'4t\')6.E.5T=T.2v},3p:7(57){(6.m.5W||T.2v)(6,57);M.2W.3y(\'5W\',6,57)}});M.4C=1b.17();q.u(q.u(M.4C.v,M.3t.v),{1I:7(1w,1l,m){6.4x={3m:1w.3m?$(1w.3m):$(1w),3z:1w.3z?$(1w.3z):(1w.3m?1L:$(1w))};6.E=M.4w();6.4a(m);d 1B=6.m.1B||T.2v;6.m.1B=(7(E,U){6.5Y();1B(E,U)}).1d(6);6.26(1l)},5Y:7(){d 3A=6.3l()?6.4x.3m:6.4x.3z;d 3k=6.E.3F;f(!6.m.3q)3k=3k.2Q();f(3A){f(6.m.60){z 6.m.60(3A,3k)}1D{k.6h(3A,3k)}}f(6.3l()){f(6.1B)2Y(6.1B.1d(6),10)}}});M.61=1b.17();M.61.v=q.u(z M.44(),{1I:7(1w,1l,m){6.4a(m);6.1B=6.m.1B;6.1J=(6.m.1J||2);6.2s=(6.m.2s||1);6.4B={};6.1w=1w;6.1l=1l;6.22()},22:7(){6.m.1B=6.63.1d(6);6.2D()},7b:7(){6.4B.1B=1v;89(6.65);(6.1B||T.2v).2n(6,N)},63:7(26){f(6.m.2s){6.2s=(26.3F==6.64?6.2s*6.m.2s:1);6.64=26.3F}6.65=2Y(6.2D.1d(6),6.2s*6.1J*4z)},2D:7(){6.4B=z M.4C(6.1w,6.1l,6.m)}});7 $(){d P=[],4;G(d i=0;i<4V>\'+6.2t+\'\';c $A(1q.2z[0].2z[0].2z)}};d 1g=z q();1g.6W=1b.17();1g.6W.v=q.u(z 1e.1g(\'96\'),{2V:7(){6.1K.97(6.4)},2X:7(2h){2h.V((7(2j){6.4.1X.55(2j,6.4)}).1d(6))}});1g.5m=1b.17();1g.5m.v=q.u(z 1e.1g(\'99\'),{2V:7(){6.1K.56(6.4);6.1K.74(11)},2X:7(2h){2h.4m(Y).V((7(2j){6.4.55(2j,6.4.9a)}).1d(6))}});1g.7h=1b.17();1g.7h.v=q.u(z 1e.1g(\'9d\'),{2V:7(){6.1K.56(6.4);6.1K.74(6.4)},2X:7(2h){2h.V((7(2j){6.4.75(2j)}).1d(6))}});1g.76=1b.17();1g.76.v=q.u(z 1e.1g(\'9i\'),{2V:7(){6.1K.9m(6.4)},2X:7(2h){2h.V((7(2j){6.4.1X.55(2j,6.4.9t)}).1d(6))}});k.3S=1b.17();k.3S.v={1I:7(4){6.4=$(4)},2m:7(o){6.4.1f.3j(/\\s+/).1k(7(B){c B.t>0}).2m(o)},5c:7(1f){6.4.1f=1f},7k:7(5a){f(6.1M(5a))c;6.5c(6.1Z().3s(5a).1N(\' \'))},42:7(4c){f(!6.1M(4c))c;6.5c(6.1k(7(1f){c 1f!=4c}).1N(\' \'))},2C:7(){c 6.1Z().1N(\' \')}};q.u(k.3S.v,1p);d 5I={5i:7(){G(d i=0;i=0){2b=4.m[w];h=2b.h||2b.1Y}c[4.B,h]},5X:7(4){d h=[];G(d i=0;i<4.t;i++){d 2b=4.m[i];f(2b.87)h.W(2b.h||2b.1Y)}c[4.B,h]}};d $F=D.k.1x;1e.3D=7(){};1e.3D.v={1I:7(4,1J,1a){6.1J=1J;6.4=$(4);6.1a=1a;6.2K=6.1x();6.2A()},2A:7(){5Z(6.2D.1d(6),6.1J*4z)},2D:7(){d h=6.1x();f(6.2K!=h){6.1a(6.4,h);6.2K=h}}};D.k.3C=1b.17();D.k.3C.v=q.u(z 1e.3D(),{1x:7(){c D.k.1x(6.4)}});D.3C=1b.17();D.3C.v=q.u(z 1e.3D(),{1x:7(){c D.3a(6.4)}});1e.2c=7(){};1e.2c.v={1I:7(4,1a){6.4=$(4);6.1a=1a;6.2K=6.1x();f(6.4.1h.2w()==\'Q\')6.67();1D 6.2A(6.4)},4K:7(){d h=6.1x();f(6.2K!=h){6.1a(6.4,h);6.2K=h}},67:7(){d 12=D.2L(6.4);G(d i=0;i<12.t;i++)6.2A(12[i])},2A:7(4){f(4.2g){6c(4.2g.2w()){1r\'6g\':1r\'6i\':1o.3B(4,\'8j\',6.4K.1d(6));1y;1r\'6l\':1r\'1Y\':1r\'3J\':1r\'1k-6n\':1r\'1k-8t\':1o.3B(4,\'8u\',6.4K.1d(6));1y}}}};D.k.2c=1b.17();D.k.2c.v=q.u(z 1e.2c(),{1x:7(){c D.k.1x(6.4)}});D.2c=1b.17();D.2c.v=q.u(z 1e.2c(),{1x:7(){c D.3a(6.4)}});f(!1W.1o){d 1o=z q()}q.u(1o,{8C:8,8F:9,8H:13,8I:27,8J:37,8L:38,8O:39,8T:40,8X:46,4:7(C){c C.Z||C.91},95:7(C){c(((C.6X)&&(C.6X==1))||((C.6Z)&&(C.6Z==1)))},9b:7(C){c C.9e||(C.9f+(J.3R.2G||J.1c.2G))},9g:7(C){c C.9j||(C.9k+(J.3R.2O||J.1c.2O))},7b:7(C){f(C.7d){C.7d();C.9r()}1D{C.48=Y;C.9w=11}},9A:7(C,1h){d 4=1o.4(C);1H(4.1X&&(!4.1h||(4.1h.3Y()!=1h.3Y())))4=4.1X;c 4},1T:Y,5u:7(4,B,1V,1u){f(!6.1T)6.1T=[];f(4.5f){6.1T.W([4,B,1V,1u]);4.5f(B,1V,1u)}1D f(4.4i){6.1T.W([4,B,1V,1u]);4.4i(\'2I\'+B,1V)}},66:7(){f(!1o.1T)c;G(d i=0;i<1o.1T.t;i++){1o.5N.2n(6,1o.1T[i]);1o.1T[i][0]=1L}1o.1T=Y},3B:7(4,B,1V,1u){d 4=$(4);1u=1u||Y;f(B==\'5U\'&&(33.4u.I(/3x|3w|3u/)||4.4i))B=\'5K\';6.5u(4,B,1V,1u)},5N:7(4,B,1V,1u){d 4=$(4);1u=1u||Y;f(B==\'5U\'&&(33.4u.I(/3x|3w|3u/)||4.4k))B=\'5K\';f(4.5x){4.5x(B,1V,1u)}1D f(4.4k){1j{4.4k(\'2I\'+B,1V)}1s(e){}}}});f(33.4u.I(/\\88\\b/))1o.3B(1W,\'8a\',1o.66,Y);d 2d={6o:Y,4P:7(){6.6z=1W.8e||J.3R.2G||J.1c.2G||0;6.6F=1W.8g||J.3R.2O||J.1c.2O||0},6u:7(4){d 19=0,15=0;2q{19+=4.2O||0;15+=4.2G||0;4=4.1X}1H(4);c[15,19]},35:7(4){d 19=0,15=0;2q{19+=4.29||0;15+=4.2f||0;4=4.1Q}1H(4);c[15,19]},68:7(4){d 19=0,15=0;2q{19+=4.29||0;15+=4.2f||0;4=4.1Q;f(4){p=k.1R(4,\'14\');f(p==\'3T\'||p==\'2o\')1y}}1H(4);c[15,19]},1Q:7(4){f(4.1Q)c 4.1Q;f(4==J.1c)c 4;1H((4=4.1X)&&4!=J.1c)f(k.1R(4,\'14\')!=\'4G\')c 4;c J.1c},8o:7(4,x,y){f(6.6o)c 6.6r(4,x,y);6.3g=x;6.34=y;6.1t=6.35(4);c(y>=6.1t[1]&&y<6.1t[1]+4.2k&&x>=6.1t[0]&&x<6.1t[0]+4.2p)},6r:7(4,x,y){d 4S=6.6u(4);6.3g=x+4S[0]-6.6z;6.34=y+4S[1]-6.6F;6.1t=6.35(4);c(6.34>=6.1t[1]&&6.34<6.1t[1]+4.2k&&6.3g>=6.1t[0]&&6.3g<6.1t[0]+4.2p)},8E:7(3Z,4){f(!3Z)c 0;f(3Z==\'8G\')c((6.1t[1]+4.2k)-6.34)/4.2k;f(3Z==\'8K\')c((6.1t[0]+4.2p)-6.3g)/4.2p},77:7(O,Z){O=$(O);Z=$(Z);Z.l.14=\'2o\';d 2P=6.35(O);Z.l.1n=2P[1]+\'1m\';Z.l.18=2P[0]+\'1m\';Z.l.21=O.2p+\'1m\';Z.l.24=O.2k+\'1m\'},4e:7(4M){d 19=0,15=0;d 4=4M;2q{19+=4.29||0;15+=4.2f||0;f(4.1Q==J.1c)f(k.1R(4,\'14\')==\'2o\')1y}1H(4=4.1Q);4=4M;2q{19-=4.2O||0;15-=4.2G||0}1H(4=4.1X);c[15,19]},77:7(O,Z){d m=q.u({5l:11,5r:11,5B:11,5q:11,29:0,2f:0},N[2]||{});O=$(O);d p=2d.4e(O);Z=$(Z);d 2J=[0,0];d 3v=1L;f(k.1R(Z,\'14\')==\'2o\'){3v=2d.1Q(Z);2J=2d.4e(3v)}f(3v==J.1c){2J[0]-=J.1c.2f;2J[1]-=J.1c.29}f(m.5l)Z.l.18=(p[0]-2J[0]+m.2f)+\'1m\';f(m.5r)Z.l.1n=(p[1]-2J[1]+m.29)+\'1m\';f(m.5B)Z.l.21=O.2p+\'1m\';f(m.5q)Z.l.24=O.2k+\'1m\'},8b:7(4){4=$(4);f(4.l.14==\'2o\')c;2d.4P();d 2P=2d.68(4);d 1n=2P[1];d 18=2P[0];d 21=4.6m;d 24=4.6p;4.6P=18-3X(4.l.18||0);4.6I=1n-3X(4.l.1n||0);4.5k=4.l.21;4.7f=4.l.24;4.l.14=\'2o\';4.l.1n=1n+\'1m\';4.l.18=18+\'1m\';4.l.21=21+\'1m\';4.l.24=24+\'1m\'},8w:7(4){4=$(4);f(4.l.14==\'3T\')c;2d.4P();4.l.14=\'3T\';d 1n=3X(4.l.1n||0)-(4.6I||0);d 18=3X(4.l.18||0)-(4.6P||0);4.l.1n=1n+\'1m\';4.l.18=18+\'1m\';4.l.24=4.7f;4.l.21=4.5k}};f(/3x|3w|3u/.4v(33.62)){2d.35=7(4){d 19=0,15=0;2q{19+=4.29||0;15+=4.2f||0;f(4.1Q==J.1c)f(k.1R(4,\'14\')==\'2o\')1y;4=4.1Q}1H(4);c[15,19]}};', 62, 600, '||||element||this|function|||||return|var||if||value|||Element|style|options||iterator||Object|||length|extend|prototype|index|||new||name|event|Form|transport||for||match|document||result|Ajax|arguments|source|results|form|||Prototype|object|each|push||false|target||true|elements||position|valueL||create|left|valueT|callback|Class|body|bind|Abstract|className|Insertion|tagName|pair|try|select|url|px|top|Event|Enumerable|div|case|catch|offset|useCapture|undefined|container|getValue|break|replacement|pattern|onComplete|map|else|Array|method|property|while|initialize|frequency|range|null|include|join|key|requestHeaders|offsetParent|getStyle|parameter|observers|inspect|observer|window|parentNode|text|toArray|els|width|start|args|height|throw|request||parameters|offsetTop|methods|opt|EventObserver|Position|html|offsetLeft|type|fragments|typeof|fragment|offsetHeight|oStringList|_each|apply|absolute|offsetWidth|do|cache|decay|content|input|emptyFunction|toLowerCase|end|replace|childNodes|registerCallback|display|toString|onTimerEvent|Serializers|readyState|scrollLeft|exclusive|on|delta|lastValue|getElements|in|hash|scrollTop|offsets|stripScripts|iterable|truncation|gsub|template|initializeRange|Responders|insertContent|setTimeout|json||hidden|status|navigator|ycomp|cumulativeOffset|inject||||serialize|responders|_overflow|Methods|collect|adjacency|xcomp|innerHTML|count|split|response|responseIsSuccess|success|Template|responder|dispatchException|evalScripts|pluck|concat|Request|KHTML|parent|Safari|Konqueror|dispatch|failure|receiver|observe|Observer|TimedObserver|ScriptFragment|responseText|script|inputs|ancestor|textarea|classNames|ObjectRange|node|typeName|RegExp|camelize|none|documentElement|ClassNames|relative|right|overflow|HTMLElement|parseFloat|toUpperCase|mode||currentlyExecuting|remove|__method|Base|memo||slice|returnValue|continue|setOptions|String|classNameToRemove|_reverse|page|focus|queryComponent|Hash|attachEvent|post|detachEvent|Version|reverse|encodeURIComponent|disabled|asynchronous|eval|respondToReadyState|activeRequestCount|Complete|appVersion|test|getTransport|containers|matchingInputs|1000|header|updater|Updater|getElementsByTagName|child|responderToAdd|static|tagElements|queryComponents|defaultView|onElementEvent|css|forElement|values|visibility|prepare|mergedHash|pos|offsetcache|_madePositioned|visible|tbody|findOrStore|_nativeExtensions|createElement|digits|trues|found|prepareReplacement|before|camelizedString|insertBefore|selectNodeContents|exception|falses|criteria|classNameToAdd|params|set|destination|last|addEventListener|indexOf|inline|clear|succ|_originalWidth|setLeft|Top|ActiveXObject|scriptTag|matchOne|setHeight|setTop|without|responderToRemove|_observeAndCache|find|reset|removeEventListener|activate|findFirstElement|setRequestHeaders|setWidth|XMLHttpRequest|constructor|application|xml|onCreate|contentType|Field|onStateChange|keydown|Events|evalJSON|stopObserving|inputSelector|img|Content|evalResponse|selectOne|onreadystatechange|keypress|postBody|onException|selectMany|updateContent|setInterval|insertion|PeriodicalUpdater|userAgent|updateComplete|lastText|timer|unloadCache|registerFormCallbacks|positionedOffset|register|parentElement|children|switch|XMLHTTP|_extended|hide|checkbox|update|radio|these|outerHTML|password|clientWidth|one|includeScrollOffsets|clientHeight|nodeValue|withinIncludingScrolloffsets|Try|scrollTo|realOffset|getComputedStyle|show|currentStyle|auto|deltaX|originalPosition|originalVisibility|originalWidth|originalHeight|opera|deltaY|bottom|array|_originalTop|flatten|addMethods|lambda|Toggle|toggle|insertAdjacentHTML|_originalLeft|PeriodicalExecuter|ownerDocument|createRange|createContextualFragment|contentFromAnonymousTable|table|Before|which|matchAll|button|extractScripts|stripTags|pairString|len|collapse|appendChild|After|clone|toQueryParams|Pattern|evaluate|stop|stringValue|preventDefault|charAt|_originalHeight|substring|Bottom|pairs|Function|add|collections|javascript|detect|findAll|entries|from|first|compact|keys|merge|present|toQueryString|getInputs|Msxml2|Microsoft|unregister|disable|urlencoded|blur|300|enable|responseIsFailure|Uninitialized|Loaded|Interactive|_|get|focusFirstElement|open|send|Requested|With|Accept|overrideMimeType|Connection|close|setRequestHeader|getResponseHeader|JSON|gi|submit|Loading|Success|Failure|checked|200|selectedIndex|www|selected|bMSIE|clearTimeout|unload|absolutize|string|getElementById|pageXOffset|getElementsByClassName|pageYOffset|removeChild|replaceChild|click|getHeight|hasClassName|addClassName|removeClassName|within|cleanWhitespace|nodeType|empty|childOf|multiple|change|getPropertyValue|relativize|setStyle|getDimensions|makePositioned|undoPositioned|makeClipping|KEY_BACKSPACE|undoClipping|overlap|KEY_TAB|vertical|KEY_RETURN|KEY_ESC|KEY_LEFT|horizontal|KEY_UP|member|tr|KEY_RIGHT|0_RC_0|Number|instanceof|shift|KEY_DOWN|bindAsEventListener|call|toColorPart|KEY_DELETE|times|finally|callee|srcElement|sub|scan|truncate|isLeftClick|beforeBegin|setStartBefore|im|afterBegin|firstChild|pointerX|unescapeHTML|beforeEnd|pageX|clientX|pointerY|parseQuery|afterEnd|pageY|clientY|RangeError|setStartAfter|all|any|grep|invoke|stopPropagation|max|nextSibling|min|partition|cancelBubble|reject|sortBy|sort|findElement|zip|pop|createTextNode|escapeHTML|strip'.split('|'), 0, {}) + +} /* END LOOP */ diff --git a/js/src/metrics/jint/sunspider/string-validate-input.js b/js/src/metrics/jint/sunspider/string-validate-input.js new file mode 100644 index 0000000..e6161c1 --- /dev/null +++ b/js/src/metrics/jint/sunspider/string-validate-input.js @@ -0,0 +1,99 @@ +letters = new Array("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"); +numbers = new Array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26); +colors = new Array("FF","CC","99","66","33","00"); + +var endResult; + +function doTest() +{ + endResult = ""; + + // make up email address + /* BEGIN LOOP */ + for (var k=0;k<4000;k++) + { + name = makeName(6); + (k%2)?email=name+"@mac.com":email=name+"(at)mac.com"; + + // validate the email address + var pattern = /^[a-zA-Z0-9\-\._]+@[a-zA-Z0-9\-_]+(\.?[a-zA-Z0-9\-_]*)\.[a-zA-Z]{2,3}$/; + + if(pattern.test(email)) + { + var r = email + " appears to be a valid email address."; + addResult(r); + } + else + { + r = email + " does NOT appear to be a valid email address."; + addResult(r); + } + } + /* END LOOP */ + + // make up ZIP codes + /* BEGIN LOOP */ + for (var s=0;s<4000;s++) + { + var zipGood = true; + var zip = makeNumber(4); + (s%2)?zip=zip+"xyz":zip=zip.concat("7"); + + // validate the zip code + /* BEGIN LOOP */ + for (var i = 0; i < zip.length; i++) { + var ch = zip.charAt(i); + if (ch < "0" || ch > "9") { + zipGood = false; + r = zip + " contains letters."; + addResult(r); + } + } + /* END LOOP */ + if (zipGood && zip.length>5) + { + zipGood = false; + r = zip + " is longer than five characters."; + addResult(r); + } + if (zipGood) + { + r = zip + " appears to be a valid ZIP code."; + addResult(r); + } + } + /* END LOOP */ +} + +function makeName(n) +{ + var tmp = ""; + /* BEGIN LOOP */ + for (var i=0;i= self.maxNodes: + return False + return True + + def findBestChild(self, node): + coeff = self.bias * math.log(node.visits) + bestChild = None + bestUCB = -float('Infinity') + + for child in node.children: + ucb = child.computeUCB(coeff) + if ucb >= bestUCB: + bestUCB = ucb + bestChild = child + + return child + + def playout(self, history): + queue = [] + for i in range(0, len(self.loops)): + queue.append(random.randint(0, 1)) + for node in history: + queue[node.loop] = not self.enableLoops + zash = 0 + for i in range(0, len(queue)): + if queue[i]: + zash |= (1 << i) + if zash in self.zobrist: + return self.zobrist[zash] + + self.bm.generateBanList(self.loops, queue) + result = self.bm.treeSearchRun(self.fd, ['-m', '-j'], 3) + self.zobrist[zash] = result + return result + + def step(self, loopList): + node = self.root + pending = loopList[:] + history = [node] + + while True: + # If this is a leaf node... + if node.children == None: + # And the leaf node is mature... + if node.visits >= self.maturityThreshold: + # If the node can be expanded, keep spinning. + if self.expandNode(node, pending) and node.children != None: + continue + + # Otherwise, this is a leaf node. Run a playout. + score = self.playout(history) + break + + # Find the best child. + node = self.findBestChild(node) + history.append(node) + pending.remove(node.loop) + + # Normalize the score. + origScore = score + score = (self.originalBest - score) / self.originalBest + + for node in history: + node.visits += 1 + node.score += score + + if int(origScore) < int(self.bestTime): + print('New best score: {0:f}ms'.format(origScore)) + self.combos = [history] + self.bestTime = origScore + elif int(origScore) == int(self.bestTime): + self.combos.append(history) + + def run(self): + loopList = [i for i in range(0, len(self.loops))] + self.numNodes = 1 + self.root = UCTNode(-1) + self.expandNode(self.root, loopList) + + for i in range(0, self.numPlayouts): + self.step(loopList) + + # Build the expected combination vector. + combos = [ ] + for combo in self.combos: + vec = [ ] + for i in range(0, len(self.loops)): + vec.append(int(self.enableLoops)) + for node in combo: + vec[node.loop] = int(not self.enableLoops) + combos.append(vec) + + return [self.bestTime, combos] + +class Benchmark: + def __init__(self, JS, fname): + self.fname = fname + self.JS = JS + self.stats = { } + self.runList = [ ] + + def run(self, fd, eargs): + args = [self.JS] + args.extend(eargs) + args.append(fd.name) + return subprocess.check_output(args).decode() + + # self.stats[name] = { } + # self.runList.append(name) + # for line in output.split('\n'): + # m = re.search('line (\d+): (\d+)', line) + # if m: + # self.stats[name][int(m.group(1))] = int(m.group(2)) + # else: + # m = re.search('total: (\d+)', line) + # if m: + # self.stats[name]['total'] = m.group(1) + + def winnerForLine(self, line): + best = self.runList[0] + bestTime = self.stats[best][line] + for run in self.runList[1:]: + x = self.stats[run][line] + if x < bestTime: + best = run + bestTime = x + return best + + def chart(self): + sys.stdout.write('{0:7s}'.format('')) + sys.stdout.write('{0:15s}'.format('line')) + for run in self.runList: + sys.stdout.write('{0:15s}'.format(run)) + sys.stdout.write('{0:15s}\n'.format('best')) + for c in self.counters: + sys.stdout.write('{0:10d}'.format(c)) + for run in self.runList: + sys.stdout.write('{0:15d}'.format(self.stats[run][c])) + sys.stdout.write('{0:12s}'.format('')) + sys.stdout.write('{0:15s}'.format(self.winnerForLine(c))) + sys.stdout.write('\n') + + def preprocess(self, lines, onBegin, onEnd): + stack = [] + counters = [] + rd = open(self.fname, 'rt') + for line in rd: + if re.search('\/\* BEGIN LOOP \*\/', line): + stack.append([len(lines), len(counters)]) + counters.append([len(lines), 0]) + onBegin(lines, len(lines)) + elif re.search('\/\* END LOOP \*\/', line): + old = stack.pop() + onEnd(lines, old[0], len(lines)) + counters[old[1]][1] = len(lines) + else: + lines.append(line) + return [lines, counters] + + def treeSearchRun(self, fd, args, count = 5): + total = 0 + for i in range(0, count): + output = self.run(fd, args) + total += int(output) + return total / count + + def generateBanList(self, counters, queue): + if os.path.exists('/tmp/permabans'): + os.unlink('/tmp/permabans') + fd = open('/tmp/permabans', 'wt') + for i in range(0, len(counters)): + for j in range(counters[i][0], counters[i][1] + 1): + fd.write('{0:d} {1:d}\n'.format(j, int(queue[i]))) + fd.close() + + def internalExhaustiveSearch(self, params): + counters = params['counters'] + + # iterative algorithm to explore every combination + ncombos = 2 ** len(counters) + queue = [] + for c in counters: + queue.append(0) + + fd = params['fd'] + bestTime = float('Infinity') + bestCombos = [] + + i = 0 + while i < ncombos: + temp = i + for j in range(0, len(counters)): + queue[j] = temp & 1 + temp = temp >> 1 + self.generateBanList(counters, queue) + + t = self.treeSearchRun(fd, ['-m', '-j']) + if (t < bestTime): + bestTime = t + bestCombos = [queue[:]] + print('New best time: {0:f}ms'.format(t)) + elif int(t) == int(bestTime): + bestCombos.append(queue[:]) + + i = i + 1 + + return [bestTime, bestCombos] + + def internalTreeSearch(self, params): + fd = params['fd'] + methodTime = params['methodTime'] + tracerTime = params['tracerTime'] + combinedTime = params['combinedTime'] + counters = params['counters'] + + # Build the initial loop data. + # If the method JIT already wins, disable tracing by default. + # Otherwise, enable tracing by default. + if methodTime < combinedTime: + enableLoops = True + else: + enableLoops = False + + enableLoops = False + + uct = UCT(self, combinedTime, enableLoops, counters[:], fd, 50000) + return uct.run() + + def treeSearch(self): + fd, counters = self.ppForTreeSearch() + + os.system("cat " + fd.name + " > /tmp/k.js") + + if os.path.exists('/tmp/permabans'): + os.unlink('/tmp/permabans') + methodTime = self.treeSearchRun(fd, ['-m']) + tracerTime = self.treeSearchRun(fd, ['-j']) + combinedTime = self.treeSearchRun(fd, ['-m', '-j']) + + #Get a rough estimate of how long this benchmark will take to fully compute. + upperBound = max(methodTime, tracerTime, combinedTime) + upperBound *= 2 ** len(counters) + upperBound *= 5 # Number of runs + treeSearch = False + if (upperBound < 1000): + print('Estimating {0:d}ms to test, so picking exhaustive '.format(int(upperBound)) + + 'search.') + else: + upperBound = int(upperBound / 1000) + delta = datetime.timedelta(seconds = upperBound) + if upperBound < 180: + print('Estimating {0:d}s to test, so picking exhaustive '.format(int(upperBound))) + else: + print('Estimating {0:s} to test, so picking tree search '.format(str(delta))) + treeSearch = True + + best = min(methodTime, tracerTime, combinedTime) + + params = { + 'fd': fd, + 'counters': counters, + 'methodTime': methodTime, + 'tracerTime': tracerTime, + 'combinedTime': combinedTime + } + + print('Method JIT: {0:d}ms'.format(int(methodTime))) + print('Tracing JIT: {0:d}ms'.format(int(tracerTime))) + print('Combined: {0:d}ms'.format(int(combinedTime))) + + if 1 and treeSearch: + results = self.internalTreeSearch(params) + else: + results = self.internalExhaustiveSearch(params) + + bestTime = results[0] + bestCombos = results[1] + print('Search found winning time {0:d}ms!'.format(int(bestTime))) + print('Combos at this time: {0:d}'.format(len(bestCombos))) + + #Find loops that traced every single time + for i in range(0, len(counters)): + start = counters[i][0] + end = counters[i][1] + n = len(bestCombos) + for j in bestCombos: + n -= j[i] + print('\tloop @ {0:d}-{1:d} traced {2:d}% of the time'.format( + start, end, int(n / len(bestCombos) * 100))) + + def ppForTreeSearch(self): + def onBegin(lines, lineno): + lines.append('GLOBAL_THINGY = 1;\n') + def onEnd(lines, old, lineno): + lines.append('GLOBAL_THINGY = 1;\n') + + lines = ['var JINT_START_TIME = Date.now();\n', + 'var GLOBAL_THINGY = 0;\n'] + + lines, counters = self.preprocess(lines, onBegin, onEnd) + fd = tempfile.NamedTemporaryFile('wt') + for line in lines: + fd.write(line) + fd.write('print(Date.now() - JINT_START_TIME);\n') + fd.flush() + return [fd, counters] + + def preprocessForLoopCounting(self): + def onBegin(lines, lineno): + lines.append('JINT_TRACKER.line_' + str(lineno) + '_start = Date.now();\n') + + def onEnd(lines, old, lineno): + lines.append('JINT_TRACKER.line_' + str(old) + '_end = Date.now();\n') + lines.append('JINT_TRACKER.line_' + str(old) + '_total += ' + \ + 'JINT_TRACKER.line_' + str(old) + '_end - ' + \ + 'JINT_TRACKER.line_' + str(old) + '_start;\n') + + lines, counters = self.preprocess(onBegin, onEnd) + fd = tempfile.NamedTemporaryFile('wt') + fd.write('var JINT_TRACKER = { };\n') + for c in counters: + fd.write('JINT_TRACKER.line_' + str(c) + '_start = 0;\n') + fd.write('JINT_TRACKER.line_' + str(c) + '_end = 0;\n') + fd.write('JINT_TRACKER.line_' + str(c) + '_total = 0;\n') + fd.write('JINT_TRACKER.begin = Date.now();\n') + for line in lines: + fd.write(line) + fd.write('JINT_TRACKER.total = Date.now() - JINT_TRACKER.begin;\n') + for c in self.counters: + fd.write('print("line ' + str(c) + ': " + JINT_TRACKER.line_' + str(c) + + '_total);') + fd.write('print("total: " + JINT_TRACKER.total);') + fd.flush() + return fd + +if __name__ == '__main__': + script_path = os.path.abspath(__file__) + script_dir = os.path.dirname(script_path) + test_dir = os.path.join(script_dir, 'tests') + lib_dir = os.path.join(script_dir, 'lib') + + # The [TESTS] optional arguments are paths of test files relative + # to the jit-test/tests directory. + + from optparse import OptionParser + op = OptionParser(usage='%prog [options] JS_SHELL test') + (OPTIONS, args) = op.parse_args() + if len(args) < 2: + op.error('missing JS_SHELL and test argument') + # We need to make sure we are using backslashes on Windows. + JS = realpath(args[0]) + test = realpath(args[1]) + + bm = Benchmark(JS, test) + bm.treeSearch() + # bm.preprocess() + # bm.run('mjit', ['-m']) + # bm.run('tjit', ['-j']) + # bm.run('m+tjit', ['-m', '-j']) + # bm.chart() + diff --git a/js/src/metrics/jint/v8/base.js b/js/src/metrics/jint/v8/base.js new file mode 100644 index 0000000..f8edc55 --- /dev/null +++ b/js/src/metrics/jint/v8/base.js @@ -0,0 +1,265 @@ +// Copyright 2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Simple framework for running the benchmark suites and +// computing a score based on the timing measurements. + + +// A benchmark has a name (string) and a function that will be run to +// do the performance measurement. The optional setup and tearDown +// arguments are functions that will be invoked before and after +// running the benchmark, but the running time of these functions will +// not be accounted for in the benchmark score. +function Benchmark(name, run, setup, tearDown) { + this.name = name; + this.run = run; + this.Setup = setup ? setup : function() { }; + this.TearDown = tearDown ? tearDown : function() { }; +} + + +// Benchmark results hold the benchmark and the measured time used to +// run the benchmark. The benchmark score is computed later once a +// full benchmark suite has run to completion. +function BenchmarkResult(benchmark, time) { + this.benchmark = benchmark; + this.time = time; +} + + +// Automatically convert results to numbers. Used by the geometric +// mean computation. +BenchmarkResult.prototype.valueOf = function() { + return this.time; +} + + +// Suites of benchmarks consist of a name and the set of benchmarks in +// addition to the reference timing that the final score will be based +// on. This way, all scores are relative to a reference run and higher +// scores implies better performance. +function BenchmarkSuite(name, reference, benchmarks) { + this.name = name; + this.reference = reference; + this.benchmarks = benchmarks; + BenchmarkSuite.suites.push(this); +} + + +// Keep track of all declared benchmark suites. +BenchmarkSuite.suites = []; + + +// Scores are not comparable across versions. Bump the version if +// you're making changes that will affect that scores, e.g. if you add +// a new benchmark or change an existing one. +BenchmarkSuite.version = '5'; + + +// To make the benchmark results predictable, we replace Math.random +// with a 100% deterministic alternative. +Math.random = (function() { + var seed = 49734321; + return function() { + // Robert Jenkins' 32 bit integer hash function. + seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff; + seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff; + seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff; + seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff; + seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff; + seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff; + return (seed & 0xfffffff) / 0x10000000; + }; +})(); + + +// Runs all registered benchmark suites and optionally yields between +// each individual benchmark to avoid running for too long in the +// context of browsers. Once done, the final score is reported to the +// runner. +BenchmarkSuite.RunSuites = function(runner) { + var continuation = null; + var suites = BenchmarkSuite.suites; + var length = suites.length; + BenchmarkSuite.scores = []; + var index = 0; + function RunStep() { + while (continuation || index < length) { + if (continuation) { + continuation = continuation(); + } else { + var suite = suites[index++]; + if (runner.NotifyStart) runner.NotifyStart(suite.name); + continuation = suite.RunStep(runner); + } + if (continuation && typeof window != 'undefined' && window.setTimeout) { + window.setTimeout(RunStep, 25); + return; + } + } + if (runner.NotifyScore) { + var score = BenchmarkSuite.GeometricMean(BenchmarkSuite.scores); + var formatted = BenchmarkSuite.FormatScore(100 * score); + runner.NotifyScore(formatted); + } + } + RunStep(); +} + + +// Counts the total number of registered benchmarks. Useful for +// showing progress as a percentage. +BenchmarkSuite.CountBenchmarks = function() { + var result = 0; + var suites = BenchmarkSuite.suites; + for (var i = 0; i < suites.length; i++) { + result += suites[i].benchmarks.length; + } + return result; +} + + +// Computes the geometric mean of a set of numbers. +BenchmarkSuite.GeometricMean = function(numbers) { + var log = 0; + for (var i = 0; i < numbers.length; i++) { + log += Math.log(numbers[i]); + } + return Math.pow(Math.E, log / numbers.length); +} + + +// Converts a score value to a string with at least three significant +// digits. +BenchmarkSuite.FormatScore = function(value) { + if (value > 100) { + return value.toFixed(0); + } else { + return value.toPrecision(3); + } +} + +// Notifies the runner that we're done running a single benchmark in +// the benchmark suite. This can be useful to report progress. +BenchmarkSuite.prototype.NotifyStep = function(result) { + this.results.push(result); + if (this.runner.NotifyStep) this.runner.NotifyStep(result.benchmark.name); +} + + +// Notifies the runner that we're done with running a suite and that +// we have a result which can be reported to the user if needed. +BenchmarkSuite.prototype.NotifyResult = function() { + var mean = BenchmarkSuite.GeometricMean(this.results); + var score = this.reference / mean; + BenchmarkSuite.scores.push(score); + if (this.runner.NotifyResult) { + var formatted = BenchmarkSuite.FormatScore(100 * score); + this.runner.NotifyResult(this.name, formatted); + } +} + + +// Notifies the runner that running a benchmark resulted in an error. +BenchmarkSuite.prototype.NotifyError = function(error) { + if (this.runner.NotifyError) { + this.runner.NotifyError(this.name, error); + } + if (this.runner.NotifyStep) { + this.runner.NotifyStep(this.name); + } +} + + +// Runs a single benchmark for at least a second and computes the +// average time it takes to run a single iteration. +BenchmarkSuite.prototype.RunSingleBenchmark = function(benchmark) { + var elapsed = 0; + var start = new Date(); + for (var n = 0; elapsed < 1000; n++) { + benchmark.run(); + elapsed = new Date() - start; + } + var usec = (elapsed * 1000) / n; + this.NotifyStep(new BenchmarkResult(benchmark, usec)); +} + + +// This function starts running a suite, but stops between each +// individual benchmark in the suite and returns a continuation +// function which can be invoked to run the next benchmark. Once the +// last benchmark has been executed, null is returned. +BenchmarkSuite.prototype.RunStep = function(runner) { + this.results = []; + this.runner = runner; + var length = this.benchmarks.length; + var index = 0; + var suite = this; + + // Run the setup, the actual benchmark, and the tear down in three + // separate steps to allow the framework to yield between any of the + // steps. + + function RunNextSetup() { + if (index < length) { + try { + suite.benchmarks[index].Setup(); + } catch (e) { + suite.NotifyError(e); + return null; + } + return RunNextBenchmark; + } + suite.NotifyResult(); + return null; + } + + function RunNextBenchmark() { + try { + suite.RunSingleBenchmark(suite.benchmarks[index]); + } catch (e) { + suite.NotifyError(e); + return null; + } + return RunNextTearDown; + } + + function RunNextTearDown() { + try { + suite.benchmarks[index++].TearDown(); + } catch (e) { + suite.NotifyError(e); + return null; + } + return RunNextSetup; + } + + // Start out running the setup. + return RunNextSetup(); +} + diff --git a/js/src/metrics/jint/v8/crypto.js b/js/src/metrics/jint/v8/crypto.js new file mode 100644 index 0000000..09be42b --- /dev/null +++ b/js/src/metrics/jint/v8/crypto.js @@ -0,0 +1,2135 @@ +// Copyright 2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Simple framework for running the benchmark suites and +// computing a score based on the timing measurements. + + +// A benchmark has a name (string) and a function that will be run to +// do the performance measurement. The optional setup and tearDown +// arguments are functions that will be invoked before and after +// running the benchmark, but the running time of these functions will +// not be accounted for in the benchmark score. +function Benchmark(name, run, setup, tearDown) { + this.name = name; + this.run = run; + this.Setup = setup ? setup : function() { }; + this.TearDown = tearDown ? tearDown : function() { }; +} + + +// Benchmark results hold the benchmark and the measured time used to +// run the benchmark. The benchmark score is computed later once a +// full benchmark suite has run to completion. +function BenchmarkResult(benchmark, time) { + this.benchmark = benchmark; + this.time = time; +} + + +// Automatically convert results to numbers. Used by the geometric +// mean computation. +BenchmarkResult.prototype.valueOf = function() { + return this.time; +} + + +// Suites of benchmarks consist of a name and the set of benchmarks in +// addition to the reference timing that the final score will be based +// on. This way, all scores are relative to a reference run and higher +// scores implies better performance. +function BenchmarkSuite(name, reference, benchmarks) { + this.name = name; + this.reference = reference; + this.benchmarks = benchmarks; + BenchmarkSuite.suites.push(this); +} + + +// Keep track of all declared benchmark suites. +BenchmarkSuite.suites = []; + + +// Scores are not comparable across versions. Bump the version if +// you're making changes that will affect that scores, e.g. if you add +// a new benchmark or change an existing one. +BenchmarkSuite.version = '5'; + + +// To make the benchmark results predictable, we replace Math.random +// with a 100% deterministic alternative. +Math.random = (function() { + var seed = 49734321; + return function() { + // Robert Jenkins' 32 bit integer hash function. + seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff; + seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff; + seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff; + seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff; + seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff; + seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff; + return (seed & 0xfffffff) / 0x10000000; + }; +})(); + + +// Runs all registered benchmark suites and optionally yields between +// each individual benchmark to avoid running for too long in the +// context of browsers. Once done, the final score is reported to the +// runner. +BenchmarkSuite.RunSuites = function(runner) { + var continuation = null; + var suites = BenchmarkSuite.suites; + var length = suites.length; + BenchmarkSuite.scores = []; + var index = 0; + function RunStep() { + while (continuation || index < length) { + if (continuation) { + continuation = continuation(); + } else { + var suite = suites[index++]; + if (runner.NotifyStart) runner.NotifyStart(suite.name); + continuation = suite.RunStep(runner); + } + if (continuation && typeof window != 'undefined' && window.setTimeout) { + window.setTimeout(RunStep, 25); + return; + } + } + if (runner.NotifyScore) { + var score = BenchmarkSuite.GeometricMean(BenchmarkSuite.scores); + var formatted = BenchmarkSuite.FormatScore(100 * score); + runner.NotifyScore(formatted); + } + } + RunStep(); +} + + +// Counts the total number of registered benchmarks. Useful for +// showing progress as a percentage. +BenchmarkSuite.CountBenchmarks = function() { + var result = 0; + var suites = BenchmarkSuite.suites; + for (var i = 0; i < suites.length; i++) { + result += suites[i].benchmarks.length; + } + return result; +} + + +// Computes the geometric mean of a set of numbers. +BenchmarkSuite.GeometricMean = function(numbers) { + var log = 0; + for (var i = 0; i < numbers.length; i++) { + log += Math.log(numbers[i]); + } + return Math.pow(Math.E, log / numbers.length); +} + + +// Converts a score value to a string with at least three significant +// digits. +BenchmarkSuite.FormatScore = function(value) { + if (value > 100) { + return value.toFixed(0); + } else { + return value.toPrecision(3); + } +} + +// Notifies the runner that we're done running a single benchmark in +// the benchmark suite. This can be useful to report progress. +BenchmarkSuite.prototype.NotifyStep = function(result) { + this.results.push(result); + if (this.runner.NotifyStep) this.runner.NotifyStep(result.benchmark.name); +} + + +// Notifies the runner that we're done with running a suite and that +// we have a result which can be reported to the user if needed. +BenchmarkSuite.prototype.NotifyResult = function() { + var mean = BenchmarkSuite.GeometricMean(this.results); + var score = this.reference / mean; + BenchmarkSuite.scores.push(score); + if (this.runner.NotifyResult) { + var formatted = BenchmarkSuite.FormatScore(100 * score); + this.runner.NotifyResult(this.name, formatted); + } +} + + +// Notifies the runner that running a benchmark resulted in an error. +BenchmarkSuite.prototype.NotifyError = function(error) { + if (this.runner.NotifyError) { + this.runner.NotifyError(this.name, error); + } + if (this.runner.NotifyStep) { + this.runner.NotifyStep(this.name); + } +} + + +// Runs a single benchmark for at least a second and computes the +// average time it takes to run a single iteration. +BenchmarkSuite.prototype.RunSingleBenchmark = function(benchmark) { + var elapsed = 0; + var start = new Date(); + for (var n = 0; elapsed < 20; n++) { + benchmark.run(); + elapsed = new Date() - start; + } + var usec = (elapsed * 1000) / n; + this.NotifyStep(new BenchmarkResult(benchmark, usec)); +} + + +// This function starts running a suite, but stops between each +// individual benchmark in the suite and returns a continuation +// function which can be invoked to run the next benchmark. Once the +// last benchmark has been executed, null is returned. +BenchmarkSuite.prototype.RunStep = function(runner) { + this.results = []; + this.runner = runner; + var length = this.benchmarks.length; + var index = 0; + var suite = this; + + // Run the setup, the actual benchmark, and the tear down in three + // separate steps to allow the framework to yield between any of the + // steps. + + function RunNextSetup() { + if (index < length) { + try { + suite.benchmarks[index].Setup(); + } catch (e) { + suite.NotifyError(e); + return null; + } + return RunNextBenchmark; + } + suite.NotifyResult(); + return null; + } + + function RunNextBenchmark() { + try { + suite.RunSingleBenchmark(suite.benchmarks[index]); + } catch (e) { + suite.NotifyError(e); + return null; + } + return RunNextTearDown; + } + + function RunNextTearDown() { + try { + suite.benchmarks[index++].TearDown(); + } catch (e) { + suite.NotifyError(e); + return null; + } + return RunNextSetup; + } + + // Start out running the setup. + return RunNextSetup(); +} + +/* + * Copyright (c) 2003-2005 Tom Wu + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * In addition, the following condition applies: + * + * All redistributions must retain an intact copy of this copyright notice + * and disclaimer. + */ + + +// The code has been adapted for use as a benchmark by Google. +var Crypto = new BenchmarkSuite('Crypto', 203037, [ + new Benchmark("Encrypt", encrypt), + new Benchmark("Decrypt", decrypt) +]); + + +// Basic JavaScript BN library - subset useful for RSA encryption. + +// Bits per digit +var dbits; +var BI_DB; +var BI_DM; +var BI_DV; + +var BI_FP; +var BI_FV; +var BI_F1; +var BI_F2; + +// JavaScript engine analysis +var canary = 0xdeadbeefcafe; +var j_lm = ((canary&0xffffff)==0xefcafe); + +// (public) Constructor +function BigInteger(a,b,c) { + this.array = new Array(); + if(a != null) + if("number" == typeof a) this.fromNumber(a,b,c); + else if(b == null && "string" != typeof a) this.fromString(a,256); + else this.fromString(a,b); +} + +// return new, unset BigInteger +function nbi() { return new BigInteger(null); } + +// am: Compute w_j += (x*this_i), propagate carries, +// c is initial carry, returns final carry. +// c < 3*dvalue, x < 2*dvalue, this_i < dvalue +// We need to select the fastest one that works in this environment. + +// am1: use a single mult and divide to get the high bits, +// max digit bits should be 26 because +// max internal value = 2*dvalue^2-2*dvalue (< 2^53) +function am1(i,x,w,j,c,n) { + var this_array = this.array; + var w_array = w.array; + /* BEGIN LOOP */ + while(--n >= 0) { + var v = x*this_array[i++]+w_array[j]+c; + c = Math.floor(v/0x4000000); + w_array[j++] = v&0x3ffffff; + } + /* END LOOP */ + return c; +} + +// am2 avoids a big mult-and-extract completely. +// Max digit bits should be <= 30 because we do bitwise ops +// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) +function am2(i,x,w,j,c,n) { + var this_array = this.array; + var w_array = w.array; + var xl = x&0x7fff, xh = x>>15; + /* BEGIN LOOP */ + while(--n >= 0) { + var l = this_array[i]&0x7fff; + var h = this_array[i++]>>15; + var m = xh*l+h*xl; + l = xl*l+((m&0x7fff)<<15)+w_array[j]+(c&0x3fffffff); + c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); + w_array[j++] = l&0x3fffffff; + } + /* END LOOP */ + return c; +} + +// Alternately, set max digit bits to 28 since some +// browsers slow down when dealing with 32-bit numbers. +function am3(i,x,w,j,c,n) { + var this_array = this.array; + var w_array = w.array; + + var xl = x&0x3fff, xh = x>>14; + /* BEGIN LOOP */ + while(--n >= 0) { + var l = this_array[i]&0x3fff; + var h = this_array[i++]>>14; + var m = xh*l+h*xl; + l = xl*l+((m&0x3fff)<<14)+w_array[j]+c; + c = (l>>28)+(m>>14)+xh*h; + w_array[j++] = l&0xfffffff; + } + /* END LOOP */ + return c; +} + +// This is tailored to VMs with 2-bit tagging. It makes sure +// that all the computations stay within the 29 bits available. +function am4(i,x,w,j,c,n) { + var this_array = this.array; + var w_array = w.array; + + var xl = x&0x1fff, xh = x>>13; + /* BEGIN LOOP */ + while(--n >= 0) { + var l = this_array[i]&0x1fff; + var h = this_array[i++]>>13; + var m = xh*l+h*xl; + l = xl*l+((m&0x1fff)<<13)+w_array[j]+c; + c = (l>>26)+(m>>13)+xh*h; + w_array[j++] = l&0x3ffffff; + } + /* END LOOP */ + return c; +} + +// am3/28 is best for SM, Rhino, but am4/26 is best for v8. +// Kestrel (Opera 9.5) gets its best result with am4/26. +// IE7 does 9% better with am3/28 than with am4/26. +// Firefox (SM) gets 10% faster with am3/28 than with am4/26. + +setupEngine = function(fn, bits) { + BigInteger.prototype.am = fn; + dbits = bits; + + BI_DB = dbits; + BI_DM = ((1<= 0; --i) r_array[i] = this_array[i]; + /* END LOOP */ + r.t = this.t; + r.s = this.s; +} + +// (protected) set from integer value x, -DV <= x < DV +function bnpFromInt(x) { + var this_array = this.array; + this.t = 1; + this.s = (x<0)?-1:0; + if(x > 0) this_array[0] = x; + else if(x < -1) this_array[0] = x+DV; + else this.t = 0; +} + +// return bigint initialized to value +function nbv(i) { var r = nbi(); r.fromInt(i); return r; } + +// (protected) set from string and radix +function bnpFromString(s,b) { + var this_array = this.array; + var k; + if(b == 16) k = 4; + else if(b == 8) k = 3; + else if(b == 256) k = 8; // byte array + else if(b == 2) k = 1; + else if(b == 32) k = 5; + else if(b == 4) k = 2; + else { this.fromRadix(s,b); return; } + this.t = 0; + this.s = 0; + var i = s.length, mi = false, sh = 0; + /* BEGIN LOOP */ + while(--i >= 0) { + var x = (k==8)?s[i]&0xff:intAt(s,i); + if(x < 0) { + if(s.charAt(i) == "-") mi = true; + continue; + } + mi = false; + if(sh == 0) + this_array[this.t++] = x; + else if(sh+k > BI_DB) { + this_array[this.t-1] |= (x&((1<<(BI_DB-sh))-1))<>(BI_DB-sh)); + } + else + this_array[this.t-1] |= x<= BI_DB) sh -= BI_DB; + } + /* END LOOP */ + if(k == 8 && (s[0]&0x80) != 0) { + this.s = -1; + if(sh > 0) this_array[this.t-1] |= ((1<<(BI_DB-sh))-1)< 0 && this_array[this.t-1] == c) --this.t; + /* END LOOP */ +} + +// (public) return string representation in given radix +function bnToString(b) { + var this_array = this.array; + if(this.s < 0) return "-"+this.negate().toString(b); + var k; + if(b == 16) k = 4; + else if(b == 8) k = 3; + else if(b == 2) k = 1; + else if(b == 32) k = 5; + else if(b == 4) k = 2; + else return this.toRadix(b); + var km = (1< 0) { + if(p < BI_DB && (d = this_array[i]>>p) > 0) { m = true; r = int2char(d); } + /* BEGIN LOOP */ + while(i >= 0) { + if(p < k) { + d = (this_array[i]&((1<>(p+=BI_DB-k); + } + else { + d = (this_array[i]>>(p-=k))&km; + if(p <= 0) { p += BI_DB; --i; } + } + if(d > 0) m = true; + if(m) r += int2char(d); + } + /* END LOOP */ + } + return m?r:"0"; +} + +// (public) -this +function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; } + +// (public) |this| +function bnAbs() { return (this.s<0)?this.negate():this; } + +// (public) return + if this > a, - if this < a, 0 if equal +function bnCompareTo(a) { + var this_array = this.array; + var a_array = a.array; + + var r = this.s-a.s; + if(r != 0) return r; + var i = this.t; + r = i-a.t; + if(r != 0) return r; + /* BEGIN LOOP */ + while(--i >= 0) if((r=this_array[i]-a_array[i]) != 0) return r; + /* END LOOP */ + return 0; +} + +// returns bit length of the integer x +function nbits(x) { + var r = 1, t; + if((t=x>>>16) != 0) { x = t; r += 16; } + if((t=x>>8) != 0) { x = t; r += 8; } + if((t=x>>4) != 0) { x = t; r += 4; } + if((t=x>>2) != 0) { x = t; r += 2; } + if((t=x>>1) != 0) { x = t; r += 1; } + return r; +} + +// (public) return the number of bits in "this" +function bnBitLength() { + var this_array = this.array; + if(this.t <= 0) return 0; + return BI_DB*(this.t-1)+nbits(this_array[this.t-1]^(this.s&BI_DM)); +} + +// (protected) r = this << n*DB +function bnpDLShiftTo(n,r) { + var this_array = this.array; + var r_array = r.array; + var i; + /* BEGIN LOOP */ + for(i = this.t-1; i >= 0; --i) r_array[i+n] = this_array[i]; + /* END LOOP */ + /* BEGIN LOOP */ + for(i = n-1; i >= 0; --i) r_array[i] = 0; + /* END LOOP */ + r.t = this.t+n; + r.s = this.s; +} + +// (protected) r = this >> n*DB +function bnpDRShiftTo(n,r) { + var this_array = this.array; + var r_array = r.array; + /* BEGIN LOOP */ + for(var i = n; i < this.t; ++i) r_array[i-n] = this_array[i]; + /* END LOOP */ + r.t = Math.max(this.t-n,0); + r.s = this.s; +} + +// (protected) r = this << n +function bnpLShiftTo(n,r) { + var this_array = this.array; + var r_array = r.array; + var bs = n%BI_DB; + var cbs = BI_DB-bs; + var bm = (1<= 0; --i) { + r_array[i+ds+1] = (this_array[i]>>cbs)|c; + c = (this_array[i]&bm)<= 0; --i) r_array[i] = 0; + /* END LOOP */ + r_array[ds] = c; + r.t = this.t+ds+1; + r.s = this.s; + r.clamp(); +} + +// (protected) r = this >> n +function bnpRShiftTo(n,r) { + var this_array = this.array; + var r_array = r.array; + r.s = this.s; + var ds = Math.floor(n/BI_DB); + if(ds >= this.t) { r.t = 0; return; } + var bs = n%BI_DB; + var cbs = BI_DB-bs; + var bm = (1<>bs; + /* BEGIN LOOP */ + for(var i = ds+1; i < this.t; ++i) { + r_array[i-ds-1] |= (this_array[i]&bm)<>bs; + } + /* END LOOP */ + if(bs > 0) r_array[this.t-ds-1] |= (this.s&bm)<>= BI_DB; + } + /* END LOOP */ + if(a.t < this.t) { + c -= a.s; + /* BEGIN LOOP */ + while(i < this.t) { + c += this_array[i]; + r_array[i++] = c&BI_DM; + c >>= BI_DB; + } + /* END LOOP */ + c += this.s; + } + else { + c += this.s; + /* BEGIN LOOP */ + while(i < a.t) { + c -= a_array[i]; + r_array[i++] = c&BI_DM; + c >>= BI_DB; + } + /* END LOOP */ + c -= a.s; + } + r.s = (c<0)?-1:0; + if(c < -1) r_array[i++] = BI_DV+c; + else if(c > 0) r_array[i++] = c; + r.t = i; + r.clamp(); +} + +// (protected) r = this * a, r != this,a (HAC 14.12) +// "this" should be the larger one if appropriate. +function bnpMultiplyTo(a,r) { + var this_array = this.array; + var r_array = r.array; + var x = this.abs(), y = a.abs(); + var y_array = y.array; + + var i = x.t; + r.t = i+y.t; + /* BEGIN LOOP */ + while(--i >= 0) r_array[i] = 0; + /* END LOOP */ + /* BEGIN LOOP */ + for(i = 0; i < y.t; ++i) r_array[i+x.t] = x.am(0,y_array[i],r,i,0,x.t); + r.s = 0; + r.clamp(); + if(this.s != a.s) BigInteger.ZERO.subTo(r,r); +} + +// (protected) r = this^2, r != this (HAC 14.16) +function bnpSquareTo(r) { + var x = this.abs(); + var x_array = x.array; + var r_array = r.array; + + var i = r.t = 2*x.t; + /* BEGIN LOOP */ + while(--i >= 0) r_array[i] = 0; + /* END LOOP */ + /* BEGIN LOOP */ + for(i = 0; i < x.t-1; ++i) { + var c = x.am(i,x_array[i],r,2*i,0,1); + if((r_array[i+x.t]+=x.am(i+1,2*x_array[i],r,2*i+1,c,x.t-i-1)) >= BI_DV) { + r_array[i+x.t] -= BI_DV; + r_array[i+x.t+1] = 1; + } + } + /* END LOOP */ + if(r.t > 0) r_array[r.t-1] += x.am(i,x_array[i],r,2*i,0,1); + r.s = 0; + r.clamp(); +} + +// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) +// r != q, this != m. q or r may be null. +function bnpDivRemTo(m,q,r) { + var pm = m.abs(); + if(pm.t <= 0) return; + var pt = this.abs(); + if(pt.t < pm.t) { + if(q != null) q.fromInt(0); + if(r != null) this.copyTo(r); + return; + } + if(r == null) r = nbi(); + var y = nbi(), ts = this.s, ms = m.s; + var pm_array = pm.array; + var nsh = BI_DB-nbits(pm_array[pm.t-1]); // normalize modulus + if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } + else { pm.copyTo(y); pt.copyTo(r); } + var ys = y.t; + + var y_array = y.array; + var y0 = y_array[ys-1]; + if(y0 == 0) return; + var yt = y0*(1<1)?y_array[ys-2]>>BI_F2:0); + var d1 = BI_FV/yt, d2 = (1<= 0) { + r_array[r.t++] = 1; + r.subTo(t,r); + } + BigInteger.ONE.dlShiftTo(ys,t); + t.subTo(y,y); // "negative" y so we can replace sub with am later + /* BEGIN LOOP */ + while(y.t < ys) y_array[y.t++] = 0; + /* END LOOP */ + /* BEGIN LOOP */ + while(--j >= 0) { + // Estimate quotient digit + var qd = (r_array[--i]==y0)?BI_DM:Math.floor(r_array[i]*d1+(r_array[i-1]+e)*d2); + if((r_array[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out + y.dlShiftTo(j,t); + r.subTo(t,r); + /* BEGIN LOOP */ + while(r_array[i] < --qd) r.subTo(t,r); + /* END LOOP */ + } + } + /* END LOOP */ + if(q != null) { + r.drShiftTo(ys,q); + if(ts != ms) BigInteger.ZERO.subTo(q,q); + } + r.t = ys; + r.clamp(); + if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder + if(ts < 0) BigInteger.ZERO.subTo(r,r); +} + +// (public) this mod a +function bnMod(a) { + var r = nbi(); + this.abs().divRemTo(a,null,r); + if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r); + return r; +} + +// Modular reduction using "classic" algorithm +function Classic(m) { this.m = m; } +function cConvert(x) { + if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); + else return x; +} +function cRevert(x) { return x; } +function cReduce(x) { x.divRemTo(this.m,null,x); } +function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } +function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +Classic.prototype.convert = cConvert; +Classic.prototype.revert = cRevert; +Classic.prototype.reduce = cReduce; +Classic.prototype.mulTo = cMulTo; +Classic.prototype.sqrTo = cSqrTo; + +// (protected) return "-1/this % 2^DB"; useful for Mont. reduction +// justification: +// xy == 1 (mod m) +// xy = 1+km +// xy(2-xy) = (1+km)(1-km) +// x[y(2-xy)] = 1-k^2m^2 +// x[y(2-xy)] == 1 (mod m^2) +// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 +// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. +// JS multiply "overflows" differently from C/C++, so care is needed here. +function bnpInvDigit() { + var this_array = this.array; + if(this.t < 1) return 0; + var x = this_array[0]; + if((x&1) == 0) return 0; + var y = x&3; // y == 1/x mod 2^2 + y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 + y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 + y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 + // last step - calculate inverse mod DV directly; + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints + y = (y*(2-x*y%BI_DV))%BI_DV; // y == 1/x mod 2^dbits + // we really want the negative inverse, and -DV < y < DV + return (y>0)?BI_DV-y:-y; +} + +// Montgomery reduction +function Montgomery(m) { + this.m = m; + this.mp = m.invDigit(); + this.mpl = this.mp&0x7fff; + this.mph = this.mp>>15; + this.um = (1<<(BI_DB-15))-1; + this.mt2 = 2*m.t; +} + +// xR mod m +function montConvert(x) { + var r = nbi(); + x.abs().dlShiftTo(this.m.t,r); + r.divRemTo(this.m,null,r); + if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r); + return r; +} + +// x/R mod m +function montRevert(x) { + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; +} + +// x = x/R mod m (HAC 14.32) +function montReduce(x) { + var x_array = x.array; + /* BEGIN LOOP */ + while(x.t <= this.mt2) // pad x so am has enough room later + x_array[x.t++] = 0; + /* END LOOP */ + /* BEGIN LOOP */ + for(var i = 0; i < this.m.t; ++i) { + // faster way of calculating u0 = x[i]*mp mod DV + var j = x_array[i]&0x7fff; + var u0 = (j*this.mpl+(((j*this.mph+(x_array[i]>>15)*this.mpl)&this.um)<<15))&BI_DM; + // use am to combine the multiply-shift-add into one call + j = i+this.m.t; + x_array[j] += this.m.am(0,u0,x,i,0,this.m.t); + // propagate carry + /* BEGIN LOOP */ + while(x_array[j] >= BI_DV) { x_array[j] -= BI_DV; x_array[++j]++; } + /* BEGIN LOOP */ + } + /* END LOOP */ + x.clamp(); + x.drShiftTo(this.m.t,x); + if(x.compareTo(this.m) >= 0) x.subTo(this.m,x); +} + +// r = "x^2/R mod m"; x != r +function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +// r = "xy/R mod m"; x,y != r +function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + +Montgomery.prototype.convert = montConvert; +Montgomery.prototype.revert = montRevert; +Montgomery.prototype.reduce = montReduce; +Montgomery.prototype.mulTo = montMulTo; +Montgomery.prototype.sqrTo = montSqrTo; + +// (protected) true iff this is even +function bnpIsEven() { + var this_array = this.array; + return ((this.t>0)?(this_array[0]&1):this.s) == 0; +} + +// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) +function bnpExp(e,z) { + if(e > 0xffffffff || e < 1) return BigInteger.ONE; + var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; + g.copyTo(r); + /* BEGIN LOOP */ + while(--i >= 0) { + z.sqrTo(r,r2); + if((e&(1< 0) z.mulTo(r2,g,r); + else { var t = r; r = r2; r2 = t; } + } + /* END LOOP */ + return z.revert(r); +} + +// (public) this^e % m, 0 <= e < 2^32 +function bnModPowInt(e,m) { + var z; + if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); + return this.exp(e,z); +} + +// protected +BigInteger.prototype.copyTo = bnpCopyTo; +BigInteger.prototype.fromInt = bnpFromInt; +BigInteger.prototype.fromString = bnpFromString; +BigInteger.prototype.clamp = bnpClamp; +BigInteger.prototype.dlShiftTo = bnpDLShiftTo; +BigInteger.prototype.drShiftTo = bnpDRShiftTo; +BigInteger.prototype.lShiftTo = bnpLShiftTo; +BigInteger.prototype.rShiftTo = bnpRShiftTo; +BigInteger.prototype.subTo = bnpSubTo; +BigInteger.prototype.multiplyTo = bnpMultiplyTo; +BigInteger.prototype.squareTo = bnpSquareTo; +BigInteger.prototype.divRemTo = bnpDivRemTo; +BigInteger.prototype.invDigit = bnpInvDigit; +BigInteger.prototype.isEven = bnpIsEven; +BigInteger.prototype.exp = bnpExp; + +// public +BigInteger.prototype.toString = bnToString; +BigInteger.prototype.negate = bnNegate; +BigInteger.prototype.abs = bnAbs; +BigInteger.prototype.compareTo = bnCompareTo; +BigInteger.prototype.bitLength = bnBitLength; +BigInteger.prototype.mod = bnMod; +BigInteger.prototype.modPowInt = bnModPowInt; + +// "constants" +BigInteger.ZERO = nbv(0); +BigInteger.ONE = nbv(1); +// Copyright (c) 2005 Tom Wu +// All Rights Reserved. +// See "LICENSE" for details. + +// Extended JavaScript BN functions, required for RSA private ops. + +// (public) +function bnClone() { var r = nbi(); this.copyTo(r); return r; } + +// (public) return value as integer +function bnIntValue() { + var this_array = this.array; + if(this.s < 0) { + if(this.t == 1) return this_array[0]-BI_DV; + else if(this.t == 0) return -1; + } + else if(this.t == 1) return this_array[0]; + else if(this.t == 0) return 0; + // assumes 16 < DB < 32 + return ((this_array[1]&((1<<(32-BI_DB))-1))<>24; +} + +// (public) return value as short (assumes DB>=16) +function bnShortValue() { + var this_array = this.array; + return (this.t==0)?this.s:(this_array[0]<<16)>>16; +} + +// (protected) return x s.t. r^x < DV +function bnpChunkSize(r) { return Math.floor(Math.LN2*BI_DB/Math.log(r)); } + +// (public) 0 if this == 0, 1 if this > 0 +function bnSigNum() { + var this_array = this.array; + if(this.s < 0) return -1; + else if(this.t <= 0 || (this.t == 1 && this_array[0] <= 0)) return 0; + else return 1; +} + +// (protected) convert to radix string +function bnpToRadix(b) { + if(b == null) b = 10; + if(this.signum() == 0 || b < 2 || b > 36) return "0"; + var cs = this.chunkSize(b); + var a = Math.pow(b,cs); + var d = nbv(a), y = nbi(), z = nbi(), r = ""; + this.divRemTo(d,y,z); + /* BEGIN LOOP */ + while(y.signum() > 0) { + r = (a+z.intValue()).toString(b).substr(1) + r; + y.divRemTo(d,y,z); + } + /* END LOOP */ + return z.intValue().toString(b) + r; +} + +// (protected) convert from radix string +function bnpFromRadix(s,b) { + this.fromInt(0); + if(b == null) b = 10; + var cs = this.chunkSize(b); + var d = Math.pow(b,cs), mi = false, j = 0, w = 0; + /* BEGIN LOOP */ + for(var i = 0; i < s.length; ++i) { + var x = intAt(s,i); + if(x < 0) { + if(s.charAt(i) == "-" && this.signum() == 0) mi = true; + continue; + } + w = b*w+x; + if(++j >= cs) { + this.dMultiply(d); + this.dAddOffset(w,0); + j = 0; + w = 0; + } + } + /* END LOOP */ + if(j > 0) { + this.dMultiply(Math.pow(b,j)); + this.dAddOffset(w,0); + } + if(mi) BigInteger.ZERO.subTo(this,this); +} + +// (protected) alternate constructor +function bnpFromNumber(a,b,c) { + if("number" == typeof b) { + // new BigInteger(int,int,RNG) + if(a < 2) this.fromInt(1); + else { + this.fromNumber(a,c); + if(!this.testBit(a-1)) // force MSB set + this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this); + if(this.isEven()) this.dAddOffset(1,0); // force odd + /* BEGIN LOOP */ + while(!this.isProbablePrime(b)) { + this.dAddOffset(2,0); + if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this); + } + /* END LOOP */ + } + } + else { + // new BigInteger(int,RNG) + var x = new Array(), t = a&7; + x.length = (a>>3)+1; + b.nextBytes(x); + if(t > 0) x[0] &= ((1< 0) { + if(p < BI_DB && (d = this_array[i]>>p) != (this.s&BI_DM)>>p) + r[k++] = d|(this.s<<(BI_DB-p)); + /* BEGIN LOOP */ + while(i >= 0) { + if(p < 8) { + d = (this_array[i]&((1<>(p+=BI_DB-8); + } + else { + d = (this_array[i]>>(p-=8))&0xff; + if(p <= 0) { p += BI_DB; --i; } + } + if((d&0x80) != 0) d |= -256; + if(k == 0 && (this.s&0x80) != (d&0x80)) ++k; + if(k > 0 || d != this.s) r[k++] = d; + } + /* END LOOP */ + } + return r; +} + +function bnEquals(a) { return(this.compareTo(a)==0); } +function bnMin(a) { return(this.compareTo(a)<0)?this:a; } +function bnMax(a) { return(this.compareTo(a)>0)?this:a; } + +// (protected) r = this op a (bitwise) +function bnpBitwiseTo(a,op,r) { + var this_array = this.array; + var a_array = a.array; + var r_array = r.array; + var i, f, m = Math.min(a.t,this.t); + /* BEGIN LOOP */ + for(i = 0; i < m; ++i) r_array[i] = op(this_array[i],a_array[i]); + /* END LOOP */ + if(a.t < this.t) { + f = a.s&BI_DM; + /* BEGIN LOOP */ + for(i = m; i < this.t; ++i) r_array[i] = op(this_array[i],f); + /* END LOOP */ + r.t = this.t; + } + else { + f = this.s&BI_DM; + /* BEGIN LOOP */ + for(i = m; i < a.t; ++i) r_array[i] = op(f,a_array[i]); + /* END LOOP */ + r.t = a.t; + } + r.s = op(this.s,a.s); + r.clamp(); +} + +// (public) this & a +function op_and(x,y) { return x&y; } +function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; } + +// (public) this | a +function op_or(x,y) { return x|y; } +function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; } + +// (public) this ^ a +function op_xor(x,y) { return x^y; } +function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; } + +// (public) this & ~a +function op_andnot(x,y) { return x&~y; } +function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; } + +// (public) ~this +function bnNot() { + var this_array = this.array; + var r = nbi(); + var r_array = r.array; + + /* BEGIN LOOP */ + for(var i = 0; i < this.t; ++i) r_array[i] = BI_DM&~this_array[i]; + /* END LOOP */ + r.t = this.t; + r.s = ~this.s; + return r; +} + +// (public) this << n +function bnShiftLeft(n) { + var r = nbi(); + if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r); + return r; +} + +// (public) this >> n +function bnShiftRight(n) { + var r = nbi(); + if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r); + return r; +} + +// return index of lowest 1-bit in x, x < 2^31 +function lbit(x) { + if(x == 0) return -1; + var r = 0; + if((x&0xffff) == 0) { x >>= 16; r += 16; } + if((x&0xff) == 0) { x >>= 8; r += 8; } + if((x&0xf) == 0) { x >>= 4; r += 4; } + if((x&3) == 0) { x >>= 2; r += 2; } + if((x&1) == 0) ++r; + return r; +} + +// (public) returns index of lowest 1-bit (or -1 if none) +function bnGetLowestSetBit() { + var this_array = this.array; + /* BEGIN LOOP */ + for(var i = 0; i < this.t; ++i) + if(this_array[i] != 0) return i*BI_DB+lbit(this_array[i]); + /* END LOOP */ + if(this.s < 0) return this.t*BI_DB; + return -1; +} + +// return number of 1 bits in x +function cbit(x) { + var r = 0; + /* BEGIN LOOP */ + while(x != 0) { x &= x-1; ++r; } + /* END LOOP */ + return r; +} + +// (public) return number of set bits +function bnBitCount() { + var r = 0, x = this.s&BI_DM; + /* BEGIN LOOP */ + for(var i = 0; i < this.t; ++i) r += cbit(this_array[i]^x); + /* END LOOP */ + return r; +} + +// (public) true iff nth bit is set +function bnTestBit(n) { + var this_array = this.array; + var j = Math.floor(n/BI_DB); + if(j >= this.t) return(this.s!=0); + return((this_array[j]&(1<<(n%BI_DB)))!=0); +} + +// (protected) this op (1<>= BI_DB; + } + /* END LOOP */ + if(a.t < this.t) { + c += a.s; + /* BEGIN LOOP */ + while(i < this.t) { + c += this_array[i]; + r_array[i++] = c&BI_DM; + c >>= BI_DB; + } + /* END LOOP */ + c += this.s; + } + else { + c += this.s; + /* BEGIN LOOP */ + while(i < a.t) { + c += a_array[i]; + r_array[i++] = c&BI_DM; + c >>= BI_DB; + } + /* END LOOP */ + c += a.s; + } + r.s = (c<0)?-1:0; + if(c > 0) r_array[i++] = c; + else if(c < -1) r_array[i++] = BI_DV+c; + r.t = i; + r.clamp(); +} + +// (public) this + a +function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; } + +// (public) this - a +function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; } + +// (public) this * a +function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; } + +// (public) this / a +function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; } + +// (public) this % a +function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; } + +// (public) [this/a,this%a] +function bnDivideAndRemainder(a) { + var q = nbi(), r = nbi(); + this.divRemTo(a,q,r); + return new Array(q,r); +} + +// (protected) this *= n, this >= 0, 1 < n < DV +function bnpDMultiply(n) { + var this_array = this.array; + this_array[this.t] = this.am(0,n-1,this,0,0,this.t); + ++this.t; + this.clamp(); +} + +// (protected) this += n << w words, this >= 0 +function bnpDAddOffset(n,w) { + var this_array = this.array; + /* BEGIN LOOP */ + while(this.t <= w) this_array[this.t++] = 0; + /* END LOOP */ + this_array[w] += n; + /* BEGIN LOOP */ + while(this_array[w] >= BI_DV) { + this_array[w] -= BI_DV; + if(++w >= this.t) this_array[this.t++] = 0; + ++this_array[w]; + } + /* END LOOP */ +} + +// A "null" reducer +function NullExp() {} +function nNop(x) { return x; } +function nMulTo(x,y,r) { x.multiplyTo(y,r); } +function nSqrTo(x,r) { x.squareTo(r); } + +NullExp.prototype.convert = nNop; +NullExp.prototype.revert = nNop; +NullExp.prototype.mulTo = nMulTo; +NullExp.prototype.sqrTo = nSqrTo; + +// (public) this^e +function bnPow(e) { return this.exp(e,new NullExp()); } + +// (protected) r = lower n words of "this * a", a.t <= n +// "this" should be the larger one if appropriate. +function bnpMultiplyLowerTo(a,n,r) { + var r_array = r.array; + var a_array = a.array; + var i = Math.min(this.t+a.t,n); + r.s = 0; // assumes a,this >= 0 + r.t = i; + /* BEGIN LOOP */ + while(i > 0) r_array[--i] = 0; + /* END LOOP */ + var j; + /* BEGIN LOOP */ + for(j = r.t-this.t; i < j; ++i) r_array[i+this.t] = this.am(0,a_array[i],r,i,0,this.t); + /* END LOOP */ + /* BEGIN LOOP */ + for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a_array[i],r,i,0,n-i); + /* END LOOP */ + r.clamp(); +} + +// (protected) r = "this * a" without lower n words, n > 0 +// "this" should be the larger one if appropriate. +function bnpMultiplyUpperTo(a,n,r) { + var r_array = r.array; + var a_array = a.array; + --n; + var i = r.t = this.t+a.t-n; + r.s = 0; // assumes a,this >= 0 + /* BEGIN LOOP */ + while(--i >= 0) r_array[i] = 0; + /* END LOOP */ + /* BEGIN LOOP */ + for(i = Math.max(n-this.t,0); i < a.t; ++i) + r_array[this.t+i-n] = this.am(n-i,a_array[i],r,0,0,this.t+i-n); + /* END LOOP */ + r.clamp(); + r.drShiftTo(1,r); +} + +// Barrett modular reduction +function Barrett(m) { + // setup Barrett + this.r2 = nbi(); + this.q3 = nbi(); + BigInteger.ONE.dlShiftTo(2*m.t,this.r2); + this.mu = this.r2.divide(m); + this.m = m; +} + +function barrettConvert(x) { + if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m); + else if(x.compareTo(this.m) < 0) return x; + else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } +} + +function barrettRevert(x) { return x; } + +// x = x mod m (HAC 14.42) +function barrettReduce(x) { + x.drShiftTo(this.m.t-1,this.r2); + if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); } + this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3); + this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2); + /* BEGIN LOOP */ + while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1); + /* END LOOP */ + x.subTo(this.r2,x); + /* BEGIN LOOP */ + while(x.compareTo(this.m) >= 0) x.subTo(this.m,x); + /* END LOOP */ +} + +// r = x^2 mod m; x != r +function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +// r = x*y mod m; x,y != r +function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + +Barrett.prototype.convert = barrettConvert; +Barrett.prototype.revert = barrettRevert; +Barrett.prototype.reduce = barrettReduce; +Barrett.prototype.mulTo = barrettMulTo; +Barrett.prototype.sqrTo = barrettSqrTo; + +// (public) this^e % m (HAC 14.85) +function bnModPow(e,m) { + var e_array = e.array; + var i = e.bitLength(), k, r = nbv(1), z; + if(i <= 0) return r; + else if(i < 18) k = 1; + else if(i < 48) k = 3; + else if(i < 144) k = 4; + else if(i < 768) k = 5; + else k = 6; + if(i < 8) + z = new Classic(m); + else if(m.isEven()) + z = new Barrett(m); + else + z = new Montgomery(m); + + // precomputation + var g = new Array(), n = 3, k1 = k-1, km = (1< 1) { + var g2 = nbi(); + z.sqrTo(g[1],g2); + /* BEGIN LOOP */ + while(n <= km) { + g[n] = nbi(); + z.mulTo(g2,g[n-2],g[n]); + n += 2; + } + /* END LOOP */ + } + + var j = e.t-1, w, is1 = true, r2 = nbi(), t; + i = nbits(e_array[j])-1; + /* BEGIN LOOP */ + while(j >= 0) { + if(i >= k1) w = (e_array[j]>>(i-k1))&km; + else { + w = (e_array[j]&((1<<(i+1))-1))<<(k1-i); + if(j > 0) w |= e_array[j-1]>>(BI_DB+i-k1); + } + + n = k; + /* BEGIN LOOP */ + while((w&1) == 0) { w >>= 1; --n; } + /* END LOOP */ + if((i -= n) < 0) { i += BI_DB; --j; } + if(is1) { // ret == 1, don't bother squaring or multiplying it + g[w].copyTo(r); + is1 = false; + } + else { + /* BEGIN LOOP */ + while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; } + /* END LOOP */ + if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; } + z.mulTo(r2,g[w],r); + } + + /* BEGIN LOOP */ + while(j >= 0 && (e_array[j]&(1< 0) { + x.rShiftTo(g,x); + y.rShiftTo(g,y); + } + /* BEGIN LOOP */ + while(x.signum() > 0) { + if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x); + if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y); + if(x.compareTo(y) >= 0) { + x.subTo(y,x); + x.rShiftTo(1,x); + } + else { + y.subTo(x,y); + y.rShiftTo(1,y); + } + } + /* END LOOP */ + if(g > 0) y.lShiftTo(g,y); + return y; +} + +// (protected) this % n, n < 2^26 +function bnpModInt(n) { + var this_array = this.array; + if(n <= 0) return 0; + var d = BI_DV%n, r = (this.s<0)?n-1:0; + if(this.t > 0) + if(d == 0) r = this_array[0]%n; + else for(var i = this.t-1; i >= 0; --i) r = (d*r+this_array[i])%n; + return r; +} + +// (public) 1/this % m (HAC 14.61) +function bnModInverse(m) { + var ac = m.isEven(); + if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO; + var u = m.clone(), v = this.clone(); + var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); + /* BEGIN LOOP */ + while(u.signum() != 0) { + /* BEGIN LOOP */ + while(u.isEven()) { + u.rShiftTo(1,u); + if(ac) { + if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); } + a.rShiftTo(1,a); + } + else if(!b.isEven()) b.subTo(m,b); + b.rShiftTo(1,b); + } + /* END LOOP */ + /* BEGIN LOOP */ + while(v.isEven()) { + v.rShiftTo(1,v); + if(ac) { + if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); } + c.rShiftTo(1,c); + } + else if(!d.isEven()) d.subTo(m,d); + d.rShiftTo(1,d); + } + /* END LOOP */ + if(u.compareTo(v) >= 0) { + u.subTo(v,u); + if(ac) a.subTo(c,a); + b.subTo(d,b); + } + else { + v.subTo(u,v); + if(ac) c.subTo(a,c); + d.subTo(b,d); + } + } + /* END LOOP */ + if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO; + if(d.compareTo(m) >= 0) return d.subtract(m); + if(d.signum() < 0) d.addTo(m,d); else return d; + if(d.signum() < 0) return d.add(m); else return d; +} + +var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509]; +var lplim = (1<<26)/lowprimes[lowprimes.length-1]; + +// (public) test primality with certainty >= 1-.5^t +function bnIsProbablePrime(t) { + var i, x = this.abs(); + var x_array = x.array; + if(x.t == 1 && x_array[0] <= lowprimes[lowprimes.length-1]) { + for(i = 0; i < lowprimes.length; ++i) + if(x_array[0] == lowprimes[i]) return true; + return false; + } + if(x.isEven()) return false; + i = 1; + /* BEGIN LOOP */ + while(i < lowprimes.length) { + var m = lowprimes[i], j = i+1; + /* BEGIN LOOP */ + while(j < lowprimes.length && m < lplim) m *= lowprimes[j++]; + /* END LOOP */ + m = x.modInt(m); + /* BEGIN LOOP */ + while(i < j) if(m%lowprimes[i++] == 0) return false; + /* END LOOP */ + } + /* END LOOP */ + return x.millerRabin(t); +} + +// (protected) true if probably prime (HAC 4.24, Miller-Rabin) +function bnpMillerRabin(t) { + var n1 = this.subtract(BigInteger.ONE); + var k = n1.getLowestSetBit(); + if(k <= 0) return false; + var r = n1.shiftRight(k); + t = (t+1)>>1; + if(t > lowprimes.length) t = lowprimes.length; + var a = nbi(); + /* BEGIN LOOP */ + for(var i = 0; i < t; ++i) { + a.fromInt(lowprimes[i]); + var y = a.modPow(r,this); + if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { + var j = 1; + /* BEGIN LOOP */ + while(j++ < k && y.compareTo(n1) != 0) { + y = y.modPowInt(2,this); + if(y.compareTo(BigInteger.ONE) == 0) return false; + } + /* END LOOP */ + if(y.compareTo(n1) != 0) return false; + } + } + /* END LOOP */ + return true; +} + +// protected +BigInteger.prototype.chunkSize = bnpChunkSize; +BigInteger.prototype.toRadix = bnpToRadix; +BigInteger.prototype.fromRadix = bnpFromRadix; +BigInteger.prototype.fromNumber = bnpFromNumber; +BigInteger.prototype.bitwiseTo = bnpBitwiseTo; +BigInteger.prototype.changeBit = bnpChangeBit; +BigInteger.prototype.addTo = bnpAddTo; +BigInteger.prototype.dMultiply = bnpDMultiply; +BigInteger.prototype.dAddOffset = bnpDAddOffset; +BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo; +BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo; +BigInteger.prototype.modInt = bnpModInt; +BigInteger.prototype.millerRabin = bnpMillerRabin; + +// public +BigInteger.prototype.clone = bnClone; +BigInteger.prototype.intValue = bnIntValue; +BigInteger.prototype.byteValue = bnByteValue; +BigInteger.prototype.shortValue = bnShortValue; +BigInteger.prototype.signum = bnSigNum; +BigInteger.prototype.toByteArray = bnToByteArray; +BigInteger.prototype.equals = bnEquals; +BigInteger.prototype.min = bnMin; +BigInteger.prototype.max = bnMax; +BigInteger.prototype.and = bnAnd; +BigInteger.prototype.or = bnOr; +BigInteger.prototype.xor = bnXor; +BigInteger.prototype.andNot = bnAndNot; +BigInteger.prototype.not = bnNot; +BigInteger.prototype.shiftLeft = bnShiftLeft; +BigInteger.prototype.shiftRight = bnShiftRight; +BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit; +BigInteger.prototype.bitCount = bnBitCount; +BigInteger.prototype.testBit = bnTestBit; +BigInteger.prototype.setBit = bnSetBit; +BigInteger.prototype.clearBit = bnClearBit; +BigInteger.prototype.flipBit = bnFlipBit; +BigInteger.prototype.add = bnAdd; +BigInteger.prototype.subtract = bnSubtract; +BigInteger.prototype.multiply = bnMultiply; +BigInteger.prototype.divide = bnDivide; +BigInteger.prototype.remainder = bnRemainder; +BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder; +BigInteger.prototype.modPow = bnModPow; +BigInteger.prototype.modInverse = bnModInverse; +BigInteger.prototype.pow = bnPow; +BigInteger.prototype.gcd = bnGCD; +BigInteger.prototype.isProbablePrime = bnIsProbablePrime; + +// BigInteger interfaces not implemented in jsbn: + +// BigInteger(int signum, byte[] magnitude) +// double doubleValue() +// float floatValue() +// int hashCode() +// long longValue() +// static BigInteger valueOf(long val) +// prng4.js - uses Arcfour as a PRNG + +function Arcfour() { + this.i = 0; + this.j = 0; + this.S = new Array(); +} + +// Initialize arcfour context from key, an array of ints, each from [0..255] +function ARC4init(key) { + var i, j, t; + /* BEGIN LOOP */ + for(i = 0; i < 256; ++i) + this.S[i] = i; + /* END LOOP */ + j = 0; + /* BEGIN LOOP */ + for(i = 0; i < 256; ++i) { + j = (j + this.S[i] + key[i % key.length]) & 255; + t = this.S[i]; + this.S[i] = this.S[j]; + this.S[j] = t; + } + /* END LOOP */ + this.i = 0; + this.j = 0; +} + +function ARC4next() { + var t; + this.i = (this.i + 1) & 255; + this.j = (this.j + this.S[this.i]) & 255; + t = this.S[this.i]; + this.S[this.i] = this.S[this.j]; + this.S[this.j] = t; + return this.S[(t + this.S[this.i]) & 255]; +} + +Arcfour.prototype.init = ARC4init; +Arcfour.prototype.next = ARC4next; + +// Plug in your RNG constructor here +function prng_newstate() { + return new Arcfour(); +} + +// Pool size must be a multiple of 4 and greater than 32. +// An array of bytes the size of the pool will be passed to init() +var rng_psize = 256; +// Random number generator - requires a PRNG backend, e.g. prng4.js + +// For best results, put code like +// +// in your main HTML document. + +var rng_state; +var rng_pool; +var rng_pptr; + +// Mix in a 32-bit integer into the pool +function rng_seed_int(x) { + rng_pool[rng_pptr++] ^= x & 255; + rng_pool[rng_pptr++] ^= (x >> 8) & 255; + rng_pool[rng_pptr++] ^= (x >> 16) & 255; + rng_pool[rng_pptr++] ^= (x >> 24) & 255; + if(rng_pptr >= rng_psize) rng_pptr -= rng_psize; +} + +// Mix in the current time (w/milliseconds) into the pool +function rng_seed_time() { + rng_seed_int(new Date().getTime()); +} + +// Initialize the pool with junk if needed. +if(rng_pool == null) { + rng_pool = new Array(); + rng_pptr = 0; + var t; + /* BEGIN LOOP */ + while(rng_pptr < rng_psize) { // extract some randomness from Math.random() + t = Math.floor(65536 * Math.random()); + rng_pool[rng_pptr++] = t >>> 8; + rng_pool[rng_pptr++] = t & 255; + } + /* END LOOP */ + rng_pptr = 0; + rng_seed_time(); + //rng_seed_int(window.screenX); + //rng_seed_int(window.screenY); +} + +function rng_get_byte() { + if(rng_state == null) { + rng_seed_time(); + rng_state = prng_newstate(); + rng_state.init(rng_pool); + /* BEGIN LOOP */ + for(rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr) + rng_pool[rng_pptr] = 0; + /* END LOOP */ + rng_pptr = 0; + //rng_pool = null; + } + // TODO: allow reseeding after first request + return rng_state.next(); +} + +function rng_get_bytes(ba) { + var i; + /* BEGIN LOOP */ + for(i = 0; i < ba.length; ++i) ba[i] = rng_get_byte(); + /* END LOOP */ +} + +function SecureRandom() {} + +SecureRandom.prototype.nextBytes = rng_get_bytes; +// Depends on jsbn.js and rng.js + +// convert a (hex) string to a bignum object +function parseBigInt(str,r) { + return new BigInteger(str,r); +} + +function linebrk(s,n) { + var ret = ""; + var i = 0; + /* BEGIN LOOP */ + while(i + n < s.length) { + ret += s.substring(i,i+n) + "\n"; + i += n; + } + /* END LOOP */ + return ret + s.substring(i,s.length); +} + +function byte2Hex(b) { + if(b < 0x10) + return "0" + b.toString(16); + else + return b.toString(16); +} + +// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint +function pkcs1pad2(s,n) { + if(n < s.length + 11) { + alert("Message too long for RSA"); + return null; + } + var ba = new Array(); + var i = s.length - 1; + /* BEGIN LOOP */ + while(i >= 0 && n > 0) ba[--n] = s.charCodeAt(i--); + /* END LOOP */ + ba[--n] = 0; + var rng = new SecureRandom(); + var x = new Array(); + /* BEGIN LOOP */ + while(n > 2) { // random non-zero pad + x[0] = 0; + /* BEGIN LOOP */ + while(x[0] == 0) rng.nextBytes(x); + /* END LOOP */ + ba[--n] = x[0]; + } + /* END LOOP */ + ba[--n] = 2; + ba[--n] = 0; + return new BigInteger(ba); +} + +// "empty" RSA key constructor +function RSAKey() { + this.n = null; + this.e = 0; + this.d = null; + this.p = null; + this.q = null; + this.dmp1 = null; + this.dmq1 = null; + this.coeff = null; +} + +// Set the public key fields N and e from hex strings +function RSASetPublic(N,E) { + if(N != null && E != null && N.length > 0 && E.length > 0) { + this.n = parseBigInt(N,16); + this.e = parseInt(E,16); + } + else + alert("Invalid RSA public key"); +} + +// Perform raw public operation on "x": return x^e (mod n) +function RSADoPublic(x) { + return x.modPowInt(this.e, this.n); +} + +// Return the PKCS#1 RSA encryption of "text" as an even-length hex string +function RSAEncrypt(text) { + var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3); + if(m == null) return null; + var c = this.doPublic(m); + if(c == null) return null; + var h = c.toString(16); + if((h.length & 1) == 0) return h; else return "0" + h; +} + +// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string +//function RSAEncryptB64(text) { +// var h = this.encrypt(text); +// if(h) return hex2b64(h); else return null; +//} + +// protected +RSAKey.prototype.doPublic = RSADoPublic; + +// public +RSAKey.prototype.setPublic = RSASetPublic; +RSAKey.prototype.encrypt = RSAEncrypt; +//RSAKey.prototype.encrypt_b64 = RSAEncryptB64; +// Depends on rsa.js and jsbn2.js + +// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext +function pkcs1unpad2(d,n) { + var b = d.toByteArray(); + var i = 0; + /* BEGIN LOOP */ + while(i < b.length && b[i] == 0) ++i; + /* END LOOP */ + if(b.length-i != n-1 || b[i] != 2) + return null; + ++i; + /* BEGIN LOOP */ + while(b[i] != 0) + if(++i >= b.length) return null; + /* END LOOP */ + var ret = ""; + /* BEGIN LOOP */ + while(++i < b.length) + ret += String.fromCharCode(b[i]); + /* END LOOP */ + return ret; +} + +// Set the private key fields N, e, and d from hex strings +function RSASetPrivate(N,E,D) { + if(N != null && E != null && N.length > 0 && E.length > 0) { + this.n = parseBigInt(N,16); + this.e = parseInt(E,16); + this.d = parseBigInt(D,16); + } + else + alert("Invalid RSA private key"); +} + +// Set the private key fields N, e, d and CRT params from hex strings +function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) { + if(N != null && E != null && N.length > 0 && E.length > 0) { + this.n = parseBigInt(N,16); + this.e = parseInt(E,16); + this.d = parseBigInt(D,16); + this.p = parseBigInt(P,16); + this.q = parseBigInt(Q,16); + this.dmp1 = parseBigInt(DP,16); + this.dmq1 = parseBigInt(DQ,16); + this.coeff = parseBigInt(C,16); + } + else + alert("Invalid RSA private key"); +} + +// Generate a new random private key B bits long, using public expt E +function RSAGenerate(B,E) { + var rng = new SecureRandom(); + var qs = B>>1; + this.e = parseInt(E,16); + var ee = new BigInteger(E,16); + /* BEGIN LOOP */ + for(;;) { + /* BEGIN LOOP */ + for(;;) { + this.p = new BigInteger(B-qs,1,rng); + if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break; + } + /* END LOOP */ + /* BEGIN LOOP */ + for(;;) { + this.q = new BigInteger(qs,1,rng); + if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break; + } + /* END LOOP */ + if(this.p.compareTo(this.q) <= 0) { + var t = this.p; + this.p = this.q; + this.q = t; + } + var p1 = this.p.subtract(BigInteger.ONE); + var q1 = this.q.subtract(BigInteger.ONE); + var phi = p1.multiply(q1); + if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) { + this.n = this.p.multiply(this.q); + this.d = ee.modInverse(phi); + this.dmp1 = this.d.mod(p1); + this.dmq1 = this.d.mod(q1); + this.coeff = this.q.modInverse(this.p); + break; + } + } + /* END LOOP */ +} + +// Perform raw private operation on "x": return x^d (mod n) +function RSADoPrivate(x) { + if(this.p == null || this.q == null) + return x.modPow(this.d, this.n); + + // TODO: re-calculate any missing CRT params + var xp = x.mod(this.p).modPow(this.dmp1, this.p); + var xq = x.mod(this.q).modPow(this.dmq1, this.q); + + /* BEGIN LOOP */ + while(xp.compareTo(xq) < 0) + xp = xp.add(this.p); + /* END LOOP */ + return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq); +} + +// Return the PKCS#1 RSA decryption of "ctext". +// "ctext" is an even-length hex string and the output is a plain string. +function RSADecrypt(ctext) { + var c = parseBigInt(ctext, 16); + var m = this.doPrivate(c); + if(m == null) return null; + return pkcs1unpad2(m, (this.n.bitLength()+7)>>3); +} + +// Return the PKCS#1 RSA decryption of "ctext". +// "ctext" is a Base64-encoded string and the output is a plain string. +//function RSAB64Decrypt(ctext) { +// var h = b64tohex(ctext); +// if(h) return this.decrypt(h); else return null; +//} + +// protected +RSAKey.prototype.doPrivate = RSADoPrivate; + +// public +RSAKey.prototype.setPrivate = RSASetPrivate; +RSAKey.prototype.setPrivateEx = RSASetPrivateEx; +RSAKey.prototype.generate = RSAGenerate; +RSAKey.prototype.decrypt = RSADecrypt; +//RSAKey.prototype.b64_decrypt = RSAB64Decrypt; + + +nValue="a5261939975948bb7a58dffe5ff54e65f0498f9175f5a09288810b8975871e99af3b5dd94057b0fc07535f5f97444504fa35169d461d0d30cf0192e307727c065168c788771c561a9400fb49175e9e6aa4e23fe11af69e9412dd23b0cb6684c4c2429bce139e848ab26d0829073351f4acd36074eafd036a5eb83359d2a698d3"; +eValue="10001"; +dValue="8e9912f6d3645894e8d38cb58c0db81ff516cf4c7e5a14c7f1eddb1459d2cded4d8d293fc97aee6aefb861859c8b6a3d1dfe710463e1f9ddc72048c09751971c4a580aa51eb523357a3cc48d31cfad1d4a165066ed92d4748fb6571211da5cb14bc11b6e2df7c1a559e6d5ac1cd5c94703a22891464fba23d0d965086277a161"; +pValue="d090ce58a92c75233a6486cb0a9209bf3583b64f540c76f5294bb97d285eed33aec220bde14b2417951178ac152ceab6da7090905b478195498b352048f15e7d"; +qValue="cab575dc652bb66df15a0359609d51d1db184750c00c6698b90ef3465c99655103edbf0d54c56aec0ce3c4d22592338092a126a0cc49f65a4a30d222b411e58f"; +dmp1Value="1a24bca8e273df2f0e47c199bbf678604e7df7215480c77c8db39f49b000ce2cf7500038acfff5433b7d582a01f1826e6f4d42e1c57f5e1fef7b12aabc59fd25"; +dmq1Value="3d06982efbbe47339e1f6d36b1216b8a741d410b0c662f54f7118b27b9a4ec9d914337eb39841d8666f3034408cf94f5b62f11c402fc994fe15a05493150d9fd"; +coeffValue="3a3e731acd8960b7ff9eb81a7ff93bd1cfa74cbd56987db58b4594fb09c09084db1734c8143f98b602b981aaa9243ca28deb69b5b280ee8dcee0fd2625e53250"; + +setupEngine(am3, 28); + +var RSA = new RSAKey(); +var TEXT = "The quick brown fox jumped over the extremely lazy frogs!"; + +RSA.setPublic(nValue, eValue); +RSA.setPrivateEx(nValue, eValue, dValue, pValue, qValue, dmp1Value, dmq1Value, coeffValue); + +function encrypt() { + return RSA.encrypt(TEXT); +} + +function decrypt() { + return RSA.decrypt(TEXT); +} + +function PrintResult(name, result) { +} + + +function PrintScore(score) { +// print(score); +} + + +BenchmarkSuite.RunSuites({ NotifyResult: PrintResult, + NotifyScore: PrintScore }); diff --git a/js/src/metrics/jint/v8/deltablue.js b/js/src/metrics/jint/v8/deltablue.js new file mode 100644 index 0000000..311f260 --- /dev/null +++ b/js/src/metrics/jint/v8/deltablue.js @@ -0,0 +1,1196 @@ +// Copyright 2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Simple framework for running the benchmark suites and +// computing a score based on the timing measurements. + + +// A benchmark has a name (string) and a function that will be run to +// do the performance measurement. The optional setup and tearDown +// arguments are functions that will be invoked before and after +// running the benchmark, but the running time of these functions will +// not be accounted for in the benchmark score. +function Benchmark(name, run, setup, tearDown) { + this.name = name; + this.run = run; + this.Setup = setup ? setup : function() { }; + this.TearDown = tearDown ? tearDown : function() { }; +} + + +// Benchmark results hold the benchmark and the measured time used to +// run the benchmark. The benchmark score is computed later once a +// full benchmark suite has run to completion. +function BenchmarkResult(benchmark, time) { + this.benchmark = benchmark; + this.time = time; +} + + +// Automatically convert results to numbers. Used by the geometric +// mean computation. +BenchmarkResult.prototype.valueOf = function() { + return this.time; +} + + +// Suites of benchmarks consist of a name and the set of benchmarks in +// addition to the reference timing that the final score will be based +// on. This way, all scores are relative to a reference run and higher +// scores implies better performance. +function BenchmarkSuite(name, reference, benchmarks) { + this.name = name; + this.reference = reference; + this.benchmarks = benchmarks; + BenchmarkSuite.suites.push(this); +} + + +// Keep track of all declared benchmark suites. +BenchmarkSuite.suites = []; + + +// Scores are not comparable across versions. Bump the version if +// you're making changes that will affect that scores, e.g. if you add +// a new benchmark or change an existing one. +BenchmarkSuite.version = '5'; + + +// To make the benchmark results predictable, we replace Math.random +// with a 100% deterministic alternative. +Math.random = (function() { + var seed = 49734321; + return function() { + // Robert Jenkins' 32 bit integer hash function. + seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff; + seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff; + seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff; + seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff; + seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff; + seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff; + return (seed & 0xfffffff) / 0x10000000; + }; +})(); + + +// Runs all registered benchmark suites and optionally yields between +// each individual benchmark to avoid running for too long in the +// context of browsers. Once done, the final score is reported to the +// runner. +BenchmarkSuite.RunSuites = function(runner) { + var continuation = null; + var suites = BenchmarkSuite.suites; + var length = suites.length; + BenchmarkSuite.scores = []; + var index = 0; + function RunStep() { + while (continuation || index < length) { + if (continuation) { + continuation = continuation(); + } else { + var suite = suites[index++]; + if (runner.NotifyStart) runner.NotifyStart(suite.name); + continuation = suite.RunStep(runner); + } + if (continuation && typeof window != 'undefined' && window.setTimeout) { + window.setTimeout(RunStep, 25); + return; + } + } + if (runner.NotifyScore) { + var score = BenchmarkSuite.GeometricMean(BenchmarkSuite.scores); + var formatted = BenchmarkSuite.FormatScore(100 * score); + runner.NotifyScore(formatted); + } + } + RunStep(); +} + + +// Counts the total number of registered benchmarks. Useful for +// showing progress as a percentage. +BenchmarkSuite.CountBenchmarks = function() { + var result = 0; + var suites = BenchmarkSuite.suites; + for (var i = 0; i < suites.length; i++) { + result += suites[i].benchmarks.length; + } + return result; +} + + +// Computes the geometric mean of a set of numbers. +BenchmarkSuite.GeometricMean = function(numbers) { + var log = 0; + for (var i = 0; i < numbers.length; i++) { + log += Math.log(numbers[i]); + } + return Math.pow(Math.E, log / numbers.length); +} + + +// Converts a score value to a string with at least three significant +// digits. +BenchmarkSuite.FormatScore = function(value) { + if (value > 100) { + return value.toFixed(0); + } else { + return value.toPrecision(3); + } +} + +// Notifies the runner that we're done running a single benchmark in +// the benchmark suite. This can be useful to report progress. +BenchmarkSuite.prototype.NotifyStep = function(result) { + this.results.push(result); + if (this.runner.NotifyStep) this.runner.NotifyStep(result.benchmark.name); +} + + +// Notifies the runner that we're done with running a suite and that +// we have a result which can be reported to the user if needed. +BenchmarkSuite.prototype.NotifyResult = function() { + var mean = BenchmarkSuite.GeometricMean(this.results); + var score = this.reference / mean; + BenchmarkSuite.scores.push(score); + if (this.runner.NotifyResult) { + var formatted = BenchmarkSuite.FormatScore(100 * score); + this.runner.NotifyResult(this.name, formatted); + } +} + + +// Notifies the runner that running a benchmark resulted in an error. +BenchmarkSuite.prototype.NotifyError = function(error) { + if (this.runner.NotifyError) { + this.runner.NotifyError(this.name, error); + } + if (this.runner.NotifyStep) { + this.runner.NotifyStep(this.name); + } +} + + +// Runs a single benchmark for at least a second and computes the +// average time it takes to run a single iteration. +BenchmarkSuite.prototype.RunSingleBenchmark = function(benchmark) { + var elapsed = 0; + var start = new Date(); + for (var n = 0; elapsed < 200; n++) { + benchmark.run(); + elapsed = new Date() - start; + } + var usec = (elapsed * 1000) / n; + this.NotifyStep(new BenchmarkResult(benchmark, usec)); +} + + +// This function starts running a suite, but stops between each +// individual benchmark in the suite and returns a continuation +// function which can be invoked to run the next benchmark. Once the +// last benchmark has been executed, null is returned. +BenchmarkSuite.prototype.RunStep = function(runner) { + this.results = []; + this.runner = runner; + var length = this.benchmarks.length; + var index = 0; + var suite = this; + + // Run the setup, the actual benchmark, and the tear down in three + // separate steps to allow the framework to yield between any of the + // steps. + + function RunNextSetup() { + if (index < length) { + try { + suite.benchmarks[index].Setup(); + } catch (e) { + suite.NotifyError(e); + return null; + } + return RunNextBenchmark; + } + suite.NotifyResult(); + return null; + } + + function RunNextBenchmark() { + try { + suite.RunSingleBenchmark(suite.benchmarks[index]); + } catch (e) { + suite.NotifyError(e); + return null; + } + return RunNextTearDown; + } + + function RunNextTearDown() { + try { + suite.benchmarks[index++].TearDown(); + } catch (e) { + suite.NotifyError(e); + return null; + } + return RunNextSetup; + } + + // Start out running the setup. + return RunNextSetup(); +} + + +// Copyright 2008 Google Inc. All Rights Reserved. +// Copyright 1996 John Maloney and Mario Wolczko. + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +// This implementation of the DeltaBlue benchmark is derived +// from the Smalltalk implementation by John Maloney and Mario +// Wolczko. Some parts have been translated directly, whereas +// others have been modified more aggresively to make it feel +// more like a JavaScript program. + + +var DeltaBlue = new BenchmarkSuite('DeltaBlue', 71104, [ + new Benchmark('DeltaBlue', deltaBlue) +]); + + +/** + * A JavaScript implementation of the DeltaBlue constrain-solving + * algorithm, as described in: + * + * "The DeltaBlue Algorithm: An Incremental Constraint Hierarchy Solver" + * Bjorn N. Freeman-Benson and John Maloney + * January 1990 Communications of the ACM, + * also available as University of Washington TR 89-08-06. + * + * Beware: this benchmark is written in a grotesque style where + * the constraint model is built by side-effects from constructors. + * I've kept it this way to avoid deviating too much from the original + * implementation. + */ + + +/* --- O b j e c t M o d e l --- */ + +Object.prototype.inherits = function (shuper) { + function Inheriter() { } + Inheriter.prototype = shuper.prototype; + this.prototype = new Inheriter(); + this.superConstructor = shuper; +} + +function OrderedCollection() { + this.elms = new Array(); +} + +OrderedCollection.prototype.add = function (elm) { + this.elms.push(elm); +} + +OrderedCollection.prototype.at = function (index) { + return this.elms[index]; +} + +OrderedCollection.prototype.size = function () { + return this.elms.length; +} + +OrderedCollection.prototype.removeFirst = function () { + return this.elms.pop(); +} + +OrderedCollection.prototype.remove = function (elm) { + var index = 0, skipped = 0; + /* BEGIN LOOP */ + for (var i = 0; i < this.elms.length; i++) { + var value = this.elms[i]; + if (value != elm) { + this.elms[index] = value; + index++; + } else { + skipped++; + } + } + /* END LOOP */ + /* BEGIN LOOP */ + for (var i = 0; i < skipped; i++) + this.elms.pop(); + /* END LOOP */ +} + +/* --- * + * S t r e n g t h + * --- */ + +/** + * Strengths are used to measure the relative importance of constraints. + * New strengths may be inserted in the strength hierarchy without + * disrupting current constraints. Strengths cannot be created outside + * this class, so pointer comparison can be used for value comparison. + */ +function Strength(strengthValue, name) { + this.strengthValue = strengthValue; + this.name = name; +} + +Strength.stronger = function (s1, s2) { + return s1.strengthValue < s2.strengthValue; +} + +Strength.weaker = function (s1, s2) { + return s1.strengthValue > s2.strengthValue; +} + +Strength.weakestOf = function (s1, s2) { + return this.weaker(s1, s2) ? s1 : s2; +} + +Strength.strongest = function (s1, s2) { + return this.stronger(s1, s2) ? s1 : s2; +} + +Strength.prototype.nextWeaker = function () { + switch (this.strengthValue) { + case 0: return Strength.WEAKEST; + case 1: return Strength.WEAK_DEFAULT; + case 2: return Strength.NORMAL; + case 3: return Strength.STRONG_DEFAULT; + case 4: return Strength.PREFERRED; + case 5: return Strength.REQUIRED; + } +} + +// Strength constants. +Strength.REQUIRED = new Strength(0, "required"); +Strength.STONG_PREFERRED = new Strength(1, "strongPreferred"); +Strength.PREFERRED = new Strength(2, "preferred"); +Strength.STRONG_DEFAULT = new Strength(3, "strongDefault"); +Strength.NORMAL = new Strength(4, "normal"); +Strength.WEAK_DEFAULT = new Strength(5, "weakDefault"); +Strength.WEAKEST = new Strength(6, "weakest"); + +/* --- * + * C o n s t r a i n t + * --- */ + +/** + * An abstract class representing a system-maintainable relationship + * (or "constraint") between a set of variables. A constraint supplies + * a strength instance variable; concrete subclasses provide a means + * of storing the constrained variables and other information required + * to represent a constraint. + */ +function Constraint(strength) { + this.strength = strength; +} + +/** + * Activate this constraint and attempt to satisfy it. + */ +Constraint.prototype.addConstraint = function () { + this.addToGraph(); + planner.incrementalAdd(this); +} + +/** + * Attempt to find a way to enforce this constraint. If successful, + * record the solution, perhaps modifying the current dataflow + * graph. Answer the constraint that this constraint overrides, if + * there is one, or nil, if there isn't. + * Assume: I am not already satisfied. + */ +Constraint.prototype.satisfy = function (mark) { + this.chooseMethod(mark); + if (!this.isSatisfied()) { + if (this.strength == Strength.REQUIRED) + alert("Could not satisfy a required constraint!"); + return null; + } + this.markInputs(mark); + var out = this.output(); + var overridden = out.determinedBy; + if (overridden != null) overridden.markUnsatisfied(); + out.determinedBy = this; + if (!planner.addPropagate(this, mark)) + alert("Cycle encountered"); + out.mark = mark; + return overridden; +} + +Constraint.prototype.destroyConstraint = function () { + if (this.isSatisfied()) planner.incrementalRemove(this); + else this.removeFromGraph(); +} + +/** + * Normal constraints are not input constraints. An input constraint + * is one that depends on external state, such as the mouse, the + * keybord, a clock, or some arbitraty piece of imperative code. + */ +Constraint.prototype.isInput = function () { + return false; +} + +/* --- * + * U n a r y C o n s t r a i n t + * --- */ + +/** + * Abstract superclass for constraints having a single possible output + * variable. + */ +function UnaryConstraint(v, strength) { + UnaryConstraint.superConstructor.call(this, strength); + this.myOutput = v; + this.satisfied = false; + this.addConstraint(); +} + +UnaryConstraint.inherits(Constraint); + +/** + * Adds this constraint to the constraint graph + */ +UnaryConstraint.prototype.addToGraph = function () { + this.myOutput.addConstraint(this); + this.satisfied = false; +} + +/** + * Decides if this constraint can be satisfied and records that + * decision. + */ +UnaryConstraint.prototype.chooseMethod = function (mark) { + this.satisfied = (this.myOutput.mark != mark) + && Strength.stronger(this.strength, this.myOutput.walkStrength); +} + +/** + * Returns true if this constraint is satisfied in the current solution. + */ +UnaryConstraint.prototype.isSatisfied = function () { + return this.satisfied; +} + +UnaryConstraint.prototype.markInputs = function (mark) { + // has no inputs +} + +/** + * Returns the current output variable. + */ +UnaryConstraint.prototype.output = function () { + return this.myOutput; +} + +/** + * Calculate the walkabout strength, the stay flag, and, if it is + * 'stay', the value for the current output of this constraint. Assume + * this constraint is satisfied. + */ +UnaryConstraint.prototype.recalculate = function () { + this.myOutput.walkStrength = this.strength; + this.myOutput.stay = !this.isInput(); + if (this.myOutput.stay) this.execute(); // Stay optimization +} + +/** + * Records that this constraint is unsatisfied + */ +UnaryConstraint.prototype.markUnsatisfied = function () { + this.satisfied = false; +} + +UnaryConstraint.prototype.inputsKnown = function () { + return true; +} + +UnaryConstraint.prototype.removeFromGraph = function () { + if (this.myOutput != null) this.myOutput.removeConstraint(this); + this.satisfied = false; +} + +/* --- * + * S t a y C o n s t r a i n t + * --- */ + +/** + * Variables that should, with some level of preference, stay the same. + * Planners may exploit the fact that instances, if satisfied, will not + * change their output during plan execution. This is called "stay + * optimization". + */ +function StayConstraint(v, str) { + StayConstraint.superConstructor.call(this, v, str); +} + +StayConstraint.inherits(UnaryConstraint); + +StayConstraint.prototype.execute = function () { + // Stay constraints do nothing +} + +/* --- * + * E d i t C o n s t r a i n t + * --- */ + +/** + * A unary input constraint used to mark a variable that the client + * wishes to change. + */ +function EditConstraint(v, str) { + EditConstraint.superConstructor.call(this, v, str); +} + +EditConstraint.inherits(UnaryConstraint); + +/** + * Edits indicate that a variable is to be changed by imperative code. + */ +EditConstraint.prototype.isInput = function () { + return true; +} + +EditConstraint.prototype.execute = function () { + // Edit constraints do nothing +} + +/* --- * + * B i n a r y C o n s t r a i n t + * --- */ + +var Direction = new Object(); +Direction.NONE = 0; +Direction.FORWARD = 1; +Direction.BACKWARD = -1; + +/** + * Abstract superclass for constraints having two possible output + * variables. + */ +function BinaryConstraint(var1, var2, strength) { + BinaryConstraint.superConstructor.call(this, strength); + this.v1 = var1; + this.v2 = var2; + this.direction = Direction.NONE; + this.addConstraint(); +} + +BinaryConstraint.inherits(Constraint); + +/** + * Decides if this constratint can be satisfied and which way it + * should flow based on the relative strength of the variables related, + * and record that decision. + */ +BinaryConstraint.prototype.chooseMethod = function (mark) { + if (this.v1.mark == mark) { + this.direction = (this.v1.mark != mark && Strength.stronger(this.strength, this.v2.walkStrength)) + ? Direction.FORWARD + : Direction.NONE; + } + if (this.v2.mark == mark) { + this.direction = (this.v1.mark != mark && Strength.stronger(this.strength, this.v1.walkStrength)) + ? Direction.BACKWARD + : Direction.NONE; + } + if (Strength.weaker(this.v1.walkStrength, this.v2.walkStrength)) { + this.direction = Strength.stronger(this.strength, this.v1.walkStrength) + ? Direction.BACKWARD + : Direction.NONE; + } else { + this.direction = Strength.stronger(this.strength, this.v2.walkStrength) + ? Direction.FORWARD + : Direction.BACKWARD + } +} + +/** + * Add this constraint to the constraint graph + */ +BinaryConstraint.prototype.addToGraph = function () { + this.v1.addConstraint(this); + this.v2.addConstraint(this); + this.direction = Direction.NONE; +} + +/** + * Answer true if this constraint is satisfied in the current solution. + */ +BinaryConstraint.prototype.isSatisfied = function () { + return this.direction != Direction.NONE; +} + +/** + * Mark the input variable with the given mark. + */ +BinaryConstraint.prototype.markInputs = function (mark) { + this.input().mark = mark; +} + +/** + * Returns the current input variable + */ +BinaryConstraint.prototype.input = function () { + return (this.direction == Direction.FORWARD) ? this.v1 : this.v2; +} + +/** + * Returns the current output variable + */ +BinaryConstraint.prototype.output = function () { + return (this.direction == Direction.FORWARD) ? this.v2 : this.v1; +} + +/** + * Calculate the walkabout strength, the stay flag, and, if it is + * 'stay', the value for the current output of this + * constraint. Assume this constraint is satisfied. + */ +BinaryConstraint.prototype.recalculate = function () { + var ihn = this.input(), out = this.output(); + out.walkStrength = Strength.weakestOf(this.strength, ihn.walkStrength); + out.stay = ihn.stay; + if (out.stay) this.execute(); +} + +/** + * Record the fact that this constraint is unsatisfied. + */ +BinaryConstraint.prototype.markUnsatisfied = function () { + this.direction = Direction.NONE; +} + +BinaryConstraint.prototype.inputsKnown = function (mark) { + var i = this.input(); + return i.mark == mark || i.stay || i.determinedBy == null; +} + +BinaryConstraint.prototype.removeFromGraph = function () { + if (this.v1 != null) this.v1.removeConstraint(this); + if (this.v2 != null) this.v2.removeConstraint(this); + this.direction = Direction.NONE; +} + +/* --- * + * S c a l e C o n s t r a i n t + * --- */ + +/** + * Relates two variables by the linear scaling relationship: "v2 = + * (v1 * scale) + offset". Either v1 or v2 may be changed to maintain + * this relationship but the scale factor and offset are considered + * read-only. + */ +function ScaleConstraint(src, scale, offset, dest, strength) { + this.direction = Direction.NONE; + this.scale = scale; + this.offset = offset; + ScaleConstraint.superConstructor.call(this, src, dest, strength); +} + +ScaleConstraint.inherits(BinaryConstraint); + +/** + * Adds this constraint to the constraint graph. + */ +ScaleConstraint.prototype.addToGraph = function () { + ScaleConstraint.superConstructor.prototype.addToGraph.call(this); + this.scale.addConstraint(this); + this.offset.addConstraint(this); +} + +ScaleConstraint.prototype.removeFromGraph = function () { + ScaleConstraint.superConstructor.prototype.removeFromGraph.call(this); + if (this.scale != null) this.scale.removeConstraint(this); + if (this.offset != null) this.offset.removeConstraint(this); +} + +ScaleConstraint.prototype.markInputs = function (mark) { + ScaleConstraint.superConstructor.prototype.markInputs.call(this, mark); + this.scale.mark = this.offset.mark = mark; +} + +/** + * Enforce this constraint. Assume that it is satisfied. + */ +ScaleConstraint.prototype.execute = function () { + if (this.direction == Direction.FORWARD) { + this.v2.value = this.v1.value * this.scale.value + this.offset.value; + } else { + this.v1.value = (this.v2.value - this.offset.value) / this.scale.value; + } +} + +/** + * Calculate the walkabout strength, the stay flag, and, if it is + * 'stay', the value for the current output of this constraint. Assume + * this constraint is satisfied. + */ +ScaleConstraint.prototype.recalculate = function () { + var ihn = this.input(), out = this.output(); + out.walkStrength = Strength.weakestOf(this.strength, ihn.walkStrength); + out.stay = ihn.stay && this.scale.stay && this.offset.stay; + if (out.stay) this.execute(); +} + +/* --- * + * E q u a l i t y C o n s t r a i n t + * --- */ + +/** + * Constrains two variables to have the same value. + */ +function EqualityConstraint(var1, var2, strength) { + EqualityConstraint.superConstructor.call(this, var1, var2, strength); +} + +EqualityConstraint.inherits(BinaryConstraint); + +/** + * Enforce this constraint. Assume that it is satisfied. + */ +EqualityConstraint.prototype.execute = function () { + this.output().value = this.input().value; +} + +/* --- * + * V a r i a b l e + * --- */ + +/** + * A constrained variable. In addition to its value, it maintain the + * structure of the constraint graph, the current dataflow graph, and + * various parameters of interest to the DeltaBlue incremental + * constraint solver. + **/ +function Variable(name, initialValue) { + this.value = initialValue || 0; + this.constraints = new OrderedCollection(); + this.determinedBy = null; + this.mark = 0; + this.walkStrength = Strength.WEAKEST; + this.stay = true; + this.name = name; +} + +/** + * Add the given constraint to the set of all constraints that refer + * this variable. + */ +Variable.prototype.addConstraint = function (c) { + this.constraints.add(c); +} + +/** + * Removes all traces of c from this variable. + */ +Variable.prototype.removeConstraint = function (c) { + this.constraints.remove(c); + if (this.determinedBy == c) this.determinedBy = null; +} + +/* --- * + * P l a n n e r + * --- */ + +/** + * The DeltaBlue planner + */ +function Planner() { + this.currentMark = 0; +} + +/** + * Attempt to satisfy the given constraint and, if successful, + * incrementally update the dataflow graph. Details: If satifying + * the constraint is successful, it may override a weaker constraint + * on its output. The algorithm attempts to resatisfy that + * constraint using some other method. This process is repeated + * until either a) it reaches a variable that was not previously + * determined by any constraint or b) it reaches a constraint that + * is too weak to be satisfied using any of its methods. The + * variables of constraints that have been processed are marked with + * a unique mark value so that we know where we've been. This allows + * the algorithm to avoid getting into an infinite loop even if the + * constraint graph has an inadvertent cycle. + */ +Planner.prototype.incrementalAdd = function (c) { + var mark = this.newMark(); + var overridden = c.satisfy(mark); + /* BEGIN LOOP */ + while (overridden != null) + overridden = overridden.satisfy(mark); + /* END LOOP */ +} + +/** + * Entry point for retracting a constraint. Remove the given + * constraint and incrementally update the dataflow graph. + * Details: Retracting the given constraint may allow some currently + * unsatisfiable downstream constraint to be satisfied. We therefore collect + * a list of unsatisfied downstream constraints and attempt to + * satisfy each one in turn. This list is traversed by constraint + * strength, strongest first, as a heuristic for avoiding + * unnecessarily adding and then overriding weak constraints. + * Assume: c is satisfied. + */ +Planner.prototype.incrementalRemove = function (c) { + var out = c.output(); + c.markUnsatisfied(); + c.removeFromGraph(); + var unsatisfied = this.removePropagateFrom(out); + var strength = Strength.REQUIRED; + /* BEGIN LOOP */ + do { + /* BEGIN LOOP */ + for (var i = 0; i < unsatisfied.size(); i++) { + var u = unsatisfied.at(i); + if (u.strength == strength) + this.incrementalAdd(u); + } + /* END LOOP */ + strength = strength.nextWeaker(); + } while (strength != Strength.WEAKEST); + /* END LOOP */ +} + +/** + * Select a previously unused mark value. + */ +Planner.prototype.newMark = function () { + return ++this.currentMark; +} + +/** + * Extract a plan for resatisfaction starting from the given source + * constraints, usually a set of input constraints. This method + * assumes that stay optimization is desired; the plan will contain + * only constraints whose output variables are not stay. Constraints + * that do no computation, such as stay and edit constraints, are + * not included in the plan. + * Details: The outputs of a constraint are marked when it is added + * to the plan under construction. A constraint may be appended to + * the plan when all its input variables are known. A variable is + * known if either a) the variable is marked (indicating that has + * been computed by a constraint appearing earlier in the plan), b) + * the variable is 'stay' (i.e. it is a constant at plan execution + * time), or c) the variable is not determined by any + * constraint. The last provision is for past states of history + * variables, which are not stay but which are also not computed by + * any constraint. + * Assume: sources are all satisfied. + */ +Planner.prototype.makePlan = function (sources) { + var mark = this.newMark(); + var plan = new Plan(); + var todo = sources; + /* BEGIN LOOP */ + while (todo.size() > 0) { + var c = todo.removeFirst(); + if (c.output().mark != mark && c.inputsKnown(mark)) { + plan.addConstraint(c); + c.output().mark = mark; + this.addConstraintsConsumingTo(c.output(), todo); + } + } + /* END LOOP */ + return plan; +} + +/** + * Extract a plan for resatisfying starting from the output of the + * given constraints, usually a set of input constraints. + */ +Planner.prototype.extractPlanFromConstraints = function (constraints) { + var sources = new OrderedCollection(); + /* BEGIN LOOP */ + for (var i = 0; i < constraints.size(); i++) { + var c = constraints.at(i); + if (c.isInput() && c.isSatisfied()) + // not in plan already and eligible for inclusion + sources.add(c); + } + /* END LOOP */ + return this.makePlan(sources); +} + +/** + * Recompute the walkabout strengths and stay flags of all variables + * downstream of the given constraint and recompute the actual + * values of all variables whose stay flag is true. If a cycle is + * detected, remove the given constraint and answer + * false. Otherwise, answer true. + * Details: Cycles are detected when a marked variable is + * encountered downstream of the given constraint. The sender is + * assumed to have marked the inputs of the given constraint with + * the given mark. Thus, encountering a marked node downstream of + * the output constraint means that there is a path from the + * constraint's output to one of its inputs. + */ +Planner.prototype.addPropagate = function (c, mark) { + var todo = new OrderedCollection(); + todo.add(c); + /* BEGIN LOOP */ + while (todo.size() > 0) { + var d = todo.removeFirst(); + if (d.output().mark == mark) { + this.incrementalRemove(c); + return false; + } + d.recalculate(); + this.addConstraintsConsumingTo(d.output(), todo); + } + /* END LOOP */ + return true; +} + + +/** + * Update the walkabout strengths and stay flags of all variables + * downstream of the given constraint. Answer a collection of + * unsatisfied constraints sorted in order of decreasing strength. + */ +Planner.prototype.removePropagateFrom = function (out) { + out.determinedBy = null; + out.walkStrength = Strength.WEAKEST; + out.stay = true; + var unsatisfied = new OrderedCollection(); + var todo = new OrderedCollection(); + todo.add(out); + /* BEGIN LOOP */ + while (todo.size() > 0) { + var v = todo.removeFirst(); + /* BEGIN LOOP */ + for (var i = 0; i < v.constraints.size(); i++) { + var c = v.constraints.at(i); + if (!c.isSatisfied()) + unsatisfied.add(c); + } + /* END LOOP */ + var determining = v.determinedBy; + /* BEGIN LOOP */ + for (var i = 0; i < v.constraints.size(); i++) { + var next = v.constraints.at(i); + if (next != determining && next.isSatisfied()) { + next.recalculate(); + todo.add(next.output()); + } + } + /* END LOOP */ + } + /* END LOOP */ + return unsatisfied; +} + +Planner.prototype.addConstraintsConsumingTo = function (v, coll) { + var determining = v.determinedBy; + var cc = v.constraints; + /* BEGIN LOOP */ + for (var i = 0; i < cc.size(); i++) { + var c = cc.at(i); + if (c != determining && c.isSatisfied()) + coll.add(c); + } + /* END LOOP */ +} + +/* --- * + * P l a n + * --- */ + +/** + * A Plan is an ordered list of constraints to be executed in sequence + * to resatisfy all currently satisfiable constraints in the face of + * one or more changing inputs. + */ +function Plan() { + this.v = new OrderedCollection(); +} + +Plan.prototype.addConstraint = function (c) { + this.v.add(c); +} + +Plan.prototype.size = function () { + return this.v.size(); +} + +Plan.prototype.constraintAt = function (index) { + return this.v.at(index); +} + +Plan.prototype.execute = function () { + /* BEGIN LOOP */ + for (var i = 0; i < this.size(); i++) { + var c = this.constraintAt(i); + c.execute(); + } + /* END LOOP */ +} + +/* --- * + * M a i n + * --- */ + +/** + * This is the standard DeltaBlue benchmark. A long chain of equality + * constraints is constructed with a stay constraint on one end. An + * edit constraint is then added to the opposite end and the time is + * measured for adding and removing this constraint, and extracting + * and executing a constraint satisfaction plan. There are two cases. + * In case 1, the added constraint is stronger than the stay + * constraint and values must propagate down the entire length of the + * chain. In case 2, the added constraint is weaker than the stay + * constraint so it cannot be accomodated. The cost in this case is, + * of course, very low. Typical situations lie somewhere between these + * two extremes. + */ +function chainTest(n) { + planner = new Planner(); + var prev = null, first = null, last = null; + + // Build chain of n equality constraints + /* BEGIN LOOP */ + for (var i = 0; i <= n; i++) { + var name = "v" + i; + var v = new Variable(name); + if (prev != null) + new EqualityConstraint(prev, v, Strength.REQUIRED); + if (i == 0) first = v; + if (i == n) last = v; + prev = v; + } + /* END LOOP */ + + new StayConstraint(last, Strength.STRONG_DEFAULT); + var edit = new EditConstraint(first, Strength.PREFERRED); + var edits = new OrderedCollection(); + edits.add(edit); + var plan = planner.extractPlanFromConstraints(edits); + /* BEGIN LOOP */ + for (var i = 0; i < 100; i++) { + first.value = i; + plan.execute(); + if (last.value != i) + alert("Chain test failed."); + } + /* END LOOP */ +} + +/** + * This test constructs a two sets of variables related to each + * other by a simple linear transformation (scale and offset). The + * time is measured to change a variable on either side of the + * mapping and to change the scale and offset factors. + */ +function projectionTest(n) { + planner = new Planner(); + var scale = new Variable("scale", 10); + var offset = new Variable("offset", 1000); + var src = null, dst = null; + + var dests = new OrderedCollection(); + /* BEGIN LOOP */ + for (var i = 0; i < n; i++) { + src = new Variable("src" + i, i); + dst = new Variable("dst" + i, i); + dests.add(dst); + new StayConstraint(src, Strength.NORMAL); + new ScaleConstraint(src, scale, offset, dst, Strength.REQUIRED); + } + /* END LOOP */ + + change(src, 17); + if (dst.value != 1170) alert("Projection 1 failed"); + change(dst, 1050); + if (src.value != 5) alert("Projection 2 failed"); + change(scale, 5); + /* BEGIN LOOP */ + for (var i = 0; i < n - 1; i++) { + if (dests.at(i).value != i * 5 + 1000) + alert("Projection 3 failed"); + } + /* END LOOP */ + change(offset, 2000); + /* BEGIN LOOP */ + for (var i = 0; i < n - 1; i++) { + if (dests.at(i).value != i * 5 + 2000) + alert("Projection 4 failed"); + } + /* END LOOP */ +} + +function change(v, newValue) { + var edit = new EditConstraint(v, Strength.PREFERRED); + var edits = new OrderedCollection(); + edits.add(edit); + var plan = planner.extractPlanFromConstraints(edits); + /* BEGIN LOOP */ + for (var i = 0; i < 10; i++) { + v.value = newValue; + plan.execute(); + } + /* END LOOP */ + edit.destroyConstraint(); +} + +// Global variable holding the current planner. +var planner = null; + +function deltaBlue() { + chainTest(100); + projectionTest(100); +} + +function PrintResult(name, result) { +} + + +function PrintScore(score) { +} + + +BenchmarkSuite.RunSuites({ NotifyResult: PrintResult, + NotifyScore: PrintScore }); + diff --git a/js/src/metrics/jint/v8/earley-boyer.js b/js/src/metrics/jint/v8/earley-boyer.js new file mode 100644 index 0000000..54a919a --- /dev/null +++ b/js/src/metrics/jint/v8/earley-boyer.js @@ -0,0 +1,4682 @@ +// This file is automatically generated by scheme2js, except for the +// benchmark harness code at the beginning and end of the file. + +var EarleyBoyer = new BenchmarkSuite('EarleyBoyer', 765819, [ + new Benchmark("Earley", function () { BgL_earleyzd2benchmarkzd2(); }), + new Benchmark("Boyer", function () { BgL_nboyerzd2benchmarkzd2(); }) +]); + + +/************* GENERATED FILE - DO NOT EDIT *************/ +/************* GENERATED FILE - DO NOT EDIT *************/ +/************* GENERATED FILE - DO NOT EDIT *************/ +/************* GENERATED FILE - DO NOT EDIT *************/ +/************* GENERATED FILE - DO NOT EDIT *************/ +/************* GENERATED FILE - DO NOT EDIT *************/ +/************* GENERATED FILE - DO NOT EDIT *************/ +/************* GENERATED FILE - DO NOT EDIT *************/ +/* + * To use write/prints/... the default-output port has to be set first. + * Simply setting SC_DEFAULT_OUT and SC_ERROR_OUT to the desired values + * should do the trick. + * In the following example the std-out and error-port are redirected to + * a DIV. +function initRuntime() { + function escapeHTML(s) { + var tmp = s; + tmp = tmp.replace(/&/g, "&"); + tmp = tmp.replace(//g, ">"); + tmp = tmp.replace(/ /g, " "); + tmp = tmp.replace(/\n/g, "
"); + tmp = tmp.replace(/\t/g, "    "); + return tmp; + + } + + document.write("
"); + SC_DEFAULT_OUT = new sc_GenericOutputPort( + function(s) { + var stdout = document.getElementById('stdout'); + stdout.innerHTML = stdout.innerHTML + escapeHTML(s); + }); + SC_ERROR_OUT = SC_DEFAULT_OUT; +} +*/ + + +function sc_print_debug() { + sc_print.apply(null, arguments); +} +/*** META ((export *js*)) */ +var sc_JS_GLOBALS = this; + +var __sc_LINE=-1; +var __sc_FILE=""; + +/*** META ((export #t)) */ +function sc_alert() { + var len = arguments.length; + var s = ""; + var i; + + for( i = 0; i < len; i++ ) { + s += sc_toDisplayString(arguments[ i ]); + } + + return alert( s ); +} + +/*** META ((export #t)) */ +function sc_typeof( x ) { + return typeof x; +} + +/*** META ((export #t)) */ +function sc_error() { + var a = [sc_jsstring2symbol("*error*")]; + for (var i = 0; i < arguments.length; i++) { + a[i+1] = arguments[i]; + } + throw a; +} + +/*** META ((export #t) + (peephole (prefix "throw "))) +*/ +function sc_raise(obj) { + throw obj; +} + +/*** META ((export with-handler-lambda)) */ +function sc_withHandlerLambda(handler, body) { + try { + return body(); + } catch(e) { + if (!e._internalException) + return handler(e); + else + throw e; + } +} + +var sc_properties = new Object(); + +/*** META ((export #t)) */ +function sc_putpropBang(sym, key, val) { + var ht = sc_properties[sym]; + if (!ht) { + ht = new Object(); + sc_properties[sym] = ht; + } + ht[key] = val; +} + +/*** META ((export #t)) */ +function sc_getprop(sym, key) { + var ht = sc_properties[sym]; + if (ht) { + if (key in ht) + return ht[key]; + else + return false; + } else + return false; +} + +/*** META ((export #t)) */ +function sc_rempropBang(sym, key) { + var ht = sc_properties[sym]; + if (ht) + delete ht[key]; +} + +/*** META ((export #t)) */ +function sc_any2String(o) { + return jsstring2string(sc_toDisplayString(o)); +} + +/*** META ((export #t) + (peephole (infix 2 2 "===")) + (type bool)) +*/ +function sc_isEqv(o1, o2) { + return (o1 === o2); +} + +/*** META ((export #t) + (peephole (infix 2 2 "===")) + (type bool)) +*/ +function sc_isEq(o1, o2) { + return (o1 === o2); +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isNumber(n) { + return (typeof n === "number"); +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isComplex(n) { + return sc_isNumber(n); +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isReal(n) { + return sc_isNumber(n); +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isRational(n) { + return sc_isReal(n); +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isInteger(n) { + return (parseInt(n) === n); +} + +/*** META ((export #t) + (type bool) + (peephole (postfix ", false"))) +*/ +// we don't have exact numbers... +function sc_isExact(n) { + return false; +} + +/*** META ((export #t) + (peephole (postfix ", true")) + (type bool)) +*/ +function sc_isInexact(n) { + return true; +} + +/*** META ((export = =fx =fl) + (type bool) + (peephole (infix 2 2 "==="))) +*/ +function sc_equal(x) { + for (var i = 1; i < arguments.length; i++) + if (x !== arguments[i]) + return false; + return true; +} + +/*** META ((export < = arguments[i]) + return false; + x = arguments[i]; + } + return true; +} + +/*** META ((export > >fx >fl) + (type bool) + (peephole (infix 2 2 ">"))) +*/ +function sc_greater(x, y) { + for (var i = 1; i < arguments.length; i++) { + if (x <= arguments[i]) + return false; + x = arguments[i]; + } + return true; +} + +/*** META ((export <= <=fx <=fl) + (type bool) + (peephole (infix 2 2 "<="))) +*/ +function sc_lessEqual(x, y) { + for (var i = 1; i < arguments.length; i++) { + if (x > arguments[i]) + return false; + x = arguments[i]; + } + return true; +} + +/*** META ((export >= >=fl >=fx) + (type bool) + (peephole (infix 2 2 ">="))) +*/ +function sc_greaterEqual(x, y) { + for (var i = 1; i < arguments.length; i++) { + if (x < arguments[i]) + return false; + x = arguments[i]; + } + return true; +} + +/*** META ((export #t) + (type bool) + (peephole (postfix "=== 0"))) +*/ +function sc_isZero(x) { + return (x === 0); +} + +/*** META ((export #t) + (type bool) + (peephole (postfix "> 0"))) +*/ +function sc_isPositive(x) { + return (x > 0); +} + +/*** META ((export #t) + (type bool) + (peephole (postfix "< 0"))) +*/ +function sc_isNegative(x) { + return (x < 0); +} + +/*** META ((export #t) + (type bool) + (peephole (postfix "%2===1"))) +*/ +function sc_isOdd(x) { + return (x % 2 === 1); +} + +/*** META ((export #t) + (type bool) + (peephole (postfix "%2===0"))) +*/ +function sc_isEven(x) { + return (x % 2 === 0); +} + +/*** META ((export #t)) */ +var sc_max = Math.max; +/*** META ((export #t)) */ +var sc_min = Math.min; + +/*** META ((export + +fx +fl) + (peephole (infix 0 #f "+" "0"))) +*/ +function sc_plus() { + var sum = 0; + for (var i = 0; i < arguments.length; i++) + sum += arguments[i]; + return sum; +} + +/*** META ((export * *fx *fl) + (peephole (infix 0 #f "*" "1"))) +*/ +function sc_multi() { + var product = 1; + for (var i = 0; i < arguments.length; i++) + product *= arguments[i]; + return product; +} + +/*** META ((export - -fx -fl) + (peephole (minus))) +*/ +function sc_minus(x) { + if (arguments.length === 1) + return -x; + else { + var res = x; + for (var i = 1; i < arguments.length; i++) + res -= arguments[i]; + return res; + } +} + +/*** META ((export / /fl) + (peephole (div))) +*/ +function sc_div(x) { + if (arguments.length === 1) + return 1/x; + else { + var res = x; + for (var i = 1; i < arguments.length; i++) + res /= arguments[i]; + return res; + } +} + +/*** META ((export #t)) */ +var sc_abs = Math.abs; + +/*** META ((export quotient /fx) + (peephole (hole 2 "parseInt(" x "/" y ")"))) +*/ +function sc_quotient(x, y) { + return parseInt(x / y); +} + +/*** META ((export #t) + (peephole (infix 2 2 "%"))) +*/ +function sc_remainder(x, y) { + return x % y; +} + +/*** META ((export #t) + (peephole (modulo))) +*/ +function sc_modulo(x, y) { + var remainder = x % y; + // if they don't have the same sign + if ((remainder * y) < 0) + return remainder + y; + else + return remainder; +} + +function sc_euclid_gcd(a, b) { + var temp; + if (a === 0) return b; + if (b === 0) return a; + if (a < 0) {a = -a;}; + if (b < 0) {b = -b;}; + if (b > a) {temp = a; a = b; b = temp;}; + while (true) { + a %= b; + if(a === 0) {return b;}; + b %= a; + if(b === 0) {return a;}; + }; + return b; +} + +/*** META ((export #t)) */ +function sc_gcd() { + var gcd = 0; + for (var i = 0; i < arguments.length; i++) + gcd = sc_euclid_gcd(gcd, arguments[i]); + return gcd; +} + +/*** META ((export #t)) */ +function sc_lcm() { + var lcm = 1; + for (var i = 0; i < arguments.length; i++) { + var f = Math.round(arguments[i] / sc_euclid_gcd(arguments[i], lcm)); + lcm *= Math.abs(f); + } + return lcm; +} + +// LIMITATION: numerator and denominator don't make sense in floating point world. +//var SC_MAX_DECIMALS = 1000000 +// +// function sc_numerator(x) { +// var rounded = Math.round(x * SC_MAX_DECIMALS); +// return Math.round(rounded / sc_euclid_gcd(rounded, SC_MAX_DECIMALS)); +// } + +// function sc_denominator(x) { +// var rounded = Math.round(x * SC_MAX_DECIMALS); +// return Math.round(SC_MAX_DECIMALS / sc_euclid_gcd(rounded, SC_MAX_DECIMALS)); +// } + +/*** META ((export #t)) */ +var sc_floor = Math.floor; +/*** META ((export #t)) */ +var sc_ceiling = Math.ceil; +/*** META ((export #t)) */ +var sc_truncate = parseInt; +/*** META ((export #t)) */ +var sc_round = Math.round; + +// LIMITATION: sc_rationalize doesn't make sense in a floating point world. + +/*** META ((export #t)) */ +var sc_exp = Math.exp; +/*** META ((export #t)) */ +var sc_log = Math.log; +/*** META ((export #t)) */ +var sc_sin = Math.sin; +/*** META ((export #t)) */ +var sc_cos = Math.cos; +/*** META ((export #t)) */ +var sc_tan = Math.tan; +/*** META ((export #t)) */ +var sc_asin = Math.asin; +/*** META ((export #t)) */ +var sc_acos = Math.acos; +/*** META ((export #t)) */ +var sc_atan = Math.atan; + +/*** META ((export #t)) */ +var sc_sqrt = Math.sqrt; +/*** META ((export #t)) */ +var sc_expt = Math.pow; + +// LIMITATION: we don't have complex numbers. +// LIMITATION: the following functions are hence not implemented. +// LIMITATION: make-rectangular, make-polar, real-part, imag-part, magnitude, angle +// LIMITATION: 2 argument atan + +/*** META ((export #t) + (peephole (id))) +*/ +function sc_exact2inexact(x) { + return x; +} + +/*** META ((export #t) + (peephole (id))) +*/ +function sc_inexact2exact(x) { + return x; +} + +function sc_number2jsstring(x, radix) { + if (radix) + return x.toString(radix); + else + return x.toString(); +} + +function sc_jsstring2number(s, radix) { + if (s === "") return false; + + if (radix) { + var t = parseInt(s, radix); + if (!t && t !== 0) return false; + // verify that each char is in range. (parseInt ignores leading + // white and trailing chars) + var allowedChars = "01234567890abcdefghijklmnopqrstuvwxyz".substring(0, radix+1); + if ((new RegExp("^["+allowedChars+"]*$", "i")).test(s)) + return t; + else return false; + } else { + var t = +s; // does not ignore trailing chars. + if (!t && t !== 0) return false; + // simply verify that first char is not whitespace. + var c = s.charAt(0); + // if +c is 0, but the char is not "0", then we have a whitespace. + if (+c === 0 && c !== "0") return false; + return t; + } +} + +/*** META ((export #t) + (type bool) + (peephole (not))) +*/ +function sc_not(b) { + return b === false; +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isBoolean(b) { + return (b === true) || (b === false); +} + +function sc_Pair(car, cdr) { + this.car = car; + this.cdr = cdr; +} + +sc_Pair.prototype.toString = function() { + return sc_toDisplayString(this); +}; +sc_Pair.prototype.sc_toWriteOrDisplayString = function(writeOrDisplay) { + var current = this; + + var res = "("; + + while(true) { + res += writeOrDisplay(current.car); + if (sc_isPair(current.cdr)) { + res += " "; + current = current.cdr; + } else if (current.cdr !== null) { + res += " . " + writeOrDisplay(current.cdr); + break; + } else // current.cdr == null + break; + } + + res += ")"; + + return res; +}; +sc_Pair.prototype.sc_toDisplayString = function() { + return this.sc_toWriteOrDisplayString(sc_toDisplayString); +}; +sc_Pair.prototype.sc_toWriteString = function() { + return this.sc_toWriteOrDisplayString(sc_toWriteString); +}; +// sc_Pair.prototype.sc_toWriteCircleString in IO.js + +/*** META ((export #t) + (type bool) + (peephole (postfix " instanceof sc_Pair"))) +*/ +function sc_isPair(p) { + return (p instanceof sc_Pair); +} + +function sc_isPairEqual(p1, p2, comp) { + return (comp(p1.car, p2.car) && comp(p1.cdr, p2.cdr)); +} + +/*** META ((export #t) + (peephole (hole 2 "new sc_Pair(" car ", " cdr ")"))) +*/ +function sc_cons(car, cdr) { + return new sc_Pair(car, cdr); +} + +/*** META ((export cons*)) */ +function sc_consStar() { + var res = arguments[arguments.length - 1]; + for (var i = arguments.length-2; i >= 0; i--) + res = new sc_Pair(arguments[i], res); + return res; +} + +/*** META ((export #t) + (peephole (postfix ".car"))) +*/ +function sc_car(p) { + return p.car; +} + +/*** META ((export #t) + (peephole (postfix ".cdr"))) +*/ +function sc_cdr(p) { + return p.cdr; +} + +/*** META ((export #t) + (peephole (hole 2 p ".car = " val))) +*/ +function sc_setCarBang(p, val) { + p.car = val; +} + +/*** META ((export #t) + (peephole (hole 2 p ".cdr = " val))) +*/ +function sc_setCdrBang(p, val) { + p.cdr = val; +} + +/*** META ((export #t) + (peephole (postfix ".car.car"))) +*/ +function sc_caar(p) { return p.car.car; } +/*** META ((export #t) + (peephole (postfix ".cdr.car"))) +*/ +function sc_cadr(p) { return p.cdr.car; } +/*** META ((export #t) + (peephole (postfix ".car.cdr"))) +*/ +function sc_cdar(p) { return p.car.cdr; } +/*** META ((export #t) + (peephole (postfix ".cdr.cdr"))) +*/ +function sc_cddr(p) { return p.cdr.cdr; } +/*** META ((export #t) + (peephole (postfix ".car.car.car"))) +*/ +function sc_caaar(p) { return p.car.car.car; } +/*** META ((export #t) + (peephole (postfix ".car.cdr.car"))) +*/ +function sc_cadar(p) { return p.car.cdr.car; } +/*** META ((export #t) + (peephole (postfix ".cdr.car.car"))) +*/ +function sc_caadr(p) { return p.cdr.car.car; } +/*** META ((export #t) + (peephole (postfix ".cdr.cdr.car"))) +*/ +function sc_caddr(p) { return p.cdr.cdr.car; } +/*** META ((export #t) + (peephole (postfix ".car.car.cdr"))) +*/ +function sc_cdaar(p) { return p.car.car.cdr; } +/*** META ((export #t) + (peephole (postfix ".cdr.car.cdr"))) +*/ +function sc_cdadr(p) { return p.cdr.car.cdr; } +/*** META ((export #t) + (peephole (postfix ".car.cdr.cdr"))) +*/ +function sc_cddar(p) { return p.car.cdr.cdr; } +/*** META ((export #t) + (peephole (postfix ".cdr.cdr.cdr"))) +*/ +function sc_cdddr(p) { return p.cdr.cdr.cdr; } +/*** META ((export #t) + (peephole (postfix ".car.car.car.car"))) +*/ +function sc_caaaar(p) { return p.car.car.car.car; } +/*** META ((export #t) + (peephole (postfix ".car.cdr.car.car"))) +*/ +function sc_caadar(p) { return p.car.cdr.car.car; } +/*** META ((export #t) + (peephole (postfix ".cdr.car.car.car"))) +*/ +function sc_caaadr(p) { return p.cdr.car.car.car; } +/*** META ((export #t) + (peephole (postfix ".cdr.cdr.car.car"))) +*/ +function sc_caaddr(p) { return p.cdr.cdr.car.car; } +/*** META ((export #t) + (peephole (postfix ".car.car.car.cdr"))) +*/ +function sc_cdaaar(p) { return p.car.car.car.cdr; } +/*** META ((export #t) + (peephole (postfix ".car.cdr.car.cdr"))) +*/ +function sc_cdadar(p) { return p.car.cdr.car.cdr; } +/*** META ((export #t) + (peephole (postfix ".cdr.car.car.cdr"))) +*/ +function sc_cdaadr(p) { return p.cdr.car.car.cdr; } +/*** META ((export #t) + (peephole (postfix ".cdr.cdr.car.cdr"))) +*/ +function sc_cdaddr(p) { return p.cdr.cdr.car.cdr; } +/*** META ((export #t) + (peephole (postfix ".car.car.cdr.car"))) +*/ +function sc_cadaar(p) { return p.car.car.cdr.car; } +/*** META ((export #t) + (peephole (postfix ".car.cdr.cdr.car"))) +*/ +function sc_caddar(p) { return p.car.cdr.cdr.car; } +/*** META ((export #t) + (peephole (postfix ".cdr.car.cdr.car"))) +*/ +function sc_cadadr(p) { return p.cdr.car.cdr.car; } +/*** META ((export #t) + (peephole (postfix ".cdr.cdr.cdr.car"))) +*/ +function sc_cadddr(p) { return p.cdr.cdr.cdr.car; } +/*** META ((export #t) + (peephole (postfix ".car.car.cdr.cdr"))) +*/ +function sc_cddaar(p) { return p.car.car.cdr.cdr; } +/*** META ((export #t) + (peephole (postfix ".car.cdr.cdr.cdr"))) +*/ +function sc_cdddar(p) { return p.car.cdr.cdr.cdr; } +/*** META ((export #t) + (peephole (postfix ".cdr.car.cdr.cdr"))) +*/ +function sc_cddadr(p) { return p.cdr.car.cdr.cdr; } +/*** META ((export #t) + (peephole (postfix ".cdr.cdr.cdr.cdr"))) +*/ +function sc_cddddr(p) { return p.cdr.cdr.cdr.cdr; } + +/*** META ((export #t)) */ +function sc_lastPair(l) { + if (!sc_isPair(l)) sc_error("sc_lastPair: pair expected"); + var res = l; + var cdr = l.cdr; + while (sc_isPair(cdr)) { + res = cdr; + cdr = res.cdr; + } + return res; +} + +/*** META ((export #t) + (type bool) + (peephole (postfix " === null"))) +*/ +function sc_isNull(o) { + return (o === null); +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isList(o) { + var rabbit; + var turtle; + + var rabbit = o; + var turtle = o; + while (true) { + if (rabbit === null || + (rabbit instanceof sc_Pair && rabbit.cdr === null)) + return true; // end of list + else if ((rabbit instanceof sc_Pair) && + (rabbit.cdr instanceof sc_Pair)) { + rabbit = rabbit.cdr.cdr; + turtle = turtle.cdr; + if (rabbit === turtle) return false; // cycle + } else + return false; // not pair + } +} + +/*** META ((export #t)) */ +function sc_list() { + var res = null; + var a = arguments; + for (var i = a.length-1; i >= 0; i--) + res = new sc_Pair(a[i], res); + return res; +} + +/*** META ((export #t)) */ +function sc_iota(num, init) { + var res = null; + if (!init) init = 0; + for (var i = num - 1; i >= 0; i--) + res = new sc_Pair(i + init, res); + return res; +} + +/*** META ((export #t)) */ +function sc_makeList(nbEls, fill) { + var res = null; + for (var i = 0; i < nbEls; i++) + res = new sc_Pair(fill, res); + return res; +} + +/*** META ((export #t)) */ +function sc_length(l) { + var res = 0; + while (l !== null) { + res++; + l = l.cdr; + } + return res; +} + +/*** META ((export #t)) */ +function sc_remq(o, l) { + var dummy = { cdr : null }; + var tail = dummy; + while (l !== null) { + if (l.car !== o) { + tail.cdr = sc_cons(l.car, null); + tail = tail.cdr; + } + l = l.cdr; + } + return dummy.cdr; +} + +/*** META ((export #t)) */ +function sc_remqBang(o, l) { + var dummy = { cdr : null }; + var tail = dummy; + var needsAssig = true; + while (l !== null) { + if (l.car === o) { + needsAssig = true; + } else { + if (needsAssig) { + tail.cdr = l; + needsAssig = false; + } + tail = l; + } + l = l.cdr; + } + tail.cdr = null; + return dummy.cdr; +} + +/*** META ((export #t)) */ +function sc_delete(o, l) { + var dummy = { cdr : null }; + var tail = dummy; + while (l !== null) { + if (!sc_isEqual(l.car, o)) { + tail.cdr = sc_cons(l.car, null); + tail = tail.cdr; + } + l = l.cdr; + } + return dummy.cdr; +} + +/*** META ((export #t)) */ +function sc_deleteBang(o, l) { + var dummy = { cdr : null }; + var tail = dummy; + var needsAssig = true; + while (l !== null) { + if (sc_isEqual(l.car, o)) { + needsAssig = true; + } else { + if (needsAssig) { + tail.cdr = l; + needsAssig = false; + } + tail = l; + } + l = l.cdr; + } + tail.cdr = null; + return dummy.cdr; +} + +function sc_reverseAppendBang(l1, l2) { + var res = l2; + while (l1 !== null) { + var tmp = res; + res = l1; + l1 = l1.cdr; + res.cdr = tmp; + } + return res; +} + +function sc_dualAppend(l1, l2) { + if (l1 === null) return l2; + if (l2 === null) return l1; + var rev = sc_reverse(l1); + return sc_reverseAppendBang(rev, l2); +} + +/*** META ((export #t)) */ +function sc_append() { + if (arguments.length === 0) + return null; + var res = arguments[arguments.length - 1]; + for (var i = arguments.length - 2; i >= 0; i--) + res = sc_dualAppend(arguments[i], res); + return res; +} + +function sc_dualAppendBang(l1, l2) { + if (l1 === null) return l2; + if (l2 === null) return l1; + var tmp = l1; + while (tmp.cdr !== null) tmp=tmp.cdr; + tmp.cdr = l2; + return l1; +} + +/*** META ((export #t)) */ +function sc_appendBang() { + var res = null; + for (var i = 0; i < arguments.length; i++) + res = sc_dualAppendBang(res, arguments[i]); + return res; +} + +/*** META ((export #t)) */ +function sc_reverse(l1) { + var res = null; + while (l1 !== null) { + res = sc_cons(l1.car, res); + l1 = l1.cdr; + } + return res; +} + +/*** META ((export #t)) */ +function sc_reverseBang(l) { + return sc_reverseAppendBang(l, null); +} + +/*** META ((export #t)) */ +function sc_listTail(l, k) { + var res = l; + for (var i = 0; i < k; i++) { + res = res.cdr; + } + return res; +} + +/*** META ((export #t)) */ +function sc_listRef(l, k) { + return sc_listTail(l, k).car; +} + +/* // unoptimized generic versions +function sc_memX(o, l, comp) { + while (l != null) { + if (comp(l.car, o)) + return l; + l = l.cdr; + } + return false; +} +function sc_memq(o, l) { return sc_memX(o, l, sc_isEq); } +function sc_memv(o, l) { return sc_memX(o, l, sc_isEqv); } +function sc_member(o, l) { return sc_memX(o, l, sc_isEqual); } +*/ + +/* optimized versions */ +/*** META ((export #t)) */ +function sc_memq(o, l) { + while (l !== null) { + if (l.car === o) + return l; + l = l.cdr; + } + return false; +} +/*** META ((export #t)) */ +function sc_memv(o, l) { + while (l !== null) { + if (l.car === o) + return l; + l = l.cdr; + } + return false; +} +/*** META ((export #t)) */ +function sc_member(o, l) { + while (l !== null) { + if (sc_isEqual(l.car,o)) + return l; + l = l.cdr; + } + return false; +} + +/* // generic unoptimized versions +function sc_assX(o, al, comp) { + while (al != null) { + if (comp(al.car.car, o)) + return al.car; + al = al.cdr; + } + return false; +} +function sc_assq(o, al) { return sc_assX(o, al, sc_isEq); } +function sc_assv(o, al) { return sc_assX(o, al, sc_isEqv); } +function sc_assoc(o, al) { return sc_assX(o, al, sc_isEqual); } +*/ +// optimized versions +/*** META ((export #t)) */ +function sc_assq(o, al) { + while (al !== null) { + if (al.car.car === o) + return al.car; + al = al.cdr; + } + return false; +} +/*** META ((export #t)) */ +function sc_assv(o, al) { + while (al !== null) { + if (al.car.car === o) + return al.car; + al = al.cdr; + } + return false; +} +/*** META ((export #t)) */ +function sc_assoc(o, al) { + while (al !== null) { + if (sc_isEqual(al.car.car, o)) + return al.car; + al = al.cdr; + } + return false; +} + +/* can be used for mutable strings and characters */ +function sc_isCharStringEqual(cs1, cs2) { return cs1.val === cs2.val; } +function sc_isCharStringLess(cs1, cs2) { return cs1.val < cs2.val; } +function sc_isCharStringGreater(cs1, cs2) { return cs1.val > cs2.val; } +function sc_isCharStringLessEqual(cs1, cs2) { return cs1.val <= cs2.val; } +function sc_isCharStringGreaterEqual(cs1, cs2) { return cs1.val >= cs2.val; } +function sc_isCharStringCIEqual(cs1, cs2) + { return cs1.val.toLowerCase() === cs2.val.toLowerCase(); } +function sc_isCharStringCILess(cs1, cs2) + { return cs1.val.toLowerCase() < cs2.val.toLowerCase(); } +function sc_isCharStringCIGreater(cs1, cs2) + { return cs1.val.toLowerCase() > cs2.val.toLowerCase(); } +function sc_isCharStringCILessEqual(cs1, cs2) + { return cs1.val.toLowerCase() <= cs2.val.toLowerCase(); } +function sc_isCharStringCIGreaterEqual(cs1, cs2) + { return cs1.val.toLowerCase() >= cs2.val.toLowerCase(); } + + + + +function sc_Char(c) { + var cached = sc_Char.lazy[c]; + if (cached) + return cached; + this.val = c; + sc_Char.lazy[c] = this; + // add return, so FF does not complain. + return undefined; +} +sc_Char.lazy = new Object(); +// thanks to Eric +sc_Char.char2readable = { + "\000": "#\\null", + "\007": "#\\bell", + "\010": "#\\backspace", + "\011": "#\\tab", + "\012": "#\\newline", + "\014": "#\\page", + "\015": "#\\return", + "\033": "#\\escape", + "\040": "#\\space", + "\177": "#\\delete", + + /* poeticless names */ + "\001": "#\\soh", + "\002": "#\\stx", + "\003": "#\\etx", + "\004": "#\\eot", + "\005": "#\\enq", + "\006": "#\\ack", + + "\013": "#\\vt", + "\016": "#\\so", + "\017": "#\\si", + + "\020": "#\\dle", + "\021": "#\\dc1", + "\022": "#\\dc2", + "\023": "#\\dc3", + "\024": "#\\dc4", + "\025": "#\\nak", + "\026": "#\\syn", + "\027": "#\\etb", + + "\030": "#\\can", + "\031": "#\\em", + "\032": "#\\sub", + "\033": "#\\esc", + "\034": "#\\fs", + "\035": "#\\gs", + "\036": "#\\rs", + "\037": "#\\us"}; + +sc_Char.readable2char = { + "null": "\000", + "bell": "\007", + "backspace": "\010", + "tab": "\011", + "newline": "\012", + "page": "\014", + "return": "\015", + "escape": "\033", + "space": "\040", + "delete": "\000", + "soh": "\001", + "stx": "\002", + "etx": "\003", + "eot": "\004", + "enq": "\005", + "ack": "\006", + "bel": "\007", + "bs": "\010", + "ht": "\011", + "nl": "\012", + "vt": "\013", + "np": "\014", + "cr": "\015", + "so": "\016", + "si": "\017", + "dle": "\020", + "dc1": "\021", + "dc2": "\022", + "dc3": "\023", + "dc4": "\024", + "nak": "\025", + "syn": "\026", + "etb": "\027", + "can": "\030", + "em": "\031", + "sub": "\032", + "esc": "\033", + "fs": "\034", + "gs": "\035", + "rs": "\036", + "us": "\037", + "sp": "\040", + "del": "\177"}; + +sc_Char.prototype.toString = function() { + return this.val; +}; +// sc_toDisplayString == toString +sc_Char.prototype.sc_toWriteString = function() { + var entry = sc_Char.char2readable[this.val]; + if (entry) + return entry; + else + return "#\\" + this.val; +}; + +/*** META ((export #t) + (type bool) + (peephole (postfix "instanceof sc_Char"))) +*/ +function sc_isChar(c) { + return (c instanceof sc_Char); +} + +/*** META ((export char=?) + (type bool) + (peephole (hole 2 c1 ".val === " c2 ".val"))) +*/ +var sc_isCharEqual = sc_isCharStringEqual; +/*** META ((export char?) + (type bool) + (peephole (hole 2 c1 ".val > " c2 ".val"))) +*/ +var sc_isCharGreater = sc_isCharStringGreater; +/*** META ((export char<=?) + (type bool) + (peephole (hole 2 c1 ".val <= " c2 ".val"))) +*/ +var sc_isCharLessEqual = sc_isCharStringLessEqual; +/*** META ((export char>=?) + (type bool) + (peephole (hole 2 c1 ".val >= " c2 ".val"))) +*/ +var sc_isCharGreaterEqual = sc_isCharStringGreaterEqual; +/*** META ((export char-ci=?) + (type bool) + (peephole (hole 2 c1 ".val.toLowerCase() === " c2 ".val.toLowerCase()"))) +*/ +var sc_isCharCIEqual = sc_isCharStringCIEqual; +/*** META ((export char-ci?) + (type bool) + (peephole (hole 2 c1 ".val.toLowerCase() > " c2 ".val.toLowerCase()"))) +*/ +var sc_isCharCIGreater = sc_isCharStringCIGreater; +/*** META ((export char-ci<=?) + (type bool) + (peephole (hole 2 c1 ".val.toLowerCase() <= " c2 ".val.toLowerCase()"))) +*/ +var sc_isCharCILessEqual = sc_isCharStringCILessEqual; +/*** META ((export char-ci>=?) + (type bool) + (peephole (hole 2 c1 ".val.toLowerCase() >= " c2 ".val.toLowerCase()"))) +*/ +var sc_isCharCIGreaterEqual = sc_isCharStringCIGreaterEqual; + +var SC_NUMBER_CLASS = "0123456789"; +var SC_WHITESPACE_CLASS = ' \r\n\t\f'; +var SC_LOWER_CLASS = 'abcdefghijklmnopqrstuvwxyz'; +var SC_UPPER_CLASS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + +function sc_isCharOfClass(c, cl) { return (cl.indexOf(c) != -1); } +/*** META ((export #t) + (type bool)) +*/ +function sc_isCharAlphabetic(c) + { return sc_isCharOfClass(c.val, SC_LOWER_CLASS) || + sc_isCharOfClass(c.val, SC_UPPER_CLASS); } +/*** META ((export #t) + (type bool) + (peephole (hole 1 "SC_NUMBER_CLASS.indexOf(" c ".val) != -1"))) +*/ +function sc_isCharNumeric(c) + { return sc_isCharOfClass(c.val, SC_NUMBER_CLASS); } +/*** META ((export #t) + (type bool)) +*/ +function sc_isCharWhitespace(c) { + var tmp = c.val; + return tmp === " " || tmp === "\r" || tmp === "\n" || tmp === "\t" || tmp === "\f"; +} +/*** META ((export #t) + (type bool) + (peephole (hole 1 "SC_UPPER_CLASS.indexOf(" c ".val) != -1"))) +*/ +function sc_isCharUpperCase(c) + { return sc_isCharOfClass(c.val, SC_UPPER_CLASS); } +/*** META ((export #t) + (type bool) + (peephole (hole 1 "SC_LOWER_CLASS.indexOf(" c ".val) != -1"))) +*/ +function sc_isCharLowerCase(c) + { return sc_isCharOfClass(c.val, SC_LOWER_CLASS); } + +/*** META ((export #t) + (peephole (postfix ".val.charCodeAt(0)"))) +*/ +function sc_char2integer(c) + { return c.val.charCodeAt(0); } +/*** META ((export #t) + (peephole (hole 1 "new sc_Char(String.fromCharCode(" n "))"))) +*/ +function sc_integer2char(n) + { return new sc_Char(String.fromCharCode(n)); } + +/*** META ((export #t) + (peephole (hole 1 "new sc_Char(" c ".val.toUpperCase())"))) +*/ +function sc_charUpcase(c) + { return new sc_Char(c.val.toUpperCase()); } +/*** META ((export #t) + (peephole (hole 1 "new sc_Char(" c ".val.toLowerCase())"))) +*/ +function sc_charDowncase(c) + { return new sc_Char(c.val.toLowerCase()); } + +function sc_makeJSStringOfLength(k, c) { + var fill; + if (c === undefined) + fill = " "; + else + fill = c; + var res = ""; + var len = 1; + // every round doubles the size of fill. + while (k >= len) { + if (k & len) + res = res.concat(fill); + fill = fill.concat(fill); + len *= 2; + } + return res; +} + +function sc_makejsString(k, c) { + var fill; + if (c) + fill = c.val; + else + fill = " "; + return sc_makeJSStringOfLength(k, fill); +} + +function sc_jsstring2list(s) { + var res = null; + for (var i = s.length - 1; i >= 0; i--) + res = sc_cons(new sc_Char(s.charAt(i)), res); + return res; +} + +function sc_list2jsstring(l) { + var a = new Array(); + while(l !== null) { + a.push(l.car.val); + l = l.cdr; + } + return "".concat.apply("", a); +} + +var sc_Vector = Array; + +sc_Vector.prototype.sc_toWriteOrDisplayString = function(writeOrDisplay) { + if (this.length === 0) return "#()"; + + var res = "#(" + writeOrDisplay(this[0]); + for (var i = 1; i < this.length; i++) + res += " " + writeOrDisplay(this[i]); + res += ")"; + return res; +}; +sc_Vector.prototype.sc_toDisplayString = function() { + return this.sc_toWriteOrDisplayString(sc_toDisplayString); +}; +sc_Vector.prototype.sc_toWriteString = function() { + return this.sc_toWriteOrDisplayString(sc_toWriteString); +}; + +/*** META ((export vector? array?) + (type bool) + (peephole (postfix " instanceof sc_Vector"))) +*/ +function sc_isVector(v) { + return (v instanceof sc_Vector); +} + +// only applies to vectors +function sc_isVectorEqual(v1, v2, comp) { + if (v1.length !== v2.length) return false; + for (var i = 0; i < v1.length; i++) + if (!comp(v1[i], v2[i])) return false; + return true; +} + +/*** META ((export make-vector make-array)) */ +function sc_makeVector(size, fill) { + var a = new sc_Vector(size); + if (fill !== undefined) + sc_vectorFillBang(a, fill); + return a; +} + +/*** META ((export vector array) + (peephole (vector))) +*/ +function sc_vector() { + var a = new sc_Vector(); + for (var i = 0; i < arguments.length; i++) + a.push(arguments[i]); + return a; +} + +/*** META ((export vector-length array-length) + (peephole (postfix ".length"))) +*/ +function sc_vectorLength(v) { + return v.length; +} + +/*** META ((export vector-ref array-ref) + (peephole (hole 2 v "[" pos "]"))) +*/ +function sc_vectorRef(v, pos) { + return v[pos]; +} + +/*** META ((export vector-set! array-set!) + (peephole (hole 3 v "[" pos "] = " val))) +*/ +function sc_vectorSetBang(v, pos, val) { + v[pos] = val; +} + +/*** META ((export vector->list array->list)) */ +function sc_vector2list(a) { + var res = null; + for (var i = a.length-1; i >= 0; i--) + res = sc_cons(a[i], res); + return res; +} + +/*** META ((export list->vector list->array)) */ +function sc_list2vector(l) { + var a = new sc_Vector(); + while(l !== null) { + a.push(l.car); + l = l.cdr; + } + return a; +} + +/*** META ((export vector-fill! array-fill!)) */ +function sc_vectorFillBang(a, fill) { + for (var i = 0; i < a.length; i++) + a[i] = fill; +} + + +/*** META ((export #t)) */ +function sc_copyVector(a, len) { + if (len <= a.length) + return a.slice(0, len); + else { + var tmp = a.concat(); + tmp.length = len; + return tmp; + } +} + +/*** META ((export #t) + (peephole (hole 3 a ".slice(" start "," end ")"))) +*/ +function sc_vectorCopy(a, start, end) { + return a.slice(start, end); +} + +/*** META ((export #t)) */ +function sc_vectorCopyBang(target, tstart, source, sstart, send) { + if (!sstart) sstart = 0; + if (!send) send = source.length; + + // if target == source we don't want to overwrite not yet copied elements. + if (tstart <= sstart) { + for (var i = tstart, j = sstart; j < send; i++, j++) { + target[i] = source[j]; + } + } else { + var diff = send - sstart; + for (var i = tstart + diff - 1, j = send - 1; + j >= sstart; + i--, j--) { + target[i] = source[j]; + } + } + return target; +} + +/*** META ((export #t) + (type bool) + (peephole (hole 1 "typeof " o " === 'function'"))) +*/ +function sc_isProcedure(o) { + return (typeof o === "function"); +} + +/*** META ((export #t)) */ +function sc_apply(proc) { + var args = new Array(); + // first part of arguments are not in list-form. + for (var i = 1; i < arguments.length - 1; i++) + args.push(arguments[i]); + var l = arguments[arguments.length - 1]; + while (l !== null) { + args.push(l.car); + l = l.cdr; + } + return proc.apply(null, args); +} + +/*** META ((export #t)) */ +function sc_map(proc, l1) { + if (l1 === undefined) + return null; + // else + var nbApplyArgs = arguments.length - 1; + var applyArgs = new Array(nbApplyArgs); + var revres = null; + while (l1 !== null) { + for (var i = 0; i < nbApplyArgs; i++) { + applyArgs[i] = arguments[i + 1].car; + arguments[i + 1] = arguments[i + 1].cdr; + } + revres = sc_cons(proc.apply(null, applyArgs), revres); + } + return sc_reverseAppendBang(revres, null); +} + +/*** META ((export #t)) */ +function sc_mapBang(proc, l1) { + if (l1 === undefined) + return null; + // else + var l1_orig = l1; + var nbApplyArgs = arguments.length - 1; + var applyArgs = new Array(nbApplyArgs); + while (l1 !== null) { + var tmp = l1; + for (var i = 0; i < nbApplyArgs; i++) { + applyArgs[i] = arguments[i + 1].car; + arguments[i + 1] = arguments[i + 1].cdr; + } + tmp.car = proc.apply(null, applyArgs); + } + return l1_orig; +} + +/*** META ((export #t)) */ +function sc_forEach(proc, l1) { + if (l1 === undefined) + return undefined; + // else + var nbApplyArgs = arguments.length - 1; + var applyArgs = new Array(nbApplyArgs); + while (l1 !== null) { + for (var i = 0; i < nbApplyArgs; i++) { + applyArgs[i] = arguments[i + 1].car; + arguments[i + 1] = arguments[i + 1].cdr; + } + proc.apply(null, applyArgs); + } + // add return so FF does not complain. + return undefined; +} + +/*** META ((export #t)) */ +function sc_filter(proc, l1) { + var dummy = { cdr : null }; + var tail = dummy; + while (l1 !== null) { + if (proc(l1.car) !== false) { + tail.cdr = sc_cons(l1.car, null); + tail = tail.cdr; + } + l1 = l1.cdr; + } + return dummy.cdr; +} + +/*** META ((export #t)) */ +function sc_filterBang(proc, l1) { + var head = sc_cons("dummy", l1); + var it = head; + var next = l1; + while (next !== null) { + if (proc(next.car) !== false) { + it.cdr = next + it = next; + } + next = next.cdr; + } + it.cdr = null; + return head.cdr; +} + +function sc_filterMap1(proc, l1) { + var revres = null; + while (l1 !== null) { + var tmp = proc(l1.car) + if (tmp !== false) revres = sc_cons(tmp, revres); + l1 = l1.cdr; + } + return sc_reverseAppendBang(revres, null); +} +function sc_filterMap2(proc, l1, l2) { + var revres = null; + while (l1 !== null) { + var tmp = proc(l1.car, l2.car); + if(tmp !== false) revres = sc_cons(tmp, revres); + l1 = l1.cdr; + l2 = l2.cdr + } + return sc_reverseAppendBang(revres, null); +} + +/*** META ((export #t)) */ +function sc_filterMap(proc, l1, l2, l3) { + if (l2 === undefined) + return sc_filterMap1(proc, l1); + else if (l3 === undefined) + return sc_filterMap2(proc, l1, l2); + // else + var nbApplyArgs = arguments.length - 1; + var applyArgs = new Array(nbApplyArgs); + var revres = null; + while (l1 !== null) { + for (var i = 0; i < nbApplyArgs; i++) { + applyArgs[i] = arguments[i + 1].car; + arguments[i + 1] = arguments[i + 1].cdr; + } + var tmp = proc.apply(null, applyArgs); + if(tmp !== false) revres = sc_cons(tmp, revres); + } + return sc_reverseAppendBang(revres, null); +} + +/*** META ((export #t)) */ +function sc_any(proc, l) { + var revres = null; + while (l !== null) { + var tmp = proc(l.car); + if(tmp !== false) return tmp; + l = l.cdr; + } + return false; +} + +/*** META ((export any?) + (peephole (hole 2 "sc_any(" proc "," l ") !== false"))) +*/ +function sc_anyPred(proc, l) { + return sc_any(proc, l)!== false; +} + +/*** META ((export #t)) */ +function sc_every(proc, l) { + var revres = null; + var tmp = true; + while (l !== null) { + tmp = proc(l.car); + if (tmp === false) return false; + l = l.cdr; + } + return tmp; +} + +/*** META ((export every?) + (peephole (hole 2 "sc_every(" proc "," l ") !== false"))) +*/ +function sc_everyPred(proc, l) { + var tmp = sc_every(proc, l); + if (tmp !== false) return true; + return false; +} + +/*** META ((export #t) + (peephole (postfix "()"))) +*/ +function sc_force(o) { + return o(); +} + +/*** META ((export #t)) */ +function sc_makePromise(proc) { + var isResultReady = false; + var result = undefined; + return function() { + if (!isResultReady) { + var tmp = proc(); + if (!isResultReady) { + isResultReady = true; + result = tmp; + } + } + return result; + }; +} + +function sc_Values(values) { + this.values = values; +} + +/*** META ((export #t) + (peephole (values))) +*/ +function sc_values() { + if (arguments.length === 1) + return arguments[0]; + else + return new sc_Values(arguments); +} + +/*** META ((export #t)) */ +function sc_callWithValues(producer, consumer) { + var produced = producer(); + if (produced instanceof sc_Values) + return consumer.apply(null, produced.values); + else + return consumer(produced); +} + +/*** META ((export #t)) */ +function sc_dynamicWind(before, thunk, after) { + before(); + try { + var res = thunk(); + return res; + } finally { + after(); + } +} + + +// TODO: eval/scheme-report-environment/null-environment/interaction-environment + +// LIMITATION: 'load' doesn't exist without files. +// LIMITATION: transcript-on/transcript-off doesn't exist without files. + + +function sc_Struct(name) { + this.name = name; +} +sc_Struct.prototype.sc_toDisplayString = function() { + return "#"; +}; +sc_Struct.prototype.sc_toWriteString = sc_Struct.prototype.sc_toDisplayString; + +/*** META ((export #t) + (peephole (hole 1 "new sc_Struct(" name ")"))) +*/ +function sc_makeStruct(name) { + return new sc_Struct(name); +} + +/*** META ((export #t) + (type bool) + (peephole (postfix " instanceof sc_Struct"))) +*/ +function sc_isStruct(o) { + return (o instanceof sc_Struct); +} + +/*** META ((export #t) + (type bool) + (peephole (hole 2 "(" 1 " instanceof sc_Struct) && ( " 1 ".name === " 0 ")"))) +*/ +function sc_isStructNamed(name, s) { + return ((s instanceof sc_Struct) && (s.name === name)); +} + +/*** META ((export struct-field) + (peephole (hole 3 0 "[" 2 "]"))) +*/ +function sc_getStructField(s, name, field) { + return s[field]; +} + +/*** META ((export struct-field-set!) + (peephole (hole 4 0 "[" 2 "] = " 3))) +*/ +function sc_setStructFieldBang(s, name, field, val) { + s[field] = val; +} + +/*** META ((export #t) + (peephole (prefix "~"))) +*/ +function sc_bitNot(x) { + return ~x; +} + +/*** META ((export #t) + (peephole (infix 2 2 "&"))) +*/ +function sc_bitAnd(x, y) { + return x & y; +} + +/*** META ((export #t) + (peephole (infix 2 2 "|"))) +*/ +function sc_bitOr(x, y) { + return x | y; +} + +/*** META ((export #t) + (peephole (infix 2 2 "^"))) +*/ +function sc_bitXor(x, y) { + return x ^ y; +} + +/*** META ((export #t) + (peephole (infix 2 2 "<<"))) +*/ +function sc_bitLsh(x, y) { + return x << y; +} + +/*** META ((export #t) + (peephole (infix 2 2 ">>"))) +*/ +function sc_bitRsh(x, y) { + return x >> y; +} + +/*** META ((export #t) + (peephole (infix 2 2 ">>>"))) +*/ +function sc_bitUrsh(x, y) { + return x >>> y; +} + +/*** META ((export js-field js-property) + (peephole (hole 2 o "[" field "]"))) +*/ +function sc_jsField(o, field) { + return o[field]; +} + +/*** META ((export js-field-set! js-property-set!) + (peephole (hole 3 o "[" field "] = " val))) +*/ +function sc_setJsFieldBang(o, field, val) { + return o[field] = val; +} + +/*** META ((export js-field-delete! js-property-delete!) + (peephole (hole 2 "delete" o "[" field "]"))) +*/ +function sc_deleteJsFieldBang(o, field) { + delete o[field]; +} + +/*** META ((export #t) + (peephole (jsCall))) +*/ +function sc_jsCall(o, fun) { + var args = new Array(); + for (var i = 2; i < arguments.length; i++) + args[i-2] = arguments[i]; + return fun.apply(o, args); +} + +/*** META ((export #t) + (peephole (jsMethodCall))) +*/ +function sc_jsMethodCall(o, field) { + var args = new Array(); + for (var i = 2; i < arguments.length; i++) + args[i-2] = arguments[i]; + return o[field].apply(o, args); +} + +/*** META ((export new js-new) + (peephole (jsNew))) +*/ +function sc_jsNew(c) { + var evalStr = "new c("; + evalStr +=arguments.length > 1? "arguments[1]": ""; + for (var i = 2; i < arguments.length; i++) + evalStr += ", arguments[" + i + "]"; + evalStr +=")"; + return eval(evalStr); +} + +// ======================== RegExp ==================== +/*** META ((export #t)) */ +function sc_pregexp(re) { + return new RegExp(sc_string2jsstring(re)); +} + +/*** META ((export #t)) */ +function sc_pregexpMatch(re, s) { + var reg = (re instanceof RegExp) ? re : sc_pregexp(re); + var tmp = reg.exec(sc_string2jsstring(s)); + + if (tmp == null) return false; + + var res = null; + for (var i = tmp.length-1; i >= 0; i--) { + if (tmp[i] !== null) { + res = sc_cons(sc_jsstring2string(tmp[i]), res); + } else { + res = sc_cons(false, res); + } + } + return res; +} + +/*** META ((export #t)) */ +function sc_pregexpReplace(re, s1, s2) { + var reg; + var jss1 = sc_string2jsstring(s1); + var jss2 = sc_string2jsstring(s2); + + if (re instanceof RegExp) { + if (re.global) + reg = re; + else + reg = new RegExp(re.source); + } else { + reg = new RegExp(sc_string2jsstring(re)); + } + + return jss1.replace(reg, jss2); +} + +/*** META ((export pregexp-replace*)) */ +function sc_pregexpReplaceAll(re, s1, s2) { + var reg; + var jss1 = sc_string2jsstring(s1); + var jss2 = sc_string2jsstring(s2); + + if (re instanceof RegExp) { + if (re.global) + reg = re; + else + reg = new RegExp(re.source, "g"); + } else { + reg = new RegExp(sc_string2jsstring(re), "g"); + } + + return jss1.replace(reg, jss2); +} + +/*** META ((export #t)) */ +function sc_pregexpSplit(re, s) { + var reg = ((re instanceof RegExp) ? + re : + new RegExp(sc_string2jsstring(re))); + var jss = sc_string2jsstring(s); + var tmp = jss.split(reg); + + if (tmp == null) return false; + + return sc_vector2list(tmp); +} + + +/* =========================================================================== */ +/* Other library stuff */ +/* =========================================================================== */ + +/*** META ((export #t) + (peephole (hole 1 "Math.floor(Math.random()*" 'n ")"))) +*/ +function sc_random(n) { + return Math.floor(Math.random()*n); +} + +/*** META ((export current-date) + (peephole (hole 0 "new Date()"))) +*/ +function sc_currentDate() { + return new Date(); +} + +function sc_Hashtable() { +} +sc_Hashtable.prototype.toString = function() { + return "#{%hashtable}"; +}; +// sc_toWriteString == sc_toDisplayString == toString + +function sc_HashtableElement(key, val) { + this.key = key; + this.val = val; +} + +/*** META ((export #t) + (peephole (hole 0 "new sc_Hashtable()"))) +*/ +function sc_makeHashtable() { + return new sc_Hashtable(); +} + +/*** META ((export #t)) */ +function sc_hashtablePutBang(ht, key, val) { + var hash = sc_hash(key); + ht[hash] = new sc_HashtableElement(key, val); +} + +/*** META ((export #t)) */ +function sc_hashtableGet(ht, key) { + var hash = sc_hash(key); + if (hash in ht) + return ht[hash].val; + else + return false; +} + +/*** META ((export #t)) */ +function sc_hashtableForEach(ht, f) { + for (var v in ht) { + if (ht[v] instanceof sc_HashtableElement) + f(ht[v].key, ht[v].val); + } +} + +/*** META ((export hashtable-contains?) + (peephole (hole 2 "sc_hash(" 1 ") in " 0))) +*/ +function sc_hashtableContains(ht, key) { + var hash = sc_hash(key); + if (hash in ht) + return true; + else + return false; +} + +var SC_HASH_COUNTER = 0; + +function sc_hash(o) { + if (o === null) + return "null"; + else if (o === undefined) + return "undefined"; + else if (o === true) + return "true"; + else if (o === false) + return "false"; + else if (typeof o === "number") + return "num-" + o; + else if (typeof o === "string") + return "jsstr-" + o; + else if (o.sc_getHash) + return o.sc_getHash(); + else + return sc_counterHash.call(o); +} +function sc_counterHash() { + if (!this.sc_hash) { + this.sc_hash = "hash-" + SC_HASH_COUNTER; + SC_HASH_COUNTER++; + } + return this.sc_hash; +} + +function sc_Trampoline(args, maxTailCalls) { + this['__trampoline return__'] = true; + this.args = args; + this.MAX_TAIL_CALLs = maxTailCalls; +} +// TODO: call/cc stuff +sc_Trampoline.prototype.restart = function() { + var o = this; + while (true) { + // set both globals. + SC_TAIL_OBJECT.calls = o.MAX_TAIL_CALLs-1; + var fun = o.args.callee; + var res = fun.apply(SC_TAIL_OBJECT, o.args); + if (res instanceof sc_Trampoline) + o = res; + else + return res; + } +} + +/*** META ((export bind-exit-lambda)) */ +function sc_bindExitLambda(proc) { + var escape_obj = new sc_BindExitException(); + var escape = function(res) { + escape_obj.res = res; + throw escape_obj; + }; + try { + return proc(escape); + } catch(e) { + if (e === escape_obj) { + return e.res; + } + throw e; + } +} +function sc_BindExitException() { + this._internalException = true; +} + +var SC_SCM2JS_GLOBALS = new Object(); + +// default tail-call depth. +// normally the program should set it again. but just in case... +var SC_TAIL_OBJECT = new Object(); +SC_SCM2JS_GLOBALS.TAIL_OBJECT = SC_TAIL_OBJECT; +// ======================== I/O ======================= + +/*------------------------------------------------------------------*/ + +function sc_EOF() { +} +var SC_EOF_OBJECT = new sc_EOF(); + +function sc_Port() { +} + +/* --------------- Input ports -------------------------------------*/ + +function sc_InputPort() { +} +sc_InputPort.prototype = new sc_Port(); + +sc_InputPort.prototype.peekChar = function() { + if (!("peeked" in this)) + this.peeked = this.getNextChar(); + return this.peeked; +} +sc_InputPort.prototype.readChar = function() { + var tmp = this.peekChar(); + delete this.peeked; + return tmp; +} +sc_InputPort.prototype.isCharReady = function() { + return true; +} +sc_InputPort.prototype.close = function() { + // do nothing +} + +/* .............. String port ..........................*/ +function sc_ErrorInputPort() { +}; +sc_ErrorInputPort.prototype = new sc_InputPort(); +sc_ErrorInputPort.prototype.getNextChar = function() { + throw "can't read from error-port."; +}; +sc_ErrorInputPort.prototype.isCharReady = function() { + return false; +}; + + +/* .............. String port ..........................*/ + +function sc_StringInputPort(jsStr) { + // we are going to do some charAts on the str. + // instead of recreating all the time a String-object, we + // create one in the beginning. (not sure, if this is really an optim) + this.str = new String(jsStr); + this.pos = 0; +} +sc_StringInputPort.prototype = new sc_InputPort(); +sc_StringInputPort.prototype.getNextChar = function() { + if (this.pos >= this.str.length) + return SC_EOF_OBJECT; + return this.str.charAt(this.pos++); +}; + +/* ------------- Read and other lib-funs -------------------------------*/ +function sc_Token(type, val, pos) { + this.type = type; + this.val = val; + this.pos = pos; +} +sc_Token.EOF = 0/*EOF*/; +sc_Token.OPEN_PAR = 1/*OPEN_PAR*/; +sc_Token.CLOSE_PAR = 2/*CLOSE_PAR*/; +sc_Token.OPEN_BRACE = 3/*OPEN_BRACE*/; +sc_Token.CLOSE_BRACE = 4/*CLOSE_BRACE*/; +sc_Token.OPEN_BRACKET = 5/*OPEN_BRACKET*/; +sc_Token.CLOSE_BRACKET = 6/*CLOSE_BRACKET*/; +sc_Token.WHITESPACE = 7/*WHITESPACE*/; +sc_Token.QUOTE = 8/*QUOTE*/; +sc_Token.ID = 9/*ID*/; +sc_Token.DOT = 10/*DOT*/; +sc_Token.STRING = 11/*STRING*/; +sc_Token.NUMBER = 12/*NUMBER*/; +sc_Token.ERROR = 13/*ERROR*/; +sc_Token.VECTOR_BEGIN = 14/*VECTOR_BEGIN*/; +sc_Token.TRUE = 15/*TRUE*/; +sc_Token.FALSE = 16/*FALSE*/; +sc_Token.UNSPECIFIED = 17/*UNSPECIFIED*/; +sc_Token.REFERENCE = 18/*REFERENCE*/; +sc_Token.STORE = 19/*STORE*/; +sc_Token.CHAR = 20/*CHAR*/; + +var SC_ID_CLASS = SC_LOWER_CLASS + SC_UPPER_CLASS + "!$%*+-./:<=>?@^_~"; +function sc_Tokenizer(port) { + this.port = port; +} +sc_Tokenizer.prototype.peekToken = function() { + if (this.peeked) + return this.peeked; + var newToken = this.nextToken(); + this.peeked = newToken; + return newToken; +}; +sc_Tokenizer.prototype.readToken = function() { + var tmp = this.peekToken(); + delete this.peeked; + return tmp; +}; +sc_Tokenizer.prototype.nextToken = function() { + var port = this.port; + + function isNumberChar(c) { + return (c >= "0" && c <= "9"); + }; + function isIdOrNumberChar(c) { + return SC_ID_CLASS.indexOf(c) != -1 || // ID-char + (c >= "0" && c <= "9"); + } + function isWhitespace(c) { + return c === " " || c === "\r" || c === "\n" || c === "\t" || c === "\f"; + }; + function isWhitespaceOrEOF(c) { + return isWhitespace(c) || c === SC_EOF_OBJECT; + }; + + function readString() { + res = ""; + while (true) { + var c = port.readChar(); + switch (c) { + case '"': + return new sc_Token(11/*STRING*/, res); + case "\\": + var tmp = port.readChar(); + switch (tmp) { + case '0': res += "\0"; break; + case 'a': res += "\a"; break; + case 'b': res += "\b"; break; + case 'f': res += "\f"; break; + case 'n': res += "\n"; break; + case 'r': res += "\r"; break; + case 't': res += "\t"; break; + case 'v': res += "\v"; break; + case '"': res += '"'; break; + case '\\': res += '\\'; break; + case 'x': + /* hexa-number */ + var nb = 0; + while (true) { + var hexC = port.peekChar(); + if (hexC >= '0' && hexC <= '9') { + port.readChar(); + nb = nb * 16 + hexC.charCodeAt(0) - '0'.charCodeAt(0); + } else if (hexC >= 'a' && hexC <= 'f') { + port.readChar(); + nb = nb * 16 + hexC.charCodeAt(0) - 'a'.charCodeAt(0); + } else if (hexC >= 'A' && hexC <= 'F') { + port.readChar(); + nb = nb * 16 + hexC.charCodeAt(0) - 'A'.charCodeAt(0); + } else { + // next char isn't part of hex. + res += String.fromCharCode(nb); + break; + } + } + break; + default: + if (tmp === SC_EOF_OBJECT) { + return new sc_Token(13/*ERROR*/, "unclosed string-literal" + res); + } + res += tmp; + } + break; + default: + if (c === SC_EOF_OBJECT) { + return new sc_Token(13/*ERROR*/, "unclosed string-literal" + res); + } + res += c; + } + } + }; + function readIdOrNumber(firstChar) { + var res = firstChar; + while (isIdOrNumberChar(port.peekChar())) + res += port.readChar(); + if (isNaN(res)) + return new sc_Token(9/*ID*/, res); + else + return new sc_Token(12/*NUMBER*/, res - 0); + }; + + function skipWhitespaceAndComments() { + var done = false; + while (!done) { + done = true; + while (isWhitespace(port.peekChar())) + port.readChar(); + if (port.peekChar() === ';') { + port.readChar(); + done = false; + while (true) { + curChar = port.readChar(); + if (curChar === SC_EOF_OBJECT || + curChar === '\n') + break; + } + } + } + }; + + function readDot() { + if (isWhitespace(port.peekChar())) + return new sc_Token(10/*DOT*/); + else + return readIdOrNumber("."); + }; + + function readSharp() { + var c = port.readChar(); + if (isWhitespace(c)) + return new sc_Token(13/*ERROR*/, "bad #-pattern0."); + + // reference + if (isNumberChar(c)) { + var nb = c - 0; + while (isNumberChar(port.peekChar())) + nb = nb*10 + (port.readChar() - 0); + switch (port.readChar()) { + case '#': + return new sc_Token(18/*REFERENCE*/, nb); + case '=': + return new sc_Token(19/*STORE*/, nb); + default: + return new sc_Token(13/*ERROR*/, "bad #-pattern1." + nb); + } + } + + if (c === "(") + return new sc_Token(14/*VECTOR_BEGIN*/); + + if (c === "\\") { // character + var tmp = "" + while (!isWhitespaceOrEOF(port.peekChar())) + tmp += port.readChar(); + switch (tmp.length) { + case 0: // it's escaping a whitespace char: + if (sc_isEOFObject(port.peekChar)) + return new sc_Token(13/*ERROR*/, "bad #-pattern2."); + else + return new sc_Token(20/*CHAR*/, port.readChar()); + case 1: + return new sc_Token(20/*CHAR*/, tmp); + default: + var entry = sc_Char.readable2char[tmp.toLowerCase()]; + if (entry) + return new sc_Token(20/*CHAR*/, entry); + else + return new sc_Token(13/*ERROR*/, "unknown character description: #\\" + tmp); + } + } + + // some constants (#t, #f, #unspecified) + var res; + var needing; + switch (c) { + case 't': res = new sc_Token(15/*TRUE*/, true); needing = ""; break; + case 'f': res = new sc_Token(16/*FALSE*/, false); needing = ""; break; + case 'u': res = new sc_Token(17/*UNSPECIFIED*/, undefined); needing = "nspecified"; break; + default: + return new sc_Token(13/*ERROR*/, "bad #-pattern3: " + c); + } + while(true) { + c = port.peekChar(); + if ((isWhitespaceOrEOF(c) || c === ')') && + needing == "") + return res; + else if (isWhitespace(c) || needing == "") + return new sc_Token(13/*ERROR*/, "bad #-pattern4 " + c + " " + needing); + else if (needing.charAt(0) == c) { + port.readChar(); // consume + needing = needing.slice(1); + } else + return new sc_Token(13/*ERROR*/, "bad #-pattern5"); + } + + }; + + skipWhitespaceAndComments(); + var curChar = port.readChar(); + if (curChar === SC_EOF_OBJECT) + return new sc_Token(0/*EOF*/, curChar); + switch (curChar) + { + case " ": + case "\n": + case "\t": + return readWhitespace(); + case "(": + return new sc_Token(1/*OPEN_PAR*/); + case ")": + return new sc_Token(2/*CLOSE_PAR*/); + case "{": + return new sc_Token(3/*OPEN_BRACE*/); + case "}": + return new sc_Token(4/*CLOSE_BRACE*/); + case "[": + return new sc_Token(5/*OPEN_BRACKET*/); + case "]": + return new sc_Token(6/*CLOSE_BRACKET*/); + case "'": + return new sc_Token(8/*QUOTE*/); + case "#": + return readSharp(); + case ".": + return readDot(); + case '"': + return readString(); + default: + if (isIdOrNumberChar(curChar)) + return readIdOrNumber(curChar); + throw "unexpected character: " + curChar; + } +}; + +function sc_Reader(tokenizer) { + this.tokenizer = tokenizer; + this.backref = new Array(); +} +sc_Reader.prototype.read = function() { + function readList(listBeginType) { + function matchesPeer(open, close) { + return open === 1/*OPEN_PAR*/ && close === 2/*CLOSE_PAR*/ + || open === 3/*OPEN_BRACE*/ && close === 4/*CLOSE_BRACE*/ + || open === 5/*OPEN_BRACKET*/ && close === 6/*CLOSE_BRACKET*/; + }; + var res = null; + + while (true) { + var token = tokenizer.peekToken(); + + switch (token.type) { + case 2/*CLOSE_PAR*/: + case 4/*CLOSE_BRACE*/: + case 6/*CLOSE_BRACKET*/: + if (matchesPeer(listBeginType, token.type)) { + tokenizer.readToken(); // consume token + return sc_reverseBang(res); + } else + throw "closing par doesn't match: " + listBeginType + + " " + listEndType; + + case 0/*EOF*/: + throw "unexpected end of file"; + + case 10/*DOT*/: + tokenizer.readToken(); // consume token + var cdr = this.read(); + var par = tokenizer.readToken(); + if (!matchesPeer(listBeginType, par.type)) + throw "closing par doesn't match: " + listBeginType + + " " + par.type; + else + return sc_reverseAppendBang(res, cdr); + + + default: + res = sc_cons(this.read(), res); + } + } + }; + function readQuote() { + return sc_cons("quote", sc_cons(this.read(), null)); + }; + function readVector() { + // opening-parenthesis is already consumed + var a = new Array(); + while (true) { + var token = tokenizer.peekToken(); + switch (token.type) { + case 2/*CLOSE_PAR*/: + tokenizer.readToken(); + return a; + + default: + a.push(this.read()); + } + } + }; + + function storeRefence(nb) { + var tmp = this.read(); + this.backref[nb] = tmp; + return tmp; + }; + + function readReference(nb) { + if (nb in this.backref) + return this.backref[nb]; + else + throw "bad reference: " + nb; + }; + + var tokenizer = this.tokenizer; + + var token = tokenizer.readToken(); + + // handle error + if (token.type === 13/*ERROR*/) + throw token.val; + + switch (token.type) { + case 1/*OPEN_PAR*/: + case 3/*OPEN_BRACE*/: + case 5/*OPEN_BRACKET*/: + return readList.call(this, token.type); + case 8/*QUOTE*/: + return readQuote.call(this); + case 11/*STRING*/: + return sc_jsstring2string(token.val); + case 20/*CHAR*/: + return new sc_Char(token.val); + case 14/*VECTOR_BEGIN*/: + return readVector.call(this); + case 18/*REFERENCE*/: + return readReference.call(this, token.val); + case 19/*STORE*/: + return storeRefence.call(this, token.val); + case 9/*ID*/: + return sc_jsstring2symbol(token.val); + case 0/*EOF*/: + case 12/*NUMBER*/: + case 15/*TRUE*/: + case 16/*FALSE*/: + case 17/*UNSPECIFIED*/: + return token.val; + default: + throw "unexpected token " + token.type + " " + token.val; + } +}; + +/*** META ((export #t)) */ +function sc_read(port) { + if (port === undefined) // we assume the port hasn't been given. + port = SC_DEFAULT_IN; // THREAD: shared var... + var reader = new sc_Reader(new sc_Tokenizer(port)); + return reader.read(); +} +/*** META ((export #t)) */ +function sc_readChar(port) { + if (port === undefined) // we assume the port hasn't been given. + port = SC_DEFAULT_IN; // THREAD: shared var... + var t = port.readChar(); + return t === SC_EOF_OBJECT? t: new sc_Char(t); +} +/*** META ((export #t)) */ +function sc_peekChar(port) { + if (port === undefined) // we assume the port hasn't been given. + port = SC_DEFAULT_IN; // THREAD: shared var... + var t = port.peekChar(); + return t === SC_EOF_OBJECT? t: new sc_Char(t); +} +/*** META ((export #t) + (type bool)) +*/ +function sc_isCharReady(port) { + if (port === undefined) // we assume the port hasn't been given. + port = SC_DEFAULT_IN; // THREAD: shared var... + return port.isCharReady(); +} +/*** META ((export #t) + (peephole (postfix ".close()"))) +*/ +function sc_closeInputPort(p) { + return p.close(); +} + +/*** META ((export #t) + (type bool) + (peephole (postfix " instanceof sc_InputPort"))) +*/ +function sc_isInputPort(o) { + return (o instanceof sc_InputPort); +} + +/*** META ((export eof-object?) + (type bool) + (peephole (postfix " === SC_EOF_OBJECT"))) +*/ +function sc_isEOFObject(o) { + return o === SC_EOF_OBJECT; +} + +/*** META ((export #t) + (peephole (hole 0 "SC_DEFAULT_IN"))) +*/ +function sc_currentInputPort() { + return SC_DEFAULT_IN; +} + +/* ------------ file operations are not supported -----------*/ +/*** META ((export #t)) */ +function sc_callWithInputFile(s, proc) { + throw "can't open " + s; +} + +/*** META ((export #t)) */ +function sc_callWithOutputFile(s, proc) { + throw "can't open " + s; +} + +/*** META ((export #t)) */ +function sc_withInputFromFile(s, thunk) { + throw "can't open " + s; +} + +/*** META ((export #t)) */ +function sc_withOutputToFile(s, thunk) { + throw "can't open " + s; +} + +/*** META ((export #t)) */ +function sc_openInputFile(s) { + throw "can't open " + s; +} + +/*** META ((export #t)) */ +function sc_openOutputFile(s) { + throw "can't open " + s; +} + +/* ----------------------------------------------------------------------------*/ +/*** META ((export #t)) */ +function sc_basename(p) { + var i = p.lastIndexOf('/'); + + if(i >= 0) + return p.substring(i + 1, p.length); + else + return ''; +} + +/*** META ((export #t)) */ +function sc_dirname(p) { + var i = p.lastIndexOf('/'); + + if(i >= 0) + return p.substring(0, i); + else + return ''; +} + +/* ----------------------------------------------------------------------------*/ + +/*** META ((export #t)) */ +function sc_withInputFromPort(p, thunk) { + try { + var tmp = SC_DEFAULT_IN; // THREAD: shared var. + SC_DEFAULT_IN = p; + return thunk(); + } finally { + SC_DEFAULT_IN = tmp; + } +} + +/*** META ((export #t)) */ +function sc_withInputFromString(s, thunk) { + return sc_withInputFromPort(new sc_StringInputPort(sc_string2jsstring(s)), thunk); +} + +/*** META ((export #t)) */ +function sc_withOutputToPort(p, thunk) { + try { + var tmp = SC_DEFAULT_OUT; // THREAD: shared var. + SC_DEFAULT_OUT = p; + return thunk(); + } finally { + SC_DEFAULT_OUT = tmp; + } +} + +/*** META ((export #t)) */ +function sc_withOutputToString(thunk) { + var p = new sc_StringOutputPort(); + sc_withOutputToPort(p, thunk); + return p.close(); +} + +/*** META ((export #t)) */ +function sc_withOutputToProcedure(proc, thunk) { + var t = function(s) { proc(sc_jsstring2string(s)); }; + return sc_withOutputToPort(new sc_GenericOutputPort(t), thunk); +} + +/*** META ((export #t) + (peephole (hole 0 "new sc_StringOutputPort()"))) +*/ +function sc_openOutputString() { + return new sc_StringOutputPort(); +} + +/*** META ((export #t)) */ +function sc_openInputString(str) { + return new sc_StringInputPort(sc_string2jsstring(str)); +} + +/* ----------------------------------------------------------------------------*/ + +function sc_OutputPort() { +} +sc_OutputPort.prototype = new sc_Port(); +sc_OutputPort.prototype.appendJSString = function(obj) { + /* do nothing */ +} +sc_OutputPort.prototype.close = function() { + /* do nothing */ +} + +function sc_StringOutputPort() { + this.res = ""; +} +sc_StringOutputPort.prototype = new sc_OutputPort(); +sc_StringOutputPort.prototype.appendJSString = function(s) { + this.res += s; +} +sc_StringOutputPort.prototype.close = function() { + return sc_jsstring2string(this.res); +} + +/*** META ((export #t)) */ +function sc_getOutputString(sp) { + return sc_jsstring2string(sp.res); +} + + +function sc_ErrorOutputPort() { +} +sc_ErrorOutputPort.prototype = new sc_OutputPort(); +sc_ErrorOutputPort.prototype.appendJSString = function(s) { + throw "don't write on ErrorPort!"; +} +sc_ErrorOutputPort.prototype.close = function() { + /* do nothing */ +} + +function sc_GenericOutputPort(appendJSString, close) { + this.appendJSString = appendJSString; + if (close) + this.close = close; +} +sc_GenericOutputPort.prototype = new sc_OutputPort(); + +/*** META ((export #t) + (type bool) + (peephole (postfix " instanceof sc_OutputPort"))) +*/ +function sc_isOutputPort(o) { + return (o instanceof sc_OutputPort); +} + +/*** META ((export #t) + (peephole (postfix ".close()"))) +*/ +function sc_closeOutputPort(p) { + return p.close(); +} + +/* ------------------ write ---------------------------------------------------*/ + +/*** META ((export #t)) */ +function sc_write(o, p) { + if (p === undefined) // we assume not given + p = SC_DEFAULT_OUT; + p.appendJSString(sc_toWriteString(o)); +} + +function sc_toWriteString(o) { + if (o === null) + return "()"; + else if (o === true) + return "#t"; + else if (o === false) + return "#f"; + else if (o === undefined) + return "#unspecified"; + else if (typeof o === 'function') + return "#"; + else if (o.sc_toWriteString) + return o.sc_toWriteString(); + else + return o.toString(); +} + +function sc_escapeWriteString(s) { + var res = ""; + var j = 0; + for (i = 0; i < s.length; i++) { + switch (s.charAt(i)) { + case "\0": res += s.substring(j, i) + "\\0"; j = i + 1; break; + case "\b": res += s.substring(j, i) + "\\b"; j = i + 1; break; + case "\f": res += s.substring(j, i) + "\\f"; j = i + 1; break; + case "\n": res += s.substring(j, i) + "\\n"; j = i + 1; break; + case "\r": res += s.substring(j, i) + "\\r"; j = i + 1; break; + case "\t": res += s.substring(j, i) + "\\t"; j = i + 1; break; + case "\v": res += s.substring(j, i) + "\\v"; j = i + 1; break; + case '"': res += s.substring(j, i) + '\\"'; j = i + 1; break; + case "\\": res += s.substring(j, i) + "\\\\"; j = i + 1; break; + default: + var c = s.charAt(i); + if ("\a" !== "a" && c == "\a") { + res += s.substring(j, i) + "\\a"; j = i + 1; continue; + } + if ("\v" !== "v" && c == "\v") { + res += s.substring(j, i) + "\\v"; j = i + 1; continue; + } + //if (s.charAt(i) < ' ' || s.charCodeAt(i) > 127) { + // CARE: Manuel is this OK with HOP? + if (s.charAt(i) < ' ') { + /* non printable character and special chars */ + res += s.substring(j, i) + "\\x" + s.charCodeAt(i).toString(16); + j = i + 1; + } + // else just let i increase... + } + } + res += s.substring(j, i); + return res; +} + +/* ------------------ display ---------------------------------------------------*/ + +/*** META ((export #t)) */ +function sc_display(o, p) { + if (p === undefined) // we assume not given + p = SC_DEFAULT_OUT; + p.appendJSString(sc_toDisplayString(o)); +} + +function sc_toDisplayString(o) { + if (o === null) + return "()"; + else if (o === true) + return "#t"; + else if (o === false) + return "#f"; + else if (o === undefined) + return "#unspecified"; + else if (typeof o === 'function') + return "#"; + else if (o.sc_toDisplayString) + return o.sc_toDisplayString(); + else + return o.toString(); +} + +/* ------------------ newline ---------------------------------------------------*/ + +/*** META ((export #t)) */ +function sc_newline(p) { + if (p === undefined) // we assume not given + p = SC_DEFAULT_OUT; + p.appendJSString("\n"); +} + +/* ------------------ write-char ---------------------------------------------------*/ + +/*** META ((export #t)) */ +function sc_writeChar(c, p) { + if (p === undefined) // we assume not given + p = SC_DEFAULT_OUT; + p.appendJSString(c.val); +} + +/* ------------------ write-circle ---------------------------------------------------*/ + +/*** META ((export #t)) */ +function sc_writeCircle(o, p) { + if (p === undefined) // we assume not given + p = SC_DEFAULT_OUT; + p.appendJSString(sc_toWriteCircleString(o)); +} + +function sc_toWriteCircleString(o) { + var symb = sc_gensym("writeCircle"); + var nbPointer = new Object(); + nbPointer.nb = 0; + sc_prepWriteCircle(o, symb, nbPointer); + return sc_genToWriteCircleString(o, symb); +} + +function sc_prepWriteCircle(o, symb, nbPointer) { + // TODO sc_Struct + if (o instanceof sc_Pair || + o instanceof sc_Vector) { + if (o[symb] !== undefined) { + // not the first visit. + o[symb]++; + // unless there is already a number, assign one. + if (!o[symb + "nb"]) o[symb + "nb"] = nbPointer.nb++; + return; + } + o[symb] = 0; + if (o instanceof sc_Pair) { + sc_prepWriteCircle(o.car, symb, nbPointer); + sc_prepWriteCircle(o.cdr, symb, nbPointer); + } else { + for (var i = 0; i < o.length; i++) + sc_prepWriteCircle(o[i], symb, nbPointer); + } + } +} + +function sc_genToWriteCircleString(o, symb) { + if (!(o instanceof sc_Pair || + o instanceof sc_Vector)) + return sc_toWriteString(o); + return o.sc_toWriteCircleString(symb); +} +sc_Pair.prototype.sc_toWriteCircleString = function(symb, inList) { + if (this[symb + "use"]) { // use-flag is set. Just use it. + var nb = this[symb + "nb"]; + if (this[symb]-- === 0) { // if we are the last use. remove all fields. + delete this[symb]; + delete this[symb + "nb"]; + delete this[symb + "use"]; + } + if (inList) + return '. #' + nb + '#'; + else + return '#' + nb + '#'; + } + if (this[symb]-- === 0) { // if we are the last use. remove all fields. + delete this[symb]; + delete this[symb + "nb"]; + delete this[symb + "use"]; + } + + var res = ""; + + if (this[symb] !== undefined) { // implies > 0 + this[symb + "use"] = true; + if (inList) + res += '. #' + this[symb + "nb"] + '='; + else + res += '#' + this[symb + "nb"] + '='; + inList = false; + } + + if (!inList) + res += "("; + + // print car + res += sc_genToWriteCircleString(this.car, symb); + + if (sc_isPair(this.cdr)) { + res += " " + this.cdr.sc_toWriteCircleString(symb, true); + } else if (this.cdr !== null) { + res += " . " + sc_genToWriteCircleString(this.cdr, symb); + } + if (!inList) + res += ")"; + return res; +}; +sc_Vector.prototype.sc_toWriteCircleString = function(symb) { + if (this[symb + "use"]) { // use-flag is set. Just use it. + var nb = this[symb + "nb"]; + if (this[symb]-- === 0) { // if we are the last use. remove all fields. + delete this[symb]; + delete this[symb + "nb"]; + delete this[symb + "use"]; + } + return '#' + nb + '#'; + } + if (this[symb]-- === 0) { // if we are the last use. remove all fields. + delete this[symb]; + delete this[symb + "nb"]; + delete this[symb + "use"]; + } + + var res = ""; + if (this[symb] !== undefined) { // implies > 0 + this[symb + "use"] = true; + res += '#' + this[symb + "nb"] + '='; + } + res += "#("; + for (var i = 0; i < this.length; i++) { + res += sc_genToWriteCircleString(this[i], symb); + if (i < this.length - 1) res += " "; + } + res += ")"; + return res; +}; + + +/* ------------------ print ---------------------------------------------------*/ + +/*** META ((export #t)) */ +function sc_print(s) { + if (arguments.length === 1) { + sc_display(s); + sc_newline(); + } + else { + for (var i = 0; i < arguments.length; i++) + sc_display(arguments[i]); + sc_newline(); + } +} + +/* ------------------ format ---------------------------------------------------*/ +/*** META ((export #t)) */ +function sc_format(s, args) { + var len = s.length; + var p = new sc_StringOutputPort(); + var i = 0, j = 1; + + while( i < len ) { + var i2 = s.indexOf("~", i); + + if (i2 == -1) { + p.appendJSString( s.substring( i, len ) ); + return p.close(); + } else { + if (i2 > i) { + if (i2 == (len - 1)) { + p.appendJSString(s.substring(i, len)); + return p.close(); + } else { + p.appendJSString(s.substring(i, i2)); + i = i2; + } + } + + switch(s.charCodeAt(i2 + 1)) { + case 65: + case 97: + // a + sc_display(arguments[j], p); + i += 2; j++; + break; + + case 83: + case 115: + // s + sc_write(arguments[j], p); + i += 2; j++; + break; + + case 86: + case 118: + // v + sc_display(arguments[j], p); + p.appendJSString("\n"); + i += 2; j++; + break; + + case 67: + case 99: + // c + p.appendJSString(String.fromCharCode(arguments[j])); + i += 2; j++; + break; + + case 88: + case 120: + // x + p.appendJSString(arguments[j].toString(6)); + i += 2; j++; + break; + + case 79: + case 111: + // o + p.appendJSString(arguments[j].toString(8)); + i += 2; j++; + break; + + case 66: + case 98: + // b + p.appendJSString(arguments[j].toString(2)); + i += 2; j++; + break; + + case 37: + case 110: + // %, n + p.appendJSString("\n"); + i += 2; break; + + case 114: + // r + p.appendJSString("\r"); + i += 2; break; + + case 126: + // ~ + p.appendJSString("~"); + i += 2; break; + + default: + sc_error( "format: illegal ~" + + String.fromCharCode(s.charCodeAt(i2 + 1)) + + " sequence" ); + return ""; + } + } + } + + return p.close(); +} + +/* ------------------ global ports ---------------------------------------------------*/ + +var SC_DEFAULT_IN = new sc_ErrorInputPort(); +var SC_DEFAULT_OUT = new sc_ErrorOutputPort(); +var SC_ERROR_OUT = new sc_ErrorOutputPort(); + +var sc_SYMBOL_PREFIX = "\u1E9C"; +var sc_KEYWORD_PREFIX = "\u1E9D"; + +/*** META ((export #t) + (peephole (id))) */ +function sc_jsstring2string(s) { + return s; +} + +/*** META ((export #t) + (peephole (prefix "'\\u1E9C' +"))) +*/ +function sc_jsstring2symbol(s) { + return sc_SYMBOL_PREFIX + s; +} + +/*** META ((export #t) + (peephole (id))) +*/ +function sc_string2jsstring(s) { + return s; +} + +/*** META ((export #t) + (peephole (symbol2jsstring_immutable))) +*/ +function sc_symbol2jsstring(s) { + return s.slice(1); +} + +/*** META ((export #t) + (peephole (postfix ".slice(1)"))) +*/ +function sc_keyword2jsstring(k) { + return k.slice(1); +} + +/*** META ((export #t) + (peephole (prefix "'\\u1E9D' +"))) +*/ +function sc_jsstring2keyword(s) { + return sc_KEYWORD_PREFIX + s; +} + +/*** META ((export #t) + (type bool)) +*/ +function sc_isKeyword(s) { + return (typeof s === "string") && + (s.charAt(0) === sc_KEYWORD_PREFIX); +} + + +/*** META ((export #t)) */ +var sc_gensym = function() { + var counter = 1000; + return function(sym) { + counter++; + if (!sym) sym = sc_SYMBOL_PREFIX; + return sym + "s" + counter + "~" + "^sC-GeNsYm "; + }; +}(); + + +/*** META ((export #t) + (type bool)) +*/ +function sc_isEqual(o1, o2) { + return ((o1 === o2) || + (sc_isPair(o1) && sc_isPair(o2) + && sc_isPairEqual(o1, o2, sc_isEqual)) || + (sc_isVector(o1) && sc_isVector(o2) + && sc_isVectorEqual(o1, o2, sc_isEqual))); +} + +/*** META ((export number->symbol integer->symbol)) */ +function sc_number2symbol(x, radix) { + return sc_SYMBOL_PREFIX + sc_number2jsstring(x, radix); +} + +/*** META ((export number->string integer->string)) */ +var sc_number2string = sc_number2jsstring; + +/*** META ((export #t)) */ +function sc_symbol2number(s, radix) { + return sc_jsstring2number(s.slice(1), radix); +} + +/*** META ((export #t)) */ +var sc_string2number = sc_jsstring2number; + +/*** META ((export #t) + (peephole (prefix "+" s))) + ;; peephole will only apply if no radix is given. +*/ +function sc_string2integer(s, radix) { + if (!radix) return +s; + return parseInt(s, radix); +} + +/*** META ((export #t) + (peephole (prefix "+"))) +*/ +function sc_string2real(s) { + return +s; +} + + +/*** META ((export #t) + (type bool)) +*/ +function sc_isSymbol(s) { + return (typeof s === "string") && + (s.charAt(0) === sc_SYMBOL_PREFIX); +} + +/*** META ((export #t) + (peephole (symbol2string_immutable))) +*/ +function sc_symbol2string(s) { + return s.slice(1); +} + +/*** META ((export #t) + (peephole (prefix "'\\u1E9C' +"))) +*/ +function sc_string2symbol(s) { + return sc_SYMBOL_PREFIX + s; +} + +/*** META ((export symbol-append) + (peephole (symbolAppend_immutable))) +*/ +function sc_symbolAppend() { + var res = sc_SYMBOL_PREFIX; + for (var i = 0; i < arguments.length; i++) + res += arguments[i].slice(1); + return res; +} + +/*** META ((export #t) + (peephole (postfix ".val"))) +*/ +function sc_char2string(c) { return c.val; } + +/*** META ((export #t) + (peephole (hole 1 "'\\u1E9C' + " c ".val"))) +*/ +function sc_char2symbol(c) { return sc_SYMBOL_PREFIX + c.val; } + +/*** META ((export #t) + (type bool)) +*/ +function sc_isString(s) { + return (typeof s === "string") && + (s.charAt(0) !== sc_SYMBOL_PREFIX); +} + +/*** META ((export #t)) */ +var sc_makeString = sc_makejsString; + + +/*** META ((export #t)) */ +function sc_string() { + for (var i = 0; i < arguments.length; i++) + arguments[i] = arguments[i].val; + return "".concat.apply("", arguments); +} + +/*** META ((export #t) + (peephole (postfix ".length"))) +*/ +function sc_stringLength(s) { return s.length; } + +/*** META ((export #t)) */ +function sc_stringRef(s, k) { + return new sc_Char(s.charAt(k)); +} + +/* there's no stringSet in the immutable version +function sc_stringSet(s, k, c) +*/ + + +/*** META ((export string=?) + (type bool) + (peephole (hole 2 str1 " === " str2))) +*/ +function sc_isStringEqual(s1, s2) { + return s1 === s2; +} +/*** META ((export string?) + (type bool) + (peephole (hole 2 str1 " > " str2))) +*/ +function sc_isStringGreater(s1, s2) { + return s1 > s2; +} +/*** META ((export string<=?) + (type bool) + (peephole (hole 2 str1 " <= " str2))) +*/ +function sc_isStringLessEqual(s1, s2) { + return s1 <= s2; +} +/*** META ((export string>=?) + (type bool) + (peephole (hole 2 str1 " >= " str2))) +*/ +function sc_isStringGreaterEqual(s1, s2) { + return s1 >= s2; +} +/*** META ((export string-ci=?) + (type bool) + (peephole (hole 2 str1 ".toLowerCase() === " str2 ".toLowerCase()"))) +*/ +function sc_isStringCIEqual(s1, s2) { + return s1.toLowerCase() === s2.toLowerCase(); +} +/*** META ((export string-ci?) + (type bool) + (peephole (hole 2 str1 ".toLowerCase() > " str2 ".toLowerCase()"))) +*/ +function sc_isStringCIGreater(s1, s2) { + return s1.toLowerCase() > s2.toLowerCase(); +} +/*** META ((export string-ci<=?) + (type bool) + (peephole (hole 2 str1 ".toLowerCase() <= " str2 ".toLowerCase()"))) +*/ +function sc_isStringCILessEqual(s1, s2) { + return s1.toLowerCase() <= s2.toLowerCase(); +} +/*** META ((export string-ci>=?) + (type bool) + (peephole (hole 2 str1 ".toLowerCase() >= " str2 ".toLowerCase()"))) +*/ +function sc_isStringCIGreaterEqual(s1, s2) { + return s1.toLowerCase() >= s2.toLowerCase(); +} + +/*** META ((export #t) + (peephole (hole 3 s ".substring(" start ", " end ")"))) +*/ +function sc_substring(s, start, end) { + return s.substring(start, end); +} + +/*** META ((export #t)) +*/ +function sc_isSubstring_at(s1, s2, i) { + return s2 == s1.substring(i, i+ s2.length); +} + +/*** META ((export #t) + (peephole (infix 0 #f "+" "''"))) +*/ +function sc_stringAppend() { + return "".concat.apply("", arguments); +} + +/*** META ((export #t)) */ +var sc_string2list = sc_jsstring2list; + +/*** META ((export #t)) */ +var sc_list2string = sc_list2jsstring; + +/*** META ((export #t) + (peephole (id))) +*/ +function sc_stringCopy(s) { + return s; +} + +/* there's no string-fill in the immutable version +function sc_stringFill(s, c) +*/ + +/*** META ((export #t) + (peephole (postfix ".slice(1)"))) +*/ +function sc_keyword2string(o) { + return o.slice(1); +} + +/*** META ((export #t) + (peephole (prefix "'\\u1E9D' +"))) +*/ +function sc_string2keyword(o) { + return sc_KEYWORD_PREFIX + o; +} + +String.prototype.sc_toDisplayString = function() { + if (this.charAt(0) === sc_SYMBOL_PREFIX) + // TODO: care for symbols with spaces (escape-chars symbols). + return this.slice(1); + else if (this.charAt(0) === sc_KEYWORD_PREFIX) + return ":" + this.slice(1); + else + return this.toString(); +}; + +String.prototype.sc_toWriteString = function() { + if (this.charAt(0) === sc_SYMBOL_PREFIX) + // TODO: care for symbols with spaces (escape-chars symbols). + return this.slice(1); + else if (this.charAt(0) === sc_KEYWORD_PREFIX) + return ":" + this.slice(1); + else + return '"' + sc_escapeWriteString(this) + '"'; +}; +/* Exported Variables */ +var BgL_testzd2boyerzd2; +var BgL_nboyerzd2benchmarkzd2; +var BgL_setupzd2boyerzd2; +/* End Exports */ + +var translate_term_nboyer; +var translate_args_nboyer; +var untranslate_term_nboyer; +var BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer; +var BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer; +var translate_alist_nboyer; +var apply_subst_nboyer; +var apply_subst_lst_nboyer; +var tautologyp_nboyer; +var if_constructor_nboyer; +var rewrite_count_nboyer; +var rewrite_nboyer; +var rewrite_args_nboyer; +var unify_subst_nboyer; +var one_way_unify1_nboyer; +var false_term_nboyer; +var true_term_nboyer; +var trans_of_implies1_nboyer; +var is_term_equal_nboyer; +var is_term_member_nboyer; +var const_nboyer; +var sc_const_3_nboyer; +var sc_const_4_nboyer; +{ + (sc_const_4_nboyer = (new sc_Pair("\u1E9Cimplies",(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cu",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cu",(new sc_Pair("\u1E9Cw",null)))))),null)))))),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cw",null)))))),null))))))); + (sc_const_3_nboyer = sc_list((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ccompile",(new sc_Pair("\u1E9Cform",null)))),(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair((new sc_Pair("\u1E9Ccodegen",(new sc_Pair((new sc_Pair("\u1E9Coptimize",(new sc_Pair("\u1E9Cform",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ceqp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreaterp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clesseqp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreatereqp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cboolean",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ciff",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ceven1",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Codd",(new sc_Pair((new sc_Pair("\u1E9Csub1",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ccountps-",(new sc_Pair("\u1E9Cl",(new sc_Pair("\u1E9Cpred",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ccountps-loop",(new sc_Pair("\u1E9Cl",(new sc_Pair("\u1E9Cpred",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfact-",(new sc_Pair("\u1E9Ci",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfact-loop",(new sc_Pair("\u1E9Ci",(new sc_Pair((1),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Creverse-",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Creverse-loop",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdivides",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cassume-true",(new sc_Pair("\u1E9Cvar",(new sc_Pair("\u1E9Calist",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cvar",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),null)))))),(new sc_Pair("\u1E9Calist",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cassume-false",(new sc_Pair("\u1E9Cvar",(new sc_Pair("\u1E9Calist",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cvar",(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))),(new sc_Pair("\u1E9Calist",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctautology-checker",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ctautologyp",(new sc_Pair((new sc_Pair("\u1E9Cnormalize",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfalsify",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfalsify1",(new sc_Pair((new sc_Pair("\u1E9Cnormalize",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cprime",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))),null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cprime1",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Csub1",(new sc_Pair("\u1E9Cx",null)))),null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair("\u1E9Cp",(new sc_Pair("\u1E9Cq",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cp",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cq",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair("\u1E9Cp",(new sc_Pair("\u1E9Cq",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cp",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cq",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair("\u1E9Cp",null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cp",(new sc_Pair((new sc_Pair("\u1E9Cf",null)),(new sc_Pair((new sc_Pair("\u1E9Ct",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cimplies",(new sc_Pair("\u1E9Cp",(new sc_Pair("\u1E9Cq",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cp",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cq",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair((new sc_Pair("\u1E9Cf",null)),null)))))))),(new sc_Pair((new sc_Pair("\u1E9Ct",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cc",null)))))))),(new sc_Pair("\u1E9Cd",(new sc_Pair("\u1E9Ce",null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Ca",(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cd",(new sc_Pair("\u1E9Ce",null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair("\u1E9Cc",(new sc_Pair("\u1E9Cd",(new sc_Pair("\u1E9Ce",null)))))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Ca",null)))),(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cb",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cc",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cc",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair("\u1E9Ca",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair((new sc_Pair("\u1E9Cplus-fringe",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Ca",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cexec",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cpds",(new sc_Pair("\u1E9Cenvrn",null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cexec",(new sc_Pair("\u1E9Cy",(new sc_Pair((new sc_Pair("\u1E9Cexec",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cpds",(new sc_Pair("\u1E9Cenvrn",null)))))))),(new sc_Pair("\u1E9Cenvrn",null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmc-flatten",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Cy",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cb",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cy",null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Ca",(new sc_Pair((new sc_Pair("\u1E9Cintersect",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cc",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cc",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Ck",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cj",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Ck",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Ck",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair((new sc_Pair("\u1E9Cexp",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cj",null)))))),(new sc_Pair("\u1E9Ck",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Creverse-loop",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Cy",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Creverse-loop",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ccount-list",(new sc_Pair("\u1E9Cz",(new sc_Pair((new sc_Pair("\u1E9Csort-lp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Ccount-list",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ccount-list",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cc",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cc",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair((new sc_Pair("\u1E9Cbig-plus1",(new sc_Pair("\u1E9Cl",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cbase",null)))))))),(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair("\u1E9Cl",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair("\u1E9Ci",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair((new sc_Pair("\u1E9Cbig-plus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cbase",null)))))))))),(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cbase",null)))))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cy",(new sc_Pair((1),null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cj",null)))))),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Ci",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cj",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cj",(new sc_Pair((1),null)))))),null)))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair((new sc_Pair("\u1E9Cpower-rep",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Ci",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cpower-eval",(new sc_Pair((new sc_Pair("\u1E9Cbig-plus",(new sc_Pair((new sc_Pair("\u1E9Cpower-rep",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cpower-rep",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair("\u1E9Cbase",null)))))))))),(new sc_Pair("\u1E9Cbase",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cj",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgcd",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cgcd",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair("\u1E9Cb",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Ca",null)))),null)))))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cy",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cy",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cc",(new sc_Pair("\u1E9Cw",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cc",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cw",(new sc_Pair("\u1E9Cx",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cb",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cc",null)))))),null)))))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cb",(new sc_Pair("\u1E9Cc",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cy",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cz",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgcd",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cz",(new sc_Pair((new sc_Pair("\u1E9Cgcd",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cvalue",(new sc_Pair((new sc_Pair("\u1E9Cnormalize",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cvalue",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cy",(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnlistp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair((new sc_Pair("\u1E9Cgopher",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csamefringe",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreatest-factor",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cy",(new sc_Pair((1),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreatest-factor",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((1),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((1),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair((new sc_Pair("\u1E9Cgreatest-factor",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cy",(new sc_Pair((1),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes-list",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair((new sc_Pair("\u1E9Ctimes-list",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ctimes-list",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cprime-list",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cprime-list",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cprime-list",(new sc_Pair("\u1E9Cy",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cz",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cw",(new sc_Pair("\u1E9Cz",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cz",null)))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cz",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cw",(new sc_Pair((1),null)))))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cgreatereqp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cor",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cand",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cy",(new sc_Pair((1),null)))))),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((1),null)))))),(new sc_Pair(sc_list("\u1E9Cand", (new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Ca",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),null)))), (new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair("\u1E9Cb",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),null)))), (new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Ca",null)))), (new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cb",null)))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csub1",(new sc_Pair("\u1E9Ca",null)))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csub1",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair((new sc_Pair("\u1E9Cdelete",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cl",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Cl",null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cl",null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csort2",(new sc_Pair((new sc_Pair("\u1E9Cdelete",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cl",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cdelete",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Csort2",(new sc_Pair("\u1E9Cl",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdsort",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Csort2",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx1",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx2",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx3",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx4",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx5",(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair("\u1E9Cx6",(new sc_Pair("\u1E9Cx7",null)))))),null)))))),null)))))),null)))))),null)))))),null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((6),(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Cx7",null)))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((2),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((2),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair("\u1E9Cy",(new sc_Pair((2),null)))))),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Csigma",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Ci",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Ci",null)))),null)))))),(new sc_Pair((2),null)))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cy",null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cx",null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cz",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnot",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cz",null)))),null)))))),null)))))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair((new sc_Pair("\u1E9Cdelete",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmeaning",(new sc_Pair((new sc_Pair("\u1E9Cplus-tree",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair("\u1E9Ca",null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cadd1",(new sc_Pair("\u1E9Cy",null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cnumberp",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cnth",(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Ci",null)))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clast",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Clast",(new sc_Pair("\u1E9Cb",null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Ca",null)))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair((new sc_Pair("\u1E9Ccar",(new sc_Pair((new sc_Pair("\u1E9Clast",(new sc_Pair("\u1E9Ca",null)))),null)))),(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair("\u1E9Cb",null)))))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clessp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ct",null)),(new sc_Pair("\u1E9Cz",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cf",null)),(new sc_Pair("\u1E9Cz",null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cassignment",(new sc_Pair("\u1E9Cx",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Cassignedp",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cassignment",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Ca",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cassignment",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cb",null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Ccar",(new sc_Pair((new sc_Pair("\u1E9Cgopher",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ccar",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair((new sc_Pair("\u1E9Ccdr",(new sc_Pair((new sc_Pair("\u1E9Cgopher",(new sc_Pair("\u1E9Cx",null)))),null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Clistp",(new sc_Pair("\u1E9Cx",null)))),(new sc_Pair((new sc_Pair("\u1E9Ccdr",(new sc_Pair((new sc_Pair("\u1E9Cflatten",(new sc_Pair("\u1E9Cx",null)))),null)))),(new sc_Pair((new sc_Pair("\u1E9Ccons",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cquotient",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cx",null)))))),(new sc_Pair("\u1E9Cy",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Czerop",(new sc_Pair("\u1E9Cy",null)))),(new sc_Pair((new sc_Pair("\u1E9Czero",null)),(new sc_Pair((new sc_Pair("\u1E9Cfix",(new sc_Pair("\u1E9Cx",null)))),null)))))))),null)))))), (new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cget",(new sc_Pair("\u1E9Cj",(new sc_Pair((new sc_Pair("\u1E9Cset",(new sc_Pair("\u1E9Ci",(new sc_Pair("\u1E9Cval",(new sc_Pair("\u1E9Cmem",null)))))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cif",(new sc_Pair((new sc_Pair("\u1E9Ceqp",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Ci",null)))))),(new sc_Pair("\u1E9Cval",(new sc_Pair((new sc_Pair("\u1E9Cget",(new sc_Pair("\u1E9Cj",(new sc_Pair("\u1E9Cmem",null)))))),null)))))))),null)))))))); + (const_nboyer = (new sc_Pair((new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cf",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cc",(new sc_Pair((new sc_Pair("\u1E9Czero",null)),null)))))),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cy",(new sc_Pair("\u1E9Cf",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair((new sc_Pair("\u1E9Ctimes",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Cc",(new sc_Pair("\u1E9Cd",null)))))),null)))))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cz",(new sc_Pair("\u1E9Cf",(new sc_Pair((new sc_Pair("\u1E9Creverse",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair((new sc_Pair("\u1E9Cappend",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cnil",null)),null)))))),null)))),null)))))),(new sc_Pair((new sc_Pair("\u1E9Cu",(new sc_Pair("\u1E9Cequal",(new sc_Pair((new sc_Pair("\u1E9Cplus",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cdifference",(new sc_Pair("\u1E9Cx",(new sc_Pair("\u1E9Cy",null)))))),null)))))))),(new sc_Pair((new sc_Pair("\u1E9Cw",(new sc_Pair("\u1E9Clessp",(new sc_Pair((new sc_Pair("\u1E9Cremainder",(new sc_Pair("\u1E9Ca",(new sc_Pair("\u1E9Cb",null)))))),(new sc_Pair((new sc_Pair("\u1E9Cmember",(new sc_Pair("\u1E9Ca",(new sc_Pair((new sc_Pair("\u1E9Clength",(new sc_Pair("\u1E9Cb",null)))),null)))))),null)))))))),null))))))))))); + BgL_nboyerzd2benchmarkzd2 = function() { + var args = null; + for (var sc_tmp = arguments.length - 1; sc_tmp >= 0; sc_tmp--) { + args = sc_cons(arguments[sc_tmp], args); + } + var n; + return ((n = ((args === null)?(0):(args.car))), (BgL_setupzd2boyerzd2()), (BgL_runzd2benchmarkzd2(("nboyer"+(sc_number2string(n))), (1), function() { + return (BgL_testzd2boyerzd2(n)); + }, function(rewrites) { + if ((sc_isNumber(rewrites))) + switch (n) { + case (0): + return (rewrites===(95024)); + break; + case (1): + return (rewrites===(591777)); + break; + case (2): + return (rewrites===(1813975)); + break; + case (3): + return (rewrites===(5375678)); + break; + case (4): + return (rewrites===(16445406)); + break; + case (5): + return (rewrites===(51507739)); + break; + default: + return true; + break; + } + else + return false; + }))); + }; + BgL_setupzd2boyerzd2 = function() { + return true; + }; + BgL_testzd2boyerzd2 = function() { + return true; + }; + translate_term_nboyer = function(term) { + var lst; + return (!(term instanceof sc_Pair)?term:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((term.car))), ((lst = (term.cdr)), ((lst === null)?null:(new sc_Pair((translate_term_nboyer((lst.car))), (translate_args_nboyer((lst.cdr)))))))))); + }; + translate_args_nboyer = function(lst) { + var sc_lst_5; + var term; + return ((lst === null)?null:(new sc_Pair(((term = (lst.car)), (!(term instanceof sc_Pair)?term:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((term.car))), (translate_args_nboyer((term.cdr))))))), ((sc_lst_5 = (lst.cdr)), ((sc_lst_5 === null)?null:(new sc_Pair((translate_term_nboyer((sc_lst_5.car))), (translate_args_nboyer((sc_lst_5.cdr)))))))))); + }; + untranslate_term_nboyer = function(term) { + var optrOpnd; + var tail1131; + var L1127; + var falseHead1130; + var symbol_record; + if (!(term instanceof sc_Pair)) + return term; + else + { + (falseHead1130 = (new sc_Pair(null, null))); + (L1127 = (term.cdr)); + (tail1131 = falseHead1130); + while (!(L1127 === null)) { + { + (tail1131.cdr = (new sc_Pair((untranslate_term_nboyer((L1127.car))), null))); + (tail1131 = (tail1131.cdr)); + (L1127 = (L1127.cdr)); + } + } + (optrOpnd = (falseHead1130.cdr)); + return (new sc_Pair(((symbol_record = (term.car)), (symbol_record[(0)])), optrOpnd)); + } + }; + BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer = function(sym) { + var r; + var x; + return ((x = (sc_assq(sym, BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer))), ((x!== false)?(x.cdr):((r = [sym, null]), (BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer = (new sc_Pair((new sc_Pair(sym, r)), BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer))), r))); + }; + (BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer = null); + translate_alist_nboyer = function(alist) { + var sc_alist_6; + var term; + return ((alist === null)?null:(new sc_Pair((new sc_Pair((alist.car.car), ((term = (alist.car.cdr)), (!(term instanceof sc_Pair)?term:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((term.car))), (translate_args_nboyer((term.cdr))))))))), ((sc_alist_6 = (alist.cdr)), ((sc_alist_6 === null)?null:(new sc_Pair((new sc_Pair((sc_alist_6.car.car), (translate_term_nboyer((sc_alist_6.car.cdr))))), (translate_alist_nboyer((sc_alist_6.cdr)))))))))); + }; + apply_subst_nboyer = function(alist, term) { + var lst; + var temp_temp; + return (!(term instanceof sc_Pair)?((temp_temp = (sc_assq(term, alist))), ((temp_temp!== false)?(temp_temp.cdr):term)):(new sc_Pair((term.car), ((lst = (term.cdr)), ((lst === null)?null:(new sc_Pair((apply_subst_nboyer(alist, (lst.car))), (apply_subst_lst_nboyer(alist, (lst.cdr)))))))))); + }; + apply_subst_lst_nboyer = function(alist, lst) { + var sc_lst_7; + return ((lst === null)?null:(new sc_Pair((apply_subst_nboyer(alist, (lst.car))), ((sc_lst_7 = (lst.cdr)), ((sc_lst_7 === null)?null:(new sc_Pair((apply_subst_nboyer(alist, (sc_lst_7.car))), (apply_subst_lst_nboyer(alist, (sc_lst_7.cdr)))))))))); + }; + tautologyp_nboyer = function(sc_x_11, true_lst, false_lst) { + var tmp1125; + var x; + var tmp1126; + var sc_x_8; + var sc_tmp1125_9; + var sc_tmp1126_10; + var sc_x_11; + var true_lst; + var false_lst; + while (true) { + if ((((sc_tmp1126_10 = (is_term_equal_nboyer(sc_x_11, true_term_nboyer))), ((sc_tmp1126_10!== false)?sc_tmp1126_10:(is_term_member_nboyer(sc_x_11, true_lst))))!== false)) + return true; + else + if ((((sc_tmp1125_9 = (is_term_equal_nboyer(sc_x_11, false_term_nboyer))), ((sc_tmp1125_9!== false)?sc_tmp1125_9:(is_term_member_nboyer(sc_x_11, false_lst))))!== false)) + return false; + else + if (!(sc_x_11 instanceof sc_Pair)) + return false; + else + if (((sc_x_11.car)===if_constructor_nboyer)) + if ((((sc_x_8 = (sc_x_11.cdr.car)), (tmp1126 = (is_term_equal_nboyer(sc_x_8, true_term_nboyer))), ((tmp1126!== false)?tmp1126:(is_term_member_nboyer(sc_x_8, true_lst))))!== false)) + (sc_x_11 = (sc_x_11.cdr.cdr.car)); + else + if ((((x = (sc_x_11.cdr.car)), (tmp1125 = (is_term_equal_nboyer(x, false_term_nboyer))), ((tmp1125!== false)?tmp1125:(is_term_member_nboyer(x, false_lst))))!== false)) + (sc_x_11 = (sc_x_11.cdr.cdr.cdr.car)); + else + if (((tautologyp_nboyer((sc_x_11.cdr.cdr.car), (new sc_Pair((sc_x_11.cdr.car), true_lst)), false_lst))!== false)) + { + (false_lst = (new sc_Pair((sc_x_11.cdr.car), false_lst))); + (sc_x_11 = (sc_x_11.cdr.cdr.cdr.car)); + } + else + return false; + else + return false; + } + }; + (if_constructor_nboyer = "\u1E9C*"); + (rewrite_count_nboyer = (0)); + rewrite_nboyer = function(term) { + var term2; + var sc_term_12; + var lst; + var symbol_record; + var sc_lst_13; + { + (++rewrite_count_nboyer); + if (!(term instanceof sc_Pair)) + return term; + else + { + (sc_term_12 = (new sc_Pair((term.car), ((sc_lst_13 = (term.cdr)), ((sc_lst_13 === null)?null:(new sc_Pair((rewrite_nboyer((sc_lst_13.car))), (rewrite_args_nboyer((sc_lst_13.cdr)))))))))); + (lst = ((symbol_record = (term.car)), (symbol_record[(1)]))); + while (true) { + if ((lst === null)) + return sc_term_12; + else + if ((((term2 = ((lst.car).cdr.car)), (unify_subst_nboyer = null), (one_way_unify1_nboyer(sc_term_12, term2)))!== false)) + return (rewrite_nboyer((apply_subst_nboyer(unify_subst_nboyer, ((lst.car).cdr.cdr.car))))); + else + (lst = (lst.cdr)); + } + } + } + }; + rewrite_args_nboyer = function(lst) { + var sc_lst_14; + return ((lst === null)?null:(new sc_Pair((rewrite_nboyer((lst.car))), ((sc_lst_14 = (lst.cdr)), ((sc_lst_14 === null)?null:(new sc_Pair((rewrite_nboyer((sc_lst_14.car))), (rewrite_args_nboyer((sc_lst_14.cdr)))))))))); + }; + (unify_subst_nboyer = "\u1E9C*"); + one_way_unify1_nboyer = function(term1, term2) { + var lst1; + var lst2; + var temp_temp; + if (!(term2 instanceof sc_Pair)) + { + (temp_temp = (sc_assq(term2, unify_subst_nboyer))); + if ((temp_temp!== false)) + return (is_term_equal_nboyer(term1, (temp_temp.cdr))); + else + if ((sc_isNumber(term2))) + return (sc_isEqual(term1, term2)); + else + { + (unify_subst_nboyer = (new sc_Pair((new sc_Pair(term2, term1)), unify_subst_nboyer))); + return true; + } + } + else + if (!(term1 instanceof sc_Pair)) + return false; + else + if (((term1.car)===(term2.car))) + { + (lst1 = (term1.cdr)); + (lst2 = (term2.cdr)); + while (true) { + if ((lst1 === null)) + return (lst2 === null); + else + if ((lst2 === null)) + return false; + else + if (((one_way_unify1_nboyer((lst1.car), (lst2.car)))!== false)) + { + (lst1 = (lst1.cdr)); + (lst2 = (lst2.cdr)); + } + else + return false; + } + } + else + return false; + }; + (false_term_nboyer = "\u1E9C*"); + (true_term_nboyer = "\u1E9C*"); + trans_of_implies1_nboyer = function(n) { + var sc_n_15; + return ((sc_isEqual(n, (1)))?(sc_list("\u1E9Cimplies", (0), (1))):(sc_list("\u1E9Cand", (sc_list("\u1E9Cimplies", (n-(1)), n)), ((sc_n_15 = (n-(1))), ((sc_isEqual(sc_n_15, (1)))?(sc_list("\u1E9Cimplies", (0), (1))):(sc_list("\u1E9Cand", (sc_list("\u1E9Cimplies", (sc_n_15-(1)), sc_n_15)), (trans_of_implies1_nboyer((sc_n_15-(1))))))))))); + }; + is_term_equal_nboyer = function(x, y) { + var lst1; + var lst2; + var r2; + var r1; + if ((x instanceof sc_Pair)) + if ((y instanceof sc_Pair)) + if ((((r1 = (x.car)), (r2 = (y.car)), (r1===r2))!== false)) + { + (lst1 = (x.cdr)); + (lst2 = (y.cdr)); + while (true) { + if ((lst1 === null)) + return (lst2 === null); + else + if ((lst2 === null)) + return false; + else + if (((is_term_equal_nboyer((lst1.car), (lst2.car)))!== false)) + { + (lst1 = (lst1.cdr)); + (lst2 = (lst2.cdr)); + } + else + return false; + } + } + else + return false; + else + return false; + else + return (sc_isEqual(x, y)); + }; + is_term_member_nboyer = function(x, lst) { + var x; + var lst; + while (true) { + if ((lst === null)) + return false; + else + if (((is_term_equal_nboyer(x, (lst.car)))!== false)) + return true; + else + (lst = (lst.cdr)); + } + }; + BgL_setupzd2boyerzd2 = function() { + var symbol_record; + var value; + var BgL_sc_symbolzd2record_16zd2; + var sym; + var sc_sym_17; + var term; + var lst; + var sc_term_18; + var sc_term_19; + { + (BgL_sc_za2symbolzd2recordszd2alistza2_2z00_nboyer = null); + (if_constructor_nboyer = (BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer("\u1E9Cif"))); + (false_term_nboyer = ((sc_term_19 = (new sc_Pair("\u1E9Cf",null))), (!(sc_term_19 instanceof sc_Pair)?sc_term_19:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((sc_term_19.car))), (translate_args_nboyer((sc_term_19.cdr)))))))); + (true_term_nboyer = ((sc_term_18 = (new sc_Pair("\u1E9Ct",null))), (!(sc_term_18 instanceof sc_Pair)?sc_term_18:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((sc_term_18.car))), (translate_args_nboyer((sc_term_18.cdr)))))))); + (lst = sc_const_3_nboyer); + while (!(lst === null)) { + { + (term = (lst.car)); + if (((term instanceof sc_Pair)&&(((term.car)==="\u1E9Cequal")&&((term.cdr.car) instanceof sc_Pair)))) + { + (sc_sym_17 = ((term.cdr.car).car)); + (value = (new sc_Pair((!(term instanceof sc_Pair)?term:(new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((term.car))), (translate_args_nboyer((term.cdr)))))), ((sym = ((term.cdr.car).car)), (BgL_sc_symbolzd2record_16zd2 = (BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(sym))), (BgL_sc_symbolzd2record_16zd2[(1)]))))); + (symbol_record = (BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer(sc_sym_17))); + (symbol_record[(1)] = value); + } + else + (sc_error("ADD-LEMMA did not like term: ", term)); + (lst = (lst.cdr)); + } + } + return true; + } + }; + BgL_testzd2boyerzd2 = function(n) { + var optrOpnd; + var term; + var sc_n_20; + var answer; + var sc_term_21; + var sc_term_22; + { + (rewrite_count_nboyer = (0)); + (term = sc_const_4_nboyer); + (sc_n_20 = n); + while (!(sc_n_20=== 0)) { + { + (term = (sc_list("\u1E9Cor", term, (new sc_Pair("\u1E9Cf",null))))); + (--sc_n_20); + } + } + (sc_term_22 = term); + if (!(sc_term_22 instanceof sc_Pair)) + (optrOpnd = sc_term_22); + else + (optrOpnd = (new sc_Pair((BgL_sc_symbolzd2ze3symbolzd2record_1ze3_nboyer((sc_term_22.car))), (translate_args_nboyer((sc_term_22.cdr)))))); + (sc_term_21 = (apply_subst_nboyer(((const_nboyer === null)?null:(new sc_Pair((new sc_Pair((const_nboyer.car.car), (translate_term_nboyer((const_nboyer.car.cdr))))), (translate_alist_nboyer((const_nboyer.cdr)))))), optrOpnd))); + (answer = (tautologyp_nboyer((rewrite_nboyer(sc_term_21)), null, null))); + (sc_write(rewrite_count_nboyer)); + (sc_display(" rewrites")); + (sc_newline()); + if ((answer!== false)) + return rewrite_count_nboyer; + else + return false; + } + }; +} +/* Exported Variables */ +var BgL_parsezd2ze3nbzd2treesze3; +var BgL_earleyzd2benchmarkzd2; +var BgL_parsezd2ze3parsedzf3zc2; +var test; +var BgL_parsezd2ze3treesz31; +var BgL_makezd2parserzd2; +/* End Exports */ + +var const_earley; +{ + (const_earley = (new sc_Pair((new sc_Pair("\u1E9Cs",(new sc_Pair((new sc_Pair("\u1E9Ca",null)),(new sc_Pair((new sc_Pair("\u1E9Cs",(new sc_Pair("\u1E9Cs",null)))),null)))))),null))); + BgL_makezd2parserzd2 = function(grammar, lexer) { + var i; + var parser_descr; + var def_loop; + var nb_nts; + var names; + var steps; + var predictors; + var enders; + var starters; + var nts; + var sc_names_1; + var sc_steps_2; + var sc_predictors_3; + var sc_enders_4; + var sc_starters_5; + var nb_confs; + var BgL_sc_defzd2loop_6zd2; + var BgL_sc_nbzd2nts_7zd2; + var sc_nts_8; + var BgL_sc_defzd2loop_9zd2; + var ind; + { + ind = function(nt, sc_nts_10) { + var i; + { + (i = ((sc_nts_10.length)-(1))); + while (true) { + if ((i>=(0))) + if ((sc_isEqual((sc_nts_10[i]), nt))) + return i; + else + (--i); + else + return false; + } + } + }; + (sc_nts_8 = ((BgL_sc_defzd2loop_9zd2 = function(defs, sc_nts_11) { + var rule_loop; + var head; + var def; + return ((defs instanceof sc_Pair)?((def = (defs.car)), (head = (def.car)), (rule_loop = function(rules, sc_nts_12) { + var nt; + var l; + var sc_nts_13; + var rule; + if ((rules instanceof sc_Pair)) + { + (rule = (rules.car)); + (l = rule); + (sc_nts_13 = sc_nts_12); + while ((l instanceof sc_Pair)) { + { + (nt = (l.car)); + (l = (l.cdr)); + (sc_nts_13 = (((sc_member(nt, sc_nts_13))!== false)?sc_nts_13:(new sc_Pair(nt, sc_nts_13)))); + } + } + return (rule_loop((rules.cdr), sc_nts_13)); + } + else + return (BgL_sc_defzd2loop_9zd2((defs.cdr), sc_nts_12)); + }), (rule_loop((def.cdr), (((sc_member(head, sc_nts_11))!== false)?sc_nts_11:(new sc_Pair(head, sc_nts_11)))))):(sc_list2vector((sc_reverse(sc_nts_11))))); + }), (BgL_sc_defzd2loop_9zd2(grammar, null)))); + (BgL_sc_nbzd2nts_7zd2 = (sc_nts_8.length)); + (nb_confs = (((BgL_sc_defzd2loop_6zd2 = function(defs, BgL_sc_nbzd2confs_14zd2) { + var rule_loop; + var def; + return ((defs instanceof sc_Pair)?((def = (defs.car)), (rule_loop = function(rules, BgL_sc_nbzd2confs_15zd2) { + var l; + var BgL_sc_nbzd2confs_16zd2; + var rule; + if ((rules instanceof sc_Pair)) + { + (rule = (rules.car)); + (l = rule); + (BgL_sc_nbzd2confs_16zd2 = BgL_sc_nbzd2confs_15zd2); + while ((l instanceof sc_Pair)) { + { + (l = (l.cdr)); + (++BgL_sc_nbzd2confs_16zd2); + } + } + return (rule_loop((rules.cdr), (BgL_sc_nbzd2confs_16zd2+(1)))); + } + else + return (BgL_sc_defzd2loop_6zd2((defs.cdr), BgL_sc_nbzd2confs_15zd2)); + }), (rule_loop((def.cdr), BgL_sc_nbzd2confs_14zd2))):BgL_sc_nbzd2confs_14zd2); + }), (BgL_sc_defzd2loop_6zd2(grammar, (0))))+BgL_sc_nbzd2nts_7zd2)); + (sc_starters_5 = (sc_makeVector(BgL_sc_nbzd2nts_7zd2, null))); + (sc_enders_4 = (sc_makeVector(BgL_sc_nbzd2nts_7zd2, null))); + (sc_predictors_3 = (sc_makeVector(BgL_sc_nbzd2nts_7zd2, null))); + (sc_steps_2 = (sc_makeVector(nb_confs, false))); + (sc_names_1 = (sc_makeVector(nb_confs, false))); + (nts = sc_nts_8); + (starters = sc_starters_5); + (enders = sc_enders_4); + (predictors = sc_predictors_3); + (steps = sc_steps_2); + (names = sc_names_1); + (nb_nts = (sc_nts_8.length)); + (i = (nb_nts-(1))); + while ((i>=(0))) { + { + (sc_steps_2[i] = (i-nb_nts)); + (sc_names_1[i] = (sc_list((sc_nts_8[i]), (0)))); + (sc_enders_4[i] = (sc_list(i))); + (--i); + } + } + def_loop = function(defs, conf) { + var rule_loop; + var head; + var def; + return ((defs instanceof sc_Pair)?((def = (defs.car)), (head = (def.car)), (rule_loop = function(rules, conf, rule_num) { + var i; + var sc_i_17; + var nt; + var l; + var sc_conf_18; + var sc_i_19; + var rule; + if ((rules instanceof sc_Pair)) + { + (rule = (rules.car)); + (names[conf] = (sc_list(head, rule_num))); + (sc_i_19 = (ind(head, nts))); + (starters[sc_i_19] = (new sc_Pair(conf, (starters[sc_i_19])))); + (l = rule); + (sc_conf_18 = conf); + while ((l instanceof sc_Pair)) { + { + (nt = (l.car)); + (steps[sc_conf_18] = (ind(nt, nts))); + (sc_i_17 = (ind(nt, nts))); + (predictors[sc_i_17] = (new sc_Pair(sc_conf_18, (predictors[sc_i_17])))); + (l = (l.cdr)); + (++sc_conf_18); + } + } + (steps[sc_conf_18] = ((ind(head, nts))-nb_nts)); + (i = (ind(head, nts))); + (enders[i] = (new sc_Pair(sc_conf_18, (enders[i])))); + return (rule_loop((rules.cdr), (sc_conf_18+(1)), (rule_num+(1)))); + } + else + return (def_loop((defs.cdr), conf)); + }), (rule_loop((def.cdr), conf, (1)))):undefined); + }; + (def_loop(grammar, (sc_nts_8.length))); + (parser_descr = [lexer, sc_nts_8, sc_starters_5, sc_enders_4, sc_predictors_3, sc_steps_2, sc_names_1]); + return function(input) { + var optrOpnd; + var sc_optrOpnd_20; + var sc_optrOpnd_21; + var sc_optrOpnd_22; + var loop1; + var BgL_sc_stateza2_23za2; + var toks; + var BgL_sc_nbzd2nts_24zd2; + var sc_steps_25; + var sc_enders_26; + var state_num; + var BgL_sc_statesza2_27za2; + var states; + var i; + var conf; + var l; + var tok_nts; + var sc_i_28; + var sc_i_29; + var l1; + var l2; + var tok; + var tail1129; + var L1125; + var goal_enders; + var BgL_sc_statesza2_30za2; + var BgL_sc_nbzd2nts_31zd2; + var BgL_sc_nbzd2confs_32zd2; + var nb_toks; + var goal_starters; + var sc_states_33; + var BgL_sc_nbzd2confs_34zd2; + var BgL_sc_nbzd2toks_35zd2; + var sc_toks_36; + var falseHead1128; + var sc_names_37; + var sc_steps_38; + var sc_predictors_39; + var sc_enders_40; + var sc_starters_41; + var sc_nts_42; + var lexer; + var sc_ind_43; + var make_states; + var BgL_sc_confzd2setzd2getza2_44za2; + var conf_set_merge_new_bang; + var conf_set_adjoin; + var BgL_sc_confzd2setzd2adjoinza2_45za2; + var BgL_sc_confzd2setzd2adjoinza2za2_46z00; + var conf_set_union; + var forw; + var is_parsed; + var deriv_trees; + var BgL_sc_derivzd2treesza2_47z70; + var nb_deriv_trees; + var BgL_sc_nbzd2derivzd2treesza2_48za2; + { + sc_ind_43 = function(nt, sc_nts_49) { + var i; + { + (i = ((sc_nts_49.length)-(1))); + while (true) { + if ((i>=(0))) + if ((sc_isEqual((sc_nts_49[i]), nt))) + return i; + else + (--i); + else + return false; + } + } + }; + make_states = function(BgL_sc_nbzd2toks_50zd2, BgL_sc_nbzd2confs_51zd2) { + var v; + var i; + var sc_states_52; + { + (sc_states_52 = (sc_makeVector((BgL_sc_nbzd2toks_50zd2+(1)), false))); + (i = BgL_sc_nbzd2toks_50zd2); + while ((i>=(0))) { + { + (v = (sc_makeVector((BgL_sc_nbzd2confs_51zd2+(1)), false))); + (v[(0)] = (-1)); + (sc_states_52[i] = v); + (--i); + } + } + return sc_states_52; + } + }; + BgL_sc_confzd2setzd2getza2_44za2 = function(state, BgL_sc_statezd2num_53zd2, sc_conf_54) { + var conf_set; + var BgL_sc_confzd2set_55zd2; + return ((BgL_sc_confzd2set_55zd2 = (state[(sc_conf_54+(1))])), ((BgL_sc_confzd2set_55zd2!== false)?BgL_sc_confzd2set_55zd2:((conf_set = (sc_makeVector((BgL_sc_statezd2num_53zd2+(6)), false))), (conf_set[(1)] = (-3)), (conf_set[(2)] = (-1)), (conf_set[(3)] = (-1)), (conf_set[(4)] = (-1)), (state[(sc_conf_54+(1))] = conf_set), conf_set))); + }; + conf_set_merge_new_bang = function(conf_set) { + return ((conf_set[((conf_set[(1)])+(5))] = (conf_set[(4)])), (conf_set[(1)] = (conf_set[(3)])), (conf_set[(3)] = (-1)), (conf_set[(4)] = (-1))); + }; + conf_set_adjoin = function(state, conf_set, sc_conf_56, i) { + var tail; + return ((tail = (conf_set[(3)])), (conf_set[(i+(5))] = (-1)), (conf_set[(tail+(5))] = i), (conf_set[(3)] = i), ((tail<(0))?((conf_set[(0)] = (state[(0)])), (state[(0)] = sc_conf_56)):undefined)); + }; + BgL_sc_confzd2setzd2adjoinza2_45za2 = function(sc_states_57, BgL_sc_statezd2num_58zd2, l, i) { + var conf_set; + var sc_conf_59; + var l1; + var state; + { + (state = (sc_states_57[BgL_sc_statezd2num_58zd2])); + (l1 = l); + while ((l1 instanceof sc_Pair)) { + { + (sc_conf_59 = (l1.car)); + (conf_set = (BgL_sc_confzd2setzd2getza2_44za2(state, BgL_sc_statezd2num_58zd2, sc_conf_59))); + if (((conf_set[(i+(5))])=== false)) + { + (conf_set_adjoin(state, conf_set, sc_conf_59, i)); + (l1 = (l1.cdr)); + } + else + (l1 = (l1.cdr)); + } + } + return undefined; + } + }; + BgL_sc_confzd2setzd2adjoinza2za2_46z00 = function(sc_states_60, BgL_sc_statesza2_61za2, BgL_sc_statezd2num_62zd2, sc_conf_63, i) { + var BgL_sc_confzd2setza2_64z70; + var BgL_sc_stateza2_65za2; + var conf_set; + var state; + return ((state = (sc_states_60[BgL_sc_statezd2num_62zd2])), ((((conf_set = (state[(sc_conf_63+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false)?((BgL_sc_stateza2_65za2 = (BgL_sc_statesza2_61za2[BgL_sc_statezd2num_62zd2])), (BgL_sc_confzd2setza2_64z70 = (BgL_sc_confzd2setzd2getza2_44za2(BgL_sc_stateza2_65za2, BgL_sc_statezd2num_62zd2, sc_conf_63))), (((BgL_sc_confzd2setza2_64z70[(i+(5))])=== false)?(conf_set_adjoin(BgL_sc_stateza2_65za2, BgL_sc_confzd2setza2_64z70, sc_conf_63, i)):undefined), true):false)); + }; + conf_set_union = function(state, conf_set, sc_conf_66, other_set) { + var i; + { + (i = (other_set[(2)])); + while ((i>=(0))) { + if (((conf_set[(i+(5))])=== false)) + { + (conf_set_adjoin(state, conf_set, sc_conf_66, i)); + (i = (other_set[(i+(5))])); + } + else + (i = (other_set[(i+(5))])); + } + return undefined; + } + }; + forw = function(sc_states_67, BgL_sc_statezd2num_68zd2, sc_starters_69, sc_enders_70, sc_predictors_71, sc_steps_72, sc_nts_73) { + var next_set; + var next; + var conf_set; + var ender; + var l; + var starter_set; + var starter; + var sc_l_74; + var sc_loop1_75; + var head; + var BgL_sc_confzd2set_76zd2; + var BgL_sc_statezd2num_77zd2; + var state; + var sc_states_78; + var preds; + var BgL_sc_confzd2set_79zd2; + var step; + var sc_conf_80; + var BgL_sc_nbzd2nts_81zd2; + var sc_state_82; + { + (sc_state_82 = (sc_states_67[BgL_sc_statezd2num_68zd2])); + (BgL_sc_nbzd2nts_81zd2 = (sc_nts_73.length)); + while (true) { + { + (sc_conf_80 = (sc_state_82[(0)])); + if ((sc_conf_80>=(0))) + { + (step = (sc_steps_72[sc_conf_80])); + (BgL_sc_confzd2set_79zd2 = (sc_state_82[(sc_conf_80+(1))])); + (head = (BgL_sc_confzd2set_79zd2[(4)])); + (sc_state_82[(0)] = (BgL_sc_confzd2set_79zd2[(0)])); + (conf_set_merge_new_bang(BgL_sc_confzd2set_79zd2)); + if ((step>=(0))) + { + (sc_l_74 = (sc_starters_69[step])); + while ((sc_l_74 instanceof sc_Pair)) { + { + (starter = (sc_l_74.car)); + (starter_set = (BgL_sc_confzd2setzd2getza2_44za2(sc_state_82, BgL_sc_statezd2num_68zd2, starter))); + if (((starter_set[(BgL_sc_statezd2num_68zd2+(5))])=== false)) + { + (conf_set_adjoin(sc_state_82, starter_set, starter, BgL_sc_statezd2num_68zd2)); + (sc_l_74 = (sc_l_74.cdr)); + } + else + (sc_l_74 = (sc_l_74.cdr)); + } + } + (l = (sc_enders_70[step])); + while ((l instanceof sc_Pair)) { + { + (ender = (l.car)); + if ((((conf_set = (sc_state_82[(ender+(1))])), ((conf_set!== false)?(conf_set[(BgL_sc_statezd2num_68zd2+(5))]):false))!== false)) + { + (next = (sc_conf_80+(1))); + (next_set = (BgL_sc_confzd2setzd2getza2_44za2(sc_state_82, BgL_sc_statezd2num_68zd2, next))); + (conf_set_union(sc_state_82, next_set, next, BgL_sc_confzd2set_79zd2)); + (l = (l.cdr)); + } + else + (l = (l.cdr)); + } + } + } + else + { + (preds = (sc_predictors_71[(step+BgL_sc_nbzd2nts_81zd2)])); + (sc_states_78 = sc_states_67); + (state = sc_state_82); + (BgL_sc_statezd2num_77zd2 = BgL_sc_statezd2num_68zd2); + (BgL_sc_confzd2set_76zd2 = BgL_sc_confzd2set_79zd2); + sc_loop1_75 = function(l) { + var sc_state_83; + var BgL_sc_nextzd2set_84zd2; + var sc_next_85; + var pred_set; + var i; + var pred; + if ((l instanceof sc_Pair)) + { + (pred = (l.car)); + (i = head); + while ((i>=(0))) { + { + (pred_set = ((sc_state_83 = (sc_states_78[i])), (sc_state_83[(pred+(1))]))); + if ((pred_set!== false)) + { + (sc_next_85 = (pred+(1))); + (BgL_sc_nextzd2set_84zd2 = (BgL_sc_confzd2setzd2getza2_44za2(state, BgL_sc_statezd2num_77zd2, sc_next_85))); + (conf_set_union(state, BgL_sc_nextzd2set_84zd2, sc_next_85, pred_set)); + } + (i = (BgL_sc_confzd2set_76zd2[(i+(5))])); + } + } + return (sc_loop1_75((l.cdr))); + } + else + return undefined; + }; + (sc_loop1_75(preds)); + } + } + else + return undefined; + } + } + } + }; + is_parsed = function(nt, i, j, sc_nts_86, sc_enders_87, sc_states_88) { + var conf_set; + var state; + var sc_conf_89; + var l; + var BgL_sc_ntza2_90za2; + { + (BgL_sc_ntza2_90za2 = (sc_ind_43(nt, sc_nts_86))); + if ((BgL_sc_ntza2_90za2!== false)) + { + (sc_nts_86.length); + (l = (sc_enders_87[BgL_sc_ntza2_90za2])); + while (true) { + if ((l instanceof sc_Pair)) + { + (sc_conf_89 = (l.car)); + if ((((state = (sc_states_88[j])), (conf_set = (state[(sc_conf_89+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false)) + return true; + else + (l = (l.cdr)); + } + else + return false; + } + } + else + return false; + } + }; + deriv_trees = function(sc_conf_91, i, j, sc_enders_92, sc_steps_93, sc_names_94, sc_toks_95, sc_states_96, BgL_sc_nbzd2nts_97zd2) { + var sc_loop1_98; + var prev; + var name; + return ((name = (sc_names_94[sc_conf_91])), ((name!== false)?((sc_conf_91=(0))) + if (((k>=i)&&(((sc_state_99 = (sc_states_96[k])), (conf_set = (sc_state_99[(prev+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false))) + { + (prev_trees = (deriv_trees(prev, i, k, sc_enders_92, sc_steps_93, sc_names_94, sc_toks_95, sc_states_96, BgL_sc_nbzd2nts_97zd2))); + (ender_trees = (deriv_trees(ender, k, j, sc_enders_92, sc_steps_93, sc_names_94, sc_toks_95, sc_states_96, BgL_sc_nbzd2nts_97zd2))); + loop3 = function(l3, l2) { + var l4; + var sc_l2_100; + var ender_tree; + if ((l3 instanceof sc_Pair)) + { + (ender_tree = (sc_list((l3.car)))); + (l4 = prev_trees); + (sc_l2_100 = l2); + while ((l4 instanceof sc_Pair)) { + { + (sc_l2_100 = (new sc_Pair((sc_append((l4.car), ender_tree)), sc_l2_100))); + (l4 = (l4.cdr)); + } + } + return (loop3((l3.cdr), sc_l2_100)); + } + else + return (loop2((ender_set[(k+(5))]), l2)); + }; + return (loop3(ender_trees, l2)); + } + else + (k = (ender_set[(k+(5))])); + else + return (sc_loop1_98((l1.cdr), l2)); + } + }; + return (loop2((ender_set[(2)]), l2)); + } + else + (l1 = (l1.cdr)); + } + else + return l2; + } + }), (sc_loop1_98((sc_enders_92[(sc_steps_93[prev])]), null))))); + }; + BgL_sc_derivzd2treesza2_47z70 = function(nt, i, j, sc_nts_101, sc_enders_102, sc_steps_103, sc_names_104, sc_toks_105, sc_states_106) { + var conf_set; + var state; + var sc_conf_107; + var l; + var trees; + var BgL_sc_nbzd2nts_108zd2; + var BgL_sc_ntza2_109za2; + { + (BgL_sc_ntza2_109za2 = (sc_ind_43(nt, sc_nts_101))); + if ((BgL_sc_ntza2_109za2!== false)) + { + (BgL_sc_nbzd2nts_108zd2 = (sc_nts_101.length)); + (l = (sc_enders_102[BgL_sc_ntza2_109za2])); + (trees = null); + while ((l instanceof sc_Pair)) { + { + (sc_conf_107 = (l.car)); + if ((((state = (sc_states_106[j])), (conf_set = (state[(sc_conf_107+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false)) + { + (l = (l.cdr)); + (trees = (sc_append((deriv_trees(sc_conf_107, i, j, sc_enders_102, sc_steps_103, sc_names_104, sc_toks_105, sc_states_106, BgL_sc_nbzd2nts_108zd2)), trees))); + } + else + (l = (l.cdr)); + } + } + return trees; + } + else + return false; + } + }; + nb_deriv_trees = function(sc_conf_110, i, j, sc_enders_111, sc_steps_112, sc_toks_113, sc_states_114, BgL_sc_nbzd2nts_115zd2) { + var sc_loop1_116; + var tmp1124; + var prev; + return ((prev = (sc_conf_110-(1))), ((((tmp1124 = (sc_conf_110=(0))) { + if (((k>=i)&&(((state = (sc_states_114[k])), (conf_set = (state[(prev+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false))) + { + (nb_prev_trees = (nb_deriv_trees(prev, i, k, sc_enders_111, sc_steps_112, sc_toks_113, sc_states_114, BgL_sc_nbzd2nts_115zd2))); + (nb_ender_trees = (nb_deriv_trees(ender, k, j, sc_enders_111, sc_steps_112, sc_toks_113, sc_states_114, BgL_sc_nbzd2nts_115zd2))); + (k = (ender_set[(k+(5))])); + (n +=(nb_prev_trees*nb_ender_trees)); + } + else + (k = (ender_set[(k+(5))])); + } + return (sc_loop1_116((l.cdr), n)); + } + else + (l = (l.cdr)); + } + else + return sc_n_118; + } + }), (sc_loop1_116((sc_enders_111[(sc_steps_112[prev])]), (0)))))); + }; + BgL_sc_nbzd2derivzd2treesza2_48za2 = function(nt, i, j, sc_nts_119, sc_enders_120, sc_steps_121, sc_toks_122, sc_states_123) { + var conf_set; + var state; + var sc_conf_124; + var l; + var nb_trees; + var BgL_sc_nbzd2nts_125zd2; + var BgL_sc_ntza2_126za2; + { + (BgL_sc_ntza2_126za2 = (sc_ind_43(nt, sc_nts_119))); + if ((BgL_sc_ntza2_126za2!== false)) + { + (BgL_sc_nbzd2nts_125zd2 = (sc_nts_119.length)); + (l = (sc_enders_120[BgL_sc_ntza2_126za2])); + (nb_trees = (0)); + while ((l instanceof sc_Pair)) { + { + (sc_conf_124 = (l.car)); + if ((((state = (sc_states_123[j])), (conf_set = (state[(sc_conf_124+(1))])), ((conf_set!== false)?(conf_set[(i+(5))]):false))!== false)) + { + (l = (l.cdr)); + (nb_trees = ((nb_deriv_trees(sc_conf_124, i, j, sc_enders_120, sc_steps_121, sc_toks_122, sc_states_123, BgL_sc_nbzd2nts_125zd2))+nb_trees)); + } + else + (l = (l.cdr)); + } + } + return nb_trees; + } + else + return false; + } + }; + (lexer = (parser_descr[(0)])); + (sc_nts_42 = (parser_descr[(1)])); + (sc_starters_41 = (parser_descr[(2)])); + (sc_enders_40 = (parser_descr[(3)])); + (sc_predictors_39 = (parser_descr[(4)])); + (sc_steps_38 = (parser_descr[(5)])); + (sc_names_37 = (parser_descr[(6)])); + (falseHead1128 = (new sc_Pair(null, null))); + (L1125 = (lexer(input))); + (tail1129 = falseHead1128); + while (!(L1125 === null)) { + { + (tok = (L1125.car)); + (l1 = (tok.cdr)); + (l2 = null); + while ((l1 instanceof sc_Pair)) { + { + (sc_i_29 = (sc_ind_43((l1.car), sc_nts_42))); + if ((sc_i_29!== false)) + { + (l1 = (l1.cdr)); + (l2 = (new sc_Pair(sc_i_29, l2))); + } + else + (l1 = (l1.cdr)); + } + } + (sc_optrOpnd_22 = (new sc_Pair((tok.car), (sc_reverse(l2))))); + (sc_optrOpnd_21 = (new sc_Pair(sc_optrOpnd_22, null))); + (tail1129.cdr = sc_optrOpnd_21); + (tail1129 = (tail1129.cdr)); + (L1125 = (L1125.cdr)); + } + } + (sc_optrOpnd_20 = (falseHead1128.cdr)); + (sc_toks_36 = (sc_list2vector(sc_optrOpnd_20))); + (BgL_sc_nbzd2toks_35zd2 = (sc_toks_36.length)); + (BgL_sc_nbzd2confs_34zd2 = (sc_steps_38.length)); + (sc_states_33 = (make_states(BgL_sc_nbzd2toks_35zd2, BgL_sc_nbzd2confs_34zd2))); + (goal_starters = (sc_starters_41[(0)])); + (BgL_sc_confzd2setzd2adjoinza2_45za2(sc_states_33, (0), goal_starters, (0))); + (forw(sc_states_33, (0), sc_starters_41, sc_enders_40, sc_predictors_39, sc_steps_38, sc_nts_42)); + (sc_i_28 = (0)); + while ((sc_i_28=(0))) { + { + (states = sc_states_33); + (BgL_sc_statesza2_27za2 = BgL_sc_statesza2_30za2); + (state_num = i); + (sc_enders_26 = sc_enders_40); + (sc_steps_25 = sc_steps_38); + (BgL_sc_nbzd2nts_24zd2 = BgL_sc_nbzd2nts_31zd2); + (toks = sc_toks_36); + (BgL_sc_stateza2_23za2 = (BgL_sc_statesza2_30za2[i])); + loop1 = function() { + var sc_loop1_127; + var prev; + var BgL_sc_statesza2_128za2; + var sc_states_129; + var j; + var i; + var sc_i_130; + var head; + var conf_set; + var sc_conf_131; + { + (sc_conf_131 = (BgL_sc_stateza2_23za2[(0)])); + if ((sc_conf_131>=(0))) + { + (conf_set = (BgL_sc_stateza2_23za2[(sc_conf_131+(1))])); + (head = (conf_set[(4)])); + (BgL_sc_stateza2_23za2[(0)] = (conf_set[(0)])); + (conf_set_merge_new_bang(conf_set)); + (sc_i_130 = head); + while ((sc_i_130>=(0))) { + { + (i = sc_i_130); + (j = state_num); + (sc_states_129 = states); + (BgL_sc_statesza2_128za2 = BgL_sc_statesza2_27za2); + (prev = (sc_conf_131-(1))); + if (((sc_conf_131>=BgL_sc_nbzd2nts_24zd2)&&((sc_steps_25[prev])>=(0)))) + { + sc_loop1_127 = function(l) { + var k; + var ender_set; + var state; + var ender; + var l; + while (true) { + if ((l instanceof sc_Pair)) + { + (ender = (l.car)); + (ender_set = ((state = (sc_states_129[j])), (state[(ender+(1))]))); + if ((ender_set!== false)) + { + (k = (ender_set[(2)])); + while ((k>=(0))) { + { + if ((k>=i)) + if (((BgL_sc_confzd2setzd2adjoinza2za2_46z00(sc_states_129, BgL_sc_statesza2_128za2, k, prev, i))!== false)) + (BgL_sc_confzd2setzd2adjoinza2za2_46z00(sc_states_129, BgL_sc_statesza2_128za2, j, ender, k)); + (k = (ender_set[(k+(5))])); + } + } + return (sc_loop1_127((l.cdr))); + } + else + (l = (l.cdr)); + } + else + return undefined; + } + }; + (sc_loop1_127((sc_enders_26[(sc_steps_25[prev])]))); + } + (sc_i_130 = (conf_set[(sc_i_130+(5))])); + } + } + return (loop1()); + } + else + return undefined; + } + }; + (loop1()); + (--i); + } + } + (optrOpnd = BgL_sc_statesza2_30za2); + return [sc_nts_42, sc_starters_41, sc_enders_40, sc_predictors_39, sc_steps_38, sc_names_37, sc_toks_36, optrOpnd, is_parsed, BgL_sc_derivzd2treesza2_47z70, BgL_sc_nbzd2derivzd2treesza2_48za2]; + } + }; + } + }; + BgL_parsezd2ze3parsedzf3zc2 = function(parse, nt, i, j) { + var is_parsed; + var states; + var enders; + var nts; + return ((nts = (parse[(0)])), (enders = (parse[(2)])), (states = (parse[(7)])), (is_parsed = (parse[(8)])), (is_parsed(nt, i, j, nts, enders, states))); + }; + BgL_parsezd2ze3treesz31 = function(parse, nt, i, j) { + var BgL_sc_derivzd2treesza2_132z70; + var states; + var toks; + var names; + var steps; + var enders; + var nts; + return ((nts = (parse[(0)])), (enders = (parse[(2)])), (steps = (parse[(4)])), (names = (parse[(5)])), (toks = (parse[(6)])), (states = (parse[(7)])), (BgL_sc_derivzd2treesza2_132z70 = (parse[(9)])), (BgL_sc_derivzd2treesza2_132z70(nt, i, j, nts, enders, steps, names, toks, states))); + }; + BgL_parsezd2ze3nbzd2treesze3 = function(parse, nt, i, j) { + var BgL_sc_nbzd2derivzd2treesza2_133za2; + var states; + var toks; + var steps; + var enders; + var nts; + return ((nts = (parse[(0)])), (enders = (parse[(2)])), (steps = (parse[(4)])), (toks = (parse[(6)])), (states = (parse[(7)])), (BgL_sc_nbzd2derivzd2treesza2_133za2 = (parse[(10)])), (BgL_sc_nbzd2derivzd2treesza2_133za2(nt, i, j, nts, enders, steps, toks, states))); + }; + test = function(k) { + var x; + var p; + return ((p = (BgL_makezd2parserzd2(const_earley, function(l) { + var sc_x_134; + var tail1134; + var L1130; + var falseHead1133; + { + (falseHead1133 = (new sc_Pair(null, null))); + (tail1134 = falseHead1133); + (L1130 = l); + while (!(L1130 === null)) { + { + (tail1134.cdr = (new sc_Pair(((sc_x_134 = (L1130.car)), (sc_list(sc_x_134, sc_x_134))), null))); + (tail1134 = (tail1134.cdr)); + (L1130 = (L1130.cdr)); + } + } + return (falseHead1133.cdr); + } + }))), (x = (p((sc_vector2list((sc_makeVector(k, "\u1E9Ca"))))))), (sc_length((BgL_parsezd2ze3treesz31(x, "\u1E9Cs", (0), k))))); + }; + BgL_earleyzd2benchmarkzd2 = function() { + var args = null; + for (var sc_tmp = arguments.length - 1; sc_tmp >= 0; sc_tmp--) { + args = sc_cons(arguments[sc_tmp], args); + } + var k; + return ((k = ((args === null)?(7):(args.car))), (BgL_runzd2benchmarkzd2("earley", (1), function() { + return (test(k)); + }, function(result) { + return ((sc_display(result)), (sc_newline()), true); + }))); + }; +} + + +/************* END OF GENERATED CODE *************/ +// Invoke this function to run a benchmark. +// The first argument is a string identifying the benchmark. +// The second argument is the number of times to run the benchmark. +// The third argument is a function that runs the benchmark. +// The fourth argument is a unary function that warns if the result +// returned by the benchmark is incorrect. +// +// Example: +// RunBenchmark("new Array()", +// 1, +// function () { new Array(1000000); } +// function (v) { +// return (v instanceof Array) && (v.length == 1000000); +// }); + +SC_DEFAULT_OUT = new sc_GenericOutputPort(function(s) {}); +SC_ERROR_OUT = SC_DEFAULT_OUT; + +function RunBenchmark(name, count, run, warn) { + for (var n = 0; n < count; ++n) { + result = run(); + } +} + +var BgL_runzd2benchmarkzd2 = RunBenchmark; + diff --git a/js/src/metrics/jint/v8/raytrace.js b/js/src/metrics/jint/v8/raytrace.js new file mode 100644 index 0000000..4561bbc --- /dev/null +++ b/js/src/metrics/jint/v8/raytrace.js @@ -0,0 +1,3418 @@ +// The ray tracer code in this file is written by Adam Burmister. It +// is available in its original form from: +// +// http://labs.flog.nz.co/raytracer/ +// +// It has been modified slightly by Google to work as a standalone +// benchmark, but the all the computational code remains +// untouched. This file also contains a copy of the Prototype +// JavaScript framework which is used by the ray tracer. + +var RayTrace = new BenchmarkSuite('RayTrace', 932666, [ + new Benchmark('RayTrace', renderScene) +]); + + +// Create dummy objects if we're not running in a browser. +if (typeof document == 'undefined') { + document = { }; + window = { opera: null }; + navigator = { userAgent: null, appVersion: "" }; +} + + +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ + + +/* Prototype JavaScript framework, version 1.5.0 + * (c) 2005-2007 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://prototype.conio.net/ + * +/*--------------------------------------------------------------------------*/ + +//-------------------- +var Prototype = { + Version: '1.5.0', + BrowserFeatures: { + XPath: !!document.evaluate + }, + + ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', + emptyFunction: function() {}, + K: function(x) { return x } +} + +var Class = { + create: function() { + return function() { + this.initialize.apply(this, arguments); + } + } +} + +var Abstract = new Object(); + +Object.extend = function(destination, source) { + for (var property in source) { + destination[property] = source[property]; + } + return destination; +} + +Object.extend(Object, { + inspect: function(object) { + try { + if (object === undefined) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : object.toString(); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + }, + + keys: function(object) { + var keys = []; + for (var property in object) + keys.push(property); + return keys; + }, + + values: function(object) { + var values = []; + for (var property in object) + values.push(object[property]); + return values; + }, + + clone: function(object) { + return Object.extend({}, object); + } +}); + +Function.prototype.bind = function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } +} + +Function.prototype.bindAsEventListener = function(object) { + var __method = this, args = $A(arguments), object = args.shift(); + return function(event) { + return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments))); + } +} + +Object.extend(Number.prototype, { + toColorPart: function() { + var digits = this.toString(16); + if (this < 16) return '0' + digits; + return digits; + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + } +}); + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) {} + } + + return returnValue; + } +} + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create(); +PeriodicalExecuter.prototype = { + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.callback(this); + } finally { + this.currentlyExecuting = false; + } + } + } +} +String.interpret = function(value){ + return value == null ? '' : String(value); +} + +Object.extend(String.prototype, { + gsub: function(pattern, replacement) { + var result = '', source = this, match; + replacement = arguments.callee.prepareReplacement(replacement); + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + }, + + sub: function(pattern, replacement, count) { + replacement = this.gsub.prepareReplacement(replacement); + count = count === undefined ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + }, + + scan: function(pattern, iterator) { + this.gsub(pattern, iterator); + return this; + }, + + truncate: function(length, truncation) { + length = length || 30; + truncation = truncation === undefined ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : this; + }, + + strip: function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + }, + + stripTags: function() { + return this.replace(/<\/?[^>]+>/gi, ''); + }, + + stripScripts: function() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + }, + + extractScripts: function() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + }, + + evalScripts: function() { + return this.extractScripts().map(function(script) { return eval(script) }); + }, + + escapeHTML: function() { + var div = document.createElement('div'); + var text = document.createTextNode(this); + div.appendChild(text); + return div.innerHTML; + }, + + unescapeHTML: function() { + var div = document.createElement('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? (div.childNodes.length > 1 ? + $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) : + div.childNodes[0].nodeValue) : ''; + }, + + toQueryParams: function(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return {}; + + return match[1].split(separator || '&').inject({}, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var name = decodeURIComponent(pair[0]); + var value = pair[1] ? decodeURIComponent(pair[1]) : undefined; + + if (hash[name] !== undefined) { + if (hash[name].constructor != Array) + hash[name] = [hash[name]]; + if (value) hash[name].push(value); + } + else hash[name] = value; + } + return hash; + }); + }, + + toArray: function() { + return this.split(''); + }, + + succ: function() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + }, + + camelize: function() { + var parts = this.split('-'), len = parts.length; + if (len == 1) return parts[0]; + + var camelized = this.charAt(0) == '-' + ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) + : parts[0]; + + for (var i = 1; i < len; i++) + camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); + + return camelized; + }, + + capitalize: function(){ + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + }, + + underscore: function() { + return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); + }, + + dasherize: function() { + return this.gsub(/_/,'-'); + }, + + inspect: function(useDoubleQuotes) { + var escapedString = this.replace(/\\/g, '\\\\'); + if (useDoubleQuotes) + return '"' + escapedString.replace(/"/g, '\\"') + '"'; + else + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + } +}); + +String.prototype.gsub.prepareReplacement = function(replacement) { + if (typeof replacement == 'function') return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; +} + +String.prototype.parseQuery = String.prototype.toQueryParams; + +var Template = Class.create(); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; +Template.prototype = { + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + return this.template.gsub(this.pattern, function(match) { + var before = match[1]; + if (before == '\\') return match[2]; + return before + String.interpret(object[match[3]]); + }); + } +} + +var $break = new Object(); +var $continue = new Object(); + +var Enumerable = { + each: function(iterator) { + var index = 0; + try { + this._each(function(value) { + try { + iterator(value, index++); + } catch (e) { + if (e != $continue) throw e; + } + }); + } catch (e) { + if (e != $break) throw e; + } + return this; + }, + + eachSlice: function(number, iterator) { + var index = -number, slices = [], array = this.toArray(); + while ((index += number) < array.length) + slices.push(array.slice(index, index+number)); + return slices.map(iterator); + }, + + all: function(iterator) { + var result = true; + this.each(function(value, index) { + result = result && !!(iterator || Prototype.K)(value, index); + if (!result) throw $break; + }); + return result; + }, + + any: function(iterator) { + var result = false; + this.each(function(value, index) { + if (result = !!(iterator || Prototype.K)(value, index)) + throw $break; + }); + return result; + }, + + collect: function(iterator) { + var results = []; + this.each(function(value, index) { + results.push((iterator || Prototype.K)(value, index)); + }); + return results; + }, + + detect: function(iterator) { + var result; + this.each(function(value, index) { + if (iterator(value, index)) { + result = value; + throw $break; + } + }); + return result; + }, + + findAll: function(iterator) { + var results = []; + this.each(function(value, index) { + if (iterator(value, index)) + results.push(value); + }); + return results; + }, + + grep: function(pattern, iterator) { + var results = []; + this.each(function(value, index) { + var stringValue = value.toString(); + if (stringValue.match(pattern)) + results.push((iterator || Prototype.K)(value, index)); + }) + return results; + }, + + include: function(object) { + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + }, + + inGroupsOf: function(number, fillWith) { + fillWith = fillWith === undefined ? null : fillWith; + return this.eachSlice(number, function(slice) { + while(slice.length < number) slice.push(fillWith); + return slice; + }); + }, + + inject: function(memo, iterator) { + this.each(function(value, index) { + memo = iterator(memo, value, index); + }); + return memo; + }, + + invoke: function(method) { + var args = $A(arguments).slice(1); + return this.map(function(value) { + return value[method].apply(value, args); + }); + }, + + max: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (result == undefined || value >= result) + result = value; + }); + return result; + }, + + min: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (result == undefined || value < result) + result = value; + }); + return result; + }, + + partition: function(iterator) { + var trues = [], falses = []; + this.each(function(value, index) { + ((iterator || Prototype.K)(value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + }, + + pluck: function(property) { + var results = []; + this.each(function(value, index) { + results.push(value[property]); + }); + return results; + }, + + reject: function(iterator) { + var results = []; + this.each(function(value, index) { + if (!iterator(value, index)) + results.push(value); + }); + return results; + }, + + sortBy: function(iterator) { + return this.map(function(value, index) { + return {value: value, criteria: iterator(value, index)}; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + }, + + toArray: function() { + return this.map(); + }, + + zip: function() { + var iterator = Prototype.K, args = $A(arguments); + if (typeof args.last() == 'function') + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + }, + + size: function() { + return this.toArray().length; + }, + + inspect: function() { + return '#'; + } +} + +Object.extend(Enumerable, { + map: Enumerable.collect, + find: Enumerable.detect, + select: Enumerable.findAll, + member: Enumerable.include, + entries: Enumerable.toArray +}); +var $A = Array.from = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) { + return iterable.toArray(); + } else { + var results = []; + for (var i = 0, length = iterable.length; i < length; i++) + results.push(iterable[i]); + return results; + } +} + +Object.extend(Array.prototype, Enumerable); + +if (!Array.prototype._reverse) + Array.prototype._reverse = Array.prototype.reverse; + +Object.extend(Array.prototype, { + _each: function(iterator) { + for (var i = 0, length = this.length; i < length; i++) + iterator(this[i]); + }, + + clear: function() { + this.length = 0; + return this; + }, + + first: function() { + return this[0]; + }, + + last: function() { + return this[this.length - 1]; + }, + + compact: function() { + return this.select(function(value) { + return value != null; + }); + }, + + flatten: function() { + return this.inject([], function(array, value) { + return array.concat(value && value.constructor == Array ? + value.flatten() : [value]); + }); + }, + + without: function() { + var values = $A(arguments); + return this.select(function(value) { + return !values.include(value); + }); + }, + + indexOf: function(object) { + for (var i = 0, length = this.length; i < length; i++) + if (this[i] == object) return i; + return -1; + }, + + reverse: function(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + }, + + reduce: function() { + return this.length > 1 ? this : this[0]; + }, + + uniq: function() { + return this.inject([], function(array, value) { + return array.include(value) ? array : array.concat([value]); + }); + }, + + clone: function() { + return [].concat(this); + }, + + size: function() { + return this.length; + }, + + inspect: function() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } +}); + +Array.prototype.toArray = Array.prototype.clone; + +function $w(string){ + string = string.strip(); + return string ? string.split(/\s+/) : []; +} + +if(window.opera){ + Array.prototype.concat = function(){ + var array = []; + for(var i = 0, length = this.length; i < length; i++) array.push(this[i]); + for(var i = 0, length = arguments.length; i < length; i++) { + if(arguments[i].constructor == Array) { + for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) + array.push(arguments[i][j]); + } else { + array.push(arguments[i]); + } + } + return array; + } +} +var Hash = function(obj) { + Object.extend(this, obj || {}); +}; + +Object.extend(Hash, { + toQueryString: function(obj) { + var parts = []; + + this.prototype._each.call(obj, function(pair) { + if (!pair.key) return; + + if (pair.value && pair.value.constructor == Array) { + var values = pair.value.compact(); + if (values.length < 2) pair.value = values.reduce(); + else { + key = encodeURIComponent(pair.key); + values.each(function(value) { + value = value != undefined ? encodeURIComponent(value) : ''; + parts.push(key + '=' + encodeURIComponent(value)); + }); + return; + } + } + if (pair.value == undefined) pair[1] = ''; + parts.push(pair.map(encodeURIComponent).join('=')); + }); + + return parts.join('&'); + } +}); + +Object.extend(Hash.prototype, Enumerable); +Object.extend(Hash.prototype, { + _each: function(iterator) { + for (var key in this) { + var value = this[key]; + if (value && value == Hash.prototype[key]) continue; + + var pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + merge: function(hash) { + return $H(hash).inject(this, function(mergedHash, pair) { + mergedHash[pair.key] = pair.value; + return mergedHash; + }); + }, + + remove: function() { + var result; + for(var i = 0, length = arguments.length; i < length; i++) { + var value = this[arguments[i]]; + if (value !== undefined){ + if (result === undefined) result = value; + else { + if (result.constructor != Array) result = [result]; + result.push(value) + } + } + delete this[arguments[i]]; + } + return result; + }, + + toQueryString: function() { + return Hash.toQueryString(this); + }, + + inspect: function() { + return '#'; + } +}); + +function $H(object) { + if (object && object.constructor == Hash) return object; + return new Hash(object); +}; +ObjectRange = Class.create(); +Object.extend(ObjectRange.prototype, Enumerable); +Object.extend(ObjectRange.prototype, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + }, + + include: function(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } +}); + +var $R = function(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +} + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (typeof responder[callback] == 'function') { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) {} + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { + Ajax.activeRequestCount++; + }, + onComplete: function() { + Ajax.activeRequestCount--; + } +}); + +Ajax.Base = function() {}; +Ajax.Base.prototype = { + setOptions: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '' + } + Object.extend(this.options, options || {}); + + this.options.method = this.options.method.toLowerCase(); + if (typeof this.options.parameters == 'string') + this.options.parameters = this.options.parameters.toQueryParams(); + } +} + +Ajax.Request = Class.create(); +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Request.prototype = Object.extend(new Ajax.Base(), { + _complete: false, + + initialize: function(url, options) { + this.transport = Ajax.getTransport(); + this.setOptions(options); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = this.options.parameters; + + if (!['get', 'post'].include(this.method)) { + // simulate other verbs over post + params['_method'] = this.method; + this.method = 'post'; + } + + params = Hash.toQueryString(params); + if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_=' + + // when GET, append parameters to URL + if (this.method == 'get' && params) + this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params; + + try { + Ajax.Responders.dispatch('onCreate', this, this.transport); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) + setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + var body = this.method == 'post' ? (this.options.postBody || params) : null; + + this.transport.send(body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + // user-defined headers + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (typeof extras.push == 'function') + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + return !this.transport.status + || (this.transport.status >= 200 && this.transport.status < 300); + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState]; + var transport = this.transport, json = this.evalJSON(); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + this.transport.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(transport, json); + } catch (e) { + this.dispatchException(e); + } + + if ((this.getHeader('Content-type') || 'text/javascript').strip(). + match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(transport, json); + Ajax.Responders.dispatch('on' + state, this, transport, json); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + // avoid memory leak in MSIE: clean up + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name); + } catch (e) { return null } + }, + + evalJSON: function() { + try { + var json = this.getHeader('X-JSON'); + return json ? eval('(' + json + ')') : null; + } catch (e) { return null } + }, + + evalResponse: function() { + try { + return eval(this.transport.responseText); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Updater = Class.create(); + +Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { + initialize: function(container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + } + + this.transport = Ajax.getTransport(); + this.setOptions(options); + + var onComplete = this.options.onComplete || Prototype.emptyFunction; + this.options.onComplete = (function(transport, param) { + this.updateContent(); + onComplete(transport, param); + }).bind(this); + + this.request(url); + }, + + updateContent: function() { + var receiver = this.container[this.success() ? 'success' : 'failure']; + var response = this.transport.responseText; + + if (!this.options.evalScripts) response = response.stripScripts(); + + if (receiver = $(receiver)) { + if (this.options.insertion) + new this.options.insertion(receiver, response); + else + receiver.update(response); + } + + if (this.success()) { + if (this.onComplete) + setTimeout(this.onComplete.bind(this), 10); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(); +Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { + initialize: function(container, url, options) { + this.setOptions(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = {}; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(request) { + if (this.options.decay) { + this.decay = (request.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = request.responseText; + } + this.timer = setTimeout(this.onTimerEvent.bind(this), + this.decay * this.frequency * 1000); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (typeof element == 'string') + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(query.snapshotItem(i)); + return results; + }; +} + +document.getElementsByClassName = function(className, parentElement) { + if (Prototype.BrowserFeatures.XPath) { + var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]"; + return document._getElementsByXPath(q, parentElement); + } else { + var children = ($(parentElement) || document.body).getElementsByTagName('*'); + var elements = [], child; + for (var i = 0, length = children.length; i < length; i++) { + child = children[i]; + if (Element.hasClassName(child, className)) + elements.push(Element.extend(child)); + } + return elements; + } +}; + +/*--------------------------------------------------------------------------*/ + +if (!window.Element) + var Element = new Object(); + +Element.extend = function(element) { + if (!element || _nativeExtensions || element.nodeType == 3) return element; + + if (!element._extended && element.tagName && element != window) { + var methods = Object.clone(Element.Methods), cache = Element.extend.cache; + + if (element.tagName == 'FORM') + Object.extend(methods, Form.Methods); + if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName)) + Object.extend(methods, Form.Element.Methods); + + Object.extend(methods, Element.Methods.Simulated); + + for (var property in methods) { + var value = methods[property]; + if (typeof value == 'function' && !(property in element)) + element[property] = cache.findOrStore(value); + } + } + + element._extended = true; + return element; +}; + +Element.extend.cache = { + findOrStore: function(value) { + return this[value] = this[value] || function() { + return value.apply(null, [this].concat($A(arguments))); + } + } +}; + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + hide: function(element) { + $(element).style.display = 'none'; + return element; + }, + + show: function(element) { + $(element).style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: function(element, html) { + html = typeof html == 'undefined' ? '' : html.toString(); + $(element).innerHTML = html.stripScripts(); + setTimeout(function() {html.evalScripts()}, 10); + return element; + }, + + replace: function(element, html) { + element = $(element); + html = typeof html == 'undefined' ? '' : html.toString(); + if (element.outerHTML) { + element.outerHTML = html.stripScripts(); + } else { + var range = element.ownerDocument.createRange(); + range.selectNodeContents(element); + element.parentNode.replaceChild( + range.createContextualFragment(html.stripScripts()), element); + } + setTimeout(function() {html.evalScripts()}, 10); + return element; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), attribute = pair.last(); + var value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property) { + element = $(element); + var elements = []; + while (element = element[property]) + if (element.nodeType == 1) + elements.push(Element.extend(element)); + return elements; + }, + + ancestors: function(element) { + return $(element).recursivelyCollect('parentNode'); + }, + + descendants: function(element) { + return $A($(element).getElementsByTagName('*')); + }, + + immediateDescendants: function(element) { + if (!(element = $(element).firstChild)) return []; + while (element && element.nodeType != 1) element = element.nextSibling; + if (element) return [element].concat($(element).nextSiblings()); + return []; + }, + + previousSiblings: function(element) { + return $(element).recursivelyCollect('previousSibling'); + }, + + nextSiblings: function(element) { + return $(element).recursivelyCollect('nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return element.previousSiblings().reverse().concat(element.nextSiblings()); + }, + + match: function(element, selector) { + if (typeof selector == 'string') + selector = new Selector(selector); + return selector.match($(element)); + }, + + up: function(element, expression, index) { + return Selector.findElement($(element).ancestors(), expression, index); + }, + + down: function(element, expression, index) { + return Selector.findElement($(element).descendants(), expression, index); + }, + + previous: function(element, expression, index) { + return Selector.findElement($(element).previousSiblings(), expression, index); + }, + + next: function(element, expression, index) { + return Selector.findElement($(element).nextSiblings(), expression, index); + }, + + getElementsBySelector: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element, args); + }, + + getElementsByClassName: function(element, className) { + return document.getElementsByClassName(className, element); + }, + + readAttribute: function(element, name) { + element = $(element); + if (document.all && !window.opera) { + var t = Element._attributeTranslations; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + var attribute = element.attributes[name]; + if(attribute) return attribute.nodeValue; + } + return element.getAttribute(name); + }, + + getHeight: function(element) { + return $(element).getDimensions().height; + }, + + getWidth: function(element) { + return $(element).getDimensions().width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + if (elementClassName.length == 0) return false; + if (elementClassName == className || + elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) + return true; + return false; + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element).add(className); + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element).remove(className); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className); + return element; + }, + + observe: function() { + Event.observe.apply(Event, arguments); + return $A(arguments).first(); + }, + + stopObserving: function() { + Event.stopObserving.apply(Event, arguments); + return $A(arguments).first(); + }, + + // removes whitespace-only text node children + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.match(/^\s*$/); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + while (element = element.parentNode) + if (element == ancestor) return true; + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = Position.cumulativeOffset(element); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + if (['float','cssFloat'].include(style)) + style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat'); + style = style.camelize(); + var value = element.style[style]; + if (!value) { + if (document.defaultView && document.defaultView.getComputedStyle) { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } else if (element.currentStyle) { + value = element.currentStyle[style]; + } + } + + if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none')) + value = element['offset'+style.capitalize()] + 'px'; + + if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) + if (Element.getStyle(element, 'position') == 'static') value = 'auto'; + if(style == 'opacity') { + if(value) return parseFloat(value); + if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if(value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + return value == 'auto' ? null : value; + }, + + setStyle: function(element, style) { + element = $(element); + for (var name in style) { + var value = style[name]; + if(name == 'opacity') { + if (value == 1) { + value = (/Gecko/.test(navigator.userAgent) && + !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0; + if(/MSIE/.test(navigator.userAgent) && !window.opera) + element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,''); + } else if(value == '') { + if(/MSIE/.test(navigator.userAgent) && !window.opera) + element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,''); + } else { + if(value < 0.00001) value = 0; + if(/MSIE/.test(navigator.userAgent) && !window.opera) + element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') + + 'alpha(opacity='+value*100+')'; + } + } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat'; + element.style[name.camelize()] = value; + } + return element; + }, + + getDimensions: function(element) { + element = $(element); + var display = $(element).getStyle('display'); + if (display != 'none' && display != null) // Safari bug + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + var originalDisplay = els.display; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = 'block'; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = originalDisplay; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (window.opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = element.style.overflow || 'auto'; + if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + } +}; + +Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf}); + +Element._attributeTranslations = {}; + +Element._attributeTranslations.names = { + colspan: "colSpan", + rowspan: "rowSpan", + valign: "vAlign", + datetime: "dateTime", + accesskey: "accessKey", + tabindex: "tabIndex", + enctype: "encType", + maxlength: "maxLength", + readonly: "readOnly", + longdesc: "longDesc" +}; + +Element._attributeTranslations.values = { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + + title: function(element) { + var node = element.getAttributeNode('title'); + return node.specified ? node.nodeValue : null; + } +}; + +Object.extend(Element._attributeTranslations.values, { + href: Element._attributeTranslations.values._getAttr, + src: Element._attributeTranslations.values._getAttr, + disabled: Element._attributeTranslations.values._flag, + checked: Element._attributeTranslations.values._flag, + readonly: Element._attributeTranslations.values._flag, + multiple: Element._attributeTranslations.values._flag +}); + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + var t = Element._attributeTranslations; + attribute = t.names[attribute] || attribute; + return $(element).getAttributeNode(attribute).specified; + } +}; + +// IE is missing .innerHTML support for TABLE-related elements +if (document.all && !window.opera){ + Element.Methods.update = function(element, html) { + element = $(element); + html = typeof html == 'undefined' ? '' : html.toString(); + var tagName = element.tagName.toUpperCase(); + if (['THEAD','TBODY','TR','TD'].include(tagName)) { + var div = document.createElement('div'); + switch (tagName) { + case 'THEAD': + case 'TBODY': + div.innerHTML = '' + html.stripScripts() + '
'; + depth = 2; + break; + case 'TR': + div.innerHTML = '' + html.stripScripts() + '
'; + depth = 3; + break; + case 'TD': + div.innerHTML = '
' + html.stripScripts() + '
'; + depth = 4; + } + $A(element.childNodes).each(function(node){ + element.removeChild(node) + }); + depth.times(function(){ div = div.firstChild }); + + $A(div.childNodes).each( + function(node){ element.appendChild(node) }); + } else { + element.innerHTML = html.stripScripts(); + } + setTimeout(function() {html.evalScripts()}, 10); + return element; + } +}; + +Object.extend(Element, Element.Methods); + +var _nativeExtensions = false; + +if(/Konqueror|Safari|KHTML/.test(navigator.userAgent)) + ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) { + var className = 'HTML' + tag + 'Element'; + if(window[className]) return; + var klass = window[className] = {}; + klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__; + }); + +Element.addMethods = function(methods) { + Object.extend(Element.Methods, methods || {}); + + function copy(methods, destination, onlyIfAbsent) { + onlyIfAbsent = onlyIfAbsent || false; + var cache = Element.extend.cache; + for (var property in methods) { + var value = methods[property]; + if (!onlyIfAbsent || !(property in destination)) + destination[property] = cache.findOrStore(value); + } + } + + if (typeof HTMLElement != 'undefined') { + copy(Element.Methods, HTMLElement.prototype); + copy(Element.Methods.Simulated, HTMLElement.prototype, true); + copy(Form.Methods, HTMLFormElement.prototype); + [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) { + copy(Form.Element.Methods, klass.prototype); + }); + _nativeExtensions = true; + } +} + +var Toggle = new Object(); +Toggle.display = Element.toggle; + +/*--------------------------------------------------------------------------*/ + +Abstract.Insertion = function(adjacency) { + this.adjacency = adjacency; +} + +Abstract.Insertion.prototype = { + initialize: function(element, content) { + this.element = $(element); + this.content = content.stripScripts(); + + if (this.adjacency && this.element.insertAdjacentHTML) { + try { + this.element.insertAdjacentHTML(this.adjacency, this.content); + } catch (e) { + var tagName = this.element.tagName.toUpperCase(); + if (['TBODY', 'TR'].include(tagName)) { + this.insertContent(this.contentFromAnonymousTable()); + } else { + throw e; + } + } + } else { + this.range = this.element.ownerDocument.createRange(); + if (this.initializeRange) this.initializeRange(); + this.insertContent([this.range.createContextualFragment(this.content)]); + } + + setTimeout(function() {content.evalScripts()}, 10); + }, + + contentFromAnonymousTable: function() { + var div = document.createElement('div'); + div.innerHTML = '' + this.content + '
'; + return $A(div.childNodes[0].childNodes[0].childNodes); + } +} + +var Insertion = new Object(); + +Insertion.Before = Class.create(); +Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { + initializeRange: function() { + this.range.setStartBefore(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, this.element); + }).bind(this)); + } +}); + +Insertion.Top = Class.create(); +Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(true); + }, + + insertContent: function(fragments) { + fragments.reverse(false).each((function(fragment) { + this.element.insertBefore(fragment, this.element.firstChild); + }).bind(this)); + } +}); + +Insertion.Bottom = Class.create(); +Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.appendChild(fragment); + }).bind(this)); + } +}); + +Insertion.After = Class.create(); +Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { + initializeRange: function() { + this.range.setStartAfter(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, + this.element.nextSibling); + }).bind(this)); + } +}); + +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set($A(this).concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set($A(this).without(classNameToRemove).join(' ')); + }, + + toString: function() { + return $A(this).join(' '); + } +}; + +Object.extend(Element.ClassNames.prototype, Enumerable); +var Selector = Class.create(); +Selector.prototype = { + initialize: function(expression) { + this.params = {classNames: []}; + this.expression = expression.toString().strip(); + this.parseExpression(); + this.compileMatcher(); + }, + + parseExpression: function() { + function abort(message) { throw 'Parse error in selector: ' + message; } + + if (this.expression == '') abort('empty expression'); + + var params = this.params, expr = this.expression, match, modifier, clause, rest; + while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) { + params.attributes = params.attributes || []; + params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''}); + expr = match[1]; + } + + if (expr == '*') return this.params.wildcard = true; + + while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) { + modifier = match[1], clause = match[2], rest = match[3]; + switch (modifier) { + case '#': params.id = clause; break; + case '.': params.classNames.push(clause); break; + case '': + case undefined: params.tagName = clause.toUpperCase(); break; + default: abort(expr.inspect()); + } + expr = rest; + } + + if (expr.length > 0) abort(expr.inspect()); + }, + + buildMatchExpression: function() { + var params = this.params, conditions = [], clause; + + if (params.wildcard) + conditions.push('true'); + if (clause = params.id) + conditions.push('element.readAttribute("id") == ' + clause.inspect()); + if (clause = params.tagName) + conditions.push('element.tagName.toUpperCase() == ' + clause.inspect()); + if ((clause = params.classNames).length > 0) + for (var i = 0, length = clause.length; i < length; i++) + conditions.push('element.hasClassName(' + clause[i].inspect() + ')'); + if (clause = params.attributes) { + clause.each(function(attribute) { + var value = 'element.readAttribute(' + attribute.name.inspect() + ')'; + var splitValueBy = function(delimiter) { + return value + ' && ' + value + '.split(' + delimiter.inspect() + ')'; + } + + switch (attribute.operator) { + case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break; + case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break; + case '|=': conditions.push( + splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect() + ); break; + case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break; + case '': + case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break; + default: throw 'Unknown operator ' + attribute.operator + ' in selector'; + } + }); + } + + return conditions.join(' && '); + }, + + compileMatcher: function() { + this.match = new Function('element', 'if (!element.tagName) return false; \ + element = $(element); \ + return ' + this.buildMatchExpression()); + }, + + findElements: function(scope) { + var element; + + if (element = $(this.params.id)) + if (this.match(element)) + if (!scope || Element.childOf(element, scope)) + return [element]; + + scope = (scope || document).getElementsByTagName(this.params.tagName || '*'); + + var results = []; + for (var i = 0, length = scope.length; i < length; i++) + if (this.match(element = scope[i])) + results.push(Element.extend(element)); + + return results; + }, + + toString: function() { + return this.expression; + } +} + +Object.extend(Selector, { + matchElements: function(elements, expression) { + var selector = new Selector(expression); + return elements.select(selector.match.bind(selector)).map(Element.extend); + }, + + findElement: function(elements, expression, index) { + if (typeof expression == 'number') index = expression, expression = false; + return Selector.matchElements(elements, expression || '*')[index || 0]; + }, + + findChildElements: function(element, expressions) { + return expressions.map(function(expression) { + return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) { + var selector = new Selector(expr); + return results.inject([], function(elements, result) { + return elements.concat(selector.findElements(result || element)); + }); + }); + }).flatten(); + } +}); + +function $$() { + return Selector.findChildElements(document, $A(arguments)); +} +var Form = { + reset: function(form) { + $(form).reset(); + return form; + }, + + serializeElements: function(elements, getHash) { + var data = elements.inject({}, function(result, element) { + if (!element.disabled && element.name) { + var key = element.name, value = $(element).getValue(); + if (value != undefined) { + if (result[key]) { + if (result[key].constructor != Array) result[key] = [result[key]]; + result[key].push(value); + } + else result[key] = value; + } + } + return result; + }); + + return getHash ? data : Hash.toQueryString(data); + } +}; + +Form.Methods = { + serialize: function(form, getHash) { + return Form.serializeElements(Form.getElements(form), getHash); + }, + + getElements: function(form) { + return $A($(form).getElementsByTagName('*')).inject([], + function(elements, child) { + if (Form.Element.Serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + } + ); + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + form.getElements().each(function(element) { + element.blur(); + element.disabled = 'true'; + }); + return form; + }, + + enable: function(form) { + form = $(form); + form.getElements().each(function(element) { + element.disabled = ''; + }); + return form; + }, + + findFirstElement: function(form) { + return $(form).getElements().find(function(element) { + return element.type != 'hidden' && !element.disabled && + ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + form.findFirstElement().activate(); + return form; + } +} + +Object.extend(Form, Form.Methods); + +/*--------------------------------------------------------------------------*/ + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +} + +Form.Element.Methods = { + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = {}; + pair[element.name] = value; + return Hash.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + element.focus(); + if (element.select && ( element.tagName.toLowerCase() != 'input' || + !['button', 'reset', 'submit'].include(element.type) ) ) + element.select(); + return element; + }, + + disable: function(element) { + element = $(element); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.blur(); + element.disabled = false; + return element; + } +} + +Object.extend(Form.Element, Form.Element.Methods); +var Field = Form.Element; +var $F = Form.Element.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = { + input: function(element) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element); + default: + return Form.Element.Serializers.textarea(element); + } + }, + + inputSelector: function(element) { + return element.checked ? element.value : null; + }, + + textarea: function(element) { + return element.value; + }, + + select: function(element) { + return this[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + }, + + selectOne: function(element) { + var index = element.selectedIndex; + return index >= 0 ? this.optionValue(element.options[index]) : null; + }, + + selectMany: function(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(this.optionValue(opt)); + } + return values; + }, + + optionValue: function(opt) { + // extend element because hasAttribute may not be native + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; + } +} + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = function() {} +Abstract.TimedObserver.prototype = { + initialize: function(element, frequency, callback) { + this.frequency = frequency; + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + var value = this.getValue(); + var changed = ('string' == typeof this.lastValue && 'string' == typeof value + ? this.lastValue != value : String(this.lastValue) != String(value)); + if (changed) { + this.callback(this.element, value); + this.lastValue = value; + } + } +} + +Form.Element.Observer = Class.create(); +Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(); +Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = function() {} +Abstract.EventObserver.prototype = { + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback.bind(this)); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +} + +Form.Element.EventObserver = Class.create(); +Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(); +Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); +if (!window.Event) { + var Event = new Object(); +} + +Object.extend(Event, { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + + element: function(event) { + return event.target || event.srcElement; + }, + + isLeftClick: function(event) { + return (((event.which) && (event.which == 1)) || + ((event.button) && (event.button == 1))); + }, + + pointerX: function(event) { + return event.pageX || (event.clientX + + (document.documentElement.scrollLeft || document.body.scrollLeft)); + }, + + pointerY: function(event) { + return event.pageY || (event.clientY + + (document.documentElement.scrollTop || document.body.scrollTop)); + }, + + stop: function(event) { + if (event.preventDefault) { + event.preventDefault(); + event.stopPropagation(); + } else { + event.returnValue = false; + event.cancelBubble = true; + } + }, + + // find the first node with the given tagName, starting from the + // node the event was triggered on; traverses the DOM upwards + findElement: function(event, tagName) { + var element = Event.element(event); + while (element.parentNode && (!element.tagName || + (element.tagName.toUpperCase() != tagName.toUpperCase()))) + element = element.parentNode; + return element; + }, + + observers: false, + + _observeAndCache: function(element, name, observer, useCapture) { + if (!this.observers) this.observers = []; + if (element.addEventListener) { + this.observers.push([element, name, observer, useCapture]); + element.addEventListener(name, observer, useCapture); + } else if (element.attachEvent) { + this.observers.push([element, name, observer, useCapture]); + element.attachEvent('on' + name, observer); + } + }, + + unloadCache: function() { + if (!Event.observers) return; + for (var i = 0, length = Event.observers.length; i < length; i++) { + Event.stopObserving.apply(this, Event.observers[i]); + Event.observers[i][0] = null; + } + Event.observers = false; + }, + + observe: function(element, name, observer, useCapture) { + element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.attachEvent)) + name = 'keydown'; + + Event._observeAndCache(element, name, observer, useCapture); + }, + + stopObserving: function(element, name, observer, useCapture) { + element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.detachEvent)) + name = 'keydown'; + + if (element.removeEventListener) { + element.removeEventListener(name, observer, useCapture); + } else if (element.detachEvent) { + try { + element.detachEvent('on' + name, observer); + } catch (e) {} + } + } +}); + +/* prevent memory leaks in IE */ +if (navigator.appVersion.match(/\bMSIE\b/)) + Event.observe(window, 'unload', Event.unloadCache, false); +var Position = { + // set to true if needed, warning: firefox performance problems + // NOT neeeded for page scrolling, only if draggable contained in + // scrollable elements + includeScrollOffsets: false, + + // must be called before calling withinIncludingScrolloffset, every time the + // page is scrolled + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + realOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return [valueL, valueT]; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return [valueL, valueT]; + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if(element.tagName=='BODY') break; + var p = Element.getStyle(element, 'position'); + if (p == 'relative' || p == 'absolute') break; + } + } while (element); + return [valueL, valueT]; + }, + + offsetParent: function(element) { + if (element.offsetParent) return element.offsetParent; + if (element == document.body) return element; + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return element; + + return document.body; + }, + + // caches x/y coordinate pair to use with overlap + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = this.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = this.realOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = this.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + // within must be called directly before + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + page: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent==document.body) + if (Element.getStyle(element,'position')=='absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + if (!window.opera || element.tagName=='BODY') { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + + return [valueL, valueT]; + }, + + clone: function(source, target) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || {}) + + // find page position of source + source = $(source); + var p = Position.page(source); + + // find coordinate system to use + target = $(target); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(target,'position') == 'absolute') { + parent = Position.offsetParent(target); + delta = Position.page(parent); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if(options.setWidth) target.style.width = source.offsetWidth + 'px'; + if(options.setHeight) target.style.height = source.offsetHeight + 'px'; + }, + + absolutize: function(element) { + element = $(element); + if (element.style.position == 'absolute') return; + Position.prepare(); + + var offsets = Position.positionedOffset(element); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.width = width + 'px'; + element.style.height = height + 'px'; + }, + + relativize: function(element) { + element = $(element); + if (element.style.position == 'relative') return; + Position.prepare(); + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + } +} + +// Safari returns margins on body which is incorrect if the child is absolutely +// positioned. For performance reasons, redefine Position.cumulativeOffset for +// KHTML/WebKit only. +if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { + Position.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return [valueL, valueT]; + } +} + +Element.addMethods(); + + +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ + +// The rest of this file is the actual ray tracer written by Adam +// Burmister. It's a concatenation of the following files: +// +// flog/color.js +// flog/light.js +// flog/vector.js +// flog/ray.js +// flog/scene.js +// flog/material/basematerial.js +// flog/material/solid.js +// flog/material/chessboard.js +// flog/shape/baseshape.js +// flog/shape/sphere.js +// flog/shape/plane.js +// flog/intersectioninfo.js +// flog/camera.js +// flog/background.js +// flog/engine.js + + +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Color = Class.create(); + +Flog.RayTracer.Color.prototype = { + red : 0.0, + green : 0.0, + blue : 0.0, + + initialize : function(r, g, b) { + if(!r) r = 0.0; + if(!g) g = 0.0; + if(!b) b = 0.0; + + this.red = r; + this.green = g; + this.blue = b; + }, + + add : function(c1, c2){ + var result = new Flog.RayTracer.Color(0,0,0); + + result.red = c1.red + c2.red; + result.green = c1.green + c2.green; + result.blue = c1.blue + c2.blue; + + return result; + }, + + addScalar: function(c1, s){ + var result = new Flog.RayTracer.Color(0,0,0); + + result.red = c1.red + s; + result.green = c1.green + s; + result.blue = c1.blue + s; + + result.limit(); + + return result; + }, + + subtract: function(c1, c2){ + var result = new Flog.RayTracer.Color(0,0,0); + + result.red = c1.red - c2.red; + result.green = c1.green - c2.green; + result.blue = c1.blue - c2.blue; + + return result; + }, + + multiply : function(c1, c2) { + var result = new Flog.RayTracer.Color(0,0,0); + + result.red = c1.red * c2.red; + result.green = c1.green * c2.green; + result.blue = c1.blue * c2.blue; + + return result; + }, + + multiplyScalar : function(c1, f) { + var result = new Flog.RayTracer.Color(0,0,0); + + result.red = c1.red * f; + result.green = c1.green * f; + result.blue = c1.blue * f; + + return result; + }, + + divideFactor : function(c1, f) { + var result = new Flog.RayTracer.Color(0,0,0); + + result.red = c1.red / f; + result.green = c1.green / f; + result.blue = c1.blue / f; + + return result; + }, + + limit: function(){ + this.red = (this.red > 0.0) ? ( (this.red > 1.0) ? 1.0 : this.red ) : 0.0; + this.green = (this.green > 0.0) ? ( (this.green > 1.0) ? 1.0 : this.green ) : 0.0; + this.blue = (this.blue > 0.0) ? ( (this.blue > 1.0) ? 1.0 : this.blue ) : 0.0; + }, + + distance : function(color) { + var d = Math.abs(this.red - color.red) + Math.abs(this.green - color.green) + Math.abs(this.blue - color.blue); + return d; + }, + + blend: function(c1, c2, w){ + var result = new Flog.RayTracer.Color(0,0,0); + result = Flog.RayTracer.Color.prototype.add( + Flog.RayTracer.Color.prototype.multiplyScalar(c1, 1 - w), + Flog.RayTracer.Color.prototype.multiplyScalar(c2, w) + ); + return result; + }, + + toString : function () { + var r = Math.floor(this.red*255); + var g = Math.floor(this.green*255); + var b = Math.floor(this.blue*255); + + return "rgb("+ r +","+ g +","+ b +")"; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Light = Class.create(); + +Flog.RayTracer.Light.prototype = { + position: null, + color: null, + intensity: 10.0, + + initialize : function(pos, color, intensity) { + this.position = pos; + this.color = color; + this.intensity = (intensity ? intensity : 10.0); + }, + + getIntensity: function(distance){ + if(distance >= intensity) return 0; + + return Math.pow((intensity - distance) / strength, 0.2); + }, + + toString : function () { + return 'Light [' + this.position.x + ',' + this.position.y + ',' + this.position.z + ']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Vector = Class.create(); + +Flog.RayTracer.Vector.prototype = { + x : 0.0, + y : 0.0, + z : 0.0, + + initialize : function(x, y, z) { + this.x = (x ? x : 0); + this.y = (y ? y : 0); + this.z = (z ? z : 0); + }, + + copy: function(vector){ + this.x = vector.x; + this.y = vector.y; + this.z = vector.z; + }, + + normalize : function() { + var m = this.magnitude(); + return new Flog.RayTracer.Vector(this.x / m, this.y / m, this.z / m); + }, + + magnitude : function() { + return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z)); + }, + + cross : function(w) { + return new Flog.RayTracer.Vector( + -this.z * w.y + this.y * w.z, + this.z * w.x - this.x * w.z, + -this.y * w.x + this.x * w.y); + }, + + dot : function(w) { + return this.x * w.x + this.y * w.y + this.z * w.z; + }, + + add : function(v, w) { + return new Flog.RayTracer.Vector(w.x + v.x, w.y + v.y, w.z + v.z); + }, + + subtract : function(v, w) { + if(!w || !v) throw 'Vectors must be defined [' + v + ',' + w + ']'; + return new Flog.RayTracer.Vector(v.x - w.x, v.y - w.y, v.z - w.z); + }, + + multiplyVector : function(v, w) { + return new Flog.RayTracer.Vector(v.x * w.x, v.y * w.y, v.z * w.z); + }, + + multiplyScalar : function(v, w) { + return new Flog.RayTracer.Vector(v.x * w, v.y * w, v.z * w); + }, + + toString : function () { + return 'Vector [' + this.x + ',' + this.y + ',' + this.z + ']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Ray = Class.create(); + +Flog.RayTracer.Ray.prototype = { + position : null, + direction : null, + initialize : function(pos, dir) { + this.position = pos; + this.direction = dir; + }, + + toString : function () { + return 'Ray [' + this.position + ',' + this.direction + ']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Scene = Class.create(); + +Flog.RayTracer.Scene.prototype = { + camera : null, + shapes : [], + lights : [], + background : null, + + initialize : function() { + this.camera = new Flog.RayTracer.Camera( + new Flog.RayTracer.Vector(0,0,-5), + new Flog.RayTracer.Vector(0,0,1), + new Flog.RayTracer.Vector(0,1,0) + ); + this.shapes = new Array(); + this.lights = new Array(); + this.background = new Flog.RayTracer.Background(new Flog.RayTracer.Color(0,0,0.5), 0.2); + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; +if(typeof(Flog.RayTracer.Material) == 'undefined') Flog.RayTracer.Material = {}; + +Flog.RayTracer.Material.BaseMaterial = Class.create(); + +Flog.RayTracer.Material.BaseMaterial.prototype = { + + gloss: 2.0, // [0...infinity] 0 = matt + transparency: 0.0, // 0=opaque + reflection: 0.0, // [0...infinity] 0 = no reflection + refraction: 0.50, + hasTexture: false, + + initialize : function() { + + }, + + getColor: function(u, v){ + + }, + + wrapUp: function(t){ + t = t % 2.0; + if(t < -1) t += 2.0; + if(t >= 1) t -= 2.0; + return t; + }, + + toString : function () { + return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Material.Solid = Class.create(); + +Flog.RayTracer.Material.Solid.prototype = Object.extend( + new Flog.RayTracer.Material.BaseMaterial(), { + initialize : function(color, reflection, refraction, transparency, gloss) { + this.color = color; + this.reflection = reflection; + this.transparency = transparency; + this.gloss = gloss; + this.hasTexture = false; + }, + + getColor: function(u, v){ + return this.color; + }, + + toString : function () { + return 'SolidMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']'; + } + } +); +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Material.Chessboard = Class.create(); + +Flog.RayTracer.Material.Chessboard.prototype = Object.extend( + new Flog.RayTracer.Material.BaseMaterial(), { + colorEven: null, + colorOdd: null, + density: 0.5, + + initialize : function(colorEven, colorOdd, reflection, transparency, gloss, density) { + this.colorEven = colorEven; + this.colorOdd = colorOdd; + this.reflection = reflection; + this.transparency = transparency; + this.gloss = gloss; + this.density = density; + this.hasTexture = true; + }, + + getColor: function(u, v){ + var t = this.wrapUp(u * this.density) * this.wrapUp(v * this.density); + + if(t < 0.0) + return this.colorEven; + else + return this.colorOdd; + }, + + toString : function () { + return 'ChessMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']'; + } + } +); +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; +if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {}; + +Flog.RayTracer.Shape.BaseShape = Class.create(); + +Flog.RayTracer.Shape.BaseShape.prototype = { + position: null, + material: null, + + initialize : function() { + this.position = new Vector(0,0,0); + this.material = new Flog.RayTracer.Material.SolidMaterial( + new Flog.RayTracer.Color(1,0,1), + 0, + 0, + 0 + ); + }, + + toString : function () { + return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; +if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {}; + +Flog.RayTracer.Shape.Sphere = Class.create(); + +Flog.RayTracer.Shape.Sphere.prototype = { + initialize : function(pos, radius, material) { + this.radius = radius; + this.position = pos; + this.material = material; + }, + + intersect: function(ray){ + var info = new Flog.RayTracer.IntersectionInfo(); + info.shape = this; + + var dst = Flog.RayTracer.Vector.prototype.subtract(ray.position, this.position); + + var B = dst.dot(ray.direction); + var C = dst.dot(dst) - (this.radius * this.radius); + var D = (B * B) - C; + + if(D > 0){ // intersection! + info.isHit = true; + info.distance = (-B) - Math.sqrt(D); + info.position = Flog.RayTracer.Vector.prototype.add( + ray.position, + Flog.RayTracer.Vector.prototype.multiplyScalar( + ray.direction, + info.distance + ) + ); + info.normal = Flog.RayTracer.Vector.prototype.subtract( + info.position, + this.position + ).normalize(); + + info.color = this.material.getColor(0,0); + } else { + info.isHit = false; + } + return info; + }, + + toString : function () { + return 'Sphere [position=' + this.position + ', radius=' + this.radius + ']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; +if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {}; + +Flog.RayTracer.Shape.Plane = Class.create(); + +Flog.RayTracer.Shape.Plane.prototype = { + d: 0.0, + + initialize : function(pos, d, material) { + this.position = pos; + this.d = d; + this.material = material; + }, + + intersect: function(ray){ + var info = new Flog.RayTracer.IntersectionInfo(); + + var Vd = this.position.dot(ray.direction); + if(Vd == 0) return info; // no intersection + + var t = -(this.position.dot(ray.position) + this.d) / Vd; + if(t <= 0) return info; + + info.shape = this; + info.isHit = true; + info.position = Flog.RayTracer.Vector.prototype.add( + ray.position, + Flog.RayTracer.Vector.prototype.multiplyScalar( + ray.direction, + t + ) + ); + info.normal = this.position; + info.distance = t; + + if(this.material.hasTexture){ + var vU = new Flog.RayTracer.Vector(this.position.y, this.position.z, -this.position.x); + var vV = vU.cross(this.position); + var u = info.position.dot(vU); + var v = info.position.dot(vV); + info.color = this.material.getColor(u,v); + } else { + info.color = this.material.getColor(0,0); + } + + return info; + }, + + toString : function () { + return 'Plane [' + this.position + ', d=' + this.d + ']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.IntersectionInfo = Class.create(); + +Flog.RayTracer.IntersectionInfo.prototype = { + isHit: false, + hitCount: 0, + shape: null, + position: null, + normal: null, + color: null, + distance: null, + + initialize : function() { + this.color = new Flog.RayTracer.Color(0,0,0); + }, + + toString : function () { + return 'Intersection [' + this.position + ']'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Camera = Class.create(); + +Flog.RayTracer.Camera.prototype = { + position: null, + lookAt: null, + equator: null, + up: null, + screen: null, + + initialize : function(pos, lookAt, up) { + this.position = pos; + this.lookAt = lookAt; + this.up = up; + this.equator = lookAt.normalize().cross(this.up); + this.screen = Flog.RayTracer.Vector.prototype.add(this.position, this.lookAt); + }, + + getRay: function(vx, vy){ + var pos = Flog.RayTracer.Vector.prototype.subtract( + this.screen, + Flog.RayTracer.Vector.prototype.subtract( + Flog.RayTracer.Vector.prototype.multiplyScalar(this.equator, vx), + Flog.RayTracer.Vector.prototype.multiplyScalar(this.up, vy) + ) + ); + pos.y = pos.y * -1; + var dir = Flog.RayTracer.Vector.prototype.subtract( + pos, + this.position + ); + + var ray = new Flog.RayTracer.Ray(pos, dir.normalize()); + + return ray; + }, + + toString : function () { + return 'Ray []'; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Background = Class.create(); + +Flog.RayTracer.Background.prototype = { + color : null, + ambience : 0.0, + + initialize : function(color, ambience) { + this.color = color; + this.ambience = ambience; + } +} +/* Fake a Flog.* namespace */ +if(typeof(Flog) == 'undefined') var Flog = {}; +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; + +Flog.RayTracer.Engine = Class.create(); + +Flog.RayTracer.Engine.prototype = { + canvas: null, /* 2d context we can render to */ + + initialize: function(options){ + this.options = Object.extend({ + canvasHeight: 100, + canvasWidth: 100, + pixelWidth: 2, + pixelHeight: 2, + renderDiffuse: false, + renderShadows: false, + renderHighlights: false, + renderReflections: false, + rayDepth: 2 + }, options || {}); + + this.options.canvasHeight /= this.options.pixelHeight; + this.options.canvasWidth /= this.options.pixelWidth; + + /* TODO: dynamically include other scripts */ + }, + + setPixel: function(x, y, color){ + var pxW, pxH; + pxW = this.options.pixelWidth; + pxH = this.options.pixelHeight; + + if (this.canvas) { + this.canvas.fillStyle = color.toString(); + this.canvas.fillRect (x * pxW, y * pxH, pxW, pxH); + } else { + // print(x * pxW, y * pxH, pxW, pxH); + } + }, + + renderScene: function(scene, canvas){ + /* Get canvas */ + if (canvas) { + this.canvas = canvas.getContext("2d"); + } else { + this.canvas = null; + } + + var canvasHeight = this.options.canvasHeight; + var canvasWidth = this.options.canvasWidth; + + for(var y=0; y < canvasHeight; y++){ + for(var x=0; x < canvasWidth; x++){ + var yp = y * 1.0 / canvasHeight * 2 - 1; + var xp = x * 1.0 / canvasWidth * 2 - 1; + + var ray = scene.camera.getRay(xp, yp); + + var color = this.getPixelColor(ray, scene); + + this.setPixel(x, y, color); + } + } + }, + + getPixelColor: function(ray, scene){ + var info = this.testIntersection(ray, scene, null); + if(info.isHit){ + var color = this.rayTrace(info, ray, scene, 0); + return color; + } + return scene.background.color; + }, + + testIntersection: function(ray, scene, exclude){ + var hits = 0; + var best = new Flog.RayTracer.IntersectionInfo(); + best.distance = 2000; + + for(var i=0; i= 0 && info.distance < best.distance){ + best = info; + hits++; + } + } + } + best.hitCount = hits; + return best; + }, + + getReflectionRay: function(P,N,V){ + var c1 = -N.dot(V); + var R1 = Flog.RayTracer.Vector.prototype.add( + Flog.RayTracer.Vector.prototype.multiplyScalar(N, 2*c1), + V + ); + return new Flog.RayTracer.Ray(P, R1); + }, + + rayTrace: function(info, ray, scene, depth){ + // Calc ambient + var color = Flog.RayTracer.Color.prototype.multiplyScalar(info.color, scene.background.ambience); + var oldColor = color; + var shininess = Math.pow(10, info.shape.material.gloss + 1); + + for(var i=0; i 0.0){ + color = Flog.RayTracer.Color.prototype.add( + color, + Flog.RayTracer.Color.prototype.multiply( + info.color, + Flog.RayTracer.Color.prototype.multiplyScalar( + light.color, + L + ) + ) + ); + } + } + + // The greater the depth the more accurate the colours, but + // this is exponentially (!) expensive + if(depth <= this.options.rayDepth){ + // calculate reflection ray + if(this.options.renderReflections && info.shape.material.reflection > 0) + { + var reflectionRay = this.getReflectionRay(info.position, info.normal, ray.direction); + var refl = this.testIntersection(reflectionRay, scene, info.shape); + + if (refl.isHit && refl.distance > 0){ + refl.color = this.rayTrace(refl, reflectionRay, scene, depth + 1); + } else { + refl.color = scene.background.color; + } + + color = Flog.RayTracer.Color.prototype.blend( + color, + refl.color, + info.shape.material.reflection + ); + } + + // Refraction + /* TODO */ + } + + /* Render shadows and highlights */ + + var shadowInfo = new Flog.RayTracer.IntersectionInfo(); + + if(this.options.renderShadows){ + var shadowRay = new Flog.RayTracer.Ray(info.position, v); + + shadowInfo = this.testIntersection(shadowRay, scene, info.shape); + if(shadowInfo.isHit && shadowInfo.shape != info.shape /*&& shadowInfo.shape.type != 'PLANE'*/){ + var vA = Flog.RayTracer.Color.prototype.multiplyScalar(color, 0.5); + var dB = (0.5 * Math.pow(shadowInfo.shape.material.transparency, 0.5)); + color = Flog.RayTracer.Color.prototype.addScalar(vA,dB); + } + } + + // Phong specular highlights + if(this.options.renderHighlights && !shadowInfo.isHit && info.shape.material.gloss > 0){ + var Lv = Flog.RayTracer.Vector.prototype.subtract( + info.shape.position, + light.position + ).normalize(); + + var E = Flog.RayTracer.Vector.prototype.subtract( + scene.camera.position, + info.shape.position + ).normalize(); + + var H = Flog.RayTracer.Vector.prototype.subtract( + E, + Lv + ).normalize(); + + var glossWeight = Math.pow(Math.max(info.normal.dot(H), 0), shininess); + color = Flog.RayTracer.Color.prototype.add( + Flog.RayTracer.Color.prototype.multiplyScalar(light.color, glossWeight), + color + ); + } + } + color.limit(); + return color; + } +}; + + +function renderScene(){ + var scene = new Flog.RayTracer.Scene(); + + scene.camera = new Flog.RayTracer.Camera( + new Flog.RayTracer.Vector(0, 0, -15), + new Flog.RayTracer.Vector(-0.2, 0, 5), + new Flog.RayTracer.Vector(0, 1, 0) + ); + + scene.background = new Flog.RayTracer.Background( + new Flog.RayTracer.Color(0.5, 0.5, 0.5), + 0.4 + ); + + var sphere = new Flog.RayTracer.Shape.Sphere( + new Flog.RayTracer.Vector(-1.5, 1.5, 2), + 1.5, + new Flog.RayTracer.Material.Solid( + new Flog.RayTracer.Color(0,0.5,0.5), + 0.3, + 0.0, + 0.0, + 2.0 + ) + ); + + var sphere1 = new Flog.RayTracer.Shape.Sphere( + new Flog.RayTracer.Vector(1, 0.25, 1), + 0.5, + new Flog.RayTracer.Material.Solid( + new Flog.RayTracer.Color(0.9,0.9,0.9), + 0.1, + 0.0, + 0.0, + 1.5 + ) + ); + + var plane = new Flog.RayTracer.Shape.Plane( + new Flog.RayTracer.Vector(0.1, 0.9, -0.5).normalize(), + 1.2, + new Flog.RayTracer.Material.Chessboard( + new Flog.RayTracer.Color(1,1,1), + new Flog.RayTracer.Color(0,0,0), + 0.2, + 0.0, + 1.0, + 0.7 + ) + ); + + scene.shapes.push(plane); + scene.shapes.push(sphere); + scene.shapes.push(sphere1); + + var light = new Flog.RayTracer.Light( + new Flog.RayTracer.Vector(5, 10, -1), + new Flog.RayTracer.Color(0.8, 0.8, 0.8) + ); + + var light1 = new Flog.RayTracer.Light( + new Flog.RayTracer.Vector(-3, 5, -15), + new Flog.RayTracer.Color(0.8, 0.8, 0.8), + 100 + ); + + scene.lights.push(light); + scene.lights.push(light1); + + var imageWidth = 100; // $F('imageWidth'); + var imageHeight = 100; // $F('imageHeight'); + var pixelSize = "5,5".split(','); // $F('pixelSize').split(','); + var renderDiffuse = true; // $F('renderDiffuse'); + var renderShadows = true; // $F('renderShadows'); + var renderHighlights = true; // $F('renderHighlights'); + var renderReflections = true; // $F('renderReflections'); + var rayDepth = 2;//$F('rayDepth'); + + var raytracer = new Flog.RayTracer.Engine( + { + canvasWidth: imageWidth, + canvasHeight: imageHeight, + pixelWidth: pixelSize[0], + pixelHeight: pixelSize[1], + "renderDiffuse": renderDiffuse, + "renderHighlights": renderHighlights, + "renderShadows": renderShadows, + "renderReflections": renderReflections, + "rayDepth": rayDepth + } + ); + + raytracer.renderScene(scene, null, 0); +} + diff --git a/js/src/metrics/jint/v8/richards.js b/js/src/metrics/jint/v8/richards.js new file mode 100644 index 0000000..8cced90 --- /dev/null +++ b/js/src/metrics/jint/v8/richards.js @@ -0,0 +1,539 @@ +// Copyright 2007 Google Inc. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// This is a JavaScript implementation of the Richards +// benchmark from: +// +// http://www.cl.cam.ac.uk/~mr10/Bench.html +// +// The benchmark was originally implemented in BCPL by +// Martin Richards. + + +var Richards = new BenchmarkSuite('Richards', 34886, [ + new Benchmark("Richards", runRichards) +]); + + +/** + * The Richards benchmark simulates the task dispatcher of an + * operating system. + **/ +function runRichards() { + var scheduler = new Scheduler(); + scheduler.addIdleTask(ID_IDLE, 0, null, COUNT); + + var queue = new Packet(null, ID_WORKER, KIND_WORK); + queue = new Packet(queue, ID_WORKER, KIND_WORK); + scheduler.addWorkerTask(ID_WORKER, 1000, queue); + + queue = new Packet(null, ID_DEVICE_A, KIND_DEVICE); + queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE); + queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE); + scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue); + + queue = new Packet(null, ID_DEVICE_B, KIND_DEVICE); + queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE); + queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE); + scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue); + + scheduler.addDeviceTask(ID_DEVICE_A, 4000, null); + + scheduler.addDeviceTask(ID_DEVICE_B, 5000, null); + + scheduler.schedule(); + + if (scheduler.queueCount != EXPECTED_QUEUE_COUNT || + scheduler.holdCount != EXPECTED_HOLD_COUNT) { + var msg = + "Error during execution: queueCount = " + scheduler.queueCount + + ", holdCount = " + scheduler.holdCount + "."; + print(msg); + } +} + +var COUNT = 1000; + +/** + * These two constants specify how many times a packet is queued and + * how many times a task is put on hold in a correct run of richards. + * They don't have any meaning a such but are characteristic of a + * correct run so if the actual queue or hold count is different from + * the expected there must be a bug in the implementation. + **/ +var EXPECTED_QUEUE_COUNT = 2322; +var EXPECTED_HOLD_COUNT = 928; + + +/** + * A scheduler can be used to schedule a set of tasks based on their relative + * priorities. Scheduling is done by maintaining a list of task control blocks + * which holds tasks and the data queue they are processing. + * @constructor + */ +function Scheduler() { + this.queueCount = 0; + this.holdCount = 0; + this.blocks = new Array(NUMBER_OF_IDS); + this.list = null; + this.currentTcb = null; + this.currentId = null; +} + +var ID_IDLE = 0; +var ID_WORKER = 1; +var ID_HANDLER_A = 2; +var ID_HANDLER_B = 3; +var ID_DEVICE_A = 4; +var ID_DEVICE_B = 5; +var NUMBER_OF_IDS = 6; + +var KIND_DEVICE = 0; +var KIND_WORK = 1; + +/** + * Add an idle task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + * @param {int} count the number of times to schedule the task + */ +Scheduler.prototype.addIdleTask = function (id, priority, queue, count) { + this.addRunningTask(id, priority, queue, new IdleTask(this, 1, count)); +}; + +/** + * Add a work task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + */ +Scheduler.prototype.addWorkerTask = function (id, priority, queue) { + this.addTask(id, priority, queue, new WorkerTask(this, ID_HANDLER_A, 0)); +}; + +/** + * Add a handler task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + */ +Scheduler.prototype.addHandlerTask = function (id, priority, queue) { + this.addTask(id, priority, queue, new HandlerTask(this)); +}; + +/** + * Add a handler task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + */ +Scheduler.prototype.addDeviceTask = function (id, priority, queue) { + this.addTask(id, priority, queue, new DeviceTask(this)) +}; + +/** + * Add the specified task and mark it as running. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + * @param {Task} task the task to add + */ +Scheduler.prototype.addRunningTask = function (id, priority, queue, task) { + this.addTask(id, priority, queue, task); + this.currentTcb.setRunning(); +}; + +/** + * Add the specified task to this scheduler. + * @param {int} id the identity of the task + * @param {int} priority the task's priority + * @param {Packet} queue the queue of work to be processed by the task + * @param {Task} task the task to add + */ +Scheduler.prototype.addTask = function (id, priority, queue, task) { + this.currentTcb = new TaskControlBlock(this.list, id, priority, queue, task); + this.list = this.currentTcb; + this.blocks[id] = this.currentTcb; +}; + +/** + * Execute the tasks managed by this scheduler. + */ +Scheduler.prototype.schedule = function () { + this.currentTcb = this.list; + while (this.currentTcb != null) { + if (this.currentTcb.isHeldOrSuspended()) { + this.currentTcb = this.currentTcb.link; + } else { + this.currentId = this.currentTcb.id; + this.currentTcb = this.currentTcb.run(); + } + } +}; + +/** + * Release a task that is currently blocked and return the next block to run. + * @param {int} id the id of the task to suspend + */ +Scheduler.prototype.release = function (id) { + var tcb = this.blocks[id]; + if (tcb == null) return tcb; + tcb.markAsNotHeld(); + if (tcb.priority > this.currentTcb.priority) { + return tcb; + } else { + return this.currentTcb; + } +}; + +/** + * Block the currently executing task and return the next task control block + * to run. The blocked task will not be made runnable until it is explicitly + * released, even if new work is added to it. + */ +Scheduler.prototype.holdCurrent = function () { + this.holdCount++; + this.currentTcb.markAsHeld(); + return this.currentTcb.link; +}; + +/** + * Suspend the currently executing task and return the next task control block + * to run. If new work is added to the suspended task it will be made runnable. + */ +Scheduler.prototype.suspendCurrent = function () { + this.currentTcb.markAsSuspended(); + return this.currentTcb; +}; + +/** + * Add the specified packet to the end of the worklist used by the task + * associated with the packet and make the task runnable if it is currently + * suspended. + * @param {Packet} packet the packet to add + */ +Scheduler.prototype.queue = function (packet) { + var t = this.blocks[packet.id]; + if (t == null) return t; + this.queueCount++; + packet.link = null; + packet.id = this.currentId; + return t.checkPriorityAdd(this.currentTcb, packet); +}; + +/** + * A task control block manages a task and the queue of work packages associated + * with it. + * @param {TaskControlBlock} link the preceding block in the linked block list + * @param {int} id the id of this block + * @param {int} priority the priority of this block + * @param {Packet} queue the queue of packages to be processed by the task + * @param {Task} task the task + * @constructor + */ +function TaskControlBlock(link, id, priority, queue, task) { + this.link = link; + this.id = id; + this.priority = priority; + this.queue = queue; + this.task = task; + if (queue == null) { + this.state = STATE_SUSPENDED; + } else { + this.state = STATE_SUSPENDED_RUNNABLE; + } +} + +/** + * The task is running and is currently scheduled. + */ +var STATE_RUNNING = 0; + +/** + * The task has packets left to process. + */ +var STATE_RUNNABLE = 1; + +/** + * The task is not currently running. The task is not blocked as such and may +* be started by the scheduler. + */ +var STATE_SUSPENDED = 2; + +/** + * The task is blocked and cannot be run until it is explicitly released. + */ +var STATE_HELD = 4; + +var STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE; +var STATE_NOT_HELD = ~STATE_HELD; + +TaskControlBlock.prototype.setRunning = function () { + this.state = STATE_RUNNING; +}; + +TaskControlBlock.prototype.markAsNotHeld = function () { + this.state = this.state & STATE_NOT_HELD; +}; + +TaskControlBlock.prototype.markAsHeld = function () { + this.state = this.state | STATE_HELD; +}; + +TaskControlBlock.prototype.isHeldOrSuspended = function () { + return (this.state & STATE_HELD) != 0 || (this.state == STATE_SUSPENDED); +}; + +TaskControlBlock.prototype.markAsSuspended = function () { + this.state = this.state | STATE_SUSPENDED; +}; + +TaskControlBlock.prototype.markAsRunnable = function () { + this.state = this.state | STATE_RUNNABLE; +}; + +/** + * Runs this task, if it is ready to be run, and returns the next task to run. + */ +TaskControlBlock.prototype.run = function () { + var packet; + if (this.state == STATE_SUSPENDED_RUNNABLE) { + packet = this.queue; + this.queue = packet.link; + if (this.queue == null) { + this.state = STATE_RUNNING; + } else { + this.state = STATE_RUNNABLE; + } + } else { + packet = null; + } + return this.task.run(packet); +}; + +/** + * Adds a packet to the worklist of this block's task, marks this as runnable if + * necessary, and returns the next runnable object to run (the one + * with the highest priority). + */ +TaskControlBlock.prototype.checkPriorityAdd = function (task, packet) { + if (this.queue == null) { + this.queue = packet; + this.markAsRunnable(); + if (this.priority > task.priority) return this; + } else { + this.queue = packet.addTo(this.queue); + } + return task; +}; + +TaskControlBlock.prototype.toString = function () { + return "tcb { " + this.task + "@" + this.state + " }"; +}; + +/** + * An idle task doesn't do any work itself but cycles control between the two + * device tasks. + * @param {Scheduler} scheduler the scheduler that manages this task + * @param {int} v1 a seed value that controls how the device tasks are scheduled + * @param {int} count the number of times this task should be scheduled + * @constructor + */ +function IdleTask(scheduler, v1, count) { + this.scheduler = scheduler; + this.v1 = v1; + this.count = count; +} + +IdleTask.prototype.run = function (packet) { + this.count--; + if (this.count == 0) return this.scheduler.holdCurrent(); + if ((this.v1 & 1) == 0) { + this.v1 = this.v1 >> 1; + return this.scheduler.release(ID_DEVICE_A); + } else { + this.v1 = (this.v1 >> 1) ^ 0xD008; + return this.scheduler.release(ID_DEVICE_B); + } +}; + +IdleTask.prototype.toString = function () { + return "IdleTask" +}; + +/** + * A task that suspends itself after each time it has been run to simulate + * waiting for data from an external device. + * @param {Scheduler} scheduler the scheduler that manages this task + * @constructor + */ +function DeviceTask(scheduler) { + this.scheduler = scheduler; + this.v1 = null; +} + +DeviceTask.prototype.run = function (packet) { + if (packet == null) { + if (this.v1 == null) return this.scheduler.suspendCurrent(); + var v = this.v1; + this.v1 = null; + return this.scheduler.queue(v); + } else { + this.v1 = packet; + return this.scheduler.holdCurrent(); + } +}; + +DeviceTask.prototype.toString = function () { + return "DeviceTask"; +}; + +/** + * A task that manipulates work packets. + * @param {Scheduler} scheduler the scheduler that manages this task + * @param {int} v1 a seed used to specify how work packets are manipulated + * @param {int} v2 another seed used to specify how work packets are manipulated + * @constructor + */ +function WorkerTask(scheduler, v1, v2) { + this.scheduler = scheduler; + this.v1 = v1; + this.v2 = v2; +} + +WorkerTask.prototype.run = function (packet) { + if (packet == null) { + return this.scheduler.suspendCurrent(); + } else { + if (this.v1 == ID_HANDLER_A) { + this.v1 = ID_HANDLER_B; + } else { + this.v1 = ID_HANDLER_A; + } + packet.id = this.v1; + packet.a1 = 0; + for (var i = 0; i < DATA_SIZE; i++) { + this.v2++; + if (this.v2 > 26) this.v2 = 1; + packet.a2[i] = this.v2; + } + return this.scheduler.queue(packet); + } +}; + +WorkerTask.prototype.toString = function () { + return "WorkerTask"; +}; + +/** + * A task that manipulates work packets and then suspends itself. + * @param {Scheduler} scheduler the scheduler that manages this task + * @constructor + */ +function HandlerTask(scheduler) { + this.scheduler = scheduler; + this.v1 = null; + this.v2 = null; +} + +HandlerTask.prototype.run = function (packet) { + if (packet != null) { + if (packet.kind == KIND_WORK) { + this.v1 = packet.addTo(this.v1); + } else { + this.v2 = packet.addTo(this.v2); + } + } + if (this.v1 != null) { + var count = this.v1.a1; + var v; + if (count < DATA_SIZE) { + if (this.v2 != null) { + v = this.v2; + this.v2 = this.v2.link; + v.a1 = this.v1.a2[count]; + this.v1.a1 = count + 1; + return this.scheduler.queue(v); + } + } else { + v = this.v1; + this.v1 = this.v1.link; + return this.scheduler.queue(v); + } + } + return this.scheduler.suspendCurrent(); +}; + +HandlerTask.prototype.toString = function () { + return "HandlerTask"; +}; + +/* --- * + * P a c k e t + * --- */ + +var DATA_SIZE = 4; + +/** + * A simple package of data that is manipulated by the tasks. The exact layout + * of the payload data carried by a packet is not importaint, and neither is the + * nature of the work performed on packets by the tasks. + * + * Besides carrying data, packets form linked lists and are hence used both as + * data and worklists. + * @param {Packet} link the tail of the linked list of packets + * @param {int} id an ID for this packet + * @param {int} kind the type of this packet + * @constructor + */ +function Packet(link, id, kind) { + this.link = link; + this.id = id; + this.kind = kind; + this.a1 = 0; + this.a2 = new Array(DATA_SIZE); +} + +/** + * Add this packet to the end of a worklist, and return the worklist. + * @param {Packet} queue the worklist to add this packet to + */ +Packet.prototype.addTo = function (queue) { + this.link = null; + if (queue == null) return this; + var peek, next = queue; + while ((peek = next.link) != null) + next = peek; + next.link = this; + return queue; +}; + +Packet.prototype.toString = function () { + return "Packet"; +}; diff --git a/js/src/metrics/jint/v8/run-earley-boyer.js b/js/src/metrics/jint/v8/run-earley-boyer.js new file mode 100644 index 0000000..ff51952 --- /dev/null +++ b/js/src/metrics/jint/v8/run-earley-boyer.js @@ -0,0 +1,44 @@ +// Copyright 2008 Google Inc. All Rights Reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +load('base.js'); +load('earley-boyer.js'); + +function PrintResult(name, result) { + print(name + ': ' + result); +} + + +function PrintScore(score) { + print('----'); + print('Score: ' + score); +} + + +BenchmarkSuite.RunSuites({ NotifyResult: PrintResult, + NotifyScore: PrintScore }); diff --git a/js/src/metrics/jint/v8/run-raytrace.js b/js/src/metrics/jint/v8/run-raytrace.js new file mode 100644 index 0000000..7af95c8 --- /dev/null +++ b/js/src/metrics/jint/v8/run-raytrace.js @@ -0,0 +1,44 @@ +// Copyright 2008 Google Inc. All Rights Reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +load('base.js'); +load('raytrace.js'); + +function PrintResult(name, result) { + print(name + ': ' + result); +} + + +function PrintScore(score) { + print('----'); + print('Score: ' + score); +} + + +BenchmarkSuite.RunSuites({ NotifyResult: PrintResult, + NotifyScore: PrintScore }); diff --git a/js/src/metrics/jint/v8/run-richards.js b/js/src/metrics/jint/v8/run-richards.js new file mode 100644 index 0000000..1dfbcb2 --- /dev/null +++ b/js/src/metrics/jint/v8/run-richards.js @@ -0,0 +1,44 @@ +// Copyright 2008 Google Inc. All Rights Reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +load('base.js'); +load('richards.js'); + +function PrintResult(name, result) { + print(name + ': ' + result); +} + + +function PrintScore(score) { + print('----'); + print('Score: ' + score); +} + + +BenchmarkSuite.RunSuites({ NotifyResult: PrintResult, + NotifyScore: PrintScore }); diff --git a/js/src/metrics/jint/v8/run.js b/js/src/metrics/jint/v8/run.js new file mode 100644 index 0000000..8302535 --- /dev/null +++ b/js/src/metrics/jint/v8/run.js @@ -0,0 +1,49 @@ +// Copyright 2008 Google Inc. All Rights Reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +load('base.js'); +load('richards.js'); +load('deltablue.js'); +load('crypto.js'); +load('raytrace.js'); +load('earley-boyer.js'); + + +function PrintResult(name, result) { + print(name + ': ' + result); +} + + +function PrintScore(score) { + print('----'); + print('Score: ' + score); +} + + +BenchmarkSuite.RunSuites({ NotifyResult: PrintResult, + NotifyScore: PrintScore }); diff --git a/js/src/mozjs185.pc.in b/js/src/mozjs185.pc.in new file mode 100644 index 0000000..806be6c --- /dev/null +++ b/js/src/mozjs185.pc.in @@ -0,0 +1,10 @@ +prefix=%prefix% +libdir=%libdir% +includedir=%includedir% + +Name: SpiderMonkey 1.8.5 +Description: The Mozilla library for JavaScript 1.8.5 +Version: %MOZILLA_VERSION% +Requires: nspr >= 4.7 +Libs: -L${libdir} -lmozjs185 +Cflags: -I${includedir}/js diff --git a/js/src/nanojit-import-filemap b/js/src/nanojit-import-filemap new file mode 100644 index 0000000..d26ac7a --- /dev/null +++ b/js/src/nanojit-import-filemap @@ -0,0 +1,13 @@ +include nanojit +include vprof +include lirasm + +exclude Makefile.in +exclude configure.in +exclude config.h.in +exclude autoconf +exclude .hgtags + +rename vprof js/src/vprof +rename nanojit js/src/nanojit +rename lirasm js/src/lirasm diff --git a/js/src/nanojit-import-rev b/js/src/nanojit-import-rev new file mode 100644 index 0000000..05095ee --- /dev/null +++ b/js/src/nanojit-import-rev @@ -0,0 +1 @@ +f6016c7c7cd415a26dad9cf39d34141b8b482d43 diff --git a/js/src/nanojit/Allocator.cpp b/js/src/nanojit/Allocator.cpp new file mode 100644 index 0000000..3c87641 --- /dev/null +++ b/js/src/nanojit/Allocator.cpp @@ -0,0 +1,103 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nanojit.h" + +#ifdef FEATURE_NANOJIT + +namespace nanojit +{ + Allocator::Allocator() + : current_chunk(NULL) + , current_top(NULL) + , current_limit(NULL) + { } + + Allocator::~Allocator() + { + reset(); + } + + void Allocator::reset() + { + Chunk *c = current_chunk; + while (c) { + Chunk *prev = c->prev; + freeChunk(c); + c = prev; + } + current_chunk = NULL; + current_top = NULL; + current_limit = NULL; + postReset(); + } + + void* Allocator::allocSlow(size_t nbytes, bool fallible) + { + NanoAssert((nbytes & 7) == 0); + if (fill(nbytes, fallible)) { + NanoAssert(current_top + nbytes <= current_limit); + void* p = current_top; + current_top += nbytes; + return p; + } + return NULL; + } + + bool Allocator::fill(size_t nbytes, bool fallible) + { + if (nbytes < MIN_CHUNK_SZB) + nbytes = MIN_CHUNK_SZB; + size_t chunkbytes = sizeof(Chunk) + nbytes - sizeof(int64_t); + void* mem = allocChunk(chunkbytes, fallible); + if (mem) { + Chunk* chunk = (Chunk*) mem; + chunk->prev = current_chunk; + current_chunk = chunk; + current_top = (char*)chunk->data; + current_limit = (char*)mem + chunkbytes; + return true; + } else { + NanoAssert(fallible); + return false; + } + } +} + +#endif // FEATURE_NANOJIT diff --git a/js/src/nanojit/Allocator.h b/js/src/nanojit/Allocator.h new file mode 100644 index 0000000..8aab15f --- /dev/null +++ b/js/src/nanojit/Allocator.h @@ -0,0 +1,140 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __nanojit_Allocator__ +#define __nanojit_Allocator__ + +namespace nanojit +{ + /** + * Allocator is a bump-pointer allocator with an SPI for getting more + * memory from embedder-implemented allocator, such as malloc()/free(). + * + * alloc() never returns NULL. The implementation of allocChunk() + * is expected to perform a longjmp or exception when an allocation can't + * proceed. fallibleAlloc() (and fallibleAllocChunk()) may return NULL. + * They should be used for large allocations whose failure can be handled + * without too much difficulty. + */ + class Allocator { + public: + Allocator(); + ~Allocator(); + + // Usable space in the minimum chunk size; there are also a few bytes + // used for administration. + static const size_t MIN_CHUNK_SZB = 2000; + + void reset(); + + /** alloc memory, never return null. */ + void* alloc(size_t nbytes) { + void* p; + nbytes = (nbytes + 7) & ~7; // round up + if (current_top + nbytes <= current_limit) { + p = current_top; + current_top += nbytes; + } else { + p = allocSlow(nbytes, /* fallible = */false); + NanoAssert(p); + } + return p; + } + + /** alloc memory, maybe return null. */ + void* fallibleAlloc(size_t nbytes) { + void* p; + nbytes = (nbytes + 7) & ~7; // round up + if (current_top + nbytes <= current_limit) { + p = current_top; + current_top += nbytes; + } else { + p = allocSlow(nbytes, /* fallible = */true); + } + return p; + } + + protected: + void* allocSlow(size_t nbytes, bool fallible = false); + bool fill(size_t minbytes, bool fallible); + + class Chunk { + public: + Chunk* prev; + int64_t data[1]; // int64_t forces 8-byte alignment. + }; + + Chunk* current_chunk; + char* current_top; + char* current_limit; + + // allocator SPI + + /** allocate another block from a host provided allocator */ + void* allocChunk(size_t nbytes, bool fallible); + + /** free back to the same allocator */ + void freeChunk(void*); + + /** hook for post-reset action. */ + void postReset(); + }; +} + +/** global new overload enabling this pattern: new (allocator) T(...) */ +inline void* operator new(size_t size, nanojit::Allocator &a) { + return a.alloc(size); +} + +/** global new overload enabling this pattern: new (allocator) T(...) */ +inline void* operator new(size_t size, nanojit::Allocator *a) { + return a->alloc(size); +} + +/** global new[] overload enabling this pattern: new (allocator) T[] */ +inline void* operator new[](size_t size, nanojit::Allocator& a) { + return a.alloc(size); +} + +/** global new[] overload enabling this pattern: new (allocator) T[] */ +inline void* operator new[](size_t size, nanojit::Allocator* a) { + return a->alloc(size); +} + +#endif // __nanojit_Allocator__ diff --git a/js/src/nanojit/Assembler.cpp b/js/src/nanojit/Assembler.cpp new file mode 100755 index 0000000..5f8b54c --- /dev/null +++ b/js/src/nanojit/Assembler.cpp @@ -0,0 +1,2632 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nanojit.h" + +#ifdef FEATURE_NANOJIT + +#ifdef VMCFG_VTUNE +#include "../core/CodegenLIR.h" +#endif + +#ifdef _MSC_VER + // disable some specific warnings which are normally useful, but pervasive in the code-gen macros + #pragma warning(disable:4310) // cast truncates constant value +#endif + +#ifdef VMCFG_VTUNE +namespace vtune { + using namespace nanojit; + void vtuneStart(void*, NIns*); + void vtuneEnd(void*, NIns*); + void vtuneLine(void*, int, NIns*); + void vtuneFile(void*, void*); +} +using namespace vtune; +#endif // VMCFG_VTUNE + + +namespace nanojit +{ + /** + * Need the following: + * + * - merging paths ( build a graph? ), possibly use external rep to drive codegen + */ + Assembler::Assembler(CodeAlloc& codeAlloc, Allocator& dataAlloc, Allocator& alloc, AvmCore* core, LogControl* logc, const Config& config) + : alloc(alloc) + , _codeAlloc(codeAlloc) + , _dataAlloc(dataAlloc) + , _thisfrag(NULL) + , _branchStateMap(alloc) + , _patches(alloc) + , _labels(alloc) + , _noise(NULL) + #if NJ_USES_IMMD_POOL + , _immDPool(alloc) + #endif + , codeList(NULL) + , _epilogue(NULL) + , _err(None) + #if PEDANTIC + , pedanticTop(NULL) + #endif + #ifdef VMCFG_VTUNE + , vtuneHandle(NULL) + #endif + , _config(config) + { + nInit(core); + (void)logc; + verbose_only( _logc = logc; ) + verbose_only( _outputCache = 0; ) + verbose_only( outline[0] = '\0'; ) + verbose_only( outlineEOL[0] = '\0'; ) + + reset(); + } + + // Per-opcode register hint table. Default to no hints for all + // instructions. It's not marked const because individual back-ends can + // install hint values for opcodes of interest in nInit(). + RegisterMask Assembler::nHints[LIR_sentinel+1] = { +#define OP___(op, number, repKind, retType, isCse) \ + 0, +#include "LIRopcode.tbl" +#undef OP___ + 0 + }; + +#ifdef _DEBUG + + /*static*/ LIns* const AR::BAD_ENTRY = (LIns*)0xdeadbeef; + + void AR::validateQuick() + { + NanoAssert(_highWaterMark < NJ_MAX_STACK_ENTRY); + NanoAssert(_entries[0] == NULL); + // Only check a few entries around _highWaterMark. + uint32_t const RADIUS = 4; + uint32_t const lo = (_highWaterMark > 1 + RADIUS ? _highWaterMark - RADIUS : 1); + uint32_t const hi = (_highWaterMark + 1 + RADIUS < NJ_MAX_STACK_ENTRY ? _highWaterMark + 1 + RADIUS : NJ_MAX_STACK_ENTRY); + for (uint32_t i = lo; i <= _highWaterMark; ++i) + NanoAssert(_entries[i] != BAD_ENTRY); + for (uint32_t i = _highWaterMark+1; i < hi; ++i) + NanoAssert(_entries[i] == BAD_ENTRY); + } + + void AR::validateFull() + { + NanoAssert(_highWaterMark < NJ_MAX_STACK_ENTRY); + NanoAssert(_entries[0] == NULL); + for (uint32_t i = 1; i <= _highWaterMark; ++i) + NanoAssert(_entries[i] != BAD_ENTRY); + for (uint32_t i = _highWaterMark+1; i < NJ_MAX_STACK_ENTRY; ++i) + NanoAssert(_entries[i] == BAD_ENTRY); + } + + void AR::validate() + { + static uint32_t validateCounter = 0; + if (++validateCounter >= 100) + { + validateFull(); + validateCounter = 0; + } + else + { + validateQuick(); + } + } + +#endif + + inline void AR::clear() + { + _highWaterMark = 0; + NanoAssert(_entries[0] == NULL); + #ifdef _DEBUG + for (uint32_t i = 1; i < NJ_MAX_STACK_ENTRY; ++i) + _entries[i] = BAD_ENTRY; + #endif + } + + bool AR::Iter::next(LIns*& ins, uint32_t& nStackSlots, int32_t& arIndex) + { + while (_i <= _ar._highWaterMark) { + ins = _ar._entries[_i]; + if (ins) { + arIndex = _i; + nStackSlots = nStackSlotsFor(ins); + _i += nStackSlots; + return true; + } + _i++; + } + ins = NULL; + nStackSlots = 0; + arIndex = 0; + return false; + } + + void Assembler::arReset() + { + _activation.clear(); + _branchStateMap.clear(); + _patches.clear(); + _labels.clear(); + #if NJ_USES_IMMD_POOL + _immDPool.clear(); + #endif + } + + void Assembler::registerResetAll() + { + nRegisterResetAll(_allocator); + _allocator.managed = _allocator.free; + + // At start, should have some registers free and none active. + NanoAssert(0 != _allocator.free); + NanoAssert(0 == _allocator.activeMask()); +#ifdef NANOJIT_IA32 + debug_only(_fpuStkDepth = 0; ) +#endif + } + + // Legend for register sets: A = allowed, P = preferred, F = free, S = SavedReg. + // + // Finds a register in 'setA___' to store the result of 'ins' (one from + // 'set_P__' if possible), evicting one if necessary. Doesn't consider + // the prior state of 'ins'. + // + // Nb: 'setA___' comes from the instruction's use, 'set_P__' comes from its def. + // Eg. in 'add(call(...), ...)': + // - the call's use means setA___==GpRegs; + // - the call's def means set_P__==rmask(retRegs[0]). + // + Register Assembler::registerAlloc(LIns* ins, RegisterMask setA___, RegisterMask set_P__) + { + Register r; + RegisterMask set__F_ = _allocator.free; + RegisterMask setA_F_ = setA___ & set__F_; + + if (setA_F_) { + RegisterMask set___S = SavedRegs; + RegisterMask setA_FS = setA_F_ & set___S; + RegisterMask setAPF_ = setA_F_ & set_P__; + RegisterMask setAPFS = setA_FS & set_P__; + RegisterMask set; + + if (setAPFS) set = setAPFS; + else if (setAPF_) set = setAPF_; + else if (setA_FS) set = setA_FS; + else set = setA_F_; + + r = nRegisterAllocFromSet(set); + _allocator.addActive(r, ins); + ins->setReg(r); + } else { + // Nothing free, steal one. + // LSRA says pick the one with the furthest use. + LIns* vic = findVictim(setA___); + NanoAssert(vic->isInReg()); + r = vic->getReg(); + + evict(vic); + + // r ends up staying active, but the LIns defining it changes. + _allocator.removeFree(r); + _allocator.addActive(r, ins); + ins->setReg(r); + } + + return r; + } + + // Finds a register in 'allow' to store a temporary value (one not + // associated with a particular LIns), evicting one if necessary. The + // returned register is marked as being free and so can only be safely + // used for code generation purposes until the regstate is next inspected + // or updated. + Register Assembler::registerAllocTmp(RegisterMask allow) + { + LIns dummyIns; + Register r = registerAlloc(&dummyIns, allow, /*prefer*/0); + + // Mark r as free, ready for use as a temporary value. + _allocator.removeActive(r); + _allocator.addFree(r); + return r; + } + + void Assembler::codeAlloc(NIns *&start, NIns *&end, NIns *&eip + verbose_only(, size_t &nBytes) + , size_t byteLimit) + { + // save the block we just filled + if (start) + CodeAlloc::add(codeList, start, end); + + // CodeAlloc contract: allocations never fail + _codeAlloc.alloc(start, end, byteLimit); + verbose_only( nBytes += (end - start) * sizeof(NIns); ) + NanoAssert(uintptr_t(end) - uintptr_t(start) >= (size_t)LARGEST_UNDERRUN_PROT); + eip = end; + verbose_only( _nInsAfter = eip; ) + } + + void Assembler::clearNInsPtrs() + { + _nIns = 0; + _nExitIns = 0; + codeStart = codeEnd = 0; + exitStart = exitEnd = 0; + codeList = 0; + } + + void Assembler::reset() + { + clearNInsPtrs(); + nativePageReset(); + registerResetAll(); + arReset(); + } + + #ifdef _DEBUG + void Assembler::pageValidate() + { + if (error()) return; + // This may be a normal code chunk or an exit code chunk. + NanoAssertMsg(codeStart <= _nIns && _nIns <= codeEnd, + "Native instruction pointer overstep paging bounds; check overrideProtect for last instruction"); + } + #endif + + #ifdef _DEBUG + + bool AR::isValidEntry(uint32_t idx, LIns* ins) const + { + return idx > 0 && idx <= _highWaterMark && _entries[idx] == ins; + } + + void AR::checkForResourceConsistency(const RegAlloc& regs) + { + validate(); + for (uint32_t i = 1; i <= _highWaterMark; ++i) + { + LIns* ins = _entries[i]; + if (!ins) + continue; + uint32_t arIndex = ins->getArIndex(); + NanoAssert(arIndex != 0); + if (ins->isop(LIR_allocp)) { + int const n = i + (ins->size()>>2); + for (int j=i+1; j < n; j++) { + NanoAssert(_entries[j]==ins); + } + NanoAssert(arIndex == (uint32_t)n-1); + i = n-1; + } + else if (ins->isQorD()) { + NanoAssert(_entries[i + 1]==ins); + i += 1; // skip high word + } + else { + NanoAssertMsg(arIndex == i, "Stack record index mismatch"); + } + NanoAssertMsg(!ins->isInReg() || regs.isConsistent(ins->getReg(), ins), + "Register record mismatch"); + } + } + + void Assembler::resourceConsistencyCheck() + { + NanoAssert(!error()); +#ifdef NANOJIT_IA32 + // Within the expansion of a single LIR instruction, we may use the x87 + // stack for unmanaged temporaries. Otherwise, we do not use the x87 stack + // as such, but use the top element alone as a single allocatable FP register. + // Compensation code must be inserted to keep the stack balanced and avoid + // overflow, and the mechanisms for this are rather fragile and IA32-specific. + // The predicate below should hold between any pair of instructions within + // a basic block, at labels, and just after a conditional branch. Currently, + // we enforce this condition between all pairs of instructions, but this is + // overly restrictive, and would fail if we did not generate unreachable x87 + // stack pops following unconditional branches. + NanoAssert((_allocator.active[REGNUM(FST0)] && _fpuStkDepth == -1) || + (!_allocator.active[REGNUM(FST0)] && _fpuStkDepth == 0)); +#endif + _activation.checkForResourceConsistency(_allocator); + registerConsistencyCheck(); + } + + void Assembler::registerConsistencyCheck() + { + RegisterMask managed = _allocator.managed; + for (Register r = lsReg(managed); managed; r = nextLsReg(managed, r)) { + // A register managed by register allocation must be either + // free or active, but not both. + if (_allocator.isFree(r)) { + NanoAssertMsgf(_allocator.getActive(r)==0, + "register %s is free but assigned to ins", gpn(r)); + } else { + // An LIns defining a register must have that register in + // its reservation. + LIns* ins = _allocator.getActive(r); + NanoAssert(ins); + NanoAssertMsg(r == ins->getReg(), "Register record mismatch"); + } + } + + RegisterMask not_managed = ~_allocator.managed; + for (Register r = lsReg(not_managed); not_managed; r = nextLsReg(not_managed, r)) { + // A register not managed by register allocation must be + // neither free nor active. + if (REGNUM(r) <= LastRegNum) { + NanoAssert(!_allocator.isFree(r)); + NanoAssert(!_allocator.getActive(r)); + } + } + } + #endif /* _DEBUG */ + + void Assembler::findRegFor2(RegisterMask allowa, LIns* ia, Register& ra, + RegisterMask allowb, LIns* ib, Register& rb) + { + // There should be some overlap between 'allowa' and 'allowb', else + // there's no point calling this function. + NanoAssert(allowa & allowb); + + if (ia == ib) { + ra = rb = findRegFor(ia, allowa & allowb); // use intersection(allowa, allowb) + + } else if (ib->isInRegMask(allowb)) { + // 'ib' is already in an allowable reg -- don't let it get evicted + // when finding 'ra'. + rb = ib->getReg(); + ra = findRegFor(ia, allowa & ~rmask(rb)); + + } else { + ra = findRegFor(ia, allowa); + rb = findRegFor(ib, allowb & ~rmask(ra)); + } + } + + Register Assembler::findSpecificRegFor(LIns* i, Register w) + { + return findRegFor(i, rmask(w)); + } + + // Like findRegFor(), but called when the LIns is used as a pointer. It + // doesn't have to be called, findRegFor() can still be used, but it can + // optimize the LIR_allocp case by indexing off FP, thus saving the use of + // a GpReg. + // + Register Assembler::getBaseReg(LIns* base, int &d, RegisterMask allow) + { + #if !PEDANTIC + if (base->isop(LIR_allocp)) { + // The value of a LIR_allocp is a pointer to its stack memory, + // which is always relative to FP. So we can just return FP if we + // also adjust 'd' (and can do so in a valid manner). Or, in the + // PEDANTIC case, we can just assign a register as normal; + // findRegFor() will allocate the stack memory for LIR_allocp if + // necessary. + d += findMemFor(base); + return FP; + } + #else + (void) d; + #endif + return findRegFor(base, allow); + } + + // Like findRegFor2(), but used for stores where the base value has the + // same type as the stored value, eg. in asm_store32() on 32-bit platforms + // and asm_store64() on 64-bit platforms. Similar to getBaseReg(), + // findRegFor2() can be called instead, but this function can optimize the + // case where the base value is a LIR_allocp. + void Assembler::getBaseReg2(RegisterMask allowValue, LIns* value, Register& rv, + RegisterMask allowBase, LIns* base, Register& rb, int &d) + { + #if !PEDANTIC + if (base->isop(LIR_allocp)) { + rb = FP; + d += findMemFor(base); + rv = findRegFor(value, allowValue); + return; + } + #else + (void) d; + #endif + findRegFor2(allowValue, value, rv, allowBase, base, rb); + } + + RegisterMask Assembler::hint(LIns* ins) + { + RegisterMask prefer = nHints[ins->opcode()]; + return (prefer == PREFER_SPECIAL) ? nHint(ins) : prefer; + } + + // Finds a register in 'allow' to hold the result of 'ins'. Used when we + // encounter a use of 'ins'. The actions depend on the prior regstate of + // 'ins': + // - If the result of 'ins' is not in any register, we find an allowed + // one, evicting one if necessary. + // - If the result of 'ins' is already in an allowed register, we use that. + // - If the result of 'ins' is already in a not-allowed register, we find an + // allowed one and move it. + // + Register Assembler::findRegFor(LIns* ins, RegisterMask allow) + { + if (ins->isop(LIR_allocp)) { + // Never allocate a reg for this without stack space too. + findMemFor(ins); + } + + Register r; + + if (!ins->isInReg()) { + // 'ins' isn't in a register (must be in a spill slot or nowhere). + r = registerAlloc(ins, allow, hint(ins)); + + } else if (rmask(r = ins->getReg()) & allow) { + // 'ins' is in an allowed register. + _allocator.useActive(r); + + } else { + // 'ins' is in a register (r) that's not in 'allow'. +#ifdef NANOJIT_IA32 + if (((rmask(r)&XmmRegs) && !(allow&XmmRegs)) || + ((rmask(r)&x87Regs) && !(allow&x87Regs))) + { + // x87 <-> xmm copy required + //_nvprof("fpu-evict",1); + evict(ins); + r = registerAlloc(ins, allow, hint(ins)); + } else +#elif defined(NANOJIT_PPC) || defined(NANOJIT_MIPS) || defined(NANOJIT_SPARC) + if (((rmask(r)&GpRegs) && !(allow&GpRegs)) || + ((rmask(r)&FpRegs) && !(allow&FpRegs))) + { + evict(ins); + r = registerAlloc(ins, allow, hint(ins)); + } else +#endif + { + // The post-state register holding 'ins' is 's', the pre-state + // register holding 'ins' is 'r'. For example, if s=eax and + // r=ecx: + // + // pre-state: ecx(ins) + // instruction: mov eax, ecx + // post-state: eax(ins) + // + Register s = r; + _allocator.retire(r); + r = registerAlloc(ins, allow, hint(ins)); + + // 'ins' is in 'allow', in register r (different to the old r); + // s is the old r. + if ((rmask(s) & GpRegs) && (rmask(r) & GpRegs)) { + MR(s, r); // move 'ins' from its pre-state reg (r) to its post-state reg (s) + } else { + asm_nongp_copy(s, r); + } + } + } + + return r; + } + + // Like findSpecificRegFor(), but only for when 'r' is known to be free + // and 'ins' is known to not already have a register allocated. Updates + // the regstate (maintaining the invariants) but does not generate any + // code. The return value is redundant, always being 'r', but it's + // sometimes useful to have it there for assignments. + Register Assembler::findSpecificRegForUnallocated(LIns* ins, Register r) + { + if (ins->isop(LIR_allocp)) { + // never allocate a reg for this w/out stack space too + findMemFor(ins); + } + + NanoAssert(!ins->isInReg()); + NanoAssert(_allocator.free & rmask(r)); + + ins->setReg(r); + _allocator.removeFree(r); + _allocator.addActive(r, ins); + + return r; + } + +#if NJ_USES_IMMD_POOL + const uint64_t* Assembler::findImmDFromPool(uint64_t q) + { + uint64_t* p = _immDPool.get(q); + if (!p) + { + p = new (_dataAlloc) uint64_t; + *p = q; + _immDPool.put(q, p); + } + return p; + } +#endif + + int Assembler::findMemFor(LIns *ins) + { +#if NJ_USES_IMMD_POOL + NanoAssert(!ins->isImmD()); +#endif + if (!ins->isInAr()) { + uint32_t const arIndex = arReserve(ins); + ins->setArIndex(arIndex); + NanoAssert(_activation.isValidEntry(ins->getArIndex(), ins) == (arIndex != 0)); + } + return arDisp(ins); + } + + // XXX: this function is dangerous and should be phased out; + // See bug 513615. Calls to it should replaced it with a + // prepareResultReg() / generate code / freeResourcesOf() sequence. + Register Assembler::deprecated_prepResultReg(LIns *ins, RegisterMask allow) + { +#ifdef NANOJIT_IA32 + // We used to have to worry about possibly popping the x87 stack here. + // But this function is no longer used on i386, and this assertion + // ensures that. + NanoAssert(0); +#endif + Register r = findRegFor(ins, allow); + deprecated_freeRsrcOf(ins); + return r; + } + + // Finds a register in 'allow' to hold the result of 'ins'. Also + // generates code to spill the result if necessary. Called just prior to + // generating the code for 'ins' (because we generate code backwards). + // + // An example where no spill is necessary. Lines marked '*' are those + // done by this function. + // + // regstate: R + // asm: define res into r + // * regstate: R + r(res) + // ... + // asm: use res in r + // + // An example where a spill is necessary. + // + // regstate: R + // asm: define res into r + // * regstate: R + r(res) + // * asm: spill res from r + // regstate: R + // ... + // asm: restore res into r2 + // regstate: R + r2(res) + other changes from "..." + // asm: use res in r2 + // + Register Assembler::prepareResultReg(LIns *ins, RegisterMask allow) + { + // At this point, we know the result of 'ins' is used later in the + // code, unless it is a call to an impure function that must be + // included for effect even though its result is ignored. It may have + // had to be evicted, in which case the restore will have already been + // generated, so we now generate the spill. QUERY: Is there any attempt + // to elide the spill if we know that all restores can be rematerialized? +#ifdef NANOJIT_IA32 + const bool notInFST0 = (!ins->isInReg() || ins->getReg() != FST0); + Register r = findRegFor(ins, allow); + // If the result register is FST0, but FST0 is not in the post-regstate, + // then we must pop the x87 stack. This may occur because the result is + // unused, or because it has been stored to a spill slot or an XMM register. + const bool needPop = notInFST0 && (r == FST0); + const bool didSpill = asm_maybe_spill(ins, needPop); + if (!didSpill && needPop) { + // If the instruction is spilled, then the pop will have already + // been performed by the store to the stack slot. Otherwise, we + // must pop now. This may occur when the result of a LIR_calld + // to an impure (side-effecting) function is not used. + FSTP(FST0); + } +#else + Register r = findRegFor(ins, allow); + asm_maybe_spill(ins, false); +#endif + return r; + } + + bool Assembler::asm_maybe_spill(LIns* ins, bool pop) + { + if (ins->isInAr()) { + int d = arDisp(ins); + Register r = ins->getReg(); + verbose_only( RefBuf b; + if (_logc->lcbits & LC_Native) { + setOutputForEOL(" <= spill %s", + _thisfrag->lirbuf->printer->formatRef(&b, ins)); } ) +#ifdef NANOJIT_IA32 + asm_spill(r, d, pop); +#else + (void)pop; + asm_spill(r, d, ins->isQorD()); +#endif + return true; + } + return false; + } + + // XXX: This function is error-prone and should be phased out; see bug 513615. + void Assembler::deprecated_freeRsrcOf(LIns *ins) + { + if (ins->isInReg()) { + asm_maybe_spill(ins, /*pop*/false); + _allocator.retire(ins->getReg()); // free any register associated with entry + ins->clearReg(); + } + if (ins->isInAr()) { + arFree(ins); // free any AR space associated with entry + ins->clearArIndex(); + } + } + + // Frees all record of registers and spill slots used by 'ins'. + void Assembler::freeResourcesOf(LIns *ins) + { + if (ins->isInReg()) { + _allocator.retire(ins->getReg()); // free any register associated with entry + ins->clearReg(); + } + if (ins->isInAr()) { + arFree(ins); // free any AR space associated with entry + ins->clearArIndex(); + } + } + + // Frees 'r' in the RegAlloc regstate, if it's not already free. + void Assembler::evictIfActive(Register r) + { + if (LIns* vic = _allocator.getActive(r)) { + NanoAssert(vic->getReg() == r); + evict(vic); + } + } + + // Frees 'r' (which currently holds the result of 'vic') in the regstate. + // An example: + // + // pre-regstate: eax(ld1) + // instruction: mov ebx,-4(ebp) <= restore add1 # %ebx is dest + // post-regstate: eax(ld1) ebx(add1) + // + // At run-time we are *restoring* 'add1' into %ebx, hence the call to + // asm_restore(). But at regalloc-time we are moving backwards through + // the code, so in that sense we are *evicting* 'add1' from %ebx. + // + void Assembler::evict(LIns* vic) + { + // Not free, need to steal. + Register r = vic->getReg(); + + NanoAssert(!_allocator.isFree(r)); + NanoAssert(vic == _allocator.getActive(r)); + + verbose_only( RefBuf b; + if (_logc->lcbits & LC_Native) { + setOutputForEOL(" <= restore %s", + _thisfrag->lirbuf->printer->formatRef(&b, vic)); } ) + asm_restore(vic, r); + + _allocator.retire(r); + vic->clearReg(); + + // At this point 'vic' is unused (if rematerializable), or in a spill + // slot (if not). + } + + // If we have this: + // + // W = ld(addp(B, lshp(I, k)))[d] , where int(1) <= k <= int(3) + // + // then we set base=B, index=I, scale=k. + // + // Otherwise, we must have this: + // + // W = ld(addp(B, I))[d] + // + // and we set base=B, index=I, scale=0. + // + void Assembler::getBaseIndexScale(LIns* addp, LIns** base, LIns** index, int* scale) + { + NanoAssert(addp->isop(LIR_addp)); + + *base = addp->oprnd1(); + LIns* rhs = addp->oprnd2(); + int k; + + if (rhs->opcode() == LIR_lshp && rhs->oprnd2()->isImmI() && + (k = rhs->oprnd2()->immI(), (1 <= k && k <= 3))) + { + *index = rhs->oprnd1(); + *scale = k; + } else { + *index = rhs; + *scale = 0; + } + } + void Assembler::patch(GuardRecord *lr) + { + if (!lr->jmp) // the guard might have been eliminated as redundant + return; + Fragment *frag = lr->exit->target; + NanoAssert(frag->fragEntry != 0); + nPatchBranch((NIns*)lr->jmp, frag->fragEntry); + CodeAlloc::flushICache(lr->jmp, LARGEST_BRANCH_PATCH); + verbose_only(verbose_outputf("patching jump at %p to target %p\n", + lr->jmp, frag->fragEntry);) + } + + void Assembler::patch(SideExit *exit) + { + GuardRecord *rec = exit->guards; + NanoAssert(rec); + while (rec) { + patch(rec); + rec = rec->next; + } + } + +#ifdef NANOJIT_IA32 + void Assembler::patch(SideExit* exit, SwitchInfo* si) + { + for (GuardRecord* lr = exit->guards; lr; lr = lr->next) { + Fragment *frag = lr->exit->target; + NanoAssert(frag->fragEntry != 0); + si->table[si->index] = frag->fragEntry; + } + } +#endif + + NIns* Assembler::asm_exit(LIns* guard) + { + SideExit *exit = guard->record()->exit; + NIns* at = 0; + if (!_branchStateMap.get(exit)) + { + at = asm_leave_trace(guard); + } + else + { + RegAlloc* captured = _branchStateMap.get(exit); + intersectRegisterState(*captured); + at = exit->target->fragEntry; + NanoAssert(at != 0); + _branchStateMap.remove(exit); + } + return at; + } + + NIns* Assembler::asm_leave_trace(LIns* guard) + { + verbose_only( verbose_outputf("----------------------------------- ## END exit block %p", guard);) + + // This point is unreachable. So free all the registers. If an + // instruction has a stack entry we will leave it alone, otherwise we + // free it entirely. intersectRegisterState() will restore. + RegAlloc capture = _allocator; + releaseRegisters(); + + swapCodeChunks(); + _inExit = true; + verbose_only( _nInsAfter = _nIns; ) + +#ifdef NANOJIT_IA32 + debug_only( _sv_fpuStkDepth = _fpuStkDepth; _fpuStkDepth = 0; ) +#endif + + nFragExit(guard); + + // Restore the callee-saved register and parameters. + assignSavedRegs(); + assignParamRegs(); + + intersectRegisterState(capture); + + // this can be useful for breaking whenever an exit is taken + //INT3(); + //NOP(); + + // we are done producing the exit logic for the guard so demark where our exit block code begins + NIns* jmpTarget = _nIns; // target in exit path for our mainline conditional jump + + // swap back pointers, effectively storing the last location used in the exit path + swapCodeChunks(); + _inExit = false; + verbose_only( _nInsAfter = _nIns; ) + + //verbose_only( verbose_outputf(" LIR_xt/xf swapCodeChunks, _nIns is now %08X(%08X), _nExitIns is now %08X(%08X)",_nIns, *_nIns,_nExitIns,*_nExitIns) ); + verbose_only( verbose_outputf("%p:", jmpTarget);) + verbose_only( verbose_outputf("----------------------------------- ## BEGIN exit block (LIR_xt|LIR_xf)") ); + +#ifdef NANOJIT_IA32 + NanoAssertMsgf(_fpuStkDepth == _sv_fpuStkDepth, "LIR_xtf, _fpuStkDepth=%d, expect %d",_fpuStkDepth, _sv_fpuStkDepth); + debug_only( _fpuStkDepth = _sv_fpuStkDepth; _sv_fpuStkDepth = 9999; ) +#endif + + return jmpTarget; + } + + void Assembler::compile(Fragment* frag, Allocator& alloc, bool optimize verbose_only(, LInsPrinter* printer)) + { + verbose_only( + bool anyVerb = (_logc->lcbits & 0xFFFF & ~LC_FragProfile) > 0; + bool liveVerb = (_logc->lcbits & 0xFFFF & LC_Liveness) > 0; + ) + + /* BEGIN decorative preamble */ + verbose_only( + if (anyVerb) { + _logc->printf("========================================" + "========================================\n"); + _logc->printf("=== BEGIN LIR::compile(%p, %p)\n", + (void*)this, (void*)frag); + _logc->printf("===\n"); + }) + /* END decorative preamble */ + + verbose_only( if (liveVerb) { + _logc->printf("\n"); + _logc->printf("=== Results of liveness analysis:\n"); + _logc->printf("===\n"); + LirReader br(frag->lastIns); + LirFilter* lir = &br; + if (optimize) { + StackFilter* sf = new (alloc) StackFilter(lir, alloc, frag->lirbuf->sp); + lir = sf; + } + live(lir, alloc, frag, _logc); + }) + + /* Set up the generic text output cache for the assembler */ + verbose_only( StringList asmOutput(alloc); ) + verbose_only( _outputCache = &asmOutput; ) + + beginAssembly(frag); + if (error()) + return; + + //_logc->printf("recompile trigger %X kind %d\n", (int)frag, frag->kind); + + verbose_only( if (anyVerb) { + _logc->printf("=== Translating LIR fragments into assembly:\n"); + }) + + // now the the main trunk + verbose_only( RefBuf b; ) + verbose_only( if (anyVerb) { + _logc->printf("=== -- Compile trunk %s: begin\n", printer->formatAddr(&b, frag)); + }) + + // Used for debug printing, if needed + debug_only(ValidateReader *validate = NULL;) + verbose_only( + ReverseLister *pp_init = NULL; + ReverseLister *pp_after_sf = NULL; + ) + + // The LIR passes through these filters as listed in this + // function, viz, top to bottom. + + // set up backwards pipeline: assembler <- StackFilter <- LirReader + LirFilter* lir = new (alloc) LirReader(frag->lastIns); + +#ifdef DEBUG + // VALIDATION + validate = new (alloc) ValidateReader(lir); + lir = validate; +#endif + + // INITIAL PRINTING + verbose_only( if (_logc->lcbits & LC_ReadLIR) { + pp_init = new (alloc) ReverseLister(lir, alloc, frag->lirbuf->printer, _logc, + "Initial LIR"); + lir = pp_init; + }) + + // STACKFILTER + if (optimize) { + StackFilter* stackfilter = new (alloc) StackFilter(lir, alloc, frag->lirbuf->sp); + lir = stackfilter; + } + + verbose_only( if (_logc->lcbits & LC_AfterSF) { + pp_after_sf = new (alloc) ReverseLister(lir, alloc, frag->lirbuf->printer, _logc, + "After StackFilter"); + lir = pp_after_sf; + }) + + assemble(frag, lir); + + // If we were accumulating debug info in the various ReverseListers, + // call finish() to emit whatever contents they have accumulated. + verbose_only( + if (pp_init) pp_init->finish(); + if (pp_after_sf) pp_after_sf->finish(); + ) + + verbose_only( if (anyVerb) { + _logc->printf("=== -- Compile trunk %s: end\n", printer->formatAddr(&b, frag)); + }) + + endAssembly(frag); + + // Reverse output so that assembly is displayed low-to-high. + // Up to this point, _outputCache has been non-NULL, and so has been + // accumulating output. Now we set it to NULL, traverse the entire + // list of stored strings, and hand them a second time to output. + // Since _outputCache is now NULL, outputf just hands these strings + // directly onwards to _logc->printf. + verbose_only( if (anyVerb) { + _logc->printf("\n"); + _logc->printf("=== Aggregated assembly output: BEGIN\n"); + _logc->printf("===\n"); + _outputCache = 0; + for (Seq* p = asmOutput.get(); p != NULL; p = p->tail) { + char *str = p->head; + outputf(" %s", str); + } + _logc->printf("===\n"); + _logc->printf("=== Aggregated assembly output: END\n"); + }); + + if (error()) + frag->fragEntry = 0; + + verbose_only( frag->nCodeBytes += codeBytes; ) + verbose_only( frag->nExitBytes += exitBytes; ) + + /* BEGIN decorative postamble */ + verbose_only( if (anyVerb) { + _logc->printf("\n"); + _logc->printf("===\n"); + _logc->printf("=== END LIR::compile(%p, %p)\n", + (void*)this, (void*)frag); + _logc->printf("========================================" + "========================================\n"); + _logc->printf("\n"); + }); + /* END decorative postamble */ + } + + void Assembler::beginAssembly(Fragment *frag) + { + verbose_only( codeBytes = 0; ) + verbose_only( exitBytes = 0; ) + + reset(); + + NanoAssert(codeList == 0); + NanoAssert(codeStart == 0); + NanoAssert(codeEnd == 0); + NanoAssert(exitStart == 0); + NanoAssert(exitEnd == 0); + NanoAssert(_nIns == 0); + NanoAssert(_nExitIns == 0); + + _thisfrag = frag; + _inExit = false; + + setError(None); + + // native code gen buffer setup + nativePageSetup(); + + // make sure we got memory at least one page + if (error()) return; + + _epilogue = NULL; + verbose_only( _nInsAfter = _nIns; ) + + nBeginAssembly(); + } + + void Assembler::assemble(Fragment* frag, LirFilter* reader) + { + if (error()) return; + _thisfrag = frag; + + // check the fragment is starting out with a sane profiling state + verbose_only( NanoAssert(frag->nStaticExits == 0); ) + verbose_only( NanoAssert(frag->nCodeBytes == 0); ) + verbose_only( NanoAssert(frag->nExitBytes == 0); ) + verbose_only( NanoAssert(frag->profCount == 0); ) + verbose_only( if (_logc->lcbits & LC_FragProfile) + NanoAssert(frag->profFragID > 0); + else + NanoAssert(frag->profFragID == 0); ) + + _inExit = false; + + gen(reader); + + if (!error()) { + // patch all branches + NInsMap::Iter iter(_patches); + while (iter.next()) { + NIns* where = iter.key(); + LIns* target = iter.value(); + if (target->isop(LIR_jtbl)) { + // Need to patch up a whole jump table, 'where' is the table. + LIns *jtbl = target; + NIns** native_table = (NIns**) (void *) where; + for (uint32_t i = 0, n = jtbl->getTableSize(); i < n; i++) { + LabelState* lstate = _labels.get(jtbl->getTarget(i)); + NIns* ntarget = lstate->addr; + if (ntarget) { + native_table[i] = ntarget; + } else { + setError(UnknownBranch); + break; + } + } + } else { + // target is a label for a single-target branch + LabelState *lstate = _labels.get(target); + NIns* ntarget = lstate->addr; + if (ntarget) { + nPatchBranch(where, ntarget); + } else { + setError(UnknownBranch); + break; + } + } + } + } + } + + void Assembler::cleanupAfterError() + { + _codeAlloc.freeAll(codeList); + if (_nExitIns) + _codeAlloc.free(exitStart, exitEnd); + _codeAlloc.free(codeStart, codeEnd); + codeList = NULL; + _codeAlloc.markAllExec(); // expensive but safe, we mark all code pages R-X + } + + void Assembler::endAssembly(Fragment* frag) + { + // don't try to patch code if we are in an error state since we might have partially + // overwritten the code cache already + if (error()) { + // something went wrong, release all allocated code memory + cleanupAfterError(); + return; + } + + NIns* fragEntry = genPrologue(); + verbose_only( asm_output("[prologue]"); ) + + debug_only(_activation.checkForResourceLeaks()); + + NanoAssert(!_inExit); + // save used parts of current block on fragment's code list, free the rest +#if defined(NANOJIT_ARM) || defined(NANOJIT_MIPS) + // [codeStart, _nSlot) ... gap ... [_nIns, codeEnd) + if (_nExitIns) { + _codeAlloc.addRemainder(codeList, exitStart, exitEnd, _nExitSlot, _nExitIns); + verbose_only( exitBytes -= (_nExitIns - _nExitSlot) * sizeof(NIns); ) + } + _codeAlloc.addRemainder(codeList, codeStart, codeEnd, _nSlot, _nIns); + verbose_only( codeBytes -= (_nIns - _nSlot) * sizeof(NIns); ) +#else + // [codeStart ... gap ... [_nIns, codeEnd)) + if (_nExitIns) { + _codeAlloc.addRemainder(codeList, exitStart, exitEnd, exitStart, _nExitIns); + verbose_only( exitBytes -= (_nExitIns - exitStart) * sizeof(NIns); ) + } + _codeAlloc.addRemainder(codeList, codeStart, codeEnd, codeStart, _nIns); + verbose_only( codeBytes -= (_nIns - codeStart) * sizeof(NIns); ) +#endif + + // note: the code pages are no longer writable from this point onwards + _codeAlloc.markExec(codeList); + + // at this point all our new code is in the d-cache and not the i-cache, + // so flush the i-cache on cpu's that need it. + CodeAlloc::flushICache(codeList); + + // save entry point pointers + frag->fragEntry = fragEntry; + frag->setCode(_nIns); + +#ifdef VMCFG_VTUNE + if (vtuneHandle) + { + vtuneEnd(vtuneHandle, codeEnd); + vtuneStart(vtuneHandle, _nIns); + } +#endif + + PERFM_NVPROF("code", CodeAlloc::size(codeList)); + +#ifdef NANOJIT_IA32 + NanoAssertMsgf(_fpuStkDepth == 0,"_fpuStkDepth %d\n",_fpuStkDepth); +#endif + + debug_only( pageValidate(); ) + NanoAssert(_branchStateMap.isEmpty()); + } + + void Assembler::releaseRegisters() + { + RegisterMask active = _allocator.activeMask(); + for (Register r = lsReg(active); active; r = nextLsReg(active, r)) + { + LIns *ins = _allocator.getActive(r); + // Clear reg allocation, preserve stack allocation. + _allocator.retire(r); + NanoAssert(r == ins->getReg()); + ins->clearReg(); + } + } + +#ifdef PERFM +#define countlir_live() _nvprof("lir-live",1) +#define countlir_ret() _nvprof("lir-ret",1) +#define countlir_alloc() _nvprof("lir-alloc",1) +#define countlir_var() _nvprof("lir-var",1) +#define countlir_use() _nvprof("lir-use",1) +#define countlir_def() _nvprof("lir-def",1) +#define countlir_imm() _nvprof("lir-imm",1) +#define countlir_param() _nvprof("lir-param",1) +#define countlir_cmov() _nvprof("lir-cmov",1) +#define countlir_ld() _nvprof("lir-ld",1) +#define countlir_ldq() _nvprof("lir-ldq",1) +#define countlir_alu() _nvprof("lir-alu",1) +#define countlir_qjoin() _nvprof("lir-qjoin",1) +#define countlir_qlo() _nvprof("lir-qlo",1) +#define countlir_qhi() _nvprof("lir-qhi",1) +#define countlir_fpu() _nvprof("lir-fpu",1) +#define countlir_st() _nvprof("lir-st",1) +#define countlir_stq() _nvprof("lir-stq",1) +#define countlir_jmp() _nvprof("lir-jmp",1) +#define countlir_jcc() _nvprof("lir-jcc",1) +#define countlir_label() _nvprof("lir-label",1) +#define countlir_xcc() _nvprof("lir-xcc",1) +#define countlir_x() _nvprof("lir-x",1) +#define countlir_call() _nvprof("lir-call",1) +#define countlir_jtbl() _nvprof("lir-jtbl",1) +#else +#define countlir_live() +#define countlir_ret() +#define countlir_alloc() +#define countlir_var() +#define countlir_use() +#define countlir_def() +#define countlir_imm() +#define countlir_param() +#define countlir_cmov() +#define countlir_ld() +#define countlir_ldq() +#define countlir_alu() +#define countlir_qjoin() +#define countlir_qlo() +#define countlir_qhi() +#define countlir_fpu() +#define countlir_st() +#define countlir_stq() +#define countlir_jmp() +#define countlir_jcc() +#define countlir_label() +#define countlir_xcc() +#define countlir_x() +#define countlir_call() +#define countlir_jtbl() +#endif + + void Assembler::asm_jmp(LIns* ins, InsList& pending_lives) + { + NanoAssert((ins->isop(LIR_j) && !ins->oprnd1()) || + (ins->isop(LIR_jf) && ins->oprnd1()->isImmI(0)) || + (ins->isop(LIR_jt) && ins->oprnd1()->isImmI(1))); + + countlir_jmp(); + LIns* to = ins->getTarget(); + LabelState *label = _labels.get(to); + // The jump is always taken so whatever register state we + // have from downstream code, is irrelevant to code before + // this jump. So clear it out. We will pick up register + // state from the jump target, if we have seen that label. + releaseRegisters(); +#ifdef NANOJIT_IA32 + // Unreachable, so assume correct stack depth. + debug_only( _fpuStkDepth = 0; ) +#endif + if (label && label->addr) { + // Forward jump - pick up register state from target. + unionRegisterState(label->regs); +#ifdef NANOJIT_IA32 + // Set stack depth according to the register state we just loaded, + // negating the effect of any unreachable x87 stack pop that might + // have been emitted by unionRegisterState(). + debug_only( _fpuStkDepth = (_allocator.getActive(FST0) ? -1 : 0); ) +#endif + JMP(label->addr); + } + else { + // Backwards jump. + handleLoopCarriedExprs(pending_lives); + if (!label) { + // save empty register state at loop header + _labels.add(to, 0, _allocator); + } + else { + intersectRegisterState(label->regs); +#ifdef NANOJIT_IA32 + debug_only( _fpuStkDepth = (_allocator.getActive(FST0) ? -1 : 0); ) +#endif + } + JMP(0); + _patches.put(_nIns, to); + } + } + + void Assembler::asm_jcc(LIns* ins, InsList& pending_lives) + { + bool branchOnFalse = (ins->opcode() == LIR_jf); + LIns* cond = ins->oprnd1(); + if (cond->isImmI()) { + if ((!branchOnFalse && !cond->immI()) || (branchOnFalse && cond->immI())) { + // jmp never taken, not needed + } else { + asm_jmp(ins, pending_lives); // jmp always taken + } + return; + } + + // Changes to the logic below will likely need to be propagated to Assembler::asm_jov(). + + countlir_jcc(); + LIns* to = ins->getTarget(); + LabelState *label = _labels.get(to); + if (label && label->addr) { + // Forward jump to known label. Need to merge with label's register state. + unionRegisterState(label->regs); + asm_branch(branchOnFalse, cond, label->addr); + } + else { + // Back edge. + handleLoopCarriedExprs(pending_lives); + if (!label) { + // Evict all registers, most conservative approach. + evictAllActiveRegs(); + _labels.add(to, 0, _allocator); + } + else { + // Evict all registers, most conservative approach. + intersectRegisterState(label->regs); + } + NIns *branch = asm_branch(branchOnFalse, cond, 0); + _patches.put(branch,to); + } + } + + void Assembler::asm_jov(LIns* ins, InsList& pending_lives) + { + // The caller is responsible for countlir_* profiling, unlike + // asm_jcc above. The reason for this is that asm_jov may not be + // be called if the instruction is dead, and it is our convention + // to count such instructions anyway. + LOpcode op = ins->opcode(); + LIns* to = ins->getTarget(); + LabelState *label = _labels.get(to); + if (label && label->addr) { + // forward jump to known label. need to merge with label's register state. + unionRegisterState(label->regs); + asm_branch_ov(op, label->addr); + } + else { + // back edge. + handleLoopCarriedExprs(pending_lives); + if (!label) { + // evict all registers, most conservative approach. + evictAllActiveRegs(); + _labels.add(to, 0, _allocator); + } + else { + // evict all registers, most conservative approach. + intersectRegisterState(label->regs); + } + NIns *branch = asm_branch_ov(op, 0); + _patches.put(branch,to); + } + } + + void Assembler::asm_x(LIns* ins) + { + verbose_only( _thisfrag->nStaticExits++; ) + countlir_x(); + // Generate the side exit branch on the main trace. + NIns *exit = asm_exit(ins); + JMP(exit); + } + + void Assembler::asm_xcc(LIns* ins) + { + LIns* cond = ins->oprnd1(); + if (cond->isImmI()) { + if ((ins->isop(LIR_xt) && !cond->immI()) || (ins->isop(LIR_xf) && cond->immI())) { + // guard never taken, not needed + } else { + asm_x(ins); // guard always taken + } + return; + } + + verbose_only( _thisfrag->nStaticExits++; ) + countlir_xcc(); + // We only support cmp with guard right now, also assume it is 'close' + // and only emit the branch. + NIns* exit = asm_exit(ins); // does intersectRegisterState() + asm_branch(ins->opcode() == LIR_xf, cond, exit); + } + + // helper function for nop insertion feature that results in no more + // than 1 no-op instruction insertion every 128-1151 Bytes + static inline uint32_t noiseForNopInsertion(Noise* n) { + return n->getValue(1023) + 128; + } + + void Assembler::gen(LirFilter* reader) + { + NanoAssert(_thisfrag->nStaticExits == 0); + + InsList pending_lives(alloc); + + NanoAssert(!error()); + + // compiler hardening setup + NIns* priorIns = _nIns; + int32_t nopInsertTrigger = hardenNopInsertion(_config) ? noiseForNopInsertion(_noise): 0; + + // What's going on here: we're visiting all the LIR instructions in + // the buffer, working strictly backwards in buffer-order, and + // generating machine instructions for them as we go. + // + // For each LIns, we first check if it's live. If so we mark its + // operands as also live, and then generate code for it *if + // necessary*. It may not be necessary if the instruction is an + // expression and code has already been generated for all its uses in + // combination with previously handled instructions (ins->isExtant() + // will return false if this is so). + + // Note that the backwards code traversal can make register allocation + // confusing. (For example, we restore a value before we spill it!) + // In particular, words like "before" and "after" must be used very + // carefully -- their meaning at regalloc-time is opposite to their + // meaning at run-time. We use the term "pre-regstate" to refer to + // the register allocation state that occurs prior to an instruction's + // execution, and "post-regstate" to refer to the state that occurs + // after an instruction's execution, e.g.: + // + // pre-regstate: ebx(ins) + // instruction: mov eax, ebx // mov dst, src + // post-regstate: eax(ins) + // + // At run-time, the instruction updates the pre-regstate into the + // post-regstate (and these states are the real machine's regstates). + // But when allocating registers, because we go backwards, the + // pre-regstate is constructed from the post-regstate (and these + // regstates are those stored in RegAlloc). + // + // One consequence of generating code backwards is that we tend to + // both spill and restore registers as early (at run-time) as + // possible; this is good for tolerating memory latency. If we + // generated code forwards, we would expect to both spill and restore + // registers as late (at run-time) as possible; this might be better + // for reducing register pressure. + + // The trace must end with one of these opcodes. Mark it as live. + NanoAssert(reader->finalIns()->isop(LIR_x) || + reader->finalIns()->isop(LIR_xtbl) || + reader->finalIns()->isRet() || + isLiveOpcode(reader->finalIns()->opcode())); + + for (currIns = reader->read(); !currIns->isop(LIR_start); currIns = reader->read()) + { + LIns* ins = currIns; // give it a shorter name for local use + + if (!ins->isLive()) { + NanoAssert(!ins->isExtant()); + continue; + } + +#ifdef NJ_VERBOSE + // Output the post-regstate (registers and/or activation). + // Because asm output comes in reverse order, doing it now means + // it is printed after the LIR and native code, exactly when the + // post-regstate should be shown. + if ((_logc->lcbits & LC_Native) && (_logc->lcbits & LC_Activation)) + printActivationState(); + if ((_logc->lcbits & LC_Native) && (_logc->lcbits & LC_RegAlloc)) + printRegState(); +#endif + + // compiler hardening technique that inserts no-op instructions in the compiled method when nopInsertTrigger < 0 + if (hardenNopInsertion(_config)) + { + size_t delta = (uintptr_t)priorIns - (uintptr_t)_nIns; // # bytes that have been emitted since last go-around + + // if no codeList then we know priorIns and _nIns are on same page, otherwise make sure priorIns was not in the previous code block + if (!codeList || !codeList->isInBlock(priorIns)) { + NanoAssert(delta < VMPI_getVMPageSize()); // sanity check + nopInsertTrigger -= (int32_t) delta; + if (nopInsertTrigger < 0) + { + nopInsertTrigger = noiseForNopInsertion(_noise); + asm_insert_random_nop(); + PERFM_NVPROF("hardening:nop-insert", 1); + } + } + priorIns = _nIns; + } + + LOpcode op = ins->opcode(); + switch (op) + { + default: + NanoAssertMsgf(false, "unsupported LIR instruction: %d\n", op); + break; + + case LIR_regfence: + evictAllActiveRegs(); + break; + + case LIR_livei: + CASE64(LIR_liveq:) + case LIR_lived: { + countlir_live(); + LIns* op1 = ins->oprnd1(); + op1->setResultLive(); + // LIR_allocp's are meant to live until the point of the + // LIR_livep instruction, marking other expressions as + // live ensures that they remain so at loop bottoms. + // LIR_allocp areas require special treatment because they + // are accessed indirectly and the indirect accesses are + // invisible to the assembler, other than via LIR_livep. + // Other expression results are only accessed directly in + // ways that are visible to the assembler, so extending + // those expression's lifetimes past the last loop edge + // isn't necessary. + if (op1->isop(LIR_allocp)) { + findMemFor(op1); + } else { + pending_lives.add(ins); + } + break; + } + + case LIR_reti: + CASE64(LIR_retq:) + case LIR_retd: + countlir_ret(); + ins->oprnd1()->setResultLive(); + asm_ret(ins); + break; + + // Allocate some stack space. The value of this instruction + // is the address of the stack space. + case LIR_allocp: + countlir_alloc(); + if (ins->isExtant()) { + NanoAssert(ins->isInAr()); + if (ins->isInReg()) + evict(ins); + freeResourcesOf(ins); + } + break; + + case LIR_immi: + countlir_imm(); + if (ins->isExtant()) { + asm_immi(ins); + } + break; + +#ifdef NANOJIT_64BIT + case LIR_immq: + countlir_imm(); + if (ins->isExtant()) { + asm_immq(ins); + } + break; +#endif + case LIR_immd: + countlir_imm(); + if (ins->isExtant()) { + asm_immd(ins); + } + break; + + case LIR_paramp: + countlir_param(); + if (ins->isExtant()) { + asm_param(ins); + } + break; + +#if NJ_SOFTFLOAT_SUPPORTED + case LIR_hcalli: { + LIns* op1 = ins->oprnd1(); + op1->setResultLive(); + if (ins->isExtant()) { + // Return result of quad-call in register. + deprecated_prepResultReg(ins, rmask(retRegs[1])); + // If hi half was used, we must use the call to ensure it happens. + findSpecificRegFor(op1, retRegs[0]); + } + break; + } + + case LIR_dlo2i: + countlir_qlo(); + ins->oprnd1()->setResultLive(); + if (ins->isExtant()) { + asm_qlo(ins); + } + break; + + case LIR_dhi2i: + countlir_qhi(); + ins->oprnd1()->setResultLive(); + if (ins->isExtant()) { + asm_qhi(ins); + } + break; + + case LIR_ii2d: + countlir_qjoin(); + ins->oprnd1()->setResultLive(); + ins->oprnd2()->setResultLive(); + if (ins->isExtant()) { + asm_qjoin(ins); + } + break; +#endif + case LIR_cmovi: + CASE64(LIR_cmovq:) + case LIR_cmovd: + countlir_cmov(); + ins->oprnd1()->setResultLive(); + ins->oprnd2()->setResultLive(); + ins->oprnd3()->setResultLive(); + if (ins->isExtant()) { + asm_cmov(ins); + } + break; + + case LIR_lduc2ui: + case LIR_ldus2ui: + case LIR_ldc2i: + case LIR_lds2i: + case LIR_ldi: + countlir_ld(); + ins->oprnd1()->setResultLive(); + if (ins->isExtant()) { + asm_load32(ins); + } + break; + + CASE64(LIR_ldq:) + case LIR_ldd: + case LIR_ldf2d: + countlir_ldq(); + ins->oprnd1()->setResultLive(); + if (ins->isExtant()) { + asm_load64(ins); + } + break; + + case LIR_negi: + case LIR_noti: + countlir_alu(); + ins->oprnd1()->setResultLive(); + if (ins->isExtant()) { + asm_neg_not(ins); + } + break; + +#if defined NANOJIT_64BIT + case LIR_addq: + case LIR_subq: + case LIR_andq: + case LIR_lshq: + case LIR_rshuq: + case LIR_rshq: + case LIR_orq: + case LIR_xorq: + countlir_alu(); + ins->oprnd1()->setResultLive(); + ins->oprnd2()->setResultLive(); + if (ins->isExtant()) { + asm_qbinop(ins); + } + break; +#endif + + case LIR_addi: + case LIR_subi: + case LIR_muli: + case LIR_andi: + case LIR_ori: + case LIR_xori: + case LIR_lshi: + case LIR_rshi: + case LIR_rshui: + CASE86(LIR_divi:) + countlir_alu(); + ins->oprnd1()->setResultLive(); + ins->oprnd2()->setResultLive(); + if (ins->isExtant()) { + asm_arith(ins); + } + break; + +#if defined NANOJIT_IA32 || defined NANOJIT_X64 + CASE86(LIR_modi:) + countlir_alu(); + ins->oprnd1()->setResultLive(); + if (ins->isExtant()) { + asm_arith(ins); + } + break; +#endif + + case LIR_negd: + countlir_fpu(); + ins->oprnd1()->setResultLive(); + if (ins->isExtant()) { + asm_fneg(ins); + } + break; + + case LIR_addd: + case LIR_subd: + case LIR_muld: + case LIR_divd: + countlir_fpu(); + ins->oprnd1()->setResultLive(); + ins->oprnd2()->setResultLive(); + if (ins->isExtant()) { + asm_fop(ins); + } + break; + + case LIR_i2d: + countlir_fpu(); + ins->oprnd1()->setResultLive(); + if (ins->isExtant()) { + asm_i2d(ins); + } + break; + + case LIR_ui2d: + countlir_fpu(); + ins->oprnd1()->setResultLive(); + if (ins->isExtant()) { + asm_ui2d(ins); + } + break; + + case LIR_d2i: + countlir_fpu(); + ins->oprnd1()->setResultLive(); + if (ins->isExtant()) { + asm_d2i(ins); + } + break; + +#ifdef NANOJIT_64BIT + case LIR_i2q: + case LIR_ui2uq: + countlir_alu(); + ins->oprnd1()->setResultLive(); + if (ins->isExtant()) { + asm_ui2uq(ins); + } + break; + + case LIR_q2i: + countlir_alu(); + ins->oprnd1()->setResultLive(); + if (ins->isExtant()) { + asm_q2i(ins); + } + break; + + case LIR_dasq: + countlir_alu(); + ins->oprnd1()->setResultLive(); + if (ins->isExtant()) { + asm_dasq(ins); + } + break; + + case LIR_qasd: + countlir_alu(); + ins->oprnd1()->setResultLive(); + if (ins->isExtant()) { + asm_qasd(ins); + } + break; +#endif + case LIR_sti2c: + case LIR_sti2s: + case LIR_sti: + countlir_st(); + ins->oprnd1()->setResultLive(); + ins->oprnd2()->setResultLive(); + asm_store32(op, ins->oprnd1(), ins->disp(), ins->oprnd2()); + break; + + CASE64(LIR_stq:) + case LIR_std: + case LIR_std2f: { + countlir_stq(); + ins->oprnd1()->setResultLive(); + ins->oprnd2()->setResultLive(); + LIns* value = ins->oprnd1(); + LIns* base = ins->oprnd2(); + int dr = ins->disp(); +#if NJ_SOFTFLOAT_SUPPORTED + if (value->isop(LIR_ii2d) && op == LIR_std) + { + // This is correct for little-endian only. + asm_store32(LIR_sti, value->oprnd1(), dr, base); + asm_store32(LIR_sti, value->oprnd2(), dr+4, base); + } + else +#endif + { + asm_store64(op, value, dr, base); + } + break; + } + + case LIR_j: + asm_jmp(ins, pending_lives); + break; + + case LIR_jt: + case LIR_jf: + ins->oprnd1()->setResultLive(); + asm_jcc(ins, pending_lives); + break; + + #if NJ_JTBL_SUPPORTED + case LIR_jtbl: { + countlir_jtbl(); + ins->oprnd1()->setResultLive(); + // Multiway jump can contain both forward and backward jumps. + // Out of range indices aren't allowed or checked. + // Code after this jtbl instruction is unreachable. + releaseRegisters(); + NanoAssert(_allocator.activeMask() == 0); + + uint32_t count = ins->getTableSize(); + bool has_back_edges = false; + + // Merge the regstates of labels we have already seen. + for (uint32_t i = count; i-- > 0;) { + LIns* to = ins->getTarget(i); + LabelState *lstate = _labels.get(to); + if (lstate) { + unionRegisterState(lstate->regs); + verbose_only( RefBuf b; ) + asm_output(" %u: [&%s]", i, _thisfrag->lirbuf->printer->formatRef(&b, to)); + } else { + has_back_edges = true; + } + } + asm_output("forward edges"); + + // In a multi-way jump, the register allocator has no ability to deal + // with two existing edges that have conflicting register assignments, unlike + // a conditional branch where code can be inserted on the fall-through path + // to reconcile registers. So, frontends *must* insert LIR_regfence at labels of + // forward jtbl jumps. Check here to make sure no registers were picked up from + // any forward edges. + NanoAssert(_allocator.activeMask() == 0); + + if (has_back_edges) { + handleLoopCarriedExprs(pending_lives); + // save merged (empty) register state at target labels we haven't seen yet + for (uint32_t i = count; i-- > 0;) { + LIns* to = ins->getTarget(i); + LabelState *lstate = _labels.get(to); + if (!lstate) { + _labels.add(to, 0, _allocator); + verbose_only( RefBuf b; ) + asm_output(" %u: [&%s]", i, _thisfrag->lirbuf->printer->formatRef(&b, to)); + } + } + asm_output("backward edges"); + } + + // Emit the jump instruction, which allocates 1 register for the jump index. + NIns** native_table = new (_dataAlloc) NIns*[count]; + asm_output("[%p]:", (void*)native_table); + _patches.put((NIns*)native_table, ins); + asm_jtbl(ins, native_table); + break; + } + #endif + + case LIR_label: { + countlir_label(); + LabelState *label = _labels.get(ins); + // add profiling inc, if necessary. + verbose_only( if (_logc->lcbits & LC_FragProfile) { + if (ins == _thisfrag->loopLabel) + asm_inc_m32(& _thisfrag->profCount); + }) + if (!label) { + // label seen first, normal target of forward jump, save addr & allocator + _labels.add(ins, _nIns, _allocator); + } + else { + // we're at the top of a loop + NanoAssert(label->addr == 0); + //evictAllActiveRegs(); + intersectRegisterState(label->regs); + label->addr = _nIns; + } + verbose_only( + RefBuf b; + if (_logc->lcbits & LC_Native) { + asm_output("[%s]", _thisfrag->lirbuf->printer->formatRef(&b, ins)); + }) + break; + } + + case LIR_xbarrier: + break; + + case LIR_xtbl: { + ins->oprnd1()->setResultLive(); +#ifdef NANOJIT_IA32 + NIns* exit = asm_exit(ins); // does intersectRegisterState() + asm_switch(ins, exit); +#else + NanoAssertMsg(0, "Not supported for this architecture"); +#endif + break; + } + + case LIR_xt: + case LIR_xf: + ins->oprnd1()->setResultLive(); + asm_xcc(ins); + break; + + case LIR_x: + asm_x(ins); + break; + + case LIR_addxovi: + case LIR_subxovi: + case LIR_mulxovi: + verbose_only( _thisfrag->nStaticExits++; ) + countlir_xcc(); + countlir_alu(); + ins->oprnd1()->setResultLive(); + ins->oprnd2()->setResultLive(); + if (ins->isExtant()) { + NIns* exit = asm_exit(ins); // does intersectRegisterState() + asm_branch_ov(op, exit); + asm_arith(ins); + } + break; + + case LIR_addjovi: + case LIR_subjovi: + case LIR_muljovi: + countlir_jcc(); + countlir_alu(); + ins->oprnd1()->setResultLive(); + ins->oprnd2()->setResultLive(); + if (ins->isExtant()) { + asm_jov(ins, pending_lives); + asm_arith(ins); + } + break; + +#ifdef NANOJIT_64BIT + case LIR_addjovq: + case LIR_subjovq: + countlir_jcc(); + countlir_alu(); + ins->oprnd1()->setResultLive(); + ins->oprnd2()->setResultLive(); + if (ins->isExtant()) { + asm_jov(ins, pending_lives); + asm_qbinop(ins); + } + break; +#endif + + case LIR_eqd: + case LIR_led: + case LIR_ltd: + case LIR_gtd: + case LIR_ged: + countlir_fpu(); + ins->oprnd1()->setResultLive(); + ins->oprnd2()->setResultLive(); + if (ins->isExtant()) { + asm_condd(ins); + } + break; + + case LIR_eqi: + case LIR_lei: + case LIR_lti: + case LIR_gti: + case LIR_gei: + case LIR_ltui: + case LIR_leui: + case LIR_gtui: + case LIR_geui: + CASE64(LIR_eqq:) + CASE64(LIR_leq:) + CASE64(LIR_ltq:) + CASE64(LIR_gtq:) + CASE64(LIR_geq:) + CASE64(LIR_ltuq:) + CASE64(LIR_leuq:) + CASE64(LIR_gtuq:) + CASE64(LIR_geuq:) + countlir_alu(); + ins->oprnd1()->setResultLive(); + ins->oprnd2()->setResultLive(); + if (ins->isExtant()) { + asm_cond(ins); + } + break; + + case LIR_callv: + case LIR_calli: + CASE64(LIR_callq:) + case LIR_calld: + countlir_call(); + for (int i = 0, argc = ins->argc(); i < argc; i++) + ins->arg(i)->setResultLive(); + + // You might think that a call cannot be pure, live, + // and-not-extant, because there's no way the codegen + // for a call can be folded into the codegen of another + // LIR instruction. However, it's possible that a pure + // call, C, has a result that is only be used (directly + // or indirectly) in a section of code that is unreachable, + // e.g. due to an always-taken branch. C is dead, but the + // assembly pass doesn't realize is dead. So C may end + // up non-extant, in which case we don't generate code + // for it. See bug 620406 for an example. + if (!ins->callInfo()->_isPure || ins->isExtant()) { + asm_call(ins); + } + break; + + #ifdef VMCFG_VTUNE + case LIR_file: { + // we traverse backwards so we are now hitting the file + // that is associated with a bunch of LIR_lines we already have seen + if (vtuneHandle) { + void * currentFile = (void *) ins->oprnd1()->immI(); + vtuneFile(vtuneHandle, currentFile); + } + break; + } + case LIR_line: { + // add a new table entry, we don't yet knwo which file it belongs + // to so we need to add it to the update table too + // note the alloc, actual act is delayed; see above + if (vtuneHandle) { + uint32_t currentLine = (uint32_t) ins->oprnd1()->immI(); + vtuneLine(vtuneHandle, currentLine, _nIns); + } + break; + } + #endif // VMCFG_VTUNE + + case LIR_comment: + // Do nothing. + break; + } + +#ifdef NJ_VERBOSE + // We do final LIR printing inside this loop to avoid printing + // dead LIR instructions. We print the LIns after generating the + // code. This ensures that the LIns will appear in debug output + // *before* the native code, because Assembler::outputf() + // prints everything in reverse. + // + if (_logc->lcbits & LC_AfterDCE) { + InsBuf b; + LInsPrinter* printer = _thisfrag->lirbuf->printer; + if (ins->isop(LIR_comment)) + outputf("%s", printer->formatIns(&b, ins)); + else + outputf(" %s", printer->formatIns(&b, ins)); + } +#endif + + if (error()) + return; + + // check that all is well (don't check in exit paths since its more complicated) + debug_only( pageValidate(); ) + debug_only( resourceConsistencyCheck(); ) + } + } + + /* + * Write a jump table for the given SwitchInfo and store the table + * address in the SwitchInfo. Every entry will initially point to + * target. + */ + void Assembler::emitJumpTable(SwitchInfo* si, NIns* target) + { + si->table = (NIns **) alloc.alloc(si->count * sizeof(NIns*)); + for (uint32_t i = 0; i < si->count; ++i) + si->table[i] = target; + } + + void Assembler::assignSavedRegs() + { + // Restore saved regsters. + LirBuffer *b = _thisfrag->lirbuf; + for (int i=0, n = NumSavedRegs; i < n; i++) { + LIns *p = b->savedRegs[i]; + if (p) + findSpecificRegForUnallocated(p, savedRegs[p->paramArg()]); + } + } + + void Assembler::reserveSavedRegs() + { + LirBuffer *b = _thisfrag->lirbuf; + for (int i = 0, n = NumSavedRegs; i < n; i++) { + LIns *ins = b->savedRegs[i]; + if (ins) + findMemFor(ins); + } + } + + void Assembler::assignParamRegs() + { + LIns* state = _thisfrag->lirbuf->state; + if (state) + findSpecificRegForUnallocated(state, argRegs[state->paramArg()]); + LIns* param1 = _thisfrag->lirbuf->param1; + if (param1) + findSpecificRegForUnallocated(param1, argRegs[param1->paramArg()]); + } + + void Assembler::handleLoopCarriedExprs(InsList& pending_lives) + { + // ensure that exprs spanning the loop are marked live at the end of the loop + reserveSavedRegs(); + for (Seq *p = pending_lives.get(); p != NULL; p = p->tail) { + LIns *ins = p->head; + NanoAssert(isLiveOpcode(ins->opcode())); + LIns *op1 = ins->oprnd1(); + // Must findMemFor even if we're going to findRegFor; loop-carried + // operands may spill on another edge, and we need them to always + // spill to the same place. +#if NJ_USES_IMMD_POOL + // Exception: if float constants are true constants, we should + // never call findMemFor on those ops. + if (!op1->isImmD()) +#endif + { + findMemFor(op1); + } + if (!op1->isImmAny()) + findRegFor(op1, ins->isop(LIR_lived) ? FpRegs : GpRegs); + } + + // clear this list since we have now dealt with those lifetimes. extending + // their lifetimes again later (earlier in the code) serves no purpose. + pending_lives.clear(); + } + + void AR::freeEntryAt(uint32_t idx) + { + NanoAssert(idx > 0 && idx <= _highWaterMark); + + // NB: this loop relies on using entry[0] being NULL, + // so that we are guaranteed to terminate + // without access negative entries. + LIns* i = _entries[idx]; + NanoAssert(i != NULL); + do { + _entries[idx] = NULL; + idx--; + } while (_entries[idx] == i); + } + +#ifdef NJ_VERBOSE + void Assembler::printRegState() + { + char* s = &outline[0]; + VMPI_memset(s, ' ', 26); s[26] = '\0'; + s += VMPI_strlen(s); + VMPI_sprintf(s, "RR"); + s += VMPI_strlen(s); + + RegisterMask active = _allocator.activeMask(); + for (Register r = lsReg(active); active != 0; r = nextLsReg(active, r)) { + LIns *ins = _allocator.getActive(r); + NanoAssertMsg(!_allocator.isFree(r), + "Coding error; register is both free and active! " ); + RefBuf b; + const char* n = _thisfrag->lirbuf->printer->formatRef(&b, ins); + + if (ins->isop(LIR_paramp) && ins->paramKind()==1 && + r == Assembler::savedRegs[ins->paramArg()]) + { + // dont print callee-saved regs that arent used + continue; + } + + VMPI_sprintf(s, " %s(%s)", gpn(r), n); + s += VMPI_strlen(s); + } + output(); + } + + void Assembler::printActivationState() + { + char* s = &outline[0]; + VMPI_memset(s, ' ', 26); s[26] = '\0'; + s += VMPI_strlen(s); + VMPI_sprintf(s, "AR"); + s += VMPI_strlen(s); + + LIns* ins = 0; + uint32_t nStackSlots = 0; + int32_t arIndex = 0; + for (AR::Iter iter(_activation); iter.next(ins, nStackSlots, arIndex); ) + { + RefBuf b; + const char* n = _thisfrag->lirbuf->printer->formatRef(&b, ins); + if (nStackSlots > 1) { + VMPI_sprintf(s," %d-%d(%s)", 4*arIndex, 4*(arIndex+nStackSlots-1), n); + } + else { + VMPI_sprintf(s," %d(%s)", 4*arIndex, n); + } + s += VMPI_strlen(s); + } + output(); + } +#endif + + inline bool AR::isEmptyRange(uint32_t start, uint32_t nStackSlots) const + { + for (uint32_t i=0; i < nStackSlots; i++) + { + if (_entries[start-i] != NULL) + return false; + } + return true; + } + + uint32_t AR::reserveEntry(LIns* ins) + { + uint32_t const nStackSlots = nStackSlotsFor(ins); + + if (nStackSlots == 1) + { + for (uint32_t i = 1; i <= _highWaterMark; i++) + { + if (_entries[i] == NULL) + { + _entries[i] = ins; + return i; + } + } + if (_highWaterMark < NJ_MAX_STACK_ENTRY - 1) + { + NanoAssert(_entries[_highWaterMark+1] == BAD_ENTRY); + _highWaterMark++; + _entries[_highWaterMark] = ins; + return _highWaterMark; + } + } + else + { + // alloc larger block on 8byte boundary. + uint32_t const start = nStackSlots + (nStackSlots & 1); + for (uint32_t i = start; i <= _highWaterMark; i += 2) + { + if (isEmptyRange(i, nStackSlots)) + { + // place the entry in the table and mark the instruction with it + for (uint32_t j=0; j < nStackSlots; j++) + { + NanoAssert(i-j <= _highWaterMark); + NanoAssert(_entries[i-j] == NULL); + _entries[i-j] = ins; + } + return i; + } + } + + // Be sure to account for any 8-byte-round-up when calculating spaceNeeded. + uint32_t const spaceLeft = NJ_MAX_STACK_ENTRY - _highWaterMark - 1; + uint32_t const spaceNeeded = nStackSlots + (_highWaterMark & 1); + if (spaceLeft >= spaceNeeded) + { + if (_highWaterMark & 1) + { + NanoAssert(_entries[_highWaterMark+1] == BAD_ENTRY); + _entries[_highWaterMark+1] = NULL; + } + _highWaterMark += spaceNeeded; + for (uint32_t j = 0; j < nStackSlots; j++) + { + NanoAssert(_highWaterMark-j < NJ_MAX_STACK_ENTRY); + NanoAssert(_entries[_highWaterMark-j] == BAD_ENTRY); + _entries[_highWaterMark-j] = ins; + } + return _highWaterMark; + } + } + // no space. oh well. + return 0; + } + + #ifdef _DEBUG + void AR::checkForResourceLeaks() const + { + for (uint32_t i = 1; i <= _highWaterMark; i++) { + NanoAssertMsgf(_entries[i] == NULL, "frame entry %d wasn't freed\n",4*i); + } + } + #endif + + uint32_t Assembler::arReserve(LIns* ins) + { + uint32_t i = _activation.reserveEntry(ins); + if (!i) + setError(StackFull); + return i; + } + + void Assembler::arFree(LIns* ins) + { + NanoAssert(ins->isInAr()); + uint32_t arIndex = ins->getArIndex(); + NanoAssert(arIndex); + NanoAssert(_activation.isValidEntry(arIndex, ins)); + _activation.freeEntryAt(arIndex); // free any stack stack space associated with entry + } + + /** + * Move regs around so the SavedRegs contains the highest priority regs. + */ + void Assembler::evictScratchRegsExcept(RegisterMask ignore) + { + // Find the top GpRegs that are candidates to put in SavedRegs. + + // 'tosave' is a binary heap stored in an array. The root is tosave[0], + // left child is at i+1, right child is at i+2. + + Register tosave[LastRegNum - FirstRegNum + 1]; + int len=0; + RegAlloc *regs = &_allocator; + RegisterMask evict_set = regs->activeMask() & GpRegs & ~ignore; + for (Register r = lsReg(evict_set); evict_set; r = nextLsReg(evict_set, r)) { + LIns *ins = regs->getActive(r); + if (canRemat(ins)) { + NanoAssert(ins->getReg() == r); + evict(ins); + } + else { + int32_t pri = regs->getPriority(r); + // add to heap by adding to end and bubbling up + int j = len++; + while (j > 0 && pri > regs->getPriority(tosave[j/2])) { + tosave[j] = tosave[j/2]; + j /= 2; + } + NanoAssert(size_t(j) < sizeof(tosave)/sizeof(tosave[0])); + tosave[j] = r; + } + } + + // Now primap has the live exprs in priority order. + // Allocate each of the top priority exprs to a SavedReg. + + RegisterMask allow = SavedRegs; + while (allow && len > 0) { + // get the highest priority var + Register hi = tosave[0]; + if (!(rmask(hi) & SavedRegs)) { + LIns *ins = regs->getActive(hi); + Register r = findRegFor(ins, allow); + allow &= ~rmask(r); + } + else { + // hi is already in a saved reg, leave it alone. + allow &= ~rmask(hi); + } + + // remove from heap by replacing root with end element and bubbling down. + if (allow && --len > 0) { + Register last = tosave[len]; + int j = 0; + while (j+1 < len) { + int child = j+1; + if (j+2 < len && regs->getPriority(tosave[j+2]) > regs->getPriority(tosave[j+1])) + child++; + if (regs->getPriority(last) > regs->getPriority(tosave[child])) + break; + tosave[j] = tosave[child]; + j = child; + } + tosave[j] = last; + } + } + + // now evict everything else. + evictSomeActiveRegs(~(SavedRegs | ignore)); + } + + // Generate code to restore any registers in 'regs' that are currently active, + void Assembler::evictSomeActiveRegs(RegisterMask regs) + { + RegisterMask evict_set = regs & _allocator.activeMask(); + for (Register r = lsReg(evict_set); evict_set; r = nextLsReg(evict_set, r)) + evict(_allocator.getActive(r)); + } + + /** + * Merge the current regstate with a previously stored version. + * + * Situation Change to _allocator + * --------- -------------------- + * !current & !saved + * !current & saved add saved + * current & !saved evict current (unionRegisterState does nothing) + * current & saved & current==saved + * current & saved & current!=saved evict current, add saved + */ + void Assembler::intersectRegisterState(RegAlloc& saved) + { + Register regsTodo[LastRegNum + 1]; + LIns* insTodo[LastRegNum + 1]; + int nTodo = 0; + + // Do evictions and pops first. + verbose_only(bool shouldMention=false; ) + // The obvious thing to do here is to iterate from FirstRegNum to + // LastRegNum. However, on ARM that causes lower-numbered integer + // registers to be be saved at higher addresses, which inhibits the + // formation of load/store multiple instructions. Hence iterate the + // loop the other way. + RegisterMask reg_set = _allocator.activeMask() | saved.activeMask(); + for (Register r = msReg(reg_set); reg_set; r = nextMsReg(reg_set, r)) + { + LIns* curins = _allocator.getActive(r); + LIns* savedins = saved.getActive(r); + if (curins != savedins) + { + if (savedins) { + regsTodo[nTodo] = r; + insTodo[nTodo] = savedins; + nTodo++; + } + if (curins) { + //_nvprof("intersect-evict",1); + verbose_only( shouldMention=true; ) + NanoAssert(curins->getReg() == r); + evict(curins); + } + + #ifdef NANOJIT_IA32 + if (savedins && r == FST0) { + verbose_only( shouldMention=true; ) + FSTP(FST0); + } + #endif + } + } + // Now reassign mainline registers. + for (int i = 0; i < nTodo; i++) { + findSpecificRegFor(insTodo[i], regsTodo[i]); + } + verbose_only( + if (shouldMention) + verbose_outputf("## merging registers (intersect) with existing edge"); + ) + } + + /** + * Merge the current state of the registers with a previously stored version. + * + * Situation Change to _allocator + * --------- -------------------- + * !current & !saved none + * !current & saved add saved + * current & !saved none (intersectRegisterState evicts current) + * current & saved & current==saved none + * current & saved & current!=saved evict current, add saved + */ + void Assembler::unionRegisterState(RegAlloc& saved) + { + Register regsTodo[LastRegNum + 1]; + LIns* insTodo[LastRegNum + 1]; + int nTodo = 0; + + // Do evictions and pops first. + verbose_only(bool shouldMention=false; ) + RegisterMask reg_set = _allocator.activeMask() | saved.activeMask(); + for (Register r = lsReg(reg_set); reg_set; r = nextLsReg(reg_set, r)) + { + LIns* curins = _allocator.getActive(r); + LIns* savedins = saved.getActive(r); + if (curins != savedins) + { + if (savedins) { + regsTodo[nTodo] = r; + insTodo[nTodo] = savedins; + nTodo++; + } + if (curins && savedins) { + //_nvprof("union-evict",1); + verbose_only( shouldMention=true; ) + NanoAssert(curins->getReg() == r); + evict(curins); + } + + #ifdef NANOJIT_IA32 + if (r == FST0) { + if (savedins) { + // Discard top of x87 stack. + FSTP(FST0); + } + else if (curins) { + // Saved state did not have fpu reg allocated, + // so we must evict here to keep x87 stack balanced. + evict(curins); + } + verbose_only( shouldMention=true; ) + } + #endif + } + } + // Now reassign mainline registers. + for (int i = 0; i < nTodo; i++) { + findSpecificRegFor(insTodo[i], regsTodo[i]); + } + verbose_only( + if (shouldMention) + verbose_outputf("## merging registers (union) with existing edge"); + ) + } + + // Scan table for instruction with the lowest priority, meaning it is used + // furthest in the future. + LIns* Assembler::findVictim(RegisterMask allow) + { + NanoAssert(allow); + LIns *ins, *vic = 0; + int allow_pri = 0x7fffffff; + RegisterMask vic_set = allow & _allocator.activeMask(); + for (Register r = lsReg(vic_set); vic_set; r = nextLsReg(vic_set, r)) + { + ins = _allocator.getActive(r); + int pri = canRemat(ins) ? 0 : _allocator.getPriority(r); + if (!vic || pri < allow_pri) { + vic = ins; + allow_pri = pri; + } + } + NanoAssert(vic != 0); + return vic; + } + +#ifdef NJ_VERBOSE + char Assembler::outline[8192]; + char Assembler::outlineEOL[512]; + + void Assembler::output() + { + // The +1 is for the terminating NUL char. + VMPI_strncat(outline, outlineEOL, sizeof(outline)-(strlen(outline)+1)); + + if (_outputCache) { + char* str = new (alloc) char[VMPI_strlen(outline)+1]; + VMPI_strcpy(str, outline); + _outputCache->insert(str); + } else { + _logc->printf("%s\n", outline); + } + + outline[0] = '\0'; + outlineEOL[0] = '\0'; + } + + void Assembler::outputf(const char* format, ...) + { + va_list args; + va_start(args, format); + + outline[0] = '\0'; + vsprintf(outline, format, args); + output(); + } + + void Assembler::setOutputForEOL(const char* format, ...) + { + va_list args; + va_start(args, format); + + outlineEOL[0] = '\0'; + vsprintf(outlineEOL, format, args); + } +#endif // NJ_VERBOSE + + void LabelStateMap::add(LIns *label, NIns *addr, RegAlloc ®s) { + LabelState *st = new (alloc) LabelState(addr, regs); + labels.put(label, st); + } + + LabelState* LabelStateMap::get(LIns *label) { + return labels.get(label); + } +} +#endif /* FEATURE_NANOJIT */ diff --git a/js/src/nanojit/Assembler.h b/js/src/nanojit/Assembler.h new file mode 100644 index 0000000..a82d73c --- /dev/null +++ b/js/src/nanojit/Assembler.h @@ -0,0 +1,553 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#ifndef __nanojit_Assembler__ +#define __nanojit_Assembler__ + + +namespace nanojit +{ + /** + * Some notes on this Assembler (Emitter). + * + * The class RegAlloc is essentially the register allocator from MIR + * + * The Assembler class parses the LIR instructions starting at any point and converts + * them to machine code. It does the translation using expression trees which are simply + * LIR instructions in the stream that have side-effects. Any other instruction in the + * stream is simply ignored. + * This approach is interesting in that dead code elimination occurs for 'free', strength + * reduction occurs fairly naturally, along with some other optimizations. + * + * A negative is that we require state as we 'push' and 'pop' nodes along the tree. + * Also, this is most easily performed using recursion which may not be desirable in + * the mobile environment. + * + */ + + #define STACK_GRANULARITY sizeof(void *) + + // Basics: + // - 'entry' records the state of the native machine stack at particular + // points during assembly. Each entry represents four bytes. + // + // - Parts of the stack can be allocated by LIR_allocp, in which case each + // slot covered by the allocation contains a pointer to the LIR_allocp + // LIns. + // + // - The stack also holds spilled values, in which case each slot holding + // a spilled value (one slot for 32-bit values, two slots for 64-bit + // values) contains a pointer to the instruction defining the spilled + // value. + // + // - Each LIns has a "reservation" which includes a stack index, + // 'arIndex'. Combined with AR, it provides a two-way mapping between + // stack slots and LIR instructions. + // + // - Invariant: the two-way mapping between active stack slots and their + // defining/allocating instructions must hold in both directions and be + // unambiguous. More specifically: + // + // * An LIns can appear in at most one contiguous sequence of slots in + // AR, and the length of that sequence depends on the opcode (1 slot + // for instructions producing 32-bit values, 2 slots for instructions + // producing 64-bit values, N slots for LIR_allocp). + // + // * An LIns named by 'entry[i]' must have an in-use reservation with + // arIndex==i (or an 'i' indexing the start of the same contiguous + // sequence that 'entry[i]' belongs to). + // + // * And vice versa: an LIns with an in-use reservation with arIndex==i + // must be named by 'entry[i]'. + // + // * If an LIns's reservation names has arIndex==0 then LIns should not + // be in 'entry[]'. + // + class AR + { + private: + uint32_t _highWaterMark; /* index of highest entry used since last clear() */ + LIns* _entries[ NJ_MAX_STACK_ENTRY ]; /* maps to 4B contiguous locations relative to the frame pointer. + NB: _entries[0] is always unused */ + + #ifdef _DEBUG + static LIns* const BAD_ENTRY; + #endif + + bool isEmptyRange(uint32_t start, uint32_t nStackSlots) const; + static uint32_t nStackSlotsFor(LIns* ins); + + public: + AR(); + + uint32_t stackSlotsNeeded() const; + + void clear(); + void freeEntryAt(uint32_t i); + uint32_t reserveEntry(LIns* ins); /* return 0 if unable to reserve the entry */ + + #ifdef _DEBUG + void validateQuick(); + void validateFull(); + void validate(); + bool isValidEntry(uint32_t idx, LIns* ins) const; /* return true iff idx and ins are matched */ + void checkForResourceConsistency(const RegAlloc& regs); + void checkForResourceLeaks() const; + #endif + + class Iter + { + private: + const AR& _ar; + // '_i' points to the start of the entries for an LIns, or to the first NULL entry. + uint32_t _i; + public: + inline Iter(const AR& ar) : _ar(ar), _i(1) { } + bool next(LIns*& ins, uint32_t& nStackSlots, int32_t& offset); // get the next one (moves iterator forward) + }; + }; + + inline AR::AR() + { + _entries[0] = NULL; + clear(); + } + + inline /*static*/ uint32_t AR::nStackSlotsFor(LIns* ins) + { + uint32_t n = 0; + if (ins->isop(LIR_allocp)) { + n = ins->size() >> 2; + } else { + switch (ins->retType()) { + case LTy_I: n = 1; break; + CASE64(LTy_Q:) + case LTy_D: n = 2; break; + case LTy_V: NanoAssert(0); break; + default: NanoAssert(0); break; + } + } + return n; + } + + inline uint32_t AR::stackSlotsNeeded() const + { + // NB: _highWaterMark is an index, not a count + return _highWaterMark+1; + } + + #ifndef AVMPLUS_ALIGN16 + #ifdef _MSC_VER + #define AVMPLUS_ALIGN16(type) __declspec(align(16)) type + #else + #define AVMPLUS_ALIGN16(type) type __attribute__ ((aligned (16))) + #endif + #endif + + class Noise + { + public: + virtual ~Noise() {} + + // produce a random number from 0-maxValue for the JIT to use in attack mitigation + virtual uint32_t getValue(uint32_t maxValue) = 0; + }; + + // error codes + enum AssmError + { + None = 0 + ,StackFull + ,UnknownBranch + ,BranchTooFar + }; + + typedef SeqBuilder NInsList; + typedef HashMap NInsMap; +#if NJ_USES_IMMD_POOL + typedef HashMap ImmDPoolMap; +#endif + +#ifdef VMCFG_VTUNE + class avmplus::CodegenLIR; +#endif + + class LabelState + { + public: + RegAlloc regs; + NIns *addr; + LabelState(NIns *a, RegAlloc &r) : regs(r), addr(a) + {} + }; + + class LabelStateMap + { + Allocator& alloc; + HashMap labels; + public: + LabelStateMap(Allocator& alloc) : alloc(alloc), labels(alloc) + {} + + void clear() { labels.clear(); } + void add(LIns *label, NIns *addr, RegAlloc ®s); + LabelState *get(LIns *); + }; + + /** map tracking the register allocation state at each bailout point + * (represented by SideExit*) in a trace fragment. */ + typedef HashMap RegAllocMap; + + /** + * Information about the activation record for the method is built up + * as we generate machine code. As part of the prologue, we issue + * a stack adjustment instruction and then later patch the adjustment + * value. Temporary values can be placed into the AR as method calls + * are issued. Also LIR_allocp instructions will consume space. + */ + class Assembler + { + friend class VerboseBlockReader; + #ifdef NJ_VERBOSE + public: + // Buffer for holding text as we generate it in reverse order. + StringList* _outputCache; + + // Outputs the format string and 'outlineEOL', and resets + // 'outline' and 'outlineEOL'. + void outputf(const char* format, ...); + + private: + // Log controller object. Contains what-stuff-should-we-print + // bits, and a sink function for debug printing. + LogControl* _logc; + + // Buffer used in most of the output function. It must big enough + // to hold both the output line and the 'outlineEOL' buffer, which + // is concatenated onto 'outline' just before it is printed. + static char outline[8192]; + // Buffer used to hold extra text to be printed at the end of some + // lines. + static char outlineEOL[512]; + + // Outputs 'outline' and 'outlineEOL', and resets them both. + // Output goes to '_outputCache' if it's non-NULL, or is printed + // directly via '_logc'. + void output(); + + // Sets 'outlineEOL'. + void setOutputForEOL(const char* format, ...); + + void printRegState(); + void printActivationState(); + #endif // NJ_VERBOSE + + public: + #ifdef VMCFG_VTUNE + void* vtuneHandle; + #endif + + Assembler(CodeAlloc& codeAlloc, Allocator& dataAlloc, Allocator& alloc, AvmCore* core, LogControl* logc, const Config& config); + + void compile(Fragment *frag, Allocator& alloc, bool optimize + verbose_only(, LInsPrinter*)); + + void endAssembly(Fragment* frag); + void assemble(Fragment* frag, LirFilter* reader); + void beginAssembly(Fragment *frag); + + void setNoiseGenerator(Noise* noise) { _noise = noise; } // used for attack mitigation; setting to 0 disables all mitigations + + void releaseRegisters(); + void patch(GuardRecord *lr); + void patch(SideExit *exit); +#ifdef NANOJIT_IA32 + void patch(SideExit *exit, SwitchInfo* si); +#endif + AssmError error() { return _err; } + void setError(AssmError e) { _err = e; } + void cleanupAfterError(); + void clearNInsPtrs(); + void reset(); + + debug_only ( void pageValidate(); ) + + // support calling out from a fragment ; used to debug the jit + debug_only( void resourceConsistencyCheck(); ) + debug_only( void registerConsistencyCheck(); ) + + private: + void gen(LirFilter* toCompile); + NIns* genPrologue(); + NIns* genEpilogue(); + + uint32_t arReserve(LIns* ins); + void arFree(LIns* ins); + void arReset(); + + Register registerAlloc(LIns* ins, RegisterMask allow, RegisterMask prefer); + Register registerAllocTmp(RegisterMask allow); + void registerResetAll(); + void evictAllActiveRegs() { + // The evicted set will be be intersected with activeSet(), + // so use an all-1s mask to avoid an extra load or call. + evictSomeActiveRegs(~RegisterMask(0)); + } + void evictSomeActiveRegs(RegisterMask regs); + void evictScratchRegsExcept(RegisterMask ignore); + void intersectRegisterState(RegAlloc& saved); + void unionRegisterState(RegAlloc& saved); + void assignSaved(RegAlloc &saved, RegisterMask skip); + LIns* findVictim(RegisterMask allow); + + Register getBaseReg(LIns *ins, int &d, RegisterMask allow); + void getBaseReg2(RegisterMask allowValue, LIns* value, Register& rv, + RegisterMask allowBase, LIns* base, Register& rb, int &d); +#if NJ_USES_IMMD_POOL + const uint64_t* + findImmDFromPool(uint64_t q); +#endif + int findMemFor(LIns* ins); + Register findRegFor(LIns* ins, RegisterMask allow); + void findRegFor2(RegisterMask allowa, LIns* ia, Register &ra, + RegisterMask allowb, LIns *ib, Register &rb); + Register findSpecificRegFor(LIns* ins, Register r); + Register findSpecificRegForUnallocated(LIns* ins, Register r); + Register deprecated_prepResultReg(LIns *ins, RegisterMask allow); + Register prepareResultReg(LIns *ins, RegisterMask allow); + void deprecated_freeRsrcOf(LIns *ins); + void freeResourcesOf(LIns *ins); + void evictIfActive(Register r); + void evict(LIns* vic); + RegisterMask hint(LIns* ins); + + void getBaseIndexScale(LIns* addp, LIns** base, LIns** index, int* scale); + + void codeAlloc(NIns *&start, NIns *&end, NIns *&eip + verbose_only(, size_t &nBytes) + , size_t byteLimit=0); + + // These instructions don't have to be saved & reloaded to spill, + // they can just be recalculated cheaply. + // + // WARNING: this function must match asm_restore() -- it should return + // true for the instructions that are handled explicitly without a spill + // in asm_restore(), and false otherwise. + // + // If it doesn't match asm_restore(), the register allocator's decisions + // about which values to evict will be suboptimal. + static bool canRemat(LIns*); + + bool deprecated_isKnownReg(Register r) { + return r != deprecated_UnknownReg; + } + + Allocator& alloc; // for items with same lifetime as this Assembler + CodeAlloc& _codeAlloc; // for code we generate + Allocator& _dataAlloc; // for data used by generated code + Fragment* _thisfrag; + RegAllocMap _branchStateMap; + NInsMap _patches; + LabelStateMap _labels; + Noise* _noise; // object to generate random noise used when hardening enabled. + #if NJ_USES_IMMD_POOL + ImmDPoolMap _immDPool; + #endif + + // We generate code into two places: normal code chunks, and exit + // code chunks (for exit stubs). We use a hack to avoid having to + // parameterise the code that does the generating -- we let that + // code assume that it's always generating into a normal code + // chunk (most of the time it is), and when we instead need to + // generate into an exit code chunk, we set _inExit to true and + // temporarily swap all the code/exit variables below (using + // swapCodeChunks()). Afterwards we swap them all back and set + // _inExit to false again. + CodeList* codeList; // finished blocks of code. + bool _inExit, vpad2[3]; + NIns *codeStart, *codeEnd; // current normal code chunk + NIns *exitStart, *exitEnd; // current exit code chunk + NIns* _nIns; // current instruction in current normal code chunk + NIns* _nExitIns; // current instruction in current exit code chunk + // note: _nExitIns == NULL until the first side exit is seen. + #ifdef NJ_VERBOSE + NIns* _nInsAfter; // next instruction (ascending) in current normal/exit code chunk (for verbose output) + size_t codeBytes; // bytes allocated in normal code chunks + size_t exitBytes; // bytes allocated in exit code chunks + #endif + + #define SWAP(t, a, b) do { t tmp = a; a = b; b = tmp; } while (0) + void swapCodeChunks(); + + NIns* _epilogue; + AssmError _err; // 0 = means assemble() appears ok, otherwise it failed + #if PEDANTIC + NIns* pedanticTop; + #endif + + // Holds the current instruction during gen(). + LIns* currIns; + + AR _activation; + RegAlloc _allocator; + + verbose_only( void asm_inc_m32(uint32_t*); ) + void asm_mmq(Register rd, int dd, Register rs, int ds); + void asm_jmp(LIns* ins, InsList& pending_lives); + void asm_jcc(LIns* ins, InsList& pending_lives); + void asm_jov(LIns* ins, InsList& pending_lives); + void asm_x(LIns* ins); + void asm_xcc(LIns* ins); + NIns* asm_exit(LIns* guard); + NIns* asm_leave_trace(LIns* guard); + void asm_store32(LOpcode op, LIns *val, int d, LIns *base); + void asm_store64(LOpcode op, LIns *val, int d, LIns *base); + + // WARNING: the implementation of asm_restore() should emit fast code + // to rematerialize instructions where canRemat() returns true. + // Otherwise, register allocation decisions will be suboptimal. + void asm_restore(LIns*, Register); + + bool asm_maybe_spill(LIns* ins, bool pop); +#ifdef NANOJIT_IA32 + void asm_spill(Register rr, int d, bool pop); +#else + void asm_spill(Register rr, int d, bool quad); +#endif + void asm_load64(LIns* ins); + void asm_ret(LIns* ins); +#ifdef NANOJIT_64BIT + void asm_immq(LIns* ins); +#endif + void asm_immd(LIns* ins); + void asm_condd(LIns* ins); + void asm_cond(LIns* ins); + void asm_arith(LIns* ins); + void asm_neg_not(LIns* ins); + void asm_load32(LIns* ins); + void asm_cmov(LIns* ins); + void asm_param(LIns* ins); + void asm_immi(LIns* ins); +#if NJ_SOFTFLOAT_SUPPORTED + void asm_qlo(LIns* ins); + void asm_qhi(LIns* ins); + void asm_qjoin(LIns *ins); +#endif + void asm_fneg(LIns* ins); + void asm_fop(LIns* ins); + void asm_i2d(LIns* ins); + void asm_ui2d(LIns* ins); + void asm_d2i(LIns* ins); +#ifdef NANOJIT_64BIT + void asm_q2i(LIns* ins); + void asm_ui2uq(LIns *ins); + void asm_dasq(LIns *ins); + void asm_qasd(LIns *ins); +#endif + void asm_nongp_copy(Register r, Register s); + void asm_call(LIns*); + Register asm_binop_rhs_reg(LIns* ins); + NIns* asm_branch(bool branchOnFalse, LIns* cond, NIns* targ); + NIns* asm_branch_ov(LOpcode op, NIns* targ); + void asm_switch(LIns* ins, NIns* target); + void asm_jtbl(LIns* ins, NIns** table); + void asm_insert_random_nop(); + void emitJumpTable(SwitchInfo* si, NIns* target); + void assignSavedRegs(); + void reserveSavedRegs(); + void assignParamRegs(); + void handleLoopCarriedExprs(InsList& pending_lives); + + // platform specific implementation (see NativeXXX.cpp file) + void nInit(AvmCore *); + void nBeginAssembly(); + Register nRegisterAllocFromSet(RegisterMask set); + void nRegisterResetAll(RegAlloc& a); + void nPatchBranch(NIns* branch, NIns* location); + void nFragExit(LIns* guard); + + static RegisterMask nHints[LIR_sentinel+1]; + RegisterMask nHint(LIns* ins); + + // A special entry for hints[]; if an opcode has this value, we call + // nHint() in the back-end. Used for cases where you need to look at more + // than just the opcode to decide. + static const RegisterMask PREFER_SPECIAL = 0xffffffff; + + // platform specific methods + public: + const static Register savedRegs[NumSavedRegs+1]; // Allocate an extra element in case NumSavedRegs == 0 + DECLARE_PLATFORM_ASSEMBLER() + + private: +#ifdef NANOJIT_IA32 + debug_only( int32_t _fpuStkDepth; ) + debug_only( int32_t _sv_fpuStkDepth; ) + + // The FPU stack depth is the number of pushes in excess of the number of pops. + // Since we generate backwards, we track the FPU stack depth as a negative number. + // We use the top of the x87 stack as the single allocatable FP register, FST0. + // Thus, between LIR instructions, the depth of the FPU stack must be either 0 or -1, + // depending on whether FST0 is in use. Within the expansion of a single LIR + // instruction, however, deeper levels of the stack may be used as unmanaged + // temporaries. Hence, we allow for all eight levels in the assertions below. + inline void fpu_push() { + debug_only( ++_fpuStkDepth; NanoAssert(_fpuStkDepth <= 0); ) + } + inline void fpu_pop() { + debug_only( --_fpuStkDepth; NanoAssert(_fpuStkDepth >= -7); ) + } +#endif + const Config& _config; + }; + + inline int32_t arDisp(LIns* ins) + { + // even on 64bit cpu's, we allocate stack area in 4byte chunks + return -4 * int32_t(ins->getArIndex()); + } + // XXX: deprecated, use arDisp() instead. See bug 538924. + inline int32_t deprecated_disp(LIns* ins) + { + // even on 64bit cpu's, we allocate stack area in 4byte chunks + return -4 * int32_t(ins->deprecated_getArIndex()); + } +} +#endif // __nanojit_Assembler__ diff --git a/js/src/nanojit/CodeAlloc.cpp b/js/src/nanojit/CodeAlloc.cpp new file mode 100644 index 0000000..61b711a --- /dev/null +++ b/js/src/nanojit/CodeAlloc.cpp @@ -0,0 +1,570 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nanojit.h" + +//#define DOPROF +#include "../vprof/vprof.h" + +#ifdef FEATURE_NANOJIT + +namespace nanojit +{ + static const bool verbose = false; +#ifdef VMCFG_VTUNE + // vtune jit profiling api can't handle non-contiguous methods, + // so make the allocation size huge to avoid non-contiguous methods + static const int pagesPerAlloc = 128; // 1MB +#elif defined(NANOJIT_ARM) + // ARM requires single-page allocations, due to the constant pool that + // lives on each page that must be reachable by a 4kb pcrel load. + static const int pagesPerAlloc = 1; +#else + static const int pagesPerAlloc = 16; +#endif + + CodeAlloc::CodeAlloc() + : heapblocks(0) + , availblocks(0) + , totalAllocated(0) + , bytesPerPage(VMPI_getVMPageSize()) + , bytesPerAlloc(pagesPerAlloc * bytesPerPage) + { + } + + CodeAlloc::~CodeAlloc() { + reset(); + } + + void CodeAlloc::reset() { + // give all memory back to gcheap. Assumption is that all + // code is done being used by now. + for (CodeList* hb = heapblocks; hb != 0; ) { + _nvprof("free page",1); + CodeList* next = hb->next; + CodeList* fb = firstBlock(hb); + markBlockWrite(fb); + freeCodeChunk(fb, bytesPerAlloc); + totalAllocated -= bytesPerAlloc; + hb = next; + } + NanoAssert(!totalAllocated); + heapblocks = availblocks = 0; + } + + CodeList* CodeAlloc::firstBlock(CodeList* term) { + // use uintptr_t, rather than char*, to avoid "increases required alignment" warning + uintptr_t end = (uintptr_t)alignUp(term, bytesPerPage); + return (CodeList*) (end - (uintptr_t)bytesPerAlloc); + } + + static int round(size_t x) { + return (int)((x + 512) >> 10); + } + + void CodeAlloc::logStats() { + size_t total = 0; + size_t frag_size = 0; + size_t free_size = 0; + int free_count = 0; + for (CodeList* hb = heapblocks; hb != 0; hb = hb->next) { + total += bytesPerAlloc; + for (CodeList* b = hb->lower; b != 0; b = b->lower) { + if (b->isFree) { + free_count++; + free_size += b->blockSize(); + if (b->size() < minAllocSize) + frag_size += b->blockSize(); + } + } + } + avmplus::AvmLog("code-heap: %dk free %dk fragmented %d\n", + round(total), round(free_size), frag_size); + } + + inline void CodeAlloc::markBlockWrite(CodeList* b) { + NanoAssert(b->terminator != NULL); + CodeList* term = b->terminator; + if (term->isExec) { + markCodeChunkWrite(firstBlock(term), bytesPerAlloc); + term->isExec = false; + } + } + + void CodeAlloc::alloc(NIns* &start, NIns* &end, size_t byteLimit) { + if (!availblocks) { + // no free mem, get more + addMem(); + } + + // grab a block + NanoAssert(!byteLimit || byteLimit > blkSpaceFor(2)); // if a limit is imposed it must be bigger than 2x minimum block size (see below) + markBlockWrite(availblocks); + CodeList* b = removeBlock(availblocks); + + // limit imposed (byteLimit > 0) and the block is too big? then break it apart + if (byteLimit > 0 && b->size() > byteLimit) { + + size_t consume; // # bytes to extract from the free block + + // enough space to carve out a perfectly sized blk? (leaving at least a full free blk) + if (b->size() >= byteLimit + headerSpaceFor(1) + blkSpaceFor(1)) { + // yes, then take exactly what we need + consume = byteLimit + headerSpaceFor(1); + } else { + // no, then we should only take the min amount + consume = blkSpaceFor(1); + + // ... and since b->size() > byteLimit && byteLimit > blkSpaceFor(2) + NanoAssert( b->size() > blkSpaceFor(2) ); + NanoAssert( b->size() - consume > blkSpaceFor(1) ); // thus, we know that at least 1 blk left. + } + + // break block into 2 pieces, returning the lower portion to the free list + CodeList* higher = b->higher; + b->end = (NIns*) ( (uintptr_t)b->end - consume ); + CodeList* b1 = b->higher; + higher->lower = b1; + b1->higher = higher; + b1->lower = b; + b1->terminator = b->terminator; + NanoAssert(b->size() > minAllocSize); + addBlock(availblocks, b); // put back the rest of the block + b = b1; + } + NanoAssert(b->size() >= minAllocSize); + b->next = 0; // not technically needed (except for debug builds), but good hygiene. + b->isFree = false; + start = b->start(); + end = b->end; + if (verbose) + avmplus::AvmLog("CodeAlloc(%p).alloc %p-%p %d\n", this, start, end, int(end-start)); + debug_only(sanity_check();) + } + + void CodeAlloc::free(NIns* start, NIns *end) { + NanoAssert(heapblocks); + CodeList *blk = getBlock(start, end); + if (verbose) + avmplus::AvmLog("free %p-%p %d\n", start, end, (int)blk->size()); + + NanoAssert(!blk->isFree); + + // coalesce adjacent blocks. + bool already_on_avail_list; + + if (blk->lower && blk->lower->isFree) { + // combine blk into blk->lower (destroy blk) + CodeList* lower = blk->lower; + CodeList* higher = blk->higher; + already_on_avail_list = lower->size() >= minAllocSize; + lower->higher = higher; + higher->lower = lower; + blk = lower; + } + else + already_on_avail_list = false; + + // the last block in each heapblock is a terminator block, + // which is never free, therefore blk->higher != null + if (blk->higher->isFree) { + CodeList *higher = blk->higher->higher; + CodeList *coalescedBlock = blk->higher; + + if ( coalescedBlock->size() >= minAllocSize ) { + // Unlink coalescedBlock from the available block chain. + if ( availblocks == coalescedBlock ) { + removeBlock(availblocks); + } + else { + CodeList* free_block = availblocks; + while ( free_block && free_block->next != coalescedBlock) { + NanoAssert(free_block->size() >= minAllocSize); + NanoAssert(free_block->isFree); + NanoAssert(free_block->next); + free_block = free_block->next; + } + NanoAssert(free_block && free_block->next == coalescedBlock); + free_block->next = coalescedBlock->next; + } + } + + // combine blk->higher into blk (destroy coalescedBlock) + blk->higher = higher; + higher->lower = blk; + } + blk->isFree = true; + NanoAssert(!blk->lower || !blk->lower->isFree); + NanoAssert(blk->higher && !blk->higher->isFree); + //memset(blk->start(), 0xCC, blk->size()); // INT 3 instruction + if ( !already_on_avail_list && blk->size() >= minAllocSize ) + addBlock(availblocks, blk); + + NanoAssert(heapblocks); + debug_only(sanity_check();) + } + + void CodeAlloc::freeAll(CodeList* &code) { + while (code) { + CodeList *b = removeBlock(code); + free(b->start(), b->end); + } + } + +#if defined NANOJIT_ARM && defined UNDER_CE + // Use a single flush for the whole CodeList, when we have no + // finer-granularity flush support, as on WinCE. + void CodeAlloc::flushICache(CodeList* &/*blocks*/) { + FlushInstructionCache(GetCurrentProcess(), NULL, NULL); + } +#else + void CodeAlloc::flushICache(CodeList* &blocks) { + for (CodeList *b = blocks; b != 0; b = b->next) + flushICache(b->start(), b->size()); + } +#endif + +#if defined(AVMPLUS_UNIX) && defined(NANOJIT_ARM) +#include +extern "C" void __clear_cache(char *BEG, char *END); +#endif + +#if defined(AVMPLUS_UNIX) && defined(NANOJIT_MIPS) +#include +extern "C" int cacheflush(char *addr, int nbytes, int cache); +#endif + +#ifdef AVMPLUS_SPARC +// Note: the linux #define provided by the compiler. +#ifdef linux // bugzilla 502369 +void sync_instruction_memory(caddr_t v, u_int len) +{ + caddr_t end = v + len; + caddr_t p = v; + while (p < end) { + asm("flush %0" : : "r" (p)); + p += 32; + } +} +#else +extern "C" void sync_instruction_memory(caddr_t v, u_int len); +#endif +#endif + +#if defined NANOJIT_IA32 || defined NANOJIT_X64 + // intel chips have dcache/icache interlock + void CodeAlloc::flushICache(void *start, size_t len) { + // Tell Valgrind that new code has been generated, and it must flush + // any translations it has for the memory range generated into. + (void)start; + (void)len; + VALGRIND_DISCARD_TRANSLATIONS(start, len); + } + +#elif defined NANOJIT_ARM && defined UNDER_CE + // On arm/winmo, just flush the whole icache. The + // WinCE docs indicate that this function actually ignores its + // 2nd and 3rd arguments, and wants them to be NULL. + void CodeAlloc::flushICache(void *, size_t) { + FlushInstructionCache(GetCurrentProcess(), NULL, NULL); + } + +#elif defined NANOJIT_ARM && defined DARWIN + void CodeAlloc::flushICache(void *, size_t) { + VMPI_debugBreak(); + } + +#elif defined AVMPLUS_MAC && defined NANOJIT_PPC + +# ifdef NANOJIT_64BIT + extern "C" void sys_icache_invalidate(const void*, size_t len); + extern "C" void sys_dcache_flush(const void*, size_t len); + + // mac 64bit requires 10.5 so use that api + void CodeAlloc::flushICache(void *start, size_t len) { + sys_dcache_flush(start, len); + sys_icache_invalidate(start, len); + } +# else + // mac ppc 32 could be 10.0 or later + // uses MakeDataExecutable() from Carbon api, OSUtils.h + // see http://developer.apple.com/documentation/Carbon/Reference/Memory_Manag_nt_Utilities/Reference/reference.html#//apple_ref/c/func/MakeDataExecutable + void CodeAlloc::flushICache(void *start, size_t len) { + MakeDataExecutable(start, len); + } +# endif + +#elif defined NANOJIT_ARM && defined VMCFG_SYMBIAN + void CodeAlloc::flushICache(void *ptr, size_t len) { + uint32_t start = (uint32_t)ptr; + uint32_t rangeEnd = start + len; + User::IMB_Range((TAny*)start, (TAny*)rangeEnd); + } + +#elif defined AVMPLUS_SPARC + // fixme: sync_instruction_memory is a solaris api, test for solaris not sparc + void CodeAlloc::flushICache(void *start, size_t len) { + sync_instruction_memory((char*)start, len); + } + +#elif defined NANOJIT_SH4 +#include /* CACHEFLUSH_*, */ +#include /* __NR_cacheflush, */ + void CodeAlloc::flushICache(void *start, size_t len) { + syscall(__NR_cacheflush, start, len, CACHEFLUSH_D_WB | CACHEFLUSH_I); + } + +#elif defined(AVMPLUS_UNIX) && defined(NANOJIT_MIPS) + void CodeAlloc::flushICache(void *start, size_t len) { + // FIXME Use synci on MIPS32R2 + cacheflush((char *)start, len, BCACHE); + } + +#elif defined AVMPLUS_UNIX + #ifdef ANDROID + void CodeAlloc::flushICache(void *start, size_t len) { + cacheflush((int)start, (int)start + len, 0); + } + #else + // fixme: __clear_cache is a libgcc feature, test for libgcc or gcc + void CodeAlloc::flushICache(void *start, size_t len) { + __clear_cache((char*)start, (char*)start + len); + } + #endif +#endif // AVMPLUS_MAC && NANOJIT_PPC + + void CodeAlloc::addBlock(CodeList* &blocks, CodeList* b) { + NanoAssert(b->terminator != NULL); // should not be mucking with terminator blocks + b->next = blocks; + blocks = b; + } + + void CodeAlloc::addMem() { + void *mem = allocCodeChunk(bytesPerAlloc); // allocations never fail + totalAllocated += bytesPerAlloc; + NanoAssert(mem != NULL); // see allocCodeChunk contract in CodeAlloc.h + _nvprof("alloc page", uintptr_t(mem)>>12); + + CodeList* b = (CodeList*)mem; + b->lower = 0; + b->next = 0; + b->end = (NIns*) (uintptr_t(mem) + bytesPerAlloc - sizeofMinBlock); + b->isFree = true; + + // create a tiny terminator block, add to fragmented list, this way + // all other blocks have a valid block at b->higher + CodeList* terminator = b->higher; + b->terminator = terminator; + terminator->lower = b; + terminator->end = 0; // this is how we identify the terminator + terminator->isFree = false; + terminator->isExec = false; + terminator->terminator = 0; + debug_only(sanity_check();) + + // add terminator to heapblocks list so we can track whole blocks + terminator->next = heapblocks; + heapblocks = terminator; + + addBlock(availblocks, b); // add to free list + } + + CodeList* CodeAlloc::getBlock(NIns* start, NIns* end) { + CodeList* b = (CodeList*) (uintptr_t(start) - offsetof(CodeList, code)); + NanoAssert(b->end == end && b->next == 0); (void) end; + return b; + } + + CodeList* CodeAlloc::removeBlock(CodeList* &blocks) { + CodeList* b = blocks; + NanoAssert(b != NULL); + NanoAssert(b->terminator != NULL); // should not be mucking with terminator blocks + blocks = b->next; + b->next = 0; + return b; + } + + void CodeAlloc::add(CodeList* &blocks, NIns* start, NIns* end) { + addBlock(blocks, getBlock(start, end)); + } + + /** + * split a block by freeing the hole in the middle defined by [holeStart,holeEnd), + * and adding the used prefix and suffix parts to the blocks CodeList. + */ + void CodeAlloc::addRemainder(CodeList* &blocks, NIns* start, NIns* end, NIns* holeStart, NIns* holeEnd) { + NanoAssert(start < end && start <= holeStart && holeStart <= holeEnd && holeEnd <= end); + // shrink the hole by aligning holeStart forward and holeEnd backward + holeStart = (NIns*) ((uintptr_t(holeStart) + sizeof(NIns*)-1) & ~(sizeof(NIns*)-1)); + holeEnd = (NIns*) (uintptr_t(holeEnd) & ~(sizeof(NIns*)-1)); + // hole needs to be big enough for 2 headers + 1 block of free space (subtraction not used in check to avoid wraparound) + size_t minHole = headerSpaceFor(2) + blkSpaceFor(1); + if (uintptr_t(holeEnd) < minHole + uintptr_t(holeStart) ) { + // the hole is too small to make a new free block and a new used block. just keep + // the whole original block and don't free anything. + add(blocks, start, end); + } else if (holeStart == start && holeEnd == end) { + // totally empty block. free whole start-end range + this->free(start, end); + } else if (holeStart == start) { + // hole is lower-aligned with start, so just need one new block + // b1 b2 + CodeList* b1 = getBlock(start, end); + CodeList* b2 = (CodeList*) (uintptr_t(holeEnd) - offsetof(CodeList, code)); + b2->terminator = b1->terminator; + b2->isFree = false; + b2->next = 0; + b2->higher = b1->higher; + b2->lower = b1; + b2->higher->lower = b2; + b1->higher = b2; + debug_only(sanity_check();) + this->free(b1->start(), b1->end); + addBlock(blocks, b2); + } else if (holeEnd == end) { + // hole is right-aligned with end, just need one new block + // todo + NanoAssert(false); + } else { + // there's enough space left to split into three blocks (two new ones) + CodeList* b1 = getBlock(start, end); + CodeList* b2 = (CodeList*) (void*) holeStart; + CodeList* b3 = (CodeList*) (uintptr_t(holeEnd) - offsetof(CodeList, code)); + b1->higher = b2; + b2->lower = b1; + b2->higher = b3; + b2->isFree = false; // redundant, since we're about to free, but good hygiene + b2->terminator = b1->terminator; + b3->lower = b2; + b3->end = end; + b3->isFree = false; + b3->higher->lower = b3; + b3->terminator = b1->terminator; + b2->next = 0; + b3->next = 0; + debug_only(sanity_check();) + this->free(b2->start(), b2->end); + addBlock(blocks, b3); + addBlock(blocks, b1); + } + } + +#ifdef PERFM + // This method is used only for profiling purposes. + // See CodegenLIR::emitMD() in Tamarin for an example. + + size_t CodeAlloc::size(const CodeList* blocks) { + size_t size = 0; + for (const CodeList* b = blocks; b != 0; b = b->next) + size += int((uintptr_t)b->end - (uintptr_t)b); + return size; + } +#endif + + size_t CodeAlloc::size() { + return totalAllocated; + } + + // check that all block neighbors are correct + #ifdef _DEBUG + void CodeAlloc::sanity_check() { + for (CodeList* hb = heapblocks; hb != 0; hb = hb->next) { + NanoAssert(hb->higher == 0); + for (CodeList* b = hb->lower; b != 0; b = b->lower) { + NanoAssert(b->higher->lower == b); + } + } + for (CodeList* avail = this->availblocks; avail; avail = avail->next) { + NanoAssert(avail->isFree && avail->size() >= minAllocSize); + } + + #if CROSS_CHECK_FREE_LIST + for(CodeList* term = heapblocks; term; term = term->next) { + for(CodeList* hb = term->lower; hb; hb = hb->lower) { + if (hb->isFree && hb->size() >= minAllocSize) { + bool found_on_avail = false; + for (CodeList* avail = this->availblocks; !found_on_avail && avail; avail = avail->next) { + found_on_avail = avail == hb; + } + + NanoAssert(found_on_avail); + } + } + } + for (CodeList* avail = this->availblocks; avail; avail = avail->next) { + bool found_in_heapblocks = false; + for(CodeList* term = heapblocks; !found_in_heapblocks && term; term = term->next) { + for(CodeList* hb = term->lower; !found_in_heapblocks && hb; hb = hb->lower) { + found_in_heapblocks = hb == avail; + } + } + NanoAssert(found_in_heapblocks); + } + #endif /* CROSS_CHECK_FREE_LIST */ + } + #endif + + // Loop through a list of blocks marking the chunks executable. If we encounter + // multiple blocks in the same chunk, only the first block will cause the + // chunk to become executable, the other calls will no-op (isExec flag checked) + void CodeAlloc::markExec(CodeList* &blocks) { + for (CodeList *b = blocks; b != 0; b = b->next) { + markChunkExec(b->terminator); + } + } + + // Variant of markExec(CodeList*) that walks all heapblocks (i.e. chunks) marking + // each one executable. On systems where bytesPerAlloc is low (i.e. have lots + // of elements in the list) this can be expensive. + void CodeAlloc::markAllExec() { + for (CodeList* hb = heapblocks; hb != NULL; hb = hb->next) { + markChunkExec(hb); + } + } + + // make an entire chunk executable + void CodeAlloc::markChunkExec(CodeList* term) { + NanoAssert(term->terminator == NULL); + if (!term->isExec) { + term->isExec = true; + markCodeChunkExec(firstBlock(term), bytesPerAlloc); + } + } +} +#endif // FEATURE_NANOJIT diff --git a/js/src/nanojit/CodeAlloc.h b/js/src/nanojit/CodeAlloc.h new file mode 100644 index 0000000..b5cb2c6 --- /dev/null +++ b/js/src/nanojit/CodeAlloc.h @@ -0,0 +1,237 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __nanojit_CodeAlloc__ +#define __nanojit_CodeAlloc__ + +namespace nanojit +{ + /** + * CodeList is a single block of code. The next field is used to + * form linked lists of non-contiguous blocks of code. Clients use CodeList* + * to point to the first block in a list. + */ + class CodeList + { + friend class CodeAlloc; + + /** for making singly linked lists of blocks in any order */ + CodeList* next; + + /** adjacent block at lower address. This field plus higher + form a doubly linked list of blocks in address order, used + for splitting and coalescing blocks. */ + CodeList* lower; + + /** pointer to the heapblock terminal that represents the code chunk containing this block */ + CodeList* terminator; + + /** true if block is free, false otherwise */ + bool isFree; + + /** (only valid for terminator blocks). Set true just before calling + * markCodeChunkExec() and false just after markCodeChunkWrite() */ + bool isExec; + + union { + // this union is used in leu of pointer punning in code + // the end of this block is always the address of the next higher block + CodeList* higher; // adjacent block at higher address + NIns* end; // points just past the end + }; + + /** code holds this block's payload of binary code, from + here to this->end */ + NIns code[1]; // more follows + + /** return the starting address for this block only */ + NIns* start() { return &code[0]; } + + /** return just the usable size of this block */ + size_t size() const { return uintptr_t(end) - uintptr_t(&code[0]); } + + /** return the whole size of this block including overhead */ + size_t blockSize() const { return uintptr_t(end) - uintptr_t(this); } + + public: + /** true is the given NIns is contained within this block */ + bool isInBlock(NIns* n) { return (n >= this->start() && n < this->end); } + }; + + /** + * Code memory allocator is a long lived manager for many code blocks that + * manages interaction with an underlying code memory allocator, + * sets page permissions. CodeAlloc provides APIs for allocating and freeing + * individual blocks of code memory (for methods, stubs, or compiled + * traces), static functions for managing lists of allocated code, and has + * a few pure virtual methods that embedders must implement to provide + * memory to the allocator. + * + * A "chunk" is a region of memory obtained from allocCodeChunk; it must + * be page aligned and be a multiple of the system page size. + * + * A "block" is a region of memory within a chunk. It can be arbitrarily + * sized and aligned, but is always contained within a single chunk. + * class CodeList represents one block; the members of CodeList track the + * extent of the block and support creating lists of blocks. + * + * The allocator coalesces free blocks when it can, in free(), but never + * coalesces chunks. + */ + class CodeAlloc + { + static const size_t sizeofMinBlock = offsetof(CodeList, code); + static const size_t minAllocSize = LARGEST_UNDERRUN_PROT; + + // Return the number of bytes needed for the header of 'n' blocks + static size_t headerSpaceFor(uint32_t nbrBlks) { return nbrBlks * sizeofMinBlock; } + + // Return the number of bytes needed in order to safely construct 'n' blocks + static size_t blkSpaceFor(uint32_t nbrBlks) { return (nbrBlks * minAllocSize) + headerSpaceFor(nbrBlks); } + + /** Terminator blocks. All active and free allocations + are reachable by traversing this chain and each + element's lower chain. */ + CodeList* heapblocks; + + /** Reusable blocks. */ + CodeList* availblocks; + size_t totalAllocated; + + /** Cached value of VMPI_getVMPageSize */ + const size_t bytesPerPage; + + /** Number of bytes to request from VMPI layer, always a multiple of the page size */ + const size_t bytesPerAlloc; + + /** remove one block from a list */ + static CodeList* removeBlock(CodeList* &list); + + /** add one block to a list */ + static void addBlock(CodeList* &blocks, CodeList* b); + + /** compute the CodeList pointer from a [start, end) range */ + static CodeList* getBlock(NIns* start, NIns* end); + + /** add raw memory to the free list */ + void addMem(); + + /** make sure all the higher/lower pointers are correct for every block */ + void sanity_check(); + + /** find the beginning of the heapblock terminated by term */ + CodeList* firstBlock(CodeList* term); + + // + // CodeAlloc's SPI (Service Provider Interface). Implementations must be + // defined by nanojit embedder. Allocation failures should cause an exception + // or longjmp; nanojit intentionally does not check for null. + // + + /** allocate nbytes of memory to hold code. Never return null! */ + void* allocCodeChunk(size_t nbytes); + + /** free a block previously allocated by allocCodeMem. nbytes will + * match the previous allocCodeMem, but is provided here as well + * to mirror the mmap()/munmap() api. markCodeChunkWrite() will have + * been called if necessary, so it is not necessary for freeCodeChunk() + * to do it again. */ + void freeCodeChunk(void* addr, size_t nbytes); + + /** make this specific extent ready to execute (might remove write) */ + void markCodeChunkExec(void* addr, size_t nbytes); + + /** make this extent ready to modify (might remove exec) */ + void markCodeChunkWrite(void* addr, size_t nbytes); + + public: + CodeAlloc(); + ~CodeAlloc(); + + /** return all the memory allocated through this allocator to the gcheap. */ + void reset(); + + /** allocate some memory (up to 'byteLimit' bytes) for code returning pointers to the region. A zero 'byteLimit' means no limit */ + void alloc(NIns* &start, NIns* &end, size_t byteLimit); + + /** free a block of memory previously returned by alloc() */ + void free(NIns* start, NIns* end); + + /** free several blocks */ + void freeAll(CodeList* &code); + + /** flush the icache for all code in the list, before executing */ + static void flushICache(CodeList* &blocks); + + /** flush the icache for a specific extent */ + static void flushICache(void *start, size_t len); + + /** add the ranges [start, holeStart) and [holeEnd, end) to code, and + free [holeStart, holeEnd) if the hole is >= minsize */ + void addRemainder(CodeList* &code, NIns* start, NIns* end, NIns* holeStart, NIns* holeEnd); + + /** add a block previously returned by alloc(), to code */ + static void add(CodeList* &code, NIns* start, NIns* end); + + /** return the number of bytes in all the code blocks in "code", including block overhead */ +#ifdef PERFM + static size_t size(const CodeList* code); +#endif + + /** return the total number of bytes held by this CodeAlloc. */ + size_t size(); + + /** print out stats about heap usage */ + void logStats(); + + /** protect all code managed by this CodeAlloc */ + void markAllExec(); + + /** protect all mem in the block list */ + void markExec(CodeList* &blocks); + + /** protect an entire chunk */ + void markChunkExec(CodeList* term); + + /** unprotect the code chunk containing just this one block */ + void markBlockWrite(CodeList* b); + }; +} + +#endif // __nanojit_CodeAlloc__ diff --git a/js/src/nanojit/Containers.cpp b/js/src/nanojit/Containers.cpp new file mode 100644 index 0000000..ecbe042 --- /dev/null +++ b/js/src/nanojit/Containers.cpp @@ -0,0 +1,95 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nanojit.h" + +#ifdef FEATURE_NANOJIT + +namespace nanojit +{ + BitSet::BitSet(Allocator& allocator, int nbits) + : allocator(allocator) + , cap((nbits+63)>>6) + , bits((int64_t*)allocator.alloc(cap * sizeof(int64_t))) + { + reset(); + } + + void BitSet::reset() + { + for (int i=0, n=cap; i < n; i++) + bits[i] = 0; + } + + bool BitSet::setFrom(BitSet& other) + { + int c = other.cap; + if (c > cap) + grow(c); + int64_t *bits = this->bits; + int64_t *otherbits = other.bits; + int64_t newbits = 0; + for (int i=0; i < c; i++) { + int64_t b = bits[i]; + int64_t b2 = otherbits[i]; + newbits |= b2 & ~b; // bits in b2 that are not in b + bits[i] = b|b2; + } + return newbits != 0; + } + + /** keep doubling the bitset length until w fits */ + void BitSet::grow(int w) + { + int cap2 = cap; + do { + cap2 <<= 1; + } while (w > cap2); + int64_t *bits2 = (int64_t*) allocator.alloc(cap2 * sizeof(int64_t)); + int j=0; + for (; j < cap; j++) + bits2[j] = bits[j]; + for (; j < cap2; j++) + bits2[j] = 0; + cap = cap2; + bits = bits2; + } +} + +#endif // FEATURE_NANOJIT diff --git a/js/src/nanojit/Containers.h b/js/src/nanojit/Containers.h new file mode 100644 index 0000000..cd4fe66 --- /dev/null +++ b/js/src/nanojit/Containers.h @@ -0,0 +1,465 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __nanojit_Containers__ +#define __nanojit_Containers__ + +namespace nanojit +{ + /** simple linear bit array, memory taken from Allocator + * warning: when bit array grows, old memory is wasted since it + * was allocated from Allocator. pre-size the bitmap when possible + * by passing nbits to the constructor. */ + class BitSet { + Allocator &allocator; + int cap; + int64_t *bits; + static const int64_t ONE = 1; + static const int SHIFT = 6; + + inline int bitnum2word(int i) { + return i >> 6; + } + inline int64_t bitnum2mask(int i) { + return ONE << (i & 63); + } + + /** keep doubling array to fit at least w words */ + void grow(int w); + + public: + BitSet(Allocator& allocator, int nbits=128); + + /** clear all bits */ + void reset(); + + /** perform a bitwise or with BitSet other, return true if + * this bitset was modified */ + bool setFrom(BitSet& other); + + /** return bit i as a bool */ + bool get(int i) { + NanoAssert(i >= 0); + int w = bitnum2word(i); + if (w < cap) + return (bits[w] & bitnum2mask(i)) != 0; + return false; + } + + /** set bit i */ + void set(int i) { + NanoAssert(i >= 0); + int w = bitnum2word(i); + if (w >= cap) + grow(w); + bits[w] |= bitnum2mask(i); + } + + /** clear bit i */ + void clear(int i) { + NanoAssert(i >= 0); + int w = bitnum2word(i); + if (w < cap) + bits[w] &= ~bitnum2mask(i); + } + }; + + /** Seq is a single node in a linked list */ + template class Seq { + public: + Seq(T head, Seq* tail=NULL) : head(head), tail(tail) {} + T head; + Seq* tail; + }; + + /** SeqBuilder is used to create a linked list of Seq by inserting + * nodes either at the beginning, with insert(), or at the end, with + * add(). Once built, the actual list can be retained while this + * SeqBuilder can be discarded. */ + template class SeqBuilder { + public: + SeqBuilder(Allocator& allocator) + : allocator(allocator) + , items(NULL) + , last(NULL) + { } + + /** add item to beginning of list */ + void insert(T item) { + Seq* e = new (allocator) Seq(item, items); + if (last == NULL) + last = e; + items = e; + } + + /** add item to end of list */ + void add(T item) { + Seq* e = new (allocator) Seq(item); + if (last == NULL) + items = e; + else + last->tail = e; + last = e; + } + + /** return first item in sequence */ + Seq* get() const { + return items; + } + + /** self explanitory */ + bool isEmpty() const { + return items == NULL; + } + + /** de-reference all items */ + void clear() { + items = last = NULL; + } + + private: + Allocator& allocator; + Seq* items; + Seq* last; + }; + +#ifdef NANOJIT_64BIT + static inline size_t murmurhash(const void *key, size_t len) { + const uint64_t m = 0xc6a4a7935bd1e995; + const int r = 47; + uint64_t h = 0; + + const uint64_t *data = (const uint64_t*)key; + const uint64_t *end = data + (len/8); + + while(data != end) + { + uint64_t k = *data++; + + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; + } + + const unsigned char *data2 = (const unsigned char*)data; + + switch(len & 7) { + case 7: h ^= uint64_t(data2[6]) << 48; + case 6: h ^= uint64_t(data2[5]) << 40; + case 5: h ^= uint64_t(data2[4]) << 32; + case 4: h ^= uint64_t(data2[3]) << 24; + case 3: h ^= uint64_t(data2[2]) << 16; + case 2: h ^= uint64_t(data2[1]) << 8; + case 1: h ^= uint64_t(data2[0]); + h *= m; + }; + + h ^= h >> r; + h *= m; + h ^= h >> r; + + return (size_t)h; + } +#else + static inline size_t murmurhash(const void * key, size_t len) { + const uint32_t m = 0x5bd1e995; + const int r = 24; + uint32_t h = 0; + + const unsigned char * data = (const unsigned char *)key; + while(len >= 4) { + uint32_t k = *(size_t *)(void*)data; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + switch(len) { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + }; + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return (size_t)h; + } +#endif + + template struct DefaultHash { + static size_t hash(const K &k) { + // (const void*) cast is required by ARM RVCT 2.2 + return murmurhash((const void*) &k, sizeof(K)); + } + }; + + template struct DefaultHash { + static size_t hash(K* k) { + uintptr_t h = (uintptr_t) k; + // move the low 3 bits higher up since they're often 0 + h = (h>>3) ^ (h<<((sizeof(uintptr_t) * 8) - 3)); + return (size_t) h; + } + }; + + /** Bucket hashtable with a fixed # of buckets (never rehash) + * Intended for use when a reasonable # of buckets can be estimated ahead of time. + * Note that operator== is used to compare keys. + */ + template > class HashMap { + Allocator& allocator; + size_t nbuckets; + class Node { + public: + K key; + T value; + Node(K k, T v) : key(k), value(v) { } + }; + Seq** buckets; + + /** return the node containing K, and the bucket index, or NULL if not found */ + Node* find(K k, size_t &i) { + i = H::hash(k) % nbuckets; + for (Seq* p = buckets[i]; p != NULL; p = p->tail) { + if (p->head.key == k) + return &p->head; + } + return NULL; + } + public: + HashMap(Allocator& a, size_t nbuckets = 16) + : allocator(a) + , nbuckets(nbuckets) + , buckets(new (a) Seq*[nbuckets]) + { + NanoAssert(nbuckets > 0); + clear(); + } + + /** clear all buckets. Since we allocate all memory from Allocator, + * nothing needs to be freed. */ + void clear() { + VMPI_memset(buckets, 0, sizeof(Seq*) * nbuckets); + } + + /** add (k,v) to the map. If k is already in the map, replace the value */ + void put(const K& k, const T& v) { + size_t i; + Node* n = find(k, i); + if (n) { + n->value = v; + return; + } + buckets[i] = new (allocator) Seq(Node(k,v), buckets[i]); + } + + /** return v for element k, or T(0) if k is not present */ + T get(const K& k) { + size_t i; + Node* n = find(k, i); + return n ? n->value : 0; + } + + /** returns true if k is in the map. */ + bool containsKey(const K& k) { + size_t i; + return find(k, i) != 0; + } + + /** remove k from the map, if it is present. if not, remove() + * silently returns */ + void remove(const K& k) { + size_t i = H::hash(k) % nbuckets; + Seq** prev = &buckets[i]; + for (Seq* p = buckets[i]; p != NULL; p = p->tail) { + if (p->head.key == k) { + (*prev) = p->tail; + return; + } + prev = &p->tail; + } + } + + /** Iter is an iterator for HashMap, intended to be instantiated on + * the stack. Iteration order is undefined. Mutating the hashmap + * while iteration is in progress gives undefined results. All iteration + * state is in class Iter, so multiple iterations can be in progress + * at the same time. for example: + * + * HashMap::Iter iter(map); + * while (iter.next()) { + * K *k = iter.key(); + * T *t = iter.value(); + * } + */ + class Iter { + friend class HashMap; + const HashMap ↦ + int bucket; + const Seq* current; + + public: + Iter(HashMap& map) : map(map), bucket((int)map.nbuckets-1), current(NULL) + { } + + /** return true if more (k,v) remain to be visited */ + bool next() { + if (current) + current = current->tail; + while (bucket >= 0 && !current) + current = map.buckets[bucket--]; + return current != NULL; + } + + /** return the current key */ + const K& key() const { + NanoAssert(current != NULL); + return current->head.key; + } + + /** return the current value */ + const T& value() const { + NanoAssert(current != NULL); + return current->head.value; + } + }; + + /** return true if the hashmap has no elements */ + bool isEmpty() { + Iter iter(*this); + return !iter.next(); + } + }; + + /** + * Simple binary tree. No balancing is performed under the assumption + * that the only users of this structure are not performance critical. + */ + template class TreeMap { + Allocator& alloc; + class Node { + public: + Node* left; + Node* right; + K key; + T value; + Node(K k, T v) : left(NULL), right(NULL), key(k), value(v) + { } + }; + Node* root; + + /** + * helper method to recursively insert (k,v) below Node n or a child + * of n so that the binary search tree remains well formed. + */ + void insert(Node* &n, K k, T v) { + if (!n) + n = new (alloc) Node(k, v); + else if (k == n->key) + n->value = v; + else if (k < n->key) + insert(n->left, k, v); + else + insert(n->right, k, v); + } + + /** + * search for key k below Node n and return n if found, or the + * closest parent n where k should be inserted. + */ + Node* find(Node* n, K k) { + if (!n) + return NULL; + if (k == n->key) + return n; + if (k < n->key) + return find(n->left, k); + if (n->right) + return find(n->right, k); + return n; + } + + public: + TreeMap(Allocator& alloc) : alloc(alloc), root(NULL) + { } + + /** set k = v in the map. if k already exists, replace its value */ + void put(K k, T v) { + insert(root, k, v); + } + + /** return the closest key that is <= k, or NULL if k + is smaller than every key in the Map. */ + K findNear(K k) { + Node* n = find(root, k); + return n ? n->key : 0; + } + + /** returns the value for k or NULL */ + T get(K k) { + Node* n = find(root, k); + return (n && n->key == k) ? n->value : 0; + } + + /** returns true iff k is in the Map. */ + bool containsKey(K k) { + Node* n = find(root, k); + return n && n->key == k; + } + + /** make the tree empty. trivial since we dont manage elements */ + void clear() { + root = NULL; + } + }; +} +#endif // __nanojit_Containers__ diff --git a/js/src/nanojit/Fragmento.cpp b/js/src/nanojit/Fragmento.cpp new file mode 100644 index 0000000..6bf35cf --- /dev/null +++ b/js/src/nanojit/Fragmento.cpp @@ -0,0 +1,80 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * Mozilla TraceMonkey Team + * Asko Tontti + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nanojit.h" + +namespace nanojit +{ + #ifdef FEATURE_NANOJIT + + using namespace avmplus; + + // + // Fragment + // + Fragment::Fragment(const void* _ip + verbose_only(, uint32_t profFragID)) + : + lirbuf(NULL), + lastIns(NULL), + ip(_ip), + recordAttempts(0), + fragEntry(NULL), + verbose_only( loopLabel(NULL), ) + verbose_only( profFragID(profFragID), ) + verbose_only( profCount(0), ) + verbose_only( nStaticExits(0), ) + verbose_only( nCodeBytes(0), ) + verbose_only( nExitBytes(0), ) + verbose_only( guardNumberer(1), ) + verbose_only( guardsForFrag(NULL), ) + _code(NULL), + _hits(0) + { + // when frag profiling is enabled, profFragID should be >= 1, + // else it should be zero. However, there's no way to assert + // that here since there's no way to determine whether frag + // profiling is enabled. + } + #endif /* FEATURE_NANOJIT */ +} + + diff --git a/js/src/nanojit/Fragmento.h b/js/src/nanojit/Fragmento.h new file mode 100644 index 0000000..f4bbe7a --- /dev/null +++ b/js/src/nanojit/Fragmento.h @@ -0,0 +1,135 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * Mozilla TraceMonkey Team + * Asko Tontti + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#ifndef __nanojit_Fragmento__ +#define __nanojit_Fragmento__ + +namespace nanojit +{ + struct GuardRecord; + + /** + * Fragments are linear sequences of native code that have a single entry + * point at the start of the fragment and may have one or more exit points + * + * It may turn out that that this arrangement causes too much traffic + * between d and i-caches and that we need to carve up the structure differently. + */ + class Fragment + { + public: + Fragment(const void* + verbose_only(, uint32_t profFragID)); + + NIns* code() { return _code; } + void setCode(NIns* codee) { _code = codee; } + int32_t& hits() { return _hits; } + + LirBuffer* lirbuf; + LIns* lastIns; + + const void* ip; + uint32_t recordAttempts; + NIns* fragEntry; + + // for fragment entry and exit profiling. See detailed + // how-to-use comment below. + verbose_only( LIns* loopLabel; ) // where's the loop top? + verbose_only( uint32_t profFragID; ) + verbose_only( uint32_t profCount; ) + verbose_only( uint32_t nStaticExits; ) + verbose_only( size_t nCodeBytes; ) + verbose_only( size_t nExitBytes; ) + verbose_only( uint32_t guardNumberer; ) + verbose_only( GuardRecord* guardsForFrag; ) + + private: + NIns* _code; // ptr to start of code + int32_t _hits; + }; +} + +/* + * How to use fragment profiling + * + * Fragprofiling adds code to count how many times each fragment is + * entered, and how many times each guard (exit) is taken. Using this + * it's possible to easily find which fragments are hot, which ones + * typically exit early, etc. The fragprofiler also gathers some + * simple static info: for each fragment, the number of code bytes, + * number of exit-block bytes, and number of guards (exits). + * + * Fragments and guards are given unique IDs (FragID, GuardID) which + * are shown in debug printouts, so as to facilitate navigating from + * the accumulated statistics to the associated bits of code. + * GuardIDs are issued automatically, but FragIDs you must supply when + * calling Fragment::Fragment. Supply values >= 1, and supply a + * different value for each new fragment (doesn't matter what, they + * just have to be unique and >= 1); else + * js_FragProfiling_FragFinalizer will assert. + * + * How to use/embed: + * + * - use a debug build (one with NJ_VERBOSE). Without it, none of + * this code is compiled in. + * + * - set LC_FragProfile in the lcbits of the LogControl* object handed + * to Nanojit + * + * When enabled, Fragment::profCount is incremented every time the + * fragment is entered, and GuardRecord::profCount is incremented + * every time that guard exits. However, NJ has no way to know where + * the fragment entry/loopback point is. So you must set + * Fragment::loopLabel before running the assembler, so as to indicate + * where the fragment-entry counter increment should be placed. If + * the fragment does not naturally have a loop label then you will + * need to artificially add one. + * + * It is the embedder's problem to fish out, collate and present the + * accumulated stats at the end of the Fragment's lifetime. A + * Fragment contains stats indicating its entry count and static code + * sizes. It also has a ::guardsForFrag field, which is a linked list + * of GuardRecords, and by traversing them you can get hold of the + * exit counts. + */ + +#endif // __nanojit_Fragmento__ diff --git a/js/src/nanojit/LIR.cpp b/js/src/nanojit/LIR.cpp new file mode 100644 index 0000000..cddca6d --- /dev/null +++ b/js/src/nanojit/LIR.cpp @@ -0,0 +1,3857 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nanojit.h" + +namespace nanojit +{ + using namespace avmplus; + #ifdef FEATURE_NANOJIT + + const uint8_t repKinds[] = { +#define OP___(op, number, repKind, retType, isCse) \ + LRK_##repKind, +#include "LIRopcode.tbl" +#undef OP___ + 0 + }; + + const LTy retTypes[] = { +#define OP___(op, number, repKind, retType, isCse) \ + LTy_##retType, +#include "LIRopcode.tbl" +#undef OP___ + LTy_V + }; + + const int8_t isCses[] = { +#define OP___(op, number, repKind, retType, isCse) \ + isCse, +#include "LIRopcode.tbl" +#undef OP___ + 0 + }; + + // LIR verbose specific + #ifdef NJ_VERBOSE + + const char* lirNames[] = { +#define OP___(op, number, repKind, retType, isCse) \ + #op, +#include "LIRopcode.tbl" +#undef OP___ + NULL + }; + + #endif /* NANOJIT_VERBOSE */ + + uint32_t CallInfo::count_args() const + { + uint32_t argc = 0; + uint32_t argt = _typesig; + argt >>= TYPESIG_FIELDSZB; // remove retType + while (argt) { + argc++; + argt >>= TYPESIG_FIELDSZB; + } + return argc; + } + + uint32_t CallInfo::count_int32_args() const + { + uint32_t argc = 0; + uint32_t argt = _typesig; + argt >>= TYPESIG_FIELDSZB; // remove retType + while (argt) { + ArgType a = ArgType(argt & TYPESIG_FIELDMASK); + if (a == ARGTYPE_I || a == ARGTYPE_UI) + argc++; + argt >>= TYPESIG_FIELDSZB; + } + return argc; + } + + uint32_t CallInfo::getArgTypes(ArgType* argTypes) const + { + uint32_t argc = 0; + uint32_t argt = _typesig; + argt >>= TYPESIG_FIELDSZB; // remove retType + while (argt) { + ArgType a = ArgType(argt & TYPESIG_FIELDMASK); + argTypes[argc] = a; + argc++; + argt >>= TYPESIG_FIELDSZB; + } + return argc; + } + + // implementation +#ifdef NJ_VERBOSE + void ReverseLister::finish() + { + _logc->printf("\n"); + _logc->printf("=== BEGIN %s ===\n", _title); + int j = 0; + for (Seq* p = _strs.get(); p != NULL; p = p->tail) + _logc->printf(" %02d: %s\n", j++, p->head); + _logc->printf("=== END %s ===\n", _title); + _logc->printf("\n"); + } + + LIns* ReverseLister::read() + { + // This check is necessary to avoid printing the LIR_start multiple + // times due to lookahead in Assembler::gen(). + if (_prevIns && _prevIns->isop(LIR_start)) + return _prevIns; + LIns* ins = in->read(); + InsBuf b; + const char* str = _printer->formatIns(&b, ins); + char* cpy = new (_alloc) char[strlen(str)+1]; + VMPI_strcpy(cpy, str); + _strs.insert(cpy); + _prevIns = ins; + return ins; + } +#endif + + // LCompressedBuffer + LirBuffer::LirBuffer(Allocator& alloc) : +#ifdef NJ_VERBOSE + printer(NULL), +#endif + abi(ABI_FASTCALL), state(NULL), param1(NULL), sp(NULL), rp(NULL), + _allocator(alloc) + { + clear(); + } + + void LirBuffer::clear() + { + // clear the stats, etc + _unused = 0; + _limit = 0; + _stats.lir = 0; + for (int i = 0; i < NumSavedRegs; ++i) + savedRegs[i] = NULL; + chunkAlloc(); + } + + void LirBuffer::chunkAlloc() + { + _unused = (uintptr_t) _allocator.alloc(CHUNK_SZB); + NanoAssert(_unused != 0); // Allocator.alloc() never returns null. See Allocator.h + _limit = _unused + CHUNK_SZB; + } + + int32_t LirBuffer::insCount() + { + return _stats.lir; + } + + // Allocate a new page, and write the first instruction to it -- a skip + // linking to last instruction of the previous page. + void LirBuffer::moveToNewChunk(uintptr_t addrOfLastLInsOnCurrentChunk) + { + chunkAlloc(); + // Link LIR stream back to prior instruction. + // Unlike all the ins*() functions, we don't call makeRoom() here + // because we know we have enough space, having just started a new + // page. + LInsSk* insSk = (LInsSk*)_unused; + LIns* ins = insSk->getLIns(); + ins->initLInsSk((LIns*)addrOfLastLInsOnCurrentChunk); + _unused += sizeof(LInsSk); + verbose_only(_stats.lir++); + } + + // Make room for a single instruction. + uintptr_t LirBuffer::makeRoom(size_t szB) + { + // Make sure the size is ok + NanoAssert(0 == szB % sizeof(void*)); + NanoAssert(sizeof(LIns) <= szB && szB <= sizeof(LInsSt)); // LInsSt is the biggest one + NanoAssert(_unused < _limit); + + debug_only( bool moved = false; ) + + // If the instruction won't fit on the current chunk, get a new chunk + if (_unused + szB > _limit) { + uintptr_t addrOfLastLInsOnChunk = _unused - sizeof(LIns); + moveToNewChunk(addrOfLastLInsOnChunk); + debug_only( moved = true; ) + } + + // We now know that we are on a chunk that has the requested amount of + // room: record the starting address of the requested space and bump + // the pointer. + uintptr_t startOfRoom = _unused; + _unused += szB; + verbose_only(_stats.lir++); // count the instruction + + // If there's no more space on this chunk, move to a new one. + // (This will only occur if the asked-for size filled up exactly to + // the end of the chunk.) This ensures that next time we enter this + // function, _unused won't be pointing one byte past the end of + // the chunk, which would break everything. + if (_unused >= _limit) { + // Check we used exactly the remaining space + NanoAssert(_unused == _limit); + NanoAssert(!moved); // shouldn't need to moveToNewChunk twice + uintptr_t addrOfLastLInsOnChunk = _unused - sizeof(LIns); + moveToNewChunk(addrOfLastLInsOnChunk); + } + + // Make sure it's word-aligned. + NanoAssert(0 == startOfRoom % sizeof(void*)); + return startOfRoom; + } + + LIns* LirBufWriter::insStore(LOpcode op, LIns* val, LIns* base, int32_t d, AccSet accSet) + { + if (isS16(d)) { + LInsSt* insSt = (LInsSt*)_buf->makeRoom(sizeof(LInsSt)); + LIns* ins = insSt->getLIns(); + ins->initLInsSt(op, val, base, d, accSet); + return ins; + } else { + // If the displacement is more than 16 bits, put it in a separate instruction. + return insStore(op, val, ins2(LIR_addp, base, insImmWord(d)), 0, accSet); + } + } + + LIns* LirBufWriter::ins0(LOpcode op) + { + LInsOp0* insOp0 = (LInsOp0*)_buf->makeRoom(sizeof(LInsOp0)); + LIns* ins = insOp0->getLIns(); + ins->initLInsOp0(op); + return ins; + } + + LIns* LirBufWriter::ins1(LOpcode op, LIns* o1) + { + LInsOp1* insOp1 = (LInsOp1*)_buf->makeRoom(sizeof(LInsOp1)); + LIns* ins = insOp1->getLIns(); + ins->initLInsOp1(op, o1); + return ins; + } + + LIns* LirBufWriter::ins2(LOpcode op, LIns* o1, LIns* o2) + { + LInsOp2* insOp2 = (LInsOp2*)_buf->makeRoom(sizeof(LInsOp2)); + LIns* ins = insOp2->getLIns(); + ins->initLInsOp2(op, o1, o2); + return ins; + } + + LIns* LirBufWriter::ins3(LOpcode op, LIns* o1, LIns* o2, LIns* o3) + { + LInsOp3* insOp3 = (LInsOp3*)_buf->makeRoom(sizeof(LInsOp3)); + LIns* ins = insOp3->getLIns(); + ins->initLInsOp3(op, o1, o2, o3); + return ins; + } + + LIns* LirBufWriter::insLoad(LOpcode op, LIns* base, int32_t d, AccSet accSet, LoadQual loadQual) + { + if (isS16(d)) { + LInsLd* insLd = (LInsLd*)_buf->makeRoom(sizeof(LInsLd)); + LIns* ins = insLd->getLIns(); + ins->initLInsLd(op, base, d, accSet, loadQual); + return ins; + } else { + // If the displacement is more than 16 bits, put it in a separate instruction. + // Note that CseFilter::insLoad() also does this, so this will + // only occur if CseFilter has been removed from the pipeline. + return insLoad(op, ins2(LIR_addp, base, insImmWord(d)), 0, accSet, loadQual); + } + } + + LIns* LirBufWriter::insGuard(LOpcode op, LIns* c, GuardRecord *gr) + { + debug_only( if (LIR_x == op || LIR_xbarrier == op) NanoAssert(!c); ) + return ins2(op, c, (LIns*)gr); + } + + LIns* LirBufWriter::insGuardXov(LOpcode op, LIns* a, LIns* b, GuardRecord *gr) + { + return ins3(op, a, b, (LIns*)gr); + } + + LIns* LirBufWriter::insBranch(LOpcode op, LIns* condition, LIns* toLabel) + { + NanoAssert((op == LIR_j && !condition) || + ((op == LIR_jf || op == LIR_jt) && condition)); + return ins2(op, condition, toLabel); + } + + LIns* LirBufWriter::insBranchJov(LOpcode op, LIns* a, LIns* b, LIns* toLabel) + { + return ins3(op, a, b, toLabel); + } + + LIns* LirBufWriter::insJtbl(LIns* index, uint32_t size) + { + LInsJtbl* insJtbl = (LInsJtbl*) _buf->makeRoom(sizeof(LInsJtbl)); + LIns** table = new (_buf->_allocator) LIns*[size]; + LIns* ins = insJtbl->getLIns(); + VMPI_memset(table, 0, size * sizeof(LIns*)); + ins->initLInsJtbl(index, size, table); + return ins; + } + + LIns* LirBufWriter::insAlloc(int32_t size) + { + size = (size+3)>>2; // # of required 32bit words + LInsI* insI = (LInsI*)_buf->makeRoom(sizeof(LInsI)); + LIns* ins = insI->getLIns(); + ins->initLInsI(LIR_allocp, size); + return ins; + } + + LIns* LirBufWriter::insParam(int32_t arg, int32_t kind) + { + LInsP* insP = (LInsP*)_buf->makeRoom(sizeof(LInsP)); + LIns* ins = insP->getLIns(); + ins->initLInsP(arg, kind); + if (kind) { + NanoAssert(arg < NumSavedRegs); + _buf->savedRegs[arg] = ins; + } + return ins; + } + + LIns* LirBufWriter::insImmI(int32_t imm) + { + LInsI* insI = (LInsI*)_buf->makeRoom(sizeof(LInsI)); + LIns* ins = insI->getLIns(); + ins->initLInsI(LIR_immi, imm); + return ins; + } + +#ifdef NANOJIT_64BIT + LIns* LirBufWriter::insImmQ(uint64_t imm) + { + LInsQorD* insQorD = (LInsQorD*)_buf->makeRoom(sizeof(LInsQorD)); + LIns* ins = insQorD->getLIns(); + ins->initLInsQorD(LIR_immq, imm); + return ins; + } +#endif + + LIns* LirBufWriter::insComment(const char* str) + { + // Allocate space for and copy the string. We use the same allocator + // as the normal LIR buffers so it has the same lifetime. + char* str2 = (char*)_buf->_allocator.alloc(VMPI_strlen(str) + 1); + VMPI_strcpy(str2, str); + return ins1(LIR_comment, (LIns*)str); + } + + LIns* LirBufWriter::insImmD(double d) + { + LInsQorD* insQorD = (LInsQorD*)_buf->makeRoom(sizeof(LInsQorD)); + LIns* ins = insQorD->getLIns(); + union { + double d; + uint64_t q; + } u; + u.d = d; + ins->initLInsQorD(LIR_immd, u.q); + return ins; + } + + // Reads the next non-skip instruction. + LIns* LirReader::read() + { + static const uint8_t insSizes[] = { + // LIR_start is treated specially -- see below. +#define OP___(op, number, repKind, retType, isCse) \ + ((number) == LIR_start ? 0 : sizeof(LIns##repKind)), +#include "LIRopcode.tbl" +#undef OP___ + 0 + }; + + // Check the invariant: _ins never points to a skip. + NanoAssert(_ins && !_ins->isop(LIR_skip)); + + // Step back one instruction. Use a table lookup rather than a switch + // to avoid branch mispredictions. LIR_start is given a special size + // of zero so that we don't step back past the start of the block. + // (Callers of this function should stop once they see a LIR_start.) + LIns* ret = _ins; + _ins = (LIns*)(uintptr_t(_ins) - insSizes[_ins->opcode()]); + + // Ensure _ins doesn't end up pointing to a skip. + while (_ins->isop(LIR_skip)) { + NanoAssert(_ins->prevLIns() != _ins); + _ins = _ins->prevLIns(); + } + + return ret; + } + + LOpcode arithOpcodeD2I(LOpcode op) + { + switch (op) { + case LIR_negd: return LIR_negi; + case LIR_addd: return LIR_addi; + case LIR_subd: return LIR_subi; + case LIR_muld: return LIR_muli; + default: NanoAssert(0); return LIR_skip; + } + } + +#ifdef NANOJIT_64BIT + LOpcode cmpOpcodeI2Q(LOpcode op) + { + switch (op) { + case LIR_eqi: return LIR_eqq; + case LIR_lti: return LIR_ltq; + case LIR_gti: return LIR_gtq; + case LIR_lei: return LIR_leq; + case LIR_gei: return LIR_geq; + case LIR_ltui: return LIR_ltuq; + case LIR_gtui: return LIR_gtuq; + case LIR_leui: return LIR_leuq; + case LIR_geui: return LIR_geuq; + default: NanoAssert(0); return LIR_skip; + } + } +#endif + + LOpcode cmpOpcodeD2I(LOpcode op) + { + switch (op) { + case LIR_eqd: return LIR_eqi; + case LIR_ltd: return LIR_lti; + case LIR_gtd: return LIR_gti; + case LIR_led: return LIR_lei; + case LIR_ged: return LIR_gei; + default: NanoAssert(0); return LIR_skip; + } + } + + LOpcode cmpOpcodeD2UI(LOpcode op) + { + switch (op) { + case LIR_eqd: return LIR_eqi; + case LIR_ltd: return LIR_ltui; + case LIR_gtd: return LIR_gtui; + case LIR_led: return LIR_leui; + case LIR_ged: return LIR_geui; + default: NanoAssert(0); return LIR_skip; + } + } + + // This is never called, but that's ok because it contains only static + // assertions. + void LIns::staticSanityCheck() + { + // LIns must be word-sized. + NanoStaticAssert(sizeof(LIns) == 1*sizeof(void*)); + + // LInsXYZ have expected sizes too. + NanoStaticAssert(sizeof(LInsOp0) == 1*sizeof(void*)); + NanoStaticAssert(sizeof(LInsOp1) == 2*sizeof(void*)); + NanoStaticAssert(sizeof(LInsOp2) == 3*sizeof(void*)); + NanoStaticAssert(sizeof(LInsOp3) == 4*sizeof(void*)); + NanoStaticAssert(sizeof(LInsLd) == 3*sizeof(void*)); + NanoStaticAssert(sizeof(LInsSt) == 4*sizeof(void*)); + NanoStaticAssert(sizeof(LInsSk) == 2*sizeof(void*)); + NanoStaticAssert(sizeof(LInsC) == 3*sizeof(void*)); + NanoStaticAssert(sizeof(LInsP) == 2*sizeof(void*)); + NanoStaticAssert(sizeof(LInsI) == 2*sizeof(void*)); + #if defined NANOJIT_64BIT + NanoStaticAssert(sizeof(LInsQorD) == 2*sizeof(void*)); + #else + NanoStaticAssert(sizeof(LInsQorD) == 3*sizeof(void*)); + #endif + NanoStaticAssert(sizeof(LInsJtbl) == 4*sizeof(void*)); + + // oprnd_1 must be in the same position in LIns{Op1,Op2,Op3,Ld,St,Jtbl} + // because oprnd1() is used for all of them. + #define OP1OFFSET (offsetof(LInsOp1, ins) - offsetof(LInsOp1, oprnd_1)) + NanoStaticAssert( OP1OFFSET == (offsetof(LInsOp2, ins) - offsetof(LInsOp2, oprnd_1)) ); + NanoStaticAssert( OP1OFFSET == (offsetof(LInsOp3, ins) - offsetof(LInsOp3, oprnd_1)) ); + NanoStaticAssert( OP1OFFSET == (offsetof(LInsLd, ins) - offsetof(LInsLd, oprnd_1)) ); + NanoStaticAssert( OP1OFFSET == (offsetof(LInsSt, ins) - offsetof(LInsSt, oprnd_1)) ); + NanoStaticAssert( OP1OFFSET == (offsetof(LInsJtbl, ins) - offsetof(LInsJtbl, oprnd_1)) ); + + // oprnd_2 must be in the same position in LIns{Op2,Op3,St} + // because oprnd2() is used for all of them. + #define OP2OFFSET (offsetof(LInsOp2, ins) - offsetof(LInsOp2, oprnd_2)) + NanoStaticAssert( OP2OFFSET == (offsetof(LInsOp3, ins) - offsetof(LInsOp3, oprnd_2)) ); + NanoStaticAssert( OP2OFFSET == (offsetof(LInsSt, ins) - offsetof(LInsSt, oprnd_2)) ); + } + + bool insIsS16(LIns* i) + { + if (i->isImmI()) { + int c = i->immI(); + return isS16(c); + } + if (i->isCmov()) { + return insIsS16(i->oprnd2()) && insIsS16(i->oprnd3()); + } + if (i->isCmp()) + return true; + // many other possibilities too. + return false; + } + + LIns* ExprFilter::ins1(LOpcode v, LIns* oprnd) + { + switch (v) { +#ifdef NANOJIT_64BIT + case LIR_q2i: + if (oprnd->isImmQ()) + return insImmI(oprnd->immQlo()); + break; + case LIR_i2q: + if (oprnd->isImmI()) + return insImmQ(int64_t(int32_t(oprnd->immI()))); + break; + case LIR_ui2uq: + if (oprnd->isImmI()) + return insImmQ(uint64_t(uint32_t(oprnd->immI()))); + break; + case LIR_dasq: + if (oprnd->isop(LIR_qasd)) + return oprnd->oprnd1(); + break; + case LIR_qasd: + if (oprnd->isop(LIR_dasq)) + return oprnd->oprnd1(); + break; +#endif +#if NJ_SOFTFLOAT_SUPPORTED + case LIR_dlo2i: + if (oprnd->isImmD()) + return insImmI(oprnd->immDlo()); + if (oprnd->isop(LIR_ii2d)) + return oprnd->oprnd1(); + break; + case LIR_dhi2i: + if (oprnd->isImmD()) + return insImmI(oprnd->immDhi()); + if (oprnd->isop(LIR_ii2d)) + return oprnd->oprnd2(); + break; +#endif + case LIR_noti: + if (oprnd->isImmI()) + return insImmI(~oprnd->immI()); + involution: + if (v == oprnd->opcode()) + return oprnd->oprnd1(); + break; + case LIR_negi: + if (oprnd->isImmI()) + return insImmI(-oprnd->immI()); + if (oprnd->isop(LIR_subi)) // -(a-b) = b-a + return out->ins2(LIR_subi, oprnd->oprnd2(), oprnd->oprnd1()); + goto involution; + case LIR_negd: + if (oprnd->isImmD()) + return insImmD(-oprnd->immD()); + if (oprnd->isop(LIR_subd)) + return out->ins2(LIR_subd, oprnd->oprnd2(), oprnd->oprnd1()); + goto involution; + case LIR_i2d: + if (oprnd->isImmI()) + return insImmD(oprnd->immI()); + // Nb: i2d(d2i(x)) != x + break; + case LIR_d2i: + if (oprnd->isImmD()) + return insImmI(int32_t(oprnd->immD())); + if (oprnd->isop(LIR_i2d)) + return oprnd->oprnd1(); + break; + case LIR_ui2d: + if (oprnd->isImmI()) + return insImmD(uint32_t(oprnd->immI())); + break; + default: + ; + } + + return out->ins1(v, oprnd); + } + + // This is an ugly workaround for an apparent compiler + // bug; in VC2008, compiling with optimization on + // will produce spurious errors if this code is inlined + // into ExprFilter::ins2(). See https://bugzilla.mozilla.org/show_bug.cgi?id=538504 + inline double do_join(int32_t c1, int32_t c2) + { + union { + double d; + uint64_t u64; + } u; + u.u64 = uint32_t(c1) | uint64_t(c2)<<32; + return u.d; + } + + LIns* ExprFilter::ins2(LOpcode v, LIns* oprnd1, LIns* oprnd2) + { + NanoAssert(oprnd1 && oprnd2); + + //------------------------------------------------------------------- + // Folding where the two operands are equal + //------------------------------------------------------------------- + if (oprnd1 == oprnd2) { + // The operands are equal. + switch (v) { + case LIR_xori: + case LIR_subi: + case LIR_ltui: + case LIR_gtui: + case LIR_gti: + case LIR_lti: + return insImmI(0); + + case LIR_ori: + case LIR_andi: + return oprnd1; + + case LIR_lei: + case LIR_leui: + case LIR_gei: + case LIR_geui: + return insImmI(1); // (x <= x) == 1; (x >= x) == 1 + + default: + break; + } + } + + //------------------------------------------------------------------- + // Folding where both operands are immediates, grouped by type + //------------------------------------------------------------------- + if (oprnd1->isImmI() && oprnd2->isImmI()) { + // The operands are both int immediates. + int32_t c1 = oprnd1->immI(); + int32_t c2 = oprnd2->immI(); + double d; + int32_t r; + + switch (v) { +#if NJ_SOFTFLOAT_SUPPORTED + case LIR_ii2d: return insImmD(do_join(c1, c2)); +#endif + case LIR_eqi: return insImmI(c1 == c2); + case LIR_lti: return insImmI(c1 < c2); + case LIR_gti: return insImmI(c1 > c2); + case LIR_lei: return insImmI(c1 <= c2); + case LIR_gei: return insImmI(c1 >= c2); + case LIR_ltui: return insImmI(uint32_t(c1) < uint32_t(c2)); + case LIR_gtui: return insImmI(uint32_t(c1) > uint32_t(c2)); + case LIR_leui: return insImmI(uint32_t(c1) <= uint32_t(c2)); + case LIR_geui: return insImmI(uint32_t(c1) >= uint32_t(c2)); + + case LIR_lshi: return insImmI(c1 << (c2 & 0x1f)); + case LIR_rshi: return insImmI(c1 >> (c2 & 0x1f)); + case LIR_rshui: return insImmI(uint32_t(c1) >> (c2 & 0x1f)); + + case LIR_ori: return insImmI(c1 | c2); + case LIR_andi: return insImmI(c1 & c2); + case LIR_xori: return insImmI(c1 ^ c2); + + case LIR_addi: d = double(c1) + double(c2); goto fold; + case LIR_subi: d = double(c1) - double(c2); goto fold; + case LIR_muli: d = double(c1) * double(c2); goto fold; + fold: + // Make sure the constant expression doesn't overflow. This + // probably isn't necessary, because the C++ overflow + // behaviour is very likely to be the same as the machine code + // overflow behaviour, but we do it just to be safe. + r = int32_t(d); + if (r == d) + return insImmI(r); + break; + +#if defined NANOJIT_IA32 || defined NANOJIT_X64 + case LIR_divi: + case LIR_modi: + // We can't easily fold div and mod, since folding div makes it + // impossible to calculate the mod that refers to it. The + // frontend shouldn't emit div and mod with constant operands. + NanoAssert(0); +#endif + default: + break; + } + +#ifdef NANOJIT_64BIT + } else if (oprnd1->isImmQ() && oprnd2->isImmQ()) { + // The operands are both quad immediates. + int64_t c1 = oprnd1->immQ(); + int64_t c2 = oprnd2->immQ(); + static const int64_t MIN_INT64 = int64_t(0x8000000000000000LL); + static const int64_t MAX_INT64 = int64_t(0x7FFFFFFFFFFFFFFFLL); + + switch (v) { + case LIR_eqq: return insImmI(c1 == c2); + case LIR_ltq: return insImmI(c1 < c2); + case LIR_gtq: return insImmI(c1 > c2); + case LIR_leq: return insImmI(c1 <= c2); + case LIR_geq: return insImmI(c1 >= c2); + case LIR_ltuq: return insImmI(uint64_t(c1) < uint64_t(c2)); + case LIR_gtuq: return insImmI(uint64_t(c1) > uint64_t(c2)); + case LIR_leuq: return insImmI(uint64_t(c1) <= uint64_t(c2)); + case LIR_geuq: return insImmI(uint64_t(c1) >= uint64_t(c2)); + + case LIR_orq: return insImmQ(c1 | c2); + case LIR_andq: return insImmQ(c1 & c2); + case LIR_xorq: return insImmQ(c1 ^ c2); + + // Nb: LIR_rshq, LIR_lshq and LIR_rshuq aren't here because their + // RHS is an int. They are below. + + case LIR_addq: + // Overflow is only possible if both values are positive or + // both negative. Just like the 32-bit case, this check + // probably isn't necessary, because the C++ overflow + // behaviour is very likely to be the same as the machine code + // overflow behaviour, but we do it just to be safe. + if (c1 > 0 && c2 > 0) { + // Overflows if: c1 + c2 > MAX_INT64 + // Re-express to avoid overflow in the check: c1 > MAX_INT64 - c2 + if (c1 > MAX_INT64 - c2) + break; // overflow + } else if (c1 < 0 && c2 < 0) { + // Overflows if: c1 + c2 < MIN_INT64 + // Re-express to avoid overflow in the check: c1 < MIN_INT64 - c2 + if (c1 < MIN_INT64 - c2) + break; // overflow + } + return insImmQ(c1 + c2); + + case LIR_subq: + // Overflow is only possible if one value is positive and one + // negative. + if (c1 > 0 && c2 < 0) { + // Overflows if: c1 - c2 > MAX_INT64 + // Re-express to avoid overflow in the check: c1 > MAX_INT64 + c2 + if (c1 > MAX_INT64 + c2) + break; // overflow + } else if (c1 < 0 && c2 > 0) { + // Overflows if: c1 - c2 < MIN_INT64 + // Re-express to avoid overflow in the check: c1 < MIN_INT64 + c2 + if (c1 < MIN_INT64 + c2) + break; // overflow + } + return insImmQ(c1 - c2); + + default: + break; + } + + } else if (oprnd1->isImmQ() && oprnd2->isImmI()) { + // The first operand is a quad immediate, the second is an int + // immediate. + int64_t c1 = oprnd1->immQ(); + int32_t c2 = oprnd2->immI(); + + switch (v) { + case LIR_lshq: return insImmQ(c1 << (c2 & 0x3f)); + case LIR_rshq: return insImmQ(c1 >> (c2 & 0x3f)); + case LIR_rshuq: return insImmQ(uint64_t(c1) >> (c2 & 0x3f)); + + default: break; + } +#endif // NANOJIT_64BIT + + } else if (oprnd1->isImmD() && oprnd2->isImmD()) { + // The operands are both double immediates. + double c1 = oprnd1->immD(); + double c2 = oprnd2->immD(); + switch (v) { + case LIR_eqd: return insImmI(c1 == c2); + case LIR_ltd: return insImmI(c1 < c2); + case LIR_gtd: return insImmI(c1 > c2); + case LIR_led: return insImmI(c1 <= c2); + case LIR_ged: return insImmI(c1 >= c2); + + case LIR_addd: return insImmD(c1 + c2); + case LIR_subd: return insImmD(c1 - c2); + case LIR_muld: return insImmD(c1 * c2); + case LIR_divd: return insImmD(c1 / c2); + + default: break; + } + } + + //------------------------------------------------------------------- + // If only one operand is an immediate, make sure it's on the RHS, if possible + //------------------------------------------------------------------- + if (oprnd1->isImmAny() && !oprnd2->isImmAny()) { + switch (v) { + case LIR_eqi: + CASE64(LIR_eqq:) + case LIR_eqd: + case LIR_addi: + CASE64(LIR_addq:) + case LIR_addd: + case LIR_muli: + case LIR_muld: + case LIR_andi: + CASE64(LIR_andq:) + case LIR_ori: + CASE64(LIR_orq:) + case LIR_xori: + CASE64(LIR_xorq:) { + // move immediate to RHS + LIns* t = oprnd2; + oprnd2 = oprnd1; + oprnd1 = t; + break; + } + default: + if (isCmpOpcode(v)) { + // move immediate to RHS, swap the operator + LIns *t = oprnd2; + oprnd2 = oprnd1; + oprnd1 = t; + v = invertCmpOpcode(v); + } + break; + } + } + + //------------------------------------------------------------------- + // Folding where the RHS is an immediate + //------------------------------------------------------------------- + if (oprnd2->isImmI()) { + // The second operand is an int immediate. + int c = oprnd2->immI(); + switch (v) { + case LIR_addi: + if (oprnd1->isop(LIR_addi) && oprnd1->oprnd2()->isImmI()) { + // add(add(x,c1),c2) => add(x,c1+c2) + c += oprnd1->oprnd2()->immI(); + oprnd2 = insImmI(c); + oprnd1 = oprnd1->oprnd1(); + } + break; + + case LIR_subi: + if (oprnd1->isop(LIR_addi) && oprnd1->oprnd2()->isImmI()) { + // sub(add(x,c1),c2) => add(x,c1-c2) + c = oprnd1->oprnd2()->immI() - c; + oprnd2 = insImmI(c); + oprnd1 = oprnd1->oprnd1(); + v = LIR_addi; + } + break; + + case LIR_rshi: + if (c == 16 && oprnd1->isop(LIR_lshi) && + oprnd1->oprnd2()->isImmI(16) && + insIsS16(oprnd1->oprnd1())) + { + // rsh(lhs(x,16),16) == x, if x is S16 + return oprnd1->oprnd1(); + } + break; + + default: + break; + } + + if (c == 0) { + switch (v) { + case LIR_addi: + case LIR_ori: + case LIR_xori: + case LIR_subi: + case LIR_lshi: + case LIR_rshi: + case LIR_rshui: + CASE64(LIR_lshq:) // These are here because their RHS is an int + CASE64(LIR_rshq:) + CASE64(LIR_rshuq:) + return oprnd1; + + case LIR_andi: + case LIR_muli: + case LIR_ltui: // unsigned < 0 -> always false + return oprnd2; + + case LIR_geui: // unsigned >= 0 -> always true + return insImmI(1); + + case LIR_eqi: + if (oprnd1->isop(LIR_ori) && + oprnd1->oprnd2()->isImmI() && + oprnd1->oprnd2()->immI() != 0) + { + // (x or c) != 0 if c != 0 + return insImmI(0); + } + + default: + break; + } + + } else if (c == -1) { + switch (v) { + case LIR_ori: return oprnd2; // x | -1 = -1 + case LIR_andi: return oprnd1; // x & -1 = x + case LIR_gtui: return insImmI(0); // u32 > 0xffffffff -> always false + case LIR_leui: return insImmI(1); // u32 <= 0xffffffff -> always true + default: break; + } + + } else if (c == 1) { + if (oprnd1->isCmp()) { + switch (v) { + case LIR_ori: return oprnd2; // 0or1 | 1 = 1 (and oprnd2 == 1) + case LIR_andi: return oprnd1; // 0or1 & 1 = 0or1 + case LIR_gtui: return insImmI(0); // 0or1 > 1 -> always false + default: break; + } + } else if (v == LIR_muli) { + return oprnd1; // x * 1 = x + } + } + +#ifdef NANOJIT_64BIT + } else if (oprnd2->isImmQ()) { + // The second operand is a quad immediate. + int64_t c = oprnd2->immQ(); + if (c == 0) { + switch (v) { + case LIR_addq: + case LIR_orq: + case LIR_xorq: + case LIR_subq: + return oprnd1; + + case LIR_andq: + return oprnd2; + + case LIR_ltuq: // unsigned < 0 -> always false + return insImmI(0); + + case LIR_geuq: // unsigned >= 0 -> always true + return insImmI(1); + + default: + break; + } + + } else if (c == -1) { + switch (v) { + case LIR_orq: return oprnd2; // x | -1 = -1 + case LIR_andq: return oprnd1; // x & -1 = x + case LIR_gtuq: return insImmI(0); // u64 > 0xffffffffffffffff -> always false + case LIR_leuq: return insImmI(1); // u64 <= 0xffffffffffffffff -> always true + default: break; + } + + } else if (c == 1) { + if (oprnd1->isCmp()) { + switch (v) { + case LIR_orq: return oprnd2; // 0or1 | 1 = 1 (and oprnd2 == 1) + case LIR_andq: return oprnd1; // 0or1 & 1 = 0or1 + case LIR_gtuq: return insImmI(0); // 0or1 > 1 -> always false + default: break; + } + } + } +#endif // NANOJIT_64BIT + } + +#if NJ_SOFTFLOAT_SUPPORTED + //------------------------------------------------------------------- + // SoftFloat-specific folding + //------------------------------------------------------------------- + LIns* ins; + if (v == LIR_ii2d && oprnd1->isop(LIR_dlo2i) && oprnd2->isop(LIR_dhi2i) && + (ins = oprnd1->oprnd1()) == oprnd2->oprnd1()) + { + // qjoin(qlo(x),qhi(x)) == x + return ins; + } +#endif + + //------------------------------------------------------------------- + // No folding possible + //------------------------------------------------------------------- + return out->ins2(v, oprnd1, oprnd2); + } + + LIns* ExprFilter::ins3(LOpcode v, LIns* oprnd1, LIns* oprnd2, LIns* oprnd3) + { + NanoAssert(oprnd1 && oprnd2 && oprnd3); + NanoAssert(isCmovOpcode(v)); + if (oprnd2 == oprnd3) { + // c ? a : a => a + return oprnd2; + } + if (oprnd1->isImmI()) { + // immediate ? x : y => return x or y depending on immediate + return oprnd1->immI() ? oprnd2 : oprnd3; + } + if (oprnd1->isop(LIR_eqi) && + ((oprnd1->oprnd2() == oprnd2 && oprnd1->oprnd1() == oprnd3) || + (oprnd1->oprnd1() == oprnd2 && oprnd1->oprnd2() == oprnd3))) { + // (y == x) ? x : y => y + // (x == y) ? x : y => y + return oprnd3; + } + + return out->ins3(v, oprnd1, oprnd2, oprnd3); + } + + LIns* ExprFilter::insGuard(LOpcode v, LIns* c, GuardRecord *gr) + { + if (v == LIR_xt || v == LIR_xf) { + if (c->isImmI()) { + if ((v == LIR_xt && !c->immI()) || (v == LIR_xf && c->immI())) { + return 0; // no guard needed + } else { +#ifdef JS_TRACER + // We're emitting a guard that will always fail. Any code + // emitted after this guard is dead code. But it won't be + // optimized away, and it could indicate a performance + // problem or other bug, so assert in debug builds. + NanoAssertMsg(0, "Constantly false guard detected"); +#endif + return out->insGuard(LIR_x, NULL, gr); + } + } else { + while (c->isop(LIR_eqi) && c->oprnd1()->isCmp() && c->oprnd2()->isImmI(0)) { + // xt(eq(cmp,0)) => xf(cmp) or xf(eq(cmp,0)) => xt(cmp) + v = invertCondGuardOpcode(v); + c = c->oprnd1(); + } + } + } + return out->insGuard(v, c, gr); + } + + // Simplify operator if possible. Always return NULL if overflow is possible. + + LIns* ExprFilter::simplifyOverflowArith(LOpcode op, LIns** opnd1, LIns** opnd2) + { + LIns* oprnd1 = *opnd1; + LIns* oprnd2 = *opnd2; + + if (oprnd1->isImmI() && oprnd2->isImmI()) { + int32_t c1 = oprnd1->immI(); + int32_t c2 = oprnd2->immI(); + double d = 0.0; + + // The code below attempts to perform the operation while + // detecting overflow. For multiplication, we may unnecessarily + // infer a possible overflow due to the insufficient integer + // range of the double type. + + switch (op) { + case LIR_addjovi: + case LIR_addxovi: d = double(c1) + double(c2); break; + case LIR_subjovi: + case LIR_subxovi: d = double(c1) - double(c2); break; + case LIR_muljovi: + case LIR_mulxovi: d = double(c1) * double(c2); break; + default: NanoAssert(0); break; + } + int32_t r = int32_t(d); + if (r == d) + return insImmI(r); + + } else if (oprnd1->isImmI() && !oprnd2->isImmI()) { + switch (op) { + case LIR_addjovi: + case LIR_addxovi: + case LIR_muljovi: + case LIR_mulxovi: { + // swap operands, moving immediate to RHS + LIns* t = oprnd2; + oprnd2 = oprnd1; + oprnd1 = t; + // swap actual arguments in caller as well + *opnd1 = oprnd1; + *opnd2 = oprnd2; + break; + } + case LIR_subjovi: + case LIR_subxovi: + break; + default: + NanoAssert(0); + } + } + + if (oprnd2->isImmI()) { + int c = oprnd2->immI(); + if (c == 0) { + switch (op) { + case LIR_addjovi: + case LIR_addxovi: + case LIR_subjovi: + case LIR_subxovi: + return oprnd1; + case LIR_muljovi: + case LIR_mulxovi: + return oprnd2; + default: + ; + } + } else if (c == 1 && (op == LIR_muljovi || op == LIR_mulxovi)) { + return oprnd1; + } + } + + return NULL; + } + + LIns* ExprFilter::insGuardXov(LOpcode op, LIns* oprnd1, LIns* oprnd2, GuardRecord *gr) + { + LIns* simplified = simplifyOverflowArith(op, &oprnd1, &oprnd2); + if (simplified) + return simplified; + + return out->insGuardXov(op, oprnd1, oprnd2, gr); + } + + LIns* ExprFilter::insBranch(LOpcode v, LIns *c, LIns *t) + { + if (v == LIR_jt || v == LIR_jf) { + if (c->isImmI()) { + if ((v == LIR_jt && !c->immI()) || (v == LIR_jf && c->immI())) { + return 0; // no jump needed + } else { +#ifdef JS_TRACER + // We're emitting a branch that will always be taken. This may + // result in dead code that will not be optimized away, and + // could indicate a performance problem or other bug, so assert + // in debug builds. + NanoAssertMsg(0, "Constantly taken branch detected"); +#endif + return out->insBranch(LIR_j, NULL, t); + } + } else { + while (c->isop(LIR_eqi) && c->oprnd1()->isCmp() && c->oprnd2()->isImmI(0)) { + // jt(eq(cmp,0)) => jf(cmp) or jf(eq(cmp,0)) => jt(cmp) + v = invertCondJmpOpcode(v); + c = c->oprnd1(); + } + } + } + return out->insBranch(v, c, t); + } + + LIns* ExprFilter::insBranchJov(LOpcode op, LIns* oprnd1, LIns* oprnd2, LIns* target) + { + LIns* simplified = simplifyOverflowArith(op, &oprnd1, &oprnd2); + if (simplified) + return simplified; + + return out->insBranchJov(op, oprnd1, oprnd2, target); + } + + LIns* ExprFilter::insLoad(LOpcode op, LIns* base, int32_t off, AccSet accSet, LoadQual loadQual) { + if (base->isImmP() && !isS8(off)) { + // if the effective address is constant, then transform: + // ld const[bigconst] => ld (const+bigconst)[0] + // note: we don't do this optimization for <8bit field offsets, + // under the assumption that we're more likely to CSE-match the + // constant base address if we dont const-fold small offsets. + uintptr_t p = (uintptr_t)base->immP() + off; + return out->insLoad(op, insImmP((void*)p), 0, accSet, loadQual); + } + return out->insLoad(op, base, off, accSet, loadQual); + } + + LIns* LirWriter::insStore(LIns* value, LIns* base, int32_t d, AccSet accSet) + { + // Determine which kind of store should be used for 'value' based on + // its type. + LOpcode op = LOpcode(0); + switch (value->retType()) { + case LTy_I: op = LIR_sti; break; +#ifdef NANOJIT_64BIT + case LTy_Q: op = LIR_stq; break; +#endif + case LTy_D: op = LIR_std; break; + case LTy_V: NanoAssert(0); break; + default: NanoAssert(0); break; + } + return insStore(op, value, base, d, accSet); + } + + LIns* LirWriter::insChoose(LIns* cond, LIns* iftrue, LIns* iffalse, bool use_cmov) + { + // 'cond' must be a conditional, unless it has been optimized to 0 or + // 1. In that case make it an ==0 test and flip the branches. It'll + // get constant-folded by ExprFilter subsequently. + if (!cond->isCmp()) { + NanoAssert(cond->isImmI()); + cond = insEqI_0(cond); + LIns* tmp = iftrue; + iftrue = iffalse; + iffalse = tmp; + } + + if (use_cmov) { + LOpcode op = LIR_cmovi; + if (iftrue->isI() && iffalse->isI()) { + op = LIR_cmovi; +#ifdef NANOJIT_64BIT + } else if (iftrue->isQ() && iffalse->isQ()) { + op = LIR_cmovq; +#endif + } else if (iftrue->isD() && iffalse->isD()) { + op = LIR_cmovd; + } else { + NanoAssert(0); // type error + } + return ins3(op, cond, iftrue, iffalse); + } + + LIns* ncond = ins1(LIR_negi, cond); // cond ? -1 : 0 + return ins2(LIR_ori, + ins2(LIR_andi, iftrue, ncond), + ins2(LIR_andi, iffalse, ins1(LIR_noti, ncond))); + } + + LIns* LirBufWriter::insCall(const CallInfo *ci, LIns* args[]) + { + LOpcode op = getCallOpcode(ci); +#if NJ_SOFTFLOAT_SUPPORTED + // SoftFloat: convert LIR_calld to LIR_calli. + if (_config.soft_float && op == LIR_calld) + op = LIR_calli; +#endif + + int32_t argc = ci->count_args(); + NanoAssert(argc <= (int)MAXARGS); + + // Allocate space for and copy the arguments. We use the same + // allocator as the normal LIR buffers so it has the same lifetime. + // Nb: this must be kept in sync with arg(). + LIns** args2 = (LIns**)_buf->_allocator.alloc(argc * sizeof(LIns*)); + memcpy(args2, args, argc * sizeof(LIns*)); + + // Allocate and write the call instruction. + LInsC* insC = (LInsC*)_buf->makeRoom(sizeof(LInsC)); + LIns* ins = insC->getLIns(); + ins->initLInsC(op, args2, ci); + return ins; + } + + using namespace avmplus; + + StackFilter::StackFilter(LirFilter *in, Allocator& alloc, LIns* sp) + : LirFilter(in), sp(sp), stk(alloc), top(0) + {} + + // If we see a sequence like this: + // + // sti sp[0] + // ... + // sti sp[0] + // + // where '...' contains no guards, we can remove the first store. Also, + // because stack entries are eight bytes each (we check this), if we have + // this: + // + // stfi sp[0] + // ... + // sti sp[0] + // + // we can again remove the first store -- even though the second store + // doesn't clobber the high four bytes -- because we know the entire value + // stored by the first store is dead. + // + LIns* StackFilter::read() + { + for (;;) { + LIns* ins = in->read(); + + if (ins->isStore()) { + LIns* base = ins->oprnd2(); + if (base == sp) { + // 'disp' must be eight-aligned because each stack entry is 8 bytes. + NanoAssert((ins->disp() & 0x7) == 0); + + int d = ins->disp() >> 3; + if (d >= top) { + continue; + } else { + d = top - d; + if (stk.get(d)) { + continue; + } else { + stk.set(d); + } + } + } + } + /* + * NB: If there is a backward branch other than the loop-restart branch, this is + * going to be wrong. Unfortunately there doesn't seem to be an easy way to detect + * such branches. Just do not create any. + * + * The isLive() call is valid because liveness will have been + * computed by Assembler::gen() for every instruction following + * this guard. + */ + else if (ins->isGuard() && ins->isLive()) { + stk.reset(); + top = getTop(ins); + top >>= 3; + } + + return ins; + } + } + +#ifdef NJ_VERBOSE + class RetiredEntry + { + public: + Seq* live; + LIns* i; + RetiredEntry(): live(NULL), i(NULL) {} + }; + + class LiveTable + { + Allocator& alloc; + public: + HashMap live; + SeqBuilder retired; + int retiredCount; + int maxlive; + LiveTable(Allocator& alloc) + : alloc(alloc) + , live(alloc) + , retired(alloc) + , retiredCount(0) + , maxlive(0) + { } + + void add(LIns* ins, LIns* use) { + if (!ins->isImmAny() && !live.containsKey(ins)) { + NanoAssert(size_t(ins->opcode()) < sizeof(lirNames) / sizeof(lirNames[0])); + live.put(ins,use); + } + } + + void retire(LIns* i) { + RetiredEntry *e = new (alloc) RetiredEntry(); + e->i = i; + SeqBuilder livelist(alloc); + HashMap::Iter iter(live); + int live_count = 0; + while (iter.next()) { + LIns* ins = iter.key(); + if (!ins->isV()) { + live_count++; + livelist.insert(ins); + } + } + e->live = livelist.get(); + if (live_count > maxlive) + maxlive = live_count; + + live.remove(i); + retired.insert(e); + retiredCount++; + } + + bool contains(LIns* i) { + return live.containsKey(i); + } + }; + + /* + * traverse the LIR buffer and discover which instructions are live + * by starting from instructions with side effects (stores, calls, branches) + * and marking instructions used by them. Works bottom-up, in one pass. + * if showLiveRefs == true, also print the set of live expressions next to + * each instruction + */ + void live(LirFilter* in, Allocator& alloc, Fragment *frag, LogControl *logc) + { + // traverse backwards to find live exprs and a few other stats. + + LiveTable live(alloc); + uint32_t exits = 0; + int total = 0; + if (frag->lirbuf->state) + live.add(frag->lirbuf->state, 0); + for (LIns* ins = in->read(); !ins->isop(LIR_start); ins = in->read()) + { + total++; + + // First handle instructions that are always live (ie. those that + // don't require being marked as live), eg. those with + // side-effects. We ignore LIR_paramp. + if (ins->isLive() && !ins->isop(LIR_paramp)) + { + live.add(ins, 0); + if (ins->isGuard()) + exits++; + } + + // now propagate liveness + if (live.contains(ins)) + { + live.retire(ins); + + switch (ins->opcode()) { + case LIR_skip: + NanoAssertMsg(0, "Shouldn't see LIR_skip"); + break; + + case LIR_start: + case LIR_regfence: + case LIR_paramp: + case LIR_x: + case LIR_xbarrier: + case LIR_j: + case LIR_label: + case LIR_immi: + CASE64(LIR_immq:) + case LIR_immd: + case LIR_allocp: + case LIR_comment: + // No operands, do nothing. + break; + + case LIR_ldi: + CASE64(LIR_ldq:) + case LIR_ldd: + case LIR_lduc2ui: + case LIR_ldus2ui: + case LIR_ldc2i: + case LIR_lds2i: + case LIR_ldf2d: + case LIR_reti: + CASE64(LIR_retq:) + case LIR_retd: + case LIR_livei: + CASE64(LIR_liveq:) + case LIR_lived: + case LIR_xt: + case LIR_xf: + case LIR_xtbl: + case LIR_jt: + case LIR_jf: + case LIR_jtbl: + case LIR_negi: + case LIR_negd: + case LIR_noti: + CASESF(LIR_dlo2i:) + CASESF(LIR_dhi2i:) + CASESF(LIR_hcalli:) + CASE64(LIR_i2q:) + CASE64(LIR_ui2uq:) + case LIR_i2d: + case LIR_ui2d: + CASE64(LIR_q2i:) + case LIR_d2i: + CASE64(LIR_dasq:) + CASE64(LIR_qasd:) + CASE86(LIR_modi:) + live.add(ins->oprnd1(), 0); + break; + + case LIR_sti: + CASE64(LIR_stq:) + case LIR_std: + case LIR_sti2c: + case LIR_sti2s: + case LIR_std2f: + case LIR_eqi: + case LIR_lti: + case LIR_gti: + case LIR_lei: + case LIR_gei: + case LIR_ltui: + case LIR_gtui: + case LIR_leui: + case LIR_geui: + case LIR_eqd: + case LIR_ltd: + case LIR_gtd: + case LIR_led: + case LIR_ged: + CASE64(LIR_eqq:) + CASE64(LIR_ltq:) + CASE64(LIR_gtq:) + CASE64(LIR_leq:) + CASE64(LIR_geq:) + CASE64(LIR_ltuq:) + CASE64(LIR_gtuq:) + CASE64(LIR_leuq:) + CASE64(LIR_geuq:) + case LIR_lshi: + case LIR_rshi: + case LIR_rshui: + CASE64(LIR_lshq:) + CASE64(LIR_rshq:) + CASE64(LIR_rshuq:) + case LIR_addi: + case LIR_subi: + case LIR_muli: + case LIR_addxovi: + case LIR_subxovi: + case LIR_mulxovi: + case LIR_addjovi: + case LIR_subjovi: + case LIR_muljovi: + CASE86(LIR_divi:) + case LIR_addd: + case LIR_subd: + case LIR_muld: + case LIR_divd: + CASE64(LIR_addq:) + CASE64(LIR_subq:) + CASE64(LIR_addjovq:) + CASE64(LIR_subjovq:) + case LIR_andi: + case LIR_ori: + case LIR_xori: + CASE64(LIR_andq:) + CASE64(LIR_orq:) + CASE64(LIR_xorq:) + CASESF(LIR_ii2d:) + case LIR_file: + case LIR_line: + live.add(ins->oprnd1(), 0); + live.add(ins->oprnd2(), 0); + break; + + case LIR_cmovi: + CASE64(LIR_cmovq:) + case LIR_cmovd: + live.add(ins->oprnd1(), 0); + live.add(ins->oprnd2(), 0); + live.add(ins->oprnd3(), 0); + break; + + case LIR_callv: + case LIR_calli: + CASE64(LIR_callq:) + case LIR_calld: + for (int i = 0, argc = ins->argc(); i < argc; i++) + live.add(ins->arg(i), 0); + break; + + default: + NanoAssertMsgf(0, "unhandled opcode: %d", ins->opcode()); + break; + } + } + } + + logc->printf(" Live instruction count %d, total %u, max pressure %d\n", + live.retiredCount, total, live.maxlive); + if (exits > 0) + logc->printf(" Side exits %u\n", exits); + logc->printf(" Showing LIR instructions with live-after variables\n"); + logc->printf("\n"); + + // print live exprs, going forwards + LInsPrinter *printer = frag->lirbuf->printer; + bool newblock = true; + for (Seq* p = live.retired.get(); p != NULL; p = p->tail) { + RetiredEntry* e = p->head; + InsBuf ib; + RefBuf rb; + char livebuf[4000], *s=livebuf; + *s = 0; + if (!newblock && e->i->isop(LIR_label)) { + logc->printf("\n"); + } + newblock = false; + for (Seq* p = e->live; p != NULL; p = p->tail) { + VMPI_strcpy(s, printer->formatRef(&rb, p->head)); + s += VMPI_strlen(s); + *s++ = ' '; *s = 0; + NanoAssert(s < livebuf+sizeof(livebuf)); + } + /* If the LIR insn is pretty short, print it and its + live-after set on the same line. If not, put + live-after set on a new line, suitably indented. */ + const char* insn_text = printer->formatIns(&ib, e->i); + if (VMPI_strlen(insn_text) >= 30-2) { + logc->printf(" %-30s\n %-30s %s\n", insn_text, "", livebuf); + } else { + logc->printf(" %-30s %s\n", insn_text, livebuf); + } + + if (e->i->isGuard() || e->i->isBranch() || e->i->isRet()) { + logc->printf("\n"); + newblock = true; + } + } + } + + void LirNameMap::addNameWithSuffix(LIns* ins, const char *name, int suffix, + bool ignoreOneSuffix) { + NanoAssert(!names.containsKey(ins)); + const int N = 100; + char name2[N]; + if (suffix == 1 && ignoreOneSuffix) { + VMPI_snprintf(name2, N, "%s", name); // don't add '1' suffix + } else if (VMPI_isdigit(name[VMPI_strlen(name)-1])) { + VMPI_snprintf(name2, N, "%s_%d", name, suffix); // use '_' to avoid confusion + } else { + VMPI_snprintf(name2, N, "%s%d", name, suffix); // normal case + } + + char *copy = new (alloc) char[VMPI_strlen(name2)+1]; + VMPI_strcpy(copy, name2); + Entry *e = new (alloc) Entry(copy); + names.put(ins, e); + } + + void LirNameMap::addName(LIns* ins, const char* name) { + // The lookup may succeed, ie. we may already have a name for this + // instruction. This can happen because of CSE. Eg. if we have this: + // + // ins = addName("foo", insImmI(0)) + // + // that assigns the name "foo1" to 'ins'. If we later do this: + // + // ins2 = addName("foo", insImmI(0)) + // + // then CSE will cause 'ins' and 'ins2' to be equal. So 'ins2' + // already has a name ("foo1") and there's no need to generate a new + // name "foo2". + // + if (!names.containsKey(ins)) { + Str* str = new (alloc) Str(alloc, name); + int suffix = namecounts.add(*str); + addNameWithSuffix(ins, name, suffix, /*ignoreOneSuffix*/true); + } + } + + const char* LirNameMap::createName(LIns* ins) { + if (ins->isCall()) { +#if NJ_SOFTFLOAT_SUPPORTED + if (ins->isop(LIR_hcalli)) { + ins = ins->oprnd1(); // we've presumably seen the other half already + } else +#endif + { + if (!names.containsKey(ins)) + addNameWithSuffix(ins, ins->callInfo()->_name, funccounts.add(ins->callInfo()), + /*ignoreOneSuffix*/false); + } + } else { + if (!names.containsKey(ins)) + addNameWithSuffix(ins, lirNames[ins->opcode()], lircounts.add(ins->opcode()), + /*ignoreOneSuffix*/false); + + } + return names.get(ins)->name; + } + + const char* LirNameMap::lookupName(LIns* ins) + { + Entry* e = names.get(ins); + return e ? e->name : NULL; + } + + char* LInsPrinter::formatAccSet(RefBuf* buf, AccSet accSet) { + if (accSet == ACCSET_NONE) { + VMPI_sprintf(buf->buf, ".none"); + } else if (accSet == ACCSET_ALL) { + VMPI_sprintf(buf->buf, ".all"); + } else { + char* b = buf->buf; + b[0] = 0; + // The AccSet may contain bits set for regions not used by the + // embedding, if any have been specified via + // (ACCSET_ALL & ~ACCSET_XYZ). So only print those that are + // relevant. + for (int i = 0; i < EMB_NUM_USED_ACCS; i++) { + if (accSet & (1 << i)) { + VMPI_strcat(b, "."); + VMPI_strcat(b, accNames[i]); + accSet &= ~(1 << i); + } + } + NanoAssert(VMPI_strlen(b) < buf->len); + } + return buf->buf; + } + + char* LInsPrinter::formatImmI(RefBuf* buf, int32_t c) { + if (-10000 < c && c < 10000) { + VMPI_snprintf(buf->buf, buf->len, "%d", c); + } else { +#if !defined NANOJIT_64BIT + formatAddr(buf, (void*)c); +#else + VMPI_snprintf(buf->buf, buf->len, "0x%x", (unsigned int)c); +#endif + } + return buf->buf; + } + +#if defined NANOJIT_64BIT + char* LInsPrinter::formatImmQ(RefBuf* buf, uint64_t c) { + if (-10000 < (int64_t)c && c < 10000) { + VMPI_snprintf(buf->buf, buf->len, "%dLL", (int)c); + } else { + formatAddr(buf, (void*)c); + } + return buf->buf; + } +#endif + + char* LInsPrinter::formatImmD(RefBuf* buf, double c) { + VMPI_snprintf(buf->buf, buf->len, "%g", c); + return buf->buf; + } + + char* LInsPrinter::formatAddr(RefBuf* buf, void* p) + { + char* name; + int32_t offset; + addrNameMap->lookupAddr(p, name, offset); + + if (name) { + if (offset != 0) { + VMPI_snprintf(buf->buf, buf->len, "%p %s+%d", p, name, offset); + } else { + VMPI_snprintf(buf->buf, buf->len, "%p %s", p, name); + } + } else { + VMPI_snprintf(buf->buf, buf->len, "%p", p); + } + + return buf->buf; + } + + char* LInsPrinter::formatRef(RefBuf* buf, LIns *ref, bool showImmValue) + { + // Give 'ref' a name if it doesn't have one. + const char* name = lirNameMap->lookupName(ref); + if (!name) { + name = lirNameMap->createName(ref); + } + + // Put it in the buffer. If it's an immediate, show the value if + // showImmValue==true. (This facility allows us to print immediate + // values when they're used but not when they're def'd, ie. we don't + // want "immi1/*1*/ = immi 1".) + RefBuf buf2; + if (ref->isImmI() && showImmValue) { + VMPI_snprintf(buf->buf, buf->len, "%s/*%s*/", name, formatImmI(&buf2, ref->immI())); + } +#ifdef NANOJIT_64BIT + else if (ref->isImmQ() && showImmValue) { + VMPI_snprintf(buf->buf, buf->len, "%s/*%s*/", name, formatImmQ(&buf2, ref->immQ())); + } +#endif + else if (ref->isImmD() && showImmValue) { + VMPI_snprintf(buf->buf, buf->len, "%s/*%s*/", name, formatImmD(&buf2, ref->immD())); + } + else { + VMPI_snprintf(buf->buf, buf->len, "%s", name); + } + + return buf->buf; + } + + char* LInsPrinter::formatIns(InsBuf* buf, LIns* i) + { + char *s = buf->buf; + size_t n = buf->len; + RefBuf b1, b2, b3, b4; + LOpcode op = i->opcode(); + switch (op) + { + case LIR_immi: + VMPI_snprintf(s, n, "%s = %s %s", formatRef(&b1, i, /*showImmValue*/false), + lirNames[op], formatImmI(&b2, i->immI())); + break; + +#ifdef NANOJIT_64BIT + case LIR_immq: + VMPI_snprintf(s, n, "%s = %s %s", formatRef(&b1, i, /*showImmValue*/false), + lirNames[op], formatImmQ(&b2, i->immQ())); + break; +#endif + + case LIR_immd: + VMPI_snprintf(s, n, "%s = %s %s", formatRef(&b1, i, /*showImmValue*/false), + lirNames[op], formatImmD(&b2, i->immD())); + break; + + case LIR_allocp: + VMPI_snprintf(s, n, "%s = %s %d", formatRef(&b1, i), lirNames[op], i->size()); + break; + + case LIR_start: + case LIR_regfence: + VMPI_snprintf(s, n, "%s", lirNames[op]); + break; + + case LIR_callv: + case LIR_calli: + CASE64(LIR_callq:) + case LIR_calld: { + const CallInfo* call = i->callInfo(); + int32_t argc = i->argc(); + int32_t m = int32_t(n); // Windows doesn't have 'ssize_t' + if (call->isIndirect()) + m -= VMPI_snprintf(s, m, "%s = %s%s [%s] ( ", formatRef(&b1, i), lirNames[op], + formatAccSet(&b2, call->_storeAccSet), + formatRef(&b3, i->arg(--argc))); + else + m -= VMPI_snprintf(s, m, "%s = %s%s #%s ( ", formatRef(&b1, i), lirNames[op], + formatAccSet(&b2, call->_storeAccSet), call->_name); + if (m < 0) break; + for (int32_t j = argc - 1; j >= 0; j--) { + s += VMPI_strlen(s); + m -= VMPI_snprintf(s, m, "%s ",formatRef(&b2, i->arg(j))); + if (m < 0) break; + } + s += VMPI_strlen(s); + m -= VMPI_snprintf(s, m, ")"); + break; + } + + case LIR_jtbl: { + int32_t m = int32_t(n); // Windows doesn't have 'ssize_t' + m -= VMPI_snprintf(s, m, "%s %s [ ", lirNames[op], formatRef(&b1, i->oprnd1())); + if (m < 0) break; + for (uint32_t j = 0, sz = i->getTableSize(); j < sz; j++) { + LIns* target = i->getTarget(j); + s += VMPI_strlen(s); + m -= VMPI_snprintf(s, m, "%s ", target ? formatRef(&b2, target) : "unpatched"); + if (m < 0) break; + } + s += VMPI_strlen(s); + m -= VMPI_snprintf(s, m, "]"); + break; + } + + case LIR_paramp: { + uint32_t arg = i->paramArg(); + if (!i->paramKind()) { + if (arg < sizeof(Assembler::argRegs)/sizeof(Assembler::argRegs[0])) { + VMPI_snprintf(s, n, "%s = %s %d %s", formatRef(&b1, i), lirNames[op], + arg, gpn(Assembler::argRegs[arg])); + } else { + VMPI_snprintf(s, n, "%s = %s %d", formatRef(&b1, i), lirNames[op], arg); + } + } else { + VMPI_snprintf(s, n, "%s = %s %d %s", formatRef(&b1, i), lirNames[op], + arg, gpn(Assembler::savedRegs[arg])); + } + break; + } + + case LIR_label: + VMPI_snprintf(s, n, "%s:", formatRef(&b1, i)); + break; + + case LIR_jt: + case LIR_jf: + VMPI_snprintf(s, n, "%s %s -> %s", lirNames[op], formatRef(&b1, i->oprnd1()), + i->oprnd2() ? formatRef(&b2, i->oprnd2()) : "unpatched"); + break; + + case LIR_j: + VMPI_snprintf(s, n, "%s -> %s", lirNames[op], + i->oprnd2() ? formatRef(&b1, i->oprnd2()) : "unpatched"); + break; + + case LIR_livei: + case LIR_lived: + CASE64(LIR_liveq:) + case LIR_reti: + CASE64(LIR_retq:) + case LIR_retd: + VMPI_snprintf(s, n, "%s %s", lirNames[op], formatRef(&b1, i->oprnd1())); + break; + + CASESF(LIR_hcalli:) + case LIR_negi: + case LIR_negd: + case LIR_i2d: + case LIR_ui2d: + CASESF(LIR_dlo2i:) + CASESF(LIR_dhi2i:) + case LIR_noti: + CASE86(LIR_modi:) + CASE64(LIR_i2q:) + CASE64(LIR_ui2uq:) + CASE64(LIR_q2i:) + case LIR_d2i: + CASE64(LIR_dasq:) + CASE64(LIR_qasd:) + VMPI_snprintf(s, n, "%s = %s %s", formatRef(&b1, i), lirNames[op], + formatRef(&b2, i->oprnd1())); + break; + + case LIR_x: + case LIR_xt: + case LIR_xf: + case LIR_xbarrier: + case LIR_xtbl: + formatGuard(buf, i); + break; + + case LIR_addxovi: + case LIR_subxovi: + case LIR_mulxovi: + formatGuardXov(buf, i); + break; + + case LIR_addjovi: + case LIR_subjovi: + case LIR_muljovi: + CASE64(LIR_addjovq:) + CASE64(LIR_subjovq:) + VMPI_snprintf(s, n, "%s = %s %s, %s ; ovf -> %s", formatRef(&b1, i), lirNames[op], + formatRef(&b2, i->oprnd1()), + formatRef(&b3, i->oprnd2()), + i->oprnd3() ? formatRef(&b4, i->oprnd3()) : "unpatched"); + break; + + case LIR_addi: CASE64(LIR_addq:) + case LIR_subi: CASE64(LIR_subq:) + case LIR_muli: + CASE86(LIR_divi:) + case LIR_addd: + case LIR_subd: + case LIR_muld: + case LIR_divd: + case LIR_andi: CASE64(LIR_andq:) + case LIR_ori: CASE64(LIR_orq:) + case LIR_xori: CASE64(LIR_xorq:) + case LIR_lshi: CASE64(LIR_lshq:) + case LIR_rshi: CASE64(LIR_rshq:) + case LIR_rshui: CASE64(LIR_rshuq:) + case LIR_eqi: CASE64(LIR_eqq:) + case LIR_lti: CASE64(LIR_ltq:) + case LIR_lei: CASE64(LIR_leq:) + case LIR_gti: CASE64(LIR_gtq:) + case LIR_gei: CASE64(LIR_geq:) + case LIR_ltui: CASE64(LIR_ltuq:) + case LIR_leui: CASE64(LIR_leuq:) + case LIR_gtui: CASE64(LIR_gtuq:) + case LIR_geui: CASE64(LIR_geuq:) + case LIR_eqd: + case LIR_ltd: + case LIR_led: + case LIR_gtd: + case LIR_ged: +#if NJ_SOFTFLOAT_SUPPORTED + case LIR_ii2d: +#endif + VMPI_snprintf(s, n, "%s = %s %s, %s", formatRef(&b1, i), lirNames[op], + formatRef(&b2, i->oprnd1()), + formatRef(&b3, i->oprnd2())); + break; + + CASE64(LIR_cmovq:) + case LIR_cmovi: + case LIR_cmovd: + VMPI_snprintf(s, n, "%s = %s %s ? %s : %s", formatRef(&b1, i), lirNames[op], + formatRef(&b2, i->oprnd1()), + formatRef(&b3, i->oprnd2()), + formatRef(&b4, i->oprnd3())); + break; + + case LIR_ldi: + CASE64(LIR_ldq:) + case LIR_ldd: + case LIR_lduc2ui: + case LIR_ldus2ui: + case LIR_ldc2i: + case LIR_lds2i: + case LIR_ldf2d: { + const char* qualStr; + switch (i->loadQual()) { + case LOAD_CONST: qualStr = "/c"; break; + case LOAD_NORMAL: qualStr = ""; break; + case LOAD_VOLATILE: qualStr = "/v"; break; + default: NanoAssert(0); qualStr = "/?"; break; + } + VMPI_snprintf(s, n, "%s = %s%s%s %s[%d]", formatRef(&b1, i), lirNames[op], + formatAccSet(&b2, i->accSet()), qualStr, formatRef(&b3, i->oprnd1()), + i->disp()); + break; + } + + case LIR_sti: + CASE64(LIR_stq:) + case LIR_std: + case LIR_sti2c: + case LIR_sti2s: + case LIR_std2f: + VMPI_snprintf(s, n, "%s%s %s[%d] = %s", lirNames[op], + formatAccSet(&b1, i->accSet()), + formatRef(&b2, i->oprnd2()), + i->disp(), + formatRef(&b3, i->oprnd1())); + break; + + case LIR_comment: + VMPI_snprintf(s, n, "------------------------------ # %s", (char*)i->oprnd1()); + break; + + default: + NanoAssertMsgf(0, "Can't handle opcode %s\n", lirNames[op]); + break; + } + return buf->buf; + } +#endif + + CseFilter::CseFilter(LirWriter *out, uint8_t embNumUsedAccs, Allocator& alloc) + : LirWriter(out), + EMB_NUM_USED_ACCS(embNumUsedAccs), + CSE_NUM_USED_ACCS(EMB_NUM_USED_ACCS + 2), + CSE_ACC_CONST( EMB_NUM_USED_ACCS + 0), + CSE_ACC_MULTIPLE( EMB_NUM_USED_ACCS + 1), + storesSinceLastLoad(ACCSET_NONE), + alloc(alloc), + knownCmpValues(alloc), + suspended(false), + initOOM(false) + { + m_findNL[NLImmISmall] = &CseFilter::findImmISmall; + m_findNL[NLImmILarge] = &CseFilter::findImmILarge; + m_findNL[NLImmQ] = PTR_SIZE(NULL, &CseFilter::findImmQ); + m_findNL[NLImmD] = &CseFilter::findImmD; + m_findNL[NL1] = &CseFilter::find1; + m_findNL[NL2] = &CseFilter::find2; + m_findNL[NL3] = &CseFilter::find3; + m_findNL[NLCall] = &CseFilter::findCall; + + m_capNL[NLImmISmall] = 17; // covers 0..16, which is over half the cases for TraceMonkey + m_capNL[NLImmILarge] = 64; + m_capNL[NLImmQ] = PTR_SIZE(0, 16); + m_capNL[NLImmD] = 16; + m_capNL[NL1] = 256; + m_capNL[NL2] = 512; + m_capNL[NL3] = 16; + m_capNL[NLCall] = 64; + + // The largish allocations are fallible, the small ones are + // infallible. See the comment on initOOM's declaration for why. + + for (NLKind nlkind = NLFirst; nlkind <= NLLast; nlkind = nextNLKind(nlkind)) { + m_listNL[nlkind] = (LIns**)alloc.fallibleAlloc(sizeof(LIns*) * m_capNL[nlkind]); + if (!m_listNL[nlkind]) { + initOOM = true; + return; + } + m_usedNL[nlkind] = 1; // Force memset in clearAll(). + } + + // Note that this allocates the CONST and MULTIPLE tables as well. + for (CseAcc a = 0; a < CSE_NUM_USED_ACCS; a++) { + m_capL[a] = 16; + m_listL[a] = (LIns**)alloc.fallibleAlloc(sizeof(LIns*) * m_capL[a]); + if (!m_listL[a]) { + initOOM = true; + return; + } + m_usedL[a] = 1; // Force memset(0) in first clearAll(). + } + + clearAll(); + } + + // Inlined/separated version of SuperFastHash. + // This content is copyrighted by Paul Hsieh. + // For reference see: http://www.azillionmonkeys.com/qed/hash.html + // + inline uint32_t CseFilter::hash8(uint32_t hash, const uint8_t data) + { + hash += data; + hash ^= hash << 10; + hash += hash >> 1; + return hash; + } + + inline uint32_t CseFilter::hash32(uint32_t hash, const uint32_t data) + { + const uint32_t dlo = data & 0xffff; + const uint32_t dhi = data >> 16; + hash += dlo; + const uint32_t tmp = (dhi << 11) ^ hash; + hash = (hash << 16) ^ tmp; + hash += hash >> 11; + return hash; + } + + inline uint32_t CseFilter::hashptr(uint32_t hash, const void* data) + { +#ifdef NANOJIT_64BIT + hash = hash32(hash, uint32_t(uintptr_t(data) >> 32)); + hash = hash32(hash, uint32_t(uintptr_t(data))); + return hash; +#else + return hash32(hash, uint32_t(data)); +#endif + } + + inline uint32_t CseFilter::hashfinish(uint32_t hash) + { + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; + } + + void CseFilter::clearNL(NLKind nlkind) { + if (m_usedNL[nlkind] > 0) { + VMPI_memset(m_listNL[nlkind], 0, sizeof(LIns*)*m_capNL[nlkind]); + m_usedNL[nlkind] = 0; + } + } + + void CseFilter::clearL(CseAcc a) { + if (m_usedL[a] > 0) { + VMPI_memset(m_listL[a], 0, sizeof(LIns*)*m_capL[a]); + m_usedL[a] = 0; + } + } + + void CseFilter::clearAll() { + for (NLKind nlkind = NLFirst; nlkind <= NLLast; nlkind = nextNLKind(nlkind)) + clearNL(nlkind); + + // Note that this clears the CONST and MULTIPLE load tables as well. + for (CseAcc a = 0; a < CSE_NUM_USED_ACCS; a++) + clearL(a); + + knownCmpValues.clear(); + } + + inline uint32_t CseFilter::hashImmI(int32_t a) { + return hashfinish(hash32(0, a)); + } + + inline uint32_t CseFilter::hashImmQorD(uint64_t a) { + uint32_t hash = hash32(0, uint32_t(a >> 32)); + return hashfinish(hash32(hash, uint32_t(a))); + } + + inline uint32_t CseFilter::hash1(LOpcode op, LIns* a) { + uint32_t hash = hash8(0, uint8_t(op)); + return hashfinish(hashptr(hash, a)); + } + + inline uint32_t CseFilter::hash2(LOpcode op, LIns* a, LIns* b) { + uint32_t hash = hash8(0, uint8_t(op)); + hash = hashptr(hash, a); + return hashfinish(hashptr(hash, b)); + } + + inline uint32_t CseFilter::hash3(LOpcode op, LIns* a, LIns* b, LIns* c) { + uint32_t hash = hash8(0, uint8_t(op)); + hash = hashptr(hash, a); + hash = hashptr(hash, b); + return hashfinish(hashptr(hash, c)); + } + + // Nb: no need to hash the load's MiniAccSet because each every load goes + // into a table where all the loads have the same MiniAccSet. + inline uint32_t CseFilter::hashLoad(LOpcode op, LIns* a, int32_t d) { + uint32_t hash = hash8(0, uint8_t(op)); + hash = hashptr(hash, a); + return hashfinish(hash32(hash, d)); + } + + inline uint32_t CseFilter::hashCall(const CallInfo *ci, uint32_t argc, LIns* args[]) { + uint32_t hash = hashptr(0, ci); + for (int32_t j=argc-1; j >= 0; j--) + hash = hashptr(hash,args[j]); + return hashfinish(hash); + } + + bool CseFilter::growNL(NLKind nlkind) + { + NanoAssert(nlkind != NLImmISmall); + const uint32_t oldcap = m_capNL[nlkind]; + m_capNL[nlkind] <<= 1; + // We make this allocation fallible because it's potentially large and + // easy to recover from. If it fails, we won't add any more + // instructions to the table and some CSE opportunities may be missed. + LIns** tmp = (LIns**)alloc.fallibleAlloc(sizeof(LIns*) * m_capNL[nlkind]); + if (tmp) { + LIns** oldlist = m_listNL[nlkind]; + m_listNL[nlkind] = tmp; + VMPI_memset(m_listNL[nlkind], 0, m_capNL[nlkind] * sizeof(LIns*)); + find_t find = m_findNL[nlkind]; + for (uint32_t i = 0; i < oldcap; i++) { + LIns* ins = oldlist[i]; + if (!ins) continue; + uint32_t j = (this->*find)(ins); + NanoAssert(!m_listNL[nlkind][j]); + m_listNL[nlkind][j] = ins; + } + return true; + } else { + m_capNL[nlkind] = oldcap; + return false; + } + } + + bool CseFilter::growL(CseAcc cseAcc) + { + const uint32_t oldcap = m_capL[cseAcc]; + m_capL[cseAcc] <<= 1; + LIns** tmp = (LIns**)alloc.fallibleAlloc(sizeof(LIns*) * m_capL[cseAcc]); + if (tmp) { + LIns** oldlist = m_listL[cseAcc]; + m_listL[cseAcc] = tmp; + VMPI_memset(m_listL[cseAcc], 0, m_capL[cseAcc] * sizeof(LIns*)); + find_t find = &CseFilter::findLoad; + for (uint32_t i = 0; i < oldcap; i++) { + LIns* ins = oldlist[i]; + if (!ins) continue; + uint32_t j = (this->*find)(ins); + NanoAssert(!m_listL[cseAcc][j]); + m_listL[cseAcc][j] = ins; + } + return true; + } else { + m_capL[cseAcc] = oldcap; + return false; + } + } + + void CseFilter::addNLImmISmall(LIns* ins, uint32_t k) + { + NanoAssert(!initOOM); + if (suspended) return; + NLKind nlkind = NLImmISmall; + NanoAssert(k < m_capNL[nlkind]); + NanoAssert(!m_listNL[nlkind][k]); + m_usedNL[nlkind]++; + m_listNL[nlkind][k] = ins; + } + + void CseFilter::addNL(NLKind nlkind, LIns* ins, uint32_t k) + { + NanoAssert(!initOOM); + if (suspended) return; + NanoAssert(!m_listNL[nlkind][k]); + m_usedNL[nlkind]++; + m_listNL[nlkind][k] = ins; + if ((m_usedNL[nlkind] * 4) >= (m_capNL[nlkind] * 3)) { // load factor of 0.75 + bool ok = growNL(nlkind); + if (!ok) { + // OOM: undo the insertion. + m_usedNL[nlkind]--; + m_listNL[nlkind][k] = NULL; + } + } + } + + void CseFilter::addL(LIns* ins, uint32_t k) + { + NanoAssert(!initOOM); + if (suspended) return; + CseAcc cseAcc = miniAccSetToCseAcc(ins->miniAccSet(), ins->loadQual()); + NanoAssert(!m_listL[cseAcc][k]); + m_usedL[cseAcc]++; + m_listL[cseAcc][k] = ins; + if ((m_usedL[cseAcc] * 4) >= (m_capL[cseAcc] * 3)) { // load factor of 0.75 + bool ok = growL(cseAcc); + if (!ok) { + // OOM: undo the insertion. + m_usedL[cseAcc]--; + m_listL[cseAcc][k] = NULL; + } + } + } + + inline LIns* CseFilter::findImmISmall(int32_t a, uint32_t &k) + { + // This one is a direct array lookup rather than a hashtable lookup. + NLKind nlkind = NLImmISmall; + k = a; + LIns* ins = m_listNL[nlkind][k]; + NanoAssert(!ins || ins->isImmI(a)); + return ins; + } + + uint32_t CseFilter::findImmISmall(LIns* ins) + { + uint32_t k; + findImmISmall(ins->immI(), k); + return k; + } + + inline LIns* CseFilter::findImmILarge(int32_t a, uint32_t &k) + { + NLKind nlkind = NLImmILarge; + const uint32_t bitmask = m_capNL[nlkind] - 1; + k = hashImmI(a) & bitmask; + uint32_t n = 1; + while (true) { + LIns* ins = m_listNL[nlkind][k]; + if (!ins) + return NULL; + NanoAssert(ins->isImmI()); + if (ins->immI() == a) + return ins; + // Quadratic probe: h(k,i) = h(k) + 0.5i + 0.5i^2, which gives the + // sequence h(k), h(k)+1, h(k)+3, h(k)+6, h+10, ... This is a + // good sequence for 2^n-sized tables as the values h(k,i) for i + // in [0,m − 1] are all distinct so termination is guaranteed. + // See http://portal.acm.org/citation.cfm?id=360737 and + // http://en.wikipedia.org/wiki/Quadratic_probing (fetched + // 06-Nov-2009) for more details. + k = (k + n) & bitmask; + n += 1; + } + } + + uint32_t CseFilter::findImmILarge(LIns* ins) + { + uint32_t k; + findImmILarge(ins->immI(), k); + return k; + } + +#ifdef NANOJIT_64BIT + inline LIns* CseFilter::findImmQ(uint64_t a, uint32_t &k) + { + NLKind nlkind = NLImmQ; + const uint32_t bitmask = m_capNL[nlkind] - 1; + k = hashImmQorD(a) & bitmask; + uint32_t n = 1; + while (true) { + LIns* ins = m_listNL[nlkind][k]; + if (!ins) + return NULL; + NanoAssert(ins->isImmQ()); + if (ins->immQ() == a) + return ins; + k = (k + n) & bitmask; + n += 1; + } + } + + uint32_t CseFilter::findImmQ(LIns* ins) + { + uint32_t k; + findImmQ(ins->immQ(), k); + return k; + } +#endif + + inline LIns* CseFilter::findImmD(uint64_t a, uint32_t &k) + { + NLKind nlkind = NLImmD; + const uint32_t bitmask = m_capNL[nlkind] - 1; + k = hashImmQorD(a) & bitmask; + uint32_t n = 1; + while (true) { + LIns* ins = m_listNL[nlkind][k]; + if (!ins) + return NULL; + NanoAssert(ins->isImmD()); + if (ins->immDasQ() == a) + return ins; + k = (k + n) & bitmask; + n += 1; + } + } + + uint32_t CseFilter::findImmD(LIns* ins) + { + uint32_t k; + findImmD(ins->immDasQ(), k); + return k; + } + + inline LIns* CseFilter::find1(LOpcode op, LIns* a, uint32_t &k) + { + NLKind nlkind = NL1; + const uint32_t bitmask = m_capNL[nlkind] - 1; + k = hash1(op, a) & bitmask; + uint32_t n = 1; + while (true) { + LIns* ins = m_listNL[nlkind][k]; + if (!ins) + return NULL; + if (ins->isop(op) && ins->oprnd1() == a) + return ins; + k = (k + n) & bitmask; + n += 1; + } + } + + uint32_t CseFilter::find1(LIns* ins) + { + uint32_t k; + find1(ins->opcode(), ins->oprnd1(), k); + return k; + } + + inline LIns* CseFilter::find2(LOpcode op, LIns* a, LIns* b, uint32_t &k) + { + NLKind nlkind = NL2; + const uint32_t bitmask = m_capNL[nlkind] - 1; + k = hash2(op, a, b) & bitmask; + uint32_t n = 1; + while (true) { + LIns* ins = m_listNL[nlkind][k]; + if (!ins) + return NULL; + if (ins->isop(op) && ins->oprnd1() == a && ins->oprnd2() == b) + return ins; + k = (k + n) & bitmask; + n += 1; + } + } + + uint32_t CseFilter::find2(LIns* ins) + { + uint32_t k; + find2(ins->opcode(), ins->oprnd1(), ins->oprnd2(), k); + return k; + } + + inline LIns* CseFilter::find3(LOpcode op, LIns* a, LIns* b, LIns* c, uint32_t &k) + { + NLKind nlkind = NL3; + const uint32_t bitmask = m_capNL[nlkind] - 1; + k = hash3(op, a, b, c) & bitmask; + uint32_t n = 1; + while (true) { + LIns* ins = m_listNL[nlkind][k]; + if (!ins) + return NULL; + if (ins->isop(op) && ins->oprnd1() == a && ins->oprnd2() == b && ins->oprnd3() == c) + return ins; + k = (k + n) & bitmask; + n += 1; + } + } + + uint32_t CseFilter::find3(LIns* ins) + { + uint32_t k; + find3(ins->opcode(), ins->oprnd1(), ins->oprnd2(), ins->oprnd3(), k); + return k; + } + + inline LIns* CseFilter::findLoad(LOpcode op, LIns* a, int32_t d, MiniAccSet miniAccSet, + LoadQual loadQual, uint32_t &k) + { + CseAcc cseAcc = miniAccSetToCseAcc(miniAccSet, loadQual); + const uint32_t bitmask = m_capL[cseAcc] - 1; + k = hashLoad(op, a, d) & bitmask; + uint32_t n = 1; + while (true) { + LIns* ins = m_listL[cseAcc][k]; + if (!ins) + return NULL; + // All the loads in this table should have the same miniAccSet and + // loadQual. + NanoAssert(miniAccSetToCseAcc(ins->miniAccSet(), ins->loadQual()) == cseAcc && + ins->loadQual() == loadQual); + if (ins->isop(op) && ins->oprnd1() == a && ins->disp() == d) + return ins; + k = (k + n) & bitmask; + n += 1; + } + } + + uint32_t CseFilter::findLoad(LIns* ins) + { + uint32_t k; + findLoad(ins->opcode(), ins->oprnd1(), ins->disp(), ins->miniAccSet(), ins->loadQual(), k); + return k; + } + + bool argsmatch(LIns* ins, uint32_t argc, LIns* args[]) + { + for (uint32_t j=0; j < argc; j++) + if (ins->arg(j) != args[j]) + return false; + return true; + } + + inline LIns* CseFilter::findCall(const CallInfo *ci, uint32_t argc, LIns* args[], uint32_t &k) + { + NLKind nlkind = NLCall; + const uint32_t bitmask = m_capNL[nlkind] - 1; + k = hashCall(ci, argc, args) & bitmask; + uint32_t n = 1; + while (true) { + LIns* ins = m_listNL[nlkind][k]; + if (!ins) + return NULL; + if (ins->isCall() && ins->callInfo() == ci && argsmatch(ins, argc, args)) + return ins; + k = (k + n) & bitmask; + n += 1; + } + } + + uint32_t CseFilter::findCall(LIns* ins) + { + LIns* args[MAXARGS]; + uint32_t argc = ins->argc(); + NanoAssert(argc < MAXARGS); + for (uint32_t j=0; j < argc; j++) + args[j] = ins->arg(j); + uint32_t k; + findCall(ins->callInfo(), argc, args, k); + return k; + } + + LIns* CseFilter::insImmI(int32_t imm) + { + uint32_t k; + LIns* ins; + if (0 <= imm && imm < int32_t(m_capNL[NLImmISmall])) { + ins = findImmISmall(imm, k); + if (!ins) { + ins = out->insImmI(imm); + addNLImmISmall(ins, k); + } + } else { + ins = findImmILarge(imm, k); + if (!ins) { + ins = out->insImmI(imm); + addNL(NLImmILarge, ins, k); + } + } + // We assume that downstream stages do not modify the instruction, so + // that we can insert 'ins' into slot 'k'. Check this. + NanoAssert(ins->isop(LIR_immi) && ins->immI() == imm); + return ins; + } + +#ifdef NANOJIT_64BIT + LIns* CseFilter::insImmQ(uint64_t q) + { + uint32_t k; + LIns* ins = findImmQ(q, k); + if (!ins) { + ins = out->insImmQ(q); + addNL(NLImmQ, ins, k); + } + NanoAssert(ins->isop(LIR_immq) && ins->immQ() == q); + return ins; + } +#endif + + LIns* CseFilter::insImmD(double d) + { + uint32_t k; + // We must pun 'd' as a uint64_t otherwise 0 and -0 will be treated as + // equal, which breaks things (see bug 527288). + union { + double d; + uint64_t u64; + } u; + u.d = d; + LIns* ins = findImmD(u.u64, k); + if (!ins) { + ins = out->insImmD(d); + addNL(NLImmD, ins, k); + } + NanoAssert(ins->isop(LIR_immd) && ins->immDasQ() == u.u64); + return ins; + } + + LIns* CseFilter::ins0(LOpcode op) + { + if (op == LIR_label && !suspended) + clearAll(); + return out->ins0(op); + } + + LIns* CseFilter::ins1(LOpcode op, LIns* a) + { + LIns* ins; + if (isCseOpcode(op)) { + uint32_t k; + ins = find1(op, a, k); + if (!ins) { + ins = out->ins1(op, a); + addNL(NL1, ins, k); + } + } else { + ins = out->ins1(op, a); + } + NanoAssert(ins->isop(op) && ins->oprnd1() == a); + return ins; + } + + LIns* CseFilter::ins2(LOpcode op, LIns* a, LIns* b) + { + LIns* ins; + NanoAssert(isCseOpcode(op)); + uint32_t k; + ins = find2(op, a, b, k); + if (!ins) { + ins = out->ins2(op, a, b); + addNL(NL2, ins, k); + } else if (ins->isCmp()) { + if (knownCmpValues.containsKey(ins)) { + // We've seen this comparison before, and it was previously + // used in a guard, so we know what its value must be at this + // point. Replace it with a constant. + NanoAssert(ins->isCmp()); + bool cmpValue = knownCmpValues.get(ins); + return insImmI(cmpValue ? 1 : 0); + } + } + NanoAssert(ins->isop(op) && ins->oprnd1() == a && ins->oprnd2() == b); + return ins; + } + + LIns* CseFilter::ins3(LOpcode op, LIns* a, LIns* b, LIns* c) + { + NanoAssert(isCseOpcode(op)); + uint32_t k; + LIns* ins = find3(op, a, b, c, k); + if (!ins) { + ins = out->ins3(op, a, b, c); + addNL(NL3, ins, k); + } + NanoAssert(ins->isop(op) && ins->oprnd1() == a && ins->oprnd2() == b && ins->oprnd3() == c); + return ins; + } + + LIns* CseFilter::insLoad(LOpcode op, LIns* base, int32_t disp, AccSet accSet, LoadQual loadQual) + { + LIns* ins; + if (isS16(disp)) { + if (storesSinceLastLoad != ACCSET_NONE) { + // Clear all normal (excludes CONST and MULTIPLE) loads + // aliased by stores and calls since the last time we were in + // this function. Aliased loads must be cleared even when CSE + // is suspended. + AccSet a = storesSinceLastLoad & ((1 << EMB_NUM_USED_ACCS) - 1); + while (a) { + int acc = msbSet32(a); + clearL((CseAcc)acc); + a &= ~(1 << acc); + } + + // No need to clear CONST loads (those in the CSE_ACC_CONST table). + + // Multi-region loads must be treated conservatively -- we + // always clear all of them. + clearL(CSE_ACC_MULTIPLE); + + storesSinceLastLoad = ACCSET_NONE; + } + + if (loadQual == LOAD_VOLATILE) { + // Volatile loads are never CSE'd, don't bother looking for + // them or inserting them in the table. + ins = out->insLoad(op, base, disp, accSet, loadQual); + } else { + uint32_t k; + ins = findLoad(op, base, disp, compressAccSet(accSet), loadQual, k); + if (!ins) { + ins = out->insLoad(op, base, disp, accSet, loadQual); + addL(ins, k); + } + } + // Nb: must compare miniAccSets, not AccSets, because the AccSet + // stored in the load may have lost info if it's multi-region. + NanoAssert(ins->isop(op) && ins->oprnd1() == base && ins->disp() == disp && + ins->miniAccSet().val == compressAccSet(accSet).val && + ins->loadQual() == loadQual); + } else { + // If the displacement is more than 16 bits, put it in a separate + // instruction. Nb: LirBufWriter also does this, we do it here + // too because CseFilter relies on LirBufWriter not changing code. + ins = insLoad(op, ins2(LIR_addp, base, insImmWord(disp)), 0, accSet, loadQual); + } + return ins; + } + + LIns* CseFilter::insStore(LOpcode op, LIns* value, LIns* base, int32_t disp, AccSet accSet) + { + LIns* ins; + if (isS16(disp)) { + storesSinceLastLoad |= accSet; + ins = out->insStore(op, value, base, disp, accSet); + NanoAssert(ins->isop(op) && ins->oprnd1() == value && ins->oprnd2() == base && + ins->disp() == disp && ins->accSet() == accSet); + } else { + // If the displacement is more than 16 bits, put it in a separate + // instruction. Nb: LirBufWriter also does this, we do it here + // too because CseFilter relies on LirBufWriter not changing code. + ins = insStore(op, value, ins2(LIR_addp, base, insImmWord(disp)), 0, accSet); + } + return ins; + } + + LIns* CseFilter::insGuard(LOpcode op, LIns* c, GuardRecord *gr) + { + // LIR_xt and LIR_xf guards are CSEable. Note that we compare the + // opcode and condition when determining if two guards are equivalent + // -- in find1() and hash1() -- but we do *not* compare the + // GuardRecord. This works because: + // - If guard 1 is taken (exits) then guard 2 is never reached, so + // guard 2 can be removed. + // - If guard 1 is not taken then neither is guard 2, so guard 2 can + // be removed. + // + // The underlying assumptions that are required for this to be safe: + // - There's never a path from the side exit of guard 1 back to guard + // 2; for tree-shaped fragments this should be true. + // - GuardRecords do not contain information other than what is needed + // to execute a successful exit. That is currently true. + // - The CSE algorithm will always keep guard 1 and remove guard 2 + // (not vice versa). The current algorithm does this. + // + LIns* ins; + if (isCseOpcode(op)) { + // conditional guard + uint32_t k; + ins = find1(op, c, k); + if (!ins) { + ins = out->insGuard(op, c, gr); + addNL(NL1, ins, k); + } + // After this guard, we know that 'c's result was true (if + // op==LIR_xf) or false (if op==LIR_xt), else we would have + // exited. Record this fact in case 'c' occurs again. + if (!suspended) { + bool c_value = (op == LIR_xt ? false : true); + knownCmpValues.put(c, c_value); + } + } else { + ins = out->insGuard(op, c, gr); + } + NanoAssert(ins->isop(op) && ins->oprnd1() == c); + return ins; + } + + LIns* CseFilter::insGuardXov(LOpcode op, LIns* a, LIns* b, GuardRecord *gr) + { + // LIR_*xov are CSEable. See CseFilter::insGuard() for details. + NanoAssert(isCseOpcode(op)); + // conditional guard + uint32_t k; + LIns* ins = find2(op, a, b, k); + if (!ins) { + ins = out->insGuardXov(op, a, b, gr); + addNL(NL2, ins, k); + } + NanoAssert(ins->isop(op) && ins->oprnd1() == a && ins->oprnd2() == b); + return ins; + } + + // There is no CseFilter::insBranchJov(), as LIR_*jov* are not CSEable. + + LIns* CseFilter::insCall(const CallInfo *ci, LIns* args[]) + { + LIns* ins; + uint32_t argc = ci->count_args(); + if (ci->_isPure) { + NanoAssert(ci->_storeAccSet == ACCSET_NONE); + uint32_t k; + ins = findCall(ci, argc, args, k); + if (!ins) { + ins = out->insCall(ci, args); + addNL(NLCall, ins, k); + } + } else { + // We only need to worry about aliasing if !ci->_isPure. + storesSinceLastLoad |= ci->_storeAccSet; + ins = out->insCall(ci, args); + } + NanoAssert(ins->isCall() && ins->callInfo() == ci && argsmatch(ins, argc, args)); + return ins; + } + + // Interval analysis can be done much more accurately than we do here. + // For speed and simplicity in a number of cases (eg. LIR_andi, LIR_rshi) + // we just look for easy-to-handle (but common!) cases such as when the + // RHS is a constant; in practice this gives good results. It also cuts + // down the amount of backwards traversals we have to do, which is good. + // + // 'lim' also limits the number of backwards traversals; it's decremented + // on each recursive call and we give up when it reaches zero. This + // prevents possible time blow-ups in long expression chains. We don't + // check 'lim' at the top of this function, as you might expect, because + // the behaviour when the limit is reached depends on the opcode. + // + Interval Interval::of(LIns* ins, int lim) + { + switch (ins->opcode()) { + case LIR_immi: { + int32_t i = ins->immI(); + return Interval(i, i); + } + + case LIR_ldc2i: return Interval( -128, 127); + case LIR_lduc2ui: return Interval( 0, 255); + case LIR_lds2i: return Interval(-32768, 32767); + case LIR_ldus2ui: return Interval( 0, 65535); + + case LIR_addi: + case LIR_addxovi: + case LIR_addjovi: + if (lim > 0) + return add(of(ins->oprnd1(), lim-1), of(ins->oprnd2(), lim-1)); + goto overflow; + + case LIR_subi: + case LIR_subxovi: + case LIR_subjovi: + if (lim > 0) + return sub(of(ins->oprnd1(), lim-1), of(ins->oprnd2(), lim-1)); + goto overflow; + + case LIR_negi: + if (lim > 0) + return sub(Interval(0, 0), of(ins->oprnd1(), lim-1)); + goto overflow; + + case LIR_muli: + case LIR_mulxovi: + case LIR_muljovi: + if (lim > 0) + return mul(of(ins->oprnd1(), lim), of(ins->oprnd2(), lim)); + goto overflow; + + case LIR_andi: { + // Only handle one common case accurately, for speed and simplicity. + if (ins->oprnd2()->isImmI() && ins->oprnd2()->immI() > 0) { + // Example: andi [lo,hi], 0xffff --> [0, 0xffff] + return Interval(0, ins->oprnd2()->immI()); + } + goto worst_non_overflow; + } + + case LIR_rshui: { + // Only handle one common case accurately, for speed and simplicity. + if (ins->oprnd2()->isImmI() && lim > 0) { + Interval x = of(ins->oprnd1(), lim-1); + int32_t y = ins->oprnd2()->immI() & 0x1f; // we only use the bottom 5 bits + NanoAssert(x.isSane()); + if (!x.hasOverflowed && (x.lo >= 0 || y > 0)) { + // If LHS is non-negative or RHS is positive, the result is + // non-negative because the top bit must be zero. + // Example: rshui [0,hi], 16 --> [0, hi>>16] + return Interval(0, x.hi >> y); + } + } + goto worst_non_overflow; + } + + case LIR_rshi: { + // Only handle one common case accurately, for speed and simplicity. + if (ins->oprnd2()->isImmI()) { + // Example: rshi [lo,hi], 16 --> [32768, 32767] + int32_t y = ins->oprnd2()->immI() & 0x1f; // we only use the bottom 5 bits + return Interval(-(1 << (31 - y)), + (1 << (31 - y)) - 1); + } + goto worst_non_overflow; + } + +#if defined NANOJIT_IA32 || defined NANOJIT_X64 + case LIR_modi: { + NanoAssert(ins->oprnd1()->isop(LIR_divi)); + LIns* op2 = ins->oprnd1()->oprnd2(); + // Only handle one common case accurately, for speed and simplicity. + if (op2->isImmI() && op2->immI() != 0) { + int32_t y = op2->immI(); + int32_t absy = (y >= 0) ? y : -y; + // The result must smaller in magnitude than 'y'. + // Example: modi [lo,hi], 5 --> [-4, 4] + return Interval(-absy + 1, absy - 1); + } + goto worst_non_overflow; + } +#endif + + case LIR_cmovi: { + if (lim > 0) { + Interval x = of(ins->oprnd2(), lim-1); + Interval y = of(ins->oprnd3(), lim-1); + NanoAssert(x.isSane() && y.isSane()); + if (!x.hasOverflowed && !y.hasOverflowed) + return Interval(NJ_MIN(x.lo, y.lo), NJ_MAX(x.hi, y.hi)); + } + goto overflow; + } + + case LIR_eqi: CASE64(LIR_eqq:) + case LIR_lti: CASE64(LIR_ltq:) + case LIR_lei: CASE64(LIR_leq:) + case LIR_gti: CASE64(LIR_gtq:) + case LIR_gei: CASE64(LIR_geq:) + case LIR_ltui: CASE64(LIR_ltuq:) + case LIR_leui: CASE64(LIR_leuq:) + case LIR_gtui: CASE64(LIR_gtuq:) + case LIR_geui: CASE64(LIR_geuq:) + case LIR_eqd: + case LIR_ltd: + case LIR_led: + case LIR_gtd: + case LIR_ged: + return Interval(0, 1); + + CASE32(LIR_paramp:) + case LIR_ldi: + case LIR_noti: + case LIR_ori: + case LIR_xori: + case LIR_lshi: + CASE86(LIR_divi:) + case LIR_calli: + case LIR_reti: + CASE64(LIR_q2i:) + case LIR_d2i: + CASESF(LIR_dlo2i:) + CASESF(LIR_dhi2i:) + CASESF(LIR_hcalli:) + goto worst_non_overflow; + + default: + NanoAssertMsgf(0, "%s", lirNames[ins->opcode()]); + } + + overflow: + return OverflowInterval(); + + worst_non_overflow: + // Only cases that cannot overflow should reach here, ie. not add/sub/mul. + return Interval(I32_MIN, I32_MAX); + } + + Interval Interval::add(Interval x, Interval y) { + NanoAssert(x.isSane() && y.isSane()); + + if (x.hasOverflowed || y.hasOverflowed) + return OverflowInterval(); + + // Nb: the bounds in x and y are known to fit in 32 bits (isSane() + // checks that) so x.lo+y.lo and x.hi+y.hi are guaranteed to fit + // in 64 bits. This also holds for the other cases below such as + // sub() and mul(). + return Interval(x.lo + y.lo, x.hi + y.hi); + } + + Interval Interval::sub(Interval x, Interval y) { + NanoAssert(x.isSane() && y.isSane()); + + if (x.hasOverflowed || y.hasOverflowed) + return OverflowInterval(); + + return Interval(x.lo - y.hi, x.hi - y.lo); + } + + Interval Interval::mul(Interval x, Interval y) { + NanoAssert(x.isSane() && y.isSane()); + + if (x.hasOverflowed || y.hasOverflowed) + return OverflowInterval(); + + int64_t a = x.lo * y.lo; + int64_t b = x.lo * y.hi; + int64_t c = x.hi * y.lo; + int64_t d = x.hi * y.hi; + return Interval(NJ_MIN(NJ_MIN(a, b), NJ_MIN(c, d)), + NJ_MAX(NJ_MAX(a, b), NJ_MAX(c, d))); + } + +#if NJ_SOFTFLOAT_SUPPORTED + static int32_t FASTCALL d2i(double d) { return (int32_t) d; } + static double FASTCALL i2d(int32_t i) { return i; } + static double FASTCALL ui2d(uint32_t u) { return u; } + static double FASTCALL negd(double a) { return -a; } + static double FASTCALL addd(double a, double b) { return a + b; } + static double FASTCALL subd(double a, double b) { return a - b; } + static double FASTCALL muld(double a, double b) { return a * b; } + static double FASTCALL divd(double a, double b) { return a / b; } + static int32_t FASTCALL eqd(double a, double b) { return a == b; } + static int32_t FASTCALL ltd(double a, double b) { return a < b; } + static int32_t FASTCALL gtd(double a, double b) { return a > b; } + static int32_t FASTCALL led(double a, double b) { return a <= b; } + static int32_t FASTCALL ged(double a, double b) { return a >= b; } + + #define SIG_I_D CallInfo::typeSig1(ARGTYPE_I, ARGTYPE_D) + #define SIG_D_I CallInfo::typeSig1(ARGTYPE_D, ARGTYPE_I) + #define SIG_D_UI CallInfo::typeSig1(ARGTYPE_D, ARGTYPE_UI) + #define SIG_D_D CallInfo::typeSig1(ARGTYPE_D, ARGTYPE_D) + #define SIG_D_DD CallInfo::typeSig2(ARGTYPE_D, ARGTYPE_D, ARGTYPE_D) + #define SIG_B_DD CallInfo::typeSig2(ARGTYPE_B, ARGTYPE_D, ARGTYPE_D) + + #define SF_CALLINFO(name, typesig) \ + static const CallInfo name##_ci = \ + { (intptr_t)&name, typesig, ABI_FASTCALL, /*isPure*/1, ACCSET_NONE verbose_only(, #name) } + + SF_CALLINFO(d2i, SIG_I_D); + SF_CALLINFO(i2d, SIG_D_I); + SF_CALLINFO(ui2d, SIG_D_UI); + SF_CALLINFO(negd, SIG_D_D); + SF_CALLINFO(addd, SIG_D_DD); + SF_CALLINFO(subd, SIG_D_DD); + SF_CALLINFO(muld, SIG_D_DD); + SF_CALLINFO(divd, SIG_D_DD); + SF_CALLINFO(eqd, SIG_B_DD); + SF_CALLINFO(ltd, SIG_B_DD); + SF_CALLINFO(gtd, SIG_B_DD); + SF_CALLINFO(led, SIG_B_DD); + SF_CALLINFO(ged, SIG_B_DD); + + SoftFloatOps::SoftFloatOps() + { + memset(opmap, 0, sizeof(opmap)); + opmap[LIR_d2i] = &d2i_ci; + opmap[LIR_i2d] = &i2d_ci; + opmap[LIR_ui2d] = &ui2d_ci; + opmap[LIR_negd] = &negd_ci; + opmap[LIR_addd] = &addd_ci; + opmap[LIR_subd] = &subd_ci; + opmap[LIR_muld] = &muld_ci; + opmap[LIR_divd] = &divd_ci; + opmap[LIR_eqd] = &eqd_ci; + opmap[LIR_ltd] = <d_ci; + opmap[LIR_gtd] = >d_ci; + opmap[LIR_led] = &led_ci; + opmap[LIR_ged] = &ged_ci; + } + + const SoftFloatOps softFloatOps; + + SoftFloatFilter::SoftFloatFilter(LirWriter *out) : LirWriter(out) + {} + + LIns* SoftFloatFilter::split(LIns *a) { + if (a->isD() && !a->isop(LIR_ii2d)) { + // all F64 args must be qjoin's for soft-float + a = ins2(LIR_ii2d, ins1(LIR_dlo2i, a), ins1(LIR_dhi2i, a)); + } + return a; + } + + LIns* SoftFloatFilter::split(const CallInfo *call, LIns* args[]) { + LIns *lo = out->insCall(call, args); + LIns *hi = out->ins1(LIR_hcalli, lo); + return out->ins2(LIR_ii2d, lo, hi); + } + + LIns* SoftFloatFilter::callD1(const CallInfo *call, LIns *a) { + LIns *args[] = { split(a) }; + return split(call, args); + } + + LIns* SoftFloatFilter::callI1(const CallInfo *call, LIns *a) { + LIns *args[] = { split(a) }; + return out->insCall(call, args); + } + + LIns* SoftFloatFilter::callD2(const CallInfo *call, LIns *a, LIns *b) { + LIns *args[] = { split(b), split(a) }; + return split(call, args); + } + + LIns* SoftFloatFilter::cmpD(const CallInfo *call, LIns *a, LIns *b) { + LIns *args[] = { split(b), split(a) }; + return out->ins2(LIR_eqi, out->insCall(call, args), out->insImmI(1)); + } + + LIns* SoftFloatFilter::ins1(LOpcode op, LIns *a) { + const CallInfo *ci = softFloatOps.opmap[op]; + if (ci) { + if (ci->returnType() == ARGTYPE_D) + return callD1(ci, a); + else + return callI1(ci, a); + } + if (op == LIR_retd) + return out->ins1(op, split(a)); + return out->ins1(op, a); + } + + LIns* SoftFloatFilter::ins2(LOpcode op, LIns *a, LIns *b) { + const CallInfo *ci = softFloatOps.opmap[op]; + if (ci) { + if (isCmpDOpcode(op)) + return cmpD(ci, a, b); + return callD2(ci, a, b); + } + return out->ins2(op, a, b); + } + + LIns* SoftFloatFilter::insCall(const CallInfo *ci, LIns* args[]) { + uint32_t nArgs = ci->count_args(); + for (uint32_t i = 0; i < nArgs; i++) + args[i] = split(args[i]); + + if (ci->returnType() == ARGTYPE_D) { + // This function returns a double as two 32bit values, so replace + // call with qjoin(qhi(call), call). + return split(ci, args); + } + return out->insCall(ci, args); + } +#endif // NJ_SOFTFLOAT_SUPPORTED + + + #endif /* FEATURE_NANOJIT */ + +#if defined(NJ_VERBOSE) + AddrNameMap::AddrNameMap(Allocator& a) + : allocator(a), names(a) + {} + + void AddrNameMap::addAddrRange(const void *p, size_t size, size_t align, const char *name) + { + if (!this || names.containsKey(p)) + return; + char* copy = new (allocator) char[VMPI_strlen(name)+1]; + VMPI_strcpy(copy, name); + Entry *e = new (allocator) Entry(copy, size << align, align); + names.put(p, e); + } + + void AddrNameMap::lookupAddr(void *p, char*& name, int32_t& offset) + { + const void *start = names.findNear(p); + if (start) { + Entry *e = names.get(start); + const void *end = (const char*)start + e->size; + if (p == start) { + name = e->name; + offset = 0; + } + else if (p > start && p < end) { + name = e->name; + offset = int32_t(intptr_t(p)-intptr_t(start)) >> e->align; + } + else { + name = NULL; + offset = 0; + } + } else { + name = NULL; + offset = 0; + } + } + + // --------------------------------------------------------------- + // START debug-logging definitions + // --------------------------------------------------------------- + + void LogControl::printf( const char* format, ... ) + { + va_list vargs; + va_start(vargs, format); + vfprintf(stdout, format, vargs); + va_end(vargs); + // Flush every line immediately so that if crashes occur in generated + // code we won't lose any output. + fflush(stdout); + } + +#endif // NJ_VERBOSE + + +#ifdef FEATURE_NANOJIT +#ifdef DEBUG + const char* ValidateWriter::type2string(LTy type) + { + switch (type) { + case LTy_V: return "void"; + case LTy_I: return "int"; +#ifdef NANOJIT_64BIT + case LTy_Q: return "quad"; +#endif + case LTy_D: return "double"; + default: NanoAssert(0); return "???"; + } + } + + void ValidateWriter::typeCheckArgs(LOpcode op, int nArgs, LTy formals[], LIns* args[]) + { + NanoAssert(nArgs >= 0); + + // Type-check the arguments. + for (int i = 0; i < nArgs; i++) { + LTy formal = formals[i]; + LTy actual = args[i]->retType(); + if (formal != actual) { + // Assert on a type error. The disadvantage of doing this (as + // opposed to printing a message and continuing) is that at + // most one type error will be detected per run. But type + // errors should be rare, and assertion failures are certain + // to be caught by test suites whereas error messages may not + // be. + NanoAssertMsgf(0, + "LIR type error (%s): arg %d of '%s' is '%s' " + "which has type %s (expected %s)", + whereInPipeline, i+1, lirNames[op], + lirNames[args[i]->opcode()], + type2string(actual), type2string(formal)); + } + } + } + + void ValidateWriter::errorStructureShouldBe(LOpcode op, const char* argDesc, int argN, + LIns* arg, const char* shouldBeDesc) + { + NanoAssertMsgf(0, + "LIR structure error (%s): %s %d of '%s' is '%s' (expected %s)", + whereInPipeline, argDesc, argN, + lirNames[op], lirNames[arg->opcode()], shouldBeDesc); + } + + void ValidateWriter::errorAccSet(const char* what, AccSet accSet, const char* shouldDesc) + { + RefBuf b; + NanoAssertMsgf(0, + "LIR AccSet error (%s): '%s' AccSet is '%s'; %s", + whereInPipeline, what, printer->formatAccSet(&b, accSet), shouldDesc); + } + + void ValidateWriter::errorLoadQual(const char* what, LoadQual loadQual) + { + NanoAssertMsgf(0, + "LIR LoadQual error (%s): '%s' loadQual is '%d'", + whereInPipeline, what, loadQual); + } + + void ValidateWriter::checkLInsIsACondOrConst(LOpcode op, int argN, LIns* ins) + { + // We could introduce a LTy_B32 type in the type system but that's a + // bit weird because its representation is identical to LTy_I. It's + // easier to just do this check structurally. Also, optimization can + // cause the condition to become a LIR_immi. + if (!ins->isCmp() && !ins->isImmI()) + errorStructureShouldBe(op, "argument", argN, ins, "a condition or 32-bit constant"); + } + + void ValidateWriter::checkLInsIsNull(LOpcode op, int argN, LIns* ins) + { + if (ins) + errorStructureShouldBe(op, "argument", argN, ins, NULL); + } + + void ValidateWriter::checkLInsHasOpcode(LOpcode op, int argN, LIns* ins, LOpcode op2) + { + if (!ins->isop(op2)) + errorStructureShouldBe(op, "argument", argN, ins, lirNames[op2]); + } + + ValidateWriter::ValidateWriter(LirWriter *out, LInsPrinter* printer, const char* where) + : LirWriter(out), printer(printer), whereInPipeline(where), + checkAccSetExtras(0) + {} + + LIns* ValidateWriter::insLoad(LOpcode op, LIns* base, int32_t d, AccSet accSet, + LoadQual loadQual) + { + checkAccSet(op, base, d, accSet); + + switch (loadQual) { + case LOAD_CONST: + case LOAD_NORMAL: + case LOAD_VOLATILE: + break; + default: + errorLoadQual(lirNames[op], loadQual); + break; + } + + + int nArgs = 1; + LTy formals[1] = { LTy_P }; + LIns* args[1] = { base }; + + switch (op) { + case LIR_ldi: + case LIR_ldd: + case LIR_lduc2ui: + case LIR_ldus2ui: + case LIR_ldc2i: + case LIR_lds2i: + case LIR_ldf2d: + CASE64(LIR_ldq:) + break; + default: + NanoAssert(0); + } + + typeCheckArgs(op, nArgs, formals, args); + + return out->insLoad(op, base, d, accSet, loadQual); + } + + LIns* ValidateWriter::insStore(LOpcode op, LIns* value, LIns* base, int32_t d, AccSet accSet) + { + checkAccSet(op, base, d, accSet); + + int nArgs = 2; + LTy formals[2] = { LTy_V, LTy_P }; // LTy_V is overwritten shortly + LIns* args[2] = { value, base }; + + switch (op) { + case LIR_sti2c: + case LIR_sti2s: + case LIR_sti: + formals[0] = LTy_I; + break; + +#ifdef NANOJIT_64BIT + case LIR_stq: + formals[0] = LTy_Q; + break; +#endif + + case LIR_std: + case LIR_std2f: + formals[0] = LTy_D; + break; + + default: + NanoAssert(0); + } + + typeCheckArgs(op, nArgs, formals, args); + + return out->insStore(op, value, base, d, accSet); + } + + LIns* ValidateWriter::ins0(LOpcode op) + { + switch (op) { + case LIR_start: + case LIR_regfence: + case LIR_label: + break; + default: + NanoAssert(0); + } + + // No args to type-check. + + return out->ins0(op); + } + + LIns* ValidateWriter::ins1(LOpcode op, LIns* a) + { + int nArgs = 1; + LTy formals[1]; + LIns* args[1] = { a }; + + switch (op) { + case LIR_negi: + case LIR_noti: + case LIR_i2d: + case LIR_ui2d: + case LIR_livei: + case LIR_reti: + formals[0] = LTy_I; + break; + +#ifdef NANOJIT_64BIT + case LIR_i2q: + case LIR_ui2uq: + formals[0] = LTy_I; + break; + + case LIR_q2i: + case LIR_qasd: + case LIR_retq: + case LIR_liveq: + formals[0] = LTy_Q; + break; +#endif + +#if defined NANOJIT_IA32 || defined NANOJIT_X64 + case LIR_modi: // see LIRopcode.tbl for why 'mod' is unary + checkLInsHasOpcode(op, 1, a, LIR_divi); + formals[0] = LTy_I; + break; +#endif + +#if NJ_SOFTFLOAT_SUPPORTED + case LIR_dlo2i: + case LIR_dhi2i: + formals[0] = LTy_D; + break; + + case LIR_hcalli: + // The operand of a LIR_hcalli is LIR_calli, even though the + // function being called has a return type of LTy_D. + checkLInsHasOpcode(op, 1, a, LIR_calli); + formals[0] = LTy_I; + break; +#endif + + case LIR_negd: + case LIR_retd: + case LIR_lived: + case LIR_d2i: + CASE64(LIR_dasq:) + formals[0] = LTy_D; + break; + + case LIR_file: + case LIR_line: + // These will never get hit since VTUNE implies !DEBUG. Ignore for the moment. + nArgs = 0; + break; + + default: + NanoAssertMsgf(0, "%s\n", lirNames[op]); + } + + typeCheckArgs(op, nArgs, formals, args); + + return out->ins1(op, a); + } + + LIns* ValidateWriter::ins2(LOpcode op, LIns* a, LIns* b) + { + int nArgs = 2; + LTy formals[2]; + LIns* args[2] = { a, b }; + + switch (op) { + case LIR_addi: + case LIR_subi: + case LIR_muli: + CASE86(LIR_divi:) + case LIR_andi: + case LIR_ori: + case LIR_xori: + case LIR_lshi: + case LIR_rshi: + case LIR_rshui: + case LIR_eqi: + case LIR_lti: + case LIR_gti: + case LIR_lei: + case LIR_gei: + case LIR_ltui: + case LIR_gtui: + case LIR_leui: + case LIR_geui: + formals[0] = LTy_I; + formals[1] = LTy_I; + break; + +#if NJ_SOFTFLOAT_SUPPORTED + case LIR_ii2d: + formals[0] = LTy_I; + formals[1] = LTy_I; + break; +#endif + +#ifdef NANOJIT_64BIT + case LIR_andq: + case LIR_orq: + case LIR_xorq: + case LIR_addq: + case LIR_subq: + case LIR_eqq: + case LIR_ltq: + case LIR_gtq: + case LIR_leq: + case LIR_geq: + case LIR_ltuq: + case LIR_gtuq: + case LIR_leuq: + case LIR_geuq: + formals[0] = LTy_Q; + formals[1] = LTy_Q; + break; + + case LIR_lshq: + case LIR_rshq: + case LIR_rshuq: + formals[0] = LTy_Q; + formals[1] = LTy_I; + break; +#endif + + case LIR_addd: + case LIR_subd: + case LIR_muld: + case LIR_divd: + case LIR_eqd: + case LIR_gtd: + case LIR_ltd: + case LIR_led: + case LIR_ged: + formals[0] = LTy_D; + formals[1] = LTy_D; + break; + + default: + NanoAssert(0); + } + + typeCheckArgs(op, nArgs, formals, args); + + return out->ins2(op, a, b); + } + + LIns* ValidateWriter::ins3(LOpcode op, LIns* a, LIns* b, LIns* c) + { + int nArgs = 3; + LTy formals[3] = { LTy_I, LTy_V, LTy_V }; // LTy_V gets overwritten + LIns* args[3] = { a, b, c }; + + switch (op) { + case LIR_cmovi: + checkLInsIsACondOrConst(op, 1, a); + formals[1] = LTy_I; + formals[2] = LTy_I; + break; + +#ifdef NANOJIT_64BIT + case LIR_cmovq: + checkLInsIsACondOrConst(op, 1, a); + formals[1] = LTy_Q; + formals[2] = LTy_Q; + break; +#endif + + case LIR_cmovd: + checkLInsIsACondOrConst(op, 1, a); + formals[1] = LTy_D; + formals[2] = LTy_D; + break; + + default: + NanoAssert(0); + } + + typeCheckArgs(op, nArgs, formals, args); + + return out->ins3(op, a, b, c); + } + + LIns* ValidateWriter::insParam(int32_t arg, int32_t kind) + { + return out->insParam(arg, kind); + } + + LIns* ValidateWriter::insImmI(int32_t imm) + { + return out->insImmI(imm); + } + +#ifdef NANOJIT_64BIT + LIns* ValidateWriter::insImmQ(uint64_t imm) + { + return out->insImmQ(imm); + } +#endif + + LIns* ValidateWriter::insImmD(double d) + { + return out->insImmD(d); + } + + static const char* argtypeNames[] = { + "void", // ARGTYPE_V = 0 + "int32_t", // ARGTYPE_I = 1 + "uint32_t", // ARGTYPE_UI = 2 + "uint64_t", // ARGTYPE_Q = 3 + "double" // ARGTYPE_D = 4 + }; + + LIns* ValidateWriter::insCall(const CallInfo *ci, LIns* args0[]) + { + ArgType argTypes[MAXARGS]; + uint32_t nArgs = ci->getArgTypes(argTypes); + LTy formals[MAXARGS]; + LIns* args[MAXARGS]; // in left-to-right order, unlike args0[] + + LOpcode op = getCallOpcode(ci); + ArgType retType = ci->returnType(); + + if ((op == LIR_callv) != (retType == ARGTYPE_V) || + (op == LIR_calli) != (retType == ARGTYPE_UI || + retType == ARGTYPE_I) || +#ifdef NANOJIT_64BIT + (op == LIR_callq) != (retType == ARGTYPE_Q) || +#endif + (op == LIR_calld) != (retType == ARGTYPE_D)) { + NanoAssertMsgf(0, + "LIR structure error (%s): return type mismatch: opcode %s with %s return type", + whereInPipeline, lirNames[op], argtypeNames[retType]); + } + + if (op == LIR_callv && ci->_isPure) { + // Since nobody can use the result of a void call, any pure call + // would just be dead. This is probably a mistake. + NanoAssertMsgf(0, + "LIR structure error (%s): LIR_callv must only be used with nonpure functions.", + whereInPipeline); + } + + if (ci->_isPure && ci->_storeAccSet != ACCSET_NONE) + errorAccSet(ci->_name, ci->_storeAccSet, "it should be ACCSET_NONE for pure functions"); + + // This loop iterates over the args from right-to-left (because arg() + // and getArgTypes() use right-to-left order), but puts the results + // into formals[] and args[] in left-to-right order so that arg + // numbers in error messages make sense to the user. + for (uint32_t i = 0; i < nArgs; i++) { + uint32_t i2 = nArgs - i - 1; // converts right-to-left to left-to-right + switch (argTypes[i]) { + case ARGTYPE_I: + case ARGTYPE_UI: formals[i2] = LTy_I; break; +#ifdef NANOJIT_64BIT + case ARGTYPE_Q: formals[i2] = LTy_Q; break; +#endif + case ARGTYPE_D: formals[i2] = LTy_D; break; + default: NanoAssertMsgf(0, "%d %s\n", argTypes[i],ci->_name); formals[i2] = LTy_V; break; + } + args[i2] = args0[i]; + } + + typeCheckArgs(op, nArgs, formals, args); + + return out->insCall(ci, args0); + } + + LIns* ValidateWriter::insGuard(LOpcode op, LIns *cond, GuardRecord *gr) + { + int nArgs = -1; // init to shut compilers up + LTy formals[1]; + LIns* args[1]; + + switch (op) { + case LIR_x: + case LIR_xbarrier: + checkLInsIsNull(op, 1, cond); + nArgs = 0; + break; + + case LIR_xt: + case LIR_xf: + checkLInsIsACondOrConst(op, 1, cond); + nArgs = 1; + formals[0] = LTy_I; + args[0] = cond; + break; + + case LIR_xtbl: + nArgs = 1; + formals[0] = LTy_I; // unlike xt/xf/jt/jf, this is an index, not a condition + args[0] = cond; + break; + + default: + NanoAssert(0); + } + + typeCheckArgs(op, nArgs, formals, args); + + return out->insGuard(op, cond, gr); + } + + LIns* ValidateWriter::insGuardXov(LOpcode op, LIns* a, LIns* b, GuardRecord* gr) + { + int nArgs = 2; + LTy formals[2] = { LTy_I, LTy_I }; + LIns* args[2] = { a, b }; + + switch (op) { + case LIR_addxovi: + case LIR_subxovi: + case LIR_mulxovi: + break; + + default: + NanoAssert(0); + } + + typeCheckArgs(op, nArgs, formals, args); + + return out->insGuardXov(op, a, b, gr); + } + + LIns* ValidateWriter::insBranch(LOpcode op, LIns* cond, LIns* to) + { + int nArgs = -1; // init to shut compilers up + LTy formals[1]; + LIns* args[1]; + + switch (op) { + case LIR_j: + checkLInsIsNull(op, 1, cond); + nArgs = 0; + break; + + case LIR_jt: + case LIR_jf: + checkLInsIsACondOrConst(op, 1, cond); + nArgs = 1; + formals[0] = LTy_I; + args[0] = cond; + break; + + default: + NanoAssert(0); + } + + // We check that target is a label in ValidateReader because it may + // not have been set here. + + typeCheckArgs(op, nArgs, formals, args); + + return out->insBranch(op, cond, to); + } + + LIns* ValidateWriter::insBranchJov(LOpcode op, LIns* a, LIns* b, LIns* to) + { + int nArgs = 2; + LTy formals[2]; + LIns* args[2] = { a, b }; + + switch (op) { + case LIR_addjovi: + case LIR_subjovi: + case LIR_muljovi: + formals[0] = LTy_I; + formals[1] = LTy_I; + break; + +#ifdef NANOJIT_64BIT + case LIR_addjovq: + case LIR_subjovq: + formals[0] = LTy_Q; + formals[1] = LTy_Q; + break; +#endif + default: + NanoAssert(0); + } + + // We check that target is a label in ValidateReader because it may + // not have been set here. + + typeCheckArgs(op, nArgs, formals, args); + + return out->insBranchJov(op, a, b, to); + } + + LIns* ValidateWriter::insAlloc(int32_t size) + { + return out->insAlloc(size); + } + + LIns* ValidateWriter::insJtbl(LIns* index, uint32_t size) + { + int nArgs = 1; + LTy formals[1] = { LTy_I }; + LIns* args[1] = { index }; + + typeCheckArgs(LIR_jtbl, nArgs, formals, args); + + // We check that all jump table entries are labels in ValidateReader + // because they won't have been set here. + + return out->insJtbl(index, size); + } + + ValidateReader::ValidateReader(LirFilter* in) : LirFilter(in) + {} + + LIns* ValidateReader::read() + { + LIns *ins = in->read(); + switch (ins->opcode()) { + case LIR_jt: + case LIR_jf: + case LIR_j: + NanoAssert(ins->getTarget() && ins->oprnd2()->isop(LIR_label)); + break; + + case LIR_addjovi: + case LIR_subjovi: + case LIR_muljovi: + CASE64(LIR_addjovq:) + CASE64(LIR_subjovq:) + NanoAssert(ins->getTarget() && ins->oprnd3()->isop(LIR_label)); + break; + + case LIR_jtbl: { + uint32_t tableSize = ins->getTableSize(); + NanoAssert(tableSize > 0); + for (uint32_t i = 0; i < tableSize; i++) { + LIns* target = ins->getTarget(i); + NanoAssert(target); + NanoAssert(target->isop(LIR_label)); + } + break; + } + default: + ; + } + return ins; + } + +#endif +#endif + +} diff --git a/js/src/nanojit/LIR.h b/js/src/nanojit/LIR.h new file mode 100644 index 0000000..4d6f03f --- /dev/null +++ b/js/src/nanojit/LIR.h @@ -0,0 +1,2443 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __nanojit_LIR__ +#define __nanojit_LIR__ + +namespace nanojit +{ + enum LOpcode +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#pragma warning(disable:4480) // nonstandard extension used: specifying underlying type for enum + : unsigned +#endif + { +#define OP___(op, number, repKind, retType, isCse) \ + LIR_##op = (number), +#include "LIRopcode.tbl" + LIR_sentinel, +#undef OP___ + +#ifdef NANOJIT_64BIT +# define PTR_SIZE(a,b) b +#else +# define PTR_SIZE(a,b) a +#endif + + // Pointer-sized synonyms. + + LIR_paramp = PTR_SIZE(LIR_parami, LIR_paramq), + + LIR_retp = PTR_SIZE(LIR_reti, LIR_retq), + + LIR_livep = PTR_SIZE(LIR_livei, LIR_liveq), + + LIR_ldp = PTR_SIZE(LIR_ldi, LIR_ldq), + + LIR_stp = PTR_SIZE(LIR_sti, LIR_stq), + + LIR_callp = PTR_SIZE(LIR_calli, LIR_callq), + + LIR_eqp = PTR_SIZE(LIR_eqi, LIR_eqq), + LIR_ltp = PTR_SIZE(LIR_lti, LIR_ltq), + LIR_gtp = PTR_SIZE(LIR_gti, LIR_gtq), + LIR_lep = PTR_SIZE(LIR_lei, LIR_leq), + LIR_gep = PTR_SIZE(LIR_gei, LIR_geq), + LIR_ltup = PTR_SIZE(LIR_ltui, LIR_ltuq), + LIR_gtup = PTR_SIZE(LIR_gtui, LIR_gtuq), + LIR_leup = PTR_SIZE(LIR_leui, LIR_leuq), + LIR_geup = PTR_SIZE(LIR_geui, LIR_geuq), + + LIR_addp = PTR_SIZE(LIR_addi, LIR_addq), + LIR_subp = PTR_SIZE(LIR_subi, LIR_subq), + LIR_addjovp = PTR_SIZE(LIR_addjovi, LIR_addjovq), + + LIR_andp = PTR_SIZE(LIR_andi, LIR_andq), + LIR_orp = PTR_SIZE(LIR_ori, LIR_orq), + LIR_xorp = PTR_SIZE(LIR_xori, LIR_xorq), + + LIR_lshp = PTR_SIZE(LIR_lshi, LIR_lshq), + LIR_rshp = PTR_SIZE(LIR_rshi, LIR_rshq), + LIR_rshup = PTR_SIZE(LIR_rshui, LIR_rshuq), + + LIR_cmovp = PTR_SIZE(LIR_cmovi, LIR_cmovq) + }; + + // 32-bit integer comparisons must be contiguous, as must 64-bit integer + // comparisons and 64-bit float comparisons. + NanoStaticAssert(LIR_eqi + 1 == LIR_lti && + LIR_eqi + 2 == LIR_gti && + LIR_eqi + 3 == LIR_lei && + LIR_eqi + 4 == LIR_gei && + LIR_eqi + 5 == LIR_ltui && + LIR_eqi + 6 == LIR_gtui && + LIR_eqi + 7 == LIR_leui && + LIR_eqi + 8 == LIR_geui); +#ifdef NANOJIT_64BIT + NanoStaticAssert(LIR_eqq + 1 == LIR_ltq && + LIR_eqq + 2 == LIR_gtq && + LIR_eqq + 3 == LIR_leq && + LIR_eqq + 4 == LIR_geq && + LIR_eqq + 5 == LIR_ltuq && + LIR_eqq + 6 == LIR_gtuq && + LIR_eqq + 7 == LIR_leuq && + LIR_eqq + 8 == LIR_geuq); +#endif + NanoStaticAssert(LIR_eqd + 1 == LIR_ltd && + LIR_eqd + 2 == LIR_gtd && + LIR_eqd + 3 == LIR_led && + LIR_eqd + 4 == LIR_ged); + + // Various opcodes must be changeable to their opposite with op^1 + // (although we use invertXyz() when possible, ie. outside static + // assertions). + NanoStaticAssert((LIR_jt^1) == LIR_jf && (LIR_jf^1) == LIR_jt); + + NanoStaticAssert((LIR_xt^1) == LIR_xf && (LIR_xf^1) == LIR_xt); + + NanoStaticAssert((LIR_lti^1) == LIR_gti && (LIR_gti^1) == LIR_lti); + NanoStaticAssert((LIR_lei^1) == LIR_gei && (LIR_gei^1) == LIR_lei); + NanoStaticAssert((LIR_ltui^1) == LIR_gtui && (LIR_gtui^1) == LIR_ltui); + NanoStaticAssert((LIR_leui^1) == LIR_geui && (LIR_geui^1) == LIR_leui); + +#ifdef NANOJIT_64BIT + NanoStaticAssert((LIR_ltq^1) == LIR_gtq && (LIR_gtq^1) == LIR_ltq); + NanoStaticAssert((LIR_leq^1) == LIR_geq && (LIR_geq^1) == LIR_leq); + NanoStaticAssert((LIR_ltuq^1) == LIR_gtuq && (LIR_gtuq^1) == LIR_ltuq); + NanoStaticAssert((LIR_leuq^1) == LIR_geuq && (LIR_geuq^1) == LIR_leuq); +#endif + + NanoStaticAssert((LIR_ltd^1) == LIR_gtd && (LIR_gtd^1) == LIR_ltd); + NanoStaticAssert((LIR_led^1) == LIR_ged && (LIR_ged^1) == LIR_led); + + + struct GuardRecord; + struct SideExit; + + enum AbiKind { + ABI_FASTCALL, + ABI_THISCALL, + ABI_STDCALL, + ABI_CDECL + }; + + // This is much the same as LTy, but we need to distinguish signed and + // unsigned 32-bit ints so that they will be extended to 64-bits correctly + // on 64-bit platforms. + // + // All values must fit into three bits. See CallInfo for details. + enum ArgType { + ARGTYPE_V = 0, // void + ARGTYPE_I = 1, // int32_t + ARGTYPE_UI = 2, // uint32_t +#ifdef NANOJIT_64BIT + ARGTYPE_Q = 3, // uint64_t +#endif + ARGTYPE_D = 4, // double + + // aliases + ARGTYPE_P = PTR_SIZE(ARGTYPE_I, ARGTYPE_Q), // pointer + ARGTYPE_B = ARGTYPE_I // bool + }; + + enum IndirectCall { + CALL_INDIRECT = 0 + }; + + //----------------------------------------------------------------------- + // Aliasing + // -------- + // *Aliasing* occurs when a single memory location can be accessed through + // multiple names. For example, consider this code: + // + // ld a[0] + // sti b[0] + // ld a[0] + // + // In general, it's possible that a[0] and b[0] may refer to the same + // memory location. This means, for example, that you cannot safely + // perform CSE on the two loads. However, if you know that 'a' cannot be + // an alias of 'b' (ie. the two loads do not alias with the store) then + // you can safely perform CSE. + // + // Access regions + // -------------- + // Doing alias analysis precisely is difficult. But it turns out that + // keeping track of aliasing at a coarse level is enough to help with many + // optimisations. So we conceptually divide the memory that is accessible + // from LIR into a small number of "access regions" (aka. "Acc"). An + // access region may be non-contiguous. No two access regions can + // overlap. The union of all access regions covers all memory accessible + // from LIR. + // + // In general a (static) load or store may be executed more than once, and + // thus may access multiple regions; however, in practice almost all + // loads and stores will obviously access only a single region. A + // function called from LIR may load and/or store multiple access regions + // (even if executed only once). + // + // If two loads/stores/calls are known to not access the same region(s), + // then they do not alias. + // + // All regions are defined by the embedding. It makes sense to add new + // embedding-specific access regions when doing so will help with one or + // more optimisations. + // + // Access region sets and instruction markings + // ------------------------------------------- + // Each load/store is marked with an "access region set" (aka. "AccSet"), + // which is a set of one or more access regions. This indicates which + // parts of LIR-accessible memory the load/store may touch. + // + // Each function called from LIR is also marked with an access region set + // for memory stored to by the function. (We could also have a marking + // for memory loads done by the function, but there's no need at the + // moment.) These markings apply to the function itself, not the call + // site, ie. they're not context-sensitive. + // + // These load/store/call markings MUST BE ACCURATE -- if not then invalid + // optimisations might occur that change the meaning of the code. + // However, they can safely be imprecise (ie. conservative), ie. a + // load/store/call can be marked with an access region set that is a + // superset of the actual access region set. Such imprecision is safe but + // may reduce optimisation opportunities. + // + // Optimisations that use access region info + // ----------------------------------------- + // Currently only CseFilter uses this, and only for determining whether + // loads can be CSE'd. Note that CseFilter treats loads that are marked + // with a single access region precisely, but all loads marked with + // multiple access regions get lumped together. So if you can't mark a + // load with a single access region, you might as well use ACC_LOAD_ANY. + //----------------------------------------------------------------------- + + // An access region set is represented as a bitset. Using a uint32_t + // restricts us to at most 32 alias regions for the moment. This could be + // expanded to a uint64_t easily if needed. + typedef uint32_t AccSet; + static const int NUM_ACCS = sizeof(AccSet) * 8; + + // Some common (non-singleton) access region sets. ACCSET_NONE does not make + // sense for loads or stores (which must access at least one region), it + // only makes sense for calls. + // + static const AccSet ACCSET_NONE = 0x0; + static const AccSet ACCSET_ALL = 0xffffffff; + static const AccSet ACCSET_LOAD_ANY = ACCSET_ALL; // synonym + static const AccSet ACCSET_STORE_ANY = ACCSET_ALL; // synonym + + inline bool isSingletonAccSet(AccSet accSet) { + // This is a neat way of testing if a value has only one bit set. + return (accSet & (accSet - 1)) == 0; + } + + // Full AccSets don't fit into load and store instructions. But + // load/store AccSets almost always contain a single access region. We + // take advantage of this to create a compressed AccSet, MiniAccSet, that + // does fit. + // + // The 32 single-region AccSets get compressed into a number in the range + // 0..31 (according to the position of the set bit), and all other + // (multi-region) AccSets get converted into MINI_ACCSET_MULTIPLE. So the + // representation is lossy in the latter case, but that case is rare for + // loads/stores. We use a full AccSet for the storeAccSets of calls, for + // which multi-region AccSets are common. + // + // We wrap the uint8_t inside a struct to avoid the possiblity of subtle + // bugs caused by mixing up AccSet and MiniAccSet, which is easy to do. + // However, the struct gets padded inside LInsLd in an inconsistent way on + // Windows, so we actually store a MiniAccSetVal inside LInsLd. Sigh. + // But we use MiniAccSet everywhere else. + // + typedef uint8_t MiniAccSetVal; + struct MiniAccSet { MiniAccSetVal val; }; + static const MiniAccSet MINI_ACCSET_MULTIPLE = { 99 }; + + static MiniAccSet compressAccSet(AccSet accSet) { + if (isSingletonAccSet(accSet)) { + MiniAccSet ret = { uint8_t(msbSet32(accSet)) }; + return ret; + } + + // If we got here, it must be a multi-region AccSet. + return MINI_ACCSET_MULTIPLE; + } + + static AccSet decompressMiniAccSet(MiniAccSet miniAccSet) { + return (miniAccSet.val == MINI_ACCSET_MULTIPLE.val) ? ACCSET_ALL : (1 << miniAccSet.val); + } + + // The LoadQual affects how a load can be optimised: + // + // - CONST: These loads are guaranteed to always return the same value + // during a single execution of a fragment (but the value is allowed to + // change between executions of the fragment). This means that the + // location is never stored to by the LIR, and is never modified by an + // external entity while the fragment is running. + // + // - NORMAL: These loads may be stored to by the LIR, but are never + // modified by an external entity while the fragment is running. + // + // - VOLATILE: These loads may be stored to by the LIR, and may be + // modified by an external entity while the fragment is running. + // + // This gives a lattice with the ordering: CONST < NORMAL < VOLATILE. + // As usual, it's safe to mark a load with a value higher (less precise) + // that actual, but it may result in fewer optimisations occurring. + // + // Generally CONST loads are highly amenable to optimisation (eg. CSE), + // VOLATILE loads are entirely unoptimisable, and NORMAL loads are in + // between and require some alias analysis to optimise. + // + // Note that CONST has a stronger meaning to "const" in C and C++; in C + // and C++ a "const" variable may be modified by an external entity, such + // as hardware. Hence "const volatile" makes sense in C and C++, but + // CONST+VOLATILE doesn't make sense in LIR. + // + // Note also that a 2-bit bitfield in LInsLd is used to hold LoadQual + // values, so you can one add one more value without expanding it. + // + enum LoadQual { + LOAD_CONST = 0, + LOAD_NORMAL = 1, + LOAD_VOLATILE = 2 + }; + + struct CallInfo + { + private: + // In CallInfo::_typesig, each entry is three bits. + static const int TYPESIG_FIELDSZB = 3; + static const int TYPESIG_FIELDMASK = 7; + + public: + uintptr_t _address; + uint32_t _typesig:27; // 9 3-bit fields indicating arg type, by ARGTYPE above (including ret type): a1 a2 a3 a4 a5 ret + AbiKind _abi:3; + uint32_t _isPure:1; // _isPure=1 means no side-effects, result only depends on args + AccSet _storeAccSet; // access regions stored by the function + verbose_only ( const char* _name; ) + + // The following encode 'r func()' through to 'r func(a1, a2, a3, a4, a5, a6, a7, a8)'. + static inline uint32_t typeSig0(ArgType r) { + return r; + } + static inline uint32_t typeSig1(ArgType r, ArgType a1) { + return a1 << TYPESIG_FIELDSZB*1 | typeSig0(r); + } + static inline uint32_t typeSig2(ArgType r, ArgType a1, ArgType a2) { + return a1 << TYPESIG_FIELDSZB*2 | typeSig1(r, a2); + } + static inline uint32_t typeSig3(ArgType r, ArgType a1, ArgType a2, ArgType a3) { + return a1 << TYPESIG_FIELDSZB*3 | typeSig2(r, a2, a3); + } + static inline uint32_t typeSig4(ArgType r, ArgType a1, ArgType a2, ArgType a3, ArgType a4) { + return a1 << TYPESIG_FIELDSZB*4 | typeSig3(r, a2, a3, a4); + } + static inline uint32_t typeSig5(ArgType r, ArgType a1, ArgType a2, ArgType a3, + ArgType a4, ArgType a5) { + return a1 << TYPESIG_FIELDSZB*5 | typeSig4(r, a2, a3, a4, a5); + } + static inline uint32_t typeSig6(ArgType r, ArgType a1, ArgType a2, ArgType a3, + ArgType a4, ArgType a5, ArgType a6) { + return a1 << TYPESIG_FIELDSZB*6 | typeSig5(r, a2, a3, a4, a5, a6); + } + static inline uint32_t typeSig7(ArgType r, ArgType a1, ArgType a2, ArgType a3, + ArgType a4, ArgType a5, ArgType a6, ArgType a7) { + return a1 << TYPESIG_FIELDSZB*7 | typeSig6(r, a2, a3, a4, a5, a6, a7); + } + static inline uint32_t typeSig8(ArgType r, ArgType a1, ArgType a2, ArgType a3, ArgType a4, + ArgType a5, ArgType a6, ArgType a7, ArgType a8) { + return a1 << TYPESIG_FIELDSZB*8 | typeSig7(r, a2, a3, a4, a5, a6, a7, a8); + } + // Encode 'r func(a1, ..., aN))' + static inline uint32_t typeSigN(ArgType r, int N, ArgType a[]) { + uint32_t typesig = r; + for (int i = 0; i < N; i++) { + typesig |= a[i] << TYPESIG_FIELDSZB*(N-i); + } + return typesig; + } + + uint32_t count_args() const; + uint32_t count_int32_args() const; + // Nb: uses right-to-left order, eg. sizes[0] is the size of the right-most arg. + // XXX: See bug 525815 for fixing this. + uint32_t getArgTypes(ArgType* types) const; + + inline ArgType returnType() const { + return ArgType(_typesig & TYPESIG_FIELDMASK); + } + + inline bool isIndirect() const { + return _address < 256; + } + }; + + /* + * Record for extra data used to compile switches as jump tables. + */ + struct SwitchInfo + { + NIns** table; // Jump table; a jump address is NIns* + uint32_t count; // Number of table entries + // Index value at last execution of the switch. The index value + // is the offset into the jump table. Thus it is computed as + // (switch expression) - (lowest case value). + uint32_t index; + }; + + // Array holding the 'isCse' field from LIRopcode.tbl. + extern const int8_t isCses[]; // cannot be uint8_t, some values are negative + + inline bool isCseOpcode(LOpcode op) { + NanoAssert(isCses[op] != -1); // see LIRopcode.tbl to understand this + return isCses[op] == 1; + } + inline bool isLiveOpcode(LOpcode op) { + return +#if defined NANOJIT_64BIT + op == LIR_liveq || +#endif + op == LIR_livei || op == LIR_lived; + } + inline bool isRetOpcode(LOpcode op) { + return +#if defined NANOJIT_64BIT + op == LIR_retq || +#endif + op == LIR_reti || op == LIR_retd; + } + inline bool isCmovOpcode(LOpcode op) { + return +#if defined NANOJIT_64BIT + op == LIR_cmovq || +#endif + op == LIR_cmovi || + op == LIR_cmovd; + } + inline bool isCmpIOpcode(LOpcode op) { + return LIR_eqi <= op && op <= LIR_geui; + } + inline bool isCmpSIOpcode(LOpcode op) { + return LIR_eqi <= op && op <= LIR_gei; + } + inline bool isCmpUIOpcode(LOpcode op) { + return LIR_eqi == op || (LIR_ltui <= op && op <= LIR_geui); + } +#ifdef NANOJIT_64BIT + inline bool isCmpQOpcode(LOpcode op) { + return LIR_eqq <= op && op <= LIR_geuq; + } + inline bool isCmpSQOpcode(LOpcode op) { + return LIR_eqq <= op && op <= LIR_geq; + } + inline bool isCmpUQOpcode(LOpcode op) { + return LIR_eqq == op || (LIR_ltuq <= op && op <= LIR_geuq); + } +#endif + inline bool isCmpDOpcode(LOpcode op) { + return LIR_eqd <= op && op <= LIR_ged; + } + inline bool isCmpOpcode(LOpcode op) { + return isCmpIOpcode(op) || +#if defined NANOJIT_64BIT + isCmpQOpcode(op) || +#endif + isCmpDOpcode(op); + } + + inline LOpcode invertCondJmpOpcode(LOpcode op) { + NanoAssert(op == LIR_jt || op == LIR_jf); + return LOpcode(op ^ 1); + } + inline LOpcode invertCondGuardOpcode(LOpcode op) { + NanoAssert(op == LIR_xt || op == LIR_xf); + return LOpcode(op ^ 1); + } + inline LOpcode invertCmpOpcode(LOpcode op) { + NanoAssert(isCmpOpcode(op)); + return LOpcode(op ^ 1); + } + + inline LOpcode getCallOpcode(const CallInfo* ci) { + LOpcode op = LIR_callp; + switch (ci->returnType()) { + case ARGTYPE_V: op = LIR_callv; break; + case ARGTYPE_I: + case ARGTYPE_UI: op = LIR_calli; break; +#ifdef NANOJIT_64BIT + case ARGTYPE_Q: op = LIR_callq; break; +#endif + case ARGTYPE_D: op = LIR_calld; break; + default: NanoAssert(0); break; + } + return op; + } + + LOpcode arithOpcodeD2I(LOpcode op); +#ifdef NANOJIT_64BIT + LOpcode cmpOpcodeI2Q(LOpcode op); +#endif + LOpcode cmpOpcodeD2I(LOpcode op); + LOpcode cmpOpcodeD2UI(LOpcode op); + + // Array holding the 'repKind' field from LIRopcode.tbl. + extern const uint8_t repKinds[]; + + enum LTy { + LTy_V, // void: no value/no type + LTy_I, // int: 32-bit integer +#ifdef NANOJIT_64BIT + LTy_Q, // quad: 64-bit integer +#endif + LTy_D, // double: 64-bit float + + LTy_P = PTR_SIZE(LTy_I, LTy_Q) // word-sized integer + }; + + // Array holding the 'retType' field from LIRopcode.tbl. + extern const LTy retTypes[]; + + inline RegisterMask rmask(Register r) + { + return RegisterMask(1) << REGNUM(r); + } + + //----------------------------------------------------------------------- + // Low-level instructions. This is a bit complicated, because we have a + // variable-width representation to minimise space usage. + // + // - Instruction size is always an integral multiple of word size. + // + // - Every instruction has at least one word, holding the opcode and the + // reservation info ("SharedFields"). That word is in class LIns. + // + // - Beyond that, most instructions have 1, 2 or 3 extra words. These + // extra words are in classes LInsOp1, LInsOp2, etc (collectively called + // "LInsXYZ" in what follows). Each LInsXYZ class also contains an LIns, + // accessible by the 'ins' member, which holds the LIns data. + // + // - LIR is written forward, but read backwards. When reading backwards, + // in order to find the opcode, it must be in a predictable place in the + // LInsXYZ isn't affected by instruction width. Therefore, the LIns + // word (which contains the opcode) is always the *last* word in an + // instruction. + // + // - Each instruction is created by casting pre-allocated bytes from a + // LirBuffer to the LInsXYZ type. Therefore there are no constructors + // for LIns or LInsXYZ. + // + // - The standard handle for an instruction is a LIns*. This actually + // points to the LIns word, ie. to the final word in the instruction. + // This is a bit odd, but it allows the instruction's opcode to be + // easily accessed. Once you've looked at the opcode and know what kind + // of instruction it is, if you want to access any of the other words, + // you need to use toLInsXYZ(), which takes the LIns* and gives you an + // LInsXYZ*, ie. the pointer to the actual start of the instruction's + // bytes. From there you can access the instruction-specific extra + // words. + // + // - However, from outside class LIns, LInsXYZ isn't visible, nor is + // toLInsXYZ() -- from outside LIns, all LIR instructions are handled + // via LIns pointers and get/set methods are used for all LIns/LInsXYZ + // accesses. In fact, all data members in LInsXYZ are private and can + // only be accessed by LIns, which is a friend class. The only thing + // anyone outside LIns can do with a LInsXYZ is call getLIns(). + // + // - An example Op2 instruction and the likely pointers to it (each line + // represents a word, and pointers to a line point to the start of the + // word on that line): + // + // [ oprnd_2 <-- LInsOp2* insOp2 == toLInsOp2(ins) + // oprnd_1 + // opcode + resv ] <-- LIns* ins + // + // - LIR_skip instructions are used to link code chunks. If the first + // instruction on a chunk isn't a LIR_start, it will be a skip, and the + // skip's operand will point to the last LIns on the preceding chunk. + // LInsSk has the same layout as LInsOp1, but we represent it as a + // different class because there are some places where we treat + // skips specially and so having it separate seems like a good idea. + // + // - Various things about the size and layout of LIns and LInsXYZ are + // statically checked in staticSanityCheck(). In particular, this is + // worthwhile because there's nothing that guarantees that all the + // LInsXYZ classes have a size that is a multiple of word size (but in + // practice all sane compilers use a layout that results in this). We + // also check that every LInsXYZ is word-aligned in + // LirBuffer::makeRoom(); this seems sensible to avoid potential + // slowdowns due to misalignment. It relies on chunks themselves being + // word-aligned, which is extremely likely. + // + // - There is an enum, LInsRepKind, with one member for each of the + // LInsXYZ kinds. Each opcode is categorised with its LInsRepKind value + // in LIRopcode.tbl, and this is used in various places. + //----------------------------------------------------------------------- + + enum LInsRepKind { + // LRK_XYZ corresponds to class LInsXYZ. + LRK_Op0, + LRK_Op1, + LRK_Op2, + LRK_Op3, + LRK_Ld, + LRK_St, + LRK_Sk, + LRK_C, + LRK_P, + LRK_I, + LRK_QorD, + LRK_Jtbl, + LRK_None // this one is used for unused opcode numbers + }; + + class LInsOp0; + class LInsOp1; + class LInsOp2; + class LInsOp3; + class LInsLd; + class LInsSt; + class LInsSk; + class LInsC; + class LInsP; + class LInsI; + class LInsQorD; + class LInsJtbl; + + class LIns + { + private: + // SharedFields: fields shared by all LIns kinds. + // + // The .inReg, .regnum, .inAr and .arIndex fields form a "reservation" + // that is used temporarily during assembly to record information + // relating to register allocation. See class RegAlloc for more + // details. Note: all combinations of .inReg/.inAr are possible, ie. + // 0/0, 0/1, 1/0, 1/1. + // + // The .isResultLive field is only used for instructions that return + // results. It indicates if the result is live. It's set (if + // appropriate) and used only during the codegen pass. + // + struct SharedFields { + uint32_t inReg:1; // if 1, 'reg' is active + uint32_t regnum:7; + uint32_t inAr:1; // if 1, 'arIndex' is active + uint32_t isResultLive:1; // if 1, the instruction's result is live + + uint32_t arIndex:14; // index into stack frame; displ is -4*arIndex + + LOpcode opcode:8; // instruction's opcode + }; + + union { + SharedFields sharedFields; + // Force sizeof(LIns)==8 and 8-byte alignment on 64-bit machines. + // This is necessary because sizeof(SharedFields)==4 and we want all + // instances of LIns to be pointer-aligned. + void* wholeWord; + }; + + inline void initSharedFields(LOpcode opcode) + { + // We must zero .inReg, .inAR and .isResultLive, but zeroing the + // whole word is easier. Then we set the opcode. + wholeWord = 0; + sharedFields.opcode = opcode; + } + + // LIns-to-LInsXYZ converters. + inline LInsOp0* toLInsOp0() const; + inline LInsOp1* toLInsOp1() const; + inline LInsOp2* toLInsOp2() const; + inline LInsOp3* toLInsOp3() const; + inline LInsLd* toLInsLd() const; + inline LInsSt* toLInsSt() const; + inline LInsSk* toLInsSk() const; + inline LInsC* toLInsC() const; + inline LInsP* toLInsP() const; + inline LInsI* toLInsI() const; + inline LInsQorD* toLInsQorD() const; + inline LInsJtbl*toLInsJtbl()const; + + void staticSanityCheck(); + + public: + // LIns initializers. + inline void initLInsOp0(LOpcode opcode); + inline void initLInsOp1(LOpcode opcode, LIns* oprnd1); + inline void initLInsOp2(LOpcode opcode, LIns* oprnd1, LIns* oprnd2); + inline void initLInsOp3(LOpcode opcode, LIns* oprnd1, LIns* oprnd2, LIns* oprnd3); + inline void initLInsLd(LOpcode opcode, LIns* val, int32_t d, AccSet accSet, LoadQual loadQual); + inline void initLInsSt(LOpcode opcode, LIns* val, LIns* base, int32_t d, AccSet accSet); + inline void initLInsSk(LIns* prevLIns); + // Nb: args[] must be allocated and initialised before being passed in; + // initLInsC() just copies the pointer into the LInsC. + inline void initLInsC(LOpcode opcode, LIns** args, const CallInfo* ci); + inline void initLInsP(int32_t arg, int32_t kind); + inline void initLInsI(LOpcode opcode, int32_t immI); + inline void initLInsQorD(LOpcode opcode, uint64_t immQorD); + inline void initLInsJtbl(LIns* index, uint32_t size, LIns** table); + + LOpcode opcode() const { return sharedFields.opcode; } + + // Generally, void instructions (statements) are always live and + // non-void instructions (expressions) are live if used by another + // live instruction. But there are some trickier cases. + // Any non-void instruction can be marked isResultLive=1 even + // when it is unreachable, e.g. due to an always-taken branch. + // The assembler marks it live if it sees any uses, regardless of + // whether those uses are in reachable code or not. + bool isLive() const { + return isV() || + sharedFields.isResultLive || + (isCall() && !callInfo()->_isPure) || // impure calls are always live + isop(LIR_paramp); // LIR_paramp is always live + } + void setResultLive() { + NanoAssert(!isV()); + sharedFields.isResultLive = 1; + } + + // XXX: old reservation manipulating functions. See bug 538924. + // Replacement strategy: + // - deprecated_markAsClear() --> clearReg() and/or clearArIndex() + // - deprecated_hasKnownReg() --> isInReg() + // - deprecated_getReg() --> getReg() after checking isInReg() + // + void deprecated_markAsClear() { + sharedFields.inReg = 0; + sharedFields.inAr = 0; + } + bool deprecated_hasKnownReg() { + NanoAssert(isExtant()); + return isInReg(); + } + Register deprecated_getReg() { + NanoAssert(isExtant()); + if (isInReg()) { + Register r = { sharedFields.regnum }; + return r; + } else { + return deprecated_UnknownReg; + } + } + uint32_t deprecated_getArIndex() { + NanoAssert(isExtant()); + return ( isInAr() ? sharedFields.arIndex : 0 ); + } + + // Reservation manipulation. + // + // "Extant" mean "in existence, still existing, surviving". In other + // words, has the value been computed explicitly (not folded into + // something else) and is it still available (in a register or spill + // slot) for use? + bool isExtant() { + return isInReg() || isInAr(); + } + bool isInReg() { + return sharedFields.inReg; + } + bool isInRegMask(RegisterMask allow) { + return isInReg() && (rmask(getReg()) & allow); + } + Register getReg() { + NanoAssert(isInReg()); + Register r = { sharedFields.regnum }; + return r; + } + void setReg(Register r) { + sharedFields.inReg = 1; + sharedFields.regnum = REGNUM(r); + } + void clearReg() { + sharedFields.inReg = 0; + } + bool isInAr() { + return sharedFields.inAr; + } + uint32_t getArIndex() { + NanoAssert(isInAr()); + return sharedFields.arIndex; + } + void setArIndex(uint32_t arIndex) { + sharedFields.inAr = 1; + sharedFields.arIndex = arIndex; + } + void clearArIndex() { + sharedFields.inAr = 0; + } + + // For various instruction kinds. + inline LIns* oprnd1() const; + inline LIns* oprnd2() const; + inline LIns* oprnd3() const; + + // For branches. + inline LIns* getTarget() const; + inline void setTarget(LIns* label); + + // For guards. + inline GuardRecord* record() const; + + // For loads. + inline LoadQual loadQual() const; + + // For loads/stores. + inline int32_t disp() const; + inline MiniAccSet miniAccSet() const; + inline AccSet accSet() const; + + // For LInsSk. + inline LIns* prevLIns() const; + + // For LInsP. + inline uint8_t paramArg() const; + inline uint8_t paramKind() const; + + // For LInsI. + inline int32_t immI() const; + + // For LInsQorD. +#ifdef NANOJIT_64BIT + inline int32_t immQlo() const; + inline uint64_t immQ() const; +#endif + inline int32_t immDlo() const; + inline int32_t immDhi() const; + inline double immD() const; + inline uint64_t immDasQ() const; + + // For LIR_allocp. + inline int32_t size() const; + inline void setSize(int32_t nbytes); + + // For LInsC. + inline LIns* arg(uint32_t i) const; // right-to-left-order: arg(0) is rightmost + inline uint32_t argc() const; + inline LIns* callArgN(uint32_t n) const; + inline const CallInfo* callInfo() const; + + // For LIR_jtbl + inline uint32_t getTableSize() const; + inline LIns* getTarget(uint32_t index) const; + inline void setTarget(uint32_t index, LIns* label) const; + + // isLInsXYZ() returns true if the instruction has the LInsXYZ form. + // Note that there is some overlap with other predicates, eg. + // isStore()==isLInsSt(), isCall()==isLInsC(), but that's ok; these + // ones are used mostly to check that opcodes are appropriate for + // instruction layouts, the others are used for non-debugging + // purposes. + bool isLInsOp0() const { + NanoAssert(LRK_None != repKinds[opcode()]); + return LRK_Op0 == repKinds[opcode()]; + } + bool isLInsOp1() const { + NanoAssert(LRK_None != repKinds[opcode()]); + return LRK_Op1 == repKinds[opcode()]; + } + bool isLInsOp2() const { + NanoAssert(LRK_None != repKinds[opcode()]); + return LRK_Op2 == repKinds[opcode()]; + } + bool isLInsOp3() const { + NanoAssert(LRK_None != repKinds[opcode()]); + return LRK_Op3 == repKinds[opcode()]; + } + bool isLInsLd() const { + NanoAssert(LRK_None != repKinds[opcode()]); + return LRK_Ld == repKinds[opcode()]; + } + bool isLInsSt() const { + NanoAssert(LRK_None != repKinds[opcode()]); + return LRK_St == repKinds[opcode()]; + } + bool isLInsSk() const { + NanoAssert(LRK_None != repKinds[opcode()]); + return LRK_Sk == repKinds[opcode()]; + } + bool isLInsC() const { + NanoAssert(LRK_None != repKinds[opcode()]); + return LRK_C == repKinds[opcode()]; + } + bool isLInsP() const { + NanoAssert(LRK_None != repKinds[opcode()]); + return LRK_P == repKinds[opcode()]; + } + bool isLInsI() const { + NanoAssert(LRK_None != repKinds[opcode()]); + return LRK_I == repKinds[opcode()]; + } + bool isLInsQorD() const { + NanoAssert(LRK_None != repKinds[opcode()]); + return LRK_QorD == repKinds[opcode()]; + } + bool isLInsJtbl() const { + NanoAssert(LRK_None != repKinds[opcode()]); + return LRK_Jtbl == repKinds[opcode()]; + } + + // LIns predicates. + bool isop(LOpcode o) const { + return opcode() == o; + } + bool isRet() const { + return isRetOpcode(opcode()); + } + bool isCmp() const { + return isCmpOpcode(opcode()); + } + bool isCall() const { + return isop(LIR_callv) || + isop(LIR_calli) || +#if defined NANOJIT_64BIT + isop(LIR_callq) || +#endif + isop(LIR_calld); + } + bool isCmov() const { + return isCmovOpcode(opcode()); + } + bool isStore() const { + return isLInsSt(); + } + bool isLoad() const { + return isLInsLd(); + } + bool isGuard() const { + return isop(LIR_x) || isop(LIR_xf) || isop(LIR_xt) || + isop(LIR_xbarrier) || isop(LIR_xtbl) || + isop(LIR_addxovi) || isop(LIR_subxovi) || isop(LIR_mulxovi); + } + bool isJov() const { + return +#ifdef NANOJIT_64BIT + isop(LIR_addjovq) || isop(LIR_subjovq) || +#endif + isop(LIR_addjovi) || isop(LIR_subjovi) || isop(LIR_muljovi); + } + // True if the instruction is a 32-bit integer immediate. + bool isImmI() const { + return isop(LIR_immi); + } + // True if the instruction is a 32-bit integer immediate and + // has the value 'val' when treated as a 32-bit signed integer. + bool isImmI(int32_t val) const { + return isImmI() && immI()==val; + } +#ifdef NANOJIT_64BIT + // True if the instruction is a 64-bit integer immediate. + bool isImmQ() const { + return isop(LIR_immq); + } +#endif + // True if the instruction is a pointer-sized integer immediate. + bool isImmP() const + { +#ifdef NANOJIT_64BIT + return isImmQ(); +#else + return isImmI(); +#endif + } + // True if the instruction is a 64-bit float immediate. + bool isImmD() const { + return isop(LIR_immd); + } + // True if the instruction is a 64-bit integer or float immediate. + bool isImmQorD() const { + return +#ifdef NANOJIT_64BIT + isImmQ() || +#endif + isImmD(); + } + // True if the instruction an any type of immediate. + bool isImmAny() const { + return isImmI() || isImmQorD(); + } + + bool isBranch() const { + return isop(LIR_jt) || isop(LIR_jf) || isop(LIR_j) || isop(LIR_jtbl) || isJov(); + } + + LTy retType() const { + return retTypes[opcode()]; + } + bool isV() const { + return retType() == LTy_V; + } + bool isI() const { + return retType() == LTy_I; + } +#ifdef NANOJIT_64BIT + bool isQ() const { + return retType() == LTy_Q; + } +#endif + bool isD() const { + return retType() == LTy_D; + } + bool isQorD() const { + return +#ifdef NANOJIT_64BIT + isQ() || +#endif + isD(); + } + bool isP() const { +#ifdef NANOJIT_64BIT + return isQ(); +#else + return isI(); +#endif + } + + inline void* immP() const + { + #ifdef NANOJIT_64BIT + return (void*)immQ(); + #else + return (void*)immI(); + #endif + } + }; + + typedef SeqBuilder InsList; + typedef SeqBuilder StringList; + + + // 0-operand form. Used for LIR_start and LIR_label. + class LInsOp0 + { + private: + friend class LIns; + + LIns ins; + + public: + LIns* getLIns() { return &ins; }; + }; + + // 1-operand form. Used for LIR_reti, unary arithmetic/logic ops, etc. + class LInsOp1 + { + private: + friend class LIns; + + LIns* oprnd_1; + + LIns ins; + + public: + LIns* getLIns() { return &ins; }; + }; + + // 2-operand form. Used for guards, branches, comparisons, binary + // arithmetic/logic ops, etc. + class LInsOp2 + { + private: + friend class LIns; + + LIns* oprnd_2; + + LIns* oprnd_1; + + LIns ins; + + public: + LIns* getLIns() { return &ins; }; + }; + + // 3-operand form. Used for conditional moves, jov branches, and xov guards. + class LInsOp3 + { + private: + friend class LIns; + + LIns* oprnd_3; + + LIns* oprnd_2; + + LIns* oprnd_1; + + LIns ins; + + public: + LIns* getLIns() { return &ins; }; + }; + + // Used for all loads. + class LInsLd + { + private: + friend class LIns; + + // Nb: the LIR writer pipeline handles things if a displacement + // exceeds 16 bits. This is rare, but does happen occasionally. We + // could go to 24 bits but then it would happen so rarely that the + // handler code would be difficult to test and thus untrustworthy. + // + // Nb: the types of these bitfields are all 32-bit integers to ensure + // they are fully packed on Windows, sigh. Also, 'loadQual' is + // unsigned to ensure the values 0, 1, and 2 all fit in 2 bits. + // + // Nb: explicit signed keyword for bitfield types is required, + // some compilers may treat them as unsigned without it. + // See Bugzilla 584219 comment #18 + signed int disp:16; + signed int miniAccSetVal:8; + uint32_t loadQual:2; + + LIns* oprnd_1; + + LIns ins; + + public: + LIns* getLIns() { return &ins; }; + }; + + // Used for all stores. + class LInsSt + { + private: + friend class LIns; + + int16_t disp; + MiniAccSetVal miniAccSetVal; + + LIns* oprnd_2; + + LIns* oprnd_1; + + LIns ins; + + public: + LIns* getLIns() { return &ins; }; + }; + + // Used for LIR_skip. + class LInsSk + { + private: + friend class LIns; + + LIns* prevLIns; + + LIns ins; + + public: + LIns* getLIns() { return &ins; }; + }; + + // Used for all variants of LIR_call. + class LInsC + { + private: + friend class LIns; + + // Arguments in reverse order, just like insCall() (ie. args[0] holds + // the rightmost arg). The array should be allocated by the same + // allocator as the LIR buffers, because it has the same lifetime. + LIns** args; + + const CallInfo* ci; + + LIns ins; + + public: + LIns* getLIns() { return &ins; }; + }; + + // Used for LIR_paramp. + class LInsP + { + private: + friend class LIns; + + uintptr_t arg:8; + uintptr_t kind:8; + + LIns ins; + + public: + LIns* getLIns() { return &ins; }; + }; + + // Used for LIR_immi and LIR_allocp. + class LInsI + { + private: + friend class LIns; + + int32_t immI; + + LIns ins; + + public: + LIns* getLIns() { return &ins; }; + }; + + // Used for LIR_immq and LIR_immd. + class LInsQorD + { + private: + friend class LIns; + + int32_t immQorDlo; + + int32_t immQorDhi; + + LIns ins; + + public: + LIns* getLIns() { return &ins; }; + }; + + // Used for LIR_jtbl. 'oprnd_1' must be a uint32_t index in + // the range 0 <= index < size; no range check is performed. + // 'table' is an array of labels. + class LInsJtbl + { + private: + friend class LIns; + + uint32_t size; // number of entries in table + LIns** table; // pointer to table[size] with same lifetime as this LInsJtbl + LIns* oprnd_1; // uint32_t index expression + + LIns ins; + + public: + LIns* getLIns() { return &ins; } + }; + + // Used only as a placeholder for OP___ macros for unused opcodes in + // LIRopcode.tbl. + class LInsNone + { + }; + + LInsOp0* LIns::toLInsOp0() const { return (LInsOp0* )(uintptr_t(this+1) - sizeof(LInsOp0 )); } + LInsOp1* LIns::toLInsOp1() const { return (LInsOp1* )(uintptr_t(this+1) - sizeof(LInsOp1 )); } + LInsOp2* LIns::toLInsOp2() const { return (LInsOp2* )(uintptr_t(this+1) - sizeof(LInsOp2 )); } + LInsOp3* LIns::toLInsOp3() const { return (LInsOp3* )(uintptr_t(this+1) - sizeof(LInsOp3 )); } + LInsLd* LIns::toLInsLd() const { return (LInsLd* )(uintptr_t(this+1) - sizeof(LInsLd )); } + LInsSt* LIns::toLInsSt() const { return (LInsSt* )(uintptr_t(this+1) - sizeof(LInsSt )); } + LInsSk* LIns::toLInsSk() const { return (LInsSk* )(uintptr_t(this+1) - sizeof(LInsSk )); } + LInsC* LIns::toLInsC() const { return (LInsC* )(uintptr_t(this+1) - sizeof(LInsC )); } + LInsP* LIns::toLInsP() const { return (LInsP* )(uintptr_t(this+1) - sizeof(LInsP )); } + LInsI* LIns::toLInsI() const { return (LInsI* )(uintptr_t(this+1) - sizeof(LInsI )); } + LInsQorD* LIns::toLInsQorD() const { return (LInsQorD*)(uintptr_t(this+1) - sizeof(LInsQorD)); } + LInsJtbl* LIns::toLInsJtbl() const { return (LInsJtbl*)(uintptr_t(this+1) - sizeof(LInsJtbl)); } + + void LIns::initLInsOp0(LOpcode opcode) { + initSharedFields(opcode); + NanoAssert(isLInsOp0()); + } + void LIns::initLInsOp1(LOpcode opcode, LIns* oprnd1) { + initSharedFields(opcode); + toLInsOp1()->oprnd_1 = oprnd1; + NanoAssert(isLInsOp1()); + } + void LIns::initLInsOp2(LOpcode opcode, LIns* oprnd1, LIns* oprnd2) { + initSharedFields(opcode); + toLInsOp2()->oprnd_1 = oprnd1; + toLInsOp2()->oprnd_2 = oprnd2; + NanoAssert(isLInsOp2()); + } + void LIns::initLInsOp3(LOpcode opcode, LIns* oprnd1, LIns* oprnd2, LIns* oprnd3) { + initSharedFields(opcode); + toLInsOp3()->oprnd_1 = oprnd1; + toLInsOp3()->oprnd_2 = oprnd2; + toLInsOp3()->oprnd_3 = oprnd3; + NanoAssert(isLInsOp3()); + } + void LIns::initLInsLd(LOpcode opcode, LIns* val, int32_t d, AccSet accSet, LoadQual loadQual) { + initSharedFields(opcode); + toLInsLd()->oprnd_1 = val; + NanoAssert(d == int16_t(d)); + toLInsLd()->disp = int16_t(d); + toLInsLd()->miniAccSetVal = compressAccSet(accSet).val; + toLInsLd()->loadQual = loadQual; + NanoAssert(isLInsLd()); + } + void LIns::initLInsSt(LOpcode opcode, LIns* val, LIns* base, int32_t d, AccSet accSet) { + initSharedFields(opcode); + toLInsSt()->oprnd_1 = val; + toLInsSt()->oprnd_2 = base; + NanoAssert(d == int16_t(d)); + toLInsSt()->disp = int16_t(d); + toLInsSt()->miniAccSetVal = compressAccSet(accSet).val; + NanoAssert(isLInsSt()); + } + void LIns::initLInsSk(LIns* prevLIns) { + initSharedFields(LIR_skip); + toLInsSk()->prevLIns = prevLIns; + NanoAssert(isLInsSk()); + } + void LIns::initLInsC(LOpcode opcode, LIns** args, const CallInfo* ci) { + initSharedFields(opcode); + toLInsC()->args = args; + toLInsC()->ci = ci; + NanoAssert(isLInsC()); + } + void LIns::initLInsP(int32_t arg, int32_t kind) { + initSharedFields(LIR_paramp); + NanoAssert(isU8(arg) && isU8(kind)); + toLInsP()->arg = arg; + toLInsP()->kind = kind; + NanoAssert(isLInsP()); + } + void LIns::initLInsI(LOpcode opcode, int32_t immI) { + initSharedFields(opcode); + toLInsI()->immI = immI; + NanoAssert(isLInsI()); + } + void LIns::initLInsQorD(LOpcode opcode, uint64_t immQorD) { + initSharedFields(opcode); + toLInsQorD()->immQorDlo = int32_t(immQorD); + toLInsQorD()->immQorDhi = int32_t(immQorD >> 32); + NanoAssert(isLInsQorD()); + } + void LIns::initLInsJtbl(LIns* index, uint32_t size, LIns** table) { + initSharedFields(LIR_jtbl); + toLInsJtbl()->oprnd_1 = index; + toLInsJtbl()->table = table; + toLInsJtbl()->size = size; + NanoAssert(isLInsJtbl()); + } + + LIns* LIns::oprnd1() const { + NanoAssert(isLInsOp1() || isLInsOp2() || isLInsOp3() || isLInsLd() || isLInsSt() || isLInsJtbl()); + return toLInsOp2()->oprnd_1; + } + LIns* LIns::oprnd2() const { + NanoAssert(isLInsOp2() || isLInsOp3() || isLInsSt()); + return toLInsOp2()->oprnd_2; + } + LIns* LIns::oprnd3() const { + NanoAssert(isLInsOp3()); + return toLInsOp3()->oprnd_3; + } + + LIns* LIns::getTarget() const { + NanoAssert(isBranch() && !isop(LIR_jtbl)); + if (isJov()) + return oprnd3(); + else + return oprnd2(); + } + + void LIns::setTarget(LIns* label) { + NanoAssert(label && label->isop(LIR_label)); + NanoAssert(isBranch() && !isop(LIR_jtbl)); + if (isJov()) + toLInsOp3()->oprnd_3 = label; + else + toLInsOp2()->oprnd_2 = label; + } + + LIns* LIns::getTarget(uint32_t index) const { + NanoAssert(isop(LIR_jtbl)); + NanoAssert(index < toLInsJtbl()->size); + return toLInsJtbl()->table[index]; + } + + void LIns::setTarget(uint32_t index, LIns* label) const { + NanoAssert(label && label->isop(LIR_label)); + NanoAssert(isop(LIR_jtbl)); + NanoAssert(index < toLInsJtbl()->size); + toLInsJtbl()->table[index] = label; + } + + GuardRecord *LIns::record() const { + NanoAssert(isGuard()); + switch (opcode()) { + case LIR_x: + case LIR_xt: + case LIR_xf: + case LIR_xtbl: + case LIR_xbarrier: + return (GuardRecord*)oprnd2(); + + case LIR_addxovi: + case LIR_subxovi: + case LIR_mulxovi: + return (GuardRecord*)oprnd3(); + + default: + NanoAssert(0); + return NULL; + } + } + + LoadQual LIns::loadQual() const { + NanoAssert(isLInsLd()); + return (LoadQual)toLInsLd()->loadQual; + } + + int32_t LIns::disp() const { + if (isLInsSt()) { + return toLInsSt()->disp; + } else { + NanoAssert(isLInsLd()); + return toLInsLd()->disp; + } + } + + MiniAccSet LIns::miniAccSet() const { + MiniAccSet miniAccSet; + if (isLInsSt()) { + miniAccSet.val = toLInsSt()->miniAccSetVal; + } else { + NanoAssert(isLInsLd()); + miniAccSet.val = toLInsLd()->miniAccSetVal; + } + return miniAccSet; + } + + AccSet LIns::accSet() const { + return decompressMiniAccSet(miniAccSet()); + } + + LIns* LIns::prevLIns() const { + NanoAssert(isLInsSk()); + return toLInsSk()->prevLIns; + } + + inline uint8_t LIns::paramArg() const { NanoAssert(isop(LIR_paramp)); return toLInsP()->arg; } + inline uint8_t LIns::paramKind() const { NanoAssert(isop(LIR_paramp)); return toLInsP()->kind; } + + inline int32_t LIns::immI() const { NanoAssert(isImmI()); return toLInsI()->immI; } + +#ifdef NANOJIT_64BIT + inline int32_t LIns::immQlo() const { NanoAssert(isImmQ()); return toLInsQorD()->immQorDlo; } + uint64_t LIns::immQ() const { + NanoAssert(isImmQ()); + return (uint64_t(toLInsQorD()->immQorDhi) << 32) | uint32_t(toLInsQorD()->immQorDlo); + } +#endif + inline int32_t LIns::immDlo() const { NanoAssert(isImmD()); return toLInsQorD()->immQorDlo; } + inline int32_t LIns::immDhi() const { NanoAssert(isImmD()); return toLInsQorD()->immQorDhi; } + double LIns::immD() const { + NanoAssert(isImmD()); + union { + double f; + uint64_t q; + } u; + u.q = immDasQ(); + return u.f; + } + uint64_t LIns::immDasQ() const { + NanoAssert(isImmD()); + return (uint64_t(toLInsQorD()->immQorDhi) << 32) | uint32_t(toLInsQorD()->immQorDlo); + } + + int32_t LIns::size() const { + NanoAssert(isop(LIR_allocp)); + return toLInsI()->immI << 2; + } + + void LIns::setSize(int32_t nbytes) { + NanoAssert(isop(LIR_allocp)); + NanoAssert(nbytes > 0); + toLInsI()->immI = (nbytes+3)>>2; // # of required 32bit words + } + + // Index args in reverse order, i.e. arg(0) returns the rightmost arg. + // Nb: this must be kept in sync with insCall(). + LIns* LIns::arg(uint32_t i) const + { + NanoAssert(isCall()); + NanoAssert(i < callInfo()->count_args()); + return toLInsC()->args[i]; // args[] is in right-to-left order as well + } + + uint32_t LIns::argc() const { + return callInfo()->count_args(); + } + + LIns* LIns::callArgN(uint32_t n) const + { + return arg(argc()-n-1); + } + + const CallInfo* LIns::callInfo() const + { + NanoAssert(isCall()); + return toLInsC()->ci; + } + + uint32_t LIns::getTableSize() const + { + NanoAssert(isLInsJtbl()); + return toLInsJtbl()->size; + } + + class LirWriter + { + public: + LirWriter *out; + + LirWriter(LirWriter* out) + : out(out) {} + virtual ~LirWriter() {} + + virtual LIns* ins0(LOpcode v) { + return out->ins0(v); + } + virtual LIns* ins1(LOpcode v, LIns* a) { + return out->ins1(v, a); + } + virtual LIns* ins2(LOpcode v, LIns* a, LIns* b) { + return out->ins2(v, a, b); + } + virtual LIns* ins3(LOpcode v, LIns* a, LIns* b, LIns* c) { + return out->ins3(v, a, b, c); + } + virtual LIns* insGuard(LOpcode v, LIns *c, GuardRecord *gr) { + return out->insGuard(v, c, gr); + } + virtual LIns* insGuardXov(LOpcode v, LIns *a, LIns* b, GuardRecord *gr) { + return out->insGuardXov(v, a, b, gr); + } + virtual LIns* insBranch(LOpcode v, LIns* condition, LIns* to) { + return out->insBranch(v, condition, to); + } + virtual LIns* insBranchJov(LOpcode v, LIns* a, LIns* b, LIns* to) { + return out->insBranchJov(v, a, b, to); + } + // arg: 0=first, 1=second, ... + // kind: 0=arg 1=saved-reg + virtual LIns* insParam(int32_t arg, int32_t kind) { + return out->insParam(arg, kind); + } + virtual LIns* insImmI(int32_t imm) { + return out->insImmI(imm); + } +#ifdef NANOJIT_64BIT + virtual LIns* insImmQ(uint64_t imm) { + return out->insImmQ(imm); + } +#endif + virtual LIns* insImmD(double d) { + return out->insImmD(d); + } + virtual LIns* insLoad(LOpcode op, LIns* base, int32_t d, AccSet accSet, LoadQual loadQual) { + return out->insLoad(op, base, d, accSet, loadQual); + } + virtual LIns* insStore(LOpcode op, LIns* value, LIns* base, int32_t d, AccSet accSet) { + return out->insStore(op, value, base, d, accSet); + } + // args[] is in reverse order, ie. args[0] holds the rightmost arg. + virtual LIns* insCall(const CallInfo *call, LIns* args[]) { + return out->insCall(call, args); + } + virtual LIns* insAlloc(int32_t size) { + NanoAssert(size != 0); + return out->insAlloc(size); + } + virtual LIns* insJtbl(LIns* index, uint32_t size) { + return out->insJtbl(index, size); + } + virtual LIns* insComment(const char* str) { + return out->insComment(str); + } + + // convenience functions + + // Inserts a conditional to execute and branches to execute if + // the condition is true and false respectively. + LIns* insChoose(LIns* cond, LIns* iftrue, LIns* iffalse, bool use_cmov); + + // Inserts an integer comparison to 0 + LIns* insEqI_0(LIns* oprnd1) { + return ins2ImmI(LIR_eqi, oprnd1, 0); + } + + // Inserts a pointer comparison to 0 + LIns* insEqP_0(LIns* oprnd1) { + return ins2(LIR_eqp, oprnd1, insImmWord(0)); + } + + // Inserts a binary operation where the second operand is an + // integer immediate. + LIns* ins2ImmI(LOpcode v, LIns* oprnd1, int32_t imm) { + return ins2(v, oprnd1, insImmI(imm)); + } + + LIns* insImmP(const void *ptr) { +#ifdef NANOJIT_64BIT + return insImmQ((uint64_t)ptr); +#else + return insImmI((int32_t)ptr); +#endif + } + + LIns* insImmWord(intptr_t value) { +#ifdef NANOJIT_64BIT + return insImmQ(value); +#else + return insImmI(value); +#endif + } + + // Sign-extend integers to native integers. On 32-bit this is a no-op. + LIns* insI2P(LIns* intIns) { +#ifdef NANOJIT_64BIT + return ins1(LIR_i2q, intIns); +#else + return intIns; +#endif + } + + // Zero-extend integers to native integers. On 32-bit this is a no-op. + LIns* insUI2P(LIns* uintIns) { + #ifdef NANOJIT_64BIT + return ins1(LIR_ui2uq, uintIns); + #else + return uintIns; + #endif + } + + // Do a load with LoadQual==LOAD_NORMAL. + LIns* insLoad(LOpcode op, LIns* base, int32_t d, AccSet accSet) { + return insLoad(op, base, d, accSet, LOAD_NORMAL); + } + + // Chooses LIR_sti, LIR_stq or LIR_std according to the type of 'value'. + LIns* insStore(LIns* value, LIns* base, int32_t d, AccSet accSet); + }; + + +#ifdef NJ_VERBOSE + extern const char* lirNames[]; + + // Maps address ranges to meaningful names. + class AddrNameMap + { + Allocator& allocator; + class Entry + { + public: + Entry(int) : name(0), size(0), align(0) {} + Entry(char *n, size_t s, size_t a) : name(n), size(s), align(a) {} + char* name; + size_t size:29, align:3; + }; + TreeMap names; // maps code regions to names + public: + AddrNameMap(Allocator& allocator); + void addAddrRange(const void *p, size_t size, size_t align, const char *name); + void lookupAddr(void *p, char*& name, int32_t& offset); + }; + + // Maps LIR instructions to meaningful names. + class LirNameMap + { + private: + Allocator& alloc; + + // A small string-wrapper class, required because we need '==' to + // compare string contents, not string pointers, when strings are used + // as keys in CountMap. + struct Str { + Allocator& alloc; + char* s; + + Str(Allocator& alloc_, const char* s_) : alloc(alloc_) { + s = new (alloc) char[1+strlen(s_)]; + strcpy(s, s_); + } + + bool operator==(const Str& str) const { + return (0 == strcmp(this->s, str.s)); + } + }; + + // Similar to 'struct Str' -- we need to hash the string's contents, + // not its pointer. + template struct StrHash { + static size_t hash(const Str &k) { + // (const void*) cast is required by ARM RVCT 2.2 + return murmurhash((const void*)k.s, strlen(k.s)); + } + }; + + template > + class CountMap: public HashMap { + public: + CountMap(Allocator& alloc) : HashMap(alloc, 128) {} + int add(Key k) { + int c = 1; + if (this->containsKey(k)) { + c = 1+this->get(k); + } + this->put(k,c); + return c; + } + }; + + CountMap lircounts; + CountMap funccounts; + CountMap > namecounts; + + void addNameWithSuffix(LIns* i, const char *s, int suffix, bool ignoreOneSuffix); + + class Entry + { + public: + Entry(int) : name(0) {} + Entry(char* n) : name(n) {} + char* name; + }; + + HashMap names; + + public: + LirNameMap(Allocator& alloc) + : alloc(alloc), + lircounts(alloc), + funccounts(alloc), + namecounts(alloc), + names(alloc) + {} + + void addName(LIns* ins, const char *s); // gives 'ins' a special name + const char* createName(LIns* ins); // gives 'ins' a generic name + const char* lookupName(LIns* ins); + }; + + // We use big buffers for cases where we need to fit a whole instruction, + // and smaller buffers for all the others. These should easily be long + // enough, but for safety the formatXyz() functions check and won't exceed + // those limits. + class InsBuf { + public: + static const size_t len = 1000; + char buf[len]; + }; + class RefBuf { + public: + static const size_t len = 200; + char buf[len]; + }; + + class LInsPrinter + { + private: + Allocator& alloc; + const int EMB_NUM_USED_ACCS; + + char *formatImmI(RefBuf* buf, int32_t c); +#ifdef NANOJIT_64BIT + char *formatImmQ(RefBuf* buf, uint64_t c); +#endif + char *formatImmD(RefBuf* buf, double c); + void formatGuard(InsBuf* buf, LIns* ins); // defined by the embedder + void formatGuardXov(InsBuf* buf, LIns* ins); // defined by the embedder + + public: + static const char* accNames[]; // defined by the embedder + + LInsPrinter(Allocator& alloc, int embNumUsedAccs) + : alloc(alloc), EMB_NUM_USED_ACCS(embNumUsedAccs) + { + addrNameMap = new (alloc) AddrNameMap(alloc); + lirNameMap = new (alloc) LirNameMap(alloc); + } + + char *formatAddr(RefBuf* buf, void* p); + char *formatRef(RefBuf* buf, LIns* ref, bool showImmValue = true); + char *formatIns(InsBuf* buf, LIns* ins); + char *formatAccSet(RefBuf* buf, AccSet accSet); + + AddrNameMap* addrNameMap; + LirNameMap* lirNameMap; + }; + + + class VerboseWriter : public LirWriter + { + InsList code; + LInsPrinter* printer; + LogControl* logc; + const char* const prefix; + bool const always_flush; + public: + VerboseWriter(Allocator& alloc, LirWriter *out, LInsPrinter* printer, LogControl* logc, + const char* prefix = "", bool always_flush = false) + : LirWriter(out), code(alloc), printer(printer), logc(logc), prefix(prefix), always_flush(always_flush) + {} + + LIns* add(LIns* i) { + if (i) { + code.add(i); + if (always_flush) + flush(); + } + return i; + } + + LIns* add_flush(LIns* i) { + if ((i = add(i)) != 0) + flush(); + return i; + } + + void flush() + { + if (!code.isEmpty()) { + InsBuf b; + for (Seq* p = code.get(); p != NULL; p = p->tail) + logc->printf("%s %s\n", prefix, printer->formatIns(&b, p->head)); + code.clear(); + } + } + + LIns* insGuard(LOpcode op, LIns* cond, GuardRecord *gr) { + return add_flush(out->insGuard(op,cond,gr)); + } + + LIns* insGuardXov(LOpcode op, LIns* a, LIns* b, GuardRecord *gr) { + return add(out->insGuardXov(op,a,b,gr)); + } + + LIns* insBranch(LOpcode v, LIns* condition, LIns* to) { + return add_flush(out->insBranch(v, condition, to)); + } + + LIns* insBranchJov(LOpcode v, LIns* a, LIns* b, LIns* to) { + return add(out->insBranchJov(v, a, b, to)); + } + + LIns* insJtbl(LIns* index, uint32_t size) { + return add_flush(out->insJtbl(index, size)); + } + + LIns* ins0(LOpcode v) { + if (v == LIR_label || v == LIR_start) { + flush(); + } + return add(out->ins0(v)); + } + + LIns* ins1(LOpcode v, LIns* a) { + return isRetOpcode(v) ? add_flush(out->ins1(v, a)) : add(out->ins1(v, a)); + } + LIns* ins2(LOpcode v, LIns* a, LIns* b) { + return add(out->ins2(v, a, b)); + } + LIns* ins3(LOpcode v, LIns* a, LIns* b, LIns* c) { + return add(out->ins3(v, a, b, c)); + } + LIns* insCall(const CallInfo *call, LIns* args[]) { + return add_flush(out->insCall(call, args)); + } + LIns* insParam(int32_t i, int32_t kind) { + return add(out->insParam(i, kind)); + } + LIns* insLoad(LOpcode v, LIns* base, int32_t disp, AccSet accSet, LoadQual loadQual) { + return add(out->insLoad(v, base, disp, accSet, loadQual)); + } + LIns* insStore(LOpcode op, LIns* v, LIns* b, int32_t d, AccSet accSet) { + return add_flush(out->insStore(op, v, b, d, accSet)); + } + LIns* insAlloc(int32_t size) { + return add(out->insAlloc(size)); + } + LIns* insImmI(int32_t imm) { + return add(out->insImmI(imm)); + } +#ifdef NANOJIT_64BIT + LIns* insImmQ(uint64_t imm) { + return add(out->insImmQ(imm)); + } +#endif + LIns* insImmD(double d) { + return add(out->insImmD(d)); + } + + LIns* insComment(const char* str) { + return add_flush(out->insComment(str)); + } + }; + +#endif + + class ExprFilter: public LirWriter + { + public: + ExprFilter(LirWriter *out) : LirWriter(out) {} + LIns* ins1(LOpcode v, LIns* a); + LIns* ins2(LOpcode v, LIns* a, LIns* b); + LIns* ins3(LOpcode v, LIns* a, LIns* b, LIns* c); + LIns* insGuard(LOpcode, LIns* cond, GuardRecord *); + LIns* insGuardXov(LOpcode, LIns* a, LIns* b, GuardRecord *); + LIns* insBranch(LOpcode, LIns* cond, LIns* target); + LIns* insBranchJov(LOpcode, LIns* a, LIns* b, LIns* target); + LIns* insLoad(LOpcode op, LIns* base, int32_t off, AccSet accSet, LoadQual loadQual); + private: + LIns* simplifyOverflowArith(LOpcode op, LIns** opnd1, LIns** opnd2); + }; + + class CseFilter: public LirWriter + { + enum NLKind { + // We divide instruction kinds into groups. LIns0 isn't present + // because we don't need to record any 0-ary instructions. Loads + // aren't here, they're handled separately. + NLImmISmall = 0, + NLImmILarge = 1, + NLImmQ = 2, // only occurs on 64-bit platforms + NLImmD = 3, + NL1 = 4, + NL2 = 5, + NL3 = 6, + NLCall = 7, + + NLFirst = 0, + NLLast = 7, + // Need a value after "last" to outsmart compilers that insist last+1 is impossible. + NLInvalid = 8 + }; + #define nextNLKind(kind) NLKind(kind+1) + + // There is one table for each NLKind. This lets us size the lists + // appropriately (some instruction kinds are more common than others). + // It also lets us have NLKind-specific find/add/grow functions, which + // are faster than generic versions. + // + // Nb: m_listNL and m_capNL sizes must be a power of 2. + // Don't start m_capNL too small, or we'll waste time growing and rehashing. + // Don't start m_capNL too large, will waste memory. + // + LIns** m_listNL[NLLast + 1]; + uint32_t m_capNL[ NLLast + 1]; + uint32_t m_usedNL[NLLast + 1]; + typedef uint32_t (CseFilter::*find_t)(LIns*); + find_t m_findNL[NLLast + 1]; + + // Similarly, for loads, there is one table for each CseAcc. A CseAcc + // is like a normal access region, but there are two extra possible + // values: CSE_ACC_CONST, which is where we put all CONST-qualified + // loads, and CSE_ACC_MULTIPLE, where we put all multi-region loads. + // All remaining loads are single-region and go in the table entry for + // their region. + // + // This arrangement makes the removal of invalidated loads fast -- we + // can invalidate all loads from a single region by clearing that + // region's table. + // + typedef uint8_t CseAcc; // same type as MiniAccSet + + static const uint8_t CSE_NUM_ACCS = NUM_ACCS + 2; + + // These values would be 'static const' except they are defined in + // terms of EMB_NUM_USED_ACCS which is itself not 'static const' + // because it's passed in by the embedding. + const uint8_t EMB_NUM_USED_ACCS; // number of access regions used by the embedding + const uint8_t CSE_NUM_USED_ACCS; // EMB_NUM_USED_ACCS + 2 + const CseAcc CSE_ACC_CONST; // EMB_NUM_USED_ACCS + 0 + const CseAcc CSE_ACC_MULTIPLE; // EMB_NUM_USED_ACCS + 1 + + // We will only use CSE_NUM_USED_ACCS of these entries, ie. the + // number of lists allocated depends on the number of access regions + // in use by the embedding. + LIns** m_listL[CSE_NUM_ACCS]; + uint32_t m_capL[ CSE_NUM_ACCS]; + uint32_t m_usedL[CSE_NUM_ACCS]; + + AccSet storesSinceLastLoad; // regions stored to since the last load + + Allocator& alloc; + + // After a conditional guard such as "xf cmp", we know that 'cmp' must + // be true, else we would have side-exited. So if we see 'cmp' again + // we can treat it like a constant. This table records such + // comparisons. + HashMap knownCmpValues; + + // If true, we will not add new instructions to the CSE tables, but we + // will continue to CSE instructions that match existing table + // entries. Load instructions will still be removed if aliasing + // stores are encountered. + bool suspended; + + CseAcc miniAccSetToCseAcc(MiniAccSet miniAccSet, LoadQual loadQual) { + NanoAssert(miniAccSet.val < NUM_ACCS || miniAccSet.val == MINI_ACCSET_MULTIPLE.val); + return (loadQual == LOAD_CONST) ? CSE_ACC_CONST : + (miniAccSet.val == MINI_ACCSET_MULTIPLE.val) ? CSE_ACC_MULTIPLE : + miniAccSet.val; + } + + static uint32_t hash8(uint32_t hash, const uint8_t data); + static uint32_t hash32(uint32_t hash, const uint32_t data); + static uint32_t hashptr(uint32_t hash, const void* data); + static uint32_t hashfinish(uint32_t hash); + + static uint32_t hashImmI(int32_t); + static uint32_t hashImmQorD(uint64_t); // not NANOJIT_64BIT-only -- used by findImmD() + static uint32_t hash1(LOpcode op, LIns*); + static uint32_t hash2(LOpcode op, LIns*, LIns*); + static uint32_t hash3(LOpcode op, LIns*, LIns*, LIns*); + static uint32_t hashLoad(LOpcode op, LIns*, int32_t); + static uint32_t hashCall(const CallInfo *call, uint32_t argc, LIns* args[]); + + // These versions are used before an LIns has been created. + LIns* findImmISmall(int32_t a, uint32_t &k); + LIns* findImmILarge(int32_t a, uint32_t &k); +#ifdef NANOJIT_64BIT + LIns* findImmQ(uint64_t a, uint32_t &k); +#endif + LIns* findImmD(uint64_t d, uint32_t &k); + LIns* find1(LOpcode v, LIns* a, uint32_t &k); + LIns* find2(LOpcode v, LIns* a, LIns* b, uint32_t &k); + LIns* find3(LOpcode v, LIns* a, LIns* b, LIns* c, uint32_t &k); + LIns* findLoad(LOpcode v, LIns* a, int32_t b, MiniAccSet miniAccSet, LoadQual loadQual, + uint32_t &k); + LIns* findCall(const CallInfo *call, uint32_t argc, LIns* args[], uint32_t &k); + + // These versions are used after an LIns has been created; they are + // used for rehashing after growing. They just call onto the + // multi-arg versions above. + uint32_t findImmISmall(LIns* ins); + uint32_t findImmILarge(LIns* ins); +#ifdef NANOJIT_64BIT + uint32_t findImmQ(LIns* ins); +#endif + uint32_t findImmD(LIns* ins); + uint32_t find1(LIns* ins); + uint32_t find2(LIns* ins); + uint32_t find3(LIns* ins); + uint32_t findCall(LIns* ins); + uint32_t findLoad(LIns* ins); + + // These return false if they failed to grow due to OOM. + bool growNL(NLKind kind); + bool growL(CseAcc cseAcc); + + void addNLImmISmall(LIns* ins, uint32_t k); + // 'k' is the index found by findXYZ(). + void addNL(NLKind kind, LIns* ins, uint32_t k); + void addL(LIns* ins, uint32_t k); + + void clearAll(); // clears all tables + void clearNL(NLKind); // clears one non-load table + void clearL(CseAcc); // clears one load table + + public: + CseFilter(LirWriter *out, uint8_t embNumUsedAccs, Allocator&); + + // CseFilter does some largish fallible allocations at start-up. If + // they fail, the constructor sets this field to 'true'. It should be + // checked after creation, and if set the CseFilter cannot be used. + // (But the check can be skipped if allocChunk() always succeeds.) + // + // FIXME: This fallibility is a sop to TraceMonkey's implementation of + // infallible malloc -- by avoiding some largish infallible + // allocations, it reduces the size of the reserve space needed. + // Bug 624590 is open to fix this. + bool initOOM; + + LIns* insImmI(int32_t imm); +#ifdef NANOJIT_64BIT + LIns* insImmQ(uint64_t q); +#endif + LIns* insImmD(double d); + LIns* ins0(LOpcode v); + LIns* ins1(LOpcode v, LIns*); + LIns* ins2(LOpcode v, LIns*, LIns*); + LIns* ins3(LOpcode v, LIns*, LIns*, LIns*); + LIns* insLoad(LOpcode op, LIns* base, int32_t d, AccSet accSet, LoadQual loadQual); + LIns* insStore(LOpcode op, LIns* value, LIns* base, int32_t d, AccSet accSet); + LIns* insCall(const CallInfo *call, LIns* args[]); + LIns* insGuard(LOpcode op, LIns* cond, GuardRecord *gr); + LIns* insGuardXov(LOpcode op, LIns* a, LIns* b, GuardRecord *gr); + + // These functions provide control over CSE in the face of control + // flow. A suspend()/resume() pair may be put around a synthetic + // control flow diamond, preventing the inserted label from resetting + // the CSE state. A suspend() call must be dominated by a resume() + // call, else incorrect code could result. + void suspend() { suspended = true; } + void resume() { suspended = false; } + }; + + class LirBuffer + { + public: + LirBuffer(Allocator& alloc); + void clear(); + uintptr_t makeRoom(size_t szB); // make room for an instruction + + debug_only (void validate() const;) + verbose_only(LInsPrinter* printer;) + + int32_t insCount(); + + // stats + struct + { + uint32_t lir; // # instructions + } + _stats; + + AbiKind abi; + LIns *state, *param1, *sp, *rp; + LIns* savedRegs[NumSavedRegs+1]; // Allocate an extra element in case NumSavedRegs == 0 + + /** Each chunk is just a raw area of LIns instances, with no header + and no more than 8-byte alignment. The chunk size is somewhat arbitrary. */ + static const size_t CHUNK_SZB = 8000; + + protected: + friend class LirBufWriter; + + /** Get CHUNK_SZB more memory for LIR instructions. */ + void chunkAlloc(); + void moveToNewChunk(uintptr_t addrOfLastLInsOnCurrentChunk); + + Allocator& _allocator; + uintptr_t _unused; // next unused instruction slot in the current LIR chunk + uintptr_t _limit; // one past the last usable byte of the current LIR chunk + }; + + class LirBufWriter : public LirWriter + { + LirBuffer* _buf; // underlying buffer housing the instructions + const Config& _config; + + public: + LirBufWriter(LirBuffer* buf, const Config& config) + : LirWriter(0), _buf(buf), _config(config) { + } + + // LirWriter interface + LIns* insLoad(LOpcode op, LIns* base, int32_t disp, AccSet accSet, LoadQual loadQual); + LIns* insStore(LOpcode op, LIns* o1, LIns* o2, int32_t disp, AccSet accSet); + LIns* ins0(LOpcode op); + LIns* ins1(LOpcode op, LIns* o1); + LIns* ins2(LOpcode op, LIns* o1, LIns* o2); + LIns* ins3(LOpcode op, LIns* o1, LIns* o2, LIns* o3); + LIns* insParam(int32_t i, int32_t kind); + LIns* insImmI(int32_t imm); +#ifdef NANOJIT_64BIT + LIns* insImmQ(uint64_t imm); +#endif + LIns* insImmD(double d); + LIns* insCall(const CallInfo *call, LIns* args[]); + LIns* insGuard(LOpcode op, LIns* cond, GuardRecord *gr); + LIns* insGuardXov(LOpcode op, LIns* a, LIns* b, GuardRecord *gr); + LIns* insBranch(LOpcode v, LIns* condition, LIns* to); + LIns* insBranchJov(LOpcode v, LIns* a, LIns* b, LIns* to); + LIns* insAlloc(int32_t size); + LIns* insJtbl(LIns* index, uint32_t size); + LIns* insComment(const char* str); + }; + + class LirFilter + { + public: + LirFilter *in; + LirFilter(LirFilter *in) : in(in) {} + virtual ~LirFilter(){} + + // It's crucial that once this reaches the LIR_start at the beginning + // of the buffer, that it just keeps returning that LIR_start LIns on + // any subsequent calls. + virtual LIns* read() { + return in->read(); + } + virtual LIns* finalIns() { + return in->finalIns(); + } + }; + + // concrete + class LirReader : public LirFilter + { + LIns* _ins; // next instruction to be read; invariant: is never a skip + LIns* _finalIns; // final instruction in the stream; ie. the first one to be read + + public: + LirReader(LIns* ins) : LirFilter(0), _ins(ins), _finalIns(ins) + { + // The last instruction for a fragment shouldn't be a skip. + // (Actually, if the last *inserted* instruction exactly fills up + // a chunk, a new chunk will be created, and thus the last *written* + // instruction will be a skip -- the one needed for the + // cross-chunk link. But the last *inserted* instruction is what + // is recorded and used to initialise each LirReader, and that is + // what is seen here, and therefore this assertion holds.) + NanoAssert(ins && !ins->isop(LIR_skip)); + } + virtual ~LirReader() {} + + // Returns next instruction and advances to the prior instruction. + // Invariant: never returns a skip. + LIns* read(); + + LIns* finalIns() { + return _finalIns; + } + }; + + verbose_only(void live(LirFilter* in, Allocator& alloc, Fragment* frag, LogControl*);) + + // WARNING: StackFilter assumes that all stack entries are eight bytes. + // Some of its optimisations aren't valid if that isn't true. See + // StackFilter::read() for more details. + class StackFilter: public LirFilter + { + LIns* sp; + BitSet stk; + int top; + int getTop(LIns* br); + + public: + StackFilter(LirFilter *in, Allocator& alloc, LIns* sp); + LIns* read(); + }; + + // This type is used to perform a simple interval analysis of 32-bit + // add/sub/mul. It lets us avoid overflow checks in some cases. + struct Interval + { + // The bounds are 64-bit integers so that any overflow from a 32-bit + // operation can be safely detected. + // + // If 'hasOverflowed' is false, 'lo' and 'hi' must be in the range + // I32_MIN..I32_MAX. If 'hasOverflowed' is true, 'lo' and 'hi' should + // not be trusted (and in debug builds we set them both to a special + // value UNTRUSTWORTHY that is outside the I32_MIN..I32_MAX range to + // facilitate sanity checking). + // + int64_t lo; + int64_t hi; + bool hasOverflowed; + + static const int64_t I32_MIN = int64_t(int32_t(0x80000000)); + static const int64_t I32_MAX = int64_t(int32_t(0x7fffffff)); + +#ifdef DEBUG + static const int64_t UNTRUSTWORTHY = int64_t(0xdeafdeadbeeffeedLL); + + bool isSane() { + return (hasOverflowed && lo == UNTRUSTWORTHY && hi == UNTRUSTWORTHY) || + (!hasOverflowed && lo <= hi && I32_MIN <= lo && hi <= I32_MAX); + } +#endif + + Interval(int64_t lo_, int64_t hi_) { + if (lo_ < I32_MIN || I32_MAX < hi_) { + hasOverflowed = true; +#ifdef DEBUG + lo = UNTRUSTWORTHY; + hi = UNTRUSTWORTHY; +#endif + } else { + hasOverflowed = false; + lo = lo_; + hi = hi_; + } + NanoAssert(isSane()); + } + + static Interval OverflowInterval() { + Interval interval(0, 0); +#ifdef DEBUG + interval.lo = UNTRUSTWORTHY; + interval.hi = UNTRUSTWORTHY; +#endif + interval.hasOverflowed = true; + return interval; + } + + static Interval of(LIns* ins, int32_t lim); + + static Interval add(Interval x, Interval y); + static Interval sub(Interval x, Interval y); + static Interval mul(Interval x, Interval y); + + bool canBeZero() { + NanoAssert(isSane()); + return hasOverflowed || (lo <= 0 && 0 <= hi); + } + + bool canBeNegative() { + NanoAssert(isSane()); + return hasOverflowed || (lo < 0); + } + }; + +#if NJ_SOFTFLOAT_SUPPORTED + struct SoftFloatOps + { + const CallInfo* opmap[LIR_sentinel]; + SoftFloatOps(); + }; + + extern const SoftFloatOps softFloatOps; + + // Replaces fpu ops with function calls, for platforms lacking float + // hardware (eg. some ARM machines). + class SoftFloatFilter: public LirWriter + { + public: + static const CallInfo* opmap[LIR_sentinel]; + + SoftFloatFilter(LirWriter *out); + LIns *split(LIns *a); + LIns *split(const CallInfo *call, LIns* args[]); + LIns *callD1(const CallInfo *call, LIns *a); + LIns *callD2(const CallInfo *call, LIns *a, LIns *b); + LIns *callI1(const CallInfo *call, LIns *a); + LIns *cmpD(const CallInfo *call, LIns *a, LIns *b); + LIns *ins1(LOpcode op, LIns *a); + LIns *ins2(LOpcode op, LIns *a, LIns *b); + LIns *insCall(const CallInfo *ci, LIns* args[]); + }; +#endif + +#ifdef DEBUG + // This class does thorough checking of LIR. It checks *implicit* LIR + // instructions, ie. LIR instructions specified via arguments -- to + // methods like insLoad() -- that have not yet been converted into + // *explicit* LIns objects in a LirBuffer. The reason for this is that if + // we wait until the LIR instructions are explicit, they will have gone + // through the entire writer pipeline and been optimised. By checking + // implicit LIR instructions we can check the LIR code at the start of the + // writer pipeline, exactly as it is generated by the compiler front-end. + // + // A general note about the errors produced by this class: for + // TraceMonkey, they won't include special names for instructions that + // have them unless TMFLAGS is specified. + class ValidateWriter : public LirWriter + { + private: + LInsPrinter* printer; + const char* whereInPipeline; + + const char* type2string(LTy type); + void typeCheckArgs(LOpcode op, int nArgs, LTy formals[], LIns* args[]); + void errorStructureShouldBe(LOpcode op, const char* argDesc, int argN, LIns* arg, + const char* shouldBeDesc); + void errorAccSet(const char* what, AccSet accSet, const char* shouldDesc); + void errorLoadQual(const char* what, LoadQual loadQual); + void checkLInsHasOpcode(LOpcode op, int argN, LIns* ins, LOpcode op2); + void checkLInsIsACondOrConst(LOpcode op, int argN, LIns* ins); + void checkLInsIsNull(LOpcode op, int argN, LIns* ins); + void checkAccSet(LOpcode op, LIns* base, int32_t disp, AccSet accSet); // defined by the embedder + + // These can be set by the embedder and used in checkAccSet(). + void** checkAccSetExtras; + + public: + ValidateWriter(LirWriter* out, LInsPrinter* printer, const char* where); + void setCheckAccSetExtras(void** extras) { checkAccSetExtras = extras; } + + LIns* insLoad(LOpcode op, LIns* base, int32_t d, AccSet accSet, LoadQual loadQual); + LIns* insStore(LOpcode op, LIns* value, LIns* base, int32_t d, AccSet accSet); + LIns* ins0(LOpcode v); + LIns* ins1(LOpcode v, LIns* a); + LIns* ins2(LOpcode v, LIns* a, LIns* b); + LIns* ins3(LOpcode v, LIns* a, LIns* b, LIns* c); + LIns* insParam(int32_t arg, int32_t kind); + LIns* insImmI(int32_t imm); +#ifdef NANOJIT_64BIT + LIns* insImmQ(uint64_t imm); +#endif + LIns* insImmD(double d); + LIns* insCall(const CallInfo *call, LIns* args[]); + LIns* insGuard(LOpcode v, LIns *c, GuardRecord *gr); + LIns* insGuardXov(LOpcode v, LIns* a, LIns* b, GuardRecord* gr); + LIns* insBranch(LOpcode v, LIns* condition, LIns* to); + LIns* insBranchJov(LOpcode v, LIns* a, LIns* b, LIns* to); + LIns* insAlloc(int32_t size); + LIns* insJtbl(LIns* index, uint32_t size); + }; + + // This just checks things that aren't possible to check in + // ValidateWriter, eg. whether all branch targets are set and are labels. + class ValidateReader: public LirFilter { + public: + ValidateReader(LirFilter* in); + LIns* read(); + }; +#endif + +#ifdef NJ_VERBOSE + /* A listing filter for LIR, going through backwards. It merely + passes its input to its output, but notes it down too. When + finish() is called, prints out what went through. Is intended to be + used to print arbitrary intermediate transformation stages of + LIR. */ + class ReverseLister : public LirFilter + { + Allocator& _alloc; + LInsPrinter* _printer; + const char* _title; + StringList _strs; + LogControl* _logc; + LIns* _prevIns; + public: + ReverseLister(LirFilter* in, Allocator& alloc, + LInsPrinter* printer, LogControl* logc, const char* title) + : LirFilter(in) + , _alloc(alloc) + , _printer(printer) + , _title(title) + , _strs(alloc) + , _logc(logc) + , _prevIns(NULL) + { } + + void finish(); + LIns* read(); + }; +#endif + +} +#endif // __nanojit_LIR__ diff --git a/js/src/nanojit/LIRopcode.tbl b/js/src/nanojit/LIRopcode.tbl new file mode 100644 index 0000000..4a30079 --- /dev/null +++ b/js/src/nanojit/LIRopcode.tbl @@ -0,0 +1,367 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=0 ft=c: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey nanojit. + * + * The Initial Developer of the Original Code is + * the Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jeff Walden + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This file is best viewed with 128 columns: +12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 + * + * Definitions of LIR opcodes. If you need to allocate an opcode, look + * for one defined using OP_UN() and claim it. + * + * Includers must define an OPxyz macro of the following form: + * + * #define OPxyz(op, number, repKind, retType) ... + * + * Selected arguments can then be used within the macro expansions. + * - op Opcode name, token-pasted after "LIR_" to form an LOpcode. + * - number Opcode number, used as the LOpcode enum value. + * - repKind Indicates how the instruction is represented in memory; XYZ + * corresponds to LInsXYZ and LRK_XYZ. + * - retType Type (LTy) of the value returned by the instruction. + * - isCse 0 if the opcode can never be CSE'd safely, 1 if it always + * can, -1 if things are more complicated -- in which case + * isCseOpcode() shouldn't be called on this opcode. + * + * Opcodes use type-indicators suffixes that are loosly based on C type names: + * - 'c': "char", ie. 8-bit integer + * - 's': "short", ie. 16-bit integer + * - 'i': "int", ie. 32-bit integer + * - 'q': "quad", ie. 64-bit integer + * - 'u': "unsigned", is used as a prefix on integer type-indicators when necessary + * - 'f': "float", ie. 32-bit floating point value + * - 'd': "double", ie. 64-bit floating point value + * - 'p': "pointer", ie. a int on 32-bit machines, a quad on 64-bit machines + * + * 'p' opcodes are all aliases of int and quad opcodes, they're given in LIR.h + * and chosen according to the platform pointer size. + * + * Certain opcodes aren't supported on all platforms, so OPxyz must be one of + * the following: + * + * OP___: for opcodes supported on all platforms. + * OP_UN: for opcodes not yet used on any platform. + * OP_32: for opcodes supported only on 32-bit platforms. + * OP_64: for opcodes supported only on 64-bit platforms. + * OP_SF: for opcodes supported only on SoftFloat platforms. + * OP_86: for opcodes supported only on i386/X64. + */ + +#define OP_UN(n) OP___(__##n, n, None, V, -1) + +#ifdef NANOJIT_64BIT +# define OP_32(a, b, c, d, e) OP_UN(b) +# define OP_64 OP___ +#else +# define OP_32 OP___ +# define OP_64(a, b, c, d, e) OP_UN(b) +#endif + +#if NJ_SOFTFLOAT_SUPPORTED +# define OP_SF OP___ +#else +# define OP_SF(a, b, c, d, e) OP_UN(b) +#endif + +#if defined NANOJIT_IA32 || defined NANOJIT_X64 +# define OP_86 OP___ +#else +# define OP_86(a, b, c, d, e) OP_UN(b) +#endif + +//--------------------------------------------------------------------------- +// Miscellaneous operations +//--------------------------------------------------------------------------- +OP___(start, 0, Op0, V, 0) // start of a fragment + +// A register fence causes no code to be generated, but it affects register +// allocation so that no registers are live when it is reached. +OP___(regfence, 1, Op0, V, 0) + +OP___(skip, 2, Sk, V, 0) // links code chunks + +OP_32(parami, 3, P, I, 0) // load an int parameter (register or stack location) +OP_64(paramq, 4, P, Q, 0) // load a quad parameter (register or stack location) + +OP___(allocp, 5, I, P, 0) // allocate stack space (result is an address) + +OP___(reti, 6, Op1, V, 0) // return an int +OP_64(retq, 7, Op1, V, 0) // return a quad +OP___(retd, 8, Op1, V, 0) // return a double + +OP___(livei, 9, Op1, V, 0) // extend live range of an int +OP_64(liveq, 10, Op1, V, 0) // extend live range of a quad +OP___(lived, 11, Op1, V, 0) // extend live range of a double + +OP___(file, 12, Op1, V, 0) // source filename for debug symbols +OP___(line, 13, Op1, V, 0) // source line number for debug symbols + +OP___(comment, 14, Op1, V, 0) // a comment shown, on its own line, in LIR dumps +OP_UN(15) +OP_UN(16) + +//--------------------------------------------------------------------------- +// Loads and stores +//--------------------------------------------------------------------------- +OP___(ldc2i, 17, Ld, I, -1) // load char and sign-extend to an int +OP___(lds2i, 18, Ld, I, -1) // load short and sign-extend to an int +OP___(lduc2ui, 19, Ld, I, -1) // load unsigned char and zero-extend to an unsigned int +OP___(ldus2ui, 20, Ld, I, -1) // load unsigned short and zero-extend to an unsigned int +OP___(ldi, 21, Ld, I, -1) // load int +OP_64(ldq, 22, Ld, Q, -1) // load quad +OP___(ldd, 23, Ld, D, -1) // load double +OP___(ldf2d, 24, Ld, D, -1) // load float and extend to a double + +OP___(sti2c, 25, St, V, 0) // store int truncated to char +OP___(sti2s, 26, St, V, 0) // store int truncated to short +OP___(sti, 27, St, V, 0) // store int +OP_64(stq, 28, St, V, 0) // store quad +OP___(std, 29, St, V, 0) // store double +OP___(std2f, 30, St, V, 0) // store double as a float (losing precision) + +OP_UN(31) +OP_UN(32) + +//--------------------------------------------------------------------------- +// Calls +//--------------------------------------------------------------------------- +OP___(callv, 33, C, V, -1) // call subroutine that returns void +OP___(calli, 34, C, I, -1) // call subroutine that returns an int +OP_64(callq, 35, C, Q, -1) // call subroutine that returns a quad +OP___(calld, 36, C, D, -1) // call subroutine that returns a double + +//--------------------------------------------------------------------------- +// Branches and labels +//--------------------------------------------------------------------------- +// 'jt' and 'jf' must be adjacent so that (op ^ 1) gives the opposite one. +// Static assertions in LIR.h check this requirement. +OP___(j, 37, Op2, V, 0) // jump always +OP___(jt, 38, Op2, V, 0) // jump if true +OP___(jf, 39, Op2, V, 0) // jump if false +OP___(jtbl, 40, Jtbl, V, 0) // jump to address in table + +OP___(label, 41, Op0, V, 0) // a jump target (no machine code is emitted for this) + +OP_UN(42) + +//--------------------------------------------------------------------------- +// Guards +//--------------------------------------------------------------------------- +// 'xt' and 'xf' must be adjacent so that (op ^ 1) gives the opposite one. +// Static assertions in LIR.h check this requirement. +OP___(x, 43, Op2, V, 0) // exit always +OP___(xt, 44, Op2, V, 1) // exit if true +OP___(xf, 45, Op2, V, 1) // exit if false +OP___(xtbl, 46, Op2, V, 0) // exit via indirect jump +// A LIR_xbarrier cause no code to be generated, but it acts like a never-taken +// guard in that it inhibits certain optimisations, such as dead stack store +// elimination. +OP___(xbarrier, 47, Op2, V, 0) + +OP_UN(48) + +//--------------------------------------------------------------------------- +// Immediates +//--------------------------------------------------------------------------- +OP___(immi, 49, I, I, 1) // int immediate +OP_64(immq, 50, QorD, Q, 1) // quad immediate +OP___(immd, 51, QorD, D, 1) // double immediate + +OP_UN(52) + +//--------------------------------------------------------------------------- +// Comparisons +//--------------------------------------------------------------------------- + +// All comparisons return an int: 0 on failure and 1 on success. +// +// Within each type group, order must be preserved so that, except for eq*, (op +// ^ 1) gives the opposite one (eg. lt ^ 1 == gt). eq* must have odd numbers +// for this to work. They must also remain contiguous so that opcode range +// checking works correctly. Static assertions in LIR.h check these +// requirements. +OP___(eqi, 53, Op2, I, 1) // int equality +OP___(lti, 54, Op2, I, 1) // signed int less-than +OP___(gti, 55, Op2, I, 1) // signed int greater-than +OP___(lei, 56, Op2, I, 1) // signed int less-than-or-equal +OP___(gei, 57, Op2, I, 1) // signed int greater-than-or-equal +OP___(ltui, 58, Op2, I, 1) // unsigned int less-than +OP___(gtui, 59, Op2, I, 1) // unsigned int greater-than +OP___(leui, 60, Op2, I, 1) // unsigned int less-than-or-equal +OP___(geui, 61, Op2, I, 1) // unsigned int greater-than-or-equal + +OP_UN(62) + +OP_64(eqq, 63, Op2, I, 1) // quad equality +OP_64(ltq, 64, Op2, I, 1) // signed quad less-than +OP_64(gtq, 65, Op2, I, 1) // signed quad greater-than +OP_64(leq, 66, Op2, I, 1) // signed quad less-than-or-equal +OP_64(geq, 67, Op2, I, 1) // signed quad greater-than-or-equal +OP_64(ltuq, 68, Op2, I, 1) // unsigned quad less-than +OP_64(gtuq, 69, Op2, I, 1) // unsigned quad greater-than +OP_64(leuq, 70, Op2, I, 1) // unsigned quad less-than-or-equal +OP_64(geuq, 71, Op2, I, 1) // unsigned quad greater-than-or-equal + +OP_UN(72) + +OP___(eqd, 73, Op2, I, 1) // double equality +OP___(ltd, 74, Op2, I, 1) // double less-than +OP___(gtd, 75, Op2, I, 1) // double greater-than +OP___(led, 76, Op2, I, 1) // double less-than-or-equal +OP___(ged, 77, Op2, I, 1) // double greater-than-or-equal + +//--------------------------------------------------------------------------- +// Arithmetic +//--------------------------------------------------------------------------- +OP___(negi, 78, Op1, I, 1) // negate int +OP___(addi, 79, Op2, I, 1) // add int +OP___(subi, 80, Op2, I, 1) // subtract int +OP___(muli, 81, Op2, I, 1) // multiply int +OP_86(divi, 82, Op2, I, 1) // divide int +// LIR_modi is a hack. It's only used on i386/X64. The operand is the result +// of a LIR_divi because on i386/X64 div and mod results are computed by the +// same instruction. +OP_86(modi, 83, Op1, I, 1) // modulo int + +OP___(noti, 84, Op1, I, 1) // bitwise-NOT int +OP___(andi, 85, Op2, I, 1) // bitwise-AND int +OP___(ori, 86, Op2, I, 1) // bitwise-OR int +OP___(xori, 87, Op2, I, 1) // bitwise-XOR int + +// For all three integer shift operations, only the bottom five bits of the +// second operand are used, and they are treated as unsigned. This matches +// x86 semantics. +OP___(lshi, 88, Op2, I, 1) // left shift int +OP___(rshi, 89, Op2, I, 1) // right shift int (>>) +OP___(rshui, 90, Op2, I, 1) // right shift unsigned int (>>>) + +OP_64(addq, 91, Op2, Q, 1) // add quad +OP_64(subq, 92, Op2, Q, 1) // subtract quad + +OP_64(andq, 93, Op2, Q, 1) // bitwise-AND quad +OP_64(orq, 94, Op2, Q, 1) // bitwise-OR quad +OP_64(xorq, 95, Op2, Q, 1) // bitwise-XOR quad + +// For all three quad shift operations, only the bottom six bits of the +// second operand are used, and they are treated as unsigned. This matches +// x86-64 semantics. +OP_64(lshq, 96, Op2, Q, 1) // left shift quad; 2nd operand is an int +OP_64(rshq, 97, Op2, Q, 1) // right shift quad; 2nd operand is an int +OP_64(rshuq, 98, Op2, Q, 1) // right shift unsigned quad; 2nd operand is an int + +OP___(negd, 99, Op1, D, 1) // negate double +OP___(addd, 100, Op2, D, 1) // add double +OP___(subd, 101, Op2, D, 1) // subtract double +OP___(muld, 102, Op2, D, 1) // multiply double +OP___(divd, 103, Op2, D, 1) // divide double +// LIR_modd is just a place-holder opcode, ie. the back-ends cannot generate +// code for it. It's used in TraceMonkey briefly but is always demoted to a +// LIR_modl or converted to a function call before Nanojit has to do anything +// serious with it. +OP___(modd, 104, Op2, D, 1) // modulo double + +OP___(cmovi, 105, Op3, I, 1) // conditional move int +OP_64(cmovq, 106, Op3, Q, 1) // conditional move quad +OP___(cmovd, 107, Op3, D, 1) // conditional move double + +//--------------------------------------------------------------------------- +// Conversions +//--------------------------------------------------------------------------- +OP_64(i2q, 108, Op1, Q, 1) // sign-extend int to quad +OP_64(ui2uq, 109, Op1, Q, 1) // zero-extend unsigned int to unsigned quad +OP_64(q2i, 110, Op1, I, 1) // truncate quad to int (removes the high 32 bits) + +OP___(i2d, 111, Op1, D, 1) // convert int to double +OP___(ui2d, 112, Op1, D, 1) // convert unsigned int to double + +// The rounding behavior of LIR_d2i is platform specific. +// +// Platform Asm code Behavior +// -------- -------- -------- +// x86 w/ x87 fist uses current FP control word (default is rounding) +// x86 w/ SSE cvttsd2si performs round to zero (truncate) +// x64 (SSE) cvttsd2si performs round to zero (truncate) +// PowerPC unsupported +// ARM ftosid round to nearest +// MIPS trunc.w.d performs round to zero (truncate) +// SH4 frtc performs round to zero (truncate) +// SPARC fdtoi performs round to zero (truncate) +// +// round to zero examples: 1.9 -> 1, 1.1 -> 1, -1.1 -> -1, -1.9 -> -1 +// round to nearest examples: 1.9 -> 2, 1.1 -> 1, -1.1 -> -1, -1.9 -> -2 +OP___(d2i, 113, Op1, I, 1) // convert double to int (no exceptions raised) + +OP_64(dasq, 114, Op1, Q, 1) // interpret the bits of a double as a quad +OP_64(qasd, 115, Op1, D, 1) // interpret the bits of a quad as a double + +//--------------------------------------------------------------------------- +// Overflow arithmetic +//--------------------------------------------------------------------------- +// These all exit if overflow occurred. The result is valid on either path. +OP___(addxovi, 116, Op3, I, 1) // add int and exit on overflow +OP___(subxovi, 117, Op3, I, 1) // subtract int and exit on overflow +OP___(mulxovi, 118, Op3, I, 1) // multiply int and exit on overflow + +// These all branch if overflow occurred. The result is valid on either path. +OP___(addjovi, 119, Op3, I, 1) // add int and branch on overflow +OP___(subjovi, 120, Op3, I, 1) // subtract int and branch on overflow +OP___(muljovi, 121, Op3, I, 1) // multiply int and branch on overflow + +OP_64(addjovq, 122, Op3, Q, 1) // add quad and branch on overflow +OP_64(subjovq, 123, Op3, Q, 1) // subtract quad and branch on overflow + +//--------------------------------------------------------------------------- +// SoftFloat +//--------------------------------------------------------------------------- +OP_SF(dlo2i, 124, Op1, I, 1) // get the low 32 bits of a double as an int +OP_SF(dhi2i, 125, Op1, I, 1) // get the high 32 bits of a double as an int +OP_SF(ii2d, 126, Op2, D, 1) // join two ints (1st arg is low bits, 2nd is high) + +// LIR_hcalli is a hack that's only used on 32-bit platforms that use +// SoftFloat. Its operand is always a LIR_calli, but one that specifies a +// function that returns a double. It indicates that the double result is +// returned via two 32-bit integer registers. The result is always used as the +// second operand of a LIR_ii2d. +OP_SF(hcalli, 127, Op1, I, 1) + +#undef OP_UN +#undef OP_32 +#undef OP_64 +#undef OP_SF +#undef OP_86 diff --git a/js/src/nanojit/Native.h b/js/src/nanojit/Native.h new file mode 100644 index 0000000..dc67b13 --- /dev/null +++ b/js/src/nanojit/Native.h @@ -0,0 +1,193 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#ifndef __nanojit_Native__ +#define __nanojit_Native__ + +// define PEDANTIC=1 to ignore specialized forms, force general forms +// for everything, far branches, extra page-linking, etc. This will +// flush out many corner cases. + +#define PEDANTIC 0 +#if PEDANTIC +# define UNLESS_PEDANTIC(...) +# define IF_PEDANTIC(...) __VA_ARGS__ +#else +# define UNLESS_PEDANTIC(...) __VA_ARGS__ +# define IF_PEDANTIC(...) +#endif + +#ifdef NANOJIT_IA32 +#include "Nativei386.h" +#elif defined(NANOJIT_ARM) +#include "NativeARM.h" +#elif defined(NANOJIT_PPC) +#include "NativePPC.h" +#elif defined(NANOJIT_SPARC) +#include "NativeSparc.h" +#elif defined(NANOJIT_X64) +#include "NativeX64.h" +#elif defined(NANOJIT_SH4) +#include "NativeSH4.h" +#elif defined(NANOJIT_MIPS) +#include "NativeMIPS.h" +#else +#error "unknown nanojit architecture" +#endif + +#ifndef NJ_USES_IMMD_POOL +# define NJ_USES_IMMD_POOL 0 +#endif + +#ifndef NJ_JTBL_SUPPORTED +# define NJ_JTBL_SUPPORTED 0 +#endif + +#ifndef NJ_EXPANDED_LOADSTORE_SUPPORTED +# define NJ_EXPANDED_LOADSTORE_SUPPORTED 0 +#endif + +#ifndef NJ_F2I_SUPPORTED +# define NJ_F2I_SUPPORTED 0 +#endif + +#ifndef NJ_SOFTFLOAT_SUPPORTED +# define NJ_SOFTFLOAT_SUPPORTED 0 +#endif + +#ifndef NJ_DIVI_SUPPORTED +# define NJ_DIVI_SUPPORTED 0 +#endif + +#if NJ_SOFTFLOAT_SUPPORTED + #define CASESF(x) case x +#else + #define CASESF(x) +#endif + +namespace nanojit { + + class Fragment; + struct SideExit; + struct SwitchInfo; + + struct GuardRecord + { + void* jmp; + GuardRecord* next; + SideExit* exit; + // profiling stuff + verbose_only( uint32_t profCount; ) + verbose_only( uint32_t profGuardID; ) + verbose_only( GuardRecord* nextInFrag; ) + }; + + struct SideExit + { + GuardRecord* guards; + Fragment* from; + Fragment* target; + SwitchInfo* switchInfo; + + void addGuard(GuardRecord* gr) + { + NanoAssert(gr->next == NULL); + NanoAssert(guards != gr); + gr->next = guards; + guards = gr; + } + }; +} + + #define isSPorFP(r) ( (r)==SP || (r)==FP ) + + #ifdef NJ_NO_VARIADIC_MACROS + static void asm_output(const char *f, ...) {} + #define gpn(r) regNames[(REGNUM(n))] + #elif defined(NJ_VERBOSE) + inline char cvaltoa(unsigned char u) { + return u<10 ? u+'0' : u+'a'-10; + } + + inline char* appendHexVals(char* str, char* valFrom, char* valTo) { + NanoAssert(valFrom <= valTo); + str += VMPI_strlen(str); + for(char* ch = valFrom; ch < valTo; ch++) { + unsigned char u = (unsigned char)*ch; + *str++ = cvaltoa(u >> 4); + *str++ = cvaltoa(u & 0xf); + *str++ = ' '; + } + *str = '\0'; + return str; + } + + inline char* padTo(char* str, int n, char c=' ') { + char* start = str + VMPI_strlen(str); + char* end = &str[n]; + while(start < end) + *start++ = c; + *end = '\0'; + return end; + } + + // Used for printing native instructions. Like Assembler::outputf(), + // but only outputs if LC_Native is set. Also prepends the output + // with the address of the current native instruction. + #define asm_output(...) do { \ + if (_logc->lcbits & LC_Native) { \ + outline[0]='\0'; \ + VMPI_sprintf(outline, "%p ", _nIns); \ + if (_logc->lcbits & LC_Bytes) { \ + appendHexVals(outline, (char*)_nIns, (char*)_nInsAfter); \ + padTo(outline, 3*15); \ + } \ + VMPI_sprintf(outline + VMPI_strlen(outline), ##__VA_ARGS__); \ + output(); \ + _nInsAfter = _nIns; \ + } \ + } while (0) /* no semi */ + #define gpn(r) regNames[(REGNUM(r))] + #else + #define asm_output(...) + #define gpn(r) + #endif /* NJ_VERBOSE */ + +#endif // __nanojit_Native__ diff --git a/js/src/nanojit/NativeARM.cpp b/js/src/nanojit/NativeARM.cpp new file mode 100644 index 0000000..1c38cac --- /dev/null +++ b/js/src/nanojit/NativeARM.cpp @@ -0,0 +1,2928 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * Vladimir Vukicevic + * Jacob Bramley + * Tero Koskinen + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nanojit.h" + +#ifdef UNDER_CE +#include +#endif + +#if defined(FEATURE_NANOJIT) && defined(NANOJIT_ARM) + +namespace nanojit +{ + +#ifdef NJ_VERBOSE +const char* regNames[] = {"r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","r10","fp","ip","sp","lr","pc", + "d0","d1","d2","d3","d4","d5","d6","d7","s0"}; +const char* condNames[] = {"eq","ne","cs","cc","mi","pl","vs","vc","hi","ls","ge","lt","gt","le",""/*al*/,"nv"}; +const char* shiftNames[] = { "lsl", "lsl", "lsr", "lsr", "asr", "asr", "ror", "ror" }; +#endif + +const Register Assembler::argRegs[] = { R0, R1, R2, R3 }; +const Register Assembler::retRegs[] = { R0, R1 }; +const Register Assembler::savedRegs[] = { R4, R5, R6, R7, R8, R9, R10 }; + +// -------------------------------- +// ARM-specific utility functions. +// -------------------------------- + +#ifdef DEBUG +// Return true if enc is a valid Operand 2 encoding and thus can be used as-is +// in an ARM arithmetic operation that accepts such encoding. +// +// This utility does not know (or determine) the actual value that the encoded +// value represents, and thus cannot be used to ensure the correct operation of +// encOp2Imm, but it does ensure that the encoded value can be used to encode a +// valid ARM instruction. decOp2Imm can be used if you also need to check that +// a literal is correctly encoded (and thus that encOp2Imm is working +// correctly). +inline bool +Assembler::isOp2Imm(uint32_t enc) +{ + return ((enc & 0xfff) == enc); +} + +// Decodes operand 2 immediate values (for debug output and assertions). +inline uint32_t +Assembler::decOp2Imm(uint32_t enc) +{ + NanoAssert(isOp2Imm(enc)); + + uint32_t imm8 = enc & 0xff; + uint32_t rot = 32 - ((enc >> 7) & 0x1e); + + return imm8 << (rot & 0x1f); +} +#endif + +// Calculate the number of leading zeroes in data. +static inline uint32_t +CountLeadingZeroesSlow(uint32_t data) +{ + // Other platforms must fall back to a C routine. This won't be as + // efficient as the CLZ instruction, but it is functional. + uint32_t try_shift; + + uint32_t leading_zeroes = 0; + + // This loop does a bisection search rather than the obvious rotation loop. + // This should be faster, though it will still be no match for CLZ. + for (try_shift = 16; try_shift != 0; try_shift /= 2) { + uint32_t shift = leading_zeroes + try_shift; + if (((data << shift) >> shift) == data) { + leading_zeroes = shift; + } + } + + return leading_zeroes; +} + +inline uint32_t +Assembler::CountLeadingZeroes(uint32_t data) +{ + uint32_t leading_zeroes; + +#if defined(__ARMCC__) + // ARMCC can do this with an intrinsic. + leading_zeroes = __clz(data); +#elif defined(__GNUC__) + // GCC can use inline assembler to insert a CLZ instruction. + if (ARM_ARCH_AT_LEAST(5)) { + __asm ( +#if defined(ANDROID) && (NJ_COMPILER_ARM_ARCH < 7) + // On Android gcc compiler, the clz instruction is not supported with a + // target smaller than armv7, despite it being legal for armv5+. + " .arch armv7-a\n" +#elif (NJ_COMPILER_ARM_ARCH < 5) + // Targetting armv5t allows a toolchain with armv4t target to still build + // with clz, and clz to be used when appropriate at runtime. + " .arch armv5t\n" +#endif + " clz %0, %1 \n" + : "=r" (leading_zeroes) + : "r" (data) + ); + } else { + leading_zeroes = CountLeadingZeroesSlow(data); + } +#elif defined(UNDER_CE) + // WinCE can do this with an intrinsic. + leading_zeroes = _CountLeadingZeros(data); +#else + leading_zeroes = CountLeadingZeroesSlow(data); +#endif + + // Assert that the operation worked! + NanoAssert(((0xffffffff >> leading_zeroes) & data) == data); + + return leading_zeroes; +} + +// The ARM instruction set allows some flexibility to the second operand of +// most arithmetic operations. When operand 2 is an immediate value, it takes +// the form of an 8-bit value rotated by an even value in the range 0-30. +// +// Some values that can be encoded this scheme — such as 0xf000000f — are +// probably fairly rare in practice and require extra code to detect, so this +// function implements a fast CLZ-based heuristic to detect any value that can +// be encoded using just a shift, and not a full rotation. For example, +// 0xff000000 and 0x000000ff are both detected, but 0xf000000f is not. +// +// This function will return true to indicate that the encoding was successful, +// or false to indicate that the literal could not be encoded as an operand 2 +// immediate. If successful, the encoded value will be written to *enc. +inline bool +Assembler::encOp2Imm(uint32_t literal, uint32_t * enc) +{ + // The number of leading zeroes in the literal. This is used to calculate + // the rotation component of the encoding. + uint32_t leading_zeroes; + + // Components of the operand 2 encoding. + int32_t rot; + uint32_t imm8; + + // Check the literal to see if it is a simple 8-bit value. I suspect that + // most literals are in fact small values, so doing this check early should + // give a decent speed-up. + if (literal < 256) + { + *enc = literal; + return true; + } + + // Determine the number of leading zeroes in the literal. This is used to + // calculate the required rotation. + leading_zeroes = CountLeadingZeroes(literal); + + // We've already done a check to see if the literal is an 8-bit value, so + // leading_zeroes must be less than (and not equal to) (32-8)=24. However, + // if it is greater than 24, this algorithm will break, so debug code + // should use an assertion here to check that we have a value that we + // expect. + NanoAssert(leading_zeroes < 24); + + // Assuming that we have a field of no more than 8 bits for a valid + // literal, we can calculate the required rotation by subtracting + // leading_zeroes from (32-8): + // + // Example: + // 0: Known to be zero. + // 1: Known to be one. + // X: Either zero or one. + // .: Zero in a valid operand 2 literal. + // + // Literal: [ 1XXXXXXX ........ ........ ........ ] + // leading_zeroes = 0 + // Therefore rot (left) = 24. + // Encoded 8-bit literal: [ 1XXXXXXX ] + // + // Literal: [ ........ ..1XXXXX XX...... ........ ] + // leading_zeroes = 10 + // Therefore rot (left) = 14. + // Encoded 8-bit literal: [ 1XXXXXXX ] + // + // Note, however, that we can only encode even shifts, and so + // "rot=24-leading_zeroes" is not sufficient by itself. By ignoring + // zero-bits in odd bit positions, we can ensure that we get a valid + // encoding. + // + // Example: + // Literal: [ 01XXXXXX ........ ........ ........ ] + // leading_zeroes = 1 + // Therefore rot (left) = round_up(23) = 24. + // Encoded 8-bit literal: [ 01XXXXXX ] + rot = 24 - (leading_zeroes & ~1); + + // The imm8 component of the operand 2 encoding can be calculated from the + // rot value. + imm8 = literal >> rot; + + // The validity of the literal can be checked by reversing the + // calculation. It is much easier to decode the immediate than it is to + // encode it! + if (literal != (imm8 << rot)) { + // The encoding is not valid, so report the failure. Calling code + // should use some other method of loading the value (such as LDR). + return false; + } + + // The operand is valid, so encode it. + // Note that the ARM encoding is actually described by a rotate to the + // _right_, so rot must be negated here. Calculating a left shift (rather + // than calculating a right rotation) simplifies the above code. + *enc = ((-rot << 7) & 0xf00) | imm8; + + // Assert that the operand was properly encoded. + NanoAssert(decOp2Imm(*enc) == literal); + + return true; +} + +// Encode "rd = rn + imm" using an appropriate instruction sequence. +// Set stat to 1 to update the status flags. Otherwise, set it to 0 or omit it. +// (The declaration in NativeARM.h defines the default value of stat as 0.) +// +// It is not valid to call this function if: +// (rd == IP) AND (rn == IP) AND !encOp2Imm(imm) AND !encOp2Imm(-imm) +// Where: if (encOp2Imm(imm)), imm can be encoded as an ARM operand 2 using the +// encOp2Imm method. +void +Assembler::asm_add_imm(Register rd, Register rn, int32_t imm, int stat /* =0 */) +{ + // Operand 2 encoding of the immediate. + uint32_t op2imm; + + NanoAssert(IsGpReg(rd)); + NanoAssert(IsGpReg(rn)); + NanoAssert((stat & 1) == stat); + + // As a special case to simplify code elsewhere, emit nothing where we + // don't want to update the flags (stat == 0), the second operand is 0 and + // (rd == rn). Such instructions are effectively NOPs. + if ((imm == 0) && (stat == 0) && (rd == rn)) { + return; + } + + // Try to encode the value directly as an operand 2 immediate value, then + // fall back to loading the value into a register. + if (encOp2Imm(imm, &op2imm)) { + ADDis(rd, rn, op2imm, stat); + } else if (encOp2Imm(-imm, &op2imm)) { + // We could not encode the value for ADD, so try to encode it for SUB. + // Note that this is valid even if stat is set, _unless_ imm is 0, but + // that case is caught above. + NanoAssert(imm != 0); + SUBis(rd, rn, op2imm, stat); + } else { + // We couldn't encode the value directly, so use an intermediate + // register to encode the value. We will use IP to do this unless rn is + // IP; in that case we can reuse rd. This allows every case other than + // "ADD IP, IP, =#imm". + Register rm = (rn == IP) ? (rd) : (IP); + NanoAssert(rn != rm); + + ADDs(rd, rn, rm, stat); + asm_ld_imm(rm, imm); + } +} + +// Encode "rd = rn - imm" using an appropriate instruction sequence. +// Set stat to 1 to update the status flags. Otherwise, set it to 0 or omit it. +// (The declaration in NativeARM.h defines the default value of stat as 0.) +// +// It is not valid to call this function if: +// (rd == IP) AND (rn == IP) AND !encOp2Imm(imm) AND !encOp2Imm(-imm) +// Where: if (encOp2Imm(imm)), imm can be encoded as an ARM operand 2 using the +// encOp2Imm method. +void +Assembler::asm_sub_imm(Register rd, Register rn, int32_t imm, int stat /* =0 */) +{ + // Operand 2 encoding of the immediate. + uint32_t op2imm; + + NanoAssert(IsGpReg(rd)); + NanoAssert(IsGpReg(rn)); + NanoAssert((stat & 1) == stat); + + // As a special case to simplify code elsewhere, emit nothing where we + // don't want to update the flags (stat == 0), the second operand is 0 and + // (rd == rn). Such instructions are effectively NOPs. + if ((imm == 0) && (stat == 0) && (rd == rn)) { + return; + } + + // Try to encode the value directly as an operand 2 immediate value, then + // fall back to loading the value into a register. + if (encOp2Imm(imm, &op2imm)) { + SUBis(rd, rn, op2imm, stat); + } else if (encOp2Imm(-imm, &op2imm)) { + // We could not encode the value for SUB, so try to encode it for ADD. + // Note that this is valid even if stat is set, _unless_ imm is 0, but + // that case is caught above. + NanoAssert(imm != 0); + ADDis(rd, rn, op2imm, stat); + } else { + // We couldn't encode the value directly, so use an intermediate + // register to encode the value. We will use IP to do this unless rn is + // IP; in that case we can reuse rd. This allows every case other than + // "SUB IP, IP, =#imm". + Register rm = (rn == IP) ? (rd) : (IP); + NanoAssert(rn != rm); + + SUBs(rd, rn, rm, stat); + asm_ld_imm(rm, imm); + } +} + +// Encode "rd = rn & imm" using an appropriate instruction sequence. +// Set stat to 1 to update the status flags. Otherwise, set it to 0 or omit it. +// (The declaration in NativeARM.h defines the default value of stat as 0.) +// +// It is not valid to call this function if: +// (rd == IP) AND (rn == IP) AND !encOp2Imm(imm) AND !encOp2Imm(~imm) +// Where: if (encOp2Imm(imm)), imm can be encoded as an ARM operand 2 using the +// encOp2Imm method. +void +Assembler::asm_and_imm(Register rd, Register rn, int32_t imm, int stat /* =0 */) +{ + // Operand 2 encoding of the immediate. + uint32_t op2imm; + + NanoAssert(IsGpReg(rd)); + NanoAssert(IsGpReg(rn)); + NanoAssert((stat & 1) == stat); + + // Try to encode the value directly as an operand 2 immediate value, then + // fall back to loading the value into a register. + if (encOp2Imm(imm, &op2imm)) { + ANDis(rd, rn, op2imm, stat); + } else if (encOp2Imm(~imm, &op2imm)) { + // Use BIC with the inverted immediate. + BICis(rd, rn, op2imm, stat); + } else { + // We couldn't encode the value directly, so use an intermediate + // register to encode the value. We will use IP to do this unless rn is + // IP; in that case we can reuse rd. This allows every case other than + // "AND IP, IP, =#imm". + Register rm = (rn == IP) ? (rd) : (IP); + NanoAssert(rn != rm); + + ANDs(rd, rn, rm, stat); + asm_ld_imm(rm, imm); + } +} + +// Encode "rd = rn | imm" using an appropriate instruction sequence. +// Set stat to 1 to update the status flags. Otherwise, set it to 0 or omit it. +// (The declaration in NativeARM.h defines the default value of stat as 0.) +// +// It is not valid to call this function if: +// (rd == IP) AND (rn == IP) AND !encOp2Imm(imm) +// Where: if (encOp2Imm(imm)), imm can be encoded as an ARM operand 2 using the +// encOp2Imm method. +void +Assembler::asm_orr_imm(Register rd, Register rn, int32_t imm, int stat /* =0 */) +{ + // Operand 2 encoding of the immediate. + uint32_t op2imm; + + NanoAssert(IsGpReg(rd)); + NanoAssert(IsGpReg(rn)); + NanoAssert((stat & 1) == stat); + + // Try to encode the value directly as an operand 2 immediate value, then + // fall back to loading the value into a register. + if (encOp2Imm(imm, &op2imm)) { + ORRis(rd, rn, op2imm, stat); + } else { + // We couldn't encode the value directly, so use an intermediate + // register to encode the value. We will use IP to do this unless rn is + // IP; in that case we can reuse rd. This allows every case other than + // "ORR IP, IP, =#imm". + Register rm = (rn == IP) ? (rd) : (IP); + NanoAssert(rn != rm); + + ORRs(rd, rn, rm, stat); + asm_ld_imm(rm, imm); + } +} + +// Encode "rd = rn ^ imm" using an appropriate instruction sequence. +// Set stat to 1 to update the status flags. Otherwise, set it to 0 or omit it. +// (The declaration in NativeARM.h defines the default value of stat as 0.) +// +// It is not valid to call this function if: +// (rd == IP) AND (rn == IP) AND !encOp2Imm(imm) +// Where: if (encOp2Imm(imm)), imm can be encoded as an ARM operand 2 using the +// encOp2Imm method. +void +Assembler::asm_eor_imm(Register rd, Register rn, int32_t imm, int stat /* =0 */) +{ + // Operand 2 encoding of the immediate. + uint32_t op2imm; + + NanoAssert(IsGpReg(rd)); + NanoAssert(IsGpReg(rn)); + NanoAssert((stat & 1) == stat); + + // Try to encode the value directly as an operand 2 immediate value, then + // fall back to loading the value into a register. + if (encOp2Imm(imm, &op2imm)) { + EORis(rd, rn, op2imm, stat); + } else { + // We couldn't encoder the value directly, so use an intermediate + // register to encode the value. We will use IP to do this unless rn is + // IP; in that case we can reuse rd. This allows every case other than + // "EOR IP, IP, =#imm". + Register rm = (rn == IP) ? (rd) : (IP); + NanoAssert(rn != rm); + + EORs(rd, rn, rm, stat); + asm_ld_imm(rm, imm); + } +} + +// -------------------------------- +// Assembler functions. +// -------------------------------- + +void +Assembler::nInit(AvmCore*) +{ + nHints[LIR_calli] = rmask(retRegs[0]); + nHints[LIR_hcalli] = rmask(retRegs[1]); + nHints[LIR_paramp] = PREFER_SPECIAL; +} + +void Assembler::nBeginAssembly() +{ + max_out_args = 0; +} + +NIns* +Assembler::genPrologue() +{ + /** + * Prologue + */ + + // NJ_RESV_OFFSET is space at the top of the stack for us + // to use for parameter passing (8 bytes at the moment) + uint32_t stackNeeded = max_out_args + STACK_GRANULARITY * _activation.stackSlotsNeeded(); + uint32_t savingCount = 2; + + uint32_t savingMask = rmask(FP) | rmask(LR); + + // so for alignment purposes we've pushed return addr and fp + uint32_t stackPushed = STACK_GRANULARITY * savingCount; + uint32_t aligned = alignUp(stackNeeded + stackPushed, NJ_ALIGN_STACK); + int32_t amt = aligned - stackPushed; + + // Make room on stack for what we are doing + if (amt) + asm_sub_imm(SP, SP, amt); + + verbose_only( asm_output("## %p:",(void*)_nIns); ) + verbose_only( asm_output("## patch entry"); ) + NIns *patchEntry = _nIns; + + MOV(FP, SP); + PUSH_mask(savingMask); + return patchEntry; +} + +void +Assembler::nFragExit(LIns* guard) +{ + SideExit * exit = guard->record()->exit; + Fragment * frag = exit->target; + + bool target_is_known = frag && frag->fragEntry; + + if (target_is_known) { + // The target exists so we can simply emit a branch to its location. + JMP_far(frag->fragEntry); + } else { + // The target doesn't exit yet, so emit a jump to the epilogue. If the + // target is created later on, the jump will be patched. + + GuardRecord *gr = guard->record(); + + if (!_epilogue) + _epilogue = genEpilogue(); + + // Jump to the epilogue. This may get patched later, but JMP_far always + // emits two instructions even when only one is required, so patching + // will work correctly. + JMP_far(_epilogue); + + // In the future you may want to move this further down so that we can + // overwrite the r0 guard record load during a patch to a different + // fragment with some assumed input-register state. Not today though. + gr->jmp = _nIns; + + // NB: this is a workaround for the fact that, by patching a + // fragment-exit jump, we could be changing the *meaning* of the R0 + // register we're passing to the jump target. If we jump to the + // epilogue, ideally R0 means "return value when exiting fragment". + // If we patch this to jump to another fragment however, R0 means + // "incoming 0th parameter". This is just a quirk of ARM ABI. So + // we compromise by passing "return value" to the epilogue in IP, + // not R0, and have the epilogue MOV(R0, IP) first thing. + + asm_ld_imm(IP, int(gr)); + } + +#ifdef NJ_VERBOSE + if (_config.arm_show_stats) { + // load R1 with Fragment *fromFrag, target fragment + // will make use of this when calling fragenter(). + int fromfrag = int((Fragment*)_thisfrag); + asm_ld_imm(argRegs[1], fromfrag); + } +#endif + + // profiling for the exit + verbose_only( + if (_logc->lcbits & LC_FragProfile) { + asm_inc_m32( &guard->record()->profCount ); + } + ) + + // Pop the stack frame. + MOV(SP, FP); +} + +NIns* +Assembler::genEpilogue() +{ + RegisterMask savingMask; + + if (ARM_ARCH_AT_LEAST(5)) { + // On ARMv5+, loading directly to PC correctly handles interworking. + savingMask = rmask(FP) | rmask(PC); + + } else { + // On ARMv4T, interworking is not handled properly, therefore, we pop + // lr and use bx lr to avoid that. + savingMask = rmask(FP) | rmask(LR); + BX(LR); + } + POP_mask(savingMask); // regs + + // NB: this is the later half of the dual-nature patchable exit branch + // workaround noted above in nFragExit. IP has the "return value" + // incoming, we need to move it to R0. + MOV(R0, IP); + + return _nIns; +} + +/* + * asm_arg will encode the specified argument according to the current ABI, and + * will update r and stkd as appropriate so that the next argument can be + * encoded. + * + * Linux has used ARM's EABI for some time. Windows CE uses the legacy ABI. + * + * Under EABI: + * - doubles are 64-bit aligned both in registers and on the stack. + * If the next available argument register is R1, it is skipped + * and the double is placed in R2:R3. If R0:R1 or R2:R3 are not + * available, the double is placed on the stack, 64-bit aligned. + * - 32-bit arguments are placed in registers and 32-bit aligned + * on the stack. + * + * Under EABI with hardware floating-point procedure-call variant: + * - Same as EABI, but doubles are passed in D0..D7 registers. + * + * Under legacy ABI: + * - doubles are placed in subsequent arg registers; if the next + * available register is r3, the low order word goes into r3 + * and the high order goes on the stack. + * - 32-bit arguments are placed in the next available arg register, + * - both doubles and 32-bit arguments are placed on stack with 32-bit + * alignment. + */ +void +Assembler::asm_arg(ArgType ty, LIns* arg, ParameterRegisters& params) +{ + // The stack pointer must always be at least aligned to 4 bytes. + NanoAssert((params.stkd & 3) == 0); + + if (ty == ARGTYPE_D) { + // This task is fairly complex and so is delegated to asm_arg_64. + asm_arg_64(arg, params); + } else { + NanoAssert(ty == ARGTYPE_I || ty == ARGTYPE_UI); + // pre-assign registers R0-R3 for arguments (if they fit) + if (params.r < R4) { + asm_regarg(ty, arg, params.r); + params.r = Register(params.r + 1); + } else { + asm_stkarg(arg, params.stkd); + params.stkd += 4; + } + } +} + +// Encode a 64-bit floating-point argument using the appropriate ABI. +// This function operates in the same way as asm_arg, except that it will only +// handle arguments where (ArgType)ty == ARGTYPE_D. + +#ifdef NJ_ARM_EABI_HARD_FLOAT +void +Assembler::asm_arg_64(LIns* arg, ParameterRegisters& params) +{ + NanoAssert(IsFpReg(params.float_r)); + if (params.float_r <= D7) { + findSpecificRegFor(arg, params.float_r); + params.float_r = Register(params.float_r + 1); + } else { + NanoAssertMsg(0, "Only 8 floating point arguments supported"); + } +} + +#else +void +Assembler::asm_arg_64(LIns* arg, ParameterRegisters& params) +{ + // The stack pointer must always be at least aligned to 4 bytes. + NanoAssert((params.stkd & 3) == 0); + // The only use for this function when we are using soft floating-point + // is for LIR_ii2d. + NanoAssert(ARM_VFP || arg->isop(LIR_ii2d)); + +#ifdef NJ_ARM_EABI + // EABI requires that 64-bit arguments are aligned on even-numbered + // registers, as R0:R1 or R2:R3. If the register base is at an + // odd-numbered register, advance it. Note that this will push r past + // R3 if r is R3 to start with, and will force the argument to go on + // the stack. + if ((params.r == R1) || (params.r == R3)) { + params.r = Register(params.r + 1); + } +#endif + + if (params.r < R3) { + Register ra = params.r; + Register rb = Register(params.r + 1); + params.r = Register(rb + 1); + +#ifdef NJ_ARM_EABI + // EABI requires that 64-bit arguments are aligned on even-numbered + // registers, as R0:R1 or R2:R3. + NanoAssert( ((ra == R0) && (rb == R1)) || ((ra == R2) && (rb == R3)) ); +#endif + + // Put the argument in ra and rb. If the argument is in a VFP register, + // use FMRRD to move it to ra and rb. Otherwise, let asm_regarg deal + // with the argument as if it were two 32-bit arguments. + if (ARM_VFP) { + Register dm = findRegFor(arg, FpRegs); + FMRRD(ra, rb, dm); + } else { + asm_regarg(ARGTYPE_I, arg->oprnd1(), ra); + asm_regarg(ARGTYPE_I, arg->oprnd2(), rb); + } + +#ifndef NJ_ARM_EABI + } else if (params.r == R3) { + // We only have one register left, but the legacy ABI requires that we + // put 32 bits of the argument in the register (R3) and the remaining + // 32 bits on the stack. + Register ra = params.r; // R3 + params.r = R4; + + // We're splitting the argument between registers and the stack. This + // must be the first time that the stack is used, so stkd must be at 0. + NanoAssert(params.stkd == 0); + + if (ARM_VFP) { + Register dm = findRegFor(arg, FpRegs); + // TODO: We could optimize the this to store directly from + // the VFP register to memory using "FMRRD ra, fp_reg[31:0]" and + // "STR fp_reg[63:32], [SP, #stkd]". + + // Load from the floating-point register as usual, but use IP + // as a swap register. + STR(IP, SP, 0); + FMRRD(ra, IP, dm); + } else { + // Without VFP, we can simply use asm_regarg and asm_stkarg to + // encode the two 32-bit words as we don't need to load from a VFP + // register. + asm_regarg(ARGTYPE_I, arg->oprnd1(), ra); + asm_stkarg(arg->oprnd2(), 0); + } + params.stkd += 4; +#endif + } else { + // The argument won't fit in registers, so pass on to asm_stkarg. +#ifdef NJ_ARM_EABI + // EABI requires that 64-bit arguments are 64-bit aligned. + if ((params.stkd & 7) != 0) { + // stkd will always be aligned to at least 4 bytes; this was + // asserted on entry to this function. + params.stkd += 4; + } +#endif + if (ARM_VFP) { + asm_stkarg(arg, params.stkd); + } else { + asm_stkarg(arg->oprnd1(), params.stkd); + asm_stkarg(arg->oprnd2(), params.stkd+4); + } + params.stkd += 8; + } +} +#endif // NJ_ARM_EABI_HARD_FLOAT + +void +Assembler::asm_regarg(ArgType ty, LIns* p, Register rd) +{ + // Note that we don't have to prepareResultReg here because it is already + // done by the caller, and the target register is passed as 'rd'. + // Similarly, we don't have to freeResourcesOf(p). + + if (ty == ARGTYPE_I || ty == ARGTYPE_UI) + { + // Put the argument in register rd. + if (p->isImmI()) { + asm_ld_imm(rd, p->immI()); + } else { + if (p->isInReg()) { + MOV(rd, p->getReg()); + } else { + // Re-use the target register if the source is no longer + // required. This saves a MOV instruction. + findSpecificRegForUnallocated(p, rd); + } + } + } else { + NanoAssert(ty == ARGTYPE_D); + // Floating-point arguments are handled as two integer arguments. + NanoAssert(false); + } +} + +void +Assembler::asm_stkarg(LIns* arg, int stkd) +{ + // The ABI doesn't allow accesses below the SP. + NanoAssert(stkd >= 0); + // The argument resides somewhere in registers, so we simply need to + // push it onto the stack. + if (arg->isI()) { + Register rt = findRegFor(arg, GpRegs); + asm_str(rt, SP, stkd); + } else { + // According to the comments in asm_arg_64, LIR_ii2d + // can have a 64-bit argument even if VFP is disabled. However, + // asm_arg_64 will split the argument and issue two 32-bit + // arguments to asm_stkarg so we can ignore that case here. + NanoAssert(arg->isD()); + NanoAssert(ARM_VFP); + Register dt = findRegFor(arg, FpRegs); +#ifdef NJ_ARM_EABI + // EABI requires that 64-bit arguments are 64-bit aligned. + NanoAssert((stkd % 8) == 0); +#endif + FSTD(dt, SP, stkd); + } +} + +void +Assembler::asm_call(LIns* ins) +{ + if (ARM_VFP && ins->isop(LIR_calld)) { + /* Because ARM actually returns the result in (R0,R1), and not in a + * floating point register, the code to move the result into a correct + * register is below. We do nothing here. + * + * The reason being that if we did something here, the final code + * sequence we'd get would be something like: + * MOV {R0-R3},params [from below] + * BL function [from below] + * MOV {R0-R3},spilled data [from evictScratchRegsExcept()] + * MOV Dx,{R0,R1} [from here] + * which is clearly broken. + * + * This is not a problem for non-floating point calls, because the + * restoring of spilled data into R0 is done via a call to + * prepareResultReg(R0) in the other branch of this if-then-else, + * meaning that evictScratchRegsExcept() will not modify R0. However, + * prepareResultReg is not aware of the concept of using a register + * pair (R0,R1) for the result of a single operation, so it can only be + * used here with the ultimate VFP register, and not R0/R1, which + * potentially allows for R0/R1 to get corrupted as described. + */ +#ifdef NJ_ARM_EABI_HARD_FLOAT + /* With ARM hardware floating point ABI, D0 is used to return the double + * from the function. We need to prepare it like we do for R0 in the else + * branch. + */ + prepareResultReg(ins, rmask(D0)); + freeResourcesOf(ins); +#endif + } else if (!ins->isop(LIR_callv)) { + prepareResultReg(ins, rmask(retRegs[0])); + // Immediately free the resources as we need to re-use the register for + // the arguments. + freeResourcesOf(ins); + } + + // Do this after we've handled the call result, so we don't + // force the call result to be spilled unnecessarily. + + evictScratchRegsExcept(0); + + const CallInfo* ci = ins->callInfo(); + ArgType argTypes[MAXARGS]; + uint32_t argc = ci->getArgTypes(argTypes); + bool indirect = ci->isIndirect(); + + // If we aren't using VFP, assert that the LIR operation is an integer + // function call. + NanoAssert(ARM_VFP || ins->isop(LIR_callv) || ins->isop(LIR_calli)); + + // If we're using VFP, but not hardware floating point ABI, and + // the return type is a double, it'll come back in R0/R1. + // We need to either place it in the result fp reg, or store it. + // See comments above for more details as to why this is necessary here + // for floating point calls, but not for integer calls. + if (!ARM_EABI_HARD && ARM_VFP && ins->isExtant()) { + // If the result size is a floating-point value, treat the result + // specially, as described previously. + if (ci->returnType() == ARGTYPE_D) { + NanoAssert(ins->isop(LIR_calld)); + + if (ins->isInReg()) { + Register dd = ins->getReg(); + // Copy the result to the (VFP) result register. + FMDRR(dd, R0, R1); + } else { + int d = findMemFor(ins); + // Immediately free the resources so the arguments can re-use + // the slot. + freeResourcesOf(ins); + + // The result doesn't have a register allocated, so store the + // result (in R0,R1) directly to its stack slot. + asm_str(R0, FP, d+0); + asm_str(R1, FP, d+4); + } + } + } + + // Emit the branch. + if (!indirect) { + verbose_only(if (_logc->lcbits & LC_Native) + outputf(" %p:", _nIns); + ) + + BranchWithLink((NIns*)ci->_address); + } else { + // Indirect call: we assign the address arg to LR + if (ARM_ARCH_AT_LEAST(5)) { +#ifndef UNDER_CE + // workaround for msft device emulator bug (blx lr emulated as no-op) + underrunProtect(8); + BLX(IP); + MOV(IP, LR); +#else + BLX(LR); +#endif + } else { + underrunProtect(12); + BX(IP); + MOV(LR, PC); + MOV(IP, LR); + } + asm_regarg(ARGTYPE_I, ins->arg(--argc), LR); + } + + // Encode the arguments, starting at R0 and with an empty argument stack (0). + // With hardware fp ABI, floating point arguments start from D0. + ParameterRegisters params = init_params(0, R0, D0); + + // Iterate through the argument list and encode each argument according to + // the ABI. + // Note that we loop through the arguments backwards as LIR specifies them + // in reverse order. + uint32_t i = argc; + while(i--) { + asm_arg(argTypes[i], ins->arg(i), params); + } + + if (params.stkd > max_out_args) { + max_out_args = params.stkd; + } +} + +Register +Assembler::nRegisterAllocFromSet(RegisterMask set) +{ + NanoAssert(set != 0); + + // The CountLeadingZeroes function will use the CLZ instruction where + // available. In other cases, it will fall back to a (slower) C + // implementation. + Register r = (Register)(31-CountLeadingZeroes(set)); + _allocator.free &= ~rmask(r); + + NanoAssert(IsGpReg(r) || IsFpReg(r)); + NanoAssert((rmask(r) & set) == rmask(r)); + + return r; +} + +void +Assembler::nRegisterResetAll(RegAlloc& a) +{ + // add scratch registers to our free list for the allocator + a.clear(); + a.free = + rmask(R0) | rmask(R1) | rmask(R2) | rmask(R3) | rmask(R4) | + rmask(R5) | rmask(R6) | rmask(R7) | rmask(R8) | rmask(R9) | + rmask(R10) | rmask(LR); + if (ARM_VFP) { + a.free |= + rmask(D0) | rmask(D1) | rmask(D2) | rmask(D3) | + rmask(D4) | rmask(D5) | rmask(D6) | rmask(D7); + } +} + +static inline ConditionCode +get_cc(NIns *ins) +{ + return ConditionCode((*ins >> 28) & 0xF); +} + +static inline bool +branch_is_B(NIns* branch) +{ + return (*branch & 0x0E000000) == 0x0A000000; +} + +static inline bool +branch_is_LDR_PC(NIns* branch) +{ + return (*branch & 0x0F7FF000) == 0x051FF000; +} + +// Is this an instruction of the form ldr/str reg, [fp, #-imm] ? +static inline bool +is_ldstr_reg_fp_minus_imm(/*OUT*/uint32_t* isLoad, /*OUT*/uint32_t* rX, + /*OUT*/uint32_t* immX, NIns i1) +{ + if ((i1 & 0xFFEF0000) != 0xE50B0000) + return false; + *isLoad = (i1 >> 20) & 1; + *rX = (i1 >> 12) & 0xF; + *immX = i1 & 0xFFF; + return true; +} + +// Is this an instruction of the form ldmdb/stmdb fp, regset ? +static inline bool +is_ldstmdb_fp(/*OUT*/uint32_t* isLoad, /*OUT*/uint32_t* regSet, NIns i1) +{ + if ((i1 & 0xFFEF0000) != 0xE90B0000) + return false; + *isLoad = (i1 >> 20) & 1; + *regSet = i1 & 0xFFFF; + return true; +} + +// Make an instruction of the form ldmdb/stmdb fp, regset +static inline NIns +mk_ldstmdb_fp(uint32_t isLoad, uint32_t regSet) +{ + return 0xE90B0000 | (regSet & 0xFFFF) | ((isLoad & 1) << 20); +} + +// Compute the number of 1 bits in the lowest 16 bits of regSet +static inline uint32_t +size_of_regSet(uint32_t regSet) +{ + uint32_t x = regSet; + x = (x & 0x5555) + ((x >> 1) & 0x5555); + x = (x & 0x3333) + ((x >> 2) & 0x3333); + x = (x & 0x0F0F) + ((x >> 4) & 0x0F0F); + x = (x & 0x00FF) + ((x >> 8) & 0x00FF); + return x; +} + +// See if two ARM instructions, i1 and i2, can be combined into one +static bool +do_peep_2_1(/*OUT*/NIns* merged, NIns i1, NIns i2) +{ + uint32_t rX, rY, immX, immY, isLoadX, isLoadY, regSet; + /* ld/str rX, [fp, #-8] + ld/str rY, [fp, #-4] + ==> + ld/stmdb fp, {rX, rY} + when + X < Y and X != fp and Y != fp and X != 15 and Y != 15 + */ + if (is_ldstr_reg_fp_minus_imm(&isLoadX, &rX, &immX, i1) && + is_ldstr_reg_fp_minus_imm(&isLoadY, &rY, &immY, i2) && + immX == 8 && immY == 4 && rX < rY && + isLoadX == isLoadY && + rX != FP && rY != FP && + rX != 15 && rY != 15) { + *merged = mk_ldstmdb_fp(isLoadX, (1 << rX) | (1< + ld/stmdb fp, union(regset,{rX}) + when + regset is nonempty + X < all elements of regset + N == 4 * (1 + card(regset)) + X != fp and X != 15 + */ + if (is_ldstr_reg_fp_minus_imm(&isLoadX, &rX, &immX, i1) && + is_ldstmdb_fp(&isLoadY, ®Set, i2) && + regSet != 0 && + (regSet & ((1 << (rX + 1)) - 1)) == 0 && + immX == 4 * (1 + size_of_regSet(regSet)) && + isLoadX == isLoadY && + rX != FP && rX != 15) { + *merged = mk_ldstmdb_fp(isLoadX, regSet | (1 << rX)); + return true; + } + return false; +} + +// Determine whether or not it's safe to look at _nIns[1]. +// Necessary condition for safe peepholing with do_peep_2_1. +static inline bool +does_next_instruction_exist(NIns* _nIns, NIns* codeStart, NIns* codeEnd, + NIns* exitStart, NIns* exitEnd) +{ + return (exitStart <= _nIns && _nIns+1 < exitEnd) || + (codeStart <= _nIns && _nIns+1 < codeEnd); +} + +void +Assembler::nPatchBranch(NIns* branch, NIns* target) +{ + // Patch the jump in a loop + + // + // There are two feasible cases here, the first of which has 2 sub-cases: + // + // (1) We are patching a patchable unconditional jump emitted by + // JMP_far. All possible encodings we may be looking at with + // involve 2 words, though we *may* have to change from 1 word to + // 2 or vice verse. + // + // 1a: B ±32MB ; BKPT + // 1b: LDR PC [PC, #-4] ; $imm + // + // (2) We are patching a patchable conditional jump emitted by + // B_cond_chk. Short conditional jumps are non-patchable, so we + // won't have one here; will only ever have an instruction of the + // following form: + // + // LDRcc PC [PC, #lit] ... + // + // We don't actually know whether the lit-address is in the + // constant pool or in-line of the instruction stream, following + // the insn (with a jump over it) and we don't need to. For our + // purposes here, cases 2, 3 and 4 all look the same. + // + // For purposes of handling our patching task, we group cases 1b and 2 + // together, and handle case 1a on its own as it might require expanding + // from a short-jump to a long-jump. + // + // We do not handle contracting from a long-jump to a short-jump, though + // this is a possible future optimisation for case 1b. For now it seems + // not worth the trouble. + // + + if (branch_is_B(branch)) { + // Case 1a + // A short B branch, must be unconditional. + NanoAssert(get_cc(branch) == AL); + + int32_t offset = PC_OFFSET_FROM(target, branch); + if (isS24(offset>>2)) { + // We can preserve the existing form, just rewrite its offset. + NIns cond = *branch & 0xF0000000; + *branch = (NIns)( cond | (0xA<<24) | ((offset>>2) & 0xFFFFFF) ); + } else { + // We need to expand the existing branch to a long jump. + // make sure the next instruction is a dummy BKPT + NanoAssert(*(branch+1) == BKPT_insn); + + // Set the branch instruction to LDRcc pc, [pc, #-4] + NIns cond = *branch & 0xF0000000; + *branch++ = (NIns)( cond | (0x51<<20) | (PC<<16) | (PC<<12) | (4)); + *branch++ = (NIns)target; + } + } else { + // Case 1b & 2 + // Not a B branch, must be LDR, might be any kind of condition. + NanoAssert(branch_is_LDR_PC(branch)); + + NIns *addr = branch+2; + int offset = (*branch & 0xFFF) / sizeof(NIns); + if (*branch & (1<<23)) { + addr += offset; + } else { + addr -= offset; + } + + // Just redirect the jump target, leave the insn alone. + *addr = (NIns) target; + } +} + +RegisterMask +Assembler::nHint(LIns* ins) +{ + NanoAssert(ins->isop(LIR_paramp)); + RegisterMask prefer = 0; + if (ins->paramKind() == 0) + if (ins->paramArg() < 4) + prefer = rmask(argRegs[ins->paramArg()]); + return prefer; +} + +void +Assembler::asm_qjoin(LIns *ins) +{ + int d = findMemFor(ins); + NanoAssert(d); + LIns* lo = ins->oprnd1(); + LIns* hi = ins->oprnd2(); + + Register rlo; + Register rhi; + + findRegFor2(GpRegs, lo, rlo, GpRegs, hi, rhi); + + asm_str(rhi, FP, d+4); + asm_str(rlo, FP, d); + + freeResourcesOf(ins); +} + +void +Assembler::asm_store32(LOpcode op, LIns *value, int dr, LIns *base) +{ + Register ra, rb; + getBaseReg2(GpRegs, value, ra, GpRegs, base, rb, dr); + + switch (op) { + case LIR_sti: + if (isU12(-dr) || isU12(dr)) { + STR(ra, rb, dr); + } else { + STR(ra, IP, 0); + asm_add_imm(IP, rb, dr); + } + return; + case LIR_sti2c: + if (isU12(-dr) || isU12(dr)) { + STRB(ra, rb, dr); + } else { + STRB(ra, IP, 0); + asm_add_imm(IP, rb, dr); + } + return; + case LIR_sti2s: + // Similar to the sti/stb case, but the max offset is smaller. + if (isU8(-dr) || isU8(dr)) { + STRH(ra, rb, dr); + } else { + STRH(ra, IP, 0); + asm_add_imm(IP, rb, dr); + } + return; + default: + NanoAssertMsg(0, "asm_store32 should never receive this LIR opcode"); + return; + } +} + +bool +canRematALU(LIns *ins) +{ + // Return true if we can generate code for this instruction that neither + // sets CCs, clobbers an input register, nor requires allocating a register. + switch (ins->opcode()) { + case LIR_addi: + case LIR_subi: + case LIR_andi: + case LIR_ori: + case LIR_xori: + return ins->oprnd1()->isInReg() && ins->oprnd2()->isImmI(); + default: + ; + } + return false; +} + +bool +Assembler::canRemat(LIns* ins) +{ + return ins->isImmI() || ins->isop(LIR_allocp) || canRematALU(ins); +} + +void +Assembler::asm_restore(LIns* i, Register r) +{ + // The following registers should never be restored: + NanoAssert(r != PC); + NanoAssert(r != IP); + NanoAssert(r != SP); + + if (i->isop(LIR_allocp)) { + int d = findMemFor(i); + asm_add_imm(r, FP, d); + } else if (i->isImmI()) { + asm_ld_imm(r, i->immI()); + } else if (canRematALU(i)) { + Register rn = i->oprnd1()->getReg(); + int32_t imm = i->oprnd2()->immI(); + switch (i->opcode()) { + case LIR_addi: asm_add_imm(r, rn, imm, /*stat=*/ 0); break; + case LIR_subi: asm_sub_imm(r, rn, imm, /*stat=*/ 0); break; + case LIR_andi: asm_and_imm(r, rn, imm, /*stat=*/ 0); break; + case LIR_ori: asm_orr_imm(r, rn, imm, /*stat=*/ 0); break; + case LIR_xori: asm_eor_imm(r, rn, imm, /*stat=*/ 0); break; + default: NanoAssert(0); break; + } + } else { + // We can't easily load immediate values directly into FP registers, so + // ensure that memory is allocated for the constant and load it from + // memory. + int d = findMemFor(i); + if (ARM_VFP && IsFpReg(r)) { + if (isU8(d/4) || isU8(-d/4)) { + FLDD(r, FP, d); + } else { + FLDD(r, IP, d%1024); + asm_add_imm(IP, FP, d-(d%1024)); + } + } else { + NIns merged; + LDR(r, FP, d); + // See if we can merge this load into an immediately following + // one, by creating or extending an LDM instruction. + if (/* is it safe to poke _nIns[1] ? */ + does_next_instruction_exist(_nIns, codeStart, codeEnd, + exitStart, exitEnd) + && /* can we merge _nIns[0] into _nIns[1] ? */ + do_peep_2_1(&merged, _nIns[0], _nIns[1])) { + _nIns[1] = merged; + _nIns++; + verbose_only( asm_output("merge next into LDMDB"); ) + } + } + } +} + +void +Assembler::asm_spill(Register rr, int d, bool quad) +{ + (void) quad; + NanoAssert(d); + // The following registers should never be spilled: + NanoAssert(rr != PC); + NanoAssert(rr != IP); + NanoAssert(rr != SP); + if (ARM_VFP && IsFpReg(rr)) { + if (isU8(d/4) || isU8(-d/4)) { + FSTD(rr, FP, d); + } else { + FSTD(rr, IP, d%1024); + asm_add_imm(IP, FP, d-(d%1024)); + } + } else { + NIns merged; + // asm_str always succeeds, but returns '1' to indicate that it emitted + // a simple, easy-to-merge STR. + if (asm_str(rr, FP, d)) { + // See if we can merge this store into an immediately following one, + // one, by creating or extending a STM instruction. + if (/* is it safe to poke _nIns[1] ? */ + does_next_instruction_exist(_nIns, codeStart, codeEnd, + exitStart, exitEnd) + && /* can we merge _nIns[0] into _nIns[1] ? */ + do_peep_2_1(&merged, _nIns[0], _nIns[1])) { + _nIns[1] = merged; + _nIns++; + verbose_only( asm_output("merge next into STMDB"); ) + } + } + } +} + +void +Assembler::asm_load64(LIns* ins) +{ + NanoAssert(ins->isD()); + + if (ARM_VFP) { + Register dd; + LIns* base = ins->oprnd1(); + Register rn = findRegFor(base, GpRegs); + int offset = ins->disp(); + + if (ins->isInReg()) { + dd = prepareResultReg(ins, FpRegs & ~rmask(D0)); + } else { + // If the result isn't already in a register, use the VFP scratch + // register for the result and store it directly into memory. + NanoAssert(ins->isInAr()); + int d = arDisp(ins); + evictIfActive(D0); + dd = D0; + // VFP can only do loads and stores with a range of ±1020, so we + // might need to do some arithmetic to extend its range. + if (isU8(d/4) || isU8(-d/4)) { + FSTD(dd, FP, d); + } else { + FSTD(dd, IP, d%1024); + asm_add_imm(IP, FP, d-(d%1024)); + } + } + + switch (ins->opcode()) { + case LIR_ldd: + if (isU8(offset/4) || isU8(-offset/4)) { + FLDD(dd, rn, offset); + } else { + FLDD(dd, IP, offset%1024); + asm_add_imm(IP, rn, offset-(offset%1024)); + } + break; + case LIR_ldf2d: + evictIfActive(D0); + FCVTDS(dd, S0); + if (isU8(offset/4) || isU8(-offset/4)) { + FLDS(S0, rn, offset); + } else { + FLDS(S0, IP, offset%1024); + asm_add_imm(IP, rn, offset-(offset%1024)); + } + break; + default: + NanoAssertMsg(0, "LIR opcode unsupported by asm_load64."); + break; + } + } else { + NanoAssert(ins->isInAr()); + int d = arDisp(ins); + + LIns* base = ins->oprnd1(); + Register rn = findRegFor(base, GpRegs); + int offset = ins->disp(); + + switch (ins->opcode()) { + case LIR_ldd: + asm_mmq(FP, d, rn, offset); + break; + case LIR_ldf2d: + NanoAssertMsg(0, "LIR_ldf2d is not yet implemented for soft-float."); + break; + default: + NanoAssertMsg(0, "LIR opcode unsupported by asm_load64."); + break; + } + } + + freeResourcesOf(ins); +} + +void +Assembler::asm_store64(LOpcode op, LIns* value, int dr, LIns* base) +{ + NanoAssert(value->isD()); + + if (ARM_VFP) { + Register dd = findRegFor(value, FpRegs & ~rmask(D0)); + Register rn = findRegFor(base, GpRegs); + + switch (op) { + case LIR_std: + // VFP can only do stores with a range of ±1020, so we might + // need to do some arithmetic to extend its range. + if (isU8(dr/4) || isU8(-dr/4)) { + FSTD(dd, rn, dr); + } else { + FSTD(dd, IP, dr%1024); + asm_add_imm(IP, rn, dr-(dr%1024)); + } + + break; + case LIR_std2f: + // VFP can only do stores with a range of ±1020, so we might + // need to do some arithmetic to extend its range. + evictIfActive(D0); + if (isU8(dr/4) || isU8(-dr/4)) { + FSTS(S0, rn, dr); + } else { + FSTS(S0, IP, dr%1024); + asm_add_imm(IP, rn, dr-(dr%1024)); + } + + FCVTSD(S0, dd); + + break; + default: + NanoAssertMsg(0, "LIR opcode unsupported by asm_store64."); + break; + } + } else { + int d = findMemFor(value); + Register rn = findRegFor(base, GpRegs); + + switch (op) { + case LIR_std: + // Doubles in soft-float never get registers allocated, so this + // is always a simple two-word memcpy. + // *(uint64_t*)(rb+dr) = *(uint64_t*)(FP+da) + asm_mmq(rn, dr, FP, d); + break; + case LIR_std2f: + NanoAssertMsg(0, "TODO: Soft-float implementation of LIR_std2f."); + break; + default: + NanoAssertMsg(0, "LIR opcode unsupported by asm_store64."); + break; + } + } +} + +// Load the float64 specified by immDhi:immDlo into VFP register dd. +void +Assembler::asm_immd_nochk(Register dd, int32_t immDlo, int32_t immDhi) +{ + // We're not going to use a slot, because it might be too far + // away. Instead, we're going to stick a branch in the stream to + // jump over the constants, and then load from a short PC relative + // offset. + + // stream should look like: + // branch A + // immDlo + // immDhi + // A: FLDD PC-16 + + FLDD(dd, PC, -16); + + *(--_nIns) = (NIns) immDhi; + *(--_nIns) = (NIns) immDlo; + + B_nochk(_nIns+2); +} + +void +Assembler::asm_immd(LIns* ins) +{ + // If the value isn't in a register, it's simplest to use integer + // instructions to put the value in its stack slot. Otherwise, use a VFP + // load to get the value from a literal pool. + if (ARM_VFP && ins->isInReg()) { + Register dd = prepareResultReg(ins, FpRegs); + underrunProtect(4*4); + asm_immd_nochk(dd, ins->immDlo(), ins->immDhi()); + } else { + NanoAssert(ins->isInAr()); + int d = arDisp(ins); + asm_str(IP, FP, d+4); + asm_ld_imm(IP, ins->immDhi()); + asm_str(IP, FP, d); + asm_ld_imm(IP, ins->immDlo()); + } + + freeResourcesOf(ins); +} + +void +Assembler::asm_nongp_copy(Register r, Register s) +{ + if (ARM_VFP && IsFpReg(r) && IsFpReg(s)) { + // fp->fp + FCPYD(r, s); + } else { + // We can't move a double-precision FP register into a 32-bit GP + // register, so assert that no calling code is trying to do that. + NanoAssert(0); + } +} + +/** + * copy 64 bits: (rd+dd) <- (rs+ds) + */ +void +Assembler::asm_mmq(Register rd, int dd, Register rs, int ds) +{ + // The value is either a 64bit struct or maybe a float that isn't live in + // an FPU reg. Either way, don't put it in an FPU reg just to load & store + // it. + // This operation becomes a simple 64-bit memcpy. + + // In order to make the operation optimal, we will require two GP + // registers. We can't allocate a register here because the caller may have + // called deprecated_freeRsrcOf, and allocating a register here may cause something + // else to spill onto the stack which has just be conveniently freed by + // deprecated_freeRsrcOf (resulting in stack corruption). + // + // Falling back to a single-register implementation of asm_mmq is better + // than adjusting the callers' behaviour (to allow us to allocate another + // register here) because spilling a register will end up being slower than + // just using the same register twice anyway. + // + // Thus, if there is a free register which we can borrow, we will emit the + // following code: + // LDR rr, [rs, #ds] + // LDR ip, [rs, #(ds+4)] + // STR rr, [rd, #dd] + // STR ip, [rd, #(dd+4)] + // (Where rr is the borrowed register.) + // + // If there is no free register, don't spill an existing allocation. Just + // do the following: + // LDR ip, [rs, #ds] + // STR ip, [rd, #dd] + // LDR ip, [rs, #(ds+4)] + // STR ip, [rd, #(dd+4)] + // + // Note that if rs+4 or rd+4 is outside the LDR or STR range, extra + // instructions will be emitted as required to make the code work. + + // Ensure that the PC is not used as either base register. The instruction + // generation macros call underrunProtect, and a side effect of this is + // that we may be pushed onto another page, so the PC is not a reliable + // base register. + NanoAssert(rs != PC); + NanoAssert(rd != PC); + + // We use IP as a swap register, so check that it isn't used for something + // else by the caller. + NanoAssert(rs != IP); + NanoAssert(rd != IP); + + // Find the list of free registers from the allocator's free list and the + // GpRegs mask. This excludes any floating-point registers that may be on + // the free list. + RegisterMask free = _allocator.free & AllowableFlagRegs; + + // Ensure that ds and dd are within the +/-4095 offset range of STR and + // LDR. If either is out of range, adjust and modify rd or rs so that the + // load works correctly. + // The modification here is performed after the LDR/STR block (because code + // is emitted backwards), so this one is the reverse operation. + + int32_t dd_adj = 0; + int32_t ds_adj = 0; + + if ((dd+4) >= 0x1000) { + dd_adj = ((dd+4) & ~0xfff); + } else if (dd <= -0x1000) { + dd_adj = -((-dd) & ~0xfff); + } + if ((ds+4) >= 0x1000) { + ds_adj = ((ds+4) & ~0xfff); + } else if (ds <= -0x1000) { + ds_adj = -((-ds) & ~0xfff); + } + + // These will emit no code if d*_adj is 0. + asm_sub_imm(rd, rd, dd_adj); + asm_sub_imm(rs, rs, ds_adj); + + ds -= ds_adj; + dd -= dd_adj; + + if (free) { + // There is at least one register on the free list, so grab one for + // temporary use. There is no need to allocate it explicitly because + // we won't need it after this function returns. + + // The CountLeadingZeroes utility can be used to quickly find a set bit + // in the free mask. + Register rr = (Register)(31-CountLeadingZeroes(free)); + + // Note: Not every register in GpRegs is usable here. However, these + // registers will never appear on the free list. + NanoAssert((free & rmask(PC)) == 0); + NanoAssert((free & rmask(LR)) == 0); + NanoAssert((free & rmask(SP)) == 0); + NanoAssert((free & rmask(IP)) == 0); + NanoAssert((free & rmask(FP)) == 0); + + // Emit the actual instruction sequence. + STR(IP, rd, dd+4); + STR(rr, rd, dd); + LDR(IP, rs, ds+4); + LDR(rr, rs, ds); + } else { + // There are no free registers, so fall back to using IP twice. + STR(IP, rd, dd+4); + LDR(IP, rs, ds+4); + STR(IP, rd, dd); + LDR(IP, rs, ds); + } + + // Re-adjust the base registers. (These will emit no code if d*_adj is 0. + asm_add_imm(rd, rd, dd_adj); + asm_add_imm(rs, rs, ds_adj); +} + +// Increment the 32-bit profiling counter at pCtr, without +// changing any registers. +verbose_only( +void Assembler::asm_inc_m32(uint32_t* pCtr) +{ + // We need to temporarily free up two registers to do this, so + // just push r0 and r1 on the stack. This assumes that the area + // at r13 - 8 .. r13 - 1 isn't being used for anything else at + // this point. This guaranteed us by the EABI; although the + // situation with the legacy ABI I'm not sure of. + // + // Plan: emit the following bit of code. It's not efficient, but + // this is for profiling debug builds only, and is self contained, + // except for above comment re stack use. + // + // E92D0003 push {r0,r1} + // E59F0000 ldr r0, [r15] ; pCtr + // EA000000 b .+8 ; jump over imm + // 12345678 .word 0x12345678 ; pCtr + // E5901000 ldr r1, [r0] + // E2811001 add r1, r1, #1 + // E5801000 str r1, [r0] + // E8BD0003 pop {r0,r1} + + // We need keep the 4 words beginning at "ldr r0, [r15]" + // together. Simplest to underrunProtect the whole thing. + underrunProtect(8*4); + IMM32(0xE8BD0003); // pop {r0,r1} + IMM32(0xE5801000); // str r1, [r0] + IMM32(0xE2811001); // add r1, r1, #1 + IMM32(0xE5901000); // ldr r1, [r0] + IMM32((uint32_t)pCtr); // .word pCtr + IMM32(0xEA000000); // b .+8 + IMM32(0xE59F0000); // ldr r0, [r15] + IMM32(0xE92D0003); // push {r0,r1} +} +) + +void +Assembler::nativePageReset() +{ + _nSlot = 0; + _nExitSlot = 0; +} + +void +Assembler::nativePageSetup() +{ + NanoAssert(!_inExit); + if (!_nIns) + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes), NJ_MAX_CPOOL_OFFSET); + + // constpool starts at top of page and goes down, + // code starts at bottom of page and moves up + if (!_nSlot) + _nSlot = codeStart; +} + + +void +Assembler::underrunProtect(int bytes) +{ + NanoAssertMsg(bytes<=LARGEST_UNDERRUN_PROT, "constant LARGEST_UNDERRUN_PROT is too small"); + NanoAssert(_nSlot != 0 && int(_nIns)-int(_nSlot) <= 4096); + uintptr_t top = uintptr_t(_nSlot); + uintptr_t pc = uintptr_t(_nIns); + if (pc - bytes < top) + { + verbose_only(verbose_outputf(" %p:", _nIns);) + NIns* target = _nIns; + // This may be in a normal code chunk or an exit code chunk. + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes), NJ_MAX_CPOOL_OFFSET); + + _nSlot = codeStart; + + // _nSlot points to the first empty position in the new code block + // _nIns points just past the last empty position. + // Assume B_nochk won't ever try to write to _nSlot. See B_cond_chk macro. + B_nochk(target); + } +} + +void +Assembler::JMP_far(NIns* addr) +{ + // Even if a simple branch is all that is required, this function must emit + // two words so that the branch can be arbitrarily patched later on. + underrunProtect(8); + + intptr_t offs = PC_OFFSET_FROM(addr,_nIns-2); + + if (isS24(offs>>2)) { + // Emit a BKPT to ensure that we reserve enough space for a full 32-bit + // branch patch later on. The BKPT should never be executed. + BKPT_nochk(); + + asm_output("bkpt"); + + // B [PC+offs] + *(--_nIns) = (NIns)( COND_AL | (0xA<<24) | ((offs>>2) & 0xFFFFFF) ); + + asm_output("b %p", (void*)addr); + } else { + // Insert the target address as a constant in the instruction stream. + *(--_nIns) = (NIns)((addr)); + // ldr pc, [pc, #-4] // load the address into pc, reading it from [pc-4] (e.g., + // the next instruction) + *(--_nIns) = (NIns)( COND_AL | (0x51<<20) | (PC<<16) | (PC<<12) | (4)); + + asm_output("ldr pc, =%p", (void*)addr); + } +} + +// Perform a branch with link, and ARM/Thumb exchange if necessary. The actual +// BLX instruction is only available from ARMv5 onwards, but as we don't +// support anything older than that this function will not attempt to output +// pre-ARMv5 sequences. +// +// Note: This function is not designed to be used with branches which will be +// patched later, though it will work if the patcher knows how to patch the +// generated instruction sequence. +void +Assembler::BranchWithLink(NIns* addr) +{ + // Most branches emitted by TM are loaded through a register, so always + // reserve enough space for the LDR sequence. This should give us a slight + // net gain over reserving the exact amount required for shorter branches. + // This _must_ be called before PC_OFFSET_FROM as it can move _nIns! + underrunProtect(8+LD32_size); + + // Calculate the offset from the instruction that is about to be + // written (at _nIns-1) to the target. + intptr_t offs = PC_OFFSET_FROM(addr,_nIns-1); + + // ARMv5 and above can use BLX for branches within ±32MB of the + // PC and BLX Rm for long branches. + if (isS24(offs>>2)) { + // the value we need to stick in the instruction; masked, + // because it will be sign-extended back to 32 bits. + intptr_t offs2 = (offs>>2) & 0xffffff; + + if (((intptr_t)addr & 1) == 0) { + // The target is ARM, so just emit a BL. + + // BL target + *(--_nIns) = (NIns)( (COND_AL) | (0xB<<24) | (offs2) ); + asm_output("bl %p", (void*)addr); + return; + } else if (ARM_ARCH_AT_LEAST(5)) { + // The target is Thumb, so emit a BLX (ARMv5+) + // The (pre-shifted) value of the "H" bit in the BLX encoding. + uint32_t H = (offs & 0x2) << 23; + + // BLX addr + *(--_nIns) = (NIns)( (0xF << 28) | (0x5<<25) | (H) | (offs2) ); + asm_output("blx %p", (void*)addr); + return; + } + /* If we get here, it means we are on ARMv4T, and the target is Thumb, + in which case we want to emit a branch with a register */ + } + if (ARM_ARCH_AT_LEAST(5)) { + // Load the target address into IP and branch to that. We've already + // done underrunProtect, so we can skip that here. + BLX(IP, false); + } else { + BX(IP); + MOV(LR, PC); + } + // LDR IP, =addr + asm_ld_imm(IP, (int32_t)addr, false); +} + +// This is identical to BranchWithLink(NIns*) but emits a branch to an address +// held in a register rather than a literal address. +inline void +Assembler::BLX(Register addr, bool chk /* = true */) +{ + // We need to emit an ARMv5+ instruction, so assert that we have a suitable + // processor. Note that we don't support ARMv4(T), but this serves as a + // useful sanity check. + NanoAssert(ARM_ARCH_AT_LEAST(5)); + + NanoAssert(IsGpReg(addr)); +#ifdef UNDER_CE + // There is a bug in the WinCE device emulator which stops "BLX LR" from + // working as expected. Assert that we never do that! + NanoAssert(addr != LR); +#endif + + if (chk) { + underrunProtect(4); + } + + // BLX reg + *(--_nIns) = (NIns)( (COND_AL) | (0x12<<20) | (0xFFF<<8) | (0x3<<4) | (addr) ); + asm_output("blx %s", gpn(addr)); +} + +// Emit the code required to load a memory address into a register as follows: +// d = *(b+off) +// underrunProtect calls from this function can be disabled by setting chk to +// false. However, this function can use more than LD32_size bytes of space if +// the offset is out of the range of a LDR instruction; the maximum space this +// function requires for underrunProtect is 4+LD32_size. +void +Assembler::asm_ldr_chk(Register d, Register b, int32_t off, bool chk) +{ + if (ARM_VFP && IsFpReg(d)) { + FLDD_chk(d,b,off,chk); + return; + } + + NanoAssert(IsGpReg(d)); + NanoAssert(IsGpReg(b)); + + // We can't use underrunProtect if the base register is the PC because + // underrunProtect might move the PC if there isn't enough space on the + // current page. + NanoAssert((b != PC) || (!chk)); + + if (isU12(off)) { + // LDR d, b, #+off + if (chk) underrunProtect(4); + *(--_nIns) = (NIns)( COND_AL | (0x59<<20) | (b<<16) | (d<<12) | off ); + } else if (isU12(-off)) { + // LDR d, b, #-off + if (chk) underrunProtect(4); + *(--_nIns) = (NIns)( COND_AL | (0x51<<20) | (b<<16) | (d<<12) | -off ); + } else { + // The offset is over 4096 (and outside the range of LDR), so we need + // to add a level of indirection to get the address into IP. + + // Because of that, we can't do a PC-relative load unless it fits within + // the single-instruction forms above. + + NanoAssert(b != PC); + NanoAssert(b != IP); + + if (chk) underrunProtect(4+LD32_size); + + *(--_nIns) = (NIns)( COND_AL | (0x79<<20) | (b<<16) | (d<<12) | IP ); + asm_ld_imm(IP, off, false); + } + + asm_output("ldr %s, [%s, #%d]",gpn(d),gpn(b),(off)); +} + +// Emit a store, using a register base and an arbitrary immediate offset. This +// behaves like a STR instruction, but doesn't care about the offset range, and +// emits one of the following instruction sequences: +// +// ---- +// STR rt, [rr, #offset] +// ---- +// asm_add_imm ip, rr, #(offset & ~0xfff) +// STR rt, [ip, #(offset & 0xfff)] +// ---- +// # This one's fairly horrible, but should be rare. +// asm_add_imm rr, rr, #(offset & ~0xfff) +// STR rt, [ip, #(offset & 0xfff)] +// asm_sub_imm rr, rr, #(offset & ~0xfff) +// ---- +// SUB-based variants (for negative offsets) are also supported. +// ---- +// +// The return value is 1 if a simple STR could be emitted, or 0 if the required +// sequence was more complex. +int32_t +Assembler::asm_str(Register rt, Register rr, int32_t offset) +{ + // We can't do PC-relative stores, and we can't store the PC value, because + // we use macros (such as STR) which call underrunProtect, and this can + // push _nIns to a new page, thus making any PC value impractical to + // predict. + NanoAssert(rr != PC); + NanoAssert(rt != PC); + if (offset >= 0) { + // The offset is positive, so use ADD (and variants). + if (isU12(offset)) { + STR(rt, rr, offset); + return 1; + } + + if (rt != IP) { + STR(rt, IP, offset & 0xfff); + asm_add_imm(IP, rr, offset & ~0xfff); + } else { + int32_t adj = offset & ~0xfff; + asm_sub_imm(rr, rr, adj); + STR(rt, rr, offset-adj); + asm_add_imm(rr, rr, adj); + } + } else { + // The offset is negative, so use SUB (and variants). + if (isU12(-offset)) { + STR(rt, rr, offset); + return 1; + } + + if (rt != IP) { + STR(rt, IP, -((-offset) & 0xfff)); + asm_sub_imm(IP, rr, (-offset) & ~0xfff); + } else { + int32_t adj = ((-offset) & ~0xfff); + asm_add_imm(rr, rr, adj); + STR(rt, rr, offset+adj); + asm_sub_imm(rr, rr, adj); + } + } + + return 0; +} + +// Emit the code required to load an immediate value (imm) into general-purpose +// register d. Optimal (MOV-based) mechanisms are used if the immediate can be +// encoded using ARM's operand 2 encoding. Otherwise, a slot is used on the +// literal pool and LDR is used to load the value. +// +// chk can be explicitly set to false in order to disable underrunProtect calls +// from this function; this allows the caller to perform the check manually. +// This function guarantees not to use more than LD32_size bytes of space. +void +Assembler::asm_ld_imm(Register d, int32_t imm, bool chk /* = true */) +{ + uint32_t op2imm; + + NanoAssert(IsGpReg(d)); + + // Attempt to encode the immediate using the second operand of MOV or MVN. + // This is the simplest solution and generates the shortest and fastest + // code, but can only encode a limited set of values. + + if (encOp2Imm(imm, &op2imm)) { + // Use MOV to encode the literal. + MOVis(d, op2imm, 0); + return; + } + + if (encOp2Imm(~imm, &op2imm)) { + // Use MVN to encode the inverted literal. + MVNis(d, op2imm, 0); + return; + } + + // Try to use simple MOV, MVN or MOV(W|T) instructions to load the + // immediate. If this isn't possible, load it from memory. + // - We cannot use MOV(W|T) on cores older than the introduction of + // Thumb-2 or if the target register is the PC. + // + // (Note that we use Thumb-2 if arm_arch is ARMv7 or later; the only earlier + // ARM core that provided Thumb-2 is ARMv6T2/ARM1156, which is a real-time + // core that nanojit is unlikely to ever target.) + if (ARM_ARCH_AT_LEAST(7) && (d != PC)) { + // ARMv6T2 and above have MOVW and MOVT. + uint32_t high_h = (uint32_t)imm >> 16; + uint32_t low_h = imm & 0xffff; + + if (high_h != 0) { + // Load the high half-word (if necessary). + MOVTi_chk(d, high_h, chk); + } + // Load the low half-word. This also zeroes the high half-word, and + // thus must execute _before_ MOVT, and is necessary even if low_h is 0 + // because MOVT will not change the existing low half-word. + MOVWi_chk(d, low_h, chk); + + return; + } + + // We couldn't encode the literal in the instruction stream, so load it + // from memory. + + // Because the literal pool is on the same page as the generated code, it + // will almost always be within the ±4096 range of a LDR. However, this may + // not be the case if _nSlot is at the start of the page and _nIns is at + // the end because the PC is 8 bytes ahead of _nIns. This is unlikely to + // happen, but if it does occur we can simply waste a word or two of + // literal space. + + // We must do the underrunProtect before PC_OFFSET_FROM as underrunProtect + // can move the PC if there isn't enough space on the current page! + if (chk) { + underrunProtect(LD32_size); + } + + int offset = PC_OFFSET_FROM(_nSlot, _nIns-1); + // If the offset is out of range, waste literal space until it is in range. + while (offset <= -4096) { + ++_nSlot; + offset += sizeof(_nSlot); + } + NanoAssert((isU12(-offset) || isU12(offset)) && (offset <= -8)); + + // Write the literal. + *(_nSlot++) = imm; + asm_output("## imm= 0x%x", imm); + + // Load the literal. + LDR_nochk(d,PC,offset); + NanoAssert(uintptr_t(_nIns) + 8 + offset == uintptr_t(_nSlot-1)); + NanoAssert(*((int32_t*)_nSlot-1) == imm); +} + +// Branch to target address _t with condition _c, doing underrun +// checks (_chk == 1) or skipping them (_chk == 0). +// +// Set the target address (_t) to 0 if the target is not yet known and the +// branch will be patched up later. +// +// If the jump is to a known address (with _t != 0) and it fits in a relative +// jump (±32MB), emit that. +// If the jump is unconditional, emit the dest address inline in +// the instruction stream and load it into pc. +// If the jump has a condition, but noone's mucked with _nIns and our _nSlot +// pointer is valid, stick the constant in the slot and emit a conditional +// load into pc. +// Otherwise, emit the conditional load into pc from a nearby constant, +// and emit a jump to jump over it it in case the condition fails. +// +// NB: B_nochk depends on this not calling samepage() when _c == AL +void +Assembler::B_cond_chk(ConditionCode _c, NIns* _t, bool _chk) +{ + int32_t offs = PC_OFFSET_FROM(_t,_nIns-1); + //nj_dprintf("B_cond_chk target: 0x%08x offset: %d @0x%08x\n", _t, offs, _nIns-1); + + // optimistically check if this will fit in 24 bits + if (_chk && isS24(offs>>2) && (_t != 0)) { + underrunProtect(4); + // recalculate the offset, because underrunProtect may have + // moved _nIns to a new page + offs = PC_OFFSET_FROM(_t,_nIns-1); + } + + // Emit one of the following patterns: + // + // --- Short branch. This can never be emitted if the branch target is not + // known. + // B(cc) ±32MB + // + // --- Long unconditional branch. + // LDR PC, #lit + // lit: #target + // + // --- Long conditional branch. Note that conditional branches will never + // be patched, so the nPatchBranch function doesn't need to know where + // the literal pool is located. + // LDRcc PC, #lit + // ; #lit is in the literal pool at _nSlot + // + // --- Long conditional branch (if the slot isn't on the same page as the instruction). + // LDRcc PC, #lit + // B skip ; Jump over the literal data. + // lit: #target + // skip: [...] + + if (isS24(offs>>2) && (_t != 0)) { + // The underrunProtect for this was done above (if required by _chk). + *(--_nIns) = (NIns)( ((_c)<<28) | (0xA<<24) | (((offs)>>2) & 0xFFFFFF) ); + asm_output("b%s %p", _c == AL ? "" : condNames[_c], (void*)(_t)); + } else if (_c == AL) { + if(_chk) underrunProtect(8); + *(--_nIns) = (NIns)(_t); + *(--_nIns) = (NIns)( COND_AL | (0x51<<20) | (PC<<16) | (PC<<12) | 0x4 ); + asm_output("b%s %p", _c == AL ? "" : condNames[_c], (void*)(_t)); + } else if (PC_OFFSET_FROM(_nSlot, _nIns-1) > -0x1000) { + if(_chk) underrunProtect(8); + *(_nSlot++) = (NIns)(_t); + offs = PC_OFFSET_FROM(_nSlot-1,_nIns-1); + NanoAssert(offs < 0); + *(--_nIns) = (NIns)( ((_c)<<28) | (0x51<<20) | (PC<<16) | (PC<<12) | ((-offs) & 0xFFF) ); + asm_output("ldr%s %s, [%s, #-%d]", condNames[_c], gpn(PC), gpn(PC), -offs); + NanoAssert(uintptr_t(_nIns)+8+offs == uintptr_t(_nSlot-1)); + } else { + if(_chk) underrunProtect(12); + // Emit a pointer to the target as a literal in the instruction stream. + *(--_nIns) = (NIns)(_t); + // Emit a branch to skip over the literal. The PC value is 8 bytes + // ahead of the executing instruction, so to branch two instructions + // forward this must branch 8-8=0 bytes. + *(--_nIns) = (NIns)( COND_AL | (0xA<<24) | 0x0 ); + // Emit the conditional branch. + *(--_nIns) = (NIns)( ((_c)<<28) | (0x51<<20) | (PC<<16) | (PC<<12) | 0x0 ); + asm_output("b%s %p", _c == AL ? "" : condNames[_c], (void*)(_t)); + } +} + +/* + * VFP + */ + +void +Assembler::asm_i2d(LIns* ins) +{ + Register dd = prepareResultReg(ins, FpRegs & ~rmask(D0)); + Register rt = findRegFor(ins->oprnd1(), GpRegs); + + evictIfActive(D0); + FSITOD(dd, S0); + FMSR(S0, rt); + + freeResourcesOf(ins); +} + +void +Assembler::asm_ui2d(LIns* ins) +{ + Register dd = prepareResultReg(ins, FpRegs & ~rmask(D0)); + Register rt = findRegFor(ins->oprnd1(), GpRegs); + + evictIfActive(D0); + FUITOD(dd, S0); + FMSR(S0, rt); + + freeResourcesOf(ins); +} + +void Assembler::asm_d2i(LIns* ins) +{ + evictIfActive(D0); + if (ins->isInReg()) { + Register rt = ins->getReg(); + FMRS(rt, S0); + } else { + // There's no active result register, so store the result directly into + // memory to avoid the FP->GP transfer cost on Cortex-A8. + int32_t d = arDisp(ins); + // VFP can only do stores with a range of ±1020, so we might need to do + // some arithmetic to extend its range. + if (isU8(d/4) || isU8(-d/4)) { + FSTS(S0, FP, d); + } else { + FSTS(S0, IP, d%1024); + asm_add_imm(IP, FP, d-(d%1024)); + } + } + + Register dm = findRegFor(ins->oprnd1(), FpRegs & ~rmask(D0)); + + FTOSID(S0, dm); + + freeResourcesOf(ins); +} + +void +Assembler::asm_fneg(LIns* ins) +{ + LIns* lhs = ins->oprnd1(); + + Register dd = prepareResultReg(ins, FpRegs); + // If the argument doesn't have a register assigned, re-use dd. + Register dm = lhs->isInReg() ? lhs->getReg() : dd; + + FNEGD(dd, dm); + + freeResourcesOf(ins); + if (dd == dm) { + NanoAssert(!lhs->isInReg()); + findSpecificRegForUnallocated(lhs, dd); + } +} + +void +Assembler::asm_fop(LIns* ins) +{ + LIns* lhs = ins->oprnd1(); + LIns* rhs = ins->oprnd2(); + + Register dd = prepareResultReg(ins, FpRegs); + // Try to re-use the result register for one of the arguments. + Register dn = lhs->isInReg() ? lhs->getReg() : dd; + Register dm = rhs->isInReg() ? rhs->getReg() : dd; + if ((dn == dm) && (lhs != rhs)) { + // We can't re-use the result register for both arguments, so force one + // into its own register. + dm = findRegFor(rhs, FpRegs & ~rmask(dd)); + NanoAssert(rhs->isInReg()); + } + + // TODO: Special cases for simple constants. + + switch(ins->opcode()) { + case LIR_addd: FADDD(dd,dn,dm); break; + case LIR_subd: FSUBD(dd,dn,dm); break; + case LIR_muld: FMULD(dd,dn,dm); break; + case LIR_divd: FDIVD(dd,dn,dm); break; + default: NanoAssert(0); break; + } + + freeResourcesOf(ins); + + // If we re-used the result register, mark it as active. + if (dn == dd) { + NanoAssert(!lhs->isInReg()); + findSpecificRegForUnallocated(lhs, dd); + } else if (dm == dd) { + NanoAssert(!rhs->isInReg()); + findSpecificRegForUnallocated(rhs, dd); + } else { + NanoAssert(lhs->isInReg()); + NanoAssert(rhs->isInReg()); + } +} + +void +Assembler::asm_cmpd(LIns* ins) +{ + LIns* lhs = ins->oprnd1(); + LIns* rhs = ins->oprnd2(); + LOpcode op = ins->opcode(); + + NanoAssert(ARM_VFP); + NanoAssert(isCmpDOpcode(op)); + NanoAssert(lhs->isD() && rhs->isD()); + + Register ra, rb; + findRegFor2(FpRegs, lhs, ra, FpRegs, rhs, rb); + + int e_bit = (op != LIR_eqd); + + // Do the comparison and get results loaded in ARM status register. + // TODO: For asm_condd, we should put the results directly into an ARM + // machine register, then use bit operations to get the result. + FMSTAT(); + FCMPD(ra, rb, e_bit); +} + +/* Call this with targ set to 0 if the target is not yet known and the branch + * will be patched up later. + */ +NIns* +Assembler::asm_branch(bool branchOnFalse, LIns* cond, NIns* targ) +{ + LOpcode condop = cond->opcode(); + NanoAssert(cond->isCmp()); + NanoAssert(ARM_VFP || !isCmpDOpcode(condop)); + + // The old "never" condition code has special meaning on newer ARM cores, + // so use "always" as a sensible default code. + ConditionCode cc = AL; + + // Detect whether or not this is a floating-point comparison. + bool fp_cond; + + // Select the appropriate ARM condition code to match the LIR instruction. + switch (condop) + { + // Floating-point conditions. Note that the VFP LT/LE conditions + // require use of the unsigned condition codes, even though + // float-point comparisons are always signed. + case LIR_eqd: cc = EQ; fp_cond = true; break; + case LIR_ltd: cc = LO; fp_cond = true; break; + case LIR_led: cc = LS; fp_cond = true; break; + case LIR_ged: cc = GE; fp_cond = true; break; + case LIR_gtd: cc = GT; fp_cond = true; break; + + // Standard signed and unsigned integer comparisons. + case LIR_eqi: cc = EQ; fp_cond = false; break; + case LIR_lti: cc = LT; fp_cond = false; break; + case LIR_lei: cc = LE; fp_cond = false; break; + case LIR_gti: cc = GT; fp_cond = false; break; + case LIR_gei: cc = GE; fp_cond = false; break; + case LIR_ltui: cc = LO; fp_cond = false; break; + case LIR_leui: cc = LS; fp_cond = false; break; + case LIR_gtui: cc = HI; fp_cond = false; break; + case LIR_geui: cc = HS; fp_cond = false; break; + + // Default case for invalid or unexpected LIR instructions. + default: cc = AL; fp_cond = false; break; + } + + // Invert the condition if required. + if (branchOnFalse) + cc = OppositeCond(cc); + + // Ensure that we got a sensible condition code. + NanoAssert((cc != AL) && (cc != NV)); + + // Ensure that we don't hit floating-point LIR codes if VFP is disabled. + NanoAssert(ARM_VFP || !fp_cond); + + // Emit a suitable branch instruction. + B_cond(cc, targ); + + // Store the address of the branch instruction so that we can return it. + // asm_[f]cmp will move _nIns so we must do this now. + NIns *at = _nIns; + + asm_cmp(cond); + + return at; +} + +NIns* Assembler::asm_branch_ov(LOpcode op, NIns* target) +{ + // Because MUL can't set the V flag, we use SMULL and CMP to set the Z flag + // to detect overflow on multiply. Thus, if we have a LIR_mulxovi, we must + // be conditional on !Z, not V. + ConditionCode cc = ( (op == LIR_mulxovi) || (op == LIR_muljovi) ? NE : VS ); + + // Emit a suitable branch instruction. + B_cond(cc, target); + return _nIns; +} + +void +Assembler::asm_cmp(LIns *cond) +{ + LIns* lhs = cond->oprnd1(); + LIns* rhs = cond->oprnd2(); + + // Forward floating-point comparisons directly to asm_cmpd to simplify + // logic in other methods which need to issue an implicit comparison, but + // don't care about the details of comparison itself. + if (lhs->isD()) { + NanoAssert(rhs->isD()); + asm_cmpd(cond); + return; + } + + NanoAssert(lhs->isI() && rhs->isI()); + + // ready to issue the compare + if (rhs->isImmI()) { + int c = rhs->immI(); + Register r = findRegFor(lhs, GpRegs); + asm_cmpi(r, c); + } else { + Register ra, rb; + findRegFor2(GpRegs, lhs, ra, GpRegs, rhs, rb); + CMP(ra, rb); + } +} + +void +Assembler::asm_cmpi(Register r, int32_t imm) +{ + if (imm < 0) { + if (imm > -256) { + ALUi(AL, cmn, 1, 0, r, -imm); + } else { + underrunProtect(4 + LD32_size); + CMP(r, IP); + asm_ld_imm(IP, imm); + } + } else { + if (imm < 256) { + ALUi(AL, cmp, 1, 0, r, imm); + } else { + underrunProtect(4 + LD32_size); + CMP(r, IP); + asm_ld_imm(IP, imm); + } + } +} + +void +Assembler::asm_condd(LIns* ins) +{ + Register rd = prepareResultReg(ins, GpRegs); + + // TODO: Modify cmpd to allow the FP flags to move directly to an ARM + // machine register, then use simple bit operations here rather than + // conditional moves. + + switch (ins->opcode()) { + case LIR_eqd: SETEQ(rd); break; + case LIR_ltd: SETLO(rd); break; // Note: VFP LT/LE operations require + case LIR_led: SETLS(rd); break; // unsigned LO/LS condition codes! + case LIR_ged: SETGE(rd); break; + case LIR_gtd: SETGT(rd); break; + default: NanoAssert(0); break; + } + + freeResourcesOf(ins); + + asm_cmpd(ins); +} + +void +Assembler::asm_cond(LIns* ins) +{ + Register rd = prepareResultReg(ins, GpRegs); + LOpcode op = ins->opcode(); + + switch(op) + { + case LIR_eqi: SETEQ(rd); break; + case LIR_lti: SETLT(rd); break; + case LIR_lei: SETLE(rd); break; + case LIR_gti: SETGT(rd); break; + case LIR_gei: SETGE(rd); break; + case LIR_ltui: SETLO(rd); break; + case LIR_leui: SETLS(rd); break; + case LIR_gtui: SETHI(rd); break; + case LIR_geui: SETHS(rd); break; + default: NanoAssert(0); break; + } + + freeResourcesOf(ins); + + asm_cmp(ins); +} + +void +Assembler::asm_arith(LIns* ins) +{ + LOpcode op = ins->opcode(); + LIns* lhs = ins->oprnd1(); + LIns* rhs = ins->oprnd2(); + + // We always need the result register and the first operand register, so + // find them up-front. (If the second operand is constant it is encoded + // differently.) + Register rd = prepareResultReg(ins, GpRegs); + + // Try to re-use the result register for operand 1. + Register rn = lhs->isInReg() ? lhs->getReg() : rd; + + // If the rhs is constant, we can use the instruction-specific code to + // determine if the value can be encoded in an ARM instruction. If the + // value cannot be encoded, it will be loaded into a register. + // + // Note that the MUL instruction can never take an immediate argument so + // even if the argument is constant, we must allocate a register for it. + if (rhs->isImmI() && (op != LIR_muli) && (op != LIR_mulxovi) && (op != LIR_muljovi)) + { + int32_t immI = rhs->immI(); + + switch (op) + { + case LIR_addi: asm_add_imm(rd, rn, immI); break; + case LIR_addjovi: + case LIR_addxovi: asm_add_imm(rd, rn, immI, 1); break; + case LIR_subi: asm_sub_imm(rd, rn, immI); break; + case LIR_subjovi: + case LIR_subxovi: asm_sub_imm(rd, rn, immI, 1); break; + case LIR_andi: asm_and_imm(rd, rn, immI); break; + case LIR_ori: asm_orr_imm(rd, rn, immI); break; + case LIR_xori: asm_eor_imm(rd, rn, immI); break; + case LIR_lshi: LSLi(rd, rn, immI); break; + case LIR_rshi: ASRi(rd, rn, immI); break; + case LIR_rshui: LSRi(rd, rn, immI); break; + + default: + NanoAssertMsg(0, "Unsupported"); + break; + } + + freeResourcesOf(ins); + if (rd == rn) { + // Mark the re-used register as active. + NanoAssert(!lhs->isInReg()); + findSpecificRegForUnallocated(lhs, rd); + } + return; + } + + // The rhs is either already in a register or cannot be encoded as an + // Operand 2 constant for this operation. + + Register rm = rhs->isInReg() ? rhs->getReg() : rd; + if ((rm == rn) && (lhs != rhs)) { + // We can't re-use the result register for both arguments, so force one + // into its own register. We favour re-use for operand 2 (rm) here as + // it is more likely to take a fast path for LIR_mul on ARMv5. + rn = findRegFor(lhs, GpRegs & ~rmask(rd)); + NanoAssert(lhs->isInReg()); + } + + switch (op) + { + case LIR_addi: ADDs(rd, rn, rm, 0); break; + case LIR_addjovi: + case LIR_addxovi: ADDs(rd, rn, rm, 1); break; + case LIR_subi: SUBs(rd, rn, rm, 0); break; + case LIR_subjovi: + case LIR_subxovi: SUBs(rd, rn, rm, 1); break; + case LIR_andi: ANDs(rd, rn, rm, 0); break; + case LIR_ori: ORRs(rd, rn, rm, 0); break; + case LIR_xori: EORs(rd, rn, rm, 0); break; + + case LIR_muli: + if (!ARM_ARCH_AT_LEAST(6) && (rd == rn)) { + // ARMv4 and ARMv5 cannot handle a MUL where rd == rn, so + // explicitly assign a new register to rn. + NanoAssert(!lhs->isInReg()); + rn = findRegFor(lhs, GpRegs & ~rmask(rd) & ~rmask(rm)); + if (lhs == rhs) { + rm = rn; + } + } + MUL(rd, rn, rm); + break; + case LIR_muljovi: + case LIR_mulxovi: + if (!ARM_ARCH_AT_LEAST(6) && (rd == rn)) { + // ARMv5 (and earlier) cannot handle a MUL where rd == rn, so + // if that is the case, explicitly assign a new register to rn. + NanoAssert(!lhs->isInReg()); + rn = findRegFor(lhs, GpRegs & ~rmask(rd) & ~rmask(rm)); + if (lhs == rhs) { + rm = rn; + } + } + // ARM cannot automatically detect overflow from a MUL operation, + // so we have to perform some other arithmetic: + // SMULL rr, ip, ra, rb + // CMP ip, rr, ASR #31 + // An explanation can be found in bug 521161. This sets Z if we did + // _not_ overflow, and clears it if we did. + ALUr_shi(AL, cmp, 1, SBZ, IP, rd, ASR_imm, 31); + SMULL(rd, IP, rn, rm); + break; + + // The shift operations need a mask to match the JavaScript + // specification because the ARM architecture allows a greater shift + // range than JavaScript. + case LIR_lshi: + LSL(rd, rn, IP); + ANDi(IP, rm, 0x1f); + break; + case LIR_rshi: + ASR(rd, rn, IP); + ANDi(IP, rm, 0x1f); + break; + case LIR_rshui: + LSR(rd, rn, IP); + ANDi(IP, rm, 0x1f); + break; + default: + NanoAssertMsg(0, "Unsupported"); + break; + } + + freeResourcesOf(ins); + // If we re-used the result register, mark it as active. + if (rn == rd) { + NanoAssert(!lhs->isInReg()); + findSpecificRegForUnallocated(lhs, rd); + } else if (rm == rd) { + NanoAssert(!rhs->isInReg()); + findSpecificRegForUnallocated(rhs, rd); + } else { + NanoAssert(lhs->isInReg()); + NanoAssert(rhs->isInReg()); + } +} + +void +Assembler::asm_neg_not(LIns* ins) +{ + LIns* lhs = ins->oprnd1(); + Register rr = prepareResultReg(ins, GpRegs); + + // If 'lhs' isn't in a register, we can give it the result register. + Register ra = lhs->isInReg() ? lhs->getReg() : rr; + + if (ins->isop(LIR_noti)) { + MVN(rr, ra); + } else { + NanoAssert(ins->isop(LIR_negi)); + RSBS(rr, ra); + } + + freeResourcesOf(ins); + if (!lhs->isInReg()) { + NanoAssert(ra == rr); + // Update the register state to indicate that we've claimed ra for lhs. + findSpecificRegForUnallocated(lhs, ra); + } +} + +void +Assembler::asm_load32(LIns* ins) +{ + LOpcode op = ins->opcode(); + LIns* base = ins->oprnd1(); + int d = ins->disp(); + + Register rt = prepareResultReg(ins, GpRegs); + // Try to re-use the result register for the base pointer. + Register rn = base->isInReg() ? base->getReg() : rt; + + // TODO: The x86 back-end has a special case where the base address is + // given by LIR_addp. The same technique may be useful here to take + // advantage of ARM's register+register addressing mode. + + switch (op) { + case LIR_lduc2ui: + if (isU12(-d) || isU12(d)) { + LDRB(rt, rn, d); + } else { + LDRB(rt, IP, d%4096); + asm_add_imm(IP, rn, d-(d%4096)); + } + break; + case LIR_ldus2ui: + // Some ARM machines require 2-byte alignment here. + // Similar to the lduc2ui case, but the max offset is smaller. + if (isU8(-d) || isU8(d)) { + LDRH(rt, rn, d); + } else { + LDRH(rt, IP, d%256); + asm_add_imm(IP, rn, d-(d%256)); + } + break; + case LIR_ldi: + // Some ARM machines require 4-byte alignment here. + if (isU12(-d) || isU12(d)) { + LDR(rt, rn, d); + } else { + LDR(rt, IP, d%4096); + asm_add_imm(IP, rn, d-(d%4096)); + } + break; + case LIR_ldc2i: + // Like LIR_lduc2ui, but sign-extend. + // Some ARM machines require 2-byte alignment here. + if (isU8(-d) || isU8(d)) { + LDRSB(rt, rn, d); + } else { + LDRSB(rn, IP, d%256); + asm_add_imm(IP, rn, d-(d%256)); + } + break; + case LIR_lds2i: + // Like LIR_ldus2ui, but sign-extend. + if (isU8(-d) || isU8(d)) { + LDRSH(rt, rn, d); + } else { + LDRSH(rt, IP, d%256); + asm_add_imm(IP, rn, d-(d%256)); + } + break; + default: + NanoAssertMsg(0, "asm_load32 should never receive this LIR opcode"); + break; + } + + freeResourcesOf(ins); + + if (rn == rt) { + NanoAssert(!base->isInReg()); + findSpecificRegForUnallocated(base, rn); + } +} + +void +Assembler::asm_cmov(LIns* ins) +{ + LIns* condval = ins->oprnd1(); + LIns* iftrue = ins->oprnd2(); + LIns* iffalse = ins->oprnd3(); + RegisterMask allow = ins->isD() ? FpRegs : GpRegs; + ConditionCode cc; + + NanoAssert(condval->isCmp()); + NanoAssert((ins->isop(LIR_cmovi) && iftrue->isI() && iffalse->isI()) || + (ins->isop(LIR_cmovd) && iftrue->isD() && iffalse->isD())); + + Register rd = prepareResultReg(ins, allow); + + // Try to re-use the result register for one of the arguments. + Register rt = iftrue->isInReg() ? iftrue->getReg() : rd; + Register rf = iffalse->isInReg() ? iffalse->getReg() : rd; + // Note that iftrue and iffalse may actually be the same, though it + // shouldn't happen with the LIR optimizers turned on. + if ((rt == rf) && (iftrue != iffalse)) { + // We can't re-use the result register for both arguments, so force one + // into its own register. + rf = findRegFor(iffalse, allow & ~rmask(rd)); + NanoAssert(iffalse->isInReg()); + } + + switch(condval->opcode()) { + default: NanoAssert(0); + // Integer comparisons. + case LIR_eqi: cc = EQ; break; + case LIR_lti: cc = LT; break; + case LIR_lei: cc = LE; break; + case LIR_gti: cc = GT; break; + case LIR_gei: cc = GE; break; + case LIR_ltui: cc = LO; break; + case LIR_leui: cc = LS; break; + case LIR_gtui: cc = HI; break; + case LIR_geui: cc = HS; break; + // VFP comparisons. + case LIR_eqd: cc = EQ; break; + case LIR_ltd: cc = LO; break; + case LIR_led: cc = LS; break; + case LIR_ged: cc = GE; break; + case LIR_gtd: cc = GT; break; + } + + // Emit something like this: + // CMP [...] + // MOV(CC) rd, rf + // MOV(!CC) rd, rt + // If the destination was re-used for an input, the corresponding MOV will + // be omitted as it will be redundant. + if (ins->isI()) { + if (rd != rf) { + MOV_cond(OppositeCond(cc), rd, rf); + } + if (rd != rt) { + MOV_cond(cc, rd, rt); + } + } else if (ins->isD()) { + // The VFP sequence is similar to the integer sequence, but uses a + // VFP instruction in place of MOV. + NanoAssert(ARM_VFP); + if (rd != rf) { + FCPYD_cond(OppositeCond(cc), rd, rf); + } + if (rd != rt) { + FCPYD_cond(cc, rd, rt); + } + } else { + NanoAssert(0); + } + + freeResourcesOf(ins); + + // If we re-used the result register, mark it as active for either iftrue + // or iffalse (or both in the corner-case where they're the same). + if (rt == rd) { + NanoAssert(!iftrue->isInReg()); + findSpecificRegForUnallocated(iftrue, rd); + } else if (rf == rd) { + NanoAssert(!iffalse->isInReg()); + findSpecificRegForUnallocated(iffalse, rd); + } else { + NanoAssert(iffalse->isInReg()); + NanoAssert(iftrue->isInReg()); + } + + asm_cmp(condval); +} + +void +Assembler::asm_qhi(LIns* ins) +{ + Register rd = prepareResultReg(ins, GpRegs); + LIns *lhs = ins->oprnd1(); + int d = findMemFor(lhs); + + LDR(rd, FP, d+4); + + freeResourcesOf(ins); +} + +void +Assembler::asm_qlo(LIns* ins) +{ + Register rd = prepareResultReg(ins, GpRegs); + LIns *lhs = ins->oprnd1(); + int d = findMemFor(lhs); + + LDR(rd, FP, d); + + freeResourcesOf(ins); +} + +void +Assembler::asm_param(LIns* ins) +{ + uint32_t a = ins->paramArg(); + uint32_t kind = ins->paramKind(); + if (kind == 0) { + // Ordinary parameter. These are always (32-bit-)word-sized, and will + // be in the first four registers (argRegs) and then on the stack. + if (a < 4) { + // Register argument. + prepareResultReg(ins, rmask(argRegs[a])); + } else { + // Stack argument. + Register r = prepareResultReg(ins, GpRegs); + int d = (a - 4) * sizeof(intptr_t) + 8; + LDR(r, FP, d); + } + } else { + // Saved parameter. + NanoAssert(a < (sizeof(savedRegs)/sizeof(savedRegs[0]))); + prepareResultReg(ins, rmask(savedRegs[a])); + } + freeResourcesOf(ins); +} + +void +Assembler::asm_immi(LIns* ins) +{ + Register rd = prepareResultReg(ins, GpRegs); + asm_ld_imm(rd, ins->immI()); + freeResourcesOf(ins); +} + +void +Assembler::asm_ret(LIns *ins) +{ + genEpilogue(); + + // NB: our contract with genEpilogue is actually that the return value + // we are intending for R0 is currently IP, not R0. This has to do with + // the strange dual-nature of the patchable jump in a side-exit. See + // nPatchBranch. + // + // With hardware floating point ABI we can skip this for retd. + if (!(ARM_EABI_HARD && ins->isop(LIR_retd))) { + MOV(IP, R0); + } + + // Pop the stack frame. + MOV(SP,FP); + + releaseRegisters(); + assignSavedRegs(); + LIns *value = ins->oprnd1(); + if (ins->isop(LIR_reti)) { + findSpecificRegFor(value, R0); + } + else { + NanoAssert(ins->isop(LIR_retd)); + if (ARM_VFP) { +#ifdef NJ_ARM_EABI_HARD_FLOAT + findSpecificRegFor(value, D0); +#else + Register reg = findRegFor(value, FpRegs); + FMRRD(R0, R1, reg); +#endif + } else { + NanoAssert(value->isop(LIR_ii2d)); + findSpecificRegFor(value->oprnd1(), R0); // lo + findSpecificRegFor(value->oprnd2(), R1); // hi + } + } +} + +void +Assembler::asm_jtbl(LIns* ins, NIns** table) +{ + Register indexreg = findRegFor(ins->oprnd1(), GpRegs); + Register tmp = registerAllocTmp(GpRegs & ~rmask(indexreg)); + LDR_scaled(PC, tmp, indexreg, 2); // LDR PC, [tmp + index*4] + asm_ld_imm(tmp, (int32_t)table); // tmp = #table +} + +void Assembler::swapCodeChunks() { + if (!_nExitIns) + codeAlloc(exitStart, exitEnd, _nExitIns verbose_only(, exitBytes), NJ_MAX_CPOOL_OFFSET); + if (!_nExitSlot) + _nExitSlot = exitStart; + SWAP(NIns*, _nIns, _nExitIns); + SWAP(NIns*, _nSlot, _nExitSlot); // this one is ARM-specific + SWAP(NIns*, codeStart, exitStart); + SWAP(NIns*, codeEnd, exitEnd); + verbose_only( SWAP(size_t, codeBytes, exitBytes); ) +} + +void Assembler::asm_insert_random_nop() { + NanoAssert(0); // not supported +} + +} +#endif /* FEATURE_NANOJIT */ diff --git a/js/src/nanojit/NativeARM.h b/js/src/nanojit/NativeARM.h new file mode 100644 index 0000000..4b7a940 --- /dev/null +++ b/js/src/nanojit/NativeARM.h @@ -0,0 +1,1117 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * Vladimir Vukicevic + * Jacob Bramley + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#ifndef __nanojit_NativeARM__ +#define __nanojit_NativeARM__ + + +#ifdef PERFM +#include "../vprof/vprof.h" +#define count_instr() _nvprof("arm",1) +#define count_prolog() _nvprof("arm-prolog",1); count_instr(); +#define count_imt() _nvprof("arm-imt",1) count_instr() +#else +#define count_instr() +#define count_prolog() +#define count_imt() +#endif + +#ifdef DEBUG +#define ARM_ARCH_AT_LEAST(wanted) (_config.arm_arch >= (wanted)) +#define ARM_VFP (_config.arm_vfp) +#else +/* Note: Non DEBUG builds will ignore arm_arch if it is lower than + NJ_COMPILER_ARM_ARCH, and will ignore arm_vfp if NJ_COMPILER_ARM_ARCH + is greater or equal to 7. */ +#define ARM_ARCH_AT_LEAST(wanted) \ + ((NJ_COMPILER_ARM_ARCH >= (wanted)) || (_config.arm_arch >= (wanted))) +#define ARM_VFP ((NJ_COMPILER_ARM_ARCH >= 7) || (_config.arm_vfp)) +#endif + +namespace nanojit +{ +#if defined VMCFG_DOUBLE_MSW_FIRST || defined _MSC_VER +# undef NJ_ARM_EABI +#else +# define NJ_ARM_EABI 1 +#endif + +// GCC defines __ARM_PCS_VFP if it uses hardware floating point ABI +// See http://gcc.gnu.org/viewcvs?view=revision&revision=162637 +#ifdef __ARM_PCS_VFP +# define NJ_ARM_EABI_HARD_FLOAT 1 +#endif + +#ifdef NJ_ARM_EABI_HARD_FLOAT +# define ARM_EABI_HARD true +#else +# define ARM_EABI_HARD false +#endif + +// only d0-d7 are used; in addition, we'll use d0 as s0-s1 for i2d/u2f/etc. +#define NJ_VFP_MAX_REGISTERS 8 +#define NJ_MAX_REGISTERS (11 + NJ_VFP_MAX_REGISTERS) +#define NJ_MAX_STACK_ENTRY 4096 +#define NJ_MAX_PARAMETERS 16 +#define NJ_ALIGN_STACK 8 + +#define NJ_JTBL_SUPPORTED 1 +#define NJ_EXPANDED_LOADSTORE_SUPPORTED 1 +#define NJ_F2I_SUPPORTED 1 +#define NJ_SOFTFLOAT_SUPPORTED 1 +#define NJ_DIVI_SUPPORTED 0 + +#define NJ_CONSTANT_POOLS +const int NJ_MAX_CPOOL_OFFSET = 4096; +const int NJ_CPOOL_SIZE = 16; + +const int LARGEST_UNDERRUN_PROT = 32; // largest value passed to underrunProtect + +typedef int NIns; + +// Bytes of icache to flush after Assembler::patch +const size_t LARGEST_BRANCH_PATCH = 2 * sizeof(NIns); + +/* ARM registers */ +typedef uint32_t Register; +static const Register + R0 = { 0 }, + R1 = { 1 }, + R2 = { 2 }, + R3 = { 3 }, + R4 = { 4 }, + R5 = { 5 }, + R6 = { 6 }, + R7 = { 7 }, + R8 = { 8 }, + R9 = { 9 }, + R10 = { 10 }, + FP = { 11 }, + IP = { 12 }, + SP = { 13 }, + LR = { 14 }, + PC = { 15 }, + + // VFP regs (we currently only use D0-D7 and S0) + D0 = { 16 }, + D1 = { 17 }, + D2 = { 18 }, + D3 = { 19 }, + D4 = { 20 }, + D5 = { 21 }, + D6 = { 22 }, + D7 = { 23 }, + // D8-D15 are caller-saved registers that we don't currently handle. + + FirstFloatReg = D0, + LastFloatReg = D7, + + deprecated_UnknownReg = { 32 }, // XXX: remove eventually, see bug 538924 + + // S0 overlaps with D0 and is hard-coded into i2d and u2f operations + S0 = { 24 }, + + SBZ = { 0 } ; // Used for 'should-be-zero' fields in instructions with + // unused register fields. + +/* winmo builds error with C2057 and C2229 on usage of First/LastRegNum as R0/D7 */ +static const uint32_t FirstRegNum = 0; /* R0 */ +static const uint32_t LastRegNum = 23; /* D7 */ +} + +#define NJ_USE_UINT32_REGISTER 1 +#include "NativeCommon.h" + +namespace nanojit +{ + +/* ARM condition codes */ +typedef enum { + EQ = 0x0, // Equal + NE = 0x1, // Not Equal + CS = 0x2, // Carry Set (or HS) + HS = 0x2, + CC = 0x3, // Carry Clear (or LO) + LO = 0x3, + MI = 0x4, // MInus + PL = 0x5, // PLus + VS = 0x6, // oVerflow Set + VC = 0x7, // oVerflow Clear + HI = 0x8, // HIgher + LS = 0x9, // Lower or Same + GE = 0xA, // Greater or Equal + LT = 0xB, // Less Than + GT = 0xC, // Greater Than + LE = 0xD, // Less or Equal + AL = 0xE, // ALways + + // Note that condition code NV is unpredictable on ARMv3 and ARMv4, and has + // special meaning for ARMv5 onwards. As such, it should never be used in + // an instruction encoding unless the special (ARMv5+) meaning is required. + NV = 0xF // NeVer +} ConditionCode; +#define IsCond(cc) (((cc) >= EQ) && ((cc) <= AL)) + +// Bit 0 of the condition code can be flipped to obtain the opposite condition. +// However, this won't work for AL because its opposite — NV — has special +// meaning. +#define OppositeCond(cc) ((ConditionCode)((unsigned int)(cc)^0x1)) + +typedef int RegisterMask; +typedef struct _FragInfo { + RegisterMask needRestoring; + NIns* epilogue; +} FragInfo; + +typedef struct _ParameterRegisters { + int stkd; + Register r; +#ifdef NJ_ARM_EABI_HARD_FLOAT + Register float_r; +#endif +} ParameterRegisters; + +#ifdef NJ_ARM_EABI_HARD_FLOAT +#define init_params(a,b,c) { (a), (b), (c) } +#else +#define init_params(a,b,c) { (a), (b) } +#endif + +// D0-D7 are not saved; D8-D15 are, but we don't use those, +// so we don't have to worry about saving/restoring them +static const RegisterMask SavedFpRegs = 0; +static const RegisterMask SavedRegs = 1<= LSL_imm) && ((sh) <= ROR_reg)) + +#define LD32_size 8 + +#define BEGIN_NATIVE_CODE(x) \ + { DWORD* _nIns = (uint8_t*)x + +#define END_NATIVE_CODE(x) \ + (x) = (dictwordp*)_nIns; } + +// BX +#define BX(_r) do { \ + underrunProtect(4); \ + NanoAssert(IsGpReg(_r)); \ + *(--_nIns) = (NIns)( COND_AL | (0x12<<20) | (0xFFF<<8) | (1<<4) | (_r)); \ + asm_output("bx %s", gpn(_r)); } while(0) + +/* + * ALU operations + */ + +enum { + ARM_and = 0, + ARM_eor = 1, + ARM_sub = 2, + ARM_rsb = 3, + ARM_add = 4, + ARM_adc = 5, + ARM_sbc = 6, + ARM_rsc = 7, + ARM_tst = 8, + ARM_teq = 9, + ARM_cmp = 10, + ARM_cmn = 11, + ARM_orr = 12, + ARM_mov = 13, + ARM_bic = 14, + ARM_mvn = 15 +}; +#define IsOp(op) (((ARM_##op) >= ARM_and) && ((ARM_##op) <= ARM_mvn)) + +// ALU operation with register and 8-bit immediate arguments +// S - bit, 0 or 1, whether the CPSR register is updated +// rd - destination register +// rl - first (left) operand register +// op2imm - operand 2 immediate. Use encOp2Imm (from NativeARM.cpp) to calculate this. +#define ALUi(cond, op, S, rd, rl, op2imm) ALUi_chk(cond, op, S, rd, rl, op2imm, 1) +#define ALUi_chk(cond, op, S, rd, rl, op2imm, chk) do {\ + if (chk) underrunProtect(4);\ + NanoAssert(IsCond(cond));\ + NanoAssert(IsOp(op));\ + NanoAssert(((S)==0) || ((S)==1));\ + NanoAssert(IsGpReg(rd) && IsGpReg(rl));\ + NanoAssert(isOp2Imm(op2imm));\ + *(--_nIns) = (NIns) ((cond)<<28 | OP_IMM | (ARM_##op)<<21 | (S)<<20 | (rl)<<16 | (rd)<<12 | (op2imm));\ + if (ARM_##op == ARM_mov || ARM_##op == ARM_mvn) { \ + asm_output("%s%s%s %s, #0x%X", #op, condNames[cond], (S)?"s":"", gpn(rd), decOp2Imm(op2imm));\ + } else if (ARM_##op >= ARM_tst && ARM_##op <= ARM_cmn) { \ + NanoAssert(S==1);\ + asm_output("%s%s %s, #0x%X", #op, condNames[cond], gpn(rl), decOp2Imm(op2imm));\ + } else { \ + asm_output("%s%s%s %s, %s, #0x%X", #op, condNames[cond], (S)?"s":"", gpn(rd), gpn(rl), decOp2Imm(op2imm));\ + }\ + } while (0) + +// ALU operation with two register arguments +// S - bit, 0 or 1, whether the CPSR register is updated +// rd - destination register +// rl - first (left) operand register +// rr - first (left) operand register +#define ALUr(cond, op, S, rd, rl, rr) ALUr_chk(cond, op, S, rd, rl, rr, 1) +#define ALUr_chk(cond, op, S, rd, rl, rr, chk) do {\ + if (chk) underrunProtect(4);\ + NanoAssert(IsCond(cond));\ + NanoAssert(IsOp(op));\ + NanoAssert(((S)==0) || ((S)==1));\ + NanoAssert(IsGpReg(rd) && IsGpReg(rl) && IsGpReg(rr));\ + *(--_nIns) = (NIns) ((cond)<<28 |(ARM_##op)<<21 | (S)<<20 | (rl)<<16 | (rd)<<12 | (rr));\ + if (ARM_##op == ARM_mov || ARM_##op == ARM_mvn) { \ + asm_output("%s%s%s %s, %s", #op, condNames[cond], (S)?"s":"", gpn(rd), gpn(rr));\ + } else if (ARM_##op >= ARM_tst && ARM_##op <= ARM_cmn) { \ + NanoAssert(S==1);\ + asm_output("%s%s %s, %s", #op, condNames[cond], gpn(rl), gpn(rr));\ + } else { \ + asm_output("%s%s%s %s, %s, %s", #op, condNames[cond], (S)?"s":"", gpn(rd), gpn(rl), gpn(rr));\ + }\ + } while (0) + +// ALU operation with two register arguments, with rr operated on by a shift and shift immediate +// S - bit, 0 or 1, whether the CPSR register is updated +// rd - destination register +// rl - first (left) operand register +// rr - second (right) operand register +// sh - a ShiftOperator +// imm - immediate argument to shift operator, 5 bits (0..31) +#define ALUr_shi(cond, op, S, rd, rl, rr, sh, imm) do {\ + underrunProtect(4);\ + NanoAssert(IsCond(cond));\ + NanoAssert(IsOp(op));\ + NanoAssert(((S)==0) || ((S)==1));\ + NanoAssert(IsGpReg(rd) && IsGpReg(rl) && IsGpReg(rr));\ + NanoAssert(IsShift(sh));\ + NanoAssert((imm)>=0 && (imm)<32);\ + *(--_nIns) = (NIns) ((cond)<<28 |(ARM_##op)<<21 | (S)<<20 | (rl)<<16 | (rd)<<12 | (imm)<<7 | (sh)<<4 | (rr));\ + if (ARM_##op == ARM_mov || ARM_##op == ARM_mvn) { \ + NanoAssert(rl==0); \ + asm_output("%s%s%s %s, %s, %s #%d", #op, condNames[cond], (S)?"s":"", gpn(rd), gpn(rr), shiftNames[sh], (imm));\ + } else if (ARM_##op >= ARM_tst && ARM_##op <= ARM_cmn) { \ + NanoAssert(S==1);\ + NanoAssert(rd==0);\ + asm_output("%s%s %s, %s, %s #%d", #op, condNames[cond], gpn(rl), gpn(rr), shiftNames[sh], (imm));\ + } else { \ + asm_output("%s%s%s %s, %s, %s, %s #%d", #op, condNames[cond], (S)?"s":"", gpn(rd), gpn(rl), gpn(rr), shiftNames[sh], (imm));\ + }\ + } while (0) + +// ALU operation with two register arguments, with rr operated on by a shift and shift register +// S - bit, 0 or 1, whether the CPSR register is updated +// rd - destination register +// rl - first (left) operand register +// rr - first (left) operand register +// sh - a ShiftOperator +// rs - shift operand register +#define ALUr_shr(cond, op, S, rd, rl, rr, sh, rs) do {\ + underrunProtect(4);\ + NanoAssert(IsCond(cond));\ + NanoAssert(IsOp(op));\ + NanoAssert(((S)==0) || ((S)==1));\ + NanoAssert(IsGpReg(rd) && IsGpReg(rl) && IsGpReg(rr) && IsGpReg(rs));\ + NanoAssert(IsShift(sh));\ + *(--_nIns) = (NIns) ((cond)<<28 |(ARM_##op)<<21 | (S)<<20 | (rl)<<16 | (rd)<<12 | (rs)<<8 | (sh)<<4 | (rr));\ + if (ARM_##op == ARM_mov || ARM_##op == ARM_mvn) { \ + asm_output("%s%s%s %s, %s, %s %s", #op, condNames[cond], (S)?"s":"", gpn(rd), gpn(rr), shiftNames[sh], gpn(rs));\ + } else if (ARM_##op >= ARM_tst && ARM_##op <= ARM_cmn) { \ + NanoAssert(S==1);\ + asm_output("%s%s %s, %s, %s %s", #op, condNames[cond], gpn(rl), gpn(rr), shiftNames[sh], gpn(rs));\ + } else { \ + asm_output("%s%s%s %s, %s, %s, %s %s", #op, condNames[cond], (S)?"s":"", gpn(rd), gpn(rl), gpn(rr), shiftNames[sh], gpn(rs));\ + }\ + } while (0) + +// -------- +// Basic arithmetic operations. +// -------- +// Argument naming conventions for these macros: +// _d Destination register. +// _l First (left) operand. +// _r Second (right) operand. +// _op2imm An operand 2 immediate value. Use encOp2Imm to calculate this. +// _s Set to 1 to update the status flags (for subsequent conditional +// tests). Otherwise, set to 0. + +// _d = _l + decOp2Imm(_op2imm) +#define ADDis(_d,_l,_op2imm,_s) ALUi(AL, add, _s, _d, _l, _op2imm) +#define ADDi(_d,_l,_op2imm) ALUi(AL, add, 0, _d, _l, _op2imm) + +// _d = _l & ~decOp2Imm(_op2imm) +#define BICis(_d,_l,_op2imm,_s) ALUi(AL, bic, _s, _d, _l, _op2imm) +#define BICi(_d,_l,_op2imm) ALUi(AL, bic, 0, _d, _l, _op2imm) + +// _d = _l - decOp2Imm(_op2imm) +#define SUBis(_d,_l,_op2imm,_s) ALUi(AL, sub, _s, _d, _l, _op2imm) +#define SUBi(_d,_l,_op2imm) ALUi(AL, sub, 0, _d, _l, _op2imm) + +// _d = _l & decOp2Imm(_op2imm) +#define ANDis(_d,_l,_op2imm,_s) ALUi(AL, and, _s, _d, _l, _op2imm) +#define ANDi(_d,_l,_op2imm) ALUi(AL, and, 0, _d, _l, _op2imm) + +// _d = _l | decOp2Imm(_op2imm) +#define ORRis(_d,_l,_op2imm,_s) ALUi(AL, orr, _s, _d, _l, _op2imm) +#define ORRi(_d,_l,_op2imm) ALUi(AL, orr, 0, _d, _l, _op2imm) + +// _d = _l ^ decOp2Imm(_op2imm) +#define EORis(_d,_l,_op2imm,_s) ALUi(AL, eor, _s, _d, _l, _op2imm) +#define EORi(_d,_l,_op2imm) ALUi(AL, eor, 0, _d, _l, _op2imm) + +// _d = _l | _r +#define ORRs(_d,_l,_r,_s) ALUr(AL, orr, _s, _d, _l, _r) +#define ORR(_d,_l,_r) ALUr(AL, orr, 0, _d, _l, _r) + +// _d = _l & _r +#define ANDs(_d,_l,_r,_s) ALUr(AL, and, _s, _d, _l, _r) +#define AND(_d,_l,_r) ALUr(AL, and, 0, _d, _l, _r) + +// _d = _l ^ _r +#define EORs(_d,_l,_r,_s) ALUr(AL, eor, _s, _d, _l, _r) +#define EOR(_d,_l,_r) ALUr(AL, eor, 0, _d, _l, _r) + +// _d = _l + _r +#define ADDs(_d,_l,_r,_s) ALUr(AL, add, _s, _d, _l, _r) +#define ADD(_d,_l,_r) ALUr(AL, add, 0, _d, _l, _r) + +// _d = _l - _r +#define SUBs(_d,_l,_r,_s) ALUr(AL, sub, _s, _d, _l, _r) +#define SUB(_d,_l,_r) ALUr(AL, sub, 0, _d, _l, _r) + +// -------- +// Other operations. +// -------- + +// [_d_hi,_d] = _l * _r +#define SMULL(_d, _d_hi, _l, _r) do { \ + underrunProtect(4); \ + NanoAssert(ARM_ARCH_AT_LEAST(6) || ((_d ) != (_l))); \ + NanoAssert(ARM_ARCH_AT_LEAST(6) || ((_d_hi) != (_l))); \ + NanoAssert(IsGpReg(_d) && IsGpReg(_d_hi) && IsGpReg(_l) && IsGpReg(_r)); \ + NanoAssert(((_d) != PC) && ((_d_hi) != PC) && ((_l) != PC) && ((_r) != PC)); \ + *(--_nIns) = (NIns)( COND_AL | 0xc00090 | (_d_hi)<<16 | (_d)<<12 | (_r)<<8 | (_l) ); \ + asm_output("smull %s, %s, %s, %s",gpn(_d),gpn(_d_hi),gpn(_l),gpn(_r)); \ +} while(0) + +// _d = _l * _r +#define MUL(_d, _l, _r) do { \ + underrunProtect(4); \ + NanoAssert(ARM_ARCH_AT_LEAST(6) || ((_d) != (_l))); \ + NanoAssert(IsGpReg(_d) && IsGpReg(_l) && IsGpReg(_r)); \ + NanoAssert(((_d) != PC) && ((_l) != PC) && ((_r) != PC)); \ + *(--_nIns) = (NIns)( COND_AL | (_d)<<16 | (_r)<<8 | 0x90 | (_l) ); \ + asm_output("mul %s, %s, %s",gpn(_d),gpn(_l),gpn(_r)); \ +} while(0) + +// RSBS _d, _r +// _d = 0 - _r +#define RSBS(_d,_r) ALUi(AL, rsb, 1, _d, _r, 0) + +// MVN +// _d = ~_r (one's compliment) +#define MVN(_d,_r) ALUr(AL, mvn, 0, _d, 0, _r) +#define MVNis_chk(_d,_op2imm,_stat,_chk) ALUi_chk(AL, mvn, _stat, _d, 0, op2imm, _chk) +#define MVNis(_d,_op2imm,_stat) MVNis_chk(_d,_op2imm,_stat,1); + +// Logical Shift Right (LSR) rotates the bits without maintaining sign extensions. +// MOVS _d, _r, LSR <_s> +// _d = _r >> _s +#define LSR(_d,_r,_s) ALUr_shr(AL, mov, 1, _d, 0, _r, LSR_reg, _s) + +// Logical Shift Right (LSR) rotates the bits without maintaining sign extensions. +// MOVS _d, _r, LSR #(_imm & 0x1f) +// _d = _r >> (_imm & 0x1f) +#define LSRi(_d,_r,_imm) ALUr_shi(AL, mov, 1, _d, 0, _r, LSR_imm, (_imm & 0x1f)) + +// Arithmetic Shift Right (ASR) maintains the sign extension. +// MOVS _d, _r, ASR <_s> +// _d = _r >> _s +#define ASR(_d,_r,_s) ALUr_shr(AL, mov, 1, _d, 0, _r, ASR_reg, _s) + +// Arithmetic Shift Right (ASR) maintains the sign extension. +// MOVS _r, _r, ASR #(_imm & 0x1f) +// _d = _r >> (_imm & 0x1f) +#define ASRi(_d,_r,_imm) ALUr_shi(AL, mov, 1, _d, 0, _r, ASR_imm, (_imm & 0x1f)) + +// Logical Shift Left (LSL). +// MOVS _d, _r, LSL <_s> +// _d = _r << _s +#define LSL(_d, _r, _s) ALUr_shr(AL, mov, 1, _d, 0, _r, LSL_reg, _s) + +// Logical Shift Left (LSL). +// MOVS _d, _r, LSL #(_imm & 0x1f) +// _d = _r << (_imm & 0x1f) +#define LSLi(_d, _r, _imm) ALUr_shi(AL, mov, 1, _d, 0, _r, LSL_imm, (_imm & 0x1f)) + +// TST +#define TST(_l,_r) ALUr(AL, tst, 1, 0, _l, _r) +#define TSTi(_d,_imm) ALUi(AL, tst, 1, 0, _d, _imm) + +// CMP +#define CMP(_l,_r) ALUr(AL, cmp, 1, 0, _l, _r) +#define CMN(_l,_r) ALUr(AL, cmn, 1, 0, _l, _r) + +// MOV +#define MOVis_chk(_d,_op2imm,_stat,_chk) ALUi_chk(AL, mov, _stat, _d, 0, op2imm, _chk) +#define MOVis(_d,_op2imm,_stat) MOVis_chk(_d,_op2imm,_stat,1) +#define MOVi(_d,_op2imm) MOVis(_d,_op2imm,0); + +#define MOV_cond(_cond,_d,_s) ALUr(_cond, mov, 0, _d, 0, _s) + +#define MOV(dr,sr) MOV_cond(AL, dr, sr) + +// _d = [_b+off] +#define LDR(_d,_b,_off) asm_ldr_chk(_d,_b,_off,1) +#define LDR_nochk(_d,_b,_off) asm_ldr_chk(_d,_b,_off,0) + +// _d = [_b + _x<<_s] +#define LDR_scaled(_d, _b, _x, _s) do { \ + NanoAssert(((_s)&31) == _s);\ + NanoAssert(IsGpReg(_d) && IsGpReg(_b) && IsGpReg(_x));\ + underrunProtect(4);\ + *(--_nIns) = (NIns)(COND_AL | (0x79<<20) | ((_b)<<16) | ((_d)<<12) | ((_s)<<7) | (_x));\ + asm_output("ldr %s, [%s, +%s, LSL #%d]", gpn(_d), gpn(_b), gpn(_x), (_s));\ + } while (0) + +// _d = #_imm +#define LDi(_d,_imm) asm_ld_imm(_d,_imm) + +// MOVW and MOVT are ARMv6T2 or newer only + +// MOVW -- writes _imm into _d, zero-extends. +#define MOVWi_cond_chk(_cond,_d,_imm,_chk) do { \ + NanoAssert(isU16(_imm)); \ + NanoAssert(IsGpReg(_d)); \ + NanoAssert(IsCond(_cond)); \ + if (_chk) underrunProtect(4); \ + *(--_nIns) = (NIns)( (_cond)<<28 | 3<<24 | 0<<20 | (((_imm)>>12)&0xf)<<16 | (_d)<<12 | ((_imm)&0xfff) ); \ + asm_output("movw%s %s, #0x%x", condNames[_cond], gpn(_d), (_imm)); \ + } while (0) + +#define MOVWi(_d,_imm) MOVWi_cond_chk(AL, _d, _imm, 1) +#define MOVWi_chk(_d,_imm,_chk) MOVWi_cond_chk(AL, _d, _imm, _chk) +#define MOVWi_cond(_cond,_d,_imm) MOVWi_cond_chk(_cond, _d, _imm, 1) + +// MOVT -- writes _imm into top halfword of _d, does not affect bottom halfword +#define MOVTi_cond_chk(_cond,_d,_imm,_chk) do { \ + NanoAssert(isU16(_imm)); \ + NanoAssert(IsGpReg(_d)); \ + NanoAssert(IsCond(_cond)); \ + if (_chk) underrunProtect(4); \ + *(--_nIns) = (NIns)( (_cond)<<28 | 3<<24 | 4<<20 | (((_imm)>>12)&0xf)<<16 | (_d)<<12 | ((_imm)&0xfff) ); \ + asm_output("movt%s %s, #0x%x", condNames[_cond], gpn(_d), (_imm)); \ + } while (0) + +#define MOVTi(_d,_imm) MOVTi_cond_chk(AL, _d, _imm, 1) +#define MOVTi_chk(_d,_imm,_chk) MOVTi_cond_chk(AL, _d, _imm, _chk) +#define MOVTi_cond(_cond,_d,_imm) MOVTi_cond_chk(_cond, _d, _imm, 1) + +// i386 compat, for Assembler.cpp +#define MR(d,s) MOV(d,s) +#define ST(base,offset,reg) STR(reg,base,offset) + +// Load a byte (8 bits). The offset range is ±4095. +#define LDRB(_d,_n,_off) do { \ + NanoAssert(IsGpReg(_d) && IsGpReg(_n)); \ + underrunProtect(4); \ + if (_off < 0) { \ + NanoAssert(isU12(-(_off))); \ + *(--_nIns) = (NIns)( COND_AL | (0x55<<20) | ((_n)<<16) | ((_d)<<12) | ((-(_off))&0xfff) ); \ + } else { \ + NanoAssert(isU12(_off)); \ + *(--_nIns) = (NIns)( COND_AL | (0x5D<<20) | ((_n)<<16) | ((_d)<<12) | ((_off)&0xfff) ); \ + } \ + asm_output("ldrb %s, [%s,#%d]", gpn(_d),gpn(_n),(_off)); \ + } while(0) + +// Load a byte (8 bits), sign-extend to 32 bits. The offset range is +// ±255 (different from LDRB, same as LDRH/LDRSH) +#define LDRSB(_d,_n,_off) do { \ + NanoAssert(IsGpReg(_d) && IsGpReg(_n)); \ + underrunProtect(4); \ + if (_off < 0) { \ + NanoAssert(isU8(-(_off))); \ + *(--_nIns) = (NIns)( COND_AL | (0x15<<20) | ((_n)<<16) | ((_d)<<12) | ((0xD)<<4) | (((-(_off))&0xf0)<<4) | ((-(_off))&0xf) ); \ + } else { \ + NanoAssert(isU8(_off)); \ + *(--_nIns) = (NIns)( COND_AL | (0x1D<<20) | ((_n)<<16) | ((_d)<<12) | ((0xD)<<4) | (((_off)&0xf0)<<4) | ((_off)&0xf) ); \ + } \ + asm_output("ldrsb %s, [%s,#%d]", gpn(_d),gpn(_n),(_off)); \ + } while(0) + +// Load and sign-extend a half word (16 bits). The offset range is ±255, and +// must be aligned to two bytes on some architectures (the caller is responsible +// for ensuring appropriate alignment) +#define LDRH(_d,_n,_off) do { \ + NanoAssert(IsGpReg(_d) && IsGpReg(_n)); \ + underrunProtect(4); \ + if (_off < 0) { \ + NanoAssert(isU8(-(_off))); \ + *(--_nIns) = (NIns)( COND_AL | (0x15<<20) | ((_n)<<16) | ((_d)<<12) | ((0xB)<<4) | (((-(_off))&0xf0)<<4) | ((-(_off))&0xf) ); \ + } else { \ + NanoAssert(isU8(_off)); \ + *(--_nIns) = (NIns)( COND_AL | (0x1D<<20) | ((_n)<<16) | ((_d)<<12) | ((0xB)<<4) | (((_off)&0xf0)<<4) | ((_off)&0xf) ); \ + } \ + asm_output("ldrh %s, [%s,#%d]", gpn(_d),gpn(_n),(_off)); \ + } while(0) + +// Load and sign-extend a half word (16 bits). The offset range is ±255, and +// must be aligned to two bytes on some architectures (the caller is responsible +// for ensuring appropriate alignment) +#define LDRSH(_d,_n,_off) do { \ + NanoAssert(IsGpReg(_d) && IsGpReg(_n)); \ + underrunProtect(4); \ + if (_off < 0) { \ + NanoAssert(isU8(-(_off))); \ + *(--_nIns) = (NIns)( COND_AL | (0x15<<20) | ((_n)<<16) | ((_d)<<12) | ((0xF)<<4) | (((-(_off))&0xf0)<<4) | ((-(_off))&0xf) ); \ + } else { \ + NanoAssert(isU8(_off)); \ + *(--_nIns) = (NIns)( COND_AL | (0x1D<<20) | ((_n)<<16) | ((_d)<<12) | ((0xF)<<4) | (((_off)&0xf0)<<4) | ((_off)&0xf) ); \ + } \ + asm_output("ldrsh %s, [%s,#%d]", gpn(_d),gpn(_n),(_off)); \ + } while(0) + +// Valid offset for STR and STRB is +/- 4095, STRH only has +/- 255 +#define STR(_d,_n,_off) do { \ + NanoAssert(IsGpReg(_d) && IsGpReg(_n)); \ + NanoAssert(isU12(_off) || isU12(-(_off))); \ + underrunProtect(4); \ + if ((_off)<0) *(--_nIns) = (NIns)( COND_AL | (0x50<<20) | ((_n)<<16) | ((_d)<<12) | ((-(_off))&0xFFF) ); \ + else *(--_nIns) = (NIns)( COND_AL | (0x58<<20) | ((_n)<<16) | ((_d)<<12) | ((_off)&0xFFF) ); \ + asm_output("str %s, [%s, #%d]", gpn(_d), gpn(_n), (_off)); \ + } while(0) + +#define STRB(_d,_n,_off) do { \ + NanoAssert(IsGpReg(_d) && IsGpReg(_n)); \ + NanoAssert(isU12(_off) || isU12(-(_off))); \ + underrunProtect(4); \ + if ((_off)<0) *(--_nIns) = (NIns)( COND_AL | (0x54<<20) | ((_n)<<16) | ((_d)<<12) | ((-(_off))&0xFFF) ); \ + else *(--_nIns) = (NIns)( COND_AL | (0x5C<<20) | ((_n)<<16) | ((_d)<<12) | ((_off)&0xFFF) ); \ + asm_output("strb %s, [%s, #%d]", gpn(_d), gpn(_n), (_off)); \ + } while(0) + +// Only +/- 255 range, unlike STRB/STR +#define STRH(_d,_n,_off) do { \ + NanoAssert(IsGpReg(_d) && IsGpReg(_n)); \ + underrunProtect(4); \ + if ((_off)<0) { \ + NanoAssert(isU8(-(_off))); \ + *(--_nIns) = (NIns)( COND_AL | (0x14<<20) | ((_n)<<16) | ((_d)<<12) | (((-(_off))&0xF0)<<4) | (0xB<<4) | ((-(_off))&0xF) ); \ + } else { \ + NanoAssert(isU8(_off)); \ + *(--_nIns) = (NIns)( COND_AL | (0x1C<<20) | ((_n)<<16) | ((_d)<<12) | (((_off)&0xF0)<<4) | (0xB<<4) | ((_off)&0xF) ); \ + } \ + asm_output("strh %s, [%s, #%d]", gpn(_d), gpn(_n), (_off)); \ + } while(0) + +// Encode a breakpoint. The ID is not important and is ignored by the +// processor, but it can be useful as a marker when debugging emitted code. +#define BKPT_insn ((NIns)( COND_AL | (0x12<<20) | (0x7<<4) )) +#define BKPTi_insn(id) ((NIns)(BKPT_insn | ((id << 4) & 0xfff00) | (id & 0xf))); + +#define BKPT_nochk() BKPTi_nochk(0) +#define BKPTi_nochk(id) do { \ + NanoAssert((id & 0xffff) == id); \ + *(--_nIns) = BKPTi_insn(id); \ + } while (0) + +// STMFD SP!, {reg} +#define PUSHr(_r) do { \ + underrunProtect(4); \ + NanoAssert(IsGpReg(_r)); \ + *(--_nIns) = (NIns)( COND_AL | (0x92<<20) | (SP<<16) | rmask(_r) ); \ + asm_output("push %s",gpn(_r)); } while (0) + +// STMFD SP!,{reglist} +#define PUSH_mask(_mask) do { \ + underrunProtect(4); \ + NanoAssert(isU16(_mask)); \ + *(--_nIns) = (NIns)( COND_AL | (0x92<<20) | (SP<<16) | (_mask) ); \ + asm_output("push %x", (_mask));} while (0) + +// LDMFD SP!,{reg} +#define POPr(_r) do { \ + underrunProtect(4); \ + NanoAssert(IsGpReg(_r)); \ + *(--_nIns) = (NIns)( COND_AL | (0x8B<<20) | (SP<<16) | rmask(_r) ); \ + asm_output("pop %s",gpn(_r));} while (0) + +// LDMFD SP!,{reglist} +#define POP_mask(_mask) do { \ + underrunProtect(4); \ + NanoAssert(isU16(_mask)); \ + *(--_nIns) = (NIns)( COND_AL | (0x8B<<20) | (SP<<16) | (_mask) ); \ + asm_output("pop %x", (_mask));} while (0) + +// PC always points to current instruction + 8, so when calculating pc-relative +// offsets, use PC+8. +#define PC_OFFSET_FROM(target,frompc) ((intptr_t)(target) - ((intptr_t)(frompc) + 8)) + +#define B_cond(_c,_t) \ + B_cond_chk(_c,_t,1) + +#define B_nochk(_t) \ + B_cond_chk(AL,_t,0) + +#define B(t) B_cond(AL,t) +#define BHI(t) B_cond(HI,t) +#define BLS(t) B_cond(LS,t) +#define BHS(t) B_cond(HS,t) +#define BLO(t) B_cond(LO,t) +#define BEQ(t) B_cond(EQ,t) +#define BNE(t) B_cond(NE,t) +#define BLT(t) B_cond(LT,t) +#define BGE(t) B_cond(GE,t) +#define BLE(t) B_cond(LE,t) +#define BGT(t) B_cond(GT,t) +#define BVS(t) B_cond(VS,t) +#define BVC(t) B_cond(VC,t) +#define BCC(t) B_cond(CC,t) +#define BCS(t) B_cond(CS,t) + +#define JMP(t) B(t) +#define JMP_nochk(t) B_nochk(t) + +// MOV(cond) _r, #1 +// MOV(!cond) _r, #0 +#define SET(_r,_cond) do { \ + ConditionCode _opp = OppositeCond(_cond); \ + underrunProtect(8); \ + *(--_nIns) = (NIns)( ( _opp<<28) | (0x3A<<20) | ((_r)<<12) | (0) ); \ + *(--_nIns) = (NIns)( (_cond<<28) | (0x3A<<20) | ((_r)<<12) | (1) ); \ + asm_output("mov%s %s, #1", condNames[_cond], gpn(_r)); \ + asm_output("mov%s %s, #0", condNames[_opp], gpn(_r)); \ + } while (0) + +#define SETEQ(r) SET(r,EQ) +#define SETNE(r) SET(r,NE) +#define SETLT(r) SET(r,LT) +#define SETLE(r) SET(r,LE) +#define SETGT(r) SET(r,GT) +#define SETGE(r) SET(r,GE) +#define SETLO(r) SET(r,LO) +#define SETLS(r) SET(r,LS) +#define SETHI(r) SET(r,HI) +#define SETHS(r) SET(r,HS) +#define SETVS(r) SET(r,VS) +#define SETCS(r) SET(r,CS) + +// Load and sign extend a 16-bit value into a reg +#define MOVSX(_d,_off,_b) do { \ + if ((_off)>=0) { \ + if ((_off)<256) { \ + underrunProtect(4); \ + *(--_nIns) = (NIns)( COND_AL | (0x1D<<20) | ((_b)<<16) | ((_d)<<12) | ((((_off)>>4)&0xF)<<8) | (0xF<<4) | ((_off)&0xF) ); \ + } else if ((_off)<=510) { \ + underrunProtect(8); \ + int rem = (_off) - 255; \ + NanoAssert(rem<256); \ + *(--_nIns) = (NIns)( COND_AL | (0x1D<<20) | ((_d)<<16) | ((_d)<<12) | ((((rem)>>4)&0xF)<<8) | (0xF<<4) | ((rem)&0xF) ); \ + *(--_nIns) = (NIns)( COND_AL | OP_IMM | (1<<23) | ((_b)<<16) | ((_d)<<12) | (0xFF) ); \ + } else { \ + underrunProtect(16); \ + int rem = (_off) & 3; \ + *(--_nIns) = (NIns)( COND_AL | (0x19<<20) | ((_b)<<16) | ((_d)<<12) | (0xF<<4) | (_d) ); \ + asm_output("ldrsh %s,[%s, #%d]",gpn(_d), gpn(_b), (_off)); \ + *(--_nIns) = (NIns)( COND_AL | OP_IMM | (1<<23) | ((_d)<<16) | ((_d)<<12) | rem ); \ + *(--_nIns) = (NIns)( COND_AL | (0x1A<<20) | ((_d)<<12) | (2<<7)| (_d) ); \ + *(--_nIns) = (NIns)( COND_AL | (0x3B<<20) | ((_d)<<12) | (((_off)>>2)&0xFF) ); \ + asm_output("mov %s,%d",gpn(_d),(_off)); \ + } \ + } else { \ + if ((_off)>-256) { \ + underrunProtect(4); \ + *(--_nIns) = (NIns)( COND_AL | (0x15<<20) | ((_b)<<16) | ((_d)<<12) | ((((-(_off))>>4)&0xF)<<8) | (0xF<<4) | ((-(_off))&0xF) ); \ + asm_output("ldrsh %s,[%s, #%d]",gpn(_d), gpn(_b), (_off)); \ + } else if ((_off)>=-510){ \ + underrunProtect(8); \ + int rem = -(_off) - 255; \ + NanoAssert(rem<256); \ + *(--_nIns) = (NIns)( COND_AL | (0x15<<20) | ((_d)<<16) | ((_d)<<12) | ((((rem)>>4)&0xF)<<8) | (0xF<<4) | ((rem)&0xF) ); \ + *(--_nIns) = (NIns)( COND_AL | OP_IMM | (1<<22) | ((_b)<<16) | ((_d)<<12) | (0xFF) ); \ + } else NanoAssert(0); \ + } \ + } while(0) + +/* + * VFP + */ + +#define FMDRR(_Dm,_Rd,_Rn) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(IsFpReg(_Dm) && IsGpReg(_Rd) && IsGpReg(_Rn)); \ + *(--_nIns) = (NIns)( COND_AL | (0xC4<<20) | ((_Rn)<<16) | ((_Rd)<<12) | (0xB1<<4) | (FpRegNum(_Dm)) ); \ + asm_output("fmdrr %s,%s,%s", gpn(_Dm), gpn(_Rd), gpn(_Rn)); \ + } while (0) + +#define FMRRD(_Rd,_Rn,_Dm) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(IsGpReg(_Rd) && IsGpReg(_Rn) && IsFpReg(_Dm)); \ + *(--_nIns) = (NIns)( COND_AL | (0xC5<<20) | ((_Rn)<<16) | ((_Rd)<<12) | (0xB1<<4) | (FpRegNum(_Dm)) ); \ + asm_output("fmrrd %s,%s,%s", gpn(_Rd), gpn(_Rn), gpn(_Dm)); \ + } while (0) + +#define FMRDH(_Rd,_Dn) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(IsGpReg(_Rd) && IsFpReg(_Dn)); \ + *(--_nIns) = (NIns)( COND_AL | (0xE3<<20) | (FpRegNum(_Dn)<<16) | ((_Rd)<<12) | (0xB<<8) | (1<<4) ); \ + asm_output("fmrdh %s,%s", gpn(_Rd), gpn(_Dn)); \ + } while (0) + +#define FMRDL(_Rd,_Dn) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(IsGpReg(_Rd) && IsFpReg(_Dn)); \ + *(--_nIns) = (NIns)( COND_AL | (0xE1<<20) | (FpRegNum(_Dn)<<16) | ((_Rd)<<12) | (0xB<<8) | (1<<4) ); \ + asm_output("fmrdh %s,%s", gpn(_Rd), gpn(_Dn)); \ + } while (0) + +#define FSTD_allowD7(_Dd,_Rn,_offs,_allowD7) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(((_offs)%4) == 0); \ + NanoAssert(isU8((_offs)/4) || isU8(-(_offs)/4)); \ + NanoAssert(IsFpReg(_Dd) && IsGpReg(_Rn)); \ + int negflag = 1<<23; \ + intptr_t offs = (_offs); \ + if (_offs < 0) { \ + negflag = 0<<23; \ + offs = -(offs); \ + } \ + *(--_nIns) = (NIns)( COND_AL | (0xD0<<20) | ((_Rn)<<16) | (FpRegNum(_Dd)<<12) | (0xB<<8) | negflag | ((offs>>2)&0xff) ); \ + asm_output("fstd %s,%s(%d)", gpn(_Dd), gpn(_Rn), _offs); \ + } while (0) + +#define FSTD(_Dd,_Rn,_offs) \ + FSTD_allowD7(_Dd,_Rn,_offs,0) + +#define FLDD_chk(_Dd,_Rn,_offs,_chk) do { \ + if(_chk) underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(((_offs)%4) == 0); \ + NanoAssert(isU8((_offs)/4) || isU8(-(_offs)/4)); \ + NanoAssert(IsFpReg(_Dd) && !IsFpReg(_Rn)); \ + int negflag = 1<<23; \ + intptr_t offs = (_offs); \ + if (_offs < 0) { \ + negflag = 0<<23; \ + offs = -(offs); \ + } \ + *(--_nIns) = (NIns)( COND_AL | (0xD1<<20) | ((_Rn)<<16) | (FpRegNum(_Dd)<<12) | (0xB<<8) | negflag | ((offs>>2)&0xff) ); \ + asm_output("fldd %s,%s(%d)", gpn(_Dd), gpn(_Rn), _offs); \ + } while (0) +#define FLDD(_Dd,_Rn,_offs) FLDD_chk(_Dd,_Rn,_offs,1) + +#define FUITOD(_Dd,_Sm) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(IsFpReg(_Dd) && ((_Sm) == S0)); \ + *(--_nIns) = (NIns)( COND_AL | (0xEB8<<16) | (FpRegNum(_Dd)<<12) | (0x2D<<6) | (0<<5) | (0x0) ); \ + asm_output("fuitod %s,%s", gpn(_Dd), gpn(_Sm)); \ + } while (0) + +#define FNEGD(_Dd,_Dm) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(IsFpReg(_Dd) && IsFpReg(_Dm)); \ + *(--_nIns) = (NIns)( COND_AL | (0xEB1<<16) | (FpRegNum(_Dd)<<12) | (0xB4<<4) | (FpRegNum(_Dm)) ); \ + asm_output("fnegd %s,%s", gpn(_Dd), gpn(_Dm)); \ + } while (0) + +#define FADDD(_Dd,_Dn,_Dm) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(IsFpReg(_Dd) && IsFpReg(_Dn) && IsFpReg(_Dm)); \ + *(--_nIns) = (NIns)( COND_AL | (0xE3<<20) | (FpRegNum(_Dn)<<16) | (FpRegNum(_Dd)<<12) | (0xB0<<4) | (FpRegNum(_Dm)) ); \ + asm_output("faddd %s,%s,%s", gpn(_Dd), gpn(_Dn), gpn(_Dm)); \ + } while (0) + +#define FSUBD(_Dd,_Dn,_Dm) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(IsFpReg(_Dd) && IsFpReg(_Dn) && IsFpReg(_Dm)); \ + *(--_nIns) = (NIns)( COND_AL | (0xE3<<20) | (FpRegNum(_Dn)<<16) | (FpRegNum(_Dd)<<12) | (0xB4<<4) | (FpRegNum(_Dm)) ); \ + asm_output("fsubd %s,%s,%s", gpn(_Dd), gpn(_Dn), gpn(_Dm)); \ + } while (0) + +#define FMULD(_Dd,_Dn,_Dm) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(IsFpReg(_Dd) && IsFpReg(_Dn) && IsFpReg(_Dm)); \ + *(--_nIns) = (NIns)( COND_AL | (0xE2<<20) | (FpRegNum(_Dn)<<16) | (FpRegNum(_Dd)<<12) | (0xB0<<4) | (FpRegNum(_Dm)) ); \ + asm_output("fmuld %s,%s,%s", gpn(_Dd), gpn(_Dn), gpn(_Dm)); \ + } while (0) + +#define FDIVD(_Dd,_Dn,_Dm) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(IsFpReg(_Dd) && IsFpReg(_Dn) && IsFpReg(_Dm)); \ + *(--_nIns) = (NIns)( COND_AL | (0xE8<<20) | (FpRegNum(_Dn)<<16) | (FpRegNum(_Dd)<<12) | (0xB0<<4) | (FpRegNum(_Dm)) ); \ + asm_output("fdivd %s,%s,%s", gpn(_Dd), gpn(_Dn), gpn(_Dm)); \ + } while (0) + +#define FMSTAT() do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + *(--_nIns) = (NIns)( COND_AL | 0x0EF1FA10); \ + asm_output("fmstat"); \ + } while (0) + +#define FCMPD(_Dd,_Dm,_E) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(IsFpReg(_Dd) && IsFpReg(_Dm)); \ + NanoAssert(((_E)==0) || ((_E)==1)); \ + *(--_nIns) = (NIns)( COND_AL | (0xEB4<<16) | (FpRegNum(_Dd)<<12) | (0xB<<8) | ((_E)<<7) | (0x4<<4) | (FpRegNum(_Dm)) ); \ + asm_output("fcmp%sd %s,%s", (((_E)==1)?"e":""), gpn(_Dd), gpn(_Dm)); \ + } while (0) + +#define FCPYD_cond(_cond,_Dd,_Dm) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(IsFpReg(_Dd) && IsFpReg(_Dm)); \ + NanoAssert(IsCond(_cond)); \ + *(--_nIns) = (NIns)( ((_cond)<<28) | (0xEB0<<16) | (FpRegNum(_Dd)<<12) | (0xB4<<4) | (FpRegNum(_Dm)) ); \ + asm_output("fcpyd%s %s,%s", condNames[_cond], gpn(_Dd), gpn(_Dm)); \ + } while (0) +#define FCPYD(_Dd,_Dm) FCPYD_cond(AL,_Dd,_Dm) + +#define FMRS(_Rd,_Sn) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(((_Sn) == S0) && IsGpReg(_Rd)); \ + *(--_nIns) = (NIns)( COND_AL | (0xE1<<20) | (0x0<<16) | ((_Rd)<<12) | (0xA<<8) | (0<<7) | (0x1<<4) ); \ + asm_output("fmrs %s,%s", gpn(_Rd), gpn(_Sn)); \ + } while (0) + +/* + * The following instructions can only be used with S0 as the + * single-precision register; that limitation can be removed if + * needed, but we'd have to teach NJ about all the single precision + * regs, and their encoding is strange (top 4 bits usually in a block, + * low bit elsewhere). + */ + +#define FSITOD(_Dd,_Sm) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(IsFpReg(_Dd) && ((_Sm) == S0)); \ + *(--_nIns) = (NIns)( COND_AL | (0xEB8<<16) | (FpRegNum(_Dd)<<12) | (0x2F<<6) | (0<<5) | (0x0) ); \ + asm_output("fsitod %s,%s", gpn(_Dd), gpn(_Sm)); \ + } while (0) + +#define FMSR(_Sn,_Rd) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(((_Sn) == S0) && IsGpReg(_Rd)); \ + *(--_nIns) = (NIns)( COND_AL | (0xE0<<20) | (0x0<<16) | ((_Rd)<<12) | (0xA<<8) | (0<<7) | (0x1<<4) ); \ + asm_output("fmsr %s,%s", gpn(_Sn), gpn(_Rd)); \ + } while (0) + +#define FMRS(_Rd,_Sn) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(((_Sn) == S0) && IsGpReg(_Rd)); \ + *(--_nIns) = (NIns)( COND_AL | (0xE1<<20) | (0x0<<16) | ((_Rd)<<12) | (0xA<<8) | (0<<7) | (0x1<<4) ); \ + asm_output("fmrs %s,%s", gpn(_Rd), gpn(_Sn)); \ + } while (0) + +#define FMSR(_Sn,_Rd) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(((_Sn) == S0) && IsGpReg(_Rd)); \ + *(--_nIns) = (NIns)( COND_AL | (0xE0<<20) | (0x0<<16) | ((_Rd)<<12) | (0xA<<8) | (0<<7) | (0x1<<4) ); \ + asm_output("fmsr %s,%s", gpn(_Sn), gpn(_Rd)); \ + } while (0) + +#define FCVTSD(_Sd,_Dm) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(((_Sd) == S0) && IsFpReg(_Dm)); \ + *(--_nIns) = (NIns)( COND_AL | (0xEB7<<16) | (0x0<<12) | (0xBC<<4) | (FpRegNum(_Dm)) ); \ + asm_output("[0x%08x] fcvtsd s0,%s", *_nIns, gpn(_Dm)); \ + } while (0) + +#define FCVTDS(_Dd,_Sm) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(((_Sm) == S0) && IsFpReg(_Dd)); \ + *(--_nIns) = (NIns)( COND_AL | (0xEB7<<16) | (FpRegNum(_Dd)<<12) | (0xAC<<4) | (0x0) ); \ + asm_output("fcvtds %s,s0", gpn(_Dd)); \ + } while(0) + +#define FLDS(_Sd,_Rn,_offs) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(((_Sd) == S0) && !IsFpReg(_Rn)); \ + NanoAssert(((_offs)%4) == 0); \ + NanoAssert((isU8((_offs)/4)) || isU8(-(_offs)/4)); \ + int addflag = 1<<23; \ + intptr_t offs = (_offs); \ + if (offs < 0) { \ + addflag = 0; \ + offs = -offs; \ + } \ + *(--_nIns) = (NIns)( COND_AL | (0xD1<<20) | ((_Rn)<<16) | (0x0<<12) | (0xA << 8) | addflag | ((offs>>2)&0xff) ); \ + asm_output("flds s0, [%s, #%d]", gpn(_Rn), (_offs)); \ + } while (0) + +#define FSTS(_Sd,_Rn,_offs) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(((_Sd) == S0) && !IsFpReg(_Rn)); \ + NanoAssert(((_offs)%4) == 0); \ + NanoAssert((isU8((_offs)/4)) || isU8(-(_offs)/4)); \ + int addflag = 1<<23; \ + intptr_t offs = (_offs); \ + if (offs < 0) { \ + addflag = 0; \ + offs = -offs; \ + } \ + *(--_nIns) = (NIns)( COND_AL | (0xD0<<20) | ((_Rn)<<16) | (0x0<<12) | (0xA << 8) | addflag | ((offs>>2)&0xff) ); \ + asm_output("fsts s0, [%s, #%d]", gpn(_Rn), (_offs)); \ + } while (0) + +#define FTOSID(_Sd,_Dm) do { \ + underrunProtect(4); \ + NanoAssert(ARM_VFP); \ + NanoAssert(((_Sd) == S0) && IsFpReg(_Dm)); \ + *(--_nIns) = (NIns)( COND_AL | (0xEBD<<16) | (0x0<<12) | (0xB4<<4) | FpRegNum(_Dm) ); \ + asm_output("ftosid s0, %s", gpn(_Dm)); \ + } while (0) + +} // namespace nanojit +#endif // __nanojit_NativeARM__ diff --git a/js/src/nanojit/NativeCommon.h b/js/src/nanojit/NativeCommon.h new file mode 100644 index 0000000..aed175b --- /dev/null +++ b/js/src/nanojit/NativeCommon.h @@ -0,0 +1,122 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __nanojit_NativeCommon__ +#define __nanojit_NativeCommon__ + +namespace nanojit +{ + // In debug builds, Register is defined as a non-integer type to avoid + // possible mix-ups with RegisterMask and integer offsets. In non-debug + // builds, it's defined as an integer just in case some compilers fail to + // optimize single-element structs in the obvious way. + // + // Note that in either case, a Register can be initialized like so: + // + // Register r = { 0 }; + // + // In the debug case it's a struct initializer, in the non-debug case it's + // a scalar initializer. + // + // XXX: The exception to all the above is that if NJ_USE_UINT32_REGISTER + // is defined, the back-end is responsible for defining its own Register + // type, which will probably be an enum. This is just to give all the + // back-ends a chance to transition smoothly. +#if defined(NJ_USE_UINT32_REGISTER) + #define REGNUM(r) (r) + +#elif defined(DEBUG) || defined(__SUNPRO_CC) + // Always use struct declaration for 'Register' with + // Solaris Studio C++ compiler, because it has a bug: + // Scalar type can not be initialized by '{1}'. + // See bug 603560. + + struct Register { + uint32_t n; // the register number + }; + + static inline uint32_t REGNUM(Register r) { + return r.n; + } + + static inline Register operator+(Register r, int c) + { + r.n += c; + return r; + } + + static inline bool operator==(Register r1, Register r2) + { + return r1.n == r2.n; + } + + static inline bool operator!=(Register r1, Register r2) + { + return r1.n != r2.n; + } + + static inline bool operator<=(Register r1, Register r2) + { + return r1.n <= r2.n; + } + + static inline bool operator<(Register r1, Register r2) + { + return r1.n < r2.n; + } + + static inline bool operator>=(Register r1, Register r2) + { + return r1.n >= r2.n; + } + + static inline bool operator>(Register r1, Register r2) + { + return r1.n > r2.n; + } +#else + typedef uint32_t Register; + + static inline uint32_t REGNUM(Register r) { + return r; + } +#endif +} // namespace nanojit + +#endif // __nanojit_NativeCommon__ diff --git a/js/src/nanojit/NativeMIPS.cpp b/js/src/nanojit/NativeMIPS.cpp new file mode 100644 index 0000000..114d2a5 --- /dev/null +++ b/js/src/nanojit/NativeMIPS.cpp @@ -0,0 +1,2073 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * MIPS Technologies Inc + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Dearman + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nanojit.h" + +#if defined FEATURE_NANOJIT && defined NANOJIT_MIPS + +namespace nanojit +{ +#ifdef NJ_VERBOSE + const char *regNames[] = { + "$zr", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", + "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", + "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", + "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra", + + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" + }; + + const char *cname[16] = { + "f", "un", "eq", "ueq", + "olt", "ult", "ole", "ule", + "sf", "ngle", "seq", "ngl", + "lt", "nge", "le", "ngt" + }; + + const char *fname[32] = { + "resv", "resv", "resv", "resv", + "resv", "resv", "resv", "resv", + "resv", "resv", "resv", "resv", + "resv", "resv", "resv", "resv", + "s", "d", "resv", "resv", + "w", "l", "ps", "resv", + "resv", "resv", "resv", "resv", + "resv", "resv", "resv", "resv", + }; + + const char *oname[64] = { + "special", "regimm", "j", "jal", "beq", "bne", "blez", "bgtz", + "addi", "addiu", "slti", "sltiu", "andi", "ori", "xori", "lui", + "cop0", "cop1", "cop2", "cop1x", "beql", "bnel", "blezl", "bgtzl", + "resv", "resv", "resv", "resv", "special2", "jalx", "resv", "special3", + "lb", "lh", "lwl", "lw", "lbu", "lhu", "lwr", "resv", + "sb", "sh", "swl", "sw", "resv", "resv", "swr", "cache", + "ll", "lwc1", "lwc2", "pref", "resv", "ldc1", "ldc2", "resv", + "sc", "swc1", "swc2", "resv", "resv", "sdc1", "sdc2", "resv", + }; +#endif + + const Register Assembler::argRegs[] = { A0, A1, A2, A3 }; + const Register Assembler::retRegs[] = { V0, V1 }; + const Register Assembler::savedRegs[] = { + S0, S1, S2, S3, S4, S5, S6, S7, +#ifdef FPCALLEESAVED + FS0, FS1, FS2, FS3, FS4, FS5 +#endif + }; + +#define USE(x) (void)x +#define BADOPCODE(op) NanoAssertMsgf(false, "unexpected opcode %s", lirNames[op]) + + // This function will get will get optimised by the compiler into a known value + static inline bool isLittleEndian(void) + { + const union { + uint32_t ival; + unsigned char cval[4]; + } u = { 1 }; + return u.cval[0] == 1; + } + + // offsets to most/least significant parts of 64bit data in memory + // These functions will get optimised by the compiler into a known value + static inline int mswoff(void) { + return isLittleEndian() ? 4 : 0; + } + + static inline int lswoff(void) { + return isLittleEndian() ? 0 : 4; + } + + static inline Register mswregpair(Register r) { + return Register(r + (isLittleEndian() ? 1 : 0)); + } + + static inline Register lswregpair(Register r) { + return Register(r + (isLittleEndian() ? 0 : 1)); + } + +// These variables affect the code generator +// They can be defined as constants and the compiler will remove +// the unused paths through dead code elimination +// Alternatively they can be defined as variables which will allow +// the exact code generated to be determined at runtime +// +// cpu_has_fpu CPU has fpu +// cpu_has_movn CPU has movn +// cpu_has_cmov CPU has movf/movn instructions +// cpu_has_lsdc1 CPU has ldc1/sdc1 instructions +// cpu_has_lsxdc1 CPU has ldxc1/sdxc1 instructions +// cpu_has_fpuhazard hazard between c.xx.xx & bc1[tf] +// +// Currently the values are initialised bases on preprocessor definitions + +#ifdef DEBUG + // Don't allow the compiler to eliminate dead code for debug builds + #define _CONST +#else + #define _CONST const +#endif + +#if NJ_SOFTFLOAT_SUPPORTED + _CONST bool cpu_has_fpu = false; +#else + _CONST bool cpu_has_fpu = true; +#endif + +#if (__mips==4 || __mips==32 || __mips==64) + _CONST bool cpu_has_cmov = true; +#else + _CONST bool cpu_has_cmov = false; +#endif + +#if __mips != 1 + _CONST bool cpu_has_lsdc1 = true; +#else + _CONST bool cpu_has_lsdc1 = false; +#endif + +#if (__mips==32 || __mips==64) && __mips_isa_rev>=2 + _CONST bool cpu_has_lsdxc1 = true; +#else + _CONST bool cpu_has_lsdxc1 = false; +#endif + +#if (__mips==1 || __mips==2 || __mips==3) + _CONST bool cpu_has_fpuhazard = true; +#else + _CONST bool cpu_has_fpuhazard = false; +#endif +#undef _CONST + + /* Support routines */ + + debug_only ( + // break to debugger when generating code to this address + static NIns *breakAddr; + static void codegenBreak(NIns *genAddr) + { + NanoAssert (breakAddr != genAddr); + } + ) + + // Equivalent to assembler %hi(), %lo() + uint16_t hi(uint32_t v) + { + uint16_t r = v >> 16; + if ((int16_t)(v) < 0) + r += 1; + return r; + } + + int16_t lo(uint32_t v) + { + int16_t r = v; + return r; + } + + void Assembler::asm_li32(Register r, int32_t imm) + { + // general case generating a full 32-bit load + ADDIU(r, r, lo(imm)); + LUI(r, hi(imm)); + } + + void Assembler::asm_li(Register r, int32_t imm) + { +#if !PEDANTIC + if (isU16(imm)) { + ORI(r, ZERO, imm); + return; + } + if (isS16(imm)) { + ADDIU(r, ZERO, imm); + return; + } + if ((imm & 0xffff) == 0) { + LUI(r, uint32_t(imm) >> 16); + return; + } +#endif + asm_li32(r, imm); + } + + // 64 bit immediate load to a register pair + void Assembler::asm_li_d(Register r, int32_t msw, int32_t lsw) + { + if (IsFpReg(r)) { + NanoAssert(cpu_has_fpu); + // li $at,lsw # iff lsw != 0 + // mtc1 $at,$r # may use $0 instead of $at + // li $at,msw # iff (msw != 0) && (msw != lsw) + // mtc1 $at,$(r+1) # may use $0 instead of $at + if (msw == 0) + MTC1(ZERO, r+1); + else { + MTC1(AT, r+1); + // If the MSW & LSW values are different, reload AT + if (msw != lsw) + asm_li(AT, msw); + } + if (lsw == 0) + MTC1(ZERO, r); + else { + MTC1(AT, r); + asm_li(AT, lsw); + } + } + else { + /* + * li $r.lo, lsw + * li $r.hi, msw # will be converted to move $f.hi,$f.lo if (msw==lsw) + */ + if (msw == lsw) + MOVE(mswregpair(r), lswregpair(r)); + else + asm_li(mswregpair(r), msw); + asm_li(lswregpair(r), lsw); + } + } + + void Assembler::asm_move(Register d, Register s) + { + MOVE(d, s); + } + + // General load/store operation + void Assembler::asm_ldst(int op, Register rt, int dr, Register rbase) + { +#if !PEDANTIC + if (isS16(dr)) { + LDST(op, rt, dr, rbase); + return; + } +#endif + + // lui AT,hi(d) + // addu AT,rbase + // ldst rt,lo(d)(AT) + LDST(op, rt, lo(dr), AT); + ADDU(AT, AT, rbase); + LUI(AT, hi(dr)); + } + + void Assembler::asm_ldst64(bool store, Register r, int dr, Register rbase) + { +#if !PEDANTIC + if (isS16(dr) && isS16(dr+4)) { + if (IsGpReg(r)) { + LDST(store ? OP_SW : OP_LW, r+1, dr+4, rbase); + LDST(store ? OP_SW : OP_LW, r, dr, rbase); + } + else { + NanoAssert(cpu_has_fpu); + // NanoAssert((dr & 7) == 0); + if (cpu_has_lsdc1 && ((dr & 7) == 0)) { + // lsdc1 $fr,dr($rbase) + LDST(store ? OP_SDC1 : OP_LDC1, r, dr, rbase); + } + else { + // lswc1 $fr, dr+LSWOFF($rbase) + // lswc1 $fr+1,dr+MSWOFF($rbase) + LDST(store ? OP_SWC1 : OP_LWC1, r+1, dr+mswoff(), rbase); + LDST(store ? OP_SWC1 : OP_LWC1, r, dr+lswoff(), rbase); + } + return; + } + } +#endif + + if (IsGpReg(r)) { + // lui $at,%hi(d) + // addu $at,$rbase + // ldsw $r, %lo(d)($at) + // ldst $r+1,%lo(d+4)($at) + LDST(store ? OP_SW : OP_LW, r+1, lo(dr+4), AT); + LDST(store ? OP_SW : OP_LW, r, lo(dr), AT); + ADDU(AT, AT, rbase); + LUI(AT, hi(dr)); + } + else { + NanoAssert(cpu_has_fpu); + if (cpu_has_lsdxc1) { + // li $at,dr + // lsdcx1 $r,$at($rbase) + if (store) + SDXC1(r, AT, rbase); + else + LDXC1(r, AT, rbase); + asm_li(AT, dr); + } + else if (cpu_has_lsdc1) { + // lui $at,%hi(dr) + // addu $at,$rbase + // lsdc1 $r,%lo(dr)($at) + LDST(store ? OP_SDC1 : OP_LDC1, r, lo(dr), AT); + ADDU(AT, AT, rbase); + LUI(AT, hi(dr)); + } + else { + // lui $at,%hi(d) + // addu $at,$rbase + // lswc1 $r, %lo(d+LSWOFF)($at) + // lswc1 $r+1,%lo(d+MSWOFF)($at) + LDST(store ? OP_SWC1 : OP_LWC1, r+1, lo(dr+mswoff()), AT); + LDST(store ? OP_SWC1 : OP_LWC1, r, lo(dr+lswoff()), AT); + ADDU(AT, AT, rbase); + LUI(AT, hi(dr)); + } + } + } + + void Assembler::asm_store_imm64(LIns *value, int dr, Register rbase) + { + NanoAssert(value->isImmD()); + int32_t msw = value->immDhi(); + int32_t lsw = value->immDlo(); + + // li $at,lsw # iff lsw != 0 + // sw $at,off+LSWOFF($rbase) # may use $0 instead of $at + // li $at,msw # iff (msw != 0) && (msw != lsw) + // sw $at,off+MSWOFF($rbase) # may use $0 instead of $at + + NanoAssert(isS16(dr) && isS16(dr+4)); + + if (lsw == 0) + SW(ZERO, dr+lswoff(), rbase); + else { + SW(AT, dr+lswoff(), rbase); + if (msw != lsw) + asm_li(AT, lsw); + } + if (msw == 0) + SW(ZERO, dr+mswoff(), rbase); + else { + SW(AT, dr+mswoff(), rbase); + // If the MSW & LSW values are different, reload AT + if (msw != lsw) + asm_li(AT, msw); + } + } + + void Assembler::asm_regarg(ArgType ty, LIns* p, Register r) + { + NanoAssert(deprecated_isKnownReg(r)); + if (ty == ARGTYPE_I || ty == ARGTYPE_UI) { + // arg goes in specific register + if (p->isImmI()) + asm_li(r, p->immI()); + else { + if (p->isExtant()) { + if (!p->deprecated_hasKnownReg()) { + // load it into the arg reg + int d = findMemFor(p); + if (p->isop(LIR_allocp)) + ADDIU(r, FP, d); + else + asm_ldst(OP_LW, r, d, FP); + } + else + // it must be in a saved reg + MOVE(r, p->deprecated_getReg()); + } + else { + // this is the last use, so fine to assign it + // to the scratch reg, it's dead after this point. + findSpecificRegFor(p, r); + } + } + } + else { + // Other argument types unsupported + NanoAssert(false); + } + } + + void Assembler::asm_stkarg(LIns* arg, int stkd) + { + bool isF64 = arg->isD(); + Register rr; + if (arg->isExtant() && (rr = arg->deprecated_getReg(), deprecated_isKnownReg(rr))) { + // The argument resides somewhere in registers, so we simply need to + // push it onto the stack. + if (!cpu_has_fpu || !isF64) { + NanoAssert(IsGpReg(rr)); + SW(rr, stkd, SP); + } + else { + NanoAssert(cpu_has_fpu); + NanoAssert(IsFpReg(rr)); + NanoAssert((stkd & 7) == 0); + asm_ldst64(true, rr, stkd, SP); + } + } + else { + // The argument does not reside in registers, so we need to get some + // memory for it and then copy it onto the stack. + int d = findMemFor(arg); + if (!isF64) { + SW(AT, stkd, SP); + if (arg->isop(LIR_allocp)) + ADDIU(AT, FP, d); + else + LW(AT, d, FP); + } + else { + NanoAssert((stkd & 7) == 0); + SW(AT, stkd+4, SP); + LW(AT, d+4, FP); + SW(AT, stkd, SP); + LW(AT, d, FP); + } + } + } + + // Encode a 64-bit floating-point argument using the appropriate ABI. + // This function operates in the same way as asm_arg, except that it will only + // handle arguments where (ArgType)ty == ARGTYPE_D. + void + Assembler::asm_arg_64(LIns* arg, Register& r, Register& fr, int& stkd) + { + // The stack offset always be at least aligned to 4 bytes. + NanoAssert((stkd & 3) == 0); +#if NJ_SOFTFLOAT_SUPPORTED + NanoAssert(arg->isop(LIR_ii2d)); +#else + NanoAssert(cpu_has_fpu); +#endif + + // O32 ABI requires that 64-bit arguments are aligned on even-numbered + // registers, as A0:A1/FA0 or A2:A3/FA1. Use the stack offset to keep track + // where we are + if (stkd & 4) { + if (stkd < 16) { + r = Register(r + 1); + fr = Register(fr + 1); + } + stkd += 4; + } + + if (stkd < 16) { + NanoAssert(fr == FA0 || fr == FA1 || fr == A2); + if (fr == FA0 || fr == FA1) + findSpecificRegFor(arg, fr); + else { + findSpecificRegFor(arg, FA1); + // Move it to the integer pair + Register fpupair = arg->getReg(); + Register intpair = fr; + MFC1(mswregpair(intpair), Register(fpupair + 1)); // Odd fpu register contains sign,expt,manthi + MFC1(lswregpair(intpair), fpupair); // Even fpu register contains mantlo + } + r = Register(r + 2); + fr = Register(fr + 2); + } + else + asm_stkarg(arg, stkd); + + stkd += 8; + } + + /* Required functions */ + +#define FRAMESIZE 8 +#define RA_OFFSET 4 +#define FP_OFFSET 0 + + void Assembler::asm_store32(LOpcode op, LIns *value, int dr, LIns *base) + { + Register rt, rbase; + getBaseReg2(GpRegs, value, rt, GpRegs, base, rbase, dr); + + switch (op) { + case LIR_sti: + asm_ldst(OP_SW, rt, dr, rbase); + break; + case LIR_sti2s: + asm_ldst(OP_SH, rt, dr, rbase); + break; + case LIR_sti2c: + asm_ldst(OP_SB, rt, dr, rbase); + break; + default: + BADOPCODE(op); + } + + TAG("asm_store32(value=%p{%s}, dr=%d, base=%p{%s})", + value, lirNames[value->opcode()], dr, base, lirNames[base->opcode()]); + } + + void Assembler::asm_ui2d(LIns *ins) + { + Register fr = deprecated_prepResultReg(ins, FpRegs); + Register v = findRegFor(ins->oprnd1(), GpRegs); + Register ft = registerAllocTmp(FpRegs & ~(rmask(fr))); // allocate temporary register for constant + + // todo: support int value in memory, as per x86 + NanoAssert(deprecated_isKnownReg(v)); + + // mtc1 $v,$ft + // bgez $v,1f + // cvt.d.w $fr,$ft + // lui $at,0x41f0 # (double)0x10000000LL = 0x41f0000000000000 + // mtc1 $0,$ft + // mtc1 $at,$ft+1 + // add.d $fr,$fr,$ft + // 1: + + underrunProtect(6*4); // keep branch and destination together + NIns *here = _nIns; + ADD_D(fr,fr,ft); + MTC1(AT,ft+1); + MTC1(ZERO,ft); + LUI(AT,0x41f0); + CVT_D_W(fr,ft); // branch delay slot + BGEZ(v,here); + MTC1(v,ft); + + TAG("asm_ui2d(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_d2i(LIns* ins) + { + NanoAssert(cpu_has_fpu); + + Register rr = deprecated_prepResultReg(ins, GpRegs); + Register sr = findRegFor(ins->oprnd1(), FpRegs); + // trunc.w.d $sr,$sr + // mfc1 $rr,$sr + MFC1(rr,sr); + TRUNC_W_D(sr,sr); + TAG("asm_d2i(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_fop(LIns *ins) + { + NanoAssert(cpu_has_fpu); + if (cpu_has_fpu) { + LIns* lhs = ins->oprnd1(); + LIns* rhs = ins->oprnd2(); + LOpcode op = ins->opcode(); + + // rr = ra OP rb + + Register rr = deprecated_prepResultReg(ins, FpRegs); + Register ra = findRegFor(lhs, FpRegs); + Register rb = (rhs == lhs) ? ra : findRegFor(rhs, FpRegs & ~rmask(ra)); + + switch (op) { + case LIR_addd: ADD_D(rr, ra, rb); break; + case LIR_subd: SUB_D(rr, ra, rb); break; + case LIR_muld: MUL_D(rr, ra, rb); break; + case LIR_divd: DIV_D(rr, ra, rb); break; + default: + BADOPCODE(op); + } + } + TAG("asm_fop(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_fneg(LIns *ins) + { + NanoAssert(cpu_has_fpu); + if (cpu_has_fpu) { + LIns* lhs = ins->oprnd1(); + Register rr = deprecated_prepResultReg(ins, FpRegs); + Register sr = ( !lhs->isInReg() + ? findRegFor(lhs, FpRegs) + : lhs->deprecated_getReg() ); + NEG_D(rr, sr); + } + TAG("asm_fneg(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_immd(LIns *ins) + { + int d = deprecated_disp(ins); + Register rr = ins->deprecated_getReg(); + + deprecated_freeRsrcOf(ins); + + if (cpu_has_fpu && deprecated_isKnownReg(rr)) { + if (d) + asm_spill(rr, d, true); + asm_li_d(rr, ins->immDhi(), ins->immDlo()); + } + else { + NanoAssert(d); + asm_store_imm64(ins, d, FP); + } + TAG("asm_immd(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + +#ifdef NANOJIT_64BIT + void + Assembler::asm_q2i(LIns *) + { + NanoAssert(0); // q2i shouldn't occur on 32-bit platforms + } + + void Assembler::asm_ui2uq(LIns *ins) + { + USE(ins); + TODO(asm_ui2uq); + TAG("asm_ui2uq(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } +#endif + + void Assembler::asm_load64(LIns *ins) + { + NanoAssert(ins->isD()); + + LIns* base = ins->oprnd1(); + int dr = ins->disp(); + + Register rd = ins->deprecated_getReg(); + int ds = deprecated_disp(ins); + + Register rbase = findRegFor(base, GpRegs); + NanoAssert(IsGpReg(rbase)); + deprecated_freeRsrcOf(ins); + + if (cpu_has_fpu && deprecated_isKnownReg(rd)) { + NanoAssert(IsFpReg(rd)); + asm_ldst64 (false, rd, dr, rbase); + } + else { + // Either FPU is not available or the result needs to go into memory; + // in either case, FPU instructions are not required. Note that the + // result will never be loaded into registers if FPU is not available. + NanoAssert(!deprecated_isKnownReg(rd)); + NanoAssert(ds != 0); + + NanoAssert(isS16(dr) && isS16(dr+4)); + NanoAssert(isS16(ds) && isS16(ds+4)); + + // Check that the offset is 8-byte (64-bit) aligned. + NanoAssert((ds & 0x7) == 0); + + // FIXME: allocate a temporary to use for the copy + // to avoid load to use delay + // lw $at,dr($rbase) + // sw $at,ds($fp) + // lw $at,dr+4($rbase) + // sw $at,ds+4($fp) + + SW(AT, ds+4, FP); + LW(AT, dr+4, rbase); + SW(AT, ds, FP); + LW(AT, dr, rbase); + } + + TAG("asm_load64(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_cond(LIns *ins) + { + Register r = deprecated_prepResultReg(ins, GpRegs); + LOpcode op = ins->opcode(); + LIns *a = ins->oprnd1(); + LIns *b = ins->oprnd2(); + + asm_cmp(op, a, b, r); + + TAG("asm_cond(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + +#if NJ_SOFTFLOAT_SUPPORTED + void Assembler::asm_qhi(LIns *ins) + { + Register rr = deprecated_prepResultReg(ins, GpRegs); + LIns *q = ins->oprnd1(); + int d = findMemFor(q); + LW(rr, d+mswoff(), FP); + TAG("asm_qhi(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_qlo(LIns *ins) + { + Register rr = deprecated_prepResultReg(ins, GpRegs); + LIns *q = ins->oprnd1(); + int d = findMemFor(q); + LW(rr, d+lswoff(), FP); + TAG("asm_qlo(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_qjoin(LIns *ins) + { + int d = findMemFor(ins); + NanoAssert(d && isS16(d)); + LIns* lo = ins->oprnd1(); + LIns* hi = ins->oprnd2(); + + Register r = findRegFor(hi, GpRegs); + SW(r, d+mswoff(), FP); + r = findRegFor(lo, GpRegs); // okay if r gets recycled. + SW(r, d+lswoff(), FP); + deprecated_freeRsrcOf(ins); // if we had a reg in use, flush it to mem + + TAG("asm_qjoin(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + +#endif + + void Assembler::asm_neg_not(LIns *ins) + { + LOpcode op = ins->opcode(); + Register rr = deprecated_prepResultReg(ins, GpRegs); + + LIns* lhs = ins->oprnd1(); + // If this is the last use of lhs in reg, we can re-use result reg. + // Else, lhs already has a register assigned. + Register ra = !lhs->isInReg() ? findSpecificRegFor(lhs, rr) : lhs->deprecated_getReg(); + if (op == LIR_noti) + NOT(rr, ra); + else + NEGU(rr, ra); + TAG("asm_neg_not(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_immi(LIns *ins) + { + Register rr = deprecated_prepResultReg(ins, GpRegs); + asm_li(rr, ins->immI()); + TAG("asm_immi(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_cmov(LIns *ins) + { + LIns* condval = ins->oprnd1(); + LIns* iftrue = ins->oprnd2(); + LIns* iffalse = ins->oprnd3(); + + NanoAssert(condval->isCmp()); + NanoAssert(ins->opcode() == LIR_cmovi && iftrue->isI() && iffalse->isI()); + + const Register rr = deprecated_prepResultReg(ins, GpRegs); + + const Register iftruereg = findRegFor(iftrue, GpRegs & ~rmask(rr)); + MOVN(rr, iftruereg, AT); + /*const Register iffalsereg =*/ findSpecificRegFor(iffalse, rr); + asm_cmp(condval->opcode(), condval->oprnd1(), condval->oprnd2(), AT); + TAG("asm_cmov(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_condd(LIns *ins) + { + NanoAssert(cpu_has_fpu); + if (cpu_has_fpu) { + Register r = deprecated_prepResultReg(ins, GpRegs); + LOpcode op = ins->opcode(); + LIns *a = ins->oprnd1(); + LIns *b = ins->oprnd2(); + + if (cpu_has_cmov) { + // c.xx.d $a,$b + // li $r,1 + // movf $r,$0,$fcc0 + MOVF(r, ZERO, 0); + ORI(r, ZERO, 1); + } + else { + // c.xx.d $a,$b + // [nop] + // bc1t 1f + // li $r,1 + // move $r,$0 + // 1: + NIns *here = _nIns; + verbose_only(verbose_outputf("%p:", here);) + underrunProtect(3*4); + MOVE(r, ZERO); + ORI(r, ZERO, 1); // branch delay slot + BC1T(here); + if (cpu_has_fpuhazard) + NOP(); + } + asm_cmp(op, a, b, r); + } + TAG("asm_condd(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_i2d(LIns *ins) + { + NanoAssert(cpu_has_fpu); + if (cpu_has_fpu) { + Register fr = deprecated_prepResultReg(ins, FpRegs); + Register v = findRegFor(ins->oprnd1(), GpRegs); + + // mtc1 $v,$fr + // cvt.d.w $fr,$fr + CVT_D_W(fr,fr); + MTC1(v,fr); + } + TAG("asm_i2d(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_ret(LIns *ins) + { + genEpilogue(); + + releaseRegisters(); + assignSavedRegs(); + + LIns *value = ins->oprnd1(); + if (ins->isop(LIR_reti)) { + findSpecificRegFor(value, V0); + } + else { + NanoAssert(ins->isop(LIR_retd)); +#if NJ_SOFTFLOAT_SUPPORTED + NanoAssert(value->isop(LIR_ii2d)); + findSpecificRegFor(value->oprnd1(), V0); // lo + findSpecificRegFor(value->oprnd2(), V1); // hi +#else + findSpecificRegFor(value, FV0); +#endif + } + TAG("asm_ret(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_load32(LIns *ins) + { + LOpcode op = ins->opcode(); + LIns* base = ins->oprnd1(); + int d = ins->disp(); + + Register rres = deprecated_prepResultReg(ins, GpRegs); + Register rbase = getBaseReg(base, d, GpRegs); + + switch (op) { + case LIR_lduc2ui: // 8-bit integer load, zero-extend to 32-bit + asm_ldst(OP_LBU, rres, d, rbase); + break; + case LIR_ldus2ui: // 16-bit integer load, zero-extend to 32-bit + asm_ldst(OP_LHU, rres, d, rbase); + break; + case LIR_ldc2i: // 8-bit integer load, sign-extend to 32-bit + asm_ldst(OP_LB, rres, d, rbase); + break; + case LIR_lds2i: // 16-bit integer load, sign-extend to 32-bit + asm_ldst(OP_LH, rres, d, rbase); + break; + case LIR_ldi: // 32-bit integer load + asm_ldst(OP_LW, rres, d, rbase); + break; + default: + BADOPCODE(op); + } + + TAG("asm_load32(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_param(LIns *ins) + { + uint32_t a = ins->paramArg(); + uint32_t kind = ins->paramKind(); + + if (kind == 0) { + // ordinary param + // first 4 args A0..A3 + if (a < 4) { + // incoming arg in register + deprecated_prepResultReg(ins, rmask(argRegs[a])); + } else { + // incoming arg is on stack + Register r = deprecated_prepResultReg(ins, GpRegs); + TODO(Check stack offset); + int d = FRAMESIZE + a * sizeof(intptr_t); + LW(r, d, FP); + } + } + else { + // saved param + deprecated_prepResultReg(ins, rmask(savedRegs[a])); + } + TAG("asm_param(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_arith(LIns *ins) + { + LOpcode op = ins->opcode(); + LIns* lhs = ins->oprnd1(); + LIns* rhs = ins->oprnd2(); + + RegisterMask allow = GpRegs; + + // We always need the result register and the first operand register. + Register rr = deprecated_prepResultReg(ins, allow); + + // If this is the last use of lhs in reg, we can re-use the result reg. + // Else, lhs already has a register assigned. + Register ra = !lhs->isInReg() ? findSpecificRegFor(lhs, rr) : lhs->deprecated_getReg(); + Register rb, t; + + // Don't re-use the registers we've already allocated. + NanoAssert(deprecated_isKnownReg(rr)); + NanoAssert(deprecated_isKnownReg(ra)); + allow &= ~rmask(rr); + allow &= ~rmask(ra); + + if (rhs->isImmI()) { + int32_t rhsc = rhs->immI(); + if (isS16(rhsc)) { + // MIPS arith immediate ops sign-extend the imm16 value + switch (op) { + case LIR_addxovi: + case LIR_addjovi: + // add with overflow result into $at + // overflow is indicated by ((sign(rr)^sign(ra)) & (sign(rr)^sign(rhsc)) + + // [move $t,$ra] if (rr==ra) + // addiu $rr,$ra,rhsc + // [xor $at,$rr,$ra] if (rr!=ra) + // [xor $at,$rr,$t] if (rr==ra) + // [not $t,$rr] if (rhsc < 0) + // [and $at,$at,$t] if (rhsc < 0) + // [and $at,$at,$rr] if (rhsc >= 0) + // srl $at,$at,31 + + t = registerAllocTmp(allow); + SRL(AT, AT, 31); + if (rhsc < 0) { + AND(AT, AT, t); + NOT(t, rr); + } + else + AND(AT, AT, rr); + if (rr == ra) + XOR(AT, rr, t); + else + XOR(AT, rr, ra); + ADDIU(rr, ra, rhsc); + if (rr == ra) + MOVE(t, ra); + goto done; + case LIR_addi: + ADDIU(rr, ra, rhsc); + goto done; + case LIR_subxovi: + case LIR_subjovi: + // subtract with overflow result into $at + // overflow is indicated by (sign(ra)^sign(rhsc)) & (sign(rr)^sign(ra)) + + // [move $t,$ra] if (rr==ra) + // addiu $rr,$ra,-rhsc + // [xor $at,$rr,$ra] if (rr!=ra) + // [xor $at,$rr,$t] if (rr==ra) + // [and $at,$at,$ra] if (rhsc >= 0 && rr!=ra) + // [and $at,$at,$t] if (rhsc >= 0 && rr==ra) + // [not $t,$ra] if (rhsc < 0 && rr!=ra) + // [not $t,$t] if (rhsc < 0 && rr==ra) + // [and $at,$at,$t] if (rhsc < 0) + // srl $at,$at,31 + if (isS16(-rhsc)) { + t = registerAllocTmp(allow); + SRL(AT,AT,31); + if (rhsc < 0) { + AND(AT, AT, t); + if (rr == ra) + NOT(t, t); + else + NOT(t, ra); + } + else { + if (rr == ra) + AND(AT, AT, t); + else + AND(AT, AT, ra); + } + if (rr == ra) + XOR(AT, rr, t); + else + XOR(AT, rr, ra); + ADDIU(rr, ra, -rhsc); + if (rr == ra) + MOVE(t, ra); + goto done; + } + break; + case LIR_subi: + if (isS16(-rhsc)) { + ADDIU(rr, ra, -rhsc); + goto done; + } + break; + case LIR_mulxovi: + case LIR_muljovi: + case LIR_muli: + // FIXME: optimise constant multiply by 2^n + // if ((rhsc & (rhsc-1)) == 0) + // SLL(rr, ra, ffs(rhsc)-1); + //goto done; + break; + default: + break; + } + } + if (isU16(rhsc)) { + // MIPS logical immediate zero-extend the imm16 value + switch (op) { + case LIR_ori: + ORI(rr, ra, rhsc); + goto done; + case LIR_andi: + ANDI(rr, ra, rhsc); + goto done; + case LIR_xori: + XORI(rr, ra, rhsc); + goto done; + default: + break; + } + } + + // LIR shift ops only use last 5bits of shift const + switch (op) { + case LIR_lshi: + SLL(rr, ra, rhsc&31); + goto done; + case LIR_rshui: + SRL(rr, ra, rhsc&31); + goto done; + case LIR_rshi: + SRA(rr, ra, rhsc&31); + goto done; + default: + break; + } + } + + // general case, put rhs in register + rb = (rhs == lhs) ? ra : findRegFor(rhs, allow); + NanoAssert(deprecated_isKnownReg(rb)); + allow &= ~rmask(rb); + + // The register allocator will have set up one of these 4 cases + // rr==ra && ra==rb r0 = r0 op r0 + // rr==ra && ra!=rb r0 = r0 op r1 + // rr!=ra && ra==rb r0 = r1 op r1 + // rr!=ra && ra!=rb && rr!=rb r0 = r1 op r2 + NanoAssert(ra == rb || rr != rb); + + switch (op) { + case LIR_addxovi: + case LIR_addjovi: + // add with overflow result into $at + // overflow is indicated by (sign(rr)^sign(ra)) & (sign(rr)^sign(rb)) + + // [move $t,$ra] if (rr==ra) + // addu $rr,$ra,$rb + // ; Generate sign($rr)^sign($ra) + // [xor $at,$rr,$t] sign($at)=sign($rr)^sign($t) if (rr==ra) + // [xor $at,$rr,$ra] sign($at)=sign($rr)^sign($ra) if (rr!=ra) + // ; Generate sign($rr)^sign($rb) if $ra!=$rb + // [xor $t,$rr,$rb] if (ra!=rb) + // [and $at,$t] if (ra!=rb) + // srl $at,31 + + t = ZERO; + if (rr == ra || ra != rb) + t = registerAllocTmp(allow); + SRL(AT, AT, 31); + if (ra != rb) { + AND(AT, AT, t); + XOR(t, rr, rb); + } + if (rr == ra) + XOR(AT, rr, t); + else + XOR(AT, rr, ra); + ADDU(rr, ra, rb); + if (rr == ra) + MOVE(t, ra); + break; + case LIR_addi: + ADDU(rr, ra, rb); + break; + case LIR_andi: + AND(rr, ra, rb); + break; + case LIR_ori: + OR(rr, ra, rb); + break; + case LIR_xori: + XOR(rr, ra, rb); + break; + case LIR_subxovi: + case LIR_subjovi: + // subtract with overflow result into $at + // overflow is indicated by (sign(ra)^sign(rb)) & (sign(rr)^sign(ra)) + + // [move $t,$ra] if (rr==ra) + // ; Generate sign($at)=sign($ra)^sign($rb) + // xor $at,$ra,$rb + // subu $rr,$ra,$rb + // ; Generate sign($t)=sign($rr)^sign($ra) + // [xor $t,$rr,$ra] if (rr!=ra) + // [xor $t,$rr,$t] if (rr==ra) + // and $at,$at,$t + // srl $at,$at,31 + + if (ra == rb) { + // special case for (ra == rb) which can't overflow + MOVE(AT, ZERO); + SUBU(rr, ra, rb); + } + else { + t = registerAllocTmp(allow); + SRL(AT, AT, 31); + AND(AT, AT, t); + if (rr == ra) + XOR(t, rr, t); + else + XOR(t, rr, ra); + SUBU(rr, ra, rb); + XOR(AT, ra, rb); + if (rr == ra) + MOVE(t, ra); + } + break; + case LIR_subi: + SUBU(rr, ra, rb); + break; + case LIR_lshi: + // SLLV uses the low-order 5 bits of rb for the shift amount so no masking required + SLLV(rr, ra, rb); + break; + case LIR_rshi: + // SRAV uses the low-order 5 bits of rb for the shift amount so no masking required + SRAV(rr, ra, rb); + break; + case LIR_rshui: + // SRLV uses the low-order 5 bits of rb for the shift amount so no masking required + SRLV(rr, ra, rb); + break; + case LIR_mulxovi: + case LIR_muljovi: + t = registerAllocTmp(allow); + // Overflow indication required + // Do a 32x32 signed multiply generating a 64 bit result + // Compare bit31 of the result with the high order bits + // mult $ra,$rb + // mflo $rr # result to $rr + // sra $t,$rr,31 # $t = 0x00000000 or 0xffffffff + // mfhi $at + // xor $at,$at,$t # sets $at to nonzero if overflow + XOR(AT, AT, t); + MFHI(AT); + SRA(t, rr, 31); + MFLO(rr); + MULT(ra, rb); + break; + case LIR_muli: + MUL(rr, ra, rb); + break; + default: + BADOPCODE(op); + } + done: + TAG("asm_arith(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + void Assembler::asm_store64(LOpcode op, LIns *value, int dr, LIns *base) + { + // NanoAssert((dr & 7) == 0); +#if NANOJIT_64BIT + NanoAssert (op == LIR_stq || op == LIR_std2f || op == LIR_std); +#else + NanoAssert (op == LIR_std2f || op == LIR_std); +#endif + + switch (op) { + case LIR_std: + if (cpu_has_fpu) { + Register rbase = findRegFor(base, GpRegs); + + if (value->isImmD()) + asm_store_imm64(value, dr, rbase); + else { + Register fr = findRegFor(value, FpRegs); + asm_ldst64(true, fr, dr, rbase); + } + } + else { + Register rbase = findRegFor(base, GpRegs); + // *(uint64_t*)(rb+dr) = *(uint64_t*)(FP+da) + + int ds = findMemFor(value); + + // lw $at,ds(FP) + // sw $at,dr($rbase) + // lw $at,ds+4(FP) + // sw $at,dr+4($rbase) + SW(AT, dr+4, rbase); + LW(AT, ds+4, FP); + SW(AT, dr, rbase); + LW(AT, ds, FP); + } + + break; + case LIR_std2f: + NanoAssertMsg(0, "NJ_EXPANDED_LOADSTORE_SUPPORTED not yet supported for this architecture"); + return; + default: + BADOPCODE(op); + return; + } + + TAG("asm_store64(value=%p{%s}, dr=%d, base=%p{%s})", + value, lirNames[value->opcode()], dr, base, lirNames[base->opcode()]); + } + + bool Assembler::canRemat(LIns* ins) + { + return ins->isImmI() || ins->isop(LIR_allocp); + } + + void Assembler::asm_restore(LIns *i, Register r) + { + int d; + if (i->isop(LIR_allocp)) { + d = deprecated_disp(i); + if (isS16(d)) + ADDIU(r, FP, d); + else { + ADDU(r, FP, AT); + asm_li(AT, d); + } + } + else if (i->isImmI()) { + asm_li(r, i->immI()); + } + else { + d = findMemFor(i); + if (IsFpReg(r)) { + asm_ldst64(false, r, d, FP); + } + else { + asm_ldst(OP_LW, r, d, FP); + } + } + TAG("asm_restore(i=%p{%s}, r=%d)", i, lirNames[i->opcode()], r); + } + + void Assembler::asm_cmp(LOpcode condop, LIns *a, LIns *b, Register cr) + { + RegisterMask allow = isCmpDOpcode(condop) ? FpRegs : GpRegs; + Register ra = findRegFor(a, allow); + Register rb = (b==a) ? ra : findRegFor(b, allow & ~rmask(ra)); + + // FIXME: Use slti if b is small constant + + /* Generate the condition code */ + switch (condop) { + case LIR_eqi: + SLTIU(cr,cr,1); + XOR(cr,ra,rb); + break; + case LIR_lti: + SLT(cr,ra,rb); + break; + case LIR_gti: + SLT(cr,rb,ra); + break; + case LIR_lei: + XORI(cr,cr,1); + SLT(cr,rb,ra); + break; + case LIR_gei: + XORI(cr,cr,1); + SLT(cr,ra,rb); + break; + case LIR_ltui: + SLTU(cr,ra,rb); + break; + case LIR_gtui: + SLTU(cr,rb,ra); + break; + case LIR_leui: + XORI(cr,cr,1); + SLTU(cr,rb,ra); + break; + case LIR_geui: + XORI(cr,cr,1); + SLTU(cr,ra,rb); + break; + case LIR_eqd: + C_EQ_D(ra,rb); + break; + case LIR_ltd: + C_LT_D(ra,rb); + break; + case LIR_gtd: + C_LT_D(rb,ra); + break; + case LIR_led: + C_LE_D(ra,rb); + break; + case LIR_ged: + C_LE_D(rb,ra); + break; + default: + debug_only(outputf("%s",lirNames[condop]);) + TODO(asm_cond); + } + } + +#define SEG(addr) (uint32_t(addr) & 0xf0000000) +#define SEGOFFS(addr) (uint32_t(addr) & 0x0fffffff) + + + // Check that the branch target is in range + // Generate a trampoline if it isn't + // Emits the branch delay slot instruction + NIns* Assembler::asm_branchtarget(NIns * const targ) + { + bool inrange; + NIns *btarg = targ; + + // do initial underrun check here to ensure that inrange test is correct + // allow + if (targ) + underrunProtect(2 * 4); // branch + delay slot + + // MIPS offsets are based on the address of the branch delay slot + // which is the next instruction that will be generated + ptrdiff_t bd = BOFFSET(targ-1); + +#if PEDANTIC + inrange = false; +#else + inrange = (targ && isS16(bd)); +#endif + + // If the branch target is known and in range we can just generate a branch + // Otherwise generate a branch to a trampoline that will be stored in the + // literal area + if (inrange) + NOP(); + else { + NIns *tramp = _nSlot; + if (targ) { + // Can the target be reached by a jump instruction? + if (SEG(targ) == SEG(tramp)) { + // [linkedinstructions] + // bxxx trampoline + // nop + // ... + // trampoline: + // j targ + // nop + + underrunProtect(4 * 4); // keep bxx and trampoline together + + NOP(); // delay slot + + // NB trampoline code is emitted in the correct order + trampJ(targ); + trampNOP(); // trampoline delay slot + + } + else { + // [linkedinstructions] + // bxxx trampoline + // lui $at,%hi(targ) + // ... + // trampoline: + // addiu $at,%lo(targ) + // jr $at + // nop + + underrunProtect(5 * 4); // keep bxx and trampoline together + + LUI(AT,hi(uint32_t(targ))); // delay slot + + // NB trampoline code is emitted in the correct order + trampADDIU(AT, AT, lo(uint32_t(targ))); + trampJR(AT); + trampNOP(); // trampoline delay slot + + } + } + else { + // Worst case is bxxx,lui addiu;jr;nop as above + // Best case is branch to trampoline can be replaced + // with branch to target in which case the trampoline will be abandoned + // Fixup handled in nPatchBranch + + underrunProtect(5 * 4); // keep bxx and trampoline together + + NOP(); // delay slot + + trampNOP(); + trampNOP(); + trampNOP(); + + } + btarg = tramp; + } + + return btarg; + } + + + NIns* Assembler::asm_bxx(bool branchOnFalse, LOpcode condop, Register ra, Register rb, NIns * const targ) + { + NIns *patch = NULL; + NIns *btarg = asm_branchtarget(targ); + + if (cpu_has_fpu && isCmpDOpcode(condop)) { + // c.xx.d $ra,$rb + // bc1x btarg + switch (condop) { + case LIR_eqd: + if (branchOnFalse) + BC1F(btarg); + else + BC1T(btarg); + patch = _nIns; + if (cpu_has_fpuhazard) + NOP(); + C_EQ_D(ra, rb); + break; + case LIR_ltd: + if (branchOnFalse) + BC1F(btarg); + else + BC1T(btarg); + patch = _nIns; + if (cpu_has_fpuhazard) + NOP(); + C_LT_D(ra, rb); + break; + case LIR_gtd: + if (branchOnFalse) + BC1F(btarg); + else + BC1T(btarg); + patch = _nIns; + if (cpu_has_fpuhazard) + NOP(); + C_LT_D(rb, ra); + break; + case LIR_led: + if (branchOnFalse) + BC1F(btarg); + else + BC1T(btarg); + patch = _nIns; + if (cpu_has_fpuhazard) + NOP(); + C_LE_D(ra, rb); + break; + case LIR_ged: + if (branchOnFalse) + BC1F(btarg); + else + BC1T(btarg); + patch = _nIns; + if (cpu_has_fpuhazard) + NOP(); + C_LE_D(rb, ra); + break; + default: + BADOPCODE(condop); + break; + } + } + else { + // general case + // s[lg]tu? $at,($ra,$rb|$rb,$ra) + // b(ne|eq)z $at,btarg + switch (condop) { + case LIR_eqi: + // special case + // b(ne|eq) $ra,$rb,btarg + if (branchOnFalse) + BNE(ra, rb, btarg); + else { + if (ra == rb) + B(btarg); + else + BEQ(ra, rb, btarg); + } + patch = _nIns; + break; + case LIR_lti: + if (branchOnFalse) + BEQ(AT, ZERO, btarg); + else + BNE(AT, ZERO, btarg); + patch = _nIns; + SLT(AT, ra, rb); + break; + case LIR_gti: + if (branchOnFalse) + BEQ(AT, ZERO, btarg); + else + BNE(AT, ZERO, btarg); + patch = _nIns; + SLT(AT, rb, ra); + break; + case LIR_lei: + if (branchOnFalse) + BNE(AT, ZERO, btarg); + else + BEQ(AT, ZERO, btarg); + patch = _nIns; + SLT(AT, rb, ra); + break; + case LIR_gei: + if (branchOnFalse) + BNE(AT, ZERO, btarg); + else + BEQ(AT, ZERO, btarg); + patch = _nIns; + SLT(AT, ra, rb); + break; + case LIR_ltui: + if (branchOnFalse) + BEQ(AT, ZERO, btarg); + else + BNE(AT, ZERO, btarg); + patch = _nIns; + SLTU(AT, ra, rb); + break; + case LIR_gtui: + if (branchOnFalse) + BEQ(AT, ZERO, btarg); + else + BNE(AT, ZERO, btarg); + patch = _nIns; + SLTU(AT, rb, ra); + break; + case LIR_leui: + if (branchOnFalse) + BNE(AT, ZERO, btarg); + else + BEQ(AT, ZERO, btarg); + patch = _nIns; + SLT(AT, rb, ra); + break; + case LIR_geui: + if (branchOnFalse) + BNE(AT, ZERO, btarg); + else + BEQ(AT, ZERO, btarg); + patch = _nIns; + SLTU(AT, ra, rb); + break; + default: + BADOPCODE(condop); + } + } + TAG("asm_bxx(branchOnFalse=%d, condop=%s, ra=%s rb=%s targ=%p)", + branchOnFalse, lirNames[condop], gpn(ra), gpn(rb), targ); + return patch; + } + + NIns* Assembler::asm_branch_ov(LOpcode op, NIns* target) + { + USE(op); + NanoAssert(target != NULL); + + NIns* patch = asm_bxx(true, LIR_eqi, AT, ZERO, target); + + TAG("asm_branch_ov(op=%s, target=%p)", lirNames[op], target); + return patch; + } + + NIns* Assembler::asm_branch(bool branchOnFalse, LIns *cond, NIns * const targ) + { + NanoAssert(cond->isCmp()); + LOpcode condop = cond->opcode(); + RegisterMask allow = isCmpDOpcode(condop) ? FpRegs : GpRegs; + LIns *a = cond->oprnd1(); + LIns *b = cond->oprnd2(); + Register ra = findRegFor(a, allow); + Register rb = (b==a) ? ra : findRegFor(b, allow & ~rmask(ra)); + + return asm_bxx(branchOnFalse, condop, ra, rb, targ); + } + + void Assembler::asm_j(NIns * const targ, bool bdelay) + { + if (targ == NULL) { + NanoAssert(bdelay); + (void) asm_bxx(false, LIR_eqi, ZERO, ZERO, targ); + } + else { + NanoAssert(SEG(targ) == SEG(_nIns)); + if (bdelay) { + underrunProtect(2*4); // j + delay + NOP(); + } + J(targ); + } + TAG("asm_j(targ=%p) bdelay=%d", targ); + } + + void + Assembler::asm_spill(Register rr, int d, bool quad) + { + USE(quad); + NanoAssert(d); + if (IsFpReg(rr)) { + NanoAssert(quad); + asm_ldst64(true, rr, d, FP); + } + else { + NanoAssert(!quad); + asm_ldst(OP_SW, rr, d, FP); + } + TAG("asm_spill(rr=%d, d=%d, quad=%d)", rr, d, quad); + } + + void + Assembler::asm_nongp_copy(Register dst, Register src) + { + NanoAssert ((rmask(dst) & FpRegs) && (rmask(src) & FpRegs)); + MOV_D(dst, src); + TAG("asm_nongp_copy(dst=%d src=%d)", dst, src); + } + + /* + * asm_arg will encode the specified argument according to the current ABI, and + * will update r and stkd as appropriate so that the next argument can be + * encoded. + * + * - doubles are 64-bit aligned. both in registers and on the stack. + * If the next available argument register is A1, it is skipped + * and the double is placed in A2:A3. If A0:A1 or A2:A3 are not + * available, the double is placed on the stack, 64-bit aligned. + * - 32-bit arguments are placed in registers and 32-bit aligned + * on the stack. + */ + void + Assembler::asm_arg(ArgType ty, LIns* arg, Register& r, Register& fr, int& stkd) + { + // The stack offset must always be at least aligned to 4 bytes. + NanoAssert((stkd & 3) == 0); + + if (ty == ARGTYPE_D) { + // This task is fairly complex and so is delegated to asm_arg_64. + asm_arg_64(arg, r, fr, stkd); + } else { + NanoAssert(ty == ARGTYPE_I || ty == ARGTYPE_UI); + if (stkd < 16) { + asm_regarg(ty, arg, r); + fr = Register(fr + 1); + r = Register(r + 1); + } + else + asm_stkarg(arg, stkd); + // The o32 ABI calling convention is that if the first arguments + // is not a double, subsequent double values are passed in integer registers + fr = r; + stkd += 4; + } + } + + void + Assembler::asm_call(LIns* ins) + { + if (!ins->isop(LIR_callv)) { + Register rr; + LOpcode op = ins->opcode(); + + switch (op) { + case LIR_calli: + rr = retRegs[0]; + break; + case LIR_calld: + NanoAssert(cpu_has_fpu); + rr = FV0; + break; + default: + BADOPCODE(op); + return; + } + + deprecated_prepResultReg(ins, rmask(rr)); + } + + // Do this after we've handled the call result, so we don't + // force the call result to be spilled unnecessarily. + evictScratchRegsExcept(0); + + const CallInfo* ci = ins->callInfo(); + ArgType argTypes[MAXARGS]; + uint32_t argc = ci->getArgTypes(argTypes); + bool indirect = ci->isIndirect(); + + // FIXME: Put one of the argument moves into the BDS slot + + underrunProtect(2*4); // jalr+delay + NOP(); + JALR(T9); + + if (!indirect) + // FIXME: If we can tell that we are calling non-PIC + // (ie JIT) code, we could call direct instead of using t9 + asm_li(T9, ci->_address); + else + // Indirect call: we assign the address arg to t9 + // which matches the o32 ABI for calling functions + asm_regarg(ARGTYPE_P, ins->arg(--argc), T9); + + // Encode the arguments, starting at A0 and with an empty argument stack. + Register r = A0, fr = FA0; + int stkd = 0; + + // Iterate through the argument list and encode each argument according to + // the ABI. + // Note that we loop through the arguments backwards as LIR specifies them + // in reverse order. + while(argc--) + asm_arg(argTypes[argc], ins->arg(argc), r, fr, stkd); + + if (stkd > max_out_args) + max_out_args = stkd; + TAG("asm_call(ins=%p{%s})", ins, lirNames[ins->opcode()]); + } + + Register + Assembler::nRegisterAllocFromSet(RegisterMask set) + { + Register i; + int n; + + // note, deliberate truncation of 64->32 bits + if (set & 0xffffffff) { + // gp reg + n = ffs(int(set)); + NanoAssert(n != 0); + i = Register(n - 1); + } + else { + // fp reg + NanoAssert(cpu_has_fpu); + n = ffs(int(set >> 32)); + NanoAssert(n != 0); + i = Register(32 + n - 1); + } + _allocator.free &= ~rmask(i); + TAG("nRegisterAllocFromSet(set=%016llx) => %s", set, gpn(i)); + return i; + } + + void + Assembler::nRegisterResetAll(RegAlloc& regs) + { + regs.clear(); + regs.free = GpRegs; + if (cpu_has_fpu) + regs.free |= FpRegs; + } + +#define signextend16(s) ((int32_t(s)<<16)>>16) + + void + Assembler::nPatchBranch(NIns* branch, NIns* target) + { + uint32_t op = (branch[0] >> 26) & 0x3f; + uint32_t bdoffset = target-(branch+1); + + if (op == OP_BEQ || op == OP_BNE || + ((branch[0] & 0xfffe0000) == ((OP_COP1 << 26) | (COP1_BC << 21)))) { + if (isS16(bdoffset)) { + // The branch is in range, so just replace the offset in the instruction + // The trampoline that was allocated is redundant and will remain unused + branch[0] = (branch[0] & 0xffff0000) | (bdoffset & 0xffff); + } + else { + // The branch is pointing to a trampoline. Find out where that is + NIns *tramp = branch + 1 + (signextend16(branch[0] & 0xffff)); + if (SEG(branch) == SEG(target)) { + *tramp = J_FORMAT(OP_J,JINDEX(target)); + } + else { + // Full 32-bit jump + // bxx tramp + // lui $at,(target>>16)>0xffff + // .. + // tramp: + // ori $at,target & 0xffff + // jr $at + // nop + branch[1] = U_FORMAT(OP_LUI,0,AT,hi(uint32_t(target))); + tramp[0] = U_FORMAT(OP_ADDIU,AT,AT,lo(uint32_t(target))); + tramp[1] = R_FORMAT(OP_SPECIAL,AT,0,0,0,SPECIAL_JR); + } + } + } + else if (op == OP_J) { + NanoAssert (SEG(branch) == SEG(target)); + branch[0] = J_FORMAT(OP_J,JINDEX(target)); + } + else + TODO(unknown_patch); + // TAG("nPatchBranch(branch=%p target=%p)", branch, target); + } + + void + Assembler::nFragExit(LIns *guard) + { + SideExit *exit = guard->record()->exit; + Fragment *frag = exit->target; + bool destKnown = (frag && frag->fragEntry); + + // Generate jump to epilogue and initialize lr. + + // If the guard already exists, use a simple jump. + if (destKnown) { + // j _fragEntry + // move $v0,$zero + underrunProtect(2 * 4); // j + branch delay + MOVE(V0, ZERO); + asm_j(frag->fragEntry, false); + } + else { + // Target doesn't exist. Jump to an epilogue for now. + // This can be patched later. + if (!_epilogue) + _epilogue = genEpilogue(); + GuardRecord *lr = guard->record(); + // FIXME: _epilogue may be in another segment + // lui $v0,%hi(lr) + // j _epilogue + // addiu $v0,%lo(lr) + underrunProtect(2 * 4); // j + branch delay + ADDIU(V0, V0, lo(int32_t(lr))); + asm_j(_epilogue, false); + LUI(V0, hi(int32_t(lr))); + lr->jmp = _nIns; + } + + // profiling for the exit + verbose_only( + if (_logc->lcbits & LC_FragProfile) { + // lui $fp,%hi(profCount) + // lw $at,%lo(profCount)(fp) + // addiu $at,1 + // sw $at,%lo(profCount)(fp) + uint32_t profCount = uint32_t(&guard->record()->profCount); + SW(AT, lo(profCount), FP); + ADDIU(AT, AT, 1); + LW(AT, lo(profCount), FP); + LUI(FP, hi(profCount)); + } + ) + + // Pop the stack frame. + MOVE(SP, FP); + + // return value is GuardRecord* + TAG("nFragExit(guard=%p{%s})", guard, lirNames[guard->opcode()]); + } + + void + Assembler::nInit(AvmCore*) + { + nHints[LIR_calli] = rmask(V0); +#if NJ_SOFTFLOAT_SUPPORTED + nHints[LIR_hcalli] = rmask(V1); +#endif + nHints[LIR_calld] = rmask(FV0); + nHints[LIR_paramp] = PREFER_SPECIAL; + } + + void Assembler::nBeginAssembly() + { + max_out_args = 16; // Always reserve space for a0-a3 + } + + // Increment the 32-bit profiling counter at pCtr, without + // changing any registers. + verbose_only( + void Assembler::asm_inc_m32(uint32_t* /*pCtr*/) + { + // TODO: implement this + } + ) + + void + Assembler::nativePageReset(void) + { + _nSlot = 0; + _nExitSlot = 0; + TAG("nativePageReset()"); + } + + void + Assembler::nativePageSetup(void) + { + NanoAssert(!_inExit); + if (!_nIns) + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes)); + if (!_nExitIns) + codeAlloc(exitStart, exitEnd, _nExitIns verbose_only(, exitBytes)); + + // constpool starts at bottom of page and moves up + // code starts at top of page and goes down, + + if (!_nSlot) + _nSlot = codeStart; + if (!_nExitSlot) + _nExitSlot = exitStart; + + TAG("nativePageSetup()"); + } + + + NIns* + Assembler::genPrologue(void) + { + /* + * Use a non standard fp because we don't know the final framesize until now + * addiu $sp,-FRAMESIZE + * sw $ra,RA_OFFSET($sp) + * sw $fp,FP_OFFSET($sp) + * move $fp,$sp + * addu $sp,-stackNeeded + */ + + uint32_t stackNeeded = max_out_args + STACK_GRANULARITY * _activation.stackSlotsNeeded(); + uint32_t amt = alignUp(stackNeeded, NJ_ALIGN_STACK); + + if (amt) { + if (isS16(-amt)) + ADDIU(SP, SP, -amt); + else { + ADDU(SP, SP, AT); + asm_li(AT, -amt); + } + } + + NIns *patchEntry = _nIns; // FIXME: who uses this value and where should it point? + + MOVE(FP, SP); + SW(FP, FP_OFFSET, SP); + SW(RA, RA_OFFSET, SP); // No need to save for leaf functions + ADDIU(SP, SP, -FRAMESIZE); + + TAG("genPrologue()"); + + return patchEntry; + } + + NIns* + Assembler::genEpilogue(void) + { + /* + * move $sp,$fp + * lw $ra,RA_OFFSET($sp) + * lw $fp,FP_OFFSET($sp) + * j $ra + * addiu $sp,FRAMESIZE + */ + ADDIU(SP, SP, FRAMESIZE); + JR(RA); + LW(FP, FP_OFFSET, SP); + LW(RA, RA_OFFSET, SP); + MOVE(SP, FP); + + TAG("genEpilogue()"); + + return _nIns; + } + + RegisterMask + Assembler::nHint(LIns* ins) + { + NanoAssert(ins->isop(LIR_paramp)); + RegisterMask prefer = 0; + // FIXME: FLOAT parameters? + if (ins->paramKind() == 0) + if (ins->paramArg() < 4) + prefer = rmask(argRegs[ins->paramArg()]); + return prefer; + } + + void + Assembler::underrunProtect(int bytes) + { + NanoAssertMsg(bytes<=LARGEST_UNDERRUN_PROT, "constant LARGEST_UNDERRUN_PROT is too small"); + NanoAssert(_nSlot != 0); + uintptr_t top = uintptr_t(_nSlot); + uintptr_t pc = uintptr_t(_nIns); + if (pc - bytes < top) { + verbose_only(verbose_outputf(" %p:", _nIns);) + NIns* target = _nIns; + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes)); + + _nSlot = codeStart; + + // _nSlot points to the first empty position in the new code block + // _nIns points just past the last empty position. + asm_j(target, true); + } + } + + void + Assembler::swapCodeChunks() { + if (!_nExitIns) + codeAlloc(exitStart, exitEnd, _nExitIns verbose_only(, exitBytes)); + if (!_nExitSlot) + _nExitSlot = exitStart; + SWAP(NIns*, _nIns, _nExitIns); + SWAP(NIns*, _nSlot, _nExitSlot); + SWAP(NIns*, codeStart, exitStart); + SWAP(NIns*, codeEnd, exitEnd); + verbose_only( SWAP(size_t, codeBytes, exitBytes); ) + } + + void + Assembler::asm_insert_random_nop() { + NanoAssert(0); // not supported + } + +} + +#endif // FEATURE_NANOJIT && NANOJIT_MIPS diff --git a/js/src/nanojit/NativeMIPS.h b/js/src/nanojit/NativeMIPS.h new file mode 100644 index 0000000..df158b8 --- /dev/null +++ b/js/src/nanojit/NativeMIPS.h @@ -0,0 +1,715 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * MIPS Technologies Inc + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Dearman + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __nanojit_NativeMIPS__ +#define __nanojit_NativeMIPS__ + +#include "../vprof/vprof.h" +#ifdef PERFM +#define DOPROF +#endif +#define count_instr() _nvprof("mips", 1) +#define count_mov() do { _nvprof("mips-mov", 1); count_instr(); } while (0) +#define count_jmp() do { _nvprof("mips-jmp", 1); count_instr(); } while (0) +#define count_prolog() do { _nvprof("mips-prolog", 1); count_instr(); } while (0) +#define count_alu() do { _nvprof("mips-alu", 1); count_instr(); } while (0) +#define count_misc() do { _nvprof("mips-misc", 1); count_instr(); } while (0) +#define count_fpu() do { _nvprof("mips-fpu", 1); count_instr(); } while (0) +#define count_br() do { _nvprof("mips-br", 1); count_instr(); } while (0) + +namespace nanojit +{ + // Req: NJ_MAX_STACK_ENTRY is number of instructions to hold in LIR stack +#if 0 + // FIXME: Inconsistent use in signed/unsigned expressions makes this generate errors + static const uint32_t NJ_MAX_STACK_ENTRY = 4096; +#else +#define NJ_MAX_STACK_ENTRY 4096 +#endif + static const int NJ_ALIGN_STACK = 8; + + typedef uint32_t NIns; // REQ: Instruction count + typedef uint64_t RegisterMask; // REQ: Large enough to hold LastRegNum-FirstRegNum bits +#define _rmask_(r) (1LL<<(r)) + + typedef uint32_t Register; // REQ: Register identifiers + // Register numbers for Native code generator + static const Register + ZERO = { 0 }, + AT = { 1 }, + V0 = { 2 }, + V1 = { 3 }, + A0 = { 4 }, + A1 = { 5 }, + A2 = { 6 }, + A3 = { 7 }, + + T0 = { 8 }, + T1 = { 9 }, + T2 = { 10 }, + T3 = { 11 }, + T4 = { 12 }, + T5 = { 13 }, + T6 = { 14 }, + T7 = { 15 }, + + S0 = { 16 }, + S1 = { 17 }, + S2 = { 18 }, + S3 = { 19 }, + S4 = { 20 }, + S5 = { 21 }, + S6 = { 22 }, + S7 = { 23 }, + + T8 = { 24 }, + T9 = { 25 }, + K0 = { 26 }, + K1 = { 27 }, + GP = { 28 }, + SP = { 29 }, + FP = { 30 }, + RA = { 31 }, + + F0 = { 32 }, + F1 = { 33 }, + F2 = { 34 }, + F3 = { 35 }, + F4 = { 36 }, + F5 = { 37 }, + F6 = { 38 }, + F7 = { 39 }, + + F8 = { 40 }, + F9 = { 41 }, + F10 = { 42 }, + F11 = { 43 }, + F12 = { 44 }, + F13 = { 45 }, + F14 = { 46 }, + F15 = { 47 }, + + F16 = { 48 }, + F17 = { 49 }, + F18 = { 50 }, + F19 = { 51 }, + F20 = { 52 }, + F21 = { 53 }, + F22 = { 54 }, + F23 = { 55 }, + + F24 = { 56 }, + F25 = { 57 }, + F26 = { 58 }, + F27 = { 59 }, + F28 = { 60 }, + F29 = { 61 }, + F30 = { 62 }, + F31 = { 63 }, + + // FP register aliases + FV0 = F0, + FV1 = F2, + FA0 = F12, + FA1 = F14, + FT0 = F4, + FT1 = F6, + FT2 = F8, + FT3 = F10, + FT4 = F16, + FT5 = F18, + FS0 = F20, + FS1 = F22, + FS2 = F24, + FS3 = F26, + FS4 = F28, + FS5 = F30, + + deprecated_UnknownReg = { 127 }; // XXX: remove eventually, see bug 538924 + + static const uint32_t FirstRegNum = ZERO; + static const uint32_t LastRegNum = F31; +} + +#define NJ_USE_UINT32_REGISTER 1 +#include "NativeCommon.h" + +namespace nanojit { + // REQ: register names + verbose_only(extern const char* regNames[];) + + // REQ: Bytes of icache to flush after Assembler::patch + const size_t LARGEST_BRANCH_PATCH = 2 * sizeof(NIns); + + // REQ: largest value passed to underrunProtect + static const int LARGEST_UNDERRUN_PROT = 32; + + // REQ: Number of callee saved registers +#ifdef FPCALLEESAVED + static const int NumSavedRegs = 14; +#else + static const int NumSavedRegs = 8; +#endif + + // REQ: Callee saved registers + const RegisterMask SavedRegs = +#ifdef FPCALLEESAVED + _rmask_(FS0) | _rmask_(FS1) | _rmask_(FS2) | + _rmask_(FS3) | _rmask_(FS4) | _rmask_(FS5) | +#endif + _rmask_(S0) | _rmask_(S1) | _rmask_(S2) | _rmask_(S3) | + _rmask_(S4) | _rmask_(S5) | _rmask_(S6) | _rmask_(S7); + + // REQ: General purpose registers + static const RegisterMask GpRegs = + _rmask_(V0) | _rmask_(V1) | + _rmask_(A0) | _rmask_(A1) | _rmask_(A2) | _rmask_(A3) | + _rmask_(S0) | _rmask_(S1) | _rmask_(S2) | _rmask_(S3) | + _rmask_(S4) | _rmask_(S5) | _rmask_(S6) | _rmask_(S7) | + _rmask_(T0) | _rmask_(T1) | _rmask_(T2) | _rmask_(T3) | + _rmask_(T4) | _rmask_(T5) | _rmask_(T6) | _rmask_(T7) | + _rmask_(T8) | _rmask_(T9); + + // REQ: Floating point registers + static const RegisterMask FpRegs = +#ifdef FPCALLEESAVED + _rmask_(FS0) | _rmask_(FS1) | _rmask_(FS2) | + _rmask_(FS3) | _rmask_(FS4) | _rmask_(FS5) | +#endif + _rmask_(FV0) | _rmask_(FV1) | + _rmask_(FA0) | _rmask_(FA1) | + _rmask_(FT0) | _rmask_(FT1) | _rmask_(FT2) | + _rmask_(FT3) | _rmask_(FT4) | _rmask_(FT5); + + static const RegisterMask AllowableFlagRegs = GpRegs; // REQ: Registers that can hold flag results FIXME + + static inline bool IsFpReg(Register r) + { + return (_rmask_(r) & FpRegs) != 0; + } + + static inline bool IsGpReg(Register r) + { + return (_rmask_(r) & GpRegs) != 0; + } + +#define GPR(r) ((r)&31) +#define FPR(r) ((r)&31) + +// REQ: Platform specific declarations to include in Stats structure +#define DECLARE_PLATFORM_STATS() + +// REQ: Platform specific declarations to include in Assembler class +#define DECLARE_PLATFORM_ASSEMBLER() \ + const static Register argRegs[4]; \ + const static Register retRegs[2]; \ + void nativePageSetup(void); \ + void nativePageReset(void); \ + void underrunProtect(int bytes); \ + bool hardenNopInsertion(const Config& /*c*/) { return false; } \ + NIns *_nSlot; \ + NIns *_nExitSlot; \ + int max_out_args; \ + Register ovreg; \ + \ + void asm_ldst(int op, Register r, int offset, Register b); \ + void asm_ldst64(bool store, Register fr, int offset, Register b); \ + void asm_store_imm64(LIns *value, int dr, Register rbase); \ + void asm_li32(Register r, int32_t imm); \ + void asm_li_d(Register fr, int32_t msw, int32_t lsw); \ + void asm_li(Register r, int32_t imm); \ + void asm_j(NIns*, bool bdelay); \ + void asm_cmp(LOpcode condop, LIns *a, LIns *b, Register cr); \ + void asm_move(Register d, Register s); \ + void asm_regarg(ArgType ty, LIns* p, Register r); \ + void asm_stkarg(LIns* arg, int stkd); \ + void asm_arg(ArgType ty, LIns* arg, Register& r, Register& fr, int& stkd); \ + void asm_arg_64(LIns* arg, Register& r, Register& fr, int& stkd); \ + NIns *asm_branchtarget(NIns*); \ + NIns *asm_bxx(bool, LOpcode, Register, Register, NIns*); + +// REQ: Platform specific declarations to include in RegAlloc class +#define DECLARE_PLATFORM_REGALLOC() + +// REQ: +#define swapptrs() do { \ + NIns* _tins = _nIns; _nIns = _nExitIns; _nExitIns = _tins; \ + NIns* _nslot = _nSlot; _nSlot = _nExitSlot; _nExitSlot = _nslot; \ + } while (0) + +#define TODO(x) do { verbose_only(avmplus::AvmLog(#x);) NanoAssertMsgf(false, "%s", #x); } while (0) +#ifdef MIPSDEBUG +#define TAG(fmt, ...) do { debug_only(verbose_outputf(" # MIPS: " fmt, ##__VA_ARGS__);) } while (0) +#else +#define TAG(fmt, ...) do { } while (0) +#endif + +#define EMIT(ins, fmt, ...) do { \ + underrunProtect(4); \ + *(--_nIns) = (NIns) (ins); \ + debug_only(codegenBreak(_nIns);) \ + asm_output(fmt, ##__VA_ARGS__); \ + } while (0) + +// Emit code in trampoline/literal area +// Assume that underrunProtect has already been called +// This is a bit hacky... +#define TRAMP(ins, fmt, ...) do { \ + verbose_only( \ + NIns *save_nIns = _nIns; _nIns = _nSlot; \ + ) \ + *_nSlot = (NIns)ins; \ + debug_only(codegenBreak(_nSlot);) \ + _nSlot++; \ + verbose_only(setOutputForEOL("<= trampoline");) \ + asm_output(fmt, ##__VA_ARGS__); \ + verbose_only( \ + _nIns = save_nIns; \ + ) \ + } while (0) + +#define MR(d, s) asm_move(d, s) + +// underrun guarantees that there is always room to insert a jump and branch delay slot +#define JMP(t) asm_j(t, true) + +// Opcodes: bits 31..26 +#define OP_SPECIAL 0x00 +#define OP_REGIMM 0x01 +#define OP_J 0x02 +#define OP_JAL 0x03 +#define OP_BEQ 0x04 +#define OP_BNE 0x05 +#define OP_ADDIU 0x09 +#define OP_SLTIU 0x0b +#define OP_ANDI 0x0c +#define OP_ORI 0x0d +#define OP_XORI 0x0e +#define OP_LUI 0x0f +#define OP_COP1 0x11 +#define OP_COP1X 0x13 +#define OP_SPECIAL2 0x1c +#define OP_LB 0x20 +#define OP_LH 0x21 +#define OP_LW 0x23 +#define OP_LBU 0x24 +#define OP_LHU 0x25 +#define OP_SB 0x28 +#define OP_SH 0x29 +#define OP_SW 0x2b +#define OP_LWC1 0x31 +#define OP_LDC1 0x35 +#define OP_SWC1 0x39 +#define OP_SDC1 0x3d + +// REGIMM: bits 20..16 +#define REGIMM_BLTZ 0x00 +#define REGIMM_BGEZ 0x01 + +// COP1: bits 25..21 +#define COP1_ADD 0x00 +#define COP1_SUB 0x01 +#define COP1_MUL 0x02 +#define COP1_DIV 0x03 +#define COP1_MOV 0x06 +#define COP1_NEG 0x07 +#define COP1_BC 0x08 +#define COP1_TRUNCW 0x0d +#define COP1_CVTD 0x21 + +// COP1X: bits 5..0 +#define COP1X_LDXC1 0x01 +#define COP1X_SDXC1 0x09 + +// SPECIAL: bits 5..0 +#define SPECIAL_SLL 0x00 +#define SPECIAL_MOVCI 0x01 +#define SPECIAL_SRL 0x02 +#define SPECIAL_SRA 0x03 +#define SPECIAL_SLLV 0x04 +#define SPECIAL_SRLV 0x06 +#define SPECIAL_SRAV 0x07 +#define SPECIAL_JR 0x08 +#define SPECIAL_JALR 0x09 +#define SPECIAL_MOVN 0x0b +#define SPECIAL_MFHI 0x10 +#define SPECIAL_MFLO 0x12 +#define SPECIAL_MULT 0x18 +#define SPECIAL_ADDU 0x21 +#define SPECIAL_SUBU 0x23 +#define SPECIAL_AND 0x24 +#define SPECIAL_OR 0x25 +#define SPECIAL_XOR 0x26 +#define SPECIAL_NOR 0x27 +#define SPECIAL_SLT 0x2a +#define SPECIAL_SLTU 0x2b + +// SPECIAL2: bits 5..0 +#define SPECIAL2_MUL 0x02 + +// FORMAT: bits 25..21 +#define FMT_S 0x10 +#define FMT_D 0x11 +#define FMT_W 0x14 +#define FMT_L 0x15 +#define FMT_PS 0x16 + +// CONDITION: bits 4..0 +#define COND_F 0x0 +#define COND_UN 0x1 +#define COND_EQ 0x2 +#define COND_UEQ 0x3 +#define COND_OLT 0x4 +#define COND_ULT 0x5 +#define COND_OLE 0x6 +#define COND_ULE 0x7 +#define COND_SF 0x8 +#define COND_NGLE 0x9 +#define COND_SEQ 0xa +#define COND_NGL 0xb +#define COND_LT 0xc +#define COND_NGE 0xd +#define COND_LE 0xe +#define COND_NGT 0xf + +// Helper definitions to encode different classes of MIPS instructions +// Parameters are in instruction order + +#define R_FORMAT(op, rs, rt, rd, re, func) \ + (((op)<<26)|(GPR(rs)<<21)|(GPR(rt)<<16)|(GPR(rd)<<11)|((re)<<6)|(func)) + +#define I_FORMAT(op, rs, rt, simm) \ + (((op)<<26)|(GPR(rs)<<21)|(GPR(rt)<<16)|((simm)&0xffff)) + +#define J_FORMAT(op, index) \ + (((op)<<26)|(index)) + +#define U_FORMAT(op, rs, rt, uimm) \ + (((op)<<26)|(GPR(rs)<<21)|(GPR(rt)<<16)|((uimm)&0xffff)) + +#define F_FORMAT(op, ffmt, ft, fs, fd, func) \ + (((op)<<26)|((ffmt)<<21)|(FPR(ft)<<16)|(FPR(fs)<<11)|(FPR(fd)<<6)|(func)) + +#define oname(op) Assembler::oname[op] +#define cname(cond) Assembler::cname[cond] +#define fname(ffmt) Assembler::fname[ffmt] +#define fpn(fr) gpn(fr) + +#define BOFFSET(targ) (uint32_t(targ - (_nIns+1))) + +#define LDST(op, rt, offset, base) \ + do { count_misc(); EMIT(I_FORMAT(op, base, rt, offset), \ + "%s %s, %d(%s)", oname[op], gpn(rt), offset, gpn(base)); } while (0) + +#define BX(op, rs, rt, targ) \ + do { count_br(); EMIT(I_FORMAT(op, rs, rt, BOFFSET(targ)), \ + "%s %s, %s, %p", oname[op], gpn(rt), gpn(rs), targ); } while (0) + +// MIPS instructions +// Parameters are in "assembler" order +#define ADDIU(rt, rs, simm) \ + do { count_alu(); EMIT(I_FORMAT(OP_ADDIU, rs, rt, simm), \ + "addiu %s, %s, %d", gpn(rt), gpn(rs), simm); } while (0) + +#define trampADDIU(rt, rs, simm) \ + do { count_alu(); TRAMP(I_FORMAT(OP_ADDIU, rs, rt, simm), \ + "addiu %s, %s, %d", gpn(rt), gpn(rs), simm); } while (0) + +#define ADDU(rd, rs, rt) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, rs, rt, rd, 0, SPECIAL_ADDU), \ + "addu %s, %s, %s", gpn(rd), gpn(rs), gpn(rt)); } while (0) + +#define AND(rd, rs, rt) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, rs, rt, rd, 0, SPECIAL_AND), \ + "and %s, %s, %s", gpn(rd), gpn(rs), gpn(rt)); } while (0) + +#define ANDI(rt, rs, uimm) \ + do { count_alu(); EMIT(U_FORMAT(OP_ANDI, rs, rt, uimm), \ + "andi %s, %s, 0x%x", gpn(rt), gpn(rs), ((uimm)&0xffff)); } while (0) + +#define BC1F(targ) \ + do { count_br(); EMIT(I_FORMAT(OP_COP1, COP1_BC, 0, BOFFSET(targ)), \ + "bc1f %p", targ); } while (0) + +#define BC1T(targ) \ + do { count_br(); EMIT(I_FORMAT(OP_COP1, COP1_BC, 1, BOFFSET(targ)), \ + "bc1t %p", targ); } while (0) + +#define B(targ) BX(OP_BEQ, ZERO, ZERO, targ) +#define BEQ(rs, rt, targ) BX(OP_BEQ, rs, rt, targ) +#define BNE(rs, rt, targ) BX(OP_BNE, rs, rt, targ) +#define BLEZ(rs, targ) BX(OP_BLEZ, rs, ZERO, targ) +#define BGTZ(rs, targ) BX(OP_BGTZ, rs, ZERO, targ) +#define BGEZ(rs, targ) BX(OP_REGIMM, rs, REGIMM_BGEZ, targ) +#define BLTZ(rs, targ) BX(OP_REGIMM, rs, REGIMM_BLTZ, targ) + +#define JINDEX(dest) ((uint32_t(dest)>>2)&0x03ffffff) + +#define J(dest) \ + do { count_jmp(); EMIT(J_FORMAT(OP_J, JINDEX(dest)), \ + "j %p", dest); } while (0) + +#define trampJ(dest) \ + do { count_jmp(); TRAMP(J_FORMAT(OP_J, JINDEX(dest)), \ + "j %p", dest); } while (0) + +#define JAL(dest) \ + do { count_jmp(); EMIT(J_FORMAT(OP_JAL, JINDEX(dest)), \ + "jal %p", dest); } while (0) + +#define JALR(rs) \ + do { count_jmp(); EMIT(R_FORMAT(OP_SPECIAL, rs, 0, RA, 0, SPECIAL_JALR), \ + "jalr %s", gpn(rs)); } while (0) + +#define JR(rs) \ + do { count_jmp(); EMIT(R_FORMAT(OP_SPECIAL, rs, 0, 0, 0, SPECIAL_JR), \ + "jr %s", gpn(rs)); } while (0) +#define trampJR(rs) \ + do { count_jmp(); TRAMP(R_FORMAT(OP_SPECIAL, rs, 0, 0, 0, SPECIAL_JR), \ + "jr %s", gpn(rs)); } while (0) + +#define LB(rt, offset, base) \ + LDST(OP_LB, rt, offset, base) + +#define LH(rt, offset, base) \ + LDST(OP_LH, rt, offset, base) + +#define LUI(rt, uimm) \ + do { count_alu(); EMIT(U_FORMAT(OP_LUI, 0, rt, uimm), \ + "lui %s, 0x%x", gpn(rt), ((uimm)&0xffff)); } while (0) + +#define LW(rt, offset, base) \ + LDST(OP_LW, rt, offset, base) + +#define MFHI(rd) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, 0, 0, rd, 0, SPECIAL_MFHI), \ + "mfhi %s", gpn(rd)); } while (0) + +#define MFLO(rd) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, 0, 0, rd, 0, SPECIAL_MFLO), \ + "mflo %s", gpn(rd)); } while (0) + +#define MUL(rd, rs, rt) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL2, rs, rt, rd, 0, SPECIAL2_MUL), \ + "mul %s, %s, %s", gpn(rd), gpn(rs), gpn(rt)); } while (0) + +#define MULT(rs, rt) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, rs, rt, 0, 0, SPECIAL_MULT), \ + "mult %s, %s", gpn(rs), gpn(rt)); } while (0) + +#define MOVE(rd, rs) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, rs, ZERO, rd, 0, SPECIAL_ADDU), \ + "move %s, %s", gpn(rd), gpn(rs)); } while (0) + +#define MOVN(rd, rs, rt) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, rs, rt, rd, 0, SPECIAL_MOVN), \ + "movn %s, %s, %s", gpn(rd), gpn(rs), gpn(rt)); } while (0) + +#define NEGU(rd, rt) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, ZERO, rt, rd, 0, SPECIAL_SUBU), \ + "negu %s, %s", gpn(rd), gpn(rt)); } while (0) + +#define NOP() \ + do { count_misc(); EMIT(R_FORMAT(OP_SPECIAL, 0, 0, 0, 0, SPECIAL_SLL), \ + "nop"); } while (0) + +#define trampNOP() \ + do { count_misc(); TRAMP(R_FORMAT(OP_SPECIAL, 0, 0, 0, 0, SPECIAL_SLL), \ + "nop"); } while (0) + +#define NOR(rd, rs, rt) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, rs, rt, rd, 0, SPECIAL_NOR), \ + "nor %s, %s, %s", gpn(rd), gpn(rs), gpn(rt)); } while (0) + +#define NOT(rd, rs) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, rs, ZERO, rd, 0, SPECIAL_NOR), \ + "not %s, %s", gpn(rd), gpn(rs)); } while (0) + +#define OR(rd, rs, rt) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, rs, rt, rd, 0, SPECIAL_OR), \ + "or %s, %s, %s", gpn(rd), gpn(rs), gpn(rt)); } while (0) + +#define ORI(rt, rs, uimm) \ + do { count_alu(); EMIT(U_FORMAT(OP_ORI, rs, rt, uimm), \ + "ori %s, %s, 0x%x", gpn(rt), gpn(rs), ((uimm)&0xffff)); } while (0) + +#define SLTIU(rt, rs, simm) \ + do { count_alu(); EMIT(I_FORMAT(OP_SLTIU, rs, rt, simm), \ + "sltiu %s, %s, %d", gpn(rt), gpn(rs), simm); } while (0) + +#define SLT(rd, rs, rt) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, rs, rt, rd, 0, SPECIAL_SLT), \ + "slt %s, %s, %s", gpn(rd), gpn(rs), gpn(rt)); } while (0) + +#define SLTU(rd, rs, rt) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, rs, rt, rd, 0, SPECIAL_SLTU), \ + "sltu %s, %s, %s", gpn(rd), gpn(rs), gpn(rt)); } while (0) + +#define SLL(rd, rt, sa) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, 0, rt, rd, sa, SPECIAL_SLL), \ + "sll %s, %s, %d", gpn(rd), gpn(rt), sa); } while (0) + +#define SLLV(rd, rt, rs) \ + do { count_misc(); EMIT(R_FORMAT(OP_SPECIAL, rs, rt, rd, 0, SPECIAL_SLLV), \ + "sllv %s, %s, %s", gpn(rd), gpn(rt), gpn(rs)); } while (0) + +#define SRA(rd, rt, sa) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, 0, rt, rd, sa, SPECIAL_SRA), \ + "sra %s, %s, %d", gpn(rd), gpn(rt), sa); } while (0) + +#define SRAV(rd, rt, rs) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, rs, rt, rd, 0, SPECIAL_SRAV), \ + "srav %s, %s, %s", gpn(rd), gpn(rt), gpn(rs)); } while (0) + +#define SRL(rd, rt, sa) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, 0, rt, rd, sa, SPECIAL_SRL), \ + "srl %s, %s, %d", gpn(rd), gpn(rt), sa); } while (0) + +#define SRLV(rd, rt, rs) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, rs, rt, rd, 0, SPECIAL_SRLV), \ + "srlv %s, %s, %s", gpn(rd), gpn(rt), gpn(rs)); } while (0) + +#define SUBU(rd, rs, rt) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, rs, rt, rd, 0, SPECIAL_SUBU), \ + "subu %s, %s, %s", gpn(rd), gpn(rs), gpn(rt)); } while (0) + +#define SW(rt, offset, base) \ + LDST(OP_SW, rt, offset, base) + +#define XOR(rd, rs, rt) \ + do { count_alu(); EMIT(R_FORMAT(OP_SPECIAL, rs, rt, rd, 0, SPECIAL_XOR), \ + "xor %s, %s, %s", gpn(rd), gpn(rs), gpn(rt)); } while (0) + +#define XORI(rt, rs, uimm) \ + do { count_alu(); EMIT(U_FORMAT(OP_XORI, rs, rt, uimm), \ + "xori %s, %s, 0x%x", gpn(rt), gpn(rs), ((uimm)&0xffff)); } while (0) + + +/* FPU instructions */ +#ifdef NJ_SOFTFLOAT_SUPPORTED + +#if !defined(__mips_soft_float) || __mips_soft_float != 1 +#error NJ_SOFTFLOAT_SUPPORTED defined but not compiled with -msoft-float +#endif + +#define LWC1(ft, offset, base) NanoAssertMsg(0, "softfloat LWC1") +#define SWC1(ft, offset, base) NanoAssertMsg(0, "softfloat SWC1") +#define LDC1(ft, offset, base) NanoAssertMsg(0, "softfloat LDC1") +#define SDC1(ft, offset, base) NanoAssertMsg(0, "softfloat SDC1") +#define LDXC1(fd, index, base) NanoAssertMsg(0, "softfloat LDXC1") +#define SDXC1(fs, index, base) NanoAssertMsg(0, "softfloat SDXC1") + +#define MFC1(rt, fs) NanoAssertMsg(0, "softfloat MFC1") +#define MTC1(rt, fs) NanoAssertMsg(0, "softfloat MTC1") +#define MOVF(rt, fs, cc) NanoAssertMsg(0, "softfloat MOVF") +#define CVT_D_W(fd, fs) NanoAssertMsg(0, "softfloat CVT_D_W") +#define C_EQ_D(fs, ft) NanoAssertMsg(0, "softfloat C_EQ_D") +#define C_LE_D(fs, ft) NanoAssertMsg(0, "softfloat C_LE_D") +#define C_LT_D(fs, ft) NanoAssertMsg(0, "softfloat C_LT_D") +#define ADD_D(fd, fs, ft) NanoAssertMsg(0, "softfloat ADD_D") +#define DIV_D(fd, fs, ft) NanoAssertMsg(0, "softfloat DIV_D") +#define MOV_D(fd, fs) NanoAssertMsg(0, "softfloat MOV_D") +#define MUL_D(fd, fs, ft) NanoAssertMsg(0, "softfloat MUL_D") +#define NEG_D(fd, fs) NanoAssertMsg(0, "softfloat NEG_D") +#define SUB_D(fd, fs, ft) NanoAssertMsg(0, "softfloat SUB_D") +#define TRUNC_W_D(fd,fs) NanoAssertMsg(0, "softfloat TRUNC_W_D") + +#else + +#if defined(__mips_soft_float) && __mips_soft_float != 0 +#error compiled with -msoft-float but NJ_SOFTFLOAT_SUPPORTED not defined +#endif + +#define FOP_FMT2(ffmt, fd, fs, func, name) \ + do { count_fpu(); EMIT(F_FORMAT(OP_COP1, ffmt, 0, fs, fd, func), \ + "%s.%s %s, %s", name, fname[ffmt], fpn(fd), fpn(fs)); } while (0) + +#define FOP_FMT3(ffmt, fd, fs, ft, func, name) \ + do { count_fpu(); EMIT(F_FORMAT(OP_COP1, ffmt, ft, fs, fd, func), \ + "%s.%s %s, %s, %s", name, fname[ffmt], fpn(fd), fpn(fs), fpn(ft)); } while (0) + +#define C_COND_FMT(cond, ffmt, fs, ft) \ + do { count_fpu(); EMIT(F_FORMAT(OP_COP1, ffmt, ft, fs, 0, 0x30|(cond)), \ + "c.%s.%s %s, %s", cname[cond], fname[ffmt], fpn(fs), fpn(ft)); } while (0) + +#define MFC1(rt, fs) \ + do { count_fpu(); EMIT(F_FORMAT(OP_COP1, 0, rt, fs, 0, 0), \ + "mfc1 %s, %s", gpn(rt), fpn(fs)); } while (0) + +#define MTC1(rt, fs) \ + do { count_fpu(); EMIT(F_FORMAT(OP_COP1, 4, rt, fs, 0, 0), \ + "mtc1 %s, %s", gpn(rt), fpn(fs)); } while (0) + +#define MOVF(rd, rs, cc) \ + do { count_fpu(); EMIT(R_FORMAT(OP_SPECIAL, rs, (cc)<<2, rd, 0, SPECIAL_MOVCI), \ + "movf %s, %s, $fcc%d", gpn(rd), gpn(rs), cc); } while (0) + +#define CVT_D_W(fd, fs) \ + do { count_fpu(); EMIT(F_FORMAT(OP_COP1, FMT_W, 0, fs, fd, COP1_CVTD), \ + "cvt.d.w %s, %s", fpn(fd), fpn(fs)); } while (0) + +#define TRUNC_W_D(fd, fs) \ + do { count_fpu(); EMIT(F_FORMAT(OP_COP1, FMT_D, 0, fs, fd, COP1_TRUNCW), \ + "trunc.w.d %s, %s", fpn(fd), fpn(fs)); } while (0) + + +#define LWC1(ft, offset, base) LDST(OP_LWC1, ft, offset, base) +#define SWC1(ft, offset, base) LDST(OP_SWC1, ft, offset, base) +#define LDC1(ft, offset, base) LDST(OP_LDC1, ft, offset, base) +#define SDC1(ft, offset, base) LDST(OP_SDC1, ft, offset, base) +#define LDXC1(fd, index, base) \ + do { count_fpu(); EMIT(R_FORMAT(OP_COP1X, base, index, 0, fd, COP1X_LDXC1), \ + "ldxc1 %s, %s(%s)", fpn(fd), gpn(index), gpn(base)); } while (0) +#define SDXC1(fs, index, base) \ + do { count_fpu(); EMIT(R_FORMAT(OP_COP1X, base, index, fs, 0, COP1X_SDXC1), \ + "sdxc1 %s, %s(%s)", fpn(fs), gpn(index), gpn(base)); } while (0) + +#define C_EQ_D(fs, ft) C_COND_FMT(COND_EQ, FMT_D, fs, ft) +#define C_LE_D(fs, ft) C_COND_FMT(COND_LE, FMT_D, fs, ft) +#define C_LT_D(fs, ft) C_COND_FMT(COND_LT, FMT_D, fs, ft) +#define ADD_D(fd, fs, ft) FOP_FMT3(FMT_D, fd, fs, ft, COP1_ADD, "add") +#define DIV_D(fd, fs, ft) FOP_FMT3(FMT_D, fd, fs, ft, COP1_DIV, "div") +#define MOV_D(fd, fs) FOP_FMT2(FMT_D, fd, fs, COP1_MOV, "mov") +#define MUL_D(fd, fs, ft) FOP_FMT3(FMT_D, fd, fs, ft, COP1_MUL, "mul") +#define NEG_D(fd, fs) FOP_FMT2(FMT_D, fd, fs, COP1_NEG, "neg") +#define SUB_D(fd, fs, ft) FOP_FMT3(FMT_D, fd, fs, ft, COP1_SUB, "sub") +#endif + +} +#endif // __nanojit_NativeMIPS__ diff --git a/js/src/nanojit/NativePPC.cpp b/js/src/nanojit/NativePPC.cpp new file mode 100644 index 0000000..b4f6341 --- /dev/null +++ b/js/src/nanojit/NativePPC.cpp @@ -0,0 +1,1459 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nanojit.h" + +#if defined FEATURE_NANOJIT && defined NANOJIT_PPC + +namespace nanojit +{ + const Register Assembler::retRegs[] = { R3, R4 }; // high=R3, low=R4 + const Register Assembler::argRegs[] = { R3, R4, R5, R6, R7, R8, R9, R10 }; + + const Register Assembler::savedRegs[] = { + #if !defined NANOJIT_64BIT + R13, + #endif + R14, R15, R16, R17, R18, R19, R20, R21, R22, + R23, R24, R25, R26, R27, R28, R29, R30 + }; + + const char *regNames[] = { + "r0", "sp", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" + }; + + const char *bitNames[] = { "lt", "gt", "eq", "so" }; + + #define TODO(x) do{ avmplus::AvmLog(#x); NanoAssertMsgf(false, "%s", #x); } while(0) + + /* + * see http://developer.apple.com/documentation/developertools/Conceptual/LowLevelABI/index.html + * stack layout (higher address going down) + * sp -> out linkage area + * out parameter area + * local variables + * saved registers + * sp' -> in linkage area + * in parameter area + * + * linkage area layout: + * PPC32 PPC64 + * sp+0 sp+0 saved sp + * sp+4 sp+8 saved cr + * sp+8 sp+16 saved lr + * sp+12 sp+24 reserved + */ + + const int min_param_area_size = 8*sizeof(void*); // r3-r10 + const int linkage_size = 6*sizeof(void*); + const int lr_offset = 2*sizeof(void*); // linkage.lr + const int cr_offset = 1*sizeof(void*); // linkage.cr + + NIns* Assembler::genPrologue() { + // mflr r0 + // stw r0, lr_offset(sp) + // stwu sp, -framesize(sp) + + // param_area must be at least large enough for r3-r10 to be saved, + // regardless of whether we think the callee needs less: e.g., the callee + // might tail-call to a function that uses varargs, which could flush + // r3-r10 to the parameter area. + uint32_t param_area = (max_param_size > min_param_area_size) ? max_param_size : min_param_area_size; + // activation frame is 4 bytes per entry even on 64bit machines + uint32_t stackNeeded = param_area + linkage_size + _activation.stackSlotsNeeded() * 4; + uint32_t aligned = alignUp(stackNeeded, NJ_ALIGN_STACK); + + UNLESS_PEDANTIC( if (isS16(aligned)) { + STPU(SP, -aligned, SP); // *(sp-aligned) = sp; sp -= aligned + } else ) { + STPUX(SP, SP, R0); + asm_li(R0, -aligned); + } + + NIns *patchEntry = _nIns; + MR(FP,SP); // save SP to use as a FP + STP(FP, cr_offset, SP); // cheat and save our FP in linkage.cr + STP(R0, lr_offset, SP); // save LR in linkage.lr + MFLR(R0); + + return patchEntry; + } + + NIns* Assembler::genEpilogue() { + BLR(); + MTLR(R0); + LP(R0, lr_offset, SP); + LP(FP, cr_offset, SP); // restore FP from linkage.cr + MR(SP,FP); + return _nIns; + } + + void Assembler::asm_load32(LIns *ins) { + LIns* base = ins->oprnd1(); + int d = ins->disp(); + Register rr = deprecated_prepResultReg(ins, GpRegs); + Register ra = getBaseReg(base, d, GpRegs); + + switch(ins->opcode()) { + case LIR_lduc2ui: + if (isS16(d)) { + LBZ(rr, d, ra); + } else { + LBZX(rr, ra, R0); // rr = [ra+R0] + asm_li(R0,d); + } + return; + case LIR_ldus2ui: + // these are expected to be 2 or 4-byte aligned + if (isS16(d)) { + LHZ(rr, d, ra); + } else { + LHZX(rr, ra, R0); // rr = [ra+R0] + asm_li(R0,d); + } + return; + case LIR_ldi: + // these are expected to be 4-byte aligned + if (isS16(d)) { + LWZ(rr, d, ra); + } else { + LWZX(rr, ra, R0); // rr = [ra+R0] + asm_li(R0,d); + } + return; + case LIR_ldc2i: + case LIR_lds2i: + NanoAssertMsg(0, "NJ_EXPANDED_LOADSTORE_SUPPORTED not yet supported for this architecture"); + return; + default: + NanoAssertMsg(0, "asm_load32 should never receive this LIR opcode"); + return; + } + } + + void Assembler::asm_store32(LOpcode op, LIns *value, int32_t dr, LIns *base) { + + switch (op) { + case LIR_sti: + case LIR_sti2c: + // handled by mainline code below for now + break; + case LIR_sti2s: + NanoAssertMsg(0, "NJ_EXPANDED_LOADSTORE_SUPPORTED not yet supported for this architecture"); + return; + default: + NanoAssertMsg(0, "asm_store32 should never receive this LIR opcode"); + return; + } + + Register rs = findRegFor(value, GpRegs); + Register ra = value == base ? rs : getBaseReg(base, dr, GpRegs & ~rmask(rs)); + + #if !PEDANTIC + if (isS16(dr)) { + switch (op) { + case LIR_sti: + STW(rs, dr, ra); + break; + case LIR_sti2c: + STB(rs, dr, ra); + break; + } + return; + } + #endif + + // general case store, any offset size + switch (op) { + case LIR_sti: + STWX(rs, ra, R0); + break; + case LIR_sti2c: + STBX(rs, ra, R0); + break; + } + asm_li(R0, dr); + } + + void Assembler::asm_load64(LIns *ins) { + + switch (ins->opcode()) { + case LIR_ldd: + CASE64(LIR_ldq:) + // handled by mainline code below for now + break; + case LIR_ldf2d: + NanoAssertMsg(0, "NJ_EXPANDED_LOADSTORE_SUPPORTED not yet supported for this architecture"); + return; + default: + NanoAssertMsg(0, "asm_load64 should never receive this LIR opcode"); + return; + } + + LIns* base = ins->oprnd1(); + #ifdef NANOJIT_64BIT + Register rr = ins->deprecated_getReg(); + if (deprecated_isKnownReg(rr) && (rmask(rr) & FpRegs)) { + // FPR already assigned, fine, use it + deprecated_freeRsrcOf(ins); + } else { + // use a GPR register; its okay to copy doubles with GPR's + // but *not* okay to copy non-doubles with FPR's + rr = deprecated_prepResultReg(ins, GpRegs); + } + #else + Register rr = deprecated_prepResultReg(ins, FpRegs); + #endif + + int dr = ins->disp(); + Register ra = getBaseReg(base, dr, GpRegs); + + #ifdef NANOJIT_64BIT + if (rmask(rr) & GpRegs) { + #if !PEDANTIC + if (isS16(dr)) { + LD(rr, dr, ra); + return; + } + #endif + // general case 64bit GPR load + LDX(rr, ra, R0); + asm_li(R0, dr); + return; + } + #endif + + // FPR + #if !PEDANTIC + if (isS16(dr)) { + LFD(rr, dr, ra); + return; + } + #endif + + // general case FPR load + LFDX(rr, ra, R0); + asm_li(R0, dr); + } + + void Assembler::asm_li(Register r, int32_t imm) { + #if !PEDANTIC + if (isS16(imm)) { + LI(r, imm); + return; + } + if ((imm & 0xffff) == 0) { + imm = uint32_t(imm) >> 16; + LIS(r, imm); + return; + } + #endif + asm_li32(r, imm); + } + + void Assembler::asm_li32(Register r, int32_t imm) { + // general case + // TODO use ADDI instead of ORI if r != r0, impl might have 3way adder + ORI(r, r, imm); + LIS(r, imm>>16); // on ppc64, this sign extends + } + + void Assembler::asm_li64(Register r, uint64_t imm) { + underrunProtect(5*sizeof(NIns)); // must be contiguous to be patchable + ORI(r,r,uint16_t(imm)); // r[0:15] = imm[0:15] + ORIS(r,r,uint16_t(imm>>16)); // r[16:31] = imm[16:31] + SLDI(r,r,32); // r[32:63] = r[0:31], r[0:31] = 0 + asm_li32(r, int32_t(imm>>32)); // r[0:31] = imm[32:63] + } + + void Assembler::asm_store64(LOpcode op, LIns *value, int32_t dr, LIns *base) { + NanoAssert(value->isQorD()); + + switch (op) { + case LIR_std: + CASE64(LIR_stq:) + // handled by mainline code below for now + break; + case LIR_std2f: + NanoAssertMsg(0, "NJ_EXPANDED_LOADSTORE_SUPPORTED not yet supported for this architecture"); + return; + default: + NanoAssertMsg(0, "asm_store64 should never receive this LIR opcode"); + return; + } + + Register ra = getBaseReg(base, dr, GpRegs); + + // general case for any value + #if !defined NANOJIT_64BIT + // on 32bit cpu's, we only use store64 for doubles + Register rs = findRegFor(value, FpRegs); + #else + // if we have to choose a register, use a GPR + Register rs = ( !value->isInReg() + ? findRegFor(value, GpRegs & ~rmask(ra)) + : value->deprecated_getReg() ); + + if (rmask(rs) & GpRegs) { + #if !PEDANTIC + if (isS16(dr)) { + // short offset + STD(rs, dr, ra); + return; + } + #endif + // general case store 64bit GPR + STDX(rs, ra, R0); + asm_li(R0, dr); + return; + } + #endif // NANOJIT_64BIT + + #if !PEDANTIC + if (isS16(dr)) { + // short offset + STFD(rs, dr, ra); + return; + } + #endif + + // general case for any offset + STFDX(rs, ra, R0); + asm_li(R0, dr); + } + + void Assembler::asm_cond(LIns *ins) { + LOpcode op = ins->opcode(); + LIns *a = ins->oprnd1(); + LIns *b = ins->oprnd2(); + ConditionRegister cr = CR7; + Register r = deprecated_prepResultReg(ins, GpRegs); + switch (op) { + case LIR_eqi: case LIR_eqd: + CASE64(LIR_eqq:) + EXTRWI(r, r, 1, 4*cr+COND_eq); // extract CR7.eq + MFCR(r); + break; + case LIR_lti: case LIR_ltui: + case LIR_ltd: case LIR_led: + CASE64(LIR_ltq:) CASE64(LIR_ltuq:) + EXTRWI(r, r, 1, 4*cr+COND_lt); // extract CR7.lt + MFCR(r); + break; + case LIR_gti: case LIR_gtui: + case LIR_gtd: case LIR_ged: + CASE64(LIR_gtq:) CASE64(LIR_gtuq:) + EXTRWI(r, r, 1, 4*cr+COND_gt); // extract CR7.gt + MFCR(r); + break; + case LIR_lei: case LIR_leui: + CASE64(LIR_leq:) CASE64(LIR_leuq:) + EXTRWI(r, r, 1, 4*cr+COND_eq); // extract CR7.eq + MFCR(r); + CROR(CR7, eq, lt, eq); + break; + case LIR_gei: case LIR_geui: + CASE64(LIR_geq:) CASE64(LIR_geuq:) + EXTRWI(r, r, 1, 4*cr+COND_eq); // select CR7.eq + MFCR(r); + CROR(CR7, eq, gt, eq); + break; + default: + debug_only(outputf("%s",lirNames[ins->opcode()]);) + TODO(asm_cond); + break; + } + asm_cmp(op, a, b, cr); + } + + void Assembler::asm_condd(LIns *ins) { + asm_cond(ins); + } + + // cause sign extension to test bits. ptrdiff_t is a signed, + // pointer-sized int + static inline bool isS14(ptrdiff_t d) { + const int shift = sizeof(ptrdiff_t) * 8 - 14; // 18 or 50 + return ((d << shift) >> shift) == d; + } + + NIns* Assembler::asm_branch(bool onfalse, LIns *cond, NIns * const targ) { + LOpcode condop = cond->opcode(); + NanoAssert(cond->isCmp()); + + // powerpc offsets are based on the address of the branch instruction + NIns *patch; + #if !PEDANTIC + ptrdiff_t bd = targ - (_nIns-1); + if (targ && isS24(bd)) + patch = asm_branch_near(onfalse, cond, targ); + else + #endif + patch = asm_branch_far(onfalse, cond, targ); + asm_cmp(condop, cond->oprnd1(), cond->oprnd2(), CR7); + return patch; + } + + NIns* Assembler::asm_branch_near(bool onfalse, LIns *cond, NIns * const targ) { + NanoAssert(targ != 0); + underrunProtect(4); + ptrdiff_t bd = targ - (_nIns-1); + NIns *patch = 0; + if (!isS14(bd)) { + underrunProtect(8); + bd = targ - (_nIns-1); + if (isS24(bd)) { + // can't fit conditional branch offset into 14 bits, but + // we can fit in 24, so invert the condition and branch + // around an unconditional jump + verbose_only(verbose_outputf("%p:", _nIns);) + NIns *skip = _nIns; + B(bd); + patch = _nIns; // this is the patchable branch to the given target + onfalse = !onfalse; + bd = skip - (_nIns-1); + NanoAssert(isS14(bd)); + verbose_only(verbose_outputf("branch24");) + } + else { + // known far target + return asm_branch_far(onfalse, cond, targ); + } + } + ConditionRegister cr = CR7; + switch (cond->opcode()) { + case LIR_eqi: + case LIR_eqd: + CASE64(LIR_eqq:) + if (onfalse) BNE(cr,bd); else BEQ(cr,bd); + break; + case LIR_lti: case LIR_ltui: + case LIR_ltd: case LIR_led: + CASE64(LIR_ltq:) CASE64(LIR_ltuq:) + if (onfalse) BNL(cr,bd); else BLT(cr,bd); + break; + case LIR_lei: case LIR_leui: + CASE64(LIR_leq:) CASE64(LIR_leuq:) + if (onfalse) BGT(cr,bd); else BLE(cr,bd); + break; + case LIR_gti: case LIR_gtui: + case LIR_gtd: case LIR_ged: + CASE64(LIR_gtq:) CASE64(LIR_gtuq:) + if (onfalse) BNG(cr,bd); else BGT(cr,bd); + break; + case LIR_gei: case LIR_geui: + CASE64(LIR_geq:) CASE64(LIR_geuq:) + if (onfalse) BLT(cr,bd); else BGE(cr,bd); + break; + default: + debug_only(outputf("%s",lirNames[cond->opcode()]);) + TODO(unknown_cond); + } + if (!patch) + patch = _nIns; + return patch; + } + + // general case branch to any address (using CTR) + NIns *Assembler::asm_branch_far(bool onfalse, LIns *cond, NIns * const targ) { + LOpcode condop = cond->opcode(); + ConditionRegister cr = CR7; + underrunProtect(16); + switch (condop) { + case LIR_eqi: + case LIR_eqd: + CASE64(LIR_eqq:) + if (onfalse) BNECTR(cr); else BEQCTR(cr); + break; + case LIR_lti: case LIR_ltui: + CASE64(LIR_ltq:) CASE64(LIR_ltuq:) + case LIR_ltd: case LIR_led: + if (onfalse) BNLCTR(cr); else BLTCTR(cr); + break; + case LIR_lei: case LIR_leui: + CASE64(LIR_leq:) CASE64(LIR_leuq:) + if (onfalse) BGTCTR(cr); else BLECTR(cr); + break; + case LIR_gti: case LIR_gtui: + CASE64(LIR_gtq:) CASE64(LIR_gtuq:) + case LIR_gtd: case LIR_ged: + if (onfalse) BNGCTR(cr); else BGTCTR(cr); + break; + case LIR_gei: case LIR_geui: + CASE64(LIR_geq:) CASE64(LIR_geuq:) + if (onfalse) BLTCTR(cr); else BGECTR(cr); + break; + default: + debug_only(outputf("%s",lirNames[condop]);) + TODO(unknown_cond); + } + + #if !defined NANOJIT_64BIT + MTCTR(R0); + asm_li32(R0, (int)targ); + #else + MTCTR(R0); + if (!targ || !isU32(uintptr_t(targ))) { + asm_li64(R0, uint64_t(targ)); + } else { + asm_li32(R0, uint32_t(uintptr_t(targ))); + } + #endif + return _nIns; + } + + NIns* Assembler::asm_branch_ov(LOpcode, NIns*) { + TODO(asm_branch_ov); + return _nIns; + } + + void Assembler::asm_cmp(LOpcode condop, LIns *a, LIns *b, ConditionRegister cr) { + RegisterMask allow = isCmpDOpcode(condop) ? FpRegs : GpRegs; + Register ra = findRegFor(a, allow); + + #if !PEDANTIC + if (b->isImmI()) { + int32_t d = b->immI(); + if (isS16(d)) { + if (isCmpSIOpcode(condop)) { + CMPWI(cr, ra, d); + return; + } + #if defined NANOJIT_64BIT + if (isCmpSQOpcode(condop)) { + CMPDI(cr, ra, d); + TODO(cmpdi); + return; + } + #endif + } + if (isU16(d)) { + if (isCmpUIOpcode(condop)) { + CMPLWI(cr, ra, d); + return; + } + #if defined NANOJIT_64BIT + if (isCmpUQOpcode(condop)) { + CMPLDI(cr, ra, d); + TODO(cmpldi); + return; + } + #endif + } + } + #endif + + // general case + Register rb = b==a ? ra : findRegFor(b, allow & ~rmask(ra)); + if (isCmpSIOpcode(condop)) { + CMPW(cr, ra, rb); + } + else if (isCmpUIOpcode(condop)) { + CMPLW(cr, ra, rb); + } + #if defined NANOJIT_64BIT + else if (isCmpSQOpcode(condop)) { + CMPD(cr, ra, rb); + } + else if (isCmpUQOpcode(condop)) { + CMPLD(cr, ra, rb); + } + #endif + else if (isCmpDOpcode(condop)) { + // set the lt/gt bit for fle/fge. We don't do this for + // int/uint because in those cases we can invert the branch condition. + // for float, we can't because of unordered comparisons + if (condop == LIR_led) + CROR(cr, lt, lt, eq); // lt = lt|eq + else if (condop == LIR_ged) + CROR(cr, gt, gt, eq); // gt = gt|eq + FCMPU(cr, ra, rb); + } + else { + TODO(asm_cmp); + } + } + + void Assembler::asm_ret(LIns *ins) { + genEpilogue(); + releaseRegisters(); + assignSavedRegs(); + LIns *value = ins->oprnd1(); + Register r = ins->isop(LIR_retd) ? F1 : R3; + findSpecificRegFor(value, r); + } + + void Assembler::asm_nongp_copy(Register r, Register s) { + // PPC doesn't support any GPR<->FPR moves + NanoAssert((rmask(r) & FpRegs) && (rmask(s) & FpRegs)); + FMR(r, s); + } + + bool Assembler::canRemat(LIns* ins) + { + return ins->isImmI() || ins->isop(LIR_allocp); + } + + void Assembler::asm_restore(LIns *i, Register r) { + int d; + if (i->isop(LIR_allocp)) { + d = deprecated_disp(i); + ADDI(r, FP, d); + } + else if (i->isImmI()) { + asm_li(r, i->immI()); + } + else { + d = findMemFor(i); + if (IsFpReg(r)) { + NanoAssert(i->isQorD()); + LFD(r, d, FP); + } else if (i->isQorD()) { + NanoAssert(IsGpReg(r)); + LD(r, d, FP); + } else { + NanoAssert(i->isI()); + NanoAssert(IsGpReg(r)); + LWZ(r, d, FP); + } + } + } + + void Assembler::asm_immi(LIns *ins) { + Register rr = deprecated_prepResultReg(ins, GpRegs); + asm_li(rr, ins->immI()); + } + + void Assembler::asm_fneg(LIns *ins) { + Register rr = deprecated_prepResultReg(ins, FpRegs); + Register ra = findRegFor(ins->oprnd1(), FpRegs); + FNEG(rr,ra); + } + + void Assembler::asm_param(LIns *ins) { + uint32_t a = ins->paramArg(); + uint32_t kind = ins->paramKind(); + if (kind == 0) { + // ordinary param + // first eight args always in R3..R10 for PPC + if (a < 8) { + // incoming arg in register + deprecated_prepResultReg(ins, rmask(argRegs[a])); + } else { + // todo: support stack based args, arg 0 is at [FP+off] where off + // is the # of regs to be pushed in genProlog() + TODO(asm_param_stk); + } + } + else { + // saved param + deprecated_prepResultReg(ins, rmask(savedRegs[a])); + } + } + + void Assembler::asm_call(LIns *ins) { + if (!ins->isop(LIR_callv)) { + Register retReg = ( ins->isop(LIR_calld) ? F1 : retRegs[0] ); + deprecated_prepResultReg(ins, rmask(retReg)); + } + + // Do this after we've handled the call result, so we don't + // force the call result to be spilled unnecessarily. + evictScratchRegsExcept(0); + + const CallInfo* call = ins->callInfo(); + ArgType argTypes[MAXARGS]; + uint32_t argc = call->getArgTypes(argTypes); + + bool indirect; + if (!(indirect = call->isIndirect())) { + verbose_only(if (_logc->lcbits & LC_Native) + outputf(" %p:", _nIns); + ) + br((NIns*)call->_address, 1); + } else { + // Indirect call: we assign the address arg to R11 since it's not + // used for regular arguments, and is otherwise scratch since it's + // clobberred by the call. + underrunProtect(8); // underrunProtect might clobber CTR + BCTRL(); + MTCTR(R11); + asm_regarg(ARGTYPE_P, ins->arg(--argc), R11); + } + + int param_size = 0; + + Register r = R3; + Register fr = F1; + for(uint32_t i = 0; i < argc; i++) { + uint32_t j = argc - i - 1; + ArgType ty = argTypes[j]; + LIns* arg = ins->arg(j); + NanoAssert(ty != ARGTYPE_V); + if (ty != ARGTYPE_D) { + // GP arg + if (r <= R10) { + asm_regarg(ty, arg, r); + r = r + 1; + param_size += sizeof(void*); + } else { + // put arg on stack + TODO(stack_int32); + } + } else { + // double + if (fr <= F13) { + asm_regarg(ty, arg, fr); + fr = fr + 1; + #ifdef NANOJIT_64BIT + r = r + 1; + #else + r = r + 2; // Skip 2 GPRs. + #endif + param_size += sizeof(double); + } else { + // put arg on stack + TODO(stack_double); + } + } + } + if (param_size > max_param_size) + max_param_size = param_size; + } + + void Assembler::asm_regarg(ArgType ty, LIns* p, Register r) + { + NanoAssert(r != deprecated_UnknownReg); + NanoAssert(ty != ARGTYPE_V); + if (ty != ARGTYPE_D) + { + #ifdef NANOJIT_64BIT + if (ty == ARGTYPE_I) { + // sign extend 32->64 + EXTSW(r, r); + } else if (ty == ARGTYPE_UI) { + // zero extend 32->64 + CLRLDI(r, r, 32); + } + #endif + // arg goes in specific register + if (p->isImmI()) { + asm_li(r, p->immI()); + } else { + if (p->isExtant()) { + if (!p->deprecated_hasKnownReg()) { + // load it into the arg reg + int d = findMemFor(p); + if (p->isop(LIR_allocp)) { + NanoAssert(isS16(d)); + ADDI(r, FP, d); + } else if (p->isQorD()) { + LD(r, d, FP); + } else { + LWZ(r, d, FP); + } + } else { + // it must be in a saved reg + MR(r, p->deprecated_getReg()); + } + } + else { + // this is the last use, so fine to assign it + // to the scratch reg, it's dead after this point. + findSpecificRegFor(p, r); + } + } + } + else { + if (p->isExtant()) { + Register rp = p->deprecated_getReg(); + if (!deprecated_isKnownReg(rp) || !IsFpReg(rp)) { + // load it into the arg reg + int d = findMemFor(p); + LFD(r, d, FP); + } else { + // it must be in a saved reg + NanoAssert(IsFpReg(r) && IsFpReg(rp)); + FMR(r, rp); + } + } + else { + // this is the last use, so fine to assign it + // to the scratch reg, it's dead after this point. + findSpecificRegFor(p, r); + } + } + } + + void Assembler::asm_spill(Register rr, int d, bool quad) { + (void)quad; + NanoAssert(d); + if (IsFpReg(rr)) { + NanoAssert(quad); + STFD(rr, d, FP); + } + #ifdef NANOJIT_64BIT + else if (quad) { + STD(rr, d, FP); + } + #endif + else { + NanoAssert(!quad); + STW(rr, d, FP); + } + } + + void Assembler::asm_arith(LIns *ins) { + LOpcode op = ins->opcode(); + LIns* lhs = ins->oprnd1(); + LIns* rhs = ins->oprnd2(); + RegisterMask allow = GpRegs; + Register rr = deprecated_prepResultReg(ins, allow); + Register ra = findRegFor(lhs, GpRegs); + + if (rhs->isImmI()) { + int32_t rhsc = rhs->immI(); + if (isS16(rhsc)) { + // ppc arith immediate ops sign-exted the imm16 value + switch (op) { + case LIR_addi: + CASE64(LIR_addq:) + ADDI(rr, ra, rhsc); + return; + case LIR_subi: + SUBI(rr, ra, rhsc); + return; + case LIR_muli: + MULLI(rr, ra, rhsc); + return; + } + } + if (isU16(rhsc)) { + // ppc logical immediate zero-extend the imm16 value + switch (op) { + CASE64(LIR_orq:) + case LIR_ori: + ORI(rr, ra, rhsc); + return; + CASE64(LIR_andq:) + case LIR_andi: + ANDI(rr, ra, rhsc); + return; + CASE64(LIR_xorq:) + case LIR_xori: + XORI(rr, ra, rhsc); + return; + } + } + + // LIR shift ops only use last 5bits of shift const + switch (op) { + case LIR_lshi: + SLWI(rr, ra, rhsc&31); + return; + case LIR_rshui: + SRWI(rr, ra, rhsc&31); + return; + case LIR_rshi: + SRAWI(rr, ra, rhsc&31); + return; + } + } + + // general case, put rhs in register + Register rb = rhs==lhs ? ra : findRegFor(rhs, GpRegs&~rmask(ra)); + switch (op) { + CASE64(LIR_addq:) + case LIR_addi: + ADD(rr, ra, rb); + break; + CASE64(LIR_andq:) + case LIR_andi: + AND(rr, ra, rb); + break; + CASE64(LIR_orq:) + case LIR_ori: + OR(rr, ra, rb); + break; + CASE64(LIR_xorq:) + case LIR_xori: + XOR(rr, ra, rb); + break; + case LIR_subi: SUBF(rr, rb, ra); break; + case LIR_lshi: SLW(rr, ra, R0); ANDI(R0, rb, 31); break; + case LIR_rshi: SRAW(rr, ra, R0); ANDI(R0, rb, 31); break; + case LIR_rshui: SRW(rr, ra, R0); ANDI(R0, rb, 31); break; + case LIR_muli: MULLW(rr, ra, rb); break; + #ifdef NANOJIT_64BIT + case LIR_lshq: + SLD(rr, ra, R0); + ANDI(R0, rb, 63); + break; + case LIR_rshuq: + SRD(rr, ra, R0); + ANDI(R0, rb, 63); + break; + case LIR_rshq: + SRAD(rr, ra, R0); + ANDI(R0, rb, 63); + TODO(qirsh); + break; + #endif + default: + debug_only(outputf("%s",lirNames[op]);) + TODO(asm_arith); + } + } + + void Assembler::asm_fop(LIns *ins) { + LOpcode op = ins->opcode(); + LIns* lhs = ins->oprnd1(); + LIns* rhs = ins->oprnd2(); + RegisterMask allow = FpRegs; + Register rr = deprecated_prepResultReg(ins, allow); + Register ra, rb; + findRegFor2(allow, lhs, ra, allow, rhs, rb); + switch (op) { + case LIR_addd: FADD(rr, ra, rb); break; + case LIR_subd: FSUB(rr, ra, rb); break; + case LIR_muld: FMUL(rr, ra, rb); break; + case LIR_divd: FDIV(rr, ra, rb); break; + default: + debug_only(outputf("%s",lirNames[op]);) + TODO(asm_fop); + } + } + + void Assembler::asm_i2d(LIns *ins) { + Register r = deprecated_prepResultReg(ins, FpRegs); + Register v = findRegFor(ins->oprnd1(), GpRegs); + const int d = 16; // natural aligned + + #if defined NANOJIT_64BIT && !PEDANTIC + FCFID(r, r); // convert to double + LFD(r, d, SP); // load into fpu register + STD(v, d, SP); // save int64 + EXTSW(v, v); // extend sign destructively, ok since oprnd1 only is 32bit + #else + FSUB(r, r, F0); + LFD(r, d, SP); // scratch area in outgoing linkage area + STW(R0, d+4, SP); + XORIS(R0, v, 0x8000); + LFD(F0, d, SP); + STW(R0, d+4, SP); + LIS(R0, 0x8000); + STW(R0, d, SP); + LIS(R0, 0x4330); + #endif + } + + void Assembler::asm_ui2d(LIns *ins) { + Register r = deprecated_prepResultReg(ins, FpRegs); + Register v = findRegFor(ins->oprnd1(), GpRegs); + const int d = 16; + + #if defined NANOJIT_64BIT && !PEDANTIC + FCFID(r, r); // convert to double + LFD(r, d, SP); // load into fpu register + STD(v, d, SP); // save int64 + CLRLDI(v, v, 32); // zero-extend destructively + #else + FSUB(r, r, F0); + LFD(F0, d, SP); + STW(R0, d+4, SP); + LI(R0, 0); + LFD(r, d, SP); + STW(v, d+4, SP); + STW(R0, d, SP); + LIS(R0, 0x4330); + #endif + } + + void Assembler::asm_d2i(LIns*) { + NanoAssertMsg(0, "NJ_F2I_SUPPORTED not yet supported for this architecture"); + } + + #if defined NANOJIT_64BIT + // XXX: this is sub-optimal, see https://bugzilla.mozilla.org/show_bug.cgi?id=540368#c7. + void Assembler::asm_q2i(LIns *ins) { + Register rr = deprecated_prepResultReg(ins, GpRegs); + int d = findMemFor(ins->oprnd1()); + LWZ(rr, d+4, FP); + } + + void Assembler::asm_ui2uq(LIns *ins) { + LOpcode op = ins->opcode(); + Register r = deprecated_prepResultReg(ins, GpRegs); + Register v = findRegFor(ins->oprnd1(), GpRegs); + switch (op) { + default: + debug_only(outputf("%s",lirNames[op])); + TODO(asm_ui2uq); + case LIR_ui2uq: + CLRLDI(r, v, 32); // clears the top 32 bits + break; + case LIR_i2q: + EXTSW(r, v); + break; + } + } + + void Assembler::asm_dasq(LIns*) { + TODO(asm_dasq); + } + + void Assembler::asm_qasd(LIns*) { + TODO(asm_qasd); + } + + #endif + +#ifdef NANOJIT_64BIT + void Assembler::asm_immq(LIns *ins) { + Register r = ins->deprecated_getReg(); + if (deprecated_isKnownReg(r) && (rmask(r) & FpRegs)) { + // FPR already assigned, fine, use it + deprecated_freeRsrcOf(ins); + } else { + // use a GPR register; its okay to copy doubles with GPR's + // but *not* okay to copy non-doubles with FPR's + r = deprecated_prepResultReg(ins, GpRegs); + } + + if (rmask(r) & FpRegs) { + union { + double d; + struct { + int32_t hi, lo; // Always assuming big-endian in NativePPC.cpp + } w; + }; + d = ins->immD(); + LFD(r, 8, SP); + STW(R0, 12, SP); + asm_li(R0, w.lo); + STW(R0, 8, SP); + asm_li(R0, w.hi); + } + else { + int64_t q = ins->immQ(); + if (isS32(q)) { + asm_li(r, int32_t(q)); + return; + } + RLDIMI(r,R0,32,0); // or 32,32? + asm_li(R0, int32_t(q>>32)); // hi bits into R0 + asm_li(r, int32_t(q)); // lo bits into dest reg + } + } +#endif + + void Assembler::asm_immd(LIns *ins) { + #ifdef NANOJIT_64BIT + Register r = ins->deprecated_getReg(); + if (deprecated_isKnownReg(r) && (rmask(r) & FpRegs)) { + // FPR already assigned, fine, use it + deprecated_freeRsrcOf(ins); + } else { + // use a GPR register; its okay to copy doubles with GPR's + // but *not* okay to copy non-doubles with FPR's + r = deprecated_prepResultReg(ins, GpRegs); + } + #else + Register r = deprecated_prepResultReg(ins, FpRegs); + #endif + + if (rmask(r) & FpRegs) { + union { + double d; + struct { + int32_t hi, lo; // Always assuming big-endian in NativePPC.cpp + } w; + }; + d = ins->immD(); + LFD(r, 8, SP); + STW(R0, 12, SP); + asm_li(R0, w.lo); + STW(R0, 8, SP); + asm_li(R0, w.hi); + } + else { + int64_t q = ins->immDasQ(); + if (isS32(q)) { + asm_li(r, int32_t(q)); + return; + } + RLDIMI(r,R0,32,0); // or 32,32? + asm_li(R0, int32_t(q>>32)); // hi bits into R0 + asm_li(r, int32_t(q)); // lo bits into dest reg + } + } + + void Assembler::br(NIns* addr, int link) { + // destination unknown, then use maximum branch possible + if (!addr) { + br_far(addr,link); + return; + } + + // powerpc offsets are based on the address of the branch instruction + underrunProtect(4); // ensure _nIns is addr of Bx + ptrdiff_t offset = addr - (_nIns-1); // we want ptr diff's implicit >>2 here + + #if !PEDANTIC + if (isS24(offset)) { + Bx(offset, 0, link); // b addr or bl addr + return; + } + ptrdiff_t absaddr = addr - (NIns*)0; // ptr diff implies >>2 + if (isS24(absaddr)) { + Bx(absaddr, 1, link); // ba addr or bla addr + return; + } + #endif // !PEDANTIC + + br_far(addr,link); + } + + void Assembler::br_far(NIns* addr, int link) { + // far jump. + // can't have a page break in this sequence, because the break + // would also clobber ctr and r2. We use R2 here because it's not available + // to the register allocator, and we use R0 everywhere else as scratch, so using + // R2 here avoids clobbering anything else besides CTR. + #ifdef NANOJIT_64BIT + if (addr==0 || !isU32(uintptr_t(addr))) { + // really far jump to 64bit abs addr + underrunProtect(28); // 7 instructions + BCTR(link); + MTCTR(R2); + asm_li64(R2, uintptr_t(addr)); // 5 instructions + return; + } + #endif + underrunProtect(16); + BCTR(link); + MTCTR(R2); + asm_li32(R2, uint32_t(uintptr_t(addr))); // 2 instructions + } + + void Assembler::underrunProtect(int bytes) { + NanoAssertMsg(bytes<=LARGEST_UNDERRUN_PROT, "constant LARGEST_UNDERRUN_PROT is too small"); + int instr = (bytes + sizeof(NIns) - 1) / sizeof(NIns); + NIns *pc = _nIns; + NIns *top = codeStart; // this may be in a normal code chunk or an exit code chunk + + #if PEDANTIC + // pedanticTop is based on the last call to underrunProtect; any time we call + // underrunProtect and would use more than what's already protected, then insert + // a page break jump. Sometimes, this will be to a new page, usually it's just + // the next instruction and the only effect is to clobber R2 & CTR + + NanoAssert(pedanticTop >= top); + if (pc - instr < pedanticTop) { + // no page break required, but insert a far branch anyway just to be difficult + #ifdef NANOJIT_64BIT + const int br_size = 7; + #else + const int br_size = 4; + #endif + if (pc - instr - br_size < top) { + // really do need a page break + verbose_only(if (_logc->lcbits & LC_Native) outputf("newpage %p:", pc);) + codeAlloc(); + } + // now emit the jump, but make sure we won't need another page break. + // we're pedantic, but not *that* pedantic. + pedanticTop = _nIns - br_size; + br(pc, 0); + pedanticTop = _nIns - instr; + } + #else + if (pc - instr < top) { + verbose_only(if (_logc->lcbits & LC_Native) outputf("newpage %p:", pc);) + // This may be in a normal code chunk or an exit code chunk. + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes)); + // This jump will call underrunProtect again, but since we're on a new + // page, nothing will happen. + br(pc, 0); + } + #endif + } + + void Assembler::asm_cmov(LIns* ins) + { + LIns* condval = ins->oprnd1(); + LIns* iftrue = ins->oprnd2(); + LIns* iffalse = ins->oprnd3(); + + #ifdef NANOJIT_64BIT + NanoAssert((ins->opcode() == LIR_cmovi && iftrue->isI() && iffalse->isI()) || + (ins->opcode() == LIR_cmovq && iftrue->isQ() && iffalse->isQ())); + #else + NanoAssert((ins->opcode() == LIR_cmovi && iftrue->isI() && iffalse->isI())); + #endif + + Register rr = prepareResultReg(ins, GpRegs); + Register rf = findRegFor(iffalse, GpRegs & ~rmask(rr)); + + // If 'iftrue' isn't in a register, it can be clobbered by 'ins'. + Register rt = iftrue->isInReg() ? iftrue->getReg() : rr; + + underrunProtect(16); // make sure branch target and branch are on same page and thus near + NIns *after = _nIns; + verbose_only(if (_logc->lcbits & LC_Native) outputf("%p:",after);) + MR(rr,rf); + + NanoAssert(isS24(after - (_nIns-1))); + asm_branch_near(false, condval, after); + + if (rr != rt) + MR(rr, rt); + + freeResourcesOf(ins); + if (!iftrue->isInReg()) { + NanoAssert(rt == rr); + findSpecificRegForUnallocated(iftrue, rr); + } + + asm_cmp(condval->opcode(), condval->oprnd1(), condval->oprnd2(), CR7); + } + + RegisterMask Assembler::nHint(LIns* ins) { + NanoAssert(ins->isop(LIR_paramp)); + RegisterMask prefer = 0; + if (ins->paramKind() == 0) + if (ins->paramArg() < 8) + prefer = rmask(argRegs[ins->paramArg()]); + return prefer; + } + + void Assembler::asm_neg_not(LIns *ins) { + Register rr = deprecated_prepResultReg(ins, GpRegs); + Register ra = findRegFor(ins->oprnd1(), GpRegs); + if (ins->isop(LIR_negi)) { + NEG(rr, ra); + } else { + NOT(rr, ra); + } + } + + void Assembler::nInit(AvmCore*) { + nHints[LIR_calli] = rmask(R3); + #ifdef NANOJIT_64BIT + nHints[LIR_callq] = rmask(R3); + #endif + nHints[LIR_calld] = rmask(F1); + nHints[LIR_paramp] = PREFER_SPECIAL; + } + + void Assembler::nBeginAssembly() { + max_param_size = 0; + } + + void Assembler::nativePageSetup() { + NanoAssert(!_inExit); + if (!_nIns) { + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes)); + IF_PEDANTIC( pedanticTop = _nIns; ) + } + } + + void Assembler::nativePageReset() + {} + + // Increment the 32-bit profiling counter at pCtr, without + // changing any registers. + verbose_only( + void Assembler::asm_inc_m32(uint32_t* /*pCtr*/) + { + } + ) + + void Assembler::nPatchBranch(NIns *branch, NIns *target) { + // ppc relative offsets are based on the addr of the branch instruction + ptrdiff_t bd = target - branch; + if (branch[0] == PPC_b) { + // unconditional, 24bit offset. Whoever generated the unpatched jump + // must have known the final size would fit in 24bits! otherwise the + // jump would be (lis,ori,mtctr,bctr) and we'd be patching the lis,ori. + NanoAssert(isS24(bd)); + branch[0] |= (bd & 0xffffff) << 2; + } + else if ((branch[0] & PPC_bc) == PPC_bc) { + // conditional, 14bit offset. Whoever generated the unpatched jump + // must have known the final size would fit in 14bits! otherwise the + // jump would be (lis,ori,mtctr,bcctr) and we'd be patching the lis,ori below. + NanoAssert(isS14(bd)); + NanoAssert(((branch[0] & 0x3fff)<<2) == 0); + branch[0] |= (bd & 0x3fff) << 2; + TODO(patch_bc); + } + #ifdef NANOJIT_64BIT + // patch 64bit branch + else if ((branch[0] & ~(31<<21)) == PPC_addis) { + // general branch, using lis,ori,sldi,oris,ori to load the const 64bit addr. + Register rd = { (branch[0] >> 21) & 31 }; + NanoAssert(branch[1] == PPC_ori | GPR(rd)<<21 | GPR(rd)<<16); + NanoAssert(branch[3] == PPC_oris | GPR(rd)<<21 | GPR(rd)<<16); + NanoAssert(branch[4] == PPC_ori | GPR(rd)<<21 | GPR(rd)<<16); + uint64_t imm = uintptr_t(target); + uint32_t lo = uint32_t(imm); + uint32_t hi = uint32_t(imm>>32); + branch[0] = PPC_addis | GPR(rd)<<21 | uint16_t(hi>>16); + branch[1] = PPC_ori | GPR(rd)<<21 | GPR(rd)<<16 | uint16_t(hi); + branch[3] = PPC_oris | GPR(rd)<<21 | GPR(rd)<<16 | uint16_t(lo>>16); + branch[4] = PPC_ori | GPR(rd)<<21 | GPR(rd)<<16 | uint16_t(lo); + } + #else // NANOJIT_64BIT + // patch 32bit branch + else if ((branch[0] & ~(31<<21)) == PPC_addis) { + // general branch, using lis,ori to load the const addr. + // patch a lis,ori sequence with a 32bit value + Register rd = { (branch[0] >> 21) & 31 }; + NanoAssert(branch[1] == PPC_ori | GPR(rd)<<21 | GPR(rd)<<16); + uint32_t imm = uint32_t(target); + branch[0] = PPC_addis | GPR(rd)<<21 | uint16_t(imm >> 16); // lis rd, imm >> 16 + branch[1] = PPC_ori | GPR(rd)<<21 | GPR(rd)<<16 | uint16_t(imm); // ori rd, rd, imm & 0xffff + } + #endif // !NANOJIT_64BIT + else { + TODO(unknown_patch); + } + } + + static int cntzlw(int set) { + // On PowerPC, prefer higher registers, to minimize + // size of nonvolatile area that must be saved. + register uint32_t i; + #ifdef __GNUC__ + asm ("cntlzw %0,%1" : "=r" (i) : "r" (set)); + #else // __GNUC__ + # error("unsupported compiler") + #endif // __GNUC__ + return 31-i; + } + + Register Assembler::nRegisterAllocFromSet(RegisterMask set) { + uint32_t i; + // note, deliberate truncation of 64->32 bits + if (set & 0xffffffff) { + i = cntzlw(int(set)); // gp reg + } else { + i = 32 + cntzlw(int(set>>32)); // fp reg + } + Register r = { i }; + _allocator.free &= ~rmask(r); + return r; + } + + void Assembler::nRegisterResetAll(RegAlloc ®s) { + regs.clear(); + regs.free = SavedRegs | 0x1ff8 /* R3-12 */ | 0x3ffe00000000LL /* F1-13 */; + } + +#ifdef NANOJIT_64BIT + void Assembler::asm_qbinop(LIns *ins) { + LOpcode op = ins->opcode(); + switch (op) { + case LIR_orq: + case LIR_andq: + case LIR_rshuq: + case LIR_rshq: + case LIR_lshq: + case LIR_xorq: + case LIR_addq: + asm_arith(ins); + break; + default: + debug_only(outputf("%s",lirNames[op])); + TODO(asm_qbinop); + } + } +#endif // NANOJIT_64BIT + + void Assembler::nFragExit(LIns*) { + TODO(nFragExit); + } + + void Assembler::asm_jtbl(LIns* ins, NIns** native_table) + { + // R0 = index*4, R2 = table, CTR = computed address to jump to. + // must ensure no page breaks in here because R2 & CTR can get clobbered. + Register indexreg = findRegFor(ins->oprnd1(), GpRegs); +#ifdef NANOJIT_64BIT + underrunProtect(9*4); + BCTR(0); // jump to address in CTR + MTCTR(R2); // CTR = R2 + LDX(R2, R2, R0); // R2 = [table + index*8] + SLDI(R0, indexreg, 3); // R0 = index*8 + asm_li64(R2, uint64_t(native_table)); // R2 = table (5 instr) +#else // 64bit + underrunProtect(6*4); + BCTR(0); // jump to address in CTR + MTCTR(R2); // CTR = R2 + LWZX(R2, R2, R0); // R2 = [table + index*4] + SLWI(R0, indexreg, 2); // R0 = index*4 + asm_li(R2, int32_t(native_table)); // R2 = table (up to 2 instructions) +#endif // 64bit + } + + void Assembler::swapCodeChunks() { + if (!_nExitIns) { + codeAlloc(exitStart, exitEnd, _nExitIns verbose_only(, exitBytes)); + } + SWAP(NIns*, _nIns, _nExitIns); + SWAP(NIns*, codeStart, exitStart); + SWAP(NIns*, codeEnd, exitEnd); + verbose_only( SWAP(size_t, codeBytes, exitBytes); ) + } + + void Assembler::asm_insert_random_nop() { + NanoAssert(0); // not supported + } + +} // namespace nanojit + +#endif // FEATURE_NANOJIT && NANOJIT_PPC diff --git a/js/src/nanojit/NativePPC.h b/js/src/nanojit/NativePPC.h new file mode 100644 index 0000000..70cd5a0 --- /dev/null +++ b/js/src/nanojit/NativePPC.h @@ -0,0 +1,604 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __nanojit_NativePPC__ +#define __nanojit_NativePPC__ + +#ifdef PERFM +#define DOPROF +#include "../vprof/vprof.h" +#define count_instr() _nvprof("ppc",1) +#define count_prolog() _nvprof("ppc-prolog",1); count_instr(); +#define count_imt() _nvprof("ppc-imt",1) count_instr() +#else +#define count_instr() +#define count_prolog() +#define count_imt() +#endif + +#include "NativeCommon.h" + +namespace nanojit +{ +#define NJ_MAX_STACK_ENTRY 4096 +#define NJ_ALIGN_STACK 16 + +#define NJ_JTBL_SUPPORTED 1 +#define NJ_EXPANDED_LOADSTORE_SUPPORTED 0 +#define NJ_F2I_SUPPORTED 0 +#define NJ_SOFTFLOAT_SUPPORTED 0 +#define NJ_DIVI_SUPPORTED 0 + + enum ConditionRegister { + CR0 = 0, + CR1 = 1, + CR2 = 2, + CR3 = 3, + CR4 = 4, + CR5 = 5, + CR6 = 6, + CR7 = 7, + }; + + enum ConditionBit { + COND_lt = 0, // msb of CR + COND_gt = 1, + COND_eq = 2, + COND_so = 3, // lsb of CR + COND_un = 3, + }; + + // this is the BO field in condition instructions + enum ConditionOption { + BO_true = 12, // branch if true + BO_false = 4, // branch if false + }; + + static const Register + // general purpose 32bit regs + R0 = { 0 }, // scratch or the value 0, excluded from regalloc + SP = { 1 }, // stack pointer, excluded from regalloc + R2 = { 2 }, // scratch on MacOSX, rtoc pointer elsewhere + R3 = { 3 }, // this, return value, MSW of int64 return + R4 = { 4 }, // param, LSW of int64 return + R5 = { 5 }, // param + R6 = { 6 }, // param + R7 = { 7 }, // param + R8 = { 8 }, // param + R9 = { 9 }, // param + R10 = { 10 }, // param + R11 = { 11 }, // scratch in leaf funcs, outgoing arg ptr otherwise + R12 = { 12 }, // scratch + R13 = { 13 }, // ppc32: saved, ppc64: thread-specific storage + R14 = { 14 }, // saved + R15 = { 15 }, + R16 = { 16 }, + R17 = { 17 }, + R18 = { 18 }, + R19 = { 19 }, + R20 = { 20 }, + R21 = { 21 }, + R22 = { 22 }, + R23 = { 23 }, + R24 = { 24 }, + R25 = { 25 }, + R26 = { 26 }, + R27 = { 27 }, + R28 = { 28 }, + R29 = { 29 }, + R30 = { 30 }, + R31 = { 31 }, // excluded from regalloc since we use it as FP + FP = R31, + + // FP regs + F0 = { 32 }, // scratch, excluded from reg alloc + F1 = { 33 }, // param, double return value + F2 = { 34 }, // param + F3 = { 35 }, // param + F4 = { 36 }, // param + F5 = { 37 }, // param + F6 = { 38 }, // param + F7 = { 39 }, // param + F8 = { 40 }, // param + F9 = { 41 }, // param + F10 = { 42 }, // param + F11 = { 43 }, // param + F12 = { 44 }, // param + F13 = { 45 }, // param + F14 = { 46 }, // F14-31 saved + F15 = { 47 }, + F16 = { 48 }, + F17 = { 49 }, + F18 = { 50 }, + F19 = { 51 }, + F20 = { 52 }, + F21 = { 53 }, + F22 = { 54 }, + F23 = { 55 }, + F24 = { 56 }, + F25 = { 57 }, + F26 = { 58 }, + F27 = { 59 }, + F28 = { 60 }, + F29 = { 61 }, + F30 = { 62 }, + F31 = { 63 }, + + // special purpose registers (SPR) + Rxer = { 1 }, + Rlr = { 8 }, + Rctr = { 9 }, + + deprecated_UnknownReg = { 127 }; // XXX: remove eventually, see bug 538924 + + static const uint32_t FirstRegNum = 0; // R0 + static const uint32_t LastRegNum = 64; // F31 + + enum PpcOpcode { + // opcodes + PPC_add = 0x7C000214, // add + PPC_addo = 0x7C000614, // add & OE=1 (can set OV) + PPC_addi = 0x38000000, // add immediate + PPC_addis = 0x3C000000, // add immediate shifted + PPC_and = 0x7C000038, // and + PPC_andc = 0x7C000078, // and with compliment + PPC_andi = 0x70000000, // and immediate + PPC_andis = 0x74000000, // and immediate shifted + PPC_b = 0x48000000, // branch + PPC_bc = 0x40000000, // branch conditional + PPC_bcctr = 0x4C000420, // branch conditional to count register + PPC_cmp = 0x7C000000, // compare + PPC_cmpi = 0x2C000000, // compare immediate + PPC_cmpl = 0x7C000040, // compare logical + PPC_cmpli = 0x28000000, // compare logical immediate + PPC_cror = 0x4C000382, // condition register or + PPC_extsw = 0x7C0007B4, // extend sign word + PPC_fadd = 0xFC00002A, // floating add (double precision) + PPC_fcfid = 0xFC00069C, // floating convert from integer doubleword + PPC_fcmpu = 0xFC000000, // floating compare unordered + PPC_fdiv = 0xFC000024, // floating divide (double precision) + PPC_fmr = 0xFC000090, // floating move register (double precision) + PPC_fmul = 0xFC000032, // floating multiply (double precision) + PPC_fneg = 0xFC000050, // floating negate + PPC_fsub = 0xFC000028, // floating subtract (double precision) + PPC_lbz = 0x88000000, // load byte and zero + PPC_lbzx = 0x7C0000AE, // load byte and zero indexed + PPC_ld = 0xE8000000, // load doubleword + PPC_ldx = 0x7C00002A, // load doubleword indexed + PPC_lfd = 0xC8000000, // load floating point double + PPC_lfdx = 0x7C0004AE, // load floating-point double indexed + PPC_lhz = 0xA0000000, // load halfword and zero + PPC_lhzx = 0x7C00022E, // load halfword and zero indexed + PPC_lwz = 0x80000000, // load word and zero + PPC_lwzx = 0x7C00002E, // load word and zero indexed + PPC_mfcr = 0x7C000026, // move from condition register + PPC_mfspr = 0x7C0002A6, // move from spr (special purpose register) + PPC_mtspr = 0x7C0003A6, // move to spr + PPC_mulli = 0x1C000000, // multiply low immediate + PPC_mullw = 0x7C0001D6, // multiply low word + PPC_neg = 0x7C0000D0, // negate + PPC_nor = 0x7C0000F8, // nor + PPC_or = 0x7C000378, // or + PPC_ori = 0x60000000, // or immediate + PPC_oris = 0x64000000, // or immediate shifted + PPC_rlwinm = 0x54000000, // rotate left word then and with mask + PPC_rldicl = 0x78000000, // rotate left doubleword immediate then clear left + PPC_rldicr = 0x78000004, // rotate left doubleword immediate then clear right + PPC_rldimi = 0x7800000C, // rotate left doubleword immediate then mask insert + PPC_sld = 0x7C000036, // shift left doubleword + PPC_slw = 0x7C000030, // shift left word + PPC_srad = 0x7C000634, // shift right algebraic doubleword (sign ext) + PPC_sradi = 0x7C000674, // shift right algebraic doubleword immediate + PPC_sraw = 0x7C000630, // shift right algebraic word (sign ext) + PPC_srawi = 0x7C000670, // shift right algebraic word immediate + PPC_srd = 0x7C000436, // shift right doubleword (zero ext) + PPC_srw = 0x7C000430, // shift right word (zero ext) + PPC_stb = 0x98000000, // store byte + PPC_stbx = 0x7C0001AE, // store byte indexed + PPC_std = 0xF8000000, // store doubleword + PPC_stdu = 0xF8000001, // store doubleword with update + PPC_stdux = 0x7C00016A, // store doubleword with update indexed + PPC_stdx = 0x7C00012A, // store doubleword indexed + PPC_stfd = 0xD8000000, // store floating-point double + PPC_stfdx = 0x7C0005AE, // store floating-point double indexed + PPC_stw = 0x90000000, // store word + PPC_stwu = 0x94000000, // store word with update + PPC_stwux = 0x7C00016E, // store word with update indexed + PPC_stwx = 0x7C00012E, // store word indexed + PPC_subf = 0x7C000050, // subtract from + PPC_xor = 0x7C000278, // xor + PPC_xori = 0x68000000, // xor immediate + PPC_xoris = 0x6C000000, // xor immediate shifted + + // simplified mnemonics + PPC_mr = PPC_or, + PPC_not = PPC_nor, + PPC_nop = PPC_ori, + }; + + typedef uint64_t RegisterMask; + + static const RegisterMask GpRegs = 0xffffffff; + static const RegisterMask FpRegs = 0xffffffff00000000LL; + // R31 is a saved reg too, but we use it as our Frame ptr FP +#ifdef NANOJIT_64BIT + // R13 reserved for thread-specific storage on ppc64-darwin + static const RegisterMask SavedRegs = 0x7fffc000; // R14-R30 saved + static const int NumSavedRegs = 17; // R14-R30 +#else + static const RegisterMask SavedRegs = 0x7fffe000; // R13-R30 saved + static const int NumSavedRegs = 18; // R13-R30 +#endif + + static inline bool IsGpReg(Register r) { + return r <= R31; + } + static inline bool IsFpReg(Register r) { + return r >= F0; + } + + verbose_only( extern const char* regNames[]; ) + + #define DECLARE_PLATFORM_STATS() + #define DECLARE_PLATFORM_REGALLOC() + +#ifdef NANOJIT_64BIT + #define DECL_PPC64()\ + void asm_qbinop(LIns*); +#else + #define DECL_PPC64() +#endif + + #define DECLARE_PLATFORM_ASSEMBLER() \ + const static Register argRegs[8], retRegs[2]; \ + void underrunProtect(int bytes); \ + void nativePageReset(); \ + void nativePageSetup(); \ + bool hardenNopInsertion(const Config& /*c*/) { return false; } \ + void br(NIns *addr, int link); \ + void br_far(NIns *addr, int link); \ + void asm_regarg(ArgType, LIns*, Register); \ + void asm_li(Register r, int32_t imm); \ + void asm_li32(Register r, int32_t imm); \ + void asm_li64(Register r, uint64_t imm); \ + void asm_cmp(LOpcode op, LIns *a, LIns *b, ConditionRegister); \ + NIns* asm_branch_far(bool onfalse, LIns *cond, NIns * const targ); \ + NIns* asm_branch_near(bool onfalse, LIns *cond, NIns * const targ); \ + int max_param_size; /* bytes */ \ + DECL_PPC64() + + const int LARGEST_UNDERRUN_PROT = 9*4; // largest value passed to underrunProtect + + typedef uint32_t NIns; + + // Bytes of icache to flush after Assembler::patch + const size_t LARGEST_BRANCH_PATCH = 4 * sizeof(NIns); + + #define EMIT1(ins, fmt, ...) do {\ + underrunProtect(4);\ + *(--_nIns) = (NIns) (ins);\ + asm_output(fmt, ##__VA_ARGS__);\ + } while (0) /* no semi */ + + #define GPR(r) REGNUM(r) + #define FPR(r) (REGNUM(r) & 31) + + #define Bx(li,aa,lk) EMIT1(PPC_b | ((li)&0xffffff)<<2 | (aa)<<1 | (lk),\ + "b%s%s %p", (lk)?"l":"", (aa)?"a":"", _nIns+(li)) + + #define B(li) Bx(li,0,0) + #define BA(li) Bx(li,1,0) + #define BL(li) Bx(li,0,1) + #define BLA(li) Bx(li,1,1) + + #define BCx(op,bo,bit,cr,bd,aa,lk) EMIT1(PPC_bc | (bo)<<21 | (4*(cr)+COND_##bit)<<16 |\ + ((bd)&0x3fff)<<2 | (aa)<<1 | (lk),\ + "%s%s%s cr%d,%p", #op, (lk)?"l":"", (aa)?"a":"", (cr), _nIns+(bd)) + + #define BLT(cr,bd) BCx(blt, BO_true, lt, cr, bd, 0, 0) + #define BGT(cr,bd) BCx(bgt, BO_true, gt, cr, bd, 0, 0) + #define BEQ(cr,bd) BCx(beq, BO_true, eq, cr, bd, 0, 0) + #define BGE(cr,bd) BCx(bge, BO_false, lt, cr, bd, 0, 0) + #define BLE(cr,bd) BCx(ble, BO_false, gt, cr, bd, 0, 0) + #define BNE(cr,bd) BCx(bne, BO_false, eq, cr, bd, 0, 0) + #define BNG(cr,bd) BCx(bng, BO_false, gt, cr, bd, 0, 0) + #define BNL(cr,bd) BCx(bnl, BO_false, lt, cr, bd, 0, 0) + + #define BCCTRx(op, bo, bit, cr, lk) EMIT1(PPC_bcctr | (bo)<<21 | (4*(cr)+COND_##bit)<<16 | (lk)&1,\ + "%sctr%s cr%d", #op, (lk)?"l":"", (cr)) + + #define BLTCTR(cr) BCCTRx(blt, BO_true, lt, cr, 0) + #define BGTCTR(cr) BCCTRx(bgt, BO_true, gt, cr, 0) + #define BEQCTR(cr) BCCTRx(beq, BO_true, eq, cr, 0) + #define BGECTR(cr) BCCTRx(bge, BO_false, lt, cr, 0) + #define BLECTR(cr) BCCTRx(ble, BO_false, gt, cr, 0) + #define BNECTR(cr) BCCTRx(bne, BO_false, eq, cr, 0) + #define BNGCTR(cr) BCCTRx(bng, BO_false, gt, cr, 0) + #define BNLCTR(cr) BCCTRx(bnl, BO_false, lt, cr, 0) + + #define Simple(asm,op) EMIT1(op, "%s", #asm) + + #define BCTR(link) EMIT1(0x4E800420 | (link), "bctr%s", (link) ? "l" : "") + #define BCTRL() BCTR(1) + + #define BLR() EMIT1(0x4E800020, "blr") + #define NOP() EMIT1(PPC_nop, "nop") /* ori 0,0,0 */ + + #define ALU2(op, rd, ra, rb, rc) EMIT1(PPC_##op | GPR(rd)<<21 | GPR(ra)<<16 | GPR(rb)<<11 | (rc),\ + "%s%s %s,%s,%s", #op, (rc)?".":"", gpn(rd), gpn(ra), gpn(rb)) + #define BITALU2(op, ra, rs, rb, rc) EMIT1(PPC_##op | GPR(rs)<<21 | GPR(ra)<<16 | GPR(rb)<<11 | (rc),\ + "%s%s %s,%s,%s", #op, (rc)?".":"", gpn(ra), gpn(rs), gpn(rb)) + #define FPUAB(op, d, a, b, rc) EMIT1(PPC_##op | FPR(d)<<21 | FPR(a)<<16 | FPR(b)<<11 | (rc),\ + "%s%s %s,%s,%s", #op, (rc)?".":"", gpn(d), gpn(a), gpn(b)) + #define FPUAC(op, d, a, c, rc) EMIT1(PPC_##op | FPR(d)<<21 | FPR(a)<<16 | FPR(c)<<6 | (rc),\ + "%s%s %s,%s,%s", #op, (rc)?".":"", gpn(d), gpn(a), gpn(c)) + + #define ADD(rd,ra,rb) ALU2(add, rd, ra, rb, 0) + #define ADD_(rd,ra,rb) ALU2(add, rd, ra, rb, 1) + #define ADDO(rd,ra,rb) ALU2(addo, rd, ra, rb, 0) + #define ADDO_(rd,ra,rb) ALU2(addo, rd, ra, rb, 1) + #define SUBF(rd,ra,rb) ALU2(subf, rd, ra, rb, 0) + #define SUBF_(rd,ra,rb) ALU2(subf, rd, ra, rb, 1) + + #define AND(rd,rs,rb) BITALU2(and, rd, rs, rb, 0) + #define AND_(rd,rs,rb) BITALU2(and, rd, rs, rb, 1) + #define OR(rd,rs,rb) BITALU2(or, rd, rs, rb, 0) + #define OR_(rd,rs,rb) BITALU2(or, rd, rs, rb, 1) + #define NOR(rd,rs,rb) BITALU2(nor, rd, rs, rb, 0) + #define NOR_(rd,rs,rb) BITALU2(nor, rd, rs, rb, 1) + #define SLW(rd,rs,rb) BITALU2(slw, rd, rs, rb, 0) + #define SLW_(rd,rs,rb) BITALU2(slw, rd, rs, rb, 1) + #define SRW(rd,rs,rb) BITALU2(srw, rd, rs, rb, 0) + #define SRW_(rd,rs,rb) BITALU2(srw, rd, rs, rb, 1) + #define SRAW(rd,rs,rb) BITALU2(sraw, rd, rs, rb, 0) + #define SRAW_(rd,rs,rb) BITALU2(sraw, rd, rs, rb, 1) + #define XOR(rd,rs,rb) BITALU2(xor, rd, rs, rb, 0) + #define XOR_(rd,rs,rb) BITALU2(xor, rd, rs, rb, 1) + + #define SLD(rd,rs,rb) BITALU2(sld, rd, rs, rb, 0) + #define SRD(rd,rs,rb) BITALU2(srd, rd, rs, rb, 0) + #define SRAD(rd,rs,rb) BITALU2(srad, rd, rs, rb, 0) + + #define FADD(rd,ra,rb) FPUAB(fadd, rd, ra, rb, 0) + #define FADD_(rd,ra,rb) FPUAB(fadd, rd, ra, rb, 1) + #define FDIV(rd,ra,rb) FPUAB(fdiv, rd, ra, rb, 0) + #define FDIV_(rd,ra,rb) FPUAB(fdiv, rd, ra, rb, 1) + #define FMUL(rd,ra,rb) FPUAC(fmul, rd, ra, rb, 0) + #define FMUL_(rd,ra,rb) FPUAC(fmul, rd, ra, rb, 1) + #define FSUB(rd,ra,rb) FPUAB(fsub, rd, ra, rb, 0) + #define FSUB_(rd,ra,rb) FPUAB(fsub, rd, ra, rb, 1) + + #define MULLI(rd,ra,simm) EMIT1(PPC_mulli | GPR(rd)<<21 | GPR(ra)<<16 | uint16_t(simm),\ + "mulli %s,%s,%d", gpn(rd), gpn(ra), int16_t(simm)) + #define MULLW(rd,ra,rb) EMIT1(PPC_mullw | GPR(rd)<<21 | GPR(ra)<<16 | GPR(rb)<<11,\ + "mullw %s,%s,%s", gpn(rd), gpn(ra), gpn(rb)) + + // same as ALU2 with rs=rb, for simplified mnemonics + #define ALU1(op, ra, rs, rc) EMIT1(PPC_##op | GPR(rs)<<21 | GPR(ra)<<16 | GPR(rs)<<11 | (rc),\ + "%s%s %s,%s", #op, (rc)?".":"", gpn(ra), gpn(rs)) + + #define MR(rd, rs) ALU1(mr, rd, rs, 0) // or rd,rs,rs + #define MR_(rd, rs) ALU1(mr, rd, rs, 1) // or. rd,rs,rs + #define NOT(rd, rs) ALU1(not, rd, rs, 0) // nor rd,rs,rs + #define NOT_(rd, rs) ALU1(not, rd, rs, 0) // nor. rd,rs,rs + + #define EXTSW(rd, rs) EMIT1(PPC_extsw | GPR(rs)<<21 | GPR(rd)<<16,\ + "extsw %s,%s", gpn(rd), gpn(rs)) + + #define NEG(rd, rs) EMIT1(PPC_neg | GPR(rd)<<21 | GPR(rs)<<16, "neg %s,%s", gpn(rd), gpn(rs)) + #define FNEG(rd,rs) EMIT1(PPC_fneg | FPR(rd)<<21 | FPR(rs)<<11, "fneg %s,%s", gpn(rd), gpn(rs)) + #define FMR(rd,rb) EMIT1(PPC_fmr | FPR(rd)<<21 | FPR(rb)<<11, "fmr %s,%s", gpn(rd), gpn(rb)) + #define FCFID(rd,rs) EMIT1(PPC_fcfid | FPR(rd)<<21 | FPR(rs)<<11, "fcfid %s,%s", gpn(rd), gpn(rs)) + + #define JMP(addr) br(addr, 0) + + #define SPR(spr) (REGNUM(R##spr)>>5|(REGNUM(R##spr)&31)<<5) + #define MTSPR(spr,rs) EMIT1(PPC_mtspr | GPR(rs)<<21 | SPR(spr)<<11,\ + "mt%s %s", #spr, gpn(rs)) + #define MFSPR(rd,spr) EMIT1(PPC_mfspr | GPR(rd)<<21 | SPR(spr)<<11,\ + "mf%s %s", #spr, gpn(rd)) + + #define MTXER(r) MTSPR(xer, r) + #define MTLR(r) MTSPR(lr, r) + #define MTCTR(r) MTSPR(ctr, r) + + #define MFXER(r) MFSPR(r, xer) + #define MFLR(r) MFSPR(r, lr) + #define MFCTR(r) MFSPR(r, ctr) + + #define MEMd(op, r, d, a) do {\ + NanoAssert(isS16(d));\ + EMIT1(PPC_##op | GPR(r)<<21 | GPR(a)<<16 | uint16_t(d), "%s %s,%d(%s)", #op, gpn(r), int16_t(d), gpn(a));\ + } while(0) /* no addr */ + + #define FMEMd(op, r, d, b) do {\ + NanoAssert(isS16(d));\ + EMIT1(PPC_##op | FPR(r)<<21 | GPR(b)<<16 | uint16_t(d), "%s %s,%d(%s)", #op, gpn(r), int16_t(d), gpn(b));\ + } while(0) /* no addr */ + + #define MEMx(op, r, a, b) EMIT1(PPC_##op | GPR(r)<<21 | GPR(a)<<16 | GPR(b)<<11,\ + "%s %s,%s,%s", #op, gpn(r), gpn(a), gpn(b)) + #define FMEMx(op, r, a, b) EMIT1(PPC_##op | FPR(r)<<21 | GPR(a)<<16 | GPR(b)<<11,\ + "%s %s,%s,%s", #op, gpn(r), gpn(a), gpn(b)) + + #define MEMux(op, rs, ra, rb) EMIT1(PPC_##op | GPR(rs)<<21 | GPR(ra)<<16 | GPR(rb)<<11,\ + "%s %s,%s,%s", #op, gpn(rs), gpn(ra), gpn(rb)) + + #define LBZ(r, d, b) MEMd(lbz, r, d, b) + #define LHZ(r, d, b) MEMd(lhz, r, d, b) + #define LWZ(r, d, b) MEMd(lwz, r, d, b) + #define LD(r, d, b) MEMd(ld, r, d, b) + #define LBZX(r, a, b) MEMx(lbzx, r, a, b) + #define LHZX(r, a, b) MEMx(lhzx, r, a, b) + #define LWZX(r, a, b) MEMx(lwzx, r, a, b) + #define LDX(r, a, b) MEMx(ldx, r, a, b) + + // store word (32-bit integer) + #define STW(r, d, b) MEMd(stw, r, d, b) + #define STWU(r, d, b) MEMd(stwu, r, d, b) + #define STWX(s, a, b) MEMx(stwx, s, a, b) + #define STWUX(s, a, b) MEMux(stwux, s, a, b) + + // store byte + #define STB(r, d, b) MEMd(stb, r, d, b) + #define STBX(s, a, b) MEMx(stbx, s, a, b) + + // store double (64-bit float) + #define STD(r, d, b) MEMd(std, r, d, b) + #define STDU(r, d, b) MEMd(stdu, r, d, b) + #define STDX(s, a, b) MEMx(stdx, s, a, b) + #define STDUX(s, a, b) MEMux(stdux, s, a, b) + +#ifdef NANOJIT_64BIT + #define LP(r, d, b) LD(r, d, b) + #define STP(r, d, b) STD(r, d, b) + #define STPU(r, d, b) STDU(r, d, b) + #define STPX(s, a, b) STDX(s, a, b) + #define STPUX(s, a, b) STDUX(s, a, b) +#else + #define LP(r, d, b) LWZ(r, d, b) + #define STP(r, d, b) STW(r, d, b) + #define STPU(r, d, b) STWU(r, d, b) + #define STPX(s, a, b) STWX(s, a, b) + #define STPUX(s, a, b) STWUX(s, a, b) +#endif + + #define LFD(r, d, b) FMEMd(lfd, r, d, b) + #define LFDX(r, a, b) FMEMx(lfdx, r, a, b) + #define STFD(r, d, b) FMEMd(stfd, r, d, b) + #define STFDX(s, a, b) FMEMx(stfdx, s, a, b) + + #define ALUI(op,rd,ra,d) EMIT1(PPC_##op | GPR(rd)<<21 | GPR(ra)<<16 | uint16_t(d),\ + "%s %s,%s,%d (0x%x)", #op, gpn(rd), gpn(ra), int16_t(d), int16_t(d)) + + #define ADDI(rd,ra,d) ALUI(addi, rd, ra, d) + #define ADDIS(rd,ra,d) ALUI(addis, rd, ra, d) + + // bitwise operators have different src/dest registers + #define BITALUI(op,rd,ra,d) EMIT1(PPC_##op | GPR(ra)<<21 | GPR(rd)<<16 | uint16_t(d),\ + "%s %s,%s,%u (0x%x)", #op, gpn(rd), gpn(ra), uint16_t(d), uint16_t(d)) + + #define ANDI(rd,ra,d) BITALUI(andi, rd, ra, d) + #define ORI(rd,ra,d) BITALUI(ori, rd, ra, d) + #define ORIS(rd,ra,d) BITALUI(oris, rd, ra, d) + #define XORI(rd,ra,d) BITALUI(xori, rd, ra, d) + #define XORIS(rd,ra,d) BITALUI(xoris, rd, ra, d) + + #define SUBI(rd,ra,d) EMIT1(PPC_addi | GPR(rd)<<21 | GPR(ra)<<16 | uint16_t(-(d)),\ + "subi %s,%s,%d", gpn(rd), gpn(ra), (d)) + + #define LI(rd,v) EMIT1(PPC_addi | GPR(rd)<<21 | uint16_t(v),\ + "li %s,%d (0x%x)", gpn(rd), int16_t(v), int16_t(v)) /* addi rd,0,v */ + + #define LIS(rd,v) EMIT1(PPC_addis | GPR(rd)<<21 | uint16_t(v),\ + "lis %s,%d (0x%x)", gpn(rd), int16_t(v), int16_t(v)<<16) /* addis, rd,0,v */ + + #define MTCR(rs) /* mtcrf 0xff,rs */ + #define MFCR(rd) EMIT1(PPC_mfcr | GPR(rd)<<21, "mfcr %s", gpn(rd)) + + #define CMPx(op, crfd, ra, rb, l) EMIT1(PPC_##op | (crfd)<<23 | (l)<<21 | GPR(ra)<<16 | GPR(rb)<<11,\ + "%s%c cr%d,%s,%s", #op, (l)?'d':'w', (crfd), gpn(ra), gpn(rb)) + + #define CMPW(cr, ra, rb) CMPx(cmp, cr, ra, rb, 0) + #define CMPLW(cr, ra, rb) CMPx(cmpl, cr, ra, rb, 0) + #define CMPD(cr, ra, rb) CMPx(cmp, cr, ra, rb, 1) + #define CMPLD(cr, ra, rb) CMPx(cmpl, cr, ra, rb, 1) + + #define CMPxI(cr, ra, simm, l) EMIT1(PPC_cmpi | (cr)<<23 | (l)<<21 | GPR(ra)<<16 | uint16_t(simm),\ + "cmp%ci cr%d,%s,%d (0x%x)", (l)?'d':'w', (cr), gpn(ra), int16_t(simm), int16_t(simm)) + + #define CMPWI(cr, ra, simm) CMPxI(cr, ra, simm, 0) + #define CMPDI(cr, ra, simm) CMPxI(cr, ra, simm, 1) + + #define CMPLxI(cr, ra, uimm, l) EMIT1(PPC_cmpli | (cr)<<23 | (l)<<21 | GPR(ra)<<16 | uint16_t(uimm),\ + "cmp%ci cr%d,%s,%d (0x%x)", (l)?'d':'w', (cr), gpn(ra), uint16_t(uimm), uint16_t(uimm)) + + #define CMPLWI(cr, ra, uimm) CMPLxI(cr, ra, uimm, 0) + #define CMPLDI(cr, ra, uimm) CMPLxI(cr, ra, uimm, 1) + + #define FCMPx(op, crfd, ra, rb) EMIT1(PPC_##op | (crfd)<<23 | FPR(ra)<<16 | FPR(rb)<<11,\ + "%s cr%d,%s,%s", #op, (crfd), gpn(ra), gpn(rb)) + + #define FCMPU(cr, ra, rb) FCMPx(fcmpu, cr, ra, rb) + + #define CROR(cr,d,a,b) EMIT1(PPC_cror | (4*(cr)+COND_##d)<<21 | (4*(cr)+COND_##a)<<16 | (4*(cr)+COND_##b)<<11,\ + "cror %d,%d,%d", 4*(cr)+COND_##d, 4*(cr)+COND_##a, 4*(cr)+COND_##b) + + #define RLWINM(rd,rs,sh,mb,me) EMIT1(PPC_rlwinm | GPR(rs)<<21 | GPR(rd)<<16 | (sh)<<11 | (mb)<<6 | (me)<<1,\ + "rlwinm %s,%s,%d,%d,%d", gpn(rd), gpn(rs), (sh), (mb), (me)) + + #define LO5(sh) ((sh) & 31) + #define BIT6(sh) (((sh) >> 5) & 1) + #define SPLITMB(mb) (LO5(mb)<<1 | BIT6(mb)) + + #define RLDICL(rd,rs,sh,mb) \ + EMIT1(PPC_rldicl | GPR(rs)<<21 | GPR(rd)<<16 | LO5(sh)<<11 | SPLITMB(mb)<<5 | BIT6(sh)<<1,\ + "rldicl %s,%s,%d,%d", gpn(rd), gpn(rs), (sh), (mb)) + + // clrldi d,s,n => rldicl d,s,0,n + #define CLRLDI(rd,rs,n) \ + EMIT1(PPC_rldicl | GPR(rs)<<21 | GPR(rd)<<16 | SPLITMB(n)<<5,\ + "clrldi %s,%s,%d", gpn(rd), gpn(rs), (n)) + + #define RLDIMI(rd,rs,sh,mb) \ + EMIT1(PPC_rldimi | GPR(rs)<<21 | GPR(rd)<<16 | LO5(sh)<<11 | SPLITMB(mb)<<5 | BIT6(sh)<<1,\ + "rldimi %s,%s,%d,%d", gpn(rd), gpn(rs), (sh), (mb)) + + // insrdi rD,rS,n,b => rldimi rD,rS,64-(b+n),b: insert n bit value into rD starting at b + #define INSRDI(rd,rs,n,b) \ + EMIT1(PPC_rldimi | GPR(rs)<<21 | GPR(rd)<<16 | LO5(64-((b)+(n)))<<11 | SPLITMB(b)<<5 | BIT6(64-((b)+(n)))<<1,\ + "insrdi %s,%s,%d,%d", gpn(rd), gpn(rs), (n), (b)) + + #define EXTRWI(rd,rs,n,b) EMIT1(PPC_rlwinm | GPR(rs)<<21 | GPR(rd)<<16 | ((n)+(b))<<11 | (32-(n))<<6 | 31<<1,\ + "extrwi %s,%s,%d,%d", gpn(rd), gpn(rs), (n), (b)) + + // sldi rd,rs,n (n<64) => rldicr rd,rs,n,63-n + #define SLDI(rd,rs,n) EMIT1(PPC_rldicr | GPR(rs)<<21 | GPR(rd)<<16 | LO5(n)<<11 | SPLITMB(63-(n))<<5 | BIT6(n)<<1,\ + "sldi %s,%s,%d", gpn(rd), gpn(rs), (n)) + + #define SLWI(rd,rs,n) EMIT1(PPC_rlwinm | GPR(rs)<<21 | GPR(rd)<<16 | (n)<<11 | 0<<6 | (31-(n))<<1,\ + "slwi %s,%s,%d", gpn(rd), gpn(rs), (n)) + #define SRWI(rd,rs,n) EMIT1(PPC_rlwinm | GPR(rs)<<21 | GPR(rd)<<16 | (32-(n))<<11 | (n)<<6 | 31<<1,\ + "slwi %s,%s,%d", gpn(rd), gpn(rs), (n)) + #define SRAWI(rd,rs,n) EMIT1(PPC_srawi | GPR(rs)<<21 | GPR(rd)<<16 | (n)<<11,\ + "srawi %s,%s,%d", gpn(rd), gpn(rs), (n)) + +} // namespace nanojit + +#endif // __nanojit_NativePPC__ diff --git a/js/src/nanojit/NativeSH4-auto-generated.h b/js/src/nanojit/NativeSH4-auto-generated.h new file mode 100644 index 0000000..9e21b32 --- /dev/null +++ b/js/src/nanojit/NativeSH4-auto-generated.h @@ -0,0 +1,1726 @@ +/* THIS FILE IS AUTO-GENERATED */ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * STMicroelectronics. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Cédric VINCENT for STMicroelectronics + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#define SH4_CHECK_RANGE_add_imm(imm) ((imm) >= -128 && (imm) <= 127) + +#define FITS_SH4_add_imm(imm) (SH4_CHECK_RANGE_add_imm(imm)) + + inline void Assembler::SH4_add_imm(int imm, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && SH4_CHECK_RANGE_add_imm(imm)); + SH4_emit16((0x7 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((imm & 0xFF) << 0)); + asm_output("add_imm %d, R%d", imm, Rx.n); + } + + inline void Assembler::SH4_add(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x3 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xC << 0)); + asm_output("add R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_addc(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x3 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xE << 0)); + asm_output("addc R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_addv(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x3 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xF << 0)); + asm_output("addv R%d, R%d", Ry.n, Rx.n); + } + +#define SH4_CHECK_RANGE_and_imm_R0(imm) ((imm) >= 0 && (imm) <= 255) + +#define FITS_SH4_and_imm_R0(imm) (SH4_CHECK_RANGE_and_imm_R0(imm)) + + inline void Assembler::SH4_and_imm_R0(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_and_imm_R0(imm)); + SH4_emit16((0xC << 12) | (0x9 << 8) | ((imm & 0xFF) << 0)); + asm_output("and_imm_R0 %d", imm); + } + + inline void Assembler::SH4_and(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x9 << 0)); + asm_output("and R%d, R%d", Ry.n, Rx.n); + } + +#define SH4_CHECK_RANGE_andb_imm_dispR0GBR(imm) ((imm) >= 0 && (imm) <= 255) + +#define FITS_SH4_andb_imm_dispR0GBR(imm) (SH4_CHECK_RANGE_andb_imm_dispR0GBR(imm)) + + inline void Assembler::SH4_andb_imm_dispR0GBR(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_andb_imm_dispR0GBR(imm)); + SH4_emit16((0xC << 12) | (0xD << 8) | ((imm & 0xFF) << 0)); + asm_output("andb_imm_dispR0GBR %d", imm); + } + +#define SH4_CHECK_RANGE_bra(imm) ((imm) >= -4096 && (imm) <= 4094) + +#define SH4_CHECK_ALIGN_bra(imm) (((imm) & 0x1) == 0) + +#define FITS_SH4_bra(imm) (SH4_CHECK_RANGE_bra((imm) + 2) && SH4_CHECK_ALIGN_bra((imm) + 2)) + + inline void Assembler::SH4_bra(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_bra(imm + 2) && SH4_CHECK_ALIGN_bra(imm + 2)); + SH4_emit16((0xA << 12) | (((imm & 0x1FFE) >> 1) << 0)); + asm_output("bra %d", imm); + } + +#define SH4_CHECK_RANGE_bsr(imm) ((imm) >= -4096 && (imm) <= 4094) + +#define SH4_CHECK_ALIGN_bsr(imm) (((imm) & 0x1) == 0) + +#define FITS_SH4_bsr(imm) (SH4_CHECK_RANGE_bsr((imm) + 2) && SH4_CHECK_ALIGN_bsr((imm) + 2)) + + inline void Assembler::SH4_bsr(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_bsr(imm + 2) && SH4_CHECK_ALIGN_bsr(imm + 2)); + SH4_emit16((0xB << 12) | (((imm & 0x1FFE) >> 1) << 0)); + asm_output("bsr %d", imm); + } + +#define SH4_CHECK_RANGE_bt(imm) ((imm) >= -256 && (imm) <= 254) + +#define SH4_CHECK_ALIGN_bt(imm) (((imm) & 0x1) == 0) + +#define FITS_SH4_bt(imm) (SH4_CHECK_RANGE_bt((imm) + 2) && SH4_CHECK_ALIGN_bt((imm) + 2)) + + inline void Assembler::SH4_bt(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_bt(imm + 2) && SH4_CHECK_ALIGN_bt(imm + 2)); + SH4_emit16((0x8 << 12) | (0x9 << 8) | (((imm & 0x1FE) >> 1) << 0)); + asm_output("bt %d", imm); + } + +#define SH4_CHECK_RANGE_bf(imm) ((imm) >= -256 && (imm) <= 254) + +#define SH4_CHECK_ALIGN_bf(imm) (((imm) & 0x1) == 0) + +#define FITS_SH4_bf(imm) (SH4_CHECK_RANGE_bf((imm) + 2) && SH4_CHECK_ALIGN_bf((imm) + 2)) + + inline void Assembler::SH4_bf(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_bf(imm + 2) && SH4_CHECK_ALIGN_bf(imm + 2)); + SH4_emit16((0x8 << 12) | (0xB << 8) | (((imm & 0x1FE) >> 1) << 0)); + asm_output("bf %d", imm); + } + +#define SH4_CHECK_RANGE_bts(imm) ((imm) >= -256 && (imm) <= 254) + +#define SH4_CHECK_ALIGN_bts(imm) (((imm) & 0x1) == 0) + +#define FITS_SH4_bts(imm) (SH4_CHECK_RANGE_bts((imm) + 2) && SH4_CHECK_ALIGN_bts((imm) + 2)) + + inline void Assembler::SH4_bts(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_bts(imm + 2) && SH4_CHECK_ALIGN_bts(imm + 2)); + SH4_emit16((0x8 << 12) | (0xD << 8) | (((imm & 0x1FE) >> 1) << 0)); + asm_output("bts %d", imm); + } + +#define SH4_CHECK_RANGE_bfs(imm) ((imm) >= -256 && (imm) <= 254) + +#define SH4_CHECK_ALIGN_bfs(imm) (((imm) & 0x1) == 0) + +#define FITS_SH4_bfs(imm) (SH4_CHECK_RANGE_bfs((imm) + 2) && SH4_CHECK_ALIGN_bfs((imm) + 2)) + + inline void Assembler::SH4_bfs(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_bfs(imm + 2) && SH4_CHECK_ALIGN_bfs(imm + 2)); + SH4_emit16((0x8 << 12) | (0xF << 8) | (((imm & 0x1FE) >> 1) << 0)); + asm_output("bfs %d", imm); + } + + inline void Assembler::SH4_clrmac() { + NanoAssert(1); + SH4_emit16((0x0 << 12) | (0x0 << 8) | (0x2 << 4) | (0x8 << 0)); + asm_output("clrmac"); + } + + inline void Assembler::SH4_clrs() { + NanoAssert(1); + SH4_emit16((0x0 << 12) | (0x0 << 8) | (0x4 << 4) | (0x8 << 0)); + asm_output("clrs"); + } + + inline void Assembler::SH4_clrt() { + NanoAssert(1); + SH4_emit16((0x0 << 12) | (0x0 << 8) | (0x0 << 4) | (0x8 << 0)); + asm_output("clrt"); + } + +#define SH4_CHECK_RANGE_cmpeq_imm_R0(imm) ((imm) >= -128 && (imm) <= 127) + +#define FITS_SH4_cmpeq_imm_R0(imm) (SH4_CHECK_RANGE_cmpeq_imm_R0(imm)) + + inline void Assembler::SH4_cmpeq_imm_R0(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_cmpeq_imm_R0(imm)); + SH4_emit16((0x8 << 12) | (0x8 << 8) | ((imm & 0xFF) << 0)); + asm_output("cmpeq_imm_R0 %d", imm); + } + + inline void Assembler::SH4_cmpeq(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x3 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x0 << 0)); + asm_output("cmpeq R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_cmpge(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x3 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x3 << 0)); + asm_output("cmpge R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_cmpgt(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x3 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x7 << 0)); + asm_output("cmpgt R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_cmphi(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x3 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x6 << 0)); + asm_output("cmphi R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_cmphs(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x3 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x2 << 0)); + asm_output("cmphs R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_cmppl(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x1 << 4) | (0x5 << 0)); + asm_output("cmppl R%d", Rx.n); + } + + inline void Assembler::SH4_cmppz(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x1 << 4) | (0x1 << 0)); + asm_output("cmppz R%d", Rx.n); + } + + inline void Assembler::SH4_cmpstr(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xC << 0)); + asm_output("cmpstr R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_div0s(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x7 << 0)); + asm_output("div0s R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_div0u() { + NanoAssert(1); + SH4_emit16((0x0 << 12) | (0x0 << 8) | (0x1 << 4) | (0x9 << 0)); + asm_output("div0u"); + } + + inline void Assembler::SH4_div1(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x3 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x4 << 0)); + asm_output("div1 R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_extsb(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xE << 0)); + asm_output("extsb R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_extsw(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xF << 0)); + asm_output("extsw R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_extub(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xC << 0)); + asm_output("extub R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_extuw(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xD << 0)); + asm_output("extuw R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_icbi_indRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0xE << 4) | (0x3 << 0)); + asm_output("icbi_indRx R%d", Rx.n); + } + + inline void Assembler::SH4_jmp_indRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0xB << 0)); + asm_output("jmp_indRx R%d", Rx.n); + } + + inline void Assembler::SH4_jsr_indRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0xB << 0)); + asm_output("jsr_indRx R%d", Rx.n); + } + + inline void Assembler::SH4_ldc_SR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0xE << 0)); + asm_output("ldc_SR R%d", Rx.n); + } + + inline void Assembler::SH4_ldc_GBR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x1 << 4) | (0xE << 0)); + asm_output("ldc_GBR R%d", Rx.n); + } + + inline void Assembler::SH4_ldc_SGR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x3 << 4) | (0xA << 0)); + asm_output("ldc_SGR R%d", Rx.n); + } + + inline void Assembler::SH4_ldc_VBR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0xE << 0)); + asm_output("ldc_VBR R%d", Rx.n); + } + + inline void Assembler::SH4_ldc_SSR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x3 << 4) | (0xE << 0)); + asm_output("ldc_SSR R%d", Rx.n); + } + + inline void Assembler::SH4_ldc_SPC(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x4 << 4) | (0xE << 0)); + asm_output("ldc_SPC R%d", Rx.n); + } + + inline void Assembler::SH4_ldc_DBR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0xF << 4) | (0xA << 0)); + asm_output("ldc_DBR R%d", Rx.n); + } + +#define SH4_CHECK_RANGE_ldc_bank(imm) ((imm) >= 0 && (imm) <= 7) + +#define FITS_SH4_ldc_bank(imm) (SH4_CHECK_RANGE_ldc_bank(imm)) + + inline void Assembler::SH4_ldc_bank(Register Rx, int imm) { + NanoAssert(1 && REGNUM(Rx) <= 15 && SH4_CHECK_RANGE_ldc_bank(imm)); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((imm & 0x7) << 4) | (0xE << 0)); + asm_output("ldc_bank R%d, %d", Rx.n, imm); + } + + inline void Assembler::SH4_ldcl_incRx_SR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0x7 << 0)); + asm_output("ldcl_incRx_SR R%d", Rx.n); + } + + inline void Assembler::SH4_ldcl_incRx_GBR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x1 << 4) | (0x7 << 0)); + asm_output("ldcl_incRx_GBR R%d", Rx.n); + } + + inline void Assembler::SH4_ldcl_incRx_VBR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0x7 << 0)); + asm_output("ldcl_incRx_VBR R%d", Rx.n); + } + + inline void Assembler::SH4_ldcl_incRx_SGR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x3 << 4) | (0x6 << 0)); + asm_output("ldcl_incRx_SGR R%d", Rx.n); + } + + inline void Assembler::SH4_ldcl_incRx_SSR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x3 << 4) | (0x7 << 0)); + asm_output("ldcl_incRx_SSR R%d", Rx.n); + } + + inline void Assembler::SH4_ldcl_incRx_SPC(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x4 << 4) | (0x7 << 0)); + asm_output("ldcl_incRx_SPC R%d", Rx.n); + } + + inline void Assembler::SH4_ldcl_incRx_DBR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0xF << 4) | (0x6 << 0)); + asm_output("ldcl_incRx_DBR R%d", Rx.n); + } + +#define SH4_CHECK_RANGE_ldcl_incRx_bank(imm) ((imm) >= 0 && (imm) <= 7) + +#define FITS_SH4_ldcl_incRx_bank(imm) (SH4_CHECK_RANGE_ldcl_incRx_bank(imm)) + + inline void Assembler::SH4_ldcl_incRx_bank(Register Rx, int imm) { + NanoAssert(1 && REGNUM(Rx) <= 15 && SH4_CHECK_RANGE_ldcl_incRx_bank(imm)); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((imm & 0x7) << 4) | (0x7 << 0)); + asm_output("ldcl_incRx_bank R%d, %d", Rx.n, imm); + } + + inline void Assembler::SH4_lds_MACH(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0xA << 0)); + asm_output("lds_MACH R%d", Rx.n); + } + + inline void Assembler::SH4_lds_MACL(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x1 << 4) | (0xA << 0)); + asm_output("lds_MACL R%d", Rx.n); + } + + inline void Assembler::SH4_lds_PR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0xA << 0)); + asm_output("lds_PR R%d", Rx.n); + } + + inline void Assembler::SH4_lds_FPUL(Register Ry) { + NanoAssert(1 && REGNUM(Ry) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Ry) & 0xF) << 8) | (0x5 << 4) | (0xA << 0)); + asm_output("lds_FPUL R%d", Ry.n); + } + + inline void Assembler::SH4_lds_FPSCR(Register Ry) { + NanoAssert(1 && REGNUM(Ry) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Ry) & 0xF) << 8) | (0x6 << 4) | (0xA << 0)); + asm_output("lds_FPSCR R%d", Ry.n); + } + + inline void Assembler::SH4_ldsl_incRx_MACH(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0x6 << 0)); + asm_output("ldsl_incRx_MACH R%d", Rx.n); + } + + inline void Assembler::SH4_ldsl_incRx_MACL(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x1 << 4) | (0x6 << 0)); + asm_output("ldsl_incRx_MACL R%d", Rx.n); + } + + inline void Assembler::SH4_ldsl_incRx_PR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0x6 << 0)); + asm_output("ldsl_incRx_PR R%d", Rx.n); + } + + inline void Assembler::SH4_ldsl_incRy_FPUL(Register Ry) { + NanoAssert(1 && REGNUM(Ry) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Ry) & 0xF) << 8) | (0x5 << 4) | (0x6 << 0)); + asm_output("ldsl_incRy_FPUL R%d", Ry.n); + } + + inline void Assembler::SH4_ldsl_incRy_FPSCR(Register Ry) { + NanoAssert(1 && REGNUM(Ry) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Ry) & 0xF) << 8) | (0x6 << 4) | (0x6 << 0)); + asm_output("ldsl_incRy_FPSCR R%d", Ry.n); + } + + inline void Assembler::SH4_ldtlb() { + NanoAssert(1); + SH4_emit16((0x0 << 12) | (0x0 << 8) | (0x3 << 4) | (0x8 << 0)); + asm_output("ldtlb"); + } + + inline void Assembler::SH4_macw_incRy_incRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xF << 0)); + asm_output("macw_incRy_incRx R%d, R%d", Ry.n, Rx.n); + } + +#define SH4_CHECK_RANGE_mov_imm(imm) ((imm) >= -128 && (imm) <= 127) + +#define FITS_SH4_mov_imm(imm) (SH4_CHECK_RANGE_mov_imm(imm)) + + inline void Assembler::SH4_mov_imm(int imm, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && SH4_CHECK_RANGE_mov_imm(imm)); + SH4_emit16((0xE << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((imm & 0xFF) << 0)); + asm_output("mov_imm %d, R%d", imm, Rx.n); + } + + inline void Assembler::SH4_mov(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x3 << 0)); + asm_output("mov R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_movb_dispR0Rx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x4 << 0)); + asm_output("movb_dispR0Rx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_movb_decRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x4 << 0)); + asm_output("movb_decRx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_movb_indRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x0 << 0)); + asm_output("movb_indRx R%d, R%d", Ry.n, Rx.n); + } + +#define SH4_CHECK_RANGE_movb_dispRy_R0(imm) ((imm) >= 0 && (imm) <= 15) + +#define FITS_SH4_movb_dispRy_R0(imm) (SH4_CHECK_RANGE_movb_dispRy_R0(imm)) + + inline void Assembler::SH4_movb_dispRy_R0(int imm, Register Ry) { + NanoAssert(1 && REGNUM(Ry) <= 15 && SH4_CHECK_RANGE_movb_dispRy_R0(imm)); + SH4_emit16((0x8 << 12) | (0x4 << 8) | ((REGNUM(Ry) & 0xF) << 4) | ((imm & 0xF) << 0)); + asm_output("movb_dispRy_R0 %d, R%d", imm, Ry.n); + } + +#define SH4_CHECK_RANGE_movb_dispGBR_R0(imm) ((imm) >= 0 && (imm) <= 255) + +#define FITS_SH4_movb_dispGBR_R0(imm) (SH4_CHECK_RANGE_movb_dispGBR_R0(imm)) + + inline void Assembler::SH4_movb_dispGBR_R0(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_movb_dispGBR_R0(imm)); + SH4_emit16((0xC << 12) | (0x4 << 8) | ((imm & 0xFF) << 0)); + asm_output("movb_dispGBR_R0 %d", imm); + } + + inline void Assembler::SH4_movb_dispR0Ry(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xC << 0)); + asm_output("movb_dispR0Ry R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_movb_incRy(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x4 << 0)); + asm_output("movb_incRy R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_movb_indRy(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x0 << 0)); + asm_output("movb_indRy R%d, R%d", Ry.n, Rx.n); + } + +#define SH4_CHECK_RANGE_movb_R0_dispRx(imm) ((imm) >= 0 && (imm) <= 15) + +#define FITS_SH4_movb_R0_dispRx(imm) (SH4_CHECK_RANGE_movb_R0_dispRx(imm)) + + inline void Assembler::SH4_movb_R0_dispRx(int imm, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && SH4_CHECK_RANGE_movb_R0_dispRx(imm)); + SH4_emit16((0x8 << 12) | (0x0 << 8) | ((REGNUM(Rx) & 0xF) << 4) | ((imm & 0xF) << 0)); + asm_output("movb_R0_dispRx %d, R%d", imm, Rx.n); + } + +#define SH4_CHECK_RANGE_movb_R0_dispGBR(imm) ((imm) >= 0 && (imm) <= 255) + +#define FITS_SH4_movb_R0_dispGBR(imm) (SH4_CHECK_RANGE_movb_R0_dispGBR(imm)) + + inline void Assembler::SH4_movb_R0_dispGBR(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_movb_R0_dispGBR(imm)); + SH4_emit16((0xC << 12) | (0x0 << 8) | ((imm & 0xFF) << 0)); + asm_output("movb_R0_dispGBR %d", imm); + } + +#define SH4_CHECK_RANGE_movl_dispRx(imm) ((imm) >= 0 && (imm) <= 60) + +#define SH4_CHECK_ALIGN_movl_dispRx(imm) (((imm) & 0x3) == 0) + +#define FITS_SH4_movl_dispRx(imm) (SH4_CHECK_RANGE_movl_dispRx(imm) && SH4_CHECK_ALIGN_movl_dispRx(imm)) + + inline void Assembler::SH4_movl_dispRx(Register Ry, int imm, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15 && SH4_CHECK_RANGE_movl_dispRx(imm) && SH4_CHECK_ALIGN_movl_dispRx(imm)); + SH4_emit16((0x1 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (((imm & 0x3C) >> 2) << 0)); + asm_output("movl_dispRx R%d, %d, R%d", Ry.n, imm, Rx.n); + } + + inline void Assembler::SH4_movl_dispR0Rx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x6 << 0)); + asm_output("movl_dispR0Rx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_movl_decRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x6 << 0)); + asm_output("movl_decRx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_movl_indRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x2 << 0)); + asm_output("movl_indRx R%d, R%d", Ry.n, Rx.n); + } + +#define SH4_CHECK_RANGE_movl_dispRy(imm) ((imm) >= 0 && (imm) <= 60) + +#define SH4_CHECK_ALIGN_movl_dispRy(imm) (((imm) & 0x3) == 0) + +#define FITS_SH4_movl_dispRy(imm) (SH4_CHECK_RANGE_movl_dispRy(imm) && SH4_CHECK_ALIGN_movl_dispRy(imm)) + + inline void Assembler::SH4_movl_dispRy(int imm, Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15 && SH4_CHECK_RANGE_movl_dispRy(imm) && SH4_CHECK_ALIGN_movl_dispRy(imm)); + SH4_emit16((0x5 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (((imm & 0x3C) >> 2) << 0)); + asm_output("movl_dispRy %d, R%d, R%d", imm, Ry.n, Rx.n); + } + +#define SH4_CHECK_RANGE_movl_dispGBR_R0(imm) ((imm) >= 0 && (imm) <= 1020) + +#define SH4_CHECK_ALIGN_movl_dispGBR_R0(imm) (((imm) & 0x3) == 0) + +#define FITS_SH4_movl_dispGBR_R0(imm) (SH4_CHECK_RANGE_movl_dispGBR_R0(imm) && SH4_CHECK_ALIGN_movl_dispGBR_R0(imm)) + + inline void Assembler::SH4_movl_dispGBR_R0(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_movl_dispGBR_R0(imm) && SH4_CHECK_ALIGN_movl_dispGBR_R0(imm)); + SH4_emit16((0xC << 12) | (0x6 << 8) | (((imm & 0x3FC) >> 2) << 0)); + asm_output("movl_dispGBR_R0 %d", imm); + } + +#define SH4_CHECK_RANGE_movl_dispPC(imm) ((imm) >= 0 && (imm) <= 1020) + +#define SH4_CHECK_ALIGN_movl_dispPC(imm) (((imm) & 0x3) == 0) + +#define FITS_SH4_movl_dispPC(imm) (SH4_CHECK_RANGE_movl_dispPC(imm) && SH4_CHECK_ALIGN_movl_dispPC(imm)) + + inline void Assembler::SH4_movl_dispPC(int imm, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && SH4_CHECK_RANGE_movl_dispPC(imm) && SH4_CHECK_ALIGN_movl_dispPC(imm)); + SH4_emit16((0xD << 12) | ((REGNUM(Rx) & 0xF) << 8) | (((imm & 0x3FC) >> 2) << 0)); + asm_output("movl_dispPC %d, R%d", imm, Rx.n); + } + + inline void Assembler::SH4_movl_dispR0Ry(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xE << 0)); + asm_output("movl_dispR0Ry R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_movl_incRy(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x6 << 0)); + asm_output("movl_incRy R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_movl_indRy(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x2 << 0)); + asm_output("movl_indRy R%d, R%d", Ry.n, Rx.n); + } + +#define SH4_CHECK_RANGE_movl_R0_dispGBR(imm) ((imm) >= 0 && (imm) <= 1020) + +#define SH4_CHECK_ALIGN_movl_R0_dispGBR(imm) (((imm) & 0x3) == 0) + +#define FITS_SH4_movl_R0_dispGBR(imm) (SH4_CHECK_RANGE_movl_R0_dispGBR(imm) && SH4_CHECK_ALIGN_movl_R0_dispGBR(imm)) + + inline void Assembler::SH4_movl_R0_dispGBR(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_movl_R0_dispGBR(imm) && SH4_CHECK_ALIGN_movl_R0_dispGBR(imm)); + SH4_emit16((0xC << 12) | (0x2 << 8) | (((imm & 0x3FC) >> 2) << 0)); + asm_output("movl_R0_dispGBR %d", imm); + } + + inline void Assembler::SH4_movw_dispR0Rx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x5 << 0)); + asm_output("movw_dispR0Rx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_movw_decRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x5 << 0)); + asm_output("movw_decRx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_movw_indRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x1 << 0)); + asm_output("movw_indRx R%d, R%d", Ry.n, Rx.n); + } + +#define SH4_CHECK_RANGE_movw_dispRy_R0(imm) ((imm) >= 0 && (imm) <= 30) + +#define SH4_CHECK_ALIGN_movw_dispRy_R0(imm) (((imm) & 0x1) == 0) + +#define FITS_SH4_movw_dispRy_R0(imm) (SH4_CHECK_RANGE_movw_dispRy_R0(imm) && SH4_CHECK_ALIGN_movw_dispRy_R0(imm)) + + inline void Assembler::SH4_movw_dispRy_R0(int imm, Register Ry) { + NanoAssert(1 && REGNUM(Ry) <= 15 && SH4_CHECK_RANGE_movw_dispRy_R0(imm) && SH4_CHECK_ALIGN_movw_dispRy_R0(imm)); + SH4_emit16((0x8 << 12) | (0x5 << 8) | ((REGNUM(Ry) & 0xF) << 4) | (((imm & 0x1E) >> 1) << 0)); + asm_output("movw_dispRy_R0 %d, R%d", imm, Ry.n); + } + +#define SH4_CHECK_RANGE_movw_dispGBR_R0(imm) ((imm) >= 0 && (imm) <= 510) + +#define SH4_CHECK_ALIGN_movw_dispGBR_R0(imm) (((imm) & 0x1) == 0) + +#define FITS_SH4_movw_dispGBR_R0(imm) (SH4_CHECK_RANGE_movw_dispGBR_R0(imm) && SH4_CHECK_ALIGN_movw_dispGBR_R0(imm)) + + inline void Assembler::SH4_movw_dispGBR_R0(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_movw_dispGBR_R0(imm) && SH4_CHECK_ALIGN_movw_dispGBR_R0(imm)); + SH4_emit16((0xC << 12) | (0x5 << 8) | (((imm & 0x1FE) >> 1) << 0)); + asm_output("movw_dispGBR_R0 %d", imm); + } + +#define SH4_CHECK_RANGE_movw_dispPC(imm) ((imm) >= 0 && (imm) <= 510) + +#define SH4_CHECK_ALIGN_movw_dispPC(imm) (((imm) & 0x1) == 0) + +#define FITS_SH4_movw_dispPC(imm) (SH4_CHECK_RANGE_movw_dispPC(imm) && SH4_CHECK_ALIGN_movw_dispPC(imm)) + + inline void Assembler::SH4_movw_dispPC(int imm, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && SH4_CHECK_RANGE_movw_dispPC(imm) && SH4_CHECK_ALIGN_movw_dispPC(imm)); + SH4_emit16((0x9 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (((imm & 0x1FE) >> 1) << 0)); + asm_output("movw_dispPC %d, R%d", imm, Rx.n); + } + + inline void Assembler::SH4_movw_dispR0Ry(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xD << 0)); + asm_output("movw_dispR0Ry R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_movw_incRy(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x5 << 0)); + asm_output("movw_incRy R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_movw_indRy(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x1 << 0)); + asm_output("movw_indRy R%d, R%d", Ry.n, Rx.n); + } + +#define SH4_CHECK_RANGE_movw_R0_dispRx(imm) ((imm) >= 0 && (imm) <= 30) + +#define SH4_CHECK_ALIGN_movw_R0_dispRx(imm) (((imm) & 0x1) == 0) + +#define FITS_SH4_movw_R0_dispRx(imm) (SH4_CHECK_RANGE_movw_R0_dispRx(imm) && SH4_CHECK_ALIGN_movw_R0_dispRx(imm)) + + inline void Assembler::SH4_movw_R0_dispRx(int imm, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && SH4_CHECK_RANGE_movw_R0_dispRx(imm) && SH4_CHECK_ALIGN_movw_R0_dispRx(imm)); + SH4_emit16((0x8 << 12) | (0x1 << 8) | ((REGNUM(Rx) & 0xF) << 4) | (((imm & 0x1E) >> 1) << 0)); + asm_output("movw_R0_dispRx %d, R%d", imm, Rx.n); + } + +#define SH4_CHECK_RANGE_movw_R0_dispGBR(imm) ((imm) >= 0 && (imm) <= 510) + +#define SH4_CHECK_ALIGN_movw_R0_dispGBR(imm) (((imm) & 0x1) == 0) + +#define FITS_SH4_movw_R0_dispGBR(imm) (SH4_CHECK_RANGE_movw_R0_dispGBR(imm) && SH4_CHECK_ALIGN_movw_R0_dispGBR(imm)) + + inline void Assembler::SH4_movw_R0_dispGBR(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_movw_R0_dispGBR(imm) && SH4_CHECK_ALIGN_movw_R0_dispGBR(imm)); + SH4_emit16((0xC << 12) | (0x1 << 8) | (((imm & 0x1FE) >> 1) << 0)); + asm_output("movw_R0_dispGBR %d", imm); + } + +#define SH4_CHECK_RANGE_mova_dispPC_R0(imm) ((imm) >= 0 && (imm) <= 1020) + +#define SH4_CHECK_ALIGN_mova_dispPC_R0(imm) (((imm) & 0x3) == 0) + +#define FITS_SH4_mova_dispPC_R0(imm) (SH4_CHECK_RANGE_mova_dispPC_R0(imm) && SH4_CHECK_ALIGN_mova_dispPC_R0(imm)) + + inline void Assembler::SH4_mova_dispPC_R0(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_mova_dispPC_R0(imm) && SH4_CHECK_ALIGN_mova_dispPC_R0(imm)); + SH4_emit16((0xC << 12) | (0x7 << 8) | (((imm & 0x3FC) >> 2) << 0)); + asm_output("mova_dispPC_R0 %d", imm); + } + + inline void Assembler::SH4_movcal_R0_indRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0xC << 4) | (0x3 << 0)); + asm_output("movcal_R0_indRx R%d", Rx.n); + } + + inline void Assembler::SH4_movcol_R0_indRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x7 << 4) | (0x3 << 0)); + asm_output("movcol_R0_indRx R%d", Rx.n); + } + + inline void Assembler::SH4_movlil_indRy_R0(Register Ry) { + NanoAssert(1 && REGNUM(Ry) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Ry) & 0xF) << 8) | (0x6 << 4) | (0x3 << 0)); + asm_output("movlil_indRy_R0 R%d", Ry.n); + } + + inline void Assembler::SH4_movt(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0x9 << 0)); + asm_output("movt R%d", Rx.n); + } + + inline void Assembler::SH4_movual_indRy_R0(Register Ry) { + NanoAssert(1 && REGNUM(Ry) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Ry) & 0xF) << 8) | (0xA << 4) | (0x9 << 0)); + asm_output("movual_indRy_R0 R%d", Ry.n); + } + + inline void Assembler::SH4_movual_incRy_R0(Register Ry) { + NanoAssert(1 && REGNUM(Ry) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Ry) & 0xF) << 8) | (0xE << 4) | (0x9 << 0)); + asm_output("movual_incRy_R0 R%d", Ry.n); + } + + inline void Assembler::SH4_mulsw(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xF << 0)); + asm_output("mulsw R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_muls(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xF << 0)); + asm_output("muls R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_mull(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x7 << 0)); + asm_output("mull R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_muluw(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xE << 0)); + asm_output("muluw R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_mulu(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xE << 0)); + asm_output("mulu R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_neg(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xB << 0)); + asm_output("neg R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_negc(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xA << 0)); + asm_output("negc R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_nop() { + NanoAssert(1); + SH4_emit16((0x0 << 12) | (0x0 << 8) | (0x0 << 4) | (0x9 << 0)); + asm_output("nop"); + } + + inline void Assembler::SH4_not(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x7 << 0)); + asm_output("not R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_ocbi_indRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x9 << 4) | (0x3 << 0)); + asm_output("ocbi_indRx R%d", Rx.n); + } + + inline void Assembler::SH4_ocbp_indRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0xA << 4) | (0x3 << 0)); + asm_output("ocbp_indRx R%d", Rx.n); + } + + inline void Assembler::SH4_ocbwb_indRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0xB << 4) | (0x3 << 0)); + asm_output("ocbwb_indRx R%d", Rx.n); + } + +#define SH4_CHECK_RANGE_or_imm_R0(imm) ((imm) >= 0 && (imm) <= 255) + +#define FITS_SH4_or_imm_R0(imm) (SH4_CHECK_RANGE_or_imm_R0(imm)) + + inline void Assembler::SH4_or_imm_R0(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_or_imm_R0(imm)); + SH4_emit16((0xC << 12) | (0xB << 8) | ((imm & 0xFF) << 0)); + asm_output("or_imm_R0 %d", imm); + } + + inline void Assembler::SH4_or(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xB << 0)); + asm_output("or R%d, R%d", Ry.n, Rx.n); + } + +#define SH4_CHECK_RANGE_orb_imm_dispR0GBR(imm) ((imm) >= 0 && (imm) <= 255) + +#define FITS_SH4_orb_imm_dispR0GBR(imm) (SH4_CHECK_RANGE_orb_imm_dispR0GBR(imm)) + + inline void Assembler::SH4_orb_imm_dispR0GBR(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_orb_imm_dispR0GBR(imm)); + SH4_emit16((0xC << 12) | (0xF << 8) | ((imm & 0xFF) << 0)); + asm_output("orb_imm_dispR0GBR %d", imm); + } + + inline void Assembler::SH4_pref_indRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x8 << 4) | (0x3 << 0)); + asm_output("pref_indRx R%d", Rx.n); + } + + inline void Assembler::SH4_prefi_indRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0xD << 4) | (0x3 << 0)); + asm_output("prefi_indRx R%d", Rx.n); + } + + inline void Assembler::SH4_rotcl(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0x4 << 0)); + asm_output("rotcl R%d", Rx.n); + } + + inline void Assembler::SH4_rotcr(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0x5 << 0)); + asm_output("rotcr R%d", Rx.n); + } + + inline void Assembler::SH4_rotl(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0x4 << 0)); + asm_output("rotl R%d", Rx.n); + } + + inline void Assembler::SH4_rotr(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0x5 << 0)); + asm_output("rotr R%d", Rx.n); + } + + inline void Assembler::SH4_rte() { + NanoAssert(1); + SH4_emit16((0x0 << 12) | (0x0 << 8) | (0x2 << 4) | (0xB << 0)); + asm_output("rte"); + } + + inline void Assembler::SH4_rts() { + NanoAssert(1); + SH4_emit16((0x0 << 12) | (0x0 << 8) | (0x0 << 4) | (0xB << 0)); + asm_output("rts"); + } + + inline void Assembler::SH4_sets() { + NanoAssert(1); + SH4_emit16((0x0 << 12) | (0x0 << 8) | (0x5 << 4) | (0x8 << 0)); + asm_output("sets"); + } + + inline void Assembler::SH4_sett() { + NanoAssert(1); + SH4_emit16((0x0 << 12) | (0x0 << 8) | (0x1 << 4) | (0x8 << 0)); + asm_output("sett"); + } + + inline void Assembler::SH4_shad(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xC << 0)); + asm_output("shad R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_shld(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xD << 0)); + asm_output("shld R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_shal(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0x0 << 0)); + asm_output("shal R%d", Rx.n); + } + + inline void Assembler::SH4_shar(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0x1 << 0)); + asm_output("shar R%d", Rx.n); + } + + inline void Assembler::SH4_shll(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0x0 << 0)); + asm_output("shll R%d", Rx.n); + } + + inline void Assembler::SH4_shll16(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0x8 << 0)); + asm_output("shll16 R%d", Rx.n); + } + + inline void Assembler::SH4_shll2(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0x8 << 0)); + asm_output("shll2 R%d", Rx.n); + } + + inline void Assembler::SH4_shll8(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x1 << 4) | (0x8 << 0)); + asm_output("shll8 R%d", Rx.n); + } + + inline void Assembler::SH4_shlr(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0x1 << 0)); + asm_output("shlr R%d", Rx.n); + } + + inline void Assembler::SH4_shlr16(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0x9 << 0)); + asm_output("shlr16 R%d", Rx.n); + } + + inline void Assembler::SH4_shlr2(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0x9 << 0)); + asm_output("shlr2 R%d", Rx.n); + } + + inline void Assembler::SH4_shlr8(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x1 << 4) | (0x9 << 0)); + asm_output("shlr8 R%d", Rx.n); + } + + inline void Assembler::SH4_sleep() { + NanoAssert(1); + SH4_emit16((0x0 << 12) | (0x0 << 8) | (0x1 << 4) | (0xB << 0)); + asm_output("sleep"); + } + + inline void Assembler::SH4_stc_SR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0x2 << 0)); + asm_output("stc_SR R%d", Rx.n); + } + + inline void Assembler::SH4_stc_GBR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x1 << 4) | (0x2 << 0)); + asm_output("stc_GBR R%d", Rx.n); + } + + inline void Assembler::SH4_stc_VBR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0x2 << 0)); + asm_output("stc_VBR R%d", Rx.n); + } + + inline void Assembler::SH4_stc_SSR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x3 << 4) | (0x2 << 0)); + asm_output("stc_SSR R%d", Rx.n); + } + + inline void Assembler::SH4_stc_SPC(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x4 << 4) | (0x2 << 0)); + asm_output("stc_SPC R%d", Rx.n); + } + + inline void Assembler::SH4_stc_SGR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x3 << 4) | (0xA << 0)); + asm_output("stc_SGR R%d", Rx.n); + } + + inline void Assembler::SH4_stc_DBR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0xF << 4) | (0xA << 0)); + asm_output("stc_DBR R%d", Rx.n); + } + +#define SH4_CHECK_RANGE_stc_bank(imm) ((imm) >= 0 && (imm) <= 7) + +#define FITS_SH4_stc_bank(imm) (SH4_CHECK_RANGE_stc_bank(imm)) + + inline void Assembler::SH4_stc_bank(int imm, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && SH4_CHECK_RANGE_stc_bank(imm)); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((imm & 0x7) << 4) | (0x2 << 0)); + asm_output("stc_bank %d, R%d", imm, Rx.n); + } + + inline void Assembler::SH4_stcl_SR_decRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0x3 << 0)); + asm_output("stcl_SR_decRx R%d", Rx.n); + } + + inline void Assembler::SH4_stcl_VBR_decRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0x3 << 0)); + asm_output("stcl_VBR_decRx R%d", Rx.n); + } + + inline void Assembler::SH4_stcl_SSR_decRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x3 << 4) | (0x3 << 0)); + asm_output("stcl_SSR_decRx R%d", Rx.n); + } + + inline void Assembler::SH4_stcl_SPC_decRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x4 << 4) | (0x3 << 0)); + asm_output("stcl_SPC_decRx R%d", Rx.n); + } + + inline void Assembler::SH4_stcl_GBR_decRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x1 << 4) | (0x3 << 0)); + asm_output("stcl_GBR_decRx R%d", Rx.n); + } + + inline void Assembler::SH4_stcl_SGR_decRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x3 << 4) | (0x2 << 0)); + asm_output("stcl_SGR_decRx R%d", Rx.n); + } + + inline void Assembler::SH4_stcl_DBR_decRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0xF << 4) | (0x2 << 0)); + asm_output("stcl_DBR_decRx R%d", Rx.n); + } + +#define SH4_CHECK_RANGE_stcl_bank_decRx(imm) ((imm) >= 0 && (imm) <= 7) + +#define FITS_SH4_stcl_bank_decRx(imm) (SH4_CHECK_RANGE_stcl_bank_decRx(imm)) + + inline void Assembler::SH4_stcl_bank_decRx(int imm, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && SH4_CHECK_RANGE_stcl_bank_decRx(imm)); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((imm & 0x7) << 4) | (0x3 << 0)); + asm_output("stcl_bank_decRx %d, R%d", imm, Rx.n); + } + + inline void Assembler::SH4_sts_MACH(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0xA << 0)); + asm_output("sts_MACH R%d", Rx.n); + } + + inline void Assembler::SH4_sts_MACL(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x1 << 4) | (0xA << 0)); + asm_output("sts_MACL R%d", Rx.n); + } + + inline void Assembler::SH4_sts_PR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0xA << 0)); + asm_output("sts_PR R%d", Rx.n); + } + + inline void Assembler::SH4_sts_FPUL(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x5 << 4) | (0xA << 0)); + asm_output("sts_FPUL R%d", Rx.n); + } + + inline void Assembler::SH4_sts_FPSCR(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x6 << 4) | (0xA << 0)); + asm_output("sts_FPSCR R%d", Rx.n); + } + + inline void Assembler::SH4_stsl_MACH_decRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0x2 << 0)); + asm_output("stsl_MACH_decRx R%d", Rx.n); + } + + inline void Assembler::SH4_stsl_MACL_decRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x1 << 4) | (0x2 << 0)); + asm_output("stsl_MACL_decRx R%d", Rx.n); + } + + inline void Assembler::SH4_stsl_PR_decRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0x2 << 0)); + asm_output("stsl_PR_decRx R%d", Rx.n); + } + + inline void Assembler::SH4_stsl_FPUL_decRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x5 << 4) | (0x2 << 0)); + asm_output("stsl_FPUL_decRx R%d", Rx.n); + } + + inline void Assembler::SH4_stsl_FPSCR_decRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x6 << 4) | (0x2 << 0)); + asm_output("stsl_FPSCR_decRx R%d", Rx.n); + } + + inline void Assembler::SH4_sub(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x3 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x8 << 0)); + asm_output("sub R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_subc(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x3 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xA << 0)); + asm_output("subc R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_subv(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x3 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xB << 0)); + asm_output("subv R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_swapb(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x8 << 0)); + asm_output("swapb R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_swapw(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x6 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x9 << 0)); + asm_output("swapw R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_synco() { + NanoAssert(1); + SH4_emit16((0x0 << 12) | (0x0 << 8) | (0xA << 4) | (0xB << 0)); + asm_output("synco"); + } + + inline void Assembler::SH4_tasb_indRx(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x1 << 4) | (0xB << 0)); + asm_output("tasb_indRx R%d", Rx.n); + } + +#define SH4_CHECK_RANGE_trapa_imm(imm) ((imm) >= 0 && (imm) <= 255) + +#define FITS_SH4_trapa_imm(imm) (SH4_CHECK_RANGE_trapa_imm(imm)) + + inline void Assembler::SH4_trapa_imm(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_trapa_imm(imm)); + SH4_emit16((0xC << 12) | (0x3 << 8) | ((imm & 0xFF) << 0)); + asm_output("trapa_imm %d", imm); + } + +#define SH4_CHECK_RANGE_tst_imm_R0(imm) ((imm) >= 0 && (imm) <= 255) + +#define FITS_SH4_tst_imm_R0(imm) (SH4_CHECK_RANGE_tst_imm_R0(imm)) + + inline void Assembler::SH4_tst_imm_R0(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_tst_imm_R0(imm)); + SH4_emit16((0xC << 12) | (0x8 << 8) | ((imm & 0xFF) << 0)); + asm_output("tst_imm_R0 %d", imm); + } + + inline void Assembler::SH4_tst(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x8 << 0)); + asm_output("tst R%d, R%d", Ry.n, Rx.n); + } + +#define SH4_CHECK_RANGE_tstb_imm_dispR0GBR(imm) ((imm) >= 0 && (imm) <= 255) + +#define FITS_SH4_tstb_imm_dispR0GBR(imm) (SH4_CHECK_RANGE_tstb_imm_dispR0GBR(imm)) + + inline void Assembler::SH4_tstb_imm_dispR0GBR(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_tstb_imm_dispR0GBR(imm)); + SH4_emit16((0xC << 12) | (0xC << 8) | ((imm & 0xFF) << 0)); + asm_output("tstb_imm_dispR0GBR %d", imm); + } + +#define SH4_CHECK_RANGE_xor_imm_R0(imm) ((imm) >= 0 && (imm) <= 255) + +#define FITS_SH4_xor_imm_R0(imm) (SH4_CHECK_RANGE_xor_imm_R0(imm)) + + inline void Assembler::SH4_xor_imm_R0(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_xor_imm_R0(imm)); + SH4_emit16((0xC << 12) | (0xA << 8) | ((imm & 0xFF) << 0)); + asm_output("xor_imm_R0 %d", imm); + } + + inline void Assembler::SH4_xor(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xA << 0)); + asm_output("xor R%d, R%d", Ry.n, Rx.n); + } + +#define SH4_CHECK_RANGE_xorb_imm_dispR0GBR(imm) ((imm) >= 0 && (imm) <= 255) + +#define FITS_SH4_xorb_imm_dispR0GBR(imm) (SH4_CHECK_RANGE_xorb_imm_dispR0GBR(imm)) + + inline void Assembler::SH4_xorb_imm_dispR0GBR(int imm) { + NanoAssert(1 && SH4_CHECK_RANGE_xorb_imm_dispR0GBR(imm)); + SH4_emit16((0xC << 12) | (0xE << 8) | ((imm & 0xFF) << 0)); + asm_output("xorb_imm_dispR0GBR %d", imm); + } + + inline void Assembler::SH4_xtrct(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x2 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xD << 0)); + asm_output("xtrct R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_dt(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x4 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x1 << 4) | (0x0 << 0)); + asm_output("dt R%d", Rx.n); + } + + inline void Assembler::SH4_dmulsl(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x3 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xD << 0)); + asm_output("dmulsl R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_dmulul(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x3 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x5 << 0)); + asm_output("dmulul R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_macl_incRy_incRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0xF << 0)); + asm_output("macl_incRy_incRx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_braf(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x2 << 4) | (0x3 << 0)); + asm_output("braf R%d", Rx.n); + } + + inline void Assembler::SH4_bsrf(Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15); + SH4_emit16((0x0 << 12) | ((REGNUM(Rx) & 0xF) << 8) | (0x0 << 4) | (0x3 << 0)); + asm_output("bsrf R%d", Rx.n); + } + + inline void Assembler::SH4_fabs(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x5 << 4) | (0xD << 0)); + asm_output("fabs R%d", Rx.n); + } + + inline void Assembler::SH4_fabs_double(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && !((REGNUM(Rx) - 16) & 0x1)); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x5 << 4) | (0xD << 0)); + asm_output("fabs_double R%d", Rx.n); + } + + inline void Assembler::SH4_fadd(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x0 << 0)); + asm_output("fadd R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fadd_double(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && !((REGNUM(Rx) - 16) & 0x1) && (REGNUM(Ry) - 16) <= 15 && !((REGNUM(Ry) - 16) & 0x1)); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x0 << 0)); + asm_output("fadd_double R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fcmpeq(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x4 << 0)); + asm_output("fcmpeq R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fcmpeq_double(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && !((REGNUM(Rx) - 16) & 0x1) && (REGNUM(Ry) - 16) <= 15 && !((REGNUM(Ry) - 16) & 0x1)); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x4 << 0)); + asm_output("fcmpeq_double R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fcmpgt(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x5 << 0)); + asm_output("fcmpgt R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fcmpgt_double(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && !((REGNUM(Rx) - 16) & 0x1) && (REGNUM(Ry) - 16) <= 15 && !((REGNUM(Ry) - 16) & 0x1)); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x5 << 0)); + asm_output("fcmpgt_double R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fcnvds_double_FPUL(Register Rx) { + NanoAssert(1 && !((REGNUM(Rx) - 16) & 0x1)); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0xB << 4) | (0xD << 0)); + asm_output("fcnvds_double_FPUL R%d", Rx.n); + } + + inline void Assembler::SH4_fcnvsd_FPUL_double(Register Rx) { + NanoAssert(1 && !((REGNUM(Rx) - 16) & 0x1)); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0xA << 4) | (0xD << 0)); + asm_output("fcnvsd_FPUL_double R%d", Rx.n); + } + + inline void Assembler::SH4_fdiv(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x3 << 0)); + asm_output("fdiv R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fdiv_double(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && !((REGNUM(Rx) - 16) & 0x1) && (REGNUM(Ry) - 16) <= 15 && !((REGNUM(Ry) - 16) & 0x1)); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x3 << 0)); + asm_output("fdiv_double R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fipr(Register Ry, Register Rx) { + NanoAssert(1 && !(((REGNUM(Rx) - 16) & 0x3) || ((REGNUM(Ry) - 16) & 0x3))); + SH4_emit16((0xF << 12) | (((((REGNUM(Rx) - 16) & 0xF) << 2) | (((REGNUM(Ry) - 16) & 0xF) >> 2)) << 8) | (0xE << 4) | (0xD << 0)); + asm_output("fipr R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fldi0(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x8 << 4) | (0xD << 0)); + asm_output("fldi0 R%d", Rx.n); + } + + inline void Assembler::SH4_fldi1(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x9 << 4) | (0xD << 0)); + asm_output("fldi1 R%d", Rx.n); + } + + inline void Assembler::SH4_flds_FPUL(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x1 << 4) | (0xD << 0)); + asm_output("flds_FPUL R%d", Rx.n); + } + + inline void Assembler::SH4_float_FPUL(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x2 << 4) | (0xD << 0)); + asm_output("float_FPUL R%d", Rx.n); + } + + inline void Assembler::SH4_float_FPUL_double(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && !((REGNUM(Rx) - 16) & 0x1)); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x2 << 4) | (0xD << 0)); + asm_output("float_FPUL_double R%d", Rx.n); + } + + inline void Assembler::SH4_fmac(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0xE << 0)); + asm_output("fmac R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmov(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0xC << 0)); + asm_output("fmov R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmov_Xdouble_Xdouble(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0xC << 0)); + asm_output("fmov_Xdouble_Xdouble R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmov_indRy(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x8 << 0)); + asm_output("fmov_indRy R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmov_indRy_Xdouble(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x8 << 0)); + asm_output("fmov_indRy_Xdouble R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmov_indRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | ((REGNUM(Rx) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0xA << 0)); + asm_output("fmov_indRx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmov_Xdouble_indRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | ((REGNUM(Rx) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0xA << 0)); + asm_output("fmov_Xdouble_indRx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmov_incRy(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x9 << 0)); + asm_output("fmov_incRy R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmov_incRy_Xdouble(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x9 << 0)); + asm_output("fmov_incRy_Xdouble R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmov_decRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | ((REGNUM(Rx) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0xB << 0)); + asm_output("fmov_decRx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmov_Xdouble_decRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | ((REGNUM(Rx) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0xB << 0)); + asm_output("fmov_Xdouble_decRx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmov_dispR0Ry(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x6 << 0)); + asm_output("fmov_dispR0Ry R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmov_dispR0Ry_Xdouble(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x6 << 0)); + asm_output("fmov_dispR0Ry_Xdouble R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmov_dispR0Rx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | ((REGNUM(Rx) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x7 << 0)); + asm_output("fmov_dispR0Rx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmov_Xdouble_dispR0Rx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | ((REGNUM(Rx) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x7 << 0)); + asm_output("fmov_Xdouble_dispR0Rx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmovd_indRy_Xdouble(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x8 << 0)); + asm_output("fmovd_indRy_Xdouble R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmovd_Xdouble_indRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | ((REGNUM(Rx) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0xA << 0)); + asm_output("fmovd_Xdouble_indRx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmovd_incRy_Xdouble(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x9 << 0)); + asm_output("fmovd_incRy_Xdouble R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmovd_Xdouble_decRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | ((REGNUM(Rx) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0xB << 0)); + asm_output("fmovd_Xdouble_decRx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmovd_dispR0Ry_Xdouble(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x6 << 0)); + asm_output("fmovd_dispR0Ry_Xdouble R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmovd_Xdouble_dispR0Rx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | ((REGNUM(Rx) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x7 << 0)); + asm_output("fmovd_Xdouble_dispR0Rx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmovs_indRy(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x8 << 0)); + asm_output("fmovs_indRy R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmovs_indRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | ((REGNUM(Rx) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0xA << 0)); + asm_output("fmovs_indRx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmovs_incRy(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x9 << 0)); + asm_output("fmovs_incRy R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmovs_decRx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | ((REGNUM(Rx) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0xB << 0)); + asm_output("fmovs_decRx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmovs_dispR0Ry(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && REGNUM(Ry) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | ((REGNUM(Ry) & 0xF) << 4) | (0x6 << 0)); + asm_output("fmovs_dispR0Ry R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmovs_dispR0Rx(Register Ry, Register Rx) { + NanoAssert(1 && REGNUM(Rx) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | ((REGNUM(Rx) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x7 << 0)); + asm_output("fmovs_dispR0Rx R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmul(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x2 << 0)); + asm_output("fmul R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fmul_double(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && !((REGNUM(Rx) - 16) & 0x1) && (REGNUM(Ry) - 16) <= 15 && !((REGNUM(Ry) - 16) & 0x1)); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x2 << 0)); + asm_output("fmul_double R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fneg(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x4 << 4) | (0xD << 0)); + asm_output("fneg R%d", Rx.n); + } + + inline void Assembler::SH4_fneg_double(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && !((REGNUM(Rx) - 16) & 0x1)); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x4 << 4) | (0xD << 0)); + asm_output("fneg_double R%d", Rx.n); + } + + inline void Assembler::SH4_fpchg() { + NanoAssert(1); + SH4_emit16((0xF << 12) | (0x7 << 8) | (0xF << 4) | (0xD << 0)); + asm_output("fpchg"); + } + + inline void Assembler::SH4_frchg() { + NanoAssert(1); + SH4_emit16((0xF << 12) | (0xB << 8) | (0xF << 4) | (0xD << 0)); + asm_output("frchg"); + } + + inline void Assembler::SH4_fsca_FPUL_double(Register Rx) { + NanoAssert(1 && !((REGNUM(Rx) - 16) & 0x1)); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0xF << 4) | (0xD << 0)); + asm_output("fsca_FPUL_double R%d", Rx.n); + } + + inline void Assembler::SH4_fschg() { + NanoAssert(1); + SH4_emit16((0xF << 12) | (0x3 << 8) | (0xF << 4) | (0xD << 0)); + asm_output("fschg"); + } + + inline void Assembler::SH4_fsqrt(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x6 << 4) | (0xD << 0)); + asm_output("fsqrt R%d", Rx.n); + } + + inline void Assembler::SH4_fsqrt_double(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && !((REGNUM(Rx) - 16) & 0x1)); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x6 << 4) | (0xD << 0)); + asm_output("fsqrt_double R%d", Rx.n); + } + + inline void Assembler::SH4_fsrra(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x7 << 4) | (0xD << 0)); + asm_output("fsrra R%d", Rx.n); + } + + inline void Assembler::SH4_fsts_FPUL(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x0 << 4) | (0xD << 0)); + asm_output("fsts_FPUL R%d", Rx.n); + } + + inline void Assembler::SH4_fsub(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && (REGNUM(Ry) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x1 << 0)); + asm_output("fsub R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_fsub_double(Register Ry, Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && !((REGNUM(Rx) - 16) & 0x1) && (REGNUM(Ry) - 16) <= 15 && !((REGNUM(Ry) - 16) & 0x1)); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (((REGNUM(Ry) - 16) & 0xF) << 4) | (0x1 << 0)); + asm_output("fsub_double R%d, R%d", Ry.n, Rx.n); + } + + inline void Assembler::SH4_ftrc_FPUL(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x3 << 4) | (0xD << 0)); + asm_output("ftrc_FPUL R%d", Rx.n); + } + + inline void Assembler::SH4_ftrc_double_FPUL(Register Rx) { + NanoAssert(1 && (REGNUM(Rx) - 16) <= 15 && !((REGNUM(Rx) - 16) & 0x1)); + SH4_emit16((0xF << 12) | (((REGNUM(Rx) - 16) & 0xF) << 8) | (0x3 << 4) | (0xD << 0)); + asm_output("ftrc_double_FPUL R%d", Rx.n); + } + + inline void Assembler::SH4_ftrv(Register Rx) { + NanoAssert(1 && !((REGNUM(Rx) - 16) & 0x3)); + SH4_emit16((0xF << 12) | (((((REGNUM(Rx) - 16) & 0xF) << 2) | 0x1) << 8) | (0xF << 4) | (0xD << 0)); + asm_output("ftrv R%d", Rx.n); + } diff --git a/js/src/nanojit/NativeSH4.cpp b/js/src/nanojit/NativeSH4.cpp new file mode 100644 index 0000000..2f1f5ec --- /dev/null +++ b/js/src/nanojit/NativeSH4.cpp @@ -0,0 +1,1586 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * STMicroelectronics. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Cédric VINCENT for STMicroelectronics + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nanojit.h" + +#if defined FEATURE_NANOJIT && defined NANOJIT_SH4 + +namespace nanojit +{ + const int Assembler::NumArgRegs = 4; + const Register Assembler::argRegs[] = { R4, R5, R6, R7 }; + const Register Assembler::retRegs[] = { R0, R1 }; + const Register Assembler::savedRegs[] = { R8, R9, R10, R11, R12, R13 }; + + const int Assembler::NumArgDregs = 4; + const Register Assembler::argDregs[] = { _D2, _D3, _D4, _D5 }; + const Register Assembler::retDregs[] = { _D0 }; + + const char *regNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "fp", "sp", + "d0", "d0~", "d1", "d1~", "d2", "d2~", "d3", "d3~", + "d4", "d4~", "d5", "d5~", "d6", "d6~", "d7", "d7~" + }; + + inline void Assembler::SH4_emit16(uint16_t value) { + NanoAssert(_nIns - codeStart >= 2); + _nIns--; + *((uint16_t*)_nIns) = value; + } + + inline void Assembler::SH4_emit32(uint32_t value) { + NanoAssert(_nIns - codeStart >= 4); + _nIns -= 2; + *((uint32_t *)(void *)_nIns) = value; + } + +#include "NativeSH4-auto-generated.h" + +#define SH4_movl_PCrel(address, reg) \ + SH4_movl_dispPC(((uint32_t)(address) - (((uint32_t)_nIns) & ~0x3)), reg) + +#define SH4_LABEL(target) (int32_t)((uint32_t)(target) - (uint32_t)(_nIns) - 2) + + void Assembler::nativePageReset() { } + + void Assembler::nativePageSetup() { + NanoAssert(!_inExit); + if (!_nIns) + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes)); + } + + void Assembler::MR(Register dest, Register src) { + underrunProtect(1 * sizeof(NIns)); + SH4_mov(src, dest); + } + + void Assembler::JMP(NIns *target, bool from_underrunProtect) { + underrunProtect(2 * sizeof(NIns)); + if (target != NULL && FITS_SH4_bra(SH4_LABEL(target + 1 * sizeof(NIns)))) { + // We can reach the target with a "bra". + SH4_nop(); + SH4_bra(SH4_LABEL(target)); + } + else if (from_underrunProtect) { + // When compiling the following code, where XXX is "large": + // + // array[XXX] = YYY + // + // The SH4 backend will produce the native code in two steps: + // + // 1. mov.l @(pc, ZZZ), Rtemp + // 2a. add FP, Rtemp + // 2b. mov.l Rsrc, @Rtemp + // + // If the code buffer is full right after the first step, + // it will add the [in]famous glue JMP: + // + // 1. mov.l @(pc, ZZZ), Rtemp + // mov.l @(pc, TARGET), Rtemp # Technically Rtemp is now the address of 2a. + // jmp @Rtemp # Jump to 2a. + // 2a. add FP, Rtemp + // 2b. mov.l Rsrc, @Rtemp + // + // As you can see, we have to keep/restore the value of + // Rtemp when called from underrunProtect(). + // TODO: do this only when needed. + + SH4_movl_incRy(SP, Rtemp); + SH4_jmp_indRx(Rtemp); + + asm_immi((int)target, Rtemp, (target == NULL)); + + SH4_movl_decRx(Rtemp, SP); + } + else { + // General case. + SH4_nop(); + SH4_jmp_indRx(Rtemp); + asm_immi((int)target, Rtemp, (target == NULL)); + } + } + + void Assembler::asm_arith(LIns *inst) { + LOpcode opcode = inst->opcode(); + LIns *operand1 = inst->oprnd1(); + LIns *operand2 = inst->oprnd2(); + + RegisterMask allow = GpRegs; + + Register result_reg = prepareResultReg(inst, allow); + allow &= ~rmask(result_reg); + + Register operand1_reg = findRegFor(operand1, allow); + allow &= ~rmask(operand1_reg); + + underrunProtect(7 * sizeof(NIns)); + + // Special case on SH4: the instruction "add" is the only + // arithmetic operation that can use an [small] immediate. + if (operand2->isImmI() && + (inst->opcode() == LIR_addi || inst->opcode() == LIR_subi)) { + int immI = operand2->immI(); + + if (inst->opcode() == LIR_subi) + immI = -immI; + + if (FITS_SH4_add_imm(immI)) { + // 2. operand2 + result -> result + SH4_add_imm(immI, result_reg); + + // 1. operand1 -> result + if (result_reg != operand1_reg) + SH4_mov(operand1_reg, result_reg); + + freeResourcesOf(inst); + return; + } + } + + Register operand2_reg = inst->oprnd1() == inst->oprnd2() + ? operand1_reg + : findRegFor(operand2, allow); + + // 2. operand2 OP result -> result + NanoAssert(result_reg != Rtemp && operand1_reg != Rtemp && operand2_reg != Rtemp); + switch (opcode) { + case LIR_rshi: + SH4_shad(Rtemp, result_reg); + SH4_neg(Rtemp, Rtemp); + SH4_and(operand2_reg, Rtemp); + SH4_mov_imm(0x1f, Rtemp); + break; + + case LIR_rshui: + SH4_shld(Rtemp, result_reg); + SH4_neg(Rtemp, Rtemp); + SH4_and(operand2_reg, Rtemp); + SH4_mov_imm(0x1f, Rtemp); + break; + + case LIR_muli: + SH4_sts_MACL(result_reg); + SH4_mull(operand2_reg, result_reg); + break; + + case LIR_muljovi: + case LIR_mulxovi: + // 3. Now the T-bit is equal to "sign_of(result_reg) == sign_of(operand1) XOR sign_of(operand2)". + SH4_shll(Rtemp); + SH4_xor(result_reg, Rtemp); + + // 2. Perform the actual multiplication. + SH4_sts_MACL(result_reg); + SH4_dmulsl(operand2_reg, result_reg); + + // 1. Now Rtemp[31] is equal to "sign_of(operand1) XOR sign_of(operand2)". + SH4_xor(operand2_reg, Rtemp); + SH4_mov(result_reg, Rtemp); + break; + + case LIR_lshi: SH4_shad(operand2_reg, result_reg); break; + case LIR_ori: SH4_or(operand2_reg, result_reg); break; + case LIR_subi: SH4_sub(operand2_reg, result_reg); break; + case LIR_addi: SH4_add(operand2_reg, result_reg); break; + case LIR_andi: SH4_and(operand2_reg, result_reg); break; + case LIR_xori: SH4_xor(operand2_reg, result_reg); break; + + case LIR_subjovi: + case LIR_subxovi: SH4_subv(operand2_reg, result_reg); break; + + case LIR_addjovi: + case LIR_addxovi: SH4_addv(operand2_reg, result_reg); break; + default: + NanoAssertMsg(0, "asm_arith does not support this LIR opcode yet"); + } + + // 1. operand1 -> result + if (result_reg != operand1_reg) + SH4_mov(operand1_reg, result_reg); + + freeResourcesOf(inst); + } + + void Assembler::asm_arg_regi(LIns *arg, Register reg) { + if (arg->isExtant()) { + if (arg->isInReg()) { + // This argument is assigned to a register, thus we + // just have to copy it to the right register. + underrunProtect(1 * sizeof(NIns)); + SH4_mov(arg->getReg(), reg); + } + else { + // This argument is not assigned to a register, thus + // we have to get its frame address first and then + // copy it to the right register. + int offset = findMemFor(arg); + + if (arg->isop(LIR_allocp)) { + // Load the address of the argument, not its value. + underrunProtect(1 * sizeof(NIns)); + SH4_add(FP, reg); // 2. arg_reg + FP -> arg_reg + asm_immi(offset, reg); // 1. offset -> arg_reg + } + else { + // Load the value of the argument. + asm_load32i(offset, FP, reg); + } + } + } + else { + // This is the last use of "arg", so fine to + // assign it to the right register immediately. + findSpecificRegFor(arg, reg); + } + } + + void Assembler::asm_arg_regd(LIns *arg, Register reg) { + if (arg->isExtant()) { + if (arg->isInReg()) { + // This argument is assigned to a register, thus we + // just have to copy it to the right register. + underrunProtect(2 * sizeof(NIns)); + SH4_fmov(arg->getReg(), reg); + SH4_fmov(arg->getReg() + 1, reg + 1); + } + else { + // This argument is not assigned to a register, thus + // we have to get its frame address first and then + // copy it to the right register. + int offset = findMemFor(arg); + asm_load64d(offset, FP, reg); + } + } + else { + // This is the last use of "arg", so fine to + // assign it to the right register immediately. + findSpecificRegFor(arg, reg); + } + } + + void Assembler::asm_arg_stacki(LIns *arg, int used_stack) { + if (arg->isExtant() && arg->isInReg()) { + Register result_reg = arg->getReg(); + // This argument is assigned to a register, thus we just + // have to copy it to the right stack slot. + asm_store32i(result_reg, used_stack, SP); + } + else { + // This argument is not assigned to a register, thus we + // have to get its frame address first and then copy it to + // the right stack slot. + int offset = findMemFor(arg); + Register reg = findRegFor(arg, GpRegs); + + asm_store32i(reg, used_stack, SP); + + if (arg->isop(LIR_allocp)) { + // Load the address of the argument, not its value. + underrunProtect(1 * sizeof(NIns)); + SH4_add(FP, reg); // 2. arg_reg + FP -> arg_reg + asm_immi(offset, reg); // 1. offset -> arg_reg + } + else { + // Load the value of the argument. + asm_load32i(offset, FP, reg); + } + } + } + + void Assembler::asm_arg_stackd(LIns *arg, int used_stack) { + if (arg->isExtant() && arg->isInReg()) { + Register result_reg = arg->getReg(); + // This argument is assigned to a register, thus we just + // have to copy it to the right stack slot. + asm_store64d(result_reg, used_stack, SP); + } + else { + // This argument is not assigned to a register, thus we + // have to get its frame address first and then copy it to + // the right stack slot. + int offset = findMemFor(arg); + Register reg = findRegFor(arg, FpRegs); + + asm_store64d(reg, used_stack, SP); + asm_load64d(offset, FP, reg); + } + } + + void Assembler::asm_call(LIns *inst) { + if (!inst->isop(LIR_callv)) { + Register result_reg = inst->isop(LIR_calld) ? retDregs[0] : retRegs[0]; + prepareResultReg(inst, rmask(result_reg)); + + // Do this after we've handled the call result, so we don't + // force the call result to be spilled unnecessarily. + evictScratchRegsExcept(rmask(result_reg)); + } else { + evictScratchRegsExcept(0); + } + ArgType types[MAXARGS]; + const CallInfo* call = inst->callInfo(); + uint32_t argc = call->getArgTypes(types); + bool indirect = call->isIndirect(); + + // Emit the branch. + if (!indirect) { + NIns *target = (NIns*)call->_address; + + underrunProtect(2 * sizeof(NIns)); + if (FITS_SH4_bsr(SH4_LABEL(target + 1 * sizeof(NIns)))) { + // We can reach the target with a "bsr". + SH4_nop(); + SH4_bsr(SH4_LABEL(target)); + } + else { + // General case. + SH4_nop(); + SH4_jsr_indRx(Rtemp); // 2. jump to target + asm_immi((int)target, Rtemp); // 1. load target + } + // Call this now so that the argument setup can involve 'result_reg'. + freeResourcesOf(inst); + } + else { + // Indirect call: we assign the address arg to R0 since it's not + // used for regular arguments, and is otherwise scratch since it's + // clobberred by the call. + underrunProtect(2 * sizeof(NIns)); + + SH4_nop(); + SH4_jsr_indRx(R0); + + // Call this now so that the argument setup can involve 'result_reg'. + freeResourcesOf(inst); + + argc--; + asm_arg_regi(inst->arg(argc), R0); + } + + // Emit the arguments. + int ireg_index = 0; + int dreg_index = 0; + int used_stack = 0; + + for (int i = argc - 1; i >= 0; i--) { + switch(types[i]) { + case ARGTYPE_I: // int32_t + case ARGTYPE_UI: // uint32_t + if (ireg_index < NumArgRegs) { + // Arguments are [still] stored into registers. + asm_arg_regi(inst->arg(i), argRegs[ireg_index]); + ireg_index++; + } + else { + // Arguments are [now] stored into the stack. + asm_arg_stacki(inst->arg(i), used_stack); + used_stack += sizeof(int); + } + break; + + case ARGTYPE_D: // double (64bit) + if (dreg_index < NumArgDregs) { + // Arguments are [still] stored into registers. + asm_arg_regd(inst->arg(i), argDregs[dreg_index]); + dreg_index++; + } + else { + // Arguments are [now] stored into the stack. + asm_arg_stackd(inst->arg(i), used_stack); + used_stack += sizeof(double); + } + break; + + default: + NanoAssertMsg(0, "asm_call does not support this size of argument yet"); + } + } + + if (used_stack > max_stack_args) + max_stack_args = used_stack; + } + + void Assembler::asm_cmov(LIns *inst) { + LIns* condition = inst->oprnd1(); + LIns* if_true = inst->oprnd2(); + LIns* if_false = inst->oprnd3(); + + NanoAssert(condition->isCmp()); + NanoAssert( (inst->isop(LIR_cmovi) && if_true->isI() && if_false->isI()) + || (inst->isop(LIR_cmovd) && if_true->isD() && if_false->isD())); + + RegisterMask allow = inst->isD() ? FpRegs : GpRegs; + + Register dest_reg = prepareResultReg(inst, allow); + + // Try to re-use the result register for one of the arguments. + Register src_true_reg = if_true->isInReg() ? if_true->getReg() : dest_reg; + Register src_false_reg = if_false->isInReg() ? if_false->getReg() : dest_reg; + + // Note that iftrue and iffalse may actually be the same, though + // it shouldn't happen with the LIR optimizers turned on. + if (src_true_reg == src_false_reg && if_true != if_false) { + // We can't re-use the result register for both arguments, + // so force one into its own register. + src_false_reg = findRegFor(if_false, allow & ~rmask(dest_reg)); + NanoAssert(if_false->isInReg()); + } + + underrunProtect(6 * sizeof(NIns)); + // 3. If the test is "true", copy the "true" source register. + NIns *after_mov_true = _nIns; + if (inst->isop(LIR_cmovd)) { + SH4_fmov(src_true_reg, dest_reg); + SH4_fmov(src_true_reg + 1, dest_reg + 1); + } + else { + SH4_mov(src_true_reg, dest_reg); + } + + // 2. If the test is "false", copy the "false" source register + // then jump over the "mov if true". + NIns *after_mov_false = _nIns; + + SH4_nop(); + SH4_bra(SH4_LABEL(after_mov_true)); + + if (inst->isop(LIR_cmovd)) { + SH4_fmov(src_false_reg, dest_reg); + SH4_fmov(src_false_reg + 1, dest_reg + 1); + } + else { + SH4_mov(src_false_reg, dest_reg); + } + + freeResourcesOf(inst); + + // If we re-used the result register, mark it as active for either if_true + // or if_false (or both in the corner-case where they're the same). + if (src_true_reg == dest_reg) { + NanoAssert(!if_true->isInReg()); + findSpecificRegForUnallocated(if_true, dest_reg); + } else if (src_false_reg == dest_reg) { + NanoAssert(!if_false->isInReg()); + findSpecificRegForUnallocated(if_false, dest_reg); + } else { + NanoAssert(if_false->isInReg()); + NanoAssert(if_true->isInReg()); + } + + // 1. Branch [or not] according to the condition. + asm_branch(false, condition, after_mov_false); + } + + void Assembler::asm_cond(LIns *inst) { + Register result_reg = prepareResultReg(inst, GpRegs); + LOpcode opcode = inst->opcode(); + + // 2. Get the T-bit. + underrunProtect(3 * sizeof(NIns)); + SH4_movt(result_reg); + + // Inverse the T-bit with a small trick. + bool negated = simplifyOpcode(opcode); + if (negated) { + SH4_tst(result_reg, result_reg); + SH4_movt(result_reg); + } + + freeResourcesOf(inst); + + // 1. Do the comparison + asm_cmp(opcode, inst); + } + + void Assembler::asm_condd(LIns *inst) { + asm_cond(inst); + } + + void Assembler::asm_fneg(LIns *inst) { + Register result_reg = prepareResultReg(inst, FpRegs); + Register operand_reg = findRegFor(inst->oprnd1(), FpRegs); + + // 2. -result -> result + underrunProtect(1 * sizeof(NIns)); + SH4_fneg_double(result_reg); + + // 1. operand -> result + if (result_reg != operand_reg) { + underrunProtect(2 * sizeof(NIns)); + SH4_fmov(operand_reg, result_reg); + SH4_fmov(operand_reg + 1, result_reg + 1); + } + + freeResourcesOf(inst); + } + + void Assembler::asm_fop(LIns *inst) { + LOpcode opcode = inst->opcode(); + LIns *operand1 = inst->oprnd1(); + LIns *operand2 = inst->oprnd2(); + + RegisterMask allow = FpRegs; + + Register result_reg = prepareResultReg(inst, allow); + allow &= ~rmask(result_reg); + + Register operand1_reg = findRegFor(operand1, allow); + allow &= ~rmask(operand1_reg); + + Register operand2_reg = inst->oprnd1() == inst->oprnd2() + ? operand1_reg + : findRegFor(operand2, allow); + + underrunProtect(3 * sizeof(NIns)); + + // 2. operand2 OP result -> result + switch (opcode) { + case LIR_addd: SH4_fadd_double(operand2_reg, result_reg); break; + case LIR_subd: SH4_fsub_double(operand2_reg, result_reg); break; + case LIR_muld: SH4_fmul_double(operand2_reg, result_reg); break; + case LIR_divd: SH4_fdiv_double(operand2_reg, result_reg); break; + default: + NanoAssertMsg(0, "asm_fop does not support this LIR opcode yet"); + } + + // 1. operand1 -> result + if (result_reg != operand1_reg) { + SH4_fmov(operand1_reg, result_reg); + SH4_fmov(operand1_reg + 1, result_reg + 1); + } + + freeResourcesOf(inst); + } + + void Assembler::asm_d2i(LIns *inst) { + Register result_reg = prepareResultReg(inst, GpRegs); + Register operand1_reg = findRegFor(inst->oprnd1(), FpRegs); + + underrunProtect(2 * sizeof(NIns)); + SH4_sts_FPUL(result_reg); + SH4_ftrc_double_FPUL(operand1_reg); + + freeResourcesOf(inst); + } + + void Assembler::asm_i2d(LIns *inst) { + Register result_reg = prepareResultReg(inst, FpRegs); + Register operand1_reg = findRegFor(inst->oprnd1(), GpRegs); + + underrunProtect(2 * sizeof(NIns)); + SH4_float_FPUL_double(result_reg); + SH4_lds_FPUL(operand1_reg); + + freeResourcesOf(inst); + } + + void Assembler::asm_ui2d(LIns *inst) { + Register result_reg = prepareResultReg(inst, FpRegs); + Register operand1_reg = findRegFor(inst->oprnd1(), GpRegs); + + underrunProtect(SH4_IMMD_NOCHK_SIZE + 5 * sizeof(NIns)); + NIns *over_conversion = _nIns; + + // 3. Otherwise adjust the result. + SH4_fadd(Dtemp, result_reg); + asm_immd_nochk(0x41F0000000000000LLU, Dtemp); // It does the trick™. + + // 2. Done if it was a positif integer. + SH4_bt(SH4_LABEL(over_conversion)); + SH4_cmppz(operand1_reg); + + // 1. Convert the *signed* integer. + SH4_float_FPUL_double(result_reg); + SH4_lds_FPUL(operand1_reg); + + freeResourcesOf(inst); + } + + void Assembler::asm_immi(LIns *inst) { + Register result_reg = prepareResultReg(inst, GpRegs); + asm_immi(inst->immI(), result_reg); + freeResourcesOf(inst); + } + + void Assembler::asm_base_offset(int offset, Register base_reg) { + underrunProtect(2 * sizeof(NIns)); + + if (offset != 0) { + if (FITS_SH4_add_imm(offset)) { + SH4_add_imm(offset, Rtemp); + if (base_reg != Rtemp) + SH4_mov(base_reg, Rtemp); + } + else { + NanoAssert(base_reg != Rtemp); + SH4_add(base_reg, Rtemp); // b. base + temp -> temp + asm_immi(offset, Rtemp); // a. offset -> temp + } + } + else { + if (base_reg != Rtemp) + SH4_mov(base_reg, Rtemp); + } + } + + void Assembler::asm_load64d(int offset, Register base_reg, Register result_reg) { + underrunProtect(2 * sizeof(NIns)); + + // 2. Load the "double" from @Rtemp. + SH4_fmovs_indRy(Rtemp, result_reg); + SH4_fmovs_incRy(Rtemp, result_reg + 1); + + // 1. base + offset -> Rtemp. + asm_base_offset(offset, base_reg); + } + + void Assembler::asm_load32d(int offset, Register base_reg, Register result_reg) { + underrunProtect(3 * sizeof(NIns)); + + // 3. Convert to double precision. + SH4_fcnvsd_FPUL_double(result_reg); + SH4_flds_FPUL(Dtemp); + + // 2. Load the "float" from @Rtemp. + SH4_fmovs_indRy(Rtemp, Dtemp); + + // 1. base + offset -> Rtemp. + asm_base_offset(offset, base_reg); + } + + void Assembler::asm_load32i(int offset, Register base_reg, Register result_reg) { + // Rtemp is mandatory to handle the "worst" case. + NanoAssert(result_reg != Rtemp); + + if (offset == 0) { + // No displacement. + underrunProtect(1 * sizeof(NIns)); + SH4_movl_indRy(base_reg, result_reg); + } + else if (FITS_SH4_movl_dispRy(offset)) { + // The displacement fits the constraints of this instruction. + underrunProtect(1 * sizeof(NIns)); + SH4_movl_dispRy(offset, base_reg, result_reg); + } + else { + // General case. + if (false // TODO: test if R0 is unused. + && base_reg != R0) { + NanoAssertMsg(0, "not yet tested."); + // Optimize when R0 is free and not used as the base. + + underrunProtect(1 * sizeof(NIns)); + SH4_movl_dispR0Ry(base_reg, result_reg); // 2. @(R0 + base) -> result + asm_immi(offset, R0); // 1. offset -> R0 + } + else { + // Worst case. + underrunProtect(2 * sizeof(NIns)); + SH4_movl_indRy(Rtemp, result_reg); // 3. @(temp) -> result + SH4_add(base_reg, Rtemp); // 2. base + temp -> temp + asm_immi(offset, Rtemp); // 1. offset -> temp + } + } + } + +#define gen_asm_loadXXi(size, length) \ + void Assembler::asm_load ## size ## i(int offset, Register base_reg, Register result_reg, bool sign_extend) { \ + underrunProtect(5 * sizeof(NIns)); \ + \ + if (!sign_extend) { \ + SH4_extu ## length(result_reg, result_reg); \ + } \ + \ + if (offset == 0) { \ + /* No displacement. */ \ + SH4_mov ## length ## _indRy(base_reg, result_reg); \ + } \ + else if (FITS_SH4_mov ## length ## _dispRy_R0(offset)) { \ + /* The displacement is small enough to fit into the */ \ + /* special #size bits load "@(base + offset) -> R0". */ \ + if (result_reg == R0) { \ + /* We are lucky, the result is R0. */ \ + NanoAssertMsg(0, "not yet tested."); \ + SH4_mov ## length ## _dispRy_R0(offset, base_reg); /* @(base + offset) -> R0 */ \ + } \ + else { \ + /* We have to save and restore R0. */ \ + NanoAssertMsg(0, "not yet tested."); \ + SH4_mov(Rtemp, R0); /* 4. Rtemp -> R0 */ \ + SH4_mov(Rtemp, result_reg); /* 3. R0 -> result */ \ + SH4_mov ## length ## _dispRy_R0(offset, base_reg); /* 2. @(base + offset) -> R0 */ \ + SH4_mov(R0, Rtemp); /* 1. R0 -> Rtemp */ \ + } \ + } \ + else { \ + /* Worst case. */ \ + SH4_mov ## length ## _indRy(Rtemp, result_reg); /* 3. @(temp) -> result */ \ + SH4_add(base_reg, Rtemp); /* 2. base + temp -> temp */ \ + asm_immi(offset, Rtemp); /* 1. offset -> temp */ \ + } \ + } + + gen_asm_loadXXi(16, w) + gen_asm_loadXXi(8, b) + + void Assembler::asm_load32(LIns *inst) { + LIns* base = inst->oprnd1(); + int offset = inst->disp(); + + Register result_reg = prepareResultReg(inst, GpRegs); + Register base_reg = getBaseReg(base, offset, GpRegs); + + switch (inst->opcode()) { + case LIR_lduc2ui: + asm_load8i(offset, base_reg, result_reg, false); + break; + case LIR_ldc2i: + asm_load8i(offset, base_reg, result_reg, true); + break; + case LIR_ldus2ui: + asm_load16i(offset, base_reg, result_reg, false); + break; + case LIR_lds2i: + asm_load16i(offset, base_reg, result_reg, true); + break; + case LIR_ldi: + asm_load32i(offset, base_reg, result_reg); + break; + default: + NanoAssertMsg(0, "asm_load32 should never receive this LIR opcode"); + } + freeResourcesOf(inst); + } + + void Assembler::asm_load64(LIns *inst) { + LIns* base = inst->oprnd1(); + int offset = inst->disp(); + + Register result_reg = prepareResultReg(inst, FpRegs); + Register base_reg = getBaseReg(base, offset, GpRegs); + + switch (inst->opcode()) { + case LIR_ldd: + asm_load64d(offset, base_reg, result_reg); + break; + case LIR_ldf2d: + asm_load32d(offset, base_reg, result_reg); + break; + default: + NanoAssertMsg(0, "asm_load64 should never receive this LIR opcode"); + } + + freeResourcesOf(inst); + } + + void Assembler::asm_neg_not(LIns *inst) { + // TODO: Try to use the same register. + Register result_reg = prepareResultReg(inst, GpRegs); + Register operand_reg = findRegFor(inst->oprnd1(), GpRegs); + + underrunProtect(1 * sizeof(NIns)); + if (inst->isop(LIR_negi)) + SH4_neg(operand_reg, result_reg); + else + SH4_not(operand_reg, result_reg); + + freeResourcesOf(inst); + } + + void Assembler::asm_nongp_copy(Register dest_reg, Register src_reg) { + NanoAssert(IsFpReg(dest_reg) && IsFpReg(src_reg)); + + underrunProtect(2 * sizeof(NIns)); + SH4_fmov(src_reg, dest_reg); + SH4_fmov(src_reg + 1, dest_reg + 1); + } + + void Assembler::asm_param(LIns *inst) { + int arg_number = inst->paramArg(); + int kind = inst->paramKind(); + + if (kind == 0) { + // Ordinary parameter. + if (arg_number < NumArgRegs) { + // The incoming parameter is in register. + prepareResultReg(inst, rmask(argRegs[arg_number])); + } + else { + // The incoming parameter is on stack, and FP points + // nearby. Keep in sync' with genPrologue(). + Register reg = prepareResultReg(inst, GpRegs); + int offset = (arg_number - NumArgRegs) * sizeof(intptr_t) + + 2 * sizeof(int); /* saved PR and saved SP. */ + asm_load32i(offset, FP, reg); + } + } + else { + // Saved parameter. + prepareResultReg(inst, rmask(savedRegs[arg_number])); + // No code to generate. + } + freeResourcesOf(inst); + } + + // Keep in sync' with SH4_IMMD_NOCHK_SIZE. + void Assembler::asm_immd_nochk(uint64_t value, Register result_reg) { + NIns *over_constant = NULL; + + // Sanity check. + NanoAssert(_nIns - SH4_IMMD_NOCHK_SIZE >= codeStart); + NanoAssert(result_reg != Rtemp); + + // 8. Load the "double" constant from @Rtemp. + SH4_fmovs_indRy(Rtemp, result_reg); + SH4_fmovs_incRy(Rtemp, result_reg + 1); + + // 7. Restore R0 from the stack. + SH4_movl_incRy(SP, R0); + + // 6. Get the address of the constant + SH4_mov(R0, Rtemp); + over_constant = _nIns; + + // 5. align the constant with nop + if (((uint32_t)_nIns & 0x3) != 0) + SH4_nop(); + + // 4. constant64 + SH4_emit32((uint32_t)(value >> 32)); + SH4_emit32((uint32_t)(value & 0x00000000FFFFFFFFLLU)); + + // 3. branch over the constant + SH4_nop(); + SH4_bra(SH4_LABEL(over_constant)); + + // 2. Compute the address of the constant. + SH4_mova_dispPC_R0(2 * sizeof(NIns)); + + // 1. Save R0 onto the stack since we need it soon. + SH4_movl_decRx(R0, SP); + } + +#define SIGNIFICAND_MASK 0x000FFFFFFFFFFFFFLLU +#define EXPONENT_MASK 0x7FF0000000000000LLU +#define SIGN_MASK 0x8000000000000000LLU +#define SIGNIFICAND_OFFSET 0 +#define EXPONENT_OFFSET 52 +#define SIGN_OFFSET 63 + + void Assembler::asm_immd(uint64_t value, Register result_reg) { + int exponent = ((value & EXPONENT_MASK ) >> EXPONENT_OFFSET) - 1023; + int sign = (value & SIGN_MASK) >> SIGN_OFFSET; + + NanoAssert(result_reg != Rtemp); + + if ((value & SIGNIFICAND_MASK) == 0 + && exponent == -1023) { + // This doube is either 0 or -0. + underrunProtect(4 * sizeof(NIns)); + + if (sign != 0) + SH4_fneg_double(result_reg); // 4. -Dreg -> Dreg + + SH4_float_FPUL_double(result_reg); // 3. FPUL -> Dreg, it's magic ! + SH4_lds_FPUL(Rtemp); // 2. Rtemp -> FPUL + SH4_mov_imm(0, Rtemp); // 1. 0x0 -> Rtemp + } + else if ((value & SIGNIFICAND_MASK) == 0 + && exponent >= 0 + && exponent < 31) { + // This double is an interger, so load it in an optimized way. + // TODO: currently it only supports power-of-2 integers :-/ + + int immI = (1 << exponent) * (sign ? -1 : 1); + + underrunProtect(3 * sizeof(NIns)); + SH4_float_FPUL_double(result_reg); // 3. FPUL -> Dreg, it's magic ! + SH4_lds_FPUL(Rtemp); // 2. Rtemp -> FPUL + asm_immi(immI, Rtemp); // 1. integer -> Rtemp + } + else { + // Generic case. + underrunProtect(SH4_IMMD_NOCHK_SIZE); + asm_immd_nochk(value, result_reg); + } + } + + void Assembler::asm_immd(LIns *inst) { + Register result_reg = prepareResultReg(inst, FpRegs); + asm_immd(inst->immDasQ(), result_reg); + freeResourcesOf(inst); + } + + bool Assembler::canRemat(LIns* inst) { + return inst->isImmI() || inst->isop(LIR_allocp); + } + + void Assembler::asm_restore(LIns *inst, Register reg) { + if (inst->isop(LIR_allocp)) { + int offset = arDisp(inst); + underrunProtect(2 * sizeof(NIns)); + if (FITS_SH4_add_imm(offset)){ + SH4_add_imm(offset, reg); // 2. reg + offset -> reg + SH4_mov(FP, reg); // 1. FP -> reg + } + else { + SH4_add(FP, reg); // 2. FP + reg -> reg + asm_immi(offset, reg); // 1. offset -> reg + } + } + else if (inst->isImmI()) { + asm_immi(inst->immI(), reg); + } + else { + int offset = findMemFor(inst); + if (IsGpReg(reg)) { + asm_load32i(offset, FP, reg); + } + else { + asm_load64d(offset, FP, reg); + } + } + } + + NIns* Assembler::genEpilogue() { + underrunProtect(5 * sizeof(NIns)); + + // 3. Perform a return to the caller using the return address. + SH4_nop(); + SH4_rts(); + + // 2. Restore the previous frame pointer. + SH4_movl_incRy(SP, FP); + + // 1. Restore the return address. + SH4_ldsl_incRx_PR(SP); + + // 0. Restore the stack pointer. + SH4_mov(FP, SP); + + return _nIns; + } + + void Assembler::asm_ret(LIns* inst) { + genEpilogue(); + releaseRegisters(); + assignSavedRegs(); + + LIns *value = inst->oprnd1(); + + Register reg = inst->isop(LIR_retd) ? retDregs[0] : retRegs[0]; + findSpecificRegFor(value, reg); + } + + void Assembler::asm_spill(Register reg, int offset, bool quad) { + (void)quad; + + if (offset == 0) + return; // Nothing to spill. + + if (IsGpReg(reg)) { + NanoAssert(!quad); + asm_store32i(reg, offset, FP); + } + else { + NanoAssert(quad); + asm_store64d(reg, offset, FP); + } + } + + NIns *Assembler::asm_immi(int constant, Register reg, bool force) { + NIns *constant_addr = NULL; + + if (FITS_SH4_mov_imm(constant) && !force) { + // Best case. + underrunProtect(1 * sizeof(NIns)); + SH4_mov_imm(constant, reg); + } + else if (false && !force) { + // TODO: use several "add" if it produces less instructions than worst solution. + NanoAssertMsg(0, "not yet tested."); + } + else { + // Worst case, TODO: use a constant-pool manager. + underrunProtect(6 * sizeof(NIns)); + NIns *over_constant = _nIns; + + // 4. align the constant with nop + if (((uint32_t)_nIns & 0x3) != 0) + SH4_nop(); + + // 3. constant32 + SH4_emit32(constant); + constant_addr = _nIns; + + // 2. branch over the constant + SH4_nop(); + SH4_bra(SH4_LABEL(over_constant)); + + // 1. @(PC + offset) -> reg + SH4_movl_PCrel(constant_addr, reg); + } + + return constant_addr; + } + + void Assembler::asm_store32i(Register value_reg, int offset, Register base_reg) { + // Rtemp is mandatory to handle the "worst" case. + NanoAssert(value_reg != Rtemp && base_reg != Rtemp); + + if (offset == 0) { + // No displacement. + underrunProtect(1 * sizeof(NIns)); + SH4_movl_indRx(value_reg, base_reg); + } + else if (FITS_SH4_movl_dispRx(offset)) { + // The displacement fits the constraints of this instruction. + underrunProtect(1 * sizeof(NIns)); + SH4_movl_dispRx(value_reg, offset, base_reg); + } + else { + // General case. + if (false // TODO: test if R0 is unused. + && base_reg != R0) { + NanoAssertMsg(0, "not yet tested."); + // Optimize when R0 is free and not used as the base. + + underrunProtect(1 * sizeof(NIns)); + SH4_movl_dispR0Rx(value_reg, base_reg); // 2. value -> @(R0 + base) + asm_immi(offset, R0); // 1. offset -> R0 + } + else { + // Worst case. + underrunProtect(2 * sizeof(NIns)); + SH4_movl_indRx(value_reg, Rtemp); // 3. value -> @(temp) + SH4_add(base_reg, Rtemp); // 2. base + temp -> temp + asm_immi(offset, Rtemp); // 1. offset -> temp + } + } + } + +#define gen_asm_storeXXi(size, length) \ + void Assembler::asm_store ## size ## i(Register value_reg, int offset, Register base_reg) { \ + if (offset == 0) { \ + /* No displacement. */ \ + underrunProtect(1 * sizeof(NIns)); \ + SH4_mov ## length ## _indRx(value_reg, base_reg); \ + } \ + else if (FITS_SH4_mov ## length ## _R0_dispRx(offset)) { \ + /* The displacement is small enough to fit into the */ \ + /* special #size bits store "R0 -> @(base + offset)". */ \ + if (value_reg == R0) { \ + /* We are lucky, the value is R0. */ \ + NanoAssertMsg(0, "not yet tested."); \ + \ + underrunProtect(1 * sizeof(NIns)); \ + SH4_mov ## length ## _R0_dispRx(offset, base_reg); /* R0 -> @(base + offset) */ \ + } else { \ + /* We have to save and restore R0. */ \ + NanoAssertMsg(0, "not yet tested."); \ + \ + underrunProtect(4 * sizeof(NIns)); \ + SH4_mov(Rtemp, R0); /* 4. Rtemp -> R0 */ \ + SH4_mov ## length ## _R0_dispRx(offset, base_reg); /* 3. R0 -> @(base + offset) */ \ + SH4_mov(value_reg, R0); /* 2. value -> R0 */ \ + SH4_mov(R0, Rtemp); /* 1. R0 -> Rtemp */ \ + } \ + } \ + else { \ + /* Worst case. */ \ + underrunProtect(2 * sizeof(NIns)); \ + SH4_mov ## length ## _indRx(value_reg, Rtemp); /* 3. value -> @(temp) */ \ + SH4_add(base_reg, Rtemp); /* 2. base + temp -> temp */ \ + asm_immi(offset, Rtemp); /* 1. offset -> temp */ \ + } \ + } + + gen_asm_storeXXi(16, w) + gen_asm_storeXXi(8, b) + + void Assembler::asm_store32(LOpcode opcode, LIns *value, int offset, LIns *base) { + Register value_reg; + Register base_reg; + + getBaseReg2(GpRegs, value, value_reg, GpRegs, base, base_reg, offset); + + switch (opcode) { + case LIR_sti: + asm_store32i(value_reg, offset, base_reg); + break; + case LIR_sti2s: + asm_store16i(value_reg, offset, base_reg); + break; + case LIR_sti2c: + asm_store8i(value_reg, offset, base_reg); + break; + default: + NanoAssertMsg(0, "asm_store32 should never receive this LIR opcode"); + return; + } + } + + void Assembler::asm_store64d(Register value_reg, int offset, Register base_reg) { + underrunProtect(2 * sizeof(NIns)); + + // 2. Store the "double" to @Rtemp. + SH4_fmovs_decRx(value_reg + 1, Rtemp); + SH4_fmovs_decRx(value_reg, Rtemp); + + // Adjust the offset since we are using a post decrement (by 4) indirect loads. + offset += 8; + + // 1. base + offset -> Rtemp. + asm_base_offset(offset, base_reg); + } + + void Assembler::asm_store32d(Register value_reg, int offset, Register base_reg) { + underrunProtect(3 * sizeof(NIns)); + + // 3. Store the "float" to @Rtemp. + SH4_fmovs_indRx(Dtemp, Rtemp); + + // 2. Convert back to simple precision. + SH4_fsts_FPUL(Dtemp); + SH4_fcnvds_double_FPUL(value_reg); + + // 1. base + offset -> Rtemp. + asm_base_offset(offset, base_reg); + } + + void Assembler::asm_store64(LOpcode opcode, LIns *value, int offset, LIns *base) { + Register value_reg; + Register base_reg; + + // If "value" is already in a register, use that one. + value_reg = ( value->isInReg() ? value->getReg() : findRegFor(value, FpRegs) ); + base_reg = getBaseReg(base, offset, GpRegs); + + switch (opcode) { + case LIR_std: + asm_store64d(value_reg, offset, base_reg); + break; + case LIR_std2f: + asm_store32d(value_reg, offset, base_reg); + break; + default: + NanoAssertMsg(0, "asm_store64 should never receive this LIR opcode"); + } + } + +#ifdef NJ_VERBOSE + void Assembler::asm_inc_m32(uint32_t *counter) { + NIns *over_constant = NULL; + NIns *constant_addr = NULL; + + // Increment the 32-bit profiling counter without changing any registers. + + underrunProtect(11 * sizeof(NIns)); + + // 6. restore the register used as a pointer to the counter + SH4_movl_incRy(SP, R0); + + // 5. (*counter)++ + SH4_movl_indRx(Rtemp, R0); + SH4_add_imm(1, Rtemp); + SH4_movl_indRy(R0, Rtemp); + + over_constant = _nIns; + // 4. align the constant with nop + if (((uint32_t)_nIns & 0x3) != 0) + SH4_nop(); + + // 3. constant (== counter address) + SH4_emit32((uint32_t)counter); + constant_addr = _nIns; + + // 2. branch over the constant + SH4_nop(); + SH4_bra(SH4_LABEL(over_constant)); + + // 1. @(PC + offset) -> R0 + SH4_movl_PCrel(constant_addr, R0); + + // 0. R0 will be used as a pointer to the counter + SH4_movl_decRx(R0, SP); + } +#endif + + void Assembler::asm_cmp(LOpcode simplified_opcode, LIns *condition) { + LIns *operand1 = condition->oprnd1(); + LIns *operand2 = condition->oprnd2(); + + Register operand1_reg; + Register operand2_reg; + + if (isCmpDOpcode(simplified_opcode)) + findRegFor2(FpRegs, operand1, operand1_reg, FpRegs, operand2, operand2_reg); + else + findRegFor2(GpRegs, operand1, operand1_reg, GpRegs, operand2, operand2_reg); + + underrunProtect(3 * sizeof(NIns)); + + switch(simplified_opcode) { + case LIR_eqi : SH4_cmpeq(operand2_reg, operand1_reg); break; + case LIR_gti : SH4_cmpgt(operand2_reg, operand1_reg); break; + case LIR_gei : SH4_cmpge(operand2_reg, operand1_reg); break; + case LIR_gtui : SH4_cmphi(operand2_reg, operand1_reg); break; + case LIR_geui : SH4_cmphs(operand2_reg, operand1_reg); break; + + case LIR_eqd : SH4_fcmpeq_double(operand2_reg, operand1_reg); break; + case LIR_gtd : SH4_fcmpgt_double(operand2_reg, operand1_reg); break; + case LIR_ltd : SH4_fcmpgt_double(operand1_reg, operand2_reg); break; + + case LIR_ged : { /* (A >= B) <==> ((A == B) || (A > B)) */ + NIns *end_of_test = _nIns; + SH4_fcmpeq_double(operand2_reg, operand1_reg); // 3. A == B ? + SH4_bt(SH4_LABEL(end_of_test)); // 2. skip to preserve T-bit. + SH4_fcmpgt_double(operand2_reg, operand1_reg); // 1. A > B ? + } + break; + + case LIR_led : { /* (A <= B) <==> ((A == B) || (B > A)) */ + NIns *end_of_test = _nIns; + SH4_fcmpeq_double(operand2_reg, operand1_reg); // 2. A == B ? + SH4_bt(SH4_LABEL(end_of_test)); // 2. skip to preserve T-bit. + SH4_fcmpgt_double(operand1_reg, operand2_reg); // 1. B > A ? + } + break; + + default: + NanoAssertMsg(0, "asm_cmp should never receive this LIR opcode"); + } + } + + NIns* Assembler::asm_branch_ov(LOpcode opcode, NIns* target) { + NIns *patch_target = NULL; + + if (opcode == LIR_mulxovi || opcode == LIR_muljovi) { + patch_target = asm_branch(false, target); + + underrunProtect(3 * sizeof(NIns)); + + // Remember the T-bit is equal to : + // sign_of(result_reg) == sign_of(operand1) XOR sign_of(operand2) + + SH4_tst(Rtemp, Rtemp); // 3. test Rtemp == 0, hence asm_branch(false) + SH4_rotcl(Rtemp); // 2. Rtemp << 1 + T-Bit -> Rtemp + SH4_sts_MACH(Rtemp); // 1. Hi32(MAC) -> Rtemp + } + else + patch_target = asm_branch(true, target); + + return patch_target; + } + + bool Assembler::simplifyOpcode(LOpcode &opcode) { + bool negated= false; + + // Those following opcodes do not exist on SH4, so we have + // to reverse the test: + switch(opcode) { + case LIR_lti: + opcode = LIR_gei; + negated = true; + break; + + case LIR_lei: + opcode = LIR_gti; + negated = true; + break; + + case LIR_ltui: + opcode = LIR_geui; + negated = true; + break; + + case LIR_leui: + opcode = LIR_gtui; + negated = true; + break; + + default: + break; + } + + return negated; + } + + NIns *Assembler::asm_branch(bool test, NIns *target) { + NIns *patch_target = NULL; + + underrunProtect(3 * sizeof(NIns)); + + // Try to select the optimal branch code sequence. + if (target != NULL && FITS_SH4_bt(SH4_LABEL(target))) { + // The target is close enough to be reached thanks to one + // instruction only. Note: FITS_SH4_bf <==> FITS_SH4_bt + if (test == true) + SH4_bt(SH4_LABEL(target)); + else + SH4_bf(SH4_LABEL(target)); + + return NULL; + } + else if (false && target != NULL && FITS_SH4_bra(SH4_LABEL(target))) { + // TODO: The target is not so far we can reach it with a unconditional + // branch wrapped around by a reversed branch. + NanoAssert(0); // TBD + return NULL; + } + + // Otherwise it's the worst case. + + NIns *over_jump = _nIns; + // 3. branch @target_reg + SH4_nop(); + SH4_jmp_indRx(Rtemp); + + // TODO: Reverse 1. and 2. to avoid an unconditional load. + // When doing this, be careful with underrunProtect() and asm_immi()! + + // 2. branch over 3. if true (negated test) + if (test == true) + SH4_bf(SH4_LABEL(over_jump)); + else + SH4_bt(SH4_LABEL(over_jump)); + + // 1. target -> target_reg + asm_immi((int)target, Rtemp, true); + patch_target = _nIns; + + return patch_target; + } + + NIns *Assembler::asm_branch(bool branchOnFalse, LIns *condition, NIns *target) { + NanoAssert(condition->isCmp()); + + LOpcode opcode = condition->opcode(); + bool negated = simplifyOpcode(opcode); + + NIns *patch_target = asm_branch(negated ? branchOnFalse : !branchOnFalse, target); + + asm_cmp(opcode, condition); + + return patch_target; + } + + void Assembler::nBeginAssembly() { + max_stack_args = 0; + } + + void Assembler::nFragExit(LIns *guard) { + Fragment *target = guard->record()->exit->target; + GuardRecord *guard_record = NULL; + + // Jump tables are not yet supported. + NanoAssert(!guard->isop(LIR_xtbl)); + + // 3. Jump to the target fragment. + if (target && target->fragEntry) + JMP(target->fragEntry); + else { + // The target fragment doesn't exist yet, so emit a jump to the epilogue. + // If the target is created later on, the jump will be patched. + if (!_epilogue) + _epilogue = genEpilogue(); + + underrunProtect(2 * sizeof(NIns)); + + // Use a branch code sequence patchable by nPatchBranch(), + // that is, with a constant pool instead of an immediate. + SH4_nop(); + SH4_jmp_indRx(Rtemp); + asm_immi((int)_epilogue, Rtemp, true); + + guard_record = guard->record(); + guard_record->jmp = _nIns; + } + + // Profiling for the exit. + verbose_only( + if (_logc->lcbits & LC_FragProfile) + asm_inc_m32(&guard->record()->profCount); + ) + + // 2. Restore the stack pointer. + MR(SP, FP); + + // 1. Set the return value. + asm_immi((int)guard_record, R0); + } + + void Assembler::nInit(avmplus::AvmCore*) { + int fpscr = 0; + + __asm__ __volatile__ ("sts fpscr, %0": "=r" (fpscr)); + + // Only the 'double' precision mode is currently supported within Nano/SH4. + NanoAssert((fpscr & (1 << 19)) != 0); + + // Only the 'simple' transfer size mode is currently supported within Nano/SH4. + NanoAssert((fpscr & (1 << 20)) == 0); + + // Declare prefered registers for some specific opcodes. + nHints[LIR_calli] = rmask(retRegs[0]); + nHints[LIR_calld] = rmask(retDregs[0]); + nHints[LIR_paramp] = PREFER_SPECIAL; + } + + // Keep in sync' with LARGEST_BRANCH_PATCH. + void Assembler::nPatchBranch(NIns *branch, NIns *target) { + // TODO: Try to relax this branch sequence: + // + // mov.l @(PC, 6), rX + // bra +6 + // nop + // .word tar- + // .word -get + // nop + // + // with: + // + // bra @(PC - target) + // nop + // nop + // nop + // nop + // nop + + // Adjust the address to point to the constant (three instructions below). + branch += 3; + + // Patch the constant. + *((uint32_t *)(void *)branch) = (uint32_t) target; + } + + Register Assembler::nRegisterAllocFromSet(RegisterMask set) { + Register reg; + + // Find the first register in this set. + reg = lsReg(set); + + _allocator.free &= ~rmask(reg); + + // Sanity check. + NanoAssert((rmask(reg) & set) == rmask(reg)); + + return reg; + } + + void Assembler::nRegisterResetAll(RegAlloc& regs) { + regs.clear(); + regs.free = GpRegs | FpRegs; + } + + // Keep in sync' with Assembler::asm_param(). + NIns* Assembler::genPrologue() { + int frame_size = max_stack_args + _activation.stackSlotsNeeded() * STACK_GRANULARITY; + frame_size = -alignUp(frame_size, NJ_ALIGN_STACK); + + // 5. Allocate enough room on stack for our busyness. + if (frame_size != 0) { + underrunProtect(1 * sizeof(NIns)); + if (FITS_SH4_add_imm(frame_size)) + SH4_add_imm(frame_size, SP); + else { + // We use R0 since it's not used for regular arguments, + // and is otherwise clobberred by the call. + SH4_add(R0, SP); + asm_immi(frame_size, R0); + } + } + + underrunProtect(3 * sizeof(NIns)); + NIns *patchEntry = _nIns; + + // 3. Set the frame pointer. + SH4_mov(SP, FP); + + // 2. Save the return address. + SH4_stsl_PR_decRx(SP); + + // 1. Save the previous frame pointer. + SH4_movl_decRx(FP, SP); + + return patchEntry; + } + + RegisterMask Assembler::nHint(LIns* inst) { + RegisterMask prefer = 0; + + NanoAssert(inst->isop(LIR_paramp)); + if (inst->paramKind() == 0) + if (inst->paramArg() < 4) + prefer = rmask(argRegs[inst->paramArg()]); + + return prefer; + } + + void Assembler::swapCodeChunks() { + if (!_nExitIns) + codeAlloc(exitStart, exitEnd, _nExitIns verbose_only(, exitBytes)); + + SWAP(NIns*, _nIns, _nExitIns); + SWAP(NIns*, codeStart, exitStart); + SWAP(NIns*, codeEnd, exitEnd); + + verbose_only( SWAP(size_t, codeBytes, exitBytes); ) + } + + void Assembler::underrunProtect(int nb_bytes) { + NanoAssertMsg(nb_bytes <= LARGEST_UNDERRUN_PROT, "constant LARGEST_UNDERRUN_PROT is too small"); + + NIns *pc = _nIns; + if (_nIns - nb_bytes < codeStart) { + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes)); + + // This jump will call underrunProtect again, but since we're on + // a new page large enough to host its code, nothing will happen. + JMP(pc, true); + } + } + + void Assembler::asm_insert_random_nop() { + NanoAssert(0); // not supported + } + +} +#endif // FEATURE_NANOJIT && FEATURE_SH4 diff --git a/js/src/nanojit/NativeSH4.h b/js/src/nanojit/NativeSH4.h new file mode 100644 index 0000000..ed51c36 --- /dev/null +++ b/js/src/nanojit/NativeSH4.h @@ -0,0 +1,463 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * STMicroelectronics. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Cédric VINCENT for STMicroelectronics + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __nanojit_NativeSH4__ +#define __nanojit_NativeSH4__ + +#include "NativeCommon.h" + +namespace nanojit +{ + /*********************************************************************** + * Definitions for the register allocation. + */ + + // General purpose and ABI registers. + + // Scratch registers (a.k.a caller-saved, a.k.a local). + static const Register R0 = { 0 }; + static const Register R1 = { 1 }; + static const Register R2 = { 2 }; + static const Register R3 = { 3 }; // Excluded from the regalloc because of its use as a hyper-scratch. + static const Register R4 = { 4 }; + static const Register R5 = { 5 }; + static const Register R6 = { 6 }; + static const Register R7 = { 7 }; + + // Saved registers (a.k.a callee-saved, a.k.a global). + static const Register R8 = { 8 }; + static const Register R9 = { 9 }; + static const Register R10 = { 10 }; + static const Register R11 = { 11 }; + static const Register R12 = { 12 }; + static const Register R13 = { 13 }; + + // ABI registers, excluded from the register allocation. + static const Register FP = { 14 }; + static const Register SP = { 15 }; + + // Floatting-point registers. + static const Register _D0 = { 16 }; + static const Register _F0 = _D0; + static const Register _F1 = { 17 }; + static const Register _D1 = { 18 }; + static const Register _F2 = _D1; + static const Register _F3 = { 19 }; + static const Register _D2 = { 20 }; + static const Register _F4 = _D2; + static const Register _F5 = { 21 }; + static const Register _D3 = { 22 }; + static const Register _F6 = _D3; + static const Register _F7 = { 23 }; + static const Register _D4 = { 24 }; + static const Register _F8 = _D4; + static const Register _F9 = { 25 }; + static const Register _D5 = { 26 }; + static const Register _F10 = _D5; + static const Register _F11 = { 27 }; + static const Register _D6 = { 28 }; + static const Register _F12 = _D6; + static const Register _F13 = { 29 }; + static const Register _D7 = { 30 }; + static const Register _F14 = _D7; // Excluded from the regalloc because of its use as a hyper-scratch. + static const Register _F15 = { 31 }; + + // Helpers. + static const Register deprecated_UnknownReg = { 32 }; + static const Register UnspecifiedReg = { 32 }; + static const Register Rtemp = R3; + static const Register Dtemp = _D7; + + static const uint32_t FirstRegNum = 0; + static const uint32_t LastRegNum = 30; +} + +#define NJ_USE_UINT32_REGISTER 1 +#include "NativeCommon.h" + +namespace nanojit +{ + // There's 16 integer registers + 8 double registers on SH4. + typedef uint32_t RegisterMask; + + static const int NumSavedRegs = 6; + static const RegisterMask SavedRegs = ((1<int conversion. +#define NJ_F2I_SUPPORTED 1 + +} + +#endif /* __nanojit_NativeSH4__ */ diff --git a/js/src/nanojit/NativeSparc.cpp b/js/src/nanojit/NativeSparc.cpp new file mode 100644 index 0000000..029a22a --- /dev/null +++ b/js/src/nanojit/NativeSparc.cpp @@ -0,0 +1,1646 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * leon.sha@oracle.com + * ginn.chen@oracle.com + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include "nanojit.h" + +namespace nanojit +{ +#ifdef FEATURE_NANOJIT + +#ifdef NJ_VERBOSE + const char *regNames[] = { + "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7", + "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7", + "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", + "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7", + "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", + "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15", + "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23", + "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31" + }; +#endif + + const Register Assembler::argRegs[] = { I0, I1, I2, I3, I4, I5 }; + const Register Assembler::retRegs[] = { O0 }; + const Register Assembler::savedRegs[] = { L1 }; // Dummy element not used, as NumSavedRegs == 0 + + static const int kLinkageAreaSize = 68; + static const int kcalleeAreaSize = 80; // The max size. + +#define BIT_ROUND_UP(v,q) ( (((uintptr_t)v)+(q)-1) & ~((q)-1) ) +#define TODO(x) do{ verbose_only(outputf(#x);) NanoAssertMsgf(false, "%s", #x); } while(0) + + inline void Assembler::CALL(const CallInfo* ci) { + int32_t offset = (ci->_address) - ((int32_t)_nIns) + 4; + int32_t i = 0x40000000 | ((offset >> 2) & 0x3FFFFFFF); + IMM32(i); + asm_output("call %s",(ci->_name)); + } + + inline void Assembler::IntegerOperation + (Register rs1, Register rs2, Register rd, int32_t op3, const char *opcode) { + Format_3_1(2, rd, op3, rs1, 0, rs2); + asm_output("%s %s, %s, %s", opcode, gpn(rs1), gpn(rs2), gpn(rd)); + } + + inline void Assembler::IntegerOperationI + (Register rs1, int32_t simm13, Register rd, int32_t op3, const char *opcode) { + Format_3_1I(2, rd, op3, rs1, simm13); + asm_output("%s %s, %d, %s", opcode, gpn(rs1), simm13, gpn(rd)); + } + + inline void Assembler::ADD(Register rs1, Register rs2, Register rd) { + IntegerOperation(rs1, rs2, rd, 0, "add"); + } + inline void Assembler::ADDCC(Register rs1, Register rs2, Register rd) { + IntegerOperation(rs1, rs2, rd, 0x10, "addcc"); + } + inline void Assembler::AND(Register rs1, Register rs2, Register rd) { + IntegerOperation(rs1, rs2, rd, 0x1, "and"); + } + inline void Assembler::ANDCC(Register rs1, Register rs2, Register rd) { + IntegerOperation(rs1, rs2, rd, 0x11, "andcc"); + } + inline void Assembler::OR(Register rs1, Register rs2, Register rd) { + IntegerOperation(rs1, rs2, rd, 0x2, "or"); + } + inline void Assembler::ORI(Register rs1, int32_t simm13, Register rd) { + IntegerOperationI(rs1, simm13, rd, 0x2, "or"); + } + inline void Assembler::ORN(Register rs1, Register rs2, Register rd) { + IntegerOperation(rs1, rs2, rd, 0x6, "orn"); + } + inline void Assembler::SMULCC(Register rs1, Register rs2, Register rd) { + IntegerOperation(rs1, rs2, rd, 0x1b, "smulcc"); + } + inline void Assembler::SUB(Register rs1, Register rs2, Register rd) { + IntegerOperation(rs1, rs2, rd, 0x4, "sub"); + } + inline void Assembler::SUBCC(Register rs1, Register rs2, Register rd) { + IntegerOperation(rs1, rs2, rd, 0x14, "subcc"); + } + inline void Assembler::SUBI(Register rs1, int32_t simm13, Register rd) { + IntegerOperationI(rs1, simm13, rd, 0x4, "sub"); + } + inline void Assembler::XOR(Register rs1, Register rs2, Register rd) { + IntegerOperation(rs1, rs2, rd, 0x3, "xor"); + } + + inline void Assembler::Bicc(int32_t a, int32_t dsp22, int32_t cond, const char *opcode) { + Format_2_2(a, cond, 0x2, dsp22); + asm_output("%s 0x%x", opcode, _nIns + dsp22 - 1); + } + + inline void Assembler::BA (int32_t a, int32_t dsp22) { Bicc(a, dsp22, 0x8, "ba"); } + inline void Assembler::BE (int32_t a, int32_t dsp22) { Bicc(a, dsp22, 0x1, "be"); } + inline void Assembler::BNE (int32_t a, int32_t dsp22) { Bicc(a, dsp22, 0x9, "bne"); } + inline void Assembler::BG (int32_t a, int32_t dsp22) { Bicc(a, dsp22, 0xa, "bg"); } + inline void Assembler::BGU (int32_t a, int32_t dsp22) { Bicc(a, dsp22, 0xc, "bgu"); } + inline void Assembler::BGE (int32_t a, int32_t dsp22) { Bicc(a, dsp22, 0xb, "bge"); } + inline void Assembler::BL (int32_t a, int32_t dsp22) { Bicc(a, dsp22, 0x3, "bl"); } + inline void Assembler::BLE (int32_t a, int32_t dsp22) { Bicc(a, dsp22, 0x2, "ble"); } + inline void Assembler::BLEU(int32_t a, int32_t dsp22) { Bicc(a, dsp22, 0x4, "bleu"); } + inline void Assembler::BCC (int32_t a, int32_t dsp22) { Bicc(a, dsp22, 0xd, "bcc"); } + inline void Assembler::BCS (int32_t a, int32_t dsp22) { Bicc(a, dsp22, 0x5, "bcs"); } + inline void Assembler::BVC (int32_t a, int32_t dsp22) { Bicc(a, dsp22, 0xf, "bvc"); } + inline void Assembler::BVS (int32_t a, int32_t dsp22) { Bicc(a, dsp22, 0x7, "bvs"); } + + inline void Assembler::FABSS(Register rs2, Register rd) { + Format_3_8(2, rd, 0x34, G0, 0x9, rs2); + asm_output("fabs %s, %s", gpn(rs2), gpn(rd)); + } + + inline void Assembler::FADDD(Register rs1, Register rs2, Register rd) { + Format_3_8(2, rd, 0x34, rs1, 0x42, rs2); + asm_output("faddd %s, %s, %s", gpn(rs1), gpn(rs2), gpn(rd)); + } + + inline void Assembler::FBfcc(int32_t a, int32_t dsp22, int32_t cond, const char *opcode) { + Format_2_2(a, cond, 0x6, dsp22); + asm_output("%s 0x%x", opcode, _nIns + dsp22 - 1); + } + + inline void Assembler::FBE (int32_t a, int32_t dsp22) { FBfcc(a, dsp22, 0x9, "fbe"); } + inline void Assembler::FBNE (int32_t a, int32_t dsp22) { FBfcc(a, dsp22, 0x1, "fbne"); } + inline void Assembler::FBUE (int32_t a, int32_t dsp22) { FBfcc(a, dsp22, 0xa, "fbue"); } + inline void Assembler::FBG (int32_t a, int32_t dsp22) { FBfcc(a, dsp22, 0x6, "fbg"); } + inline void Assembler::FBUG (int32_t a, int32_t dsp22) { FBfcc(a, dsp22, 0x5, "fbug"); } + inline void Assembler::FBGE (int32_t a, int32_t dsp22) { FBfcc(a, dsp22, 0xb, "fbge"); } + inline void Assembler::FBUGE(int32_t a, int32_t dsp22) { FBfcc(a, dsp22, 0xc, "fbuge"); } + inline void Assembler::FBL (int32_t a, int32_t dsp22) { FBfcc(a, dsp22, 0x4, "fbl"); } + inline void Assembler::FBUL (int32_t a, int32_t dsp22) { FBfcc(a, dsp22, 0x3, "fbul"); } + inline void Assembler::FBLE (int32_t a, int32_t dsp22) { FBfcc(a, dsp22, 0xd, "fble"); } + inline void Assembler::FBULE(int32_t a, int32_t dsp22) { FBfcc(a, dsp22, 0xe, "fbule"); } + + inline void Assembler::FCMPD(Register rs1, Register rs2) { + Format_3_9(2, 0, 0, 0x35, rs1, 0x52, rs2); + asm_output("fcmpd %s, %s", gpn(rs1), gpn(rs2)); + } + + inline void Assembler::FloatOperation + (Register rs1, Register rs2, Register rd, int32_t opf, const char *opcode) { + Format_3_8(2, rd, 0x34, rs1, opf, rs2); + if (rs1 != G0) { + asm_output("%s %s, %s, %s", opcode, gpn(rs1), gpn(rs2), gpn(rd)); + } else { + asm_output("%s %s, %s", opcode, gpn(rs2), gpn(rd)); + } + } + + inline void Assembler::FSUBD(Register rs1, Register rs2, Register rd) { + FloatOperation(rs1, rs2, rd, 0x46, "fsubd"); + } + inline void Assembler::FMULD(Register rs1, Register rs2, Register rd) { + FloatOperation(rs1, rs2, rd, 0x4a, "fsubd"); + } + inline void Assembler::FDTOI(Register rs2, Register rd) { + FloatOperation(G0, rs2, rd, 0xd2, "fdtoi"); + } + inline void Assembler::FDIVD(Register rs1, Register rs2, Register rd) { + FloatOperation(rs1, rs2, rd, 0x4e, "fdivd"); + } + inline void Assembler::FMOVD(Register rs2, Register rd) { + FloatOperation(G0, rs2, rd, 0x2, "fmovd"); + } + inline void Assembler::FNEGD(Register rs2, Register rd) { + FloatOperation(G0, rs2, rd, 0x6, "fnegd"); + } + inline void Assembler::FITOD(Register rs2, Register rd) { + FloatOperation(G0, rs2, rd, 0xc8, "fitod"); + } + inline void Assembler::FDTOS(Register rs2, Register rd) { + FloatOperation(G0, rs2, rd, 0xc6, "fdtos"); + } + inline void Assembler::FSTOD(Register rs2, Register rd) { + FloatOperation(G0, rs2, rd, 0xc9, "fstod"); + } + + inline void Assembler::JMPL(Register rs1, Register rs2, Register rd) { + Format_3_1(2, rd, 0x38, rs1, 0, rs2); + asm_output("jmpl [%s + %s]", gpn(rs1), gpn(rs2)); + } + + inline void Assembler::JMPLI(Register rs1, int32_t simm13, Register rd) { + Format_3_1I(2, rd, 0x38, rs1, simm13); + asm_output("jmpl [%s + 0x%x]", gpn(rs1), simm13); + } + + inline void Assembler::LoadOperation + (Register rs1, Register rs2, Register rd, int32_t op3, const char* opcode) { + Format_3_1(3, rd, op3, rs1, 0, rs2); + asm_output("%s [%s + %s], %s", opcode, gpn(rs1), gpn(rs2), gpn(rd)); + } + + inline void Assembler::LoadOperationI + (Register rs1, int32_t simm13, Register rd, int32_t op3, const char* opcode) { + Format_3_1I(3, rd, op3, rs1, simm13); + asm_output("%s [%s + 0x%x], %s", opcode, gpn(rs1), simm13, gpn(rd)); + } + + inline void Assembler::LDF(Register rs1, Register rs2, Register rd) { + LoadOperation(rs1, rs2, rd, 0x20, "ldf"); + } + inline void Assembler::LDFI(Register rs1, int32_t simm13, Register rd) { + LoadOperationI(rs1, simm13, rd, 0x20, "ldf"); + } + + inline void Assembler::LDF32(Register rs1, int32_t immI, Register rd) { + if (isIMM13(immI)) { + LDFI(rs1, immI, rd); + } else { + LDF(rs1, L0, rd); + SET32(immI, L0); + } + } + + inline void Assembler::LDDF32(Register rs1, int32_t immI, Register rd) { + if (isIMM13(immI+4)) { + LDFI(rs1, immI+4, rd + 1); + LDFI(rs1, immI, rd); + } else { + LDF(rs1, L0, rd + 1); + SET32(immI+4, L0); + LDF(rs1, L0, rd); + SET32(immI, L0); + } + } + + inline void Assembler::LDUB(Register rs1, Register rs2, Register rd) { + LoadOperation(rs1, rs2, rd, 0x1, "ldub"); + } + inline void Assembler::LDUBI(Register rs1, int32_t simm13, Register rd) { + LoadOperationI(rs1, simm13, rd, 0x1, "ldub"); + } + + inline void Assembler::LDUB32(Register rs1, int32_t immI, Register rd) { + if (isIMM13(immI)) { + LDUBI(rs1, immI, rd); + } else { + LDUB(rs1, L0, rd); + SET32(immI, L0); + } + } + + inline void Assembler::LDSB(Register rs1, Register rs2, Register rd) { + LoadOperation(rs1, rs2, rd, 0x9, "ldsb"); + } + inline void Assembler::LDSBI(Register rs1, int32_t simm13, Register rd) { + LoadOperationI(rs1, simm13, rd, 0x9, "ldsb"); + } + + inline void Assembler::LDSB32(Register rs1, int32_t immI, Register rd) { + if (isIMM13(immI)) { + LDSBI(rs1, immI, rd); + } else { + LDSB(rs1, L0, rd); + SET32(immI, L0); + } + } + + inline void Assembler::LDUH(Register rs1, Register rs2, Register rd) { + LoadOperation(rs1, rs2, rd, 0x2, "lduh"); + } + inline void Assembler::LDUHI(Register rs1, int32_t simm13, Register rd) { + LoadOperationI(rs1, simm13, rd, 0x2, "lduh"); + } + + inline void Assembler::LDUH32(Register rs1, int32_t immI, Register rd) { + if (isIMM13(immI)) { + LDUHI(rs1, immI, rd); + } else { + LDUH(rs1, L0, rd); + SET32(immI, L0); + } + } + + inline void Assembler::LDSH(Register rs1, Register rs2, Register rd) { + LoadOperation(rs1, rs2, rd, 0xa, "ldsh"); + } + inline void Assembler::LDSHI(Register rs1, int32_t simm13, Register rd) { + LoadOperationI(rs1, simm13, rd, 0xa, "ldsh"); + } + + inline void Assembler::LDSH32(Register rs1, int32_t immI, Register rd) { + if (isIMM13(immI)) { + LDSHI(rs1, immI, rd); + } else { + LDSH(rs1, L0, rd); + SET32(immI, L0); + } + } + + inline void Assembler::LDSW(Register rs1, Register rs2, Register rd) { + LoadOperation(rs1, rs2, rd, 0x8, "ldsw"); + } + inline void Assembler::LDSWI(Register rs1, int32_t simm13, Register rd) { + LoadOperationI(rs1, simm13, rd, 0x8, "ldsw"); + } + + inline void Assembler::LDSW32(Register rs1, int32_t immI, Register rd) { + if (isIMM13(immI)) { + LDSWI(rs1, immI, rd); + } else { + LDSW(rs1, L0, rd); + SET32(immI, L0); + } + } + + inline void Assembler::MOVcc + (Register rs, int32_t cc2, int32_t cc1, int32_t cc0, Register rd, int32_t cond, const char *opcode) { + Format_4_2(rd, 0x2c, cc2, cond, cc1, cc0, rs); + asm_output("%s %s, %s", opcode, gpn(rs), gpn(rd)); + } + + inline void Assembler::MOVccI + (int32_t simm11, int32_t cc2, int32_t cc1, int32_t cc0, Register rd, int32_t cond, const char *opcode) { + Format_4_2I(rd, 0x2c, cc2, cond, cc1, cc0, simm11); + asm_output("%s 0x%x, %s", opcode, simm11, gpn(rd)); + } + + inline void Assembler::MOVE (Register rs, Register rd) { MOVcc(rs, 1, 0, 0, rd, 0x1, "move"); } + inline void Assembler::MOVNE (Register rs, Register rd) { MOVcc(rs, 1, 0, 0, rd, 0x9, "movne"); } + inline void Assembler::MOVL (Register rs, Register rd) { MOVcc(rs, 1, 0, 0, rd, 0x3, "movl"); } + inline void Assembler::MOVLE (Register rs, Register rd) { MOVcc(rs, 1, 0, 0, rd, 0x2, "movle"); } + inline void Assembler::MOVG (Register rs, Register rd) { MOVcc(rs, 1, 0, 0, rd, 0xa, "movg"); } + inline void Assembler::MOVGE (Register rs, Register rd) { MOVcc(rs, 1, 0, 0, rd, 0xb, "movge"); } + inline void Assembler::MOVLEU(Register rs, Register rd) { MOVcc(rs, 1, 0, 0, rd, 0x4, "movleu"); } + inline void Assembler::MOVGU (Register rs, Register rd) { MOVcc(rs, 1, 0, 0, rd, 0xc, "movgu"); } + inline void Assembler::MOVCC (Register rs, Register rd) { MOVcc(rs, 1, 0, 0, rd, 0xd, "movcc"); } + inline void Assembler::MOVCS (Register rs, Register rd) { MOVcc(rs, 1, 0, 0, rd, 0x5, "movcs"); } + inline void Assembler::MOVVC (Register rs, Register rd) { MOVcc(rs, 1, 0, 0, rd, 0xf, "movvc"); } + inline void Assembler::MOVEI (int32_t simm11, Register rd) { MOVccI(simm11, 1, 0, 0, rd, 0x1, "move"); } + inline void Assembler::MOVNEI (int32_t simm11, Register rd) { MOVccI(simm11, 1, 0, 0, rd, 0x9, "movne"); } + inline void Assembler::MOVLI (int32_t simm11, Register rd) { MOVccI(simm11, 1, 0, 0, rd, 0x3, "movl"); } + inline void Assembler::MOVLEI (int32_t simm11, Register rd) { MOVccI(simm11, 1, 0, 0, rd, 0x2, "movle"); } + inline void Assembler::MOVGI (int32_t simm11, Register rd) { MOVccI(simm11, 1, 0, 0, rd, 0xa, "movg"); } + inline void Assembler::MOVGEI (int32_t simm11, Register rd) { MOVccI(simm11, 1, 0, 0, rd, 0xb, "movge"); } + inline void Assembler::MOVLEUI(int32_t simm11, Register rd) { MOVccI(simm11, 1, 0, 0, rd, 0x4, "movleu"); } + inline void Assembler::MOVGUI (int32_t simm11, Register rd) { MOVccI(simm11, 1, 0, 0, rd, 0xc, "movgu"); } + inline void Assembler::MOVCCI (int32_t simm11, Register rd) { MOVccI(simm11, 1, 0, 0, rd, 0xd, "movcc"); } + inline void Assembler::MOVCSI (int32_t simm11, Register rd) { MOVccI(simm11, 1, 0, 0, rd, 0x5, "movcs"); } + inline void Assembler::MOVVSI (int32_t simm11, Register rd) { MOVccI(simm11, 1, 0, 0, rd, 0x7, "movvs"); } + inline void Assembler::MOVFEI (int32_t simm11, Register rd) { MOVccI(simm11, 0, 0, 0, rd, 0x9, "movfe"); } + inline void Assembler::MOVFLI (int32_t simm11, Register rd) { MOVccI(simm11, 0, 0, 0, rd, 0x4, "movfl"); } + inline void Assembler::MOVFLEI(int32_t simm11, Register rd) { MOVccI(simm11, 0, 0, 0, rd, 0xd, "movfle"); } + inline void Assembler::MOVFGI (int32_t simm11, Register rd) { MOVccI(simm11, 0, 0, 0, rd, 0x6, "movfg"); } + inline void Assembler::MOVFGEI(int32_t simm11, Register rd) { MOVccI(simm11, 0, 0, 0, rd, 0xb, "movfge"); } + + inline void Assembler::FMOVDcc(Register rs, int32_t opt_cc, Register rd, int32_t cond, const char *opcode) { + Format_4_5(rd, 0x35, cond, opt_cc, 0x2, rs); + asm_output("%s %s, %s", opcode, gpn(rs), gpn(rd)); + } + + inline void Assembler::FMOVDNE (Register rs, Register rd) { FMOVDcc(rs, 0x4, rd, 0x9, "fmovdne"); } + inline void Assembler::FMOVDL (Register rs, Register rd) { FMOVDcc(rs, 0x4, rd, 0x3, "fmovdl"); } + inline void Assembler::FMOVDLE (Register rs, Register rd) { FMOVDcc(rs, 0x4, rd, 0x2, "fmovdle"); } + inline void Assembler::FMOVDLEU (Register rs, Register rd) { FMOVDcc(rs, 0x4, rd, 0x4, "fmovdleu");} + inline void Assembler::FMOVDG (Register rs, Register rd) { FMOVDcc(rs, 0x4, rd, 0xa, "fmovdg"); } + inline void Assembler::FMOVDGU (Register rs, Register rd) { FMOVDcc(rs, 0x4, rd, 0xc, "fmovdgu"); } + inline void Assembler::FMOVDGE (Register rs, Register rd) { FMOVDcc(rs, 0x4, rd, 0xb, "fmovdfge");} + inline void Assembler::FMOVDCC (Register rs, Register rd) { FMOVDcc(rs, 0x4, rd, 0xd, "fmovdcc"); } + inline void Assembler::FMOVDCS (Register rs, Register rd) { FMOVDcc(rs, 0x4, rd, 0x5, "fmovdcs"); } + inline void Assembler::FMOVDFNE (Register rs, Register rd) { FMOVDcc(rs, 0x0, rd, 0x1, "fmovdfne"); } + inline void Assembler::FMOVDFUG (Register rs, Register rd) { FMOVDcc(rs, 0x0, rd, 0x5, "fmovdfug"); } + inline void Assembler::FMOVDFUGE(Register rs, Register rd) { FMOVDcc(rs, 0x0, rd, 0xc, "fmovdfuge");} + inline void Assembler::FMOVDFUL (Register rs, Register rd) { FMOVDcc(rs, 0x0, rd, 0x3, "fmovdful"); } + inline void Assembler::FMOVDFULE(Register rs, Register rd) { FMOVDcc(rs, 0x0, rd, 0xe, "fmovdfule");} + + inline void Assembler::NOP() { + Format_2(0, 0x4, 0); + asm_output("nop"); + } + + inline void Assembler::RDY(Register rd) { + Format_3_1(2, rd, 0x28, G0, 0, G0); + asm_output("rdy %s", gpn(rd)); + } + + inline void Assembler::RESTORE(Register rs1, Register rs2, Register rd) { + Format_3_1(2, rd, 0x3d, rs1, 0, rs2); + asm_output("restore"); + } + + inline void Assembler::SAVE(Register rs1, Register rs2, Register rd) { + IntegerOperation(rs1, rs2, rd, 0x3c, "save"); + } + inline void Assembler::SAVEI(Register rs1, int32_t simm13, Register rd) { + IntegerOperationI(rs1, simm13, rd, 0x3c, "save"); + } + + inline void Assembler::SETHI(int32_t immI, Register rd) { + Format_2A(rd, 0x4, immI >> 10); + asm_output("sethi 0x%x, %s ! 0x%x", immI >> 10, gpn(rd), immI); + } + + inline void Assembler::SET32(int32_t immI, Register rd) { + if (isIMM13(immI)) { + ORI(G0, immI, rd); + } else { + ORI(rd, immI & 0x3FF, rd); + SETHI(immI, rd); + } + } + + inline void Assembler::ShiftOperation + (Register rs1, Register rs2, Register rd, int32_t op3, const char* opcode) { + Format_3_5(2, rd, op3, rs1, 0, rs2); + asm_output("%s %s, %s, %s", opcode, gpn(rs1), gpn(rs2), gpn(rd)); + } + + inline void Assembler::ShiftOperationI + (Register rs1, int32_t shcnt32, Register rd, int32_t op3, const char* opcode) { + Format_3_6(2, rd, op3, rs1, shcnt32); + asm_output("%s %s, %d, %s", opcode, gpn(rs1), shcnt32, gpn(rd)); + } + + inline void Assembler::SLL(Register rs1, Register rs2, Register rd) { + ShiftOperation(rs1, rs2, rd, 0x25, "sll"); + } + inline void Assembler::SRA(Register rs1, Register rs2, Register rd) { + ShiftOperation(rs1, rs2, rd, 0x27, "sra"); + } + inline void Assembler::SRAI(Register rs1, int32_t shcnt32, Register rd) { + ShiftOperationI(rs1, shcnt32, rd, 0x27, "sra"); + } + inline void Assembler::SRL(Register rs1, Register rs2, Register rd) { + ShiftOperation(rs1, rs2, rd, 0x26, "srl"); + } + + inline void Assembler::Store + (Register rd, Register rs1, Register rs2, int32_t op3, const char* opcode) { + Format_3_1(3, rd, op3, rs1, 0, rs2); + asm_output("%s %s, [%s + %s]", opcode, gpn(rd), gpn(rs1), gpn(rs2)); + } + + inline void Assembler::StoreI + (Register rd, int32_t simm13, Register rs1, int32_t op3, const char* opcode) { + Format_3_1I(3, rd, op3, rs1, simm13); + asm_output("%s %s, [%s + 0x%x]", opcode, gpn(rd), gpn(rs1), simm13); + } + + inline void Assembler::STF(Register rd, Register rs1, Register rs2) { + Store(rd, rs1, rs2, 0x24, "stf"); + } + inline void Assembler::STFI(Register rd, int32_t simm13, Register rs1) { + StoreI(rd, simm13, rs1, 0x24, "stf"); + } + + inline void Assembler::STF32(Register rd, int32_t immI, Register rs1) { + if (isIMM13(immI)) { + STFI(rd, immI, rs1); + } else { + STF(rd, L0, rs1); + SET32(immI, L0); + } + } + + inline void Assembler::STDF32(Register rd, int32_t immI, Register rs1) { + if (isIMM13(immI+4)) { + STFI(rd + 1, immI+4, rs1); + STFI(rd, immI, rs1); + } else { + STF(rd + 1, L0, rs1); + SET32(immI+4, L0); + STF(rd, L0, rs1); + SET32(immI, L0); + } + } + + inline void Assembler::STW(Register rd, Register rs1, Register rs2) { + Store(rd, rs1, rs2, 0x4, "st"); + } + inline void Assembler::STWI(Register rd, int32_t simm13, Register rs1) { + StoreI(rd, simm13, rs1, 0x4, "st"); + } + + inline void Assembler::STW32(Register rd, int32_t immI, Register rs1) { + if (isIMM13(immI)) { + STWI(rd, immI, rs1); + } else { + STW(rd, L0, rs1); + SET32(immI, L0); + } + } + + inline void Assembler::STH(Register rd, Register rs1, Register rs2) { + Store(rd, rs1, rs2, 0x6, "sth"); + } + inline void Assembler::STHI(Register rd, int32_t simm13, Register rs1) { + StoreI(rd, simm13, rs1, 0x6, "sth"); + } + + inline void Assembler::STH32(Register rd, int32_t immI, Register rs1) { + if (isIMM13(immI)) { + STHI(rd, immI, rs1); + } else { + STH(rd, L0, rs1); + SET32(immI, L0); + } + } + + inline void Assembler::STB(Register rd, Register rs1, Register rs2) { + Store(rd, rs1, rs2, 0x5, "stb"); + } + inline void Assembler::STBI(Register rd, int32_t simm13, Register rs1) { + StoreI(rd, simm13, rs1, 0x5, "stb"); + } + + inline void Assembler::STB32(Register rd, int32_t immI, Register rs1) { + if (isIMM13(immI)) { + STBI(rd, immI, rs1); + } else { + STB(rd, L0, rs1); + SET32(immI, L0); + } + } + + // general Assemble + inline void Assembler::JMP_long_nocheck(int32_t t) { + NOP(); + JMPL(G0, G2, G0); + ORI(G2, t & 0x3FF, G2); + SETHI(t, G2); + } + + inline void Assembler::JMP_long(int32_t t) { + underrunProtect(16); + JMP_long_nocheck(t); + } + + inline void Assembler::JMP_long_placeholder() { + JMP_long(0); + } + + inline int32_t Assembler::JCC(void *t) { + underrunProtect(32); + int32_t tt = ((intptr_t)t - (intptr_t)_nIns + 8) >> 2; + if( !(isIMM22(tt)) ) { + NOP(); + JMPL(G0, G2, G0); + SET32((intptr_t)t, G2); + NOP(); + BA(0, 5); + tt = 4; + } + NOP(); + return tt; + } + + void Assembler::JMP(void *t) { + if (!t) { + JMP_long_placeholder(); + } else { + int32_t tt = JCC(t); + BA(0, tt); + } + } + + void Assembler::MR(Register rd, Register rs) { + underrunProtect(4); + ORI(rs, 0, rd); + } + + void Assembler::nInit(AvmCore* core) + { + has_cmov = true; + } + + void Assembler::nBeginAssembly() { + } + + NIns* Assembler::genPrologue() + { + /** + * Prologue + */ + underrunProtect(16); + uint32_t stackNeeded = STACK_GRANULARITY * _activation.stackSlotsNeeded(); + uint32_t frameSize = stackNeeded + kcalleeAreaSize + kLinkageAreaSize; + frameSize = BIT_ROUND_UP(frameSize, 8); + + if (frameSize <= 4096) + SUBI(FP, frameSize, SP); + else { + SUB(FP, G1, SP); + ORI(G1, frameSize & 0x3FF, G1); + SETHI(frameSize, G1); + } + + verbose_only( + if (_logc->lcbits & LC_Native) { + outputf(" 0x%x:",_nIns); + outputf(" patch entry:"); + }) + NIns *patchEntry = _nIns; + + // The frame size in SAVE is faked. We will still re-caculate SP later. + // We can use 0 here but it is not good for debuggers. + SAVEI(SP, -148, SP); + + // align the entry point + asm_align_code(); + + return patchEntry; + } + + void Assembler::asm_align_code() { + while(uintptr_t(_nIns) & 15) { + NOP(); + } + } + + void Assembler::nFragExit(LIns* guard) + { + SideExit* exit = guard->record()->exit; + Fragment *frag = exit->target; + GuardRecord *lr; + if (frag && frag->fragEntry) + { + JMP(frag->fragEntry); + lr = 0; + } + else + { + // Target doesn't exit yet. Emit jump to epilog, and set up to patch later. + if (!_epilogue) + _epilogue = genEpilogue(); + lr = guard->record(); + JMP_long((intptr_t)_epilogue); + lr->jmp = _nIns; + } + + // return value is GuardRecord* + SET32(int(lr), O0); + } + + NIns *Assembler::genEpilogue() + { + underrunProtect(12); + RESTORE(G0, G0, G0); //restore + JMPLI(I7, 8, G0); //ret + ORI(O0, 0, I0); + return _nIns; + } + + void Assembler::asm_call(LIns* ins) + { + if (!ins->isop(LIR_callv)) { + Register retReg = ( ins->isop(LIR_calld) ? F0 : retRegs[0] ); + deprecated_prepResultReg(ins, rmask(retReg)); + } + + // Do this after we've handled the call result, so we don't + // force the call result to be spilled unnecessarily. + evictScratchRegsExcept(0); + + const CallInfo* ci = ins->callInfo(); + + underrunProtect(8); + NOP(); + + ArgType argTypes[MAXARGS]; + uint32_t argc = ci->getArgTypes(argTypes); + + NanoAssert(ins->isop(LIR_callv) || ins->isop(LIR_callp) || + ins->isop(LIR_calld)); + verbose_only(if (_logc->lcbits & LC_Native) + outputf(" 0x%x:", _nIns); + ) + bool indirect = ci->isIndirect(); + if (!indirect) { + CALL(ci); + } + else { + argc--; + Register r = findSpecificRegFor(ins->arg(argc), I0); + JMPL(G0, I0, O7); + } + + Register GPRIndex = O0; + uint32_t offset = kLinkageAreaSize; // start of parameters stack postion. + + for(int i=0; iarg(j), FpRegs); + + underrunProtect(48); + // We might be calling a varargs function. + // So, make sure the GPR's are also loaded with + // the value, or the stack contains it. + if (GPRIndex <= O5) { + LDSW32(SP, offset, GPRIndex); + } + GPRIndex = GPRIndex + 1; + if (GPRIndex <= O5) { + LDSW32(SP, offset+4, GPRIndex); + } + GPRIndex = GPRIndex + 1; + STDF32(r, offset, SP); + offset += 8; + } else { + if (GPRIndex > O5) { + underrunProtect(12); + Register r = findRegFor(ins->arg(j), GpRegs); + STW32(r, offset, SP); + } else { + Register r = findSpecificRegFor(ins->arg(j), GPRIndex); + } + GPRIndex = GPRIndex + 1; + offset += 4; + } + } + } + + Register Assembler::nRegisterAllocFromSet(RegisterMask set) + { + // need to implement faster way + Register i = G0; + while (!(set & rmask(i))) + i = i + 1; + _allocator.free &= ~rmask(i); + return i; + } + + void Assembler::nRegisterResetAll(RegAlloc& a) + { + a.clear(); + a.free = GpRegs | FpRegs; + } + + void Assembler::nPatchBranch(NIns* branch, NIns* location) + { + *(uint32_t*)&branch[0] &= 0xFFC00000; + *(uint32_t*)&branch[0] |= ((intptr_t)location >> 10) & 0x3FFFFF; + *(uint32_t*)&branch[1] &= 0xFFFFFC00; + *(uint32_t*)&branch[1] |= (intptr_t)location & 0x3FF; + } + + RegisterMask Assembler::nHint(LIns* ins) + { + // Never called, because no entries in nHints[] == PREFER_SPECIAL. + NanoAssert(0); + return 0; + } + + bool Assembler::canRemat(LIns* ins) + { + return ins->isImmI() || ins->isop(LIR_allocp); + } + + void Assembler::asm_restore(LIns* i, Register r) + { + underrunProtect(24); + if (i->isop(LIR_allocp)) { + ADD(FP, L2, r); + int32_t d = deprecated_disp(i); + SET32(d, L2); + } + else if (i->isImmI()) { + int v = i->immI(); + SET32(v, r); + } else { + int d = findMemFor(i); + if (rmask(r) & FpRegs) { + LDDF32(FP, d, r); + } else { + LDSW32(FP, d, r); + } + } + } + + void Assembler::asm_store32(LOpcode op, LIns *value, int dr, LIns *base) + { + switch (op) { + case LIR_sti: + case LIR_sti2c: + case LIR_sti2s: + // handled by mainline code below for now + break; + default: + NanoAssertMsg(0, "asm_store32 should never receive this LIR opcode"); + return; + } + + underrunProtect(20); + if (value->isImmI()) + { + Register rb = getBaseReg(base, dr, GpRegs); + int c = value->immI(); + switch (op) { + case LIR_sti: + STW32(L2, dr, rb); + break; + case LIR_sti2c: + STB32(L2, dr, rb); + break; + case LIR_sti2s: + STH32(L2, dr, rb); + break; + } + SET32(c, L2); + } + else + { + // make sure what is in a register + Register ra, rb; + if (base->isImmI()) { + // absolute address + dr += base->immI(); + ra = findRegFor(value, GpRegs); + rb = G0; + } else { + getBaseReg2(GpRegs, value, ra, GpRegs, base, rb, dr); + } + switch (op) { + case LIR_sti: + STW32(ra, dr, rb); + break; + case LIR_sti2c: + STB32(ra, dr, rb); + break; + case LIR_sti2s: + STH32(ra, dr, rb); + break; + } + } + } + + void Assembler::asm_spill(Register rr, int d, bool quad) + { + underrunProtect(24); + (void)quad; + NanoAssert(d); + if (rmask(rr) & FpRegs) { + STDF32(rr, d, FP); + } else { + STW32(rr, d, FP); + } + } + + void Assembler::asm_load64(LIns* ins) + { + switch (ins->opcode()) { + case LIR_ldd: + case LIR_ldf2d: + // handled by mainline code below for now + break; + default: + NanoAssertMsg(0, "asm_load64 should never receive this LIR opcode"); + return; + } + + underrunProtect(48); + LIns* base = ins->oprnd1(); + int db = ins->disp(); + Register rb = getBaseReg(base, db, GpRegs); + + if (ins->isInReg()) { + Register rr = ins->getReg(); + asm_maybe_spill(ins, false); + NanoAssert(rmask(rr) & FpRegs); + + if (ins->opcode() == LIR_ldd) { + LDDF32(rb, db, rr); + } else { + FSTOD(F28, rr); + LDF32(rb, db, F28); + } + } else { + NanoAssert(ins->isInAr()); + int dr = arDisp(ins); + + if (ins->opcode() == LIR_ldd) { + // don't use an fpu reg to simply load & store the value. + asm_mmq(FP, dr, rb, db); + } else { + STDF32(F28, dr, FP); + FSTOD(F28, F28); + LDF32(rb, db, F28); + } + } + + freeResourcesOf(ins); + } + + void Assembler::asm_store64(LOpcode op, LIns* value, int dr, LIns* base) + { + switch (op) { + case LIR_std: + case LIR_std2f: + // handled by mainline code below for now + break; + default: + NanoAssertMsg(0, "asm_store64 should never receive this LIR opcode"); + return; + } + + underrunProtect(48); + Register rb = getBaseReg(base, dr, GpRegs); + if (op == LIR_std2f) { + Register rv = ( !value->isInReg() + ? findRegFor(value, FpRegs) + : value->getReg() ); + NanoAssert(rmask(rv) & FpRegs); + STF32(F28, dr, rb); + FDTOS(rv, F28); + return; + } + + if (value->isImmD()) + { + // if a constant 64-bit value just store it now rather than + // generating a pointless store/load/store sequence + STW32(L2, dr+4, rb); + SET32(value->immDlo(), L2); + STW32(L2, dr, rb); + SET32(value->immDhi(), L2); + return; + } + + if (value->isop(LIR_ldd)) + { + // value is 64bit struct or int64_t, or maybe a double. + // it may be live in an FPU reg. Either way, don't + // put it in an FPU reg just to load & store it. + + // a) if we know it's not a double, this is right. + // b) if we guarded that its a double, this store could be on + // the side exit, copying a non-double. + // c) maybe its a double just being stored. oh well. + + int da = findMemFor(value); + asm_mmq(rb, dr, FP, da); + return; + } + + // if value already in a reg, use that, otherwise + // get it into FPU regs. + Register rv = ( !value->isInReg() + ? findRegFor(value, FpRegs) + : value->getReg() ); + + STDF32(rv, dr, rb); + } + + /** + * copy 64 bits: (rd+dd) <- (rs+ds) + */ + void Assembler::asm_mmq(Register rd, int dd, Register rs, int ds) + { + // value is either a 64bit struct or maybe a float + // that isn't live in an FPU reg. Either way, don't + // put it in an FPU reg just to load & store it. + Register t = registerAllocTmp(GpRegs & ~(rmask(rd)|rmask(rs))); + STW32(t, dd+4, rd); + LDSW32(rs, ds+4, t); + STW32(t, dd, rd); + LDSW32(rs, ds, t); + } + + NIns* Assembler::asm_branch(bool branchOnFalse, LIns* cond, NIns* targ) + { + NIns* at = 0; + LOpcode condop = cond->opcode(); + NanoAssert(cond->isCmp()); + if (isCmpDOpcode(condop)) + { + return asm_branchd(branchOnFalse, cond, targ); + } + + underrunProtect(32); + intptr_t tt = ((intptr_t)targ - (intptr_t)_nIns + 8) >> 2; + // !targ means that it needs patch. + if( !(isIMM22((int32_t)tt)) || !targ ) { + JMP_long_nocheck((intptr_t)targ); + at = _nIns; + NOP(); + BA(0, 5); + tt = 4; + } + NOP(); + + // produce the branch + if (branchOnFalse) + { + if (condop == LIR_eqi) + BNE(0, tt); + else if (condop == LIR_lti) + BGE(0, tt); + else if (condop == LIR_lei) + BG(0, tt); + else if (condop == LIR_gti) + BLE(0, tt); + else if (condop == LIR_gei) + BL(0, tt); + else if (condop == LIR_ltui) + BCC(0, tt); + else if (condop == LIR_leui) + BGU(0, tt); + else if (condop == LIR_gtui) + BLEU(0, tt); + else //if (condop == LIR_geui) + BCS(0, tt); + } + else // op == LIR_xt + { + if (condop == LIR_eqi) + BE(0, tt); + else if (condop == LIR_lti) + BL(0, tt); + else if (condop == LIR_lei) + BLE(0, tt); + else if (condop == LIR_gti) + BG(0, tt); + else if (condop == LIR_gei) + BGE(0, tt); + else if (condop == LIR_ltui) + BCS(0, tt); + else if (condop == LIR_leui) + BLEU(0, tt); + else if (condop == LIR_gtui) + BGU(0, tt); + else //if (condop == LIR_geui) + BCC(0, tt); + } + asm_cmp(cond); + return at; + } + + NIns* Assembler::asm_branch_ov(LOpcode op, NIns* targ) + { + NIns* at = 0; + underrunProtect(32); + intptr_t tt = ((intptr_t)targ - (intptr_t)_nIns + 8) >> 2; + // !targ means that it needs patch. + if( !(isIMM22((int32_t)tt)) || !targ ) { + JMP_long_nocheck((intptr_t)targ); + at = _nIns; + NOP(); + BA(0, 5); + tt = 4; + } + NOP(); + + if( op == LIR_mulxovi || op == LIR_muljovi ) + BNE(0, tt); + else + BVS(0, tt); + return at; + } + + void Assembler::asm_cmp(LIns *cond) + { + underrunProtect(12); + + LIns* lhs = cond->oprnd1(); + LIns* rhs = cond->oprnd2(); + + NanoAssert(lhs->isI() && rhs->isI()); + + // ready to issue the compare + if (rhs->isImmI()) + { + int c = rhs->immI(); + Register r = findRegFor(lhs, GpRegs); + if (c == 0 && cond->isop(LIR_eqi)) { + ANDCC(r, r, G0); + } + else { + SUBCC(r, L2, G0); + SET32(c, L2); + } + } + else + { + Register ra, rb; + findRegFor2(GpRegs, lhs, ra, GpRegs, rhs, rb); + SUBCC(ra, rb, G0); + } + } + + void Assembler::asm_condd(LIns* ins) + { + // only want certain regs + Register r = deprecated_prepResultReg(ins, AllowableFlagRegs); + underrunProtect(8); + LOpcode condop = ins->opcode(); + NanoAssert(isCmpDOpcode(condop)); + if (condop == LIR_eqd) + MOVFEI(1, r); + else if (condop == LIR_led) + MOVFLEI(1, r); + else if (condop == LIR_ltd) + MOVFLI(1, r); + else if (condop == LIR_ged) + MOVFGEI(1, r); + else // if (condop == LIR_gtd) + MOVFGI(1, r); + ORI(G0, 0, r); + asm_cmpd(ins); + } + + void Assembler::asm_cond(LIns* ins) + { + underrunProtect(8); + // only want certain regs + LOpcode op = ins->opcode(); + Register r = deprecated_prepResultReg(ins, AllowableFlagRegs); + + if (op == LIR_eqi) + MOVEI(1, r); + else if (op == LIR_lti) + MOVLI(1, r); + else if (op == LIR_lei) + MOVLEI(1, r); + else if (op == LIR_gti) + MOVGI(1, r); + else if (op == LIR_gei) + MOVGEI(1, r); + else if (op == LIR_ltui) + MOVCSI(1, r); + else if (op == LIR_leui) + MOVLEUI(1, r); + else if (op == LIR_gtui) + MOVGUI(1, r); + else // if (op == LIR_geui) + MOVCCI(1, r); + ORI(G0, 0, r); + asm_cmp(ins); + } + + void Assembler::asm_arith(LIns* ins) + { + underrunProtect(28); + LOpcode op = ins->opcode(); + LIns* lhs = ins->oprnd1(); + LIns* rhs = ins->oprnd2(); + + Register rb = deprecated_UnknownReg; + RegisterMask allow = GpRegs; + bool forceReg = (op == LIR_muli || op == LIR_mulxovi || op == LIR_muljovi || !rhs->isImmI()); + + if (lhs != rhs && forceReg) + { + if ((rb = asm_binop_rhs_reg(ins)) == deprecated_UnknownReg) { + rb = findRegFor(rhs, allow); + } + allow &= ~rmask(rb); + } + else if ((op == LIR_addi || op == LIR_addxovi || op == LIR_addjovi) && lhs->isop(LIR_allocp) && rhs->isImmI()) { + // add alloc+const, use lea + Register rr = deprecated_prepResultReg(ins, allow); + int d = findMemFor(lhs) + rhs->immI(); + ADD(FP, L2, rr); + SET32(d, L2); + return; + } + + Register rr = deprecated_prepResultReg(ins, allow); + // if this is last use of lhs in reg, we can re-use result reg + // else, lhs already has a register assigned. + Register ra = ( !lhs->isInReg() + ? findSpecificRegFor(lhs, rr) + : lhs->deprecated_getReg() ); + + if (forceReg) + { + if (lhs == rhs) + rb = ra; + + if (op == LIR_addi || op == LIR_addxovi || op == LIR_addjovi) + ADDCC(rr, rb, rr); + else if (op == LIR_subi || op == LIR_subxovi || op == LIR_subjovi) + SUBCC(rr, rb, rr); + else if (op == LIR_muli) + SMULCC(rr, rb, rr); + else if (op == LIR_mulxovi || op == LIR_muljovi) { + SUBCC(L4, L6, L4); + SRAI(rr, 31, L6); + RDY(L4); + SMULCC(rr, rb, rr); + } + else if (op == LIR_andi) + AND(rr, rb, rr); + else if (op == LIR_ori) + OR(rr, rb, rr); + else if (op == LIR_xori) + XOR(rr, rb, rr); + else if (op == LIR_lshi) + SLL(rr, rb, rr); + else if (op == LIR_rshi) + SRA(rr, rb, rr); + else if (op == LIR_rshui) + SRL(rr, rb, rr); + else + NanoAssertMsg(0, "Unsupported"); + } + else + { + int c = rhs->immI(); + if (op == LIR_addi || op == LIR_addxovi || op == LIR_addjovi) + ADDCC(rr, L2, rr); + else if (op == LIR_subi || op == LIR_subxovi || op == LIR_subjovi) + SUBCC(rr, L2, rr); + else if (op == LIR_andi) + AND(rr, L2, rr); + else if (op == LIR_ori) + OR(rr, L2, rr); + else if (op == LIR_xori) + XOR(rr, L2, rr); + else if (op == LIR_lshi) + SLL(rr, L2, rr); + else if (op == LIR_rshi) + SRA(rr, L2, rr); + else if (op == LIR_rshui) + SRL(rr, L2, rr); + else + NanoAssertMsg(0, "Unsupported"); + SET32(c, L2); + } + + if ( rr != ra ) + ORI(ra, 0, rr); + } + + void Assembler::asm_neg_not(LIns* ins) + { + underrunProtect(8); + LOpcode op = ins->opcode(); + Register rr = deprecated_prepResultReg(ins, GpRegs); + + LIns* lhs = ins->oprnd1(); + // if this is last use of lhs in reg, we can re-use result reg + // else, lhs already has a register assigned. + Register ra = ( !lhs->isInReg() + ? findSpecificRegFor(lhs, rr) + : lhs->deprecated_getReg() ); + + if (op == LIR_noti) + ORN(G0, rr, rr); + else + SUB(G0, rr, rr); + + if ( rr != ra ) + ORI(ra, 0, rr); + } + + void Assembler::asm_load32(LIns* ins) + { + underrunProtect(12); + LOpcode op = ins->opcode(); + LIns* base = ins->oprnd1(); + int d = ins->disp(); + Register rr = deprecated_prepResultReg(ins, GpRegs); + Register ra = getBaseReg(base, d, GpRegs); + switch(op) { + case LIR_lduc2ui: + LDUB32(ra, d, rr); + break; + case LIR_ldus2ui: + LDUH32(ra, d, rr); + break; + case LIR_ldi: + LDSW32(ra, d, rr); + break; + case LIR_ldc2i: + LDSB32(ra, d, rr); + break; + case LIR_lds2i: + LDSH32(ra, d, rr); + break; + default: + NanoAssertMsg(0, "asm_load32 should never receive this LIR opcode"); + return; + } + } + + void Assembler::asm_cmov(LIns* ins) + { + underrunProtect(4); + LOpcode op = ins->opcode(); + LIns* condval = ins->oprnd1(); + LIns* iftrue = ins->oprnd2(); + LIns* iffalse = ins->oprnd3(); + + NanoAssert(condval->isCmp()); + NanoAssert(op == LIR_cmovi && iftrue->isI() && iffalse->isI() || + (op == LIR_cmovd && iftrue->isD() && iffalse->isD())); + + RegisterMask rm = (op == LIR_cmovi) ? GpRegs : FpRegs; + const Register rr = deprecated_prepResultReg(ins, rm); + const Register iffalsereg = findRegFor(iffalse, rm & ~rmask(rr)); + bool isIcc = true; + + if (op == LIR_cmovi) { + switch (condval->opcode()) { + // note that these are all opposites... + case LIR_eqi: MOVNE (iffalsereg, rr); break; + case LIR_lti: MOVGE (iffalsereg, rr); break; + case LIR_lei: MOVG (iffalsereg, rr); break; + case LIR_gti: MOVLE (iffalsereg, rr); break; + case LIR_gei: MOVL (iffalsereg, rr); break; + case LIR_ltui: MOVCC (iffalsereg, rr); break; + case LIR_leui: MOVGU (iffalsereg, rr); break; + case LIR_gtui: MOVLEU(iffalsereg, rr); break; + case LIR_geui: MOVCS (iffalsereg, rr); break; + debug_only( default: NanoAssert(0); break; ) + } + } else { + switch (condval->opcode()) { + // note that these are all opposites... + case LIR_eqi: FMOVDNE (iffalsereg, rr); break; + case LIR_lti: FMOVDGE (iffalsereg, rr); break; + case LIR_lei: FMOVDG (iffalsereg, rr); break; + case LIR_gti: FMOVDLE (iffalsereg, rr); break; + case LIR_gei: FMOVDL (iffalsereg, rr); break; + case LIR_ltui: FMOVDCC (iffalsereg, rr); break; + case LIR_leui: FMOVDGU (iffalsereg, rr); break; + case LIR_gtui: FMOVDLEU (iffalsereg, rr); break; + case LIR_geui: FMOVDCS (iffalsereg, rr); break; + case LIR_eqd: FMOVDFNE (iffalsereg, rr); isIcc = false; break; + case LIR_led: FMOVDFUG (iffalsereg, rr); isIcc = false; break; + case LIR_ltd: FMOVDFUGE(iffalsereg, rr); isIcc = false; break; + case LIR_ged: FMOVDFUL (iffalsereg, rr); isIcc = false; break; + case LIR_gtd: FMOVDFULE(iffalsereg, rr); isIcc = false; break; + debug_only( default: NanoAssert(0); break; ) + } + } + + /*const Register iftruereg =*/ findSpecificRegFor(iftrue, rr); + if (isIcc) + asm_cmp(condval); + else + asm_cmpd(condval); + + } + + void Assembler::asm_param(LIns* ins) + { + underrunProtect(12); + uint32_t a = ins->paramArg(); + NanoAssertMsg(ins->paramKind() == 0, "savedRegs are not used on SPARC"); + + if (a < sizeof(argRegs)/sizeof(argRegs[0])) { // i0 - i5 + prepareResultReg(ins, rmask(argRegs[a])); + } else { + // Incoming arg is on stack + Register r = prepareResultReg(ins, GpRegs); + int32_t d = a * sizeof (intptr_t) + kLinkageAreaSize; + LDSW32(FP, d, r); + } + freeResourcesOf(ins); + } + + void Assembler::asm_immi(LIns* ins) + { + underrunProtect(8); + Register rr = deprecated_prepResultReg(ins, GpRegs); + int32_t val = ins->immI(); + if (val == 0) + XOR(rr, rr, rr); + else + SET32(val, rr); + } + + void Assembler::asm_immd(LIns* ins) + { + underrunProtect(64); + Register rr = ins->deprecated_getReg(); + if (rr != deprecated_UnknownReg) + { + // @todo -- add special-cases for 0 and 1 + _allocator.retire(rr); + ins->clearReg(); + NanoAssert((rmask(rr) & FpRegs) != 0); + findMemFor(ins); + int d = deprecated_disp(ins); + LDDF32(FP, d, rr); + } + + // @todo, if we used xor, ldsd, fldz, etc above, we don't need mem here + int d = deprecated_disp(ins); + deprecated_freeRsrcOf(ins); + if (d) + { + STW32(L2, d+4, FP); + SET32(ins->immDlo(), L2); + STW32(L2, d, FP); + SET32(ins->immDhi(), L2); + } + } + + void Assembler::asm_fneg(LIns* ins) + { + underrunProtect(4); + Register rr = deprecated_prepResultReg(ins, FpRegs); + LIns* lhs = ins->oprnd1(); + + // lhs into reg, prefer same reg as result + // if this is last use of lhs in reg, we can re-use result reg + // else, lhs already has a different reg assigned + Register ra = ( !lhs->isInReg() + ? findSpecificRegFor(lhs, rr) + : findRegFor(lhs, FpRegs) ); + + FNEGD(ra, rr); + } + + void Assembler::asm_fop(LIns* ins) + { + underrunProtect(4); + LOpcode op = ins->opcode(); + LIns *lhs = ins->oprnd1(); + LIns *rhs = ins->oprnd2(); + + RegisterMask allow = FpRegs; + Register ra, rb; + findRegFor2(allow, lhs, ra, allow, rhs, rb); + Register rr = deprecated_prepResultReg(ins, allow); + + if (op == LIR_addd) + FADDD(ra, rb, rr); + else if (op == LIR_subd) + FSUBD(ra, rb, rr); + else if (op == LIR_muld) + FMULD(ra, rb, rr); + else //if (op == LIR_divd) + FDIVD(ra, rb, rr); + + } + + void Assembler::asm_i2d(LIns* ins) + { + underrunProtect(32); + // where our result goes + Register rr = deprecated_prepResultReg(ins, FpRegs); + int d = findMemFor(ins->oprnd1()); + FITOD(rr, rr); + LDDF32(FP, d, rr); + } + + void Assembler::asm_ui2d(LIns* ins) + { + underrunProtect(72); + // where our result goes + Register rr = deprecated_prepResultReg(ins, FpRegs); + Register rt = registerAllocTmp(FpRegs & ~(rmask(rr))); + Register gr = findRegFor(ins->oprnd1(), GpRegs); + int disp = -8; + + FABSS(rr, rr); + FSUBD(rt, rr, rr); + LDDF32(SP, disp, rr); + STWI(G0, disp+4, SP); + LDDF32(SP, disp, rt); + STWI(gr, disp+4, SP); + STWI(G1, disp, SP); + SETHI(0x43300000, G1); + } + + void Assembler::asm_d2i(LIns* ins) { + underrunProtect(28); + LIns *lhs = ins->oprnd1(); + Register rr = prepareResultReg(ins, GpRegs); + Register ra = findRegFor(lhs, FpRegs); + int d = findMemFor(ins); + LDSW32(FP, d, rr); + STF32(ra, d, FP); + FDTOI(ra, ra); + freeResourcesOf(ins); + } + + void Assembler::asm_nongp_copy(Register r, Register s) + { + underrunProtect(4); + NanoAssert((rmask(r) & FpRegs) && (rmask(s) & FpRegs)); + FMOVD(s, r); + } + + NIns * Assembler::asm_branchd(bool branchOnFalse, LIns *cond, NIns *targ) + { + NIns *at = 0; + LOpcode condop = cond->opcode(); + NanoAssert(isCmpDOpcode(condop)); + underrunProtect(32); + intptr_t tt = ((intptr_t)targ - (intptr_t)_nIns + 8) >> 2; + // !targ means that it needs patch. + if( !(isIMM22((int32_t)tt)) || !targ ) { + JMP_long_nocheck((intptr_t)targ); + at = _nIns; + NOP(); + BA(0, 5); + tt = 4; + } + NOP(); + + // produce the branch + if (branchOnFalse) + { + if (condop == LIR_eqd) + FBNE(0, tt); + else if (condop == LIR_led) + FBUG(0, tt); + else if (condop == LIR_ltd) + FBUGE(0, tt); + else if (condop == LIR_ged) + FBUL(0, tt); + else //if (condop == LIR_gtd) + FBULE(0, tt); + } + else // op == LIR_xt + { + if (condop == LIR_eqd) + FBE(0, tt); + else if (condop == LIR_led) + FBLE(0, tt); + else if (condop == LIR_ltd) + FBL(0, tt); + else if (condop == LIR_ged) + FBGE(0, tt); + else //if (condop == LIR_gtd) + FBG(0, tt); + } + asm_cmpd(cond); + return at; + } + + void Assembler::asm_cmpd(LIns *cond) + { + underrunProtect(4); + LIns* lhs = cond->oprnd1(); + LIns* rhs = cond->oprnd2(); + + Register rLhs = findRegFor(lhs, FpRegs); + Register rRhs = findRegFor(rhs, FpRegs); + + FCMPD(rLhs, rRhs); + } + + void Assembler::nativePageReset() + { + } + + Register Assembler::asm_binop_rhs_reg(LIns* ins) + { + return deprecated_UnknownReg; + } + + void Assembler::nativePageSetup() + { + NanoAssert(!_inExit); + if (!_nIns) + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes)); + } + + // Increment the 32-bit profiling counter at pCtr, without + // changing any registers. + verbose_only( + void Assembler::asm_inc_m32(uint32_t*) + { + // todo: implement this + } + ) + + void + Assembler::underrunProtect(int n) + { + NIns *eip = _nIns; + // This may be in a normal code chunk or an exit code chunk. + if (eip - n < codeStart) { + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes)); + JMP_long_nocheck((intptr_t)eip); + } + } + + void Assembler::asm_ret(LIns* ins) + { + genEpilogue(); + releaseRegisters(); + assignSavedRegs(); + LIns *val = ins->oprnd1(); + if (ins->isop(LIR_reti)) { + findSpecificRegFor(val, retRegs[0]); + } else { + NanoAssert(ins->isop(LIR_retd)); + findSpecificRegFor(val, F0); + } + } + + void Assembler::swapCodeChunks() { + if (!_nExitIns) + codeAlloc(exitStart, exitEnd, _nExitIns verbose_only(, exitBytes)); + SWAP(NIns*, _nIns, _nExitIns); + SWAP(NIns*, codeStart, exitStart); + SWAP(NIns*, codeEnd, exitEnd); + verbose_only( SWAP(size_t, codeBytes, exitBytes); ) + } + + void Assembler::asm_insert_random_nop() { + NanoAssert(0); // not supported + } + +#endif /* FEATURE_NANOJIT */ +} diff --git a/js/src/nanojit/NativeSparc.h b/js/src/nanojit/NativeSparc.h new file mode 100644 index 0000000..2a69caa --- /dev/null +++ b/js/src/nanojit/NativeSparc.h @@ -0,0 +1,456 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * leon.sha@oracle.com + * ginn.chen@oracle.com + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#ifndef __nanojit_NativeSparc__ +#define __nanojit_NativeSparc__ + +#include "NativeCommon.h" + +#define count_instr() +#define count_ret() +#define count_push() +#define count_pop() +#define count_st() +#define count_stq() +#define count_ld() +#define count_ldq() +#define count_call() +#define count_calli() +#define count_prolog() +#define count_alu() +#define count_mov() +#define count_fpu() +#define count_jmp() +#define count_jcc() +#define count_fpuld() +#define count_aluld() +#define count_alust() +#define count_pushld() +#define count_imt() + +namespace nanojit +{ + const int NJ_MAX_REGISTERS = 30; // L0 - L7, I0 - I5, F2 - F14 + + const int LARGEST_UNDERRUN_PROT = 32; // largest value passed to underrunProtect + +#define NJ_MAX_STACK_ENTRY 8192 +#define NJ_MAX_PARAMETERS 1 + +#define NJ_JTBL_SUPPORTED 0 +#define NJ_EXPANDED_LOADSTORE_SUPPORTED 1 +#define NJ_F2I_SUPPORTED 1 +#define NJ_SOFTFLOAT_SUPPORTED 0 +#define NJ_DIVI_SUPPORTED 0 + + const int NJ_ALIGN_STACK = 16; + + typedef uint32_t NIns; + + // Bytes of icache to flush after Assembler::patch + const size_t LARGEST_BRANCH_PATCH = 2 * sizeof(NIns); + + // These are used as register numbers in various parts of the code + static const Register + G0 = { 0 }, + G1 = { 1 }, + G2 = { 2 }, + G3 = { 3 }, + G4 = { 4 }, + G5 = { 5 }, // Reserved for system + G6 = { 6 }, // Reserved for system + G7 = { 7 }, // Reserved for system + + O0 = { 8 }, + O1 = { 9 }, + O2 = { 10 }, + O3 = { 11 }, + O4 = { 12 }, + O5 = { 13 }, + O6 = { 14 }, // SP + O7 = { 15 }, // Not used. + + L0 = { 16 }, + L1 = { 17 }, + L2 = { 18 }, + L3 = { 19 }, + L4 = { 20 }, + L5 = { 21 }, + L6 = { 22 }, + L7 = { 23 }, + + I0 = { 24 }, + I1 = { 25 }, + I2 = { 26 }, + I3 = { 27 }, + I4 = { 28 }, + I5 = { 29 }, + I6 = { 30 }, // FP + I7 = { 31 }, // Not used + + SP = O6, + FP = I6, + + F0 = { 32 }, + F1 = { 33 }, + F2 = { 34 }, + F3 = { 35 }, + F4 = { 36 }, + F5 = { 37 }, + F6 = { 38 }, + F7 = { 39 }, + F8 = { 40 }, + F9 = { 41 }, + F10 = { 42 }, + F11 = { 43 }, + F12 = { 44 }, + F13 = { 45 }, + F14 = { 46 }, + F15 = { 47 }, + F16 = { 48 }, + F17 = { 49 }, + F18 = { 50 }, + F19 = { 51 }, + F20 = { 52 }, + F21 = { 53 }, + F22 = { 54 }, + F23 = { 55 }, + F24 = { 56 }, + F25 = { 57 }, + F26 = { 58 }, + F27 = { 59 }, + F28 = { 60 }, + F29 = { 61 }, + F30 = { 62 }, + F31 = { 63 }, + + // helpers + FRAME_PTR = G4, + + deprecated_UnknownReg = { 64 }; // XXX: remove eventually, see bug 538924 + + static const uint32_t FirstRegNum = 0; + static const uint32_t LastRegNum = 63; +} + +namespace nanojit +{ + // We only use 32 registers to be managed. + // So we choose some of them. + // And other unmanaged registers we can use them directly. + // The registers that can be used directly are G0-G4, L0, L2, L4, L6 + // SP, FP, F8-F12, F24-F28 + typedef uint64_t RegisterMask; +#define _rmask_(r) ((RegisterMask)1<<(REGNUM(r))) +#define _reg_(r) (REGNUM(r) & 0x1F) + // Assembler::savedRegs[] is not needed for sparc because the + // registers are already saved automatically by "save" instruction. + static const int NumSavedRegs = 0; + + static const RegisterMask SavedRegs = _rmask_(L1) | _rmask_(L3) | _rmask_(L5) | _rmask_(L7) | + _rmask_(I0) | _rmask_(I1) | _rmask_(I2) | _rmask_(I3) | + _rmask_(I4) | _rmask_(I5); + static const RegisterMask GpRegs = SavedRegs | _rmask_(O0) | _rmask_(O1) | _rmask_(O2) | + _rmask_(O3) | _rmask_(O4) | _rmask_(O5); + static const RegisterMask FpRegs = _rmask_(F0) | _rmask_(F2) | _rmask_(F4) | + _rmask_(F6) | _rmask_(F14) | _rmask_(F16) | + _rmask_(F18) | _rmask_(F20) | _rmask_(F22); + static const RegisterMask AllowableFlagRegs = GpRegs; + + verbose_only( extern const char* regNames[]; ) + +#define DECLARE_PLATFORM_STATS() + +#define DECLARE_PLATFORM_REGALLOC() + +#define DECLARE_PLATFORM_ASSEMBLER() \ + const static Register argRegs[6], retRegs[1]; \ + bool has_cmov; \ + void nativePageReset(); \ + void nativePageSetup(); \ + void underrunProtect(int bytes); \ + bool hardenNopInsertion(const Config& /*c*/) { return false; } \ + void asm_align_code(); \ + void asm_cmp(LIns *cond); \ + void asm_cmpd(LIns *cond); \ + NIns* asm_branchd(bool, LIns*, NIns*); \ + void IMM32(int32_t i) { \ + --_nIns; \ + *((int32_t*)_nIns) = i; \ + } \ + void CALL(const CallInfo* ci); \ + void Format_2(int32_t x, int32_t op2, int32_t imm22) { \ + int32_t i = x << 25 | op2 << 22 | imm22 & 0x3FFFFF; \ + IMM32(i); \ + } \ + void Format_2A(Register rd, int32_t op2, int32_t imm22) { \ + Format_2(_reg_(rd), op2, imm22); \ + } \ + void Format_2_2(int32_t a, int32_t cond, int32_t op2, int32_t disp22) { \ + Format_2((a & 0x1) << 4 | cond & 0xF, op2, disp22); \ + } \ + void Format_2_3(int32_t a, int32_t cond, int32_t op2, int32_t cc1, int32_t cc0, int32_t p, int32_t disp19) { \ + Format_2_2(a, cond, op2, (cc1 & 0x1) << 21 | (cc0 & 0x1) << 20 | (p & 0x1) << 19 | disp19 & 0x7FFFF); \ + } \ + void Format_2_4(int32_t a, int32_t rcond, int32_t op2, int32_t d16hi, int32_t p, int32_t rs1, int32_t d16lo) { \ + Format_2_2(a, rcond & 0x7, op2, (d16hi & 0x3) << 20 | (p & 0x1) << 19 | rs1 << 14 | d16lo & 0x3FFF); \ + } \ + void Format_3(int32_t op1, int32_t x, int32_t op3, int32_t bits19) { \ + int32_t i = op1 << 30 | x << 25 | op3 << 19 | bits19 & 0x7FFFF; \ + IMM32(i); \ + } \ + void Format_3A(int32_t op1, Register rd, int32_t op3, int32_t bits19) { \ + Format_3(op1, _reg_(rd), op3, bits19); \ + } \ + void Format_3_1(int32_t op1, Register rd, int32_t op3, Register rs1, int32_t bit8, Register rs2) { \ + Format_3A(op1, rd, op3, _reg_(rs1) << 14 | (bit8 & 0xFF) << 5 | _reg_(rs2)); \ + } \ + void Format_3_1I(int32_t op1, Register rd, int32_t op3, Register rs1, int32_t simm13) { \ + Format_3A(op1, rd, op3, _reg_(rs1) << 14 | 1 << 13 | simm13 & 0x1FFF); \ + } \ + void Format_3_2(int32_t op1, Register rd, int32_t op3, Register rs1, int32_t rcond, Register rs2) { \ + Format_3A(op1, rd, op3, _reg_(rs1) << 14 | (rcond & 0x3) << 10 | _reg_(rs2)); \ + } \ + void Format_3_2I(int32_t op1, Register rd, int32_t op3, Register rs1, int32_t rcond, int32_t simm10) { \ + Format_3A(op1, rd, op3, _reg_(rs1) << 14 | 1 << 13 | (rcond & 0x3) << 10 | simm10 & 0x1FFF); \ + } \ + void Format_3_3(int32_t op1, Register rd, int32_t op3, Register rs1, int32_t cmask, int32_t mmask) { \ + Format_3A(op1, rd, op3, _reg_(rs1) << 14 | 1 << 13 | (cmask & 0x7) << 5 | mmask & 0xF); \ + } \ + void Format_3_4(int32_t op1, Register rd, int32_t op3, int32_t bits19) { \ + Format_3A(op1, rd, op3, bits19); \ + } \ + void Format_3_5(int32_t op1, Register rd, int32_t op3, Register rs1, int32_t x, Register rs2) { \ + Format_3A(op1, rd, op3, _reg_(rs1) << 14 | (x & 0x1) << 12 | _reg_(rs2)); \ + } \ + void Format_3_6(int32_t op1, Register rd, int32_t op3, Register rs1, int32_t shcnt32) { \ + Format_3A(op1, rd, op3, _reg_(rs1) << 14 | 1 << 13 | (shcnt32 & 0x3F)); \ + } \ + void Format_3_7(int32_t op1, Register rd, int32_t op3, Register rs1, int32_t shcnt64) { \ + Format_3A(op1, rd, op3, _reg_(rs1) << 14 | 1 << 13 | 1 << 12 | (shcnt64 & 0x7F)); \ + } \ + void Format_3_8(int32_t op1, Register rd, int32_t op3, Register rs1, int32_t bits9, Register rs2) { \ + Format_3A(op1, rd, op3, _reg_(rs1) << 14 | (bits9 & 0x1FF) << 5 | _reg_(rs2)); \ + } \ + void Format_3_9(int32_t op1, int32_t cc1, int32_t cc0, int32_t op3, Register rs1, int32_t bits9, Register rs2) { \ + Format_3(op1, (cc1 & 0x1) << 1 | (cc0 & 0x1), op3, _reg_(rs1) << 14 | (bits9 & 0x1FF) << 5 | _reg_(rs2)); \ + } \ + void Format_4_1(Register rd, int32_t op3, Register rs1, int32_t cc1, int32_t cc0, Register rs2) { \ + Format_3A(2, rd, op3, _reg_(rs1) << 14 | (cc1 & 0x1) << 12 | (cc0 & 0x1) << 11 | _reg_(rs2)); \ + } \ + void Format_4_1I(Register rd, int32_t op3, Register rs1, int32_t cc1, int32_t cc0, int32_t simm11) { \ + Format_3A(2, rd, op3, _reg_(rs1) << 14 | (cc1 & 0x1) << 12 | 1 << 13 |(cc0 & 0x1) << 11 | simm11 & 0x7FF); \ + } \ + void Format_4_2(Register rd, int32_t op3, int32_t cc2, int32_t cond, int32_t cc1, int32_t cc0, Register rs2) { \ + Format_3A(2, rd, op3, (cc2 & 0x1) << 18 | (cond & 0xF) << 14 | (cc1 & 0x1) << 12 | (cc0 & 0x1) << 11 | _reg_(rs2)); \ + } \ + void Format_4_2I(Register rd, int32_t op3, int32_t cc2, int32_t cond, int32_t cc1, int32_t cc0, int32_t simm11) { \ + Format_3A(2, rd, op3, (cc2 & 0x1) << 18 | (cond & 0xF) << 14 | 1 << 13 | (cc1 & 0x1) << 12 | (cc0 & 0x1) << 11 | (simm11 & 0x7FF)); \ + } \ + void Format_4_3(Register rd, int32_t op3, Register rs1, int32_t cc1, int32_t cc0, int32_t swap_trap) { \ + Format_3A(2, rd, op3, _reg_(rs1) << 14 | 1 << 13 | (cc1 & 0x1) << 12 | (cc0 & 0x1) << 11 | swap_trap & 0x7F); \ + } \ + void Format_4_4(Register rd, int32_t op3, Register rs1, int32_t rcond, int32_t opf_low, Register rs2) { \ + Format_3A(2, rd, op3, _reg_(rs1) << 14 | (rcond & 0x7) << 10 | (opf_low & 0x1F) << 5 | _reg_(rs2)); \ + } \ + void Format_4_5(Register rd, int32_t op3, int32_t cond, int32_t opf_cc, int32_t opf_low, Register rs2) { \ + Format_3A(2, rd, op3, (cond & 0xF) << 14 | (opf_cc & 0x7) << 11 | (opf_low & 0x3F) << 5 | _reg_(rs2)); \ + } \ + void IntegerOperation(Register rs1, Register rs2, Register rd, int32_t op3, const char *opcode); \ + void IntegerOperationI(Register rs1, int32_t simm13, Register rd, int32_t op3, const char *opcode); \ + void FloatOperation(Register rs1, Register rs2, Register rd, int32_t op3, const char *opcode); \ + void Bicc(int32_t a, int32_t dsp22, int32_t cond, const char *opcode); \ + void FBfcc(int32_t a, int32_t dsp22, int32_t cond, const char *opcode); \ + void LoadOperation(Register rs1, Register rs2, Register rd, int32_t op3, const char* opcode); \ + void LoadOperationI(Register rs1, int32_t simm13, Register rd, int32_t op3, const char* opcode); \ + void MOVcc(Register rs, int32_t cc2, int32_t cc1, int32_t cc0, Register rd, int32_t cond, const char *opcode); \ + void MOVccI(int32_t simm11, int32_t cc2, int32_t cc1, int32_t cc0, Register rd, int32_t cond, const char *opcode); \ + void FMOVDcc(Register rs, int32_t opt_cc, Register rd, int32_t cond, const char *opcode); \ + void ShiftOperation(Register rs1, Register rs2, Register rd, int32_t op3, const char* opcode); \ + void ShiftOperationI(Register rs1, int32_t shcnt32, Register rd, int32_t op3, const char* opcode); \ + void Store(Register rd, Register rs1, Register rs2, int32_t op3, const char* opcode); \ + void StoreI(Register rd, int32_t simm13, Register rs1, int32_t op3, const char* opcode); \ + void ADD(Register rs1, Register rs2, Register rd); \ + void ADDCC(Register rs1, Register rs2, Register rd); \ + void AND(Register rs1, Register rs2, Register rd); \ + void ANDCC(Register rs1, Register rs2, Register rd); \ + void OR(Register rs1, Register rs2, Register rd); \ + void ORI(Register rs1, int32_t simm13, Register rd); \ + void ORN(Register rs1, Register rs2, Register rd); \ + void SMULCC(Register rs1, Register rs2, Register rd); \ + void SUB(Register rs1, Register rs2, Register rd); \ + void SUBCC(Register rs1, Register rs2, Register rd); \ + void SUBI(Register rs1, int32_t simm13, Register rd); \ + void XOR(Register rs1, Register rs2, Register rd); \ + void BA(int32_t a, int32_t dsp22); \ + void BE(int32_t a, int32_t dsp22); \ + void BNE(int32_t a, int32_t dsp22); \ + void BG(int32_t a, int32_t dsp22); \ + void BGU(int32_t a, int32_t dsp22); \ + void BGE(int32_t a, int32_t dsp22); \ + void BL(int32_t a, int32_t dsp22); \ + void BLE(int32_t a, int32_t dsp22); \ + void BLEU(int32_t a, int32_t dsp22); \ + void BCC(int32_t a, int32_t dsp22); \ + void BCS(int32_t a, int32_t dsp22); \ + void BVC(int32_t a, int32_t dsp22); \ + void BVS(int32_t a, int32_t dsp22); \ + void FABSS(Register rs2, Register rd); \ + void FADDD(Register rs1, Register rs2, Register rd); \ + void FBE(int32_t a, int32_t dsp22); \ + void FBNE(int32_t a, int32_t dsp22); \ + void FBUE(int32_t a, int32_t dsp22); \ + void FBG(int32_t a, int32_t dsp22); \ + void FBUG(int32_t a, int32_t dsp22); \ + void FBGE(int32_t a, int32_t dsp22); \ + void FBUGE(int32_t a, int32_t dsp22); \ + void FBL(int32_t a, int32_t dsp22); \ + void FBUL(int32_t a, int32_t dsp22); \ + void FBLE(int32_t a, int32_t dsp22); \ + void FBULE(int32_t a, int32_t dsp22); \ + void FCMPD(Register rs1, Register rs2); \ + void FSUBD(Register rs1, Register rs2, Register rd); \ + void FMULD(Register rs1, Register rs2, Register rd); \ + void FDTOI(Register rs2, Register rd); \ + void FDIVD(Register rs1, Register rs2, Register rd); \ + void FMOVD(Register rs2, Register rd); \ + void FNEGD(Register rs2, Register rd); \ + void FITOD(Register rs2, Register rd); \ + void FDTOS(Register rs2, Register rd); \ + void FSTOD(Register rs2, Register rd); \ + void JMPL(Register rs1, Register rs2, Register rd); \ + void JMPLI(Register rs1, int32_t simm13, Register rd); \ + void LDF(Register rs1, Register rs2, Register rd); \ + void LDFI(Register rs1, int32_t simm13, Register rd); \ + void LDF32(Register rs1, int32_t immI, Register rd); \ + void LDDF32(Register rs1, int32_t immI, Register rd); \ + void LDUB(Register rs1, Register rs2, Register rd); \ + void LDUBI(Register rs1, int32_t simm13, Register rd); \ + void LDUB32(Register rs1, int32_t immI, Register rd); \ + void LDSB(Register rs1, Register rs2, Register rd); \ + void LDSBI(Register rs1, int32_t simm13, Register rd); \ + void LDSB32(Register rs1, int32_t immI, Register rd); \ + void LDUH(Register rs1, Register rs2, Register rd); \ + void LDUHI(Register rs1, int32_t simm13, Register rd); \ + void LDUH32(Register rs1, int32_t immI, Register rd); \ + void LDSH(Register rs1, Register rs2, Register rd); \ + void LDSHI(Register rs1, int32_t simm13, Register rd); \ + void LDSH32(Register rs1, int32_t immI, Register rd); \ + void LDSW(Register rs1, Register rs2, Register rd); \ + void LDSWI(Register rs1, int32_t simm13, Register rd); \ + void LDSW32(Register rs1, int32_t immI, Register rd); \ + void MOVE(Register rs, Register rd); \ + void MOVNE(Register rs, Register rd); \ + void MOVL(Register rs, Register rd); \ + void MOVLE(Register rs, Register rd); \ + void MOVG(Register rs, Register rd); \ + void MOVGE(Register rs, Register rd); \ + void MOVLEU(Register rs, Register rd); \ + void MOVGU(Register rs, Register rd); \ + void MOVCC(Register rs, Register rd); \ + void MOVCS(Register rs, Register rd); \ + void MOVVC(Register rs, Register rd); \ + void MOVEI(int32_t simm11, Register rd); \ + void MOVNEI(int32_t simm11, Register rd); \ + void MOVLI(int32_t simm11, Register rd); \ + void MOVLEI(int32_t simm11, Register rd); \ + void MOVGI(int32_t simm11, Register rd); \ + void MOVGEI(int32_t simm11, Register rd); \ + void MOVLEUI(int32_t simm11, Register rd); \ + void MOVGUI(int32_t simm11, Register rd); \ + void MOVCCI(int32_t simm11, Register rd); \ + void MOVCSI(int32_t simm11, Register rd); \ + void MOVVSI(int32_t simm11, Register rd); \ + void MOVFEI(int32_t simm11, Register rd); \ + void MOVFLI(int32_t simm11, Register rd); \ + void MOVFLEI(int32_t simm11, Register rd); \ + void MOVFGI(int32_t simm11, Register rd); \ + void MOVFGEI(int32_t simm11, Register rd); \ + void FMOVDNE(Register rs, Register rd); \ + void FMOVDL(Register rs, Register rd); \ + void FMOVDLE(Register rs, Register rd); \ + void FMOVDLEU(Register rs, Register rd); \ + void FMOVDG(Register rs, Register rd); \ + void FMOVDGU(Register rs, Register rd); \ + void FMOVDGE(Register rs, Register rd); \ + void FMOVDCC(Register rs, Register rd); \ + void FMOVDCS(Register rs, Register rd); \ + void FMOVDFNE(Register rs, Register rd); \ + void FMOVDFUG(Register rs, Register rd); \ + void FMOVDFUGE(Register rs, Register rd); \ + void FMOVDFUL(Register rs, Register rd); \ + void FMOVDFULE(Register rs, Register rd); \ + void NOP(); \ + void RDY(Register rd); \ + void RESTORE(Register rs1, Register rs2, Register rd); \ + void SAVE(Register rs1, Register rs2, Register rd); \ + void SAVEI(Register rs1, int32_t simm13, Register rd); \ + void SETHI(int32_t immI, Register rd); \ + void SET32(int32_t immI, Register rd); \ + void SLL(Register rs1, Register rs2, Register rd); \ + void SRA(Register rs1, Register rs2, Register rd); \ + void SRAI(Register rs1, int32_t shcnt32, Register rd); \ + void SRL(Register rs1, Register rs2, Register rd); \ + void STF(Register rd, Register rs1, Register rs2); \ + void STFI(Register rd, int32_t simm13, Register rs1); \ + void STF32(Register rd, int32_t immI, Register rs1); \ + void STDF32(Register rd, int32_t immI, Register rs1); \ + void STW(Register rd, Register rs1, Register rs2); \ + void STWI(Register rd, int32_t simm13, Register rs1); \ + void STW32(Register rd, int32_t immI, Register rs1); \ + void STH(Register rd, Register rs1, Register rs2); \ + void STHI(Register rd, int32_t simm13, Register rs1); \ + void STH32(Register rd, int32_t immI, Register rs1); \ + void STB(Register rd, Register rs1, Register rs2); \ + void STBI(Register rd, int32_t simm13, Register rs1); \ + void STB32(Register rd, int32_t immI, Register rs1); \ + bool isIMM13(int32_t imm) { return (imm) <= 0xfff && (imm) >= -0x1000; } \ + bool isIMM19(int32_t imm) { return (imm) <= 0x3ffff && (imm) >= -0x40000; } \ + bool isIMM22(int32_t imm) { return (imm) <= 0x1fffff && (imm) >= -0x200000; } \ + void JMP_long_nocheck(int32_t t); \ + void JMP_long(int32_t t); \ + void JMP_long_placeholder(); \ + int32_t JCC(void *t); \ + void JMP(void *t); \ + void MR(Register rd, Register rs); +} +#endif // __nanojit_NativeSparc__ diff --git a/js/src/nanojit/NativeX64.cpp b/js/src/nanojit/NativeX64.cpp new file mode 100644 index 0000000..39fd4e0 --- /dev/null +++ b/js/src/nanojit/NativeX64.cpp @@ -0,0 +1,2214 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nanojit.h" + +// uncomment this to enable _vprof/_nvprof macros +//#define DOPROF +#include "../vprof/vprof.h" + +#if defined FEATURE_NANOJIT && defined NANOJIT_X64 + +/* +completion +- 64bit branch offsets +- finish cmov/qcmov with other conditions +- validate asm_cond with other conditions + +better code +- put R12 back in play as a base register +- no-disp addr modes (except RBP/R13) +- disp64 branch/call +- spill gp values to xmm registers? +- prefer xmm registers for copies since gprs are in higher demand? +- stack arg doubles +- stack based LIR_paramp + +tracing +- nFragExit + +*/ + +namespace nanojit +{ + const Register Assembler::retRegs[] = { RAX }; +#ifdef _WIN64 + const Register Assembler::argRegs[] = { RCX, RDX, R8, R9 }; + const static int maxArgRegs = 4; + const Register Assembler::savedRegs[] = { RBX, RSI, RDI, R12, R13, R14, R15 }; +#else + const Register Assembler::argRegs[] = { RDI, RSI, RDX, RCX, R8, R9 }; + const static int maxArgRegs = 6; + const Register Assembler::savedRegs[] = { RBX, R12, R13, R14, R15 }; +#endif + + const char *regNames[] = { + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", + "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" + }; + + const char *gpRegNames32[] = { + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", + "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" + }; + + const char *gpRegNames8[] = { + "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", + "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l" + }; + + const char *gpRegNames8hi[] = { + "ah", "ch", "dh", "bh" + }; + + const char *gpRegNames16[] = { + "ax", "cx", "dx", "bx", "spx", "bpx", "six", "dix", + "r8x", "r9x", "r10x", "r11x", "r12x", "r13x", "r14x", "r15x" + }; + +#ifdef _DEBUG + #define TODO(x) todo(#x) + static void todo(const char *s) { + verbose_only( avmplus::AvmLog("%s",s); ) + NanoAssertMsgf(false, "%s", s); + } +#else + #define TODO(x) +#endif + + // MODRM and SIB restrictions: + // memory access modes != 11 require SIB if base&7 == 4 (RSP or R12) + // mode 00 with base == x101 means RIP+disp32 (RBP or R13), use mode 01 disp8=0 instead + // mode 01 or 11 with base = x101 means disp32 + EBP or R13, not RIP relative + // base == x100 means SIB byte is present, so using ESP|R12 as base requires SIB + // rex prefix required to use RSP-R15 as 8bit registers in mod/rm8 modes. + + // take R12 out of play as a base register because using ESP or R12 as base requires the SIB byte + const RegisterMask BaseRegs = GpRegs & ~rmask(R12); + + static inline int oplen(uint64_t op) { + return op & 255; + } + + // encode 2-register rex prefix. dropped if none of its bits are set. + static inline uint64_t rexrb(uint64_t op, Register r, Register b) { + int shift = 64 - 8*oplen(op); + uint64_t rex = ((op >> shift) & 255) | ((REGNUM(r)&8)>>1) | ((REGNUM(b)&8)>>3); + return rex != 0x40 ? op | rex << shift : op - 1; + } + + // encode 3-register rex prefix. dropped if none of its bits are set. + static inline uint64_t rexrxb(uint64_t op, Register r, Register x, Register b) { + int shift = 64 - 8*oplen(op); + uint64_t rex = ((op >> shift) & 255) | ((REGNUM(r)&8)>>1) | ((REGNUM(x)&8)>>2) | ((REGNUM(b)&8)>>3); + return rex != 0x40 ? op | rex << shift : op - 1; + } + + // encode 2-register rex prefix. dropped if none of its bits are set, but + // keep REX if b >= rsp, to allow uniform use of all 16 8bit registers + static inline uint64_t rexrb8(uint64_t op, Register r, Register b) { + int shift = 64 - 8*oplen(op); + uint64_t rex = ((op >> shift) & 255) | ((REGNUM(r)&8)>>1) | ((REGNUM(b)&8)>>3); + return ((rex | (REGNUM(b) & ~3)) != 0x40) ? (op | (rex << shift)) : op - 1; + } + + // encode 2-register rex prefix that follows a manditory prefix (66,F2,F3) + // [prefix][rex][opcode] + static inline uint64_t rexprb(uint64_t op, Register r, Register b) { + int shift = 64 - 8*oplen(op) + 8; + uint64_t rex = ((op >> shift) & 255) | ((REGNUM(r)&8)>>1) | ((REGNUM(b)&8)>>3); + // to drop rex, we replace rex with manditory prefix, and decrement length + return rex != 0x40 ? op | rex << shift : + ((op & ~(255LL<>(shift-8)&255) << shift) - 1; + } + + // [rex][opcode][mod-rr] + static inline uint64_t mod_rr(uint64_t op, Register r, Register b) { + return op | uint64_t((REGNUM(r)&7)<<3 | (REGNUM(b)&7))<<56; + } + + // [rex][opcode][modrm=r][sib=xb] + static inline uint64_t mod_rxb(uint64_t op, Register r, Register x, Register b) { + return op | /*modrm*/uint64_t((REGNUM(r)&7)<<3)<<48 | /*sib*/uint64_t((REGNUM(x)&7)<<3|(REGNUM(b)&7))<<56; + } + + static inline uint64_t mod_disp32(uint64_t op, Register r, Register b, int32_t d) { + NanoAssert(IsGpReg(r) && IsGpReg(b)); + NanoAssert((REGNUM(b) & 7) != 4); // using RSP or R12 as base requires SIB + uint64_t mod = (((op>>24)&255)>>6); // mod bits in addressing mode: 0,1,2, or 3 + if (mod == 2 && isS8(d)) { + // op is: 0x[disp32=0][mod=2:r:b][op][rex][len] + int len = oplen(op); + op = (op & ~0xff000000LL) | (0x40 | (REGNUM(r)&7)<<3 | (REGNUM(b)&7))<<24; // replace mod + return op<<24 | int64_t(d)<<56 | (len-3); // shrink disp, add disp8 + } else { + // op is: 0x[disp32][mod][op][rex][len] + return op | int64_t(d)<<32 | uint64_t((REGNUM(r)&7)<<3 | (REGNUM(b)&7))<<24; + } + } + + // All the emit() functions should only be called from within codegen + // functions PUSHR(), SHR(), etc. + + void Assembler::emit(uint64_t op) { + int len = oplen(op); + // we will only move nIns by -len bytes, but we write 8 + // bytes. so need to protect 8 so we dont stomp the page + // header or the end of the preceding page (might segf) + underrunProtect(8); + ((int64_t*)_nIns)[-1] = op; + _nIns -= len; // move pointer by length encoded in opcode + _nvprof("x64-bytes", len); + } + + void Assembler::emit8(uint64_t op, int64_t v) { + NanoAssert(isS8(v)); + emit(op | uint64_t(v)<<56); + } + + void Assembler::emit_target8(size_t underrun, uint64_t op, NIns* target) { + underrunProtect(underrun); // must do this before calculating offset + // Nb: see emit_target32() for why we use _nIns here. + int64_t offset = target - _nIns; + NanoAssert(isS8(offset)); + emit(op | uint64_t(offset)<<56); + } + + void Assembler::emit_target32(size_t underrun, uint64_t op, NIns* target) { + underrunProtect(underrun); // must do this before calculating offset + // Nb: at this point in time, _nIns points to the most recently + // written instruction, ie. the jump's successor. So why do we use it + // to compute the offset, rather than the jump's address? Because in + // x86/x64-64 the offset in a relative jump is not from the jmp itself + // but from the following instruction. Eg. 'jmp $0' will jump to the + // next instruction. + int64_t offset = target ? target - _nIns : 0; + if (!isS32(offset)) { + setError(BranchTooFar); + NanoAssert(0); // assert because we'd like to know if this ever happens + } + emit(op | uint64_t(uint32_t(offset))<<32); + } + + void Assembler::emit_target64(size_t underrun, uint64_t op, NIns* target) { + NanoAssert(underrun >= 16); + underrunProtect(underrun); // must do this before calculating offset + // Nb: at this point in time, _nIns points to the most recently + // written instruction, ie. the jump's successor. + ((uint64_t*)_nIns)[-1] = (uint64_t) target; + _nIns -= 8; + emit(op); + } + + // 3-register modrm32+sib form + void Assembler::emitrxb(uint64_t op, Register r, Register x, Register b) { + emit(rexrxb(mod_rxb(op, r, x, b), r, x, b)); + } + + // 2-register modrm32 form + void Assembler::emitrr(uint64_t op, Register r, Register b) { + emit(rexrb(mod_rr(op, r, b), r, b)); + } + + // 2-register modrm8 form (8 bit operand size) + void Assembler::emitrr8(uint64_t op, Register r, Register b) { + emit(rexrb8(mod_rr(op, r, b), r, b)); + } + + // same as emitrr, but with a prefix byte + void Assembler::emitprr(uint64_t op, Register r, Register b) { + emit(rexprb(mod_rr(op, r, b), r, b)); + } + + // disp32 modrm8 form, when the disp fits in the instruction (opcode is 1-3 bytes) + void Assembler::emitrm8(uint64_t op, Register r, int32_t d, Register b) { + emit(rexrb8(mod_disp32(op, r, b, d), r, b)); + } + + // disp32 modrm form, when the disp fits in the instruction (opcode is 1-3 bytes) + void Assembler::emitrm(uint64_t op, Register r, int32_t d, Register b) { + emit(rexrb(mod_disp32(op, r, b, d), r, b)); + } + + // disp32 modrm form when the disp must be written separately (opcode is 4+ bytes) + uint64_t Assembler::emit_disp32(uint64_t op, int32_t d) { + if (isS8(d)) { + NanoAssert(((op>>56)&0xC0) == 0x80); // make sure mod bits == 2 == disp32 mode + underrunProtect(1+8); + *(--_nIns) = (NIns) d; + _nvprof("x64-bytes", 1); + op ^= 0xC000000000000000LL; // change mod bits to 1 == disp8 mode + } else { + underrunProtect(4+8); // room for displ plus fullsize op + *((int32_t*)(_nIns -= 4)) = d; + _nvprof("x64-bytes", 4); + } + return op; + } + + // disp32 modrm form when the disp must be written separately (opcode is 4+ bytes) + void Assembler::emitrm_wide(uint64_t op, Register r, int32_t d, Register b) { + op = emit_disp32(op, d); + emitrr(op, r, b); + } + + // disp32 modrm form when the disp must be written separately (opcode is 4+ bytes) + // p = prefix -- opcode must have a 66, F2, or F3 prefix + void Assembler::emitprm(uint64_t op, Register r, int32_t d, Register b) { + op = emit_disp32(op, d); + emitprr(op, r, b); + } + + // disp32 modrm form with 32-bit immediate value + void Assembler::emitrm_imm32(uint64_t op, Register b, int32_t d, int32_t imm) { + NanoAssert(IsGpReg(b)); + NanoAssert((REGNUM(b) & 7) != 4); // using RSP or R12 as base requires SIB + underrunProtect(4+4+8); // room for imm plus disp plus fullsize op + *((int32_t*)(_nIns -= 4)) = imm; + _nvprof("x86-bytes", 4); + emitrm_wide(op, RZero, d, b); + } + + // disp32 modrm form with 16-bit immediate value + // p = prefix -- opcode must have a 66, F2, or F3 prefix + void Assembler::emitprm_imm16(uint64_t op, Register b, int32_t d, int32_t imm) { + NanoAssert(IsGpReg(b)); + NanoAssert((REGNUM(b) & 7) != 4); // using RSP or R12 as base requires SIB + underrunProtect(2+4+8); // room for imm plus disp plus fullsize op + *((int16_t*)(_nIns -= 2)) = (int16_t) imm; + _nvprof("x86-bytes", 2); + emitprm(op, RZero, d, b); + } + + // disp32 modrm form with 8-bit immediate value + void Assembler::emitrm_imm8(uint64_t op, Register b, int32_t d, int32_t imm) { + NanoAssert(IsGpReg(b)); + NanoAssert((REGNUM(b) & 7) != 4); // using RSP or R12 as base requires SIB + underrunProtect(1+4+8); // room for imm plus disp plus fullsize op + *((int8_t*)(_nIns -= 1)) = (int8_t) imm; + _nvprof("x86-bytes", 1); + emitrm_wide(op, RZero, d, b); + } + + void Assembler::emitrr_imm(uint64_t op, Register r, Register b, int32_t imm) { + NanoAssert(IsGpReg(r) && IsGpReg(b)); + underrunProtect(4+8); // room for imm plus fullsize op + *((int32_t*)(_nIns -= 4)) = imm; + _nvprof("x86-bytes", 4); + emitrr(op, r, b); + } + + void Assembler::emitr_imm64(uint64_t op, Register r, uint64_t imm64) { + underrunProtect(8+8); // imm64 + worst case instr len + *((uint64_t*)(_nIns -= 8)) = imm64; + _nvprof("x64-bytes", 8); + emitr(op, r); + } + + void Assembler::emitrxb_imm(uint64_t op, Register r, Register x, Register b, int32_t imm) { + NanoAssert(IsGpReg(r) && IsGpReg(x) && IsGpReg(b)); + underrunProtect(4+8); // room for imm plus fullsize op + *((int32_t*)(_nIns -= 4)) = imm; + _nvprof("x86-bytes", 4); + emitrxb(op, r, x, b); + } + + // op = [rex][opcode][modrm][imm8] + void Assembler::emitr_imm8(uint64_t op, Register b, int32_t imm8) { + NanoAssert(IsGpReg(b) && isS8(imm8)); + op |= uint64_t(imm8)<<56 | uint64_t(REGNUM(b)&7)<<48; // modrm is 2nd to last byte + emit(rexrb(op, RZero, b)); + } + + void Assembler::emitxm_abs(uint64_t op, Register r, int32_t addr32) + { + underrunProtect(4+8); + *((int32_t*)(_nIns -= 4)) = addr32; + _nvprof("x64-bytes", 4); + op = op | uint64_t((REGNUM(r)&7)<<3)<<48; // put rr[0:2] into mod/rm byte + op = rexrb(op, r, RZero); // put rr[3] into rex byte + emit(op); + } + + void Assembler::emitxm_rel(uint64_t op, Register r, NIns* addr64) + { + underrunProtect(4+8); + int32_t d = (int32_t)(addr64 - _nIns); + *((int32_t*)(_nIns -= 4)) = d; + _nvprof("x64-bytes", 4); + emitrr(op, r, RZero); + } + + // Succeeds if 'target' is within a signed 8-bit offset from the current + // instruction's address. + bool Assembler::isTargetWithinS8(NIns* target) + { + NanoAssert(target); + // First call underrunProtect(). Without it, we might compute the + // difference just before starting a new code chunk. + underrunProtect(8); + return isS8(target - _nIns); + } + + // Like isTargetWithinS8(), but for signed 32-bit offsets. + bool Assembler::isTargetWithinS32(NIns* target) + { + NanoAssert(target); + underrunProtect(8); + return isS32(target - _nIns); + } + +#define RB(r) gpRegNames8[(REGNUM(r))] +#define RS(r) gpRegNames16[(REGNUM(r))] +#define RBhi(r) gpRegNames8hi[(REGNUM(r))] +#define RL(r) gpRegNames32[(REGNUM(r))] +#define RQ(r) gpn(r) + + typedef Register R; + typedef int I; + typedef int32_t I32; + typedef uint64_t U64; + typedef size_t S; + + void Assembler::PUSHR(R r) { emitr(X64_pushr,r); asm_output("push %s", RQ(r)); } + void Assembler::POPR( R r) { emitr(X64_popr, r); asm_output("pop %s", RQ(r)); } + void Assembler::NOT( R r) { emitr(X64_not, r); asm_output("notl %s", RL(r)); } + void Assembler::NEG( R r) { emitr(X64_neg, r); asm_output("negl %s", RL(r)); } + void Assembler::IDIV( R r) { emitr(X64_idiv, r); asm_output("idivl edx:eax, %s",RL(r)); } + + void Assembler::SHR( R r) { emitr(X64_shr, r); asm_output("shrl %s, ecx", RL(r)); } + void Assembler::SAR( R r) { emitr(X64_sar, r); asm_output("sarl %s, ecx", RL(r)); } + void Assembler::SHL( R r) { emitr(X64_shl, r); asm_output("shll %s, ecx", RL(r)); } + void Assembler::SHRQ(R r) { emitr(X64_shrq, r); asm_output("shrq %s, ecx", RQ(r)); } + void Assembler::SARQ(R r) { emitr(X64_sarq, r); asm_output("sarq %s, ecx", RQ(r)); } + void Assembler::SHLQ(R r) { emitr(X64_shlq, r); asm_output("shlq %s, ecx", RQ(r)); } + + void Assembler::SHRI( R r, I i) { emit8(rexrb(X64_shri | U64(REGNUM(r)&7)<<48, RZero, r), i); asm_output("shrl %s, %d", RL(r), i); } + void Assembler::SARI( R r, I i) { emit8(rexrb(X64_sari | U64(REGNUM(r)&7)<<48, RZero, r), i); asm_output("sarl %s, %d", RL(r), i); } + void Assembler::SHLI( R r, I i) { emit8(rexrb(X64_shli | U64(REGNUM(r)&7)<<48, RZero, r), i); asm_output("shll %s, %d", RL(r), i); } + void Assembler::SHRQI(R r, I i) { emit8(rexrb(X64_shrqi | U64(REGNUM(r)&7)<<48, RZero, r), i); asm_output("shrq %s, %d", RQ(r), i); } + void Assembler::SARQI(R r, I i) { emit8(rexrb(X64_sarqi | U64(REGNUM(r)&7)<<48, RZero, r), i); asm_output("sarq %s, %d", RQ(r), i); } + void Assembler::SHLQI(R r, I i) { emit8(rexrb(X64_shlqi | U64(REGNUM(r)&7)<<48, RZero, r), i); asm_output("shlq %s, %d", RQ(r), i); } + + void Assembler::SETE( R r) { emitr8(X64_sete, r); asm_output("sete %s", RB(r)); } + void Assembler::SETL( R r) { emitr8(X64_setl, r); asm_output("setl %s", RB(r)); } + void Assembler::SETLE(R r) { emitr8(X64_setle,r); asm_output("setle %s",RB(r)); } + void Assembler::SETG( R r) { emitr8(X64_setg, r); asm_output("setg %s", RB(r)); } + void Assembler::SETGE(R r) { emitr8(X64_setge,r); asm_output("setge %s",RB(r)); } + void Assembler::SETB( R r) { emitr8(X64_setb, r); asm_output("setb %s", RB(r)); } + void Assembler::SETBE(R r) { emitr8(X64_setbe,r); asm_output("setbe %s",RB(r)); } + void Assembler::SETA( R r) { emitr8(X64_seta, r); asm_output("seta %s", RB(r)); } + void Assembler::SETAE(R r) { emitr8(X64_setae,r); asm_output("setae %s",RB(r)); } + void Assembler::SETO( R r) { emitr8(X64_seto, r); asm_output("seto %s", RB(r)); } + + void Assembler::ADDRR(R l, R r) { emitrr(X64_addrr,l,r); asm_output("addl %s, %s", RL(l),RL(r)); } + void Assembler::SUBRR(R l, R r) { emitrr(X64_subrr,l,r); asm_output("subl %s, %s", RL(l),RL(r)); } + void Assembler::ANDRR(R l, R r) { emitrr(X64_andrr,l,r); asm_output("andl %s, %s", RL(l),RL(r)); } + void Assembler::ORLRR(R l, R r) { emitrr(X64_orlrr,l,r); asm_output("orl %s, %s", RL(l),RL(r)); } + void Assembler::XORRR(R l, R r) { emitrr(X64_xorrr,l,r); asm_output("xorl %s, %s", RL(l),RL(r)); } + void Assembler::IMUL( R l, R r) { emitrr(X64_imul, l,r); asm_output("imull %s, %s",RL(l),RL(r)); } + void Assembler::CMPLR(R l, R r) { emitrr(X64_cmplr,l,r); asm_output("cmpl %s, %s", RL(l),RL(r)); } + void Assembler::MOVLR(R l, R r) { emitrr(X64_movlr,l,r); asm_output("movl %s, %s", RL(l),RL(r)); } + + void Assembler::ADDQRR( R l, R r) { emitrr(X64_addqrr, l,r); asm_output("addq %s, %s", RQ(l),RQ(r)); } + void Assembler::SUBQRR( R l, R r) { emitrr(X64_subqrr, l,r); asm_output("subq %s, %s", RQ(l),RQ(r)); } + void Assembler::ANDQRR( R l, R r) { emitrr(X64_andqrr, l,r); asm_output("andq %s, %s", RQ(l),RQ(r)); } + void Assembler::ORQRR( R l, R r) { emitrr(X64_orqrr, l,r); asm_output("orq %s, %s", RQ(l),RQ(r)); } + void Assembler::XORQRR( R l, R r) { emitrr(X64_xorqrr, l,r); asm_output("xorq %s, %s", RQ(l),RQ(r)); } + void Assembler::CMPQR( R l, R r) { emitrr(X64_cmpqr, l,r); asm_output("cmpq %s, %s", RQ(l),RQ(r)); } + void Assembler::MOVQR( R l, R r) { emitrr(X64_movqr, l,r); asm_output("movq %s, %s", RQ(l),RQ(r)); } + void Assembler::MOVAPSR(R l, R r) { emitrr(X64_movapsr,l,r); asm_output("movaps %s, %s",RQ(l),RQ(r)); } + + void Assembler::CMOVNO( R l, R r) { emitrr(X64_cmovno, l,r); asm_output("cmovlno %s, %s", RL(l),RL(r)); } + void Assembler::CMOVNE( R l, R r) { emitrr(X64_cmovne, l,r); asm_output("cmovlne %s, %s", RL(l),RL(r)); } + void Assembler::CMOVNL( R l, R r) { emitrr(X64_cmovnl, l,r); asm_output("cmovlnl %s, %s", RL(l),RL(r)); } + void Assembler::CMOVNLE(R l, R r) { emitrr(X64_cmovnle,l,r); asm_output("cmovlnle %s, %s", RL(l),RL(r)); } + void Assembler::CMOVNG( R l, R r) { emitrr(X64_cmovng, l,r); asm_output("cmovlng %s, %s", RL(l),RL(r)); } + void Assembler::CMOVNGE(R l, R r) { emitrr(X64_cmovnge,l,r); asm_output("cmovlnge %s, %s", RL(l),RL(r)); } + void Assembler::CMOVNB( R l, R r) { emitrr(X64_cmovnb, l,r); asm_output("cmovlnb %s, %s", RL(l),RL(r)); } + void Assembler::CMOVNBE(R l, R r) { emitrr(X64_cmovnbe,l,r); asm_output("cmovlnbe %s, %s", RL(l),RL(r)); } + void Assembler::CMOVNA( R l, R r) { emitrr(X64_cmovna, l,r); asm_output("cmovlna %s, %s", RL(l),RL(r)); } + void Assembler::CMOVNAE(R l, R r) { emitrr(X64_cmovnae,l,r); asm_output("cmovlnae %s, %s", RL(l),RL(r)); } + + void Assembler::CMOVQNO( R l, R r) { emitrr(X64_cmovqno, l,r); asm_output("cmovqno %s, %s", RQ(l),RQ(r)); } + void Assembler::CMOVQNE( R l, R r) { emitrr(X64_cmovqne, l,r); asm_output("cmovqne %s, %s", RQ(l),RQ(r)); } + void Assembler::CMOVQNL( R l, R r) { emitrr(X64_cmovqnl, l,r); asm_output("cmovqnl %s, %s", RQ(l),RQ(r)); } + void Assembler::CMOVQNLE(R l, R r) { emitrr(X64_cmovqnle,l,r); asm_output("cmovqnle %s, %s", RQ(l),RQ(r)); } + void Assembler::CMOVQNG( R l, R r) { emitrr(X64_cmovqng, l,r); asm_output("cmovqng %s, %s", RQ(l),RQ(r)); } + void Assembler::CMOVQNGE(R l, R r) { emitrr(X64_cmovqnge,l,r); asm_output("cmovqnge %s, %s", RQ(l),RQ(r)); } + void Assembler::CMOVQNB( R l, R r) { emitrr(X64_cmovqnb, l,r); asm_output("cmovqnb %s, %s", RQ(l),RQ(r)); } + void Assembler::CMOVQNBE(R l, R r) { emitrr(X64_cmovqnbe,l,r); asm_output("cmovqnbe %s, %s", RQ(l),RQ(r)); } + void Assembler::CMOVQNA( R l, R r) { emitrr(X64_cmovqna, l,r); asm_output("cmovqna %s, %s", RQ(l),RQ(r)); } + void Assembler::CMOVQNAE(R l, R r) { emitrr(X64_cmovqnae,l,r); asm_output("cmovqnae %s, %s", RQ(l),RQ(r)); } + + void Assembler::MOVSXDR(R l, R r) { emitrr(X64_movsxdr,l,r); asm_output("movsxd %s, %s",RQ(l),RL(r)); } + + void Assembler::MOVZX8(R l, R r) { emitrr8(X64_movzx8,l,r); asm_output("movzx %s, %s",RQ(l),RB(r)); } + +// XORPS is a 4x32f vector operation, we use it instead of the more obvious +// XORPD because it's one byte shorter. This is ok because it's only used for +// zeroing an XMM register; hence the single argument. +// Also note that (unlike most SSE2 instructions) XORPS does not have a prefix, thus emitrr() should be used. + void Assembler::XORPS( R r) { emitrr(X64_xorps, r,r); asm_output("xorps %s, %s", RQ(r),RQ(r)); } + void Assembler::XORPS( R l, R r) { emitrr(X64_xorps, l,r); asm_output("xorps %s, %s", RQ(l),RQ(r)); } + void Assembler::DIVSD( R l, R r) { emitprr(X64_divsd, l,r); asm_output("divsd %s, %s", RQ(l),RQ(r)); } + void Assembler::MULSD( R l, R r) { emitprr(X64_mulsd, l,r); asm_output("mulsd %s, %s", RQ(l),RQ(r)); } + void Assembler::ADDSD( R l, R r) { emitprr(X64_addsd, l,r); asm_output("addsd %s, %s", RQ(l),RQ(r)); } + void Assembler::SUBSD( R l, R r) { emitprr(X64_subsd, l,r); asm_output("subsd %s, %s", RQ(l),RQ(r)); } + void Assembler::CVTSQ2SD(R l, R r) { emitprr(X64_cvtsq2sd,l,r); asm_output("cvtsq2sd %s, %s",RQ(l),RQ(r)); } + void Assembler::CVTSI2SD(R l, R r) { emitprr(X64_cvtsi2sd,l,r); asm_output("cvtsi2sd %s, %s",RQ(l),RL(r)); } + void Assembler::CVTSS2SD(R l, R r) { emitprr(X64_cvtss2sd,l,r); asm_output("cvtss2sd %s, %s",RQ(l),RL(r)); } + void Assembler::CVTSD2SS(R l, R r) { emitprr(X64_cvtsd2ss,l,r); asm_output("cvtsd2ss %s, %s",RL(l),RQ(r)); } + void Assembler::CVTSD2SI(R l, R r) { emitprr(X64_cvtsd2si,l,r); asm_output("cvtsd2si %s, %s",RL(l),RQ(r)); } + void Assembler::CVTTSD2SI(R l, R r) { emitprr(X64_cvttsd2si,l,r);asm_output("cvttsd2si %s, %s",RL(l),RQ(r));} + void Assembler::UCOMISD( R l, R r) { emitprr(X64_ucomisd, l,r); asm_output("ucomisd %s, %s", RQ(l),RQ(r)); } + void Assembler::MOVQRX( R l, R r) { emitprr(X64_movqrx, r,l); asm_output("movq %s, %s", RQ(l),RQ(r)); } // Nb: r and l are deliberately reversed within the emitprr() call. + void Assembler::MOVQXR( R l, R r) { emitprr(X64_movqxr, l,r); asm_output("movq %s, %s", RQ(l),RQ(r)); } + + // MOVI must not affect condition codes! + void Assembler::MOVI( R r, I32 i32) { emitr_imm(X64_movi, r,i32); asm_output("movl %s, %d",RL(r),i32); } + void Assembler::ADDLRI(R r, I32 i32) { emitr_imm(X64_addlri,r,i32); asm_output("addl %s, %d",RL(r),i32); } + void Assembler::SUBLRI(R r, I32 i32) { emitr_imm(X64_sublri,r,i32); asm_output("subl %s, %d",RL(r),i32); } + void Assembler::ANDLRI(R r, I32 i32) { emitr_imm(X64_andlri,r,i32); asm_output("andl %s, %d",RL(r),i32); } + void Assembler::ORLRI( R r, I32 i32) { emitr_imm(X64_orlri, r,i32); asm_output("orl %s, %d", RL(r),i32); } + void Assembler::XORLRI(R r, I32 i32) { emitr_imm(X64_xorlri,r,i32); asm_output("xorl %s, %d",RL(r),i32); } + void Assembler::CMPLRI(R r, I32 i32) { emitr_imm(X64_cmplri,r,i32); asm_output("cmpl %s, %d",RL(r),i32); } + + void Assembler::ADDQRI( R r, I32 i32) { emitr_imm(X64_addqri, r,i32); asm_output("addq %s, %d", RQ(r),i32); } + void Assembler::SUBQRI( R r, I32 i32) { emitr_imm(X64_subqri, r,i32); asm_output("subq %s, %d", RQ(r),i32); } + void Assembler::ANDQRI( R r, I32 i32) { emitr_imm(X64_andqri, r,i32); asm_output("andq %s, %d", RQ(r),i32); } + void Assembler::ORQRI( R r, I32 i32) { emitr_imm(X64_orqri, r,i32); asm_output("orq %s, %d", RQ(r),i32); } + void Assembler::XORQRI( R r, I32 i32) { emitr_imm(X64_xorqri, r,i32); asm_output("xorq %s, %d", RQ(r),i32); } + void Assembler::CMPQRI( R r, I32 i32) { emitr_imm(X64_cmpqri, r,i32); asm_output("cmpq %s, %d", RQ(r),i32); } + void Assembler::MOVQI32(R r, I32 i32) { emitr_imm(X64_movqi32,r,i32); asm_output("movqi32 %s, %d",RQ(r),i32); } + + void Assembler::ADDLR8(R r, I32 i8) { emitr_imm8(X64_addlr8,r,i8); asm_output("addl %s, %d", RL(r),i8); } + void Assembler::SUBLR8(R r, I32 i8) { emitr_imm8(X64_sublr8,r,i8); asm_output("subl %s, %d", RL(r),i8); } + void Assembler::ANDLR8(R r, I32 i8) { emitr_imm8(X64_andlr8,r,i8); asm_output("andl %s, %d", RL(r),i8); } + void Assembler::ORLR8( R r, I32 i8) { emitr_imm8(X64_orlr8, r,i8); asm_output("orl %s, %d", RL(r),i8); } + void Assembler::XORLR8(R r, I32 i8) { emitr_imm8(X64_xorlr8,r,i8); asm_output("xorl %s, %d", RL(r),i8); } + void Assembler::CMPLR8(R r, I32 i8) { emitr_imm8(X64_cmplr8,r,i8); asm_output("cmpl %s, %d", RL(r),i8); } + + void Assembler::ADDQR8(R r, I32 i8) { emitr_imm8(X64_addqr8,r,i8); asm_output("addq %s, %d",RQ(r),i8); } + void Assembler::SUBQR8(R r, I32 i8) { emitr_imm8(X64_subqr8,r,i8); asm_output("subq %s, %d",RQ(r),i8); } + void Assembler::ANDQR8(R r, I32 i8) { emitr_imm8(X64_andqr8,r,i8); asm_output("andq %s, %d",RQ(r),i8); } + void Assembler::ORQR8( R r, I32 i8) { emitr_imm8(X64_orqr8, r,i8); asm_output("orq %s, %d", RQ(r),i8); } + void Assembler::XORQR8(R r, I32 i8) { emitr_imm8(X64_xorqr8,r,i8); asm_output("xorq %s, %d",RQ(r),i8); } + void Assembler::CMPQR8(R r, I32 i8) { emitr_imm8(X64_cmpqr8,r,i8); asm_output("cmpq %s, %d",RQ(r),i8); } + + void Assembler::IMULI(R l, R r, I32 i32) { emitrr_imm(X64_imuli,l,r,i32); asm_output("imuli %s, %s, %d",RL(l),RL(r),i32); } + + void Assembler::MOVQI(R r, U64 u64) { emitr_imm64(X64_movqi,r,u64); asm_output("movq %s, %p",RQ(r),(void*)u64); } + + void Assembler::LEARIP(R r, I32 d) { emitrm(X64_learip,r,d,RZero); asm_output("lea %s, %d(rip)",RQ(r),d); } + + void Assembler::LEALRM(R r, I d, R b) { emitrm(X64_lealrm,r,d,b); asm_output("leal %s, %d(%s)",RL(r),d,RL(b)); } + void Assembler::LEAQRM(R r, I d, R b) { emitrm(X64_leaqrm,r,d,b); asm_output("leaq %s, %d(%s)",RQ(r),d,RQ(b)); } + void Assembler::MOVLRM(R r, I d, R b) { emitrm(X64_movlrm,r,d,b); asm_output("movl %s, %d(%s)",RL(r),d,RQ(b)); } + void Assembler::MOVQRM(R r, I d, R b) { emitrm(X64_movqrm,r,d,b); asm_output("movq %s, %d(%s)",RQ(r),d,RQ(b)); } + void Assembler::MOVBMR(R r, I d, R b) { emitrm8(X64_movbmr,r,d,b); asm_output("movb %d(%s), %s",d,RQ(b),RB(r)); } + void Assembler::MOVSMR(R r, I d, R b) { emitprm(X64_movsmr,r,d,b); asm_output("movs %d(%s), %s",d,RQ(b),RS(r)); } + void Assembler::MOVLMR(R r, I d, R b) { emitrm(X64_movlmr,r,d,b); asm_output("movl %d(%s), %s",d,RQ(b),RL(r)); } + void Assembler::MOVQMR(R r, I d, R b) { emitrm(X64_movqmr,r,d,b); asm_output("movq %d(%s), %s",d,RQ(b),RQ(r)); } + + void Assembler::MOVZX8M( R r, I d, R b) { emitrm_wide(X64_movzx8m, r,d,b); asm_output("movzxb %s, %d(%s)",RQ(r),d,RQ(b)); } + void Assembler::MOVZX16M(R r, I d, R b) { emitrm_wide(X64_movzx16m,r,d,b); asm_output("movzxs %s, %d(%s)",RQ(r),d,RQ(b)); } + + void Assembler::MOVSX8M( R r, I d, R b) { emitrm_wide(X64_movsx8m, r,d,b); asm_output("movsxb %s, %d(%s)",RQ(r),d,RQ(b)); } + void Assembler::MOVSX16M(R r, I d, R b) { emitrm_wide(X64_movsx16m,r,d,b); asm_output("movsxs %s, %d(%s)",RQ(r),d,RQ(b)); } + + void Assembler::MOVSDRM(R r, I d, R b) { emitprm(X64_movsdrm,r,d,b); asm_output("movsd %s, %d(%s)",RQ(r),d,RQ(b)); } + void Assembler::MOVSDMR(R r, I d, R b) { emitprm(X64_movsdmr,r,d,b); asm_output("movsd %d(%s), %s",d,RQ(b),RQ(r)); } + void Assembler::MOVSSRM(R r, I d, R b) { emitprm(X64_movssrm,r,d,b); asm_output("movss %s, %d(%s)",RQ(r),d,RQ(b)); } + void Assembler::MOVSSMR(R r, I d, R b) { emitprm(X64_movssmr,r,d,b); asm_output("movss %d(%s), %s",d,RQ(b),RQ(r)); } + + void Assembler::JMP8( S n, NIns* t) { emit_target8(n, X64_jmp8,t); asm_output("jmp %p", t); } + + void Assembler::JMP32(S n, NIns* t) { emit_target32(n,X64_jmp, t); asm_output("jmp %p", t); } + void Assembler::JMP64(S n, NIns* t) { emit_target64(n,X64_jmpi, t); asm_output("jmp %p", t); } + + void Assembler::JMPX(R indexreg, NIns** table) + { + Register R5 = { 5 }; + emitrxb_imm(X64_jmpx, RZero, indexreg, R5, (int32_t)(uintptr_t)table); + asm_output("jmpq [%s*8 + %p]", RQ(indexreg), (void*)table); + } + + void Assembler::JMPXB(R indexreg, R tablereg) { emitxb(X64_jmpxb, indexreg, tablereg); asm_output("jmp [%s*8 + %s]", RQ(indexreg), RQ(tablereg)); } + + void Assembler::JO( S n, NIns* t) { emit_target32(n,X64_jo, t); asm_output("jo %p", t); } + void Assembler::JE( S n, NIns* t) { emit_target32(n,X64_je, t); asm_output("je %p", t); } + void Assembler::JL( S n, NIns* t) { emit_target32(n,X64_jl, t); asm_output("jl %p", t); } + void Assembler::JLE(S n, NIns* t) { emit_target32(n,X64_jle, t); asm_output("jle %p",t); } + void Assembler::JG( S n, NIns* t) { emit_target32(n,X64_jg, t); asm_output("jg %p", t); } + void Assembler::JGE(S n, NIns* t) { emit_target32(n,X64_jge, t); asm_output("jge %p",t); } + void Assembler::JB( S n, NIns* t) { emit_target32(n,X64_jb, t); asm_output("jb %p", t); } + void Assembler::JBE(S n, NIns* t) { emit_target32(n,X64_jbe, t); asm_output("jbe %p",t); } + void Assembler::JA( S n, NIns* t) { emit_target32(n,X64_ja, t); asm_output("ja %p", t); } + void Assembler::JAE(S n, NIns* t) { emit_target32(n,X64_jae, t); asm_output("jae %p",t); } + void Assembler::JP( S n, NIns* t) { emit_target32(n,X64_jp, t); asm_output("jp %p",t); } + + void Assembler::JNO( S n, NIns* t) { emit_target32(n,X64_jo ^X64_jneg, t); asm_output("jno %p", t); } + void Assembler::JNE( S n, NIns* t) { emit_target32(n,X64_je ^X64_jneg, t); asm_output("jne %p", t); } + void Assembler::JNL( S n, NIns* t) { emit_target32(n,X64_jl ^X64_jneg, t); asm_output("jnl %p", t); } + void Assembler::JNLE(S n, NIns* t) { emit_target32(n,X64_jle^X64_jneg, t); asm_output("jnle %p",t); } + void Assembler::JNG( S n, NIns* t) { emit_target32(n,X64_jg ^X64_jneg, t); asm_output("jng %p", t); } + void Assembler::JNGE(S n, NIns* t) { emit_target32(n,X64_jge^X64_jneg, t); asm_output("jnge %p",t); } + void Assembler::JNB( S n, NIns* t) { emit_target32(n,X64_jb ^X64_jneg, t); asm_output("jnb %p", t); } + void Assembler::JNBE(S n, NIns* t) { emit_target32(n,X64_jbe^X64_jneg, t); asm_output("jnbe %p",t); } + void Assembler::JNA( S n, NIns* t) { emit_target32(n,X64_ja ^X64_jneg, t); asm_output("jna %p", t); } + void Assembler::JNAE(S n, NIns* t) { emit_target32(n,X64_jae^X64_jneg, t); asm_output("jnae %p",t); } + + void Assembler::JO8( S n, NIns* t) { emit_target8(n,X64_jo8, t); asm_output("jo %p", t); } + void Assembler::JE8( S n, NIns* t) { emit_target8(n,X64_je8, t); asm_output("je %p", t); } + void Assembler::JL8( S n, NIns* t) { emit_target8(n,X64_jl8, t); asm_output("jl %p", t); } + void Assembler::JLE8(S n, NIns* t) { emit_target8(n,X64_jle8, t); asm_output("jle %p",t); } + void Assembler::JG8( S n, NIns* t) { emit_target8(n,X64_jg8, t); asm_output("jg %p", t); } + void Assembler::JGE8(S n, NIns* t) { emit_target8(n,X64_jge8, t); asm_output("jge %p",t); } + void Assembler::JB8( S n, NIns* t) { emit_target8(n,X64_jb8, t); asm_output("jb %p", t); } + void Assembler::JBE8(S n, NIns* t) { emit_target8(n,X64_jbe8, t); asm_output("jbe %p",t); } + void Assembler::JA8( S n, NIns* t) { emit_target8(n,X64_ja8, t); asm_output("ja %p", t); } + void Assembler::JAE8(S n, NIns* t) { emit_target8(n,X64_jae8, t); asm_output("jae %p",t); } + void Assembler::JP8( S n, NIns* t) { emit_target8(n,X64_jp8, t); asm_output("jp %p",t); } + + void Assembler::JNO8( S n, NIns* t) { emit_target8(n,X64_jo8 ^X64_jneg8, t); asm_output("jno %p", t); } + void Assembler::JNE8( S n, NIns* t) { emit_target8(n,X64_je8 ^X64_jneg8, t); asm_output("jne %p", t); } + void Assembler::JNL8( S n, NIns* t) { emit_target8(n,X64_jl8 ^X64_jneg8, t); asm_output("jnl %p", t); } + void Assembler::JNLE8(S n, NIns* t) { emit_target8(n,X64_jle8^X64_jneg8, t); asm_output("jnle %p",t); } + void Assembler::JNG8( S n, NIns* t) { emit_target8(n,X64_jg8 ^X64_jneg8, t); asm_output("jng %p", t); } + void Assembler::JNGE8(S n, NIns* t) { emit_target8(n,X64_jge8^X64_jneg8, t); asm_output("jnge %p",t); } + void Assembler::JNB8( S n, NIns* t) { emit_target8(n,X64_jb8 ^X64_jneg8, t); asm_output("jnb %p", t); } + void Assembler::JNBE8(S n, NIns* t) { emit_target8(n,X64_jbe8^X64_jneg8, t); asm_output("jnbe %p",t); } + void Assembler::JNA8( S n, NIns* t) { emit_target8(n,X64_ja8 ^X64_jneg8, t); asm_output("jna %p", t); } + void Assembler::JNAE8(S n, NIns* t) { emit_target8(n,X64_jae8^X64_jneg8, t); asm_output("jnae %p",t); } + + void Assembler::CALL( S n, NIns* t) { emit_target32(n,X64_call,t); asm_output("call %p",t); } + + void Assembler::CALLRAX() { emit(X64_callrax); asm_output("call (rax)"); } + void Assembler::RET() { emit(X64_ret); asm_output("ret"); } + + void Assembler::MOVQMI(R r, I d, I32 imm) { emitrm_imm32(X64_movqmi,r,d,imm); asm_output("movq %d(%s), %d",d,RQ(r),imm); } + void Assembler::MOVLMI(R r, I d, I32 imm) { emitrm_imm32(X64_movlmi,r,d,imm); asm_output("movl %d(%s), %d",d,RQ(r),imm); } + void Assembler::MOVSMI(R r, I d, I32 imm) { emitprm_imm16(X64_movsmi,r,d,imm); asm_output("movs %d(%s), %d",d,RQ(r),imm); } + void Assembler::MOVBMI(R r, I d, I32 imm) { emitrm_imm8(X64_movbmi,r,d,imm); asm_output("movb %d(%s), %d",d,RQ(r),imm); } + + void Assembler::MOVQSPR(I d, R r) { emit(X64_movqspr | U64(d) << 56 | U64((REGNUM(r)&7)<<3) << 40 | U64((REGNUM(r)&8)>>1) << 24); asm_output("movq %d(rsp), %s", d, RQ(r)); } // insert r into mod/rm and rex bytes + + void Assembler::XORPSA(R r, I32 i32) { emitxm_abs(X64_xorpsa, r, i32); asm_output("xorps %s, (0x%x)",RQ(r), i32); } + void Assembler::XORPSM(R r, NIns* a64) { emitxm_rel(X64_xorpsm, r, a64); asm_output("xorps %s, (%p)", RQ(r), a64); } + + void Assembler::X86_AND8R(R r) { emit(X86_and8r | U64(REGNUM(r)<<3|(REGNUM(r)|4))<<56); asm_output("andb %s, %s", RB(r), RBhi(r)); } + void Assembler::X86_SETNP(R r) { emit(X86_setnp | U64(REGNUM(r)|4)<<56); asm_output("setnp %s", RBhi(r)); } + void Assembler::X86_SETE(R r) { emit(X86_sete | U64(REGNUM(r))<<56); asm_output("sete %s", RB(r)); } + +#undef R +#undef I +#undef I32 +#undef U64 +#undef S + + void Assembler::MR(Register d, Register s) { + NanoAssert(IsGpReg(d) && IsGpReg(s)); + MOVQR(d, s); + } + + // This is needed for guards; we must be able to patch the jmp later and + // we cannot do that if an 8-bit relative jump is used, so we can't use + // JMP(). + void Assembler::JMPl(NIns* target) { + if (!target || isTargetWithinS32(target)) { + JMP32(8, target); + } else { + JMP64(16, target); + } + } + + void Assembler::JMP(NIns *target) { + if (!target || isTargetWithinS32(target)) { + if (target && isTargetWithinS8(target)) { + JMP8(8, target); + } else { + JMP32(8, target); + } + } else { + JMP64(16, target); + } + } + + void Assembler::asm_qbinop(LIns *ins) { + asm_arith(ins); + } + + void Assembler::asm_shift(LIns *ins) { + // Shift requires rcx for shift count. + LIns *a = ins->oprnd1(); + LIns *b = ins->oprnd2(); + if (b->isImmI()) { + asm_shift_imm(ins); + return; + } + + Register rr, ra; + if (a != b) { + findSpecificRegFor(b, RCX); + beginOp1Regs(ins, GpRegs & ~rmask(RCX), rr, ra); + } else { + // Nb: this is just like beginOp1Regs() except that it asserts + // that ra is in GpRegs instead of rmask(RCX)) -- this is + // necessary for the a==b case because 'a' might not be in RCX + // (which is ok, the MR(rr, ra) below will move it into RCX). + rr = prepareResultReg(ins, rmask(RCX)); + + // If 'a' isn't in a register, it can be clobbered by 'ins'. + ra = a->isInReg() ? a->getReg() : rr; + NanoAssert(rmask(ra) & GpRegs); + } + + switch (ins->opcode()) { + default: + TODO(asm_shift); + case LIR_rshuq: SHRQ(rr); break; + case LIR_rshq: SARQ(rr); break; + case LIR_lshq: SHLQ(rr); break; + case LIR_rshui: SHR( rr); break; + case LIR_rshi: SAR( rr); break; + case LIR_lshi: SHL( rr); break; + } + if (rr != ra) + MR(rr, ra); + + endOpRegs(ins, rr, ra); + } + + void Assembler::asm_shift_imm(LIns *ins) { + Register rr, ra; + beginOp1Regs(ins, GpRegs, rr, ra); + + int shift = ins->oprnd2()->immI() & 63; + switch (ins->opcode()) { + default: TODO(shiftimm); + case LIR_rshuq: SHRQI(rr, shift); break; + case LIR_rshq: SARQI(rr, shift); break; + case LIR_lshq: SHLQI(rr, shift); break; + case LIR_rshui: SHRI( rr, shift); break; + case LIR_rshi: SARI( rr, shift); break; + case LIR_lshi: SHLI( rr, shift); break; + } + if (rr != ra) + MR(rr, ra); + + endOpRegs(ins, rr, ra); + } + + static bool isImm32(LIns *ins) { + return ins->isImmI() || (ins->isImmQ() && isS32(ins->immQ())); + } + static int32_t getImm32(LIns *ins) { + return ins->isImmI() ? ins->immI() : int32_t(ins->immQ()); + } + + // Binary op, integer regs, rhs is int32 constant. + void Assembler::asm_arith_imm(LIns *ins) { + LIns *b = ins->oprnd2(); + int32_t imm = getImm32(b); + LOpcode op = ins->opcode(); + Register rr, ra; + if (op == LIR_muli || op == LIR_muljovi || op == LIR_mulxovi) { + // Special case: imul-by-imm has true 3-addr form. So we don't + // need the MR(rr, ra) after the IMULI. + beginOp1Regs(ins, GpRegs, rr, ra); + IMULI(rr, ra, imm); + endOpRegs(ins, rr, ra); + return; + } + + beginOp1Regs(ins, GpRegs, rr, ra); + if (isS8(imm)) { + switch (ins->opcode()) { + default: TODO(arith_imm8); + case LIR_addi: + case LIR_addjovi: + case LIR_addxovi: ADDLR8(rr, imm); break; // XXX: bug 547125: could use LEA for LIR_addi + case LIR_andi: ANDLR8(rr, imm); break; + case LIR_ori: ORLR8( rr, imm); break; + case LIR_subi: + case LIR_subjovi: + case LIR_subxovi: SUBLR8(rr, imm); break; + case LIR_xori: XORLR8(rr, imm); break; + case LIR_addq: + case LIR_addjovq: ADDQR8(rr, imm); break; + case LIR_subq: + case LIR_subjovq: SUBQR8(rr, imm); break; + case LIR_andq: ANDQR8(rr, imm); break; + case LIR_orq: ORQR8( rr, imm); break; + case LIR_xorq: XORQR8(rr, imm); break; + } + } else { + switch (ins->opcode()) { + default: TODO(arith_imm); + case LIR_addi: + case LIR_addjovi: + case LIR_addxovi: ADDLRI(rr, imm); break; // XXX: bug 547125: could use LEA for LIR_addi + case LIR_andi: ANDLRI(rr, imm); break; + case LIR_ori: ORLRI( rr, imm); break; + case LIR_subi: + case LIR_subjovi: + case LIR_subxovi: SUBLRI(rr, imm); break; + case LIR_xori: XORLRI(rr, imm); break; + case LIR_addq: + case LIR_addjovq: ADDQRI(rr, imm); break; + case LIR_subq: + case LIR_subjovq: SUBQRI(rr, imm); break; + case LIR_andq: ANDQRI(rr, imm); break; + case LIR_orq: ORQRI( rr, imm); break; + case LIR_xorq: XORQRI(rr, imm); break; + } + } + if (rr != ra) + MR(rr, ra); + + endOpRegs(ins, rr, ra); + } + + // Generates code for a LIR_divi that doesn't have a subsequent LIR_modi. + void Assembler::asm_div(LIns *div) { + NanoAssert(div->isop(LIR_divi)); + LIns *a = div->oprnd1(); + LIns *b = div->oprnd2(); + + evictIfActive(RDX); + prepareResultReg(div, rmask(RAX)); + + Register rb = findRegFor(b, GpRegs & ~(rmask(RAX)|rmask(RDX))); + Register ra = a->isInReg() ? a->getReg() : RAX; + + IDIV(rb); + SARI(RDX, 31); + MR(RDX, RAX); + if (RAX != ra) + MR(RAX, ra); + + freeResourcesOf(div); + if (!a->isInReg()) { + NanoAssert(ra == RAX); + findSpecificRegForUnallocated(a, RAX); + } + } + + // Generates code for a LIR_modi(LIR_divi(divL, divR)) sequence. + void Assembler::asm_div_mod(LIns *mod) { + LIns *div = mod->oprnd1(); + + NanoAssert(mod->isop(LIR_modi)); + NanoAssert(div->isop(LIR_divi)); + + LIns *divL = div->oprnd1(); + LIns *divR = div->oprnd2(); + + prepareResultReg(mod, rmask(RDX)); + prepareResultReg(div, rmask(RAX)); + + Register rDivR = findRegFor(divR, GpRegs & ~(rmask(RAX)|rmask(RDX))); + Register rDivL = divL->isInReg() ? divL->getReg() : RAX; + + IDIV(rDivR); + SARI(RDX, 31); + MR(RDX, RAX); + if (RAX != rDivL) + MR(RAX, rDivL); + + freeResourcesOf(mod); + freeResourcesOf(div); + if (!divL->isInReg()) { + NanoAssert(rDivL == RAX); + findSpecificRegForUnallocated(divL, RAX); + } + } + + // binary op with integer registers + void Assembler::asm_arith(LIns *ins) { + Register rr, ra, rb = UnspecifiedReg; // init to shut GCC up + + switch (ins->opcode()) { + case LIR_lshi: case LIR_lshq: + case LIR_rshi: case LIR_rshq: + case LIR_rshui: case LIR_rshuq: + asm_shift(ins); + return; + case LIR_modi: + asm_div_mod(ins); + return; + case LIR_divi: + // Nb: if the div feeds into a mod it will be handled by + // asm_div_mod() rather than here. + asm_div(ins); + return; + default: + break; + } + + LIns *b = ins->oprnd2(); + if (isImm32(b)) { + asm_arith_imm(ins); + return; + } + beginOp2Regs(ins, GpRegs, rr, ra, rb); + switch (ins->opcode()) { + default: TODO(asm_arith); + case LIR_ori: ORLRR(rr, rb); break; + case LIR_subi: + case LIR_subjovi: + case LIR_subxovi: SUBRR(rr, rb); break; + case LIR_addi: + case LIR_addjovi: + case LIR_addxovi: ADDRR(rr, rb); break; // XXX: bug 547125: could use LEA for LIR_addi + case LIR_andi: ANDRR(rr, rb); break; + case LIR_xori: XORRR(rr, rb); break; + case LIR_muli: + case LIR_muljovi: + case LIR_mulxovi: IMUL(rr, rb); break; + case LIR_xorq: XORQRR(rr, rb); break; + case LIR_orq: ORQRR(rr, rb); break; + case LIR_andq: ANDQRR(rr, rb); break; + case LIR_addq: + case LIR_addjovq: ADDQRR(rr, rb); break; + case LIR_subq: + case LIR_subjovq: SUBQRR(rr, rb); break; + } + if (rr != ra) + MR(rr, ra); + + endOpRegs(ins, rr, ra); + } + + // Binary op with fp registers. + void Assembler::asm_fop(LIns *ins) { + Register rr, ra, rb = UnspecifiedReg; // init to shut GCC up + beginOp2Regs(ins, FpRegs, rr, ra, rb); + switch (ins->opcode()) { + default: TODO(asm_fop); + case LIR_divd: DIVSD(rr, rb); break; + case LIR_muld: MULSD(rr, rb); break; + case LIR_addd: ADDSD(rr, rb); break; + case LIR_subd: SUBSD(rr, rb); break; + } + if (rr != ra) { + asm_nongp_copy(rr, ra); + } + + endOpRegs(ins, rr, ra); + } + + void Assembler::asm_neg_not(LIns *ins) { + Register rr, ra; + beginOp1Regs(ins, GpRegs, rr, ra); + + if (ins->isop(LIR_noti)) + NOT(rr); + else + NEG(rr); + if (rr != ra) + MR(rr, ra); + + endOpRegs(ins, rr, ra); + } + + void Assembler::asm_call(LIns *ins) { + if (!ins->isop(LIR_callv)) { + Register rr = ( ins->isop(LIR_calld) ? XMM0 : retRegs[0] ); + prepareResultReg(ins, rmask(rr)); + evictScratchRegsExcept(rmask(rr)); + } else { + evictScratchRegsExcept(0); + } + + const CallInfo *call = ins->callInfo(); + ArgType argTypes[MAXARGS]; + int argc = call->getArgTypes(argTypes); + + if (!call->isIndirect()) { + verbose_only(if (_logc->lcbits & LC_Native) + outputf(" %p:", _nIns); + ) + NIns *target = (NIns*)call->_address; + if (isTargetWithinS32(target)) { + CALL(8, target); + } else { + // can't reach target from here, load imm64 and do an indirect jump + CALLRAX(); + asm_immq(RAX, (uint64_t)target, /*canClobberCCs*/true); + } + // Call this now so that the arg setup can involve 'rr'. + freeResourcesOf(ins); + } else { + // Indirect call: we assign the address arg to RAX since it's not + // used for regular arguments, and is otherwise scratch since it's + // clobberred by the call. + CALLRAX(); + + // Call this now so that the arg setup can involve 'rr'. + freeResourcesOf(ins); + + // Assign the call address to RAX. Must happen after freeResourcesOf() + // since RAX is usually the return value and will be allocated until that point. + asm_regarg(ARGTYPE_P, ins->arg(--argc), RAX); + } + + #ifdef _WIN64 + int stk_used = 32; // always reserve 32byte shadow area + #else + int stk_used = 0; + Register fr = XMM0; + #endif + int arg_index = 0; + for (int i = 0; i < argc; i++) { + int j = argc - i - 1; + ArgType ty = argTypes[j]; + LIns* arg = ins->arg(j); + if ((ty == ARGTYPE_I || ty == ARGTYPE_UI || ty == ARGTYPE_Q) && arg_index < NumArgRegs) { + // gp arg + asm_regarg(ty, arg, argRegs[arg_index]); + arg_index++; + } + #ifdef _WIN64 + else if (ty == ARGTYPE_D && arg_index < NumArgRegs) { + // double goes in XMM reg # based on overall arg_index + Register rxi = XMM0 + arg_index; + asm_regarg(ty, arg, rxi); + arg_index++; + } + #else + else if (ty == ARGTYPE_D && fr < XMM8) { + // double goes in next available XMM register + asm_regarg(ty, arg, fr); + fr = fr + 1; + } + #endif + else { + asm_stkarg(ty, arg, stk_used); + stk_used += sizeof(void*); + } + } + + if (stk_used > max_stk_used) + max_stk_used = stk_used; + } + + void Assembler::asm_regarg(ArgType ty, LIns *p, Register r) { + if (ty == ARGTYPE_I) { + NanoAssert(p->isI()); + if (p->isImmI()) { + asm_immq(r, int64_t(p->immI()), /*canClobberCCs*/true); + return; + } + // sign extend int32 to int64 + MOVSXDR(r, r); + } else if (ty == ARGTYPE_UI) { + NanoAssert(p->isI()); + if (p->isImmI()) { + asm_immq(r, uint64_t(uint32_t(p->immI())), /*canClobberCCs*/true); + return; + } + // zero extend with 32bit mov, auto-zeros upper 32bits + MOVLR(r, r); + } else { + // Do nothing. + } + /* there is no point in folding an immediate here, because + * the argument register must be a scratch register and we're + * just before a call. Just reserving the register will cause + * the constant to be rematerialized nearby in asm_restore(), + * which is the same instruction we would otherwise emit right + * here, and moving it earlier in the stream provides more scheduling + * freedom to the cpu. */ + findSpecificRegFor(p, r); + } + + void Assembler::asm_stkarg(ArgType ty, LIns *p, int stk_off) { + NanoAssert(isS8(stk_off)); + if (ty == ARGTYPE_I || ty == ARGTYPE_UI || ty == ARGTYPE_Q) { + Register r = findRegFor(p, GpRegs); + MOVQSPR(stk_off, r); // movq [rsp+d8], r + if (ty == ARGTYPE_I) { + // sign extend int32 to int64 + NanoAssert(p->isI()); + MOVSXDR(r, r); + } else if (ty == ARGTYPE_UI) { + // zero extend uint32 to uint64 + NanoAssert(p->isI()); + MOVLR(r, r); + } else { + NanoAssert(ty == ARGTYPE_Q); + // Do nothing. + } + } else { + TODO(asm_stkarg_non_int); + } + } + + void Assembler::asm_q2i(LIns *ins) { + Register rr, ra; + beginOp1Regs(ins, GpRegs, rr, ra); + NanoAssert(IsGpReg(ra)); + // If ra==rr we do nothing. This is valid because we don't assume the + // upper 32-bits of a 64-bit GPR are zero when doing a 32-bit + // operation. More specifically, we widen 32-bit to 64-bit in three + // places, all of which explicitly sign- or zero-extend: asm_ui2uq(), + // asm_regarg() and asm_stkarg(). For the first this is required, for + // the latter two it's unclear if this is required, but it can't hurt. + if (ra != rr) + MOVLR(rr, ra); + endOpRegs(ins, rr, ra); + } + + void Assembler::asm_ui2uq(LIns *ins) { + Register rr, ra; + beginOp1Regs(ins, GpRegs, rr, ra); + NanoAssert(IsGpReg(ra)); + if (ins->isop(LIR_ui2uq)) { + MOVLR(rr, ra); // 32bit mov zeros the upper 32bits of the target + } else { + NanoAssert(ins->isop(LIR_i2q)); + MOVSXDR(rr, ra); // sign extend 32->64 + } + endOpRegs(ins, rr, ra); + } + + void Assembler::asm_dasq(LIns *ins) { + Register rr = prepareResultReg(ins, GpRegs); + Register ra = findRegFor(ins->oprnd1(), FpRegs); + asm_nongp_copy(rr, ra); + freeResourcesOf(ins); + } + + void Assembler::asm_qasd(LIns *ins) { + Register rr = prepareResultReg(ins, FpRegs); + Register ra = findRegFor(ins->oprnd1(), GpRegs); + asm_nongp_copy(rr, ra); + freeResourcesOf(ins); + } + + // The CVTSI2SD instruction only writes to the low 64bits of the target + // XMM register, which hinders register renaming and makes dependence + // chains longer. So we precede with XORPS to clear the target register. + + void Assembler::asm_i2d(LIns *ins) { + LIns *a = ins->oprnd1(); + NanoAssert(ins->isD() && a->isI()); + + Register rr = prepareResultReg(ins, FpRegs); + Register ra = findRegFor(a, GpRegs); + CVTSI2SD(rr, ra); // cvtsi2sd xmmr, b only writes xmm:0:64 + XORPS(rr); // xorps xmmr,xmmr to break dependency chains + freeResourcesOf(ins); + } + + void Assembler::asm_ui2d(LIns *ins) { + LIns *a = ins->oprnd1(); + NanoAssert(ins->isD() && a->isI()); + + Register rr = prepareResultReg(ins, FpRegs); + Register ra = findRegFor(a, GpRegs); + // Because oprnd1 is 32bit, it's ok to zero-extend it without worrying about clobbering. + CVTSQ2SD(rr, ra); // convert int64 to double + XORPS(rr); // xorps xmmr,xmmr to break dependency chains + MOVLR(ra, ra); // zero extend u32 to int64 + freeResourcesOf(ins); + } + + void Assembler::asm_d2i(LIns *ins) { + LIns *a = ins->oprnd1(); + NanoAssert(ins->isI() && a->isD()); + + Register rr = prepareResultReg(ins, GpRegs); + Register rb = findRegFor(a, FpRegs); + CVTTSD2SI(rr, rb); + freeResourcesOf(ins); + } + + void Assembler::asm_cmov(LIns *ins) { + LIns* cond = ins->oprnd1(); + LIns* iftrue = ins->oprnd2(); + LIns* iffalse = ins->oprnd3(); + NanoAssert(cond->isCmp()); + NanoAssert((ins->isop(LIR_cmovi) && iftrue->isI() && iffalse->isI()) || + (ins->isop(LIR_cmovq) && iftrue->isQ() && iffalse->isQ()) || + (ins->isop(LIR_cmovd) && iftrue->isD() && iffalse->isD())); + + RegisterMask allow = ins->isD() ? FpRegs : GpRegs; + + Register rr = prepareResultReg(ins, allow); + + Register rf = findRegFor(iffalse, allow & ~rmask(rr)); + + if (ins->isop(LIR_cmovd)) { + // See Nativei386.cpp:asm_cmov() for an explanation of the subtleties here. + NIns* target = _nIns; + asm_nongp_copy(rr, rf); + asm_branch_helper(false, cond, target); + + // If 'iftrue' isn't in a register, it can be clobbered by 'ins'. + Register rt = iftrue->isInReg() ? iftrue->getReg() : rr; + + if (rr != rt) + asm_nongp_copy(rr, rt); + + freeResourcesOf(ins); + if (!iftrue->isInReg()) { + NanoAssert(rt == rr); + findSpecificRegForUnallocated(iftrue, rr); + } + + asm_cmp(cond); + return; + } + + // If 'iftrue' isn't in a register, it can be clobbered by 'ins'. + Register rt = iftrue->isInReg() ? iftrue->getReg() : rr; + + // WARNING: We cannot generate any code that affects the condition + // codes between the MRcc generation here and the asm_cmpi() call + // below. See asm_cmpi() for more details. + LOpcode condop = cond->opcode(); + if (ins->isop(LIR_cmovi)) { + switch (condop) { + case LIR_eqi: case LIR_eqq: CMOVNE( rr, rf); break; + case LIR_lti: case LIR_ltq: CMOVNL( rr, rf); break; + case LIR_gti: case LIR_gtq: CMOVNG( rr, rf); break; + case LIR_lei: case LIR_leq: CMOVNLE(rr, rf); break; + case LIR_gei: case LIR_geq: CMOVNGE(rr, rf); break; + case LIR_ltui: case LIR_ltuq: CMOVNB( rr, rf); break; + case LIR_gtui: case LIR_gtuq: CMOVNA( rr, rf); break; + case LIR_leui: case LIR_leuq: CMOVNBE(rr, rf); break; + case LIR_geui: case LIR_geuq: CMOVNAE(rr, rf); break; + default: NanoAssert(0); break; + } + } else { + NanoAssert(ins->isop(LIR_cmovq)); + switch (condop) { + case LIR_eqi: case LIR_eqq: CMOVQNE( rr, rf); break; + case LIR_lti: case LIR_ltq: CMOVQNL( rr, rf); break; + case LIR_gti: case LIR_gtq: CMOVQNG( rr, rf); break; + case LIR_lei: case LIR_leq: CMOVQNLE(rr, rf); break; + case LIR_gei: case LIR_geq: CMOVQNGE(rr, rf); break; + case LIR_ltui: case LIR_ltuq: CMOVQNB( rr, rf); break; + case LIR_gtui: case LIR_gtuq: CMOVQNA( rr, rf); break; + case LIR_leui: case LIR_leuq: CMOVQNBE(rr, rf); break; + case LIR_geui: case LIR_geuq: CMOVQNAE(rr, rf); break; + default: NanoAssert(0); break; + } + } + if (rr != rt) + MR(rr, rt); + + freeResourcesOf(ins); + if (!iftrue->isInReg()) { + NanoAssert(rt == rr); + findSpecificRegForUnallocated(iftrue, rr); + } + + asm_cmpi(cond); + } + + NIns* Assembler::asm_branch(bool onFalse, LIns* cond, NIns* target) { + NIns* patch = asm_branch_helper(onFalse, cond, target); + asm_cmp(cond); + return patch; + } + + NIns* Assembler::asm_branch_helper(bool onFalse, LIns *cond, NIns *target) { + if (target && !isTargetWithinS32(target)) { + // A conditional jump beyond 32-bit range, so invert the + // branch/compare and emit an unconditional jump to the target: + // j(inverted) B1 + // jmp target + // B1: + NIns* shortTarget = _nIns; + JMP(target); + target = shortTarget; + onFalse = !onFalse; + } + return isCmpDOpcode(cond->opcode()) + ? asm_branchd_helper(onFalse, cond, target) + : asm_branchi_helper(onFalse, cond, target); + } + + NIns* Assembler::asm_branchi_helper(bool onFalse, LIns *cond, NIns *target) { + // We must ensure there's room for the instruction before calculating + // the offset. And the offset determines the opcode (8bit or 32bit). + LOpcode condop = cond->opcode(); + if (target && isTargetWithinS8(target)) { + if (onFalse) { + switch (condop) { + case LIR_eqi: case LIR_eqq: JNE8( 8, target); break; + case LIR_lti: case LIR_ltq: JNL8( 8, target); break; + case LIR_gti: case LIR_gtq: JNG8( 8, target); break; + case LIR_lei: case LIR_leq: JNLE8(8, target); break; + case LIR_gei: case LIR_geq: JNGE8(8, target); break; + case LIR_ltui: case LIR_ltuq: JNB8( 8, target); break; + case LIR_gtui: case LIR_gtuq: JNA8( 8, target); break; + case LIR_leui: case LIR_leuq: JNBE8(8, target); break; + case LIR_geui: case LIR_geuq: JNAE8(8, target); break; + default: NanoAssert(0); break; + } + } else { + switch (condop) { + case LIR_eqi: case LIR_eqq: JE8( 8, target); break; + case LIR_lti: case LIR_ltq: JL8( 8, target); break; + case LIR_gti: case LIR_gtq: JG8( 8, target); break; + case LIR_lei: case LIR_leq: JLE8(8, target); break; + case LIR_gei: case LIR_geq: JGE8(8, target); break; + case LIR_ltui: case LIR_ltuq: JB8( 8, target); break; + case LIR_gtui: case LIR_gtuq: JA8( 8, target); break; + case LIR_leui: case LIR_leuq: JBE8(8, target); break; + case LIR_geui: case LIR_geuq: JAE8(8, target); break; + default: NanoAssert(0); break; + } + } + } else { + if (onFalse) { + switch (condop) { + case LIR_eqi: case LIR_eqq: JNE( 8, target); break; + case LIR_lti: case LIR_ltq: JNL( 8, target); break; + case LIR_gti: case LIR_gtq: JNG( 8, target); break; + case LIR_lei: case LIR_leq: JNLE(8, target); break; + case LIR_gei: case LIR_geq: JNGE(8, target); break; + case LIR_ltui: case LIR_ltuq: JNB( 8, target); break; + case LIR_gtui: case LIR_gtuq: JNA( 8, target); break; + case LIR_leui: case LIR_leuq: JNBE(8, target); break; + case LIR_geui: case LIR_geuq: JNAE(8, target); break; + default: NanoAssert(0); break; + } + } else { + switch (condop) { + case LIR_eqi: case LIR_eqq: JE( 8, target); break; + case LIR_lti: case LIR_ltq: JL( 8, target); break; + case LIR_gti: case LIR_gtq: JG( 8, target); break; + case LIR_lei: case LIR_leq: JLE(8, target); break; + case LIR_gei: case LIR_geq: JGE(8, target); break; + case LIR_ltui: case LIR_ltuq: JB( 8, target); break; + case LIR_gtui: case LIR_gtuq: JA( 8, target); break; + case LIR_leui: case LIR_leuq: JBE(8, target); break; + case LIR_geui: case LIR_geuq: JAE(8, target); break; + default: NanoAssert(0); break; + } + } + } + return _nIns; // address of instruction to patch + } + + NIns* Assembler::asm_branch_ov(LOpcode, NIns* target) { + // We must ensure there's room for the instr before calculating + // the offset. And the offset determines the opcode (8bit or 32bit). + if (target && isTargetWithinS8(target)) + JO8(8, target); + else + JO( 8, target); + return _nIns; + } + + void Assembler::asm_cmp(LIns *cond) { + isCmpDOpcode(cond->opcode()) ? asm_cmpd(cond) : asm_cmpi(cond); + } + + // WARNING: this function cannot generate code that will affect the + // condition codes prior to the generation of the test/cmp. See + // Nativei386.cpp:asm_cmpi() for details. + void Assembler::asm_cmpi(LIns *cond) { + LIns *b = cond->oprnd2(); + if (isImm32(b)) { + asm_cmpi_imm(cond); + return; + } + LIns *a = cond->oprnd1(); + Register ra, rb; + if (a != b) { + findRegFor2(GpRegs, a, ra, GpRegs, b, rb); + } else { + // optimize-me: this will produce a const result! + ra = rb = findRegFor(a, GpRegs); + } + + LOpcode condop = cond->opcode(); + if (isCmpQOpcode(condop)) { + CMPQR(ra, rb); + } else { + NanoAssert(isCmpIOpcode(condop)); + CMPLR(ra, rb); + } + } + + void Assembler::asm_cmpi_imm(LIns *cond) { + LOpcode condop = cond->opcode(); + LIns *a = cond->oprnd1(); + LIns *b = cond->oprnd2(); + Register ra = findRegFor(a, GpRegs); + int32_t imm = getImm32(b); + if (isCmpQOpcode(condop)) { + if (isS8(imm)) + CMPQR8(ra, imm); + else + CMPQRI(ra, imm); + } else { + NanoAssert(isCmpIOpcode(condop)); + if (isS8(imm)) + CMPLR8(ra, imm); + else + CMPLRI(ra, imm); + } + } + + // Compiling floating point branches. + // Discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=443886. + // + // fucom/p/pp: c3 c2 c0 jae ja jbe jb je jne + // ucomisd: Z P C !C !C&!Z C|Z C Z !Z + // -- -- -- -- ----- --- -- -- -- + // unordered 1 1 1 T T T + // greater > 0 0 0 T T T + // less < 0 0 1 T T T + // equal = 1 0 0 T T T + // + // Here are the cases, using conditionals: + // + // branch >= > <= < = + // ------ --- --- --- --- --- + // LIR_jt jae ja swap+jae swap+ja jp over je + // LIR_jf jb jbe swap+jb swap+jbe jne+jp + + NIns* Assembler::asm_branchd_helper(bool onFalse, LIns *cond, NIns *target) { + LOpcode condop = cond->opcode(); + NIns *patch; + if (condop == LIR_eqd) { + if (onFalse) { + // branch if unordered or != + JP(16, target); // underrun of 12 needed, round up for overhang --> 16 + JNE(0, target); // no underrun needed, previous was enough + patch = _nIns; + } else { + // jp skip (2byte) + // jeq target + // skip: ... + underrunProtect(16); // underrun of 7 needed but we write 2 instr --> 16 + NIns *skip = _nIns; + JE(0, target); // no underrun needed, previous was enough + patch = _nIns; + JP8(0, skip); // ditto + } + } + else { + // LIR_ltd and LIR_gtd are handled by the same case because + // asm_cmpd() converts LIR_ltd(a,b) to LIR_gtd(b,a). Likewise for + // LIR_led/LIR_ged. + switch (condop) { + case LIR_ltd: + case LIR_gtd: if (onFalse) JBE(8, target); else JA(8, target); break; + case LIR_led: + case LIR_ged: if (onFalse) JB(8, target); else JAE(8, target); break; + default: NanoAssert(0); break; + } + patch = _nIns; + } + return patch; + } + + void Assembler::asm_condd(LIns *ins) { + LOpcode op = ins->opcode(); + if (op == LIR_eqd) { + // result = ZF & !PF, must do logic on flags + // r = al|bl|cl|dl, can only use rh without rex prefix + Register r = prepareResultReg(ins, 1<opcode(); + LIns* a = cond->oprnd1(); + LIns* b = cond->oprnd2(); + // First, we convert (a < b) into (b > a), and (a <= b) into (b >= a). + if (opcode == LIR_ltd) { + opcode = LIR_gtd; + LIns* t = a; a = b; b = t; + } else if (opcode == LIR_led) { + opcode = LIR_ged; + LIns* t = a; a = b; b = t; + } + Register ra, rb; + findRegFor2(FpRegs, a, ra, FpRegs, b, rb); + UCOMISD(ra, rb); + } + + // Return true if we can generate code for this instruction that neither + // sets CCs nor clobbers any input register. + // LEA is the only native instruction that fits those requirements. + bool canRematLEA(LIns* ins) + { + switch (ins->opcode()) { + case LIR_addi: + return ins->oprnd1()->isInRegMask(BaseRegs) && ins->oprnd2()->isImmI(); + case LIR_addq: { + LIns* rhs; + return ins->oprnd1()->isInRegMask(BaseRegs) && + (rhs = ins->oprnd2())->isImmQ() && + isS32(rhs->immQ()); + } + // Subtract and some left-shifts could be rematerialized using LEA, + // but it hasn't shown to help in real code yet. Noting them anyway: + // maybe sub? R = subl/q rL, const => leal/q R, [rL + -const] + // maybe lsh? R = lshl/q rL, 1/2/3 => leal/q R, [rL * 2/4/8] + default: + ; + } + return false; + } + + bool Assembler::canRemat(LIns* ins) { + return ins->isImmAny() || ins->isop(LIR_allocp) || canRematLEA(ins); + } + + // WARNING: the code generated by this function must not affect the + // condition codes. See asm_cmpi() for details. + void Assembler::asm_restore(LIns *ins, Register r) { + if (ins->isop(LIR_allocp)) { + int d = arDisp(ins); + LEAQRM(r, d, FP); + } + else if (ins->isImmI()) { + asm_immi(r, ins->immI(), /*canClobberCCs*/false); + } + else if (ins->isImmQ()) { + asm_immq(r, ins->immQ(), /*canClobberCCs*/false); + } + else if (ins->isImmD()) { + asm_immd(r, ins->immDasQ(), /*canClobberCCs*/false); + } + else if (canRematLEA(ins)) { + Register lhsReg = ins->oprnd1()->getReg(); + if (ins->isop(LIR_addq)) + LEAQRM(r, (int32_t)ins->oprnd2()->immQ(), lhsReg); + else // LIR_addi + LEALRM(r, ins->oprnd2()->immI(), lhsReg); + } + else { + int d = findMemFor(ins); + if (ins->isD()) { + NanoAssert(IsFpReg(r)); + MOVSDRM(r, d, FP); + } else if (ins->isQ()) { + NanoAssert(IsGpReg(r)); + MOVQRM(r, d, FP); + } else { + NanoAssert(ins->isI()); + MOVLRM(r, d, FP); + } + } + } + + void Assembler::asm_cond(LIns *ins) { + LOpcode op = ins->opcode(); + + // unlike x86-32, with a rex prefix we can use any GP register as an 8bit target + Register r = prepareResultReg(ins, GpRegs); + + // SETcc only sets low 8 bits, so extend + MOVZX8(r, r); + switch (op) { + default: + TODO(cond); + case LIR_eqq: + case LIR_eqi: SETE(r); break; + case LIR_ltq: + case LIR_lti: SETL(r); break; + case LIR_leq: + case LIR_lei: SETLE(r); break; + case LIR_gtq: + case LIR_gti: SETG(r); break; + case LIR_geq: + case LIR_gei: SETGE(r); break; + case LIR_ltuq: + case LIR_ltui: SETB(r); break; + case LIR_leuq: + case LIR_leui: SETBE(r); break; + case LIR_gtuq: + case LIR_gtui: SETA(r); break; + case LIR_geuq: + case LIR_geui: SETAE(r); break; + } + freeResourcesOf(ins); + + asm_cmpi(ins); + } + + void Assembler::asm_ret(LIns *ins) { + genEpilogue(); + + // Restore RSP from RBP, undoing SUB(RSP,amt) in the prologue + MR(RSP,FP); + + releaseRegisters(); + assignSavedRegs(); + LIns *value = ins->oprnd1(); + Register r = ins->isop(LIR_retd) ? XMM0 : RAX; + findSpecificRegFor(value, r); + } + + void Assembler::asm_nongp_copy(Register d, Register s) { + if (!IsFpReg(d) && IsFpReg(s)) { + // gpr <- xmm: use movq r/m64, xmm (66 REX.W 0F 7E /r) + MOVQRX(d, s); + } else if (IsFpReg(d) && IsFpReg(s)) { + // xmm <- xmm: use movaps. movsd r,r causes partial register stall + MOVAPSR(d, s); + } else { + NanoAssert(IsFpReg(d) && !IsFpReg(s)); + // xmm <- gpr: use movq xmm, r/m64 (66 REX.W 0F 6E /r) + MOVQXR(d, s); + } + } + + // Register setup for load ops. Pairs with endLoadRegs(). + void Assembler::beginLoadRegs(LIns *ins, RegisterMask allow, Register &rr, int32_t &dr, Register &rb) { + dr = ins->disp(); + LIns *base = ins->oprnd1(); + rb = getBaseReg(base, dr, BaseRegs); + rr = prepareResultReg(ins, allow & ~rmask(rb)); + } + + // Register clean-up for load ops. Pairs with beginLoadRegs(). + void Assembler::endLoadRegs(LIns* ins) { + freeResourcesOf(ins); + } + + void Assembler::asm_load64(LIns *ins) { + Register rr, rb; + int32_t dr; + switch (ins->opcode()) { + case LIR_ldq: + beginLoadRegs(ins, GpRegs, rr, dr, rb); + NanoAssert(IsGpReg(rr)); + MOVQRM(rr, dr, rb); // general 64bit load, 32bit const displacement + break; + case LIR_ldd: + beginLoadRegs(ins, FpRegs, rr, dr, rb); + NanoAssert(IsFpReg(rr)); + MOVSDRM(rr, dr, rb); // load 64bits into XMM + break; + case LIR_ldf2d: + beginLoadRegs(ins, FpRegs, rr, dr, rb); + NanoAssert(IsFpReg(rr)); + CVTSS2SD(rr, rr); + MOVSSRM(rr, dr, rb); + break; + default: + NanoAssertMsg(0, "asm_load64 should never receive this LIR opcode"); + break; + } + endLoadRegs(ins); + } + + void Assembler::asm_load32(LIns *ins) { + NanoAssert(ins->isI()); + Register r, b; + int32_t d; + beginLoadRegs(ins, GpRegs, r, d, b); + LOpcode op = ins->opcode(); + switch (op) { + case LIR_lduc2ui: + MOVZX8M( r, d, b); + break; + case LIR_ldus2ui: + MOVZX16M(r, d, b); + break; + case LIR_ldi: + MOVLRM( r, d, b); + break; + case LIR_ldc2i: + MOVSX8M( r, d, b); + break; + case LIR_lds2i: + MOVSX16M( r, d, b); + break; + default: + NanoAssertMsg(0, "asm_load32 should never receive this LIR opcode"); + break; + } + endLoadRegs(ins); + } + + void Assembler::asm_store64(LOpcode op, LIns *value, int d, LIns *base) { + NanoAssert(value->isQorD()); + + switch (op) { + case LIR_stq: { + uint64_t c; + if (value->isImmQ() && (c = value->immQ(), isS32(c))) { + uint64_t c = value->immQ(); + Register rb = getBaseReg(base, d, BaseRegs); + // MOVQMI takes a 32-bit integer that gets signed extended to a 64-bit value. + MOVQMI(rb, d, int32_t(c)); + } else { + Register rr, rb; + getBaseReg2(GpRegs, value, rr, BaseRegs, base, rb, d); + MOVQMR(rr, d, rb); // gpr store + } + break; + } + case LIR_std: { + Register b = getBaseReg(base, d, BaseRegs); + Register r = findRegFor(value, FpRegs); + MOVSDMR(r, d, b); // xmm store + break; + } + case LIR_std2f: { + Register b = getBaseReg(base, d, BaseRegs); + Register r = findRegFor(value, FpRegs); + Register t = registerAllocTmp(FpRegs & ~rmask(r)); + + MOVSSMR(t, d, b); // store + CVTSD2SS(t, r); // cvt to single-precision + XORPS(t); // break dependency chains + break; + } + default: + NanoAssertMsg(0, "asm_store64 should never receive this LIR opcode"); + break; + } + } + + void Assembler::asm_store32(LOpcode op, LIns *value, int d, LIns *base) { + if (value->isImmI()) { + Register rb = getBaseReg(base, d, BaseRegs); + int c = value->immI(); + switch (op) { + case LIR_sti2c: MOVBMI(rb, d, c); break; + case LIR_sti2s: MOVSMI(rb, d, c); break; + case LIR_sti: MOVLMI(rb, d, c); break; + default: NanoAssert(0); break; + } + + } else { + // Quirk of x86-64: reg cannot appear to be ah/bh/ch/dh for + // single-byte stores with REX prefix. + const RegisterMask SrcRegs = (op == LIR_sti2c) ? SingleByteStoreRegs : GpRegs; + + NanoAssert(value->isI()); + Register b = getBaseReg(base, d, BaseRegs); + Register r = findRegFor(value, SrcRegs & ~rmask(b)); + + switch (op) { + case LIR_sti2c: MOVBMR(r, d, b); break; + case LIR_sti2s: MOVSMR(r, d, b); break; + case LIR_sti: MOVLMR(r, d, b); break; + default: NanoAssert(0); break; + } + } + } + + void Assembler::asm_immi(LIns *ins) { + Register rr = prepareResultReg(ins, GpRegs); + asm_immi(rr, ins->immI(), /*canClobberCCs*/true); + freeResourcesOf(ins); + } + + void Assembler::asm_immq(LIns *ins) { + Register rr = prepareResultReg(ins, GpRegs); + asm_immq(rr, ins->immQ(), /*canClobberCCs*/true); + freeResourcesOf(ins); + } + + void Assembler::asm_immd(LIns *ins) { + Register r = prepareResultReg(ins, FpRegs); + asm_immd(r, ins->immDasQ(), /*canClobberCCs*/true); + freeResourcesOf(ins); + } + + void Assembler::asm_immi(Register r, int32_t v, bool canClobberCCs) { + NanoAssert(IsGpReg(r)); + if (v == 0 && canClobberCCs) { + XORRR(r, r); + } else { + MOVI(r, v); + } + } + + void Assembler::asm_immq(Register r, uint64_t v, bool canClobberCCs) { + NanoAssert(IsGpReg(r)); + if (isU32(v)) { + asm_immi(r, int32_t(v), canClobberCCs); + } else if (isS32(v)) { + // safe for sign-extension 32->64 + MOVQI32(r, int32_t(v)); + } else if (isTargetWithinS32((NIns*)v)) { + // value is with +/- 2GB from RIP, can use LEA with RIP-relative disp32 + int32_t d = int32_t(int64_t(v)-int64_t(_nIns)); + LEARIP(r, d); + } else { + MOVQI(r, v); + } + } + + void Assembler::asm_immd(Register r, uint64_t v, bool canClobberCCs) { + NanoAssert(IsFpReg(r)); + if (v == 0 && canClobberCCs) { + XORPS(r); + } else { + // There's no general way to load an immediate into an XMM reg. + // For non-zero floats the best thing is to put the equivalent + // 64-bit integer into a scratch GpReg and then move it into the + // appropriate FpReg. + Register rt = registerAllocTmp(GpRegs); + MOVQXR(r, rt); + asm_immq(rt, v, canClobberCCs); + } + } + + void Assembler::asm_param(LIns *ins) { + uint32_t a = ins->paramArg(); + uint32_t kind = ins->paramKind(); + if (kind == 0) { + // Ordinary param. First four or six args always in registers for x86_64 ABI. + if (a < (uint32_t)NumArgRegs) { + // incoming arg in register + prepareResultReg(ins, rmask(argRegs[a])); + // No code to generate. + } else { + // todo: support stack based args, arg 0 is at [FP+off] where off + // is the # of regs to be pushed in genProlog() + TODO(asm_param_stk); + } + } + else { + // Saved param. + prepareResultReg(ins, rmask(savedRegs[a])); + // No code to generate. + } + freeResourcesOf(ins); + } + + // Register setup for 2-address style unary ops of the form R = (op) R. + // Pairs with endOpRegs(). + void Assembler::beginOp1Regs(LIns* ins, RegisterMask allow, Register &rr, Register &ra) { + LIns* a = ins->oprnd1(); + + rr = prepareResultReg(ins, allow); + + // If 'a' isn't in a register, it can be clobbered by 'ins'. + ra = a->isInReg() ? a->getReg() : rr; + NanoAssert(rmask(ra) & allow); + } + + // Register setup for 2-address style binary ops of the form R = R (op) B. + // Pairs with endOpRegs(). + void Assembler::beginOp2Regs(LIns *ins, RegisterMask allow, Register &rr, Register &ra, + Register &rb) { + LIns *a = ins->oprnd1(); + LIns *b = ins->oprnd2(); + if (a != b) { + rb = findRegFor(b, allow); + allow &= ~rmask(rb); + } + rr = prepareResultReg(ins, allow); + + // If 'a' isn't in a register, it can be clobbered by 'ins'. + ra = a->isInReg() ? a->getReg() : rr; + NanoAssert(rmask(ra) & allow); + + if (a == b) { + rb = ra; + } + } + + // Register clean-up for 2-address style unary ops of the form R = (op) R. + // Pairs with beginOp1Regs() and beginOp2Regs(). + void Assembler::endOpRegs(LIns* ins, Register rr, Register ra) { + (void) rr; // quell warnings when NanoAssert is compiled out. + + LIns* a = ins->oprnd1(); + + // We're finished with 'ins'. + NanoAssert(ins->getReg() == rr); + freeResourcesOf(ins); + + // If 'a' isn't in a register yet, that means it's clobbered by 'ins'. + if (!a->isInReg()) { + NanoAssert(ra == rr); + findSpecificRegForUnallocated(a, ra); + } + } + + static const AVMPLUS_ALIGN16(int64_t) negateMask[] = {0x8000000000000000LL,0}; + + void Assembler::asm_fneg(LIns *ins) { + Register rr, ra; + beginOp1Regs(ins, FpRegs, rr, ra); + if (isS32((uintptr_t)negateMask)) { + // builtin code is in bottom or top 2GB addr space, use absolute addressing + XORPSA(rr, (int32_t)(uintptr_t)negateMask); + } else if (isTargetWithinS32((NIns*)negateMask)) { + // jit code is within +/-2GB of builtin code, use rip-relative + XORPSM(rr, (NIns*)negateMask); + } else { + // This is just hideous - can't use RIP-relative load, can't use + // absolute-address load, and cant move imm64 const to XMM. + // Solution: move negateMask into a temp GP register, then copy to + // a temp XMM register. + // Nb: we don't want any F64 values to end up in a GpReg, nor any + // I64 values to end up in an FpReg. + // + // # 'gt' and 'ga' are temporary GpRegs. + // # ins->oprnd1() is in 'rr' (FpRegs) + // mov gt, 0x8000000000000000 + // mov rt, gt + // xorps rr, rt + Register rt = registerAllocTmp(FpRegs & ~(rmask(ra)|rmask(rr))); + Register gt = registerAllocTmp(GpRegs); + XORPS(rr, rt); + MOVQXR(rt, gt); + asm_immq(gt, negateMask[0], /*canClobberCCs*/true); + } + if (ra != rr) + asm_nongp_copy(rr,ra); + endOpRegs(ins, rr, ra); + } + + void Assembler::asm_spill(Register rr, int d, bool quad) { + NanoAssert(d); + if (!IsFpReg(rr)) { + if (quad) + MOVQMR(rr, d, FP); + else + MOVLMR(rr, d, FP); + } else { + // store 64bits from XMM to memory + NanoAssert(quad); + MOVSDMR(rr, d, FP); + } + } + + NIns* Assembler::genPrologue() { + // activation frame is 4 bytes per entry even on 64bit machines + uint32_t stackNeeded = max_stk_used + _activation.stackSlotsNeeded() * 4; + + uint32_t stackPushed = + sizeof(void*) + // returnaddr + sizeof(void*); // ebp + uint32_t aligned = alignUp(stackNeeded + stackPushed, NJ_ALIGN_STACK); + uint32_t amt = aligned - stackPushed; + + // Reserve stackNeeded bytes, padded + // to preserve NJ_ALIGN_STACK-byte alignment. + if (amt) { + if (isS8(amt)) + SUBQR8(RSP, amt); + else + SUBQRI(RSP, amt); + } + + verbose_only( asm_output("[patch entry]"); ) + NIns *patchEntry = _nIns; + MR(FP, RSP); // Establish our own FP. + PUSHR(FP); // Save caller's FP. + + return patchEntry; + } + + NIns* Assembler::genEpilogue() { + // pop rbp + // ret + RET(); + POPR(RBP); + return _nIns; + } + + void Assembler::nRegisterResetAll(RegAlloc &a) { + // add scratch registers to our free list for the allocator + a.clear(); +#ifdef _WIN64 + a.free = 0x001fffcf; // rax-rbx, rsi, rdi, r8-r15, xmm0-xmm5 +#else + a.free = 0xffffffff & ~(1<,jp, for LIR_jf(feq) + // we just patched the jne, now patch the jp. + next += 6; + NanoAssert(((int32_t*)next)[-1] == 0); + NanoAssert(isS32(target - next)); + ((int32_t*)next)[-1] = int32_t(target - next); + } + } + + Register Assembler::nRegisterAllocFromSet(RegisterMask set) { + #if defined _MSC_VER + DWORD tr; + _BitScanForward(&tr, set); + Register r = { tr }; + _allocator.free &= ~rmask(r); + return r; + #else + // gcc asm syntax + uint32_t regnum; + asm("bsf %1, %%eax\n\t" + "btr %%eax, %2\n\t" + "movl %%eax, %0\n\t" + : "=m"(regnum) : "m"(set), "m"(_allocator.free) : "%eax", "memory"); + (void)set; + Register r = { regnum }; + return r; + #endif + } + + void Assembler::nFragExit(LIns *guard) { + SideExit *exit = guard->record()->exit; + Fragment *frag = exit->target; + GuardRecord *lr = 0; + bool destKnown = (frag && frag->fragEntry); + // Generate jump to epilog and initialize lr. + // If the guard is LIR_xtbl, use a jump table with epilog in every entry + if (guard->isop(LIR_xtbl)) { + NanoAssert(!guard->isop(LIR_xtbl)); + } else { + // If the guard already exists, use a simple jump. + if (destKnown) { + JMP(frag->fragEntry); + lr = 0; + } else { // target doesn't exist. Use 0 jump offset and patch later + if (!_epilogue) + _epilogue = genEpilogue(); + lr = guard->record(); + JMPl(_epilogue); + lr->jmp = _nIns; + } + } + + // profiling for the exit + verbose_only( + if (_logc->lcbits & LC_FragProfile) { + asm_inc_m32( &guard->record()->profCount ); + } + ) + + MR(RSP, RBP); + + // return value is GuardRecord* + asm_immq(RAX, uintptr_t(lr), /*canClobberCCs*/true); + } + + void Assembler::nInit(AvmCore*) { + nHints[LIR_calli] = rmask(retRegs[0]); + nHints[LIR_calld] = rmask(XMM0); + nHints[LIR_paramp] = PREFER_SPECIAL; + } + + void Assembler::nBeginAssembly() { + max_stk_used = 0; + } + + // This should only be called from within emit() et al. + void Assembler::underrunProtect(ptrdiff_t bytes) { + NanoAssertMsg(bytes<=LARGEST_UNDERRUN_PROT, "constant LARGEST_UNDERRUN_PROT is too small"); + NIns *pc = _nIns; + NIns *top = codeStart; // this may be in a normal code chunk or an exit code chunk + + #if PEDANTIC + // pedanticTop is based on the last call to underrunProtect; any time we call + // underrunProtect and would use more than what's already protected, then insert + // a page break jump. Sometimes, this will be to a new page, usually it's just + // the next instruction + + NanoAssert(pedanticTop >= top); + if (pc - bytes < pedanticTop) { + // no page break required, but insert a far branch anyway just to be difficult + const int br_size = 8; // opcode + 32bit addr + if (pc - bytes - br_size < top) { + // really do need a page break + verbose_only(if (_logc->lcbits & LC_Native) outputf("newpage %p:", pc);) + // This may be in a normal code chunk or an exit code chunk. + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes)); + } + // now emit the jump, but make sure we won't need another page break. + // we're pedantic, but not *that* pedantic. + pedanticTop = _nIns - br_size; + JMP(pc); + pedanticTop = _nIns - bytes; + } + #else + if (pc - bytes < top) { + verbose_only(if (_logc->lcbits & LC_Native) outputf("newpage %p:", pc);) + // This may be in a normal code chunk or an exit code chunk. + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes)); + // This jump will call underrunProtect again, but since we're on a new + // page, nothing will happen. + JMP(pc); + } + #endif + } + + RegisterMask Assembler::nHint(LIns* ins) + { + NanoAssert(ins->isop(LIR_paramp)); + RegisterMask prefer = 0; + uint8_t arg = ins->paramArg(); + if (ins->paramKind() == 0) { + if (arg < maxArgRegs) + prefer = rmask(argRegs[arg]); + } else { + if (arg < NumSavedRegs) + prefer = rmask(savedRegs[arg]); + } + return prefer; + } + + void Assembler::nativePageSetup() { + NanoAssert(!_inExit); + if (!_nIns) { + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes)); + IF_PEDANTIC( pedanticTop = _nIns; ) + } + } + + void Assembler::nativePageReset() + {} + + // Increment the 32-bit profiling counter at pCtr, without + // changing any registers. + verbose_only( + void Assembler::asm_inc_m32(uint32_t* pCtr) + { + // Not as simple as on x86. We need to temporarily free up a + // register into which to generate the address, so just push + // it on the stack. This assumes that the scratch area at + // -8(%rsp) .. -1(%esp) isn't being used for anything else + // at this point. + emitr(X64_popr, RAX); // popq %rax + emit(X64_inclmRAX); // incl (%rax) + asm_immq(RAX, (uint64_t)pCtr, /*canClobberCCs*/true); // movabsq $pCtr, %rax + emitr(X64_pushr, RAX); // pushq %rax + } + ) + + void Assembler::asm_jtbl(LIns* ins, NIns** table) + { + // exclude R12 because ESP and R12 cannot be used as an index + // (index=100 in SIB means "none") + Register indexreg = findRegFor(ins->oprnd1(), GpRegs & ~rmask(R12)); + if (isS32((intptr_t)table)) { + // table is in low 2GB or high 2GB, can use absolute addressing + // jmpq [indexreg*8 + table] + JMPX(indexreg, table); + } else { + // don't use R13 for base because we want to use mod=00, i.e. [index*8+base + 0] + Register tablereg = registerAllocTmp(GpRegs & ~(rmask(indexreg)|rmask(R13))); + // jmp [indexreg*8 + tablereg] + JMPXB(indexreg, tablereg); + // tablereg <- #table + asm_immq(tablereg, (uint64_t)table, /*canClobberCCs*/true); + } + } + + void Assembler::swapCodeChunks() { + if (!_nExitIns) { + codeAlloc(exitStart, exitEnd, _nExitIns verbose_only(, exitBytes)); + } + SWAP(NIns*, _nIns, _nExitIns); + SWAP(NIns*, codeStart, exitStart); + SWAP(NIns*, codeEnd, exitEnd); + verbose_only( SWAP(size_t, codeBytes, exitBytes); ) + } + + void Assembler::asm_insert_random_nop() { + NanoAssert(0); // not supported + } + +} // namespace nanojit + +#endif // FEATURE_NANOJIT && NANOJIT_X64 diff --git a/js/src/nanojit/NativeX64.h b/js/src/nanojit/NativeX64.h new file mode 100644 index 0000000..872b5f2 --- /dev/null +++ b/js/src/nanojit/NativeX64.h @@ -0,0 +1,630 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __nanojit_NativeX64__ +#define __nanojit_NativeX64__ + +#include "NativeCommon.h" + +#ifndef NANOJIT_64BIT +#error "NANOJIT_64BIT must be defined for X64 backend" +#endif + +#ifdef PERFM +#define DOPROF +#include "../vprof/vprof.h" +#define count_instr() _nvprof("x64",1) +#define count_prolog() _nvprof("x64-prolog",1); count_instr(); +#define count_imt() _nvprof("x64-imt",1) count_instr() +#else +#define count_instr() +#define count_prolog() +#define count_imt() +#endif + +namespace nanojit +{ +#define NJ_MAX_STACK_ENTRY 4096 +#define NJ_ALIGN_STACK 16 + +#define NJ_JTBL_SUPPORTED 1 +#define NJ_EXPANDED_LOADSTORE_SUPPORTED 1 +#define NJ_F2I_SUPPORTED 1 +#define NJ_SOFTFLOAT_SUPPORTED 0 +#define NJ_DIVI_SUPPORTED 1 + + static const Register RAX = { 0 }; // 1st int return, # of sse varargs + static const Register RCX = { 1 }; // 4th int arg + static const Register RDX = { 2 }; // 3rd int arg 2nd return + static const Register RBX = { 3 }; // saved + static const Register RSP = { 4 }; // stack ptr + static const Register RBP = { 5 }; // frame ptr, saved, sib reqd + static const Register RSI = { 6 }; // 2nd int arg + static const Register RDI = { 7 }; // 1st int arg + static const Register R8 = { 8 }; // 5th int arg + static const Register R9 = { 9 }; // 6th int arg + static const Register R10 = { 10 }; // scratch + static const Register R11 = { 11 }; // scratch + static const Register R12 = { 12 }; // saved + static const Register R13 = { 13 }; // saved, sib reqd like rbp + static const Register R14 = { 14 }; // saved + static const Register R15 = { 15 }; // saved + + static const Register XMM0 = { 16 }; // 1st double arg, return + static const Register XMM1 = { 17 }; // 2nd double arg, return + static const Register XMM2 = { 18 }; // 3rd double arg + static const Register XMM3 = { 19 }; // 4th double arg + static const Register XMM4 = { 20 }; // 5th double arg + static const Register XMM5 = { 21 }; // 6th double arg + static const Register XMM6 = { 22 }; // 7th double arg + static const Register XMM7 = { 23 }; // 8th double arg + static const Register XMM8 = { 24 }; // scratch + static const Register XMM9 = { 25 }; // scratch + static const Register XMM10 = { 26 }; // scratch + static const Register XMM11 = { 27 }; // scratch + static const Register XMM12 = { 28 }; // scratch + static const Register XMM13 = { 29 }; // scratch + static const Register XMM14 = { 30 }; // scratch + static const Register XMM15 = { 31 }; // scratch + + static const Register FP = RBP; + static const Register RZero = { 0 }; // useful in a few places in codegen + + static const uint32_t FirstRegNum = 0; + static const uint32_t LastRegNum = 31; + + static const Register deprecated_UnknownReg = { 32 }; // XXX: remove eventually, see bug 538924 + static const Register UnspecifiedReg = { 32 }; + +/* + * Micro-templating variable-length opcodes, idea first + * describe by Mike Pall of Luajit. + * + * X86-64 opcode encodings: LSB encodes the length of the + * opcode in bytes, remaining bytes are encoded as 1-7 bytes + * in a single uint64_t value. The value is written as a single + * store into the code stream, and the code pointer is decremented + * by the length. each successive instruction partially overlaps + * the previous one. + * + * emit methods below are able to encode mod/rm, sib, rex, and + * register and small immediate values into these opcode values + * without much branchy code. + * + * these opcodes encapsulate all the const parts of the instruction. + * for example, the alu-immediate opcodes (add, sub, etc) encode + * part of their opcode in the R field of the mod/rm byte; this + * hardcoded value is in the constant below, and the R argument + * to emitrr() is 0. In a few cases, a whole instruction is encoded + * this way (eg callrax). + * + * when a disp32, immI, or imm64 suffix can't fit in an 8-byte + * opcode, then it is written into the code separately and not counted + * in the opcode length. + */ + + enum X64Opcode +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#pragma warning(disable:4480) // nonstandard extension used: specifying underlying type for enum + : uint64_t +#endif + { + // 64bit opcode constants + // msb lsb len + X64_addqrr = 0xC003480000000003LL, // 64bit add r += b + X64_addqri = 0xC081480000000003LL, // 64bit add r += int64(immI) + X64_addqr8 = 0x00C0834800000004LL, // 64bit add r += int64(imm8) + X64_andqri = 0xE081480000000003LL, // 64bit and r &= int64(immI) + X64_andqr8 = 0x00E0834800000004LL, // 64bit and r &= int64(imm8) + X64_orqri = 0xC881480000000003LL, // 64bit or r |= int64(immI) + X64_orqr8 = 0x00C8834800000004LL, // 64bit or r |= int64(imm8) + X64_xorqri = 0xF081480000000003LL, // 64bit xor r ^= int64(immI) + X64_xorqr8 = 0x00F0834800000004LL, // 64bit xor r ^= int64(imm8) + X64_addlri = 0xC081400000000003LL, // 32bit add r += immI + X64_addlr8 = 0x00C0834000000004LL, // 32bit add r += imm8 + X64_andlri = 0xE081400000000003LL, // 32bit and r &= immI + X64_andlr8 = 0x00E0834000000004LL, // 32bit and r &= imm8 + X64_orlri = 0xC881400000000003LL, // 32bit or r |= immI + X64_orlr8 = 0x00C8834000000004LL, // 32bit or r |= imm8 + X64_sublri = 0xE881400000000003LL, // 32bit sub r -= immI + X64_sublr8 = 0x00E8834000000004LL, // 32bit sub r -= imm8 + X64_xorlri = 0xF081400000000003LL, // 32bit xor r ^= immI + X64_xorlr8 = 0x00F0834000000004LL, // 32bit xor r ^= imm8 + X64_addrr = 0xC003400000000003LL, // 32bit add r += b + X64_andqrr = 0xC023480000000003LL, // 64bit and r &= b + X64_andrr = 0xC023400000000003LL, // 32bit and r &= b + X64_call = 0x00000000E8000005LL, // near call + X64_callrax = 0xD0FF000000000002LL, // indirect call to addr in rax (no REX) + X64_cmovqno = 0xC0410F4800000004LL, // 64bit conditional mov if (no overflow) r = b + X64_cmovqnae= 0xC0420F4800000004LL, // 64bit conditional mov if (uint <) r = b + X64_cmovqnb = 0xC0430F4800000004LL, // 64bit conditional mov if (uint >=) r = b + X64_cmovqne = 0xC0450F4800000004LL, // 64bit conditional mov if (c) r = b + X64_cmovqna = 0xC0460F4800000004LL, // 64bit conditional mov if (uint <=) r = b + X64_cmovqnbe= 0xC0470F4800000004LL, // 64bit conditional mov if (uint >) r = b + X64_cmovqnge= 0xC04C0F4800000004LL, // 64bit conditional mov if (int <) r = b + X64_cmovqnl = 0xC04D0F4800000004LL, // 64bit conditional mov if (int >=) r = b + X64_cmovqng = 0xC04E0F4800000004LL, // 64bit conditional mov if (int <=) r = b + X64_cmovqnle= 0xC04F0F4800000004LL, // 64bit conditional mov if (int >) r = b + X64_cmovno = 0xC0410F4000000004LL, // 32bit conditional mov if (no overflow) r = b + X64_cmovnae = 0xC0420F4000000004LL, // 32bit conditional mov if (uint <) r = b + X64_cmovnb = 0xC0430F4000000004LL, // 32bit conditional mov if (uint >=) r = b + X64_cmovne = 0xC0450F4000000004LL, // 32bit conditional mov if (c) r = b + X64_cmovna = 0xC0460F4000000004LL, // 32bit conditional mov if (uint <=) r = b + X64_cmovnbe = 0xC0470F4000000004LL, // 32bit conditional mov if (uint >) r = b + X64_cmovnge = 0xC04C0F4000000004LL, // 32bit conditional mov if (int <) r = b + X64_cmovnl = 0xC04D0F4000000004LL, // 32bit conditional mov if (int >=) r = b + X64_cmovng = 0xC04E0F4000000004LL, // 32bit conditional mov if (int <=) r = b + X64_cmovnle = 0xC04F0F4000000004LL, // 32bit conditional mov if (int >) r = b + X64_cmplr = 0xC03B400000000003LL, // 32bit compare r,b + X64_cmpqr = 0xC03B480000000003LL, // 64bit compare r,b + X64_cmplri = 0xF881400000000003LL, // 32bit compare r,immI + X64_cmpqri = 0xF881480000000003LL, // 64bit compare r,int64(immI) + X64_cmplr8 = 0x00F8834000000004LL, // 32bit compare r,imm8 + X64_cmpqr8 = 0x00F8834800000004LL, // 64bit compare r,int64(imm8) + X64_cvtsi2sd= 0xC02A0F40F2000005LL, // convert int32 to double r = (double) b + X64_cvtsq2sd= 0xC02A0F48F2000005LL, // convert int64 to double r = (double) b + X64_cvtss2sd= 0xC05A0F40F3000005LL, // convert float to double r = (double) b + X64_cvtsd2ss= 0xC05A0F40F2000005LL, // convert double to float r = (float) b + X64_cvtsd2si= 0xC02D0F40F2000005LL, // convert double to int32 with rounding r = (int32) b + X64_cvttsd2si=0xC02C0F40F2000005LL, // convert double to int32 r = (int32) b + X64_divsd = 0xC05E0F40F2000005LL, // divide scalar double r /= b + X64_mulsd = 0xC0590F40F2000005LL, // multiply scalar double r *= b + X64_addsd = 0xC0580F40F2000005LL, // add scalar double r += b + X64_idiv = 0xF8F7400000000003LL, // 32bit signed div (rax = rdx:rax/r, rdx=rdx:rax%r) + X64_imul = 0xC0AF0F4000000004LL, // 32bit signed mul r *= b + X64_imuli = 0xC069400000000003LL, // 32bit signed mul r = b * immI + X64_imul8 = 0x00C06B4000000004LL, // 32bit signed mul r = b * imm8 + X64_jmpi = 0x0000000025FF0006LL, // jump *0(rip) + X64_jmp = 0x00000000E9000005LL, // jump near rel32 + X64_jmp8 = 0x00EB000000000002LL, // jump near rel8 + X64_jo = 0x00000000800F0006LL, // jump near if overflow + X64_jb = 0x00000000820F0006LL, // jump near if below (uint <) + X64_jae = 0x00000000830F0006LL, // jump near if above or equal (uint >=) + X64_ja = 0x00000000870F0006LL, // jump near if above (uint >) + X64_jbe = 0x00000000860F0006LL, // jump near if below or equal (uint <=) + X64_je = 0x00000000840F0006LL, // near jump if equal + X64_jl = 0x000000008C0F0006LL, // jump near if less (int <) + X64_jge = 0x000000008D0F0006LL, // jump near if greater or equal (int >=) + X64_jg = 0x000000008F0F0006LL, // jump near if greater (int >) + X64_jle = 0x000000008E0F0006LL, // jump near if less or equal (int <=) + X64_jp = 0x000000008A0F0006LL, // jump near if parity (PF == 1) + X64_jneg = 0x0000000001000000LL, // xor with this mask to negate the condition + X64_jo8 = 0x0070000000000002LL, // jump near if overflow + X64_jb8 = 0x0072000000000002LL, // jump near if below (uint <) + X64_jae8 = 0x0073000000000002LL, // jump near if above or equal (uint >=) + X64_ja8 = 0x0077000000000002LL, // jump near if above (uint >) + X64_jbe8 = 0x0076000000000002LL, // jump near if below or equal (uint <=) + X64_je8 = 0x0074000000000002LL, // near jump if equal + X64_jne8 = 0x0075000000000002LL, // jump near if not equal + X64_jl8 = 0x007C000000000002LL, // jump near if less (int <) + X64_jge8 = 0x007D000000000002LL, // jump near if greater or equal (int >=) + X64_jg8 = 0x007F000000000002LL, // jump near if greater (int >) + X64_jle8 = 0x007E000000000002LL, // jump near if less or equal (int <=) + X64_jp8 = 0x007A000000000002LL, // jump near if parity (PF == 1) + X64_jnp8 = 0x007B000000000002LL, // jump near if not parity (PF == 0) + X64_jneg8 = 0x0001000000000000LL, // xor with this mask to negate the condition + X64_leaqrm = 0x00000000808D4807LL, // 64bit load effective addr reg <- disp32+base + X64_lealrm = 0x00000000808D4007LL, // 32bit load effective addr reg <- disp32+base + X64_learip = 0x00000000058D4807LL, // 64bit RIP-relative lea. reg <- disp32+rip (modrm = 00rrr101 = 05) + X64_movlr = 0xC08B400000000003LL, // 32bit mov r <- b + X64_movbmr = 0x0000000080884007LL, // 8bit store r -> [b+d32] + X64_movsmr = 0x8089406600000004LL, // 16bit store r -> [b+d32] + X64_movlmr = 0x0000000080894007LL, // 32bit store r -> [b+d32] + X64_movlrm = 0x00000000808B4007LL, // 32bit load r <- [b+d32] + X64_movqmr = 0x0000000080894807LL, // 64bit store gpr -> [b+d32] + X64_movqspr = 0x0024448948000005LL, // 64bit store gpr -> [rsp+d32] (sib required) + X64_movqr = 0xC08B480000000003LL, // 64bit mov r <- b + X64_movqi = 0xB848000000000002LL, // 64bit mov r <- imm64 + X64_movi = 0xB840000000000002LL, // 32bit mov r <- immI + X64_movqi32 = 0xC0C7480000000003LL, // 64bit mov r <- int64(immI) + X64_movapsr = 0xC0280F4000000004LL, // 128bit mov xmm <- xmm + X64_movqrx = 0xC07E0F4866000005LL, // 64bit mov b <- xmm-r (reverses the usual r/b order) + X64_movqxr = 0xC06E0F4866000005LL, // 64bit mov b -> xmm-r + X64_movqrm = 0x00000000808B4807LL, // 64bit load r <- [b+d32] + X64_movsdrr = 0xC0100F40F2000005LL, // 64bit mov xmm-r <- xmm-b (upper 64bits unchanged) + X64_movsdrm = 0x80100F40F2000005LL, // 64bit load xmm-r <- [b+d32] (upper 64 cleared) + X64_movsdmr = 0x80110F40F2000005LL, // 64bit store xmm-r -> [b+d32] + X64_movssrm = 0x80100F40F3000005LL, // 32bit load xmm-r <- [b+d32] (upper 96 cleared) + X64_movssmr = 0x80110F40F3000005LL, // 32bit store xmm-r -> [b+d32] + X64_movsxdr = 0xC063480000000003LL, // sign extend i32 to i64 r = (int64)(int32) b + X64_movzx8 = 0xC0B60F4000000004LL, // zero extend i8 to i64 r = (uint64)(uint8) b + X64_movzx8m = 0x80B60F4000000004LL, // zero extend i8 load to i32 r <- [b+d32] + X64_movzx16m= 0x80B70F4000000004LL, // zero extend i16 load to i32 r <- [b+d32] + X64_movsx8m = 0x80BE0F4000000004LL, // sign extend i8 load to i32 r <- [b+d32] + X64_movsx16m= 0x80BF0F4000000004LL, // sign extend i16 load to i32 r <- [b+d32] + X64_neg = 0xD8F7400000000003LL, // 32bit two's compliment b = -b + X64_nop1 = 0x9000000000000001LL, // one byte NOP + X64_nop2 = 0x9066000000000002LL, // two byte NOP + X64_nop3 = 0x001F0F0000000003LL, // three byte NOP + X64_nop4 = 0x00401F0F00000004LL, // four byte NOP + X64_nop5 = 0x0000441F0F000005LL, // five byte NOP + X64_nop6 = 0x0000441F0F660006LL, // six byte NOP + X64_nop7 = 0x00000000801F0F07LL, // seven byte NOP + X64_not = 0xD0F7400000000003LL, // 32bit ones compliment b = ~b + X64_orlrr = 0xC00B400000000003LL, // 32bit or r |= b + X64_orqrr = 0xC00B480000000003LL, // 64bit or r |= b + X64_popr = 0x5840000000000002LL, // 64bit pop r <- [rsp++] + X64_pushr = 0x5040000000000002LL, // 64bit push r -> [--rsp] + X64_pxor = 0xC0EF0F4066000005LL, // 128bit xor xmm-r ^= xmm-b + X64_ret = 0xC300000000000001LL, // near return from called procedure + X64_sete = 0xC0940F4000000004LL, // set byte if equal (ZF == 1) + X64_seto = 0xC0900F4000000004LL, // set byte if overflow (OF == 1) + X64_setc = 0xC0920F4000000004LL, // set byte if carry (CF == 1) + X64_setl = 0xC09C0F4000000004LL, // set byte if less (int <) (SF != OF) + X64_setle = 0xC09E0F4000000004LL, // set byte if less or equal (int <=) (ZF == 1 || SF != OF) + X64_setg = 0xC09F0F4000000004LL, // set byte if greater (int >) (ZF == 0 && SF == OF) + X64_setge = 0xC09D0F4000000004LL, // set byte if greater or equal (int >=) (SF == OF) + X64_seta = 0xC0970F4000000004LL, // set byte if above (uint >) (CF == 0 && ZF == 0) + X64_setae = 0xC0930F4000000004LL, // set byte if above or equal (uint >=) (CF == 0) + X64_setb = 0xC0920F4000000004LL, // set byte if below (uint <) (CF == 1) + X64_setbe = 0xC0960F4000000004LL, // set byte if below or equal (uint <=) (ZF == 1 || CF == 1) + X64_subsd = 0xC05C0F40F2000005LL, // subtract scalar double r -= b + X64_shl = 0xE0D3400000000003LL, // 32bit left shift r <<= rcx + X64_shlq = 0xE0D3480000000003LL, // 64bit left shift r <<= rcx + X64_shr = 0xE8D3400000000003LL, // 32bit uint right shift r >>= rcx + X64_shrq = 0xE8D3480000000003LL, // 64bit uint right shift r >>= rcx + X64_sar = 0xF8D3400000000003LL, // 32bit int right shift r >>= rcx + X64_sarq = 0xF8D3480000000003LL, // 64bit int right shift r >>= rcx + X64_shli = 0x00E0C14000000004LL, // 32bit left shift r <<= imm8 + X64_shlqi = 0x00E0C14800000004LL, // 64bit left shift r <<= imm8 + X64_sari = 0x00F8C14000000004LL, // 32bit int right shift r >>= imm8 + X64_sarqi = 0x00F8C14800000004LL, // 64bit int right shift r >>= imm8 + X64_shri = 0x00E8C14000000004LL, // 32bit uint right shift r >>= imm8 + X64_shrqi = 0x00E8C14800000004LL, // 64bit uint right shift r >>= imm8 + X64_subqrr = 0xC02B480000000003LL, // 64bit sub r -= b + X64_subrr = 0xC02B400000000003LL, // 32bit sub r -= b + X64_subqri = 0xE881480000000003LL, // 64bit sub r -= int64(immI) + X64_subqr8 = 0x00E8834800000004LL, // 64bit sub r -= int64(imm8) + X64_ucomisd = 0xC02E0F4066000005LL, // unordered compare scalar double + X64_xorqrr = 0xC033480000000003LL, // 64bit xor r &= b + X64_xorrr = 0xC033400000000003LL, // 32bit xor r &= b + X64_xorpd = 0xC0570F4066000005LL, // 128bit xor xmm (two packed doubles) + X64_xorps = 0xC0570F4000000004LL, // 128bit xor xmm (four packed singles), one byte shorter + X64_xorpsm = 0x05570F4000000004LL, // 128bit xor xmm, [rip+disp32] + X64_xorpsa = 0x2504570F40000005LL, // 128bit xor xmm, [disp32] + X64_inclmRAX= 0x00FF000000000002LL, // incl (%rax) + X64_jmpx = 0xC524ff4000000004LL, // jmp [d32+x*8] + X64_jmpxb = 0xC024ff4000000004LL, // jmp [b+x*8] + + X64_movqmi = 0x80C7480000000003LL, // 32bit signed extended to 64-bit store imm -> qword ptr[b+disp32] + X64_movlmi = 0x80C7400000000003LL, // 32bit store imm -> dword ptr[b+disp32] + X64_movsmi = 0x80C7406600000004LL, // 16bit store imm -> word ptr[b+disp32] + X64_movbmi = 0x80C6400000000003LL, // 8bit store imm -> byte ptr[b+disp32] + + X86_and8r = 0xC022000000000002LL, // and rl,rh + X86_sete = 0xC0940F0000000003LL, // no-rex version of X64_sete + X86_setnp = 0xC09B0F0000000003LL // no-rex set byte if odd parity (ordered fcmp result) (PF == 0) + }; + + typedef uint32_t RegisterMask; + + static const RegisterMask GpRegs = 0xffff; + static const RegisterMask FpRegs = 0xffff0000; +#ifdef _WIN64 + static const RegisterMask SavedRegs = 1< + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "nanojit.h" + +#ifdef _MSC_VER + // disable some specific warnings which are normally useful, but pervasive in the code-gen macros + #pragma warning(disable:4310) // cast truncates constant value +#endif + +namespace nanojit +{ + #if defined FEATURE_NANOJIT && defined NANOJIT_IA32 + + #ifdef NJ_VERBOSE + const char *regNames[] = { + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", + "f0" + }; + + const char *gpRegNames8lo[] = { "al", "cl", "dl", "bl" }; + const char *gpRegNames8hi[] = { "ah", "ch", "dh", "bh" }; + #endif + + #define TODO(x) do{ verbose_only(outputf(#x);) NanoAssertMsgf(false, "%s", #x); } while(0) + + const Register Assembler::argRegs[] = { rECX, rEDX }; + const Register Assembler::retRegs[] = { rEAX, rEDX }; + const Register Assembler::savedRegs[] = { rEBX, rESI, rEDI }; + + const static uint8_t max_abi_regs[] = { + 2, /* ABI_FASTCALL */ + 1, /* ABI_THISCALL */ + 0, /* ABI_STDCALL */ + 0 /* ABI_CDECL */ + }; + + #define RB(r) gpRegNames8lo[REGNUM(r)] + #define RBhi(r) gpRegNames8hi[REGNUM(r)] + + typedef Register R; + typedef int32_t I32; + + // Length: 2--6 bytes. + inline void Assembler::MODRMsib(I32 r, R b, R i, I32 s, I32 d) { + if (d == 0 && b != rEBP) { + SIB(s, REGNUM(i), REGNUM(b)); + MODRM(0, r, 4); // amode == (b + i<>8); + } + + inline void Assembler::ALU2m(I32 c, R r, I32 d, R b) { + underrunProtect(9); + MODRMm(REGNUM(r), d, b); + *(--_nIns) = uint8_t(c); + *(--_nIns) = uint8_t(c>>8); + } + + inline void Assembler::ALU2sib(I32 c, Register r, R base, R index, I32 scale, I32 disp) { + underrunProtect(8); + MODRMsib(REGNUM(r), base, index, scale, disp); + *(--_nIns) = uint8_t(c); + *(--_nIns) = uint8_t(c>>8); + } + + inline void Assembler::ALUi(I32 c, R r, I32 i) { + underrunProtect(6); + NanoAssert(REGNUM(r) < 8); + if (isS8(i)) { + *(--_nIns) = uint8_t(i); + MODRMr(c>>3, REGNUM(r)); + *(--_nIns) = uint8_t(0x83); + } else { + IMM32(i); + if ( r == rEAX) { + *(--_nIns) = uint8_t(c); + } else { + MODRMr(c >> 3, REGNUM(r)); + *(--_nIns) = uint8_t(0x81); + } + } + } + + inline void Assembler::ALUmi(I32 c, I32 d, Register b, I32 i) { + underrunProtect(10); + NanoAssert(REGNUM(b) < 8); + if (isS8(i)) { + *(--_nIns) = uint8_t(i); + MODRMm(c>>3, d, b); + *(--_nIns) = uint8_t(0x83); + } else { + IMM32(i); + MODRMm(c>>3, d, b); + *(--_nIns) = uint8_t(0x81); + } + } + + inline void Assembler::ALU2(I32 c, R d, R s) { + underrunProtect(3); + MODRMr(REGNUM(d), REGNUM(s)); + *(--_nIns) = uint8_t(c); + *(--_nIns) = uint8_t(c>>8); + } + + inline Register Assembler::AL2AHReg(R r) { + NanoAssert(REGNUM(r) < 4); // one of: al, cl, dl, bl + Register r2 = { REGNUM(r) | 4 }; // convert to one of: ah, ch, dh, bh + return r2; + } + + inline void Assembler::OR(R l, R r) { count_alu(); ALU(0x0b, REGNUM(l), r); asm_output("or %s,%s", gpn(l), gpn(r)); } + inline void Assembler::AND(R l, R r) { count_alu(); ALU(0x23, REGNUM(l), r); asm_output("and %s,%s", gpn(l), gpn(r)); } + inline void Assembler::XOR(R l, R r) { count_alu(); ALU(0x33, REGNUM(l), r); asm_output("xor %s,%s", gpn(l), gpn(r)); } + inline void Assembler::ADD(R l, R r) { count_alu(); ALU(0x03, REGNUM(l), r); asm_output("add %s,%s", gpn(l), gpn(r)); } + inline void Assembler::SUB(R l, R r) { count_alu(); ALU(0x2b, REGNUM(l), r); asm_output("sub %s,%s", gpn(l), gpn(r)); } + inline void Assembler::IMUL(R l, R r){ count_alu(); ALU2(0x0faf, l, r); asm_output("imul %s,%s", gpn(l), gpn(r)); } + inline void Assembler::DIV(R r) { count_alu(); ALU(0xf7, 7, r); asm_output("idiv edx:eax, %s", gpn(r)); } + inline void Assembler::NOT(R r) { count_alu(); ALU(0xf7, 2, r); asm_output("not %s", gpn(r)); } + inline void Assembler::NEG(R r) { count_alu(); ALU(0xf7, 3, r); asm_output("neg %s", gpn(r)); } + inline void Assembler::AND8R(R r) { count_alu(); ALU(0x22, REGNUM(r), AL2AHReg(r)); asm_output("andb %s, %s", RB(r), RBhi(r)); } + + inline void Assembler::SHR(R r, R s) { + count_alu(); + NanoAssert(s == rECX); (void)s; + ALU(0xd3, 5, r); + asm_output("shr %s,%s", gpn(r), gpn(s)); + } + + inline void Assembler::SAR(R r, R s) { + count_alu(); + NanoAssert(s == rECX); (void)s; + ALU(0xd3, 7, r); + asm_output("sar %s,%s", gpn(r), gpn(s)); + } + + inline void Assembler::SHL(R r, R s) { + count_alu(); + NanoAssert(s == rECX); (void)s; + ALU(0xd3, 4, r); + asm_output("shl %s,%s", gpn(r), gpn(s)); + } + + inline void Assembler::SHIFT(I32 c, R r, I32 i) { + underrunProtect(3); + *--_nIns = uint8_t(i); + MODRMr(c, REGNUM(r)); + *--_nIns = 0xc1; + } + + inline void Assembler::SHLi(R r, I32 i) { count_alu(); SHIFT(4, r, i); asm_output("shl %s,%d", gpn(r), i); } + inline void Assembler::SHRi(R r, I32 i) { count_alu(); SHIFT(5, r, i); asm_output("shr %s,%d", gpn(r), i); } + inline void Assembler::SARi(R r, I32 i) { count_alu(); SHIFT(7, r, i); asm_output("sar %s,%d", gpn(r), i); } + + inline void Assembler::MOVZX8(R d, R s) { count_alu(); ALU2(0x0fb6, d, s); asm_output("movzx %s,%s", gpn(d), gpn(s)); } + + inline void Assembler::SUBi(R r, I32 i) { count_alu(); ALUi(0x2d, r, i); asm_output("sub %s,%d", gpn(r), i); } + inline void Assembler::ADDi(R r, I32 i) { count_alu(); ALUi(0x05, r, i); asm_output("add %s,%d", gpn(r), i); } + inline void Assembler::ANDi(R r, I32 i) { count_alu(); ALUi(0x25, r, i); asm_output("and %s,%d", gpn(r), i); } + inline void Assembler::ORi(R r, I32 i) { count_alu(); ALUi(0x0d, r, i); asm_output("or %s,%d", gpn(r), i); } + inline void Assembler::XORi(R r, I32 i) { count_alu(); ALUi(0x35, r, i); asm_output("xor %s,%d", gpn(r), i); } + + inline void Assembler::ADDmi(I32 d, R b, I32 i) { count_alust(); ALUmi(0x05, d, b, i); asm_output("add %d(%s), %d", d, gpn(b), i); } + + inline void Assembler::TEST(R d, R s) { count_alu(); ALU(0x85, REGNUM(d), s); asm_output("test %s,%s", gpn(d), gpn(s)); } + inline void Assembler::CMP(R l, R r) { count_alu(); ALU(0x3b, REGNUM(l), r); asm_output("cmp %s,%s", gpn(l), gpn(r)); } + inline void Assembler::CMPi(R r, I32 i) { count_alu(); ALUi(0x3d, r, i); asm_output("cmp %s,%d", gpn(r), i); } + + inline void Assembler::LEA(R r, I32 d, R b) { count_alu(); ALUm(0x8d, REGNUM(r), d, b); asm_output("lea %s,%d(%s)", gpn(r), d, gpn(b)); } + // This addressing mode is not supported by the MODRMsib function. + inline void Assembler::LEAmi4(R r, I32 d, R i) { + count_alu(); + IMM32(int32_t(d)); + SIB(2, REGNUM(i), 5); + MODRM(0, REGNUM(r), 4); // amode == d(i*4) + *(--_nIns) = 0x8d; + asm_output("lea %s, %p(%s*4)", gpn(r), (void*)d, gpn(i)); + } + + inline void Assembler::CDQ() { SARi(rEDX, 31); MR(rEDX, rEAX); } + + inline void Assembler::INCLi(I32 p) { + count_alu(); + underrunProtect(6); + IMM32((uint32_t)(ptrdiff_t)p); *(--_nIns) = 0x05; *(--_nIns) = 0xFF; + asm_output("incl (%p)", (void*)p); + } + + inline void Assembler::SETE( R r) { count_alu(); ALU2(0x0f94, r, r); asm_output("sete %s", gpn(r)); } + inline void Assembler::SETNP(R r) { count_alu(); ALU2(0x0f9B, r, r); asm_output("setnp %s", gpn(r)); } + inline void Assembler::SETNPH(R r) { count_alu(); ALU2(0x0f9B, AL2AHReg(r), AL2AHReg(r)); asm_output("setnp %s", RBhi(r)); } + inline void Assembler::SETL( R r) { count_alu(); ALU2(0x0f9C, r, r); asm_output("setl %s", gpn(r)); } + inline void Assembler::SETLE(R r) { count_alu(); ALU2(0x0f9E, r, r); asm_output("setle %s", gpn(r)); } + inline void Assembler::SETG( R r) { count_alu(); ALU2(0x0f9F, r, r); asm_output("setg %s", gpn(r)); } + inline void Assembler::SETGE(R r) { count_alu(); ALU2(0x0f9D, r, r); asm_output("setge %s", gpn(r)); } + inline void Assembler::SETB( R r) { count_alu(); ALU2(0x0f92, r, r); asm_output("setb %s", gpn(r)); } + inline void Assembler::SETBE(R r) { count_alu(); ALU2(0x0f96, r, r); asm_output("setbe %s", gpn(r)); } + inline void Assembler::SETA( R r) { count_alu(); ALU2(0x0f97, r, r); asm_output("seta %s", gpn(r)); } + inline void Assembler::SETAE(R r) { count_alu(); ALU2(0x0f93, r, r); asm_output("setae %s", gpn(r)); } + inline void Assembler::SETO( R r) { count_alu(); ALU2(0x0f92, r, r); asm_output("seto %s", gpn(r)); } + + inline void Assembler::MREQ(R d, R s) { count_alu(); ALU2(0x0f44, d, s); asm_output("cmove %s,%s", gpn(d), gpn(s)); } + inline void Assembler::MRNE(R d, R s) { count_alu(); ALU2(0x0f45, d, s); asm_output("cmovne %s,%s", gpn(d), gpn(s)); } + inline void Assembler::MRL( R d, R s) { count_alu(); ALU2(0x0f4C, d, s); asm_output("cmovl %s,%s", gpn(d), gpn(s)); } + inline void Assembler::MRLE(R d, R s) { count_alu(); ALU2(0x0f4E, d, s); asm_output("cmovle %s,%s", gpn(d), gpn(s)); } + inline void Assembler::MRG( R d, R s) { count_alu(); ALU2(0x0f4F, d, s); asm_output("cmovg %s,%s", gpn(d), gpn(s)); } + inline void Assembler::MRGE(R d, R s) { count_alu(); ALU2(0x0f4D, d, s); asm_output("cmovge %s,%s", gpn(d), gpn(s)); } + inline void Assembler::MRB( R d, R s) { count_alu(); ALU2(0x0f42, d, s); asm_output("cmovb %s,%s", gpn(d), gpn(s)); } + inline void Assembler::MRBE(R d, R s) { count_alu(); ALU2(0x0f46, d, s); asm_output("cmovbe %s,%s", gpn(d), gpn(s)); } + inline void Assembler::MRA( R d, R s) { count_alu(); ALU2(0x0f47, d, s); asm_output("cmova %s,%s", gpn(d), gpn(s)); } + inline void Assembler::MRAE(R d, R s) { count_alu(); ALU2(0x0f43, d, s); asm_output("cmovae %s,%s", gpn(d), gpn(s)); } + inline void Assembler::MRNO(R d, R s) { count_alu(); ALU2(0x0f41, d, s); asm_output("cmovno %s,%s", gpn(d), gpn(s)); } + + // these aren't currently used but left in for reference + //#define LDEQ(r,d,b) do { ALU2m(0x0f44,r,d,b); asm_output("cmove %s,%d(%s)", gpn(r),d,gpn(b)); } while(0) + //#define LDNEQ(r,d,b) do { ALU2m(0x0f45,r,d,b); asm_output("cmovne %s,%d(%s)", gpn(r),d,gpn(b)); } while(0) + + inline void Assembler::LD(R reg, I32 disp, R base) { + count_ld(); + ALUm(0x8b, REGNUM(reg), disp, base); + asm_output("mov %s,%d(%s)", gpn(reg), disp, gpn(base)); + } + + inline void Assembler::LDdm(R reg, I32 addr) { + count_ld(); + ALUdm(0x8b, reg, addr); + asm_output("mov %s,0(%p)", gpn(reg), (void*)addr); + } + +#define SIBIDX(n) "1248"[n] + + inline void Assembler::LDsib(R reg, I32 disp, R base, R index, I32 scale) { + count_ld(); + ALUsib(0x8b, reg, base, index, scale, disp); + asm_output("mov %s,%d(%s+%s*%c)", gpn(reg), disp, gpn(base), gpn(index), SIBIDX(scale)); + } + + // note: movzx/movsx are being output with an 8/16 suffix to indicate the + // size being loaded. This doesn't really match standard intel format + // (though is arguably terser and more obvious in this case) and would + // probably be nice to fix. (Likewise, the 8/16 bit stores being output + // as "mov8" and "mov16" respectively.) + + // Load 16-bit, sign extend. + inline void Assembler::LD16S(R r, I32 d, R b) { + count_ld(); + ALU2m(0x0fbf, r, d, b); + asm_output("movsx16 %s,%d(%s)", gpn(r), d, gpn(b)); + } + + inline void Assembler::LD16Sdm(R r, I32 addr) { + count_ld(); + ALU2dm(0x0fbf, r, addr); + asm_output("movsx16 %s,0(%lx)", gpn(r), (unsigned long)addr); + } + + inline void Assembler::LD16Ssib(R r, I32 disp, R base, R index, I32 scale) { + count_ld(); + ALU2sib(0x0fbf, r, base, index, scale, disp); + asm_output("movsx16 %s,%d(%s+%s*%c)", gpn(r), disp, gpn(base), gpn(index), SIBIDX(scale)); + } + + // Load 16-bit, zero extend. + inline void Assembler::LD16Z(R r, I32 d, R b) { + count_ld(); + ALU2m(0x0fb7, r, d, b); + asm_output("movzx16 %s,%d(%s)", gpn(r), d, gpn(b)); + } + + inline void Assembler::LD16Zdm(R r, I32 addr) { + count_ld(); + ALU2dm(0x0fb7, r, addr); + asm_output("movzx16 %s,0(%lx)", gpn(r), (unsigned long)addr); + } + + inline void Assembler::LD16Zsib(R r, I32 disp, R base, R index, I32 scale) { + count_ld(); + ALU2sib(0x0fb7, r, base, index, scale, disp); + asm_output("movzx16 %s,%d(%s+%s*%c)", gpn(r), disp, gpn(base), gpn(index), SIBIDX(scale)); + } + + // Load 8-bit, zero extend. + inline void Assembler::LD8Z(R r, I32 d, R b) { + count_ld(); + ALU2m(0x0fb6, r, d, b); + asm_output("movzx8 %s,%d(%s)", gpn(r), d, gpn(b)); + } + + inline void Assembler::LD8Zdm(R r, I32 addr) { + count_ld(); + ALU2dm(0x0fb6, r, addr); + asm_output("movzx8 %s,0(%lx)", gpn(r), (long unsigned)addr); + } + + inline void Assembler::LD8Zsib(R r, I32 disp, R base, R index, I32 scale) { + count_ld(); + ALU2sib(0x0fb6, r, base, index, scale, disp); + asm_output("movzx8 %s,%d(%s+%s*%c)", gpn(r), disp, gpn(base), gpn(index), SIBIDX(scale)); + } + + // Load 8-bit, sign extend. + inline void Assembler::LD8S(R r, I32 d, R b) { + count_ld(); + ALU2m(0x0fbe, r, d, b); + asm_output("movsx8 %s,%d(%s)", gpn(r), d, gpn(b)); + } + + inline void Assembler::LD8Sdm(R r, I32 addr) { + count_ld(); + ALU2dm(0x0fbe, r, addr); + asm_output("movsx8 %s,0(%lx)", gpn(r), (long unsigned)addr); + } + + inline void Assembler::LD8Ssib(R r, I32 disp, R base, R index, I32 scale) { + count_ld(); + ALU2sib(0x0fbe, r, base, index, scale, disp); + asm_output("movsx8 %s,%d(%s+%s*%c)", gpn(r), disp, gpn(base), gpn(index), SIBIDX(scale)); + } + + inline void Assembler::LDi(R r, I32 i) { + count_ld(); + underrunProtect(5); + IMM32(i); + NanoAssert(REGNUM(r) < 8); + *(--_nIns) = uint8_t(0xb8 | REGNUM(r)); + asm_output("mov %s,%d", gpn(r), i); + } + + // Quirk of x86-32: reg must be a/b/c/d for byte stores here. + inline void Assembler::ST8(R base, I32 disp, R reg) { + count_st(); + NanoAssert(REGNUM(reg) < 4); + ALUm(0x88, REGNUM(reg), disp, base); + asm_output("mov8 %d(%s),%s", disp, base==UnspecifiedReg ? "0" : gpn(base), gpn(reg)); + } + + // Quirk of x86-32: reg must be a/b/c/d for byte stores here. + inline void Assembler::ST8sib(I32 disp, R base, R index, I32 scale, R reg) { + count_st(); + NanoAssert(REGNUM(reg) < 4); + ALUsib(0x88, reg, base, index, scale, disp); + asm_output("mov8 %d(%s+%s*%c),%s", disp, base==UnspecifiedReg ? "0" : gpn(base), + gpn(index), SIBIDX(scale), gpn(reg)); + } + + inline void Assembler::ST16(R base, I32 disp, R reg) { + count_st(); + ALUm16(0x89, REGNUM(reg), disp, base); + asm_output("mov16 %d(%s),%s", disp, base==UnspecifiedReg ? "0" : gpn(base), gpn(reg)); + } + + inline void Assembler::ST16sib(I32 disp, R base, R index, I32 scale, R reg) { + count_st(); + ALUsib16(0x89, reg, base, index, scale, disp); + asm_output("mov16 %d(%s+%s*%c),%s", disp, base==UnspecifiedReg ? "0" : gpn(base), + gpn(index), SIBIDX(scale), gpn(reg)); + } + + inline void Assembler::ST(R base, I32 disp, R reg) { + count_st(); + ALUm(0x89, REGNUM(reg), disp, base); + asm_output("mov %d(%s),%s", disp, base==UnspecifiedReg ? "0" : gpn(base), gpn(reg)); + } + + inline void Assembler::STsib(I32 disp, R base, R index, I32 scale, R reg) { + count_st(); + ALUsib(0x89, reg, base, index, scale, disp); + asm_output("mov %d(%s+%s*%c),%s", disp, base==UnspecifiedReg ? "0" : gpn(base), + gpn(index), SIBIDX(scale), gpn(reg)); + } + + inline void Assembler::ST8i(R base, I32 disp, I32 imm) { + count_st(); + underrunProtect(8); + IMM8(imm); + MODRMm(0, disp, base); + *(--_nIns) = 0xc6; + asm_output("mov8 %d(%s),%d", disp, gpn(base), imm); + } + + inline void Assembler::ST8isib(I32 disp, R base, R index, I32 scale, I32 imm) { + count_st(); + underrunProtect(8); + IMM8(imm); + MODRMsib(0, base, index, scale, disp); + *(--_nIns) = 0xc6; + asm_output("mov8 %d(%s+%s*%c),%d", disp, gpn(base), gpn(index), SIBIDX(scale), imm); + } + + inline void Assembler::ST16i(R base, I32 disp, I32 imm) { + count_st(); + underrunProtect(10); + IMM16(imm); + MODRMm(0, disp, base); + *(--_nIns) = 0xc7; + *(--_nIns) = 0x66; + asm_output("mov16 %d(%s),%d", disp, gpn(base), imm); + } + + inline void Assembler::ST16isib(I32 disp, R base, R index, I32 scale, I32 imm) { + count_st(); + underrunProtect(10); + IMM16(imm); + MODRMsib(0, base, index, scale, disp); + *(--_nIns) = 0xc7; + *(--_nIns) = 0x66; + asm_output("mov16 %d(%s+%s*%c),%d", disp, gpn(base), gpn(index), SIBIDX(scale), imm); + } + + inline void Assembler::STi(R base, I32 disp, I32 imm) { + count_st(); + underrunProtect(11); + IMM32(imm); + MODRMm(0, disp, base); + *(--_nIns) = 0xc7; + asm_output("mov %d(%s),%d", disp, gpn(base), imm); + } + + inline void Assembler::STisib(I32 disp, R base, R index, I32 scale, I32 imm) { + count_st(); + underrunProtect(11); + IMM32(imm); + MODRMsib(0, base, index, scale, disp); + *(--_nIns) = 0xc7; + asm_output("mov %d(%s+%s*%c),%d", disp, gpn(base), gpn(index), SIBIDX(scale), imm); + } + + const uint8_t INT3_OP = 0xcc; + + inline void Assembler::RET() { count_ret(); ALU0(0xc3); asm_output("ret"); } + inline void Assembler::NOP() { count_alu(); ALU0(0x90); asm_output("nop"); } + inline void Assembler::INT3() { ALU0(INT3_OP); asm_output("int3"); } + + inline void Assembler::PUSHi(I32 i) { + count_push(); + if (isS8(i)) { + underrunProtect(2); + *(--_nIns) = uint8_t(i); + *(--_nIns) = 0x6a; + asm_output("push %d", i); + } else { + underrunProtect(5); + IMM32(i); + *(--_nIns) = 0x68; + asm_output("push %d", i); + } + } + + inline void Assembler::PUSHr(R r) { + count_push(); + underrunProtect(1); + NanoAssert(REGNUM(r) < 8); + *(--_nIns) = uint8_t(0x50 | REGNUM(r)); + asm_output("push %s", gpn(r)); + } + + inline void Assembler::PUSHm(I32 d, R b) { + count_pushld(); + ALUm(0xff, 6, d, b); + asm_output("push %d(%s)", d, gpn(b)); + } + + inline void Assembler::POPr(R r) { + count_pop(); + underrunProtect(1); + NanoAssert(REGNUM(r) < 8); + *(--_nIns) = uint8_t(0x58 | REGNUM(r)); + asm_output("pop %s", gpn(r)); + } + + inline void Assembler::JCC(I32 o, NIns* t, const char* n) { + count_jcc(); + underrunProtect(6); + intptr_t tt = (intptr_t)t - (intptr_t)_nIns; + if (t && isS8(tt)) { + *(--_nIns) = uint8_t(tt); + *(--_nIns) = uint8_t(0x70 | o); + } else { + IMM32(tt); + *(--_nIns) = uint8_t(0x80 | o); + *(--_nIns) = JCC32; + } + asm_output("%-5s %p", n, t); + (void) n; + } + + inline void Assembler::JMP_long(NIns* t) { + count_jmp(); + underrunProtect(5); + NanoAssert(t); + intptr_t tt = (intptr_t)t - (intptr_t)_nIns; + IMM32(tt); + *(--_nIns) = JMP32; + asm_output("jmp %p", t); + verbose_only( verbose_outputf("%p:", (void*)_nIns); ) + } + + inline void Assembler::JMP_indirect(R r) { + underrunProtect(2); + MODRMm(4, 0, r); + *(--_nIns) = 0xff; + asm_output("jmp *(%s)", gpn(r)); + } + + inline void Assembler::JMP_indexed(Register x, I32 ss, NIns** addr) { + underrunProtect(7); + IMM32(int32_t(addr)); + SIB(ss, REGNUM(x), 5); + MODRM(0, 4, 4); // amode == addr(table + x<> 8) & 0xff); + *(--_nIns) = uint8_t((c >> 16) & 0xff); + } + + inline void Assembler::SSEm(I32 c, R r, I32 d, R b) { + underrunProtect(9); + MODRMm(REGNUM(r)&7, d, b); + *(--_nIns) = uint8_t(c & 0xff); + *(--_nIns) = uint8_t((c >> 8) & 0xff); + *(--_nIns) = uint8_t((c >> 16) & 0xff); + } + + inline void Assembler::SSEsib(I32 c, R rr, I32 d, R rb, R ri, I32 scale) { + underrunProtect(9); + MODRMsib(REGNUM(rr)&7, rb, ri, scale, d); + *(--_nIns) = uint8_t(c & 0xff); + *(--_nIns) = uint8_t((c >> 8) & 0xff); + *(--_nIns) = uint8_t((c >> 16) & 0xff); + } + + inline void Assembler::LDSDm(R r, const double* addr) { + count_ldq(); + underrunProtect(8); + IMM32(int32_t(addr)); + MODRM(0, REGNUM(r) & 7, 5); // amode == addr(r) + *(--_nIns) = 0x10; + *(--_nIns) = 0x0f; + *(--_nIns) = 0xf2; + // *addr is a constant, so we can print it here. + asm_output("movsd %s,(%p) // =%f", gpn(r), (void*)addr, *addr); + } + + inline void Assembler::SSE_LDQ( R r, I32 d, R b) { count_ldq(); SSEm(0xf30f7e, r, d, b); asm_output("movq %s,%d(%s)", gpn(r), d, gpn(b)); } + inline void Assembler::SSE_LDSS(R r, I32 d, R b) { count_ld(); SSEm(0xf30f10, r, d, b); asm_output("movss %s,%d(%s)", gpn(r), d, gpn(b)); } + + inline void Assembler::SSE_LDQsib(R rr, I32 d, R rb, R ri, I32 scale) + { + count_ldq(); + SSEsib(0xf30f7e, rr, d, rb, ri, scale); + asm_output("movq %s,%d(%s+%s*%c)", gpn(rr), d, gpn(rb), gpn(ri), SIBIDX(scale)); + } + + inline void Assembler::SSE_LDSSsib(R rr, I32 d, R rb, R ri, I32 scale) + { + count_ld(); + SSEsib(0xf30f10, rr, d, rb, ri, scale); + asm_output("movss %s,%d(%s+%s*%c)", gpn(rr), d, gpn(rb), gpn(ri), SIBIDX(scale)); + } + + inline void Assembler::SSE_STSD(I32 d, R b, R r) { count_stq(); SSEm(0xf20f11, r, d, b); asm_output("movsd %d(%s),%s", d, gpn(b), gpn(r)); } + inline void Assembler::SSE_STQ( I32 d, R b, R r) { count_stq(); SSEm(0x660fd6, r, d, b); asm_output("movq %d(%s),%s", d, gpn(b), gpn(r)); } + inline void Assembler::SSE_STSS(I32 d, R b, R r) { count_st(); SSEm(0xf30f11, r, d, b); asm_output("movss %d(%s),%s", d, gpn(b), gpn(r)); } + + inline void Assembler::SSE_STQsib(I32 d, R rb, R ri, I32 scale, R rv) { + count_stq(); + SSEsib(0x660fd6, rv, d, rb, ri, scale); + asm_output("movq %d(%s+%s*%c),%s", d, gpn(rb), gpn(ri), SIBIDX(scale), gpn(rv)); + } + + inline void Assembler::SSE_CVTSI2SD(R xr, R gr) { count_fpu(); SSE(0xf20f2a, xr, gr); asm_output("cvtsi2sd %s,%s", gpn(xr), gpn(gr)); } + inline void Assembler::SSE_CVTSD2SI(R gr, R xr) { count_fpu(); SSE(0xf20f2d, gr, xr); asm_output("cvtsd2si %s,%s", gpn(gr), gpn(xr)); } + inline void Assembler::SSE_CVTTSD2SI(R gr, R xr) { count_fpu(); SSE(0xf20f2c, gr, xr); asm_output("cvttsd2si %s,%s",gpn(gr), gpn(xr)); } + inline void Assembler::SSE_CVTSD2SS(R xr, R gr) { count_fpu(); SSE(0xf20f5a, xr, gr); asm_output("cvtsd2ss %s,%s", gpn(xr), gpn(gr)); } + inline void Assembler::SSE_CVTSS2SD(R xr, R gr) { count_fpu(); SSE(0xf30f5a, xr, gr); asm_output("cvtss2sd %s,%s", gpn(xr), gpn(gr)); } + inline void Assembler::SSE_CVTDQ2PD(R d, R r) { count_fpu(); SSE(0xf30fe6, d, r); asm_output("cvtdq2pd %s,%s", gpn(d), gpn(r)); } + + // Move and zero-extend GP reg to XMM reg. + inline void Assembler::SSE_MOVD(R d, R s) { + count_mov(); + if (IsXmmReg(s)) { + NanoAssert(IsGpReg(d)); + SSE(0x660f7e, s, d); + } else { + NanoAssert(IsGpReg(s)); + NanoAssert(IsXmmReg(d)); + SSE(0x660f6e, d, s); + } + asm_output("movd %s,%s", gpn(d), gpn(s)); + } + + inline void Assembler::SSE_MOVSD(R rd, R rs) { + count_mov(); + NanoAssert(IsXmmReg(rd) && IsXmmReg(rs)); + SSE(0xf20f10, rd, rs); + asm_output("movsd %s,%s", gpn(rd), gpn(rs)); + } + + inline void Assembler::SSE_ADDSD(R rd, R rs) { + count_fpu(); + NanoAssert(IsXmmReg(rd) && IsXmmReg(rs)); + SSE(0xf20f58, rd, rs); + asm_output("addsd %s,%s", gpn(rd), gpn(rs)); + } + + inline void Assembler::SSE_ADDSDm(R r, const double* addr) { + count_fpuld(); + underrunProtect(8); + NanoAssert(IsXmmReg(r)); + const double* daddr = addr; + IMM32(int32_t(daddr)); + MODRM(0, REGNUM(r) & 7, 5); // amode == daddr(r) + *(--_nIns) = 0x58; + *(--_nIns) = 0x0f; + *(--_nIns) = 0xf2; + // *daddr is a constant, so we can print it here. + asm_output("addsd %s,(%p) // =%f", gpn(r), (void*)daddr, *daddr); + } + + inline void Assembler::SSE_SUBSD(R rd, R rs) { + count_fpu(); + NanoAssert(IsXmmReg(rd) && IsXmmReg(rs)); + SSE(0xf20f5c, rd, rs); + asm_output("subsd %s,%s", gpn(rd), gpn(rs)); + } + + inline void Assembler::SSE_MULSD(R rd, R rs) { + count_fpu(); + NanoAssert(IsXmmReg(rd) && IsXmmReg(rs)); + SSE(0xf20f59, rd, rs); + asm_output("mulsd %s,%s", gpn(rd), gpn(rs)); + } + + inline void Assembler::SSE_DIVSD(R rd, R rs) { + count_fpu(); + NanoAssert(IsXmmReg(rd) && IsXmmReg(rs)); + SSE(0xf20f5e, rd, rs); + asm_output("divsd %s,%s", gpn(rd), gpn(rs)); + } + + inline void Assembler::SSE_UCOMISD(R rl, R rr) { + count_fpu(); + NanoAssert(IsXmmReg(rl) && IsXmmReg(rr)); + SSE(0x660f2e, rl, rr); + asm_output("ucomisd %s,%s", gpn(rl), gpn(rr)); + } + + inline void Assembler::SSE_XORPD(R r, const uint32_t* maskaddr) { + count_fpuld(); + underrunProtect(8); + IMM32(int32_t(maskaddr)); + MODRM(0, REGNUM(r) & 7, 5); // amode == maskaddr(r) + *(--_nIns) = 0x57; + *(--_nIns) = 0x0f; + *(--_nIns) = 0x66; + asm_output("xorpd %s,(%p)", gpn(r), (void*)maskaddr); + } + + inline void Assembler::SSE_XORPDr(R rd, R rs) { + count_fpu(); + SSE(0x660f57, rd, rs); + asm_output("xorpd %s,%s", gpn(rd), gpn(rs)); + } + + // floating point unit + inline void Assembler::FPUc(I32 o) { + underrunProtect(2); + *(--_nIns) = uint8_t(o & 0xff); + *(--_nIns) = uint8_t((o >> 8) & 0xff); + } + + inline void Assembler::FPUm(I32 o, I32 d, R b) { + underrunProtect(7); + MODRMm(uint8_t(o), d, b); + *(--_nIns) = uint8_t(o >> 8); + } + + inline void Assembler::FPUdm(I32 o, const double* const m) { + underrunProtect(6); + MODRMdm(uint8_t(o), int32_t(m)); + *(--_nIns) = uint8_t(o >> 8); + } + + inline void Assembler::TEST_AH(I32 i) { + count_alu(); + underrunProtect(3); + *(--_nIns) = uint8_t(i); + *(--_nIns) = 0xc4; + *(--_nIns) = 0xf6; + asm_output("test ah, %d", i); + } + + inline void Assembler::TEST_AX(I32 i) { + count_fpu(); + underrunProtect(5); + *(--_nIns) = 0; + *(--_nIns) = uint8_t(i); + *(--_nIns) = uint8_t(i >> 8); + *(--_nIns) = 0; + *(--_nIns) = 0xa9; + asm_output("test ax, %d", i); + } + + inline void Assembler::FNSTSW_AX() { count_fpu(); FPUc(0xdfe0); asm_output("fnstsw_ax"); } + inline void Assembler::FCHS() { count_fpu(); FPUc(0xd9e0); asm_output("fchs"); } + inline void Assembler::FLD1() { count_fpu(); FPUc(0xd9e8); asm_output("fld1"); fpu_push(); } + inline void Assembler::FLDZ() { count_fpu(); FPUc(0xd9ee); asm_output("fldz"); fpu_push(); } + + inline void Assembler::FST32(bool p, I32 d, R b){ count_stq(); FPUm(0xd902|(p?1:0), d, b); asm_output("fst%s32 %d(%s)", (p?"p":""), d, gpn(b)); if (p) fpu_pop(); } + inline void Assembler::FSTQ(bool p, I32 d, R b) { count_stq(); FPUm(0xdd02|(p?1:0), d, b); asm_output("fst%sq %d(%s)", (p?"p":""), d, gpn(b)); if (p) fpu_pop(); } + + inline void Assembler::FSTPQ(I32 d, R b) { FSTQ(1, d, b); } + + inline void Assembler::FCOM(bool p, I32 d, R b) { count_fpuld(); FPUm(0xdc02|(p?1:0), d, b); asm_output("fcom%s %d(%s)", (p?"p":""), d, gpn(b)); if (p) fpu_pop(); } + inline void Assembler::FCOMdm(bool p, const double* dm) { + count_fpuld(); + FPUdm(0xdc02|(p?1:0), dm); + asm_output("fcom%s (%p)", (p?"p":""), (void*)dm); + if (p) fpu_pop(); + } + + inline void Assembler::FLD32(I32 d, R b) { count_ldq(); FPUm(0xd900, d, b); asm_output("fld32 %d(%s)", d, gpn(b)); fpu_push();} + inline void Assembler::FLDQ(I32 d, R b) { count_ldq(); FPUm(0xdd00, d, b); asm_output("fldq %d(%s)", d, gpn(b)); fpu_push();} + inline void Assembler::FLDQdm(const double* dm) { count_ldq(); FPUdm(0xdd00, dm); asm_output("fldq (%p)", (void*)dm); fpu_push();} + inline void Assembler::FILDQ(I32 d, R b) { count_fpuld(); FPUm(0xdf05, d, b); asm_output("fildq %d(%s)", d, gpn(b)); fpu_push(); } + inline void Assembler::FILD(I32 d, R b) { count_fpuld(); FPUm(0xdb00, d, b); asm_output("fild %d(%s)", d, gpn(b)); fpu_push(); } + + inline void Assembler::FIST(bool p, I32 d, R b) { + count_fpu(); + FPUm(0xdb02 | (p?1:0), d, b); + asm_output("fist%s %d(%s)", (p?"p":""), d, gpn(b)); + if (p) fpu_pop(); + } + + inline void Assembler::FADD( I32 d, R b) { count_fpu(); FPUm(0xdc00, d, b); asm_output("fadd %d(%s)", d, gpn(b)); } + inline void Assembler::FSUB( I32 d, R b) { count_fpu(); FPUm(0xdc04, d, b); asm_output("fsub %d(%s)", d, gpn(b)); } + inline void Assembler::FSUBR(I32 d, R b) { count_fpu(); FPUm(0xdc05, d, b); asm_output("fsubr %d(%s)", d, gpn(b)); } + inline void Assembler::FMUL( I32 d, R b) { count_fpu(); FPUm(0xdc01, d, b); asm_output("fmul %d(%s)", d, gpn(b)); } + inline void Assembler::FDIV( I32 d, R b) { count_fpu(); FPUm(0xdc06, d, b); asm_output("fdiv %d(%s)", d, gpn(b)); } + inline void Assembler::FDIVR(I32 d, R b) { count_fpu(); FPUm(0xdc07, d, b); asm_output("fdivr %d(%s)", d, gpn(b)); } + + inline void Assembler::FADDdm( const double *dm) { count_ldq(); FPUdm(0xdc00, dm); asm_output("fadd (%p)", (void*)dm); } + inline void Assembler::FSUBRdm(const double* dm) { count_ldq(); FPUdm(0xdc05, dm); asm_output("fsubr (%p)", (void*)dm); } + inline void Assembler::FMULdm( const double* dm) { count_ldq(); FPUdm(0xdc01, dm); asm_output("fmul (%p)", (void*)dm); } + inline void Assembler::FDIVRdm(const double* dm) { count_ldq(); FPUdm(0xdc07, dm); asm_output("fdivr (%p)", (void*)dm); } + + inline void Assembler::FCOMP() { count_fpu(); FPUc(0xD8D9); asm_output("fcomp"); fpu_pop();} + inline void Assembler::FCOMPP() { count_fpu(); FPUc(0xDED9); asm_output("fcompp"); fpu_pop();fpu_pop();} + inline void Assembler::FLDr(R r) { count_ldq(); FPU(0xd9c0, r); asm_output("fld %s", gpn(r)); fpu_push(); } + inline void Assembler::EMMS() { count_fpu(); FPUc(0x0f77); asm_output("emms"); } + + // standard direct call + inline void Assembler::CALL(const CallInfo* ci) { + count_call(); + underrunProtect(5); + int offset = (ci->_address) - ((int)_nIns); + IMM32((uint32_t)offset); + *(--_nIns) = 0xE8; + verbose_only(asm_output("call %s", (ci->_name));) + debug_only(if (ci->returnType()==ARGTYPE_D) fpu_push();) + } + + // indirect call thru register + inline void Assembler::CALLr(const CallInfo* ci, Register r) { + count_calli(); + underrunProtect(2); + ALU(0xff, 2, r); + verbose_only(asm_output("call %s", gpn(r));) + debug_only(if (ci->returnType()==ARGTYPE_D) fpu_push();) (void)ci; + } + + void Assembler::nInit(AvmCore*) + { + nHints[LIR_calli] = rmask(retRegs[0]); + nHints[LIR_calld] = rmask(FST0); + nHints[LIR_paramp] = PREFER_SPECIAL; + nHints[LIR_immi] = ScratchRegs; + // Nb: Doing this with a loop future-proofs against the possibilty of + // new comparison operations being added. + for (LOpcode op = LOpcode(0); op < LIR_sentinel; op = LOpcode(op+1)) + if (isCmpOpcode(op)) + nHints[op] = AllowableByteRegs; + } + + void Assembler::nBeginAssembly() { + max_stk_args = 0; + } + + NIns* Assembler::genPrologue() + { + // Prologue + uint32_t stackNeeded = max_stk_args + STACK_GRANULARITY * _activation.stackSlotsNeeded(); + + uint32_t stackPushed = + STACK_GRANULARITY + // returnaddr + STACK_GRANULARITY; // ebp + + uint32_t aligned = alignUp(stackNeeded + stackPushed, NJ_ALIGN_STACK); + uint32_t amt = aligned - stackPushed; + + // Reserve stackNeeded bytes, padded + // to preserve NJ_ALIGN_STACK-byte alignment. + if (amt) + { + SUBi(SP, amt); + } + + verbose_only( asm_output("[frag entry]"); ) + NIns *fragEntry = _nIns; + MR(FP, SP); // Establish our own FP. + PUSHr(FP); // Save caller's FP. + + return fragEntry; + } + + void Assembler::nFragExit(LIns* guard) + { + SideExit *exit = guard->record()->exit; + Fragment *frag = exit->target; + GuardRecord *lr = 0; + bool destKnown = (frag && frag->fragEntry); + + // Generate jump to epilog and initialize lr. + // If the guard is LIR_xtbl, use a jump table with epilog in every entry + if (guard->isop(LIR_xtbl)) { + lr = guard->record(); + Register r = rEDX; + SwitchInfo* si = guard->record()->exit->switchInfo; + if (!_epilogue) + _epilogue = genEpilogue(); + emitJumpTable(si, _epilogue); + JMP_indirect(r); + LEAmi4(r, int32_t(si->table), r); + } else { + // If the guard already exists, use a simple jump. + if (destKnown) { + JMP(frag->fragEntry); + lr = 0; + } else { // Target doesn't exist. Jump to an epilogue for now. This can be patched later. + if (!_epilogue) + _epilogue = genEpilogue(); + lr = guard->record(); + JMP_long(_epilogue); + lr->jmp = _nIns; + } + } + + // profiling for the exit + verbose_only( + if (_logc->lcbits & LC_FragProfile) { + INCLi(int32_t(&guard->record()->profCount)); + } + ) + + // Restore rESP from rEBP, undoing SUBi(SP,amt) in the prologue + MR(SP,FP); + + // return value is GuardRecord* + asm_immi(rEAX, int(lr), /*canClobberCCs*/true); + } + + NIns *Assembler::genEpilogue() + { + RET(); + POPr(FP); // Restore caller's FP. + + return _nIns; + } + + void Assembler::asm_call(LIns* ins) + { + if (!ins->isop(LIR_callv)) { + Register rr = ( ins->isop(LIR_calld) ? FST0 : retRegs[0] ); + prepareResultReg(ins, rmask(rr)); + evictScratchRegsExcept(rmask(rr)); + } else { + evictScratchRegsExcept(0); + } + const CallInfo* call = ins->callInfo(); + // must be signed, not unsigned + uint32_t iargs = call->count_int32_args(); + int32_t fargs = call->count_args() - iargs; + + bool indirect = call->isIndirect(); + if (indirect) { + // target arg isn't pushed, its consumed in the call + iargs --; + } + + AbiKind abi = call->_abi; + uint32_t max_regs = max_abi_regs[abi]; + if (max_regs > iargs) + max_regs = iargs; + + int32_t istack = iargs-max_regs; // first 2 4B args are in registers + int32_t extra = 0; + const int32_t pushsize = 4*istack + 8*fargs; // actual stack space used + +#if _MSC_VER + // msc only provides 4-byte alignment but we have 8 byte stack adjustment + // logic so maintain our 8 byte alignment. + uint32_t align = 8; +#else + uint32_t align = NJ_ALIGN_STACK; +#endif + + if (pushsize) { + if (_config.i386_fixed_esp) { + // In case of fastcall, stdcall and thiscall the callee cleans up the stack, + // and since we reserve max_stk_args words in the prolog to call functions + // and don't adjust the stack pointer individually for each call we have + // to undo here any changes the callee just did to the stack. + if (abi != ABI_CDECL) + SUBi(SP, pushsize); + } else { + // stack re-alignment + // only pop our adjustment amount since callee pops args in FASTCALL mode + extra = alignUp(pushsize, align) - pushsize; + if (call->_abi == ABI_CDECL) { + // with CDECL only, caller pops args + ADDi(SP, extra+pushsize); + } else if (extra > 0) { + ADDi(SP, extra); + } + } + } + + NanoAssert(ins->isop(LIR_callv) || ins->isop(LIR_callp) || ins->isop(LIR_calld)); + if (!indirect) { + CALL(call); + } + else { + // Indirect call. x86 Calling conventions don't use rEAX as an + // argument, and do use rEAX as a return value. We need a register + // for the address to call, so we use rEAX since it will always be + // available. + CALLr(call, rEAX); + } + + // Call this now so that the arg setup can involve 'rr'. + freeResourcesOf(ins); + + // Make sure fpu stack is empty before call. + NanoAssert(_allocator.isFree(FST0)); + + // Pre-assign registers to the first N 4B args based on the calling convention. + uint32_t n = 0; + + ArgType argTypes[MAXARGS]; + uint32_t argc = call->getArgTypes(argTypes); + int32_t stkd = 0; + + if (indirect) { + argc--; + asm_arg(ARGTYPE_P, ins->arg(argc), rEAX, stkd); + if (!_config.i386_fixed_esp) + stkd = 0; + } + + for (uint32_t i = 0; i < argc; i++) + { + uint32_t j = argc-i-1; + ArgType ty = argTypes[j]; + Register r = UnspecifiedReg; + if (n < max_regs && ty != ARGTYPE_D) { + r = argRegs[n++]; // tell asm_arg what reg to use + } + asm_arg(ty, ins->arg(j), r, stkd); + if (!_config.i386_fixed_esp) + stkd = 0; + } + + if (_config.i386_fixed_esp) { + if (pushsize > max_stk_args) + max_stk_args = pushsize; + } else if (extra > 0) { + SUBi(SP, extra); + } + } + + Register Assembler::nRegisterAllocFromSet(RegisterMask set) + { + Register r; + RegAlloc ®s = _allocator; + #ifdef _MSC_VER + _asm + { + mov ecx, regs + bsf eax, set // i = first bit set + btr RegAlloc::free[ecx], eax // free &= ~rmask(i) + mov r, eax + } + #else + asm( + "bsf %1, %%eax\n\t" + "btr %%eax, %2\n\t" + "movl %%eax, %0\n\t" + : "=m"(r) : "m"(set), "m"(regs.free) : "%eax", "memory" ); + #endif /* _MSC_VER */ + return r; + } + + void Assembler::nRegisterResetAll(RegAlloc& a) + { + // add scratch registers to our free list for the allocator + a.clear(); + a.free = SavedRegs | ScratchRegs; + if (!_config.i386_sse2) + a.free &= ~XmmRegs; + } + + void Assembler::nPatchBranch(NIns* branch, NIns* targ) + { + intptr_t offset = intptr_t(targ) - intptr_t(branch); + if (branch[0] == JMP32) { + *(int32_t*)&branch[1] = offset - 5; + } else if (branch[0] == JCC32) { + *(int32_t*)&branch[2] = offset - 6; + } else + NanoAssertMsg(0, "Unknown branch type in nPatchBranch"); + } + + RegisterMask Assembler::nHint(LIns* ins) + { + NanoAssert(ins->isop(LIR_paramp)); + RegisterMask prefer = 0; + uint8_t arg = ins->paramArg(); + if (ins->paramKind() == 0) { + uint32_t max_regs = max_abi_regs[_thisfrag->lirbuf->abi]; + if (arg < max_regs) + prefer = rmask(argRegs[arg]); + } else { + if (arg < NumSavedRegs) + prefer = rmask(savedRegs[arg]); + } + return prefer; + } + + // Return true if we can generate code for this instruction that neither + // sets CCs nor clobbers any input register. + // LEA is the only native instruction that fits those requirements. + bool canRematLEA(LIns* ins) + { + if (ins->isop(LIR_addi)) + return ins->oprnd1()->isInReg() && ins->oprnd2()->isImmI(); + // Subtract and some left-shifts could be rematerialized using LEA, + // but it hasn't shown to help in real code yet. Noting them anyway: + // maybe sub? R = subl rL, const => leal R, [rL + -const] + // maybe lsh? R = lshl rL, 1/2/3 => leal R, [rL * 2/4/8] + return false; + } + + bool Assembler::canRemat(LIns* ins) + { + return ins->isImmAny() || ins->isop(LIR_allocp) || canRematLEA(ins); + } + + // WARNING: the code generated by this function must not affect the + // condition codes. See asm_cmpi(). + void Assembler::asm_restore(LIns* ins, Register r) + { + NanoAssert(ins->getReg() == r); + + uint32_t arg; + uint32_t abi_regcount; + if (ins->isop(LIR_allocp)) { + // The value of a LIR_allocp instruction is the address of the + // stack allocation. We can rematerialize that from the record we + // have of where the allocation lies in the stack. + NanoAssert(ins->isInAr()); // must have stack slots allocated + LEA(r, arDisp(ins), FP); + + } else if (ins->isImmI()) { + asm_immi(r, ins->immI(), /*canClobberCCs*/false); + + } else if (ins->isImmD()) { + asm_immd(r, ins->immDasQ(), ins->immD(), /*canClobberCCs*/false); + + } else if (ins->isop(LIR_paramp) && ins->paramKind() == 0 && + (arg = ins->paramArg()) >= (abi_regcount = max_abi_regs[_thisfrag->lirbuf->abi])) { + // Incoming arg is on stack, can restore it from there instead of spilling. + + // this case is intentionally not detected in canRemat(), because we still + // emit a load instead of a fast ALU operation. We don't want parameter + // spills to have precedence over immediates & ALU ops, but if one does + // spill, we want to load it directly from its stack area, saving a store + // in the prolog. + + // Compute position of argument relative to ebp. Higher argument + // numbers are at higher positive offsets. The first abi_regcount + // arguments are in registers, rest on stack. +8 accomodates the + // return address and saved ebp value. Assuming abi_regcount == 0: + // + // low-addr ebp + // [frame...][saved-ebp][return-addr][arg0][arg1]... + // + int d = (arg - abi_regcount) * sizeof(intptr_t) + 8; + LD(r, d, FP); + + } else if (canRematLEA(ins)) { + LEA(r, ins->oprnd2()->immI(), ins->oprnd1()->getReg()); + + } else { + int d = findMemFor(ins); + if (ins->isI()) { + NanoAssert(rmask(r) & GpRegs); + LD(r, d, FP); + } else { + NanoAssert(ins->isD()); + if (rmask(r) & XmmRegs) { + SSE_LDQ(r, d, FP); + } else { + NanoAssert(r == FST0); + FLDQ(d, FP); + } + } + } + } + + void Assembler::asm_store32(LOpcode op, LIns* value, int dr, LIns* base) + { + if (value->isImmI()) { + if (base->opcode() == LIR_addp) { + LIns* index; + int scale; + getBaseIndexScale(base, &base, &index, &scale); + + Register rb, ri; + getBaseReg2(GpRegs, index, ri, GpRegs, base, rb, dr); + + int c = value->immI(); + switch (op) { + case LIR_sti2c: ST8isib( dr, rb, ri, scale, c); break; + case LIR_sti2s: ST16isib(dr, rb, ri, scale, c); break; + case LIR_sti: STisib( dr, rb, ri, scale, c); break; + default: NanoAssert(0); break; + } + } else { + Register rb = getBaseReg(base, dr, GpRegs); + int c = value->immI(); + switch (op) { + case LIR_sti2c: ST8i( rb, dr, c); break; + case LIR_sti2s: ST16i(rb, dr, c); break; + case LIR_sti: STi( rb, dr, c); break; + default: NanoAssert(0); break; + } + } + + } else { + // Quirk of x86-32: reg must be a/b/c/d for single-byte stores. + const RegisterMask SrcRegs = (op == LIR_sti2c) ? AllowableByteRegs : GpRegs; + + Register rv, rb; + if (base->opcode() == LIR_addp) { + LIns* index; + int scale; + getBaseIndexScale(base, &base, &index, &scale); + + Register rb, ri, rv; + getBaseReg2(SrcRegs, value, rv, GpRegs, base, rb, dr); + ri = (index == value) ? rv + : (index == base) ? rb + : findRegFor(index, GpRegs & ~(rmask(rb)|rmask(rv))); + + switch (op) { + case LIR_sti2c: ST8sib( dr, rb, ri, scale, rv); break; + case LIR_sti2s: ST16sib(dr, rb, ri, scale, rv); break; + case LIR_sti: STsib( dr, rb, ri, scale, rv); break; + default: NanoAssert(0); break; + } + + } else { + if (base->isImmI()) { + // absolute address + rb = UnspecifiedReg; + dr += base->immI(); + rv = findRegFor(value, SrcRegs); + } else { + getBaseReg2(SrcRegs, value, rv, GpRegs, base, rb, dr); + } + switch (op) { + case LIR_sti2c: ST8( rb, dr, rv); break; + case LIR_sti2s: ST16(rb, dr, rv); break; + case LIR_sti: ST( rb, dr, rv); break; + default: NanoAssert(0); break; + } + } + } + } + + void Assembler::asm_spill(Register rr, int d, bool pop) + { + NanoAssert(d); + if (rmask(rr) & GpRegs) { + ST(FP, d, rr); + } else if (rmask(rr) & XmmRegs) { + SSE_STQ(d, FP, rr); + } else { + NanoAssert(rr == FST0); + FSTQ(pop, d, FP); + } + } + + void Assembler::asm_load64(LIns* ins) + { + LIns* base = ins->oprnd1(); + int d = ins->disp(); + + // There are two cases: + // - 'ins' is in FpRegs: load it. + // - otherwise: there's no point loading the value into a register + // because its only use will be to immediately spill it. Instead we + // do a memory-to-memory move from the load address directly to the + // spill slot. (There must be a spill slot assigned.) This is why + // we don't use prepareResultReg() here unlike most other places -- + // because it mandates bringing the value into a register. + // + if (ins->isInReg()) { + Register rr = prepareResultReg(ins, rmask(ins->getReg())); + + if (base->opcode() == LIR_addp && rmask(rr) & XmmRegs) { + LIns* index; + int scale; + getBaseIndexScale(base, &base, &index, &scale); + + // (**) We don't have the usual opportunity to clobber 'base' + // or 'ins' with the result because it has a different type. + Register rb, ri; + RegisterMask allow = GpRegs & ~rmask(rr); + getBaseReg2(allow, index, ri, allow, base, rb, d); + + switch (ins->opcode()) { + case LIR_ldd: SSE_LDQsib(rr, d, rb, ri, scale); break; + case LIR_ldf2d: SSE_CVTSS2SD(rr, rr); + SSE_LDSSsib(rr, d, rb, ri, scale); + SSE_XORPDr(rr, rr); break; + default: NanoAssert(0); break; + } + + } else { + // (**) We don't have the usual opportunity to clobber 'base' + // or 'ins' with the result because it has a different type. + Register rb = getBaseReg(base, d, GpRegs); + if (rmask(rr) & XmmRegs) { + switch (ins->opcode()) { + case LIR_ldd: SSE_LDQ(rr, d, rb); break; + case LIR_ldf2d: SSE_CVTSS2SD(rr, rr); + SSE_LDSS(rr, d, rb); + SSE_XORPDr(rr, rr); break; + default: NanoAssert(0); break; + } + } else { + NanoAssert(rr == FST0); + switch (ins->opcode()) { + case LIR_ldd: FLDQ(d, rb); break; + case LIR_ldf2d: FLD32(d, rb); break; + default: NanoAssert(0); break; + } + } + } + + } else { + Register rb = getBaseReg(base, d, GpRegs); + + NanoAssert(ins->isInAr()); + int dr = arDisp(ins); + + switch (ins->opcode()) { + case LIR_ldd: + // Don't use an fpu reg to simply load & store the value. + asm_mmq(FP, dr, rb, d); + break; + + case LIR_ldf2d: + // Need to use fpu to expand 32->64. + FSTPQ(dr, FP); + FLD32(d, rb); + break; + + default: + NanoAssert(0); + break; + } + } + + freeResourcesOf(ins); + // Nb: no need for a possible findSpecificRegForUnallocated() call + // here because of (**) above. + } + + void Assembler::asm_store64(LOpcode op, LIns* value, int d, LIns* base) + { + if (op == LIR_std2f) { + Register rb = getBaseReg(base, d, GpRegs); + bool pop = !value->isInReg(); + Register rv = ( pop + ? findRegFor(value, _config.i386_sse2 ? XmmRegs : FpRegs) + : value->getReg() ); + + if (rmask(rv) & XmmRegs) { + // need a scratch reg + Register rt = registerAllocTmp(XmmRegs); + + // cvt to single-precision and store + SSE_STSS(d, rb, rt); + SSE_CVTSD2SS(rt, rv); + SSE_XORPDr(rt, rt); // zero dest to ensure no dependency stalls + + } else { + FST32(pop, d, rb); + } + + } else if (value->isImmD()) { + Register rb = getBaseReg(base, d, GpRegs); + STi(rb, d+4, value->immDhi()); + STi(rb, d, value->immDlo()); + + } else if (base->opcode() == LIR_addp && _config.i386_sse2) { + LIns* index; + int scale; + getBaseIndexScale(base, &base, &index, &scale); + + Register rb, ri; + getBaseReg2(GpRegs, index, ri, GpRegs, base, rb, d); + + Register rv = value->isInReg() ? value->getReg() : findRegFor(value, XmmRegs); + NanoAssert(rmask(rv) & XmmRegs); + SSE_STQsib(d, rb, ri, scale, rv); + + } else if (value->isop(LIR_ldd) && !_config.i386_sse2) { + // 'value' may be live in an FPU reg. Either way, don't put it on + // the FPU stack just to load & store it. + Register rb = getBaseReg(base, d, GpRegs); + int da = findMemFor(value); + asm_mmq(rb, d, FP, da); + + } else { + Register rb = getBaseReg(base, d, GpRegs); + bool pop = !value->isInReg(); + Register rv = ( pop + ? findRegFor(value, _config.i386_sse2 ? XmmRegs : FpRegs) + : value->getReg() ); + if (rmask(rv) & XmmRegs) + SSE_STQ(d, rb, rv); + else + FSTQ(pop, d, rb); + } + } + + // Copy 64 bits: (rd+dd) <- (rs+ds). + // + void Assembler::asm_mmq(Register rd, int dd, Register rs, int ds) + { + // Value is either a 64-bit struct or maybe a float that isn't live in + // an FPU reg. Either way, avoid allocating an FPU reg just to load + // and store it. + if (_config.i386_sse2) { + Register t = registerAllocTmp(XmmRegs); + SSE_STQ(dd, rd, t); + SSE_LDQ(t, ds, rs); + } else { + // We avoid copying via the FP stack because it's slow and likely + // to cause spills. + Register t = registerAllocTmp(GpRegs & ~(rmask(rd)|rmask(rs))); + ST(rd, dd+4, t); + LD(t, ds+4, rs); + ST(rd, dd, t); + LD(t, ds, rs); + } + } + + NIns* Assembler::asm_branch_helper(bool branchOnFalse, LIns* cond, NIns* targ) + { + return isCmpDOpcode(cond->opcode()) + ? asm_branchd_helper(branchOnFalse, cond, targ) + : asm_branchi_helper(branchOnFalse, cond, targ); + } + + NIns* Assembler::asm_branchi_helper(bool branchOnFalse, LIns* cond, NIns* targ) + { + if (branchOnFalse) { + // op == LIR_xf/LIR_jf + switch (cond->opcode()) { + case LIR_eqi: JNE(targ); break; + case LIR_lti: JNL(targ); break; + case LIR_lei: JNLE(targ); break; + case LIR_gti: JNG(targ); break; + case LIR_gei: JNGE(targ); break; + case LIR_ltui: JNB(targ); break; + case LIR_leui: JNBE(targ); break; + case LIR_gtui: JNA(targ); break; + case LIR_geui: JNAE(targ); break; + default: NanoAssert(0); break; + } + } else { + // op == LIR_xt/LIR_jt + switch (cond->opcode()) { + case LIR_eqi: JE(targ); break; + case LIR_lti: JL(targ); break; + case LIR_lei: JLE(targ); break; + case LIR_gti: JG(targ); break; + case LIR_gei: JGE(targ); break; + case LIR_ltui: JB(targ); break; + case LIR_leui: JBE(targ); break; + case LIR_gtui: JA(targ); break; + case LIR_geui: JAE(targ); break; + default: NanoAssert(0); break; + } + } + return _nIns; + } + + NIns* Assembler::asm_branch(bool branchOnFalse, LIns* cond, NIns* targ) + { + NIns* at = asm_branch_helper(branchOnFalse, cond, targ); + asm_cmp(cond); + return at; + } + + NIns* Assembler::asm_branch_ov(LOpcode, NIns* target) + { + JO(target); + return _nIns; + } + + void Assembler::asm_switch(LIns* ins, NIns* exit) + { + LIns* diff = ins->oprnd1(); + findSpecificRegFor(diff, rEDX); + JMP(exit); + } + + void Assembler::asm_jtbl(LIns* ins, NIns** table) + { + Register indexreg = findRegFor(ins->oprnd1(), GpRegs); + JMP_indexed(indexreg, 2, table); + } + + void Assembler::asm_cmp(LIns *cond) + { + isCmpDOpcode(cond->opcode()) ? asm_cmpd(cond) : asm_cmpi(cond); + } + + // This generates a 'test' or 'cmp' instruction for a condition, which + // causes the condition codes to be set appropriately. It's used with + // conditional branches, conditional moves, and when generating + // conditional values. For example: + // + // LIR: eq1 = eq a, 0 + // LIR: xf1: xf eq1 -> ... + // asm: test edx, edx # generated by this function + // asm: je ... + // + // If this is the only use of eq1, then on entry 'cond' is *not* marked as + // used, and we do not allocate a register for it. That's because its + // result ends up in the condition codes rather than a normal register. + // This doesn't get recorded in the regstate and so the asm code that + // consumes the result (eg. a conditional branch like 'je') must follow + // shortly after. + // + // If eq1 is instead used again later, we will also generate code + // (eg. in asm_cond()) to compute it into a normal register, something + // like this: + // + // LIR: eq1 = eq a, 0 + // LIR: test edx, edx + // asm: sete ebx + // asm: movzx ebx, ebx + // + // In this case we end up computing the condition twice, but that's ok, as + // it's just as short as testing eq1's value in the code generated for the + // guard. + // + // WARNING: Because the condition code update is not recorded in the + // regstate, this function cannot generate any code that will affect the + // condition codes prior to the generation of the test/cmp, because any + // such code will be run after the test/cmp but before the instruction + // that consumes the condition code. And because this function calls + // findRegFor() before the test/cmp is generated, and findRegFor() calls + // asm_restore(), that means that asm_restore() cannot generate code which + // affects the condition codes. + // + void Assembler::asm_cmpi(LIns *cond) + { + LIns* lhs = cond->oprnd1(); + LIns* rhs = cond->oprnd2(); + + NanoAssert(lhs->isI() && rhs->isI()); + + // Ready to issue the compare. + if (rhs->isImmI()) { + int c = rhs->immI(); + // findRegFor() can call asm_restore() -- asm_restore() better not + // disturb the CCs! + Register r = findRegFor(lhs, GpRegs); + if (c == 0 && cond->isop(LIR_eqi)) { + bool canSkipTest = lhs->isop(LIR_andi) || lhs->isop(LIR_ori); + if (canSkipTest) { + // Setup a short-lived reader to do lookahead; does no + // optimisations but that should be good enough for this + // simple case, something like this: + // + // a = andi x, y # lhs + // eq1 = eq a, 0 # cond + // xt eq1 # currIns + // + // Note that we don't have to worry about lookahead + // hitting the start of the buffer, because read() will + // just return LIR_start repeatedly in that case. + // + LirReader lookahead(currIns); + canSkipTest = currIns == lookahead.read() && + cond == lookahead.read() && + lhs == lookahead.read(); + } + if (canSkipTest) { + // Do nothing. At run-time, 'lhs' will have just computed + // by an i386 instruction that sets ZF for us ('and' or + // 'or'), so we don't have to do it ourselves. + } else { + TEST(r, r); // sets ZF according to the value of 'lhs' + } + } else { + CMPi(r, c); + } + } else { + Register ra, rb; + findRegFor2(GpRegs, lhs, ra, GpRegs, rhs, rb); + CMP(ra, rb); + } + } + + void Assembler::asm_condd(LIns* ins) + { + LOpcode opcode = ins->opcode(); + Register r = prepareResultReg(ins, AllowableByteRegs); + + // SETcc only sets low 8 bits, so extend + MOVZX8(r,r); + + if (_config.i386_sse2) { + // LIR_ltd and LIR_gtd are handled by the same case because + // asm_cmpd() converts LIR_ltd(a,b) to LIR_gtd(b,a). Likewise + // for LIR_led/LIR_ged. + switch (opcode) { + case LIR_eqd: + if (ins->oprnd1() == ins->oprnd2()) { + SETNP(r); + } else { + // result = ZF & !PF, must do logic on flags + AND8R(r); // and rl,rh rl &= rh + SETNPH(r); // setnp rh rh = !PF + SETE(r); // sete rl rl = ZF + } + break; + case LIR_ltd: + case LIR_gtd: SETA(r); break; + case LIR_led: + case LIR_ged: SETAE(r); break; + default: NanoAssert(0); break; + } + } else { + SETNP(r); + } + + freeResourcesOf(ins); + + asm_cmpd(ins); + } + + void Assembler::asm_cond(LIns* ins) + { + LOpcode op = ins->opcode(); + + Register r = prepareResultReg(ins, AllowableByteRegs); + + // SETcc only sets low 8 bits, so extend + MOVZX8(r,r); + switch (op) { + case LIR_eqi: SETE(r); break; + case LIR_lti: SETL(r); break; + case LIR_lei: SETLE(r); break; + case LIR_gti: SETG(r); break; + case LIR_gei: SETGE(r); break; + case LIR_ltui: SETB(r); break; + case LIR_leui: SETBE(r); break; + case LIR_gtui: SETA(r); break; + case LIR_geui: SETAE(r); break; + default: NanoAssert(0); break; + } + + freeResourcesOf(ins); + + asm_cmpi(ins); + } + + // Two example cases for "ins = add lhs, rhs". '*' lines are those + // generated in this function. + // + // asm: define lhs into rr + // asm: define rhs into rb + // ... + // * asm: add rr, rb + // * asm: spill rr if necessary + // ... no more uses of lhs in rr... + // + // asm: define lhs into ra + // asm: define rhs into rb + // ... + // * asm: mov rr, ra + // * asm: add rr, rb + // * asm: spill rr if necessary + // ... some uses of lhs in ra... + // + void Assembler::asm_arith(LIns* ins) + { + LOpcode op = ins->opcode(); + + // First special case. + if (op == LIR_modi) { + asm_div_mod(ins); + return; + } + + LIns* lhs = ins->oprnd1(); + LIns* rhs = ins->oprnd2(); + + // Second special case. + // XXX: bug 547125: don't need this once LEA is used for LIR_addi in all cases below + if (op == LIR_addi && lhs->isop(LIR_allocp) && rhs->isImmI()) { + // LIR_addi(LIR_allocp, LIR_immi) -- use lea. + Register rr = prepareResultReg(ins, GpRegs); + int d = findMemFor(lhs) + rhs->immI(); + + LEA(rr, d, FP); + + freeResourcesOf(ins); + + return; + } + + bool isConstRhs; + RegisterMask allow = GpRegs; + Register rb = UnspecifiedReg; + + switch (op) { + case LIR_divi: + // Nb: if the div feeds into a mod it will be handled by + // asm_div_mod() rather than here. + isConstRhs = false; + rb = findRegFor(rhs, (GpRegs & ~(rmask(rEAX)|rmask(rEDX)))); + allow = rmask(rEAX); + evictIfActive(rEDX); + break; + case LIR_muli: + case LIR_muljovi: + case LIR_mulxovi: + isConstRhs = false; + if (lhs != rhs) { + rb = findRegFor(rhs, allow); + allow &= ~rmask(rb); + } + break; + case LIR_lshi: + case LIR_rshi: + case LIR_rshui: + isConstRhs = rhs->isImmI(); + if (!isConstRhs) { + rb = findSpecificRegFor(rhs, rECX); + allow &= ~rmask(rb); + } + break; + default: + isConstRhs = rhs->isImmI(); + if (!isConstRhs && lhs != rhs) { + rb = findRegFor(rhs, allow); + allow &= ~rmask(rb); + } + break; + } + + // Somewhere for the result of 'ins'. + Register rr = prepareResultReg(ins, allow); + + // If 'lhs' isn't in a register, it can be clobbered by 'ins'. + Register ra = lhs->isInReg() ? lhs->getReg() : rr; + + if (!isConstRhs) { + if (lhs == rhs) + rb = ra; + + switch (op) { + case LIR_addi: + case LIR_addjovi: + case LIR_addxovi: ADD(rr, rb); break; // XXX: bug 547125: could use LEA for LIR_addi + case LIR_subi: + case LIR_subjovi: + case LIR_subxovi: SUB(rr, rb); break; + case LIR_muli: + case LIR_muljovi: + case LIR_mulxovi: IMUL(rr, rb); break; + case LIR_andi: AND(rr, rb); break; + case LIR_ori: OR( rr, rb); break; + case LIR_xori: XOR(rr, rb); break; + case LIR_lshi: SHL(rr, rb); break; + case LIR_rshi: SAR(rr, rb); break; + case LIR_rshui: SHR(rr, rb); break; + case LIR_divi: + DIV(rb); + CDQ(); // sign-extend rEAX into rEDX:rEAX + break; + default: NanoAssert(0); break; + } + + } else { + int c = rhs->immI(); + switch (op) { + case LIR_addi: + // this doesn't set cc's, only use it when cc's not required. + LEA(rr, c, ra); + ra = rr; // suppress mov + break; + case LIR_addjovi: + case LIR_addxovi: ADDi(rr, c); break; + case LIR_subi: + case LIR_subjovi: + case LIR_subxovi: SUBi(rr, c); break; + case LIR_andi: ANDi(rr, c); break; + case LIR_ori: ORi( rr, c); break; + case LIR_xori: XORi(rr, c); break; + case LIR_lshi: SHLi(rr, c); break; + case LIR_rshi: SARi(rr, c); break; + case LIR_rshui: SHRi(rr, c); break; + default: NanoAssert(0); break; + } + } + + if (rr != ra) + MR(rr, ra); + + freeResourcesOf(ins); + if (!lhs->isInReg()) { + NanoAssert(ra == rr); + findSpecificRegForUnallocated(lhs, ra); + } + } + + // Generates code for a LIR_modi(LIR_divi(divL, divR)) sequence. + void Assembler::asm_div_mod(LIns* mod) + { + LIns* div = mod->oprnd1(); + + // LIR_modi expects the LIR_divi to be near (no interference from the register allocator). + NanoAssert(mod->isop(LIR_modi)); + NanoAssert(div->isop(LIR_divi)); + + LIns* divL = div->oprnd1(); + LIns* divR = div->oprnd2(); + + prepareResultReg(mod, rmask(rEDX)); + prepareResultReg(div, rmask(rEAX)); + + Register rDivR = findRegFor(divR, (GpRegs & ~(rmask(rEAX)|rmask(rEDX)))); + Register rDivL = divL->isInReg() ? divL->getReg() : rEAX; + + DIV(rDivR); + CDQ(); // sign-extend rEAX into rEDX:rEAX + if (rEAX != rDivL) + MR(rEAX, rDivL); + + freeResourcesOf(mod); + freeResourcesOf(div); + if (!divL->isInReg()) { + NanoAssert(rDivL == rEAX); + findSpecificRegForUnallocated(divL, rEAX); + } + } + + // Two example cases for "ins = neg lhs". Lines marked with '*' are + // generated in this function. + // + // asm: define lhs into rr + // ... + // * asm: neg rr + // * asm: spill rr if necessary + // ... no more uses of lhs in rr... + // + // + // asm: define lhs into ra + // ... + // * asm: mov rr, ra + // * asm: neg rr + // * asm: spill rr if necessary + // ... more uses of lhs in ra... + // + void Assembler::asm_neg_not(LIns* ins) + { + LIns* lhs = ins->oprnd1(); + + Register rr = prepareResultReg(ins, GpRegs); + + // If 'lhs' isn't in a register, it can be clobbered by 'ins'. + Register ra = lhs->isInReg() ? lhs->getReg() : rr; + + if (ins->isop(LIR_noti)) { + NOT(rr); + } else { + NanoAssert(ins->isop(LIR_negi)); + NEG(rr); + } + if (rr != ra) + MR(rr, ra); + + freeResourcesOf(ins); + if (!lhs->isInReg()) { + NanoAssert(ra == rr); + findSpecificRegForUnallocated(lhs, ra); + } + } + + void Assembler::asm_load32(LIns* ins) + { + LOpcode op = ins->opcode(); + LIns* base = ins->oprnd1(); + int32_t d = ins->disp(); + + Register rr = prepareResultReg(ins, GpRegs); + + if (base->isImmI()) { + intptr_t addr = base->immI(); + addr += d; + switch (op) { + case LIR_lduc2ui: LD8Zdm( rr, addr); break; + case LIR_ldc2i: LD8Sdm( rr, addr); break; + case LIR_ldus2ui: LD16Zdm(rr, addr); break; + case LIR_lds2i: LD16Sdm(rr, addr); break; + case LIR_ldi: LDdm( rr, addr); break; + default: NanoAssert(0); break; + } + + freeResourcesOf(ins); + + } else if (base->opcode() == LIR_addp) { + LIns* index; + int scale; + getBaseIndexScale(base, &base, &index, &scale); + + // If 'base' isn't in a register, it can be clobbered by 'ins'. + // Likewise for 'rhs', but we try it with 'base' first. + Register rb, ri; + // @todo -- If base and/or index is const, we could eliminate a register use. + if (!base->isInReg()) { + rb = rr; + ri = findRegFor(index, GpRegs & ~(rmask(rb))); + + } else { + rb = base->getReg(); + NanoAssert(rb != rr); + ri = index->isInReg() ? findRegFor(index, GpRegs & ~(rmask(rb))) : rr; + } + + switch (op) { + case LIR_lduc2ui: LD8Zsib( rr, d, rb, ri, scale); break; + case LIR_ldc2i: LD8Ssib( rr, d, rb, ri, scale); break; + case LIR_ldus2ui: LD16Zsib(rr, d, rb, ri, scale); break; + case LIR_lds2i: LD16Ssib(rr, d, rb, ri, scale); break; + case LIR_ldi: LDsib( rr, d, rb, ri, scale); break; + default: NanoAssert(0); break; + } + + freeResourcesOf(ins); + if (!base->isInReg()) { + NanoAssert(rb == rr); + findSpecificRegForUnallocated(base, rb); + } else if (!index->isInReg()) { + NanoAssert(ri == rr); + findSpecificRegForUnallocated(index, ri); + } + + } else { + Register ra = getBaseReg(base, d, GpRegs); + + switch (op) { + case LIR_lduc2ui: LD8Z( rr, d, ra); break; + case LIR_ldc2i: LD8S( rr, d, ra); break; + case LIR_ldus2ui: LD16Z(rr, d, ra); break; + case LIR_lds2i: LD16S(rr, d, ra); break; + case LIR_ldi: LD( rr, d, ra); break; + default: NanoAssert(0); break; + } + + freeResourcesOf(ins); + if (!base->isop(LIR_allocp) && !base->isInReg()) { + NanoAssert(ra == rr); + findSpecificRegForUnallocated(base, ra); + } + } + } + + void Assembler::asm_cmov(LIns* ins) + { + LIns* condval = ins->oprnd1(); + LIns* iftrue = ins->oprnd2(); + LIns* iffalse = ins->oprnd3(); + + NanoAssert(condval->isCmp()); + NanoAssert((ins->isop(LIR_cmovi) && iftrue->isI() && iffalse->isI()) || + (ins->isop(LIR_cmovd) && iftrue->isD() && iffalse->isD())); + + if (!_config.i386_sse2 && ins->isop(LIR_cmovd)) { + // See the SSE2 case below for an explanation of the subtleties here. + debug_only( Register rr = ) prepareResultReg(ins, x87Regs); + NanoAssert(FST0 == rr); + NanoAssert(!iftrue->isInReg() && !iffalse->isInReg()); + + NIns* target = _nIns; + + if (iffalse->isImmD()) { + asm_immd(FST0, iffalse->immDasQ(), iffalse->immD(), /*canClobberCCs*/false); + } else { + int df = findMemFor(iffalse); + FLDQ(df, FP); + } + FSTP(FST0); // pop the stack + asm_branch_helper(false, condval, target); + + NanoAssert(ins->getReg() == rr); + freeResourcesOf(ins); + if (!iftrue->isInReg()) + findSpecificRegForUnallocated(iftrue, FST0); + + asm_cmp(condval); + + return; + } + + RegisterMask allow = ins->isD() ? XmmRegs : GpRegs; + Register rr = prepareResultReg(ins, allow); + Register rf = findRegFor(iffalse, allow & ~rmask(rr)); + + if (ins->isop(LIR_cmovd)) { + // The obvious way to handle this is as follows: + // + // mov rr, rt # only needed if rt is live afterwards + // do comparison + // jt end + // mov rr, rf + // end: + // + // The problem with this is that doing the comparison can cause + // registers to be evicted, possibly including 'rr', which holds + // 'ins'. And that screws things up. So instead we do this: + // + // do comparison + // mov rr, rt # only needed if rt is live afterwards + // jt end + // mov rr, rf + // end: + // + // Putting the 'mov' between the comparison and the jump is ok + // because move instructions don't modify the condition codes. + // + NIns* target = _nIns; + asm_nongp_copy(rr, rf); + asm_branch_helper(false, condval, target); + + // If 'iftrue' isn't in a register, it can be clobbered by 'ins'. + Register rt = iftrue->isInReg() ? iftrue->getReg() : rr; + + if (rr != rt) + asm_nongp_copy(rr, rt); + + NanoAssert(ins->getReg() == rr); + freeResourcesOf(ins); + if (!iftrue->isInReg()) { + NanoAssert(rt == rr); + findSpecificRegForUnallocated(iftrue, rr); + } + + asm_cmp(condval); + return; + } + + // If 'iftrue' isn't in a register, it can be clobbered by 'ins'. + Register rt = iftrue->isInReg() ? iftrue->getReg() : rr; + NanoAssert(ins->isop(LIR_cmovi)); + + // WARNING: We cannot generate any code that affects the condition + // codes between the MRcc generation here and the asm_cmpi() call + // below. See asm_cmpi() for more details. + switch (condval->opcode()) { + // Note that these are all opposites... + case LIR_eqi: MRNE(rr, rf); break; + case LIR_lti: MRGE(rr, rf); break; + case LIR_lei: MRG( rr, rf); break; + case LIR_gti: MRLE(rr, rf); break; + case LIR_gei: MRL( rr, rf); break; + case LIR_ltui: MRAE(rr, rf); break; + case LIR_leui: MRA( rr, rf); break; + case LIR_gtui: MRBE(rr, rf); break; + case LIR_geui: MRB( rr, rf); break; + default: NanoAssert(0); break; + } + + if (rr != rt) + MR(rr, rt); + + NanoAssert(ins->getReg() == rr); + freeResourcesOf(ins); + if (!iftrue->isInReg()) { + NanoAssert(rt == rr); + findSpecificRegForUnallocated(iftrue, rr); + } + + asm_cmp(condval); + } + + void Assembler::asm_param(LIns* ins) + { + uint32_t arg = ins->paramArg(); + uint32_t kind = ins->paramKind(); + if (kind == 0) { + // ordinary param + AbiKind abi = _thisfrag->lirbuf->abi; + uint32_t abi_regcount = max_abi_regs[abi]; + // argRegs must have as many elements as the largest argument register + // requirement of an abi. Currently, this is 2, for ABI_FASTCALL. See + // the definition of max_abi_regs earlier in this file. The following + // assertion reflects this invariant: + NanoAssert(abi_regcount <= sizeof(argRegs)/sizeof(argRegs[0])); + if (arg < abi_regcount) { + // Incoming arg in register. + prepareResultReg(ins, rmask(argRegs[arg])); + // No code to generate. + } else { + // Incoming arg is on stack, and rEBP points nearby (see genPrologue()). + Register r = prepareResultReg(ins, GpRegs); + int d = (arg - abi_regcount) * sizeof(intptr_t) + 8; + LD(r, d, FP); + } + } else { + // Saved param. + prepareResultReg(ins, rmask(savedRegs[arg])); + // No code to generate. + } + freeResourcesOf(ins); + } + + void Assembler::asm_immi(LIns* ins) + { + Register rr = prepareResultReg(ins, GpRegs); + + asm_immi(rr, ins->immI(), /*canClobberCCs*/true); + + freeResourcesOf(ins); + } + + void Assembler::asm_immi(Register r, int32_t val, bool canClobberCCs) + { + if (val == 0 && canClobberCCs) + XOR(r, r); + else + LDi(r, val); + } + + void Assembler::asm_immd(Register r, uint64_t q, double d, bool canClobberCCs) + { + // Floats require non-standard handling. There is no load-64-bit-immediate + // instruction on i386, so in the general case, we must load it from memory. + // This is unlike most other LIR operations which can be computed directly + // in a register. We can special-case 0.0 and various other small ints + // (1.0 on x87, any int32_t value on SSE2), but for all other values, we + // allocate an 8-byte chunk via dataAlloc and load from there. Note that + // this implies that floats never require spill area, since they will always + // be rematerialized from const data (or inline instructions in the special cases). + + if (rmask(r) & XmmRegs) { + if (q == 0) { + // test (int64)0 since -0.0 == 0.0 + SSE_XORPDr(r, r); + } else if (d && d == (int)d && canClobberCCs) { + // can fit in 32bits? then use cvt which is faster + Register tr = registerAllocTmp(GpRegs); + SSE_CVTSI2SD(r, tr); + SSE_XORPDr(r, r); // zero r to ensure no dependency stalls + asm_immi(tr, (int)d, canClobberCCs); + } else { + const uint64_t* p = findImmDFromPool(q); + LDSDm(r, (const double*)p); + } + } else { + NanoAssert(r == FST0); + if (q == 0) { + // test (int64)0 since -0.0 == 0.0 + FLDZ(); + } else if (d == 1.0) { + FLD1(); + } else { + const uint64_t* p = findImmDFromPool(q); + FLDQdm((const double*)p); + } + } + } + + void Assembler::asm_immd(LIns* ins) + { + NanoAssert(ins->isImmD()); + if (ins->isInReg()) { + Register rr = ins->getReg(); + NanoAssert(rmask(rr) & FpRegs); + asm_immd(rr, ins->immDasQ(), ins->immD(), /*canClobberCCs*/true); + } else { + // Do nothing, will be rematerialized when necessary. + } + + freeResourcesOf(ins); + } + + // negateMask is used by asm_fneg. +#if defined __SUNPRO_CC + // From Sun Studio C++ Readme: #pragma align inside namespace requires mangled names. + // Initialize here to avoid multithreading contention issues during initialization. + static uint32_t negateMask_temp[] = {0, 0, 0, 0, 0, 0, 0}; + + static uint32_t* negateMaskInit() + { + uint32_t* negateMask = (uint32_t*)alignUp(negateMask_temp, 16); + negateMask[1] = 0x80000000; + return negateMask; + } + + static uint32_t *negateMask = negateMaskInit(); +#else + static const AVMPLUS_ALIGN16(uint32_t) negateMask[] = {0,0x80000000,0,0}; +#endif + + void Assembler::asm_fneg(LIns* ins) + { + LIns *lhs = ins->oprnd1(); + + if (_config.i386_sse2) { + Register rr = prepareResultReg(ins, XmmRegs); + + // If 'lhs' isn't in a register, it can be clobbered by 'ins'. + Register ra; + if (!lhs->isInReg()) { + ra = rr; + } else if (!(rmask(lhs->getReg()) & XmmRegs)) { + // We need to evict lhs from x87Regs, which then puts us in + // the same situation as the !isInReg() case. + evict(lhs); + ra = rr; + } else { + ra = lhs->getReg(); + } + + SSE_XORPD(rr, negateMask); + + if (rr != ra) + SSE_MOVSD(rr, ra); + + freeResourcesOf(ins); + if (!lhs->isInReg()) { + NanoAssert(ra == rr); + findSpecificRegForUnallocated(lhs, ra); + } + + } else { + debug_only( Register rr = ) prepareResultReg(ins, x87Regs); + NanoAssert(FST0 == rr); + + NanoAssert(!lhs->isInReg() || FST0 == lhs->getReg()); + + FCHS(); + + freeResourcesOf(ins); + if (!lhs->isInReg()) + findSpecificRegForUnallocated(lhs, FST0); + } + } + + void Assembler::asm_arg(ArgType ty, LIns* ins, Register r, int32_t& stkd) + { + // If 'r' is known, then that's the register we have to put 'ins' + // into. + + if (ty == ARGTYPE_I || ty == ARGTYPE_UI) { + if (r != UnspecifiedReg) { + if (ins->isImmI()) { + // Rematerialize the constant. + asm_immi(r, ins->immI(), /*canClobberCCs*/true); + } else if (ins->isInReg()) { + if (r != ins->getReg()) + MR(r, ins->getReg()); + } else if (ins->isInAr()) { + int d = arDisp(ins); + NanoAssert(d != 0); + if (ins->isop(LIR_allocp)) { + LEA(r, d, FP); + } else { + LD(r, d, FP); + } + + } else { + // This is the last use, so fine to assign it + // to the scratch reg, it's dead after this point. + findSpecificRegForUnallocated(ins, r); + } + } + else { + if (_config.i386_fixed_esp) + asm_stkarg(ins, stkd); + else + asm_pusharg(ins); + } + + } else { + NanoAssert(ty == ARGTYPE_D); + asm_farg(ins, stkd); + } + } + + void Assembler::asm_pusharg(LIns* ins) + { + // arg goes on stack + if (!ins->isExtant() && ins->isImmI()) + { + PUSHi(ins->immI()); // small const we push directly + } + else if (!ins->isExtant() || ins->isop(LIR_allocp)) + { + Register ra = findRegFor(ins, GpRegs); + PUSHr(ra); + } + else if (ins->isInReg()) + { + PUSHr(ins->getReg()); + } + else + { + NanoAssert(ins->isInAr()); + PUSHm(arDisp(ins), FP); + } + } + + void Assembler::asm_stkarg(LIns* ins, int32_t& stkd) + { + // arg goes on stack + if (!ins->isExtant() && ins->isImmI()) + { + // small const we push directly + STi(SP, stkd, ins->immI()); + } + else { + Register ra; + if (!ins->isInReg() || ins->isop(LIR_allocp)) + ra = findRegFor(ins, GpRegs & (~SavedRegs)); + else + ra = ins->getReg(); + ST(SP, stkd, ra); + } + + stkd += sizeof(int32_t); + } + + void Assembler::asm_farg(LIns* ins, int32_t& stkd) + { + NanoAssert(ins->isD()); + Register r = findRegFor(ins, FpRegs); + if (rmask(r) & XmmRegs) { + SSE_STQ(stkd, SP, r); + } else { + FSTPQ(stkd, SP); + + // 22Jul09 rickr - Enabling the evict causes a 10% slowdown on primes + // + // evict() triggers a very expensive fstpq/fldq pair around the store. + // We need to resolve the bug some other way. + // + // see https://bugzilla.mozilla.org/show_bug.cgi?id=491084 + + // It's possible that the same LIns* with r=FST0 will appear in the argument list more + // than once. In this case FST0 will not have been evicted and the multiple pop + // actions will unbalance the FPU stack. A quick fix is to always evict FST0 manually. + NanoAssert(r == FST0); + NanoAssert(ins == _allocator.getActive(r)); + evict(ins); + } + if (!_config.i386_fixed_esp) + SUBi(rESP, 8); + + stkd += sizeof(double); + } + + void Assembler::asm_fop(LIns* ins) + { + LOpcode op = ins->opcode(); + if (_config.i386_sse2) + { + LIns *lhs = ins->oprnd1(); + LIns *rhs = ins->oprnd2(); + + RegisterMask allow = XmmRegs; + Register rb = UnspecifiedReg; + if (lhs != rhs) { + rb = findRegFor(rhs, allow); + allow &= ~rmask(rb); + } + + Register rr = prepareResultReg(ins, allow); + + // If 'lhs' isn't in a register, it can be clobbered by 'ins'. + Register ra; + if (!lhs->isInReg()) { + ra = rr; + + } else if (!(rmask(lhs->getReg()) & XmmRegs)) { + NanoAssert(lhs->getReg() == FST0); + + // We need to evict lhs from x87Regs, which then puts us in + // the same situation as the !isInReg() case. + evict(lhs); + ra = rr; + + } else { + ra = lhs->getReg(); + NanoAssert(rmask(ra) & XmmRegs); + } + + if (lhs == rhs) + rb = ra; + + switch (op) { + case LIR_addd: SSE_ADDSD(rr, rb); break; + case LIR_subd: SSE_SUBSD(rr, rb); break; + case LIR_muld: SSE_MULSD(rr, rb); break; + case LIR_divd: SSE_DIVSD(rr, rb); break; + default: NanoAssert(0); + } + + if (rr != ra) + SSE_MOVSD(rr, ra); + + freeResourcesOf(ins); + if (!lhs->isInReg()) { + NanoAssert(ra == rr); + findSpecificRegForUnallocated(lhs, ra); + } + } + else + { + // We swap lhs/rhs on purpose here, it works out better with + // only one fpu reg -- we can use divr/subr. + LIns* rhs = ins->oprnd1(); + LIns* lhs = ins->oprnd2(); + debug_only( Register rr = ) prepareResultReg(ins, rmask(FST0)); + NanoAssert(FST0 == rr); + NanoAssert(!lhs->isInReg() || FST0 == lhs->getReg()); + + if (rhs->isImmD()) { + const uint64_t* p = findImmDFromPool(rhs->immDasQ()); + + switch (op) { + case LIR_addd: FADDdm( (const double*)p); break; + case LIR_subd: FSUBRdm((const double*)p); break; + case LIR_muld: FMULdm( (const double*)p); break; + case LIR_divd: FDIVRdm((const double*)p); break; + default: NanoAssert(0); + } + + } else { + int db = findMemFor(rhs); + + switch (op) { + case LIR_addd: FADD( db, FP); break; + case LIR_subd: FSUBR(db, FP); break; + case LIR_muld: FMUL( db, FP); break; + case LIR_divd: FDIVR(db, FP); break; + default: NanoAssert(0); + } + } + freeResourcesOf(ins); + if (!lhs->isInReg()) { + findSpecificRegForUnallocated(lhs, FST0); + } + } + } + + void Assembler::asm_i2d(LIns* ins) + { + LIns* lhs = ins->oprnd1(); + + Register rr = prepareResultReg(ins, FpRegs); + if (rmask(rr) & XmmRegs) { + // todo support int value in memory + Register ra = findRegFor(lhs, GpRegs); + SSE_CVTSI2SD(rr, ra); + SSE_XORPDr(rr, rr); // zero rr to ensure no dependency stalls + } else { + int d = findMemFor(lhs); + FILD(d, FP); + } + + freeResourcesOf(ins); + } + + void Assembler::asm_ui2d(LIns* ins) + { + LIns* lhs = ins->oprnd1(); + + Register rr = prepareResultReg(ins, FpRegs); + if (rmask(rr) & XmmRegs) { + Register rt = registerAllocTmp(GpRegs); + + // Technique inspired by gcc disassembly. Edwin explains it: + // + // rt is 0..2^32-1 + // + // sub rt,0x80000000 + // + // Now rt is -2^31..2^31-1, i.e. the range of int, but not the same value + // as before. + // + // cvtsi2sd rr,rt + // + // rr is now a double with the int value range. + // + // addsd rr, 2147483648.0 + // + // Adding back double(0x80000000) makes the range 0..2^32-1. + + static const double k_NEGONE = 2147483648.0; + SSE_ADDSDm(rr, &k_NEGONE); + + SSE_CVTSI2SD(rr, rt); + SSE_XORPDr(rr, rr); // zero rr to ensure no dependency stalls + + if (lhs->isInRegMask(GpRegs)) { + Register ra = lhs->getReg(); + LEA(rt, 0x80000000, ra); + + } else { + const int d = findMemFor(lhs); + SUBi(rt, 0x80000000); + LD(rt, d, FP); + } + + } else { + // Use space just below rESP and use PUSH to avoid writing + // past the end of the stack, see bug 590553. + Register ra = findRegFor(lhs, GpRegs); + NanoAssert(rr == FST0); + ADDi(SP, 8); // fix up the stack + FILDQ(0, SP); // convert int64 to double + PUSHr(ra); // low 32 bits = unsigned value + PUSHi(0); // high 32 bits = 0 + } + + freeResourcesOf(ins); + } + + void Assembler::asm_d2i(LIns* ins) + { + LIns *lhs = ins->oprnd1(); + + if (_config.i386_sse2) { + Register rr = prepareResultReg(ins, GpRegs); + Register ra = findRegFor(lhs, XmmRegs); + SSE_CVTTSD2SI(rr, ra); + } else { + bool pop = !lhs->isInReg(); + findSpecificRegFor(lhs, FST0); + if (ins->isInReg()) + evict(ins); + int d = findMemFor(ins); + FIST(pop, d, FP); + } + + freeResourcesOf(ins); + } + + void Assembler::asm_nongp_copy(Register rd, Register rs) + { + if ((rmask(rd) & XmmRegs) && (rmask(rs) & XmmRegs)) { + // xmm -> xmm + SSE_MOVSD(rd, rs); + } else if ((rmask(rd) & GpRegs) && (rmask(rs) & XmmRegs)) { + // xmm -> gp + SSE_MOVD(rd, rs); + } else { + NanoAssertMsgf(false, "bad asm_nongp_copy(%s, %s)", gpn(rd), gpn(rs)); + } + } + + NIns* Assembler::asm_branchd_helper(bool branchOnFalse, LIns* cond, NIns *targ) + { + NIns* at = 0; + LOpcode opcode = cond->opcode(); + + if (_config.i386_sse2) { + // LIR_ltd and LIR_gtd are handled by the same case because + // asm_cmpd() converts LIR_ltd(a,b) to LIR_gtd(b,a). Likewise + // for LIR_led/LIR_ged. + if (branchOnFalse) { + // op == LIR_xf + switch (opcode) { + case LIR_eqd: + if (cond->oprnd1() == cond->oprnd2()) { + JP(targ); + } else { + JP(targ); + JNE(targ); + } + break; + case LIR_ltd: + case LIR_gtd: JNA(targ); break; + case LIR_led: + case LIR_ged: JNAE(targ); break; + default: NanoAssert(0); break; + } + } else { + // op == LIR_xt + switch (opcode) { + case LIR_eqd: + if (cond->oprnd1() == cond->oprnd2()) { + JNP(targ); + } else { + // jp skip (2byte) + // je target + // skip: ... + underrunProtect(16); // underrun of 7 needed but we write 2 instr --> 16 + NIns *skip = _nIns; + JE(targ); + at = _nIns; + JP(skip); + } + break; + case LIR_ltd: + case LIR_gtd: JA(targ); break; + case LIR_led: + case LIR_ged: JAE(targ); break; + default: NanoAssert(0); break; + } + } + } else { + if (branchOnFalse) + JP(targ); + else + JNP(targ); + } + + if (!at) + at = _nIns; + + return at; + } + + // WARNING: This function cannot generate any code that will affect the + // condition codes prior to the generation of the + // ucomisd/fcompp/fcmop/fcom. See asm_cmpi() for more details. + void Assembler::asm_cmpd(LIns *cond) + { + LOpcode condop = cond->opcode(); + NanoAssert(isCmpDOpcode(condop)); + LIns* lhs = cond->oprnd1(); + LIns* rhs = cond->oprnd2(); + NanoAssert(lhs->isD() && rhs->isD()); + + if (_config.i386_sse2) { + // First, we convert (a < b) into (b > a), and (a <= b) into (b >= a). + if (condop == LIR_ltd) { + condop = LIR_gtd; + LIns* t = lhs; lhs = rhs; rhs = t; + } else if (condop == LIR_led) { + condop = LIR_ged; + LIns* t = lhs; lhs = rhs; rhs = t; + } + + // LIR_eqd, if lhs == rhs: + // ucomisd ZPC outcome (SETNP/JNP succeeds if P==0) + // ------- --- ------- + // UNORDERED 111 SETNP/JNP fails + // EQUAL 100 SETNP/JNP succeeds + // + // LIR_eqd, if lhs != rhs; + // ucomisd ZPC outcome (SETP/JP succeeds if P==0, + // SETE/JE succeeds if Z==0) + // ------- --- ------- + // UNORDERED 111 SETP/JP succeeds (and skips to fail target) + // EQUAL 100 SETP/JP fails, SETE/JE succeeds + // GREATER_THAN 000 SETP/JP fails, SETE/JE fails + // LESS_THAN 001 SETP/JP fails, SETE/JE fails + // + // LIR_gtd: + // ucomisd ZPC outcome (SETA/JA succeeds if CZ==00) + // ------- --- ------- + // UNORDERED 111 SETA/JA fails + // EQUAL 100 SETA/JA fails + // GREATER_THAN 000 SETA/JA succeeds + // LESS_THAN 001 SETA/JA fails + // + // LIR_ged: + // ucomisd ZPC outcome (SETAE/JAE succeeds if C==0) + // ------- --- ------- + // UNORDERED 111 SETAE/JAE fails + // EQUAL 100 SETAE/JAE succeeds + // GREATER_THAN 000 SETAE/JAE succeeds + // LESS_THAN 001 SETAE/JAE fails + + Register ra, rb; + findRegFor2(XmmRegs, lhs, ra, XmmRegs, rhs, rb); + SSE_UCOMISD(ra, rb); + + } else { + // First, we convert (a > b) into (b < a), and (a >= b) into (b <= a). + // Note that this is the opposite of the sse2 conversion above. + if (condop == LIR_gtd) { + condop = LIR_ltd; + LIns* t = lhs; lhs = rhs; rhs = t; + } else if (condop == LIR_ged) { + condop = LIR_led; + LIns* t = lhs; lhs = rhs; rhs = t; + } + + // FNSTSW_AX puts the flags into AH like so: B:C3:TOP3:TOP2:TOP1:C2:C1:C0. + // Furthermore, fcom/fcomp/fcompp sets C3:C2:C0 the same values + // that Z:P:C are set by ucomisd, and the relative positions in AH + // line up. (Someone at Intel has a sense of humour.) Therefore + // we can use the same lahf/test(mask) technique as used in the + // sse2 case above. We could use fcomi/fcomip/fcomipp which set + // ZPC directly and then use LAHF instead of FNSTSW_AX and make + // this code generally more like the sse2 code, but we don't + // because fcomi/fcomip/fcomipp/lahf aren't available on earlier + // x86 machines. + // + // The masks are as follows: + // - LIR_eqd: mask == 0x44 == 0100_0100b, which extracts 0Z00_0P00 from AH. + // - LIR_ltd: mask == 0x05 == 0000_0101b, which extracts 0000_0P0C from AH. + // - LIR_led: mask == 0x41 == 0100_0001b, which extracts 0Z00_000C from AH. + // + // LIR_eqd: + // ucomisd C3:C2:C0 lahf/test(0x44) SZP outcome + // ------- -------- --------- --- ------- + // UNORDERED 111 0100_0100 001 SETNP fails + // EQUAL 100 0100_0000 000 SETNP succeeds + // GREATER_THAN 000 0000_0000 011 SETNP fails + // LESS_THAN 001 0000_0000 011 SETNP fails + // + // LIR_ltd: + // fcom C3:C2:C0 lahf/test(0x05) SZP outcome + // ------- -------- --------- --- ------- + // UNORDERED 111 0000_0101 001 SETNP fails + // EQUAL 100 0000_0000 011 SETNP fails + // GREATER_THAN 000 0000_0000 011 SETNP fails + // LESS_THAN 001 0000_0001 000 SETNP succeeds + // + // LIR_led: + // fcom C3:C2:C0 lahf/test(0x41) SZP outcome + // ------- --- --------- --- ------- + // UNORDERED 111 0100_0001 001 SETNP fails + // EQUAL 100 0100_0000 000 SETNP succeeds + // GREATER_THAN 000 0000_0000 011 SETNP fails + // LESS_THAN 001 0000_0001 010 SETNP succeeds + + int mask = 0; // init to avoid MSVC compile warnings + switch (condop) { + case LIR_eqd: mask = 0x44; break; + case LIR_ltd: mask = 0x05; break; + case LIR_led: mask = 0x41; break; + default: NanoAssert(0); break; + } + + evictIfActive(rEAX); + bool pop = !lhs->isInReg(); + findSpecificRegFor(lhs, FST0); + + if (lhs == rhs) { + // NaN test. + TEST_AH(mask); + FNSTSW_AX(); // requires rEAX to be free + if (pop) + FCOMPP(); + else + FCOMP(); + FLDr(FST0); // DUP + } else { + TEST_AH(mask); + FNSTSW_AX(); // requires rEAX to be free + if (rhs->isImmD()) { + const uint64_t* p = findImmDFromPool(rhs->immDasQ()); + FCOMdm(pop, (const double*)p); + } else { + int d = findMemFor(rhs); + FCOM(pop, d, FP); + } + } + } + } + + // Increment the 32-bit profiling counter at pCtr, without + // changing any registers. + verbose_only( + void Assembler::asm_inc_m32(uint32_t* pCtr) + { + INCLi(int32_t(pCtr)); + } + ) + + void Assembler::nativePageReset() + {} + + void Assembler::nativePageSetup() + { + NanoAssert(!_inExit); + if (!_nIns) + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes)); + + // add some random padding, so functions aren't predictably placed. + if (_config.harden_function_alignment) + { + int32_t pad = _noise->getValue(LARGEST_UNDERRUN_PROT); + underrunProtect(pad); + _nIns -= pad; + VMPI_memset(_nIns, INT3_OP, pad); + PERFM_NVPROF("hardening:func-align", pad); + } + } + + // enough room for n bytes + void Assembler::underrunProtect(int n) + { + NIns *eip = _nIns; + NanoAssertMsg(n<=LARGEST_UNDERRUN_PROT, "constant LARGEST_UNDERRUN_PROT is too small"); + // This may be in a normal code chunk or an exit code chunk. + if (eip - n < codeStart) { + codeAlloc(codeStart, codeEnd, _nIns verbose_only(, codeBytes)); + JMP(eip); + } + } + + void Assembler::asm_insert_random_nop() + { + // one of a random nop instructions + uint32_t r = _noise->getValue(5); + switch(r) + { + case 0: MR(rEAX,rEAX); break; + case 1: MR(rEDI,rEDI); break; + case 2: MR(rECX,rECX); break; + case 3: LEA(rECX,0,rECX); break; + case 4: LEA(rESP,0,rESP); break; + } + } + + void Assembler::asm_ret(LIns* ins) + { + genEpilogue(); + + // Restore rESP from rEBP, undoing SUBi(SP,amt) in the prologue + MR(SP,FP); + + releaseRegisters(); + assignSavedRegs(); + + LIns *val = ins->oprnd1(); + if (ins->isop(LIR_reti)) { + findSpecificRegFor(val, retRegs[0]); + } else { + NanoAssert(ins->isop(LIR_retd)); + findSpecificRegFor(val, FST0); + fpu_pop(); + } + } + + void Assembler::swapCodeChunks() { + if (!_nExitIns) + codeAlloc(exitStart, exitEnd, _nExitIns verbose_only(, exitBytes)); + SWAP(NIns*, _nIns, _nExitIns); + SWAP(NIns*, codeStart, exitStart); + SWAP(NIns*, codeEnd, exitEnd); + verbose_only( SWAP(size_t, codeBytes, exitBytes); ) + } + + #endif /* FEATURE_NANOJIT */ +} diff --git a/js/src/nanojit/Nativei386.h b/js/src/nanojit/Nativei386.h new file mode 100644 index 0000000..a88dbf1 --- /dev/null +++ b/js/src/nanojit/Nativei386.h @@ -0,0 +1,472 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#ifndef __nanojit_Nativei386__ +#define __nanojit_Nativei386__ + +#include "NativeCommon.h" + +#ifdef PERFM +#define DOPROF +#include "../vprof/vprof.h" +#define count_instr() _nvprof("x86",1) +#define count_ret() _nvprof("x86-ret",1); count_instr(); +#define count_push() _nvprof("x86-push",1); count_instr(); +#define count_pop() _nvprof("x86-pop",1); count_instr(); +#define count_st() _nvprof("x86-st",1); count_instr(); +#define count_stq() _nvprof("x86-stq",1); count_instr(); +#define count_ld() _nvprof("x86-ld",1); count_instr(); +#define count_ldq() _nvprof("x86-ldq",1); count_instr(); +#define count_call() _nvprof("x86-call",1); count_instr(); +#define count_calli() _nvprof("x86-calli",1); count_instr(); +#define count_prolog() _nvprof("x86-prolog",1); count_instr(); +#define count_alu() _nvprof("x86-alu",1); count_instr(); +#define count_mov() _nvprof("x86-mov",1); count_instr(); +#define count_fpu() _nvprof("x86-fpu",1); count_instr(); +#define count_jmp() _nvprof("x86-jmp",1); count_instr(); +#define count_jcc() _nvprof("x86-jcc",1); count_instr(); +#define count_fpuld() _nvprof("x86-ldq",1); _nvprof("x86-fpu",1); count_instr() +#define count_aluld() _nvprof("x86-ld",1); _nvprof("x86-alu",1); count_instr() +#define count_alust() _nvprof("x86-ld",1); _nvprof("x86-alu",1); _nvprof("x86-st",1); count_instr() +#define count_pushld() _nvprof("x86-ld",1); _nvprof("x86-push",1); count_instr() +#define count_imt() _nvprof("x86-imt",1) count_instr() +#else +#define count_instr() +#define count_ret() +#define count_push() +#define count_pop() +#define count_st() +#define count_stq() +#define count_ld() +#define count_ldq() +#define count_call() +#define count_calli() +#define count_prolog() +#define count_alu() +#define count_mov() +#define count_fpu() +#define count_jmp() +#define count_jcc() +#define count_fpuld() +#define count_aluld() +#define count_alust() +#define count_pushld() +#define count_imt() +#endif + +namespace nanojit +{ + const int NJ_MAX_REGISTERS = 24; // gpregs, x87 regs, xmm regs + + #define NJ_MAX_STACK_ENTRY 4096 + #define NJ_MAX_PARAMETERS 1 + + #define NJ_USES_IMMD_POOL 1 + + #define NJ_JTBL_SUPPORTED 1 + #define NJ_EXPANDED_LOADSTORE_SUPPORTED 1 + #define NJ_F2I_SUPPORTED 1 + #define NJ_SOFTFLOAT_SUPPORTED 0 + #define NJ_DIVI_SUPPORTED 1 + + // Preserve a 16-byte stack alignment, to support the use of + // SSE instructions like MOVDQA (if not by Tamarin itself, + // then by the C functions it calls). + const int NJ_ALIGN_STACK = 16; + + const int32_t LARGEST_UNDERRUN_PROT = 32; // largest value passed to underrunProtect + + typedef uint8_t NIns; + + // Bytes of icache to flush after patch + const size_t LARGEST_BRANCH_PATCH = 16 * sizeof(NIns); + + static const Register + // General purpose 32 bit registers. The names are rEAX, rEBX, etc, + // because EAX, EBX, et al clash with on Solaris (sigh). + // See bug 570726 for details. + rEAX = { 0 }, // return value, scratch + rECX = { 1 }, // this/arg0, scratch + rEDX = { 2 }, // arg1, return-msw, scratch + rEBX = { 3 }, + rESP = { 4 }, // stack pointer + rEBP = { 5 }, // frame pointer + rESI = { 6 }, + rEDI = { 7 }, + + SP = rESP, // alias SP to ESP for convenience + FP = rEBP, // alias FP to EBP for convenience + + // SSE regs come before X87 so we prefer them + XMM0 = { 8 }, + XMM1 = { 9 }, + XMM2 = { 10 }, + XMM3 = { 11 }, + XMM4 = { 12 }, + XMM5 = { 13 }, + XMM6 = { 14 }, + XMM7 = { 15 }, + + // X87 regs + FST0 = { 16 }, + + deprecated_UnknownReg = { 17 }, // XXX: remove eventually, see bug 538924 + UnspecifiedReg = { 17 }; + + static const uint32_t FirstRegNum = 0; + static const uint32_t LastRegNum = 16; + + typedef int RegisterMask; + + static const int NumSavedRegs = 3; + static const RegisterMask SavedRegs = 1<> 8) & 0xff); \ + }; \ + void FPUm(int32_t o, int32_t d, Register b); \ + void FPUdm(int32_t o, const double* const m); \ + void TEST_AH(int32_t i); \ + void TEST_AX(int32_t i); \ + void FNSTSW_AX(); \ + void FCHS(); \ + void FLD1(); \ + void FLDZ(); \ + void FST32(bool p, int32_t d, Register b); \ + void FSTQ(bool p, int32_t d, Register b); \ + void FSTPQ(int32_t d, Register b); \ + void FCOM(bool p, int32_t d, Register b); \ + void FCOMdm(bool p, const double* dm); \ + void FLD32(int32_t d, Register b); \ + void FLDQ(int32_t d, Register b); \ + void FLDQdm(const double* dm); \ + void FILDQ(int32_t d, Register b); \ + void FILD(int32_t d, Register b); \ + void FIST(bool p, int32_t d, Register b); \ + void FADD( int32_t d, Register b); \ + void FSUB( int32_t d, Register b); \ + void FSUBR(int32_t d, Register b); \ + void FMUL( int32_t d, Register b); \ + void FDIV( int32_t d, Register b); \ + void FDIVR(int32_t d, Register b); \ + void FADDdm( const double *dm); \ + void FSUBRdm(const double* dm); \ + void FMULdm( const double* dm); \ + void FDIVRdm(const double* dm); \ + void FSTP(Register r) { \ + count_fpu(); \ + FPU(0xddd8, r); \ + asm_output("fstp %s", gpn(r)); \ + fpu_pop(); \ + }; \ + void FCOMP(); \ + void FCOMPP(); \ + void FLDr(Register r); \ + void EMMS(); \ + void CALL(const CallInfo* ci); \ + void CALLr(const CallInfo* ci, Register r); +} + + + +#endif // __nanojit_Nativei386__ diff --git a/js/src/nanojit/RegAlloc.cpp b/js/src/nanojit/RegAlloc.cpp new file mode 100644 index 0000000..29019d1 --- /dev/null +++ b/js/src/nanojit/RegAlloc.cpp @@ -0,0 +1,57 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nanojit.h" + +namespace nanojit +{ + #ifdef FEATURE_NANOJIT + + #ifdef _DEBUG + + bool RegAlloc::isConsistent(Register r, LIns* i) const + { + NanoAssert(r != deprecated_UnknownReg); + return (isFree(r) && !getActive(r) && !i) || + (!isFree(r) && getActive(r)== i && i ); + } + + #endif /*DEBUG*/ + #endif /* FEATURE_NANOJIT */ +} diff --git a/js/src/nanojit/RegAlloc.h b/js/src/nanojit/RegAlloc.h new file mode 100644 index 0000000..ad3e9da --- /dev/null +++ b/js/src/nanojit/RegAlloc.h @@ -0,0 +1,211 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#ifndef __nanojit_RegAlloc__ +#define __nanojit_RegAlloc__ + + +namespace nanojit +{ + class RegAlloc + { + public: + RegAlloc() + { + clear(); + } + + void clear() + { + VMPI_memset(this, 0, sizeof(*this)); + } + + bool isFree(Register r) const + { + NanoAssert(r != deprecated_UnknownReg); + return (free & rmask(r)) != 0; + } + + void addFree(Register r) + { + NanoAssert(!isFree(r)); + free |= rmask(r); + } + + void removeFree(Register r) + { + NanoAssert(isFree(r)); + free &= ~rmask(r); + } + + void addActive(Register r, LIns* v) + { + // Count++; + NanoAssert(v); + NanoAssert(r != deprecated_UnknownReg); + NanoAssert(active[REGNUM(r)] == NULL); + active[REGNUM(r)] = v; + useActive(r); + } + + void useActive(Register r) + { + NanoAssert(r != deprecated_UnknownReg); + NanoAssert(active[REGNUM(r)] != NULL); + usepri[REGNUM(r)] = priority++; + } + + void removeActive(Register r) + { + //registerReleaseCount++; + NanoAssert(r != deprecated_UnknownReg); + NanoAssert(active[REGNUM(r)] != NULL); + + // remove the given register from the active list + active[REGNUM(r)] = NULL; + } + + void retire(Register r) + { + NanoAssert(r != deprecated_UnknownReg); + NanoAssert(active[REGNUM(r)] != NULL); + active[REGNUM(r)] = NULL; + free |= rmask(r); + } + + int32_t getPriority(Register r) { + NanoAssert(r != deprecated_UnknownReg && active[REGNUM(r)]); + return usepri[REGNUM(r)]; + } + + LIns* getActive(Register r) const { + NanoAssert(r != deprecated_UnknownReg); + return active[REGNUM(r)]; + } + + // Return a mask containing the active registers. For each register + // in this set, getActive(register) will be a nonzero LIns pointer. + RegisterMask activeMask() const { + return ~free & managed; + } + + debug_only( bool isConsistent(Register r, LIns* v) const; ) + + // Some basics: + // + // - 'active' indicates which registers are active at a particular + // point, and for each active register, which instruction + // defines the value it holds. At the start of register + // allocation no registers are active. + // + // - 'free' indicates which registers are free at a particular point + // and thus available for use. At the start of register + // allocation most registers are free; those that are not + // aren't available for general use, e.g. the stack pointer and + // frame pointer registers. + // + // - 'managed' is exactly this list of initially free registers, + // ie. the registers managed by the register allocator. + // + // - Each LIns has a "reservation" which includes a register value, + // 'reg'. Combined with 'active', this provides a two-way + // mapping between registers and LIR instructions. + // + // - Invariant 1: each register must be in exactly one of the + // following states at all times: unmanaged, free, or active. + // In terms of the relevant fields: + // + // * A register in 'managed' must be in 'active' or 'free' but + // not both. + // + // * A register not in 'managed' must be in neither 'active' nor + // 'free'. + // + // - Invariant 2: the two-way mapping between active registers and + // their defining instructions must always hold in both + // directions and be unambiguous. More specifically: + // + // * An LIns can appear at most once in 'active'. + // + // * An LIns named by 'active[R]' must have an in-use + // reservation that names R. + // + // * And vice versa: an LIns with an in-use reservation that + // names R must be named by 'active[R]'. + // + // * If an LIns's reservation names 'deprecated_UnknownReg' then LIns + // should not be in 'active'. + // + LIns* active[LastRegNum + 1]; // active[REGNUM(r)] = LIns that defines r + int32_t usepri[LastRegNum + 1]; // used priority. lower = more likely to spill. + RegisterMask free; // Registers currently free. + RegisterMask managed; // Registers under management (invariant). + int32_t priority; + + DECLARE_PLATFORM_REGALLOC() + }; + + // Return the lowest numbered Register in mask. + inline Register lsReg(RegisterMask mask) { + // This is faster than it looks; we rely on the C++ optimizer + // to strip the dead branch and inline just one alternative. + Register r = { (sizeof(RegisterMask) == 4) ? lsbSet32(mask) : lsbSet64(mask) }; + return r; + } + + // Return the highest numbered Register in mask. + inline Register msReg(RegisterMask mask) { + // This is faster than it looks; we rely on the C++ optimizer + // to strip the dead branch and inline just one alternative. + Register r = { (sizeof(RegisterMask) == 4) ? msbSet32(mask) : msbSet64(mask) }; + return r; + } + + // Clear bit r in mask, then return lsReg(mask). + inline Register nextLsReg(RegisterMask& mask, Register r) { + return lsReg(mask &= ~rmask(r)); + } + + // Clear bit r in mask, then return msReg(mask). + inline Register nextMsReg(RegisterMask& mask, Register r) { + return msReg(mask &= ~rmask(r)); + } +} +#endif // __nanojit_RegAlloc__ diff --git a/js/src/nanojit/VMPI.cpp b/js/src/nanojit/VMPI.cpp new file mode 100644 index 0000000..68aa882 --- /dev/null +++ b/js/src/nanojit/VMPI.cpp @@ -0,0 +1,153 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is [Open Source Virtual Machine.] + * + * The Initial Developer of the Original Code is Adobe System Incorporated. Portions created + * by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights + * Reserved. + * + * Contributor(s): Adobe AS3 Team + * Andreas Gal + * + * Alternatively, the contents of this file may be used under the terms of either the GNU + * General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public + * License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the + * LGPL are applicable instead of those above. If you wish to allow use of your version of this + * file only under the terms of either the GPL or the LGPL, and not to allow others to use your + * version of this file under the terms of the MPL, indicate your decision by deleting provisions + * above and replace them with the notice and other provisions required by the GPL or the + * LGPL. If you do not delete the provisions above, a recipient may use your version of this file + * under the terms of any one of the MPL, the GPL or the LGPL. + * + ***** END LICENSE BLOCK ***** */ + +#include "nanojit.h" + +#ifdef SOLARIS + typedef caddr_t maddr_ptr; +#else + typedef void *maddr_ptr; +#endif + +using namespace avmplus; + +size_t +VMPI_getVMPageSize() +{ + return 4096; +} + +#ifdef WIN32 +void +VMPI_setPageProtection(void *address, + size_t size, + bool executableFlag, + bool writeableFlag) +{ + DWORD oldProtectFlags = 0; + DWORD newProtectFlags = 0; + if ( executableFlag && writeableFlag ) { + newProtectFlags = PAGE_EXECUTE_READWRITE; + } else if ( executableFlag ) { + newProtectFlags = PAGE_EXECUTE_READ; + } else if ( writeableFlag ) { + newProtectFlags = PAGE_READWRITE; + } else { + newProtectFlags = PAGE_READONLY; + } + + BOOL retval; + MEMORY_BASIC_INFORMATION mbi; + do { + VirtualQuery(address, &mbi, sizeof(MEMORY_BASIC_INFORMATION)); + size_t markSize = size > mbi.RegionSize ? mbi.RegionSize : size; + + retval = VirtualProtect(address, markSize, newProtectFlags, &oldProtectFlags); + NanoAssert(retval); + + address = (char*) address + markSize; + size -= markSize; + } while(size > 0 && retval); + + // We should not be clobbering PAGE_GUARD protections + NanoAssert((oldProtectFlags & PAGE_GUARD) == 0); +} + +#elif defined(AVMPLUS_OS2) + +void +VMPI_setPageProtection(void *address, + size_t size, + bool executableFlag, + bool writeableFlag) +{ + ULONG flags = PAG_READ; + if (executableFlag) { + flags |= PAG_EXECUTE; + } + if (writeableFlag) { + flags |= PAG_WRITE; + } + address = (void*)((size_t)address & ~(0xfff)); + size = (size + 0xfff) & ~(0xfff); + + ULONG attribFlags = PAG_FREE; + while (size) { + ULONG attrib; + ULONG range = size; + ULONG retval = DosQueryMem(address, &range, &attrib); + NanoAssert(retval == 0); + + // exit if this is the start of the next memory object + if (attrib & attribFlags) { + break; + } + attribFlags |= PAG_BASE; + + range = size > range ? range : size; + retval = DosSetMem(address, range, flags); + NanoAssert(retval == 0); + + address = (char*)address + range; + size -= range; + } +} + +#else // !WIN32 && !AVMPLUS_OS2 + +void VMPI_setPageProtection(void *address, + size_t size, + bool executableFlag, + bool writeableFlag) +{ + int bitmask = sysconf(_SC_PAGESIZE) - 1; + // mprotect requires that the addresses be aligned on page boundaries + void *endAddress = (void*) ((char*)address + size); + void *beginPage = (void*) ((size_t)address & ~bitmask); + void *endPage = (void*) (((size_t)endAddress + bitmask) & ~bitmask); + size_t sizePaged = (size_t)endPage - (size_t)beginPage; + + int flags = PROT_READ; + if (executableFlag) { + flags |= PROT_EXEC; + } + if (writeableFlag) { + flags |= PROT_WRITE; + } + int retval = mprotect((maddr_ptr)beginPage, (unsigned int)sizePaged, flags); + NanoAssert(retval == 0); + (void)retval; +} + +#endif // WIN32 diff --git a/js/src/nanojit/VMPI.h b/js/src/nanojit/VMPI.h new file mode 100644 index 0000000..429ed11 --- /dev/null +++ b/js/src/nanojit/VMPI.h @@ -0,0 +1,139 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Stub VMPI implementation to support standalone nanojit repository. + * + * Really only works if you *don't* have a busted-up C library. + */ + +#ifndef __VMPI_h__ +#define __VMPI_h__ + +#if defined(HAVE_CONFIG_H) && defined(NANOJIT_CENTRAL) +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if defined(AVMPLUS_UNIX) || defined(AVMPLUS_OS2) +#include +#include +#endif + +#ifdef AVMPLUS_WIN32 +#if ! defined(_STDINT_H) +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed __int64 int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +#endif +#else +#include +#include +#endif + +#define VMPI_strlen strlen +#define VMPI_strcat strcat +#define VMPI_strcmp strcmp +#define VMPI_strncat strncat +#define VMPI_strcpy strcpy +#define VMPI_sprintf sprintf +#ifdef _MSC_VER +# define VMPI_snprintf sprintf_s +#else +# define VMPI_snprintf snprintf +#endif +#define VMPI_vfprintf vfprintf +#define VMPI_memset memset +#define VMPI_isdigit isdigit +#define VMPI_getDate() + +extern size_t VMPI_getVMPageSize(); + +extern void VMPI_setPageProtection(void *address, + size_t size, + bool executableFlag, + bool writeableFlag); + +// Keep this warning-set relatively in sync with platform/win32/win32-platform.h in tamarin. + +#ifdef _MSC_VER + #pragma warning(disable:4201) // nonstandard extension used : nameless struct/union + #pragma warning(disable:4512) // assignment operator could not be generated + #pragma warning(disable:4511) // can't generate copy ctor + #pragma warning(disable:4127) // conditional expression is constant - appears to be compiler noise primarily + #pragma warning(disable:4611) // interaction between _setjmp and destruct + #pragma warning(disable:4725) // instruction may be inaccurate on some Pentiums + #pragma warning(disable:4611) // interaction between '_setjmp' and C++ object destruction is non-portable + #pragma warning(disable:4251) // X needs to have dll-interface to be used by clients of class Y + + // enable some that are off even in /W4 mode, but are still handy + #pragma warning(default:4265) // 'class' : class has virtual functions, but destructor is not virtual + #pragma warning(default:4905) // wide string literal cast to 'LPSTR' + #pragma warning(default:4906) // string literal cast to 'LPWSTR' + #pragma warning(default:4263) // 'function' : member function does not override any base class virtual member function + #pragma warning(default:4264) // 'virtual_function' : no override available for virtual member function from base 'class'; function is hidden + #pragma warning(default:4266) // 'function' : no override available for virtual member function from base 'type'; function is hidden + #pragma warning(default:4242) // 'identifier' : conversion from 'type1' to 'type2', possible loss of data + #pragma warning(default:4263) // member function does not override any base class virtual member function + #pragma warning(default:4296) // expression is always true (false) (Generally, an unsigned variable was used in a comparison operation with zero.) +#endif + +// This part defined in avmshell.h but similarly required for a warning-free nanojit experience. +#ifdef _MSC_VER +#pragma warning(disable:4996) // 'scanf' was declared deprecated +#endif + +// This part is inhibited manually by the CFLAGS in the tamarin configury. +#ifdef _MSC_VER +#pragma warning(disable:4291) // presence of a 'new' operator in nanojit/Allocator.h without matching 'delete' +#endif + +#endif diff --git a/js/src/nanojit/avmplus.cpp b/js/src/nanojit/avmplus.cpp new file mode 100644 index 0000000..f757349 --- /dev/null +++ b/js/src/nanojit/avmplus.cpp @@ -0,0 +1,184 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is [Open Source Virtual Machine.] + * + * The Initial Developer of the Original Code is Adobe System Incorporated. Portions created + * by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights + * Reserved. + * + * Contributor(s): Adobe AS3 Team + * Andreas Gal + * + * Alternatively, the contents of this file may be used under the terms of either the GNU + * General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public + * License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the + * LGPL are applicable instead of those above. If you wish to allow use of your version of this + * file only under the terms of either the GPL or the LGPL, and not to allow others to use your + * version of this file under the terms of the MPL, indicate your decision by deleting provisions + * above and replace them with the notice and other provisions required by the GPL or the + * LGPL. If you do not delete the provisions above, a recipient may use your version of this file + * under the terms of any one of the MPL, the GPL or the LGPL. + * + ***** END LICENSE BLOCK ***** */ + +#include +#include "nanojit.h" + +#ifdef SOLARIS + typedef caddr_t maddr_ptr; +#else + typedef void *maddr_ptr; +#endif + +using namespace avmplus; + +nanojit::Config AvmCore::config; + +void +avmplus::AvmLog(char const *msg, ...) { + va_list ap; + va_start(ap, msg); + VMPI_vfprintf(stderr, msg, ap); + va_end(ap); +} + +#ifdef _DEBUG +namespace avmplus { + void AvmAssertFail(const char* /* msg */) { + fflush(stderr); +#if defined(WIN32) + DebugBreak(); + exit(3); +#elif defined(__APPLE__) + /* + * On Mac OS X, Breakpad ignores signals. Only real Mach exceptions are + * trapped. + */ + *((int *) NULL) = 0; /* To continue from here in GDB: "return" then "continue". */ + raise(SIGABRT); /* In case above statement gets nixed by the optimizer. */ +#else + raise(SIGABRT); /* To continue from here in GDB: "signal 0". */ +#endif + } +} +#endif + +#ifdef WINCE + +// Due to the per-process heap slots on Windows Mobile, we can often run in to OOM +// situations. jemalloc has worked around this problem, and so we use it here. +// Using posix_memalign (or other malloc)functions) here only works because the OS +// and hardware doesn't check for the execute bit being set. + +#ifndef MOZ_MEMORY +#error MOZ_MEMORY required for building on WINCE +#endif + +void* +nanojit::CodeAlloc::allocCodeChunk(size_t nbytes) { + void * buffer; + posix_memalign(&buffer, 4096, nbytes); + VMPI_setPageProtection(buffer, nbytes, true /* exec */, true /* write */); + return buffer; +} + +void +nanojit::CodeAlloc::freeCodeChunk(void *p, size_t nbytes) { + VMPI_setPageProtection(p, nbytes, false /* exec */, true /* write */); + ::free(p); +} + +#elif defined(WIN32) + +void* +nanojit::CodeAlloc::allocCodeChunk(size_t nbytes) { + return VirtualAlloc(NULL, + nbytes, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); +} + +void +nanojit::CodeAlloc::freeCodeChunk(void *p, size_t) { + VirtualFree(p, 0, MEM_RELEASE); +} + +#elif defined(AVMPLUS_OS2) + +void* +nanojit::CodeAlloc::allocCodeChunk(size_t nbytes) { + + // alloc from high memory, fallback to low memory if that fails + void * addr; + if (DosAllocMem(&addr, nbytes, OBJ_ANY | + PAG_COMMIT | PAG_READ | PAG_WRITE | PAG_EXECUTE)) { + if (DosAllocMem(&addr, nbytes, + PAG_COMMIT | PAG_READ | PAG_WRITE | PAG_EXECUTE)) { + return 0; + } + } + return addr; +} + +void +nanojit::CodeAlloc::freeCodeChunk(void *p, size_t nbytes) { + DosFreeMem(p); +} + +#elif defined(AVMPLUS_UNIX) + +void* +nanojit::CodeAlloc::allocCodeChunk(size_t nbytes) { + return mmap(NULL, + nbytes, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANON, + -1, + 0); +} + +void +nanojit::CodeAlloc::freeCodeChunk(void *p, size_t nbytes) { + munmap((maddr_ptr)p, nbytes); +} + +#else // !WIN32 && !AVMPLUS_OS2 && !AVMPLUS_UNIX + +void* +nanojit::CodeAlloc::allocCodeChunk(size_t nbytes) { + void* mem = valloc(nbytes); + VMPI_setPageProtection(mem, nbytes, true /* exec */, true /* write */); + return mem; +} + +void +nanojit::CodeAlloc::freeCodeChunk(void *p, size_t nbytes) { + VMPI_setPageProtection(p, nbytes, false /* exec */, true /* write */); + ::free(p); +} + +#endif // WIN32 + +// All of the allocCodeChunk/freeCodeChunk implementations above allocate +// code memory as RWX and then free it, so the explicit page protection api's +// below are no-ops. + +void +nanojit::CodeAlloc::markCodeChunkWrite(void*, size_t) +{} + +void +nanojit::CodeAlloc::markCodeChunkExec(void*, size_t) +{} + diff --git a/js/src/nanojit/avmplus.h b/js/src/nanojit/avmplus.h new file mode 100644 index 0000000..c0b842c --- /dev/null +++ b/js/src/nanojit/avmplus.h @@ -0,0 +1,347 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTY OF ANY KIND, either express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is [Open Source Virtual Machine.] + * + * The Initial Developer of the Original Code is Adobe System Incorporated. Portions created + * by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights + * Reserved. + * + * Contributor(s): Adobe AS3 Team + * Andreas Gal + * Asko Tontti + * + * Alternatively, the contents of this file may be used under the terms of either the GNU + * General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public + * License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the + * LGPL are applicable instead of those above. If you wish to allow use of your version of this + * file only under the terms of either the GPL or the LGPL, and not to allow others to use your + * version of this file under the terms of the MPL, indicate your decision by deleting provisions + * above and replace them with the notice and other provisions required by the GPL or the + * LGPL. If you do not delete the provisions above, a recipient may use your version of this file + * under the terms of any one of the MPL, the GPL or the LGPL. + * + ***** END LICENSE BLOCK ***** */ + +#ifndef avm_h___ +#define avm_h___ + +#include "VMPI.h" +#include "njcpudetect.h" +#include "njconfig.h" + +#if !defined(AVMPLUS_LITTLE_ENDIAN) && !defined(AVMPLUS_BIG_ENDIAN) +#ifdef IS_BIG_ENDIAN +#define AVMPLUS_BIG_ENDIAN +#else +#define AVMPLUS_LITTLE_ENDIAN +#endif +#endif + +#if defined(_MSC_VER) && defined(_M_IX86) +#define FASTCALL __fastcall +#elif defined(__GNUC__) && defined(__i386__) && \ + ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +#define FASTCALL __attribute__((fastcall)) +#else +#define FASTCALL +#define NO_FASTCALL +#endif + +#if defined(NO_FASTCALL) +#if defined(AVMPLUS_IA32) +#define SIMULATE_FASTCALL(lr, state_ptr, frag_ptr, func_addr) \ + asm volatile( \ + "call *%%esi" \ + : "=a" (lr) \ + : "c" (state_ptr), "d" (frag_ptr), "S" (func_addr) \ + : "memory", "cc" \ + ); +#endif /* defined(AVMPLUS_IA32) */ +#endif /* defined(NO_FASTCALL) */ + +#ifdef WIN32 +#include +#elif defined(AVMPLUS_OS2) +#define INCL_DOSMEMMGR +#include +#endif + +#if defined(__SUNPRO_CC) +#define __asm__ asm +#define __volatile__ volatile +#define __inline__ inline +#endif + +#if defined(DEBUG) || defined(NJ_NO_VARIADIC_MACROS) +#if !defined _DEBUG +#define _DEBUG +#endif +#define NJ_VERBOSE 1 +#include +#endif + +#ifdef _DEBUG +namespace avmplus { + void AvmAssertFail(const char* msg); +} +#endif + +#if defined(AVMPLUS_IA32) +#if defined(_MSC_VER) + +# define AVMPLUS_HAS_RDTSC 1 + +__declspec(naked) static inline __int64 rdtsc() +{ + __asm + { + rdtsc; + ret; + } +} + +#elif defined(__i386__) || defined(__i386) + +# define AVMPLUS_HAS_RDTSC 1 + +static __inline__ unsigned long long rdtsc(void) +{ + unsigned long long int x; + __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); + return x; +} + +#endif /* compilers */ + +#elif defined(__x86_64__) + +# define AVMPLUS_HAS_RDTSC 1 + +static __inline__ uint64_t rdtsc(void) +{ + unsigned hi, lo; + __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); + return ( (uint64_t)lo)|( ((uint64_t)hi)<<32 ); +} + +#elif defined(_MSC_VER) && defined(_M_AMD64) + +# define AVMPLUS_HAS_RDTSC 1 + +#include +#pragma intrinsic(__rdtsc) + +static inline unsigned __int64 rdtsc(void) +{ + return __rdtsc(); +} + +#elif defined(__powerpc__) + +# define AVMPLUS_HAS_RDTSC 1 + +typedef unsigned long long int unsigned long long; + +static __inline__ unsigned long long rdtsc(void) +{ + unsigned long long int result=0; + unsigned long int upper, lower,tmp; + __asm__ volatile( + "0: \n" + "\tmftbu %0 \n" + "\tmftb %1 \n" + "\tmftbu %2 \n" + "\tcmpw %2,%0 \n" + "\tbne 0b \n" + : "=r"(upper),"=r"(lower),"=r"(tmp) + ); + result = upper; + result = result<<32; + result = result|lower; + + return(result); +} + +#endif /* architecture */ + +#ifndef AVMPLUS_HAS_RDTSC +# define AVMPLUS_HAS_RDTSC 0 +#endif + +struct JSContext; + +#ifdef PERFM +# define PERFM_NVPROF(n,v) _nvprof(n,v) +# define PERFM_NTPROF(n) _ntprof(n) +# define PERFM_TPROF_END() _tprof_end() +#else +# define PERFM_NVPROF(n,v) +# define PERFM_NTPROF(n) +# define PERFM_TPROF_END() +#endif + +namespace avmplus { + + typedef int FunctionID; + + extern void AvmLog(char const *msg, ...); + + static const int kstrconst_emptyString = 0; + + class AvmInterpreter + { + class Labels { + public: + const char* format(const void* ip) + { + static char buf[33]; + sprintf(buf, "%p", ip); + return buf; + } + }; + + Labels _labels; + public: + Labels* labels; + + AvmInterpreter() + { + labels = &_labels; + } + + }; + + class AvmConsole + { + public: + AvmConsole& operator<<(const char* s) + { + fprintf(stdout, "%s", s); + return *this; + } + }; + + class AvmCore + { + public: + AvmInterpreter interp; + AvmConsole console; + + static nanojit::Config config; + +#ifdef AVMPLUS_IA32 + static inline bool + use_sse2() + { + return config.i386_sse2; + } +#endif + + static inline bool + use_cmov() + { +#ifdef AVMPLUS_IA32 + return config.i386_use_cmov; +#else + return true; +#endif + } + }; + + /** + * Bit vectors are an efficent method of keeping True/False information + * on a set of items or conditions. Class BitSet provides functions + * to manipulate individual bits in the vector. + * + * This object is not optimized for a fixed sized bit vector + * it instead allows for dynamically growing the bit vector. + */ + class BitSet + { + public: + enum { kUnit = 8*sizeof(long), + kDefaultCapacity = 4 }; + + BitSet() + { + capacity = kDefaultCapacity; + ar = (long*)calloc(capacity, sizeof(long)); + reset(); + } + + ~BitSet() + { + free(ar); + } + + void reset() + { + for (int i = 0; i < capacity; i++) + ar[i] = 0; + } + + void set(int bitNbr) + { + int index = bitNbr / kUnit; + int bit = bitNbr % kUnit; + if (index >= capacity) + grow(index+1); + + ar[index] |= (1< +#elif !defined(VALGRIND_DISCARD_TRANSLATIONS) +# define VALGRIND_DISCARD_TRANSLATIONS(addr, szB) +#endif + +namespace nanojit +{ + /** + * ------------------------------------------- + * START AVM bridging definitions + * ------------------------------------------- + */ + typedef avmplus::AvmCore AvmCore; + + const uint32_t MAXARGS = 8; + + #ifdef NJ_NO_VARIADIC_MACROS + inline void NanoAssertMsgf(bool a,const char *f,...) {} + inline void NanoAssertMsg(bool a,const char *m) {} + inline void NanoAssert(bool a) {} + #elif defined(_DEBUG) + + #define __NanoAssertMsgf(a, file_, line_, f, ...) \ + if (!(a)) { \ + avmplus::AvmLog("Assertion failure: " f "%s (%s:%d)\n", __VA_ARGS__, #a, file_, line_); \ + avmplus::AvmAssertFail(""); \ + } + + #define _NanoAssertMsgf(a, file_, line_, f, ...) __NanoAssertMsgf(a, file_, line_, f, __VA_ARGS__) + + #define NanoAssertMsgf(a,f,...) do { __NanoAssertMsgf(a, __FILE__, __LINE__, f ": ", __VA_ARGS__); } while (0) + #define NanoAssertMsg(a,m) do { __NanoAssertMsgf(a, __FILE__, __LINE__, "\"%s\": ", m); } while (0) + #define NanoAssert(a) do { __NanoAssertMsgf(a, __FILE__, __LINE__, "%s", ""); } while (0) + #else + #define NanoAssertMsgf(a,f,...) do { } while (0) /* no semi */ + #define NanoAssertMsg(a,m) do { } while (0) /* no semi */ + #define NanoAssert(a) do { } while (0) /* no semi */ + #endif + + /* + * Sun Studio C++ compiler has a bug + * "sizeof expression not accepted as size of array parameter" + * The bug number is 6688515. It is not public yet. + * Turn off this assert for Sun Studio until this bug is fixed. + */ + #ifdef __SUNPRO_CC + #define NanoStaticAssert(condition) + #else + #define NanoStaticAssert(condition) \ + extern void nano_static_assert(int arg[(condition) ? 1 : -1]) + #endif + + + /** + * ------------------------------------------- + * END AVM bridging definitions + * ------------------------------------------- + */ +} + +#ifdef AVMPLUS_VERBOSE + #define NJ_VERBOSE 1 +#endif + +#ifdef NJ_NO_VARIADIC_MACROS + #include + #define verbose_outputf if (_logc->lcbits & LC_Native) \ + Assembler::outputf + #define verbose_only(x) x +#elif defined(NJ_VERBOSE) + #include + #define verbose_outputf if (_logc->lcbits & LC_Native) \ + Assembler::outputf + #define verbose_only(...) __VA_ARGS__ +#else + #define verbose_outputf + #define verbose_only(...) +#endif /*NJ_VERBOSE*/ + +#ifdef _DEBUG + #define debug_only(x) x +#else + #define debug_only(x) +#endif /* DEBUG */ + +#define isS8(i) ( int32_t(i) == int8_t(i) ) +#define isU8(i) ( int32_t(i) == uint8_t(i) ) +#define isS16(i) ( int32_t(i) == int16_t(i) ) +#define isU16(i) ( int32_t(i) == uint16_t(i) ) +#define isS24(i) ( (int32_t((i)<<8)>>8) == (i) ) + +static inline bool isS32(intptr_t i) { + return int32_t(i) == i; +} + +static inline bool isU32(uintptr_t i) { + return uint32_t(i) == i; +} + +#define alignTo(x,s) ((((uintptr_t)(x)))&~(((uintptr_t)s)-1)) +#define alignUp(x,s) ((((uintptr_t)(x))+(((uintptr_t)s)-1))&~(((uintptr_t)s)-1)) + +#define NJ_MIN(x, y) ((x) < (y) ? (x) : (y)) +#define NJ_MAX(x, y) ((x) > (y) ? (x) : (y)) + +namespace nanojit +{ +// Define msbSet32(), lsbSet32(), msbSet64(), and lsbSet64() functions using +// fast find-first-bit instructions intrinsics when available. +// The fall-back implementations use iteration. +#if defined(_WIN32) && (_MSC_VER >= 1300) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64)) + + extern "C" unsigned char _BitScanForward(unsigned long * Index, unsigned long Mask); + extern "C" unsigned char _BitScanReverse(unsigned long * Index, unsigned long Mask); + # pragma intrinsic(_BitScanForward) + # pragma intrinsic(_BitScanReverse) + + // Returns the index of the most significant bit that is set. + static inline int msbSet32(uint32_t x) { + unsigned long idx; + _BitScanReverse(&idx, (unsigned long)(x | 1)); // the '| 1' ensures a 0 result when x==0 + return idx; + } + + // Returns the index of the least significant bit that is set. + static inline int lsbSet32(uint32_t x) { + unsigned long idx; + _BitScanForward(&idx, (unsigned long)(x | 0x80000000)); // the '| 0x80000000' ensures a 0 result when x==0 + return idx; + } + +#if defined(_M_AMD64) || defined(_M_X64) + extern "C" unsigned char _BitScanForward64(unsigned long * Index, unsigned __int64 Mask); + extern "C" unsigned char _BitScanReverse64(unsigned long * Index, unsigned __int64 Mask); + # pragma intrinsic(_BitScanForward64) + # pragma intrinsic(_BitScanReverse64) + + // Returns the index of the most significant bit that is set. + static inline int msbSet64(uint64_t x) { + unsigned long idx; + _BitScanReverse64(&idx, (unsigned __int64)(x | 1)); // the '| 1' ensures a 0 result when x==0 + return idx; + } + + // Returns the index of the least significant bit that is set. + static inline int lsbSet64(uint64_t x) { + unsigned long idx; + _BitScanForward64(&idx, (unsigned __int64)(x | 0x8000000000000000LL)); // the '| 0x80000000' ensures a 0 result when x==0 + return idx; + } +#else + // Returns the index of the most significant bit that is set. + static int msbSet64(uint64_t x) { + return (x & 0xffffffff00000000LL) ? msbSet32(uint32_t(x >> 32)) + 32 : msbSet32(uint32_t(x)); + } + // Returns the index of the least significant bit that is set. + static int lsbSet64(uint64_t x) { + return (x & 0x00000000ffffffffLL) ? lsbSet32(uint32_t(x)) : lsbSet32(uint32_t(x >> 32)) + 32; + } +#endif + +#elif (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + + // Returns the index of the most significant bit that is set. + static inline int msbSet32(uint32_t x) { + return 31 - __builtin_clz(x | 1); + } + + // Returns the index of the least significant bit that is set. + static inline int lsbSet32(uint32_t x) { + return __builtin_ctz(x | 0x80000000); + } + + // Returns the index of the most significant bit that is set. + static inline int msbSet64(uint64_t x) { + return 63 - __builtin_clzll(x | 1); + } + + // Returns the index of the least significant bit that is set. + static inline int lsbSet64(uint64_t x) { + return __builtin_ctzll(x | 0x8000000000000000LL); + } + +#else + + // Slow fall-back: return most significant bit set by searching iteratively. + static int msbSet32(uint32_t x) { + for (int i = 31; i >= 0; i--) + if ((1 << i) & x) + return i; + return 0; + } + + // Slow fall-back: return least significant bit set by searching iteratively. + static int lsbSet32(uint32_t x) { + for (int i = 0; i < 32; i++) + if ((1 << i) & x) + return i; + return 31; + } + + // Slow fall-back: return most significant bit set by searching iteratively. + static int msbSet64(uint64_t x) { + for (int i = 63; i >= 0; i--) + if ((1LL << i) & x) + return i; + return 0; + } + + // Slow fall-back: return least significant bit set by searching iteratively. + static int lsbSet64(uint64_t x) { + for (int i = 0; i < 64; i++) + if ((1LL << i) & x) + return i; + return 63; + } + +#endif // select compiler +} // namespace nanojit + +// ------------------------------------------------------------------- +// START debug-logging definitions +// ------------------------------------------------------------------- + +/* Debug printing stuff. All Nanojit and jstracer debug printing + should be routed through LogControl::printf. Don't use + ad-hoc calls to printf, fprintf(stderr, ...) etc. + + Similarly, don't use ad-hoc getenvs etc to decide whether or not to + print debug output. Instead consult the relevant control bit in + LogControl::lcbits in the LogControl object you are supplied with. +*/ + +# if defined(__GNUC__) +# define PRINTF_CHECK(x, y) __attribute__((format(__printf__, x, y))) +# else +# define PRINTF_CHECK(x, y) +# endif + +namespace nanojit { + + // LogControl, a class for controlling and routing debug output + + enum LC_Bits { + /* Output control bits for Nanojit code. Only use bits 15 + and below, so that callers can use bits 16 and above for + themselves. */ + // TODO: add entries for the writer pipeline + LC_FragProfile = 1<<8, // collect per-frag usage counts + LC_Liveness = 1<<7, // show LIR liveness analysis + LC_ReadLIR = 1<<6, // as read from LirBuffer + LC_AfterSF = 1<<5, // after StackFilter + LC_AfterDCE = 1<<4, // after dead code elimination + LC_Bytes = 1<<3, // byte values of native instruction + LC_Native = 1<<2, // final native code + LC_RegAlloc = 1<<1, // stuff to do with reg alloc + LC_Activation = 1<<0 // enable printActivationState + }; + + class LogControl + { + public: + // All Nanojit and jstracer printing should be routed through + // this function. + virtual ~LogControl() {} + #ifdef NJ_VERBOSE + virtual void printf( const char* format, ... ) PRINTF_CHECK(2,3); + #endif + + // An OR of LC_Bits values, indicating what should be output + uint32_t lcbits; + }; +} + +// ------------------------------------------------------------------- +// END debug-logging definitions +// ------------------------------------------------------------------- + + +#include "njconfig.h" +#include "Allocator.h" +#include "Containers.h" +#include "Native.h" +#include "CodeAlloc.h" +#include "LIR.h" +#include "RegAlloc.h" +#include "Fragmento.h" +#include "Assembler.h" + +#endif // FEATURE_NANOJIT +#endif // __nanojit_h__ diff --git a/js/src/nanojit/njconfig.cpp b/js/src/nanojit/njconfig.cpp new file mode 100644 index 0000000..88e1d05 --- /dev/null +++ b/js/src/nanojit/njconfig.cpp @@ -0,0 +1,117 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nanojit.h" + +#ifdef FEATURE_NANOJIT + +namespace nanojit +{ +#ifdef NANOJIT_IA32 + static int getCpuFeatures() + { + int features = 0; + #if defined _MSC_VER + __asm + { + pushad + mov eax, 1 + cpuid + mov features, edx + popad + } + #elif defined __GNUC__ + asm("xchg %%esi, %%ebx\n" /* we can't clobber ebx on gcc (PIC register) */ + "mov $0x01, %%eax\n" + "cpuid\n" + "mov %%edx, %0\n" + "xchg %%esi, %%ebx\n" + : "=m" (features) + : /* We have no inputs */ + : "%eax", "%esi", "%ecx", "%edx" + ); + #elif defined __SUNPRO_C || defined __SUNPRO_CC + asm("push %%ebx\n" + "mov $0x01, %%eax\n" + "cpuid\n" + "pop %%ebx\n" + : "=d" (features) + : /* We have no inputs */ + : "%eax", "%ecx" + ); + #endif + return features; + } +#endif + + Config::Config() + { + VMPI_memset(this, 0, sizeof(*this)); + + cseopt = true; + +#ifdef NANOJIT_IA32 + int const features = getCpuFeatures(); + i386_sse2 = (features & (1<<26)) != 0; + i386_use_cmov = (features & (1<<15)) != 0; + i386_fixed_esp = false; +#endif + harden_function_alignment = false; + harden_nop_insertion = false; + +#if defined(NANOJIT_ARM) + + // XXX: temporarily disabled, see bug 547063. + //NanoStaticAssert(NJ_COMPILER_ARM_ARCH >= 5 && NJ_COMPILER_ARM_ARCH <= 7); + + arm_arch = NJ_COMPILER_ARM_ARCH; + arm_vfp = (arm_arch >= 7); + + #if defined(DEBUG) || defined(_DEBUG) + arm_show_stats = true; + #else + arm_show_stats = false; + #endif + + soft_float = !arm_vfp; + +#endif // NANOJIT_ARM + } +} +#endif /* FEATURE_NANOJIT */ diff --git a/js/src/nanojit/njconfig.h b/js/src/nanojit/njconfig.h new file mode 100644 index 0000000..548adc3 --- /dev/null +++ b/js/src/nanojit/njconfig.h @@ -0,0 +1,107 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __njconfig_h__ +#define __njconfig_h__ + +#include "avmplus.h" + +// Do not include nanojit.h here; this file should be usable without it. + +#ifdef FEATURE_NANOJIT + +namespace nanojit +{ + /*** + * A struct used to configure the assumptions that Assembler can make when + * generating code. The ctor will fill in all fields with the most reasonable + * values it can derive from compiler flags and/or runtime detection, but + * the embedder is free to override any or all of them as it sees fit. + * Using the ctor-provided default setup is guaranteed to provide a safe + * runtime environment (though perhaps suboptimal in some cases), so an embedder + * should replace these values with great care. + * + * Note that although many fields are used on only specific architecture(s), + * this struct is deliberately declared without ifdef's for them, so (say) ARM-specific + * fields are declared everywhere. This reduces build dependencies (so that this + * files does not require nanojit.h to be included beforehand) and also reduces + * clutter in this file; the extra storage space required is trivial since most + * fields are single bits. + */ + struct Config + { + public: + // fills in reasonable default values for all fields. + Config(); + + // ARM architecture to assume when generate instructions for (currently, 4 <= arm_arch <= 7) + uint8_t arm_arch; + + // If true, use CSE. + uint32_t cseopt:1; + + // Can we use SSE2 instructions? (x86-only) + uint32_t i386_sse2:1; + + // Can we use cmov instructions? (x86-only) + uint32_t i386_use_cmov:1; + + // Should we use a virtual stack pointer? (x86-only) + uint32_t i386_fixed_esp:1; + + // Whether or not to generate VFP instructions. (ARM only) + uint32_t arm_vfp:1; + + // @todo, document me + uint32_t arm_show_stats:1; + + // If true, use softfloat for all floating point operations, + // whether or not an FPU is present. (ARM only for now, but might also includes MIPS in the future) + uint32_t soft_float:1; + + // If true, compiler will insert a random amount of space in between functions (x86-32 only) + uint32_t harden_function_alignment:1; + + // If true, compiler will insert randomly choosen no-op instructions at random locations within a compiled method (x86-32 only) + uint32_t harden_nop_insertion:1; + }; +} + +#endif // FEATURE_NANOJIT +#endif // __njconfig_h__ diff --git a/js/src/nanojit/njcpudetect.h b/js/src/nanojit/njcpudetect.h new file mode 100644 index 0000000..db2313f --- /dev/null +++ b/js/src/nanojit/njcpudetect.h @@ -0,0 +1,115 @@ +/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is [Open Source Virtual Machine]. + * + * The Initial Developer of the Original Code is + * Adobe System Incorporated. + * Portions created by the Initial Developer are Copyright (C) 2004-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adobe AS3 Team + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __njcpudetect__ +#define __njcpudetect__ + +/*** + * Note: this file should not include *any* other files, nor should it wrap + * itself in ifdef FEATURE_NANOJIT, nor should it do anything other than + * define preprocessor symbols. + */ + +/*** + * NJ_COMPILER_ARM_ARCH attempts to specify the minimum ARM architecture + * that the C++ compiler has specified. Note that although Config::arm_arch + * is initialized to this value by default, there is no requirement that they + * be in sync. + * + * Note, this is done via #define so that downstream preprocessor usage can + * examine it, but please don't attempt to redefine it. + * + * Note, this is deliberately not encased in "ifdef NANOJIT_ARM", as this file + * may be included before that is defined. On non-ARM platforms we will hit the + * "Unable to determine" case. + */ + +// GCC and RealView usually define __ARM_ARCH__ +#if defined(__ARM_ARCH__) + + #define NJ_COMPILER_ARM_ARCH __ARM_ARCH__ + +// ok, try well-known GCC flags ( see http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html ) +#elif defined(__ARM_ARCH_7__) || \ + defined(__ARM_ARCH_7A__) || \ + defined(__ARM_ARCH_7M__) || \ + defined(__ARM_ARCH_7R__) || \ + defined(_ARM_ARCH_7) + + #define NJ_COMPILER_ARM_ARCH 7 + +#elif defined(__ARM_ARCH_6__) || \ + defined(__ARM_ARCH_6J__) || \ + defined(__ARM_ARCH_6T2__) || \ + defined(__ARM_ARCH_6Z__) || \ + defined(__ARM_ARCH_6ZK__) || \ + defined(__ARM_ARCH_6M__) || \ + defined(_ARM_ARCH_6) + + #define NJ_COMPILER_ARM_ARCH 6 + +#elif defined(__ARM_ARCH_5__) || \ + defined(__ARM_ARCH_5T__) || \ + defined(__ARM_ARCH_5E__) || \ + defined(__ARM_ARCH_5TE__) + + #define NJ_COMPILER_ARM_ARCH 5 + +#elif defined(__ARM_ARCH_4T__) + + #define NJ_COMPILER_ARM_ARCH 4 + +// Visual C has its own mojo +#elif defined(_MSC_VER) && defined(_M_ARM) + + #define NJ_COMPILER_ARM_ARCH _M_ARM + +// RVCT +#elif defined(__TARGET_ARCH_ARM) + + #define NJ_COMPILER_ARM_ARCH __TARGET_ARCH_ARM + +#else + + // non-numeric value + #define NJ_COMPILER_ARM_ARCH "Unable to determine valid NJ_COMPILER_ARM_ARCH (nanojit only supports ARMv4T or later)" + +#endif + +#endif // __njcpudetect__ diff --git a/js/src/perf/jsperf.cpp b/js/src/perf/jsperf.cpp new file mode 100644 index 0000000..3c99722 --- /dev/null +++ b/js/src/perf/jsperf.cpp @@ -0,0 +1,295 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Zack Weinberg (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsperf.h" +#include "jscntxt.h" /* for error messages */ +#include "jsobj.h" /* for unwrapping without a context */ + +using JS::PerfMeasurement; + +// You cannot forward-declare a static object in C++, so instead +// we have to forward-declare the helper functions that refer to it. +static PerfMeasurement* GetPM(JSContext* cx, JSObject* obj, const char* fname); +static PerfMeasurement* GetPMFromThis(JSContext* cx, jsval* vp); + +// Constructor and destructor + +static JSBool +pm_construct(JSContext* cx, uintN argc, jsval* vp) +{ + uint32 mask; + if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "u", &mask)) + return JS_FALSE; + + JSObject *obj = JS_NewObjectForConstructor(cx, vp); + if (!obj) + return JS_FALSE; + + if (!JS_FreezeObject(cx, obj)) + return JS_FALSE; + + PerfMeasurement* p = js_new(PerfMeasurement::EventMask(mask)); + if (!p) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + + JS_SetPrivate(cx, obj, p); + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +static void +pm_finalize(JSContext* cx, JSObject* obj) +{ + js_delete((PerfMeasurement*) JS_GetPrivate(cx, obj)); +} + +// Property access + +#define GETTER(name) \ + static JSBool \ + pm_get_##name(JSContext* cx, JSObject* obj, jsid /*unused*/, jsval* vp) \ + { \ + PerfMeasurement* p = GetPM(cx, obj, #name); \ + if (!p) \ + return JS_FALSE; \ + return JS_NewNumberValue(cx, jsdouble(p->name), vp); \ + } + +GETTER(cpu_cycles) +GETTER(instructions) +GETTER(cache_references) +GETTER(cache_misses) +GETTER(branch_instructions) +GETTER(branch_misses) +GETTER(bus_cycles) +GETTER(page_faults) +GETTER(major_page_faults) +GETTER(context_switches) +GETTER(cpu_migrations) +GETTER(eventsMeasured) + +#undef GETTER + +// Calls + +static JSBool +pm_start(JSContext* cx, uintN /*unused*/, jsval* vp) +{ + PerfMeasurement* p = GetPMFromThis(cx, vp); + if (!p) + return JS_FALSE; + + p->start(); + return JS_TRUE; +} + +static JSBool +pm_stop(JSContext* cx, uintN /*unused*/, jsval* vp) +{ + PerfMeasurement* p = GetPMFromThis(cx, vp); + if (!p) + return JS_FALSE; + + p->stop(); + return JS_TRUE; +} + +static JSBool +pm_reset(JSContext* cx, uintN /*unused*/, jsval* vp) +{ + PerfMeasurement* p = GetPMFromThis(cx, vp); + if (!p) + return JS_FALSE; + + p->reset(); + return JS_TRUE; +} + +static JSBool +pm_canMeasureSomething(JSContext* cx, uintN /*unused*/, jsval* vp) +{ + PerfMeasurement* p = GetPMFromThis(cx, vp); + if (!p) + return JS_FALSE; + + JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(p->canMeasureSomething())); + return JS_TRUE; +} + +const uint8 PM_FATTRS = JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED; +static JSFunctionSpec pm_fns[] = { + JS_FN("start", pm_start, 0, PM_FATTRS), + JS_FN("stop", pm_stop, 0, PM_FATTRS), + JS_FN("reset", pm_reset, 0, PM_FATTRS), + JS_FN("canMeasureSomething", pm_canMeasureSomething, 0, PM_FATTRS), + JS_FS_END +}; + +const uint8 PM_PATTRS = + JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED; + +#define GETTER(name) \ + { #name, 0, PM_PATTRS, pm_get_##name, 0 } + +static JSPropertySpec pm_props[] = { + GETTER(cpu_cycles), + GETTER(instructions), + GETTER(cache_references), + GETTER(cache_misses), + GETTER(branch_instructions), + GETTER(branch_misses), + GETTER(bus_cycles), + GETTER(page_faults), + GETTER(major_page_faults), + GETTER(context_switches), + GETTER(cpu_migrations), + GETTER(eventsMeasured), + {0,0,0,0,0} +}; + +#undef GETTER + +// If this were C++ these would be "static const" members. + +const uint8 PM_CATTRS = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT; + +#define CONSTANT(name) { #name, PerfMeasurement::name } + +static const struct pm_const { + const char *name; + PerfMeasurement::EventMask value; +} pm_consts[] = { + CONSTANT(CPU_CYCLES), + CONSTANT(INSTRUCTIONS), + CONSTANT(CACHE_REFERENCES), + CONSTANT(CACHE_MISSES), + CONSTANT(BRANCH_INSTRUCTIONS), + CONSTANT(BRANCH_MISSES), + CONSTANT(BUS_CYCLES), + CONSTANT(PAGE_FAULTS), + CONSTANT(MAJOR_PAGE_FAULTS), + CONSTANT(CONTEXT_SWITCHES), + CONSTANT(CPU_MIGRATIONS), + CONSTANT(ALL), + CONSTANT(NUM_MEASURABLE_EVENTS), + { 0, PerfMeasurement::EventMask(0) } +}; + +#undef CONSTANT + +static JSClass pm_class = { + "PerfMeasurement", JSCLASS_HAS_PRIVATE, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, pm_finalize, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +// Helpers (declared above) + +static PerfMeasurement* +GetPM(JSContext* cx, JSObject* obj, const char* fname) +{ + PerfMeasurement* p = (PerfMeasurement*) + JS_GetInstancePrivate(cx, obj, &pm_class, 0); + if (p) + return p; + + // JS_GetInstancePrivate only sets an exception if its last argument + // is nonzero, so we have to do it by hand. + JS_ReportErrorNumber(cx, js_GetErrorMessage, 0, JSMSG_INCOMPATIBLE_PROTO, + pm_class.name, fname, JS_GET_CLASS(cx, obj)->name); + return 0; +} + +static PerfMeasurement* +GetPMFromThis(JSContext* cx, jsval* vp) +{ + JSObject* this_ = JS_THIS_OBJECT(cx, vp); + if (!this_) + return 0; + return (PerfMeasurement*) + JS_GetInstancePrivate(cx, this_, &pm_class, JS_ARGV(cx, vp)); +} + +namespace JS { + +JSObject* +RegisterPerfMeasurement(JSContext *cx, JSObject *global) +{ + JSObject *prototype = JS_InitClass(cx, global, 0 /* parent */, + &pm_class, pm_construct, 1, + pm_props, pm_fns, 0, 0); + if (!prototype) + return 0; + + JSObject *ctor = JS_GetConstructor(cx, prototype); + if (!ctor) + return 0; + + for (const pm_const *c = pm_consts; c->name; c++) { + if (!JS_DefineProperty(cx, ctor, c->name, INT_TO_JSVAL(c->value), + JS_PropertyStub, JS_StrictPropertyStub, PM_CATTRS)) + return 0; + } + + if (!JS_FreezeObject(cx, prototype) || + !JS_FreezeObject(cx, ctor)) { + return 0; + } + + return prototype; +} + +PerfMeasurement* +ExtractPerfMeasurement(jsval wrapper) +{ + if (JSVAL_IS_PRIMITIVE(wrapper)) + return 0; + + // This is what JS_GetInstancePrivate does internally. We can't + // call JS_anything from here, because we don't have a JSContext. + JSObject *obj = JSVAL_TO_OBJECT(wrapper); + if (obj->getClass() != js::Valueify(&pm_class)) + return 0; + + return (PerfMeasurement*) obj->getPrivate(); +} + +} // namespace JS diff --git a/js/src/perf/jsperf.h b/js/src/perf/jsperf.h new file mode 100644 index 0000000..aed019a --- /dev/null +++ b/js/src/perf/jsperf.h @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Zack Weinberg (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsperf_h___ +#define jsperf_h___ + +#include "jsapi.h" + +namespace JS { + +/* + * JS::PerfMeasurement is a generic way to access detailed performance + * measurement APIs provided by your operating system. The details of + * exactly how this works and what can be measured are highly + * system-specific, but this interface is (one hopes) implementable + * on top of all of them. + * + * To use this API, create a PerfMeasurement object, passing its + * constructor a bitmask indicating which events you are interested + * in. Thereafter, Start() zeroes all counters and starts timing; + * Stop() stops timing again; and the counters for the events you + * requested are available as data values after calling Stop(). The + * object may be reused for many measurements. + */ +class JS_FRIEND_API(PerfMeasurement) +{ + protected: + // Implementation-specific data, if any. + void* impl; + + public: + /* + * Events that may be measured. Taken directly from the list of + * "generalized hardware performance event types" in the Linux + * perf_event API, plus some of the "software events". + */ + enum EventMask { + CPU_CYCLES = 0x00000001, + INSTRUCTIONS = 0x00000002, + CACHE_REFERENCES = 0x00000004, + CACHE_MISSES = 0x00000008, + BRANCH_INSTRUCTIONS = 0x00000010, + BRANCH_MISSES = 0x00000020, + BUS_CYCLES = 0x00000040, + PAGE_FAULTS = 0x00000080, + MAJOR_PAGE_FAULTS = 0x00000100, + CONTEXT_SWITCHES = 0x00000200, + CPU_MIGRATIONS = 0x00000400, + + ALL = 0x000007ff, + NUM_MEASURABLE_EVENTS = 11 + }; + + /* + * Bitmask of events that will be measured when this object is + * active (between Start() and Stop()). This may differ from the + * bitmask passed to the constructor if the platform does not + * support measuring all of the requested events. + */ + const EventMask eventsMeasured; + + /* + * Counters for each measurable event. + * Immediately after one of these objects is created, all of the + * counters for enabled events will be zero, and all of the + * counters for disabled events will be uint64(-1). + */ + uint64 cpu_cycles; + uint64 instructions; + uint64 cache_references; + uint64 cache_misses; + uint64 branch_instructions; + uint64 branch_misses; + uint64 bus_cycles; + uint64 page_faults; + uint64 major_page_faults; + uint64 context_switches; + uint64 cpu_migrations; + + /* + * Prepare to measure the indicated set of events. If not all of + * the requested events can be measured on the current platform, + * then the eventsMeasured bitmask will only include the subset of + * |toMeasure| corresponding to the events that can be measured. + */ + PerfMeasurement(EventMask toMeasure); + + /* Done with this set of measurements, tear down OS-level state. */ + ~PerfMeasurement(); + + /* Start a measurement cycle. */ + void start(); + + /* + * End a measurement cycle, and for each enabled counter, add the + * number of measured events of that type to the appropriate + * visible variable. + */ + void stop(); + + /* Reset all enabled counters to zero. */ + void reset(); + + /* + * True if this platform supports measuring _something_, i.e. it's + * not using the stub implementation. + */ + static bool canMeasureSomething(); +}; + +/* Inject a Javascript wrapper around the above C++ class into the + * Javascript object passed as an argument (this will normally be a + * global object). The JS-visible API is identical to the C++ API. + */ +extern JS_FRIEND_API(JSObject*) + RegisterPerfMeasurement(JSContext *cx, JSObject *global); + +/* + * Given a jsval which contains an instance of the aforementioned + * wrapper class, extract the C++ object. Returns NULL if the + * jsval is not an instance of the wrapper. + */ +extern JS_FRIEND_API(PerfMeasurement*) + ExtractPerfMeasurement(jsval wrapper); + +} // namespace JS + +#endif // jsperf_h___ diff --git a/js/src/perf/pm_linux.cpp b/js/src/perf/pm_linux.cpp new file mode 100644 index 0000000..bcd5615 --- /dev/null +++ b/js/src/perf/pm_linux.cpp @@ -0,0 +1,343 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Zack Weinberg (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsperf.h" +#include "jsutil.h" + +/* This variant of nsIPerfMeasurement uses the perf_event interface + * added in Linux 2.6.31. We key compilation of this file off the + * existence of . + */ + +#include +#include +#include +#include +#include +#include +#include + +// As of July 2010, this system call has not been added to the +// C library, so we have to provide our own wrapper function. +// If this code runs on a kernel that does not implement the +// system call (2.6.30 or older) nothing unpredictable will +// happen - it will just always fail and return -1. +static int +sys_perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu, + int group_fd, unsigned long flags) +{ + return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); +} + +namespace { + +using JS::PerfMeasurement; +typedef PerfMeasurement::EventMask EventMask; + +// Additional state required by this implementation. +struct Impl +{ + // Each active counter corresponds to an open file descriptor. + int f_cpu_cycles; + int f_instructions; + int f_cache_references; + int f_cache_misses; + int f_branch_instructions; + int f_branch_misses; + int f_bus_cycles; + int f_page_faults; + int f_major_page_faults; + int f_context_switches; + int f_cpu_migrations; + + // Counter group leader, for Start and Stop. + int group_leader; + + // Whether counters are running. + bool running; + + Impl(); + ~Impl(); + + EventMask init(EventMask toMeasure); + void start(); + void stop(PerfMeasurement* counters); +}; + +// Mapping from our event bitmask to codes passed into the kernel, and +// to fields in the PerfMeasurement and PerfMeasurement::impl structures. +static const struct +{ + EventMask bit; + uint32 type; + uint32 config; + uint64 PerfMeasurement::* counter; + int Impl::* fd; +} kSlots[PerfMeasurement::NUM_MEASURABLE_EVENTS] = { +#define HW(mask, constant, fieldname) \ + { PerfMeasurement::mask, PERF_TYPE_HARDWARE, PERF_COUNT_HW_##constant, \ + &PerfMeasurement::fieldname, &Impl::f_##fieldname } +#define SW(mask, constant, fieldname) \ + { PerfMeasurement::mask, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_##constant, \ + &PerfMeasurement::fieldname, &Impl::f_##fieldname } + + HW(CPU_CYCLES, CPU_CYCLES, cpu_cycles), + HW(INSTRUCTIONS, INSTRUCTIONS, instructions), + HW(CACHE_REFERENCES, CACHE_REFERENCES, cache_references), + HW(CACHE_MISSES, CACHE_MISSES, cache_misses), + HW(BRANCH_INSTRUCTIONS, BRANCH_INSTRUCTIONS, branch_instructions), + HW(BRANCH_MISSES, BRANCH_MISSES, branch_misses), + HW(BUS_CYCLES, BUS_CYCLES, bus_cycles), + SW(PAGE_FAULTS, PAGE_FAULTS, page_faults), + SW(MAJOR_PAGE_FAULTS, PAGE_FAULTS_MAJ, major_page_faults), + SW(CONTEXT_SWITCHES, CONTEXT_SWITCHES, context_switches), + SW(CPU_MIGRATIONS, CPU_MIGRATIONS, cpu_migrations), + +#undef HW +#undef SW +}; + +Impl::Impl() + : f_cpu_cycles(-1), + f_instructions(-1), + f_cache_references(-1), + f_cache_misses(-1), + f_branch_instructions(-1), + f_branch_misses(-1), + f_bus_cycles(-1), + f_page_faults(-1), + f_major_page_faults(-1), + f_context_switches(-1), + f_cpu_migrations(-1), + group_leader(-1), + running(false) +{ +} + +Impl::~Impl() +{ + // Close all active counter descriptors. Take care to do the group + // leader last (this may not be necessary, but it's unclear what + // happens if you close the group leader out from under a group). + for (int i = 0; i < PerfMeasurement::NUM_MEASURABLE_EVENTS; i++) { + int fd = this->*(kSlots[i].fd); + if (fd != -1 && fd != group_leader) + close(fd); + } + + if (group_leader != -1) + close(group_leader); +} + +EventMask +Impl::init(EventMask toMeasure) +{ + JS_ASSERT(group_leader == -1); + if (!toMeasure) + return EventMask(0); + + EventMask measured = EventMask(0); + struct perf_event_attr attr; + for (int i = 0; i < PerfMeasurement::NUM_MEASURABLE_EVENTS; i++) { + if (!(toMeasure & kSlots[i].bit)) + continue; + + memset(&attr, 0, sizeof(attr)); + attr.size = sizeof(attr); + + // Set the type and config fields to indicate the counter we + // want to enable. We want read format 0, and we're not using + // sampling, so leave those fields unset. + attr.type = kSlots[i].type; + attr.config = kSlots[i].config; + + // If this will be the group leader it should start off + // disabled. Otherwise it should start off enabled (but blocked + // on the group leader). + if (group_leader == -1) + attr.disabled = 1; + + // The rest of the bit fields are really poorly documented. + // For instance, I have *no idea* whether we should be setting + // the inherit, inherit_stat, or task flags. I'm pretty sure + // we do want to set mmap and comm, and not any of the ones I + // haven't mentioned. + attr.mmap = 1; + attr.comm = 1; + + int fd = sys_perf_event_open(&attr, + 0 /* trace self */, + -1 /* on any cpu */, + group_leader, + 0 /* no flags presently defined */); + if (fd == -1) + continue; + + measured = EventMask(measured | kSlots[i].bit); + this->*(kSlots[i].fd) = fd; + if (group_leader == -1) + group_leader = fd; + } + return measured; +} + +void +Impl::start() +{ + if (running || group_leader == -1) + return; + + running = true; + ioctl(group_leader, PERF_EVENT_IOC_ENABLE, 0); +} + +void +Impl::stop(PerfMeasurement* counters) +{ + // This scratch buffer is to ensure that we have read all the + // available data, even if that's more than we expect. + unsigned char buf[1024]; + + if (!running || group_leader == -1) + return; + + ioctl(group_leader, PERF_EVENT_IOC_DISABLE, 0); + running = false; + + // read out and reset all the counter values + for (int i = 0; i < PerfMeasurement::NUM_MEASURABLE_EVENTS; i++) { + int fd = this->*(kSlots[i].fd); + if (fd == -1) + continue; + + if (read(fd, buf, sizeof(buf)) == sizeof(uint64)) { + uint64 cur; + memcpy(&cur, buf, sizeof(uint64)); + counters->*(kSlots[i].counter) += cur; + } + + // Reset the counter regardless of whether the read did what + // we expected. + ioctl(fd, PERF_EVENT_IOC_RESET, 0); + } +} + +} // anonymous namespace + + +namespace JS { + +#define initCtr(flag) ((eventsMeasured & flag) ? 0 : -1) + +PerfMeasurement::PerfMeasurement(PerfMeasurement::EventMask toMeasure) + : impl(js_new()), + eventsMeasured(impl ? static_cast(impl)->init(toMeasure) + : EventMask(0)), + cpu_cycles(initCtr(CPU_CYCLES)), + instructions(initCtr(INSTRUCTIONS)), + cache_references(initCtr(CACHE_REFERENCES)), + cache_misses(initCtr(CACHE_MISSES)), + branch_instructions(initCtr(BRANCH_INSTRUCTIONS)), + branch_misses(initCtr(BRANCH_MISSES)), + bus_cycles(initCtr(BUS_CYCLES)), + page_faults(initCtr(PAGE_FAULTS)), + major_page_faults(initCtr(MAJOR_PAGE_FAULTS)), + context_switches(initCtr(CONTEXT_SWITCHES)), + cpu_migrations(initCtr(CPU_MIGRATIONS)) +{ +} + +#undef initCtr + +PerfMeasurement::~PerfMeasurement() +{ + js_delete(static_cast(impl)); +} + +void +PerfMeasurement::start() +{ + if (impl) + static_cast(impl)->start(); +} + +void +PerfMeasurement::stop() +{ + if (impl) + static_cast(impl)->stop(this); +} + +void +PerfMeasurement::reset() +{ + for (int i = 0; i < NUM_MEASURABLE_EVENTS; i++) { + if (eventsMeasured & kSlots[i].bit) + this->*(kSlots[i].counter) = 0; + else + this->*(kSlots[i].counter) = -1; + } +} + +bool +PerfMeasurement::canMeasureSomething() +{ + // Find out if the kernel implements the performance measurement + // API. If it doesn't, syscall(__NR_perf_event_open, ...) is + // guaranteed to return -1 and set errno to ENOSYS. + // + // We set up input parameters that should provoke an EINVAL error + // from a kernel that does implement perf_event_open, but we can't + // be sure it will (newer kernels might add more event types), so + // we have to take care to close any valid fd it might return. + + struct perf_event_attr attr; + memset(&attr, 0, sizeof(attr)); + attr.size = sizeof(attr); + attr.type = PERF_TYPE_MAX; + + int fd = sys_perf_event_open(&attr, 0, -1, -1, 0); + if (fd >= 0) { + close(fd); + return true; + } else { + return errno != ENOSYS; + } +} + +} // namespace JS diff --git a/js/src/perf/pm_stub.cpp b/js/src/perf/pm_stub.cpp new file mode 100644 index 0000000..caa08a2 --- /dev/null +++ b/js/src/perf/pm_stub.cpp @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Zack Weinberg (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "jsperf.h" + +namespace JS { + +PerfMeasurement::PerfMeasurement(PerfMeasurement::EventMask) + : impl(0), + eventsMeasured(EventMask(0)), + cpu_cycles(-1), + instructions(-1), + cache_references(-1), + cache_misses(-1), + branch_instructions(-1), + branch_misses(-1), + bus_cycles(-1), + page_faults(-1), + major_page_faults(-1), + context_switches(-1), + cpu_migrations(-1) +{ +} + +PerfMeasurement::~PerfMeasurement() +{ +} + +void +PerfMeasurement::start() +{ +} + +void +PerfMeasurement::stop() +{ +} + +void +PerfMeasurement::reset() +{ + cpu_cycles = -1; + instructions = -1; + cache_references = -1; + cache_misses = -1; + branch_instructions = -1; + branch_misses = -1; + bus_cycles = -1; + page_faults = -1; + major_page_faults = -1; + context_switches = -1; + cpu_migrations = -1; +} + +bool +PerfMeasurement::canMeasureSomething() +{ + return false; +} + +} // namespace JS diff --git a/js/src/perfect.js b/js/src/perfect.js new file mode 100644 index 0000000..aeca121 --- /dev/null +++ b/js/src/perfect.js @@ -0,0 +1,39 @@ +// Some simple testing of new, eval and some string stuff. + +// constructor -- expression array initialization +function ExprArray(n,v) +{ + // Initializes n values to v coerced to a string. + for (var i = 0; i < n; i++) { + this[i] = "" + v; + } +} + + +// Print the perfect numbers up to n and the sum expression for n's divisors. +function perfect(n) +{ + print("The perfect numbers up to " + n + " are:"); + + // We build sumOfDivisors[i] to hold a string expression for + // the sum of the divisors of i, excluding i itself. + var sumOfDivisors = new ExprArray(n+1,1); + for (var divisor = 2; divisor <= n; divisor++) { + for (var j = divisor + divisor; j <= n; j += divisor) { + sumOfDivisors[j] += " + " + divisor; + } + // At this point everything up to 'divisor' has its sumOfDivisors + // expression calculated, so we can determine whether it's perfect + // already by evaluating. + if (eval(sumOfDivisors[divisor]) == divisor) { + print("" + divisor + " = " + sumOfDivisors[divisor]); + } + } + print("That's all."); +} + + +print("\nA number is 'perfect' if it is equal to the sum of its") +print("divisors (excluding itself).\n"); +perfect(500); + diff --git a/js/src/plify_jsdhash.sed b/js/src/plify_jsdhash.sed new file mode 100644 index 0000000..90b3692 --- /dev/null +++ b/js/src/plify_jsdhash.sed @@ -0,0 +1,39 @@ +/ * Double hashing implementation./a\ +\ * GENERATED BY js/src/plify_jsdhash.sed -- DO NOT EDIT!!! +/ * Double hashing, a la Knuth 6./a\ +\ * GENERATED BY js/src/plify_jsdhash.sed -- DO NOT EDIT!!! +s/jsdhash_h___/pldhash_h___/ +s/jsdhash\.bigdump/pldhash.bigdump/ +s/jstypes\.h/nscore.h/ +s/jsbit\.h/prbit.h/ +s/jsdhash\.h/pldhash.h/ +s/jsdhash\.c/pldhash.c/ +s/jsdhash:/pldhash:/ +s/jsutil\.h/nsDebug.h/ +s/JS_DHASH/PL_DHASH/g +s/JS_DHash/PL_DHash/g +s/JSDHash/PLDHash/g +s/JSHash/PLHash/g +s/uint8 /PRUint8/g +s/uint16 /PRUint16/g +s/uint32 /PRUint32/g +s/\([^U]\)int8 /\1PRInt8/g +s/\([^U]\)int16 /\1PRInt16/g +s/\([^U]\)int32 /\1PRInt32/g +s/uint8/PRUint8/g +s/uint16/PRUint16/g +s/uint32/PRUint32/g +s/\([^U]\)int8/\1PRInt8/g +s/\([^U]\)int16/\1PRInt16/g +s/\([^U]\)int32/\1PRInt32/g +s/JSBool/PRBool/g +s/extern JS_PUBLIC_API(\([^()]*\))/NS_COM_GLUE \1/ +s/JS_PUBLIC_API(\([^()]*\))/\1/ +s/JS_NewDHashTable/PL_NewDHashTable/ +s/JS_ASSERT(0)/NS_NOTREACHED("0")/ +s/\( *\)JS_ASSERT(\(.*\));/\1NS_ASSERTION(\2,\n\1 "\2");/ +s/JSDHASH_ONELINE_ASSERT(\(.*\));/NS_ASSERTION(\1, "\1");/ +s/JS_UNLIKELY/NS_UNLIKELY/g +s/JS_LIKELY/NS_LIKELY/g +s/JS_/PR_/g +s/fprintf(stderr,/printf_stderr(/ diff --git a/js/src/prmjtime.cpp b/js/src/prmjtime.cpp new file mode 100644 index 0000000..d0114e8 --- /dev/null +++ b/js/src/prmjtime.cpp @@ -0,0 +1,872 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * PR time code. + */ +#ifdef SOLARIS +#define _REENTRANT 1 +#endif +#include +#include + +#include "jsstdint.h" +#include "jstypes.h" +#include "jsutil.h" + +#include "jsprf.h" +#include "jslock.h" +#include "prmjtime.h" + +#define PRMJ_DO_MILLISECONDS 1 + +#ifdef XP_OS2 +#include +#endif +#ifdef XP_WIN +#include +#include +#include /* for fabs */ +#include /* for timeBegin/EndPeriod */ +/* VC++ 8.0 or later, and not WINCE */ +#if _MSC_VER >= 1400 && !defined(WINCE) +#define NS_HAVE_INVALID_PARAMETER_HANDLER 1 +#endif +#ifdef NS_HAVE_INVALID_PARAMETER_HANDLER +#include /* for _set_invalid_parameter_handler */ +#include /* for _CrtSetReportMode */ +#endif + +#ifdef JS_THREADSAFE +#include +#endif + +#endif + +#if defined(XP_UNIX) || defined(XP_BEOS) + +#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris */ +extern int gettimeofday(struct timeval *tv); +#endif + +#include + +#endif /* XP_UNIX */ + +#define PRMJ_YEAR_DAYS 365L +#define PRMJ_FOUR_YEARS_DAYS (4 * PRMJ_YEAR_DAYS + 1) +#define PRMJ_CENTURY_DAYS (25 * PRMJ_FOUR_YEARS_DAYS - 1) +#define PRMJ_FOUR_CENTURIES_DAYS (4 * PRMJ_CENTURY_DAYS + 1) +#define PRMJ_HOUR_SECONDS 3600L +#define PRMJ_DAY_SECONDS (24L * PRMJ_HOUR_SECONDS) +#define PRMJ_YEAR_SECONDS (PRMJ_DAY_SECONDS * PRMJ_YEAR_DAYS) +#define PRMJ_MAX_UNIX_TIMET 2145859200L /*time_t value equiv. to 12/31/2037 */ + +/* Get the local time. localtime_r is preferred as it is reentrant. */ +static inline bool +ComputeLocalTime(time_t local, struct tm *ptm) +{ +#ifdef HAVE_LOCALTIME_R + return localtime_r(&local, ptm); +#else + struct tm *otm = localtime(&local); + if (!otm) + return false; + *ptm = *otm; + return true; +#endif +} + +/* + * get the difference in seconds between this time zone and UTC (GMT) + */ +JSInt32 +PRMJ_LocalGMTDifference() +{ +#if defined(XP_WIN) && !defined(WINCE) + /* Windows does not follow POSIX. Updates to the + * TZ environment variable are not reflected + * immediately on that platform as they are + * on UNIX systems without this call. + */ + _tzset(); +#endif + + /* + * Get the difference between this time zone and GMT, by checking the local + * time for days 0 and 180 of 1970, using a date for which daylight savings + * time was not in effect. + */ + int day = 0; + struct tm tm; + + if (!ComputeLocalTime(0, &tm)) + return 0; + if (tm.tm_isdst > 0) { + day = 180; + if (!ComputeLocalTime(PRMJ_DAY_SECONDS * day, &tm)) + return 0; + } + + int time = (tm.tm_hour * 3600) + (tm.tm_min * 60) + tm.tm_sec; + time = PRMJ_DAY_SECONDS - time; + + if (tm.tm_yday == day) + time -= PRMJ_DAY_SECONDS; + + return time; +} + +/* Constants for GMT offset from 1970 */ +#define G1970GMTMICROHI 0x00dcdcad /* micro secs to 1970 hi */ +#define G1970GMTMICROLOW 0x8b3fa000 /* micro secs to 1970 low */ + +#define G2037GMTMICROHI 0x00e45fab /* micro secs to 2037 high */ +#define G2037GMTMICROLOW 0x7a238000 /* micro secs to 2037 low */ + +#ifdef HAVE_SYSTEMTIMETOFILETIME + +static const JSInt64 win2un = JSLL_INIT(0x19DB1DE, 0xD53E8000); + +#define FILETIME2INT64(ft) (((JSInt64)ft.dwHighDateTime) << 32LL | (JSInt64)ft.dwLowDateTime) + +#endif + +#if defined(HAVE_GETSYSTEMTIMEASFILETIME) || defined(HAVE_SYSTEMTIMETOFILETIME) + +#if defined(HAVE_GETSYSTEMTIMEASFILETIME) +inline void +LowResTime(LPFILETIME lpft) +{ + GetSystemTimeAsFileTime(lpft); +} +#elif defined(HAVE_SYSTEMTIMETOFILETIME) +inline void +LowResTime(LPFILETIME lpft) +{ + GetCurrentFT(lpft); +} +#else +#error "No implementation of PRMJ_Now was selected." +#endif + +typedef struct CalibrationData { + long double freq; /* The performance counter frequency */ + long double offset; /* The low res 'epoch' */ + long double timer_offset; /* The high res 'epoch' */ + + /* The last high res time that we returned since recalibrating */ + JSInt64 last; + + JSBool calibrated; + +#ifdef JS_THREADSAFE + CRITICAL_SECTION data_lock; + CRITICAL_SECTION calibration_lock; +#endif +#ifdef WINCE + JSInt64 granularity; +#endif +} CalibrationData; + +static CalibrationData calibration = { 0 }; + +static void +NowCalibrate() +{ + FILETIME ft, ftStart; + LARGE_INTEGER liFreq, now; + + if (calibration.freq == 0.0) { + if(!QueryPerformanceFrequency(&liFreq)) { + /* High-performance timer is unavailable */ + calibration.freq = -1.0; + } else { + calibration.freq = (long double) liFreq.QuadPart; + } + } + if (calibration.freq > 0.0) { + JSInt64 calibrationDelta = 0; + + /* By wrapping a timeBegin/EndPeriod pair of calls around this loop, + the loop seems to take much less time (1 ms vs 15ms) on Vista. */ + timeBeginPeriod(1); + LowResTime(&ftStart); + do { + LowResTime(&ft); + } while (memcmp(&ftStart,&ft, sizeof(ft)) == 0); + timeEndPeriod(1); + +#ifdef WINCE + calibration.granularity = (FILETIME2INT64(ft) - + FILETIME2INT64(ftStart))/10; +#endif + /* + calibrationDelta = (FILETIME2INT64(ft) - FILETIME2INT64(ftStart))/10; + fprintf(stderr, "Calibration delta was %I64d us\n", calibrationDelta); + */ + + QueryPerformanceCounter(&now); + + calibration.offset = (long double) FILETIME2INT64(ft); + calibration.timer_offset = (long double) now.QuadPart; + + /* The windows epoch is around 1600. The unix epoch is around + 1970. win2un is the difference (in windows time units which + are 10 times more highres than the JS time unit) */ + calibration.offset -= win2un; + calibration.offset *= 0.1; + calibration.last = 0; + + calibration.calibrated = JS_TRUE; + } +} + +#define CALIBRATIONLOCK_SPINCOUNT 0 +#define DATALOCK_SPINCOUNT 4096 +#define LASTLOCK_SPINCOUNT 4096 + +#ifdef JS_THREADSAFE +static PRStatus +NowInit(void) +{ + memset(&calibration, 0, sizeof(calibration)); + NowCalibrate(); +#ifdef WINCE + InitializeCriticalSection(&calibration.calibration_lock); + InitializeCriticalSection(&calibration.data_lock); +#else + InitializeCriticalSectionAndSpinCount(&calibration.calibration_lock, CALIBRATIONLOCK_SPINCOUNT); + InitializeCriticalSectionAndSpinCount(&calibration.data_lock, DATALOCK_SPINCOUNT); +#endif + return PR_SUCCESS; +} + +void +PRMJ_NowShutdown() +{ + DeleteCriticalSection(&calibration.calibration_lock); + DeleteCriticalSection(&calibration.data_lock); +} + +#define MUTEX_LOCK(m) EnterCriticalSection(m) +#define MUTEX_TRYLOCK(m) TryEnterCriticalSection(m) +#define MUTEX_UNLOCK(m) LeaveCriticalSection(m) +#ifdef WINCE +#define MUTEX_SETSPINCOUNT(m, c) +#else +#define MUTEX_SETSPINCOUNT(m, c) SetCriticalSectionSpinCount((m),(c)) +#endif + +static PRCallOnceType calibrationOnce = { 0 }; + +#else + +#define MUTEX_LOCK(m) +#define MUTEX_TRYLOCK(m) 1 +#define MUTEX_UNLOCK(m) +#define MUTEX_SETSPINCOUNT(m, c) + +#endif + +#endif /* HAVE_GETSYSTEMTIMEASFILETIME */ + + +#if defined(XP_OS2) +JSInt64 +PRMJ_Now(void) +{ + JSInt64 s, us, ms2us, s2us; + struct timeb b; + + ftime(&b); + JSLL_UI2L(ms2us, PRMJ_USEC_PER_MSEC); + JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC); + JSLL_UI2L(s, b.time); + JSLL_UI2L(us, b.millitm); + JSLL_MUL(us, us, ms2us); + JSLL_MUL(s, s, s2us); + JSLL_ADD(s, s, us); + return s; +} + +#elif defined(XP_UNIX) || defined(XP_BEOS) +JSInt64 +PRMJ_Now(void) +{ + struct timeval tv; + JSInt64 s, us, s2us; + +#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris */ + gettimeofday(&tv); +#else + gettimeofday(&tv, 0); +#endif /* _SVID_GETTOD */ + JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC); + JSLL_UI2L(s, tv.tv_sec); + JSLL_UI2L(us, tv.tv_usec); + JSLL_MUL(s, s, s2us); + JSLL_ADD(s, s, us); + return s; +} + +#else +/* + +Win32 python-esque pseudo code +Please see bug 363258 for why the win32 timing code is so complex. + +calibration mutex : Win32CriticalSection(spincount=0) +data mutex : Win32CriticalSection(spincount=4096) + +def NowInit(): + init mutexes + PRMJ_NowCalibration() + +def NowCalibration(): + expensive up-to-15ms call + +def PRMJ_Now(): + returnedTime = 0 + needCalibration = False + cachedOffset = 0.0 + calibrated = False + PR_CallOnce(PRMJ_NowInit) + do + if not global.calibrated or needCalibration: + acquire calibration mutex + acquire data mutex + + // Only recalibrate if someone didn't already + if cachedOffset == calibration.offset: + // Have all waiting threads immediately wait + set data mutex spin count = 0 + PRMJ_NowCalibrate() + calibrated = 1 + + set data mutex spin count = default + release data mutex + release calibration mutex + + calculate lowres time + + if highres timer available: + acquire data mutex + calculate highres time + cachedOffset = calibration.offset + highres time = calibration.last = max(highres time, calibration.last) + release data mutex + + get kernel tick interval + + if abs(highres - lowres) < kernel tick: + returnedTime = highres time + needCalibration = False + else: + if calibrated: + returnedTime = lowres + needCalibration = False + else: + needCalibration = True + else: + returnedTime = lowres + while needCalibration + +*/ + +// We parameterize the delay count just so that shell builds can +// set it to 0 in order to get high-resolution benchmarking. +// 10 seems to be the number of calls to load with a blank homepage. +int CALIBRATION_DELAY_COUNT = 10; + +JSInt64 +PRMJ_Now(void) +{ + static int nCalls = 0; + long double lowresTime, highresTimerValue; + FILETIME ft; + LARGE_INTEGER now; + JSBool calibrated = JS_FALSE; + JSBool needsCalibration = JS_FALSE; + JSInt64 returnedTime; + long double cachedOffset = 0.0; + + /* To avoid regressing startup time (where high resolution is likely + not needed), give the old behavior for the first few calls. + This does not appear to be needed on Vista as the timeBegin/timeEndPeriod + calls seem to immediately take effect. */ + int thiscall = JS_ATOMIC_INCREMENT(&nCalls); + if (thiscall <= CALIBRATION_DELAY_COUNT) { + LowResTime(&ft); + return (FILETIME2INT64(ft)-win2un)/10L; + } + + /* For non threadsafe platforms, NowInit is not necessary */ +#ifdef JS_THREADSAFE + PR_CallOnce(&calibrationOnce, NowInit); +#endif + do { + if (!calibration.calibrated || needsCalibration) { + MUTEX_LOCK(&calibration.calibration_lock); + MUTEX_LOCK(&calibration.data_lock); + + /* Recalibrate only if no one else did before us */ + if(calibration.offset == cachedOffset) { + /* Since calibration can take a while, make any other + threads immediately wait */ + MUTEX_SETSPINCOUNT(&calibration.data_lock, 0); + + NowCalibrate(); + + calibrated = JS_TRUE; + + /* Restore spin count */ + MUTEX_SETSPINCOUNT(&calibration.data_lock, DATALOCK_SPINCOUNT); + } + MUTEX_UNLOCK(&calibration.data_lock); + MUTEX_UNLOCK(&calibration.calibration_lock); + } + + + /* Calculate a low resolution time */ + LowResTime(&ft); + lowresTime = 0.1*(long double)(FILETIME2INT64(ft) - win2un); + + if (calibration.freq > 0.0) { + long double highresTime, diff; + + DWORD timeAdjustment, timeIncrement; + BOOL timeAdjustmentDisabled; + + /* Default to 15.625 ms if the syscall fails */ + long double skewThreshold = 15625.25; + /* Grab high resolution time */ + QueryPerformanceCounter(&now); + highresTimerValue = (long double)now.QuadPart; + + MUTEX_LOCK(&calibration.data_lock); + highresTime = calibration.offset + PRMJ_USEC_PER_SEC* + (highresTimerValue-calibration.timer_offset)/calibration.freq; + cachedOffset = calibration.offset; + + /* On some dual processor/core systems, we might get an earlier time + so we cache the last time that we returned */ + calibration.last = JS_MAX(calibration.last,(JSInt64)highresTime); + returnedTime = calibration.last; + MUTEX_UNLOCK(&calibration.data_lock); + +#ifdef WINCE + /* Get an estimate of clock ticks per second from our own test */ + skewThreshold = calibration.granularity; +#else + /* Rather than assume the NT kernel ticks every 15.6ms, ask it */ + if (GetSystemTimeAdjustment(&timeAdjustment, + &timeIncrement, + &timeAdjustmentDisabled)) { + if (timeAdjustmentDisabled) { + /* timeAdjustment is in units of 100ns */ + skewThreshold = timeAdjustment/10.0; + } else { + /* timeIncrement is in units of 100ns */ + skewThreshold = timeIncrement/10.0; + } + } +#endif + /* Check for clock skew */ + diff = lowresTime - highresTime; + + /* For some reason that I have not determined, the skew can be + up to twice a kernel tick. This does not seem to happen by + itself, but I have only seen it triggered by another program + doing some kind of file I/O. The symptoms are a negative diff + followed by an equally large positive diff. */ + if (fabs(diff) > 2*skewThreshold) { + /*fprintf(stderr,"Clock skew detected (diff = %f)!\n", diff);*/ + + if (calibrated) { + /* If we already calibrated once this instance, and the + clock is still skewed, then either the processor(s) are + wildly changing clockspeed or the system is so busy that + we get switched out for long periods of time. In either + case, it would be infeasible to make use of high + resolution results for anything, so let's resort to old + behavior for this call. It's possible that in the + future, the user will want the high resolution timer, so + we don't disable it entirely. */ + returnedTime = (JSInt64)lowresTime; + needsCalibration = JS_FALSE; + } else { + /* It is possible that when we recalibrate, we will return a + value less than what we have returned before; this is + unavoidable. We cannot tell the different between a + faulty QueryPerformanceCounter implementation and user + changes to the operating system time. Since we must + respect user changes to the operating system time, we + cannot maintain the invariant that Date.now() never + decreases; the old implementation has this behavior as + well. */ + needsCalibration = JS_TRUE; + } + } else { + /* No detectable clock skew */ + returnedTime = (JSInt64)highresTime; + needsCalibration = JS_FALSE; + } + } else { + /* No high resolution timer is available, so fall back */ + returnedTime = (JSInt64)lowresTime; + } + } while (needsCalibration); + + return returnedTime; +} +#endif + +#ifdef NS_HAVE_INVALID_PARAMETER_HANDLER +static void +PRMJ_InvalidParameterHandler(const wchar_t *expression, + const wchar_t *function, + const wchar_t *file, + unsigned int line, + uintptr_t pReserved) +{ + /* empty */ +} +#endif + +/* Format a time value into a buffer. Same semantics as strftime() */ +size_t +PRMJ_FormatTime(char *buf, int buflen, const char *fmt, PRMJTime *prtm) +{ + size_t result = 0; +#if defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) + struct tm a; + int fake_tm_year = 0; +#ifdef NS_HAVE_INVALID_PARAMETER_HANDLER + _invalid_parameter_handler oldHandler; + int oldReportMode; +#endif + + memset(&a, 0, sizeof(struct tm)); + + a.tm_sec = prtm->tm_sec; + a.tm_min = prtm->tm_min; + a.tm_hour = prtm->tm_hour; + a.tm_mday = prtm->tm_mday; + a.tm_mon = prtm->tm_mon; + a.tm_wday = prtm->tm_wday; + + /* + * On systems where |struct tm| has members tm_gmtoff and tm_zone, we + * must fill in those values, or else strftime will return wrong results + * (e.g., bug 511726, bug 554338). + */ +#if defined(HAVE_LOCALTIME_R) && defined(HAVE_TM_ZONE_TM_GMTOFF) + { + /* + * Fill out |td| to the time represented by |prtm|, leaving the + * timezone fields zeroed out. localtime_r will then fill in the + * timezone fields for that local time according to the system's + * timezone parameters. + */ + struct tm td; + memset(&td, 0, sizeof(td)); + td.tm_sec = prtm->tm_sec; + td.tm_min = prtm->tm_min; + td.tm_hour = prtm->tm_hour; + td.tm_mday = prtm->tm_mday; + td.tm_mon = prtm->tm_mon; + td.tm_wday = prtm->tm_wday; + td.tm_year = prtm->tm_year - 1900; + td.tm_yday = prtm->tm_yday; + td.tm_isdst = prtm->tm_isdst; + time_t t = mktime(&td); + localtime_r(&t, &td); + + a.tm_gmtoff = td.tm_gmtoff; + a.tm_zone = td.tm_zone; + } +#endif + + /* + * Years before 1900 and after 9999 cause strftime() to abort on Windows. + * To avoid that we replace it with FAKE_YEAR_BASE + year % 100 and then + * replace matching substrings in the strftime() result with the real year. + * Note that FAKE_YEAR_BASE should be a multiple of 100 to make 2-digit + * year formats (%y) work correctly (since we won't find the fake year + * in that case). + * e.g. new Date(1873, 0).toLocaleFormat('%Y %y') => "1873 73" + * See bug 327869. + */ +#define FAKE_YEAR_BASE 9900 + if (prtm->tm_year < 1900 || prtm->tm_year > 9999) { + fake_tm_year = FAKE_YEAR_BASE + prtm->tm_year % 100; + a.tm_year = fake_tm_year - 1900; + } + else { + a.tm_year = prtm->tm_year - 1900; + } + a.tm_yday = prtm->tm_yday; + a.tm_isdst = prtm->tm_isdst; + + /* + * Even with the above, SunOS 4 seems to detonate if tm_zone and tm_gmtoff + * are null. This doesn't quite work, though - the timezone is off by + * tzoff + dst. (And mktime seems to return -1 for the exact dst + * changeover time.) + */ + +#ifdef NS_HAVE_INVALID_PARAMETER_HANDLER + oldHandler = _set_invalid_parameter_handler(PRMJ_InvalidParameterHandler); + oldReportMode = _CrtSetReportMode(_CRT_ASSERT, 0); +#endif + + result = strftime(buf, buflen, fmt, &a); + +#ifdef NS_HAVE_INVALID_PARAMETER_HANDLER + _set_invalid_parameter_handler(oldHandler); + _CrtSetReportMode(_CRT_ASSERT, oldReportMode); +#endif + + if (fake_tm_year && result) { + char real_year[16]; + char fake_year[16]; + size_t real_year_len; + size_t fake_year_len; + char* p; + + sprintf(real_year, "%d", prtm->tm_year); + real_year_len = strlen(real_year); + sprintf(fake_year, "%d", fake_tm_year); + fake_year_len = strlen(fake_year); + + /* Replace the fake year in the result with the real year. */ + for (p = buf; (p = strstr(p, fake_year)); p += real_year_len) { + size_t new_result = result + real_year_len - fake_year_len; + if ((int)new_result >= buflen) { + return 0; + } + memmove(p + real_year_len, p + fake_year_len, strlen(p + fake_year_len)); + memcpy(p, real_year, real_year_len); + result = new_result; + *(buf + result) = '\0'; + } + } +#endif + return result; +} + +JSInt64 +DSTOffsetCache::computeDSTOffsetMilliseconds(int64 localTimeSeconds) +{ + JS_ASSERT(localTimeSeconds >= 0); + JS_ASSERT(localTimeSeconds <= MAX_UNIX_TIMET); + +#if defined(XP_WIN) && !defined(WINCE) + /* Windows does not follow POSIX. Updates to the + * TZ environment variable are not reflected + * immediately on that platform as they are + * on UNIX systems without this call. + */ + _tzset(); +#endif + + struct tm tm; + if (!ComputeLocalTime(static_cast(localTimeSeconds), &tm)) + return 0; + + JSInt32 base = PRMJ_LocalGMTDifference(); + + int32 dayoff = int32((localTimeSeconds - base) % (SECONDS_PER_HOUR * 24)); + int32 tmoff = tm.tm_sec + (tm.tm_min * SECONDS_PER_MINUTE) + + (tm.tm_hour * SECONDS_PER_HOUR); + + JSInt32 diff = tmoff - dayoff; + + if (diff < 0) + diff += SECONDS_PER_DAY; + + return diff * MILLISECONDS_PER_SECOND; +} + +JSInt64 +DSTOffsetCache::getDSTOffsetMilliseconds(JSInt64 localTimeMilliseconds, JSContext *cx) +{ + sanityCheck(); + noteOffsetCalculation(); + + JSInt64 localTimeSeconds = localTimeMilliseconds / MILLISECONDS_PER_SECOND; + + if (localTimeSeconds > MAX_UNIX_TIMET) { + localTimeSeconds = MAX_UNIX_TIMET; + } else if (localTimeSeconds < 0) { + /* Go ahead a day to make localtime work (does not work with 0). */ + localTimeSeconds = SECONDS_PER_DAY; + } + + /* + * NB: Be aware of the initial range values when making changes to this + * code: the first call to this method, with those initial range + * values, must result in a cache miss. + */ + + if (rangeStartSeconds <= localTimeSeconds && + localTimeSeconds <= rangeEndSeconds) { + noteCacheHit(); + return offsetMilliseconds; + } + + if (oldRangeStartSeconds <= localTimeSeconds && + localTimeSeconds <= oldRangeEndSeconds) { + noteCacheHit(); + return oldOffsetMilliseconds; + } + + oldOffsetMilliseconds = offsetMilliseconds; + oldRangeStartSeconds = rangeStartSeconds; + oldRangeEndSeconds = rangeEndSeconds; + + if (rangeStartSeconds <= localTimeSeconds) { + JSInt64 newEndSeconds = JS_MIN(rangeEndSeconds + RANGE_EXPANSION_AMOUNT, MAX_UNIX_TIMET); + if (newEndSeconds >= localTimeSeconds) { + JSInt64 endOffsetMilliseconds = computeDSTOffsetMilliseconds(newEndSeconds); + if (endOffsetMilliseconds == offsetMilliseconds) { + noteCacheMissIncrease(); + rangeEndSeconds = newEndSeconds; + return offsetMilliseconds; + } + + offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds); + if (offsetMilliseconds == endOffsetMilliseconds) { + noteCacheMissIncreasingOffsetChangeUpper(); + rangeStartSeconds = localTimeSeconds; + rangeEndSeconds = newEndSeconds; + } else { + noteCacheMissIncreasingOffsetChangeExpand(); + rangeEndSeconds = localTimeSeconds; + } + return offsetMilliseconds; + } + + noteCacheMissLargeIncrease(); + offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds); + rangeStartSeconds = rangeEndSeconds = localTimeSeconds; + return offsetMilliseconds; + } + + JSInt64 newStartSeconds = JS_MAX(rangeStartSeconds - RANGE_EXPANSION_AMOUNT, 0); + if (newStartSeconds <= localTimeSeconds) { + JSInt64 startOffsetMilliseconds = computeDSTOffsetMilliseconds(newStartSeconds); + if (startOffsetMilliseconds == offsetMilliseconds) { + noteCacheMissDecrease(); + rangeStartSeconds = newStartSeconds; + return offsetMilliseconds; + } + + offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds); + if (offsetMilliseconds == startOffsetMilliseconds) { + noteCacheMissDecreasingOffsetChangeLower(); + rangeStartSeconds = newStartSeconds; + rangeEndSeconds = localTimeSeconds; + } else { + noteCacheMissDecreasingOffsetChangeExpand(); + rangeStartSeconds = localTimeSeconds; + } + return offsetMilliseconds; + } + + noteCacheMissLargeDecrease(); + rangeStartSeconds = rangeEndSeconds = localTimeSeconds; + offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds); + return offsetMilliseconds; +} + +void +DSTOffsetCache::sanityCheck() +{ + JS_ASSERT(rangeStartSeconds <= rangeEndSeconds); + JS_ASSERT_IF(rangeStartSeconds == INT64_MIN, rangeEndSeconds == INT64_MIN); + JS_ASSERT_IF(rangeEndSeconds == INT64_MIN, rangeStartSeconds == INT64_MIN); + JS_ASSERT_IF(rangeStartSeconds != INT64_MIN, + rangeStartSeconds >= 0 && rangeEndSeconds >= 0); + JS_ASSERT_IF(rangeStartSeconds != INT64_MIN, + rangeStartSeconds <= MAX_UNIX_TIMET && rangeEndSeconds <= MAX_UNIX_TIMET); + +#ifdef JS_METER_DST_OFFSET_CACHING + JS_ASSERT(totalCalculations == + hit + + missIncreasing + missDecreasing + + missIncreasingOffsetChangeExpand + missIncreasingOffsetChangeUpper + + missDecreasingOffsetChangeExpand + missDecreasingOffsetChangeLower + + missLargeIncrease + missLargeDecrease); +#endif +} + +#ifdef JS_METER_DST_OFFSET_CACHING +void +DSTOffsetCache::dumpStats() +{ + if (!getenv("JS_METER_DST_OFFSET_CACHING")) + return; + FILE *fp = fopen("/tmp/dst-offset-cache.stats", "a"); + if (!fp) + return; + typedef unsigned long UL; + fprintf(fp, + "hit:\n" + " in range: %lu\n" + "misses:\n" + " increase range end: %lu\n" + " decrease range start: %lu\n" + " increase, offset change, expand: %lu\n" + " increase, offset change, new range: %lu\n" + " decrease, offset change, expand: %lu\n" + " decrease, offset change, new range: %lu\n" + " large increase: %lu\n" + " large decrease: %lu\n" + "total: %lu\n\n", + UL(hit), + UL(missIncreasing), UL(missDecreasing), + UL(missIncreasingOffsetChangeExpand), UL(missIncreasingOffsetChangeUpper), + UL(missDecreasingOffsetChangeExpand), UL(missDecreasingOffsetChangeLower), + UL(missLargeIncrease), UL(missLargeDecrease), + UL(totalCalculations)); + fclose(fp); +} +#endif diff --git a/js/src/prmjtime.h b/js/src/prmjtime.h new file mode 100644 index 0000000..44bc2b9 --- /dev/null +++ b/js/src/prmjtime.h @@ -0,0 +1,227 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef prmjtime_h___ +#define prmjtime_h___ +/* + * PR date stuff for mocha and java. Placed here temporarily not to break + * Navigator and localize changes to mocha. + */ +#include + +#include "jslong.h" +#ifdef MOZILLA_CLIENT +#include "jscompat.h" +#endif + +struct JSContext; + +/* + * Implements a small cache for daylight saving time offset computation. + * + * The basic idea is premised upon this fact: the DST offset never changes more + * than once in any thirty-day period. If we know the offset at t_0 is o_0, + * the offset at [t_1, t_2] is also o_0, where t_1 + 3_0 days == t_2, + * t_1 <= t_0, and t0 <= t2. (In other words, t_0 is always somewhere within a + * thirty-day range where the DST offset is constant: DST changes never occur + * more than once in any thirty-day period.) Therefore, if we intelligently + * retain knowledge of the offset for a range of dates (which may vary over + * time), and if requests are usually for dates within that range, we can often + * provide a response without repeated offset calculation. + * + * Our caching strategy is as follows: on the first request at date t_0 compute + * the requested offset o_0. Save { start: t_0, end: t_0, offset: o_0 } as the + * cache's state. Subsequent requests within that range are straightforwardly + * handled. If a request for t_i is far outside the range (more than thirty + * days), compute o_i = dstOffset(t_i) and save { start: t_i, end: t_i, + * offset: t_i }. Otherwise attempt to *overextend* the range to either + * [start - 30d, end] or [start, end + 30d] as appropriate to encompass + * t_i. If the offset o_i30 is the same as the cached offset, extend the + * range. Otherwise the over-guess crossed a DST change -- compute + * o_i = dstOffset(t_i) and either extend the original range (if o_i == offset) + * or start a new one beneath/above the current one with o_i30 as the offset. + * + * This cache strategy results in 0 to 2 DST offset computations. The naive + * always-compute strategy is 1 computation, and since cache maintenance is a + * handful of integer arithmetic instructions the speed difference between + * always-1 and 1-with-cache is negligible. Caching loses if two computations + * happen: when the date is within 30 days of the cached range and when that + * 30-day range crosses a DST change. This is relatively uncommon. Further, + * instances of such are often dominated by in-range hits, so caching is an + * overall slight win. + * + * Why 30 days? For correctness the duration must be smaller than any possible + * duration between DST changes. Past that, note that 1) a large duration + * increases the likelihood of crossing a DST change while reducing the number + * of cache misses, and 2) a small duration decreases the size of the cached + * range while producing more misses. Using a month as the interval change is + * a balance between these two that tries to optimize for the calendar month at + * a time that a site might display. (One could imagine an adaptive duration + * that accommodates near-DST-change dates better; we don't believe the + * potential win from better caching offsets the loss from extra complexity.) + */ +class DSTOffsetCache { + public: + inline DSTOffsetCache(); + JSInt64 getDSTOffsetMilliseconds(int64 localTimeMilliseconds, JSContext *cx); + + inline void purge(); +#ifdef JS_METER_DST_OFFSET_CACHING + void dumpStats(); +#endif + + private: + JSInt64 computeDSTOffsetMilliseconds(int64 localTimeSeconds); + + JSInt64 offsetMilliseconds; + JSInt64 rangeStartSeconds, rangeEndSeconds; + + JSInt64 oldOffsetMilliseconds; + JSInt64 oldRangeStartSeconds, oldRangeEndSeconds; + +#ifdef JS_METER_DST_OFFSET_CACHING + size_t totalCalculations; + size_t hit; + size_t missIncreasing; + size_t missDecreasing; + size_t missIncreasingOffsetChangeUpper; + size_t missIncreasingOffsetChangeExpand; + size_t missLargeIncrease; + size_t missDecreasingOffsetChangeLower; + size_t missDecreasingOffsetChangeExpand; + size_t missLargeDecrease; +#endif + + static const JSInt64 MAX_UNIX_TIMET = 2145859200; /* time_t 12/31/2037 */ + static const JSInt64 MILLISECONDS_PER_SECOND = 1000; + static const JSInt64 SECONDS_PER_MINUTE = 60; + static const JSInt64 SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE; + static const JSInt64 SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR; + + static const JSInt64 RANGE_EXPANSION_AMOUNT = 30 * SECONDS_PER_DAY; + + private: + void sanityCheck(); + +#ifdef JS_METER_DST_OFFSET_CACHING +#define NOTE_GENERIC(member) this->member++ +#else +#define NOTE_GENERIC(member) ((void)0) +#endif + void noteOffsetCalculation() { + NOTE_GENERIC(totalCalculations); + } + void noteCacheHit() { + NOTE_GENERIC(hit); + } + void noteCacheMissIncrease() { + NOTE_GENERIC(missIncreasing); + } + void noteCacheMissDecrease() { + NOTE_GENERIC(missDecreasing); + } + void noteCacheMissIncreasingOffsetChangeUpper() { + NOTE_GENERIC(missIncreasingOffsetChangeUpper); + } + void noteCacheMissIncreasingOffsetChangeExpand() { + NOTE_GENERIC(missIncreasingOffsetChangeExpand); + } + void noteCacheMissLargeIncrease() { + NOTE_GENERIC(missLargeIncrease); + } + void noteCacheMissDecreasingOffsetChangeLower() { + NOTE_GENERIC(missDecreasingOffsetChangeLower); + } + void noteCacheMissDecreasingOffsetChangeExpand() { + NOTE_GENERIC(missDecreasingOffsetChangeExpand); + } + void noteCacheMissLargeDecrease() { + NOTE_GENERIC(missLargeDecrease); + } +#undef NOTE_GENERIC +}; + +JS_BEGIN_EXTERN_C + +typedef struct PRMJTime PRMJTime; + +/* + * Broken down form of 64 bit time value. + */ +struct PRMJTime { + JSInt32 tm_usec; /* microseconds of second (0-999999) */ + JSInt8 tm_sec; /* seconds of minute (0-59) */ + JSInt8 tm_min; /* minutes of hour (0-59) */ + JSInt8 tm_hour; /* hour of day (0-23) */ + JSInt8 tm_mday; /* day of month (1-31) */ + JSInt8 tm_mon; /* month of year (0-11) */ + JSInt8 tm_wday; /* 0=sunday, 1=monday, ... */ + JSInt32 tm_year; /* absolute year, AD */ + JSInt16 tm_yday; /* day of year (0 to 365) */ + JSInt8 tm_isdst; /* non-zero if DST in effect */ +}; + +/* Some handy constants */ +#define PRMJ_USEC_PER_SEC 1000000L +#define PRMJ_USEC_PER_MSEC 1000L + +/* Return the current local time in micro-seconds */ +extern JSInt64 +PRMJ_Now(void); + +/* Release the resources associated with PRMJ_Now; don't call PRMJ_Now again */ +#if defined(JS_THREADSAFE) && (defined(HAVE_GETSYSTEMTIMEASFILETIME) || defined(HAVE_SYSTEMTIMETOFILETIME)) +extern void +PRMJ_NowShutdown(void); +#else +#define PRMJ_NowShutdown() +#endif + +/* get the difference between this time zone and gmt timezone in seconds */ +extern JSInt32 +PRMJ_LocalGMTDifference(void); + +/* Format a time value into a buffer. Same semantics as strftime() */ +extern size_t +PRMJ_FormatTime(char *buf, int buflen, const char *fmt, PRMJTime *tm); + +JS_END_EXTERN_C + +#endif /* prmjtime_h___ */ + diff --git a/js/src/ref-config/AIX4.1.mk b/js/src/ref-config/AIX4.1.mk new file mode 100644 index 0000000..09c7cb9 --- /dev/null +++ b/js/src/ref-config/AIX4.1.mk @@ -0,0 +1,65 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for AIX +# + +CC = xlC_r +CCC = xlC_r + +RANLIB = ranlib + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< +ARCH := aix +CPU_ARCH = rs6000 +GFX_ARCH = x +INLINES = js_compare_and_swap:js_fast_lock1:js_fast_unlock1:js_lock_get_slot:js_lock_set_slot:js_lock_scope1 + +OS_CFLAGS = -qarch=com -qinline+$(INLINES) -DXP_UNIX -DAIX -DAIXV3 -DSYSV -DHAVE_LOCALTIME_R +OS_LIBS = -lbsd -lsvld -lm +#-lpthreads -lc_r + +MKSHLIB = $(LD) -bM:SRE -bh:4 -bnoentry -berok +XLDFLAGS += -lc + +ifdef JS_THREADSAFE +XLDFLAGS += -lsvld +endif diff --git a/js/src/ref-config/AIX4.2.mk b/js/src/ref-config/AIX4.2.mk new file mode 100644 index 0000000..1e3f1f1 --- /dev/null +++ b/js/src/ref-config/AIX4.2.mk @@ -0,0 +1,64 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for AIX +# + +CC = xlC_r +CCC = xlC_r +CFLAGS += -qarch=com -qnoansialias -qinline+$(INLINES) -DXP_UNIX -DAIX -DAIXV3 -DSYSV -DHAVE_LOCALTIME_R + +RANLIB = ranlib + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< +ARCH := aix +CPU_ARCH = rs6000 +GFX_ARCH = x +INLINES = js_compare_and_swap:js_fast_lock1:js_fast_unlock1:js_lock_get_slot:js_lock_set_slot:js_lock_scope1 + +#-lpthreads -lc_r + +MKSHLIB = /usr/lpp/xlC/bin/makeC++SharedLib_r -p 0 -G -berok + +ifdef JS_THREADSAFE +XLDFLAGS += -ldl +endif + diff --git a/js/src/ref-config/AIX4.3.mk b/js/src/ref-config/AIX4.3.mk new file mode 100644 index 0000000..df05d8c --- /dev/null +++ b/js/src/ref-config/AIX4.3.mk @@ -0,0 +1,65 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for AIX +# + +CC = xlC_r +CCC = xlC_r +CFLAGS += -qarch=com -qnoansialias -qinline+$(INLINES) -DXP_UNIX -DAIX -DAIXV3 -DSYSV -DAIX4_3 -DHAVE_LOCALTIME_R + +RANLIB = ranlib + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< +ARCH := aix +CPU_ARCH = rs6000 +GFX_ARCH = x +INLINES = js_compare_and_swap:js_fast_lock1:js_fast_unlock1:js_lock_get_slot:js_lock_set_slot:js_lock_scope1 + +#-lpthreads -lc_r + +MKSHLIB_BIN = /usr/ibmcxx/bin/makeC++SharedLib_r +MKSHLIB = $(MKSHLIB_BIN) -p 0 -G -berok -bM:UR + +ifdef JS_THREADSAFE +XLDFLAGS += -ldl +endif + diff --git a/js/src/ref-config/Darwin.mk b/js/src/ref-config/Darwin.mk new file mode 100644 index 0000000..86c4b9d --- /dev/null +++ b/js/src/ref-config/Darwin.mk @@ -0,0 +1,85 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Steve Zellers (zellers@apple.com) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Mac OS X as of PR3 +# Just ripped from Linux config +# + +CC = gcc +CCC = g++ +CFLAGS += -Wall -Wno-format -MMD +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DDARWIN + +RANLIB = ranlib +MKSHLIB = $(CCC) -dynamiclib $(XMKSHLIBOPTS) -framework System + +SO_SUFFIX = dylib + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = $(shell uname -m) +ifeq (86,$(findstring 86,$(CPU_ARCH))) +CPU_ARCH = x86 +OS_CFLAGS+= -DX86_LINUX +OS_CFLAGS += -DAVMPLUS_IA32 -DAVMPLUS_UNIX +NANOJIT_ARCH = i386 +endif +GFX_ARCH = x + +OS_LIBS = -lc -framework System + +ASFLAGS += -x assembler-with-cpp + +ifeq ($(CPU_ARCH),alpha) + +# Ask the C compiler on alpha linux to let us work with denormalized +# double values, which are required by the ECMA spec. + +OS_CFLAGS += -mieee +endif + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 + +# Don't allow Makefile.ref to use libmath +NO_LIBM = 1 + diff --git a/js/src/ref-config/Darwin1.3.mk b/js/src/ref-config/Darwin1.3.mk new file mode 100644 index 0000000..05d3767 --- /dev/null +++ b/js/src/ref-config/Darwin1.3.mk @@ -0,0 +1,81 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Steve Zellers (zellers@apple.com) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Mac OS X as of PR3 +# Just ripped from Linux config +# + +CC = cc +CCC = g++ +CFLAGS += -Wall -Wno-format +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DRHAPSODY + +RANLIB = ranlib +MKSHLIB = libtool $(XMKSHLIBOPTS) -framework System + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = $(shell uname -m) +ifeq (86,$(findstring 86,$(CPU_ARCH))) +CPU_ARCH = x86 +OS_CFLAGS+= -DX86_LINUX +endif +GFX_ARCH = x + +OS_LIBS = -lc -framework System + +ASFLAGS += -x assembler-with-cpp + +ifeq ($(CPU_ARCH),alpha) + +# Ask the C compiler on alpha linux to let us work with denormalized +# double values, which are required by the ECMA spec. + +OS_CFLAGS += -mieee +endif + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 + +# Don't allow Makefile.ref to use libmath +NO_LIBM = 1 + diff --git a/js/src/ref-config/Darwin1.4.mk b/js/src/ref-config/Darwin1.4.mk new file mode 100644 index 0000000..f7b6af8 --- /dev/null +++ b/js/src/ref-config/Darwin1.4.mk @@ -0,0 +1,41 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mike McCabe +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +include $(DEPTH)/config/Darwin1.3.mk diff --git a/js/src/ref-config/Darwin5.2.mk b/js/src/ref-config/Darwin5.2.mk new file mode 100644 index 0000000..9b9b6ff --- /dev/null +++ b/js/src/ref-config/Darwin5.2.mk @@ -0,0 +1,81 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Steve Zellers (zellers@apple.com) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Mac OS X as of PR3 +# Just ripped from Linux config +# + +CC = cc +CCC = g++ +CFLAGS += -Wall -Wno-format +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DDARWIN + +RANLIB = ranlib +MKSHLIB = libtool $(XMKSHLIBOPTS) -framework System + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = $(shell uname -m) +ifeq (86,$(findstring 86,$(CPU_ARCH))) +CPU_ARCH = x86 +OS_CFLAGS+= -DX86_LINUX +endif +GFX_ARCH = x + +OS_LIBS = -lc -framework System + +ASFLAGS += -x assembler-with-cpp + +ifeq ($(CPU_ARCH),alpha) + +# Ask the C compiler on alpha linux to let us work with denormalized +# double values, which are required by the ECMA spec. + +OS_CFLAGS += -mieee +endif + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 + +# Don't allow Makefile.ref to use libmath +NO_LIBM = 1 + diff --git a/js/src/ref-config/Darwin5.3.mk b/js/src/ref-config/Darwin5.3.mk new file mode 100644 index 0000000..9b9b6ff --- /dev/null +++ b/js/src/ref-config/Darwin5.3.mk @@ -0,0 +1,81 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Steve Zellers (zellers@apple.com) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Mac OS X as of PR3 +# Just ripped from Linux config +# + +CC = cc +CCC = g++ +CFLAGS += -Wall -Wno-format +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DDARWIN + +RANLIB = ranlib +MKSHLIB = libtool $(XMKSHLIBOPTS) -framework System + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = $(shell uname -m) +ifeq (86,$(findstring 86,$(CPU_ARCH))) +CPU_ARCH = x86 +OS_CFLAGS+= -DX86_LINUX +endif +GFX_ARCH = x + +OS_LIBS = -lc -framework System + +ASFLAGS += -x assembler-with-cpp + +ifeq ($(CPU_ARCH),alpha) + +# Ask the C compiler on alpha linux to let us work with denormalized +# double values, which are required by the ECMA spec. + +OS_CFLAGS += -mieee +endif + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 + +# Don't allow Makefile.ref to use libmath +NO_LIBM = 1 + diff --git a/js/src/ref-config/Darwin64.mk b/js/src/ref-config/Darwin64.mk new file mode 100644 index 0000000..db195b5 --- /dev/null +++ b/js/src/ref-config/Darwin64.mk @@ -0,0 +1,72 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Steve Zellers (zellers@apple.com) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Mac OS X as of PR3 +# Just ripped from Linux config +# + +CC = cc +CCC = g++ +CFLAGS += -Wall -Wno-format -MMD +OS_LDFLAGS += -m64 +OS_CFLAGS = -m64 -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DDARWIN + +RANLIB = ranlib +MKSHLIB = $(CCC) -dynamiclib $(XMKSHLIBOPTS) -framework System + +SO_SUFFIX = dylib + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = x86_64 +GFX_ARCH = x + +OS_LIBS = -lc -framework System + +ASFLAGS += -x assembler-with-cpp + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 + +# Don't allow Makefile.ref to use libmath +NO_LIBM = 1 + diff --git a/js/src/ref-config/HP-UXB.10.10.mk b/js/src/ref-config/HP-UXB.10.10.mk new file mode 100644 index 0000000..8cd9d20 --- /dev/null +++ b/js/src/ref-config/HP-UXB.10.10.mk @@ -0,0 +1,77 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for HPUX +# + +# CC = gcc +# CCC = g++ +# CFLAGS += -Wall -Wno-format -fPIC + +CC = cc -Ae +Z +CCC = CC -Ae +a1 +eh +Z + +RANLIB = echo +MKSHLIB = $(LD) -b + +SO_SUFFIX = sl + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = hppa +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DHPUX -DSYSV -DHAVE_LOCALTIME_R +OS_LIBS = -ldld + +ifeq ($(OS_RELEASE),B.10) +PLATFORM_FLAGS += -DHPUX10 -Dhpux10 +PORT_FLAGS += -DRW_NO_OVERLOAD_SCHAR -DHAVE_MODEL_H +ifeq ($(OS_VERSION),.10) +PLATFORM_FLAGS += -DHPUX10_10 +endif +ifeq ($(OS_VERSION),.20) +PLATFORM_FLAGS += -DHPUX10_20 +endif +ifeq ($(OS_VERSION),.30) +PLATFORM_FLAGS += -DHPUX10_30 +endif +endif diff --git a/js/src/ref-config/HP-UXB.10.20.mk b/js/src/ref-config/HP-UXB.10.20.mk new file mode 100644 index 0000000..8cd9d20 --- /dev/null +++ b/js/src/ref-config/HP-UXB.10.20.mk @@ -0,0 +1,77 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for HPUX +# + +# CC = gcc +# CCC = g++ +# CFLAGS += -Wall -Wno-format -fPIC + +CC = cc -Ae +Z +CCC = CC -Ae +a1 +eh +Z + +RANLIB = echo +MKSHLIB = $(LD) -b + +SO_SUFFIX = sl + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = hppa +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DHPUX -DSYSV -DHAVE_LOCALTIME_R +OS_LIBS = -ldld + +ifeq ($(OS_RELEASE),B.10) +PLATFORM_FLAGS += -DHPUX10 -Dhpux10 +PORT_FLAGS += -DRW_NO_OVERLOAD_SCHAR -DHAVE_MODEL_H +ifeq ($(OS_VERSION),.10) +PLATFORM_FLAGS += -DHPUX10_10 +endif +ifeq ($(OS_VERSION),.20) +PLATFORM_FLAGS += -DHPUX10_20 +endif +ifeq ($(OS_VERSION),.30) +PLATFORM_FLAGS += -DHPUX10_30 +endif +endif diff --git a/js/src/ref-config/HP-UXB.11.00.mk b/js/src/ref-config/HP-UXB.11.00.mk new file mode 100644 index 0000000..239188d --- /dev/null +++ b/js/src/ref-config/HP-UXB.11.00.mk @@ -0,0 +1,80 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for HPUX +# + +ifdef NS_USE_NATIVE + CC = cc +Z +DAportable +DS2.0 +u4 +# LD = aCC +Z -b -Wl,+s -Wl,-B,symbolic +else + CC = gcc -Wall -Wno-format -fPIC + CCC = g++ -Wall -Wno-format -fPIC +endif + +RANLIB = echo +MKSHLIB = $(LD) -b + +SO_SUFFIX = sl + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = hppa +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DHPUX -DSYSV -D_HPUX -DNATIVE -D_POSIX_C_SOURCE=199506L -DHAVE_LOCALTIME_R +OS_LIBS = -ldld + +XLDFLAGS = -lpthread + +ifeq ($(OS_RELEASE),B.10) +PLATFORM_FLAGS += -DHPUX10 -Dhpux10 +PORT_FLAGS += -DRW_NO_OVERLOAD_SCHAR -DHAVE_MODEL_H +ifeq ($(OS_VERSION),.10) +PLATFORM_FLAGS += -DHPUX10_10 +endif +ifeq ($(OS_VERSION),.20) +PLATFORM_FLAGS += -DHPUX10_20 +endif +ifeq ($(OS_VERSION),.30) +PLATFORM_FLAGS += -DHPUX10_30 +endif +endif diff --git a/js/src/ref-config/HP-UXB.11.31.mk b/js/src/ref-config/HP-UXB.11.31.mk new file mode 100644 index 0000000..8c1cc40 --- /dev/null +++ b/js/src/ref-config/HP-UXB.11.31.mk @@ -0,0 +1,65 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for HPUX +# +ifdef NS_USE_NATIVE + CC = cc +Z +u4 +else + CC = gcc -Wall -Wno-format -fPIC + CCC = g++ -Wall -Wno-format -fPIC +endif + +RANLIB = echo +MKSHLIB = $(LD) -b + +SO_SUFFIX = sl + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = ia64 +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DHPUX -DSYSV -D_HPUX \ + -DNATIVE -D_POSIX_C_SOURCE=199506L -DHAVE_LOCALTIME_R +OS_LIBS = -ldld + +XLDFLAGS = -lpthread diff --git a/js/src/ref-config/IRIX.mk b/js/src/ref-config/IRIX.mk new file mode 100644 index 0000000..88b162f --- /dev/null +++ b/js/src/ref-config/IRIX.mk @@ -0,0 +1,87 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for IRIX +# + +CPU_ARCH = mips +GFX_ARCH = x + +RANLIB = /bin/true + +#NS_USE_GCC = 1 + +ifndef NS_USE_NATIVE +CC = gcc +CCC = g++ +AS = $(CC) -x assembler-with-cpp +ODD_CFLAGS = -Wall -Wno-format +ifdef BUILD_OPT +OPTIMIZER = -O6 +endif +else +ifeq ($(OS_RELEASE),6.2) +CC = cc -n32 -DIRIX6_2 +endif +ifeq ($(OS_RELEASE),6.3) +CC = cc -n32 -DIRIX6_3 +endif +ifeq ($(OS_RELEASE),6.5) +CC = cc -n32 -DIRIX6_5 +endif +CCC = CC +# LD = CC +ODD_CFLAGS = -fullwarn -xansi +ifdef BUILD_OPT +OPTIMIZER += -Olimit 4000 +endif +endif + +# For purify +HAVE_PURIFY = 1 +PURE_OS_CFLAGS = $(ODD_CFLAGS) -DXP_UNIX -DSVR4 -DSW_THREADS -DIRIX -DHAVE_LOCALTIME_R + +OS_CFLAGS = $(PURE_OS_CFLAGS) -MDupdate $(DEPENDENCIES) + +BSDECHO = echo +MKSHLIB = $(LD) -n32 -shared + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 diff --git a/js/src/ref-config/IRIX5.3.mk b/js/src/ref-config/IRIX5.3.mk new file mode 100644 index 0000000..f38cc94 --- /dev/null +++ b/js/src/ref-config/IRIX5.3.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for IRIX5.3 +# + +include $(DEPTH)/config/IRIX.mk diff --git a/js/src/ref-config/IRIX6.1.mk b/js/src/ref-config/IRIX6.1.mk new file mode 100644 index 0000000..354f1d1 --- /dev/null +++ b/js/src/ref-config/IRIX6.1.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for IRIX6.3 +# + +include $(DEPTH)/config/IRIX.mk diff --git a/js/src/ref-config/IRIX6.2.mk b/js/src/ref-config/IRIX6.2.mk new file mode 100644 index 0000000..354f1d1 --- /dev/null +++ b/js/src/ref-config/IRIX6.2.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for IRIX6.3 +# + +include $(DEPTH)/config/IRIX.mk diff --git a/js/src/ref-config/IRIX6.3.mk b/js/src/ref-config/IRIX6.3.mk new file mode 100644 index 0000000..354f1d1 --- /dev/null +++ b/js/src/ref-config/IRIX6.3.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for IRIX6.3 +# + +include $(DEPTH)/config/IRIX.mk diff --git a/js/src/ref-config/IRIX6.5.mk b/js/src/ref-config/IRIX6.5.mk new file mode 100644 index 0000000..354f1d1 --- /dev/null +++ b/js/src/ref-config/IRIX6.5.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for IRIX6.3 +# + +include $(DEPTH)/config/IRIX.mk diff --git a/js/src/ref-config/Linux_All.mk b/js/src/ref-config/Linux_All.mk new file mode 100644 index 0000000..6c289b4 --- /dev/null +++ b/js/src/ref-config/Linux_All.mk @@ -0,0 +1,105 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for all versions of Linux +# + +CC = gcc +CCC = g++ +LD = g++ +CFLAGS += -Wall -Wno-format -MMD +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DHAVE_LOCALTIME_R -DLINUX + +RANLIB = echo +MKSHLIB = $(LD) -shared $(XMKSHLIBOPTS) + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = $(shell uname -m) +# don't filter in x86-64 architecture +ifneq (x86_64,$(CPU_ARCH)) +ifeq (86,$(findstring 86,$(CPU_ARCH))) +CPU_ARCH = x86 +OS_CFLAGS += -DX86_LINUX -DAVMPLUS_IA32 -DAVMPLUS_UNIX -DAVMPLUS_LINUX +NANOJIT_ARCH = i386 +endif # 86 +endif # !x86_64 + +#JIT disabled until x64 port is cleaned up +#ifeq ($(CPU_ARCH),x86_64) +#OS_CFLAGS += -DAVMPLUS_AMD64 -DAVMPLUS_64BIT -DAVMPLUS_UNIX -DAVMPLUS_LINUX +#NANOJIT_ARCH = i386 +#endif + +ifeq ($(CPU_ARCH),arm) +OS_CFLAGS += -DAVMPLUS_ARM -DAVMPLUS_UNIX -DAVMPLUS_LINUX +NANOJIT_ARCH = ARM +endif + +GFX_ARCH = x + +OS_LIBS = -lm -lc + +ASFLAGS += -x assembler-with-cpp + + +ifeq ($(CPU_ARCH),alpha) + +# Ask the C compiler on alpha linux to let us work with denormalized +# double values, which are required by the ECMA spec. + +OS_CFLAGS += -mieee +endif + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 + +ifeq ($(CPU_ARCH),x86_64) +# Use VA_COPY() standard macro on x86-64 +# FIXME: better use it everywhere +OS_CFLAGS += -DHAVE_VA_COPY -DVA_COPY=va_copy +endif + +ifeq ($(CPU_ARCH),x86_64) +# We need PIC code for shared libraries +# FIXME: better patch rules.mk & fdlibm/Makefile* +OS_CFLAGS += -DPIC -fPIC +endif diff --git a/js/src/ref-config/Mac_OS10.0.mk b/js/src/ref-config/Mac_OS10.0.mk new file mode 100644 index 0000000..74ba151 --- /dev/null +++ b/js/src/ref-config/Mac_OS10.0.mk @@ -0,0 +1,82 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Steve Zellers (zellers@apple.com) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Mac OS X as of PR3 +# Just ripped from Linux config +# + +CC = cc +CCC = g++ +CFLAGS += -Wall -Wno-format +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE +-DRHAPSODY + +RANLIB = ranlib +MKSHLIB = libtool -dynamic $(XMKSHLIBOPTS) -framework System + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = $(shell uname -m) +ifeq (86,$(findstring 86,$(CPU_ARCH))) +CPU_ARCH = x86 +OS_CFLAGS+= -DX86_LINUX +endif +GFX_ARCH = x + +OS_LIBS = -lc -framework System + +ASFLAGS += -x assembler-with-cpp + +ifeq ($(CPU_ARCH),alpha) + +# Ask the C compiler on alpha linux to let us work with denormalized +# double values, which are required by the ECMA spec. + +OS_CFLAGS += -mieee +endif + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 + +# Don't allow Makefile.ref to use libmath +NO_LIBM = 1 + diff --git a/js/src/ref-config/OSF1V4.0.mk b/js/src/ref-config/OSF1V4.0.mk new file mode 100644 index 0000000..337ca74 --- /dev/null +++ b/js/src/ref-config/OSF1V4.0.mk @@ -0,0 +1,72 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for Data General DG/UX +# + +# +# Initial DG/UX port by Marc Fraioli (fraioli@dg-rtp.dg.com) +# + +ifndef NS_USE_NATIVE +CC = gcc +CCC = g++ +CFLAGS += -mieee -Wall -Wno-format +else +CC = cc +CCC = cxx +CFLAGS += -ieee -std +# LD = cxx +endif + +RANLIB = echo +MKSHLIB = $(LD) -shared -taso -all -expect_unresolved "*" + +# +# _DGUX_SOURCE is needed to turn on a lot of stuff in the headers if +# you're not using DG's compiler. It shouldn't hurt if you are. +# +# _POSIX4A_DRAFT10_SOURCE is needed to pick up localtime_r, used in +# prtime.c +# +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -DDGUX -D_DGUX_SOURCE -D_POSIX4A_DRAFT10_SOURCE -DOSF1 -DHAVE_LOCALTIME_R +OS_LIBS = -lsocket -lnsl + +NOSUCHFILE = /no-such-file diff --git a/js/src/ref-config/OSF1V5.0.mk b/js/src/ref-config/OSF1V5.0.mk new file mode 100644 index 0000000..b65738c --- /dev/null +++ b/js/src/ref-config/OSF1V5.0.mk @@ -0,0 +1,69 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for Tru64 Unix 5.0 +# + +# +# Initial DG/UX port by Marc Fraioli (fraioli@dg-rtp.dg.com) +# + +ifndef NS_USE_NATIVE +CC = gcc +CCC = g++ +CFLAGS += -mieee -Wall -Wno-format +else +CC = cc +CCC = cxx +CFLAGS += -ieee -std -pthread +# LD = cxx +endif + +RANLIB = echo +MKSHLIB = $(LD) -shared -all -expect_unresolved "*" + +# +# _POSIX4A_DRAFT10_SOURCE is needed to pick up localtime_r, used in +# prtime.c +# +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_POSIX4A_DRAFT10_SOURCE -DOSF1 -DHAVE_LOCALTIME_R +OS_LIBS = -lsocket -lnsl + +NOSUCHFILE = /no-such-file diff --git a/js/src/ref-config/SunOS4.1.4.mk b/js/src/ref-config/SunOS4.1.4.mk new file mode 100644 index 0000000..62f4815 --- /dev/null +++ b/js/src/ref-config/SunOS4.1.4.mk @@ -0,0 +1,101 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS4.1 +# + +CC = gcc +CCC = g++ +RANLIB = ranlib + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = sparc +GFX_ARCH = x + +# A pile of -D's to build xfe on sunos +MOZ_CFLAGS = -DSTRINGS_ALIGNED -DNO_REGEX -DNO_ISDIR -DUSE_RE_COMP \ + -DNO_REGCOMP -DUSE_GETWD -DNO_MEMMOVE -DNO_ALLOCA \ + -DBOGUS_MB_MAX -DNO_CONST + +# Purify doesn't like -MDupdate +NOMD_OS_CFLAGS = -DXP_UNIX -Wall -Wno-format -DSW_THREADS -DSUNOS4 -DNEED_SYSCALL \ + $(MOZ_CFLAGS) + +OS_CFLAGS = $(NOMD_OS_CFLAGS) -MDupdate $(DEPENDENCIES) +OS_LIBS = -ldl -lm + +MKSHLIB = $(LD) -L$(MOTIF)/lib + +HAVE_PURIFY = 1 +MOTIF = /home/motif/usr +MOTIFLIB = -L$(MOTIF)/lib -lXm +INCLUDES += -I/usr/X11R5/include -I$(MOTIF)/include + +NOSUCHFILE = /solaris-rm-f-sucks + +LOCALE_MAP = $(DEPTH)/cmd/xfe/intl/sunos.lm + +EN_LOCALE = en_US +DE_LOCALE = de +FR_LOCALE = fr +JP_LOCALE = ja +SJIS_LOCALE = ja_JP.SJIS +KR_LOCALE = ko +CN_LOCALE = zh +TW_LOCALE = zh_TW +I2_LOCALE = i2 +IT_LOCALE = it +SV_LOCALE = sv +ES_LOCALE = es +NL_LOCALE = nl +PT_LOCALE = pt + +LOC_LIB_DIR = /usr/openwin/lib/locale + +BSDECHO = echo + +# +# These defines are for building unix plugins +# +BUILD_UNIX_PLUGINS = 1 +DSO_LDOPTS = +DSO_LDFLAGS = diff --git a/js/src/ref-config/SunOS5.10.mk b/js/src/ref-config/SunOS5.10.mk new file mode 100644 index 0000000..dc0b0a0 --- /dev/null +++ b/js/src/ref-config/SunOS5.10.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.10, using vendor gcc and NSPR +# + +include $(DEPTH)/config/SunOS5.5.mk + +INCLUDES += -I/usr/sfw/include/mozilla/nspr +OTHER_LIBS += -L/usr/sfw/lib/mozilla -R/usr/sfw/lib/mozilla + +CC=gcc + diff --git a/js/src/ref-config/SunOS5.3.mk b/js/src/ref-config/SunOS5.3.mk new file mode 100644 index 0000000..bd615de --- /dev/null +++ b/js/src/ref-config/SunOS5.3.mk @@ -0,0 +1,91 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.3 +# + +CC = gcc +CCC = g++ +CFLAGS += -Wall -Wno-format + +#CC = /opt/SUNWspro/SC3.0.1/bin/cc +RANLIB = echo + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = sparc +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -DSOLARIS -DHAVE_LOCALTIME_R +OS_LIBS = -lsocket -lnsl -ldl + +ASFLAGS += -P -L -K PIC -D_ASM -D__STDC__=0 + +HAVE_PURIFY = 1 + +NOSUCHFILE = /solaris-rm-f-sucks + +ifndef JS_NO_ULTRA +ULTRA_OPTIONS := -xarch=v8plus +ULTRA_OPTIONSD := -DULTRA_SPARC +else +ULTRA_OPTIONS := -xarch=v8 +ULTRA_OPTIONSD := +endif + +ifeq ($(OS_CPUARCH),sun4u) +DEFINES += $(ULTRA_OPTIONSD) +ifeq ($(findstring gcc,$(CC)),gcc) +DEFINES += -Wa,$(ULTRA_OPTIONS),$(ULTRA_OPTIONSD) +else +ASFLAGS += $(ULTRA_OPTIONS) $(ULTRA_OPTIONSD) +endif +endif + +ifeq ($(OS_CPUARCH),sun4m) +ifeq ($(findstring gcc,$(CC)),gcc) +DEFINES += -Wa,-xarch=v8 +else +ASFLAGS += -xarch=v8 +endif +endif + +MKSHLIB = $(LD) -G diff --git a/js/src/ref-config/SunOS5.4.mk b/js/src/ref-config/SunOS5.4.mk new file mode 100644 index 0000000..de01924 --- /dev/null +++ b/js/src/ref-config/SunOS5.4.mk @@ -0,0 +1,92 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.4 +# + +ifdef NS_USE_NATIVE +CC = cc +CCC = CC +else +CC = gcc +CCC = g++ +CFLAGS += -Wall -Wno-format +endif + +RANLIB = echo + +CPU_ARCH = sparc +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D__svr4 -DSOLARIS -DHAVE_LOCALTIME_R +OS_LIBS = -lsocket -lnsl -ldl + +ASFLAGS += -P -L -K PIC -D_ASM -D__STDC__=0 + +HAVE_PURIFY = 1 + +NOSUCHFILE = /solaris-rm-f-sucks + +ifndef JS_NO_ULTRA +ULTRA_OPTIONS := -xarch=v8plus +ULTRA_OPTIONSD := -DULTRA_SPARC +else +ULTRA_OPTIONS := -xarch=v8 +ULTRA_OPTIONSD := +endif + +ifeq ($(OS_CPUARCH),sun4u) +DEFINES += $(ULTRA_OPTIONSD) +ifeq ($(findstring gcc,$(CC)),gcc) +DEFINES += -Wa,$(ULTRA_OPTIONS),$(ULTRA_OPTIONSD) +else +ASFLAGS += $(ULTRA_OPTIONS) $(ULTRA_OPTIONSD) +endif +endif + +ifeq ($(OS_CPUARCH),sun4m) +ifeq ($(findstring gcc,$(CC)),gcc) +DEFINES += -Wa,-xarch=v8 +else +ASFLAGS += -xarch=v8 +endif +endif + +MKSHLIB = $(LD) -G diff --git a/js/src/ref-config/SunOS5.5.1.mk b/js/src/ref-config/SunOS5.5.1.mk new file mode 100644 index 0000000..648f72f --- /dev/null +++ b/js/src/ref-config/SunOS5.5.1.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.5.1 +# + +include $(DEPTH)/config/SunOS5.5.mk diff --git a/js/src/ref-config/SunOS5.5.mk b/js/src/ref-config/SunOS5.5.mk new file mode 100644 index 0000000..e26b3a3 --- /dev/null +++ b/js/src/ref-config/SunOS5.5.mk @@ -0,0 +1,87 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.5 +# + +AS = /usr/ccs/bin/as +ifndef NS_USE_NATIVE +CC = gcc +CCC = g++ +CFLAGS += -Wall -Wno-format +else +CC = cc +CCC = CC +endif + +RANLIB = echo + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = sparc +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -DSOLARIS -DHAVE_LOCALTIME_R +OS_LIBS = -lsocket -lnsl -ldl + +ASFLAGS += -P -L -K PIC -D_ASM -D__STDC__=0 + +HAVE_PURIFY = 1 + +NOSUCHFILE = /solaris-rm-f-sucks + +ifeq ($(OS_CPUARCH),sun4u) # ultra sparc? +ifeq ($(CC),gcc) # using gcc? +ifndef JS_NO_ULTRA # do we want ultra? +ifdef JS_THREADSAFE # only in thread-safe mode +DEFINES += -DULTRA_SPARC +DEFINES += -Wa,-xarch=v8plus,-DULTRA_SPARC +else +ASFLAGS += -xarch=v8plus -DULTRA_SPARC +endif +endif +endif +endif + +MKSHLIB = $(LD) -G + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 diff --git a/js/src/ref-config/SunOS5.6.mk b/js/src/ref-config/SunOS5.6.mk new file mode 100644 index 0000000..efe1152 --- /dev/null +++ b/js/src/ref-config/SunOS5.6.mk @@ -0,0 +1,89 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.5 +# + +AS = /usr/ccs/bin/as +ifndef NS_USE_NATIVE + CC = gcc + CCC = g++ + CFLAGS += -Wall -Wno-format +else + CC = cc + CCC = CC + CFLAGS += -mt -KPIC +# LD = CC +endif + +RANLIB = echo + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = sparc +GFX_ARCH = x + +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -DSOLARIS -DHAVE_LOCALTIME_R +OS_LIBS = -lsocket -lnsl -ldl + +ASFLAGS += -P -L -K PIC -D_ASM -D__STDC__=0 + +HAVE_PURIFY = 1 + +NOSUCHFILE = /solaris-rm-f-sucks + +ifeq ($(OS_CPUARCH),sun4u) # ultra sparc? +ifeq ($(CC),gcc) # using gcc? +ifndef JS_NO_ULTRA # do we want ultra? +ifdef JS_THREADSAFE # only in thread-safe mode +DEFINES += -DULTRA_SPARC +DEFINES += -Wa,-xarch=v8plus,-DULTRA_SPARC +else +ASFLAGS += -xarch=v8plus -DULTRA_SPARC +endif +endif +endif +endif + +MKSHLIB = $(LD) -G + +# Use the editline library to provide line-editing support. +JS_EDITLINE = 1 diff --git a/js/src/ref-config/SunOS5.7.mk b/js/src/ref-config/SunOS5.7.mk new file mode 100644 index 0000000..2cb02f2 --- /dev/null +++ b/js/src/ref-config/SunOS5.7.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.7 +# + +include $(DEPTH)/config/SunOS5.5.mk diff --git a/js/src/ref-config/SunOS5.8.mk b/js/src/ref-config/SunOS5.8.mk new file mode 100644 index 0000000..dd8a32d --- /dev/null +++ b/js/src/ref-config/SunOS5.8.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.8 +# + +include $(DEPTH)/config/SunOS5.5.mk diff --git a/js/src/ref-config/SunOS5.9.mk b/js/src/ref-config/SunOS5.9.mk new file mode 100644 index 0000000..b01ec9c --- /dev/null +++ b/js/src/ref-config/SunOS5.9.mk @@ -0,0 +1,44 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for SunOS5.9 +# + +include $(DEPTH)/config/SunOS5.5.mk diff --git a/js/src/ref-config/WINNT4.0.mk b/js/src/ref-config/WINNT4.0.mk new file mode 100644 index 0000000..1d36f91 --- /dev/null +++ b/js/src/ref-config/WINNT4.0.mk @@ -0,0 +1,118 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Windows NT using MS Visual C++ (version?) +# + +CC = cl +CXX = cl + +RANLIB = echo + +PDBFILE = $(basename $(@F)).pdb + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = x86 # XXX fixme +GFX_ARCH = win32 + +# MSVC compiler options for both debug/optimize +# -nologo - suppress copyright message +# -W3 - Warning level 3 +# -Gm - enable minimal rebuild +# -Z7 - put debug info into the executable, not in .pdb file +# -Zi - put debug info into .pdb file +# -YX - automatic precompiled headers +# -GX - enable C++ exception support +WIN_CFLAGS = -nologo -W3 + +# MSVC compiler options for debug builds linked to MSVCRTD.DLL +# -MDd - link with MSVCRTD.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_IDG_CFLAGS = -MDd -Od -Z7 + +# MSVC compiler options for debug builds linked to MSVCRT.DLL +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_DEBUG_CFLAGS = -MD -Od -Zi -Fd$(OBJDIR)/$(PDBFILE) + +# MSVC compiler options for release (optimized) builds +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, C-runtime) +# -O2 - Optimize for speed +# -G5 - Optimize for Pentium +WIN_OPT_CFLAGS = -MD -O2 + +ifdef BUILD_OPT +OPTIMIZER = $(WIN_OPT_CFLAGS) +else +ifdef BUILD_IDG +OPTIMIZER = $(WIN_IDG_CFLAGS) +else +OPTIMIZER = $(WIN_DEBUG_CFLAGS) +endif +endif + +OS_CFLAGS = -D_X86_=1 -DXP_WIN -DXP_WIN32 -DWIN32 -D_WINDOWS -D_WIN32 $(WIN_CFLAGS) +JSDLL_CFLAGS = -DEXPORT_JS_API +OS_LIBS = -lm -lc + +PREBUILT_CPUCFG = 1 +USE_MSVC = 1 + +LIB_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib \ + winmm.lib \ + -nologo\ + -subsystem:windows -dll -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +EXE_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib -nologo\ + -subsystem:console -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +# CAFEDIR = t:/cafe +# JCLASSPATH = $(CAFEDIR)/Java/Lib/classes.zip +# JAVAC = $(CAFEDIR)/Bin/sj.exe +# JAVAH = $(CAFEDIR)/Java/Bin/javah.exe +# JCFLAGS = -I$(CAFEDIR)/Java/Include -I$(CAFEDIR)/Java/Include/win32 diff --git a/js/src/ref-config/WINNT5.0.mk b/js/src/ref-config/WINNT5.0.mk new file mode 100644 index 0000000..7681e01 --- /dev/null +++ b/js/src/ref-config/WINNT5.0.mk @@ -0,0 +1,118 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Windows NT using MS Visual C++ (version?) +# + +CC = cl +CXX = cl + +RANLIB = echo + +PDBFILE = $(basename $(@F)).pdb + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = x86 # XXX fixme +GFX_ARCH = win32 + +# MSVC compiler options for both debug/optimize +# -nologo - suppress copyright message +# -W3 - Warning level 3 +# -Gm - enable minimal rebuild +# -Z7 - put debug info into the executable, not in .pdb file +# -Zi - put debug info into .pdb file +# -YX - automatic precompiled headers +# -GX - enable C++ exception support +WIN_CFLAGS = -nologo -W3 + +# MSVC compiler options for debug builds linked to MSVCRTD.DLL +# -MDd - link with MSVCRTD.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_IDG_CFLAGS = -MDd -Od -Z7 + +# MSVC compiler options for debug builds linked to MSVCRT.DLL +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_DEBUG_CFLAGS = -MD -Od -Zi -Fd$(OBJDIR)/$(PDBFILE) + +# MSVC compiler options for release (optimized) builds +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, C-runtime) +# -O2 - Optimize for speed +# -G5 - Optimize for Pentium +WIN_OPT_CFLAGS = -MD -O2 + +ifdef BUILD_OPT +OPTIMIZER = $(WIN_OPT_CFLAGS) +else +ifdef BUILD_IDG +OPTIMIZER = $(WIN_IDG_CFLAGS) +else +OPTIMIZER = $(WIN_DEBUG_CFLAGS) +endif +endif + +OS_CFLAGS = -D_X86_=1 -DXP_WIN -DXP_WIN32 -DWIN32 -D_WINDOWS -D_WIN32 -DWINVER=0x500 -D_WIN32_WINNT=0x500 $(WIN_CFLAGS) +JSDLL_CFLAGS = -DEXPORT_JS_API +OS_LIBS = -lm -lc + +PREBUILT_CPUCFG = 1 +USE_MSVC = 1 + +LIB_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib \ + winmm.lib \ + -nologo\ + -subsystem:windows -dll -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +EXE_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib -nologo\ + -subsystem:console -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +# CAFEDIR = t:/cafe +# JCLASSPATH = $(CAFEDIR)/Java/Lib/classes.zip +# JAVAC = $(CAFEDIR)/Bin/sj.exe +# JAVAH = $(CAFEDIR)/Java/Bin/javah.exe +# JCFLAGS = -I$(CAFEDIR)/Java/Include -I$(CAFEDIR)/Java/Include/win32 diff --git a/js/src/ref-config/WINNT5.1.mk b/js/src/ref-config/WINNT5.1.mk new file mode 100644 index 0000000..7681e01 --- /dev/null +++ b/js/src/ref-config/WINNT5.1.mk @@ -0,0 +1,118 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Windows NT using MS Visual C++ (version?) +# + +CC = cl +CXX = cl + +RANLIB = echo + +PDBFILE = $(basename $(@F)).pdb + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = x86 # XXX fixme +GFX_ARCH = win32 + +# MSVC compiler options for both debug/optimize +# -nologo - suppress copyright message +# -W3 - Warning level 3 +# -Gm - enable minimal rebuild +# -Z7 - put debug info into the executable, not in .pdb file +# -Zi - put debug info into .pdb file +# -YX - automatic precompiled headers +# -GX - enable C++ exception support +WIN_CFLAGS = -nologo -W3 + +# MSVC compiler options for debug builds linked to MSVCRTD.DLL +# -MDd - link with MSVCRTD.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_IDG_CFLAGS = -MDd -Od -Z7 + +# MSVC compiler options for debug builds linked to MSVCRT.DLL +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_DEBUG_CFLAGS = -MD -Od -Zi -Fd$(OBJDIR)/$(PDBFILE) + +# MSVC compiler options for release (optimized) builds +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, C-runtime) +# -O2 - Optimize for speed +# -G5 - Optimize for Pentium +WIN_OPT_CFLAGS = -MD -O2 + +ifdef BUILD_OPT +OPTIMIZER = $(WIN_OPT_CFLAGS) +else +ifdef BUILD_IDG +OPTIMIZER = $(WIN_IDG_CFLAGS) +else +OPTIMIZER = $(WIN_DEBUG_CFLAGS) +endif +endif + +OS_CFLAGS = -D_X86_=1 -DXP_WIN -DXP_WIN32 -DWIN32 -D_WINDOWS -D_WIN32 -DWINVER=0x500 -D_WIN32_WINNT=0x500 $(WIN_CFLAGS) +JSDLL_CFLAGS = -DEXPORT_JS_API +OS_LIBS = -lm -lc + +PREBUILT_CPUCFG = 1 +USE_MSVC = 1 + +LIB_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib \ + winmm.lib \ + -nologo\ + -subsystem:windows -dll -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +EXE_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib -nologo\ + -subsystem:console -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +# CAFEDIR = t:/cafe +# JCLASSPATH = $(CAFEDIR)/Java/Lib/classes.zip +# JAVAC = $(CAFEDIR)/Bin/sj.exe +# JAVAH = $(CAFEDIR)/Java/Bin/javah.exe +# JCFLAGS = -I$(CAFEDIR)/Java/Include -I$(CAFEDIR)/Java/Include/win32 diff --git a/js/src/ref-config/WINNT5.2.mk b/js/src/ref-config/WINNT5.2.mk new file mode 100644 index 0000000..5fbcbfe --- /dev/null +++ b/js/src/ref-config/WINNT5.2.mk @@ -0,0 +1,118 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Windows NT using MS Visual C++ (version?) +# + +CC = cl +CXX = cl + +RANLIB = echo + +PDBFILE = $(basename $(@F)).pdb + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = x86 # XXX fixme +GFX_ARCH = win32 + +# MSVC compiler options for both debug/optimize +# -nologo - suppress copyright message +# -W3 - Warning level 3 +# -Gm - enable minimal rebuild +# -Z7 - put debug info into the executable, not in .pdb file +# -Zi - put debug info into .pdb file +# -YX - automatic precompiled headers +# -GX - enable C++ exception support +WIN_CFLAGS = -nologo -W3 + +# MSVC compiler options for debug builds linked to MSVCRTD.DLL +# -MDd - link with MSVCRTD.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_IDG_CFLAGS = -MDd -Od -Z7 + +# MSVC compiler options for debug builds linked to MSVCRT.DLL +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_DEBUG_CFLAGS = -MD -Od -Zi -Fd$(OBJDIR)/$(PDBFILE) + +# MSVC compiler options for release (optimized) builds +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, C-runtime) +# -O2 - Optimize for speed +# -G5 - Optimize for Pentium +WIN_OPT_CFLAGS = -MD -O2 + +ifdef BUILD_OPT +OPTIMIZER = $(WIN_OPT_CFLAGS) +else +ifdef BUILD_IDG +OPTIMIZER = $(WIN_IDG_CFLAGS) +else +OPTIMIZER = $(WIN_DEBUG_CFLAGS) +endif +endif + +OS_CFLAGS = -D_X86_=1 -DXP_WIN -DXP_WIN32 -DWIN32 -D_WINDOWS -D_WIN32 -DWINVER=0x500 -D_WIN32_WINNT=0x500 $(WIN_CFLAGS) -DAVMPLUS_WIN32 -DAVMPLUS_IA32 +JSDLL_CFLAGS = -DEXPORT_JS_API +OS_LIBS = -lm -lc + +PREBUILT_CPUCFG = 1 +USE_MSVC = 1 + +LIB_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib \ + winmm.lib \ + -nologo\ + -subsystem:windows -dll -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +EXE_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib -nologo\ + -subsystem:console -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +# CAFEDIR = t:/cafe +# JCLASSPATH = $(CAFEDIR)/Java/Lib/classes.zip +# JAVAC = $(CAFEDIR)/Bin/sj.exe +# JAVAH = $(CAFEDIR)/Java/Bin/javah.exe +# JCFLAGS = -I$(CAFEDIR)/Java/Include -I$(CAFEDIR)/Java/Include/win32 diff --git a/js/src/ref-config/WINNT6.0.mk b/js/src/ref-config/WINNT6.0.mk new file mode 100644 index 0000000..7681e01 --- /dev/null +++ b/js/src/ref-config/WINNT6.0.mk @@ -0,0 +1,118 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config for Windows NT using MS Visual C++ (version?) +# + +CC = cl +CXX = cl + +RANLIB = echo + +PDBFILE = $(basename $(@F)).pdb + +#.c.o: +# $(CC) -c -MD $*.d $(CFLAGS) $< + +CPU_ARCH = x86 # XXX fixme +GFX_ARCH = win32 + +# MSVC compiler options for both debug/optimize +# -nologo - suppress copyright message +# -W3 - Warning level 3 +# -Gm - enable minimal rebuild +# -Z7 - put debug info into the executable, not in .pdb file +# -Zi - put debug info into .pdb file +# -YX - automatic precompiled headers +# -GX - enable C++ exception support +WIN_CFLAGS = -nologo -W3 + +# MSVC compiler options for debug builds linked to MSVCRTD.DLL +# -MDd - link with MSVCRTD.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_IDG_CFLAGS = -MDd -Od -Z7 + +# MSVC compiler options for debug builds linked to MSVCRT.DLL +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, debug C-runtime) +# -Od - minimal optimization +WIN_DEBUG_CFLAGS = -MD -Od -Zi -Fd$(OBJDIR)/$(PDBFILE) + +# MSVC compiler options for release (optimized) builds +# -MD - link with MSVCRT.LIB (Dynamically-linked, multi-threaded, C-runtime) +# -O2 - Optimize for speed +# -G5 - Optimize for Pentium +WIN_OPT_CFLAGS = -MD -O2 + +ifdef BUILD_OPT +OPTIMIZER = $(WIN_OPT_CFLAGS) +else +ifdef BUILD_IDG +OPTIMIZER = $(WIN_IDG_CFLAGS) +else +OPTIMIZER = $(WIN_DEBUG_CFLAGS) +endif +endif + +OS_CFLAGS = -D_X86_=1 -DXP_WIN -DXP_WIN32 -DWIN32 -D_WINDOWS -D_WIN32 -DWINVER=0x500 -D_WIN32_WINNT=0x500 $(WIN_CFLAGS) +JSDLL_CFLAGS = -DEXPORT_JS_API +OS_LIBS = -lm -lc + +PREBUILT_CPUCFG = 1 +USE_MSVC = 1 + +LIB_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib \ + winmm.lib \ + -nologo\ + -subsystem:windows -dll -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +EXE_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib -nologo\ + -subsystem:console -debug -pdb:$(OBJDIR)/$(PDBFILE)\ + -machine:I386\ + -opt:ref -opt:noicf + +# CAFEDIR = t:/cafe +# JCLASSPATH = $(CAFEDIR)/Java/Lib/classes.zip +# JAVAC = $(CAFEDIR)/Bin/sj.exe +# JAVAH = $(CAFEDIR)/Java/Bin/javah.exe +# JCFLAGS = -I$(CAFEDIR)/Java/Include -I$(CAFEDIR)/Java/Include/win32 diff --git a/js/src/ref-config/dgux.mk b/js/src/ref-config/dgux.mk new file mode 100644 index 0000000..3b5967e --- /dev/null +++ b/js/src/ref-config/dgux.mk @@ -0,0 +1,64 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# Config stuff for Data General DG/UX +# + +# +# Initial DG/UX port by Marc Fraioli (fraioli@dg-rtp.dg.com) +# + +AS = as +CC = gcc +CCC = g++ + +RANLIB = echo + +# +# _DGUX_SOURCE is needed to turn on a lot of stuff in the headers if +# you're not using DG's compiler. It shouldn't hurt if you are. +# +# _POSIX4A_DRAFT10_SOURCE is needed to pick up localtime_r, used in +# prtime.c +# +OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -DDGUX -D_DGUX_SOURCE -D_POSIX4A_DRAFT10_SOURCE -DHAVE_LOCALTIME_R +OS_LIBS = -lsocket -lnsl + +NOSUCHFILE = /no-such-file diff --git a/js/src/resource.h b/js/src/resource.h new file mode 100644 index 0000000..59dbde3 --- /dev/null +++ b/js/src/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by js3240.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/js/src/rules.mk b/js/src/rules.mk new file mode 100644 index 0000000..5a1e053 --- /dev/null +++ b/js/src/rules.mk @@ -0,0 +1,206 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998-1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Michael Ang +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# +# JSRef GNUmake makefile rules +# + +ifdef USE_MSVC +LIB_OBJS = $(addprefix $(OBJDIR)/, $(LIB_CPPFILES:.cpp=.obj)) +PROG_OBJS = $(addprefix $(OBJDIR)/, $(PROG_CPPFILES:.cpp=.obj)) +else +LIB_OBJS = $(addprefix $(OBJDIR)/, $(LIB_CPPFILES:.cpp=.o)) +LIB_OBJS += $(addprefix $(OBJDIR)/, $(LIB_ASFILES:.s=.o)) +PROG_OBJS = $(addprefix $(OBJDIR)/, $(PROG_CPPFILES:.cpp=.o)) +endif + +CPPFILES = $(LIB_CPPFILES) $(PROG_CPPFILES) +OBJS = $(LIB_OBJS) $(PROG_OBJS) + +ifdef USE_MSVC +# TARGETS = $(LIBRARY) # $(PROGRAM) not supported for MSVC yet +TARGETS += $(SHARED_LIBRARY) $(PROGRAM) # it is now +else +TARGETS += $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) +endif + +all: + +$(LOOP_OVER_PREDIRS) +ifneq "$(strip $(TARGETS))" "" + $(MAKE) -f Makefile.ref $(TARGETS) +endif + +$(LOOP_OVER_DIRS) + +$(OBJDIR)/%: %.cpp + @$(MAKE_OBJDIR) + $(CXX) -o $@ $(CFLAGS) $(OPTIMIZER) $< $(LDFLAGS) + +# This rule must come before the rule with no dep on header +$(OBJDIR)/%.o: %.cpp %.h + @$(MAKE_OBJDIR) + $(CXX) -o $@ -c $(CFLAGS) $(OPTIMIZER) $< + +$(OBJDIR)/jsinterp.o: jsinterp.cpp jsinterp.h + @$(MAKE_OBJDIR) + $(CXX) -o $@ -c $(CFLAGS) $(INTERP_OPTIMIZER) jsinterp.cpp + +$(OBJDIR)/jsbuiltins.o: jsbuiltins.cpp jsinterp.h + @$(MAKE_OBJDIR) + $(CXX) -o $@ -c $(CFLAGS) $(BUILTINS_OPTIMIZER) jsbuiltins.cpp + +$(OBJDIR)/%.o: %.cpp + @$(MAKE_OBJDIR) + $(CXX) -o $@ -c $(CFLAGS) $(OPTIMIZER) $< + +$(OBJDIR)/%.o: %.s + @$(MAKE_OBJDIR) + $(AS) -o $@ $(ASFLAGS) $< + +# This rule must come before rule with no dep on header +$(OBJDIR)/%.obj: %.cpp %.h + @$(MAKE_OBJDIR) + $(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $(JSDLL_CFLAGS) $(OPTIMIZER) $< + +$(OBJDIR)/jsinterp.obj: jsinterp.cpp jsinterp.h + @$(MAKE_OBJDIR) + $(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $(JSDLL_CFLAGS) $(INTERP_OPTIMIZER) jsinterp.cpp + +$(OBJDIR)/jsbuiltins.obj: jsbuiltins.cpp jsinterp.h + @$(MAKE_OBJDIR) + $(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $(JSDLL_CFLAGS) $(BUILTINS_OPTIMIZER) jsbuiltins.cpp + +$(OBJDIR)/%.obj: %.cpp + @$(MAKE_OBJDIR) + $(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $(JSDLL_CFLAGS) $(OPTIMIZER) $< + +$(OBJDIR)/js.obj: js.cpp + @$(MAKE_OBJDIR) + $(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $(OPTIMIZER) $< + +ifeq ($(OS_ARCH),OS2) +$(LIBRARY): $(LIB_OBJS) + $(AR) $@ $? $(AR_OS2_SUFFIX) + $(RANLIB) $@ +else +ifdef USE_MSVC +$(SHARED_LIBRARY): $(LIB_OBJS) + link.exe $(LIB_LINK_FLAGS) /base:0x61000000 $(OTHER_LIBS) \ + /out:"$@" /pdb:none\ + /implib:"$(OBJDIR)/$(@F:.dll=.lib)" $^ +else +$(LIBRARY): $(LIB_OBJS) + $(AR) rv $@ $? + $(RANLIB) $@ + +$(SHARED_LIBRARY): $(LIB_OBJS) + $(MKSHLIB) -o $@ $(LIB_OBJS) $(LDFLAGS) $(OTHER_LIBS) +endif +endif + +# Java stuff +$(CLASSDIR)/$(OBJDIR)/$(JARPATH)/%.class: %.java + mkdir -p $(@D) + $(JAVAC) $(JAVAC_FLAGS) $< + +define MAKE_OBJDIR +if test ! -d $(@D); then rm -rf $(@D); mkdir -p $(@D); fi +endef + +ifdef DIRS +LOOP_OVER_DIRS = \ + @for d in $(DIRS); do \ + if test -d $$d; then \ + set -e; \ + echo "cd $$d; $(MAKE) -f Makefile.ref $@"; \ + cd $$d; $(MAKE) -f Makefile.ref $@; cd ..; \ + set +e; \ + else \ + echo "Skipping non-directory $$d..."; \ + fi; \ + done +endif + +ifdef PREDIRS +LOOP_OVER_PREDIRS = \ + @for d in $(PREDIRS); do \ + if test -d $$d; then \ + set -e; \ + echo "cd $$d; $(MAKE) -f Makefile.ref $@"; \ + cd $$d; $(MAKE) -f Makefile.ref $@; cd ..; \ + set +e; \ + else \ + echo "Skipping non-directory $$d..."; \ + fi; \ + done +endif + +export: + +$(LOOP_OVER_PREDIRS) + mkdir -p $(DIST)/include $(DIST)/$(LIBDIR) $(DIST)/bin +ifneq "$(strip $(HFILES))" "" + $(CP) $(HFILES) $(DIST)/include +endif +ifneq "$(strip $(LIBRARY))" "" + $(CP) $(LIBRARY) $(DIST)/$(LIBDIR) +endif +ifneq "$(strip $(JARS))" "" + $(CP) $(JARS) $(DIST)/$(LIBDIR) +endif +ifneq "$(strip $(SHARED_LIBRARY))" "" + $(CP) $(SHARED_LIBRARY) $(DIST)/$(LIBDIR) +endif +ifneq "$(strip $(PROGRAM))" "" + $(CP) $(PROGRAM) $(DIST)/bin +endif + +$(LOOP_OVER_DIRS) + +clean: + +$(LOOP_OVER_PREDIRS) + rm -rf $(OBJS) $(GARBAGE) + +clobber: + +$(LOOP_OVER_PREDIRS) + rm -rf $(OBJS) $(TARGETS) $(DEPENDENCIES) $(GARBAGE) + if test -d $(OBJDIR); then rmdir $(OBJDIR); fi + +tar: + tar cvf $(TARNAME) $(TARFILES) + gzip $(TARNAME) + diff --git a/js/src/sharkctl.cpp b/js/src/sharkctl.cpp new file mode 100644 index 0000000..615ee56 --- /dev/null +++ b/js/src/sharkctl.cpp @@ -0,0 +1,238 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=80: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * Copyright (C) 2010 Patrick Walton + * + * Contributor(s): + * Andreas Gal + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifdef __APPLE__ + +#include "sharkctl.h" + +#include "sharkctl.h" +#include +#include +#include +#include + +#include "jsutil.h" + +#define SHARK_MSG_ACQUIRE 0x29a +#define SHARK_MSG_RELEASE 0x29b +#define SHARK_MSG_STOP 0x29c +#define SHARK_MSG_START 0x29d + +#define RECV_SIZEOF(ty) offsetof(ty, out) + +// Private API in libSystem.dylib +extern "C" void bootstrap_look_up(mach_port_t special_port, const char *name, + mach_port_t *dest_port); + +struct chud_client_acquire_msg { + mach_msg_header_t hdr; + uint32_t unk0; // always 0 + uint32_t unk1; // always 1 + uint32_t pid; + uint32_t out[2]; +}; + +struct chud_client_start_msg { + mach_msg_header_t hdr; + uint32_t unk0; // always 1 + uint32_t name0; + uint32_t arg2; // always 6 + uint8_t unk1; // always 0 + uint8_t unk2; // always 1 + uint8_t unk3; // uninitialized + uint8_t unk4; // always 1 + uint32_t unk5; // always 0 + uint32_t unk6; // always 1 + uint32_t name1; // same as name0 +}; + +struct chud_client_stop_msg { + mach_msg_header_t hdr; + uint32_t out[5]; +}; + +struct chud_client_release_msg { + mach_msg_header_t hdr; + uint32_t unk0; // always 0 + uint32_t unk1; // always 1 + uint32_t pid; + uint32_t out[2]; +}; + +static mach_port_t +CreatePort(void) +{ + mach_port_t bootstrap_port, shark_port = 0; + task_get_special_port(mach_task_self(), TASK_BOOTSTRAP_PORT, + &bootstrap_port); + bootstrap_look_up(bootstrap_port, "CHUD_IPC", &shark_port); + return shark_port; +} + +static mach_msg_return_t +Connect(mach_port_t shark_port) +{ + mach_port_t reply_port = mig_get_reply_port(); + + struct chud_client_acquire_msg msg; + msg.hdr.msgh_bits = 0x1513; + msg.hdr.msgh_size = sizeof(mach_msg_header_t); + msg.hdr.msgh_remote_port = shark_port; + msg.hdr.msgh_local_port = reply_port; + msg.hdr.msgh_reserved = 0; + msg.hdr.msgh_id = SHARK_MSG_ACQUIRE; + msg.unk0 = 0; + msg.unk1 = 1; + msg.pid = getpid(); + + JS_ASSERT(RECV_SIZEOF(struct chud_client_acquire_msg) == 0x24); + JS_ASSERT(sizeof(msg) == 0x2c); + mach_msg_return_t result = mach_msg(&msg.hdr, MACH_SEND_MSG | MACH_RCV_MSG, + RECV_SIZEOF(struct chud_client_acquire_msg), + sizeof(msg), reply_port, 0, 0); + mig_dealloc_reply_port(reply_port); + return result; +} + +static mach_msg_return_t +Start(mach_port_t shark_port, uint32_t name) +{ + mach_port_t reply_port = mig_get_reply_port(); + + struct chud_client_start_msg msg; + msg.hdr.msgh_bits = 0x80001513; + msg.hdr.msgh_size = sizeof(mach_msg_header_t); + msg.hdr.msgh_remote_port = shark_port; + msg.hdr.msgh_local_port = reply_port; + msg.hdr.msgh_reserved = 0; + msg.hdr.msgh_id = SHARK_MSG_START; + msg.unk0 = 1; + msg.name0 = name; + msg.arg2 = 6; + msg.unk1 = 0; + msg.unk2 = 1; + msg.unk3 = 0; + msg.unk4 = 1; + msg.unk5 = 0; + msg.unk6 = 1; + msg.name1 = name; + + JS_ASSERT(sizeof(msg) == 0x34); + mach_msg_return_t result = mach_msg(&msg.hdr, MACH_SEND_MSG | MACH_RCV_MSG, + sizeof(msg), 0x30, reply_port, 0, 0); + mig_dealloc_reply_port(reply_port); + return result; +} + +mach_msg_return_t +Stop(mach_port_t shark_port) +{ + mach_port_t reply_port = mig_get_reply_port(); + + struct chud_client_stop_msg msg; + msg.hdr.msgh_bits = 0x1513; + msg.hdr.msgh_size = sizeof(mach_msg_header_t); + msg.hdr.msgh_remote_port = shark_port; + msg.hdr.msgh_local_port = reply_port; + msg.hdr.msgh_reserved = 0; + msg.hdr.msgh_id = SHARK_MSG_STOP; + + JS_ASSERT(RECV_SIZEOF(struct chud_client_stop_msg) == 0x18); + JS_ASSERT(sizeof(msg) == 0x2c); + mach_msg_return_t result = mach_msg(&msg.hdr, MACH_SEND_MSG | MACH_RCV_MSG, + RECV_SIZEOF(struct chud_client_stop_msg), + sizeof(msg), reply_port, 0, 0); + mig_dealloc_reply_port(reply_port); + return result; +} + +static mach_msg_return_t +Disconnect(mach_port_t shark_port) +{ + mach_port_t reply_port = mig_get_reply_port(); + + struct chud_client_release_msg msg; + msg.hdr.msgh_bits = 0x1513; + msg.hdr.msgh_size = sizeof(mach_msg_header_t); + msg.hdr.msgh_remote_port = shark_port; + msg.hdr.msgh_local_port = reply_port; + msg.hdr.msgh_reserved = 0; + msg.hdr.msgh_id = SHARK_MSG_RELEASE; + msg.unk0 = 0; + msg.unk1 = 1; + msg.pid = getpid(); + + JS_ASSERT(RECV_SIZEOF(struct chud_client_release_msg) == 0x24); + JS_ASSERT(sizeof(msg) == 0x2c); + mach_msg_return_t result = mach_msg(&msg.hdr, MACH_SEND_MSG | MACH_RCV_MSG, + RECV_SIZEOF(struct chud_client_release_msg), + sizeof(msg), reply_port, 0, 0); + mig_dealloc_reply_port(reply_port); + return result; +} + +static mach_port_t shark_port = 0; +static bool connected = false; +static bool running = false; + +namespace Shark { + +bool +Start() +{ + if (!shark_port && !(shark_port = CreatePort())) + return false; + if (!connected && Connect(shark_port)) + return false; + connected = true; + if (!running && ::Start(shark_port, 0xdeadbeef)) + return false; + return running = true; +}; + +void +Stop() +{ + if (!shark_port || !connected) + return; + ::Stop(shark_port); + running = false; + Disconnect(shark_port); + connected = false; +} + +} + +#endif diff --git a/js/src/sharkctl.h b/js/src/sharkctl.h new file mode 100644 index 0000000..c5fb366 --- /dev/null +++ b/js/src/sharkctl.h @@ -0,0 +1,53 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=80: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * Copyright (C) 2010 Patrick Walton + * + * Contributor(s): + * Andreas Gal + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _SHARKCTL_H +#define _SHARKCTL_H + +#ifdef __APPLE__ + +#include +#include + +namespace Shark { + +bool Start(); +void Stop(); + +}; + +#endif + +#endif diff --git a/js/src/shell/Makefile.in b/js/src/shell/Makefile.in new file mode 100644 index 0000000..058b3b2 --- /dev/null +++ b/js/src/shell/Makefile.in @@ -0,0 +1,81 @@ +# -*- Mode: makefile -*- +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Spidermonkey build system. +# +# The Initial Developer of the Original Code is +# The Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Ted Mielczarek +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +PROGRAM = js$(BIN_SUFFIX) +CPPSRCS = \ + js.cpp \ + jsworkers.cpp \ + $(NULL) + +DEFINES += -DEXPORT_JS_API + +LIBS = $(NSPR_LIBS) $(EDITLINE_LIBS) $(DEPTH)/$(LIB_PREFIX)js_static.$(LIB_SUFFIX) + +LOCAL_INCLUDES += -I$(topsrcdir) -I.. + +ifdef _MSC_VER +ifdef WINCE +WIN32_EXE_LDFLAGS += -ENTRY:mainACRTStartup +endif +endif + +ifeq ($(OS_ARCH),Darwin) +ifeq ($(TARGET_CPU),x86_64) +DARWIN_EXE_LDFLAGS += -pagezero_size 10000 -image_base 100000000 +endif +endif + +include $(topsrcdir)/config/rules.mk + +ifdef MOZ_SHARK +CFLAGS += -F/System/Library/PrivateFrameworks +CXXFLAGS += -F/System/Library/PrivateFrameworks +LDFLAGS += -F/System/Library/PrivateFrameworks -framework CHUD +endif + +# People expect the js shell to wind up in the top-level JS dir. +libs:: + $(INSTALL) $(IFLAGS2) $(PROGRAM) $(DEPTH) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp new file mode 100644 index 0000000..96d460c --- /dev/null +++ b/js/src/shell/js.cpp @@ -0,0 +1,5815 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#define __STDC_LIMIT_MACROS + +/* + * JS shell. + */ +#include +#include +#include +#include +#include +#include +#include +#include "jstypes.h" +#include "jsstdint.h" +#include "jsarena.h" +#include "jsutil.h" +#include "jsprf.h" +#include "jswrapper.h" +#include "jsapi.h" +#include "jsarray.h" +#include "jsatom.h" +#include "jsbuiltins.h" +#include "jscntxt.h" +#include "jsdate.h" +#include "jsdbgapi.h" +#include "jsemit.h" +#include "jsfun.h" +#include "jsgc.h" +#include "jsiter.h" +#include "jslock.h" +#include "jsnum.h" +#include "jsobj.h" +#include "jsparse.h" +#include "jsreflect.h" +#include "jsscope.h" +#include "jsscript.h" +#include "jstracer.h" +#include "jstypedarray.h" +#include "jsxml.h" +#include "jsperf.h" + +#include "prmjtime.h" + +#ifdef JSDEBUGGER +#include "jsdebug.h" +#ifdef JSDEBUGGER_JAVA_UI +#include "jsdjava.h" +#endif /* JSDEBUGGER_JAVA_UI */ +#ifdef JSDEBUGGER_C_UI +#include "jsdb.h" +#endif /* JSDEBUGGER_C_UI */ +#endif /* JSDEBUGGER */ + +#include "jsworkers.h" + +#include "jsinterpinlines.h" +#include "jsobjinlines.h" +#include "jsscriptinlines.h" + +#ifdef XP_UNIX +#include +#include +#include +#endif + +#if defined(XP_WIN) || defined(XP_OS2) +#include /* for isatty() */ +#endif + +#ifdef XP_WIN +#include "jswin.h" +#endif + +using namespace js; + +typedef enum JSShellExitCode { + EXITCODE_RUNTIME_ERROR = 3, + EXITCODE_FILE_NOT_FOUND = 4, + EXITCODE_OUT_OF_MEMORY = 5, + EXITCODE_TIMEOUT = 6 +} JSShellExitCode; + +size_t gStackChunkSize = 8192; + +/* Assume that we can not use more than 5e5 bytes of C stack by default. */ +#if (defined(DEBUG) && defined(__SUNPRO_CC)) || defined(JS_CPU_SPARC) +/* Sun compiler uses larger stack space for js_Interpret() with debug + Use a bigger gMaxStackSize to make "make check" happy. */ +#define DEFAULT_MAX_STACK_SIZE 5000000 +#else +#define DEFAULT_MAX_STACK_SIZE 500000 +#endif + +size_t gMaxStackSize = DEFAULT_MAX_STACK_SIZE; + + +#ifdef JS_THREADSAFE +static PRUintn gStackBaseThreadIndex; +#else +static jsuword gStackBase; +#endif + +static size_t gScriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA; + +/* + * Limit the timeout to 30 minutes to prevent an overflow on platfoms + * that represent the time internally in microseconds using 32-bit int. + */ +static jsdouble MAX_TIMEOUT_INTERVAL = 1800.0; +static jsdouble gTimeoutInterval = -1.0; +static volatile bool gCanceled = false; + +static bool enableTraceJit = false; +static bool enableMethodJit = false; +static bool enableProfiling = false; + +static bool printTiming = false; + +static JSBool +SetTimeoutValue(JSContext *cx, jsdouble t); + +static bool +InitWatchdog(JSRuntime *rt); + +static void +KillWatchdog(); + +static bool +ScheduleWatchdog(JSRuntime *rt, jsdouble t); + +static void +CancelExecution(JSRuntime *rt); + +/* + * Watchdog thread state. + */ +#ifdef JS_THREADSAFE + +static PRLock *gWatchdogLock = NULL; +static PRCondVar *gWatchdogWakeup = NULL; +static PRThread *gWatchdogThread = NULL; +static bool gWatchdogHasTimeout = false; +static PRIntervalTime gWatchdogTimeout = 0; + +static PRCondVar *gSleepWakeup = NULL; + +#else + +static JSRuntime *gRuntime = NULL; + +#endif + +int gExitCode = 0; +JSBool gQuitting = JS_FALSE; +FILE *gErrFile = NULL; +FILE *gOutFile = NULL; +#ifdef JS_THREADSAFE +JSObject *gWorkers = NULL; +js::workers::ThreadPool *gWorkerThreadPool = NULL; +#endif + +static JSBool reportWarnings = JS_TRUE; +static JSBool compileOnly = JS_FALSE; + +typedef enum JSShellErrNum { +#define MSG_DEF(name, number, count, exception, format) \ + name = number, +#include "jsshell.msg" +#undef MSG_DEF + JSShellErr_Limit +#undef MSGDEF +} JSShellErrNum; + +static JSContext * +NewContext(JSRuntime *rt); + +static void +DestroyContext(JSContext *cx, bool withGC); + +static const JSErrorFormatString * +my_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber); + +static JSObject * +split_setup(JSContext *cx, JSBool evalcx); + +#ifdef EDITLINE +JS_BEGIN_EXTERN_C +JS_EXTERN_API(char) *readline(const char *prompt); +JS_EXTERN_API(void) add_history(char *line); +JS_END_EXTERN_C +#endif + +static void +ReportException(JSContext *cx) +{ + if (JS_IsExceptionPending(cx)) { + if (!JS_ReportPendingException(cx)) + JS_ClearPendingException(cx); + } +} + +class ToString { + public: + ToString(JSContext *aCx, jsval v, JSBool aThrow = JS_FALSE) + : cx(aCx), mThrow(aThrow) + { + mStr = JS_ValueToString(cx, v); + if (!aThrow && !mStr) + ReportException(cx); + JS_AddNamedStringRoot(cx, &mStr, "Value ToString helper"); + } + ~ToString() { + JS_RemoveStringRoot(cx, &mStr); + } + JSBool threw() { return !mStr; } + jsval getJSVal() { return STRING_TO_JSVAL(mStr); } + const char *getBytes() { + if (mStr && (mBytes.ptr() || mBytes.encode(cx, mStr))) + return mBytes.ptr(); + return "(error converting value)"; + } + private: + JSContext *cx; + JSString *mStr; + JSBool mThrow; + JSAutoByteString mBytes; +}; + +class IdToString : public ToString { +public: + IdToString(JSContext *cx, jsid id, JSBool aThrow = JS_FALSE) + : ToString(cx, IdToJsval(id), aThrow) + { } +}; + +static char * +GetLine(FILE *file, const char * prompt) +{ + size_t size; + char *buffer; +#ifdef EDITLINE + /* + * Use readline only if file is stdin, because there's no way to specify + * another handle. Are other filehandles interactive? + */ + if (file == stdin) { + char *linep = readline(prompt); + /* + * We set it to zero to avoid complaining about inappropriate ioctl + * for device in the case of EOF. Looks like errno == 251 if line is + * finished with EOF and errno == 25 (EINVAL on Mac) if there is + * nothing left to read. + */ + if (errno == 251 || errno == 25 || errno == EINVAL) + errno = 0; + if (!linep) + return NULL; + if (linep[0] != '\0') + add_history(linep); + return linep; + } +#endif + size_t len = 0; + if (*prompt != '\0') { + fprintf(gOutFile, "%s", prompt); + fflush(gOutFile); + } + size = 80; + buffer = (char *) malloc(size); + if (!buffer) + return NULL; + char *current = buffer; + while (fgets(current, size - len, file)) { + len += strlen(current); + char *t = buffer + len - 1; + if (*t == '\n') { + /* Line was read. We remove '\n' and exit. */ + *t = '\0'; + return buffer; + } + if (len + 1 == size) { + size = size * 2; + char *tmp = (char *) realloc(buffer, size); + if (!tmp) { + free(buffer); + return NULL; + } + buffer = tmp; + } + current = buffer + len; + } + if (len && !ferror(file)) + return buffer; + free(buffer); + return NULL; +} + +/* + * State to store as JSContext private. + * + * We declare such timestamp as volatile as they are updated in the operation + * callback without taking any locks. Any possible race can only lead to more + * frequent callback calls. This is safe as the callback does everything based + * on timing. + */ +struct JSShellContextData { + volatile JSIntervalTime startTime; +}; + +static JSShellContextData * +NewContextData() +{ + /* Prevent creation of new contexts after we have been canceled. */ + if (gCanceled) + return NULL; + + JSShellContextData *data = (JSShellContextData *) + calloc(sizeof(JSShellContextData), 1); + if (!data) + return NULL; + data->startTime = js_IntervalNow(); + return data; +} + +static inline JSShellContextData * +GetContextData(JSContext *cx) +{ + JSShellContextData *data = (JSShellContextData *) JS_GetContextPrivate(cx); + + JS_ASSERT(data); + return data; +} + +static JSBool +ShellOperationCallback(JSContext *cx) +{ + if (!gCanceled) + return JS_TRUE; + + JS_ClearPendingException(cx); + return JS_FALSE; +} + +static void +SetContextOptions(JSContext *cx) +{ + JS_SetNativeStackQuota(cx, gMaxStackSize); + JS_SetScriptStackQuota(cx, gScriptStackQuota); + JS_SetOperationCallback(cx, ShellOperationCallback); +} + +#ifdef WINCE +int errno; +#endif + +static void +Process(JSContext *cx, JSObject *obj, char *filename, JSBool forceTTY) +{ + JSBool ok, hitEOF; + JSObject *scriptObj; + jsval result; + JSString *str; + char *buffer; + size_t size; + int lineno; + int startline; + FILE *file; + uint32 oldopts; + + if (forceTTY || !filename || strcmp(filename, "-") == 0) { + file = stdin; + } else { + file = fopen(filename, "r"); + if (!file) { + JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, + JSSMSG_CANT_OPEN, filename, strerror(errno)); + gExitCode = EXITCODE_FILE_NOT_FOUND; + return; + } + } + + SetContextOptions(cx); + +#ifndef WINCE + /* windows mobile (and possibly other os's) does not have a TTY */ + if (!forceTTY && !isatty(fileno(file))) +#endif + { + /* + * It's not interactive - just execute it. + * + * Support the UNIX #! shell hack; gobble the first line if it starts + * with '#'. TODO - this isn't quite compatible with sharp variables, + * as a legal js program (using sharp variables) might start with '#'. + * But that would require multi-character lookahead. + */ + int ch = fgetc(file); + if (ch == '#') { + while((ch = fgetc(file)) != EOF) { + if (ch == '\n' || ch == '\r') + break; + } + } + ungetc(ch, file); + + int64 t1 = PRMJ_Now(); + oldopts = JS_GetOptions(cx); + JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL); + scriptObj = JS_CompileFileHandle(cx, obj, filename, file); + JS_SetOptions(cx, oldopts); + if (scriptObj && !compileOnly) { + (void) JS_ExecuteScript(cx, obj, scriptObj, NULL); + int64 t2 = PRMJ_Now() - t1; + if (printTiming) + printf("runtime = %.3f ms\n", double(t2) / PRMJ_USEC_PER_MSEC); + } + + goto cleanup; + } + + /* It's an interactive filehandle; drop into read-eval-print loop. */ + lineno = 1; + hitEOF = JS_FALSE; + buffer = NULL; + size = 0; /* assign here to avoid warnings */ + do { + /* + * Accumulate lines until we get a 'compilable unit' - one that either + * generates an error (before running out of source) or that compiles + * cleanly. This should be whenever we get a complete statement that + * coincides with the end of a line. + */ + startline = lineno; + size_t len = 0; /* initialize to avoid warnings */ + do { + ScheduleWatchdog(cx->runtime, -1); + gCanceled = false; + errno = 0; + + char *line; + { + JSAutoSuspendRequest suspended(cx); + line = GetLine(file, startline == lineno ? "js> " : ""); + } + if (!line) { + if (errno) { + JS_ReportError(cx, strerror(errno)); + free(buffer); + goto cleanup; + } + hitEOF = JS_TRUE; + break; + } + if (!buffer) { + buffer = line; + len = strlen(buffer); + size = len + 1; + } else { + /* + * len + 1 is required to store '\n' in the end of line. + */ + size_t newlen = strlen(line) + (len ? len + 1 : 0); + if (newlen + 1 > size) { + size = newlen + 1 > size * 2 ? newlen + 1 : size * 2; + char *newBuf = (char *) realloc(buffer, size); + if (!newBuf) { + free(buffer); + free(line); + JS_ReportOutOfMemory(cx); + goto cleanup; + } + buffer = newBuf; + } + char *current = buffer + len; + if (startline != lineno) + *current++ = '\n'; + strcpy(current, line); + len = newlen; + free(line); + } + lineno++; + if (!ScheduleWatchdog(cx->runtime, gTimeoutInterval)) { + hitEOF = JS_TRUE; + break; + } + } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, len)); + + if (hitEOF && !buffer) + break; + + /* Clear any pending exception from previous failed compiles. */ + JS_ClearPendingException(cx); + + /* Even though we're interactive, we have a compile-n-go opportunity. */ + oldopts = JS_GetOptions(cx); + if (!compileOnly) + JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO); + scriptObj = JS_CompileScript(cx, obj, buffer, len, "typein", + startline); + if (!compileOnly) + JS_SetOptions(cx, oldopts); + + if (scriptObj && !compileOnly) { + ok = JS_ExecuteScript(cx, obj, scriptObj, &result); + if (ok && !JSVAL_IS_VOID(result)) { + str = JS_ValueToSource(cx, result); + ok = !!str; + if (ok) { + JSAutoByteString bytes(cx, str); + ok = !!bytes; + if (ok) + fprintf(gOutFile, "%s\n", bytes.ptr()); + } + } + } + *buffer = '\0'; + } while (!hitEOF && !gQuitting); + + free(buffer); + fprintf(gOutFile, "\n"); +cleanup: + if (file != stdin) + fclose(file); + return; +} + +static int +usage(void) +{ + fprintf(gErrFile, "%s\n", JS_GetImplementationVersion()); + fprintf(gErrFile, "usage: js [options] [scriptfile] [scriptarg...]\n" + "Options:\n" + " -h Display this information\n" + " -z Create a split global object\n" + " Warning: this option is probably not useful\n" + " -P Deeply freeze the global object prototype\n" + " -s Toggle JSOPTION_STRICT flag\n" + " -w Report strict warnings\n" + " -W Do not report strict warnings\n" + " -x Toggle JSOPTION_XML flag\n" + " -C Compile-only; do not execute\n" + " -i Enable interactive read-eval-print loop\n" + " -j Enable the TraceMonkey tracing JIT\n" + " -m Enable the JaegerMonkey method JIT\n" + " -a Always method JIT, ignore internal tuning\n" + " This only has effect with -m\n" + " -p Enable loop profiling for TraceMonkey\n" + " -d Enable debug mode\n" + " -b Print timing statistics\n" + " -t Interrupt long-running execution after seconds, where\n" + " <= 1800.0. Negative values indicate no timeout (default).\n" + " -c Suggest stack chunk size of bytes. Default is 8192.\n" + " Warning: this option is currently ignored.\n" + " -o